From 1727bbcc7046eb5870df7409310d58e0c9483233 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andrzej=20G=C5=82=C4=85bek?= Date: Fri, 3 Nov 2023 12:08:09 +0100 Subject: [PATCH 0001/3723] drivers: nrf_qspi_nor: Prevent reading status before sending RDPD MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit After entering the Deep Power-down mode, some flash chips ignore all commands except from the one that releases the chip from the DP mode and it is not possible to successfully read their Status Register then. Since the QSPI peripheral tries to read this register when it is being activated, it consequently fails to send the actual command that would release the flash chip from the DP mode if that is to be done right after QSPI initialization. Prevent this problem by performing the QSPI activation with all pins disconnected. This causes that the Status Register value is read as all zeros and allows the activation to always finish successfully, and the RDPD command to be properly sent. Signed-off-by: Andrzej Głąbek --- drivers/flash/nrf_qspi_nor.c | 27 +++++++++++++++++++++++---- 1 file changed, 23 insertions(+), 4 deletions(-) diff --git a/drivers/flash/nrf_qspi_nor.c b/drivers/flash/nrf_qspi_nor.c index 28c705f6707..467d0643d48 100644 --- a/drivers/flash/nrf_qspi_nor.c +++ b/drivers/flash/nrf_qspi_nor.c @@ -1339,15 +1339,34 @@ static int enter_dpd(const struct device *const dev) static int exit_dpd(const struct device *const dev) { if (IS_ENABLED(DT_INST_PROP(0, has_dpd))) { + nrf_qspi_pins_t pins; + nrf_qspi_pins_t disconnected_pins = { + .sck_pin = NRF_QSPI_PIN_NOT_CONNECTED, + .csn_pin = NRF_QSPI_PIN_NOT_CONNECTED, + .io0_pin = NRF_QSPI_PIN_NOT_CONNECTED, + .io1_pin = NRF_QSPI_PIN_NOT_CONNECTED, + .io2_pin = NRF_QSPI_PIN_NOT_CONNECTED, + .io3_pin = NRF_QSPI_PIN_NOT_CONNECTED, + }; struct qspi_cmd cmd = { .op_code = SPI_NOR_CMD_RDPD, }; uint32_t t_exit_dpd = DT_INST_PROP_OR(0, t_exit_dpd, 0); - int ret; + nrfx_err_t res; + int rc; - ret = qspi_send_cmd(dev, &cmd, false); - if (ret < 0) { - return ret; + nrf_qspi_pins_get(NRF_QSPI, &pins); + nrf_qspi_pins_set(NRF_QSPI, &disconnected_pins); + res = nrfx_qspi_activate(true); + nrf_qspi_pins_set(NRF_QSPI, &pins); + + if (res != NRFX_SUCCESS) { + return -EIO; + } + + rc = qspi_send_cmd(dev, &cmd, false); + if (rc < 0) { + return rc; } if (t_exit_dpd) { From b172e5133b09ec0c32dbbe74dafa9ef8f2d9da33 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andrzej=20G=C5=82=C4=85bek?= Date: Tue, 21 Nov 2023 08:27:07 +0100 Subject: [PATCH 0002/3723] boards: nrf52840dk_nrf52840: Fix reserved GPIO lines MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This is a follow-up to commit 7a83724e0f18d7f2400517407150f9e9a1ecd6e6. There is no reason to mark that many GPIO lines as reserved on this board. And doing so causes several existing tests to fail as they are configured to use some of those now unavailable GPIO lines. Limit reservation to the lines that actually cannot be used as GPIOs without changes in the default configuration of the board or its physical modification (via solder bridges), i.e.: - XL1 and XL2 (connections for the 32.768 kHz crystal) - NFC1 and NFC2 (NFC antenna connections) - RESET - TXD and RXD (lines used by the console UART) - QSPI lines: CS, CLK, and DIO0-3 Provide names for all the GPIO lines that are described on the board. Even for the reserved ones, so that it is clear why they are reserved. Signed-off-by: Andrzej Głąbek --- .../nrf52840dk_nrf52840/nrf52840dk_nrf52840.dts | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/boards/arm/nrf52840dk_nrf52840/nrf52840dk_nrf52840.dts b/boards/arm/nrf52840dk_nrf52840/nrf52840dk_nrf52840.dts index dcee7b0db5f..60c3ecf55a1 100644 --- a/boards/arm/nrf52840dk_nrf52840/nrf52840dk_nrf52840.dts +++ b/boards/arm/nrf52840dk_nrf52840/nrf52840dk_nrf52840.dts @@ -149,18 +149,18 @@ &gpio0 { status = "okay"; - gpio-reserved-ranges = <0 11>, <17 7>, <26 6>; - gpio-line-names = "", "", "", "", "", "", "", "", - "", "", "", "BUTTON1", "BUTTON2", "LED1", "LED2", "LED3", - "LED4", "", "", "", "", "", "", "", - "BUTTON3", "BUTTON4", "", "", "", "", "", ""; + gpio-reserved-ranges = <0 2>, <6 1>, <8 3>, <17 7>; + gpio-line-names = "XL1", "XL2", "AREF", "A0", "A1", "RTS", "TXD", + "CTS", "RXD", "NFC1", "NFC2", "BUTTON1", "BUTTON2", "LED1", + "LED2", "LED3", "LED4", "QSPI CS", "RESET", "QSPI CLK", + "QSPI DIO0", "QSPI DIO1", "QSPI DIO2", "QSPI DIO3","BUTTON3", + "BUTTON4", "SDA", "SCL", "A2", "A3", "A4", "A5"; }; &gpio1 { status = "okay"; - gpio-reserved-ranges = <0 1>, <9 1>, <12 4>; gpio-line-names = "", "D0", "D1", "D2", "D3", "D4", "D5", "D6", - "D7", "", "D8", "D9", "", "", "", ""; + "D7", "", "D8", "D9", "D10", "D11", "D12", "D13"; }; &uart0 { From 4a4558128848b3cc01a153ab128fb6aa09316a99 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andrzej=20G=C5=82=C4=85bek?= Date: Mon, 6 Nov 2023 14:31:56 +0100 Subject: [PATCH 0003/3723] drivers: nrf_qspi_nor: Clean up handling of return values MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Consistently use `res` for results of calls to nrfx functions and `rc` for Zephyr return codes, to avoid mixing up those two and for example calling `qspi_get_zephyr_ret_code()` for a value that is already a Zephyr return code. Correct also such call in `qspi_nor_write()`. Signed-off-by: Andrzej Głąbek --- drivers/flash/nrf_qspi_nor.c | 248 ++++++++++++++++++----------------- 1 file changed, 125 insertions(+), 123 deletions(-) diff --git a/drivers/flash/nrf_qspi_nor.c b/drivers/flash/nrf_qspi_nor.c index 467d0643d48..ca4673e8aa2 100644 --- a/drivers/flash/nrf_qspi_nor.c +++ b/drivers/flash/nrf_qspi_nor.c @@ -371,7 +371,7 @@ static int qspi_device_init(const struct device *dev) return pm_device_runtime_get(dev); #else nrfx_err_t res; - int ret = 0; + int rc = 0; qspi_lock(dev); @@ -389,13 +389,13 @@ static int qspi_device_init(const struct device *dev) res = nrfx_qspi_init(&dev_config->nrfx_cfg, qspi_handler, dev_data); - ret = qspi_get_zephyr_ret_code(res); - qspi_initialized = (ret == 0); + rc = qspi_get_zephyr_ret_code(res); + qspi_initialized = (rc == 0); } qspi_unlock(dev); - return ret; + return rc; #endif } @@ -408,10 +408,10 @@ static void qspi_device_uninit(const struct device *dev) } #ifdef CONFIG_PM_DEVICE_RUNTIME - int ret = pm_device_runtime_put(dev); + int rc = pm_device_runtime_put(dev); - if (ret < 0) { - LOG_ERR("Failed to schedule device sleep: %d", ret); + if (rc < 0) { + LOG_ERR("Failed to schedule device sleep: %d", rc); } #else bool last = true; @@ -526,27 +526,27 @@ static int qspi_rdsr(const struct device *dev, uint8_t sr_num) .op_code = opcode, .rx_buf = &sr_buf, }; - int ret = qspi_send_cmd(dev, &cmd, false); + int rc = qspi_send_cmd(dev, &cmd, false); - return (ret < 0) ? ret : sr; + return (rc < 0) ? rc : sr; } /* Wait until RDSR confirms write is not in progress. */ static int qspi_wait_while_writing(const struct device *dev) { - int ret; + int rc; do { - ret = qspi_rdsr(dev, 1); - } while ((ret >= 0) - && ((ret & SPI_NOR_WIP_BIT) != 0U)); + rc = qspi_rdsr(dev, 1); + } while ((rc >= 0) + && ((rc & SPI_NOR_WIP_BIT) != 0U)); - return (ret < 0) ? ret : 0; + return (rc < 0) ? rc : 0; } static int qspi_wrsr(const struct device *dev, uint8_t sr_val, uint8_t sr_num) { - int ret = 0; + int rc = 0; uint8_t opcode = SPI_NOR_CMD_WRSR; uint8_t length = 1; uint8_t sr_array[2] = {0}; @@ -559,12 +559,12 @@ static int qspi_wrsr(const struct device *dev, uint8_t sr_val, uint8_t sr_num) sr_array[0] = sr_val; #if SR1_WRITE_CLEARS_SR2 /* Writing sr1 clears sr2. need to read/modify/write both. */ - ret = qspi_rdsr(dev, 2); - if (ret < 0) { - LOG_ERR("RDSR for WRSR failed: %d", ret); - return ret; + rc = qspi_rdsr(dev, 2); + if (rc < 0) { + LOG_ERR("RDSR for WRSR failed: %d", rc); + return rc; } - sr_array[1] = ret; + sr_array[1] = rc; length = 2; #endif } else { /* sr_num == 2 */ @@ -574,12 +574,12 @@ static int qspi_wrsr(const struct device *dev, uint8_t sr_val, uint8_t sr_num) * Uses standard WRSR opcode */ sr_array[1] = sr_val; - ret = qspi_rdsr(dev, 1); - if (ret < 0) { - LOG_ERR("RDSR for WRSR failed: %d", ret); - return ret; + rc = qspi_rdsr(dev, 1); + if (rc < 0) { + LOG_ERR("RDSR for WRSR failed: %d", rc); + return rc; } - sr_array[0] = ret; + sr_array[0] = rc; length = 2; #elif IS_EQUAL(INST_0_QER, JESD216_DW15_QER_VAL_S2B1v6) /* Writing sr2 uses a dedicated WRSR2 command */ @@ -600,17 +600,17 @@ static int qspi_wrsr(const struct device *dev, uint8_t sr_val, uint8_t sr_num) .tx_buf = &sr_buf, }; - ret = qspi_send_cmd(dev, &cmd, true); + rc = qspi_send_cmd(dev, &cmd, true); /* Writing SR can take some time, and further * commands sent while it's happening can be * corrupted. Wait. */ - if (ret == 0) { - ret = qspi_wait_while_writing(dev); + if (rc == 0) { + rc = qspi_wait_while_writing(dev); } - return ret; + return rc; } #endif /* !IS_EQUAL(INST_0_QER, JESD216_DW15_QER_VAL_NONE) */ @@ -627,16 +627,16 @@ static int qspi_erase(const struct device *dev, uint32_t addr, uint32_t size) return -EINVAL; } - int rv = 0; const struct qspi_nor_config *params = dev->config; + int rc, rc2; - rv = qspi_device_init(dev); - if (rv != 0) { + rc = qspi_device_init(dev); + if (rc != 0) { goto out; } qspi_trans_lock(dev); - rv = qspi_nor_write_protection_set(dev, false); - if (rv != 0) { + rc = qspi_nor_write_protection_set(dev, false); + if (rc != 0) { goto out_trans_unlock; } qspi_lock(dev); @@ -670,16 +670,16 @@ static int qspi_erase(const struct device *dev, uint32_t addr, uint32_t size) size -= adj; } else { LOG_ERR("erase error at 0x%lx size %zu", (long)addr, size); - rv = qspi_get_zephyr_ret_code(res); + rc = qspi_get_zephyr_ret_code(res); break; } } qspi_unlock(dev); - int rv2 = qspi_nor_write_protection_set(dev, true); + rc2 = qspi_nor_write_protection_set(dev, true); - if (!rv) { - rv = rv2; + if (!rc) { + rc = rc2; } out_trans_unlock: @@ -687,7 +687,7 @@ static int qspi_erase(const struct device *dev, uint32_t addr, uint32_t size) out: qspi_device_uninit(dev); - return rv; + return rc; } /* Configures QSPI memory for the transfer */ @@ -695,6 +695,8 @@ static int qspi_nrfx_configure(const struct device *dev) { struct qspi_nor_data *dev_data = dev->data; const struct qspi_nor_config *dev_config = dev->config; + nrfx_err_t res; + int rc; #if defined(CONFIG_SOC_SERIES_NRF53X) /* When the QSPI peripheral is activated, during the nrfx_qspi driver @@ -705,18 +707,16 @@ static int qspi_nrfx_configure(const struct device *dev) nrf_clock_hfclk192m_div_set(NRF_CLOCK, BASE_CLOCK_DIV); #endif - nrfx_err_t res = nrfx_qspi_init(&dev_config->nrfx_cfg, - qspi_handler, - dev_data); + res = nrfx_qspi_init(&dev_config->nrfx_cfg, qspi_handler, dev_data); #if defined(CONFIG_SOC_SERIES_NRF53X) /* Restore the default /4 divider after the QSPI initialization. */ nrf_clock_hfclk192m_div_set(NRF_CLOCK, NRF_CLOCK_HFCLK_DIV_4); #endif - int ret = qspi_get_zephyr_ret_code(res); - if (ret < 0) { - return ret; + rc = qspi_get_zephyr_ret_code(res); + if (rc < 0) { + return rc; } #if DT_INST_NODE_HAS_PROP(0, rx_delay) @@ -736,9 +736,9 @@ static int qspi_nrfx_configure(const struct device *dev) * bootloader) might have set DPD mode before reboot. As a result, * attempt to exit DPD mode regardless of whether CONFIG_PM_DEVICE is set. */ - ret = exit_dpd(dev); - if (ret < 0) { - return ret; + rc = exit_dpd(dev); + if (rc < 0) { + return rc; } /* Set QE to match transfer mode. If not using quad @@ -769,28 +769,28 @@ static int qspi_nrfx_configure(const struct device *dev) return -EINVAL; #endif - ret = qspi_rdsr(dev, sr_num); - if (ret < 0) { - LOG_ERR("RDSR failed: %d", ret); - return ret; + rc = qspi_rdsr(dev, sr_num); + if (rc < 0) { + LOG_ERR("RDSR failed: %d", rc); + return rc; } - uint8_t sr = (uint8_t)ret; + uint8_t sr = (uint8_t)rc; bool qe_state = ((sr & qe_mask) != 0U); LOG_DBG("RDSR %02x QE %d need %d: %s", sr, qe_state, qe_value, (qe_state != qe_value) ? "updating" : "no-change"); - ret = 0; + rc = 0; if (qe_state != qe_value) { sr ^= qe_mask; - ret = qspi_wrsr(dev, sr, sr_num); + rc = qspi_wrsr(dev, sr, sr_num); } - if (ret < 0) { + if (rc < 0) { LOG_ERR("QE %s failed: %d", qe_value ? "set" : "clear", - ret); - return ret; + rc); + return rc; } #endif @@ -802,16 +802,16 @@ static int qspi_nrfx_configure(const struct device *dev) /* Call will send write enable before instruction if that * requirement is encoded in INST_0_4BA. */ - ret = qspi_send_cmd(dev, &cmd, (INST_0_4BA & 0x02)); + rc = qspi_send_cmd(dev, &cmd, (INST_0_4BA & 0x02)); - if (ret < 0) { - LOG_ERR("E4BA cmd issue failed: %d.", ret); + if (rc < 0) { + LOG_ERR("E4BA cmd issue failed: %d.", rc); } else { LOG_DBG("E4BA cmd issued."); } } - return ret; + return rc; } static int qspi_read_jedec_id(const struct device *dev, @@ -826,14 +826,14 @@ static int qspi_read_jedec_id(const struct device *dev, .rx_buf = &rx_buf, }; - int ret = qspi_device_init(dev); + int rc = qspi_device_init(dev); - if (ret == 0) { - ret = qspi_send_cmd(dev, &cmd, false); + if (rc == 0) { + rc = qspi_send_cmd(dev, &cmd, false); } qspi_device_uninit(dev); - return ret; + return rc; } #if defined(CONFIG_FLASH_JESD216_API) @@ -856,13 +856,13 @@ static int qspi_sfdp_read(const struct device *dev, off_t offset, .io3_level = true, }; - int ret = qspi_device_init(dev); + int rc = qspi_device_init(dev); nrfx_err_t res = NRFX_SUCCESS; - if (ret != 0) { - LOG_DBG("qspi_device_init: %d", ret); + if (rc != 0) { + LOG_DBG("qspi_device_init: %d", rc); qspi_device_uninit(dev); - return ret; + return rc; } qspi_lock(dev); @@ -901,9 +901,9 @@ static int qspi_sfdp_read(const struct device *dev, off_t offset, static inline int qspi_nor_read_id(const struct device *dev) { uint8_t id[SPI_NOR_MAX_ID_LEN]; - int ret = qspi_read_jedec_id(dev, id); + int rc = qspi_read_jedec_id(dev, id); - if (ret != 0) { + if (rc != 0) { return -EIO; } @@ -1109,6 +1109,7 @@ static int qspi_nor_write(const struct device *dev, off_t addr, } const struct qspi_nor_config *params = dev->config; + int rc, rc2; /* affected region should be within device */ if (addr < 0 || @@ -1119,18 +1120,18 @@ static int qspi_nor_write(const struct device *dev, off_t addr, return -EINVAL; } - nrfx_err_t res = NRFX_SUCCESS; - - int rc = qspi_device_init(dev); + rc = qspi_device_init(dev); if (rc != 0) { goto out; } qspi_trans_lock(dev); - res = qspi_nor_write_protection_set(dev, false); + rc = qspi_nor_write_protection_set(dev, false); qspi_lock(dev); - if (!res) { + if (rc == 0) { + nrfx_err_t res; + if (size < 4U) { res = write_sub_word(dev, addr, src, size); } else if (!nrfx_is_in_ram(src) || @@ -1140,17 +1141,18 @@ static int qspi_nor_write(const struct device *dev, off_t addr, res = nrfx_qspi_write(src, size, addr); qspi_wait_for_completion(dev, res); } + + rc = qspi_get_zephyr_ret_code(res); } qspi_unlock(dev); - int res2 = qspi_nor_write_protection_set(dev, true); + rc2 = qspi_nor_write_protection_set(dev, true); qspi_trans_unlock(dev); - if (!res) { - res = res2; + if (rc == 0) { + rc = rc2; } - rc = qspi_get_zephyr_ret_code(res); out: qspi_device_uninit(dev); return rc; @@ -1169,24 +1171,24 @@ static int qspi_nor_erase(const struct device *dev, off_t addr, size_t size) return -EINVAL; } - int ret = qspi_erase(dev, addr, size); + int rc = qspi_erase(dev, addr, size); - return ret; + return rc; } static int qspi_nor_write_protection_set(const struct device *dev, bool write_protect) { - int ret = 0; + int rc = 0; struct qspi_cmd cmd = { .op_code = ((write_protect) ? SPI_NOR_CMD_WRDI : SPI_NOR_CMD_WREN), }; if (qspi_send_cmd(dev, &cmd, false) != 0) { - ret = -EIO; + rc = -EIO; } - return ret; + return rc; } /** @@ -1198,16 +1200,16 @@ static int qspi_nor_write_protection_set(const struct device *dev, */ static int qspi_nor_configure(const struct device *dev) { - int ret = qspi_nrfx_configure(dev); + int rc = qspi_nrfx_configure(dev); - if (ret != 0) { - return ret; + if (rc != 0) { + return rc; } #ifdef CONFIG_PM_DEVICE_RUNTIME - ret = pm_device_runtime_enable(dev); - if (ret < 0) { - LOG_ERR("Failed to enable runtime power management: %d", ret); + rc = pm_device_runtime_enable(dev); + if (rc < 0) { + LOG_ERR("Failed to enable runtime power management: %d", rc); } else { LOG_DBG("Runtime power management enabled"); } @@ -1231,12 +1233,12 @@ static int qspi_nor_configure(const struct device *dev) */ static int qspi_nor_init(const struct device *dev) { - int rc; const struct qspi_nor_config *dev_config = dev->config; - int ret = pinctrl_apply_state(dev_config->pcfg, PINCTRL_STATE_DEFAULT); + int rc; - if (ret < 0) { - return ret; + rc = pinctrl_apply_state(dev_config->pcfg, PINCTRL_STATE_DEFAULT); + if (rc < 0) { + return rc; } IRQ_CONNECT(DT_IRQN(QSPI_NODE), DT_IRQ(QSPI_NODE, priority), @@ -1317,11 +1319,11 @@ static int enter_dpd(const struct device *const dev) .op_code = SPI_NOR_CMD_DPD, }; uint32_t t_enter_dpd = DT_INST_PROP_OR(0, t_enter_dpd, 0); - int ret; + int rc; - ret = qspi_send_cmd(dev, &cmd, false); - if (ret < 0) { - return ret; + rc = qspi_send_cmd(dev, &cmd, false); + if (rc < 0) { + return rc; } if (t_enter_dpd) { @@ -1386,8 +1388,8 @@ static int qspi_nor_pm_action(const struct device *dev, { struct qspi_nor_data *dev_data = dev->data; const struct qspi_nor_config *dev_config = dev->config; - int ret; - nrfx_err_t err; + int rc; + nrfx_err_t res; if (pm_device_is_busy(dev)) { return -EBUSY; @@ -1397,9 +1399,9 @@ static int qspi_nor_pm_action(const struct device *dev, case PM_DEVICE_ACTION_SUSPEND: #ifndef CONFIG_PM_DEVICE_RUNTIME /* If PM_DEVICE_RUNTIME, we don't uninit after RESUME */ - ret = qspi_device_init(dev); - if (ret < 0) { - return ret; + rc = qspi_device_init(dev); + if (rc < 0) { + return rc; } #endif @@ -1411,35 +1413,35 @@ static int qspi_nor_pm_action(const struct device *dev, return -EBUSY; } - ret = enter_dpd(dev); - if (ret < 0) { - return ret; + rc = enter_dpd(dev); + if (rc < 0) { + return rc; } nrfx_qspi_uninit(); - ret = pinctrl_apply_state(dev_config->pcfg, + rc = pinctrl_apply_state(dev_config->pcfg, PINCTRL_STATE_SLEEP); - if (ret < 0) { - return ret; + if (rc < 0) { + return rc; } break; case PM_DEVICE_ACTION_RESUME: - ret = pinctrl_apply_state(dev_config->pcfg, + rc = pinctrl_apply_state(dev_config->pcfg, PINCTRL_STATE_DEFAULT); - if (ret < 0) { - return ret; + if (rc < 0) { + return rc; } - err = nrfx_qspi_init(&dev_config->nrfx_cfg, + res = nrfx_qspi_init(&dev_config->nrfx_cfg, qspi_handler, dev_data); - if (err != NRFX_SUCCESS) { + if (res != NRFX_SUCCESS) { return -EIO; } - ret = exit_dpd(dev); - if (ret < 0) { - return ret; + rc = exit_dpd(dev); + if (rc < 0) { + return rc; } #ifndef CONFIG_PM_DEVICE_RUNTIME @@ -1459,16 +1461,16 @@ static int qspi_nor_pm_action(const struct device *dev, void z_impl_nrf_qspi_nor_xip_enable(const struct device *dev, bool enable) { struct qspi_nor_data *dev_data = dev->data; - int ret; + int rc; if (dev_data->xip_enabled == enable) { return; } - ret = qspi_device_init(dev); + rc = qspi_device_init(dev); - if (ret != 0) { - LOG_ERR("NRF QSPI NOR XIP %s failed with %d\n", enable ? "enable" : "disable", ret); + if (rc != 0) { + LOG_ERR("NRF QSPI NOR XIP %s failed with %d\n", enable ? "enable" : "disable", rc); return; } From 8c3df0aa9e9a8e7fe864b07ece840610009b3069 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andrzej=20G=C5=82=C4=85bek?= Date: Mon, 6 Nov 2023 14:10:19 +0100 Subject: [PATCH 0004/3723] drivers: nrf_qspi_nor: Refactor deactivation and locking access to QSPI MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit After integration of nrfx 3.2.0, it is no longer needed to deinitialize the nrfx_qspi driver to avoid increased power consumption when the QSPI peripheral is idle. Now it is enough to call `nrfx_qspi_dectivate()` when a given operation is done. The driver will automatically activate the QSPI peripheral again when a next operation is requested. This commit applies the following changes: - `qspi_device_init` and `qspi_device_uninit` functions are replaced by `qspi_acquire` and `qspi_release`, respectively; those handle exclusive access to the QSPI peripheral and deactivation of it or runtime device power management - locking is removed from `qspi_send_cmd` as it is the resposibility of the caller of that function - `trans_lock` and `trans_unlock` functions are removed together with the related semaphore as they are no longer needed - checking of input parameters is moved from `qspi_erase` to its caller, `qspi_nor_erase` - `qspi_nor_pm_action` is refactored to properly handle locking of the QSPI peripheral; checking of the `xip_enabled` flag is removed from that function as now the call to `pm_device_is_busy()` covers that (when XIP is enabled, the device is kept indicated as busy) Signed-off-by: Andrzej Głąbek --- drivers/flash/nrf_qspi_nor.c | 507 +++++++++++++---------------------- 1 file changed, 193 insertions(+), 314 deletions(-) diff --git a/drivers/flash/nrf_qspi_nor.c b/drivers/flash/nrf_qspi_nor.c index ca4673e8aa2..aa6449763be 100644 --- a/drivers/flash/nrf_qspi_nor.c +++ b/drivers/flash/nrf_qspi_nor.c @@ -26,15 +26,15 @@ LOG_MODULE_REGISTER(qspi_nor, CONFIG_FLASH_LOG_LEVEL); #include struct qspi_nor_data { +#if !defined(CONFIG_PM_DEVICE_RUNTIME) && defined(CONFIG_MULTITHREADING) + /* A semaphore to control QSPI deactivation. */ + struct k_sem count; +#endif #ifdef CONFIG_MULTITHREADING - /* The semaphore to control exclusive access on write/erase. */ - struct k_sem trans; /* The semaphore to control exclusive access to the device. */ struct k_sem sem; /* The semaphore to indicate that transfer has completed. */ struct k_sem sync; - /* The semaphore to control driver init/uninit. */ - struct k_sem count; #else /* CONFIG_MULTITHREADING */ /* A flag that signals completed transfer when threads are * not enabled. @@ -173,12 +173,6 @@ BUILD_ASSERT(DT_INST_PROP(0, address_size_32), "After entering 4 byte addressing mode, 4 byte addressing is expected"); #endif -#ifndef CONFIG_PM_DEVICE_RUNTIME -static bool qspi_initialized; -#endif - -static int qspi_device_init(const struct device *dev); -static void qspi_device_uninit(const struct device *dev); void z_impl_nrf_qspi_nor_xip_enable(const struct device *dev, bool enable); void z_vrfy_nrf_qspi_nor_xip_enable(const struct device *dev, bool enable); @@ -245,72 +239,99 @@ static inline int qspi_get_zephyr_ret_code(nrfx_err_t res) static inline void qspi_lock(const struct device *dev) { +#ifdef CONFIG_MULTITHREADING struct qspi_nor_data *dev_data = dev->data; - pm_device_busy_set(dev); - -#ifdef CONFIG_MULTITHREADING k_sem_take(&dev_data->sem, K_FOREVER); -#else /* CONFIG_MULTITHREADING */ - ARG_UNUSED(dev_data); -#endif /* CONFIG_MULTITHREADING */ - - /* - * Change the base clock divider only for the time the driver is locked - * to perform a QSPI operation, otherwise the power consumption would be - * increased also when the QSPI peripheral is idle. - * When XIP is enabled, there is nothing to do here as the changed - * divider is kept all the time. - */ -#if defined(CONFIG_SOC_SERIES_NRF53X) - if (!dev_data->xip_enabled) { - nrf_clock_hfclk192m_div_set(NRF_CLOCK, BASE_CLOCK_DIV); - } #endif } static inline void qspi_unlock(const struct device *dev) { +#ifdef CONFIG_MULTITHREADING struct qspi_nor_data *dev_data = dev->data; -#if defined(CONFIG_SOC_SERIES_NRF53X) - /* Restore the default base clock divider to reduce power consumption. - * Unless XIP is enabled, then the changed divider needs to be kept. - */ - if (!dev_data->xip_enabled) { - nrf_clock_hfclk192m_div_set(NRF_CLOCK, NRF_CLOCK_HFCLK_DIV_4); - } + k_sem_give(&dev_data->sem); #endif +} -#ifdef CONFIG_MULTITHREADING - k_sem_give(&dev_data->sem); -#else - ARG_UNUSED(dev_data); +static inline void qspi_clock_div_change(void) +{ +#ifdef CONFIG_SOC_SERIES_NRF53X + /* Make sure the base clock divider is changed accordingly + * before a QSPI transfer is performed. + */ + nrf_clock_hfclk192m_div_set(NRF_CLOCK, BASE_CLOCK_DIV); #endif +} - pm_device_busy_clear(dev); +static inline void qspi_clock_div_restore(void) +{ +#ifdef CONFIG_SOC_SERIES_NRF53X + /* Restore the default base clock divider to reduce power + * consumption when the QSPI peripheral is idle. + */ + nrf_clock_hfclk192m_div_set(NRF_CLOCK, NRF_CLOCK_HFCLK_DIV_4); +#endif } -static inline void qspi_trans_lock(const struct device *dev) +static void qspi_acquire(const struct device *dev) { -#ifdef CONFIG_MULTITHREADING struct qspi_nor_data *dev_data = dev->data; - k_sem_take(&dev_data->trans, K_FOREVER); -#else /* CONFIG_MULTITHREADING */ - ARG_UNUSED(dev); -#endif /* CONFIG_MULTITHREADING */ +#if defined(CONFIG_PM_DEVICE_RUNTIME) + int rc = pm_device_runtime_get(dev); + + if (rc < 0) { + LOG_ERR("pm_device_runtime_get failed: %d", rc); + } +#elif defined(CONFIG_MULTITHREADING) + /* In multithreading, the driver can call qspi_acquire more than once + * before calling qspi_release. Keeping count, so QSPI is deactivated + * only at the last call (count == 0). + */ + k_sem_give(&dev_data->count); +#endif + + qspi_lock(dev); + + if (!dev_data->xip_enabled) { + qspi_clock_div_change(); + + pm_device_busy_set(dev); + } } -static inline void qspi_trans_unlock(const struct device *dev) +static void qspi_release(const struct device *dev) { -#ifdef CONFIG_MULTITHREADING struct qspi_nor_data *dev_data = dev->data; + bool deactivate = true; - k_sem_give(&dev_data->trans); -#else /* CONFIG_MULTITHREADING */ - ARG_UNUSED(dev); -#endif /* CONFIG_MULTITHREADING */ +#if !defined(CONFIG_PM_DEVICE_RUNTIME) && defined(CONFIG_MULTITHREADING) + /* The last thread to finish using the driver deactivates the QSPI */ + (void) k_sem_take(&dev_data->count, K_NO_WAIT); + deactivate = (k_sem_count_get(&dev_data->count) == 0); +#endif + + if (!dev_data->xip_enabled) { + qspi_clock_div_restore(); + + if (deactivate && !IS_ENABLED(CONFIG_PM_DEVICE_RUNTIME)) { + (void) nrfx_qspi_deactivate(); + } + + pm_device_busy_clear(dev); + } + + qspi_unlock(dev); + +#if defined(CONFIG_PM_DEVICE_RUNTIME) + int rc = pm_device_runtime_put(dev); + + if (rc < 0) { + LOG_ERR("pm_device_runtime_put failed: %d", rc); + } +#endif } static inline void qspi_wait_for_completion(const struct device *dev, @@ -359,89 +380,6 @@ static void qspi_handler(nrfx_qspi_evt_t event, void *p_context) } } -static int qspi_device_init(const struct device *dev) -{ - struct qspi_nor_data *dev_data = dev->data; - - if (dev_data->xip_enabled) { - return 0; - } - -#ifdef CONFIG_PM_DEVICE_RUNTIME - return pm_device_runtime_get(dev); -#else - nrfx_err_t res; - int rc = 0; - - qspi_lock(dev); - - /* In multithreading, driver can call qspi_device_init more than once - * before calling qspi_device_uninit. Keepping count, so QSPI is - * uninitialized only at the last call (count == 0). - */ -#ifdef CONFIG_MULTITHREADING - k_sem_give(&dev_data->count); -#endif - - if (!qspi_initialized) { - const struct qspi_nor_config *dev_config = dev->config; - - res = nrfx_qspi_init(&dev_config->nrfx_cfg, - qspi_handler, - dev_data); - rc = qspi_get_zephyr_ret_code(res); - qspi_initialized = (rc == 0); - } - - qspi_unlock(dev); - - return rc; -#endif -} - -static void qspi_device_uninit(const struct device *dev) -{ - struct qspi_nor_data *dev_data = dev->data; - - if (dev_data->xip_enabled) { - return; - } - -#ifdef CONFIG_PM_DEVICE_RUNTIME - int rc = pm_device_runtime_put(dev); - - if (rc < 0) { - LOG_ERR("Failed to schedule device sleep: %d", rc); - } -#else - bool last = true; - - qspi_lock(dev); - -#ifdef CONFIG_MULTITHREADING - /* The last thread to finish using the driver uninit the QSPI */ - (void) k_sem_take(&dev_data->count, K_NO_WAIT); - last = (k_sem_count_get(&dev_data->count) == 0); -#endif - - if (last) { - while (nrfx_qspi_mem_busy_check() != NRFX_SUCCESS) { - if (IS_ENABLED(CONFIG_MULTITHREADING)) { - k_msleep(50); - } else { - k_busy_wait(50000); - } - } - - nrfx_qspi_uninit(); - - qspi_initialized = false; - } - - qspi_unlock(dev); -#endif -} - /* QSPI send custom command. * * If this is used for both send and receive the buffer sizes must be @@ -497,11 +435,8 @@ static int qspi_send_cmd(const struct device *dev, const struct qspi_cmd *cmd, .wren = wren, }; - qspi_lock(dev); - int res = nrfx_qspi_cinstr_xfer(&cinstr_cfg, tx_buf, rx_buf); - qspi_unlock(dev); return qspi_get_zephyr_ret_code(res); } @@ -617,29 +552,13 @@ static int qspi_wrsr(const struct device *dev, uint8_t sr_val, uint8_t sr_num) /* QSPI erase */ static int qspi_erase(const struct device *dev, uint32_t addr, uint32_t size) { - /* address must be sector-aligned */ - if ((addr % QSPI_SECTOR_SIZE) != 0) { - return -EINVAL; - } - - /* size must be a non-zero multiple of sectors */ - if ((size == 0) || (size % QSPI_SECTOR_SIZE) != 0) { - return -EINVAL; - } - const struct qspi_nor_config *params = dev->config; int rc, rc2; - rc = qspi_device_init(dev); - if (rc != 0) { - goto out; - } - qspi_trans_lock(dev); rc = qspi_nor_write_protection_set(dev, false); if (rc != 0) { - goto out_trans_unlock; + return rc; } - qspi_lock(dev); while (size > 0) { nrfx_err_t res = !NRFX_SUCCESS; uint32_t adj = 0; @@ -674,20 +593,10 @@ static int qspi_erase(const struct device *dev, uint32_t addr, uint32_t size) break; } } - qspi_unlock(dev); rc2 = qspi_nor_write_protection_set(dev, true); - if (!rc) { - rc = rc2; - } - -out_trans_unlock: - qspi_trans_unlock(dev); - -out: - qspi_device_uninit(dev); - return rc; + return rc != 0 ? rc : rc2; } /* Configures QSPI memory for the transfer */ @@ -698,22 +607,7 @@ static int qspi_nrfx_configure(const struct device *dev) nrfx_err_t res; int rc; -#if defined(CONFIG_SOC_SERIES_NRF53X) - /* When the QSPI peripheral is activated, during the nrfx_qspi driver - * initialization, it reads the status of the connected flash chip. - * Make sure this transaction is performed with a valid base clock - * divider. - */ - nrf_clock_hfclk192m_div_set(NRF_CLOCK, BASE_CLOCK_DIV); -#endif - res = nrfx_qspi_init(&dev_config->nrfx_cfg, qspi_handler, dev_data); - -#if defined(CONFIG_SOC_SERIES_NRF53X) - /* Restore the default /4 divider after the QSPI initialization. */ - nrf_clock_hfclk192m_div_set(NRF_CLOCK, NRF_CLOCK_HFCLK_DIV_4); -#endif - rc = qspi_get_zephyr_ret_code(res); if (rc < 0) { return rc; @@ -814,8 +708,7 @@ static int qspi_nrfx_configure(const struct device *dev) return rc; } -static int qspi_read_jedec_id(const struct device *dev, - uint8_t *id) +static int qspi_rdid(const struct device *dev, uint8_t *id) { const struct qspi_buf rx_buf = { .buf = id, @@ -826,18 +719,24 @@ static int qspi_read_jedec_id(const struct device *dev, .rx_buf = &rx_buf, }; - int rc = qspi_device_init(dev); + return qspi_send_cmd(dev, &cmd, false); +} - if (rc == 0) { - rc = qspi_send_cmd(dev, &cmd, false); - } - qspi_device_uninit(dev); +#if defined(CONFIG_FLASH_JESD216_API) + +static int qspi_read_jedec_id(const struct device *dev, uint8_t *id) +{ + int rc; + + qspi_acquire(dev); + + rc = qspi_rdid(dev, id); + + qspi_release(dev); return rc; } -#if defined(CONFIG_FLASH_JESD216_API) - static int qspi_sfdp_read(const struct device *dev, off_t offset, void *data, size_t len) { @@ -855,17 +754,10 @@ static int qspi_sfdp_read(const struct device *dev, off_t offset, .io2_level = true, .io3_level = true, }; + nrfx_err_t res; - int rc = qspi_device_init(dev); - nrfx_err_t res = NRFX_SUCCESS; - - if (rc != 0) { - LOG_DBG("qspi_device_init: %d", rc); - qspi_device_uninit(dev); - return rc; - } + qspi_acquire(dev); - qspi_lock(dev); res = nrfx_qspi_lfm_start(&cinstr_cfg); if (res != NRFX_SUCCESS) { LOG_DBG("lfm_start: %x", res); @@ -885,8 +777,8 @@ static int qspi_sfdp_read(const struct device *dev, off_t offset, } out: - qspi_unlock(dev); - qspi_device_uninit(dev); + qspi_release(dev); + return qspi_get_zephyr_ret_code(res); } @@ -901,7 +793,7 @@ static int qspi_sfdp_read(const struct device *dev, off_t offset, static inline int qspi_nor_read_id(const struct device *dev) { uint8_t id[SPI_NOR_MAX_ID_LEN]; - int rc = qspi_read_jedec_id(dev, id); + int rc = qspi_rdid(dev, id); if (rc != 0) { return -EIO; @@ -993,6 +885,9 @@ static inline nrfx_err_t read_non_aligned(const struct device *dev, static int qspi_nor_read(const struct device *dev, off_t addr, void *dest, size_t size) { + const struct qspi_nor_config *params = dev->config; + nrfx_err_t res; + if (!dest) { return -EINVAL; } @@ -1002,8 +897,6 @@ static int qspi_nor_read(const struct device *dev, off_t addr, void *dest, return 0; } - const struct qspi_nor_config *params = dev->config; - /* affected region should be within device */ if (addr < 0 || (addr + size) > params->size) { @@ -1013,23 +906,13 @@ static int qspi_nor_read(const struct device *dev, off_t addr, void *dest, return -EINVAL; } - int rc = qspi_device_init(dev); - - if (rc != 0) { - goto out; - } - - qspi_lock(dev); - - nrfx_err_t res = read_non_aligned(dev, addr, dest, size); + qspi_acquire(dev); - qspi_unlock(dev); + res = read_non_aligned(dev, addr, dest, size); - rc = qspi_get_zephyr_ret_code(res); + qspi_release(dev); -out: - qspi_device_uninit(dev); - return rc; + return qspi_get_zephyr_ret_code(res); } /* addr aligned, sptr not null, slen less than 4 */ @@ -1094,6 +977,9 @@ static int qspi_nor_write(const struct device *dev, off_t addr, const void *src, size_t size) { + const struct qspi_nor_config *params = dev->config; + int rc, rc2; + if (!src) { return -EINVAL; } @@ -1108,9 +994,6 @@ static int qspi_nor_write(const struct device *dev, off_t addr, return -EINVAL; } - const struct qspi_nor_config *params = dev->config; - int rc, rc2; - /* affected region should be within device */ if (addr < 0 || (addr + size) > params->size) { @@ -1120,15 +1003,9 @@ static int qspi_nor_write(const struct device *dev, off_t addr, return -EINVAL; } + qspi_acquire(dev); - rc = qspi_device_init(dev); - if (rc != 0) { - goto out; - } - - qspi_trans_lock(dev); rc = qspi_nor_write_protection_set(dev, false); - qspi_lock(dev); if (rc == 0) { nrfx_err_t res; @@ -1144,23 +1021,28 @@ static int qspi_nor_write(const struct device *dev, off_t addr, rc = qspi_get_zephyr_ret_code(res); } - qspi_unlock(dev); rc2 = qspi_nor_write_protection_set(dev, true); - qspi_trans_unlock(dev); - if (rc == 0) { - rc = rc2; - } + qspi_release(dev); -out: - qspi_device_uninit(dev); - return rc; + return rc != 0 ? rc : rc2; } static int qspi_nor_erase(const struct device *dev, off_t addr, size_t size) { const struct qspi_nor_config *params = dev->config; + int rc; + + /* address must be sector-aligned */ + if ((addr % QSPI_SECTOR_SIZE) != 0) { + return -EINVAL; + } + + /* size must be a non-zero multiple of sectors */ + if ((size == 0) || (size % QSPI_SECTOR_SIZE) != 0) { + return -EINVAL; + } /* affected region should be within device */ if (addr < 0 || @@ -1171,7 +1053,11 @@ static int qspi_nor_erase(const struct device *dev, off_t addr, size_t size) return -EINVAL; } - int rc = qspi_erase(dev, addr, size); + qspi_acquire(dev); + + rc = qspi_erase(dev, addr, size); + + qspi_release(dev); return rc; } @@ -1206,17 +1092,6 @@ static int qspi_nor_configure(const struct device *dev) return rc; } -#ifdef CONFIG_PM_DEVICE_RUNTIME - rc = pm_device_runtime_enable(dev); - if (rc < 0) { - LOG_ERR("Failed to enable runtime power management: %d", rc); - } else { - LOG_DBG("Runtime power management enabled"); - } -#else - qspi_device_uninit(dev); -#endif - /* now the spi bus is configured, we can verify the flash id */ if (qspi_nor_read_id(dev) != 0) { return -ENODEV; @@ -1244,10 +1119,24 @@ static int qspi_nor_init(const struct device *dev) IRQ_CONNECT(DT_IRQN(QSPI_NODE), DT_IRQ(QSPI_NODE, priority), nrfx_isr, nrfx_qspi_irq_handler, 0); + qspi_clock_div_change(); + rc = qspi_nor_configure(dev); + qspi_clock_div_restore(); + +#ifdef CONFIG_PM_DEVICE_RUNTIME + int rc2 = pm_device_runtime_enable(dev); + + if (rc2 < 0) { + LOG_ERR("Failed to enable runtime power management: %d", rc2); + } else { + LOG_DBG("Runtime power management enabled"); + } +#endif + #ifdef CONFIG_NORDIC_QSPI_NOR_XIP - if (!rc) { + if (rc == 0) { /* Enable XIP mode for QSPI NOR flash, this will prevent the * flash from being powered down */ @@ -1383,108 +1272,97 @@ static int exit_dpd(const struct device *const dev) } #ifdef CONFIG_PM_DEVICE -static int qspi_nor_pm_action(const struct device *dev, - enum pm_device_action action) +static int qspi_suspend(const struct device *dev) { - struct qspi_nor_data *dev_data = dev->data; const struct qspi_nor_config *dev_config = dev->config; - int rc; nrfx_err_t res; + int rc; - if (pm_device_is_busy(dev)) { + res = nrfx_qspi_mem_busy_check(); + if (res != NRFX_SUCCESS) { return -EBUSY; } - switch (action) { - case PM_DEVICE_ACTION_SUSPEND: -#ifndef CONFIG_PM_DEVICE_RUNTIME - /* If PM_DEVICE_RUNTIME, we don't uninit after RESUME */ - rc = qspi_device_init(dev); - if (rc < 0) { - return rc; - } -#endif + rc = enter_dpd(dev); + if (rc < 0) { + return rc; + } - if (dev_data->xip_enabled) { - return -EBUSY; - } + nrfx_qspi_uninit(); - if (nrfx_qspi_mem_busy_check() != NRFX_SUCCESS) { - return -EBUSY; - } + return pinctrl_apply_state(dev_config->pcfg, PINCTRL_STATE_SLEEP); +} - rc = enter_dpd(dev); - if (rc < 0) { - return rc; - } +static int qspi_resume(const struct device *dev) +{ + const struct qspi_nor_config *dev_config = dev->config; + nrfx_err_t res; + int rc; - nrfx_qspi_uninit(); - rc = pinctrl_apply_state(dev_config->pcfg, - PINCTRL_STATE_SLEEP); - if (rc < 0) { - return rc; - } - break; + rc = pinctrl_apply_state(dev_config->pcfg, PINCTRL_STATE_DEFAULT); + if (rc < 0) { + return rc; + } - case PM_DEVICE_ACTION_RESUME: - rc = pinctrl_apply_state(dev_config->pcfg, - PINCTRL_STATE_DEFAULT); - if (rc < 0) { - return rc; - } - res = nrfx_qspi_init(&dev_config->nrfx_cfg, - qspi_handler, - dev_data); - if (res != NRFX_SUCCESS) { - return -EIO; - } + res = nrfx_qspi_init(&dev_config->nrfx_cfg, qspi_handler, dev->data); + if (res != NRFX_SUCCESS) { + return -EIO; + } - rc = exit_dpd(dev); - if (rc < 0) { - return rc; - } + return exit_dpd(dev); +} -#ifndef CONFIG_PM_DEVICE_RUNTIME - /* If PM_DEVICE_RUNTIME, we're immediately going to use the device */ - qspi_device_uninit(dev); -#endif +static int qspi_nor_pm_action(const struct device *dev, + enum pm_device_action action) +{ + int rc; + + if (pm_device_is_busy(dev)) { + return -EBUSY; + } + + qspi_lock(dev); + qspi_clock_div_change(); + + switch (action) { + case PM_DEVICE_ACTION_SUSPEND: + rc = qspi_suspend(dev); + break; + + case PM_DEVICE_ACTION_RESUME: + rc = qspi_resume(dev); break; default: - return -ENOTSUP; + rc = -ENOTSUP; } - return 0; + qspi_clock_div_restore(); + qspi_unlock(dev); + + return rc; } #endif /* CONFIG_PM_DEVICE */ void z_impl_nrf_qspi_nor_xip_enable(const struct device *dev, bool enable) { struct qspi_nor_data *dev_data = dev->data; - int rc; if (dev_data->xip_enabled == enable) { return; } - rc = qspi_device_init(dev); - - if (rc != 0) { - LOG_ERR("NRF QSPI NOR XIP %s failed with %d\n", enable ? "enable" : "disable", rc); - return; - } + qspi_acquire(dev); #if NRF_QSPI_HAS_XIPEN nrf_qspi_xip_set(NRF_QSPI, enable); #endif - qspi_lock(dev); if (enable) { (void)nrfx_qspi_activate(false); } dev_data->xip_enabled = enable; - qspi_unlock(dev); - qspi_device_uninit(dev); + qspi_release(dev); } #ifdef CONFIG_USERSPACE @@ -1502,11 +1380,12 @@ void z_vrfy_nrf_qspi_nor_xip_enable(const struct device *dev, bool enable) #endif /* CONFIG_USERSPACE */ static struct qspi_nor_data qspi_nor_dev_data = { +#if !defined(CONFIG_PM_DEVICE_RUNTIME) && defined(CONFIG_MULTITHREADING) + .count = Z_SEM_INITIALIZER(qspi_nor_dev_data.count, 0, K_SEM_MAX_LIMIT), +#endif #ifdef CONFIG_MULTITHREADING - .trans = Z_SEM_INITIALIZER(qspi_nor_dev_data.trans, 1, 1), .sem = Z_SEM_INITIALIZER(qspi_nor_dev_data.sem, 1, 1), .sync = Z_SEM_INITIALIZER(qspi_nor_dev_data.sync, 0, 1), - .count = Z_SEM_INITIALIZER(qspi_nor_dev_data.count, 0, K_SEM_MAX_LIMIT), #endif /* CONFIG_MULTITHREADING */ }; From ea1be7f242b9348863a27adb17215014f15b318a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andrzej=20G=C5=82=C4=85bek?= Date: Fri, 10 Nov 2023 16:52:12 +0100 Subject: [PATCH 0005/3723] drivers: nrf_qspi_nor: Fix and refactor driver initialization MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit So far the driver first changed the configuration of the flash chip and after that checked the signature of that chip. This could lead to improper change of the chip configuration if the actually found one was different than that specified in devicetree. This commit reverses the order of these two initialization steps and also restructures a bit the initialization code. Signed-off-by: Andrzej Głąbek --- drivers/flash/nrf_qspi_nor.c | 125 +++++++++++++---------------------- 1 file changed, 45 insertions(+), 80 deletions(-) diff --git a/drivers/flash/nrf_qspi_nor.c b/drivers/flash/nrf_qspi_nor.c index aa6449763be..d6695989857 100644 --- a/drivers/flash/nrf_qspi_nor.c +++ b/drivers/flash/nrf_qspi_nor.c @@ -599,41 +599,10 @@ static int qspi_erase(const struct device *dev, uint32_t addr, uint32_t size) return rc != 0 ? rc : rc2; } -/* Configures QSPI memory for the transfer */ -static int qspi_nrfx_configure(const struct device *dev) +static int configure_chip(const struct device *dev) { - struct qspi_nor_data *dev_data = dev->data; const struct qspi_nor_config *dev_config = dev->config; - nrfx_err_t res; - int rc; - - res = nrfx_qspi_init(&dev_config->nrfx_cfg, qspi_handler, dev_data); - rc = qspi_get_zephyr_ret_code(res); - if (rc < 0) { - return rc; - } - -#if DT_INST_NODE_HAS_PROP(0, rx_delay) - if (!nrf53_errata_121()) { - nrf_qspi_iftiming_set(NRF_QSPI, DT_INST_PROP(0, rx_delay)); - } -#endif - - /* It may happen that after the flash chip was previously put into - * the DPD mode, the system was reset but the flash chip was not. - * Consequently, the flash chip can be in the DPD mode at this point. - * Some flash chips will just exit the DPD mode on the first CS pulse, - * but some need to receive the dedicated command to do it, so send it. - * This can be the case even if the current image does not have - * CONFIG_PM_DEVICE set to enter DPD mode, as a previously executing image - * (for example the main image if the currently executing image is the - * bootloader) might have set DPD mode before reboot. As a result, - * attempt to exit DPD mode regardless of whether CONFIG_PM_DEVICE is set. - */ - rc = exit_dpd(dev); - if (rc < 0) { - return rc; - } + int rc = 0; /* Set QE to match transfer mode. If not using quad * it's OK to leave QE set, but doing so prevents use @@ -784,33 +753,6 @@ static int qspi_sfdp_read(const struct device *dev, off_t offset, #endif /* CONFIG_FLASH_JESD216_API */ -/** - * @brief Retrieve the Flash JEDEC ID and compare it with the one expected - * - * @param dev The device structure - * @return 0 on success, negative errno code otherwise - */ -static inline int qspi_nor_read_id(const struct device *dev) -{ - uint8_t id[SPI_NOR_MAX_ID_LEN]; - int rc = qspi_rdid(dev, id); - - if (rc != 0) { - return -EIO; - } - - const struct qspi_nor_config *qnc = dev->config; - - if (memcmp(qnc->id, id, SPI_NOR_MAX_ID_LEN) != 0) { - LOG_ERR("JEDEC id [%02x %02x %02x] expect [%02x %02x %02x]", - id[0], id[1], id[2], - qnc->id[0], qnc->id[1], qnc->id[2]); - return -ENODEV; - } - - return 0; -} - static inline nrfx_err_t read_non_aligned(const struct device *dev, off_t addr, void *dest, size_t size) @@ -1077,35 +1019,58 @@ static int qspi_nor_write_protection_set(const struct device *dev, return rc; } -/** - * @brief Configure the flash - * - * @param dev The flash device structure - * @param info The flash info structure - * @return 0 on success, negative errno code otherwise - */ -static int qspi_nor_configure(const struct device *dev) +static int qspi_init(const struct device *dev) { - int rc = qspi_nrfx_configure(dev); + const struct qspi_nor_config *dev_config = dev->config; + uint8_t id[SPI_NOR_MAX_ID_LEN]; + nrfx_err_t res; + int rc; - if (rc != 0) { + res = nrfx_qspi_init(&dev_config->nrfx_cfg, qspi_handler, dev->data); + rc = qspi_get_zephyr_ret_code(res); + if (rc < 0) { + return rc; + } + +#if DT_INST_NODE_HAS_PROP(0, rx_delay) + if (!nrf53_errata_121()) { + nrf_qspi_iftiming_set(NRF_QSPI, DT_INST_PROP(0, rx_delay)); + } +#endif + + /* It may happen that after the flash chip was previously put into + * the DPD mode, the system was reset but the flash chip was not. + * Consequently, the flash chip can be in the DPD mode at this point. + * Some flash chips will just exit the DPD mode on the first CS pulse, + * but some need to receive the dedicated command to do it, so send it. + * This can be the case even if the current image does not have + * CONFIG_PM_DEVICE set to enter DPD mode, as a previously executing image + * (for example the main image if the currently executing image is the + * bootloader) might have set DPD mode before reboot. As a result, + * attempt to exit DPD mode regardless of whether CONFIG_PM_DEVICE is set. + */ + rc = exit_dpd(dev); + if (rc < 0) { + return rc; + } + + /* Retrieve the Flash JEDEC ID and compare it with the one expected. */ + rc = qspi_rdid(dev, id); + if (rc < 0) { return rc; } - /* now the spi bus is configured, we can verify the flash id */ - if (qspi_nor_read_id(dev) != 0) { + if (memcmp(dev_config->id, id, SPI_NOR_MAX_ID_LEN) != 0) { + LOG_ERR("JEDEC id [%02x %02x %02x] expect [%02x %02x %02x]", + id[0], id[1], id[2], dev_config->id[0], + dev_config->id[1], dev_config->id[2]); return -ENODEV; } - return 0; + /* The chip is correct, it can be configured now. */ + return configure_chip(dev); } -/** - * @brief Initialize and configure the flash - * - * @param name The flash name - * @return 0 on success, negative errno code otherwise - */ static int qspi_nor_init(const struct device *dev) { const struct qspi_nor_config *dev_config = dev->config; @@ -1121,7 +1086,7 @@ static int qspi_nor_init(const struct device *dev) qspi_clock_div_change(); - rc = qspi_nor_configure(dev); + rc = qspi_init(dev); qspi_clock_div_restore(); From 7a9ff701d434801b6e7c4b0c4c118b69ea2adf92 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andrzej=20G=C5=82=C4=85bek?= Date: Mon, 30 Oct 2023 15:56:34 +0100 Subject: [PATCH 0006/3723] drivers: pinctrl_nrf: Fix pin drive configuration MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit With the introduction of nrfx 3.0.0, values of `nrf_gpio_pin_drive_t` constants may be defined differently, depending on the SoC family. Since the nrf-pinctrl.h file is included also from dts files, it is not possible to use there different definitions of `NRF_GPIO_PIN_*` values based on Kconfig symbols that indicate given SoC family (as Kconfig is processed after devicetree) so that those values could still match `nrf_gpio_pin_drive_t` constants. To solve this problem, the pinctrl_nrf driver now uses a lookup table for mapping `NRF_GPIO_PIN_*` indexes to drive configuration values required by the GPIO HAL. Signed-off-by: Andrzej Głąbek --- drivers/pinctrl/pinctrl_nrf.c | 48 ++++++++++++------- .../zephyr/dt-bindings/pinctrl/nrf-pinctrl.h | 3 +- 2 files changed, 31 insertions(+), 20 deletions(-) diff --git a/drivers/pinctrl/pinctrl_nrf.c b/drivers/pinctrl/pinctrl_nrf.c index c2ac538c93b..12ee1d52294 100644 --- a/drivers/pinctrl/pinctrl_nrf.c +++ b/drivers/pinctrl/pinctrl_nrf.c @@ -13,19 +13,24 @@ BUILD_ASSERT(((NRF_PULL_NONE == NRF_GPIO_PIN_NOPULL) && (NRF_PULL_UP == NRF_GPIO_PIN_PULLUP)), "nRF pinctrl pull settings do not match HAL values"); -BUILD_ASSERT(((NRF_DRIVE_S0S1 == NRF_GPIO_PIN_S0S1) && - (NRF_DRIVE_H0S1 == NRF_GPIO_PIN_H0S1) && - (NRF_DRIVE_S0H1 == NRF_GPIO_PIN_S0H1) && - (NRF_DRIVE_H0H1 == NRF_GPIO_PIN_H0H1) && - (NRF_DRIVE_D0S1 == NRF_GPIO_PIN_D0S1) && - (NRF_DRIVE_D0H1 == NRF_GPIO_PIN_D0H1) && - (NRF_DRIVE_S0D1 == NRF_GPIO_PIN_S0D1) && - (NRF_DRIVE_H0D1 == NRF_GPIO_PIN_H0D1) && -#if defined(GPIO_PIN_CNF_DRIVE_E0E1) - (NRF_DRIVE_E0E1 == NRF_GPIO_PIN_E0E1) && -#endif /* defined(GPIO_PIN_CNF_DRIVE_E0E1) */ - (1U)), - "nRF pinctrl drive settings do not match HAL values"); +#if defined(GPIO_PIN_CNF_DRIVE_E0E1) || defined(GPIO_PIN_CNF_DRIVE0_E0) +#define NRF_DRIVE_COUNT (NRF_DRIVE_E0E1 + 1) +#else +#define NRF_DRIVE_COUNT (NRF_DRIVE_H0D1 + 1) +#endif +static const nrf_gpio_pin_drive_t drive_modes[NRF_DRIVE_COUNT] = { + [NRF_DRIVE_S0S1] = NRF_GPIO_PIN_S0S1, + [NRF_DRIVE_H0S1] = NRF_GPIO_PIN_H0S1, + [NRF_DRIVE_S0H1] = NRF_GPIO_PIN_S0H1, + [NRF_DRIVE_H0H1] = NRF_GPIO_PIN_H0H1, + [NRF_DRIVE_D0S1] = NRF_GPIO_PIN_D0S1, + [NRF_DRIVE_D0H1] = NRF_GPIO_PIN_D0H1, + [NRF_DRIVE_S0D1] = NRF_GPIO_PIN_S0D1, + [NRF_DRIVE_H0D1] = NRF_GPIO_PIN_H0D1, +#if defined(GPIO_PIN_CNF_DRIVE_E0E1) || defined(GPIO_PIN_CNF_DRIVE0_E0) + [NRF_DRIVE_E0E1] = NRF_GPIO_PIN_E0E1, +#endif +}; /* value to indicate pin level doesn't need initialization */ #define NO_WRITE UINT32_MAX @@ -86,12 +91,19 @@ int pinctrl_configure_pins(const pinctrl_soc_pin_t *pins, uint8_t pin_cnt, uintptr_t reg) { for (uint8_t i = 0U; i < pin_cnt; i++) { - nrf_gpio_pin_drive_t drive = NRF_GET_DRIVE(pins[i]); + nrf_gpio_pin_drive_t drive; + uint8_t drive_idx = NRF_GET_DRIVE(pins[i]); uint32_t psel = NRF_GET_PIN(pins[i]); uint32_t write = NO_WRITE; nrf_gpio_pin_dir_t dir; nrf_gpio_pin_input_t input; + if (drive_idx < ARRAY_SIZE(drive_modes)) { + drive = drive_modes[drive_idx]; + } else { + return -EINVAL; + } + if (psel == NRF_PIN_DISCONNECTED) { psel = PSEL_DISCONNECTED; } @@ -165,22 +177,22 @@ int pinctrl_configure_pins(const pinctrl_soc_pin_t *pins, uint8_t pin_cnt, #if defined(NRF_PSEL_TWIM) case NRF_FUN_TWIM_SCL: NRF_PSEL_TWIM(reg, SCL) = psel; - if (drive == NRF_DRIVE_S0S1) { + if (drive == NRF_GPIO_PIN_S0S1) { /* Override the default drive setting with one * suitable for TWI/TWIM peripherals (S0D1). * This drive cannot be used always so that * users are able to select e.g. H0D1 or E0E1 * in devicetree. */ - drive = NRF_DRIVE_S0D1; + drive = NRF_GPIO_PIN_S0D1; } dir = NRF_GPIO_PIN_DIR_INPUT; input = NRF_GPIO_PIN_INPUT_CONNECT; break; case NRF_FUN_TWIM_SDA: NRF_PSEL_TWIM(reg, SDA) = psel; - if (drive == NRF_DRIVE_S0S1) { - drive = NRF_DRIVE_S0D1; + if (drive == NRF_GPIO_PIN_S0S1) { + drive = NRF_GPIO_PIN_S0D1; } dir = NRF_GPIO_PIN_DIR_INPUT; input = NRF_GPIO_PIN_INPUT_CONNECT; diff --git a/include/zephyr/dt-bindings/pinctrl/nrf-pinctrl.h b/include/zephyr/dt-bindings/pinctrl/nrf-pinctrl.h index b2dcd7ae6c9..9d7f8c2312f 100644 --- a/include/zephyr/dt-bindings/pinctrl/nrf-pinctrl.h +++ b/include/zephyr/dt-bindings/pinctrl/nrf-pinctrl.h @@ -131,7 +131,6 @@ /** * @name nRF pinctrl output drive. - * @note Values match nrf_gpio_pin_drive_t constants. * @{ */ @@ -152,7 +151,7 @@ /** High drive '0', disconnect '1'. */ #define NRF_DRIVE_H0D1 7U /** Extra high drive '0', extra high drive '1'. */ -#define NRF_DRIVE_E0E1 11U +#define NRF_DRIVE_E0E1 8U /** @} */ From 0bda2169a791ae5506a0e349f8256ec927b8cd0b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Adolfo=20E=2E=20Garc=C3=ADa?= Date: Sat, 18 Nov 2023 19:12:22 -0600 Subject: [PATCH 0007/3723] boards: xtensa: add heltec_wireless_stick_lite_v3 MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Adds support for the Wireless Stick Lite (V3), a development board from HelTec Automation. Signed-off-by: Adolfo E. García --- .../CMakeLists.txt | 6 + .../Kconfig.board | 13 + .../Kconfig.defconfig | 21 ++ .../Kconfig.sysbuild | 10 + .../heltec_wireless_stick_lite_v3/board.cmake | 9 + .../board_init.c | 30 ++ .../doc/heltec_wireless_stick_lite_v3.webp | Bin 0 -> 13134 bytes .../heltec_wireless_stick_lite_v3_pinout.webp | Bin 0 -> 59966 bytes .../doc/index.rst | 306 ++++++++++++++++++ ...heltec_wireless_stick_lite_v3-pinctrl.dtsi | 70 ++++ .../heltec_wireless_stick_lite_v3.dts | 215 ++++++++++++ .../heltec_wireless_stick_lite_v3.yaml | 22 ++ .../heltec_wireless_stick_lite_v3_defconfig | 14 + .../support/openocd.cfg | 7 + 14 files changed, 723 insertions(+) create mode 100644 boards/xtensa/heltec_wireless_stick_lite_v3/CMakeLists.txt create mode 100644 boards/xtensa/heltec_wireless_stick_lite_v3/Kconfig.board create mode 100644 boards/xtensa/heltec_wireless_stick_lite_v3/Kconfig.defconfig create mode 100644 boards/xtensa/heltec_wireless_stick_lite_v3/Kconfig.sysbuild create mode 100644 boards/xtensa/heltec_wireless_stick_lite_v3/board.cmake create mode 100644 boards/xtensa/heltec_wireless_stick_lite_v3/board_init.c create mode 100644 boards/xtensa/heltec_wireless_stick_lite_v3/doc/heltec_wireless_stick_lite_v3.webp create mode 100644 boards/xtensa/heltec_wireless_stick_lite_v3/doc/heltec_wireless_stick_lite_v3_pinout.webp create mode 100644 boards/xtensa/heltec_wireless_stick_lite_v3/doc/index.rst create mode 100644 boards/xtensa/heltec_wireless_stick_lite_v3/heltec_wireless_stick_lite_v3-pinctrl.dtsi create mode 100644 boards/xtensa/heltec_wireless_stick_lite_v3/heltec_wireless_stick_lite_v3.dts create mode 100644 boards/xtensa/heltec_wireless_stick_lite_v3/heltec_wireless_stick_lite_v3.yaml create mode 100644 boards/xtensa/heltec_wireless_stick_lite_v3/heltec_wireless_stick_lite_v3_defconfig create mode 100644 boards/xtensa/heltec_wireless_stick_lite_v3/support/openocd.cfg diff --git a/boards/xtensa/heltec_wireless_stick_lite_v3/CMakeLists.txt b/boards/xtensa/heltec_wireless_stick_lite_v3/CMakeLists.txt new file mode 100644 index 00000000000..11856690835 --- /dev/null +++ b/boards/xtensa/heltec_wireless_stick_lite_v3/CMakeLists.txt @@ -0,0 +1,6 @@ +# SPDX-License-Identifier: Apache-2.0 + +if(CONFIG_GPIO_ESP32) + zephyr_library() + zephyr_library_sources(board_init.c) +endif() diff --git a/boards/xtensa/heltec_wireless_stick_lite_v3/Kconfig.board b/boards/xtensa/heltec_wireless_stick_lite_v3/Kconfig.board new file mode 100644 index 00000000000..a590916109d --- /dev/null +++ b/boards/xtensa/heltec_wireless_stick_lite_v3/Kconfig.board @@ -0,0 +1,13 @@ +# Heltec Wireless Stick Lite (V3) board configuration + +# Copyright (c) 2021 Instituto de Pesquisas Eldorado (eldorado.org.br) +# Copyright (c) 2023 The Zephyr Project Contributors +# SPDX-License-Identifier: Apache-2.0 + +config BOARD_HELTEC_WIRELESS_STICK_LITE + bool "Heltec Wireless Stick Lite (V3) Board" + depends on SOC_SERIES_ESP32S3 + +choice SOC_PART_NUMBER + default SOC_ESP32S3_FN8 +endchoice diff --git a/boards/xtensa/heltec_wireless_stick_lite_v3/Kconfig.defconfig b/boards/xtensa/heltec_wireless_stick_lite_v3/Kconfig.defconfig new file mode 100644 index 00000000000..ce6459f509e --- /dev/null +++ b/boards/xtensa/heltec_wireless_stick_lite_v3/Kconfig.defconfig @@ -0,0 +1,21 @@ +# Heltec Wireless Stick Lite (V3) board configuration + +# Copyright (c) 2021 Instituto de Pesquisas Eldorado (eldorado.org.br) +# Copyright (c) 2023 The Zephyr Project Contributors +# SPDX-License-Identifier: Apache-2.0 + +config BOARD + default "heltec_wireless_stick_lite_v3" + depends on BOARD_HELTEC_WIRELESS_STICK_LITE + +config ENTROPY_GENERATOR + default y + +config HEAP_MEM_POOL_SIZE + default 98304 if WIFI + default 40960 if BT + default 4096 + +choice BT_HCI_BUS_TYPE + default BT_ESP32 if BT +endchoice diff --git a/boards/xtensa/heltec_wireless_stick_lite_v3/Kconfig.sysbuild b/boards/xtensa/heltec_wireless_stick_lite_v3/Kconfig.sysbuild new file mode 100644 index 00000000000..3a2d17ac5cf --- /dev/null +++ b/boards/xtensa/heltec_wireless_stick_lite_v3/Kconfig.sysbuild @@ -0,0 +1,10 @@ +# Copyright (c) 2023 Espressif Systems (Shanghai) Co., Ltd. +# SPDX-License-Identifier: Apache-2.0 + +choice BOOTLOADER + default BOOTLOADER_MCUBOOT +endchoice + +choice BOOT_SIGNATURE_TYPE + default BOOT_SIGNATURE_TYPE_NONE +endchoice diff --git a/boards/xtensa/heltec_wireless_stick_lite_v3/board.cmake b/boards/xtensa/heltec_wireless_stick_lite_v3/board.cmake new file mode 100644 index 00000000000..2f04d1fe886 --- /dev/null +++ b/boards/xtensa/heltec_wireless_stick_lite_v3/board.cmake @@ -0,0 +1,9 @@ +# SPDX-License-Identifier: Apache-2.0 + +if(NOT "${OPENOCD}" MATCHES "^${ESPRESSIF_TOOLCHAIN_PATH}/.*") + set(OPENOCD OPENOCD-NOTFOUND) +endif() +find_program(OPENOCD openocd PATHS ${ESPRESSIF_TOOLCHAIN_PATH}/openocd-esp32/bin NO_DEFAULT_PATH) + +include(${ZEPHYR_BASE}/boards/common/esp32.board.cmake) +include(${ZEPHYR_BASE}/boards/common/openocd.board.cmake) diff --git a/boards/xtensa/heltec_wireless_stick_lite_v3/board_init.c b/boards/xtensa/heltec_wireless_stick_lite_v3/board_init.c new file mode 100644 index 00000000000..f36032fcfa4 --- /dev/null +++ b/boards/xtensa/heltec_wireless_stick_lite_v3/board_init.c @@ -0,0 +1,30 @@ +/* + * Copyright (c) 2021 Instituto de Pesquisas Eldorado (eldorado.org.br) + * Copyright (c) 2023 The Zephyr Project Contributors + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include +#include +#include + +#define VEXT_PIN DT_GPIO_PIN(DT_NODELABEL(vext), gpios) + +static int board_heltec_wireless_stick_lite_v3_init(void) +{ + const struct device *gpio; + + gpio = DEVICE_DT_GET(DT_NODELABEL(gpio0)); + if (!device_is_ready(gpio)) { + return -ENODEV; + } + + /* turns external VCC on */ + gpio_pin_configure(gpio, VEXT_PIN, GPIO_OUTPUT); + gpio_pin_set_raw(gpio, VEXT_PIN, 0); + + return 0; +} + +SYS_INIT(board_heltec_wireless_stick_lite_v3_init, PRE_KERNEL_2, CONFIG_GPIO_INIT_PRIORITY); diff --git a/boards/xtensa/heltec_wireless_stick_lite_v3/doc/heltec_wireless_stick_lite_v3.webp b/boards/xtensa/heltec_wireless_stick_lite_v3/doc/heltec_wireless_stick_lite_v3.webp new file mode 100644 index 0000000000000000000000000000000000000000..4cdb9bfdded8ab67afaebe781c4447389da01a18 GIT binary patch literal 13134 zcmb7qQ*b2=ux9K`Y}+YNXJXs7ZQHgn(Zrtk?7uI!YWMASeO=WrU0wa~b+uHa zB_t%+KtMFbMU*s@xV7LwKtPcH(*)4}3t>4WsaXgR5KtU(dpwrz&$BnQ{ZJt>AeB(Q zN{bi)TjxJ~Nc$aThQMvd2q7^$@chPuUbW02aH)xZ z^82mc{!Ei9xisR#EGKW?sKN!O2w#Web1SC6C}ZcqlJO`_QXPL>kVx8myVq0|l45J@ zp0P9+sY@ecAr(^zIlN)X{Kl4~|JSwUN90RVZQFt0y%5(x2q9(;@G!~3d5N=5{6}hg>f-;&5!)p$@$bhJkE<^pRskV^0 zR0^)lh@uQ5m!`%a|DRhU`DFC$Q8jls-xx_hcQ~CA+-)jdtnmW|OOPJTt`x5KZH>Qc zQ3Jb?!%rHOB0*l)sky!?6#s0+QGYGcJlHGTsZ&WV&wWYGhshfWSmZY~o=Uaco7CA< z%$*uO7|-H^Gz#`l7(1oR6b*lxcp`Mx+bBYghEO>Ey)QvQ^vh)2KJZhBB{J;tFBQ5Jv?zc==jEfTw5(1xHfZ%#83S`AEWNG&yvh}`D--=J z&a^4g!E2hxQ&2(2;!pcd{9kw4c7q0Y`CCkWmIgEmS4tAJNQrzai4aUtjhYiEZm~1$ zr*#t;_Or&nMJOB-=JphV^H;% zv)+fzhoB*WpRWv@z`IcLIzn|eqc$1vM+k=258Eem+{2o=Id(s}Im)3@9uPorcuK+m z#BQ=@0>h1^!~L0hI*hb6#30K0d=JJR%k^UwPy%Xh`= z#L>b>{d=DE&(q?->44J!*7wHi!RNs3-Jaoo;8tMV1J%*ME7A4E(jAQ1R-8~Ebu^xXiwy0!j91ZF&adHP{s4Slx`ztJ*< zep-j!s~JMSuD~Bw_9NYtV+|?$5$(t^g%rO5+A|Fy#qR^{nfu{l4u7_d|2J;8uks@i z9f)ZNzajq%_Ae(SJCbL`nq5|Uta(i(BZmuATio;PWjpq>KFZYC1JjOWq5*ybE=efc zX@A41a9I6z?~tD2>+S4^6$}Og{h_$*pM1IU5#TZz`D@L8=Hch+iey|8qy(+$hF#r! z<}kh^E_{tthZT^q*A#M+S`(Ex-!UMs1ez)oYU|YAV^31T+7H{t73|@Q1(@{RxlT; zCe0l=fYP7_8BXWI{`r?Rp>`>^b1DUkXP)$sPPpN0NEY_a_Hd{UUH5#sQdtBoW04%l zEYO}FH9l}#F}2btM6_9o{ZN8tri*j1bIvoYP1?&5*ECFA^YD)zU`U;TuVWm)0zQY! z7o?p4iJ|j+jxUdVo-(P{OhLjn*Jdw*C1lG9*!u=FVkaBaTc+`UkSKAE8#pxw z8zG6dqu{&|mvW~)r@6rr>d5qGyg)v{h9RmA%4FRgej}Jh?}#Hln$tLX*iEv*rOF#+G!mE*qLgB0bte|rAc^jGQP*c8 z)AY#BHu{9X1Wjcxt`IN5GRa#5UYSR$leM156c*-dSLfY$&uo-{Yes7;A{*+9!WQQh zaMznN{3={#pU(QPoW{F-0Vo^?Fip#di@$zS2qo9&z_6g5glip3#yk>qNi9{_p-`CAxU!zz9+&RB!p`aRS8Z!~-erlpGP*!bqw0aYl)eY-NZ%i?!3-vI z%~!oZaM@u(f&~PWvQU8+ zG`6^kim3=I!kF-ZPGO+C!!*>YyzYV@%7?iRR%`N2!OnZ z^er-g$-kcO5Suq9?x41J$Q2u*1m(Ke@)vZaV%Gg_4EFMev964Vnw8Z00es!lJetB?@P5Vn^;1lCi8et=V{ek4k~;!?NIIz|8|1KC_1xYm1$RGUU8vLv1`Fb; zg*}O1m-t1umaknB7cDEh{v)^AkDL96b7WCoew7I?@@xXlbZW{C)D>BH^kUj9S15RM zJp_>FVrp})bd9)?Rll5#iWY;ghG2De8Vgo1C_Fl5T2(xyx%l*syc+_F+?*WiE3UxmPdL99l)T`v z#yeu`Y=cLA9n^3QLl;ouB!_{W+I(0ru|&C;wrvAD*MuW7S|y5$%`$&7EYsoiR(Nwkww~c+x@0`Q#glV*vHwWI+rG{3(f%Yhex)^(*UuJzA)pL zkj+%nhy7Z5T+ERA7Dt};{0kUDm5s|;BVV;~qYxNW_8+!nJH`i@p2=pYi6IvkP7ryp zFv^SkVbPf&^ZrMOSUZh=*lYph<9e-wbPrcXg`N8Z@nCorY_6m5%*yCrL|ucCWcT9i%hT{@T9KEgXOj=}A(Co<8Rn@Atze#hBYRX4 zDKb1L96EhVkOdpBp(%AM1{;7qJik6^p^Wj0UluTr#9@%z27n--Mt#HhKzfY#G5v&m z*Br3KT*Zn}zdtAk+g(EAE|=<&t|@8ZDX&ax&1H=bf51LH# zY0n5VGzk@z4r2{pY&m8rPeKL)r3)-+(+XvHKK)>Xm2+4}x5_K1fq^opwDMjZ^k634 z#GmC9wpz$K8@O6Y5+%L;GL$c;HgaZeA+UVAF%arvE5j!7k7wiV3H&E>hL-}oOq$L5 zJ}e{@9#56R&|Kxj!|{g^lX~uqej{XW$7$x34*Vd3;R=)UAO(?ve<2ETdt%=6W27EFeWR(za^3HQz$Fu%H%tNE-AL!L$xw1T+U7Q`WK<#%1wT{RQi@w<=hijE5FE>Rx3b^IKqUFl zp%G`955F0jJ`E|DR$xxYg@1#eAY?LMlGN|3Olbu%X0tE_o(lcJSm9t=`H7DQr``?< z!u-38R}X39sB*lF-$eO>4-OaVc`_RQw`*US)rZZ1d}?v|<-9>@rep_~gDN@do=Xok z@rKQ-BcJ4D4vwjXk~7K+Rl%2Z3dv+hE}t7o0~gQ21}4?SUbZ=yycN%A4Euvtp z9dBW;rI9HN%f2m>-JOe3s~-Ijw7!QHH)cMZk_sscSJS_B`}$0CuATacRv&T8eo{vc z$*bvjxNxIxRw6C$JlkVIWkM@<4@?LgWnr6QTE2kqOzJUX#I)bZ;$8nd;6Z(S&Hk(z z4w+M{_}D7@ePK4o|2a_`1NSlV71)3Io=Dl}kT~pB;nauIQ-&(o zi_9th(8|Ee!Tam6g@hYoU-lY|p3|#f)x*)+|(}EVmm4%@&rK zZxb|X`8ap|n1^a~s{bh&cimCi{!2Sy(_BrA3pLgOv#n|oA?xIxnLbFpQgyC_y|?)ks=X_OS* zDx(&hn|uS*cEe~C$=Q2M;79NE8mA-5wV1(!4pqv}J?;FVtYgpi=;-m_hocMkV=RNe zz@xiBC2Px7)n@*4%+3!F`EWD&K?jel&sd)&TGFRyGVkmOpYst@zd>;N6wP}&Z|K5U zb0)j}W1v4RvK-Gs&lk*Cujy&Ic|*(j2HQi1&f(0Y&`GD|j)$z28SDP^S)$>V_h8`# zR@%I(dAwzteWEXuZ~{H2=NYMijH&^T537jhAgwFV6NA#`MOc{cos>%Ec!{ll%b$MO z&d6*_&CTZTZPy<*gWXx5$VW7PVr-OINsZSZ3@LG{xO4Y?G0iu)3VOzx{m;4T=m#!3(TU{w6d0k^*3I&NMWV#j#r#-F-wN1+q$>BhZumKc(M>5_Omv$a}<(mc>?!qdcSUBz7y+318}*0xnH{+?>aJnt~S*kQ$p@f zU^My|V=EktnQ{3V*JIxl7pb13Kt4?Nvr+a$PGwbajiOQ&HpCR9g;zY<6CE_Qu)@)l zrg&?xf9WTvAfuu&);GbCJZtNrx(BMAI2Hz`yVa_!WlNQ1)-kC$P!|6;RW6~Sbeh+) z@&Cq)FZ;}sMu!Anc5gOgTzeZ!CQkKRvt7h@s@eV~(NTcC!XY40jYXby_=wo5@Xugm{t(XB%Ds-bA3dh!^~I4S<+8RUr&ji%8B$vd6>NYZ68bd+eI8MP5W_!f6}J;(S< zi_Bx1$DX&5_xwl6m0Lsp9`=DBu9(w`{&1ZHFKg?a#QG<;~mjgZHmuAc$}Z+m0@ady<_ zdE*`5UY9I@jXIOu^#rSSYQ#{Vqftrlxdk%YHw*hw*OyX0 zpb(N?V8z#O^d~vtTR8sWJZa>gZ*jw_^Im?7QXs*sQ?aC9dWW!=jmY;qtIju~u}<{u zVViHUj{=rVrVVw-y!nRb2@O>z-l_R`^dYp)W<2rXBK+ab^Wg=leN*WwtX@mfDslRg z*Xqr-Ew*4ehHUrpDIGKfDzdB35ROmb^Pz5#dW+1X_c?{f&( zT?vVc>Ds^g4~g>N={Xd~sfy=;d;8p(_{UYi!xBZl`i88xi}f;^ zm1iqUR@=&kk4_)`OWO3>z4`!C@RIM^IS`i+;v(Au)bR$-+_(-I_jBz6MUnXpgxmu% zJmw}gr2accgo7u#4gxm<@zwC)R|AqxE}s>kD=)1TLiq{rWb79v54plgiZ*Au#+g!N z-kZ7n?+opH(Jh2r!zpEL$Y*Se*aak!m4<`*l+Co5I7_pS(@q(~??~BK<_1Hr-?@2h zfy4H4axhtYllP!}q`AcxZPe-&_=;3uEmn`HZ;I4EhE5QofL!N6W8%1DgM*>SYeMP$ zwjMEJwre|%oiwlH!S&_da_wQ~v{i0D(HP-rqUY+kD-Ltx>uWXj3^zutR(?v6NmCHa!PAy{_>UKsCr+bBS$I?LAlfN@ zUN}w0D;s)p*|2n;NuGwNVQ1GxE(ph+v9qliGtTs~ygJq1ctJkIF?L3YXjna8jpA*j z-UlYF7NRt={kKGWQ7M{;EJ`0708_9k|74!NGQI9nqpqu}LVi(Du!!8%_?xIsjF7;0 zQ>*3YTVDS6ybW>>ZYz0C#}!-MWP1OJTbB-;w=|Jz6~ja8;y|`rY?;eZo32@G$QrZ4 z%<5W7qxo~96pp=p=~zcS%O@HcNe&hwae))gZ(V3xAOSsYk)b3+|e1HT}&i+j+37W+(Tud4PQY7y@nG5vy_znXN0}Uvlkuh^|gnbQ}HLIVyNm_ zTY{q0Z_il)%66&-?!>;@8JyxB^*LMktxNb+Rho@7w?9vI_#1G)nT67LTnh>Xd7TbQ z%|!9-NrPvWX_Fhh3yE1z7VXHWvjr;&6|kD>jDrw zeYdd9B%F8LOkluXeHlnxWAcfs(^T8mbrEE{KT)2xFXx49lbZ+vhIu^a&OeuYoyGn2=~v z3XVkNAFF}`U{N+l{i{AtxnIH?@!Gt@A|eZur2E7QF;Z>_KlaI1tZ<_oVcS38e*IM| zaYIe2RHLm`#AKqvES>*79$s{MUk02}+9)OKs#>AcHj3yJ*L-a6o_~HR-sBnL<0*|& zbc>#FYRSLe^|&Vq_CjSJ>e;Tkb(>oqi)=XoNT{;(yH~~~o-@$NZI=HBPI7gO%p59-N(fyZ3@+U zNLusPjX<_7*oZgZS;?qC-l{2vpNf^q^f;pT3@v-Q{TB@R%Olvs_b2AS(cZpH4JrS5 zcH+bn(1QgMDgx3~M?}GofHgGz8D4IcluCkE+a-`#mUn!Z;@!(dq?SihNsC$P`}slM zC%CTwMz=TqAWh`rthLlg8;1pWLZ%0&VWQu|CUnaBh&t#rP&%kTu%)LcHIA`nm)B;w zKHqY2cufvq-T86{K%Zv}-gutpV`Qt=DDnc1>5vq~4VGCVBwm-$7KCETS%l-TXKYx8O6ORkcfPQ0;Q`jPLbvzPit=s%`RcA1NV zxj9$cV>dJaX|=r9lUfB^V=geR>z1xYx}oZeLejF>H%MmH-a z!yHN8ap$if4rw=d^p)=_r>9+Wx4h&M;f1~5SI5_NB~gbNBYsHdbS+)v59prz|Mj4cc*AoJkh zrd>Tx+(XkC6>?KsO#I47evAm&f+eWm+%VEUdLd&+KC$;uL%)dMP(PhMHN7mVp49TH zuK%VU%X*-Ih5q!*X&U6;ndQZCmPTYhE->-COJB<>@=wh3FY6#1Dk_*z8%6{<4{+N> zj+L7L3tOD6bLa1Kfi{)UFFtSD3xwaz^dF|D(;v#iNM_}9i(eu^fF*g74T-^P;2q8u zs{AVU=@y#A08+@*yw?dhkdU1qtC67R>36}oHqWDjwn$Bw_z<5>lRuQgW~8OM6OW)w zLhRZHE~w$;Hnp00N6l|pdT>s?1Xn!-rNCd+mNd>le%{&%F?P=H0Y164HDQ_t7r8=o z1GzLxp#duZEwU1TAlSp1yRG7vHWpG@w#1<4mGZ9iDt6$03DE73`~Xin$fY7iffnfns`^0bx@uYb`Y zSYcQqZhnIfR;-pd)!$h64Zl}hask&{LLQLc6$u@M6c}}|^dzJ)7#g`AmTkQ-gBR7v zmh*#5`b6|Ye@&wI3=))*3O;sp=lFq6v&ssmrv|eAgq%HS{Z>u7)*_u^-7EXJ9RZB|Y$7szS#r-~kZ=;5lO@arN7#g<% zhm+yXvhqJ++UwLE>T1{(3Vp@Gu@1&S{=^A%;HYDJ|9zr;qSF8tDC>@p9t&OA*8vbrb0@RysdM)sio^}vVVs96T69p^a zC48?;8qm=H0NB{2Yvo9qsrB+f&;KFJKlxXt0Qi*l)3AlU@5b=QTF{xP2v2s~qq@id z`)!-`x3b4TA_ml0Z=sN%T^zyEhuzXW^NgOTxveN>VEU$q{aH=Ez5H7x@(29gFWk7D z3e*eYORht)R(R6F{SEP{s{TOpUQcx1ac1)Pjla5;K>qDmgSa=Q??l3mL|BAf{pc3z zq5M9`G{}{?!gAUOMxDnTQ0hHO=29B>y4(PQdCdraj#`GGpndO6?A2TzrY(*B+H1|` zt1q1cf9-F%Pjm|p2ydj3f&}63Zei{#D+#>vTYt5;f?`smrPxZO+Uyt(zAJarS@QCaU2hsj{iD1KUb(uwx*@=8x2-LMHtwtcsM z@|{l+H%I6l!E%>jcW}~Ztwfx9^UlwmrkaIsd1C!rQ57ttJ^grU=_l7wIY#{!|5M2M zZi5shh=?W*S+B;T=6}6X!*QI2SYaIy*GQ_@;U7Vo?1QAM3WzUN40$&=)kF%d8?>5Q zd_)pIKf+ewQ(9^yt=YnCVm*v(FfaC6o%Xo6ykWE z9ZeEU{YT{c^k7NVD3uTccg zAb5e1&aU}qxQGVXm`3(Cov^|^oWRf>ek3cP#p3Azvff0k{l3TI#A=!cxOOMKKd&nH zPwOG1Bwv$t@~q7M2<(Idk5H=L$26JC`@rqi51d0McxpTJh&^$_W;8<9yM=^LJ+9po z{~s@lL8-X)IFh=9F6UM4K#6{DJ|=fcU9}VhlZGm#tWBJg%&}b4AGpvG?1Vorv^ujf zjweUhyxyRKGu8e059L~WT$jcko(NDOs_UW^3l2rECt^cl z>wUS(<35F5ekQE#gu@!FCoX9&{daUN5NA(hfZ0rk)bQVj5qyLlKicNQ-v;y;Bc3Zi zd4F^0&MEs$J=|fL7%4A3%RtUUG9=9Cam1+|(5PSU&rpq-@asXd!`uCr9W^L$#+C6e zDQp=`H0Lu@D&pU+nQmt}YFj&l)L?3iT0n)BEarYXX2LONvZXhLz#(8UH`}r{qyBL$ zToj~pHe;3mT5$n3_&{v%-$3Of`pc9Ms~s(?FQDq2N<8m&f%v}%!2A;_#USA!UPQ@C_ z434ds0}mzUG7HXyxbaSY5Mzr$_(x`H@(ff=S(tEC!k`U{1K@}}XvU0090ckD?#i#%&?p?&27ix!&?^BtO=gE!G4U$4L zlD7AcN($wS8eE($$pDnJ&}<4(6Lg1(x()$mz({p$-IK7B=5mO&kIRQ-_ zu8P|!m{ZU$OW3}!t&Kk7UJ=D1jd*jm;)L|s^9IFA2Y4=XCUv@^HzCSWRvnRk+V^_K z%)2**`O$O%2t_6zVaG+Xhf44=vC>aC=9ogR1H4i_(vEDZHsndkd@E0eDK#iQBL2fk z@GzVFtfnpT9U~?@nStmZ`l(5pXhFw(47huc$355`M@j$9T>6&`Ld&p9i=?r}mxbG6 zzN>#;2Bw?En>-L2Hfs`Y%n~|_<}cvX6l?Xo^U*SJgql9Hv6Vdb7$4LSr%4%l zKh=*N%5FUby3!2rjc?aDj8dFa%Qg#J%u9Eqko9~TV;$;@#|_!4dLc-Xhc!&1 zERDck?9j2?2h{+49oB^_ml-nX?K|)Z!+oVg%622LHNi zY&7=bqF#9;28HJ({nxH^8SSS=Z&~Hm^X@s%zzQqzoUhc=NS5P%noSzY3rApK94stss~7DzlIiEQ{fPi=&Xn>LI13t@bp$?=U?p+D|; znbTS~Y-^NrGOZsFjj zFE+8ccmEnx#5_dV0D~%@o{g&z;h-B!RifyEt75_4UEU>G(I&bK@4a7#OattgB$Xf-RzoU1BrAD~P?PWw1jkHtC}4|8_WK5q7kz^@tfDfgOGNv($>l; zqJ}Z5?hbsV+Xeo|)#J8ugNi|zs1==f(QCpd>w_P&_r-DeC^oN8udW3$3|=`mT398k z(f8xn0*Zhfq5jX`kg%ip+@;?FqW2Cu$Bo%xE?EjY<`@mM8eY38?X@&cR*zS_#%Hz3 z!4et~5%o;C*o_#f?bg4Z^ohb_3p7S&K$``Bl7GhAqv^;VS))hWDt9<9#YF->JhJt# zvxce?=|0DfLmQ-N&hDHdR-|my6O9ZptXycG{ospCMy{2j17=c~_r0cllYQML(oN(P znv=jUeV!#v0!YS-Ow^)ntnjE4a5tjhmFjH3el`RiP_U*_T-!h;i<#vX_klQG_Fhc_ zlATnhHaGo{aLfJa_EBdX2D<$BvuR%$!d{lZoZ~5MOQ@qF2oG;|?-c^S!W>3Fi$w#a z2w&Q=L;C#UYA4AD+1|g~awA;o#k_O3DjTrZyyH9z<7H~N6p6p;&B8Ro&$bnS*wQ!u(CIdU1J8?Ql|;!AyD*M~tq>3~$@ey>1TgU@JB)q8cUTdH_Un$kwXCs+5U z*owKe0pM?1rD)jrtaw_ot3vO?Rquew(e>qFG~&MyL!cb2FbExh6~PkmV8u~|IOI)) z1wBw6vVdx*n(T|DLz!3;8Cul1PVM>$)ELHBcn!R?c(7x)6i0rji2Vq6i29n7`c3MD z@p)7(G2b3{qI*UVeH{V_RNckWIGR+jn$L~uVfX?ruAw4^+!ZdgG(E9Z1J(fr=&W1j z1hG$k_ORULQqcC`%wXRkTf4LDzysx$e+Vz>ZO~5dZa^c9#T?e?y4X!~y4QNry_|O> z;UF^?-};BV5mp`cFb7w{z0-Gp$0)BI)4myj^02DSvwy=WQHaL+#r#D3Lu`-G<^wBX z`p9cxbIfCO7)-_k^Mof`&6gM_Q0!I9qQy{>@I#34;94NJ*<&w0o*lTp=o6AF*qPmM%59xo^ZzFGY_dW-Iw2;Sc>^7sQW|IK2Y$qb*I?G*`=M zgVd}0^8Tr;X$}XLYny|r!=J#c0{KZ5}{St{E}}PN|}A;shrSD;=?@)b;x;U;S1`eIerO5dZjDKpT!TF z9jOqGTP*~i%nuv@kBRivOCV${uf)LxHq*&MM6+kP&il$0000G000120swyj06|PpNETuM009|?ZQDo^ z?E8=Dzu}#kZ6Tun6OiP2j^xpP?^MEAE*OK-ZAQDO3r5>n6m2V}7EY{`xY)JKB4#j< zrL0Hhk+^QQoxxGiwhiO*$GwXnA|`-zk?(xNtofzZt@atVZR6^ zUni&8w%6zT8`+tageW993GNQXy%cvS6f17UDNx)kxVt;W9SR5TPS6ktAqmm-k>B_I z$4I`vu$v9JuIs)dVgkltCN#0wyfXgaveGv*Ov6lQYCLbxCgYFqzdz-1n+o9kBj_2I zxo@*KW&-CI--p=s2<6;Cd(8yKVogN!h!G=GGXZ3c9y4-tfk4(n%x!33{Qv!b-<(R% zwbByJr9xxc=2FQwD6+Xy8k%Hou9Qp*U^W*@wm);JHuS4vbD!j@p}9`_wWtcx+$C;6 zL#?vrD#;B_)j;vwBsNcrsA=+ZkEkmxYAb5AxkgGQqh4ilbBn}fR2SsabBUBZGaKdR z4vA$mrEDg#s9`P$?+NG{67%_fZf*x36H=KdDV1{lQgb^HHp(PL!Dsqs=Vp*6bT%>X z6}2?X#ZV5WbUHbcH8;$)5R2gEk`jP5=jKw7w*)dtSq0XdpDV$8l5~lgsBFs5g`k)o zu_-tAL9Aq)C6tb8(43pwAQs6=38kzSO$~Dwc#`%c>oU~on$mL<_}G$CQciU!YL4a} zkSA%C6Us)^t8~*`170NVi^;eK>Q_TFw?H{Li+wWLl7&S#ohWJmq#scnKN_FoSB(3GiPSboKvxV>_mD>Qw-|aJec}U&d2yxSz@IUiRMYv zaw!jgjK(eYS`08um_P=|kOUriOGTyk?)=o$6F5I)zoqi@?Cl@k(Pru^Ip1%C1=BJT z?<||bxxAAlpviAc%L@Agn0B~6PtqG@ySZJMcXF)d$436P7Q6KXFO@mlI!VYn;mhM(I++x2(Y`3-)!Og;`N{4qc zk~UINPhh@rW1=39n7?I;roND4{Z(Vv zvJt(e55!s7E8rKu~;m{zl~u|ylY9T*H9b=8V${a z>N1-ZAhRShFYkTqV_!^^qDgqSuVep&|pT&($@{O0}$-SwzjvcRz<& zv=sLarancIrC+wsqfR!1WZA) zo=##KT?CW|%zA>LR>K(9JcC)%81+<^9zQenQj9)tx*3#x``g81di>~%_gx`?Ej1!P zuz8~h>yheRaPaqLngzVQwDVbu7*X+iWq++pG~6JXT9lgUup}etvFp zs*8Z$MQMcfc$1rl6uXL=1(56biXPv2`nuNKAS%`H`;E-1Dwn7?m0{M+HB46k^X*7R zPw!aruJ);|uiRRk1@LA)o;-ctd`?vNseZEzM!C>kmI2n%pjk)iE)cYU8NFchQoyrm zOvxeNsx4;Dc)E!{u=zrFG1ts2-B~7V zH^_PebB_YI3uHspqinRwW|I z)Z-C<@hNk_qn4DCQy~?php=L6OtP}#-M0^w^<+kF5GgOs;j*TTNWQ%*)zA>3S;;Jr zm8QjDX2K)|0Y*=zXBU$v<2_-`OqhIyGX*h8b4D5)MB>)bMY%m{Xh@-1#jH>cLF3yUuhsB_G8T-hzz zD6DgIYziazzsdrckCtc@_WMsb@8_RS7$6K8!a!L0`!?o)HZ+sG6^c~%-9?v6o079~ zzY|xD1LYd;ySlv2X{+Xhb$@i`|C|rf3#JHc+UP$kke1!LGa~n+Y2{`!HBkrdrm!m|E7D@Hrr#S(cPlIM_K$MCcSF7G};yrcoqr9Rw}4rgGT`g#yEv zB}KV|GSGa@dXJpiWvbER8+DtS?%AqspGQ-%`BX%mMxv=Sb2b|+IqURcpxl(438QRwQlRMZ%Xmni};- zgY@8%Vcmm}<>{rxujA(Dky{%*zTwspswL*&Hn_yB)J>8Nc@f+pOTg+76V9S?zI#`F z_Cb6t>*<8*@%Gamd;V}$7nSYQ>10W0&PJ+1B<(v$GTmgs#NHH;QtQBJ1}K$-Qq>(E6gOUIVaH@o0G3_ ze)Bt=3@l#e-mPw1)4MPxJNa1LoD8Q#tk^}8xjczl*9HSH!vAv_yaTXu>agtuVDgxn za-zEFr20%T7?lUOata{Q3OD@)M_`Mi{rY*EbCIx>J4iBE4^@dC%vfZF%5obRgSo^DK?+aFsnMp99ruj$td4d;ty@2repq#N+#F6>DqqV zJ+5i)Me26(Qmd9zCp?uFO3jDWGD~F6ro1Vbb&#Yr77O;rlGTF3n4**G`Uyv?(Tl1c z&*+a<=F%IQJU;)zGO8unoEl#yxOFGfRPHhoH)IJ|9X^_J9hI5OHhc7moa(R=*`%E} z|K({-2GS+!bR;Ux2{0E*s&E#-N?p#72Xg_Gr_+!G&Vrd6yHF$xC7U#1dGD&gI8p*D zo;YYm%GF_{%6_~K46xEK_-e8@|B?P*bi+upp4oc-5 z>L^i`Hn22PD?@Nh(+a1Po%s9y!&#$JJyY(Kr(Kd z?D~A>7ujrHFd4Es1lIlGM_%bIm(OZutWYx9gcrYa<>8wz0EVg_hPOGp}2y z8zc14($s}KRow#SO=O!u%oZ9G%2e%|#^5H5(1V-l>pQ>XjRRw=Lsm;BxAOt1?WG_x zH1zaGwj;I*WHsvC?5MH(5L+NMoxS&8h*N=FyxB%yEP)J6_Md%jb8)KKaOTykXeJy; zfb*-}-{c)wy!OriynT^43S@rQv-*6-rUT0HdBxp4E!%@{3*wEFK@>X1C=?}(aRjZdZZMffemvjPUmc>zN zWH!PGZVVhupWjGUBx&V{L=9OmOqKvhj@pWv^WJr>bIaiG_8y(}y@%>?e&M@@bH$B~ z-h4xU>NI1HwJ8~qsFA3Nn#Mx6m|?{=2X~L$>|&#~=|sK8@ZoW^-Qj7W)Bvnj!ZruM z{z$T93`-(mSuHX3u5KsSx%nv#`Z`iAqtx@sf46J>*M9-B?=7!dCQD*YU?G{J%O)X{ zB@vg9g%em3^>@768Oh=+|GnCaujYKMUQk#qS;wC1|MEGNrRmg^b@V66IPUv>kGzG7 zQ}0IWmZMNIp4hxW7RtNtr*7b*V6w;78z2ki-A`jS^sb8dE^ZOvuXf5&TbNA%s)elM z8B9PFzmBTN+Hd|>S{BMjW5%MsovG!ibqOAE5htVw?RfWqTecU0<+%CMVx&;szCQF3 zL|_@$9yi^|07Y%LmgNDOz}L|min?V^9zb0G$%@`ldFx3pAOb7m>Ne;5b~wM_C7Wa{ zgz&$fL;TRm!<<}h^VdP`kt${rEp9q#J`9YF z4rkLPu`mXkEc}zHuZQyl7PuHUbzDhp4Ji-iLDXp)ab$5P#Sx*6O?E+qHgVBXM1+pm^dw{z7DrpP#7;nGIo+T-kPgj+cb-U? zqOFJ{0H>CV=aVD+rVEXA%;A)PVpl^}i26k%MglDZaltUnnveY5x%bEjU-JZDp6-Ns4J4|-1OSi z^xfXc`6^cGq}2Iku4(3mdvYFS2GjzKL^Y>`xFeIZSxhK_S=X5N-(|y!>!mvSuYI9W zX>ogOCD7Cei!PrPN;fd8iaDpg!!=txOBt4g%_?HT`JItm=VsS5PJ1h@D!vUvFV!PH zyk@^&_WOX!k5^P3O2ll=3BJ>sOEVFpB#K=q0hN3rifch>QnwR4^pC$h`)-4;(ovun ztk23vEjoQlB+O@HYKjs{qF9)N0v*m&kNBjVl7;eo`g$UE!*BRtp3fh^yDH+t&YS?A zDW@AmWoM_udcOK)`T>gp*Zm=?BJ($Qn1Xq}{1MGTQB2+5-njA@Ld&&Xe$hCmP~y2` zuE9dd6)rw+w37jfzP;Y4k~euOeG!52R2MRnsCwm73(G2a_?SBhuBhXpg7b4w0{;7j z^}P!NS3LX0>9Hw{Z0zBs^B*xEimM-+@bAvN3|ZknpZAZc^wf0y3Wb8in^}3P`sm9e zA4$vb?u*0y@o$(91m`~PJackSSQjJoKi6IK*hm(}w9r``ycHJ6*l(L5C*@^e${u^b zxU?$jwH&P(<7p-^RAKS3W79G)mO7ThSI2_wxB7d|&#`fS)l-~zfy~c)%&|**BlsSt zosjjx{5;1VzlIFJ{OSjsYyf89t0C9W>~x}jLzpT!a((XrQ*_KRCuV#oi$|QXr8mu~ zG1hO0BSIUiZH^Jz#PJK@2<=$$@6@?Y|Dr?YJDeJ7AYnRGpBU2C6#>d_Ky_34lzHR` z?O1)}cgCDrm(F1%kZ(=^qbWs_sVr72Ds(uR&mXb&QxCfuy|0~i(3t&40~E3~Fq$zE z%r`Q})|v|!*S_U}25(9a#j1ffl9cA$ zG-gG@q9-&4>{T|bxF+2Vi^oPU9mi1U?iNaW=6L7wUnQ zhs8hrDdTHd&sV<~)vwK`1WI*LQ?#KZI@>W61~WfLz{LtewnR4jL1*5(P@cD*N9va@Q*azP>9bLsq)+r~WaOp59$lRW$L!NAohoCzo=~TLcnZ z_u(;@68^K4-1&U9e-fUimyH3uAuxjrlXTmJ4JY z`1g?)rSVll^4Ooaj5M(6E-5!ig@$P)&~MqtM}m+glLc>V*9 z1Wbl^s24I91167&$|Fa_5rDDF#rt3cHU?kfl_qqWMgOwhBCNbiB%3`D6G~}Wk07QN zXA#ZYj}+nE9#J?P%dCwfy!Ic83x#9xzv8HBtkl0dRW4=AalSp}>M+xZ>bZP(SBz3C zPW;6Q^V!ufswg_BNx?uklFW1Jd%Spw(CorzAFNe&J%J(~Wma`0YR*V9oy8Kclp|3` zooef}E*N~t8qbU>Io0SjvrX0*7dxYC_8qtP|G-nsP}9g_gg274Lcy@2H)a!D*Ae%P zq-VV8mRaVHEtCKvQKR1eJC%x^u5+7xIqsl)o9I1Nk#0t~rWtGP&w@8Toe@e6$Etyh zKdfA2%uagu;l}?M3HAq*b-(nmtT!ul_YAQQZ4dYe1=14%C?wmFc z@BB9}d_yady7rk+ob&xzVOnc`Gax!Cr^MUf2f)^_Z8^T9k19p_Df6iq#~oN6RDdyy;7 zzIAI^7`e97A3W`Mr$BOVUUuc(SRh&VNe>(|CQ=}|PtLpTW;p=k+6WKe&Ex@8DA15` zJ)U_QMV%fGBGow0o%ihyAlH84gU7c!1@h55r(JzS$rMC3WtV5I{gMSf0rlZ*^4o-; z@{WD@E1}?{F_ZpJC=ASaosYgJ7+?I@{Z=V0LsohR7gr!rQ^jr?vO1-kjDYeDZ7-M7 zGQ=;>GPy|jj^EchBrOYK%yYuR>b{n~z4LpY7tH*^*Drkeirxh~V)u=1Fj*M$L+@Mg zs!hEMt=!;D(uSI2KzT zM{v{T{Sz>Tt&XFrWAR@*B4Oq1d_TvgTD_pC*NQ{en(&?(lp9B4RCj9`2^w+)H=5?d z=;ND_q{&D!%3$Fz8A-}hQ&ukEK|^m`_>-finQBoBf9yfL&9=a#*%{N@Tm};R!q(sc-aL6Sij}nk2W3HBL%Ds5R8=I~5L>}LZ z)UC{z19u*C$Mi@R=ewxalz_~XM5)k6GMB)N=_rZOaROrEPf5tW=s>~5jInrEW5&>8 zcTqO=ps&Ds5y|R6*>{g7*9@S^sG4}U+Z4>(w1O#^=eO^Xvp|x-ESv;p!KB#?7yEEg z$3thiV4g`we}hlp?ol{}^45OvJNN`1KMN-Vl;WPIfoZx6FvIZFww|xOtG}rR%7HxK zIvyVt$pCMYPk4&pavX6p!4+}!&N}%6iDv=3vRyH$co2YX5|HzOUnYtx<8rdyjyoZ z3#0M>rzjr2S}suGqn}K(5iVZ;9Kb?Ae8maHPQsTv=_(Vxt4urL<951=1fx(?7u5@2 zH#d4@nFd!V_+AByZK;Na2vyXU6~>n{RJQ--=bMkaZBrz-*(#f^GOy&1Fn1UHq&f_#S5H8?5HiPB~x_FKcl0AnVijLk^A^UGKJ1kBZyDw-kQTjdg9E?1h~USae9wW0e@o~E zZrJ>J=Vuq3-;#2cI*r;67e_}pybFY5*cHp*2*2+M#71DJemAU(Beb#88Tbgm#Y0zp zG9$nW#ir({++D6_3aE@bT|+|(D;8YN0c3U~jsToSj#?Q~Xf0Qv`N# z%e9|fL^}4)0GTOHdBcmyC|`2(MOS^B_Q+)NQ5*qrWHN#K<;v|25wnlOa0HK7!r=&S zE2ao<3||aKaMLPHSONo{yiDWyx(u_Cx;I1GAkD7 z9aSUSh*A>|*!-90#nfpeDN9C5L_~1y-~aN;n$4#*4{v$vg(a^n@A>%H7sm4V zB*-|x^T_T~-rf4zsek$2H@~#u8!u-so@@eQ%})HZa01?a9IfhII9@NJV4g9b){1Y~g%V#0fP z7fjJd3&6CisTvLFcnY|L=oO+D4CbG(;-isg#`SO`Tu#62Tjvs$CZvQbEjYDknmsT) zPYqwiyFhYWoVwr10(rhV>aB2cTyr*&LU|i|;8XZuaObJrP6qh&ci#@^GEA9Fdvlji z2feFnP6<$E9(e(-aPMuA4Dj~dzdpi;l5xQ^_yq1f)jL@r+4O@BIC>N{I}%e@DGD0AeTu!;icgW46%6D4KNmSxa~q#yI5>PCt{ta$^tv;poqt4+NK8_u^qP zg^`=I$4^JT9Qi=r?!EGzBMJ>N6iqp+Y2JbXQmX8ro$4l?s#tSIR4S&b&;R$>3(_*= z#vJt7;h#Gn2u7W{-&@WH^6swFUOh}E3nJ^<|AT*D|I8PWsu-$PY4OtS2T#BL!XGEs zgNd5+Eb-uT=4T6Bx#_~kpJkO97-3~AH`z*rAF!g9oevAP?2z>8CJO`o)?lecut3HV zL({8dF);dX^zzh{sFYzH^s-G2VkS+Q;VBHDabC^a4+}OdJ9GdR$e6ERw7SU%YUI{t zVD`tcMo^8JfADvY9kG61R!41F_ZvT%m>slu&?T&O%Wucvqd?|&JU-gayFlif&)NQ* z!9JAv%}zgZZxPs(y=eQ(7mb6(tDLa&!N>rm_U*hSU&WcHyWEQi$mK+J2U11ne#amK z^Fu~$c=3Whlxf#%Zdfu77H@LS0s9hMcI=)T-giI2cRpv&(y#Xt+<9gbcWc+stvo(O zXk+gPBebLC!ufH8HnuwmSs+ZQE0!Z7bi`JtA_rh`wEc^1uA;M$r<*#B2g)>2yGzQZ z1?0CUjsTp7UOWOvXw&{{Dk8LF+oSLtQKFxMHSWx)WEqpH!Z{!(*SY z@uc(bqjTVc??3TVhk?x|0dgd3eCP%CH@bd0^XUY^T!w9CF~o%2T~(PquHSba?MXaxwQx^YuhsQOimWayH}3C z;O`=^T=}xLBZtZY$v$}KzHo9}a`ady0~C$B9DH#GM95RG@n%v{6P`-l^l*!JRbD#y zv2ZeuTscdzc=dGMRg2ZGb?Za!_-0dhg~+wJ#u?RMhIxFFK2=M~O7@z!ZY zt1^>H_y6=lW`~V$R(x<8hc1H=R`&6>?(r351T{wN^PfFd#t6Ol2NU){j-bZyzumgc zx>z7%*S} zIx1HxV`!$V+=(lkHEaP#Q2)z#OtU}cSG;T4+YkBjRHsmQcYSn#cLY*&@L@+~y$fW1 z$=wV1h`_SFTaIn^!Qx@3|9eZSnzlInEThta?@iE5xY!{enz6;j$iU)-uU_|}79Yyu z)z974{YH}ulWz2J#>$ktMMx)aHvU~gJBis}*>cU47u(i(M`+okXrL?*M&_hu9HEU3 z2NT|8$1Q{-bi}$xAgjPfTV{$*nD_MN>T2p%Rv5)SD5n4-Eq%pcIYK)&T=d6Gzm&qr zgM5_j=L=n>03PJcLdi2*?CyH@;7Mm6NunM{g095~Z!~3a!7%!zNix%fQ8QD?5SU5J>4vfqpG=OFcNHPp~=N0DGv?(3f;w-swy99c3EVJ8c4Qm zQ4)xxWx+rsDpAwOF4^VeI=8!q!WRE?zDC~htRC07(&>3dJ({J|ksXRv0~v`blZ{DS zmh+{qq5{nR3)F+j=mCu(N0tpMY)(hxsu(q6>7;s4HVcCm$QBBu)6A-BY!I`eEZeWt zRZyR!(vtDGL@Xi0lCXrVmKc9Rdn8xf=;3+BJcDX=_juIhbDv$e+pkCeUsM1-T1mA` ziMR%4Rgq~acNKi!LmeobY+BSJ3+KCYiFB8nWC?V|iNxK=Y81PC33z4m)n6WMzLwEi zK6CyVGX~6XhX0)!(nJz16$}fdYE})fOuuq>cNqgz%|fY~1=8$<@X@cM z+vIb*P%zJzKQ#~svIvivkLv&|7k77ifXEBy6$!9k!n@6{hghU9Ymh zfvdL66qt`S^|dRevEyGYC9EzP!piZpkNJT|4v(BL88TUgOqj}(uN?3EY{G|tm2Zl2 zg!P>mBJY?yu-7^YYw4PkBlRx^+ z2<6jV7`503EK zdk8KRj%9YjQPo&8*A)qiJ)U0Mx@U}-GA$)gb{&jLQ~KzBvQU^Gfl`D{v&?Qp77F=; zt{Imu)pAl@>7U1KyCbO>RLe==1VrVhPIP`Yp{9Z*Y0Wtq5k`WU2ur|HjwCIj&L|=V zQfIF7-z&VS_fS0+cb$9qkN@}#ppd1e(TEY=2_wPW0F2;9V;iOPF6HsRv@Q{Ke9VT+ zJ+$Pv3(mLr?_VwR%y_1$9WU7Qi^V6dF?!IFPmgAYC0_ghz*EYl3$qu0NNda+Ny}v6 z5VLImUAxO&>fHJ$F5B@@7xx}@+vHVGh*r4i{;W`XC{_(Hk~EU_5lPD6pTlqY$2(u0 z`t7Bxx83{4H(&GDkCy)54@+);4Q58=wzqFMaPUbdF0tuVsmmpPrH}CV^=FtLSRW)GG?{J_!BxJxz45UUi!^PQ7xm> zy4vmYWB)b!@L#E%hU!ov!jdqTi~)BX{CevyFJIrX?SEf9_`-XO`+xgmcf7|EEr0}= z{bc2#5(hG+ zIDZU2Sj_(}!DJN?&$l+m*3oVg-k{NSm3s|T%}T8vaGh8TxYEm~R+AOZo@zdr+-LI+ zk%jW^!?#W{Ss_5Z$24HU-LxP*M zEDo9}$PrCi{-p;_-N?H@P6r>c_-zf|fhlw8F7IX9Jdo}e31kiZN?j$?hVl~b#_tJIe=;GTXHzrq71QPm@Gaj8oUEieCjkit0@-55tzW9f7uB`lpAFsYmpfJnDAn@)fg z+No-4SZU&qfcfl-7**u<$%Vr-7+EMBOYVpxxLBN6gq8<+f_wVL7N}TX&nd_wyipike1> zBuy9zrgJ1}%<&X}Y0xTZz47Kk%h;hio__A<=E2mNOUA60WALFx!@9QKntivuwK=ZR zJ6gFdrmBlq+RYEW{)IFswE$KPup}@Nm6DkQYN9gw-_^HdW$F3U-8O$)k*Z2Yss+|i zbaJ^oP-yq2-a~CAs*6dJhVatud2c>@4Rwk?@Ejfqz%%acSj!C^H)iD{F1}!|C4Mvk z=1>ymYWe8*%cvZ5=Xwv{%amNMw~*RJO>f`tz4wn7wo=)KYB?n$ED4L|=ybLW_#qWT z^d*%~a2bG$5kF3MZz0hj+n5H|9bKRhWg60JC6H-$1VT>G21bn0XIS9CX0Z?-3{P)Y&*0porUJ z7Xw!K5mQr6^pd`t`khQM;Nr)wh-83wlaIK1QSU;@p8eWVBklgF%KX!gsPKK=OqPr1*43x`@s%AZ& zG!q_ArMUjOLjdGv9R2KZR}Yhgk-d53zkhQIr0D%qZ@FA13nD9>`2_Kz3pv?LM3J+I zaX(t7t7Y*Pc^}7K^~tq<-R3+aMrOjqKYu1u-@xMO3oc#^;|C6yz~t!!V{%*ZrQa8% za`IE&`3eNtCTdH%;Bv(`iy0Z>x3_rW-R(u_DIK5wL@+-2o;SL4gl>C-ei!UI4}quu z_w0$Ap0z}Vu*Gjrelm0JqCZDLtURcE{A5#K!1;fyy-pXQSGeT3tJjTPAm?{DVUgPw z^bX7~@YsgmJ6~a>nw@IIUA>Jt`3mPZxH;n;IKSlm8=SJeTp-gn7mZrWyFg9{oV4QY zIq$-lA8^mQM;?rRddIaJ;|OhRckY7T0l4z~haN+viN=(tW=Fwzs?QXI34=o$$|(S+)lS|6 z5!%>uI~<|KffqD+M_{Mn*Q`VwQMUnB#k(EPoVOfVm4M~cE8`C7bRL|Kyvgu}$w>zO zygN64&gcuaw2mPbSiW2NY(!_vlv1v7GC<77%k=Y>z>tk`R5jMg79(NtfMtG}kx>=v zk|WhL-*!K|Adt_D#8GpT0k~iw5#F)DMmU0-)=v`=+R=Y?A|rS?b;H4qjC?6wGH;$- zw?T~aSgQQdLi80Km3Gr(6OMjzx91y{{N?`L2EF)*35Y#Lf)-I{R3HWxdvL|qj+l@V zVBPKX{Hn_|&;9H9f8N&U@%e~4(}paZSppC_k~HT?($W~=a-E*X62cbDw9 z&u^37UMjcKaKNn3V1TJ%^!!7=%iyDJ`~7!`9lq^G07^!xB|6^fcHqAz#S|y7xXnAP z=TkkNA4V_9jn_AMeEz>nskgIPV9jk_+4`{^yVmMIeL!QTb4L2(@f)tmu<@Wig9k*{ z<1x7@_fLI#^?N?sX#R__iYP*f#K>w)xCg)u|Iex~Je?Exwlck~Z2T^JkG?Gih>FxH zumq$;WC5Hd!&8TKhTIQssBqe|V~avnGpt^{*0MECQ_tjQvfHF`9Sm7UszKl=c{v*dY?*O0r{yOM#p!oHbv}V-FCr2Oqp0|w1Gbb81#jH?Kq|ICiun76zg(mO zbt@(Y@N6^uS=0x>+nvY%-_zZZs?=|#;TxRz=@D;6K9G0!pYhu+z^Pj%1T|2``%L+d7qtr-LH9tu&#b9`Er)fMlKVbdctLQjBe6Q zDcvyjt*@KE-F>|gQJDC<*V~$J-g2#h-U7%?fA_O&F~9MG&U|-lnhE&y+3C*HC*a7I z?Fl~k=FLYf6^C;1hG*|`dR7Le%qf4rt0e|-<|(&&svEJ+@B*CQ`7&f+exYl(KK9w` zGE^~>3{0xh$u?Kqv4FQwe(m!Mn;p|Q;*s&pd^%;B2A}D8EGBT&kns&)UoXO1xrbu|9 zsL4V}LRm*>c`ySo-_~t2BYFCW`L=1qsugGSuA=OsQ-7a7txVS>!wRiF;&Y4y zn=_|h8G zi8|%u)+n#_ZyWs0*55f_!+Jbak7@V=OK|3`joy4NPn{M^RJ!&p_xa(=O&?$6uh&13 zrqt#EBT*N}4i{sptFe)uwPi-B&w?r-J7di$*{45zV3$kR*!l}<8i^XUjRmeLn=IaF zaMu#sTx#^nE?#tra_Zn$QlMxkRtux1a`R-T6x*LU@Ry7!U9xGrZaD7$=ma`q>hw9RiW)vSEi>euZztUyTSpgwkxiytGR;iB zQ9X{8yXd3NXk7Va0hGQ2_>yn#fv*q{v;J#SoPv3NdWCYTN}L`|B*0%q{RUt4Ae(R> zm@q5;h_ChX@IjOE0!aUgk9|7zNw(1CD$1;fg%gv0$bdOa)s$<-)$(9Yfy}(BX%ICIpyakuSLE-Bit-_tmY=hmzykDcLe5Po36IO}V^Wq08A!2tz0?X0u*6 zT*{fDWZH}LQGN9M8}GcItC(pkN6YLy;pDfR59ICsE5F<9C&mMVsN`~B+gQj14`K#}Bxr*9FU!jJTU;EcVk2xO*&Oe{l4|iMk0!&q`!KsE# zf9u_J*Mgfbn4Sqkrr3A=@Z@hM02f8sC}j#~9bNQQEnZ};e}CAZ5K!82_d|AG84F}= zx&=e?RLu{hrZca4tj9w$QQOpig$M)aw|H^8br;;7(2F&%wj360okci*$7t~r30uDS zoOMrp?<=cAX1-MLfcZslKJ7#20bc@_&Sgx2th1dy?2#|sLhw^AJN={vA1oet@+J>1 z;T@PpKDzPi&I8Vasg9ms%%qb^6&!c~GB7{j!b8tpFedm`H(xixhcdtJIsZ7i3Hd;& zlXlzkwtKU}kRc3TE>nBUllSa0Q9F~%nnGBi)%RIUP5Fn21o&DezyVR|f&VTlN9c$Z zuV{!P04t{s-vtBnBUgOuS5xmX(;iPGlaRlHr@Vtc-h0`u8$PwDu>?FLiD3Euj zJ^#dDu%fcvks~gZ$^gzgOwY8g`KnQOJ|Ai3tURMkA2wZx@q*~@ZmPAsi={stFeBGyddTC$p%)^7U5xp$ZE{``xtKmK&(oj!i& zt=*4{P07_Orrq1+a2-3ImE#*!hw)U8F=U8$>+hV&qbMelz)a@rv7WDfS>bg|Ks@C$ zRO^`%3MOkUSvb#+Pvc!MMXxT@uPy7{>+L)S(9r*NDnA5^b4z@SW{z%hs%FJ*`o5Q4 zbHcM7#!Q+32JK(G;QS7!K#Inn^MCsnvNB|)ecy5(K;AsPsp>;!ctDP;pByX$Jg*)9 zbU2w#xeFgk##N_GaI!$M?~dE=l(P!Xm%#*dPoTC^XMg>rg`hj*s`(E3ymG%DeCQb> zsFnYB3wK^lU|H$3R~k0SVqi*d($H<9QuHpW4|%Hk=-quE%E|EV%OfV9@V4_|1n1p+ z#>>tJyY!lG_G)XE1(8iUlME>Yc3t$4Lh_9Se{(yG!%AK1GIr=>Gt=oIYx zuTZA+`D^ZeC^9M!Jos{>(wTfc*5l2*p$dyz_Q}b>7`c<*dU-62!PZM{vKki1*mmV; zzh)Uhjlp{yvr+!CpGxh7^dolN>;(&=QU<`<=@WaiQb!TR6IRKa083BY{jn7vPE^noxff7R(NKA0bI=8?M-T(;lAt6lnXzKy`E zoVL$2Qvix72iB>+5%NZ8vF@Po$W+UE8{g2alz`M<@ezPi z(Y=j~qv36Gl~Iuo>ZjRI7;2j2~;AWTE+rb#bCw1G;|Ev@Diifba_fGWBXgEmi2f<)Sbz~JVUbHd^$zXXo+=uW7_X9?wxbe@6h?v z(Qh(>Ur_n+imF42NQqct zDg#Rl{p65EqBl}|+&b@&>$dvl)}PG-vOs37%pvSfrt<@2Rp1>Tc|cD9qPF#TimBK9 z$@8^#qy);8sVNF50dJ-x3T?=Oi9)XI4SqU*Tyy{FR~ClO&!`!L3vGtsn5P)Xbued8 zygfPc!91f6{nTWDqS03%0XUPV7me$Ph-LhSl>yiN=26vTfEn9X2Jw`GeCe_ z>cpphc0P!hQz&kHicoOJQ$tV7$-tC7eW&rJ3Nxu5>){NkMpH(OaiP0JRUiF)>Z5rX z-hFZ!r`~Tq5Ip|cjW6LtaqZL7PnkNgGZQ54-*`^z-G4oDM#%`Mbj#h3;F-gD=B{$V zj@fy?^}GWxzt&MF8i2`Ts-yR8&I!4^id{tkE*^PlUItDpUdCSAV1bN-j``Q7xIo5H zJIr^&5s#+(1yN?VV~?GBZ@Iq_RMVN$>HJbhAp)C^&e@%sVxxvage=Yu`#CoCBC3+h z2|&=O&Z2;$mWd;({$uas@;(&e)Z-DMeD1_kUcQ%X(cul5Oa{WR*xD|+c+U&w`F%Q} zou9*Dtky4fp>P_pIIbGFZen2AT`RqK@HA5mGhWqf6O~qW%TAd%pwL|`XIIClG_lWu zI6|AUDOo5SD{b;1W^otU5)GwvDbwzvbR5UN(b5gi?v#=97D%2so*9xfQQI->oRVSP zn{LQ1JKyNy8a==}Fhdc;e4OHoKuXTOL9O)|nOoh?Ceflc-1NPBnDA4Yz$ zS^Jdlhs?8R^z^i}6-v%UB?X!jszhe8JgHbQ1?ZwTRYhwimod4Hzx>liT>4Z-CWc|P z1PX^4iFzQKx~SVA=MIY>-fmL#^ltC2_}#RfVgSQsI+)Y#qe)j%*?i5~Pdtq8MXIVW zBc02bYj1C6%%?eTK3ky2R5an!?0~nU{eEeTM&9(g+iboonqHpRLZz~%IW{gCA0w** zaYNAwYx_sP8JKEWkEbf2;*4}I`}N8H{Nc23Gs5R*pt>vpDH#VAXS!1_?q9rWt^J>E z-T(Dpo?kT@{$7MYkji%Vfy{zQU>42;X2Fc9Nr={`F{&ERcDpiQ%rHbRs%k)~wJCqs z79|Z5;5w)&#uZUGZ{`!Qwkgd-#-92Cg^I05th zmQ07Sw$I}!hyM~OkfM)IoboP}GJpGI=PMAscB&;3h)QK|eSUKp$Q90b^|Y~(0?B^g z|G*ihK#G1mW7NPiUr#rtg$YcUs2OkCet)ANpX=)D9Ju9#P7A^ioilp=bGK~~1~OTN zOa?;ZMqQy@PFuo(feer#1B7+IdD4e(eMK-n_+qbfs+ioBn||zkg)^^u%sO0iO4OPD z<-VKJGQx`T2M)kNZj<{qxN>vv0y!OU$}YqafW-rMI>i8- z2U8tAzf{ATG6FL^)>UYX*S$0?1Lv2%HFv|7-UTua+4G7uybI*C*NLm`zu{<@Cz?4Z zuXFq?0MYR5)4QBRr8ReT_&y863*X{}r*0EqK8oMo)a0-rkYZ$!lwm=z zNL$XMaHhfYVYOn)fM4<9#h&~7R8x)KGuJ4vQoj{{|C%;$KC=Wy71^#0;V`wNMR2DP zE4~A!wkC^-h)R^xO2>**k!bp0*Q_ca->KQ2W4Jc$zERM<5fT3`KR``mh7Cb-@_p9jq1wuD|HnV!qS;+ zTNktWLVTWS-SL^_j{E%ow$bD7UiHl?=dJ$=24*BHWZ^IpHR^4Ba-JC1vFnMM!cT~r z*5jdyRI?LU_cB|=Ef>C+7DNkR)xazXj9G9@Ys<>xqC+O#vwq>Dr%!DgHg?%}GX?4w znU->)T=uHRT$IYDqOJn7|8m{G{!&srqu1u{CZRumF?7NvLu8hVu0u8^ys6yFI{8J zhg<)#&HMkilwUaWQ${uuRSghT4G_dL%FoW!|Ar$cro6=_YMN4I=ZTamF8ag5*>JLn z-3uik_tnCASt!}$AJ&YW0Wv;96=pI|o!0Y#<#VE{GSBY?kuWh0Rg;Zdhy-QGg2^V1 z9sXe|j$W5L&)HLkPD{tBcVa0@xvu$Lv1w)kYI=!>@BEqlk0Nw&=^YQedbyGd7CkWO z2qz2VqpsujS0P=Y1ww?}X$cyS$Dw`<=qWICPA{pS_w3E+Y z*t<}&`xaZ>yI?%=$|*aS0Q|HZRb|2eN{j4$Gs(AhGrMofUzY#Bb|)}_2~!PQXoFi` zKlq-73I4$Mv>t1+Ac|U#=aKzak%dv}xi{H=-);IKn||lX1y^OJjUHdtMD4h(gs0MT z!!?Hi$hDsG_^G1?%fiTBJZyn`myv~$d+t9IPkQ2|X-?o8ohoW;@VZaE(CCxu=wSBW z#J04*Op3>6MjkcD{z% zOVpGreO6A%fa%}x{qKm-qo+;!9T9rmbbgs{(diBl4Jp-Q@sI)I%0{x**+yT`M3Vh4 zy6Q=SUwZtQwUG;Be!j~tIEXkE$o!s*|8H-qrWd|$>!+NrFq3){YfOon?cJD@uWH*}%I%rhlIL(mq>_r)JKOfeet9*E;9S_wqgoE6h-z0GtK0 z^432-86gi*obt#Kn}L*)E1mbq=ENxiI}JXs6-Q{}A1e_@6_is4Z7ma+Jf>d6IZ@p@ zx-i9HRPIkX1>m&gWvk){Y_d~RI6{j(Kfh>v+I!(V5zV-=A`@OIqBri_{sfY=^7NR# zZp6SZAa+Bd?&(7(HpEfU51Uc;Q7SXl$~LuSDICE~Yk?&&cnA?y9Sb&gM8e{M3xCsY zs%1T#%$Kk#R_MUA@NVBeD!``}#!=N+Gevk)h6J4!Uiu4SpX<-$25YsBK{E!XJIblJ zDfK&X)7Mc(N%+HD+(ddM&S~OVN zQ~&z1ICPi0pS|vg0k5|8Pl<%Bt&={nsC2oB%{xw5YxveD3*WR7Qm)b+)T-m(F_<4GRfo^ih1RUQhsW2Y_tSE_-}?KfeRnm^vMQU<1VasgL(A+_%blH_Z6Q@W;O& zo*8-Vj5G!cW`!A|Z#-#DI|q89-7A`n@5@U+jD_AZ#*>nrq=g_2G9Z6)t& z{7gzq!P4>a+Q8<}*vS6}bzZ>yJ%G+nS+i@R`!mfqp zFDOM>MV*ULv_Mvx5z{C3JbuT{4*|r0AO`RNF`Rbf%V$TjKt3A(pItWhE)?AI`K4*^ z0Ht&d-UCM2Nz`dQ-OS1yv4H0Iftw>45J%tt^Y+!^C=^`3%=+F1V1C{^ z*E;_%aTLh>>en`m@Gg+^o1Oj2+8cX9FM9pv&o=r1*3nL%*~MGD_i5V8SD3&Am>`lX zUvc%{@DYKXGM9D{5!$isDtHHAakOWoNLcLg^ro`<%mb0ya}A9<5=Q{e&v)tuI6^zW z2Hp|c*naf!KJC45p2(Y`GG<`jhI z&z&9fWSYJpwobPQMsU*z5;U4yaMbJIP#@TNipAacC|+7$Ut>iX+}(++po081B>}- zxtEuT7aK$L?)EPnb=sHa!I7lN5&&UTH(LHyaB`hnoxt_mKH+?go?ljv^9$X#AeY|U z=NJoA!${VHi|0MtKew8DeZgn8`*@c(20XFOH^se<1{`z{MVTn&T!p~OGs^U} zW&Wu*ek+}FYg8z2_}LAc9sAqVpGzrvPNV;hWy1;^(A}^oMosJSP(8-{3zk#6|2r*| z8jRKYqkH$$E7^taOCA4ZVX?g~|LC$)2mN=60Z|MBQ(T0|MJX4VbLM9h>03(xnTD^M zF8E^Hfiv#e_CTI{f2$Q!jkAKyD&pq@%K$4qvdD*zp<3$s>h^s0+!h^2J)H68^KUG# zTJ}dWDvj^AieFvefN_532mE8pFV%1OeB+FnHKNG*0)1@PfQjF(`sMt^KI&R^>W}Bn zKen^uihgH&iHxW#orGjIYk;M@OxVZkkNo_1^R=wUlhq?@+x;)&Kc)y2Jara@B_T^h z2IBSTo9&9vEVbIR?c4Rg`}^Ttlb4@>u&BO1x%hDhVx#nnO?VUg0QWP%Zvf^;eE;^^ zJ-FeZ*oBHyKm4#+IjU05eBR{*vR_`oL~Zpd$fiGyAk70GUbD8Cg%~R2MSC1A^w>v;M^0JH7tOv@XCW+n%`%D zH$YZHRv{aIdBm|tt>yrIbm}M0Qz=i~?Qzd0Yme$fo~qtn-Q%3aWvKMhah>P<=fDB7 z5VH1%&uBRNZ#k=w&4ie8-KgSa=l(o7Z(zRQRS(QJQ$YMp!8`%QYp-vn9?Yk|eGpS!b;=%DXUVj%_K#!N z`R|d#h#FIxDVY3a#6b(UR4A8IeQ5MIxF_~mt)B@n@Ev7S4J*9g?mT^d8KVjAym#&2 zd4dXD+3csuh>*g0?+Tw&)p>%r-!Hpopm#l#l=|#SOazvj@+MWCH~S7Cn>Njq%UQAg zW2)w(nK0jBcsJ#x3{_>tGW9#p96;fMDF$ywXvIj5;AQY;RpbdPUb^#Wll4e4_x6pr znBd-Ah2)WU1}eLpLo;DE`j>zRLx2=Tz&G)8T7%bO2Ml7aFy~^ zg3ICyuG&T3^*BNiFFc4Vlc3^?>YmEhR4yB#T81wa3gCgLk(lanR0Z#Wrff`gKcmE- ziE@*U8MU+XW`7LLjB1&~rrr7#uFNc6ZcAmOjI#=<7pF@!_3{U`tu?m|Rt3`3rrwHTU+Sx{G zcXacoqlpcVUcUuEfCWg@dwK8WV_zA^ak*SB$J4+1{P$+Cm>x54?N+0WjIW_|L%XV( z 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 -DOPENOCD_DEFAULT_PATH=`` +parameter when building. + +Here is an example for building the :ref:`hello_world` application. + +.. zephyr-app-commands:: + :zephyr-app: samples/hello_world + :board: heltec_wireless_stick_lite_v3 + :goals: build flash + :gen-args: -DOPENOCD= -DOPENOCD_DEFAULT_PATH= + +You can debug an application in the usual way. Here is an example for the :ref:`hello_world` application. + +.. zephyr-app-commands:: + :zephyr-app: samples/hello_world + :board: heltec_wireless_stick_lite_v3 + :goals: debug + +References +********** + +- `Heltec Wireless Stick Lite (v3) Pinout Diagram `_ +- `Heltec Wireless Stick Lite (v3) Schematic Diagrams `_ +- `ESP-IDF Programming Guide `_ +- `esptool documentation `_ +- `OpenOCD ESP32 `_ + +.. [1] https://heltec.org/project/wireless-stick-lite-v2/ diff --git a/boards/xtensa/heltec_wireless_stick_lite_v3/heltec_wireless_stick_lite_v3-pinctrl.dtsi b/boards/xtensa/heltec_wireless_stick_lite_v3/heltec_wireless_stick_lite_v3-pinctrl.dtsi new file mode 100644 index 00000000000..6afc36ddec6 --- /dev/null +++ b/boards/xtensa/heltec_wireless_stick_lite_v3/heltec_wireless_stick_lite_v3-pinctrl.dtsi @@ -0,0 +1,70 @@ +/* + * Copyright (c) 2022 Espressif Systems (Shanghai) Co., Ltd. + * Copyright (c) 2023 The Zephyr Project Contributors + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include +#include +#include + +&pinctrl { + uart0_default: uart0_default { + group1 { + pinmux = ; + output-high; + }; + group2 { + pinmux = ; + bias-pull-up; + }; + }; + + uart1_default: uart1_default { + group1 { + pinmux = ; + output-high; + }; + group2 { + pinmux = ; + bias-pull-up; + }; + }; + + i2c0_default: i2c0_default { + group1 { + pinmux = , + ; + bias-pull-up; + drive-open-drain; + output-high; + }; + }; + + spim2_default: spim2_default { + group1 { + pinmux = , + , + ; + }; + group2 { + pinmux = ; + output-low; + }; + }; + + twai_default: twai_default { + group1 { + pinmux = , + ; + }; + }; + + ledc0_default: ledc0_default { + group1 { + pinmux = ; + output-enable; + }; + }; +}; diff --git a/boards/xtensa/heltec_wireless_stick_lite_v3/heltec_wireless_stick_lite_v3.dts b/boards/xtensa/heltec_wireless_stick_lite_v3/heltec_wireless_stick_lite_v3.dts new file mode 100644 index 00000000000..c91564a303f --- /dev/null +++ b/boards/xtensa/heltec_wireless_stick_lite_v3/heltec_wireless_stick_lite_v3.dts @@ -0,0 +1,215 @@ +/* + * Copyright (c) 2021 Instituto de Pesquisas Eldorado (eldorado.org.br) + * Copyright (c) 2022 Espressif Systems (Shanghai) Co., Ltd. + * Copyright (c) 2023 The Zephyr Project Contributors + * + * SPDX-License-Identifier: Apache-2.0 + */ +/dts-v1/; + +#include +#include "heltec_wireless_stick_lite_v3-pinctrl.dtsi" +#include +#include +#include + +/ { + model = "heltec_wireless_stick_lite_v3"; + compatible = "espressif,esp32s3"; + + aliases { + pwm-0 = &ledc0; + pwm-led0 = &pwm_led_white; + uart-0 = &uart0; + uart-1 = &uart1; + i2c-0 = &i2c0; + lora0 = &lora0; + sw0 = &button0; + watchdog0 = &wdt0; + }; + + leds { + compatible = "gpio-leds"; + + vext: vext { + gpios = <&gpio0 36 (GPIO_PULL_UP | GPIO_ACTIVE_LOW)>; + label = "Vext Control"; + }; + + adc: adc { + gpios = <&gpio0 37 GPIO_ACTIVE_LOW>; + label = "ADC Control"; + }; + }; + + pwmleds { + compatible = "pwm-leds"; + pwm_led_white: pwm_led_gpio0_35 { + label = "White PWM LED"; + pwms = <&ledc0 0 PWM_MSEC(10) PWM_POLARITY_NORMAL>; + }; + }; + + buttons { + compatible = "gpio-keys"; + button0: button_0 { + gpios = <&gpio0 0 (GPIO_PULL_UP | GPIO_ACTIVE_LOW)>; + label = "USER SW"; + zephyr,code = ; + }; + }; + + vbatt { + compatible = "voltage-divider"; + io-channels = <&adc1 0>; + output-ohms = <100000>; + full-ohms = <(100000 + 390000)>; + }; + + chosen { + zephyr,sram = &sram0; + zephyr,console = &uart0; + zephyr,shell-uart = &uart0; + zephyr,flash = &flash0; + }; +}; + +&cpu0 { + clock-frequency = ; +}; + +&cpu1 { + clock-frequency = ; +}; + +&adc1 { + status ="okay"; +}; + +&uart0 { + status = "okay"; + current-speed = <115200>; + pinctrl-0 = <&uart0_default>; + pinctrl-names = "default"; +}; + +&gpio0 { + status = "okay"; +}; + +&gpio1 { + status = "okay"; +}; + +&ledc0 { + pinctrl-0 = <&ledc0_default>; + pinctrl-names = "default"; + status = "okay"; + #address-cells = <1>; + #size-cells = <0>; + channel0@0 { + reg = <0x0>; + timer = <0>; + }; +}; + +&i2c0 { + clock-frequency = ; + pinctrl-0 = <&i2c0_default>; + pinctrl-names = "default"; +}; + +&spi2 { + #address-cells = <1>; + #size-cells = <0>; + status = "okay"; + pinctrl-0 = <&spim2_default>; + pinctrl-names = "default"; + lora0: lora@0 { + compatible = "semtech,sx1262"; + reg = <0>; + reset-gpios = <&gpio0 12 (GPIO_OPEN_DRAIN | GPIO_ACTIVE_LOW)>; + busy-gpios = <&gpio0 13 GPIO_ACTIVE_HIGH>; + dio1-gpios = <&gpio0 14 GPIO_ACTIVE_HIGH>; + dio2-tx-enable; + dio3-tcxo-voltage = ; + tcxo-power-startup-delay-ms = <5>; + spi-max-frequency = <16000000>; + }; +}; + +&twai { + pinctrl-0 = <&twai_default>; + pinctrl-names = "default"; + bus-speed = <125000>; +}; + +&timer0 { + status = "okay"; +}; + +&timer1 { + status = "okay"; +}; + +&timer2 { + status = "okay"; +}; + +&timer3 { + status = "okay"; +}; + +&wdt0 { + status = "okay"; +}; + +&trng0 { + status = "okay"; +}; + +&uart1 { + status = "okay"; + current-speed = <115200>; + pinctrl-0 = <&uart1_default>; + pinctrl-names = "default"; +}; + +&flash0 { + status = "okay"; + partitions { + compatible = "fixed-partitions"; + #address-cells = <1>; + #size-cells = <1>; + + /* Reserve 64kB for the bootloader */ + boot_partition: partition@0 { + label = "mcuboot"; + reg = <0x00000000 0x00010000>; + read-only; + }; + + /* Reserve 1024kB for the application in slot 0 */ + slot0_partition: partition@10000 { + label = "image-0"; + reg = <0x00010000 0x00100000>; + }; + + /* Reserve 1024kB for the application in slot 1 */ + slot1_partition: partition@110000 { + label = "image-1"; + reg = <0x00110000 0x00100000>; + }; + + /* Reserve 256kB for the scratch partition */ + scratch_partition: partition@210000 { + label = "image-scratch"; + reg = <0x00210000 0x00040000>; + }; + + storage_partition: partition@250000 { + label = "storage"; + reg = <0x00250000 0x00006000>; + }; + }; +}; diff --git a/boards/xtensa/heltec_wireless_stick_lite_v3/heltec_wireless_stick_lite_v3.yaml b/boards/xtensa/heltec_wireless_stick_lite_v3/heltec_wireless_stick_lite_v3.yaml new file mode 100644 index 00000000000..05c89b6d984 --- /dev/null +++ b/boards/xtensa/heltec_wireless_stick_lite_v3/heltec_wireless_stick_lite_v3.yaml @@ -0,0 +1,22 @@ +identifier: heltec_wireless_stick_lite_v3 +name: Heltec Wireless Stick Lite (V3) +type: mcu +arch: xtensa +toolchain: + - zephyr +supported: + - gpio + - uart + - i2c + - spi + - can + - counter + - watchdog + - entropy + - pwm + - dma + - lora +testing: + ignore_tags: + - net + - bluetooth diff --git a/boards/xtensa/heltec_wireless_stick_lite_v3/heltec_wireless_stick_lite_v3_defconfig b/boards/xtensa/heltec_wireless_stick_lite_v3/heltec_wireless_stick_lite_v3_defconfig new file mode 100644 index 00000000000..a32ddde0422 --- /dev/null +++ b/boards/xtensa/heltec_wireless_stick_lite_v3/heltec_wireless_stick_lite_v3_defconfig @@ -0,0 +1,14 @@ +# SPDX-License-Identifier: Apache-2.0 + +CONFIG_BOARD_HELTEC_WIRELESS_STICK_LITE=y +CONFIG_SOC_SERIES_ESP32S3=y + +CONFIG_MAIN_STACK_SIZE=2048 + +CONFIG_CLOCK_CONTROL=y +CONFIG_CONSOLE=y +CONFIG_GPIO=y +CONFIG_PWM=y +CONFIG_SERIAL=y +CONFIG_SPI=y +CONFIG_UART_CONSOLE=y diff --git a/boards/xtensa/heltec_wireless_stick_lite_v3/support/openocd.cfg b/boards/xtensa/heltec_wireless_stick_lite_v3/support/openocd.cfg new file mode 100644 index 00000000000..2f740b4a36a --- /dev/null +++ b/boards/xtensa/heltec_wireless_stick_lite_v3/support/openocd.cfg @@ -0,0 +1,7 @@ +set ESP_RTOS none +set ESP32_ONLYCPU 1 + +# Source the JTAG interface configuration file +source [find interface/esp_usb_jtag.cfg] +# Source the ESP32-S3 configuration file +source [find target/esp32s3.cfg] From 7d63942c31709739578797ce91b69818308bd9e1 Mon Sep 17 00:00:00 2001 From: Alexander Leris Date: Fri, 3 Nov 2023 01:16:00 +1100 Subject: [PATCH 0008/3723] doc: logging: Fix some grammar issues Fixes some grammar issues in the documentation. Signed-off-by: Alexander Leris --- doc/services/logging/index.rst | 63 ++++++++++++++++--------------- include/zephyr/logging/log_ctrl.h | 2 +- 2 files changed, 33 insertions(+), 32 deletions(-) diff --git a/doc/services/logging/index.rst b/doc/services/logging/index.rst index 2b9fe9a707a..84d862b9076 100644 --- a/doc/services/logging/index.rst +++ b/doc/services/logging/index.rst @@ -124,9 +124,9 @@ allocated. :kconfig:option:`CONFIG_LOG_PRINTK`: Redirect printk calls to the logging. -:kconfig:option:`CONFIG_LOG_PROCESS_TRIGGER_THRESHOLD`: When number of buffered log -messages reaches the threshold dedicated thread (see :c:func:`log_thread_set`) -is waken up. If :kconfig:option:`CONFIG_LOG_PROCESS_THREAD` is enabled then this +:kconfig:option:`CONFIG_LOG_PROCESS_TRIGGER_THRESHOLD`: When the number of buffered log +messages reaches the threshold, the dedicated thread (see :c:func:`log_thread_set`) +is woken up. If :kconfig:option:`CONFIG_LOG_PROCESS_THREAD` is enabled then this threshold is used by the internal thread. :kconfig:option:`CONFIG_LOG_PROCESS_THREAD`: When enabled, logging thread is created @@ -242,7 +242,7 @@ Logging in a module instance ============================ In case of modules which are multi-instance and instances are widely used -across the system enabling logs will lead to flooding. Logger provide the tools +across the system enabling logs will lead to flooding. The logger provides the tools which can be used to provide filtering on instance level rather than module level. In that case logging can be enabled for particular instance. @@ -305,16 +305,16 @@ By default, logging processing in deferred mode is handled internally by the dedicated task which starts automatically. However, it might not be available if multithreading is disabled. It can also be disabled by unsetting :kconfig:option:`CONFIG_LOG_PROCESS_TRIGGER_THRESHOLD`. In that case, logging can -be controlled using API defined in :zephyr_file:`include/zephyr/logging/log_ctrl.h`. -Logging must be initialized before it can be used. Optionally, user can provide -function which returns timestamp value. If not provided, :c:macro:`k_cycle_get` +be controlled using the API defined in :zephyr_file:`include/zephyr/logging/log_ctrl.h`. +Logging must be initialized before it can be used. Optionally, the user can provide +a function which returns the timestamp value. If not provided, :c:macro:`k_cycle_get` or :c:macro:`k_cycle_get_32` is used for timestamping. -:c:func:`log_process` function is used to trigger processing of one log -message (if pending). Function returns true if there is more messages pending. +The :c:func:`log_process` function is used to trigger processing of one log +message (if pending), and returns true if there are more messages pending. However, it is recommended to use macro wrappers (:c:macro:`LOG_INIT` and -:c:macro:`LOG_PROCESS`) which handles case when logging is disabled. +:c:macro:`LOG_PROCESS`) which handle the case where logging is disabled. -Following snippet shows how logging can be processed in simple forever loop. +The following snippet shows how logging can be processed in simple forever loop. .. code-block:: c @@ -356,16 +356,17 @@ that moment all logs are processed in a blocking way. Printk ****** -Typically, logging and :c:func:`printk` is using the same output for which they -compete. This can lead to issues if the output does not support preemption but -also it may result in the corrupted output because logging data is interleaved -with printk data. However, it is possible to redirect printk messages to the +Typically, logging and :c:func:`printk` use the same output, which they compete +for. This can lead to issues if the output does not support preemption but it may +also result in corrupted output because logging data is interleaved with printk +data. However, it is possible to redirect printk messages to the logging subsystem by enabling :kconfig:option:`CONFIG_LOG_PRINTK`. In that case, printk entries are treated as log messages with level 0 (they cannot be disabled). When enabled, logging manages the output so there is no interleaving. However, -in the deferred mode it changes the behavior of the printk because output is delayed -until logging thread processes the data. :kconfig:option:`CONFIG_LOG_PRINTK` is by -default enabled. +in deferred mode the printk behaviour is changed since the output is delayed +until the logging thread processes the data. :kconfig:option:`CONFIG_LOG_PRINTK` +is enabled by default. + .. _log_architecture: @@ -384,27 +385,27 @@ instance of a module. Default Frontend ================ -Default frontend is engaged when logging API is called in a source of logging (e.g. +Default frontend is engaged when the logging API is called in a source of logging (e.g. :c:macro:`LOG_INF`) and is responsible for filtering a message (compile and run -time), allocating buffer for the message, creating the message and committing that -message. Since logging API can be called in an interrupt, frontend is optimized +time), allocating a buffer for the message, creating the message and committing that +message. Since the logging API can be called in an interrupt, the frontend is optimized to log the message as fast as possible. Log message ----------- -Log message contains message descriptor (source, domain and level), timestamp, +A log message contains a message descriptor (source, domain and level), timestamp, formatted string details (see :ref:`cbprintf_packaging`) and optional data. Log messages are stored in a continuous block of memory. -Memory is allocated from a circular packet buffer (:ref:`mpsc_pbuf`). It has -few consequences: +Memory is allocated from a circular packet buffer (:ref:`mpsc_pbuf`), which has +a few consequences: - * Each message is self-contained, continuous block of memory thus it is suited + * Each message is a self-contained, continuous block of memory thus it is suited for copying the message (e.g. for offline processing). * Messages must be sequentially freed. Backend processing is synchronous. Backend can make a copy for deferred processing. -Log message has following format: +A log message has following format: +------------------+----------------------------------------------------+ | Message Header | 2 bits: MPSC packet buffer header | @@ -446,12 +447,12 @@ Log message has following format: Log message allocation ---------------------- -It may happen that frontend cannot allocate a message. It happens if system is -generating more log messages than it can process in certain time frame. There -are two strategies to handle that case: +It may happen that the frontend cannot allocate a message. This happens if the +system is generating more log messages than it can process in certain time +frame. There are two strategies to handle that case: -- No overflow - new log is dropped if space for a message cannot be allocated. -- Overflow - oldest pending messages are freed, until new message can be +- No overflow - the new log is dropped if space for a message cannot be allocated. +- Overflow - the oldest pending messages are freed, until the new message can be allocated. Enabled by :kconfig:option:`CONFIG_LOG_MODE_OVERFLOW`. Note that it degrades performance thus it is recommended to adjust buffer size and amount of enabled logs to limit dropping. diff --git a/include/zephyr/logging/log_ctrl.h b/include/zephyr/logging/log_ctrl.h index dc5f39a2e7d..6b8a5ec0414 100644 --- a/include/zephyr/logging/log_ctrl.h +++ b/include/zephyr/logging/log_ctrl.h @@ -82,7 +82,7 @@ __syscall void log_panic(void); /** * @brief Process one pending log message. * - * @retval true There is more messages pending to be processed. + * @retval true There are more messages pending to be processed. * @retval false No messages pending. */ __syscall bool log_process(void); From 0d42acadb43463a15bcb5be2ef39fb7c2af516bd Mon Sep 17 00:00:00 2001 From: Erwan Gouriou Date: Mon, 2 Oct 2023 15:10:08 +0200 Subject: [PATCH 0009/3723] boards: nucleo_wb55rg: Use stm32cubeprogrammer as default runner When playing with PM related applications, stm32cubeprogrammer is useful to allow flashing even when SoC is in Stop mode. Signed-off-by: Erwan Gouriou --- boards/arm/nucleo_wb55rg/board.cmake | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/boards/arm/nucleo_wb55rg/board.cmake b/boards/arm/nucleo_wb55rg/board.cmake index 83fd477865f..75762ef577e 100644 --- a/boards/arm/nucleo_wb55rg/board.cmake +++ b/boards/arm/nucleo_wb55rg/board.cmake @@ -2,6 +2,6 @@ board_runner_args(pyocd "--target=stm32wb55rgvx") board_runner_args(stm32cubeprogrammer "--port=swd" "--reset-mode=hw") +include(${ZEPHYR_BASE}/boards/common/stm32cubeprogrammer.board.cmake) include(${ZEPHYR_BASE}/boards/common/openocd.board.cmake) include(${ZEPHYR_BASE}/boards/common/pyocd.board.cmake) -include(${ZEPHYR_BASE}/boards/common/stm32cubeprogrammer.board.cmake) From e5ab70b72431b143766935c434f139ae9b5cd3e5 Mon Sep 17 00:00:00 2001 From: Erwan Gouriou Date: Thu, 16 Nov 2023 12:17:59 +0100 Subject: [PATCH 0010/3723] drivers: uart: stm32: Complete wakeup feature Serial wakeup feature was only working whe DBG in Stop mode setting was enabled. Add required changes to make it functional also when this configuration isn't set. Signed-off-by: Erwan Gouriou --- drivers/serial/uart_stm32.c | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+) diff --git a/drivers/serial/uart_stm32.c b/drivers/serial/uart_stm32.c index fa2371cc1df..5c1ff75bd6d 100644 --- a/drivers/serial/uart_stm32.c +++ b/drivers/serial/uart_stm32.c @@ -1278,6 +1278,18 @@ static void uart_stm32_isr(const struct device *dev) /* Clear errors */ uart_stm32_err_check(dev); #endif /* CONFIG_UART_ASYNC_API */ + +#ifdef CONFIG_PM + if (LL_USART_IsEnabledIT_WKUP(config->usart) && + LL_USART_IsActiveFlag_WKUP(config->usart)) { + + LL_USART_ClearFlag_WKUP(config->usart); +#ifdef USART_ISR_REACK + while (LL_USART_IsActiveFlag_REACK(config->usart) == 0) { + } +#endif + } +#endif } #endif /* CONFIG_UART_INTERRUPT_DRIVEN || CONFIG_UART_ASYNC_API || CONFIG_PM */ @@ -2005,7 +2017,14 @@ static int uart_stm32_init(const struct device *dev) * CONFIG_PM_DEVICE=n : Always active * CONFIG_PM_DEVICE=y : Controlled by pm_device_wakeup_enable() */ + + LL_USART_Disable(config->usart); + LL_USART_SetWKUPType(config->usart, LL_USART_WAKEUP_ON_RXNE); + LL_USART_EnableIT_WKUP(config->usart); + LL_USART_ClearFlag_WKUP(config->usart); LL_USART_EnableInStopMode(config->usart); + LL_USART_Enable(config->usart); + if (config->wakeup_line != STM32_EXTI_LINE_NONE) { /* Prepare the WAKEUP with the expected EXTI line */ LL_EXTI_EnableIT_0_31(BIT(config->wakeup_line)); From b4fcbc4eb68d4def62187fa0bb4f1f12ea782ae7 Mon Sep 17 00:00:00 2001 From: Erwan Gouriou Date: Thu, 16 Nov 2023 12:21:20 +0100 Subject: [PATCH 0011/3723] samples: boards: stm32: serial_wakeup: Fix nucloe_wb55rg configuration On STM32WB55 series, wakeup in stop mode is not supported. Disable this state in order to support this sample. Add comments to other sections of the configuration. Signed-off-by: Erwan Gouriou --- .../boards/nucleo_wb55rg.overlay | 20 +++++++++++++++++-- 1 file changed, 18 insertions(+), 2 deletions(-) diff --git a/samples/boards/stm32/power_mgmt/serial_wakeup/boards/nucleo_wb55rg.overlay b/samples/boards/stm32/power_mgmt/serial_wakeup/boards/nucleo_wb55rg.overlay index f924e6fdea5..bcbed7c5824 100644 --- a/samples/boards/stm32/power_mgmt/serial_wakeup/boards/nucleo_wb55rg.overlay +++ b/samples/boards/stm32/power_mgmt/serial_wakeup/boards/nucleo_wb55rg.overlay @@ -1,19 +1,35 @@ /* * Copyright (c) 2022 Linaro Limited + * Copyright (c) 2022 STMicroelectronics * * SPDX-License-Identifier: Apache-2.0 */ -&clk_hsi { - status = "okay"; +&cpu0{ + /* USART Wakeup requires automatic HSI16 switch on in deepsleep mode + * which isn't possible in Stop Mode 2. + * Remove Stop Mode 2 from supported modes + */ + cpu-power-states = <&stop0 &stop1>; }; &usart1 { + /* Set domain clock to HSI to allow wakeup from Stop mode */ clocks = <&rcc STM32_CLOCK_BUS_APB2 0x00004000>, <&rcc STM32_SRC_HSI USART1_SEL(2)>; + /* Configure device as wakeup source */ wakeup-source; + /* Configure sleep pinctrl configuration which will be used when + * device is not configured as wakeup source by the application. + * This use case is only applicable in PM_DEVICE mode. + */ pinctrl-1 = <&analog_pb6 &analog_pb7>; pinctrl-names = "default", "sleep"; }; + +&clk_hsi { + /* Make sure HSI is enabled */ + status = "okay"; +}; From 6a96ee88b319db55cf507d16c274ea903e90fbd9 Mon Sep 17 00:00:00 2001 From: Erwan Gouriou Date: Thu, 16 Nov 2023 12:25:13 +0100 Subject: [PATCH 0012/3723] samples: boards: stm32: serial_wakeup: Minor changes Cleanup sample yaml file and code comments. Enable PM_DEVICE_RUNTIME mode. Signed-off-by: Erwan Gouriou --- samples/boards/stm32/power_mgmt/serial_wakeup/prj.conf | 5 +++-- samples/boards/stm32/power_mgmt/serial_wakeup/sample.yaml | 2 -- samples/boards/stm32/power_mgmt/serial_wakeup/src/main.c | 3 ++- 3 files changed, 5 insertions(+), 5 deletions(-) diff --git a/samples/boards/stm32/power_mgmt/serial_wakeup/prj.conf b/samples/boards/stm32/power_mgmt/serial_wakeup/prj.conf index 3e1a61bf9db..ca1e6cf73a9 100644 --- a/samples/boards/stm32/power_mgmt/serial_wakeup/prj.conf +++ b/samples/boards/stm32/power_mgmt/serial_wakeup/prj.conf @@ -1,7 +1,8 @@ CONFIG_PM=y CONFIG_PM_DEVICE=y -CONFIG_PM_DEVICE_RUNTIME=n -CONFIG_PM_DEVICE_RUNTIME_EXCLUSIVE=n +CONFIG_PM_DEVICE_RUNTIME=y +CONFIG_PM_DEVICE_RUNTIME_EXCLUSIVE=y + CONFIG_SHELL=y CONFIG_DEBUG=n diff --git a/samples/boards/stm32/power_mgmt/serial_wakeup/sample.yaml b/samples/boards/stm32/power_mgmt/serial_wakeup/sample.yaml index 42528be505d..e0f61361500 100644 --- a/samples/boards/stm32/power_mgmt/serial_wakeup/sample.yaml +++ b/samples/boards/stm32/power_mgmt/serial_wakeup/sample.yaml @@ -4,8 +4,6 @@ tests: sample.boards.stm32.power_mgmt.serial_wakeup: tags: - UART - - Wake - - up - power harness: console harness_config: diff --git a/samples/boards/stm32/power_mgmt/serial_wakeup/src/main.c b/samples/boards/stm32/power_mgmt/serial_wakeup/src/main.c index 74284abf41b..35846c04411 100644 --- a/samples/boards/stm32/power_mgmt/serial_wakeup/src/main.c +++ b/samples/boards/stm32/power_mgmt/serial_wakeup/src/main.c @@ -24,7 +24,8 @@ int main(void) #if CONFIG_PM_DEVICE /* In PM_DEVICE modes, enable device as a wakeup source will prevent * system to switch it off (clock off, set pins to sleep configuration, ...) - * It is not requested in PM mode only since this mode will not + * It is not requested in CONFIG_PM mode only as in this case, device is not + * suspended before stop mode entry. */ bool ret; From c6bba39f4d8d4ac4148a59e5d8cdc0c26b9c9926 Mon Sep 17 00:00:00 2001 From: Erwan Gouriou Date: Thu, 16 Nov 2023 12:29:34 +0100 Subject: [PATCH 0013/3723] dts: stm32wl: Configure LPUART wakeup line Rather than configuring in serial_wakeup sample, define LPUART1 wakeup line in wl.dtsi file. Additionally make few cosmetic changes to nucleo_wl55rj overlay in serial wakeup sample. Signed-off-by: Erwan Gouriou --- dts/arm/st/wl/stm32wl.dtsi | 1 + .../serial_wakeup/boards/nucleo_wl55jc.overlay | 15 +++++++++------ 2 files changed, 10 insertions(+), 6 deletions(-) diff --git a/dts/arm/st/wl/stm32wl.dtsi b/dts/arm/st/wl/stm32wl.dtsi index cc4b4dc31c9..feeb013af6e 100644 --- a/dts/arm/st/wl/stm32wl.dtsi +++ b/dts/arm/st/wl/stm32wl.dtsi @@ -259,6 +259,7 @@ clocks = <&rcc STM32_CLOCK_BUS_APB1_2 0x00000001>; resets = <&rctl STM32_RESET(APB1H, 0U)>; interrupts = <38 0>; + wakeup-line = <28>; status = "disabled"; }; diff --git a/samples/boards/stm32/power_mgmt/serial_wakeup/boards/nucleo_wl55jc.overlay b/samples/boards/stm32/power_mgmt/serial_wakeup/boards/nucleo_wl55jc.overlay index 83c607ff8a0..8b6b062cd67 100644 --- a/samples/boards/stm32/power_mgmt/serial_wakeup/boards/nucleo_wl55jc.overlay +++ b/samples/boards/stm32/power_mgmt/serial_wakeup/boards/nucleo_wl55jc.overlay @@ -4,17 +4,20 @@ * SPDX-License-Identifier: Apache-2.0 */ -&clk_lse { - status = "okay"; -}; -/* LPUART1 clock source on LSE : set console at 9600 */ &lpuart1 { - /delete-property/ clocks; + /* Set domain clock to LSE to allow wakeup from Stop mode */ clocks = <&rcc STM32_CLOCK_BUS_APB1_2 0x00000001>, <&rcc STM32_SRC_LSE LPUART1_SEL(3)>; + /* LPUART1 clock source on LSE : set console at 9600 */ current-speed = <9600>; + + /* Enable as wakeup source */ wakeup-source; - wakeup-line = <28>; +}; + +&clk_lse { + /* Make sure LSE clock is enabled */ + status = "okay"; }; From 5b9605a6a20c0ebe2dab063a1b818dfb1826dc19 Mon Sep 17 00:00:00 2001 From: Daniel Leung Date: Thu, 24 Aug 2023 12:20:50 -0700 Subject: [PATCH 0014/3723] xtensa: mmu: implement cached/uncached ptr funcs if !RPO_CACHE This implements the following functions when CONFIG_XTENSA_RPO_CACHE is false: * arch_xtensa_is_ptr_cached() returns false * arch_xtensa_is_ptr_uncached() returns false * arch_xtensa_cached_ptr() returns unmodified pointer * arch_xtensa_uncached_ptr() returns unmodified pointer Signed-off-by: Daniel Leung --- include/zephyr/arch/xtensa/arch.h | 28 +++++++++++++++++++++++++++- 1 file changed, 27 insertions(+), 1 deletion(-) diff --git a/include/zephyr/arch/xtensa/arch.h b/include/zephyr/arch/xtensa/arch.h index 2d13615a753..0838e68ee5a 100644 --- a/include/zephyr/arch/xtensa/arch.h +++ b/include/zephyr/arch/xtensa/arch.h @@ -243,7 +243,33 @@ static inline void *arch_xtensa_uncached_ptr(void __sparse_cache *ptr) FOR_EACH(_SET_ONE_TLB, (;), 0, 1, 2, 3, 4, 5, 6, 7); \ } while (0) -#endif +#else /* CONFIG_XTENSA_RPO_CACHE */ + +static inline bool arch_xtensa_is_ptr_cached(void *ptr) +{ + ARG_UNUSED(ptr); + + return false; +} + +static inline bool arch_xtensa_is_ptr_uncached(void *ptr) +{ + ARG_UNUSED(ptr); + + return false; +} + +static inline void *arch_xtensa_cached_ptr(void *ptr) +{ + return ptr; +} + +static inline void *arch_xtensa_uncached_ptr(void *ptr) +{ + return ptr; +} + +#endif /* CONFIG_XTENSA_RPO_CACHE */ #ifdef CONFIG_XTENSA_MMU extern void arch_xtensa_mmu_post_init(bool is_core0); From 080e14f0f454b9a443de44329957cb5bcbf21a51 Mon Sep 17 00:00:00 2001 From: Andy Ross Date: Mon, 21 Aug 2023 16:54:04 -0700 Subject: [PATCH 0015/3723] arch/xtensa: Rename "ALLOCA" ZSR to "A0SAVE" This register alias was originally introduced to allow A0 to be used as a scratch register when handling exceptions from MOVSP instructions. (It replaced some upstream code from Cadence that hard-coded EXCSAVE1). Now the MMU code is now using too, and for exactly the same purpose. Calling it "ALLOCA" is only confusing. Rename it to make it clear what it's doing. Signed-off-by: Andy Ross --- arch/xtensa/core/gen_zsr.py | 2 +- arch/xtensa/core/window_vectors.S | 4 ++-- arch/xtensa/core/xtensa-asm2-util.S | 18 +++++++++--------- 3 files changed, 12 insertions(+), 12 deletions(-) diff --git a/arch/xtensa/core/gen_zsr.py b/arch/xtensa/core/gen_zsr.py index 8d052f4891d..574542a4578 100755 --- a/arch/xtensa/core/gen_zsr.py +++ b/arch/xtensa/core/gen_zsr.py @@ -11,7 +11,7 @@ # -dM") core-isa.h file for the current architecture and assigns # registers to usages. -NEEDED = ("ALLOCA", "CPU", "FLUSH") +NEEDED = ("A0SAVE", "CPU", "FLUSH") coreisa = sys.argv[1] outfile = sys.argv[2] diff --git a/arch/xtensa/core/window_vectors.S b/arch/xtensa/core/window_vectors.S index a63923cbd6f..90eba495bde 100644 --- a/arch/xtensa/core/window_vectors.S +++ b/arch/xtensa/core/window_vectors.S @@ -84,7 +84,7 @@ _WindowUnderflow4: /* Handle alloca exception generated by interruptee executing 'movsp'. * This uses space between the window vectors, so is essentially * "free". All interruptee's regs are intact except a0 which is saved - * in $ZSR_ALLOCA (assigned at build time, see gen_zsr.py for + * in $ZSR_A0SAVE (assigned at build time, see gen_zsr.py for * details), and PS.EXCM has been set by the exception hardware (can't * be interrupted). The fact the alloca exception was taken means the * registers associated with the base-save area have been spilled and @@ -102,7 +102,7 @@ _xt_alloca_exc: rsr a2, PS extui a3, a2, XCHAL_PS_OWB_SHIFT, XCHAL_PS_OWB_BITS xor a3, a3, a4 /* bits changed from old to current windowbase */ - rsr a4, ZSR_ALLOCA /* restore original a0 (now in a4) */ + rsr a4, ZSR_A0SAVE /* restore original a0 (now in a4) */ slli a3, a3, XCHAL_PS_OWB_SHIFT xor a2, a2, a3 /* flip changed bits in old window base */ wsr a2, PS /* update PS.OWB to new window base */ diff --git a/arch/xtensa/core/xtensa-asm2-util.S b/arch/xtensa/core/xtensa-asm2-util.S index d7ba88aaffc..bc526ae0165 100644 --- a/arch/xtensa/core/xtensa-asm2-util.S +++ b/arch/xtensa/core/xtensa-asm2-util.S @@ -342,7 +342,7 @@ DEF_EXCINT XCHAL_DEBUGLEVEL, _handle_excint, xtensa_debugint_c .pushsection .UserExceptionVector.text, "ax" .global _Level1RealVector _Level1RealVector: - wsr a0, ZSR_ALLOCA + wsr a0, ZSR_A0SAVE rsync rsr.exccause a0 #ifdef CONFIG_XTENSA_MMU @@ -355,7 +355,7 @@ _Level1RealVector: j _xt_alloca_exc _not_alloca: - rsr a0, ZSR_ALLOCA + rsr a0, ZSR_A0SAVE j _Level1Vector #ifdef CONFIG_XTENSA_MMU _handle_tlb_miss_user: @@ -374,7 +374,7 @@ _handle_tlb_miss_user: */ rsr.ptevaddr a0 l32i a0, a0, 0 - rsr a0, ZSR_ALLOCA + rsr a0, ZSR_A0SAVE rfe #endif /* CONFIG_XTENSA_MMU */ .popsection @@ -391,12 +391,12 @@ _handle_tlb_miss_user: .global _KernelExceptionVector _KernelExceptionVector: #ifdef CONFIG_XTENSA_MMU - wsr a0, ZSR_ALLOCA + wsr a0, ZSR_A0SAVE rsr.exccause a0 beqi a0, EXCCAUSE_ITLB_MISS, _handle_tlb_miss_kernel addi a0, a0, -EXCCAUSE_DTLB_MISS beqz a0, _handle_tlb_miss_kernel - rsr a0, ZSR_ALLOCA + rsr a0, ZSR_A0SAVE #endif j _Level1Vector #ifdef CONFIG_XTENSA_MMU @@ -410,7 +410,7 @@ _handle_tlb_miss_kernel: */ rsr.ptevaddr a0 l32i a0, a0, 0 - rsr a0, ZSR_ALLOCA + rsr a0, ZSR_A0SAVE rfe #endif .popsection @@ -420,14 +420,14 @@ _handle_tlb_miss_kernel: .global _DoubleExceptionVector _DoubleExceptionVector: #ifdef CONFIG_XTENSA_MMU - wsr a0, ZSR_ALLOCA + wsr a0, ZSR_A0SAVE rsync rsr.exccause a0 addi a0, a0, -EXCCAUSE_DTLB_MISS beqz a0, _handle_tlb_miss_dblexc - rsr a0, ZSR_ALLOCA + rsr a0, ZSR_A0SAVE #endif #if defined(CONFIG_SIMULATOR_XTENSA) || defined(XT_SIMULATOR) 1: @@ -459,7 +459,7 @@ _handle_tlb_miss_dblexc: rsr.ptevaddr a0 l32i a0, a0, 0 - rsr a0, ZSR_ALLOCA + rsr a0, ZSR_A0SAVE rfde #endif .popsection From 3620e6b969d69d63e08c443234a9b49427949df3 Mon Sep 17 00:00:00 2001 From: Andy Ross Date: Sun, 27 Aug 2023 09:03:20 -0700 Subject: [PATCH 0016/3723] drivers/console: xtensa_sim_console: implement arch_printk_char_out() This is an older driver and didn't support the weak arch_printk_char_out() hook, which is a link-time symbol that allows logging to work from the first instruction. Some drivers can't do that because they need an initialization step, but this one works great. Signed-off-by: Andy Ross --- drivers/console/xtensa_sim_console.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/drivers/console/xtensa_sim_console.c b/drivers/console/xtensa_sim_console.c index 16e48eeee48..316162ddc0c 100644 --- a/drivers/console/xtensa_sim_console.c +++ b/drivers/console/xtensa_sim_console.c @@ -13,7 +13,7 @@ * @param c Character to output * @return The character passed as input. */ -static int console_out(int c) +int arch_printk_char_out(int c) { char buf[16]; @@ -54,8 +54,8 @@ extern void __printk_hook_install(int (*fn)(int)); */ static void xt_sim_console_hook_install(void) { - __stdout_hook_install(console_out); - __printk_hook_install(console_out); + __stdout_hook_install(arch_printk_char_out); + __printk_hook_install(arch_printk_char_out); } /** From a1bb2b9c640359f4d8f6f3ea9c5e89a5b821e62a Mon Sep 17 00:00:00 2001 From: Flavio Ceolin Date: Fri, 17 Nov 2023 13:54:36 -0800 Subject: [PATCH 0017/3723] xtensa: mmu: Simplify autorefill TLB helpers Replace all autorefill helpers with only one that invalidates both, DTLB and ITLB, since that is what is really needed. Signed-off-by: Flavio Ceolin --- arch/xtensa/core/include/xtensa_mmu_priv.h | 115 +++------------------ 1 file changed, 14 insertions(+), 101 deletions(-) diff --git a/arch/xtensa/core/include/xtensa_mmu_priv.h b/arch/xtensa/core/include/xtensa_mmu_priv.h index 7519c1b6010..dcfb9deefc0 100644 --- a/arch/xtensa/core/include/xtensa_mmu_priv.h +++ b/arch/xtensa/core/include/xtensa_mmu_priv.h @@ -163,119 +163,32 @@ static ALWAYS_INLINE void xtensa_itlb_entry_write_sync(uint32_t pte, uint32_t en } /** - * @brief Invalidate all ITLB entries. + * @brief Invalidate all autorefill DTLB and ITLB entries. * - * This should be used carefully since all entries in the instruction TLB - * will be erased and the only way to find lookup a physical address will be - * through the page tables. - */ -static inline void xtensa_itlb_invalidate_sync(void) -{ - uint8_t way, i; - - for (way = 0; way < Z_XTENSA_ITLB_WAYS; way++) { - for (i = 0; i < (1 << XCHAL_ITLB_ARF_ENTRIES_LOG2); i++) { - uint32_t entry = way + (i << Z_XTENSA_PPN_SHIFT); - - xtensa_itlb_entry_invalidate(entry); - } - } - __asm__ volatile("isync"); -} - -/** - * @brief Invalidate all DTLB entries. + * This should be used carefully since all refill entries in the data + * and instruction TLB. At least two pages, the current code page and + * the current stack, will be repopulated by this code as it returns. * - * This should be used carefully since all entries in the data TLB will be - * erased and the only way to find lookup a physical address will be through - * the page tables. + * This needs to be called in any circumstance where the mappings for + * a previously-used page table change. It does not need to be called + * on context switch, where ASID tagging isolates entries for us. */ -static inline void xtensa_dtlb_invalidate_sync(void) +static inline void xtensa_tlb_autorefill_invalidate(void) { - uint8_t way, i; - - for (way = 0; way < Z_XTENSA_DTLB_WAYS; way++) { - for (i = 0; i < (1 << XCHAL_DTLB_ARF_ENTRIES_LOG2); i++) { - uint32_t entry = way + (i << Z_XTENSA_PPN_SHIFT); - - xtensa_dtlb_entry_invalidate(entry); - } - } - __asm__ volatile("isync"); -} + uint8_t way, i, entries; -/** - * @brief Invalidates an autorefill DTLB entry. - * - * Invalidates the page table enrty that maps a given virtual address. - */ -static inline void xtensa_dtlb_autorefill_invalidate_sync(void *vaddr) -{ - uint8_t way; + entries = BIT(MAX(XCHAL_ITLB_ARF_ENTRIES_LOG2, + XCHAL_DTLB_ARF_ENTRIES_LOG2)); for (way = 0; way < Z_XTENSA_TLB_AUTOREFILL_WAYS; way++) { - xtensa_dtlb_entry_invalidate(Z_XTENSA_TLB_ENTRY((uint32_t)vaddr, way)); - } - __asm__ volatile("dsync"); -} - -/** - * @brief Invalidates an autorefill ITLB entry. - * - * Invalidates the page table enrty that maps a given virtual address. - */ -static inline void xtensa_itlb_autorefill_invalidate_sync(void *vaddr) -{ - uint8_t way; - - for (way = 0; way < Z_XTENSA_TLB_AUTOREFILL_WAYS; way++) { - xtensa_itlb_entry_invalidate(Z_XTENSA_TLB_ENTRY((uint32_t)vaddr, way)); - } - __asm__ volatile("isync"); -} -/** - * @brief Invalidate all autorefill ITLB entries. - * - * This should be used carefully since all entries in the instruction TLB - * will be erased and the only way to find lookup a physical address will be - * through the page tables. - */ -static inline void xtensa_itlb_autorefill_invalidate_all_sync(void) -{ - uint8_t way, i; - - for (way = 0; way < Z_XTENSA_TLB_AUTOREFILL_WAYS; way++) { - for (i = 0; i < (1 << XCHAL_ITLB_ARF_ENTRIES_LOG2); i++) { + for (i = 0; i < entries; i++) { uint32_t entry = way + (i << Z_XTENSA_PPN_SHIFT); - - xtensa_itlb_entry_invalidate(entry); + xtensa_dtlb_entry_invalidate_sync(entry); + xtensa_itlb_entry_invalidate_sync(entry); } } - __asm__ volatile("isync"); } -/** - * @brief Invalidate all autorefill DTLB entries. - * - * This should be used carefully since all entries in the data TLB will be - * erased and the only way to find lookup a physical address will be through - * the page tables. - */ -static inline void xtensa_dtlb_autorefill_invalidate_all_sync(void) -{ - uint8_t way, i; - - for (way = 0; way < Z_XTENSA_TLB_AUTOREFILL_WAYS; way++) { - for (i = 0; i < (1 << XCHAL_DTLB_ARF_ENTRIES_LOG2); i++) { - uint32_t entry = way + (i << Z_XTENSA_PPN_SHIFT); - - xtensa_dtlb_entry_invalidate(entry); - } - } - __asm__ volatile("isync"); -} - - /** * @brief Set the page tables. * From fff91cb5425c75a0118a61fe69089a7fcfc3c0e4 Mon Sep 17 00:00:00 2001 From: Flavio Ceolin Date: Wed, 1 Nov 2023 22:55:43 -0700 Subject: [PATCH 0018/3723] xtensa: mmu: Simplify initialization Simplify the logic around xtensa_mmu_init. - Do not have a different path to init part of kernel - Call xtensa_mmu_init from C Signed-off-by: Flavio Ceolin --- arch/xtensa/core/crt1.S | 8 -------- arch/xtensa/core/xtensa_mmu.c | 17 +++-------------- arch/xtensa/include/kernel_arch_func.h | 16 +++++----------- include/zephyr/arch/xtensa/xtensa_mmu.h | 2 -- 4 files changed, 8 insertions(+), 35 deletions(-) diff --git a/arch/xtensa/core/crt1.S b/arch/xtensa/core/crt1.S index 0fa3ad23099..c616b0889d7 100644 --- a/arch/xtensa/core/crt1.S +++ b/arch/xtensa/core/crt1.S @@ -24,10 +24,6 @@ .global __start .type z_cstart, @function -#ifdef CONFIG_XTENSA_MMU -.type z_xtensa_mmu_init, @function -#endif - /* Macros to abstract away ABI differences */ @@ -192,10 +188,6 @@ _start: #endif /* !XCHAL_HAVE_BOOTLOADER */ -#ifdef CONFIG_XTENSA_MMU - CALL z_xtensa_mmu_init -#endif - /* Enter C domain, never returns from here */ CALL z_cstart diff --git a/arch/xtensa/core/xtensa_mmu.c b/arch/xtensa/core/xtensa_mmu.c index e50c51a3848..18ce5f22f63 100644 --- a/arch/xtensa/core/xtensa_mmu.c +++ b/arch/xtensa/core/xtensa_mmu.c @@ -213,19 +213,18 @@ __weak void arch_xtensa_mmu_post_init(bool is_core0) ARG_UNUSED(is_core0); } -static void xtensa_mmu_init(bool is_core0) +void z_xtensa_mmu_init(void) { volatile uint8_t entry; uint32_t ps, vecbase; - if (is_core0) { + if (_current_cpu->id == 0) { /* This is normally done via arch_kernel_init() inside z_cstart(). * However, before that is called, we go through the sys_init of * INIT_LEVEL_EARLY, which is going to result in TLB misses. * So setup whatever necessary so the exception handler can work * properly. */ - z_xtensa_kernel_init(); xtensa_init_page_tables(); } @@ -326,17 +325,7 @@ static void xtensa_mmu_init(bool is_core0) xtensa_dtlb_entry_invalidate_sync(Z_XTENSA_TLB_ENTRY(Z_XTENSA_PTEVADDR + MB(4), 3)); xtensa_itlb_entry_invalidate_sync(Z_XTENSA_TLB_ENTRY(Z_XTENSA_PTEVADDR + MB(4), 3)); - arch_xtensa_mmu_post_init(is_core0); -} - -void z_xtensa_mmu_init(void) -{ - xtensa_mmu_init(true); -} - -void z_xtensa_mmu_smp_init(void) -{ - xtensa_mmu_init(false); + arch_xtensa_mmu_post_init(_current_cpu->id == 0); } #ifdef CONFIG_ARCH_HAS_RESERVED_PAGE_FRAMES diff --git a/arch/xtensa/include/kernel_arch_func.h b/arch/xtensa/include/kernel_arch_func.h index 6427b306e62..2256f72f645 100644 --- a/arch/xtensa/include/kernel_arch_func.h +++ b/arch/xtensa/include/kernel_arch_func.h @@ -25,7 +25,7 @@ extern void z_xtensa_fatal_error(unsigned int reason, const z_arch_esf_t *esf); K_KERNEL_STACK_ARRAY_DECLARE(z_interrupt_stacks, CONFIG_MP_MAX_NUM_CPUS, CONFIG_ISR_STACK_SIZE); -static ALWAYS_INLINE void z_xtensa_kernel_init(void) +static ALWAYS_INLINE void arch_kernel_init(void) { _cpu_t *cpu0 = &_kernel.cpus[0]; @@ -51,21 +51,15 @@ static ALWAYS_INLINE void z_xtensa_kernel_init(void) * win. */ XTENSA_WSR(ZSR_CPU_STR, cpu0); -} - -static ALWAYS_INLINE void arch_kernel_init(void) -{ -#ifndef CONFIG_XTENSA_MMU - /* This is called in z_xtensa_mmu_init() before z_cstart() - * so we do not need to call it again. - */ - z_xtensa_kernel_init(); -#endif #ifdef CONFIG_INIT_STACKS memset(Z_KERNEL_STACK_BUFFER(z_interrupt_stacks[0]), 0xAA, K_KERNEL_STACK_SIZEOF(z_interrupt_stacks[0])); #endif + +#ifdef CONFIG_XTENSA_MMU + z_xtensa_mmu_init(); +#endif } void xtensa_switch(void *switch_to, void **switched_from); diff --git a/include/zephyr/arch/xtensa/xtensa_mmu.h b/include/zephyr/arch/xtensa/xtensa_mmu.h index d03f876af30..2ee3dc6c9ab 100644 --- a/include/zephyr/arch/xtensa/xtensa_mmu.h +++ b/include/zephyr/arch/xtensa/xtensa_mmu.h @@ -26,6 +26,4 @@ extern int xtensa_soc_mmu_ranges_num; void z_xtensa_mmu_init(void); -void z_xtensa_mmu_smp_init(void); - #endif /* ZEPHYR_INCLUDE_ARCH_XTENSA_XTENSA_MMU_H */ From a651862b300ddb119d2ecb980d15ae5516c7de8e Mon Sep 17 00:00:00 2001 From: Flavio Ceolin Date: Wed, 14 Dec 2022 00:35:36 -0800 Subject: [PATCH 0019/3723] xtensa: Enable userspace Userspace support for Xtensa architecture using Xtensa MMU. Some considerations: - Syscalls are not inline functions like in other architectures because some compiler issues when using multiple registers to pass parameters to the syscall. So here we have a function call so we can use registers as we need. - TLS is not supported by xcc in xtensa and reading PS register is a privileged instruction. So, we have to use threadptr to know if a thread is an user mode thread. Signed-off-by: Flavio Ceolin Signed-off-by: Daniel Leung --- arch/Kconfig | 1 + arch/xtensa/Kconfig | 20 + arch/xtensa/core/CMakeLists.txt | 2 + arch/xtensa/core/fatal.c | 9 + arch/xtensa/core/include/xtensa_mmu_priv.h | 83 ++- arch/xtensa/core/offsets/offsets.c | 7 + arch/xtensa/core/syscall_helper.c | 124 ++++ arch/xtensa/core/userspace.S | 302 ++++++++ arch/xtensa/core/xtensa-asm2-util.S | 21 +- arch/xtensa/core/xtensa-asm2.c | 44 +- arch/xtensa/core/xtensa_mmu.c | 772 +++++++++++++++++++-- arch/xtensa/include/kernel_arch_func.h | 7 + arch/xtensa/include/offsets_short_arch.h | 16 +- arch/xtensa/include/xtensa-asm2-s.h | 13 +- include/zephyr/arch/syscall.h | 2 + include/zephyr/arch/xtensa/arch.h | 10 + include/zephyr/arch/xtensa/syscall.h | 238 +++++++ include/zephyr/arch/xtensa/thread.h | 9 + include/zephyr/arch/xtensa/xtensa_mmu.h | 34 + 19 files changed, 1646 insertions(+), 68 deletions(-) create mode 100644 arch/xtensa/core/syscall_helper.c create mode 100644 arch/xtensa/core/userspace.S create mode 100644 include/zephyr/arch/xtensa/syscall.h diff --git a/arch/Kconfig b/arch/Kconfig index 5e3b96f414d..cc9925e7774 100644 --- a/arch/Kconfig +++ b/arch/Kconfig @@ -125,6 +125,7 @@ config XTENSA select IRQ_OFFLOAD_NESTED if IRQ_OFFLOAD select ARCH_HAS_CODE_DATA_RELOCATION select ARCH_HAS_TIMING_FUNCTIONS + select ARCH_MEM_DOMAIN_DATA if USERSPACE imply ATOMIC_OPERATIONS_ARCH help Xtensa architecture diff --git a/arch/xtensa/Kconfig b/arch/xtensa/Kconfig index a1517f17ed0..c875aa30972 100644 --- a/arch/xtensa/Kconfig +++ b/arch/xtensa/Kconfig @@ -113,6 +113,7 @@ config XTENSA_MMU bool "Xtensa MMU Support" default n select MMU + select ARCH_MEM_DOMAIN_SYNCHRONOUS_API if USERSPACE select XTENSA_SMALL_VECTOR_TABLE_ENTRY select KERNEL_VM_USE_CUSTOM_MEM_RANGE_CHECK if XTENSA_RPO_CACHE help @@ -144,8 +145,18 @@ if XTENSA_MMU The bit shift number for the virtual address for Xtensa page table (PTEVADDR). + config XTENSA_MMU_NUM_L1_TABLES + int "Number of L1 page tables" + default 1 if !USERSPACE + default 4 + help + This option specifies the maximum number of traslation tables. + Translation tables are directly related to the number of + memory domains in the target, considering the kernel itself requires one. + config XTENSA_MMU_NUM_L2_TABLES int "Number of L2 page tables" + default 20 if USERSPACE default 10 help Each table can address up to 4MB memory address. @@ -159,6 +170,15 @@ if XTENSA_MMU endif # XTENSA_MMU +config XTENSA_SYSCALL_USE_HELPER + bool "Use userspace syscall helper" + default y if "$(ZEPHYR_TOOLCHAIN_VARIANT)" = "xcc-clang" + depends on USERSPACE + help + Use syscall helpers for passing more then 3 arguments. + This is a workaround for toolchains where they have + issue modeling register usage. + endif # CPU_HAS_MMU endmenu diff --git a/arch/xtensa/core/CMakeLists.txt b/arch/xtensa/core/CMakeLists.txt index c6fffd4f5e1..8a23b65b9a9 100644 --- a/arch/xtensa/core/CMakeLists.txt +++ b/arch/xtensa/core/CMakeLists.txt @@ -22,6 +22,8 @@ zephyr_library_sources_ifdef(CONFIG_DEBUG_COREDUMP coredump.c) zephyr_library_sources_ifdef(CONFIG_TIMING_FUNCTIONS timing.c) zephyr_library_sources_ifdef(CONFIG_GDBSTUB gdbstub.c) zephyr_library_sources_ifdef(CONFIG_XTENSA_MMU xtensa_mmu.c) +zephyr_library_sources_ifdef(CONFIG_USERSPACE userspace.S) +zephyr_library_sources_ifdef(CONFIG_XTENSA_SYSCALL_USE_HELPER syscall_helper.c) zephyr_library_sources_ifdef( CONFIG_KERNEL_VM_USE_CUSTOM_MEM_RANGE_CHECK diff --git a/arch/xtensa/core/fatal.c b/arch/xtensa/core/fatal.c index e693937f99b..3117ebc4a56 100644 --- a/arch/xtensa/core/fatal.c +++ b/arch/xtensa/core/fatal.c @@ -15,6 +15,7 @@ #endif #endif #include +#include #include LOG_MODULE_DECLARE(os, CONFIG_KERNEL_LOG_LEVEL); @@ -120,6 +121,14 @@ void z_xtensa_fatal_error(unsigned int reason, const z_arch_esf_t *esf) z_fatal_error(reason, esf); } +#ifdef CONFIG_USERSPACE +Z_EXC_DECLARE(z_xtensa_user_string_nlen); + +static const struct z_exc_handle exceptions[] = { + Z_EXC_HANDLE(z_xtensa_user_string_nlen) +}; +#endif /* CONFIG_USERSPACE */ + #ifdef XT_SIMULATOR void exit(int return_code) { diff --git a/arch/xtensa/core/include/xtensa_mmu_priv.h b/arch/xtensa/core/include/xtensa_mmu_priv.h index dcfb9deefc0..cf72c921383 100644 --- a/arch/xtensa/core/include/xtensa_mmu_priv.h +++ b/arch/xtensa/core/include/xtensa_mmu_priv.h @@ -18,18 +18,37 @@ #define Z_XTENSA_PTE_VPN_MASK 0xFFFFF000U #define Z_XTENSA_PTE_PPN_MASK 0xFFFFF000U #define Z_XTENSA_PTE_ATTR_MASK 0x0000000FU +#define Z_XTENSA_PTE_ATTR_CACHED_MASK 0x0000000CU #define Z_XTENSA_L1_MASK 0x3FF00000U #define Z_XTENSA_L2_MASK 0x3FFFFFU #define Z_XTENSA_PPN_SHIFT 12U #define Z_XTENSA_PTE_RING_MASK 0x00000030U +#define Z_XTENSA_PTE_RING_SHIFT 4U #define Z_XTENSA_PTE(paddr, ring, attr) \ (((paddr) & Z_XTENSA_PTE_PPN_MASK) | \ - (((ring) << 4) & Z_XTENSA_PTE_RING_MASK) | \ + (((ring) << Z_XTENSA_PTE_RING_SHIFT) & Z_XTENSA_PTE_RING_MASK) | \ ((attr) & Z_XTENSA_PTE_ATTR_MASK)) +#define Z_XTENSA_PTE_ATTR_GET(pte) \ + (pte) & Z_XTENSA_PTE_ATTR_MASK + +#define Z_XTENSA_PTE_ATTR_SET(pte, attr) \ + (((pte) & ~Z_XTENSA_PTE_ATTR_MASK) | (attr)) + +#define Z_XTENSA_PTE_RING_SET(pte, ring) \ + (((pte) & ~Z_XTENSA_PTE_RING_MASK) | \ + ((ring) << Z_XTENSA_PTE_RING_SHIFT)) + +#define Z_XTENSA_PTE_RING_GET(pte) \ + (((pte) & ~Z_XTENSA_PTE_RING_MASK) >> Z_XTENSA_PTE_RING_SHIFT) + +#define Z_XTENSA_PTE_ASID_GET(pte, rasid) \ + (((rasid) >> ((((pte) & Z_XTENSA_PTE_RING_MASK) \ + >> Z_XTENSA_PTE_RING_SHIFT) * 8)) & 0xFF) + #define Z_XTENSA_TLB_ENTRY(vaddr, way) \ (((vaddr) & Z_XTENSA_PTE_PPN_MASK) | (way)) @@ -38,11 +57,38 @@ (((vaddr) >> Z_XTENSA_PPN_SHIFT) & 0x03U)) #define Z_XTENSA_L2_POS(vaddr) \ - (((vaddr) & Z_XTENSA_L2_MASK) >> Z_XTENSA_PPN_SHIFT) + (((vaddr) & Z_XTENSA_L2_MASK) >> 12U) + +#define Z_XTENSA_L1_POS(vaddr) \ + ((vaddr) >> 22U) + +/* PTE attributes for entries in the L1 page table. Should never be + * writable, may be cached in non-SMP contexts only + */ +#if CONFIG_MP_MAX_NUM_CPUS == 1 +#define Z_XTENSA_PAGE_TABLE_ATTR Z_XTENSA_MMU_CACHED_WB +#else +#define Z_XTENSA_PAGE_TABLE_ATTR 0 +#endif + +/* This ASID is shared between all domains and kernel. */ +#define Z_XTENSA_MMU_SHARED_ASID 255 + +/* Fixed data TLB way to map the page table */ +#define Z_XTENSA_MMU_PTE_WAY 7 + +/* Fixed data TLB way to map the vecbase */ +#define Z_XTENSA_MMU_VECBASE_WAY 8 /* Kernel specific ASID. Ring field in the PTE */ #define Z_XTENSA_KERNEL_RING 0 +/* User specific ASID. Ring field in the PTE */ +#define Z_XTENSA_USER_RING 2 + +/* Ring value for MMU_SHARED_ASID */ +#define Z_XTENSA_SHARED_RING 3 + /* Number of data TLB ways [0-9] */ #define Z_XTENSA_DTLB_WAYS 10 @@ -96,6 +142,14 @@ #define Z_XTENSA_PAGE_TABLE_VADDR \ Z_XTENSA_PTE_ENTRY_VADDR(Z_XTENSA_PTEVADDR) +/* + * Get asid for a given ring from rasid register. + * rasid contains four asid, one per ring. + */ + +#define Z_XTENSA_RASID_ASID_GET(rasid, ring) \ + (((rasid) >> ((ring) * 8)) & 0xff) + static ALWAYS_INLINE void xtensa_rasid_set(uint32_t rasid) { __asm__ volatile("wsr %0, rasid\n\t" @@ -110,6 +164,16 @@ static ALWAYS_INLINE uint32_t xtensa_rasid_get(void) return rasid; } +static ALWAYS_INLINE void xtensa_rasid_asid_set(uint8_t asid, uint8_t pos) +{ + uint32_t rasid = xtensa_rasid_get(); + + rasid = (rasid & ~(0xff << (pos * 8))) | ((uint32_t)asid << (pos * 8)); + + xtensa_rasid_set(rasid); +} + + static ALWAYS_INLINE void xtensa_itlb_entry_invalidate(uint32_t entry) { __asm__ volatile("iitlb %0\n\t" @@ -201,6 +265,21 @@ static ALWAYS_INLINE void xtensa_ptevaddr_set(void *ptables) __asm__ volatile("wsr.ptevaddr %0" : : "a"((uint32_t)ptables)); } +/** + * @brief Get the current page tables. + * + * The page tables is obtained by reading ptevaddr address. + * + * @return ptables The page tables address (virtual address) + */ +static ALWAYS_INLINE void *xtensa_ptevaddr_get(void) +{ + uint32_t ptables; + + __asm__ volatile("rsr.ptevaddr %0" : "=a" (ptables)); + + return (void *)ptables; +} /* * The following functions are helpful when debugging. */ diff --git a/arch/xtensa/core/offsets/offsets.c b/arch/xtensa/core/offsets/offsets.c index 860a12eb408..8d4022fd81e 100644 --- a/arch/xtensa/core/offsets/offsets.c +++ b/arch/xtensa/core/offsets/offsets.c @@ -5,6 +5,7 @@ #include #include +#include #include @@ -60,4 +61,10 @@ GEN_OFFSET_SYM(_xtensa_irq_bsa_t, fpu14); GEN_OFFSET_SYM(_xtensa_irq_bsa_t, fpu15); #endif +#ifdef CONFIG_USERSPACE +GEN_OFFSET_SYM(_thread_arch_t, psp); +GEN_OFFSET_SYM(_thread_arch_t, ptables); +#endif + + GEN_ABS_SYM_END diff --git a/arch/xtensa/core/syscall_helper.c b/arch/xtensa/core/syscall_helper.c new file mode 100644 index 00000000000..fbbdf104191 --- /dev/null +++ b/arch/xtensa/core/syscall_helper.c @@ -0,0 +1,124 @@ +/* + * Copyright (c) 2022 Intel Corporation. + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include + +uintptr_t arch_syscall_invoke6_helper(uintptr_t arg1, uintptr_t arg2, + uintptr_t arg3, uintptr_t arg4, + uintptr_t arg5, uintptr_t arg6, + uintptr_t call_id) +{ + register uintptr_t a2 __asm__("%a2") = call_id; + register uintptr_t a6 __asm__("%a6") = arg1; + register uintptr_t a3 __asm__("%a3") = arg2; + register uintptr_t a4 __asm__("%a4") = arg3; + register uintptr_t a5 __asm__("%a5") = arg4; + register uintptr_t a8 __asm__("%a8") = arg5; + register uintptr_t a9 __asm__("%a9") = arg6; + + __asm__ volatile("syscall\n\t" + : "=r" (a2) + : "r" (a2), "r" (a6), "r" (a3), "r" (a4), + "r" (a5), "r" (a8), "r" (a9) + : "memory"); + + return a2; +} + +uintptr_t arch_syscall_invoke5_helper(uintptr_t arg1, uintptr_t arg2, + uintptr_t arg3, uintptr_t arg4, + uintptr_t arg5, uintptr_t call_id) +{ + register uintptr_t a2 __asm__("%a2") = call_id; + register uintptr_t a6 __asm__("%a6") = arg1; + register uintptr_t a3 __asm__("%a3") = arg2; + register uintptr_t a4 __asm__("%a4") = arg3; + register uintptr_t a5 __asm__("%a5") = arg4; + register uintptr_t a8 __asm__("%a8") = arg5; + + __asm__ volatile("syscall\n\t" + : "=r" (a2) + : "r" (a2), "r" (a6), "r" (a3), "r" (a4), + "r" (a5), "r" (a8) + : "memory"); + + return a2; +} + +uintptr_t arch_syscall_invoke4_helper(uintptr_t arg1, uintptr_t arg2, + uintptr_t arg3, uintptr_t arg4, + uintptr_t call_id) +{ + register uintptr_t a2 __asm__("%a2") = call_id; + register uintptr_t a6 __asm__("%a6") = arg1; + register uintptr_t a3 __asm__("%a3") = arg2; + register uintptr_t a4 __asm__("%a4") = arg3; + register uintptr_t a5 __asm__("%a5") = arg4; + + __asm__ volatile("syscall\n\t" + : "=r" (a2) + : "r" (a2), "r" (a6), "r" (a3), "r" (a4), + "r" (a5) + : "memory"); + + return a2; +} + +uintptr_t arch_syscall_invoke3_helper(uintptr_t arg1, uintptr_t arg2, + uintptr_t arg3, uintptr_t call_id) +{ + register uintptr_t a2 __asm__("%a2") = call_id; + register uintptr_t a6 __asm__("%a6") = arg1; + register uintptr_t a3 __asm__("%a3") = arg2; + register uintptr_t a4 __asm__("%a4") = arg3; + + __asm__ volatile("syscall\n\t" + : "=r" (a2) + : "r" (a2), "r" (a6), "r" (a3), "r" (a4) + : "memory"); + + return a2; +} + +uintptr_t arch_syscall_invoke2_helper(uintptr_t arg1, uintptr_t arg2, + uintptr_t call_id) +{ + register uintptr_t a2 __asm__("%a2") = call_id; + register uintptr_t a6 __asm__("%a6") = arg1; + register uintptr_t a3 __asm__("%a3") = arg2; + + __asm__ volatile("syscall\n\t" + : "=r" (a2) + : "r" (a2), "r" (a6), "r" (a3) + : "memory"); + + return a2; +} + +uintptr_t arch_syscall_invoke1_helper(uintptr_t arg1, uintptr_t call_id) +{ + register uintptr_t a2 __asm__("%a2") = call_id; + register uintptr_t a6 __asm__("%a6") = arg1; + + __asm__ volatile("syscall\n\t" + : "=r" (a2) + : "r" (a2), "r" (a6) + : "memory"); + + return a2; +} + +uintptr_t arch_syscall_invoke0_helper(uintptr_t call_id) +{ + register uintptr_t a2 __asm__("%a2") = call_id; + + __asm__ volatile("syscall\n\t" + : "=r" (a2) + : "r" (a2) + : "memory"); + + return a2; +} diff --git a/arch/xtensa/core/userspace.S b/arch/xtensa/core/userspace.S new file mode 100644 index 00000000000..b649014fd52 --- /dev/null +++ b/arch/xtensa/core/userspace.S @@ -0,0 +1,302 @@ +/* + * Copyright (c) 2022, Intel Corporation + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include +#include +#include +#include +#include + +/** + * syscall number arg1, arg2, arg3, arg4, arg5, arg6 + * -------------- ---------------------------------- + * a2 a6, a3, a4, a5, a8, a9 + * + **/ +.pushsection .text.z_xtensa_do_syscall, "ax" +.global z_xtensa_do_syscall +.align 4 +z_xtensa_do_syscall: + rsr a0, ZSR_CPU + l32i a0, a0, ___cpu_t_current_OFFSET + l32i a0, a0, _thread_offset_to_psp + + addi a0, a0, -___xtensa_irq_bsa_t_SIZEOF + + s32i a1, a0, ___xtensa_irq_bsa_t_scratch_OFFSET + s32i a2, a0, ___xtensa_irq_bsa_t_a2_OFFSET + s32i a3, a0, ___xtensa_irq_bsa_t_a3_OFFSET + rsr a2, ZSR_A0SAVE + s32i a2, a0, ___xtensa_irq_bsa_t_a0_OFFSET + rsr.ps a2 + movi a3, ~PS_OWB_MASK + and a2, a2, a3 + s32i a2, a0, ___xtensa_irq_bsa_t_ps_OFFSET + rsr.epc1 a2 + s32i a2, a0, ___xtensa_irq_bsa_t_pc_OFFSET + + movi a2, PS_WOE|PS_INTLEVEL(XCHAL_NMILEVEL) + rsr.ps a3 + or a3, a3, a2 + movi a2, ~(PS_EXCM | PS_RING_MASK) + and a3, a3, a2 + wsr.ps a3 + rsync + l32i a2, a0, ___xtensa_irq_bsa_t_a2_OFFSET + l32i a3, a0, ___xtensa_irq_bsa_t_a3_OFFSET + SPILL_ALL_WINDOWS + + rsr a0, ZSR_CPU + l32i a0, a0, ___cpu_t_current_OFFSET + l32i a0, a0, _thread_offset_to_psp + addi a0, a0, -___xtensa_irq_bsa_t_SIZEOF + + mov a1, a0 + + l32i a3, a1, ___xtensa_irq_bsa_t_pc_OFFSET +#if XCHAL_HAVE_LOOPS + /* If the syscall instruction was the last instruction in the body of + * a zero-overhead loop, and the loop will execute again, decrement + * the loop count and resume execution at the head of the loop. + */ + rsr.lend a2 + addi a3, a3, 3 + bne a2, a3, end_loop + rsr.lcount a2 + beqz a2, end_loop + addi a2, a2, -1 + wsr.lcount a2 + rsr.lbeg a3 +end_loop: +#else + /* EPC1 (and now a3) contains the address that invoked syscall. + * We need to increment it to execute the next instruction when + * we return. The instruction size is 3 bytes, so lets just add it. + */ + addi a3, a3, 3 +#endif + s32i a3, a1, ___xtensa_irq_bsa_t_pc_OFFSET + ODD_REG_SAVE + + call0 xtensa_save_high_regs + + l32i a2, a1, 0 + l32i a2, a2, ___xtensa_irq_bsa_t_a2_OFFSET + movi a0, K_SYSCALL_LIMIT + bgeu a2, a0, _bad_syscall + +_id_ok: + /* Find the function handler for the given syscall id. */ + movi a3, _k_syscall_table + slli a2, a2, 2 + add a2, a2, a3 + l32i a2, a2, 0 + + /* Clear up the threadptr because it is used + * to check if a thread is running on user mode. Since + * we are in a interruption we don't want the system + * thinking it is possibly running in user mode. + */ + movi a0, 0 + wur.THREADPTR a0 + + /* Set syscall parameters. We have an initial call4 to set up the + * the stack and then a new call4 for the syscall function itself. + * So parameters should be put as if it was a call8. + */ + mov a10, a8 + mov a11, a9 + mov a8, a4 + mov a9, a5 + l32i a3, a1, 0 + l32i a7, a3, ___xtensa_irq_bsa_t_a3_OFFSET + + + /* Since we are unmasking EXCM, we need to set RING bits to kernel + * mode, otherwise we won't be able to run the exception handler in C. + */ + movi a0, PS_WOE|PS_CALLINC(0)|PS_UM|PS_INTLEVEL(0) + wsr.ps a0 + rsync + + call4 _syscall_call0 + + /* copy return value. Lets put it in the top of stack + * because registers will be clobbered in + * xtensa_restore_high_regs + */ + l32i a3, a1, 0 + s32i a6, a3, ___xtensa_irq_bsa_t_a2_OFFSET + + j _syscall_returned + +.align 4 +_syscall_call0: + /* We want an ENTRY to set a bit in windowstart */ + jx a2 + + +_syscall_returned: + call0 xtensa_restore_high_regs + + l32i a3, a1, ___xtensa_irq_bsa_t_sar_OFFSET + wsr a3, SAR +#if XCHAL_HAVE_LOOPS + l32i a3, a1, ___xtensa_irq_bsa_t_lbeg_OFFSET + wsr a3, LBEG + l32i a3, a1, ___xtensa_irq_bsa_t_lend_OFFSET + wsr a3, LEND + l32i a3, a1, ___xtensa_irq_bsa_t_lcount_OFFSET + wsr a3, LCOUNT +#endif +#if XCHAL_HAVE_S32C1I + l32i a3, a1, ___xtensa_irq_bsa_t_scompare1_OFFSET + wsr a3, SCOMPARE1 +#endif + + rsr a3, ZSR_CPU + l32i a3, a3, ___cpu_t_current_OFFSET + wur.THREADPTR a3 + + l32i a3, a1, ___xtensa_irq_bsa_t_ps_OFFSET + wsr.ps a3 + + l32i a3, a1, ___xtensa_irq_bsa_t_pc_OFFSET + wsr.epc1 a3 + + l32i a0, a1, ___xtensa_irq_bsa_t_a0_OFFSET + l32i a2, a1, ___xtensa_irq_bsa_t_a2_OFFSET + l32i a3, a1, ___xtensa_irq_bsa_t_a3_OFFSET + + l32i a1, a1, ___xtensa_irq_bsa_t_scratch_OFFSET + rsync + + rfe + +_bad_syscall: + movi a2, K_SYSCALL_BAD + j _id_ok + +.popsection + +/* FUNC_NORETURN void z_xtensa_userspace_enter(k_thread_entry_t user_entry, + * void *p1, void *p2, void *p3, + * uint32_t stack_end, + * uint32_t stack_start) + * + * A one-way trip to userspace. + */ +.global z_xtensa_userspace_enter +.type z_xtensa_userspace_enter, @function +.align 4 +z_xtensa_userspace_enter: + /* Call entry to set a bit in the windowstart and + * do the rotation, but we are going to set our own + * stack. + */ + entry a1, 16 + + /* We have to switch to kernel stack before spill kernel data and + * erase user stack to avoid leak from previous context. + */ + mov a1, a7 /* stack start (low address) */ + addi a1, a1, -16 + + SPILL_ALL_WINDOWS + + rsr a0, ZSR_CPU + l32i a0, a0, ___cpu_t_current_OFFSET + + addi a1, a1, -28 + s32i a0, a1, 24 + s32i a2, a1, 20 + s32i a3, a1, 16 + s32i a4, a1, 12 + s32i a5, a1, 8 + s32i a6, a1, 4 + s32i a7, a1, 0 + + l32i a6, a1, 24 + call4 xtensa_user_stack_perms + + l32i a6, a1, 24 + call4 z_xtensa_swap_update_page_tables + + /* Set threadptr with the thread address, we are going to user mode. */ + l32i a0, a1, 24 + wur.THREADPTR a0 + + /* Set now z_thread_entry parameters, we are simulating a call4 + * call, so parameters start at a6, a7, ... + */ + l32i a6, a1, 20 + l32i a7, a1, 16 + l32i a8, a1, 12 + l32i a9, a1, 8 + + /* stash user stack */ + l32i a0, a1, 4 + + addi a1, a1, 28 + + /* Go back to user stack */ + mov a1, a0 + + movi a0, z_thread_entry + wsr.epc2 a0 + + /* Configuring PS register. + * We have to set callinc as well, since the called + * function will do "entry" + */ + movi a0, PS_WOE|PS_CALLINC(1)|PS_UM|PS_RING(2) + wsr a0, EPS2 + + movi a0, 0 + + rfi 2 + +/* + * size_t arch_user_string_nlen(const char *s, size_t maxsize, int *err_arg) + */ +.global arch_user_string_nlen +.type arch_user_string_nlen, @function +.align 4 +arch_user_string_nlen: + entry a1, 32 + + /* error value, set to -1. */ + movi a5, -1 + s32i a5, a4, 0 + + /* length count */ + xor a5, a5, a5 + + /* This code might page fault */ +strlen_loop: +.global z_xtensa_user_string_nlen_fault_start +z_xtensa_user_string_nlen_fault_start: + l8ui a6, a2, 0 /* Current char */ + +.global z_xtensa_user_string_nlen_fault_end +z_xtensa_user_string_nlen_fault_end: + beqz a6, strlen_done + addi a5, a5, 1 + addi a2, a2, 1 + beq a5, a3, strlen_done + j strlen_loop + +strlen_done: + /* Set return value */ + mov a2, a5 + + /* Set error value to 0 since we succeeded */ + movi a5, 0x0 + s32i a5, a4, 0 + +.global z_xtensa_user_string_nlen_fixup +z_xtensa_user_string_nlen_fixup: + retw diff --git a/arch/xtensa/core/xtensa-asm2-util.S b/arch/xtensa/core/xtensa-asm2-util.S index bc526ae0165..c108a09dee4 100644 --- a/arch/xtensa/core/xtensa-asm2-util.S +++ b/arch/xtensa/core/xtensa-asm2-util.S @@ -174,7 +174,8 @@ _restore_context: l32i a0, a1, ___xtensa_irq_bsa_t_scompare1_OFFSET wsr a0, SCOMPARE1 #endif -#if XCHAL_HAVE_THREADPTR && defined(CONFIG_THREAD_LOCAL_STORAGE) +#if XCHAL_HAVE_THREADPTR && \ + (defined(CONFIG_USERSPACE) || defined(CONFIG_THREAD_LOCAL_STORAGE)) l32i a0, a1, ___xtensa_irq_bsa_t_threadptr_OFFSET wur a0, THREADPTR #endif @@ -258,6 +259,16 @@ noflush: l32i a3, a2, ___xtensa_irq_bsa_t_a3_OFFSET s32i a1, a3, 0 +#ifdef CONFIG_USERSPACE + /* Switch page tables */ + rsr a6, ZSR_CPU + l32i a6, a6, ___cpu_t_current_OFFSET + call4 z_xtensa_swap_update_page_tables + + l32i a2, a3, 0 + l32i a2, a2, 0 +#endif + /* Switch stack pointer and restore. The jump to * _restore_context does not return as such, but we arrange * for the restored "next" address to be immediately after for @@ -347,6 +358,9 @@ _Level1RealVector: rsr.exccause a0 #ifdef CONFIG_XTENSA_MMU beqi a0, EXCCAUSE_ITLB_MISS, _handle_tlb_miss_user +#ifdef CONFIG_USERSPACE + beqi a0, EXCCAUSE_SYSCALL, _syscall +#endif /* CONFIG_USERSPACE */ addi a0, a0, -EXCCAUSE_DTLB_MISS beqz a0, _handle_tlb_miss_user rsr.exccause a0 @@ -376,6 +390,11 @@ _handle_tlb_miss_user: l32i a0, a0, 0 rsr a0, ZSR_A0SAVE rfe +#ifdef CONFIG_USERSPACE +_syscall: + rsr a0, ZSR_A0SAVE + j z_xtensa_do_syscall +#endif /* CONFIG_USERSPACE */ #endif /* CONFIG_XTENSA_MMU */ .popsection diff --git a/arch/xtensa/core/xtensa-asm2.c b/arch/xtensa/core/xtensa-asm2.c index c2371ac8f55..1e8c92759e4 100644 --- a/arch/xtensa/core/xtensa-asm2.c +++ b/arch/xtensa/core/xtensa-asm2.c @@ -26,6 +26,13 @@ void *xtensa_init_stack(struct k_thread *thread, int *stack_top, { void *ret; _xtensa_irq_stack_frame_a11_t *frame; +#ifdef CONFIG_USERSPACE + struct z_xtensa_thread_stack_header *header = + (struct z_xtensa_thread_stack_header *)thread->stack_obj; + + thread->arch.psp = header->privilege_stack + + sizeof(header->privilege_stack); +#endif /* Not-a-cpu ID Ensures that the first time this is run, the * stack will be invalidated. That covers the edge case of @@ -48,11 +55,23 @@ void *xtensa_init_stack(struct k_thread *thread, int *stack_top, (void)memset(frame, 0, bsasz); - frame->bsa.pc = (uintptr_t)z_thread_entry; frame->bsa.ps = PS_WOE | PS_UM | PS_CALLINC(1); +#ifdef CONFIG_USERSPACE + if ((thread->base.user_options & K_USER) == K_USER) { + frame->bsa.pc = (uintptr_t)arch_user_mode_enter; + } else { + frame->bsa.pc = (uintptr_t)z_thread_entry; + } +#else + frame->bsa.pc = (uintptr_t)z_thread_entry; +#endif -#if XCHAL_HAVE_THREADPTR && defined(CONFIG_THREAD_LOCAL_STORAGE) +#if XCHAL_HAVE_THREADPTR +#ifdef CONFIG_THREAD_LOCAL_STORAGE frame->bsa.threadptr = thread->tls; +#elif CONFIG_USERSPACE + frame->bsa.threadptr = (uintptr_t)((thread->base.user_options & K_USER) ? thread : NULL); +#endif #endif /* Arguments to z_thread_entry(). Remember these start at A6, @@ -471,3 +490,24 @@ void arch_spin_relax(void) #undef NOP1 } #endif /* CONFIG_XTENSA_MORE_SPIN_RELAX_NOPS */ + +#ifdef CONFIG_USERSPACE +FUNC_NORETURN void arch_user_mode_enter(k_thread_entry_t user_entry, + void *p1, void *p2, void *p3) +{ + struct k_thread *current = _current; + size_t stack_end; + + /* Transition will reset stack pointer to initial, discarding + * any old context since this is a one-way operation + */ + stack_end = Z_STACK_PTR_ALIGN(current->stack_info.start + + current->stack_info.size - + current->stack_info.delta); + + z_xtensa_userspace_enter(user_entry, p1, p2, p3, + stack_end, current->stack_info.start); + + CODE_UNREACHABLE; +} +#endif /* CONFIG_USERSPACE */ diff --git a/arch/xtensa/core/xtensa_mmu.c b/arch/xtensa/core/xtensa_mmu.c index 18ce5f22f63..915a26357eb 100644 --- a/arch/xtensa/core/xtensa_mmu.c +++ b/arch/xtensa/core/xtensa_mmu.c @@ -4,6 +4,7 @@ */ #include #include +#include #include #include #include @@ -15,22 +16,24 @@ #include #include -/* Fixed data TLB way to map the page table */ -#define MMU_PTE_WAY 7 - -/* Fixed data TLB way to map VECBASE */ -#define MMU_VECBASE_WAY 8 - /* Level 1 contains page table entries * necessary to map the page table itself. */ #define XTENSA_L1_PAGE_TABLE_ENTRIES 1024U +/* Size of level 1 page table. + */ +#define XTENSA_L1_PAGE_TABLE_SIZE (XTENSA_L1_PAGE_TABLE_ENTRIES * sizeof(uint32_t)) + /* Level 2 contains page table entries * necessary to map the page table itself. */ #define XTENSA_L2_PAGE_TABLE_ENTRIES 1024U +/* Size of level 2 page table. + */ +#define XTENSA_L2_PAGE_TABLE_SIZE (XTENSA_L2_PAGE_TABLE_ENTRIES * sizeof(uint32_t)) + LOG_MODULE_DECLARE(os, CONFIG_KERNEL_LOG_LEVEL); BUILD_ASSERT(CONFIG_MMU_PAGE_SIZE == 0x1000, @@ -40,8 +43,18 @@ BUILD_ASSERT(CONFIG_MMU_PAGE_SIZE == 0x1000, * Level 1 page table has to be 4Kb to fit into one of the wired entries. * All entries are initialized as INVALID, so an attempt to read an unmapped * area will cause a double exception. + * + * Each memory domain contains its own l1 page table. The kernel l1 page table is + * located at the index 0. */ -uint32_t l1_page_table[XTENSA_L1_PAGE_TABLE_ENTRIES] __aligned(KB(4)); +static uint32_t l1_page_table[CONFIG_XTENSA_MMU_NUM_L1_TABLES][XTENSA_L1_PAGE_TABLE_ENTRIES] + __aligned(KB(4)); + + +/* + * That is an alias for the page tables set used by the kernel. + */ +uint32_t *z_xtensa_kernel_ptables = (uint32_t *)l1_page_table[0]; /* * Each table in the level 2 maps a 4Mb memory range. It consists of 1024 entries each one @@ -50,12 +63,41 @@ uint32_t l1_page_table[XTENSA_L1_PAGE_TABLE_ENTRIES] __aligned(KB(4)); static uint32_t l2_page_tables[CONFIG_XTENSA_MMU_NUM_L2_TABLES][XTENSA_L2_PAGE_TABLE_ENTRIES] __aligned(KB(4)); +/* + * This additional variable tracks which l1 tables are in use. This is kept separated from + * the tables to keep alignment easier. + * + * @note: The first bit is set because it is used for the kernel page tables. + */ +static ATOMIC_DEFINE(l1_page_table_track, CONFIG_XTENSA_MMU_NUM_L1_TABLES); + /* * This additional variable tracks which l2 tables are in use. This is kept separated from * the tables to keep alignment easier. */ static ATOMIC_DEFINE(l2_page_tables_track, CONFIG_XTENSA_MMU_NUM_L2_TABLES); +/* + * Protects xtensa_domain_list and serializes access to page tables. + */ +static struct k_spinlock xtensa_mmu_lock; + +#ifdef CONFIG_USERSPACE + +/* + * Each domain has its own ASID. ASID can go through 1 (kernel) to 255. + * When a TLB entry matches, the hw will check the ASID in the entry and finds + * the correspondent position in the RASID register. This position will then be + * compared with the current ring (CRING) to check the permission. + */ +static uint8_t asid_count = 3; + +/* + * List with all active and initialized memory domains. + */ +static sys_slist_t xtensa_domain_list; +#endif /* CONFIG_USERSPACE */ + extern char _heap_end[]; extern char _heap_start[]; extern char __data_start[]; @@ -100,18 +142,61 @@ static const struct xtensa_mmu_range mmu_zephyr_ranges[] = { { .start = (uint32_t)__text_region_start, .end = (uint32_t)__text_region_end, - .attrs = Z_XTENSA_MMU_X | Z_XTENSA_MMU_CACHED_WB, + .attrs = Z_XTENSA_MMU_X | Z_XTENSA_MMU_CACHED_WB | Z_XTENSA_MMU_MAP_SHARED, .name = "text", }, /* Mark rodata segment cacheable, read only and non-executable */ { .start = (uint32_t)__rodata_region_start, .end = (uint32_t)__rodata_region_end, - .attrs = Z_XTENSA_MMU_CACHED_WB, + .attrs = Z_XTENSA_MMU_CACHED_WB | Z_XTENSA_MMU_MAP_SHARED, .name = "rodata", }, }; +static inline uint32_t *thread_page_tables_get(const struct k_thread *thread) +{ +#ifdef CONFIG_USERSPACE + if ((thread->base.user_options & K_USER) != 0U) { + return thread->arch.ptables; + } +#endif + + return z_xtensa_kernel_ptables; +} + +/** + * @brief Check if the page table entry is illegal. + * + * @param[in] Page table entry. + */ +static inline bool is_pte_illegal(uint32_t pte) +{ + uint32_t attr = pte & Z_XTENSA_PTE_ATTR_MASK; + + /* + * The ISA manual states only 12 and 14 are illegal values. + * 13 and 15 are not. So we need to be specific than simply + * testing if bits 2 and 3 are set. + */ + return (attr == 12) || (attr == 14); +} + +/* + * @brief Initialize all page table entries to be illegal. + * + * @param[in] Pointer to page table. + * @param[in] Number of page table entries in the page table. + */ +static void init_page_table(uint32_t *ptable, size_t num_entries) +{ + int i; + + for (i = 0; i < num_entries; i++) { + ptable[i] = Z_XTENSA_MMU_ILLEGAL; + } +} + static inline uint32_t *alloc_l2_table(void) { uint16_t idx; @@ -125,45 +210,86 @@ static inline uint32_t *alloc_l2_table(void) return NULL; } +/** + * @brief Switch page tables + * + * This switches the page tables to the incoming ones (@a ptables). + * Since data TLBs to L2 page tables are auto-filled, @a dtlb_inv + * can be used to invalidate these data TLBs. @a cache_inv can be + * set to true to invalidate cache to the page tables. + * + * @param[in] ptables Page tables to be switched to. + * @param[in] dtlb_inv True if to invalidate auto-fill data TLBs. + * @param[in] cache_inv True if to invalidate cache to page tables. + */ +static ALWAYS_INLINE void switch_page_tables(uint32_t *ptables, bool dtlb_inv, bool cache_inv) +{ + if (cache_inv) { + sys_cache_data_invd_range((void *)ptables, XTENSA_L1_PAGE_TABLE_SIZE); + sys_cache_data_invd_range((void *)l2_page_tables, sizeof(l2_page_tables)); + } + + /* Invalidate data TLB to L1 page table */ + xtensa_dtlb_vaddr_invalidate((void *)Z_XTENSA_PAGE_TABLE_VADDR); + + /* Now map the pagetable itself with KERNEL asid to avoid user thread + * from tampering with it. + */ + xtensa_dtlb_entry_write_sync( + Z_XTENSA_PTE((uint32_t)ptables, Z_XTENSA_KERNEL_RING, Z_XTENSA_PAGE_TABLE_ATTR), + Z_XTENSA_TLB_ENTRY(Z_XTENSA_PAGE_TABLE_VADDR, Z_XTENSA_MMU_PTE_WAY)); + + if (dtlb_inv) { + /* Since L2 page tables are auto-refilled, + * invalidate all of them to flush the old entries out. + */ + xtensa_tlb_autorefill_invalidate(); + } +} + static void map_memory_range(const uint32_t start, const uint32_t end, - const uint32_t attrs) + const uint32_t attrs, bool shared) { uint32_t page, *table; for (page = start; page < end; page += CONFIG_MMU_PAGE_SIZE) { - uint32_t pte = Z_XTENSA_PTE(page, Z_XTENSA_KERNEL_RING, attrs); + uint32_t pte = Z_XTENSA_PTE(page, + shared ? Z_XTENSA_SHARED_RING : Z_XTENSA_KERNEL_RING, + attrs); uint32_t l2_pos = Z_XTENSA_L2_POS(page); - uint32_t l1_pos = page >> 22; + uint32_t l1_pos = Z_XTENSA_L1_POS(page); - if (l1_page_table[l1_pos] == Z_XTENSA_MMU_ILLEGAL) { + if (is_pte_illegal(z_xtensa_kernel_ptables[l1_pos])) { table = alloc_l2_table(); __ASSERT(table != NULL, "There is no l2 page table available to " "map 0x%08x\n", page); - l1_page_table[l1_pos] = + init_page_table(table, XTENSA_L2_PAGE_TABLE_ENTRIES); + + z_xtensa_kernel_ptables[l1_pos] = Z_XTENSA_PTE((uint32_t)table, Z_XTENSA_KERNEL_RING, - Z_XTENSA_MMU_CACHED_WT); + Z_XTENSA_PAGE_TABLE_ATTR); } - table = (uint32_t *)(l1_page_table[l1_pos] & Z_XTENSA_PTE_PPN_MASK); + table = (uint32_t *)(z_xtensa_kernel_ptables[l1_pos] & Z_XTENSA_PTE_PPN_MASK); table[l2_pos] = pte; } } static void map_memory(const uint32_t start, const uint32_t end, - const uint32_t attrs) + const uint32_t attrs, bool shared) { - map_memory_range(start, end, attrs); + map_memory_range(start, end, attrs, shared); #ifdef CONFIG_XTENSA_MMU_DOUBLE_MAP if (arch_xtensa_is_ptr_uncached((void *)start)) { map_memory_range(POINTER_TO_UINT(z_soc_cached_ptr((void *)start)), POINTER_TO_UINT(z_soc_cached_ptr((void *)end)), - attrs | Z_XTENSA_MMU_CACHED_WB); + attrs | Z_XTENSA_MMU_CACHED_WB, shared); } else if (arch_xtensa_is_ptr_cached((void *)start)) { map_memory_range(POINTER_TO_UINT(z_soc_uncached_ptr((void *)start)), - POINTER_TO_UINT(z_soc_uncached_ptr((void *)end)), attrs); + POINTER_TO_UINT(z_soc_uncached_ptr((void *)end)), attrs, shared); } #endif } @@ -171,16 +297,19 @@ static void map_memory(const uint32_t start, const uint32_t end, static void xtensa_init_page_tables(void) { volatile uint8_t entry; - uint32_t page; - for (page = 0; page < XTENSA_L1_PAGE_TABLE_ENTRIES; page++) { - l1_page_table[page] = Z_XTENSA_MMU_ILLEGAL; - } + init_page_table(z_xtensa_kernel_ptables, XTENSA_L1_PAGE_TABLE_ENTRIES); + atomic_set_bit(l1_page_table_track, 0); for (entry = 0; entry < ARRAY_SIZE(mmu_zephyr_ranges); entry++) { const struct xtensa_mmu_range *range = &mmu_zephyr_ranges[entry]; + bool shared; + uint32_t attrs; - map_memory(range->start, range->end, range->attrs); + shared = !!(range->attrs & Z_XTENSA_MMU_MAP_SHARED); + attrs = range->attrs & ~Z_XTENSA_MMU_MAP_SHARED; + + map_memory(range->start, range->end, attrs, shared); } /** @@ -198,8 +327,13 @@ static void xtensa_init_page_tables(void) #endif for (entry = 0; entry < xtensa_soc_mmu_ranges_num; entry++) { const struct xtensa_mmu_range *range = &xtensa_soc_mmu_ranges[entry]; + bool shared; + uint32_t attrs; + + shared = !!(range->attrs & Z_XTENSA_MMU_MAP_SHARED); + attrs = range->attrs & ~Z_XTENSA_MMU_MAP_SHARED; - map_memory(range->start, range->end, range->attrs); + map_memory(range->start, range->end, attrs, shared); } #if defined(__GNUC__) #pragma GCC diagnostic pop @@ -231,6 +365,9 @@ void z_xtensa_mmu_init(void) /* Set the page table location in the virtual address */ xtensa_ptevaddr_set((void *)Z_XTENSA_PTEVADDR); + /* Set rasid */ + xtensa_rasid_asid_set(Z_XTENSA_MMU_SHARED_ASID, Z_XTENSA_SHARED_RING); + /* Next step is to invalidate the tlb entry that contains the top level * page table. This way we don't cause a multi hit exception. */ @@ -243,9 +380,9 @@ void z_xtensa_mmu_init(void) * Lets use one of the wired entry, so we never have tlb miss for * the top level table. */ - xtensa_dtlb_entry_write(Z_XTENSA_PTE((uint32_t)l1_page_table, Z_XTENSA_KERNEL_RING, - Z_XTENSA_MMU_CACHED_WT), - Z_XTENSA_TLB_ENTRY(Z_XTENSA_PAGE_TABLE_VADDR, MMU_PTE_WAY)); + xtensa_dtlb_entry_write(Z_XTENSA_PTE((uint32_t)z_xtensa_kernel_ptables, + Z_XTENSA_KERNEL_RING, Z_XTENSA_PAGE_TABLE_ATTR), + Z_XTENSA_TLB_ENTRY(Z_XTENSA_PAGE_TABLE_VADDR, Z_XTENSA_MMU_PTE_WAY)); /* Before invalidate the text region in the TLB entry 6, we need to * map the exception vector into one of the wired entries to avoid @@ -297,7 +434,7 @@ void z_xtensa_mmu_init(void) xtensa_dtlb_entry_write( Z_XTENSA_PTE((uint32_t)vecbase, Z_XTENSA_KERNEL_RING, Z_XTENSA_MMU_CACHED_WB), - Z_XTENSA_TLB_ENTRY((uint32_t)vecbase, MMU_VECBASE_WAY)); + Z_XTENSA_TLB_ENTRY((uint32_t)vecbase, Z_XTENSA_MMU_VECBASE_WAY)); /* * Pre-load TLB for vecbase so exception handling won't result @@ -325,6 +462,12 @@ void z_xtensa_mmu_init(void) xtensa_dtlb_entry_invalidate_sync(Z_XTENSA_TLB_ENTRY(Z_XTENSA_PTEVADDR + MB(4), 3)); xtensa_itlb_entry_invalidate_sync(Z_XTENSA_TLB_ENTRY(Z_XTENSA_PTEVADDR + MB(4), 3)); + /* + * Clear out THREADPTR as we use it to indicate + * whether we are in user mode or not. + */ + XTENSA_WUR("THREADPTR", 0); + arch_xtensa_mmu_post_init(_current_cpu->id == 0); } @@ -351,32 +494,121 @@ __weak void arch_reserved_pages_update(void) } #endif /* CONFIG_ARCH_HAS_RESERVED_PAGE_FRAMES */ -static bool l2_page_table_map(void *vaddr, uintptr_t phys, uint32_t flags) +static bool l2_page_table_map(uint32_t *l1_table, void *vaddr, uintptr_t phys, + uint32_t flags, bool is_user) { uint32_t l1_pos = (uint32_t)vaddr >> 22; - uint32_t pte = Z_XTENSA_PTE(phys, Z_XTENSA_KERNEL_RING, flags); uint32_t l2_pos = Z_XTENSA_L2_POS((uint32_t)vaddr); uint32_t *table; - if (l1_page_table[l1_pos] == Z_XTENSA_MMU_ILLEGAL) { + sys_cache_data_invd_range((void *)&l1_table[l1_pos], sizeof(l1_table[0])); + + if (is_pte_illegal(l1_table[l1_pos])) { table = alloc_l2_table(); if (table == NULL) { return false; } - l1_page_table[l1_pos] = Z_XTENSA_PTE((uint32_t)table, Z_XTENSA_KERNEL_RING, - Z_XTENSA_MMU_CACHED_WT); + init_page_table(table, XTENSA_L2_PAGE_TABLE_ENTRIES); + + l1_table[l1_pos] = Z_XTENSA_PTE((uint32_t)table, Z_XTENSA_KERNEL_RING, + Z_XTENSA_PAGE_TABLE_ATTR); + + sys_cache_data_flush_range((void *)&l1_table[l1_pos], sizeof(l1_table[0])); + } + + table = (uint32_t *)(l1_table[l1_pos] & Z_XTENSA_PTE_PPN_MASK); + table[l2_pos] = Z_XTENSA_PTE(phys, is_user ? Z_XTENSA_USER_RING : Z_XTENSA_KERNEL_RING, + flags); + + sys_cache_data_flush_range((void *)&table[l2_pos], sizeof(table[0])); + + return true; +} + +static inline void __arch_mem_map(void *va, uintptr_t pa, uint32_t xtensa_flags, bool is_user) +{ + bool ret; + void *vaddr, *vaddr_uc; + uintptr_t paddr, paddr_uc; + uint32_t flags, flags_uc; + + if (IS_ENABLED(CONFIG_XTENSA_MMU_DOUBLE_MAP)) { + if (arch_xtensa_is_ptr_cached(va)) { + vaddr = va; + vaddr_uc = arch_xtensa_uncached_ptr(va); + } else { + vaddr = arch_xtensa_cached_ptr(va); + vaddr_uc = va; + } + + if (arch_xtensa_is_ptr_cached((void *)pa)) { + paddr = pa; + paddr_uc = (uintptr_t)arch_xtensa_uncached_ptr((void *)pa); + } else { + paddr = (uintptr_t)arch_xtensa_cached_ptr((void *)pa); + paddr_uc = pa; + } + + flags_uc = (xtensa_flags & ~Z_XTENSA_PTE_ATTR_CACHED_MASK); + flags = flags_uc | Z_XTENSA_MMU_CACHED_WB; + } else { + vaddr = va; + paddr = pa; + flags = xtensa_flags; + } + + ret = l2_page_table_map(z_xtensa_kernel_ptables, (void *)vaddr, paddr, + flags, is_user); + __ASSERT(ret, "Virtual address (%p) already mapped", va); + + if (IS_ENABLED(CONFIG_XTENSA_MMU_DOUBLE_MAP) && ret) { + ret = l2_page_table_map(z_xtensa_kernel_ptables, (void *)vaddr_uc, paddr_uc, + flags_uc, is_user); + __ASSERT(ret, "Virtual address (%p) already mapped", vaddr_uc); } - table = (uint32_t *)(l1_page_table[l1_pos] & Z_XTENSA_PTE_PPN_MASK); - table[l2_pos] = pte; +#ifndef CONFIG_USERSPACE + ARG_UNUSED(ret); +#else + if (ret) { + sys_snode_t *node; + struct arch_mem_domain *domain; + k_spinlock_key_t key; + + key = k_spin_lock(&z_mem_domain_lock); + SYS_SLIST_FOR_EACH_NODE(&xtensa_domain_list, node) { + domain = CONTAINER_OF(node, struct arch_mem_domain, node); + + ret = l2_page_table_map(domain->ptables, (void *)vaddr, paddr, + flags, is_user); + __ASSERT(ret, "Virtual address (%p) already mapped for domain %p", + vaddr, domain); + + if (IS_ENABLED(CONFIG_XTENSA_MMU_DOUBLE_MAP) && ret) { + ret = l2_page_table_map(domain->ptables, + (void *)vaddr_uc, paddr_uc, + flags_uc, is_user); + __ASSERT(ret, "Virtual address (%p) already mapped for domain %p", + vaddr_uc, domain); + } + } + k_spin_unlock(&z_mem_domain_lock, key); + } +#endif /* CONFIG_USERSPACE */ - if ((flags & Z_XTENSA_MMU_X) == Z_XTENSA_MMU_X) { + if ((xtensa_flags & Z_XTENSA_MMU_X) == Z_XTENSA_MMU_X) { xtensa_itlb_vaddr_invalidate(vaddr); } xtensa_dtlb_vaddr_invalidate(vaddr); - return true; + + if (IS_ENABLED(CONFIG_XTENSA_MMU_DOUBLE_MAP)) { + if (xtensa_flags & Z_XTENSA_MMU_X) { + xtensa_itlb_vaddr_invalidate(vaddr_uc); + } + xtensa_dtlb_vaddr_invalidate(vaddr_uc); + } } void arch_mem_map(void *virt, uintptr_t phys, size_t size, uint32_t flags) @@ -385,7 +617,8 @@ void arch_mem_map(void *virt, uintptr_t phys, size_t size, uint32_t flags) uint32_t pa = (uint32_t)phys; uint32_t rem_size = (uint32_t)size; uint32_t xtensa_flags = 0; - int key; + k_spinlock_key_t key; + bool is_user; if (size == 0) { LOG_ERR("Cannot map physical memory at 0x%08X: invalid " @@ -414,63 +647,130 @@ void arch_mem_map(void *virt, uintptr_t phys, size_t size, uint32_t flags) xtensa_flags |= Z_XTENSA_MMU_X; } - key = arch_irq_lock(); + is_user = (flags & K_MEM_PERM_USER) == K_MEM_PERM_USER; + + key = k_spin_lock(&xtensa_mmu_lock); while (rem_size > 0) { - bool ret = l2_page_table_map((void *)va, pa, xtensa_flags); + __arch_mem_map((void *)va, pa, xtensa_flags, is_user); - ARG_UNUSED(ret); - __ASSERT(ret, "Virtual address (%u) already mapped", (uint32_t)virt); rem_size -= (rem_size >= KB(4)) ? KB(4) : rem_size; va += KB(4); pa += KB(4); } - arch_irq_unlock(key); + k_spin_unlock(&xtensa_mmu_lock, key); } -static void l2_page_table_unmap(void *vaddr) +/** + * @return True if page is executable (thus need to invalidate ITLB), + * false if not. + */ +static bool l2_page_table_unmap(uint32_t *l1_table, void *vaddr) { uint32_t l1_pos = (uint32_t)vaddr >> 22; uint32_t l2_pos = Z_XTENSA_L2_POS((uint32_t)vaddr); - uint32_t *table; + uint32_t *l2_table; uint32_t table_pos; bool exec; - if (l1_page_table[l1_pos] == Z_XTENSA_MMU_ILLEGAL) { - return; + sys_cache_data_invd_range((void *)&l1_table[l1_pos], sizeof(l1_table[0])); + + if (is_pte_illegal(l1_table[l1_pos])) { + /* We shouldn't be unmapping an illegal entry. + * Return true so that we can invalidate ITLB too. + */ + return true; } - exec = l1_page_table[l1_pos] & Z_XTENSA_MMU_X; + exec = l1_table[l1_pos] & Z_XTENSA_MMU_X; + + l2_table = (uint32_t *)(l1_table[l1_pos] & Z_XTENSA_PTE_PPN_MASK); + + sys_cache_data_invd_range((void *)&l2_table[l2_pos], sizeof(l2_table[0])); - table = (uint32_t *)(l1_page_table[l1_pos] & Z_XTENSA_PTE_PPN_MASK); - table[l2_pos] = Z_XTENSA_MMU_ILLEGAL; + l2_table[l2_pos] = Z_XTENSA_MMU_ILLEGAL; + + sys_cache_data_flush_range((void *)&l2_table[l2_pos], sizeof(l2_table[0])); for (l2_pos = 0; l2_pos < XTENSA_L2_PAGE_TABLE_ENTRIES; l2_pos++) { - if (table[l2_pos] != Z_XTENSA_MMU_ILLEGAL) { + if (!is_pte_illegal(l2_table[l2_pos])) { goto end; } } - l1_page_table[l1_pos] = Z_XTENSA_MMU_ILLEGAL; - table_pos = (table - (uint32_t *)l2_page_tables) / (XTENSA_L2_PAGE_TABLE_ENTRIES); + l1_table[l1_pos] = Z_XTENSA_MMU_ILLEGAL; + sys_cache_data_flush_range((void *)&l1_table[l1_pos], sizeof(l1_table[0])); + + table_pos = (l2_table - (uint32_t *)l2_page_tables) / (XTENSA_L2_PAGE_TABLE_ENTRIES); atomic_clear_bit(l2_page_tables_track, table_pos); /* Need to invalidate L2 page table as it is no longer valid. */ - xtensa_dtlb_vaddr_invalidate((void *)table); + xtensa_dtlb_vaddr_invalidate((void *)l2_table); end: - if (exec) { + return exec; +} + +static inline void __arch_mem_unmap(void *va) +{ + bool is_exec; + void *vaddr, *vaddr_uc; + + if (IS_ENABLED(CONFIG_XTENSA_MMU_DOUBLE_MAP)) { + if (arch_xtensa_is_ptr_cached(va)) { + vaddr = va; + vaddr_uc = arch_xtensa_uncached_ptr(va); + } else { + vaddr = arch_xtensa_cached_ptr(va); + vaddr_uc = va; + } + } else { + vaddr = va; + } + + is_exec = l2_page_table_unmap(z_xtensa_kernel_ptables, (void *)vaddr); + + if (IS_ENABLED(CONFIG_XTENSA_MMU_DOUBLE_MAP)) { + (void)l2_page_table_unmap(z_xtensa_kernel_ptables, (void *)vaddr_uc); + } + +#ifdef CONFIG_USERSPACE + sys_snode_t *node; + struct arch_mem_domain *domain; + k_spinlock_key_t key; + + key = k_spin_lock(&z_mem_domain_lock); + SYS_SLIST_FOR_EACH_NODE(&xtensa_domain_list, node) { + domain = CONTAINER_OF(node, struct arch_mem_domain, node); + + (void)l2_page_table_unmap(domain->ptables, (void *)vaddr); + + if (IS_ENABLED(CONFIG_XTENSA_MMU_DOUBLE_MAP)) { + (void)l2_page_table_unmap(domain->ptables, (void *)vaddr_uc); + } + } + k_spin_unlock(&z_mem_domain_lock, key); +#endif /* CONFIG_USERSPACE */ + + if (is_exec) { xtensa_itlb_vaddr_invalidate(vaddr); } xtensa_dtlb_vaddr_invalidate(vaddr); + + if (IS_ENABLED(CONFIG_XTENSA_MMU_DOUBLE_MAP)) { + if (is_exec) { + xtensa_itlb_vaddr_invalidate(vaddr_uc); + } + xtensa_dtlb_vaddr_invalidate(vaddr_uc); + } } void arch_mem_unmap(void *addr, size_t size) { uint32_t va = (uint32_t)addr; uint32_t rem_size = (uint32_t)size; - int key; + k_spinlock_key_t key; if (addr == NULL) { LOG_ERR("Cannot unmap NULL pointer"); @@ -482,13 +782,363 @@ void arch_mem_unmap(void *addr, size_t size) return; } - key = arch_irq_lock(); + key = k_spin_lock(&xtensa_mmu_lock); while (rem_size > 0) { - l2_page_table_unmap((void *)va); + __arch_mem_unmap((void *)va); + rem_size -= (rem_size >= KB(4)) ? KB(4) : rem_size; va += KB(4); } - arch_irq_unlock(key); + k_spin_unlock(&xtensa_mmu_lock, key); } + +#ifdef CONFIG_USERSPACE + +static inline uint32_t *alloc_l1_table(void) +{ + uint16_t idx; + + for (idx = 0; idx < CONFIG_XTENSA_MMU_NUM_L1_TABLES; idx++) { + if (!atomic_test_and_set_bit(l1_page_table_track, idx)) { + return (uint32_t *)&l1_page_table[idx]; + } + } + + return NULL; +} + +static uint32_t *dup_table(uint32_t *source_table) +{ + uint16_t i, j; + uint32_t *dst_table = alloc_l1_table(); + + if (!dst_table) { + return NULL; + } + + for (i = 0; i < XTENSA_L1_PAGE_TABLE_ENTRIES; i++) { + uint32_t *l2_table, *src_l2_table; + + if (is_pte_illegal(source_table[i])) { + dst_table[i] = Z_XTENSA_MMU_ILLEGAL; + continue; + } + + src_l2_table = (uint32_t *)(source_table[i] & Z_XTENSA_PTE_PPN_MASK); + l2_table = alloc_l2_table(); + if (l2_table == NULL) { + goto err; + } + + for (j = 0; j < XTENSA_L2_PAGE_TABLE_ENTRIES; j++) { + l2_table[j] = src_l2_table[j]; + } + + /* The page table is using kernel ASID because we don't + * user thread manipulate it. + */ + dst_table[i] = Z_XTENSA_PTE((uint32_t)l2_table, Z_XTENSA_KERNEL_RING, + Z_XTENSA_PAGE_TABLE_ATTR); + + sys_cache_data_flush_range((void *)l2_table, XTENSA_L2_PAGE_TABLE_SIZE); + } + + sys_cache_data_flush_range((void *)dst_table, XTENSA_L1_PAGE_TABLE_SIZE); + + return dst_table; + +err: + /* TODO: Cleanup failed allocation*/ + return NULL; +} + +int arch_mem_domain_init(struct k_mem_domain *domain) +{ + uint32_t *ptables; + k_spinlock_key_t key; + int ret; + + /* + * For now, lets just assert if we have reached the maximum number + * of asid we assert. + */ + __ASSERT(asid_count < (Z_XTENSA_MMU_SHARED_ASID), "Reached maximum of ASID available"); + + key = k_spin_lock(&xtensa_mmu_lock); + ptables = dup_table(z_xtensa_kernel_ptables); + + if (ptables == NULL) { + ret = -ENOMEM; + goto err; + } + + domain->arch.ptables = ptables; + domain->arch.asid = ++asid_count; + + sys_slist_append(&xtensa_domain_list, &domain->arch.node); + + ret = 0; + +err: + k_spin_unlock(&xtensa_mmu_lock, key); + + return ret; +} + +static int region_map_update(uint32_t *ptables, uintptr_t start, + size_t size, uint32_t ring, uint32_t flags) +{ + int ret = 0; + + for (size_t offset = 0; offset < size; offset += CONFIG_MMU_PAGE_SIZE) { + uint32_t *l2_table, pte; + uint32_t page = start + offset; + uint32_t l1_pos = page >> 22; + uint32_t l2_pos = Z_XTENSA_L2_POS(page); + + /* Make sure we grab a fresh copy of L1 page table */ + sys_cache_data_invd_range((void *)&ptables[l1_pos], sizeof(ptables[0])); + + l2_table = (uint32_t *)(ptables[l1_pos] & Z_XTENSA_PTE_PPN_MASK); + + sys_cache_data_invd_range((void *)&l2_table[l2_pos], sizeof(l2_table[0])); + + pte = Z_XTENSA_PTE_RING_SET(l2_table[l2_pos], ring); + pte = Z_XTENSA_PTE_ATTR_SET(pte, flags); + + l2_table[l2_pos] = pte; + + sys_cache_data_flush_range((void *)&l2_table[l2_pos], sizeof(l2_table[0])); + + xtensa_dtlb_vaddr_invalidate( + (void *)(pte & Z_XTENSA_PTE_PPN_MASK)); + } + + return ret; +} + +static inline int update_region(uint32_t *ptables, uintptr_t start, + size_t size, uint32_t ring, uint32_t flags) +{ + int ret; + k_spinlock_key_t key; + + key = k_spin_lock(&xtensa_mmu_lock); + +#ifdef CONFIG_XTENSA_MMU_DOUBLE_MAP + uintptr_t va, va_uc; + uint32_t new_flags, new_flags_uc; + + if (arch_xtensa_is_ptr_cached((void *)start)) { + va = start; + va_uc = (uintptr_t)arch_xtensa_uncached_ptr((void *)start); + } else { + va = (uintptr_t)arch_xtensa_cached_ptr((void *)start); + va_uc = start; + } + + new_flags_uc = (flags & ~Z_XTENSA_PTE_ATTR_CACHED_MASK); + new_flags = new_flags_uc | Z_XTENSA_MMU_CACHED_WB; + + ret = region_map_update(ptables, va, size, ring, new_flags); + + if (ret == 0) { + ret = region_map_update(ptables, va_uc, size, ring, new_flags_uc); + } +#else + ret = region_map_update(ptables, start, size, ring, flags); +#endif /* CONFIG_XTENSA_MMU_DOUBLE_MAP */ + + k_spin_unlock(&xtensa_mmu_lock, key); + + return ret; +} + +static inline int reset_region(uint32_t *ptables, uintptr_t start, size_t size) +{ + return update_region(ptables, start, size, Z_XTENSA_KERNEL_RING, Z_XTENSA_MMU_W); +} + +void xtensa_set_stack_perms(struct k_thread *thread) +{ + if ((thread->base.user_options & K_USER) == 0) { + return; + } + + update_region(thread_page_tables_get(thread), + thread->stack_info.start, thread->stack_info.size, + Z_XTENSA_USER_RING, Z_XTENSA_MMU_W | Z_XTENSA_MMU_CACHED_WB); +} + +void xtensa_user_stack_perms(struct k_thread *thread) +{ + (void)memset((void *)thread->stack_info.start, 0xAA, + thread->stack_info.size - thread->stack_info.delta); + + update_region(thread_page_tables_get(thread), + thread->stack_info.start, thread->stack_info.size, + Z_XTENSA_USER_RING, Z_XTENSA_MMU_W | Z_XTENSA_MMU_CACHED_WB); +} + +int arch_mem_domain_max_partitions_get(void) +{ + return CONFIG_MAX_DOMAIN_PARTITIONS; +} + +int arch_mem_domain_partition_remove(struct k_mem_domain *domain, + uint32_t partition_id) +{ + struct k_mem_partition *partition = &domain->partitions[partition_id]; + + /* Reset the partition's region back to defaults */ + return reset_region(domain->arch.ptables, partition->start, + partition->size); +} + +int arch_mem_domain_partition_add(struct k_mem_domain *domain, + uint32_t partition_id) +{ + uint32_t ring = domain->arch.asid == 0 ? Z_XTENSA_KERNEL_RING : Z_XTENSA_USER_RING; + struct k_mem_partition *partition = &domain->partitions[partition_id]; + + return update_region(domain->arch.ptables, partition->start, + partition->size, ring, partition->attr); +} + +/* These APIs don't need to do anything */ +int arch_mem_domain_thread_add(struct k_thread *thread) +{ + int ret = 0; + bool is_user, is_migration; + uint32_t *old_ptables; + struct k_mem_domain *domain; + + old_ptables = thread->arch.ptables; + domain = thread->mem_domain_info.mem_domain; + thread->arch.ptables = domain->arch.ptables; + + is_user = (thread->base.user_options & K_USER) != 0; + is_migration = (old_ptables != NULL) && is_user; + + /* Give access to the thread's stack in its new + * memory domain if it is migrating. + */ + if (is_migration) { + xtensa_set_stack_perms(thread); + } + + if (is_migration) { + ret = reset_region(old_ptables, + thread->stack_info.start, + thread->stack_info.size); + } + + return ret; +} + +int arch_mem_domain_thread_remove(struct k_thread *thread) +{ + struct k_mem_domain *domain = thread->mem_domain_info.mem_domain; + + if ((thread->base.user_options & K_USER) == 0) { + return 0; + } + + if ((thread->base.thread_state & _THREAD_DEAD) == 0) { + /* Thread is migrating to another memory domain and not + * exiting for good; we weren't called from + * z_thread_abort(). Resetting the stack region will + * take place in the forthcoming thread_add() call. + */ + return 0; + } + + /* Restore permissions on the thread's stack area since it is no + * longer a member of the domain. + */ + return reset_region(domain->arch.ptables, + thread->stack_info.start, + thread->stack_info.size); +} + +static bool page_validate(uint32_t *ptables, uint32_t page, uint8_t ring, bool write) +{ + uint8_t asid_ring; + uint32_t rasid, pte, *l2_table; + uint32_t l1_pos = page >> 22; + uint32_t l2_pos = Z_XTENSA_L2_POS(page); + + if (is_pte_illegal(ptables[l1_pos])) { + return false; + } + + l2_table = (uint32_t *)(ptables[l1_pos] & Z_XTENSA_PTE_PPN_MASK); + pte = l2_table[l2_pos]; + + if (is_pte_illegal(pte)) { + return false; + } + + asid_ring = 0; + rasid = xtensa_rasid_get(); + for (uint32_t i = 0; i < 4; i++) { + if (Z_XTENSA_PTE_ASID_GET(pte, rasid) == + Z_XTENSA_RASID_ASID_GET(rasid, i)) { + asid_ring = i; + break; + } + } + + if (ring > asid_ring) { + return false; + } + + if (write) { + return (Z_XTENSA_PTE_ATTR_GET((pte)) & Z_XTENSA_MMU_W) != 0; + } + + return true; +} + +int arch_buffer_validate(void *addr, size_t size, int write) +{ + int ret = 0; + uint8_t *virt; + size_t aligned_size; + const struct k_thread *thread = _current; + uint32_t *ptables = thread_page_tables_get(thread); + uint8_t ring = ((thread->base.user_options & K_USER) != 0) ? + Z_XTENSA_USER_RING : Z_XTENSA_KERNEL_RING; + + /* addr/size arbitrary, fix this up into an aligned region */ + k_mem_region_align((uintptr_t *)&virt, &aligned_size, + (uintptr_t)addr, size, CONFIG_MMU_PAGE_SIZE); + + for (size_t offset = 0; offset < aligned_size; + offset += CONFIG_MMU_PAGE_SIZE) { + if (!page_validate(ptables, (uint32_t)(virt + offset), ring, write)) { + ret = -1; + break; + } + } + + return ret; +} + +void z_xtensa_swap_update_page_tables(struct k_thread *incoming) +{ + uint32_t *ptables = incoming->arch.ptables; + struct arch_mem_domain *domain = + &(incoming->mem_domain_info.mem_domain->arch); + + /* Lets set the asid for the incoming thread */ + if ((incoming->base.user_options & K_USER) != 0) { + xtensa_rasid_asid_set(domain->asid, Z_XTENSA_USER_RING); + } + + switch_page_tables(ptables, true, false); +} + +#endif /* CONFIG_USERSPACE */ diff --git a/arch/xtensa/include/kernel_arch_func.h b/arch/xtensa/include/kernel_arch_func.h index 2256f72f645..8ce5cc52a5b 100644 --- a/arch/xtensa/include/kernel_arch_func.h +++ b/arch/xtensa/include/kernel_arch_func.h @@ -174,6 +174,13 @@ static inline bool arch_is_in_isr(void) return arch_curr_cpu()->nested != 0U; } +#ifdef CONFIG_USERSPACE +extern void z_xtensa_userspace_enter(k_thread_entry_t user_entry, + void *p1, void *p2, void *p3, + uintptr_t stack_end, + uintptr_t stack_start); +#endif /* CONFIG_USERSPACE */ + #ifdef __cplusplus } #endif diff --git a/arch/xtensa/include/offsets_short_arch.h b/arch/xtensa/include/offsets_short_arch.h index 34a4a5842cf..f19750dc0ac 100644 --- a/arch/xtensa/include/offsets_short_arch.h +++ b/arch/xtensa/include/offsets_short_arch.h @@ -2,4 +2,18 @@ * Copyright (c) 2021 Intel Corporation * SPDX-License-Identifier: Apache-2.0 */ -/* Empty File */ +#ifndef ZEPHYR_ARCH_XTENSA_INCLUDE_OFFSETS_SHORT_ARCH_H_ +#define ZEPHYR_ARCH_XTENSA_INCLUDE_OFFSETS_SHORT_ARCH_H_ + +#define _thread_offset_to_flags \ + (___thread_t_arch_OFFSET + ___thread_arch_t_flags_OFFSET) + +#ifdef CONFIG_USERSPACE +#define _thread_offset_to_psp \ + (___thread_t_arch_OFFSET + ___thread_arch_t_psp_OFFSET) + +#define _thread_offset_to_ptables \ + (___thread_t_arch_OFFSET + ___thread_arch_t_ptables_OFFSET) +#endif /* CONFIG_USERSPACE */ + +#endif /* ZEPHYR_ARCH_XTENSA_INCLUDE_OFFSETS_SHORT_ARCH_H_ */ diff --git a/arch/xtensa/include/xtensa-asm2-s.h b/arch/xtensa/include/xtensa-asm2-s.h index f691dbc6cad..a98c61db253 100644 --- a/arch/xtensa/include/xtensa-asm2-s.h +++ b/arch/xtensa/include/xtensa-asm2-s.h @@ -176,7 +176,8 @@ rsr.SCOMPARE1 a0 s32i a0, a1, ___xtensa_irq_bsa_t_scompare1_OFFSET #endif -#if XCHAL_HAVE_THREADPTR && defined(CONFIG_THREAD_LOCAL_STORAGE) +#if XCHAL_HAVE_THREADPTR && \ + (defined(CONFIG_USERSPACE) || defined(CONFIG_THREAD_LOCAL_STORAGE)) rur.THREADPTR a0 s32i a0, a1, ___xtensa_irq_bsa_t_threadptr_OFFSET #endif @@ -409,6 +410,16 @@ _xstack_returned_\@: l32i a2, a1, 0 l32i a2, a2, ___xtensa_irq_bsa_t_scratch_OFFSET +#if XCHAL_HAVE_THREADPTR && defined(CONFIG_USERSPACE) + /* Clear up the threadptr because it is used + * to check if a thread is runnig on user mode. Since + * we are in a interruption we don't want the system + * thinking it is possbly running in user mode. + */ + movi.n a0, 0 + wur.THREADPTR a0 +#endif /* XCHAL_HAVE_THREADPTR && CONFIG_USERSPACE */ + /* There's a gotcha with level 1 handlers: the INTLEVEL field * gets left at zero and not set like high priority interrupts * do. That works fine for exceptions, but for L1 interrupts, diff --git a/include/zephyr/arch/syscall.h b/include/zephyr/arch/syscall.h index b657717e3d4..5b41561b681 100644 --- a/include/zephyr/arch/syscall.h +++ b/include/zephyr/arch/syscall.h @@ -23,6 +23,8 @@ #include #elif defined(CONFIG_RISCV) #include +#elif defined(CONFIG_XTENSA) +#include #endif #endif /* ZEPHYR_INCLUDE_ARCH_SYSCALL_H_ */ diff --git a/include/zephyr/arch/xtensa/arch.h b/include/zephyr/arch/xtensa/arch.h index 0838e68ee5a..397e5c7fa78 100644 --- a/include/zephyr/arch/xtensa/arch.h +++ b/include/zephyr/arch/xtensa/arch.h @@ -29,6 +29,7 @@ #include #include #include +#include #include @@ -47,6 +48,15 @@ extern "C" { #endif +struct arch_mem_domain { +#ifdef CONFIG_XTENSA_MMU + uint32_t *ptables __aligned(CONFIG_MMU_PAGE_SIZE); + uint8_t asid; + bool dirty; +#endif + sys_snode_t node; +}; + extern void xtensa_arch_except(int reason_p); #define ARCH_EXCEPT(reason_p) do { \ diff --git a/include/zephyr/arch/xtensa/syscall.h b/include/zephyr/arch/xtensa/syscall.h new file mode 100644 index 00000000000..3d78827b77c --- /dev/null +++ b/include/zephyr/arch/xtensa/syscall.h @@ -0,0 +1,238 @@ +/* + * Copyright (c) 2022 Intel Corporation. + * + * SPDX-License-Identifier: Apache-2.0 + */ + +/** + * @file + * @brief Xtensa specific syscall header + * + * This header contains the Xtensa specific syscall interface. It is + * included by the syscall interface architecture-abstraction header + * (include/arch/syscall.h) + */ + +#ifndef ZEPHYR_INCLUDE_ARCH_XTENSA_SYSCALL_H_ +#define ZEPHYR_INCLUDE_ARCH_XTENSA_SYSCALL_H_ + +#ifdef CONFIG_USERSPACE +#ifndef _ASMLANGUAGE + +#include +#include +#include +#include + +#ifdef __cplusplus +extern "C" { +#endif + +#ifdef CONFIG_XTENSA_SYSCALL_USE_HELPER +uintptr_t arch_syscall_invoke6_helper(uintptr_t arg1, uintptr_t arg2, + uintptr_t arg3, uintptr_t arg4, + uintptr_t arg5, uintptr_t arg6, + uintptr_t call_id); + +uintptr_t arch_syscall_invoke5_helper(uintptr_t arg1, uintptr_t arg2, + uintptr_t arg3, uintptr_t arg4, + uintptr_t arg5, + uintptr_t call_id); + +uintptr_t arch_syscall_invoke4_helper(uintptr_t arg1, uintptr_t arg2, + uintptr_t arg3, uintptr_t arg4, + uintptr_t call_id); + +uintptr_t arch_syscall_invoke3_helper(uintptr_t arg1, uintptr_t arg2, + uintptr_t arg3, uintptr_t call_id); + +uintptr_t arch_syscall_invoke2_helper(uintptr_t arg1, uintptr_t arg2, + uintptr_t call_id); + +uintptr_t arch_syscall_invoke1_helper(uintptr_t arg1, uintptr_t call_id); + +uintptr_t arch_syscall_invoke0_helper(uintptr_t call_id); +#endif /* CONFIG_XTENSA_SYSCALL_USE_HELPER */ + +/** + * We are following Linux Xtensa syscall ABI: + * + * syscall number arg1, arg2, arg3, arg4, arg5, arg6 + * -------------- ---------------------------------- + * a2 a6, a3, a4, a5, a8, a9 + * + **/ + +static inline uintptr_t arch_syscall_invoke6(uintptr_t arg1, uintptr_t arg2, + uintptr_t arg3, uintptr_t arg4, + uintptr_t arg5, uintptr_t arg6, + uintptr_t call_id) +{ +#ifdef CONFIG_XTENSA_SYSCALL_USE_HELPER + return arch_syscall_invoke6_helper(arg1, arg2, arg3, + arg4, arg5, arg6, + call_id); +#else + register uintptr_t a2 __asm__("%a2") = call_id; + register uintptr_t a6 __asm__("%a6") = arg1; + register uintptr_t a3 __asm__("%a3") = arg2; + register uintptr_t a4 __asm__("%a4") = arg3; + register uintptr_t a5 __asm__("%a5") = arg4; + register uintptr_t a8 __asm__("%a8") = arg5; + register uintptr_t a9 __asm__("%a9") = arg6; + + __asm__ volatile("syscall\n\t" + : "=r" (a2) + : "r" (a2), "r" (a6), "r" (a3), "r" (a4), + "r" (a5), "r" (a8), "r" (a9) + : "memory"); + + return a2; +#endif /* CONFIG_XTENSA_SYSCALL_USE_HELPER */ +} + +static inline uintptr_t arch_syscall_invoke5(uintptr_t arg1, uintptr_t arg2, + uintptr_t arg3, uintptr_t arg4, + uintptr_t arg5, uintptr_t call_id) +{ +#ifdef CONFIG_XTENSA_SYSCALL_USE_HELPER + return arch_syscall_invoke5_helper(arg1, arg2, arg3, + arg4, arg5, call_id); +#else + register uintptr_t a2 __asm__("%a2") = call_id; + register uintptr_t a6 __asm__("%a6") = arg1; + register uintptr_t a3 __asm__("%a3") = arg2; + register uintptr_t a4 __asm__("%a4") = arg3; + register uintptr_t a5 __asm__("%a5") = arg4; + register uintptr_t a8 __asm__("%a8") = arg5; + + __asm__ volatile("syscall\n\t" + : "=r" (a2) + : "r" (a2), "r" (a6), "r" (a3), "r" (a4), + "r" (a5), "r" (a8) + : "memory"); + + return a2; +#endif /* CONFIG_XTENSA_SYSCALL_USE_HELPER */ +} + +static inline uintptr_t arch_syscall_invoke4(uintptr_t arg1, uintptr_t arg2, + uintptr_t arg3, uintptr_t arg4, + uintptr_t call_id) +{ +#ifdef CONFIG_XTENSA_SYSCALL_USE_HELPER + return arch_syscall_invoke4_helper(arg1, arg2, arg3, arg4, call_id); +#else + register uintptr_t a2 __asm__("%a2") = call_id; + register uintptr_t a6 __asm__("%a6") = arg1; + register uintptr_t a3 __asm__("%a3") = arg2; + register uintptr_t a4 __asm__("%a4") = arg3; + register uintptr_t a5 __asm__("%a5") = arg4; + + __asm__ volatile("syscall\n\t" + : "=r" (a2) + : "r" (a2), "r" (a6), "r" (a3), "r" (a4), + "r" (a5) + : "memory"); + + return a2; +#endif /* CONFIG_XTENSA_SYSCALL_USE_HELPER */ +} + +static inline uintptr_t arch_syscall_invoke3(uintptr_t arg1, uintptr_t arg2, + uintptr_t arg3, uintptr_t call_id) +{ +#ifdef CONFIG_XTENSA_SYSCALL_USE_HELPER + return arch_syscall_invoke3_helper(arg1, arg2, arg3, call_id); +#else + register uintptr_t a2 __asm__("%a2") = call_id; + register uintptr_t a6 __asm__("%a6") = arg1; + register uintptr_t a3 __asm__("%a3") = arg2; + register uintptr_t a4 __asm__("%a4") = arg3; + + __asm__ volatile("syscall\n\t" + : "=r" (a2) + : "r" (a2), "r" (a6), "r" (a3), "r" (a4) + : "memory"); + + return a2; +#endif /* CONFIG_XTENSA_SYSCALL_USE_HELPER */ +} + +static inline uintptr_t arch_syscall_invoke2(uintptr_t arg1, uintptr_t arg2, + uintptr_t call_id) +{ +#ifdef CONFIG_XTENSA_SYSCALL_USE_HELPER + return arch_syscall_invoke2_helper(arg1, arg2, call_id); +#else + register uintptr_t a2 __asm__("%a2") = call_id; + register uintptr_t a6 __asm__("%a6") = arg1; + register uintptr_t a3 __asm__("%a3") = arg2; + + __asm__ volatile("syscall\n\t" + : "=r" (a2) + : "r" (a2), "r" (a6), "r" (a3) + : "memory"); + + return a2; +#endif +} + +static inline uintptr_t arch_syscall_invoke1(uintptr_t arg1, + uintptr_t call_id) +{ +#ifdef CONFIG_XTENSA_SYSCALL_USE_HELPER + return arch_syscall_invoke1_helper(arg1, call_id); +#else + register uintptr_t a2 __asm__("%a2") = call_id; + register uintptr_t a6 __asm__("%a6") = arg1; + + __asm__ volatile("syscall\n\t" + : "=r" (a2) + : "r" (a2), "r" (a6) + : "memory"); + + return a2; +#endif +} + +static inline uintptr_t arch_syscall_invoke0(uintptr_t call_id) +{ +#ifdef CONFIG_XTENSA_SYSCALL_USE_HELPER + return arch_syscall_invoke0_helper(call_id); +#else + register uintptr_t a2 __asm__("%a2") = call_id; + + __asm__ volatile("syscall\n\t" + : "=r" (a2) + : "r" (a2) + : "memory"); + + return a2; +#endif +} + +/* + * There is no easy (or generic) way to figure out if a thread is runnining + * in un-privileged mode. Reading the currrent ring (PS.CRING) is a privileged + * instruction and not thread local storage is not available in xcc. + */ +static inline bool arch_is_user_context(void) +{ + uint32_t thread; + + __asm__ volatile( + "rur.THREADPTR %0\n\t" + : "=a" (thread) + ); + + return !!thread; +} + +#ifdef __cplusplus +} +#endif + +#endif /* _ASMLANGUAGE */ +#endif /* CONFIG_USERSPACE */ +#endif /* ZEPHYR_INCLUDE_ARCH_XTENSA_SYSCALL_H_ */ diff --git a/include/zephyr/arch/xtensa/thread.h b/include/zephyr/arch/xtensa/thread.h index 4ec5da1ea2c..2bebe2722bc 100644 --- a/include/zephyr/arch/xtensa/thread.h +++ b/include/zephyr/arch/xtensa/thread.h @@ -7,6 +7,7 @@ #ifndef ZEPHYR_INCLUDE_ARCH_XTENSA_THREAD_H_ #define ZEPHYR_INCLUDE_ARCH_XTENSA_THREAD_H_ +#include #ifndef _ASMLANGUAGE /* Xtensa doesn't use these structs, but Zephyr core requires they be @@ -22,6 +23,14 @@ typedef struct _callee_saved _callee_saved_t; struct _thread_arch { uint32_t last_cpu; +#ifdef CONFIG_USERSPACE + uint32_t *ptables; + + /* Initial privilege mode stack pointer when doing a system call. + * Un-set for surpervisor threads. + */ + uint8_t *psp; +#endif }; typedef struct _thread_arch _thread_arch_t; diff --git a/include/zephyr/arch/xtensa/xtensa_mmu.h b/include/zephyr/arch/xtensa/xtensa_mmu.h index 2ee3dc6c9ab..40fd0ff8f5c 100644 --- a/include/zephyr/arch/xtensa/xtensa_mmu.h +++ b/include/zephyr/arch/xtensa/xtensa_mmu.h @@ -9,8 +9,40 @@ #define Z_XTENSA_MMU_X BIT(0) #define Z_XTENSA_MMU_W BIT(1) +#define Z_XTENSA_MMU_XW (BIT(1) | BIT(0)) + #define Z_XTENSA_MMU_CACHED_WB BIT(2) #define Z_XTENSA_MMU_CACHED_WT BIT(3) + +#define K_MEM_PARTITION_IS_EXECUTABLE(attr) (((attr) & Z_XTENSA_MMU_X) != 0) +#define K_MEM_PARTITION_IS_WRITABLE(attr) (((attr) & Z_XENSA_MMU_W) != 0) + +/* Read-Write access permission attributes */ +#define K_MEM_PARTITION_P_RW_U_RW ((k_mem_partition_attr_t) \ + {Z_XTENSA_MMU_W}) +#define K_MEM_PARTITION_P_RW_U_NA ((k_mem_partition_attr_t) \ + {0}) +#define K_MEM_PARTITION_P_RO_U_RO ((k_mem_partition_attr_t) \ + {0}) +#define K_MEM_PARTITION_P_RO_U_NA ((k_mem_partition_attr_t) \ + {0}) +#define K_MEM_PARTITION_P_NA_U_NA ((k_mem_partition_attr_t) \ + {0}) + +/* Execution-allowed attributes */ +#define K_MEM_PARTITION_P_RX_U_RX ((k_mem_partition_attr_t) \ + {Z_XTENSA_MMU_X}) + +/* + * This BIT tells the mapping code whether the uncached pointer should + * be shared between all threads. That is not used in the HW, it is + * just for the implementation. + * + * The pte mapping this memory will use an ASID that is set in the + * ring 4 spot in RASID. + */ +#define Z_XTENSA_MMU_MAP_SHARED BIT(30) + #define Z_XTENSA_MMU_ILLEGAL (BIT(3) | BIT(2)) /* Struct used to map a memory region */ @@ -21,6 +53,8 @@ struct xtensa_mmu_range { const uint32_t attrs; }; +typedef uint32_t k_mem_partition_attr_t; + extern const struct xtensa_mmu_range xtensa_soc_mmu_ranges[]; extern int xtensa_soc_mmu_ranges_num; From c53325298d2bf20027b04ed08cd05db9df81741e Mon Sep 17 00:00:00 2001 From: Flavio Ceolin Date: Wed, 16 Nov 2022 22:48:42 -0800 Subject: [PATCH 0020/3723] xtensa: userspace: Stack object header Add a header with architecture specific macros and definitions that re used on userspace for stack objects. Signed-off-by: Flavio Ceolin --- include/zephyr/arch/xtensa/arch.h | 7 +-- include/zephyr/arch/xtensa/thread_stack.h | 67 +++++++++++++++++++++++ 2 files changed, 68 insertions(+), 6 deletions(-) create mode 100644 include/zephyr/arch/xtensa/thread_stack.h diff --git a/include/zephyr/arch/xtensa/arch.h b/include/zephyr/arch/xtensa/arch.h index 397e5c7fa78..9f2fb757a11 100644 --- a/include/zephyr/arch/xtensa/arch.h +++ b/include/zephyr/arch/xtensa/arch.h @@ -29,16 +29,11 @@ #include #include #include +#include #include #include -#ifdef CONFIG_KERNEL_COHERENCE -#define ARCH_STACK_PTR_ALIGN XCHAL_DCACHE_LINESIZE -#else -#define ARCH_STACK_PTR_ALIGN 16 -#endif - /* Xtensa GPRs are often designated by two different names */ #define sys_define_gpr_with_alias(name1, name2) union { uint32_t name1, name2; } diff --git a/include/zephyr/arch/xtensa/thread_stack.h b/include/zephyr/arch/xtensa/thread_stack.h new file mode 100644 index 00000000000..eaa160ccf1f --- /dev/null +++ b/include/zephyr/arch/xtensa/thread_stack.h @@ -0,0 +1,67 @@ +/* + * Copyright (c) 2022 Intel Corporation + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#ifndef ZEPHYR_INCLUDE_ARCH_XTENSA_THREAD_STACK_H_ +#define ZEPHYR_INCLUDE_ARCH_XTENSA_THREAD_STACK_H_ + +#include +#include + +#ifdef CONFIG_KERNEL_COHERENCE +#define ARCH_STACK_PTR_ALIGN XCHAL_DCACHE_LINESIZE +#else +#define ARCH_STACK_PTR_ALIGN 16 +#endif + + +#if CONFIG_USERSPACE +#define Z_XTENSA_STACK_BASE_ALIGN CONFIG_MMU_PAGE_SIZE +#define Z_XTENSA_STACK_SIZE_ALIGN CONFIG_MMU_PAGE_SIZE +#else +#define Z_XTENSA_STACK_BASE_ALIGN ARCH_STACK_PTR_ALIGN +#define Z_XTENSA_STACK_SIZE_ALIGN ARCH_STACK_PTR_ALIGN +#endif + +/* + * + * High memory addresses + * + * +-------------------+ <- thread.stack_info.start + thread.stack_info.size + * | TLS | + * +-------------------+ <- initial sp (computable with thread.stack_info.delta) + * | | + * | Thread stack | + * | | + * +-------------------+ <- thread.stack_info.start + * | Privileged stack | } CONFIG_MMU_PAGE_SIZE + * +-------------------+ <- thread.stack_obj + * + * Low Memory addresses + */ + +#ifndef _ASMLANGUAGE + +/* thread stack */ +#ifdef CONFIG_XTENSA_MMU +struct z_xtensa_thread_stack_header { + char privilege_stack[CONFIG_MMU_PAGE_SIZE]; +} __packed __aligned(Z_XTENSA_STACK_BASE_ALIGN); + +#define ARCH_THREAD_STACK_RESERVED \ + sizeof(struct z_xtensa_thread_stack_header) +#endif /* CONFIG_XTENSA_MMU */ + +#define ARCH_THREAD_STACK_OBJ_ALIGN(size) Z_XTENSA_STACK_BASE_ALIGN +#define ARCH_THREAD_STACK_SIZE_ADJUST(size) \ + ROUND_UP((size), Z_XTENSA_STACK_SIZE_ALIGN) + +/* kernel stack */ +#define ARCH_KERNEL_STACK_RESERVED 0 +#define ARCH_KERNEL_STACK_OBJ_ALIGN ARCH_STACK_PTR_ALIGN + +#endif /* _ASMLANGUAGE */ + +#endif From c4706a382300b57032546fd4085acc474a48864e Mon Sep 17 00:00:00 2001 From: Daniel Leung Date: Tue, 31 Jan 2023 13:07:48 -0800 Subject: [PATCH 0021/3723] xtensa: mmu: handle page faults in double exception handler This changes the TLB misses handling back to the assembly in user exception, and any page faults during TLB misses to be handled in double exception handler. This should speed up simple TLB miss handling as we don't have to go all the way to the C handler. Signed-off-by: Daniel Leung Signed-off-by: Flavio Ceolin --- arch/xtensa/core/xtensa-asm2-util.S | 6 +- arch/xtensa/core/xtensa-asm2.c | 95 +++++++++++------------------ 2 files changed, 41 insertions(+), 60 deletions(-) diff --git a/arch/xtensa/core/xtensa-asm2-util.S b/arch/xtensa/core/xtensa-asm2-util.S index c108a09dee4..1ef9e5e1b4f 100644 --- a/arch/xtensa/core/xtensa-asm2-util.S +++ b/arch/xtensa/core/xtensa-asm2-util.S @@ -447,7 +447,10 @@ _DoubleExceptionVector: beqz a0, _handle_tlb_miss_dblexc rsr a0, ZSR_A0SAVE -#endif + + j _Level1Vector +#else + #if defined(CONFIG_SIMULATOR_XTENSA) || defined(XT_SIMULATOR) 1: /* Tell simulator to stop executing here, instead of trying to do @@ -465,6 +468,7 @@ _DoubleExceptionVector: 1: #endif j 1b +#endif /* CONFIG_XTENSA_MMU */ #ifdef CONFIG_XTENSA_MMU _handle_tlb_miss_dblexc: diff --git a/arch/xtensa/core/xtensa-asm2.c b/arch/xtensa/core/xtensa-asm2.c index 1e8c92759e4..3fb519cd80d 100644 --- a/arch/xtensa/core/xtensa-asm2.c +++ b/arch/xtensa/core/xtensa-asm2.c @@ -293,34 +293,31 @@ void *xtensa_excint1_c(int *interrupted_stack) uint32_t ps; void *pc; +#ifdef CONFIG_XTENSA_MMU + bool is_dblexc; + uint32_t depc; +#else + const bool is_dblexc = false; +#endif /* CONFIG_XTENSA_MMU */ + __asm__ volatile("rsr.exccause %0" : "=r"(cause)); #ifdef CONFIG_XTENSA_MMU - /* TLB miss exception comes through level 1 interrupt also. - * We need to preserve execution context after we have handled - * the TLB miss, so we cannot unconditionally unmask interrupts. - * For other cause, we can unmask interrupts so this would act - * the same as if there is no MMU. - */ - switch (cause) { - case EXCCAUSE_ITLB_MISS: - /* Instruction TLB miss */ - __fallthrough; - case EXCCAUSE_DTLB_MISS: - /* Data TLB miss */ + __asm__ volatile("rsr.depc %0" : "=r"(depc)); - /* Do not unmask interrupt while handling TLB misses. */ - break; - default: - /* For others, we can unmask interrupts. */ - bsa->ps &= ~PS_INTLEVEL_MASK; - break; - } + is_dblexc = (depc != 0U); #endif /* CONFIG_XTENSA_MMU */ switch (cause) { case EXCCAUSE_LEVEL1_INTERRUPT: - return xtensa_int1_c(interrupted_stack); + if (!is_dblexc) { + return xtensa_int1_c(interrupted_stack); + } + break; +#ifndef CONFIG_USERSPACE + /* Syscalls are handled earlier in assembly if MMU is enabled. + * So we don't need this here. + */ case EXCCAUSE_SYSCALL: /* Just report it to the console for now */ LOG_ERR(" ** SYSCALL PS %p PC %p", @@ -333,38 +330,7 @@ void *xtensa_excint1_c(int *interrupted_stack) */ bsa->pc += 3; break; -#ifdef CONFIG_XTENSA_MMU - case EXCCAUSE_ITLB_MISS: - /* Instruction TLB miss */ - __fallthrough; - case EXCCAUSE_DTLB_MISS: - /* Data TLB miss */ - - /** - * The way it works is, when we try to access an address - * that is not mapped, we will have a miss. The HW then - * will try to get the correspondent memory in the page - * table. As the page table is not mapped in memory we will - * have a second miss, which will trigger an exception. - * In the exception (here) what we do is to exploit this - * hardware capability just trying to load the page table - * (not mapped address), which will cause a miss, but then - * the hardware will automatically map it again from - * the page table. This time it will work since the page - * necessary to map the page table itself are wired map. - */ - __asm__ volatile("wsr a0, " ZSR_EXTRA0_STR "\n\t" - "rsr.ptevaddr a0\n\t" - "l32i a0, a0, 0\n\t" - "rsr a0, " ZSR_EXTRA0_STR "\n\t" - "rsync" - : : : "a0", "memory"); - - /* Since we are dealing with TLB misses, we will probably not - * want to switch to another thread. - */ - return interrupted_stack; -#endif /* CONFIG_XTENSA_MMU */ +#endif /* !CONFIG_USERSPACE */ default: ps = bsa->ps; pc = (void *)bsa->pc; @@ -373,6 +339,7 @@ void *xtensa_excint1_c(int *interrupted_stack) /* Default for exception */ int reason = K_ERR_CPU_EXCEPTION; + is_fatal_error = true; /* We need to distinguish between an ill in xtensa_arch_except, * e.g for k_panic, and any other ill. For exceptions caused by @@ -389,13 +356,19 @@ void *xtensa_excint1_c(int *interrupted_stack) reason = bsa->a2; } - LOG_ERR(" ** FATAL EXCEPTION"); + LOG_ERR(" ** FATAL EXCEPTION%s", (is_dblexc ? " (DOUBLE)" : "")); LOG_ERR(" ** CPU %d EXCCAUSE %d (%s)", arch_curr_cpu()->id, cause, z_xtensa_exccause(cause)); LOG_ERR(" ** PC %p VADDR %p", pc, (void *)vaddr); LOG_ERR(" ** PS %p", (void *)bsa->ps); + if (is_dblexc) { + LOG_ERR(" ** DEPC %p", (void *)depc); + } +#ifdef CONFIG_USERSPACE + LOG_ERR(" ** THREADPTR %p", (void *)bsa->threadptr); +#endif /* CONFIG_USERSPACE */ LOG_ERR(" ** (INTLEVEL:%d EXCM: %d UM:%d RING:%d WOE:%d OWB:%d CALLINC:%d)", get_bits(0, 4, ps), get_bits(4, 1, ps), get_bits(5, 1, ps), get_bits(6, 2, ps), @@ -412,13 +385,12 @@ void *xtensa_excint1_c(int *interrupted_stack) break; } - +#ifdef CONFIG_XTENSA_MMU switch (cause) { - case EXCCAUSE_SYSCALL: case EXCCAUSE_LEVEL1_INTERRUPT: - case EXCCAUSE_ALLOCA: - case EXCCAUSE_ITLB_MISS: - case EXCCAUSE_DTLB_MISS: +#ifndef CONFIG_USERSPACE + case EXCCAUSE_SYSCALL: +#endif /* !CONFIG_USERSPACE */ is_fatal_error = false; break; default: @@ -426,7 +398,12 @@ void *xtensa_excint1_c(int *interrupted_stack) break; } - if (is_fatal_error) { + if (is_dblexc) { + __asm__ volatile("wsr.depc %0" : : "r"(0)); + } +#endif /* CONFIG_XTENSA_MMU */ + + if (is_dblexc || is_fatal_error) { uint32_t ignore; /* We are going to manipulate _current_cpu->nested manually. From bc0656a92e0689a380e464963b92a983346df7cc Mon Sep 17 00:00:00 2001 From: Daniel Leung Date: Thu, 16 Feb 2023 11:25:48 -0800 Subject: [PATCH 0022/3723] xtensa: mmu: allocate scratch registers for MMU When MMU is enabled, we need some scratch registers to preload page table entries. So update gen_zsr.py to that. Signed-off-by: Daniel Leung Signed-off-by: Flavio Ceolin --- arch/xtensa/core/CMakeLists.txt | 1 + arch/xtensa/core/gen_zsr.py | 24 ++++++++++++++++++++---- arch/xtensa/core/xtensa-asm2-util.S | 6 +++--- arch/xtensa/include/xtensa-asm2-s.h | 8 ++++---- 4 files changed, 28 insertions(+), 11 deletions(-) diff --git a/arch/xtensa/core/CMakeLists.txt b/arch/xtensa/core/CMakeLists.txt index 8a23b65b9a9..331bcd9bfc5 100644 --- a/arch/xtensa/core/CMakeLists.txt +++ b/arch/xtensa/core/CMakeLists.txt @@ -59,6 +59,7 @@ add_custom_command(OUTPUT ${CORE_ISA_DM} set(ZSR_H ${CMAKE_BINARY_DIR}/zephyr/include/generated/zsr.h) add_custom_command(OUTPUT ${ZSR_H} DEPENDS ${CORE_ISA_DM} COMMAND ${PYTHON_EXECUTABLE} ${CMAKE_CURRENT_SOURCE_DIR}/gen_zsr.py + $<$:--mmu> ${CORE_ISA_DM} ${ZSR_H}) add_custom_target(zsr_h DEPENDS ${ZSR_H}) add_dependencies(zephyr_interface zsr_h) diff --git a/arch/xtensa/core/gen_zsr.py b/arch/xtensa/core/gen_zsr.py index 574542a4578..0e3069a4c45 100755 --- a/arch/xtensa/core/gen_zsr.py +++ b/arch/xtensa/core/gen_zsr.py @@ -1,7 +1,7 @@ #!/usr/bin/env python3 # Copyright (c) 2022 Intel corporation # SPDX-License-Identifier: Apache-2.0 -import sys +import argparse import re # Scratch register allocator. Zephyr uses multiple Xtensa SRs as @@ -11,10 +11,26 @@ # -dM") core-isa.h file for the current architecture and assigns # registers to usages. -NEEDED = ("A0SAVE", "CPU", "FLUSH") +def parse_args(): + parser = argparse.ArgumentParser(allow_abbrev=False) -coreisa = sys.argv[1] -outfile = sys.argv[2] + parser.add_argument("--mmu", action="store_true", + help="Enable scratch registers for MMU usage") + parser.add_argument("coreisa", + help="Path to preprocessed core-isa.h") + parser.add_argument("outfile", + help="Output file") + + return parser.parse_args() + +args = parse_args() + +NEEDED = ["A0SAVE", "CPU", "FLUSH"] +if args.mmu: + NEEDED += ["MMU_0", "MMU_1", "DBLEXC"] + +coreisa = args.coreisa +outfile = args.outfile syms = {} diff --git a/arch/xtensa/core/xtensa-asm2-util.S b/arch/xtensa/core/xtensa-asm2-util.S index 1ef9e5e1b4f..7dfd1d0bc92 100644 --- a/arch/xtensa/core/xtensa-asm2-util.S +++ b/arch/xtensa/core/xtensa-asm2-util.S @@ -439,14 +439,14 @@ _handle_tlb_miss_kernel: .global _DoubleExceptionVector _DoubleExceptionVector: #ifdef CONFIG_XTENSA_MMU - wsr a0, ZSR_A0SAVE + wsr a0, ZSR_DBLEXC rsync rsr.exccause a0 addi a0, a0, -EXCCAUSE_DTLB_MISS beqz a0, _handle_tlb_miss_dblexc - rsr a0, ZSR_A0SAVE + rsr a0, ZSR_DBLEXC j _Level1Vector #else @@ -482,7 +482,7 @@ _handle_tlb_miss_dblexc: rsr.ptevaddr a0 l32i a0, a0, 0 - rsr a0, ZSR_A0SAVE + rsr a0, ZSR_DBLEXC rfde #endif .popsection diff --git a/arch/xtensa/include/xtensa-asm2-s.h b/arch/xtensa/include/xtensa-asm2-s.h index a98c61db253..8c08916c8c6 100644 --- a/arch/xtensa/include/xtensa-asm2-s.h +++ b/arch/xtensa/include/xtensa-asm2-s.h @@ -558,8 +558,8 @@ _Level\LVL\()VectorHelper : _Level\LVL\()Vector: #endif #ifdef CONFIG_XTENSA_MMU - wsr.ZSR_EXTRA0 a2 - wsr.ZSR_EXTRA1 a3 + wsr.ZSR_MMU_0 a2 + wsr.ZSR_MMU_1 a3 rsync /* Calculations below will clobber registers used. @@ -579,8 +579,8 @@ _Level\LVL\()Vector: rsr.ZSR_CPU a3 PRELOAD_PTEVADDR a3, a2 - rsr.ZSR_EXTRA1 a3 - rsr.ZSR_EXTRA0 a2 + rsr.ZSR_MMU_1 a3 + rsr.ZSR_MMU_0 a2 #endif /* CONFIG_XTENSA_MMU */ addi a1, a1, -___xtensa_irq_bsa_t_SIZEOF s32i a0, a1, ___xtensa_irq_bsa_t_a0_OFFSET From e9c449a737e98c95b983a38d6855742c9f6c6d0c Mon Sep 17 00:00:00 2001 From: Daniel Leung Date: Thu, 16 Mar 2023 14:34:28 -0700 Subject: [PATCH 0023/3723] xtensa: mmu: do not fault for known exceptions There are known exceptions which are not fatal, and we need to handle them properly by returning to the fixup addresses as indicated. This adds the code necessary in the exception handler for this situation. Signed-off-by: Daniel Leung Signed-off-by: Flavio Ceolin --- arch/xtensa/core/fatal.c | 8 ------- arch/xtensa/core/xtensa-asm2.c | 38 ++++++++++++++++++++++++++++++---- 2 files changed, 34 insertions(+), 12 deletions(-) diff --git a/arch/xtensa/core/fatal.c b/arch/xtensa/core/fatal.c index 3117ebc4a56..b262a8aad4d 100644 --- a/arch/xtensa/core/fatal.c +++ b/arch/xtensa/core/fatal.c @@ -121,14 +121,6 @@ void z_xtensa_fatal_error(unsigned int reason, const z_arch_esf_t *esf) z_fatal_error(reason, esf); } -#ifdef CONFIG_USERSPACE -Z_EXC_DECLARE(z_xtensa_user_string_nlen); - -static const struct z_exc_handle exceptions[] = { - Z_EXC_HANDLE(z_xtensa_user_string_nlen) -}; -#endif /* CONFIG_USERSPACE */ - #ifdef XT_SIMULATOR void exit(int return_code) { diff --git a/arch/xtensa/core/xtensa-asm2.c b/arch/xtensa/core/xtensa-asm2.c index 3fb519cd80d..79c784f5f7d 100644 --- a/arch/xtensa/core/xtensa-asm2.c +++ b/arch/xtensa/core/xtensa-asm2.c @@ -15,11 +15,20 @@ #include #include #include +#include LOG_MODULE_DECLARE(os, CONFIG_KERNEL_LOG_LEVEL); extern char xtensa_arch_except_epc[]; +#ifdef CONFIG_USERSPACE +Z_EXC_DECLARE(z_xtensa_user_string_nlen); + +static const struct z_exc_handle exceptions[] = { + Z_EXC_HANDLE(z_xtensa_user_string_nlen) +}; +#endif /* CONFIG_USERSPACE */ + void *xtensa_init_stack(struct k_thread *thread, int *stack_top, void (*entry)(void *, void *, void *), void *arg1, void *arg2, void *arg3) @@ -335,6 +344,21 @@ void *xtensa_excint1_c(int *interrupted_stack) ps = bsa->ps; pc = (void *)bsa->pc; +#ifdef CONFIG_USERSPACE + /* If the faulting address is from one of the known + * exceptions that should not be fatal, return to + * the fixup address. + */ + for (int i = 0; i < ARRAY_SIZE(exceptions); i++) { + if ((pc >= exceptions[i].start) && + (pc < exceptions[i].end)) { + bsa->pc = (uintptr_t)exceptions[i].fixup; + + goto fixup_out; + } + } +#endif /* CONFIG_USERSPACE */ + __asm__ volatile("rsr.excvaddr %0" : "=r"(vaddr)); /* Default for exception */ @@ -397,10 +421,6 @@ void *xtensa_excint1_c(int *interrupted_stack) is_fatal_error = true; break; } - - if (is_dblexc) { - __asm__ volatile("wsr.depc %0" : : "r"(0)); - } #endif /* CONFIG_XTENSA_MMU */ if (is_dblexc || is_fatal_error) { @@ -432,6 +452,16 @@ void *xtensa_excint1_c(int *interrupted_stack) _current_cpu->nested = 1; } +#ifdef CONFIG_XTENSA_MMU +#ifdef CONFIG_USERSPACE +fixup_out: +#endif + if (is_dblexc) { + __asm__ volatile("wsr.depc %0" : : "r"(0)); + } +#endif /* CONFIG_XTENSA_MMU */ + + return return_to(interrupted_stack); } From 716efb2e405d4478dc7438e8c28ef311280e4b09 Mon Sep 17 00:00:00 2001 From: Daniel Leung Date: Wed, 12 Apr 2023 16:04:12 -0700 Subject: [PATCH 0024/3723] xtensa: extract printing of fatal exception into its own func This extracts the printing of fatal exception information into its own function to declutter xtensa_excint1_c(). Signed-off-by: Daniel Leung Signed-off-by: Flavio Ceolin --- arch/xtensa/core/xtensa-asm2.c | 65 +++++++++++++++++++--------------- 1 file changed, 37 insertions(+), 28 deletions(-) diff --git a/arch/xtensa/core/xtensa-asm2.c b/arch/xtensa/core/xtensa-asm2.c index 79c784f5f7d..92b410c46c8 100644 --- a/arch/xtensa/core/xtensa-asm2.c +++ b/arch/xtensa/core/xtensa-asm2.c @@ -202,6 +202,39 @@ static inline unsigned int get_bits(int offset, int num_bits, unsigned int val) return val & mask; } +static void print_fatal_exception(_xtensa_irq_bsa_t *bsa, int cause, + bool is_dblexc, uint32_t depc) +{ + void *pc; + uint32_t ps, vaddr; + + ps = bsa->ps; + pc = (void *)bsa->pc; + + __asm__ volatile("rsr.excvaddr %0" : "=r"(vaddr)); + + LOG_ERR(" ** FATAL EXCEPTION%s", (is_dblexc ? " (DOUBLE)" : "")); + LOG_ERR(" ** CPU %d EXCCAUSE %d (%s)", + arch_curr_cpu()->id, cause, + z_xtensa_exccause(cause)); + LOG_ERR(" ** PC %p VADDR %p", pc, (void *)vaddr); + + if (is_dblexc) { + LOG_ERR(" ** DEPC %p", (void *)depc); + } + +#ifdef CONFIG_USERSPACE + LOG_ERR(" ** THREADPTR %p", (void *)bsa->threadptr); +#endif /* CONFIG_USERSPACE */ + + LOG_ERR(" ** PS %p", (void *)bsa->ps); + LOG_ERR(" ** (INTLEVEL:%d EXCM: %d UM:%d RING:%d WOE:%d OWB:%d CALLINC:%d)", + get_bits(0, 4, ps), get_bits(4, 1, ps), + get_bits(5, 1, ps), get_bits(6, 2, ps), + get_bits(18, 1, ps), + get_bits(8, 4, ps), get_bits(16, 2, ps)); +} + static ALWAYS_INLINE void usage_stop(void) { #ifdef CONFIG_SCHED_THREAD_USAGE @@ -296,18 +329,13 @@ static inline DEF_INT_C_HANDLER(1) */ void *xtensa_excint1_c(int *interrupted_stack) { - int cause, vaddr; + int cause; _xtensa_irq_bsa_t *bsa = (void *)*(int **)interrupted_stack; bool is_fatal_error = false; + bool is_dblexc = false; uint32_t ps; void *pc; - -#ifdef CONFIG_XTENSA_MMU - bool is_dblexc; - uint32_t depc; -#else - const bool is_dblexc = false; -#endif /* CONFIG_XTENSA_MMU */ + uint32_t depc = 0; __asm__ volatile("rsr.exccause %0" : "=r"(cause)); @@ -359,8 +387,6 @@ void *xtensa_excint1_c(int *interrupted_stack) } #endif /* CONFIG_USERSPACE */ - __asm__ volatile("rsr.excvaddr %0" : "=r"(vaddr)); - /* Default for exception */ int reason = K_ERR_CPU_EXCEPTION; is_fatal_error = true; @@ -380,24 +406,7 @@ void *xtensa_excint1_c(int *interrupted_stack) reason = bsa->a2; } - LOG_ERR(" ** FATAL EXCEPTION%s", (is_dblexc ? " (DOUBLE)" : "")); - LOG_ERR(" ** CPU %d EXCCAUSE %d (%s)", - arch_curr_cpu()->id, cause, - z_xtensa_exccause(cause)); - LOG_ERR(" ** PC %p VADDR %p", - pc, (void *)vaddr); - LOG_ERR(" ** PS %p", (void *)bsa->ps); - if (is_dblexc) { - LOG_ERR(" ** DEPC %p", (void *)depc); - } -#ifdef CONFIG_USERSPACE - LOG_ERR(" ** THREADPTR %p", (void *)bsa->threadptr); -#endif /* CONFIG_USERSPACE */ - LOG_ERR(" ** (INTLEVEL:%d EXCM: %d UM:%d RING:%d WOE:%d OWB:%d CALLINC:%d)", - get_bits(0, 4, ps), get_bits(4, 1, ps), - get_bits(5, 1, ps), get_bits(6, 2, ps), - get_bits(18, 1, ps), - get_bits(8, 4, ps), get_bits(16, 2, ps)); + print_fatal_exception(bsa, cause, is_dblexc, depc); /* FIXME: legacy xtensa port reported "HW" exception * for all unhandled exceptions, which seems incorrect From 75936d8db2217e88c1e0db048c8fe00b7e855d4c Mon Sep 17 00:00:00 2001 From: Flavio Ceolin Date: Thu, 15 Dec 2022 15:05:14 -0800 Subject: [PATCH 0025/3723] xtensa: userspace: Implement arch_syscall_oops This function is needed by userspace. Signed-off-by: Flavio Ceolin --- arch/xtensa/core/fatal.c | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/arch/xtensa/core/fatal.c b/arch/xtensa/core/fatal.c index b262a8aad4d..fbf19d9df91 100644 --- a/arch/xtensa/core/fatal.c +++ b/arch/xtensa/core/fatal.c @@ -141,3 +141,11 @@ FUNC_NORETURN void z_system_halt(unsigned int reason) CODE_UNREACHABLE; } #endif + +FUNC_NORETURN void arch_syscall_oops(void *ssf) +{ + z_arch_esf_t *esf = ssf; + + z_xtensa_fatal_error(K_ERR_KERNEL_OOPS, esf); + CODE_UNREACHABLE; +} From 586bb920492ef89717fd71c8d9635452a30de908 Mon Sep 17 00:00:00 2001 From: Flavio Ceolin Date: Wed, 8 Feb 2023 13:35:18 -0800 Subject: [PATCH 0026/3723] xtensa: userspace: Add syscall for user exception Trigger exception on Xtensa requires kernel privileges. Add a new syscall that is used when ARCH_EXCEPT is invoked from userspace. Signed-off-by: Flavio Ceolin --- arch/xtensa/CMakeLists.txt | 1 + arch/xtensa/core/fatal.c | 21 +++++++++++++++++++++ include/zephyr/arch/xtensa/arch.h | 21 +++++++++++++++++++++ 3 files changed, 43 insertions(+) diff --git a/arch/xtensa/CMakeLists.txt b/arch/xtensa/CMakeLists.txt index 133d74331d8..4626421f11a 100644 --- a/arch/xtensa/CMakeLists.txt +++ b/arch/xtensa/CMakeLists.txt @@ -1,4 +1,5 @@ # SPDX-License-Identifier: Apache-2.0 +zephyr_syscall_header(${ZEPHYR_BASE}/include/zephyr/arch/xtensa/arch.h) set_property(GLOBAL PROPERTY PROPERTY_OUTPUT_FORMAT elf32-xtensa-le) add_subdirectory(core) diff --git a/arch/xtensa/core/fatal.c b/arch/xtensa/core/fatal.c index fbf19d9df91..307f4b6ff1d 100644 --- a/arch/xtensa/core/fatal.c +++ b/arch/xtensa/core/fatal.c @@ -149,3 +149,24 @@ FUNC_NORETURN void arch_syscall_oops(void *ssf) z_xtensa_fatal_error(K_ERR_KERNEL_OOPS, esf); CODE_UNREACHABLE; } + +#ifdef CONFIG_USERSPACE +void z_impl_xtensa_user_fault(unsigned int reason) +{ + if ((_current->base.user_options & K_USER) != 0) { + if ((reason != K_ERR_KERNEL_OOPS) && + (reason != K_ERR_STACK_CHK_FAIL)) { + reason = K_ERR_KERNEL_OOPS; + } + } + xtensa_arch_except(reason); +} + +static void z_vrfy_xtensa_user_fault(unsigned int reason) +{ + z_impl_xtensa_user_fault(reason); +} + +#include + +#endif /* CONFIG_USERSPACE */ diff --git a/include/zephyr/arch/xtensa/arch.h b/include/zephyr/arch/xtensa/arch.h index 9f2fb757a11..16bfd08091a 100644 --- a/include/zephyr/arch/xtensa/arch.h +++ b/include/zephyr/arch/xtensa/arch.h @@ -23,6 +23,7 @@ #include #include #include +#include #include #include #include @@ -54,11 +55,31 @@ struct arch_mem_domain { extern void xtensa_arch_except(int reason_p); +#ifdef CONFIG_USERSPACE + +#define ARCH_EXCEPT(reason_p) do { \ + if (k_is_user_context()) { \ + arch_syscall_invoke1(reason_p, \ + K_SYSCALL_XTENSA_USER_FAULT); \ + } else { \ + xtensa_arch_except(reason_p); \ + } \ + CODE_UNREACHABLE; \ +} while (false) + +#else + #define ARCH_EXCEPT(reason_p) do { \ xtensa_arch_except(reason_p); \ CODE_UNREACHABLE; \ } while (false) +#endif + +__syscall void xtensa_user_fault(unsigned int reason); + +#include + /* internal routine documented in C file, needed by IRQ_CONNECT() macro */ extern void z_irq_priority_set(uint32_t irq, uint32_t prio, uint32_t flags); From eb546a8d877fdfbaaad8935e414f95cb5ca15555 Mon Sep 17 00:00:00 2001 From: Daniel Leung Date: Wed, 12 Apr 2023 15:42:38 -0700 Subject: [PATCH 0027/3723] xtensa: rework kernel oops exception path When kernel OOPS is raised, we need to actually go through the process of terminating the offending thread, instead of simply printing the stack and continue running. This change employs similar mechanism to xtensa_arch_except() to use illegal instruction to raise hardware exception, and going through the fatal exception path. Signed-off-by: Daniel Leung Signed-off-by: Flavio Ceolin --- arch/xtensa/core/fatal.c | 8 ++++--- arch/xtensa/core/xtensa-asm2-util.S | 14 +++++++++++ arch/xtensa/core/xtensa-asm2.c | 36 ++++++++++++++++++++++------- include/zephyr/arch/xtensa/arch.h | 1 + 4 files changed, 48 insertions(+), 11 deletions(-) diff --git a/arch/xtensa/core/fatal.c b/arch/xtensa/core/fatal.c index 307f4b6ff1d..79a24baa105 100644 --- a/arch/xtensa/core/fatal.c +++ b/arch/xtensa/core/fatal.c @@ -87,6 +87,8 @@ char *z_xtensa_exccause(unsigned int cause_code) case 63: /* i.e. z_except_reason */ return "zephyr exception"; + case 64: + return "kernel oops"; default: return "unknown/reserved"; } @@ -114,7 +116,6 @@ void z_xtensa_fatal_error(unsigned int reason, const z_arch_esf_t *esf) z_xtensa_backtrace_print(100, (int *)esf); #endif #endif - arch_irq_unlock(key); } @@ -144,9 +145,10 @@ FUNC_NORETURN void z_system_halt(unsigned int reason) FUNC_NORETURN void arch_syscall_oops(void *ssf) { - z_arch_esf_t *esf = ssf; + ARG_UNUSED(ssf); + + xtensa_arch_kernel_oops(K_ERR_KERNEL_OOPS, ssf); - z_xtensa_fatal_error(K_ERR_KERNEL_OOPS, esf); CODE_UNREACHABLE; } diff --git a/arch/xtensa/core/xtensa-asm2-util.S b/arch/xtensa/core/xtensa-asm2-util.S index 7dfd1d0bc92..4f8af894ccb 100644 --- a/arch/xtensa/core/xtensa-asm2-util.S +++ b/arch/xtensa/core/xtensa-asm2-util.S @@ -204,6 +204,20 @@ xtensa_arch_except_epc: ill retw +/* + * void xtensa_arch_kernel_oops(int reason_p, void *ssf); + * + * Simply to raise hardware exception for Kernel OOPS. + */ +.global xtensa_arch_kernel_oops +.global xtensa_arch_kernel_oops_epc +.align 4 +xtensa_arch_kernel_oops: + entry a1, 16 +xtensa_arch_kernel_oops_epc: + ill + retw + /* * void xtensa_switch(void *new, void **old_return); * diff --git a/arch/xtensa/core/xtensa-asm2.c b/arch/xtensa/core/xtensa-asm2.c index 92b410c46c8..ed8f340f1bc 100644 --- a/arch/xtensa/core/xtensa-asm2.c +++ b/arch/xtensa/core/xtensa-asm2.c @@ -20,6 +20,7 @@ LOG_MODULE_DECLARE(os, CONFIG_KERNEL_LOG_LEVEL); extern char xtensa_arch_except_epc[]; +extern char xtensa_arch_kernel_oops_epc[]; #ifdef CONFIG_USERSPACE Z_EXC_DECLARE(z_xtensa_user_string_nlen); @@ -202,11 +203,12 @@ static inline unsigned int get_bits(int offset, int num_bits, unsigned int val) return val & mask; } -static void print_fatal_exception(_xtensa_irq_bsa_t *bsa, int cause, +static void print_fatal_exception(void *print_stack, int cause, bool is_dblexc, uint32_t depc) { void *pc; uint32_t ps, vaddr; + _xtensa_irq_bsa_t *bsa = (void *)*(int **)print_stack; ps = bsa->ps; pc = (void *)bsa->pc; @@ -334,7 +336,7 @@ void *xtensa_excint1_c(int *interrupted_stack) bool is_fatal_error = false; bool is_dblexc = false; uint32_t ps; - void *pc; + void *pc, *print_stack = (void *)interrupted_stack; uint32_t depc = 0; __asm__ volatile("rsr.exccause %0" : "=r"(cause)); @@ -399,14 +401,32 @@ void *xtensa_excint1_c(int *interrupted_stack) * We assign EXCCAUSE the unused, reserved code 63; this may be * problematic if the app or new boards also decide to repurpose * this code. + * + * Another intentionally ill is from xtensa_arch_kernel_oops. + * Kernel OOPS has to be explicity raised so we can simply + * set the reason and continue. */ - if ((pc == (void *) &xtensa_arch_except_epc) && (cause == 0)) { - cause = 63; - __asm__ volatile("wsr.exccause %0" : : "r"(cause)); - reason = bsa->a2; + if (cause == EXCCAUSE_ILLEGAL) { + if (pc == (void *)&xtensa_arch_except_epc) { + cause = 63; + __asm__ volatile("wsr.exccause %0" : : "r"(cause)); + reason = bsa->a2; + } else if (pc == (void *)&xtensa_arch_kernel_oops_epc) { + cause = 64; /* kernel oops */ + reason = K_ERR_KERNEL_OOPS; + + /* A3 contains the second argument to + * xtensa_arch_kernel_oops(reason, ssf) + * where ssf is the stack frame causing + * the kernel oops. + */ + print_stack = (void *)bsa->a3; + } } - print_fatal_exception(bsa, cause, is_dblexc, depc); + if (reason != K_ERR_KERNEL_OOPS) { + print_fatal_exception(print_stack, cause, is_dblexc, depc); + } /* FIXME: legacy xtensa port reported "HW" exception * for all unhandled exceptions, which seems incorrect @@ -414,7 +434,7 @@ void *xtensa_excint1_c(int *interrupted_stack) * up. */ z_xtensa_fatal_error(reason, - (void *)interrupted_stack); + (void *)print_stack); break; } diff --git a/include/zephyr/arch/xtensa/arch.h b/include/zephyr/arch/xtensa/arch.h index 16bfd08091a..d486bb4d7b6 100644 --- a/include/zephyr/arch/xtensa/arch.h +++ b/include/zephyr/arch/xtensa/arch.h @@ -54,6 +54,7 @@ struct arch_mem_domain { }; extern void xtensa_arch_except(int reason_p); +extern void xtensa_arch_kernel_oops(int reason_p, void *ssf); #ifdef CONFIG_USERSPACE From 81ea43692cf855c4ee5af2cd828eafe3785e889b Mon Sep 17 00:00:00 2001 From: Daniel Leung Date: Thu, 16 Mar 2023 20:27:47 -0700 Subject: [PATCH 0028/3723] xtensa: mmu: send IPI to invalidate TLBs on other CPUs After changing content of page table(s), it is needed to notify the other CPUs that the page table(s) have been changed so they can do the necessary steps to use the updated version. Note that the actual way to send IPI is SoC specific as Xtensa does not have a common way to do this at the moment. Signed-off-by: Daniel Leung --- arch/xtensa/core/xtensa_mmu.c | 79 +++++++++++++++++++++++++ include/zephyr/arch/xtensa/xtensa_mmu.h | 20 +++++++ 2 files changed, 99 insertions(+) diff --git a/arch/xtensa/core/xtensa_mmu.c b/arch/xtensa/core/xtensa_mmu.c index 915a26357eb..8a2dcab7ee8 100644 --- a/arch/xtensa/core/xtensa_mmu.c +++ b/arch/xtensa/core/xtensa_mmu.c @@ -659,6 +659,10 @@ void arch_mem_map(void *virt, uintptr_t phys, size_t size, uint32_t flags) pa += KB(4); } +#if CONFIG_MP_MAX_NUM_CPUS > 1 + z_xtensa_mmu_tlb_ipi(); +#endif + k_spin_unlock(&xtensa_mmu_lock, key); } @@ -791,9 +795,80 @@ void arch_mem_unmap(void *addr, size_t size) va += KB(4); } +#if CONFIG_MP_MAX_NUM_CPUS > 1 + z_xtensa_mmu_tlb_ipi(); +#endif + k_spin_unlock(&xtensa_mmu_lock, key); } +/* This should be implemented in the SoC layer. + * This weak version is here to avoid build errors. + */ +void __weak z_xtensa_mmu_tlb_ipi(void) +{ +} + +void z_xtensa_mmu_tlb_shootdown(void) +{ + unsigned int key; + + /* Need to lock interrupts to prevent any context + * switching until all the page tables are updated. + * Or else we would be switching to another thread + * and running that with incorrect page tables + * which would result in permission issues. + */ + key = arch_irq_lock(); + + /* We don't have information on which page tables have changed, + * so we just invalidate the cache for all L1 page tables. + */ + sys_cache_data_invd_range((void *)l1_page_table, sizeof(l1_page_table)); + sys_cache_data_invd_range((void *)l2_page_tables, sizeof(l2_page_tables)); + +#ifdef CONFIG_USERSPACE + struct k_thread *thread = _current_cpu->current; + + /* If current thread is a user thread, we need to see if it has + * been migrated to another memory domain as the L1 page table + * is different from the currently used one. + */ + if ((thread->base.user_options & K_USER) == K_USER) { + uint32_t ptevaddr_entry, ptevaddr, thread_ptables; + + /* Need to read the currently used L1 page table. + * We know that L1 page table is always mapped at way + * MMU_PTE_WAY, so we can skip the probing step by + * generating the query entry directly. + */ + ptevaddr_entry = Z_XTENSA_PAGE_TABLE_VADDR | MMU_PTE_WAY; + ptevaddr = xtensa_dtlb_paddr_read(ptevaddr_entry); + + thread_ptables = (uint32_t)thread->arch.ptables; + + if (thread_ptables != ptevaddr) { + /* Need to remap the thread page tables if the ones + * indicated by the current thread are different + * than the current mapped page table. + */ + switch_page_tables((uint32_t *)thread_ptables, false, false); + } + + } +#endif /* CONFIG_USERSPACE */ + + /* L2 are done via autofill, so invalidate autofill TLBs + * would refresh the L2 page tables. + * + * L1 will be refreshed during context switch so no need + * to do anything here. + */ + xtensa_tlb_autorefill_invalidate(); + + arch_irq_unlock(key); +} + #ifdef CONFIG_USERSPACE static inline uint32_t *alloc_l1_table(void) @@ -951,6 +1026,10 @@ static inline int update_region(uint32_t *ptables, uintptr_t start, ret = region_map_update(ptables, start, size, ring, flags); #endif /* CONFIG_XTENSA_MMU_DOUBLE_MAP */ +#if CONFIG_MP_MAX_NUM_CPUS > 1 + z_xtensa_mmu_tlb_ipi(); +#endif + k_spin_unlock(&xtensa_mmu_lock, key); return ret; diff --git a/include/zephyr/arch/xtensa/xtensa_mmu.h b/include/zephyr/arch/xtensa/xtensa_mmu.h index 40fd0ff8f5c..aa00f935a8a 100644 --- a/include/zephyr/arch/xtensa/xtensa_mmu.h +++ b/include/zephyr/arch/xtensa/xtensa_mmu.h @@ -60,4 +60,24 @@ extern int xtensa_soc_mmu_ranges_num; void z_xtensa_mmu_init(void); +/** + * @brief Tell other processors to flush TLBs. + * + * This sends IPI to other processors to telling them to + * invalidate cache to page tables and flush TLBs. This is + * needed when one processor is updating page tables that + * may affect threads running on other processors. + * + * @note This needs to be implemented in the SoC layer. + */ +void z_xtensa_mmu_tlb_ipi(void); + +/** + * @brief Invalidate cache to page tables and flush TLBs. + * + * This invalidates cache to all page tables and flush TLBs + * as they may have been modified by other processors. + */ +void z_xtensa_mmu_tlb_shootdown(void); + #endif /* ZEPHYR_INCLUDE_ARCH_XTENSA_XTENSA_MMU_H */ From c9c88a4368f5d23a513d1f6391f9a760c90066b7 Mon Sep 17 00:00:00 2001 From: Daniel Leung Date: Mon, 27 Mar 2023 16:27:34 -0700 Subject: [PATCH 0029/3723] xtensa: mmu: cache and TLB actions when adding thread to domain When adding a thread to a memory domain, we need to also update the mapped page table if it is the current running thread on the same CPU. If it's not on the same CPU, we need to notify the other CPUs in case the thread is running in one of them. Signed-off-by: Daniel Leung Signed-off-by: Anas Nashif Signed-off-by: Flavio Ceolin --- arch/xtensa/core/xtensa_mmu.c | 80 +++++++++++++++++++++++------------ 1 file changed, 53 insertions(+), 27 deletions(-) diff --git a/arch/xtensa/core/xtensa_mmu.c b/arch/xtensa/core/xtensa_mmu.c index 8a2dcab7ee8..ef0020a76c6 100644 --- a/arch/xtensa/core/xtensa_mmu.c +++ b/arch/xtensa/core/xtensa_mmu.c @@ -16,6 +16,12 @@ #include #include +/* Skip TLB IPI when updating page tables. + * This allows us to send IPI only after the last + * changes of a series. + */ +#define OPTION_NO_TLB_IPI BIT(0) + /* Level 1 contains page table entries * necessary to map the page table itself. */ @@ -995,7 +1001,8 @@ static int region_map_update(uint32_t *ptables, uintptr_t start, } static inline int update_region(uint32_t *ptables, uintptr_t start, - size_t size, uint32_t ring, uint32_t flags) + size_t size, uint32_t ring, uint32_t flags, + uint32_t option) { int ret; k_spinlock_key_t key; @@ -1027,7 +1034,9 @@ static inline int update_region(uint32_t *ptables, uintptr_t start, #endif /* CONFIG_XTENSA_MMU_DOUBLE_MAP */ #if CONFIG_MP_MAX_NUM_CPUS > 1 - z_xtensa_mmu_tlb_ipi(); + if ((option & OPTION_NO_TLB_IPI) != OPTION_NO_TLB_IPI) { + z_xtensa_mmu_tlb_ipi(); + } #endif k_spin_unlock(&xtensa_mmu_lock, key); @@ -1035,20 +1044,9 @@ static inline int update_region(uint32_t *ptables, uintptr_t start, return ret; } -static inline int reset_region(uint32_t *ptables, uintptr_t start, size_t size) +static inline int reset_region(uint32_t *ptables, uintptr_t start, size_t size, uint32_t option) { - return update_region(ptables, start, size, Z_XTENSA_KERNEL_RING, Z_XTENSA_MMU_W); -} - -void xtensa_set_stack_perms(struct k_thread *thread) -{ - if ((thread->base.user_options & K_USER) == 0) { - return; - } - - update_region(thread_page_tables_get(thread), - thread->stack_info.start, thread->stack_info.size, - Z_XTENSA_USER_RING, Z_XTENSA_MMU_W | Z_XTENSA_MMU_CACHED_WB); + return update_region(ptables, start, size, Z_XTENSA_KERNEL_RING, Z_XTENSA_MMU_W, option); } void xtensa_user_stack_perms(struct k_thread *thread) @@ -1058,7 +1056,7 @@ void xtensa_user_stack_perms(struct k_thread *thread) update_region(thread_page_tables_get(thread), thread->stack_info.start, thread->stack_info.size, - Z_XTENSA_USER_RING, Z_XTENSA_MMU_W | Z_XTENSA_MMU_CACHED_WB); + Z_XTENSA_USER_RING, Z_XTENSA_MMU_W | Z_XTENSA_MMU_CACHED_WB, 0); } int arch_mem_domain_max_partitions_get(void) @@ -1073,7 +1071,7 @@ int arch_mem_domain_partition_remove(struct k_mem_domain *domain, /* Reset the partition's region back to defaults */ return reset_region(domain->arch.ptables, partition->start, - partition->size); + partition->size, 0); } int arch_mem_domain_partition_add(struct k_mem_domain *domain, @@ -1083,7 +1081,7 @@ int arch_mem_domain_partition_add(struct k_mem_domain *domain, struct k_mem_partition *partition = &domain->partitions[partition_id]; return update_region(domain->arch.ptables, partition->start, - partition->size, ring, partition->attr); + partition->size, ring, partition->attr, 0); } /* These APIs don't need to do anything */ @@ -1101,19 +1099,42 @@ int arch_mem_domain_thread_add(struct k_thread *thread) is_user = (thread->base.user_options & K_USER) != 0; is_migration = (old_ptables != NULL) && is_user; - /* Give access to the thread's stack in its new - * memory domain if it is migrating. - */ - if (is_migration) { - xtensa_set_stack_perms(thread); - } - if (is_migration) { + /* Give access to the thread's stack in its new + * memory domain if it is migrating. + */ + update_region(thread_page_tables_get(thread), + thread->stack_info.start, thread->stack_info.size, + Z_XTENSA_USER_RING, + Z_XTENSA_MMU_W | Z_XTENSA_MMU_CACHED_WB, + OPTION_NO_TLB_IPI); + /* and reset thread's stack permission in + * the old page tables. + */ ret = reset_region(old_ptables, thread->stack_info.start, - thread->stack_info.size); + thread->stack_info.size, 0); + } + + /* Need to switch to new page tables if this is + * the current thread running. + */ + if (thread == _current_cpu->current) { + switch_page_tables(thread->arch.ptables, true, true); } +#if CONFIG_MP_MAX_NUM_CPUS > 1 + /* Need to tell other CPUs to switch to the new page table + * in case the thread is running on one of them. + * + * Note that there is no need to send TLB IPI if this is + * migration as it was sent above during reset_region(). + */ + if ((thread != _current_cpu->current) && !is_migration) { + z_xtensa_mmu_tlb_ipi(); + } +#endif + return ret; } @@ -1136,10 +1157,15 @@ int arch_mem_domain_thread_remove(struct k_thread *thread) /* Restore permissions on the thread's stack area since it is no * longer a member of the domain. + * + * Note that, since every thread must have an associated memory + * domain, removing a thread from domain will be followed by + * adding it back to another. So there is no need to send TLB IPI + * at this point. */ return reset_region(domain->arch.ptables, thread->stack_info.start, - thread->stack_info.size); + thread->stack_info.size, OPTION_NO_TLB_IPI); } static bool page_validate(uint32_t *ptables, uint32_t page, uint8_t ring, bool write) From 7a5d2a2d8146223f40428578b2a2924a01053367 Mon Sep 17 00:00:00 2001 From: Daniel Leung Date: Wed, 6 Sep 2023 11:26:41 -0700 Subject: [PATCH 0030/3723] xtensa: userspace: swap page tables at context restore Swap page tables at exit of exception handler if we are going to be restored to another thread context. Or else we would be using the outgoing thread's page tables which is not going to work correctly due to mapping and permissions. Signed-off-by: Daniel Leung --- arch/xtensa/include/xtensa-asm2-s.h | 32 +++++++++++++++++++++++++++++ 1 file changed, 32 insertions(+) diff --git a/arch/xtensa/include/xtensa-asm2-s.h b/arch/xtensa/include/xtensa-asm2-s.h index 8c08916c8c6..3f3ffd90b7a 100644 --- a/arch/xtensa/include/xtensa-asm2-s.h +++ b/arch/xtensa/include/xtensa-asm2-s.h @@ -507,6 +507,8 @@ _do_call_\@: * spills to the right place. */ beq a6, a1, _restore_\@ + +#ifndef CONFIG_USERSPACE l32i a1, a1, 0 l32i a0, a1, ___xtensa_irq_bsa_t_a0_OFFSET addi a1, a1, ___xtensa_irq_bsa_t_SIZEOF @@ -516,7 +518,37 @@ _do_call_\@: */ SPILL_ALL_WINDOWS #endif + + /* Restore A1 stack pointer from "next" handle. */ mov a1, a6 +#else + /* With userspace, we cannot simply restore A1 stack pointer + * at this pointer because we need to swap page tables to + * the incoming thread, and we do not want to call that + * function with thread's stack. So we stash the new stack + * pointer into A2 first, then move it to A1 after we have + * swapped the page table. + */ + mov a2, a6 + + /* Need to switch page tables because the "next" handle + * returned above is not the same handle as we started + * with. This means we are being restored to another + * thread. + */ + rsr a6, ZSR_CPU + l32i a6, a6, ___cpu_t_current_OFFSET + + call4 z_xtensa_swap_update_page_tables + l32i a1, a1, 0 + l32i a0, a1, ___xtensa_irq_bsa_t_a0_OFFSET + addi a1, a1, ___xtensa_irq_bsa_t_SIZEOF + + SPILL_ALL_WINDOWS + + /* Moved stashed stack pointer to A1 to restore stack. */ + mov a1, a2 +#endif _restore_\@: j _restore_context From be5eccdd15522e33d4b7bf588bf142b76da8bead Mon Sep 17 00:00:00 2001 From: Flavio Ceolin Date: Thu, 19 Jan 2023 10:05:43 -0800 Subject: [PATCH 0031/3723] tests: userspace: Add xtensa support This test requires architecture specific code to work. Signed-off-by: Flavio Ceolin Signed-off-by: Daniel Leung --- tests/kernel/mem_protect/userspace/src/main.c | 35 +++++++++++++++++-- 1 file changed, 33 insertions(+), 2 deletions(-) diff --git a/tests/kernel/mem_protect/userspace/src/main.c b/tests/kernel/mem_protect/userspace/src/main.c index 1c0e7d3ef21..bcf504102db 100644 --- a/tests/kernel/mem_protect/userspace/src/main.c +++ b/tests/kernel/mem_protect/userspace/src/main.c @@ -20,6 +20,11 @@ #include "test_syscall.h" #include /* for z_libc_partition */ +#if defined(CONFIG_XTENSA) +#include +#include +#endif + #if defined(CONFIG_ARC) #include #endif @@ -178,6 +183,12 @@ ZTEST_USER(userspace, test_write_control) set_fault(K_ERR_CPU_EXCEPTION); __asm__ volatile("csrr %0, mstatus" : "=r" (status)); +#elif defined(CONFIG_XTENSA) + unsigned int ps; + + set_fault(K_ERR_CPU_EXCEPTION); + + __asm__ volatile("rsr.ps %0" : "=r" (ps)); #else #error "Not implemented for this architecture" zassert_unreachable("Write to control register did not fault"); @@ -245,6 +256,24 @@ ZTEST_USER(userspace, test_disable_mmu_mpu) */ csr_write(pmpaddr3, LLONG_MAX); csr_write(pmpcfg0, (PMP_R|PMP_W|PMP_X|PMP_NAPOT) << 24); +#elif defined(CONFIG_XTENSA) + set_fault(K_ERR_CPU_EXCEPTION); + + /* Reset way 6 to do identity mapping. + * Complier would complain addr going out of range if we + * simply do addr = i * 0x20000000 inside the loop. So + * we do increment instead. + */ + uint32_t addr = 0U; + + for (int i = 0; i < 8; i++) { + uint32_t attr = addr | Z_XTENSA_MMU_XW; + + __asm__ volatile("wdtlb %0, %1; witlb %0, %1" + :: "r"(attr), "r"(addr)); + + addr += 0x20000000; + } #else #error "Not implemented for this architecture" #endif @@ -381,7 +410,8 @@ ZTEST_USER(userspace, test_read_priv_stack) s[0] = 0; priv_stack_ptr = (char *)&s[0] - size; -#elif defined(CONFIG_ARM) || defined(CONFIG_X86) || defined(CONFIG_RISCV) || defined(CONFIG_ARM64) +#elif defined(CONFIG_ARM) || defined(CONFIG_X86) || defined(CONFIG_RISCV) || \ + defined(CONFIG_ARM64) || defined(CONFIG_XTENSA) /* priv_stack_ptr set by test_main() */ #else #error "Not implemented for this architecture" @@ -405,7 +435,8 @@ ZTEST_USER(userspace, test_write_priv_stack) s[0] = 0; priv_stack_ptr = (char *)&s[0] - size; -#elif defined(CONFIG_ARM) || defined(CONFIG_X86) || defined(CONFIG_RISCV) || defined(CONFIG_ARM64) +#elif defined(CONFIG_ARM) || defined(CONFIG_X86) || defined(CONFIG_RISCV) || \ + defined(CONFIG_ARM64) || defined(CONFIG_XTENSA) /* priv_stack_ptr set by test_main() */ #else #error "Not implemented for this architecture" From 6c6894c8d8afea3817c7679845942c488563a5c4 Mon Sep 17 00:00:00 2001 From: Daniel Leung Date: Tue, 31 Jan 2023 15:35:15 -0800 Subject: [PATCH 0032/3723] tests: mem_protect: enable for Xtensa This enables tests/kernel/mem_protect/mem_protect to be tested on Xtensa. Signed-off-by: Daniel Leung Signed-off-by: Flavio Ceolin --- tests/kernel/mem_protect/mem_protect/src/mem_protect.h | 2 ++ 1 file changed, 2 insertions(+) diff --git a/tests/kernel/mem_protect/mem_protect/src/mem_protect.h b/tests/kernel/mem_protect/mem_protect/src/mem_protect.h index ef0ba48a519..4d5400bb1d6 100644 --- a/tests/kernel/mem_protect/mem_protect/src/mem_protect.h +++ b/tests/kernel/mem_protect/mem_protect/src/mem_protect.h @@ -67,6 +67,8 @@ static inline void set_fault_valid(bool valid) #else #define MEM_REGION_ALLOC (4) #endif +#elif defined(CONFIG_XTENSA) +#define MEM_REGION_ALLOC (4096) #else #error "Test suite not compatible for the given architecture" #endif From 156f1d443623aa443851fce73848ef42ba05890e Mon Sep 17 00:00:00 2001 From: Flavio Ceolin Date: Fri, 2 Jun 2023 22:36:14 -0700 Subject: [PATCH 0033/3723] xtensa: mmu: Flush cache when altering pages When the target has a cache way size (cache size / cache wasy) bigger than the page size we have cache aliasing, since the number of bits required by the cache index is bigger than the number of bits in the page offset. To avoid this problem we flush the whole cache on context switch or when the current page table is changed. Signed-off-by: Flavio Ceolin --- arch/xtensa/core/xtensa_mmu.c | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/arch/xtensa/core/xtensa_mmu.c b/arch/xtensa/core/xtensa_mmu.c index ef0020a76c6..74ced424210 100644 --- a/arch/xtensa/core/xtensa_mmu.c +++ b/arch/xtensa/core/xtensa_mmu.c @@ -231,8 +231,7 @@ static inline uint32_t *alloc_l2_table(void) static ALWAYS_INLINE void switch_page_tables(uint32_t *ptables, bool dtlb_inv, bool cache_inv) { if (cache_inv) { - sys_cache_data_invd_range((void *)ptables, XTENSA_L1_PAGE_TABLE_SIZE); - sys_cache_data_invd_range((void *)l2_page_tables, sizeof(l2_page_tables)); + sys_cache_data_flush_and_invd_all(); } /* Invalidate data TLB to L1 page table */ @@ -669,6 +668,7 @@ void arch_mem_map(void *virt, uintptr_t phys, size_t size, uint32_t flags) z_xtensa_mmu_tlb_ipi(); #endif + sys_cache_data_flush_and_invd_all(); k_spin_unlock(&xtensa_mmu_lock, key); } @@ -805,6 +805,7 @@ void arch_mem_unmap(void *addr, size_t size) z_xtensa_mmu_tlb_ipi(); #endif + sys_cache_data_flush_and_invd_all(); k_spin_unlock(&xtensa_mmu_lock, key); } @@ -858,7 +859,7 @@ void z_xtensa_mmu_tlb_shootdown(void) * indicated by the current thread are different * than the current mapped page table. */ - switch_page_tables((uint32_t *)thread_ptables, false, false); + switch_page_tables((uint32_t *)thread_ptables, true, true); } } @@ -1039,6 +1040,7 @@ static inline int update_region(uint32_t *ptables, uintptr_t start, } #endif + sys_cache_data_flush_and_invd_all(); k_spin_unlock(&xtensa_mmu_lock, key); return ret; From 9a33c400a164ba77f7b644ad8c6d3b51cb527108 Mon Sep 17 00:00:00 2001 From: Flavio Ceolin Date: Tue, 29 Aug 2023 10:08:27 -0700 Subject: [PATCH 0034/3723] xtensa: mmu: Fix possible race condition on tlb shootdown We need to use the mmu spin lock when invalidating the cache during tlb shootdown, otherwise it is possible that this happens when another thread is updating the page tables. Signed-off-by: Flavio Ceolin Signed-off-by: Anas Nashif --- arch/xtensa/core/xtensa_mmu.c | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) diff --git a/arch/xtensa/core/xtensa_mmu.c b/arch/xtensa/core/xtensa_mmu.c index 74ced424210..1c120d5eb31 100644 --- a/arch/xtensa/core/xtensa_mmu.c +++ b/arch/xtensa/core/xtensa_mmu.c @@ -828,11 +828,13 @@ void z_xtensa_mmu_tlb_shootdown(void) */ key = arch_irq_lock(); - /* We don't have information on which page tables have changed, - * so we just invalidate the cache for all L1 page tables. - */ - sys_cache_data_invd_range((void *)l1_page_table, sizeof(l1_page_table)); - sys_cache_data_invd_range((void *)l2_page_tables, sizeof(l2_page_tables)); + K_SPINLOCK(&xtensa_mmu_lock) { + /* We don't have information on which page tables have changed, + * so we just invalidate the cache for all L1 page tables. + */ + sys_cache_data_invd_range((void *)l1_page_table, sizeof(l1_page_table)); + sys_cache_data_invd_range((void *)l2_page_tables, sizeof(l2_page_tables)); + } #ifdef CONFIG_USERSPACE struct k_thread *thread = _current_cpu->current; From d9f643d007b65ee24ad3872427c9dca3180f6629 Mon Sep 17 00:00:00 2001 From: Daniel Leung Date: Tue, 29 Aug 2023 10:49:56 -0700 Subject: [PATCH 0035/3723] xtensa: mmu: do not map heap if not using heap Do not map the heap area by default if we are not using heap at all. Signed-off-by: Daniel Leung --- arch/xtensa/core/xtensa_mmu.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/arch/xtensa/core/xtensa_mmu.c b/arch/xtensa/core/xtensa_mmu.c index 1c120d5eb31..eba89c970ad 100644 --- a/arch/xtensa/core/xtensa_mmu.c +++ b/arch/xtensa/core/xtensa_mmu.c @@ -133,6 +133,7 @@ static const struct xtensa_mmu_range mmu_zephyr_ranges[] = { #endif .name = "data", }, +#if CONFIG_HEAP_MEM_POOL_SIZE > 0 /* System heap memory */ { .start = (uint32_t)_heap_start, @@ -144,6 +145,7 @@ static const struct xtensa_mmu_range mmu_zephyr_ranges[] = { #endif .name = "heap", }, +#endif /* Mark text segment cacheable, read only and executable */ { .start = (uint32_t)__text_region_start, From 6252fcfccfae49fa18beee1b1bec0f57b4e37a0a Mon Sep 17 00:00:00 2001 From: Daniel Leung Date: Tue, 29 Aug 2023 12:07:19 -0700 Subject: [PATCH 0036/3723] xtensa: userspace: simplify syscall helper Consolidate all syscall helpers into one functions. Signed-off-by: Daniel Leung --- arch/xtensa/core/syscall_helper.c | 103 ++------------------------- include/zephyr/arch/xtensa/syscall.h | 62 ++++++---------- 2 files changed, 27 insertions(+), 138 deletions(-) diff --git a/arch/xtensa/core/syscall_helper.c b/arch/xtensa/core/syscall_helper.c index fbbdf104191..f8fb7ec903e 100644 --- a/arch/xtensa/core/syscall_helper.c +++ b/arch/xtensa/core/syscall_helper.c @@ -6,10 +6,10 @@ #include -uintptr_t arch_syscall_invoke6_helper(uintptr_t arg1, uintptr_t arg2, - uintptr_t arg3, uintptr_t arg4, - uintptr_t arg5, uintptr_t arg6, - uintptr_t call_id) +uintptr_t xtensa_syscall_helper(uintptr_t arg1, uintptr_t arg2, + uintptr_t arg3, uintptr_t arg4, + uintptr_t arg5, uintptr_t arg6, + uintptr_t call_id) { register uintptr_t a2 __asm__("%a2") = call_id; register uintptr_t a6 __asm__("%a6") = arg1; @@ -27,98 +27,3 @@ uintptr_t arch_syscall_invoke6_helper(uintptr_t arg1, uintptr_t arg2, return a2; } - -uintptr_t arch_syscall_invoke5_helper(uintptr_t arg1, uintptr_t arg2, - uintptr_t arg3, uintptr_t arg4, - uintptr_t arg5, uintptr_t call_id) -{ - register uintptr_t a2 __asm__("%a2") = call_id; - register uintptr_t a6 __asm__("%a6") = arg1; - register uintptr_t a3 __asm__("%a3") = arg2; - register uintptr_t a4 __asm__("%a4") = arg3; - register uintptr_t a5 __asm__("%a5") = arg4; - register uintptr_t a8 __asm__("%a8") = arg5; - - __asm__ volatile("syscall\n\t" - : "=r" (a2) - : "r" (a2), "r" (a6), "r" (a3), "r" (a4), - "r" (a5), "r" (a8) - : "memory"); - - return a2; -} - -uintptr_t arch_syscall_invoke4_helper(uintptr_t arg1, uintptr_t arg2, - uintptr_t arg3, uintptr_t arg4, - uintptr_t call_id) -{ - register uintptr_t a2 __asm__("%a2") = call_id; - register uintptr_t a6 __asm__("%a6") = arg1; - register uintptr_t a3 __asm__("%a3") = arg2; - register uintptr_t a4 __asm__("%a4") = arg3; - register uintptr_t a5 __asm__("%a5") = arg4; - - __asm__ volatile("syscall\n\t" - : "=r" (a2) - : "r" (a2), "r" (a6), "r" (a3), "r" (a4), - "r" (a5) - : "memory"); - - return a2; -} - -uintptr_t arch_syscall_invoke3_helper(uintptr_t arg1, uintptr_t arg2, - uintptr_t arg3, uintptr_t call_id) -{ - register uintptr_t a2 __asm__("%a2") = call_id; - register uintptr_t a6 __asm__("%a6") = arg1; - register uintptr_t a3 __asm__("%a3") = arg2; - register uintptr_t a4 __asm__("%a4") = arg3; - - __asm__ volatile("syscall\n\t" - : "=r" (a2) - : "r" (a2), "r" (a6), "r" (a3), "r" (a4) - : "memory"); - - return a2; -} - -uintptr_t arch_syscall_invoke2_helper(uintptr_t arg1, uintptr_t arg2, - uintptr_t call_id) -{ - register uintptr_t a2 __asm__("%a2") = call_id; - register uintptr_t a6 __asm__("%a6") = arg1; - register uintptr_t a3 __asm__("%a3") = arg2; - - __asm__ volatile("syscall\n\t" - : "=r" (a2) - : "r" (a2), "r" (a6), "r" (a3) - : "memory"); - - return a2; -} - -uintptr_t arch_syscall_invoke1_helper(uintptr_t arg1, uintptr_t call_id) -{ - register uintptr_t a2 __asm__("%a2") = call_id; - register uintptr_t a6 __asm__("%a6") = arg1; - - __asm__ volatile("syscall\n\t" - : "=r" (a2) - : "r" (a2), "r" (a6) - : "memory"); - - return a2; -} - -uintptr_t arch_syscall_invoke0_helper(uintptr_t call_id) -{ - register uintptr_t a2 __asm__("%a2") = call_id; - - __asm__ volatile("syscall\n\t" - : "=r" (a2) - : "r" (a2) - : "memory"); - - return a2; -} diff --git a/include/zephyr/arch/xtensa/syscall.h b/include/zephyr/arch/xtensa/syscall.h index 3d78827b77c..70a075db454 100644 --- a/include/zephyr/arch/xtensa/syscall.h +++ b/include/zephyr/arch/xtensa/syscall.h @@ -29,29 +29,14 @@ extern "C" { #endif #ifdef CONFIG_XTENSA_SYSCALL_USE_HELPER -uintptr_t arch_syscall_invoke6_helper(uintptr_t arg1, uintptr_t arg2, - uintptr_t arg3, uintptr_t arg4, - uintptr_t arg5, uintptr_t arg6, - uintptr_t call_id); +uintptr_t xtensa_syscall_helper(uintptr_t arg1, uintptr_t arg2, + uintptr_t arg3, uintptr_t arg4, + uintptr_t arg5, uintptr_t arg6, + uintptr_t call_id); -uintptr_t arch_syscall_invoke5_helper(uintptr_t arg1, uintptr_t arg2, - uintptr_t arg3, uintptr_t arg4, - uintptr_t arg5, - uintptr_t call_id); - -uintptr_t arch_syscall_invoke4_helper(uintptr_t arg1, uintptr_t arg2, - uintptr_t arg3, uintptr_t arg4, - uintptr_t call_id); - -uintptr_t arch_syscall_invoke3_helper(uintptr_t arg1, uintptr_t arg2, - uintptr_t arg3, uintptr_t call_id); - -uintptr_t arch_syscall_invoke2_helper(uintptr_t arg1, uintptr_t arg2, - uintptr_t call_id); - -uintptr_t arch_syscall_invoke1_helper(uintptr_t arg1, uintptr_t call_id); - -uintptr_t arch_syscall_invoke0_helper(uintptr_t call_id); +#define SYSINL ALWAYS_INLINE +#else +#define SYSINL inline #endif /* CONFIG_XTENSA_SYSCALL_USE_HELPER */ /** @@ -63,15 +48,13 @@ uintptr_t arch_syscall_invoke0_helper(uintptr_t call_id); * **/ -static inline uintptr_t arch_syscall_invoke6(uintptr_t arg1, uintptr_t arg2, +static SYSINL uintptr_t arch_syscall_invoke6(uintptr_t arg1, uintptr_t arg2, uintptr_t arg3, uintptr_t arg4, uintptr_t arg5, uintptr_t arg6, uintptr_t call_id) { #ifdef CONFIG_XTENSA_SYSCALL_USE_HELPER - return arch_syscall_invoke6_helper(arg1, arg2, arg3, - arg4, arg5, arg6, - call_id); + return xtensa_syscall_helper(arg1, arg2, arg3, arg4, arg5, arg6, call_id); #else register uintptr_t a2 __asm__("%a2") = call_id; register uintptr_t a6 __asm__("%a6") = arg1; @@ -91,13 +74,12 @@ static inline uintptr_t arch_syscall_invoke6(uintptr_t arg1, uintptr_t arg2, #endif /* CONFIG_XTENSA_SYSCALL_USE_HELPER */ } -static inline uintptr_t arch_syscall_invoke5(uintptr_t arg1, uintptr_t arg2, +static SYSINL uintptr_t arch_syscall_invoke5(uintptr_t arg1, uintptr_t arg2, uintptr_t arg3, uintptr_t arg4, uintptr_t arg5, uintptr_t call_id) { #ifdef CONFIG_XTENSA_SYSCALL_USE_HELPER - return arch_syscall_invoke5_helper(arg1, arg2, arg3, - arg4, arg5, call_id); + return xtensa_syscall_helper(arg1, arg2, arg3, arg4, arg5, 0, call_id); #else register uintptr_t a2 __asm__("%a2") = call_id; register uintptr_t a6 __asm__("%a6") = arg1; @@ -116,12 +98,12 @@ static inline uintptr_t arch_syscall_invoke5(uintptr_t arg1, uintptr_t arg2, #endif /* CONFIG_XTENSA_SYSCALL_USE_HELPER */ } -static inline uintptr_t arch_syscall_invoke4(uintptr_t arg1, uintptr_t arg2, +static SYSINL uintptr_t arch_syscall_invoke4(uintptr_t arg1, uintptr_t arg2, uintptr_t arg3, uintptr_t arg4, uintptr_t call_id) { #ifdef CONFIG_XTENSA_SYSCALL_USE_HELPER - return arch_syscall_invoke4_helper(arg1, arg2, arg3, arg4, call_id); + return xtensa_syscall_helper(arg1, arg2, arg3, arg4, 0, 0, call_id); #else register uintptr_t a2 __asm__("%a2") = call_id; register uintptr_t a6 __asm__("%a6") = arg1; @@ -139,11 +121,11 @@ static inline uintptr_t arch_syscall_invoke4(uintptr_t arg1, uintptr_t arg2, #endif /* CONFIG_XTENSA_SYSCALL_USE_HELPER */ } -static inline uintptr_t arch_syscall_invoke3(uintptr_t arg1, uintptr_t arg2, +static SYSINL uintptr_t arch_syscall_invoke3(uintptr_t arg1, uintptr_t arg2, uintptr_t arg3, uintptr_t call_id) { #ifdef CONFIG_XTENSA_SYSCALL_USE_HELPER - return arch_syscall_invoke3_helper(arg1, arg2, arg3, call_id); + return xtensa_syscall_helper(arg1, arg2, arg3, 0, 0, 0, call_id); #else register uintptr_t a2 __asm__("%a2") = call_id; register uintptr_t a6 __asm__("%a6") = arg1; @@ -159,11 +141,11 @@ static inline uintptr_t arch_syscall_invoke3(uintptr_t arg1, uintptr_t arg2, #endif /* CONFIG_XTENSA_SYSCALL_USE_HELPER */ } -static inline uintptr_t arch_syscall_invoke2(uintptr_t arg1, uintptr_t arg2, +static SYSINL uintptr_t arch_syscall_invoke2(uintptr_t arg1, uintptr_t arg2, uintptr_t call_id) { #ifdef CONFIG_XTENSA_SYSCALL_USE_HELPER - return arch_syscall_invoke2_helper(arg1, arg2, call_id); + return xtensa_syscall_helper(arg1, arg2, 0, 0, 0, 0, call_id); #else register uintptr_t a2 __asm__("%a2") = call_id; register uintptr_t a6 __asm__("%a6") = arg1; @@ -178,11 +160,11 @@ static inline uintptr_t arch_syscall_invoke2(uintptr_t arg1, uintptr_t arg2, #endif } -static inline uintptr_t arch_syscall_invoke1(uintptr_t arg1, +static SYSINL uintptr_t arch_syscall_invoke1(uintptr_t arg1, uintptr_t call_id) { #ifdef CONFIG_XTENSA_SYSCALL_USE_HELPER - return arch_syscall_invoke1_helper(arg1, call_id); + return xtensa_syscall_helper(arg1, 0, 0, 0, 0, 0, call_id); #else register uintptr_t a2 __asm__("%a2") = call_id; register uintptr_t a6 __asm__("%a6") = arg1; @@ -196,10 +178,10 @@ static inline uintptr_t arch_syscall_invoke1(uintptr_t arg1, #endif } -static inline uintptr_t arch_syscall_invoke0(uintptr_t call_id) +static SYSINL uintptr_t arch_syscall_invoke0(uintptr_t call_id) { #ifdef CONFIG_XTENSA_SYSCALL_USE_HELPER - return arch_syscall_invoke0_helper(call_id); + return xtensa_syscall_helper(0, 0, 0, 0, 0, 0, call_id); #else register uintptr_t a2 __asm__("%a2") = call_id; @@ -229,6 +211,8 @@ static inline bool arch_is_user_context(void) return !!thread; } +#undef SYSINL + #ifdef __cplusplus } #endif From 0e7def1977aab1d4578fa9ebe93648c58b15280f Mon Sep 17 00:00:00 2001 From: Daniel Leung Date: Mon, 11 Sep 2023 16:25:22 -0700 Subject: [PATCH 0037/3723] xtensa: selectively init interrupt stack at boot During arch_kernel_init(), the interrupt stack is being initialized. However, if the current in-use stack is the interrupt stack, it would wipe all the data up to that point in stack, and might result in crash. So skip initializing the interrupt stack if the current stack pointer is within the boundary of interrupt stack. Signed-off-by: Daniel Leung --- arch/xtensa/include/kernel_arch_func.h | 18 ++++++++++++++++-- 1 file changed, 16 insertions(+), 2 deletions(-) diff --git a/arch/xtensa/include/kernel_arch_func.h b/arch/xtensa/include/kernel_arch_func.h index 8ce5cc52a5b..080b81d72bf 100644 --- a/arch/xtensa/include/kernel_arch_func.h +++ b/arch/xtensa/include/kernel_arch_func.h @@ -53,8 +53,22 @@ static ALWAYS_INLINE void arch_kernel_init(void) XTENSA_WSR(ZSR_CPU_STR, cpu0); #ifdef CONFIG_INIT_STACKS - memset(Z_KERNEL_STACK_BUFFER(z_interrupt_stacks[0]), 0xAA, - K_KERNEL_STACK_SIZEOF(z_interrupt_stacks[0])); + char *stack_start = Z_KERNEL_STACK_BUFFER(z_interrupt_stacks[0]); + size_t stack_sz = K_KERNEL_STACK_SIZEOF(z_interrupt_stacks[0]); + char *stack_end = stack_start + stack_sz; + + uint32_t sp; + + __asm__ volatile("mov %0, sp" : "=a"(sp)); + + /* Only clear the interrupt stack if the current stack pointer + * is not within the interrupt stack. Or else we would be + * wiping the in-use stack. + */ + if (((uintptr_t)sp < (uintptr_t)stack_start) || + ((uintptr_t)sp >= (uintptr_t)stack_end)) { + memset(stack_start, 0xAA, stack_sz); + } #endif #ifdef CONFIG_XTENSA_MMU From 0d794815403224d6942e72a576e6c8694f524e01 Mon Sep 17 00:00:00 2001 From: Daniel Leung Date: Wed, 30 Aug 2023 15:36:21 -0700 Subject: [PATCH 0038/3723] xtensa: userspace: only write 0xAA to stack if INIT_STACKS Only clear the user stack to 0xAA if CONFIG_INIT_STACKS is enabled. Otherwise, write 0x00 as if the stack is in BSS. Signed-off-by: Daniel Leung --- arch/xtensa/core/xtensa_mmu.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/arch/xtensa/core/xtensa_mmu.c b/arch/xtensa/core/xtensa_mmu.c index eba89c970ad..2130a870e77 100644 --- a/arch/xtensa/core/xtensa_mmu.c +++ b/arch/xtensa/core/xtensa_mmu.c @@ -1057,8 +1057,9 @@ static inline int reset_region(uint32_t *ptables, uintptr_t start, size_t size, void xtensa_user_stack_perms(struct k_thread *thread) { - (void)memset((void *)thread->stack_info.start, 0xAA, - thread->stack_info.size - thread->stack_info.delta); + (void)memset((void *)thread->stack_info.start, + (IS_ENABLED(CONFIG_INIT_STACKS)) ? 0xAA : 0x00, + thread->stack_info.size - thread->stack_info.delta); update_region(thread_page_tables_get(thread), thread->stack_info.start, thread->stack_info.size, From a36e39c2a65f3705832875053f8a4e13320dcd4c Mon Sep 17 00:00:00 2001 From: Daniel Leung Date: Mon, 28 Aug 2023 17:01:16 -0700 Subject: [PATCH 0039/3723] xtensa: dc233c: enable userspace support This massages kconfig and linker script to enable userspace support on dc233c core. Signed-off-by: Daniel Leung --- soc/xtensa/dc233c/Kconfig.soc | 1 + soc/xtensa/dc233c/include/xtensa-dc233c.ld | 94 +++++++++++++--------- soc/xtensa/dc233c/mmu.c | 7 +- 3 files changed, 61 insertions(+), 41 deletions(-) diff --git a/soc/xtensa/dc233c/Kconfig.soc b/soc/xtensa/dc233c/Kconfig.soc index 89b814da4d2..617eaa13849 100644 --- a/soc/xtensa/dc233c/Kconfig.soc +++ b/soc/xtensa/dc233c/Kconfig.soc @@ -9,3 +9,4 @@ config SOC_XTENSA_DC233C select ARCH_HAS_THREAD_LOCAL_STORAGE select CPU_HAS_MMU select ARCH_HAS_RESERVED_PAGE_FRAMES if XTENSA_MMU + select ARCH_HAS_USERSPACE if XTENSA_MMU diff --git a/soc/xtensa/dc233c/include/xtensa-dc233c.ld b/soc/xtensa/dc233c/include/xtensa-dc233c.ld index b165016fa6a..2153c4a420c 100644 --- a/soc/xtensa/dc233c/include/xtensa-dc233c.ld +++ b/soc/xtensa/dc233c/include/xtensa-dc233c.ld @@ -20,7 +20,7 @@ #include #define RAMABLE_REGION RAM :sram0_phdr -#define ROMABLE_REGION rom0_seg :rom0_phdr +#define ROMABLE_REGION RAM :sram0_phdr #ifdef CONFIG_MMU #define MMU_PAGE_ALIGN . = ALIGN(CONFIG_MMU_PAGE_SIZE); @@ -287,6 +287,9 @@ SECTIONS _DoubleExceptionVector_text_end = ABSOLUTE(.); } >sram0_18_seg :sram0_18_phdr +#define LIB_OBJ_FUNC_IN_SECT(library, obj_file, func) \ + *##library##:##obj_file##(.literal.##func .text.##func) \ + #ifdef CONFIG_XTENSA_MMU .vec_helpers : { @@ -301,48 +304,45 @@ SECTIONS * TLB multi-hit exception. */ - *libarch__xtensa__core.a:xtensa-asm2-util.S.obj(.literal) - *libarch__xtensa__core.a:xtensa-asm2-util.S.obj(.text) - *libarch__xtensa__core.a:xtensa-asm2-util.S.obj(.iram.text) - *libarch__xtensa__core.a:xtensa-asm2-util.S.obj(.iram0.text) + *libarch__xtensa__core.a:xtensa-asm2-util.S.obj(.literal .text) + *libarch__xtensa__core.a:xtensa-asm2-util.S.obj(.iram.text .iram0.text) *libarch__xtensa__core.a:window_vectors.S.obj(.iram.text) - *libarch__xtensa__core.a:xtensa-asm2.c.obj(.literal.*) - *libarch__xtensa__core.a:xtensa-asm2.c.obj(.text.*) - - *libarch__xtensa__core.a:fatal.c.obj(.literal.*) - *libarch__xtensa__core.a:fatal.c.obj(.text.*) - - *libarch__xtensa__core.a:crt1.S.obj(.literal) - *libarch__xtensa__core.a:crt1.S.obj(.text) + *libarch__xtensa__core.a:crt1.S.obj(.literal .text) - *libarch__xtensa__core.a:cpu_idle.c.obj(.literal.*) - *libarch__xtensa__core.a:cpu_idle.c.obj(.text.*) + LIB_OBJ_FUNC_IN_SECT(libarch__xtensa__core.a,xtensa-asm2.c.obj,*) + LIB_OBJ_FUNC_IN_SECT(libarch__xtensa__core.a,fatal.c.obj,*) + LIB_OBJ_FUNC_IN_SECT(libarch__xtensa__core.a,cpu_idle.c.obj,*) *(.text.arch_is_in_isr) /* To support backtracing */ - *libarch__xtensa__core.a:xtensa_backtrace.c.obj(.literal.*) - *libarch__xtensa__core.a:xtensa_backtrace.c.obj(.text.*) - *libarch__xtensa__core.a:debug_helpers_asm.S.obj(.iram1.literal) - *libarch__xtensa__core.a:debug_helpers_asm.S.obj(.iram1) + LIB_OBJ_FUNC_IN_SECT(libarch__xtensa__core.a,xtensa_backtrace.c.obj,*) - *libkernel.a:fatal.c.obj(.literal.*) - *libkernel.a:fatal.c.obj(.text.*) + *libarch__xtensa__core.a:debug_helpers_asm.S.obj(.iram1.literal .iram1) + + /* Userspace related stuff */ + LIB_OBJ_FUNC_IN_SECT(libarch__xtensa__core.a,userspace.S.obj,z_xtensa_do_syscall) + LIB_OBJ_FUNC_IN_SECT(libarch__xtensa__core.a,xtensa_mmu.c.obj,z_xtensa_swap_update_page_tables) /* Below are to speed up execution by avoiding TLB misses * on frequently used functions. + * + * There is almost 1MB space (due to TLB pinning) so we can + * be generous. */ - *libkernel.a:sched.c.obj(.literal.*) - *libkernel.a:sched.c.obj(.text.*) - *libkernel.a:timeout.c.obj(.literal.*) - *libkernel.a:timeout.c.obj(.text.*) - - *libdrivers__console.a:(.literal.*) - *libdrivers__console.a:(.text.*) - *libdrivers__timer.a:(.literal.*) - *libdrivers__timer.a:(.text.*) + LIB_OBJ_FUNC_IN_SECT(libkernel.a,,*) + + LIB_OBJ_FUNC_IN_SECT(libdrivers__console.a,,*) + LIB_OBJ_FUNC_IN_SECT(libdrivers__timer.a,,*) + + *(.literal.z_vrfy_* .text.z_vrfy_*) + *(.literal.z_mrsh_* .text.z_mrsh_*) + *(.literal.z_impl_* .text.z_impl_*) + *(.literal.z_obj_* .text.z_obj_*) + + *(.literal.k_sys_fatal_error_handler .text.k_sys_fatal_error_handler) } >vec_helpers :vec_helpers_phdr #endif /* CONFIG_XTENSA_MMU */ @@ -380,7 +380,7 @@ SECTIONS _text_end = ABSOLUTE(.); _etext = .; - } >RAM :sram0_phdr + } >RAMABLE_REGION __text_region_end = .; .rodata : HDR_MMU_PAGE_ALIGN @@ -394,7 +394,16 @@ SECTIONS . = ALIGN(4); #include #include + } >RAMABLE_REGION + +#include + +#include +#include + + .rodata_end : ALIGN(4) + { . = ALIGN(4); /* this table MUST be 4-byte aligned */ _bss_table_start = ABSOLUTE(.); LONG(_bss_start) @@ -404,19 +413,26 @@ SECTIONS MMU_PAGE_ALIGN __rodata_region_end = ABSOLUTE(.); - } >RAM :sram0_phdr + } >RAMABLE_REGION -#include +#ifdef CONFIG_USERSPACE +#define SMEM_PARTITION_ALIGN(size) MMU_PAGE_ALIGN +#define APP_SHARED_ALIGN MMU_PAGE_ALIGN -#include +#include -#include - -#include + _image_ram_start = _app_smem_start; + _app_smem_size = _app_smem_end - _app_smem_start; + _app_smem_num_words = _app_smem_size >> 2; + _app_smem_rom_start = LOADADDR(_APP_SMEM_SECTION_NAME); + _app_smem_num_words = _app_smem_size >> 2; +#endif /* CONFIG_USERSPACE */ .data : HDR_MMU_PAGE_ALIGN { +#ifndef CONFIG_USERSPACE _image_ram_start = ABSOLUTE(.); +#endif __data_start = ABSOLUTE(.); *(.data) *(.data.*) @@ -438,7 +454,9 @@ SECTIONS MMU_PAGE_ALIGN __data_end = ABSOLUTE(.); - } >RAM :sram0_phdr + } >RAMABLE_REGION + +#include #include diff --git a/soc/xtensa/dc233c/mmu.c b/soc/xtensa/dc233c/mmu.c index 4b8d6b154b8..718f79779eb 100644 --- a/soc/xtensa/dc233c/mmu.c +++ b/soc/xtensa/dc233c/mmu.c @@ -18,7 +18,7 @@ const struct xtensa_mmu_range xtensa_soc_mmu_ranges[] = { { .start = (uint32_t)XCHAL_VECBASE_RESET_VADDR, .end = (uint32_t)CONFIG_SRAM_OFFSET, - .attrs = Z_XTENSA_MMU_X | Z_XTENSA_MMU_CACHED_WB, + .attrs = Z_XTENSA_MMU_X | Z_XTENSA_MMU_CACHED_WB | Z_XTENSA_MMU_MAP_SHARED, .name = "vecbase", }, { @@ -52,7 +52,8 @@ void arch_xtensa_mmu_post_init(bool is_core0) /* Map VECBASE permanently in instr TLB way 4 so we will always have * access to exception handlers. Each way 4 TLB covers 1MB (unless * ITLBCFG has been changed before this, which should not have - * happened). + * happened). Also this needs to be mapped as SHARED so both kernel + * and userspace can execute code here => same as .text. * * Note that we don't want to map the first 1MB in data TLB as * we want to keep page 0 (0x00000000) unmapped to catch null pointer @@ -60,7 +61,7 @@ void arch_xtensa_mmu_post_init(bool is_core0) */ vecbase = ROUND_DOWN(vecbase, MB(1)); xtensa_itlb_entry_write_sync( - Z_XTENSA_PTE(vecbase, Z_XTENSA_KERNEL_RING, + Z_XTENSA_PTE(vecbase, Z_XTENSA_SHARED_RING, Z_XTENSA_MMU_X | Z_XTENSA_MMU_CACHED_WT), Z_XTENSA_TLB_ENTRY((uint32_t)vecbase, 4)); } From 1247f8465c22b00e7a5ab0cf1179d54ba883052c Mon Sep 17 00:00:00 2001 From: Flavio Ceolin Date: Thu, 7 Sep 2023 19:48:35 +0000 Subject: [PATCH 0040/3723] xtensa: userspace: Supports tls on userspace Use thread local storage to check whether or not a thread is running in user mode. This allows to use threadptr to properly support tls. Signed-off-by: Flavio Ceolin --- arch/xtensa/core/userspace.S | 31 +++++++++++++++++++++++++--- arch/xtensa/core/xtensa-asm2.c | 8 +++++++ include/zephyr/arch/xtensa/syscall.h | 9 ++++++++ 3 files changed, 45 insertions(+), 3 deletions(-) diff --git a/arch/xtensa/core/userspace.S b/arch/xtensa/core/userspace.S index b649014fd52..1a000d75d57 100644 --- a/arch/xtensa/core/userspace.S +++ b/arch/xtensa/core/userspace.S @@ -100,8 +100,17 @@ _id_ok: * we are in a interruption we don't want the system * thinking it is possibly running in user mode. */ +#ifdef CONFIG_THREAD_LOCAL_STORAGE + movi a0, is_user_mode@tpoff + rur.THREADPTR a3 + add a0, a3, a0 + + movi a3, 0 + s32i a3, a0, 0 +#else movi a0, 0 wur.THREADPTR a0 +#endif /* Set syscall parameters. We have an initial call4 to set up the * the stack and then a new call4 for the syscall function itself. @@ -157,9 +166,17 @@ _syscall_returned: wsr a3, SCOMPARE1 #endif +#ifdef CONFIG_THREAD_LOCAL_STORAGE + l32i a3, a1, ___xtensa_irq_bsa_t_threadptr_OFFSET + movi a0, is_user_mode@tpoff + add a0, a3, a0 + movi a3, 1 + s32i a3, a0, 0 +#else rsr a3, ZSR_CPU l32i a3, a3, ___cpu_t_current_OFFSET wur.THREADPTR a3 +#endif l32i a3, a1, ___xtensa_irq_bsa_t_ps_OFFSET wsr.ps a3 @@ -225,9 +242,17 @@ z_xtensa_userspace_enter: l32i a6, a1, 24 call4 z_xtensa_swap_update_page_tables - /* Set threadptr with the thread address, we are going to user mode. */ - l32i a0, a1, 24 - wur.THREADPTR a0 +#ifdef CONFIG_THREAD_LOCAL_STORAGE + rur.threadptr a3 + movi a0, is_user_mode@tpoff + add a0, a3, a0 + movi a3, 1 + s32i a3, a0, 0 +#else + rsr a3, ZSR_CPU + l32i a3, a3, ___cpu_t_current_OFFSET + wur.THREADPTR a3 +#endif /* Set now z_thread_entry parameters, we are simulating a call4 * call, so parameters start at a6, a7, ... diff --git a/arch/xtensa/core/xtensa-asm2.c b/arch/xtensa/core/xtensa-asm2.c index ed8f340f1bc..88783c178c6 100644 --- a/arch/xtensa/core/xtensa-asm2.c +++ b/arch/xtensa/core/xtensa-asm2.c @@ -28,6 +28,14 @@ Z_EXC_DECLARE(z_xtensa_user_string_nlen); static const struct z_exc_handle exceptions[] = { Z_EXC_HANDLE(z_xtensa_user_string_nlen) }; + +#ifdef CONFIG_THREAD_LOCAL_STORAGE +/* + * Per-thread (TLS) variable indicating whether execution is in user mode. + */ +__thread uint32_t is_user_mode; +#endif + #endif /* CONFIG_USERSPACE */ void *xtensa_init_stack(struct k_thread *thread, int *stack_top, diff --git a/include/zephyr/arch/xtensa/syscall.h b/include/zephyr/arch/xtensa/syscall.h index 70a075db454..b8b0bea8cdb 100644 --- a/include/zephyr/arch/xtensa/syscall.h +++ b/include/zephyr/arch/xtensa/syscall.h @@ -207,8 +207,17 @@ static inline bool arch_is_user_context(void) "rur.THREADPTR %0\n\t" : "=a" (thread) ); +#ifdef CONFIG_THREAD_LOCAL_STORAGE + extern __thread uint32_t is_user_mode; + if (!thread) { + return false; + } + + return is_user_mode != 0; +#else return !!thread; +#endif } #undef SYSINL From 8679c58644716b11310682a25c9605dac46f536d Mon Sep 17 00:00:00 2001 From: Flavio Ceolin Date: Mon, 18 Sep 2023 12:44:03 -0700 Subject: [PATCH 0041/3723] kernel: Option to not use tls to get current thread Add a Kconfig option to tell whether or not using thread local storage to store current thread. The function using it can be called from ISR and using TLS variables in this context may (should ???) not be allowed Signed-off-by: Flavio Ceolin --- include/zephyr/kernel.h | 3 ++- kernel/Kconfig | 14 ++++++++++++++ lib/os/thread_entry.c | 4 ++-- 3 files changed, 18 insertions(+), 3 deletions(-) diff --git a/include/zephyr/kernel.h b/include/zephyr/kernel.h index fac7df01904..d2b912f6d46 100644 --- a/include/zephyr/kernel.h +++ b/include/zephyr/kernel.h @@ -596,7 +596,8 @@ __syscall k_tid_t k_sched_current_thread_query(void); __attribute_const__ static inline k_tid_t k_current_get(void) { -#ifdef CONFIG_THREAD_LOCAL_STORAGE +#ifdef CONFIG_CURRENT_THREAD_USE_TLS + /* Thread-local cache of current thread ID, set in z_thread_entry() */ extern __thread k_tid_t z_tls_current; diff --git a/kernel/Kconfig b/kernel/Kconfig index 6280e80a400..4a72d76da67 100644 --- a/kernel/Kconfig +++ b/kernel/Kconfig @@ -288,6 +288,20 @@ config ERRNO_IN_TLS Use thread local storage to store errno instead of storing it in the kernel thread struct. This avoids a syscall if userspace is enabled. +config CURRENT_THREAD_USE_NO_TLS + bool + help + Hidden symbol to not use thread local storage to store current + thread. + +config CURRENT_THREAD_USE_TLS + bool "Store current thread in thread local storage (TLS)" + depends on THREAD_LOCAL_STORAGE && !CURRENT_THREAD_USE_NO_TLS + default y + help + Use thread local storage to store the current thread. This avoids a + syscall if userspace is enabled. + choice SCHED_ALGORITHM prompt "Scheduler priority queue algorithm" default SCHED_DUMB diff --git a/lib/os/thread_entry.c b/lib/os/thread_entry.c index 89eb2fe7b4b..ed6ca142d99 100644 --- a/lib/os/thread_entry.c +++ b/lib/os/thread_entry.c @@ -12,7 +12,7 @@ */ #include -#ifdef CONFIG_THREAD_LOCAL_STORAGE +#ifdef CONFIG_CURRENT_THREAD_USE_TLS #include __thread k_tid_t z_tls_current; @@ -35,7 +35,7 @@ extern __thread volatile uintptr_t __stack_chk_guard; FUNC_NORETURN void z_thread_entry(k_thread_entry_t entry, void *p1, void *p2, void *p3) { -#ifdef CONFIG_THREAD_LOCAL_STORAGE +#ifdef CONFIG_CURRENT_THREAD_USE_TLS z_tls_current = k_sched_current_thread_query(); #endif #ifdef CONFIG_STACK_CANARIES_TLS From dd36389879abda87e8999a12105702c4f223761b Mon Sep 17 00:00:00 2001 From: Flavio Ceolin Date: Fri, 29 Sep 2023 21:33:45 -0700 Subject: [PATCH 0042/3723] arch: xtensa: Not use TLS to store current thread Xtensa clears out threadptr durint ISR when userspace is enabled. Signed-off-by: Flavio Ceolin --- arch/xtensa/Kconfig | 1 + 1 file changed, 1 insertion(+) diff --git a/arch/xtensa/Kconfig b/arch/xtensa/Kconfig index c875aa30972..fefc77e2521 100644 --- a/arch/xtensa/Kconfig +++ b/arch/xtensa/Kconfig @@ -116,6 +116,7 @@ config XTENSA_MMU select ARCH_MEM_DOMAIN_SYNCHRONOUS_API if USERSPACE select XTENSA_SMALL_VECTOR_TABLE_ENTRY select KERNEL_VM_USE_CUSTOM_MEM_RANGE_CHECK if XTENSA_RPO_CACHE + select CURRENT_THREAD_USE_NO_TLS if USERSPACE help Enable support for Xtensa Memory Management Unit. From b7d96ab42ab31050c28c1de6f65b9b673cfa74e8 Mon Sep 17 00:00:00 2001 From: Flavio Ceolin Date: Tue, 17 Oct 2023 15:50:31 -0700 Subject: [PATCH 0043/3723] xtensa: userspace: Warning about impl security Add a Kconfig option (and build warning) alerting about the problem of the kernel spilling register in behave of the userspace. Signed-off-by: Flavio Ceolin --- arch/xtensa/CMakeLists.txt | 6 ++++++ arch/xtensa/Kconfig | 5 +++++ 2 files changed, 11 insertions(+) diff --git a/arch/xtensa/CMakeLists.txt b/arch/xtensa/CMakeLists.txt index 4626421f11a..21de223d4ec 100644 --- a/arch/xtensa/CMakeLists.txt +++ b/arch/xtensa/CMakeLists.txt @@ -3,3 +3,9 @@ zephyr_syscall_header(${ZEPHYR_BASE}/include/zephyr/arch/xtensa/arch.h) set_property(GLOBAL PROPERTY PROPERTY_OUTPUT_FORMAT elf32-xtensa-le) add_subdirectory(core) + +if (CONFIG_XTENSA_INSECURE_USERSPACE) + message(WARNING " + This userspace implementation uses the window ABI this means that the kernel + will spill registers in behave of the userpsace. Use it carefully.") +endif() diff --git a/arch/xtensa/Kconfig b/arch/xtensa/Kconfig index fefc77e2521..326c7749e6b 100644 --- a/arch/xtensa/Kconfig +++ b/arch/xtensa/Kconfig @@ -180,6 +180,11 @@ config XTENSA_SYSCALL_USE_HELPER This is a workaround for toolchains where they have issue modeling register usage. +config XTENSA_INSECURE_USERSPACE + bool + default y if USERSPACE + depends on XTENSA_MMU + endif # CPU_HAS_MMU endmenu From e7e8f6655c27ae6b77fdab25f168b59092e9295a Mon Sep 17 00:00:00 2001 From: Andy Ross Date: Sun, 27 Aug 2023 12:32:57 -0700 Subject: [PATCH 0044/3723] arch/xtensa: #include cleanup This file doesn't need the asm2 header, and the preprocessor logic around whether to include the backtrace header is needless (all it does is declare functions). Signed-off-by: Andy Ross --- arch/xtensa/core/fatal.c | 5 ----- 1 file changed, 5 deletions(-) diff --git a/arch/xtensa/core/fatal.c b/arch/xtensa/core/fatal.c index 79a24baa105..6e939e243cd 100644 --- a/arch/xtensa/core/fatal.c +++ b/arch/xtensa/core/fatal.c @@ -8,12 +8,7 @@ #include #include #include -#include -#if defined(CONFIG_XTENSA_ENABLE_BACKTRACE) -#if XCHAL_HAVE_WINDOWED #include -#endif -#endif #include #include #include From 8dd84bc1816ae749e45ebd8de687504017d036b9 Mon Sep 17 00:00:00 2001 From: Flavio Ceolin Date: Wed, 1 Nov 2023 16:07:02 -0700 Subject: [PATCH 0045/3723] arch: xtensa: Rename xtensa_mmu.c to ptables.c Initial work to split page table manipulation from mmu hardware interaction. Signed-off-by: Flavio Ceolin --- arch/xtensa/core/CMakeLists.txt | 2 +- arch/xtensa/core/{xtensa_mmu.c => ptables.c} | 0 soc/xtensa/dc233c/include/xtensa-dc233c.ld | 2 +- 3 files changed, 2 insertions(+), 2 deletions(-) rename arch/xtensa/core/{xtensa_mmu.c => ptables.c} (100%) diff --git a/arch/xtensa/core/CMakeLists.txt b/arch/xtensa/core/CMakeLists.txt index 331bcd9bfc5..1e4b045085e 100644 --- a/arch/xtensa/core/CMakeLists.txt +++ b/arch/xtensa/core/CMakeLists.txt @@ -21,7 +21,7 @@ zephyr_library_sources_ifdef(CONFIG_XTENSA_ENABLE_BACKTRACE debug_helpers_asm.S) zephyr_library_sources_ifdef(CONFIG_DEBUG_COREDUMP coredump.c) zephyr_library_sources_ifdef(CONFIG_TIMING_FUNCTIONS timing.c) zephyr_library_sources_ifdef(CONFIG_GDBSTUB gdbstub.c) -zephyr_library_sources_ifdef(CONFIG_XTENSA_MMU xtensa_mmu.c) +zephyr_library_sources_ifdef(CONFIG_XTENSA_MMU ptables.c) zephyr_library_sources_ifdef(CONFIG_USERSPACE userspace.S) zephyr_library_sources_ifdef(CONFIG_XTENSA_SYSCALL_USE_HELPER syscall_helper.c) diff --git a/arch/xtensa/core/xtensa_mmu.c b/arch/xtensa/core/ptables.c similarity index 100% rename from arch/xtensa/core/xtensa_mmu.c rename to arch/xtensa/core/ptables.c diff --git a/soc/xtensa/dc233c/include/xtensa-dc233c.ld b/soc/xtensa/dc233c/include/xtensa-dc233c.ld index 2153c4a420c..9c120e1b9d8 100644 --- a/soc/xtensa/dc233c/include/xtensa-dc233c.ld +++ b/soc/xtensa/dc233c/include/xtensa-dc233c.ld @@ -324,7 +324,7 @@ SECTIONS /* Userspace related stuff */ LIB_OBJ_FUNC_IN_SECT(libarch__xtensa__core.a,userspace.S.obj,z_xtensa_do_syscall) - LIB_OBJ_FUNC_IN_SECT(libarch__xtensa__core.a,xtensa_mmu.c.obj,z_xtensa_swap_update_page_tables) + LIB_OBJ_FUNC_IN_SECT(libarch__xtensa__core.a,ptables.c.obj,z_xtensa_swap_update_page_tables) /* Below are to speed up execution by avoiding TLB misses * on frequently used functions. From c47880af0d98cdeef05e2aa331f35ee41d0de44f Mon Sep 17 00:00:00 2001 From: Flavio Ceolin Date: Sun, 19 Nov 2023 15:44:56 -0800 Subject: [PATCH 0046/3723] arch/xtensa: Add new MMU layer Andy Ross re-implementation of MMU layer with some subtle changes, like re-using existent macros, fix page table cache property when direct mapping it in TLB. From Andy's original commit message: This is a reworked MMU layer, sitting cleanly below the page table handling in the OS. Notable differences from the original work: + Significantly smaller code and simpler API (just three functions to be called from the OS/userspace/ptable layer). + Big README-MMU document containing my learnings over the process, so hopefully fewer people need to go through this in the future. + No TLB flushing needed. Clean separation of ASIDs, just requires that the upper levels match the ASID to the L1 page table page consistently. + Vector mapping is done with a 4k page and not a 4M page, leading to much more flexibility with hardware memory layout. The original scheme required that the 4M region containing vecbase be mapped virtually to a location other than the hardware address, which makes confusing linkage with call0 and difficult initialization constraints where the exception vectors run at different addresses before and after MMU setup (effectively forcing them to be PIC code). + More provably correct initialization, all MMU changes happen in a single asm block with no memory accesses which would generate a refill. Signed-off-by: Andy Ross Signed-off-by: Flavio Ceolin --- arch/xtensa/core/CMakeLists.txt | 2 +- arch/xtensa/core/README-MMU.txt | 268 +++++++++++++++++++++ arch/xtensa/core/include/xtensa_mmu_priv.h | 15 +- arch/xtensa/core/mmu.c | 178 ++++++++++++++ arch/xtensa/core/ptables.c | 213 ++-------------- arch/xtensa/include/xtensa-asm2-s.h | 25 -- soc/xtensa/dc233c/mmu.c | 30 --- 7 files changed, 479 insertions(+), 252 deletions(-) create mode 100644 arch/xtensa/core/README-MMU.txt create mode 100644 arch/xtensa/core/mmu.c diff --git a/arch/xtensa/core/CMakeLists.txt b/arch/xtensa/core/CMakeLists.txt index 1e4b045085e..f3122c1a550 100644 --- a/arch/xtensa/core/CMakeLists.txt +++ b/arch/xtensa/core/CMakeLists.txt @@ -21,7 +21,7 @@ zephyr_library_sources_ifdef(CONFIG_XTENSA_ENABLE_BACKTRACE debug_helpers_asm.S) zephyr_library_sources_ifdef(CONFIG_DEBUG_COREDUMP coredump.c) zephyr_library_sources_ifdef(CONFIG_TIMING_FUNCTIONS timing.c) zephyr_library_sources_ifdef(CONFIG_GDBSTUB gdbstub.c) -zephyr_library_sources_ifdef(CONFIG_XTENSA_MMU ptables.c) +zephyr_library_sources_ifdef(CONFIG_XTENSA_MMU ptables.c mmu.c) zephyr_library_sources_ifdef(CONFIG_USERSPACE userspace.S) zephyr_library_sources_ifdef(CONFIG_XTENSA_SYSCALL_USE_HELPER syscall_helper.c) diff --git a/arch/xtensa/core/README-MMU.txt b/arch/xtensa/core/README-MMU.txt new file mode 100644 index 00000000000..499a251cdf2 --- /dev/null +++ b/arch/xtensa/core/README-MMU.txt @@ -0,0 +1,268 @@ +# Xtensa MMU Operation + +As with other elements of the architecture, paged virtual memory +management on Xtensa is somewhat unique. And there is similarly a +lack of introductory material available. This document is an attempt +to introduce the architecture at an overview/tutorial level, and to +describe Zephyr's specific implementation choices. + +## General TLB Operation + +The Xtensa MMU operates on top of a fairly conventional TLB cache. +The TLB stores virtual to physical translation for individual pages of +memory. It is partitioned into an automatically managed +4-way-set-associative bank of entries mapping 4k pages, and 3-6 +"special" ways storing mappings under OS control. Some of these are +for mapping pages larger than 4k, which Zephyr does not directly +support. A few are for bootstrap and initialization, and will be +discussed below. + +Like the L1 cache, the TLB is split into separate instruction and data +entries. Zephyr manages both as needed, but symmetrically. The +architecture technically supports separately-virtualized instruction +and data spaces, but the hardware page table refill mechanism (see +below) does not, and Zephyr's memory spaces are unified regardless. + +The TLB may be loaded with permissions and attributes controlling +cacheability, access control based on ring (i.e. the contents of the +RING field of the PS register) and togglable write and execute access. +Memory access, even with a matching TLB entry, may therefore create +Kernel/User exceptions as desired to enforce permissions choices on +userspace code. + +Live TLB entries are tagged with an 8-bit "ASID" value derived from +their ring field of the PTE that loaded them, via a simple translation +specified in the RASID special register. The intent is that each +non-kernel address space will get a separate ring 3 ASID set in RASID, +such that you can switch between them without a TLB flush. The ASID +value of ring zero is fixed at 1, it may not be changed. (An ASID +value of zero is used to tag an invalid/unmapped TLB entry at +initialization, but this mechanism isn't accessible to OS code except +in special circumstances, and in any case there is already an invalid +attribute value that can be used in a PTE). + +## Virtually-mapped Page Tables + +Xtensa has a unique (and, to someone exposed for the first time, +extremely confusing) "page table" format. The simplest was to begin +to explain this is just to describe the (quite simple) hardware +behavior: + +On a TLB miss, the hardware immediately does a single fetch (at ring 0 +privilege) from RAM by adding the "desired address right shifted by +10 bits with the bottom two bits set to zero" (i.e. the page frame +number in units of 4 bytes) to the value in the PTEVADDR special +register. If this load succeeds, then the word is treated as a PTE +with which to fill the TLB and use for a (restarted) memory access. +This is extremely simple (just one extra hardware state that does just +one thing the hardware can already do), and quite fast (only one +memory fetch vs. e.g. the 2-5 fetches required to walk a page table on +x86). + +This special "refill" fetch is otherwise identical to any other memory +access, meaning it too uses the TLB to translate from a virtual to +physical address. Which means that the page tables occupy a 4M region +of virtual, not physical, address space, in the same memory space +occupied by the running code. The 1024 pages in that range (not all +of which might be mapped in physical memory) are a linear array of +1048576 4-byte PTE entries, each describing a mapping for 4k of +virtual memory. Note especially that exactly one of those pages +contains the 1024 PTE entries for the 4M page table itself, pointed to +by PTEVADDR. + +Obviously, the page table memory being virtual means that the fetch +can fail: there are 1024 possible pages in a complete page table +covering all of memory, and the ~16 entry TLB clearly won't contain +entries mapping all of them. If we are missing a TLB entry for the +page translation we want (NOT for the original requested address, we +already know we're missing that TLB entry), the hardware has exactly +one more special trick: it throws a TLB Miss exception (there are two, +one each for instruction/data TLBs, but in Zephyr they operate +identically). + +The job of that exception handler is simply to ensure that the TLB has +an entry for the page table page we want. And the simplest way to do +that is to just load the faulting PTE as an address, which will then +go through the same refill process above. This second TLB fetch in +the exception handler may result in an invalid/inapplicable mapping +within the 4M page table region. This is an typical/expected runtime +fault, and simply indicates unmapped memory. The result is TLB miss +exception from within the TLB miss exception handler (i.e. while the +EXCM bit is set). This will produce a Double Exception fault, which +is handled by the OS identically to a general Kernel/User data access +prohibited exception. + +After the TLB refill exception, the original faulting instruction is +restarted, which retries the refill process, which succeeds in +fetching a new TLB entry, which is then used to service the original +memory access. (And may then result in yet another exception if it +turns out that the TLB entry doesn't permit the access requested, of +course.) + +## Special Cases + +The page-tables-specified-in-virtual-memory trick works very well in +practice. But it does have a chicken/egg problem with the initial +state. Because everything depends on state in the TLB, something +needs to tell the hardware how to find a physical address using the +TLB to begin the process. Here we exploit the separate +non-automatically-refilled TLB ways to store bootstrap records. + +First, note that the refill process to load a PTE requires that the 4M +space of PTE entries be resolvable by the TLB directly, without +requiring another refill. This 4M mapping is provided by a single +page of PTE entries (which itself lives in the 4M page table region!). +This page must always be in the TLB. + +Thankfully, for the data TLB Xtensa provides 3 special/non-refillable +ways (ways 7-9) with at least one 4k page mapping each. We can use +one of these to "pin" the top-level page table entry in place, +ensuring that a refill access will be able to find a PTE address. + +But now note that the load from that PTE address for the refill is +done in an exception handler. And running an exception handler +requires doing a fetch via the instruction TLB. And that obviously +means that the page(s) containing the exception handler must never +require a refill exception of its own. + +Ideally we would just pin the vector/handler page in the ITLB in the +same way we do for data, but somewhat inexplicably, Xtensa does not +provide 4k "pinnable" ways in the instruction TLB (frankly this seems +like a design flaw). + +Instead, we load ITLB entries for vector handlers via the refill +mechanism using the data TLB, and so need the refill mechanism for the +vector page to succeed always. The way to do this is to similarly pin +the page table page containing the (single) PTE for the vector page in +the data TLB, such that instruction fetches always find their TLB +mapping via refill, without requiring an exception. + +## Initialization + +Unlike most other architectures, Xtensa does not have a "disable" mode +for the MMU. Virtual address translation through the TLB is active at +all times. There therefore needs to be a mechanism for the CPU to +execute code before the OS is able to initialize a refillable page +table. + +The way Xtensa resolves this (on the hardware Zephyr supports, see the +note below) is to have an 8-entry set ("way 6") of 512M pages able to +cover all of memory. These 8 entries are initialized as valid, with +attributes specifying that they are accessible only to an ASID of 1 +(i.e. the fixed ring zero / kernel ASID), writable, executable, and +uncached. So at boot the CPU relies on these TLB entries to provide a +clean view of hardware memory. + +But that means that enabling page-level translation requires some +care, as the CPU will throw an exception ("multi hit") if a memory +access matches more than one live entry in the TLB. The +initialization algorithm is therefore: + +0. Start with a fully-initialized page table layout, including the + top-level "L1" page containing the mappings for the page table + itself. + +1. Ensure that the initialization routine does not cross a page + boundary (to prevent stray TLB refill exceptions), that it occupies + a separate 4k page than the exception vectors (which we must + temporarily double-map), and that it operates entirely in registers + (to avoid doing memory access at inopportune moments). + +2. Pin the L1 page table PTE into the data TLB. This creates a double + mapping condition, but it is safe as nothing will use it until we + start refilling. + +3. Pin the page table page containing the PTE for the TLB miss + exception handler into the data TLB. This will likewise not be + accessed until the double map condition is resolved. + +4. Set PTEVADDR appropriately. The CPU state to handle refill + exceptions is now complete, but cannot be used until we resolve the + double mappings. + +5. Disable the initial/way6 data TLB entries first, by setting them to + an ASID of zero. This is safe as the code being executed is not + doing data accesses yet (including refills), and will resolve the + double mapping conditions we created above. + +6. Disable the initial/way6 instruction TLBs second. The very next + instruction following the invalidation of the currently-executing + code page will then cause a TLB refill exception, which will work + normally because we just resolved the final double-map condition. + (Pedantic note: if the vector page and the currently-executing page + are in different 512M way6 pages, disable the mapping for the + exception handlers first so the trap from our current code can be + handled. Currently Zephyr doesn't handle this condition as in all + reasonable hardware these regions will be near each other) + +Note: there is a different variant of the Xtensa MMU architecture +where the way 5/6 pages are immutable, and specify a set of +unchangable mappings from the final 384M of memory to the bottom and +top of physical memory. The intent here would (presumably) be that +these would be used by the kernel for all physical memory and that the +remaining memory space would be used for virtual mappings. This +doesn't match Zephyr's architecture well, as we tend to assume +page-level control over physical memory (e.g. .text/.rodata is cached +but .data is not on SMP, etc...). And in any case we don't have any +such hardware to experiment with. But with a little address +translation we could support this. + +## ASID vs. Virtual Mapping + +The ASID mechanism in Xtensa works like other architectures, and is +intended to be used similarly. The intent of the design is that at +context switch time, you can simply change RADID and the page table +data, and leave any existing mappings in place in the TLB using the +old ASID value(s). So in the common case where you switch back, +nothing needs to be flushed. + +Unfortunately this runs afoul of the virtual mapping of the page +refill: data TLB entries storing the 4M page table mapping space are +stored at ASID 1 (ring 0), they can't change when the page tables +change! So this region naively would have to be flushed, which is +tantamount to flushing the entire TLB regardless (the TLB is much +smaller than the 1024-page PTE array). + +The resolution in Zephyr is to give each ASID its own PTEVADDR mapping +in virtual space, such that the page tables don't overlap. This is +expensive in virtual address space: assigning 4M of space to each of +the 256 ASIDs (actually 254 as 0 and 1 are never used by user access) +would take a full gigabyte of address space. Zephyr optimizes this a +bit by deriving a unique sequential ASID from the hardware address of +the statically allocated array of L1 page table pages. + +Note, obviously, that any change of the mappings within an ASID +(e.g. to re-use it for another memory domain, or just for any runtime +mapping change other than mapping previously-unmapped pages) still +requires a TLB flush, and always will. + +## SMP/Cache Interaction + +A final important note is that the hardware PTE refill fetch works +like any other CPU memory access, and in particular it is governed by +the cacheability attributes of the TLB entry through which it was +loaded. This means that if the page table entries are marked +cacheable, then the hardware TLB refill process will be downstream of +the L1 data cache on the CPU. If the physical memory storing page +tables has been accessed recently by the CPU (for a refill of another +page mapped within the same cache line, or to change the tables) then +the refill will be served from the data cache and not main memory. + +This may or may not be desirable depending on access patterns. It +lets the L1 data cache act as a "L2 TLB" for applications with a lot +of access variability. But it also means that the TLB entries end up +being stored twice in the same CPU, wasting transistors that could +presumably store other useful data. + +But it it also important to note that the L1 data cache on Xtensa is +incoherent! The cache being used for refill reflects the last access +on the current CPU only, and not of the underlying memory being +mapped. Page table changes in the data cache of one CPU will be +invisible to the data cache of another. There is no simple way of +notifying another CPU of changes to page mappings beyond doing +system-wide flushes on all cpus every time a memory domain is +modified. + +The result is that, when SMP is enabled, Zephyr must ensure that all +page table mappings in the system are set uncached. The OS makes no +attempt to bolt on a software coherence layer. diff --git a/arch/xtensa/core/include/xtensa_mmu_priv.h b/arch/xtensa/core/include/xtensa_mmu_priv.h index cf72c921383..7b1030786f4 100644 --- a/arch/xtensa/core/include/xtensa_mmu_priv.h +++ b/arch/xtensa/core/include/xtensa_mmu_priv.h @@ -132,15 +132,8 @@ * * PTE_ENTRY_ADDRESS = PTEVADDR + ((VADDR / 4096) * 4) */ -#define Z_XTENSA_PTE_ENTRY_VADDR(vaddr) \ - (Z_XTENSA_PTEVADDR + (((vaddr) / KB(4)) * 4)) - -/* - * The address of the top level page where the page - * is located in the virtual address. - */ -#define Z_XTENSA_PAGE_TABLE_VADDR \ - Z_XTENSA_PTE_ENTRY_VADDR(Z_XTENSA_PTEVADDR) +#define Z_XTENSA_PTE_ENTRY_VADDR(base, vaddr) \ + ((base) + (((vaddr) / KB(4)) * 4)) /* * Get asid for a given ring from rasid register. @@ -349,4 +342,8 @@ static inline void xtensa_dtlb_vaddr_invalidate(void *vaddr) } } +void xtensa_init_paging(uint32_t *l1_page); + +void xtensa_set_paging(uint32_t asid, uint32_t *l1_page); + #endif /* ZEPHYR_ARCH_XTENSA_XTENSA_MMU_PRIV_H_ */ diff --git a/arch/xtensa/core/mmu.c b/arch/xtensa/core/mmu.c new file mode 100644 index 00000000000..24e47a42b9d --- /dev/null +++ b/arch/xtensa/core/mmu.c @@ -0,0 +1,178 @@ +/* + * Copyright 2023 Google LLC + * SPDX-License-Identifier: Apache-2.0 + */ +#include +#include +#include +#include +#include + +#define ASID_INVALID 0 + +struct tlb_regs { + uint32_t rasid; + uint32_t ptevaddr; + uint32_t ptepin_as; + uint32_t ptepin_at; + uint32_t vecpin_as; + uint32_t vecpin_at; +}; + +static void compute_regs(uint32_t user_asid, uint32_t *l1_page, struct tlb_regs *regs) +{ + uint32_t vecbase = XTENSA_RSR("VECBASE"); + + __ASSERT_NO_MSG((((uint32_t)l1_page) & 0xfff) == 0); + __ASSERT_NO_MSG((user_asid == 0) || ((user_asid > 2) && + (user_asid < Z_XTENSA_MMU_SHARED_ASID))); + + /* We don't use ring 1, ring 0 ASID must be 1 */ + regs->rasid = (Z_XTENSA_MMU_SHARED_ASID << 24) | + (user_asid << 16) | 0x000201; + + /* Derive PTEVADDR from ASID so each domain gets its own PTE area */ + regs->ptevaddr = CONFIG_XTENSA_MMU_PTEVADDR + user_asid * 0x400000; + + /* The ptables code doesn't add the mapping for the l1 page itself */ + l1_page[Z_XTENSA_L1_POS(regs->ptevaddr)] = + (uint32_t)l1_page | Z_XTENSA_PAGE_TABLE_ATTR; + + regs->ptepin_at = (uint32_t)l1_page; + regs->ptepin_as = Z_XTENSA_PTE_ENTRY_VADDR(regs->ptevaddr, regs->ptevaddr) + | Z_XTENSA_MMU_PTE_WAY; + + /* Pin mapping for refilling the vector address into the ITLB + * (for handling TLB miss exceptions). Note: this is NOT an + * instruction TLB entry for the vector code itself, it's a + * DATA TLB entry for the page containing the vector mapping + * so the refill on instruction fetch can find it. The + * hardware doesn't have a 4k pinnable instruction TLB way, + * frustratingly. + */ + uint32_t vb_pte = l1_page[Z_XTENSA_L1_POS(vecbase)]; + + regs->vecpin_at = vb_pte; + regs->vecpin_as = Z_XTENSA_PTE_ENTRY_VADDR(regs->ptevaddr, vecbase) + | Z_XTENSA_MMU_VECBASE_WAY; +} + +/* Switch to a new page table. There are four items we have to set in + * the hardware: the PTE virtual address, the ring/ASID mapping + * register, and two pinned entries in the data TLB handling refills + * for the page tables and the vector handlers. + * + * These can be done in any order, provided that we ensure that no + * memory access which cause a TLB miss can happen during the process. + * This means that we must work entirely within registers in a single + * asm block. Also note that instruction fetches are memory accesses + * too, which means we cannot cross a page boundary which might reach + * a new page not in the TLB (a single jump to an aligned address that + * holds our five instructions is sufficient to guarantee that: I + * couldn't think of a way to do the alignment statically that also + * interoperated well with inline assembly). + */ +void xtensa_set_paging(uint32_t user_asid, uint32_t *l1_page) +{ + /* Optimization note: the registers computed here are pure + * functions of the two arguments. With a minor API tweak, + * they could be cached in e.g. a thread struct instead of + * being recomputed. This is called on context switch paths + * and is performance-sensitive. + */ + struct tlb_regs regs; + + compute_regs(user_asid, l1_page, ®s); + + __asm__ volatile("j 1f\n" + ".align 16\n" /* enough for 5 insns */ + "1:\n" + "wsr %0, PTEVADDR\n" + "wsr %1, RASID\n" + "wdtlb %2, %3\n" + "wdtlb %4, %5\n" + "isync" + :: "r"(regs.ptevaddr), "r"(regs.rasid), + "r"(regs.ptepin_at), "r"(regs.ptepin_as), + "r"(regs.vecpin_at), "r"(regs.vecpin_as)); +} + +/* This is effectively the same algorithm from xtensa_set_paging(), + * but it also disables the hardware-initialized 512M TLB entries in + * way 6 (because the hardware disallows duplicate TLB mappings). For + * instruction fetches this produces a critical ordering constraint: + * the instruction following the invalidation of ITLB entry mapping + * the current PC will by definition create a refill condition, which + * will (because the data TLB was invalidated) cause a refill + * exception. Therefore this step must be the very last one, once + * everything else is setup up and working, which includes the + * invalidation of the virtual PTEVADDR area so that the resulting + * refill can complete. + * + * Note that we can't guarantee that the compiler won't insert a data + * fetch from our stack memory after exit from the asm block (while it + * might be double-mapped), so we invalidate that data TLB inside the + * asm for correctness. The other 13 entries get invalidated in a C + * loop at the end. + */ +void xtensa_init_paging(uint32_t *l1_page) +{ + extern char z_xt_init_pc; /* defined in asm below */ + struct tlb_regs regs; + +#if CONFIG_MP_MAX_NUM_CPUS > 1 + /* The incoherent cache can get into terrible trouble if it's + * allowed to cache PTEs differently across CPUs. We require + * that all page tables supplied by the OS have exclusively + * uncached mappings for page data, but can't do anything + * about earlier code/firmware. Dump the cache to be safe. + */ + sys_cache_data_flush_and_invd_all(); +#endif + + compute_regs(ASID_INVALID, l1_page, ®s); + + uint32_t idtlb_pte = (regs.ptevaddr & 0xe0000000) | XCHAL_SPANNING_WAY; + uint32_t idtlb_stk = (((uint32_t)®s) & ~0xfff) | XCHAL_SPANNING_WAY; + uint32_t iitlb_pc = (((uint32_t)&z_xt_init_pc) & ~0xfff) | XCHAL_SPANNING_WAY; + + /* Note: the jump is mostly pedantry, as it's almost + * inconceivable that a hardware memory region at boot is + * going to cross a 512M page boundary. But we need the entry + * symbol to get the address above, so the jump is here for + * symmetry with the set_paging() code. + */ + __asm__ volatile("j z_xt_init_pc\n" + ".align 32\n" /* room for 10 insns */ + ".globl z_xt_init_pc\n" + "z_xt_init_pc:\n" + "wsr %0, PTEVADDR\n" + "wsr %1, RASID\n" + "wdtlb %2, %3\n" + "wdtlb %4, %5\n" + "idtlb %6\n" /* invalidate pte */ + "idtlb %7\n" /* invalidate stk */ + "isync\n" + "iitlb %8\n" /* invalidate pc */ + "isync\n" /* <--- traps a ITLB miss */ + :: "r"(regs.ptevaddr), "r"(regs.rasid), + "r"(regs.ptepin_at), "r"(regs.ptepin_as), + "r"(regs.vecpin_at), "r"(regs.vecpin_as), + "r"(idtlb_pte), "r"(idtlb_stk), "r"(iitlb_pc)); + + /* Invalidate the remaining (unused by this function) + * initialization entries. Now we're flying free with our own + * page table. + */ + for (int i = 0; i < 8; i++) { + uint32_t ixtlb = (i * 0x2000000000) | XCHAL_SPANNING_WAY; + + if (ixtlb != iitlb_pc) { + __asm__ volatile("iitlb %0" :: "r"(ixtlb)); + } + if (ixtlb != idtlb_stk && ixtlb != idtlb_pte) { + __asm__ volatile("idtlb %0" :: "r"(ixtlb)); + } + } + __asm__ volatile("isync"); +} diff --git a/arch/xtensa/core/ptables.c b/arch/xtensa/core/ptables.c index 2130a870e77..17950114544 100644 --- a/arch/xtensa/core/ptables.c +++ b/arch/xtensa/core/ptables.c @@ -218,42 +218,6 @@ static inline uint32_t *alloc_l2_table(void) return NULL; } -/** - * @brief Switch page tables - * - * This switches the page tables to the incoming ones (@a ptables). - * Since data TLBs to L2 page tables are auto-filled, @a dtlb_inv - * can be used to invalidate these data TLBs. @a cache_inv can be - * set to true to invalidate cache to the page tables. - * - * @param[in] ptables Page tables to be switched to. - * @param[in] dtlb_inv True if to invalidate auto-fill data TLBs. - * @param[in] cache_inv True if to invalidate cache to page tables. - */ -static ALWAYS_INLINE void switch_page_tables(uint32_t *ptables, bool dtlb_inv, bool cache_inv) -{ - if (cache_inv) { - sys_cache_data_flush_and_invd_all(); - } - - /* Invalidate data TLB to L1 page table */ - xtensa_dtlb_vaddr_invalidate((void *)Z_XTENSA_PAGE_TABLE_VADDR); - - /* Now map the pagetable itself with KERNEL asid to avoid user thread - * from tampering with it. - */ - xtensa_dtlb_entry_write_sync( - Z_XTENSA_PTE((uint32_t)ptables, Z_XTENSA_KERNEL_RING, Z_XTENSA_PAGE_TABLE_ATTR), - Z_XTENSA_TLB_ENTRY(Z_XTENSA_PAGE_TABLE_VADDR, Z_XTENSA_MMU_PTE_WAY)); - - if (dtlb_inv) { - /* Since L2 page tables are auto-refilled, - * invalidate all of them to flush the old entries out. - */ - xtensa_tlb_autorefill_invalidate(); - } -} - static void map_memory_range(const uint32_t start, const uint32_t end, const uint32_t attrs, bool shared) { @@ -345,6 +309,17 @@ static void xtensa_init_page_tables(void) #if defined(__GNUC__) #pragma GCC diagnostic pop #endif + /* Finally, the direct-mapped pages used in the page tables + * must be fixed up to use the same cache attribute (but these + * must be writable, obviously). They shouldn't be left at + * the default. + */ + map_memory_range((uint32_t) &l1_page_table[0], + (uint32_t) &l1_page_table[CONFIG_XTENSA_MMU_NUM_L1_TABLES], + Z_XTENSA_PAGE_TABLE_ATTR | Z_XTENSA_MMU_W, false); + map_memory_range((uint32_t) &l2_page_tables[0], + (uint32_t) &l2_page_tables[CONFIG_XTENSA_MMU_NUM_L2_TABLES], + Z_XTENSA_PAGE_TABLE_ATTR | Z_XTENSA_MMU_W, false); sys_cache_data_flush_all(); } @@ -356,9 +331,6 @@ __weak void arch_xtensa_mmu_post_init(bool is_core0) void z_xtensa_mmu_init(void) { - volatile uint8_t entry; - uint32_t ps, vecbase; - if (_current_cpu->id == 0) { /* This is normally done via arch_kernel_init() inside z_cstart(). * However, before that is called, we go through the sys_init of @@ -369,111 +341,7 @@ void z_xtensa_mmu_init(void) xtensa_init_page_tables(); } - /* Set the page table location in the virtual address */ - xtensa_ptevaddr_set((void *)Z_XTENSA_PTEVADDR); - - /* Set rasid */ - xtensa_rasid_asid_set(Z_XTENSA_MMU_SHARED_ASID, Z_XTENSA_SHARED_RING); - - /* Next step is to invalidate the tlb entry that contains the top level - * page table. This way we don't cause a multi hit exception. - */ - xtensa_dtlb_entry_invalidate_sync(Z_XTENSA_TLB_ENTRY(Z_XTENSA_PAGE_TABLE_VADDR, 6)); - xtensa_itlb_entry_invalidate_sync(Z_XTENSA_TLB_ENTRY(Z_XTENSA_PAGE_TABLE_VADDR, 6)); - - /* We are not using a flat table page, so we need to map - * only the top level page table (which maps the page table itself). - * - * Lets use one of the wired entry, so we never have tlb miss for - * the top level table. - */ - xtensa_dtlb_entry_write(Z_XTENSA_PTE((uint32_t)z_xtensa_kernel_ptables, - Z_XTENSA_KERNEL_RING, Z_XTENSA_PAGE_TABLE_ATTR), - Z_XTENSA_TLB_ENTRY(Z_XTENSA_PAGE_TABLE_VADDR, Z_XTENSA_MMU_PTE_WAY)); - - /* Before invalidate the text region in the TLB entry 6, we need to - * map the exception vector into one of the wired entries to avoid - * a page miss for the exception. - */ - __asm__ volatile("rsr.vecbase %0" : "=r"(vecbase)); - - xtensa_itlb_entry_write_sync( - Z_XTENSA_PTE(vecbase, Z_XTENSA_KERNEL_RING, - Z_XTENSA_MMU_X | Z_XTENSA_MMU_CACHED_WT), - Z_XTENSA_TLB_ENTRY( - Z_XTENSA_PTEVADDR + MB(4), 3)); - - xtensa_dtlb_entry_write_sync( - Z_XTENSA_PTE(vecbase, Z_XTENSA_KERNEL_RING, - Z_XTENSA_MMU_X | Z_XTENSA_MMU_CACHED_WT), - Z_XTENSA_TLB_ENTRY( - Z_XTENSA_PTEVADDR + MB(4), 3)); - - /* Temporarily uses KernelExceptionVector for level 1 interrupts - * handling. This is due to UserExceptionVector needing to jump to - * _Level1Vector. The jump ('j') instruction offset is incorrect - * when we move VECBASE below. - */ - __asm__ volatile("rsr.ps %0" : "=r"(ps)); - ps &= ~PS_UM; - __asm__ volatile("wsr.ps %0; rsync" :: "a"(ps)); - - __asm__ volatile("wsr.vecbase %0; rsync\n\t" - :: "a"(Z_XTENSA_PTEVADDR + MB(4))); - - - /* Finally, lets invalidate all entries in way 6 as the page tables - * should have already mapped the regions we care about for boot. - */ - for (entry = 0; entry < BIT(XCHAL_ITLB_ARF_ENTRIES_LOG2); entry++) { - __asm__ volatile("iitlb %[idx]\n\t" - "isync" - :: [idx] "a"((entry << 29) | 6)); - } - - for (entry = 0; entry < BIT(XCHAL_DTLB_ARF_ENTRIES_LOG2); entry++) { - __asm__ volatile("idtlb %[idx]\n\t" - "dsync" - :: [idx] "a"((entry << 29) | 6)); - } - - /* Map VECBASE to a fixed data TLB */ - xtensa_dtlb_entry_write( - Z_XTENSA_PTE((uint32_t)vecbase, - Z_XTENSA_KERNEL_RING, Z_XTENSA_MMU_CACHED_WB), - Z_XTENSA_TLB_ENTRY((uint32_t)vecbase, Z_XTENSA_MMU_VECBASE_WAY)); - - /* - * Pre-load TLB for vecbase so exception handling won't result - * in TLB miss during boot, and that we can handle single - * TLB misses. - */ - xtensa_itlb_entry_write_sync( - Z_XTENSA_PTE(vecbase, Z_XTENSA_KERNEL_RING, - Z_XTENSA_MMU_X | Z_XTENSA_MMU_CACHED_WT), - Z_XTENSA_AUTOFILL_TLB_ENTRY(vecbase)); - - /* To finish, just restore vecbase and invalidate TLB entries - * used to map the relocated vecbase. - */ - __asm__ volatile("wsr.vecbase %0; rsync\n\t" - :: "a"(vecbase)); - - /* Restore PS_UM so that level 1 interrupt handling will go to - * UserExceptionVector. - */ - __asm__ volatile("rsr.ps %0" : "=r"(ps)); - ps |= PS_UM; - __asm__ volatile("wsr.ps %0; rsync" :: "a"(ps)); - - xtensa_dtlb_entry_invalidate_sync(Z_XTENSA_TLB_ENTRY(Z_XTENSA_PTEVADDR + MB(4), 3)); - xtensa_itlb_entry_invalidate_sync(Z_XTENSA_TLB_ENTRY(Z_XTENSA_PTEVADDR + MB(4), 3)); - - /* - * Clear out THREADPTR as we use it to indicate - * whether we are in user mode or not. - */ - XTENSA_WUR("THREADPTR", 0); + xtensa_init_paging(z_xtensa_kernel_ptables); arch_xtensa_mmu_post_init(_current_cpu->id == 0); } @@ -504,7 +372,7 @@ __weak void arch_reserved_pages_update(void) static bool l2_page_table_map(uint32_t *l1_table, void *vaddr, uintptr_t phys, uint32_t flags, bool is_user) { - uint32_t l1_pos = (uint32_t)vaddr >> 22; + uint32_t l1_pos = Z_XTENSA_L1_POS((uint32_t)vaddr); uint32_t l2_pos = Z_XTENSA_L2_POS((uint32_t)vaddr); uint32_t *table; @@ -530,6 +398,7 @@ static bool l2_page_table_map(uint32_t *l1_table, void *vaddr, uintptr_t phys, flags); sys_cache_data_flush_range((void *)&table[l2_pos], sizeof(table[0])); + xtensa_tlb_autorefill_invalidate(); return true; } @@ -604,18 +473,6 @@ static inline void __arch_mem_map(void *va, uintptr_t pa, uint32_t xtensa_flags, k_spin_unlock(&z_mem_domain_lock, key); } #endif /* CONFIG_USERSPACE */ - - if ((xtensa_flags & Z_XTENSA_MMU_X) == Z_XTENSA_MMU_X) { - xtensa_itlb_vaddr_invalidate(vaddr); - } - xtensa_dtlb_vaddr_invalidate(vaddr); - - if (IS_ENABLED(CONFIG_XTENSA_MMU_DOUBLE_MAP)) { - if (xtensa_flags & Z_XTENSA_MMU_X) { - xtensa_itlb_vaddr_invalidate(vaddr_uc); - } - xtensa_dtlb_vaddr_invalidate(vaddr_uc); - } } void arch_mem_map(void *virt, uintptr_t phys, size_t size, uint32_t flags) @@ -680,7 +537,7 @@ void arch_mem_map(void *virt, uintptr_t phys, size_t size, uint32_t flags) */ static bool l2_page_table_unmap(uint32_t *l1_table, void *vaddr) { - uint32_t l1_pos = (uint32_t)vaddr >> 22; + uint32_t l1_pos = Z_XTENSA_L1_POS((uint32_t)vaddr); uint32_t l2_pos = Z_XTENSA_L2_POS((uint32_t)vaddr); uint32_t *l2_table; uint32_t table_pos; @@ -717,10 +574,9 @@ static bool l2_page_table_unmap(uint32_t *l1_table, void *vaddr) table_pos = (l2_table - (uint32_t *)l2_page_tables) / (XTENSA_L2_PAGE_TABLE_ENTRIES); atomic_clear_bit(l2_page_tables_track, table_pos); - /* Need to invalidate L2 page table as it is no longer valid. */ - xtensa_dtlb_vaddr_invalidate((void *)l2_table); - end: + /* Need to invalidate L2 page table as it is no longer valid. */ + xtensa_tlb_autorefill_invalidate(); return exec; } @@ -764,18 +620,6 @@ static inline void __arch_mem_unmap(void *va) } k_spin_unlock(&z_mem_domain_lock, key); #endif /* CONFIG_USERSPACE */ - - if (is_exec) { - xtensa_itlb_vaddr_invalidate(vaddr); - } - xtensa_dtlb_vaddr_invalidate(vaddr); - - if (IS_ENABLED(CONFIG_XTENSA_MMU_DOUBLE_MAP)) { - if (is_exec) { - xtensa_itlb_vaddr_invalidate(vaddr_uc); - } - xtensa_dtlb_vaddr_invalidate(vaddr_uc); - } } void arch_mem_unmap(void *addr, size_t size) @@ -853,7 +697,7 @@ void z_xtensa_mmu_tlb_shootdown(void) * MMU_PTE_WAY, so we can skip the probing step by * generating the query entry directly. */ - ptevaddr_entry = Z_XTENSA_PAGE_TABLE_VADDR | MMU_PTE_WAY; + ptevaddr_entry = (uint32_t)xtensa_ptevaddr_get() | Z_XTENSA_MMU_PTE_WAY; ptevaddr = xtensa_dtlb_paddr_read(ptevaddr_entry); thread_ptables = (uint32_t)thread->arch.ptables; @@ -863,7 +707,9 @@ void z_xtensa_mmu_tlb_shootdown(void) * indicated by the current thread are different * than the current mapped page table. */ - switch_page_tables((uint32_t *)thread_ptables, true, true); + struct arch_mem_domain *domain = + &(thread->mem_domain_info.mem_domain->arch); + xtensa_set_paging(domain->asid, (uint32_t *)thread_ptables); } } @@ -981,9 +827,8 @@ static int region_map_update(uint32_t *ptables, uintptr_t start, for (size_t offset = 0; offset < size; offset += CONFIG_MMU_PAGE_SIZE) { uint32_t *l2_table, pte; uint32_t page = start + offset; - uint32_t l1_pos = page >> 22; + uint32_t l1_pos = Z_XTENSA_L1_POS(page); uint32_t l2_pos = Z_XTENSA_L2_POS(page); - /* Make sure we grab a fresh copy of L1 page table */ sys_cache_data_invd_range((void *)&ptables[l1_pos], sizeof(ptables[0])); @@ -998,8 +843,7 @@ static int region_map_update(uint32_t *ptables, uintptr_t start, sys_cache_data_flush_range((void *)&l2_table[l2_pos], sizeof(l2_table[0])); - xtensa_dtlb_vaddr_invalidate( - (void *)(pte & Z_XTENSA_PTE_PPN_MASK)); + xtensa_dtlb_vaddr_invalidate((void *)page); } return ret; @@ -1127,7 +971,7 @@ int arch_mem_domain_thread_add(struct k_thread *thread) * the current thread running. */ if (thread == _current_cpu->current) { - switch_page_tables(thread->arch.ptables, true, true); + xtensa_set_paging(domain->arch.asid, thread->arch.ptables); } #if CONFIG_MP_MAX_NUM_CPUS > 1 @@ -1179,7 +1023,7 @@ static bool page_validate(uint32_t *ptables, uint32_t page, uint8_t ring, bool w { uint8_t asid_ring; uint32_t rasid, pte, *l2_table; - uint32_t l1_pos = page >> 22; + uint32_t l1_pos = Z_XTENSA_L1_POS(page); uint32_t l2_pos = Z_XTENSA_L2_POS(page); if (is_pte_illegal(ptables[l1_pos])) { @@ -1245,12 +1089,7 @@ void z_xtensa_swap_update_page_tables(struct k_thread *incoming) struct arch_mem_domain *domain = &(incoming->mem_domain_info.mem_domain->arch); - /* Lets set the asid for the incoming thread */ - if ((incoming->base.user_options & K_USER) != 0) { - xtensa_rasid_asid_set(domain->asid, Z_XTENSA_USER_RING); - } - - switch_page_tables(ptables, true, false); + xtensa_set_paging(domain->asid, ptables); } #endif /* CONFIG_USERSPACE */ diff --git a/arch/xtensa/include/xtensa-asm2-s.h b/arch/xtensa/include/xtensa-asm2-s.h index 3f3ffd90b7a..416a83453a2 100644 --- a/arch/xtensa/include/xtensa-asm2-s.h +++ b/arch/xtensa/include/xtensa-asm2-s.h @@ -589,31 +589,6 @@ _Level\LVL\()VectorHelper : .global _Level\LVL\()Vector _Level\LVL\()Vector: #endif -#ifdef CONFIG_XTENSA_MMU - wsr.ZSR_MMU_0 a2 - wsr.ZSR_MMU_1 a3 - rsync - - /* Calculations below will clobber registers used. - * So we make a copy of the stack pointer to avoid - * changing it. - */ - mov a3, a1 - - CALC_PTEVADDR_BASE a2 - - /* Preload PTE entry page of current stack. */ - PRELOAD_PTEVADDR a3, a2 - - /* Preload PTE entry page of new stack, where - * it will be used later (in EXCINT_HANDLER above). - */ - rsr.ZSR_CPU a3 - PRELOAD_PTEVADDR a3, a2 - - rsr.ZSR_MMU_1 a3 - rsr.ZSR_MMU_0 a2 -#endif /* CONFIG_XTENSA_MMU */ addi a1, a1, -___xtensa_irq_bsa_t_SIZEOF s32i a0, a1, ___xtensa_irq_bsa_t_a0_OFFSET s32i a2, a1, ___xtensa_irq_bsa_t_a2_OFFSET diff --git a/soc/xtensa/dc233c/mmu.c b/soc/xtensa/dc233c/mmu.c index 718f79779eb..8decc952bf2 100644 --- a/soc/xtensa/dc233c/mmu.c +++ b/soc/xtensa/dc233c/mmu.c @@ -35,33 +35,3 @@ const struct xtensa_mmu_range xtensa_soc_mmu_ranges[] = { }; int xtensa_soc_mmu_ranges_num = ARRAY_SIZE(xtensa_soc_mmu_ranges); - -void arch_xtensa_mmu_post_init(bool is_core0) -{ - uint32_t vecbase; - - ARG_UNUSED(is_core0); - - __asm__ volatile("rsr.vecbase %0" : "=r"(vecbase)); - - /* Invalidate any autorefill instr TLBs of VECBASE so we can map it - * permanently below. - */ - xtensa_itlb_vaddr_invalidate((void *)vecbase); - - /* Map VECBASE permanently in instr TLB way 4 so we will always have - * access to exception handlers. Each way 4 TLB covers 1MB (unless - * ITLBCFG has been changed before this, which should not have - * happened). Also this needs to be mapped as SHARED so both kernel - * and userspace can execute code here => same as .text. - * - * Note that we don't want to map the first 1MB in data TLB as - * we want to keep page 0 (0x00000000) unmapped to catch null pointer - * de-references. - */ - vecbase = ROUND_DOWN(vecbase, MB(1)); - xtensa_itlb_entry_write_sync( - Z_XTENSA_PTE(vecbase, Z_XTENSA_SHARED_RING, - Z_XTENSA_MMU_X | Z_XTENSA_MMU_CACHED_WT), - Z_XTENSA_TLB_ENTRY((uint32_t)vecbase, 4)); -} From d7513fb5260dd4dec4aded2c35d5cd059a6743a6 Mon Sep 17 00:00:00 2001 From: Erwan Gouriou Date: Tue, 14 Nov 2023 16:49:18 +0100 Subject: [PATCH 0047/3723] driver: serial: stm32u5: DMAT Errata behavior valid only on some SoCs Workaround for DMAT errata was applied on all SoCs declaring STM32U5 DMA compatible. This errata has been fixed in later SoCs revisions and should not be applied anymore as this can cause compatibility issues with power mgmt (can not enter STOP1 in some cases). Declare a specific Kconfig symbol to restrict the workaround only to the set of SoCs impacted by the issue and requiring workaround. Note that I preferred using Kconfig over device tree since it doesn't feel right to declare a compatible on a silicon bug base. Signed-off-by: Erwan Gouriou --- drivers/serial/Kconfig.stm32 | 15 +++++++++++++++ drivers/serial/uart_stm32.c | 8 ++++---- 2 files changed, 19 insertions(+), 4 deletions(-) diff --git a/drivers/serial/Kconfig.stm32 b/drivers/serial/Kconfig.stm32 index c6aa6051993..75d0e22c157 100644 --- a/drivers/serial/Kconfig.stm32 +++ b/drivers/serial/Kconfig.stm32 @@ -21,3 +21,18 @@ config UART_STM32 This option enables the UART driver for STM32 family of processors. Say y if you wish to use serial port on STM32 MCU. + +if UART_STM32 + +config UART_STM32U5_ERRATA_DMAT + bool + default y + depends on SOC_STM32U575XX || SOC_STM32U585XX || \ + SOC_STM32H562XX || SOC_STM32H563XX || SOC_STM32H573XX + help + Handles erratum "USART does not generate DMA requests after + setting/clearing DMAT bit". + Seen in Errata Sheet 0499 § 2.19.2 and §2.20.1 for stm32u57x/u58x, + Errata Sheet 0565 § 2.14.1 and §2.15.1 for stm32h56x/h57x + +endif diff --git a/drivers/serial/uart_stm32.c b/drivers/serial/uart_stm32.c index 5c1ff75bd6d..dd79612322d 100644 --- a/drivers/serial/uart_stm32.c +++ b/drivers/serial/uart_stm32.c @@ -1321,7 +1321,7 @@ static inline void uart_stm32_dma_tx_enable(const struct device *dev) static inline void uart_stm32_dma_tx_disable(const struct device *dev) { -#if DT_HAS_COMPAT_STATUS_OKAY(st_stm32u5_dma) +#ifdef CONFIG_UART_STM32U5_ERRATA_DMAT ARG_UNUSED(dev); /* @@ -1333,7 +1333,7 @@ static inline void uart_stm32_dma_tx_disable(const struct device *dev) const struct uart_stm32_config *config = dev->config; LL_USART_DisableDMAReq_TX(config->usart); -#endif /* ! st_stm32u5_dma */ +#endif } static inline void uart_stm32_dma_rx_enable(const struct device *dev) @@ -1633,9 +1633,9 @@ static int uart_stm32_async_tx_abort(const struct device *dev) data->dma_tx.counter = tx_buffer_length - stat.pending_length; } -#if DT_HAS_COMPAT_STATUS_OKAY(st_stm32u5_dma) +#ifdef CONFIG_UART_STM32U5_ERRATA_DMAT dma_suspend(data->dma_tx.dma_dev, data->dma_tx.dma_channel); -#endif /* st_stm32u5_dma */ +#endif dma_stop(data->dma_tx.dma_dev, data->dma_tx.dma_channel); async_evt_tx_abort(data); From 3ee526b4c3fc59cde98f1528f19870a0e148b645 Mon Sep 17 00:00:00 2001 From: Pieter De Gendt Date: Thu, 16 Nov 2023 10:06:02 +0100 Subject: [PATCH 0048/3723] drivers: audio: Codec shell fix compiler warnings This commit fixes the following compiler warnings: * implicit declaration of function 'strtoul'; did you mean 'strtok'? * passing argument 2 of 'parse_named_int' discards 'const' qualifier Signed-off-by: Pieter De Gendt --- drivers/audio/codec_shell.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/drivers/audio/codec_shell.c b/drivers/audio/codec_shell.c index 6fb47d11184..b5c3421bf26 100644 --- a/drivers/audio/codec_shell.c +++ b/drivers/audio/codec_shell.c @@ -4,6 +4,7 @@ * SPDX-License-Identifier: Apache-2.0 */ +#include #include #include @@ -55,7 +56,7 @@ static const struct args_index args_indx = { .value = 4, }; -static int parse_named_int(const char *name, const char *keystack[], size_t count) +static int parse_named_int(const char *name, const char *const keystack[], size_t count) { char *endptr; int i; From ca7ce90dc7b4ad7e8835718b7c60cb7409102500 Mon Sep 17 00:00:00 2001 From: Ibe Van de Veire Date: Tue, 14 Nov 2023 11:15:57 +0100 Subject: [PATCH 0049/3723] net: ip: utils: changed input arguments of igmp_checksum to net_pkt Added igmpv3 checksum function to make it possible to calculate the checksum of a complete igmpv3 pkt at once. Signed-off-by: Ibe Van de Veire --- subsys/net/ip/Kconfig.ipv4 | 8 +++++++- subsys/net/ip/igmp.c | 5 ++--- subsys/net/ip/net_private.h | 4 ++-- subsys/net/ip/utils.c | 11 +++-------- 4 files changed, 14 insertions(+), 14 deletions(-) diff --git a/subsys/net/ip/Kconfig.ipv4 b/subsys/net/ip/Kconfig.ipv4 index a5e073051de..3158fe43e41 100644 --- a/subsys/net/ip/Kconfig.ipv4 +++ b/subsys/net/ip/Kconfig.ipv4 @@ -50,7 +50,7 @@ config NET_IPV4_ACCEPT_ZERO_BROADCAST 0.0.0.0 broadcast address as described in RFC 1122 ch. 3.3.6 config NET_IPV4_IGMP - bool "Internet Group Management Protocol (IGMP) support" + bool "Internet Group Management Protocol (IGMPv2) support" select NET_IPV4_HDR_OPTIONS help The value depends on your network needs. IGMP should normally be @@ -59,6 +59,12 @@ config NET_IPV4_IGMP because IP Router Alert option must be sent. See RFC 2236 for details. +config NET_IPV4_IGMPV3 + bool "Internet Group Management Protocol version 3 (IGMPv3) support" + depends on NET_IPV4_IGMP + help + Use IGMPv3 for managing the multicast groups. + config NET_DHCPV4 bool "DHCPv4 client" select NET_MGMT diff --git a/subsys/net/ip/igmp.c b/subsys/net/ip/igmp.c index f09aecc4bf9..a8ecc0d28f9 100644 --- a/subsys/net/ip/igmp.c +++ b/subsys/net/ip/igmp.c @@ -56,7 +56,7 @@ static int igmp_v2_create(struct net_pkt *pkt, const struct in_addr *addr, igmp->max_rsp = 0U; net_ipaddr_copy(&igmp->address, addr); igmp->chksum = 0; - igmp->chksum = net_calc_chksum_igmp((uint8_t *)igmp, sizeof(*igmp)); + igmp->chksum = net_calc_chksum_igmp(pkt); if (net_pkt_set_data(pkt, &igmp_access)) { return -ENOBUFS; @@ -217,8 +217,7 @@ enum net_verdict net_ipv4_igmp_input(struct net_pkt *pkt, return NET_DROP; } - if (net_calc_chksum_igmp((uint8_t *)igmp_hdr, - sizeof(*igmp_hdr)) != 0U) { + if (net_calc_chksum_igmp(pkt)) { NET_DBG("DROP: Invalid checksum"); goto drop; } diff --git a/subsys/net/ip/net_private.h b/subsys/net/ip/net_private.h index 0906a7a28b1..2fd0928b170 100644 --- a/subsys/net/ip/net_private.h +++ b/subsys/net/ip/net_private.h @@ -230,12 +230,12 @@ void net_ipv4_igmp_init(struct net_if *iface); #endif /* CONFIG_NET_IPV4_IGMP */ #if defined(CONFIG_NET_IPV4_IGMP) -uint16_t net_calc_chksum_igmp(uint8_t *data, size_t len); +uint16_t net_calc_chksum_igmp(struct net_pkt *pkt); enum net_verdict net_ipv4_igmp_input(struct net_pkt *pkt, struct net_ipv4_hdr *ip_hdr); #else #define net_ipv4_igmp_input(...) -#define net_calc_chksum_igmp(data, len) 0U +#define net_calc_chksum_igmp(struct net_pkt *pkt) 0U #endif /* CONFIG_NET_IPV4_IGMP */ static inline uint16_t net_calc_chksum_icmpv6(struct net_pkt *pkt) diff --git a/subsys/net/ip/utils.c b/subsys/net/ip/utils.c index 0e3bbce5d33..a1b3facd905 100644 --- a/subsys/net/ip/utils.c +++ b/subsys/net/ip/utils.c @@ -644,7 +644,7 @@ uint16_t net_calc_chksum(struct net_pkt *pkt, uint8_t proto) if (IS_ENABLED(CONFIG_NET_IPV4) && net_pkt_family(pkt) == AF_INET) { - if (proto != IPPROTO_ICMP) { + if (proto != IPPROTO_ICMP && proto != IPPROTO_IGMP) { len = 2 * sizeof(struct in_addr); sum = net_pkt_get_len(pkt) - net_pkt_ip_hdr_len(pkt) - @@ -700,14 +700,9 @@ uint16_t net_calc_chksum_ipv4(struct net_pkt *pkt) #endif /* CONFIG_NET_IPV4 */ #if defined(CONFIG_NET_IPV4_IGMP) -uint16_t net_calc_chksum_igmp(uint8_t *data, size_t len) +uint16_t net_calc_chksum_igmp(struct net_pkt *pkt) { - uint16_t sum; - - sum = calc_chksum(0, data, len); - sum = (sum == 0U) ? 0xffff : htons(sum); - - return ~sum; + return net_calc_chksum(pkt, IPPROTO_IGMP); } #endif /* CONFIG_NET_IPV4_IGMP */ From 1d0f47b00576bbd8b0ac3e3d468ea4f7a5d78f8d Mon Sep 17 00:00:00 2001 From: Ibe Van de Veire Date: Thu, 16 Nov 2023 10:36:56 +0100 Subject: [PATCH 0050/3723] net: ip: igmp: add igmpv3 support Added igmpv3 support based on the already existing structure for igmpv2. The already existing api is not modified to prevent breaking exisiting applications. Signed-off-by: Ibe Van de Veire --- include/zephyr/net/igmp.h | 15 +- include/zephyr/net/net_if.h | 11 + subsys/net/ip/Kconfig.ipv4 | 4 + subsys/net/ip/igmp.c | 390 +++++++++++++++++++++++++-- subsys/net/ip/ipv4.h | 53 ++++ subsys/net/ip/net_private.h | 2 +- subsys/net/lib/dns/llmnr_responder.c | 4 +- subsys/net/lib/dns/mdns_responder.c | 4 +- subsys/net/lib/shell/ipv4.c | 2 +- tests/net/igmp/src/main.c | 2 +- 10 files changed, 451 insertions(+), 36 deletions(-) diff --git a/include/zephyr/net/igmp.h b/include/zephyr/net/igmp.h index 7119676f237..ed39a31359f 100644 --- a/include/zephyr/net/igmp.h +++ b/include/zephyr/net/igmp.h @@ -27,22 +27,31 @@ extern "C" { #endif +struct igmp_param { + struct in_addr *source_list; /* List of sources to include or exclude */ + size_t sources_len; /* Length of source list */ + bool include; /* Source list filter type */ +}; + /** * @brief Join a given multicast group. * * @param iface Network interface where join message is sent * @param addr Multicast group to join + * @param param Optional parameters * * @return Return 0 if joining was done, <0 otherwise. */ #if defined(CONFIG_NET_IPV4_IGMP) -int net_ipv4_igmp_join(struct net_if *iface, const struct in_addr *addr); +int net_ipv4_igmp_join(struct net_if *iface, const struct in_addr *addr, + const struct igmp_param *param); #else -static inline int net_ipv4_igmp_join(struct net_if *iface, - const struct in_addr *addr) +static inline int net_ipv4_igmp_join(struct net_if *iface, const struct in_addr *addr, + const struct igmp_param *param) { ARG_UNUSED(iface); ARG_UNUSED(addr); + ARG_UNUSED(param); return -ENOSYS; } diff --git a/include/zephyr/net/net_if.h b/include/zephyr/net/net_if.h index 788c3316391..1780adeb5ca 100644 --- a/include/zephyr/net/net_if.h +++ b/include/zephyr/net/net_if.h @@ -94,6 +94,17 @@ struct net_if_mcast_addr { /** IP address */ struct net_addr address; +#if defined(CONFIG_NET_IPV4_IGMPV3) + /** Sources to filter on */ + struct net_addr sources[CONFIG_NET_IF_MCAST_IPV4_SOURCE_COUNT]; + + /** Number of sources to be used by the filter */ + uint16_t sources_len; + + /** Filter mode (used in IGMPV3) */ + uint8_t record_type; +#endif + /** Is this multicast IP address used or not */ uint8_t is_used : 1; diff --git a/subsys/net/ip/Kconfig.ipv4 b/subsys/net/ip/Kconfig.ipv4 index 3158fe43e41..e5d30cfc27c 100644 --- a/subsys/net/ip/Kconfig.ipv4 +++ b/subsys/net/ip/Kconfig.ipv4 @@ -37,6 +37,10 @@ config NET_IF_MCAST_IPV4_ADDR_COUNT default 2 if NET_IPV4_IGMP default 1 +config NET_IF_MCAST_IPV4_SOURCE_COUNT + int "Max number of IPv4 sources per mcast address to be included or excluded" + default 1 + config NET_ICMPV4_ACCEPT_BROADCAST bool "Accept broadcast ICMPv4 echo-request" help diff --git a/subsys/net/ip/igmp.c b/subsys/net/ip/igmp.c index a8ecc0d28f9..3cd7be7de49 100644 --- a/subsys/net/ip/igmp.c +++ b/subsys/net/ip/igmp.c @@ -28,8 +28,18 @@ LOG_MODULE_DECLARE(net_ipv4, CONFIG_NET_IPV4_LOG_LEVEL); #define IPV4_OPT_HDR_ROUTER_ALERT_LEN 4 +#define IGMPV3_MODE_IS_INCLUDE 0x01 +#define IGMPV3_MODE_IS_EXCLUDE 0x02 +#define IGMPV3_CHANGE_TO_INCLUDE_MODE 0x03 +#define IGMPV3_CHANGE_TO_EXCLUDE_MODE 0x04 +#define IGMPV3_ALLOW_NEW_SOURCES 0x05 +#define IGMPV3_BLOCK_OLD_SOURCES 0x06 + static const struct in_addr all_systems = { { { 224, 0, 0, 1 } } }; static const struct in_addr all_routers = { { { 224, 0, 0, 2 } } }; +#if defined(CONFIG_NET_IPV4_IGMPV3) +static const struct in_addr igmp_multicast_addr = { { { 224, 0, 0, 22 } } }; +#endif #define dbg_addr(action, pkt_str, src, dst) \ NET_DBG("%s %s from %s to %s", action, pkt_str, \ @@ -39,6 +49,12 @@ static const struct in_addr all_routers = { { { 224, 0, 0, 2 } } }; #define dbg_addr_recv(pkt_str, src, dst) \ dbg_addr("Received", pkt_str, src, dst) +enum igmp_version { + IGMPV1, + IGMPV2, + IGMPV3, +}; + static int igmp_v2_create(struct net_pkt *pkt, const struct in_addr *addr, uint8_t type) { @@ -56,14 +72,118 @@ static int igmp_v2_create(struct net_pkt *pkt, const struct in_addr *addr, igmp->max_rsp = 0U; net_ipaddr_copy(&igmp->address, addr); igmp->chksum = 0; + + if (net_pkt_set_data(pkt, &igmp_access)) { + return -ENOBUFS; + } + igmp->chksum = net_calc_chksum_igmp(pkt); + net_pkt_set_overwrite(pkt, true); + net_pkt_cursor_init(pkt); + + net_pkt_skip(pkt, offsetof(struct net_ipv4_igmp_v2_report, chksum)); + if (net_pkt_write(pkt, &igmp->chksum, sizeof(igmp->chksum))) { + return -ENOBUFS; + } + + return 0; +} + +#if defined(CONFIG_NET_IPV4_IGMPV3) +static int igmp_v3_create(struct net_pkt *pkt, uint8_t type, struct net_if_mcast_addr mcast[], + size_t mcast_len) +{ + NET_PKT_DATA_ACCESS_DEFINE(igmp_access, struct net_ipv4_igmp_v3_report); + NET_PKT_DATA_ACCESS_DEFINE(group_record_access, struct net_ipv4_igmp_v3_group_record); + struct net_ipv4_igmp_v3_report *igmp; + struct net_ipv4_igmp_v3_group_record *group_record; + + uint16_t group_count = 0; + + igmp = (struct net_ipv4_igmp_v3_report *)net_pkt_get_data(pkt, &igmp_access); + if (!igmp) { + return -ENOBUFS; + } + + for (int i = 0; i < mcast_len; i++) { + /* We don't need to send an IGMP membership report to the IGMP + * all systems multicast address of 224.0.0.1 so skip over it. + * Since the IGMP all systems multicast address is marked as + * used and joined during init time, we have to check this + * address separately to skip over it. + */ + if (!mcast[i].is_used || !mcast[i].is_joined || + net_ipv4_addr_cmp_raw((uint8_t *)&mcast[i].address.in_addr, + (uint8_t *)&all_systems)) { + continue; + } + + group_count++; + } + + igmp->type = type; + igmp->reserved_1 = 0U; + igmp->reserved_2 = 0U; + igmp->groups_len = htons(group_count); + /* Setting initial value of chksum to 0 to calculate chksum as described in RFC 3376 + * ch 4.1.2 + */ + igmp->chksum = 0; + if (net_pkt_set_data(pkt, &igmp_access)) { return -ENOBUFS; } + for (int i = 0; i < mcast_len; i++) { + /* We don't need to send an IGMP membership report to the IGMP + * all systems multicast address of 224.0.0.1 so skip over it. + * Since the IGMP all systems multicast address is marked as + * used and joined during init time, we have to check this + * address separately to skip over it. + */ + if (!mcast[i].is_used || !mcast[i].is_joined || + net_ipv4_addr_cmp_raw((uint8_t *)&mcast[i].address.in_addr, + (uint8_t *)&all_systems)) { + continue; + } + + group_record = (struct net_ipv4_igmp_v3_group_record *)net_pkt_get_data( + pkt, &group_record_access); + if (!group_record) { + return -ENOBUFS; + } + + group_record->type = mcast[i].record_type; + group_record->aux_len = 0U; + net_ipaddr_copy(&group_record->address, &mcast[i].address.in_addr); + group_record->sources_len = htons(mcast[i].sources_len); + + if (net_pkt_set_data(pkt, &group_record_access)) { + return -ENOBUFS; + } + + for (int j = 0; j < mcast[i].sources_len; j++) { + if (net_pkt_write(pkt, &mcast[i].sources[j].in_addr.s_addr, + sizeof(mcast[i].sources[j].in_addr.s_addr))) { + return -ENOBUFS; + } + } + } + + igmp->chksum = net_calc_chksum_igmp(pkt); + + net_pkt_set_overwrite(pkt, true); + net_pkt_cursor_init(pkt); + + net_pkt_skip(pkt, offsetof(struct net_ipv4_igmp_v3_report, chksum)); + if (net_pkt_write(pkt, &igmp->chksum, sizeof(igmp->chksum))) { + return -ENOBUFS; + } + return 0; } +#endif static int igmp_v2_create_packet(struct net_pkt *pkt, const struct in_addr *dst, const struct in_addr *group, uint8_t type) @@ -95,6 +215,30 @@ static int igmp_v2_create_packet(struct net_pkt *pkt, const struct in_addr *dst, return igmp_v2_create(pkt, group, type); } +#if defined(CONFIG_NET_IPV4_IGMPV3) +static int igmp_v3_create_packet(struct net_pkt *pkt, const struct in_addr *dst, + struct net_if_mcast_addr mcast[], size_t mcast_len, uint8_t type) +{ + const uint32_t router_alert = 0x94040000; /* RFC 2213 ch 2.1 */ + int ret; + + ret = net_ipv4_create_full(pkt, net_if_ipv4_select_src_addr(net_pkt_iface(pkt), dst), dst, + 0U, 0U, 0U, 0U, 1U); /* TTL set to 1, RFC 3376 ch 2 */ + if (ret) { + return -ENOBUFS; + } + + /* Add router alert option, RFC 3376 ch 2 */ + if (net_pkt_write_be32(pkt, router_alert)) { + return -ENOBUFS; + } + + net_pkt_set_ipv4_opts_len(pkt, IPV4_OPT_HDR_ROUTER_ALERT_LEN); + + return igmp_v3_create(pkt, type, mcast, mcast_len); +} +#endif + static int igmp_send(struct net_pkt *pkt) { int ret; @@ -195,41 +339,156 @@ static int send_igmp_report(struct net_if *iface, return ret; } -enum net_verdict net_ipv4_igmp_input(struct net_pkt *pkt, - struct net_ipv4_hdr *ip_hdr) +#if defined(CONFIG_NET_IPV4_IGMPV3) +static int send_igmp_v3_report(struct net_if *iface, struct net_ipv4_igmp_v3_query *igmp_v3_hdr) { - NET_PKT_DATA_ACCESS_CONTIGUOUS_DEFINE(igmp_access, - struct net_ipv4_igmp_v2_query); - struct net_ipv4_igmp_v2_query *igmp_hdr; + struct net_if_ipv4 *ipv4 = iface->config.ip.ipv4; + struct net_pkt *pkt = NULL; + int i, group_count = 0, source_count = 0; + int ret = 0; + + if (!ipv4) { + return -ENOENT; + } - /* TODO: receive from arbitrary group address instead of - * all_systems + for (i = 0; i < NET_IF_MAX_IPV4_MADDR; i++) { + /* We don't need to send an IGMP membership report to the IGMP + * all systems multicast address of 224.0.0.1 so skip over it. + * Since the IGMP all systems multicast address is marked as + * used and joined during init time, we have to check this + * address separately to skip over it. + */ + if (!ipv4->mcast[i].is_used || !ipv4->mcast[i].is_joined || + net_ipv4_addr_cmp_raw((uint8_t *)&ipv4->mcast[i].address.in_addr, + (uint8_t *)&all_systems)) { + continue; + } + + group_count++; + source_count += ipv4->mcast[i].sources_len; + } + + if (group_count == 0) { + return -ESRCH; + } + + pkt = net_pkt_alloc_with_buffer( + iface, + IPV4_OPT_HDR_ROUTER_ALERT_LEN + sizeof(struct net_ipv4_igmp_v3_report) + + sizeof(struct net_ipv4_igmp_v3_group_record) * group_count + + sizeof(struct in_addr) * source_count, + AF_INET, IPPROTO_IGMP, PKT_WAIT_TIME); + if (!pkt) { + return -ENOMEM; + } + + /* Send the IGMP V3 membership report to the igmp multicast + * address, as per RFC 3376 Section 4.2.14. */ + + ret = igmp_v3_create_packet(pkt, &igmp_multicast_addr, ipv4->mcast, NET_IF_MAX_IPV4_MADDR, + NET_IPV4_IGMP_REPORT_V3); + if (ret < 0) { + goto drop; + } + + ret = igmp_send(pkt); + if (ret < 0) { + goto drop; + } + + /* So that we do not free the data while it is being sent */ + pkt = NULL; + +drop: + if (pkt) { + net_pkt_unref(pkt); + } + + return ret; +} +#endif + +enum net_verdict net_ipv4_igmp_input(struct net_pkt *pkt, struct net_ipv4_hdr *ip_hdr) +{ +#if defined(CONFIG_NET_IPV4_IGMPV3) + NET_PKT_DATA_ACCESS_CONTIGUOUS_DEFINE(igmpv3_access, struct net_ipv4_igmp_v3_query); + struct net_ipv4_igmp_v3_query *igmpv3_hdr; +#endif + NET_PKT_DATA_ACCESS_CONTIGUOUS_DEFINE(igmpv2_access, struct net_ipv4_igmp_v2_query); + struct net_ipv4_igmp_v2_query *igmpv2_hdr; + enum igmp_version version; + int ret; + int igmp_buf_len = pkt->buffer->len - net_pkt_ip_hdr_len(pkt); + + /* Detect IGMP type (RFC 3376 ch 7.1) */ + if (igmp_buf_len == 8) { + /* IGMPv1/2 detected */ + version = IGMPV2; + } else if (igmp_buf_len >= 12) { + /* IGMPv3 detected */ + version = IGMPV3; +#if !defined(CONFIG_NET_IPV4_IGMPV3) + NET_DBG("DROP: %sv3 msg received but %s support is disabled", "IGMP", "IGMP"); + return NET_DROP; +#endif + } else { + NET_DBG("DROP: unsupported payload length"); + return NET_DROP; + } + if (!net_ipv4_addr_cmp_raw(ip_hdr->dst, (uint8_t *)&all_systems)) { NET_DBG("DROP: Invalid dst address"); return NET_DROP; } - igmp_hdr = (struct net_ipv4_igmp_v2_query *)net_pkt_get_data(pkt, - &igmp_access); - if (!igmp_hdr) { - NET_DBG("DROP: NULL IGMP header"); - return NET_DROP; +#if defined(CONFIG_NET_IPV4_IGMPV3) + if (version == IGMPV3) { + igmpv3_hdr = (struct net_ipv4_igmp_v3_query *)net_pkt_get_data(pkt, &igmpv3_access); + if (!igmpv3_hdr) { + NET_DBG("DROP: NULL %sv3 header", "IGMP"); + return NET_DROP; + } + } else { +#endif + igmpv2_hdr = (struct net_ipv4_igmp_v2_query *)net_pkt_get_data(pkt, &igmpv2_access); + if (!igmpv2_hdr) { + NET_DBG("DROP: NULL %s header", "IGMP"); + return NET_DROP; + } +#if defined(CONFIG_NET_IPV4_IGMPV3) } +#endif - if (net_calc_chksum_igmp(pkt)) { + ret = net_calc_chksum_igmp(pkt); + if (ret != 0u) { NET_DBG("DROP: Invalid checksum"); goto drop; } - net_pkt_acknowledge_data(pkt, &igmp_access); +#if defined(CONFIG_NET_IPV4_IGMPV3) + if (version == IGMPV3) { + net_pkt_acknowledge_data(pkt, &igmpv3_access); + } else { +#endif + net_pkt_acknowledge_data(pkt, &igmpv2_access); +#if defined(CONFIG_NET_IPV4_IGMPV3) + } +#endif - dbg_addr_recv("Internet Group Management Protocol", &ip_hdr->src, - &ip_hdr->dst); + dbg_addr_recv("Internet Group Management Protocol", &ip_hdr->src, &ip_hdr->dst); net_stats_update_ipv4_igmp_recv(net_pkt_iface(pkt)); - (void)send_igmp_report(net_pkt_iface(pkt), igmp_hdr); +#if defined(CONFIG_NET_IPV4_IGMPV3) + if (version == IGMPV3) { + (void)send_igmp_v3_report(net_pkt_iface(pkt), igmpv3_hdr); + } else { +#endif + (void)send_igmp_report(net_pkt_iface(pkt), igmpv2_hdr); +#if defined(CONFIG_NET_IPV4_IGMPV3) + } +#endif net_pkt_unref(pkt); @@ -241,6 +500,7 @@ enum net_verdict net_ipv4_igmp_input(struct net_pkt *pkt, return NET_DROP; } +#if !defined(CONFIG_NET_IPV4_IGMPV3) static int igmp_send_generic(struct net_if *iface, const struct in_addr *addr, bool join) @@ -280,12 +540,57 @@ static int igmp_send_generic(struct net_if *iface, return ret; } +#endif + +#if defined(CONFIG_NET_IPV4_IGMPV3) +static int igmpv3_send_generic(struct net_if *iface, struct net_if_mcast_addr *mcast) +{ + struct net_pkt *pkt; + int ret; + + pkt = net_pkt_alloc_with_buffer(iface, + IPV4_OPT_HDR_ROUTER_ALERT_LEN + + sizeof(struct net_ipv4_igmp_v3_report) + + sizeof(struct net_ipv4_igmp_v3_group_record) + + sizeof(struct in_addr) * mcast->sources_len, + AF_INET, IPPROTO_IGMP, PKT_WAIT_TIME); + if (!pkt) { + return -ENOMEM; + } + + ret = igmp_v3_create_packet(pkt, &igmp_multicast_addr, mcast, 1, NET_IPV4_IGMP_REPORT_V3); + if (ret < 0) { + goto drop; + } + + ret = igmp_send(pkt); + if (ret < 0) { + goto drop; + } + + return 0; + +drop: + net_pkt_unref(pkt); + + return ret; +} +#endif -int net_ipv4_igmp_join(struct net_if *iface, const struct in_addr *addr) +int net_ipv4_igmp_join(struct net_if *iface, const struct in_addr *addr, + const struct igmp_param *param) { struct net_if_mcast_addr *maddr; int ret; +#if defined(CONFIG_NET_IPV4_IGMPV3) + if (param != NULL) { + if (param->sources_len > CONFIG_NET_IF_MCAST_IPV4_SOURCE_COUNT) { + return -ENOMEM; + } + } +#endif + maddr = net_if_ipv4_maddr_lookup(addr, &iface); if (maddr && net_if_ipv4_maddr_is_joined(maddr)) { return -EALREADY; @@ -298,18 +603,45 @@ int net_ipv4_igmp_join(struct net_if *iface, const struct in_addr *addr) } } +#if defined(CONFIG_NET_IPV4_IGMPV3) + if (param != NULL) { + maddr->record_type = param->include ? IGMPV3_CHANGE_TO_INCLUDE_MODE + : IGMPV3_CHANGE_TO_EXCLUDE_MODE; + maddr->sources_len = param->sources_len; + for (int i = 0; i < param->sources_len; i++) { + net_ipaddr_copy(&maddr->sources[i].in_addr.s_addr, + ¶m->source_list[i].s_addr); + } + } else { + maddr->record_type = IGMPV3_CHANGE_TO_EXCLUDE_MODE; + } +#endif + + net_if_ipv4_maddr_join(iface, maddr); + +#if defined(CONFIG_NET_IPV4_IGMPV3) + ret = igmpv3_send_generic(iface, maddr); +#else ret = igmp_send_generic(iface, addr, true); +#endif if (ret < 0) { + net_if_ipv4_maddr_leave(iface, maddr); return ret; } - net_if_ipv4_maddr_join(iface, maddr); +#if defined(CONFIG_NET_IPV4_IGMPV3) + if (param != NULL) { + /* Updating the record type for further use after sending the join report */ + maddr->record_type = + param->include ? IGMPV3_MODE_IS_INCLUDE : IGMPV3_MODE_IS_EXCLUDE; + } +#endif net_if_mcast_monitor(iface, &maddr->address, true); - net_mgmt_event_notify_with_info(NET_EVENT_IPV4_MCAST_JOIN, iface, - &maddr->address.in_addr, + net_mgmt_event_notify_with_info(NET_EVENT_IPV4_MCAST_JOIN, iface, &maddr->address.in_addr, sizeof(struct in_addr)); + return ret; } @@ -323,21 +655,27 @@ int net_ipv4_igmp_leave(struct net_if *iface, const struct in_addr *addr) return -ENOENT; } - if (!net_if_ipv4_maddr_rm(iface, addr)) { - return -EINVAL; - } +#if defined(CONFIG_NET_IPV4_IGMPV3) + maddr->record_type = IGMPV3_CHANGE_TO_INCLUDE_MODE; + maddr->sources_len = 0; + ret = igmpv3_send_generic(iface, maddr); +#else ret = igmp_send_generic(iface, addr, false); +#endif if (ret < 0) { return ret; } + if (!net_if_ipv4_maddr_rm(iface, addr)) { + return -EINVAL; + } + net_if_ipv4_maddr_leave(iface, maddr); net_if_mcast_monitor(iface, &maddr->address, false); - net_mgmt_event_notify_with_info(NET_EVENT_IPV4_MCAST_LEAVE, iface, - &maddr->address.in_addr, + net_mgmt_event_notify_with_info(NET_EVENT_IPV4_MCAST_LEAVE, iface, &maddr->address.in_addr, sizeof(struct in_addr)); return ret; } diff --git a/subsys/net/ip/ipv4.h b/subsys/net/ip/ipv4.h index 1359d04bc03..1d7d64fd0b5 100644 --- a/subsys/net/ip/ipv4.h +++ b/subsys/net/ip/ipv4.h @@ -50,19 +50,72 @@ #define NET_IPV4_IGMP_REPORT_V3 0x22 /* v3 Membership report */ struct net_ipv4_igmp_v2_query { + /* IGMP message type */ uint8_t type; + /* Max response code */ uint8_t max_rsp; + /* 16-bit ones' complement of the entire message */ uint16_t chksum; + /* The multicast address being queried */ struct in_addr address; } __packed; struct net_ipv4_igmp_v2_report { + /* IGMP message type */ uint8_t type; + /* Max response code */ uint8_t max_rsp; + /* 16-bit ones' complement of the entire message */ uint16_t chksum; + /* The multicast address being queried */ struct in_addr address; } __packed; +struct net_ipv4_igmp_v3_query { + /* IGMP message type */ + uint8_t type; + /* Max response code */ + uint8_t max_rsp; + /* 16-bit ones' complement of the entire message */ + uint16_t chksum; + /* The multicast address being queried */ + struct in_addr address; + /* Reserved field, ignore */ + uint8_t reserved: 4; + /* Suppress Router-side Processing Flag */ + uint8_t suppress: 1; + /* Querier's Robustness Variable */ + uint8_t qrv: 3; + /* Querier's Query Interval Code */ + uint8_t qqic; + /* Number of Source Addresses */ + uint16_t sources_len; +} __packed; + +struct net_ipv4_igmp_v3_group_record { + /* Record type */ + uint8_t type; + /* Aux Data Len */ + uint8_t aux_len; + /* Number of Source Addresses */ + uint16_t sources_len; + /* The multicast address to report to*/ + struct in_addr address; +} __packed; + +struct net_ipv4_igmp_v3_report { + /* IGMP message type */ + uint8_t type; + /* Reserved field, ignore */ + uint8_t reserved_1; + /* 16-bit ones' complement of the entire message */ + uint16_t chksum; + /* Reserved field, ignore */ + uint16_t reserved_2; + /* Number of Group Records */ + uint16_t groups_len; +} __packed; + /** * @brief Create IPv4 packet in provided net_pkt with option to set all the * caller settable values. diff --git a/subsys/net/ip/net_private.h b/subsys/net/ip/net_private.h index 2fd0928b170..73b15ae4cfa 100644 --- a/subsys/net/ip/net_private.h +++ b/subsys/net/ip/net_private.h @@ -235,7 +235,7 @@ enum net_verdict net_ipv4_igmp_input(struct net_pkt *pkt, struct net_ipv4_hdr *ip_hdr); #else #define net_ipv4_igmp_input(...) -#define net_calc_chksum_igmp(struct net_pkt *pkt) 0U +#define net_calc_chksum_igmp(pkt) 0U #endif /* CONFIG_NET_IPV4_IGMP */ static inline uint16_t net_calc_chksum_icmpv6(struct net_pkt *pkt) diff --git a/subsys/net/lib/dns/llmnr_responder.c b/subsys/net/lib/dns/llmnr_responder.c index e52e986d145..0c41b7df424 100644 --- a/subsys/net/lib/dns/llmnr_responder.c +++ b/subsys/net/lib/dns/llmnr_responder.c @@ -118,7 +118,7 @@ static void llmnr_iface_event_handler(struct net_mgmt_event_callback *cb, { if (mgmt_event == NET_EVENT_IF_UP) { #if defined(CONFIG_NET_IPV4) - int ret = net_ipv4_igmp_join(iface, &local_addr4.sin_addr); + int ret = net_ipv4_igmp_join(iface, &local_addr4.sin_addr, NULL); if (ret < 0) { NET_DBG("Cannot add IPv4 multicast address to iface %p", @@ -592,7 +592,7 @@ static void iface_ipv4_cb(struct net_if *iface, void *user_data) struct in_addr *addr = user_data; int ret; - ret = net_ipv4_igmp_join(iface, addr); + ret = net_ipv4_igmp_join(iface, addr, NULL); if (ret < 0) { NET_DBG("Cannot add IPv4 multicast address to iface %p", iface); diff --git a/subsys/net/lib/dns/mdns_responder.c b/subsys/net/lib/dns/mdns_responder.c index 04acbabbecd..4b8ad11dc1b 100644 --- a/subsys/net/lib/dns/mdns_responder.c +++ b/subsys/net/lib/dns/mdns_responder.c @@ -94,7 +94,7 @@ static void mdns_iface_event_handler(struct net_mgmt_event_callback *cb, { if (mgmt_event == NET_EVENT_IF_UP) { #if defined(CONFIG_NET_IPV4) - int ret = net_ipv4_igmp_join(iface, &local_addr4.sin_addr); + int ret = net_ipv4_igmp_join(iface, &local_addr4.sin_addr, NULL); if (ret < 0) { NET_DBG("Cannot add IPv4 multicast address to iface %p", @@ -634,7 +634,7 @@ static void iface_ipv4_cb(struct net_if *iface, void *user_data) struct in_addr *addr = user_data; int ret; - ret = net_ipv4_igmp_join(iface, addr); + ret = net_ipv4_igmp_join(iface, addr, NULL); if (ret < 0) { NET_DBG("Cannot add IPv4 multicast address to iface %p", iface); diff --git a/subsys/net/lib/shell/ipv4.c b/subsys/net/lib/shell/ipv4.c index 8fc88168c9a..752b1cda046 100644 --- a/subsys/net/lib/shell/ipv4.c +++ b/subsys/net/lib/shell/ipv4.c @@ -118,7 +118,7 @@ static int cmd_net_ip_add(const struct shell *sh, size_t argc, char *argv[]) if (net_ipv4_is_addr_mcast(&addr)) { int ret; - ret = net_ipv4_igmp_join(iface, &addr); + ret = net_ipv4_igmp_join(iface, &addr, NULL); if (ret < 0) { PR_ERROR("Cannot %s multicast group %s for interface %d (%d)\n", "join", net_sprint_ipv4_addr(&addr), idx, ret); diff --git a/tests/net/igmp/src/main.c b/tests/net/igmp/src/main.c index 473b66d3241..ca43c33d164 100644 --- a/tests/net/igmp/src/main.c +++ b/tests/net/igmp/src/main.c @@ -236,7 +236,7 @@ static void join_group(void) { int ret; - ret = net_ipv4_igmp_join(net_iface, &mcast_addr); + ret = net_ipv4_igmp_join(net_iface, &mcast_addr, NULL); if (ignore_already) { zassert_true(ret == 0 || ret == -EALREADY, From a43e516ff2f7bc7091835bf9a97c979937a75366 Mon Sep 17 00:00:00 2001 From: Ibe Van de Veire Date: Tue, 21 Nov 2023 11:53:39 +0100 Subject: [PATCH 0051/3723] doc: migration guide: add note about IGMP migration Added note about the migration steps needed to support the new IGMP api. The api now expects an additional argument used for joining an IGMPv3 group. Signed-off-by: Ibe Van de Veire --- doc/releases/migration-guide-3.6.rst | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/doc/releases/migration-guide-3.6.rst b/doc/releases/migration-guide-3.6.rst index c4b93e5f150..aed44043e3f 100644 --- a/doc/releases/migration-guide-3.6.rst +++ b/doc/releases/migration-guide-3.6.rst @@ -139,6 +139,13 @@ Networking ``request`` argument for :c:func:`coap_well_known_core_get` is made ``const``. (:github:`64265`) +* The IGMP multicast library now supports IGMPv3. This results in a minor change to the existing + api. The :c:func:`net_ipv4_igmp_join` now takes an additional argument of the type + ``const struct igmp_param *param``. This allows IGMPv3 to exclude/include certain groups of + addresses. If this functionality is not used or available (when using IGMPv2), you can safely pass + a NULL pointer. IGMPv3 can be enabled using the Kconfig ``CONFIG_NET_IPV4_IGMPV3``. + (:github:`65293`) + Other Subsystems ================ From a38c8d25e7b387ead1ded76d372c918e3147ba4c Mon Sep 17 00:00:00 2001 From: Erwan Gouriou Date: Tue, 21 Nov 2023 16:59:27 +0100 Subject: [PATCH 0052/3723] drivers: serial: stm32u5: Serial wakeup is based on autonomous capability On some devices such as STM32U5, there is no UART WKUP dedicated registers as the hardware block has an integrated autonomous wakeup capability. Hence it's capable to wake up the device from stop modes (down to Stop 1). This behavior relies on RCC UESM bit which is enabled by default at reset and not modified today in drivers. Since driver will not compile otherwise, remain in this simple configuration. This might be changed later on, if a need is seen to disable UESM bit. Signed-off-by: Erwan Gouriou --- drivers/serial/uart_stm32.c | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/drivers/serial/uart_stm32.c b/drivers/serial/uart_stm32.c index dd79612322d..097ba70c1b6 100644 --- a/drivers/serial/uart_stm32.c +++ b/drivers/serial/uart_stm32.c @@ -1279,7 +1279,8 @@ static void uart_stm32_isr(const struct device *dev) uart_stm32_err_check(dev); #endif /* CONFIG_UART_ASYNC_API */ -#ifdef CONFIG_PM +#if defined(CONFIG_PM) && defined(IS_UART_WAKEUP_FROMSTOP_INSTANCE) \ + && defined(USART_CR3_WUFIE) if (LL_USART_IsEnabledIT_WKUP(config->usart) && LL_USART_IsActiveFlag_WKUP(config->usart)) { @@ -2017,13 +2018,14 @@ static int uart_stm32_init(const struct device *dev) * CONFIG_PM_DEVICE=n : Always active * CONFIG_PM_DEVICE=y : Controlled by pm_device_wakeup_enable() */ - +#ifdef USART_CR3_WUFIE LL_USART_Disable(config->usart); LL_USART_SetWKUPType(config->usart, LL_USART_WAKEUP_ON_RXNE); LL_USART_EnableIT_WKUP(config->usart); LL_USART_ClearFlag_WKUP(config->usart); - LL_USART_EnableInStopMode(config->usart); LL_USART_Enable(config->usart); +#endif + LL_USART_EnableInStopMode(config->usart); if (config->wakeup_line != STM32_EXTI_LINE_NONE) { /* Prepare the WAKEUP with the expected EXTI line */ From 7be1a8119bfd43810aae71a04670e40c0cc4e04b Mon Sep 17 00:00:00 2001 From: Erwan Gouriou Date: Tue, 21 Nov 2023 17:03:23 +0100 Subject: [PATCH 0053/3723] samples: stm32: serial_wakeup: b_u585i_iot02a support Add a sample overlay for b_u585i_iot02a Signed-off-by: Erwan Gouriou --- .../boards/b_u585i_iot02a.overlay | 34 +++++++++++++++++++ 1 file changed, 34 insertions(+) create mode 100644 samples/boards/stm32/power_mgmt/serial_wakeup/boards/b_u585i_iot02a.overlay diff --git a/samples/boards/stm32/power_mgmt/serial_wakeup/boards/b_u585i_iot02a.overlay b/samples/boards/stm32/power_mgmt/serial_wakeup/boards/b_u585i_iot02a.overlay new file mode 100644 index 00000000000..cce711c785c --- /dev/null +++ b/samples/boards/stm32/power_mgmt/serial_wakeup/boards/b_u585i_iot02a.overlay @@ -0,0 +1,34 @@ +/* + * Copyright (c) 2023 STMicroelectronics + * + * SPDX-License-Identifier: Apache-2.0 + */ + +&cpu0{ + /* USART Wakeup requires automatic HSI16 switch on in deepsleep mode + * which isn't possible in Stop Mode 2. + * Remove Stop Mode 2 from supported modes + */ + cpu-power-states = <&stop0 &stop1>; +}; + +&usart1 { + /* Set domain clock to HSI to allow wakeup from Stop mode */ + clocks = <&rcc STM32_CLOCK_BUS_APB2 0x00004000>, + <&rcc STM32_SRC_HSI16 USART1_SEL(2)>; + + /* Configure device as wakeup source */ + wakeup-source; + + /* Configure sleep pinctrl configuration which will be used when + * device is not configured as wakeup source by the application. + * This use case is only applicable in PM_DEVICE mode. + */ + pinctrl-1 = <&analog_pa9 &analog_pa10>; + pinctrl-names = "default", "sleep"; +}; + +&clk_hsi { + /* Make sure HSI is enabled */ + status = "okay"; +}; From aedefd41d7acadcca61cc297d666b391d047e566 Mon Sep 17 00:00:00 2001 From: Keith Packard Date: Tue, 21 Nov 2023 10:42:47 -0800 Subject: [PATCH 0054/3723] tests/kernel/mem_protect/mem_map: Reduce printf size for qemu_x86_tiny qemu_x86_tiny has very limited memory resources; if too much text is included in this test, it will not have enough remaining memory to run it. When using picolibc before 1.8.5, the only way to get 'long long' support was to use the full version, including floating point support. This is too large for this testcase. Reduce the size of the printf code by switching to the version without 64-bit integer support. This allows the test to pass when using older picolibc versions, such as that included with SDK version 0.16.3. Signed-off-by: Keith Packard --- tests/kernel/mem_protect/mem_map/testcase.yaml | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/tests/kernel/mem_protect/mem_map/testcase.yaml b/tests/kernel/mem_protect/mem_map/testcase.yaml index ff42310403b..860c76dcb6b 100644 --- a/tests/kernel/mem_protect/mem_map/testcase.yaml +++ b/tests/kernel/mem_protect/mem_map/testcase.yaml @@ -7,7 +7,9 @@ tests: kernel.memory_protection.mem_map: filter: CONFIG_MMU and not CONFIG_X86_64 extra_sections: _TRANSPLANTED_FUNC - extra_args: CONFIG_COMMON_LIBC_MALLOC_ARENA_SIZE=0 + extra_configs: + - CONFIG_COMMON_LIBC_MALLOC_ARENA_SIZE=0 + - CONFIG_CBPRINTF_REDUCED_INTEGRAL=y platform_exclude: qemu_x86_64 integration_platforms: - qemu_x86 From 1dc6279d12ea81041c21c8e76d6eae6a2e17bba0 Mon Sep 17 00:00:00 2001 From: Keith Packard Date: Tue, 21 Nov 2023 11:15:37 -0800 Subject: [PATCH 0055/3723] tests/subsys/logging/log_backend_uart: Reduce printf size When using picolibc before 1.8.5, the only way to get 'long long' support was to use the full version, including floating point support. This is too large for this testcase. Reduce the size of the printf code by switching to the version without 64-bit integer support. This allows the test to pass when using older picolibc versions, such as that included with SDK version 0.16.3. Signed-off-by: Keith Packard --- tests/subsys/logging/log_backend_uart/testcase.yaml | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/tests/subsys/logging/log_backend_uart/testcase.yaml b/tests/subsys/logging/log_backend_uart/testcase.yaml index 05a4626ba62..b28181b3d53 100644 --- a/tests/subsys/logging/log_backend_uart/testcase.yaml +++ b/tests/subsys/logging/log_backend_uart/testcase.yaml @@ -12,5 +12,9 @@ common: tests: logging.backend.uart.single: extra_args: DTC_OVERLAY_FILE="./single.overlay" + extra_configs: + - CONFIG_CBPRINTF_REDUCED_INTEGRAL=y logging.backend.uart.multi: extra_args: DTC_OVERLAY_FILE="./multi.overlay" + extra_configs: + - CONFIG_CBPRINTF_REDUCED_INTEGRAL=y From 23408ac538741317471c17f83e430f06634d662e Mon Sep 17 00:00:00 2001 From: David Leach Date: Tue, 21 Nov 2023 16:27:44 -0600 Subject: [PATCH 0056/3723] drivers: eth_mcus: Conditionally wrap IPV4/6 code Regression failure introduced problem where driver code was not properly wrapping code that only existed when compiled for IPv4/v6 applications. Fixes #65549 Signed-off-by: David Leach --- drivers/ethernet/eth_mcux.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/drivers/ethernet/eth_mcux.c b/drivers/ethernet/eth_mcux.c index f9ab95db9aa..81edc564259 100644 --- a/drivers/ethernet/eth_mcux.c +++ b/drivers/ethernet/eth_mcux.c @@ -1163,6 +1163,7 @@ static int eth_init(const struct device *dev) return 0; } +#if defined(CONFIG_NET_NATIVE_IPV4) || defined(CONFIG_NET_NATIVE_IPV6) static void net_if_mcast_cb(struct net_if *iface, const struct net_addr *addr, bool is_joined) @@ -1185,15 +1186,18 @@ static void net_if_mcast_cb(struct net_if *iface, ENET_LeaveMulticastGroup(context->base, mac_addr.addr); } } +#endif /* CONFIG_NET_NATIVE_IPV4 || CONFIG_NET_NATIVE_IPV6 */ static void eth_iface_init(struct net_if *iface) { const struct device *dev = net_if_get_device(iface); struct eth_context *context = dev->data; +#if defined(CONFIG_NET_NATIVE_IPV4) || defined(CONFIG_NET_NATIVE_IPV6) static struct net_if_mcast_monitor mon; net_if_mcast_mon_register(&mon, iface, net_if_mcast_cb); +#endif /* CONFIG_NET_NATIVE_IPV4 || CONFIG_NET_NATIVE_IPV6 */ net_if_set_link_addr(iface, context->mac_addr, sizeof(context->mac_addr), From bf6c2fcde81e0651ca0918820b52bfc2e182412f Mon Sep 17 00:00:00 2001 From: Keith Packard Date: Tue, 21 Nov 2023 13:26:36 -0800 Subject: [PATCH 0057/3723] samples/bluetooth/hci_ipc: Reduce printf size When using picolibc before 1.8.5, the only way to get 'long long' support was to use the full version, including floating point support. This is too large for this testcase. Reduce the size of the printf code by switching to the version without 64-bit integer support. This allows the test to pass when using older picolibc versions, such as that included with SDK version 0.16.3. Signed-off-by: Keith Packard --- samples/bluetooth/hci_ipc/nrf5340_cpunet_iso-bt_ll_sw_split.conf | 1 + 1 file changed, 1 insertion(+) diff --git a/samples/bluetooth/hci_ipc/nrf5340_cpunet_iso-bt_ll_sw_split.conf b/samples/bluetooth/hci_ipc/nrf5340_cpunet_iso-bt_ll_sw_split.conf index e9e5ac63483..f80f324be53 100644 --- a/samples/bluetooth/hci_ipc/nrf5340_cpunet_iso-bt_ll_sw_split.conf +++ b/samples/bluetooth/hci_ipc/nrf5340_cpunet_iso-bt_ll_sw_split.conf @@ -7,6 +7,7 @@ CONFIG_MAIN_STACK_SIZE=512 CONFIG_SYSTEM_WORKQUEUE_STACK_SIZE=512 CONFIG_IPC_SERVICE_BACKEND_RPMSG_WQ_STACK_SIZE=512 CONFIG_HEAP_MEM_POOL_SIZE=8192 +CONFIG_CBPRINTF_REDUCED_INTEGRAL=y CONFIG_BT=y CONFIG_BT_HCI_RAW=y From e1a14bad30bb89bf62000ce0a7d18bc1142bf078 Mon Sep 17 00:00:00 2001 From: Mariusz Skamra Date: Thu, 19 Oct 2023 15:21:57 +0200 Subject: [PATCH 0058/3723] Bluetooth: audio: has: Add non-volatile settings This adds non-volatile settings for the HAS Server. Those are needed to restore the client awareness of preset list entries exposed by the server. Based on the settings, the implementation determines how to notify the client about the HAS related characteristic value changes. Signed-off-by: Mariusz Skamra --- subsys/bluetooth/audio/has.c | 108 ++++++++++++++++++++++++++++------- 1 file changed, 87 insertions(+), 21 deletions(-) diff --git a/subsys/bluetooth/audio/has.c b/subsys/bluetooth/audio/has.c index fc1aba7aec2..6013cadd014 100644 --- a/subsys/bluetooth/audio/has.c +++ b/subsys/bluetooth/audio/has.c @@ -15,6 +15,7 @@ #include #include "../bluetooth/host/hci_core.h" +#include "../bluetooth/host/settings.h" #include "audio_internal.h" #include "has_internal.h" @@ -298,8 +299,6 @@ static struct has_client *client_alloc(struct bt_conn *conn) } LOG_DBG("New client_context for %s", bt_addr_le_str(info.le.dst)); - } else { - LOG_DBG("Restored client_context for %s", bt_addr_le_str(info.le.dst)); } return client; @@ -508,26 +507,15 @@ static void bond_deleted_cb(uint8_t id, const bt_addr_le_t *addr) if (context != NULL) { context_free(context); } + + if (IS_ENABLED(CONFIG_BT_SETTINGS)) { + bt_settings_delete("has", 0, addr); + } } static struct bt_conn_auth_info_cb auth_info_cb = { .bond_deleted = bond_deleted_cb, }; - -static void restore_client_context(const struct bt_bond_info *info, void *user_data) -{ - struct client_context *context; - - context = context_alloc(&info->addr); - if (context == NULL) { - LOG_ERR("Failed to allocate client_context for %s", bt_addr_le_str(&info->addr)); - return; - } - - /* Notify all the characteristics values after reboot */ - atomic_set(context->flags, BONDED_CLIENT_INIT_FLAGS); -} - #endif /* CONFIG_BT_HAS_PRESET_SUPPORT || CONFIG_BT_HAS_FEATURES_NOTIFIABLE */ #if defined(CONFIG_BT_HAS_PRESET_SUPPORT) @@ -868,10 +856,86 @@ static int bt_has_cp_generic_update(struct has_client *client, uint8_t prev_inde } } +#if defined(CONFIG_BT_SETTINGS) +struct client_context_store { + /* Last notified preset index */ + uint8_t last_preset_index_known; +} __packed; + +static int settings_set_cb(const char *name, size_t len_rd, settings_read_cb read_cb, void *cb_arg) +{ + struct client_context_store store; + struct client_context *context; + bt_addr_le_t addr; + ssize_t len; + int err; + + if (!name) { + LOG_ERR("Insufficient number of arguments"); + return -EINVAL; + } + + err = bt_settings_decode_key(name, &addr); + if (err) { + LOG_ERR("Unable to decode address %s", name); + return -EINVAL; + } + + context = context_find(&addr); + if (context == NULL) { + /* Find and initialize a free entry */ + context = context_alloc(&addr); + if (context == NULL) { + LOG_ERR("Failed to allocate client_context for %s", bt_addr_le_str(&addr)); + return -ENOMEM; + } + } + + if (len_rd) { + len = read_cb(cb_arg, &store, sizeof(store)); + if (len < 0) { + LOG_ERR("Failed to decode value (err %zd)", len); + return len; + } + + context->last_preset_index_known = store.last_preset_index_known; + } else { + context->last_preset_index_known = 0x00; + } + + /* Notify all the characteristics values after reboot */ + atomic_set(context->flags, BONDED_CLIENT_INIT_FLAGS); + + return 0; +} + +BT_SETTINGS_DEFINE(has, "has", settings_set_cb, NULL); + +static void store_client_context(struct client_context *context) +{ + struct client_context_store store = { + .last_preset_index_known = context->last_preset_index_known, + }; + int err; + + LOG_DBG("%s last_preset_index_known 0x%02x", + bt_addr_le_str(&context->addr), store.last_preset_index_known); + + err = bt_settings_store("has", 0, &context->addr, &store, sizeof(store)); + if (err != 0) { + LOG_ERR("Failed to store err %d", err); + } +} +#else +#define store_client_context(...) +#endif /* CONFIG_BT_SETTINGS */ + static void update_last_preset_index_known(struct has_client *client, uint8_t index) { - if (client != NULL) { + if (client != NULL && client->context != NULL && + client->context->last_preset_index_known != index) { client->context->last_preset_index_known = index; + store_client_context(client->context); return; } @@ -879,8 +943,10 @@ static void update_last_preset_index_known(struct has_client *client, uint8_t in client = &has_client_list[i]; /* For each connected client */ - if (client->conn != NULL && client->context != NULL) { + if (client->conn != NULL && client->context != NULL && + client->context->last_preset_index_known != index) { client->context->last_preset_index_known = index; + store_client_context(client->context); } } } @@ -933,6 +999,8 @@ static int bt_has_cp_preset_record_deleted(struct has_client *client, uint8_t in NET_BUF_SIMPLE_DEFINE(buf, sizeof(struct bt_has_cp_hdr) + sizeof(struct bt_has_cp_preset_changed) + sizeof(uint8_t)); + LOG_DBG("client %p index 0x%02x", client, index); + preset_changed_prepare(&buf, BT_HAS_CHANGE_ID_PRESET_DELETED, BT_HAS_IS_LAST); net_buf_simple_add_u8(&buf, index); @@ -1709,8 +1777,6 @@ int bt_has_register(const struct bt_has_features_param *features) #if defined(CONFIG_BT_HAS_PRESET_SUPPORT) || defined(CONFIG_BT_HAS_FEATURES_NOTIFIABLE) bt_conn_auth_info_cb_register(&auth_info_cb); - - bt_foreach_bond(BT_ID_DEFAULT, restore_client_context, NULL); #endif /* CONFIG_BT_HAS_PRESET_SUPPORT || CONFIG_BT_HAS_FEATURES_NOTIFIABLE */ has.registered = true; From 300746310eac1fbfdb6b7c916c39d876ec06cc92 Mon Sep 17 00:00:00 2001 From: Jamie McCrae Date: Tue, 31 Oct 2023 13:01:17 +0000 Subject: [PATCH 0059/3723] doc: mcumgr: smp_group_3: Fix rc text Fixes the "rc" text to include that it can also be returned when SMP version 2 is used to indicate an SMP error instead of a group error. Signed-off-by: Jamie McCrae --- doc/services/device_mgmt/smp_groups/smp_group_3.rst | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/doc/services/device_mgmt/smp_groups/smp_group_3.rst b/doc/services/device_mgmt/smp_groups/smp_group_3.rst index c70897809e1..0636e72e3f6 100644 --- a/doc/services/device_mgmt/smp_groups/smp_group_3.rst +++ b/doc/services/device_mgmt/smp_groups/smp_group_3.rst @@ -132,7 +132,7 @@ where: | | non-zero (error condition) when using SMP version 2. | +------------------+-------------------------------------------------------------------------+ | "rc" | :c:enum:`mcumgr_err_t` only appears if non-zero (error condition) when | - | | using SMP version 1. | + | | using SMP version 1 or for SMP errors when using SMP version 2. | +------------------+-------------------------------------------------------------------------+ Write setting request @@ -220,7 +220,7 @@ where: | | non-zero (error condition) when using SMP version 2. | +------------------+-------------------------------------------------------------------------+ | "rc" | :c:enum:`mcumgr_err_t` only appears if non-zero (error condition) when | - | | using SMP version 1. | + | | using SMP version 1 or for SMP errors when using SMP version 2. | +------------------+-------------------------------------------------------------------------+ Delete setting command @@ -310,7 +310,7 @@ where: | | non-zero (error condition) when using SMP version 2. | +------------------+-------------------------------------------------------------------------+ | "rc" | :c:enum:`mcumgr_err_t` only appears if non-zero (error condition) when | - | | using SMP version 1. | + | | using SMP version 1 or for SMP errors when using SMP version 2. | +------------------+-------------------------------------------------------------------------+ Commit settings command @@ -386,7 +386,7 @@ where: | | non-zero (error condition) when using SMP version 2. | +------------------+-------------------------------------------------------------------------+ | "rc" | :c:enum:`mcumgr_err_t` only appears if non-zero (error condition) when | - | | using SMP version 1. | + | | using SMP version 1 or for SMP errors when using SMP version 2. | +------------------+-------------------------------------------------------------------------+ Load/Save settings command @@ -462,7 +462,7 @@ where: | | non-zero (error condition) when using SMP version 2. | +------------------+-------------------------------------------------------------------------+ | "rc" | :c:enum:`mcumgr_err_t` only appears if non-zero (error condition) when | - | | using SMP version 1. | + | | using SMP version 1 or for SMP errors when using SMP version 2. | +------------------+-------------------------------------------------------------------------+ Save settings request @@ -532,7 +532,7 @@ where: | | non-zero (error condition) when using SMP version 2. | +------------------+------------------------------------------------------------------------+ | "rc" | :c:enum:`mcumgr_err_t` only appears if non-zero (error condition) when | - | | using SMP version 1. | + | | using SMP version 1 or for SMP errors when using SMP version 2. | +------------------+------------------------------------------------------------------------+ Settings access callback From 3613f94fdc4be895a6c5c711a5a8758b6f37da04 Mon Sep 17 00:00:00 2001 From: Jamie McCrae Date: Tue, 31 Oct 2023 13:04:30 +0000 Subject: [PATCH 0060/3723] doc: mcumgr: smp_group_63: Add zephyr mgmt group documentation Adds documentation describing the MCUmgr Zephyr management group and supported commands Signed-off-by: Jamie McCrae --- doc/services/device_mgmt/index.rst | 1 + .../device_mgmt/smp_groups/smp_group_63.rst | 92 +++++++++++++++++++ doc/services/device_mgmt/smp_protocol.rst | 2 +- 3 files changed, 94 insertions(+), 1 deletion(-) create mode 100644 doc/services/device_mgmt/smp_groups/smp_group_63.rst diff --git a/doc/services/device_mgmt/index.rst b/doc/services/device_mgmt/index.rst index 96ba59e4a01..6094e49acc1 100644 --- a/doc/services/device_mgmt/index.rst +++ b/doc/services/device_mgmt/index.rst @@ -28,3 +28,4 @@ SMP Groups smp_groups/smp_group_3.rst smp_groups/smp_group_8.rst smp_groups/smp_group_9.rst + smp_groups/smp_group_63.rst diff --git a/doc/services/device_mgmt/smp_groups/smp_group_63.rst b/doc/services/device_mgmt/smp_groups/smp_group_63.rst new file mode 100644 index 00000000000..8d1f9015bcb --- /dev/null +++ b/doc/services/device_mgmt/smp_groups/smp_group_63.rst @@ -0,0 +1,92 @@ +.. _mcumgr_smp_group_63: + +Zephyr Management Group +####################### + +Zephyr management group defines the following commands: + +.. table:: + :align: center + + +----------------+------------------------------+ + | ``Command ID`` | Command description | + +================+==============================+ + | ``0`` | Erase storage | + +----------------+------------------------------+ + +Erase storage command +********************* + +Erase storage command allows clearing the ``storage_partition`` flash partition on a device, +generally this is used when switching to a new application build if the application uses storage +that should be cleared (application dependent). + +Erase storage request +===================== + +Erase storage request header fields: + +.. table:: + :align: center + + +--------+--------------+----------------+ + | ``OP`` | ``Group ID`` | ``Command ID`` | + +========+==============+================+ + | ``2`` | ``63`` | ``0`` | + +--------+--------------+----------------+ + +The command sends sends empty CBOR map as data. + +Erase storage response +====================== + +Read setting response header fields: + +.. table:: + :align: center + + +--------+--------------+----------------+ + | ``OP`` | ``Group ID`` | ``Command ID`` | + +========+==============+================+ + | ``3`` | ``63`` | ``0`` | + +--------+--------------+----------------+ + +The command sends an empty CBOR map as data if successful. In case of error the CBOR data takes +the form: + +.. tabs:: + + .. group-tab:: SMP version 2 + + .. code-block:: none + + { + (str)"err" : { + (str)"group" : (uint) + (str)"rc" : (uint) + } + } + + .. group-tab:: SMP version 1 + + .. code-block:: none + + { + (str)"rc" : (int) + } + +where: + +.. table:: + :align: center + + +------------------+-------------------------------------------------------------------------+ + | "err" -> "group" | :c:enum:`mcumgr_group_t` group of the group-based error code. Only | + | | appears if an error is returned when using SMP version 2. | + +------------------+-------------------------------------------------------------------------+ + | "err" -> "rc" | contains the index of the group-based error code. Only appears if | + | | non-zero (error condition) when using SMP version 2. | + +------------------+-------------------------------------------------------------------------+ + | "rc" | :c:enum:`mcumgr_err_t` only appears if non-zero (error condition) when | + | | using SMP version 1 or for SMP errors when using SMP version 2. | + +------------------+-------------------------------------------------------------------------+ diff --git a/doc/services/device_mgmt/smp_protocol.rst b/doc/services/device_mgmt/smp_protocol.rst index 44c30f32d29..1ad4634d6e7 100644 --- a/doc/services/device_mgmt/smp_protocol.rst +++ b/doc/services/device_mgmt/smp_protocol.rst @@ -141,7 +141,7 @@ groups. The following table presents a list of common groups: +---------------+-----------------------------------------------+ | ``9`` | :ref:`mcumgr_smp_group_9` | +---------------+-----------------------------------------------+ - | ``63`` | Zephyr specific basic commands group | + | ``63`` | :ref:`mcumgr_smp_group_63` | +---------------+-----------------------------------------------+ | ``64`` | This is the base group for defining | | | an application specific management groups. | From f03192f489aef8399e132f84f574811e7e9b85d8 Mon Sep 17 00:00:00 2001 From: Jamie McCrae Date: Tue, 31 Oct 2023 13:05:12 +0000 Subject: [PATCH 0061/3723] doc: mcumgr: Add missing Settings management text Adds that settings (config) management is supported to the list of supported command groups Signed-off-by: Jamie McCrae --- doc/services/device_mgmt/mcumgr.rst | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/doc/services/device_mgmt/mcumgr.rst b/doc/services/device_mgmt/mcumgr.rst index f868aaceb17..f16a77d43a9 100644 --- a/doc/services/device_mgmt/mcumgr.rst +++ b/doc/services/device_mgmt/mcumgr.rst @@ -12,9 +12,10 @@ The following management operations are available: * Image management * File System management * OS management +* Settings (config) management * Shell management * Statistic management -* Zephyr-basic management +* Zephyr management over the following transports: From 4ddbf51042808015f51b40453bb2381ffea92f0e Mon Sep 17 00:00:00 2001 From: "F. Ramu" Date: Thu, 16 Nov 2023 13:24:15 +0100 Subject: [PATCH 0062/3723] west.yml: update modules/hal/stm32/hal_stm32 for stm32h503 Update the stm32h5xx/drivers/include/ to enable the SAI, DelayBlock and DCACHE only if the instance exists in the soc. Which is not the case for stm32h503x device https://github.com/zephyrproject-rtos/hal_stm32/pull/181/ Signed-off-by: Francois Ramu --- west.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/west.yml b/west.yml index 14847109194..f1fd789503e 100644 --- a/west.yml +++ b/west.yml @@ -229,7 +229,7 @@ manifest: groups: - hal - name: hal_stm32 - revision: 89ef0a3383edebf661073073bcdf6e2836fe90ee + revision: af2d314b6f7f87cfa8365009497132468ca3a686 path: modules/hal/stm32 groups: - hal From 65b6d2f18010dc999d9416d4c2acff54121d320e Mon Sep 17 00:00:00 2001 From: Pisit Sawangvonganan Date: Fri, 17 Nov 2023 15:48:09 +0700 Subject: [PATCH 0063/3723] toolchain: esp32: fix cmake build issue with 'espressif' toolchain Change CROSS_COMPILE_TARGET to be defined based on CONFIG_SOC_SERIES. This fix adjusts CROSS_COMPILE_TARGET to ensure compatibility with the 'espressif' toolchain variant, following the changes in commit 6b57b3b786be. Signed-off-by: Pisit Sawangvonganan --- cmake/toolchain/espressif/target.cmake | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cmake/toolchain/espressif/target.cmake b/cmake/toolchain/espressif/target.cmake index 35d2a01555a..7d6f7eddf16 100644 --- a/cmake/toolchain/espressif/target.cmake +++ b/cmake/toolchain/espressif/target.cmake @@ -12,7 +12,7 @@ set(CROSS_COMPILE_TARGET_xtensa_esp32s2 xtensa-esp32s2-elf) set(CROSS_COMPILE_TARGET_xtensa_esp32s3 xtensa-esp32s3-elf) set(CROSS_COMPILE_TARGET_riscv_esp32c3 riscv32-esp-elf) -set(CROSS_COMPILE_TARGET ${CROSS_COMPILE_TARGET_${ARCH}_${CONFIG_SOC}}) +set(CROSS_COMPILE_TARGET ${CROSS_COMPILE_TARGET_${ARCH}_${CONFIG_SOC_SERIES}}) set(SYSROOT_TARGET ${CROSS_COMPILE_TARGET}) if(ESPRESSIF_DEPRECATED_PATH) From adcb2f580cedd21273cb71d1dbd2be2683e78cd5 Mon Sep 17 00:00:00 2001 From: Fabio Baltieri Date: Fri, 17 Nov 2023 13:12:24 +0000 Subject: [PATCH 0064/3723] input: gpio_kbd_matrix: define a type for the row data Add a typedef for the row type rather than using uint8_t directly, this allow supporting bigger matrix as an option by using a different type. Signed-off-by: Fabio Baltieri --- drivers/input/input_gpio_kbd_matrix.c | 2 +- drivers/input/input_ite_it8xxx2_kbd.c | 2 +- drivers/input/input_kbd_matrix.c | 22 ++++++++++----------- drivers/input/input_npcx_kbd.c | 2 +- include/zephyr/input/input_kbd_matrix.h | 26 +++++++++++++++---------- 5 files changed, 29 insertions(+), 25 deletions(-) diff --git a/drivers/input/input_gpio_kbd_matrix.c b/drivers/input/input_gpio_kbd_matrix.c index 9d532bfd0af..f81a01837f9 100644 --- a/drivers/input/input_gpio_kbd_matrix.c +++ b/drivers/input/input_gpio_kbd_matrix.c @@ -64,7 +64,7 @@ static void gpio_kbd_matrix_drive_column(const struct device *dev, int col) data->last_col_state = state; } -static int gpio_kbd_matrix_read_row(const struct device *dev) +static kbd_row_t gpio_kbd_matrix_read_row(const struct device *dev) { const struct gpio_kbd_matrix_config *cfg = dev->config; const struct input_kbd_matrix_common_config *common = &cfg->common; diff --git a/drivers/input/input_ite_it8xxx2_kbd.c b/drivers/input/input_ite_it8xxx2_kbd.c index 8d688d42db1..5e62e6ee32e 100644 --- a/drivers/input/input_ite_it8xxx2_kbd.c +++ b/drivers/input/input_ite_it8xxx2_kbd.c @@ -79,7 +79,7 @@ static void it8xxx2_kbd_drive_column(const struct device *dev, int col) } } -static int it8xxx2_kbd_read_row(const struct device *dev) +static kbd_row_t it8xxx2_kbd_read_row(const struct device *dev) { const struct it8xxx2_kbd_config *const config = dev->config; struct kscan_it8xxx2_regs *const inst = config->base; diff --git a/drivers/input/input_kbd_matrix.c b/drivers/input/input_kbd_matrix.c index 6005a76b3b3..07e3c4c0545 100644 --- a/drivers/input/input_kbd_matrix.c +++ b/drivers/input/input_kbd_matrix.c @@ -16,8 +16,6 @@ LOG_MODULE_REGISTER(input_kbd_matrix, CONFIG_INPUT_LOG_LEVEL); -#define INPUT_KBD_MATRIX_ROW_MASK UINT8_MAX - void input_kbd_matrix_poll_start(const struct device *dev) { struct input_kbd_matrix_common_data *data = dev->data; @@ -28,7 +26,7 @@ void input_kbd_matrix_poll_start(const struct device *dev) static bool input_kbd_matrix_ghosting(const struct device *dev) { const struct input_kbd_matrix_common_config *cfg = dev->config; - const uint8_t *state = cfg->matrix_new_state; + const kbd_row_t *state = cfg->matrix_new_state; /* * Matrix keyboard designs are suceptible to ghosting. @@ -59,7 +57,7 @@ static bool input_kbd_matrix_ghosting(const struct device *dev) * using z&(z-1) which is non-zero only if z has more * than one bit set. */ - uint8_t common_row_bits = state[c] & state[c_next]; + kbd_row_t common_row_bits = state[c] & state[c_next]; if (common_row_bits & (common_row_bits - 1)) { return true; @@ -74,8 +72,8 @@ static bool input_kbd_matrix_scan(const struct device *dev) { const struct input_kbd_matrix_common_config *cfg = dev->config; const struct input_kbd_matrix_api *api = cfg->api; - int row; - uint8_t key_event = 0U; + kbd_row_t row; + kbd_row_t key_event = 0U; for (int col = 0; col < cfg->col_size; col++) { api->drive_column(dev, col); @@ -83,7 +81,7 @@ static bool input_kbd_matrix_scan(const struct device *dev) /* Allow the matrix to stabilize before reading it */ k_busy_wait(cfg->settle_time_us); - row = api->read_row(dev) & INPUT_KBD_MATRIX_ROW_MASK; + row = api->read_row(dev); cfg->matrix_new_state[col] = row; key_event |= row; } @@ -97,10 +95,10 @@ static void input_kbd_matrix_update_state(const struct device *dev) { const struct input_kbd_matrix_common_config *cfg = dev->config; struct input_kbd_matrix_common_data *data = dev->data; - uint8_t *matrix_new_state = cfg->matrix_new_state; + kbd_row_t *matrix_new_state = cfg->matrix_new_state; uint32_t cycles_now; - uint8_t row_changed; - uint8_t deb_col; + kbd_row_t row_changed; + kbd_row_t deb_col; cycles_now = k_cycle_get_32(); @@ -143,8 +141,8 @@ static void input_kbd_matrix_update_state(const struct device *dev) /* Debouncing for each row key occurs here */ for (int r = 0; r < cfg->row_size; r++) { - uint8_t mask = BIT(r); - uint8_t row_bit = matrix_new_state[c] & mask; + kbd_row_t mask = BIT(r); + kbd_row_t row_bit = matrix_new_state[c] & mask; /* Continue if we already debounce a key */ if (!(deb_col & mask)) { diff --git a/drivers/input/input_npcx_kbd.c b/drivers/input/input_npcx_kbd.c index 64cde93bda9..25f28e3e60e 100644 --- a/drivers/input/input_npcx_kbd.c +++ b/drivers/input/input_npcx_kbd.c @@ -97,7 +97,7 @@ static void npcx_kbd_drive_column(const struct device *dev, int col) inst->KBSOUT1 = ((mask >> 16) & 0x03); } -static int npcx_kbd_read_row(const struct device *dev) +static kbd_row_t npcx_kbd_read_row(const struct device *dev) { const struct npcx_kbd_config *config = dev->config; const struct input_kbd_matrix_common_config *common = &config->common; diff --git a/include/zephyr/input/input_kbd_matrix.h b/include/zephyr/input/input_kbd_matrix.h index 0566f14d2cd..98bd791d49a 100644 --- a/include/zephyr/input/input_kbd_matrix.h +++ b/include/zephyr/input/input_kbd_matrix.h @@ -29,6 +29,12 @@ /** Number of tracked scan cycles */ #define INPUT_KBD_MATRIX_SCAN_OCURRENCES 30U +/** Row entry data type */ +typedef uint8_t kbd_row_t; + +/** Maximum number of rows */ +#define INPUT_KBD_MATRIX_ROW_BITS NUM_BITS(kbd_row_t) + /** * @brief Keyboard matrix internal APIs. */ @@ -49,7 +55,7 @@ struct input_kbd_matrix_api { * * @param dev Pointer to the keyboard matrix device. */ - int (*read_row)(const struct device *dev); + kbd_row_t (*read_row)(const struct device *dev); /** * @brief Request to put the matrix in detection mode. * @@ -80,10 +86,10 @@ struct input_kbd_matrix_common_config { bool ghostkey_check; /* extra data pointers */ - uint8_t *matrix_stable_state; - uint8_t *matrix_unstable_state; - uint8_t *matrix_previous_state; - uint8_t *matrix_new_state; + kbd_row_t *matrix_stable_state; + kbd_row_t *matrix_unstable_state; + kbd_row_t *matrix_previous_state; + kbd_row_t *matrix_new_state; uint8_t *scan_cycle_idx; }; @@ -96,12 +102,12 @@ struct input_kbd_matrix_common_config { * specify row and col count. */ #define INPUT_KBD_MATRIX_DT_DEFINE_ROW_COL(node_id, _row_size, _col_size) \ - BUILD_ASSERT(IN_RANGE(_row_size, 1, 8), "invalid row-size"); \ + BUILD_ASSERT(IN_RANGE(_row_size, 1, INPUT_KBD_MATRIX_ROW_BITS), "invalid row-size"); \ BUILD_ASSERT(IN_RANGE(_col_size, 1, UINT8_MAX), "invalid col-size"); \ - static uint8_t INPUT_KBD_MATRIX_DATA_NAME(node_id, stable_state)[_col_size]; \ - static uint8_t INPUT_KBD_MATRIX_DATA_NAME(node_id, unstable_state)[_col_size]; \ - static uint8_t INPUT_KBD_MATRIX_DATA_NAME(node_id, previous_state)[_col_size]; \ - static uint8_t INPUT_KBD_MATRIX_DATA_NAME(node_id, new_state)[_col_size]; \ + static kbd_row_t INPUT_KBD_MATRIX_DATA_NAME(node_id, stable_state)[_col_size]; \ + static kbd_row_t INPUT_KBD_MATRIX_DATA_NAME(node_id, unstable_state)[_col_size]; \ + static kbd_row_t INPUT_KBD_MATRIX_DATA_NAME(node_id, previous_state)[_col_size]; \ + static kbd_row_t INPUT_KBD_MATRIX_DATA_NAME(node_id, new_state)[_col_size]; \ static uint8_t INPUT_KBD_MATRIX_DATA_NAME(node_id, scan_cycle_idx)[_row_size * _col_size]; /** From f9ed74e0d5836c6cfe60d604e66c3aeff40f799e Mon Sep 17 00:00:00 2001 From: Fabio Baltieri Date: Fri, 17 Nov 2023 13:22:30 +0000 Subject: [PATCH 0065/3723] input: gpio_kbd_matrix: add 16 bit rows support Add a Kconfig option to extend the row type to 16 bits, allowing the library to handle a 16 row matrix. Signed-off-by: Fabio Baltieri --- drivers/input/Kconfig.kbd_matrix | 6 ++++++ include/zephyr/input/input_kbd_matrix.h | 4 ++++ 2 files changed, 10 insertions(+) diff --git a/drivers/input/Kconfig.kbd_matrix b/drivers/input/Kconfig.kbd_matrix index 5d1328a227f..002c7f3cb8a 100644 --- a/drivers/input/Kconfig.kbd_matrix +++ b/drivers/input/Kconfig.kbd_matrix @@ -14,4 +14,10 @@ config INPUT_KBD_MATRIX_THREAD_STACK_SIZE help Size of the stack used for the keyboard matrix thread. +config INPUT_KBD_MATRIX_16_BIT_ROW + bool "16 bit row size support" + help + Use a 16 bit type for the internal structure, allow using a matrix + with up to 16 rows if the driver supports it. + endif # INPUT_KBD_MATRIX diff --git a/include/zephyr/input/input_kbd_matrix.h b/include/zephyr/input/input_kbd_matrix.h index 98bd791d49a..a8e85b08855 100644 --- a/include/zephyr/input/input_kbd_matrix.h +++ b/include/zephyr/input/input_kbd_matrix.h @@ -30,7 +30,11 @@ #define INPUT_KBD_MATRIX_SCAN_OCURRENCES 30U /** Row entry data type */ +#if CONFIG_INPUT_KBD_MATRIX_16_BIT_ROW +typedef uint16_t kbd_row_t; +#else typedef uint8_t kbd_row_t; +#endif /** Maximum number of rows */ #define INPUT_KBD_MATRIX_ROW_BITS NUM_BITS(kbd_row_t) From 5e10cd9aeedb4a8ccc78927ff4c24152c57d4b80 Mon Sep 17 00:00:00 2001 From: Fabio Baltieri Date: Fri, 17 Nov 2023 13:54:13 +0000 Subject: [PATCH 0066/3723] tests: build_all: input: test the 16 bit row option Add a test case for the 16 bit row size option. Signed-off-by: Fabio Baltieri --- tests/drivers/build_all/input/testcase.yaml | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/tests/drivers/build_all/input/testcase.yaml b/tests/drivers/build_all/input/testcase.yaml index 32fe44b883f..2831b693e28 100644 --- a/tests/drivers/build_all/input/testcase.yaml +++ b/tests/drivers/build_all/input/testcase.yaml @@ -13,3 +13,7 @@ tests: - CONFIG_INPUT_CST816S_INTERRUPT=n - CONFIG_INPUT_FT5336_INTERRUPT=y - CONFIG_INPUT_GT911_INTERRUPT=y + + drivers.input.kbd_16_bit: + extra_configs: + - CONFIG_INPUT_KBD_MATRIX_16_BIT_ROW=y From 71db6550cd5511ad9814477409fc47c237cf9efd Mon Sep 17 00:00:00 2001 From: Alberto Escolar Piedras Date: Mon, 20 Nov 2023 11:39:12 +0100 Subject: [PATCH 0067/3723] native simulator: Get latest from upstream Align with native_simulator's upstream main 7d652dbfb313260cf07d595ccf26638f2b3c2959 Which includes: * 7d652db Provide macros for noreturn and unreachable & annotate Signed-off-by: Alberto Escolar Piedras --- scripts/native_simulator/common/src/include/nsi_main.h | 4 +++- scripts/native_simulator/common/src/include/nsi_utils.h | 4 ++++ scripts/native_simulator/common/src/main.c | 2 +- 3 files changed, 8 insertions(+), 2 deletions(-) diff --git a/scripts/native_simulator/common/src/include/nsi_main.h b/scripts/native_simulator/common/src/include/nsi_main.h index 83ba8cac433..33508edb7fe 100644 --- a/scripts/native_simulator/common/src/include/nsi_main.h +++ b/scripts/native_simulator/common/src/include/nsi_main.h @@ -7,6 +7,8 @@ #ifndef NSI_COMMON_SRC_INCL_NSI_MAIN_H #define NSI_COMMON_SRC_INCL_NSI_MAIN_H +#include "nsi_utils.h" + #ifdef __cplusplus extern "C" { #endif @@ -31,7 +33,7 @@ int nsi_exit_inner(int exit_code); * Note that other components may have requested a different * exit code which may have precedence if it was !=0 */ -void nsi_exit(int exit_code); +NSI_FUNC_NORETURN void nsi_exit(int exit_code); #ifdef __cplusplus } diff --git a/scripts/native_simulator/common/src/include/nsi_utils.h b/scripts/native_simulator/common/src/include/nsi_utils.h index f41fdf9ddc8..996ad635409 100644 --- a/scripts/native_simulator/common/src/include/nsi_utils.h +++ b/scripts/native_simulator/common/src/include/nsi_utils.h @@ -25,4 +25,8 @@ #define NSI_ARG_UNUSED(x) (void)(x) #endif +#define NSI_CODE_UNREACHABLE __builtin_unreachable() + +#define NSI_FUNC_NORETURN __attribute__((__noreturn__)) + #endif /* NSI_COMMON_SRC_INCL_NSI_UTILS_H */ diff --git a/scripts/native_simulator/common/src/main.c b/scripts/native_simulator/common/src/main.c index ffe1d3b93d1..b9d97c91748 100644 --- a/scripts/native_simulator/common/src/main.c +++ b/scripts/native_simulator/common/src/main.c @@ -44,7 +44,7 @@ int nsi_exit_inner(int exit_code) return max_exit_code; } -void nsi_exit(int exit_code) +NSI_FUNC_NORETURN void nsi_exit(int exit_code) { exit(nsi_exit_inner(exit_code)); } From ab896ad6efcbaad7c8cbb0beff8d3faf935ba908 Mon Sep 17 00:00:00 2001 From: Alberto Escolar Piedras Date: Mon, 20 Nov 2023 11:41:57 +0100 Subject: [PATCH 0068/3723] arch posix: annotate posix_exit and nsi_exit as noreturn Annotate posix_exit() and nsi_exit() as noreturn mainly to ease the life of static analysis tools. Signed-off-by: Alberto Escolar Piedras --- arch/posix/core/nsi_compat/nsi_compat.c | 7 ++++--- soc/posix/inf_clock/posix_board_if.h | 3 ++- 2 files changed, 6 insertions(+), 4 deletions(-) diff --git a/arch/posix/core/nsi_compat/nsi_compat.c b/arch/posix/core/nsi_compat/nsi_compat.c index cd338ca1e4f..eccf419efb1 100644 --- a/arch/posix/core/nsi_compat/nsi_compat.c +++ b/arch/posix/core/nsi_compat/nsi_compat.c @@ -13,6 +13,8 @@ */ #include +#include +#include "posix_board_if.h" void nsi_print_error_and_exit(const char *format, ...) { @@ -41,9 +43,8 @@ void nsi_print_trace(const char *format, ...) va_end(variable_args); } -void nsi_exit(int exit_code) +FUNC_NORETURN void nsi_exit(int exit_code) { - extern void posix_exit(int exit_code); - posix_exit(exit_code); + CODE_UNREACHABLE; } diff --git a/soc/posix/inf_clock/posix_board_if.h b/soc/posix/inf_clock/posix_board_if.h index 1d851fb3935..49384530e14 100644 --- a/soc/posix/inf_clock/posix_board_if.h +++ b/soc/posix/inf_clock/posix_board_if.h @@ -7,6 +7,7 @@ #define _POSIX_CORE_BOARD_PROVIDED_IF_H #include +#include /* * This file lists the functions the posix "inf_clock" soc @@ -22,7 +23,7 @@ extern "C" { #endif void posix_irq_handler(void); -void posix_exit(int exit_code); +FUNC_NORETURN void posix_exit(int exit_code); uint64_t posix_get_hw_cycle(void); void posix_cpu_hold(uint32_t usec_to_waste); From c3b7159cdf7680affd8314bd0e5454e27081fd0c Mon Sep 17 00:00:00 2001 From: Alberto Escolar Piedras Date: Mon, 20 Nov 2023 13:17:43 +0100 Subject: [PATCH 0069/3723] tests/bluetooth/mesh: Enable for native_sim Enable this tests for native_sim and switch the default integration platform to be native_sim from native_posix Signed-off-by: Alberto Escolar Piedras --- tests/bluetooth/mesh/blob_io_flash/testcase.yaml | 6 ++++-- tests/bluetooth/mesh/rpl/testcase.yaml | 6 ++++-- 2 files changed, 8 insertions(+), 4 deletions(-) diff --git a/tests/bluetooth/mesh/blob_io_flash/testcase.yaml b/tests/bluetooth/mesh/blob_io_flash/testcase.yaml index 3bc3651f5cc..c27ea3081af 100644 --- a/tests/bluetooth/mesh/blob_io_flash/testcase.yaml +++ b/tests/bluetooth/mesh/blob_io_flash/testcase.yaml @@ -1,8 +1,10 @@ tests: bluetooth.mesh.blob_io_flash: - platform_allow: native_posix + platform_allow: + - native_posix + - native_sim tags: - bluetooth - mesh integration_platforms: - - native_posix + - native_sim diff --git a/tests/bluetooth/mesh/rpl/testcase.yaml b/tests/bluetooth/mesh/rpl/testcase.yaml index e1f1d5323bf..16b947fe626 100644 --- a/tests/bluetooth/mesh/rpl/testcase.yaml +++ b/tests/bluetooth/mesh/rpl/testcase.yaml @@ -1,8 +1,10 @@ tests: bluetooth.mesh.rpl: - platform_allow: native_posix + platform_allow: + - native_posix + - native_sim tags: - bluetooth - mesh integration_platforms: - - native_posix + - native_sim From fd6f473515a58ab0cd9502f65639fa96cc07db6b Mon Sep 17 00:00:00 2001 From: Alberto Escolar Piedras Date: Mon, 20 Nov 2023 13:24:49 +0100 Subject: [PATCH 0070/3723] tests/bluetooth/ctrl_isoal: Remove instructions from header comment How to run tests is described in the twister documentation, let's not replicate that kind of instructions in all files. Signed-off-by: Alberto Escolar Piedras --- tests/bluetooth/ctrl_isoal/src/isoal_test_common.c | 5 ----- tests/bluetooth/ctrl_isoal/src/isoal_test_common.h | 5 ----- tests/bluetooth/ctrl_isoal/src/isoal_test_debug.c | 5 ----- tests/bluetooth/ctrl_isoal/src/isoal_test_debug.h | 5 ----- tests/bluetooth/ctrl_isoal/src/main.c | 5 ----- tests/bluetooth/ctrl_isoal/src/sub_sets/isoal_test_rx.c | 5 ----- tests/bluetooth/ctrl_isoal/src/sub_sets/isoal_test_tx.c | 5 ----- 7 files changed, 35 deletions(-) diff --git a/tests/bluetooth/ctrl_isoal/src/isoal_test_common.c b/tests/bluetooth/ctrl_isoal/src/isoal_test_common.c index 35947656336..32536201a3a 100644 --- a/tests/bluetooth/ctrl_isoal/src/isoal_test_common.c +++ b/tests/bluetooth/ctrl_isoal/src/isoal_test_common.c @@ -2,11 +2,6 @@ * Copyright (c) 2020 Demant * * SPDX-License-Identifier: Apache-2.0 - * - * Run this test from zephyr directory as: - * - * ./scripts/twister --coverage -p native_posix -v -T tests/bluetooth/ctrl_isoal/ - * */ #include diff --git a/tests/bluetooth/ctrl_isoal/src/isoal_test_common.h b/tests/bluetooth/ctrl_isoal/src/isoal_test_common.h index 730cb2e6f40..d9a6f146648 100644 --- a/tests/bluetooth/ctrl_isoal/src/isoal_test_common.h +++ b/tests/bluetooth/ctrl_isoal/src/isoal_test_common.h @@ -2,11 +2,6 @@ * Copyright (c) 2022 Demant * * SPDX-License-Identifier: Apache-2.0 - * - * Run this test from zephyr directory as: - * - * ./scripts/twister --coverage -p native_posix -v -T tests/bluetooth/ctrl_isoal/ - * */ #ifndef _ISOAL_TEST_COMMON_H_ diff --git a/tests/bluetooth/ctrl_isoal/src/isoal_test_debug.c b/tests/bluetooth/ctrl_isoal/src/isoal_test_debug.c index 084677cf462..d990a2b9629 100644 --- a/tests/bluetooth/ctrl_isoal/src/isoal_test_debug.c +++ b/tests/bluetooth/ctrl_isoal/src/isoal_test_debug.c @@ -2,11 +2,6 @@ * Copyright (c) 2020 Demant * * SPDX-License-Identifier: Apache-2.0 - * - * Run this test from zephyr directory as: - * - * ./scripts/twister --coverage -p native_posix -v -T tests/bluetooth/ctrl_isoal/ - * */ #include diff --git a/tests/bluetooth/ctrl_isoal/src/isoal_test_debug.h b/tests/bluetooth/ctrl_isoal/src/isoal_test_debug.h index 5fc535a0806..85465a9c539 100644 --- a/tests/bluetooth/ctrl_isoal/src/isoal_test_debug.h +++ b/tests/bluetooth/ctrl_isoal/src/isoal_test_debug.h @@ -2,11 +2,6 @@ * Copyright (c) 2020 Demant * * SPDX-License-Identifier: Apache-2.0 - * - * Run this test from zephyr directory as: - * - * ./scripts/twister --coverage -p native_posix -v -T tests/bluetooth/ctrl_isoal/ - * */ #ifndef _ISOAL_TEST_DEBUG_H_ diff --git a/tests/bluetooth/ctrl_isoal/src/main.c b/tests/bluetooth/ctrl_isoal/src/main.c index 8cbd36c509a..7c0747b3639 100644 --- a/tests/bluetooth/ctrl_isoal/src/main.c +++ b/tests/bluetooth/ctrl_isoal/src/main.c @@ -2,11 +2,6 @@ * Copyright (c) 2020 Demant * * SPDX-License-Identifier: Apache-2.0 - * - * Run this test from zephyr directory as: - * - * ./scripts/twister --coverage -p native_posix -v -T tests/bluetooth/ctrl_isoal/ - * */ #include diff --git a/tests/bluetooth/ctrl_isoal/src/sub_sets/isoal_test_rx.c b/tests/bluetooth/ctrl_isoal/src/sub_sets/isoal_test_rx.c index fdb86af1f5c..06407816c38 100644 --- a/tests/bluetooth/ctrl_isoal/src/sub_sets/isoal_test_rx.c +++ b/tests/bluetooth/ctrl_isoal/src/sub_sets/isoal_test_rx.c @@ -2,11 +2,6 @@ * Copyright (c) 2022 Demant * * SPDX-License-Identifier: Apache-2.0 - * - * Run this test from zephyr directory as: - * - * ./scripts/twister --coverage -p native_posix -v -T tests/bluetooth/ctrl_isoal/ - * */ FAKE_VALUE_FUNC(isoal_status_t, diff --git a/tests/bluetooth/ctrl_isoal/src/sub_sets/isoal_test_tx.c b/tests/bluetooth/ctrl_isoal/src/sub_sets/isoal_test_tx.c index c9a6fe67637..a8749a7909b 100644 --- a/tests/bluetooth/ctrl_isoal/src/sub_sets/isoal_test_tx.c +++ b/tests/bluetooth/ctrl_isoal/src/sub_sets/isoal_test_tx.c @@ -2,11 +2,6 @@ * Copyright (c) 2020 Demant * * SPDX-License-Identifier: Apache-2.0 - * - * Run this test from zephyr directory as: - * - * ./scripts/twister --coverage -p native_posix -v -T tests/bluetooth/ctrl_isoal/ - * */ /* Each segment header in a test would usually be written to when it is first From 53103b9a65a67ea55ce5c8b31619fc10a2460fcc Mon Sep 17 00:00:00 2001 From: Alberto Escolar Piedras Date: Mon, 20 Nov 2023 13:57:34 +0100 Subject: [PATCH 0071/3723] tests/bluetooth/shell: Enable for native_sim Enable these tests for native_sim and switch the default integration platform from native_posix to native_sim. Signed-off-by: Alberto Escolar Piedras --- tests/bluetooth/shell/boards/native_sim.conf | 16 +++++ .../bluetooth/shell/boards/native_sim_64.conf | 16 +++++ tests/bluetooth/shell/testcase.yaml | 58 +++++-------------- 3 files changed, 47 insertions(+), 43 deletions(-) create mode 100644 tests/bluetooth/shell/boards/native_sim.conf create mode 100644 tests/bluetooth/shell/boards/native_sim_64.conf diff --git a/tests/bluetooth/shell/boards/native_sim.conf b/tests/bluetooth/shell/boards/native_sim.conf new file mode 100644 index 00000000000..a2ab2f4e87a --- /dev/null +++ b/tests/bluetooth/shell/boards/native_sim.conf @@ -0,0 +1,16 @@ +CONFIG_NO_OPTIMIZATIONS=y +# Allows for copying larger amount of data into the shell +CONFIG_SHELL_BACKEND_SERIAL_RX_RING_BUFFER_SIZE=4096 + +# For native posix k_sleep is used in the data path as well as for shell input +# detection, hence data processing is at least two ticks per packet. To support +# 5ms ISO interval bidirectional data the system shall never stall for more +# than 1.5 ms in average. +CONFIG_SYS_CLOCK_TICKS_PER_SEC=500 + +# For LC3 the following configs are needed +CONFIG_FPU=y +CONFIG_LIBLC3=y +# The LC3 codec uses a large amount of stack. This app runs the codec in the work-queue, hence +# inctease stack size for that thread. +CONFIG_SYSTEM_WORKQUEUE_STACK_SIZE=4096 diff --git a/tests/bluetooth/shell/boards/native_sim_64.conf b/tests/bluetooth/shell/boards/native_sim_64.conf new file mode 100644 index 00000000000..a2ab2f4e87a --- /dev/null +++ b/tests/bluetooth/shell/boards/native_sim_64.conf @@ -0,0 +1,16 @@ +CONFIG_NO_OPTIMIZATIONS=y +# Allows for copying larger amount of data into the shell +CONFIG_SHELL_BACKEND_SERIAL_RX_RING_BUFFER_SIZE=4096 + +# For native posix k_sleep is used in the data path as well as for shell input +# detection, hence data processing is at least two ticks per packet. To support +# 5ms ISO interval bidirectional data the system shall never stall for more +# than 1.5 ms in average. +CONFIG_SYS_CLOCK_TICKS_PER_SEC=500 + +# For LC3 the following configs are needed +CONFIG_FPU=y +CONFIG_LIBLC3=y +# The LC3 codec uses a large amount of stack. This app runs the codec in the work-queue, hence +# inctease stack size for that thread. +CONFIG_SYSTEM_WORKQUEUE_STACK_SIZE=4096 diff --git a/tests/bluetooth/shell/testcase.yaml b/tests/bluetooth/shell/testcase.yaml index 4b46c8d6781..9dae1a53868 100644 --- a/tests/bluetooth/shell/testcase.yaml +++ b/tests/bluetooth/shell/testcase.yaml @@ -1,3 +1,10 @@ +common: + # Default platform_allow & integration_platforms for the tests below, which a few override + platform_allow: + - native_posix + - native_sim + integration_platforms: + - native_sim tests: bluetooth.shell.main: extra_configs: @@ -6,6 +13,8 @@ tests: - qemu_x86 - native_posix - native_posix_64 + - native_sim + - native_sim_64 - nrf52840dk_nrf52840 integration_platforms: - qemu_x86 @@ -21,9 +30,11 @@ tests: platform_allow: - native_posix - native_posix_64 + - native_sim + - native_sim_64 - nrf52840dk_nrf52840 integration_platforms: - - native_posix + - native_sim platform_exclude: nrf52dk_nrf52810 tags: bluetooth harness: keyboard @@ -37,19 +48,19 @@ tests: - qemu_x86 - native_posix - native_posix_64 + - native_sim + - native_sim_64 integration_platforms: - - native_posix + - native_sim platform_exclude: nrf52dk_nrf52810 tags: bluetooth harness: keyboard bluetooth.shell.no_privacy: build_only: true extra_args: CONFIG_BT_PRIVACY=n - platform_allow: native_posix tags: bluetooth bluetooth.shell.log_defaults: build_only: true - platform_allow: native_posix extra_args: CONF_FILE="log.conf" tags: bluetooth @@ -57,19 +68,16 @@ tests: bluetooth.shell.audio: extra_args: CONF_FILE="audio.conf" build_only: true - platform_allow: native_posix tags: bluetooth bluetooth.shell.audio.no_vcs: extra_args: CONF_FILE="audio.conf" build_only: true - platform_allow: native_posix extra_configs: - CONFIG_BT_VCP_VOL_REND=n tags: bluetooth bluetooth.shell.audio.no_vocs: extra_args: CONF_FILE="audio.conf" build_only: true - platform_allow: native_posix extra_configs: - CONFIG_BT_VOCS_MAX_INSTANCE_COUNT=0 - CONFIG_BT_VCP_VOL_REND_VOCS_INSTANCE_COUNT=0 @@ -77,7 +85,6 @@ tests: bluetooth.shell.audio.no_aics: extra_args: CONF_FILE="audio.conf" build_only: true - platform_allow: native_posix extra_configs: - CONFIG_BT_AICS_MAX_INSTANCE_COUNT=0 - CONFIG_BT_VCP_VOL_REND_AICS_INSTANCE_COUNT=0 @@ -86,7 +93,6 @@ tests: bluetooth.shell.audio.no_aics_vocs: extra_args: CONF_FILE="audio.conf" build_only: true - platform_allow: native_posix extra_configs: - CONFIG_BT_VOCS_MAX_INSTANCE_COUNT=0 - CONFIG_BT_VCP_VOL_REND_VOCS_INSTANCE_COUNT=0 @@ -97,14 +103,12 @@ tests: bluetooth.shell.audio.no_vcp_vol_ctlr: extra_args: CONF_FILE="audio.conf" build_only: true - platform_allow: native_posix extra_configs: - CONFIG_BT_VCP_VOL_CTLR=n tags: bluetooth bluetooth.shell.audio.no_vcs_vcp_vol_ctlr: extra_args: CONF_FILE="audio.conf" build_only: true - platform_allow: native_posix extra_configs: - CONFIG_BT_VCP_VOL_REND=n - CONFIG_BT_VCP_VOL_CTLR=n @@ -112,35 +116,30 @@ tests: bluetooth.shell.audio.vcp_vol_ctlr_no_aics_client: extra_args: CONF_FILE="audio.conf" build_only: true - platform_allow: native_posix extra_configs: - CONFIG_BT_VCP_VOL_CTLR_MAX_AICS_INST=0 tags: bluetooth bluetooth.shell.audio.vcp_vol_ctlr_no_vocs_client: extra_args: CONF_FILE="audio.conf" build_only: true - platform_allow: native_posix extra_configs: - CONFIG_BT_VCP_VOL_CTLR_MAX_VOCS_INST=0 tags: bluetooth bluetooth.shell.audio.no_micp_mic_dev: extra_args: CONF_FILE="audio.conf" build_only: true - platform_allow: native_posix extra_configs: - CONFIG_BT_MICP_MIC_DEV=n tags: bluetooth bluetooth.shell.audio.no_micp_mic_ctlr: extra_args: CONF_FILE="audio.conf" build_only: true - platform_allow: native_posix extra_configs: - CONFIG_BT_MICP_MIC_CTLR=n tags: bluetooth bluetooth.shell.audio.no_micp_mic_dev_micp_mic_ctlr: extra_args: CONF_FILE="audio.conf" build_only: true - platform_allow: native_posix extra_configs: - CONFIG_BT_MICP_MIC_DEV=n - CONFIG_BT_MICP_MIC_CTLR=n @@ -148,42 +147,36 @@ tests: bluetooth.shell.audio.micp_mic_ctlr_no_aics_client: extra_args: CONF_FILE="audio.conf" build_only: true - platform_allow: native_posix extra_configs: - CONFIG_BT_MICP_MIC_CTLR_MAX_AICS_INST=0 tags: bluetooth bluetooth.shell.audio.no_mcs: extra_args: CONF_FILE="audio.conf" build_only: true - platform_allow: native_posix extra_configs: - CONFIG_BT_MCS=n tags: bluetooth bluetooth.shell.audio.no_mcc: extra_args: CONF_FILE="audio.conf" build_only: true - platform_allow: native_posix extra_configs: - CONFIG_BT_MCC=n tags: bluetooth bluetooth.shell.audio.no_ots: extra_args: CONF_FILE="audio.conf" build_only: true - platform_allow: native_posix extra_configs: - CONFIG_BT_OTS=n tags: bluetooth bluetooth.shell.audio.no_mcc_ots: extra_args: CONF_FILE="audio.conf" build_only: true - platform_allow: native_posix extra_configs: - CONFIG_BT_MCC_OTS=n tags: bluetooth bluetooth.shell.audio.no_otsc: extra_args: CONF_FILE="audio.conf" build_only: true - platform_allow: native_posix extra_configs: - CONFIG_BT_OTS=n - CONFIG_BT_MCC_OTS=n @@ -191,68 +184,57 @@ tests: bluetooth.audio_shell.no_pac_snk: extra_args: CONF_FILE="audio.conf" build_only: true - platform_allow: native_posix extra_configs: - CONFIG_BT_PAC_SNK=n bluetooth.audio_shell.no_pac_src: extra_args: CONF_FILE="audio.conf" build_only: true - platform_allow: native_posix extra_configs: - CONFIG_BT_PAC_SRC=n bluetooth.audio_shell.no_unicast_client: extra_args: CONF_FILE="audio.conf" build_only: true - platform_allow: native_posix extra_configs: - CONFIG_BT_BAP_UNICAST_CLIENT=n bluetooth.audio_shell.no_unicast_server: extra_args: CONF_FILE="audio.conf" build_only: true - platform_allow: native_posix extra_configs: - CONFIG_BT_BAP_UNICAST_SERVER=n - CONFIG_BT_HAS=n bluetooth.audio_shell.no_server_ase_snk: extra_args: CONF_FILE="audio.conf" build_only: true - platform_allow: native_posix extra_configs: - CONFIG_BT_ASCS_ASE_SNK_COUNT=0 bluetooth.audio_shell.no_server_ase_src: extra_args: CONF_FILE="audio.conf" build_only: true - platform_allow: native_posix extra_configs: - CONFIG_BT_ASCS_ASE_SRC_COUNT=0 bluetooth.audio_shell.no_client_ase_snk: extra_args: CONF_FILE="audio.conf" build_only: true - platform_allow: native_posix extra_configs: - CONFIG_BT_BAP_UNICAST_CLIENT_ASE_SNK_COUNT=0 bluetooth.audio_shell.no_client_ase_src: extra_args: CONF_FILE="audio.conf" build_only: true - platform_allow: native_posix extra_configs: - CONFIG_BT_BAP_UNICAST_CLIENT_ASE_SRC_COUNT=0 bluetooth.audio_shell.no_broadcast_source: extra_args: CONF_FILE="audio.conf" build_only: true - platform_allow: native_posix extra_configs: - CONFIG_BT_BAP_BROADCAST_SOURCE=n bluetooth.audio_shell.no_broadcast_sink: extra_args: CONF_FILE="audio.conf" build_only: true - platform_allow: native_posix extra_configs: - CONFIG_BT_BAP_BROADCAST_SINK=n bluetooth.audio_shell.no_audio_tx: extra_args: CONF_FILE="audio.conf" build_only: true - platform_allow: native_posix extra_configs: - CONFIG_BT_BAP_BROADCAST_SOURCE=n - CONFIG_BT_BAP_UNICAST_CLIENT_ASE_SNK_COUNT=0 @@ -260,7 +242,6 @@ tests: bluetooth.audio_shell.no_audio_rx: extra_args: CONF_FILE="audio.conf" build_only: true - platform_allow: native_posix extra_configs: - CONFIG_BT_BAP_BROADCAST_SINK=n - CONFIG_BT_BAP_UNICAST_CLIENT_ASE_SRC_COUNT=0 @@ -268,26 +249,22 @@ tests: bluetooth.audio_shell.no_has: extra_args: CONF_FILE="audio.conf" build_only: true - platform_allow: native_posix extra_configs: - CONFIG_BT_HAS=n bluetooth.audio_shell.no_has_client: extra_args: CONF_FILE="audio.conf" build_only: true - platform_allow: native_posix extra_configs: - CONFIG_BT_HAS_CLIENT=n bluetooth.shell.audio.no_tbs: extra_args: CONF_FILE="audio.conf" build_only: true - platform_allow: native_posix extra_configs: - CONFIG_BT_TBS=n tags: bluetooth bluetooth.shell.audio.no_tbs_client: extra_args: CONF_FILE="audio.conf" build_only: true - platform_allow: native_posix extra_configs: - CONFIG_BT_TBS_CLIENT_TBS=n - CONFIG_BT_TBS_CLIENT_GTBS=n @@ -295,32 +272,27 @@ tests: bluetooth.shell.audio.tbs_only_client: extra_args: CONF_FILE="audio.conf" build_only: true - platform_allow: native_posix extra_configs: - CONFIG_BT_TBS_CLIENT_GTBS=n tags: bluetooth bluetooth.shell.audio.gtbs_only_client: extra_args: CONF_FILE="audio.conf" build_only: true - platform_allow: native_posix extra_configs: - CONFIG_BT_TBS_CLIENT_TBS=n tags: bluetooth bluetooth.audio_shell.no_cap_acceptor: extra_args: CONF_FILE="audio.conf" build_only: true - platform_allow: native_posix extra_configs: - CONFIG_BT_CAP_ACCEPTOR=n bluetooth.audio_shell.no_cap_acceptor_set_member: extra_args: CONF_FILE="audio.conf" build_only: true - platform_allow: native_posix extra_configs: - CONFIG_BT_CAP_ACCEPTOR_SET_MEMBER=n bluetooth.audio_shell.no_cap_initiator: extra_args: CONF_FILE="audio.conf" build_only: true - platform_allow: native_posix extra_configs: - CONFIG_BT_CAP_INITIATOR=n From ed2251ae751e7b1109a0f525ca7807dcb32a4579 Mon Sep 17 00:00:00 2001 From: Alberto Escolar Piedras Date: Mon, 20 Nov 2023 14:03:07 +0100 Subject: [PATCH 0072/3723] tests/bluetooth/hci_uart_async: Switch to native_sim Switch from native_posix to native_sim as default test platform And add overlays for native_sim. Signed-off-by: Alberto Escolar Piedras --- tests/bluetooth/hci_uart_async/boards/native_posix.conf | 2 +- tests/bluetooth/hci_uart_async/boards/native_sim.conf | 3 +++ tests/bluetooth/hci_uart_async/testcase.yaml | 3 +++ 3 files changed, 7 insertions(+), 1 deletion(-) create mode 100644 tests/bluetooth/hci_uart_async/boards/native_sim.conf diff --git a/tests/bluetooth/hci_uart_async/boards/native_posix.conf b/tests/bluetooth/hci_uart_async/boards/native_posix.conf index e638cd6a0ef..d9130d07be5 100644 --- a/tests/bluetooth/hci_uart_async/boards/native_posix.conf +++ b/tests/bluetooth/hci_uart_async/boards/native_posix.conf @@ -1,3 +1,3 @@ -# Print logs and test results on stdout. For some reason, this not the +# Print logs and test results on stdout as this not the # default when SERIAL=y. CONFIG_LOG_BACKEND_NATIVE_POSIX=y diff --git a/tests/bluetooth/hci_uart_async/boards/native_sim.conf b/tests/bluetooth/hci_uart_async/boards/native_sim.conf new file mode 100644 index 00000000000..d9130d07be5 --- /dev/null +++ b/tests/bluetooth/hci_uart_async/boards/native_sim.conf @@ -0,0 +1,3 @@ +# Print logs and test results on stdout as this not the +# default when SERIAL=y. +CONFIG_LOG_BACKEND_NATIVE_POSIX=y diff --git a/tests/bluetooth/hci_uart_async/testcase.yaml b/tests/bluetooth/hci_uart_async/testcase.yaml index 31b7ac8bde4..8df5113b354 100644 --- a/tests/bluetooth/hci_uart_async/testcase.yaml +++ b/tests/bluetooth/hci_uart_async/testcase.yaml @@ -6,3 +6,6 @@ tests: harness: ztest platform_allow: - native_posix + - native_sim + integration_platforms: + - native_sim From 6c9dfe1b2c1821d86693cb4d1100d884584060b4 Mon Sep 17 00:00:00 2001 From: Alberto Escolar Piedras Date: Mon, 20 Nov 2023 14:00:59 +0100 Subject: [PATCH 0073/3723] tests/bluetooth/*: Enable for native_sim Enable all remaining bluetooth tests for native_sim and switch from native_posix to native_sim as default test platform Signed-off-by: Alberto Escolar Piedras --- tests/bluetooth/addr/testcase.yaml | 4 +++- tests/bluetooth/bluetooth/testcase.yaml | 2 ++ tests/bluetooth/bt_crypto/testcase.yaml | 4 +++- tests/bluetooth/bt_crypto_ccm/testcase.yaml | 4 +++- tests/bluetooth/ctrl_isoal/testcase.yaml | 6 +++++- tests/bluetooth/ctrl_sw_privacy_unit/testcase.yaml | 6 +++++- tests/bluetooth/gatt/testcase.yaml | 4 +++- tests/bluetooth/hci_prop_evt/testcase.yaml | 4 +++- tests/bluetooth/host_long_adv_recv/testcase.yaml | 4 +++- tests/bluetooth/l2cap/testcase.yaml | 4 +++- tests/bluetooth/uuid/testcase.yaml | 4 +++- 11 files changed, 36 insertions(+), 10 deletions(-) diff --git a/tests/bluetooth/addr/testcase.yaml b/tests/bluetooth/addr/testcase.yaml index 8a803c14d40..736d4b5a2ba 100644 --- a/tests/bluetooth/addr/testcase.yaml +++ b/tests/bluetooth/addr/testcase.yaml @@ -3,10 +3,12 @@ tests: platform_allow: - native_posix - native_posix_64 + - native_sim + - native_sim_64 - qemu_x86 - qemu_cortex_m3 tags: - bluetooth - addr integration_platforms: - - native_posix + - native_sim diff --git a/tests/bluetooth/bluetooth/testcase.yaml b/tests/bluetooth/bluetooth/testcase.yaml index d423b051539..7f8ac610821 100644 --- a/tests/bluetooth/bluetooth/testcase.yaml +++ b/tests/bluetooth/bluetooth/testcase.yaml @@ -5,6 +5,8 @@ tests: - qemu_cortex_m3 - native_posix - native_posix_64 + - native_sim + - native_sim_64 integration_platforms: - qemu_x86 tags: bluetooth diff --git a/tests/bluetooth/bt_crypto/testcase.yaml b/tests/bluetooth/bt_crypto/testcase.yaml index 4c24d9fb05c..5de0839b29e 100644 --- a/tests/bluetooth/bt_crypto/testcase.yaml +++ b/tests/bluetooth/bt_crypto/testcase.yaml @@ -3,8 +3,10 @@ tests: platform_allow: - native_posix - native_posix_64 + - native_sim + - native_sim_64 - qemu_x86 - qemu_cortex_m3 integration_platforms: - - native_posix + - native_sim tags: bluetooth diff --git a/tests/bluetooth/bt_crypto_ccm/testcase.yaml b/tests/bluetooth/bt_crypto_ccm/testcase.yaml index 119ff184f42..b1827e56aff 100644 --- a/tests/bluetooth/bt_crypto_ccm/testcase.yaml +++ b/tests/bluetooth/bt_crypto_ccm/testcase.yaml @@ -3,6 +3,8 @@ tests: platform_allow: - native_posix - native_posix_64 + - native_sim + - native_sim_64 integration_platforms: - - native_posix + - native_sim tags: bluetooth diff --git a/tests/bluetooth/ctrl_isoal/testcase.yaml b/tests/bluetooth/ctrl_isoal/testcase.yaml index 9b7b4a1f06a..d638f089b3d 100644 --- a/tests/bluetooth/ctrl_isoal/testcase.yaml +++ b/tests/bluetooth/ctrl_isoal/testcase.yaml @@ -2,4 +2,8 @@ common: tags: bluetooth tests: bluetooth.isoal.test: - platform_allow: native_posix + platform_allow: + - native_posix + - native_sim + integration_platforms: + - native_sim diff --git a/tests/bluetooth/ctrl_sw_privacy_unit/testcase.yaml b/tests/bluetooth/ctrl_sw_privacy_unit/testcase.yaml index a965acfbcae..7dd0dcbc16e 100644 --- a/tests/bluetooth/ctrl_sw_privacy_unit/testcase.yaml +++ b/tests/bluetooth/ctrl_sw_privacy_unit/testcase.yaml @@ -2,4 +2,8 @@ common: tags: bluetooth tests: bluetooth.privacy.test: - platform_allow: native_posix + platform_allow: + - native_posix + - native_sim + integration_platforms: + - native_sim diff --git a/tests/bluetooth/gatt/testcase.yaml b/tests/bluetooth/gatt/testcase.yaml index 5acd7838610..9a02af34de0 100644 --- a/tests/bluetooth/gatt/testcase.yaml +++ b/tests/bluetooth/gatt/testcase.yaml @@ -3,10 +3,12 @@ tests: platform_allow: - native_posix - native_posix_64 + - native_sim + - native_sim_64 - qemu_x86 - qemu_cortex_m3 integration_platforms: - - native_posix + - native_sim tags: - bluetooth - gatt diff --git a/tests/bluetooth/hci_prop_evt/testcase.yaml b/tests/bluetooth/hci_prop_evt/testcase.yaml index 457414d5082..6f41a722e80 100644 --- a/tests/bluetooth/hci_prop_evt/testcase.yaml +++ b/tests/bluetooth/hci_prop_evt/testcase.yaml @@ -5,8 +5,10 @@ tests: - qemu_cortex_m3 - native_posix - native_posix_64 + - native_sim + - native_sim_64 integration_platforms: - - native_posix + - native_sim tags: - bluetooth - hci diff --git a/tests/bluetooth/host_long_adv_recv/testcase.yaml b/tests/bluetooth/host_long_adv_recv/testcase.yaml index 708bef794c8..a94b021d1ef 100644 --- a/tests/bluetooth/host_long_adv_recv/testcase.yaml +++ b/tests/bluetooth/host_long_adv_recv/testcase.yaml @@ -3,8 +3,10 @@ tests: platform_allow: - native_posix - native_posix_64 + - native_sim + - native_sim_64 integration_platforms: - - native_posix + - native_sim tags: - bluetooth - host diff --git a/tests/bluetooth/l2cap/testcase.yaml b/tests/bluetooth/l2cap/testcase.yaml index 39b7164a37f..18a2fc52858 100644 --- a/tests/bluetooth/l2cap/testcase.yaml +++ b/tests/bluetooth/l2cap/testcase.yaml @@ -3,10 +3,12 @@ tests: platform_allow: - native_posix - native_posix_64 + - native_sim + - native_sim_64 - qemu_x86 - qemu_cortex_m3 integration_platforms: - - native_posix + - native_sim tags: - bluetooth - l2cap diff --git a/tests/bluetooth/uuid/testcase.yaml b/tests/bluetooth/uuid/testcase.yaml index bfd161e7cd4..d7ad13764d1 100644 --- a/tests/bluetooth/uuid/testcase.yaml +++ b/tests/bluetooth/uuid/testcase.yaml @@ -3,10 +3,12 @@ tests: platform_allow: - native_posix - native_posix_64 + - native_sim + - native_sim_64 - qemu_x86 - qemu_cortex_m3 integration_platforms: - - native_posix + - native_sim tags: - bluetooth - uuid From c1fa9f736b768568739ba82b95e7098de2bfafd9 Mon Sep 17 00:00:00 2001 From: Alberto Escolar Piedras Date: Mon, 20 Nov 2023 12:45:13 +0100 Subject: [PATCH 0074/3723] tests/drivers kscan_input: Switch to native_sim Switch from native_posix to native_sim as default test platform And switch overlays to native_sim. Signed-off-by: Alberto Escolar Piedras --- .../boards/{native_posix.overlay => native_sim.overlay} | 0 .../{native_posix_64.overlay => native_sim_64.overlay} | 2 +- tests/drivers/kscan/kscan_input/testcase.yaml | 6 +++--- 3 files changed, 4 insertions(+), 4 deletions(-) rename tests/drivers/kscan/kscan_input/boards/{native_posix.overlay => native_sim.overlay} (100%) rename tests/drivers/kscan/kscan_input/boards/{native_posix_64.overlay => native_sim_64.overlay} (70%) diff --git a/tests/drivers/kscan/kscan_input/boards/native_posix.overlay b/tests/drivers/kscan/kscan_input/boards/native_sim.overlay similarity index 100% rename from tests/drivers/kscan/kscan_input/boards/native_posix.overlay rename to tests/drivers/kscan/kscan_input/boards/native_sim.overlay diff --git a/tests/drivers/kscan/kscan_input/boards/native_posix_64.overlay b/tests/drivers/kscan/kscan_input/boards/native_sim_64.overlay similarity index 70% rename from tests/drivers/kscan/kscan_input/boards/native_posix_64.overlay rename to tests/drivers/kscan/kscan_input/boards/native_sim_64.overlay index 166e6f02e82..a906fce7488 100644 --- a/tests/drivers/kscan/kscan_input/boards/native_posix_64.overlay +++ b/tests/drivers/kscan/kscan_input/boards/native_sim_64.overlay @@ -3,4 +3,4 @@ * * SPDX-License-Identifier: Apache-2.0 */ -#include "native_posix.overlay" +#include "native_sim.overlay" diff --git a/tests/drivers/kscan/kscan_input/testcase.yaml b/tests/drivers/kscan/kscan_input/testcase.yaml index 9b233608dd2..e9565c5de0f 100644 --- a/tests/drivers/kscan/kscan_input/testcase.yaml +++ b/tests/drivers/kscan/kscan_input/testcase.yaml @@ -3,11 +3,11 @@ tests: drivers.input.kscan_input: platform_allow: - - native_posix - - native_posix_64 + - native_sim + - native_sim_64 tags: - drivers - kscan - input integration_platforms: - - native_posix + - native_sim From a7ee8b27574c1b4e4d90fa35a75d3a964fb90eb8 Mon Sep 17 00:00:00 2001 From: Alberto Escolar Piedras Date: Mon, 20 Nov 2023 12:50:21 +0100 Subject: [PATCH 0075/3723] tests/drivers/adc: Switch to native_sim Switch from native_posix to native_sim as default test platform. For test with overlays, switch overlays and platform_allow from native_posix to native_sim. For tests without overlays, enable also in native_sim, and set native_sim as integration platform. Signed-off-by: Alberto Escolar Piedras --- tests/drivers/adc/adc_emul/testcase.yaml | 6 +++++- .../boards/{native_posix.overlay => native_sim.overlay} | 0 .../{native_posix_64.overlay => native_sim_64.overlay} | 2 +- tests/drivers/adc/adc_rescale/testcase.yaml | 4 +++- 4 files changed, 9 insertions(+), 3 deletions(-) rename tests/drivers/adc/adc_rescale/boards/{native_posix.overlay => native_sim.overlay} (100%) rename tests/drivers/adc/adc_rescale/boards/{native_posix_64.overlay => native_sim_64.overlay} (73%) diff --git a/tests/drivers/adc/adc_emul/testcase.yaml b/tests/drivers/adc/adc_emul/testcase.yaml index 6f857096531..a82efd67a93 100644 --- a/tests/drivers/adc/adc_emul/testcase.yaml +++ b/tests/drivers/adc/adc_emul/testcase.yaml @@ -6,4 +6,8 @@ common: tests: drivers.adc.emul: depends_on: adc - platform_allow: native_posix + platform_allow: + - native_posix + - native_sim + integration_platforms: + - native_sim diff --git a/tests/drivers/adc/adc_rescale/boards/native_posix.overlay b/tests/drivers/adc/adc_rescale/boards/native_sim.overlay similarity index 100% rename from tests/drivers/adc/adc_rescale/boards/native_posix.overlay rename to tests/drivers/adc/adc_rescale/boards/native_sim.overlay diff --git a/tests/drivers/adc/adc_rescale/boards/native_posix_64.overlay b/tests/drivers/adc/adc_rescale/boards/native_sim_64.overlay similarity index 73% rename from tests/drivers/adc/adc_rescale/boards/native_posix_64.overlay rename to tests/drivers/adc/adc_rescale/boards/native_sim_64.overlay index b71b19b0e76..13b1a7899b9 100644 --- a/tests/drivers/adc/adc_rescale/boards/native_posix_64.overlay +++ b/tests/drivers/adc/adc_rescale/boards/native_sim_64.overlay @@ -3,4 +3,4 @@ * * SPDX-License-Identifier: Apache-2.0 */ -#include "native_posix.overlay" +#include "native_sim.overlay" diff --git a/tests/drivers/adc/adc_rescale/testcase.yaml b/tests/drivers/adc/adc_rescale/testcase.yaml index 3d60d071486..a03f30895cc 100644 --- a/tests/drivers/adc/adc_rescale/testcase.yaml +++ b/tests/drivers/adc/adc_rescale/testcase.yaml @@ -3,4 +3,6 @@ common: tests: drivers.adc.rescale: depends_on: adc - platform_allow: native_posix + platform_allow: + - native_sim + - native_sim_64 From 5c7eae67450f16f02889e9e82d414bb55c1685e9 Mon Sep 17 00:00:00 2001 From: Alberto Escolar Piedras Date: Mon, 20 Nov 2023 12:57:08 +0100 Subject: [PATCH 0076/3723] tests/drivers/bbram: Switch to native_sim Switch from native_posix to native_sim as default test platform, switch overlays to native_sim. For the HW test, filter whole posix arch to speed up twister run. Signed-off-by: Alberto Escolar Piedras --- .../emul/boards/{native_posix.overlay => native_sim.overlay} | 0 tests/drivers/bbram/emul/testcase.yaml | 4 ++-- tests/drivers/bbram/testcase.yaml | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) rename tests/drivers/bbram/emul/boards/{native_posix.overlay => native_sim.overlay} (100%) diff --git a/tests/drivers/bbram/emul/boards/native_posix.overlay b/tests/drivers/bbram/emul/boards/native_sim.overlay similarity index 100% rename from tests/drivers/bbram/emul/boards/native_posix.overlay rename to tests/drivers/bbram/emul/boards/native_sim.overlay diff --git a/tests/drivers/bbram/emul/testcase.yaml b/tests/drivers/bbram/emul/testcase.yaml index 49ca3ec6e74..219027b85aa 100644 --- a/tests/drivers/bbram/emul/testcase.yaml +++ b/tests/drivers/bbram/emul/testcase.yaml @@ -7,6 +7,6 @@ tests: - drivers - bbram harness: ztest - platform_allow: native_posix + platform_allow: native_sim integration_platforms: - - native_posix + - native_sim diff --git a/tests/drivers/bbram/testcase.yaml b/tests/drivers/bbram/testcase.yaml index db1d1640772..261b1f137b3 100644 --- a/tests/drivers/bbram/testcase.yaml +++ b/tests/drivers/bbram/testcase.yaml @@ -7,7 +7,7 @@ common: - bbram build_only: true harness: ztest - platform_exclude: native_posix + arch_exclude: posix tests: drivers.bbram.it8xxx2: filter: dt_compat_enabled("ite,it8xxx2-bbram") From 5f61df65698d62a6aa1f62717fdd9064a2271b88 Mon Sep 17 00:00:00 2001 From: Alberto Escolar Piedras Date: Mon, 20 Nov 2023 13:00:25 +0100 Subject: [PATCH 0077/3723] tests/drivers/bc12: Switch to native_sim Switch from native_posix to native_sim as default test platform And switch overlays to native_sim. Signed-off-by: Alberto Escolar Piedras --- .../drivers/bc12/boards/{native_posix.conf => native_sim.conf} | 0 .../bc12/boards/{native_posix.overlay => native_sim.overlay} | 0 tests/drivers/bc12/testcase.yaml | 2 +- 3 files changed, 1 insertion(+), 1 deletion(-) rename tests/drivers/bc12/boards/{native_posix.conf => native_sim.conf} (100%) rename tests/drivers/bc12/boards/{native_posix.overlay => native_sim.overlay} (100%) diff --git a/tests/drivers/bc12/boards/native_posix.conf b/tests/drivers/bc12/boards/native_sim.conf similarity index 100% rename from tests/drivers/bc12/boards/native_posix.conf rename to tests/drivers/bc12/boards/native_sim.conf diff --git a/tests/drivers/bc12/boards/native_posix.overlay b/tests/drivers/bc12/boards/native_sim.overlay similarity index 100% rename from tests/drivers/bc12/boards/native_posix.overlay rename to tests/drivers/bc12/boards/native_sim.overlay diff --git a/tests/drivers/bc12/testcase.yaml b/tests/drivers/bc12/testcase.yaml index 1562b625592..36f879fb2f7 100644 --- a/tests/drivers/bc12/testcase.yaml +++ b/tests/drivers/bc12/testcase.yaml @@ -4,4 +4,4 @@ tests: - drivers - usb - bc12 - platform_allow: native_posix + platform_allow: native_sim From 982425f8188887e2ab0da65efd825b7216cc1797 Mon Sep 17 00:00:00 2001 From: Alberto Escolar Piedras Date: Mon, 20 Nov 2023 13:14:02 +0100 Subject: [PATCH 0078/3723] tests/drivers/gpio/*: Switch to native_sim Switch from native_posix to native_sim as default test platform And switch overlays to native_sim. For gpio_enable_disable_interrupt, also filter with platform_allow to save time, as the dt filter requires cmake to be run, but only the platforms with overlays provided by the test can be run. Signed-off-by: Alberto Escolar Piedras --- ...ative_posix.overlay => native_sim.overlay} | 0 ...posix_64.overlay => native_sim_64.overlay} | 2 +- ...ative_posix.overlay => native_sim.overlay} | 0 ...posix_64.overlay => native_sim_64.overlay} | 2 +- .../boards/native_posix_64.overlay | 1 - ...ative_posix.overlay => native_sim.overlay} | 0 .../boards/native_sim_64.overlay | 1 + .../testcase.yaml | 3 ++ .../boards/native_posix_64.overlay | 1 - ...ative_posix.overlay => native_sim.overlay} | 0 .../boards/native_sim_64.overlay | 1 + .../gpio_hogs/boards/native_posix_64.overlay | 35 ------------------- ...ative_posix.overlay => native_sim.overlay} | 0 .../gpio_hogs/boards/native_sim_64.overlay | 7 ++++ tests/drivers/gpio/gpio_hogs/testcase.yaml | 8 ++--- .../boards/native_posix_64.overlay | 2 +- .../gpio/gpio_reserved_ranges/testcase.yaml | 8 +++-- 17 files changed, 24 insertions(+), 47 deletions(-) rename tests/drivers/gpio/gpio_api_1pin/boards/{native_posix.overlay => native_sim.overlay} (100%) rename tests/drivers/gpio/gpio_api_1pin/boards/{native_posix_64.overlay => native_sim_64.overlay} (78%) rename tests/drivers/gpio/gpio_basic_api/boards/{native_posix.overlay => native_sim.overlay} (100%) rename tests/drivers/gpio/gpio_basic_api/boards/{native_posix_64.overlay => native_sim_64.overlay} (78%) delete mode 100644 tests/drivers/gpio/gpio_enable_disable_interrupt/boards/native_posix_64.overlay rename tests/drivers/gpio/gpio_enable_disable_interrupt/boards/{native_posix.overlay => native_sim.overlay} (100%) create mode 100644 tests/drivers/gpio/gpio_enable_disable_interrupt/boards/native_sim_64.overlay delete mode 100644 tests/drivers/gpio/gpio_get_direction/boards/native_posix_64.overlay rename tests/drivers/gpio/gpio_get_direction/boards/{native_posix.overlay => native_sim.overlay} (100%) create mode 100644 tests/drivers/gpio/gpio_get_direction/boards/native_sim_64.overlay delete mode 100644 tests/drivers/gpio/gpio_hogs/boards/native_posix_64.overlay rename tests/drivers/gpio/gpio_hogs/boards/{native_posix.overlay => native_sim.overlay} (100%) create mode 100644 tests/drivers/gpio/gpio_hogs/boards/native_sim_64.overlay diff --git a/tests/drivers/gpio/gpio_api_1pin/boards/native_posix.overlay b/tests/drivers/gpio/gpio_api_1pin/boards/native_sim.overlay similarity index 100% rename from tests/drivers/gpio/gpio_api_1pin/boards/native_posix.overlay rename to tests/drivers/gpio/gpio_api_1pin/boards/native_sim.overlay diff --git a/tests/drivers/gpio/gpio_api_1pin/boards/native_posix_64.overlay b/tests/drivers/gpio/gpio_api_1pin/boards/native_sim_64.overlay similarity index 78% rename from tests/drivers/gpio/gpio_api_1pin/boards/native_posix_64.overlay rename to tests/drivers/gpio/gpio_api_1pin/boards/native_sim_64.overlay index 02b0040e8a6..2a9749002bd 100644 --- a/tests/drivers/gpio/gpio_api_1pin/boards/native_posix_64.overlay +++ b/tests/drivers/gpio/gpio_api_1pin/boards/native_sim_64.overlay @@ -3,4 +3,4 @@ * * SPDX-License-Identifier: Apache-2.0 */ -#include "native_posix.overlay" +#include "native_sim.overlay" diff --git a/tests/drivers/gpio/gpio_basic_api/boards/native_posix.overlay b/tests/drivers/gpio/gpio_basic_api/boards/native_sim.overlay similarity index 100% rename from tests/drivers/gpio/gpio_basic_api/boards/native_posix.overlay rename to tests/drivers/gpio/gpio_basic_api/boards/native_sim.overlay diff --git a/tests/drivers/gpio/gpio_basic_api/boards/native_posix_64.overlay b/tests/drivers/gpio/gpio_basic_api/boards/native_sim_64.overlay similarity index 78% rename from tests/drivers/gpio/gpio_basic_api/boards/native_posix_64.overlay rename to tests/drivers/gpio/gpio_basic_api/boards/native_sim_64.overlay index 02b0040e8a6..2a9749002bd 100644 --- a/tests/drivers/gpio/gpio_basic_api/boards/native_posix_64.overlay +++ b/tests/drivers/gpio/gpio_basic_api/boards/native_sim_64.overlay @@ -3,4 +3,4 @@ * * SPDX-License-Identifier: Apache-2.0 */ -#include "native_posix.overlay" +#include "native_sim.overlay" diff --git a/tests/drivers/gpio/gpio_enable_disable_interrupt/boards/native_posix_64.overlay b/tests/drivers/gpio/gpio_enable_disable_interrupt/boards/native_posix_64.overlay deleted file mode 100644 index 2b055bf3de6..00000000000 --- a/tests/drivers/gpio/gpio_enable_disable_interrupt/boards/native_posix_64.overlay +++ /dev/null @@ -1 +0,0 @@ -#include "native_posix.overlay" diff --git a/tests/drivers/gpio/gpio_enable_disable_interrupt/boards/native_posix.overlay b/tests/drivers/gpio/gpio_enable_disable_interrupt/boards/native_sim.overlay similarity index 100% rename from tests/drivers/gpio/gpio_enable_disable_interrupt/boards/native_posix.overlay rename to tests/drivers/gpio/gpio_enable_disable_interrupt/boards/native_sim.overlay diff --git a/tests/drivers/gpio/gpio_enable_disable_interrupt/boards/native_sim_64.overlay b/tests/drivers/gpio/gpio_enable_disable_interrupt/boards/native_sim_64.overlay new file mode 100644 index 00000000000..6a3daca3241 --- /dev/null +++ b/tests/drivers/gpio/gpio_enable_disable_interrupt/boards/native_sim_64.overlay @@ -0,0 +1 @@ +#include "native_sim.overlay" diff --git a/tests/drivers/gpio/gpio_enable_disable_interrupt/testcase.yaml b/tests/drivers/gpio/gpio_enable_disable_interrupt/testcase.yaml index e60dc4efe86..0e88895295e 100644 --- a/tests/drivers/gpio/gpio_enable_disable_interrupt/testcase.yaml +++ b/tests/drivers/gpio/gpio_enable_disable_interrupt/testcase.yaml @@ -5,3 +5,6 @@ tests: - gpio depends_on: gpio filter: dt_compat_enabled("test-gpio-enable-disable-interrupt") + platform_allow: + - native_sim + - native_sim_64 diff --git a/tests/drivers/gpio/gpio_get_direction/boards/native_posix_64.overlay b/tests/drivers/gpio/gpio_get_direction/boards/native_posix_64.overlay deleted file mode 100644 index 2b055bf3de6..00000000000 --- a/tests/drivers/gpio/gpio_get_direction/boards/native_posix_64.overlay +++ /dev/null @@ -1 +0,0 @@ -#include "native_posix.overlay" diff --git a/tests/drivers/gpio/gpio_get_direction/boards/native_posix.overlay b/tests/drivers/gpio/gpio_get_direction/boards/native_sim.overlay similarity index 100% rename from tests/drivers/gpio/gpio_get_direction/boards/native_posix.overlay rename to tests/drivers/gpio/gpio_get_direction/boards/native_sim.overlay diff --git a/tests/drivers/gpio/gpio_get_direction/boards/native_sim_64.overlay b/tests/drivers/gpio/gpio_get_direction/boards/native_sim_64.overlay new file mode 100644 index 00000000000..6a3daca3241 --- /dev/null +++ b/tests/drivers/gpio/gpio_get_direction/boards/native_sim_64.overlay @@ -0,0 +1 @@ +#include "native_sim.overlay" diff --git a/tests/drivers/gpio/gpio_hogs/boards/native_posix_64.overlay b/tests/drivers/gpio/gpio_hogs/boards/native_posix_64.overlay deleted file mode 100644 index 44a29b59ab3..00000000000 --- a/tests/drivers/gpio/gpio_hogs/boards/native_posix_64.overlay +++ /dev/null @@ -1,35 +0,0 @@ -/* - * Copyright (c) 2023 Vestas Wind Systems A/S - * - * SPDX-License-Identifier: Apache-2.0 -*/ - -#include - -/ { - zephyr,user { - output-high-gpios = <&gpio0 1 GPIO_ACTIVE_LOW>; - output-low-gpios = <&gpio0 2 GPIO_ACTIVE_HIGH>; - input-gpios = <&gpio0 3 GPIO_ACTIVE_HIGH>; - }; -}; - -&gpio0 { - hog1 { - gpio-hog; - gpios = <1 GPIO_ACTIVE_LOW>; - output-high; - }; - - hog2 { - gpio-hog; - gpios = <2 GPIO_ACTIVE_HIGH>; - output-low; - }; - - hog3 { - gpio-hog; - gpios = <3 GPIO_ACTIVE_HIGH>; - input; - }; -}; diff --git a/tests/drivers/gpio/gpio_hogs/boards/native_posix.overlay b/tests/drivers/gpio/gpio_hogs/boards/native_sim.overlay similarity index 100% rename from tests/drivers/gpio/gpio_hogs/boards/native_posix.overlay rename to tests/drivers/gpio/gpio_hogs/boards/native_sim.overlay diff --git a/tests/drivers/gpio/gpio_hogs/boards/native_sim_64.overlay b/tests/drivers/gpio/gpio_hogs/boards/native_sim_64.overlay new file mode 100644 index 00000000000..d3b3d261734 --- /dev/null +++ b/tests/drivers/gpio/gpio_hogs/boards/native_sim_64.overlay @@ -0,0 +1,7 @@ +/* + * Copyright (c) 2023 Vestas Wind Systems A/S + * + * SPDX-License-Identifier: Apache-2.0 +*/ + +#include "native_sim.overlay" diff --git a/tests/drivers/gpio/gpio_hogs/testcase.yaml b/tests/drivers/gpio/gpio_hogs/testcase.yaml index 6c02bf5f7f1..98e279b789c 100644 --- a/tests/drivers/gpio/gpio_hogs/testcase.yaml +++ b/tests/drivers/gpio/gpio_hogs/testcase.yaml @@ -5,8 +5,8 @@ tests: - gpio depends_on: gpio platform_allow: - - native_posix - - native_posix_64 + - native_sim + - native_sim_64 - frdm_k64f - nrf52840dk_nrf52840 - nucleo_g474re @@ -15,5 +15,5 @@ tests: - s32z270dc2_rtu0_r52 - s32z270dc2_rtu1_r52 integration_platforms: - - native_posix - - native_posix_64 + - native_sim + - native_sim_64 diff --git a/tests/drivers/gpio/gpio_reserved_ranges/boards/native_posix_64.overlay b/tests/drivers/gpio/gpio_reserved_ranges/boards/native_posix_64.overlay index 0d3e3ea93f2..2c46f3ddc56 100644 --- a/tests/drivers/gpio/gpio_reserved_ranges/boards/native_posix_64.overlay +++ b/tests/drivers/gpio/gpio_reserved_ranges/boards/native_posix_64.overlay @@ -3,4 +3,4 @@ * * SPDX-License-Identifier: Apache-2.0 */ -#include "native_posix.overlay" +#include "native_sim.overlay" diff --git a/tests/drivers/gpio/gpio_reserved_ranges/testcase.yaml b/tests/drivers/gpio/gpio_reserved_ranges/testcase.yaml index 57c6f2c291a..015cf79c3fc 100644 --- a/tests/drivers/gpio/gpio_reserved_ranges/testcase.yaml +++ b/tests/drivers/gpio/gpio_reserved_ranges/testcase.yaml @@ -3,7 +3,9 @@ tests: tags: drivers gpio depends_on: gpio filter: dt_compat_enabled("test-gpio-reserved-ranges") - platform_allow: native_posix native_posix_64 + platform_allow: + - native_sim + - native_sim_64 integration_platforms: - - native_posix - - native_posix_64 + - native_sim + - native_sim_64 From 3692675dcf4e54fd6ebcc6b2a3688a31d151892b Mon Sep 17 00:00:00 2001 From: Alberto Escolar Piedras Date: Mon, 20 Nov 2023 14:27:29 +0100 Subject: [PATCH 0079/3723] tests/subsys/settings/fcb: Switch to native_sim Switch from native_posix to native_sim as default test platform Switch overlays from native_posix to native_sim. And move overlays into a boards/ directory Signed-off-by: Alberto Escolar Piedras --- .../native_sim.overlay} | 0 .../settings/fcb/boards/native_sim_64.overlay | 7 ++++++ .../{ => boards}/nrf52840dk_nrf52840.overlay | 0 .../fcb/{ => boards}/nrf52dk_nrf52832.overlay | 0 .../settings/fcb/native_posix_64.overlay | 22 ------------------- tests/subsys/settings/fcb/testcase.yaml | 6 ++--- 6 files changed, 10 insertions(+), 25 deletions(-) rename tests/subsys/settings/fcb/{native_posix.overlay => boards/native_sim.overlay} (100%) create mode 100644 tests/subsys/settings/fcb/boards/native_sim_64.overlay rename tests/subsys/settings/fcb/{ => boards}/nrf52840dk_nrf52840.overlay (100%) rename tests/subsys/settings/fcb/{ => boards}/nrf52dk_nrf52832.overlay (100%) delete mode 100644 tests/subsys/settings/fcb/native_posix_64.overlay diff --git a/tests/subsys/settings/fcb/native_posix.overlay b/tests/subsys/settings/fcb/boards/native_sim.overlay similarity index 100% rename from tests/subsys/settings/fcb/native_posix.overlay rename to tests/subsys/settings/fcb/boards/native_sim.overlay diff --git a/tests/subsys/settings/fcb/boards/native_sim_64.overlay b/tests/subsys/settings/fcb/boards/native_sim_64.overlay new file mode 100644 index 00000000000..8dbed8eb97a --- /dev/null +++ b/tests/subsys/settings/fcb/boards/native_sim_64.overlay @@ -0,0 +1,7 @@ +/* + * Copyright (c) 2019 Jan Van Winkel + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include "native_sim.overlay" diff --git a/tests/subsys/settings/fcb/nrf52840dk_nrf52840.overlay b/tests/subsys/settings/fcb/boards/nrf52840dk_nrf52840.overlay similarity index 100% rename from tests/subsys/settings/fcb/nrf52840dk_nrf52840.overlay rename to tests/subsys/settings/fcb/boards/nrf52840dk_nrf52840.overlay diff --git a/tests/subsys/settings/fcb/nrf52dk_nrf52832.overlay b/tests/subsys/settings/fcb/boards/nrf52dk_nrf52832.overlay similarity index 100% rename from tests/subsys/settings/fcb/nrf52dk_nrf52832.overlay rename to tests/subsys/settings/fcb/boards/nrf52dk_nrf52832.overlay diff --git a/tests/subsys/settings/fcb/native_posix_64.overlay b/tests/subsys/settings/fcb/native_posix_64.overlay deleted file mode 100644 index f7f09615138..00000000000 --- a/tests/subsys/settings/fcb/native_posix_64.overlay +++ /dev/null @@ -1,22 +0,0 @@ -/* - * Copyright (c) 2019 Jan Van Winkel - * - * SPDX-License-Identifier: Apache-2.0 - */ - -/delete-node/ &storage_partition; -/delete-node/ &scratch_partition; - -&flash0 { - - partitions { - compatible = "fixed-partitions"; - #address-cells = <1>; - #size-cells = <1>; - - storage_partition: partition@70000 { - label = "storage"; - reg = <0x00070000 0x10000>; - }; - }; -}; diff --git a/tests/subsys/settings/fcb/testcase.yaml b/tests/subsys/settings/fcb/testcase.yaml index dd000db1c09..0382c74ff00 100644 --- a/tests/subsys/settings/fcb/testcase.yaml +++ b/tests/subsys/settings/fcb/testcase.yaml @@ -3,12 +3,12 @@ tests: platform_allow: - nrf52840dk_nrf52840 - nrf52dk_nrf52832 - - native_posix - - native_posix_64 + - native_sim + - native_sim_64 - mr_canhubk3 integration_platforms: - nrf52840dk_nrf52840 - - native_posix + - native_sim tags: - settings - fcb From f27760ab47a5e73928dbd26e0668a58905f77f37 Mon Sep 17 00:00:00 2001 From: Alberto Escolar Piedras Date: Mon, 20 Nov 2023 14:30:11 +0100 Subject: [PATCH 0080/3723] tests/subsys/settings/file: Switch to native_sim Switch from native_posix to native_sim as default test platform And switch overlays to native_sim. Signed-off-by: Alberto Escolar Piedras --- .../file/boards/native_posix_64.overlay | 21 ------------------- ...ative_posix.overlay => native_sim.overlay} | 0 .../file/boards/native_sim_64.overlay | 7 +++++++ tests/subsys/settings/file/testcase.yaml | 4 ++-- 4 files changed, 9 insertions(+), 23 deletions(-) delete mode 100644 tests/subsys/settings/file/boards/native_posix_64.overlay rename tests/subsys/settings/file/boards/{native_posix.overlay => native_sim.overlay} (100%) create mode 100644 tests/subsys/settings/file/boards/native_sim_64.overlay diff --git a/tests/subsys/settings/file/boards/native_posix_64.overlay b/tests/subsys/settings/file/boards/native_posix_64.overlay deleted file mode 100644 index 1c4d5371fc9..00000000000 --- a/tests/subsys/settings/file/boards/native_posix_64.overlay +++ /dev/null @@ -1,21 +0,0 @@ -/* - * Copyright (c) 2019 Nordic Semiconductor ASA - * - * SPDX-License-Identifier: Apache-2.0 - */ - -&flashcontroller0 { - reg = <0x00000000 DT_SIZE_K(4096)>; -}; - -&flash0 { - reg = <0x00000000 DT_SIZE_K(4096)>; - partitions { - compatible = "fixed-partitions"; - - settings_file_partition: partition@0 { - label = "settings_file_partition"; - reg = <0x00000000 0x00010000>; - }; - }; -}; diff --git a/tests/subsys/settings/file/boards/native_posix.overlay b/tests/subsys/settings/file/boards/native_sim.overlay similarity index 100% rename from tests/subsys/settings/file/boards/native_posix.overlay rename to tests/subsys/settings/file/boards/native_sim.overlay diff --git a/tests/subsys/settings/file/boards/native_sim_64.overlay b/tests/subsys/settings/file/boards/native_sim_64.overlay new file mode 100644 index 00000000000..55d159158f8 --- /dev/null +++ b/tests/subsys/settings/file/boards/native_sim_64.overlay @@ -0,0 +1,7 @@ +/* + * Copyright (c) 2019 Nordic Semiconductor ASA + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include "native_sim.overlay" diff --git a/tests/subsys/settings/file/testcase.yaml b/tests/subsys/settings/file/testcase.yaml index 68add10790b..9491f9b2046 100644 --- a/tests/subsys/settings/file/testcase.yaml +++ b/tests/subsys/settings/file/testcase.yaml @@ -5,8 +5,8 @@ tests: settings.file.raw: platform_allow: - nrf52840dk_nrf52840 - - native_posix - - native_posix_64 + - native_sim + - native_sim_64 - mr_canhubk3 tags: - settings From b7fa935a0d4d8695fe8b29852ed8611bd9c72039 Mon Sep 17 00:00:00 2001 From: Alberto Escolar Piedras Date: Mon, 20 Nov 2023 14:30:45 +0100 Subject: [PATCH 0081/3723] tests/subsys/settings/functional/*: Switch to native_sim Enable native_sim for these tests (platform_allow filter) Switch from native_posix to native_sim as default test platform And switch overlays from native_posix to native_sim Signed-off-by: Alberto Escolar Piedras --- .../settings/functional/fcb/testcase.yaml | 6 ++++- .../functional/file/native_posix_64.overlay | 22 ------------------- ...ative_posix.overlay => native_sim.overlay} | 0 .../functional/file/native_sim_64.overlay | 7 ++++++ .../settings/functional/file/testcase.yaml | 6 ++--- .../settings/functional/nvs/testcase.yaml | 4 ++++ 6 files changed, 19 insertions(+), 26 deletions(-) delete mode 100644 tests/subsys/settings/functional/file/native_posix_64.overlay rename tests/subsys/settings/functional/file/{native_posix.overlay => native_sim.overlay} (100%) create mode 100644 tests/subsys/settings/functional/file/native_sim_64.overlay diff --git a/tests/subsys/settings/functional/fcb/testcase.yaml b/tests/subsys/settings/functional/fcb/testcase.yaml index fb484e210b1..d9d63adc66c 100644 --- a/tests/subsys/settings/functional/fcb/testcase.yaml +++ b/tests/subsys/settings/functional/fcb/testcase.yaml @@ -5,6 +5,8 @@ tests: - nrf52dk_nrf52832 - native_posix - native_posix_64 + - native_sim + - native_sim_64 - mr_canhubk3 integration_platforms: - nrf52840dk_nrf52840 @@ -16,9 +18,11 @@ tests: platform_allow: - native_posix - native_posix_64 + - native_sim + - native_sim_64 - mr_canhubk3 integration_platforms: - - native_posix + - native_sim tags: - settings - fcb diff --git a/tests/subsys/settings/functional/file/native_posix_64.overlay b/tests/subsys/settings/functional/file/native_posix_64.overlay deleted file mode 100644 index 294dd4b1e62..00000000000 --- a/tests/subsys/settings/functional/file/native_posix_64.overlay +++ /dev/null @@ -1,22 +0,0 @@ -/* - * Copyright (c) 2019 Jan Van Winkel - * - * SPDX-License-Identifier: Apache-2.0 - */ - -/delete-node/ &storage_partition; -/delete-node/ &scratch_partition; - -&flash0 { - - partitions { - compatible = "fixed-partitions"; - #address-cells = <1>; - #size-cells = <1>; - - storage_partition: partition@70000 { - label = "storage"; - reg = <0x00070000 0x20000>; - }; - }; -}; diff --git a/tests/subsys/settings/functional/file/native_posix.overlay b/tests/subsys/settings/functional/file/native_sim.overlay similarity index 100% rename from tests/subsys/settings/functional/file/native_posix.overlay rename to tests/subsys/settings/functional/file/native_sim.overlay diff --git a/tests/subsys/settings/functional/file/native_sim_64.overlay b/tests/subsys/settings/functional/file/native_sim_64.overlay new file mode 100644 index 00000000000..8dbed8eb97a --- /dev/null +++ b/tests/subsys/settings/functional/file/native_sim_64.overlay @@ -0,0 +1,7 @@ +/* + * Copyright (c) 2019 Jan Van Winkel + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include "native_sim.overlay" diff --git a/tests/subsys/settings/functional/file/testcase.yaml b/tests/subsys/settings/functional/file/testcase.yaml index 7a28a2f41bc..6f876e93f3f 100644 --- a/tests/subsys/settings/functional/file/testcase.yaml +++ b/tests/subsys/settings/functional/file/testcase.yaml @@ -3,11 +3,11 @@ tests: platform_allow: - nrf52840dk_nrf52840 - nrf52dk_nrf52832 - - native_posix - - native_posix_64 + - native_sim + - native_sim_64 - mr_canhubk3 integration_platforms: - - native_posix + - native_sim tags: - settings - file diff --git a/tests/subsys/settings/functional/nvs/testcase.yaml b/tests/subsys/settings/functional/nvs/testcase.yaml index 6f2be71a86f..def7aa02a52 100644 --- a/tests/subsys/settings/functional/nvs/testcase.yaml +++ b/tests/subsys/settings/functional/nvs/testcase.yaml @@ -4,6 +4,8 @@ tests: - qemu_x86 - native_posix - native_posix_64 + - native_sim + - native_sim_64 tags: - settings - nvs @@ -12,6 +14,8 @@ tests: platform_allow: - native_posix - native_posix_64 + - native_sim + - native_sim_64 tags: - settings - nvs From 3d702e6ffa3aadfd5d16808fc78cda4d2e97beb7 Mon Sep 17 00:00:00 2001 From: Alberto Escolar Piedras Date: Mon, 20 Nov 2023 14:46:22 +0100 Subject: [PATCH 0082/3723] tests/subsys/dfu/*: Switch to native_sim Switch from native_posix to native_sim as default test platform And switch overlays to native_sim. Signed-off-by: Alberto Escolar Piedras --- tests/subsys/dfu/img_util/testcase.yaml | 21 +++++------ tests/subsys/dfu/mcuboot/testcase.yaml | 2 + .../dfu/mcuboot_multi/native_posix_64.overlay | 37 ------------------- ...ative_posix.overlay => native_sim.overlay} | 0 .../dfu/mcuboot_multi/native_sim_64.overlay | 7 ++++ tests/subsys/dfu/mcuboot_multi/testcase.yaml | 4 +- 6 files changed, 20 insertions(+), 51 deletions(-) delete mode 100644 tests/subsys/dfu/mcuboot_multi/native_posix_64.overlay rename tests/subsys/dfu/mcuboot_multi/{native_posix.overlay => native_sim.overlay} (100%) create mode 100644 tests/subsys/dfu/mcuboot_multi/native_sim_64.overlay diff --git a/tests/subsys/dfu/img_util/testcase.yaml b/tests/subsys/dfu/img_util/testcase.yaml index 89d44339572..e90fb0842b1 100644 --- a/tests/subsys/dfu/img_util/testcase.yaml +++ b/tests/subsys/dfu/img_util/testcase.yaml @@ -1,18 +1,15 @@ +common: + platform_allow: + - nrf52840dk_nrf52840 + - native_posix + - native_posix_64 + - native_sim + - native_sim_64 + integration_platforms: + - nrf52840dk_nrf52840 tests: dfu.image_util: - platform_allow: - - nrf52840dk_nrf52840 - - native_posix - - native_posix_64 tags: dfu_image_util - integration_platforms: - - nrf52840dk_nrf52840 dfu.image_util.progressive: extra_args: OVERLAY_CONFIG=progressively_overlay.conf - platform_allow: - - nrf52840dk_nrf52840 - - native_posix - - native_posix_64 tags: dfu_image_util - integration_platforms: - - nrf52840dk_nrf52840 diff --git a/tests/subsys/dfu/mcuboot/testcase.yaml b/tests/subsys/dfu/mcuboot/testcase.yaml index c05a05ae5df..6b630c71865 100644 --- a/tests/subsys/dfu/mcuboot/testcase.yaml +++ b/tests/subsys/dfu/mcuboot/testcase.yaml @@ -4,6 +4,8 @@ tests: - nrf52840dk_nrf52840 - native_posix - native_posix_64 + - native_sim + - native_sim_64 tags: dfu_mcuboot integration_platforms: - nrf52840dk_nrf52840 diff --git a/tests/subsys/dfu/mcuboot_multi/native_posix_64.overlay b/tests/subsys/dfu/mcuboot_multi/native_posix_64.overlay deleted file mode 100644 index 5166674f432..00000000000 --- a/tests/subsys/dfu/mcuboot_multi/native_posix_64.overlay +++ /dev/null @@ -1,37 +0,0 @@ -/* - * Copyright (c) 2020 Nordic Semiconductor ASA - * - * SPDX-License-Identifier: Apache-2.0 - */ - -/delete-node/ &scratch_partition; -/delete-node/ &storage_partition; - -&flash0 { - partitions { - compatible = "fixed-partitions"; - #address-cells = <1>; - #size-cells = <1>; - - boot_partition: partition@0 { - label = "mcuboot"; - reg = <0x00000000 0x0000C000>; - }; - slot0_partition: partition@c000 { - label = "image-0"; - reg = <0x0000C000 0x00069000>; - }; - slot1_partition: partition@75000 { - label = "image-1"; - reg = <0x00075000 0x00069000>; - }; - slot2_partition: partition@DE000 { - label = "image-2"; - reg = <0x000DE000 0x00069000>; - }; - slot3_partition: partition@146000 { - label = "image-3"; - reg = <0x00146000 0x00069000>; - }; - }; -}; diff --git a/tests/subsys/dfu/mcuboot_multi/native_posix.overlay b/tests/subsys/dfu/mcuboot_multi/native_sim.overlay similarity index 100% rename from tests/subsys/dfu/mcuboot_multi/native_posix.overlay rename to tests/subsys/dfu/mcuboot_multi/native_sim.overlay diff --git a/tests/subsys/dfu/mcuboot_multi/native_sim_64.overlay b/tests/subsys/dfu/mcuboot_multi/native_sim_64.overlay new file mode 100644 index 00000000000..3e51723713a --- /dev/null +++ b/tests/subsys/dfu/mcuboot_multi/native_sim_64.overlay @@ -0,0 +1,7 @@ +/* + * Copyright (c) 2020 Nordic Semiconductor ASA + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include "native_sim.overlay" diff --git a/tests/subsys/dfu/mcuboot_multi/testcase.yaml b/tests/subsys/dfu/mcuboot_multi/testcase.yaml index dbebd3fddbd..742bbe38ce6 100644 --- a/tests/subsys/dfu/mcuboot_multi/testcase.yaml +++ b/tests/subsys/dfu/mcuboot_multi/testcase.yaml @@ -2,8 +2,8 @@ tests: dfu.mcuboot.multiimage: platform_allow: - nrf52840dk_nrf52840 - - native_posix - - native_posix_64 + - native_sim + - native_sim_64 tags: dfu_mcuboot integration_platforms: - nrf52840dk_nrf52840 From ec7ed0ea7d95bac152d30d4870f39de2da16d3fa Mon Sep 17 00:00:00 2001 From: Alberto Escolar Piedras Date: Mon, 20 Nov 2023 14:52:18 +0100 Subject: [PATCH 0083/3723] tests/drivers smbus_emul: Switch to native_sim Switch from native_posix to native_sim as default test platform Signed-off-by: Alberto Escolar Piedras --- tests/drivers/smbus/smbus_emul/testcase.yaml | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/tests/drivers/smbus/smbus_emul/testcase.yaml b/tests/drivers/smbus/smbus_emul/testcase.yaml index 26fc9254c55..8eef32526bb 100644 --- a/tests/drivers/smbus/smbus_emul/testcase.yaml +++ b/tests/drivers/smbus/smbus_emul/testcase.yaml @@ -1,5 +1,9 @@ common: - platform_allow: native_posix + platform_allow: + - native_posix + - native_sim + integration_platforms: + - native_sim tests: drivers.smbus.emul: tags: smbus From 81179bcd637265d99fb24d396d66ebbe26d581a6 Mon Sep 17 00:00:00 2001 From: Alberto Escolar Piedras Date: Mon, 20 Nov 2023 14:52:44 +0100 Subject: [PATCH 0084/3723] tests/subsys/mem_mgmt/mem_attr: Switch to native_sim Enable native_sim for this test. Switch from native_posix to native_sim as default test platform Signed-off-by: Alberto Escolar Piedras --- tests/subsys/mem_mgmt/mem_attr/testcase.yaml | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/tests/subsys/mem_mgmt/mem_attr/testcase.yaml b/tests/subsys/mem_mgmt/mem_attr/testcase.yaml index ecb445a077e..63e5c1668d6 100644 --- a/tests/subsys/mem_mgmt/mem_attr/testcase.yaml +++ b/tests/subsys/mem_mgmt/mem_attr/testcase.yaml @@ -2,7 +2,9 @@ common: platform_allow: - native_posix - native_posix_64 + - native_sim + - native_sim_64 integration_platforms: - - native_posix + - native_sim tests: mem_mgmt.mem_attr.default: {} From 6caf76346ac380ad7173c8eefb387b17a012f0cf Mon Sep 17 00:00:00 2001 From: Alexander Vasiliev Date: Thu, 2 Nov 2023 16:30:55 +0000 Subject: [PATCH 0085/3723] net: mqtt-sn: Add a function to get topic name by topic ID Add a function to MQTT-SN library API to get topic name by ID from the internal topics list. Signed-off-by: Alexander Vasiliev --- include/zephyr/net/mqtt_sn.h | 13 +++++++++++++ subsys/net/lib/mqtt_sn/mqtt_sn.c | 19 +++++++++++++++++++ 2 files changed, 32 insertions(+) diff --git a/include/zephyr/net/mqtt_sn.h b/include/zephyr/net/mqtt_sn.h index 7700558f1fe..cb1a6d33731 100644 --- a/include/zephyr/net/mqtt_sn.h +++ b/include/zephyr/net/mqtt_sn.h @@ -397,6 +397,19 @@ int mqtt_sn_publish(struct mqtt_sn_client *client, enum mqtt_sn_qos qos, */ int mqtt_sn_input(struct mqtt_sn_client *client); +/** + * @brief Get topic name by topic ID. + * + * @param[in] client The MQTT-SN client that uses this topic. + * @param[in] id Topic identifier. + * @param[out] topic_name Will be assigned to topic name. + * + * @return 0 on success, -ENOENT if topic ID doesn't exist, + * or -EINVAL on invalid arguments. + */ +int mqtt_sn_get_topic_name(struct mqtt_sn_client *client, uint16_t id, + struct mqtt_sn_data *topic_name); + #ifdef __cplusplus } #endif diff --git a/subsys/net/lib/mqtt_sn/mqtt_sn.c b/subsys/net/lib/mqtt_sn/mqtt_sn.c index 213ca55753f..4c0be807c21 100644 --- a/subsys/net/lib/mqtt_sn/mqtt_sn.c +++ b/subsys/net/lib/mqtt_sn/mqtt_sn.c @@ -1224,3 +1224,22 @@ int mqtt_sn_input(struct mqtt_sn_client *client) /* Should be zero */ return -client->rx.len; } + +int mqtt_sn_get_topic_name(struct mqtt_sn_client *client, uint16_t id, + struct mqtt_sn_data *topic_name) +{ + struct mqtt_sn_topic *topic; + + if (!client || !topic_name) { + return -EINVAL; + } + + SYS_SLIST_FOR_EACH_CONTAINER(&client->topic, topic, next) { + if (topic->topic_id == id) { + topic_name->data = (const uint8_t *)topic->name; + topic_name->size = topic->namelen; + return 0; + } + } + return -ENOENT; +} From 76276e2bd3ddb698a081ecfec79fc2c36b9450b4 Mon Sep 17 00:00:00 2001 From: Alexander Vasiliev Date: Thu, 2 Nov 2023 16:38:12 +0000 Subject: [PATCH 0086/3723] net: mqtt-sn: Remember incoming registered topic name When a client uses wildcard subscription and a new message is published to the matching topic for the first time, the gateway sends REGISTER message to the client, containing the exact topic name and a new topic ID. This change fixes adding these topic ID and name to the internal topics list. Signed-off-by: Alexander Vasiliev --- subsys/net/lib/mqtt_sn/mqtt_sn.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/subsys/net/lib/mqtt_sn/mqtt_sn.c b/subsys/net/lib/mqtt_sn/mqtt_sn.c index 4c0be807c21..2a7b71ae055 100644 --- a/subsys/net/lib/mqtt_sn/mqtt_sn.c +++ b/subsys/net/lib/mqtt_sn/mqtt_sn.c @@ -949,6 +949,8 @@ static void handle_register(struct mqtt_sn_client *client, struct mqtt_sn_param_ topic->topic_id = p->topic_id; topic->type = MQTT_SN_TOPIC_TYPE_NORMAL; + sys_slist_append(&client->topic, &topic->next); + response.params.regack.ret_code = MQTT_SN_CODE_ACCEPTED; response.params.regack.topic_id = p->topic_id; response.params.regack.msg_id = p->msg_id; From bc8313e26e342684b52c6d694e13ee5ebc294715 Mon Sep 17 00:00:00 2001 From: Alberto Escolar Piedras Date: Mon, 20 Nov 2023 17:01:12 +0100 Subject: [PATCH 0087/3723] pm: Fix definition of pm device slot This pointers need to be writable by the power management code, but were declared as const, resulting in a fault for platforms which prevent writing to RAM containing const values. Signed-off-by: Alberto Escolar Piedras --- include/zephyr/pm/device.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/include/zephyr/pm/device.h b/include/zephyr/pm/device.h index cbfbf6f5f46..ab54fd677fe 100644 --- a/include/zephyr/pm/device.h +++ b/include/zephyr/pm/device.h @@ -220,7 +220,7 @@ struct pm_device { * @param dev_id Device id. */ #define Z_PM_DEVICE_DEFINE_SLOT(dev_id) \ - static const STRUCT_SECTION_ITERABLE_ALTERNATE(pm_device_slots, device, \ + static STRUCT_SECTION_ITERABLE_ALTERNATE(pm_device_slots, device, \ _CONCAT(__pm_slot_, dev_id)) #ifdef CONFIG_PM_DEVICE From b39d7c2c3d9d31afa1fdbf5bddac347387609320 Mon Sep 17 00:00:00 2001 From: Alberto Escolar Piedras Date: Mon, 20 Nov 2023 16:44:25 +0100 Subject: [PATCH 0088/3723] tests/subsys/pm/*: Switch to native_sim Enable all these tests which run in native_posix in native_sim, Switch from native_posix to native_sim as default test platform And switch native_posix overlays to native_sim. Signed-off-by: Alberto Escolar Piedras --- tests/subsys/pm/device_driver_init/testcase.yaml | 3 +++ tests/subsys/pm/device_power_domains/testcase.yaml | 3 +++ tests/subsys/pm/device_runtime_api/testcase.yaml | 2 +- .../boards/{native_posix.overlay => native_sim.overlay} | 0 tests/subsys/pm/device_wakeup_api/testcase.yaml | 3 ++- tests/subsys/pm/policy_api/testcase.yaml | 4 +++- tests/subsys/pm/power_domain/testcase.yaml | 6 +++++- .../boards/{native_posix.overlay => native_sim.overlay} | 0 tests/subsys/pm/power_mgmt/testcase.yaml | 2 +- .../boards/{native_posix.overlay => native_sim.overlay} | 0 tests/subsys/pm/power_states_api/testcase.yaml | 3 ++- 11 files changed, 20 insertions(+), 6 deletions(-) rename tests/subsys/pm/device_wakeup_api/boards/{native_posix.overlay => native_sim.overlay} (100%) rename tests/subsys/pm/power_mgmt/boards/{native_posix.overlay => native_sim.overlay} (100%) rename tests/subsys/pm/power_states_api/boards/{native_posix.overlay => native_sim.overlay} (100%) diff --git a/tests/subsys/pm/device_driver_init/testcase.yaml b/tests/subsys/pm/device_driver_init/testcase.yaml index 8920e38741b..cf8e338e5c5 100644 --- a/tests/subsys/pm/device_driver_init/testcase.yaml +++ b/tests/subsys/pm/device_driver_init/testcase.yaml @@ -1,6 +1,9 @@ common: platform_allow: - native_posix + - native_sim + integration_platforms: + - native_sim tags: - pm tests: diff --git a/tests/subsys/pm/device_power_domains/testcase.yaml b/tests/subsys/pm/device_power_domains/testcase.yaml index 11b00299f5c..4d2037dff76 100644 --- a/tests/subsys/pm/device_power_domains/testcase.yaml +++ b/tests/subsys/pm/device_power_domains/testcase.yaml @@ -4,3 +4,6 @@ tests: - pm platform_allow: - native_posix + - native_sim + integration_platforms: + - native_sim diff --git a/tests/subsys/pm/device_runtime_api/testcase.yaml b/tests/subsys/pm/device_runtime_api/testcase.yaml index 4b9f38fd8bb..72c9c512942 100644 --- a/tests/subsys/pm/device_runtime_api/testcase.yaml +++ b/tests/subsys/pm/device_runtime_api/testcase.yaml @@ -2,4 +2,4 @@ tests: pm.device_runtime.api: tags: pm integration_platforms: - - native_posix + - native_sim diff --git a/tests/subsys/pm/device_wakeup_api/boards/native_posix.overlay b/tests/subsys/pm/device_wakeup_api/boards/native_sim.overlay similarity index 100% rename from tests/subsys/pm/device_wakeup_api/boards/native_posix.overlay rename to tests/subsys/pm/device_wakeup_api/boards/native_sim.overlay diff --git a/tests/subsys/pm/device_wakeup_api/testcase.yaml b/tests/subsys/pm/device_wakeup_api/testcase.yaml index 790173546f9..4106eb8aac1 100644 --- a/tests/subsys/pm/device_wakeup_api/testcase.yaml +++ b/tests/subsys/pm/device_wakeup_api/testcase.yaml @@ -1,4 +1,5 @@ tests: pm.device-wakeup-api.dts: tags: pm - platform_allow: native_posix + platform_allow: + - native_sim diff --git a/tests/subsys/pm/policy_api/testcase.yaml b/tests/subsys/pm/policy_api/testcase.yaml index 1e770694f33..5df6032ab1d 100644 --- a/tests/subsys/pm/policy_api/testcase.yaml +++ b/tests/subsys/pm/policy_api/testcase.yaml @@ -6,8 +6,10 @@ common: platform_allow: - native_posix - native_posix_64 + - native_sim + - native_sim_64 integration_platforms: - - native_posix + - native_sim tests: pm.policy.api.default: {} pm.policy.api.app: diff --git a/tests/subsys/pm/power_domain/testcase.yaml b/tests/subsys/pm/power_domain/testcase.yaml index e2f81406806..287267ba0f8 100644 --- a/tests/subsys/pm/power_domain/testcase.yaml +++ b/tests/subsys/pm/power_domain/testcase.yaml @@ -1,4 +1,8 @@ tests: pm.power_domain: - platform_allow: native_posix + platform_allow: + - native_posix + - native_sim + integration_platforms: + - native_sim tags: pm diff --git a/tests/subsys/pm/power_mgmt/boards/native_posix.overlay b/tests/subsys/pm/power_mgmt/boards/native_sim.overlay similarity index 100% rename from tests/subsys/pm/power_mgmt/boards/native_posix.overlay rename to tests/subsys/pm/power_mgmt/boards/native_sim.overlay diff --git a/tests/subsys/pm/power_mgmt/testcase.yaml b/tests/subsys/pm/power_mgmt/testcase.yaml index d08f0386aa2..b51b282ea55 100644 --- a/tests/subsys/pm/power_mgmt/testcase.yaml +++ b/tests/subsys/pm/power_mgmt/testcase.yaml @@ -1,4 +1,4 @@ tests: pm.system: - platform_allow: native_posix + platform_allow: native_sim tags: pm diff --git a/tests/subsys/pm/power_states_api/boards/native_posix.overlay b/tests/subsys/pm/power_states_api/boards/native_sim.overlay similarity index 100% rename from tests/subsys/pm/power_states_api/boards/native_posix.overlay rename to tests/subsys/pm/power_states_api/boards/native_sim.overlay diff --git a/tests/subsys/pm/power_states_api/testcase.yaml b/tests/subsys/pm/power_states_api/testcase.yaml index 507e8f3e22f..7ad42f20681 100644 --- a/tests/subsys/pm/power_states_api/testcase.yaml +++ b/tests/subsys/pm/power_states_api/testcase.yaml @@ -1,4 +1,5 @@ tests: pm.states.api.dts: tags: pm - platform_allow: native_posix + platform_allow: + - native_sim From 1a2fc865d2bd5fef788022b509e8c131e13a9384 Mon Sep 17 00:00:00 2001 From: Alberto Escolar Piedras Date: Mon, 20 Nov 2023 15:50:46 +0100 Subject: [PATCH 0089/3723] tests/subsys/fs/*: Switch to native_sim Enable all these tests which run in native_posix in native_sim, Switch from native_posix to native_sim as default test platform And switch native_posix overlays to native_sim. Signed-off-by: Alberto Escolar Piedras --- .../fs/ext2/boards/native_posix_64.overlay | 31 ------------------- ...ative_posix.overlay => native_sim.overlay} | 0 .../fs/ext2/boards/native_sim_64.overlay | 7 +++++ tests/subsys/fs/ext2/testcase.yaml | 18 ++++++++--- tests/subsys/fs/fat_fs_api/README.txt | 4 +-- ...ative_posix.overlay => native_sim.overlay} | 0 ...ive_posix_ram.conf => prj_native_ram.conf} | 0 tests/subsys/fs/fat_fs_api/testcase.yaml | 14 ++++++--- .../subsys/fs/fat_fs_dual_drive/testcase.yaml | 3 +- ...x00.overlay => native_sim_ev_0x00.overlay} | 0 tests/subsys/fs/fcb/testcase.yaml | 8 +++-- tests/subsys/fs/fs_api/testcase.yaml | 2 +- .../littlefs/boards/native_posix_64.overlay | 31 ------------------- ...ative_posix.overlay => native_sim.overlay} | 0 .../fs/littlefs/boards/native_sim_64.overlay | 7 +++++ tests/subsys/fs/littlefs/testcase.yaml | 4 +-- tests/subsys/fs/multi-fs/testcase.yaml | 6 ++-- ...ative_posix.overlay => native_sim.overlay} | 0 tests/subsys/fs/nvs/src/main.c | 6 ++-- tests/subsys/fs/nvs/testcase.yaml | 2 +- 20 files changed, 57 insertions(+), 86 deletions(-) delete mode 100644 tests/subsys/fs/ext2/boards/native_posix_64.overlay rename tests/subsys/fs/ext2/boards/{native_posix.overlay => native_sim.overlay} (100%) create mode 100644 tests/subsys/fs/ext2/boards/native_sim_64.overlay rename tests/subsys/fs/fat_fs_api/boards/{native_posix.overlay => native_sim.overlay} (100%) rename tests/subsys/fs/fat_fs_api/{prj_native_posix_ram.conf => prj_native_ram.conf} (100%) rename tests/subsys/fs/fcb/boards/{native_posix_ev_0x00.overlay => native_sim_ev_0x00.overlay} (100%) delete mode 100644 tests/subsys/fs/littlefs/boards/native_posix_64.overlay rename tests/subsys/fs/littlefs/boards/{native_posix.overlay => native_sim.overlay} (100%) create mode 100644 tests/subsys/fs/littlefs/boards/native_sim_64.overlay rename tests/subsys/fs/nvs/boards/{native_posix.overlay => native_sim.overlay} (100%) diff --git a/tests/subsys/fs/ext2/boards/native_posix_64.overlay b/tests/subsys/fs/ext2/boards/native_posix_64.overlay deleted file mode 100644 index 5b403948590..00000000000 --- a/tests/subsys/fs/ext2/boards/native_posix_64.overlay +++ /dev/null @@ -1,31 +0,0 @@ -/* - * Copyright (c) 2023 Antmicro - * - * SPDX-License-Identifier: Apache-2.0 - */ - -&flashcontroller0 { - reg = <0x00000000 DT_SIZE_M(128)>; -}; - -&flash0 { - reg = <0x00000000 DT_SIZE_M(128)>; - partitions { - compatible = "fixed-partitions"; - #address-cells = <1>; - #size-cells = <1>; - - storage: partition@0 { - reg = <0x00000000 0x08000000>; - }; - }; -}; - -/ { - storage_disk { - compatible = "zephyr,flash-disk"; - partition = <&storage>; - disk-name = "NAND"; - cache-size = <4096>; - }; -}; diff --git a/tests/subsys/fs/ext2/boards/native_posix.overlay b/tests/subsys/fs/ext2/boards/native_sim.overlay similarity index 100% rename from tests/subsys/fs/ext2/boards/native_posix.overlay rename to tests/subsys/fs/ext2/boards/native_sim.overlay diff --git a/tests/subsys/fs/ext2/boards/native_sim_64.overlay b/tests/subsys/fs/ext2/boards/native_sim_64.overlay new file mode 100644 index 00000000000..f3f8b087d9b --- /dev/null +++ b/tests/subsys/fs/ext2/boards/native_sim_64.overlay @@ -0,0 +1,7 @@ +/* + * Copyright (c) 2023 Antmicro + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include "native_sim.overlay" diff --git a/tests/subsys/fs/ext2/testcase.yaml b/tests/subsys/fs/ext2/testcase.yaml index 21615994ba6..7466e0984b9 100644 --- a/tests/subsys/fs/ext2/testcase.yaml +++ b/tests/subsys/fs/ext2/testcase.yaml @@ -2,20 +2,30 @@ common: tags: filesystem tests: filesystem.ext2.default: - platform_allow: native_posix native_posix_64 hifive_unmatched bl5340_dvk_cpuapp + platform_allow: + - native_sim + - native_sim_64 + - hifive_unmatched + - bl5340_dvk_cpuapp extra_args: - EXTRA_DTC_OVERLAY_FILE="ramdisk_small.overlay" filesystem.ext2.big: - platform_allow: native_posix native_posix_64 + platform_allow: + - native_sim + - native_sim_64 extra_args: - CONF_FILE=prj_big.conf - EXTRA_DTC_OVERLAY_FILE="ramdisk_big.overlay" filesystem.ext2.sdcard: - platform_allow: hifive_unmatched bl5340_dvk_cpuapp + platform_allow: + - hifive_unmatched + - bl5340_dvk_cpuapp extra_args: CONF_FILE=prj_sdcard.conf filesystem.ext2.flash: - platform_allow: native_posix native_posix_64 + platform_allow: + - native_sim + - native_sim_64 extra_args: CONF_FILE=prj_flash.conf diff --git a/tests/subsys/fs/fat_fs_api/README.txt b/tests/subsys/fs/fat_fs_api/README.txt index 10fbfb73118..58ddbb3c6cd 100644 --- a/tests/subsys/fs/fat_fs_api/README.txt +++ b/tests/subsys/fs/fat_fs_api/README.txt @@ -7,10 +7,10 @@ Demonstrates basic file and dir operations using the Zephyr file system. Building and Running Project: -The demo will run on native_posix and will use the on-board SPI flash. +The demo will run on native_sim using the flash simulator. mkdir build; cd build - cmake -DBOARD=native_posix .. + cmake -DBOARD=native_sim .. make run To test fatfs on MMC, add this cmake option to your build command: diff --git a/tests/subsys/fs/fat_fs_api/boards/native_posix.overlay b/tests/subsys/fs/fat_fs_api/boards/native_sim.overlay similarity index 100% rename from tests/subsys/fs/fat_fs_api/boards/native_posix.overlay rename to tests/subsys/fs/fat_fs_api/boards/native_sim.overlay diff --git a/tests/subsys/fs/fat_fs_api/prj_native_posix_ram.conf b/tests/subsys/fs/fat_fs_api/prj_native_ram.conf similarity index 100% rename from tests/subsys/fs/fat_fs_api/prj_native_posix_ram.conf rename to tests/subsys/fs/fat_fs_api/prj_native_ram.conf diff --git a/tests/subsys/fs/fat_fs_api/testcase.yaml b/tests/subsys/fs/fat_fs_api/testcase.yaml index bc3927def92..59cd6035ddd 100644 --- a/tests/subsys/fs/fat_fs_api/testcase.yaml +++ b/tests/subsys/fs/fat_fs_api/testcase.yaml @@ -6,20 +6,24 @@ common: - fatfs tests: filesystem.fat.api: - platform_allow: native_posix + platform_allow: + - native_sim filesystem.fat.api.lfn: extra_args: CONF_FILE="prj_lfn.conf" - platform_allow: native_posix + platform_allow: + - native_sim filesystem.fat.api.mmc: extra_args: CONF_FILE="prj_mmc.conf" filter: dt_compat_enabled("zephyr,mmc-disk") filesystem.fat.ram.api: - platform_allow: native_posix + platform_allow: + - native_sim extra_args: - - CONF_FILE="prj_native_posix_ram.conf" + - CONF_FILE="prj_native_ram.conf" - EXTRA_DTC_OVERLAY_FILE="ramdisk.overlay" filesystem.fat.api.reentrant: - platform_allow: native_posix + platform_allow: + - native_sim extra_configs: - CONFIG_FS_FATFS_REENTRANT=y - CONFIG_MULTITHREADING=y diff --git a/tests/subsys/fs/fat_fs_dual_drive/testcase.yaml b/tests/subsys/fs/fat_fs_dual_drive/testcase.yaml index a4db89c676c..ab8264579ad 100644 --- a/tests/subsys/fs/fat_fs_dual_drive/testcase.yaml +++ b/tests/subsys/fs/fat_fs_dual_drive/testcase.yaml @@ -3,9 +3,10 @@ tests: platform_allow: - qemu_x86 - native_posix + - native_sim - qemu_leon3 - qemu_riscv32 - qemu_riscv64 tags: filesystem integration_platforms: - - native_posix + - native_sim diff --git a/tests/subsys/fs/fcb/boards/native_posix_ev_0x00.overlay b/tests/subsys/fs/fcb/boards/native_sim_ev_0x00.overlay similarity index 100% rename from tests/subsys/fs/fcb/boards/native_posix_ev_0x00.overlay rename to tests/subsys/fs/fcb/boards/native_sim_ev_0x00.overlay diff --git a/tests/subsys/fs/fcb/testcase.yaml b/tests/subsys/fs/fcb/testcase.yaml index 0d5d1938b25..3945049a534 100644 --- a/tests/subsys/fs/fcb/testcase.yaml +++ b/tests/subsys/fs/fcb/testcase.yaml @@ -6,13 +6,15 @@ tests: - nrf51dk_nrf51422 - native_posix - native_posix_64 + - native_sim + - native_sim_64 - mr_canhubk3 tags: flash_circural_buffer integration_platforms: - nrf52840dk_nrf52840 - filesystem.fcb.native_posix.fcb_0x00: - extra_args: DTC_OVERLAY_FILE=boards/native_posix_ev_0x00.overlay - platform_allow: native_posix + filesystem.fcb.native_sim.fcb_0x00: + extra_args: DTC_OVERLAY_FILE=boards/native_sim_ev_0x00.overlay + platform_allow: native_sim filesystem.fcb.qemu_x86.fcb_0x00: extra_args: DTC_OVERLAY_FILE=boards/qemu_x86_ev_0x00.overlay platform_allow: qemu_x86 diff --git a/tests/subsys/fs/fs_api/testcase.yaml b/tests/subsys/fs/fs_api/testcase.yaml index 7f8e1a03b27..635598cc856 100644 --- a/tests/subsys/fs/fs_api/testcase.yaml +++ b/tests/subsys/fs/fs_api/testcase.yaml @@ -2,4 +2,4 @@ tests: filesystem.api: tags: filesystem integration_platforms: - - native_posix + - native_sim diff --git a/tests/subsys/fs/littlefs/boards/native_posix_64.overlay b/tests/subsys/fs/littlefs/boards/native_posix_64.overlay deleted file mode 100644 index f44d78c8a11..00000000000 --- a/tests/subsys/fs/littlefs/boards/native_posix_64.overlay +++ /dev/null @@ -1,31 +0,0 @@ -/* - * Copyright (c) 2019 Jan Van Winkel - * - * SPDX-License-Identifier: Apache-2.0 - */ - -&flashcontroller0 { - reg = <0x00000000 DT_SIZE_K(4096)>; -}; - -&flash0 { - reg = <0x00000000 DT_SIZE_K(4096)>; - partitions { - compatible = "fixed-partitions"; - #address-cells = <1>; - #size-cells = <1>; - - small_partition: partition@0 { - label = "small"; - reg = <0x00000000 0x00010000>; - }; - medium_partition: partition@10000 { - label = "medium"; - reg = <0x00010000 0x000F0000>; - }; - large_partition: partition@100000 { - label = "large"; - reg = <0x00100000 0x00300000>; - }; - }; -}; diff --git a/tests/subsys/fs/littlefs/boards/native_posix.overlay b/tests/subsys/fs/littlefs/boards/native_sim.overlay similarity index 100% rename from tests/subsys/fs/littlefs/boards/native_posix.overlay rename to tests/subsys/fs/littlefs/boards/native_sim.overlay diff --git a/tests/subsys/fs/littlefs/boards/native_sim_64.overlay b/tests/subsys/fs/littlefs/boards/native_sim_64.overlay new file mode 100644 index 00000000000..8dbed8eb97a --- /dev/null +++ b/tests/subsys/fs/littlefs/boards/native_sim_64.overlay @@ -0,0 +1,7 @@ +/* + * Copyright (c) 2019 Jan Van Winkel + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include "native_sim.overlay" diff --git a/tests/subsys/fs/littlefs/testcase.yaml b/tests/subsys/fs/littlefs/testcase.yaml index 4fa20c791a9..211137180f8 100644 --- a/tests/subsys/fs/littlefs/testcase.yaml +++ b/tests/subsys/fs/littlefs/testcase.yaml @@ -4,8 +4,8 @@ common: - littlefs platform_allow: - nrf52840dk_nrf52840 - - native_posix - - native_posix_64 + - native_sim + - native_sim_64 - mimxrt1060_evk - mr_canhubk3 integration_platforms: diff --git a/tests/subsys/fs/multi-fs/testcase.yaml b/tests/subsys/fs/multi-fs/testcase.yaml index b4c1e49d195..35d4c562607 100644 --- a/tests/subsys/fs/multi-fs/testcase.yaml +++ b/tests/subsys/fs/multi-fs/testcase.yaml @@ -12,15 +12,17 @@ tests: - EXTRA_DTC_OVERLAY_FILE="ramdisk.overlay" platform_allow: - native_posix + - native_sim - qemu_x86 integration_platforms: - - native_posix + - native_sim filesystem.fs_shell: extra_args: - CONF_FILE="prj_fs_shell.conf" - EXTRA_DTC_OVERLAY_FILE="ramdisk.overlay" platform_allow: - native_posix + - native_sim - qemu_x86 integration_platforms: - - native_posix + - native_sim diff --git a/tests/subsys/fs/nvs/boards/native_posix.overlay b/tests/subsys/fs/nvs/boards/native_sim.overlay similarity index 100% rename from tests/subsys/fs/nvs/boards/native_posix.overlay rename to tests/subsys/fs/nvs/boards/native_sim.overlay diff --git a/tests/subsys/fs/nvs/src/main.c b/tests/subsys/fs/nvs/src/main.c index 34899277f55..d8cedee63a1 100644 --- a/tests/subsys/fs/nvs/src/main.c +++ b/tests/subsys/fs/nvs/src/main.c @@ -8,11 +8,11 @@ * This test is designed to be run using flash-simulator which provide * functionality for flash property customization and emulating errors in * flash operation in parallel to regular flash API. - * Test should be run on qemu_x86 or native_posix target. + * Test should be run on qemu_x86 or native_sim target. */ -#if !defined(CONFIG_BOARD_QEMU_X86) && !defined(CONFIG_BOARD_NATIVE_POSIX) -#error "Run on qemu_x86 or native_posix only" +#if !defined(CONFIG_BOARD_QEMU_X86) && !defined(CONFIG_ARCH_POSIX) +#error "Run only on qemu_x86 or a posix architecture based target (for ex. native_sim)" #endif #include diff --git a/tests/subsys/fs/nvs/testcase.yaml b/tests/subsys/fs/nvs/testcase.yaml index fd8386ffbd7..f462a33ff0e 100644 --- a/tests/subsys/fs/nvs/testcase.yaml +++ b/tests/subsys/fs/nvs/testcase.yaml @@ -10,4 +10,4 @@ tests: extra_args: - CONFIG_NVS_LOOKUP_CACHE=y - CONFIG_NVS_LOOKUP_CACHE_SIZE=64 - platform_allow: native_posix + platform_allow: native_sim From 13b7557fe10b037ced8aa5cdac2d064bb1c45ca5 Mon Sep 17 00:00:00 2001 From: Alberto Escolar Piedras Date: Mon, 20 Nov 2023 15:54:07 +0100 Subject: [PATCH 0090/3723] tests/subsys/modem/*: Switch to native_sim Enable all these tests which run in native_posix in native_sim And add native_sim as default test platform Signed-off-by: Alberto Escolar Piedras --- tests/subsys/modem/backends/tty/testcase.yaml | 6 +++++- tests/subsys/modem/modem_chat/testcase.yaml | 6 +++++- tests/subsys/modem/modem_cmux/testcase.yaml | 6 +++++- tests/subsys/modem/modem_ppp/testcase.yaml | 6 +++++- 4 files changed, 20 insertions(+), 4 deletions(-) diff --git a/tests/subsys/modem/backends/tty/testcase.yaml b/tests/subsys/modem/backends/tty/testcase.yaml index 11f78b1d641..28d3c3d4aa2 100644 --- a/tests/subsys/modem/backends/tty/testcase.yaml +++ b/tests/subsys/modem/backends/tty/testcase.yaml @@ -5,4 +5,8 @@ tests: modem.backends.tty: tags: modem_backend_tty harness: ztest - platform_allow: native_posix + platform_allow: + - native_posix + - native_sim + integration_platforms: + - native_sim diff --git a/tests/subsys/modem/modem_chat/testcase.yaml b/tests/subsys/modem/modem_chat/testcase.yaml index 8716d7f0d17..2b8723428ea 100644 --- a/tests/subsys/modem/modem_chat/testcase.yaml +++ b/tests/subsys/modem/modem_chat/testcase.yaml @@ -5,4 +5,8 @@ tests: modem.modem_chat: tags: modem_chat harness: ztest - platform_allow: native_posix + platform_allow: + - native_posix + - native_sim + integration_platforms: + - native_sim diff --git a/tests/subsys/modem/modem_cmux/testcase.yaml b/tests/subsys/modem/modem_cmux/testcase.yaml index c7d1f53a085..fd89a3f5656 100644 --- a/tests/subsys/modem/modem_cmux/testcase.yaml +++ b/tests/subsys/modem/modem_cmux/testcase.yaml @@ -5,4 +5,8 @@ tests: modem.modem_cmux: tags: modem_cmux harness: ztest - platform_allow: native_posix + platform_allow: + - native_posix + - native_sim + integration_platforms: + - native_sim diff --git a/tests/subsys/modem/modem_ppp/testcase.yaml b/tests/subsys/modem/modem_ppp/testcase.yaml index 0b3fef701f3..7e0937ea144 100644 --- a/tests/subsys/modem/modem_ppp/testcase.yaml +++ b/tests/subsys/modem/modem_ppp/testcase.yaml @@ -5,4 +5,8 @@ tests: modem.modem_ppp: tags: modem_ppp harness: ztest - platform_allow: native_posix + platform_allow: + - native_posix + - native_sim + integration_platforms: + - native_sim From f59c9c0ddea97c668320a10547c1f75c8c8d13d2 Mon Sep 17 00:00:00 2001 From: Alberto Escolar Piedras Date: Mon, 20 Nov 2023 16:16:03 +0100 Subject: [PATCH 0091/3723] tests/subsys/input/*: Switch to native_sim Switch from native_posix to native_sim as default test platform And switch overlays to native_sim. Signed-off-by: Alberto Escolar Piedras --- .../boards/{native_posix.overlay => native_sim.overlay} | 0 .../{native_posix_64.overlay => native_sim_64.overlay} | 2 +- tests/subsys/input/input_longpress/testcase.yaml | 6 +++--- tests/subsys/input/input_shell/testcase.yaml | 4 ++++ 4 files changed, 8 insertions(+), 4 deletions(-) rename tests/subsys/input/input_longpress/boards/{native_posix.overlay => native_sim.overlay} (100%) rename tests/subsys/input/input_longpress/boards/{native_posix_64.overlay => native_sim_64.overlay} (70%) diff --git a/tests/subsys/input/input_longpress/boards/native_posix.overlay b/tests/subsys/input/input_longpress/boards/native_sim.overlay similarity index 100% rename from tests/subsys/input/input_longpress/boards/native_posix.overlay rename to tests/subsys/input/input_longpress/boards/native_sim.overlay diff --git a/tests/subsys/input/input_longpress/boards/native_posix_64.overlay b/tests/subsys/input/input_longpress/boards/native_sim_64.overlay similarity index 70% rename from tests/subsys/input/input_longpress/boards/native_posix_64.overlay rename to tests/subsys/input/input_longpress/boards/native_sim_64.overlay index 166e6f02e82..a906fce7488 100644 --- a/tests/subsys/input/input_longpress/boards/native_posix_64.overlay +++ b/tests/subsys/input/input_longpress/boards/native_sim_64.overlay @@ -3,4 +3,4 @@ * * SPDX-License-Identifier: Apache-2.0 */ -#include "native_posix.overlay" +#include "native_sim.overlay" diff --git a/tests/subsys/input/input_longpress/testcase.yaml b/tests/subsys/input/input_longpress/testcase.yaml index 10ca378dd60..8ad1d41a31a 100644 --- a/tests/subsys/input/input_longpress/testcase.yaml +++ b/tests/subsys/input/input_longpress/testcase.yaml @@ -3,10 +3,10 @@ tests: input.input_longpress: platform_allow: - - native_posix - - native_posix_64 + - native_sim + - native_sim_64 tags: - drivers - input integration_platforms: - - native_posix + - native_sim diff --git a/tests/subsys/input/input_shell/testcase.yaml b/tests/subsys/input/input_shell/testcase.yaml index e226780164f..2848957f74a 100644 --- a/tests/subsys/input/input_shell/testcase.yaml +++ b/tests/subsys/input/input_shell/testcase.yaml @@ -6,6 +6,10 @@ tests: platform_allow: - native_posix - native_posix_64 + - native_sim + - native_sim_64 + integration_platforms: + - native_sim harness: console harness_config: type: multi_line From 6d762359a563c556ac665a1af9dca0796021223b Mon Sep 17 00:00:00 2001 From: Alberto Escolar Piedras Date: Mon, 20 Nov 2023 16:20:49 +0100 Subject: [PATCH 0092/3723] tests/subsys/storage/*: Switch to native_sim Enable all these tests which run in native_posix in native_sim, Switch from native_posix to native_sim as default test platform Signed-off-by: Alberto Escolar Piedras --- tests/subsys/storage/flash_map/testcase.yaml | 8 +++++-- .../storage/stream/stream_flash/testcase.yaml | 22 ++++++++++--------- 2 files changed, 18 insertions(+), 12 deletions(-) diff --git a/tests/subsys/storage/flash_map/testcase.yaml b/tests/subsys/storage/flash_map/testcase.yaml index b9b13002d52..1d03fc2ed2f 100644 --- a/tests/subsys/storage/flash_map/testcase.yaml +++ b/tests/subsys/storage/flash_map/testcase.yaml @@ -5,10 +5,12 @@ tests: - qemu_x86 - native_posix - native_posix_64 + - native_sim + - native_sim_64 - mr_canhubk3 tags: flash_map integration_platforms: - - native_posix + - native_sim storage.flash_map.mpu: extra_args: OVERLAY_CONFIG=overlay-mpu.conf platform_allow: @@ -27,7 +29,9 @@ tests: - qemu_x86 - native_posix - native_posix_64 + - native_sim + - native_sim_64 - mr_canhubk3 tags: flash_map integration_platforms: - - native_posix + - native_sim diff --git a/tests/subsys/storage/stream/stream_flash/testcase.yaml b/tests/subsys/storage/stream/stream_flash/testcase.yaml index 4caff73e58d..9f4b8c16383 100644 --- a/tests/subsys/storage/stream/stream_flash/testcase.yaml +++ b/tests/subsys/storage/stream/stream_flash/testcase.yaml @@ -1,22 +1,24 @@ +common: + platform_allow: + - native_posix + - native_posix_64 + - native_sim + - native_sim_64 + integration_platforms: + - native_sim tests: storage.stream_flash: - platform_allow: - - native_posix - - native_posix_64 tags: stream_flash storage.stream_flash.dword_wbs: extra_args: DTC_OVERLAY_FILE=unaligned_flush.overlay - platform_allow: - - native_posix - - native_posix_64 tags: stream_flash storage.stream_flash.no_erase: extra_args: OVERLAY_CONFIG=no_erase.overlay - platform_allow: - - native_posix - - native_posix_64 tags: stream_flash storage.stream_flash.mpu_allow_flash_write: extra_args: OVERLAY_CONFIG=mpu_allow_flash_write.overlay - platform_allow: nrf52840dk_nrf52840 + platform_allow: + - nrf52840dk_nrf52840 + integration_platforms: + - nrf52840dk_nrf52840 tags: stream_flash From eb127538b10e792179d60ca7124e9f41571e487c Mon Sep 17 00:00:00 2001 From: Seppo Takalo Date: Mon, 13 Nov 2023 13:33:58 +0200 Subject: [PATCH 0093/3723] test: lwm2m: Mark some tests as slow This allows quick filtering with pytest_args: ['-k not slow'] Signed-off-by: Seppo Takalo --- tests/net/lib/lwm2m/interop/pytest/pytest.ini | 3 +++ tests/net/lib/lwm2m/interop/pytest/test_lwm2m.py | 9 +++++++++ 2 files changed, 12 insertions(+) create mode 100644 tests/net/lib/lwm2m/interop/pytest/pytest.ini diff --git a/tests/net/lib/lwm2m/interop/pytest/pytest.ini b/tests/net/lib/lwm2m/interop/pytest/pytest.ini new file mode 100644 index 00000000000..761785364d8 --- /dev/null +++ b/tests/net/lib/lwm2m/interop/pytest/pytest.ini @@ -0,0 +1,3 @@ +[pytest] +markers = + slow: marks tests as slow (deselect with '-m "not slow"') diff --git a/tests/net/lib/lwm2m/interop/pytest/test_lwm2m.py b/tests/net/lib/lwm2m/interop/pytest/test_lwm2m.py index 8f3acd69c7e..c37a3900aa6 100644 --- a/tests/net/lib/lwm2m/interop/pytest/test_lwm2m.py +++ b/tests/net/lib/lwm2m/interop/pytest/test_lwm2m.py @@ -51,6 +51,7 @@ def test_LightweightM2M_1_1_int_104(shell: Shell, dut: DeviceAdapter, leshan: Le leshan.execute(endpoint, '1/0/8') dut.readlines_until(regex='.*net_lwm2m_rd_client: Update Done', timeout=5.0) +@pytest.mark.slow def test_LightweightM2M_1_1_int_107(shell: Shell, dut: DeviceAdapter, leshan: Leshan, endpoint: str): """LightweightM2M-1.1-int-107 - Extending the lifetime of a registration""" leshan.write(endpoint, '1/0/1', 120) @@ -66,6 +67,7 @@ def test_LightweightM2M_1_1_int_108(leshan, endpoint): """LightweightM2M-1.1-int-108 - Turn on Queue Mode""" assert leshan.get(f'/clients/{endpoint}')["queuemode"] +@pytest.mark.slow def test_LightweightM2M_1_1_int_109(shell: Shell, dut: DeviceAdapter, leshan: Leshan, endpoint: str): """LightweightM2M-1.1-int-109 - Behavior in Queue Mode""" logger.debug('Wait for Queue RX OFF') @@ -500,6 +502,7 @@ def test_LightweightM2M_1_1_int_281(shell: Shell, leshan: Leshan, endpoint: str) # Information Reporting Interface [300-399] # +@pytest.mark.slow def test_LightweightM2M_1_1_int_301(shell: Shell, leshan: Leshan, endpoint: str): """LightweightM2M-1.1-int-301 - Observation and Notification of parameter values""" pwr_src = leshan.read(endpoint, '3/0/6') @@ -527,6 +530,7 @@ def test_LightweightM2M_1_1_int_301(shell: Shell, leshan: Leshan, endpoint: str) assert (start + 15) <= time.time() + 1 # Allow 1 second slack. (pMinx + pMax=15) leshan.cancel_observe(endpoint, '3/0/7') +@pytest.mark.slow def test_LightweightM2M_1_1_int_302(shell: Shell, dut: DeviceAdapter, leshan: Leshan, endpoint: str): """LightweightM2M-1.1-int-302 - Cancel Observations using Reset Operation""" leshan.observe(endpoint, '3/0/7') @@ -546,6 +550,7 @@ def test_LightweightM2M_1_1_int_302(shell: Shell, dut: DeviceAdapter, leshan: Le shell.exec_command('lwm2m write /3/0/8/0 -u32 50') dut.readlines_until(regex=r'.*Observer removed for 3/0/8') +@pytest.mark.slow def test_LightweightM2M_1_1_int_304(shell: Shell, leshan: Leshan, endpoint: str): """LightweightM2M-1.1-int-304 - Observe-Composite Operation""" assert leshan.put_raw(f'/clients/{endpoint}/1/0/1/attributes?pmin=30')['status'] == 'CHANGED(204)' @@ -590,6 +595,8 @@ def test_LightweightM2M_1_1_int_307(shell: Shell, dut: DeviceAdapter, leshan: Le shell.exec_command('lwm2m send /3/0') dut.readlines_until(regex=r'.*SEND status: 0', timeout=5.0) + +@pytest.mark.slow def test_LightweightM2M_1_1_int_308(shell: Shell, dut: DeviceAdapter, leshan: Leshan, endpoint: str): """LightweightM2M-1.1-int-308 - Observe-Composite and Creating Object Instance""" shell.exec_command('lwm2m delete /16/0') @@ -631,6 +638,7 @@ def test_LightweightM2M_1_1_int_308(shell: Shell, dut: DeviceAdapter, leshan: Le shell.exec_command('lwm2m write 1/0/2 -u32 1') shell.exec_command('lwm2m write 1/0/3 -u32 10') +@pytest.mark.slow def test_LightweightM2M_1_1_int_309(shell: Shell, dut: DeviceAdapter, leshan: Leshan, endpoint: str): """LightweightM2M-1.1-int-309 - Observe-Composite and Deleting Object Instance""" shell.exec_command('lwm2m delete /16/0') @@ -673,6 +681,7 @@ def test_LightweightM2M_1_1_int_309(shell: Shell, dut: DeviceAdapter, leshan: Le shell.exec_command('lwm2m write 1/0/2 -u32 1') shell.exec_command('lwm2m write 1/0/3 -u32 10') +@pytest.mark.slow def test_LightweightM2M_1_1_int_310(shell: Shell, leshan: Leshan, endpoint: str): """LightweightM2M-1.1-int-310 - Observe-Composite and modification of parameter values""" # Need to use Configuration C.1 From 92ceaab491a0a579a585b55c85d66673bceb7ea6 Mon Sep 17 00:00:00 2001 From: Seppo Takalo Date: Mon, 13 Nov 2023 16:02:07 +0200 Subject: [PATCH 0094/3723] test: lwm2m: Implement write_attributes() Implement write and remove attributes command for Leshan. Remove all written attributes at the end of test, so it won't affect the next test case. Remove skip marks from testcase that is fixed on Leshan side. Signed-off-by: Seppo Takalo --- tests/net/lib/lwm2m/interop/README.md | 2 +- tests/net/lib/lwm2m/interop/pytest/leshan.py | 19 ++++++- .../lib/lwm2m/interop/pytest/test_lwm2m.py | 56 ++++++++++--------- 3 files changed, 48 insertions(+), 29 deletions(-) diff --git a/tests/net/lib/lwm2m/interop/README.md b/tests/net/lib/lwm2m/interop/README.md index bda38924d26..3654ca94b01 100644 --- a/tests/net/lib/lwm2m/interop/README.md +++ b/tests/net/lib/lwm2m/interop/README.md @@ -167,7 +167,7 @@ Tests are written from test spec; |LightweightM2M-1.1-int-256 - Write Operation Failure|:white_check_mark:| | |LightweightM2M-1.1-int-257 - Write-Composite Operation|:white_check_mark:| | |LightweightM2M-1.1-int-260 - Discover Command|:white_check_mark:| | -|LightweightM2M-1.1-int-261 - Write-Attribute Operation on a multiple resource|:large_orange_diamond:|Leshan don't allow writing attributes to resource instance| +|LightweightM2M-1.1-int-261 - Write-Attribute Operation on a multiple resource|:white_check_mark:| | |LightweightM2M-1.1-int-280 - Successful Read-Composite Operation|:white_check_mark:| | |LightweightM2M-1.1-int-281 - Partially Successful Read-Composite Operation|:white_check_mark:| | |LightweightM2M-1.1-int-301 - Observation and Notification of parameter values|:white_check_mark:| | diff --git a/tests/net/lib/lwm2m/interop/pytest/leshan.py b/tests/net/lib/lwm2m/interop/pytest/leshan.py index 7240aae2baf..4add988ea77 100644 --- a/tests/net/lib/lwm2m/interop/pytest/leshan.py +++ b/tests/net/lib/lwm2m/interop/pytest/leshan.py @@ -62,9 +62,9 @@ def get(self, path: str): resp = self._s.get(f'{self.api_url}{path}', params=params, timeout=self.timeout) return Leshan.handle_response(resp) - def put_raw(self, path: str, data: str | dict | None = None, headers: dict | None = None): + def put_raw(self, path: str, data: str | dict | None = None, headers: dict | None = None, params: dict | None = None): """Send HTTP PUT query without any default parameters""" - resp = self._s.put(f'{self.api_url}{path}', data=data, headers=headers, timeout=self.timeout) + resp = self._s.put(f'{self.api_url}{path}', data=data, headers=headers, params=params, timeout=self.timeout) return Leshan.handle_response(resp) def put(self, path: str, data: str | dict, uri_options: str = ''): @@ -108,6 +108,21 @@ def write(self, endpoint: str, path: str, value: bool | int | str): rid = path.split('/')[-1] return self.put(f'/clients/{endpoint}/{path}', self._define_resource(rid, value, kind)) + def write_attributes(self, endpoint: str, path: str, attributes: dict): + """Send LwM2M Write-Attributes to given path + example: + leshan.write_attributes(endpoint, '1/2/3, {'pmin': 10, 'pmax': 40}) + """ + return self.put_raw(f'/clients/{endpoint}/{path}/attributes', params=attributes) + + def remove_attributes(self, endpoint: str, path: str, attributes: list): + """Send LwM2M Write-Attributes to given path + example: + leshan.remove_attributes(endpoint, '1/2/3, ['pmin', 'pmax']) + """ + attrs = '&'.join(attributes) + return self.put_raw(f'/clients/{endpoint}/{path}/attributes?'+ attrs) + def update_obj_instance(self, endpoint: str, path: str, resources: dict): """Update object instance""" data = self._define_obj_inst(path, resources) diff --git a/tests/net/lib/lwm2m/interop/pytest/test_lwm2m.py b/tests/net/lib/lwm2m/interop/pytest/test_lwm2m.py index c37a3900aa6..f596f74d30a 100644 --- a/tests/net/lib/lwm2m/interop/pytest/test_lwm2m.py +++ b/tests/net/lib/lwm2m/interop/pytest/test_lwm2m.py @@ -202,7 +202,7 @@ def test_LightweightM2M_1_1_int_221(shell: Shell, leshan: Leshan, endpoint: str) """LightweightM2M-1.1-int-221 - Attempt to perform operations on Security""" assert leshan.read(endpoint, '0/0')['status'] == 'UNAUTHORIZED(401)' assert leshan.write(endpoint, '0/0/0', 'coap://localhost')['status'] == 'UNAUTHORIZED(401)' - assert leshan.put_raw(f'/clients/{endpoint}/0/attributes?pmin=10')['status'] == 'UNAUTHORIZED(401)' + assert leshan.write_attributes(endpoint, '0', {'pmin':10})['status'] == 'UNAUTHORIZED(401)' def test_LightweightM2M_1_1_int_222(shell: Shell, leshan: Leshan, endpoint: str): """LightweightM2M-1.1-int-222 - Read on Object""" @@ -429,15 +429,12 @@ def test_LightweightM2M_1_1_int_260(shell: Shell, leshan: Leshan, endpoint: str) expected_keys = ['/3', '/3/0', '/3/0/1', '/3/0/2', '/3/0/3', '/3/0/4', '/3/0/6', '/3/0/7', '/3/0/8', '/3/0/9', '/3/0/11', '/3/0/16'] missing_keys = [key for key in expected_keys if key not in resp.keys()] assert len(missing_keys) == 0 - assert leshan.put_raw(f'/clients/{endpoint}/3/attributes?pmin=10')['status'] == 'CHANGED(204)' - assert leshan.put_raw(f'/clients/{endpoint}/3/attributes?pmax=200')['status'] == 'CHANGED(204)' + assert leshan.write_attributes(endpoint, '3', {'pmin': 10, 'pmax': 200})['status'] == 'CHANGED(204)' resp = leshan.discover(endpoint, '3/0') assert int(resp['/3/0/6']['dim']) == 2 assert int(resp['/3/0/7']['dim']) == 2 assert int(resp['/3/0/8']['dim']) == 2 - assert leshan.put_raw(f'/clients/{endpoint}/3/0/7/attributes?lt=1')['status'] == 'CHANGED(204)' - assert leshan.put_raw(f'/clients/{endpoint}/3/0/7/attributes?gt=6')['status'] == 'CHANGED(204)' - assert leshan.put_raw(f'/clients/{endpoint}/3/0/7/attributes?st=1')['status'] == 'CHANGED(204)' + assert leshan.write_attributes(endpoint, '3/0/7', {'lt': 1, 'gt': 6, 'st': 1})['status'] == 'CHANGED(204)' resp = leshan.discover(endpoint, '3/0') expected_keys = ['/3/0', '/3/0/1', '/3/0/2', '/3/0/3', '/3/0/4', '/3/0/6', '/3/0/7', '/3/0/8', '/3/0/9', '/3/0/11', '/3/0/16'] missing_keys = [key for key in expected_keys if key not in resp.keys()] @@ -451,8 +448,9 @@ def test_LightweightM2M_1_1_int_260(shell: Shell, leshan: Leshan, endpoint: str) missing_keys = [key for key in expected_keys if key not in resp.keys()] assert len(missing_keys) == 0 assert len(resp) == len(expected_keys) + # restore + leshan.remove_attributes(endpoint, '3', ['pmin', 'pmax']) -@pytest.mark.skip(reason="Leshan don't allow writing attributes to resource instance") def test_LightweightM2M_1_1_int_261(shell: Shell, leshan: Leshan, endpoint: str): """LightweightM2M-1.1-int-261 - Write-Attribute Operation on a multiple resource""" resp = leshan.discover(endpoint, '3/0/11') @@ -462,19 +460,20 @@ def test_LightweightM2M_1_1_int_261(shell: Shell, leshan: Leshan, endpoint: str) assert len(missing_keys) == 0 assert len(resp) == len(expected_keys) assert int(resp['/3/0/11']['dim']) == 1 - assert leshan.put_raw(f'/clients/{endpoint}/3/attributes?pmin=10')['status'] == 'CHANGED(204)' - assert leshan.put_raw(f'/clients/{endpoint}/3/attributes?pmax=200')['status'] == 'CHANGED(204)' - assert leshan.put_raw(f'/clients/{endpoint}/3/0/attributes?pmax=320')['status'] == 'CHANGED(204)' - assert leshan.put_raw(f'/clients/{endpoint}/3/0/11/0/attributes?pmax=100')['status'] == 'CHANGED(204)' - assert leshan.put_raw(f'/clients/{endpoint}/3/0/11/0/attributes?epmin=1')['status'] == 'CHANGED(204)' - assert leshan.put_raw(f'/clients/{endpoint}/3/0/11/0/attributes?epmax=20')['status'] == 'CHANGED(204)' + assert leshan.write_attributes(endpoint, '3', {'pmin':10, 'pmax':200})['status'] == 'CHANGED(204)' + assert leshan.write_attributes(endpoint, '3/0', {'pmax':320})['status'] == 'CHANGED(204)' + assert leshan.write_attributes(endpoint, '3/0/11/0', {'pmax':100, 'epmin':1, 'epmax':20})['status'] == 'CHANGED(204)' resp = leshan.discover(endpoint, '3/0/11') logger.debug(resp) assert int(resp['/3/0/11']['pmin']) == 10 assert int(resp['/3/0/11']['pmax']) == 320 assert int(resp['/3/0/11/0']['pmax']) == 100 - assert int(resp['/3/0/11/0']['epmin']) == 1 - assert int(resp['/3/0/11/0']['epmax']) == 20 + # Note: Zephyr does not support epmin&epmax. + # Restore + leshan.remove_attributes(endpoint, '3', ['pmin', 'pmax']) + leshan.remove_attributes(endpoint, '3/0', ['pmax']) + leshan.remove_attributes(endpoint, '3/0/11/0', ['pmax']) + def test_LightweightM2M_1_1_int_280(shell: Shell, leshan: Leshan, endpoint: str): """LightweightM2M-1.1-int-280 - Successful Read-Composite Operation""" @@ -509,8 +508,7 @@ def test_LightweightM2M_1_1_int_301(shell: Shell, leshan: Leshan, endpoint: str) logger.debug(pwr_src) assert pwr_src[6][0] == 1 assert pwr_src[6][1] == 5 - assert leshan.put_raw(f'/clients/{endpoint}/3/0/7/attributes?pmin=5')['status'] == 'CHANGED(204)' - assert leshan.put_raw(f'/clients/{endpoint}/3/0/7/attributes?pmax=10')['status'] == 'CHANGED(204)' + assert leshan.write_attributes(endpoint, '3/0/7', {'pmin': 5, 'pmax': 10})['status'] == 'CHANGED(204)' leshan.observe(endpoint, '3/0/7') with leshan.get_event_stream(endpoint, timeout=30) as events: shell.exec_command('lwm2m write /3/0/7/0 -u32 3000') @@ -529,6 +527,7 @@ def test_LightweightM2M_1_1_int_301(shell: Shell, leshan: Leshan, endpoint: str) assert data[3][0][7][0] == 3500 assert (start + 15) <= time.time() + 1 # Allow 1 second slack. (pMinx + pMax=15) leshan.cancel_observe(endpoint, '3/0/7') + leshan.remove_attributes(endpoint, '3/0/7', ['pmin', 'pmax']) @pytest.mark.slow def test_LightweightM2M_1_1_int_302(shell: Shell, dut: DeviceAdapter, leshan: Leshan, endpoint: str): @@ -553,8 +552,10 @@ def test_LightweightM2M_1_1_int_302(shell: Shell, dut: DeviceAdapter, leshan: Le @pytest.mark.slow def test_LightweightM2M_1_1_int_304(shell: Shell, leshan: Leshan, endpoint: str): """LightweightM2M-1.1-int-304 - Observe-Composite Operation""" - assert leshan.put_raw(f'/clients/{endpoint}/1/0/1/attributes?pmin=30')['status'] == 'CHANGED(204)' - assert leshan.put_raw(f'/clients/{endpoint}/1/0/1/attributes?pmax=45')['status'] == 'CHANGED(204)' + # Need to use Configuration C.1 + shell.exec_command('lwm2m write 1/0/2 -u32 0') + shell.exec_command('lwm2m write 1/0/3 -u32 0') + assert leshan.write_attributes(endpoint, '1/0/1', {'pmin': 30, 'pmax': 45})['status'] == 'CHANGED(204)' data = leshan.composite_observe(endpoint, ['/1/0/1', '/3/0/11/0', '/3/0/16']) assert data[1][0][1] is not None assert data[3][0][11][0] is not None @@ -575,6 +576,10 @@ def test_LightweightM2M_1_1_int_304(shell: Shell, leshan: Leshan, endpoint: str) assert (start + 30) < time.time() assert (start + 45) > time.time() - 1 leshan.cancel_composite_observe(endpoint, ['/1/0/1', '/3/0/11/0', '/3/0/16']) + # Restore configuration C.3 + shell.exec_command('lwm2m write 1/0/2 -u32 1') + shell.exec_command('lwm2m write 1/0/3 -u32 10') + leshan.remove_attributes(endpoint, '1/0/1', ['pmin', 'pmax']) def test_LightweightM2M_1_1_int_306(shell: Shell, dut: DeviceAdapter, leshan: Leshan, endpoint: str): """LightweightM2M-1.1-int-306 - Send Operation""" @@ -620,8 +625,7 @@ def test_LightweightM2M_1_1_int_308(shell: Shell, dut: DeviceAdapter, leshan: Le content_both = {16: {0: resources_a, 1: resources_b}} assert leshan.create_obj_instance(endpoint, '16/0', resources_a)['status'] == 'CREATED(201)' dut.readlines_until(regex='.*net_lwm2m_rd_client: Update Done', timeout=5.0) - assert leshan.put_raw(f'/clients/{endpoint}/16/0/attributes?pmin=30')['status'] == 'CHANGED(204)' - assert leshan.put_raw(f'/clients/{endpoint}/16/0/attributes?pmax=45')['status'] == 'CHANGED(204)' + assert leshan.write_attributes(endpoint, '16/0', {'pmin': 30, 'pmax': 45})['status'] == 'CHANGED(204)' data = leshan.composite_observe(endpoint, ['/16/0', '/16/1']) assert data == content_one with leshan.get_event_stream(endpoint, timeout=50) as events: @@ -637,6 +641,7 @@ def test_LightweightM2M_1_1_int_308(shell: Shell, dut: DeviceAdapter, leshan: Le # Restore configuration C.3 shell.exec_command('lwm2m write 1/0/2 -u32 1') shell.exec_command('lwm2m write 1/0/3 -u32 10') + leshan.remove_attributes(endpoint, '16/0', ['pmin','pmax']) @pytest.mark.slow def test_LightweightM2M_1_1_int_309(shell: Shell, dut: DeviceAdapter, leshan: Leshan, endpoint: str): @@ -663,8 +668,7 @@ def test_LightweightM2M_1_1_int_309(shell: Shell, dut: DeviceAdapter, leshan: Le assert leshan.create_obj_instance(endpoint, '16/0', resources_a)['status'] == 'CREATED(201)' assert leshan.create_obj_instance(endpoint, '16/1', resources_b)['status'] == 'CREATED(201)' dut.readlines_until(regex='.*net_lwm2m_rd_client: Update Done', timeout=5.0) - assert leshan.put_raw(f'/clients/{endpoint}/16/0/attributes?pmin=30')['status'] == 'CHANGED(204)' - assert leshan.put_raw(f'/clients/{endpoint}/16/0/attributes?pmax=45')['status'] == 'CHANGED(204)' + assert leshan.write_attributes(endpoint, '16/0', {'pmin': 30, 'pmax': 45})['status'] == 'CHANGED(204)' data = leshan.composite_observe(endpoint, ['/16/0', '/16/1']) assert data == content_both with leshan.get_event_stream(endpoint, timeout=50) as events: @@ -680,6 +684,7 @@ def test_LightweightM2M_1_1_int_309(shell: Shell, dut: DeviceAdapter, leshan: Le # Restore configuration C.3 shell.exec_command('lwm2m write 1/0/2 -u32 1') shell.exec_command('lwm2m write 1/0/3 -u32 10') + leshan.remove_attributes(endpoint, '16/0', ['pmin', 'pmax']) @pytest.mark.slow def test_LightweightM2M_1_1_int_310(shell: Shell, leshan: Leshan, endpoint: str): @@ -687,11 +692,9 @@ def test_LightweightM2M_1_1_int_310(shell: Shell, leshan: Leshan, endpoint: str) # Need to use Configuration C.1 shell.exec_command('lwm2m write 1/0/2 -u32 0') shell.exec_command('lwm2m write 1/0/3 -u32 0') - # Ensure that our previous attributes are not conflicting - assert leshan.put_raw(f'/clients/{endpoint}/3/attributes?pmin=0')['status'] == 'CHANGED(204)' leshan.composite_observe(endpoint, ['/1/0/1', '/3/0']) with leshan.get_event_stream(endpoint, timeout=50) as events: - assert leshan.put_raw(f'/clients/{endpoint}/3/attributes?pmax=5')['status'] == 'CHANGED(204)' + assert leshan.write_attributes(endpoint, '3', {'pmax': 5})['status'] == 'CHANGED(204)' start = time.time() data = events.next_event('NOTIFICATION') assert data[3][0][0] == 'Zephyr' @@ -704,6 +707,7 @@ def test_LightweightM2M_1_1_int_310(shell: Shell, leshan: Leshan, endpoint: str) # Restore configuration C.3 shell.exec_command('lwm2m write 1/0/2 -u32 1') shell.exec_command('lwm2m write 1/0/3 -u32 10') + leshan.remove_attributes(endpoint, '3', ['pmax']) def test_LightweightM2M_1_1_int_311(shell: Shell, leshan: Leshan, endpoint: str): """LightweightM2M-1.1-int-311 - Send command""" From 2135e009e4d9dbc77a9083313705236708868dad Mon Sep 17 00:00:00 2001 From: Seppo Takalo Date: Mon, 13 Nov 2023 16:36:03 +0200 Subject: [PATCH 0095/3723] test: lwm2m: Implement Read-Composite Operation on root path Test case: LightweightM2M-1.1-int-235 - Read-Composite Operation on root path is now working as Leshan added a support for reading the root path. Signed-off-by: Seppo Takalo --- tests/net/lib/lwm2m/interop/README.md | 2 +- tests/net/lib/lwm2m/interop/pytest/leshan.py | 4 ++++ tests/net/lib/lwm2m/interop/pytest/test_lwm2m.py | 7 +++++-- 3 files changed, 10 insertions(+), 3 deletions(-) diff --git a/tests/net/lib/lwm2m/interop/README.md b/tests/net/lib/lwm2m/interop/README.md index 3654ca94b01..204aff636ac 100644 --- a/tests/net/lib/lwm2m/interop/README.md +++ b/tests/net/lib/lwm2m/interop/README.md @@ -160,7 +160,7 @@ Tests are written from test spec; |LightweightM2M-1.1-int-232 - Querying basic information in SenML CBOR format|:white_check_mark:| | |LightweightM2M-1.1-int-233 - Setting basic information in SenML CBOR format|:white_check_mark:| | |LightweightM2M-1.1-int-234 - Setting basic information in SenML JSON format|:white_check_mark:| | -|LightweightM2M-1.1-int-235 - Read-Composite Operation on root path|:large_orange_diamond:|Root Path is not yet supported by Leshan.| +|LightweightM2M-1.1-int-235 - Read-Composite Operation on root path|:white_check_mark:| | |LightweightM2M-1.1-int-236 - Read-Composite - Partial Presence|:white_check_mark:| | |LightweightM2M-1.1-int-237 - Read on Object without specifying Content-Type|:white_check_mark:| | |LightweightM2M-1.1-int-241 - Executable Resource: Rebooting the device|:white_check_mark:| | diff --git a/tests/net/lib/lwm2m/interop/pytest/leshan.py b/tests/net/lib/lwm2m/interop/pytest/leshan.py index 4add988ea77..65295e652bc 100644 --- a/tests/net/lib/lwm2m/interop/pytest/leshan.py +++ b/tests/net/lib/lwm2m/interop/pytest/leshan.py @@ -271,6 +271,10 @@ def parse_composite(cls, payload: dict): raise RuntimeError(f'No content received') payload = payload['content'] for path, content in payload.items(): + if path == "/": + for obj in content['objects']: + data.update(cls._decode_obj(obj)) + continue keys = [int(key) for key in path.lstrip("/").split('/')] if len(keys) == 1: data.update(cls._decode_obj(content)) diff --git a/tests/net/lib/lwm2m/interop/pytest/test_lwm2m.py b/tests/net/lib/lwm2m/interop/pytest/test_lwm2m.py index f596f74d30a..eabc4bbc614 100644 --- a/tests/net/lib/lwm2m/interop/pytest/test_lwm2m.py +++ b/tests/net/lib/lwm2m/interop/pytest/test_lwm2m.py @@ -367,9 +367,12 @@ def test_LightweightM2M_1_1_int_234(shell: Shell, leshan: Leshan, endpoint: str) """LightweightM2M-1.1-int-234 - Setting basic information in SenML JSON format""" setting_basic_senml(shell, leshan, endpoint, 'SENML_JSON') -@pytest.mark.skip("Leshan does not allow reading root path") -def test_LightweightM2M_1_1_int_235(): +def test_LightweightM2M_1_1_int_235(leshan: Leshan, endpoint: str): """LightweightM2M-1.1-int-235 - Read-Composite Operation on root path""" + resp = leshan.composite_read(endpoint, ['/']) + expected_keys = [16, 1, 3, 5] + missing_keys = [key for key in expected_keys if key not in resp.keys()] + assert len(missing_keys) == 0 def test_LightweightM2M_1_1_int_236(shell: Shell, leshan: Leshan, endpoint: str): """LightweightM2M-1.1-int-236 - Read-Composite - Partial Presence""" From 31e9a5674267dbc3efc717f15bf601a2e064d1ec Mon Sep 17 00:00:00 2001 From: Seppo Takalo Date: Mon, 20 Nov 2023 16:14:07 +0200 Subject: [PATCH 0096/3723] test: lwm2m: Test cancellation using observe parameter Implement test cases: LightweightM2M-1.1-int-303 - Cancel observations using Observe with Cancel parameter LightweightM2M-1.1-int-305 - Cancel Observation-Composite Operation Modify existing Leshan API to passive_cancel(). Signed-off-by: Seppo Takalo --- tests/net/lib/lwm2m/interop/README.md | 4 +-- tests/net/lib/lwm2m/interop/pytest/leshan.py | 7 +++++ .../lib/lwm2m/interop/pytest/test_lwm2m.py | 30 +++++++++++++++++-- 3 files changed, 36 insertions(+), 5 deletions(-) diff --git a/tests/net/lib/lwm2m/interop/README.md b/tests/net/lib/lwm2m/interop/README.md index 204aff636ac..3acbfcc71f8 100644 --- a/tests/net/lib/lwm2m/interop/README.md +++ b/tests/net/lib/lwm2m/interop/README.md @@ -172,9 +172,9 @@ Tests are written from test spec; |LightweightM2M-1.1-int-281 - Partially Successful Read-Composite Operation|:white_check_mark:| | |LightweightM2M-1.1-int-301 - Observation and Notification of parameter values|:white_check_mark:| | |LightweightM2M-1.1-int-302 - Cancel Observations using Reset Operation|:white_check_mark:| | -|LightweightM2M-1.1-int-303 - Cancel observations using Observe with Cancel parameter|:large_orange_diamond:|Leshan only supports passive cancelling| +|LightweightM2M-1.1-int-303 - Cancel observations using Observe with Cancel parameter|:white_check_mark:|| |LightweightM2M-1.1-int-304 - Observe-Composite Operation|:white_check_mark:| | -|LightweightM2M-1.1-int-305 - Cancel Observation-Composite Operation|:large_orange_diamond:|Leshan only supports passive cancelling| +|LightweightM2M-1.1-int-305 - Cancel Observation-Composite Operation|:white_check_mark:| | |LightweightM2M-1.1-int-306 – Send Operation|:white_check_mark:|[~~#64290~~](https://github.com/zephyrproject-rtos/zephyr/issues/64290)| |LightweightM2M-1.1-int-307 – Muting Send|:white_check_mark:| | |LightweightM2M-1.1-int-308 - Observe-Composite and Creating Object Instance|:white_check_mark:|[~~#64634~~](https://github.com/zephyrproject-rtos/zephyr/issues/64634)| diff --git a/tests/net/lib/lwm2m/interop/pytest/leshan.py b/tests/net/lib/lwm2m/interop/pytest/leshan.py index 65295e652bc..181f15ebf61 100644 --- a/tests/net/lib/lwm2m/interop/pytest/leshan.py +++ b/tests/net/lib/lwm2m/interop/pytest/leshan.py @@ -389,6 +389,9 @@ def observe(self, endpoint: str, path: str): return self.post(f'/clients/{endpoint}/{path}/observe', data="") def cancel_observe(self, endpoint: str, path: str): + return self.delete_raw(f'/clients/{endpoint}/{path}/observe?active') + + def passive_cancel_observe(self, endpoint: str, path: str): return self.delete_raw(f'/clients/{endpoint}/{path}/observe') def composite_observe(self, endpoint: str, paths: list[str]): @@ -398,6 +401,10 @@ def composite_observe(self, endpoint: str, paths: list[str]): return self.parse_composite(payload) def cancel_composite_observe(self, endpoint: str, paths: list[str]): + paths = [path if path.startswith('/') else '/' + path for path in paths] + return self.delete_raw(f'/clients/{endpoint}/composite/observe?paths=' + ','.join(paths) + '&active') + + def passive_cancel_composite_observe(self, endpoint: str, paths: list[str]): paths = [path if path.startswith('/') else '/' + path for path in paths] return self.delete_raw(f'/clients/{endpoint}/composite/observe?paths=' + ','.join(paths)) diff --git a/tests/net/lib/lwm2m/interop/pytest/test_lwm2m.py b/tests/net/lib/lwm2m/interop/pytest/test_lwm2m.py index eabc4bbc614..131acb68e14 100644 --- a/tests/net/lib/lwm2m/interop/pytest/test_lwm2m.py +++ b/tests/net/lib/lwm2m/interop/pytest/test_lwm2m.py @@ -532,7 +532,6 @@ def test_LightweightM2M_1_1_int_301(shell: Shell, leshan: Leshan, endpoint: str) leshan.cancel_observe(endpoint, '3/0/7') leshan.remove_attributes(endpoint, '3/0/7', ['pmin', 'pmax']) -@pytest.mark.slow def test_LightweightM2M_1_1_int_302(shell: Shell, dut: DeviceAdapter, leshan: Leshan, endpoint: str): """LightweightM2M-1.1-int-302 - Cancel Observations using Reset Operation""" leshan.observe(endpoint, '3/0/7') @@ -541,17 +540,34 @@ def test_LightweightM2M_1_1_int_302(shell: Shell, dut: DeviceAdapter, leshan: Le shell.exec_command('lwm2m write /3/0/7/0 -u32 4000') data = events.next_event('NOTIFICATION') assert data[3][0][7][0] == 4000 - leshan.cancel_observe(endpoint, '3/0/7') + leshan.passive_cancel_observe(endpoint, '3/0/7') shell.exec_command('lwm2m write /3/0/7/0 -u32 3000') dut.readlines_until(regex=r'.*Observer removed for 3/0/7') with leshan.get_event_stream(endpoint) as events: shell.exec_command('lwm2m write /3/0/8/0 -u32 100') data = events.next_event('NOTIFICATION') assert data[3][0][8][0] == 100 - leshan.cancel_observe(endpoint, '3/0/8') + leshan.passive_cancel_observe(endpoint, '3/0/8') shell.exec_command('lwm2m write /3/0/8/0 -u32 50') dut.readlines_until(regex=r'.*Observer removed for 3/0/8') +def test_LightweightM2M_1_1_int_303(shell: Shell, dut: DeviceAdapter, leshan: Leshan, endpoint: str): + """LightweightM2M-1.1-int-303 - Cancel observations using Observe with Cancel parameter""" + leshan.observe(endpoint, '3/0/7') + leshan.observe(endpoint, '3/0/8') + with leshan.get_event_stream(endpoint) as events: + shell.exec_command('lwm2m write /3/0/7/0 -u32 4000') + data = events.next_event('NOTIFICATION') + assert data[3][0][7][0] == 4000 + leshan.cancel_observe(endpoint, '3/0/7') + dut.readlines_until(regex=r'.*Observer removed for 3/0/7') + with leshan.get_event_stream(endpoint) as events: + shell.exec_command('lwm2m write /3/0/8/0 -u32 100') + data = events.next_event('NOTIFICATION') + assert data[3][0][8][0] == 100 + leshan.cancel_observe(endpoint, '3/0/8') + dut.readlines_until(regex=r'.*Observer removed for 3/0/8') + @pytest.mark.slow def test_LightweightM2M_1_1_int_304(shell: Shell, leshan: Leshan, endpoint: str): """LightweightM2M-1.1-int-304 - Observe-Composite Operation""" @@ -584,6 +600,14 @@ def test_LightweightM2M_1_1_int_304(shell: Shell, leshan: Leshan, endpoint: str) shell.exec_command('lwm2m write 1/0/3 -u32 10') leshan.remove_attributes(endpoint, '1/0/1', ['pmin', 'pmax']) +def test_LightweightM2M_1_1_int_305(dut: DeviceAdapter, leshan: Leshan, endpoint: str): + """LightweightM2M-1.1-int-305 - Cancel Observation-Composite Operation""" + leshan.composite_observe(endpoint, ['/1/0/1', '/3/0/11/0', '/3/0/16']) + leshan.cancel_composite_observe(endpoint, ['/1/0/1', '/3/0/11/0', '/3/0/16']) + dut.readlines_until(regex=r'.*Observer removed for 1/0/1') + dut.readlines_until(regex=r'.*Observer removed for 3/0/11/0') + dut.readlines_until(regex=r'.*Observer removed for 3/0/16') + def test_LightweightM2M_1_1_int_306(shell: Shell, dut: DeviceAdapter, leshan: Leshan, endpoint: str): """LightweightM2M-1.1-int-306 - Send Operation""" with leshan.get_event_stream(endpoint) as events: From 90dfbf99d8e83e11bfae64fb1216613e24ac0bcc Mon Sep 17 00:00:00 2001 From: Jamie McCrae Date: Mon, 20 Nov 2023 15:00:59 +0000 Subject: [PATCH 0097/3723] drivers: ieee802154: nrf5: Fix missed variable rename Fixes and issue with a variable that has been renamed but whose reference in the source file has not Signed-off-by: Jamie McCrae --- drivers/ieee802154/ieee802154_nrf5.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/ieee802154/ieee802154_nrf5.c b/drivers/ieee802154/ieee802154_nrf5.c index 9a02aef7e4c..2b7d9b8fb6d 100644 --- a/drivers/ieee802154/ieee802154_nrf5.c +++ b/drivers/ieee802154/ieee802154_nrf5.c @@ -930,9 +930,9 @@ static int nrf5_configure(const struct device *dev, #if defined(CONFIG_NRF_802154_SER_HOST) net_time_t period_ns = nrf5_data.csl_period * NSEC_PER_TEN_SYMBOLS; - bool changed = (config->csl_rx_time - nrf5_data.csl_rx_time) % period_ns; + bool changed = (config->expected_rx_time - nrf5_data.csl_rx_time) % period_ns; - nrf5_data.csl_rx_time = config->csl_rx_time; + nrf5_data.csl_rx_time = config->expected_rx_time; if (changed) #endif /* CONFIG_NRF_802154_SER_HOST */ From 98f33a76d69fd13ce6c2f741f2b8823409f13349 Mon Sep 17 00:00:00 2001 From: Andrei Emeltchenko Date: Tue, 21 Nov 2023 15:06:08 +0200 Subject: [PATCH 0098/3723] drivers: tsl2561: Fix type Use int as correct type, fixes also warning comparing uint8_t < 0. Signed-off-by: Andrei Emeltchenko --- drivers/sensor/tsl2561/tsl2561.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/sensor/tsl2561/tsl2561.c b/drivers/sensor/tsl2561/tsl2561.c index 42efffb2242..0e5c0209b6b 100644 --- a/drivers/sensor/tsl2561/tsl2561.c +++ b/drivers/sensor/tsl2561/tsl2561.c @@ -136,7 +136,7 @@ static int tsl2561_sample_fetch(const struct device *dev, enum sensor_channel ch const struct tsl2561_config *config = dev->config; struct tsl2561_data *data = dev->data; uint8_t bytes[2]; - uint8_t ret; + int ret; if (chan != SENSOR_CHAN_ALL && chan != SENSOR_CHAN_LIGHT) { LOG_ERR("Unsupported sensor channel"); From 69d4c13ab39fd36a67d4f1efc835c2d3bb837172 Mon Sep 17 00:00:00 2001 From: Armando Visconti Date: Tue, 21 Nov 2023 17:21:55 +0100 Subject: [PATCH 0099/3723] dt-bindings: sensor: fix typos in ST sensors comment Fix dt-binding wrong filename in dts comment for ST sensors. Signed-off-by: Armando Visconti --- dts/bindings/sensor/st,iis2dlpc-common.yaml | 4 ++-- dts/bindings/sensor/st,iis2iclx-common.yaml | 4 ++-- dts/bindings/sensor/st,ism330dhcx-common.yaml | 4 ++-- dts/bindings/sensor/st,lis2dh-common.yaml | 4 ++-- dts/bindings/sensor/st,lis2ds12-common.yaml | 4 ++-- dts/bindings/sensor/st,lis2dw12-common.yaml | 4 ++-- dts/bindings/sensor/st,lps22df-common.yaml | 4 ++-- dts/bindings/sensor/st,lps22hh-common.yaml | 4 ++-- dts/bindings/sensor/st,lsm6dso-common.yaml | 4 ++-- dts/bindings/sensor/st,lsm6dso16is-common.yaml | 4 ++-- dts/bindings/sensor/st,lsm6dsv16x-common.yaml | 4 ++-- 11 files changed, 22 insertions(+), 22 deletions(-) diff --git a/dts/bindings/sensor/st,iis2dlpc-common.yaml b/dts/bindings/sensor/st,iis2dlpc-common.yaml index 997b0b189f0..d21f4a6d195 100644 --- a/dts/bindings/sensor/st,iis2dlpc-common.yaml +++ b/dts/bindings/sensor/st,iis2dlpc-common.yaml @@ -3,10 +3,10 @@ description: | When setting the odr property in a .dts or .dtsi file you may include - st_iis2dlpc.h and use the macros defined there. + iis2dlpc.h and use the macros defined there. Example: - #include + #include iis2dlpc: iis2dlpc@0 { ... diff --git a/dts/bindings/sensor/st,iis2iclx-common.yaml b/dts/bindings/sensor/st,iis2iclx-common.yaml index 0a312824c98..73bf2894081 100644 --- a/dts/bindings/sensor/st,iis2iclx-common.yaml +++ b/dts/bindings/sensor/st,iis2iclx-common.yaml @@ -3,10 +3,10 @@ description: | When setting the range, odr properties in a .dts or .dtsi file you may - include st_iis2iclx.h and use the macros defined there. + include iis2iclx.h and use the macros defined there. Example: - #include + #include iis2iclx: iis2iclx@0 { ... diff --git a/dts/bindings/sensor/st,ism330dhcx-common.yaml b/dts/bindings/sensor/st,ism330dhcx-common.yaml index f00f37c1700..a12ab3446c1 100644 --- a/dts/bindings/sensor/st,ism330dhcx-common.yaml +++ b/dts/bindings/sensor/st,ism330dhcx-common.yaml @@ -3,10 +3,10 @@ description: | When setting the accel-odr and gyro-odr properties in a .dts or .dtsi file you may include - st_ism330dhcx.h and use the macros defined there. + ism330dhcx.h and use the macros defined there. Example: - #include + #include ism330dhcx: ism330dhcx@0 { ... diff --git a/dts/bindings/sensor/st,lis2dh-common.yaml b/dts/bindings/sensor/st,lis2dh-common.yaml index 351fa0dc97f..1988a7c1deb 100644 --- a/dts/bindings/sensor/st,lis2dh-common.yaml +++ b/dts/bindings/sensor/st,lis2dh-common.yaml @@ -3,10 +3,10 @@ description: | When setting the int1-gpio-config/int2-gpio-config and anym-mode properties - in a .dts or .dtsi file you may include st_lis2dh.h and use the macros defined there. + in a .dts or .dtsi file you may include lis2dh.h and use the macros defined there. Example: - #include + #include lis2dh: lis2dh@0 { ... diff --git a/dts/bindings/sensor/st,lis2ds12-common.yaml b/dts/bindings/sensor/st,lis2ds12-common.yaml index 4ac18b40a55..230e57c0bb5 100644 --- a/dts/bindings/sensor/st,lis2ds12-common.yaml +++ b/dts/bindings/sensor/st,lis2ds12-common.yaml @@ -3,10 +3,10 @@ description: | When setting the odr and power-mode properties in a .dts or .dtsi file you may include - st_lis2ds12.h and use the macros defined there. + lis2ds12.h and use the macros defined there. Example: - #include + #include lis2ds12: lis2ds12@0 { ... diff --git a/dts/bindings/sensor/st,lis2dw12-common.yaml b/dts/bindings/sensor/st,lis2dw12-common.yaml index 0c9f8dcee67..c95a97da398 100644 --- a/dts/bindings/sensor/st,lis2dw12-common.yaml +++ b/dts/bindings/sensor/st,lis2dw12-common.yaml @@ -3,10 +3,10 @@ description: | When setting the odr property in a .dts or .dtsi file you may include - st_lis2dw12.h and use the macros defined there. + lis2dw12.h and use the macros defined there. Example: - #include + #include lis2dw12: lis2dw12@0 { ... diff --git a/dts/bindings/sensor/st,lps22df-common.yaml b/dts/bindings/sensor/st,lps22df-common.yaml index cc3f11c106f..f8b54960648 100644 --- a/dts/bindings/sensor/st,lps22df-common.yaml +++ b/dts/bindings/sensor/st,lps22df-common.yaml @@ -3,10 +3,10 @@ description: | When setting the odr, lpf, avg properties in a .dts or .dtsi file - you may include st_lps22df.h and use the macros defined there. + you may include lps22df.h and use the macros defined there. Example: - #include + #include lps22df@5d { ... diff --git a/dts/bindings/sensor/st,lps22hh-common.yaml b/dts/bindings/sensor/st,lps22hh-common.yaml index eeeffe25f96..a5e27c30b30 100644 --- a/dts/bindings/sensor/st,lps22hh-common.yaml +++ b/dts/bindings/sensor/st,lps22hh-common.yaml @@ -3,10 +3,10 @@ description: | When setting the odr property in a .dts or .dtsi file you may include - st_lps22hh.h and use the macros defined there. + lps22hh.h and use the macros defined there. Example: - #include + #include lps22hh: lps22hh@0 { ... diff --git a/dts/bindings/sensor/st,lsm6dso-common.yaml b/dts/bindings/sensor/st,lsm6dso-common.yaml index 0b4b17df720..fe1c4d90ab1 100644 --- a/dts/bindings/sensor/st,lsm6dso-common.yaml +++ b/dts/bindings/sensor/st,lsm6dso-common.yaml @@ -3,11 +3,11 @@ description: | When setting the accel-pm, accel-range, accel-odr, gyro-pm, gyro-range, - gyro-odr properties in a .dts or .dtsi file you may include st_lsm6dso.h + gyro-odr properties in a .dts or .dtsi file you may include lsm6dso.h and use the macros defined there. Example: - #include + #include lsm6dso: lsm6dso@0 { ... diff --git a/dts/bindings/sensor/st,lsm6dso16is-common.yaml b/dts/bindings/sensor/st,lsm6dso16is-common.yaml index 49f7fd187fb..07c1f21adef 100644 --- a/dts/bindings/sensor/st,lsm6dso16is-common.yaml +++ b/dts/bindings/sensor/st,lsm6dso16is-common.yaml @@ -3,11 +3,11 @@ description: | When setting the accel-range, accel-odr, gyro-range, gyro-odr properties in - a .dts or .dtsi file you may include st_lsm6dso16is.h and use the macros + a .dts or .dtsi file you may include lsm6dso16is.h and use the macros defined there. Example: - #include + #include lsm6dso16is: lsm6dso16is@0 { ... diff --git a/dts/bindings/sensor/st,lsm6dsv16x-common.yaml b/dts/bindings/sensor/st,lsm6dsv16x-common.yaml index 99167a6506d..420c1d728c4 100644 --- a/dts/bindings/sensor/st,lsm6dsv16x-common.yaml +++ b/dts/bindings/sensor/st,lsm6dsv16x-common.yaml @@ -3,11 +3,11 @@ description: | When setting the accel-range, accel-odr, gyro-range, gyro-odr properties in - a .dts or .dtsi file you may include st_lsm6dsv16x.h and use the macros + a .dts or .dtsi file you may include lsm6dsv16x.h and use the macros defined there. Example: - #include + #include lsm6dsv16x: lsm6dsv16x@0 { ... From a877bb50010ca230c34aff0f4e5767264e22d8ee Mon Sep 17 00:00:00 2001 From: Dawid Niedzwiecki Date: Tue, 21 Nov 2023 12:46:45 +0100 Subject: [PATCH 0100/3723] timer: cortex_m_systick: add idle timer dependency Allow enabling the Cortex-m idle timer only if power management is set. It doesn't make sense to use an idle timer without PM. It allows adding the idle timer chosen node to dts without enabling the idle timer by default. Now, the PM config has to be set as well. Signed-off-by: Dawid Niedzwiecki --- drivers/timer/Kconfig.cortex_m_systick | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/timer/Kconfig.cortex_m_systick b/drivers/timer/Kconfig.cortex_m_systick index baf1f6c817e..2a4f48832cf 100644 --- a/drivers/timer/Kconfig.cortex_m_systick +++ b/drivers/timer/Kconfig.cortex_m_systick @@ -48,6 +48,7 @@ config CORTEX_M_SYSTICK_IDLE_TIMER default $(dt_chosen_enabled,$(DT_CHOSEN_IDLE_TIMER)) depends on COUNTER depends on TICKLESS_KERNEL + depends on PM help There are chips e.g. STMFX family that use SysTick as a system timer, but SysTick is not clocked in low power mode. These chips usually have From 3387c57a9448c144d08d643ebc4821ff21c01713 Mon Sep 17 00:00:00 2001 From: Dawid Niedzwiecki Date: Tue, 21 Nov 2023 12:55:11 +0100 Subject: [PATCH 0101/3723] dts: stm32f4: set RTC as idle timer by default Only RTC can be used as the idle timer for cortex-m systick. Set the chosen node as RTC by default. The idle timer will be enabled only if PM management is set. Signed-off-by: Dawid Niedzwiecki --- dts/arm/st/f4/stm32f4.dtsi | 1 + 1 file changed, 1 insertion(+) diff --git a/dts/arm/st/f4/stm32f4.dtsi b/dts/arm/st/f4/stm32f4.dtsi index f53c9cdf228..4a03abd609b 100644 --- a/dts/arm/st/f4/stm32f4.dtsi +++ b/dts/arm/st/f4/stm32f4.dtsi @@ -22,6 +22,7 @@ / { chosen { zephyr,flash-controller = &flash; + zephyr,cortex-m-idle-timer = &rtc; }; cpus { From 3f1024b93f687266524898399e03e74d3ebc3bc5 Mon Sep 17 00:00:00 2001 From: ingram weeks Date: Tue, 31 Oct 2023 12:24:52 +0000 Subject: [PATCH 0102/3723] doc: README.rst added to subsys/console/echo sample README added to the console echo sample Signed-off-by: ingram weeks --- samples/subsys/console/echo/README.rst | 43 ++++++++++++++++++++++++++ 1 file changed, 43 insertions(+) create mode 100644 samples/subsys/console/echo/README.rst diff --git a/samples/subsys/console/echo/README.rst b/samples/subsys/console/echo/README.rst new file mode 100644 index 00000000000..b5851f16265 --- /dev/null +++ b/samples/subsys/console/echo/README.rst @@ -0,0 +1,43 @@ +.. zephyr:code-sample:: console_echo + :name: Console echo + :relevant-api: console_api + + Echo an input character back to the output using the Console API. + +Overview +******** + +This example shows how the :c:func:`console_getchar` and +:c:func:`console_putchar` functions can be used to echo an input character +back to the console. + +Requirements +************ + +UART console is required to run this sample. + +Building and Running +******************** + +Build and flash the sample as follows, changing ``nucleo_f401re`` for your +board. Alternatively you can run this using QEMU, as described in +:zephyr:code-sample:`console_getchar`. + +.. zephyr-app-commands:: + :zephyr-app: samples/subsys/console/echo + :host-os: unix + :board: nucleo_f401re + :goals: build flash + :compact: + +Following the initial prompt given by the firmware, start pressing keys on a +keyboard, and they will be echoed back to the terminal program you are using. + +Sample Output +============= + +.. code-block:: console + + You should see another line with instructions below. If not, + the (interrupt-driven) console device doesn't work as expected: + Start typing characters to see them echoed back From 6718a21b56b9e85e9d696a8f60029e7a97a6239e Mon Sep 17 00:00:00 2001 From: ingram weeks Date: Thu, 2 Nov 2023 11:49:58 +0000 Subject: [PATCH 0103/3723] doc: console_api group added to doxygen console.h modified to include console api in doxygen Signed-off-by: ingram weeks --- include/zephyr/console/console.h | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/include/zephyr/console/console.h b/include/zephyr/console/console.h index 9ce09c081de..fbecfdad0d3 100644 --- a/include/zephyr/console/console.h +++ b/include/zephyr/console/console.h @@ -15,6 +15,13 @@ extern "C" { #endif +/** + * @brief Console API + * @defgroup console_api Console API + * @ingroup os_services + * @{ + */ + /** @brief Initialize console device. * * This function should be called once to initialize pull-style @@ -107,4 +114,8 @@ char *console_getline(void); } #endif +/** + * @} + */ + #endif /* ZEPHYR_INCLUDE_CONSOLE_CONSOLE_H_ */ From 45a5cedfd6a0d647f6976547e3868a00b1d83269 Mon Sep 17 00:00:00 2001 From: ingram weeks Date: Mon, 6 Nov 2023 14:37:58 +0000 Subject: [PATCH 0104/3723] doc: Console.rst added to os_services docs Barebones Console.rst added to os_services docs Signed-off-by: ingram weeks --- doc/services/console.rst | 6 ++++++ doc/services/index.rst | 1 + 2 files changed, 7 insertions(+) create mode 100644 doc/services/console.rst diff --git a/doc/services/console.rst b/doc/services/console.rst new file mode 100644 index 00000000000..05e506bb14a --- /dev/null +++ b/doc/services/console.rst @@ -0,0 +1,6 @@ +.. _console: + +Console +####### + +.. doxygengroup:: console_api diff --git a/doc/services/index.rst b/doc/services/index.rst index c9055e8081f..9e4dc3c98dc 100644 --- a/doc/services/index.rst +++ b/doc/services/index.rst @@ -8,6 +8,7 @@ OS Services binary_descriptors/index.rst + console.rst crypto/index debugging/index.rst device_mgmt/index From 8ec1b5487e464514e05d9dc2b678bc865fcee4a2 Mon Sep 17 00:00:00 2001 From: Fabio Baltieri Date: Thu, 9 Nov 2023 15:48:28 +0000 Subject: [PATCH 0105/3723] input: gpio_kbd_matrix: add column drive mode Add an option to drive inactive columns to inactive state rather than high impedance. This is useful if the matrix has isolation diodes for every key, as it allows the matrix to stabilize faster and the API for changing the pin value is more efficient than the one to change the pin configuration. Signed-off-by: Fabio Baltieri --- drivers/input/input_gpio_kbd_matrix.c | 12 ++++++++++-- dts/bindings/input/gpio-kbd-matrix.yaml | 11 +++++++++-- 2 files changed, 19 insertions(+), 4 deletions(-) diff --git a/drivers/input/input_gpio_kbd_matrix.c b/drivers/input/input_gpio_kbd_matrix.c index f81a01837f9..f7310d37b65 100644 --- a/drivers/input/input_gpio_kbd_matrix.c +++ b/drivers/input/input_gpio_kbd_matrix.c @@ -24,6 +24,7 @@ struct gpio_kbd_matrix_config { const struct gpio_dt_spec *col_gpio; struct gpio_callback *gpio_cb; gpio_callback_handler_t handler; + bool col_drive_inactive; }; struct gpio_kbd_matrix_data { @@ -53,7 +54,9 @@ static void gpio_kbd_matrix_drive_column(const struct device *dev, int col) const struct gpio_dt_spec *gpio = &cfg->col_gpio[i]; if ((data->last_col_state ^ state) & BIT(i)) { - if (state & BIT(i)) { + if (cfg->col_drive_inactive) { + gpio_pin_set_dt(gpio, state & BIT(i)); + } else if (state & BIT(i)) { gpio_pin_configure_dt(gpio, GPIO_OUTPUT_ACTIVE); } else { gpio_pin_configure_dt(gpio, GPIO_INPUT); @@ -114,7 +117,11 @@ static int gpio_kbd_matrix_init(const struct device *dev) return -ENODEV; } - ret = gpio_pin_configure_dt(gpio, GPIO_INPUT); + if (cfg->col_drive_inactive) { + ret = gpio_pin_configure_dt(gpio, GPIO_OUTPUT_INACTIVE); + } else { + ret = gpio_pin_configure_dt(gpio, GPIO_INPUT); + } if (ret != 0) { LOG_ERR("Pin %d configuration failed: %d", i, ret); return ret; @@ -186,6 +193,7 @@ static const struct input_kbd_matrix_api gpio_kbd_matrix_api = { .col_gpio = gpio_kbd_matrix_col_gpio_##n, \ .gpio_cb = gpio_kbd_matrix_gpio_cb_##n, \ .handler = gpio_kbd_matrix_cb_##n, \ + .col_drive_inactive = DT_INST_PROP(n, col_drive_inactive), \ }; \ \ static struct gpio_kbd_matrix_data gpio_kbd_matrix_data_##n; \ diff --git a/dts/bindings/input/gpio-kbd-matrix.yaml b/dts/bindings/input/gpio-kbd-matrix.yaml index ef08ebaa44e..7cdc07dd4dd 100644 --- a/dts/bindings/input/gpio-kbd-matrix.yaml +++ b/dts/bindings/input/gpio-kbd-matrix.yaml @@ -39,5 +39,12 @@ properties: required: true description: | GPIO for the keyboard matrix columns, supports up to 32 different GPIOs. - The pins will be driven according to the GPIO_ACTIVE_HIGH or - GPIO_ACTIVE_LOW flags when selected, high impedance when not selected. + When unselected, this pin will be either driven to inactive state or + configured to high impedance (input) depending on the col-drive-inactive + property. + + col-drive-inactive: + type: boolean + description: | + If enabled, unselected column GPIOs will be driven to inactive state. + Default to configure unselected column GPIOs to high impedance. From 6cd72493ff2235b3f9f560d3f6e58a0068c1ffdd Mon Sep 17 00:00:00 2001 From: Fabio Baltieri Date: Thu, 9 Nov 2023 10:12:59 +0000 Subject: [PATCH 0106/3723] input: gpio_kbd_matrix: add direct access support When the matrix is connected to consecutive pins on the same port, it's possible to read the whole row or set the whole column in a single operation. For the column, this is only possible if the matrix is configured for driving unselected column, as there's no API to configure multiple pins at the same time at the moment. This is more efficient than checking the pins individually, and it's particularly useful if the row or columns are driven from a GPIO port expander. Add some code to detect the condition and enable it automatically as long as the hw configuration supports it. Signed-off-by: Fabio Baltieri --- drivers/input/input_gpio_kbd_matrix.c | 53 +++++++++++++++++++++++++++ 1 file changed, 53 insertions(+) diff --git a/drivers/input/input_gpio_kbd_matrix.c b/drivers/input/input_gpio_kbd_matrix.c index f7310d37b65..3d8cc2a3104 100644 --- a/drivers/input/input_gpio_kbd_matrix.c +++ b/drivers/input/input_gpio_kbd_matrix.c @@ -30,6 +30,8 @@ struct gpio_kbd_matrix_config { struct gpio_kbd_matrix_data { struct input_kbd_matrix_common_data common; uint32_t last_col_state; + bool direct_read; + bool direct_write; }; INPUT_KBD_STRUCT_CHECK(struct gpio_kbd_matrix_config, @@ -50,6 +52,19 @@ static void gpio_kbd_matrix_drive_column(const struct device *dev, int col) state = BIT(col); } + if (data->direct_write) { + const struct gpio_dt_spec *gpio0 = &cfg->col_gpio[0]; + gpio_port_pins_t gpio_mask; + gpio_port_value_t gpio_val; + + gpio_mask = BIT_MASK(common->col_size) << gpio0->pin; + gpio_val = state << gpio0->pin; + + gpio_port_set_masked(gpio0->port, gpio_mask, gpio_val); + + return; + } + for (int i = 0; i < common->col_size; i++) { const struct gpio_dt_spec *gpio = &cfg->col_gpio[i]; @@ -71,8 +86,18 @@ static kbd_row_t gpio_kbd_matrix_read_row(const struct device *dev) { const struct gpio_kbd_matrix_config *cfg = dev->config; const struct input_kbd_matrix_common_config *common = &cfg->common; + struct gpio_kbd_matrix_data *data = dev->data; int val = 0; + if (data->direct_read) { + const struct gpio_dt_spec *gpio0 = &cfg->row_gpio[0]; + gpio_port_value_t gpio_val; + + gpio_port_get(gpio0->port, &gpio_val); + + return (gpio_val >> gpio0->pin) & BIT_MASK(common->row_size); + } + for (int i = 0; i < common->row_size; i++) { const struct gpio_dt_spec *gpio = &cfg->row_gpio[i]; @@ -102,10 +127,27 @@ static void gpio_kbd_matrix_set_detect_mode(const struct device *dev, bool enabl } } +static bool gpio_kbd_matrix_is_gpio_coherent( + const struct gpio_dt_spec *gpio, int gpio_count) +{ + const struct gpio_dt_spec *gpio0 = &gpio[0]; + + for (int i = 1; i < gpio_count; i++) { + if (gpio[i].port != gpio0->port || + gpio[i].dt_flags != gpio0->dt_flags || + gpio[i].pin != gpio0->pin + i) { + return false; + } + } + + return true; +} + static int gpio_kbd_matrix_init(const struct device *dev) { const struct gpio_kbd_matrix_config *cfg = dev->config; const struct input_kbd_matrix_common_config *common = &cfg->common; + struct gpio_kbd_matrix_data *data = dev->data; int ret; int i; @@ -152,6 +194,17 @@ static int gpio_kbd_matrix_init(const struct device *dev) } } + data->direct_read = gpio_kbd_matrix_is_gpio_coherent( + cfg->row_gpio, common->row_size); + + if (cfg->col_drive_inactive) { + data->direct_write = gpio_kbd_matrix_is_gpio_coherent( + cfg->col_gpio, common->col_size); + } + + LOG_DBG("direct_read: %d direct_write: %d", + data->direct_read, data->direct_write); + gpio_kbd_matrix_set_detect_mode(dev, true); return input_kbd_matrix_common_init(dev); From ea887af0aa112b1e707be84a299788a789b0c129 Mon Sep 17 00:00:00 2001 From: Fabio Baltieri Date: Mon, 20 Nov 2023 16:18:37 +0000 Subject: [PATCH 0107/3723] input: gpio_kbd_matrix: drop redundant gpio_kbd_matrix_set_detect_mode This is called already as soon as the polling thread starts, so the call in the gpio init function is harmless but redundant, drop it. Signed-off-by: Fabio Baltieri --- drivers/input/input_gpio_kbd_matrix.c | 2 -- 1 file changed, 2 deletions(-) diff --git a/drivers/input/input_gpio_kbd_matrix.c b/drivers/input/input_gpio_kbd_matrix.c index 3d8cc2a3104..2c0d22bbaaa 100644 --- a/drivers/input/input_gpio_kbd_matrix.c +++ b/drivers/input/input_gpio_kbd_matrix.c @@ -205,8 +205,6 @@ static int gpio_kbd_matrix_init(const struct device *dev) LOG_DBG("direct_read: %d direct_write: %d", data->direct_read, data->direct_write); - gpio_kbd_matrix_set_detect_mode(dev, true); - return input_kbd_matrix_common_init(dev); } From 1ab08634f2799556e924cc8c7f70a60cd292ed4e Mon Sep 17 00:00:00 2001 From: Kamil Piszczek Date: Tue, 7 Nov 2023 12:27:25 +0100 Subject: [PATCH 0108/3723] settings: nvs: improve the name ID metadata handling on delete operation Improved the updates to the name ID metadata (NVS_NAMECNT_ID) item in the Settings NVS backend implementation. The improvements should make the implementation more robust in handling edge cases such as: power downs, resets or a case in which the storage partition is full. In the last case, the NVS backend could return an ENOSPC error in the context of the settings_delete API. This change also fixes this issue. Signed-off-by: Kamil Piszczek --- subsys/settings/src/settings_nvs.c | 59 ++++++++++++++++++------------ 1 file changed, 35 insertions(+), 24 deletions(-) diff --git a/subsys/settings/src/settings_nvs.c b/subsys/settings/src/settings_nvs.c index 8e5bfbf3767..f1e53bfad22 100644 --- a/subsys/settings/src/settings_nvs.c +++ b/subsys/settings/src/settings_nvs.c @@ -147,6 +147,17 @@ static int settings_nvs_load(struct settings_store *cs, &buf, sizeof(buf)); if ((rc1 <= 0) && (rc2 <= 0)) { + /* Settings largest ID in use is invalid due to + * reset, power failure or partition overflow. + * Decrement it and check the next ID in subsequent + * iteration. + */ + if (name_id == cf->last_name_id) { + cf->last_name_id--; + nvs_write(&cf->cf_nvs, NVS_NAMECNT_ID, + &cf->last_name_id, sizeof(uint16_t)); + } + continue; } @@ -156,13 +167,15 @@ static int settings_nvs_load(struct settings_store *cs, * or deleted. Clean dirty entries to make space for * future settings item. */ + nvs_delete(&cf->cf_nvs, name_id); + nvs_delete(&cf->cf_nvs, name_id + NVS_NAME_ID_OFFSET); + if (name_id == cf->last_name_id) { cf->last_name_id--; nvs_write(&cf->cf_nvs, NVS_NAMECNT_ID, &cf->last_name_id, sizeof(uint16_t)); } - nvs_delete(&cf->cf_nvs, name_id); - nvs_delete(&cf->cf_nvs, name_id + NVS_NAME_ID_OFFSET); + continue; } @@ -254,6 +267,16 @@ static int settings_nvs_save(struct settings_store *cs, const char *name, return 0; } + rc = nvs_delete(&cf->cf_nvs, name_id); + if (rc >= 0) { + rc = nvs_delete(&cf->cf_nvs, name_id + + NVS_NAME_ID_OFFSET); + } + + if (rc < 0) { + return rc; + } + if (name_id == cf->last_name_id) { cf->last_name_id--; rc = nvs_write(&cf->cf_nvs, NVS_NAMECNT_ID, @@ -266,17 +289,6 @@ static int settings_nvs_save(struct settings_store *cs, const char *name, } } - rc = nvs_delete(&cf->cf_nvs, name_id); - - if (rc >= 0) { - rc = nvs_delete(&cf->cf_nvs, name_id + - NVS_NAME_ID_OFFSET); - } - - if (rc < 0) { - return rc; - } - return 0; } @@ -285,6 +297,16 @@ static int settings_nvs_save(struct settings_store *cs, const char *name, return -ENOMEM; } + /* update the last_name_id and write to flash if required*/ + if (write_name_id > cf->last_name_id) { + cf->last_name_id = write_name_id; + rc = nvs_write(&cf->cf_nvs, NVS_NAMECNT_ID, &cf->last_name_id, + sizeof(uint16_t)); + if (rc < 0) { + return rc; + } + } + /* write the value */ rc = nvs_write(&cf->cf_nvs, write_name_id + NVS_NAME_ID_OFFSET, value, val_len); @@ -300,17 +322,6 @@ static int settings_nvs_save(struct settings_store *cs, const char *name, } } - /* update the last_name_id and write to flash if required*/ - if (write_name_id > cf->last_name_id) { - cf->last_name_id = write_name_id; - rc = nvs_write(&cf->cf_nvs, NVS_NAMECNT_ID, &cf->last_name_id, - sizeof(uint16_t)); - } - - if (rc < 0) { - return rc; - } - return 0; } From 46bbe052d370dde2795107da28bf29890df6b013 Mon Sep 17 00:00:00 2001 From: Jerzy Kasenberg Date: Fri, 27 Oct 2023 13:01:50 +0200 Subject: [PATCH 0109/3723] drivers: regulator: add LDO/DCDC support for Smartbond. This add regulator driver for Smartbond DA1469X SOC. Driver can control VDD, V14, V18, V18P, V30 rails, full voltage range supported by SOC is covered. For VDD, V14, V18, V18P DCDC can be configured. Special VDD_CLAMP (always on) and VDD_SLEPP are added to allow configuration of VDD in sleep modes. Signed-off-by: Jerzy Kasenberg --- drivers/regulator/CMakeLists.txt | 1 + drivers/regulator/Kconfig | 1 + drivers/regulator/Kconfig.da1469x | 16 + drivers/regulator/regulator_da1469x.c | 415 ++++++++++++++++++ dts/arm/renesas/smartbond/da1469x.dtsi | 46 ++ .../regulator/renesas,da1469x-regulator.yaml | 46 ++ 6 files changed, 525 insertions(+) create mode 100644 drivers/regulator/Kconfig.da1469x create mode 100644 drivers/regulator/regulator_da1469x.c create mode 100644 dts/bindings/regulator/renesas,da1469x-regulator.yaml diff --git a/drivers/regulator/CMakeLists.txt b/drivers/regulator/CMakeLists.txt index 94c3a032aff..c7612fa2067 100644 --- a/drivers/regulator/CMakeLists.txt +++ b/drivers/regulator/CMakeLists.txt @@ -6,6 +6,7 @@ zephyr_library() zephyr_library_sources(regulator_common.c) zephyr_library_sources_ifdef(CONFIG_REGULATOR_AXP192 regulator_axp192.c) zephyr_library_sources_ifdef(CONFIG_REGULATOR_ADP5360 regulator_adp5360.c) +zephyr_library_sources_ifdef(CONFIG_REGULATOR_DA1469X regulator_da1469x.c) zephyr_library_sources_ifdef(CONFIG_REGULATOR_FAKE regulator_fake.c) zephyr_library_sources_ifdef(CONFIG_REGULATOR_FIXED regulator_fixed.c) zephyr_library_sources_ifdef(CONFIG_REGULATOR_GPIO regulator_gpio.c) diff --git a/drivers/regulator/Kconfig b/drivers/regulator/Kconfig index c35ae389669..754ba31783e 100644 --- a/drivers/regulator/Kconfig +++ b/drivers/regulator/Kconfig @@ -28,6 +28,7 @@ source "subsys/logging/Kconfig.template.log_config" source "drivers/regulator/Kconfig.axp192" source "drivers/regulator/Kconfig.adp5360" +source "drivers/regulator/Kconfig.da1469x" source "drivers/regulator/Kconfig.fake" source "drivers/regulator/Kconfig.fixed" source "drivers/regulator/Kconfig.gpio" diff --git a/drivers/regulator/Kconfig.da1469x b/drivers/regulator/Kconfig.da1469x new file mode 100644 index 00000000000..d8205ed4925 --- /dev/null +++ b/drivers/regulator/Kconfig.da1469x @@ -0,0 +1,16 @@ +# Copyright 2023 Renesas Electronics Corporation +# SPDX-License-Identifier: Apache-2.0 + +config REGULATOR_DA1469X + bool "DA1469X regulators driver" + default y + depends on DT_HAS_RENESAS_SMARTBOND_REGULATOR_ENABLED + help + Enable support for the Smartbond DA1469x regulators. + +config REGULATOR_DA1469X_INIT_PRIORITY + int "Renesas DA1469x regulators driver init priority" + default KERNEL_INIT_PRIORITY_DEVICE + depends on REGULATOR_DA1469X + help + Init priority for the Renesas DA1469x regulators driver. diff --git a/drivers/regulator/regulator_da1469x.c b/drivers/regulator/regulator_da1469x.c new file mode 100644 index 00000000000..36d8fe1d35f --- /dev/null +++ b/drivers/regulator/regulator_da1469x.c @@ -0,0 +1,415 @@ +/* + * Copyright 2023 Renesas Electronics Corporation + * SPDX-License-Identifier: Apache-2.0 + */ + +#define DT_DRV_COMPAT renesas_smartbond_regulator + +#include + +#include +#include +#include +#include + +LOG_MODULE_REGISTER(regulator_da1469x, CONFIG_REGULATOR_LOG_LEVEL); + +#define DCDC_REQUESTED (DCDC_DCDC_VDD_REG_DCDC_VDD_ENABLE_HV_Msk |\ + DCDC_DCDC_VDD_REG_DCDC_VDD_ENABLE_LV_Msk) + +#define DA1469X_LDO_3V0_MODE_VBAT BIT(8) +#define DA1469X_LDO_3V0_MODE_VBUS BIT(9) + +static const struct linear_range curren_ranges[] = { + LINEAR_RANGE_INIT(30000, 30000, 0, 31), +}; + +static const struct linear_range vdd_clamp_ranges[] = { + LINEAR_RANGE_INIT(706000, 0, 15, 15), + LINEAR_RANGE_INIT(798000, 0, 14, 14), + LINEAR_RANGE_INIT(828000, 0, 13, 13), + LINEAR_RANGE_INIT(861000, 0, 11, 11), + LINEAR_RANGE_INIT(862000, 0, 12, 12), + LINEAR_RANGE_INIT(889000, 0, 10, 10), + LINEAR_RANGE_INIT(918000, 0, 9, 9), + LINEAR_RANGE_INIT(946000, 0, 3, 3), + LINEAR_RANGE_INIT(952000, 0, 8, 8), + LINEAR_RANGE_INIT(978000, 0, 2, 2), + LINEAR_RANGE_INIT(1005000, 0, 1, 1), + LINEAR_RANGE_INIT(1030000, 0, 7, 7), + LINEAR_RANGE_INIT(1037000, 0, 0, 0), + LINEAR_RANGE_INIT(1058000, 0, 6, 6), + LINEAR_RANGE_INIT(1089000, 0, 5, 5), + LINEAR_RANGE_INIT(1120000, 0, 4, 4), +}; + +static const struct linear_range vdd_ranges[] = { + LINEAR_RANGE_INIT(900000, 100000, 0, 3), +}; + +static const struct linear_range vdd_sleep_ranges[] = { + LINEAR_RANGE_INIT(750000, 50000, 0, 3), +}; + +static const struct linear_range v14_ranges[] = { + LINEAR_RANGE_INIT(1200000, 50000, 0, 7), +}; + +static const struct linear_range v30_ranges[] = { + LINEAR_RANGE_INIT(3000000, 300000, 0, 1), +}; + +static const struct linear_range v18_ranges[] = { + LINEAR_RANGE_INIT(1200000, 600000, 0, 1), +}; + +static const struct linear_range v18p_ranges[] = { + LINEAR_RANGE_INIT(1800000, 0, 0, 0), +}; + +enum da1469x_rail { + VDD_CLAMP, + VDD_SLEEP, + VDD, + V14, + V18, + V18P, + V30, +}; + +struct regulator_da1469x_desc { + const struct linear_range *voltage_ranges; + const struct linear_range *current_ranges; + uint8_t voltage_range_count; + /* Bit from POWER_CTRL_REG that can be used for enabling rail */ + uint32_t enable_mask; + uint32_t voltage_idx_mask; + volatile uint32_t *dcdc_register; +}; + +static const struct regulator_da1469x_desc vdd_desc = { + .voltage_ranges = vdd_ranges, + .current_ranges = curren_ranges, + .voltage_range_count = ARRAY_SIZE(vdd_ranges), + .enable_mask = CRG_TOP_POWER_CTRL_REG_LDO_CORE_ENABLE_Msk, + .voltage_idx_mask = CRG_TOP_POWER_CTRL_REG_VDD_LEVEL_Msk, + .dcdc_register = &DCDC->DCDC_VDD_REG, +}; + +static const struct regulator_da1469x_desc vdd_sleep_desc = { + .voltage_ranges = vdd_sleep_ranges, + .voltage_range_count = ARRAY_SIZE(vdd_sleep_ranges), + .enable_mask = CRG_TOP_POWER_CTRL_REG_LDO_CORE_RET_ENABLE_SLEEP_Msk, + .voltage_idx_mask = CRG_TOP_POWER_CTRL_REG_VDD_SLEEP_LEVEL_Msk, +}; + +static const struct regulator_da1469x_desc vdd_clamp_desc = { + .voltage_ranges = vdd_clamp_ranges, + .voltage_range_count = ARRAY_SIZE(vdd_clamp_ranges), + .enable_mask = 0, + .voltage_idx_mask = CRG_TOP_POWER_CTRL_REG_VDD_CLAMP_LEVEL_Msk, +}; + +static const struct regulator_da1469x_desc v14_desc = { + .voltage_ranges = v14_ranges, + .current_ranges = curren_ranges, + .voltage_range_count = ARRAY_SIZE(v14_ranges), + .enable_mask = CRG_TOP_POWER_CTRL_REG_LDO_RADIO_ENABLE_Msk, + .voltage_idx_mask = CRG_TOP_POWER_CTRL_REG_V14_LEVEL_Msk, + .dcdc_register = &DCDC->DCDC_V14_REG, +}; + +static const struct regulator_da1469x_desc v18_desc = { + .voltage_ranges = v18_ranges, + .current_ranges = curren_ranges, + .voltage_range_count = ARRAY_SIZE(v18_ranges), + .enable_mask = CRG_TOP_POWER_CTRL_REG_LDO_1V8_ENABLE_Msk | + CRG_TOP_POWER_CTRL_REG_LDO_1V8_RET_ENABLE_SLEEP_Msk, + .voltage_idx_mask = CRG_TOP_POWER_CTRL_REG_V18_LEVEL_Msk, + .dcdc_register = &DCDC->DCDC_V18_REG, +}; + +static const struct regulator_da1469x_desc v18p_desc = { + .voltage_ranges = v18p_ranges, + .current_ranges = curren_ranges, + .voltage_range_count = ARRAY_SIZE(v18p_ranges), + .enable_mask = CRG_TOP_POWER_CTRL_REG_LDO_1V8P_ENABLE_Msk | + CRG_TOP_POWER_CTRL_REG_LDO_1V8P_RET_ENABLE_SLEEP_Msk, + .voltage_idx_mask = 0, + .dcdc_register = &DCDC->DCDC_V18P_REG, +}; + +static const struct regulator_da1469x_desc v30_desc = { + .voltage_ranges = v30_ranges, + .voltage_range_count = ARRAY_SIZE(v30_ranges), + .enable_mask = CRG_TOP_POWER_CTRL_REG_LDO_3V0_RET_ENABLE_SLEEP_Msk | + CRG_TOP_POWER_CTRL_REG_LDO_3V0_MODE_Msk, + .voltage_idx_mask = CRG_TOP_POWER_CTRL_REG_V30_LEVEL_Msk, +}; + +#define DA1469X_LDO_VDD_CLAMP_RET 0 +#define DA1469X_LDO_VDD_SLEEP_RET 0 +#define DA1469X_LDO_VDD_RET CRG_TOP_POWER_CTRL_REG_LDO_CORE_RET_ENABLE_SLEEP_Msk +#define DA1469X_LDO_V14_RET 0 +#define DA1469X_LDO_V18_RET CRG_TOP_POWER_CTRL_REG_LDO_1V8_RET_ENABLE_SLEEP_Msk +#define DA1469X_LDO_V18P_RET CRG_TOP_POWER_CTRL_REG_LDO_1V8P_RET_ENABLE_SLEEP_Msk +#define DA1469X_LDO_V30_RET CRG_TOP_POWER_CTRL_REG_LDO_3V0_RET_ENABLE_SLEEP_Msk + +struct regulator_da1469x_config { + struct regulator_common_config common; + enum da1469x_rail rail; + const struct regulator_da1469x_desc *desc; + uint32_t power_bits; + uint32_t dcdc_bits; +}; + +struct regulator_da1469x_data { + struct regulator_common_data common; +}; + +static int regulator_da1469x_enable(const struct device *dev) +{ + const struct regulator_da1469x_config *config = dev->config; + uint32_t reg_val; + + if (config->desc->enable_mask & config->power_bits) { + reg_val = CRG_TOP->POWER_CTRL_REG & ~(config->desc->enable_mask); + reg_val |= config->power_bits & config->desc->enable_mask; + CRG_TOP->POWER_CTRL_REG |= reg_val; + } + + if (config->desc->dcdc_register) { + reg_val = *config->desc->dcdc_register & + ~(DCDC_DCDC_V14_REG_DCDC_V14_ENABLE_HV_Msk | + DCDC_DCDC_V14_REG_DCDC_V14_ENABLE_LV_Msk); + reg_val |= config->dcdc_bits; + *config->desc->dcdc_register = reg_val; + } + + /* + * Enable DCDC if: + * 1. it was not already enabled, and + * 2. VBAT is above minimal value + * 3. Just turned on rail requested DCDC + */ + if (((DCDC->DCDC_CTRL1_REG & DCDC_DCDC_CTRL1_REG_DCDC_ENABLE_Msk) == 0) && + (CRG_TOP->ANA_STATUS_REG & CRG_TOP_ANA_STATUS_REG_COMP_VBAT_HIGH_Msk) && + config->dcdc_bits & DCDC_REQUESTED) { + DCDC->DCDC_CTRL1_REG |= DCDC_DCDC_CTRL1_REG_DCDC_ENABLE_Msk; + } + + return 0; +} + +static int regulator_da1469x_disable(const struct device *dev) +{ + const struct regulator_da1469x_config *config = dev->config; + uint32_t reg_val; + + if (config->desc->enable_mask & config->power_bits) { + CRG_TOP->POWER_CTRL_REG &= ~(config->desc->enable_mask & + config->power_bits); + } + if (config->desc->dcdc_register) { + reg_val = *config->desc->dcdc_register & + ~(DCDC_DCDC_V14_REG_DCDC_V14_ENABLE_HV_Msk | + DCDC_DCDC_V14_REG_DCDC_V14_ENABLE_LV_Msk); + *config->desc->dcdc_register = reg_val; + } + + /* Turn off DCDC if it's no longer requested by any rail */ + if ((DCDC->DCDC_CTRL1_REG & DCDC_DCDC_CTRL1_REG_DCDC_ENABLE_Msk) && + (DCDC->DCDC_VDD_REG & DCDC_REQUESTED) == 0 && + (DCDC->DCDC_V14_REG & DCDC_REQUESTED) == 0 && + (DCDC->DCDC_V18_REG & DCDC_REQUESTED) == 0 && + (DCDC->DCDC_V18P_REG & DCDC_REQUESTED) == 0) { + DCDC->DCDC_CTRL1_REG &= ~DCDC_DCDC_CTRL1_REG_DCDC_ENABLE_Msk; + } + + return 0; +} + +static unsigned int regulator_da1469x_count_voltages(const struct device *dev) +{ + const struct regulator_da1469x_config *config = dev->config; + + return linear_range_group_values_count(config->desc->voltage_ranges, + config->desc->voltage_range_count); +} + +static int regulator_da1469x_list_voltage(const struct device *dev, + unsigned int idx, + int32_t *volt_uv) +{ + const struct regulator_da1469x_config *config = dev->config; + + if (config->desc->voltage_ranges) { + return linear_range_group_get_value(config->desc->voltage_ranges, + config->desc->voltage_range_count, + idx, volt_uv); + } + + return -ENOTSUP; +} + +static int regulator_da1469x_set_voltage(const struct device *dev, int32_t min_uv, + int32_t max_uv) +{ + int ret; + const struct regulator_da1469x_config *config = dev->config; + uint16_t idx; + uint32_t mask; + + ret = linear_range_group_get_win_index(config->desc->voltage_ranges, + config->desc->voltage_range_count, + min_uv, max_uv, &idx); + + if (ret == 0) { + mask = config->desc->voltage_idx_mask; + /* + * Mask is 0 for V18. + * Setting value 1.8V is accepted since range is valid and already checked. + */ + if (mask) { + CRG_TOP->POWER_CTRL_REG = (CRG_TOP->POWER_CTRL_REG & ~mask) | + FIELD_PREP(mask, idx); + } + } + + return ret; +} + +static int regulator_da1469x_get_voltage(const struct device *dev, + int32_t *volt_uv) +{ + const struct regulator_da1469x_config *config = dev->config; + uint16_t idx; + + if (config->desc->voltage_idx_mask) { + idx = FIELD_GET(CRG_TOP->POWER_CTRL_REG, config->desc->voltage_idx_mask); + } else { + idx = 0; + } + + return linear_range_group_get_value(config->desc->voltage_ranges, + config->desc->voltage_range_count, idx, volt_uv); +} + +static int regulator_da1469x_set_current_limit(const struct device *dev, + int32_t min_ua, int32_t max_ua) +{ + const struct regulator_da1469x_config *config = dev->config; + int ret; + uint16_t idx; + uint32_t reg_val; + + if (config->desc->current_ranges == NULL) { + return -ENOTSUP; + } + + ret = linear_range_group_get_win_index(config->desc->current_ranges, + 1, + min_ua, max_ua, &idx); + if (ret) { + return ret; + } + + /* All registers have same bits layout */ + reg_val = *config->desc->dcdc_register & ~(DCDC_DCDC_V14_REG_DCDC_V14_CUR_LIM_MAX_HV_Msk | + DCDC_DCDC_V14_REG_DCDC_V14_CUR_LIM_MAX_LV_Msk | + DCDC_DCDC_V14_REG_DCDC_V14_CUR_LIM_MIN_Msk); + reg_val |= FIELD_PREP(DCDC_DCDC_V14_REG_DCDC_V14_CUR_LIM_MAX_HV_Msk, idx); + reg_val |= FIELD_PREP(DCDC_DCDC_V14_REG_DCDC_V14_CUR_LIM_MAX_LV_Msk, idx); + reg_val |= FIELD_PREP(DCDC_DCDC_V14_REG_DCDC_V14_CUR_LIM_MIN_Msk, idx); + + *config->desc->dcdc_register = reg_val; + + return ret; +} + +static int regulator_da1469x_get_current_limit(const struct device *dev, + int32_t *curr_ua) +{ + const struct regulator_da1469x_config *config = dev->config; + int ret; + uint16_t idx; + + if (config->desc->current_ranges == NULL) { + return -ENOTSUP; + } + idx = FIELD_GET(*config->desc->dcdc_register, + DCDC_DCDC_V14_REG_DCDC_V14_CUR_LIM_MAX_HV_Msk); + ret = linear_range_group_get_value(config->desc->current_ranges, 1, idx, curr_ua); + + return ret; +} + +static const struct regulator_driver_api regulator_da1469x_api = { + .enable = regulator_da1469x_enable, + .disable = regulator_da1469x_disable, + .count_voltages = regulator_da1469x_count_voltages, + .list_voltage = regulator_da1469x_list_voltage, + .set_voltage = regulator_da1469x_set_voltage, + .get_voltage = regulator_da1469x_get_voltage, + .set_current_limit = regulator_da1469x_set_current_limit, + .get_current_limit = regulator_da1469x_get_current_limit, +}; + +static int regulator_da1469x_init(const struct device *dev) +{ + const struct regulator_da1469x_config *config = dev->config; + + regulator_common_data_init(dev); + + if ((config->rail == V30) && + (config->power_bits & CRG_TOP_POWER_CTRL_REG_LDO_3V0_REF_Msk)) { + CRG_TOP->POWER_CTRL_REG |= CRG_TOP_POWER_CTRL_REG_LDO_3V0_REF_Msk; + } + + return regulator_common_init(dev, 0); +} + +#define REGULATOR_DA1469X_DEFINE(node, id, rail_id) \ + static struct regulator_da1469x_data data_##id; \ + \ + static const struct regulator_da1469x_config config_##id = { \ + .common = REGULATOR_DT_COMMON_CONFIG_INIT(node), \ + .desc = &id ## _desc, \ + .power_bits = \ + (DT_PROP(node, renesas_regulator_v30_clamp) * \ + CRG_TOP_POWER_CTRL_REG_CLAMP_3V0_VBAT_ENABLE_Msk) | \ + (DT_PROP(node, renesas_regulator_v30_vbus) * \ + DA1469X_LDO_3V0_MODE_VBAT) | \ + (DT_PROP(node, renesas_regulator_v30_vbat) * \ + DA1469X_LDO_3V0_MODE_VBUS) | \ + (DT_PROP(node, renesas_regulator_sleep_ldo) * \ + (DA1469X_LDO_ ## rail_id ##_RET)) | \ + (DT_PROP(node, renesas_regulator_v30_ref_bandgap) * \ + CRG_TOP_POWER_CTRL_REG_LDO_3V0_REF_Msk), \ + .dcdc_bits = \ + (DT_PROP(node, renesas_regulator_dcdc_vbat_high) * \ + DCDC_DCDC_VDD_REG_DCDC_VDD_ENABLE_HV_Msk) | \ + (DT_PROP(node, renesas_regulator_dcdc_vbat_low) * \ + DCDC_DCDC_VDD_REG_DCDC_VDD_ENABLE_LV_Msk) \ + }; \ + DEVICE_DT_DEFINE(node, regulator_da1469x_init, NULL, &data_##id, \ + &config_##id, PRE_KERNEL_1, \ + CONFIG_REGULATOR_DA1469X_INIT_PRIORITY, \ + ®ulator_da1469x_api); + +#define REGULATOR_DA1469X_DEFINE_COND(inst, child, source) \ + COND_CODE_1(DT_NODE_EXISTS(DT_INST_CHILD(inst, child)), \ + (REGULATOR_DA1469X_DEFINE( \ + DT_INST_CHILD(inst, child), child, source)), \ + ()) + +#define REGULATOR_DA1469X_DEFINE_ALL(inst) \ + REGULATOR_DA1469X_DEFINE_COND(inst, vdd_clamp, VDD_CLAMP) \ + REGULATOR_DA1469X_DEFINE_COND(inst, vdd_sleep, VDD_SLEEP) \ + REGULATOR_DA1469X_DEFINE_COND(inst, vdd, VDD) \ + REGULATOR_DA1469X_DEFINE_COND(inst, v14, V14) \ + REGULATOR_DA1469X_DEFINE_COND(inst, v18, V18) \ + REGULATOR_DA1469X_DEFINE_COND(inst, v18p, V18P) \ + REGULATOR_DA1469X_DEFINE_COND(inst, v30, V30) \ + +DT_INST_FOREACH_STATUS_OKAY(REGULATOR_DA1469X_DEFINE_ALL) diff --git a/dts/arm/renesas/smartbond/da1469x.dtsi b/dts/arm/renesas/smartbond/da1469x.dtsi index 6916b2b804c..72f7e6fa89f 100644 --- a/dts/arm/renesas/smartbond/da1469x.dtsi +++ b/dts/arm/renesas/smartbond/da1469x.dtsi @@ -86,6 +86,52 @@ clock-src = <&rc32k>; status = "okay"; }; + + regulators { + compatible = "renesas,smartbond-regulator"; + vdd: VDD { + regulator-init-microvolt = <900000>; + regulator-boot-on; + renesas,regulator-sleep-ldo; + renesas,regulator-dcdc-vbat-high; + renesas,regulator-dcdc-vbat-low; + }; + vdd_clamp: VDD_CLAMP { + regulator-boot-on; + regulator-always-on; + regulator-init-microvolt = <706000>; + }; + vdd_sleep: VDD_SLEEP { + regulator-boot-on; + regulator-init-microvolt = <750000>; + }; + v14: V14 { + regulator-init-microvolt = <1400000>; + regulator-boot-on; + renesas,regulator-dcdc-vbat-high; + renesas,regulator-dcdc-vbat-low; + }; + v18: V18 { + regulator-init-microvolt = <1800000>; + regulator-boot-on; + renesas,regulator-dcdc-vbat-high; + }; + v18p: V18P { + regulator-init-microvolt = <1800000>; + regulator-boot-on; + renesas,regulator-sleep-ldo; + renesas,regulator-dcdc-vbat-high; + }; + v30: V30 { + regulator-init-microvolt = <3000000>; + regulator-boot-on; + renesas,regulator-sleep-ldo; + renesas,regulator-v30-vbus; + renesas,regulator-v30-vbat; + renesas,regulator-v30-clamp; + renesas,regulator-v30-ref-bandgap; + }; + }; }; soc { diff --git a/dts/bindings/regulator/renesas,da1469x-regulator.yaml b/dts/bindings/regulator/renesas,da1469x-regulator.yaml new file mode 100644 index 00000000000..2537b7e09d7 --- /dev/null +++ b/dts/bindings/regulator/renesas,da1469x-regulator.yaml @@ -0,0 +1,46 @@ +# Copyright (c), 2023 Renesas Electronics Corporation +# SPDX -License-Identifier: Apache-2.0 + +description: | + Renesas Smartbond(tm) LDO and DCDC regulators + +compatible: "renesas,smartbond-regulator" + +child-binding: + include: + - name: regulator.yaml + property-allowlist: + - regulator-always-on + - regulator-boot-on + - regulator-init-microvolt + - regulator-initial-mode + - regulator-max-microamp + properties: + renesas,regulator-v30-ref-bandgap: + type: boolean + description: | + Selects reference source for V30 LDO to Bandgap output. + renesas,regulator-v30-clamp: + type: boolean + description: | + Enables clamp that can supply V30 from VBAT. + renesas,regulator-v30-vbus: + type: boolean + description: | + Allow V30 to be powered from VBUS. + renesas,regulator-v30-vbat: + type: boolean + description: | + Allow V30 to be powered from VBAT. + renesas,regulator-dcdc-vbat-high: + type: boolean + description: | + Enable DCDC in high battery voltage mode. + renesas,regulator-dcdc-vbat-low: + type: boolean + description: | + Enable DCDC in low battery voltage mode. + renesas,regulator-sleep-ldo: + type: boolean + description: | + Enable LDO in sleep mode. From 4e976e0d58588366b138a5b33f42e02027ce8696 Mon Sep 17 00:00:00 2001 From: Aleksander Wasaznik Date: Thu, 16 Nov 2023 10:03:06 +0100 Subject: [PATCH 0110/3723] sys: atomic: Fix includes, create `atomic_types.h` This patch fixes the include of `atomic_builtin.h` and `atomic_arch.h` so that they are IWYU. This mean they compile correctly independent of other includes at the include-site. It was nessessary to move the definition of the atomic types out of `atomic.h` to avoid unsatifiable circular dependencies between `atomic.h` and `atomic_builtin.h`, as well as definition conflicts between `atomic_arch.h` and `atomic_builtin.h`. The definition of the type was to moved to a new file `atomic_types.h`. The include in `atomic.h` has a IWYU pragma which will preserve backwards compatibility with code expecting the types to be defined in `atomic.h` if we start linting for IWYU. Signed-off-by: Aleksander Wasaznik --- include/zephyr/sys/atomic.h | 7 ++----- include/zephyr/sys/atomic_arch.h | 4 ++++ include/zephyr/sys/atomic_builtin.h | 4 ++++ include/zephyr/sys/atomic_types.h | 24 ++++++++++++++++++++++++ 4 files changed, 34 insertions(+), 5 deletions(-) create mode 100644 include/zephyr/sys/atomic_types.h diff --git a/include/zephyr/sys/atomic.h b/include/zephyr/sys/atomic.h index bcb122bf38a..8618e1bf903 100644 --- a/include/zephyr/sys/atomic.h +++ b/include/zephyr/sys/atomic.h @@ -1,6 +1,7 @@ /* * Copyright (c) 1997-2015, Wind River Systems, Inc. * Copyright (c) 2021 Intel Corporation + * Copyright (c) 2023 Nordic Semiconductor ASA * * SPDX-License-Identifier: Apache-2.0 */ @@ -12,6 +13,7 @@ #include #include +#include /* IWYU pragma: export */ #include #include @@ -19,11 +21,6 @@ extern "C" { #endif -typedef long atomic_t; -typedef atomic_t atomic_val_t; -typedef void *atomic_ptr_t; -typedef atomic_ptr_t atomic_ptr_val_t; - /* Low-level primitives come in several styles: */ #if defined(CONFIG_ATOMIC_OPERATIONS_C) diff --git a/include/zephyr/sys/atomic_arch.h b/include/zephyr/sys/atomic_arch.h index 7305743c4fb..1225a2e0970 100644 --- a/include/zephyr/sys/atomic_arch.h +++ b/include/zephyr/sys/atomic_arch.h @@ -1,5 +1,6 @@ /* * Copyright (c) 2021 Demant A/S + * Copyright (c) 2023 Nordic Semiconductor ASA * * SPDX-License-Identifier: Apache-2.0 */ @@ -7,6 +8,9 @@ #ifndef ZEPHYR_INCLUDE_SYS_ATOMIC_ARCH_H_ #define ZEPHYR_INCLUDE_SYS_ATOMIC_ARCH_H_ +#include +#include + /* Included from */ /* Arch specific atomic primitives */ diff --git a/include/zephyr/sys/atomic_builtin.h b/include/zephyr/sys/atomic_builtin.h index 43b40e8bed4..972200c4fc6 100644 --- a/include/zephyr/sys/atomic_builtin.h +++ b/include/zephyr/sys/atomic_builtin.h @@ -2,6 +2,7 @@ /* * Copyright (c) 1997-2015, Wind River Systems, Inc. + * Copyright (c) 2023 Nordic Semiconductor ASA * * SPDX-License-Identifier: Apache-2.0 */ @@ -9,6 +10,9 @@ #ifndef ZEPHYR_INCLUDE_SYS_ATOMIC_BUILTIN_H_ #define ZEPHYR_INCLUDE_SYS_ATOMIC_BUILTIN_H_ +#include +#include + #ifdef __cplusplus extern "C" { #endif diff --git a/include/zephyr/sys/atomic_types.h b/include/zephyr/sys/atomic_types.h new file mode 100644 index 00000000000..33935971f50 --- /dev/null +++ b/include/zephyr/sys/atomic_types.h @@ -0,0 +1,24 @@ +/* Copyright (c) 1997-2015, Wind River Systems, Inc. + * Copyright (c) 2021 Intel Corporation + * Copyright (c) 2023 Nordic Semiconductor ASA + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#ifndef ZEPHYR_INCLUDE_SYS_ATOMIC_TYPES_H_ +#define ZEPHYR_INCLUDE_SYS_ATOMIC_TYPES_H_ + +#ifdef __cplusplus +extern "C" { +#endif + +typedef long atomic_t; +typedef atomic_t atomic_val_t; +typedef void *atomic_ptr_t; +typedef atomic_ptr_t atomic_ptr_val_t; + +#ifdef __cplusplus +} +#endif + +#endif /* ZEPHYR_INCLUDE_SYS_ATOMIC_TYPES_H_ */ From 589f3ad904b04fd9f4b453d6045bbcdcb3e67826 Mon Sep 17 00:00:00 2001 From: Aleksander Wasaznik Date: Wed, 23 Mar 2022 16:54:36 +0100 Subject: [PATCH 0111/3723] Bluetooth: testlib: Create `testlib/conn.h` This header file declares the functions that rely on `bluetooth/conn.h`. This collects `testlib/connect.h`, `conn_ref.h` and `conn_wait.h` into one. Initial documentation for the functions in this file is also added. Signed-off-by: Aleksander Wasaznik --- tests/bluetooth/common/testlib/CMakeLists.txt | 3 +- .../common/testlib/include/testlib/conn.h | 75 +++++++++++++++++++ .../testlib/include/testlib/conn_wait.h | 12 --- .../common/testlib/include/testlib/connect.h | 12 --- .../testlib/conn_ref.h => src/conn_ref.c} | 8 +- .../bluetooth/common/testlib/src/conn_wait.c | 2 + tests/bluetooth/common/testlib/src/connect.c | 2 +- .../bsim/bluetooth/host/att/long_read/main.c | 4 +- .../host/att/retry_on_sec_err/client/main.c | 2 +- 9 files changed, 84 insertions(+), 36 deletions(-) create mode 100644 tests/bluetooth/common/testlib/include/testlib/conn.h delete mode 100644 tests/bluetooth/common/testlib/include/testlib/conn_wait.h delete mode 100644 tests/bluetooth/common/testlib/include/testlib/connect.h rename tests/bluetooth/common/testlib/{include/testlib/conn_ref.h => src/conn_ref.c} (80%) diff --git a/tests/bluetooth/common/testlib/CMakeLists.txt b/tests/bluetooth/common/testlib/CMakeLists.txt index 7166abd3e06..91d685439c8 100644 --- a/tests/bluetooth/common/testlib/CMakeLists.txt +++ b/tests/bluetooth/common/testlib/CMakeLists.txt @@ -17,8 +17,9 @@ target_sources(testlib PRIVATE src/adv.c src/att_read.c src/att_write.c - src/connect.c + src/conn_ref.c src/conn_wait.c + src/connect.c src/scan.c src/security.c ) diff --git a/tests/bluetooth/common/testlib/include/testlib/conn.h b/tests/bluetooth/common/testlib/include/testlib/conn.h new file mode 100644 index 00000000000..9554eb7b033 --- /dev/null +++ b/tests/bluetooth/common/testlib/include/testlib/conn.h @@ -0,0 +1,75 @@ +/* Copyright (c) 2023 Nordic Semiconductor ASA + * SPDX-License-Identifier: Apache-2.0 + */ + +#ifndef ZEPHYR_TESTS_BLUETOOTH_COMMON_TESTLIB_INCLUDE_TESTLIB_CONN_H_ +#define ZEPHYR_TESTS_BLUETOOTH_COMMON_TESTLIB_INCLUDE_TESTLIB_CONN_H_ + +#include + +/** + * @brief Scan and connect using address + * + * Synchronous: Blocks until the connection procedure completes. + * Thread-safe: + * + * This is a synchronous wrapper around @ref bt_conn_le_create with + * default params. It will wait until the @ref bt_conn_cb.connected + * event and return the HCI status of the connection creation. + * + * The reference created by @ref bt_conn_le_create is put in @p connp. + * + * @note The connection reference presists if the connection procedure + * fails at a later point. @p connp is a reified reference: if it's not + * NULL, then it's a valid reference. + * + * @remark Not disposing of the connection reference in the case of + * connection failure is intentional. It's useful for comparing against + * raw @ref bt_conn_cb.connected events. + * + * @note The reference variable @p connp is required be empty (i.e. + * NULL) on entry. + * + * @param peer Peer address. + * @param[out] conn Connection reference variable. + * + * @retval 0 Connection was enstablished. + * @retval -errno @ref bt_conn_le_create error. No connection object + * reference was created. + * @retval BT_HCI_ERR HCI reason for connection failure. A connection + * object reference was created and put in @p connp. + * + */ +int bt_testlib_connect(const bt_addr_le_t *peer, struct bt_conn **connp); + +/** + * @brief Wait for connected state + * + * Thread-safe. + * + * @attention This function does not look at the history of a connection + * object. If it's already disconnected after a connection, then this + * function will wait forever. Don't use this function if you cannot + * guarantee that any disconnection event comes after this function is + * called. This is only truly safe in a simulated environment. + */ +int bt_testlib_wait_connected(struct bt_conn *conn); + +/** + * @brief Wait for disconnected state + * + * Thread-safe. + */ +int bt_testlib_wait_disconnected(struct bt_conn *conn); + +/** + * @brief Dispose of a reified connection reference + * + * Thread-safe. + * + * Atomically swaps NULL into the reference variable @p connp, then + * moves the reference into @ref bt_conn_unref. + */ +void bt_testlib_conn_unref(struct bt_conn **connp); + +#endif /* ZEPHYR_TESTS_BLUETOOTH_COMMON_TESTLIB_INCLUDE_TESTLIB_CONN_H_ */ diff --git a/tests/bluetooth/common/testlib/include/testlib/conn_wait.h b/tests/bluetooth/common/testlib/include/testlib/conn_wait.h deleted file mode 100644 index 00f8ddb5cdc..00000000000 --- a/tests/bluetooth/common/testlib/include/testlib/conn_wait.h +++ /dev/null @@ -1,12 +0,0 @@ -/* Copyright (c) 2023 Nordic Semiconductor ASA - * SPDX-License-Identifier: Apache-2.0 - */ - -#ifndef ZEPHYR_TESTS_BLUETOOTH_COMMON_TESTLIB_INCLUDE_TESTLIB_CONN_WAIT_H_ -#define ZEPHYR_TESTS_BLUETOOTH_COMMON_TESTLIB_INCLUDE_TESTLIB_CONN_WAIT_H_ -#include - -int bt_testlib_wait_connected(struct bt_conn *conn); -int bt_testlib_wait_disconnected(struct bt_conn *conn); - -#endif /* ZEPHYR_TESTS_BLUETOOTH_COMMON_TESTLIB_INCLUDE_TESTLIB_CONN_WAIT_H_ */ diff --git a/tests/bluetooth/common/testlib/include/testlib/connect.h b/tests/bluetooth/common/testlib/include/testlib/connect.h deleted file mode 100644 index 912e4d0cdc7..00000000000 --- a/tests/bluetooth/common/testlib/include/testlib/connect.h +++ /dev/null @@ -1,12 +0,0 @@ -/* Copyright (c) 2023 Nordic Semiconductor ASA - * SPDX-License-Identifier: Apache-2.0 - */ - -#ifndef ZEPHYR_TESTS_BLUETOOTH_COMMON_TESTLIB_INCLUDE_TESTLIB_CONNECT_H_ -#define ZEPHYR_TESTS_BLUETOOTH_COMMON_TESTLIB_INCLUDE_TESTLIB_CONNECT_H_ - -#include - -int bt_testlib_connect(const bt_addr_le_t *peer, struct bt_conn **conn); - -#endif /* ZEPHYR_TESTS_BLUETOOTH_COMMON_TESTLIB_INCLUDE_TESTLIB_CONNECT_H_ */ diff --git a/tests/bluetooth/common/testlib/include/testlib/conn_ref.h b/tests/bluetooth/common/testlib/src/conn_ref.c similarity index 80% rename from tests/bluetooth/common/testlib/include/testlib/conn_ref.h rename to tests/bluetooth/common/testlib/src/conn_ref.c index 9e96eb3fc40..8e26c7104dc 100644 --- a/tests/bluetooth/common/testlib/include/testlib/conn_ref.h +++ b/tests/bluetooth/common/testlib/src/conn_ref.c @@ -2,11 +2,9 @@ * SPDX-License-Identifier: Apache-2.0 */ -#ifndef ZEPHYR_TESTS_BLUETOOTH_COMMON_TESTLIB_INCLUDE_TESTLIB_CONN_REF_H_ -#define ZEPHYR_TESTS_BLUETOOTH_COMMON_TESTLIB_INCLUDE_TESTLIB_CONN_REF_H_ - +#include +#include #include -#include /** * @file @@ -38,5 +36,3 @@ void bt_testlib_conn_unref(struct bt_conn **connp) __ASSERT_NO_MSG(conn); bt_conn_unref(conn); } - -#endif /* ZEPHYR_TESTS_BLUETOOTH_COMMON_TESTLIB_INCLUDE_TESTLIB_CONN_REF_H_ */ diff --git a/tests/bluetooth/common/testlib/src/conn_wait.c b/tests/bluetooth/common/testlib/src/conn_wait.c index a99b47a0edc..fdcaa4680d4 100644 --- a/tests/bluetooth/common/testlib/src/conn_wait.c +++ b/tests/bluetooth/common/testlib/src/conn_wait.c @@ -13,6 +13,8 @@ #include #include +#include + #include LOG_MODULE_REGISTER(bt_testlib_conn_wait, LOG_LEVEL_DBG); diff --git a/tests/bluetooth/common/testlib/src/connect.c b/tests/bluetooth/common/testlib/src/connect.c index afb4b9c271d..e8f5a90224e 100644 --- a/tests/bluetooth/common/testlib/src/connect.c +++ b/tests/bluetooth/common/testlib/src/connect.c @@ -7,7 +7,7 @@ #include #include -#include +#include LOG_MODULE_REGISTER(bt_testlib_connect, LOG_LEVEL_INF); diff --git a/tests/bsim/bluetooth/host/att/long_read/main.c b/tests/bsim/bluetooth/host/att/long_read/main.c index 29a3de0a9e6..2f13b346a80 100644 --- a/tests/bsim/bluetooth/host/att/long_read/main.c +++ b/tests/bsim/bluetooth/host/att/long_read/main.c @@ -15,9 +15,7 @@ #include "testlib/att_write.h" #include "bs_macro.h" #include "bs_sync.h" -#include "testlib/conn_ref.h" -#include "testlib/conn_wait.h" -#include "testlib/connect.h" +#include #include "testlib/log_utils.h" #include "testlib/scan.h" #include "testlib/security.h" diff --git a/tests/bsim/bluetooth/host/att/retry_on_sec_err/client/main.c b/tests/bsim/bluetooth/host/att/retry_on_sec_err/client/main.c index 2a3c005515c..fc86d8aa5e3 100644 --- a/tests/bsim/bluetooth/host/att/retry_on_sec_err/client/main.c +++ b/tests/bsim/bluetooth/host/att/retry_on_sec_err/client/main.c @@ -13,7 +13,7 @@ #include "../common_defs.h" #include "../test_utils.h" -#include "testlib/connect.h" +#include #include "testlib/scan.h" #include "testlib/security.h" From 608cc4d1f21d7ae413f3293d7b7f46e0ee602aaa Mon Sep 17 00:00:00 2001 From: "Najumon B.A" Date: Sat, 18 Nov 2023 07:40:58 +0530 Subject: [PATCH 0112/3723] drivers: ns16550: remove parent init level dependency remove parent init level dependency such as PRE_KERNEL or POST_KERNEL. Uart driver init level change always to PRE_KERNEL Signed-off-by: Najumon B.A --- drivers/serial/Kconfig.ns16550 | 10 ---------- drivers/serial/uart_ns16550.c | 3 +-- 2 files changed, 1 insertion(+), 12 deletions(-) diff --git a/drivers/serial/Kconfig.ns16550 b/drivers/serial/Kconfig.ns16550 index 1c97a08637e..594216092e7 100644 --- a/drivers/serial/Kconfig.ns16550 +++ b/drivers/serial/Kconfig.ns16550 @@ -60,16 +60,6 @@ config UART_NS16550_ACCESS_WORD_ONLY 16550 (DesignWare UART) only allows word access, byte access will raise exception. -config UART_NS16550_PARENT_INIT_LEVEL - bool "Boot level based on parent node" - default y if ACPI - help - Boot level based on parent node (PCI or no PCI device). Some platforms the - PCI bus driver depends on ACPI sub system to retrieve platform information - such as interrupt routing information. But ACPI sub system currently support - only post kernel and hence such platforms the UART driver instance init - should be invoked only post kernel in case parent node is PCI. - config UART_NS16550_TI_K3 bool "Add support for NS16550 variant specific to TI K3 SoCs" help diff --git a/drivers/serial/uart_ns16550.c b/drivers/serial/uart_ns16550.c index a41cdca7843..3f64d83cf36 100644 --- a/drivers/serial/uart_ns16550.c +++ b/drivers/serial/uart_ns16550.c @@ -1423,8 +1423,7 @@ static const struct uart_driver_api uart_ns16550_driver_api = { }; \ DEVICE_DT_INST_DEFINE(n, &uart_ns16550_init, NULL, \ &uart_ns16550_dev_data_##n, &uart_ns16550_dev_cfg_##n, \ - COND_CODE_1(CONFIG_UART_NS16550_PARENT_INIT_LEVEL, \ - (POST_KERNEL), (PRE_KERNEL_1)), \ + PRE_KERNEL_1, \ CONFIG_SERIAL_INIT_PRIORITY, \ &uart_ns16550_driver_api); \ UART_NS16550_PCIE_IRQ_FUNC_DEFINE(n) From c0d61d0bbd8c0174b23920833a0a0963c0ef1b6e Mon Sep 17 00:00:00 2001 From: "Najumon B.A" Date: Sat, 18 Nov 2023 07:43:47 +0530 Subject: [PATCH 0113/3723] board: x86: remove parent init level dependency config remove parent init level config from Intel Alder Lake platform Signed-off-by: Najumon B.A --- boards/x86/intel_adl/intel_adl_crb_defconfig | 1 - boards/x86/intel_adl/intel_adl_rvp_defconfig | 1 - boards/x86/intel_adl/up_squared_pro_7000_defconfig | 1 - 3 files changed, 3 deletions(-) diff --git a/boards/x86/intel_adl/intel_adl_crb_defconfig b/boards/x86/intel_adl/intel_adl_crb_defconfig index c2c1a37850d..5287bfcacc0 100644 --- a/boards/x86/intel_adl/intel_adl_crb_defconfig +++ b/boards/x86/intel_adl/intel_adl_crb_defconfig @@ -12,4 +12,3 @@ CONFIG_X2APIC=y CONFIG_SMP=y CONFIG_BUILD_OUTPUT_EFI=y CONFIG_BUILD_NO_GAP_FILL=y -CONFIG_UART_NS16550_PARENT_INIT_LEVEL=y diff --git a/boards/x86/intel_adl/intel_adl_rvp_defconfig b/boards/x86/intel_adl/intel_adl_rvp_defconfig index 41260a3b233..0f6ed718268 100644 --- a/boards/x86/intel_adl/intel_adl_rvp_defconfig +++ b/boards/x86/intel_adl/intel_adl_rvp_defconfig @@ -12,4 +12,3 @@ CONFIG_X2APIC=y CONFIG_SMP=y CONFIG_BUILD_OUTPUT_EFI=y CONFIG_BUILD_NO_GAP_FILL=y -CONFIG_UART_NS16550_PARENT_INIT_LEVEL=y diff --git a/boards/x86/intel_adl/up_squared_pro_7000_defconfig b/boards/x86/intel_adl/up_squared_pro_7000_defconfig index 211ce9f24e1..4c228677a70 100644 --- a/boards/x86/intel_adl/up_squared_pro_7000_defconfig +++ b/boards/x86/intel_adl/up_squared_pro_7000_defconfig @@ -12,4 +12,3 @@ CONFIG_X2APIC=y CONFIG_SMP=y CONFIG_BUILD_OUTPUT_EFI=y CONFIG_BUILD_NO_GAP_FILL=y -CONFIG_UART_NS16550_PARENT_INIT_LEVEL=y From 5edb7cbe41f82ea0b5641f75d6206829801fd77e Mon Sep 17 00:00:00 2001 From: Peter van der Perk Date: Sat, 18 Nov 2023 19:08:21 +0100 Subject: [PATCH 0114/3723] soc: arm: nxp_imx: rt11xx: add support for CONFIG_ETH_MCUX_RMII_EXT_CLK ENET_REF_CLK as an input during rt11xx clock initialization. Signed-off-by: Peter van der Perk --- boards/arm/vmu_rt1170/vmu_rt1170-pinctrl.dtsi | 3 ++- soc/arm/nxp_imx/rt/soc_rt11xx.c | 12 ++++++++++++ 2 files changed, 14 insertions(+), 1 deletion(-) diff --git a/boards/arm/vmu_rt1170/vmu_rt1170-pinctrl.dtsi b/boards/arm/vmu_rt1170/vmu_rt1170-pinctrl.dtsi index 3f27e5c3a33..d556fff21ae 100644 --- a/boards/arm/vmu_rt1170/vmu_rt1170-pinctrl.dtsi +++ b/boards/arm/vmu_rt1170/vmu_rt1170-pinctrl.dtsi @@ -38,8 +38,9 @@ group3 { pinmux = <&iomuxc_gpio_disp_b1_11_enet_1g_ref_clk1>; drive-strength = "high"; - slew-rate = "slow"; + slew-rate = "fast"; input-enable; + bias-pull-down; }; }; diff --git a/soc/arm/nxp_imx/rt/soc_rt11xx.c b/soc/arm/nxp_imx/rt/soc_rt11xx.c index f9eb7b7e381..190be4746ed 100644 --- a/soc/arm/nxp_imx/rt/soc_rt11xx.c +++ b/soc/arm/nxp_imx/rt/soc_rt11xx.c @@ -402,10 +402,16 @@ static ALWAYS_INLINE void clock_init(void) rootCfg.mux = kCLOCK_ENET1_ClockRoot_MuxSysPll1Div2; rootCfg.div = 10; CLOCK_SetRootClock(kCLOCK_Root_Enet1, &rootCfg); +#if CONFIG_ETH_MCUX_RMII_EXT_CLK + /* Set ENET_REF_CLK as an input driven by PHY */ + IOMUXC_GPR->GPR4 &= ~IOMUXC_GPR_GPR4_ENET_REF_CLK_DIR(0x01U); + IOMUXC_GPR->GPR4 |= IOMUXC_GPR_GPR4_ENET_TX_CLK_SEL(0x1U); +#else /* Set ENET_REF_CLK as an output driven by ENET1_CLK_ROOT */ IOMUXC_GPR->GPR4 |= (IOMUXC_GPR_GPR4_ENET_REF_CLK_DIR(0x01U) | IOMUXC_GPR_GPR4_ENET_TX_CLK_SEL(0x1U)); #endif +#endif #if DT_NODE_HAS_STATUS(DT_NODELABEL(enet1g), okay) /* * 50 MHz clock for 10/100Mbit RMII PHY - @@ -414,11 +420,17 @@ static ALWAYS_INLINE void clock_init(void) rootCfg.mux = kCLOCK_ENET2_ClockRoot_MuxSysPll1Div2; rootCfg.div = 10; CLOCK_SetRootClock(kCLOCK_Root_Enet2, &rootCfg); +#if CONFIG_ETH_MCUX_RMII_EXT_CLK + /* Set ENET1G_REF_CLK as an input driven by PHY */ + IOMUXC_GPR->GPR5 &= ~IOMUXC_GPR_GPR5_ENET1G_REF_CLK_DIR(0x01U); + IOMUXC_GPR->GPR5 |= IOMUXC_GPR_GPR5_ENET1G_TX_CLK_SEL(0x1U); +#else /* Set ENET1G_REF_CLK as an output driven by ENET2_CLK_ROOT */ IOMUXC_GPR->GPR5 |= (IOMUXC_GPR_GPR5_ENET1G_REF_CLK_DIR(0x01U) | IOMUXC_GPR_GPR5_ENET1G_TX_CLK_SEL(0x1U)); #endif #endif +#endif #ifdef CONFIG_PTP_CLOCK_MCUX /* 24MHz PTP clock */ From efc32081893dd607dfc51938ef93787872008fe2 Mon Sep 17 00:00:00 2001 From: Rander Wang Date: Mon, 20 Nov 2023 11:29:01 +0800 Subject: [PATCH 0115/3723] soc: intel_adsp: cavs: mask idc interrupt before halting cpu Secondary dsp is idle and waiting for interrupt before it is totally halted. The other active cores can trigger idc interrupt to this core, this can wake it up and result to fw panic. Mask idc interrupt as timer interrupt to prevent this case. Signed-off-by: Rander Wang --- soc/xtensa/intel_adsp/cavs/multiprocessing.c | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/soc/xtensa/intel_adsp/cavs/multiprocessing.c b/soc/xtensa/intel_adsp/cavs/multiprocessing.c index 85d834065a7..5b13b813858 100644 --- a/soc/xtensa/intel_adsp/cavs/multiprocessing.c +++ b/soc/xtensa/intel_adsp/cavs/multiprocessing.c @@ -186,19 +186,25 @@ __imr void soc_mp_init(void) int soc_adsp_halt_cpu(int id) { + unsigned int irq_mask; + if (id == 0 || id == arch_curr_cpu()->id) { return -EINVAL; } + irq_mask = CAVS_L2_IDC; + #ifdef CONFIG_INTEL_ADSP_TIMER /* * Mask timer interrupt for this CPU so it won't wake up * by itself once WFI (wait for interrupt) instruction * runs. */ - CAVS_INTCTRL[id].l2.set = CAVS_L2_DWCT0; + irq_mask |= CAVS_L2_DWCT0; #endif + CAVS_INTCTRL[id].l2.set = irq_mask; + /* Stop sending IPIs to this core */ soc_cpus_active[id] = false; From 18c4574786371146608c359353c3d9ae4597bffd Mon Sep 17 00:00:00 2001 From: Ian Morris Date: Mon, 20 Nov 2023 13:38:00 -0800 Subject: [PATCH 0116/3723] drivers: clock_control: clock_control_ra.c: main oscillator select fix Due to a typo it is not possible to select the main oscillator (MOSC) as a clock source for an RA Microcontroller. This patch resolves the issue. Signed-off-by: Ian Morris --- drivers/clock_control/clock_control_ra.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/clock_control/clock_control_ra.c b/drivers/clock_control/clock_control_ra.c index b1008e3bf83..d3549c1e7c4 100644 --- a/drivers/clock_control/clock_control_ra.c +++ b/drivers/clock_control/clock_control_ra.c @@ -16,7 +16,7 @@ #if DT_SAME_NODE(DT_INST_PROP(0, clock_source), DT_PATH(clocks, pll)) #define SYSCLK_SRC pll #elif DT_SAME_NODE(DT_INST_PROP(0, clock_source), DT_PATH(clocks, mosc)) -#define SYSCLK_SRC moco +#define SYSCLK_SRC mosc #elif DT_SAME_NODE(DT_INST_PROP(0, clock_source), DT_PATH(clocks, sosc)) #define SYSCLK_SRC soco #elif DT_SAME_NODE(DT_INST_PROP(0, clock_source), DT_PATH(clocks, hoco)) From 716de6fef2c6163ee3c6f89abe5c5b50de9adcbb Mon Sep 17 00:00:00 2001 From: Huifeng Zhang Date: Tue, 21 Nov 2023 15:47:05 +0800 Subject: [PATCH 0117/3723] MAINTAINERS: Add myself to ARM arch as collaborator Adding myself as a collaborator on ARM arch so that I can help maintain the aarch32 cortex-a/r codes. Signed-off-by: Huifeng Zhang --- MAINTAINERS.yml | 1 + 1 file changed, 1 insertion(+) diff --git a/MAINTAINERS.yml b/MAINTAINERS.yml index 97d0ec0222f..a4ad483ce2c 100644 --- a/MAINTAINERS.yml +++ b/MAINTAINERS.yml @@ -155,6 +155,7 @@ ARM arch: - bbolen - povergoing - ithinuel + - sgrrzhf files: - arch/arm/ - arch/arm/core/offsets/ From f66930fd3edd4680a45b6bf63ac7864a9f47462c Mon Sep 17 00:00:00 2001 From: Anisetti Avinash Krishna Date: Fri, 13 Oct 2023 20:19:03 +0530 Subject: [PATCH 0118/3723] drivers: uart: uart_ns16550: Enable Async operations using DMA Enabled Async API feature for ns16550 driver using DMA support. Signed-off-by: Anisetti Avinash Krishna --- drivers/serial/Kconfig.ns16550 | 7 + drivers/serial/uart_ns16550.c | 561 ++++++++++++++++++++++++++++++++- 2 files changed, 565 insertions(+), 3 deletions(-) diff --git a/drivers/serial/Kconfig.ns16550 b/drivers/serial/Kconfig.ns16550 index 594216092e7..fd7f1156a14 100644 --- a/drivers/serial/Kconfig.ns16550 +++ b/drivers/serial/Kconfig.ns16550 @@ -30,6 +30,13 @@ config UART_NS16550_DRV_CMD Says n if not sure. +config UART_NS16550_INTEL_LPSS_DMA + bool "INTEL LPSS support for NS16550" + select SERIAL_SUPPORT_ASYNC + select DMA if UART_ASYNC_API + help + This enables the usage of INTEL LPSS internal DMA for Async operations. + choice UART_NS16550_VARIANT prompt "UART variant" default UART_NS16550_VARIANT_NS16550 diff --git a/drivers/serial/uart_ns16550.c b/drivers/serial/uart_ns16550.c index 3f64d83cf36..22243a34d16 100644 --- a/drivers/serial/uart_ns16550.c +++ b/drivers/serial/uart_ns16550.c @@ -58,6 +58,16 @@ BUILD_ASSERT(IS_ENABLED(CONFIG_PCIE), "NS16550(s) in DT need CONFIG_PCIE"); #include #endif +#if defined(CONFIG_UART_ASYNC_API) +#include +#include + +#if defined(CONFIG_UART_NS16550_INTEL_LPSS_DMA) +#include +#endif + +#endif + /* If any node has property io-mapped set, we need to support IO port * access in the code and device config struct. * @@ -90,6 +100,12 @@ BUILD_ASSERT(IS_ENABLED(CONFIG_PCIE), "NS16550(s) in DT need CONFIG_PCIE"); #define REG_PCP 0x200 /* PRV_CLOCK_PARAMS (Apollo Lake) */ #define REG_MDR1 0x08 /* Mode control reg. (TI_K3) */ +#if defined(CONFIG_UART_NS16550_INTEL_LPSS_DMA) +#define REG_LPSS_SRC_TRAN 0xAF8 /* SRC Transfer LPSS DMA */ +#define REG_LPSS_CLR_SRC_TRAN 0xB48 /* Clear SRC Tran LPSS DMA */ +#define REG_LPSS_MST 0xB20 /* Mask SRC Transfer LPSS DMA */ +#endif + /* equates for interrupt enable register */ #define IER_RXRDY 0x01 /* receiver data ready */ @@ -240,6 +256,15 @@ BUILD_ASSERT(IS_ENABLED(CONFIG_PCIE), "NS16550(s) in DT need CONFIG_PCIE"); #define DLF(dev) (get_port(dev) + REG_DLF) #define PCP(dev) (get_port(dev) + REG_PCP) +#if defined(CONFIG_UART_NS16550_INTEL_LPSS_DMA) +#define SRC_TRAN(dev) (get_port(dev) + REG_LPSS_SRC_TRAN) +#define CLR_SRC_TRAN(dev) (get_port(dev) + REG_LPSS_CLR_SRC_TRAN) +#define MST(dev) (get_port(dev) + REG_LPSS_MST) + +#define MASK_LPSS_INT(chan) (BIT(8) << chan) /* mask LPSS DMA Interrupt */ +#define UNMASK_LPSS_INT(chan) (BIT(chan) | (BIT(8) << chan)) /* unmask LPSS DMA Interrupt */ +#endif + #define IIRC(dev) (((struct uart_ns16550_dev_data *)(dev)->data)->iir_cache) #ifdef CONFIG_UART_NS16550_ITE_HIGH_SPEED_BUADRATE @@ -259,6 +284,45 @@ BUILD_ASSERT(IS_ENABLED(CONFIG_PCIE), "NS16550(s) in DT need CONFIG_PCIE"); #define ECSPMR(dev) (get_port(dev) + REG_ECSPMR * reg_interval(dev)) #endif +#if defined(CONFIG_UART_ASYNC_API) +struct uart_ns16550_rx_dma_params { + const struct device *dma_dev; + uint8_t dma_channel; + struct dma_config dma_cfg; + struct dma_block_config active_dma_block; + uint8_t *buf; + size_t buf_len; + size_t offset; + size_t counter; + struct k_work_delayable timeout_work; + size_t timeout_us; +}; + +struct uart_ns16550_tx_dma_params { + const struct device *dma_dev; + uint8_t dma_channel; + struct dma_config dma_cfg; + struct dma_block_config active_dma_block; + const uint8_t *buf; + size_t buf_len; + struct k_work_delayable timeout_work; + size_t timeout_us; +}; + +struct uart_ns16550_async_data { + const struct device *uart_dev; + struct uart_ns16550_tx_dma_params tx_dma_params; + struct uart_ns16550_rx_dma_params rx_dma_params; + uint8_t *next_rx_buffer; + size_t next_rx_buffer_len; + uart_callback_t user_callback; + void *user_data; +}; + +static void uart_ns16550_async_rx_timeout(struct k_work *work); +static void uart_ns16550_async_tx_timeout(struct k_work *work); +#endif + /* device config */ struct uart_ns16550_device_config { union { @@ -309,6 +373,11 @@ struct uart_ns16550_dev_data { #if defined(CONFIG_UART_INTERRUPT_DRIVEN) && defined(CONFIG_PM) bool tx_stream_on; #endif + +#if defined(CONFIG_UART_ASYNC_API) + uint64_t phys_addr; + struct uart_ns16550_async_data async; +#endif }; static void ns16550_outbyte(const struct uart_ns16550_device_config *cfg, @@ -358,7 +427,8 @@ static uint8_t ns16550_inbyte(const struct uart_ns16550_device_config *cfg, return 0; } -#if UART_NS16550_PCP_ENABLED +#if (defined(CONFIG_UART_NS16550_INTEL_LPSS_DMA) & (defined(CONFIG_UART_ASYNC_API)))\ + | UART_NS16550_PCP_ENABLED static void ns16550_outword(const struct uart_ns16550_device_config *cfg, uintptr_t port, uint32_t val) { @@ -689,6 +759,16 @@ static int uart_reset_config(const struct reset_dt_spec *reset_spec) } #endif /* UART_NS16550_RESET_ENABLED */ +#if (IS_ENABLED(CONFIG_UART_ASYNC_API)) +static inline void async_timer_start(struct k_work_delayable *work, size_t timeout_us) +{ + if ((timeout_us != SYS_FOREVER_US) && (timeout_us != 0)) { + k_work_reschedule(work, K_USEC(timeout_us)); + } +} + +#endif + /** * @brief Initialize individual UART port * @@ -729,6 +809,12 @@ static int uart_ns16550_init(const struct device *dev) device_map(DEVICE_MMIO_RAM_PTR(dev), mbar.phys_addr, mbar.size, K_MEM_CACHE_NONE); +#if defined(CONFIG_UART_ASYNC_API) + if (data->async.tx_dma_params.dma_dev != NULL) { + pcie_set_cmd(dev_cfg->pcie->bdf, PCIE_CONF_CMDSTAT_MASTER, true); + data->phys_addr = mbar.phys_addr; + } +#endif } else #endif /* DT_ANY_INST_ON_BUS_STATUS_OKAY(pcie) */ { @@ -741,7 +827,34 @@ static int uart_ns16550_init(const struct device *dev) DEVICE_MMIO_MAP(dev, K_MEM_CACHE_NONE); } } - +#if defined(CONFIG_UART_ASYNC_API) + if (data->async.tx_dma_params.dma_dev != NULL) { + data->async.next_rx_buffer = NULL; + data->async.next_rx_buffer_len = 0; + data->async.uart_dev = dev; + k_work_init_delayable(&data->async.rx_dma_params.timeout_work, + uart_ns16550_async_rx_timeout); + k_work_init_delayable(&data->async.tx_dma_params.timeout_work, + uart_ns16550_async_tx_timeout); + data->async.rx_dma_params.dma_cfg.head_block = + &data->async.rx_dma_params.active_dma_block; + data->async.tx_dma_params.dma_cfg.head_block = + &data->async.tx_dma_params.active_dma_block; +#if defined(CONFIG_UART_NS16550_INTEL_LPSS_DMA) + if (!dev_cfg->io_map) { + uintptr_t base; + + base = DEVICE_MMIO_GET(dev) + DMA_INTEL_LPSS_OFFSET; + dma_intel_lpss_set_base(data->async.tx_dma_params.dma_dev, base); + dma_intel_lpss_setup(data->async.tx_dma_params.dma_dev); + sys_write32((uint32_t)data->phys_addr, + DEVICE_MMIO_GET(dev) + DMA_INTEL_LPSS_REMAP_LOW); + sys_write32((uint32_t)(data->phys_addr >> DMA_INTEL_LPSS_ADDR_RIGHT_SHIFT), + DEVICE_MMIO_GET(dev) + DMA_INTEL_LPSS_REMAP_HI); + } +#endif + } +#endif ret = uart_ns16550_configure(dev, &data->uart_config); if (ret != 0) { return ret; @@ -1155,6 +1268,31 @@ static void uart_ns16550_isr(const struct device *dev) if (dev_data->cb) { dev_data->cb(dev, dev_data->cb_data); } +#if (IS_ENABLED(CONFIG_UART_ASYNC_API)) + if (dev_data->async.tx_dma_params.dma_dev != NULL) { + const struct uart_ns16550_device_config * const config = dev->config; + uint8_t IIR_status = ns16550_inbyte(config, IIR(dev)); +#if (IS_ENABLED(CONFIG_UART_NS16550_INTEL_LPSS_DMA)) + uint32_t dma_status = ns16550_inword(config, SRC_TRAN(dev)); + + if (dma_status & BIT(dev_data->async.rx_dma_params.dma_channel)) { + async_timer_start(&dev_data->async.rx_dma_params.timeout_work, + dev_data->async.rx_dma_params.timeout_us); + ns16550_outword(config, CLR_SRC_TRAN(dev), + BIT(dev_data->async.rx_dma_params.dma_channel)); + return; + } + dma_intel_lpss_isr(dev_data->async.rx_dma_params.dma_dev); +#endif + if (IIR_status & IIR_RBRF) { + async_timer_start(&dev_data->async.rx_dma_params.timeout_work, + dev_data->async.rx_dma_params.timeout_us); + ns16550_outword(config, CLR_SRC_TRAN(dev), + BIT(dev_data->async.rx_dma_params.dma_channel)); + return; + } + } +#endif #ifdef CONFIG_UART_NS16550_WA_ISR_REENABLE_INTERRUPT const struct uart_ns16550_device_config * const dev_cfg = dev->config; @@ -1257,6 +1395,352 @@ static int uart_ns16550_drv_cmd(const struct device *dev, uint32_t cmd, #endif /* CONFIG_UART_NS16550_DRV_CMD */ +#if (IS_ENABLED(CONFIG_UART_ASYNC_API)) +static void async_user_callback(const struct device *dev, struct uart_event *evt) +{ + const struct uart_ns16550_dev_data *data = dev->data; + + if (data->async.user_callback) { + data->async.user_callback(dev, evt, data->async.user_data); + } +} + +static void async_evt_tx_done(struct device *dev) +{ + struct uart_ns16550_dev_data *data = dev->data; + struct uart_ns16550_tx_dma_params *tx_params = &data->async.tx_dma_params; + + (void)k_work_cancel_delayable(&data->async.tx_dma_params.timeout_work); + + struct uart_event event = { + .type = UART_TX_DONE, + .data.tx.buf = tx_params->buf, + .data.tx.len = tx_params->buf_len + }; + + tx_params->buf = NULL; + tx_params->buf_len = 0U; + + async_user_callback(dev, &event); +} + +static void async_evt_rx_rdy(const struct device *dev) +{ + struct uart_ns16550_dev_data *data = dev->data; + struct uart_ns16550_rx_dma_params *dma_params = &data->async.rx_dma_params; + + struct uart_event event = { + .type = UART_RX_RDY, + .data.rx.buf = dma_params->buf, + .data.rx.len = dma_params->counter - dma_params->offset, + .data.rx.offset = dma_params->offset + }; + + dma_params->offset = dma_params->counter; + + if (event.data.rx.len > 0) { + async_user_callback(dev, &event); + } +} + +static void async_evt_rx_buf_release(const struct device *dev) +{ + struct uart_ns16550_dev_data *data = (struct uart_ns16550_dev_data *)dev->data; + struct uart_event evt = { + .type = UART_RX_BUF_RELEASED, + .data.rx_buf.buf = data->async.rx_dma_params.buf + }; + + async_user_callback(dev, &evt); + data->async.rx_dma_params.buf = NULL; + data->async.rx_dma_params.buf_len = 0U; + data->async.rx_dma_params.offset = 0U; + data->async.rx_dma_params.counter = 0U; +} + +static void async_evt_rx_buf_request(const struct device *dev) +{ + struct uart_event evt = { + .type = UART_RX_BUF_REQUEST + }; + async_user_callback(dev, &evt); +} + +static void uart_ns16550_async_rx_flush(const struct device *dev) +{ + struct uart_ns16550_dev_data *data = dev->data; + struct uart_ns16550_rx_dma_params *dma_params = &data->async.rx_dma_params; + struct dma_status status; + + dma_get_status(dma_params->dma_dev, + dma_params->dma_channel, + &status); + + const int rx_count = dma_params->buf_len - status.pending_length; + + if (rx_count > dma_params->counter) { + dma_params->counter = rx_count; + async_evt_rx_rdy(dev); + } +} + +static int uart_ns16550_rx_disable(const struct device *dev) +{ + const struct uart_ns16550_device_config * const config = dev->config; + struct uart_ns16550_dev_data *data = (struct uart_ns16550_dev_data *)dev->data; + struct uart_ns16550_rx_dma_params *dma_params = &data->async.rx_dma_params; + k_spinlock_key_t key = k_spin_lock(&data->lock); + int ret = 0; + + if (!device_is_ready(dma_params->dma_dev)) { + ret = -ENODEV; + goto out; + } + + (void)k_work_cancel_delayable(&data->async.rx_dma_params.timeout_work); + + if (dma_params->buf && (dma_params->buf_len > 0)) { + uart_ns16550_async_rx_flush(dev); + async_evt_rx_buf_release(dev); + if (data->async.next_rx_buffer != NULL) { + dma_params->buf = data->async.next_rx_buffer; + dma_params->buf_len = data->async.next_rx_buffer_len; + data->async.next_rx_buffer = NULL; + data->async.next_rx_buffer_len = 0; + async_evt_rx_buf_release(dev); + } + } + ret = dma_stop(dma_params->dma_dev, + dma_params->dma_channel); + + struct uart_event event = { + .type = UART_RX_DISABLED + }; + + async_user_callback(dev, &event); + + if (IS_ENABLED(CONFIG_UART_NS16550_INTEL_LPSS_DMA)) { + ns16550_outword(config, MST(dev), UNMASK_LPSS_INT(dma_params->dma_channel)); + } + +out: + k_spin_unlock(&data->lock, key); + return ret; +} + +static void prepare_rx_dma_block_config(const struct device *dev) +{ + struct uart_ns16550_dev_data *data = (struct uart_ns16550_dev_data *)dev->data; + struct uart_ns16550_rx_dma_params *rx_dma_params = &data->async.rx_dma_params; + + assert(rx_dma_params->buf != NULL); + assert(rx_dma_params->buf_len > 0); + + struct dma_block_config *head_block_config = &rx_dma_params->active_dma_block; + + head_block_config->dest_address = (uint64_t)rx_dma_params->buf; + head_block_config->source_address = data->phys_addr; + head_block_config->block_size = rx_dma_params->buf_len; +} + +static void dma_callback(const struct device *dev, void *user_data, uint32_t channel, + int status) +{ + struct device *uart_dev = (struct device *)user_data; + struct uart_ns16550_dev_data *data = (struct uart_ns16550_dev_data *)uart_dev->data; + struct uart_ns16550_rx_dma_params *rx_params = &data->async.rx_dma_params; + struct uart_ns16550_tx_dma_params *tx_params = &data->async.tx_dma_params; + + if (channel == tx_params->dma_channel) { + async_evt_tx_done(uart_dev); + } else if (channel == rx_params->dma_channel) { + + rx_params->counter = rx_params->buf_len; + + async_evt_rx_rdy(uart_dev); + async_evt_rx_buf_release(uart_dev); + + rx_params->buf = data->async.next_rx_buffer; + rx_params->buf_len = data->async.next_rx_buffer_len; + data->async.next_rx_buffer = NULL; + data->async.next_rx_buffer_len = 0U; + + if (rx_params->buf != NULL && + rx_params->buf_len > 0) { + dma_reload(dev, rx_params->dma_channel, data->phys_addr, + (uint64_t)rx_params->buf, rx_params->buf_len); + dma_start(dev, rx_params->dma_channel); + async_evt_rx_buf_request(uart_dev); + } else { + uart_ns16550_rx_disable(uart_dev); + } + } +} + +static int uart_ns16550_callback_set(const struct device *dev, uart_callback_t callback, + void *user_data) +{ + struct uart_ns16550_dev_data *data = dev->data; + + data->async.user_callback = callback; + data->async.user_data = user_data; + + return 0; +} + +static int uart_ns16550_tx(const struct device *dev, const uint8_t *buf, size_t len, + int32_t timeout_us) +{ + struct uart_ns16550_dev_data *data = dev->data; + struct uart_ns16550_tx_dma_params *tx_params = &data->async.tx_dma_params; + k_spinlock_key_t key = k_spin_lock(&data->lock); + int ret = 0; + + if (!device_is_ready(tx_params->dma_dev)) { + ret = -ENODEV; + goto out; + } + + tx_params->buf = buf; + tx_params->buf_len = len; + tx_params->active_dma_block.source_address = (uint64_t)buf; + tx_params->active_dma_block.dest_address = data->phys_addr; + tx_params->active_dma_block.block_size = len; + tx_params->active_dma_block.next_block = NULL; + + ret = dma_config(tx_params->dma_dev, + tx_params->dma_channel, + (struct dma_config *)&tx_params->dma_cfg); + + if (ret == 0) { + ret = dma_start(tx_params->dma_dev, + tx_params->dma_channel); + if (ret) { + ret = -EIO; + goto out; + } + async_timer_start(&data->async.tx_dma_params.timeout_work, timeout_us); + } + +out: + k_spin_unlock(&data->lock, key); + return ret; +} + +static int uart_ns16550_tx_abort(const struct device *dev) +{ + struct uart_ns16550_dev_data *data = dev->data; + struct uart_ns16550_tx_dma_params *tx_params = &data->async.tx_dma_params; + struct dma_status status; + int ret = 0; + size_t bytes_tx; + + k_spinlock_key_t key = k_spin_lock(&data->lock); + + if (!device_is_ready(tx_params->dma_dev)) { + ret = -ENODEV; + goto out; + } + + (void)k_work_cancel_delayable(&data->async.tx_dma_params.timeout_work); + + ret = dma_stop(tx_params->dma_dev, tx_params->dma_channel); + dma_get_status(tx_params->dma_dev, + tx_params->dma_channel, + &status); + bytes_tx = tx_params->buf_len - status.pending_length; + + if (ret == 0) { + struct uart_event tx_aborted_event = { + .type = UART_TX_ABORTED, + .data.tx.buf = tx_params->buf, + .data.tx.len = bytes_tx + }; + async_user_callback(dev, &tx_aborted_event); + } +out: + k_spin_unlock(&data->lock, key); + return ret; +} + +static int uart_ns16550_rx_enable(const struct device *dev, uint8_t *buf, const size_t len, + const int32_t timeout_us) +{ + struct uart_ns16550_dev_data *data = dev->data; + const struct uart_ns16550_device_config *config = dev->config; + struct uart_ns16550_rx_dma_params *rx_dma_params = &data->async.rx_dma_params; + int ret = 0; + k_spinlock_key_t key = k_spin_lock(&data->lock); + + if (!device_is_ready(rx_dma_params->dma_dev)) { + ret = -ENODEV; + goto out; + } + + rx_dma_params->timeout_us = timeout_us; + rx_dma_params->buf = buf; + rx_dma_params->buf_len = len; + + if (IS_ENABLED(CONFIG_UART_NS16550_INTEL_LPSS_DMA)) { + ns16550_outword(config, MST(dev), UNMASK_LPSS_INT(DMA_INTEL_LPSS_RX_CHAN)); + } else { + ns16550_outbyte(config, IER(dev), + (ns16550_inbyte(config, IER(dev)) | IER_RXRDY)); + ns16550_outbyte(config, FCR(dev), FCR_FIFO); + } + prepare_rx_dma_block_config(dev); + dma_config(rx_dma_params->dma_dev, + rx_dma_params->dma_channel, + (struct dma_config *)&rx_dma_params->dma_cfg); + dma_start(rx_dma_params->dma_dev, rx_dma_params->dma_channel); + async_evt_rx_buf_request(dev); +out: + k_spin_unlock(&data->lock, key); + return ret; +} + +static int uart_ns16550_rx_buf_rsp(const struct device *dev, uint8_t *buf, size_t len) +{ + struct uart_ns16550_dev_data *data = dev->data; + + assert(data->async.next_rx_buffer == NULL); + assert(data->async.next_rx_buffer_len == 0); + data->async.next_rx_buffer = buf; + data->async.next_rx_buffer_len = len; + + return 0; +} + +static void uart_ns16550_async_rx_timeout(struct k_work *work) +{ + struct k_work_delayable *work_delay = CONTAINER_OF(work, struct k_work_delayable, work); + struct uart_ns16550_rx_dma_params *rx_params = + CONTAINER_OF(work_delay, struct uart_ns16550_rx_dma_params, + timeout_work); + struct uart_ns16550_async_data *async_data = + CONTAINER_OF(rx_params, struct uart_ns16550_async_data, + rx_dma_params); + const struct device *dev = async_data->uart_dev; + + uart_ns16550_async_rx_flush(dev); + +} + +static void uart_ns16550_async_tx_timeout(struct k_work *work) +{ + struct k_work_delayable *work_delay = CONTAINER_OF(work, struct k_work_delayable, work); + struct uart_ns16550_tx_dma_params *tx_params = + CONTAINER_OF(work_delay, struct uart_ns16550_tx_dma_params, + timeout_work); + struct uart_ns16550_async_data *async_data = + CONTAINER_OF(tx_params, struct uart_ns16550_async_data, + tx_dma_params); + const struct device *dev = async_data->uart_dev; + + (void)uart_ns16550_tx_abort(dev); +} + +#endif /* CONFIG_UART_ASYNC_API */ static const struct uart_driver_api uart_ns16550_driver_api = { .poll_in = uart_ns16550_poll_in, @@ -1285,6 +1769,15 @@ static const struct uart_driver_api uart_ns16550_driver_api = { #endif +#ifdef CONFIG_UART_ASYNC_API + .callback_set = uart_ns16550_callback_set, + .tx = uart_ns16550_tx, + .tx_abort = uart_ns16550_tx_abort, + .rx_enable = uart_ns16550_rx_enable, + .rx_disable = uart_ns16550_rx_disable, + .rx_buf_rsp = uart_ns16550_rx_buf_rsp, +#endif + #ifdef CONFIG_UART_NS16550_LINE_CTRL .line_ctrl_set = uart_ns16550_line_ctrl_set, #endif @@ -1356,6 +1849,67 @@ static const struct uart_driver_api uart_ns16550_driver_api = { #define UART_NS16550_PCIE_IRQ_FUNC_DEFINE(n) #endif /* CONFIG_UART_INTERRUPT_DRIVEN */ +#ifdef CONFIG_UART_ASYNC_API +#define DMA_PARAMS(n) \ + .async.tx_dma_params = { \ + .dma_dev = \ + DEVICE_DT_GET(DT_INST_DMAS_CTLR_BY_NAME(n, tx)), \ + .dma_channel = \ + DT_INST_DMAS_CELL_BY_NAME(n, tx, channel), \ + .dma_cfg = { \ + .source_burst_length = 1, \ + .dest_burst_length = 1, \ + .source_data_size = 1, \ + .dest_data_size = 1, \ + .complete_callback_en = 0, \ + .error_callback_en = 1, \ + .block_count = 1, \ + .channel_direction = MEMORY_TO_PERIPHERAL, \ + .dma_slot = DT_INST_DMAS_CELL_BY_NAME(n, tx, channel), \ + .dma_callback = dma_callback, \ + .user_data = (void *)DEVICE_DT_INST_GET(n) \ + }, \ + }, \ + .async.rx_dma_params = { \ + .dma_dev = \ + DEVICE_DT_GET(DT_INST_DMAS_CTLR_BY_NAME(n, rx)), \ + .dma_channel = \ + DT_INST_DMAS_CELL_BY_NAME(n, rx, channel), \ + .dma_cfg = { \ + .source_burst_length = 1, \ + .dest_burst_length = 1, \ + .source_data_size = 1, \ + .dest_data_size = 1, \ + .complete_callback_en = 0, \ + .error_callback_en = 1, \ + .block_count = 1, \ + .channel_direction = PERIPHERAL_TO_MEMORY, \ + .dma_slot = DT_INST_DMAS_CELL_BY_NAME(n, rx, channel), \ + .dma_callback = dma_callback, \ + .user_data = (void *)DEVICE_DT_INST_GET(n) \ + }, \ + }, \ + COND_CODE_0(DT_INST_ON_BUS(n, pcie), \ + (.phys_addr = DT_INST_REG_ADDR(n),), ()) + +#define DMA_PARAMS_NULL(n) \ + .async.tx_dma_params = { \ + .dma_dev = NULL \ + }, \ + .async.rx_dma_params = { \ + .dma_dev = NULL \ + }, \ + +#define DEV_DATA_ASYNC(n) \ + COND_CODE_0(DT_INST_PROP(n, io_mapped), \ + (COND_CODE_1(DT_INST_NODE_HAS_PROP(n, dmas), \ + (DMA_PARAMS(n)), (DMA_PARAMS_NULL(n)))), \ + (DMA_PARAMS_NULL(n))) +#else +#define DEV_DATA_ASYNC(n) +#endif /* CONFIG_UART_ASYNC_API */ + + #define UART_NS16550_COMMON_DEV_CFG_INITIALIZER(n) \ COND_CODE_1(DT_INST_NODE_HAS_PROP(n, clock_frequency), ( \ .sys_clk_freq = DT_INST_PROP(n, clock_frequency), \ @@ -1386,7 +1940,8 @@ static const struct uart_driver_api uart_ns16550_driver_api = { (UART_CFG_FLOW_CTRL_RTS_CTS), \ (UART_CFG_FLOW_CTRL_NONE)), \ IF_ENABLED(DT_INST_NODE_HAS_PROP(n, dlf), \ - (.dlf = DT_INST_PROP_OR(n, dlf, 0),)) + (.dlf = DT_INST_PROP_OR(n, dlf, 0),)) \ + DEV_DATA_ASYNC(n) \ #define UART_NS16550_DEVICE_IO_MMIO_INIT(n) \ UART_NS16550_IRQ_FUNC_DECLARE(n); \ From 05fd5b042658d4d5cd9ca640084b594ee52d7f21 Mon Sep 17 00:00:00 2001 From: Anisetti Avinash Krishna Date: Sat, 14 Oct 2023 23:00:33 +0530 Subject: [PATCH 0119/3723] boards: x86: intel_rpl: Added modifications for Asycn NS16550 Added modifications to support async apis for ns16550 on RPL-s using LPSS DMA. Signed-off-by: Anisetti Avinash Krishna --- boards/x86/intel_rpl/Kconfig.defconfig | 3 +++ 1 file changed, 3 insertions(+) diff --git a/boards/x86/intel_rpl/Kconfig.defconfig b/boards/x86/intel_rpl/Kconfig.defconfig index 78c10d200a3..ea93b03e039 100644 --- a/boards/x86/intel_rpl/Kconfig.defconfig +++ b/boards/x86/intel_rpl/Kconfig.defconfig @@ -53,4 +53,7 @@ config DMA_DW_CHANNEL_COUNT default 2 endif +config UART_NS16550_INTEL_LPSS_DMA + default y + endif # BOARD_INTEL_RPL_S_CRB From 7b412be883d8fe5f4822b45904075c2ea2e8e4bc Mon Sep 17 00:00:00 2001 From: Anisetti Avinash Krishna Date: Sat, 14 Oct 2023 23:15:08 +0530 Subject: [PATCH 0120/3723] dts: x86: intel: raptor_lake: Added LPSS dma node for UART Added LPSS dma node for UART Async API support Signed-off-by: Anisetti Avinash Krishna --- dts/x86/intel/raptor_lake.dtsi | 22 +++++++++++++++++++--- 1 file changed, 19 insertions(+), 3 deletions(-) diff --git a/dts/x86/intel/raptor_lake.dtsi b/dts/x86/intel/raptor_lake.dtsi index 797a3fa0e54..ab3e9958928 100644 --- a/dts/x86/intel/raptor_lake.dtsi +++ b/dts/x86/intel/raptor_lake.dtsi @@ -79,7 +79,7 @@ compatible = "intel,lpss"; dma-parent = <&i2c0>; #dma-cells = <1>; - status = "okay"; + status = "disabled"; }; i2c1: i2c1 { @@ -272,6 +272,12 @@ status = "disabled"; }; + uart0_dma: uart0_dma { + compatible = "intel,lpss"; + #dma-cells = <1>; + status = "disabled"; + }; + uart0: uart0 { compatible = "ns16550"; vendor-id = <0x8086>; @@ -281,7 +287,15 @@ interrupts = ; interrupt-parent = <&intc>; current-speed = <115200>; - status = "okay"; + dmas = <&uart0_dma 0>, <&uart0_dma 1>; + dma-names = "tx", "rx"; + status = "disabled"; + }; + + uart1_dma: uart1_dma { + compatible = "intel,lpss"; + #dma-cells = <1>; + status = "disabled"; }; uart1: uart1 { @@ -293,7 +307,9 @@ interrupts = ; interrupt-parent = <&intc>; current-speed = <115200>; - status = "okay"; + dmas = <&uart1_dma 0>, <&uart1_dma 1>; + dma-names = "tx", "rx"; + status = "disabled"; }; uart2: uart2 { From 6de5a1a5d578e99da0852c4661abfeed40f3f994 Mon Sep 17 00:00:00 2001 From: Anisetti Avinash Krishna Date: Sat, 14 Oct 2023 23:21:15 +0530 Subject: [PATCH 0121/3723] tests: drivers: uart: uart_async_api: Enabled tests for rpl_s platform Enabled tests for intel_rpl_s_crb platform. Signed-off-by: Anisetti Avinash Krishna --- .../uart/uart_async_api/boards/intel_rpl_s_crb.conf | 1 + .../uart_async_api/boards/intel_rpl_s_crb.overlay | 13 +++++++++++++ 2 files changed, 14 insertions(+) create mode 100644 tests/drivers/uart/uart_async_api/boards/intel_rpl_s_crb.conf create mode 100644 tests/drivers/uart/uart_async_api/boards/intel_rpl_s_crb.overlay diff --git a/tests/drivers/uart/uart_async_api/boards/intel_rpl_s_crb.conf b/tests/drivers/uart/uart_async_api/boards/intel_rpl_s_crb.conf new file mode 100644 index 00000000000..86df0aff3e6 --- /dev/null +++ b/tests/drivers/uart/uart_async_api/boards/intel_rpl_s_crb.conf @@ -0,0 +1 @@ +CONFIG_UART_INTERRUPT_DRIVEN=y diff --git a/tests/drivers/uart/uart_async_api/boards/intel_rpl_s_crb.overlay b/tests/drivers/uart/uart_async_api/boards/intel_rpl_s_crb.overlay new file mode 100644 index 00000000000..35c408a8526 --- /dev/null +++ b/tests/drivers/uart/uart_async_api/boards/intel_rpl_s_crb.overlay @@ -0,0 +1,13 @@ +/* + * Copyright (c) 2023 Intel Corporation + * + * SPDX-License-Identifier: Apache-2.0 + */ + +dut: &uart0 { + status = "okay"; +}; + +&uart0_dma { + status = "okay"; +}; From bd6d43d4c8e134437865b5e5d2222119c62c493a Mon Sep 17 00:00:00 2001 From: Jamie McCrae Date: Wed, 1 Nov 2023 14:47:08 +0000 Subject: [PATCH 0122/3723] sysbuild: bootloader: Fix setting application Kconfig in MCUboot Fixes wrongly setting configuration to generate an unsigned image in the MCUboot configuration when this does not apply to MCUboot Signed-off-by: Jamie McCrae --- .../image_configurations/BOOTLOADER_image_default.cmake | 8 -------- 1 file changed, 8 deletions(-) diff --git a/share/sysbuild/image_configurations/BOOTLOADER_image_default.cmake b/share/sysbuild/image_configurations/BOOTLOADER_image_default.cmake index 5594109668b..0da5a89ce11 100644 --- a/share/sysbuild/image_configurations/BOOTLOADER_image_default.cmake +++ b/share/sysbuild/image_configurations/BOOTLOADER_image_default.cmake @@ -27,11 +27,3 @@ foreach(loopkeytype ${keytypes}) set_config_bool(${ZCMAKE_APPLICATION} ${loopkeytype} n) endif() endforeach() - -if(SB_CONFIG_BOOTLOADER_MCUBOOT) - if("${SB_CONFIG_SIGNATURE_TYPE}" STREQUAL "NONE") - set_config_bool(${ZCMAKE_APPLICATION} CONFIG_MCUBOOT_GENERATE_UNSIGNED_IMAGE y) - else() - set_config_bool(${ZCMAKE_APPLICATION} CONFIG_MCUBOOT_GENERATE_UNSIGNED_IMAGE n) - endif() -endif() From 67696b7311b1cd88926349c0064449236d03951f Mon Sep 17 00:00:00 2001 From: Jamie McCrae Date: Wed, 1 Nov 2023 14:48:03 +0000 Subject: [PATCH 0123/3723] sysbuild: mcuboot: Disable signing key in no signing mode Prevents allowing the user to enter a signing key when the signing mode is set to hash check only without signatures Signed-off-by: Jamie McCrae --- share/sysbuild/images/bootloader/Kconfig | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/share/sysbuild/images/bootloader/Kconfig b/share/sysbuild/images/bootloader/Kconfig index e8c788f72c5..d8e1bf70d75 100644 --- a/share/sysbuild/images/bootloader/Kconfig +++ b/share/sysbuild/images/bootloader/Kconfig @@ -56,7 +56,7 @@ config BOOT_SIGNATURE_TYPE_ED25519 endchoice config BOOT_SIGNATURE_KEY_FILE - string "Signing PEM key file" + string "Signing PEM key file" if !BOOT_SIGNATURE_TYPE_NONE default "$(ZEPHYR_MCUBOOT_MODULE_DIR)/root-ec-p256.pem" if BOOT_SIGNATURE_TYPE_ECDSA_P256 default "$(ZEPHYR_MCUBOOT_MODULE_DIR)/root-ed25519.pem" if BOOT_SIGNATURE_TYPE_ED25519 default "$(ZEPHYR_MCUBOOT_MODULE_DIR)/root-rsa-2048.pem" if BOOT_SIGNATURE_TYPE_RSA From 2a6cec0687c279dde5756aa9aa38ff5bbba9fa42 Mon Sep 17 00:00:00 2001 From: Jamie McCrae Date: Tue, 21 Nov 2023 10:41:03 +0000 Subject: [PATCH 0124/3723] west.yml: MCUboot synchronization from upstream Update Zephyr fork of MCUboot to revision: 47b34362552835621bc289d53d2127691088cb7c Brings following Zephyr relevant fixes: - 47b34362 zephyr: kconfig: Prevent MBEDTLS selection when tinycrypt is used - cd82f8bf boot: zephyr: add support for lpcxpresso55s28 Signed-off-by: Jamie McCrae --- west.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/west.yml b/west.yml index f1fd789503e..fbeb9919eac 100644 --- a/west.yml +++ b/west.yml @@ -282,7 +282,7 @@ manifest: groups: - crypto - name: mcuboot - revision: 0c0470e294dcfb52aab92299356a5f3caa0aa52b + revision: 47b34362552835621bc289d53d2127691088cb7c path: bootloader/mcuboot - name: mipi-sys-t path: modules/debug/mipi-sys-t From 939b90be4c9a242b4e5dced0c2b00f145ccd671c Mon Sep 17 00:00:00 2001 From: Fabio Baltieri Date: Thu, 16 Nov 2023 16:26:38 +0000 Subject: [PATCH 0125/3723] drivers: drop few redundant guard around pm_policy_state_lock_* The pm_policy_state_lock_put and pm_policy_state_lock_put functions already become a no-op if CONFIG_PM is not enabled. Drop the guards around it in few different drivers. Signed-off-by: Fabio Baltieri --- drivers/display/display_rm67162.c | 18 +++++++----------- drivers/dma/dma_mcux_smartdma.c | 12 ++++++------ drivers/eeprom/eeprom_mchp_xec.c | 11 +++-------- drivers/kscan/kscan_mchp_xec.c | 6 ++---- drivers/ps2/ps2_mchp_xec.c | 16 ++++++---------- drivers/sensor/mchp_tach_xec/tach_mchp_xec.c | 7 +++---- 6 files changed, 27 insertions(+), 43 deletions(-) diff --git a/drivers/display/display_rm67162.c b/drivers/display/display_rm67162.c index 5516e57789d..afb7f4dd851 100644 --- a/drivers/display/display_rm67162.c +++ b/drivers/display/display_rm67162.c @@ -434,18 +434,14 @@ static int rm67162_write(const struct device *dev, const uint16_t x, * give to the TE semaphore) before sending the frame */ if (config->te_gpio.port != NULL) { - if (IS_ENABLED(CONFIG_PM)) { - /* Block sleep state until next TE interrupt - * so we can send frame during that interval - */ - pm_policy_state_lock_get(PM_STATE_SUSPEND_TO_IDLE, - PM_ALL_SUBSTATES); - } + /* Block sleep state until next TE interrupt so we can send + * frame during that interval + */ + pm_policy_state_lock_get(PM_STATE_SUSPEND_TO_IDLE, + PM_ALL_SUBSTATES); k_sem_take(&data->te_sem, K_FOREVER); - if (IS_ENABLED(CONFIG_PM)) { - pm_policy_state_lock_put(PM_STATE_SUSPEND_TO_IDLE, - PM_ALL_SUBSTATES); - } + pm_policy_state_lock_put(PM_STATE_SUSPEND_TO_IDLE, + PM_ALL_SUBSTATES); } src = buf; first_cmd = true; diff --git a/drivers/dma/dma_mcux_smartdma.c b/drivers/dma/dma_mcux_smartdma.c index b1870b3959c..9899797ae53 100644 --- a/drivers/dma/dma_mcux_smartdma.c +++ b/drivers/dma/dma_mcux_smartdma.c @@ -148,12 +148,12 @@ static int dma_mcux_smartdma_start(const struct device *dev, uint32_t channel) { const struct dma_mcux_smartdma_config *config = dev->config; -#ifdef CONFIG_PM /* Block PM transition until DMA completes */ pm_policy_state_lock_get(PM_STATE_SUSPEND_TO_IDLE, PM_ALL_SUBSTATES); -#endif + /* Kick off SMARTDMA */ config->base->CTRL = SMARTDMA_MAGIC | SMARTDMA_BOOT; + return 0; } @@ -162,12 +162,13 @@ static int dma_mcux_smartdma_stop(const struct device *dev, uint32_t channel) { ARG_UNUSED(dev); ARG_UNUSED(channel); + /* Stop DMA */ SMARTDMA_Reset(); -#ifdef CONFIG_PM + /* Release PM lock */ pm_policy_state_lock_put(PM_STATE_SUSPEND_TO_IDLE, PM_ALL_SUBSTATES); -#endif + return 0; } @@ -195,10 +196,9 @@ static void dma_mcux_smartdma_irq(const struct device *dev) if (data->callback) { data->callback(dev, data->user_data, 0, 0); } -#ifdef CONFIG_PM + /* Release PM lock */ pm_policy_state_lock_put(PM_STATE_SUSPEND_TO_IDLE, PM_ALL_SUBSTATES); -#endif } /** diff --git a/drivers/eeprom/eeprom_mchp_xec.c b/drivers/eeprom/eeprom_mchp_xec.c index bd1c83e4c74..171940a008d 100644 --- a/drivers/eeprom/eeprom_mchp_xec.c +++ b/drivers/eeprom/eeprom_mchp_xec.c @@ -241,9 +241,8 @@ static int eeprom_xec_read(const struct device *dev, off_t offset, } k_mutex_lock(&data->lock_mtx, K_FOREVER); -#ifdef CONFIG_PM_DEVICE pm_policy_state_lock_get(PM_STATE_SUSPEND_TO_IDLE, PM_ALL_SUBSTATES); -#endif + /* EEPROM HW READ */ for (chunk_idx = 0; chunk_idx < len; chunk_idx += XEC_EEPROM_TRANSFER_SIZE_READ) { if ((len-chunk_idx) < XEC_EEPROM_TRANSFER_SIZE_READ) { @@ -252,9 +251,7 @@ static int eeprom_xec_read(const struct device *dev, off_t offset, eeprom_xec_data_read_32_bytes(regs, &data_buf[chunk_idx], chunk_size, (offset+chunk_idx)); } -#ifdef CONFIG_PM_DEVICE pm_policy_state_lock_put(PM_STATE_SUSPEND_TO_IDLE, PM_ALL_SUBSTATES); -#endif k_mutex_unlock(&data->lock_mtx); return 0; @@ -280,9 +277,8 @@ static int eeprom_xec_write(const struct device *dev, off_t offset, } k_mutex_lock(&data->lock_mtx, K_FOREVER); -#ifdef CONFIG_PM_DEVICE pm_policy_state_lock_get(PM_STATE_SUSPEND_TO_IDLE, PM_ALL_SUBSTATES); -#endif + /* EEPROM HW WRITE */ for (chunk_idx = 0; chunk_idx < len; chunk_idx += XEC_EEPROM_TRANSFER_SIZE_WRITE) { if ((len-chunk_idx) < XEC_EEPROM_TRANSFER_SIZE_WRITE) { @@ -291,9 +287,8 @@ static int eeprom_xec_write(const struct device *dev, off_t offset, eeprom_xec_data_write_32_bytes(regs, &data_buf[chunk_idx], chunk_size, (offset+chunk_idx)); } -#ifdef CONFIG_PM_DEVICE + pm_policy_state_lock_put(PM_STATE_SUSPEND_TO_IDLE, PM_ALL_SUBSTATES); -#endif k_mutex_unlock(&data->lock_mtx); return 0; diff --git a/drivers/kscan/kscan_mchp_xec.c b/drivers/kscan/kscan_mchp_xec.c index e0960b1c946..e3e8fa4043e 100644 --- a/drivers/kscan/kscan_mchp_xec.c +++ b/drivers/kscan/kscan_mchp_xec.c @@ -373,9 +373,8 @@ void polling_task(const struct device *dev, void *dummy2, void *dummy3) drive_keyboard_column(dev, KEYBOARD_COLUMN_DRIVE_ALL); k_sem_take(&data->poll_lock, K_FOREVER); -#ifdef CONFIG_PM_DEVICE pm_policy_state_lock_get(PM_STATE_SUSPEND_TO_IDLE, PM_ALL_SUBSTATES); -#endif + uint32_t start_poll_cycles = k_cycle_get_32(); while (atomic_get(&data->enable_scan) == 1U) { @@ -416,9 +415,8 @@ void polling_task(const struct device *dev, void *dummy2, void *dummy3) /* Allow other threads to run while we sleep */ k_usleep(wait_period); } -#ifdef CONFIG_PM_DEVICE + pm_policy_state_lock_put(PM_STATE_SUSPEND_TO_IDLE, PM_ALL_SUBSTATES); -#endif } } diff --git a/drivers/ps2/ps2_mchp_xec.c b/drivers/ps2/ps2_mchp_xec.c index f3b1a9e10bf..0a667786912 100644 --- a/drivers/ps2/ps2_mchp_xec.c +++ b/drivers/ps2/ps2_mchp_xec.c @@ -172,9 +172,9 @@ static int ps2_xec_write(const struct device *dev, uint8_t value) LOG_DBG("PS2 write timed out"); return -ETIMEDOUT; } -#ifdef CONFIG_PM_DEVICE + pm_policy_state_lock_get(PM_STATE_SUSPEND_TO_IDLE, PM_ALL_SUBSTATES); -#endif + /* Inhibit ps2 controller and clear status register */ regs->CTRL = 0x00; @@ -306,33 +306,29 @@ static void ps2_xec_isr(const struct device *dev) ps2_xec_girq_clr(config->girq_id, config->girq_bit); if (status & MCHP_PS2_STATUS_RXD_RDY) { -#ifdef CONFIG_PM_DEVICE pm_policy_state_lock_get(PM_STATE_SUSPEND_TO_IDLE, PM_ALL_SUBSTATES); -#endif + regs->CTRL = 0x00; if (data->callback_isr) { data->callback_isr(dev, regs->TRX_BUFF); } -#ifdef CONFIG_PM_DEVICE + pm_policy_state_lock_put(PM_STATE_SUSPEND_TO_IDLE, PM_ALL_SUBSTATES); -#endif } else if (status & (MCHP_PS2_STATUS_TX_TMOUT | MCHP_PS2_STATUS_TX_ST_TMOUT)) { /* Clear sticky bits and go to read mode */ regs->STATUS = MCHP_PS2_STATUS_RW1C_MASK; LOG_ERR("TX time out: %0x", status); -#ifdef CONFIG_PM_DEVICE + pm_policy_state_lock_put(PM_STATE_SUSPEND_TO_IDLE, PM_ALL_SUBSTATES); -#endif } else if (status & (MCHP_PS2_STATUS_RX_TMOUT | MCHP_PS2_STATUS_PE | MCHP_PS2_STATUS_FE)) { /* catch and clear rx error if any */ regs->STATUS = MCHP_PS2_STATUS_RW1C_MASK; } else if (status & MCHP_PS2_STATUS_TX_IDLE) { /* Transfer completed, release the lock to enter low per mode */ -#ifdef CONFIG_PM_DEVICE + pm_policy_state_lock_put(PM_STATE_SUSPEND_TO_IDLE, PM_ALL_SUBSTATES); -#endif } /* The control register reverts to RX automatically after diff --git a/drivers/sensor/mchp_tach_xec/tach_mchp_xec.c b/drivers/sensor/mchp_tach_xec/tach_mchp_xec.c index 49fbbac8fe2..12cd63ee316 100644 --- a/drivers/sensor/mchp_tach_xec/tach_mchp_xec.c +++ b/drivers/sensor/mchp_tach_xec/tach_mchp_xec.c @@ -58,9 +58,8 @@ int tach_xec_sample_fetch(const struct device *dev, enum sensor_channel chan) struct tach_regs * const tach = cfg->regs; uint8_t poll_count = 0; -#ifdef CONFIG_PM_DEVICE pm_policy_state_lock_get(PM_STATE_SUSPEND_TO_IDLE, PM_ALL_SUBSTATES); -#endif + while (poll_count < PIN_STS_TIMEOUT) { /* See whether internal counter is already latched */ if (tach->STATUS & MCHP_TACH_STS_CNT_RDY) { @@ -74,9 +73,9 @@ int tach_xec_sample_fetch(const struct device *dev, enum sensor_channel chan) /* Allow other threads to run while we sleep */ k_usleep(USEC_PER_MSEC); } -#ifdef CONFIG_PM_DEVICE + pm_policy_state_lock_put(PM_STATE_SUSPEND_TO_IDLE, PM_ALL_SUBSTATES); -#endif + if (poll_count == PIN_STS_TIMEOUT) { return -EINVAL; } From 43d5f392090dd5060d056a527917312bef913864 Mon Sep 17 00:00:00 2001 From: Bartosz Bilas Date: Wed, 22 Nov 2023 15:40:15 +0100 Subject: [PATCH 0126/3723] zbus: add MULTITHREADING dependency Zbus uses mutexes internally that are available only when MULTITHREADING is enabled so add it to fix the following error: /opt/zephyr-sdk-0.16.3/arm-zephyr-eabi/bin/../lib/gcc/arm-zephyr-eabi/ 12.2.0/../../../../arm-zephyr-eabi/bin/ld.bfd: zephyr/subsys/ zbus/libsubsys__zbus.a(zbus.c.obj): in function `k_mutex_init': /builds/zephyr/mcuboot/zephyr/include/generated/syscalls/kernel.h:969: undefined reference to `z_impl_k_mutex_init' Signed-off-by: Bartosz Bilas --- subsys/zbus/Kconfig | 1 + 1 file changed, 1 insertion(+) diff --git a/subsys/zbus/Kconfig b/subsys/zbus/Kconfig index f250865b466..ba1c9dd08d0 100644 --- a/subsys/zbus/Kconfig +++ b/subsys/zbus/Kconfig @@ -3,6 +3,7 @@ menuconfig ZBUS bool "Zbus support" + depends on MULTITHREADING help Enables support for Zephyr message bus. From 46889819e6d2fbc3e8ff919f0f695faee55438c8 Mon Sep 17 00:00:00 2001 From: Jamie McCrae Date: Wed, 22 Nov 2023 10:12:11 +0000 Subject: [PATCH 0127/3723] cmake: modules: dts: Fix board revision 0 overlay Fixes an issue whereby a board revision is 0 and the overlay file exists but would not be included Signed-off-by: Jamie McCrae --- cmake/modules/dts.cmake | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cmake/modules/dts.cmake b/cmake/modules/dts.cmake index c9ac751a1e5..23659c18692 100644 --- a/cmake/modules/dts.cmake +++ b/cmake/modules/dts.cmake @@ -125,7 +125,7 @@ set(VENDOR_PREFIXES dts/bindings/vendor-prefixes.txt) set_ifndef(DTS_SOURCE ${BOARD_DIR}/${BOARD}.dts) if(EXISTS ${DTS_SOURCE}) # We found a devicetree. Check for a board revision overlay. - if(BOARD_REVISION AND EXISTS ${BOARD_DIR}/${BOARD}_${BOARD_REVISION_STRING}.overlay) + if(DEFINED BOARD_REVISION AND EXISTS ${BOARD_DIR}/${BOARD}_${BOARD_REVISION_STRING}.overlay) list(APPEND DTS_SOURCE ${BOARD_DIR}/${BOARD}_${BOARD_REVISION_STRING}.overlay) endif() else() From d34f725df81852b468dba2727a4d569022cb907d Mon Sep 17 00:00:00 2001 From: Marek Matej Date: Thu, 16 Nov 2023 19:28:13 +0100 Subject: [PATCH 0128/3723] soc: xtensa: esp32s3: Update SOC variant list Add missing combinations of the ESP32-S3 Wroom module. Signed-off-by: Marek Matej --- .../espressif/esp32s3/esp32s3_wroom_n16r2.dtsi | 18 ++++++++++++++++++ .../espressif/esp32s3/esp32s3_wroom_n4r2.dtsi | 18 ++++++++++++++++++ .../espressif/esp32s3/esp32s3_wroom_n8r2.dtsi | 18 ++++++++++++++++++ .../espressif/esp32s3/esp32s3_wroom_n8r8.dtsi | 1 + soc/xtensa/espressif_esp32/esp32s3/Kconfig.soc | 8 +++++++- 5 files changed, 62 insertions(+), 1 deletion(-) create mode 100644 dts/xtensa/espressif/esp32s3/esp32s3_wroom_n16r2.dtsi create mode 100644 dts/xtensa/espressif/esp32s3/esp32s3_wroom_n4r2.dtsi create mode 100644 dts/xtensa/espressif/esp32s3/esp32s3_wroom_n8r2.dtsi diff --git a/dts/xtensa/espressif/esp32s3/esp32s3_wroom_n16r2.dtsi b/dts/xtensa/espressif/esp32s3/esp32s3_wroom_n16r2.dtsi new file mode 100644 index 00000000000..c4c0929063d --- /dev/null +++ b/dts/xtensa/espressif/esp32s3/esp32s3_wroom_n16r2.dtsi @@ -0,0 +1,18 @@ +/* + * Copyright (c) 2023 Espressif Systems (Shanghai) Co., Ltd. + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include "esp32s3_common.dtsi" + +/* 16MB flash */ +&flash0 { + reg = <0x0 DT_SIZE_M(16)>; +}; + +/* 2MB psram */ +&psram0 { + reg = <0x3c000000 DT_SIZE_M(2)>; + status = "okay"; +}; diff --git a/dts/xtensa/espressif/esp32s3/esp32s3_wroom_n4r2.dtsi b/dts/xtensa/espressif/esp32s3/esp32s3_wroom_n4r2.dtsi new file mode 100644 index 00000000000..b8f733a3c54 --- /dev/null +++ b/dts/xtensa/espressif/esp32s3/esp32s3_wroom_n4r2.dtsi @@ -0,0 +1,18 @@ +/* + * Copyright (c) 2023 Espressif Systems (Shanghai) Co., Ltd. + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include "esp32s3_common.dtsi" + +/* 4MB flash */ +&flash0 { + reg = <0x0 DT_SIZE_M(4)>; +}; + +/* 2MB psram */ +&psram0 { + reg = <0x3c000000 DT_SIZE_M(2)>; + status = "okay"; +}; diff --git a/dts/xtensa/espressif/esp32s3/esp32s3_wroom_n8r2.dtsi b/dts/xtensa/espressif/esp32s3/esp32s3_wroom_n8r2.dtsi new file mode 100644 index 00000000000..b77169f172b --- /dev/null +++ b/dts/xtensa/espressif/esp32s3/esp32s3_wroom_n8r2.dtsi @@ -0,0 +1,18 @@ +/* + * Copyright (c) 2023 Espressif Systems (Shanghai) Co., Ltd. + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include "esp32s3_common.dtsi" + +/* 8MB flash */ +&flash0 { + reg = <0x0 DT_SIZE_M(8)>; +}; + +/* 2MB psram */ +&psram0 { + reg = <0x3c000000 DT_SIZE_M(2)>; + status = "okay"; +}; diff --git a/dts/xtensa/espressif/esp32s3/esp32s3_wroom_n8r8.dtsi b/dts/xtensa/espressif/esp32s3/esp32s3_wroom_n8r8.dtsi index eac737e3d61..34ec0ec5ac1 100644 --- a/dts/xtensa/espressif/esp32s3/esp32s3_wroom_n8r8.dtsi +++ b/dts/xtensa/espressif/esp32s3/esp32s3_wroom_n8r8.dtsi @@ -14,4 +14,5 @@ /* 8MB psram */ &psram0 { reg = <0x3c000000 DT_SIZE_M(8)>; + status = "okay"; }; diff --git a/soc/xtensa/espressif_esp32/esp32s3/Kconfig.soc b/soc/xtensa/espressif_esp32/esp32s3/Kconfig.soc index b8cc95b62cb..ad8b4b4234b 100644 --- a/soc/xtensa/espressif_esp32/esp32s3/Kconfig.soc +++ b/soc/xtensa/espressif_esp32/esp32s3/Kconfig.soc @@ -43,7 +43,13 @@ choice SOC_PART_NUMBER config SOC_ESP32S3_WROOM_N8R8 bool "ESP32S3_WROOM_N8R8" config SOC_ESP32S3_WROOM_N16R8 - bool "ESP32S3_WROOM_N16" + bool "ESP32S3_WROOM_N16R8" + config SOC_ESP32S3_WROOM_N4R2 + bool "ESP32S3_WROOM_N4R2" + config SOC_ESP32S3_WROOM_N8R2 + bool "ESP32S3_WROOM_N8R2" + config SOC_ESP32S3_WROOM_N16R2 + bool "ESP32S3_WROOM_N16R2" endchoice # SOC_PART_NUMBER From d9fd752392624285d906838c9271448421f85c37 Mon Sep 17 00:00:00 2001 From: Fabio Baltieri Date: Wed, 22 Nov 2023 20:35:40 +0000 Subject: [PATCH 0129/3723] sensor: mchp_tach_xec: drop PM_DEVICE guards These are not needed and are now causing build errors since the pm_device calls are always there and need the header to become a no-op. Signed-off-by: Fabio Baltieri --- drivers/sensor/mchp_tach_xec/tach_mchp_xec.c | 2 -- 1 file changed, 2 deletions(-) diff --git a/drivers/sensor/mchp_tach_xec/tach_mchp_xec.c b/drivers/sensor/mchp_tach_xec/tach_mchp_xec.c index 12cd63ee316..9ee732475da 100644 --- a/drivers/sensor/mchp_tach_xec/tach_mchp_xec.c +++ b/drivers/sensor/mchp_tach_xec/tach_mchp_xec.c @@ -22,9 +22,7 @@ #include #include -#ifdef CONFIG_PM_DEVICE #include -#endif LOG_MODULE_REGISTER(tach_xec, CONFIG_SENSOR_LOG_LEVEL); From 5efa5b28926097becd6aa4f7ab42a2966f6c2a1e Mon Sep 17 00:00:00 2001 From: Fabio Baltieri Date: Wed, 22 Nov 2023 17:30:45 +0000 Subject: [PATCH 0130/3723] tests: drop input_ prefix from input tests These are already in a "input" subdirectory, the prefix is redundant, drop it. Signed-off-by: Fabio Baltieri --- tests/subsys/input/{input_longpress => longpress}/CMakeLists.txt | 0 .../{input_longpress => longpress}/boards/native_sim.overlay | 0 .../{input_longpress => longpress}/boards/native_sim_64.overlay | 0 tests/subsys/input/{input_longpress => longpress}/prj.conf | 0 tests/subsys/input/{input_longpress => longpress}/src/main.c | 0 tests/subsys/input/{input_longpress => longpress}/testcase.yaml | 0 tests/subsys/input/{input_shell => shell}/CMakeLists.txt | 0 tests/subsys/input/{input_shell => shell}/prj.conf | 0 tests/subsys/input/{input_shell => shell}/src/main.c | 0 tests/subsys/input/{input_shell => shell}/testcase.yaml | 0 10 files changed, 0 insertions(+), 0 deletions(-) rename tests/subsys/input/{input_longpress => longpress}/CMakeLists.txt (100%) rename tests/subsys/input/{input_longpress => longpress}/boards/native_sim.overlay (100%) rename tests/subsys/input/{input_longpress => longpress}/boards/native_sim_64.overlay (100%) rename tests/subsys/input/{input_longpress => longpress}/prj.conf (100%) rename tests/subsys/input/{input_longpress => longpress}/src/main.c (100%) rename tests/subsys/input/{input_longpress => longpress}/testcase.yaml (100%) rename tests/subsys/input/{input_shell => shell}/CMakeLists.txt (100%) rename tests/subsys/input/{input_shell => shell}/prj.conf (100%) rename tests/subsys/input/{input_shell => shell}/src/main.c (100%) rename tests/subsys/input/{input_shell => shell}/testcase.yaml (100%) diff --git a/tests/subsys/input/input_longpress/CMakeLists.txt b/tests/subsys/input/longpress/CMakeLists.txt similarity index 100% rename from tests/subsys/input/input_longpress/CMakeLists.txt rename to tests/subsys/input/longpress/CMakeLists.txt diff --git a/tests/subsys/input/input_longpress/boards/native_sim.overlay b/tests/subsys/input/longpress/boards/native_sim.overlay similarity index 100% rename from tests/subsys/input/input_longpress/boards/native_sim.overlay rename to tests/subsys/input/longpress/boards/native_sim.overlay diff --git a/tests/subsys/input/input_longpress/boards/native_sim_64.overlay b/tests/subsys/input/longpress/boards/native_sim_64.overlay similarity index 100% rename from tests/subsys/input/input_longpress/boards/native_sim_64.overlay rename to tests/subsys/input/longpress/boards/native_sim_64.overlay diff --git a/tests/subsys/input/input_longpress/prj.conf b/tests/subsys/input/longpress/prj.conf similarity index 100% rename from tests/subsys/input/input_longpress/prj.conf rename to tests/subsys/input/longpress/prj.conf diff --git a/tests/subsys/input/input_longpress/src/main.c b/tests/subsys/input/longpress/src/main.c similarity index 100% rename from tests/subsys/input/input_longpress/src/main.c rename to tests/subsys/input/longpress/src/main.c diff --git a/tests/subsys/input/input_longpress/testcase.yaml b/tests/subsys/input/longpress/testcase.yaml similarity index 100% rename from tests/subsys/input/input_longpress/testcase.yaml rename to tests/subsys/input/longpress/testcase.yaml diff --git a/tests/subsys/input/input_shell/CMakeLists.txt b/tests/subsys/input/shell/CMakeLists.txt similarity index 100% rename from tests/subsys/input/input_shell/CMakeLists.txt rename to tests/subsys/input/shell/CMakeLists.txt diff --git a/tests/subsys/input/input_shell/prj.conf b/tests/subsys/input/shell/prj.conf similarity index 100% rename from tests/subsys/input/input_shell/prj.conf rename to tests/subsys/input/shell/prj.conf diff --git a/tests/subsys/input/input_shell/src/main.c b/tests/subsys/input/shell/src/main.c similarity index 100% rename from tests/subsys/input/input_shell/src/main.c rename to tests/subsys/input/shell/src/main.c diff --git a/tests/subsys/input/input_shell/testcase.yaml b/tests/subsys/input/shell/testcase.yaml similarity index 100% rename from tests/subsys/input/input_shell/testcase.yaml rename to tests/subsys/input/shell/testcase.yaml From 3b4523588724d52c2e037d65fbe98ae4f06097d2 Mon Sep 17 00:00:00 2001 From: Christopher Friedt Date: Thu, 12 Oct 2023 20:02:16 -0400 Subject: [PATCH 0131/3723] doc: posix: structural reorganization of posix docs Revise the structure of the POSIX API docs. This separates related items out to dedicated pages. Further improvements could yet be made - e.g. using the 'collapse' feature to expand and collapse large sections of text or tables. Signed-off-by: Christopher Friedt --- doc/_scripts/redirects.py | 2 +- doc/introduction/index.rst | 2 + doc/services/portability/index.rst | 2 +- doc/services/portability/posix/aep/index.rst | 191 ++++++++ .../portability/posix/conformance/index.rst | 145 +++++++ .../posix/implementation/index.rst | 77 ++++ doc/services/portability/posix/index.rst | 14 + .../portability/posix/kconfig/index.rst | 52 +++ .../option_groups/index.rst} | 408 ++++++++++-------- .../portability/posix/overview/index.rst | 135 ++++++ .../{ => posix/overview}/posix.svg | 2 +- 11 files changed, 851 insertions(+), 179 deletions(-) create mode 100644 doc/services/portability/posix/aep/index.rst create mode 100644 doc/services/portability/posix/conformance/index.rst create mode 100644 doc/services/portability/posix/implementation/index.rst create mode 100644 doc/services/portability/posix/index.rst create mode 100644 doc/services/portability/posix/kconfig/index.rst rename doc/services/portability/{posix.rst => posix/option_groups/index.rst} (57%) create mode 100644 doc/services/portability/posix/overview/index.rst rename doc/services/portability/{ => posix/overview}/posix.svg (68%) diff --git a/doc/_scripts/redirects.py b/doc/_scripts/redirects.py index 0180d1f5373..78c5c8ed84f 100644 --- a/doc/_scripts/redirects.py +++ b/doc/_scripts/redirects.py @@ -71,7 +71,7 @@ ('guides/pm/power_domain', 'services/pm/power_domain'), ('guides/pm/system', 'services/pm/system'), ('guides/portability/index', 'services/portability/index'), - ('guides/portability/posix', 'services/portability/posix'), + ('guides/portability/posix', 'services/portability/posix/index'), ('guides/porting/arch', 'hardware/porting/arch'), ('guides/porting/board_porting', 'hardware/porting/board_porting'), ('guides/porting/index', 'hardware/porting/index'), diff --git a/doc/introduction/index.rst b/doc/introduction/index.rst index 85968ca456a..985ffe8e002 100644 --- a/doc/introduction/index.rst +++ b/doc/introduction/index.rst @@ -80,6 +80,8 @@ Zephyr offers a large and ever growing number of features including: * Red/black tree ready queue * Traditional multi-queue ready queue +.. _zephyr_intro_configurability: + **Highly configurable / Modular for flexibility** Allows an application to incorporate *only* the capabilities it needs as it needs them, and to specify their quantity and size. diff --git a/doc/services/portability/index.rst b/doc/services/portability/index.rst index 18b1a83c95f..357aa778514 100644 --- a/doc/services/portability/index.rst +++ b/doc/services/portability/index.rst @@ -14,6 +14,6 @@ supported by the Zephyr RTOS. .. toctree:: :maxdepth: 1 - posix.rst + posix/index.rst cmsis_rtos_v1.rst cmsis_rtos_v2.rst diff --git a/doc/services/portability/posix/aep/index.rst b/doc/services/portability/posix/aep/index.rst new file mode 100644 index 00000000000..857635c1031 --- /dev/null +++ b/doc/services/portability/posix/aep/index.rst @@ -0,0 +1,191 @@ +.. _posix_aep: + +POSIX Application Environment Profiles (AEP) +############################################ + +Although inactive, `IEEE 1003.13-2003`_ defined a number of AEP that inspired the modern +subprofiling options of `IEEE 1003.1-2017`_. The single-purpose realtime system profiles +are listed below, for reference, in terms that agree with the current POSIX-1 standard. PSE54 +is not considered at this time. + +.. _posix_aep_pse51: + +Minimal Realtime System Profile (PSE51) +======================================= + +.. Conforming implementations shall define _POSIX_AEP_REALTIME_MINIMAL to the value 200312L + +.. csv-table:: PSE51 System Interfaces + :header: Symbol, Support, Remarks + :widths: 50, 10, 50 + + _POSIX_AEP_REALTIME_MINIMAL, -1, + +.. csv-table:: PSE51 Option Groups + :header: Symbol, Support, Remarks + :widths: 50, 10, 50 + + POSIX_C_LANG_JUMP,, + POSIX_C_LANG_SUPPORT, yes, :ref:`†` + POSIX_DEVICE_IO,, :ref:`†` + POSIX_FILE_LOCKING,, + POSIX_SIGNALS,, :ref:`†` + POSIX_SINGLE_PROCESS,, :ref:`†` + POSIX_THREADS_BASE, yes, :ref:`†` + XSI_THREADS_EXT, yes, :ref:`†` + +.. csv-table:: PSE51 Option Requirements + :header: Symbol, Support, Remarks + :widths: 50, 10, 50 + + _POSIX_CLOCK_SELECTION, 200809L, :kconfig:option:`CONFIG_POSIX_CLOCK` + _POSIX_FSYNC, -1, + _POSIX_MEMLOCK, -1, + _POSIX_MEMLOCK_RANGE, -1, + _POSIX_MONOTONIC_CLOCK, 200809L, :kconfig:option:`CONFIG_POSIX_CLOCK` + _POSIX_REALTIME_SIGNALS, -1, + _POSIX_SEMAPHORES, 200809L, :kconfig:option:`CONFIG_PTHREAD_IPC` + _POSIX_SHARED_MEMORY_OBJECTS, -1, + _POSIX_SYNCHRONIZED_IO, -1, + _POSIX_THREAD_ATTR_STACKADDR, 200809L, :kconfig:option:`CONFIG_PTHREAD` + _POSIX_THREAD_ATTR_STACKSIZE, 200809L, :kconfig:option:`CONFIG_PTHREAD` + _POSIX_THREAD_CPUTIME, -1, + _POSIX_THREAD_PRIO_INHERIT, 200809L, :kconfig:option:`CONFIG_PTHREAD_MUTEX` + _POSIX_THREAD_PRIO_PROTECT, -1, + _POSIX_THREAD_PRIORITY_SCHEDULING, -1, + _POSIX_THREAD_SPORADIC_SERVER, -1, + _POSIX_TIMEOUTS, 200809L, :kconfig:option:`CONFIG_PTHREAD_IPC` + _POSIX_TIMERS, 200809L, :kconfig:option:`CONFIG_POSIX_CLOCK` + +.. note:: + For PSE51 support, 44 of 75 symbols are currently implemented. + +.. _posix_aep_pse52: + +Realtime Controller System Profile (PSE52) +========================================== + +.. Conforming implementations shall define _POSIX_AEP_REALTIME_CONTROLLER to the value 200312L + +.. csv-table:: PSE52 System Interfaces + :header: Symbol, Support, Remarks + :widths: 50, 10, 50 + + _POSIX_AEP_REALTIME_CONTROLLER, -1, + +.. csv-table:: PSE52 Option Groups + :header: Symbol, Support, Remarks + :widths: 50, 10, 50 + + POSIX_C_LANG_JUMP,, + POSIX_C_LANG_MATH, yes, + POSIX_C_LANG_SUPPORT, yes, :ref:`†` + POSIX_DEVICE_IO,, :ref:`†` + POSIX_FD_MGMT,, + POSIX_FILE_LOCKING,, + POSIX_FILE_SYSTEM,, + POSIX_SIGNALS,, :ref:`†` + POSIX_SINGLE_PROCESS,, :ref:`†` + POSIX_THREADS_BASE, yes, :ref:`†` + XSI_THREADS_EXT, yes, :ref:`†` + +.. csv-table:: PSE52 Option Requirements + :header: Symbol, Support, Remarks + :widths: 50, 10, 50 + + _POSIX_CLOCK_SELECTION, 200809L, :kconfig:option:`CONFIG_POSIX_CLOCK` + _POSIX_FSYNC, -1, + _POSIX_MAPPED_FILES, -1, + _POSIX_MEMLOCK, -1, + _POSIX_MEMLOCK_RANGE, -1, + _POSIX_MESSAGE_PASSING, 200809L, :kconfig:option:`CONFIG_POSIX_MQUEUE` + _POSIX_MONOTONIC_CLOCK, 200809L, :kconfig:option:`CONFIG_POSIX_CLOCK` + _POSIX_REALTIME_SIGNALS, -1, + _POSIX_SEMAPHORES, 200809L, :kconfig:option:`CONFIG_PTHREAD_IPC` + _POSIX_SHARED_MEMORY_OBJECTS, -1, + _POSIX_SYNCHRONIZED_IO, -1, + _POSIX_THREAD_ATTR_STACKADDR, 200809L, :kconfig:option:`CONFIG_PTHREAD` + _POSIX_THREAD_ATTR_STACKSIZE, 200809L, :kconfig:option:`CONFIG_PTHREAD` + _POSIX_THREAD_CPUTIME, -1, + _POSIX_THREAD_PRIO_INHERIT, 200809L, :kconfig:option:`CONFIG_PTHREAD_MUTEX` + _POSIX_THREAD_PRIO_PROTECT, -1, + _POSIX_THREAD_PRIORITY_SCHEDULING, -1, + _POSIX_THREAD_SPORADIC_SERVER, -1, + _POSIX_TIMEOUTS, 200809L, :kconfig:option:`CONFIG_PTHREAD_IPC` + _POSIX_TIMERS, 200809L, :kconfig:option:`CONFIG_POSIX_CLOCK` + _POSIX_TRACE, -1, + _POSIX_TRACE_EVENT_FILTER, -1, + _POSIX_TRACE_LOG, -1, + +.. _posix_aep_pse53: + +Dedicated Realtime System Profile (PSE53) +========================================= + +.. Conforming implementations shall define _POSIX_AEP_REALTIME_MINIMAL to the value 200312L + +.. csv-table:: PSE53 System Interfaces + :header: Symbol, Support, Remarks + :widths: 50, 10, 50 + + _POSIX_AEP_REALTIME_CONTROLLER, -1, + +.. csv-table:: PSE53 Option Groups + :header: Symbol, Support, Remarks + :widths: 50, 10, 50 + + POSIX_C_LANG_JUMP,, + POSIX_C_LANG_MATH, yes, + POSIX_C_LANG_SUPPORT, yes, :ref:`†` + POSIX_DEVICE_IO,, :ref:`†` + POSIX_FD_MGMT,, + POSIX_FILE_LOCKING,, + POSIX_FILE_SYSTEM,, + POSIX_MULTI_PROCESS,, :ref:`†` + POSIX_NETWORKING, yes, :ref:`†` + POSIX_PIPE,, :ref:`†` + POSIX_SIGNALS,, :ref:`†` + POSIX_SIGNAL_JUMP,, :ref:`†` + POSIX_SINGLE_PROCESS,, :ref:`†` + POSIX_THREADS_BASE, yes, :ref:`†` + XSI_THREADS_EXT, yes, :ref:`†` + +.. csv-table:: PSE53 Option Requirements + :header: Symbol, Support, Remarks + :widths: 50, 10, 50 + + _POSIX_ASYNCHRONOUS_IO, -1, + _POSIX_CLOCK_SELECTION, 200809L, :kconfig:option:`CONFIG_POSIX_CLOCK` + _POSIX_CPUTIME, -1, + _POSIX_FSYNC, -1, + _POSIX_MAPPED_FILES, -1, + _POSIX_MEMLOCK, -1, + _POSIX_MEMLOCK_RANGE, -1, + _POSIX_MEMORY_PROTECTION, -1, + _POSIX_MESSAGE_PASSING, 200809L, :kconfig:option:`CONFIG_POSIX_MQUEUE` + _POSIX_MONOTONIC_CLOCK, 200809L, :kconfig:option:`CONFIG_POSIX_CLOCK` + _POSIX_PRIORITIZED_IO, -1, + _POSIX_PRIORITY_SCHEDULING, -1, + _POSIX_RAW_SOCKETS, 200809L, :kconfig:option:`CONFIG_NET_SOCKETS` + _POSIX_REALTIME_SIGNALS, -1, + _POSIX_SEMAPHORES, 200809L, :kconfig:option:`CONFIG_PTHREAD_IPC` + _POSIX_SHARED_MEMORY_OBJECTS, -1, + _POSIX_SPAWN, -1, + _POSIX_SPORADIC_SERVER, -1, + _POSIX_SYNCHRONIZED_IO, -1, + _POSIX_THREAD_ATTR_STACKADDR, 200809L, :kconfig:option:`CONFIG_PTHREAD` + _POSIX_THREAD_ATTR_STACKSIZE, 200809L, :kconfig:option:`CONFIG_PTHREAD` + _POSIX_THREAD_CPUTIME, -1, + _POSIX_THREAD_PRIO_INHERIT, 200809L, :kconfig:option:`CONFIG_PTHREAD_MUTEX` + _POSIX_THREAD_PRIO_PROTECT, -1, + _POSIX_THREAD_PRIORITY_SCHEDULING, -1, + _POSIX_THREAD_PROCESS_SHARED, -1, + _POSIX_THREAD_SPORADIC_SERVER, -1, + _POSIX_TIMEOUTS, 200809L, :kconfig:option:`CONFIG_PTHREAD_IPC` + _POSIX_TIMERS, 200809L, :kconfig:option:`CONFIG_POSIX_CLOCK` + _POSIX_TRACE, -1, + _POSIX_TRACE_EVENT_FILTER, -1, + _POSIX_TRACE_LOG, -1, + +.. _IEEE 1003.1-2017: https://standards.ieee.org/ieee/1003.1/7101/ +.. _IEEE 1003.13-2003: https://standards.ieee.org/ieee/1003.13/3322/ diff --git a/doc/services/portability/posix/conformance/index.rst b/doc/services/portability/posix/conformance/index.rst new file mode 100644 index 00000000000..7d28efcf9ac --- /dev/null +++ b/doc/services/portability/posix/conformance/index.rst @@ -0,0 +1,145 @@ +.. _posix_conformance: + +POSIX Conformance +################# + +As per `IEEE 1003.1-2017`, this section details Zephyr's POSIX conformance. + +.. _posix_undefined_behaviour: + +.. note:: + As per POSIX 1003.13, single process mode is supported directly by both PSE51 and PSE52 + profiles. While Zephyr includes support for many features found in PSE53, PSE53 itself requires + supporting multiple processes. Since supporting multiple processes is beyond the scope of + Zephyr's current design, some features requiring multi-process capabilities may exhibit + undefined behaviour, which we denote with the † (obelus) symbol. + +.. _posix_system_interfaces: + +POSIX System Interfaces +======================= + +.. The following have values greater than -1 in Zephyr, conformant with the POSIX specification. + +.. csv-table:: POSIX System Interfaces + :header: Symbol, Support, Remarks + :widths: 50, 10, 50 + + _POSIX_CHOWN_RESTRICTED, 0, + _POSIX_NO_TRUNC, 0, + _POSIX_VDISABLE, 0, + +.. The following should be valued greater than zero in Zephyr, in order to be strictly conformant + with the POSIX specification. + +.. csv-table:: POSIX System Interfaces + :header: Symbol, Support, Remarks + :widths: 50, 10, 50 + + _POSIX_JOB_CONTROL, -1, :ref:`†` + _POSIX_REGEXP, -1, :ref:`†` + _POSIX_SAVED_IDS, -1, :ref:`†` + _POSIX_SHELL, -1, :ref:`†` + +.. TODO: POSIX_ASYNCHRONOUS_IO, and other interfaces below, are mandatory. That means that a + strictly conforming application need not be modified in order to compile against Zephyr. + However, we may add implementations that simply fail with ENOSYS as long as the functional + modification is clearly documented. The implementation is not required for PSE51 or PSE52 + and beyond that POSIX async I/O functions are rarely used in practice. + +.. csv-table:: POSIX System Interfaces + :header: Symbol, Support, Remarks + :widths: 50, 10, 50 + + _POSIX_VERSION, 200809L, + _POSIX_ASYNCHRONOUS_IO, -1, :ref:`†` + :ref:`_POSIX_BARRIERS`, 200809L, :kconfig:option:`CONFIG_PTHREAD_BARRIER` + :ref:`_POSIX_CLOCK_SELECTION`, 200809L, :kconfig:option:`CONFIG_POSIX_CLOCK` + _POSIX_MAPPED_FILES, -1, :ref:`†` + _POSIX_MEMORY_PROTECTION, -1, :ref:`†` + :ref:`_POSIX_READER_WRITER_LOCKS`, -1, :kconfig:option:`CONFIG_PTHREAD_IPC` + _POSIX_REALTIME_SIGNALS, -1, :ref:`†` + :ref:`_POSIX_SEMAPHORES`, 200809L, :kconfig:option:`CONFIG_PTHREAD_IPC` + :ref:`_POSIX_SPIN_LOCKS`, 200809L, :kconfig:option:`CONFIG_PTHREAD_SPINLOCK` + _POSIX_THREAD_SAFE_FUNCTIONS, 200809L, + :ref:`_POSIX_THREADS`, -1, :kconfig:option:`CONFIG_PTHREAD_IPC` + :ref:`_POSIX_TIMEOUTS`, 200809L, :kconfig:option:`CONFIG_PTHREAD_IPC` + :ref:`_POSIX_TIMERS`, 200809L, :kconfig:option:`CONFIG_POSIX_CLOCK` + _POSIX2_C_BIND, 200809L, + +.. csv-table:: POSIX System Interfaces (Optional) + :header: Symbol, Support, Remarks + :widths: 50, 10, 50 + + _POSIX_ADVISORY_INFO, -1, + _POSIX_CPUTIME, -1, + _POSIX_FSYNC, -1, + _POSIX_IPV6, 200809L, :kconfig:option:`CONFIG_NET_IPV6` + _POSIX_MEMLOCK, -1, + _POSIX_MEMLOCK_RANGE, -1, + :ref:`_POSIX_MESSAGE_PASSING`, 200809L, :kconfig:option:`CONFIG_POSIX_MQUEUE` + _POSIX_MONOTONIC_CLOCK, 200809L, :kconfig:option:`CONFIG_POSIX_CLOCK` + _POSIX_PRIORITIZED_IO, -1, + :ref:`_POSIX_PRIORITY_SCHEDULING`, -1, :kconfig:option:`CONFIG_PTHREAD` + _POSIX_RAW_SOCKETS, 200809L, :kconfig:option:`CONFIG_NET_SOCKETS` + _POSIX_SHARED_MEMORY_OBJECTS, -1, + _POSIX_SPAWN, -1, + _POSIX_SPORADIC_SERVER, -1, + _POSIX_SYNCHRONIZED_IO, -1, + :ref:`_POSIX_THREAD_ATTR_STACKADDR`, 200809L, :kconfig:option:`CONFIG_PTHREAD` + _POSIX_THREAD_CPUTIME, -1, + :ref:`_POSIX_THREAD_ATTR_STACKSIZE`, 200809L, :kconfig:option:`CONFIG_PTHREAD` + _POSIX_THREAD_PRIO_INHERIT, 200809L, :kconfig:option:`CONFIG_PTHREAD_MUTEX` + _POSIX_THREAD_PRIO_PROTECT, -1, + :ref:`_POSIX_THREAD_PRIORITY_SCHEDULING`, 200809L, :kconfig:option:`CONFIG_PTHREAD` + _POSIX_THREAD_PROCESS_SHARED, -1, + _POSIX_THREAD_SPORADIC_SERVER, -1, + _POSIX_TRACE, -1, + _POSIX_TRACE_EVENT_FILTER, -1, + _POSIX_TRACE_INHERIT, -1, + _POSIX_TRACE_LOG, -1, + _POSIX_TYPED_MEMORY_OBJECTS, -1, + _XOPEN_CRYPT, -1, + _XOPEN_REALTIME, -1, + _XOPEN_REALTIME_THREADS, -1, + :ref:`_XOPEN_STREAMS`, -1, :kconfig:option:`CONFIG_NET_SOCKETS` + _XOPEN_UNIX, -1, + +POSIX Shell and Utilities +========================= + +Zephyr does not support a POSIX shell or utilities at this time. + +.. csv-table:: POSIX Shell and Utilities + :header: Symbol, Support, Remarks + :widths: 50, 10, 50 + + _POSIX2_C_DEV, -1, :ref:`†` + _POSIX2_CHAR_TERM, -1, :ref:`†` + _POSIX2_FORT_DEV, -1, :ref:`†` + _POSIX2_FORT_RUN, -1, :ref:`†` + _POSIX2_LOCALEDEF, -1, :ref:`†` + _POSIX2_PBS, -1, :ref:`†` + _POSIX2_PBS_ACCOUNTING, -1, :ref:`†` + _POSIX2_PBS_LOCATE, -1, :ref:`†` + _POSIX2_PBS_MESSAGE, -1, :ref:`†` + _POSIX2_PBS_TRACK, -1, :ref:`†` + _POSIX2_SW_DEV, -1, :ref:`†` + _POSIX2_UPE, -1, :ref:`†` + _POSIX2_UNIX, -1, :ref:`†` + _POSIX2_UUCP, -1, :ref:`†` + +XSI Conformance +############### + +XSI System Interfaces +===================== + +.. csv-table:: XSI System Interfaces + :header: Symbol, Support, Remarks + :widths: 50, 10, 50 + + _POSIX_FSYNC, -1, :ref:`†` + :ref:`_POSIX_THREAD_ATTR_STACKADDR`, 200809L, :kconfig:option:`CONFIG_PTHREAD` + :ref:`_POSIX_THREAD_ATTR_STACKSIZE`, 200809L, :kconfig:option:`CONFIG_PTHREAD` + _POSIX_THREAD_PROCESS_SHARED, -1, diff --git a/doc/services/portability/posix/implementation/index.rst b/doc/services/portability/posix/implementation/index.rst new file mode 100644 index 00000000000..011317fef34 --- /dev/null +++ b/doc/services/portability/posix/implementation/index.rst @@ -0,0 +1,77 @@ +.. _posix_details: + +Implementation Details +###################### + +In many ways, Zephyr provides support like any POSIX OS; API bindings are provided in the C +programming language, POSIX headers are available in the standard include path, when configured. + +Unlike other multi-purpose POSIX operating systems + +- Zephyr is not "a POSIX OS". The Zephyr kernel was not designed around the POSIX standard, and + POSIX support is an opt-in feature +- Zephyr apps are not linked separately, nor do they execute as subprocesses +- Zephyr, libraries, and application code are compiled and linked together, running similarly to + a single-process application, in a single (possibly virtual) address space +- Zephyr does not provide a POSIX shell, compiler, utilities, and is not self-hosting. + +.. note:: + Unlike the Linux kernel or FreeBSD, Zephyr does not maintain a static table of system call + numbers for each supported architecture, but instead generates system calls dynamically at + build time. See `System Calls `_ for more information. + +Design +====== + +As a library, Zephyr's POSIX API implementation makes an effort to be a thin abstraction layer +between the application, middleware, and the Zephyr kernel. + +Some general design considerations: + +- The POSIX interface and implementations should be part of Zephyr's POSIX library, and not + elsewhere, unless required both by the POSIX API implementation and some other feature. An + example where the implementation should remain part of the POSIX implementation is + ``getopt()``. Examples where the implementation should be part of separate libraries are + multithreading and networking. + +- When the POSIX API and another Zephyr subsystem both rely on a feature, the implementation of + that feature should be as a separate Zephyr library that can be used by both the POSIX API and + the other library or subsystem. This reduces the likelihood of dependency cycles in code. When + practical, that rule should expand to include macros. In the example below, ``libposix`` + depends on ``libzfoo`` for the implementation of some functionality "foo" in Zephyr. If + ``libzfoo`` also depends on ``libposix``, then there is a dependency cycle. The cycle can be + removed via mutual dependency, ``libcommon``. + +.. graphviz:: + :caption: Dependency cycle between POSIX and another Zephyr library + + digraph { + node [shape=rect, style=rounded]; + rankdir=LR; + + libposix [fillcolor="#d5e8d4"]; + libzfoo [fillcolor="#dae8fc"]; + + libposix -> libzfoo; + libzfoo -> libposix; + } + +.. graphviz:: + :caption: Mutual dependencies between POSIX and other Zephyr libraries + + digraph { + node [shape=rect, style=rounded]; + rankdir=LR; + + libposix [fillcolor="#d5e8d4"]; + libzfoo [fillcolor="#dae8fc"]; + libcommon [fillcolor="#f8cecc"]; + + libposix -> libzfoo; + libposix -> libcommon; + libzfoo -> libcommon; + } + +- POSIX API calls should be provided as regular callable C functions; if a Zephyr + `System Call `_ is needed as part of the implementation, the declaration and the + implementation of that system call should be hidden behind the POSIX API. diff --git a/doc/services/portability/posix/index.rst b/doc/services/portability/posix/index.rst new file mode 100644 index 00000000000..5fc5117df44 --- /dev/null +++ b/doc/services/portability/posix/index.rst @@ -0,0 +1,14 @@ +.. _posix_support: + +POSIX +##### + +.. toctree:: + :maxdepth: 2 + + overview/index.rst + conformance/index.rst + aep/index.rst + implementation/index.rst + option_groups/index.rst + kconfig/index.rst diff --git a/doc/services/portability/posix/kconfig/index.rst b/doc/services/portability/posix/kconfig/index.rst new file mode 100644 index 00000000000..c1599dd5506 --- /dev/null +++ b/doc/services/portability/posix/kconfig/index.rst @@ -0,0 +1,52 @@ +.. _posix_kconfig_options: + +Configuration Options +********************* + +This is a non-exhaustive list of specific :ref:`kconfig` options relating to Zephyr's +implementation of the POSIX API. + +* :kconfig:option:`CONFIG_APP_LINK_WITH_POSIX_SUBSYS` +* :kconfig:option:`CONFIG_EVENTFD` +* :kconfig:option:`CONFIG_EVENTFD_MAX` +* :kconfig:option:`CONFIG_FDTABLE` +* :kconfig:option:`CONFIG_FNMATCH` +* :kconfig:option:`CONFIG_GETOPT` +* :kconfig:option:`CONFIG_GETOPT_LONG` +* :kconfig:option:`CONFIG_MAX_PTHREAD_BARRIER_COUNT` +* :kconfig:option:`CONFIG_MAX_PTHREAD_COUNT` +* :kconfig:option:`CONFIG_MAX_PTHREAD_KEY_COUNT` +* :kconfig:option:`CONFIG_MAX_PTHREAD_MUTEX_COUNT` +* :kconfig:option:`CONFIG_MAX_PTHREAD_SPINLOCK_COUNT` +* :kconfig:option:`CONFIG_MAX_TIMER_COUNT` +* :kconfig:option:`CONFIG_MQUEUE_NAMELEN_MAX` +* :kconfig:option:`CONFIG_MSG_COUNT_MAX` +* :kconfig:option:`CONFIG_MSG_SIZE_MAX` +* :kconfig:option:`CONFIG_NET_SOCKETPAIR` +* :kconfig:option:`CONFIG_NET_SOCKETS` +* :kconfig:option:`CONFIG_NET_SOCKETS_POLL_MAX` +* :kconfig:option:`CONFIG_NET_SOCKETS_POSIX_NAMES` +* :kconfig:option:`CONFIG_POSIX_API` +* :kconfig:option:`CONFIG_POSIX_CLOCK` +* :kconfig:option:`CONFIG_POSIX_FS` +* :kconfig:option:`CONFIG_POSIX_LIMITS_RTSIG_MAX` +* :kconfig:option:`CONFIG_POSIX_MAX_FDS` +* :kconfig:option:`CONFIG_POSIX_MAX_OPEN_FILES` +* :kconfig:option:`CONFIG_POSIX_MQUEUE` +* :kconfig:option:`CONFIG_POSIX_RTSIG_MAX` +* :kconfig:option:`CONFIG_POSIX_SIGNAL` +* :kconfig:option:`CONFIG_POSIX_SIGNAL_STRING_DESC` +* :kconfig:option:`CONFIG_POSIX_UNAME` +* :kconfig:option:`CONFIG_POSIX_UNAME_NODENAME_LEN` +* :kconfig:option:`CONFIG_POSIX_UNAME_VERSION_LEN` +* :kconfig:option:`CONFIG_PTHREAD` +* :kconfig:option:`CONFIG_PTHREAD_BARRIER` +* :kconfig:option:`CONFIG_PTHREAD_COND` +* :kconfig:option:`CONFIG_PTHREAD_CREATE_BARRIER` +* :kconfig:option:`CONFIG_PTHREAD_IPC` +* :kconfig:option:`CONFIG_PTHREAD_KEY` +* :kconfig:option:`CONFIG_PTHREAD_MUTEX` +* :kconfig:option:`CONFIG_PTHREAD_RECYCLER_DELAY_MS` +* :kconfig:option:`CONFIG_PTHREAD_SPINLOCK` +* :kconfig:option:`CONFIG_SEM_VALUE_MAX` +* :kconfig:option:`CONFIG_TIMER` diff --git a/doc/services/portability/posix.rst b/doc/services/portability/posix/option_groups/index.rst similarity index 57% rename from doc/services/portability/posix.rst rename to doc/services/portability/posix/option_groups/index.rst index 392147594c8..0381b184820 100644 --- a/doc/services/portability/posix.rst +++ b/doc/services/portability/posix/option_groups/index.rst @@ -1,131 +1,18 @@ -.. _posix_support: +.. _posix_option_groups: -POSIX Support -############# +Subprofiling Option Groups +########################## -The Portable Operating System Interface (POSIX) is a family of standards -specified by the IEEE Computer Society for maintaining compatibility between -operating systems. Zephyr implements a subset of the embedded profiles PSE51 -and PSE52, and BSD Sockets API. - -With the POSIX support available in Zephyr, an existing POSIX compliant -application can be ported to run on the Zephyr kernel, and therefore leverage -Zephyr features and functionality. Additionally, a library designed for use with -POSIX threading compatible operating systems can be ported to Zephyr kernel -based applications with minimal or no changes. - -.. figure:: posix.svg - :align: center - :alt: POSIX Support in Zephyr - - POSIX support in Zephyr - -The POSIX API subset is an increasingly popular OSAL (operating system -abstraction layer) for IoT and embedded applications, as can be seen in -Zephyr, AWS:FreeRTOS, TI-RTOS, and NuttX. - -Benefits of POSIX support in Zephyr include: - -- Offering a familiar API to non-embedded programmers, especially from Linux -- Enabling reuse (portability) of existing libraries based on POSIX APIs -- Providing an efficient API subset appropriate for small (MCU) embedded systems - - -System Overview -=============== - -Units of Functionality -++++++++++++++++++++++ - -The system profile is defined in terms of component profiles that specify Units -of Functionality that can be combined to realize the application platform. A Unit -of Functionality is a defined set of services which can be implemented. If -implemented, the standard prescribes that all services in the Unit must -be implemented. - -A Minimal Realtime System Profile implementation must support the -following Units of Functionality as defined in IEEE Std. 1003.1 (also referred to -as POSIX.1-2017). - - -.. csv-table:: Units of Functionality - :header: Requirements, Supported, Remarks - :widths: 50,10,60 - - - POSIX_C_LANG_JUMP, - POSIX_C_LANG_SUPPORT,yes - POSIX_DEVICE_IO, - POSIX_FILE_LOCKING, - POSIX_SIGNALS, - POSIX_SINGLE_PROCESS, - POSIX_SPIN_LOCKS,yes - POSIX_THREADS_BASE,yes - XSI_THREAD_MUTEX_EXT,yes - XSI_THREADS_EXT,yes - - -Option Requirements -++++++++++++++++++++ - -An implementation supporting the Minimal Realtime System -Profile must support the POSIX.1 Option Requirements which are defined in the -standard. Options Requirements are used for further sub-profiling within the -units of functionality: they further define the functional behavior of the -system service (normally adding extra functionality). Depending on the profile -to which the POSIX implementation complies,parameters and/or the precise -functionality of certain services may differ. - -The following list shows the option requirements that are implemented in -Zephyr. - - -.. csv-table:: Option Requirements - :header: Requirements, Supported - :widths: 50,10 - - _POSIX_BARRIERS,yes - _POSIX_CLOCK_SELECTION,yes - _POSIX_FSYNC, - _POSIX_MEMLOCK, - _POSIX_MEMLOCK_RANGE, - _POSIX_MONOTONIC_CLOCK,yes - _POSIX_NO_TRUNC, - _POSIX_REALTIME_SIGNALS, - _POSIX_SEMAPHORES,yes - _POSIX_SHARED_MEMORY_OBJECTS, - _POSIX_SPIN_LOCKS,yes - _POSIX_SYNCHRONIZED_IO, - _POSIX_THREAD_ATTR_STACKADDR,yes - _POSIX_THREAD_ATTR_STACKSIZE,yes - _POSIX_THREAD_CPUTIME, - _POSIX_THREAD_PRIO_INHERIT, - _POSIX_THREAD_PRIO_PROTECT, - _POSIX_THREAD_PRIORITY_SCHEDULING,yes - _POSIX_THREAD_SPORADIC_SERVER, - _POSIX_TIMEOUTS, - _POSIX_TIMERS,yes - _POSIX2_C_DEV, - _POSIX2_SW_DEV, - - - -Units of Functionality -====================== - -This section describes the Units of Functionality (fixed sets of interfaces) -which are implemented (partially or completely) in Zephyr. Please refer to the -standard for a full description of each listed interface. +.. _posix_option_group_threads_base: POSIX_THREADS_BASE -+++++++++++++++++++ +================== The basic assumption in this profile is that the system consists of a single (implicit) process with multiple threads. Therefore, the standard requires all basic thread services, except those related to multiple processes. - .. csv-table:: POSIX_THREADS_BASE :header: API, Supported :widths: 50,10 @@ -179,12 +66,12 @@ multiple processes. pthread_sigmask(), pthread_testcancel(), - +.. _posix_option_group_xsi_thread_ext: XSI_THREAD_EXT -++++++++++++++ +============== -The XSI_THREADS_EXT Unit of Functionality is required because it provides +The XSI_THREADS_EXT option group is required because it provides functions to control a thread's stack. This is considered useful for any real-time application. @@ -201,33 +88,14 @@ This table lists service support status in Zephyr: pthread_getconcurrency(), pthread_setconcurrency() - -XSI_THREAD_MUTEX_EXT -++++++++++++++++++++ - -The XSI_THREAD_MUTEX_EXT Unit of Functionality is required because it has -options for controlling the behavior of mutexes under erroneous application use. - - -This table lists service support status in Zephyr: - -.. csv-table:: XSI_THREAD_MUTEX_EXT - :header: API, Supported - :widths: 50,10 - - pthread_mutexattr_gettype(),yes - pthread_mutexattr_settype(),yes - +.. _posix_option_group_c_lang_support: POSIX_C_LANG_SUPPORT -++++++++++++++++++++ +==================== -The POSIX_C_LANG_SUPPORT Unit of Functionality contains the general ISO C +The POSIX_C_LANG_SUPPORT option group contains the general ISO C Library. -This is implemented as part of the minimal C library available in Zephyr. - - .. csv-table:: POSIX_C_LANG_SUPPORT :header: API, Supported :widths: 50,10 @@ -338,11 +206,12 @@ This is implemented as part of the minimal C library available in Zephyr. vsprintf(),yes vsscanf(), +.. _posix_option_group_single_process: POSIX_SINGLE_PROCESS -+++++++++++++++++++++ +==================== -The POSIX_SINGLE_PROCESS Unit of Functionality contains services for single +The POSIX_SINGLE_PROCESS option group contains services for single process applications. .. csv-table:: POSIX_SINGLE_PROCESS @@ -358,9 +227,10 @@ process applications. uname(),yes unsetenv() +.. _posix_option_group_signals: POSIX_SIGNALS -+++++++++++++ +============= Signal services are a basic mechanism within POSIX-based systems and are required for error and event handling. @@ -369,7 +239,6 @@ required for error and event handling. :header: API, Supported :widths: 50,10 - abort(),yes alarm(), kill(), @@ -388,32 +257,20 @@ required for error and event handling. sigwait(), strsignal(),yes -.. csv-table:: POSIX_SPIN_LOCKS - :header: API, Supported - :widths: 50,10 - - pthread_spin_destroy(),yes - pthread_spin_init(),yes - pthread_spin_lock(),yes - pthread_spin_trylock(),yes - pthread_spin_unlock(),yes - +.. _posix_option_group_device_io: POSIX_DEVICE_IO -+++++++++++++++ +=============== .. csv-table:: POSIX_DEVICE_IO :header: API, Supported :widths: 50,10 - flockfile(), - ftrylockfile(), - funlockfile(), - getc_unlocked(), - getchar_unlocked(),yes - putc_unlocked(), - putchar_unlocked() - clearerr(), + FD_CLR(),yes + FD_ISSET(),yes + FD_SET(),yes + FD_ZERO(),yes + clearerr(),yes close(),yes fclose(), fdopen(), @@ -436,17 +293,22 @@ POSIX_DEVICE_IO gets(), open(),yes perror(),yes + poll(),yes printf(),yes + pread(), + pselect(), putc(),yes putchar(),yes puts(),yes + pwrite(), read(),yes scanf(), + select(),yes setbuf(), setvbuf(), - stderr,yes - stdin,yes - stdout,yes + stderr, + stdin, + stdout, ungetc(), vfprintf(),yes vfscanf(), @@ -454,8 +316,72 @@ POSIX_DEVICE_IO vscanf(), write(),yes +.. _posix_option_group_barriers: + +POSIX_BARRIERS +============== + +.. csv-table:: POSIX_BARRIERS + :header: API, Supported + :widths: 50,10 + + pthread_barrier_destroy(),yes + pthread_barrier_init(),yes + pthread_barrier_wait(),yes + pthread_barrierattr_destroy(),yes + pthread_barrierattr_init(),yes + +.. _posix_option_group_clock_selection: + +POSIX_CLOCK_SELECTION +===================== + +.. csv-table:: POSIX_CLOCK_SELECTION + :header: API, Supported + :widths: 50,10 + + pthread_condattr_getclock(),yes + pthread_condattr_setclock(),yes + clock_nanosleep(),yes + +.. _posix_option_group_semaphores: + +POSIX_SEMAPHORES +================ + +.. csv-table:: POSIX_SEMAPHORES + :header: API, Supported + :widths: 50,10 + + sem_close(), + sem_destroy(),yes + sem_getvalue(),yes + sem_init(),yes + sem_open(), + sem_post(),yes + sem_trywait(),yes + sem_unlink(), + sem_wait(),yes + +.. _posix_option_group_spin_locks: + +POSIX_SPIN_LOCKS +================ + +.. csv-table:: POSIX_SPIN_LOCKS + :header: API, Supported + :widths: 50,10 + + pthread_spin_destroy(),yes + pthread_spin_init(),yes + pthread_spin_lock(),yes + pthread_spin_trylock(),yes + pthread_spin_unlock(),yes + +.. _posix_option_group_timers: + POSIX_TIMERS -++++++++++++ +============ .. csv-table:: POSIX_TIMERS :header: API, Supported @@ -471,13 +397,143 @@ POSIX_TIMERS timer_getoverrun(),yes timer_settime(),yes -POSIX_CLOCK_SELECTION -+++++++++++++++++++++ -.. csv-table:: POSIX_CLOCK_SELECTION +.. _posix_options: + +Additional POSIX Options +======================== + +.. _posix_option_message_passing: + +_POSIX_MESSAGE_PASSING +++++++++++++++++++++++ + +.. csv-table:: _POSIX_MESSAGE_PASSING :header: API, Supported :widths: 50,10 - pthread_condattr_getclock(),yes - pthread_condattr_setclock(),yes - clock_nanosleep(),yes + mq_close(),yes + mq_getattr(),yes + mq_notify(), + mq_open(),yes + mq_receive(),yes + mq_send(),yes + mq_setattr(),yes + mq_unlink(),yes + +_POSIX_PRIORITY_SCHEDULING +++++++++++++++++++++++++++ + +.. _posix_option_priority_scheduling: + +.. csv-table:: _POSIX_PRIORITY_SCHEDULING + :header: API, Supported + :widths: 50,10 + + sched_get_priority_max(),yes + sched_get_priority_min(),yes + sched_getparam(), + sched_getscheduler(), + sched_rr_get_interval(), + sched_setparam(), + sched_setscheduler(), + sched_yield(),yes + +.. _posix_option_reader_writer_locks: + +_POSIX_READER_WRITER_LOCKS +++++++++++++++++++++++++++ + +.. csv-table:: _POSIX_READER_WRITER_LOCKS + :header: API, Supported + :widths: 50,10 + + pthread_rwlock_destroy(),yes + pthread_rwlock_init(),yes + pthread_rwlock_rdlock(),yes + pthread_rwlock_tryrdlock(),yes + pthread_rwlock_trywrlock(),yes + pthread_rwlock_unlock(),yes + pthread_rwlock_wrlock(),yes + pthread_rwlockattr_destroy(),yes + pthread_rwlockattr_getpshared(), + pthread_rwlockattr_init(),yes + pthread_rwlockattr_setpshared(), + +.. _posix_option_thread_attr_stackaddr: + +_POSIX_THREAD_ATTR_STACKADDR +++++++++++++++++++++++++++++ + +.. csv-table:: _POSIX_THREAD_ATTR_STACKADDR + :header: API, Supported + :widths: 50,10 + + pthread_attr_getstackaddr(),yes + pthread_attr_setstackaddr(),yes + +.. _posix_option_thread_attr_stacksize: + +_POSIX_THREAD_ATTR_STACKSIZE +++++++++++++++++++++++++++++ + +.. csv-table:: _POSIX_THREAD_ATTR_STACKSIZE + :header: API, Supported + :widths: 50,10 + + pthread_attr_getstacksize(),yes + pthread_attr_setstacksize(),yes + +.. _posix_option_thread_priority_scheduling: + +_POSIX_THREAD_PRIORITY_SCHEDULING ++++++++++++++++++++++++++++++++++ + +.. csv-table:: _POSIX_THREAD_PRIORITY_SCHEDULING + :header: API, Supported + :widths: 50,10 + + pthread_attr_getinheritsched(), + pthread_attr_getschedpolicy(),yes + pthread_attr_getscope(), + pthread_attr_setinheritsched(), + pthread_attr_setschedpolicy(),yes + pthread_attr_setscope(), + pthread_getschedparam(),yes + pthread_setschedparam(),yes + pthread_setschedprio(),yes + +.. _posix_option_timeouts: + +_POSIX_TIMEOUTS ++++++++++++++++ + +.. csv-table:: _POSIX_TIMEOUTS + :header: API, Supported + :widths: 50,10 + + mq_timedreceive(), + mq_timedsend(), + pthread_mutex_timedlock(),yes + pthread_rwlock_timedrdlock(),yes + pthread_rwlock_timedwrlock(),yes + sem_timedwait(),yes + posix_trace_timedgetnext_event(), + +.. _posix_option_xopen_streams: + +_XOPEN_STREAMS +++++++++++++++ + +.. csv-table:: _XOPEN_STREAMS + :header: API, Supported + :widths: 50,10 + + fattach(), + fdetach(), + getmsg(), + getpmsg(), + ioctl(),yes + isastream(), + putmsg(), + putpmsg(), diff --git a/doc/services/portability/posix/overview/index.rst b/doc/services/portability/posix/overview/index.rst new file mode 100644 index 00000000000..56810e49ac1 --- /dev/null +++ b/doc/services/portability/posix/overview/index.rst @@ -0,0 +1,135 @@ +.. _posix_overview: + +Overview +######## + +The Portable Operating System Interface (POSIX) is a family of standards specified by the +`IEEE Computer Society`_ for maintaining compatibility between operating systems. Zephyr +implements a subset of the standard POSIX API specified by `IEEE 1003.1-2017`_ (also known as +POSIX-1.2017). + +.. figure:: posix.svg + :align: center + :alt: POSIX Support in Zephyr + + POSIX support in Zephyr + +.. note:: + This page does not document Zephyr's :ref:`POSIX architecture`, which is used to + run Zephyr as a native application under the host operating system for prototyping, + test, and diagnostic purposes. + +With the POSIX support available in Zephyr, an existing POSIX conformant +application can be ported to run on the Zephyr kernel, and therefore leverage +Zephyr features and functionality. Additionally, a library designed to be +POSIX conformant can be ported to Zephyr kernel based applications with no changes. + +The POSIX API is an increasingly popular OSAL (operating system abstraction layer) for IoT and +embedded applications, as can be seen in Zephyr, AWS:FreeRTOS, TI-RTOS, and NuttX. + +Benefits of POSIX support in Zephyr include: + +- Offering a familiar API to non-embedded programmers, especially from Linux +- Enabling reuse (portability) of existing libraries based on POSIX APIs +- Providing an efficient API subset appropriate for small (MCU) embedded systems + +.. _posix_subprofiles: + +POSIX Subprofiles +================= + +While Zephyr supports running multiple `threads `_ (possibly in an `SMP `_ +configuration), as well as `Virtual Memory and MMUs `_, Zephyr code and data +normally share a common address space. The Zephyr kernel executable code and the application +executable code are typically compiled into the same binary artifact. From that perspective, Zephyr +apps can be seen as running in the context of a single process. + +While multi-purpose operating systems (OS) offer full POSIX conformance, Real-Time Operating +Systems (RTOS) such as Zephyr typically serve a fixed-purpose, have limited hardware resources, +and experience limited user interaction. In such systems, full POSIX conformance can be +impractical and unnecessary. + +For that reason, POSIX defined the following :ref:`Application Environment Profiles (AEP)` +as part of `IEEE 1003.13-2003`_ (also known as POSIX.13-2003). + +* Minimal Realtime System Profile (:ref:`PSE51 `) +* Realtime Controller System Profile (:ref:`PSE52 `) +* Dedicated Realtime System Profile (:ref:`PSE53 `) +* Multi-Purpose Realtime System (PSE54) + +POSIX.13-2003 AEP were formalized in 2003 via "Units of Functionality" but the specification is now +inactive (for reference only). Nevertheless, the intent is still captured as part of POSIX-1.2017 +via :ref:`Options` and :ref:`Option Groups`, in Appendix E. + +.. _posix_apps: + +POSIX Applications in Zephyr +============================ + +A POSIX app in Zephyr is :ref:`built like any other app` and therefore requires the +usual :file:`prj.conf`, :file:`CMakeLists.txt`, and source code. For example, the app below +leverages the ``nanosleep()`` and ``perror()`` POSIX functions. + +.. code-block:: cfg + :caption: `prj.conf` for a simple POSIX app in Zephyr + + CONFIG_POSIX_API=y + +.. code-block:: c + :caption: A simple app that uses Zephyr's POSIX API + + #include + #include + #include + + void megasleep(size_t megaseconds) + { + struct timespec ts = { + .tv_sec = megaseconds * 1000000, + .tv_nsec = 0, + }; + + printf("See you in a while!\n"); + if (nanosleep(&ts, NULL) == -1) { + perror("nanosleep"); + } + } + + int main() + { + megasleep(42); + return 0; + } + +.. + TODO: insert a link to a list of all samples tagged with 'posix' + +.. _posix_config: + +Configuration +============= + +Like most features in Zephyr, POSIX features are +:ref:`highly configurable` but disabled by default. Users must +explicitly choose to enable POSIX options via :ref:`Kconfig` selection. Indeed, there are +:ref:`many Kconfig options in Zephyr` for the POSIX API to allow for +feature selection at various levels of granularity. + +Alternatively, users may enable one of the Kconfig options below as a shortcut to enable multiple +:ref:`Option Groups`. + +* :kconfig:option:`CONFIG_POSIX_API` +* :kconfig:option:`CONFIG_PTHREAD_IPC` + +.. note:: + Since the POSIX environment in Zephyr is fully configurable via :ref:`Kconfig`, + configurations that require modifying features should not be made if strict compliance is + required (POSIX-1.2017, section 2.1.3.1). + +.. + TODO: create Kconfig shortcuts for PSE51, PSE52, and PSE53 + +.. _IEEE: https://www.ieee.org/ +.. _IEEE Computer Society: https://www.computer.org/ +.. _IEEE 1003.1-2017: https://standards.ieee.org/ieee/1003.1/7101/ +.. _IEEE 1003.13-2003: https://standards.ieee.org/ieee/1003.13/3322/ diff --git a/doc/services/portability/posix.svg b/doc/services/portability/posix/overview/posix.svg similarity index 68% rename from doc/services/portability/posix.svg rename to doc/services/portability/posix/overview/posix.svg index c21ecba2ae5..a62be70994e 100644 --- a/doc/services/portability/posix.svg +++ b/doc/services/portability/posix/overview/posix.svg @@ -1,2 +1,2 @@ -
Hardware
Hardware
BSP
BSP
Zephyr Kernel
Zephyr Kernel
POSIX PSE51
POSIX PSE51
File System
File System
POSIX PSE52
<div>POSIX PSE52</div>
Networking
Networking
BSD Sockets
<div>BSD Sockets<br></div>
 Middleware
 Middleware
Application
Application
\ No newline at end of file +
Hardware
Hardware
BSP
BSP
Zephyr Kernel
Zephyr Kernel
POSIX PSE51
POSIX PSE51
File System
File System
POSIX PSE52
POSIX PSE52
Networking
Networking
POSIX PSE53
POSIX PSE53
 Middleware
 Middleware
Application
Application
\ No newline at end of file From a0c307c0a56cc89bfa51e631da58119911c03797 Mon Sep 17 00:00:00 2001 From: Christopher Friedt Date: Wed, 22 Nov 2023 21:29:00 -0500 Subject: [PATCH 0132/3723] posix: pthread: implement pthread_atfork() pthread_atfork() is required by the POSIX_THREADS_BASE Option Group as detailed in Section E.1 of IEEE-1003.1-2017. The POSIX_THREADS_BASE Option Group is required for PSE51, PSE52, PSE53, and PSE54 conformance, and is otherwise mandatory for any POSIX conforming system as per Section A.2.1.3 of IEEE-1003-1.2017. Since Zephyr does not yet support processes and (by extension) fork(), this implementation includes a deviation and should be categorized as producing undefined behaviour. Signed-off-by: Christopher Friedt --- include/zephyr/posix/pthread.h | 1 + lib/posix/pthread.c | 9 +++++++++ 2 files changed, 10 insertions(+) diff --git a/include/zephyr/posix/pthread.h b/include/zephyr/posix/pthread.h index d978e914a5e..2f942f6553c 100644 --- a/include/zephyr/posix/pthread.h +++ b/include/zephyr/posix/pthread.h @@ -473,6 +473,7 @@ int pthread_key_create(pthread_key_t *key, int pthread_key_delete(pthread_key_t key); int pthread_setspecific(pthread_key_t key, const void *value); void *pthread_getspecific(pthread_key_t key); +int pthread_atfork(void (*prepare)(void), void (*parent)(void), void (*child)(void)); /* Glibc / Oracle Extension Functions */ diff --git a/lib/posix/pthread.c b/lib/posix/pthread.c index f2bbc07ae9a..c5c00a53491 100644 --- a/lib/posix/pthread.c +++ b/lib/posix/pthread.c @@ -954,6 +954,15 @@ int pthread_getname_np(pthread_t thread, char *name, size_t len) #endif } +int pthread_atfork(void (*prepare)(void), void (*parent)(void), void (*child)(void)) +{ + ARG_UNUSED(prepare); + ARG_UNUSED(parent); + ARG_UNUSED(child); + + return ENOSYS; +} + static int posix_thread_pool_init(void) { size_t i; From 1d501a76afc5e24806309390a8a53c6c5814ec96 Mon Sep 17 00:00:00 2001 From: Christopher Friedt Date: Wed, 22 Nov 2023 21:49:37 -0500 Subject: [PATCH 0133/3723] doc: services: portability: posix: pthread_atfork() supported Mark pthread_atfork() as supported in the documentation. This option is a mandatory requirement (i.e. it must be present) even when calling it produces undefined behaviour. That is the case here, and documentation sbould be updated to reflect that. Signed-off-by: Christopher Friedt --- doc/services/portability/posix/option_groups/index.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/doc/services/portability/posix/option_groups/index.rst b/doc/services/portability/posix/option_groups/index.rst index 0381b184820..e151788586d 100644 --- a/doc/services/portability/posix/option_groups/index.rst +++ b/doc/services/portability/posix/option_groups/index.rst @@ -17,7 +17,7 @@ multiple processes. :header: API, Supported :widths: 50,10 - pthread_atfork(), + pthread_atfork(),yes pthread_attr_destroy(),yes pthread_attr_getdetachstate(),yes pthread_attr_getschedparam(),yes From 41b7c17ac4bd0198fc9bb3a0e55aa8d5e2fae96e Mon Sep 17 00:00:00 2001 From: Christopher Friedt Date: Wed, 22 Nov 2023 21:53:07 -0500 Subject: [PATCH 0134/3723] tests: posix: pthread: check that pthread_atfork() exists Add a simple existence check that pthread_atfork() has some kind of implementation. The function is mandatory by all conforming POSIX systems. Signed-off-by: Christopher Friedt --- tests/posix/headers/src/pthread_h.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/posix/headers/src/pthread_h.c b/tests/posix/headers/src/pthread_h.c index d535a134693..b249c337c18 100644 --- a/tests/posix/headers/src/pthread_h.c +++ b/tests/posix/headers/src/pthread_h.c @@ -60,7 +60,7 @@ ZTEST(posix_headers, test_pthread_h) /* pthread_rwlock_t lock = PTHREAD_RWLOCK_INITIALIZER; */ /* not implemented */ if (IS_ENABLED(CONFIG_POSIX_API)) { - /* zassert_not_null(pthread_atfork); */ /* not implemented */ + zassert_not_null(pthread_atfork); zassert_not_null(pthread_attr_destroy); zassert_not_null(pthread_attr_getdetachstate); /* zassert_not_null(pthread_attr_getguardsize); */ /* not implemented */ From d2bd778bcce2b4cc12b1c286b2a3c3584b540a89 Mon Sep 17 00:00:00 2001 From: Andrej Butok Date: Tue, 7 Nov 2023 10:46:26 +0100 Subject: [PATCH 0135/3723] kconfig: mcuboot: Add MCUBOOT_IMGTOOL_OVERWRITE_ONLY option Add MCUBOOT_IMGTOOL_OVERWRITE_ONLY Kconfig option which passes the --overwrite-only option to imgtool to avoid adding the swap status area size when calculating overflow. It is used by non-swap update modes. Signed-off-by: Andrej Butok --- cmake/mcuboot.cmake | 5 +++++ modules/Kconfig.mcuboot | 10 ++++++++++ 2 files changed, 15 insertions(+) diff --git a/cmake/mcuboot.cmake b/cmake/mcuboot.cmake index 3b29069ca35..2347ae3108c 100644 --- a/cmake/mcuboot.cmake +++ b/cmake/mcuboot.cmake @@ -96,6 +96,11 @@ function(zephyr_mcuboot_tasks) set(imgtool_extra --key "${keyfile}" ${imgtool_extra}) endif() + # Use overwrite-only instead of swap upgrades. + if(CONFIG_MCUBOOT_IMGTOOL_OVERWRITE_ONLY) + set(imgtool_extra --overwrite-only ${imgtool_extra}) + endif() + set(imgtool_args -- ${imgtool_extra}) # Extensionless prefix of any output file. diff --git a/modules/Kconfig.mcuboot b/modules/Kconfig.mcuboot index 8df4bde8829..7f41167d3d3 100644 --- a/modules/Kconfig.mcuboot +++ b/modules/Kconfig.mcuboot @@ -110,6 +110,12 @@ config MCUBOOT_IMGTOOL_SIGN_VERSION argument to the tool. The format is major.minor.revision+build. +config MCUBOOT_IMGTOOL_OVERWRITE_ONLY + bool "Use overwrite-only instead of swap upgrades" + help + If enabled, --overwrite-only option passed to imgtool to avoid + adding the swap status area size when calculating overflow. + config MCUBOOT_EXTRA_IMGTOOL_ARGS string "Extra arguments to pass to imgtool when signing" default "" @@ -148,6 +154,7 @@ choice MCUBOOT_BOOTLOADER_MODE config MCUBOOT_BOOTLOADER_MODE_SINGLE_APP bool "MCUboot has been configured for single slot execution" + select MCUBOOT_IMGTOOL_OVERWRITE_ONLY help MCUboot will only boot slot0_partition placed application and does not care about other slots. In this mode application is not able @@ -178,6 +185,7 @@ config MCUBOOT_BOOTLOADER_MODE_SWAP_SCRATCH config MCUBOOT_BOOTLOADER_MODE_OVERWRITE_ONLY bool "MCUboot has been configured to just overwrite primary slot" select MCUBOOT_BOOTLOADER_MODE_HAS_NO_DOWNGRADE + select MCUBOOT_IMGTOOL_OVERWRITE_ONLY help MCUboot will take contents of secondary slot of an image and will overwrite primary slot with it. @@ -191,6 +199,7 @@ config MCUBOOT_BOOTLOADER_MODE_DIRECT_XIP bool "MCUboot has been configured for DirectXIP operation" select MCUBOOT_BOOTLOADER_MODE_HAS_NO_DOWNGRADE select MCUBOOT_BOOTLOADER_NO_DOWNGRADE + select MCUBOOT_IMGTOOL_OVERWRITE_ONLY help MCUboot expects slot0_partition and slot1_partition to exist in DT. In this mode MCUboot can boot from either partition and will @@ -206,6 +215,7 @@ config MCUBOOT_BOOTLOADER_MODE_DIRECT_XIP_WITH_REVERT select MCUBOOT_BOOTUTIL_LIB_FOR_DIRECT_XIP select MCUBOOT_BOOTLOADER_MODE_HAS_NO_DOWNGRADE select MCUBOOT_BOOTLOADER_NO_DOWNGRADE + select MCUBOOT_IMGTOOL_OVERWRITE_ONLY help MCUboot expects slot0_partition and slot1_partition to exist in DT. In this mode MCUboot will boot the application with the higher version From 061a87aff8650ba55bc698dbe7f00a08a4abb6e5 Mon Sep 17 00:00:00 2001 From: Siddharth Chandrasekaran Date: Sat, 15 Jul 2023 03:32:29 +0200 Subject: [PATCH 0136/3723] mgmt/osdp: Replace __ASSERT() with an explicit if Commit c7fec71193a ("mgmt/osdp: Add length checks for commands and replies") attempted to remove code duplication by adding a macro to perform a length check. At the time, a CI linter did not like macros with control flow so the code was switched to a method which called __ASSERT() on this condition. The __ASSERT() macro is a nop if CONFIG_ASSERT=n (which is the default) and causes the buffer access to be unguarded which may lead to OOB accesses. This patch fixes the issue by reintroducing the if check. Fixes: c7fec71193a19f6be1a2adca8cf7753cd7103c78. Signed-off-by: Siddharth Chandrasekaran --- subsys/mgmt/osdp/src/osdp_cp.c | 73 +++++++++++++++++++++++++--------- subsys/mgmt/osdp/src/osdp_pd.c | 61 ++++++++++++++++++++-------- 2 files changed, 99 insertions(+), 35 deletions(-) diff --git a/subsys/mgmt/osdp/src/osdp_cp.c b/subsys/mgmt/osdp/src/osdp_cp.c index 86a1e9d20e3..e9c5d19d2eb 100644 --- a/subsys/mgmt/osdp/src/osdp_cp.c +++ b/subsys/mgmt/osdp/src/osdp_cp.c @@ -114,10 +114,13 @@ int osdp_extract_address(int *address) return (pd_offset == CONFIG_OSDP_NUM_CONNECTED_PD) ? 0 : -1; } -static inline void assert_buf_len(int need, int have) +static inline bool check_buf_len(int need, int have) { - __ASSERT(need < have, "OOM at build command: need:%d have:%d", - need, have); + if (need >= have) { + LOG_ERR("OOM at build command: need:%d have:%d", need, have); + return false; + } + return true; } static int cp_build_command(struct osdp_pd *pd, uint8_t *buf, int max_len) @@ -137,42 +140,60 @@ static int cp_build_command(struct osdp_pd *pd, uint8_t *buf, int max_len) switch (pd->cmd_id) { case CMD_POLL: - assert_buf_len(CMD_POLL_LEN, max_len); + if (!check_buf_len(CMD_POLL_LEN, max_len)) { + return OSDP_CP_ERR_GENERIC; + } buf[len++] = pd->cmd_id; break; case CMD_LSTAT: - assert_buf_len(CMD_LSTAT_LEN, max_len); + if (!check_buf_len(CMD_LSTAT_LEN, max_len)) { + return OSDP_CP_ERR_GENERIC; + } buf[len++] = pd->cmd_id; break; case CMD_ISTAT: - assert_buf_len(CMD_ISTAT_LEN, max_len); + if (!check_buf_len(CMD_ISTAT_LEN, max_len)) { + return OSDP_CP_ERR_GENERIC; + } buf[len++] = pd->cmd_id; break; case CMD_OSTAT: - assert_buf_len(CMD_OSTAT_LEN, max_len); + if (!check_buf_len(CMD_OSTAT_LEN, max_len)) { + return OSDP_CP_ERR_GENERIC; + } buf[len++] = pd->cmd_id; break; case CMD_RSTAT: - assert_buf_len(CMD_RSTAT_LEN, max_len); + if (!check_buf_len(CMD_RSTAT_LEN, max_len)) { + return OSDP_CP_ERR_GENERIC; + } buf[len++] = pd->cmd_id; break; case CMD_ID: - assert_buf_len(CMD_ID_LEN, max_len); + if (!check_buf_len(CMD_ID_LEN, max_len)) { + return OSDP_CP_ERR_GENERIC; + } buf[len++] = pd->cmd_id; buf[len++] = 0x00; break; case CMD_CAP: - assert_buf_len(CMD_CAP_LEN, max_len); + if (!check_buf_len(CMD_CAP_LEN, max_len)) { + return OSDP_CP_ERR_GENERIC; + } buf[len++] = pd->cmd_id; buf[len++] = 0x00; break; case CMD_DIAG: - assert_buf_len(CMD_DIAG_LEN, max_len); + if (!check_buf_len(CMD_DIAG_LEN, max_len)) { + return OSDP_CP_ERR_GENERIC; + } buf[len++] = pd->cmd_id; buf[len++] = 0x00; break; case CMD_OUT: - assert_buf_len(CMD_OUT_LEN, max_len); + if (!check_buf_len(CMD_OUT_LEN, max_len)) { + return OSDP_CP_ERR_GENERIC; + } cmd = (struct osdp_cmd *)pd->ephemeral_data; buf[len++] = pd->cmd_id; buf[len++] = cmd->output.output_no; @@ -181,7 +202,9 @@ static int cp_build_command(struct osdp_pd *pd, uint8_t *buf, int max_len) buf[len++] = BYTE_1(cmd->output.timer_count); break; case CMD_LED: - assert_buf_len(CMD_LED_LEN, max_len); + if (!check_buf_len(CMD_LED_LEN, max_len)) { + return OSDP_CP_ERR_GENERIC; + } cmd = (struct osdp_cmd *)pd->ephemeral_data; buf[len++] = pd->cmd_id; buf[len++] = cmd->led.reader; @@ -202,7 +225,9 @@ static int cp_build_command(struct osdp_pd *pd, uint8_t *buf, int max_len) buf[len++] = cmd->led.permanent.off_color; break; case CMD_BUZ: - assert_buf_len(CMD_BUZ_LEN, max_len); + if (!check_buf_len(CMD_BUZ_LEN, max_len)) { + return OSDP_CP_ERR_GENERIC; + } cmd = (struct osdp_cmd *)pd->ephemeral_data; buf[len++] = pd->cmd_id; buf[len++] = cmd->buzzer.reader; @@ -213,7 +238,9 @@ static int cp_build_command(struct osdp_pd *pd, uint8_t *buf, int max_len) break; case CMD_TEXT: cmd = (struct osdp_cmd *)pd->ephemeral_data; - assert_buf_len(CMD_TEXT_LEN + cmd->text.length, max_len); + if (!check_buf_len(CMD_TEXT_LEN + cmd->text.length, max_len)) { + return OSDP_CP_ERR_GENERIC; + } buf[len++] = pd->cmd_id; buf[len++] = cmd->text.reader; buf[len++] = cmd->text.control_code; @@ -225,7 +252,9 @@ static int cp_build_command(struct osdp_pd *pd, uint8_t *buf, int max_len) len += cmd->text.length; break; case CMD_COMSET: - assert_buf_len(CMD_COMSET_LEN, max_len); + if (!check_buf_len(CMD_COMSET_LEN, max_len)) { + return OSDP_CP_ERR_GENERIC; + } cmd = (struct osdp_cmd *)pd->ephemeral_data; buf[len++] = pd->cmd_id; buf[len++] = cmd->comset.address; @@ -240,7 +269,9 @@ static int cp_build_command(struct osdp_pd *pd, uint8_t *buf, int max_len) LOG_ERR("Cannot perform KEYSET without SC!"); return OSDP_CP_ERR_GENERIC; } - assert_buf_len(CMD_KEYSET_LEN, max_len); + if (!check_buf_len(CMD_KEYSET_LEN, max_len)) { + return OSDP_CP_ERR_GENERIC; + } cmd = (struct osdp_cmd *)pd->ephemeral_data; if (cmd->keyset.length != 16) { LOG_ERR("Invalid key length"); @@ -260,7 +291,9 @@ static int cp_build_command(struct osdp_pd *pd, uint8_t *buf, int max_len) len += 16; break; case CMD_CHLNG: - assert_buf_len(CMD_CHLNG_LEN, max_len); + if (!check_buf_len(CMD_CHLNG_LEN, max_len)) { + return OSDP_CP_ERR_GENERIC; + } if (smb == NULL) { LOG_ERR("Invalid secure message block!"); return -1; @@ -273,7 +306,9 @@ static int cp_build_command(struct osdp_pd *pd, uint8_t *buf, int max_len) len += 8; break; case CMD_SCRYPT: - assert_buf_len(CMD_SCRYPT_LEN, max_len); + if (!check_buf_len(CMD_SCRYPT_LEN, max_len)) { + return OSDP_CP_ERR_GENERIC; + } if (smb == NULL) { LOG_ERR("Invalid secure message block!"); return -1; diff --git a/subsys/mgmt/osdp/src/osdp_pd.c b/subsys/mgmt/osdp/src/osdp_pd.c index ceb17c2d1a9..9f3e7d42892 100644 --- a/subsys/mgmt/osdp/src/osdp_pd.c +++ b/subsys/mgmt/osdp/src/osdp_pd.c @@ -556,10 +556,13 @@ static int pd_decode_command(struct osdp_pd *pd, uint8_t *buf, int len) return ret; } -static inline void assert_buf_len(int need, int have) +static inline bool check_buf_len(int need, int have) { - __ASSERT(need < have, "OOM at build command: need:%d have:%d", - need, have); + if (need >= have) { + LOG_ERR("OOM at build reply: need:%d have:%d", need, have); + return false; + } + return true; } /** @@ -582,12 +585,16 @@ static int pd_build_reply(struct osdp_pd *pd, uint8_t *buf, int max_len) switch (pd->reply_id) { case REPLY_ACK: - assert_buf_len(REPLY_ACK_LEN, max_len); + if (!check_buf_len(REPLY_ACK_LEN, max_len)) { + return OSDP_PD_ERR_GENERIC; + } buf[len++] = pd->reply_id; ret = OSDP_PD_ERR_NONE; break; case REPLY_PDID: - assert_buf_len(REPLY_PDID_LEN, max_len); + if (!check_buf_len(REPLY_PDID_LEN, max_len)) { + return OSDP_PD_ERR_GENERIC; + } buf[len++] = pd->reply_id; buf[len++] = BYTE_0(pd->id.vendor_code); @@ -608,7 +615,9 @@ static int pd_build_reply(struct osdp_pd *pd, uint8_t *buf, int max_len) ret = OSDP_PD_ERR_NONE; break; case REPLY_PDCAP: - assert_buf_len(REPLY_PDCAP_LEN, max_len); + if (!check_buf_len(REPLY_PDCAP_LEN, max_len)) { + return OSDP_PD_ERR_GENERIC; + } buf[len++] = pd->reply_id; for (i = 1; i < OSDP_PD_CAP_SENTINEL; i++) { if (pd->cap[i].function_code != i) { @@ -626,21 +635,27 @@ static int pd_build_reply(struct osdp_pd *pd, uint8_t *buf, int max_len) ret = OSDP_PD_ERR_NONE; break; case REPLY_LSTATR: - assert_buf_len(REPLY_LSTATR_LEN, max_len); + if (!check_buf_len(REPLY_LSTATR_LEN, max_len)) { + return OSDP_PD_ERR_GENERIC; + } buf[len++] = pd->reply_id; buf[len++] = ISSET_FLAG(pd, PD_FLAG_TAMPER); buf[len++] = ISSET_FLAG(pd, PD_FLAG_POWER); ret = OSDP_PD_ERR_NONE; break; case REPLY_RSTATR: - assert_buf_len(REPLY_RSTATR_LEN, max_len); + if (!check_buf_len(REPLY_RSTATR_LEN, max_len)) { + return OSDP_PD_ERR_GENERIC; + } buf[len++] = pd->reply_id; buf[len++] = ISSET_FLAG(pd, PD_FLAG_R_TAMPER); ret = OSDP_PD_ERR_NONE; break; case REPLY_KEYPPAD: event = (struct osdp_event *)pd->ephemeral_data; - assert_buf_len(REPLY_KEYPAD_LEN + event->keypress.length, max_len); + if (!check_buf_len(REPLY_KEYPAD_LEN + event->keypress.length, max_len)) { + return OSDP_PD_ERR_GENERIC; + } buf[len++] = pd->reply_id; buf[len++] = (uint8_t)event->keypress.reader_no; buf[len++] = (uint8_t)event->keypress.length; @@ -653,7 +668,9 @@ static int pd_build_reply(struct osdp_pd *pd, uint8_t *buf, int max_len) event = (struct osdp_event *)pd->ephemeral_data; len_bytes = (event->cardread.length + 7) / 8; - assert_buf_len(REPLY_RAW_LEN + len_bytes, max_len); + if (!check_buf_len(REPLY_RAW_LEN + len_bytes, max_len)) { + return OSDP_PD_ERR_GENERIC; + } buf[len++] = pd->reply_id; buf[len++] = (uint8_t)event->cardread.reader_no; buf[len++] = (uint8_t)event->cardread.format; @@ -666,7 +683,9 @@ static int pd_build_reply(struct osdp_pd *pd, uint8_t *buf, int max_len) } case REPLY_FMT: event = (struct osdp_event *)pd->ephemeral_data; - assert_buf_len(REPLY_FMT_LEN + event->cardread.length, max_len); + if (!check_buf_len(REPLY_FMT_LEN + event->cardread.length, max_len)) { + return OSDP_PD_ERR_GENERIC; + } buf[len++] = pd->reply_id; buf[len++] = (uint8_t)event->cardread.reader_no; buf[len++] = (uint8_t)event->cardread.direction; @@ -676,7 +695,9 @@ static int pd_build_reply(struct osdp_pd *pd, uint8_t *buf, int max_len) ret = OSDP_PD_ERR_NONE; break; case REPLY_COM: - assert_buf_len(REPLY_COM_LEN, max_len); + if (!check_buf_len(REPLY_COM_LEN, max_len)) { + return OSDP_PD_ERR_GENERIC; + } /** * If COMSET succeeds, the PD must reply with the old params and * then switch to the new params from then then on. We have the @@ -702,7 +723,9 @@ static int pd_build_reply(struct osdp_pd *pd, uint8_t *buf, int max_len) ret = OSDP_PD_ERR_NONE; break; case REPLY_NAK: - assert_buf_len(REPLY_NAK_LEN, max_len); + if (!check_buf_len(REPLY_NAK_LEN, max_len)) { + return OSDP_PD_ERR_GENERIC; + } buf[len++] = pd->reply_id; buf[len++] = pd->ephemeral_data[0]; ret = OSDP_PD_ERR_NONE; @@ -712,7 +735,9 @@ static int pd_build_reply(struct osdp_pd *pd, uint8_t *buf, int max_len) if (smb == NULL) { break; } - assert_buf_len(REPLY_CCRYPT_LEN, max_len); + if (!check_buf_len(REPLY_CCRYPT_LEN, max_len)) { + return OSDP_PD_ERR_GENERIC; + } osdp_fill_random(pd->sc.pd_random, 8); osdp_compute_session_keys(pd); osdp_compute_pd_cryptogram(pd); @@ -730,7 +755,9 @@ static int pd_build_reply(struct osdp_pd *pd, uint8_t *buf, int max_len) if (smb == NULL) { break; } - assert_buf_len(REPLY_RMAC_I_LEN, max_len); + if (!check_buf_len(REPLY_RMAC_I_LEN, max_len)) { + return OSDP_PD_ERR_GENERIC; + } osdp_compute_rmac_i(pd); buf[len++] = pd->reply_id; memcpy(buf + len, pd->sc.r_mac, 16); @@ -766,7 +793,9 @@ static int pd_build_reply(struct osdp_pd *pd, uint8_t *buf, int max_len) /* catch all errors and report it as a RECORD error to CP */ LOG_ERR("Failed to build REPLY(%02x); Sending NAK instead!", pd->reply_id); - assert_buf_len(REPLY_NAK_LEN, max_len); + if (!check_buf_len(REPLY_NAK_LEN, max_len)) { + return OSDP_PD_ERR_GENERIC; + } buf[0] = REPLY_NAK; buf[1] = OSDP_PD_NAK_RECORD; len = 2; From 5b24a8ad72c5dc37f14a4469be8683b057ed6f62 Mon Sep 17 00:00:00 2001 From: Siddharth Chandrasekaran Date: Tue, 24 Oct 2023 22:15:09 +0200 Subject: [PATCH 0137/3723] mgmt/osdp: Fix off-by-one in buf len checks Initially, the command/reply ID byte was not part of the data length macros. But later, when it was changed to include it, the buffer length checks was not adjusted. Due to this, we were not using the last byte in the buffer. Fix this issue by correcting the condition. Signed-off-by: Siddharth Chandrasekaran --- subsys/mgmt/osdp/src/osdp_cp.c | 2 +- subsys/mgmt/osdp/src/osdp_pd.c | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/subsys/mgmt/osdp/src/osdp_cp.c b/subsys/mgmt/osdp/src/osdp_cp.c index e9c5d19d2eb..cf475c5c4cb 100644 --- a/subsys/mgmt/osdp/src/osdp_cp.c +++ b/subsys/mgmt/osdp/src/osdp_cp.c @@ -116,7 +116,7 @@ int osdp_extract_address(int *address) static inline bool check_buf_len(int need, int have) { - if (need >= have) { + if (need > have) { LOG_ERR("OOM at build command: need:%d have:%d", need, have); return false; } diff --git a/subsys/mgmt/osdp/src/osdp_pd.c b/subsys/mgmt/osdp/src/osdp_pd.c index 9f3e7d42892..bbaa24a5f0e 100644 --- a/subsys/mgmt/osdp/src/osdp_pd.c +++ b/subsys/mgmt/osdp/src/osdp_pd.c @@ -558,7 +558,7 @@ static int pd_decode_command(struct osdp_pd *pd, uint8_t *buf, int len) static inline bool check_buf_len(int need, int have) { - if (need >= have) { + if (need > have) { LOG_ERR("OOM at build reply: need:%d have:%d", need, have); return false; } From 2750e1e3b58a17b631bf84e6b55703e8a2b24c6a Mon Sep 17 00:00:00 2001 From: Hein Wessels Date: Sat, 18 Nov 2023 07:47:05 +0100 Subject: [PATCH 0138/3723] drivers: dma: stm32: add utilities to access properties by idx Some drivers like the ADC access the DMA through it's index and not the DMA name. This commit add some better support for such instances. Signed-off-by: Hein Wessels --- include/zephyr/drivers/dma/dma_stm32.h | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/include/zephyr/drivers/dma/dma_stm32.h b/include/zephyr/drivers/dma/dma_stm32.h index 3ccfeb9be10..c4c593457cb 100644 --- a/include/zephyr/drivers/dma/dma_stm32.h +++ b/include/zephyr/drivers/dma/dma_stm32.h @@ -33,8 +33,10 @@ /* macro for dma slot (only for dma-v1 or dma-v2 types) */ #if DT_HAS_COMPAT_STATUS_OKAY(st_stm32_dma_v2bis) #define STM32_DMA_SLOT(id, dir, slot) 0 +#define STM32_DMA_SLOT_BY_IDX(id, idx, slot) #else #define STM32_DMA_SLOT(id, dir, slot) DT_INST_DMAS_CELL_BY_NAME(id, dir, slot) +#define STM32_DMA_SLOT_BY_IDX(id, idx, slot) DT_INST_DMAS_CELL_BY_IDX(id, idx, slot) #endif #if DT_HAS_COMPAT_STATUS_OKAY(st_stm32_dma_v2) || \ @@ -50,6 +52,8 @@ DT_INST_DMAS_CTLR_BY_NAME(id, dir) #define STM32_DMA_CHANNEL_CONFIG(id, dir) \ DT_INST_DMAS_CELL_BY_NAME(id, dir, channel_config) +#define STM32_DMA_CHANNEL_CONFIG_BY_IDX(id, idx) \ + DT_INST_DMAS_CELL_BY_IDX(id, idx, channel_config) /* macros for channel-config */ /* direction defined on bits 6-7 */ From f27e45473ae2c096d4b6bd03427723ec6fa8894f Mon Sep 17 00:00:00 2001 From: Hein Wessels Date: Sat, 18 Nov 2023 08:15:44 +0100 Subject: [PATCH 0139/3723] drivers: adc: stm32: driver now agnostic of actual dma name Previously the STM32 DMA driver was dependent on a very specific name for the DMA in the DTS. This hidden requirement has caused a bit of confusion. This commit changes the driver to instead always use the first DMA listed in the ADC node's dma property. Should fix: #65387 Signed-off-by: Hein Wessels --- drivers/adc/adc_stm32.c | 34 +++++++++++++++++----------------- 1 file changed, 17 insertions(+), 17 deletions(-) diff --git a/drivers/adc/adc_stm32.c b/drivers/adc/adc_stm32.c index 12a38c415fd..fd5dd686d46 100644 --- a/drivers/adc/adc_stm32.c +++ b/drivers/adc/adc_stm32.c @@ -1521,39 +1521,39 @@ static void adc_stm32_irq_init(void) #define ADC_STM32_IRQ_CONFIG(index) #define ADC_STM32_IRQ_FUNC(index) \ .irq_cfg_func = adc_stm32_irq_init, -#define ADC_DMA_CHANNEL(id, dir, DIR, src, dest) +#define ADC_DMA_CHANNEL(id, src, dest) #elif defined(CONFIG_ADC_STM32_DMA) /* !CONFIG_ADC_STM32_SHARED_IRQS */ -#define ADC_DMA_CHANNEL_INIT(index, name, dir_cap, src_dev, dest_dev) \ +#define ADC_DMA_CHANNEL_INIT(index, src_dev, dest_dev) \ .dma = { \ - .dma_dev = DEVICE_DT_GET(STM32_DMA_CTLR(index, name)), \ - .channel = DT_INST_DMAS_CELL_BY_NAME(index, name, channel), \ + .dma_dev = DEVICE_DT_GET(DT_INST_DMAS_CTLR_BY_IDX(index, 0)), \ + .channel = STM32_DMA_SLOT_BY_IDX(index, 0, channel), \ .dma_cfg = { \ - .dma_slot = STM32_DMA_SLOT(index, name, slot), \ + .dma_slot = STM32_DMA_SLOT_BY_IDX(index, 0, slot), \ .channel_direction = STM32_DMA_CONFIG_DIRECTION( \ - STM32_DMA_CHANNEL_CONFIG(index, name)), \ + STM32_DMA_CHANNEL_CONFIG_BY_IDX(index, 0)), \ .source_data_size = STM32_DMA_CONFIG_##src_dev##_DATA_SIZE( \ - STM32_DMA_CHANNEL_CONFIG(index, name)), \ + STM32_DMA_CHANNEL_CONFIG_BY_IDX(index, 0)), \ .dest_data_size = STM32_DMA_CONFIG_##dest_dev##_DATA_SIZE( \ - STM32_DMA_CHANNEL_CONFIG(index, name)), \ + STM32_DMA_CHANNEL_CONFIG_BY_IDX(index, 0)), \ .source_burst_length = 1, /* SINGLE transfer */ \ .dest_burst_length = 1, /* SINGLE transfer */ \ .channel_priority = STM32_DMA_CONFIG_PRIORITY( \ - STM32_DMA_CHANNEL_CONFIG(index, name)), \ + STM32_DMA_CHANNEL_CONFIG_BY_IDX(index, 0)), \ .dma_callback = dma_callback, \ .block_count = 2, \ }, \ .src_addr_increment = STM32_DMA_CONFIG_##src_dev##_ADDR_INC( \ - STM32_DMA_CHANNEL_CONFIG(index, name)), \ + STM32_DMA_CHANNEL_CONFIG_BY_IDX(index, 0)), \ .dst_addr_increment = STM32_DMA_CONFIG_##dest_dev##_ADDR_INC( \ - STM32_DMA_CHANNEL_CONFIG(index, name)), \ + STM32_DMA_CHANNEL_CONFIG_BY_IDX(index, 0)), \ } -#define ADC_DMA_CHANNEL(id, dir, DIR, src, dest) \ - COND_CODE_1(DT_INST_DMAS_HAS_NAME(id, dir), \ - (ADC_DMA_CHANNEL_INIT(id, dir, DIR, src, dest)), \ - (EMPTY)) +#define ADC_DMA_CHANNEL(id, src, dest) \ + COND_CODE_1(DT_INST_DMAS_HAS_IDX(id, 0), \ + (ADC_DMA_CHANNEL_INIT(id, src, dest)), \ + (/* Required for other adc instances without dma */)) #define ADC_STM32_IRQ_CONFIG(index) \ static void adc_stm32_cfg_func_##index(void){ EMPTY } @@ -1572,7 +1572,7 @@ static void adc_stm32_cfg_func_##index(void) \ } #define ADC_STM32_IRQ_FUNC(index) \ .irq_cfg_func = adc_stm32_cfg_func_##index, -#define ADC_DMA_CHANNEL(id, dir, DIR, src, dest) +#define ADC_DMA_CHANNEL(id, src, dest) #endif /* CONFIG_ADC_STM32_DMA && CONFIG_ADC_STM32_SHARED_IRQS */ @@ -1605,7 +1605,7 @@ static struct adc_stm32_data adc_stm32_data_##index = { \ ADC_CONTEXT_INIT_TIMER(adc_stm32_data_##index, ctx), \ ADC_CONTEXT_INIT_LOCK(adc_stm32_data_##index, ctx), \ ADC_CONTEXT_INIT_SYNC(adc_stm32_data_##index, ctx), \ - ADC_DMA_CHANNEL(index, dmamux, NULL, PERIPHERAL, MEMORY) \ + ADC_DMA_CHANNEL(index, PERIPHERAL, MEMORY) \ }; \ \ PM_DEVICE_DT_INST_DEFINE(index, adc_stm32_pm_action); \ From a257bcb73589779985b2c3632d7236c42c159b58 Mon Sep 17 00:00:00 2001 From: Hein Wessels Date: Mon, 20 Nov 2023 14:24:04 +0100 Subject: [PATCH 0140/3723] drivers: adc: stm32: add dma support for other mcus This commit adds support for more STM32 CPUs that has a different DMA interface. This was tested only for the nucleo_l476rg. Signed-off-by: Hein Wessels --- drivers/adc/adc_stm32.c | 49 ++++++++++++++++++++++++++++------------- 1 file changed, 34 insertions(+), 15 deletions(-) diff --git a/drivers/adc/adc_stm32.c b/drivers/adc/adc_stm32.c index fd5dd686d46..767308a396b 100644 --- a/drivers/adc/adc_stm32.c +++ b/drivers/adc/adc_stm32.c @@ -216,6 +216,39 @@ static bool init_irq = true; #endif #ifdef CONFIG_ADC_STM32_DMA +static void adc_stm32_enable_dma_support(ADC_TypeDef *adc) +{ + /* Allow ADC to create DMA request and set to one-shot mode as implemented in HAL drivers */ + +#if defined(CONFIG_SOC_SERIES_STM32H7X) + +#if defined(ADC_VER_V5_V90) + if (adc == ADC3) { + LL_ADC_REG_SetDMATransferMode(adc, + ADC3_CFGR_DMACONTREQ(LL_ADC_REG_DMA_TRANSFER_LIMITED)); + LL_ADC_EnableDMAReq(adc); + } else { + LL_ADC_REG_SetDataTransferMode(adc, + ADC_CFGR_DMACONTREQ(LL_ADC_REG_DMA_TRANSFER_LIMITED)); + } +#elif defined(ADC_VER_V5_X) + LL_ADC_REG_SetDataTransferMode(adc, LL_ADC_REG_DMA_TRANSFER_LIMITED); +#else +#error "Unsupported ADC version" +#endif + +#elif DT_HAS_COMPAT_STATUS_OKAY(st_stm32f1_adc) /* defined(CONFIG_SOC_SERIES_STM32H7X) */ + +#error "The STM32F1 ADC + DMA is not yet supported" + +#else /* DT_HAS_COMPAT_STATUS_OKAY(st_stm32f1_adc) */ + + /* Default mechanism for other MCUs */ + LL_ADC_REG_SetDMATransfer(adc, LL_ADC_REG_DMA_TRANSFER_LIMITED); + +#endif +} + static int adc_stm32_dma_start(const struct device *dev, void *buffer, size_t channel_count) { @@ -257,21 +290,7 @@ static int adc_stm32_dma_start(const struct device *dev, return ret; } - /* Allow ADC to create DMA request and set to one-shot mode, - * as implemented in HAL drivers, if applicable. - */ -#if defined(ADC_VER_V5_V90) - if (adc == ADC3) { - LL_ADC_REG_SetDMATransferMode(adc, - ADC3_CFGR_DMACONTREQ(LL_ADC_REG_DMA_TRANSFER_LIMITED)); - LL_ADC_EnableDMAReq(adc); - } else { - LL_ADC_REG_SetDataTransferMode(adc, - ADC_CFGR_DMACONTREQ(LL_ADC_REG_DMA_TRANSFER_LIMITED)); - } -#elif defined(ADC_VER_V5_X) - LL_ADC_REG_SetDataTransferMode(adc, LL_ADC_REG_DMA_TRANSFER_LIMITED); -#endif + adc_stm32_enable_dma_support(adc); data->dma_error = 0; ret = dma_start(data->dma.dma_dev, data->dma.channel); From 82a6a69b818df6830e1d1bfa0fe82f5a89e65011 Mon Sep 17 00:00:00 2001 From: Hein Wessels Date: Mon, 20 Nov 2023 14:36:04 +0100 Subject: [PATCH 0141/3723] tests: drivers: adc_dma: add test for nucleo_l476rg Add test to verify the ADC + DMA functionality works for the STM32L476 MCU. Signed-off-by: Hein Wessels --- .../adc/adc_dma/boards/nucleo_l476rg.conf | 8 ++++++++ .../adc/adc_dma/boards/nucleo_l476rg.overlay | 17 +++++++++++++++++ tests/drivers/adc/adc_dma/src/test_adc.c | 11 +++++++++++ 3 files changed, 36 insertions(+) create mode 100644 tests/drivers/adc/adc_dma/boards/nucleo_l476rg.conf create mode 100644 tests/drivers/adc/adc_dma/boards/nucleo_l476rg.overlay diff --git a/tests/drivers/adc/adc_dma/boards/nucleo_l476rg.conf b/tests/drivers/adc/adc_dma/boards/nucleo_l476rg.conf new file mode 100644 index 00000000000..e3fe93c1c0c --- /dev/null +++ b/tests/drivers/adc/adc_dma/boards/nucleo_l476rg.conf @@ -0,0 +1,8 @@ +# +# Copyright (c) 2023 Hein Wessels, Nobleo Technology +# +# SPDX-License-Identifier: Apache-2.0 +# + +CONFIG_ADC_STM32_DMA=y +CONFIG_ADC_ASYNC=y diff --git a/tests/drivers/adc/adc_dma/boards/nucleo_l476rg.overlay b/tests/drivers/adc/adc_dma/boards/nucleo_l476rg.overlay new file mode 100644 index 00000000000..990a83f351b --- /dev/null +++ b/tests/drivers/adc/adc_dma/boards/nucleo_l476rg.overlay @@ -0,0 +1,17 @@ +/* + * Copyright (c) 2023 Hein Wessels, Nobleo Technology + * + * SPDX-License-Identifier: Apache-2.0 + */ + +&adc1 { + dmas = < &dma1 1 0 (STM32_DMA_PERIPH_RX | STM32_DMA_MEM_16BITS | STM32_DMA_PERIPH_16BITS) >; + dma-names = "dma"; + + #address-cells = <1>; + #size-cells = <0>; +}; + +test_dma: &dma1 { + status = "okay"; +}; diff --git a/tests/drivers/adc/adc_dma/src/test_adc.c b/tests/drivers/adc/adc_dma/src/test_adc.c index c9a1ac4b0dc..f80ee54dd7e 100644 --- a/tests/drivers/adc/adc_dma/src/test_adc.c +++ b/tests/drivers/adc/adc_dma/src/test_adc.c @@ -61,6 +61,17 @@ #define ADC_2ND_CHANNEL_ID 7 #define ALIGNMENT 32 +#elif defined(CONFIG_BOARD_NUCLEO_L476RG) + +#define ADC_DEVICE_NODE DT_INST(0, st_stm32_adc) +#define ADC_RESOLUTION 12 +#define ADC_GAIN ADC_GAIN_1 +#define ADC_REFERENCE ADC_REF_INTERNAL +#define ADC_ACQUISITION_TIME ADC_ACQ_TIME_DEFAULT +#define ADC_1ST_CHANNEL_ID 1 +#define ADC_2ND_CHANNEL_ID 7 +#define ALIGNMENT 32 + #endif /* Invalid value that is not supposed to be written by the driver. It is used From c0eb91803771ad0a0df30af5e1152c5da31ac865 Mon Sep 17 00:00:00 2001 From: Kamil Rakoczy Date: Wed, 22 Nov 2023 14:07:15 +0100 Subject: [PATCH 0142/3723] posix: sys: fix missing include to _timeval.h in native_sim zephyr/net/socket_types.h file also includes _timeval.h, but it uses correct path/filename depending on configuration. Signed-off-by: Kamil Rakoczy --- include/zephyr/posix/sys/select.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/include/zephyr/posix/sys/select.h b/include/zephyr/posix/sys/select.h index 0fd2b5de9e6..4420b69eaba 100644 --- a/include/zephyr/posix/sys/select.h +++ b/include/zephyr/posix/sys/select.h @@ -6,8 +6,8 @@ #ifndef ZEPHYR_INCLUDE_POSIX_SYS_SELECT_H_ #define ZEPHYR_INCLUDE_POSIX_SYS_SELECT_H_ +#include #include -#include #ifdef __cplusplus extern "C" { From 58175fcf1829a9350ce936b9e02dd2e20279961e Mon Sep 17 00:00:00 2001 From: Maximilian Deubel Date: Wed, 22 Nov 2023 13:30:36 +0100 Subject: [PATCH 0143/3723] boards: nrf9131ek and nrf9161dk: update readme to emphasize nr-plus This patch changes readme files of nRF91x1 dev kits to highlight their added NR+ feature. Signed-off-by: Maximilian Deubel --- boards/arm/nrf9131ek_nrf9131/doc/index.rst | 3 ++- boards/arm/nrf9161dk_nrf9161/doc/index.rst | 2 +- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/boards/arm/nrf9131ek_nrf9131/doc/index.rst b/boards/arm/nrf9131ek_nrf9131/doc/index.rst index a72cd1526e3..57473c631ed 100644 --- a/boards/arm/nrf9131ek_nrf9131/doc/index.rst +++ b/boards/arm/nrf9131ek_nrf9131/doc/index.rst @@ -6,7 +6,8 @@ nRF9131 EK Overview ******** -The nRF9131 EK (PCA10165) is a single-board evaluation kit for the nRF9131 SiP for LTE-M and NB-IoT. +The nRF9131 EK (PCA10165) is a single-board evaluation kit for the nRF9131 SiP +for DECT NR+ and LTE-M/NB-IoT with GNSS. The nrf9131ek_nrf9131 board configuration provides support for the Nordic Semiconductor nRF9131 ARM Cortex-M33F CPU with ARMv8-M Security Extension and the following devices: diff --git a/boards/arm/nrf9161dk_nrf9161/doc/index.rst b/boards/arm/nrf9161dk_nrf9161/doc/index.rst index 559288b06aa..18b214a7fde 100644 --- a/boards/arm/nrf9161dk_nrf9161/doc/index.rst +++ b/boards/arm/nrf9161dk_nrf9161/doc/index.rst @@ -7,7 +7,7 @@ Overview ******** The nRF9161 DK (PCA10153) is a single-board development kit for evaluation and -development on the nRF9161 SiP for LTE-M and NB-IoT. The nrf9161dk_nrf9161 +development on the nRF9161 SiP for DECT NR+ and LTE-M/NB-IoT with GNSS. The nrf9161dk_nrf9161 board configuration provides support for the Nordic Semiconductor nRF9161 ARM Cortex-M33F CPU with ARMv8-M Security Extension and the following devices: From 1ab669e3d08510da2b107d917da501f376e6a76d Mon Sep 17 00:00:00 2001 From: Joakim Andersson Date: Tue, 21 Nov 2023 17:40:23 +0100 Subject: [PATCH 0144/3723] tfm: Remove SFN model FP limitation Despite what the TF-M documentation says about SFN model not supporting Floating Point, it does support it, according to TF-M developers. Remove SFN limitation not supported with FP Hard ABI. Signed-off-by: Joakim Andersson --- arch/arm/core/Kconfig | 2 -- modules/trusted-firmware-m/Kconfig.tfm | 1 - 2 files changed, 3 deletions(-) diff --git a/arch/arm/core/Kconfig b/arch/arm/core/Kconfig index 75a64ea90eb..ac3fe19b984 100644 --- a/arch/arm/core/Kconfig +++ b/arch/arm/core/Kconfig @@ -276,8 +276,6 @@ config FP_HARDABI point instructions are generated and uses FPU-specific calling conventions. - Note: When building with TF-M enabled only the IPC mode is supported. - config FP_SOFTABI bool "Floating point Soft ABI" help diff --git a/modules/trusted-firmware-m/Kconfig.tfm b/modules/trusted-firmware-m/Kconfig.tfm index b635347b6e1..d29b7093de0 100644 --- a/modules/trusted-firmware-m/Kconfig.tfm +++ b/modules/trusted-firmware-m/Kconfig.tfm @@ -324,7 +324,6 @@ config TFM_IPC config TFM_SFN bool "SFN model" - depends on !FP_HARDABI help Use the SFN Model as the SPM backend for the PSA API. The SFN model supports the SFN Partition model, and isolation level 1. From 2ad6dda9fdfc81ef2a83e44e25a85be01719d623 Mon Sep 17 00:00:00 2001 From: Joakim Andersson Date: Tue, 21 Nov 2023 19:02:47 +0100 Subject: [PATCH 0145/3723] tfm: Remove limitation of enabling FP when build TF-M NS application Remove limitation of enabling FP when building TF-M NS application. FP support have been fixed in the tf-m-tests repository for NS application. Board support for NS executable may still be lacking for some boards. Signed-off-by: Joakim Andersson --- arch/arm/core/Kconfig | 3 --- 1 file changed, 3 deletions(-) diff --git a/arch/arm/core/Kconfig b/arch/arm/core/Kconfig index ac3fe19b984..dd322bff626 100644 --- a/arch/arm/core/Kconfig +++ b/arch/arm/core/Kconfig @@ -268,9 +268,6 @@ choice config FP_HARDABI bool "Floating point Hard ABI" - # TF-M build system does not build the NS app and libraries correctly with Hard ABI. - # This limitation should be removed in the next TF-M synchronization. - depends on !TFM_BUILD_NS help This option selects the Floating point ABI in which hardware floating point instructions are generated and uses FPU-specific calling From b43271dc2d6f4bde312b96c675bead73a122dcbd Mon Sep 17 00:00:00 2001 From: Flavio Ceolin Date: Tue, 21 Nov 2023 10:08:03 -0800 Subject: [PATCH 0146/3723] doc: vuln: Disclose information about CVE-2023-5055 Information about CVE-2023-5055 Signed-off-by: Flavio Ceolin --- doc/security/vulnerabilities.rst | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/doc/security/vulnerabilities.rst b/doc/security/vulnerabilities.rst index 61d0d25f618..eb2e4e47229 100644 --- a/doc/security/vulnerabilities.rst +++ b/doc/security/vulnerabilities.rst @@ -1506,7 +1506,16 @@ Under embargo until 2023/11/01 CVE-2023-5055 ------------- -Under embargo until 2023/11/01 +L2CAP: Possible Stack based buffer overflow in le_ecred_reconf_req() + +- `Zephyr project bug tracker GHSA-wr8r-7f8x-24jj + `_ + +This has been fixed in main for v3.5.0 + +- `PR 62381 fix for main + `_ + CVE-2023-5139 ------------- From 062fc2242acb39f21aae9ae4a5a8251b780d43f0 Mon Sep 17 00:00:00 2001 From: Daniel Leung Date: Tue, 21 Nov 2023 12:56:12 -0800 Subject: [PATCH 0147/3723] sys: arch_interface: include arch/syscall.h if USERSPACE Due to arch_syscall_invoke are declared static, if there are no corresponding definition, compiler will complain. It has been working fine so far because arch/syscall.h is included indirectly through some other headers (especially through generated syscall stubs). However, with enough header files shuffling this becomes an issue. So include arch/syscall.h in arch_interface.h explicitly. Signed-off-by: Daniel Leung --- include/zephyr/sys/arch_interface.h | 2 ++ 1 file changed, 2 insertions(+) diff --git a/include/zephyr/sys/arch_interface.h b/include/zephyr/sys/arch_interface.h index e694bce55cc..1e5eaad87b1 100644 --- a/include/zephyr/sys/arch_interface.h +++ b/include/zephyr/sys/arch_interface.h @@ -517,6 +517,8 @@ static inline unsigned int arch_num_cpus(void); */ #ifdef CONFIG_USERSPACE +#include + /** * Invoke a system call with 0 arguments. * From 40ba4015e313863facc721f7f06210b03057197c Mon Sep 17 00:00:00 2001 From: Daniel Leung Date: Tue, 21 Nov 2023 15:04:02 -0800 Subject: [PATCH 0148/3723] kernel: mm: only include demand_paging.h if needed This moves including of demand_paging.h out of kernel/mm.h, so that users of demand paging APIs must include the header explicitly. Since the main user is kernel itself, we can be more discipline about header inclusion. Signed-off-by: Daniel Leung --- arch/x86/core/userspace.c | 4 ++++ include/zephyr/kernel/mm.h | 1 - include/zephyr/kernel/thread.h | 2 +- kernel/mmu.c | 4 ++++ kernel/paging/statistics.c | 2 +- .../demand_paging/backing_store/backing_store_qemu_x86_tiny.c | 1 + subsys/demand_paging/backing_store/ram.c | 1 + subsys/demand_paging/eviction/nru.c | 2 ++ tests/kernel/fatal/exception/src/main.c | 4 ++++ tests/kernel/mem_protect/demand_paging/src/main.c | 1 + 10 files changed, 19 insertions(+), 3 deletions(-) diff --git a/arch/x86/core/userspace.c b/arch/x86/core/userspace.c index 2b058206232..9380c14d005 100644 --- a/arch/x86/core/userspace.c +++ b/arch/x86/core/userspace.c @@ -11,6 +11,10 @@ #include #include +#ifdef CONFIG_DEMAND_PAGING +#include +#endif + #ifndef CONFIG_X86_KPTI /* Update the to the incoming thread's page table, and update the location of * the privilege elevation stack. diff --git a/include/zephyr/kernel/mm.h b/include/zephyr/kernel/mm.h index 392dc4b7cde..0f6c76e7cdc 100644 --- a/include/zephyr/kernel/mm.h +++ b/include/zephyr/kernel/mm.h @@ -14,7 +14,6 @@ #endif #include -#include /** * @brief Kernel Memory Management diff --git a/include/zephyr/kernel/thread.h b/include/zephyr/kernel/thread.h index b152dfb909a..91cf710e870 100644 --- a/include/zephyr/kernel/thread.h +++ b/include/zephyr/kernel/thread.h @@ -8,7 +8,7 @@ #define ZEPHYR_INCLUDE_KERNEL_THREAD_H_ #ifdef CONFIG_DEMAND_PAGING_THREAD_STATS -#include +#include #endif #include diff --git a/kernel/mmu.c b/kernel/mmu.c index 6abd9349dd6..a58bc77189b 100644 --- a/kernel/mmu.c +++ b/kernel/mmu.c @@ -20,6 +20,10 @@ #include LOG_MODULE_DECLARE(os, CONFIG_KERNEL_LOG_LEVEL); +#ifdef CONFIG_DEMAND_PAGING +#include +#endif + /* * General terminology: * - A page frame is a page-sized physical memory region in RAM. It is a diff --git a/kernel/paging/statistics.c b/kernel/paging/statistics.c index e8972738135..06e867cd218 100644 --- a/kernel/paging/statistics.c +++ b/kernel/paging/statistics.c @@ -8,7 +8,7 @@ #include #include #include -#include +#include extern struct k_mem_paging_stats_t paging_stats; diff --git a/subsys/demand_paging/backing_store/backing_store_qemu_x86_tiny.c b/subsys/demand_paging/backing_store/backing_store_qemu_x86_tiny.c index 023adc06fad..9f100649d49 100644 --- a/subsys/demand_paging/backing_store/backing_store_qemu_x86_tiny.c +++ b/subsys/demand_paging/backing_store/backing_store_qemu_x86_tiny.c @@ -20,6 +20,7 @@ #include #include #include +#include void *location_to_flash(uintptr_t location) { diff --git a/subsys/demand_paging/backing_store/ram.c b/subsys/demand_paging/backing_store/ram.c index c8ba9378a0b..a18995e1b7f 100644 --- a/subsys/demand_paging/backing_store/ram.c +++ b/subsys/demand_paging/backing_store/ram.c @@ -8,6 +8,7 @@ #include #include #include +#include /* * TODO: diff --git a/subsys/demand_paging/eviction/nru.c b/subsys/demand_paging/eviction/nru.c index 108bc504c02..83c4a3b53d7 100644 --- a/subsys/demand_paging/eviction/nru.c +++ b/subsys/demand_paging/eviction/nru.c @@ -10,6 +10,8 @@ #include #include +#include + /* The accessed and dirty states of each page frame are used to create * a hierarchy with a numerical value. When evicting a page, try to evict * page with the highest value (we prefer clean, not accessed pages). diff --git a/tests/kernel/fatal/exception/src/main.c b/tests/kernel/fatal/exception/src/main.c index ea4ffaa7c34..07ac26ffc55 100644 --- a/tests/kernel/fatal/exception/src/main.c +++ b/tests/kernel/fatal/exception/src/main.c @@ -18,6 +18,10 @@ #include "test_syscalls.h" #endif +#if defined(CONFIG_DEMAND_PAGING) +#include +#endif + #if defined(CONFIG_X86) && defined(CONFIG_X86_MMU) #define STACKSIZE (8192) #else diff --git a/tests/kernel/mem_protect/demand_paging/src/main.c b/tests/kernel/mem_protect/demand_paging/src/main.c index a453c06a573..7b733bfc340 100644 --- a/tests/kernel/mem_protect/demand_paging/src/main.c +++ b/tests/kernel/mem_protect/demand_paging/src/main.c @@ -6,6 +6,7 @@ #include #include +#include #include #include #include From 468890d70fa407b5013bf3bcb9911d0fcae4c7b8 Mon Sep 17 00:00:00 2001 From: Marcio Ribeiro Date: Wed, 15 Nov 2023 15:51:44 -0300 Subject: [PATCH 0149/3723] drivers: clock_control: clock_control_esp32 assert remotion No longer necessary assert removal Signed-off-by: Marcio Ribeiro --- drivers/clock_control/clock_control_esp32.c | 6 ------ 1 file changed, 6 deletions(-) diff --git a/drivers/clock_control/clock_control_esp32.c b/drivers/clock_control/clock_control_esp32.c index fba7091b871..52fb330d4b4 100644 --- a/drivers/clock_control/clock_control_esp32.c +++ b/drivers/clock_control/clock_control_esp32.c @@ -602,9 +602,3 @@ DEVICE_DT_DEFINE(DT_NODELABEL(rtc), PRE_KERNEL_1, CONFIG_CLOCK_CONTROL_INIT_PRIORITY, &clock_control_esp32_api); - -#ifndef CONFIG_SOC_SERIES_ESP32C3 -BUILD_ASSERT((CONFIG_SYS_CLOCK_HW_CYCLES_PER_SEC) == - DT_PROP(DT_INST(0, DT_CPU_COMPAT), clock_frequency), - "SYS_CLOCK_HW_CYCLES_PER_SEC Value must be equal to CPU_Freq"); -#endif From e7c7c5a769025bb1363b81c2fb4e630949093ad4 Mon Sep 17 00:00:00 2001 From: Bartosz Bilas Date: Tue, 21 Nov 2023 20:36:12 +0100 Subject: [PATCH 0150/3723] doc: zbus: add missing timeout arg for zbus_chan_add/rm_obs funcs zbus_chan_add_obs and zbus_chan_rm_obs functions require a timeout as their third arg. Signed-off-by: Bartosz Bilas --- doc/services/zbus/index.rst | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/doc/services/zbus/index.rst b/doc/services/zbus/index.rst index ca8ab6142a8..59d45317a7b 100644 --- a/doc/services/zbus/index.rst +++ b/doc/services/zbus/index.rst @@ -763,9 +763,9 @@ following example illustrates the runtime registration usage. void thread_entry(void) { // ... /* Adding the observer to channel chan1 */ - zbus_chan_add_obs(&chan1, &my_listener); + zbus_chan_add_obs(&chan1, &my_listener, K_NO_WAIT); /* Removing the observer from channel chan1 */ - zbus_chan_rm_obs(&chan1, &my_listener); + zbus_chan_rm_obs(&chan1, &my_listener, K_NO_WAIT); Samples From 4a262c3947e745fff542a2d78dbedfe460cc2541 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andrzej=20G=C5=82=C4=85bek?= Date: Tue, 21 Nov 2023 17:36:52 +0100 Subject: [PATCH 0151/3723] tests: drivers: flash: Update nrf52840dk_mx25r_high_perf.overlay MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This is a follow-up to commit 7a83724e0f18d7f2400517407150f9e9a1ecd6e6. This overlay uses an alternative connection (via spi2) for the external flash present on the nRF52840 DK and it needs to use one of the QSPI pins as GPIO, to get CS line control in the SPI communication. To make it possible, that GPIO must be removed from those marked as reserved. Signed-off-by: Andrzej Głąbek --- .../flash/common/boards/nrf52840dk_mx25r_high_perf.overlay | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/tests/drivers/flash/common/boards/nrf52840dk_mx25r_high_perf.overlay b/tests/drivers/flash/common/boards/nrf52840dk_mx25r_high_perf.overlay index eabb26ebda6..a67f25e46c0 100644 --- a/tests/drivers/flash/common/boards/nrf52840dk_mx25r_high_perf.overlay +++ b/tests/drivers/flash/common/boards/nrf52840dk_mx25r_high_perf.overlay @@ -1,5 +1,9 @@ /delete-node/ &qspi; +&gpio0 { + gpio-reserved-ranges = <0 2>, <6 1>, <8 3>, <18 6>; +}; + &spi2 { compatible = "nordic,nrf-spim"; status = "okay"; From c949018d36bd6a2b0453a52062adcc108060cce4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andrzej=20G=C5=82=C4=85bek?= Date: Tue, 21 Nov 2023 17:43:35 +0100 Subject: [PATCH 0152/3723] tests: drivers: flash: Use fixtures for tests requiring external chips MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Several scenarios in this test require specific external flash chips to be connected to the nRF52840 DK. Specify proper fixture for them so that they are not performed on the board without those required external components connected. Signed-off-by: Andrzej Głąbek --- tests/drivers/flash/common/testcase.yaml | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/tests/drivers/flash/common/testcase.yaml b/tests/drivers/flash/common/testcase.yaml index f7ee0b7fc6d..b0b0c9af91a 100644 --- a/tests/drivers/flash/common/testcase.yaml +++ b/tests/drivers/flash/common/testcase.yaml @@ -21,7 +21,7 @@ tests: - OVERLAY_CONFIG=boards/nrf52840_flash_qspi.conf - DTC_OVERLAY_FILE=boards/nrf52840dk_mx25l51245g.overlay harness_config: - fixture: external_flash + fixture: external_flash_mx25l51245g integration_platforms: - nrf52840dk_nrf52840 drivers.flash.common.soc_flash_nrf: @@ -78,11 +78,15 @@ tests: extra_args: - OVERLAY_CONFIG=boards/nrf52840dk_flash_spi.conf - DTC_OVERLAY_FILE=boards/nrf52840dk_spi_nor.overlay + harness_config: + fixture: external_flash_mx25v1635f drivers.flash.common.spi_nor_wp_hold: platform_allow: nrf52840dk_nrf52840 extra_args: - OVERLAY_CONFIG=boards/nrf52840dk_flash_spi.conf - DTC_OVERLAY_FILE=boards/nrf52840dk_spi_nor_wp_hold.overlay + harness_config: + fixture: external_flash_mx25v1635f drivers.flash.common.sam0: platform_allow: - atsamd20_xpro From f442c03a20f4d17b8a05ad304a9776493c2e4ecc Mon Sep 17 00:00:00 2001 From: Francois Ramu Date: Tue, 21 Nov 2023 16:15:50 +0100 Subject: [PATCH 0153/3723] samples: subsys: nvs on nucleo_g431 requires 6kB for storage partitions Add the overlay for running the samples/subsys/nvs/ application on the nucleo_g31rb. Define a 6kB storage_partition at the end of the 128kB flash. Signed-off-by: Francois Ramu --- samples/subsys/nvs/boards/nucleo_g431rb.overlay | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) create mode 100644 samples/subsys/nvs/boards/nucleo_g431rb.overlay diff --git a/samples/subsys/nvs/boards/nucleo_g431rb.overlay b/samples/subsys/nvs/boards/nucleo_g431rb.overlay new file mode 100644 index 00000000000..ee0f1af77ac --- /dev/null +++ b/samples/subsys/nvs/boards/nucleo_g431rb.overlay @@ -0,0 +1,17 @@ +/* + * Copyright (c) 2023 STMicroelectronics + * + * SPDX-License-Identifier: Apache-2.0 + */ + +/delete-node/ &storage_partition; + +&flash0 { + partitions { + /* Set 6KB of storage at the end of 128KB flash */ + storage_partition: partition@1e800 { + label = "storage"; + reg = <0x0001e800 DT_SIZE_K(6)>; + }; + }; +}; From c143daf98dbdc88f2154f86c05c4256d01cb79f2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Krzysztof=20Chru=C5=9Bci=C5=84ski?= Date: Tue, 21 Nov 2023 15:59:33 +0100 Subject: [PATCH 0154/3723] tests: logging: log_backend_uart: Disable backends other than UART MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Test expects that there are no other backends enabled and some may be enabled by default. Signed-off-by: Krzysztof Chruściński --- tests/subsys/logging/log_backend_uart/prj.conf | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/tests/subsys/logging/log_backend_uart/prj.conf b/tests/subsys/logging/log_backend_uart/prj.conf index ef6894f355e..c8615a65adb 100644 --- a/tests/subsys/logging/log_backend_uart/prj.conf +++ b/tests/subsys/logging/log_backend_uart/prj.conf @@ -9,3 +9,8 @@ CONFIG_LOG=y CONFIG_LOG_BACKEND_UART=y CONFIG_LOG_MODE_IMMEDIATE=y CONFIG_LOG_PRINTK=n +# +# Disable all potential other default backends +CONFIG_LOG_BACKEND_NATIVE_POSIX=n +CONFIG_LOG_BACKEND_RTT=n +CONFIG_LOG_BACKEND_XTENSA_SIM=n From 84955951efba678bc024bc07caa362f92d13c6e2 Mon Sep 17 00:00:00 2001 From: Andrej Butok Date: Tue, 21 Nov 2023 15:02:20 +0100 Subject: [PATCH 0155/3723] boards: lpcxpresso55Sxx: Make Jlink a default runner. Make Jlink a default runner for lpcxpresso55Sxx. The LinkServer runner command line tool does not support .hex flashing. This feature is planned for LinkServer v1.6 (July 2024). Signed-off-by: Andrej Butok --- boards/arm/lpcxpresso55s06/board.cmake | 2 +- boards/arm/lpcxpresso55s16/board.cmake | 2 +- boards/arm/lpcxpresso55s28/board.cmake | 4 +++- boards/arm/lpcxpresso55s36/board.cmake | 2 +- 4 files changed, 6 insertions(+), 4 deletions(-) diff --git a/boards/arm/lpcxpresso55s06/board.cmake b/boards/arm/lpcxpresso55s06/board.cmake index 305ed963f21..a6df50bba73 100644 --- a/boards/arm/lpcxpresso55s06/board.cmake +++ b/boards/arm/lpcxpresso55s06/board.cmake @@ -8,5 +8,5 @@ board_runner_args(linkserver "--device=LPC55S06:LPCXpresso55S06") board_runner_args(jlink "--device=LPC55S06" "--reset-after-load") -include(${ZEPHYR_BASE}/boards/common/linkserver.board.cmake) include(${ZEPHYR_BASE}/boards/common/jlink.board.cmake) +include(${ZEPHYR_BASE}/boards/common/linkserver.board.cmake) diff --git a/boards/arm/lpcxpresso55s16/board.cmake b/boards/arm/lpcxpresso55s16/board.cmake index 45ca5dcfe1c..f1a6370b01f 100644 --- a/boards/arm/lpcxpresso55s16/board.cmake +++ b/boards/arm/lpcxpresso55s16/board.cmake @@ -9,6 +9,6 @@ board_runner_args(linkserver "--device=LPC55S16:LPCXpresso55S16") board_runner_args(jlink "--device=LPC55S16" "--reset-after-load") board_runner_args(pyocd "--target=lpc55s16") -include(${ZEPHYR_BASE}/boards/common/linkserver.board.cmake) include(${ZEPHYR_BASE}/boards/common/jlink.board.cmake) +include(${ZEPHYR_BASE}/boards/common/linkserver.board.cmake) include(${ZEPHYR_BASE}/boards/common/pyocd.board.cmake) diff --git a/boards/arm/lpcxpresso55s28/board.cmake b/boards/arm/lpcxpresso55s28/board.cmake index 9cd2296a404..933e3815a8c 100644 --- a/boards/arm/lpcxpresso55s28/board.cmake +++ b/boards/arm/lpcxpresso55s28/board.cmake @@ -4,8 +4,10 @@ # SPDX-License-Identifier: Apache-2.0 # +board_runner_args(linkserver "--device=LPC55S28:LPCXpresso55S28") board_runner_args(pyocd "--target=lpc55s28") board_runner_args(jlink "--device=LPC55S28" "--reset-after-load") -include(${ZEPHYR_BASE}/boards/common/pyocd.board.cmake) include(${ZEPHYR_BASE}/boards/common/jlink.board.cmake) +include(${ZEPHYR_BASE}/boards/common/linkserver.board.cmake) +include(${ZEPHYR_BASE}/boards/common/pyocd.board.cmake) diff --git a/boards/arm/lpcxpresso55s36/board.cmake b/boards/arm/lpcxpresso55s36/board.cmake index b1e16906bd5..d1a92d0164d 100644 --- a/boards/arm/lpcxpresso55s36/board.cmake +++ b/boards/arm/lpcxpresso55s36/board.cmake @@ -8,6 +8,6 @@ board_runner_args(linkserver "--device=LPC55S36:LPCXpresso55S36") board_runner_args(jlink "--device=LPC55S36" "--reset-after-load") board_runner_args(pyocd "--target=lpc55s36") -include(${ZEPHYR_BASE}/boards/common/linkserver.board.cmake) include(${ZEPHYR_BASE}/boards/common/jlink.board.cmake) +include(${ZEPHYR_BASE}/boards/common/linkserver.board.cmake) include(${ZEPHYR_BASE}/boards/common/pyocd.board.cmake) From a1698b691d9bfd25dfd70fc1ed42e819cdec61a3 Mon Sep 17 00:00:00 2001 From: Grzegorz Chwierut Date: Tue, 21 Nov 2023 11:01:17 +0100 Subject: [PATCH 0156/3723] twister: pytest: Add --pytest-args to Twister command line Extend Twister command line with --pytest-args. This parameter is passed to pytest subprocess. It allows to select a specific testcase from a test suite. Signed-off-by: Grzegorz Chwierut --- doc/develop/test/pytest.rst | 10 +++ .../pylib/twister/twisterlib/environment.py | 5 ++ scripts/pylib/twister/twisterlib/harness.py | 19 ++++-- .../pytest_integration/test_harness_pytest.py | 66 +++++++++++++++++++ 4 files changed, 96 insertions(+), 4 deletions(-) diff --git a/doc/develop/test/pytest.rst b/doc/develop/test/pytest.rst index e644882191e..f3db6fcee89 100644 --- a/doc/develop/test/pytest.rst +++ b/doc/develop/test/pytest.rst @@ -56,6 +56,16 @@ Pytest scans the given locations looking for tests, following its default `discovery rules `_ One can also pass some extra arguments to the pytest from yaml file using ``pytest_args`` keyword under ``harness_config``, e.g.: ``pytest_args: [‘-k=test_method’, ‘--log-level=DEBUG’]``. +There is also an option to pass ``--pytest-args`` through Twister command line parameters. +This can be particularly useful when one wants to select a specific testcase from a test suite. +For instance, one can use a command: + +.. code-block:: console + + $ ./scripts/twister --platform native_sim -T samples/subsys/testsuite/pytest/shell \ + -s samples/subsys/testsuite/pytest/shell/sample.pytest.shell \ + --pytest-args='-k test_shell_print_version' + Helpers & fixtures ================== diff --git a/scripts/pylib/twister/twisterlib/environment.py b/scripts/pylib/twister/twisterlib/environment.py index 86965f1f9cf..b7e11406cd4 100644 --- a/scripts/pylib/twister/twisterlib/environment.py +++ b/scripts/pylib/twister/twisterlib/environment.py @@ -216,6 +216,11 @@ def add_parse_arguments(parser = None): and 'fifo_loop' is a name of a function found in main.c without test prefix. """) + parser.add_argument("--pytest-args", + help="""Pass additional arguments to the pytest subprocess. This parameter + will override the pytest_args from the harness_config in YAML file. + """) + valgrind_asan_group.add_argument( "--enable-valgrind", action="store_true", help="""Run binary through valgrind and check for several memory access diff --git a/scripts/pylib/twister/twisterlib/harness.py b/scripts/pylib/twister/twisterlib/harness.py index 052def7162a..dece1673c7a 100644 --- a/scripts/pylib/twister/twisterlib/harness.py +++ b/scripts/pylib/twister/twisterlib/harness.py @@ -309,8 +309,9 @@ def pytest_run(self, timeout): def generate_command(self): config = self.instance.testsuite.harness_config + handler: Handler = self.instance.handler pytest_root = config.get('pytest_root', ['pytest']) if config else ['pytest'] - pytest_args = config.get('pytest_args', []) if config else [] + pytest_args_yaml = config.get('pytest_args', []) if config else [] pytest_dut_scope = config.get('pytest_dut_scope', None) if config else None command = [ 'pytest', @@ -324,12 +325,19 @@ def generate_command(self): ] command.extend([os.path.normpath(os.path.join( self.source_dir, os.path.expanduser(os.path.expandvars(src)))) for src in pytest_root]) - command.extend(pytest_args) + + if handler.options.pytest_args: + command.append(handler.options.pytest_args) + if pytest_args_yaml: + logger.warning(f'The pytest_args ({handler.options.pytest_args}) specified ' + 'in the command line will override the pytest_args defined ' + f'in the YAML file {pytest_args_yaml}') + else: + command.extend(pytest_args_yaml) + if pytest_dut_scope: command.append(f'--dut-scope={pytest_dut_scope}') - handler: Handler = self.instance.handler - if handler.options.verbose > 1: command.extend([ '--log-cli-level=DEBUG', @@ -489,6 +497,9 @@ def _parse_report_file(self, report): tc.status = 'error' tc.reason = elem.get('message') tc.output = elem.text + else: + self.state = 'skipped' + self.instance.reason = 'No tests collected' class Gtest(Harness): diff --git a/scripts/tests/twister/pytest_integration/test_harness_pytest.py b/scripts/tests/twister/pytest_integration/test_harness_pytest.py index 150980059b3..fc60b99e0d1 100644 --- a/scripts/tests/twister/pytest_integration/test_harness_pytest.py +++ b/scripts/tests/twister/pytest_integration/test_harness_pytest.py @@ -25,6 +25,7 @@ def testinstance() -> TestInstance: testinstance.handler = mock.Mock() testinstance.handler.options = mock.Mock() testinstance.handler.options.verbose = 1 + testinstance.handler.options.pytest_args = None testinstance.handler.type_str = 'native' return testinstance @@ -67,6 +68,18 @@ def test_pytest_command_extra_args(testinstance: TestInstance): assert c in command +def test_pytest_command_extra_args_in_options(testinstance: TestInstance): + pytest_harness = Pytest() + pytest_args_from_yaml = '-k test_from_yaml' + pytest_args_from_cmd = '-k test_from_cmd' + testinstance.testsuite.harness_config['pytest_args'] = [pytest_args_from_yaml] + testinstance.handler.options.pytest_args = pytest_args_from_cmd + pytest_harness.configure(testinstance) + command = pytest_harness.generate_command() + assert pytest_args_from_cmd in command + assert pytest_args_from_yaml not in command + + @pytest.mark.parametrize( ('pytest_root', 'expected'), [ @@ -222,3 +235,56 @@ def test_skip_2(): assert len(testinstance.testcases) == 2 for tc in testinstance.testcases: assert tc.status == "skipped" + + +def test_if_report_with_filter(pytester, testinstance: TestInstance): + test_file_content = textwrap.dedent(""" + import pytest + def test_A(): + pass + def test_B(): + pass + """) + test_file = pytester.path / 'test_filter.py' + test_file.write_text(test_file_content) + report_file = pytester.path / 'report.xml' + result = pytester.runpytest( + str(test_file), + '-k', 'test_B', + f'--junit-xml={str(report_file)}' + ) + result.assert_outcomes(passed=1) + assert report_file.is_file() + + pytest_harness = Pytest() + pytest_harness.configure(testinstance) + pytest_harness.report_file = report_file + pytest_harness._update_test_status() + assert pytest_harness.state == "passed" + assert testinstance.status == "passed" + assert len(testinstance.testcases) == 1 + + +def test_if_report_with_no_collected(pytester, testinstance: TestInstance): + test_file_content = textwrap.dedent(""" + import pytest + def test_A(): + pass + """) + test_file = pytester.path / 'test_filter.py' + test_file.write_text(test_file_content) + report_file = pytester.path / 'report.xml' + result = pytester.runpytest( + str(test_file), + '-k', 'test_B', + f'--junit-xml={str(report_file)}' + ) + result.assert_outcomes(passed=0) + assert report_file.is_file() + + pytest_harness = Pytest() + pytest_harness.configure(testinstance) + pytest_harness.report_file = report_file + pytest_harness._update_test_status() + assert pytest_harness.state == "skipped" + assert testinstance.status == "skipped" From d4c1e8ef6715da8b09e107b60b45f3d3101c7d92 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Benjamin=20Cab=C3=A9?= Date: Fri, 17 Nov 2023 16:50:02 +0100 Subject: [PATCH 0157/3723] lorawan: include: add missing Doxygen comments MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Added missing comments to various structs and enums in the lorawan.h header. Signed-off-by: Benjamin Cabé --- include/zephyr/lorawan/lorawan.h | 72 ++++++++++++++++---------------- 1 file changed, 37 insertions(+), 35 deletions(-) diff --git a/include/zephyr/lorawan/lorawan.h b/include/zephyr/lorawan/lorawan.h index 2e07e99d694..b0f0117d91d 100644 --- a/include/zephyr/lorawan/lorawan.h +++ b/include/zephyr/lorawan/lorawan.h @@ -26,63 +26,63 @@ extern "C" { * @brief LoRaWAN class types. */ enum lorawan_class { - LORAWAN_CLASS_A = 0x00, - LORAWAN_CLASS_B = 0x01, - LORAWAN_CLASS_C = 0x02, + LORAWAN_CLASS_A = 0x00, /**< Class A device */ + LORAWAN_CLASS_B = 0x01, /**< Class B device */ + LORAWAN_CLASS_C = 0x02, /**< Class C device */ }; /** * @brief LoRaWAN activation types. */ enum lorawan_act_type { - LORAWAN_ACT_OTAA = 0, - LORAWAN_ACT_ABP, + LORAWAN_ACT_OTAA = 0, /**< Over-the-Air Activation (OTAA) */ + LORAWAN_ACT_ABP, /**< Activation by Personalization (ABP) */ }; /** * @brief LoRaWAN datarate types. */ enum lorawan_datarate { - LORAWAN_DR_0 = 0, - LORAWAN_DR_1, - LORAWAN_DR_2, - LORAWAN_DR_3, - LORAWAN_DR_4, - LORAWAN_DR_5, - LORAWAN_DR_6, - LORAWAN_DR_7, - LORAWAN_DR_8, - LORAWAN_DR_9, - LORAWAN_DR_10, - LORAWAN_DR_11, - LORAWAN_DR_12, - LORAWAN_DR_13, - LORAWAN_DR_14, - LORAWAN_DR_15, + LORAWAN_DR_0 = 0, /**< DR0 data rate */ + LORAWAN_DR_1, /**< DR1 data rate */ + LORAWAN_DR_2, /**< DR2 data rate */ + LORAWAN_DR_3, /**< DR3 data rate */ + LORAWAN_DR_4, /**< DR4 data rate */ + LORAWAN_DR_5, /**< DR5 data rate */ + LORAWAN_DR_6, /**< DR6 data rate */ + LORAWAN_DR_7, /**< DR7 data rate */ + LORAWAN_DR_8, /**< DR8 data rate */ + LORAWAN_DR_9, /**< DR9 data rate */ + LORAWAN_DR_10, /**< DR10 data rate */ + LORAWAN_DR_11, /**< DR11 data rate */ + LORAWAN_DR_12, /**< DR12 data rate */ + LORAWAN_DR_13, /**< DR13 data rate */ + LORAWAN_DR_14, /**< DR14 data rate */ + LORAWAN_DR_15, /**< DR15 data rate */ }; /** * @brief LoRaWAN region types. */ enum lorawan_region { - LORAWAN_REGION_AS923, - LORAWAN_REGION_AU915, - LORAWAN_REGION_CN470, - LORAWAN_REGION_CN779, - LORAWAN_REGION_EU433, - LORAWAN_REGION_EU868, - LORAWAN_REGION_KR920, - LORAWAN_REGION_IN865, - LORAWAN_REGION_US915, - LORAWAN_REGION_RU864, + LORAWAN_REGION_AS923, /**< Asia 923 MHz frequency band */ + LORAWAN_REGION_AU915, /**< Australia 915 MHz frequency band */ + LORAWAN_REGION_CN470, /**< China 470 MHz frequency band */ + LORAWAN_REGION_CN779, /**< China 779 MHz frequency band */ + LORAWAN_REGION_EU433, /**< Europe 433 MHz frequency band */ + LORAWAN_REGION_EU868, /**< Europe 868 MHz frequency band */ + LORAWAN_REGION_KR920, /**< South Korea 920 MHz frequency band */ + LORAWAN_REGION_IN865, /**< India 865 MHz frequency band */ + LORAWAN_REGION_US915, /**< United States 915 MHz frequency band */ + LORAWAN_REGION_RU864, /**< Russia 864 MHz frequency band */ }; /** * @brief LoRaWAN message types. */ enum lorawan_message_type { - LORAWAN_MSG_UNCONFIRMED = 0, - LORAWAN_MSG_CONFIRMED, + LORAWAN_MSG_UNCONFIRMED = 0, /**< Unconfirmed message */ + LORAWAN_MSG_CONFIRMED, /**< Confirmed message */ }; /** @@ -128,9 +128,10 @@ struct lorawan_join_abp { * @brief LoRaWAN join parameters */ struct lorawan_join_config { + /** Join parameters */ union { - struct lorawan_join_otaa otaa; - struct lorawan_join_abp abp; + struct lorawan_join_otaa otaa; /**< OTAA join parameters */ + struct lorawan_join_abp abp; /**< ABP join parameters */ }; /** Device EUI. Optional if a secure element is present. */ @@ -140,6 +141,7 @@ struct lorawan_join_config { enum lorawan_act_type mode; }; +/** Flag to indicate receiving on any port */ #define LW_RECV_PORT_ANY UINT16_MAX /** From 64cce4866f3da605b2f1c8af314d6df84e0ab42c Mon Sep 17 00:00:00 2001 From: Mulin Chao Date: Wed, 8 Nov 2023 18:16:24 -0800 Subject: [PATCH 0158/3723] MAINTAINERS: add Nuvoton collaborators for Nuvoton NPCX Platforms Add Nuvoton guys, TomChang19 and alvsun, in collaborators of Nuvoton NPCX Platforms and remove MulinChao and ChiHuaL since they are already the maintainers. Signed-off-by: Mulin Chao --- MAINTAINERS.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/MAINTAINERS.yml b/MAINTAINERS.yml index a4ad483ce2c..8a514d236c2 100644 --- a/MAINTAINERS.yml +++ b/MAINTAINERS.yml @@ -2503,8 +2503,8 @@ Nuvoton NPCX Platforms: - MulinChao - ChiHuaL collaborators: - - MulinChao - - ChiHuaL + - TomChang19 + - alvsun - sjg20 - keith-zephyr - jackrosenthal From c3a54ae1c34e939db83431bea354c0f4d0add0b3 Mon Sep 17 00:00:00 2001 From: Andy Sinclair Date: Wed, 22 Nov 2023 16:34:02 +0000 Subject: [PATCH 0159/3723] drivers: regulator: Fixed reference counting during enable Reference counting was broken when adding the enable delay. Now reverted to previous pattern. Signed-off-by: Andy Sinclair --- drivers/regulator/regulator_common.c | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/drivers/regulator/regulator_common.c b/drivers/regulator/regulator_common.c index 7f33040d2d9..14866a3738f 100644 --- a/drivers/regulator/regulator_common.c +++ b/drivers/regulator/regulator_common.c @@ -107,10 +107,13 @@ int regulator_enable(const struct device *dev) (void)k_mutex_lock(&data->lock, K_FOREVER); #endif - if (data->refcnt == 0) { + data->refcnt++; + + if (data->refcnt == 1) { ret = api->enable(dev); - if (ret == 0) { - data->refcnt++; + if (ret < 0) { + data->refcnt--; + } else { regulator_delay(config->off_on_delay_us); } } From eeb6bf7dd998c8c191f58df692097bfcfaf1e3bf Mon Sep 17 00:00:00 2001 From: Juliane Schulze Date: Fri, 10 Nov 2023 17:37:24 +0100 Subject: [PATCH 0160/3723] input: make short-inputs optional By making short inputs optional, the user can bypass short-events all together if necessary (e.g. custom button-press listener). Signed-off-by: Juliane Schulze --- .../input/zephyr,input-longpress.yaml | 9 +++-- subsys/input/input_longpress.c | 11 ++++-- .../input/longpress/boards/native_sim.overlay | 8 +++++ tests/subsys/input/longpress/src/main.c | 34 +++++++++++++++++++ 4 files changed, 56 insertions(+), 6 deletions(-) diff --git a/dts/bindings/input/zephyr,input-longpress.yaml b/dts/bindings/input/zephyr,input-longpress.yaml index abf87a15803..a6ef96f5d40 100644 --- a/dts/bindings/input/zephyr,input-longpress.yaml +++ b/dts/bindings/input/zephyr,input-longpress.yaml @@ -8,7 +8,9 @@ description: | corresponding to short and long press. Can be optionally be associated to a specific device to listen for events - only from that device. Example configuration: + only from that device. + + Example configuration: #include @@ -23,12 +25,14 @@ description: | Example output: + # short press input event: dev=buttons SYN type= 1 code= 11 value=1 # INPUT_KEY_0 press # release before one second input event: dev=buttons SYN type= 1 code= 11 value=0 # INPUT_KEY_0 release input event: dev=longpress SYN type= 1 code= 30 value=1 # INPUT_KEY_A press input event: dev=longpress SYN type= 1 code= 30 value=0 # INPUT_KEY_A release + # long press input event: dev=buttons SYN type= 1 code= 11 value=1 # INPUT_KEY_0 press # hold for more than one second input event: dev=longpress SYN type= 1 code= 45 value=1 # INPUT_KEY_X press @@ -52,9 +56,8 @@ properties: short-codes: type: array - required: true description: | - Array of key codes to be generated for short press (INPUT_KEY_* or + Optional array of key codes to be generated for short press (INPUT_KEY_* or INPUT_BTN_*). long-codes: diff --git a/subsys/input/input_longpress.c b/subsys/input/input_longpress.c index c9acbbf14fe..5e0b6f0ac9f 100644 --- a/subsys/input/input_longpress.c +++ b/subsys/input/input_longpress.c @@ -80,7 +80,7 @@ static void longpress_cb(const struct device *dev, struct input_event *evt) k_work_cancel_delayable(&entry->work); if (entry->long_fired) { input_report_key(dev, cfg->long_codes[i], 0, true, K_FOREVER); - } else { + } else if (cfg->short_codes != NULL) { input_report_key(dev, cfg->short_codes[i], 1, true, K_FOREVER); input_report_key(dev, cfg->short_codes[i], 0, true, K_FOREVER); } @@ -109,8 +109,9 @@ static int longpress_init(const struct device *dev) } #define INPUT_LONGPRESS_DEFINE(inst) \ - BUILD_ASSERT(DT_INST_PROP_LEN(inst, input_codes) == \ - DT_INST_PROP_LEN(inst, short_codes)); \ + BUILD_ASSERT((DT_INST_PROP_LEN(inst, input_codes) == \ + DT_INST_PROP_LEN_OR(inst, short_codes, 0)) || \ + !DT_INST_NODE_HAS_PROP(inst, short_codes)); \ BUILD_ASSERT(DT_INST_PROP_LEN(inst, input_codes) == \ DT_INST_PROP_LEN(inst, long_codes)); \ static void longpress_cb_##inst(struct input_event *evt) \ @@ -120,12 +121,16 @@ static int longpress_init(const struct device *dev) INPUT_CALLBACK_DEFINE(DEVICE_DT_GET_OR_NULL(DT_INST_PHANDLE(inst, input)), \ longpress_cb_##inst); \ static const uint16_t longpress_input_codes_##inst[] = DT_INST_PROP(inst, input_codes); \ + IF_ENABLED(DT_INST_NODE_HAS_PROP(inst, short_codes), ( \ static const uint16_t longpress_short_codes_##inst[] = DT_INST_PROP(inst, short_codes); \ + )); \ static const uint16_t longpress_long_codes_##inst[] = DT_INST_PROP(inst, long_codes); \ static const struct longpress_config longpress_config_##inst = { \ .input_dev = DEVICE_DT_GET_OR_NULL(DT_INST_PHANDLE(inst, input)), \ .input_codes = longpress_input_codes_##inst, \ + IF_ENABLED(DT_INST_NODE_HAS_PROP(inst, short_codes), ( \ .short_codes = longpress_short_codes_##inst, \ + )) \ .long_codes = longpress_long_codes_##inst, \ .num_codes = DT_INST_PROP_LEN(inst, input_codes), \ .long_delays_ms = DT_INST_PROP(inst, long_delay_ms), \ diff --git a/tests/subsys/input/longpress/boards/native_sim.overlay b/tests/subsys/input/longpress/boards/native_sim.overlay index 14dcd8d0d4e..a742ed99c5c 100644 --- a/tests/subsys/input/longpress/boards/native_sim.overlay +++ b/tests/subsys/input/longpress/boards/native_sim.overlay @@ -19,4 +19,12 @@ long-codes = , ; long-delay-ms = <100>; }; + + longpress_no_short: longpress-no-short { + input = <&fake_input_device>; + compatible = "zephyr,input-longpress"; + input-codes = , ; + long-codes = , ; + long-delay-ms = <100>; + }; }; diff --git a/tests/subsys/input/longpress/src/main.c b/tests/subsys/input/longpress/src/main.c index 22d5e720038..4f81901a742 100644 --- a/tests/subsys/input/longpress/src/main.c +++ b/tests/subsys/input/longpress/src/main.c @@ -13,6 +13,8 @@ static const struct device *const fake_dev = DEVICE_DT_GET( DT_NODELABEL(fake_input_device)); static const struct device *const longpress_dev = DEVICE_DT_GET( DT_NODELABEL(longpress)); +static const struct device *const longpress_no_short_dev = DEVICE_DT_GET( + DT_NODELABEL(longpress_no_short)); DEVICE_DT_DEFINE(DT_INST(0, vnd_input_device), NULL, NULL, NULL, NULL, PRE_KERNEL_1, CONFIG_KERNEL_INIT_PRIORITY_DEVICE, NULL); @@ -30,6 +32,18 @@ static void test_cb(struct input_event *evt) } INPUT_CALLBACK_DEFINE(longpress_dev, test_cb); +static int event_count_no_short; +static struct input_event last_events_no_short[2]; +static void test_cb_no_short(struct input_event *evt) +{ + TC_PRINT("%s: %d %x %d\n", __func__, event_count_no_short, evt->code, evt->value); + + event_count_no_short++; + memcpy(&last_events_no_short[1], &last_events_no_short[0], sizeof(struct input_event)); + memcpy(&last_events_no_short[0], evt, sizeof(struct input_event)); +} +INPUT_CALLBACK_DEFINE(longpress_no_short_dev, test_cb_no_short); + ZTEST(longpress, test_longpress_test) { zassert_equal(event_count, 0); @@ -38,9 +52,11 @@ ZTEST(longpress, test_longpress_test) input_report_key(fake_dev, INPUT_KEY_3, 1, true, K_FOREVER); input_report_key(fake_dev, INPUT_KEY_3, 0, true, K_FOREVER); zassert_equal(event_count, 0); + zassert_equal(event_count_no_short, 0); input_report_abs(fake_dev, INPUT_KEY_0, 1, true, K_FOREVER); input_report_abs(fake_dev, INPUT_KEY_0, 0, true, K_FOREVER); zassert_equal(event_count, 0); + zassert_equal(event_count_no_short, 0); /* short press */ input_report_key(fake_dev, INPUT_KEY_0, 1, true, K_FOREVER); @@ -53,6 +69,7 @@ ZTEST(longpress, test_longpress_test) zassert_equal(last_events[0].type, INPUT_EV_KEY); zassert_equal(last_events[0].code, INPUT_KEY_A); zassert_equal(last_events[0].value, 0); + zassert_equal(event_count_no_short, 0); /* short press - other key */ input_report_key(fake_dev, INPUT_KEY_1, 1, true, K_FOREVER); @@ -65,6 +82,7 @@ ZTEST(longpress, test_longpress_test) zassert_equal(last_events[0].type, INPUT_EV_KEY); zassert_equal(last_events[0].code, INPUT_KEY_B); zassert_equal(last_events[0].value, 0); + zassert_equal(event_count_no_short, 0); /* long press */ input_report_key(fake_dev, INPUT_KEY_0, 1, true, K_FOREVER); @@ -78,6 +96,14 @@ ZTEST(longpress, test_longpress_test) zassert_equal(last_events[0].code, INPUT_KEY_X); zassert_equal(last_events[0].value, 0); + zassert_equal(event_count_no_short, 2); + zassert_equal(last_events_no_short[1].type, INPUT_EV_KEY); + zassert_equal(last_events_no_short[1].code, INPUT_KEY_X); + zassert_equal(last_events_no_short[1].value, 1); + zassert_equal(last_events_no_short[0].type, INPUT_EV_KEY); + zassert_equal(last_events_no_short[0].code, INPUT_KEY_X); + zassert_equal(last_events_no_short[0].value, 0); + /* long press - other key */ input_report_key(fake_dev, INPUT_KEY_1, 1, true, K_FOREVER); k_sleep(K_MSEC(150)); @@ -89,6 +115,14 @@ ZTEST(longpress, test_longpress_test) zassert_equal(last_events[0].type, INPUT_EV_KEY); zassert_equal(last_events[0].code, INPUT_KEY_Y); zassert_equal(last_events[0].value, 0); + + zassert_equal(event_count_no_short, 4); + zassert_equal(last_events_no_short[1].type, INPUT_EV_KEY); + zassert_equal(last_events_no_short[1].code, INPUT_KEY_Y); + zassert_equal(last_events_no_short[1].value, 1); + zassert_equal(last_events_no_short[0].type, INPUT_EV_KEY); + zassert_equal(last_events_no_short[0].code, INPUT_KEY_Y); + zassert_equal(last_events_no_short[0].value, 0); } ZTEST_SUITE(longpress, NULL, NULL, NULL, NULL, NULL); From 67ec329a702616e39ec9ea44d8d3f350e8cf3e2a Mon Sep 17 00:00:00 2001 From: Henrik Brix Andersen Date: Thu, 23 Nov 2023 14:32:25 +0100 Subject: [PATCH 0161/3723] tests: kernel: mem_protect: mem_map: fix wrong include This test needs to include zephyr/kernel/mm/demand_paging.h, not zephyr/kernel/mm.h, due to its use of k_mem_pin(). Signed-off-by: Henrik Brix Andersen --- tests/kernel/mem_protect/mem_map/src/main.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/tests/kernel/mem_protect/mem_map/src/main.c b/tests/kernel/mem_protect/mem_map/src/main.c index 45ca0aa1cf3..93ba0406693 100644 --- a/tests/kernel/mem_protect/mem_map/src/main.c +++ b/tests/kernel/mem_protect/mem_map/src/main.c @@ -5,11 +5,14 @@ */ #include -#include #include #include #include +#ifdef CONFIG_DEMAND_PAGING +#include +#endif /* CONFIG_DEMAND_PAGING */ + /* 32-bit IA32 page tables have no mechanism to restrict execution */ #if defined(CONFIG_X86) && !defined(CONFIG_X86_64) && !defined(CONFIG_X86_PAE) #define SKIP_EXECUTE_TESTS From 69d62add980bcafa6d90b73920372390cc10ea7c Mon Sep 17 00:00:00 2001 From: Anisetti Avinash Krishna Date: Thu, 23 Nov 2023 19:19:18 +0530 Subject: [PATCH 0162/3723] drivers: serial: ns16550: Fixed few bugs causing CI failure Removed if (IS_ENABLED()) and used #if as they are causing CI failures and removed LPSS related functions which are not under LPSS config. Signed-off-by: Anisetti Avinash Krishna --- drivers/serial/uart_ns16550.c | 28 ++++++++++------------------ 1 file changed, 10 insertions(+), 18 deletions(-) diff --git a/drivers/serial/uart_ns16550.c b/drivers/serial/uart_ns16550.c index 22243a34d16..e0c9ccebd03 100644 --- a/drivers/serial/uart_ns16550.c +++ b/drivers/serial/uart_ns16550.c @@ -261,7 +261,6 @@ BUILD_ASSERT(IS_ENABLED(CONFIG_PCIE), "NS16550(s) in DT need CONFIG_PCIE"); #define CLR_SRC_TRAN(dev) (get_port(dev) + REG_LPSS_CLR_SRC_TRAN) #define MST(dev) (get_port(dev) + REG_LPSS_MST) -#define MASK_LPSS_INT(chan) (BIT(8) << chan) /* mask LPSS DMA Interrupt */ #define UNMASK_LPSS_INT(chan) (BIT(chan) | (BIT(8) << chan)) /* unmask LPSS DMA Interrupt */ #endif @@ -1287,8 +1286,6 @@ static void uart_ns16550_isr(const struct device *dev) if (IIR_status & IIR_RBRF) { async_timer_start(&dev_data->async.rx_dma_params.timeout_work, dev_data->async.rx_dma_params.timeout_us); - ns16550_outword(config, CLR_SRC_TRAN(dev), - BIT(dev_data->async.rx_dma_params.dma_channel)); return; } } @@ -1486,7 +1483,6 @@ static void uart_ns16550_async_rx_flush(const struct device *dev) static int uart_ns16550_rx_disable(const struct device *dev) { - const struct uart_ns16550_device_config * const config = dev->config; struct uart_ns16550_dev_data *data = (struct uart_ns16550_dev_data *)dev->data; struct uart_ns16550_rx_dma_params *dma_params = &data->async.rx_dma_params; k_spinlock_key_t key = k_spin_lock(&data->lock); @@ -1519,10 +1515,6 @@ static int uart_ns16550_rx_disable(const struct device *dev) async_user_callback(dev, &event); - if (IS_ENABLED(CONFIG_UART_NS16550_INTEL_LPSS_DMA)) { - ns16550_outword(config, MST(dev), UNMASK_LPSS_INT(dma_params->dma_channel)); - } - out: k_spin_unlock(&data->lock, key); return ret; @@ -1538,7 +1530,7 @@ static void prepare_rx_dma_block_config(const struct device *dev) struct dma_block_config *head_block_config = &rx_dma_params->active_dma_block; - head_block_config->dest_address = (uint64_t)rx_dma_params->buf; + head_block_config->dest_address = (uintptr_t)rx_dma_params->buf; head_block_config->source_address = data->phys_addr; head_block_config->block_size = rx_dma_params->buf_len; } @@ -1568,7 +1560,7 @@ static void dma_callback(const struct device *dev, void *user_data, uint32_t cha if (rx_params->buf != NULL && rx_params->buf_len > 0) { dma_reload(dev, rx_params->dma_channel, data->phys_addr, - (uint64_t)rx_params->buf, rx_params->buf_len); + (uintptr_t)rx_params->buf, rx_params->buf_len); dma_start(dev, rx_params->dma_channel); async_evt_rx_buf_request(uart_dev); } else { @@ -1603,7 +1595,7 @@ static int uart_ns16550_tx(const struct device *dev, const uint8_t *buf, size_t tx_params->buf = buf; tx_params->buf_len = len; - tx_params->active_dma_block.source_address = (uint64_t)buf; + tx_params->active_dma_block.source_address = (uintptr_t)buf; tx_params->active_dma_block.dest_address = data->phys_addr; tx_params->active_dma_block.block_size = len; tx_params->active_dma_block.next_block = NULL; @@ -1681,13 +1673,13 @@ static int uart_ns16550_rx_enable(const struct device *dev, uint8_t *buf, const rx_dma_params->buf = buf; rx_dma_params->buf_len = len; - if (IS_ENABLED(CONFIG_UART_NS16550_INTEL_LPSS_DMA)) { - ns16550_outword(config, MST(dev), UNMASK_LPSS_INT(DMA_INTEL_LPSS_RX_CHAN)); - } else { - ns16550_outbyte(config, IER(dev), - (ns16550_inbyte(config, IER(dev)) | IER_RXRDY)); - ns16550_outbyte(config, FCR(dev), FCR_FIFO); - } +#if defined(CONFIG_UART_NS16550_INTEL_LPSS_DMA) + ns16550_outword(config, MST(dev), UNMASK_LPSS_INT(rx_dma_params->dma_channel)); +#else + ns16550_outbyte(config, IER(dev), + (ns16550_inbyte(config, IER(dev)) | IER_RXRDY)); + ns16550_outbyte(config, FCR(dev), FCR_FIFO); +#endif prepare_rx_dma_block_config(dev); dma_config(rx_dma_params->dma_dev, rx_dma_params->dma_channel, From e76ace4647362ec3a770f6c0aa5f3a8394f09dc2 Mon Sep 17 00:00:00 2001 From: Anisetti Avinash Krishna Date: Fri, 24 Nov 2023 00:49:40 +0530 Subject: [PATCH 0163/3723] drivers: serial: ns16550: Condition added for dma_callback Enable a condition as define dma_callback function only if any one instance of ns16550 has dmas parameter in dts. This resolves conflict of dma_callback function defined but not used warning in case of UART_ASYNC_API enabled but dmas parameter is not provided to any ns16550 UARTs dts instances. Signed-off-by: Anisetti Avinash Krishna --- drivers/serial/uart_ns16550.c | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/drivers/serial/uart_ns16550.c b/drivers/serial/uart_ns16550.c index e0c9ccebd03..665b44062ac 100644 --- a/drivers/serial/uart_ns16550.c +++ b/drivers/serial/uart_ns16550.c @@ -45,6 +45,7 @@ LOG_MODULE_REGISTER(uart_ns16550, CONFIG_UART_LOG_LEVEL); #define UART_NS16550_PCP_ENABLED DT_ANY_INST_HAS_PROP_STATUS_OKAY(pcp) #define UART_NS16550_DLF_ENABLED DT_ANY_INST_HAS_PROP_STATUS_OKAY(dlf) +#define UART_NS16550_DMAS_ENABLED DT_ANY_INST_HAS_PROP_STATUS_OKAY(dmas) #if DT_ANY_INST_ON_BUS_STATUS_OKAY(pcie) BUILD_ASSERT(IS_ENABLED(CONFIG_PCIE), "NS16550(s) in DT need CONFIG_PCIE"); @@ -1402,6 +1403,7 @@ static void async_user_callback(const struct device *dev, struct uart_event *evt } } +#if UART_NS16550_DMAS_ENABLED static void async_evt_tx_done(struct device *dev) { struct uart_ns16550_dev_data *data = dev->data; @@ -1420,6 +1422,7 @@ static void async_evt_tx_done(struct device *dev) async_user_callback(dev, &event); } +#endif static void async_evt_rx_rdy(const struct device *dev) { @@ -1535,6 +1538,7 @@ static void prepare_rx_dma_block_config(const struct device *dev) head_block_config->block_size = rx_dma_params->buf_len; } +#if UART_NS16550_DMAS_ENABLED static void dma_callback(const struct device *dev, void *user_data, uint32_t channel, int status) { @@ -1568,6 +1572,7 @@ static void dma_callback(const struct device *dev, void *user_data, uint32_t cha } } } +#endif static int uart_ns16550_callback_set(const struct device *dev, uart_callback_t callback, void *user_data) From 5afaa38e671af7b10513eab6aa2c4a665d7a824f Mon Sep 17 00:00:00 2001 From: Jamie McCrae Date: Sat, 28 Oct 2023 18:55:41 +0100 Subject: [PATCH 0164/3723] drivers: led_strip: ws2812: Remove scratch selection for non-GPIO The WS2812 LED strip driver does not use a scratch byte, therefore free up a byte per pixel which was unused except in the GPIO-based driver whereby it is used Signed-off-by: Jamie McCrae --- drivers/led_strip/Kconfig.ws2812 | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/led_strip/Kconfig.ws2812 b/drivers/led_strip/Kconfig.ws2812 index fc91250c2f2..7682ba4be87 100644 --- a/drivers/led_strip/Kconfig.ws2812 +++ b/drivers/led_strip/Kconfig.ws2812 @@ -9,7 +9,6 @@ menuconfig WS2812_STRIP bool "WS2812 (and compatible) LED strip driver" - select LED_STRIP_RGB_SCRATCH help Enable LED strip driver for daisy chains of WS2812-ish (or WS2812B, WS2813, SK6812, Everlight B1414, or compatible) devices. @@ -39,6 +38,7 @@ config WS2812_STRIP_GPIO # Only an Cortex-M0 inline assembly implementation for the nRF51 # is supported currently. depends on SOC_SERIES_NRF51X + select LED_STRIP_RGB_SCRATCH help The GPIO driver does bit-banging with inline assembly, and is not available on all SoCs. From cce77c8902e112da97c6fb00d0ca39f15a435923 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Benjamin=20Cab=C3=A9?= Date: Fri, 17 Nov 2023 14:33:32 +0100 Subject: [PATCH 0165/3723] doc: latex: enable pdflscape package MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Enable the pdflscape package (available in the Latex distros recommended for Zephyr) to allow for some pages to be rendered in landscape mode. Signed-off-by: Benjamin Cabé --- doc/_static/latex/preamble.tex | 1 + 1 file changed, 1 insertion(+) diff --git a/doc/_static/latex/preamble.tex b/doc/_static/latex/preamble.tex index 3213c955bdb..50ef29d4d2b 100644 --- a/doc/_static/latex/preamble.tex +++ b/doc/_static/latex/preamble.tex @@ -5,6 +5,7 @@ \usepackage[some]{background} \usepackage{sectsty} +\usepackage{pdflscape} \definecolor{bg-color}{HTML}{333f67} From 2a9f914db250e2e9180c11e534d42a46efbf681a Mon Sep 17 00:00:00 2001 From: Jamie McCrae Date: Tue, 14 Nov 2023 09:54:39 +0000 Subject: [PATCH 0166/3723] doc: mgmt: mcumgr: Add list of libraries/tools Adds a list of tools and libraries that are available Signed-off-by: Jamie McCrae --- doc/services/device_mgmt/mcumgr.rst | 82 ++++++++++++++++++++++++++++- 1 file changed, 81 insertions(+), 1 deletion(-) diff --git a/doc/services/device_mgmt/mcumgr.rst b/doc/services/device_mgmt/mcumgr.rst index f16a77d43a9..0b21ce0771a 100644 --- a/doc/services/device_mgmt/mcumgr.rst +++ b/doc/services/device_mgmt/mcumgr.rst @@ -34,6 +34,85 @@ the Zephyr tree. Additionally, there is a :zephyr:code-sample:`sample ` sample that provides management functionality over BLE and serial. +.. _mcumgr_tools_libraries: + +Tools/libraries +*************** + +There are various tools and libraries available which enable usage of MCUmgr functionality on a +device which are listed below. Note that these tools are not part of or related to the Zephyr +project. + +.. only:: html + + .. table:: Tools and Libraries for MCUmgr + :align: center + + +--------------------------------------------------------------------------------+-------------------------------------------+--------------------------+--------------------------------------------------+---------------+------------+---------+ + | Name | OS support | Transports | Groups | Type | Language | License | + | +---------+-------+-----+--------+----------+--------+-----------+-----+----+-----+------+----------+----+-------+--------+ | | | + | | Windows | Linux | mac | Mobile | Embedded | Serial | Bluetooth | UDP | OS | IMG | Stat | Settings | FS | Shell | Zephyr | | | | + +================================================================================+=========+=======+=====+========+==========+========+===========+=====+====+=====+======+==========+====+=======+========+===============+============+=========+ + | `AuTerm `_ | ✓ | ✓ | ✓ | ✕ | ✕ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | Application | C++ (Qt) | GPLv3 | + +--------------------------------------------------------------------------------+---------+-------+-----+--------+----------+--------+-----------+-----+----+-----+------+----------+----+-------+--------+---------------+------------+---------+ + | `mcumgr-client `_ | ✓ | ✓ | ✓ | ✕ | ✕ | ✓ | ✕ | ✕ | ✕ | ✓ | ✕ | ✕ | ✕ | ✕ | ✕ | Application | Rust | BSD | + +--------------------------------------------------------------------------------+---------+-------+-----+--------+----------+--------+-----------+-----+----+-----+------+----------+----+-------+--------+---------------+------------+---------+ + | `mcumgr-web `_ | ✓ | ✓ | ✓ | ✕ | ✕ | ✕ | ✓ | ✕ | ✕ | ✓ | ✕ | ✕ | ✕ | ✕ | ✕ | Web page | Javascript | MIT | + | | | | | | | | | | | | | | | | | (chrome only) | | | + +--------------------------------------------------------------------------------+---------+-------+-----+--------+----------+--------+-----------+-----+----+-----+------+----------+----+-------+--------+---------------+------------+---------+ + | nRF Connect Device Manager: |br| | | | | | | | | | | | | | | | | | | | + | `Android | ✕ | ✕ | ✕ | ✓ | ✕ | ✕ | ✓ | ✕ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | Library and | Java, | Apache | + | `_ | | | | | | | | | | | | | | | | application | Kotlin, | | + | and `iOS | | | | | | | | | | | | | | | | | Swift | | + | `_ | | | | | | | | | | | | | | | | | | | + +--------------------------------------------------------------------------------+---------+-------+-----+--------+----------+--------+-----------+-----+----+-----+------+----------+----+-------+--------+---------------+------------+---------+ + | Zephyr MCUmgr client (in-tree) | ✕ | ✓ | ✕ | ✕ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✕ | ✕ | ✕ | ✕ | ✕ | Library | C | Apache | + +--------------------------------------------------------------------------------+---------+-------+-----+--------+----------+--------+-----------+-----+----+-----+------+----------+----+-------+--------+---------------+------------+---------+ + +.. only:: latex + + .. raw:: latex + + \begin{landscape} + + .. table:: Tools and Libraries for MCUmgr + :align: center + + +--------------------------------------------------------------------------------+---------------+-----------------+--------------------------------------------------+---------------+------------+ + | Name | OS support | Transports | Groups | Type | Language | + | | | +----+-----+------+----------+----+-------+--------+ | | + | | | | OS | IMG | Stat | Settings | FS | Shell | Zephyr | | | + +================================================================================+===============+=================+====+=====+======+==========+====+=======+========+===============+============+ + | `AuTerm `_ | Windows, |br| | Serial, |br| | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | App | C++ (Qt) | + | | Linux, |br| | Bluetooth, |br| | | | | | | | | | | + | | macOS | UDP | | | | | | | | | | + +--------------------------------------------------------------------------------+---------------+-----------------+----+-----+------+----------+----+-------+--------+---------------+------------+ + | `mcumgr-client `_ | Windows, |br| | Serial | ✕ | ✓ | ✕ | ✕ | ✕ | ✕ | ✕ | App | Rust | + | | Linux, |br| | | | | | | | | | | | + | | macOS | | | | | | | | | | | + +--------------------------------------------------------------------------------+---------------+-----------------+----+-----+------+----------+----+-------+--------+---------------+------------+ + | `mcumgr-web `_ | Windows, |br| | Bluetooth | ✕ | ✓ | ✕ | ✕ | ✕ | ✕ | ✕ | Web (chrome | Javascript | + | | Linux, |br| | | | | | | | | | only) | | + | | macOS | | | | | | | | | | | + +--------------------------------------------------------------------------------+---------------+-----------------+----+-----+------+----------+----+-------+--------+---------------+------------+ + | nRF Connect Device Manager: |br| | iOS, |br| | Bluetooth | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | Library, App | Java, | + | `Android | Android | | | | | | | | | | Kotlin, | + | `_ | | | | | | | | | | | Swift | + | and `iOS | | | | | | | | | | | | + | `_ | | | | | | | | | | | | + +--------------------------------------------------------------------------------+---------------+-----------------+----+-----+------+----------+----+-------+--------+---------------+------------+ + | Zephyr MCUmgr client (in-tree) | Linux, |br| | Serial, |br| | ✓ | ✓ | ✕ | ✕ | ✕ | ✕ | ✕ | Library | C | + | | Zephyr | Bluetooth, |br| | | | | | | | | | | + | | | UDP | | | | | | | | | | + +--------------------------------------------------------------------------------+---------------+-----------------+----+-----+------+----------+----+-------+--------+---------------+------------+ + + .. raw:: latex + + \end{landscape} + +Note that a tick for a particular group indicates basic support for that group in the code, it is +possible that not all commands/features of a group are supported by the implementation. + .. _mcumgr_cli: Command-line Tool @@ -49,7 +128,8 @@ The tool is written in the Go programming language. aborting will, in some circumstances, sit in an endless loop of sending the same command over and over again. A universal replacement for this tool is currently in development and once released, support for the go tool will be - dropped entirely. + dropped entirely. It is recommended that usage of tools listed above in the + :ref:`mcumgr_tools_libraries` section are used instead of the go client. To install the tool: From f9a547558aab6148fa1ee7824da2618e3a6f0a19 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Krzysztof=20Chru=C5=9Bci=C5=84ski?= Date: Tue, 21 Nov 2023 09:40:44 +0100 Subject: [PATCH 0167/3723] sys: cbprintf: Add macro for validating strings for packaging MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit When cbprintf package is created statically then only argument types are taken into account and not the format string. It means that a character pointer is always interpreted as %s and not %p. When %s is found then string from rw location is copied into the package. Copying unexpected data may lead to memory faults so it must be avoided. User shall cast an argument to a pointer of a different type. Patch adds macros which can at compile time determine if %p is used with char *. Result cannot be passed to static assert because compiler sees it as non-constant (even though calculated at compile time) but a runtime logging error message can be added instead of original message. Z_CBPRINTF_NONE_CHAR_PTR_COUNT counts number of none character pointers in the arguments list. Z_CBPRINTF_P_COUNT counts number of %p occurrences in the format string. If results of both macros are equal it means that string is ok. Signed-off-by: Krzysztof Chruściński --- include/zephyr/sys/cbprintf_cxx.h | 109 ++++++++ include/zephyr/sys/cbprintf_internal.h | 350 +++++++++++++++++++++++++ 2 files changed, 459 insertions(+) diff --git a/include/zephyr/sys/cbprintf_cxx.h b/include/zephyr/sys/cbprintf_cxx.h index 3b65b229517..1930e18b7d4 100644 --- a/include/zephyr/sys/cbprintf_cxx.h +++ b/include/zephyr/sys/cbprintf_cxx.h @@ -139,6 +139,115 @@ static inline int z_cbprintf_cxx_is_word_num(T arg) _Pragma("GCC diagnostic pop") } +/* C++ version for determining if argument is a none character pointer. */ +static inline int z_cbprintf_cxx_is_none_char_ptr(char) +{ + return 0; +} + +static inline int z_cbprintf_cxx_is_none_char_ptr(unsigned char) +{ + return 0; +} + +static inline int z_cbprintf_cxx_is_none_char_ptr(short) +{ + return 0; +} + +static inline int z_cbprintf_cxx_is_none_char_ptr(unsigned short) +{ + return 0; +} + +static inline int z_cbprintf_cxx_is_none_char_ptr(int) +{ + return 0; +} + +static inline int z_cbprintf_cxx_is_none_char_ptr(unsigned int) +{ + return 0; +} + +static inline int z_cbprintf_cxx_is_none_char_ptr(long) +{ + return 0; +} + +static inline int z_cbprintf_cxx_is_none_char_ptr(unsigned long) +{ + return 0; +} + +static inline int z_cbprintf_cxx_is_none_char_ptr(long long) +{ + return 0; +} + +static inline int z_cbprintf_cxx_is_none_char_ptr(unsigned long long) +{ + return 0; +} + +static inline int z_cbprintf_cxx_is_none_char_ptr(float) +{ + return 0; +} + +static inline int z_cbprintf_cxx_is_none_char_ptr(double) +{ + return 0; +} + +static inline int z_cbprintf_cxx_is_none_char_ptr(char *) +{ + return 0; +} + +static inline int z_cbprintf_cxx_is_none_char_ptr(volatile char *) +{ + return 0; +} + +static inline int z_cbprintf_cxx_is_none_char_ptr(const char *) +{ + return 0; +} + +static inline int z_cbprintf_cxx_is_none_char_ptr(const volatile char *) +{ + return 0; +} + +static inline int z_cbprintf_cxx_is_none_char_ptr(unsigned char *) +{ + return 0; +} + +static inline int z_cbprintf_cxx_is_none_char_ptr(volatile unsigned char *) +{ + return 0; +} + +static inline int z_cbprintf_cxx_is_none_char_ptr(const unsigned char *) +{ + return 0; +} + +static inline int z_cbprintf_cxx_is_none_char_ptr(const volatile unsigned char *) +{ + return 0; +} + +template < typename T > +static inline int z_cbprintf_cxx_is_none_char_ptr(T arg) +{ + ARG_UNUSED(arg); + + return 1; +} + /* C++ version for calculating argument size. */ static inline size_t z_cbprintf_cxx_arg_size(float f) { diff --git a/include/zephyr/sys/cbprintf_internal.h b/include/zephyr/sys/cbprintf_internal.h index eed2bbc3944..51b99494b96 100644 --- a/include/zephyr/sys/cbprintf_internal.h +++ b/include/zephyr/sys/cbprintf_internal.h @@ -138,6 +138,356 @@ extern "C" { 0) #endif +/** @brief Check if argument is a none character pointer. + * + * @note Macro triggers a pointer arithmetic warning and usage shall be wrapped in + * the pragma that suppresses this warning. + * + * @param x Input argument. + * + * @retval 1 if variable is a none character pointer. + * @retval 0 if variable is of different type. + */ +#ifdef __cplusplus +#define Z_CBPRINTF_IS_NONE_CHAR_PTR(x) z_cbprintf_cxx_is_none_char_ptr(x) +#else +#define Z_CBPRINTF_IS_NONE_CHAR_PTR(x) \ + _Generic((x) + 0, \ + char * : 0, \ + volatile char * : 0, \ + const char * : 0, \ + const volatile char * : 0, \ + unsigned char * : 0, \ + volatile unsigned char * : 0, \ + const unsigned char * : 0, \ + const volatile unsigned char * : 0, \ + char: 0, \ + unsigned char: 0, \ + short: 0, \ + unsigned short: 0, \ + int: 0, \ + unsigned int: 0,\ + long: 0, \ + unsigned long: 0,\ + long long: 0, \ + unsigned long long: 0, \ + float: 0, \ + double: 0, \ + default : \ + 1) +#endif + +/** @brief Get number of none character pointers in the string with at least 1 argument. + * + * @param ... String with at least 1 argument. + * + * @return Number of none character pointer arguments. + */ +#define Z_CBPRINTF_NONE_CHAR_PTR_ARGS(...) \ + (FOR_EACH(Z_CBPRINTF_IS_NONE_CHAR_PTR, (+), __VA_ARGS__)) \ + +/** @brief Get number of none character pointers in the string argument list. + * + * @param ... Format string with arguments. + * + * @return Number of none character pointer arguments. + */ +#define Z_CBPRINTF_NONE_CHAR_PTR_COUNT(...) \ + COND_CODE_0(NUM_VA_ARGS_LESS_1(__VA_ARGS__), \ + (0), \ + (Z_CBPRINTF_NONE_CHAR_PTR_ARGS(GET_ARGS_LESS_N(1, __VA_ARGS__)))) + +/** @brief Calculate number of pointer format specifiers in the string. + * + * If constant string is provided then result is calculated at compile time + * however for it is not consider constant by the compiler, e.g. can not be + * used in the static assert. + * + * String length is limited to 256. + * + * @param fmt Format string. + * @param ... String arguments. + * + * @return Number of %p format specifiers in the string. + */ +#define Z_CBPRINTF_P_COUNT(fmt, ...) \ + ((sizeof(fmt) >= 2 && fmt[0] == '%' && fmt[1] == 'p') ? 1 : 0) + \ + ((sizeof(fmt) >= 3 && fmt[0] != '%' && fmt[1] == '%' && fmt[2] == 'p') ? 1 : 0) + \ + ((sizeof(fmt) >= 4 && fmt[1] != '%' && fmt[2] == '%' && fmt[3] == 'p') ? 1 : 0) + \ + ((sizeof(fmt) >= 5 && fmt[2] != '%' && fmt[3] == '%' && fmt[4] == 'p') ? 1 : 0) + \ + ((sizeof(fmt) >= 6 && fmt[3] != '%' && fmt[4] == '%' && fmt[5] == 'p') ? 1 : 0) + \ + ((sizeof(fmt) >= 7 && fmt[4] != '%' && fmt[5] == '%' && fmt[6] == 'p') ? 1 : 0) + \ + ((sizeof(fmt) >= 8 && fmt[5] != '%' && fmt[6] == '%' && fmt[7] == 'p') ? 1 : 0) + \ + ((sizeof(fmt) >= 9 && fmt[6] != '%' && fmt[7] == '%' && fmt[8] == 'p') ? 1 : 0) + \ + ((sizeof(fmt) >= 10 && fmt[7] != '%' && fmt[8] == '%' && fmt[9] == 'p') ? 1 : 0) + \ + ((sizeof(fmt) >= 11 && fmt[8] != '%' && fmt[9] == '%' && fmt[10] == 'p') ? 1 : 0) + \ + ((sizeof(fmt) >= 12 && fmt[9] != '%' && fmt[10] == '%' && fmt[11] == 'p') ? 1 : 0) + \ + ((sizeof(fmt) >= 13 && fmt[10] != '%' && fmt[11] == '%' && fmt[12] == 'p') ? 1 : 0) + \ + ((sizeof(fmt) >= 14 && fmt[11] != '%' && fmt[12] == '%' && fmt[13] == 'p') ? 1 : 0) + \ + ((sizeof(fmt) >= 15 && fmt[12] != '%' && fmt[13] == '%' && fmt[14] == 'p') ? 1 : 0) + \ + ((sizeof(fmt) >= 16 && fmt[13] != '%' && fmt[14] == '%' && fmt[15] == 'p') ? 1 : 0) + \ + ((sizeof(fmt) >= 17 && fmt[14] != '%' && fmt[15] == '%' && fmt[16] == 'p') ? 1 : 0) + \ + ((sizeof(fmt) >= 18 && fmt[15] != '%' && fmt[16] == '%' && fmt[17] == 'p') ? 1 : 0) + \ + ((sizeof(fmt) >= 19 && fmt[16] != '%' && fmt[17] == '%' && fmt[18] == 'p') ? 1 : 0) + \ + ((sizeof(fmt) >= 20 && fmt[17] != '%' && fmt[18] == '%' && fmt[19] == 'p') ? 1 : 0) + \ + ((sizeof(fmt) >= 21 && fmt[18] != '%' && fmt[19] == '%' && fmt[20] == 'p') ? 1 : 0) + \ + ((sizeof(fmt) >= 22 && fmt[19] != '%' && fmt[20] == '%' && fmt[21] == 'p') ? 1 : 0) + \ + ((sizeof(fmt) >= 23 && fmt[20] != '%' && fmt[21] == '%' && fmt[22] == 'p') ? 1 : 0) + \ + ((sizeof(fmt) >= 24 && fmt[21] != '%' && fmt[22] == '%' && fmt[23] == 'p') ? 1 : 0) + \ + ((sizeof(fmt) >= 25 && fmt[22] != '%' && fmt[23] == '%' && fmt[24] == 'p') ? 1 : 0) + \ + ((sizeof(fmt) >= 26 && fmt[23] != '%' && fmt[24] == '%' && fmt[25] == 'p') ? 1 : 0) + \ + ((sizeof(fmt) >= 27 && fmt[24] != '%' && fmt[25] == '%' && fmt[26] == 'p') ? 1 : 0) + \ + ((sizeof(fmt) >= 28 && fmt[25] != '%' && fmt[26] == '%' && fmt[27] == 'p') ? 1 : 0) + \ + ((sizeof(fmt) >= 29 && fmt[26] != '%' && fmt[27] == '%' && fmt[28] == 'p') ? 1 : 0) + \ + ((sizeof(fmt) >= 30 && fmt[27] != '%' && fmt[28] == '%' && fmt[29] == 'p') ? 1 : 0) + \ + ((sizeof(fmt) >= 31 && fmt[28] != '%' && fmt[29] == '%' && fmt[30] == 'p') ? 1 : 0) + \ + ((sizeof(fmt) >= 32 && fmt[29] != '%' && fmt[30] == '%' && fmt[31] == 'p') ? 1 : 0) + \ + ((sizeof(fmt) >= 33 && fmt[30] != '%' && fmt[31] == '%' && fmt[32] == 'p') ? 1 : 0) + \ + ((sizeof(fmt) >= 34 && fmt[31] != '%' && fmt[32] == '%' && fmt[33] == 'p') ? 1 : 0) + \ + ((sizeof(fmt) >= 35 && fmt[32] != '%' && fmt[33] == '%' && fmt[34] == 'p') ? 1 : 0) + \ + ((sizeof(fmt) >= 36 && fmt[33] != '%' && fmt[34] == '%' && fmt[35] == 'p') ? 1 : 0) + \ + ((sizeof(fmt) >= 37 && fmt[34] != '%' && fmt[35] == '%' && fmt[36] == 'p') ? 1 : 0) + \ + ((sizeof(fmt) >= 38 && fmt[35] != '%' && fmt[36] == '%' && fmt[37] == 'p') ? 1 : 0) + \ + ((sizeof(fmt) >= 39 && fmt[36] != '%' && fmt[37] == '%' && fmt[38] == 'p') ? 1 : 0) + \ + ((sizeof(fmt) >= 40 && fmt[37] != '%' && fmt[38] == '%' && fmt[39] == 'p') ? 1 : 0) + \ + ((sizeof(fmt) >= 41 && fmt[38] != '%' && fmt[39] == '%' && fmt[40] == 'p') ? 1 : 0) + \ + ((sizeof(fmt) >= 42 && fmt[39] != '%' && fmt[40] == '%' && fmt[41] == 'p') ? 1 : 0) + \ + ((sizeof(fmt) >= 43 && fmt[40] != '%' && fmt[41] == '%' && fmt[42] == 'p') ? 1 : 0) + \ + ((sizeof(fmt) >= 44 && fmt[41] != '%' && fmt[42] == '%' && fmt[43] == 'p') ? 1 : 0) + \ + ((sizeof(fmt) >= 45 && fmt[42] != '%' && fmt[43] == '%' && fmt[44] == 'p') ? 1 : 0) + \ + ((sizeof(fmt) >= 46 && fmt[43] != '%' && fmt[44] == '%' && fmt[45] == 'p') ? 1 : 0) + \ + ((sizeof(fmt) >= 47 && fmt[44] != '%' && fmt[45] == '%' && fmt[46] == 'p') ? 1 : 0) + \ + ((sizeof(fmt) >= 48 && fmt[45] != '%' && fmt[46] == '%' && fmt[47] == 'p') ? 1 : 0) + \ + ((sizeof(fmt) >= 49 && fmt[46] != '%' && fmt[47] == '%' && fmt[48] == 'p') ? 1 : 0) + \ + ((sizeof(fmt) >= 50 && fmt[47] != '%' && fmt[48] == '%' && fmt[49] == 'p') ? 1 : 0) + \ + ((sizeof(fmt) >= 51 && fmt[48] != '%' && fmt[49] == '%' && fmt[50] == 'p') ? 1 : 0) + \ + ((sizeof(fmt) >= 52 && fmt[49] != '%' && fmt[50] == '%' && fmt[51] == 'p') ? 1 : 0) + \ + ((sizeof(fmt) >= 53 && fmt[50] != '%' && fmt[51] == '%' && fmt[52] == 'p') ? 1 : 0) + \ + ((sizeof(fmt) >= 54 && fmt[51] != '%' && fmt[52] == '%' && fmt[53] == 'p') ? 1 : 0) + \ + ((sizeof(fmt) >= 55 && fmt[52] != '%' && fmt[53] == '%' && fmt[54] == 'p') ? 1 : 0) + \ + ((sizeof(fmt) >= 56 && fmt[53] != '%' && fmt[54] == '%' && fmt[55] == 'p') ? 1 : 0) + \ + ((sizeof(fmt) >= 57 && fmt[54] != '%' && fmt[55] == '%' && fmt[56] == 'p') ? 1 : 0) + \ + ((sizeof(fmt) >= 58 && fmt[55] != '%' && fmt[56] == '%' && fmt[57] == 'p') ? 1 : 0) + \ + ((sizeof(fmt) >= 59 && fmt[56] != '%' && fmt[57] == '%' && fmt[58] == 'p') ? 1 : 0) + \ + ((sizeof(fmt) >= 60 && fmt[57] != '%' && fmt[58] == '%' && fmt[59] == 'p') ? 1 : 0) + \ + ((sizeof(fmt) >= 61 && fmt[58] != '%' && fmt[59] == '%' && fmt[60] == 'p') ? 1 : 0) + \ + ((sizeof(fmt) >= 62 && fmt[59] != '%' && fmt[60] == '%' && fmt[61] == 'p') ? 1 : 0) + \ + ((sizeof(fmt) >= 63 && fmt[60] != '%' && fmt[61] == '%' && fmt[62] == 'p') ? 1 : 0) + \ + ((sizeof(fmt) >= 64 && fmt[61] != '%' && fmt[62] == '%' && fmt[63] == 'p') ? 1 : 0) + \ + ((sizeof(fmt) >= 65 && fmt[62] != '%' && fmt[63] == '%' && fmt[64] == 'p') ? 1 : 0) + \ + ((sizeof(fmt) >= 66 && fmt[63] != '%' && fmt[64] == '%' && fmt[65] == 'p') ? 1 : 0) + \ + ((sizeof(fmt) >= 67 && fmt[64] != '%' && fmt[65] == '%' && fmt[66] == 'p') ? 1 : 0) + \ + ((sizeof(fmt) >= 68 && fmt[65] != '%' && fmt[66] == '%' && fmt[67] == 'p') ? 1 : 0) + \ + ((sizeof(fmt) >= 69 && fmt[66] != '%' && fmt[67] == '%' && fmt[68] == 'p') ? 1 : 0) + \ + ((sizeof(fmt) >= 70 && fmt[67] != '%' && fmt[68] == '%' && fmt[69] == 'p') ? 1 : 0) + \ + ((sizeof(fmt) >= 71 && fmt[68] != '%' && fmt[69] == '%' && fmt[70] == 'p') ? 1 : 0) + \ + ((sizeof(fmt) >= 72 && fmt[69] != '%' && fmt[70] == '%' && fmt[71] == 'p') ? 1 : 0) + \ + ((sizeof(fmt) >= 73 && fmt[70] != '%' && fmt[71] == '%' && fmt[72] == 'p') ? 1 : 0) + \ + ((sizeof(fmt) >= 74 && fmt[71] != '%' && fmt[72] == '%' && fmt[73] == 'p') ? 1 : 0) + \ + ((sizeof(fmt) >= 75 && fmt[72] != '%' && fmt[73] == '%' && fmt[74] == 'p') ? 1 : 0) + \ + ((sizeof(fmt) >= 76 && fmt[73] != '%' && fmt[74] == '%' && fmt[75] == 'p') ? 1 : 0) + \ + ((sizeof(fmt) >= 77 && fmt[74] != '%' && fmt[75] == '%' && fmt[76] == 'p') ? 1 : 0) + \ + ((sizeof(fmt) >= 78 && fmt[75] != '%' && fmt[76] == '%' && fmt[77] == 'p') ? 1 : 0) + \ + ((sizeof(fmt) >= 79 && fmt[76] != '%' && fmt[77] == '%' && fmt[78] == 'p') ? 1 : 0) + \ + ((sizeof(fmt) >= 80 && fmt[77] != '%' && fmt[78] == '%' && fmt[79] == 'p') ? 1 : 0) + \ + ((sizeof(fmt) >= 81 && fmt[78] != '%' && fmt[79] == '%' && fmt[80] == 'p') ? 1 : 0) + \ + ((sizeof(fmt) >= 82 && fmt[79] != '%' && fmt[80] == '%' && fmt[81] == 'p') ? 1 : 0) + \ + ((sizeof(fmt) >= 83 && fmt[80] != '%' && fmt[81] == '%' && fmt[82] == 'p') ? 1 : 0) + \ + ((sizeof(fmt) >= 84 && fmt[81] != '%' && fmt[82] == '%' && fmt[83] == 'p') ? 1 : 0) + \ + ((sizeof(fmt) >= 85 && fmt[82] != '%' && fmt[83] == '%' && fmt[84] == 'p') ? 1 : 0) + \ + ((sizeof(fmt) >= 86 && fmt[83] != '%' && fmt[84] == '%' && fmt[85] == 'p') ? 1 : 0) + \ + ((sizeof(fmt) >= 87 && fmt[84] != '%' && fmt[85] == '%' && fmt[86] == 'p') ? 1 : 0) + \ + ((sizeof(fmt) >= 88 && fmt[85] != '%' && fmt[86] == '%' && fmt[87] == 'p') ? 1 : 0) + \ + ((sizeof(fmt) >= 89 && fmt[86] != '%' && fmt[87] == '%' && fmt[88] == 'p') ? 1 : 0) + \ + ((sizeof(fmt) >= 90 && fmt[87] != '%' && fmt[88] == '%' && fmt[89] == 'p') ? 1 : 0) + \ + ((sizeof(fmt) >= 91 && fmt[88] != '%' && fmt[89] == '%' && fmt[90] == 'p') ? 1 : 0) + \ + ((sizeof(fmt) >= 92 && fmt[89] != '%' && fmt[90] == '%' && fmt[91] == 'p') ? 1 : 0) + \ + ((sizeof(fmt) >= 93 && fmt[90] != '%' && fmt[91] == '%' && fmt[92] == 'p') ? 1 : 0) + \ + ((sizeof(fmt) >= 94 && fmt[91] != '%' && fmt[92] == '%' && fmt[93] == 'p') ? 1 : 0) + \ + ((sizeof(fmt) >= 95 && fmt[92] != '%' && fmt[93] == '%' && fmt[94] == 'p') ? 1 : 0) + \ + ((sizeof(fmt) >= 96 && fmt[93] != '%' && fmt[94] == '%' && fmt[95] == 'p') ? 1 : 0) + \ + ((sizeof(fmt) >= 97 && fmt[94] != '%' && fmt[95] == '%' && fmt[96] == 'p') ? 1 : 0) + \ + ((sizeof(fmt) >= 98 && fmt[95] != '%' && fmt[96] == '%' && fmt[97] == 'p') ? 1 : 0) + \ + ((sizeof(fmt) >= 99 && fmt[96] != '%' && fmt[97] == '%' && fmt[98] == 'p') ? 1 : 0) + \ + ((sizeof(fmt) >= 100 && fmt[97] != '%' && fmt[98] == '%' && fmt[99] == 'p') ? 1 : 0) + \ + ((sizeof(fmt) >= 101 && fmt[98] != '%' && fmt[99] == '%' && fmt[100] == 'p') ? 1 : 0) + \ + ((sizeof(fmt) >= 102 && fmt[99] != '%' && fmt[100] == '%' && fmt[101] == 'p') ? 1 : 0) + \ + ((sizeof(fmt) >= 103 && fmt[100] != '%' && fmt[101] == '%' && fmt[102] == 'p') ? 1 : 0) + \ + ((sizeof(fmt) >= 104 && fmt[101] != '%' && fmt[102] == '%' && fmt[103] == 'p') ? 1 : 0) + \ + ((sizeof(fmt) >= 105 && fmt[102] != '%' && fmt[103] == '%' && fmt[104] == 'p') ? 1 : 0) + \ + ((sizeof(fmt) >= 106 && fmt[103] != '%' && fmt[104] == '%' && fmt[105] == 'p') ? 1 : 0) + \ + ((sizeof(fmt) >= 107 && fmt[104] != '%' && fmt[105] == '%' && fmt[106] == 'p') ? 1 : 0) + \ + ((sizeof(fmt) >= 108 && fmt[105] != '%' && fmt[106] == '%' && fmt[107] == 'p') ? 1 : 0) + \ + ((sizeof(fmt) >= 109 && fmt[106] != '%' && fmt[107] == '%' && fmt[108] == 'p') ? 1 : 0) + \ + ((sizeof(fmt) >= 110 && fmt[107] != '%' && fmt[108] == '%' && fmt[109] == 'p') ? 1 : 0) + \ + ((sizeof(fmt) >= 111 && fmt[108] != '%' && fmt[109] == '%' && fmt[110] == 'p') ? 1 : 0) + \ + ((sizeof(fmt) >= 112 && fmt[109] != '%' && fmt[110] == '%' && fmt[111] == 'p') ? 1 : 0) + \ + ((sizeof(fmt) >= 113 && fmt[110] != '%' && fmt[111] == '%' && fmt[112] == 'p') ? 1 : 0) + \ + ((sizeof(fmt) >= 114 && fmt[111] != '%' && fmt[112] == '%' && fmt[113] == 'p') ? 1 : 0) + \ + ((sizeof(fmt) >= 115 && fmt[112] != '%' && fmt[113] == '%' && fmt[114] == 'p') ? 1 : 0) + \ + ((sizeof(fmt) >= 116 && fmt[113] != '%' && fmt[114] == '%' && fmt[115] == 'p') ? 1 : 0) + \ + ((sizeof(fmt) >= 117 && fmt[114] != '%' && fmt[115] == '%' && fmt[116] == 'p') ? 1 : 0) + \ + ((sizeof(fmt) >= 118 && fmt[115] != '%' && fmt[116] == '%' && fmt[117] == 'p') ? 1 : 0) + \ + ((sizeof(fmt) >= 119 && fmt[116] != '%' && fmt[117] == '%' && fmt[118] == 'p') ? 1 : 0) + \ + ((sizeof(fmt) >= 120 && fmt[117] != '%' && fmt[118] == '%' && fmt[119] == 'p') ? 1 : 0) + \ + ((sizeof(fmt) >= 121 && fmt[118] != '%' && fmt[119] == '%' && fmt[120] == 'p') ? 1 : 0) + \ + ((sizeof(fmt) >= 122 && fmt[119] != '%' && fmt[120] == '%' && fmt[121] == 'p') ? 1 : 0) + \ + ((sizeof(fmt) >= 123 && fmt[120] != '%' && fmt[121] == '%' && fmt[122] == 'p') ? 1 : 0) + \ + ((sizeof(fmt) >= 124 && fmt[121] != '%' && fmt[122] == '%' && fmt[123] == 'p') ? 1 : 0) + \ + ((sizeof(fmt) >= 125 && fmt[122] != '%' && fmt[123] == '%' && fmt[124] == 'p') ? 1 : 0) + \ + ((sizeof(fmt) >= 126 && fmt[123] != '%' && fmt[124] == '%' && fmt[125] == 'p') ? 1 : 0) + \ + ((sizeof(fmt) >= 127 && fmt[124] != '%' && fmt[125] == '%' && fmt[126] == 'p') ? 1 : 0) + \ + ((sizeof(fmt) >= 128 && fmt[125] != '%' && fmt[126] == '%' && fmt[127] == 'p') ? 1 : 0) + \ + ((sizeof(fmt) >= 129 && fmt[126] != '%' && fmt[127] == '%' && fmt[128] == 'p') ? 1 : 0) + \ + ((sizeof(fmt) >= 130 && fmt[127] != '%' && fmt[128] == '%' && fmt[129] == 'p') ? 1 : 0) + \ + ((sizeof(fmt) >= 131 && fmt[128] != '%' && fmt[129] == '%' && fmt[130] == 'p') ? 1 : 0) + \ + ((sizeof(fmt) >= 132 && fmt[129] != '%' && fmt[130] == '%' && fmt[131] == 'p') ? 1 : 0) + \ + ((sizeof(fmt) >= 133 && fmt[130] != '%' && fmt[131] == '%' && fmt[132] == 'p') ? 1 : 0) + \ + ((sizeof(fmt) >= 134 && fmt[131] != '%' && fmt[132] == '%' && fmt[133] == 'p') ? 1 : 0) + \ + ((sizeof(fmt) >= 135 && fmt[132] != '%' && fmt[133] == '%' && fmt[134] == 'p') ? 1 : 0) + \ + ((sizeof(fmt) >= 136 && fmt[133] != '%' && fmt[134] == '%' && fmt[135] == 'p') ? 1 : 0) + \ + ((sizeof(fmt) >= 137 && fmt[134] != '%' && fmt[135] == '%' && fmt[136] == 'p') ? 1 : 0) + \ + ((sizeof(fmt) >= 138 && fmt[135] != '%' && fmt[136] == '%' && fmt[137] == 'p') ? 1 : 0) + \ + ((sizeof(fmt) >= 139 && fmt[136] != '%' && fmt[137] == '%' && fmt[138] == 'p') ? 1 : 0) + \ + ((sizeof(fmt) >= 140 && fmt[137] != '%' && fmt[138] == '%' && fmt[139] == 'p') ? 1 : 0) + \ + ((sizeof(fmt) >= 141 && fmt[138] != '%' && fmt[139] == '%' && fmt[140] == 'p') ? 1 : 0) + \ + ((sizeof(fmt) >= 142 && fmt[139] != '%' && fmt[140] == '%' && fmt[141] == 'p') ? 1 : 0) + \ + ((sizeof(fmt) >= 143 && fmt[140] != '%' && fmt[141] == '%' && fmt[142] == 'p') ? 1 : 0) + \ + ((sizeof(fmt) >= 144 && fmt[141] != '%' && fmt[142] == '%' && fmt[143] == 'p') ? 1 : 0) + \ + ((sizeof(fmt) >= 145 && fmt[142] != '%' && fmt[143] == '%' && fmt[144] == 'p') ? 1 : 0) + \ + ((sizeof(fmt) >= 146 && fmt[143] != '%' && fmt[144] == '%' && fmt[145] == 'p') ? 1 : 0) + \ + ((sizeof(fmt) >= 147 && fmt[144] != '%' && fmt[145] == '%' && fmt[146] == 'p') ? 1 : 0) + \ + ((sizeof(fmt) >= 148 && fmt[145] != '%' && fmt[146] == '%' && fmt[147] == 'p') ? 1 : 0) + \ + ((sizeof(fmt) >= 149 && fmt[146] != '%' && fmt[147] == '%' && fmt[148] == 'p') ? 1 : 0) + \ + ((sizeof(fmt) >= 150 && fmt[147] != '%' && fmt[148] == '%' && fmt[149] == 'p') ? 1 : 0) + \ + ((sizeof(fmt) >= 151 && fmt[148] != '%' && fmt[149] == '%' && fmt[150] == 'p') ? 1 : 0) + \ + ((sizeof(fmt) >= 152 && fmt[149] != '%' && fmt[150] == '%' && fmt[151] == 'p') ? 1 : 0) + \ + ((sizeof(fmt) >= 153 && fmt[150] != '%' && fmt[151] == '%' && fmt[152] == 'p') ? 1 : 0) + \ + ((sizeof(fmt) >= 154 && fmt[151] != '%' && fmt[152] == '%' && fmt[153] == 'p') ? 1 : 0) + \ + ((sizeof(fmt) >= 155 && fmt[152] != '%' && fmt[153] == '%' && fmt[154] == 'p') ? 1 : 0) + \ + ((sizeof(fmt) >= 156 && fmt[153] != '%' && fmt[154] == '%' && fmt[155] == 'p') ? 1 : 0) + \ + ((sizeof(fmt) >= 157 && fmt[154] != '%' && fmt[155] == '%' && fmt[156] == 'p') ? 1 : 0) + \ + ((sizeof(fmt) >= 158 && fmt[155] != '%' && fmt[156] == '%' && fmt[157] == 'p') ? 1 : 0) + \ + ((sizeof(fmt) >= 159 && fmt[156] != '%' && fmt[157] == '%' && fmt[158] == 'p') ? 1 : 0) + \ + ((sizeof(fmt) >= 160 && fmt[157] != '%' && fmt[158] == '%' && fmt[159] == 'p') ? 1 : 0) + \ + ((sizeof(fmt) >= 161 && fmt[158] != '%' && fmt[159] == '%' && fmt[160] == 'p') ? 1 : 0) + \ + ((sizeof(fmt) >= 162 && fmt[159] != '%' && fmt[160] == '%' && fmt[161] == 'p') ? 1 : 0) + \ + ((sizeof(fmt) >= 163 && fmt[160] != '%' && fmt[161] == '%' && fmt[162] == 'p') ? 1 : 0) + \ + ((sizeof(fmt) >= 164 && fmt[161] != '%' && fmt[162] == '%' && fmt[163] == 'p') ? 1 : 0) + \ + ((sizeof(fmt) >= 165 && fmt[162] != '%' && fmt[163] == '%' && fmt[164] == 'p') ? 1 : 0) + \ + ((sizeof(fmt) >= 166 && fmt[163] != '%' && fmt[164] == '%' && fmt[165] == 'p') ? 1 : 0) + \ + ((sizeof(fmt) >= 167 && fmt[164] != '%' && fmt[165] == '%' && fmt[166] == 'p') ? 1 : 0) + \ + ((sizeof(fmt) >= 168 && fmt[165] != '%' && fmt[166] == '%' && fmt[167] == 'p') ? 1 : 0) + \ + ((sizeof(fmt) >= 169 && fmt[166] != '%' && fmt[167] == '%' && fmt[168] == 'p') ? 1 : 0) + \ + ((sizeof(fmt) >= 170 && fmt[167] != '%' && fmt[168] == '%' && fmt[169] == 'p') ? 1 : 0) + \ + ((sizeof(fmt) >= 171 && fmt[168] != '%' && fmt[169] == '%' && fmt[170] == 'p') ? 1 : 0) + \ + ((sizeof(fmt) >= 172 && fmt[169] != '%' && fmt[170] == '%' && fmt[171] == 'p') ? 1 : 0) + \ + ((sizeof(fmt) >= 173 && fmt[170] != '%' && fmt[171] == '%' && fmt[172] == 'p') ? 1 : 0) + \ + ((sizeof(fmt) >= 174 && fmt[171] != '%' && fmt[172] == '%' && fmt[173] == 'p') ? 1 : 0) + \ + ((sizeof(fmt) >= 175 && fmt[172] != '%' && fmt[173] == '%' && fmt[174] == 'p') ? 1 : 0) + \ + ((sizeof(fmt) >= 176 && fmt[173] != '%' && fmt[174] == '%' && fmt[175] == 'p') ? 1 : 0) + \ + ((sizeof(fmt) >= 177 && fmt[174] != '%' && fmt[175] == '%' && fmt[176] == 'p') ? 1 : 0) + \ + ((sizeof(fmt) >= 178 && fmt[175] != '%' && fmt[176] == '%' && fmt[177] == 'p') ? 1 : 0) + \ + ((sizeof(fmt) >= 179 && fmt[176] != '%' && fmt[177] == '%' && fmt[178] == 'p') ? 1 : 0) + \ + ((sizeof(fmt) >= 180 && fmt[177] != '%' && fmt[178] == '%' && fmt[179] == 'p') ? 1 : 0) + \ + ((sizeof(fmt) >= 181 && fmt[178] != '%' && fmt[179] == '%' && fmt[180] == 'p') ? 1 : 0) + \ + ((sizeof(fmt) >= 182 && fmt[179] != '%' && fmt[180] == '%' && fmt[181] == 'p') ? 1 : 0) + \ + ((sizeof(fmt) >= 183 && fmt[180] != '%' && fmt[181] == '%' && fmt[182] == 'p') ? 1 : 0) + \ + ((sizeof(fmt) >= 184 && fmt[181] != '%' && fmt[182] == '%' && fmt[183] == 'p') ? 1 : 0) + \ + ((sizeof(fmt) >= 185 && fmt[182] != '%' && fmt[183] == '%' && fmt[184] == 'p') ? 1 : 0) + \ + ((sizeof(fmt) >= 186 && fmt[183] != '%' && fmt[184] == '%' && fmt[185] == 'p') ? 1 : 0) + \ + ((sizeof(fmt) >= 187 && fmt[184] != '%' && fmt[185] == '%' && fmt[186] == 'p') ? 1 : 0) + \ + ((sizeof(fmt) >= 188 && fmt[185] != '%' && fmt[186] == '%' && fmt[187] == 'p') ? 1 : 0) + \ + ((sizeof(fmt) >= 189 && fmt[186] != '%' && fmt[187] == '%' && fmt[188] == 'p') ? 1 : 0) + \ + ((sizeof(fmt) >= 190 && fmt[187] != '%' && fmt[188] == '%' && fmt[189] == 'p') ? 1 : 0) + \ + ((sizeof(fmt) >= 191 && fmt[188] != '%' && fmt[189] == '%' && fmt[190] == 'p') ? 1 : 0) + \ + ((sizeof(fmt) >= 192 && fmt[189] != '%' && fmt[190] == '%' && fmt[191] == 'p') ? 1 : 0) + \ + ((sizeof(fmt) >= 193 && fmt[190] != '%' && fmt[191] == '%' && fmt[192] == 'p') ? 1 : 0) + \ + ((sizeof(fmt) >= 194 && fmt[191] != '%' && fmt[192] == '%' && fmt[193] == 'p') ? 1 : 0) + \ + ((sizeof(fmt) >= 195 && fmt[192] != '%' && fmt[193] == '%' && fmt[194] == 'p') ? 1 : 0) + \ + ((sizeof(fmt) >= 196 && fmt[193] != '%' && fmt[194] == '%' && fmt[195] == 'p') ? 1 : 0) + \ + ((sizeof(fmt) >= 197 && fmt[194] != '%' && fmt[195] == '%' && fmt[196] == 'p') ? 1 : 0) + \ + ((sizeof(fmt) >= 198 && fmt[195] != '%' && fmt[196] == '%' && fmt[197] == 'p') ? 1 : 0) + \ + ((sizeof(fmt) >= 199 && fmt[196] != '%' && fmt[197] == '%' && fmt[198] == 'p') ? 1 : 0) + \ + ((sizeof(fmt) >= 200 && fmt[197] != '%' && fmt[198] == '%' && fmt[199] == 'p') ? 1 : 0) + \ + ((sizeof(fmt) >= 201 && fmt[198] != '%' && fmt[199] == '%' && fmt[200] == 'p') ? 1 : 0) + \ + ((sizeof(fmt) >= 202 && fmt[199] != '%' && fmt[200] == '%' && fmt[201] == 'p') ? 1 : 0) + \ + ((sizeof(fmt) >= 203 && fmt[200] != '%' && fmt[201] == '%' && fmt[202] == 'p') ? 1 : 0) + \ + ((sizeof(fmt) >= 204 && fmt[201] != '%' && fmt[202] == '%' && fmt[203] == 'p') ? 1 : 0) + \ + ((sizeof(fmt) >= 205 && fmt[202] != '%' && fmt[203] == '%' && fmt[204] == 'p') ? 1 : 0) + \ + ((sizeof(fmt) >= 206 && fmt[203] != '%' && fmt[204] == '%' && fmt[205] == 'p') ? 1 : 0) + \ + ((sizeof(fmt) >= 207 && fmt[204] != '%' && fmt[205] == '%' && fmt[206] == 'p') ? 1 : 0) + \ + ((sizeof(fmt) >= 208 && fmt[205] != '%' && fmt[206] == '%' && fmt[207] == 'p') ? 1 : 0) + \ + ((sizeof(fmt) >= 209 && fmt[206] != '%' && fmt[207] == '%' && fmt[208] == 'p') ? 1 : 0) + \ + ((sizeof(fmt) >= 210 && fmt[207] != '%' && fmt[208] == '%' && fmt[209] == 'p') ? 1 : 0) + \ + ((sizeof(fmt) >= 211 && fmt[208] != '%' && fmt[209] == '%' && fmt[210] == 'p') ? 1 : 0) + \ + ((sizeof(fmt) >= 212 && fmt[209] != '%' && fmt[210] == '%' && fmt[211] == 'p') ? 1 : 0) + \ + ((sizeof(fmt) >= 213 && fmt[210] != '%' && fmt[211] == '%' && fmt[212] == 'p') ? 1 : 0) + \ + ((sizeof(fmt) >= 214 && fmt[211] != '%' && fmt[212] == '%' && fmt[213] == 'p') ? 1 : 0) + \ + ((sizeof(fmt) >= 215 && fmt[212] != '%' && fmt[213] == '%' && fmt[214] == 'p') ? 1 : 0) + \ + ((sizeof(fmt) >= 216 && fmt[213] != '%' && fmt[214] == '%' && fmt[215] == 'p') ? 1 : 0) + \ + ((sizeof(fmt) >= 217 && fmt[214] != '%' && fmt[215] == '%' && fmt[216] == 'p') ? 1 : 0) + \ + ((sizeof(fmt) >= 218 && fmt[215] != '%' && fmt[216] == '%' && fmt[217] == 'p') ? 1 : 0) + \ + ((sizeof(fmt) >= 219 && fmt[216] != '%' && fmt[217] == '%' && fmt[218] == 'p') ? 1 : 0) + \ + ((sizeof(fmt) >= 220 && fmt[217] != '%' && fmt[218] == '%' && fmt[219] == 'p') ? 1 : 0) + \ + ((sizeof(fmt) >= 221 && fmt[218] != '%' && fmt[219] == '%' && fmt[220] == 'p') ? 1 : 0) + \ + ((sizeof(fmt) >= 222 && fmt[219] != '%' && fmt[220] == '%' && fmt[221] == 'p') ? 1 : 0) + \ + ((sizeof(fmt) >= 223 && fmt[220] != '%' && fmt[221] == '%' && fmt[222] == 'p') ? 1 : 0) + \ + ((sizeof(fmt) >= 224 && fmt[221] != '%' && fmt[222] == '%' && fmt[223] == 'p') ? 1 : 0) + \ + ((sizeof(fmt) >= 225 && fmt[222] != '%' && fmt[223] == '%' && fmt[224] == 'p') ? 1 : 0) + \ + ((sizeof(fmt) >= 226 && fmt[223] != '%' && fmt[224] == '%' && fmt[225] == 'p') ? 1 : 0) + \ + ((sizeof(fmt) >= 227 && fmt[224] != '%' && fmt[225] == '%' && fmt[226] == 'p') ? 1 : 0) + \ + ((sizeof(fmt) >= 228 && fmt[225] != '%' && fmt[226] == '%' && fmt[227] == 'p') ? 1 : 0) + \ + ((sizeof(fmt) >= 229 && fmt[226] != '%' && fmt[227] == '%' && fmt[228] == 'p') ? 1 : 0) + \ + ((sizeof(fmt) >= 230 && fmt[227] != '%' && fmt[228] == '%' && fmt[229] == 'p') ? 1 : 0) + \ + ((sizeof(fmt) >= 231 && fmt[228] != '%' && fmt[229] == '%' && fmt[230] == 'p') ? 1 : 0) + \ + ((sizeof(fmt) >= 232 && fmt[229] != '%' && fmt[230] == '%' && fmt[231] == 'p') ? 1 : 0) + \ + ((sizeof(fmt) >= 233 && fmt[230] != '%' && fmt[231] == '%' && fmt[232] == 'p') ? 1 : 0) + \ + ((sizeof(fmt) >= 234 && fmt[231] != '%' && fmt[232] == '%' && fmt[233] == 'p') ? 1 : 0) + \ + ((sizeof(fmt) >= 235 && fmt[232] != '%' && fmt[233] == '%' && fmt[234] == 'p') ? 1 : 0) + \ + ((sizeof(fmt) >= 236 && fmt[233] != '%' && fmt[234] == '%' && fmt[235] == 'p') ? 1 : 0) + \ + ((sizeof(fmt) >= 237 && fmt[234] != '%' && fmt[235] == '%' && fmt[236] == 'p') ? 1 : 0) + \ + ((sizeof(fmt) >= 238 && fmt[235] != '%' && fmt[236] == '%' && fmt[237] == 'p') ? 1 : 0) + \ + ((sizeof(fmt) >= 239 && fmt[236] != '%' && fmt[237] == '%' && fmt[238] == 'p') ? 1 : 0) + \ + ((sizeof(fmt) >= 240 && fmt[237] != '%' && fmt[238] == '%' && fmt[239] == 'p') ? 1 : 0) + \ + ((sizeof(fmt) >= 241 && fmt[238] != '%' && fmt[239] == '%' && fmt[240] == 'p') ? 1 : 0) + \ + ((sizeof(fmt) >= 242 && fmt[239] != '%' && fmt[240] == '%' && fmt[241] == 'p') ? 1 : 0) + \ + ((sizeof(fmt) >= 243 && fmt[240] != '%' && fmt[241] == '%' && fmt[242] == 'p') ? 1 : 0) + \ + ((sizeof(fmt) >= 244 && fmt[241] != '%' && fmt[242] == '%' && fmt[243] == 'p') ? 1 : 0) + \ + ((sizeof(fmt) >= 245 && fmt[242] != '%' && fmt[243] == '%' && fmt[244] == 'p') ? 1 : 0) + \ + ((sizeof(fmt) >= 246 && fmt[243] != '%' && fmt[244] == '%' && fmt[245] == 'p') ? 1 : 0) + \ + ((sizeof(fmt) >= 247 && fmt[244] != '%' && fmt[245] == '%' && fmt[246] == 'p') ? 1 : 0) + \ + ((sizeof(fmt) >= 248 && fmt[245] != '%' && fmt[246] == '%' && fmt[247] == 'p') ? 1 : 0) + \ + ((sizeof(fmt) >= 249 && fmt[246] != '%' && fmt[247] == '%' && fmt[248] == 'p') ? 1 : 0) + \ + ((sizeof(fmt) >= 250 && fmt[247] != '%' && fmt[248] == '%' && fmt[249] == 'p') ? 1 : 0) + \ + ((sizeof(fmt) >= 251 && fmt[248] != '%' && fmt[249] == '%' && fmt[250] == 'p') ? 1 : 0) + \ + ((sizeof(fmt) >= 252 && fmt[249] != '%' && fmt[250] == '%' && fmt[251] == 'p') ? 1 : 0) + \ + ((sizeof(fmt) >= 253 && fmt[250] != '%' && fmt[251] == '%' && fmt[252] == 'p') ? 1 : 0) + \ + ((sizeof(fmt) >= 254 && fmt[251] != '%' && fmt[252] == '%' && fmt[253] == 'p') ? 1 : 0) + \ + ((sizeof(fmt) >= 255 && fmt[252] != '%' && fmt[253] == '%' && fmt[254] == 'p') ? 1 : 0) + \ + ((sizeof(fmt) >= 256 && fmt[253] != '%' && fmt[254] == '%' && fmt[255] == 'p') ? 1 : 0) + +/** @brief Determine if all %p arguments are none character pointer arguments. + * + * Static package creation relies on the assumption that character pointers are + * only using %s arguments. To not confuse it with %p, any character pointer + * that is used with %p should be casted to a pointer of a different type, e.g. + * void *. This macro can be used to determine, at compile time, if such casting + * is missing. It is determined at compile time but cannot be used for static + * assertion so only runtime error reporting can be added. + * + * @note Macro triggers a pointer arithmetic warning and usage shall be wrapped in + * the pragma that suppresses this warning. + * + * @param ... Format string with arguments. + * + * @retval True if string is okay. + * @retval False if casting is missing. + */ +#define Z_CBPRINTF_POINTERS_VALIDATE(...) \ + (Z_CBPRINTF_NONE_CHAR_PTR_COUNT(__VA_ARGS__) == \ + Z_CBPRINTF_P_COUNT(GET_ARG_N(1, __VA_ARGS__))) + /* @brief Check if argument is a certain type of char pointer. What exectly is checked * depends on @p flags. If flags is 0 then 1 is returned if @p x is a char pointer. * From aa2e315ab0bdc259e5835d14f280036815f0eaf5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Krzysztof=20Chru=C5=9Bci=C5=84ski?= Date: Tue, 21 Nov 2023 09:46:00 +0100 Subject: [PATCH 0168/3723] tests: unit: cbprintf: Add tests for string validation MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Add tests for Z_CBPRINTF_NONE_CHAR_PTR_COUNT, Z_CBPRINTF_P_COUNT and Z_CBPRINTF_POINTERS_VALIDATE. Signed-off-by: Krzysztof Chruściński --- tests/unit/cbprintf/main.c | 99 ++++++++++++++++++++++++++++++++++++++ 1 file changed, 99 insertions(+) diff --git a/tests/unit/cbprintf/main.c b/tests/unit/cbprintf/main.c index 3d618bb9300..ace6aa6ff25 100644 --- a/tests/unit/cbprintf/main.c +++ b/tests/unit/cbprintf/main.c @@ -1338,6 +1338,105 @@ ZTEST(prf, test_nop) { } +ZTEST(prf, test_is_none_char_ptr) +{ + char c = 0; + const char cc = 0; + volatile char vc = 0; + volatile const char vcc = 0; + + unsigned char uc = 0; + const unsigned char cuc = 0; + volatile unsigned char vuc = 0; + volatile const unsigned char vcuc = 0; + + short s = 0; + unsigned short us = 0; + + int i = 0; + unsigned int ui = 0; + + long l = 0; + unsigned long ul = 0; + + long long ll = 0; + unsigned long long ull = 0; + + float f = 0.1; + double d = 0.1; + + _Pragma("GCC diagnostic push") + _Pragma("GCC diagnostic ignored \"-Wpointer-arith\"") + zassert_equal(Z_CBPRINTF_IS_NONE_CHAR_PTR(c), 0); + zassert_equal(Z_CBPRINTF_IS_NONE_CHAR_PTR(cc), 0); + zassert_equal(Z_CBPRINTF_IS_NONE_CHAR_PTR(vc), 0); + zassert_equal(Z_CBPRINTF_IS_NONE_CHAR_PTR(vcc), 0); + + zassert_equal(Z_CBPRINTF_IS_NONE_CHAR_PTR(&c), 0); + zassert_equal(Z_CBPRINTF_IS_NONE_CHAR_PTR(&cc), 0); + zassert_equal(Z_CBPRINTF_IS_NONE_CHAR_PTR(&vc), 0); + zassert_equal(Z_CBPRINTF_IS_NONE_CHAR_PTR(&vcc), 0); + + zassert_equal(Z_CBPRINTF_IS_NONE_CHAR_PTR(uc), 0); + zassert_equal(Z_CBPRINTF_IS_NONE_CHAR_PTR(cuc), 0); + zassert_equal(Z_CBPRINTF_IS_NONE_CHAR_PTR(vuc), 0); + zassert_equal(Z_CBPRINTF_IS_NONE_CHAR_PTR(vcuc), 0); + + zassert_equal(Z_CBPRINTF_IS_NONE_CHAR_PTR(&uc), 0); + zassert_equal(Z_CBPRINTF_IS_NONE_CHAR_PTR(&cuc), 0); + zassert_equal(Z_CBPRINTF_IS_NONE_CHAR_PTR(&vuc), 0); + zassert_equal(Z_CBPRINTF_IS_NONE_CHAR_PTR(&vcuc), 0); + + zassert_equal(Z_CBPRINTF_IS_NONE_CHAR_PTR(s), 0); + zassert_equal(Z_CBPRINTF_IS_NONE_CHAR_PTR(us), 0); + zassert_equal(Z_CBPRINTF_IS_NONE_CHAR_PTR(&s), 1); + zassert_equal(Z_CBPRINTF_IS_NONE_CHAR_PTR(&us), 1); + + zassert_equal(Z_CBPRINTF_IS_NONE_CHAR_PTR(i), 0); + zassert_equal(Z_CBPRINTF_IS_NONE_CHAR_PTR(ui), 0); + zassert_equal(Z_CBPRINTF_IS_NONE_CHAR_PTR(&i), 1); + zassert_equal(Z_CBPRINTF_IS_NONE_CHAR_PTR(&ui), 1); + + zassert_equal(Z_CBPRINTF_IS_NONE_CHAR_PTR(l), 0); + zassert_equal(Z_CBPRINTF_IS_NONE_CHAR_PTR(ul), 0); + zassert_equal(Z_CBPRINTF_IS_NONE_CHAR_PTR(&l), 1); + zassert_equal(Z_CBPRINTF_IS_NONE_CHAR_PTR(&ul), 1); + + zassert_equal(Z_CBPRINTF_IS_NONE_CHAR_PTR(ll), 0); + zassert_equal(Z_CBPRINTF_IS_NONE_CHAR_PTR(ull), 0); + zassert_equal(Z_CBPRINTF_IS_NONE_CHAR_PTR(&ll), 1); + zassert_equal(Z_CBPRINTF_IS_NONE_CHAR_PTR(&ull), 1); + + zassert_equal(Z_CBPRINTF_IS_NONE_CHAR_PTR(f), 0); + zassert_equal(Z_CBPRINTF_IS_NONE_CHAR_PTR(d), 0); + zassert_equal(Z_CBPRINTF_IS_NONE_CHAR_PTR(&f), 1); + zassert_equal(Z_CBPRINTF_IS_NONE_CHAR_PTR(&d), 1); + + zassert_equal(Z_CBPRINTF_IS_NONE_CHAR_PTR((void *)&c), 1); + + _Pragma("GCC diagnostic pop") +} + +ZTEST(prf, test_p_count) +{ + zassert_equal(Z_CBPRINTF_P_COUNT("no pointers"), 0); + zassert_equal(Z_CBPRINTF_P_COUNT("no %%p pointers"), 0); + + zassert_equal(Z_CBPRINTF_P_COUNT("%d %%p %x %s %p %f"), 1); + zassert_equal(Z_CBPRINTF_P_COUNT("%p %p %llx %p "), 3); +} + +ZTEST(prf, test_pointers_validate) +{ + _Pragma("GCC diagnostic push") + _Pragma("GCC diagnostic ignored \"-Wpointer-arith\"") + zassert_equal(Z_CBPRINTF_POINTERS_VALIDATE("no arguments"), true); + /* const char fails validation */ + zassert_equal(Z_CBPRINTF_POINTERS_VALIDATE("%p", "string"), false); + zassert_equal(Z_CBPRINTF_POINTERS_VALIDATE("%p", (void *)"string"), true); + _Pragma("GCC diagnostic pop") +} + static void *cbprintf_setup(void) { if (sizeof(int) == 4) { From 465446e5aab7722b5c048280e140ae4968f06229 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Krzysztof=20Chru=C5=9Bci=C5=84ski?= Date: Tue, 21 Nov 2023 09:50:52 +0100 Subject: [PATCH 0169/3723] logging: Add string validation to detect %p misuse MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Logging shall not use character pointers with %p because in certain configurations it may lead to memory faults. A compile time detection is added. If faulty usage is detected then message is replaced with error message which indicates which message failed and what shall be done (casting to a pointer of different type). Validation is enabled only for configurations which remove strings from binary as otherwise it may impact CI execution time. Signed-off-by: Krzysztof Chruściński --- include/zephyr/logging/log_core.h | 30 ++++++++++++++++++++++++++++++ subsys/logging/Kconfig.misc | 9 +++++++++ 2 files changed, 39 insertions(+) diff --git a/include/zephyr/logging/log_core.h b/include/zephyr/logging/log_core.h index bc4cb2d8f36..b18fe00c09e 100644 --- a/include/zephyr/logging/log_core.h +++ b/include/zephyr/logging/log_core.h @@ -190,6 +190,30 @@ static inline char z_log_minimal_level_to_char(int level) #define Z_LOG_INST(_inst) COND_CODE_1(CONFIG_LOG, (_inst), NULL) +/* If strings are removed from the binary then there is a risk of creating invalid + * cbprintf package if %p is used with character pointer which is interpreted as + * string. A compile time check is performed (since format string is known at + * compile time) and check fails logging message is not created but error is + * emitted instead. String check may increase compilation time so it is not + * always performed (could significantly increase CI time). + */ +#if CONFIG_LOG_FMT_STRING_VALIDATE +#define LOG_STRING_WARNING(_mode, _src, ...) \ + Z_LOG_MSG_CREATE(UTIL_NOT(IS_ENABLED(CONFIG_USERSPACE)), _mode, \ + Z_LOG_LOCAL_DOMAIN_ID, _src, LOG_LEVEL_ERR, NULL, 0, \ + "char pointer used for %%p, cast to void *:\"%s\"", \ + GET_ARG_N(1, __VA_ARGS__)) + +#define LOG_POINTERS_VALIDATE(string_ok, ...) \ + _Pragma("GCC diagnostic push") \ + _Pragma("GCC diagnostic ignored \"-Wpointer-arith\"") \ + string_ok = Z_CBPRINTF_POINTERS_VALIDATE(__VA_ARGS__); \ + _Pragma("GCC diagnostic pop") +#else +#define LOG_POINTERS_VALIDATE(string_ok, ...) string_ok = true +#define LOG_STRING_WARNING(_mode, _src, ...) +#endif + /*****************************************************************************/ /****************** Macros for standard logging ******************************/ /*****************************************************************************/ @@ -234,6 +258,12 @@ static inline char z_log_minimal_level_to_char(int level) int _mode; \ void *_src = IS_ENABLED(CONFIG_LOG_RUNTIME_FILTERING) ? \ (void *)_dsource : (void *)_source; \ + bool string_ok; \ + LOG_POINTERS_VALIDATE(string_ok, __VA_ARGS__); \ + if (!string_ok) { \ + LOG_STRING_WARNING(_mode, _src, __VA_ARGS__); \ + break; \ + } \ Z_LOG_MSG_CREATE(UTIL_NOT(IS_ENABLED(CONFIG_USERSPACE)), _mode, \ Z_LOG_LOCAL_DOMAIN_ID, _src, _level, NULL,\ 0, __VA_ARGS__); \ diff --git a/subsys/logging/Kconfig.misc b/subsys/logging/Kconfig.misc index ce34bdae0a0..4b2d9fa143c 100644 --- a/subsys/logging/Kconfig.misc +++ b/subsys/logging/Kconfig.misc @@ -70,6 +70,15 @@ config LOG_FMT_SECTION_STRIP depends on LOG_FMT_SECTION depends on LINKER_DEVNULL_SUPPORT imply LINKER_DEVNULL_MEMORY + imply LOG_FMT_STRING_VALIDATE + +config LOG_FMT_STRING_VALIDATE + bool "Validate logging strings" + help + Logging strings cannot use %p with character pointers. They should be + casted to the pointer of another type (e.g. void *). With this feature + enabled, at compile time, the preprocessor detects strings with %p + without casting and reports an error at runtime. config LOG_USE_TAGGED_ARGUMENTS bool "Using tagged arguments for packaging" From 8342d87478b55cb10bc10cdcd4128f9dc02da29a Mon Sep 17 00:00:00 2001 From: Yong Cong Sin Date: Wed, 22 Nov 2023 22:10:15 +0800 Subject: [PATCH 0170/3723] drivers: intc: plic: brackets for if-conds & use explicit comparison if-conditionals should have brackets according to Zephyr's coding standard, and explicitly compares `edge_irq` against 0. Signed-off-by: Yong Cong Sin --- drivers/interrupt_controller/intc_plic.c | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/drivers/interrupt_controller/intc_plic.c b/drivers/interrupt_controller/intc_plic.c index 51ce1769396..c41610a46d0 100644 --- a/drivers/interrupt_controller/intc_plic.c +++ b/drivers/interrupt_controller/intc_plic.c @@ -271,8 +271,9 @@ static void plic_irq_handler(const struct device *dev) * If the IRQ is out of range, call z_irq_spurious. * A call to z_irq_spurious will not return. */ - if (local_irq == 0U || local_irq >= config->num_irqs) + if (local_irq == 0U || local_irq >= config->num_irqs) { z_irq_spurious(NULL); + } edge_irq = riscv_plic_is_edge_irq(dev, local_irq); @@ -281,8 +282,9 @@ static void plic_irq_handler(const struct device *dev) * to indicate to the PLIC controller that the IRQ has been handled * for edge triggered interrupts. */ - if (edge_irq) + if (edge_irq != 0) { sys_write32(local_irq, claim_complete_addr); + } const uint32_t parent_irq = COND_CODE_1(IS_ENABLED(CONFIG_DYNAMIC_INTERRUPTS), (z_get_sw_isr_irq_from_device(dev)), (0U)); @@ -300,8 +302,9 @@ static void plic_irq_handler(const struct device *dev) * PLIC controller that the IRQ has been handled * for level triggered interrupts. */ - if (!edge_irq) + if (edge_irq == 0) { sys_write32(local_irq, claim_complete_addr); + } } /** From e9fa6f8b4a339bb0b6e89ed90b3d103d9ce05284 Mon Sep 17 00:00:00 2001 From: Yong Cong Sin Date: Tue, 21 Nov 2023 22:53:01 +0800 Subject: [PATCH 0171/3723] drivers: intc: plic: add shell cmd to get irq stats for debugging Introduced `CONFIG_PLIC_SHELL` to enable the build of shell debugging command to get the hit count of each interrupt controller's IRQ line. This is especially useful when working with dynamically installed ISRs, which will be the case for `plic_sw`. Example usage: ``` uart:~$ plic stats get interrupt-controller@c000000 IRQ Hits ================== 10 177 uart:~$ plic stats get interrupt-controller@c000000 IRQ Hits ================== 10 236 uart:~$ plic stats clear interrupt-controller@c000000 Cleared stats of interrupt-controller@c000000. uart:~$ plic stats get interrupt-controller@c000000 IRQ Hits ================== 10 90 ``` Signed-off-by: Yong Cong Sin Signed-off-by: Maxim Adelman --- drivers/interrupt_controller/CMakeLists.txt | 7 + drivers/interrupt_controller/Kconfig.plic | 11 ++ drivers/interrupt_controller/intc_plic.c | 148 +++++++++++++++++++- 3 files changed, 165 insertions(+), 1 deletion(-) diff --git a/drivers/interrupt_controller/CMakeLists.txt b/drivers/interrupt_controller/CMakeLists.txt index 5598d038940..7ef0a5e161e 100644 --- a/drivers/interrupt_controller/CMakeLists.txt +++ b/drivers/interrupt_controller/CMakeLists.txt @@ -42,4 +42,11 @@ if(CONFIG_INTEL_VTD_ICTL) zephyr_library_include_directories(${ZEPHYR_BASE}/arch/x86/include) endif() +if(CONFIG_PLIC_SHELL) + message(WARNING " + WARNING: `CONFIG_PLIC_SHELL` is enabled. + This can use quite a bit of RAM (PLICs * IRQs * sizeof(uint16_t))" + ) +endif() + zephyr_library_include_directories(${ZEPHYR_BASE}/arch/common/include) diff --git a/drivers/interrupt_controller/Kconfig.plic b/drivers/interrupt_controller/Kconfig.plic index c1e16c7c1c5..d4f91a3fbd2 100644 --- a/drivers/interrupt_controller/Kconfig.plic +++ b/drivers/interrupt_controller/Kconfig.plic @@ -10,3 +10,14 @@ config PLIC help Platform Level Interrupt Controller provides support for external interrupt lines defined by the RISC-V SoC. + +if PLIC + +config PLIC_SHELL + bool "PLIC shell commands" + depends on SHELL + help + Enable additional shell commands useful for debugging. + Caution: This can use quite a bit of RAM (PLICs * IRQs * sizeof(uint16_t)). + +endif # PLIC diff --git a/drivers/interrupt_controller/intc_plic.c b/drivers/interrupt_controller/intc_plic.c index c41610a46d0..d05d28b8834 100644 --- a/drivers/interrupt_controller/intc_plic.c +++ b/drivers/interrupt_controller/intc_plic.c @@ -13,11 +13,14 @@ * for RISC-V processors */ +#include + #include "sw_isr_common.h" #include #include #include +#include #include #include @@ -62,6 +65,14 @@ struct plic_config { riscv_plic_irq_config_func_t irq_config_func; }; +struct plic_stats { + uint16_t *irq_count; +}; + +struct plic_data { + struct plic_stats stats; +}; + static uint32_t save_irq; static const struct device *save_dev; @@ -258,6 +269,16 @@ static void plic_irq_handler(const struct device *dev) /* Get the IRQ number generating the interrupt */ const uint32_t local_irq = sys_read32(claim_complete_addr); +#ifdef CONFIG_PLIC_SHELL + const struct plic_data *data = dev->data; + struct plic_stats stat = data->stats; + + /* Cap the count at __UINT16_MAX__ */ + if (stat.irq_count[local_irq] != __UINT16_MAX__) { + stat.irq_count[local_irq]++; + } +#endif /* CONFIG_PLIC_SHELL */ + /* * Save IRQ in save_irq. To be used, if need be, by * subsequent handlers registered in the _sw_isr_table table, @@ -340,6 +361,130 @@ static int plic_init(const struct device *dev) return 0; } +#ifdef CONFIG_PLIC_SHELL +static inline int parse_device(const struct shell *sh, size_t argc, char *argv[], + const struct device **plic) +{ + ARG_UNUSED(argc); + + *plic = device_get_binding(argv[1]); + if (*plic == NULL) { + shell_error(sh, "PLIC device (%s) not found!\n", argv[1]); + return -ENODEV; + } + + return 0; +} + +static int cmd_get_stats(const struct shell *sh, size_t argc, char *argv[]) +{ + const struct device *dev; + int ret = parse_device(sh, argc, argv, &dev); + uint16_t min_hit = 0; + + if (ret != 0) { + return ret; + } + + const struct plic_config *config = dev->config; + const struct plic_data *data = dev->data; + struct plic_stats stat = data->stats; + + if (argc > 2) { + min_hit = (uint16_t)atoi(argv[2]); + shell_print(sh, "IRQ line with > %d hits:", min_hit); + } + + shell_print(sh, " IRQ\t Hits"); + shell_print(sh, "=================="); + for (size_t i = 0; i < MIN(config->num_irqs, CONFIG_MAX_IRQ_PER_AGGREGATOR); i++) { + if (stat.irq_count[i] > min_hit) { + shell_print(sh, "%6d\t%10d", i, stat.irq_count[i]); + } + } + shell_print(sh, ""); + + return 0; +} + +static int cmd_clear_stats(const struct shell *sh, size_t argc, char *argv[]) +{ + const struct device *dev; + int ret = parse_device(sh, argc, argv, &dev); + + if (ret != 0) { + return ret; + } + + const struct plic_config *config = dev->config; + const struct plic_data *data = dev->data; + struct plic_stats stat = data->stats; + + memset(stat.irq_count, 0, + MIN(config->num_irqs, CONFIG_MAX_IRQ_PER_AGGREGATOR) * sizeof(uint16_t)); + + shell_print(sh, "Cleared stats of %s.\n", dev->name); + + return 0; +} + +/* Device name autocompletion support */ +static void device_name_get(size_t idx, struct shell_static_entry *entry) +{ + const struct device *dev = shell_device_lookup(idx, NULL); + + entry->syntax = (dev != NULL) ? dev->name : NULL; + entry->handler = NULL; + entry->help = NULL; + entry->subcmd = NULL; +} + +SHELL_DYNAMIC_CMD_CREATE(dsub_device_name, device_name_get); + +SHELL_STATIC_SUBCMD_SET_CREATE(plic_stats_cmds, + SHELL_CMD_ARG(get, &dsub_device_name, + "Read PLIC's stats.\n" + "Usage: plic stats get [minimum hits]", + cmd_get_stats, 2, 1), + SHELL_CMD_ARG(clear, &dsub_device_name, + "Reset PLIC's stats.\n" + "Usage: plic stats clear ", + cmd_clear_stats, 2, 0), + SHELL_SUBCMD_SET_END +); + +SHELL_STATIC_SUBCMD_SET_CREATE(plic_cmds, + SHELL_CMD_ARG(stats, &plic_stats_cmds, "PLIC stats", NULL, 3, 0), + SHELL_SUBCMD_SET_END +); + +static int cmd_plic(const struct shell *sh, size_t argc, char **argv) +{ + shell_error(sh, "%s:unknown parameter: %s", argv[0], argv[1]); + return -EINVAL; +} + +SHELL_CMD_ARG_REGISTER(plic, &plic_cmds, "PLIC shell commands", + cmd_plic, 2, 0); + +#define PLIC_INTC_IRQ_COUNT_BUF_DEFINE(n) \ + static uint16_t local_irq_count_##n[MIN(DT_INST_PROP(n, riscv_ndev), \ + CONFIG_MAX_IRQ_PER_AGGREGATOR)]; + +#define PLIC_INTC_DATA_INIT(n) \ + PLIC_INTC_IRQ_COUNT_BUF_DEFINE(n); \ + static struct plic_data plic_data_##n = { \ + .stats = { \ + .irq_count = local_irq_count_##n, \ + }, \ + }; + +#define PLIC_INTC_DATA(n) &plic_data_##n +#else +#define PLIC_INTC_DATA_INIT(...) +#define PLIC_INTC_DATA(n) (NULL) +#endif + #define PLIC_INTC_IRQ_FUNC_DECLARE(n) static void plic_irq_config_func_##n(void) #define PLIC_INTC_IRQ_FUNC_DEFINE(n) \ @@ -364,8 +509,9 @@ static int plic_init(const struct device *dev) #define PLIC_INTC_DEVICE_INIT(n) \ PLIC_INTC_CONFIG_INIT(n) \ + PLIC_INTC_DATA_INIT(n) \ DEVICE_DT_INST_DEFINE(n, &plic_init, NULL, \ - NULL, &plic_config_##n, \ + PLIC_INTC_DATA(n), &plic_config_##n, \ PRE_KERNEL_1, CONFIG_INTC_INIT_PRIORITY, \ NULL); From 88d91fb82f3891c4efe661b0430522442ac2f936 Mon Sep 17 00:00:00 2001 From: Armando Visconti Date: Tue, 21 Nov 2023 17:01:01 +0100 Subject: [PATCH 0172/3723] drivers/sensor: lsm6dsv16x: fix DT configuration read for int1/int2 Since lsm6dsv16x may be multi-instantiated, triggers must be enabled and configured on DT basis and not only thru CONFIG_LSM6DSV16X_TRIGGER macro; if either int1-gpios of int2-gpios (or both) are configured in DT, the flag trig_enable is set to 'true' for that instance. The previous implentation was lacking the check of those two Device Tree properties, so trig_enabled was always true for all instances. Signed-off-by: Armando Visconti --- drivers/sensor/lsm6dsv16x/lsm6dsv16x.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/drivers/sensor/lsm6dsv16x/lsm6dsv16x.c b/drivers/sensor/lsm6dsv16x/lsm6dsv16x.c index f7d53bc0b93..e507a2165b0 100644 --- a/drivers/sensor/lsm6dsv16x/lsm6dsv16x.c +++ b/drivers/sensor/lsm6dsv16x/lsm6dsv16x.c @@ -923,6 +923,7 @@ static int lsm6dsv16x_init(const struct device *dev) .trig_enabled = true, \ .int1_gpio = GPIO_DT_SPEC_INST_GET_OR(inst, int1_gpios, { 0 }), \ .int2_gpio = GPIO_DT_SPEC_INST_GET_OR(inst, int2_gpios, { 0 }), \ + .drdy_pulsed = DT_INST_PROP(inst, drdy_pulsed), \ .drdy_pin = DT_INST_PROP(inst, drdy_pin) #else #define LSM6DSV16X_CFG_IRQ(inst) @@ -938,8 +939,9 @@ static int lsm6dsv16x_init(const struct device *dev) .accel_range = DT_INST_PROP(inst, accel_range), \ .gyro_odr = DT_INST_PROP(inst, gyro_odr), \ .gyro_range = DT_INST_PROP(inst, gyro_range), \ - .drdy_pulsed = DT_INST_PROP(inst, drdy_pulsed), \ - LSM6DSV16X_CFG_IRQ(inst) + IF_ENABLED(UTIL_OR(DT_INST_NODE_HAS_PROP(inst, int1_gpios), \ + DT_INST_NODE_HAS_PROP(inst, int2_gpios)), \ + (LSM6DSV16X_CFG_IRQ(inst))) #define LSM6DSV16X_CONFIG_SPI(inst) \ { \ From 05df6830b73dc2c36212929f9e9577c54d310dba Mon Sep 17 00:00:00 2001 From: Marcio Ribeiro Date: Wed, 15 Nov 2023 17:47:31 -0300 Subject: [PATCH 0173/3723] boards: dts: add missing code partition into ESP32 based boards zephyr,code-partition added to ESP32 based board files Signed-off-by: Marcio Ribeiro --- boards/riscv/esp32c3_devkitm/esp32c3_devkitm.dts | 1 + boards/riscv/esp32c3_luatos_core/esp32c3_luatos_core.dts | 1 + boards/riscv/icev_wireless/icev_wireless.dts | 1 + boards/riscv/stamp_c3/stamp_c3.dts | 1 + boards/riscv/xiao_esp32c3/xiao_esp32c3.dts | 1 + boards/xtensa/esp32_devkitc_wroom/esp32_devkitc_wroom.dts | 1 + boards/xtensa/esp32_devkitc_wrover/esp32_devkitc_wrover.dts | 1 + boards/xtensa/esp32_ethernet_kit/esp32_ethernet_kit.dts | 1 + boards/xtensa/esp32s2_franzininho/esp32s2_franzininho.dts | 1 + boards/xtensa/esp32s2_lolin_mini/esp32s2_lolin_mini.dts | 1 + boards/xtensa/esp32s2_saola/esp32s2_saola.dts | 1 + boards/xtensa/esp32s3_devkitm/esp32s3_devkitm.dts | 1 + boards/xtensa/esp32s3_luatos_core/esp32s3_luatos_core.dts | 1 + boards/xtensa/esp_wrover_kit/esp_wrover_kit.dts | 1 + boards/xtensa/heltec_wifi_lora32_v2/heltec_wifi_lora32_v2.dts | 1 + .../heltec_wireless_stick_lite_v3.dts | 1 + boards/xtensa/m5stack_atoms3/m5stack_atoms3.dts | 1 + boards/xtensa/m5stickc_plus/m5stickc_plus.dts | 1 + boards/xtensa/odroid_go/odroid_go.dts | 1 + boards/xtensa/olimex_esp32_evb/olimex_esp32_evb.dts | 1 + boards/xtensa/xiao_esp32s3/xiao_esp32s3.dts | 1 + boards/xtensa/yd_esp32/yd_esp32.dts | 1 + 22 files changed, 22 insertions(+) diff --git a/boards/riscv/esp32c3_devkitm/esp32c3_devkitm.dts b/boards/riscv/esp32c3_devkitm/esp32c3_devkitm.dts index 60cfdea523a..6c390956e48 100644 --- a/boards/riscv/esp32c3_devkitm/esp32c3_devkitm.dts +++ b/boards/riscv/esp32c3_devkitm/esp32c3_devkitm.dts @@ -19,6 +19,7 @@ zephyr,console = &uart0; zephyr,shell-uart = &uart0; zephyr,flash = &flash0; + zephyr,code-partition = &slot0_partition; }; aliases { diff --git a/boards/riscv/esp32c3_luatos_core/esp32c3_luatos_core.dts b/boards/riscv/esp32c3_luatos_core/esp32c3_luatos_core.dts index 5a74be9984e..00a69833557 100644 --- a/boards/riscv/esp32c3_luatos_core/esp32c3_luatos_core.dts +++ b/boards/riscv/esp32c3_luatos_core/esp32c3_luatos_core.dts @@ -14,5 +14,6 @@ zephyr,console = &uart0; zephyr,shell-uart = &uart0; zephyr,flash = &flash0; + zephyr,code-partition = &slot0_partition; }; }; diff --git a/boards/riscv/icev_wireless/icev_wireless.dts b/boards/riscv/icev_wireless/icev_wireless.dts index 998ce4c0bc3..1e5719fe2aa 100644 --- a/boards/riscv/icev_wireless/icev_wireless.dts +++ b/boards/riscv/icev_wireless/icev_wireless.dts @@ -19,6 +19,7 @@ zephyr,console = &usb_serial; zephyr,shell-uart = &usb_serial; zephyr,flash = &flash0; + zephyr,code-partition = &slot0_partition; }; aliases { diff --git a/boards/riscv/stamp_c3/stamp_c3.dts b/boards/riscv/stamp_c3/stamp_c3.dts index 029ae49b198..56353da3d81 100644 --- a/boards/riscv/stamp_c3/stamp_c3.dts +++ b/boards/riscv/stamp_c3/stamp_c3.dts @@ -19,6 +19,7 @@ zephyr,console = &uart0; zephyr,shell-uart = &uart0; zephyr,flash = &flash0; + zephyr,code-partition = &slot0_partition; }; aliases { diff --git a/boards/riscv/xiao_esp32c3/xiao_esp32c3.dts b/boards/riscv/xiao_esp32c3/xiao_esp32c3.dts index 45823b069c8..5cea1004af6 100644 --- a/boards/riscv/xiao_esp32c3/xiao_esp32c3.dts +++ b/boards/riscv/xiao_esp32c3/xiao_esp32c3.dts @@ -19,6 +19,7 @@ zephyr,console = &usb_serial; zephyr,shell-uart = &usb_serial; zephyr,flash = &flash0; + zephyr,code-partition = &slot0_partition; zephyr,canbus = &twai; }; diff --git a/boards/xtensa/esp32_devkitc_wroom/esp32_devkitc_wroom.dts b/boards/xtensa/esp32_devkitc_wroom/esp32_devkitc_wroom.dts index 6fa0bf47f61..ef6d619676c 100644 --- a/boards/xtensa/esp32_devkitc_wroom/esp32_devkitc_wroom.dts +++ b/boards/xtensa/esp32_devkitc_wroom/esp32_devkitc_wroom.dts @@ -34,6 +34,7 @@ zephyr,console = &uart0; zephyr,shell-uart = &uart0; zephyr,flash = &flash0; + zephyr,code-partition = &slot0_partition; }; }; diff --git a/boards/xtensa/esp32_devkitc_wrover/esp32_devkitc_wrover.dts b/boards/xtensa/esp32_devkitc_wrover/esp32_devkitc_wrover.dts index 43218f3e81f..d4cbdce3d90 100644 --- a/boards/xtensa/esp32_devkitc_wrover/esp32_devkitc_wrover.dts +++ b/boards/xtensa/esp32_devkitc_wrover/esp32_devkitc_wrover.dts @@ -34,6 +34,7 @@ zephyr,console = &uart0; zephyr,shell-uart = &uart0; zephyr,flash = &flash0; + zephyr,code-partition = &slot0_partition; }; }; diff --git a/boards/xtensa/esp32_ethernet_kit/esp32_ethernet_kit.dts b/boards/xtensa/esp32_ethernet_kit/esp32_ethernet_kit.dts index 3139e8beaa3..50b01b88b2f 100644 --- a/boards/xtensa/esp32_ethernet_kit/esp32_ethernet_kit.dts +++ b/boards/xtensa/esp32_ethernet_kit/esp32_ethernet_kit.dts @@ -22,6 +22,7 @@ zephyr,console = &uart0; zephyr,shell-uart = &uart0; zephyr,flash = &flash0; + zephyr,code-partition = &slot0_partition; }; }; diff --git a/boards/xtensa/esp32s2_franzininho/esp32s2_franzininho.dts b/boards/xtensa/esp32s2_franzininho/esp32s2_franzininho.dts index 66c85606097..2ce35ee5534 100644 --- a/boards/xtensa/esp32s2_franzininho/esp32s2_franzininho.dts +++ b/boards/xtensa/esp32s2_franzininho/esp32s2_franzininho.dts @@ -25,6 +25,7 @@ zephyr,console = &uart0; zephyr,shell-uart = &uart0; zephyr,flash = &flash0; + zephyr,code-partition = &slot0_partition; }; leds { diff --git a/boards/xtensa/esp32s2_lolin_mini/esp32s2_lolin_mini.dts b/boards/xtensa/esp32s2_lolin_mini/esp32s2_lolin_mini.dts index 9f90447560b..3ce00f8bdb8 100644 --- a/boards/xtensa/esp32s2_lolin_mini/esp32s2_lolin_mini.dts +++ b/boards/xtensa/esp32s2_lolin_mini/esp32s2_lolin_mini.dts @@ -25,6 +25,7 @@ zephyr,console = &uart0; zephyr,shell-uart = &uart0; zephyr,flash = &flash0; + zephyr,code-partition = &slot0_partition; }; leds { diff --git a/boards/xtensa/esp32s2_saola/esp32s2_saola.dts b/boards/xtensa/esp32s2_saola/esp32s2_saola.dts index 7a5c4fb087a..61787f0051a 100644 --- a/boards/xtensa/esp32s2_saola/esp32s2_saola.dts +++ b/boards/xtensa/esp32s2_saola/esp32s2_saola.dts @@ -25,6 +25,7 @@ zephyr,console = &uart0; zephyr,shell-uart = &uart0; zephyr,flash = &flash0; + zephyr,code-partition = &slot0_partition; }; gpio_keys { diff --git a/boards/xtensa/esp32s3_devkitm/esp32s3_devkitm.dts b/boards/xtensa/esp32s3_devkitm/esp32s3_devkitm.dts index f7c75b12017..5d80b0619e9 100644 --- a/boards/xtensa/esp32s3_devkitm/esp32s3_devkitm.dts +++ b/boards/xtensa/esp32s3_devkitm/esp32s3_devkitm.dts @@ -23,6 +23,7 @@ zephyr,console = &uart0; zephyr,shell-uart = &uart0; zephyr,flash = &flash0; + zephyr,code-partition = &slot0_partition; }; aliases { diff --git a/boards/xtensa/esp32s3_luatos_core/esp32s3_luatos_core.dts b/boards/xtensa/esp32s3_luatos_core/esp32s3_luatos_core.dts index 89bebe9018c..fea76fca3b7 100644 --- a/boards/xtensa/esp32s3_luatos_core/esp32s3_luatos_core.dts +++ b/boards/xtensa/esp32s3_luatos_core/esp32s3_luatos_core.dts @@ -25,5 +25,6 @@ zephyr,console = &uart0; zephyr,shell-uart = &uart0; zephyr,flash = &flash0; + zephyr,code-partition = &slot0_partition; }; }; diff --git a/boards/xtensa/esp_wrover_kit/esp_wrover_kit.dts b/boards/xtensa/esp_wrover_kit/esp_wrover_kit.dts index 54ded2ac1b3..f5d366e0313 100644 --- a/boards/xtensa/esp_wrover_kit/esp_wrover_kit.dts +++ b/boards/xtensa/esp_wrover_kit/esp_wrover_kit.dts @@ -32,6 +32,7 @@ zephyr,console = &uart0; zephyr,shell-uart = &uart0; zephyr,flash = &flash0; + zephyr,code-partition = &slot0_partition; zephyr,display = &ili9341; }; diff --git a/boards/xtensa/heltec_wifi_lora32_v2/heltec_wifi_lora32_v2.dts b/boards/xtensa/heltec_wifi_lora32_v2/heltec_wifi_lora32_v2.dts index 5fd323082a3..636f1afd354 100644 --- a/boards/xtensa/heltec_wifi_lora32_v2/heltec_wifi_lora32_v2.dts +++ b/boards/xtensa/heltec_wifi_lora32_v2/heltec_wifi_lora32_v2.dts @@ -54,6 +54,7 @@ zephyr,console = &uart0; zephyr,shell-uart = &uart0; zephyr,flash = &flash0; + zephyr,code-partition = &slot0_partition; }; }; diff --git a/boards/xtensa/heltec_wireless_stick_lite_v3/heltec_wireless_stick_lite_v3.dts b/boards/xtensa/heltec_wireless_stick_lite_v3/heltec_wireless_stick_lite_v3.dts index c91564a303f..9a23a008c2f 100644 --- a/boards/xtensa/heltec_wireless_stick_lite_v3/heltec_wireless_stick_lite_v3.dts +++ b/boards/xtensa/heltec_wireless_stick_lite_v3/heltec_wireless_stick_lite_v3.dts @@ -71,6 +71,7 @@ zephyr,console = &uart0; zephyr,shell-uart = &uart0; zephyr,flash = &flash0; + zephyr,code-partition = &slot0_partition; }; }; diff --git a/boards/xtensa/m5stack_atoms3/m5stack_atoms3.dts b/boards/xtensa/m5stack_atoms3/m5stack_atoms3.dts index abbff8bbbfd..72ebd81b42f 100644 --- a/boards/xtensa/m5stack_atoms3/m5stack_atoms3.dts +++ b/boards/xtensa/m5stack_atoms3/m5stack_atoms3.dts @@ -19,6 +19,7 @@ zephyr,console = &usb_serial; zephyr,shell-uart = &usb_serial; zephyr,flash = &flash0; + zephyr,code-partition = &slot0_partition; zephyr,display = &st7789v; }; diff --git a/boards/xtensa/m5stickc_plus/m5stickc_plus.dts b/boards/xtensa/m5stickc_plus/m5stickc_plus.dts index 8cdd4170ba5..6737973adae 100644 --- a/boards/xtensa/m5stickc_plus/m5stickc_plus.dts +++ b/boards/xtensa/m5stickc_plus/m5stickc_plus.dts @@ -27,6 +27,7 @@ zephyr,console = &uart0; zephyr,shell-uart = &uart0; zephyr,flash = &flash0; + zephyr,code-partition = &slot0_partition; }; leds { diff --git a/boards/xtensa/odroid_go/odroid_go.dts b/boards/xtensa/odroid_go/odroid_go.dts index 0a868adc2a3..458a8251b1c 100644 --- a/boards/xtensa/odroid_go/odroid_go.dts +++ b/boards/xtensa/odroid_go/odroid_go.dts @@ -18,6 +18,7 @@ zephyr,console = &uart0; zephyr,shell-uart = &uart0; zephyr,flash = &flash0; + zephyr,code-partition = &slot0_partition; zephyr,display = &ili9341; }; diff --git a/boards/xtensa/olimex_esp32_evb/olimex_esp32_evb.dts b/boards/xtensa/olimex_esp32_evb/olimex_esp32_evb.dts index 0abf7d7128e..11747f1a7b6 100644 --- a/boards/xtensa/olimex_esp32_evb/olimex_esp32_evb.dts +++ b/boards/xtensa/olimex_esp32_evb/olimex_esp32_evb.dts @@ -19,6 +19,7 @@ zephyr,shell-uart = &uart0; zephyr,sram = &sram0; zephyr,flash = &flash0; + zephyr,code-partition = &slot0_partition; }; aliases { diff --git a/boards/xtensa/xiao_esp32s3/xiao_esp32s3.dts b/boards/xtensa/xiao_esp32s3/xiao_esp32s3.dts index ecd7814bb6b..a4592b26bce 100644 --- a/boards/xtensa/xiao_esp32s3/xiao_esp32s3.dts +++ b/boards/xtensa/xiao_esp32s3/xiao_esp32s3.dts @@ -19,6 +19,7 @@ zephyr,console = &usb_serial; zephyr,shell-uart = &usb_serial; zephyr,flash = &flash0; + zephyr,code-partition = &slot0_partition; }; aliases { diff --git a/boards/xtensa/yd_esp32/yd_esp32.dts b/boards/xtensa/yd_esp32/yd_esp32.dts index 3995788beb2..9442e5009e4 100644 --- a/boards/xtensa/yd_esp32/yd_esp32.dts +++ b/boards/xtensa/yd_esp32/yd_esp32.dts @@ -34,6 +34,7 @@ zephyr,console = &uart0; zephyr,shell-uart = &uart0; zephyr,flash = &flash0; + zephyr,code-partition = &slot0_partition; }; }; From 86cf5829a49085a3a58426054cce5639833810ff Mon Sep 17 00:00:00 2001 From: Martin Gritzan Date: Wed, 22 Nov 2023 09:25:37 +0100 Subject: [PATCH 0174/3723] dts: arm: stm32: add stm32f303xb bindings The STM32F303xB is very similar to the xC, the only difference being the RAM and flash sizes. Signed-off-by: Martin Gritzan --- dts/arm/st/f3/stm32f303Xb.dtsi | 45 +++++++++++++++++++ dts/arm/st/f3/stm32f303Xc.dtsi | 43 +++--------------- .../stm32f3/Kconfig.defconfig.stm32f303x(b-c) | 16 +++++++ .../stm32f3/Kconfig.defconfig.stm32f303xc | 14 ------ soc/arm/st_stm32/stm32f3/Kconfig.soc | 4 ++ 5 files changed, 72 insertions(+), 50 deletions(-) create mode 100644 dts/arm/st/f3/stm32f303Xb.dtsi create mode 100644 soc/arm/st_stm32/stm32f3/Kconfig.defconfig.stm32f303x(b-c) delete mode 100644 soc/arm/st_stm32/stm32f3/Kconfig.defconfig.stm32f303xc diff --git a/dts/arm/st/f3/stm32f303Xb.dtsi b/dts/arm/st/f3/stm32f303Xb.dtsi new file mode 100644 index 00000000000..040566c0b22 --- /dev/null +++ b/dts/arm/st/f3/stm32f303Xb.dtsi @@ -0,0 +1,45 @@ +/* + * Copyright (c) 2023 Martin Gritzan + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include +#include + +/ { + ccm0: memory@10000000 { + compatible = "zephyr,memory-region", "st,stm32-ccm"; + reg = <0x10000000 DT_SIZE_K(8)>; + zephyr,memory-region = "CCM"; + }; + + sram0: memory@20000000 { + reg = <0x20000000 DT_SIZE_K(32)>; + }; + + soc { + flash-controller@40022000 { + flash0: flash@8000000 { + reg = <0x08000000 DT_SIZE_K(128)>; + }; + }; + + dma2: dma@40020400 { + compatible = "st,stm32-dma-v2bis"; + #dma-cells = <2>; + reg = <0x40020400 0x400>; + clocks = <&rcc STM32_CLOCK_BUS_AHB1 0x2>; + interrupts = <56 0 57 0 58 0 59 0 60 0>; + status = "disabled"; + }; + + rtc@40002800 { + bbram: backup_regs { + compatible = "st,stm32-bbram"; + st,backup-regs = <16>; + status = "disabled"; + }; + }; + }; +}; diff --git a/dts/arm/st/f3/stm32f303Xc.dtsi b/dts/arm/st/f3/stm32f303Xc.dtsi index fd857c1a8fd..76131f72349 100644 --- a/dts/arm/st/f3/stm32f303Xc.dtsi +++ b/dts/arm/st/f3/stm32f303Xc.dtsi @@ -1,45 +1,16 @@ /* - * Copyright (c) 2018 Linaro Limited + * Copyright (c) 2023 Martin Gritzan * * SPDX-License-Identifier: Apache-2.0 */ #include -#include +#include -/ { - ccm0: memory@10000000 { - compatible = "zephyr,memory-region", "st,stm32-ccm"; - reg = <0x10000000 DT_SIZE_K(8)>; - zephyr,memory-region = "CCM"; - }; - - sram0: memory@20000000 { - reg = <0x20000000 DT_SIZE_K(40)>; - }; - - soc { - flash-controller@40022000 { - flash0: flash@8000000 { - reg = <0x08000000 DT_SIZE_K(256)>; - }; - }; - - dma2: dma@40020400 { - compatible = "st,stm32-dma-v2bis"; - #dma-cells = <2>; - reg = <0x40020400 0x400>; - clocks = <&rcc STM32_CLOCK_BUS_AHB1 0x2>; - interrupts = <56 0 57 0 58 0 59 0 60 0>; - status = "disabled"; - }; +&sram0 { + reg = <0x20000000 DT_SIZE_K(40)>; +}; - rtc@40002800 { - bbram: backup_regs { - compatible = "st,stm32-bbram"; - st,backup-regs = <16>; - status = "disabled"; - }; - }; - }; +&flash0 { + reg = <0x08000000 DT_SIZE_K(256)>; }; diff --git a/soc/arm/st_stm32/stm32f3/Kconfig.defconfig.stm32f303x(b-c) b/soc/arm/st_stm32/stm32f3/Kconfig.defconfig.stm32f303x(b-c) new file mode 100644 index 00000000000..752bef89690 --- /dev/null +++ b/soc/arm/st_stm32/stm32f3/Kconfig.defconfig.stm32f303x(b-c) @@ -0,0 +1,16 @@ +# ST Microelectronics STM32F303XC MCU + +# Copyright (c) 2016 RnDity Sp. z o.o. +# SPDX-License-Identifier: Apache-2.0 + +# The HAL expects STM32F302XC to be defined for both the xB and xC variants (only RAM- and Flash- +# size differ). +if SOC_STM32F303XB || SOC_STM32F303XC + +config SOC + default "stm32f303xc" + +config NUM_IRQS + default 82 + +endif # SOC_STM32F303XB || SOC_STM32F303XC diff --git a/soc/arm/st_stm32/stm32f3/Kconfig.defconfig.stm32f303xc b/soc/arm/st_stm32/stm32f3/Kconfig.defconfig.stm32f303xc deleted file mode 100644 index 875ed373a69..00000000000 --- a/soc/arm/st_stm32/stm32f3/Kconfig.defconfig.stm32f303xc +++ /dev/null @@ -1,14 +0,0 @@ -# ST Microelectronics STM32F303XC MCU - -# Copyright (c) 2016 RnDity Sp. z o.o. -# SPDX-License-Identifier: Apache-2.0 - -if SOC_STM32F303XC - -config SOC - default "stm32f303xc" - -config NUM_IRQS - default 82 - -endif # SOC_STM32F303XC diff --git a/soc/arm/st_stm32/stm32f3/Kconfig.soc b/soc/arm/st_stm32/stm32f3/Kconfig.soc index 6dde4dfd8cf..20af2538ba5 100644 --- a/soc/arm/st_stm32/stm32f3/Kconfig.soc +++ b/soc/arm/st_stm32/stm32f3/Kconfig.soc @@ -17,6 +17,10 @@ config SOC_STM32F302XC config SOC_STM32F303X8 bool "STM32F303X8" +config SOC_STM32F303XB + bool "STM32F303XB" + select CPU_HAS_ARM_MPU + config SOC_STM32F303XC bool "STM32F303XC" select CPU_HAS_ARM_MPU From 0bad09c7faec98ccfb01326896fc3032f466147c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?J=C4=99drzej=20Ciupis?= Date: Wed, 22 Nov 2023 09:56:03 +0100 Subject: [PATCH 0175/3723] drivers: ieee802154: nrf5: support raw mode MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit When CONFIG_IEEE802154_RAW_MODE is set there is no network interface that could provide pointer to the device the interface is running on top of. The current implementation of nRF5 ieee802154 driver implicitly assumes that such an interface is always present, which leads to crashes when raw mode is enabled. This commit adds support for IEEE802154_RAW_MODE in nRF5 ieee802154 driver by latching pointer to the ieee802154 device on initialization if needed so that it doesn't have to be retrieved using the network interface in run-time. Signed-off-by: Jędrzej Ciupis --- drivers/ieee802154/ieee802154_nrf5.c | 21 ++++++++++++++++++--- 1 file changed, 18 insertions(+), 3 deletions(-) diff --git a/drivers/ieee802154/ieee802154_nrf5.c b/drivers/ieee802154/ieee802154_nrf5.c index 2b7d9b8fb6d..dd32f633364 100644 --- a/drivers/ieee802154/ieee802154_nrf5.c +++ b/drivers/ieee802154/ieee802154_nrf5.c @@ -57,6 +57,9 @@ struct nrf5_802154_config { }; static struct nrf5_802154_data nrf5_data; +#if defined(CONFIG_IEEE802154_RAW_MODE) +static const struct device *nrf5_dev; +#endif #define DRX_SLOT_RX 0 /* Delayed reception window ID */ @@ -95,6 +98,15 @@ static struct nrf5_802154_data nrf5_data; #define IEEE802154_NRF5_VENDOR_OUI (uint32_t)0xF4CE36 #endif +static inline const struct device *nrf5_get_device(void) +{ +#if defined(CONFIG_IEEE802154_RAW_MODE) + return nrf5_dev; +#else + return net_if_get_device(nrf5_data.iface); +#endif +} + static void nrf5_get_eui64(uint8_t *mac) { uint64_t factoryAddress; @@ -726,6 +738,9 @@ static int nrf5_init(const struct device *dev) { const struct nrf5_802154_config *nrf5_radio_cfg = NRF5_802154_CFG(dev); struct nrf5_802154_data *nrf5_radio = NRF5_802154_DATA(dev); +#if defined(CONFIG_IEEE802154_RAW_MODE) + nrf5_dev = dev; +#endif k_fifo_init(&nrf5_radio->rx_fifo); k_sem_init(&nrf5_radio->tx_wait, 0, 1); @@ -1046,7 +1061,7 @@ void nrf_802154_received_timestamp_raw(uint8_t *data, int8_t power, uint8_t lqi, void nrf_802154_receive_failed(nrf_802154_rx_error_t error, uint32_t id) { - const struct device *dev = net_if_get_device(nrf5_data.iface); + const struct device *dev = nrf5_get_device(); #if defined(CONFIG_IEEE802154_CSL_ENDPOINT) if (id == DRX_SLOT_RX) { @@ -1165,7 +1180,7 @@ void nrf_802154_energy_detected(const nrf_802154_energy_detected_t *result) energy_scan_done_cb_t callback = nrf5_data.energy_scan_done; nrf5_data.energy_scan_done = NULL; - callback(net_if_get_device(nrf5_data.iface), result->ed_dbm); + callback(nrf5_get_device(), result->ed_dbm); } } @@ -1175,7 +1190,7 @@ void nrf_802154_energy_detection_failed(nrf_802154_ed_error_t error) energy_scan_done_cb_t callback = nrf5_data.energy_scan_done; nrf5_data.energy_scan_done = NULL; - callback(net_if_get_device(nrf5_data.iface), SHRT_MAX); + callback(nrf5_get_device(), SHRT_MAX); } } From 1378c90a938e651bd3f000505d3388a4134f2a9f Mon Sep 17 00:00:00 2001 From: Arnaud MAZIN Date: Wed, 22 Nov 2023 10:07:21 +0100 Subject: [PATCH 0176/3723] driver: display: sdl: Introduce SDL_DISPLAY_ZOOM_PCT This option modifies SDL window size and help with readability of very small screens Signed-off-by: Arnaud MAZIN --- drivers/display/Kconfig.sdl | 7 +++++++ drivers/display/display_sdl.c | 6 ++++-- drivers/display/display_sdl_bottom.c | 6 +++--- drivers/display/display_sdl_bottom.h | 2 +- 4 files changed, 15 insertions(+), 6 deletions(-) diff --git a/drivers/display/Kconfig.sdl b/drivers/display/Kconfig.sdl index a06b143f31e..5bf18115a33 100644 --- a/drivers/display/Kconfig.sdl +++ b/drivers/display/Kconfig.sdl @@ -39,4 +39,11 @@ choice SDL_DISPLAY_DEFAULT_PIXEL_FORMAT endchoice +config SDL_DISPLAY_ZOOM_PCT + int "Default zoom percentage" + default 100 + range 10 10000 + help + SDL window zoom percentage to adjust readability on small screens + endif # SDL_DISPLAY diff --git a/drivers/display/display_sdl.c b/drivers/display/display_sdl.c index 2a457249ede..b813ee34872 100644 --- a/drivers/display/display_sdl.c +++ b/drivers/display/display_sdl.c @@ -54,8 +54,10 @@ static int sdl_display_init(const struct device *dev) #endif /* SDL_DISPLAY_DEFAULT_PIXEL_FORMAT */ ; - int rc = sdl_display_init_bottom(config->height, config->width, &disp_data->window, - &disp_data->renderer, &disp_data->texture); + int rc = sdl_display_init_bottom(config->height, config->width, + CONFIG_SDL_DISPLAY_ZOOM_PCT, + &disp_data->window, &disp_data->renderer, + &disp_data->texture); if (rc != 0) { LOG_ERR("Failed to create SDL display"); diff --git a/drivers/display/display_sdl_bottom.c b/drivers/display/display_sdl_bottom.c index a7ad1929f4e..92c09f36fcd 100644 --- a/drivers/display/display_sdl_bottom.c +++ b/drivers/display/display_sdl_bottom.c @@ -11,12 +11,12 @@ #include #include "nsi_tracing.h" -int sdl_display_init_bottom(uint16_t height, uint16_t width, +int sdl_display_init_bottom(uint16_t height, uint16_t width, uint16_t zoom_pct, void **window, void **renderer, void **texture) { *window = SDL_CreateWindow("Zephyr Display", SDL_WINDOWPOS_UNDEFINED, - SDL_WINDOWPOS_UNDEFINED, width, - height, SDL_WINDOW_SHOWN); + SDL_WINDOWPOS_UNDEFINED, width * zoom_pct / 100, + height * zoom_pct / 100, SDL_WINDOW_SHOWN); if (*window == NULL) { nsi_print_warning("Failed to create SDL window: %s", SDL_GetError()); return -1; diff --git a/drivers/display/display_sdl_bottom.h b/drivers/display/display_sdl_bottom.h index 91ea890c13b..d60c8b15f40 100644 --- a/drivers/display/display_sdl_bottom.h +++ b/drivers/display/display_sdl_bottom.h @@ -20,7 +20,7 @@ extern "C" { /* Note: None of these functions are public interfaces. But internal to the SDL display driver */ -int sdl_display_init_bottom(uint16_t height, uint16_t width, +int sdl_display_init_bottom(uint16_t height, uint16_t width, uint16_t zoom_pct, void **window, void **renderer, void **texture); void sdl_display_write_bottom(const uint16_t height, const uint16_t width, const uint16_t x, const uint16_t y, From d1fc5fe2aeb20bcecfe55734be3c989c220ed56f Mon Sep 17 00:00:00 2001 From: Yong Cong Sin Date: Wed, 22 Nov 2023 18:12:06 +0800 Subject: [PATCH 0177/3723] boards: riscv: hifive_unmatched: add Renode simulation support Add Renode simulation support for `hifive_unmatched`, the script is basically copied over from `hifive_unleashed`, with very minor edits. Signed-off-by: Yong Cong Sin --- boards/riscv/hifive_unmatched/board.cmake | 4 +++ .../support/hifive_unmatched.resc | 25 +++++++++++++++++++ 2 files changed, 29 insertions(+) create mode 100644 boards/riscv/hifive_unmatched/support/hifive_unmatched.resc diff --git a/boards/riscv/hifive_unmatched/board.cmake b/boards/riscv/hifive_unmatched/board.cmake index c985f2d7bca..56fe497dd2a 100644 --- a/boards/riscv/hifive_unmatched/board.cmake +++ b/boards/riscv/hifive_unmatched/board.cmake @@ -1,5 +1,9 @@ # SPDX-License-Identifier: Apache-2.0 +set(SUPPORTED_EMU_PLATFORMS renode) +set(RENODE_SCRIPT ${CMAKE_CURRENT_LIST_DIR}/support/hifive_unmatched.resc) +set(RENODE_UART sysbus.uart0) + set(OPENOCD_USE_LOAD_IMAGE NO) board_runner_args(openocd "--config=${BOARD_DIR}/support/openocd_hifive_unmatched.cfg") diff --git a/boards/riscv/hifive_unmatched/support/hifive_unmatched.resc b/boards/riscv/hifive_unmatched/support/hifive_unmatched.resc new file mode 100644 index 00000000000..535bb06c69c --- /dev/null +++ b/boards/riscv/hifive_unmatched/support/hifive_unmatched.resc @@ -0,0 +1,25 @@ +:description: This script is prepared to run Zephyr on SiFive-FU740 board. +:name: SiFive-FU740 + +$name?="SiFive-FU740" + +using sysbus +mach create $name + +set platform +""" +using "platforms/cpus/sifive-fu740.repl" + +clint: + frequency: 10000000 +""" + +machine LoadPlatformDescriptionFromString $platform +machine PyDevFromFile @scripts/pydev/flipflop.py 0x10000000 0x100 True +showAnalyzer uart0 + +macro reset +""" + sysbus LoadELF $bin +""" +runMacro $reset From b39816a1117157733ff64b213184e74d6bf45194 Mon Sep 17 00:00:00 2001 From: Wojciech Slenska Date: Wed, 22 Nov 2023 14:00:54 +0100 Subject: [PATCH 0178/3723] drivers: i2c: stm32: fix compilation for PM_DEVICE_RUNTIME Added clk variable which is needed when CONFIG_PM_DEVICE_RUNTIME is enabled. Signed-off-by: Wojciech Slenska --- drivers/i2c/i2c_ll_stm32.c | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/drivers/i2c/i2c_ll_stm32.c b/drivers/i2c/i2c_ll_stm32.c index 2fcb1f8e931..552acfb6ab2 100644 --- a/drivers/i2c/i2c_ll_stm32.c +++ b/drivers/i2c/i2c_ll_stm32.c @@ -62,20 +62,19 @@ int i2c_stm32_runtime_configure(const struct device *dev, uint32_t config) { const struct i2c_stm32_config *cfg = dev->config; struct i2c_stm32_data *data = dev->data; + const struct device *clk = DEVICE_DT_GET(STM32_CLOCK_CONTROL_NODE); I2C_TypeDef *i2c = cfg->i2c; uint32_t i2c_clock = 0U; int ret; if (IS_ENABLED(STM32_I2C_DOMAIN_CLOCK_SUPPORT) && (cfg->pclk_len > 1)) { - if (clock_control_get_rate(DEVICE_DT_GET(STM32_CLOCK_CONTROL_NODE), - (clock_control_subsys_t)&cfg->pclken[1], + if (clock_control_get_rate(clk, (clock_control_subsys_t)&cfg->pclken[1], &i2c_clock) < 0) { LOG_ERR("Failed call clock_control_get_rate(pclken[1])"); return -EIO; } } else { - if (clock_control_get_rate(DEVICE_DT_GET(STM32_CLOCK_CONTROL_NODE), - (clock_control_subsys_t) &cfg->pclken[0], + if (clock_control_get_rate(clk, (clock_control_subsys_t)&cfg->pclken[0], &i2c_clock) < 0) { LOG_ERR("Failed call clock_control_get_rate(pclken[0])"); return -EIO; From 60dc8dd410de079cce76f6708f5afa2422811095 Mon Sep 17 00:00:00 2001 From: Wojciech Sipak Date: Wed, 22 Nov 2023 14:37:03 +0100 Subject: [PATCH 0179/3723] boards: Use unique names for boards in the YAML files There are duplicated names specified in per-board YAML files. This change will allow distinguishing boards in software that presents the pretty names and not the raw names of boards. Signed-off-by: Wojciech Sipak --- boards/arc/emsdp/emsdp.yaml | 2 +- boards/arc/emsdp/emsdp_em4.yaml | 2 +- boards/arc/emsdp/emsdp_em5d.yaml | 2 +- boards/arc/emsdp/emsdp_em6.yaml | 2 +- boards/arc/emsdp/emsdp_em7d.yaml | 2 +- boards/arc/emsdp/emsdp_em7d_esp.yaml | 2 +- boards/arc/emsdp/emsdp_em9d.yaml | 2 +- boards/arc/nsim/nsim_em7d_v22.yaml | 2 +- boards/arc/nsim/nsim_hs5x_smp_12cores.yaml | 2 +- boards/arc/nsim/nsim_hs6x_smp_12cores.yaml | 2 +- boards/arc/nsim/nsim_hs_flash_xip.yaml | 2 +- boards/arc/nsim/nsim_hs_sram.yaml | 2 +- boards/arc/nsim/nsim_sem_mpu_stack_guard.yaml | 2 +- boards/arc/qemu_arc/qemu_arc_hs6x.yaml | 2 +- boards/arc/qemu_arc/qemu_arc_hs_xip.yaml | 2 +- .../fvp_baser_aemv8r_aarch32/fvp_baser_aemv8r_aarch32_smp.yaml | 2 +- boards/arm/s32z270dc2_r52/s32z270dc2_rtu0_r52_D.yaml | 2 +- boards/arm/s32z270dc2_r52/s32z270dc2_rtu1_r52_D.yaml | 2 +- .../fvp_base_revc_2xaemv8a/fvp_base_revc_2xaemv8a_smp_ns.yaml | 2 +- boards/arm64/fvp_baser_aemv8r/fvp_baser_aemv8r_smp.yaml | 2 +- boards/mips/qemu_malta/qemu_malta.yaml | 2 +- boards/mips/qemu_malta/qemu_malta_be.yaml | 2 +- 22 files changed, 22 insertions(+), 22 deletions(-) diff --git a/boards/arc/emsdp/emsdp.yaml b/boards/arc/emsdp/emsdp.yaml index b6fa38fb515..c5a9afc8da4 100644 --- a/boards/arc/emsdp/emsdp.yaml +++ b/boards/arc/emsdp/emsdp.yaml @@ -1,5 +1,5 @@ identifier: emsdp -name: EM Software Development Platform +name: EM Software Development Platform (EM11D) type: mcu arch: arc toolchain: diff --git a/boards/arc/emsdp/emsdp_em4.yaml b/boards/arc/emsdp/emsdp_em4.yaml index a146eb72bff..9be5bbca31b 100644 --- a/boards/arc/emsdp/emsdp_em4.yaml +++ b/boards/arc/emsdp/emsdp_em4.yaml @@ -1,5 +1,5 @@ identifier: emsdp_em4 -name: EM Software Development Platform +name: EM Software Development Platform (EM4) type: mcu arch: arc toolchain: diff --git a/boards/arc/emsdp/emsdp_em5d.yaml b/boards/arc/emsdp/emsdp_em5d.yaml index d0117790975..80cbc08e066 100644 --- a/boards/arc/emsdp/emsdp_em5d.yaml +++ b/boards/arc/emsdp/emsdp_em5d.yaml @@ -1,5 +1,5 @@ identifier: emsdp_em5d -name: EM Software Development Platform +name: EM Software Development Platform (EM5D) type: mcu arch: arc toolchain: diff --git a/boards/arc/emsdp/emsdp_em6.yaml b/boards/arc/emsdp/emsdp_em6.yaml index 2584fb8a953..ce15754d7be 100644 --- a/boards/arc/emsdp/emsdp_em6.yaml +++ b/boards/arc/emsdp/emsdp_em6.yaml @@ -1,5 +1,5 @@ identifier: emsdp_em6 -name: EM Software Development Platform +name: EM Software Development Platform (EM6) type: mcu arch: arc toolchain: diff --git a/boards/arc/emsdp/emsdp_em7d.yaml b/boards/arc/emsdp/emsdp_em7d.yaml index 57f78c3c7e7..e3591d300f5 100644 --- a/boards/arc/emsdp/emsdp_em7d.yaml +++ b/boards/arc/emsdp/emsdp_em7d.yaml @@ -1,5 +1,5 @@ identifier: emsdp_em7d -name: EM Software Development Platform +name: EM Software Development Platform (EM7D) type: mcu arch: arc toolchain: diff --git a/boards/arc/emsdp/emsdp_em7d_esp.yaml b/boards/arc/emsdp/emsdp_em7d_esp.yaml index e3387d64798..2b8cc296bb8 100644 --- a/boards/arc/emsdp/emsdp_em7d_esp.yaml +++ b/boards/arc/emsdp/emsdp_em7d_esp.yaml @@ -1,5 +1,5 @@ identifier: emsdp_em7d_esp -name: EM Software Development Platform +name: EM Software Development Platform (EM7D_ESP) type: mcu arch: arc toolchain: diff --git a/boards/arc/emsdp/emsdp_em9d.yaml b/boards/arc/emsdp/emsdp_em9d.yaml index 7bdf0340232..f20f29d18d0 100644 --- a/boards/arc/emsdp/emsdp_em9d.yaml +++ b/boards/arc/emsdp/emsdp_em9d.yaml @@ -1,5 +1,5 @@ identifier: emsdp_em9d -name: EM Software Development Platform +name: EM Software Development Platform (EM9D) type: mcu arch: arc toolchain: diff --git a/boards/arc/nsim/nsim_em7d_v22.yaml b/boards/arc/nsim/nsim_em7d_v22.yaml index 036e9b37bae..bd2069c8359 100644 --- a/boards/arc/nsim/nsim_em7d_v22.yaml +++ b/boards/arc/nsim/nsim_em7d_v22.yaml @@ -1,5 +1,5 @@ identifier: nsim_em7d_v22 -name: EM Nsim simulator +name: EM nSIM simulator (EM7D_v22) type: sim simulation: nsim simulation_exec: nsimdrv diff --git a/boards/arc/nsim/nsim_hs5x_smp_12cores.yaml b/boards/arc/nsim/nsim_hs5x_smp_12cores.yaml index 416dcd2133d..f7f9fa1ec72 100644 --- a/boards/arc/nsim/nsim_hs5x_smp_12cores.yaml +++ b/boards/arc/nsim/nsim_hs5x_smp_12cores.yaml @@ -1,5 +1,5 @@ identifier: nsim_hs5x_smp_12cores -name: Multi-core HS5x nSIM simulator +name: Multi-core HS5x nSIM simulator (12 cores) type: sim simulation: mdb-nsim simulation_exec: mdb diff --git a/boards/arc/nsim/nsim_hs6x_smp_12cores.yaml b/boards/arc/nsim/nsim_hs6x_smp_12cores.yaml index 3113b84e8d6..9abea29aabc 100644 --- a/boards/arc/nsim/nsim_hs6x_smp_12cores.yaml +++ b/boards/arc/nsim/nsim_hs6x_smp_12cores.yaml @@ -1,5 +1,5 @@ identifier: nsim_hs6x_smp_12cores -name: Multi-core HS6x nSIM simulator +name: Multi-core HS6x nSIM simulator (12 cores) type: sim simulation: mdb-nsim simulation_exec: mdb diff --git a/boards/arc/nsim/nsim_hs_flash_xip.yaml b/boards/arc/nsim/nsim_hs_flash_xip.yaml index 02da85f5864..eabe0c9cd84 100644 --- a/boards/arc/nsim/nsim_hs_flash_xip.yaml +++ b/boards/arc/nsim/nsim_hs_flash_xip.yaml @@ -1,5 +1,5 @@ identifier: nsim_hs_flash_xip -name: HS nSIM simulator +name: HS nSIM simulator (FLASH XIP) type: sim simulation: nsim simulation_exec: nsimdrv diff --git a/boards/arc/nsim/nsim_hs_sram.yaml b/boards/arc/nsim/nsim_hs_sram.yaml index 7a99a91ceff..cfbf02d6023 100644 --- a/boards/arc/nsim/nsim_hs_sram.yaml +++ b/boards/arc/nsim/nsim_hs_sram.yaml @@ -1,5 +1,5 @@ identifier: nsim_hs_sram -name: HS nSIM simulator +name: HS nSIM simulator (SRAM) type: sim simulation: nsim simulation_exec: nsimdrv diff --git a/boards/arc/nsim/nsim_sem_mpu_stack_guard.yaml b/boards/arc/nsim/nsim_sem_mpu_stack_guard.yaml index 45949212a00..13a48179fd5 100644 --- a/boards/arc/nsim/nsim_sem_mpu_stack_guard.yaml +++ b/boards/arc/nsim/nsim_sem_mpu_stack_guard.yaml @@ -1,5 +1,5 @@ identifier: nsim_sem_mpu_stack_guard -name: SEM Nsim simulator +name: SEM nSIM simulator (stack guard) type: sim arch: arc simulation: nsim diff --git a/boards/arc/qemu_arc/qemu_arc_hs6x.yaml b/boards/arc/qemu_arc/qemu_arc_hs6x.yaml index 5346dbc1251..ed5425cc565 100644 --- a/boards/arc/qemu_arc/qemu_arc_hs6x.yaml +++ b/boards/arc/qemu_arc/qemu_arc_hs6x.yaml @@ -1,5 +1,5 @@ identifier: qemu_arc_hs6x -name: QEMU Emulation for ARC HS +name: QEMU Emulation for ARC HS6x type: qemu simulation: qemu arch: arc diff --git a/boards/arc/qemu_arc/qemu_arc_hs_xip.yaml b/boards/arc/qemu_arc/qemu_arc_hs_xip.yaml index 829045078d2..4f7b9cee45d 100644 --- a/boards/arc/qemu_arc/qemu_arc_hs_xip.yaml +++ b/boards/arc/qemu_arc/qemu_arc_hs_xip.yaml @@ -1,5 +1,5 @@ identifier: qemu_arc_hs_xip -name: QEMU Emulation for ARC HS +name: QEMU Emulation for ARC HS (XIP) type: qemu simulation: qemu arch: arc diff --git a/boards/arm/fvp_baser_aemv8r_aarch32/fvp_baser_aemv8r_aarch32_smp.yaml b/boards/arm/fvp_baser_aemv8r_aarch32/fvp_baser_aemv8r_aarch32_smp.yaml index 08d01e51ec4..0ecd14f9076 100644 --- a/boards/arm/fvp_baser_aemv8r_aarch32/fvp_baser_aemv8r_aarch32_smp.yaml +++ b/boards/arm/fvp_baser_aemv8r_aarch32/fvp_baser_aemv8r_aarch32_smp.yaml @@ -2,7 +2,7 @@ # SPDX-License-Identifier: Apache-2.0 identifier: fvp_baser_aemv8r_aarch32_smp -name: FVP Emulation FVP_BaseR_AEMv8R AArch32 +name: FVP Emulation FVP_BaseR_AEMv8R AArch32 (SMP) arch: arm type: sim toolchain: diff --git a/boards/arm/s32z270dc2_r52/s32z270dc2_rtu0_r52_D.yaml b/boards/arm/s32z270dc2_r52/s32z270dc2_rtu0_r52_D.yaml index 063ea90c351..481ce3e63b2 100644 --- a/boards/arm/s32z270dc2_r52/s32z270dc2_rtu0_r52_D.yaml +++ b/boards/arm/s32z270dc2_r52/s32z270dc2_rtu0_r52_D.yaml @@ -2,7 +2,7 @@ # SPDX-License-Identifier: Apache-2.0 identifier: s32z270dc2_rtu0_r52@D -name: NXP X-S32Z270-DC (DC2) on RTU0 Cortex-R52 cores +name: NXP X-S32Z270-DC (DC2) on RTU0 Cortex-R52 cores (rev. D) type: mcu arch: arm ram: 1024 diff --git a/boards/arm/s32z270dc2_r52/s32z270dc2_rtu1_r52_D.yaml b/boards/arm/s32z270dc2_r52/s32z270dc2_rtu1_r52_D.yaml index 70a37261c8e..9f0a55547c1 100644 --- a/boards/arm/s32z270dc2_r52/s32z270dc2_rtu1_r52_D.yaml +++ b/boards/arm/s32z270dc2_r52/s32z270dc2_rtu1_r52_D.yaml @@ -2,7 +2,7 @@ # SPDX-License-Identifier: Apache-2.0 identifier: s32z270dc2_rtu1_r52@D -name: NXP X-S32Z270-DC (DC2) on RTU1 Cortex-R52 cores +name: NXP X-S32Z270-DC (DC2) on RTU1 Cortex-R52 cores (rev. D) type: mcu arch: arm ram: 1024 diff --git a/boards/arm64/fvp_base_revc_2xaemv8a/fvp_base_revc_2xaemv8a_smp_ns.yaml b/boards/arm64/fvp_base_revc_2xaemv8a/fvp_base_revc_2xaemv8a_smp_ns.yaml index 68ef6a664e8..b6e39f0dab3 100644 --- a/boards/arm64/fvp_base_revc_2xaemv8a/fvp_base_revc_2xaemv8a_smp_ns.yaml +++ b/boards/arm64/fvp_base_revc_2xaemv8a/fvp_base_revc_2xaemv8a_smp_ns.yaml @@ -2,7 +2,7 @@ # SPDX-License-Identifier: Apache-2.0 identifier: fvp_base_revc_2xaemv8a_smp_ns -name: FVP Emulation FVP_Base_RevC-2xAEMvA +name: FVP Emulation FVP_Base_RevC-2xAEMvA (SMP) arch: arm64 type: sim toolchain: diff --git a/boards/arm64/fvp_baser_aemv8r/fvp_baser_aemv8r_smp.yaml b/boards/arm64/fvp_baser_aemv8r/fvp_baser_aemv8r_smp.yaml index 1e0dfa4a9b2..ed63f35d101 100644 --- a/boards/arm64/fvp_baser_aemv8r/fvp_baser_aemv8r_smp.yaml +++ b/boards/arm64/fvp_baser_aemv8r/fvp_baser_aemv8r_smp.yaml @@ -2,7 +2,7 @@ # SPDX-License-Identifier: Apache-2.0 identifier: fvp_baser_aemv8r_smp -name: FVP Emulation FVP_BaseR_AEMv8R +name: FVP Emulation FVP_BaseR_AEMv8R (SMP) arch: arm64 type: sim toolchain: diff --git a/boards/mips/qemu_malta/qemu_malta.yaml b/boards/mips/qemu_malta/qemu_malta.yaml index 3749da567ea..083fb0e93b1 100644 --- a/boards/mips/qemu_malta/qemu_malta.yaml +++ b/boards/mips/qemu_malta/qemu_malta.yaml @@ -1,5 +1,5 @@ identifier: qemu_malta -name: QEMU emulation for MIPS +name: QEMU emulation for MIPS (little endian) type: qemu simulation: qemu arch: mips diff --git a/boards/mips/qemu_malta/qemu_malta_be.yaml b/boards/mips/qemu_malta/qemu_malta_be.yaml index 80eab182050..91a9444d00b 100644 --- a/boards/mips/qemu_malta/qemu_malta_be.yaml +++ b/boards/mips/qemu_malta/qemu_malta_be.yaml @@ -1,5 +1,5 @@ identifier: qemu_malta_be -name: QEMU emulation for MIPS +name: QEMU emulation for MIPS (big endian) type: qemu simulation: qemu arch: mips From 3d37549bac90f2008c5e7cfc41ec79c553dbe99a Mon Sep 17 00:00:00 2001 From: Aleksandr Khromykh Date: Wed, 22 Nov 2023 16:24:48 +0100 Subject: [PATCH 0180/3723] Bluetooth: Mesh: allocate mesh max required buffer number Since sending of public key was moved into system work (https://github.com/zephyrproject-rtos/zephyr/pull/62331) it uses the same context as a Host Tx buffer allocator for gatt sending. Host cannot wait for free buffer anymore. Mesh requires 4 buffers to send max size frame(public key) during provisioning. Signed-off-by: Aleksandr Khromykh --- subsys/bluetooth/common/Kconfig | 1 + 1 file changed, 1 insertion(+) diff --git a/subsys/bluetooth/common/Kconfig b/subsys/bluetooth/common/Kconfig index bf4aee75e48..7b6bc839b89 100644 --- a/subsys/bluetooth/common/Kconfig +++ b/subsys/bluetooth/common/Kconfig @@ -33,6 +33,7 @@ config BT_BUF_ACL_TX_SIZE config BT_BUF_ACL_TX_COUNT int "Number of outgoing ACL data buffers" default 7 if BT_HCI_RAW + default 4 if BT_MESH_GATT default 3 range 1 255 help From 108f7bde83c3c0490f8ffd41385212d75fbe93ed Mon Sep 17 00:00:00 2001 From: Jonas Remmert Date: Wed, 22 Nov 2023 16:43:17 +0100 Subject: [PATCH 0181/3723] tests: build_all: sensor: fix i2c duplicate address Fix address for hs300x driver in dts file for test. Signed-off-by: Jonas Remmert --- tests/drivers/build_all/sensor/i2c.dtsi | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/tests/drivers/build_all/sensor/i2c.dtsi b/tests/drivers/build_all/sensor/i2c.dtsi index 6ad5ac8703e..4e79590ce99 100644 --- a/tests/drivers/build_all/sensor/i2c.dtsi +++ b/tests/drivers/build_all/sensor/i2c.dtsi @@ -854,7 +854,7 @@ test_i2c_lps22df: lps22df@79 { avg = ; }; -test_i2c_hs300x: hs300x@79 { +test_i2c_hs300x: hs300x@7a { compatible = "renesas,hs300x"; - reg = <0x79>; + reg = <0x7a>; }; From 20acd64a1bb76ff2504101efb13bf0d1ecd7d058 Mon Sep 17 00:00:00 2001 From: Bartosz Bilas Date: Wed, 22 Nov 2023 19:00:03 +0100 Subject: [PATCH 0182/3723] doc: zbus: fix msg subscriber thread signatures Fix the thread function signatures to match k_thread_entry_t. Signed-off-by: Bartosz Bilas --- doc/services/zbus/index.rst | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/doc/services/zbus/index.rst b/doc/services/zbus/index.rst index 59d45317a7b..6f9378ba5c3 100644 --- a/doc/services/zbus/index.rst +++ b/doc/services/zbus/index.rst @@ -424,8 +424,11 @@ exchanges accelerometer data, for example. K_THREAD_DEFINE(subscriber_task_id, 512, subscriber_task, NULL, NULL, NULL, 3, 0, 0); ZBUS_MSG_SUBSCRIBER_DEFINE(my_msg_subscriber); - static void msg_subscriber_task(void *sub) + static void msg_subscriber_task(void *ptr1, void *ptr2, void *ptr3) { + ARG_UNUSED(ptr1); + ARG_UNUSED(ptr2); + ARG_UNUSED(ptr3); const struct zbus_channel *chan; struct acc_msg acc = {0}; From 13f3c6d0bda59855b8928fb510cb1cd3687c4dce Mon Sep 17 00:00:00 2001 From: Torsten Rasmussen Date: Thu, 23 Nov 2023 12:54:12 +0100 Subject: [PATCH 0183/3723] sysbuild: introduce Kconfig setting for controlling HCI IPC inclusion Follow-up: #64704 Introducing NET_CORE_IMAGE_HCI_IPC Kconfig setting to control inclusion of HCI IPC image when building through sysbuild. This allows users with custom netcore applications to avoid inclusion of the default HCI IPC image. Signed-off-by: Torsten Rasmussen --- samples/bluetooth/broadcast_audio_sink/Kconfig.sysbuild | 5 +++++ samples/bluetooth/broadcast_audio_sink/sysbuild.cmake | 2 +- 2 files changed, 6 insertions(+), 1 deletion(-) diff --git a/samples/bluetooth/broadcast_audio_sink/Kconfig.sysbuild b/samples/bluetooth/broadcast_audio_sink/Kconfig.sysbuild index 37a6b66c7f4..f434010f81d 100644 --- a/samples/bluetooth/broadcast_audio_sink/Kconfig.sysbuild +++ b/samples/bluetooth/broadcast_audio_sink/Kconfig.sysbuild @@ -8,3 +8,8 @@ config NET_CORE_BOARD default "nrf5340dk_nrf5340_cpunet" if $(BOARD) = "nrf5340dk_nrf5340_cpuapp" default "nrf5340_audio_dk_nrf5340_cpunet" if $(BOARD) = "nrf5340_audio_dk_nrf5340_cpuapp" default "nrf5340bsim_nrf5340_cpunet" if $(BOARD) = "nrf5340bsim_nrf5340_cpuapp" + +config NET_CORE_IMAGE_HCI_IPC + bool "HCI IPC image on network core" + default y + depends on NET_CORE_BOARD != "" diff --git a/samples/bluetooth/broadcast_audio_sink/sysbuild.cmake b/samples/bluetooth/broadcast_audio_sink/sysbuild.cmake index c150913cc55..ed30d7f31f3 100644 --- a/samples/bluetooth/broadcast_audio_sink/sysbuild.cmake +++ b/samples/bluetooth/broadcast_audio_sink/sysbuild.cmake @@ -1,7 +1,7 @@ # Copyright (c) 2023 Nordic Semiconductor ASA # SPDX-License-Identifier: Apache-2.0 -if(NOT("${SB_CONFIG_NET_CORE_BOARD}" STREQUAL "")) +if(SB_CONFIG_NET_CORE_IMAGE_HCI_IPC) # For builds in the nrf5340, we build the netcore image with the controller set(NET_APP hci_ipc) From ecb2df0444f10bd21dbdd1220cbe353655cab5cc Mon Sep 17 00:00:00 2001 From: Yong Cong Sin Date: Fri, 24 Nov 2023 11:15:53 +0800 Subject: [PATCH 0184/3723] scripts/checkpatch: add `__unused` to the `$Attribute` list Add `__unused` to the `$Attribute` family along with its `__maybe_unused`, `__always_unused` & `__used` brothers, so that: ```c __unused int ret; ``` is recognized as variable declaration, and doesn't raise `LINE_SPACING` warning in CI. Signed-off-by: Yong Cong Sin --- scripts/checkpatch.pl | 1 + 1 file changed, 1 insertion(+) diff --git a/scripts/checkpatch.pl b/scripts/checkpatch.pl index 544fc4ea0e4..fd82a880c1f 100755 --- a/scripts/checkpatch.pl +++ b/scripts/checkpatch.pl @@ -389,6 +389,7 @@ sub hash_show_words { __always_unused| __noreturn| __used| + __unused| __cold| __pure| __noclone| From 199743de0118077df2183d9bed0f9e322f2cfb6d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Benjamin=20Cab=C3=A9?= Date: Fri, 24 Nov 2023 11:21:21 +0100 Subject: [PATCH 0185/3723] ci: hotfix: Use latest version of greetings action MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This fixes a bug with the action's Docker container apparently not being able to run Node correctly anymore... Signed-off-by: Benjamin Cabé --- .github/workflows/greet_first_time_contributor.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/greet_first_time_contributor.yml b/.github/workflows/greet_first_time_contributor.yml index 5984b29fe1f..13584774a54 100644 --- a/.github/workflows/greet_first_time_contributor.yml +++ b/.github/workflows/greet_first_time_contributor.yml @@ -13,7 +13,7 @@ jobs: steps: - uses: actions/checkout@v3 - - uses: zephyrproject-rtos/action-first-interaction@v1.1.1-zephyr-4 + - uses: zephyrproject-rtos/action-first-interaction@v1.1.1-zephyr-5 with: repo-token: ${{ secrets.GITHUB_TOKEN }} From 05025e6b7c47bc0acf7815f56b66d5fecea1262e Mon Sep 17 00:00:00 2001 From: Jeppe Odgaard Date: Fri, 3 Nov 2023 13:29:42 +0100 Subject: [PATCH 0186/3723] cmake: add initlevels to usage Fix missing `initlevels` entry in the `usage` command. Signed-off-by: Jeppe Odgaard --- cmake/usage/usage.cmake | 1 + 1 file changed, 1 insertion(+) diff --git a/cmake/usage/usage.cmake b/cmake/usage/usage.cmake index 9472f2fa9bb..2f4b0b76ddd 100644 --- a/cmake/usage/usage.cmake +++ b/cmake/usage/usage.cmake @@ -27,6 +27,7 @@ message(" debugserver - Run \"west debugserver\" (or start GDB server on port message(" attach - Run \"west attach\"") message(" ram_report - Build and create RAM usage report") message(" rom_report - Build and create ROM usage report") +message(" initlevels - Display the initialization sequence") message(" boards - Display supported boards") message(" shields - Display supported shields") message(" usage - Display this text") From 10a167f6c1f1ab4850f3bf1f8007826bff6f5285 Mon Sep 17 00:00:00 2001 From: Lukas Streitenberger Date: Thu, 16 Nov 2023 15:52:51 +0100 Subject: [PATCH 0187/3723] Bluetooth: TBS: Added missing callState notifications Changes of call state were not notified. Fixed by calling notify_calls in respective functions. Signed-off-by: Lukas Streitenberger --- subsys/bluetooth/audio/tbs.c | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/subsys/bluetooth/audio/tbs.c b/subsys/bluetooth/audio/tbs.c index 86588c11c71..06b5d7d2e3c 100644 --- a/subsys/bluetooth/audio/tbs.c +++ b/subsys/bluetooth/audio/tbs.c @@ -1836,6 +1836,8 @@ int bt_tbs_hold(uint8_t call_index) status = tbs_hold_call(inst, &ccp); } + notify_calls(inst); + return status; } @@ -1852,6 +1854,8 @@ int bt_tbs_retrieve(uint8_t call_index) status = retrieve_call(inst, &ccp); } + notify_calls(inst); + return status; } @@ -1869,6 +1873,8 @@ int bt_tbs_terminate(uint8_t call_index) BT_TBS_REASON_SERVER_ENDED_CALL); } + notify_calls(inst); + return status; } @@ -2028,6 +2034,8 @@ int bt_tbs_remote_terminate(uint8_t call_index) BT_TBS_REASON_REMOTE_ENDED_CALL); } + notify_calls(inst); + return status; } From 74f07b04ff4f72a46b3b6064ecd61cb4a14b2297 Mon Sep 17 00:00:00 2001 From: Jun Lin Date: Fri, 10 Nov 2023 10:38:21 +0800 Subject: [PATCH 0188/3723] soc: npcx: shi: add new registers for npcx4 Add the SHI enhanced buffer mode register definition for npcx4. Signed-off-by: Jun Lin --- soc/arm/nuvoton_npcx/common/reg/reg_def.h | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/soc/arm/nuvoton_npcx/common/reg/reg_def.h b/soc/arm/nuvoton_npcx/common/reg/reg_def.h index e9ef3460e63..21c0d99a87f 100644 --- a/soc/arm/nuvoton_npcx/common/reg/reg_def.h +++ b/soc/arm/nuvoton_npcx/common/reg/reg_def.h @@ -1619,7 +1619,11 @@ struct shi_reg { volatile uint8_t EVSTAT2; /* 0x010: Event Enable 2 */ volatile uint8_t EVENABLE2; - volatile uint8_t reserved4[15]; + /* 0x011: SHI Configuration 6 - only in chips which support enhanced buffer mode */ + volatile uint8_t SHICFG6; + /* 0x012: Single Byte Output Buffer - only in chips which support enhanced buffer mode */ + volatile uint8_t SBOBUF; + volatile uint8_t reserved4[13]; /* 0x20~0x9F: Output Buffer */ volatile uint8_t OBUF[128]; /* 0xA0~0x11F: Input Buffer */ @@ -1670,5 +1674,7 @@ struct shi_reg { #define NPCX_EVENABLE2_IBHF2EN 0 #define NPCX_EVENABLE2_CSNREEN 1 #define NPCX_EVENABLE2_CSNFEEN 2 +#define NPCX_SHICFG6_EBUFMD 0 +#define NPCX_SHICFG6_OBUF_SL 1 #endif /* _NUVOTON_NPCX_REG_DEF_H */ From ba38a54faa03249dae7847eb51921be2e043c8b9 Mon Sep 17 00:00:00 2001 From: Jun Lin Date: Fri, 10 Nov 2023 10:40:41 +0800 Subject: [PATCH 0189/3723] dts: npcx: shi: support two version of shi hardware The shi module in npcx4 supports the enhanced buffer mode. Add a new compatible string "nuvoton,npcx-shi-enhanced" for it. Then the shi driver can determine if it should use the enhanced buffer mode based on the compatiable string. Signed-off-by: Jun Lin --- dts/arm/nuvoton/npcx/npcx.dtsi | 10 ---------- dts/arm/nuvoton/npcx/npcx4.dtsi | 11 +++++++++++ dts/arm/nuvoton/npcx/npcx7.dtsi | 11 +++++++++++ dts/arm/nuvoton/npcx/npcx9.dtsi | 11 +++++++++++ dts/bindings/shi/nuvoton,npcx-shi-enhanced.yaml | 8 ++++++++ 5 files changed, 41 insertions(+), 10 deletions(-) create mode 100644 dts/bindings/shi/nuvoton,npcx-shi-enhanced.yaml diff --git a/dts/arm/nuvoton/npcx/npcx.dtsi b/dts/arm/nuvoton/npcx/npcx.dtsi index c1a77c4fe69..28a491de16f 100644 --- a/dts/arm/nuvoton/npcx/npcx.dtsi +++ b/dts/arm/nuvoton/npcx/npcx.dtsi @@ -376,16 +376,6 @@ status = "disabled"; }; - shi0: shi@4000f000 { - compatible = "nuvoton,npcx-shi"; - reg = <0x4000f000 0x120>; - interrupts = <18 1>; - clocks = <&pcc NPCX_CLOCK_BUS_APB3 NPCX_PWDWN_CTL5 1>; - status = "disabled"; - buffer-rx-size = <128>; - buffer-tx-size = <128>; - }; - host_sub: lpc@400c1000 { compatible = "nuvoton,npcx-host-sub"; /* host sub-module register address & size */ diff --git a/dts/arm/nuvoton/npcx/npcx4.dtsi b/dts/arm/nuvoton/npcx/npcx4.dtsi index a01d5d69abf..36f6bb579b8 100644 --- a/dts/arm/nuvoton/npcx/npcx4.dtsi +++ b/dts/arm/nuvoton/npcx/npcx4.dtsi @@ -295,6 +295,17 @@ context-buffer-size = <228>; status = "disabled"; }; + + shi0: shi@4000f000 { + compatible = "nuvoton,npcx-shi-enhanced"; + reg = <0x4000f000 0x120>; + interrupts = <18 1>; + clocks = <&pcc NPCX_CLOCK_BUS_APB3 NPCX_PWDWN_CTL5 1>; + status = "disabled"; + buffer-rx-size = <128>; + buffer-tx-size = <128>; + shi-cs-wui =<&wui_io53>; + }; }; soc-if { diff --git a/dts/arm/nuvoton/npcx/npcx7.dtsi b/dts/arm/nuvoton/npcx/npcx7.dtsi index 529d5bdef35..29be4fcc1f3 100644 --- a/dts/arm/nuvoton/npcx/npcx7.dtsi +++ b/dts/arm/nuvoton/npcx/npcx7.dtsi @@ -244,6 +244,17 @@ qspi_fiu0: quadspi@40020000 { clocks = <&pcc NPCX_CLOCK_BUS_FIU NPCX_PWDWN_CTL1 2>; }; + + shi0: shi@4000f000 { + compatible = "nuvoton,npcx-shi"; + reg = <0x4000f000 0x120>; + interrupts = <18 1>; + clocks = <&pcc NPCX_CLOCK_BUS_APB3 NPCX_PWDWN_CTL5 1>; + status = "disabled"; + buffer-rx-size = <128>; + buffer-tx-size = <128>; + shi-cs-wui =<&wui_io53>; + }; }; soc-id { diff --git a/dts/arm/nuvoton/npcx/npcx9.dtsi b/dts/arm/nuvoton/npcx/npcx9.dtsi index 4d0cb7dc69e..f4716d7947e 100644 --- a/dts/arm/nuvoton/npcx/npcx9.dtsi +++ b/dts/arm/nuvoton/npcx/npcx9.dtsi @@ -272,6 +272,17 @@ context-buffer-size = <212>; status = "disabled"; }; + + shi0: shi@4000f000 { + compatible = "nuvoton,npcx-shi"; + reg = <0x4000f000 0x120>; + interrupts = <18 1>; + clocks = <&pcc NPCX_CLOCK_BUS_APB3 NPCX_PWDWN_CTL5 1>; + status = "disabled"; + buffer-rx-size = <128>; + buffer-tx-size = <128>; + shi-cs-wui =<&wui_io53>; + }; }; soc-id { diff --git a/dts/bindings/shi/nuvoton,npcx-shi-enhanced.yaml b/dts/bindings/shi/nuvoton,npcx-shi-enhanced.yaml new file mode 100644 index 00000000000..dc197fb6fd8 --- /dev/null +++ b/dts/bindings/shi/nuvoton,npcx-shi-enhanced.yaml @@ -0,0 +1,8 @@ +# Copyright (c) 2022 Google LLC +# SPDX-License-Identifier: Apache-2.0 + +description: Nuvoton, NPCX Serial Host Interface (SHI) node + +compatible: "nuvoton,npcx-shi-enhanced" + +include: [pinctrl-device.yaml, shi-device.yaml, "nuvoton,npcx-shi.yaml"] From 717a7835bbf22a04ad62bab09f508346f09650b9 Mon Sep 17 00:00:00 2001 From: Jun Lin Date: Fri, 17 Nov 2023 17:57:49 +0800 Subject: [PATCH 0190/3723] mgmt: ec_host_cmd: shi_npcx: add pm_policy lock Implement the pm_policy lock to prevent the chip enters the deep slepp mode while shi transaction is ongoing. Signed-off-by: Jun Lin --- .../backends/ec_host_cmd_backend_shi_npcx.c | 33 +++++++++++++++++++ 1 file changed, 33 insertions(+) diff --git a/subsys/mgmt/ec_host_cmd/backends/ec_host_cmd_backend_shi_npcx.c b/subsys/mgmt/ec_host_cmd/backends/ec_host_cmd_backend_shi_npcx.c index f98f3bf7584..e5294e0f609 100644 --- a/subsys/mgmt/ec_host_cmd/backends/ec_host_cmd_backend_shi_npcx.c +++ b/subsys/mgmt/ec_host_cmd/backends/ec_host_cmd_backend_shi_npcx.c @@ -15,6 +15,7 @@ #include #include #include +#include #include @@ -95,6 +96,11 @@ enum shi_npcx_state { SHI_STATE_BAD_RECEIVED_DATA, }; +enum shi_npcx_pm_policy_state_flag { + SHI_NPCX_PM_POLICY_FLAG, + SHI_NPCX_PM_POLICY_FLAG_COUNT, +}; + /* Device config */ struct shi_npcx_config { /* Serial Host Interface (SHI) base address */ @@ -127,6 +133,7 @@ struct shi_npcx_data { SHI_OUT_END_PAD] __aligned(4); uint8_t *const out_msg; uint8_t in_msg[CONFIG_EC_HOST_CMD_BACKEND_SHI_MAX_REQUEST] __aligned(4); + ATOMIC_DEFINE(pm_policy_state_flag, SHI_NPCX_PM_POLICY_FLAG_COUNT); }; struct ec_host_cmd_shi_npcx_ctx { @@ -144,6 +151,22 @@ struct ec_host_cmd_shi_npcx_ctx { /* Forward declaration */ static void shi_npcx_reset_prepare(const struct device *dev); +static void shi_npcx_pm_policy_state_lock_get(struct shi_npcx_data *data, + enum shi_npcx_pm_policy_state_flag flag) +{ + if (atomic_test_and_set_bit(data->pm_policy_state_flag, flag) == 0) { + pm_policy_state_lock_get(PM_STATE_SUSPEND_TO_IDLE, PM_ALL_SUBSTATES); + } +} + +static void shi_npcx_pm_policy_state_lock_put(struct shi_npcx_data *data, + enum shi_npcx_pm_policy_state_flag flag) +{ + if (atomic_test_and_clear_bit(data->pm_policy_state_flag, flag) == 1) { + pm_policy_state_lock_put(PM_STATE_SUSPEND_TO_IDLE, PM_ALL_SUBSTATES); + } +} + /* Read pointer of input or output buffer by consecutive reading */ static uint32_t shi_npcx_read_buf_pointer(struct shi_reg *const inst) { @@ -495,6 +518,8 @@ static void shi_npcx_handle_cs_assert(const struct device *dev) * irrelevant now that CS is re-asserted. */ inst->EVSTAT = BIT(NPCX_EVSTAT_EOR); + + shi_npcx_pm_policy_state_lock_get(data, SHI_NPCX_PM_POLICY_FLAG); } static void shi_npcx_handle_cs_deassert(const struct device *dev) @@ -712,6 +737,8 @@ static void shi_npcx_reset_prepare(const struct device *dev) shi_npcx_sec_ibf_int_enable(inst, 1); irq_enable(DT_INST_IRQN(0)); + shi_npcx_pm_policy_state_lock_put(data, SHI_NPCX_PM_POLICY_FLAG); + LOG_DBG("RDY-"); } @@ -769,6 +796,12 @@ static int shi_npcx_disable(const struct device *dev) return ret; } + /* + * Allow deep sleep again in case CS dropped before ec was + * informed in hook function and turn off SHI's interrupt in time. + */ + shi_npcx_pm_policy_state_lock_put(data, SHI_NPCX_PM_POLICY_FLAG); + return 0; } From 3f9d24e4c01ba282a73d774c28639761118ec9c7 Mon Sep 17 00:00:00 2001 From: Jun Lin Date: Mon, 20 Nov 2023 11:06:05 +0800 Subject: [PATCH 0191/3723] mgmt: ec_host_cmd: shi_npcx: support the enhanced mode The original SHI module only has one output FIFO buffer. It costs a lot when the driver has to send/change the protocol control code because it must fill out all 128 bytes of output FIFO. In npcx4, we introduce another output buffer in 1-byte depth. These two buffers can switch back and forth during the transaction. We can use the single-byte buffer to send the control code and the 128-byte FIFO to send the data payload. It helps improve the SHI driver's efficiency. Signed-off-by: Jun Lin --- soc/arm/nuvoton_npcx/common/reg/reg_def.h | 2 + subsys/mgmt/ec_host_cmd/backends/Kconfig | 10 +- .../backends/ec_host_cmd_backend_shi_npcx.c | 121 ++++++++++++++---- 3 files changed, 109 insertions(+), 24 deletions(-) diff --git a/soc/arm/nuvoton_npcx/common/reg/reg_def.h b/soc/arm/nuvoton_npcx/common/reg/reg_def.h index 21c0d99a87f..d6b081533df 100644 --- a/soc/arm/nuvoton_npcx/common/reg/reg_def.h +++ b/soc/arm/nuvoton_npcx/common/reg/reg_def.h @@ -1677,4 +1677,6 @@ struct shi_reg { #define NPCX_SHICFG6_EBUFMD 0 #define NPCX_SHICFG6_OBUF_SL 1 +#define IBF_IBHF_EN_MASK (BIT(NPCX_EVENABLE_IBFEN) | BIT(NPCX_EVENABLE_IBHFEN)) + #endif /* _NUVOTON_NPCX_REG_DEF_H */ diff --git a/subsys/mgmt/ec_host_cmd/backends/Kconfig b/subsys/mgmt/ec_host_cmd/backends/Kconfig index d1482fe7976..de9ec920560 100644 --- a/subsys/mgmt/ec_host_cmd/backends/Kconfig +++ b/subsys/mgmt/ec_host_cmd/backends/Kconfig @@ -53,7 +53,8 @@ choice EC_HOST_CMD_BACKEND_SHI_DRIVER config EC_HOST_CMD_BACKEND_SHI_NPCX bool "SHI by Nuvoton" - depends on DT_HAS_NUVOTON_NPCX_SHI_ENABLED + depends on DT_HAS_NUVOTON_NPCX_SHI_ENABLED || \ + DT_HAS_NUVOTON_NPCX_SHI_ENHANCED_ENABLED help This option enables the driver for SHI backend in the Nuvoton NPCX chip. @@ -67,6 +68,13 @@ config EC_HOST_CMD_BACKEND_SHI_ITE endchoice +config EC_HOST_CMD_BACKEND_SHI_NPCX_ENHANCED_BUF_MODE + def_bool DT_HAS_NUVOTON_NPCX_SHI_ENHANCED_ENABLED + help + In this mode, besides the original 128-bytes FIFO, an additional + single-byte output buffer can be selected/switched to generate a + response to simultaneous Read/Write transactions. + config EC_HOST_CMD_BACKEND_SHI_MAX_REQUEST int "Max data size for the version 3 request packet" default 544 if EC_HOST_CMD_BACKEND_SHI_NPCX diff --git a/subsys/mgmt/ec_host_cmd/backends/ec_host_cmd_backend_shi_npcx.c b/subsys/mgmt/ec_host_cmd/backends/ec_host_cmd_backend_shi_npcx.c index e5294e0f609..a5bb9adadde 100644 --- a/subsys/mgmt/ec_host_cmd/backends/ec_host_cmd_backend_shi_npcx.c +++ b/subsys/mgmt/ec_host_cmd/backends/ec_host_cmd_backend_shi_npcx.c @@ -4,8 +4,6 @@ * SPDX-License-Identifier: Apache-2.0 */ -#define DT_DRV_COMPAT nuvoton_npcx_shi - #include "ec_host_cmd_backend_shi.h" #include @@ -19,7 +17,14 @@ #include +#if DT_HAS_COMPAT_STATUS_OKAY(nuvoton_npcx_shi) +#define DT_DRV_COMPAT nuvoton_npcx_shi +#elif DT_HAS_COMPAT_STATUS_OKAY(nuvoton_npcx_shi_enhanced) +#define DT_DRV_COMPAT nuvoton_npcx_shi_enhanced +#endif BUILD_ASSERT(DT_NUM_INST_STATUS_OKAY(DT_DRV_COMPAT) == 1, "Invalid number of NPCX SHI peripherals"); +BUILD_ASSERT(!(DT_HAS_COMPAT_STATUS_OKAY(nuvoton_npcx_shi) && + DT_HAS_COMPAT_STATUS_OKAY(nuvoton_npcx_shi_enhanced))); LOG_MODULE_REGISTER(host_cmd_shi_npcx, CONFIG_EC_HC_LOG_LEVEL); @@ -152,7 +157,7 @@ struct ec_host_cmd_shi_npcx_ctx { static void shi_npcx_reset_prepare(const struct device *dev); static void shi_npcx_pm_policy_state_lock_get(struct shi_npcx_data *data, - enum shi_npcx_pm_policy_state_flag flag) + enum shi_npcx_pm_policy_state_flag flag) { if (atomic_test_and_set_bit(data->pm_policy_state_flag, flag) == 0) { pm_policy_state_lock_get(PM_STATE_SUSPEND_TO_IDLE, PM_ALL_SUBSTATES); @@ -160,7 +165,7 @@ static void shi_npcx_pm_policy_state_lock_get(struct shi_npcx_data *data, } static void shi_npcx_pm_policy_state_lock_put(struct shi_npcx_data *data, - enum shi_npcx_pm_policy_state_flag flag) + enum shi_npcx_pm_policy_state_flag flag) { if (atomic_test_and_clear_bit(data->pm_policy_state_flag, flag) == 1) { pm_policy_state_lock_put(PM_STATE_SUSPEND_TO_IDLE, PM_ALL_SUBSTATES); @@ -180,13 +185,40 @@ static uint32_t shi_npcx_read_buf_pointer(struct shi_reg *const inst) return (uint32_t)stat; } +/* + * Write pointer of output buffer by consecutive reading + * Note: this function (OBUFSTAT) should only be usd in Enhanced Buffer Mode. + */ +static uint32_t shi_npcx_write_buf_pointer(struct shi_reg *const inst) +{ + uint8_t stat; + + /* Wait for two consecutive equal values are read */ + do { + stat = inst->OBUFSTAT; + } while (stat != inst->OBUFSTAT); + + return stat; +} + /* * Valid offset of SHI output buffer to write. - * When SIMUL bit is set, IBUFPTR can be used instead of OBUFPTR + * - In Simultaneous Standard FIFO Mode (SIMUL = 1 and EBUFMD = 0): + * OBUFPTR cannot be used. IBUFPTR can be used instead because it points to + * the same location as OBUFPTR. + * - In Simultaneous Enhanced FIFO Mode (SIMUL = 1 and EBUFMD = 1): + * IBUFPTR may not point to the same location as OBUFPTR. + * In this case OBUFPTR reflects the 128-byte payload buffer pointer only + * during the SPI transaction. */ static uint32_t shi_npcx_valid_obuf_offset(struct shi_reg *const inst) { - return (shi_npcx_read_buf_pointer(inst) + EC_SHI_OUT_PREAMBLE_LENGTH) % SHI_OBUF_FULL_SIZE; + if (IS_ENABLED(CONFIG_EC_HOST_CMD_BACKEND_SHI_NPCX_ENHANCED_BUF_MODE)) { + return shi_npcx_write_buf_pointer(inst) % SHI_OBUF_FULL_SIZE; + } else { + return (shi_npcx_read_buf_pointer(inst) + EC_SHI_OUT_PREAMBLE_LENGTH) % + SHI_OBUF_FULL_SIZE; + } } /* @@ -246,6 +278,16 @@ static void shi_npcx_fill_out_status(struct shi_reg *const inst, uint8_t status) volatile uint8_t *fill_end; volatile uint8_t *obuf_end; + if (IS_ENABLED(CONFIG_EC_HOST_CMD_BACKEND_SHI_NPCX_ENHANCED_BUF_MODE)) { + /* + * In Enhanced Buffer Mode, SHI module outputs the status code + * in SBOBUF repeatedly. + */ + inst->SBOBUF = status; + + return; + } + /* * Disable interrupts in case the interfere by the other interrupts. * Use __disable_irq/__enable_irq instead of using irq_lock/irq_unlock @@ -282,6 +324,10 @@ static void shi_npcx_bad_received_data(const struct device *dev) struct shi_npcx_data *data = dev->data; struct shi_reg *const inst = HAL_INSTANCE(dev); + if (IS_ENABLED(CONFIG_EC_HOST_CMD_BACKEND_SHI_NPCX_ENHANCED_BUF_MODE)) { + inst->EVENABLE &= ~IBF_IBHF_EN_MASK; + } + /* State machine mismatch, timeout, or protocol we can't handle. */ shi_npcx_fill_out_status(inst, EC_SHI_RX_BAD_DATA); data->state = SHI_STATE_BAD_RECEIVED_DATA; @@ -367,6 +413,10 @@ static void shi_npcx_handle_host_package(const struct device *dev) data->state = SHI_STATE_PROCESSING; LOG_DBG("PRC-"); + if (IS_ENABLED(CONFIG_EC_HOST_CMD_BACKEND_SHI_NPCX_ENHANCED_BUF_MODE)) { + inst->EVENABLE &= ~IBF_IBHF_EN_MASK; + } + /* Fill output buffer to indicate we`re processing request */ shi_npcx_fill_out_status(inst, EC_SHI_PROCESSING); data->out_msg[0] = EC_SHI_FRAME_START; @@ -719,14 +769,20 @@ static void shi_npcx_reset_prepare(const struct device *dev) data->sz_request = 0; data->sz_response = 0; - /* - * Fill output buffer to indicate we`re - * ready to receive next transaction. - */ - for (i = 1; i < SHI_OBUF_FULL_SIZE; i++) { - inst->OBUF[i] = EC_SHI_RECEIVING; + if (IS_ENABLED(CONFIG_EC_HOST_CMD_BACKEND_SHI_NPCX_ENHANCED_BUF_MODE)) { + inst->SBOBUF = EC_SHI_RX_READY; + inst->SBOBUF = EC_SHI_RECEIVING; + inst->EVENABLE |= IBF_IBHF_EN_MASK; + inst->EVENABLE &= ~(BIT(NPCX_EVENABLE_OBEEN) | BIT(NPCX_EVENABLE_OBHEEN)); + } else { + /* + * Fill output buffer to indicate we`re ready to receive next transaction. + */ + for (i = 1; i < SHI_OBUF_FULL_SIZE; i++) { + inst->OBUF[i] = EC_SHI_RECEIVING; + } + inst->OBUF[0] = EC_SHI_RX_READY; } - inst->OBUF[0] = EC_SHI_RX_READY; /* SHI/Host Write/input buffer wrap-around enable */ inst->SHICFG1 = BIT(NPCX_SHICFG1_IWRAP) | BIT(NPCX_SHICFG1_WEN) | BIT(NPCX_SHICFG1_EN); @@ -861,8 +917,7 @@ static int shi_npcx_init_registers(const struct device *dev) * [1] - OBHEEN = 0: Output Buffer Half Empty Interrupt Enable * [0] - OBEEN = 0: Output Buffer Empty Interrupt Enable */ - inst->EVENABLE = - BIT(NPCX_EVENABLE_EOREN) | BIT(NPCX_EVENABLE_IBHFEN) | BIT(NPCX_EVENABLE_IBFEN); + inst->EVENABLE = BIT(NPCX_EVENABLE_EOREN) | IBF_IBHF_EN_MASK; /* * EVENABLE2 (Event Enable 2) setting @@ -875,6 +930,10 @@ static int shi_npcx_init_registers(const struct device *dev) /* Clear SHI events status register */ inst->EVSTAT = 0xff; + if (IS_ENABLED(CONFIG_EC_HOST_CMD_BACKEND_SHI_NPCX_ENHANCED_BUF_MODE)) { + inst->SHICFG6 |= BIT(NPCX_SHICFG6_EBUFMD); + } + npcx_miwu_interrupt_configure(&config->shi_cs_wui, NPCX_MIWU_MODE_EDGE, NPCX_MIWU_TRIG_LOW); /* SHI interrupt installation */ @@ -928,13 +987,15 @@ static int shi_npcx_backend_send(const struct ec_host_cmd_backend *backend) struct shi_npcx_data *data = hc_shi->dev->data; uint8_t *out_buf = data->out_msg + EC_SHI_FRAME_START_LENGTH; - /* - * Disable interrupts. This routine is not called from interrupt context and buffer - * underrun will likely occur if it is preempted after writing its initial reply byte. - * Also, we must be sure our state doesn't unexpectedly change, in case we're expected - * to take RESP_NOT_RDY actions. - */ - __disable_irq(); + if (!IS_ENABLED(CONFIG_EC_HOST_CMD_BACKEND_SHI_NPCX_ENHANCED_BUF_MODE)) { + /* + * Disable interrupts. This routine is not called from interrupt context and buffer + * underrun will likely occur if it is preempted after writing its initial reply + * byte. Also, we must be sure our state doesn't unexpectedly change, in case we're + * expected to take RESP_NOT_RDY actions. + */ + __disable_irq(); + } if (data->state == SHI_STATE_PROCESSING) { /* Append our past-end byte, which we reserved space for. */ @@ -948,6 +1009,17 @@ static int shi_npcx_backend_send(const struct ec_host_cmd_backend *backend) /* Transmit the reply */ data->state = SHI_STATE_SENDING; + if (IS_ENABLED(CONFIG_EC_HOST_CMD_BACKEND_SHI_NPCX_ENHANCED_BUF_MODE)) { + struct shi_reg *const inst = HAL_INSTANCE(hc_shi->dev); + + /* + * Enable output buffer half/full empty interrupt and + * switch output mode from the repeated single byte mode + * to FIFO mode. + */ + inst->EVENABLE |= BIT(NPCX_EVENABLE_OBEEN) | BIT(NPCX_EVENABLE_OBHEEN); + inst->SHICFG6 |= BIT(NPCX_SHICFG6_OBUF_SL); + } LOG_DBG("SND-"); } else if (data->state == SHI_STATE_CNL_RESP_NOT_RDY) { /* @@ -961,7 +1033,10 @@ static int shi_npcx_backend_send(const struct ec_host_cmd_backend *backend) LOG_ERR("Unexpected state %d in response handler", data->state); } - __enable_irq(); + if (!IS_ENABLED(CONFIG_EC_HOST_CMD_BACKEND_SHI_NPCX_ENHANCED_BUF_MODE)) { + __enable_irq(); + } + return 0; } From f89c5ddd1aaf0e4a5b6fd0a1397c5a72f1cba388 Mon Sep 17 00:00:00 2001 From: Johan Hedberg Date: Wed, 22 Nov 2023 17:29:40 +0200 Subject: [PATCH 0192/3723] samples: chre: Fix format strings for size_t types The correct printf format specifier for size_t is %zu. Without this change the sample generates warnings like this: warning: format '%u' expects argument of type 'unsigned int', but argument 2 has type 'size_t' {aka 'long unsigned int'} [-Wformat=] Signed-off-by: Johan Hedberg --- samples/modules/chre/src/main.cpp | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/samples/modules/chre/src/main.cpp b/samples/modules/chre/src/main.cpp index f9b2b16cb52..675e57e8932 100644 --- a/samples/modules/chre/src/main.cpp +++ b/samples/modules/chre/src/main.cpp @@ -37,12 +37,12 @@ int main(void) k_msleep(100); } printk("Starting EchoApp... %s\n", boolToString(eventLoop.startNanoapp(echo_app))); - printk("Nanoapp count=%u\n", eventLoop.getNanoappCount()); + printk("Nanoapp count=%zu\n", eventLoop.getNanoappCount()); printk("Finding instance ID... %s\n", boolToString(eventLoop.findNanoappInstanceIdByAppId(1, &instanceId))); - printk("Nanoapp count=%u\n", eventLoop.getNanoappCount()); + printk("Nanoapp count=%zu\n", eventLoop.getNanoappCount()); printk("Instance ID: %u\n", instanceId); - printk("Sending event %u...\n", eventLoop.getNanoappCount()); + printk("Sending event %zu...\n", eventLoop.getNanoappCount()); eventLoop.postEventOrDie(CHRE_EVENT_MESSAGE_FROM_HOST, nullptr, [](uint16_t eventType, void *eventData) { printk("Event (%u) complete!\n", eventType); }); From 2abf0314c27f83001434c0a009c33eba7205d3c0 Mon Sep 17 00:00:00 2001 From: Igor Druzhinin Date: Fri, 29 Sep 2023 15:04:32 +0100 Subject: [PATCH 0193/3723] toolchain: gcc: fix GCC < 11.0.0 build with -Wundef When building using GCC version < 11.0.0, TOOLCHAIN_CLANG_VERSION is not yet defined in gcc.h. Nevertheless, it's still needed due to reuse of gcc.h in llvm.h. Guard access to TOOLCHAIN_CLANG_VERSION to fix that. Signed-off-by: Igor Druzhinin --- include/zephyr/toolchain/gcc.h | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/include/zephyr/toolchain/gcc.h b/include/zephyr/toolchain/gcc.h index d3dce3b253f..e086c644e87 100644 --- a/include/zephyr/toolchain/gcc.h +++ b/include/zephyr/toolchain/gcc.h @@ -648,7 +648,8 @@ do { \ * * @note Only supported for GCC >= 11.0.0 or Clang >= 7. */ -#if (TOOLCHAIN_GCC_VERSION >= 110000) || (TOOLCHAIN_CLANG_VERSION >= 70000) +#if (TOOLCHAIN_GCC_VERSION >= 110000) || \ + (defined(TOOLCHAIN_CLANG_VERSION) && (TOOLCHAIN_CLANG_VERSION >= 70000)) #define FUNC_NO_STACK_PROTECTOR __attribute__((no_stack_protector)) #else #define FUNC_NO_STACK_PROTECTOR From 897b300b2e516c733ffa6df45a77948996a563dd Mon Sep 17 00:00:00 2001 From: Dean Sellers Date: Thu, 23 Nov 2023 09:28:16 +1000 Subject: [PATCH 0194/3723] drivers: spi: esp32xx: Fix CS reset over split transaction In the case where a transaction is spilt due to the rx buff len being longer than the tx or the transaction buffer exceeding the size of the requested buffer with non gpio CS, the chip select would be de-asserted/asserted in the middle of the transaction. Fixes: #57577 Signed-off-by: Dean Sellers --- drivers/spi/spi_esp32_spim.c | 15 +++++++++------ 1 file changed, 9 insertions(+), 6 deletions(-) diff --git a/drivers/spi/spi_esp32_spim.c b/drivers/spi/spi_esp32_spim.c index a6ace4f263f..0bfed3fc8be 100644 --- a/drivers/spi/spi_esp32_spim.c +++ b/drivers/spi/spi_esp32_spim.c @@ -71,7 +71,8 @@ static int IRAM_ATTR spi_esp32_transfer(const struct device *dev) size_t max_buf_sz = cfg->dma_enabled ? SPI_DMA_MAX_BUFFER_SIZE : SOC_SPI_MAXIMUM_BUFFER_SIZE; size_t transfer_len_bytes = MIN(chunk_len_bytes, max_buf_sz); - size_t bit_len = transfer_len_bytes << 3; + size_t transfer_len_frames = transfer_len_bytes / data->dfs; + size_t bit_len = transfer_len_bytes << 3; uint8_t *rx_temp = NULL; uint8_t *tx_temp = NULL; uint8_t dma_len_tx = MIN(ctx->tx_len * data->dfs, SPI_DMA_MAX_BUFFER_SIZE); @@ -90,7 +91,7 @@ static int IRAM_ATTR spi_esp32_transfer(const struct device *dev) memcpy(tx_temp, &ctx->tx_buf[0], dma_len_tx); } if (ctx->rx_buf && (!esp_ptr_dma_capable((uint32_t *)&ctx->rx_buf[0]) || - ((int)&ctx->rx_buf[0] % 4 != 0) || (dma_len_tx % 4 != 0))) { + ((int)&ctx->rx_buf[0] % 4 != 0) || (dma_len_rx % 4 != 0))) { /* The rx buffer need to be length of * multiples of 32 bits to avoid heap * corruption. @@ -112,9 +113,11 @@ static int IRAM_ATTR spi_esp32_transfer(const struct device *dev) hal_trans->tx_bitlen = bit_len; hal_trans->rx_bitlen = bit_len; - /* keep cs line active ultil last transmission */ + /* keep cs line active until last transmission */ hal_trans->cs_keep_active = - (!ctx->num_cs_gpios && (ctx->rx_count > 1 || ctx->tx_count > 1)); + (!ctx->num_cs_gpios && + (ctx->rx_count > 1 || ctx->tx_count > 1 || ctx->rx_len > transfer_len_frames || + ctx->tx_len > transfer_len_frames)); /* configure SPI */ spi_hal_setup_trans(hal, hal_dev, hal_trans); @@ -122,7 +125,7 @@ static int IRAM_ATTR spi_esp32_transfer(const struct device *dev) /* send data */ spi_hal_user_start(hal); - spi_context_update_tx(&data->ctx, data->dfs, transfer_len_bytes/data->dfs); + spi_context_update_tx(&data->ctx, data->dfs, transfer_len_frames); while (!spi_hal_usr_is_done(hal)) { /* nop */ @@ -135,7 +138,7 @@ static int IRAM_ATTR spi_esp32_transfer(const struct device *dev) memcpy(&ctx->rx_buf[0], rx_temp, transfer_len_bytes); } - spi_context_update_rx(&data->ctx, data->dfs, transfer_len_bytes/data->dfs); + spi_context_update_rx(&data->ctx, data->dfs, transfer_len_frames); k_free(tx_temp); k_free(rx_temp); From e3f5c966675b0c2d8b5f53562750834a74635d55 Mon Sep 17 00:00:00 2001 From: Pieter De Gendt Date: Wed, 15 Nov 2023 16:37:18 +0100 Subject: [PATCH 0195/3723] modules: nanopb: Let Nanopb search for protoc The Nanopb cmake locates the protoc executable, verify the result instead of doing it ourselves. Signed-off-by: Pieter De Gendt --- modules/nanopb/nanopb.cmake | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/modules/nanopb/nanopb.cmake b/modules/nanopb/nanopb.cmake index ddcdb5f61d1..24263c825e4 100644 --- a/modules/nanopb/nanopb.cmake +++ b/modules/nanopb/nanopb.cmake @@ -6,14 +6,15 @@ include_guard(GLOBAL) list(APPEND CMAKE_MODULE_PATH ${ZEPHYR_NANOPB_MODULE_DIR}/extra) -find_program(PROTOC protoc) -if(NOT PROTOC) +find_package(Nanopb REQUIRED) + +if(NOT PROTOBUF_PROTOC_EXECUTABLE) message(FATAL_ERROR "'protoc' not found, please ensure protoc is installed\ and in path. See https://docs.zephyrproject.org/latest/samples/modules/nanopb/README.html") +else() + message(STATUS "Found protoc: ${PROTOBUF_PROTOC_EXECUTABLE}") endif() -find_package(Nanopb REQUIRED) - # Usage: # list(APPEND CMAKE_MODULE_PATH ${ZEPHYR_BASE}/modules/nanopb) # include(nanopb) From a89fa32dac0de646a69ee916570f0a010fb9e6c6 Mon Sep 17 00:00:00 2001 From: Christopher Friedt Date: Thu, 23 Nov 2023 11:42:50 -0500 Subject: [PATCH 0196/3723] posix: pthread: ensure pthread_key_delete() removes correct key Previously, `pthread_key_delete()` was only ever deleting key 0 rather than the key corresponding to the provided argument. Signed-off-by: Christopher Friedt --- lib/posix/key.c | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/lib/posix/key.c b/lib/posix/key.c index 03d03eed84a..1a3f2b92a13 100644 --- a/lib/posix/key.c +++ b/lib/posix/key.c @@ -10,6 +10,7 @@ #include #include #include +#include struct pthread_key_data { sys_snode_t node; @@ -120,6 +121,8 @@ int pthread_key_create(pthread_key_t *key, */ int pthread_key_delete(pthread_key_t key) { + size_t bit; + __unused int ret; pthread_key_obj *key_obj; struct pthread_key_data *key_data; sys_snode_t *node_l, *next_node_l; @@ -145,7 +148,9 @@ int pthread_key_delete(pthread_key_t key) k_free((void *)key_data); } - (void)sys_bitarray_free(&posix_key_bitarray, 1, 0); + bit = posix_key_to_offset(key_obj); + ret = sys_bitarray_free(&posix_key_bitarray, 1, bit); + __ASSERT_NO_MSG(ret == 0); k_spin_unlock(&pthread_key_lock, key_key); From 0e11bcf5a0e748c29925199d9cbb634979e495d1 Mon Sep 17 00:00:00 2001 From: Christopher Friedt Date: Thu, 23 Nov 2023 11:47:21 -0500 Subject: [PATCH 0197/3723] tests: posix: add tests to ensure pthread_key_delete() works Ensure that the correct key is deleted via pthread_key_delete(). Signed-off-by: Christopher Friedt --- tests/posix/common/src/key.c | 31 +++++++++++++++++++++++++++++++ 1 file changed, 31 insertions(+) diff --git a/tests/posix/common/src/key.c b/tests/posix/common/src/key.c index ff01617f698..eeadf8f0058 100644 --- a/tests/posix/common/src/key.c +++ b/tests/posix/common/src/key.c @@ -213,3 +213,34 @@ ZTEST(posix_apis, test_key_Nto1_thread) } printk("\n"); } + +ZTEST(posix_apis, test_key_resource_leak) +{ + pthread_key_t key; + + for (size_t i = 0; i < CONFIG_MAX_PTHREAD_KEY_COUNT; ++i) { + zassert_ok(pthread_key_create(&key, NULL), "failed to create key %zu", i); + zassert_ok(pthread_key_delete(key), "failed to delete key %zu", i); + } +} + +ZTEST(posix_apis, test_correct_key_is_deleted) +{ + pthread_key_t key; + size_t j = CONFIG_MAX_PTHREAD_KEY_COUNT - 1; + pthread_key_t keys[CONFIG_MAX_PTHREAD_KEY_COUNT]; + + for (size_t i = 0; i < ARRAY_SIZE(keys); ++i) { + zassert_ok(pthread_key_create(&keys[i], NULL), "failed to create key %zu", i); + } + + key = keys[j]; + zassert_ok(pthread_key_delete(keys[j])); + zassert_ok(pthread_key_create(&keys[j], NULL), "failed to create key %zu", j); + + zassert_equal(key, keys[j], "deleted key %x instead of key %x", keys[j], key); + + for (size_t i = 0; i < ARRAY_SIZE(keys); ++i) { + zassert_ok(pthread_key_delete(keys[i]), "failed to delete key %zu", i); + } +} From cc6bf663452936f1460314f3e5140cdb4b645553 Mon Sep 17 00:00:00 2001 From: Shahar Hadas Date: Sun, 29 Oct 2023 00:24:02 +0300 Subject: [PATCH 0198/3723] auxdisplay: Enhance SerLCD auxdisplay driver Added export of command and special command delays as configurable options. Signed-off-by: Shahar Hadas --- drivers/auxdisplay/auxdisplay_serlcd.c | 25 +++++++++----------- dts/bindings/auxdisplay/sparkfun,serlcd.yaml | 22 +++++++++++++++++ 2 files changed, 33 insertions(+), 14 deletions(-) diff --git a/drivers/auxdisplay/auxdisplay_serlcd.c b/drivers/auxdisplay/auxdisplay_serlcd.c index f3c0e764869..19c7154de29 100644 --- a/drivers/auxdisplay/auxdisplay_serlcd.c +++ b/drivers/auxdisplay/auxdisplay_serlcd.c @@ -28,16 +28,6 @@ LOG_MODULE_REGISTER(auxdisplay_serlcd, CONFIG_AUXDISPLAY_LOG_LEVEL); */ #define SERLCD_BEGIN_SPECIAL_COMMAND 0xFE -/* - * delay in milliseconds after a normal command was sent - */ -#define SERLCD_COMMAND_DELAY_MS 10 - -/* - * delay in milliseconds after a special command was sent - */ -#define SERLCD_SPECIAL_COMMAND_DELAY_MS 50 - /* * maximum amount of custom chars the display supports */ @@ -89,6 +79,8 @@ struct auxdisplay_serlcd_data { struct auxdisplay_serlcd_config { struct auxdisplay_capabilities capabilities; struct i2c_dt_spec bus; + uint16_t command_delay_ms; + uint16_t special_command_delay_ms; }; enum auxdisplay_serlcd_command { @@ -111,7 +103,7 @@ static int auxdisplay_serlcd_send_command(const struct device *dev, int rc = i2c_write_dt(&config->bus, buffer, sizeof(buffer)); - k_sleep(K_MSEC(SERLCD_COMMAND_DELAY_MS)); + k_sleep(K_MSEC(config->command_delay_ms)); return rc; } @@ -124,7 +116,7 @@ auxdisplay_serlcd_send_special_command(const struct device *dev, int rc = i2c_write_dt(&config->bus, buffer, sizeof(buffer)); - k_sleep(K_MSEC(SERLCD_SPECIAL_COMMAND_DELAY_MS)); + k_sleep(K_MSEC(config->special_command_delay_ms)); return rc; } @@ -269,9 +261,11 @@ static int auxdisplay_serlcd_capabilities_get(const struct device *dev, static int auxdisplay_serlcd_clear(const struct device *dev) { + const struct auxdisplay_serlcd_config *config = dev->config; + int rc = auxdisplay_serlcd_send_command(dev, SERLCD_COMMAND_CLEAR); - k_sleep(K_MSEC(SERLCD_COMMAND_DELAY_MS)); + k_sleep(K_MSEC(config->command_delay_ms)); return rc; } @@ -425,7 +419,10 @@ static const struct auxdisplay_driver_api auxdisplay_serlcd_auxdisplay_api = { .custom_character_width = SERLCD_CUSTOM_CHAR_WIDTH, \ .custom_character_height = SERLCD_CUSTOM_CHAR_HEIGHT, \ }, \ - .bus = I2C_DT_SPEC_INST_GET(inst)}; \ + .bus = I2C_DT_SPEC_INST_GET(inst), \ + .command_delay_ms = DT_INST_PROP(inst, command_delay_ms), \ + .special_command_delay_ms = DT_INST_PROP(inst, special_command_delay_ms), \ + }; \ \ static struct auxdisplay_serlcd_data auxdisplay_serlcd_data_##inst; \ \ diff --git a/dts/bindings/auxdisplay/sparkfun,serlcd.yaml b/dts/bindings/auxdisplay/sparkfun,serlcd.yaml index 1a4d5734f36..60c17fc7860 100644 --- a/dts/bindings/auxdisplay/sparkfun,serlcd.yaml +++ b/dts/bindings/auxdisplay/sparkfun,serlcd.yaml @@ -11,6 +11,8 @@ description: | reg = <0x72>; columns = <16>; rows = <2>; + command-delay = <10>; + special-command-delay = <50>; }; }; @@ -32,3 +34,23 @@ properties: enum: - 2 - 4 + + command-delay-ms: + type: int + default: 10 + description: | + Delay in milliseconds (defaults to 10ms if not set) after a normal command was sent. + The default value is based on the original SparkFun SerLCD library + implementation which assumes 100 kbps I2C configuration. This value + might require tweaking if using I2C at a higher bitrare and/or relativily + high update frequency of the display. + + special-command-delay-ms: + type: int + default: 50 + description: | + Delay in milliseconds (defaults to 50ms if not set) after a special command was sent. + The default value is based on the original SparkFun SerLCD library + implementation which assumes 100 kbps I2C configuration. This value + might require tweaking if using I2C at a higher bitrare and/or relativily + high update frequency of the display. From ad5441bbdde5ee3534e74c732004973d2d9a363d Mon Sep 17 00:00:00 2001 From: Christopher Friedt Date: Wed, 22 Nov 2023 21:23:53 -0500 Subject: [PATCH 0199/3723] posix: pthread: move pthread_equal() closer to pthread_self() * "identity" functions grouped more closely * posix_thread_pool_init() should be adjacent to the SYS_INIT() Signed-off-by: Christopher Friedt --- lib/posix/pthread.c | 11 +++++------ 1 file changed, 5 insertions(+), 6 deletions(-) diff --git a/lib/posix/pthread.c b/lib/posix/pthread.c index c5c00a53491..5566fc6616b 100644 --- a/lib/posix/pthread.c +++ b/lib/posix/pthread.c @@ -135,6 +135,11 @@ pthread_t pthread_self(void) return mark_pthread_obj_initialized(bit); } +int pthread_equal(pthread_t pt1, pthread_t pt2) +{ + return (pt1 == pt2); +} + static bool is_posix_policy_prio_valid(uint32_t priority, int policy) { if (priority >= sched_get_priority_min(policy) && @@ -973,10 +978,4 @@ static int posix_thread_pool_init(void) return 0; } - -int pthread_equal(pthread_t pt1, pthread_t pt2) -{ - return (pt1 == pt2); -} - SYS_INIT(posix_thread_pool_init, PRE_KERNEL_1, 0); From 131220cb95d6742bd3b20bc6bb04f2b2c6deafab Mon Sep 17 00:00:00 2001 From: Christopher Friedt Date: Wed, 22 Nov 2023 22:02:21 -0500 Subject: [PATCH 0200/3723] tests: posix: headers: check pthread_spin_lock() et al exist The simple header test was not updated to verify that the following functions were implemented even though they were implemented some time ago. * pthread_spin_destroy() * pthread_spin_init() * pthread_spin_lock() * pthread_spin_trylock() * pthread_spin_unlock() Signed-off-by: Christopher Friedt --- tests/posix/headers/src/pthread_h.c | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/tests/posix/headers/src/pthread_h.c b/tests/posix/headers/src/pthread_h.c index b249c337c18..0ff56ea7cf0 100644 --- a/tests/posix/headers/src/pthread_h.c +++ b/tests/posix/headers/src/pthread_h.c @@ -152,10 +152,11 @@ ZTEST(posix_headers, test_pthread_h) zassert_not_null(pthread_setschedparam); /* zassert_not_null(pthread_setschedprio); */ /* not implemented */ zassert_not_null(pthread_setspecific); - /* zassert_not_null(pthread_spin_destroy); */ /* not implemented */ - /* zassert_not_null(pthread_spin_init); */ /* not implemented */ - /* zassert_not_null(pthread_spin_lock); */ /* not implemented */ - /* zassert_not_null(pthread_spin_unlock); */ /* not implemented */ + zassert_not_null(pthread_spin_destroy); + zassert_not_null(pthread_spin_init); + zassert_not_null(pthread_spin_lock); + zassert_not_null(pthread_spin_trylock); + zassert_not_null(pthread_spin_unlock); /* zassert_not_null(pthread_testcancel); */ /* not implemented */ } } From 505e9be2e1ed8df662ba7a9c96e5d0503a6852d1 Mon Sep 17 00:00:00 2001 From: Christopher Friedt Date: Wed, 22 Nov 2023 22:07:42 -0500 Subject: [PATCH 0201/3723] tests: posix: headers: ensure pthread_condattr_getclock() exist These calls were added some time ago, so ensure they are checked for existence. * pthread_condattr_getclock() * pthread_condattr_setclock() Signed-off-by: Christopher Friedt --- tests/posix/headers/src/pthread_h.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/tests/posix/headers/src/pthread_h.c b/tests/posix/headers/src/pthread_h.c index 0ff56ea7cf0..08cf465a823 100644 --- a/tests/posix/headers/src/pthread_h.c +++ b/tests/posix/headers/src/pthread_h.c @@ -94,10 +94,10 @@ ZTEST(posix_headers, test_pthread_h) zassert_not_null(pthread_cond_timedwait); zassert_not_null(pthread_cond_wait); zassert_not_null(pthread_condattr_destroy); - /* zassert_not_null(pthread_condattr_getclock); */ /* not implemented */ + zassert_not_null(pthread_condattr_getclock); /* zassert_not_null(pthread_condattr_getpshared); */ /* not implemented */ zassert_not_null(pthread_condattr_init); - /* zassert_not_null(pthread_condattr_setclock); */ /* not implemented */ + zassert_not_null(pthread_condattr_setclock); /* zassert_not_null(pthread_condattr_setpshared); */ /* not implemented */ zassert_not_null(pthread_create); zassert_not_null(pthread_detach); From 19ef279dc3bd6365b8e8b538b2a5f9270764fc9b Mon Sep 17 00:00:00 2001 From: Christopher Friedt Date: Wed, 22 Nov 2023 22:12:54 -0500 Subject: [PATCH 0202/3723] posix: define PTHREAD_CANCELED globally Move the definition of PTHREAD_CANCELED from pthread.c to pthread.h. Signed-off-by: Christopher Friedt --- include/zephyr/posix/pthread.h | 1 + lib/posix/pthread.c | 3 +-- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/include/zephyr/posix/pthread.h b/include/zephyr/posix/pthread.h index 2f942f6553c..c8c1f16f292 100644 --- a/include/zephyr/posix/pthread.h +++ b/include/zephyr/posix/pthread.h @@ -30,6 +30,7 @@ extern "C" { #define PTHREAD_PROCESS_SHARED 1 /* Pthread cancellation */ +#define PTHREAD_CANCELED ((void *)-1) #define _PTHREAD_CANCEL_POS 0 #define PTHREAD_CANCEL_ENABLE (0U << _PTHREAD_CANCEL_POS) #define PTHREAD_CANCEL_DISABLE BIT(_PTHREAD_CANCEL_POS) diff --git a/lib/posix/pthread.c b/lib/posix/pthread.c index 5566fc6616b..686b4195f9c 100644 --- a/lib/posix/pthread.c +++ b/lib/posix/pthread.c @@ -25,8 +25,7 @@ LOG_MODULE_REGISTER(pthread, CONFIG_PTHREAD_LOG_LEVEL); #define DYNAMIC_STACK_SIZE 0 #endif -#define PTHREAD_INIT_FLAGS PTHREAD_CANCEL_ENABLE -#define PTHREAD_CANCELED ((void *) -1) +#define PTHREAD_INIT_FLAGS PTHREAD_CANCEL_ENABLE enum posix_thread_qid { /* ready to be started via pthread_create() */ From d2e729233db6b9316fbe66b9f41b35494f584bda Mon Sep 17 00:00:00 2001 From: Christopher Friedt Date: Wed, 22 Nov 2023 22:13:49 -0500 Subject: [PATCH 0203/3723] tests: posix: headers: add verification tests for more constants Ensure that the "headers" test checks that the following constants are defined: * PTHREAD_PROCESS_SHARED * PTHREAD_PROCESS_PRIVATE * PTHREAD_COND_INITIALIZER * PTHREAD_MUTEX_INITIALIZER * PTHREAD_CANCELED They were already defined by previous commits, but the test had not been updated. Signed-off-by: Christopher Friedt --- tests/posix/headers/src/pthread_h.c | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/tests/posix/headers/src/pthread_h.c b/tests/posix/headers/src/pthread_h.c index 08cf465a823..51452d88de5 100644 --- a/tests/posix/headers/src/pthread_h.c +++ b/tests/posix/headers/src/pthread_h.c @@ -28,7 +28,7 @@ ZTEST(posix_headers, test_pthread_h) /* zassert_not_equal(-1, PTHREAD_CANCEL_DEFERRED); */ /* not implemented */ zassert_not_equal(-1, PTHREAD_CANCEL_DISABLE); - /* zassert_not_equal(-1, PTHREAD_CANCELED); */ /* not implemented */ + zassert_not_equal((void *)-42, PTHREAD_CANCELED); zassert_not_equal(-1, PTHREAD_CREATE_DETACHED); zassert_not_equal(-1, PTHREAD_CREATE_JOINABLE); @@ -49,14 +49,14 @@ ZTEST(posix_headers, test_pthread_h) zassert_not_equal(-1, PTHREAD_PRIO_NONE); /* zassert_not_equal(-1, PTHREAD_PRIO_PROTECT); */ /* not implemented */ - /* zassert_not_equal(-1, PTHREAD_PROCESS_SHARED); */ /* not implemented */ - /* zassert_not_equal(-1, PTHREAD_PROCESS_PRIVATE); */ /* not implemented */ + zassert_not_equal(-1, PTHREAD_PROCESS_SHARED); + zassert_not_equal(-1, PTHREAD_PROCESS_PRIVATE); /* zassert_not_equal(-1, PTHREAD_SCOPE_PROCESS); */ /* not implemented */ /* zassert_not_equal(-1, PTHREAD_SCOPE_SYSTEM); */ /* not implemented */ - /* pthread_cond_t cond = PTHREAD_COND_INITIALIZER; */ /* not implemented */ - /* pthread_mutex_t mu = PTHREAD_MUTEX_INITIALIZER; */ /* not implemented */ + pthread_cond_t cond = PTHREAD_COND_INITIALIZER; + pthread_mutex_t mu = PTHREAD_MUTEX_INITIALIZER; /* pthread_rwlock_t lock = PTHREAD_RWLOCK_INITIALIZER; */ /* not implemented */ if (IS_ENABLED(CONFIG_POSIX_API)) { From 87635dd34ae095ebd7cdc4c754c998c7d3768e8c Mon Sep 17 00:00:00 2001 From: Christopher Friedt Date: Wed, 22 Nov 2023 22:23:44 -0500 Subject: [PATCH 0204/3723] posix: do not define _PTHREAD_CANCEL_POS _PTHREAD_CANCEL_POS is an implementation detail and should not be defined in the global scope. Furthermore, _PTHREAD_CANCEL_POS uses a reserved identifier (underscore followed by capital letter). Adjust definitions so that the implementation detail is only used in the implementation and not in the interface. Additionally, modify naming so that the non-standard macro does not use a reserved identifier. Signed-off-by: Christopher Friedt --- include/zephyr/posix/pthread.h | 7 +++---- lib/posix/pthread.c | 5 ++++- 2 files changed, 7 insertions(+), 5 deletions(-) diff --git a/include/zephyr/posix/pthread.h b/include/zephyr/posix/pthread.h index c8c1f16f292..c7909d40ae2 100644 --- a/include/zephyr/posix/pthread.h +++ b/include/zephyr/posix/pthread.h @@ -30,10 +30,9 @@ extern "C" { #define PTHREAD_PROCESS_SHARED 1 /* Pthread cancellation */ -#define PTHREAD_CANCELED ((void *)-1) -#define _PTHREAD_CANCEL_POS 0 -#define PTHREAD_CANCEL_ENABLE (0U << _PTHREAD_CANCEL_POS) -#define PTHREAD_CANCEL_DISABLE BIT(_PTHREAD_CANCEL_POS) +#define PTHREAD_CANCELED ((void *)-1) +#define PTHREAD_CANCEL_ENABLE 0 +#define PTHREAD_CANCEL_DISABLE 1 /* Passed to pthread_once */ #define PTHREAD_ONCE_INIT \ diff --git a/lib/posix/pthread.c b/lib/posix/pthread.c index 686b4195f9c..e96cfc287e0 100644 --- a/lib/posix/pthread.c +++ b/lib/posix/pthread.c @@ -16,6 +16,7 @@ #include #include #include +#include LOG_MODULE_REGISTER(pthread, CONFIG_PTHREAD_LOG_LEVEL); @@ -25,6 +26,8 @@ LOG_MODULE_REGISTER(pthread, CONFIG_PTHREAD_LOG_LEVEL); #define DYNAMIC_STACK_SIZE 0 #endif +#define _pthread_cancel_pos LOG2(PTHREAD_CANCEL_DISABLE) + #define PTHREAD_INIT_FLAGS PTHREAD_CANCEL_ENABLE enum posix_thread_qid { @@ -406,7 +409,7 @@ int pthread_create(pthread_t *th, const pthread_attr_t *_attr, void *(*threadrou sys_dlist_append(&run_q, &t->q_node); t->qid = POSIX_THREAD_RUN_Q; t->detachstate = attr->detachstate; - if ((BIT(_PTHREAD_CANCEL_POS) & attr->flags) != 0) { + if ((BIT(_pthread_cancel_pos) & attr->flags) != 0) { t->cancel_state = PTHREAD_CANCEL_ENABLE; } t->cancel_pending = false; From ca45155a23f7ad32bb0b2492ee8c70def1efd9bf Mon Sep 17 00:00:00 2001 From: Vinayak Kariappa Chettimada Date: Mon, 20 Nov 2023 10:03:16 +0100 Subject: [PATCH 0205/3723] Bluetooth: Controller: Fix NULL pointer dereferencing in Sync ISO Fix NULL pointer dereferencing when Host supplies an out of bounds BIG handle. Signed-off-by: Vinayak Kariappa Chettimada --- subsys/bluetooth/controller/ll_sw/ull_sync_iso.c | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/subsys/bluetooth/controller/ll_sw/ull_sync_iso.c b/subsys/bluetooth/controller/ll_sw/ull_sync_iso.c index 513ee3cdbed..2287a2bc356 100644 --- a/subsys/bluetooth/controller/ll_sw/ull_sync_iso.c +++ b/subsys/bluetooth/controller/ll_sw/ull_sync_iso.c @@ -91,6 +91,16 @@ uint8_t ll_big_sync_create(uint8_t big_handle, uint16_t sync_handle, } sync_iso = sync_iso_get(big_handle); + if (!sync_iso) { + /* Host requested more than supported number of ISO Synchronized + * Receivers. + * Or probably HCI handles where not translated to zero-indexed + * controller handles? + */ + return BT_HCI_ERR_MEM_CAPACITY_EXCEEDED; + } + + /* Check if this ISO already is associated with a Periodic Sync */ if (sync_iso->sync) { return BT_HCI_ERR_CMD_DISALLOWED; } From 6c7c5bd5dd1ce6450ae3017cf5e5e10b323e9351 Mon Sep 17 00:00:00 2001 From: Vinayak Kariappa Chettimada Date: Wed, 22 Nov 2023 10:43:23 +0100 Subject: [PATCH 0206/3723] Bluetooth: Controller: Fix uninitialized ad_len_chain variable Fix uninitialized ad_len_chain variable. Signed-off-by: Vinayak Kariappa Chettimada --- .../bluetooth/controller/ll_sw/ull_adv_sync.c | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) diff --git a/subsys/bluetooth/controller/ll_sw/ull_adv_sync.c b/subsys/bluetooth/controller/ll_sw/ull_adv_sync.c index 5fec8a37534..897a39ce65f 100644 --- a/subsys/bluetooth/controller/ll_sw/ull_adv_sync.c +++ b/subsys/bluetooth/controller/ll_sw/ull_adv_sync.c @@ -403,6 +403,14 @@ uint8_t ll_adv_sync_ad_data_set(uint8_t handle, uint8_t op, uint8_t len, /* No AD data overflow */ ad_len_overflow = 0U; + + /* No chain PDU. + * Note: Not required to assign as referencing + * is guarded by the fact that ad_len_overflow + * is zero; having the below to make compilers + * not complain of uninitialized variable. + */ + ad_len_chain = 0U; } } } else { @@ -484,7 +492,16 @@ uint8_t ll_adv_sync_ad_data_set(uint8_t handle, uint8_t op, uint8_t len, /* Proceed to add chain PDU */ err = 0U; } else { + /* No AD data overflow */ ad_len_overflow = 0U; + + /* No chain PDU. + * Note: Not required to assign as referencing is + * guarded by the fact that ad_len_overflow is zero; + * having the below to make compilers not complain of + * uninitialized variable. + */ + ad_len_chain = 0U; } #endif /* CONFIG_BT_CTLR_ADV_SYNC_PDU_LINK */ } From 4cb194f3e8f64908f9e2f7d08a08fbca71cb73bc Mon Sep 17 00:00:00 2001 From: Nikolay Agishev Date: Fri, 17 Nov 2023 13:27:46 +0300 Subject: [PATCH 0207/3723] ARC: MWDT: Force cleanup .device_states section This PR fixes https://github.com/zephyrproject-rtos/zephyr/issues/64268 MWDT supposes .device_states section as BSS because .device_states variables defined as uninitialized. This causes the section marked as NOLOAD section and OpenOCD does not take it in account while flashing it into board memory. Finally .device_states variables becomes initialized with garbage from RAM. In this PR it's suggested to clean .device_states in early init stage. Signed-off-by: Nikolay Agishev --- arch/arc/core/prep_c.c | 19 ++++++++++++++++++- 1 file changed, 18 insertions(+), 1 deletion(-) diff --git a/arch/arc/core/prep_c.c b/arch/arc/core/prep_c.c index 8bf481c86b2..f0b31a2bb36 100644 --- a/arch/arc/core/prep_c.c +++ b/arch/arc/core/prep_c.c @@ -23,7 +23,6 @@ #include #include - /* XXX - keep for future use in full-featured cache APIs */ #if 0 /** @@ -67,6 +66,21 @@ static void invalidate_dcache(void) } #endif +#ifdef __CCAC__ +extern char __device_states_start[]; +extern char __device_states_end[]; +/** + * @brief Clear device_states section + * + * This routine clears the device_states section, + * as MW compiler marks the section with NOLOAD flag. + */ +static void dev_state_zero(void) +{ + z_early_memset(__device_states_start, 0, __device_states_end - __device_states_start); +} +#endif + extern FUNC_NORETURN void z_cstart(void); /** * @brief Prepare to and run C code @@ -77,6 +91,9 @@ extern FUNC_NORETURN void z_cstart(void); void _PrepC(void) { z_bss_zero(); +#ifdef __CCAC__ + dev_state_zero(); +#endif z_data_copy(); z_cstart(); CODE_UNREACHABLE; From 2ba6bcf90612fe8267eea5821c3449bd0ee647b5 Mon Sep 17 00:00:00 2001 From: Anas Nashif Date: Wed, 22 Nov 2023 16:30:10 -0500 Subject: [PATCH 0208/3723] twister: measure build time and report it in json output Measure both cmake and make/ninja build times and log them in debug mode and additionally put the result in the json report for tracking build times. Cleanup what build/cmake function return and remove unused keys in the result map. Remove some excessive logging of launched jobs or default platforms that gets in the way when in debug mode. Signed-off-by: Anas Nashif --- scripts/pylib/twister/twisterlib/reports.py | 1 + scripts/pylib/twister/twisterlib/runner.py | 66 ++++++++++--------- .../pylib/twister/twisterlib/testinstance.py | 1 + scripts/pylib/twister/twisterlib/testplan.py | 1 - 4 files changed, 38 insertions(+), 31 deletions(-) diff --git a/scripts/pylib/twister/twisterlib/reports.py b/scripts/pylib/twister/twisterlib/reports.py index be1bbb4dbd7..4895fdfe170 100644 --- a/scripts/pylib/twister/twisterlib/reports.py +++ b/scripts/pylib/twister/twisterlib/reports.py @@ -304,6 +304,7 @@ def json_report(self, filename, version="NA"): if instance.status is not None: suite["execution_time"] = f"{float(handler_time):.2f}" + suite["build_time"] = f"{float(instance.build_time):.2f}" testcases = [] diff --git a/scripts/pylib/twister/twisterlib/runner.py b/scripts/pylib/twister/twisterlib/runner.py index 3471f6bf702..e3e6562d437 100644 --- a/scripts/pylib/twister/twisterlib/runner.py +++ b/scripts/pylib/twister/twisterlib/runner.py @@ -263,27 +263,31 @@ def run_build(self, args=[]): if self.cwd: kwargs['cwd'] = self.cwd + start_time = time.time() if sys.platform == 'linux': p = self.jobserver.popen(cmd, **kwargs) else: p = subprocess.Popen(cmd, **kwargs) + logger.debug(f'Running {"".join(cmd)}') out, _ = p.communicate() - results = {} + ret = {} + duration = time.time() - start_time + self.instance.build_time += duration if p.returncode == 0: - msg = "Finished building %s for %s" % (self.source_dir, self.platform.name) + msg = f"Finished building {self.source_dir} for {self.platform.name} in {duration:.2f} seconds" + logger.debug(msg) self.instance.status = "passed" if not self.instance.run: self.instance.add_missing_case_status("skipped", "Test was built only") - results = {'msg': msg, "returncode": p.returncode, "instance": self.instance} + ret = {"returncode": p.returncode} if out: log_msg = out.decode(self.default_encoding) with open(os.path.join(self.build_dir, self.log), "a", encoding=self.default_encoding) as log: log.write(log_msg) - else: return None else: @@ -310,12 +314,11 @@ def run_build(self, args=[]): self.instance.status = "error" self.instance.reason = "Build failure" - results = { - "returncode": p.returncode, - "instance": self.instance, + ret = { + "returncode": p.returncode } - return results + return ret def run_cmake(self, args="", filter_stages=[]): @@ -384,18 +387,24 @@ def run_cmake(self, args="", filter_stages=[]): if self.cwd: kwargs['cwd'] = self.cwd + start_time = time.time() if sys.platform == 'linux': p = self.jobserver.popen(cmd, **kwargs) else: p = subprocess.Popen(cmd, **kwargs) out, _ = p.communicate() + duration = time.time() - start_time + self.instance.build_time += duration + if p.returncode == 0: filter_results = self.parse_generated(filter_stages) - msg = "Finished building %s for %s" % (self.source_dir, self.platform.name) + msg = f"Finished running cmake {self.source_dir} for {self.platform.name} in {duration:.2f} seconds" logger.debug(msg) - results = {'msg': msg, 'filter': filter_results} - + ret = { + 'returncode': p.returncode, + 'filter': filter_results + } else: self.instance.status = "error" self.instance.reason = "Cmake build failure" @@ -404,7 +413,7 @@ def run_cmake(self, args="", filter_stages=[]): tc.status = self.instance.status logger.error("Cmake build failure: %s for %s" % (self.source_dir, self.platform.name)) - results = {"returncode": p.returncode} + ret = {"returncode": p.returncode} if out: os.makedirs(self.build_dir, exist_ok=True) @@ -412,7 +421,7 @@ def run_cmake(self, args="", filter_stages=[]): log_msg = out.decode(self.default_encoding) log.write(log_msg) - return results + return ret class FilterBuilder(CMake): @@ -502,14 +511,14 @@ def parse_generated(self, filter_stages=[]): edt = pickle.load(f) else: edt = None - res = expr_parser.parse(self.testsuite.filter, filter_data, edt) + ret = expr_parser.parse(self.testsuite.filter, filter_data, edt) except (ValueError, SyntaxError) as se: sys.stderr.write( "Failed processing %s\n" % self.testsuite.yamlfile) raise se - if not res: + if not ret: return {os.path.join(self.platform.name, self.testsuite.name): True} else: return {os.path.join(self.platform.name, self.testsuite.name): False} @@ -584,12 +593,12 @@ def process(self, pipeline, done, message, lock, results): self.instance.setup_handler(self.env) if op == "filter": - res = self.cmake(filter_stages=self.instance.filter_stages) + ret = self.cmake(filter_stages=self.instance.filter_stages) if self.instance.status in ["failed", "error"]: pipeline.put({"op": "report", "test": self.instance}) else: # Here we check the dt/kconfig filter results coming from running cmake - if self.instance.name in res['filter'] and res['filter'][self.instance.name]: + if self.instance.name in ret['filter'] and ret['filter'][self.instance.name]: logger.debug("filtering %s" % self.instance.name) self.instance.status = "filtered" self.instance.reason = "runtime filter" @@ -600,8 +609,8 @@ def process(self, pipeline, done, message, lock, results): pipeline.put({"op": "cmake", "test": self.instance}) # The build process, call cmake and build with configured generator - if op == "cmake": - res = self.cmake() + elif op == "cmake": + ret = self.cmake() if self.instance.status in ["failed", "error"]: pipeline.put({"op": "report", "test": self.instance}) elif self.options.cmake_only: @@ -610,7 +619,7 @@ def process(self, pipeline, done, message, lock, results): pipeline.put({"op": "report", "test": self.instance}) else: # Here we check the runtime filter results coming from running cmake - if self.instance.name in res['filter'] and res['filter'][self.instance.name]: + if self.instance.name in ret['filter'] and ret['filter'][self.instance.name]: logger.debug("filtering %s" % self.instance.name) self.instance.status = "filtered" self.instance.reason = "runtime filter" @@ -622,8 +631,8 @@ def process(self, pipeline, done, message, lock, results): elif op == "build": logger.debug("build test: %s" % self.instance.name) - res = self.build() - if not res: + ret = self.build() + if not ret: self.instance.status = "error" self.instance.reason = "Build Failure" pipeline.put({"op": "report", "test": self.instance}) @@ -634,7 +643,7 @@ def process(self, pipeline, done, message, lock, results): results.skipped_runtime += 1 self.instance.add_missing_case_status("skipped", self.instance.reason) - if res.get('returncode', 1) > 0: + if ret.get('returncode', 1) > 0: self.instance.add_missing_case_status("blocked", self.instance.reason) pipeline.put({"op": "report", "test": self.instance}) else: @@ -1040,13 +1049,10 @@ def cmake(self, filter_stages=[]): self.options.extra_args, # CMake extra args self.instance.build_dir, ) - - res = self.run_cmake(args,filter_stages) - return res + return self.run_cmake(args,filter_stages) def build(self): - res = self.run_build(['--build', self.build_dir]) - return res + return self.run_build(['--build', self.build_dir]) def run(self): @@ -1289,11 +1295,11 @@ def execute(self, pipeline, done): processes = [] - for job in range(self.jobs): - logger.debug(f"Launch process {job}") + for _ in range(self.jobs): p = Process(target=self.pipeline_mgr, args=(pipeline, done, lock, self.results, )) processes.append(p) p.start() + logger.debug(f"Launched {self.jobs} jobs") try: for p in processes: diff --git a/scripts/pylib/twister/twisterlib/testinstance.py b/scripts/pylib/twister/twisterlib/testinstance.py index 958019b411a..d3cbbaf4986 100644 --- a/scripts/pylib/twister/twisterlib/testinstance.py +++ b/scripts/pylib/twister/twisterlib/testinstance.py @@ -50,6 +50,7 @@ def __init__(self, testsuite, platform, outdir): self.handler = None self.outdir = outdir self.execution_time = 0 + self.build_time = 0 self.retries = 0 self.name = os.path.join(platform.name, testsuite.name) diff --git a/scripts/pylib/twister/twisterlib/testplan.py b/scripts/pylib/twister/twisterlib/testplan.py index 930d4573b19..64de8864711 100755 --- a/scripts/pylib/twister/twisterlib/testplan.py +++ b/scripts/pylib/twister/twisterlib/testplan.py @@ -416,7 +416,6 @@ def add_configurations(self): self.platforms.append(platform) if not platform_config.get('override_default_platforms', False): if platform.default: - logger.debug(f"adding {platform.name} to default platforms") self.default_platforms.append(platform.name) else: if platform.name in platform_config.get('default_platforms', []): From c696344f0d55009e05f049fe5a597a886dde16bd Mon Sep 17 00:00:00 2001 From: Anas Nashif Date: Thu, 23 Nov 2023 07:32:27 -0500 Subject: [PATCH 0209/3723] twister: tests: adapt tests for new behaviour in runner class We have removed some return data and added build time to instance class. Signed-off-by: Anas Nashif --- scripts/tests/twister/test_runner.py | 40 +++++++++------------------- 1 file changed, 12 insertions(+), 28 deletions(-) diff --git a/scripts/tests/twister/test_runner.py b/scripts/tests/twister/test_runner.py index f0c2cbb50cf..e4d886191fd 100644 --- a/scripts/tests/twister/test_runner.py +++ b/scripts/tests/twister/test_runner.py @@ -250,20 +250,20 @@ def test_cmake_parse_generated(mocked_jobserver): ] TESTDATA_1_2 = [ (0, False, 'dummy out', - True, True, True, True, 'passed', None, False, True), + True, True, 'passed', None, False, True), (0, True, '', - False, False, False, False, 'passed', None, False, False), + False, False, 'passed', None, False, False), (1, True, 'ERROR: region `FLASH\' overflowed by 123 MB', - False, True, True, True, 'skipped', 'FLASH overflow', True, False), + True, True, 'skipped', 'FLASH overflow', True, False), (1, True, 'Error: Image size (99 B) + trailer (1 B) exceeds requested size', - False, True, True, True, 'skipped', 'imgtool overflow', True, False), + True, True, 'skipped', 'imgtool overflow', True, False), (1, True, 'mock.ANY', - False, True, True, True, 'error', 'Build failure', False, False) + True, True, 'error', 'Build failure', False, False) ] @pytest.mark.parametrize( - 'return_code, is_instance_run, p_out, expect_msg, expect_returncode,' \ - ' expect_instance, expect_writes, expected_status, expected_reason,' \ + 'return_code, is_instance_run, p_out, expect_returncode,' \ + ' expect_writes, expected_status, expected_reason,' \ ' expected_change_skip, expected_add_missing', TESTDATA_1_2, ids=['no error, no instance run', 'no error, instance run', @@ -275,9 +275,7 @@ def test_cmake_run_build( return_code, is_instance_run, p_out, - expect_msg, expect_returncode, - expect_instance, expect_writes, expected_status, expected_reason, @@ -303,6 +301,7 @@ def mock_popen(*args, **kwargs): popen=mock.Mock(side_effect=mock_popen) ) instance_mock = mock.Mock(add_missing_case_status=mock.Mock()) + instance_mock.build_time = 0 instance_mock.run = is_instance_run instance_mock.status = None instance_mock.reason = None @@ -328,14 +327,8 @@ def mock_popen(*args, **kwargs): result = cmake.run_build(args=['arg1', 'arg2']) expected_results = {} - if expect_msg: - expected_results['msg'] = 'Finished building %s for %s' % \ - (os.path.join('source', 'dir'), \ - '') if expect_returncode: expected_results['returncode'] = return_code - if expect_instance: - expected_results['instance'] = instance_mock if expected_results == {}: expected_results = None @@ -369,7 +362,7 @@ def mock_popen(*args, **kwargs): TESTDATA_2_2 = [ (True, ['dummy_stage_1', 'ds2'], 0, False, '', - True, False, True, False, + True, True, False, None, None, [os.path.join('dummy', 'cmake'), '-B' + os.path.join('build', 'dir'), '-DTC_RUNID=1', @@ -383,7 +376,7 @@ def mock_popen(*args, **kwargs): '-Pzephyr_base/cmake/package_helper.cmake']), (False, [], 1, True, 'ERROR: region `FLASH\' overflowed by 123 MB', - False, True, False, True, + True, False, True, 'error', 'Cmake build failure', [os.path.join('dummy', 'cmake'), '-B' + os.path.join('build', 'dir'), '-DTC_RUNID=1', @@ -398,7 +391,7 @@ def mock_popen(*args, **kwargs): @pytest.mark.parametrize( 'error_warns, f_stages,' \ - ' return_code, is_instance_run, p_out, expect_msg, expect_returncode,' \ + ' return_code, is_instance_run, p_out, expect_returncode,' \ ' expect_filter, expect_writes, expected_status, expected_reason,' \ ' expected_cmd', TESTDATA_2_2, @@ -412,7 +405,6 @@ def test_cmake_run_cmake( return_code, is_instance_run, p_out, - expect_msg, expect_returncode, expect_filter, expect_writes, @@ -442,6 +434,7 @@ def mock_popen(*args, **kwargs): instance_mock = mock.Mock(add_missing_case_status=mock.Mock()) instance_mock.run = is_instance_run instance_mock.run_id = 1 + instance_mock.build_time = 0 instance_mock.status = None instance_mock.reason = None instance_mock.testsuite = mock.Mock() @@ -476,10 +469,6 @@ def mock_popen(*args, **kwargs): result = cmake.run_cmake(args=['arg1', 'arg2'], filter_stages=f_stages) expected_results = {} - if expect_msg: - expected_results['msg'] = 'Finished building %s for %s' % \ - (os.path.join('source', 'dir'), \ - '') if expect_returncode: expected_results['returncode'] = return_code if expect_filter: @@ -2650,11 +2639,6 @@ def mock_join(): with mock.patch('twisterlib.runner.Process', process_mock): tr.execute(pipeline_mock, done_mock) - assert 'Launch process 0' in caplog.text - assert 'Launch process 1' in caplog.text - assert 'Launch process 2' in caplog.text - assert 'Launch process 3' in caplog.text - assert 'Launch process 4' in caplog.text assert 'Execution interrupted' in caplog.text assert len(process_mock().start.call_args_list) == 5 From eb879413be488d441ea2e48084dc77852045b2df Mon Sep 17 00:00:00 2001 From: Aymeric Aillet Date: Mon, 17 Jul 2023 15:43:05 +0200 Subject: [PATCH 0210/3723] drivers: gpio: rcar: Add R-Car Gen4 support Renesas Gen4 SoCs GPIO IPs are using one more register comparing to Gen3 SoCs. The new "INEN" register is used to enable general input. Signed-off-by: Aymeric Aillet --- drivers/gpio/gpio_rcar.c | 13 ++++++++++++- 1 file changed, 12 insertions(+), 1 deletion(-) diff --git a/drivers/gpio/gpio_rcar.c b/drivers/gpio/gpio_rcar.c index 820db5fc76c..f60112427bc 100644 --- a/drivers/gpio/gpio_rcar.c +++ b/drivers/gpio/gpio_rcar.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2020 IoT.bzh + * Copyright (c) 2020-2023 IoT.bzh * * SPDX-License-Identifier: Apache-2.0 */ @@ -52,6 +52,7 @@ struct gpio_rcar_data { #define FILONOFF 0x28 /* Chattering Prevention On/Off Register */ #define OUTDTSEL 0x40 /* Output Data Select Register */ #define BOTHEDGE 0x4c /* One Edge/Both Edge Select Register */ +#define INEN 0x50 /* General Input Enable Register */ static inline uint32_t gpio_rcar_read(const struct device *dev, uint32_t offs) { @@ -106,6 +107,11 @@ static void gpio_rcar_config_general_input_output_mode( /* Configure positive logic in POSNEG */ gpio_rcar_modify_bit(dev, POSNEG, gpio, false); + /* Select "Input Enable/Disable" in INEN for Gen4 SoCs */ +#ifdef CONFIG_SOC_SERIES_RCAR_GEN4 + gpio_rcar_modify_bit(dev, INEN, gpio, !output); +#endif + /* Select "General Input/Output Mode" in IOINTSEL */ gpio_rcar_modify_bit(dev, IOINTSEL, gpio, false); @@ -223,6 +229,11 @@ static int gpio_rcar_pin_interrupt_configure(const struct device *dev, gpio_rcar_modify_bit(dev, BOTHEDGE, pin, true); } + /* Select "Input Enable" in INEN for Gen4 SoCs */ +#ifdef CONFIG_SOC_SERIES_RCAR_GEN4 + gpio_rcar_modify_bit(dev, INEN, pin, true); +#endif + gpio_rcar_modify_bit(dev, IOINTSEL, pin, true); if (mode == GPIO_INT_MODE_EDGE) { From 1738543c5d15d31be4d98f952a23395f23e27fa5 Mon Sep 17 00:00:00 2001 From: Aymeric Aillet Date: Tue, 18 Jul 2023 13:53:24 +0200 Subject: [PATCH 0211/3723] drivers: pinctrl: Add R-Car Gen4 support Renesas R-Car Gen4 is different from Gen3 regarding pinmux. While Gen3 had only one base address to manage all pins, Gen4 has one set of pinmux registers per GPIO banks. We could expose one pinmux register per GPIO controllers, but that would break potential compatibility with Linux Device tree. Instead create a reg_base array to parse all reg base from device tree and identify proper base address based on the pin definition. This imply to add a pfc_base parameter to most of the pfc_rcar function. Signed-off-by: Julien Massot Signed-off-by: Pierre Marzin Signed-off-by: Aymeric Aillet --- drivers/pinctrl/pfc_rcar.c | 95 ++++++++++----- drivers/pinctrl/pfc_rcar.h | 26 ++++ .../pinctrl/renesas/pinctrl-rcar-common.h | 34 +++++- soc/arm/renesas_rcar/CMakeLists.txt | 1 + soc/arm/renesas_rcar/common/pinctrl_rcar.h | 115 ++++++++++++++++++ soc/arm/renesas_rcar/gen3/pfc_r8a77951.c | 10 +- soc/arm/renesas_rcar/gen3/pinctrl_soc.h | 109 +---------------- soc/arm/renesas_rcar/gen4/CMakeLists.txt | 2 + soc/arm/renesas_rcar/gen4/pinctrl_soc.h | 12 ++ soc/arm64/renesas_rcar/gen3/pfc_r8a77951.c | 7 ++ soc/arm64/renesas_rcar/gen3/pfc_r8a77961.c | 7 ++ soc/arm64/renesas_rcar/gen3/pinctrl_soc.h | 3 - 12 files changed, 281 insertions(+), 140 deletions(-) create mode 100644 drivers/pinctrl/pfc_rcar.h create mode 100644 soc/arm/renesas_rcar/common/pinctrl_rcar.h create mode 100644 soc/arm/renesas_rcar/gen4/CMakeLists.txt create mode 100644 soc/arm/renesas_rcar/gen4/pinctrl_soc.h diff --git a/drivers/pinctrl/pfc_rcar.c b/drivers/pinctrl/pfc_rcar.c index 17705e0a863..26c5d08c20b 100644 --- a/drivers/pinctrl/pfc_rcar.c +++ b/drivers/pinctrl/pfc_rcar.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2021 IoT.bzh + * Copyright (c) 2021-2023 IoT.bzh * * SPDX-License-Identifier: Apache-2.0 * @@ -7,6 +7,7 @@ #define DT_DRV_COMPAT renesas_rcar_pfc +#include "pfc_rcar.h" #include #include #include @@ -14,12 +15,25 @@ #include #include -DEVICE_MMIO_TOPLEVEL_STATIC(pfc, DT_DRV_INST(0)); - -#define PFC_REG_BASE DEVICE_MMIO_TOPLEVEL_GET(pfc) #define PFC_RCAR_PMMR 0x0 + +/* Gen3 only has one base address, Gen4 has one per GPIO controller */ +#if defined(CONFIG_SOC_SERIES_RCAR_GEN3) #define PFC_RCAR_GPSR 0x100 #define PFC_RCAR_IPSR 0x200 +DEVICE_MMIO_TOPLEVEL_STATIC(pfc, DT_DRV_INST(0)); +static uintptr_t reg_base[1]; +#elif defined(CONFIG_SOC_SERIES_RCAR_GEN4) +#define PFC_RCAR_GPSR 0x040 +#define PFC_RCAR_IPSR 0x060 +/* swap both arguments */ +#define PFC_REG_ADDRESS(idx, node_id) DT_REG_ADDR_BY_IDX(node_id, idx) +static const uintptr_t reg_base[] = { + LISTIFY(DT_NUM_REGS(DT_DRV_INST(0)), PFC_REG_ADDRESS, (,), DT_DRV_INST(0)) +}; +#else +#error Unsupported SoC Series +#endif /* * Each drive step is either encoded in 2 or 3 bits. @@ -33,18 +47,25 @@ DEVICE_MMIO_TOPLEVEL_STATIC(pfc, DT_DRV_INST(0)); /* Some registers such as IPSR GPSR or DRVCTRL are protected and * must be preceded to a write to PMMR with the inverse value. */ -static void pfc_rcar_write(uint32_t offs, uint32_t val) +static void pfc_rcar_write(uintptr_t pfc_base, uint32_t offs, uint32_t val) { - sys_write32(~val, PFC_REG_BASE + PFC_RCAR_PMMR); - sys_write32(val, PFC_REG_BASE + offs); + sys_write32(~val, pfc_base + PFC_RCAR_PMMR); + sys_write32(val, pfc_base + offs); } /* Set the pin either in gpio or peripheral */ -static void pfc_rcar_set_gpsr(uint16_t pin, bool peripheral) +static void pfc_rcar_set_gpsr(uintptr_t pfc_base, + uint16_t pin, bool peripheral) { +#if defined(CONFIG_SOC_SERIES_RCAR_GEN3) + /* On Gen3 we have multiple GPSR at one base address */ uint8_t bank = pin / 32; +#elif defined(CONFIG_SOC_SERIES_RCAR_GEN4) + /* On Gen4 we have one GPSR at multiple base address */ + uint8_t bank = 0; +#endif uint8_t bit = pin % 32; - uint32_t val = sys_read32(PFC_REG_BASE + PFC_RCAR_GPSR + + uint32_t val = sys_read32(pfc_base + PFC_RCAR_GPSR + bank * sizeof(uint32_t)); if (peripheral) { @@ -52,18 +73,19 @@ static void pfc_rcar_set_gpsr(uint16_t pin, bool peripheral) } else { val &= ~BIT(bit); } - pfc_rcar_write(PFC_RCAR_GPSR + bank * sizeof(uint32_t), val); + pfc_rcar_write(pfc_base, PFC_RCAR_GPSR + bank * sizeof(uint32_t), val); } /* Set peripheral function */ -static void pfc_rcar_set_ipsr(const struct rcar_pin_func *rcar_func) +static void pfc_rcar_set_ipsr(uintptr_t pfc_base, + const struct rcar_pin_func *rcar_func) { uint16_t reg_offs = PFC_RCAR_IPSR + rcar_func->bank * sizeof(uint32_t); - uint32_t val = sys_read32(PFC_REG_BASE + reg_offs); + uint32_t val = sys_read32(pfc_base + reg_offs); val &= ~(0xFU << rcar_func->shift); val |= (rcar_func->func << rcar_func->shift); - pfc_rcar_write(reg_offs, val); + pfc_rcar_write(pfc_base, reg_offs, val); } static uint32_t pfc_rcar_get_drive_reg(uint16_t pin, uint8_t *offset, @@ -90,7 +112,8 @@ static uint32_t pfc_rcar_get_drive_reg(uint16_t pin, uint8_t *offset, * using DRVCTRLx registers, some pins have 8 steps (3 bits size encoded) * some have 4 steps (2 bits size encoded). */ -static int pfc_rcar_set_drive_strength(uint16_t pin, uint8_t strength) +static int pfc_rcar_set_drive_strength(uintptr_t pfc_base, uint16_t pin, + uint8_t strength) { uint8_t offset, size, step; uint32_t reg, val; @@ -110,11 +133,11 @@ static int pfc_rcar_set_drive_strength(uint16_t pin, uint8_t strength) */ strength = (strength / step) - 1U; /* clear previous drive strength value */ - val = sys_read32(PFC_REG_BASE + reg); + val = sys_read32(pfc_base + reg); val &= ~GENMASK(offset + size - 1U, offset); val |= strength << offset; - pfc_rcar_write(reg, val); + pfc_rcar_write(pfc_base, reg, val); return 0; } @@ -138,7 +161,7 @@ static const struct pfc_bias_reg *pfc_rcar_get_bias_reg(uint16_t pin, return NULL; } -int pfc_rcar_set_bias(uint16_t pin, uint16_t flags) +int pfc_rcar_set_bias(uintptr_t pfc_base, uint16_t pin, uint16_t flags) { uint32_t val; uint8_t bit; @@ -149,19 +172,19 @@ int pfc_rcar_set_bias(uint16_t pin, uint16_t flags) } /* pull enable/disable*/ - val = sys_read32(PFC_REG_BASE + bias_reg->puen); + val = sys_read32(pfc_base + bias_reg->puen); if ((flags & RCAR_PIN_FLAGS_PUEN) == 0U) { - sys_write32(val & ~BIT(bit), PFC_REG_BASE + bias_reg->puen); + sys_write32(val & ~BIT(bit), pfc_base + bias_reg->puen); return 0; } - sys_write32(val | BIT(bit), PFC_REG_BASE + bias_reg->puen); + sys_write32(val | BIT(bit), pfc_base + bias_reg->puen); /* pull - up/down */ - val = sys_read32(PFC_REG_BASE + bias_reg->pud); + val = sys_read32(pfc_base + bias_reg->pud); if (flags & RCAR_PIN_FLAGS_PUD) { - sys_write32(val | BIT(bit), PFC_REG_BASE + bias_reg->pud); + sys_write32(val | BIT(bit), pfc_base + bias_reg->pud); } else { - sys_write32(val & ~BIT(bit), PFC_REG_BASE + bias_reg->pud); + sys_write32(val & ~BIT(bit), pfc_base + bias_reg->pud); } return 0; } @@ -169,10 +192,23 @@ int pfc_rcar_set_bias(uint16_t pin, uint16_t flags) int pinctrl_configure_pin(const pinctrl_soc_pin_t *pin) { int ret = 0; + uint8_t reg_index; + uintptr_t pfc_base; + + ret = pfc_rcar_get_reg_index(pin->pin, ®_index); + if (ret) { + return ret; + } + + if (reg_index >= ARRAY_SIZE(reg_base)) { + return -EINVAL; + } + + pfc_base = reg_base[reg_index]; /* Set pin as GPIO if capable */ if (RCAR_IS_GP_PIN(pin->pin)) { - pfc_rcar_set_gpsr(pin->pin, false); + pfc_rcar_set_gpsr(pfc_base, pin->pin, false); } else if ((pin->flags & RCAR_PIN_FLAGS_FUNC_SET) == 0U) { /* A function must be set for non GPIO capable pin */ return -EINVAL; @@ -180,14 +216,14 @@ int pinctrl_configure_pin(const pinctrl_soc_pin_t *pin) /* Select function for pin */ if ((pin->flags & RCAR_PIN_FLAGS_FUNC_SET) != 0U) { - pfc_rcar_set_ipsr(&pin->func); + pfc_rcar_set_ipsr(pfc_base, &pin->func); if (RCAR_IS_GP_PIN(pin->pin)) { - pfc_rcar_set_gpsr(pin->pin, true); + pfc_rcar_set_gpsr(pfc_base, pin->pin, true); } if ((pin->flags & RCAR_PIN_FLAGS_PULL_SET) != 0U) { - ret = pfc_rcar_set_bias(pin->pin, pin->flags); + ret = pfc_rcar_set_bias(pfc_base, pin->pin, pin->flags); if (ret < 0) { return ret; } @@ -195,7 +231,7 @@ int pinctrl_configure_pin(const pinctrl_soc_pin_t *pin) } if (pin->drive_strength != 0U) { - ret = pfc_rcar_set_drive_strength(pin->pin, + ret = pfc_rcar_set_drive_strength(pfc_base, pin->pin, pin->drive_strength); } @@ -218,10 +254,13 @@ int pinctrl_configure_pins(const pinctrl_soc_pin_t *pins, uint8_t pin_cnt, return ret; } +#if defined(CONFIG_SOC_SERIES_RCAR_GEN3) __boot_func static int pfc_rcar_driver_init(void) { DEVICE_MMIO_TOPLEVEL_MAP(pfc, K_MEM_CACHE_NONE); + reg_base[0] = DEVICE_MMIO_TOPLEVEL_GET(pfc); return 0; } SYS_INIT(pfc_rcar_driver_init, PRE_KERNEL_1, CONFIG_KERNEL_INIT_PRIORITY_DEFAULT); +#endif diff --git a/drivers/pinctrl/pfc_rcar.h b/drivers/pinctrl/pfc_rcar.h new file mode 100644 index 00000000000..cbef35ff76b --- /dev/null +++ b/drivers/pinctrl/pfc_rcar.h @@ -0,0 +1,26 @@ +/* + * Copyright (c) 2023 IoT.bzh + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#ifndef ZEPHYR_DRIVERS_PINCTRL_PFC_RCAR_H_ +#define ZEPHYR_DRIVERS_PINCTRL_PFC_RCAR_H_ + +#include +#include + +const struct pfc_bias_reg *pfc_rcar_get_bias_regs(void); +const struct pfc_drive_reg *pfc_rcar_get_drive_regs(void); + +/** + * @brief set the register index for a given pin + * + * @param the pin + * @param pointer for the resulting register index + * @return 0 if the register index is found, negative + * errno otherwise. + */ +int pfc_rcar_get_reg_index(uint8_t pin, uint8_t *reg_index); + +#endif /* ZEPHYR_DRIVERS_PINCTRL_PFC_RCAR_H_ */ diff --git a/include/zephyr/dt-bindings/pinctrl/renesas/pinctrl-rcar-common.h b/include/zephyr/dt-bindings/pinctrl/renesas/pinctrl-rcar-common.h index fc8d5090e84..504ee2a4d55 100644 --- a/include/zephyr/dt-bindings/pinctrl/renesas/pinctrl-rcar-common.h +++ b/include/zephyr/dt-bindings/pinctrl/renesas/pinctrl-rcar-common.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2021 IoT.bzh + * Copyright (c) 2021-2023 IoT.bzh * * SPDX-License-Identifier: Apache-2.0 */ @@ -40,4 +40,36 @@ */ #define RCAR_NOGP_PIN(pin) (PIN_NOGPSR_START + pin) +/* Renesas Gen4 has IPSR registers at different base address + * reg is here an index for the base address. + * Each base address has 4 IPSR banks. + */ +#define IPnSR(bank, reg, shift, func) \ + IPSR(((reg) << 4U) | (bank), shift, func) + +#define IP0SR0(shift, func) IPnSR(0, 0, shift, func) +#define IP1SR0(shift, func) IPnSR(1, 0, shift, func) +#define IP2SR0(shift, func) IPnSR(2, 0, shift, func) +#define IP3SR0(shift, func) IPnSR(3, 0, shift, func) +#define IP0SR1(shift, func) IPnSR(0, 1, shift, func) +#define IP1SR1(shift, func) IPnSR(1, 1, shift, func) +#define IP2SR1(shift, func) IPnSR(2, 1, shift, func) +#define IP3SR1(shift, func) IPnSR(3, 1, shift, func) +#define IP0SR2(shift, func) IPnSR(0, 2, shift, func) +#define IP1SR2(shift, func) IPnSR(1, 2, shift, func) +#define IP2SR2(shift, func) IPnSR(2, 2, shift, func) +#define IP3SR2(shift, func) IPnSR(3, 2, shift, func) +#define IP0SR3(shift, func) IPnSR(0, 3, shift, func) +#define IP1SR3(shift, func) IPnSR(1, 3, shift, func) +#define IP2SR3(shift, func) IPnSR(2, 3, shift, func) +#define IP3SR3(shift, func) IPnSR(3, 3, shift, func) +#define IP0SR4(shift, func) IPnSR(0, 4, shift, func) +#define IP1SR4(shift, func) IPnSR(1, 4, shift, func) +#define IP2SR4(shift, func) IPnSR(2, 4, shift, func) +#define IP3SR4(shift, func) IPnSR(3, 4, shift, func) +#define IP0SR5(shift, func) IPnSR(0, 5, shift, func) +#define IP1SR5(shift, func) IPnSR(1, 5, shift, func) +#define IP2SR5(shift, func) IPnSR(2, 5, shift, func) +#define IP3SR5(shift, func) IPnSR(3, 5, shift, func) + #endif /* ZEPHYR_INCLUDE_DT_BINDINGS_PINCTRL_RENESAS_PINCTRL_RCAR_COMMON_H_ */ diff --git a/soc/arm/renesas_rcar/CMakeLists.txt b/soc/arm/renesas_rcar/CMakeLists.txt index 226f3bd626f..20bed32f36a 100644 --- a/soc/arm/renesas_rcar/CMakeLists.txt +++ b/soc/arm/renesas_rcar/CMakeLists.txt @@ -1,3 +1,4 @@ # SPDX-License-Identifier: Apache-2.0 add_subdirectory(${SOC_SERIES}) +zephyr_include_directories(common) diff --git a/soc/arm/renesas_rcar/common/pinctrl_rcar.h b/soc/arm/renesas_rcar/common/pinctrl_rcar.h new file mode 100644 index 00000000000..0533649d413 --- /dev/null +++ b/soc/arm/renesas_rcar/common/pinctrl_rcar.h @@ -0,0 +1,115 @@ +/* + * Copyright (c) 2023 IoT.bzh + * + * SPDX-License-Identifier: Apache-2.0 + * + */ + +#ifndef ZEPHYR_SOC_ARM_RENESAS_RCAR_COMMON_PINCTRL_SOC_H_ +#define ZEPHYR_SOC_ARM_RENESAS_RCAR_COMMON_PINCTRL_SOC_H_ + +#include +#include +#include +#include + +struct rcar_pin_func { + uint8_t bank:5; /* bank number 0 - 18 */ + uint8_t shift:5; /* bit shift 0 - 28 */ + uint8_t func:4; /* choice from 0x0 to 0xF */ +}; + +/** Pull-up, pull-down, or bias disable is requested */ +#define RCAR_PIN_FLAGS_PULL_SET BIT(0) +/** Performs on/off control of the pull resistors */ +#define RCAR_PIN_FLAGS_PUEN BIT(1) +/** Select pull-up resistor if set pull-down otherwise */ +#define RCAR_PIN_FLAGS_PUD BIT(2) +/** Alternate function for the pin is requested */ +#define RCAR_PIN_FLAGS_FUNC_SET BIT(3) + +#define RCAR_PIN_PULL_UP (RCAR_PIN_FLAGS_PULL_SET | RCAR_PIN_FLAGS_PUEN | RCAR_PIN_FLAGS_PUD) +#define RCAR_PIN_PULL_DOWN (RCAR_PIN_FLAGS_PULL_SET | RCAR_PIN_FLAGS_PUEN) +#define RCAR_PIN_PULL_DISABLE RCAR_PIN_FLAGS_PULL_SET + +/** Type for R-Car pin. */ +typedef struct pinctrl_soc_pin { + uint16_t pin; + struct rcar_pin_func func; + uint8_t flags; + uint8_t drive_strength; +} pinctrl_soc_pin_t; + +#define RCAR_IPSR(node_id) DT_PROP_BY_IDX(node_id, pin, 1) +#define RCAR_HAS_IPSR(node_id) DT_PROP_HAS_IDX(node_id, pin, 1) + +/* Offsets are defined in dt-bindings pinctrl-rcar-common.h */ +#define RCAR_PIN_FUNC(node_id) \ + { \ + ((RCAR_IPSR(node_id) >> 10U) & 0x1FU), \ + ((RCAR_IPSR(node_id) >> 4U) & 0x1FU), \ + ((RCAR_IPSR(node_id) & 0xFU)) \ + } + +#define RCAR_PIN_FLAGS(node_id) \ + DT_PROP(node_id, bias_pull_up) * RCAR_PIN_PULL_UP | \ + DT_PROP(node_id, bias_pull_down) * RCAR_PIN_PULL_DOWN | \ + DT_PROP(node_id, bias_disable) * RCAR_PIN_PULL_DISABLE | \ + RCAR_HAS_IPSR(node_id) * RCAR_PIN_FLAGS_FUNC_SET + +#define RCAR_DT_PIN(node_id) \ + { \ + .pin = DT_PROP_BY_IDX(node_id, pin, 0), \ + .func = COND_CODE_1(RCAR_HAS_IPSR(node_id), \ + (RCAR_PIN_FUNC(node_id)), {0}), \ + .flags = RCAR_PIN_FLAGS(node_id), \ + .drive_strength = \ + COND_CODE_1(DT_NODE_HAS_PROP(node_id, drive_strength), \ + (DT_PROP(node_id, drive_strength)), (0)), \ + }, + +/** + * @brief Utility macro to initialize each pin. + * + * @param node_id Node identifier. + * @param state_prop State property name. + * @param idx State property entry index. + */ +#define Z_PINCTRL_STATE_PIN_INIT(node_id, state_prop, idx) \ + RCAR_DT_PIN(DT_PROP_BY_IDX(node_id, state_prop, idx)) + +/** + * @brief Utility macro to initialize state pins contained in a given property. + * + * @param node_id Node identifier. + * @param prop Property name describing state pins. + */ +#define Z_PINCTRL_STATE_PINS_INIT(node_id, prop) \ + { DT_FOREACH_PROP_ELEM(node_id, prop, Z_PINCTRL_STATE_PIN_INIT) } + +struct pfc_drive_reg_field { + uint16_t pin; + uint8_t offset; + uint8_t size; +}; + +struct pfc_drive_reg { + uint32_t reg; + const struct pfc_drive_reg_field fields[8]; +}; + +struct pfc_bias_reg { + uint32_t puen; /** Pull-enable or pull-up control register */ + uint32_t pud; /** Pull-up/down or pull-down control register */ + const uint16_t pins[32]; +}; + +/** + * @brief Utility macro to check if a pin is GPIO capable + * + * @param pin + * @return true if pin is GPIO capable false otherwise + */ +#define RCAR_IS_GP_PIN(pin) (pin < PIN_NOGPSR_START) + +#endif /* ZEPHYR_SOC_ARM_RENESAS_RCAR_COMMON_PINCTRL_SOC_H_ */ diff --git a/soc/arm/renesas_rcar/gen3/pfc_r8a77951.c b/soc/arm/renesas_rcar/gen3/pfc_r8a77951.c index c59be6cfe6f..c5fb3ab967b 100644 --- a/soc/arm/renesas_rcar/gen3/pfc_r8a77951.c +++ b/soc/arm/renesas_rcar/gen3/pfc_r8a77951.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2021 IoT.bzh + * Copyright (c) 2021-2023 IoT.bzh * * SPDX-License-Identifier: Apache-2.0 * @@ -528,6 +528,7 @@ const struct pfc_bias_reg pfc_bias_regs[] = { } }, { /* sentinel */ }, }; + const struct pfc_bias_reg *pfc_rcar_get_bias_regs(void) { return pfc_bias_regs; @@ -536,3 +537,10 @@ const struct pfc_drive_reg *pfc_rcar_get_drive_regs(void) { return pfc_drive_regs; } + +int pfc_rcar_get_reg_index(uint8_t pin, uint8_t *reg_index) +{ + /* There is only one register on Gen 3 */ + *reg_index = 0; + return 0; +} diff --git a/soc/arm/renesas_rcar/gen3/pinctrl_soc.h b/soc/arm/renesas_rcar/gen3/pinctrl_soc.h index 92f7aa507a4..b4f5da3bff0 100644 --- a/soc/arm/renesas_rcar/gen3/pinctrl_soc.h +++ b/soc/arm/renesas_rcar/gen3/pinctrl_soc.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2021 IoT.bzh + * Copyright (c) 2021-2023 IoT.bzh * * SPDX-License-Identifier: Apache-2.0 * @@ -7,111 +7,6 @@ #ifndef ZEPHYR_SOC_ARM_RENESAS_RCAR_GEN3_PINCTRL_SOC_H_ #define ZEPHYR_SOC_ARM_RENESAS_RCAR_GEN3_PINCTRL_SOC_H_ - -#include -#include -#include -#include - -struct rcar_pin_func { - uint8_t bank:5; /* bank number 0 - 18 */ - uint8_t shift:5; /* bit shift 0 - 28 */ - uint8_t func:4; /* choice from 0x0 to 0xF */ -}; -/** Pull-up, pull-down, or bias disable is requested */ -#define RCAR_PIN_FLAGS_PULL_SET BIT(0) -/** Performs on/off control of the pull resistors */ -#define RCAR_PIN_FLAGS_PUEN BIT(1) -/** Select pull-up resistor if set pull-down otherwise */ -#define RCAR_PIN_FLAGS_PUD BIT(2) -/** Alternate function for the pin is requested */ -#define RCAR_PIN_FLAGS_FUNC_SET BIT(3) - -#define RCAR_PIN_PULL_UP (RCAR_PIN_FLAGS_PULL_SET | RCAR_PIN_FLAGS_PUEN | RCAR_PIN_FLAGS_PUD) -#define RCAR_PIN_PULL_DOWN (RCAR_PIN_FLAGS_PULL_SET | RCAR_PIN_FLAGS_PUEN) -#define RCAR_PIN_PULL_DISABLE RCAR_PIN_FLAGS_PULL_SET - -/** Type for R-Car pin. */ -typedef struct pinctrl_soc_pin { - uint16_t pin; - struct rcar_pin_func func; - uint8_t flags; - uint8_t drive_strength; -} pinctrl_soc_pin_t; - -#define RCAR_IPSR(node_id) DT_PROP_BY_IDX(node_id, pin, 1) -#define RCAR_HAS_IPSR(node_id) DT_PROP_HAS_IDX(node_id, pin, 1) - -/* Offsets are defined in dt-bindings pinctrl-rcar-common.h */ -#define RCAR_PIN_FUNC(node_id) \ - { \ - ((RCAR_IPSR(node_id) >> 10U) & 0x1FU), \ - ((RCAR_IPSR(node_id) >> 4U) & 0x1FU), \ - ((RCAR_IPSR(node_id) & 0xFU)) \ - } - -#define RCAR_PIN_FLAGS(node_id) \ - DT_PROP(node_id, bias_pull_up) * RCAR_PIN_PULL_UP | \ - DT_PROP(node_id, bias_pull_down) * RCAR_PIN_PULL_DOWN | \ - DT_PROP(node_id, bias_disable) * RCAR_PIN_PULL_DISABLE | \ - RCAR_HAS_IPSR(node_id) * RCAR_PIN_FLAGS_FUNC_SET - -#define RCAR_DT_PIN(node_id) \ - { \ - .pin = DT_PROP_BY_IDX(node_id, pin, 0), \ - .func = COND_CODE_1(RCAR_HAS_IPSR(node_id), \ - (RCAR_PIN_FUNC(node_id)), (0)), \ - .flags = RCAR_PIN_FLAGS(node_id), \ - .drive_strength = \ - COND_CODE_1(DT_NODE_HAS_PROP(node_id, drive_strength), \ - (DT_PROP(node_id, drive_strength)), (0)), \ - }, - -/** - * @brief Utility macro to initialize each pin. - * - * @param node_id Node identifier. - * @param state_prop State property name. - * @param idx State property entry index. - */ -#define Z_PINCTRL_STATE_PIN_INIT(node_id, state_prop, idx) \ - RCAR_DT_PIN(DT_PROP_BY_IDX(node_id, state_prop, idx)) - -/** - * @brief Utility macro to initialize state pins contained in a given property. - * - * @param node_id Node identifier. - * @param prop Property name describing state pins. - */ -#define Z_PINCTRL_STATE_PINS_INIT(node_id, prop) \ - { DT_FOREACH_PROP_ELEM(node_id, prop, Z_PINCTRL_STATE_PIN_INIT) } - -struct pfc_drive_reg_field { - uint16_t pin; - uint8_t offset; - uint8_t size; -}; - -struct pfc_drive_reg { - uint32_t reg; - const struct pfc_drive_reg_field fields[8]; -}; - -struct pfc_bias_reg { - uint32_t puen; /** Pull-enable or pull-up control register */ - uint32_t pud; /** Pull-up/down or pull-down control register */ - const uint16_t pins[32]; -}; - -const struct pfc_bias_reg *pfc_rcar_get_bias_regs(void); -const struct pfc_drive_reg *pfc_rcar_get_drive_regs(void); - -/** - * @brief Utility macro to check if a pin is GPIO capable - * - * @param pin - * @return true if pin is GPIO capable false otherwise - */ -#define RCAR_IS_GP_PIN(pin) (pin < PIN_NOGPSR_START) +#include #endif /* ZEPHYR_SOC_ARM_RENESAS_RCAR_GEN3_PINCTRL_SOC_H_ */ diff --git a/soc/arm/renesas_rcar/gen4/CMakeLists.txt b/soc/arm/renesas_rcar/gen4/CMakeLists.txt new file mode 100644 index 00000000000..3315eaa55eb --- /dev/null +++ b/soc/arm/renesas_rcar/gen4/CMakeLists.txt @@ -0,0 +1,2 @@ +# Copyright (c) 2023 IoT.bzh +# SPDX-License-Identifier: Apache-2.0 diff --git a/soc/arm/renesas_rcar/gen4/pinctrl_soc.h b/soc/arm/renesas_rcar/gen4/pinctrl_soc.h new file mode 100644 index 00000000000..f55b114cddb --- /dev/null +++ b/soc/arm/renesas_rcar/gen4/pinctrl_soc.h @@ -0,0 +1,12 @@ +/* + * Copyright (c) 2023 IoT.bzh + * + * SPDX-License-Identifier: Apache-2.0 + * + */ + +#ifndef ZEPHYR_SOC_ARM_RENESAS_RCAR_GEN4_PINCTRL_SOC_H_ +#define ZEPHYR_SOC_ARM_RENESAS_RCAR_GEN4_PINCTRL_SOC_H_ +#include + +#endif /* ZEPHYR_SOC_ARM_RENESAS_RCAR_GEN4_PINCTRL_SOC_H_ */ diff --git a/soc/arm64/renesas_rcar/gen3/pfc_r8a77951.c b/soc/arm64/renesas_rcar/gen3/pfc_r8a77951.c index c59be6cfe6f..2d5c02316ef 100644 --- a/soc/arm64/renesas_rcar/gen3/pfc_r8a77951.c +++ b/soc/arm64/renesas_rcar/gen3/pfc_r8a77951.c @@ -536,3 +536,10 @@ const struct pfc_drive_reg *pfc_rcar_get_drive_regs(void) { return pfc_drive_regs; } + +int pfc_rcar_get_reg_index(uint8_t pin, uint8_t *reg_index) +{ + /* There is only one register on Gen 3 */ + *reg_index = 0; + return 0; +} diff --git a/soc/arm64/renesas_rcar/gen3/pfc_r8a77961.c b/soc/arm64/renesas_rcar/gen3/pfc_r8a77961.c index c130dd510a8..b219e626e44 100644 --- a/soc/arm64/renesas_rcar/gen3/pfc_r8a77961.c +++ b/soc/arm64/renesas_rcar/gen3/pfc_r8a77961.c @@ -144,3 +144,10 @@ const struct pfc_drive_reg *pfc_rcar_get_drive_regs(void) { return pfc_drive_regs; } + +int pfc_rcar_get_reg_index(uint8_t pin, uint8_t *reg_index) +{ + /* There is only one register on Gen 3 */ + *reg_index = 0; + return 0; +} diff --git a/soc/arm64/renesas_rcar/gen3/pinctrl_soc.h b/soc/arm64/renesas_rcar/gen3/pinctrl_soc.h index 92f7aa507a4..72c07ae9a4f 100644 --- a/soc/arm64/renesas_rcar/gen3/pinctrl_soc.h +++ b/soc/arm64/renesas_rcar/gen3/pinctrl_soc.h @@ -103,9 +103,6 @@ struct pfc_bias_reg { const uint16_t pins[32]; }; -const struct pfc_bias_reg *pfc_rcar_get_bias_regs(void); -const struct pfc_drive_reg *pfc_rcar_get_drive_regs(void); - /** * @brief Utility macro to check if a pin is GPIO capable * From 6033db5360f9320065f4df25806be1a45fdc980c Mon Sep 17 00:00:00 2001 From: Aymeric Aillet Date: Tue, 21 Mar 2023 18:07:11 +0100 Subject: [PATCH 0212/3723] drivers: pinctrl: rcar: Add r8a779f0 support Enable PFC controller for r8a779f0 SoC. Declare pin list for r8a779f0 SoC. Signed-off-by: Aymeric Aillet --- .../pinctrl/renesas/pinctrl-r8a779f0.h | 536 ++++++++++++++++ soc/arm/renesas_rcar/gen4/CMakeLists.txt | 2 + soc/arm/renesas_rcar/gen4/pfc_r8a779f0.c | 604 ++++++++++++++++++ 3 files changed, 1142 insertions(+) create mode 100644 include/zephyr/dt-bindings/pinctrl/renesas/pinctrl-r8a779f0.h create mode 100644 soc/arm/renesas_rcar/gen4/pfc_r8a779f0.c diff --git a/include/zephyr/dt-bindings/pinctrl/renesas/pinctrl-r8a779f0.h b/include/zephyr/dt-bindings/pinctrl/renesas/pinctrl-r8a779f0.h new file mode 100644 index 00000000000..50e8a358007 --- /dev/null +++ b/include/zephyr/dt-bindings/pinctrl/renesas/pinctrl-r8a779f0.h @@ -0,0 +1,536 @@ +/* + * Copyright (c) 2023 IoT.bzh + * + * SPDX-License-Identifier: Apache-2.0 + */ +#ifndef ZEPHYR_INCLUDE_DT_BINDINGS_PINCTRL_RENESAS_PINCTRL_R8A779F0_H_ +#define ZEPHYR_INCLUDE_DT_BINDINGS_PINCTRL_RENESAS_PINCTRL_R8A779F0_H_ + +#include "pinctrl-rcar-common.h" + +/* Pins declaration */ +#define PIN_NONE -1 +#define PIN_SCIF_CLK RCAR_GP_PIN(0, 0) +#define PIN_HSCK0 RCAR_GP_PIN(0, 1) +#define PIN_HRX0 RCAR_GP_PIN(0, 2) +#define PIN_HTX0 RCAR_GP_PIN(0, 3) +#define PIN_HCTS0_N RCAR_GP_PIN(0, 4) +#define PIN_HRTS0_N RCAR_GP_PIN(0, 5) +#define PIN_RX0 RCAR_GP_PIN(0, 6) +#define PIN_TX0 RCAR_GP_PIN(0, 7) +#define PIN_SCK0 RCAR_GP_PIN(0, 8) +#define PIN_RTS0_N RCAR_GP_PIN(0, 9) +#define PIN_CTS0_N RCAR_GP_PIN(0, 10) +#define PIN_MSIOF0_SYNC RCAR_GP_PIN(0, 11) +#define PIN_MSIOF0_RXD RCAR_GP_PIN(0, 12) +#define PIN_MSIOF0_TXD RCAR_GP_PIN(0, 13) +#define PIN_MSIOF0_SCK RCAR_GP_PIN(0, 14) +#define PIN_MSIOF0_SS1 RCAR_GP_PIN(0, 15) +#define PIN_MSIOF0_SS2 RCAR_GP_PIN(0, 16) +#define PIN_IRQ0 RCAR_GP_PIN(0, 17) +#define PIN_IRQ1 RCAR_GP_PIN(0, 18) +#define PIN_IRQ2 RCAR_GP_PIN(0, 19) +#define PIN_IRQ3 RCAR_GP_PIN(0, 20) +#define PIN_GP1_00 RCAR_GP_PIN(1, 0) +#define PIN_GP1_01 RCAR_GP_PIN(1, 1) +#define PIN_GP1_02 RCAR_GP_PIN(1, 2) +#define PIN_GP1_03 RCAR_GP_PIN(1, 3) +#define PIN_GP1_04 RCAR_GP_PIN(1, 4) +#define PIN_GP1_05 RCAR_GP_PIN(1, 5) +#define PIN_GP1_06 RCAR_GP_PIN(1, 6) +#define PIN_GP1_07 RCAR_GP_PIN(1, 7) +#define PIN_GP1_08 RCAR_GP_PIN(1, 8) +#define PIN_GP1_09 RCAR_GP_PIN(1, 9) +#define PIN_GP1_10 RCAR_GP_PIN(1, 10) +#define PIN_GP1_11 RCAR_GP_PIN(1, 11) +#define PIN_MMC_SD_CLK RCAR_GP_PIN(1, 12) +#define PIN_MMC_SD_D0 RCAR_GP_PIN(1, 13) +#define PIN_MMC_SD_D1 RCAR_GP_PIN(1, 14) +#define PIN_MMC_SD_D2 RCAR_GP_PIN(1, 15) +#define PIN_MMC_SD_D3 RCAR_GP_PIN(1, 16) +#define PIN_MMC_D5 RCAR_GP_PIN(1, 17) +#define PIN_MMC_D4 RCAR_GP_PIN(1, 18) +#define PIN_MMC_D6 RCAR_GP_PIN(1, 19) +#define PIN_MMC_DS RCAR_GP_PIN(1, 20) +#define PIN_MMC_D7 RCAR_GP_PIN(1, 21) +#define PIN_MMC_SD_CMD RCAR_GP_PIN(1, 22) +#define PIN_SD_CD RCAR_GP_PIN(1, 23) +#define PIN_SD_WP RCAR_GP_PIN(1, 24) +#define PIN_RPC_INT_N RCAR_GP_PIN(2, 0) +#define PIN_RPC_WP_N RCAR_GP_PIN(2, 1) +#define PIN_RPC_RESET_N RCAR_GP_PIN(2, 2) +#define PIN_QSPI1_SSL RCAR_GP_PIN(2, 3) +#define PIN_QSPI1_IO3 RCAR_GP_PIN(2, 4) +#define PIN_QSPI1_MISO_IO1 RCAR_GP_PIN(2, 5) +#define PIN_QSPI1_IO2 RCAR_GP_PIN(2, 6) +#define PIN_QSPI1_MOSI_IO0 RCAR_GP_PIN(2, 7) +#define PIN_QSPI1_SPCLK RCAR_GP_PIN(2, 8) +#define PIN_QSPI0_MOSI_IO0 RCAR_GP_PIN(2, 9) +#define PIN_QSPI0_SPCLK RCAR_GP_PIN(2, 10) +#define PIN_QSPI0_IO2 RCAR_GP_PIN(2, 11) +#define PIN_QSPI0_MISO_IO1 RCAR_GP_PIN(2, 12) +#define PIN_QSPI0_SSL RCAR_GP_PIN(2, 13) +#define PIN_QSPI0_IO3 RCAR_GP_PIN(2, 14) +#define PIN_PCIE0_CLKREQ_N RCAR_GP_PIN(2, 15) +#define PIN_PCIE1_CLKREQ_N RCAR_GP_PIN(2, 16) +#define PIN_TSN1_MDIO RCAR_GP_PIN(3, 0) +#define PIN_TSN2_MDIO RCAR_GP_PIN(3, 1) +#define PIN_TSN0_MDIO RCAR_GP_PIN(3, 2) +#define PIN_TSN2_MDC RCAR_GP_PIN(3, 3) +#define PIN_TSN0_MDC RCAR_GP_PIN(3, 4) +#define PIN_TSN1_MDC RCAR_GP_PIN(3, 5) +#define PIN_TSN1_LINK RCAR_GP_PIN(3, 6) +#define PIN_TSN2_LINK RCAR_GP_PIN(3, 7) +#define PIN_TSN0_LINK RCAR_GP_PIN(3, 8) +#define PIN_TSN2_PHY_INT RCAR_GP_PIN(3, 9) +#define PIN_TSN0_PHY_INT RCAR_GP_PIN(3, 10) +#define PIN_TSN1_PHY_INT RCAR_GP_PIN(3, 11) +#define PIN_TSN0_MAGIC RCAR_GP_PIN(3, 12) +#define PIN_TSN1_AVTP_PPS RCAR_GP_PIN(3, 13) +#define PIN_TSN1_AVTP_MATCH RCAR_GP_PIN(3, 14) +#define PIN_TSN1_AVTP_CAPTURE RCAR_GP_PIN(3, 15) +#define PIN_TSN0_AVTP_PPS RCAR_GP_PIN(3, 16) +#define PIN_TSN0_AVTP_MATCH RCAR_GP_PIN(3, 17) +#define PIN_TSN0_AVTP_CAPTURE RCAR_GP_PIN(3, 18) +#define PIN_GP4_00 RCAR_GP_PIN(4, 0) +#define PIN_GP4_01 RCAR_GP_PIN(4, 1) +#define PIN_GP4_02 RCAR_GP_PIN(4, 2) +#define PIN_GP4_03 RCAR_GP_PIN(4, 3) +#define PIN_GP4_04 RCAR_GP_PIN(4, 4) +#define PIN_GP4_05 RCAR_GP_PIN(4, 5) +#define PIN_GP4_06 RCAR_GP_PIN(4, 6) +#define PIN_GP4_07 RCAR_GP_PIN(4, 7) +#define PIN_GP4_08 RCAR_GP_PIN(4, 8) +#define PIN_GP4_09 RCAR_GP_PIN(4, 9) +#define PIN_GP4_10 RCAR_GP_PIN(4, 10) +#define PIN_GP4_11 RCAR_GP_PIN(4, 11) +#define PIN_GP4_12 RCAR_GP_PIN(4, 12) +#define PIN_GP4_13 RCAR_GP_PIN(4, 13) +#define PIN_GP4_14 RCAR_GP_PIN(4, 14) +#define PIN_GP4_15 RCAR_GP_PIN(4, 15) +#define PIN_GP4_16 RCAR_GP_PIN(4, 16) +#define PIN_GP4_17 RCAR_GP_PIN(4, 17) +#define PIN_GP4_18 RCAR_GP_PIN(4, 18) +#define PIN_GP4_19 RCAR_GP_PIN(4, 19) +#define PIN_MSPI0SC RCAR_GP_PIN(4, 20) +#define PIN_MSPI0SI RCAR_GP_PIN(4, 21) +#define PIN_MSPI0SO_MSPI0DCS RCAR_GP_PIN(4, 22) +#define PIN_MSPI0CSS1 RCAR_GP_PIN(4, 23) +#define PIN_MSPI0CSS0 RCAR_GP_PIN(4, 24) +#define PIN_MSPI1SI RCAR_GP_PIN(4, 25) +#define PIN_MSPI1SO_MSPI1DCS RCAR_GP_PIN(4, 26) +#define PIN_MSPI1CSS0 RCAR_GP_PIN(4, 27) +#define PIN_MSPI1SC RCAR_GP_PIN(4, 28) +#define PIN_MSPI1CSS2 RCAR_GP_PIN(4, 29) +#define PIN_MSPI1CSS1 RCAR_GP_PIN(4, 30) +#define PIN_RIIC0SCL RCAR_GP_PIN(5, 0) +#define PIN_RIIC0SDA RCAR_GP_PIN(5, 1) +#define PIN_ETNB0MD RCAR_GP_PIN(5, 2) +#define PIN_ETNB0WOL RCAR_GP_PIN(5, 3) +#define PIN_ETNB0LINKSTA RCAR_GP_PIN(5, 4) +#define PIN_ETNB0MDC RCAR_GP_PIN(5, 5) +#define PIN_ETNB0RXER RCAR_GP_PIN(5, 6) +#define PIN_ETNB0RXD3 RCAR_GP_PIN(5, 7) +#define PIN_ETNB0RXD1 RCAR_GP_PIN(5, 8) +#define PIN_ETNB0RXD2 RCAR_GP_PIN(5, 9) +#define PIN_ETNB0RXDV RCAR_GP_PIN(5, 10) +#define PIN_ETNB0RXD0 RCAR_GP_PIN(5, 11) +#define PIN_ETNB0RXCLK RCAR_GP_PIN(5, 12) +#define PIN_ETNB0TXER RCAR_GP_PIN(5, 13) +#define PIN_ETNB0TXD3 RCAR_GP_PIN(5, 14) +#define PIN_ETNB0TXCLK RCAR_GP_PIN(5, 15) +#define PIN_ETNB0TXD1 RCAR_GP_PIN(5, 16) +#define PIN_ETNB0TXD2 RCAR_GP_PIN(5, 17) +#define PIN_ETNB0TXEN RCAR_GP_PIN(5, 18) +#define PIN_ETNB0TXD0 RCAR_GP_PIN(5, 19) +#define PIN_RLIN37TX RCAR_GP_PIN(6, 0) +#define PIN_RLIN37RX_INTP23 RCAR_GP_PIN(6, 1) +#define PIN_RLIN36TX RCAR_GP_PIN(6, 2) +#define PIN_RLIN36RX_INTP22 RCAR_GP_PIN(6, 3) +#define PIN_RLIN35TX RCAR_GP_PIN(6, 4) +#define PIN_RLIN35RX_INTP21 RCAR_GP_PIN(6, 5) +#define PIN_RLIN34TX RCAR_GP_PIN(6, 6) +#define PIN_RLIN34RX_INTP20 RCAR_GP_PIN(6, 7) +#define PIN_RLIN33TX RCAR_GP_PIN(6, 8) +#define PIN_RLIN33RX_INTP19 RCAR_GP_PIN(6, 9) +#define PIN_RLIN32TX RCAR_GP_PIN(6, 10) +#define PIN_RLIN32RX_INTP18 RCAR_GP_PIN(6, 11) +#define PIN_RLIN31TX RCAR_GP_PIN(6, 12) +#define PIN_RLIN31RX_INTP17 RCAR_GP_PIN(6, 13) +#define PIN_RLIN30TX RCAR_GP_PIN(6, 14) +#define PIN_RLIN30RX_INTP16 RCAR_GP_PIN(6, 15) +#define PIN_INTP37 RCAR_GP_PIN(6, 16) +#define PIN_INTP36 RCAR_GP_PIN(6, 17) +#define PIN_INTP35 RCAR_GP_PIN(6, 18) +#define PIN_INTP34 RCAR_GP_PIN(6, 19) +#define PIN_INTP33 RCAR_GP_PIN(6, 20) +#define PIN_INTP32 RCAR_GP_PIN(6, 21) +#define PIN_NMI1 RCAR_GP_PIN(6, 22) +#define PIN_PRESETOUT1_N RCAR_GP_PIN(6, 31) +#define PIN_CAN0TX RCAR_GP_PIN(7, 0) +#define PIN_CAN0RX_INTP0 RCAR_GP_PIN(7, 1) +#define PIN_CAN1TX RCAR_GP_PIN(7, 2) +#define PIN_CAN1RX_INTP1 RCAR_GP_PIN(7, 3) +#define PIN_CAN2TX RCAR_GP_PIN(7, 4) +#define PIN_CAN2RX_INTP2 RCAR_GP_PIN(7, 5) +#define PIN_CAN3TX RCAR_GP_PIN(7, 6) +#define PIN_CAN3RX_INTP3 RCAR_GP_PIN(7, 7) +#define PIN_CAN4TX RCAR_GP_PIN(7, 8) +#define PIN_CAN4RX_INTP4 RCAR_GP_PIN(7, 9) +#define PIN_CAN5TX RCAR_GP_PIN(7, 10) +#define PIN_CAN5RX_INTP5 RCAR_GP_PIN(7, 11) +#define PIN_CAN6TX RCAR_GP_PIN(7, 12) +#define PIN_CAN6RX_INTP6 RCAR_GP_PIN(7, 13) +#define PIN_CAN7TX RCAR_GP_PIN(7, 14) +#define PIN_CAN7RX_INTP7 RCAR_GP_PIN(7, 15) +#define PIN_CAN8TX RCAR_GP_PIN(7, 16) +#define PIN_CAN8RX_INTP8 RCAR_GP_PIN(7, 17) +#define PIN_CAN9TX RCAR_GP_PIN(7, 18) +#define PIN_CAN9RX_INTP9 RCAR_GP_PIN(7, 19) +#define PIN_CAN10TX RCAR_GP_PIN(7, 20) +#define PIN_CAN10RX_INTP10 RCAR_GP_PIN(7, 21) +#define PIN_CAN11TX RCAR_GP_PIN(7, 22) +#define PIN_CAN11RX_INTP11 RCAR_GP_PIN(7, 23) +#define PIN_CAN12TX RCAR_GP_PIN(7, 24) +#define PIN_CAN12RX_INTP12 RCAR_GP_PIN(7, 25) +#define PIN_CAN13TX RCAR_GP_PIN(7, 26) +#define PIN_CAN13RX_INTP13 RCAR_GP_PIN(7, 27) +#define PIN_CAN14TX RCAR_GP_PIN(7, 28) +#define PIN_CAN14RX_INTP14 RCAR_GP_PIN(7, 29) +#define PIN_CAN15TX RCAR_GP_PIN(7, 30) +#define PIN_CAN15RX_INTP15 RCAR_GP_PIN(7, 31) + +/* Pinmux function declarations */ +#define FUNC_SCIF_CLK IP0SR0(0, 0) +#define FUNC_HSCK0 IP0SR0(4, 0) +#define FUNC_SCK3 IP0SR0(4, 1) +#define FUNC_MSIOF3_SCK IP0SR0(4, 2) +#define FUNC_TSN0_AVTP_CAPTURE_A IP0SR0(4, 5) +#define FUNC_HRX0 IP0SR0(8, 0) +#define FUNC_RX3 IP0SR0(8, 1) +#define FUNC_MSIOF3_RXD IP0SR0(8, 2) +#define FUNC_TSN0_AVTP_MATCH_A IP0SR0(8, 5) +#define FUNC_HTX0 IP0SR0(12, 0) +#define FUNC_TX3 IP0SR0(12, 1) +#define FUNC_MSIOF3_TXD IP0SR0(12, 2) +#define FUNC_HCTS0_N IP0SR0(16, 0) +#define FUNC_CTS3_N IP0SR0(16, 1) +#define FUNC_MSIOF3_SS1 IP0SR0(16, 2) +#define FUNC_TSN0_MDC_A IP0SR0(16, 5) +#define FUNC_HRTS0_N IP0SR0(20, 0) +#define FUNC_RTS3_N IP0SR0(20, 1) +#define FUNC_MSIOF3_SS2 IP0SR0(20, 2) +#define FUNC_TSN0_MDIO_A IP0SR0(20, 5) +#define FUNC_RX0 IP0SR0(24, 0) +#define FUNC_HRX1 IP0SR0(24, 1) +#define FUNC_MSIOF1_RXD IP0SR0(24, 3) +#define FUNC_TSN1_AVTP_MATCH_A IP0SR0(24, 5) +#define FUNC_TX0 IP0SR0(28, 0) +#define FUNC_HTX1 IP0SR0(28, 1) +#define FUNC_MSIOF1_TXD IP0SR0(28, 3) +#define FUNC_TSN1_AVTP_CAPTURE_A IP0SR0(28, 5) +#define FUNC_SCK0 IP1SR0(0, 0) +#define FUNC_HSCK1 IP1SR0(0, 1) +#define FUNC_MSIOF1_SCK IP1SR0(0, 3) +#define FUNC_RTS0_N IP1SR0(4, 0) +#define FUNC_HRTS1_N IP1SR0(4, 1) +#define FUNC_MSIOF3_SYNC IP1SR0(4, 2) +#define FUNC_TSN1_MDIO_A IP1SR0(4, 5) +#define FUNC_CTS0_N IP1SR0(8, 0) +#define FUNC_HCTS1_N IP1SR0(8, 1) +#define FUNC_MSIOF1_SYNC IP1SR0(8, 3) +#define FUNC_TSN1_MDC_A IP1SR0(8, 5) +#define FUNC_MSIOF0_SYNC IP1SR0(12, 0) +#define FUNC_HCTS3_N IP1SR0(12, 1) +#define FUNC_CTS1_N IP1SR0(12, 2) +#define FUNC_IRQ4 IP1SR0(12, 3) +#define FUNC_TSN0_LINK_A IP1SR0(12, 5) +#define FUNC_MSIOF0_RXD IP1SR0(16, 0) +#define FUNC_HRX3 IP1SR0(16, 1) +#define FUNC_RX1 IP1SR0(16, 2) +#define FUNC_MSIOF0_TXD IP1SR0(20, 0) +#define FUNC_HTX3 IP1SR0(20, 1) +#define FUNC_TX1 IP1SR0(20, 2) +#define FUNC_MSIOF0_SCK IP1SR0(24, 0) +#define FUNC_HSCK3 IP1SR0(24, 1) +#define FUNC_SCK1 IP1SR0(24, 2) +#define FUNC_MSIOF0_SS1 IP1SR0(28, 0) +#define FUNC_HRTS3_N IP1SR0(28, 1) +#define FUNC_RTS1_N IP1SR0(28, 2) +#define FUNC_IRQ5 IP1SR0(28, 3) +#define FUNC_TSN1_LINK_A IP1SR0(28, 5) +#define FUNC_MSIOF0_SS2 IP2SR0(0, 0) +#define FUNC_TSN2_LINK_A IP2SR0(0, 5) +#define FUNC_IRQ0 IP2SR0(4, 0) +#define FUNC_MSIOF1_SS1 IP2SR0(4, 3) +#define FUNC_TSN0_MAGIC_A IP2SR0(4, 5) +#define FUNC_IRQ1 IP2SR0(8, 0) +#define FUNC_MSIOF1_SS2 IP2SR0(8, 3) +#define FUNC_TSN0_PHY_INT_A IP2SR0(8, 5) +#define FUNC_IRQ2 IP2SR0(12, 0) +#define FUNC_TSN1_PHY_INT_A IP2SR0(12, 5) +#define FUNC_IRQ3 IP2SR0(16, 0) +#define FUNC_TSN2_PHY_INT_A IP2SR0(16, 5) +#define FUNC_GP1_00 IP0SR1(0, 0) +#define FUNC_TCLK1 IP0SR1(0, 1) +#define FUNC_HSCK2 IP0SR1(0, 2) +#define FUNC_GP1_01 IP0SR1(4, 0) +#define FUNC_TCLK4 IP0SR1(4, 1) +#define FUNC_HRX2 IP0SR1(4, 2) +#define FUNC_GP1_02 IP0SR1(8, 0) +#define FUNC_HTX2 IP0SR1(8, 2) +#define FUNC_MSIOF2_SS1 IP0SR1(8, 3) +#define FUNC_TSN2_MDC_A IP0SR1(8, 5) +#define FUNC_GP1_03 IP0SR1(12, 0) +#define FUNC_TCLK2 IP0SR1(12, 1) +#define FUNC_HCTS2_N IP0SR1(12, 2) +#define FUNC_MSIOF2_SS2 IP0SR1(12, 3) +#define FUNC_CTS4_N IP0SR1(12, 4) +#define FUNC_TSN2_MDIO_A IP0SR1(12, 5) +#define FUNC_GP1_04 IP0SR1(16, 0) +#define FUNC_TCLK3 IP0SR1(16, 1) +#define FUNC_HRTS2_N IP0SR1(16, 2) +#define FUNC_MSIOF2_SYNC IP0SR1(16, 3) +#define FUNC_RTS4_N IP0SR1(16, 4) +#define FUNC_GP1_05 IP0SR1(20, 0) +#define FUNC_MSIOF2_SCK IP0SR1(20, 1) +#define FUNC_SCK4 IP0SR1(20, 2) +#define FUNC_GP1_06 IP0SR1(24, 0) +#define FUNC_MSIOF2_RXD IP0SR1(24, 1) +#define FUNC_RX4 IP0SR1(24, 2) +#define FUNC_GP1_07 IP0SR1(28, 0) +#define FUNC_MSIOF2_TXD IP0SR1(28, 1) +#define FUNC_TX4 IP0SR1(28, 2) +#define FUNC_GP4_00 IP0SR4(0, 0) +#define FUNC_MSPI4SC IP0SR4(0, 1) +#define FUNC_TAUD0I2 IP0SR4(0, 3) +#define FUNC_TAUD0O2 IP0SR4(0, 4) +#define FUNC_GP4_01 IP0SR4(4, 0) +#define FUNC_MSPI4SI IP0SR4(4, 1) +#define FUNC_TAUD0I4 IP0SR4(4, 3) +#define FUNC_TAUD0O4 IP0SR4(4, 4) +#define FUNC_GP4_02 IP0SR4(8, 0) +#define FUNC_MSPI4SO_MSPI4DCS IP0SR4(8, 1) +#define FUNC_TAUD0I3 IP0SR4(8, 3) +#define FUNC_TAUD0O3 IP0SR4(8, 4) +#define FUNC_GP4_03 IP0SR4(12, 0) +#define FUNC_MSPI4CSS1 IP0SR4(12, 1) +#define FUNC_TAUD0I6 IP0SR4(12, 3) +#define FUNC_TAUD0O6 IP0SR4(12, 4) +#define FUNC_GP4_04 IP0SR4(16, 0) +#define FUNC_MSPI4CSS0 IP0SR4(16, 1) +#define FUNC_MSPI4SSI_N IP0SR4(16, 2) +#define FUNC_TAUD0I5 IP0SR4(16, 3) +#define FUNC_TAUD0O5 IP0SR4(16, 4) +#define FUNC_GP4_05 IP0SR4(20, 0) +#define FUNC_MSPI4CSS3 IP0SR4(20, 1) +#define FUNC_TAUD0I8 IP0SR4(20, 3) +#define FUNC_TAUD0O8 IP0SR4(20, 4) +#define FUNC_GP4_06 IP0SR4(24, 0) +#define FUNC_MSPI4CSS2 IP0SR4(24, 1) +#define FUNC_TAUD0I7 IP0SR4(24, 3) +#define FUNC_TAUD0O7 IP0SR4(24, 4) +#define FUNC_GP4_07 IP0SR4(28, 0) +#define FUNC_MSPI4CSS5 IP0SR4(28, 1) +#define FUNC_TAUD0I10 IP0SR4(28, 3) +#define FUNC_TAUD0O10 IP0SR4(28, 4) +#define FUNC_GP4_08 IP1SR4(0, 0) +#define FUNC_MSPI4CSS4 IP1SR4(0, 1) +#define FUNC_TAUD0I9 IP1SR4(0, 3) +#define FUNC_TAUD0O9 IP1SR4(0, 4) +#define FUNC_GP4_09 IP1SR4(4, 0) +#define FUNC_MSPI4CSS7 IP1SR4(4, 1) +#define FUNC_TAUD0I12 IP1SR4(4, 3) +#define FUNC_TAUD0O12 IP1SR4(4, 4) +#define FUNC_GP4_10 IP1SR4(8, 0) +#define FUNC_MSPI4CSS6 IP1SR4(8, 1) +#define FUNC_TAUD0I11 IP1SR4(8, 3) +#define FUNC_TAUD0O11 IP1SR4(8, 4) +#define FUNC_GP4_11 IP1SR4(12, 0) +#define FUNC_ERRORIN0_N IP1SR4(12, 1) +#define FUNC_TAUD0I14 IP1SR4(12, 3) +#define FUNC_TAUD0O14 IP1SR4(12, 4) +#define FUNC_GP4_12 IP1SR4(16, 0) +#define FUNC_ERROROUT_C_N IP1SR4(16, 1) +#define FUNC_TAUD0I13 IP1SR4(16, 3) +#define FUNC_TAUD0O13 IP1SR4(16, 4) +#define FUNC_GP4_13 IP1SR4(20, 0) +#define FUNC_GP4_14 IP1SR4(24, 0) +#define FUNC_ERRORIN1_N IP1SR4(24, 1) +#define FUNC_TAUD0I15 IP1SR4(24, 3) +#define FUNC_TAUD0O15 IP1SR4(24, 4) +#define FUNC_GP4_15 IP1SR4(28, 0) +#define FUNC_MSPI1CSS3 IP1SR4(28, 1) +#define FUNC_TAUD1I1 IP1SR4(28, 3) +#define FUNC_TAUD1O1 IP1SR4(28, 4) +#define FUNC_GP4_16 IP2SR4(0, 0) +#define FUNC_TAUD1I0 IP2SR4(0, 3) +#define FUNC_TAUD1O0 IP2SR4(0, 4) +#define FUNC_GP4_17 IP2SR4(4, 0) +#define FUNC_MSPI1CSS5 IP2SR4(4, 1) +#define FUNC_TAUD1I3 IP2SR4(4, 3) +#define FUNC_TAUD1O3 IP2SR4(4, 4) +#define FUNC_GP4_18 IP2SR4(8, 0) +#define FUNC_MSPI1CSS4 IP2SR4(8, 1) +#define FUNC_TAUD1I2 IP2SR4(8, 3) +#define FUNC_TAUD1O2 IP2SR4(8, 4) +#define FUNC_GP4_19 IP2SR4(12, 0) +#define FUNC_MSPI1CSS6 IP2SR4(12, 1) +#define FUNC_TAUD1I4 IP2SR4(12, 3) +#define FUNC_TAUD1O4 IP2SR4(12, 4) +#define FUNC_MSPI0SC IP2SR4(16, 0) +#define FUNC_MSPI1CSS7 IP2SR4(16, 1) +#define FUNC_TAUD1I5 IP2SR4(16, 3) +#define FUNC_TAUD1O5 IP2SR4(16, 4) +#define FUNC_MSPI0SI IP2SR4(20, 0) +#define FUNC_TAUD1I7 IP2SR4(20, 3) +#define FUNC_TAUD1O7 IP2SR4(20, 4) +#define FUNC_MSPI0SO_MSPI0DCS IP2SR4(24, 0) +#define FUNC_TAUD1I6 IP2SR4(24, 3) +#define FUNC_TAUD1O6 IP2SR4(24, 4) +#define FUNC_MSPI0CSS1 IP2SR4(28, 0) +#define FUNC_TAUD1I9 IP2SR4(28, 3) +#define FUNC_TAUD1O9 IP2SR4(28, 4) +#define FUNC_MSPI0CSS0 IP3SR4(0, 0) +#define FUNC_MSPI0SSI_N IP3SR4(0, 1) +#define FUNC_TAUD1I8 IP3SR4(0, 3) +#define FUNC_TAUD1O8 IP3SR4(0, 4) +#define FUNC_MSPI1SO_MSPI1DCS IP3SR4(8, 0) +#define FUNC_MSPI0CSS3 IP3SR4(8, 2) +#define FUNC_TAUD1I11 IP3SR4(8, 3) +#define FUNC_TAUD1O11 IP3SR4(8, 4) +#define FUNC_MSPI1SC IP3SR4(16, 0) +#define FUNC_MSPI0CSS2 IP3SR4(16, 2) +#define FUNC_TAUD1I10 IP3SR4(16, 3) +#define FUNC_TAUD1O10 IP3SR4(16, 4) +#define FUNC_RIIC0SCL IP0SR5(0, 0) +#define FUNC_TAUD0I0 IP0SR5(0, 3) +#define FUNC_TAUD0O0 IP0SR5(0, 4) +#define FUNC_RIIC0SDA IP0SR5(4, 0) +#define FUNC_TAUD0I1 IP0SR5(4, 3) +#define FUNC_TAUD0O1 IP0SR5(4, 4) +#define FUNC_ETNB0MD IP0SR5(8, 0) +#define FUNC_ETNB0WOL IP0SR5(12, 0) +#define FUNC_ETNB0LINKSTA IP0SR5(16, 0) +#define FUNC_ETNB0MDC IP0SR5(20, 0) +#define FUNC_ETNB0RXCLK IP0SR5(24, 0) +#define FUNC_ETNB0CRS_DV IP0SR5(24, 1) +#define FUNC_ETNB0TXCLK IP0SR5(28, 0) +#define FUNC_ETNB0REFCLK IP0SR5(28, 1) +#define FUNC_RLIN33TX IP1SR6(0, 0) +#define FUNC_TAUJ3O3 IP1SR6(0, 3) +#define FUNC_TAUJ3I3 IP1SR6(0, 4) +#define FUNC_NMI1 IP1SR6(0, 5) +#define FUNC_RLIN33RX_INTP19 IP1SR6(4, 0) +#define FUNC_TAUJ3O2 IP1SR6(4, 3) +#define FUNC_TAUJ3I2 IP1SR6(4, 4) +#define FUNC_RLIN32TX IP1SR6(8, 0) +#define FUNC_TAUJ3O1 IP1SR6(8, 3) +#define FUNC_TAUJ3I1 IP1SR6(8, 4) +#define FUNC_RLIN32RX_INTP18 IP1SR6(12, 0) +#define FUNC_TAUJ3O0 IP1SR6(12, 3) +#define FUNC_TAUJ3I0 IP1SR6(12, 4) +#define FUNC_INTP35 IP1SR6(12, 5) +#define FUNC_RLIN31TX IP1SR6(16, 0) +#define FUNC_TAUJ1I3 IP1SR6(16, 3) +#define FUNC_TAUJ1O3 IP1SR6(16, 4) +#define FUNC_INTP34 IP1SR6(16, 5) +#define FUNC_RLIN31RX_INTP17 IP1SR6(20, 0) +#define FUNC_TAUJ1I2 IP1SR6(20, 3) +#define FUNC_TAUJ1O2 IP1SR6(20, 4) +#define FUNC_INTP33 IP1SR6(20, 5) +#define FUNC_RLIN30TX IP1SR6(24, 0) +#define FUNC_TAUJ1I1 IP1SR6(24, 3) +#define FUNC_TAUJ1O1 IP1SR6(24, 4) +#define FUNC_RLIN30RX_INTP16 IP1SR6(28, 0) +#define FUNC_TAUJ1I0 IP1SR6(28, 3) +#define FUNC_TAUJ1O0 IP1SR6(28, 4) +#define FUNC_FLXA0STPWT IP2SR6(8, 2) +#define FUNC_CAN0TX IP0SR7(0, 0) +#define FUNC_RSENT0SPCO IP0SR7(0, 1) +#define FUNC_MSPI2SO_MSPI2DCS IP0SR7(0, 3) +#define FUNC_CAN0RX_INTP0 IP0SR7(4, 0) +#define FUNC_RSENT0RX IP0SR7(4, 1) +#define FUNC_RSENT0RX_RSENT0SPCO IP0SR7(4, 2) +#define FUNC_MSPI2SC IP0SR7(4, 3) +#define FUNC_CAN1TX IP0SR7(8, 0) +#define FUNC_RSENT1SPCO IP0SR7(8, 1) +#define FUNC_MSPI2SSI_N IP0SR7(8, 3) +#define FUNC_MSPI2CSS0 IP0SR7(8, 4) +#define FUNC_CAN1RX_INTP1 IP0SR7(12, 0) +#define FUNC_RSENT1RX IP0SR7(12, 1) +#define FUNC_RSENT1RX_RSENT1SPCO IP0SR7(12, 2) +#define FUNC_MSPI2SI IP0SR7(12, 3) +#define FUNC_CAN2TX IP0SR7(16, 0) +#define FUNC_RSENT2SPCO IP0SR7(16, 1) +#define FUNC_MSPI2CSS2 IP0SR7(16, 4) +#define FUNC_CAN2RX_INTP2 IP0SR7(20, 0) +#define FUNC_RSENT2RX IP0SR7(20, 1) +#define FUNC_RSENT2RX_RSENT2SPCO IP0SR7(20, 2) +#define FUNC_MSPI2CSS1 IP0SR7(20, 4) +#define FUNC_CAN3TX IP0SR7(24, 0) +#define FUNC_RSENT3SPCO IP0SR7(24, 1) +#define FUNC_MSPI2CSS4 IP0SR7(24, 4) +#define FUNC_CAN3RX_INTP3 IP0SR7(28, 0) +#define FUNC_RSENT3RX IP0SR7(28, 1) +#define FUNC_RSENT3RX_RSENT3SPCO IP0SR7(28, 2) +#define FUNC_MSPI2CSS3 IP0SR7(28, 4) +#define FUNC_CAN4TX IP1SR7(0, 0) +#define FUNC_RSENT4SPCO IP1SR7(0, 1) +#define FUNC_MSPI2CSS6 IP1SR7(0, 4) +#define FUNC_CAN4RX_INTP4 IP1SR7(4, 0) +#define FUNC_RSENT4RX IP1SR7(4, 1) +#define FUNC_RSENT4RX_RSENT4SPCO IP1SR7(4, 2) +#define FUNC_MSPI2CSS5 IP1SR7(4, 4) +#define FUNC_CAN5TX IP1SR7(8, 0) +#define FUNC_RSENT5SPCO IP1SR7(8, 1) +#define FUNC_CAN5RX_INTP5 IP1SR7(12, 0) +#define FUNC_RSENT5RX IP1SR7(12, 1) +#define FUNC_RSENT5RX_RSENT5SPCO IP1SR7(12, 2) +#define FUNC_MSPI2CSS7 IP1SR7(12, 4) +#define FUNC_CAN6TX IP1SR7(16, 0) +#define FUNC_RSENT6SPCO IP1SR7(16, 1) +#define FUNC_MSPI3SO_MSPI3DCS IP1SR7(16, 3) +#define FUNC_CAN6RX_INTP6 IP1SR7(20, 0) +#define FUNC_RSENT6RX IP1SR7(20, 1) +#define FUNC_RSENT6RX_RSENT6SPCO IP1SR7(20, 2) +#define FUNC_MSPI3SC IP1SR7(20, 3) +#define FUNC_CAN7TX IP1SR7(24, 0) +#define FUNC_RSENT7SPCO IP1SR7(24, 1) +#define FUNC_MSPI3SSI_N IP1SR7(24, 3) +#define FUNC_CAN7RX_INTP7 IP1SR7(28, 0) +#define FUNC_RSENT7RX IP1SR7(28, 1) +#define FUNC_RSENT7RX_RSENT7SPCO IP1SR7(28, 2) +#define FUNC_MSPI3SI IP1SR7(28, 3) +#define FUNC_CAN8TX IP2SR7(0, 0) +#define FUNC_RLIN38TX IP2SR7(0, 1) +#define FUNC_MSPI3CSS1 IP2SR7(0, 3) +#define FUNC_CAN8RX_INTP8 IP2SR7(4, 0) +#define FUNC_RLIN38RX_INTP24 IP2SR7(4, 1) +#define FUNC_MSPI3CSS0 IP2SR7(4, 3) +#define FUNC_CAN9TX IP2SR7(8, 0) +#define FUNC_RLIN39TX IP2SR7(8, 1) +#define FUNC_MSPI3CSS3 IP2SR7(8, 3) +#define FUNC_CAN9RX_INTP9 IP2SR7(12, 0) +#define FUNC_RLIN39RX_INTP25 IP2SR7(12, 1) +#define FUNC_MSPI3CSS2 IP2SR7(12, 3) +#define FUNC_CAN10TX IP2SR7(16, 0) +#define FUNC_RLIN310TX IP2SR7(16, 1) +#define FUNC_MSPI3CSS5 IP2SR7(16, 3) +#define FUNC_CAN10RX_INTP10 IP2SR7(20, 0) +#define FUNC_RLIN310RX_INTP26 IP2SR7(20, 1) +#define FUNC_MSPI3CSS4 IP2SR7(20, 3) +#define FUNC_CAN11TX IP2SR7(24, 0) +#define FUNC_RLIN311TX IP2SR7(24, 1) +#define FUNC_MSPI3CSS7 IP2SR7(24, 3) +#define FUNC_CAN11RX_INTP11 IP2SR7(28, 0) +#define FUNC_RLIN311RX_INTP27 IP2SR7(28, 1) +#define FUNC_MSPI3CSS6 IP2SR7(28, 3) +#define FUNC_FLXA0RXDB IP3SR7(8, 2) +#define FUNC_FLXA0RXDA IP3SR7(12, 2) +#define FUNC_FLXA0TXDB IP3SR7(16, 2) +#define FUNC_FLXA0TXDA IP3SR7(20, 2) +#define FUNC_FLXA0TXENB IP3SR7(24, 2) +#define FUNC_FLXA0TXENA IP3SR7(28, 2) + +#endif /* ZEPHYR_INCLUDE_DT_BINDINGS_PINCTRL_RENESAS_PINCTRL_R8A779F0_H_ */ diff --git a/soc/arm/renesas_rcar/gen4/CMakeLists.txt b/soc/arm/renesas_rcar/gen4/CMakeLists.txt index 3315eaa55eb..906bfdecfba 100644 --- a/soc/arm/renesas_rcar/gen4/CMakeLists.txt +++ b/soc/arm/renesas_rcar/gen4/CMakeLists.txt @@ -1,2 +1,4 @@ # Copyright (c) 2023 IoT.bzh # SPDX-License-Identifier: Apache-2.0 + +zephyr_library_sources_ifdef(CONFIG_SOC_R8A779F0 pfc_r8a779f0.c) diff --git a/soc/arm/renesas_rcar/gen4/pfc_r8a779f0.c b/soc/arm/renesas_rcar/gen4/pfc_r8a779f0.c new file mode 100644 index 00000000000..25eba334d77 --- /dev/null +++ b/soc/arm/renesas_rcar/gen4/pfc_r8a779f0.c @@ -0,0 +1,604 @@ +/* + * Copyright (c) 2023 IoT.bzh + * + * SPDX-License-Identifier: Apache-2.0 + * + */ + +#include +#include "pinctrl_soc.h" +#include + +const struct pfc_drive_reg pfc_drive_regs[] = { + /* DRV0CTRL0 */ + { 0x80, { + { RCAR_GP_PIN(0, 7), 28, 3 }, /* TX0 */ + { RCAR_GP_PIN(0, 6), 24, 3 }, /* RX0 */ + { RCAR_GP_PIN(0, 5), 20, 3 }, /* HRTS0_N */ + { RCAR_GP_PIN(0, 4), 16, 3 }, /* HCTS0_N */ + { RCAR_GP_PIN(0, 3), 12, 3 }, /* HTX0 */ + { RCAR_GP_PIN(0, 2), 8, 3 }, /* HRX0 */ + { RCAR_GP_PIN(0, 1), 4, 3 }, /* HSCK0 */ + { RCAR_GP_PIN(0, 0), 0, 3 }, /* SCIF_CLK */ + } }, + /* DRV1CTRL0 */ + { 0x84, { + { RCAR_GP_PIN(0, 15), 28, 3 }, /* MSIOF0_SS1 */ + { RCAR_GP_PIN(0, 14), 24, 3 }, /* MSIOF0_SCK */ + { RCAR_GP_PIN(0, 13), 20, 3 }, /* MSIOF0_TXD */ + { RCAR_GP_PIN(0, 12), 16, 3 }, /* MSIOF0_RXD */ + { RCAR_GP_PIN(0, 11), 12, 3 }, /* MSIOF0_SYNC */ + { RCAR_GP_PIN(0, 10), 8, 3 }, /* CTS0_N */ + { RCAR_GP_PIN(0, 9), 4, 3 }, /* RTS0_N */ + { RCAR_GP_PIN(0, 8), 0, 3 }, /* SCK0 */ + } }, + /* DRV2CTRL0 */ + { 0x88, { + { RCAR_GP_PIN(0, 20), 16, 3 }, /* IRQ3 */ + { RCAR_GP_PIN(0, 19), 12, 3 }, /* IRQ2 */ + { RCAR_GP_PIN(0, 18), 8, 3 }, /* IRQ1 */ + { RCAR_GP_PIN(0, 17), 4, 3 }, /* IRQ0 */ + { RCAR_GP_PIN(0, 16), 0, 3 }, /* MSIOF0_SS2 */ + } }, + /* DRV3CTRL0 is empty */ + /* DRV0CTRL1 */ + { 0x80, { + { RCAR_GP_PIN(1, 7), 28, 3 }, /* GP1_07 */ + { RCAR_GP_PIN(1, 6), 24, 3 }, /* GP1_06 */ + { RCAR_GP_PIN(1, 5), 20, 3 }, /* GP1_05 */ + { RCAR_GP_PIN(1, 4), 16, 3 }, /* GP1_04 */ + { RCAR_GP_PIN(1, 3), 12, 3 }, /* GP1_03 */ + { RCAR_GP_PIN(1, 2), 8, 3 }, /* GP1_02 */ + { RCAR_GP_PIN(1, 1), 4, 3 }, /* GP1_01 */ + { RCAR_GP_PIN(1, 0), 0, 3 }, /* GP1_00 */ + } }, + /* DRV1CTRL1 */ + { 0x84, { + { RCAR_GP_PIN(1, 15), 28, 3 }, /* MMC_SD_D2 */ + { RCAR_GP_PIN(1, 14), 24, 3 }, /* MMC_SD_D1 */ + { RCAR_GP_PIN(1, 13), 20, 3 }, /* MMC_SD_D0 */ + { RCAR_GP_PIN(1, 12), 16, 3 }, /* MMC_SD_CLK */ + { RCAR_GP_PIN(1, 11), 12, 3 }, /* GP1_11 */ + { RCAR_GP_PIN(1, 10), 8, 3 }, /* GP1_10 */ + { RCAR_GP_PIN(1, 9), 4, 3 }, /* GP1_09 */ + { RCAR_GP_PIN(1, 8), 0, 3 }, /* GP1_08 */ + } }, + /* DRV2CTRL1 */ + { 0x88, { + { RCAR_GP_PIN(1, 23), 28, 3 }, /* SD_CD */ + { RCAR_GP_PIN(1, 22), 24, 3 }, /* MMC_SD_CMD */ + { RCAR_GP_PIN(1, 21), 20, 3 }, /* MMC_D7 */ + { RCAR_GP_PIN(1, 20), 16, 3 }, /* MMC_DS */ + { RCAR_GP_PIN(1, 19), 12, 3 }, /* MMC_D6 */ + { RCAR_GP_PIN(1, 18), 8, 3 }, /* MMC_D4 */ + { RCAR_GP_PIN(1, 17), 4, 3 }, /* MMC_D5 */ + { RCAR_GP_PIN(1, 16), 0, 3 }, /* MMC_SD_D3 */ + } }, + /* DRV3CTRL1 */ + { 0x8c, { + { RCAR_GP_PIN(1, 24), 0, 3 }, /* SD_WP */ + } }, + /* DRV0CTRL2 */ + { 0x80, { + { RCAR_GP_PIN(2, 7), 28, 2 }, /* QSPI1_MOSI_IO0 */ + { RCAR_GP_PIN(2, 6), 24, 2 }, /* QSPI1_IO2 */ + { RCAR_GP_PIN(2, 5), 20, 2 }, /* QSPI1_MISO_IO1 */ + { RCAR_GP_PIN(2, 4), 16, 2 }, /* QSPI1_IO3 */ + { RCAR_GP_PIN(2, 3), 12, 2 }, /* QSPI1_SSL */ + { RCAR_GP_PIN(2, 2), 8, 2 }, /* RPC_RESET_N */ + { RCAR_GP_PIN(2, 1), 4, 2 }, /* RPC_WP_N */ + { RCAR_GP_PIN(2, 0), 0, 2 }, /* RPC_INT_N */ + } }, + /* DRV1CTRL2 */ + { 0x84, { + { RCAR_GP_PIN(2, 15), 28, 3 }, /* PCIE0_CLKREQ_N */ + { RCAR_GP_PIN(2, 14), 24, 2 }, /* QSPI0_IO3 */ + { RCAR_GP_PIN(2, 13), 20, 2 }, /* QSPI0_SSL */ + { RCAR_GP_PIN(2, 12), 16, 2 }, /* QSPI0_MISO_IO1 */ + { RCAR_GP_PIN(2, 11), 12, 2 }, /* QSPI0_IO2 */ + { RCAR_GP_PIN(2, 10), 8, 2 }, /* QSPI0_SPCLK */ + { RCAR_GP_PIN(2, 9), 4, 2 }, /* QSPI0_MOSI_IO0 */ + { RCAR_GP_PIN(2, 8), 0, 2 }, /* QSPI1_SPCLK */ + } }, + /* DRV2CTRL2 */ + { 0x88, { + { RCAR_GP_PIN(2, 16), 0, 3 }, /* PCIE1_CLKREQ_N */ + } }, + /* DRV3CTRL2 is empty */ + /* DRV0CTRL3 */ + { 0x80, { + { RCAR_GP_PIN(3, 7), 28, 3 }, /* TSN2_LINK_B */ + { RCAR_GP_PIN(3, 6), 24, 3 }, /* TSN1_LINK_B */ + { RCAR_GP_PIN(3, 5), 20, 3 }, /* TSN1_MDC_B */ + { RCAR_GP_PIN(3, 4), 16, 3 }, /* TSN0_MDC_B */ + { RCAR_GP_PIN(3, 3), 12, 3 }, /* TSN2_MDC_B */ + { RCAR_GP_PIN(3, 2), 8, 3 }, /* TSN0_MDIO_B */ + { RCAR_GP_PIN(3, 1), 4, 3 }, /* TSN2_MDIO_B */ + { RCAR_GP_PIN(3, 0), 0, 3 }, /* TSN1_MDIO_B */ + } }, + /* DRV1CTRL3 */ + { 0x84, { + { RCAR_GP_PIN(3, 15), 28, 3 }, /* TSN1_AVTP_CAPTURE_B */ + { RCAR_GP_PIN(3, 14), 24, 3 }, /* TSN1_AVTP_MATCH_B */ + { RCAR_GP_PIN(3, 13), 20, 3 }, /* TSN1_AVTP_PPS */ + { RCAR_GP_PIN(3, 12), 16, 3 }, /* TSN0_MAGIC_B */ + { RCAR_GP_PIN(3, 11), 12, 3 }, /* TSN1_PHY_INT_B */ + { RCAR_GP_PIN(3, 10), 8, 3 }, /* TSN0_PHY_INT_B */ + { RCAR_GP_PIN(3, 9), 4, 3 }, /* TSN2_PHY_INT_B */ + { RCAR_GP_PIN(3, 8), 0, 3 }, /* TSN0_LINK_B */ + } }, + /* DRV2CTRL3 */ + { 0x88, { + { RCAR_GP_PIN(3, 18), 8, 3 }, /* TSN0_AVTP_CAPTURE_B */ + { RCAR_GP_PIN(3, 17), 4, 3 }, /* TSN0_AVTP_MATCH_B */ + { RCAR_GP_PIN(3, 16), 0, 3 }, /* TSN0_AVTP_PPS */ + } }, + /* DRV3CTRL3 is empty */ + /* DRV0CTRL4 */ + { 0x80, { + { RCAR_GP_PIN(4, 7), 28, 3 }, /* GP4_07 */ + { RCAR_GP_PIN(4, 6), 24, 3 }, /* GP4_06 */ + { RCAR_GP_PIN(4, 5), 20, 3 }, /* GP4_05 */ + { RCAR_GP_PIN(4, 4), 16, 3 }, /* GP4_04 */ + { RCAR_GP_PIN(4, 3), 12, 3 }, /* GP4_03 */ + { RCAR_GP_PIN(4, 2), 8, 3 }, /* GP4_02 */ + { RCAR_GP_PIN(4, 1), 4, 3 }, /* GP4_01 */ + { RCAR_GP_PIN(4, 0), 0, 3 }, /* GP4_00 */ + } }, + /* DRV1CTRL4 */ + { 0x84, { + { RCAR_GP_PIN(4, 15), 28, 3 }, /* GP4_15 */ + { RCAR_GP_PIN(4, 14), 24, 3 }, /* GP4_14 */ + { RCAR_GP_PIN(4, 13), 20, 3 }, /* GP4_13 */ + { RCAR_GP_PIN(4, 12), 16, 3 }, /* GP4_12 */ + { RCAR_GP_PIN(4, 11), 12, 3 }, /* GP4_11 */ + { RCAR_GP_PIN(4, 10), 8, 3 }, /* GP4_10 */ + { RCAR_GP_PIN(4, 9), 4, 3 }, /* GP4_09 */ + { RCAR_GP_PIN(4, 8), 0, 3 }, /* GP4_08 */ + } }, + /* DRV2CTRL4 */ + { 0x88, { + { RCAR_GP_PIN(4, 23), 28, 3 }, /* MSPI0CSS1 */ + { RCAR_GP_PIN(4, 22), 24, 3 }, /* MPSI0SO/MSPI0DCS */ + { RCAR_GP_PIN(4, 21), 20, 3 }, /* MPSI0SI */ + { RCAR_GP_PIN(4, 20), 16, 3 }, /* MSPI0SC */ + { RCAR_GP_PIN(4, 19), 12, 3 }, /* GP4_19 */ + { RCAR_GP_PIN(4, 18), 8, 3 }, /* GP4_18 */ + { RCAR_GP_PIN(4, 17), 4, 3 }, /* GP4_17 */ + { RCAR_GP_PIN(4, 16), 0, 3 }, /* GP4_16 */ + } }, + /* DRV3CTRL4 */ + { 0x8c, { + { RCAR_GP_PIN(4, 30), 24, 3 }, /* MSPI1CSS1 */ + { RCAR_GP_PIN(4, 29), 20, 3 }, /* MSPI1CSS2 */ + { RCAR_GP_PIN(4, 28), 16, 3 }, /* MSPI1SC */ + { RCAR_GP_PIN(4, 27), 12, 3 }, /* MSPI1CSS0 */ + { RCAR_GP_PIN(4, 26), 8, 3 }, /* MPSI1SO/MSPI1DCS */ + { RCAR_GP_PIN(4, 25), 4, 3 }, /* MSPI1SI */ + { RCAR_GP_PIN(4, 24), 0, 3 }, /* MSPI0CSS0 */ + } }, + /* DRV0CTRL5 */ + { 0x80, { + { RCAR_GP_PIN(5, 7), 28, 3 }, /* ETNB0RXD3 */ + { RCAR_GP_PIN(5, 6), 24, 3 }, /* ETNB0RXER */ + { RCAR_GP_PIN(5, 5), 20, 3 }, /* ETNB0MDC */ + { RCAR_GP_PIN(5, 4), 16, 3 }, /* ETNB0LINKSTA */ + { RCAR_GP_PIN(5, 3), 12, 3 }, /* ETNB0WOL */ + { RCAR_GP_PIN(5, 2), 8, 3 }, /* ETNB0MD */ + { RCAR_GP_PIN(5, 1), 4, 3 }, /* RIIC0SDA */ + { RCAR_GP_PIN(5, 0), 0, 3 }, /* RIIC0SCL */ + } }, + /* DRV1CTRL5 */ + { 0x84, { + { RCAR_GP_PIN(5, 15), 28, 3 }, /* ETNB0TXCLK */ + { RCAR_GP_PIN(5, 14), 24, 3 }, /* ETNB0TXD3 */ + { RCAR_GP_PIN(5, 13), 20, 3 }, /* ETNB0TXER */ + { RCAR_GP_PIN(5, 12), 16, 3 }, /* ETNB0RXCLK */ + { RCAR_GP_PIN(5, 11), 12, 3 }, /* ETNB0RXD0 */ + { RCAR_GP_PIN(5, 10), 8, 3 }, /* ETNB0RXDV */ + { RCAR_GP_PIN(5, 9), 4, 3 }, /* ETNB0RXD2 */ + { RCAR_GP_PIN(5, 8), 0, 3 }, /* ETNB0RXD1 */ + } }, + /* DRV2CTRL5 */ + { 0x88, { + { RCAR_GP_PIN(5, 19), 12, 3 }, /* ETNB0TXD0 */ + { RCAR_GP_PIN(5, 18), 8, 3 }, /* ETNB0TXEN */ + { RCAR_GP_PIN(5, 17), 4, 3 }, /* ETNB0TXD2 */ + { RCAR_GP_PIN(5, 16), 0, 3 }, /* ETNB0TXD1 */ + } }, + /* DRV3CTRL5 is empty */ + /* DRV0CTRL6 */ + { 0x80, { + { RCAR_GP_PIN(6, 7), 28, 3 }, /* RLIN34RX/INTP20 */ + { RCAR_GP_PIN(6, 6), 24, 3 }, /* RLIN34TX */ + { RCAR_GP_PIN(6, 5), 20, 3 }, /* RLIN35RX/INTP21 */ + { RCAR_GP_PIN(6, 4), 16, 3 }, /* RLIN35TX */ + { RCAR_GP_PIN(6, 3), 12, 3 }, /* RLIN36RX/INTP22 */ + { RCAR_GP_PIN(6, 2), 8, 3 }, /* RLIN36TX */ + { RCAR_GP_PIN(6, 1), 4, 3 }, /* RLIN37RX/INTP23 */ + { RCAR_GP_PIN(6, 0), 0, 3 }, /* RLIN37TX */ + } }, + /* DRV1CTRL6 */ + { 0x84, { + { RCAR_GP_PIN(6, 15), 28, 3 }, /* RLIN30RX/INTP16 */ + { RCAR_GP_PIN(6, 14), 24, 3 }, /* RLIN30TX */ + { RCAR_GP_PIN(6, 13), 20, 3 }, /* RLIN31RX/INTP17 */ + { RCAR_GP_PIN(6, 12), 16, 3 }, /* RLIN31TX */ + { RCAR_GP_PIN(6, 11), 12, 3 }, /* RLIN32RX/INTP18 */ + { RCAR_GP_PIN(6, 10), 8, 3 }, /* RLIN32TX */ + { RCAR_GP_PIN(6, 9), 4, 3 }, /* RLIN33RX/INTP19 */ + { RCAR_GP_PIN(6, 8), 0, 3 }, /* RLIN33TX */ + } }, + /* DRV2CTRL6 */ + { 0x88, { + { RCAR_GP_PIN(6, 22), 24, 3 }, /* NMI1 */ + { RCAR_GP_PIN(6, 21), 20, 3 }, /* INTP32 */ + { RCAR_GP_PIN(6, 20), 16, 3 }, /* INTP33 */ + { RCAR_GP_PIN(6, 19), 12, 3 }, /* INTP34 */ + { RCAR_GP_PIN(6, 18), 8, 3 }, /* INTP35 */ + { RCAR_GP_PIN(6, 17), 4, 3 }, /* INTP36 */ + { RCAR_GP_PIN(6, 16), 0, 3 }, /* INTP37 */ + } }, + /* DRV3CTRL6 */ + { 0x8c, { + { RCAR_GP_PIN(6, 31), 28, 3 }, /* PRESETOUT1# */ + } }, + /* DRV0CTRL7 */ + { 0x80, { + { RCAR_GP_PIN(7, 7), 28, 3 }, /* CAN3RX/INTP3 */ + { RCAR_GP_PIN(7, 6), 24, 3 }, /* CAN3TX */ + { RCAR_GP_PIN(7, 5), 20, 3 }, /* CAN2RX/INTP2 */ + { RCAR_GP_PIN(7, 4), 16, 3 }, /* CAN2TX */ + { RCAR_GP_PIN(7, 3), 12, 3 }, /* CAN1RX/INTP1 */ + { RCAR_GP_PIN(7, 2), 8, 3 }, /* CAN1TX */ + { RCAR_GP_PIN(7, 1), 4, 3 }, /* CAN0RX/INTP0 */ + { RCAR_GP_PIN(7, 0), 0, 3 }, /* CAN0TX */ + } }, + /* DRV1CTRL7 */ + { 0x84, { + { RCAR_GP_PIN(7, 15), 28, 3 }, /* CAN7RX/INTP7 */ + { RCAR_GP_PIN(7, 14), 24, 3 }, /* CAN7TX */ + { RCAR_GP_PIN(7, 13), 20, 3 }, /* CAN6RX/INTP6 */ + { RCAR_GP_PIN(7, 12), 16, 3 }, /* CAN6TX */ + { RCAR_GP_PIN(7, 11), 12, 3 }, /* CAN5RX/INTP5 */ + { RCAR_GP_PIN(7, 10), 8, 3 }, /* CAN5TX */ + { RCAR_GP_PIN(7, 9), 4, 3 }, /* CAN4RX/INTP4 */ + { RCAR_GP_PIN(7, 8), 0, 3 }, /* CAN4TX */ + } }, + /* DRV2CTRL7 */ + { 0x88, { + { RCAR_GP_PIN(7, 23), 28, 3 }, /* CAN11RX/INTP11 */ + { RCAR_GP_PIN(7, 22), 24, 3 }, /* CAN11TX */ + { RCAR_GP_PIN(7, 21), 20, 3 }, /* CAN10RX/INTP10 */ + { RCAR_GP_PIN(7, 20), 16, 3 }, /* CAN10TX */ + { RCAR_GP_PIN(7, 19), 12, 3 }, /* CAN9RX/INTP9 */ + { RCAR_GP_PIN(7, 18), 8, 3 }, /* CAN9TX */ + { RCAR_GP_PIN(7, 17), 4, 3 }, /* CAN8RX/INTP8 */ + { RCAR_GP_PIN(7, 16), 0, 3 }, /* CAN8TX */ + } }, + /* DRV3CTRL7 */ + { 0x8c, { + { RCAR_GP_PIN(7, 31), 28, 3 }, /* CAN15RX/INTP15 */ + { RCAR_GP_PIN(7, 30), 24, 3 }, /* CAN15TX */ + { RCAR_GP_PIN(7, 29), 20, 3 }, /* CAN14RX/INTP14 */ + { RCAR_GP_PIN(7, 28), 16, 3 }, /* CAN14TX */ + { RCAR_GP_PIN(7, 27), 12, 3 }, /* CAN13RX/INTP13 */ + { RCAR_GP_PIN(7, 26), 8, 3 }, /* CAN13TX */ + { RCAR_GP_PIN(7, 25), 4, 3 }, /* CAN12RX/INTP12 */ + { RCAR_GP_PIN(7, 24), 0, 3 }, /* CAN12TX */ + } }, + /* DRV0CTRLSYS0 */ + { 0x80, { + { RCAR_GP_PIN(8, 0), 0, 3 }, /* PRESETOUT0# */ + } }, + /* DRV1CTRLSYS0 */ + { 0x84, { + { RCAR_GP_PIN(8, 12), 16, 2 }, /* DCUTCK0 */ + { RCAR_GP_PIN(8, 11), 12, 2 }, /* DCUTDO0 */ + { RCAR_GP_PIN(8, 10), 8, 2 }, /* DCUTDI0 */ + { RCAR_GP_PIN(8, 9), 4, 2 }, /* DCUTDY0# */ + { RCAR_GP_PIN(8, 8), 0, 2 }, /* DCUTMS0 */ + } }, + { }, +}; + +#define PFC_BIAS_REG(r1, r2) \ + .puen = r1, \ + .pud = r2, \ + .pins = + +const struct pfc_bias_reg pfc_bias_regs[] = { + { PFC_BIAS_REG(0xc0, 0xe0) { /* PUEN0, PUD0 */ + [0] = RCAR_GP_PIN(0, 0), /* SCIF_CLK */ + [1] = RCAR_GP_PIN(0, 1), /* HSCK0 */ + [2] = RCAR_GP_PIN(0, 2), /* HRX0 */ + [3] = RCAR_GP_PIN(0, 3), /* HTX0 */ + [4] = RCAR_GP_PIN(0, 4), /* HCTS0_N */ + [5] = RCAR_GP_PIN(0, 5), /* HRTS0_N */ + [6] = RCAR_GP_PIN(0, 6), /* RX0 */ + [7] = RCAR_GP_PIN(0, 7), /* TX0 */ + [8] = RCAR_GP_PIN(0, 8), /* SCK0 */ + [9] = RCAR_GP_PIN(0, 9), /* RTS0_N */ + [10] = RCAR_GP_PIN(0, 10), /* CTS0_N */ + [11] = RCAR_GP_PIN(0, 11), /* MSIOF0_SYNC */ + [12] = RCAR_GP_PIN(0, 12), /* MSIOF0_RXD */ + [13] = RCAR_GP_PIN(0, 13), /* MSIOF0_TXD */ + [14] = RCAR_GP_PIN(0, 14), /* MSIOF0_SCK */ + [15] = RCAR_GP_PIN(0, 15), /* MSIOF0_SS1 */ + [16] = RCAR_GP_PIN(0, 16), /* MSIOF0_SS2 */ + [17] = RCAR_GP_PIN(0, 17), /* IRQ0 */ + [18] = RCAR_GP_PIN(0, 18), /* IRQ1 */ + [19] = RCAR_GP_PIN(0, 19), /* IRQ2 */ + [20] = RCAR_GP_PIN(0, 20), /* IRQ3 */ + [21] = PIN_NONE, + [22] = PIN_NONE, + [23] = PIN_NONE, + [24] = PIN_NONE, + [25] = PIN_NONE, + [26] = PIN_NONE, + [27] = PIN_NONE, + [28] = PIN_NONE, + [29] = PIN_NONE, + [30] = PIN_NONE, + [31] = PIN_NONE, + } }, + { PFC_BIAS_REG(0xc0, 0xe0) { /* PUEN1, PUD1 */ + [0] = RCAR_GP_PIN(1, 0), /* GP1_00 */ + [1] = RCAR_GP_PIN(1, 1), /* GP1_01 */ + [2] = RCAR_GP_PIN(1, 2), /* GP1_02 */ + [3] = RCAR_GP_PIN(1, 3), /* GP1_03 */ + [4] = RCAR_GP_PIN(1, 4), /* GP1_04 */ + [5] = RCAR_GP_PIN(1, 5), /* GP1_05 */ + [6] = RCAR_GP_PIN(1, 6), /* GP1_06 */ + [7] = RCAR_GP_PIN(1, 7), /* GP1_07 */ + [8] = RCAR_GP_PIN(1, 8), /* GP1_08 */ + [9] = RCAR_GP_PIN(1, 9), /* GP1_09 */ + [10] = RCAR_GP_PIN(1, 10), /* GP1_10 */ + [11] = RCAR_GP_PIN(1, 11), /* GP1_11 */ + [12] = RCAR_GP_PIN(1, 12), /* MMC_SD_CLK */ + [13] = RCAR_GP_PIN(1, 13), /* MMC_SD_D0 */ + [14] = RCAR_GP_PIN(1, 14), /* MMC_SD_D1 */ + [15] = RCAR_GP_PIN(1, 15), /* MMC_SD_D2 */ + [16] = RCAR_GP_PIN(1, 16), /* MMC_SD_D3 */ + [17] = RCAR_GP_PIN(1, 17), /* MMC_D5 */ + [18] = RCAR_GP_PIN(1, 18), /* MMC_D4 */ + [19] = RCAR_GP_PIN(1, 19), /* MMC_D6 */ + [20] = RCAR_GP_PIN(1, 20), /* MMC_DS */ + [21] = RCAR_GP_PIN(1, 21), /* MMC_D7 */ + [22] = RCAR_GP_PIN(1, 22), /* MMC_SD_CMD */ + [23] = RCAR_GP_PIN(1, 23), /* SD_CD */ + [24] = RCAR_GP_PIN(1, 24), /* SD_WP */ + [25] = PIN_NONE, + [26] = PIN_NONE, + [27] = PIN_NONE, + [28] = PIN_NONE, + [29] = PIN_NONE, + [30] = PIN_NONE, + [31] = PIN_NONE, + } }, + { PFC_BIAS_REG(0xc0, 0xe0) { /* PUEN2, PUD2 */ + [0] = RCAR_GP_PIN(2, 0), /* RPC_INT_N */ + [1] = RCAR_GP_PIN(2, 1), /* RPC_WP_N */ + [2] = RCAR_GP_PIN(2, 2), /* RPC_RESET_N */ + [3] = RCAR_GP_PIN(2, 3), /* QSPI1_SSL */ + [4] = RCAR_GP_PIN(2, 4), /* QSPI1_IO3 */ + [5] = RCAR_GP_PIN(2, 5), /* QSPI1_MISO_IO1 */ + [6] = RCAR_GP_PIN(2, 6), /* QSPI1_IO2 */ + [7] = RCAR_GP_PIN(2, 7), /* QSPI1_MOSI_IO0 */ + [8] = RCAR_GP_PIN(2, 8), /* QSPI1_SPCLK */ + [9] = RCAR_GP_PIN(2, 9), /* QSPI0_MOSI_IO0 */ + [10] = RCAR_GP_PIN(2, 10), /* QSPI0_SPCLK */ + [11] = RCAR_GP_PIN(2, 11), /* QSPI0_IO2 */ + [12] = RCAR_GP_PIN(2, 12), /* QSPI0_MISO_IO1 */ + [13] = RCAR_GP_PIN(2, 13), /* QSPI0_SSL */ + [14] = RCAR_GP_PIN(2, 14), /* QSPI0_IO3 */ + [15] = RCAR_GP_PIN(2, 15), /* PCIE0_CLKREQ_N */ + [16] = RCAR_GP_PIN(2, 16), /* PCIE1_CLKREQ_N */ + [17] = PIN_NONE, + [18] = PIN_NONE, + [19] = PIN_NONE, + [20] = PIN_NONE, + [21] = PIN_NONE, + [22] = PIN_NONE, + [23] = PIN_NONE, + [24] = PIN_NONE, + [25] = PIN_NONE, + [26] = PIN_NONE, + [27] = PIN_NONE, + [28] = PIN_NONE, + [29] = PIN_NONE, + [30] = PIN_NONE, + [31] = PIN_NONE, + } }, + { PFC_BIAS_REG(0xc0, 0xe0) { /* PUEN3, PUD3 */ + [0] = RCAR_GP_PIN(3, 0), /* TSN1_MDIO_B */ + [1] = RCAR_GP_PIN(3, 1), /* TSN2_MDIO_B */ + [2] = RCAR_GP_PIN(3, 2), /* TSN0_MDIO_B */ + [3] = RCAR_GP_PIN(3, 3), /* TSN2_MDC_B */ + [4] = RCAR_GP_PIN(3, 4), /* TSN0_MDC_B */ + [5] = RCAR_GP_PIN(3, 5), /* TSN1_MDC_B */ + [6] = RCAR_GP_PIN(3, 6), /* TSN1_LINK_B */ + [7] = RCAR_GP_PIN(3, 7), /* TSN2_LINK_B */ + [8] = RCAR_GP_PIN(3, 8), /* TSN0_LINK_B */ + [9] = RCAR_GP_PIN(3, 9), /* TSN2_PHY_INT_B */ + [10] = RCAR_GP_PIN(3, 10), /* TSN0_PHY_INT_B */ + [11] = RCAR_GP_PIN(3, 11), /* TSN1_PHY_INT_B */ + [12] = RCAR_GP_PIN(3, 12), /* TSN0_MAGIC_B */ + [13] = RCAR_GP_PIN(3, 13), /* TSN1_AVTP_PPS */ + [14] = RCAR_GP_PIN(3, 14), /* TSN1_AVTP_MATCH_B */ + [15] = RCAR_GP_PIN(3, 15), /* TSN1_AVTP_CAPTURE_B */ + [16] = RCAR_GP_PIN(3, 16), /* TSN0_AVTP_PPS */ + [17] = RCAR_GP_PIN(3, 17), /* TSN0_AVTP_MATCH_B */ + [18] = RCAR_GP_PIN(3, 18), /* TSN0_AVTP_CAPTURE_B */ + [19] = PIN_NONE, + [20] = PIN_NONE, + [21] = PIN_NONE, + [22] = PIN_NONE, + [23] = PIN_NONE, + [24] = PIN_NONE, + [25] = PIN_NONE, + [26] = PIN_NONE, + [27] = PIN_NONE, + [28] = PIN_NONE, + [29] = PIN_NONE, + [30] = PIN_NONE, + [31] = PIN_NONE, + } }, + { PFC_BIAS_REG(0xc0, 0xe0) { /* PUEN4, PUD4 */ + [0] = RCAR_GP_PIN(4, 0), /* GP4_00 */ + [1] = RCAR_GP_PIN(4, 1), /* GP4_01 */ + [2] = RCAR_GP_PIN(4, 2), /* GP4_02 */ + [3] = RCAR_GP_PIN(4, 3), /* GP4_03 */ + [4] = RCAR_GP_PIN(4, 4), /* GP4_04 */ + [5] = RCAR_GP_PIN(4, 5), /* GP4_05 */ + [6] = RCAR_GP_PIN(4, 6), /* GP4_06 */ + [7] = RCAR_GP_PIN(4, 7), /* GP4_07 */ + [8] = RCAR_GP_PIN(4, 8), /* GP4_08 */ + [9] = RCAR_GP_PIN(4, 9), /* GP4_09 */ + [10] = RCAR_GP_PIN(4, 10), /* GP4_10 */ + [11] = RCAR_GP_PIN(4, 11), /* GP4_11 */ + [12] = RCAR_GP_PIN(4, 12), /* GP4_12 */ + [13] = RCAR_GP_PIN(4, 13), /* GP4_13 */ + [14] = RCAR_GP_PIN(4, 14), /* GP4_14 */ + [15] = RCAR_GP_PIN(4, 15), /* GP4_15 */ + [16] = RCAR_GP_PIN(4, 16), /* GP4_16 */ + [17] = RCAR_GP_PIN(4, 17), /* GP4_17 */ + [18] = RCAR_GP_PIN(4, 18), /* GP4_18 */ + [19] = RCAR_GP_PIN(4, 19), /* GP4_19 */ + [20] = RCAR_GP_PIN(4, 20), /* MSPI0SC */ + [21] = RCAR_GP_PIN(4, 21), /* MSPI0SI */ + [22] = RCAR_GP_PIN(4, 22), /* MSPI0SO/MSPI0DCS */ + [23] = RCAR_GP_PIN(4, 23), /* MSPI0CSS1 */ + [24] = RCAR_GP_PIN(4, 24), /* MSPI0CSS0 */ + [25] = RCAR_GP_PIN(4, 25), /* MSPI1SI */ + [26] = RCAR_GP_PIN(4, 26), /* MSPI1SO/MSPI1DCS */ + [27] = RCAR_GP_PIN(4, 27), /* MSPI1CSS0 */ + [28] = RCAR_GP_PIN(4, 28), /* MSPI1SC */ + [29] = RCAR_GP_PIN(4, 29), /* MSPI1CSS2 */ + [30] = RCAR_GP_PIN(4, 30), /* MSPI1CSS1 */ + [31] = PIN_NONE, + } }, + { PFC_BIAS_REG(0xc0, 0xe0) { /* PUEN5, PUD5 */ + [0] = RCAR_GP_PIN(5, 0), /* RIIC0SCL */ + [1] = RCAR_GP_PIN(5, 1), /* RIIC0SDA */ + [2] = RCAR_GP_PIN(5, 2), /* ETNB0MD */ + [3] = RCAR_GP_PIN(5, 3), /* ETNB0WOL */ + [4] = RCAR_GP_PIN(5, 4), /* ETNB0LINKSTA */ + [5] = RCAR_GP_PIN(5, 5), /* ETNB0MDC */ + [6] = RCAR_GP_PIN(5, 6), /* ETNB0RXER */ + [7] = RCAR_GP_PIN(5, 7), /* ETNB0RXD3 */ + [8] = RCAR_GP_PIN(5, 8), /* ETNB0RXD1 */ + [9] = RCAR_GP_PIN(5, 9), /* ETNB0RXD2 */ + [10] = RCAR_GP_PIN(5, 10), /* ETNB0RXDV */ + [11] = RCAR_GP_PIN(5, 11), /* ETNB0RXD0 */ + [12] = RCAR_GP_PIN(5, 12), /* ETNB0RXCLK */ + [13] = RCAR_GP_PIN(5, 13), /* ETNB0TXER */ + [14] = RCAR_GP_PIN(5, 14), /* ETNB0TXD3 */ + [15] = RCAR_GP_PIN(5, 15), /* ETNB0TXCLK */ + [16] = RCAR_GP_PIN(5, 16), /* ETNB0TXD1 */ + [17] = RCAR_GP_PIN(5, 17), /* ETNB0TXD2 */ + [18] = RCAR_GP_PIN(5, 18), /* ETNB0TXEN */ + [19] = RCAR_GP_PIN(5, 19), /* ETNB0TXD0 */ + [20] = PIN_NONE, + [21] = PIN_NONE, + [22] = PIN_NONE, + [23] = PIN_NONE, + [24] = PIN_NONE, + [25] = PIN_NONE, + [26] = PIN_NONE, + [27] = PIN_NONE, + [28] = PIN_NONE, + [29] = PIN_NONE, + [30] = PIN_NONE, + [31] = PIN_NONE, + } }, + { PFC_BIAS_REG(0xc0, 0xe0) { /* PUEN6, PUD6 */ + [0] = RCAR_GP_PIN(6, 0), /* RLIN37TX */ + [1] = RCAR_GP_PIN(6, 1), /* RLIN37RX/INTP23 */ + [2] = RCAR_GP_PIN(6, 2), /* RLIN36TX */ + [3] = RCAR_GP_PIN(6, 3), /* RLIN36RX/INTP22 */ + [4] = RCAR_GP_PIN(6, 4), /* RLIN35TX */ + [5] = RCAR_GP_PIN(6, 5), /* RLIN35RX/INTP21 */ + [6] = RCAR_GP_PIN(6, 6), /* RLIN34TX */ + [7] = RCAR_GP_PIN(6, 7), /* RLIN34RX/INTP20 */ + [8] = RCAR_GP_PIN(6, 8), /* RLIN33TX */ + [9] = RCAR_GP_PIN(6, 9), /* RLIN33RX/INTP19 */ + [10] = RCAR_GP_PIN(6, 10), /* RLIN32TX */ + [11] = RCAR_GP_PIN(6, 11), /* RLIN32RX/INTP18 */ + [12] = RCAR_GP_PIN(6, 12), /* RLIN31TX */ + [13] = RCAR_GP_PIN(6, 13), /* RLIN31RX/INTP17 */ + [14] = RCAR_GP_PIN(6, 14), /* RLIN30TX */ + [15] = RCAR_GP_PIN(6, 15), /* RLIN30RX/INTP16 */ + [16] = RCAR_GP_PIN(6, 16), /* INTP37 */ + [17] = RCAR_GP_PIN(6, 17), /* INTP36 */ + [18] = RCAR_GP_PIN(6, 18), /* INTP35 */ + [19] = RCAR_GP_PIN(6, 19), /* INTP34 */ + [20] = RCAR_GP_PIN(6, 20), /* INTP33 */ + [21] = RCAR_GP_PIN(6, 21), /* INTP32 */ + [22] = RCAR_GP_PIN(6, 22), /* NMI1 */ + [23] = PIN_NONE, + [24] = PIN_NONE, + [25] = PIN_NONE, + [26] = PIN_NONE, + [27] = PIN_NONE, + [28] = PIN_NONE, + [29] = PIN_NONE, + [30] = PIN_NONE, + [31] = PIN_NONE, + } }, + { PFC_BIAS_REG(0xc0, 0xe0) { /* PUEN7, PUD7 */ + [0] = RCAR_GP_PIN(7, 0), /* CAN0TX */ + [1] = RCAR_GP_PIN(7, 1), /* CAN0RX/INTP0 */ + [2] = RCAR_GP_PIN(7, 2), /* CAN1TX */ + [3] = RCAR_GP_PIN(7, 3), /* CAN1RX/INTP1 */ + [4] = RCAR_GP_PIN(7, 4), /* CAN2TX */ + [5] = RCAR_GP_PIN(7, 5), /* CAN2RX/INTP2 */ + [6] = RCAR_GP_PIN(7, 6), /* CAN3TX */ + [7] = RCAR_GP_PIN(7, 7), /* CAN3RX/INTP3 */ + [8] = RCAR_GP_PIN(7, 8), /* CAN4TX */ + [9] = RCAR_GP_PIN(7, 9), /* CAN4RX/INTP4 */ + [10] = RCAR_GP_PIN(7, 10), /* CAN5TX */ + [11] = RCAR_GP_PIN(7, 11), /* CAN5RX/INTP5 */ + [12] = RCAR_GP_PIN(7, 12), /* CAN6TX */ + [13] = RCAR_GP_PIN(7, 13), /* CAN6RX/INTP6 */ + [14] = RCAR_GP_PIN(7, 14), /* CAN7TX */ + [15] = RCAR_GP_PIN(7, 15), /* CAN7RX/INTP7 */ + [16] = RCAR_GP_PIN(7, 16), /* CAN8TX */ + [17] = RCAR_GP_PIN(7, 17), /* CAN8RX/INTP8 */ + [18] = RCAR_GP_PIN(7, 18), /* CAN9TX */ + [19] = RCAR_GP_PIN(7, 19), /* CAN9RX/INTP9 */ + [20] = RCAR_GP_PIN(7, 20), /* CAN10TX */ + [21] = RCAR_GP_PIN(7, 21), /* CAN10RX/INTP10 */ + [22] = RCAR_GP_PIN(7, 22), /* CAN11TX */ + [23] = RCAR_GP_PIN(7, 23), /* CAN11RX/INTP11 */ + [24] = RCAR_GP_PIN(7, 24), /* CAN12TX */ + [25] = RCAR_GP_PIN(7, 25), /* CAN12RX/INTP12 */ + [26] = RCAR_GP_PIN(7, 26), /* CAN13TX */ + [27] = RCAR_GP_PIN(7, 27), /* CAN13RX/INTP13 */ + [28] = RCAR_GP_PIN(7, 28), /* CAN14TX */ + [29] = RCAR_GP_PIN(7, 29), /* CAN14RX/INTP14 */ + [30] = RCAR_GP_PIN(7, 30), /* CAN15TX */ + [31] = RCAR_GP_PIN(7, 31), /* CAN15RX/INTP15 */ + } }, + { /* sentinel */ }, +}; + +const struct pfc_bias_reg *pfc_rcar_get_bias_regs(void) +{ + return pfc_bias_regs; +} + +const struct pfc_drive_reg *pfc_rcar_get_drive_regs(void) +{ + return pfc_drive_regs; +} + +int pfc_rcar_get_reg_index(uint8_t pin, uint8_t *reg_index) +{ + if (RCAR_IS_GP_PIN(pin) == false) + return -EINVAL; + + *reg_index = pin / 32; + + return 0; +} From 5461917952cc714cd0a9f7fb37266a560210dcfe Mon Sep 17 00:00:00 2001 From: Mykola Kvach Date: Thu, 20 Jul 2023 17:06:58 +0200 Subject: [PATCH 0213/3723] drivers: clock: rcar: Add r8a779f0 support Add support of r8a779f0 cpg driver. r8a779f0 soc has its own clock tree. Gen4 SoCs common registers addresses have been added in header. Signed-off-by: Mykola Kvach Signed-off-by: Aymeric Aillet --- drivers/clock_control/CMakeLists.txt | 1 + drivers/clock_control/Kconfig.rcar | 4 +- .../clock_control_r8a779f0_cpg_mssr.c | 186 ++++++++++++++++++ .../clock_control_renesas_cpg_mssr.h | 30 ++- .../clock/renesas,r8a779f0-cpg-mssr.yaml | 8 + .../dt-bindings/clock/r8a779f0_cpg_mssr.h | 67 +++++++ 6 files changed, 293 insertions(+), 3 deletions(-) create mode 100644 drivers/clock_control/clock_control_r8a779f0_cpg_mssr.c create mode 100644 dts/bindings/clock/renesas,r8a779f0-cpg-mssr.yaml create mode 100644 include/zephyr/dt-bindings/clock/r8a779f0_cpg_mssr.h diff --git a/drivers/clock_control/CMakeLists.txt b/drivers/clock_control/CMakeLists.txt index a1f553fc134..219aac76b97 100644 --- a/drivers/clock_control/CMakeLists.txt +++ b/drivers/clock_control/CMakeLists.txt @@ -71,6 +71,7 @@ zephyr_library_sources_ifdef(CONFIG_CLOCK_CONTROL_AGILEX5 clock_control_agilex5. if(CONFIG_CLOCK_CONTROL_RCAR_CPG_MSSR) zephyr_library_sources(clock_control_renesas_cpg_mssr.c) zephyr_library_sources_ifdef(CONFIG_DT_HAS_RENESAS_R8A7795_CPG_MSSR_ENABLED clock_control_r8a7795_cpg_mssr.c) + zephyr_library_sources_ifdef(CONFIG_DT_HAS_RENESAS_R8A779F0_CPG_MSSR_ENABLED clock_control_r8a779f0_cpg_mssr.c) endif() zephyr_library_sources_ifdef(CONFIG_CLOCK_CONTROL_AST10X0 clock_control_ast10x0.c) diff --git a/drivers/clock_control/Kconfig.rcar b/drivers/clock_control/Kconfig.rcar index b4a69a47e35..0caa0723554 100644 --- a/drivers/clock_control/Kconfig.rcar +++ b/drivers/clock_control/Kconfig.rcar @@ -1,9 +1,9 @@ -# Copyright (c) 2021-2022 IoT.bzh +# Copyright (c) 2021-2023 IoT.bzh # SPDX-License-Identifier: Apache-2.0 config CLOCK_CONTROL_RCAR_CPG_MSSR bool "RCar CPG MSSR driver" default y - depends on DT_HAS_RENESAS_R8A7795_CPG_MSSR_ENABLED + depends on SOC_FAMILY_RCAR help Enable support for Renesas RCar CPG MSSR driver. diff --git a/drivers/clock_control/clock_control_r8a779f0_cpg_mssr.c b/drivers/clock_control/clock_control_r8a779f0_cpg_mssr.c new file mode 100644 index 00000000000..c0d9f15cd58 --- /dev/null +++ b/drivers/clock_control/clock_control_r8a779f0_cpg_mssr.c @@ -0,0 +1,186 @@ +/* + * Copyright (c) 2023 EPAM Systems + * Copyright (c) 2023 IoT.bzh + * + * r8a779f0 Clock Pulse Generator / Module Standby and Software Reset + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#define DT_DRV_COMPAT renesas_r8a779f0_cpg_mssr + +#include +#include +#include +#include +#include +#include +#include +#include "clock_control_renesas_cpg_mssr.h" + +#define LOG_LEVEL CONFIG_CLOCK_CONTROL_LOG_LEVEL +#include +LOG_MODULE_DECLARE(clock_control_rcar); + +struct r8a779f0_cpg_mssr_cfg { + DEVICE_MMIO_ROM; /* Must be first */ +}; + +struct r8a779f0_cpg_mssr_data { + struct rcar_cpg_mssr_data cmn; /* Must be first */ +}; + +/* NOTE: the array MUST be sorted by module field */ +static struct cpg_clk_info_table core_props[] = { + RCAR_CORE_CLK_INFO_ITEM(R8A779F0_CLK_S0D12_PER, RCAR_CPG_NONE, RCAR_CPG_NONE, + RCAR_CPG_KHZ(66660)), + + RCAR_CORE_CLK_INFO_ITEM(R8A779F0_CLK_CL16M, RCAR_CPG_NONE, RCAR_CPG_NONE, + RCAR_CPG_KHZ(16660)), +}; + +/* NOTE: the array MUST be sorted by module field */ +static struct cpg_clk_info_table mod_props[] = { + RCAR_MOD_CLK_INFO_ITEM(702, R8A779F0_CLK_S0D12_PER), + RCAR_MOD_CLK_INFO_ITEM(704, R8A779F0_CLK_S0D12_PER), + + RCAR_MOD_CLK_INFO_ITEM(915, R8A779F0_CLK_CL16M), +}; + +static int r8a779f0_cpg_enable_disable_core(const struct device *dev, + struct cpg_clk_info_table *clk_info, uint32_t enable) +{ + ARG_UNUSED(dev); + ARG_UNUSED(clk_info); + ARG_UNUSED(enable); + + return -ENOTSUP; +} + +static int r8a779f0_cpg_core_clock_endisable(const struct device *dev, struct rcar_cpg_clk *clk, + bool enable) +{ + struct cpg_clk_info_table *clk_info; + struct r8a779f0_cpg_mssr_data *data = dev->data; + k_spinlock_key_t key; + + clk_info = rcar_cpg_find_clk_info_by_module_id(dev, clk->domain, clk->module); + if (!clk_info) { + return -EINVAL; + } + + if (enable) { + if (clk->rate > 0) { + int ret; + uintptr_t rate = clk->rate; + + ret = rcar_cpg_set_rate(dev, (clock_control_subsys_t)clk, + (clock_control_subsys_rate_t)rate); + if (ret < 0) { + return ret; + } + } + } + + key = k_spin_lock(&data->cmn.lock); + r8a779f0_cpg_enable_disable_core(dev, clk_info, enable); + k_spin_unlock(&data->cmn.lock, key); + + return 0; +} + +int r8a779f0_cpg_mssr_start_stop(const struct device *dev, clock_control_subsys_t sys, bool enable) +{ + struct rcar_cpg_clk *clk = (struct rcar_cpg_clk *)sys; + int ret; + + if (!dev || !sys) { + return -EINVAL; + } + + if (clk->domain == CPG_MOD) { + struct r8a779f0_cpg_mssr_data *data = dev->data; + k_spinlock_key_t key; + + key = k_spin_lock(&data->cmn.lock); + ret = rcar_cpg_mstp_clock_endisable(DEVICE_MMIO_GET(dev), clk->module, enable); + k_spin_unlock(&data->cmn.lock, key); + } else if (clk->domain == CPG_CORE) { + ret = r8a779f0_cpg_core_clock_endisable(dev, clk, enable); + } else { + ret = -EINVAL; + } + + return ret; +} + +static uint32_t r8a779f0_get_div_helper(uint32_t reg_val, uint32_t module) +{ + switch (module) { + case R8A779F0_CLK_S0D12_PER: + case R8A779F0_CLK_CL16M: + return 1; + default: + return RCAR_CPG_NONE; + } +} + +static int r8a779f0_set_rate_helper(uint32_t module, uint32_t *divider, uint32_t *div_mask) +{ + ARG_UNUSED(module); + ARG_UNUSED(divider); + ARG_UNUSED(div_mask); + + return -ENOTSUP; +} + +static int r8a779f0_cpg_mssr_start(const struct device *dev, clock_control_subsys_t sys) +{ + return r8a779f0_cpg_mssr_start_stop(dev, sys, true); +} + +static int r8a779f0_cpg_mssr_stop(const struct device *dev, clock_control_subsys_t sys) +{ + return r8a779f0_cpg_mssr_start_stop(dev, sys, false); +} + +static int r8a779f0_cpg_mssr_init(const struct device *dev) +{ + DEVICE_MMIO_MAP(dev, K_MEM_CACHE_NONE); + + rcar_cpg_build_clock_relationship(dev); + rcar_cpg_update_all_in_out_freq(dev); + return 0; +} + +static const struct clock_control_driver_api r8a779f0_cpg_mssr_api = { + .on = r8a779f0_cpg_mssr_start, + .off = r8a779f0_cpg_mssr_stop, + .get_rate = rcar_cpg_get_rate, + .set_rate = rcar_cpg_set_rate, +}; + +#define R8A779F0_MSSR_INIT(inst) \ + static struct r8a779f0_cpg_mssr_cfg cpg_mssr##inst##_cfg = { \ + DEVICE_MMIO_ROM_INIT(DT_DRV_INST(inst)), \ + }; \ + \ + static struct r8a779f0_cpg_mssr_data cpg_mssr##inst##_data = { \ + .cmn.clk_info_table[CPG_CORE] = core_props, \ + .cmn.clk_info_table_size[CPG_CORE] = ARRAY_SIZE(core_props), \ + .cmn.clk_info_table[CPG_MOD] = mod_props, \ + .cmn.clk_info_table_size[CPG_MOD] = ARRAY_SIZE(mod_props), \ + .cmn.get_div_helper = r8a779f0_get_div_helper, \ + .cmn.set_rate_helper = r8a779f0_set_rate_helper \ + }; \ + \ + DEVICE_DT_INST_DEFINE(inst, \ + &r8a779f0_cpg_mssr_init, \ + NULL, \ + &cpg_mssr##inst##_data, \ + &cpg_mssr##inst##_cfg, \ + PRE_KERNEL_1, \ + CONFIG_CLOCK_CONTROL_INIT_PRIORITY, \ + &r8a779f0_cpg_mssr_api); + +DT_INST_FOREACH_STATUS_OKAY(R8A779F0_MSSR_INIT) diff --git a/drivers/clock_control/clock_control_renesas_cpg_mssr.h b/drivers/clock_control/clock_control_renesas_cpg_mssr.h index d616567763e..5850d6f12db 100644 --- a/drivers/clock_control/clock_control_renesas_cpg_mssr.h +++ b/drivers/clock_control/clock_control_renesas_cpg_mssr.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2022 IoT.bzh + * Copyright (c) 2022-2023 IoT.bzh * * SPDX-License-Identifier: Apache-2.0 */ @@ -109,6 +109,34 @@ static const uint16_t srcr[] = { /* Peripherals Clocks */ #define S3D4_CLK_RATE 66600000 /* SCIF */ #define S0D12_CLK_RATE 66600000 /* PWM */ +#elif defined(CONFIG_SOC_SERIES_RCAR_GEN4) +/* Software Reset Clearing Register offsets */ +#define SRSTCLR(i) (0x2C80 + (i) * 4) + +/* CPG write protect offset */ +#define CPGWPR 0x0 + +/* Realtime Module Stop Control Register offsets */ +static const uint16_t mstpcr[] = { + 0x2D00, 0x2D04, 0x2D08, 0x2D0C, + 0x2D10, 0x2D14, 0x2D18, 0x2D1C, + 0x2D20, 0x2D24, 0x2D28, 0x2D2C, + 0x2D30, 0x2D34, 0x2D38, 0x2D3C, + 0x2D40, 0x2D44, 0x2D48, 0x2D4C, + 0x2D50, 0x2D54, 0x2D58, 0x2D5C, + 0x2D60, 0x2D64, 0x2D68, 0x2D6C, +}; + +/* Software Reset Register offsets */ +static const uint16_t srcr[] = { + 0x2C00, 0x2C04, 0x2C08, 0x2C0C, + 0x2C10, 0x2C14, 0x2C18, 0x2C1C, + 0x2C20, 0x2C24, 0x2C28, 0x2C2C, + 0x2C30, 0x2C34, 0x2C38, 0x2C3C, + 0x2C40, 0x2C44, 0x2C48, 0x2C4C, + 0x2C50, 0x2C54, 0x2C58, 0x2C5C, + 0x2C60, 0x2C64, 0x2C68, 0x2C6C, +}; #endif /* CONFIG_SOC_SERIES_RCAR_GEN3 */ void rcar_cpg_write(uint32_t base_address, uint32_t reg, uint32_t val); diff --git a/dts/bindings/clock/renesas,r8a779f0-cpg-mssr.yaml b/dts/bindings/clock/renesas,r8a779f0-cpg-mssr.yaml new file mode 100644 index 00000000000..89d3fa6fdfe --- /dev/null +++ b/dts/bindings/clock/renesas,r8a779f0-cpg-mssr.yaml @@ -0,0 +1,8 @@ +# Copyright (c) 2023 EPAM Systems +# SPDX-License-Identifier: Apache-2.0 + +description: Renesas R8A779F0 SoC Clock Pulse Generator / Module Standby and Software Reset + +compatible: "renesas,r8a779f0-cpg-mssr" + +include: renesas,rcar-cpg-mssr.yaml diff --git a/include/zephyr/dt-bindings/clock/r8a779f0_cpg_mssr.h b/include/zephyr/dt-bindings/clock/r8a779f0_cpg_mssr.h new file mode 100644 index 00000000000..d0f01809795 --- /dev/null +++ b/include/zephyr/dt-bindings/clock/r8a779f0_cpg_mssr.h @@ -0,0 +1,67 @@ +/* + * Copyright (c) 2023 IoT.bzh + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#ifndef ZEPHYR_INCLUDE_DT_BINDINGS_CLOCK_RENESAS_CLOCK_R8A779F0_H_ +#define ZEPHYR_INCLUDE_DT_BINDINGS_CLOCK_RENESAS_CLOCK_R8A779F0_H_ + +#include "renesas_cpg_mssr.h" + +/* r8a779f0 CPG Core Clocks */ +#define R8A779F0_CLK_Z0 0 +#define R8A779F0_CLK_Z1 1 +#define R8A779F0_CLK_ZR 2 +#define R8A779F0_CLK_ZX 3 +#define R8A779F0_CLK_ZS 4 +#define R8A779F0_CLK_ZT 5 +#define R8A779F0_CLK_ZTR 6 +#define R8A779F0_CLK_S0D2 7 +#define R8A779F0_CLK_S0D3 8 +#define R8A779F0_CLK_S0D4 9 +#define R8A779F0_CLK_S0D2_MM 10 +#define R8A779F0_CLK_S0D3_MM 11 +#define R8A779F0_CLK_S0D4_MM 12 +#define R8A779F0_CLK_S0D2_RT 13 +#define R8A779F0_CLK_S0D3_RT 14 +#define R8A779F0_CLK_S0D4_RT 15 +#define R8A779F0_CLK_S0D6_RT 16 +#define R8A779F0_CLK_S0D3_PER 17 +#define R8A779F0_CLK_S0D6_PER 18 +#define R8A779F0_CLK_S0D12_PER 19 +#define R8A779F0_CLK_S0D24_PER 20 +#define R8A779F0_CLK_S0D2_HSC 21 +#define R8A779F0_CLK_S0D3_HSC 22 +#define R8A779F0_CLK_S0D4_HSC 23 +#define R8A779F0_CLK_S0D6_HSC 24 +#define R8A779F0_CLK_S0D12_HSC 25 +#define R8A779F0_CLK_S0D2_CC 26 +#define R8A779F0_CLK_CL 27 +#define R8A779F0_CLK_CL16M 28 +#define R8A779F0_CLK_CL16M_MM 29 +#define R8A779F0_CLK_CL16M_RT 30 +#define R8A779F0_CLK_CL16M_PER 31 +#define R8A779F0_CLK_CL16M_HSC 32 +#define R8A779F0_CLK_ZB3 33 +#define R8A779F0_CLK_ZB3D2 34 +#define R8A779F0_CLK_ZB3D4 35 +#define R8A779F0_CLK_SD0H 36 +#define R8A779F0_CLK_SD0 37 +#define R8A779F0_CLK_RPC 38 +#define R8A779F0_CLK_RPCD2 39 +#define R8A779F0_CLK_MSO 40 +#define R8A779F0_CLK_POST 41 +#define R8A779F0_CLK_POST2 42 +#define R8A779F0_CLK_SASYNCRT 43 +#define R8A779F0_CLK_SASYNCPERD1 44 +#define R8A779F0_CLK_SASYNCPERD2 45 +#define R8A779F0_CLK_SASYNCPERD4 46 +#define R8A779F0_CLK_DBGSOC_HSC 47 +#define R8A779F0_CLK_RSW2 48 +#define R8A779F0_CLK_CPEX 49 +#define R8A779F0_CLK_CBFUSA 50 +#define R8A779F0_CLK_R 51 +#define R8A779F0_CLK_OSC 52 + +#endif /* ZEPHYR_INCLUDE_DT_BINDINGS_CLOCK_RENESAS_CLOCK_R8A779F0_H_ */ From cfb93c1c82932c4c64aa65533b35ea386ed70e7c Mon Sep 17 00:00:00 2001 From: Aymeric Aillet Date: Wed, 27 Jul 2022 15:13:07 +0200 Subject: [PATCH 0214/3723] dts: arm: Add Renesas r8a779f0 support r8a779f0 is also know as S4, this SoC is part of the Gen4 SoC series, has 8 Cortex-A55 and a dual core lockstep Cortex-R52 processor. SCIF0 is dedicated to Zephyr and SCIF3 to Linux. **Control Domains** IMPORTANT: This SoC is divided into two "domains": - Application domain contains some peripherals as well as A55 & R52 cores. - Control domain that contain a G4MH/RH850 MCU and other peripherals. In order to access control domain peripherals such as gpio4-7 and CAN-FD from application domain, the G4MH MCU has to unlock a protection mechanism from control domain buses. "Protected" controllers will be flagged in gen4 device trees, warning users that they need to flash a custom G4MH firmware to unlock access to these controllers. **Clock controller** This SoC clock controller is offering "domains" for each world (Zephyr/Linux). These domains are several "entry points" to the clock controller which are arbitrated to avoid a world from turning off a clock needed by another one. We decided to use the same domain as Linux because the security mechanism as to be implemented before accessing another domain. Signed-off-by: Aymeric Aillet --- dts/arm/renesas/rcar/gen4/r8a779f0.dtsi | 70 +++++++++++++++++++ dts/arm/renesas/rcar/gen4/rcar_gen4_cr52.dtsi | 68 ++++++++++++++++++ 2 files changed, 138 insertions(+) create mode 100644 dts/arm/renesas/rcar/gen4/r8a779f0.dtsi create mode 100644 dts/arm/renesas/rcar/gen4/rcar_gen4_cr52.dtsi diff --git a/dts/arm/renesas/rcar/gen4/r8a779f0.dtsi b/dts/arm/renesas/rcar/gen4/r8a779f0.dtsi new file mode 100644 index 00000000000..0b1667aa4a1 --- /dev/null +++ b/dts/arm/renesas/rcar/gen4/r8a779f0.dtsi @@ -0,0 +1,70 @@ +/* + * Copyright (c) 2023 IoT.bzh + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include +#include +#include + +/ { + soc { + /* The last four registers of this controller are + * located in the control domain + * A custom G4MH/RH850 µC firmware has to be flashed to access them + */ + pfc: pin-controller@e6050000 { + compatible = "renesas,rcar-pfc"; + reg = <0xe6050000 0x16c>, <0xe6050800 0x16c>, + <0xe6051000 0x16c>, <0xe6051800 0x16c>, + <0xdfd90000 0x16c>, <0xdfd90800 0x16c>, + <0xdfd91000 0x16c>, <0xdfd91800 0x16c>; + }; + + /* Clock controller + * Using domain 0 as Linux + */ + cpg: clock-controller@e6150000 { + compatible = "renesas,r8a779f0-cpg-mssr"; + reg = <0xe6150000 0x4000>; + #clock-cells = <2>; + }; + + gpio0: gpio@e6050180 { + compatible = "renesas,rcar-gpio"; + reg = <0xe6050180 0x54>; + #gpio-cells = <2>; + gpio-controller; + interrupts = ; + clocks = <&cpg CPG_MOD 915>; + status = "disabled"; + }; + + /* + * Control domain security has to be released to access gpio4 controller + * A custom G4MH/RH850 µC firmware has to be flashed to do that + */ + gpio4: gpio@dfd90180 { + compatible = "renesas,rcar-gpio"; + reg = <0xdfd90180 0x54>; + #gpio-cells = <2>; + gpio-controller; + interrupts = ; + clocks = <&cpg CPG_MOD 915>; + status = "disabled"; + }; + + /* Zephyr console */ + scif0: serial@e6e60000 { + interrupts = ; + clocks = <&cpg CPG_MOD 702>, <&cpg CPG_CORE R8A779F0_CLK_S0D12_PER>; + }; + + /* Linux console */ + scif3: serial@e6c50000 { + interrupts = ; + clocks = <&cpg CPG_MOD 704>, <&cpg CPG_CORE R8A779F0_CLK_S0D12_PER>; + }; + }; +}; diff --git a/dts/arm/renesas/rcar/gen4/rcar_gen4_cr52.dtsi b/dts/arm/renesas/rcar/gen4/rcar_gen4_cr52.dtsi new file mode 100644 index 00000000000..1ce2ec9151c --- /dev/null +++ b/dts/arm/renesas/rcar/gen4/rcar_gen4_cr52.dtsi @@ -0,0 +1,68 @@ +/* + * Copyright (c) 2023 IoT.bzh + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include +#include +#include +#include + +/ { + cpus { + #address-cells = <1>; + #size-cells = <0>; + + cpu@0 { + device_type = "cpu"; + compatible = "arm,cortex-r52"; + reg = <0>; + }; + }; + + timer { + compatible = "arm,armv8-timer"; + interrupt-parent = <&gic>; + interrupts = , + , + , + ; + }; + + soc { + interrupt-parent = <&gic>; + + sram0: memory@40040000 { + compatible = "mmio-sram"; + reg = <0x40040000 0x100000>; + }; + + gic: interrupt-controller@f0000000 { + compatible = "arm,gic-v3", "arm,gic"; + reg = <0xf0000000 0x1000>, + <0xf0100000 0x20000>; + interrupt-controller; + #interrupt-cells = <4>; + status = "okay"; + }; + + scif0: serial@e6e60000 { + compatible = "renesas,rcar-scif"; + reg = <0xe6e60000 0x64>; + current-speed = <115200>; + status = "disabled"; + }; + + scif3: serial@e6c50000 { + compatible = "renesas,rcar-scif"; + reg = <0xe6c50000 0x64>; + current-speed = <115200>; + status = "disabled"; + }; + }; +}; From f2061a073af483452a9fa6486e8c0bc5926d18f8 Mon Sep 17 00:00:00 2001 From: Aymeric Aillet Date: Tue, 21 Mar 2023 18:09:44 +0100 Subject: [PATCH 0215/3723] soc: arm: reneas: Add r8a779f0 support r8a779f0 SoC is part of the Renesas R-Car Gen4 SoC series. This SoC has a dual core lockstep Cortex-R52 CPU. Signed-off-by: Aymeric Aillet --- .../gen4/Kconfig.defconfig.r8a779f0 | 15 +++++++++++++++ .../renesas_rcar/gen4/Kconfig.defconfig.series | 13 +++++++++++++ soc/arm/renesas_rcar/gen4/Kconfig.series | 13 +++++++++++++ soc/arm/renesas_rcar/gen4/Kconfig.soc | 11 +++++++++++ soc/arm/renesas_rcar/gen4/linker.ld | 7 +++++++ soc/arm/renesas_rcar/gen4/soc.h | 18 ++++++++++++++++++ 6 files changed, 77 insertions(+) create mode 100644 soc/arm/renesas_rcar/gen4/Kconfig.defconfig.r8a779f0 create mode 100644 soc/arm/renesas_rcar/gen4/Kconfig.defconfig.series create mode 100644 soc/arm/renesas_rcar/gen4/Kconfig.series create mode 100644 soc/arm/renesas_rcar/gen4/Kconfig.soc create mode 100644 soc/arm/renesas_rcar/gen4/linker.ld create mode 100644 soc/arm/renesas_rcar/gen4/soc.h diff --git a/soc/arm/renesas_rcar/gen4/Kconfig.defconfig.r8a779f0 b/soc/arm/renesas_rcar/gen4/Kconfig.defconfig.r8a779f0 new file mode 100644 index 00000000000..6da34845bf9 --- /dev/null +++ b/soc/arm/renesas_rcar/gen4/Kconfig.defconfig.r8a779f0 @@ -0,0 +1,15 @@ +# Copyright (c) 2023 IoT.bzh +# SPDX-License-Identifier: Apache-2.0 + +if SOC_R8A779F0 + +config SOC + default "r8a779f0" + +config NUM_IRQS + default 1216 #960 SPI + 256 LPI + +config PINCTRL + default y + +endif # SOC_R8A779F0 diff --git a/soc/arm/renesas_rcar/gen4/Kconfig.defconfig.series b/soc/arm/renesas_rcar/gen4/Kconfig.defconfig.series new file mode 100644 index 00000000000..36218fe504f --- /dev/null +++ b/soc/arm/renesas_rcar/gen4/Kconfig.defconfig.series @@ -0,0 +1,13 @@ +# Renesas R-Car Gen4 SoC line + +# Copyright (c) 2023 IoT.bzh +# SPDX-License-Identifier: Apache-2.0 + +if SOC_SERIES_RCAR_GEN4 + +source "soc/arm/renesas_rcar/gen4/Kconfig.defconfig.r8a779*" + +config SOC_SERIES + default "gen4" + +endif # SOC_SERIES_RCAR_GEN4 diff --git a/soc/arm/renesas_rcar/gen4/Kconfig.series b/soc/arm/renesas_rcar/gen4/Kconfig.series new file mode 100644 index 00000000000..606b2c50e43 --- /dev/null +++ b/soc/arm/renesas_rcar/gen4/Kconfig.series @@ -0,0 +1,13 @@ +# Copyright (c) 2023 IoT.bzh +# SPDX-License-Identifier: Apache-2.0 + +config SOC_SERIES_RCAR_GEN4 + bool "Renesas R-Car Gen4 Cortex R52" + select ARM + select CPU_CORTEX_R52 + select GIC_SINGLE_SECURITY_STATE + select SOC_FAMILY_RCAR + select CLOCK_CONTROL_RCAR_CPG_MSSR if CLOCK_CONTROL + select ARM_ARCH_TIMER + help + Enable support for Renesas R-Car Gen4 SoC series diff --git a/soc/arm/renesas_rcar/gen4/Kconfig.soc b/soc/arm/renesas_rcar/gen4/Kconfig.soc new file mode 100644 index 00000000000..5c443d6101e --- /dev/null +++ b/soc/arm/renesas_rcar/gen4/Kconfig.soc @@ -0,0 +1,11 @@ +# Copyright (c) 2023 IoT.bzh +# SPDX-License-Identifier: Apache-2.0 + +choice + prompt "Renesas RCar SoC Selection" + depends on SOC_SERIES_RCAR_GEN4 + +config SOC_R8A779F0 + bool "r8a779f0" + +endchoice diff --git a/soc/arm/renesas_rcar/gen4/linker.ld b/soc/arm/renesas_rcar/gen4/linker.ld new file mode 100644 index 00000000000..a51ff84991f --- /dev/null +++ b/soc/arm/renesas_rcar/gen4/linker.ld @@ -0,0 +1,7 @@ +/* + * Copyright (c) 2023 IoT.bzh + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include diff --git a/soc/arm/renesas_rcar/gen4/soc.h b/soc/arm/renesas_rcar/gen4/soc.h new file mode 100644 index 00000000000..3717fb8a8a8 --- /dev/null +++ b/soc/arm/renesas_rcar/gen4/soc.h @@ -0,0 +1,18 @@ +/* + * Copyright (c) 2023 IoT.bzh + * + * SPDX-License-Identifier: Apache-2.0 + * + */ + +#ifndef _SOC__H_ +#define _SOC__H_ + +/* Define CMSIS configurations */ +#define __CR_REV 1U + +/* Do not let CMSIS to handle GIC and Timer */ +#define __GIC_PRESENT 0 +#define __TIM_PRESENT 0 + +#endif /* _SOC__H_ */ From cf4ab0e907b3586761c1806dc07fe597f02abe72 Mon Sep 17 00:00:00 2001 From: Aymeric Aillet Date: Wed, 27 Jul 2022 16:24:51 +0200 Subject: [PATCH 0216/3723] boards: arm: Add Renesas Spider support Renesas Spider board use a S4 SoC (r8a779f0). Add basic support for UART, GPIO and clock control. We are using SCIF0 as SCIF3 is used by Linux. Signed-off-by: Aymeric Aillet --- boards/arm/rcar_spider/Kconfig.board | 6 ++ boards/arm/rcar_spider/Kconfig.defconfig | 9 +++ boards/arm/rcar_spider/board.cmake | 3 + .../rcar_spider/rcar_spider_cr52-pinctrl.dtsi | 25 ++++++++ boards/arm/rcar_spider/rcar_spider_cr52.dts | 58 +++++++++++++++++++ boards/arm/rcar_spider/rcar_spider_cr52.yaml | 11 ++++ .../rcar_spider/rcar_spider_cr52_defconfig | 13 +++++ boards/arm/rcar_spider/support/openocd.cfg | 27 +++++++++ 8 files changed, 152 insertions(+) create mode 100644 boards/arm/rcar_spider/Kconfig.board create mode 100644 boards/arm/rcar_spider/Kconfig.defconfig create mode 100644 boards/arm/rcar_spider/board.cmake create mode 100644 boards/arm/rcar_spider/rcar_spider_cr52-pinctrl.dtsi create mode 100644 boards/arm/rcar_spider/rcar_spider_cr52.dts create mode 100644 boards/arm/rcar_spider/rcar_spider_cr52.yaml create mode 100644 boards/arm/rcar_spider/rcar_spider_cr52_defconfig create mode 100644 boards/arm/rcar_spider/support/openocd.cfg diff --git a/boards/arm/rcar_spider/Kconfig.board b/boards/arm/rcar_spider/Kconfig.board new file mode 100644 index 00000000000..1ff4c7e794d --- /dev/null +++ b/boards/arm/rcar_spider/Kconfig.board @@ -0,0 +1,6 @@ +# Copyright (c) 2023 IoT.bzh +# SPDX-License-Identifier: Apache-2.0 + +config BOARD_RCAR_SPIDER_CR52 + bool "Cortex-R52 for Renesas Spider" + depends on SOC_R8A779F0 diff --git a/boards/arm/rcar_spider/Kconfig.defconfig b/boards/arm/rcar_spider/Kconfig.defconfig new file mode 100644 index 00000000000..b2a590250f9 --- /dev/null +++ b/boards/arm/rcar_spider/Kconfig.defconfig @@ -0,0 +1,9 @@ +# Copyright (c) 2023 IoT.bzh +# SPDX-License-Identifier: Apache-2.0 + +if BOARD_RCAR_SPIDER_CR52 + +config BOARD + default "rcar_spider_cr52" + +endif # BOARD_RCAR_SPIDER_CR52 diff --git a/boards/arm/rcar_spider/board.cmake b/boards/arm/rcar_spider/board.cmake new file mode 100644 index 00000000000..b106c562c54 --- /dev/null +++ b/boards/arm/rcar_spider/board.cmake @@ -0,0 +1,3 @@ +# SPDX-License-Identifier: Apache-2.0 +board_runner_args(openocd "--use-elf") +include(${ZEPHYR_BASE}/boards/common/openocd.board.cmake) diff --git a/boards/arm/rcar_spider/rcar_spider_cr52-pinctrl.dtsi b/boards/arm/rcar_spider/rcar_spider_cr52-pinctrl.dtsi new file mode 100644 index 00000000000..b164961271a --- /dev/null +++ b/boards/arm/rcar_spider/rcar_spider_cr52-pinctrl.dtsi @@ -0,0 +1,25 @@ +/* + * Copyright (c) 2023 IoT.bzh + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include + +&pfc { + scif0_data_tx_default: scif0_data_tx_default { + pin = ; + }; + + scif0_data_rx_default: scif0_data_rx_default { + pin = ; + }; + + scif3_data_tx_default: scif3_data_tx_default { + pin = ; + }; + + scif3_data_rx_default: scif3_data_rx_default { + pin = ; + }; +}; diff --git a/boards/arm/rcar_spider/rcar_spider_cr52.dts b/boards/arm/rcar_spider/rcar_spider_cr52.dts new file mode 100644 index 00000000000..6d89b3ede94 --- /dev/null +++ b/boards/arm/rcar_spider/rcar_spider_cr52.dts @@ -0,0 +1,58 @@ +/* + * Copyright (c) 2023 IoT.bzh + * + * SPDX-License-Identifier: Apache-2.0 + * + */ + +/dts-v1/; +#include +#include "rcar_spider_cr52-pinctrl.dtsi" +#include + +/ { + model = "Renesas Spider board"; + compatible = "renesas,spider-cr52"; + + chosen { + zephyr,sram = &sram0; + zephyr,console = &scif0; + zephyr,shell-uart = &scif0; + }; + + leds { + compatible = "gpio-leds"; + user_led: led_8 { + gpios = <&gpio0 14 GPIO_ACTIVE_HIGH>; + label = "User LED"; + }; + }; + + gpio_keys { + compatible = "gpio-keys"; + user_button: sw10 { + gpios = <&gpio4 13 GPIO_ACTIVE_LOW>; + label = "User switch"; + zephyr,code = ; + }; + }; + + aliases { + led0 = &user_led; + sw0 = &user_button; + }; +}; + +&scif0 { + pinctrl-0 = <&scif0_data_tx_default &scif0_data_rx_default>; + pinctrl-names = "default"; + status = "okay"; +}; + +&gpio0 { + status = "okay"; +}; + +&gpio4 { + status = "okay"; +}; diff --git a/boards/arm/rcar_spider/rcar_spider_cr52.yaml b/boards/arm/rcar_spider/rcar_spider_cr52.yaml new file mode 100644 index 00000000000..6dea2b344b7 --- /dev/null +++ b/boards/arm/rcar_spider/rcar_spider_cr52.yaml @@ -0,0 +1,11 @@ +identifier: rcar_spider_cr52 +name: Cortex r52 for Renesas Spider +type: mcu +arch: arm +toolchain: + - zephyr + - gnuarmemb +supported: + - gpio + - clock_control + - uart diff --git a/boards/arm/rcar_spider/rcar_spider_cr52_defconfig b/boards/arm/rcar_spider/rcar_spider_cr52_defconfig new file mode 100644 index 00000000000..7eea72fd80a --- /dev/null +++ b/boards/arm/rcar_spider/rcar_spider_cr52_defconfig @@ -0,0 +1,13 @@ +CONFIG_SOC_R8A779F0=y +CONFIG_SOC_SERIES_RCAR_GEN4=y +CONFIG_BOARD_RCAR_SPIDER_CR52=y +CONFIG_CLOCK_CONTROL=y +CONFIG_SYS_CLOCK_HW_CYCLES_PER_SEC=12500000 +CONFIG_CONSOLE=y +CONFIG_RAM_CONSOLE=y +CONFIG_FLASH_SIZE=0 +CONFIG_FLASH_BASE_ADDRESS=0 +CONFIG_SERIAL=y +CONFIG_UART_CONSOLE=y +CONFIG_UART_INTERRUPT_DRIVEN=y +CONFIG_GPIO=y diff --git a/boards/arm/rcar_spider/support/openocd.cfg b/boards/arm/rcar_spider/support/openocd.cfg new file mode 100644 index 00000000000..518b63c7f48 --- /dev/null +++ b/boards/arm/rcar_spider/support/openocd.cfg @@ -0,0 +1,27 @@ +# Renesas R-Car Spider S4 Cortex-R52 Board Config + +source [find interface/ftdi/olimex-arm-usb-ocd-h.cfg] +source [find target/renesas_rcar_reset_common.cfg] + +set _CHIPNAME r8a779f0 +set _CORE_NAME r52 +set _TARGETNAME $_CHIPNAME.$_CORE_NAME +set _CTINAME $_TARGETNAME.cti +set _DAPNAME $_CHIPNAME.dap +set DAP_TAPID 0x5ba00477 + +set CR52_DBGBASE 0x80c10000 +set CR52_CTIBASE 0x80c20000 + +adapter srst delay 1000 +adapter speed 20000 +global $_CHIPNAME +transport select jtag + +jtag newtap $_CHIPNAME cpu -irlen 4 -ircapture 0x01 -irmask 0x0f -expected-id $DAP_TAPID +dap create $_DAPNAME -chain-position $_CHIPNAME.cpu + +cti create $_CTINAME -dap $_DAPNAME -ap-num 1 -baseaddr $CR52_CTIBASE +target create $_TARGETNAME armv8r -dap $_DAPNAME -ap-num 1 -dbgbase $CR52_DBGBASE -cti $_CTINAME + +$_TARGETNAME configure -rtos auto From 36f2627363f4c0f4374a759f587456967815316b Mon Sep 17 00:00:00 2001 From: Aymeric Aillet Date: Tue, 21 Mar 2023 16:12:51 +0100 Subject: [PATCH 0217/3723] doc: Add Renesas Spider board documentation Adding Spider board documentation based on Renesas official documentation and following Zephyr guideline. The documentation is describing the board and its current Zephyr support. Signed-off-by: Aymeric Aillet --- .../doc/img/rcar_s4_block_diagram.jpg | Bin 0 -> 95075 bytes .../doc/img/rcar_s4_spider_full.jpg | Bin 0 -> 82817 bytes boards/arm/rcar_spider/doc/rcar_spider.rst | 200 ++++++++++++++++++ 3 files changed, 200 insertions(+) create mode 100644 boards/arm/rcar_spider/doc/img/rcar_s4_block_diagram.jpg create mode 100644 boards/arm/rcar_spider/doc/img/rcar_s4_spider_full.jpg create mode 100644 boards/arm/rcar_spider/doc/rcar_spider.rst diff --git a/boards/arm/rcar_spider/doc/img/rcar_s4_block_diagram.jpg b/boards/arm/rcar_spider/doc/img/rcar_s4_block_diagram.jpg new file mode 100644 index 0000000000000000000000000000000000000000..76bda515cfb8363cea03e4f3363cf40228ef2087 GIT binary patch literal 95075 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
dm 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

Vd(E$R8vs*)2qLz-Uo;#e8apfKMFni;e3ZGg0D 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 literal 0 HcmV?d00001 diff --git a/boards/arm/rcar_spider/doc/rcar_spider.rst b/boards/arm/rcar_spider/doc/rcar_spider.rst new file mode 100644 index 00000000000..33deb1f27a8 --- /dev/null +++ b/boards/arm/rcar_spider/doc/rcar_spider.rst @@ -0,0 +1,200 @@ +.. _rcar_spider_boards: + +Renesas R-Car Spider +#################### + +Overview +******** + +| R-Car S4 enables the launch of Car Server/CoGW with high performance, high-speed networking, +| high security and high functional safety levels that are required as E/E architectures +| evolve into domains and zones. + +| The R-Car S4 solution allows designers to re-use up to 88 percent of software code developed +| for 3rd generation R-Car SoCs and RH850 MCU applications.\ +| The software package supports the real-time cores with various drivers and basic software +| such as Linux BSP and hypervisors. + +The Renesas R-Car Spider board is the Renesas R-Car S4 reference board and is designed for +evaluating features and performance of this SoC. + +.. figure:: img/rcar_s4_spider_full.jpg + :align: center + :alt: R-Car S4 Spider + +More information about the board can be found at `Renesas R-Car S4 Spider`_ website. + +Hardware +******** + +Hardware capabilities for the S4 Spider board can be found on the `eLinux S4 Spider`_ page. + +.. figure:: img/rcar_s4_block_diagram.jpg + :align: center + :alt: R-Car S4 Spider block diagram + +.. note:: We support Zephyr running on the CR52 processor that is provided for RTOS purpose. + +More information about the SoC that equips the board can be found here: + +- `Renesas R-Car S4 chip`_ + +Supported Features +================== + +Here are the current supported features when running Zephyr Project on the R-Car S4 Spider CR52: + ++-----------+------------------------------+--------------------------------+ +| Interface | Driver/components | Support level | ++===========+==============================+================================+ +| PINMUX | pinmux | | ++-----------+------------------------------+--------------------------------+ +| CLOCK | clock_control | | ++-----------+------------------------------+--------------------------------+ +| GPIO | gpio | | ++-----------+------------------------------+--------------------------------+ +| UART | uart | serial port-polling | ++ + + + +| | FT232RQ | serial port-interrupt | ++-----------+------------------------------+--------------------------------+ +| I2C | i2c | interrupt driven | ++-----------+------------------------------+--------------------------------+ +| PWM | pwm | All channels | ++-----------+------------------------------+--------------------------------+ + +It is also currently possible to write on the ram console. + +More features will be supported soon. + +Connections and IOs +=================== + +| The "Spider board" consists of a CPU board and a Breakout board. +| The CPU board is stuck on top of the Breakout board. + +Here are the official IOs figures from eLinux for S4 board: + +`S4 Spider CPU board IOs`_ + +`S4 Spider breakout board IOs`_ + +GPIO +---- + +By running Zephyr on S4 Spider, the software controllable LED 'LED8' can be used as output. + +UART +---- + +Here is information about both serial ports provided on the S4 Spider board : + ++--------------------+----------+--------------------+-------------+------------------------+ +| Physical Interface | Location | Software Interface | Converter | Further Information | ++====================+==========+====================+=============+========================+ +| CN20 USB Port | CPU Board| SCIF0/HSCIF1 | FT232HQ | Default Zephyr serial | ++--------------------+----------+--------------------+-------------+------------------------+ +| CN21 USB Port | CPU Board| SCIF3/HSCIF0 | FT2232H-56Q | Used by U-BOOT & Linux | ++--------------------+----------+--------------------+-------------+------------------------+ + +.. note:: + The Zephyr console output is assigned to SCIF0 (CN20 USB Port) with settings: + 115200 8N1 without hardware flow control by default. + +I2C +--- + +I2C is mainly used to manage and power-on some onboard chips on the S4 Spider board. + +Embedded I2C devices and I/O expanders are not yet supported. +The current I2C support therefore does not make any devices available to the user at this time. + +Programming and Debugging +************************* + +Build and flash applications as usual (see :ref:`build_an_application` and +:ref:`application_run` for more details). + +Supported Debug Probe +===================== + +| The "Olimex ARM-USB-OCD-H" probe is the only officially supported probe. +| This probe is supported by OpenOCD that is shipped with the Zephyr SDK. + +The "Olimex ARM-USB-OCD-H" probe needs to be connected with a "Coresight 20 pins" +adapter to CN1 connector on Spider board. + +Configuring a Console +===================== + +Connect a USB cable from your PC to CN20 USB port of your Spider board. + +Use the following settings with your serial terminal of choice (minicom, putty, +etc.): + +- Speed: 115200 +- Data: 8 bits +- Parity: None +- Stop bits: 1 + +Flashing +======== + +First of all, open your serial terminal. + +Applications for the ``rcar_spider_cr52`` board configuration can be built in the +usual way (see :ref:`build_an_application` for more details). + +.. zephyr-app-commands:: + :zephyr-app: samples/hello_world + :board: rcar_spider_cr52 + :goals: flash + +You should see the following message in the terminal: + +.. code-block:: console + + *** Booting Zephyr OS build v3.3.0-rc2 *** + Hello World! rcar_spider_cr52 + +Debugging +========= + +First of all, open your serial terminal. + +Here is an example for the :ref:`hello_world` application. + +.. zephyr-app-commands:: + :zephyr-app: samples/hello_world + :board: rcar_spider_cr52 + :goals: debug + +You will then get access to a GDB session for debugging. + +By continuing the app, you should see the following message in the terminal: + +.. code-block:: console + + *** Booting Zephyr OS build v3.3.0-rc2 *** + Hello World! rcar_spider_cr52 + +References +********** + +- `Renesas R-Car S4 Spider`_ +- `Renesas R-Car S4 chip`_ +- `eLinux S4 Spider`_ + +.. _Renesas R-Car S4 Spider: + https://www.renesas.com/us/en/products/automotive-products/automotive-system-chips-socs/rtp8a779f0askb0sp2s-r-car-s4-reference-boardspider + +.. _Renesas R-Car S4 chip: + https://www.renesas.com/us/en/products/automotive-products/automotive-system-chips-socs/r-car-s4-automotive-system-chip-soc-car-servercommunication-gateway + +.. _eLinux S4 Spider: + https://elinux.org/R-Car/Boards/Spider + +.. _S4 Spider CPU board IOs: + https://elinux.org/images/6/6d/Rcar_s4_spider_cpu_board.jpg + +.. _S4 Spider breakout board IOs: + https://elinux.org/images/2/29/Rcar_s4_spider_breakout_board.jpg From cb10e94799d72991ff34b64ceb3538b5a38549b2 Mon Sep 17 00:00:00 2001 From: Yong Cong Sin Date: Thu, 23 Nov 2023 16:23:58 +0800 Subject: [PATCH 0218/3723] drivers: intc: plic: minor code refactor The `riscv_plic_irq_enable` & `riscv_plic_irq_disable` are very similar, refactor them out into `plic_irq_enable_set_state`. Signed-off-by: Yong Cong Sin --- drivers/interrupt_controller/intc_plic.c | 42 ++++++++++-------------- 1 file changed, 18 insertions(+), 24 deletions(-) diff --git a/drivers/interrupt_controller/intc_plic.c b/drivers/interrupt_controller/intc_plic.c index d05d28b8834..c579d28dad2 100644 --- a/drivers/interrupt_controller/intc_plic.c +++ b/drivers/interrupt_controller/intc_plic.c @@ -142,17 +142,7 @@ static int riscv_plic_is_edge_irq(const struct device *dev, uint32_t local_irq) return sys_read32(trig_addr) & BIT(local_irq); } -/** - * @brief Enable a riscv PLIC-specific interrupt line - * - * This routine enables a RISCV PLIC-specific interrupt line. - * riscv_plic_irq_enable is called by SOC_FAMILY_RISCV_PRIVILEGED - * arch_irq_enable function to enable external interrupts for - * IRQS level == 2, whenever CONFIG_RISCV_HAS_PLIC variable is set. - * - * @param irq IRQ number to enable - */ -void riscv_plic_irq_enable(uint32_t irq) +static void plic_irq_enable_set_state(uint32_t irq, bool enable) { const struct device *dev = get_plic_dev_from_irq(irq); const struct plic_config *config = dev->config; @@ -163,11 +153,26 @@ void riscv_plic_irq_enable(uint32_t irq) key = irq_lock(); en_value = sys_read32(en_addr); - WRITE_BIT(en_value, local_irq & PLIC_REG_MASK, true); + WRITE_BIT(en_value, local_irq & PLIC_REG_MASK, enable); sys_write32(en_value, en_addr); irq_unlock(key); } +/** + * @brief Enable a riscv PLIC-specific interrupt line + * + * This routine enables a RISCV PLIC-specific interrupt line. + * riscv_plic_irq_enable is called by SOC_FAMILY_RISCV_PRIVILEGED + * arch_irq_enable function to enable external interrupts for + * IRQS level == 2, whenever CONFIG_RISCV_HAS_PLIC variable is set. + * + * @param irq IRQ number to enable + */ +void riscv_plic_irq_enable(uint32_t irq) +{ + plic_irq_enable_set_state(irq, true); +} + /** * @brief Disable a riscv PLIC-specific interrupt line * @@ -180,18 +185,7 @@ void riscv_plic_irq_enable(uint32_t irq) */ void riscv_plic_irq_disable(uint32_t irq) { - const struct device *dev = get_plic_dev_from_irq(irq); - const struct plic_config *config = dev->config; - const uint32_t local_irq = irq_from_level_2(irq); - mem_addr_t en_addr = config->irq_en + local_irq_to_reg_offset(local_irq); - uint32_t en_value; - uint32_t key; - - key = irq_lock(); - en_value = sys_read32(en_addr); - WRITE_BIT(en_value, local_irq & PLIC_REG_MASK, false); - sys_write32(en_value, en_addr); - irq_unlock(key); + plic_irq_enable_set_state(irq, false); } /** From 13e5c6359b126edca81857ea654ec8be2ee14462 Mon Sep 17 00:00:00 2001 From: Dawid Niedzwiecki Date: Fri, 24 Nov 2023 10:24:31 +0100 Subject: [PATCH 0219/3723] maintainers: correct user name Update user name from semihalf-niedzwiecki-dawid to niedzwiecki-dawid. Signed-off-by: Dawid Niedzwiecki --- MAINTAINERS.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/MAINTAINERS.yml b/MAINTAINERS.yml index 8a514d236c2..7309472c274 100644 --- a/MAINTAINERS.yml +++ b/MAINTAINERS.yml @@ -1602,7 +1602,7 @@ Release Notes: EC Host Commands: status: maintained maintainers: - - semihalf-niedzwiecki-dawid + - niedzwiecki-dawid files: - subsys/mgmt/ec_host_cmd/ - include/zephyr/mgmt/ec_host_cmd/ From 8b9537662547730e5b6e878c4f157786e1541adb Mon Sep 17 00:00:00 2001 From: Jordan Yates Date: Thu, 23 Nov 2023 18:16:17 +1000 Subject: [PATCH 0220/3723] bluetooth: hci: increase SPI driver stack size Increase the SPI RX driver stack size by 128 bytes. Overflows have previously been observed on real hardware at the default stack size of 512. Signed-off-by: Jordan Yates --- drivers/bluetooth/hci/Kconfig | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/bluetooth/hci/Kconfig b/drivers/bluetooth/hci/Kconfig index 0f792b58b08..60326ec7cf8 100644 --- a/drivers/bluetooth/hci/Kconfig +++ b/drivers/bluetooth/hci/Kconfig @@ -185,7 +185,7 @@ config BT_DRV_TX_STACK_SIZE config BT_DRV_RX_STACK_SIZE int - default 512 if BT_SPI + default 640 if BT_SPI default BT_RX_STACK_SIZE if (BT_H4 || BT_HCI_RAW_H4) default BT_STM32_IPM_RX_STACK_SIZE if BT_STM32_IPM default 256 From e1cd9f335d32b3b3809f63eb7c69dd18638b1921 Mon Sep 17 00:00:00 2001 From: Jordan Yates Date: Thu, 23 Nov 2023 18:19:54 +1000 Subject: [PATCH 0221/3723] bluetooth: hci: spi: handle interrupt return code Handle the GPIO module failing to configure the interrupt line. Fixes #65583 Signed-off-by: Jordan Yates --- drivers/bluetooth/hci/spi.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/drivers/bluetooth/hci/spi.c b/drivers/bluetooth/hci/spi.c index 32b50ea191f..a61920b0745 100644 --- a/drivers/bluetooth/hci/spi.c +++ b/drivers/bluetooth/hci/spi.c @@ -493,7 +493,10 @@ static int bt_spi_open(void) } /* Enable the interrupt line */ - gpio_pin_interrupt_configure_dt(&irq_gpio, GPIO_INT_EDGE_TO_ACTIVE); + err = gpio_pin_interrupt_configure_dt(&irq_gpio, GPIO_INT_EDGE_TO_ACTIVE); + if (err) { + return err; + } /* Take BLE out of reset */ k_sleep(K_MSEC(DT_INST_PROP_OR(0, reset_assert_duration_ms, 0))); From af671a41bbab8f32d77edd68c6de92a2412c6a35 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Benjamin=20Cab=C3=A9?= Date: Thu, 23 Nov 2023 09:33:51 +0100 Subject: [PATCH 0222/3723] drivers: display: doc: Add missing Doxygen comments MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Added proper doxygen comments where they were missing. Signed-off-by: Benjamin Cabé --- include/zephyr/drivers/display.h | 25 +++++++++++++------------ 1 file changed, 13 insertions(+), 12 deletions(-) diff --git a/include/zephyr/drivers/display.h b/include/zephyr/drivers/display.h index a72534b4e50..ae879401dd5 100644 --- a/include/zephyr/drivers/display.h +++ b/include/zephyr/drivers/display.h @@ -38,12 +38,12 @@ extern "C" { * big endian. */ enum display_pixel_format { - PIXEL_FORMAT_RGB_888 = BIT(0), - PIXEL_FORMAT_MONO01 = BIT(1), /* 0=Black 1=White */ - PIXEL_FORMAT_MONO10 = BIT(2), /* 1=Black 0=White */ - PIXEL_FORMAT_ARGB_8888 = BIT(3), - PIXEL_FORMAT_RGB_565 = BIT(4), - PIXEL_FORMAT_BGR_565 = BIT(5), + PIXEL_FORMAT_RGB_888 = BIT(0), /**< 24-bit RGB */ + PIXEL_FORMAT_MONO01 = BIT(1), /**< Monochrome (0=Black 1=White) */ + PIXEL_FORMAT_MONO10 = BIT(2), /**< Monochrome (1=Black 0=White) */ + PIXEL_FORMAT_ARGB_8888 = BIT(3), /**< 32-bit ARGB */ + PIXEL_FORMAT_RGB_565 = BIT(4), /**< 16-bit RGB */ + PIXEL_FORMAT_BGR_565 = BIT(5), /**< 16-bit BGR */ }; /** @@ -61,6 +61,9 @@ enum display_pixel_format { (((fmt & PIXEL_FORMAT_RGB_565) >> 4) * 16U) + \ (((fmt & PIXEL_FORMAT_BGR_565) >> 5) * 16U)) +/** + * @brief Display screen information + */ enum display_screen_info { /** * If selected, one octet represents 8 pixels ordered vertically, @@ -87,15 +90,13 @@ enum display_screen_info { }; /** - * @enum display_orientation * @brief Enumeration with possible display orientation - * */ enum display_orientation { - DISPLAY_ORIENTATION_NORMAL, - DISPLAY_ORIENTATION_ROTATED_90, - DISPLAY_ORIENTATION_ROTATED_180, - DISPLAY_ORIENTATION_ROTATED_270, + DISPLAY_ORIENTATION_NORMAL, /**< No rotation */ + DISPLAY_ORIENTATION_ROTATED_90, /**< Rotated 90 degrees clockwise */ + DISPLAY_ORIENTATION_ROTATED_180, /**< Rotated 180 degrees clockwise */ + DISPLAY_ORIENTATION_ROTATED_270, /**< Rotated 270 degrees clockwise */ }; /** @brief Structure holding display capabilities. */ From 12cefe1027013f73ce916586524b6ebc0098e7f6 Mon Sep 17 00:00:00 2001 From: Vinayak Kariappa Chettimada Date: Mon, 20 Nov 2023 10:08:46 +0100 Subject: [PATCH 0223/3723] Bluetooth: Controller: Fix compiler warning when RL_SIZE=1 Fix compiler warning when BT_CTLR_RL_SIZE=1. Signed-off-by: Vinayak Kariappa Chettimada --- subsys/bluetooth/controller/ll_sw/ull_filter.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/subsys/bluetooth/controller/ll_sw/ull_filter.c b/subsys/bluetooth/controller/ll_sw/ull_filter.c index 341b7296515..5d6e68238ae 100644 --- a/subsys/bluetooth/controller/ll_sw/ull_filter.c +++ b/subsys/bluetooth/controller/ll_sw/ull_filter.c @@ -390,7 +390,7 @@ uint8_t ll_rl_remove(bt_addr_le_t *id_addr) /* Swap with last item */ uint8_t pi = rl[i].pirk_idx, pj = peer_irk_count - 1; - if (pj && pi != pj) { + if (pj && (pj < ARRAY_SIZE(peer_irks)) && (pi != pj)) { (void)memcpy(peer_irks[pi], peer_irks[pj], IRK_SIZE); for (k = 0U; From 0b39da6869dff49da135f8a63cda290e6830eca8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Benjamin=20Cab=C3=A9?= Date: Thu, 23 Nov 2023 14:02:19 +0100 Subject: [PATCH 0224/3723] doc: Do not fail when manually authored doc file is not tracked by git MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This fixes a bug where a newly created documentation file not yet tracked by git would cause the documentation generation to fail. Signed-off-by: Benjamin Cabé --- doc/_extensions/zephyr/gh_utils.py | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) diff --git a/doc/_extensions/zephyr/gh_utils.py b/doc/_extensions/zephyr/gh_utils.py index 6ba75ce5ab7..38c5cff316e 100644 --- a/doc/_extensions/zephyr/gh_utils.py +++ b/doc/_extensions/zephyr/gh_utils.py @@ -173,7 +173,8 @@ def git_info_filter(app: Sphinx, pagename) -> Optional[Tuple[str, str]]: Returns: Optional[Tuple[str, str]] -- Tuple with the date and SHA1 of the last commit made to the - page, or None if the page is not in the repo. + page, or None if the page is not in the repo (generated file, or manually authored file not + yet tracked by git). """ page_prefix = get_page_prefix(app, pagename) @@ -186,6 +187,15 @@ def git_info_filter(app: Sphinx, pagename) -> Optional[Tuple[str, str]]: app.env.doc2path(pagename, False), ) + # Check if the file is tracked by git + try: + subprocess.check_output( + ["git", "ls-files", "--error-unmatch", orig_path], + stderr=subprocess.STDOUT, + ) + except subprocess.CalledProcessError: + return None + try: date_and_sha1 = ( subprocess.check_output( @@ -212,7 +222,6 @@ def git_info_filter(app: Sphinx, pagename) -> Optional[Tuple[str, str]]: except subprocess.CalledProcessError: return None - def add_jinja_filter(app: Sphinx): if app.builder.format != "html": return From 20979f80a659c9734c2c13a68c4cb85a29e21f77 Mon Sep 17 00:00:00 2001 From: Marco Widmer Date: Thu, 23 Nov 2023 17:46:44 +0100 Subject: [PATCH 0225/3723] drivers: uart: esp32: use config from device tree The parity, stop bits and data bits config was hard-coded instead of taken from the device tree. Signed-off-by: Marco Widmer --- drivers/serial/uart_esp32.c | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/drivers/serial/uart_esp32.c b/drivers/serial/uart_esp32.c index 6608d91a44a..8a7a2f336af 100644 --- a/drivers/serial/uart_esp32.c +++ b/drivers/serial/uart_esp32.c @@ -999,9 +999,11 @@ static const DRAM_ATTR struct uart_driver_api uart_esp32_api = { \ static struct uart_esp32_data uart_esp32_data_##idx = { \ .uart_config = {.baudrate = DT_INST_PROP(idx, current_speed), \ - .parity = UART_CFG_PARITY_NONE, \ - .stop_bits = UART_CFG_STOP_BITS_1, \ - .data_bits = UART_CFG_DATA_BITS_8, \ + .parity = DT_INST_ENUM_IDX_OR(idx, parity, UART_CFG_PARITY_NONE), \ + .stop_bits = DT_INST_ENUM_IDX_OR(idx, stop_bits, \ + UART_CFG_STOP_BITS_1), \ + .data_bits = DT_INST_ENUM_IDX_OR(idx, data_bits, \ + UART_CFG_DATA_BITS_8), \ .flow_ctrl = MAX(COND_CODE_1(DT_INST_PROP(idx, hw_rs485_hd_mode), \ (UART_CFG_FLOW_CTRL_RS485), \ (UART_CFG_FLOW_CTRL_NONE)), \ From 1e7eb7a6da62a20cb2d8f72022523a4dc5eb6271 Mon Sep 17 00:00:00 2001 From: Christopher Friedt Date: Wed, 22 Nov 2023 23:09:57 -0500 Subject: [PATCH 0226/3723] posix: pthread: support for pthread_setcanceltype() pthread_setcanceltype() is required by the POSIX_THREADS_BASE Option Group as detailed in Section E.1 of IEEE-1003.1-2017. The POSIX_THREADS_BASE Option Group is required for PSE51, PSE52, PSE53, and PSE54 conformance, and is otherwise mandatory for any POSIX conforming system as per Section A.2.1.3 of IEEE-1003-1.2017. Signed-off-by: Christopher Friedt --- include/zephyr/posix/pthread.h | 3 +++ lib/posix/posix_internal.h | 1 + lib/posix/pthread.c | 28 ++++++++++++++++++++++++++++ 3 files changed, 32 insertions(+) diff --git a/include/zephyr/posix/pthread.h b/include/zephyr/posix/pthread.h index c7909d40ae2..a7feef8bc7e 100644 --- a/include/zephyr/posix/pthread.h +++ b/include/zephyr/posix/pthread.h @@ -33,6 +33,8 @@ extern "C" { #define PTHREAD_CANCELED ((void *)-1) #define PTHREAD_CANCEL_ENABLE 0 #define PTHREAD_CANCEL_DISABLE 1 +#define PTHREAD_CANCEL_DEFERRED 0 +#define PTHREAD_CANCEL_ASYNCHRONOUS 1 /* Passed to pthread_once */ #define PTHREAD_ONCE_INIT \ @@ -452,6 +454,7 @@ int pthread_detach(pthread_t thread); int pthread_create(pthread_t *newthread, const pthread_attr_t *attr, void *(*threadroutine)(void *), void *arg); int pthread_setcancelstate(int state, int *oldstate); +int pthread_setcanceltype(int type, int *oldtype); int pthread_attr_setschedparam(pthread_attr_t *attr, const struct sched_param *schedparam); int pthread_setschedparam(pthread_t pthread, int policy, diff --git a/lib/posix/posix_internal.h b/lib/posix/posix_internal.h index 39c64c53331..4ce000e5147 100644 --- a/lib/posix/posix_internal.h +++ b/lib/posix/posix_internal.h @@ -38,6 +38,7 @@ struct posix_thread { /* Pthread cancellation */ uint8_t cancel_state; + uint8_t cancel_type; bool cancel_pending; /* Detach state */ diff --git a/lib/posix/pthread.c b/lib/posix/pthread.c index e96cfc287e0..d00d5564c73 100644 --- a/lib/posix/pthread.c +++ b/lib/posix/pthread.c @@ -500,6 +500,34 @@ int pthread_setcancelstate(int state, int *oldstate) return 0; } +/** + * @brief Set cancelability Type. + * + * See IEEE 1003.1 + */ +int pthread_setcanceltype(int type, int *oldtype) +{ + k_spinlock_key_t key; + struct posix_thread *t; + + if (type != PTHREAD_CANCEL_DEFERRED && type != PTHREAD_CANCEL_ASYNCHRONOUS) { + LOG_ERR("Invalid pthread cancel type %d", type); + return EINVAL; + } + + t = to_posix_thread(pthread_self()); + if (t == NULL) { + return EINVAL; + } + + key = k_spin_lock(&pthread_pool_lock); + *oldtype = t->cancel_type; + t->cancel_type = type; + k_spin_unlock(&pthread_pool_lock, key); + + return 0; +} + /** * @brief Cancel execution of a thread. * From 5f64a47d524b6d1e51537c2d51aac54653cf3bdb Mon Sep 17 00:00:00 2001 From: Christopher Friedt Date: Wed, 22 Nov 2023 23:17:53 -0500 Subject: [PATCH 0227/3723] tests: posix: headers: support pthread_setcancelstate() / type() The function pthread_setcancelstate() has been supported for some time already in Zephyr. For some reason, it was not being checked in the "headers" testsuite. Additionally, check for pthread_setcanceltype() since it was added in a prior commit. Signed-off-by: Christopher Friedt --- tests/posix/headers/src/pthread_h.c | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/tests/posix/headers/src/pthread_h.c b/tests/posix/headers/src/pthread_h.c index 51452d88de5..444a487f85c 100644 --- a/tests/posix/headers/src/pthread_h.c +++ b/tests/posix/headers/src/pthread_h.c @@ -23,9 +23,10 @@ ZTEST(posix_headers, test_pthread_h) { zassert_not_equal(-1, PTHREAD_BARRIER_SERIAL_THREAD); - /* zassert_not_equal(-1, PTHREAD_CANCEL_ASYNCHRONOUS); */ /* not implemented */ + zassert_not_equal(-1, PTHREAD_CANCEL_ASYNCHRONOUS); + zassert_not_equal(-1, PTHREAD_CANCEL_DEFERRED); + zassert_not_equal(-1, PTHREAD_CANCEL_ENABLE); - /* zassert_not_equal(-1, PTHREAD_CANCEL_DEFERRED); */ /* not implemented */ zassert_not_equal(-1, PTHREAD_CANCEL_DISABLE); zassert_not_equal((void *)-42, PTHREAD_CANCELED); @@ -146,8 +147,8 @@ ZTEST(posix_headers, test_pthread_h) zassert_not_null(pthread_rwlockattr_init); /* zassert_not_null(pthread_rwlockattr_setpshared); */ /* not implemented */ zassert_not_null(pthread_self); - /* zassert_not_null(pthread_setcancelstate); */ /* not implemented */ - /* zassert_not_null(pthread_setcanceltype); */ /* not implemented */ + zassert_not_null(pthread_setcancelstate); + zassert_not_null(pthread_setcanceltype); /* zassert_not_null(pthread_setconcurrency); */ /* not implemented */ zassert_not_null(pthread_setschedparam); /* zassert_not_null(pthread_setschedprio); */ /* not implemented */ From ecd2961160644823d9924c9360030a9f712f561b Mon Sep 17 00:00:00 2001 From: Christopher Friedt Date: Wed, 22 Nov 2023 23:20:43 -0500 Subject: [PATCH 0228/3723] doc: services: portability: posix: add pthread_setcanceltype() The function pthread_setcanceltype() is supported and mandatory for conforming implementations. Mark it as supported since the preceding commit. Signed-off-by: Christopher Friedt --- doc/services/portability/posix/option_groups/index.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/doc/services/portability/posix/option_groups/index.rst b/doc/services/portability/posix/option_groups/index.rst index e151788586d..eb623f0e626 100644 --- a/doc/services/portability/posix/option_groups/index.rst +++ b/doc/services/portability/posix/option_groups/index.rst @@ -61,7 +61,7 @@ multiple processes. pthread_once(),yes pthread_self(),yes pthread_setcancelstate(),yes - pthread_setcanceltype(), + pthread_setcanceltype(),yes pthread_setspecific(),yes pthread_sigmask(), pthread_testcancel(), From 4d8442d3a5827ef928447846c7dc9b7529622371 Mon Sep 17 00:00:00 2001 From: Christopher Friedt Date: Fri, 24 Nov 2023 21:02:33 -0500 Subject: [PATCH 0229/3723] docs: posix: update the XSI_THREADS_EXT option group Previously pthread_attr_getguardsize() and pthread_attr_setguardsize() were part of the XSI_THREADS_EXT option group. That is no longer the case. In IEEE 1003.1-2017 they are part of the POSIX_THREADS_EXT option group. Signed-off-by: Christopher Friedt --- .../portability/posix/option_groups/index.rst | 18 ++++++++++++++++-- 1 file changed, 16 insertions(+), 2 deletions(-) diff --git a/doc/services/portability/posix/option_groups/index.rst b/doc/services/portability/posix/option_groups/index.rst index eb623f0e626..fe1f7aa95b6 100644 --- a/doc/services/portability/posix/option_groups/index.rst +++ b/doc/services/portability/posix/option_groups/index.rst @@ -66,6 +66,22 @@ multiple processes. pthread_sigmask(), pthread_testcancel(), +.. _posix_option_group_posix_threads_ext: + +POSIX_THREADS_EXT +================= + +This table lists service support status in Zephyr: + +.. csv-table:: POSIX_THREADS_EXT + :header: API, Supported + :widths: 50,10 + + pthread_attr_getguardsize(), + pthread_attr_setguardsize(), + pthread_mutexattr_gettype(),yes + pthread_mutexattr_settype(),yes + .. _posix_option_group_xsi_thread_ext: XSI_THREAD_EXT @@ -81,9 +97,7 @@ This table lists service support status in Zephyr: :header: API, Supported :widths: 50,10 - pthread_attr_getguardsize(), pthread_attr_getstack(),yes - pthread_attr_setguardsize(), pthread_attr_setstack(),yes pthread_getconcurrency(), pthread_setconcurrency() From 5da13ea30a6a1b1beef19466a4f2211f34b4d61c Mon Sep 17 00:00:00 2001 From: Christopher Friedt Date: Fri, 24 Nov 2023 21:15:34 -0500 Subject: [PATCH 0230/3723] docs: posix: correct spelling of XSI_THREADS_EXT The option group includes a trailing S Signed-off-by: Christopher Friedt --- doc/services/portability/posix/option_groups/index.rst | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/doc/services/portability/posix/option_groups/index.rst b/doc/services/portability/posix/option_groups/index.rst index fe1f7aa95b6..97d7ce226a8 100644 --- a/doc/services/portability/posix/option_groups/index.rst +++ b/doc/services/portability/posix/option_groups/index.rst @@ -82,10 +82,10 @@ This table lists service support status in Zephyr: pthread_mutexattr_gettype(),yes pthread_mutexattr_settype(),yes -.. _posix_option_group_xsi_thread_ext: +.. _posix_option_group_xsi_threads_ext: -XSI_THREAD_EXT -============== +XSI_THREADS_EXT +=============== The XSI_THREADS_EXT option group is required because it provides functions to control a thread's stack. This is considered useful for any @@ -93,7 +93,7 @@ real-time application. This table lists service support status in Zephyr: -.. csv-table:: XSI_THREAD_EXT +.. csv-table:: XSI_THREADS_EXT :header: API, Supported :widths: 50,10 From b58a1f15af95ce586331fad02e860f31a50d45ca Mon Sep 17 00:00:00 2001 From: Anas Nashif Date: Wed, 15 Nov 2023 13:37:48 +0100 Subject: [PATCH 0231/3723] kernel: sanitize thread options Some thread options were made architecture specific, i.e. K_ARC_DSP_IDX. We have other architectures with similar functionality and we need to be architecture agnostic at this level. Changed the option to be more generic. The option is now called K_DSP_IDX. Also remove multiple level of ifdefs and guards around those defines to allow for documentation to be published and added a note about required configs in the docstring. Signed-off-by: Anas Nashif --- include/zephyr/kernel.h | 22 +++---------------- .../arc/arc_dsp_sharing/src/test_common.h | 2 +- 2 files changed, 4 insertions(+), 20 deletions(-) diff --git a/include/zephyr/kernel.h b/include/zephyr/kernel.h index d2b912f6d46..1ea059e5df4 100644 --- a/include/zephyr/kernel.h +++ b/include/zephyr/kernel.h @@ -171,7 +171,6 @@ void k_thread_foreach_unlocked( * */ #define K_ESSENTIAL (BIT(0)) -#if defined(CONFIG_FPU_SHARING) /** * @brief FPU registers are managed by context switch * @@ -183,7 +182,6 @@ void k_thread_foreach_unlocked( */ #define K_FP_IDX 1 #define K_FP_REGS (BIT(K_FP_IDX)) -#endif /** * @brief user mode thread @@ -214,10 +212,6 @@ void k_thread_foreach_unlocked( */ #define K_CALLBACK_STATE (BIT(4)) -#ifdef CONFIG_ARC -/* ARC processor Bitmask definitions for threads user options */ - -#if defined(CONFIG_ARC_DSP_SHARING) /** * @brief DSP registers are managed by context switch * @@ -225,13 +219,11 @@ void k_thread_foreach_unlocked( * This option indicates that the thread uses the CPU's DSP registers. * This instructs the kernel to take additional steps to save and * restore the contents of these registers when scheduling the thread. - * No effect if @kconfig{CONFIG_ARC_DSP_SHARING} is not enabled. + * No effect if @kconfig{CONFIG_DSP_SHARING} is not enabled. */ #define K_DSP_IDX 6 -#define K_ARC_DSP_REGS (BIT(K_DSP_IDX)) -#endif +#define K_DSP_REGS (BIT(K_DSP_IDX)) -#if defined(CONFIG_ARC_AGU_SHARING) /** * @brief AGU registers are managed by context switch * @@ -241,14 +233,8 @@ void k_thread_foreach_unlocked( * No effect if @kconfig{CONFIG_ARC_AGU_SHARING} is not enabled. */ #define K_AGU_IDX 7 -#define K_ARC_AGU_REGS (BIT(K_AGU_IDX)) -#endif -#endif - -#ifdef CONFIG_X86 -/* x86 Bitmask definitions for threads user options */ +#define K_AGU_REGS (BIT(K_AGU_IDX)) -#if defined(CONFIG_FPU_SHARING) && defined(CONFIG_X86_SSE) /** * @brief FP and SSE registers are managed by context switch on x86 * @@ -259,8 +245,6 @@ void k_thread_foreach_unlocked( * the thread. No effect if @kconfig{CONFIG_X86_SSE} is not enabled. */ #define K_SSE_REGS (BIT(7)) -#endif -#endif /* end - thread options */ diff --git a/tests/arch/arc/arc_dsp_sharing/src/test_common.h b/tests/arch/arc/arc_dsp_sharing/src/test_common.h index f64c652b59e..a38c3a59ed8 100644 --- a/tests/arch/arc/arc_dsp_sharing/src/test_common.h +++ b/tests/arch/arc/arc_dsp_sharing/src/test_common.h @@ -14,4 +14,4 @@ #define THREAD_HIGH_PRIORITY 5 #define THREAD_LOW_PRIORITY 10 -#define THREAD_DSP_FLAGS (K_ARC_DSP_REGS | K_ARC_AGU_REGS) +#define THREAD_DSP_FLAGS (K_DSP_REGS | K_AGU_REGS) From aed0c451f8f68e1ced4fe1cdf75b281e3aa6106b Mon Sep 17 00:00:00 2001 From: Anas Nashif Date: Thu, 16 Nov 2023 09:16:42 -0500 Subject: [PATCH 0232/3723] arch: introduce DSP_SHARING and CPU_HAS_DSP configs introduce global DSP_SHARING and CPU_HAS_DSP to be used by all architectures and change existing usage in ARC to use those global configs. Signed-off-by: Anas Nashif --- arch/Kconfig | 16 ++++++++++++++++ arch/arc/core/dsp/Kconfig | 11 +++-------- arch/arc/core/dsp/dsp_offsets.c | 2 +- arch/arc/core/dsp/swap_dsp_macros.h | 4 ++-- arch/arc/core/offsets/offsets.c | 2 +- arch/arc/core/thread.c | 6 +++--- arch/arc/include/kernel_arch_data.h | 2 +- soc/arc/snps_arc_hsdk4xd/Kconfig.soc | 2 +- soc/arc/snps_nsim/Kconfig | 2 +- tests/arch/arc/arc_dsp_sharing/prj.conf | 2 +- tests/arch/arc/arc_dsp_sharing/src/main.c | 2 +- tests/arch/arc/arc_dsp_sharing/testcase.yaml | 4 ++-- 12 files changed, 33 insertions(+), 22 deletions(-) diff --git a/arch/Kconfig b/arch/Kconfig index cc9925e7774..2884540ef37 100644 --- a/arch/Kconfig +++ b/arch/Kconfig @@ -656,6 +656,11 @@ config CPU_HAS_FPU This option is enabled when the CPU has hardware floating point unit. +config CPU_HAS_DSP + bool + help + This option is enabled when the CPU has hardware DSP unit. + config CPU_HAS_FPU_DOUBLE_PRECISION bool select CPU_HAS_FPU @@ -820,6 +825,17 @@ config CODE_DATA_RELOCATION the target regions should be specified in CMakeLists.txt using zephyr_code_relocate(). +menu "DSP Options" + +config DSP_SHARING + bool "DSP register sharing" + depends on CPU_HAS_DSP + help + This option enables preservation of the hardware DSP registers + across context switches to allow multiple threads to perform concurrent + DSP operations. +endmenu + menu "Floating Point Options" config FPU diff --git a/arch/arc/core/dsp/Kconfig b/arch/arc/core/dsp/Kconfig index 396f9c6840e..48a910198ec 100644 --- a/arch/arc/core/dsp/Kconfig +++ b/arch/arc/core/dsp/Kconfig @@ -3,13 +3,8 @@ # Copyright (c) 2022 Synopsys # SPDX-License-Identifier: Apache-2.0 -config ARC_HAS_DSP - bool - help - This option is enabled when the ARC CPU has hardware DSP unit. - menu "ARC DSP Options" -depends on ARC_HAS_DSP +depends on CPU_HAS_DSP config ARC_DSP bool "digital signal processing (DSP)" @@ -22,7 +17,7 @@ config ARC_DSP_TURNED_OFF help This option disables DSP block via resetting DSP_CRTL register. -config ARC_DSP_SHARING +config DSP_SHARING bool "DSP register sharing" depends on ARC_DSP && MULTITHREADING select ARC_HAS_ACCL_REGS @@ -49,7 +44,7 @@ config ARC_XY_ENABLE config ARC_AGU_SHARING bool "ARC address generation unit register sharing" depends on ARC_XY_ENABLE && MULTITHREADING - default y if ARC_DSP_SHARING + default y if DSP_SHARING help This option enables preservation of the hardware AGU registers across context switches to allow multiple threads to perform concurrent diff --git a/arch/arc/core/dsp/dsp_offsets.c b/arch/arc/core/dsp/dsp_offsets.c index bc606c9c26e..77db2d82c1f 100644 --- a/arch/arc/core/dsp/dsp_offsets.c +++ b/arch/arc/core/dsp/dsp_offsets.c @@ -9,7 +9,7 @@ * @brief ARCv2 DSP and AGU structure member offset definition file * */ -#ifdef CONFIG_ARC_DSP_SHARING +#ifdef CONFIG_DSP_SHARING GEN_OFFSET_SYM(_callee_saved_stack_t, dsp_ctrl); GEN_OFFSET_SYM(_callee_saved_stack_t, acc0_glo); GEN_OFFSET_SYM(_callee_saved_stack_t, acc0_ghi); diff --git a/arch/arc/core/dsp/swap_dsp_macros.h b/arch/arc/core/dsp/swap_dsp_macros.h index 0d322fa28fc..07615286683 100644 --- a/arch/arc/core/dsp/swap_dsp_macros.h +++ b/arch/arc/core/dsp/swap_dsp_macros.h @@ -10,7 +10,7 @@ * */ .macro _save_dsp_regs -#ifdef CONFIG_ARC_DSP_SHARING +#ifdef CONFIG_DSP_SHARING ld_s r13, [r2, ___thread_base_t_user_options_OFFSET] bbit0 r13, K_DSP_IDX, dsp_skip_save lr r13, [_ARC_V2_DSP_CTRL] @@ -136,7 +136,7 @@ agu_skip_save : .endm .macro _load_dsp_regs -#ifdef CONFIG_ARC_DSP_SHARING +#ifdef CONFIG_DSP_SHARING ld_s r13, [r2, ___thread_base_t_user_options_OFFSET] bbit0 r13, K_DSP_IDX, dsp_skip_load ld_s r13, [sp, ___callee_saved_stack_t_dsp_ctrl_OFFSET] diff --git a/arch/arc/core/offsets/offsets.c b/arch/arc/core/offsets/offsets.c index 450a6d23047..855270fa3ab 100644 --- a/arch/arc/core/offsets/offsets.c +++ b/arch/arc/core/offsets/offsets.c @@ -26,7 +26,7 @@ #include #include #include -#ifdef CONFIG_ARC_DSP_SHARING +#ifdef CONFIG_DSP_SHARING #include "../dsp/dsp_offsets.c" #endif diff --git a/arch/arc/core/thread.c b/arch/arc/core/thread.c index eeb12d45f6a..56340120143 100644 --- a/arch/arc/core/thread.c +++ b/arch/arc/core/thread.c @@ -19,7 +19,7 @@ #include #endif -#if defined(CONFIG_ARC_DSP) && defined(CONFIG_ARC_DSP_SHARING) +#if defined(CONFIG_ARC_DSP) && defined(CONFIG_DSP_SHARING) #include static struct k_spinlock lock; #endif @@ -297,7 +297,7 @@ FUNC_NORETURN void z_arc_switch_to_main_no_multithreading(k_thread_entry_t main_ } #endif /* !CONFIG_MULTITHREADING */ -#if defined(CONFIG_ARC_DSP) && defined(CONFIG_ARC_DSP_SHARING) +#if defined(CONFIG_ARC_DSP) && defined(CONFIG_DSP_SHARING) void arc_dsp_disable(struct k_thread *thread, unsigned int options) { /* Ensure a preemptive context switch does not occur */ @@ -319,4 +319,4 @@ void arc_dsp_enable(struct k_thread *thread, unsigned int options) k_spin_unlock(&lock, key); } -#endif /* CONFIG_ARC_DSP && CONFIG_ARC_DSP_SHARING */ +#endif /* CONFIG_ARC_DSP && CONFIG_DSP_SHARING */ diff --git a/arch/arc/include/kernel_arch_data.h b/arch/arc/include/kernel_arch_data.h index 14f7869763f..efe2bd7d1c6 100644 --- a/arch/arc/include/kernel_arch_data.h +++ b/arch/arc/include/kernel_arch_data.h @@ -160,7 +160,7 @@ struct _callee_saved_stack { #endif #endif -#ifdef CONFIG_ARC_DSP_SHARING +#ifdef CONFIG_DSP_SHARING #ifdef CONFIG_ARC_DSP_BFLY_SHARING uintptr_t dsp_fft_ctrl; uintptr_t dsp_bfly0; diff --git a/soc/arc/snps_arc_hsdk4xd/Kconfig.soc b/soc/arc/snps_arc_hsdk4xd/Kconfig.soc index be4331ad48b..6354c659d30 100644 --- a/soc/arc/snps_arc_hsdk4xd/Kconfig.soc +++ b/soc/arc/snps_arc_hsdk4xd/Kconfig.soc @@ -5,4 +5,4 @@ config SOC_ARC_HSDK4XD bool "Synopsys ARC HSDK4XD SoC" select ARC select CPU_HAS_FPU - select ARC_HAS_DSP + select CPU_HAS_DSP diff --git a/soc/arc/snps_nsim/Kconfig b/soc/arc/snps_nsim/Kconfig index 62b74e8a743..cdf2ec69cae 100644 --- a/soc/arc/snps_nsim/Kconfig +++ b/soc/arc/snps_nsim/Kconfig @@ -18,7 +18,7 @@ config SOC_NSIM_EM7D_V22 config SOC_NSIM_EM11D bool "Synopsys ARC EM11D in nSIM" select CPU_HAS_MPU - select ARC_HAS_DSP + select CPU_HAS_DSP config SOC_NSIM_SEM bool "Synopsys ARC SEM in nSIM" diff --git a/tests/arch/arc/arc_dsp_sharing/prj.conf b/tests/arch/arc/arc_dsp_sharing/prj.conf index f3be5294428..0215be6e34d 100644 --- a/tests/arch/arc/arc_dsp_sharing/prj.conf +++ b/tests/arch/arc/arc_dsp_sharing/prj.conf @@ -1,5 +1,5 @@ CONFIG_ZTEST=y CONFIG_ARC_DSP=y -CONFIG_ARC_DSP_SHARING=y +CONFIG_DSP_SHARING=y CONFIG_MAIN_STACK_SIZE=1024 CONFIG_ARC_DSP_BFLY_SHARING=y diff --git a/tests/arch/arc/arc_dsp_sharing/src/main.c b/tests/arch/arc/arc_dsp_sharing/src/main.c index 9367cc54875..641e6c01b74 100644 --- a/tests/arch/arc/arc_dsp_sharing/src/main.c +++ b/tests/arch/arc/arc_dsp_sharing/src/main.c @@ -11,7 +11,7 @@ #error Rebuild with the ARC_DSP config option enabled #endif -#ifndef CONFIG_ARC_DSP_SHARING +#ifndef CONFIG_DSP_SHARING #error Rebuild with the ARC_DSP_SHARING config option enabled #endif diff --git a/tests/arch/arc/arc_dsp_sharing/testcase.yaml b/tests/arch/arc/arc_dsp_sharing/testcase.yaml index 21cb221e059..c2149b0570e 100644 --- a/tests/arch/arc/arc_dsp_sharing/testcase.yaml +++ b/tests/arch/arc/arc_dsp_sharing/testcase.yaml @@ -1,8 +1,8 @@ tests: arch.arc.dsp_sharing.test_load_store: - filter: CONFIG_ISA_ARCV2 and CONFIG_ARC_HAS_DSP + filter: CONFIG_ISA_ARCV2 and CONFIG_CPU_HAS_DSP platform_allow: nsim_em11d arch.arc.dsp_sharing.test_calculation: - filter: CONFIG_ISA_ARCV2 and CONFIG_ARC_HAS_DSP + filter: CONFIG_ISA_ARCV2 and CONFIG_CPU_HAS_DSP toolchain_allow: arcmwdt platform_allow: nsim_em11d From 9f1b1bbba436e29af026bbf99ee8db26dcaab342 Mon Sep 17 00:00:00 2001 From: TOKITA Hiroshi Date: Wed, 22 Nov 2023 07:34:27 +0900 Subject: [PATCH 0233/3723] boards: arm: rpi_pico: add pyocd runner configuration Adding configuration for support pyocd. Signed-off-by: TOKITA Hiroshi --- boards/arm/rpi_pico/board.cmake | 2 ++ 1 file changed, 2 insertions(+) diff --git a/boards/arm/rpi_pico/board.cmake b/boards/arm/rpi_pico/board.cmake index 07a128fad7b..e9cd4edc18f 100644 --- a/boards/arm/rpi_pico/board.cmake +++ b/boards/arm/rpi_pico/board.cmake @@ -27,8 +27,10 @@ board_runner_args(openocd --cmd-pre-init "set_adapter_speed_if_not_set 2000") board_runner_args(jlink "--device=RP2040_M0_0") board_runner_args(uf2 "--board-id=RPI-RP2") +board_runner_args(pyocd "--target=rp2040") include(${ZEPHYR_BASE}/boards/common/openocd.board.cmake) include(${ZEPHYR_BASE}/boards/common/jlink.board.cmake) include(${ZEPHYR_BASE}/boards/common/uf2.board.cmake) include(${ZEPHYR_BASE}/boards/common/blackmagicprobe.board.cmake) +include(${ZEPHYR_BASE}/boards/common/pyocd.board.cmake) From 1b364c1422010dd450146510237d11779395b85c Mon Sep 17 00:00:00 2001 From: Jamie McCrae Date: Wed, 22 Nov 2023 12:21:30 +0000 Subject: [PATCH 0234/3723] drivers: console: uart_mcumgr: Skip reading FIFO during setup Drops calling the UART FIFO read function during the setup function (when not in async mode) which could cause issues on some devices since this function is not called in an ISR. Signed-off-by: Jamie McCrae --- drivers/console/uart_mcumgr.c | 7 ------- 1 file changed, 7 deletions(-) diff --git a/drivers/console/uart_mcumgr.c b/drivers/console/uart_mcumgr.c index 30b0c7be718..2b068e6810c 100644 --- a/drivers/console/uart_mcumgr.c +++ b/drivers/console/uart_mcumgr.c @@ -228,16 +228,9 @@ static void uart_mcumgr_setup(const struct device *uart) #else static void uart_mcumgr_setup(const struct device *uart) { - uint8_t c; - uart_irq_rx_disable(uart); uart_irq_tx_disable(uart); - /* Drain the fifo */ - while (uart_fifo_read(uart, &c, 1)) { - continue; - } - uart_irq_callback_set(uart, uart_mcumgr_isr); uart_irq_rx_enable(uart); From 5ae648d4173354191142898da2493cc23dfad38a Mon Sep 17 00:00:00 2001 From: Joseph Yates Date: Fri, 14 Jul 2023 08:36:41 +0100 Subject: [PATCH 0235/3723] boards: shields: Adding support for the waveshare pico ups-b shield Adding support for the Waveshare pico ups-b shield with documentation Signed-off-by: Joseph Yates --- boards/arm/rpi_pico/rpi_pico-common.dtsi | 9 ++ boards/arm/rpi_pico/rpi_pico-pinctrl.dtsi | 8 + boards/shields/waveshare_ups/Kconfig.shield | 5 + .../waveshare_ups/boards/rpi_pico.overlay | 18 +++ boards/shields/waveshare_ups/doc/index.rst | 141 ++++++++++++++++++ .../doc/waveshare_pico_ups_b.jpg | Bin 0 -> 39292 bytes .../waveshare_pico_ups_b.overlay | 19 +++ 7 files changed, 200 insertions(+) create mode 100644 boards/shields/waveshare_ups/Kconfig.shield create mode 100644 boards/shields/waveshare_ups/boards/rpi_pico.overlay create mode 100644 boards/shields/waveshare_ups/doc/index.rst create mode 100644 boards/shields/waveshare_ups/doc/waveshare_pico_ups_b.jpg create mode 100644 boards/shields/waveshare_ups/waveshare_pico_ups_b.overlay diff --git a/boards/arm/rpi_pico/rpi_pico-common.dtsi b/boards/arm/rpi_pico/rpi_pico-common.dtsi index 54f12e53843..680d2032449 100644 --- a/boards/arm/rpi_pico/rpi_pico-common.dtsi +++ b/boards/arm/rpi_pico/rpi_pico-common.dtsi @@ -112,6 +112,13 @@ pinctrl-names = "default"; }; +&i2c1 { + pinctrl-0 = <&i2c1_default>; + pinctrl-names = "default"; + status = "disabled"; + clock-frequency = ; +}; + &spi0 { clock-frequency = ; status = "okay"; @@ -149,3 +156,5 @@ zephyr_udc0: &usbd { }; pico_spi: &spi0 {}; +pico_i2c0: &i2c0 {}; +pico_i2c1: &i2c1 {}; diff --git a/boards/arm/rpi_pico/rpi_pico-pinctrl.dtsi b/boards/arm/rpi_pico/rpi_pico-pinctrl.dtsi index 93790191e6e..747b0d04e40 100644 --- a/boards/arm/rpi_pico/rpi_pico-pinctrl.dtsi +++ b/boards/arm/rpi_pico/rpi_pico-pinctrl.dtsi @@ -24,6 +24,14 @@ }; }; + i2c1_default: i2c1_default { + group1 { + pinmux = , ; + input-enable; + input-schmitt-enable; + }; + }; + spi0_default: spi0_default { group1 { pinmux = , , ; diff --git a/boards/shields/waveshare_ups/Kconfig.shield b/boards/shields/waveshare_ups/Kconfig.shield new file mode 100644 index 00000000000..38da89750c4 --- /dev/null +++ b/boards/shields/waveshare_ups/Kconfig.shield @@ -0,0 +1,5 @@ +# Copyright (c) 2023 Joseph Yates +# SPDX-License-Identifier: Apache-2.0 + +config SHIELD_WAVESHARE_PICO_UPS_B + def_bool $(shields_list_contains,waveshare_pico_ups_b) diff --git a/boards/shields/waveshare_ups/boards/rpi_pico.overlay b/boards/shields/waveshare_ups/boards/rpi_pico.overlay new file mode 100644 index 00000000000..e8fe6525af1 --- /dev/null +++ b/boards/shields/waveshare_ups/boards/rpi_pico.overlay @@ -0,0 +1,18 @@ +/* + * Copyright (c) 2023 Joseph Yates + * + * SPDX-License-Identifier: Apache-2.0 + */ + + +&pinctrl { + i2c1_default: i2c1_default { + group1 { + bias-pull-up; + }; + }; +}; + +&pico_i2c1 { + status = "okay"; +}; diff --git a/boards/shields/waveshare_ups/doc/index.rst b/boards/shields/waveshare_ups/doc/index.rst new file mode 100644 index 00000000000..4fc35403b46 --- /dev/null +++ b/boards/shields/waveshare_ups/doc/index.rst @@ -0,0 +1,141 @@ +.. _waveshare_pico_ups_b_shield: + +Waveshare Pico UPS-B shield +########################### + +Overview +******** + +The Waveshare Pico UPS-B shield is an uninterruptible Power supply (UPS) +module designed for the Raspberry Pi Pico which uses the Texas Instruments' INA219 +current/power Monitor. It communicates with the Raspberry Pi Pico over I2C + +.. figure:: waveshare_pico_ups_b.jpg + :align: center + :alt: Waveshare Pico UPS-B shield + + Waveshare Pico UPS-B shield + +Hardware +-------- + +- INA219 + + - Senses bus voltages from 0 to 26 V + - Reports current, voltage and power + - 16 Programmable Addresses + - SOT23-8 and SOIC-8 packages + - Calibration registers + +- ETA6003 + + - Switching charger with power path management + - Up to 95% DC-DC efficiency + - 0mΩ power path MOSFET + - Up to 2.5A max charging current + +- Connectivity + + - Raspberry Pi Pico compatible (I2C) + - 2 pin jst header for Li-po battery + +-------+-----------------------+---------------------------+ +| Name | Function | Usage | ++=======+=======================+===========================+ +| GP0 | None | | ++-------+-----------------------+---------------------------+ +| GP1 | None | | ++-------+-----------------------+---------------------------+ +| GP2 | None | | ++-------+-----------------------+---------------------------+ +| GP3 | None | | ++-------+-----------------------+---------------------------+ +| GP4 | None | | ++-------+-----------------------+---------------------------+ +| GP5 | None | | ++-------+-----------------------+---------------------------+ +| GP6 | I2C1_SDA ACTIVE_LOW | INA219 | ++-------+-----------------------+---------------------------+ +| GP7 | I2C1_SCL ACTIVE_LOW | INA219 | ++-------+-----------------------+---------------------------+ +| GP8 | None | | ++-------+-----------------------+---------------------------+ +| GP9 | None | | ++-------+-----------------------+---------------------------+ +| GP10 | None | | ++-------+-----------------------+---------------------------+ +| GP11 | None | | ++-------+-----------------------+---------------------------+ +| GP12 | None | | ++-------+-----------------------+---------------------------+ +| GP13 | None | | ++-------+-----------------------+---------------------------+ +| GP14 | None | | ++-------+-----------------------+---------------------------+ +| GP15 | None | | ++-------+-----------------------+---------------------------+ +| GP16 | None | | ++-------+-----------------------+---------------------------+ +| GP17 | None | | ++-------+-----------------------+---------------------------+ +| GP18 | None | | ++-------+-----------------------+---------------------------+ +| GP19 | None | | ++-------+-----------------------+---------------------------+ +| GP20 | None | | ++-------+-----------------------+---------------------------+ +| GP21 | None | | ++-------+-----------------------+---------------------------+ +| GP22 | None | | ++-------+-----------------------+---------------------------+ +| GP23 | None | | ++-------+-----------------------+---------------------------+ +| GP24 | None | | ++-------+-----------------------+---------------------------+ +| GP25 | None | | ++-------+-----------------------+---------------------------+ +| GP26 | None | | ++-------+-----------------------+---------------------------+ +| GP27 | None | | ++-------+-----------------------+---------------------------+ +| GP28 | None | | ++-------+-----------------------+---------------------------+ + + +- Power Supply + + - 3.3V ~ 5V + +- Components + + - Power switch + - Power LED + - Charging LED + +For more information about the Waveshare Pico UPS-B: + +- `Waveshare Pico UPS website`_ +- `INA219 data sheet`_ +- `ETA6003 data sheet`_ + +Programming +*********** + +Set ``-DSHIELD=waveshare_pico_ups_b`` when you invoke ``west build`` or ``cmake`` in your Zephyr application. For +example: + +.. zephyr-app-commands:: + :zephyr-app: samples/sensor/ina219 + :tool: all + :board: rpi_pico + :shield: waveshare_pico_ups_b + :goals: build flash + +.. _Waveshare Pico UPS website: + https://www.waveshare.com/wiki/Pico-UPS-B + +.. _INA219 data sheet: + https://www.ti.com/lit/ds/symlink/ina219.pdf + +.. _ETA6003 data sheet: + https://www.waveshare.com/w/upload/3/3f/ETA6003.pdf diff --git a/boards/shields/waveshare_ups/doc/waveshare_pico_ups_b.jpg b/boards/shields/waveshare_ups/doc/waveshare_pico_ups_b.jpg new file mode 100644 index 0000000000000000000000000000000000000000..53f1191db5a035b7a22bee4285f4375acd7f3c07 GIT binary patch literal 39292 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 F|Jg=(l5hY3 literal 0 HcmV?d00001 diff --git a/boards/shields/waveshare_ups/waveshare_pico_ups_b.overlay b/boards/shields/waveshare_ups/waveshare_pico_ups_b.overlay new file mode 100644 index 00000000000..381bce67c74 --- /dev/null +++ b/boards/shields/waveshare_ups/waveshare_pico_ups_b.overlay @@ -0,0 +1,19 @@ +/* + * Copyright (c) 2023 Joseph Yates + * + * SPDX-License-Identifier: Apache-2.0 + */ + +&pico_i2c1 { + waveshare_pico_ups: ina219@43 { + status = "okay"; + compatible = "ti,ina219"; + reg = <0x43>; + brng = <1>; + pg = <3>; + sadc = <12>; + badc = <12>; + shunt-milliohm = <100>; + lsb-microamp = <20>; + }; +}; From ec7bdde22b6af9d57018e142fd68b12212270d15 Mon Sep 17 00:00:00 2001 From: Vinayak Kariappa Chettimada Date: Tue, 31 Oct 2023 20:14:09 +0100 Subject: [PATCH 0236/3723] Bluetooth: Controller: Improve preempt timeout req/ack counting Improve preempt timeout request and acknowledge counting. Signed-off-by: Vinayak Kariappa Chettimada --- subsys/bluetooth/controller/ll_sw/nordic/lll/lll.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/subsys/bluetooth/controller/ll_sw/nordic/lll/lll.c b/subsys/bluetooth/controller/ll_sw/nordic/lll/lll.c index db8f25a374c..6d51b63ecbb 100644 --- a/subsys/bluetooth/controller/ll_sw/nordic/lll/lll.c +++ b/subsys/bluetooth/controller/ll_sw/nordic/lll/lll.c @@ -832,7 +832,7 @@ static void ticker_stop_op_cb(uint32_t status, void *param) ARG_UNUSED(status); LL_ASSERT(preempt_stop_req != preempt_stop_ack); - preempt_stop_ack++; + preempt_stop_ack = preempt_stop_req; preempt_req = preempt_ack; } @@ -852,7 +852,7 @@ static void ticker_start_op_cb(uint32_t status, void *param) * start operation has been handled. */ LL_ASSERT(preempt_start_req != preempt_start_ack); - preempt_start_ack++; + preempt_start_ack = preempt_start_req; } static uint32_t preempt_ticker_start(struct lll_event *first, @@ -974,7 +974,7 @@ static void preempt_ticker_cb(uint32_t ticks_at_expire, uint32_t ticks_drift, uint32_t ret; LL_ASSERT(preempt_ack != preempt_req); - preempt_ack++; + preempt_ack = preempt_req; mfy.param = param; ret = mayfly_enqueue(TICKER_USER_ID_ULL_HIGH, TICKER_USER_ID_LLL, From b444dc442b8c7ead81bf27a07168047c70602f15 Mon Sep 17 00:00:00 2001 From: Vinayak Kariappa Chettimada Date: Tue, 31 Oct 2023 20:33:31 +0100 Subject: [PATCH 0237/3723] Bluetooth: Controller: Minor re-arrange advanced feature Kconfig Minor refactor of Kconfig order such that the advanced feature Kconfig is just above the enabling/visible of the advanced features menu. Signed-off-by: Vinayak Kariappa Chettimada --- subsys/bluetooth/controller/Kconfig.ll_sw_split | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/subsys/bluetooth/controller/Kconfig.ll_sw_split b/subsys/bluetooth/controller/Kconfig.ll_sw_split index 2b9e33ef82d..7cef480413d 100644 --- a/subsys/bluetooth/controller/Kconfig.ll_sw_split +++ b/subsys/bluetooth/controller/Kconfig.ll_sw_split @@ -240,11 +240,6 @@ config BT_CTLR_CONN_ISO_AVOID_SEGMENTATION interface, the config provides a way to force the Max_PDU to Max_SDU + 5 (header + offset). -config BT_CTLR_ADVANCED_FEATURES - bool "Show advanced features" - help - Makes advanced features visible to controller developers. - choice prompt "CIS Creation Policy Selection" default BT_CTLR_CONN_ISO_RELIABILITY_POLICY @@ -272,6 +267,11 @@ config BT_CTLR_TEST help Run in-system unit tests +config BT_CTLR_ADVANCED_FEATURES + bool "Show advanced features" + help + Makes advanced features visible to controller developers. + menu "Advanced features" visible if BT_CTLR_ADVANCED_FEATURES From d573951f0daf5f541703293256885fe0e93b7799 Mon Sep 17 00:00:00 2001 From: Vinayak Kariappa Chettimada Date: Tue, 31 Oct 2023 20:17:11 +0100 Subject: [PATCH 0238/3723] Bluetooth: Controller: Revert back early abort of previous prepare Revert back to implementation that did early abort of previous prepare when a short prepare is enqueued. Adds back implementation deleted in commit 7f388bb70a3d ("Bluetooth: Controller: Fix short prepare when many enqueued in pipeline"). Signed-off-by: Vinayak Kariappa Chettimada --- .../bluetooth/controller/Kconfig.ll_sw_split | 7 +++++++ .../controller/ll_sw/nordic/lll/lll.c | 20 +++++++++++++++++++ 2 files changed, 27 insertions(+) diff --git a/subsys/bluetooth/controller/Kconfig.ll_sw_split b/subsys/bluetooth/controller/Kconfig.ll_sw_split index 7cef480413d..0e2685f29ca 100644 --- a/subsys/bluetooth/controller/Kconfig.ll_sw_split +++ b/subsys/bluetooth/controller/Kconfig.ll_sw_split @@ -961,6 +961,13 @@ config BT_CTLR_SCAN_UNRESERVED Scanner will not use time space reservation for scan window when in continuous scan mode. +config BT_CTLR_EARLY_ABORT_PREVIOUS_PREPARE + bool "Early abort previous prepare" + default y + help + Early abort previous prepare present before a short prepare is + enqueued in the prepare pipeline. + config BT_MAYFLY_YIELD_AFTER_CALL bool "Yield from mayfly thread after first call" default y diff --git a/subsys/bluetooth/controller/ll_sw/nordic/lll/lll.c b/subsys/bluetooth/controller/ll_sw/nordic/lll/lll.c index 6d51b63ecbb..473282eb618 100644 --- a/subsys/bluetooth/controller/ll_sw/nordic/lll/lll.c +++ b/subsys/bluetooth/controller/ll_sw/nordic/lll/lll.c @@ -906,6 +906,26 @@ static uint32_t preempt_ticker_start(struct lll_event *first, LL_ASSERT((ret == TICKER_STATUS_SUCCESS) || (ret == TICKER_STATUS_BUSY)); +#if defined(CONFIG_BT_CTLR_EARLY_ABORT_PREVIOUS_PREPARE) + /* FIXME: Prepare pipeline is not a ordered list implementation, + * and for short prepare being enqueued, ideally the + * pipeline has to be implemented as ordered list. + * Until then a workaround to abort a prepare present + * before the short prepare being enqueued is implemented + * below. + * A proper solution will be to re-design the pipeline + * as a ordered list, instead of the current FIFO. + */ + /* Set early as we get called again through the call to + * abort_cb(). + */ + ticks_at_preempt = ticks_at_preempt_new; + + /* Abort previous prepare that set the preempt timeout */ + prev->is_aborted = 1U; + prev->abort_cb(&prev->prepare_param, prev->prepare_param.param); +#endif /* CONFIG_BT_CTLR_EARLY_ABORT_PREVIOUS_PREPARE */ + /* Schedule short preempt timeout */ first = next; } else { From d36e085eccedcf6a053016badeb267ea0f5c3cd2 Mon Sep 17 00:00:00 2001 From: Vinayak Kariappa Chettimada Date: Tue, 31 Oct 2023 20:17:34 +0100 Subject: [PATCH 0239/3723] Bluetooth: Controller: Fix scan aux context leak Fix scan aux context leak under BT_CTLR_SCAN_UNRESERVED. Signed-off-by: Vinayak Kariappa Chettimada --- subsys/bluetooth/controller/ll_sw/nordic/lll/lll_scan_aux.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/subsys/bluetooth/controller/ll_sw/nordic/lll/lll_scan_aux.c b/subsys/bluetooth/controller/ll_sw/nordic/lll/lll_scan_aux.c index c8188d87cb6..57132835fba 100644 --- a/subsys/bluetooth/controller/ll_sw/nordic/lll/lll_scan_aux.c +++ b/subsys/bluetooth/controller/ll_sw/nordic/lll/lll_scan_aux.c @@ -632,6 +632,7 @@ static int is_abort_cb(void *next, void *curr, lll_prepare_cb_t *resume_cb) static void abort_cb(struct lll_prepare_param *prepare_param, void *param) { + struct event_done_extra *e; int err; /* NOTE: This is not a prepare being cancelled */ @@ -651,6 +652,9 @@ static void abort_cb(struct lll_prepare_param *prepare_param, void *param) err = lll_hfclock_off(); LL_ASSERT(err >= 0); + e = ull_done_extra_type_set(EVENT_DONE_EXTRA_TYPE_SCAN_AUX); + LL_ASSERT(e); + lll_done(param); } From 64cc0764ee2247c014a851453d0be9c8153cdf46 Mon Sep 17 00:00:00 2001 From: Grant Ramsay Date: Sun, 12 Nov 2023 10:29:36 +1300 Subject: [PATCH 0240/3723] drivers: virtualization: Map ivshmem-v2 sections individually Recent changes to the arm64 MMU code mean that you can no longer map R/O memory as R/W. Mapping R/W memory now causes a cache invalidation instruction (DC IVAC) that requires write permissions or else a fault is generated. Modify ivshmem-v2 to map each R/O and R/W section individually Signed-off-by: Grant Ramsay --- drivers/virtualization/Kconfig | 6 ++ drivers/virtualization/virt_ivshmem.c | 59 ++++++++++++++----- drivers/virtualization/virt_ivshmem.h | 5 +- .../zephyr/drivers/virtualization/ivshmem.h | 6 ++ 4 files changed, 59 insertions(+), 17 deletions(-) diff --git a/drivers/virtualization/Kconfig b/drivers/virtualization/Kconfig index 4f32552f09a..f439f5ba97d 100644 --- a/drivers/virtualization/Kconfig +++ b/drivers/virtualization/Kconfig @@ -66,4 +66,10 @@ config IVSHMEM_V2 Enable ivshmem-v2 support. ivshmem-v2 is primarily used for IPC in the Jailhouse hypervisor. +config IVSHMEM_V2_MAX_PEERS + int "Maximum number of ivshmem-v2 peers" + depends on IVSHMEM_V2 + default 2 + range 2 65536 + endif # VIRTUALIZATION diff --git a/drivers/virtualization/virt_ivshmem.c b/drivers/virtualization/virt_ivshmem.c index 6e8258f1dad..f620ab473f9 100644 --- a/drivers/virtualization/virt_ivshmem.c +++ b/drivers/virtualization/virt_ivshmem.c @@ -198,7 +198,7 @@ static bool ivshmem_configure(const struct device *dev) (volatile struct ivshmem_v2_reg *)DEVICE_MMIO_GET(dev); data->max_peers = regs->max_peers; - if (!IN_RANGE(data->max_peers, 2, 0x10000)) { + if (!IN_RANGE(data->max_peers, 2, CONFIG_IVSHMEM_V2_MAX_PEERS)) { LOG_ERR("Invalid max peers %u", data->max_peers); return false; } @@ -211,26 +211,49 @@ static bool ivshmem_configure(const struct device *dev) shmem_phys_addr = pcie_conf_read_u64(data->pcie->bdf, cap_pos); } + /* State table R/O */ cap_pos = vendor_cap + IVSHMEM_CFG_STATE_TAB_SZ / 4; size_t state_table_size = pcie_conf_read(data->pcie->bdf, cap_pos); - LOG_INF("State table size 0x%zX", state_table_size); if (state_table_size < sizeof(uint32_t) * data->max_peers) { LOG_ERR("Invalid state table size %zu", state_table_size); return false; } + z_phys_map((uint8_t **)&data->state_table_shmem, + shmem_phys_addr, state_table_size, + K_MEM_CACHE_WB | K_MEM_PERM_USER); + /* R/W section (optional) */ cap_pos = vendor_cap + IVSHMEM_CFG_RW_SECTION_SZ / 4; data->rw_section_size = pcie_conf_read_u64(data->pcie->bdf, cap_pos); - data->rw_section_offset = state_table_size; + size_t rw_section_offset = state_table_size; LOG_INF("RW section size 0x%zX", data->rw_section_size); + if (data->rw_section_size > 0) { + z_phys_map((uint8_t **)&data->rw_section_shmem, + shmem_phys_addr + rw_section_offset, data->rw_section_size, + K_MEM_CACHE_WB | K_MEM_PERM_RW | K_MEM_PERM_USER); + } + /* Output sections */ cap_pos = vendor_cap + IVSHMEM_CFG_OUTPUT_SECTION_SZ / 4; data->output_section_size = pcie_conf_read_u64(data->pcie->bdf, cap_pos); - data->output_section_offset = data->rw_section_offset + data->rw_section_size; + size_t output_section_offset = rw_section_offset + data->rw_section_size; LOG_INF("Output section size 0x%zX", data->output_section_size); + for (uint32_t i = 0; i < data->max_peers; i++) { + uintptr_t phys_addr = shmem_phys_addr + + output_section_offset + + (data->output_section_size * i); + uint32_t flags = K_MEM_CACHE_WB | K_MEM_PERM_USER; + + /* Only your own output section is R/W */ + if (i == regs->id) { + flags |= K_MEM_PERM_RW; + } + z_phys_map((uint8_t **)&data->output_section_shmem[i], + phys_addr, data->output_section_size, flags); + } - data->size = data->output_section_offset + + data->size = output_section_offset + data->output_section_size * data->max_peers; /* Ensure one-shot ISR mode is disabled */ @@ -249,11 +272,11 @@ static bool ivshmem_configure(const struct device *dev) } data->size = mbar_shmem.size; - } - z_phys_map((uint8_t **)&data->shmem, - shmem_phys_addr, data->size, - K_MEM_CACHE_WB | K_MEM_PERM_RW | K_MEM_PERM_USER); + z_phys_map((uint8_t **)&data->shmem, + shmem_phys_addr, data->size, + K_MEM_CACHE_WB | K_MEM_PERM_RW | K_MEM_PERM_USER); + } if (msi_x_bar_present) { if (!ivshmem_configure_msi_x_interrupts(dev)) { @@ -284,6 +307,13 @@ static size_t ivshmem_api_get_mem(const struct device *dev, { struct ivshmem *data = dev->data; +#ifdef CONFIG_IVSHMEM_V2 + if (data->ivshmem_v2) { + *memmap = 0; + return 0; + } +#endif + *memmap = data->shmem; return data->size; @@ -389,11 +419,11 @@ static size_t ivshmem_api_get_rw_mem_section(const struct device *dev, struct ivshmem *data = dev->data; if (!data->ivshmem_v2) { - memmap = NULL; + *memmap = 0; return 0; } - *memmap = data->shmem + data->rw_section_offset; + *memmap = data->rw_section_shmem; return data->rw_section_size; } @@ -405,12 +435,11 @@ static size_t ivshmem_api_get_output_mem_section(const struct device *dev, struct ivshmem *data = dev->data; if (!data->ivshmem_v2 || peer_id >= data->max_peers) { - memmap = NULL; + *memmap = 0; return 0; } - *memmap = data->shmem + data->output_section_offset + - data->output_section_size * peer_id; + *memmap = data->output_section_shmem[peer_id]; return data->output_section_size; } @@ -425,7 +454,7 @@ static uint32_t ivshmem_api_get_state(const struct device *dev, } const volatile uint32_t *state_table = - (const volatile uint32_t *)data->shmem; + (const volatile uint32_t *)data->state_table_shmem; return state_table[peer_id]; } diff --git a/drivers/virtualization/virt_ivshmem.h b/drivers/virtualization/virt_ivshmem.h index e6439408787..8a7ae11c364 100644 --- a/drivers/virtualization/virt_ivshmem.h +++ b/drivers/virtualization/virt_ivshmem.h @@ -57,9 +57,10 @@ struct ivshmem { bool ivshmem_v2; uint32_t max_peers; size_t rw_section_size; - size_t rw_section_offset; size_t output_section_size; - size_t output_section_offset; + uintptr_t state_table_shmem; + uintptr_t rw_section_shmem; + uintptr_t output_section_shmem[CONFIG_IVSHMEM_V2_MAX_PEERS]; #endif }; diff --git a/include/zephyr/drivers/virtualization/ivshmem.h b/include/zephyr/drivers/virtualization/ivshmem.h index 0507eb6ae1a..20bd1e42336 100644 --- a/include/zephyr/drivers/virtualization/ivshmem.h +++ b/include/zephyr/drivers/virtualization/ivshmem.h @@ -84,6 +84,12 @@ __subsystem struct ivshmem_driver_api { /** * @brief Get the inter-VM shared memory * + * Note: This API is not supported for ivshmem-v2, as + * the R/W and R/O areas may not be mapped contiguously. + * For ivshmem-v2, use the ivshmem_get_rw_mem_section, + * ivshmem_get_output_mem_section and ivshmem_get_state + * APIs to access the shared memory. + * * @param dev Pointer to the device structure for the driver instance * @param memmap A pointer to fill in with the memory address * From 82644a31c28991e4d586563fe43bd0d6a6c09df2 Mon Sep 17 00:00:00 2001 From: Grant Ramsay Date: Sun, 12 Nov 2023 10:39:00 +1300 Subject: [PATCH 0241/3723] drivers: ethernet: Fix eth_ivshmem shared memory mapping This driver assumed the ivshmem-v2 output sections would be mapped contiguously, which is no longer true. Modify eth_ivshmem to treat each output section independently Signed-off-by: Grant Ramsay --- drivers/ethernet/eth_ivshmem.c | 11 ++++++----- drivers/ethernet/eth_ivshmem_priv.h | 4 ++-- drivers/ethernet/eth_ivshmem_queue.c | 14 ++++---------- .../ethernet/eth_ivshmem_queue/src/main.c | 19 ++++++++++++------- 4 files changed, 24 insertions(+), 24 deletions(-) diff --git a/drivers/ethernet/eth_ivshmem.c b/drivers/ethernet/eth_ivshmem.c index eb869261cbc..0d2c104359a 100644 --- a/drivers/ethernet/eth_ivshmem.c +++ b/drivers/ethernet/eth_ivshmem.c @@ -297,14 +297,15 @@ int eth_ivshmem_initialize(const struct device *dev) } dev_data->peer_id = (id == 0) ? 1 : 0; - bool tx_buffer_first = id == 0; - uintptr_t output_section_addr; + uintptr_t output_sections[2]; size_t output_section_size = ivshmem_get_output_mem_section( - cfg_data->ivshmem, 0, &output_section_addr); + cfg_data->ivshmem, 0, &output_sections[0]); + ivshmem_get_output_mem_section( + cfg_data->ivshmem, 1, &output_sections[1]); res = eth_ivshmem_queue_init( - &dev_data->ivshmem_queue, output_section_addr, - output_section_size, tx_buffer_first); + &dev_data->ivshmem_queue, output_sections[id], + output_sections[dev_data->peer_id], output_section_size); if (res != 0) { LOG_ERR("Failed to init ivshmem queue"); return res; diff --git a/drivers/ethernet/eth_ivshmem_priv.h b/drivers/ethernet/eth_ivshmem_priv.h index b5769a31f03..f537d3be295 100644 --- a/drivers/ethernet/eth_ivshmem_priv.h +++ b/drivers/ethernet/eth_ivshmem_priv.h @@ -40,8 +40,8 @@ struct eth_ivshmem_queue { }; int eth_ivshmem_queue_init( - struct eth_ivshmem_queue *q, uintptr_t shmem, - size_t shmem_section_size, bool tx_buffer_first); + struct eth_ivshmem_queue *q, uintptr_t tx_shmem, + uintptr_t rx_shmem, size_t shmem_section_size); void eth_ivshmem_queue_reset(struct eth_ivshmem_queue *q); int eth_ivshmem_queue_tx_get_buff(struct eth_ivshmem_queue *q, void **data, size_t len); int eth_ivshmem_queue_tx_commit_buff(struct eth_ivshmem_queue *q); diff --git a/drivers/ethernet/eth_ivshmem_queue.c b/drivers/ethernet/eth_ivshmem_queue.c index d5b5b29a735..3301dd72a35 100644 --- a/drivers/ethernet/eth_ivshmem_queue.c +++ b/drivers/ethernet/eth_ivshmem_queue.c @@ -28,8 +28,8 @@ static int tx_clean_used(struct eth_ivshmem_queue *q); static int get_rx_avail_desc_idx(struct eth_ivshmem_queue *q, uint16_t *avail_desc_idx); int eth_ivshmem_queue_init( - struct eth_ivshmem_queue *q, uintptr_t shmem, - size_t shmem_section_size, bool tx_buffer_first) + struct eth_ivshmem_queue *q, uintptr_t tx_shmem, + uintptr_t rx_shmem, size_t shmem_section_size) { memset(q, 0, sizeof(*q)); @@ -44,14 +44,8 @@ int eth_ivshmem_queue_init( q->desc_max_len = vring_desc_len; q->vring_data_max_len = shmem_section_size - vring_header_size; q->vring_header_size = vring_header_size; - - if (tx_buffer_first) { - q->tx.shmem = (void *)shmem; - q->rx.shmem = (void *)(shmem + shmem_section_size); - } else { - q->rx.shmem = (void *)shmem; - q->tx.shmem = (void *)(shmem + shmem_section_size); - } + q->tx.shmem = (void *)tx_shmem; + q->rx.shmem = (void *)rx_shmem; /* Init vrings */ vring_init(&q->tx.vring, vring_desc_len, q->tx.shmem, ETH_IVSHMEM_VRING_ALIGNMENT); diff --git a/tests/drivers/ethernet/eth_ivshmem_queue/src/main.c b/tests/drivers/ethernet/eth_ivshmem_queue/src/main.c index 53c65e39e16..2c268a274d1 100644 --- a/tests/drivers/ethernet/eth_ivshmem_queue/src/main.c +++ b/tests/drivers/ethernet/eth_ivshmem_queue/src/main.c @@ -16,16 +16,21 @@ #define VRING_DATA_MAX_LEN 2304 static struct eth_ivshmem_queue q1, q2; -static uint8_t shmem_buff[SHMEM_SECTION_SIZE * 2]; +static uint8_t shmem_buff[2][SHMEM_SECTION_SIZE] __aligned(KB(4)); static const void *rx_message; static size_t rx_len; static void test_init_queues(void) { - int res = eth_ivshmem_queue_init(&q1, (uintptr_t)shmem_buff, SHMEM_SECTION_SIZE, true); + int res; + res = eth_ivshmem_queue_init( + &q1, (uintptr_t)shmem_buff[0], + (uintptr_t)shmem_buff[1], SHMEM_SECTION_SIZE); zassert_ok(res); - res = eth_ivshmem_queue_init(&q2, (uintptr_t)shmem_buff, SHMEM_SECTION_SIZE, false); + res = eth_ivshmem_queue_init( + &q2, (uintptr_t)shmem_buff[1], + (uintptr_t)shmem_buff[0], SHMEM_SECTION_SIZE); zassert_ok(res); } @@ -55,10 +60,10 @@ ZTEST(eth_ivshmem_queue_tests, test_init) zassert_equal(q1.desc_max_len, VRING_DESC_LEN); zassert_equal(q1.vring_header_size, VRING_HEADER_SIZE); zassert_equal(q1.vring_data_max_len, VRING_DATA_MAX_LEN); - zassert_equal_ptr(q1.tx.shmem, shmem_buff); - zassert_equal_ptr(q1.rx.shmem, shmem_buff + SHMEM_SECTION_SIZE); - zassert_equal_ptr(q2.tx.shmem, shmem_buff + SHMEM_SECTION_SIZE); - zassert_equal_ptr(q2.rx.shmem, shmem_buff); + zassert_equal_ptr(q1.tx.shmem, shmem_buff[0]); + zassert_equal_ptr(q1.rx.shmem, shmem_buff[1]); + zassert_equal_ptr(q2.tx.shmem, shmem_buff[1]); + zassert_equal_ptr(q2.rx.shmem, shmem_buff[0]); } ZTEST(eth_ivshmem_queue_tests, test_simple_send_receive) From a1614e8c955ebbcdbece8ad8feb4260edc47fb7c Mon Sep 17 00:00:00 2001 From: Minho Jin Date: Tue, 14 Nov 2023 16:50:38 +0900 Subject: [PATCH 0242/3723] driver: counter: rpi_pico_timer: fix counter cancel alarm setting function checks channel callback and it returns -EBUSY if callback is registered. but alarm cancel function doesn't clear callback function. this prevents from alarm setting after alarm cancel Signed-off-by: Minho Jin --- drivers/counter/counter_rpi_pico_timer.c | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/drivers/counter/counter_rpi_pico_timer.c b/drivers/counter/counter_rpi_pico_timer.c index 3e1a1dcbb0b..40a5aadd491 100644 --- a/drivers/counter/counter_rpi_pico_timer.c +++ b/drivers/counter/counter_rpi_pico_timer.c @@ -106,6 +106,11 @@ static int counter_rpi_pico_timer_set_alarm(const struct device *dev, uint8_t id static int counter_rpi_pico_timer_cancel_alarm(const struct device *dev, uint8_t id) { + struct counter_rpi_pico_timer_data *data = dev->data; + struct counter_rpi_pico_timer_ch_data *chdata = &data->ch_data[id]; + + chdata->callback = NULL; + chdata->user_data = NULL; hardware_alarm_cancel(id); return 0; From 637b4b62ee233cb4e3733b0bf65e4b415e41daa1 Mon Sep 17 00:00:00 2001 From: Juha Ylinen Date: Mon, 20 Nov 2023 13:40:55 +0200 Subject: [PATCH 0243/3723] samples: lwm2m: Add support for Connection Manager Using Connection Manager, it's easy to run lwm2m sample on devices supporting different connectivity technologies (for example, Wi-Fi and LTE). Signed-off-by: Juha Ylinen --- samples/net/lwm2m_client/src/lwm2m-client.c | 78 +++++++++++++++++++++ 1 file changed, 78 insertions(+) diff --git a/samples/net/lwm2m_client/src/lwm2m-client.c b/samples/net/lwm2m_client/src/lwm2m-client.c index 748f654d9ee..a120506639d 100644 --- a/samples/net/lwm2m_client/src/lwm2m-client.c +++ b/samples/net/lwm2m_client/src/lwm2m-client.c @@ -16,6 +16,8 @@ LOG_MODULE_REGISTER(LOG_MODULE_NAME); #include #include #include +#include +#include #include "modules.h" #define APP_BANNER "Run LWM2M client" @@ -29,6 +31,10 @@ LOG_MODULE_REGISTER(LOG_MODULE_NAME); #define CLIENT_FIRMWARE_VER "1.0" #define CLIENT_HW_VER "1.0.1" +/* Macros used to subscribe to specific Zephyr NET management events. */ +#define L4_EVENT_MASK (NET_EVENT_L4_CONNECTED | NET_EVENT_L4_DISCONNECTED) +#define CONN_LAYER_EVENT_MASK (NET_EVENT_CONN_IF_FATAL_ERROR) + static uint8_t bat_idx = LWM2M_DEVICE_PWR_SRC_TYPE_BAT_INT; static int bat_mv = 3800; static int bat_ma = 125; @@ -52,6 +58,12 @@ BUILD_ASSERT(sizeof(endpoint) <= CONFIG_LWM2M_SECURITY_KEY_SIZE, static struct k_sem quit_lock; +/* Zephyr NET management event callback structures. */ +static struct net_mgmt_event_callback l4_cb; +static struct net_mgmt_event_callback conn_cb; + +static K_SEM_DEFINE(network_connected_sem, 0, 1); + static int device_reboot_cb(uint16_t obj_inst_id, uint8_t *args, uint16_t args_len) { @@ -265,6 +277,47 @@ static void observe_cb(enum lwm2m_observe_event event, } } +static void on_net_event_l4_disconnected(void) +{ + LOG_INF("Disconnected from network"); + lwm2m_engine_pause(); +} + +static void on_net_event_l4_connected(void) +{ + LOG_INF("Connected to network"); + k_sem_give(&network_connected_sem); + lwm2m_engine_resume(); +} + +static void l4_event_handler(struct net_mgmt_event_callback *cb, + uint32_t event, + struct net_if *iface) +{ + switch (event) { + case NET_EVENT_L4_CONNECTED: + LOG_INF("IP Up"); + on_net_event_l4_connected(); + break; + case NET_EVENT_L4_DISCONNECTED: + LOG_INF("IP down"); + on_net_event_l4_disconnected(); + break; + default: + break; + } +} + +static void connectivity_event_handler(struct net_mgmt_event_callback *cb, + uint32_t event, + struct net_if *iface) +{ + if (event == NET_EVENT_CONN_IF_FATAL_ERROR) { + LOG_ERR("Fatal error received from the connectivity layer"); + return; + } +} + int main(void) { uint32_t flags = IS_ENABLED(CONFIG_LWM2M_RD_CLIENT_SUPPORT_BOOTSTRAP) ? @@ -275,6 +328,31 @@ int main(void) k_sem_init(&quit_lock, 0, K_SEM_MAX_LIMIT); + if (IS_ENABLED(CONFIG_NET_CONNECTION_MANAGER)) { + /* Setup handler for Zephyr NET Connection Manager events. */ + net_mgmt_init_event_callback(&l4_cb, l4_event_handler, L4_EVENT_MASK); + net_mgmt_add_event_callback(&l4_cb); + + /* Setup handler for Zephyr NET Connection Manager Connectivity layer. */ + net_mgmt_init_event_callback(&conn_cb, connectivity_event_handler, + CONN_LAYER_EVENT_MASK); + net_mgmt_add_event_callback(&conn_cb); + + ret = net_if_up(net_if_get_default()); + + if (ret < 0 && ret != -EALREADY) { + LOG_ERR("net_if_up, error: %d", ret); + return ret; + } + + ret = conn_mgr_if_connect(net_if_get_default()); + /* Ignore errors from interfaces not requiring connectivity */ + if (ret == 0) { + LOG_INF("Connecting to network"); + k_sem_take(&network_connected_sem, K_FOREVER); + } + } + ret = lwm2m_setup(); if (ret < 0) { LOG_ERR("Cannot setup LWM2M fields (%d)", ret); From b37307927523ac4a38b4e81c50baebff37b8b5c5 Mon Sep 17 00:00:00 2001 From: Mariusz Skamra Date: Tue, 21 Nov 2023 12:45:10 +0100 Subject: [PATCH 0244/3723] Bluetooth: audio: ascs: Remove spurious error message This removes spurious error message printed when CIS has been disconnected and it was not used by any of the endpoints. This case is valid and may happen on Connection Timeout when the controller reports ACL Disconnection first. When the CIS Disconnection is reported after, the ASE is already in idle state and the referenece to CIS has been already removed (on ACL disconnection). Fixes: #64896 Signed-off-by: Mariusz Skamra --- subsys/bluetooth/audio/ascs.c | 1 - 1 file changed, 1 deletion(-) diff --git a/subsys/bluetooth/audio/ascs.c b/subsys/bluetooth/audio/ascs.c index 116071d4c0f..e30c467df49 100644 --- a/subsys/bluetooth/audio/ascs.c +++ b/subsys/bluetooth/audio/ascs.c @@ -944,7 +944,6 @@ static void ascs_iso_disconnected(struct bt_iso_chan *chan, uint8_t reason) struct bt_bap_iso *iso = CONTAINER_OF(chan, struct bt_bap_iso, chan); if (iso->rx.ep == NULL && iso->tx.ep == NULL) { - LOG_ERR("iso %p not bound with ep", chan); return; } From 65068fb4dfbc4b0d5d8f0bbfbeef299bf7a9d20e Mon Sep 17 00:00:00 2001 From: Tim Woolliscroft Date: Fri, 24 Nov 2023 10:10:03 +0000 Subject: [PATCH 0245/3723] drivers: i2c: stm32: Fix routing of secondary target address Fixes the routing of the events associated with a secondary i2c target address being routed to the primary config. The i2c_target_config/slave_cfg was being selected from the driver address match but then over written by the primary. This change fully implements the if/else of 10bit addressing and includes a assert if the slave_cfg is NULL, and explains why dual 10bit addresses on STM32 won't work. Signed-off-by: Tim Woolliscroft --- drivers/i2c/i2c_ll_stm32_v2.c | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) diff --git a/drivers/i2c/i2c_ll_stm32_v2.c b/drivers/i2c/i2c_ll_stm32_v2.c index c75d68e4f19..8292b2f6738 100644 --- a/drivers/i2c/i2c_ll_stm32_v2.c +++ b/drivers/i2c/i2c_ll_stm32_v2.c @@ -142,9 +142,19 @@ static void stm32_i2c_slave_event(const struct device *dev) __ASSERT_NO_MSG(0); return; } + } else { + /* On STM32 the LL_I2C_GetAddressMatchCode & (ISR register) returns + * only 7bits of address match so 10 bit dual addressing is broken. + * Revert to assuming single address match. + */ + if (data->slave_cfg != NULL) { + slave_cfg = data->slave_cfg; + } else { + __ASSERT_NO_MSG(0); + return; + } } - slave_cfg = data->slave_cfg; slave_cb = slave_cfg->callbacks; if (LL_I2C_IsActiveFlag_TXIS(i2c)) { From 06e8d01e9311ac67fa3f24084cc1d8f9d6ad80e0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Benjamin=20Cab=C3=A9?= Date: Thu, 23 Nov 2023 07:52:07 +0100 Subject: [PATCH 0246/3723] drivers: led: Fix doxygen comments for led_info struct MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Fixed improperly commented struct. Signed-off-by: Benjamin Cabé --- include/zephyr/drivers/led.h | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/include/zephyr/drivers/led.h b/include/zephyr/drivers/led.h index b9dd8cc2775..cb178a9442d 100644 --- a/include/zephyr/drivers/led.h +++ b/include/zephyr/drivers/led.h @@ -32,16 +32,15 @@ extern "C" { * @brief LED information structure * * This structure gathers useful information about LED controller. - * - * @param label LED label. - * @param num_colors Number of colors per LED. - * @param index Index of the LED on the controller. - * @param color_mapping Mapping of the LED colors. */ struct led_info { + /** LED label */ const char *label; + /** Number of colors per LED */ uint32_t index; + /** Index of the LED on the controller */ uint8_t num_colors; + /** Mapping of the LED colors */ const uint8_t *color_mapping; }; From e4993fcc5bfb8e46629414b7c6811dc3b2b199dd Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Benjamin=20Cab=C3=A9?= Date: Thu, 23 Nov 2023 08:21:32 +0100 Subject: [PATCH 0247/3723] drivers: spi: doc: Doxygen cleanup MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - Fixed a few improperly formatted struct - Marked some mask definitions as internal when macros abstracting them out already exist - Fixed a few code blocks to add proper syntax highlightingy Signed-off-by: Benjamin Cabé --- include/zephyr/drivers/spi.h | 65 +++++++++++++++++++++--------------- 1 file changed, 39 insertions(+), 26 deletions(-) diff --git a/include/zephyr/drivers/spi.h b/include/zephyr/drivers/spi.h index fa3b8834c9e..44863f49acd 100644 --- a/include/zephyr/drivers/spi.h +++ b/include/zephyr/drivers/spi.h @@ -37,9 +37,12 @@ extern "C" { * @name SPI operational mode * @{ */ -#define SPI_OP_MODE_MASTER 0U -#define SPI_OP_MODE_SLAVE BIT(0) +#define SPI_OP_MODE_MASTER 0U /**< Master mode. */ +#define SPI_OP_MODE_SLAVE BIT(0) /**< Slave mode. */ +/** @cond INTERNAL_HIDDEN */ #define SPI_OP_MODE_MASK 0x1U +/** @endcond */ +/** Get SPI operational mode. */ #define SPI_OP_MODE_GET(_operation_) ((_operation_) & SPI_OP_MODE_MASK) /** @} */ @@ -70,8 +73,10 @@ extern "C" { * support this, and can be used for testing purposes only. */ #define SPI_MODE_LOOP BIT(3) - +/** @cond INTERNAL_HIDDEN */ #define SPI_MODE_MASK (0xEU) +/** @endcond */ +/** Get SPI polarity and phase mode bits. */ #define SPI_MODE_GET(_mode_) \ ((_mode_) & SPI_MODE_MASK) @@ -81,19 +86,22 @@ extern "C" { * @name SPI Transfer modes (host controller dependent) * @{ */ -#define SPI_TRANSFER_MSB (0U) -#define SPI_TRANSFER_LSB BIT(4) +#define SPI_TRANSFER_MSB (0U) /**< Most significant bit first. */ +#define SPI_TRANSFER_LSB BIT(4) /**< Least significant bit first. */ /** @} */ /** * @name SPI word size * @{ */ +/** @cond INTERNAL_HIDDEN */ #define SPI_WORD_SIZE_SHIFT (5U) #define SPI_WORD_SIZE_MASK (0x3FU << SPI_WORD_SIZE_SHIFT) +/** @endcond */ +/** Get SPI word size. */ #define SPI_WORD_SIZE_GET(_operation_) \ (((_operation_) & SPI_WORD_SIZE_MASK) >> SPI_WORD_SIZE_SHIFT) - +/** Set SPI word size. */ #define SPI_WORD_SET(_word_size_) \ ((_word_size_) << SPI_WORD_SIZE_SHIFT) /** @} */ @@ -102,16 +110,16 @@ extern "C" { * @name Specific SPI devices control bits * @{ */ -/* Requests - if possible - to keep CS asserted after the transaction */ +/** Requests - if possible - to keep CS asserted after the transaction */ #define SPI_HOLD_ON_CS BIT(12) -/* Keep the device locked after the transaction for the current config. +/** Keep the device locked after the transaction for the current config. * Use this with extreme caution (see spi_release() below) as it will * prevent other callers to access the SPI device until spi_release() is * properly called. */ #define SPI_LOCK_ON BIT(13) -/* Active high logic on CS - Usually, and by default, CS logic is active +/** Active high logic on CS. Usually, and by default, CS logic is active * low. However, some devices may require the reverse logic: active high. * This bit will request the controller to use that logic. Note that not * all controllers are able to handle that natively. In this case deferring @@ -130,12 +138,13 @@ extern "C" { * Without @kconfig{CONFIG_SPI_EXTENDED_MODES} being enabled, single is the * only supported one. */ -#define SPI_LINES_SINGLE (0U << 16) -#define SPI_LINES_DUAL (1U << 16) -#define SPI_LINES_QUAD (2U << 16) -#define SPI_LINES_OCTAL (3U << 16) +#define SPI_LINES_SINGLE (0U << 16) /**< Single line */ +#define SPI_LINES_DUAL (1U << 16) /**< Dual lines */ +#define SPI_LINES_QUAD (2U << 16) /**< Quad lines */ +#define SPI_LINES_OCTAL (3U << 16) /**< Octal lines */ + +#define SPI_LINES_MASK (0x3U << 16) /**< Mask for MISO lines in spi_operation_t */ -#define SPI_LINES_MASK (0x3U << 16) /** @} */ /** @@ -225,22 +234,28 @@ struct spi_cs_control { * * Example devicetree fragment: * - * spi@... { + * @code{.devicetree} + * spi@abcd0001 { * cs-gpios = <&gpio0 1 GPIO_ACTIVE_LOW>; * spidev: spi-device@0 { ... }; * }; + * @endcode * * Example usage: * + * @code{.c} * struct spi_cs_control ctrl = * SPI_CS_CONTROL_INIT(DT_NODELABEL(spidev), 2); + * @endcode * * This example is equivalent to: * + * @code{.c} * struct spi_cs_control ctrl = { * .gpio = SPI_CS_GPIOS_DT_SPEC_GET(DT_NODELABEL(spidev)), * .delay = 2, * }; + * @endcode * * @param node_id Devicetree node identifier for a device on a SPI bus * @param delay_ The @p delay field to set in the @p spi_cs_control @@ -356,12 +371,11 @@ struct spi_config { /** * @brief Complete SPI DT information - * - * @param bus is the SPI bus - * @param config is the slave specific configuration */ struct spi_dt_spec { + /** SPI bus */ const struct device *bus; + /** Slave specific configuration */ struct spi_config config; }; @@ -405,25 +419,24 @@ struct spi_dt_spec { /** * @brief SPI buffer structure - * - * @param buf is a valid pointer on a data buffer, or NULL otherwise. - * @param len is the length of the buffer or, if buf is NULL, will be the - * length which as to be sent as dummy bytes (as TX buffer) or - * the length of bytes that should be skipped (as RX buffer). */ struct spi_buf { + /** Valid pointer to a data buffer, or NULL otherwise */ void *buf; + /** Length of the buffer @a buf. + * If @a buf is NULL, length which as to be sent as dummy bytes (as TX + * buffer) or the length of bytes that should be skipped (as RX buffer). + */ size_t len; }; /** * @brief SPI buffer array structure - * - * @param buffers is a valid pointer on an array of spi_buf, or NULL. - * @param count is the length of the array pointed by buffers. */ struct spi_buf_set { + /** Pointer to an array of spi_buf, or NULL */ const struct spi_buf *buffers; + /** Length of the array pointed by @a buffers */ size_t count; }; From cd5f88e8d30007bafad70ac99ce3fb666d39cf89 Mon Sep 17 00:00:00 2001 From: Alberto Escolar Piedras Date: Thu, 23 Nov 2023 09:13:18 +0100 Subject: [PATCH 0248/3723] boards native_posix/sim: Define native_posix DTS from native_sim's Get the native_posix DTS from native_sim instead of the oposite. As native_sim is now the default test platform. Note this commit is practically just swapping files. There is no changes to the DTS content, beyond changing the board name. Signed-off-by: Alberto Escolar Piedras --- boards/posix/native_posix/native_posix.dts | 216 +-------------------- boards/posix/native_sim/native_sim.dts | 216 ++++++++++++++++++++- 2 files changed, 216 insertions(+), 216 deletions(-) diff --git a/boards/posix/native_posix/native_posix.dts b/boards/posix/native_posix/native_posix.dts index 75af8bdb1fd..74a3c30049b 100644 --- a/boards/posix/native_posix/native_posix.dts +++ b/boards/posix/native_posix/native_posix.dts @@ -1,219 +1,7 @@ /* - * Copyright (c) 2019 Jan Van Winkel (jan.van_winkel@dxplore.eu) + * Copyright (c) 2023 Nordic Semiconductor ASA * * SPDX-License-Identifier: Apache-2.0 */ -/dts-v1/; -#include -#include -#include -#include - -/ { - model = "Native POSIX Board"; - compatible = "zephyr,posix"; - - chosen { - zephyr,console = &uart0; - zephyr,shell-uart = &uart0; - zephyr,uart-mcumgr = &uart0; - zephyr,flash = &flash0; - zephyr,entropy = &rng; - zephyr,flash-controller = &flashcontroller0; - zephyr,display = &sdl_dc; - zephyr,canbus = &can_loopback0; - }; - - aliases { - eeprom-0 = &eeprom0; - i2c-0 = &i2c0; - spi-0 = &spi0; - led0 = &led0; - rtc = &rtc; - }; - - leds { - compatible = "gpio-leds"; - led0: led_0 { - gpios = <&gpio0 0 GPIO_ACTIVE_HIGH>; - label = "Green LED"; - }; - }; - - lvgl_pointer { - compatible = "zephyr,lvgl-pointer-input"; - input = <&input_sdl_touch>; - }; - - cpus { - #address-cells = <1>; - #size-cells = <0>; - - cpu0: cpu@0 { - compatible = "zephyr,native-posix-cpu"; - reg = <0>; - }; - }; - - flashcontroller0: flash-controller@0 { - compatible = "zephyr,sim-flash"; - reg = <0x00000000 DT_SIZE_K(2048)>; - - #address-cells = <1>; - #size-cells = <1>; - erase-value = <0xff>; - - flash0: flash@0 { - status = "okay"; - compatible = "soc-nv-flash"; - erase-block-size = <4096>; - write-block-size = <1>; - reg = <0x00000000 DT_SIZE_K(2048)>; - - partitions { - compatible = "fixed-partitions"; - #address-cells = <1>; - #size-cells = <1>; - - boot_partition: partition@0 { - label = "mcuboot"; - reg = <0x00000000 0x0000C000>; - }; - slot0_partition: partition@c000 { - label = "image-0"; - reg = <0x0000C000 0x00069000>; - }; - slot1_partition: partition@75000 { - label = "image-1"; - reg = <0x00075000 0x00069000>; - }; - scratch_partition: partition@de000 { - label = "image-scratch"; - reg = <0x000de000 0x0001e000>; - }; - storage_partition: partition@fc000 { - label = "storage"; - reg = <0x000fc000 0x00004000>; - }; - }; - }; - }; - - eeprom0: eeprom { - status = "okay"; - compatible = "zephyr,sim-eeprom"; - size = ; - }; - - i2c0: i2c@100 { - status = "okay"; - compatible = "zephyr,i2c-emul-controller"; - clock-frequency = ; - #address-cells = <1>; - #size-cells = <0>; - reg = <0x100 4>; - }; - - spi0: spi@200 { - status = "okay"; - compatible = "zephyr,spi-emul-controller"; - clock-frequency = <50000000>; - #address-cells = <1>; - #size-cells = <0>; - reg = <0x200 4>; - }; - - espi0: espi@300 { - status = "okay"; - compatible = "zephyr,espi-emul-controller"; - reg = <0x300 4>; - #address-cells = <1>; - #size-cells = <0>; - }; - - uart0: uart { - status = "okay"; - compatible = "zephyr,native-posix-uart"; - /* Dummy current-speed entry to comply with serial - * DTS binding - */ - current-speed = <0>; - }; - - uart1: uart_1 { - status = "okay"; - compatible = "zephyr,native-posix-uart"; - /* Dummy current-speed entry to comply with serial - * DTS binding - */ - current-speed = <0>; - }; - - rng: rng { - status = "okay"; - compatible = "zephyr,native-posix-rng"; - }; - - counter0: counter { - status = "okay"; - compatible = "zephyr,native-posix-counter"; - }; - - gpio0: gpio@800 { - status = "okay"; - compatible = "zephyr,gpio-emul"; - reg = <0x800 0x4>; - rising-edge; - falling-edge; - high-level; - low-level; - gpio-controller; - #gpio-cells = <2>; - }; - - zephyr_udc0: udc0 { - compatible = "zephyr,native-posix-udc"; - }; - - sdl_dc: sdl_dc { - compatible = "zephyr,sdl-dc"; - height = <240>; - width = <320>; - }; - - input_sdl_touch: input-sdl-touch { - compatible = "zephyr,input-sdl-touch"; - }; - - can_loopback0: can_loopback0 { - status = "okay"; - compatible = "zephyr,can-loopback"; - sample-point = <875>; - bus-speed = <125000>; - }; - - can0: can { - status = "disabled"; - compatible = "zephyr,native-posix-linux-can"; - /* adjust zcan0 to desired host interface or create an alternative - * name, e.g.: sudo ip link property add dev vcan0 altname zcan0 - */ - host-interface = "zcan0"; - sample-point = <875>; - bus-speed = <125000>; - }; - - rtc: rtc { - status = "okay"; - compatible = "zephyr,rtc-emul"; - alarms-count = <2>; - }; - - adc0: adc { - compatible = "zephyr,adc-emul"; - nchannels = <2>; - #io-channel-cells = <1>; - status = "okay"; - }; -}; +#include "../native_sim/native_sim.dts" diff --git a/boards/posix/native_sim/native_sim.dts b/boards/posix/native_sim/native_sim.dts index b27a9bd540d..73c703ece0b 100644 --- a/boards/posix/native_sim/native_sim.dts +++ b/boards/posix/native_sim/native_sim.dts @@ -1,7 +1,219 @@ /* - * Copyright (c) 2023 Nordic Semiconductor ASA + * Copyright (c) 2019 Jan Van Winkel (jan.van_winkel@dxplore.eu) * * SPDX-License-Identifier: Apache-2.0 */ -#include "../native_posix/native_posix.dts" +/dts-v1/; +#include +#include +#include +#include + +/ { + model = "Native Sim Board"; + compatible = "zephyr,posix"; + + chosen { + zephyr,console = &uart0; + zephyr,shell-uart = &uart0; + zephyr,uart-mcumgr = &uart0; + zephyr,flash = &flash0; + zephyr,entropy = &rng; + zephyr,flash-controller = &flashcontroller0; + zephyr,display = &sdl_dc; + zephyr,canbus = &can_loopback0; + }; + + aliases { + eeprom-0 = &eeprom0; + i2c-0 = &i2c0; + spi-0 = &spi0; + led0 = &led0; + rtc = &rtc; + }; + + leds { + compatible = "gpio-leds"; + led0: led_0 { + gpios = <&gpio0 0 GPIO_ACTIVE_HIGH>; + label = "Green LED"; + }; + }; + + lvgl_pointer { + compatible = "zephyr,lvgl-pointer-input"; + input = <&input_sdl_touch>; + }; + + cpus { + #address-cells = <1>; + #size-cells = <0>; + + cpu0: cpu@0 { + compatible = "zephyr,native-posix-cpu"; + reg = <0>; + }; + }; + + flashcontroller0: flash-controller@0 { + compatible = "zephyr,sim-flash"; + reg = <0x00000000 DT_SIZE_K(2048)>; + + #address-cells = <1>; + #size-cells = <1>; + erase-value = <0xff>; + + flash0: flash@0 { + status = "okay"; + compatible = "soc-nv-flash"; + erase-block-size = <4096>; + write-block-size = <1>; + reg = <0x00000000 DT_SIZE_K(2048)>; + + partitions { + compatible = "fixed-partitions"; + #address-cells = <1>; + #size-cells = <1>; + + boot_partition: partition@0 { + label = "mcuboot"; + reg = <0x00000000 0x0000C000>; + }; + slot0_partition: partition@c000 { + label = "image-0"; + reg = <0x0000C000 0x00069000>; + }; + slot1_partition: partition@75000 { + label = "image-1"; + reg = <0x00075000 0x00069000>; + }; + scratch_partition: partition@de000 { + label = "image-scratch"; + reg = <0x000de000 0x0001e000>; + }; + storage_partition: partition@fc000 { + label = "storage"; + reg = <0x000fc000 0x00004000>; + }; + }; + }; + }; + + eeprom0: eeprom { + status = "okay"; + compatible = "zephyr,sim-eeprom"; + size = ; + }; + + i2c0: i2c@100 { + status = "okay"; + compatible = "zephyr,i2c-emul-controller"; + clock-frequency = ; + #address-cells = <1>; + #size-cells = <0>; + reg = <0x100 4>; + }; + + spi0: spi@200 { + status = "okay"; + compatible = "zephyr,spi-emul-controller"; + clock-frequency = <50000000>; + #address-cells = <1>; + #size-cells = <0>; + reg = <0x200 4>; + }; + + espi0: espi@300 { + status = "okay"; + compatible = "zephyr,espi-emul-controller"; + reg = <0x300 4>; + #address-cells = <1>; + #size-cells = <0>; + }; + + uart0: uart { + status = "okay"; + compatible = "zephyr,native-posix-uart"; + /* Dummy current-speed entry to comply with serial + * DTS binding + */ + current-speed = <0>; + }; + + uart1: uart_1 { + status = "okay"; + compatible = "zephyr,native-posix-uart"; + /* Dummy current-speed entry to comply with serial + * DTS binding + */ + current-speed = <0>; + }; + + rng: rng { + status = "okay"; + compatible = "zephyr,native-posix-rng"; + }; + + counter0: counter { + status = "okay"; + compatible = "zephyr,native-posix-counter"; + }; + + gpio0: gpio@800 { + status = "okay"; + compatible = "zephyr,gpio-emul"; + reg = <0x800 0x4>; + rising-edge; + falling-edge; + high-level; + low-level; + gpio-controller; + #gpio-cells = <2>; + }; + + zephyr_udc0: udc0 { + compatible = "zephyr,native-posix-udc"; + }; + + sdl_dc: sdl_dc { + compatible = "zephyr,sdl-dc"; + height = <240>; + width = <320>; + }; + + input_sdl_touch: input-sdl-touch { + compatible = "zephyr,input-sdl-touch"; + }; + + can_loopback0: can_loopback0 { + status = "okay"; + compatible = "zephyr,can-loopback"; + sample-point = <875>; + bus-speed = <125000>; + }; + + can0: can { + status = "disabled"; + compatible = "zephyr,native-posix-linux-can"; + /* adjust zcan0 to desired host interface or create an alternative + * name, e.g.: sudo ip link property add dev vcan0 altname zcan0 + */ + host-interface = "zcan0"; + sample-point = <875>; + bus-speed = <125000>; + }; + + rtc: rtc { + status = "okay"; + compatible = "zephyr,rtc-emul"; + alarms-count = <2>; + }; + + adc0: adc { + compatible = "zephyr,adc-emul"; + nchannels = <2>; + #io-channel-cells = <1>; + status = "okay"; + }; +}; From 7ed88f169bb0ac0ec1d0e4d7af407c6fffba213d Mon Sep 17 00:00:00 2001 From: Yong Cong Sin Date: Thu, 23 Nov 2023 18:43:54 +0800 Subject: [PATCH 0249/3723] drivers: intc: stm32: fix a minor copy paste error The description of `STM32_EXTI_TRIG_FALLING` got copied into the `STM32_EXTI_TRIG_BOTH` as well, fix that. Signed-off-by: Yong Cong Sin --- include/zephyr/drivers/interrupt_controller/exti_stm32.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/include/zephyr/drivers/interrupt_controller/exti_stm32.h b/include/zephyr/drivers/interrupt_controller/exti_stm32.h index 2bd41415983..0bd808f921c 100644 --- a/include/zephyr/drivers/interrupt_controller/exti_stm32.h +++ b/include/zephyr/drivers/interrupt_controller/exti_stm32.h @@ -49,7 +49,7 @@ enum stm32_exti_trigger { STM32_EXTI_TRIG_RISING = 0x1, /* trigger on falling edge */ STM32_EXTI_TRIG_FALLING = 0x2, - /* trigger on falling edge */ + /* trigger on both rising & falling edge */ STM32_EXTI_TRIG_BOTH = 0x3, }; From bec7789862ea5449a63626de9c943678c95a13e8 Mon Sep 17 00:00:00 2001 From: Bjarki Arge Andreasen Date: Thu, 23 Nov 2023 12:18:17 +0100 Subject: [PATCH 0250/3723] tests: modem: backend: uart: Add fixture to test suite Add fixture to test suite to allow for and signal that the test must be run on real hardware. Signed-off-by: Bjarki Arge Andreasen --- .../uart/boards/b_u585i_iot02a.overlay | 35 +++------------- .../boards/nrf5340dk_nrf5340_cpuapp.overlay | 42 ++++++++----------- tests/subsys/modem/backends/uart/src/main.c | 2 +- .../subsys/modem/backends/uart/testcase.yaml | 18 ++++---- 4 files changed, 33 insertions(+), 64 deletions(-) diff --git a/tests/subsys/modem/backends/uart/boards/b_u585i_iot02a.overlay b/tests/subsys/modem/backends/uart/boards/b_u585i_iot02a.overlay index 394facef7bb..30402e6e9d2 100644 --- a/tests/subsys/modem/backends/uart/boards/b_u585i_iot02a.overlay +++ b/tests/subsys/modem/backends/uart/boards/b_u585i_iot02a.overlay @@ -1,34 +1,11 @@ +/* SPDX-License-Identifier: Apache-2.0 */ + /* - * Pins 2 and 3 must be connected to each other on the STMOD+1 connector to - * loopback RX/TX. + * The Arduino D0 and D1 must be connected to each other to loopback RX/TX. */ -/ { - aliases { - test-uart = &usart2; - }; -}; - -&gpioh { - misc_fixed_usart2 { - gpio-hog; - gpios = <13 GPIO_ACTIVE_HIGH>; - output-high; - }; -}; - -&gpdma1 { - status = "okay"; -}; - -&usart2 { - pinctrl-0 = <&usart2_tx_pa2 &usart2_rx_pa3 &usart2_rts_pa1 &usart2_cts_pa0>; - pinctrl-names = "default"; - current-speed = <115200>; - - dmas = <&gpdma1 0 27 STM32_DMA_PERIPH_TX - &gpdma1 1 26 STM32_DMA_PERIPH_RX>; +dut: &usart3 { + dmas = <&gpdma1 0 29 STM32_DMA_PERIPH_TX + &gpdma1 1 28 STM32_DMA_PERIPH_RX>; dma-names = "tx", "rx"; - - status = "okay"; }; diff --git a/tests/subsys/modem/backends/uart/boards/nrf5340dk_nrf5340_cpuapp.overlay b/tests/subsys/modem/backends/uart/boards/nrf5340dk_nrf5340_cpuapp.overlay index 2d47b0f0744..777aebd8d3b 100644 --- a/tests/subsys/modem/backends/uart/boards/nrf5340dk_nrf5340_cpuapp.overlay +++ b/tests/subsys/modem/backends/uart/boards/nrf5340dk_nrf5340_cpuapp.overlay @@ -1,37 +1,31 @@ +/* SPDX-License-Identifier: Apache-2.0 */ + /* - * Pins P1.10 and P1.11 must be connected to each other to loopback RX/TX. + * Pins P0.4 and P0.5 must be connected to each other to loopback RX/TX. */ -/ { - aliases { - test-uart = &uart1; - }; -}; - -&uart1 { - status = "okay"; - current-speed = <115200>; - pinctrl-0 = <&uart1_default>; - pinctrl-1 = <&uart1_sleep>; - hw-flow-control; - pinctrl-names = "default", "sleep"; -}; - &pinctrl { - uart1_default: uart1_default { + uart1_default_alt: uart1_default_alt { group1 { - psels = ; - }; - group2 { - psels = ; + psels = , + ; }; }; - uart1_sleep: uart1_sleep { + uart1_sleep_alt: uart1_sleep_alt { group1 { - psels = , - ; + psels = , + ; low-power-enable; }; }; }; + +dut: &uart1 { + compatible = "nordic,nrf-uarte"; + current-speed = <115200>; + status = "okay"; + pinctrl-0 = <&uart1_default_alt>; + pinctrl-1 = <&uart1_sleep_alt>; + pinctrl-names = "default", "sleep"; +}; diff --git a/tests/subsys/modem/backends/uart/src/main.c b/tests/subsys/modem/backends/uart/src/main.c index 8a6c4c2813a..dffc203bb21 100644 --- a/tests/subsys/modem/backends/uart/src/main.c +++ b/tests/subsys/modem/backends/uart/src/main.c @@ -28,7 +28,7 @@ /*************************************************************************************************/ /* Mock pipe */ /*************************************************************************************************/ -static const struct device *uart = DEVICE_DT_GET(DT_ALIAS(test_uart)); +static const struct device *uart = DEVICE_DT_GET(DT_NODELABEL(dut)); static struct modem_backend_uart uart_backend; static struct modem_pipe *pipe; K_SEM_DEFINE(receive_ready_sem, 0, 1); diff --git a/tests/subsys/modem/backends/uart/testcase.yaml b/tests/subsys/modem/backends/uart/testcase.yaml index 626ca639f75..54d8a6b9470 100644 --- a/tests/subsys/modem/backends/uart/testcase.yaml +++ b/tests/subsys/modem/backends/uart/testcase.yaml @@ -1,21 +1,19 @@ # Copyright (c) 2023 Trackunit Corporation # SPDX-License-Identifier: Apache-2.0 +common: + harness: ztest + harness_config: + fixture: gpio_loopback + platform_allow: + - b_u585i_iot02a + - nrf5340dk_nrf5340_cpuapp + tests: modem.backends.uart.async: - tags: modem_backend - harness: ztest - platform_allow: - - b_u585i_iot02a - - nrf5340dk_nrf5340_cpuapp extra_configs: - CONFIG_UART_ASYNC_API=y modem.backends.uart.isr: - tags: modem_backend - harness: ztest - platform_allow: - - b_u585i_iot02a - - nrf5340dk_nrf5340_cpuapp extra_configs: - CONFIG_UART_INTERRUPT_DRIVEN=y From 8146fe4f6603f11d3ab4022c6646b3b365a7af29 Mon Sep 17 00:00:00 2001 From: Francois Ramu Date: Thu, 23 Nov 2023 14:22:35 +0100 Subject: [PATCH 0251/3723] dts: bindings: stm32 lptimer has no divider on the clock source freq Revert "dts: bindings: LPtimer of stm32 has a x2 factor on its clock" The stm32u5 lptim clock source has no prescaler to divide the the LPTIM input clock frequency : no property required. This reverts commit 572b286010b4219c6146dc8d9cde36d1cbc50c74. Signed-off-by: Francois Ramu --- dts/bindings/timer/st,stm32-lptim.yaml | 8 -------- 1 file changed, 8 deletions(-) diff --git a/dts/bindings/timer/st,stm32-lptim.yaml b/dts/bindings/timer/st,stm32-lptim.yaml index a13deb1f794..90db9084800 100644 --- a/dts/bindings/timer/st,stm32-lptim.yaml +++ b/dts/bindings/timer/st,stm32-lptim.yaml @@ -39,11 +39,3 @@ properties: - 32 - 64 - 128 - - st,static-prescaler: - type: boolean - description: | - Clock x2 factor at the input of the LPTIM, - depending on the serie. - For example, stm32U5x have a x2-factor for LPTIM1,3,4. - To be adapted once the value is selectable. From f1af7f13eb938452a891591f1615ac047194ef91 Mon Sep 17 00:00:00 2001 From: Francois Ramu Date: Thu, 23 Nov 2023 14:26:10 +0100 Subject: [PATCH 0252/3723] drivers: timer: stm32 lptimer revert static-prescaler Revert "drivers: timer: lptim timer clock on stm32u5 has a prescaler" This reverts commit c14670abea4412fbf1e54996807b6ebb67eb98b6. Signed-off-by: Francois Ramu --- drivers/timer/stm32_lptim_timer.c | 13 ------------- 1 file changed, 13 deletions(-) diff --git a/drivers/timer/stm32_lptim_timer.c b/drivers/timer/stm32_lptim_timer.c index aaf83c30057..ffda551524d 100644 --- a/drivers/timer/stm32_lptim_timer.c +++ b/drivers/timer/stm32_lptim_timer.c @@ -387,19 +387,6 @@ static int sys_clock_driver_init(void) return -EIO; } - if (IS_ENABLED(DT_PROP(DT_DRV_INST(0), st_static_prescaler))) { - /* - * LPTIM of the stm32, like stm32U5, which has a clock source x2. - * A full 16bit LPTIM counter is counting 4s at 2 * 1/32768 (with LSE) - * Time base = (4s * freq) - 1 - */ - lptim_clock_freq = lptim_clock_freq / 2; - } - /* - * Else, a full 16bit LPTIM counter is counting 2s at 1/32768 (with LSE) - * Time base = (2s * freq) - 1 - */ - /* Actual lptim clock freq when the clock source is reduced by the prescaler */ lptim_clock_freq = lptim_clock_freq / LPTIM_CLOCK_RATIO; From c3940cb4f7c6ab5b85b5bc8556faacc1e9908a2b Mon Sep 17 00:00:00 2001 From: Francois Ramu Date: Thu, 23 Nov 2023 14:34:18 +0100 Subject: [PATCH 0253/3723] Revert "dts: arm: stm32u5 family has a x2 factor on its LPTIM clock" This reverts commit 823b0e6016b99e49050f65e84515ef9ac76084f7. Signed-off-by: Francois Ramu --- dts/arm/st/u5/stm32u5.dtsi | 4 ---- 1 file changed, 4 deletions(-) diff --git a/dts/arm/st/u5/stm32u5.dtsi b/dts/arm/st/u5/stm32u5.dtsi index 7363181e663..ae9dd9d9c8c 100644 --- a/dts/arm/st/u5/stm32u5.dtsi +++ b/dts/arm/st/u5/stm32u5.dtsi @@ -434,7 +434,6 @@ clocks = <&rcc STM32_CLOCK_BUS_APB3 0x00000800>; interrupts = <67 1>; interrupt-names = "wakeup"; - st,static-prescaler; status = "disabled"; }; @@ -446,7 +445,6 @@ clocks = <&rcc STM32_CLOCK_BUS_APB1_2 0x00000020>; interrupts = <68 0>; interrupt-names = "global"; - st,static-prescaler; status = "disabled"; }; @@ -458,7 +456,6 @@ clocks = <&rcc STM32_CLOCK_BUS_APB3 0x00001000>; interrupts = <98 0>; interrupt-names = "global"; - st,static-prescaler; status = "disabled"; }; @@ -470,7 +467,6 @@ clocks = <&rcc STM32_CLOCK_BUS_APB3 0x00002000>; interrupts = <110 0>; interrupt-names = "global"; - st,static-prescaler; status = "disabled"; }; From 9bb708eb7ddbde2c5579450e111a099f39ea5e45 Mon Sep 17 00:00:00 2001 From: Alberto Escolar Piedras Date: Thu, 23 Nov 2023 15:27:09 +0100 Subject: [PATCH 0254/3723] init_priorities: Fix for native_simulator based targets Fix the init_prioties related cmake targets so they also work with native_simulator based build targets. Mostly this consists of pointing to the right file (final build result instead of intermediate elf library) and setting the dependency to that final build result. Note that for the native_simulator based targets the init priorities check can only be run on build if we are building the final image (not just a partial prelinked library), and we are not assembling several images together into one executable. Signed-off-by: Alberto Escolar Piedras --- CMakeLists.txt | 35 +++++++++++++++++++++++------------ Kconfig.zephyr | 4 +++- 2 files changed, 26 insertions(+), 13 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 164d82fde0e..3b0af4e34a3 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -1751,7 +1751,6 @@ if(CONFIG_BUILD_OUTPUT_EXE) post_build_byproducts ${KERNEL_EXE_NAME} ) - set(BYPRODUCT_KERNEL_EXE_NAME "${PROJECT_BINARY_DIR}/${KERNEL_EXE_NAME}" CACHE FILEPATH "Kernel exe file" FORCE) else() if(CMAKE_GENERATOR STREQUAL "Unix Makefiles") set(MAKE "${CMAKE_MAKE_PROGRAM}" CACHE FILEPATH "cmake defined make") @@ -1768,6 +1767,7 @@ if(CONFIG_BUILD_OUTPUT_EXE) BYPRODUCTS ${KERNEL_EXE_NAME} ) endif() + set(BYPRODUCT_KERNEL_EXE_NAME "${PROJECT_BINARY_DIR}/${KERNEL_EXE_NAME}" CACHE FILEPATH "Kernel exe file" FORCE) endif() if(CONFIG_BUILD_OUTPUT_INFO_HEADER) @@ -1784,21 +1784,32 @@ if(CONFIG_BUILD_OUTPUT_INFO_HEADER) ) endif() -if(CONFIG_CHECK_INIT_PRIORITIES) - list(APPEND - post_build_commands - COMMAND ${PYTHON_EXECUTABLE} ${ZEPHYR_BASE}/scripts/build/check_init_priorities.py - --elf-file=${ZEPHYR_BINARY_DIR}/${KERNEL_ELF_NAME} +if(NOT CMAKE_C_COMPILER_ID STREQUAL "ARMClang") + set(check_init_priorities_input + $,${BYPRODUCT_KERNEL_EXE_NAME},${BYPRODUCT_KERNEL_ELF_NAME}> + ) + set(check_init_priorities_command + ${PYTHON_EXECUTABLE} ${ZEPHYR_BASE}/scripts/build/check_init_priorities.py + --elf-file=${check_init_priorities_input} + ) + set(check_init_priorities_dependencies + ${logical_target_for_zephyr_elf} + $<$:native_runner_executable> + ) + + if(CONFIG_CHECK_INIT_PRIORITIES) + add_custom_target( + check_init_priorities + ALL + COMMAND ${check_init_priorities_command} + DEPENDS ${check_init_priorities_dependencies} ) -endif() + endif() -if(NOT CMAKE_C_COMPILER_ID STREQUAL "ARMClang") add_custom_target( initlevels - COMMAND ${PYTHON_EXECUTABLE} ${ZEPHYR_BASE}/scripts/build/check_init_priorities.py - --elf-file=${ZEPHYR_BINARY_DIR}/${KERNEL_ELF_NAME} - --initlevels - DEPENDS ${logical_target_for_zephyr_elf} + COMMAND ${check_init_priorities_command} --initlevels + DEPENDS ${check_init_priorities_dependencies} USES_TERMINAL ) endif() diff --git a/Kconfig.zephyr b/Kconfig.zephyr index c484898206b..e1694173048 100644 --- a/Kconfig.zephyr +++ b/Kconfig.zephyr @@ -777,7 +777,9 @@ config BUILD_OUTPUT_STRIP_PATHS config CHECK_INIT_PRIORITIES bool "Build time initialization priorities check" default y - depends on !NATIVE_LIBRARY + # If we are building a native_simulator target, we can only check the init priorities + # if we are building the final output but we are not assembling several images together + depends on !(NATIVE_LIBRARY && (!BUILD_OUTPUT_EXE || NATIVE_SIMULATOR_EXTRA_IMAGE_PATHS != "")) depends on "$(ZEPHYR_TOOLCHAIN_VARIANT)" != "armclang" help Check the build for initialization priority issues by comparing the From 9aafc832a2eb3a6e530a221f642512eed9cd9958 Mon Sep 17 00:00:00 2001 From: Alberto Escolar Piedras Date: Thu, 23 Nov 2023 13:31:06 +0100 Subject: [PATCH 0255/3723] tests/misc/check_init_priorities: Fix for native_sim Fix this test for the native_simulator, and add it as a default test target. Also be a bit clearer in stdout about the test having passed or not. Signed-off-by: Alberto Escolar Piedras --- .../misc/check_init_priorities/CMakeLists.txt | 6 ++- .../boards/native_posix.overlay | 33 +--------------- .../boards/native_sim.overlay | 38 +++++++++++++++++++ ...posix_64.overlay => native_sim_64.overlay} | 2 +- .../misc/check_init_priorities/testcase.yaml | 6 ++- .../validate_check_init_priorities_output.py | 2 + 6 files changed, 51 insertions(+), 36 deletions(-) create mode 100644 tests/misc/check_init_priorities/boards/native_sim.overlay rename tests/misc/check_init_priorities/boards/{native_posix_64.overlay => native_sim_64.overlay} (70%) diff --git a/tests/misc/check_init_priorities/CMakeLists.txt b/tests/misc/check_init_priorities/CMakeLists.txt index 8803b2fa651..9a615977d5d 100644 --- a/tests/misc/check_init_priorities/CMakeLists.txt +++ b/tests/misc/check_init_priorities/CMakeLists.txt @@ -8,10 +8,12 @@ set(output_file ${PROJECT_BINARY_DIR}/check_init_priorities_output.txt) add_custom_command( COMMENT "Running check_init_priorities.py" OUTPUT ${output_file} - DEPENDS ${BYPRODUCT_KERNEL_ELF_NAME} + DEPENDS + ${logical_target_for_zephyr_elf} + $<$:native_runner_executable> COMMAND ${PYTHON_EXECUTABLE} ${ZEPHYR_BASE}/scripts/build/check_init_priorities.py + --elf-file=$,${BYPRODUCT_KERNEL_EXE_NAME},${BYPRODUCT_KERNEL_ELF_NAME}> --verbose - --elf-file=${ZEPHYR_BINARY_DIR}/${KERNEL_ELF_NAME} --output ${output_file} --always-succeed COMMAND ${PYTHON_EXECUTABLE} ${APPLICATION_SOURCE_DIR}/validate_check_init_priorities_output.py diff --git a/tests/misc/check_init_priorities/boards/native_posix.overlay b/tests/misc/check_init_priorities/boards/native_posix.overlay index 0f32c8121a8..1cf720283b3 100644 --- a/tests/misc/check_init_priorities/boards/native_posix.overlay +++ b/tests/misc/check_init_priorities/boards/native_posix.overlay @@ -4,35 +4,4 @@ * SPDX-License-Identifier: Apache-2.0 */ -/ { - test_gpio_0: gpio@ffff { - gpio-controller; - #gpio-cells = <0x2>; - compatible = "vnd,gpio-device"; - status = "okay"; - reg = <0xffff 0x1000>; - }; - - test_i2c: i2c@11112222 { - #address-cells = <1>; - #size-cells = <0>; - compatible = "vnd,i2c"; - status = "okay"; - reg = <0x11112222 0x1000>; - clock-frequency = <100000>; - - test_dev_a: test-i2c-dev@10 { - compatible = "vnd,i2c-device"; - status = "okay"; - reg = <0x10>; - supply-gpios = <&test_gpio_0 1 0>; - }; - - test_dev_b: test-i2c-dev@11 { - compatible = "vnd,i2c-device"; - status = "okay"; - reg = <0x11>; - supply-gpios = <&test_gpio_0 2 0>; - }; - }; -}; +#include "native_sim.overlay" diff --git a/tests/misc/check_init_priorities/boards/native_sim.overlay b/tests/misc/check_init_priorities/boards/native_sim.overlay new file mode 100644 index 00000000000..0f32c8121a8 --- /dev/null +++ b/tests/misc/check_init_priorities/boards/native_sim.overlay @@ -0,0 +1,38 @@ +/* + * Copyright 2023 Google LLC + * + * SPDX-License-Identifier: Apache-2.0 + */ + +/ { + test_gpio_0: gpio@ffff { + gpio-controller; + #gpio-cells = <0x2>; + compatible = "vnd,gpio-device"; + status = "okay"; + reg = <0xffff 0x1000>; + }; + + test_i2c: i2c@11112222 { + #address-cells = <1>; + #size-cells = <0>; + compatible = "vnd,i2c"; + status = "okay"; + reg = <0x11112222 0x1000>; + clock-frequency = <100000>; + + test_dev_a: test-i2c-dev@10 { + compatible = "vnd,i2c-device"; + status = "okay"; + reg = <0x10>; + supply-gpios = <&test_gpio_0 1 0>; + }; + + test_dev_b: test-i2c-dev@11 { + compatible = "vnd,i2c-device"; + status = "okay"; + reg = <0x11>; + supply-gpios = <&test_gpio_0 2 0>; + }; + }; +}; diff --git a/tests/misc/check_init_priorities/boards/native_posix_64.overlay b/tests/misc/check_init_priorities/boards/native_sim_64.overlay similarity index 70% rename from tests/misc/check_init_priorities/boards/native_posix_64.overlay rename to tests/misc/check_init_priorities/boards/native_sim_64.overlay index 166e6f02e82..a906fce7488 100644 --- a/tests/misc/check_init_priorities/boards/native_posix_64.overlay +++ b/tests/misc/check_init_priorities/boards/native_sim_64.overlay @@ -3,4 +3,4 @@ * * SPDX-License-Identifier: Apache-2.0 */ -#include "native_posix.overlay" +#include "native_sim.overlay" diff --git a/tests/misc/check_init_priorities/testcase.yaml b/tests/misc/check_init_priorities/testcase.yaml index e136e4ae389..1484ae9c100 100644 --- a/tests/misc/check_init_priorities/testcase.yaml +++ b/tests/misc/check_init_priorities/testcase.yaml @@ -3,6 +3,10 @@ tests: init.check_init_priorities: build_only: true - platform_allow: native_posix native_posix_64 + platform_allow: + - native_sim + - native_sim_64 + - native_posix integration_platforms: + - native_sim - native_posix diff --git a/tests/misc/check_init_priorities/validate_check_init_priorities_output.py b/tests/misc/check_init_priorities/validate_check_init_priorities_output.py index 714976e1a09..f5d322164c6 100755 --- a/tests/misc/check_init_priorities/validate_check_init_priorities_output.py +++ b/tests/misc/check_init_priorities/validate_check_init_priorities_output.py @@ -34,6 +34,8 @@ print() print("got:") print("\n".join(sorted(output))) + print("TEST FAILED") sys.exit(1) +print("TEST PASSED") sys.exit(0) From 084b8e4f9725323c13fe512b01b15bcfec9b42a6 Mon Sep 17 00:00:00 2001 From: Johan Hedberg Date: Fri, 24 Nov 2023 13:38:02 +0200 Subject: [PATCH 0256/3723] x86: Only enable EFI_CONSOLE if UART console is not enabled Most x86 build configurations enable the UART console. Since EFI console has also defaulted to enabled, this means that the EFI covers the early part of the boot until UART takes over. This is all fine, except that enabling EFI console has the effect of disabling PRINTK_SYNC. This in turn has the effect of causing garbled output over UART, which has led to several bug reports on x86 platforms (in particular on up_squared). Since EFI console should really only be used for early platform bringup and debugging purposes, it's not really ideal to unconditionally have it enabled by default. Instead, change the default enabling to be conditional to the UART console being disabled. Fixes #54861 Fixes #55071 Signed-off-by: Johan Hedberg --- arch/x86/Kconfig | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/arch/x86/Kconfig b/arch/x86/Kconfig index d7ccfca7ecd..7f852742fb8 100644 --- a/arch/x86/Kconfig +++ b/arch/x86/Kconfig @@ -472,7 +472,7 @@ config X86_EFI_CONSOLE bool depends on X86_EFI && X86_64 && !X86_VERY_EARLY_CONSOLE select EFI_CONSOLE - default y + default y if !UART_CONSOLE help This enables the use of the UEFI console device as the Zephyr printk handler. It requires that no interferences From 8f78b7148ce5234aa877b2653ae99ddcab3a5c75 Mon Sep 17 00:00:00 2001 From: Alberto Escolar Piedras Date: Fri, 24 Nov 2023 12:45:11 +0100 Subject: [PATCH 0257/3723] samples/bluetooth: sysbuild: Add Kconfig setting for HCI IPC inclusion Introduce NET_CORE_IMAGE_HCI_IPC Kconfig setting to control inclusion of HCI IPC image when building through sysbuild. This allows users with custom netcore applications to avoid inclusion of the default HCI IPC image. Signed-off-by: Alberto Escolar Piedras --- samples/bluetooth/broadcast_audio_source/Kconfig.sysbuild | 5 +++++ samples/bluetooth/broadcast_audio_source/sysbuild.cmake | 2 +- samples/bluetooth/unicast_audio_client/Kconfig.sysbuild | 5 +++++ samples/bluetooth/unicast_audio_client/sysbuild.cmake | 2 +- samples/bluetooth/unicast_audio_server/Kconfig.sysbuild | 5 +++++ samples/bluetooth/unicast_audio_server/sysbuild.cmake | 2 +- 6 files changed, 18 insertions(+), 3 deletions(-) diff --git a/samples/bluetooth/broadcast_audio_source/Kconfig.sysbuild b/samples/bluetooth/broadcast_audio_source/Kconfig.sysbuild index 37a6b66c7f4..f434010f81d 100644 --- a/samples/bluetooth/broadcast_audio_source/Kconfig.sysbuild +++ b/samples/bluetooth/broadcast_audio_source/Kconfig.sysbuild @@ -8,3 +8,8 @@ config NET_CORE_BOARD default "nrf5340dk_nrf5340_cpunet" if $(BOARD) = "nrf5340dk_nrf5340_cpuapp" default "nrf5340_audio_dk_nrf5340_cpunet" if $(BOARD) = "nrf5340_audio_dk_nrf5340_cpuapp" default "nrf5340bsim_nrf5340_cpunet" if $(BOARD) = "nrf5340bsim_nrf5340_cpuapp" + +config NET_CORE_IMAGE_HCI_IPC + bool "HCI IPC image on network core" + default y + depends on NET_CORE_BOARD != "" diff --git a/samples/bluetooth/broadcast_audio_source/sysbuild.cmake b/samples/bluetooth/broadcast_audio_source/sysbuild.cmake index c150913cc55..ed30d7f31f3 100644 --- a/samples/bluetooth/broadcast_audio_source/sysbuild.cmake +++ b/samples/bluetooth/broadcast_audio_source/sysbuild.cmake @@ -1,7 +1,7 @@ # Copyright (c) 2023 Nordic Semiconductor ASA # SPDX-License-Identifier: Apache-2.0 -if(NOT("${SB_CONFIG_NET_CORE_BOARD}" STREQUAL "")) +if(SB_CONFIG_NET_CORE_IMAGE_HCI_IPC) # For builds in the nrf5340, we build the netcore image with the controller set(NET_APP hci_ipc) diff --git a/samples/bluetooth/unicast_audio_client/Kconfig.sysbuild b/samples/bluetooth/unicast_audio_client/Kconfig.sysbuild index 37a6b66c7f4..f434010f81d 100644 --- a/samples/bluetooth/unicast_audio_client/Kconfig.sysbuild +++ b/samples/bluetooth/unicast_audio_client/Kconfig.sysbuild @@ -8,3 +8,8 @@ config NET_CORE_BOARD default "nrf5340dk_nrf5340_cpunet" if $(BOARD) = "nrf5340dk_nrf5340_cpuapp" default "nrf5340_audio_dk_nrf5340_cpunet" if $(BOARD) = "nrf5340_audio_dk_nrf5340_cpuapp" default "nrf5340bsim_nrf5340_cpunet" if $(BOARD) = "nrf5340bsim_nrf5340_cpuapp" + +config NET_CORE_IMAGE_HCI_IPC + bool "HCI IPC image on network core" + default y + depends on NET_CORE_BOARD != "" diff --git a/samples/bluetooth/unicast_audio_client/sysbuild.cmake b/samples/bluetooth/unicast_audio_client/sysbuild.cmake index c150913cc55..ed30d7f31f3 100644 --- a/samples/bluetooth/unicast_audio_client/sysbuild.cmake +++ b/samples/bluetooth/unicast_audio_client/sysbuild.cmake @@ -1,7 +1,7 @@ # Copyright (c) 2023 Nordic Semiconductor ASA # SPDX-License-Identifier: Apache-2.0 -if(NOT("${SB_CONFIG_NET_CORE_BOARD}" STREQUAL "")) +if(SB_CONFIG_NET_CORE_IMAGE_HCI_IPC) # For builds in the nrf5340, we build the netcore image with the controller set(NET_APP hci_ipc) diff --git a/samples/bluetooth/unicast_audio_server/Kconfig.sysbuild b/samples/bluetooth/unicast_audio_server/Kconfig.sysbuild index 37a6b66c7f4..f434010f81d 100644 --- a/samples/bluetooth/unicast_audio_server/Kconfig.sysbuild +++ b/samples/bluetooth/unicast_audio_server/Kconfig.sysbuild @@ -8,3 +8,8 @@ config NET_CORE_BOARD default "nrf5340dk_nrf5340_cpunet" if $(BOARD) = "nrf5340dk_nrf5340_cpuapp" default "nrf5340_audio_dk_nrf5340_cpunet" if $(BOARD) = "nrf5340_audio_dk_nrf5340_cpuapp" default "nrf5340bsim_nrf5340_cpunet" if $(BOARD) = "nrf5340bsim_nrf5340_cpuapp" + +config NET_CORE_IMAGE_HCI_IPC + bool "HCI IPC image on network core" + default y + depends on NET_CORE_BOARD != "" diff --git a/samples/bluetooth/unicast_audio_server/sysbuild.cmake b/samples/bluetooth/unicast_audio_server/sysbuild.cmake index c150913cc55..ed30d7f31f3 100644 --- a/samples/bluetooth/unicast_audio_server/sysbuild.cmake +++ b/samples/bluetooth/unicast_audio_server/sysbuild.cmake @@ -1,7 +1,7 @@ # Copyright (c) 2023 Nordic Semiconductor ASA # SPDX-License-Identifier: Apache-2.0 -if(NOT("${SB_CONFIG_NET_CORE_BOARD}" STREQUAL "")) +if(SB_CONFIG_NET_CORE_IMAGE_HCI_IPC) # For builds in the nrf5340, we build the netcore image with the controller set(NET_APP hci_ipc) From 82d7535b1904253913a73a7245378207bcf6696c Mon Sep 17 00:00:00 2001 From: Kacper Dalach Date: Sat, 25 Nov 2023 11:32:04 +0100 Subject: [PATCH 0258/3723] dts: st: Add cpu node labels After porting from h5 to f7 i noticed that not all mcus have cpu node labels. Added cpu0 node labels to all stm32 dts. Signed-off-by: Kacper Dalach --- 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/f7/stm32f7.dtsi | 2 +- dts/arm/st/g4/stm32g4.dtsi | 2 +- dts/arm/st/l1/stm32l1.dtsi | 2 +- dts/arm/st/mp1/stm32mp157.dtsi | 2 +- 8 files changed, 8 insertions(+), 8 deletions(-) diff --git a/dts/arm/st/f0/stm32f0.dtsi b/dts/arm/st/f0/stm32f0.dtsi index e9e521cd47e..3a7e5dac8ce 100644 --- a/dts/arm/st/f0/stm32f0.dtsi +++ b/dts/arm/st/f0/stm32f0.dtsi @@ -26,7 +26,7 @@ #address-cells = <1>; #size-cells = <0>; - cpu@0 { + cpu0: cpu@0 { device_type = "cpu"; compatible = "arm,cortex-m0"; reg = <0>; diff --git a/dts/arm/st/f1/stm32f1.dtsi b/dts/arm/st/f1/stm32f1.dtsi index b70130db308..d3eb976b566 100644 --- a/dts/arm/st/f1/stm32f1.dtsi +++ b/dts/arm/st/f1/stm32f1.dtsi @@ -26,7 +26,7 @@ #address-cells = <1>; #size-cells = <0>; - cpu@0 { + cpu0: cpu@0 { device_type = "cpu"; compatible = "arm,cortex-m3"; reg = <0>; diff --git a/dts/arm/st/f2/stm32f2.dtsi b/dts/arm/st/f2/stm32f2.dtsi index 845cd6fb5a2..7cef6f2428a 100644 --- a/dts/arm/st/f2/stm32f2.dtsi +++ b/dts/arm/st/f2/stm32f2.dtsi @@ -27,7 +27,7 @@ #address-cells = <1>; #size-cells = <0>; - cpu@0 { + cpu0: cpu@0 { device_type = "cpu"; compatible = "arm,cortex-m3"; reg = <0>; diff --git a/dts/arm/st/f3/stm32f3.dtsi b/dts/arm/st/f3/stm32f3.dtsi index a426a84ea3e..5f5099a90d6 100644 --- a/dts/arm/st/f3/stm32f3.dtsi +++ b/dts/arm/st/f3/stm32f3.dtsi @@ -25,7 +25,7 @@ #address-cells = <1>; #size-cells = <0>; - cpu@0 { + cpu0: cpu@0 { device_type = "cpu"; compatible = "arm,cortex-m4f"; reg = <0>; diff --git a/dts/arm/st/f7/stm32f7.dtsi b/dts/arm/st/f7/stm32f7.dtsi index 2df24d0c8d2..6569d35c49f 100644 --- a/dts/arm/st/f7/stm32f7.dtsi +++ b/dts/arm/st/f7/stm32f7.dtsi @@ -30,7 +30,7 @@ #address-cells = <1>; #size-cells = <0>; - cpu@0 { + cpu0: cpu@0 { device_type = "cpu"; compatible = "arm,cortex-m7"; reg = <0>; diff --git a/dts/arm/st/g4/stm32g4.dtsi b/dts/arm/st/g4/stm32g4.dtsi index feec71388aa..4cc6c26fc02 100644 --- a/dts/arm/st/g4/stm32g4.dtsi +++ b/dts/arm/st/g4/stm32g4.dtsi @@ -28,7 +28,7 @@ #address-cells = <1>; #size-cells = <0>; - cpu@0 { + cpu0: cpu@0 { device_type = "cpu"; compatible = "arm,cortex-m4f"; reg = <0>; diff --git a/dts/arm/st/l1/stm32l1.dtsi b/dts/arm/st/l1/stm32l1.dtsi index 0203f740c83..2f08501a2c1 100644 --- a/dts/arm/st/l1/stm32l1.dtsi +++ b/dts/arm/st/l1/stm32l1.dtsi @@ -26,7 +26,7 @@ #address-cells = <1>; #size-cells = <0>; - cpu@0 { + cpu0: cpu@0 { device_type = "cpu"; compatible = "arm,cortex-m3"; reg = <0>; diff --git a/dts/arm/st/mp1/stm32mp157.dtsi b/dts/arm/st/mp1/stm32mp157.dtsi index f70a96b6ead..1877301b9f2 100644 --- a/dts/arm/st/mp1/stm32mp157.dtsi +++ b/dts/arm/st/mp1/stm32mp157.dtsi @@ -22,7 +22,7 @@ #address-cells = <1>; #size-cells = <0>; - cpu@0 { + cpu0: cpu@0 { device_type = "cpu"; compatible = "arm,cortex-m4"; reg = <0>; From db1c21bfd75f9915d2d829f3c38f70ff65ae07f8 Mon Sep 17 00:00:00 2001 From: Andrei Emeltchenko Date: Sat, 25 Nov 2023 16:07:24 +0200 Subject: [PATCH 0259/3723] drivers: sensor: adxl367: Add missing breaks Fix missing breaks errors. Signed-off-by: Andrei Emeltchenko --- drivers/sensor/adxl367/adxl367.c | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/drivers/sensor/adxl367/adxl367.c b/drivers/sensor/adxl367/adxl367.c index f63b8f73a32..1d5c31ad021 100644 --- a/drivers/sensor/adxl367/adxl367.c +++ b/drivers/sensor/adxl367/adxl367.c @@ -287,16 +287,22 @@ int adxl367_self_test(const struct device *dev) switch (cfg->odr) { case ADXL367_ODR_12P5HZ: st_delay_ms = 320; + break; case ADXL367_ODR_25HZ: st_delay_ms = 160; + break; case ADXL367_ODR_50HZ: st_delay_ms = 80; + break; case ADXL367_ODR_100HZ: st_delay_ms = 40; + break; case ADXL367_ODR_200HZ: st_delay_ms = 20; + break; case ADXL367_ODR_400HZ: st_delay_ms = 10; + break; default: return -EINVAL; } From 08a4829682b3df44c671fc0db5b575be53ab4886 Mon Sep 17 00:00:00 2001 From: Bartosz Bilas Date: Sat, 25 Nov 2023 17:29:54 +0100 Subject: [PATCH 0260/3723] drivers: ethernet: esp32: fix Kconfig Add the missing dependency of the node status value and enable the driver by default when they are met. Signed-off-by: Bartosz Bilas --- drivers/ethernet/Kconfig.esp32 | 2 ++ 1 file changed, 2 insertions(+) diff --git a/drivers/ethernet/Kconfig.esp32 b/drivers/ethernet/Kconfig.esp32 index 8adb24cfb77..35c07860f4e 100644 --- a/drivers/ethernet/Kconfig.esp32 +++ b/drivers/ethernet/Kconfig.esp32 @@ -5,7 +5,9 @@ menuconfig ETH_ESP32 bool "ESP32 Ethernet driver" + default y depends on SOC_SERIES_ESP32 + depends on DT_HAS_ESPRESSIF_ESP32_ETH_ENABLED select MDIO help Enable ESP32 Ethernet driver. From 0b76b4f0161481bbc0539278e7092ba20a0cfc51 Mon Sep 17 00:00:00 2001 From: Bartosz Bilas Date: Sat, 25 Nov 2023 17:28:42 +0100 Subject: [PATCH 0261/3723] drivers: mdio: esp32: add dependency of node status MDIO driver should be available and enabled only when mdio node has status okay. Signed-off-by: Bartosz Bilas --- drivers/mdio/Kconfig.esp32 | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/drivers/mdio/Kconfig.esp32 b/drivers/mdio/Kconfig.esp32 index bdc8fb1221e..9c4d8f8bae5 100644 --- a/drivers/mdio/Kconfig.esp32 +++ b/drivers/mdio/Kconfig.esp32 @@ -3,7 +3,8 @@ config MDIO_ESP32 bool "ESP32 MDIO driver" - depends on SOC_SERIES_ESP32 default y + depends on SOC_SERIES_ESP32 + depends on DT_HAS_ESPRESSIF_ESP32_MDIO_ENABLED help Enable ESP32 MCU Family MDIO driver. From e3520c681386fbb2ba64a65c456a84b7f9ff07f8 Mon Sep 17 00:00:00 2001 From: Yonatan Schachter Date: Sun, 26 Nov 2023 22:53:41 +0200 Subject: [PATCH 0262/3723] dts: rp2040: Fix num-irq-priority-bits The number of IRQ priority bits was incorrectly set to 3 instead of 2, which is the correct number for Cortex-M0+. Signed-off-by: Yonatan Schachter --- dts/arm/rpi_pico/rp2040.dtsi | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/dts/arm/rpi_pico/rp2040.dtsi b/dts/arm/rpi_pico/rp2040.dtsi index fd83297fa5a..1e4211075f8 100644 --- a/dts/arm/rpi_pico/rp2040.dtsi +++ b/dts/arm/rpi_pico/rp2040.dtsi @@ -255,5 +255,5 @@ }; &nvic { - arm,num-irq-priority-bits = <3>; + arm,num-irq-priority-bits = <2>; }; From e49ae776cc2c3354b3bacc875edeb77c8a886c7b Mon Sep 17 00:00:00 2001 From: Christopher Friedt Date: Thu, 23 Nov 2023 01:13:43 -0500 Subject: [PATCH 0263/3723] posix: pthread: implement pthread_getconcurrency() Zephyr must support all functionality of the XSI_THREADS_EXT subprofiling option group in order to claim it supports that subprofiling option group. The XSI_THREADS_EXT option group is critical to be able to run POSIX threads with statically allocated thread stacks, which has been a feature of the implementation since it was initially added. The pthread_getconcurrency() and pthread_setconcurrency() functions are the only remaining, unimplemented functions of the XSI_THREADS_EXT option group. Implement pthread_getconcurrency() and pthread_setconcurrency() via the more "posixly correct" interpretation of the specification. I.e. as the pthread_t:k_thread relationship is 1:1 and not M:N, Zephyr does not support multiplexing of user threads on top of schedulable kernel entities (i.e. "user threads" are directly mapped to native threads, just like linuxthreads or NPTL are in Linux). For that reason, to be "posixly correct", we should save the provided value via pthread_setconcurrency(), in the absense of errors, and also return that same value back via pthread_getconcurrency(), even though that serves zero purpose in Zephyr for the foreseeable future. Note: the specification also states "an implementation can always ignore any calls to pthread_setconcurrency() and return a constant for pthread_getconcurrency()." For that reason, the implementation may be revisited at a later time when when considering optimizations and when there is a better system in place for documenting deviations. Any such optimization should be explicitly controlled via Kconfig. Signed-off-by: Christopher Friedt --- include/zephyr/posix/pthread.h | 2 ++ lib/posix/pthread.c | 30 +++++++++++++++++++++++++++++- 2 files changed, 31 insertions(+), 1 deletion(-) diff --git a/include/zephyr/posix/pthread.h b/include/zephyr/posix/pthread.h index a7feef8bc7e..d61c46c5116 100644 --- a/include/zephyr/posix/pthread.h +++ b/include/zephyr/posix/pthread.h @@ -477,6 +477,8 @@ int pthread_key_delete(pthread_key_t key); int pthread_setspecific(pthread_key_t key, const void *value); void *pthread_getspecific(pthread_key_t key); int pthread_atfork(void (*prepare)(void), void (*parent)(void), void (*child)(void)); +int pthread_getconcurrency(void); +int pthread_setconcurrency(int new_level); /* Glibc / Oracle Extension Functions */ diff --git a/lib/posix/pthread.c b/lib/posix/pthread.c index d00d5564c73..3cc4413949b 100644 --- a/lib/posix/pthread.c +++ b/lib/posix/pthread.c @@ -51,7 +51,7 @@ static sys_dlist_t run_q = SYS_DLIST_STATIC_INIT(&run_q); static sys_dlist_t done_q = SYS_DLIST_STATIC_INIT(&done_q); static struct posix_thread posix_thread_pool[CONFIG_MAX_PTHREAD_COUNT]; static struct k_spinlock pthread_pool_lock; - +static int pthread_concurrency; static K_MUTEX_DEFINE(pthread_once_lock); static const struct pthread_attr init_pthread_attrs = { @@ -466,6 +466,34 @@ int pthread_create(pthread_t *th, const pthread_attr_t *_attr, void *(*threadrou return 0; } +int pthread_getconcurrency(void) +{ + int ret; + + K_SPINLOCK(&pthread_pool_lock) { + ret = pthread_concurrency; + } + + return ret; +} + +int pthread_setconcurrency(int new_level) +{ + if (new_level < 0) { + return EINVAL; + } + + if (new_level > CONFIG_MP_MAX_NUM_CPUS) { + return EAGAIN; + } + + K_SPINLOCK(&pthread_pool_lock) { + pthread_concurrency = new_level; + } + + return 0; +} + /** * @brief Set cancelability State. * From c0f2038c262792a92f8d53ea5ed4dbc975bf942e Mon Sep 17 00:00:00 2001 From: Christopher Friedt Date: Thu, 23 Nov 2023 01:16:58 -0500 Subject: [PATCH 0264/3723] tests: posix: headers: check for pthread_getconcurrency() Check for the existence of pthread_getconcurrency() and pthread_setconcurrency(). Signed-off-by: Christopher Friedt --- tests/posix/headers/src/pthread_h.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/tests/posix/headers/src/pthread_h.c b/tests/posix/headers/src/pthread_h.c index 444a487f85c..354a79dbfdf 100644 --- a/tests/posix/headers/src/pthread_h.c +++ b/tests/posix/headers/src/pthread_h.c @@ -104,7 +104,7 @@ ZTEST(posix_headers, test_pthread_h) zassert_not_null(pthread_detach); zassert_not_null(pthread_equal); zassert_not_null(pthread_exit); - /* zassert_not_null(pthread_getconcurrency); */ /* not implemented */ + zassert_not_null(pthread_getconcurrency); /* zassert_not_null(pthread_getcpuclockid); */ /* not implemented */ zassert_not_null(pthread_getschedparam); zassert_not_null(pthread_getspecific); @@ -149,7 +149,7 @@ ZTEST(posix_headers, test_pthread_h) zassert_not_null(pthread_self); zassert_not_null(pthread_setcancelstate); zassert_not_null(pthread_setcanceltype); - /* zassert_not_null(pthread_setconcurrency); */ /* not implemented */ + zassert_not_null(pthread_setconcurrency); zassert_not_null(pthread_setschedparam); /* zassert_not_null(pthread_setschedprio); */ /* not implemented */ zassert_not_null(pthread_setspecific); From caf72569a995ca6eb09d31f1ab055e22da7ba83d Mon Sep 17 00:00:00 2001 From: Christopher Friedt Date: Fri, 24 Nov 2023 09:36:49 -0500 Subject: [PATCH 0265/3723] tests: posix: common: test pthread_getconcurrency() Add functional tests for pthread_getconcurrency() and pthread_setconcurrency(). Note: the specification explicitly says > an implementation can always ignore any calls to > pthread_setconcurrency() and return a constant for > pthread_getconcurrency() The implementation and tests could be up for revision at a future time when optimizations are considered and there is a better system in placeo for documenting POSIX options and deviations. Any such optimizations should be explicitly controlled via Kconfig. Signed-off-by: Christopher Friedt --- tests/posix/common/src/pthread.c | 23 +++++++++++++++++++++++ 1 file changed, 23 insertions(+) diff --git a/tests/posix/common/src/pthread.c b/tests/posix/common/src/pthread.c index 6b7cb25616e..0276afd6045 100644 --- a/tests/posix/common/src/pthread.c +++ b/tests/posix/common/src/pthread.c @@ -882,3 +882,26 @@ ZTEST(posix_apis, test_pthread_join_detached) /* need to allow this thread to be clean-up by the recycler */ k_msleep(500); } + +ZTEST(posix_apis, test_pthread_set_get_concurrency) +{ + /* EINVAL if the value specified by new_level is negative */ + zassert_equal(EINVAL, pthread_setconcurrency(-42)); + + /* + * Note: the special value 0 indicates the implementation will + * maintain the concurrency level at its own discretion. + * + * pthread_getconcurrency() should return a value of 0 on init. + */ + zassert_equal(0, pthread_getconcurrency()); + + for (int i = 0; i <= CONFIG_MP_MAX_NUM_CPUS; ++i) { + zassert_ok(pthread_setconcurrency(i)); + /* verify parameter is saved */ + zassert_equal(i, pthread_getconcurrency()); + } + + /* EAGAIN if the a system resource to be exceeded */ + zassert_equal(EAGAIN, pthread_setconcurrency(CONFIG_MP_MAX_NUM_CPUS + 1)); +} From 5bfed9ef6b27b225ace044807fbad3a5d68b598c Mon Sep 17 00:00:00 2001 From: Christopher Friedt Date: Thu, 23 Nov 2023 01:17:53 -0500 Subject: [PATCH 0266/3723] doc: posix; mark pthread_getconcurrency() supported Mark pthread_getconcurrency() and pthread_setconcurrency() as supported in documentation. Signed-off-by: Christopher Friedt --- doc/services/portability/posix/option_groups/index.rst | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/doc/services/portability/posix/option_groups/index.rst b/doc/services/portability/posix/option_groups/index.rst index 97d7ce226a8..65b96a4d201 100644 --- a/doc/services/portability/posix/option_groups/index.rst +++ b/doc/services/portability/posix/option_groups/index.rst @@ -99,8 +99,8 @@ This table lists service support status in Zephyr: pthread_attr_getstack(),yes pthread_attr_setstack(),yes - pthread_getconcurrency(), - pthread_setconcurrency() + pthread_getconcurrency(),yes + pthread_setconcurrency(),yes .. _posix_option_group_c_lang_support: From a97e30a82952f15b946c4087729ba6bab2f4f76f Mon Sep 17 00:00:00 2001 From: Felipe Neves Date: Wed, 18 Oct 2023 16:36:47 -0300 Subject: [PATCH 0267/3723] boards: arm: arduino_opta_m4: adds initial support to the arduino_opta PLC on the M4 core. Signed-off-by: Felipe Neves --- boards/arm/arduino_opta_m4/Kconfig.board | 7 + boards/arm/arduino_opta_m4/Kconfig.defconfig | 9 + .../arm/arduino_opta_m4/arduino_opta_m4.dts | 74 ++++++++ .../arm/arduino_opta_m4/arduino_opta_m4.yaml | 21 +++ .../arduino_opta_m4/arduino_opta_m4_defconfig | 25 +++ boards/arm/arduino_opta_m4/board.cmake | 5 + .../arduino_opta_m4/doc/img/arduino_opta.jpeg | Bin 0 -> 16369 bytes boards/arm/arduino_opta_m4/doc/index.rst | 177 ++++++++++++++++++ 8 files changed, 318 insertions(+) create mode 100644 boards/arm/arduino_opta_m4/Kconfig.board create mode 100644 boards/arm/arduino_opta_m4/Kconfig.defconfig create mode 100644 boards/arm/arduino_opta_m4/arduino_opta_m4.dts create mode 100644 boards/arm/arduino_opta_m4/arduino_opta_m4.yaml create mode 100644 boards/arm/arduino_opta_m4/arduino_opta_m4_defconfig create mode 100644 boards/arm/arduino_opta_m4/board.cmake create mode 100644 boards/arm/arduino_opta_m4/doc/img/arduino_opta.jpeg create mode 100644 boards/arm/arduino_opta_m4/doc/index.rst diff --git a/boards/arm/arduino_opta_m4/Kconfig.board b/boards/arm/arduino_opta_m4/Kconfig.board new file mode 100644 index 00000000000..cce1cd6337a --- /dev/null +++ b/boards/arm/arduino_opta_m4/Kconfig.board @@ -0,0 +1,7 @@ +# Copyright (c) 2023 Felipe Neves +# SPDX-License-Identifier: Apache-2.0 + +config BOARD_ARDUINO_OPTA_M4 + bool "Arduino OPTA Programmable Logic Controller M4 Core" + depends on SOC_STM32H747XX + select CPU_CORTEX_M4 diff --git a/boards/arm/arduino_opta_m4/Kconfig.defconfig b/boards/arm/arduino_opta_m4/Kconfig.defconfig new file mode 100644 index 00000000000..be17c009555 --- /dev/null +++ b/boards/arm/arduino_opta_m4/Kconfig.defconfig @@ -0,0 +1,9 @@ +# Copyright (c) 2023 Felipe Neves +# SPDX-License-Identifier: Apache-2.0 + +if BOARD_ARDUINO_OPTA_M4 + +config BOARD + default "arduino_opta_m4" + +endif # BOARD_ARDUINO_OPTA_M4 diff --git a/boards/arm/arduino_opta_m4/arduino_opta_m4.dts b/boards/arm/arduino_opta_m4/arduino_opta_m4.dts new file mode 100644 index 00000000000..bc74a2691f4 --- /dev/null +++ b/boards/arm/arduino_opta_m4/arduino_opta_m4.dts @@ -0,0 +1,74 @@ +/* + * Copyright (c) 2023 Felipe Neves + * + * SPDX-License-Identifier: Apache-2.0 + */ + +/dts-v1/; +#include +#include +#include + +/ { + model = "Arduino OPTA M4 core Programmable Logic Controller"; + compatible = "arduino,opta-m4"; + + chosen { + zephyr,sram = &sram1; + zephyr,flash = &flash1; + zephyr,code-partition = &slot0_partition; + }; + + leds { + compatible = "gpio-leds"; + status_led_1: led_1 { + gpios = <&gpioi 0 GPIO_ACTIVE_LOW>; + }; + status_led_2: led_2 { + gpios = <&gpioi 1 GPIO_ACTIVE_LOW>; + }; + status_led_3: led_3 { + gpios = <&gpioi 3 GPIO_ACTIVE_LOW>; + }; + status_led_4: led_4 { + gpios = <&gpioh 15 GPIO_ACTIVE_LOW>; + }; + }; + + gpio_keys { + compatible = "gpio-keys"; + + user_button: button { + gpios = <&gpioe 4 GPIO_ACTIVE_HIGH>; + zephyr,code = ; + }; + }; + + aliases { + sw0 = &user_button; + led0 = &status_led_1; + }; +}; + +&flash1 { + partitions { + compatible = "fixed-partitions"; + #address-cells = <1>; + #size-cells = <1>; + + slot0_partition: partition@80000 { + label = "image-0"; + reg = <0x00080000 DT_SIZE_K(512)>; + }; + }; +}; + +&rcc { + d1cpre = <1>; + hpre = <2>; + d1ppre = <2>; + d2ppre1 = <2>; + d2ppre2 = <2>; + d3ppre = <2>; + clock-frequency = ; +}; diff --git a/boards/arm/arduino_opta_m4/arduino_opta_m4.yaml b/boards/arm/arduino_opta_m4/arduino_opta_m4.yaml new file mode 100644 index 00000000000..4030cb402f6 --- /dev/null +++ b/boards/arm/arduino_opta_m4/arduino_opta_m4.yaml @@ -0,0 +1,21 @@ +identifier: arduino_opta_m4 +name: ARDUINO OPTA (M4) +type: mcu +arch: arm +toolchain: + - zephyr + - gnuarmemb + - xtools +ram: 288 +flash: 512 +supported: + - gpio +testing: + ignore_tags: + - mpu + - nfc + - net + - flash + - input + - mcumgr +vendor: arduino diff --git a/boards/arm/arduino_opta_m4/arduino_opta_m4_defconfig b/boards/arm/arduino_opta_m4/arduino_opta_m4_defconfig new file mode 100644 index 00000000000..bcf01ccabfb --- /dev/null +++ b/boards/arm/arduino_opta_m4/arduino_opta_m4_defconfig @@ -0,0 +1,25 @@ +# Copyright (c) 2023 Felipe Neves +# SPDX-License-Identifier: Apache-2.0 + +CONFIG_SOC_SERIES_STM32H7X=y +CONFIG_SOC_STM32H747XX=y + +CONFIG_BOARD_ARDUINO_OPTA_M4=y + +# enable GPIO +CONFIG_GPIO=y + +# clock configuration +CONFIG_CLOCK_CONTROL=y + +# Enable MPU +CONFIG_ARM_MPU=y + +# Enable HW stack protection +CONFIG_HW_STACK_PROTECTION=y + +# enable pin controller +CONFIG_PINCTRL=y + +# Use zephyr,code-partition as flash offset +CONFIG_USE_DT_CODE_PARTITION=y diff --git a/boards/arm/arduino_opta_m4/board.cmake b/boards/arm/arduino_opta_m4/board.cmake new file mode 100644 index 00000000000..029ae806f4d --- /dev/null +++ b/boards/arm/arduino_opta_m4/board.cmake @@ -0,0 +1,5 @@ +# SPDX-License-Identifier: Apache-2.0 + +board_runner_args(dfu-util "--pid=2341:0364" "--alt=0" "--dfuse") + +include(${ZEPHYR_BASE}/boards/common/dfu-util.board.cmake) diff --git a/boards/arm/arduino_opta_m4/doc/img/arduino_opta.jpeg b/boards/arm/arduino_opta_m4/doc/img/arduino_opta.jpeg new file mode 100644 index 0000000000000000000000000000000000000000..4b3a8e54d57474032abe6dc95d117e66515ada12 GIT binary patch literal 16369 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 literal 0 HcmV?d00001 diff --git a/boards/arm/arduino_opta_m4/doc/index.rst b/boards/arm/arduino_opta_m4/doc/index.rst new file mode 100644 index 00000000000..be914c3fa48 --- /dev/null +++ b/boards/arm/arduino_opta_m4/doc/index.rst @@ -0,0 +1,177 @@ +.. _arduino_opta_m4_board: + +Arduino OPTA M4-Core +####################### + +Overview +******** + +The Arduino™ Opta® is a secure micro Programmable Logic Controller (PLC) +with Industrial Internet of Things (IoT) capabilities. + +Developed in partnership with Finder®, this device supports both the Arduino +programming language and standard IEC-61131-3 PLC programming languages, +such as Ladder Diagram (LD), Sequential Function Chart (SFC), +Function Block Diagram (FBD), Structured Text (ST), and Instruction List (IL), +making it an ideal device for automation engineers. + +For Zephyr RTOS, only the M4 is supported for now, making the M7 run the PLC +tasks while the M4 core under Zephyr acts as a coprocessor. + +Additionally, the device features: + +- Ethernet compliant with IEEE802.3-2002 +- 16MB QSPI Flash +- 4 x green color status LEDs +- 1 x user push-button +- 1 x reset push-button accessible via pinhole +- 8 x analog inputs +- 4 x isolated relay outputs + +.. image:: img/arduino_opta.jpeg + :align: center + :alt: ARDUINO-OPTA + +More information about the board can be found at the `ARDUINO-OPTA website`_. +More information about STM32H747XIH6 can be found here: + +- `STM32H747XI on www.st.com`_ +- `STM32H747xx reference manual`_ +- `STM32H747xx datasheet`_ + +Supported Features +================== + +The current Zephyr arduino_opta_m4 board configuration supports the following hardware features: + ++-----------+------------+-------------------------------------+ +| Interface | Controller | Driver/Component | ++===========+============+=====================================+ +| NVIC | on-chip | nested vector interrupt controller | ++-----------+------------+-------------------------------------+ +| PINMUX | on-chip | pinmux | ++-----------+------------+-------------------------------------+ +| GPIO | on-chip | gpio | ++-----------+------------+-------------------------------------+ +| FLASH | on-chip | flash memory | ++-----------+------------+-------------------------------------+ +| RNG | on-chip | True Random number generator | ++-----------+------------+-------------------------------------+ +| IPM | on-chip | virtual mailbox based on HSEM | ++-----------+------------+-------------------------------------+ + +Other hardware features are not yet supported on Zephyr porting. + +The default configuration per core can be found in the defconfig files: +``boards/arm/arduino_opta_m4/arduino_opta_m4_defconfig`` + +Pin Mapping +=========== + +ARDUINO OPTA M4 has access to the 9 GPIO controllers. These controllers are responsible for pin muxing, +input/output, pull-up, etc. + +For mode details please refer to `ARDUINO-OPTA website`_. + +Default Zephyr Peripheral Mapping +--------------------------------- + +- Status LED1 : PI0 +- Status LED2 : PI1 +- Status LED3 : PI3 +- Status LED4 : PH15 +- User button : PE4 + +System Clock +============ + +The STM32H747I System Clock can be driven by an internal or external oscillator, +as well as by the main PLL clock. By default, the CPU2 (Cortex-M4) System clock +is driven at 240MHz. PLL clock is fed by a 25MHz high speed external clock. + +Resources sharing +================= + +The dual core nature of STM32H747 SoC requires sharing HW resources between the +two cores. This is done in 3 ways: + +- **Compilation**: Clock configuration is only accessible to M7 core. M4 core only + has access to bus clock activation and deactivation. +- **Static pre-compilation assignment**: Peripherals such as a UART are assigned in + devicetree before compilation. The user must ensure peripherals are not assigned + to both cores at the same time. +- **Run time protection**: Interrupt-controller and GPIO configurations could be + accessed by both cores at run time. Accesses are protected by a hardware semaphore + to avoid potential concurrent access issues. + +Programming and Debugging +************************* + +Applications for the ``arduino_opta_m4`` use the regular Zephyr build commands. +See :ref:`build_an_application` for more information about application builds. + +Flashing +======== + +Flashing operation will depend on the target to be flashed and the SoC +option bytes configuration. The OPTA has a DFU capable bootloader which +can be accessed by connecting the device to the USB, and then pressing +the RESET button shortly twice, the RESET-LED on the board will fade +indicating the board is in bootloader mode. + +By default: + + - CPU2 (Cortex-M4) boot address is set to 0x08180000 (OB: BOOT_CM4_ADD0) + +Zephyr flash configuration has been set to meet these default settings. + +Flashing an application to ARDUINO OPTA M4 +------------------------------------------ + +First, connect the device to your host computer using +the USB port to prepare it for flashing. Then build and flash your application. + +Here is an example for the :zephyr:code-sample:`blinky` application on M4 core. + +.. zephyr-app-commands:: + :zephyr-app: samples/basic/blinky + :board: arduino_opta_m4 + :goals: build flash + +Starting the application on the ARDUINO OPTA M4 +----------------------------------------------- + +Make sure the option bytes are set to prevent the M4 from auto-starting, and +that the M7 side starts the M4 at the correct Flash address. + +This can be done by selecting in the Arduino IDE's "Tools" / "Flash Split" +menu the "1.5MB M7 + 0.5MB M4" option, and loading a sketch that contains +at least the following code: + + .. code-block:: cpp + + #include + + void setup() { + RPC.begin(); + } + + void loop() { } + +Debugging +========= + +Debugging is not yet supported by this board, since the debug port does +not have an easy access. + +.. _ARDUINO-OPTA website: + https://docs.arduino.cc/hardware/opta + +.. _STM32H747XI on www.st.com: + https://www.st.com/content/st_com/en/products/microcontrollers-microprocessors/stm32-32-bit-arm-cortex-mcus/stm32-high-performance-mcus/stm32h7-series/stm32h747-757/stm32h747xi.html + +.. _STM32H747xx reference manual: + https://www.st.com/resource/en/reference_manual/dm00176879.pdf + +.. _STM32H747xx datasheet: + https://www.st.com/resource/en/datasheet/stm32h747xi.pdf From dfff1107b8c42db98cbc45127c459de3e87eb767 Mon Sep 17 00:00:00 2001 From: cyliang tw Date: Fri, 24 Nov 2023 18:06:02 +0800 Subject: [PATCH 0268/3723] drivers: i2c: support for Nuvoton numaker series Add Nuvoton numaker series I2C controller feature. Support dual role and at most one slave at one time Signed-off-by: cyliang tw --- drivers/i2c/CMakeLists.txt | 1 + drivers/i2c/Kconfig | 1 + drivers/i2c/Kconfig.numaker | 14 + drivers/i2c/i2c_numaker.c | 784 ++++++++++++++++++++++ dts/arm/nuvoton/m46x.dtsi | 61 ++ dts/bindings/i2c/nuvoton,numaker-i2c.yaml | 21 + 6 files changed, 882 insertions(+) create mode 100644 drivers/i2c/Kconfig.numaker create mode 100644 drivers/i2c/i2c_numaker.c create mode 100644 dts/bindings/i2c/nuvoton,numaker-i2c.yaml diff --git a/drivers/i2c/CMakeLists.txt b/drivers/i2c/CMakeLists.txt index f7f363ed8d4..406ce5dd4c5 100644 --- a/drivers/i2c/CMakeLists.txt +++ b/drivers/i2c/CMakeLists.txt @@ -55,6 +55,7 @@ zephyr_library_sources_ifdef(CONFIG_I2C_MCHP_MSS i2c_mchp_mss.c) zephyr_library_sources_ifdef(CONFIG_I2C_SEDI i2c_sedi.c) zephyr_library_sources_ifdef(CONFIG_I2C_AMBIQ i2c_ambiq.c) zephyr_library_sources_ifdef(CONFIG_GPIO_I2C_SWITCH gpio_i2c_switch.c) +zephyr_library_sources_ifdef(CONFIG_I2C_NUMAKER i2c_numaker.c) zephyr_library_sources_ifdef(CONFIG_I2C_STM32_V1 i2c_ll_stm32_v1.c diff --git a/drivers/i2c/Kconfig b/drivers/i2c/Kconfig index 233879167c6..b486977fbb0 100644 --- a/drivers/i2c/Kconfig +++ b/drivers/i2c/Kconfig @@ -92,6 +92,7 @@ source "drivers/i2c/Kconfig.xilinx_axi" source "drivers/i2c/Kconfig.mchp_mss" source "drivers/i2c/Kconfig.sedi" source "drivers/i2c/Kconfig.ambiq" +source "drivers/i2c/Kconfig.numaker" config I2C_INIT_PRIORITY int "Init priority" diff --git a/drivers/i2c/Kconfig.numaker b/drivers/i2c/Kconfig.numaker new file mode 100644 index 00000000000..622592cd020 --- /dev/null +++ b/drivers/i2c/Kconfig.numaker @@ -0,0 +1,14 @@ +# NUMAKER I2C driver configuration options + +# Copyright (c) 2023 Nuvoton Technology Corporation +# SPDX-License-Identifier: Apache-2.0 + +config I2C_NUMAKER + bool "Nuvoton NuMaker I2C driver" + default y + select HAS_NUMAKER_I2C + depends on DT_HAS_NUVOTON_NUMAKER_I2C_ENABLED + help + This option enables I2C driver for Nuvoton NuMaker family of + processors. + Say y if you wish to enable NuMaker I2C. diff --git a/drivers/i2c/i2c_numaker.c b/drivers/i2c/i2c_numaker.c new file mode 100644 index 00000000000..0c856015660 --- /dev/null +++ b/drivers/i2c/i2c_numaker.c @@ -0,0 +1,784 @@ +/* + * Copyright (c) 2023 Nuvoton Technology Corporation. + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#define DT_DRV_COMPAT nuvoton_numaker_i2c + +#include +#include +#include +#include +#include +#include + +LOG_MODULE_REGISTER(i2c_numaker, CONFIG_I2C_LOG_LEVEL); + +#include "i2c-priv.h" +#include +#include + +/* i2c Master Mode Status */ +#define M_START 0x08 /* Start */ +#define M_REPEAT_START 0x10 /* Master Repeat Start */ +#define M_TRAN_ADDR_ACK 0x18 /* Master Transmit Address ACK */ +#define M_TRAN_ADDR_NACK 0x20 /* Master Transmit Address NACK */ +#define M_TRAN_DATA_ACK 0x28 /* Master Transmit Data ACK */ +#define M_TRAN_DATA_NACK 0x30 /* Master Transmit Data NACK */ +#define M_ARB_LOST 0x38 /* Master Arbitration Los */ +#define M_RECE_ADDR_ACK 0x40 /* Master Receive Address ACK */ +#define M_RECE_ADDR_NACK 0x48 /* Master Receive Address NACK */ +#define M_RECE_DATA_ACK 0x50 /* Master Receive Data ACK */ +#define M_RECE_DATA_NACK 0x58 /* Master Receive Data NACK */ +#define BUS_ERROR 0x00 /* Bus error */ + +/* i2c Slave Mode Status */ +#define S_REPEAT_START_STOP 0xA0 /* Slave Transmit Repeat Start or Stop */ +#define S_TRAN_ADDR_ACK 0xA8 /* Slave Transmit Address ACK */ +#define S_TRAN_DATA_ACK 0xB8 /* Slave Transmit Data ACK */ +#define S_TRAN_DATA_NACK 0xC0 /* Slave Transmit Data NACK */ +#define S_TRAN_LAST_DATA_ACK 0xC8 /* Slave Transmit Last Data ACK */ +#define S_RECE_ADDR_ACK 0x60 /* Slave Receive Address ACK */ +#define S_RECE_ARB_LOST 0x68 /* Slave Receive Arbitration Lost */ +#define S_RECE_DATA_ACK 0x80 /* Slave Receive Data ACK */ +#define S_RECE_DATA_NACK 0x88 /* Slave Receive Data NACK */ + +/* i2c GC Mode Status */ +#define GC_ADDR_ACK 0x70 /* GC mode Address ACK */ +#define GC_ARB_LOST 0x78 /* GC mode Arbitration Lost */ +#define GC_DATA_ACK 0x90 /* GC mode Data ACK */ +#define GC_DATA_NACK 0x98 /* GC mode Data NACK */ + +/* i2c Other Status */ +#define ADDR_TRAN_ARB_LOST 0xB0 /* Address Transmit Arbitration Lost */ +#define BUS_RELEASED 0xF8 /* Bus Released */ + +struct i2c_numaker_config { + I2C_T *i2c_base; + const struct reset_dt_spec reset; + uint32_t clk_modidx; + uint32_t clk_src; + uint32_t clk_div; + const struct device *clkctrl_dev; + uint32_t irq_n; + void (*irq_config_func)(const struct device *dev); + const struct pinctrl_dev_config *pincfg; + uint32_t bitrate; +}; + +struct i2c_numaker_data { + struct k_sem lock; + uint32_t dev_config; + /* Master transfer context */ + struct { + struct k_sem xfer_sync; + uint16_t addr; + struct i2c_msg *msgs_beg; + struct i2c_msg *msgs_pos; + struct i2c_msg *msgs_end; + uint8_t *buf_beg; + uint8_t *buf_pos; + uint8_t *buf_end; + } master_xfer; +#ifdef CONFIG_I2C_TARGET + /* Slave transfer context */ + struct { + struct i2c_target_config *slave_config; + bool slave_addressed; + } slave_xfer; +#endif +}; + +/* ACK/NACK last data byte, dependent on whether or not message merge is allowed */ +static void m_numaker_i2c_master_xfer_msg_read_last_byte(const struct device *dev) +{ + const struct i2c_numaker_config *config = dev->config; + struct i2c_numaker_data *data = dev->data; + I2C_T *i2c_base = config->i2c_base; + + /* Shouldn't invoke with message pointer OOB */ + __ASSERT_NO_MSG(data->master_xfer.msgs_pos < data->master_xfer.msgs_end); + /* Should invoke with exactly one data byte remaining for read */ + __ASSERT_NO_MSG((data->master_xfer.msgs_pos->flags & I2C_MSG_RW_MASK) == I2C_MSG_READ); + __ASSERT_NO_MSG((data->master_xfer.buf_end - data->master_xfer.buf_pos) == 1); + + /* Flags of previous message */ + bool do_stop_prev = data->master_xfer.msgs_pos->flags & I2C_MSG_STOP; + + /* Advance to next messages temporarily */ + data->master_xfer.msgs_pos++; + + /* Has next message? */ + if (data->master_xfer.msgs_pos < data->master_xfer.msgs_end) { + /* Flags of next message */ + struct i2c_msg *msgs_pos = data->master_xfer.msgs_pos; + bool is_read_next = (msgs_pos->flags & I2C_MSG_RW_MASK) == I2C_MSG_READ; + bool do_restart_next = data->master_xfer.msgs_pos->flags & I2C_MSG_RESTART; + + /* + * Different R/W bit so message merge is disallowed. + * Force I2C Repeat Start on I2C Stop/Repeat Start missing + */ + if (!is_read_next) { + if (!do_stop_prev && !do_restart_next) { + do_restart_next = true; + } + } + + if (do_stop_prev || do_restart_next) { + /* NACK last data byte (required for Master Receiver) */ + I2C_SET_CONTROL_REG(i2c_base, I2C_CTL0_SI_Msk); + } else { + /* ACK last data byte, so to merge adjacent messages into one transaction */ + I2C_SET_CONTROL_REG(i2c_base, I2C_CTL0_SI_Msk | I2C_CTL0_AA_Msk); + } + } else { + /* NACK last data byte (required for Master Receiver) */ + I2C_SET_CONTROL_REG(i2c_base, I2C_CTL0_SI_Msk); + } + + /* Roll back message pointer */ + data->master_xfer.msgs_pos--; +} + +/* End the transfer, involving I2C Stop and signal to thread */ +static void m_numaker_i2c_master_xfer_end(const struct device *dev, bool do_stop) +{ + const struct i2c_numaker_config *config = dev->config; + struct i2c_numaker_data *data = dev->data; + I2C_T *i2c_base = config->i2c_base; + + if (do_stop) { + /* Do I2C Stop */ + I2C_SET_CONTROL_REG(i2c_base, I2C_CTL0_STO_Msk | I2C_CTL0_SI_Msk); + } + + /* Signal master transfer end */ + k_sem_give(&data->master_xfer.xfer_sync); +} + +static void m_numaker_i2c_master_xfer_msg_end(const struct device *dev); +/* Read next data byte, involving ACK/NACK last data byte and message merge */ +static void m_numaker_i2c_master_xfer_msg_read_next_byte(const struct device *dev) +{ + const struct i2c_numaker_config *config = dev->config; + struct i2c_numaker_data *data = dev->data; + I2C_T *i2c_base = config->i2c_base; + + switch (data->master_xfer.buf_end - data->master_xfer.buf_pos) { + case 0: + /* Last data byte ACKed, we'll do message merge */ + m_numaker_i2c_master_xfer_msg_end(dev); + break; + case 1: + /* Read last data byte for this message */ + m_numaker_i2c_master_xfer_msg_read_last_byte(dev); + break; + default: + /* ACK non-last data byte */ + I2C_SET_CONTROL_REG(i2c_base, I2C_CTL0_SI_Msk | I2C_CTL0_AA_Msk); + } +} + +/* End one message transfer, involving message merge and transfer end */ +static void m_numaker_i2c_master_xfer_msg_end(const struct device *dev) +{ + const struct i2c_numaker_config *config = dev->config; + struct i2c_numaker_data *data = dev->data; + I2C_T *i2c_base = config->i2c_base; + + /* Shouldn't invoke with message pointer OOB */ + __ASSERT_NO_MSG(data->master_xfer.msgs_pos < data->master_xfer.msgs_end); + /* Should have transferred up */ + __ASSERT_NO_MSG((data->master_xfer.buf_end - data->master_xfer.buf_pos) == 0); + + /* Flags of previous message */ + bool is_read_prev = (data->master_xfer.msgs_pos->flags & I2C_MSG_RW_MASK) == I2C_MSG_READ; + bool do_stop_prev = data->master_xfer.msgs_pos->flags & I2C_MSG_STOP; + + /* Advance to next messages */ + data->master_xfer.msgs_pos++; + + /* Has next message? */ + if (data->master_xfer.msgs_pos < data->master_xfer.msgs_end) { + /* Flags of next message */ + struct i2c_msg *msgs_pos = data->master_xfer.msgs_pos; + bool is_read_next = (msgs_pos->flags & I2C_MSG_RW_MASK) == I2C_MSG_READ; + bool do_restart_next = data->master_xfer.msgs_pos->flags & I2C_MSG_RESTART; + + /* + * Different R/W bit so message merge is disallowed. + * Force I2C Repeat Start on I2C Stop/Repeat Start missing + */ + if (!is_read_prev != !is_read_next) { /* Logical XOR idiom */ + if (!do_stop_prev && !do_restart_next) { + LOG_WRN("Cannot merge adjacent messages, force I2C Repeat Start"); + do_restart_next = true; + } + } + + if (do_stop_prev) { + /* Do I2C Stop and then Start */ + I2C_SET_CONTROL_REG(i2c_base, I2C_CTL0_STA_Msk | + I2C_CTL0_STO_Msk | I2C_CTL0_SI_Msk); + } else if (do_restart_next) { + /* Do I2C Repeat Start */ + I2C_SET_CONTROL_REG(i2c_base, I2C_CTL0_STA_Msk | I2C_CTL0_SI_Msk); + } else { + /* Merge into the same transaction */ + + /* Prepare buffer for current message */ + data->master_xfer.buf_beg = data->master_xfer.msgs_pos->buf; + data->master_xfer.buf_pos = data->master_xfer.msgs_pos->buf; + data->master_xfer.buf_end = data->master_xfer.msgs_pos->buf + + data->master_xfer.msgs_pos->len; + + if (is_read_prev) { + m_numaker_i2c_master_xfer_msg_read_next_byte(dev); + } else { + /* + * Interrupt flag not cleared, expect to re-enter ISR with + * context unchanged, except buffer changed for message change. + */ + } + } + } else { + if (!do_stop_prev) { + LOG_WRN("Last message not marked I2C Stop"); + } + + m_numaker_i2c_master_xfer_end(dev, do_stop_prev); + } +} + +static int i2c_numaker_configure(const struct device *dev, uint32_t dev_config) +{ + const struct i2c_numaker_config *config = dev->config; + struct i2c_numaker_data *data = dev->data; + uint32_t bitrate; + + /* Check address size */ + if (dev_config & I2C_ADDR_10_BITS) { + LOG_ERR("10-bits address not supported"); + return -ENOTSUP; + } + + switch (I2C_SPEED_GET(dev_config)) { + case I2C_SPEED_STANDARD: + bitrate = KHZ(100); + break; + case I2C_SPEED_FAST: + bitrate = KHZ(400); + break; + case I2C_SPEED_FAST_PLUS: + bitrate = MHZ(1); + break; + default: + LOG_ERR("Speed code %d not supported", I2C_SPEED_GET(dev_config)); + return -ENOTSUP; + } + + I2C_T *i2c_base = config->i2c_base; + int err = 0; + + k_sem_take(&data->lock, K_FOREVER); + irq_disable(config->irq_n); + +#ifdef CONFIG_I2C_TARGET + if (data->slave_xfer.slave_addressed) { + LOG_ERR("Reconfigure with slave being busy"); + err = -EBUSY; + goto done; + } +#endif + + I2C_Open(i2c_base, bitrate); + /* INTEN bit and FSM control bits (STA, STO, SI, AA) are packed in one register CTL0. */ + i2c_base->CTL0 |= (I2C_CTL0_INTEN_Msk | I2C_CTL0_I2CEN_Msk); + data->dev_config = dev_config; + +done: + + irq_enable(config->irq_n); + k_sem_give(&data->lock); + + return err; +} + +static int i2c_numaker_get_config(const struct device *dev, uint32_t *dev_config) +{ + struct i2c_numaker_data *data = dev->data; + + if (!dev_config) { + return -EINVAL; + } + + k_sem_take(&data->lock, K_FOREVER); + *dev_config = data->dev_config; + k_sem_give(&data->lock); + + return 0; +} + +/* + * Master active transfer: + * 1. Do I2C Start to start the transfer (thread) + * 2. I2C FSM (ISR) + * 3. Force I2C Stop to end the transfer (thread) + * Slave passive transfer: + * 1. Prepare callback (thread) + * 2. Do data transfer via above callback (ISR) + */ +static int i2c_numaker_transfer(const struct device *dev, struct i2c_msg *msgs, + uint8_t num_msgs, uint16_t addr) +{ + const struct i2c_numaker_config *config = dev->config; + struct i2c_numaker_data *data = dev->data; + I2C_T *i2c_base = config->i2c_base; + int err = 0; + + k_sem_take(&data->lock, K_FOREVER); + irq_disable(config->irq_n); + + if (data->slave_xfer.slave_addressed) { + LOG_ERR("Master transfer with slave being busy"); + err = -EBUSY; + goto cleanup; + } + + if (num_msgs == 0) { + goto cleanup; + } + + /* Prepare to start transfer */ + data->master_xfer.addr = addr; + data->master_xfer.msgs_beg = msgs; + data->master_xfer.msgs_pos = msgs; + data->master_xfer.msgs_end = msgs + num_msgs; + + /* Do I2C Start to start the transfer */ + I2C_SET_CONTROL_REG(i2c_base, I2C_CTL0_STA_Msk | I2C_CTL0_SI_Msk); + + irq_enable(config->irq_n); + k_sem_take(&data->master_xfer.xfer_sync, K_FOREVER); + irq_disable(config->irq_n); + + /* Check transfer result */ + if (data->master_xfer.msgs_pos != data->master_xfer.msgs_end) { + bool is_read; + bool is_10bit; + + is_read = (data->master_xfer.msgs_pos->flags & I2C_MSG_RW_MASK) == I2C_MSG_READ; + is_10bit = data->master_xfer.msgs_pos->flags & I2C_MSG_ADDR_10_BITS; + LOG_ERR("Failed message:"); + LOG_ERR("MSG IDX: %d", data->master_xfer.msgs_pos - data->master_xfer.msgs_beg); + LOG_ERR("ADDR (%d-bit): 0x%04X", is_10bit ? 10 : 7, addr); + LOG_ERR("DIR: %s", is_read ? "R" : "W"); + LOG_ERR("Expected %d bytes transferred, but actual %d", + data->master_xfer.msgs_pos->len, + data->master_xfer.buf_pos - data->master_xfer.buf_beg); + err = -EIO; + goto i2c_stop; + } + +i2c_stop: + + /* Do I2C Stop to release bus ownership */ + I2C_SET_CONTROL_REG(i2c_base, I2C_CTL0_STO_Msk | I2C_CTL0_SI_Msk); + +#ifdef CONFIG_I2C_TARGET + /* Enable slave mode if one slave is registered */ + if (data->slave_xfer.slave_config) { + I2C_SET_CONTROL_REG(i2c_base, I2C_CTL0_SI_Msk | I2C_CTL0_AA_Msk); + } +#endif + +cleanup: + + irq_enable(config->irq_n); + k_sem_give(&data->lock); + + return err; +} + +#ifdef CONFIG_I2C_TARGET +static int i2c_numaker_slave_register(const struct device *dev, + struct i2c_target_config *slave_config) +{ + if (!slave_config || !slave_config->callbacks) { + return -EINVAL; + } + + if (slave_config->flags & I2C_ADDR_10_BITS) { + LOG_ERR("10-bits address not supported"); + return -ENOTSUP; + } + + const struct i2c_numaker_config *config = dev->config; + struct i2c_numaker_data *data = dev->data; + I2C_T *i2c_base = config->i2c_base; + int err = 0; + + k_sem_take(&data->lock, K_FOREVER); + irq_disable(config->irq_n); + + if (data->slave_xfer.slave_config) { + err = -EBUSY; + goto cleanup; + } + + data->slave_xfer.slave_config = slave_config; + /* Slave address */ + I2C_SetSlaveAddr(i2c_base, + 0, + slave_config->address, + I2C_GCMODE_DISABLE); + + /* Slave address state */ + data->slave_xfer.slave_addressed = false; + + /* Enable slave mode */ + I2C_SET_CONTROL_REG(i2c_base, I2C_CTL0_SI_Msk | I2C_CTL0_AA_Msk); + +cleanup: + + irq_enable(config->irq_n); + k_sem_give(&data->lock); + + return err; +} + +static int i2c_numaker_slave_unregister(const struct device *dev, + struct i2c_target_config *slave_config) +{ + const struct i2c_numaker_config *config = dev->config; + struct i2c_numaker_data *data = dev->data; + I2C_T *i2c_base = config->i2c_base; + int err = 0; + + if (!slave_config) { + return -EINVAL; + } + + k_sem_take(&data->lock, K_FOREVER); + irq_disable(config->irq_n); + + if (data->slave_xfer.slave_config != slave_config) { + err = -EINVAL; + goto cleanup; + } + + if (data->slave_xfer.slave_addressed) { + LOG_ERR("Unregister slave driver with slave being busy"); + err = -EBUSY; + goto cleanup; + } + + /* Slave address: Zero */ + I2C_SetSlaveAddr(i2c_base, + 0, + 0, + I2C_GCMODE_DISABLE); + + /* Slave address state */ + data->slave_xfer.slave_addressed = false; + + /* Disable slave mode */ + I2C_SET_CONTROL_REG(i2c_base, I2C_CTL0_SI_Msk); + data->slave_xfer.slave_config = NULL; + +cleanup: + + irq_enable(config->irq_n); + k_sem_give(&data->lock); + + return err; +} +#endif + +static int i2c_numaker_recover_bus(const struct device *dev) +{ + const struct i2c_numaker_config *config = dev->config; + struct i2c_numaker_data *data = dev->data; + I2C_T *i2c_base = config->i2c_base; + + k_sem_take(&data->lock, K_FOREVER); + /* Do I2C Stop to release bus ownership */ + I2C_SET_CONTROL_REG(i2c_base, I2C_CTL0_STO_Msk | I2C_CTL0_SI_Msk); + k_sem_give(&data->lock); + + return 0; +} + +static void i2c_numaker_isr(const struct device *dev) +{ + const struct i2c_numaker_config *config = dev->config; + struct i2c_numaker_data *data = dev->data; + I2C_T *i2c_base = config->i2c_base; +#ifdef CONFIG_I2C_TARGET + struct i2c_target_config *slave_config = data->slave_xfer.slave_config; + const struct i2c_target_callbacks *slave_callbacks = + slave_config ? slave_config->callbacks : NULL; + uint8_t data_byte; +#endif + uint32_t status; + + if (I2C_GET_TIMEOUT_FLAG(i2c_base)) { + I2C_ClearTimeoutFlag(i2c_base); + return; + } + + status = I2C_GET_STATUS(i2c_base); + + switch (status) { + case M_START: /* Start */ + case M_REPEAT_START: /* Master Repeat Start */ + /* Prepare buffer for current message */ + data->master_xfer.buf_beg = data->master_xfer.msgs_pos->buf; + data->master_xfer.buf_pos = data->master_xfer.msgs_pos->buf; + data->master_xfer.buf_end = data->master_xfer.msgs_pos->buf + + data->master_xfer.msgs_pos->len; + + /* Write I2C address */ + struct i2c_msg *msgs_pos = data->master_xfer.msgs_pos; + bool is_read = (msgs_pos->flags & I2C_MSG_RW_MASK) == I2C_MSG_READ; + uint16_t addr = data->master_xfer.addr; + int addr_rw = is_read ? ((addr << 1) | 1) : (addr << 1); + + I2C_SET_DATA(i2c_base, (uint8_t) (addr_rw & 0xFF)); + I2C_SET_CONTROL_REG(i2c_base, I2C_CTL0_SI_Msk); + break; + case M_TRAN_ADDR_ACK: /* Master Transmit Address ACK */ + case M_TRAN_DATA_ACK: /* Master Transmit Data ACK */ + __ASSERT_NO_MSG(data->master_xfer.buf_pos); + if (data->master_xfer.buf_pos < data->master_xfer.buf_end) { + I2C_SET_DATA(i2c_base, *data->master_xfer.buf_pos++); + I2C_SET_CONTROL_REG(i2c_base, I2C_CTL0_SI_Msk | I2C_CTL0_AA_Msk); + } else { + /* End this message */ + m_numaker_i2c_master_xfer_msg_end(dev); + } + break; + case M_TRAN_ADDR_NACK: /* Master Transmit Address NACK */ + case M_TRAN_DATA_NACK: /* Master Transmit Data NACK */ + case M_RECE_ADDR_NACK: /* Master Receive Address NACK */ + case M_ARB_LOST: /* Master Arbitration Lost */ + m_numaker_i2c_master_xfer_end(dev, true); + break; + case M_RECE_ADDR_ACK: /* Master Receive Address ACK */ + case M_RECE_DATA_ACK: /* Master Receive Data ACK */ + __ASSERT_NO_MSG(data->master_xfer.buf_pos); + + if (status == M_RECE_ADDR_ACK) { + __ASSERT_NO_MSG(data->master_xfer.buf_pos < data->master_xfer.buf_end); + } else if (status == M_RECE_DATA_ACK) { + __ASSERT_NO_MSG((data->master_xfer.buf_end - + data->master_xfer.buf_pos) >= 1); + *data->master_xfer.buf_pos++ = I2C_GET_DATA(i2c_base); + } + + m_numaker_i2c_master_xfer_msg_read_next_byte(dev); + break; + case M_RECE_DATA_NACK: /* Master Receive Data NACK */ + __ASSERT_NO_MSG((data->master_xfer.buf_end - data->master_xfer.buf_pos) == 1); + *data->master_xfer.buf_pos++ = I2C_GET_DATA(i2c_base); + /* End this message */ + m_numaker_i2c_master_xfer_msg_end(dev); + break; + case BUS_ERROR: /* Bus error */ + m_numaker_i2c_master_xfer_end(dev, true); + break; +#ifdef CONFIG_I2C_TARGET + /* NOTE: Don't disable interrupt here because slave mode relies on */ + /* for passive transfer in ISR. */ + + /* Slave Transmit */ + case S_TRAN_ADDR_ACK: /* Slave Transmit Address ACK */ + case ADDR_TRAN_ARB_LOST: /* Slave Transmit Arbitration Lost */ + data->slave_xfer.slave_addressed = true; + if (slave_callbacks->read_requested(slave_config, &data_byte) == 0) { + /* Non-last data byte */ + I2C_SET_DATA(i2c_base, data_byte); + I2C_SET_CONTROL_REG(i2c_base, I2C_CTL0_SI_Msk | I2C_CTL0_AA_Msk); + } else { + /* Go S_TRAN_LAST_DATA_ACK on error */ + I2C_SET_DATA(i2c_base, 0xFF); + I2C_SET_CONTROL_REG(i2c_base, I2C_CTL0_SI_Msk); + } + break; + case S_TRAN_DATA_ACK: /* Slave Transmit Data ACK */ + if (slave_callbacks->read_processed(slave_config, &data_byte) == 0) { + /* Non-last data byte */ + I2C_SET_DATA(i2c_base, data_byte); + I2C_SET_CONTROL_REG(i2c_base, I2C_CTL0_SI_Msk | I2C_CTL0_AA_Msk); + } else { + /* Go S_TRAN_LAST_DATA_ACK on error */ + I2C_SET_DATA(i2c_base, 0xFF); + I2C_SET_CONTROL_REG(i2c_base, I2C_CTL0_SI_Msk); + } + break; + case S_TRAN_DATA_NACK: /* Slave Transmit Data NACK */ + case S_TRAN_LAST_DATA_ACK: /* Slave Transmit Last Data ACK */ + /* Go slave end */ + data->slave_xfer.slave_addressed = false; + slave_callbacks->stop(slave_config); + I2C_SET_CONTROL_REG(i2c_base, I2C_CTL0_SI_Msk | I2C_CTL0_AA_Msk); + break; + /* Slave Receive */ + case S_RECE_DATA_ACK: /* Slave Receive Data ACK */ + data_byte = I2C_GET_DATA(i2c_base); + if (slave_callbacks->write_received(slave_config, data_byte) == 0) { + /* Write OK, ACK next data byte */ + I2C_SET_CONTROL_REG(i2c_base, I2C_CTL0_SI_Msk | I2C_CTL0_AA_Msk); + } else { + /* Write FAILED, NACK next data byte */ + I2C_SET_CONTROL_REG(i2c_base, I2C_CTL0_SI_Msk); + } + break; + case S_RECE_DATA_NACK: /* Slave Receive Data NACK */ + /* Go slave end */ + data->slave_xfer.slave_addressed = false; + slave_callbacks->stop(slave_config); + I2C_SET_CONTROL_REG(i2c_base, I2C_CTL0_SI_Msk | I2C_CTL0_AA_Msk); + break; + case S_RECE_ADDR_ACK: /* Slave Receive Address ACK */ + case S_RECE_ARB_LOST: /* Slave Receive Arbitration Lost */ + data->slave_xfer.slave_addressed = true; + if (slave_callbacks->write_requested(slave_config) == 0) { + /* Write ready, ACK next byte */ + I2C_SET_CONTROL_REG(i2c_base, I2C_CTL0_SI_Msk | I2C_CTL0_AA_Msk); + } else { + /* Write not ready, NACK next byte */ + I2C_SET_CONTROL_REG(i2c_base, I2C_CTL0_SI_Msk); + } + break; + case S_REPEAT_START_STOP: /* Slave Transmit/Receive Repeat Start or Stop */ + /* Go slave end */ + data->slave_xfer.slave_addressed = false; + slave_callbacks->stop(slave_config); + I2C_SET_CONTROL_REG(i2c_base, I2C_CTL0_SI_Msk | I2C_CTL0_AA_Msk); + break; +#endif /* CONFIG_I2C_TARGET */ + + case BUS_RELEASED: /* Bus Released */ + /* Ignore the interrupt raised by BUS_RELEASED. */ + break; + default: + __ASSERT(false, "Uncaught I2C FSM state"); + m_numaker_i2c_master_xfer_end(dev, true); + } +} + +static int i2c_numaker_init(const struct device *dev) +{ + const struct i2c_numaker_config *config = dev->config; + struct i2c_numaker_data *data = dev->data; + int err = 0; + struct numaker_scc_subsys scc_subsys; + + /* Validate this module's reset object */ + if (!device_is_ready(config->reset.dev)) { + LOG_ERR("reset controller not ready"); + return -ENODEV; + } + + /* Clean mutable context */ + memset(data, 0x00, sizeof(*data)); + + k_sem_init(&data->lock, 1, 1); + k_sem_init(&data->master_xfer.xfer_sync, 0, 1); + + SYS_UnlockReg(); + + memset(&scc_subsys, 0x00, sizeof(scc_subsys)); + scc_subsys.subsys_id = NUMAKER_SCC_SUBSYS_ID_PCC; + scc_subsys.pcc.clk_modidx = config->clk_modidx; + scc_subsys.pcc.clk_src = config->clk_src; + scc_subsys.pcc.clk_div = config->clk_div; + + /* Equivalent to CLK_EnableModuleClock() */ + err = clock_control_on(config->clkctrl_dev, (clock_control_subsys_t) &scc_subsys); + if (err != 0) { + goto cleanup; + } + /* Equivalent to CLK_SetModuleClock() */ + err = clock_control_configure(config->clkctrl_dev, + (clock_control_subsys_t) &scc_subsys, + NULL); + if (err != 0) { + goto cleanup; + } + + /* Configure pinmux (NuMaker's SYS MFP) */ + err = pinctrl_apply_state(config->pincfg, PINCTRL_STATE_DEFAULT); + if (err != 0) { + goto cleanup; + } + + /* Reset I2C to default state, same as BSP's SYS_ResetModule(id_rst) */ + reset_line_toggle_dt(&config->reset); + + err = i2c_numaker_configure(dev, I2C_MODE_CONTROLLER | i2c_map_dt_bitrate(config->bitrate)); + if (err != 0) { + goto cleanup; + } + + config->irq_config_func(dev); + +cleanup: + + SYS_LockReg(); + return err; +} + +static const struct i2c_driver_api i2c_numaker_driver_api = { + .configure = i2c_numaker_configure, + .get_config = i2c_numaker_get_config, + .transfer = i2c_numaker_transfer, +#ifdef CONFIG_I2C_TARGET + .target_register = i2c_numaker_slave_register, + .target_unregister = i2c_numaker_slave_unregister, +#endif + .recover_bus = i2c_numaker_recover_bus, +}; + +#define I2C_NUMAKER_INIT(inst) \ + PINCTRL_DT_INST_DEFINE(inst); \ + \ + static void i2c_numaker_irq_config_func_##inst(const struct device *dev) \ + { \ + IRQ_CONNECT(DT_INST_IRQN(inst), \ + DT_INST_IRQ(inst, priority), \ + i2c_numaker_isr, \ + DEVICE_DT_INST_GET(inst), \ + 0); \ + \ + irq_enable(DT_INST_IRQN(inst)); \ + } \ + \ + static const struct i2c_numaker_config i2c_numaker_config_##inst = { \ + .i2c_base = (I2C_T *) DT_INST_REG_ADDR(inst), \ + .reset = RESET_DT_SPEC_INST_GET(inst), \ + .clk_modidx = DT_INST_CLOCKS_CELL(inst, clock_module_index), \ + .clk_src = DT_INST_CLOCKS_CELL(inst, clock_source), \ + .clk_div = DT_INST_CLOCKS_CELL(inst, clock_divider), \ + .clkctrl_dev = DEVICE_DT_GET(DT_PARENT(DT_INST_CLOCKS_CTLR(inst))),\ + .irq_n = DT_INST_IRQN(inst), \ + .irq_config_func = i2c_numaker_irq_config_func_##inst, \ + .pincfg = PINCTRL_DT_INST_DEV_CONFIG_GET(inst), \ + .bitrate = DT_INST_PROP(inst, clock_frequency), \ + }; \ + \ + static struct i2c_numaker_data i2c_numaker_data_##inst; \ + \ + I2C_DEVICE_DT_INST_DEFINE(inst, \ + i2c_numaker_init, \ + NULL, \ + &i2c_numaker_data_##inst, \ + &i2c_numaker_config_##inst, \ + POST_KERNEL, \ + CONFIG_I2C_INIT_PRIORITY, \ + &i2c_numaker_driver_api); + +DT_INST_FOREACH_STATUS_OKAY(I2C_NUMAKER_INIT); diff --git a/dts/arm/nuvoton/m46x.dtsi b/dts/arm/nuvoton/m46x.dtsi index 3e6efbb1745..bb0b95c4c80 100644 --- a/dts/arm/nuvoton/m46x.dtsi +++ b/dts/arm/nuvoton/m46x.dtsi @@ -10,6 +10,7 @@ #include #include #include +#include / { chosen { @@ -502,6 +503,66 @@ clocks = <&pcc NUMAKER_EMAC0_MODULE 0 0>; status = "disabled"; }; + + i2c0: i2c@40080000 { + compatible = "nuvoton,numaker-i2c"; + clock-frequency = ; + reg = <0x40080000 0x1000>; + interrupts = <38 0>; + resets = <&rst NUMAKER_I2C0_RST>; + clocks = <&pcc NUMAKER_I2C0_MODULE 0 0>; + status = "disabled"; + #address-cells = <1>; + #size-cells = <0>; + }; + + i2c1: i2c@40081000 { + compatible = "nuvoton,numaker-i2c"; + clock-frequency = ; + reg = <0x40081000 0x1000>; + interrupts = <39 0>; + resets = <&rst NUMAKER_I2C1_RST>; + clocks = <&pcc NUMAKER_I2C1_MODULE 0 0>; + status = "disabled"; + #address-cells = <1>; + #size-cells = <0>; + }; + + i2c2: i2c@40082000 { + compatible = "nuvoton,numaker-i2c"; + clock-frequency = ; + reg = <0x40082000 0x1000>; + interrupts = <82 0>; + resets = <&rst NUMAKER_I2C2_RST>; + clocks = <&pcc NUMAKER_I2C2_MODULE 0 0>; + status = "disabled"; + #address-cells = <1>; + #size-cells = <0>; + }; + + i2c3: i2c@40083000 { + compatible = "nuvoton,numaker-i2c"; + clock-frequency = ; + reg = <0x40083000 0x1000>; + interrupts = <83 0>; + resets = <&rst NUMAKER_I2C3_RST>; + clocks = <&pcc NUMAKER_I2C3_MODULE 0 0>; + status = "disabled"; + #address-cells = <1>; + #size-cells = <0>; + }; + + i2c4: i2c@40084000 { + compatible = "nuvoton,numaker-i2c"; + clock-frequency = ; + reg = <0x40084000 0x1000>; + interrupts = <118 0>; + resets = <&rst NUMAKER_I2C4_RST>; + clocks = <&pcc NUMAKER_I2C4_MODULE 0 0>; + status = "disabled"; + #address-cells = <1>; + #size-cells = <0>; + }; }; }; diff --git a/dts/bindings/i2c/nuvoton,numaker-i2c.yaml b/dts/bindings/i2c/nuvoton,numaker-i2c.yaml new file mode 100644 index 00000000000..5ba876448c1 --- /dev/null +++ b/dts/bindings/i2c/nuvoton,numaker-i2c.yaml @@ -0,0 +1,21 @@ +# Copyright (c) 2023 Nuvoton Technology Corporation +# SPDX-License-Identifier: Apache-2.0 + +description: Nuvoton, NuMaker I2C controller + +compatible: "nuvoton,numaker-i2c" + +include: [i2c-controller.yaml, reset-device.yaml, pinctrl-device.yaml] + +properties: + reg: + required: true + + interrupts: + required: true + + resets: + required: true + + clocks: + required: true From c07156ef3c70bd798ff5f6eb728594acf30c5d9d Mon Sep 17 00:00:00 2001 From: cyliang tw Date: Fri, 24 Nov 2023 14:55:27 +0800 Subject: [PATCH 0269/3723] tests: drivers: i2c: i2c_target_api: support numaker_pfm_m467 Add support for Nuvoton numaker board numaker_pfm_m467. Signed-off-by: cyliang tw --- .../boards/numaker_pfm_m467.conf | 2 + .../boards/numaker_pfm_m467.overlay | 41 +++++++++++++++++++ 2 files changed, 43 insertions(+) create mode 100644 tests/drivers/i2c/i2c_target_api/boards/numaker_pfm_m467.conf create mode 100644 tests/drivers/i2c/i2c_target_api/boards/numaker_pfm_m467.overlay diff --git a/tests/drivers/i2c/i2c_target_api/boards/numaker_pfm_m467.conf b/tests/drivers/i2c/i2c_target_api/boards/numaker_pfm_m467.conf new file mode 100644 index 00000000000..f3d64527b85 --- /dev/null +++ b/tests/drivers/i2c/i2c_target_api/boards/numaker_pfm_m467.conf @@ -0,0 +1,2 @@ +CONFIG_I2C=y +CONFIG_I2C_TARGET=y diff --git a/tests/drivers/i2c/i2c_target_api/boards/numaker_pfm_m467.overlay b/tests/drivers/i2c/i2c_target_api/boards/numaker_pfm_m467.overlay new file mode 100644 index 00000000000..2d3d972b260 --- /dev/null +++ b/tests/drivers/i2c/i2c_target_api/boards/numaker_pfm_m467.overlay @@ -0,0 +1,41 @@ +/* SPDX-License-Identifier: Apache-2.0 */ + +&pinctrl { + i2c1_default: i2c1_default { + group0 { + pinmux = , /* UNO D0 */ + ; /* UNO D1 */ + }; + }; + + i2c3_default: i2c3_default { + group0 { + pinmux = , /* UNO D14 */ + ; /* UNO D15 */ + }; + }; +}; + +&i2c1 { + pinctrl-0 = <&i2c1_default>; + pinctrl-names = "default"; + status = "okay"; + + eeprom0: eeprom@54 { + compatible = "zephyr,i2c-target-eeprom"; + reg = <0x54>; + size = <1024>; + }; +}; + +&i2c3 { + pinctrl-0 = <&i2c3_default>; + pinctrl-names = "default"; + status = "okay"; + + eeprom1: eeprom@56 { + compatible = "zephyr,i2c-target-eeprom"; + reg = <0x56>; + size = <1024>; + }; +}; From 38118c24a3c6a0bf8724284819f7bc195ced8125 Mon Sep 17 00:00:00 2001 From: Maciej Baczmanski Date: Fri, 24 Nov 2023 09:42:32 +0100 Subject: [PATCH 0270/3723] MAINTAINERS: add myself as collaborator for openthread related repos Add maciejbaczmanski as collaborator for openthread repos. Signed-off-by: Maciej Baczmanski --- MAINTAINERS.yml | 2 ++ 1 file changed, 2 insertions(+) diff --git a/MAINTAINERS.yml b/MAINTAINERS.yml index 7309472c274..d9bcd2bb3c6 100644 --- a/MAINTAINERS.yml +++ b/MAINTAINERS.yml @@ -2185,6 +2185,7 @@ Networking: - canisLupus1313 - mariuszpos - edmont + - maciejbaczmanski files: - subsys/net/l2/openthread/ - samples/net/openthread/ @@ -3666,6 +3667,7 @@ West: - canisLupus1313 - mariuszpos - edmont + - maciejbaczmanski files: - modules/openthread/ labels: From c1656a4486cf8c469cb6c63d5e57f3eb0ad10910 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Benjamin=20Cab=C3=A9?= Date: Thu, 23 Nov 2023 14:21:31 +0100 Subject: [PATCH 0271/3723] doc: redirects: fix redirect for POSIX portability homepage MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Add a proper redirect for pre-3.5.99 POSIX portabiltity home page. Signed-off-by: Benjamin Cabé --- doc/_scripts/redirects.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/doc/_scripts/redirects.py b/doc/_scripts/redirects.py index 78c5c8ed84f..0394c7c016a 100644 --- a/doc/_scripts/redirects.py +++ b/doc/_scripts/redirects.py @@ -71,7 +71,6 @@ ('guides/pm/power_domain', 'services/pm/power_domain'), ('guides/pm/system', 'services/pm/system'), ('guides/portability/index', 'services/portability/index'), - ('guides/portability/posix', 'services/portability/posix/index'), ('guides/porting/arch', 'hardware/porting/arch'), ('guides/porting/board_porting', 'hardware/porting/board_porting'), ('guides/porting/index', 'hardware/porting/index'), @@ -165,4 +164,5 @@ ('reference/util/index', 'kernel/util/index'), ('samples/drivers/kscan_touch', 'samples/subsys/input/input'), ('samples/net/cloud/google_iot_mqtt', 'samples/net/cloud'), + ('services/portability/posix', 'services/portability/posix/index'), ] From 0bd03239ee6264aa607d39bea3fa49e0721723bf Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Benjamin=20Cab=C3=A9?= Date: Thu, 23 Nov 2023 15:23:52 +0100 Subject: [PATCH 0272/3723] MAINTAINERS: clean up POSIX area MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Ensure documentation related to POSIX portability matches POSIX area. Signed-off-by: Benjamin Cabé --- MAINTAINERS.yml | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/MAINTAINERS.yml b/MAINTAINERS.yml index d9bcd2bb3c6..7035252fa3b 100644 --- a/MAINTAINERS.yml +++ b/MAINTAINERS.yml @@ -473,7 +473,7 @@ CMSIS API layer: - include/zephyr/portability/cmsis* - samples/subsys/portability/cmsis_rtos_v*/ - tests/subsys/portability/cmsis_rtos_v*/ - - doc/services/portability/ + - doc/services/portability/cmsis* labels: - "area: CMSIS API Layer" - "area: Portability" @@ -2249,6 +2249,7 @@ POSIX API layer: - tests/posix/ - samples/posix/ - tests/lib/fdtable/ + - doc/services/portability/posix/ labels: - "area: POSIX" From 8d6421df046c2d62616eff8b97112c83bca78e5e Mon Sep 17 00:00:00 2001 From: Alberto Escolar Piedras Date: Thu, 23 Nov 2023 09:24:25 +0100 Subject: [PATCH 0273/3723] tests/subsys/emul: Enable for native_sim Enable this test which runs in native_posix in native_sim, Switch from native_posix to native_sim as default test platform Signed-off-by: Alberto Escolar Piedras --- tests/subsys/emul/testcase.yaml | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/tests/subsys/emul/testcase.yaml b/tests/subsys/emul/testcase.yaml index 94c2b906f8b..0cfebaf6325 100644 --- a/tests/subsys/emul/testcase.yaml +++ b/tests/subsys/emul/testcase.yaml @@ -1,4 +1,8 @@ tests: emul.emul: tags: emul - platform_allow: native_posix + platform_allow: + - native_posix + - native_sim + integration_platforms: + - native_sim From 617616888f2516d5c6af27e8e2cea5624faa1afc Mon Sep 17 00:00:00 2001 From: Alberto Escolar Piedras Date: Thu, 23 Nov 2023 09:29:51 +0100 Subject: [PATCH 0274/3723] tests/subsys/bindesc: Enable for native_sim Enable these tests which run in native_posix also in native_sim, And add native_sim as default test platform. Signed-off-by: Alberto Escolar Piedras --- tests/subsys/bindesc/definition/testcase.yaml | 20 +++++++------------ 1 file changed, 7 insertions(+), 13 deletions(-) diff --git a/tests/subsys/bindesc/definition/testcase.yaml b/tests/subsys/bindesc/definition/testcase.yaml index 72ede27a059..3da2484a15b 100644 --- a/tests/subsys/bindesc/definition/testcase.yaml +++ b/tests/subsys/bindesc/definition/testcase.yaml @@ -1,31 +1,25 @@ +common: + platform_allow: + - native_posix + - native_sim + integration_platforms: + - native_sim + tags: bindesc tests: bindesc.define: - tags: bindesc platform_allow: > native_posix qemu_x86 qemu_cortex_m0 qemu_cortex_m3 qemu_cortex_r5 qemu_arc_em qemu_arc_hs qemu_arc_hs5x qemu_arc_hs6x qemu_riscv32 qemu_riscv32e qemu_riscv64 bindesc.define.c99: - platform_allow: native_posix - tags: bindesc extra_args: CSTD="c99" bindesc.define.c11: - platform_allow: native_posix - tags: bindesc extra_args: CSTD="c11" bindesc.define.c17: - platform_allow: native_posix - tags: bindesc extra_args: CSTD="c17" bindesc.define.gnu99: - platform_allow: native_posix - tags: bindesc extra_args: CSTD="gnu99" bindesc.define.gnu11: - platform_allow: native_posix - tags: bindesc extra_args: CSTD="gnu11" bindesc.define.gnu17: - platform_allow: native_posix - tags: bindesc extra_args: CSTD="gnu17" From c47702cb7e00fccf96a0e64b0c5e9f4db810e8c3 Mon Sep 17 00:00:00 2001 From: Alberto Escolar Piedras Date: Thu, 23 Nov 2023 09:33:43 +0100 Subject: [PATCH 0275/3723] tests/subsys/shell/shell_flash: Enable for native_sim Enable this test which runs in native_posix in native_sim. Signed-off-by: Alberto Escolar Piedras --- tests/subsys/shell/shell_flash/testcase.yaml | 1 + 1 file changed, 1 insertion(+) diff --git a/tests/subsys/shell/shell_flash/testcase.yaml b/tests/subsys/shell/shell_flash/testcase.yaml index 9e6df805431..5537e453b93 100644 --- a/tests/subsys/shell/shell_flash/testcase.yaml +++ b/tests/subsys/shell/shell_flash/testcase.yaml @@ -9,3 +9,4 @@ tests: platform_allow: - qemu_x86 - native_posix + - native_sim From bb090128f6764f599997831eb23ded7d9079817b Mon Sep 17 00:00:00 2001 From: Alberto Escolar Piedras Date: Thu, 23 Nov 2023 09:35:35 +0100 Subject: [PATCH 0276/3723] tests/subsys/mgmt/ec_host_cmd/*: Enable for native_sim Enable these test which run in native_posix in native_sim, And set native_sim as default test platform Signed-off-by: Alberto Escolar Piedras --- tests/subsys/mgmt/ec_host_cmd/simulator/testcase.yaml | 6 +++++- tests/subsys/mgmt/ec_host_cmd/uart/testcase.yaml | 6 +++++- 2 files changed, 10 insertions(+), 2 deletions(-) diff --git a/tests/subsys/mgmt/ec_host_cmd/simulator/testcase.yaml b/tests/subsys/mgmt/ec_host_cmd/simulator/testcase.yaml index 2469f0f7686..02500435c02 100644 --- a/tests/subsys/mgmt/ec_host_cmd/simulator/testcase.yaml +++ b/tests/subsys/mgmt/ec_host_cmd/simulator/testcase.yaml @@ -1,4 +1,8 @@ tests: mgmt.ec_host_cmd.simulator.core: - platform_allow: native_posix + platform_allow: + - native_posix + - native_sim + integration_platforms: + - native_sim tags: ec_host_cmd diff --git a/tests/subsys/mgmt/ec_host_cmd/uart/testcase.yaml b/tests/subsys/mgmt/ec_host_cmd/uart/testcase.yaml index 70f22c97beb..de003570380 100644 --- a/tests/subsys/mgmt/ec_host_cmd/uart/testcase.yaml +++ b/tests/subsys/mgmt/ec_host_cmd/uart/testcase.yaml @@ -1,4 +1,8 @@ tests: mgmt.ec_host_cmd.uart.core: - platform_allow: native_posix + platform_allow: + - native_posix + - native_sim + integration_platforms: + - native_sim tags: ec_host_cmd From bf937b0d92b38589cb3bef2cd95aae867cd88e46 Mon Sep 17 00:00:00 2001 From: Alberto Escolar Piedras Date: Thu, 23 Nov 2023 09:42:49 +0100 Subject: [PATCH 0277/3723] tests/subsys/mgmt/mcumgr/*: Switch to native_sim Enable all these tests which run in native_posix in native_sim, For those with native_posix as default test platform, which it to native_sim. Signed-off-by: Alberto Escolar Piedras --- tests/subsys/mgmt/mcumgr/cb_notifications/testcase.yaml | 2 ++ .../subsys/mgmt/mcumgr/fs_mgmt_hash_supported/testcase.yaml | 2 +- tests/subsys/mgmt/mcumgr/mcumgr_client/testcase.yaml | 6 +++++- tests/subsys/mgmt/mcumgr/os_mgmt_datetime/testcase.yaml | 1 + tests/subsys/mgmt/mcumgr/settings_mgmt/testcase.yaml | 2 ++ tests/subsys/mgmt/mcumgr/smp_client/testcase.yaml | 6 +++++- tests/subsys/mgmt/mcumgr/smp_reassembly/testcase.yaml | 6 +++++- tests/subsys/mgmt/mcumgr/zcbor_bulk/testcase.yaml | 1 + 8 files changed, 22 insertions(+), 4 deletions(-) diff --git a/tests/subsys/mgmt/mcumgr/cb_notifications/testcase.yaml b/tests/subsys/mgmt/mcumgr/cb_notifications/testcase.yaml index 4208556288b..a2514c4dac8 100644 --- a/tests/subsys/mgmt/mcumgr/cb_notifications/testcase.yaml +++ b/tests/subsys/mgmt/mcumgr/cb_notifications/testcase.yaml @@ -9,6 +9,8 @@ tests: - qemu_cortex_m3 - native_posix - native_posix_64 + - native_sim + - native_sim_64 - qemu_riscv32_smp - qemu_riscv64 tags: diff --git a/tests/subsys/mgmt/mcumgr/fs_mgmt_hash_supported/testcase.yaml b/tests/subsys/mgmt/mcumgr/fs_mgmt_hash_supported/testcase.yaml index 9d32f111085..81f679d3c28 100644 --- a/tests/subsys/mgmt/mcumgr/fs_mgmt_hash_supported/testcase.yaml +++ b/tests/subsys/mgmt/mcumgr/fs_mgmt_hash_supported/testcase.yaml @@ -9,7 +9,7 @@ common: - mcumgr - fs_mgmt_hash_supported integration_platforms: - - native_posix + - native_sim tests: mgmt.mcumgr.fs.mgmt.hash.supported.crc32: extra_args: > diff --git a/tests/subsys/mgmt/mcumgr/mcumgr_client/testcase.yaml b/tests/subsys/mgmt/mcumgr/mcumgr_client/testcase.yaml index 99b9fac34ad..d1ba03f3290 100644 --- a/tests/subsys/mgmt/mcumgr/mcumgr_client/testcase.yaml +++ b/tests/subsys/mgmt/mcumgr/mcumgr_client/testcase.yaml @@ -5,7 +5,11 @@ # tests: mgmt.mcumgr.mcumgr.client: - platform_allow: native_posix + platform_allow: + - native_posix + - native_sim + integration_platforms: + - native_sim tags: - mcumgr - mcumgr_client diff --git a/tests/subsys/mgmt/mcumgr/os_mgmt_datetime/testcase.yaml b/tests/subsys/mgmt/mcumgr/os_mgmt_datetime/testcase.yaml index 013a371c9a0..82d0021d325 100644 --- a/tests/subsys/mgmt/mcumgr/os_mgmt_datetime/testcase.yaml +++ b/tests/subsys/mgmt/mcumgr/os_mgmt_datetime/testcase.yaml @@ -9,6 +9,7 @@ common: - os_mgmt_datetime platform_allow: - native_posix + - native_sim - qemu_cortex_m0 - qemu_riscv64 - qemu_riscv64_smp diff --git a/tests/subsys/mgmt/mcumgr/settings_mgmt/testcase.yaml b/tests/subsys/mgmt/mcumgr/settings_mgmt/testcase.yaml index 7a9205afc7f..2e8a68cca64 100644 --- a/tests/subsys/mgmt/mcumgr/settings_mgmt/testcase.yaml +++ b/tests/subsys/mgmt/mcumgr/settings_mgmt/testcase.yaml @@ -8,6 +8,8 @@ tests: platform_allow: - native_posix - native_posix_64 + - native_sim + - native_sim_64 - nrf52840dk_nrf52840 tags: - settings_mgmt diff --git a/tests/subsys/mgmt/mcumgr/smp_client/testcase.yaml b/tests/subsys/mgmt/mcumgr/smp_client/testcase.yaml index 49971116251..92afb043baa 100644 --- a/tests/subsys/mgmt/mcumgr/smp_client/testcase.yaml +++ b/tests/subsys/mgmt/mcumgr/smp_client/testcase.yaml @@ -5,7 +5,11 @@ # tests: mgmt.mcumgr.smp.client: - platform_allow: native_posix + platform_allow: + - native_posix + - native_sim + integration_platforms: + - native_sim tags: - mcumgr - smp_client diff --git a/tests/subsys/mgmt/mcumgr/smp_reassembly/testcase.yaml b/tests/subsys/mgmt/mcumgr/smp_reassembly/testcase.yaml index cd55657012d..097b83e8de1 100644 --- a/tests/subsys/mgmt/mcumgr/smp_reassembly/testcase.yaml +++ b/tests/subsys/mgmt/mcumgr/smp_reassembly/testcase.yaml @@ -5,7 +5,11 @@ # tests: mgmt.mcumgr.smp.reassembly: - platform_allow: native_posix + platform_allow: + - native_posix + - native_sim + integration_platforms: + - native_sim tags: - smp_reassembly - mgmt diff --git a/tests/subsys/mgmt/mcumgr/zcbor_bulk/testcase.yaml b/tests/subsys/mgmt/mcumgr/zcbor_bulk/testcase.yaml index ff8f5a839c7..df8e0d25316 100644 --- a/tests/subsys/mgmt/mcumgr/zcbor_bulk/testcase.yaml +++ b/tests/subsys/mgmt/mcumgr/zcbor_bulk/testcase.yaml @@ -7,6 +7,7 @@ tests: mgmt.mcumgr.zcbor.bulk: platform_allow: - native_posix + - native_sim - qemu_cortex_m0 - qemu_cortex_m3 tags: From aa683e2a8ba9085162ee3de3d893b5c53d1eb909 Mon Sep 17 00:00:00 2001 From: Alberto Escolar Piedras Date: Thu, 23 Nov 2023 10:05:18 +0100 Subject: [PATCH 0278/3723] tests/subsys/logging/log_backend_fs: Simplify and enable for native_sim * Simplify the test definition by using an EXTRA DTC overlay so we don't need one test per board * Move native_posix overlays to native_sim * Switch the default integration platform to native_sim from native_posix Signed-off-by: Alberto Escolar Piedras --- .../{boards => }/automount.overlay | 0 .../{native_posix.conf => native_sim.conf} | 0 ...ative_posix.overlay => native_sim.overlay} | 0 ...ative_posix_64.conf => native_sim_64.conf} | 0 ...posix_64.overlay => native_sim_64.overlay} | 0 .../logging/log_backend_fs/testcase.yaml | 36 ++++++------------- 6 files changed, 10 insertions(+), 26 deletions(-) rename tests/subsys/logging/log_backend_fs/{boards => }/automount.overlay (100%) rename tests/subsys/logging/log_backend_fs/boards/{native_posix.conf => native_sim.conf} (100%) rename tests/subsys/logging/log_backend_fs/boards/{native_posix.overlay => native_sim.overlay} (100%) rename tests/subsys/logging/log_backend_fs/boards/{native_posix_64.conf => native_sim_64.conf} (100%) rename tests/subsys/logging/log_backend_fs/boards/{native_posix_64.overlay => native_sim_64.overlay} (100%) diff --git a/tests/subsys/logging/log_backend_fs/boards/automount.overlay b/tests/subsys/logging/log_backend_fs/automount.overlay similarity index 100% rename from tests/subsys/logging/log_backend_fs/boards/automount.overlay rename to tests/subsys/logging/log_backend_fs/automount.overlay diff --git a/tests/subsys/logging/log_backend_fs/boards/native_posix.conf b/tests/subsys/logging/log_backend_fs/boards/native_sim.conf similarity index 100% rename from tests/subsys/logging/log_backend_fs/boards/native_posix.conf rename to tests/subsys/logging/log_backend_fs/boards/native_sim.conf diff --git a/tests/subsys/logging/log_backend_fs/boards/native_posix.overlay b/tests/subsys/logging/log_backend_fs/boards/native_sim.overlay similarity index 100% rename from tests/subsys/logging/log_backend_fs/boards/native_posix.overlay rename to tests/subsys/logging/log_backend_fs/boards/native_sim.overlay diff --git a/tests/subsys/logging/log_backend_fs/boards/native_posix_64.conf b/tests/subsys/logging/log_backend_fs/boards/native_sim_64.conf similarity index 100% rename from tests/subsys/logging/log_backend_fs/boards/native_posix_64.conf rename to tests/subsys/logging/log_backend_fs/boards/native_sim_64.conf diff --git a/tests/subsys/logging/log_backend_fs/boards/native_posix_64.overlay b/tests/subsys/logging/log_backend_fs/boards/native_sim_64.overlay similarity index 100% rename from tests/subsys/logging/log_backend_fs/boards/native_posix_64.overlay rename to tests/subsys/logging/log_backend_fs/boards/native_sim_64.overlay diff --git a/tests/subsys/logging/log_backend_fs/testcase.yaml b/tests/subsys/logging/log_backend_fs/testcase.yaml index f372776f10f..c8caccc8c8f 100644 --- a/tests/subsys/logging/log_backend_fs/testcase.yaml +++ b/tests/subsys/logging/log_backend_fs/testcase.yaml @@ -7,30 +7,14 @@ common: - filesystem - fs - littlefs + platform_allow: + - native_sim + - native_sim_64 + - nrf52840dk_nrf52840 + - mr_canhubk3 + integration_platforms: + - native_sim tests: - logging.backend.fs.automounted: - platform_allow: - - native_posix - - native_posix_64 - - nrf52840dk_nrf52840 - - mr_canhubk3 - integration_platforms: - - native_posix - logging.backend.fs.manualmounted.native_posix: - platform_allow: native_posix - extra_args: DTC_OVERLAY_FILE="./boards/native_posix.overlay;./boards/automount.overlay" - integration_platforms: - - native_posix - logging.backend.fs.manualmounted.native_posix_64: - platform_allow: native_posix_64 - extra_args: DTC_OVERLAY_FILE="./boards/native_posix_64.overlay;./boards/automount.overlay" - integration_platforms: - - native_posix_64 - logging.backend.fs.manualmounted.nrf5840dk: - platform_allow: nrf52840dk_nrf52840 - extra_args: DTC_OVERLAY_FILE="./boards/nrf52840dk_nrf52840.overlay;./boards/automount.overlay" - integration_platforms: - - nrf52840dk_nrf52840 - logging.backend.fs.manualmounted.mr_canhubk3: - platform_allow: mr_canhubk3 - extra_args: DTC_OVERLAY_FILE="./boards/mr_canhubk3.overlay;./boards/automount.overlay" + logging.backend.fs.automounted: {} + logging.backend.fs.manualmounted: + extra_args: EXTRA_DTC_OVERLAY_FILE="automount.overlay" From e628a5b9d015e954f647744bb90cd892232796f6 Mon Sep 17 00:00:00 2001 From: Alberto Escolar Piedras Date: Thu, 23 Nov 2023 10:11:36 +0100 Subject: [PATCH 0279/3723] tests/subsys/logging/*: Enable for native_sim For all tests which were enabled for native_posix enable them also for native_sim. For those with native_posix as integration_platform, set native_sim instead. Signed-off-by: Alberto Escolar Piedras --- tests/subsys/logging/log_api/testcase.yaml | 7 ++++++- tests/subsys/logging/log_benchmark/testcase.yaml | 14 +++++--------- tests/subsys/logging/log_cache/testcase.yaml | 2 +- .../logging/log_core_additional/testcase.yaml | 4 ++-- .../subsys/logging/log_custom_header/testcase.yaml | 2 +- tests/subsys/logging/log_immediate/testcase.yaml | 2 +- tests/subsys/logging/log_link_order/testcase.yaml | 2 +- tests/subsys/logging/log_links/testcase.yaml | 2 +- tests/subsys/logging/log_msg/testcase.yaml | 2 +- tests/subsys/logging/log_output/testcase.yaml | 2 +- tests/subsys/logging/log_timestamp/testcase.yaml | 2 +- 11 files changed, 21 insertions(+), 20 deletions(-) diff --git a/tests/subsys/logging/log_api/testcase.yaml b/tests/subsys/logging/log_api/testcase.yaml index 2b389d01073..6e6698c294d 100644 --- a/tests/subsys/logging/log_api/testcase.yaml +++ b/tests/subsys/logging/log_api/testcase.yaml @@ -9,7 +9,7 @@ common: - arch - simulation integration_platforms: - - native_posix + - native_sim min_ram: 32 tests: logging.deferred.api.overflow_rt_filter: @@ -59,6 +59,7 @@ tests: - qemu_cortex_m3 - qemu_cortex_a9 - native_posix + - native_sim extra_configs: - CONFIG_LOG_MODE_DEFERRED=y - CONFIG_LOG_OVERRIDE_LEVEL=4 @@ -110,6 +111,7 @@ tests: - qemu_cortex_m3 - qemu_cortex_a9 - native_posix + - native_sim extra_configs: - CONFIG_LOG_FRONTEND=y - CONFIG_LOG_MODE_IMMEDIATE=y @@ -122,6 +124,7 @@ tests: - qemu_cortex_m3 - qemu_cortex_a9 - native_posix + - native_sim extra_configs: - CONFIG_LOG_MODE_DEFERRED=y - CONFIG_LOG_RUNTIME_FILTERING=y @@ -315,6 +318,7 @@ tests: - qemu_cortex_m3 - qemu_cortex_a9 - native_posix + - native_sim toolchain_exclude: xcc extra_configs: - CONFIG_LOG_MODE_DEFERRED=y @@ -328,6 +332,7 @@ tests: - qemu_cortex_m3 - qemu_cortex_a9 - native_posix + - native_sim toolchain_exclude: xcc extra_configs: - CONFIG_LOG_MODE_DEFERRED=y diff --git a/tests/subsys/logging/log_benchmark/testcase.yaml b/tests/subsys/logging/log_benchmark/testcase.yaml index b530895ba54..3d25efcda2c 100644 --- a/tests/subsys/logging/log_benchmark/testcase.yaml +++ b/tests/subsys/logging/log_benchmark/testcase.yaml @@ -1,28 +1,24 @@ +common: + integration_platforms: + - native_sim + tags: logging tests: logging.benchmark: - integration_platforms: - - native_posix - tags: logging extra_configs: - CONFIG_LOG_MODE_DEFERRED=y - CONFIG_CBPRINTF_COMPLETE=y - logging.benchmark_speed: - integration_platforms: - - native_posix - tags: logging extra_configs: - CONFIG_LOG_MODE_DEFERRED=y - CONFIG_CBPRINTF_COMPLETE=y - CONFIG_LOG_SPEED=y - logging.benchmark_user: integration_platforms: - qemu_x86 - tags: logging platform_allow: - qemu_x86 - native_posix + - native_sim extra_configs: - CONFIG_LOG_MODE_DEFERRED=y - CONFIG_CBPRINTF_COMPLETE=y diff --git a/tests/subsys/logging/log_cache/testcase.yaml b/tests/subsys/logging/log_cache/testcase.yaml index 65aa2fa388e..c8b2f7e8f40 100644 --- a/tests/subsys/logging/log_cache/testcase.yaml +++ b/tests/subsys/logging/log_cache/testcase.yaml @@ -1,6 +1,6 @@ common: integration_platforms: - - native_posix + - native_sim tests: logging.cache: diff --git a/tests/subsys/logging/log_core_additional/testcase.yaml b/tests/subsys/logging/log_core_additional/testcase.yaml index 7fc508440ee..53c2d34f5e0 100644 --- a/tests/subsys/logging/log_core_additional/testcase.yaml +++ b/tests/subsys/logging/log_core_additional/testcase.yaml @@ -3,12 +3,12 @@ tests: tags: logging extra_args: CONF_FILE=prj.conf integration_platforms: - - native_posix + - native_sim logging.sync: tags: logging extra_args: CONF_FILE=log_sync.conf integration_platforms: - - native_posix + - native_sim logging.log_user: tags: logging filter: CONFIG_USERSPACE diff --git a/tests/subsys/logging/log_custom_header/testcase.yaml b/tests/subsys/logging/log_custom_header/testcase.yaml index ff13ce77d04..41da229c056 100644 --- a/tests/subsys/logging/log_custom_header/testcase.yaml +++ b/tests/subsys/logging/log_custom_header/testcase.yaml @@ -1,6 +1,6 @@ common: integration_platforms: - - native_posix + - native_sim tests: logging.log_custom_header: diff --git a/tests/subsys/logging/log_immediate/testcase.yaml b/tests/subsys/logging/log_immediate/testcase.yaml index dd63de3c17f..6e98959f5dc 100644 --- a/tests/subsys/logging/log_immediate/testcase.yaml +++ b/tests/subsys/logging/log_immediate/testcase.yaml @@ -1,6 +1,6 @@ common: integration_platforms: - - native_posix + - native_sim tests: logging.immediate: diff --git a/tests/subsys/logging/log_link_order/testcase.yaml b/tests/subsys/logging/log_link_order/testcase.yaml index 88759e7daad..f6acb33af22 100644 --- a/tests/subsys/logging/log_link_order/testcase.yaml +++ b/tests/subsys/logging/log_link_order/testcase.yaml @@ -1,7 +1,7 @@ tests: logging.log_link_order: integration_platforms: - - native_posix + - native_sim tags: - log_links - logging diff --git a/tests/subsys/logging/log_links/testcase.yaml b/tests/subsys/logging/log_links/testcase.yaml index d323afe53bf..95f5ea54f8a 100644 --- a/tests/subsys/logging/log_links/testcase.yaml +++ b/tests/subsys/logging/log_links/testcase.yaml @@ -1,7 +1,7 @@ tests: logging.log_links: integration_platforms: - - native_posix + - native_sim tags: - log_links - logging diff --git a/tests/subsys/logging/log_msg/testcase.yaml b/tests/subsys/logging/log_msg/testcase.yaml index 543eb046630..59e9fa9b716 100644 --- a/tests/subsys/logging/log_msg/testcase.yaml +++ b/tests/subsys/logging/log_msg/testcase.yaml @@ -6,7 +6,7 @@ common: - log_api - logging integration_platforms: - - native_posix + - native_sim filter: not CONFIG_LOG_ALWAYS_RUNTIME tests: logging.message: diff --git a/tests/subsys/logging/log_output/testcase.yaml b/tests/subsys/logging/log_output/testcase.yaml index cb265420276..71c390cb017 100644 --- a/tests/subsys/logging/log_output/testcase.yaml +++ b/tests/subsys/logging/log_output/testcase.yaml @@ -1,6 +1,6 @@ common: integration_platforms: - - native_posix + - native_sim tests: logging.output: diff --git a/tests/subsys/logging/log_timestamp/testcase.yaml b/tests/subsys/logging/log_timestamp/testcase.yaml index 6173e67c1d2..9504ec615d3 100644 --- a/tests/subsys/logging/log_timestamp/testcase.yaml +++ b/tests/subsys/logging/log_timestamp/testcase.yaml @@ -1,6 +1,6 @@ common: integration_platforms: - - native_posix + - native_sim tests: logging.output.default_timestamp: From 1d64f1b3975cd887bbe8ebd4ff5f69f0e741ed93 Mon Sep 17 00:00:00 2001 From: Alberto Escolar Piedras Date: Thu, 23 Nov 2023 10:26:19 +0100 Subject: [PATCH 0280/3723] tests/subsys/openthread: Enable for native_sim Enable these test which run in native_posix in native_sim Switch from native_posix to native_sim as default test platform Signed-off-by: Alberto Escolar Piedras --- tests/subsys/openthread/testcase.yaml | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/tests/subsys/openthread/testcase.yaml b/tests/subsys/openthread/testcase.yaml index dfa48f75aad..d017c38370a 100644 --- a/tests/subsys/openthread/testcase.yaml +++ b/tests/subsys/openthread/testcase.yaml @@ -2,8 +2,10 @@ common: platform_allow: - native_posix - native_posix_64 + - native_sim + - native_sim_64 integration_platforms: - - native_posix + - native_sim tags: - openthread tests: From 2231c3ab97633cdf925b5bf8d38c3bc6c31b9fb9 Mon Sep 17 00:00:00 2001 From: Alberto Escolar Piedras Date: Thu, 23 Nov 2023 10:35:33 +0100 Subject: [PATCH 0281/3723] tests/subsys/usb/*: Enable for native_sim Enable all these tests which run in native_posix in native_sim, Switch from native_posix to native_sim as default test platform And switch native_posix overlays to native_sim. Signed-off-by: Alberto Escolar Piedras --- .../boards/{native_posix.overlay => native_sim.overlay} | 0 tests/subsys/usb/device_next/testcase.yaml | 4 ++-- tests/subsys/usb/os_desc/testcase.yaml | 4 +++- 3 files changed, 5 insertions(+), 3 deletions(-) rename tests/subsys/usb/device_next/boards/{native_posix.overlay => native_sim.overlay} (100%) diff --git a/tests/subsys/usb/device_next/boards/native_posix.overlay b/tests/subsys/usb/device_next/boards/native_sim.overlay similarity index 100% rename from tests/subsys/usb/device_next/boards/native_posix.overlay rename to tests/subsys/usb/device_next/boards/native_sim.overlay diff --git a/tests/subsys/usb/device_next/testcase.yaml b/tests/subsys/usb/device_next/testcase.yaml index 47e6aa3a0a1..5a826887b88 100644 --- a/tests/subsys/usb/device_next/testcase.yaml +++ b/tests/subsys/usb/device_next/testcase.yaml @@ -3,7 +3,7 @@ tests: depends_on: usb_device tags: usb platform_allow: - - native_posix + - native_sim - qemu_cortex_m3 integration_platforms: - - native_posix + - native_sim diff --git a/tests/subsys/usb/os_desc/testcase.yaml b/tests/subsys/usb/os_desc/testcase.yaml index fd73efb44b5..18b8ac279cc 100644 --- a/tests/subsys/usb/os_desc/testcase.yaml +++ b/tests/subsys/usb/os_desc/testcase.yaml @@ -3,9 +3,11 @@ tests: platform_allow: - native_posix - native_posix_64 + - native_sim + - native_sim_64 - frdm_k64f tags: - usb - osdesc integration_platforms: - - native_posix + - native_sim From 7332eb2ea7c2d5e960d748acebbd71cbb959db99 Mon Sep 17 00:00:00 2001 From: Alberto Escolar Piedras Date: Thu, 23 Nov 2023 11:44:35 +0100 Subject: [PATCH 0282/3723] board native_sim/posix: Provide NEVER/NSI_NEVER definitions Some native_posix specific apps/tests use the macro NEVER provided it also for native_sim until all have switched to the new NSI_NEVER. And ensure NSI_NEVER is also avaiable when building for native_posix to ease the transition. Signed-off-by: Alberto Escolar Piedras --- boards/posix/native_posix/hw_models_top.h | 1 + boards/posix/native_sim/native_posix_compat.h | 2 ++ 2 files changed, 3 insertions(+) diff --git a/boards/posix/native_posix/hw_models_top.h b/boards/posix/native_posix/hw_models_top.h index 47d3333277e..ea50d0f949c 100644 --- a/boards/posix/native_posix/hw_models_top.h +++ b/boards/posix/native_posix/hw_models_top.h @@ -15,6 +15,7 @@ extern "C" { #endif #define NEVER UINT64_MAX +#define NSI_NEVER UINT64_MAX void hwm_one_event(void); void hwm_init(void); diff --git a/boards/posix/native_sim/native_posix_compat.h b/boards/posix/native_sim/native_posix_compat.h index a2b5dc0299b..6c943606f3f 100644 --- a/boards/posix/native_sim/native_posix_compat.h +++ b/boards/posix/native_sim/native_posix_compat.h @@ -33,6 +33,8 @@ static ALWAYS_INLINE uint64_t hwm_get_time(void) return nsi_hws_get_time(); } +#define NEVER NSI_NEVER + #ifdef __cplusplus } #endif From 3d406a7a56285107e2301547ec7acfcf19df08a4 Mon Sep 17 00:00:00 2001 From: Alberto Escolar Piedras Date: Thu, 23 Nov 2023 11:48:37 +0100 Subject: [PATCH 0283/3723] native_simulator: Get latest from upstream Align with native_simulator's upstream main ae241af736d06874ec02deb9aacb79918d745aba Which includes: * ae241af native timer_model: Allow calling into get_host_us_time Signed-off-by: Alberto Escolar Piedras --- scripts/native_simulator/native/src/timer_model.c | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/scripts/native_simulator/native/src/timer_model.c b/scripts/native_simulator/native/src/timer_model.c index de74e6cac93..a25cc1c5e6e 100644 --- a/scripts/native_simulator/native/src/timer_model.c +++ b/scripts/native_simulator/native/src/timer_model.c @@ -126,7 +126,12 @@ static inline void host_clock_gettime(struct timespec *tv) #endif } -static uint64_t get_host_us_time(void) +/* + * This function is globally available only for tests purposes + * It should not be used for any functional purposes, + * and as such is not present in this component header. + */ +uint64_t get_host_us_time(void) { struct timespec tv; From 5f4bd36b9821f7f2cfd6e3bbf7c06f291240e5ce Mon Sep 17 00:00:00 2001 From: Alberto Escolar Piedras Date: Thu, 23 Nov 2023 11:50:22 +0100 Subject: [PATCH 0284/3723] tests/boards/native*: Moved to native_sim Moved folder to tests/boards/native_sim from native_posix (including updating the MAINTAINERS file) And enable all these tests for native_sim. Signed-off-by: Alberto Escolar Piedras --- MAINTAINERS.yml | 2 +- tests/boards/native_posix/native_tasks/testcase.yaml | 5 ----- .../{native_posix => native_sim}/cpu_wait/CMakeLists.txt | 0 tests/boards/{native_posix => native_sim}/cpu_wait/prj.conf | 0 .../boards/{native_posix => native_sim}/cpu_wait/src/main.c | 0 .../{native_posix => native_sim}/cpu_wait/testcase.yaml | 6 ++++-- .../native_tasks/CMakeLists.txt | 0 .../{native_posix => native_sim}/native_tasks/prj.conf | 0 .../{native_posix => native_sim}/native_tasks/src/main.c | 0 tests/boards/native_sim/native_tasks/testcase.yaml | 3 +++ .../boards/{native_posix => native_sim}/rtc/CMakeLists.txt | 0 tests/boards/{native_posix => native_sim}/rtc/prj.conf | 0 tests/boards/{native_posix => native_sim}/rtc/src/main.c | 2 +- tests/boards/{native_posix => native_sim}/rtc/testcase.yaml | 4 +++- 14 files changed, 12 insertions(+), 10 deletions(-) delete mode 100644 tests/boards/native_posix/native_tasks/testcase.yaml rename tests/boards/{native_posix => native_sim}/cpu_wait/CMakeLists.txt (100%) rename tests/boards/{native_posix => native_sim}/cpu_wait/prj.conf (100%) rename tests/boards/{native_posix => native_sim}/cpu_wait/src/main.c (100%) rename tests/boards/{native_posix => native_sim}/cpu_wait/testcase.yaml (64%) rename tests/boards/{native_posix => native_sim}/native_tasks/CMakeLists.txt (100%) rename tests/boards/{native_posix => native_sim}/native_tasks/prj.conf (100%) rename tests/boards/{native_posix => native_sim}/native_tasks/src/main.c (100%) create mode 100644 tests/boards/native_sim/native_tasks/testcase.yaml rename tests/boards/{native_posix => native_sim}/rtc/CMakeLists.txt (100%) rename tests/boards/{native_posix => native_sim}/rtc/prj.conf (100%) rename tests/boards/{native_posix => native_sim}/rtc/src/main.c (99%) rename tests/boards/{native_posix => native_sim}/rtc/testcase.yaml (84%) diff --git a/MAINTAINERS.yml b/MAINTAINERS.yml index 7035252fa3b..3393ef145e5 100644 --- a/MAINTAINERS.yml +++ b/MAINTAINERS.yml @@ -2004,7 +2004,7 @@ Native POSIX/Sim and POSIX arch: - scripts/native_simulator/ - scripts/valgrind.supp - soc/posix/ - - tests/boards/native_posix/ + - tests/boards/native_sim/ labels: - "area: native port" description: >- diff --git a/tests/boards/native_posix/native_tasks/testcase.yaml b/tests/boards/native_posix/native_tasks/testcase.yaml deleted file mode 100644 index 7fd9eccb03c..00000000000 --- a/tests/boards/native_posix/native_tasks/testcase.yaml +++ /dev/null @@ -1,5 +0,0 @@ -tests: - boards.native_posix.native_tasks: - arch_allow: posix - boards.native_posix_64.native_tasks: - arch_allow: posix diff --git a/tests/boards/native_posix/cpu_wait/CMakeLists.txt b/tests/boards/native_sim/cpu_wait/CMakeLists.txt similarity index 100% rename from tests/boards/native_posix/cpu_wait/CMakeLists.txt rename to tests/boards/native_sim/cpu_wait/CMakeLists.txt diff --git a/tests/boards/native_posix/cpu_wait/prj.conf b/tests/boards/native_sim/cpu_wait/prj.conf similarity index 100% rename from tests/boards/native_posix/cpu_wait/prj.conf rename to tests/boards/native_sim/cpu_wait/prj.conf diff --git a/tests/boards/native_posix/cpu_wait/src/main.c b/tests/boards/native_sim/cpu_wait/src/main.c similarity index 100% rename from tests/boards/native_posix/cpu_wait/src/main.c rename to tests/boards/native_sim/cpu_wait/src/main.c diff --git a/tests/boards/native_posix/cpu_wait/testcase.yaml b/tests/boards/native_sim/cpu_wait/testcase.yaml similarity index 64% rename from tests/boards/native_posix/cpu_wait/testcase.yaml rename to tests/boards/native_sim/cpu_wait/testcase.yaml index a461d048793..cd9ea17b066 100644 --- a/tests/boards/native_posix/cpu_wait/testcase.yaml +++ b/tests/boards/native_sim/cpu_wait/testcase.yaml @@ -1,8 +1,10 @@ # Test of the posix_arch k_busy_wait & cpu_hold() functionality tests: - boards.native_posix.cpu_wait: + boards.native_sim.cpu_wait: platform_allow: - native_posix - native_posix_64 + - native_sim + - native_sim_64 integration_platforms: - - native_posix + - native_sim diff --git a/tests/boards/native_posix/native_tasks/CMakeLists.txt b/tests/boards/native_sim/native_tasks/CMakeLists.txt similarity index 100% rename from tests/boards/native_posix/native_tasks/CMakeLists.txt rename to tests/boards/native_sim/native_tasks/CMakeLists.txt diff --git a/tests/boards/native_posix/native_tasks/prj.conf b/tests/boards/native_sim/native_tasks/prj.conf similarity index 100% rename from tests/boards/native_posix/native_tasks/prj.conf rename to tests/boards/native_sim/native_tasks/prj.conf diff --git a/tests/boards/native_posix/native_tasks/src/main.c b/tests/boards/native_sim/native_tasks/src/main.c similarity index 100% rename from tests/boards/native_posix/native_tasks/src/main.c rename to tests/boards/native_sim/native_tasks/src/main.c diff --git a/tests/boards/native_sim/native_tasks/testcase.yaml b/tests/boards/native_sim/native_tasks/testcase.yaml new file mode 100644 index 00000000000..d4983554fd1 --- /dev/null +++ b/tests/boards/native_sim/native_tasks/testcase.yaml @@ -0,0 +1,3 @@ +tests: + boards.native_sim.native_tasks: + arch_allow: posix diff --git a/tests/boards/native_posix/rtc/CMakeLists.txt b/tests/boards/native_sim/rtc/CMakeLists.txt similarity index 100% rename from tests/boards/native_posix/rtc/CMakeLists.txt rename to tests/boards/native_sim/rtc/CMakeLists.txt diff --git a/tests/boards/native_posix/rtc/prj.conf b/tests/boards/native_sim/rtc/prj.conf similarity index 100% rename from tests/boards/native_posix/rtc/prj.conf rename to tests/boards/native_sim/rtc/prj.conf diff --git a/tests/boards/native_posix/rtc/src/main.c b/tests/boards/native_sim/rtc/src/main.c similarity index 99% rename from tests/boards/native_posix/rtc/src/main.c rename to tests/boards/native_sim/rtc/src/main.c index b1960c2e492..3cb783202de 100644 --- a/tests/boards/native_posix/rtc/src/main.c +++ b/tests/boards/native_sim/rtc/src/main.c @@ -19,7 +19,7 @@ static char *us_time_to_str(char *dest, uint64_t time) { - if (time != NEVER) { + if (time != NSI_NEVER) { unsigned int hour; unsigned int minute; unsigned int second; diff --git a/tests/boards/native_posix/rtc/testcase.yaml b/tests/boards/native_sim/rtc/testcase.yaml similarity index 84% rename from tests/boards/native_posix/rtc/testcase.yaml rename to tests/boards/native_sim/rtc/testcase.yaml index 527603a7494..02da1cd41be 100644 --- a/tests/boards/native_posix/rtc/testcase.yaml +++ b/tests/boards/native_sim/rtc/testcase.yaml @@ -4,8 +4,10 @@ tests: platform_allow: - native_posix - native_posix_64 + - native_sim + - native_sim_64 integration_platforms: - - native_posix + - native_sim build_only: true # Note: this test depends too much on not having a high host load to pass. # Therefore it should not be run in automated regression From 18c71868a54d4dcd81748530d47234a6ade17d81 Mon Sep 17 00:00:00 2001 From: Alberto Escolar Piedras Date: Thu, 23 Nov 2023 12:57:47 +0100 Subject: [PATCH 0285/3723] tests/lib/mpsc_pbuf: Switch to native_sim Enable this test which runs in native_posix in native_sim, Switch from native_posix to native_sim as default test platform Signed-off-by: Alberto Escolar Piedras --- tests/lib/mpsc_pbuf/testcase.yaml | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/tests/lib/mpsc_pbuf/testcase.yaml b/tests/lib/mpsc_pbuf/testcase.yaml index df896168fdf..61341277ec1 100644 --- a/tests/lib/mpsc_pbuf/testcase.yaml +++ b/tests/lib/mpsc_pbuf/testcase.yaml @@ -16,8 +16,9 @@ tests: - qemu_x86_64 - qemu_xtensa - native_posix + - native_sim integration_platforms: - - native_posix + - native_sim libraries.mpsc_pbuf.concurrent: tags: mpsc_pbuf From 70e0d1e04e03323d0e37a61637b4ca36c9d0e854 Mon Sep 17 00:00:00 2001 From: Alberto Escolar Piedras Date: Thu, 23 Nov 2023 13:00:11 +0100 Subject: [PATCH 0286/3723] tests/lib/devicetree: Enable for native_sim Enable these tests which run in native_posix in native_sim, Switch from native_posix to native_sim as default test platform Signed-off-by: Alberto Escolar Piedras --- tests/lib/devicetree/api/testcase.yaml | 5 +++-- tests/lib/devicetree/api_ext/testcase.yaml | 4 ++-- tests/lib/devicetree/devices/testcase.yaml | 4 ++-- 3 files changed, 7 insertions(+), 6 deletions(-) diff --git a/tests/lib/devicetree/api/testcase.yaml b/tests/lib/devicetree/api/testcase.yaml index 105f7c73ebf..65e87cc093e 100644 --- a/tests/lib/devicetree/api/testcase.yaml +++ b/tests/lib/devicetree/api/testcase.yaml @@ -1,13 +1,14 @@ tests: libraries.devicetree.api: tags: devicetree - # We only need this to run on one platform so use native_posix as it + # We only need this to run on one platform so use native_sim as it # will mostly likely be the fastest. platform_allow: - native_posix + - native_sim - qemu_x86 - qemu_x86_64 - qemu_cortex_m3 - qemu_riscv32 integration_platforms: - - native_posix + - native_sim diff --git a/tests/lib/devicetree/api_ext/testcase.yaml b/tests/lib/devicetree/api_ext/testcase.yaml index 00f070deb50..cd229e31d1a 100644 --- a/tests/lib/devicetree/api_ext/testcase.yaml +++ b/tests/lib/devicetree/api_ext/testcase.yaml @@ -1,7 +1,7 @@ tests: libraries.devicetree.api_ext: tags: devicetree - # We only need this to run on one platform so use native_posix as it + # We only need this to run on one platform so use native_sim as it # will mostly likely be the fastest. integration_platforms: - - native_posix + - native_sim diff --git a/tests/lib/devicetree/devices/testcase.yaml b/tests/lib/devicetree/devices/testcase.yaml index 07c99fcdb62..27be9c7c9e1 100644 --- a/tests/lib/devicetree/devices/testcase.yaml +++ b/tests/lib/devicetree/devices/testcase.yaml @@ -1,10 +1,10 @@ tests: libraries.devicetree.devices: tags: devicetree - # We only need this to run on one platform so use native_posix as it + # We only need this to run on one platform so use native_sim as it # will mostly likely be the fastest. integration_platforms: - - native_posix + - native_sim platform_exclude: - hsdk - hsdk_2cores From 6568825174730903ce41d928b394121888726664 Mon Sep 17 00:00:00 2001 From: Alberto Escolar Piedras Date: Thu, 23 Nov 2023 13:03:41 +0100 Subject: [PATCH 0287/3723] tests/crypto/*: Switch from native_posix to native_sim Enable these tests which run in native_posix in native_sim, Switch from native_posix to native_sim as default test platform For drivers.rand32.random_psa_crypto, filter the posix arch to save some CI time, as TFM is not supported in this architecture all together. Signed-off-by: Alberto Escolar Piedras --- tests/crypto/crypto_hash/testcase.yaml | 6 +++++- tests/crypto/mbedtls/testcase.yaml | 2 +- tests/crypto/rand32/testcase.yaml | 5 +++-- tests/crypto/tinycrypt/testcase.yaml | 2 +- tests/crypto/tinycrypt_hmac_prng/testcase.yaml | 2 +- 5 files changed, 11 insertions(+), 6 deletions(-) diff --git a/tests/crypto/crypto_hash/testcase.yaml b/tests/crypto/crypto_hash/testcase.yaml index 70a6a1e3763..8821234d03c 100644 --- a/tests/crypto/crypto_hash/testcase.yaml +++ b/tests/crypto/crypto_hash/testcase.yaml @@ -1,4 +1,8 @@ tests: crypto.hash: - platform_allow: native_posix + platform_allow: + - native_posix + - native_sim + integration_platforms: + - native_sim tags: crypto diff --git a/tests/crypto/mbedtls/testcase.yaml b/tests/crypto/mbedtls/testcase.yaml index 1e2b26b8664..9b89364da93 100644 --- a/tests/crypto/mbedtls/testcase.yaml +++ b/tests/crypto/mbedtls/testcase.yaml @@ -14,4 +14,4 @@ tests: - arch:riscv64:CONFIG_ZTEST_STACK_SIZE=8192 integration_platforms: - qemu_x86 - - native_posix + - native_sim diff --git a/tests/crypto/rand32/testcase.yaml b/tests/crypto/rand32/testcase.yaml index c2fd12f069f..5db81483366 100644 --- a/tests/crypto/rand32/testcase.yaml +++ b/tests/crypto/rand32/testcase.yaml @@ -17,15 +17,16 @@ tests: filter: CONFIG_ENTROPY_HAS_DRIVER min_ram: 16 integration_platforms: - - native_posix + - native_sim crypto.rand32.random_ctr_drbg: extra_args: CONF_FILE=prj_ctr_drbg.conf filter: CONFIG_ENTROPY_HAS_DRIVER min_ram: 16 integration_platforms: - - native_posix + - native_sim drivers.rand32.random_psa_crypto: filter: CONFIG_BUILD_WITH_TFM + arch_exclude: posix extra_args: - DTC_OVERLAY_FILE=./entropy_psa_crypto.overlay - CONF_FILE=prj_hw_random_psa_crypto.conf diff --git a/tests/crypto/tinycrypt/testcase.yaml b/tests/crypto/tinycrypt/testcase.yaml index fcd9611b137..ac08d94fd95 100644 --- a/tests/crypto/tinycrypt/testcase.yaml +++ b/tests/crypto/tinycrypt/testcase.yaml @@ -11,5 +11,5 @@ tests: - m2gl025_miv timeout: 500 integration_platforms: - - native_posix + - native_sim toolchain_exclude: xcc diff --git a/tests/crypto/tinycrypt_hmac_prng/testcase.yaml b/tests/crypto/tinycrypt_hmac_prng/testcase.yaml index 882cd25ef1a..62f7eee9d93 100644 --- a/tests/crypto/tinycrypt_hmac_prng/testcase.yaml +++ b/tests/crypto/tinycrypt_hmac_prng/testcase.yaml @@ -11,5 +11,5 @@ tests: - mec1501modular_assy6885 - m2gl025_miv integration_platforms: - - native_posix + - native_sim toolchain_exclude: xcc From 161b23612429600d0b052f15f4ece85824e07413 Mon Sep 17 00:00:00 2001 From: Alberto Escolar Piedras Date: Thu, 23 Nov 2023 13:06:37 +0100 Subject: [PATCH 0288/3723] tests/misc/kconfigoptions: Switch to native_sim Switch from native_posix to native_sim as test platform and switch overlay to native_sim. Signed-off-by: Alberto Escolar Piedras --- .../kconfigoptions/{native_posix.overlay => native_sim.overlay} | 0 tests/misc/kconfigoptions/testcase.yaml | 2 +- 2 files changed, 1 insertion(+), 1 deletion(-) rename tests/misc/kconfigoptions/{native_posix.overlay => native_sim.overlay} (100%) diff --git a/tests/misc/kconfigoptions/native_posix.overlay b/tests/misc/kconfigoptions/native_sim.overlay similarity index 100% rename from tests/misc/kconfigoptions/native_posix.overlay rename to tests/misc/kconfigoptions/native_sim.overlay diff --git a/tests/misc/kconfigoptions/testcase.yaml b/tests/misc/kconfigoptions/testcase.yaml index d2ee1c06408..af141a172ee 100644 --- a/tests/misc/kconfigoptions/testcase.yaml +++ b/tests/misc/kconfigoptions/testcase.yaml @@ -1,4 +1,4 @@ tests: kconfig.kconfigoptions: tags: kconfigoptions - platform_allow: native_posix + platform_allow: native_sim From 31ec1d044b4b09e9e7eab7bcbe20bdeef497e2d3 Mon Sep 17 00:00:00 2001 From: Alberto Escolar Piedras Date: Thu, 23 Nov 2023 13:30:15 +0100 Subject: [PATCH 0289/3723] tests/misc/test_build: Switch integration_platform to native_sim Switch from native_posix to native_sim as default test platform Signed-off-by: Alberto Escolar Piedras --- tests/misc/test_build/testcase.yaml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/tests/misc/test_build/testcase.yaml b/tests/misc/test_build/testcase.yaml index 983d3e4a96e..42732457c42 100644 --- a/tests/misc/test_build/testcase.yaml +++ b/tests/misc/test_build/testcase.yaml @@ -8,7 +8,7 @@ tests: extra_args: CONF_FILE=debug.conf tags: debug integration_platforms: - - native_posix + - native_sim filter: CONFIG_CONSOLE_HAS_DRIVER bootloader.mcuboot.build: tags: mcuboot @@ -25,6 +25,6 @@ tests: build_only: true tags: kconfig integration_platforms: - - native_posix + - native_sim extra_configs: - CONFIG_KERNEL_BIN_NAME="A_kconfig_value_with_a_utf8_char_in_it_Bøe_" From 548739cf8c2708e8917962c5074a80d91241112d Mon Sep 17 00:00:00 2001 From: Alberto Escolar Piedras Date: Thu, 23 Nov 2023 13:34:31 +0100 Subject: [PATCH 0290/3723] tests/cmake/*: Switch to native_sim Switch from native_posix to native_sim as test platform Signed-off-by: Alberto Escolar Piedras --- tests/cmake/config_dir/testcase.yaml | 2 +- tests/cmake/overlays/var_expansions/testcase.yaml | 2 +- tests/cmake/snippets/testcase.yaml | 3 ++- tests/cmake/zephyr_get/testcase.yaml | 2 +- 4 files changed, 5 insertions(+), 4 deletions(-) diff --git a/tests/cmake/config_dir/testcase.yaml b/tests/cmake/config_dir/testcase.yaml index 16105025664..d88fe6f76e8 100644 --- a/tests/cmake/config_dir/testcase.yaml +++ b/tests/cmake/config_dir/testcase.yaml @@ -1,5 +1,5 @@ tests: buildsystem.config_dir.user_defined: - platform_allow: native_posix + platform_allow: native_sim build_only: true extra_args: APPLICATION_CONFIG_DIR:PATH=foo diff --git a/tests/cmake/overlays/var_expansions/testcase.yaml b/tests/cmake/overlays/var_expansions/testcase.yaml index 1149a7f7c28..919e75f7739 100644 --- a/tests/cmake/overlays/var_expansions/testcase.yaml +++ b/tests/cmake/overlays/var_expansions/testcase.yaml @@ -1,7 +1,7 @@ common: tags: cmake build_only: true - platform_allow: native_posix + platform_allow: native_sim tests: buildsystem.overlays.var_expansions.CONF_FILE: extra_conf_files: diff --git a/tests/cmake/snippets/testcase.yaml b/tests/cmake/snippets/testcase.yaml index c8dad26a94f..f584ca3a0fc 100644 --- a/tests/cmake/snippets/testcase.yaml +++ b/tests/cmake/snippets/testcase.yaml @@ -2,11 +2,12 @@ common: tags: snippets platform_allow: - native_posix + - native_sim - qemu_x86 - qemu_x86_64 - qemu_cortex_m3 integration_platforms: - - native_posix + - native_sim tests: # Test the initial state with no snippets applied diff --git a/tests/cmake/zephyr_get/testcase.yaml b/tests/cmake/zephyr_get/testcase.yaml index 5159efb093c..02b8a7fc17f 100644 --- a/tests/cmake/zephyr_get/testcase.yaml +++ b/tests/cmake/zephyr_get/testcase.yaml @@ -1,7 +1,7 @@ common: tags: cmake build_only: true - platform_allow: native_posix + platform_allow: native_sim tests: buildsystem.extensions.zephyr_get.no_sysbuild: sysbuild: false From e6f6d60cd9b4f78bcfb3f4cee9dc66ce9a695978 Mon Sep 17 00:00:00 2001 From: Alberto Escolar Piedras Date: Thu, 23 Nov 2023 16:48:59 +0100 Subject: [PATCH 0291/3723] tests/drivers/udc: Switch to native_sim_64 Enable this test which run in native_posix_64 in native_sim_64, And switch native_posix_64 overlays to native_sim_64. Signed-off-by: Alberto Escolar Piedras --- .../udc/boards/{native_posix_64.conf => native_sim_64.conf} | 0 .../boards/{native_posix_64.overlay => native_sim_64.overlay} | 0 tests/drivers/udc/testcase.yaml | 2 +- 3 files changed, 1 insertion(+), 1 deletion(-) rename tests/drivers/udc/boards/{native_posix_64.conf => native_sim_64.conf} (100%) rename tests/drivers/udc/boards/{native_posix_64.overlay => native_sim_64.overlay} (100%) diff --git a/tests/drivers/udc/boards/native_posix_64.conf b/tests/drivers/udc/boards/native_sim_64.conf similarity index 100% rename from tests/drivers/udc/boards/native_posix_64.conf rename to tests/drivers/udc/boards/native_sim_64.conf diff --git a/tests/drivers/udc/boards/native_posix_64.overlay b/tests/drivers/udc/boards/native_sim_64.overlay similarity index 100% rename from tests/drivers/udc/boards/native_posix_64.overlay rename to tests/drivers/udc/boards/native_sim_64.overlay diff --git a/tests/drivers/udc/testcase.yaml b/tests/drivers/udc/testcase.yaml index 97b644d6d8c..e15fdd6761c 100644 --- a/tests/drivers/udc/testcase.yaml +++ b/tests/drivers/udc/testcase.yaml @@ -5,4 +5,4 @@ tests: - drivers platform_allow: - nrf52840dk_nrf52840 - - native_posix_64 + - native_sim_64 From f2283df0ef1809dfe54678fde28395b0ed2ad754 Mon Sep 17 00:00:00 2001 From: Alberto Escolar Piedras Date: Thu, 23 Nov 2023 16:54:02 +0100 Subject: [PATCH 0292/3723] tests/drivers/clock_control/fixed_clock: Enable for native_sim_64 Switch from native_posix_64 to native_sim_64 as default test platform Signed-off-by: Alberto Escolar Piedras --- tests/drivers/clock_control/fixed_clock/testcase.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/drivers/clock_control/fixed_clock/testcase.yaml b/tests/drivers/clock_control/fixed_clock/testcase.yaml index 1f0e6c16126..dc4d34c6e5c 100644 --- a/tests/drivers/clock_control/fixed_clock/testcase.yaml +++ b/tests/drivers/clock_control/fixed_clock/testcase.yaml @@ -4,4 +4,4 @@ tests: - drivers - clock platform_allow: - - native_posix_64 + - native_sim_64 From b51f0ee4cddf246cb1dcec8c24dda72351529641 Mon Sep 17 00:00:00 2001 From: Alberto Escolar Piedras Date: Thu, 23 Nov 2023 16:56:04 +0100 Subject: [PATCH 0293/3723] tests/subsys/testsuite/fff_fake_contexts: Enable for native_sim Enable this test which runs in native_posix_64 in native_sim, Switch from native_posix_64 to native_sim_64 as default test platform Signed-off-by: Alberto Escolar Piedras --- tests/subsys/testsuite/fff_fake_contexts/testcase.yaml | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/tests/subsys/testsuite/fff_fake_contexts/testcase.yaml b/tests/subsys/testsuite/fff_fake_contexts/testcase.yaml index bb17487fe72..894e0f1aa99 100644 --- a/tests/subsys/testsuite/fff_fake_contexts/testcase.yaml +++ b/tests/subsys/testsuite/fff_fake_contexts/testcase.yaml @@ -8,8 +8,10 @@ tests: testing.testsuite.fff_fake_contexts: integration_platforms: - qemu_cortex_m3 - - native_posix_64 + - native_sim_64 tags: test_framework platform_allow: - qemu_cortex_m3 - native_posix_64 + - native_sim_64 + - native_sim From fd095c36b99437c80c9835325f238abeb5c0c28f Mon Sep 17 00:00:00 2001 From: Alberto Escolar Piedras Date: Thu, 23 Nov 2023 16:58:52 +0100 Subject: [PATCH 0294/3723] tests/lib/gui/lvgl: Enable for native_sim Enable this test which runs in native_posix_64 in native_sim(_64), and set default test platform to native_sim. Signed-off-by: Alberto Escolar Piedras --- tests/lib/gui/lvgl/testcase.yaml | 40 +++++++++----------------------- 1 file changed, 11 insertions(+), 29 deletions(-) diff --git a/tests/lib/gui/lvgl/testcase.yaml b/tests/lib/gui/lvgl/testcase.yaml index 4b35bcb7d10..fca009d9113 100644 --- a/tests/lib/gui/lvgl/testcase.yaml +++ b/tests/lib/gui/lvgl/testcase.yaml @@ -1,54 +1,36 @@ +common: + tags: + - display + - gui + platform_allow: + - native_posix_64 + - native_sim_64 + - native_sim + integration_platforms: + - native_sim tests: - libraries.gui.lvgl: - tags: - - display - - gui - platform_allow: native_posix_64 + libraries.gui.lvgl: {} libraries.gui.lvgl.dynamic.heap.libc: filter: CONFIG_FULL_LIBC_SUPPORTED - tags: - - display - - gui - platform_allow: native_posix_64 extra_configs: - CONFIG_REQUIRES_FULL_LIBC=y - CONFIG_LV_Z_BUFFER_ALLOC_DYNAMIC=y - CONFIG_LV_Z_MEM_POOL_HEAP_LIB_C=y libraries.gui.lvgl.dynamic.pool.sys_heap: - tags: - - display - - gui - platform_allow: native_posix_64 extra_configs: - CONFIG_LV_Z_BUFFER_ALLOC_DYNAMIC=y - CONFIG_LV_Z_MEM_POOL_SYS_HEAP=y - CONFIG_LV_Z_MEM_POOL_SIZE=98304 libraries.gui.lvgl.16bit: - tags: - - display - - gui - platform_allow: native_posix_64 extra_configs: - CONFIG_LV_COLOR_DEPTH_16=y libraries.gui.lvgl.8bit: - tags: - - display - - gui - platform_allow: native_posix_64 extra_configs: - CONFIG_LV_COLOR_DEPTH_8=y libraries.gui.lvgl.mono: - tags: - - display - - gui - platform_allow: native_posix_64 extra_configs: - CONFIG_LV_COLOR_DEPTH_1=y libraries.gui.lvgl.16bit.swap: - tags: - - display - - gui - platform_allow: native_posix_64 extra_configs: - CONFIG_LV_COLOR_DEPTH_16=y - CONFIG_LV_COLOR_16_SWAP=y From 7b1813e9dcfb36b6472eb979fd11995729597619 Mon Sep 17 00:00:00 2001 From: Alberto Escolar Piedras Date: Thu, 23 Nov 2023 18:23:34 +0100 Subject: [PATCH 0295/3723] tests/drivers/build_all/*: Switch to native_sim Enable all these tests which run in native_posix in native_sim, Switch from native_posix to native_sim as default test platform And switch native_posix overlays to native_sim. Signed-off-by: Alberto Escolar Piedras --- .../adc/boards/{native_posix.overlay => native_sim.overlay} | 0 .../boards/{native_posix_64.overlay => native_sim_64.overlay} | 2 +- tests/drivers/build_all/adc/testcase.yaml | 4 ++-- tests/drivers/build_all/charger/testcase.yaml | 4 +++- tests/drivers/build_all/dac/testcase.yaml | 4 +++- tests/drivers/build_all/fpga/testcase.yaml | 4 +++- tests/drivers/build_all/ieee802154/testcase.yaml | 4 +++- tests/drivers/build_all/input/testcase.yaml | 4 +++- tests/drivers/build_all/mfd/testcase.yaml | 4 +++- tests/drivers/build_all/modem/testcase.yaml | 2 ++ tests/drivers/build_all/regulator/testcase.yaml | 4 +++- tests/drivers/build_all/video/testcase.yaml | 4 +++- 12 files changed, 29 insertions(+), 11 deletions(-) rename tests/drivers/build_all/adc/boards/{native_posix.overlay => native_sim.overlay} (100%) rename tests/drivers/build_all/adc/boards/{native_posix_64.overlay => native_sim_64.overlay} (74%) diff --git a/tests/drivers/build_all/adc/boards/native_posix.overlay b/tests/drivers/build_all/adc/boards/native_sim.overlay similarity index 100% rename from tests/drivers/build_all/adc/boards/native_posix.overlay rename to tests/drivers/build_all/adc/boards/native_sim.overlay diff --git a/tests/drivers/build_all/adc/boards/native_posix_64.overlay b/tests/drivers/build_all/adc/boards/native_sim_64.overlay similarity index 74% rename from tests/drivers/build_all/adc/boards/native_posix_64.overlay rename to tests/drivers/build_all/adc/boards/native_sim_64.overlay index b5655714d89..16e56822d5f 100644 --- a/tests/drivers/build_all/adc/boards/native_posix_64.overlay +++ b/tests/drivers/build_all/adc/boards/native_sim_64.overlay @@ -3,4 +3,4 @@ * SPDX-License-Identifier: Apache-2.0 */ -#include "native_posix.overlay" +#include "native_sim.overlay" diff --git a/tests/drivers/build_all/adc/testcase.yaml b/tests/drivers/build_all/adc/testcase.yaml index a8102364b60..3b8995e1769 100644 --- a/tests/drivers/build_all/adc/testcase.yaml +++ b/tests/drivers/build_all/adc/testcase.yaml @@ -7,8 +7,8 @@ tests: drivers.adc.build: # will cover I2C, SPI, and emul based drivers platform_allow: - - native_posix - - native_posix_64 + - native_sim + - native_sim_64 extra_args: "CONFIG_GPIO=y" drivers.adc.cc32xx.build: platform_allow: cc3220sf_launchxl diff --git a/tests/drivers/build_all/charger/testcase.yaml b/tests/drivers/build_all/charger/testcase.yaml index f2005d9f238..0a29ccc7b39 100644 --- a/tests/drivers/build_all/charger/testcase.yaml +++ b/tests/drivers/build_all/charger/testcase.yaml @@ -7,4 +7,6 @@ tests: - drivers - charger build_only: true - platform_allow: native_posix + platform_allow: + - native_posix + - native_sim diff --git a/tests/drivers/build_all/dac/testcase.yaml b/tests/drivers/build_all/dac/testcase.yaml index 12252b8661f..a298ded77b4 100644 --- a/tests/drivers/build_all/dac/testcase.yaml +++ b/tests/drivers/build_all/dac/testcase.yaml @@ -6,7 +6,9 @@ common: tests: drivers.dac.build: # will cover I2C, SPI based drivers - platform_allow: native_posix + platform_allow: + - native_posix + - native_sim extra_args: "CONFIG_GPIO=y" drivers.dac.mcux.build: platform_allow: frdm_k22f diff --git a/tests/drivers/build_all/fpga/testcase.yaml b/tests/drivers/build_all/fpga/testcase.yaml index 33cccf76dde..ad0d3e8123e 100644 --- a/tests/drivers/build_all/fpga/testcase.yaml +++ b/tests/drivers/build_all/fpga/testcase.yaml @@ -2,7 +2,9 @@ common: tags: - drivers - sensors - platform_allow: native_posix + platform_allow: + - native_posix + - native_sim build_only: true tests: drivers.fpga.build: diff --git a/tests/drivers/build_all/ieee802154/testcase.yaml b/tests/drivers/build_all/ieee802154/testcase.yaml index fd9fb07e062..399f3fac3cf 100644 --- a/tests/drivers/build_all/ieee802154/testcase.yaml +++ b/tests/drivers/build_all/ieee802154/testcase.yaml @@ -5,7 +5,9 @@ common: build_only: true tests: ieee802154.build.external: - platform_allow: native_posix + platform_allow: + - native_posix + - native_sim ieee802154.build.cc13xx_cc26xx: platform_allow: cc1352r_sensortag ieee802154.build.kw41z: diff --git a/tests/drivers/build_all/input/testcase.yaml b/tests/drivers/build_all/input/testcase.yaml index 2831b693e28..eb915db1673 100644 --- a/tests/drivers/build_all/input/testcase.yaml +++ b/tests/drivers/build_all/input/testcase.yaml @@ -3,7 +3,9 @@ common: - drivers - input build_only: true - platform_allow: native_posix + platform_allow: + - native_posix + - native_sim tests: drivers.input.default: {} diff --git a/tests/drivers/build_all/mfd/testcase.yaml b/tests/drivers/build_all/mfd/testcase.yaml index 80864481bdf..126fdb40e55 100644 --- a/tests/drivers/build_all/mfd/testcase.yaml +++ b/tests/drivers/build_all/mfd/testcase.yaml @@ -5,4 +5,6 @@ common: - mfd tests: drivers.mfd.build: - platform_allow: native_posix + platform_allow: + - native_posix + - native_sim diff --git a/tests/drivers/build_all/modem/testcase.yaml b/tests/drivers/build_all/modem/testcase.yaml index 89abfbd79df..25c338b9fda 100644 --- a/tests/drivers/build_all/modem/testcase.yaml +++ b/tests/drivers/build_all/modem/testcase.yaml @@ -79,6 +79,8 @@ tests: platform_allow: - native_posix_64 - native_posix + - native_sim_64 + - native_sim - qemu_x86 - qemu_x86_64 min_ram: 36 diff --git a/tests/drivers/build_all/regulator/testcase.yaml b/tests/drivers/build_all/regulator/testcase.yaml index 9b9c25511c4..58fc0851981 100644 --- a/tests/drivers/build_all/regulator/testcase.yaml +++ b/tests/drivers/build_all/regulator/testcase.yaml @@ -7,4 +7,6 @@ tests: - drivers - regulator build_only: true - platform_allow: native_posix + platform_allow: + - native_posix + - native_sim diff --git a/tests/drivers/build_all/video/testcase.yaml b/tests/drivers/build_all/video/testcase.yaml index 22595c7be54..08dd430da73 100644 --- a/tests/drivers/build_all/video/testcase.yaml +++ b/tests/drivers/build_all/video/testcase.yaml @@ -5,7 +5,9 @@ common: - video tests: drivers.video.build: - platform_allow: native_posix + platform_allow: + - native_posix + - native_sim min_ram: 32 depends_on: - gpio From a8d56c4f1f874bebfdce7f411e40eca94938dd4b Mon Sep 17 00:00:00 2001 From: Seppo Takalo Date: Thu, 23 Nov 2023 16:59:57 +0200 Subject: [PATCH 0296/3723] net: scripts: Use native_sim instead of native_posix Sample tests should also be using native_sim board. Signed-off-by: Seppo Takalo --- scripts/net/run-sample-tests.sh | 2 +- tests/net/lib/lwm2m/interop/docker-test.sh | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/scripts/net/run-sample-tests.sh b/scripts/net/run-sample-tests.sh index 11162b30b5e..85f5d62efc9 100755 --- a/scripts/net/run-sample-tests.sh +++ b/scripts/net/run-sample-tests.sh @@ -157,7 +157,7 @@ start_zephyr () fi rm -rf build && mkdir build && \ - cmake -GNinja -DBOARD=native_posix -B build "$@" . && \ + cmake -GNinja -DBOARD=native_sim -B build "$@" . && \ ninja -C build # Run the binary directly so that ninja does not print errors that diff --git a/tests/net/lib/lwm2m/interop/docker-test.sh b/tests/net/lib/lwm2m/interop/docker-test.sh index 9184461aec4..4efeec96257 100644 --- a/tests/net/lib/lwm2m/interop/docker-test.sh +++ b/tests/net/lib/lwm2m/interop/docker-test.sh @@ -13,7 +13,7 @@ FWD="-p 8080:8080 -p 8081:8081 -p 5683:5683/udp" start_configuration "$IP $FWD" || return $? start_docker "/net-tools/start-leshan.sh" || return $? -twister -p native_posix -T ./ --enable-slow -vv +twister -p native_sim -T ./ --enable-slow -vv result=$? From 09fd6b6ea5a7f8bf39902963feff8e167bc869dd Mon Sep 17 00:00:00 2001 From: Carlo Caione Date: Sat, 23 Sep 2023 17:34:25 +0200 Subject: [PATCH 0297/3723] mem_mgmt: Add a memory attributes memory allocator Using this new library it is now possible to leverage the memory attribute property 'zephyr,memory-attr' to define and create a set of memory heaps from which the user can allocate memory from with certain attributes / capabilities. When the CONFIG_MEM_ATTR_HEAP option is set, every region marked with one of the memory attributes listed in include/zephyr/dt-bindings/memory-attr/memory-attr-sw.h is added to a pool of memory heaps used for dynamic allocation of memory buffers with certain attributes. Signed-off-by: Carlo Caione --- .../dt-bindings/memory-attr/memory-attr-sw.h | 27 ++++ include/zephyr/mem_mgmt/mem_attr_heap.h | 98 +++++++++++++ subsys/mem_mgmt/CMakeLists.txt | 1 + subsys/mem_mgmt/Kconfig | 7 + subsys/mem_mgmt/mem_attr_heap.c | 136 ++++++++++++++++++ 5 files changed, 269 insertions(+) create mode 100644 include/zephyr/dt-bindings/memory-attr/memory-attr-sw.h create mode 100644 include/zephyr/mem_mgmt/mem_attr_heap.h create mode 100644 subsys/mem_mgmt/mem_attr_heap.c diff --git a/include/zephyr/dt-bindings/memory-attr/memory-attr-sw.h b/include/zephyr/dt-bindings/memory-attr/memory-attr-sw.h new file mode 100644 index 00000000000..ccd47addf11 --- /dev/null +++ b/include/zephyr/dt-bindings/memory-attr/memory-attr-sw.h @@ -0,0 +1,27 @@ +/* + * Copyright (c) 2023 Carlo Caione + * + * SPDX-License-Identifier: Apache-2.0 + */ +#ifndef ZEPHYR_INCLUDE_DT_BINDINGS_MEM_ATTR_SW_H_ +#define ZEPHYR_INCLUDE_DT_BINDINGS_MEM_ATTR_SW_H_ + +#include +#include + +/* + * Software specific memory attributes. + */ +#define DT_MEM_SW_MASK DT_MEM_SW_ATTR_MASK +#define DT_MEM_SW_GET(x) ((x) & DT_MEM_SW_ATTR_MASK) +#define DT_MEM_SW(x) ((x) << DT_MEM_SW_ATTR_SHIFT) + +#define ATTR_SW_ALLOC_CACHE BIT(0) +#define ATTR_SW_ALLOC_NON_CACHE BIT(1) +#define ATTR_SW_ALLOC_DMA BIT(2) + +#define DT_MEM_SW_ALLOC_CACHE DT_MEM_SW(ATTR_SW_ALLOC_CACHE) +#define DT_MEM_SW_ALLOC_NON_CACHE DT_MEM_SW(ATTR_SW_ALLOC_NON_CACHE) +#define DT_MEM_SW_ALLOC_DMA DT_MEM_SW(ATTR_SW_ALLOC_DMA) + +#endif /* ZEPHYR_INCLUDE_DT_BINDINGS_MEM_ATTR_SW_H_ */ diff --git a/include/zephyr/mem_mgmt/mem_attr_heap.h b/include/zephyr/mem_mgmt/mem_attr_heap.h new file mode 100644 index 00000000000..60cf183dd49 --- /dev/null +++ b/include/zephyr/mem_mgmt/mem_attr_heap.h @@ -0,0 +1,98 @@ +/* + * Copyright (c) 2023 Carlo Caione, + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#ifndef ZEPHYR_INCLUDE_MEM_ATTR_HEAP_H_ +#define ZEPHYR_INCLUDE_MEM_ATTR_HEAP_H_ + +/** + * @brief Memory heaps based on memory attributes + * @defgroup memory_attr_heap Memory heaps based on memory attributes + * @ingroup mem_mgmt + * @{ + */ + +#include + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * @brief Init the memory pool + * + * This must be the first function to be called to initialize the memory pools + * from all the memory regions with the a software attribute. + * + * @retval 0 on success. + * @retval -EALREADY if the pool was already initialized. + * @retval -ENOMEM too many regions already allocated. + */ +int mem_attr_heap_pool_init(void); + +/** + * @brief Allocate memory with a specified attribute and size. + * + * Allocates a block of memory of the specified size in bytes and with a + * specified capability / attribute. The attribute is used to select the + * correct memory heap to allocate memory from. + * + * @param attr capability / attribute requested for the memory block. + * @param bytes requested size of the allocation in bytes. + * + * @retval ptr a valid pointer to the allocated memory. + * @retval NULL if no memory is available with that attribute and size. + */ +void *mem_attr_heap_alloc(uint32_t attr, size_t bytes); + +/** + * @brief Allocate aligned memory with a specified attribute, size and alignment. + * + * Allocates a block of memory of the specified size in bytes and with a + * specified capability / attribute. Takes an additional parameter specifying a + * power of two alignment in bytes. + * + * @param attr capability / attribute requested for the memory block. + * @param align power of two alignment for the returned pointer in bytes. + * @param bytes requested size of the allocation in bytes. + * + * @retval ptr a valid pointer to the allocated memory. + * @retval NULL if no memory is available with that attribute and size. + */ +void *mem_attr_heap_aligned_alloc(uint32_t attr, size_t align, size_t bytes); + +/** + * @brief Free the allocated memory + * + * Used to free the passed block of memory that must be the return value of a + * previously call to @ref mem_attr_heap_alloc or @ref + * mem_attr_heap_aligned_alloc. + * + * @param block block to free, must be a pointer to a block allocated by + * @ref mem_attr_heap_alloc or @ref mem_attr_heap_aligned_alloc. + */ +void mem_attr_heap_free(void *block); + +/** + * @brief Get a specific memory region descriptor for a provided address + * + * Finds the memory region descriptor struct controlling the provided pointer. + * + * @param addr address to be found, must be a pointer to a block allocated by + * @ref mem_attr_heap_alloc or @ref mem_attr_heap_aligned_alloc. + * + * @retval str pointer to a memory region structure the address belongs to. + */ +const struct mem_attr_region_t *mem_attr_heap_get_region(void *addr); + +#ifdef __cplusplus +} +#endif + +/** + * @} + */ + +#endif /* ZEPHYR_INCLUDE_MEM_ATTR_HEAP_H_ */ diff --git a/subsys/mem_mgmt/CMakeLists.txt b/subsys/mem_mgmt/CMakeLists.txt index 62e61fb4d1f..d2fcd1a72f2 100644 --- a/subsys/mem_mgmt/CMakeLists.txt +++ b/subsys/mem_mgmt/CMakeLists.txt @@ -1,3 +1,4 @@ # SPDX-License-Identifier: Apache-2.0 zephyr_sources_ifdef(CONFIG_MEM_ATTR mem_attr.c) +zephyr_sources_ifdef(CONFIG_MEM_ATTR_HEAP mem_attr_heap.c) diff --git a/subsys/mem_mgmt/Kconfig b/subsys/mem_mgmt/Kconfig index dda1a404167..b381b3892e5 100644 --- a/subsys/mem_mgmt/Kconfig +++ b/subsys/mem_mgmt/Kconfig @@ -10,3 +10,10 @@ config MEM_ATTR time an array of the memory regions defined in the DT that can be probed at run-time using several helper functions. Set to `N` if unsure to save RODATA space. + +config MEM_ATTR_HEAP + bool "Memory Attributes heap allocator" + depends on MEM_ATTR + help + Enable an heap allocator based on memory attributes to dynamically + allocate memory from DeviceTree defined memory regions. diff --git a/subsys/mem_mgmt/mem_attr_heap.c b/subsys/mem_mgmt/mem_attr_heap.c new file mode 100644 index 00000000000..e1b3578a4ed --- /dev/null +++ b/subsys/mem_mgmt/mem_attr_heap.c @@ -0,0 +1,136 @@ +/* + * Copyright (c) 2021 Carlo Caione, + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include +#include +#include +#include +#include +#include +#include + +struct ma_heap { + struct sys_heap heap; + uint32_t attr; +}; + +struct { + struct ma_heap ma_heaps[MAX_MULTI_HEAPS]; + struct sys_multi_heap multi_heap; + int nheaps; +} mah_data; + +static void *mah_choice(struct sys_multi_heap *m_heap, void *cfg, size_t align, size_t size) +{ + uint32_t attr; + void *block; + + if (size == 0) { + return NULL; + } + + attr = (uint32_t)(long) cfg; + + /* Set in case the user requested a non-existing attr */ + block = NULL; + + for (size_t hdx = 0; hdx < mah_data.nheaps; hdx++) { + struct ma_heap *h; + + h = &mah_data.ma_heaps[hdx]; + + if (h->attr != attr) { + continue; + } + + block = sys_heap_aligned_alloc(&h->heap, align, size); + if (block != NULL) { + break; + } + } + + return block; +} + +void mem_attr_heap_free(void *block) +{ + sys_multi_heap_free(&mah_data.multi_heap, block); +} + +void *mem_attr_heap_alloc(uint32_t attr, size_t bytes) +{ + return sys_multi_heap_alloc(&mah_data.multi_heap, + (void *)(long) attr, bytes); +} + +void *mem_attr_heap_aligned_alloc(uint32_t attr, size_t align, size_t bytes) +{ + return sys_multi_heap_aligned_alloc(&mah_data.multi_heap, + (void *)(long) attr, align, bytes); +} + +const struct mem_attr_region_t *mem_attr_heap_get_region(void *addr) +{ + const struct sys_multi_heap_rec *heap_rec; + + heap_rec = sys_multi_heap_get_heap(&mah_data.multi_heap, addr); + + return (const struct mem_attr_region_t *) heap_rec->user_data; +} + +static int ma_heap_add(const struct mem_attr_region_t *region, uint32_t attr) +{ + struct ma_heap *mh; + struct sys_heap *h; + + /* No more heaps available */ + if (mah_data.nheaps >= MAX_MULTI_HEAPS) { + return -ENOMEM; + } + + mh = &mah_data.ma_heaps[mah_data.nheaps++]; + h = &mh->heap; + + mh->attr = attr; + + sys_heap_init(h, (void *) region->dt_addr, region->dt_size); + sys_multi_heap_add_heap(&mah_data.multi_heap, h, (void *) region); + + return 0; +} + + +int mem_attr_heap_pool_init(void) +{ + const struct mem_attr_region_t *regions; + static atomic_t state; + size_t num_regions; + + if (!atomic_cas(&state, 0, 1)) { + return -EALREADY; + } + + sys_multi_heap_init(&mah_data.multi_heap, mah_choice); + + num_regions = mem_attr_get_regions(®ions); + + for (size_t idx = 0; idx < num_regions; idx++) { + uint32_t sw_attr; + + sw_attr = DT_MEM_SW_ATTR_GET(regions[idx].dt_attr); + + /* No SW attribute is present */ + if (!sw_attr) { + continue; + } + + if (ma_heap_add(®ions[idx], sw_attr)) { + return -ENOMEM; + } + } + + return 0; +} From 06571fc87b2e48132aaea04885ea030aaa92d96f Mon Sep 17 00:00:00 2001 From: Carlo Caione Date: Sat, 23 Sep 2023 17:34:32 +0200 Subject: [PATCH 0298/3723] doc: Add documentation for the new allocator Add new documentation for the new attribute-based memory allocator. Signed-off-by: Carlo Caione --- doc/services/mem_mgmt/index.rst | 105 ++++++++++++++++++++++++++++++++ 1 file changed, 105 insertions(+) diff --git a/doc/services/mem_mgmt/index.rst b/doc/services/mem_mgmt/index.rst index eb689c409d1..d42b72ebe51 100644 --- a/doc/services/mem_mgmt/index.rst +++ b/doc/services/mem_mgmt/index.rst @@ -84,7 +84,112 @@ one by renaming the property and changing its value according to the following l "IO" -> <( DT_ARM_MPU(ATTR_MPU_IO) )> "EXTMEM" -> <( DT_ARM_MPU(ATTR_MPU_EXTMEM) )> +Memory Attributes Heap Allocator +******************************** + +It is possible to leverage the memory attribute property ``zephyr,memory-attr`` +to define and create a set of memory heaps from which the user can allocate +memory from with certain attributes / capabilities. + +When the :kconfig:option:`CONFIG_MEM_ATTR_HEAP` is set, every region marked +with one of the memory attributes listed in in +:zephyr_file:`include/zephyr/dt-bindings/memory-attr/memory-attr-sw.h` is added +to a pool of memory heaps used for dynamic allocation of memory buffers with +certain attributes. + +Here a non exhaustive list of possible attributes: + +.. code-block:: none + + DT_MEM_SW_ALLOC_CACHE + DT_MEM_SW_ALLOC_NON_CACHE + DT_MEM_SW_ALLOC_DMA + +For example we can define several memory regions with different attributes and +use the appropriate attribute to indicate that it is possible to dynamically +allocate memory from those regions: + +.. code-block:: devicetree + + mem_cacheable: memory@10000000 { + compatible = "mmio-sram"; + reg = <0x10000000 0x1000>; + zephyr,memory-attr = <( DT_MEM_CACHEABLE | DT_MEM_SW_ALLOC_CACHE )>; + }; + + mem_non_cacheable: memory@20000000 { + compatible = "mmio-sram"; + reg = <0x20000000 0x1000>; + zephyr,memory-attr = <( DT_MEM_NON_CACHEABLE | ATTR_SW_ALLOC_NON_CACHE )>; + }; + + mem_cacheable_big: memory@30000000 { + compatible = "mmio-sram"; + reg = <0x30000000 0x10000>; + zephyr,memory-attr = <( DT_MEM_CACHEABLE | DT_MEM_OOO | DT_MEM_SW_ALLOC_CACHE )>; + }; + + mem_cacheable_dma: memory@40000000 { + compatible = "mmio-sram"; + reg = <0x40000000 0x10000>; + zephyr,memory-attr = <( DT_MEM_CACHEABLE | DT_MEM_DMA | + DT_MEM_SW_ALLOC_CACHE | DT_MEM_SW_ALLOC_DMA )>; + }; + +The user can then dynamically carve memory out of those regions using the +provided functions, the library will take care of allocating memory from the +correct heap depending on the provided attribute and size: + +.. code-block:: c + + // Init the pool + mem_attr_heap_pool_init(); + + // Allocate 0x100 bytes of cacheable memory from `mem_cacheable` + block = mem_attr_heap_alloc(DT_MEM_SW_ALLOC_CACHE, 0x100); + + // Allocate 0x200 bytes of non-cacheable memory aligned to 32 bytes + // from `mem_non_cacheable` + block = mem_attr_heap_aligned_alloc(ATTR_SW_ALLOC_NON_CACHE, 0x100, 32); + + // Allocate 0x100 bytes of cacheable and dma-able memory from `mem_cacheable_dma` + block = mem_attr_heap_alloc(DT_MEM_SW_ALLOC_CACHE | DT_MEM_SW_ALLOC_DMA, 0x100); + +When several regions are marked with the same attributes, the memory is allocated: + +1. From the regions where the ``zephyr,memory-attr`` property has the requested + property (or properties). + +2. Among the regions as at point 1, from the smallest region if there is any + unallocated space left for the requested size + +3. If there is not enough space, from the next bigger region able to + accommodate the requested size + +The following example shows the point 3: + +.. code-block:: c + + // This memory is allocated from `mem_non_cacheable` + block = mem_attr_heap_alloc(DT_MEM_SW_ALLOC_CACHE, 0x100); + + // This memory is allocated from `mem_cacheable_big` + block = mem_attr_heap_alloc(DT_MEM_SW_ALLOC_CACHE, 0x5000); + +.. note:: + + The framework is assuming that the memory regions used to create the heaps + are usable by the code and available at init time. The user must take of + initializing and setting the memory area before calling + :c:func:`mem_attr_heap_pool_init`. + + That means that the region must be correctly configured in terms of MPU / + MMU (if needed) and that an actual heap can be created out of it, for + example by leveraging the ``zephyr,memory-region`` property to create a + proper linker section to accommodate the heap. + API Reference ************* .. doxygengroup:: memory_attr_interface +.. doxygengroup:: memory_attr_heap From 90257890648fa4ae13f2514958309c918ee236a0 Mon Sep 17 00:00:00 2001 From: Carlo Caione Date: Sat, 23 Sep 2023 17:34:38 +0200 Subject: [PATCH 0299/3723] tests: Add test for the memory allocator Add a new test for the attribute-based memory allocator. Signed-off-by: Carlo Caione --- .../mem_mgmt/mem_attr_heap/CMakeLists.txt | 8 + .../boards/qemu_cortex_m3.overlay | 52 +++++++ tests/subsys/mem_mgmt/mem_attr_heap/prj.conf | 6 + .../subsys/mem_mgmt/mem_attr_heap/src/main.c | 145 ++++++++++++++++++ .../mem_mgmt/mem_attr_heap/testcase.yaml | 9 ++ 5 files changed, 220 insertions(+) create mode 100644 tests/subsys/mem_mgmt/mem_attr_heap/CMakeLists.txt create mode 100644 tests/subsys/mem_mgmt/mem_attr_heap/boards/qemu_cortex_m3.overlay create mode 100644 tests/subsys/mem_mgmt/mem_attr_heap/prj.conf create mode 100644 tests/subsys/mem_mgmt/mem_attr_heap/src/main.c create mode 100644 tests/subsys/mem_mgmt/mem_attr_heap/testcase.yaml diff --git a/tests/subsys/mem_mgmt/mem_attr_heap/CMakeLists.txt b/tests/subsys/mem_mgmt/mem_attr_heap/CMakeLists.txt new file mode 100644 index 00000000000..bebaf8dd83b --- /dev/null +++ b/tests/subsys/mem_mgmt/mem_attr_heap/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(mem_attr_heap) + +target_sources(app PRIVATE src/main.c) diff --git a/tests/subsys/mem_mgmt/mem_attr_heap/boards/qemu_cortex_m3.overlay b/tests/subsys/mem_mgmt/mem_attr_heap/boards/qemu_cortex_m3.overlay new file mode 100644 index 00000000000..dc2e25a4e0d --- /dev/null +++ b/tests/subsys/mem_mgmt/mem_attr_heap/boards/qemu_cortex_m3.overlay @@ -0,0 +1,52 @@ +#include +#include +#include + +/ { + mem_cache: memory@20008000 { + compatible = "zephyr,memory-region", "mmio-sram"; + reg = <0x20008000 0x1000>; + zephyr,memory-region = "MEM_CACHEABLE"; + zephyr,memory-attr = <( DT_MEM_CACHEABLE )>; + }; + + mem_cache_sw: memory@20009000 { + compatible = "zephyr,memory-region", "mmio-sram"; + reg = <0x20009000 0x1000>; + zephyr,memory-region = "MEM_CACHEABLE_SW"; + zephyr,memory-attr = <( DT_MEM_CACHEABLE | DT_MEM_SW_ALLOC_CACHE )>; + }; + + mem_noncache_sw: memory@2000A000 { + compatible = "zephyr,memory-region", "mmio-sram"; + reg = <0x2000A000 0x1000>; + zephyr,memory-region = "MEM_NON_CACHEABLE_SW"; + zephyr,memory-attr = <( DT_MEM_SW_ALLOC_NON_CACHE )>; + }; + + mem_dma_sw: memory@2000B000 { + compatible = "zephyr,memory-region", "mmio-sram"; + reg = <0x2000B000 0x1000>; + zephyr,memory-region = "MEM_DMA_SW"; + zephyr,memory-attr = <( DT_MEM_DMA | DT_MEM_SW_ALLOC_DMA )>; + }; + + mem_cache_sw_big: memory@2000C000 { + compatible = "zephyr,memory-region", "mmio-sram"; + reg = <0x2000C000 0x2000>; + zephyr,memory-region = "MEM_CACHEABLE_SW_BIG"; + zephyr,memory-attr = <( DT_MEM_CACHEABLE | DT_MEM_SW_ALLOC_CACHE )>; + }; + + mem_cache_cache_dma_multi: memory@2000E000 { + compatible = "zephyr,memory-region", "mmio-sram"; + reg = <0x2000E000 0x1000>; + zephyr,memory-region = "MEM_CACHEABLE_SW_MULTI_ATTR"; + zephyr,memory-attr = <( DT_MEM_CACHEABLE | DT_MEM_DMA | + DT_MEM_SW_ALLOC_CACHE | DT_MEM_SW_ALLOC_DMA)>; + }; +}; + +&sram0 { + reg = <0x20000000 DT_SIZE_K(32)>; +}; diff --git a/tests/subsys/mem_mgmt/mem_attr_heap/prj.conf b/tests/subsys/mem_mgmt/mem_attr_heap/prj.conf new file mode 100644 index 00000000000..64c26116108 --- /dev/null +++ b/tests/subsys/mem_mgmt/mem_attr_heap/prj.conf @@ -0,0 +1,6 @@ +# Copyright 2023 Carlo Caione +# SPDX-License-Identifier: Apache-2.0 + +CONFIG_ZTEST=y +CONFIG_MEM_ATTR=y +CONFIG_MEM_ATTR_HEAP=y diff --git a/tests/subsys/mem_mgmt/mem_attr_heap/src/main.c b/tests/subsys/mem_mgmt/mem_attr_heap/src/main.c new file mode 100644 index 00000000000..cf7d6c3bec2 --- /dev/null +++ b/tests/subsys/mem_mgmt/mem_attr_heap/src/main.c @@ -0,0 +1,145 @@ +/* + * Copyright (c) 2023 Carlo Caione + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include +#include +#include +#include + +#define ADDR_MEM_CACHE DT_REG_ADDR(DT_NODELABEL(mem_cache)) +#define ADDR_MEM_CACHE_SW DT_REG_ADDR(DT_NODELABEL(mem_cache_sw)) +#define ADDR_MEM_NON_CACHE_SW DT_REG_ADDR(DT_NODELABEL(mem_noncache_sw)) +#define ADDR_MEM_DMA_SW DT_REG_ADDR(DT_NODELABEL(mem_dma_sw)) +#define ADDR_MEM_CACHE_BIG_SW DT_REG_ADDR(DT_NODELABEL(mem_cache_sw_big)) +#define ADDR_MEM_CACHE_DMA_SW DT_REG_ADDR(DT_NODELABEL(mem_cache_cache_dma_multi)) + +ZTEST(mem_attr_heap, test_mem_attr_heap) +{ + const struct mem_attr_region_t *region; + void *block, *old_block; + int ret; + + /* + * Init the pool. + */ + ret = mem_attr_heap_pool_init(); + zassert_equal(0, ret, "Failed initialization"); + + /* + * Any subsequent initialization should fail. + */ + ret = mem_attr_heap_pool_init(); + zassert_equal(-EALREADY, ret, "Second init should be failing"); + + /* + * Allocate 0x100 bytes of cacheable memory. + */ + block = mem_attr_heap_alloc(DT_MEM_SW_ALLOC_CACHE, 0x100); + zassert_not_null(block, "Failed to allocate memory"); + + /* + * Check that the just allocated memory was allocated from the correct + * memory region. + */ + region = mem_attr_heap_get_region(block); + zassert_equal(region->dt_addr, ADDR_MEM_CACHE_SW, + "Memory allocated from the wrong region"); + + /* + * Allocate 0x100 bytes of non-cacheable memory. + */ + block = mem_attr_heap_alloc(DT_MEM_SW_ALLOC_NON_CACHE, 0x100); + zassert_not_null(block, "Failed to allocate memory"); + + /* + * Check that the just allocated memory was allocated from the correct + * memory region. + */ + region = mem_attr_heap_get_region(block); + zassert_equal(region->dt_addr, ADDR_MEM_NON_CACHE_SW, + "Memory allocated from the wrong region"); + + /* + * Allocate 0x100 bytes of DMA memory. + */ + block = mem_attr_heap_alloc(DT_MEM_SW_ALLOC_DMA, 0x100); + zassert_not_null(block, "Failed to allocate memory"); + + /* + * Check that the just allocated memory was allocated from the correct + * memory region. + */ + region = mem_attr_heap_get_region(block); + zassert_equal(region->dt_addr, ADDR_MEM_DMA_SW, + "Memory allocated from the wrong region"); + + /* + * Allocate 0x100 bytes of cacheable and DMA memory. + */ + block = mem_attr_heap_alloc(DT_MEM_SW_ALLOC_CACHE | DT_MEM_SW_ALLOC_DMA, 0x100); + zassert_not_null(block, "Failed to allocate memory"); + + /* + * Check that the just allocated memory was allocated from the correct + * memory region (CACHE + DMA and not just CACHE or just DMA). + */ + region = mem_attr_heap_get_region(block); + zassert_equal(region->dt_addr, ADDR_MEM_CACHE_DMA_SW, + "Memory allocated from the wrong region"); + + /* + * Allocate memory with a non-existing attribute. + */ + block = mem_attr_heap_alloc(DT_MEM_SW(DT_MEM_SW_ATTR_UNKNOWN), 0x100); + zassert_is_null(block, "Memory allocated with non-existing attribute"); + + /* + * Allocate memory too big to fit into the first cacheable memory + * region. It should be allocated from the second bigger memory region. + */ + block = mem_attr_heap_alloc(DT_MEM_SW_ALLOC_CACHE, 0x1500); + zassert_not_null(block, "Failed to allocate memory"); + + /* + * Check that the just allocated memory was allocated from the correct + * (bigger) cacheable memory region + */ + region = mem_attr_heap_get_region(block); + zassert_equal(region->dt_addr, ADDR_MEM_CACHE_BIG_SW, + "Memory allocated from the wrong region"); + + /* + * Try to allocate a buffer too big. + */ + block = mem_attr_heap_alloc(DT_MEM_SW_ALLOC_CACHE, 0x4000); + zassert_is_null(block, "Buffer too big for regions correctly allocated"); + + /* + * Check if the memory is correctly released and can be reused + */ + block = mem_attr_heap_alloc(DT_MEM_SW_ALLOC_CACHE, 0x100); + old_block = block; + mem_attr_heap_free(block); + block = mem_attr_heap_alloc(DT_MEM_SW_ALLOC_CACHE, 0x100); + zassert_equal_ptr(old_block, block, "Memory not correctly released"); + + /* + * Check if the memory is correctly aligned when requested + */ + block = mem_attr_heap_alloc(DT_MEM_SW_ALLOC_NON_CACHE, 0x100); + zassert_true(((uintptr_t) block % 32 != 0), ""); + mem_attr_heap_free(block); + block = mem_attr_heap_aligned_alloc(DT_MEM_SW_ALLOC_NON_CACHE, 0x100, 32); + zassert_true(((uintptr_t) block % 32 == 0), ""); + + /* + * Try with a different alignment + */ + block = mem_attr_heap_aligned_alloc(DT_MEM_SW_ALLOC_NON_CACHE, 0x100, 64); + zassert_true(((uintptr_t) block % 64 == 0), ""); +} + +ZTEST_SUITE(mem_attr_heap, NULL, NULL, NULL, NULL, NULL); diff --git a/tests/subsys/mem_mgmt/mem_attr_heap/testcase.yaml b/tests/subsys/mem_mgmt/mem_attr_heap/testcase.yaml new file mode 100644 index 00000000000..903836ed367 --- /dev/null +++ b/tests/subsys/mem_mgmt/mem_attr_heap/testcase.yaml @@ -0,0 +1,9 @@ +# Copyright 2023 Carlo Caione +# SPDX-License-Identifier: Apache-2.0 + +tests: + mem_mgmt.mem_attr_heap: + platform_allow: + - qemu_cortex_m3 + integration_platforms: + - qemu_cortex_m3 From 683accaef04bcdd24676c334842b8cdb52840459 Mon Sep 17 00:00:00 2001 From: Flavio Ceolin Date: Wed, 22 Nov 2023 22:31:43 +0000 Subject: [PATCH 0300/3723] xtensa: mmu: Include missing header This file uses inline functions declared in cache.h and consequently has to include that file. Signed-off-by: Flavio Ceolin --- arch/xtensa/core/mmu.c | 1 + 1 file changed, 1 insertion(+) diff --git a/arch/xtensa/core/mmu.c b/arch/xtensa/core/mmu.c index 24e47a42b9d..5632d05c1ec 100644 --- a/arch/xtensa/core/mmu.c +++ b/arch/xtensa/core/mmu.c @@ -7,6 +7,7 @@ #include #include #include +#include #define ASID_INVALID 0 From a66667cabac6bf351ea8c552a10efcea9b186731 Mon Sep 17 00:00:00 2001 From: Flavio Ceolin Date: Wed, 22 Nov 2023 22:29:13 +0000 Subject: [PATCH 0301/3723] kernel: mm: Include missing header mm.h uses sys_mm_is_virt_addr_in_range() that is declared in sys/mem_manage.h. Signed-off-by: Flavio Ceolin --- include/zephyr/kernel/internal/mm.h | 1 + 1 file changed, 1 insertion(+) diff --git a/include/zephyr/kernel/internal/mm.h b/include/zephyr/kernel/internal/mm.h index c859e939234..2ebf06463f4 100644 --- a/include/zephyr/kernel/internal/mm.h +++ b/include/zephyr/kernel/internal/mm.h @@ -56,6 +56,7 @@ #include #include #include +#include /* Just like Z_MEM_PHYS_ADDR() but with type safety and assertions */ static inline uintptr_t z_mem_phys_addr(void *virt) From 09e17c17b15cf572568b9c10098fa07e01e86f0b Mon Sep 17 00:00:00 2001 From: Flavio Ceolin Date: Wed, 22 Nov 2023 21:23:25 -0800 Subject: [PATCH 0302/3723] mem_manage: Remove unnecessary header "zephyr/kernel/mm.h" is not needed in "zephyr/sys/mem_manage.h". Signed-off-by: Flavio Ceolin --- include/zephyr/sys/mem_manage.h | 2 -- 1 file changed, 2 deletions(-) diff --git a/include/zephyr/sys/mem_manage.h b/include/zephyr/sys/mem_manage.h index 850a1376eaf..a05b72d3886 100644 --- a/include/zephyr/sys/mem_manage.h +++ b/include/zephyr/sys/mem_manage.h @@ -7,8 +7,6 @@ #ifndef ZEPHYR_INCLUDE_SYS_MEM_MANAGE_H #define ZEPHYR_INCLUDE_SYS_MEM_MANAGE_H -#include - /** * @brief Memory Management * @defgroup memory_management Memory Management From 39564cdf202116efad66f637d59624cee9b93a05 Mon Sep 17 00:00:00 2001 From: Andy Sinclair Date: Mon, 6 Nov 2023 15:49:26 +0000 Subject: [PATCH 0303/3723] boards: shields: npm1300_ek: Settings moved to board overlay The existing npm1300_ek shield overlay has several example voltage and gpio settings. For many use cases these are invalid and need to be overridden, or removed with delete-property. These example configurations have been moved to a board specific overlay. Signed-off-by: Andy Sinclair --- boards/shields/npm1300_ek/npm1300_ek.overlay | 11 +--------- .../npm1300_ek/nrf52dk_nrf52832.overlay | 22 +++++++++++++++++-- 2 files changed, 21 insertions(+), 12 deletions(-) diff --git a/boards/shields/npm1300_ek/npm1300_ek.overlay b/boards/shields/npm1300_ek/npm1300_ek.overlay index c5991f78598..592aa55f124 100644 --- a/boards/shields/npm1300_ek/npm1300_ek.overlay +++ b/boards/shields/npm1300_ek/npm1300_ek.overlay @@ -23,32 +23,23 @@ /* limits are set to min/max allowed values */ npm1300_ek_buck1: BUCK1 { - regulator-min-microvolt = <1800000>; + regulator-min-microvolt = <1000000>; regulator-max-microvolt = <3300000>; }; npm1300_ek_buck2: BUCK2 { regulator-min-microvolt = <1000000>; regulator-max-microvolt = <3300000>; - regulator-init-microvolt = <3300000>; - retention-microvolt = <2500000>; - enable-gpios = <&npm1300_ek_gpio 1 GPIO_ACTIVE_LOW>; - retention-gpios = <&npm1300_ek_gpio 2 GPIO_ACTIVE_HIGH>; - pwm-gpios = <&npm1300_ek_gpio 2 GPIO_ACTIVE_LOW>; }; npm1300_ek_ldo1: LDO1 { regulator-min-microvolt = <1000000>; regulator-max-microvolt = <3300000>; - regulator-initial-mode = ; - enable-gpios = <&npm1300_ek_gpio 2 GPIO_ACTIVE_LOW>; }; npm1300_ek_ldo2: LDO2 { regulator-min-microvolt = <1000000>; regulator-max-microvolt = <3300000>; - regulator-initial-mode = ; - enable-gpios = <&npm1300_ek_gpio 2 GPIO_ACTIVE_LOW>; }; }; diff --git a/samples/shields/npm1300_ek/nrf52dk_nrf52832.overlay b/samples/shields/npm1300_ek/nrf52dk_nrf52832.overlay index 339ad015c0c..762a84311fb 100644 --- a/samples/shields/npm1300_ek/nrf52dk_nrf52832.overlay +++ b/samples/shields/npm1300_ek/nrf52dk_nrf52832.overlay @@ -9,14 +9,32 @@ }; &npm1300_ek_regulators { - dvs-gpios = <&gpio0 17 GPIO_ACTIVE_LOW>, - <&gpio0 18 GPIO_ACTIVE_LOW>; + dvs-gpios = <&gpio0 17 GPIO_ACTIVE_LOW>, + <&gpio0 18 GPIO_ACTIVE_LOW>; }; &npm1300_ek_buck1 { regulator-init-microvolt = <2000000>; }; +&npm1300_ek_buck2 { + regulator-init-microvolt = <3300000>; + retention-microvolt = <2500000>; + enable-gpios = <&npm1300_ek_gpio 1 GPIO_ACTIVE_LOW>; + retention-gpios = <&npm1300_ek_gpio 2 GPIO_ACTIVE_HIGH>; + pwm-gpios = <&npm1300_ek_gpio 2 GPIO_ACTIVE_LOW>; +}; + +&npm1300_ek_ldo1 { + regulator-initial-mode = ; + enable-gpios = <&npm1300_ek_gpio 2 GPIO_ACTIVE_LOW>; +}; + +&npm1300_ek_ldo2 { + regulator-initial-mode = ; + enable-gpios = <&npm1300_ek_gpio 2 GPIO_ACTIVE_LOW>; +}; + &npm1300_ek_pmic { host-int-gpios = <&gpio0 22 0>; pmic-int-pin = <3>; From f3447c0c1ecf7e00ccde87e8b946b4f779aecb16 Mon Sep 17 00:00:00 2001 From: Andy Sinclair Date: Fri, 17 Nov 2023 15:10:17 +0000 Subject: [PATCH 0304/3723] samples: shields: npm1300_ek: Added missing shell configs Sample readme states that shell inteface is supported for evaluation. Added missing GPIO_SHELL and SENSOR_SHELL to Kconfig. Signed-off-by: Andy Sinclair --- samples/shields/npm1300_ek/prj.conf | 2 ++ 1 file changed, 2 insertions(+) diff --git a/samples/shields/npm1300_ek/prj.conf b/samples/shields/npm1300_ek/prj.conf index c8421d9bf0c..975d56d4e50 100644 --- a/samples/shields/npm1300_ek/prj.conf +++ b/samples/shields/npm1300_ek/prj.conf @@ -4,7 +4,9 @@ CONFIG_SHELL=y CONFIG_LOG=y CONFIG_GPIO=y +CONFIG_GPIO_SHELL=y CONFIG_REGULATOR=y CONFIG_REGULATOR_SHELL=y CONFIG_SENSOR=y +CONFIG_SENSOR_SHELL=y CONFIG_LED=y From a757c26e50b0f78201810a6304ca72ecc2698059 Mon Sep 17 00:00:00 2001 From: Andy Sinclair Date: Fri, 17 Nov 2023 15:16:32 +0000 Subject: [PATCH 0305/3723] samples: shields: npm1300_ek: Fix display of negative temperature Update temperature printing to handle negative values. Signed-off-by: Andy Sinclair --- samples/shields/npm1300_ek/src/main.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/samples/shields/npm1300_ek/src/main.c b/samples/shields/npm1300_ek/src/main.c index 62e1059cf09..47ed6214677 100644 --- a/samples/shields/npm1300_ek/src/main.c +++ b/samples/shields/npm1300_ek/src/main.c @@ -93,7 +93,8 @@ void read_sensors(void) printk("I: %s%d.%04d ", ((current.val1 < 0) || (current.val2 < 0)) ? "-" : "", abs(current.val1), abs(current.val2) / 100); - printk("T: %d.%02d\n", temp.val1, temp.val2 / 10000); + printk("T: %s%d.%02d\n", ((temp.val1 < 0) || (temp.val2 < 0)) ? "-" : "", abs(temp.val1), + abs(temp.val2) / 10000); printk("Charger Status: %d, Error: %d\n", status.val1, error.val1); } From 6c8c0f57f98cd70d767eb2b9e425d5e1ca8655ee Mon Sep 17 00:00:00 2001 From: Lukasz Majewski Date: Tue, 7 Nov 2023 13:47:43 +0100 Subject: [PATCH 0306/3723] drivers: net: tc6: Add read,modify and write operation on control regs The OA TC6 driver requires some bits manipulations in control registers. Up till now - it has been implemented as an explicit set of read and write registers' operations. One good example would be the oa_tc6_set_protected_ctrl() implementation, which used such scheme. This patch brings dedicated function for this operation; oa_tc6_reg_rmw(). The aforementioned oa_tc6_set_protected_ctrl() function now uses it internally. Signed-off-by: Lukasz Majewski --- drivers/ethernet/oa_tc6.c | 23 +++++++++++++++-------- drivers/ethernet/oa_tc6.h | 16 ++++++++++++++++ 2 files changed, 31 insertions(+), 8 deletions(-) diff --git a/drivers/ethernet/oa_tc6.c b/drivers/ethernet/oa_tc6.c index 0fa1f105581..3a7448f7957 100644 --- a/drivers/ethernet/oa_tc6.c +++ b/drivers/ethernet/oa_tc6.c @@ -135,23 +135,30 @@ int oa_tc6_reg_write(struct oa_tc6 *tc6, const uint32_t reg, uint32_t val) return ret; } -int oa_tc6_set_protected_ctrl(struct oa_tc6 *tc6, bool prote) +int oa_tc6_reg_rmw(struct oa_tc6 *tc6, const uint32_t reg, + uint32_t mask, uint32_t val) { - uint32_t val; + uint32_t tmp; int ret; - ret = oa_tc6_reg_read(tc6, OA_CONFIG0, &val); + ret = oa_tc6_reg_read(tc6, reg, &tmp); if (ret < 0) { return ret; } - if (prote) { - val |= OA_CONFIG0_PROTE; - } else { - val &= ~OA_CONFIG0_PROTE; + tmp &= ~mask; + + if (val) { + tmp |= val; } - ret = oa_tc6_reg_write(tc6, OA_CONFIG0, val); + return oa_tc6_reg_write(tc6, reg, tmp); +} + +int oa_tc6_set_protected_ctrl(struct oa_tc6 *tc6, bool prote) +{ + int ret = oa_tc6_reg_rmw(tc6, OA_CONFIG0, OA_CONFIG0_PROTE, + prote ? OA_CONFIG0_PROTE : 0); if (ret < 0) { return ret; } diff --git a/drivers/ethernet/oa_tc6.h b/drivers/ethernet/oa_tc6.h index 7a9337e7c5d..7d2cead09a8 100644 --- a/drivers/ethernet/oa_tc6.h +++ b/drivers/ethernet/oa_tc6.h @@ -230,4 +230,20 @@ int oa_tc6_read_status(struct oa_tc6 *tc6, uint32_t *ftr); * @return 0 if successful, <0 otherwise. */ int oa_tc6_update_buf_info(struct oa_tc6 *tc6); + +/** + * @brief Read, modify and write control register from OA TC6 device + * + * @param tc6 OA TC6 specific data + * + * @param reg register to modify + * + * @param mask bit mask for modified register + * + * @param value to be stored in the register + * + * @return 0 if successful, <0 otherwise. + */ +int oa_tc6_reg_rmw(struct oa_tc6 *tc6, const uint32_t reg, + uint32_t mask, uint32_t val); #endif /* OA_TC6_CFG_H__ */ From d378e6450891ff8c135e7e8f9bdc6e44d8f70d53 Mon Sep 17 00:00:00 2001 From: Lukasz Majewski Date: Wed, 8 Nov 2023 11:05:58 +0100 Subject: [PATCH 0307/3723] drivers: net: Force LAN865x to start received frames at first chunk word Zephyr's network stack has issues with network IP header split across fragments. To alleviate this problem, the frame would be now aligned to first byte of the chunk. This would ensure that the header is stored at one network buffer fragment (as we explicitly set its size to 64B). Signed-off-by: Lukasz Majewski --- drivers/ethernet/eth_lan865x.c | 3 ++- drivers/ethernet/oa_tc6.h | 1 + 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/drivers/ethernet/eth_lan865x.c b/drivers/ethernet/eth_lan865x.c index 8107b7d3542..3fda80545da 100644 --- a/drivers/ethernet/eth_lan865x.c +++ b/drivers/ethernet/eth_lan865x.c @@ -408,7 +408,8 @@ static void lan865x_int_thread(const struct device *dev) oa_tc6_reg_write(tc6, OA_STATUS0, sts); lan865x_default_config(dev, ctx->silicon_rev); oa_tc6_reg_read(tc6, OA_CONFIG0, &val); - oa_tc6_reg_write(tc6, OA_CONFIG0, OA_CONFIG0_SYNC | val); + val |= OA_CONFIG0_SYNC | OA_CONFIG0_RFA_ZARFE; + oa_tc6_reg_write(tc6, OA_CONFIG0, val); lan865x_mac_rxtx_control(dev, LAN865x_MAC_TXRX_ON); ctx->reset = true; diff --git a/drivers/ethernet/oa_tc6.h b/drivers/ethernet/oa_tc6.h index 7d2cead09a8..06e53e21fb1 100644 --- a/drivers/ethernet/oa_tc6.h +++ b/drivers/ethernet/oa_tc6.h @@ -21,6 +21,7 @@ #define OA_RESET_SWRESET BIT(0) #define OA_CONFIG0 MMS_REG(0x0, 0x004) #define OA_CONFIG0_SYNC BIT(15) +#define OA_CONFIG0_RFA_ZARFE BIT(12) #define OA_CONFIG0_PROTE BIT(5) #define OA_STATUS0 MMS_REG(0x0, 0x008) #define OA_STATUS0_RESETC BIT(6) From 59980d5c98be62c47e97782cfdf9344275757d15 Mon Sep 17 00:00:00 2001 From: Lukasz Majewski Date: Thu, 9 Nov 2023 10:36:47 +0100 Subject: [PATCH 0308/3723] drivers: net: tc6: Saturate RCA and RBA when read directly from OA_BUFSTS The RCA and RBA fields in OA_BUFSTS register are stored with 8 bits each. On the other hand, when one receives those values in footer, the value is saturated to 5 bits due to 32 bit size constrain of the footer itself. To avoid any mismatches - the values read from OA_BUFSTS are saturated as well. Signed-off-by: Lukasz Majewski --- drivers/ethernet/oa_tc6.c | 20 ++++++++++++++++++++ drivers/ethernet/oa_tc6.h | 2 ++ 2 files changed, 22 insertions(+) diff --git a/drivers/ethernet/oa_tc6.c b/drivers/ethernet/oa_tc6.c index 3a7448f7957..e7d3ce9d945 100644 --- a/drivers/ethernet/oa_tc6.c +++ b/drivers/ethernet/oa_tc6.c @@ -237,6 +237,26 @@ int oa_tc6_update_buf_info(struct oa_tc6 *tc6) tc6->rca = FIELD_GET(OA_BUFSTS_RCA, val); tc6->txc = FIELD_GET(OA_BUFSTS_TXC, val); + /* + * There is a mismatch in the max value of RBA(RCA) and TXC provided by the + * OA TC6 standard. + * + * The OA_BUFSTS register has 8 bits for RBA(RCA) and TXC (max value is 0x30) + * + * However, with footer, the RBA(RCA) and TXC are saturated to 0x1F maximal + * value (due to 32 bit constrain of footer size). + * + * To avoid any issues, the number read directly from OA_BUFSTS is saturated + * as well. + */ + if (tc6->rca >= OA_TC6_FTR_RCA_MAX) { + tc6->rca = OA_TC6_FTR_RCA_MAX; + } + + if (tc6->txc >= OA_TC6_FTR_TXC_MAX) { + tc6->txc = OA_TC6_FTR_TXC_MAX; + } + return 0; } diff --git a/drivers/ethernet/oa_tc6.h b/drivers/ethernet/oa_tc6.h index 06e53e21fb1..e15ca8c40c1 100644 --- a/drivers/ethernet/oa_tc6.h +++ b/drivers/ethernet/oa_tc6.h @@ -77,6 +77,8 @@ #define OA_TC6_HDR_SIZE 4 #define OA_TC6_FTR_SIZE 4 #define OA_TC6_BUF_ALLOC_TIMEOUT K_MSEC(10) +#define OA_TC6_FTR_RCA_MAX GENMASK(4, 0) +#define OA_TC6_FTR_TXC_MAX GENMASK(4, 0) /** * @brief OA TC6 data. From cceeba3f42e399d43f789dbdb993575595b12531 Mon Sep 17 00:00:00 2001 From: Lukasz Majewski Date: Thu, 16 Nov 2023 11:37:54 +0100 Subject: [PATCH 0309/3723] drivers: net: tc6: Do not send extra last chunk when not required Current code sends extra, last chunk, when packet's size is a multiple of chunk size (i.e. 64 bytes). This patch fixes this issue by checking this corner case - i.e. if the modulo division equals to zero. Signed-off-by: Lukasz Majewski --- drivers/ethernet/oa_tc6.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/drivers/ethernet/oa_tc6.c b/drivers/ethernet/oa_tc6.c index e7d3ce9d945..31fce88ceee 100644 --- a/drivers/ethernet/oa_tc6.c +++ b/drivers/ethernet/oa_tc6.c @@ -175,7 +175,10 @@ int oa_tc6_send_chunks(struct oa_tc6 *tc6, struct net_pkt *pkt) uint8_t chunks, i; int ret; - chunks = (len / tc6->cps) + 1; + chunks = len / tc6->cps; + if (len % tc6->cps) { + chunks++; + } /* Check if LAN865x has any free internal buffer space */ if (chunks > tc6->txc) { From aa733d789f7d2df7beda71e6cd7bc4c6e7f24d28 Mon Sep 17 00:00:00 2001 From: Lukasz Majewski Date: Thu, 16 Nov 2023 11:48:55 +0100 Subject: [PATCH 0310/3723] drivers: net: tc6: Avoid sending packet when no data provided This commit adds check if the packet to be sent has any data. Signed-off-by: Lukasz Majewski --- drivers/ethernet/oa_tc6.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/drivers/ethernet/oa_tc6.c b/drivers/ethernet/oa_tc6.c index 31fce88ceee..10e5715b09f 100644 --- a/drivers/ethernet/oa_tc6.c +++ b/drivers/ethernet/oa_tc6.c @@ -175,6 +175,10 @@ int oa_tc6_send_chunks(struct oa_tc6 *tc6, struct net_pkt *pkt) uint8_t chunks, i; int ret; + if (len == 0) { + return -ENODATA; + } + chunks = len / tc6->cps; if (len % tc6->cps) { chunks++; From c2f5a9d67ce56f4093d95d80f58c5c93878db900 Mon Sep 17 00:00:00 2001 From: Lukasz Majewski Date: Wed, 15 Nov 2023 14:02:43 +0100 Subject: [PATCH 0311/3723] drivers: net: lan865x: Do not read chunks if protected read error detected The oa_tc6_update_buf_info() function returns error code when read (protected or not) of OA_BUFSTS has been detected. In that situation - one shall re-start the interrupt thread handling (and hence correctly re-read value of this register) than use old (stalled) RCA(RBA) data to read chunks (which may result in lockup). Signed-off-by: Lukasz Majewski --- drivers/ethernet/eth_lan865x.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/drivers/ethernet/eth_lan865x.c b/drivers/ethernet/eth_lan865x.c index 3fda80545da..9ba5f2ae935 100644 --- a/drivers/ethernet/eth_lan865x.c +++ b/drivers/ethernet/eth_lan865x.c @@ -426,7 +426,9 @@ static void lan865x_int_thread(const struct device *dev) * The IRQ_N is asserted when RCA becomes > 0, so update its value * before reading chunks. */ - oa_tc6_update_buf_info(tc6); + if (oa_tc6_update_buf_info(tc6) < 0) { + continue; + } while (tc6->rca > 0) { lan865x_read_chunks(dev); From ecfe5f1167aa2831d55335c5f1df486fcbc919b1 Mon Sep 17 00:00:00 2001 From: Lukasz Majewski Date: Fri, 17 Nov 2023 15:54:55 +0100 Subject: [PATCH 0312/3723] drivers: net: lan865x: Fix use of RX/TX semaphore in read chunks function This commit ensures that whole receive function (called from interrupt handler) is protected by the RX/TX semaphore. Signed-off-by: Lukasz Majewski --- drivers/ethernet/eth_lan865x.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/drivers/ethernet/eth_lan865x.c b/drivers/ethernet/eth_lan865x.c index 9ba5f2ae935..61c2bfda647 100644 --- a/drivers/ethernet/eth_lan865x.c +++ b/drivers/ethernet/eth_lan865x.c @@ -373,16 +373,16 @@ static void lan865x_read_chunks(const struct device *dev) k_sem_take(&ctx->tx_rx_sem, K_FOREVER); pkt = net_pkt_rx_alloc(K_MSEC(cfg->timeout)); if (!pkt) { - LOG_ERR("OA RX: Could not allocate packet!"); k_sem_give(&ctx->tx_rx_sem); + LOG_ERR("OA RX: Could not allocate packet!"); return; } ret = oa_tc6_read_chunks(tc6, pkt); - k_sem_give(&ctx->tx_rx_sem); if (ret < 0) { eth_stats_update_errors_rx(ctx->iface); net_pkt_unref(pkt); + k_sem_give(&ctx->tx_rx_sem); return; } @@ -392,6 +392,7 @@ static void lan865x_read_chunks(const struct device *dev) LOG_ERR("OA RX: Could not process packet (%d)!", ret); net_pkt_unref(pkt); } + k_sem_give(&ctx->tx_rx_sem); } static void lan865x_int_thread(const struct device *dev) From 8df4482f4c0def9bacd3ae0912ddcadc01264c0a Mon Sep 17 00:00:00 2001 From: Lukasz Majewski Date: Mon, 20 Nov 2023 16:11:43 +0100 Subject: [PATCH 0313/3723] drivers: net: lan865x: Fix initialization of semaphores This change fixes semaphores' definition. To be more specific - the limit was wrongly set to UINT_MAX. With those changes - the 'tx_rx_sem' now assures that only one execution path (i.e. receiving or sending data) is executed at a time. Moreover, the change in 'int_sem' now assures that this semaphore limit, when reached, is saturated. Signed-off-by: Lukasz Majewski --- drivers/ethernet/eth_lan865x.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/ethernet/eth_lan865x.c b/drivers/ethernet/eth_lan865x.c index 61c2bfda647..d132c595b0a 100644 --- a/drivers/ethernet/eth_lan865x.c +++ b/drivers/ethernet/eth_lan865x.c @@ -577,8 +577,8 @@ static const struct ethernet_api lan865x_api_func = { static struct lan865x_data lan865x_data_##inst = { \ .mac_address = DT_INST_PROP(inst, local_mac_address), \ .tx_rx_sem = \ - Z_SEM_INITIALIZER((lan865x_data_##inst).tx_rx_sem, 1, UINT_MAX), \ - .int_sem = Z_SEM_INITIALIZER((lan865x_data_##inst).int_sem, 0, UINT_MAX), \ + Z_SEM_INITIALIZER((lan865x_data_##inst).tx_rx_sem, 1, 1), \ + .int_sem = Z_SEM_INITIALIZER((lan865x_data_##inst).int_sem, 0, 1), \ .tc6 = &oa_tc6_##inst \ }; \ \ From b0b57dac72b90bbe572fdef389310d3b55786a08 Mon Sep 17 00:00:00 2001 From: Lukasz Majewski Date: Thu, 23 Nov 2023 16:51:59 +0100 Subject: [PATCH 0314/3723] drivers: net: tc6: Provide separate function to check IC status The code to handle OA TC6 compliant device's status is generic and can be moved to device agnostic driver (oa_tc6.c). Moreover, the original code has been augmented with LOG_WRN() messages. Signed-off-by: Lukasz Majewski --- drivers/ethernet/eth_lan865x.c | 18 +----------------- drivers/ethernet/oa_tc6.c | 26 ++++++++++++++++++++++++++ drivers/ethernet/oa_tc6.h | 9 +++++++++ 3 files changed, 36 insertions(+), 17 deletions(-) diff --git a/drivers/ethernet/eth_lan865x.c b/drivers/ethernet/eth_lan865x.c index d132c595b0a..91af1980f55 100644 --- a/drivers/ethernet/eth_lan865x.c +++ b/drivers/ethernet/eth_lan865x.c @@ -435,23 +435,7 @@ static void lan865x_int_thread(const struct device *dev) lan865x_read_chunks(dev); } - if (tc6->exst) { - /* - * Just clear any pending interrupts - data RX will be served - * earlier. - * The RESETC is handled separately as it requires LAN865x device - * configuration. - */ - oa_tc6_reg_read(tc6, OA_STATUS0, &sts); - if (sts != 0) { - oa_tc6_reg_write(tc6, OA_STATUS0, sts); - } - - oa_tc6_reg_read(tc6, OA_STATUS1, &sts); - if (sts != 0) { - oa_tc6_reg_write(tc6, OA_STATUS1, sts); - } - } + oa_tc6_check_status(tc6); } } diff --git a/drivers/ethernet/oa_tc6.c b/drivers/ethernet/oa_tc6.c index 10e5715b09f..5de831babdc 100644 --- a/drivers/ethernet/oa_tc6.c +++ b/drivers/ethernet/oa_tc6.c @@ -223,6 +223,32 @@ int oa_tc6_send_chunks(struct oa_tc6 *tc6, struct net_pkt *pkt) return 0; } +int oa_tc6_check_status(struct oa_tc6 *tc6) +{ + uint32_t sts; + + if (tc6->exst) { + /* + * Just clear any pending interrupts. + * The RESETC is handled separately as it requires per + * device configuration. + */ + oa_tc6_reg_read(tc6, OA_STATUS0, &sts); + if (sts != 0) { + oa_tc6_reg_write(tc6, OA_STATUS0, sts); + LOG_WRN("EXST: OA_STATUS0: 0x%x", sts); + } + + oa_tc6_reg_read(tc6, OA_STATUS1, &sts); + if (sts != 0) { + oa_tc6_reg_write(tc6, OA_STATUS1, sts); + LOG_WRN("EXST: OA_STATUS1: 0x%x", sts); + } + } + + return 0; +} + static void oa_tc6_update_status(struct oa_tc6 *tc6, uint32_t ftr) { tc6->exst = FIELD_GET(OA_DATA_FTR_EXST, ftr); diff --git a/drivers/ethernet/oa_tc6.h b/drivers/ethernet/oa_tc6.h index e15ca8c40c1..7e82e9db748 100644 --- a/drivers/ethernet/oa_tc6.h +++ b/drivers/ethernet/oa_tc6.h @@ -249,4 +249,13 @@ int oa_tc6_update_buf_info(struct oa_tc6 *tc6); */ int oa_tc6_reg_rmw(struct oa_tc6 *tc6, const uint32_t reg, uint32_t mask, uint32_t val); + +/** + * @brief Check the status of OA TC6 device + * + * @param tc6 OA TC6 specific data + * + * @return 0 if successful, <0 otherwise. + */ +int oa_tc6_check_status(struct oa_tc6 *tc6); #endif /* OA_TC6_CFG_H__ */ From 2ae09993cae8a8892d0f586877c8ce1e65f50387 Mon Sep 17 00:00:00 2001 From: Dawid Niedzwiecki Date: Thu, 23 Nov 2023 09:35:17 +0100 Subject: [PATCH 0315/3723] timer: cortex_m_systick: handle cycle count overflow with idle timer When the idle timer is in use, we calculate number of cycles passed since the sys_clock_set_timeout call. The cycle counter can overflow easily, when the counter is 32-bit wide. Handle that case. Signed-off-by: Dawid Niedzwiecki --- drivers/timer/cortex_m_systick.c | 15 +++++++++++++-- 1 file changed, 13 insertions(+), 2 deletions(-) diff --git a/drivers/timer/cortex_m_systick.c b/drivers/timer/cortex_m_systick.c index 13e499efec4..d376273bc7d 100644 --- a/drivers/timer/cortex_m_systick.c +++ b/drivers/timer/cortex_m_systick.c @@ -366,17 +366,28 @@ void sys_clock_idle_exit(void) { #ifdef CONFIG_CORTEX_M_SYSTICK_IDLE_TIMER if (timeout_idle) { - cycle_t systick_diff, missed_cycles; + cycle_t cycle_post_idle, systick_diff, missed_cycles; uint32_t idle_timer_diff, idle_timer_post, dcycles, dticks; uint64_t systick_us, idle_timer_us, measurement_diff_us; /* Get current values for both timers */ counter_get_value(idle_timer, &idle_timer_post); - systick_diff = cycle_count + elapsed() - cycle_pre_idle; + cycle_post_idle = cycle_count + elapsed(); /* Calculate has much time has pasted since last measurement for both timers */ idle_timer_diff = idle_timer_post - idle_timer_pre_idle; idle_timer_us = counter_ticks_to_us(idle_timer, idle_timer_diff); + +#ifndef CONFIG_CORTEX_M_SYSTICK_64BIT_CYCLE_COUNTER + /* Check cycle counter overflow when using uint32_t */ + if (cycle_pre_idle > cycle_post_idle) { + systick_diff = (UINT32_MAX - cycle_pre_idle) + cycle_post_idle + 1; + } else { + systick_diff = cycle_post_idle - cycle_pre_idle; + } +#else + systick_diff = cycle_post_idle - cycle_pre_idle; +#endif /* !CONFIG_CORTEX_M_SYSTICK_64BIT_CYCLE_COUNTER */ systick_us = ((uint64_t)systick_diff * USEC_PER_SEC) / sys_clock_hw_cycles_per_sec(); From 4104f54987727532d8cd0cc8f2784fbd0fcd2820 Mon Sep 17 00:00:00 2001 From: Dawid Niedzwiecki Date: Thu, 23 Nov 2023 09:53:58 +0100 Subject: [PATCH 0316/3723] timer: cortex_m_systick: handle idle timer overflow The idle timer has its max value and can overflow. We measure time passed since the sys_clock_set_timeout call. Take possibility of the overflow into account. Signed-off-by: Dawid Niedzwiecki --- drivers/timer/cortex_m_systick.c | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/drivers/timer/cortex_m_systick.c b/drivers/timer/cortex_m_systick.c index d376273bc7d..9a415524e0c 100644 --- a/drivers/timer/cortex_m_systick.c +++ b/drivers/timer/cortex_m_systick.c @@ -375,7 +375,15 @@ void sys_clock_idle_exit(void) cycle_post_idle = cycle_count + elapsed(); /* Calculate has much time has pasted since last measurement for both timers */ - idle_timer_diff = idle_timer_post - idle_timer_pre_idle; + /* Check IDLE timer overflow */ + if (idle_timer_pre_idle > idle_timer_post) { + idle_timer_diff = + (counter_get_top_value(idle_timer) - idle_timer_pre_idle) + + idle_timer_post + 1; + + } else { + idle_timer_diff = idle_timer_post - idle_timer_pre_idle; + } idle_timer_us = counter_ticks_to_us(idle_timer, idle_timer_diff); #ifndef CONFIG_CORTEX_M_SYSTICK_64BIT_CYCLE_COUNTER From 733bddb32e715627ddd601836ad224e943956dcb Mon Sep 17 00:00:00 2001 From: Dawid Niedzwiecki Date: Thu, 23 Nov 2023 10:37:46 +0100 Subject: [PATCH 0317/3723] timer: cortex_m_systick: idle timer: handle no sleep case SysTick usually has higher measurement resolution than the IDLE timer. When the time in low power mode is very short or 0, it is possible that SysTick usually has measures more time since the sys_clock_set_timeout than the idle timer. Handle that case to keep uptime correct. Signed-off-by: Dawid Niedzwiecki --- drivers/timer/cortex_m_systick.c | 19 +++++++++++++++---- 1 file changed, 15 insertions(+), 4 deletions(-) diff --git a/drivers/timer/cortex_m_systick.c b/drivers/timer/cortex_m_systick.c index 9a415524e0c..abd60f5ad7a 100644 --- a/drivers/timer/cortex_m_systick.c +++ b/drivers/timer/cortex_m_systick.c @@ -368,7 +368,7 @@ void sys_clock_idle_exit(void) if (timeout_idle) { cycle_t cycle_post_idle, systick_diff, missed_cycles; uint32_t idle_timer_diff, idle_timer_post, dcycles, dticks; - uint64_t systick_us, idle_timer_us, measurement_diff_us; + uint64_t systick_us, idle_timer_us; /* Get current values for both timers */ counter_get_value(idle_timer, &idle_timer_post); @@ -402,9 +402,20 @@ void sys_clock_idle_exit(void) /* Calculate difference in measurements to get how much time * the SysTick missed in idle state. */ - measurement_diff_us = idle_timer_us - systick_us; - missed_cycles = - (sys_clock_hw_cycles_per_sec() * measurement_diff_us) / USEC_PER_SEC; + if (idle_timer_us < systick_us) { + /* This case is possible, when the time in low power mode is + * very short or 0. SysTick usually has higher measurement + * resolution of than the IDLE timer, thus the measurement of + * passed time since the sys_clock_set_timeout call can be higher. + */ + missed_cycles = 0; + } else { + uint64_t measurement_diff_us; + + measurement_diff_us = idle_timer_us - systick_us; + missed_cycles = (sys_clock_hw_cycles_per_sec() * measurement_diff_us) / + USEC_PER_SEC; + } /* Update the cycle counter to include the cycles missed in idle */ cycle_count += missed_cycles; From e887b3e452daa8859480766b8c436b8a9fe8fced Mon Sep 17 00:00:00 2001 From: Laurentiu Mihalcea Date: Thu, 23 Nov 2023 16:06:56 +0200 Subject: [PATCH 0318/3723] include: drivers: dai: Align DAI direction with SOF direction Currently, DAI_DIR_TX and DAI_DIR_RX have different values from SOF_IPC_STREAM_PLAYBACK and SOF_IPC_STREAM_CAPTURE. Since SOF performs no conversion from one encoding to another this may lead DAI operations performed on the wrong directions. Since it's much easier to just change the values for DAI_DIR_TX and DAI_DIR_RX rather than try to perform a conversion from one format to another on SOF side, this commit changes DAI_DIR_TX to 0 (equal to SOF_IPC_STREAM_PLAYBACK) and DAI_DIR_RX to 1 (equal to SOF_IPC_STREAM_CAPTURE). Signed-off-by: Laurentiu Mihalcea --- include/zephyr/drivers/dai.h | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/include/zephyr/drivers/dai.h b/include/zephyr/drivers/dai.h index da124b4512d..8e5fbcf553e 100644 --- a/include/zephyr/drivers/dai.h +++ b/include/zephyr/drivers/dai.h @@ -64,10 +64,10 @@ enum dai_type { * @brief DAI Direction */ enum dai_dir { - /** Receive data */ - DAI_DIR_RX = 1, /** Transmit data */ - DAI_DIR_TX, + DAI_DIR_TX = 0, + /** Receive data */ + DAI_DIR_RX, /** Both receive and transmit data */ DAI_DIR_BOTH, }; From 4b365fab454dfc82e19a7af45f7b79ebc6f745f0 Mon Sep 17 00:00:00 2001 From: Jukka Rissanen Date: Thu, 23 Nov 2023 11:03:17 +0200 Subject: [PATCH 0319/3723] net: sockets: Add recvmsg() implementation Add support for recvmsg() function which can return data in msghdr struct (iovec). Signed-off-by: Jukka Rissanen --- include/zephyr/net/socket.h | 20 ++ subsys/net/lib/sockets/sockets.c | 336 +++++++++++++++++++++- subsys/net/lib/sockets/sockets_internal.h | 1 + 3 files changed, 342 insertions(+), 15 deletions(-) diff --git a/include/zephyr/net/socket.h b/include/zephyr/net/socket.h index 91f9193bbf8..7d0c2c79c91 100644 --- a/include/zephyr/net/socket.h +++ b/include/zephyr/net/socket.h @@ -466,6 +466,20 @@ __syscall ssize_t zsock_recvfrom(int sock, void *buf, size_t max_len, int flags, struct sockaddr *src_addr, socklen_t *addrlen); +/** + * @brief Receive a message from an arbitrary network address + * + * @details + * @rst + * See `POSIX.1-2017 article + * `__ + * for normative description. + * This function is also exposed as ``recvmsg()`` + * if :kconfig:option:`CONFIG_NET_SOCKETS_POSIX_NAMES` is defined. + * @endrst + */ +__syscall ssize_t zsock_recvmsg(int sock, struct msghdr *msg, int flags); + /** * @brief Receive data from a connected peer * @@ -862,6 +876,12 @@ static inline ssize_t recvfrom(int sock, void *buf, size_t max_len, int flags, return zsock_recvfrom(sock, buf, max_len, flags, src_addr, addrlen); } +/** POSIX wrapper for @ref zsock_recvmsg */ +static inline ssize_t recvmsg(int sock, struct msghdr *msg, int flags) +{ + return zsock_recvmsg(sock, msg, flags); +} + /** POSIX wrapper for @ref zsock_poll */ static inline int poll(struct zsock_pollfd *fds, int nfds, int timeout) { diff --git a/subsys/net/lib/sockets/sockets.c b/subsys/net/lib/sockets/sockets.c index d35317352c9..95d45c2fd53 100644 --- a/subsys/net/lib/sockets/sockets.c +++ b/subsys/net/lib/sockets/sockets.c @@ -1194,6 +1194,7 @@ int zsock_wait_data(struct net_context *ctx, k_timeout_t *timeout) } static inline ssize_t zsock_recv_dgram(struct net_context *ctx, + struct msghdr *msg, void *buf, size_t max_len, int flags, @@ -1283,12 +1284,58 @@ static inline ssize_t zsock_recv_dgram(struct net_context *ctx, } } - recv_len = net_pkt_remaining_data(pkt); - read_len = MIN(recv_len, max_len); + if (msg != NULL) { + int iovec = 0; + size_t tmp_read_len; - if (net_pkt_read(pkt, buf, read_len)) { - errno = ENOBUFS; - goto fail; + if (msg->msg_iovlen < 1 || msg->msg_iov == NULL) { + errno = ENOMEM; + return -1; + } + + recv_len = net_pkt_remaining_data(pkt); + tmp_read_len = read_len = MIN(recv_len, max_len); + + while (tmp_read_len > 0) { + size_t len; + + buf = msg->msg_iov[iovec].iov_base; + if (buf == NULL) { + errno = EINVAL; + return -1; + } + + len = MIN(tmp_read_len, msg->msg_iov[iovec].iov_len); + + if (net_pkt_read(pkt, buf, len)) { + errno = ENOBUFS; + goto fail; + } + + if (len <= tmp_read_len) { + tmp_read_len -= len; + msg->msg_iov[iovec].iov_len = len; + iovec++; + } else { + errno = EINVAL; + return -1; + } + } + + msg->msg_iovlen = iovec; + + if (recv_len != read_len) { + msg->msg_flags |= ZSOCK_MSG_TRUNC; + } + + } else { + recv_len = net_pkt_remaining_data(pkt); + read_len = MIN(recv_len, max_len); + + if (net_pkt_read(pkt, buf, read_len)) { + errno = ENOBUFS; + goto fail; + } } if (IS_ENABLED(CONFIG_NET_PKT_RXTIME_STATS) && @@ -1391,14 +1438,28 @@ static int zsock_fionread_ctx(struct net_context *ctx) return MIN(ret, INT_MAX); } -static ssize_t zsock_recv_stream_timed(struct net_context *ctx, uint8_t *buf, size_t max_len, +static ssize_t zsock_recv_stream_timed(struct net_context *ctx, struct msghdr *msg, + uint8_t *buf, size_t max_len, int flags, k_timeout_t timeout) { int res; k_timepoint_t end; - size_t recv_len = 0; + size_t recv_len = 0, iovec, available_len, max_iovlen = 0; const bool waitall = (flags & ZSOCK_MSG_WAITALL) == ZSOCK_MSG_WAITALL; + if (msg != NULL && buf == NULL) { + if (msg->msg_iovlen < 1) { + return -EINVAL; + } + + iovec = 0; + + buf = msg->msg_iov[iovec].iov_base; + available_len = msg->msg_iov[iovec].iov_len; + msg->msg_iov[iovec].iov_len = 0; + max_iovlen = msg->msg_iovlen; + } + for (end = sys_timepoint_calc(timeout); max_len > 0; timeout = sys_timepoint_timeout(end)) { if (sock_is_error(ctx)) { @@ -1416,12 +1477,49 @@ static ssize_t zsock_recv_stream_timed(struct net_context *ctx, uint8_t *buf, si } } - res = zsock_recv_stream_immediate(ctx, &buf, &max_len, flags); - recv_len += res; - if (res == 0) { - if (recv_len == 0 && K_TIMEOUT_EQ(timeout, K_NO_WAIT)) { + if (msg != NULL) { +again: + res = zsock_recv_stream_immediate(ctx, &buf, &available_len, flags); + recv_len += res; + + if (res == 0 && recv_len == 0 && K_TIMEOUT_EQ(timeout, K_NO_WAIT)) { return -EAGAIN; } + + msg->msg_iov[iovec].iov_len += res; + buf = (uint8_t *)(msg->msg_iov[iovec].iov_base) + res; + max_len -= res; + + if (available_len == 0) { + /* All data to this iovec was written */ + iovec++; + + if (iovec == max_iovlen) { + break; + } + + msg->msg_iovlen = iovec; + buf = msg->msg_iov[iovec].iov_base; + available_len = msg->msg_iov[iovec].iov_len; + msg->msg_iov[iovec].iov_len = 0; + + /* If there is more data, read it now and do not wait */ + if (buf != NULL && available_len > 0) { + goto again; + } + + continue; + } + + } else { + res = zsock_recv_stream_immediate(ctx, &buf, &max_len, flags); + recv_len += res; + + if (res == 0) { + if (recv_len == 0 && K_TIMEOUT_EQ(timeout, K_NO_WAIT)) { + return -EAGAIN; + } + } } if (!waitall) { @@ -1432,7 +1530,8 @@ static ssize_t zsock_recv_stream_timed(struct net_context *ctx, uint8_t *buf, si return recv_len; } -static ssize_t zsock_recv_stream(struct net_context *ctx, void *buf, size_t max_len, int flags) +static ssize_t zsock_recv_stream(struct net_context *ctx, struct msghdr *msg, + void *buf, size_t max_len, int flags) { ssize_t res; size_t recv_len = 0; @@ -1459,7 +1558,7 @@ static ssize_t zsock_recv_stream(struct net_context *ctx, void *buf, size_t max_ return 0; } - res = zsock_recv_stream_timed(ctx, buf, max_len, flags, timeout); + res = zsock_recv_stream_timed(ctx, msg, buf, max_len, flags, timeout); recv_len += MAX(0, res); if (res < 0) { @@ -1485,9 +1584,9 @@ ssize_t zsock_recvfrom_ctx(struct net_context *ctx, void *buf, size_t max_len, } if (sock_type == SOCK_DGRAM) { - return zsock_recv_dgram(ctx, buf, max_len, flags, src_addr, addrlen); + return zsock_recv_dgram(ctx, NULL, buf, max_len, flags, src_addr, addrlen); } else if (sock_type == SOCK_STREAM) { - return zsock_recv_stream(ctx, buf, max_len, flags); + return zsock_recv_stream(ctx, NULL, buf, max_len, flags); } else { __ASSERT(0, "Unknown socket type"); } @@ -1539,6 +1638,207 @@ ssize_t z_vrfy_zsock_recvfrom(int sock, void *buf, size_t max_len, int flags, #include #endif /* CONFIG_USERSPACE */ +ssize_t zsock_recvmsg_ctx(struct net_context *ctx, struct msghdr *msg, + int flags) +{ + enum net_sock_type sock_type = net_context_get_type(ctx); + size_t i, max_len = 0; + + if (msg == NULL) { + errno = EINVAL; + return -1; + } + + for (i = 0; i < msg->msg_iovlen; i++) { + max_len += msg->msg_iov[i].iov_len; + } + + if (sock_type == SOCK_DGRAM) { + return zsock_recv_dgram(ctx, msg, NULL, max_len, flags, + msg->msg_name, &msg->msg_namelen); + } else if (sock_type == SOCK_STREAM) { + return zsock_recv_stream(ctx, msg, NULL, max_len, flags); + } + + __ASSERT(0, "Unknown socket type"); + + errno = ENOTSUP; + + return -1; +} + +ssize_t z_impl_zsock_recvmsg(int sock, struct msghdr *msg, int flags) +{ + int bytes_received; + + bytes_received = VTABLE_CALL(recvmsg, sock, msg, flags); + + sock_obj_core_update_recv_stats(sock, bytes_received); + + return bytes_received; +} + +#ifdef CONFIG_USERSPACE +ssize_t z_vrfy_zsock_recvmsg(int sock, struct msghdr *msg, int flags) +{ + struct msghdr msg_copy; + size_t iovlen; + size_t i; + int ret; + + if (msg == NULL) { + errno = EINVAL; + return -1; + } + + K_OOPS(k_usermode_from_copy(&msg_copy, (void *)msg, sizeof(msg_copy))); + + k_usermode_from_copy(&iovlen, &msg->msg_iovlen, sizeof(iovlen)); + + msg_copy.msg_name = NULL; + msg_copy.msg_control = NULL; + + msg_copy.msg_iov = k_usermode_alloc_from_copy(msg->msg_iov, + msg->msg_iovlen * sizeof(struct iovec)); + if (!msg_copy.msg_iov) { + errno = ENOMEM; + goto fail; + } + + /* Clear the pointers in the copy so that if the allocation in the + * next loop fails, we do not try to free non allocated memory + * in fail branch. + */ + memset(msg_copy.msg_iov, 0, msg->msg_iovlen * sizeof(struct iovec)); + + for (i = 0; i < iovlen; i++) { + /* TODO: In practice we do not need to copy the actual data + * in msghdr when receiving data but currently there is no + * ready made function to do just that (unless we want to call + * relevant malloc function here ourselves). So just use + * the copying variant for now. + */ + msg_copy.msg_iov[i].iov_base = + k_usermode_alloc_from_copy(msg->msg_iov[i].iov_base, + msg->msg_iov[i].iov_len); + if (!msg_copy.msg_iov[i].iov_base) { + errno = ENOMEM; + goto fail; + } + + msg_copy.msg_iov[i].iov_len = msg->msg_iov[i].iov_len; + } + + if (msg->msg_namelen > 0) { + if (msg->msg_name == NULL) { + errno = EINVAL; + goto fail; + } + + msg_copy.msg_name = k_usermode_alloc_from_copy(msg->msg_name, + msg->msg_namelen); + if (msg_copy.msg_name == NULL) { + errno = ENOMEM; + goto fail; + } + } + + if (msg->msg_controllen > 0) { + if (msg->msg_control == NULL) { + errno = EINVAL; + goto fail; + } + + msg_copy.msg_control = + k_usermode_alloc_from_copy(msg->msg_control, + msg->msg_controllen); + if (msg_copy.msg_control == NULL) { + errno = ENOMEM; + goto fail; + } + } + + ret = z_impl_zsock_recvmsg(sock, &msg_copy, flags); + + /* Do not copy anything back if there was an error or nothing was + * received. + */ + if (ret > 0) { + if (msg->msg_namelen > 0 && msg->msg_name != NULL) { + K_OOPS(k_usermode_to_copy(msg->msg_name, + msg_copy.msg_name, + msg_copy.msg_namelen)); + } + + if (msg->msg_controllen > 0 && + msg->msg_control != NULL) { + K_OOPS(k_usermode_to_copy(msg->msg_control, + msg_copy.msg_control, + msg_copy.msg_controllen)); + } + + k_usermode_to_copy(&msg->msg_iovlen, + &msg_copy.msg_iovlen, + sizeof(msg->msg_iovlen)); + + /* The new iovlen cannot be bigger than the original one */ + NET_ASSERT(msg_copy.msg_iovlen <= iovlen); + + for (i = 0; i < iovlen; i++) { + if (i < msg_copy.msg_iovlen) { + K_OOPS(k_usermode_to_copy(msg->msg_iov[i].iov_base, + msg_copy.msg_iov[i].iov_base, + msg_copy.msg_iov[i].iov_len)); + K_OOPS(k_usermode_to_copy(&msg->msg_iov[i].iov_len, + &msg_copy.msg_iov[i].iov_len, + sizeof(msg->msg_iov[i].iov_len))); + } else { + /* Clear out those vectors that we could not populate */ + msg->msg_iov[i].iov_len = 0; + } + } + + k_usermode_to_copy(&msg->msg_flags, + &msg_copy.msg_flags, + sizeof(msg->msg_flags)); + } + + k_free(msg_copy.msg_name); + k_free(msg_copy.msg_control); + + /* Note that we need to free according to original iovlen */ + for (i = 0; i < iovlen; i++) { + k_free(msg_copy.msg_iov[i].iov_base); + } + + k_free(msg_copy.msg_iov); + + return ret; + +fail: + if (msg_copy.msg_name) { + k_free(msg_copy.msg_name); + } + + if (msg_copy.msg_control) { + k_free(msg_copy.msg_control); + } + + if (msg_copy.msg_iov) { + for (i = 0; i < msg_copy.msg_iovlen; i++) { + if (msg_copy.msg_iov[i].iov_base) { + k_free(msg_copy.msg_iov[i].iov_base); + } + } + + k_free(msg_copy.msg_iov); + } + + return -1; +} +#include +#endif /* CONFIG_USERSPACE */ + /* As this is limited function, we don't follow POSIX signature, with * "..." instead of last arg. */ @@ -2822,6 +3122,11 @@ static ssize_t sock_sendmsg_vmeth(void *obj, const struct msghdr *msg, return zsock_sendmsg_ctx(obj, msg, flags); } +static ssize_t sock_recvmsg_vmeth(void *obj, struct msghdr *msg, int flags) +{ + return zsock_recvmsg_ctx(obj, msg, flags); +} + static ssize_t sock_recvfrom_vmeth(void *obj, void *buf, size_t max_len, int flags, struct sockaddr *src_addr, socklen_t *addrlen) @@ -2872,6 +3177,7 @@ const struct socket_op_vtable sock_fd_op_vtable = { .accept = sock_accept_vmeth, .sendto = sock_sendto_vmeth, .sendmsg = sock_sendmsg_vmeth, + .recvmsg = sock_recvmsg_vmeth, .recvfrom = sock_recvfrom_vmeth, .getsockopt = sock_getsockopt_vmeth, .setsockopt = sock_setsockopt_vmeth, diff --git a/subsys/net/lib/sockets/sockets_internal.h b/subsys/net/lib/sockets/sockets_internal.h index 9398608b4d0..7af35d2a219 100644 --- a/subsys/net/lib/sockets/sockets_internal.h +++ b/subsys/net/lib/sockets/sockets_internal.h @@ -70,6 +70,7 @@ struct socket_op_vtable { int (*setsockopt)(void *obj, int level, int optname, const void *optval, socklen_t optlen); ssize_t (*sendmsg)(void *obj, const struct msghdr *msg, int flags); + ssize_t (*recvmsg)(void *obj, struct msghdr *msg, int flags); int (*getpeername)(void *obj, struct sockaddr *addr, socklen_t *addrlen); int (*getsockname)(void *obj, struct sockaddr *addr, From 0b71043f6ae99b8467dc1f77a9369c41246f84d2 Mon Sep 17 00:00:00 2001 From: Jukka Rissanen Date: Thu, 23 Nov 2023 11:05:22 +0200 Subject: [PATCH 0320/3723] tests: net: socket: Add UDP tests for recvmsg() Make sure recvmsg() works as expected for UDP data. Signed-off-by: Jukka Rissanen --- tests/net/socket/udp/src/main.c | 271 ++++++++++++++++++++++++++++++++ 1 file changed, 271 insertions(+) diff --git a/tests/net/socket/udp/src/main.c b/tests/net/socket/udp/src/main.c index 31c1fba43f5..fc9361330a3 100644 --- a/tests/net/socket/udp/src/main.c +++ b/tests/net/socket/udp/src/main.c @@ -16,6 +16,7 @@ LOG_MODULE_REGISTER(net_test, CONFIG_NET_SOCKETS_LOG_LEVEL); #include #include "ipv6.h" +#include "net_private.h" #include "../../socket_helpers.h" #if defined(CONFIG_NET_SOCKETS_LOG_LEVEL_DBG) @@ -1383,6 +1384,276 @@ ZTEST(net_socket_udp, test_25_v6_dgram_connected) (struct sockaddr *)&server_addr_2, sizeof(server_addr_2)); } +ZTEST_USER(net_socket_udp, test_26_recvmsg_invalid) +{ + struct msghdr msg; + struct sockaddr_in6 server_addr; + struct cmsghdr *cmsg; + struct iovec io_vector[1]; + union { + struct cmsghdr hdr; + unsigned char buf[CMSG_SPACE(sizeof(int))]; + } cmsgbuf; + int ret; + + /* Userspace is needed for this test */ + Z_TEST_SKIP_IFNDEF(CONFIG_USERSPACE); + + io_vector[0].iov_base = TEST_STR_SMALL; + io_vector[0].iov_len = strlen(TEST_STR_SMALL); + + ret = recvmsg(0, NULL, 0); + zassert_true(ret < 0 && errno == EINVAL, "Wrong errno (%d)", errno); + + /* Set various pointers to NULL or invalid value which should cause failure */ + memset(&msg, 0, sizeof(msg)); + msg.msg_controllen = sizeof(cmsgbuf.buf); + + ret = recvmsg(0, &msg, 0); + zassert_true(ret < 0, "recvmsg() succeed"); + + msg.msg_control = &cmsgbuf.buf; + + ret = recvmsg(0, &msg, 0); + zassert_true(ret < 0, "recvmsg() succeed"); + + msg.msg_iov = io_vector; + msg.msg_iovlen = 1; + msg.msg_name = (void *)1; + msg.msg_namelen = sizeof(server_addr); + + cmsg = CMSG_FIRSTHDR(&msg); + cmsg->cmsg_len = CMSG_LEN(sizeof(int)); + cmsg->cmsg_level = SOL_SOCKET; + cmsg->cmsg_type = 1122; + *(int *)CMSG_DATA(cmsg) = 42; + + ret = recvmsg(0, &msg, 0); + zassert_true(ret < 0, "recvmsg() succeed"); +} + +static void comm_sendmsg_recvmsg(int client_sock, + struct sockaddr *client_addr, + socklen_t client_addrlen, + const struct msghdr *client_msg, + int server_sock, + struct sockaddr *server_addr, + socklen_t server_addrlen, + void *cmsg, int cmsg_len) +{ +#define MAX_BUF_LEN 64 +#define SMALL_BUF_LEN (sizeof(TEST_STR_SMALL) - 1 - 2) + char buf[MAX_BUF_LEN]; + char buf2[SMALL_BUF_LEN]; + struct iovec io_vector[2]; + struct msghdr msg; + ssize_t sent; + ssize_t recved; + struct sockaddr_in addr; + socklen_t addrlen = sizeof(addr); + int len, i; + + zassert_not_null(client_addr, "null client addr"); + zassert_not_null(server_addr, "null server addr"); + + /* + * Test client -> server sending + */ + + sent = sendmsg(client_sock, client_msg, 0); + zassert_true(sent > 0, "sendmsg failed (%d)", -errno); + + for (i = 0, len = 0; i < client_msg->msg_iovlen; i++) { + len += client_msg->msg_iov[i].iov_len; + } + + zassert_equal(sent, len, "iovec len (%d) vs sent (%d)", len, sent); + + /* Test first with one iovec */ + io_vector[0].iov_base = buf; + io_vector[0].iov_len = sizeof(buf); + + memset(&msg, 0, sizeof(msg)); + msg.msg_control = cmsg; + msg.msg_controllen = cmsg_len; + msg.msg_iov = io_vector; + msg.msg_iovlen = 1; + msg.msg_name = &addr; + msg.msg_namelen = addrlen; + + /* Test recvmsg(MSG_PEEK) */ + addrlen = sizeof(addr); + recved = recvmsg(server_sock, &msg, MSG_PEEK); + zassert_true(recved > 0, "recvmsg fail, %s (%d)", strerror(errno), errno); + zassert_equal(recved, strlen(TEST_STR_SMALL), + "unexpected received bytes (%d vs %d)", + recved, strlen(TEST_STR_SMALL)); + zassert_equal(sent, recved, "sent(%d)/received(%d) mismatch", + sent, recved); + + zassert_mem_equal(buf, TEST_STR_SMALL, strlen(TEST_STR_SMALL), + "wrong data (%s)", rx_buf); + zassert_equal(addrlen, client_addrlen, "unexpected addrlen"); + + /* Test normal recvmsg() */ + addrlen = sizeof(addr); + clear_buf(rx_buf); + recved = recvmsg(server_sock, &msg, 0); + zassert_true(recved > 0, "recvfrom fail"); + zassert_equal(recved, strlen(TEST_STR_SMALL), + "unexpected received bytes"); + zassert_mem_equal(buf, TEST_STR_SMALL, strlen(TEST_STR_SMALL), + "wrong data (%s)", rx_buf); + zassert_equal(addrlen, client_addrlen, "unexpected addrlen"); + + /* Check the client port */ + if (net_sin(client_addr)->sin_port != ANY_PORT) { + zassert_equal(net_sin(client_addr)->sin_port, + addr.sin_port, + "unexpected client port"); + } + + /* Then send the message again and verify that we could receive + * the full message in smaller chunks too. + */ + sent = sendmsg(client_sock, client_msg, 0); + zassert_true(sent > 0, "sendmsg failed (%d)", -errno); + + for (i = 0, len = 0; i < client_msg->msg_iovlen; i++) { + len += client_msg->msg_iov[i].iov_len; + } + + zassert_equal(sent, len, "iovec len (%d) vs sent (%d)", len, sent); + + /* and then test with two iovec */ + io_vector[0].iov_base = buf2; + io_vector[0].iov_len = sizeof(buf2); + io_vector[1].iov_base = buf; + io_vector[1].iov_len = sizeof(buf); + + memset(&msg, 0, sizeof(msg)); + msg.msg_control = cmsg; + msg.msg_controllen = cmsg_len; + msg.msg_iov = io_vector; + msg.msg_iovlen = 2; + msg.msg_name = &addr; + msg.msg_namelen = addrlen; + + /* Test recvmsg(MSG_PEEK) */ + addrlen = sizeof(addr); + recved = recvmsg(server_sock, &msg, MSG_PEEK); + zassert_true(recved >= 0, "recvfrom fail (errno %d)", errno); + zassert_equal(recved, strlen(TEST_STR_SMALL), + "unexpected received bytes (%d vs %d)", recved, strlen(TEST_STR_SMALL)); + zassert_equal(sent, recved, "sent(%d)/received(%d) mismatch", + sent, recved); + + zassert_mem_equal(msg.msg_iov[0].iov_base, TEST_STR_SMALL, msg.msg_iov[0].iov_len, + "wrong data in %s", "iov[0]"); + zassert_mem_equal(msg.msg_iov[1].iov_base, &TEST_STR_SMALL[msg.msg_iov[0].iov_len], + msg.msg_iov[1].iov_len, + "wrong data in %s", "iov[1]"); + zassert_equal(addrlen, client_addrlen, "unexpected addrlen"); + + /* Test normal recvfrom() */ + addrlen = sizeof(addr); + recved = recvmsg(server_sock, &msg, MSG_PEEK); + zassert_true(recved >= 0, "recvfrom fail (errno %d)", errno); + zassert_equal(recved, strlen(TEST_STR_SMALL), + "unexpected received bytes (%d vs %d)", recved, strlen(TEST_STR_SMALL)); + zassert_equal(sent, recved, "sent(%d)/received(%d) mismatch", + sent, recved); + + zassert_mem_equal(msg.msg_iov[0].iov_base, TEST_STR_SMALL, msg.msg_iov[0].iov_len, + "wrong data in %s", "iov[0]"); + zassert_mem_equal(msg.msg_iov[1].iov_base, &TEST_STR_SMALL[msg.msg_iov[0].iov_len], + msg.msg_iov[1].iov_len, + "wrong data in %s", "iov[1]"); + zassert_equal(addrlen, client_addrlen, "unexpected addrlen"); + + /* Then check that the trucation flag is set correctly */ + sent = sendmsg(client_sock, client_msg, 0); + zassert_true(sent > 0, "sendmsg failed (%d)", -errno); + + for (i = 0, len = 0; i < client_msg->msg_iovlen; i++) { + len += client_msg->msg_iov[i].iov_len; + } + + zassert_equal(sent, len, "iovec len (%d) vs sent (%d)", len, sent); + + /* Test first with one iovec */ + io_vector[0].iov_base = buf2; + io_vector[0].iov_len = sizeof(buf2); + + memset(&msg, 0, sizeof(msg)); + msg.msg_control = cmsg; + msg.msg_controllen = cmsg_len; + msg.msg_iov = io_vector; + msg.msg_iovlen = 1; + msg.msg_name = &addr; + msg.msg_namelen = addrlen; + + /* Test recvmsg */ + addrlen = sizeof(addr); + recved = recvmsg(server_sock, &msg, 0); + zassert_true(recved > 0, "recvmsg fail, %s (%d)", strerror(errno), errno); + zassert_equal(recved, sizeof(buf2), + "unexpected received bytes (%d vs %d)", + recved, sizeof(buf2)); + zassert_true(msg.msg_flags & MSG_TRUNC, "Message not truncated"); + + zassert_mem_equal(buf2, TEST_STR_SMALL, sizeof(buf2), + "wrong data (%s)", buf2); + zassert_equal(addrlen, client_addrlen, "unexpected addrlen"); +} + +ZTEST_USER(net_socket_udp, test_27_recvmsg_user) +{ + int rv; + int client_sock; + int server_sock; + struct sockaddr_in client_addr; + struct sockaddr_in server_addr; + struct msghdr msg; + struct iovec io_vector[1]; + + prepare_sock_udp_v4(MY_IPV4_ADDR, ANY_PORT, &client_sock, &client_addr); + prepare_sock_udp_v4(MY_IPV4_ADDR, SERVER_PORT, &server_sock, &server_addr); + + rv = bind(server_sock, + (struct sockaddr *)&server_addr, + sizeof(server_addr)); + zassert_equal(rv, 0, "server bind failed"); + + rv = bind(client_sock, + (struct sockaddr *)&client_addr, + sizeof(client_addr)); + zassert_equal(rv, 0, "client bind failed"); + + io_vector[0].iov_base = TEST_STR_SMALL; + io_vector[0].iov_len = strlen(TEST_STR_SMALL); + + memset(&msg, 0, sizeof(msg)); + msg.msg_iov = io_vector; + msg.msg_iovlen = 1; + msg.msg_name = &server_addr; + msg.msg_namelen = sizeof(server_addr); + + comm_sendmsg_recvmsg(client_sock, + (struct sockaddr *)&client_addr, + sizeof(client_addr), + &msg, + server_sock, + (struct sockaddr *)&server_addr, + sizeof(server_addr), + NULL, 0); + + rv = close(client_sock); + zassert_equal(rv, 0, "close failed"); + rv = close(server_sock); + zassert_equal(rv, 0, "close failed"); +} + static void after(void *arg) { ARG_UNUSED(arg); From 34929a57e094e63acb2ce2c9b9ae1af016caca1d Mon Sep 17 00:00:00 2001 From: Jukka Rissanen Date: Thu, 23 Nov 2023 14:11:44 +0200 Subject: [PATCH 0321/3723] tests: net: socket: Add TCP tests for recvmsg() Make sure recvmsg() works as expected for TCP data. Signed-off-by: Jukka Rissanen --- tests/net/socket/tcp/prj.conf | 4 + tests/net/socket/tcp/src/main.c | 127 ++++++++++++++++++++++++++++++++ 2 files changed, 131 insertions(+) diff --git a/tests/net/socket/tcp/prj.conf b/tests/net/socket/tcp/prj.conf index 9f9534aec4c..15499df7131 100644 --- a/tests/net/socket/tcp/prj.conf +++ b/tests/net/socket/tcp/prj.conf @@ -52,3 +52,7 @@ CONFIG_NET_CONTEXT_SNDBUF=y #CONFIG_LOG_MODE_DEFERRED=y #CONFIG_NET_LOG=y #CONFIG_NET_TCP_LOG_LEVEL_DBG=y + +# Because of userspace and recvmsg() we need some extra heap in order to +# copy the iovec in the recvmsg tests. +CONFIG_HEAP_MEM_POOL_SIZE=512 diff --git a/tests/net/socket/tcp/src/main.c b/tests/net/socket/tcp/src/main.c index c96ecb029a2..90de450ac11 100644 --- a/tests/net/socket/tcp/src/main.c +++ b/tests/net/socket/tcp/src/main.c @@ -16,6 +16,13 @@ LOG_MODULE_REGISTER(net_test, CONFIG_NET_SOCKETS_LOG_LEVEL); #define TEST_STR_SMALL "test" +#define TEST_STR_LONG \ + "The Zephyr Project, a Linux Foundation hosted Collaboration " \ + "Project, is an open source collaborative effort uniting leaders " \ + "from across the industry to build a best-in-breed small, scalable, " \ + "real-time operating system (RTOS) optimized for resource-" \ + "constrained devices, across multiple architectures." + #define MY_IPV4_ADDR "127.0.0.1" #define MY_IPV6_ADDR "::1" @@ -128,6 +135,21 @@ static void test_recvfrom(int sock, "unexpected data"); } +static void test_recvmsg(int sock, + struct msghdr *msg, + int flags, + size_t expected, + int line) +{ + ssize_t recved; + + recved = recvmsg(sock, msg, flags); + + zassert_equal(recved, expected, + "line %d, unexpected received bytes (%d vs %d)", + line, recved, expected); +} + static void test_shutdown(int sock, int how) { zassert_equal(shutdown(sock, how), @@ -697,6 +719,111 @@ ZTEST_USER(net_socket_tcp, test_v6_sendto_recvfrom_null_dest) k_sleep(TCP_TEARDOWN_TIMEOUT); } +ZTEST_USER(net_socket_tcp, test_v4_sendto_recvmsg) +{ + int c_sock; + int s_sock; + int new_sock; + struct sockaddr_in c_saddr; + struct sockaddr_in s_saddr; + struct sockaddr addr; + socklen_t addrlen = sizeof(addr); +#define MAX_BUF_LEN 64 +#define SMALL_BUF_LEN (sizeof(TEST_STR_SMALL) - 1 - 2) + char buf[MAX_BUF_LEN]; + char buf2[SMALL_BUF_LEN]; + char buf3[MAX_BUF_LEN]; + struct iovec io_vector[3]; + struct msghdr msg; + int i, len; + + prepare_sock_tcp_v4(MY_IPV4_ADDR, ANY_PORT, &c_sock, &c_saddr); + prepare_sock_tcp_v4(MY_IPV4_ADDR, SERVER_PORT, &s_sock, &s_saddr); + + test_bind(s_sock, (struct sockaddr *)&s_saddr, sizeof(s_saddr)); + test_listen(s_sock); + + test_connect(c_sock, (struct sockaddr *)&s_saddr, sizeof(s_saddr)); + test_sendto(c_sock, TEST_STR_SMALL, strlen(TEST_STR_SMALL), 0, + (struct sockaddr *)&s_saddr, sizeof(s_saddr)); + + test_accept(s_sock, &new_sock, &addr, &addrlen); + zassert_equal(addrlen, sizeof(struct sockaddr_in), "wrong addrlen"); + + /* Read data first in one chunk */ + io_vector[0].iov_base = buf; + io_vector[0].iov_len = sizeof(buf); + + memset(&msg, 0, sizeof(msg)); + msg.msg_iov = io_vector; + msg.msg_iovlen = 1; + msg.msg_name = &addr; + msg.msg_namelen = addrlen; + + test_recvmsg(new_sock, &msg, MSG_PEEK, strlen(TEST_STR_SMALL), + __LINE__); + zassert_mem_equal(buf, TEST_STR_SMALL, strlen(TEST_STR_SMALL), + "wrong data (%s)", buf); + + /* Then in two chunks */ + io_vector[0].iov_base = buf2; + io_vector[0].iov_len = sizeof(buf2); + io_vector[1].iov_base = buf; + io_vector[1].iov_len = sizeof(buf); + + memset(&msg, 0, sizeof(msg)); + msg.msg_iov = io_vector; + msg.msg_iovlen = 2; + msg.msg_name = &addr; + msg.msg_namelen = addrlen; + + test_recvmsg(new_sock, &msg, 0, strlen(TEST_STR_SMALL), __LINE__); + zassert_mem_equal(msg.msg_iov[0].iov_base, TEST_STR_SMALL, msg.msg_iov[0].iov_len, + "wrong data in %s", "iov[0]"); + zassert_mem_equal(msg.msg_iov[1].iov_base, &TEST_STR_SMALL[msg.msg_iov[0].iov_len], + msg.msg_iov[1].iov_len, + "wrong data in %s", "iov[1]"); + + /* Send larger test buffer */ + test_sendto(c_sock, TEST_STR_LONG, strlen(TEST_STR_LONG), 0, + (struct sockaddr *)&s_saddr, sizeof(s_saddr)); + + /* Verify that the data is truncated */ + io_vector[0].iov_base = buf; + io_vector[0].iov_len = sizeof(buf); + io_vector[1].iov_base = buf2; + io_vector[1].iov_len = sizeof(buf2); + io_vector[2].iov_base = buf3; + io_vector[2].iov_len = sizeof(buf3); + + memset(&msg, 0, sizeof(msg)); + msg.msg_iov = io_vector; + msg.msg_iovlen = 3; + msg.msg_name = &addr; + msg.msg_namelen = addrlen; + + for (i = 0, len = 0; i < msg.msg_iovlen; i++) { + len += msg.msg_iov[i].iov_len; + } + + test_recvmsg(new_sock, &msg, 0, len, __LINE__); + zassert_mem_equal(msg.msg_iov[0].iov_base, TEST_STR_LONG, msg.msg_iov[0].iov_len, + "wrong data in %s", "iov[0]"); + zassert_mem_equal(msg.msg_iov[1].iov_base, &TEST_STR_LONG[msg.msg_iov[0].iov_len], + msg.msg_iov[1].iov_len, + "wrong data in %s", "iov[1]"); + zassert_mem_equal(msg.msg_iov[2].iov_base, + &TEST_STR_LONG[msg.msg_iov[0].iov_len + msg.msg_iov[1].iov_len], + msg.msg_iov[2].iov_len, + "wrong data in %s", "iov[2]"); + + test_close(new_sock); + test_close(s_sock); + test_close(c_sock); + + k_sleep(TCP_TEARDOWN_TIMEOUT); +} + void _test_recv_enotconn(int c_sock, int s_sock) { char rx_buf[1] = {0}; From bb880c645795ce558948eec5e56b3484f8536291 Mon Sep 17 00:00:00 2001 From: Jukka Rissanen Date: Wed, 22 Nov 2023 17:29:59 +0200 Subject: [PATCH 0322/3723] tests: net: udp: Make receive timeout shorter No need to wait 2.5 seconds for the test to pass, 400ms wait is enough. Signed-off-by: Jukka Rissanen --- tests/net/socket/udp/src/main.c | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/tests/net/socket/udp/src/main.c b/tests/net/socket/udp/src/main.c index fc9361330a3..ee136f91a08 100644 --- a/tests/net/socket/udp/src/main.c +++ b/tests/net/socket/udp/src/main.c @@ -783,8 +783,8 @@ ZTEST(net_socket_udp, test_09_so_rcvtimeo) uint32_t start_time, time_diff; struct timeval optval = { - .tv_sec = 2, - .tv_usec = 500000, + .tv_sec = 0, + .tv_usec = 300000, }; prepare_sock_udp_v4(MY_IPV4_ADDR, 55555, &sock1, &bind_addr4); @@ -800,7 +800,7 @@ ZTEST(net_socket_udp, test_09_so_rcvtimeo) sizeof(optval)); zassert_equal(rv, 0, "setsockopt failed (%d)", errno); - optval.tv_usec = 0; + optval.tv_usec = 400000; rv = setsockopt(sock2, SOL_SOCKET, SO_RCVTIMEO, &optval, sizeof(optval)); zassert_equal(rv, 0, "setsockopt failed (%d)", errno); @@ -814,7 +814,7 @@ ZTEST(net_socket_udp, test_09_so_rcvtimeo) zassert_equal(recved, -1, "Unexpected return code"); zassert_equal(errno, EAGAIN, "Unexpected errno value: %d", errno); - zassert_true(time_diff >= 2500, "Expected timeout after 2500ms but " + zassert_true(time_diff >= 300, "Expected timeout after 300ms but " "was %dms", time_diff); start_time = k_uptime_get_32(); @@ -824,7 +824,7 @@ ZTEST(net_socket_udp, test_09_so_rcvtimeo) zassert_equal(recved, -1, "Unexpected return code"); zassert_equal(errno, EAGAIN, "Unexpected errno value: %d", errno); - zassert_true(time_diff >= 2000, "Expected timeout after 2000ms but " + zassert_true(time_diff >= 400, "Expected timeout after 400ms but " "was %dms", time_diff); rv = close(sock1); From 760c2f2949b9e18c186796c6e9d40d01fbc222de Mon Sep 17 00:00:00 2001 From: Jukka Rissanen Date: Wed, 22 Nov 2023 17:43:57 +0200 Subject: [PATCH 0323/3723] net: sockets: Remove extra check from sendmsg() There was double "if (status < 0)" check in sendmsg(), remove the extra check. Signed-off-by: Jukka Rissanen --- subsys/net/lib/sockets/sockets.c | 18 ++++++++---------- 1 file changed, 8 insertions(+), 10 deletions(-) diff --git a/subsys/net/lib/sockets/sockets.c b/subsys/net/lib/sockets/sockets.c index 95d45c2fd53..8bdd99b61c9 100644 --- a/subsys/net/lib/sockets/sockets.c +++ b/subsys/net/lib/sockets/sockets.c @@ -909,19 +909,17 @@ ssize_t zsock_sendmsg_ctx(struct net_context *ctx, const struct msghdr *msg, while (1) { status = net_context_sendmsg(ctx, msg, flags, NULL, timeout, NULL); if (status < 0) { + status = send_check_and_wait(ctx, status, + buf_timeout, + timeout, &retry_timeout); if (status < 0) { - status = send_check_and_wait(ctx, status, - buf_timeout, - timeout, &retry_timeout); - if (status < 0) { - return status; - } + return status; + } - /* Update the timeout value in case loop is repeated. */ - timeout = sys_timepoint_timeout(end); + /* Update the timeout value in case loop is repeated. */ + timeout = sys_timepoint_timeout(end); - continue; - } + continue; } break; From c3acd56e27b8305a76390c24d2689783424a8723 Mon Sep 17 00:00:00 2001 From: Jukka Rissanen Date: Wed, 22 Nov 2023 15:07:39 +0200 Subject: [PATCH 0324/3723] net: context: Add support for setting receive pktinfo option Add low level support for setting IP_PKTINFO or IPV6_RECVPKTINFO socket options. The support is disabled by default. Signed-off-by: Jukka Rissanen --- include/zephyr/net/net_context.h | 4 ++ subsys/net/ip/Kconfig | 8 ++++ subsys/net/ip/net_context.c | 73 ++++++++++++++++++++++++++++++++ subsys/net/ip/net_private.h | 6 +++ 4 files changed, 91 insertions(+) diff --git a/include/zephyr/net/net_context.h b/include/zephyr/net/net_context.h index ea116a24846..7e73bf8eee7 100644 --- a/include/zephyr/net/net_context.h +++ b/include/zephyr/net/net_context.h @@ -331,6 +331,9 @@ __net_socket struct net_context { #endif #if defined(CONFIG_NET_IPV4_MAPPING_TO_IPV6) bool ipv6_v6only; +#endif +#if defined(CONFIG_NET_CONTEXT_RECV_PKTINFO) + bool recv_pktinfo; #endif } options; @@ -1102,6 +1105,7 @@ enum net_context_option { NET_OPT_REUSEADDR = 9, NET_OPT_REUSEPORT = 10, NET_OPT_IPV6_V6ONLY = 11, + NET_OPT_RECV_PKTINFO = 12, }; /** diff --git a/subsys/net/ip/Kconfig b/subsys/net/ip/Kconfig index fffa028b628..1f78eaaf839 100644 --- a/subsys/net/ip/Kconfig +++ b/subsys/net/ip/Kconfig @@ -737,6 +737,14 @@ config NET_CONTEXT_REUSEPORT Allow to set the SO_REUSEPORT flag on a socket. This enables multiple sockets to bind to the same local IP address and port combination. +config NET_CONTEXT_RECV_PKTINFO + bool "Add receive PKTINFO support to net_context" + depends on NET_UDP + help + Allow to set the IP_PKTINFO or IPV6_RECVPKTINFO flags on a socket. + This way user can get extra information about the received data in the + socket. + config NET_TEST bool "Network Testing" help diff --git a/subsys/net/ip/net_context.c b/subsys/net/ip/net_context.c index a628297f650..f92cd5c0875 100644 --- a/subsys/net/ip/net_context.c +++ b/subsys/net/ip/net_context.c @@ -89,6 +89,17 @@ bool net_context_is_v6only_set(struct net_context *context) #endif } +bool net_context_is_recv_pktinfo_set(struct net_context *context) +{ +#if defined(CONFIG_NET_CONTEXT_RECV_PKTINFO) + return context->options.recv_pktinfo; +#else + ARG_UNUSED(context); + + return false; +#endif +} + #if defined(CONFIG_NET_UDP) || defined(CONFIG_NET_TCP) static inline bool is_in_tcp_listen_state(struct net_context *context) { @@ -1558,6 +1569,36 @@ static int get_context_ipv6_v6only(struct net_context *context, #endif } +static int get_context_recv_pktinfo(struct net_context *context, + void *value, size_t *len) +{ +#if defined(CONFIG_NET_CONTEXT_RECV_PKTINFO) + if (!value || !len) { + return -EINVAL; + } + + if (*len != sizeof(int)) { + return -EINVAL; + } + + if (context->options.recv_pktinfo == true) { + *((int *)value) = (int) true; + } else { + *((int *)value) = (int) false; + } + + *len = sizeof(int); + + return 0; +#else + ARG_UNUSED(context); + ARG_UNUSED(value); + ARG_UNUSED(len); + + return -ENOTSUP; +#endif +} + /* If buf is not NULL, then use it. Otherwise read the data to be written * to net_pkt from msghdr. */ @@ -2697,6 +2738,32 @@ static int set_context_ipv6_v6only(struct net_context *context, #endif } +static int set_context_recv_pktinfo(struct net_context *context, + const void *value, size_t len) +{ +#if defined(CONFIG_NET_CONTEXT_RECV_PKTINFO) + bool pktinfo = false; + + if (len != sizeof(int)) { + return -EINVAL; + } + + if (*((int *) value) != 0) { + pktinfo = true; + } + + context->options.recv_pktinfo = pktinfo; + + return 0; +#else + ARG_UNUSED(context); + ARG_UNUSED(value); + ARG_UNUSED(len); + + return -ENOTSUP; +#endif +} + int net_context_set_option(struct net_context *context, enum net_context_option option, const void *value, size_t len) @@ -2745,6 +2812,9 @@ int net_context_set_option(struct net_context *context, case NET_OPT_IPV6_V6ONLY: ret = set_context_ipv6_v6only(context, value, len); break; + case NET_OPT_RECV_PKTINFO: + ret = set_context_recv_pktinfo(context, value, len); + break; } k_mutex_unlock(&context->lock); @@ -2800,6 +2870,9 @@ int net_context_get_option(struct net_context *context, case NET_OPT_IPV6_V6ONLY: ret = get_context_ipv6_v6only(context, value, len); break; + case NET_OPT_RECV_PKTINFO: + ret = get_context_recv_pktinfo(context, value, len); + break; } k_mutex_unlock(&context->lock); diff --git a/subsys/net/ip/net_private.h b/subsys/net/ip/net_private.h index 73b15ae4cfa..780b9fbea04 100644 --- a/subsys/net/ip/net_private.h +++ b/subsys/net/ip/net_private.h @@ -72,6 +72,7 @@ extern const char *net_context_state(struct net_context *context); extern bool net_context_is_reuseaddr_set(struct net_context *context); extern bool net_context_is_reuseport_set(struct net_context *context); extern bool net_context_is_v6only_set(struct net_context *context); +extern bool net_context_is_recv_pktinfo_set(struct net_context *context); extern void net_pkt_init(void); extern void net_tc_tx_init(void); extern void net_tc_rx_init(void); @@ -95,6 +96,11 @@ static inline bool net_context_is_reuseport_set(struct net_context *context) ARG_UNUSED(context); return false; } +static inline bool net_context_is_recv_pktinfo_set(struct net_context *context) +{ + ARG_UNUSED(context); + return false; +} #endif #if defined(CONFIG_NET_NATIVE) From 80704bb3617dc651fdb1bc4fa0bb05a6f6aabe79 Mon Sep 17 00:00:00 2001 From: Jukka Rissanen Date: Wed, 22 Nov 2023 15:08:59 +0200 Subject: [PATCH 0325/3723] net: socket: Add support for setting pktinfo options Add IP_PKTINFO or IPV6_RECVPKTINFO BSD socket options that can be used to get extra information of received data in the ancillary data in recvmsg() call. For IPV6_RECVPKTINFO see RFC 3542 for details. For IP_PKTINFO see Linux ip(7) manual page for details. Signed-off-by: Jukka Rissanen --- include/zephyr/net/socket.h | 23 +++++++++++++++++++++ subsys/net/lib/sockets/sockets.c | 34 ++++++++++++++++++++++++++++++++ 2 files changed, 57 insertions(+) diff --git a/include/zephyr/net/socket.h b/include/zephyr/net/socket.h index 7d0c2c79c91..adf756c3650 100644 --- a/include/zephyr/net/socket.h +++ b/include/zephyr/net/socket.h @@ -1095,10 +1095,33 @@ struct ifreq { /** sockopt: Set or receive the Type-Of-Service value for an outgoing packet. */ #define IP_TOS 1 +/** sockopt: Pass an IP_PKTINFO ancillary message that contains a + * pktinfo structure that supplies some information about the + * incoming packet. + */ +#define IP_PKTINFO 8 + +struct in_pktinfo { + unsigned int ipi_ifindex; /* Interface index */ + struct in_addr ipi_spec_dst; /* Local address */ + struct in_addr ipi_addr; /* Header Destination address */ +}; + /* Socket options for IPPROTO_IPV6 level */ /** sockopt: Don't support IPv4 access (ignored, for compatibility) */ #define IPV6_V6ONLY 26 +/** sockopt: Pass an IPV6_RECVPKTINFO ancillary message that contains a + * in6_pktinfo structure that supplies some information about the + * incoming packet. See RFC 3542. + */ +#define IPV6_RECVPKTINFO 49 + +struct in6_pktinfo { + struct in6_addr ipi6_addr; /* src/dst IPv6 address */ + unsigned int ipi6_ifindex; /* send/recv interface index */ +}; + /** sockopt: Set or receive the traffic class value for an outgoing packet. */ #define IPV6_TCLASS 67 diff --git a/subsys/net/lib/sockets/sockets.c b/subsys/net/lib/sockets/sockets.c index 8bdd99b61c9..d1e2a69aa1d 100644 --- a/subsys/net/lib/sockets/sockets.c +++ b/subsys/net/lib/sockets/sockets.c @@ -2756,6 +2756,23 @@ int zsock_setsockopt_ctx(struct net_context *ctx, int level, int optname, return 0; } + break; + + case IP_PKTINFO: + if (IS_ENABLED(CONFIG_NET_IPV4) && + IS_ENABLED(CONFIG_NET_CONTEXT_RECV_PKTINFO)) { + ret = net_context_set_option(ctx, + NET_OPT_RECV_PKTINFO, + optval, + optlen); + if (ret < 0) { + errno = -ret; + return -1; + } + + return 0; + } + break; } @@ -2777,6 +2794,23 @@ int zsock_setsockopt_ctx(struct net_context *ctx, int level, int optname, return 0; + case IPV6_RECVPKTINFO: + if (IS_ENABLED(CONFIG_NET_IPV6) && + IS_ENABLED(CONFIG_NET_CONTEXT_RECV_PKTINFO)) { + ret = net_context_set_option(ctx, + NET_OPT_RECV_PKTINFO, + optval, + optlen); + if (ret < 0) { + errno = -ret; + return -1; + } + + return 0; + } + + break; + case IPV6_TCLASS: if (IS_ENABLED(CONFIG_NET_CONTEXT_DSCP_ECN)) { ret = net_context_set_option(ctx, From 5488e76bb20c317624616d69afd3594d9502f516 Mon Sep 17 00:00:00 2001 From: Jukka Rissanen Date: Thu, 23 Nov 2023 15:46:36 +0200 Subject: [PATCH 0326/3723] net: socket: Add support for filling receive pktinfo data If user has set either IP_PKTINFO (for IPv4) or IPV6_RECVPKTINFO (for IPv6) socket options, then the system will return relevant information in recvmsg() ancillary data. Fixes #36415 Signed-off-by: Jukka Rissanen --- include/zephyr/net/socket.h | 5 ++ subsys/net/lib/sockets/sockets.c | 99 ++++++++++++++++++++++++++++++++ 2 files changed, 104 insertions(+) diff --git a/include/zephyr/net/socket.h b/include/zephyr/net/socket.h index adf756c3650..756688d9b86 100644 --- a/include/zephyr/net/socket.h +++ b/include/zephyr/net/socket.h @@ -57,6 +57,9 @@ struct zsock_pollfd { /** zsock_recv: Read data without removing it from socket input queue */ #define ZSOCK_MSG_PEEK 0x02 +/** zsock_recvmsg: Control data buffer too small. + */ +#define ZSOCK_MSG_CTRUNC 0x08 /** zsock_recv: return the real length of the datagram, even when it was longer * than the passed buffer */ @@ -979,6 +982,8 @@ static inline char *inet_ntop(sa_family_t family, const void *src, char *dst, /** POSIX wrapper for @ref ZSOCK_MSG_PEEK */ #define MSG_PEEK ZSOCK_MSG_PEEK +/** POSIX wrapper for @ref ZSOCK_MSG_CTRUNC */ +#define MSG_CTRUNC ZSOCK_MSG_CTRUNC /** POSIX wrapper for @ref ZSOCK_MSG_TRUNC */ #define MSG_TRUNC ZSOCK_MSG_TRUNC /** POSIX wrapper for @ref ZSOCK_MSG_DONTWAIT */ diff --git a/subsys/net/lib/sockets/sockets.c b/subsys/net/lib/sockets/sockets.c index d1e2a69aa1d..d7697e60b6c 100644 --- a/subsys/net/lib/sockets/sockets.c +++ b/subsys/net/lib/sockets/sockets.c @@ -1191,6 +1191,96 @@ int zsock_wait_data(struct net_context *ctx, k_timeout_t *timeout) return 0; } + +static int insert_pktinfo(struct msghdr *msg, int level, int type, + void *pktinfo, size_t pktinfo_len) +{ + struct cmsghdr *cmsg; + + if (msg->msg_controllen < pktinfo_len) { + return -EINVAL; + } + + cmsg = CMSG_FIRSTHDR(msg); + if (cmsg == NULL) { + return -EINVAL; + } + + cmsg->cmsg_len = CMSG_LEN(pktinfo_len); + cmsg->cmsg_level = level; + cmsg->cmsg_type = type; + + memcpy(CMSG_DATA(cmsg), pktinfo, pktinfo_len); + + return 0; +} + +static int add_pktinfo(struct net_context *ctx, + struct net_pkt *pkt, + struct msghdr *msg) +{ + int ret = -ENOTSUP; + struct net_pkt_cursor backup; + + net_pkt_cursor_backup(pkt, &backup); + net_pkt_cursor_init(pkt); + + if (IS_ENABLED(CONFIG_NET_IPV4) && net_pkt_family(pkt) == AF_INET) { + NET_PKT_DATA_ACCESS_CONTIGUOUS_DEFINE(ipv4_access, + struct net_ipv4_hdr); + struct in_pktinfo info; + struct net_ipv4_hdr *ipv4_hdr; + + ipv4_hdr = (struct net_ipv4_hdr *)net_pkt_get_data( + pkt, &ipv4_access); + if (ipv4_hdr == NULL || + net_pkt_acknowledge_data(pkt, &ipv4_access) || + net_pkt_skip(pkt, net_pkt_ipv4_opts_len(pkt))) { + ret = -ENOBUFS; + goto out; + } + + net_ipv4_addr_copy_raw((uint8_t *)&info.ipi_addr, ipv4_hdr->dst); + net_ipv4_addr_copy_raw((uint8_t *)&info.ipi_spec_dst, + (uint8_t *)net_sin_ptr(&ctx->local)->sin_addr); + info.ipi_ifindex = ctx->iface; + + ret = insert_pktinfo(msg, IPPROTO_IP, IP_PKTINFO, + &info, sizeof(info)); + + goto out; + } + + if (IS_ENABLED(CONFIG_NET_IPV6) && net_pkt_family(pkt) == AF_INET6) { + NET_PKT_DATA_ACCESS_CONTIGUOUS_DEFINE(ipv6_access, + struct net_ipv6_hdr); + struct in6_pktinfo info; + struct net_ipv6_hdr *ipv6_hdr; + + ipv6_hdr = (struct net_ipv6_hdr *)net_pkt_get_data( + pkt, &ipv6_access); + if (ipv6_hdr == NULL || + net_pkt_acknowledge_data(pkt, &ipv6_access) || + net_pkt_skip(pkt, net_pkt_ipv6_ext_len(pkt))) { + ret = -ENOBUFS; + goto out; + } + + net_ipv6_addr_copy_raw((uint8_t *)&info.ipi6_addr, ipv6_hdr->dst); + info.ipi6_ifindex = ctx->iface; + + ret = insert_pktinfo(msg, IPPROTO_IPV6, IPV6_RECVPKTINFO, + &info, sizeof(info)); + + goto out; + } + +out: + net_pkt_cursor_restore(pkt, &backup); + + return ret; +} + static inline ssize_t zsock_recv_dgram(struct net_context *ctx, struct msghdr *msg, void *buf, @@ -1336,6 +1426,15 @@ static inline ssize_t zsock_recv_dgram(struct net_context *ctx, } } + if (msg != NULL && msg->msg_control != NULL && msg->msg_controllen > 0) { + if (IS_ENABLED(CONFIG_NET_CONTEXT_RECV_PKTINFO) && + net_context_is_recv_pktinfo_set(ctx)) { + if (add_pktinfo(ctx, pkt, msg) < 0) { + msg->msg_flags |= ZSOCK_MSG_CTRUNC; + } + } + } + if (IS_ENABLED(CONFIG_NET_PKT_RXTIME_STATS) && !(flags & ZSOCK_MSG_PEEK)) { net_socket_update_tc_rx_time(pkt, k_cycle_get_32()); From 5539a47eb672ef9b68d44099a1112e7986ec14ce Mon Sep 17 00:00:00 2001 From: Jukka Rissanen Date: Thu, 23 Nov 2023 15:50:36 +0200 Subject: [PATCH 0327/3723] tests: net: socket: Add recv pktinfo ancillary tests for recvmsg Make sure recvmsg() is able to return IPv4 IP_PKTINFO and IPv6 IPV6_RECVPKTINFO ancillary data to the caller. Signed-off-by: Jukka Rissanen --- tests/net/socket/udp/src/main.c | 300 ++++++++++++++++++++++++----- tests/net/socket/udp/testcase.yaml | 3 + 2 files changed, 253 insertions(+), 50 deletions(-) diff --git a/tests/net/socket/udp/src/main.c b/tests/net/socket/udp/src/main.c index ee136f91a08..48162d634b2 100644 --- a/tests/net/socket/udp/src/main.c +++ b/tests/net/socket/udp/src/main.c @@ -1439,18 +1439,18 @@ static void comm_sendmsg_recvmsg(int client_sock, int server_sock, struct sockaddr *server_addr, socklen_t server_addrlen, - void *cmsg, int cmsg_len) + struct msghdr *msg, + void *cmsgbuf, int cmsgbuf_len) { #define MAX_BUF_LEN 64 #define SMALL_BUF_LEN (sizeof(TEST_STR_SMALL) - 1 - 2) char buf[MAX_BUF_LEN]; char buf2[SMALL_BUF_LEN]; struct iovec io_vector[2]; - struct msghdr msg; ssize_t sent; ssize_t recved; - struct sockaddr_in addr; - socklen_t addrlen = sizeof(addr); + struct sockaddr addr; + socklen_t addrlen = server_addrlen; int len, i; zassert_not_null(client_addr, "null client addr"); @@ -1461,7 +1461,7 @@ static void comm_sendmsg_recvmsg(int client_sock, */ sent = sendmsg(client_sock, client_msg, 0); - zassert_true(sent > 0, "sendmsg failed (%d)", -errno); + zassert_true(sent > 0, "sendmsg failed, %s (%d)", strerror(errno), -errno); for (i = 0, len = 0; i < client_msg->msg_iovlen; i++) { len += client_msg->msg_iov[i].iov_len; @@ -1473,18 +1473,17 @@ static void comm_sendmsg_recvmsg(int client_sock, io_vector[0].iov_base = buf; io_vector[0].iov_len = sizeof(buf); - memset(&msg, 0, sizeof(msg)); - msg.msg_control = cmsg; - msg.msg_controllen = cmsg_len; - msg.msg_iov = io_vector; - msg.msg_iovlen = 1; - msg.msg_name = &addr; - msg.msg_namelen = addrlen; + memset(msg, 0, sizeof(*msg)); + msg->msg_control = cmsgbuf; + msg->msg_controllen = cmsgbuf_len; + msg->msg_iov = io_vector; + msg->msg_iovlen = 1; + msg->msg_name = &addr; + msg->msg_namelen = addrlen; /* Test recvmsg(MSG_PEEK) */ - addrlen = sizeof(addr); - recved = recvmsg(server_sock, &msg, MSG_PEEK); - zassert_true(recved > 0, "recvmsg fail, %s (%d)", strerror(errno), errno); + recved = recvmsg(server_sock, msg, MSG_PEEK); + zassert_true(recved > 0, "recvmsg fail, %s (%d)", strerror(errno), -errno); zassert_equal(recved, strlen(TEST_STR_SMALL), "unexpected received bytes (%d vs %d)", recved, strlen(TEST_STR_SMALL)); @@ -1496,9 +1495,8 @@ static void comm_sendmsg_recvmsg(int client_sock, zassert_equal(addrlen, client_addrlen, "unexpected addrlen"); /* Test normal recvmsg() */ - addrlen = sizeof(addr); clear_buf(rx_buf); - recved = recvmsg(server_sock, &msg, 0); + recved = recvmsg(server_sock, msg, 0); zassert_true(recved > 0, "recvfrom fail"); zassert_equal(recved, strlen(TEST_STR_SMALL), "unexpected received bytes"); @@ -1507,10 +1505,20 @@ static void comm_sendmsg_recvmsg(int client_sock, zassert_equal(addrlen, client_addrlen, "unexpected addrlen"); /* Check the client port */ - if (net_sin(client_addr)->sin_port != ANY_PORT) { - zassert_equal(net_sin(client_addr)->sin_port, - addr.sin_port, - "unexpected client port"); + if (addr.sa_family == AF_INET) { + if (net_sin(client_addr)->sin_port != ANY_PORT) { + zassert_equal(net_sin(client_addr)->sin_port, + net_sin(&addr)->sin_port, + "unexpected client port"); + } + } + + if (addr.sa_family == AF_INET6) { + if (net_sin6(client_addr)->sin6_port != ANY_PORT) { + zassert_equal(net_sin6(client_addr)->sin6_port, + net_sin6(&addr)->sin6_port, + "unexpected client port"); + } } /* Then send the message again and verify that we could receive @@ -1531,43 +1539,41 @@ static void comm_sendmsg_recvmsg(int client_sock, io_vector[1].iov_base = buf; io_vector[1].iov_len = sizeof(buf); - memset(&msg, 0, sizeof(msg)); - msg.msg_control = cmsg; - msg.msg_controllen = cmsg_len; - msg.msg_iov = io_vector; - msg.msg_iovlen = 2; - msg.msg_name = &addr; - msg.msg_namelen = addrlen; + memset(msg, 0, sizeof(*msg)); + msg->msg_control = cmsgbuf; + msg->msg_controllen = cmsgbuf_len; + msg->msg_iov = io_vector; + msg->msg_iovlen = 2; + msg->msg_name = &addr; + msg->msg_namelen = addrlen; /* Test recvmsg(MSG_PEEK) */ - addrlen = sizeof(addr); - recved = recvmsg(server_sock, &msg, MSG_PEEK); + recved = recvmsg(server_sock, msg, MSG_PEEK); zassert_true(recved >= 0, "recvfrom fail (errno %d)", errno); zassert_equal(recved, strlen(TEST_STR_SMALL), "unexpected received bytes (%d vs %d)", recved, strlen(TEST_STR_SMALL)); zassert_equal(sent, recved, "sent(%d)/received(%d) mismatch", sent, recved); - zassert_mem_equal(msg.msg_iov[0].iov_base, TEST_STR_SMALL, msg.msg_iov[0].iov_len, + zassert_mem_equal(msg->msg_iov[0].iov_base, TEST_STR_SMALL, msg->msg_iov[0].iov_len, "wrong data in %s", "iov[0]"); - zassert_mem_equal(msg.msg_iov[1].iov_base, &TEST_STR_SMALL[msg.msg_iov[0].iov_len], - msg.msg_iov[1].iov_len, + zassert_mem_equal(msg->msg_iov[1].iov_base, &TEST_STR_SMALL[msg->msg_iov[0].iov_len], + msg->msg_iov[1].iov_len, "wrong data in %s", "iov[1]"); zassert_equal(addrlen, client_addrlen, "unexpected addrlen"); /* Test normal recvfrom() */ - addrlen = sizeof(addr); - recved = recvmsg(server_sock, &msg, MSG_PEEK); + recved = recvmsg(server_sock, msg, MSG_PEEK); zassert_true(recved >= 0, "recvfrom fail (errno %d)", errno); zassert_equal(recved, strlen(TEST_STR_SMALL), "unexpected received bytes (%d vs %d)", recved, strlen(TEST_STR_SMALL)); zassert_equal(sent, recved, "sent(%d)/received(%d) mismatch", sent, recved); - zassert_mem_equal(msg.msg_iov[0].iov_base, TEST_STR_SMALL, msg.msg_iov[0].iov_len, + zassert_mem_equal(msg->msg_iov[0].iov_base, TEST_STR_SMALL, msg->msg_iov[0].iov_len, "wrong data in %s", "iov[0]"); - zassert_mem_equal(msg.msg_iov[1].iov_base, &TEST_STR_SMALL[msg.msg_iov[0].iov_len], - msg.msg_iov[1].iov_len, + zassert_mem_equal(msg->msg_iov[1].iov_base, &TEST_STR_SMALL[msg->msg_iov[0].iov_len], + msg->msg_iov[1].iov_len, "wrong data in %s", "iov[1]"); zassert_equal(addrlen, client_addrlen, "unexpected addrlen"); @@ -1585,22 +1591,21 @@ static void comm_sendmsg_recvmsg(int client_sock, io_vector[0].iov_base = buf2; io_vector[0].iov_len = sizeof(buf2); - memset(&msg, 0, sizeof(msg)); - msg.msg_control = cmsg; - msg.msg_controllen = cmsg_len; - msg.msg_iov = io_vector; - msg.msg_iovlen = 1; - msg.msg_name = &addr; - msg.msg_namelen = addrlen; + memset(msg, 0, sizeof(*msg)); + msg->msg_control = cmsgbuf; + msg->msg_controllen = cmsgbuf_len; + msg->msg_iov = io_vector; + msg->msg_iovlen = 1; + msg->msg_name = &addr; + msg->msg_namelen = addrlen; /* Test recvmsg */ - addrlen = sizeof(addr); - recved = recvmsg(server_sock, &msg, 0); + recved = recvmsg(server_sock, msg, 0); zassert_true(recved > 0, "recvmsg fail, %s (%d)", strerror(errno), errno); zassert_equal(recved, sizeof(buf2), "unexpected received bytes (%d vs %d)", recved, sizeof(buf2)); - zassert_true(msg.msg_flags & MSG_TRUNC, "Message not truncated"); + zassert_true(msg->msg_flags & MSG_TRUNC, "Message not truncated"); zassert_mem_equal(buf2, TEST_STR_SMALL, sizeof(buf2), "wrong data (%s)", buf2); @@ -1614,7 +1619,7 @@ ZTEST_USER(net_socket_udp, test_27_recvmsg_user) int server_sock; struct sockaddr_in client_addr; struct sockaddr_in server_addr; - struct msghdr msg; + struct msghdr msg, server_msg; struct iovec io_vector[1]; prepare_sock_udp_v4(MY_IPV4_ADDR, ANY_PORT, &client_sock, &client_addr); @@ -1646,7 +1651,7 @@ ZTEST_USER(net_socket_udp, test_27_recvmsg_user) server_sock, (struct sockaddr *)&server_addr, sizeof(server_addr), - NULL, 0); + &server_msg, NULL, 0); rv = close(client_sock); zassert_equal(rv, 0, "close failed"); @@ -1654,6 +1659,201 @@ ZTEST_USER(net_socket_udp, test_27_recvmsg_user) zassert_equal(rv, 0, "close failed"); } +static void run_ancillary_recvmsg_test(int client_sock, + struct sockaddr *client_addr, + int client_addr_len, + int server_sock, + struct sockaddr *server_addr, + int server_addr_len) +{ + int rv; + int opt; + int ifindex = 0; + socklen_t optlen; + struct sockaddr addr = { 0 }; + struct net_if *iface; + struct msghdr msg; + struct msghdr server_msg; + struct iovec io_vector[1]; + struct cmsghdr *cmsg, *prevcmsg; + union { + struct cmsghdr hdr; + unsigned char buf[CMSG_SPACE(sizeof(struct in6_pktinfo))]; + } cmsgbuf; +#define SMALL_BUF_LEN (sizeof(TEST_STR_SMALL) - 1 - 2) + char buf[MAX_BUF_LEN]; + + Z_TEST_SKIP_IFNDEF(CONFIG_NET_CONTEXT_RECV_PKTINFO); + + rv = bind(server_sock, server_addr, server_addr_len); + zassert_equal(rv, 0, "server bind failed"); + + rv = bind(client_sock, client_addr, client_addr_len); + zassert_equal(rv, 0, "client bind failed"); + + io_vector[0].iov_base = TEST_STR_SMALL; + io_vector[0].iov_len = strlen(TEST_STR_SMALL); + + memset(&cmsgbuf, 0, sizeof(cmsgbuf)); + + memset(&msg, 0, sizeof(msg)); + msg.msg_iov = io_vector; + msg.msg_iovlen = 1; + msg.msg_name = server_addr; + msg.msg_namelen = server_addr_len; + + comm_sendmsg_recvmsg(client_sock, + client_addr, + client_addr_len, + &msg, + server_sock, + server_addr, + server_addr_len, + &server_msg, &cmsgbuf.buf, sizeof(cmsgbuf.buf)); + + for (prevcmsg = NULL, cmsg = CMSG_FIRSTHDR(&server_msg); + cmsg != NULL && prevcmsg != cmsg; + prevcmsg = cmsg, cmsg = CMSG_NXTHDR(&server_msg, cmsg)) { + if (cmsg->cmsg_level == IPPROTO_IP && + cmsg->cmsg_type == IP_PKTINFO) { + net_sin(&addr)->sin_addr = ((struct in_pktinfo *)CMSG_DATA(cmsg))->ipi_addr; + break; + } + } + + /* As we have not set the socket option, the address should not be set */ + if (server_addr->sa_family == AF_INET) { + zassert_equal(net_sin(&addr)->sin_addr.s_addr, INADDR_ANY, "Source address set!"); + } + + if (server_addr->sa_family == AF_INET6) { + zassert_true(net_sin6(&addr)->sin6_addr.s6_addr32[0] == 0 && + net_sin6(&addr)->sin6_addr.s6_addr32[1] == 0 && + net_sin6(&addr)->sin6_addr.s6_addr32[2] == 0 && + net_sin6(&addr)->sin6_addr.s6_addr32[3] == 0, + "Source address set!"); + } + + opt = 1; + optlen = sizeof(opt); + rv = setsockopt(server_sock, IPPROTO_IP, IP_PKTINFO, &opt, optlen); + zassert_equal(rv, 0, "setsockopt failed (%d)", -errno); + + memset(&cmsgbuf, 0, sizeof(cmsgbuf)); + + memset(&msg, 0, sizeof(msg)); + msg.msg_iov = io_vector; + msg.msg_iovlen = 1; + msg.msg_name = server_addr; + msg.msg_namelen = server_addr_len; + + comm_sendmsg_recvmsg(client_sock, + client_addr, + client_addr_len, + &msg, + server_sock, + server_addr, + server_addr_len, + &server_msg, &cmsgbuf.buf, sizeof(cmsgbuf.buf)); + + for (cmsg = CMSG_FIRSTHDR(&server_msg); cmsg != NULL; + cmsg = CMSG_NXTHDR(&server_msg, cmsg)) { + if (cmsg->cmsg_level == IPPROTO_IP && + cmsg->cmsg_type == IP_PKTINFO) { + net_sin(&addr)->sin_addr = + ((struct in_pktinfo *)CMSG_DATA(cmsg))->ipi_addr; + ifindex = ((struct in_pktinfo *)CMSG_DATA(cmsg))->ipi_ifindex; + break; + } + + if (cmsg->cmsg_level == IPPROTO_IPV6 && + cmsg->cmsg_type == IPV6_RECVPKTINFO) { + net_ipaddr_copy(&net_sin6(&addr)->sin6_addr, + &((struct in6_pktinfo *)CMSG_DATA(cmsg))->ipi6_addr); + ifindex = ((struct in6_pktinfo *)CMSG_DATA(cmsg))->ipi6_ifindex; + break; + } + } + + if (server_addr->sa_family == AF_INET) { + zassert_equal(net_sin(&addr)->sin_addr.s_addr, + net_sin(server_addr)->sin_addr.s_addr, + "Source address not set properly!"); + } + + if (server_addr->sa_family == AF_INET6) { + zassert_mem_equal(&net_sin6(&addr)->sin6_addr, + &net_sin6(server_addr)->sin6_addr, + sizeof(struct in6_addr), + "Source address not set properly!"); + } + + if (!k_is_user_context()) { + iface = net_if_get_default(); + zassert_equal(ifindex, net_if_get_by_iface(iface)); + } + + /* Make sure that the recvmsg() fails if control area is too small */ + rv = sendto(client_sock, BUF_AND_SIZE(TEST_STR_SMALL), 0, + server_addr, server_addr_len); + zassert_equal(rv, STRLEN(TEST_STR_SMALL), "sendto failed (%d)", -errno); + + io_vector[0].iov_base = buf; + io_vector[0].iov_len = sizeof(buf); + + memset(&msg, 0, sizeof(msg)); + msg.msg_control = &cmsgbuf.buf; + msg.msg_controllen = 1; /* making sure the control buf is always too small */ + msg.msg_iov = io_vector; + msg.msg_iovlen = 1; + + rv = recvmsg(server_sock, &msg, 0); + zassert_true(rv, "recvmsg succeed (%d)", rv); + + zassert_true(msg.msg_flags & MSG_CTRUNC, "Control message not truncated"); + + rv = close(client_sock); + zassert_equal(rv, 0, "close failed"); + rv = close(server_sock); + zassert_equal(rv, 0, "close failed"); +} + +ZTEST_USER(net_socket_udp, test_28_recvmsg_ancillary_ipv4_pktinfo_data_user) +{ + struct sockaddr_in client_addr; + struct sockaddr_in server_addr; + int client_sock; + int server_sock; + + prepare_sock_udp_v4(MY_IPV4_ADDR, ANY_PORT, &client_sock, &client_addr); + prepare_sock_udp_v4(MY_IPV4_ADDR, SERVER_PORT, &server_sock, &server_addr); + + run_ancillary_recvmsg_test(client_sock, + (struct sockaddr *)&client_addr, + sizeof(client_addr), + server_sock, + (struct sockaddr *)&server_addr, + sizeof(server_addr)); +} + +ZTEST_USER(net_socket_udp, test_29_recvmsg_ancillary_ipv6_pktinfo_data_user) +{ + struct sockaddr_in6 client_addr; + struct sockaddr_in6 server_addr; + int client_sock; + int server_sock; + + prepare_sock_udp_v6(MY_IPV6_ADDR, ANY_PORT, &client_sock, &client_addr); + prepare_sock_udp_v6(MY_IPV6_ADDR, SERVER_PORT, &server_sock, &server_addr); + + run_ancillary_recvmsg_test(client_sock, + (struct sockaddr *)&client_addr, + sizeof(client_addr), + server_sock, + (struct sockaddr *)&server_addr, + sizeof(server_addr)); +} + static void after(void *arg) { ARG_UNUSED(arg); diff --git a/tests/net/socket/udp/testcase.yaml b/tests/net/socket/udp/testcase.yaml index 253d5698b21..aa541a84598 100644 --- a/tests/net/socket/udp/testcase.yaml +++ b/tests/net/socket/udp/testcase.yaml @@ -16,3 +16,6 @@ tests: net.socket.udp.ipv6_fragment: extra_configs: - CONFIG_NET_IPV6_FRAGMENT=y + net.socket.udp.pktinfo: + extra_configs: + - CONFIG_NET_CONTEXT_RECV_PKTINFO=y From 1961adfb96df7a876a804c48baa73d84f33dc432 Mon Sep 17 00:00:00 2001 From: Jukka Rissanen Date: Mon, 27 Nov 2023 12:50:27 +0200 Subject: [PATCH 0328/3723] net: socket: Return ENOTSUP for unknown socket type in recvfrom() If we for some reason are supplied unsupported socket type in recvfrom(), then return ENOTSUP error to the caller instead of silently accept it by returning 0. Signed-off-by: Jukka Rissanen --- subsys/net/lib/sockets/sockets.c | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/subsys/net/lib/sockets/sockets.c b/subsys/net/lib/sockets/sockets.c index d7697e60b6c..00f55299583 100644 --- a/subsys/net/lib/sockets/sockets.c +++ b/subsys/net/lib/sockets/sockets.c @@ -1684,11 +1684,13 @@ ssize_t zsock_recvfrom_ctx(struct net_context *ctx, void *buf, size_t max_len, return zsock_recv_dgram(ctx, NULL, buf, max_len, flags, src_addr, addrlen); } else if (sock_type == SOCK_STREAM) { return zsock_recv_stream(ctx, NULL, buf, max_len, flags); - } else { - __ASSERT(0, "Unknown socket type"); } - return 0; + __ASSERT(0, "Unknown socket type"); + + errno = ENOTSUP; + + return -1; } ssize_t z_impl_zsock_recvfrom(int sock, void *buf, size_t max_len, int flags, From 513ba04168c6de6679699090d2d228250d8d2135 Mon Sep 17 00:00:00 2001 From: Dat Nguyen Duy Date: Wed, 22 Nov 2023 17:11:29 +0700 Subject: [PATCH 0329/3723] soc: nxp_s32: cmsis rtos v2 adaptation There are symbols are both defined by the NXP S32 HAL and the CMSIS RTOS V2 wrapper, to avoid interference between them, redefine the symbols under an enum. Also this is may a common issue for all NXP S32 platforms, move to common place to be reused Signed-off-by: Dat Nguyen Duy --- soc/arm/nxp_s32/common/cmsis_rtos_v2_adapt.h | 19 +++++++++++++++++++ soc/arm/nxp_s32/s32k3/soc.h | 7 +------ soc/arm/nxp_s32/s32ze/soc.h | 4 ++++ 3 files changed, 24 insertions(+), 6 deletions(-) create mode 100644 soc/arm/nxp_s32/common/cmsis_rtos_v2_adapt.h diff --git a/soc/arm/nxp_s32/common/cmsis_rtos_v2_adapt.h b/soc/arm/nxp_s32/common/cmsis_rtos_v2_adapt.h new file mode 100644 index 00000000000..ab2bcd971f0 --- /dev/null +++ b/soc/arm/nxp_s32/common/cmsis_rtos_v2_adapt.h @@ -0,0 +1,19 @@ +/* + * Copyright 2023 NXP + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#ifndef ZEPHYR_SOC_ARM_NXP_S32_COMMON_CMSIS_RTOS_V2_ADAPT_H_ +#define ZEPHYR_SOC_ARM_NXP_S32_COMMON_CMSIS_RTOS_V2_ADAPT_H_ + +/* + * The HAL is defining these symbols already. To avoid interference + * between HAL and the CMSIS RTOS wrapper, redefine them under an enum. + */ +#undef TRUE +#undef FALSE + +enum { FALSE, TRUE}; + +#endif /* ZEPHYR_SOC_ARM_NXP_S32_COMMON_CMSIS_RTOS_V2_ADAPT_H_ */ diff --git a/soc/arm/nxp_s32/s32k3/soc.h b/soc/arm/nxp_s32/s32k3/soc.h index bbc53e18023..ef2734554df 100644 --- a/soc/arm/nxp_s32/s32k3/soc.h +++ b/soc/arm/nxp_s32/s32k3/soc.h @@ -10,12 +10,7 @@ #include #if defined(CONFIG_CMSIS_RTOS_V2) -/* - * The HAL is defining these symbols already. To avoid redefinitions, - * let CMSIS RTOS wrapper define them. - */ -#undef TRUE -#undef FALSE +#include #endif /* Aliases for peripheral base addresses */ diff --git a/soc/arm/nxp_s32/s32ze/soc.h b/soc/arm/nxp_s32/s32ze/soc.h index f7c96aa2ed9..e042ebe8af9 100644 --- a/soc/arm/nxp_s32/s32ze/soc.h +++ b/soc/arm/nxp_s32/s32ze/soc.h @@ -16,6 +16,10 @@ #error "SoC not supported" #endif +#if defined(CONFIG_CMSIS_RTOS_V2) +#include +#endif + /* Aliases for peripheral base addresses */ /* SIUL2 */ From c2f1ff7f5fbf053def69606a18df4fea83dc7b18 Mon Sep 17 00:00:00 2001 From: Maciej Baczmanski Date: Fri, 24 Nov 2023 08:58:45 +0100 Subject: [PATCH 0330/3723] net: openthread: upmerge to `75694d2` Regular OpenThread upmerge to commit `75694d2`. Move CONFIG_OPENTHREAD_PLATFORM_KEY_REFERENCES_ENABLE from header file to Kconfig. Signed-off-by: Maciej Baczmanski --- modules/openthread/CMakeLists.txt | 6 ++++++ modules/openthread/Kconfig.features | 6 ++++++ .../platform/openthread-core-zephyr-config.h | 10 ---------- subsys/net/l2/openthread/Kconfig | 10 ++-------- west.yml | 2 +- 5 files changed, 15 insertions(+), 19 deletions(-) diff --git a/modules/openthread/CMakeLists.txt b/modules/openthread/CMakeLists.txt index 2b2b593f82f..94351a38d6d 100644 --- a/modules/openthread/CMakeLists.txt +++ b/modules/openthread/CMakeLists.txt @@ -388,6 +388,12 @@ else() set(OT_PING_SENDER OFF CACHE BOOL "Enable ping sender support" FORCE) endif() +if(OPENTHREAD_PLATFORM_KEY_REF) + set(OT_PLATFORM_KEY_REF ON CACHE BOOL "Enable platform key reference support" FORCE) +else() + set(OT_PLATFORM_KEY_REF OFF CACHE BOOL "Enable platform key reference support" FORCE) +endif() + if(CONFIG_OPENTHREAD_PLATFORM_NETIF) set(OT_PLATFORM_NETIF ON CACHE BOOL "Enable platform netif support" FORCE) else() diff --git a/modules/openthread/Kconfig.features b/modules/openthread/Kconfig.features index a75c9e8fd48..36ce7615e35 100644 --- a/modules/openthread/Kconfig.features +++ b/modules/openthread/Kconfig.features @@ -242,6 +242,12 @@ config OPENTHREAD_OTNS config OPENTHREAD_PING_SENDER bool "Ping sender support" +config OPENTHREAD_PLATFORM_KEY_REF + bool "Platform cryptographic key reference support" + help + Enable usage of cryptographic key references instead of literal keys. + This requires a crypto backend library that supports key references. + config OPENTHREAD_PLATFORM_NETIF bool "Platform netif support" diff --git a/modules/openthread/platform/openthread-core-zephyr-config.h b/modules/openthread/platform/openthread-core-zephyr-config.h index 881585e5578..773cd170f2c 100644 --- a/modules/openthread/platform/openthread-core-zephyr-config.h +++ b/modules/openthread/platform/openthread-core-zephyr-config.h @@ -396,16 +396,6 @@ #define OPENTHREAD_CONFIG_CRYPTO_LIB OPENTHREAD_CONFIG_CRYPTO_LIB_PSA #endif -/** - * @def OPENTHREAD_CONFIG_PLATFORM_KEY_REFERENCES_ENABLE - * - * Set to 1 if you want to enable key reference usage support. - * - */ -#ifdef CONFIG_OPENTHREAD_PLATFORM_KEY_REFERENCES_ENABLE -#define OPENTHREAD_CONFIG_PLATFORM_KEY_REFERENCES_ENABLE 1 -#endif - /** * @def OPENTHREAD_CONFIG_PLATFORM_MAC_KEYS_EXPORTABLE_ENABLE * diff --git a/subsys/net/l2/openthread/Kconfig b/subsys/net/l2/openthread/Kconfig index 98113975797..aa7e03b8204 100644 --- a/subsys/net/l2/openthread/Kconfig +++ b/subsys/net/l2/openthread/Kconfig @@ -324,21 +324,15 @@ config OPENTHREAD_MAC_SOFTWARE_CSMA_BACKOFF_ENABLE config OPENTHREAD_CRYPTO_PSA bool "ARM PSA crypto API" depends on MBEDTLS_PSA_CRYPTO_C || BUILD_WITH_TFM - select OPENTHREAD_PLATFORM_KEY_REFERENCES_ENABLE + select OPENTHREAD_PLATFORM_KEY_REF select OPENTHREAD_PLATFORM_KEYS_EXPORTABLE_ENABLE help Enable crypto backend library implementation based on ARM PSA crypto API instead of the default, using mbedTLS. -config OPENTHREAD_PLATFORM_KEY_REFERENCES_ENABLE - bool "Cryptographic key reference support" - help - Enable usage of cryptographic key references instead of literal keys - This requires a crypto backend library that supports key references. - config OPENTHREAD_PLATFORM_KEYS_EXPORTABLE_ENABLE bool "Make MAC keys exportable" - depends on OPENTHREAD_PLATFORM_KEY_REFERENCES_ENABLE + depends on OPENTHREAD_PLATFORM_KEY_REF help Enable the creation of exportable MAC keys in the OpenThread Key Manager. diff --git a/west.yml b/west.yml index fbeb9919eac..71cbf94efb2 100644 --- a/west.yml +++ b/west.yml @@ -301,7 +301,7 @@ manifest: revision: 214f9fc1539f8e5937c0474cb6ee29b6dcb2d4b8 path: modules/lib/open-amp - name: openthread - revision: 193e77e40ec2387d458eaebd1e03902d86f484a5 + revision: 75694d2860282d216d7286f3956388e957c7cfb5 path: modules/lib/openthread - name: percepio path: modules/debug/percepio From 411731f778b771f0130b2d7d39e7dfd326305f61 Mon Sep 17 00:00:00 2001 From: Vinayak Kariappa Chettimada Date: Fri, 24 Nov 2023 12:02:14 +0100 Subject: [PATCH 0331/3723] tests: bsim: Bluetooth: Enable nrf5340bsim CIS ACL group test Enable testing CIS ACL group test on nrf5340bsim. Signed-off-by: Vinayak Kariappa Chettimada --- .../compile.nrf5340bsim_nrf5340_cpuapp.sh | 1 + tests/bsim/bluetooth/ll/cis/Kconfig.sysbuild | 14 ++ tests/bsim/bluetooth/ll/cis/sysbuild.cmake | 47 +++++++ ...0_cpunet_iso_acl_group-bt_ll_sw_split.conf | 122 ++++++++++++++++++ 4 files changed, 184 insertions(+) create mode 100644 tests/bsim/bluetooth/ll/cis/Kconfig.sysbuild create mode 100644 tests/bsim/bluetooth/ll/cis/sysbuild.cmake create mode 100644 tests/bsim/bluetooth/ll/cis/sysbuild/hci_ipc/nrf5340_cpunet_iso_acl_group-bt_ll_sw_split.conf diff --git a/tests/bsim/bluetooth/compile.nrf5340bsim_nrf5340_cpuapp.sh b/tests/bsim/bluetooth/compile.nrf5340bsim_nrf5340_cpuapp.sh index 4f175540347..65769185867 100755 --- a/tests/bsim/bluetooth/compile.nrf5340bsim_nrf5340_cpuapp.sh +++ b/tests/bsim/bluetooth/compile.nrf5340bsim_nrf5340_cpuapp.sh @@ -21,6 +21,7 @@ source ${ZEPHYR_BASE}/tests/bsim/compile.source app=tests/bsim/bluetooth/ll/conn conf_file=prj_split_privacy.conf sysbuild=1 compile app=tests/bsim/bluetooth/ll/bis sysbuild=1 compile +app=tests/bsim/bluetooth/ll/cis conf_overlay=overlay-acl_group.conf sysbuild=1 compile run_in_background ${ZEPHYR_BASE}/tests/bsim/bluetooth/audio_samples/compile.sh diff --git a/tests/bsim/bluetooth/ll/cis/Kconfig.sysbuild b/tests/bsim/bluetooth/ll/cis/Kconfig.sysbuild new file mode 100644 index 00000000000..6c89fddc9f3 --- /dev/null +++ b/tests/bsim/bluetooth/ll/cis/Kconfig.sysbuild @@ -0,0 +1,14 @@ +# Copyright 2023 Nordic Semiconductor ASA +# SPDX-License-Identifier: Apache-2.0 + +source "share/sysbuild/Kconfig" + +config NET_CORE_BOARD + string + default "nrf5340bsim_nrf5340_cpunet" if $(BOARD) = "nrf5340bsim_nrf5340_cpuapp" + +config NATIVE_SIMULATOR_PRIMARY_MCU_INDEX + int + # Let's pass the test arguments to the application MCU test + # otherwise by default they would have gone to the net core. + default 0 if $(BOARD) = "nrf5340bsim_nrf5340_cpuapp" diff --git a/tests/bsim/bluetooth/ll/cis/sysbuild.cmake b/tests/bsim/bluetooth/ll/cis/sysbuild.cmake new file mode 100644 index 00000000000..495c3f4a20d --- /dev/null +++ b/tests/bsim/bluetooth/ll/cis/sysbuild.cmake @@ -0,0 +1,47 @@ +# Copyright (c) 2023 Nordic Semiconductor ASA +# SPDX-License-Identifier: Apache-2.0 + +if(NOT("${SB_CONFIG_NET_CORE_BOARD}" STREQUAL "")) + set(NET_APP hci_ipc) + set(NET_APP_SRC_DIR ${ZEPHYR_BASE}/samples/bluetooth/${NET_APP}) + + ExternalZephyrProject_Add( + APPLICATION ${NET_APP} + SOURCE_DIR ${NET_APP_SRC_DIR} + BOARD ${SB_CONFIG_NET_CORE_BOARD} + ) + + set(${NET_APP}_CONF_FILE + ${APP_DIR}/sysbuild/hci_ipc/nrf5340_cpunet_iso_acl_group-bt_ll_sw_split.conf + CACHE INTERNAL "" + ) + + # For the simulated board, the application core build will produce the final executable + # for that, we give it the path to the netcore image + set(NET_LIBRARY_PATH ${CMAKE_BINARY_DIR}/${NET_APP}/zephyr/zephyr.elf) + set_property(TARGET ${DEFAULT_IMAGE} APPEND_STRING PROPERTY CONFIG + "CONFIG_NATIVE_SIMULATOR_EXTRA_IMAGE_PATHS=\"${NET_LIBRARY_PATH}\"\n" + ) + + if (NOT ("${SB_CONFIG_NATIVE_SIMULATOR_PRIMARY_MCU_INDEX}" STREQUAL "")) + set_property(TARGET ${NET_APP} APPEND_STRING PROPERTY CONFIG + "CONFIG_NATIVE_SIMULATOR_PRIMARY_MCU_INDEX=${SB_CONFIG_NATIVE_SIMULATOR_PRIMARY_MCU_INDEX}\n" + ) + set_property(TARGET ${DEFAULT_IMAGE} APPEND_STRING PROPERTY CONFIG + "CONFIG_NATIVE_SIMULATOR_PRIMARY_MCU_INDEX=${SB_CONFIG_NATIVE_SIMULATOR_PRIMARY_MCU_INDEX}\n" + ) + endif() + + # Let's build the net core library first + add_dependencies(${DEFAULT_IMAGE} ${NET_APP}) +endif() + +# Let's meet the expectation of finding the final executable in zephyr/zephyr.exe +add_custom_target(final_executable + ALL + COMMAND + ${CMAKE_COMMAND} -E copy + ${CMAKE_BINARY_DIR}/${DEFAULT_IMAGE}/zephyr/zephyr.exe + ${CMAKE_BINARY_DIR}/zephyr/zephyr.exe + DEPENDS ${DEFAULT_IMAGE} +) diff --git a/tests/bsim/bluetooth/ll/cis/sysbuild/hci_ipc/nrf5340_cpunet_iso_acl_group-bt_ll_sw_split.conf b/tests/bsim/bluetooth/ll/cis/sysbuild/hci_ipc/nrf5340_cpunet_iso_acl_group-bt_ll_sw_split.conf new file mode 100644 index 00000000000..a3c8f43c71f --- /dev/null +++ b/tests/bsim/bluetooth/ll/cis/sysbuild/hci_ipc/nrf5340_cpunet_iso_acl_group-bt_ll_sw_split.conf @@ -0,0 +1,122 @@ +CONFIG_IPC_SERVICE=y +CONFIG_MBOX=y + +CONFIG_ISR_STACK_SIZE=1024 +CONFIG_IDLE_STACK_SIZE=256 +CONFIG_MAIN_STACK_SIZE=512 +CONFIG_SYSTEM_WORKQUEUE_STACK_SIZE=512 +CONFIG_IPC_SERVICE_BACKEND_RPMSG_WQ_STACK_SIZE=512 +CONFIG_HEAP_MEM_POOL_SIZE=8192 +CONFIG_CBPRINTF_REDUCED_INTEGRAL=y + +CONFIG_BT=y +CONFIG_BT_HCI_RAW=y +CONFIG_BT_HCI_RAW_RESERVE=1 +CONFIG_BT_MAX_CONN=4 + +# Workaround: Unable to allocate command buffer when using K_NO_WAIT since +# Host number of completed commands does not follow normal flow control. +CONFIG_BT_BUF_CMD_TX_COUNT=10 + +CONFIG_BT_BUF_EVT_RX_COUNT=16 + +CONFIG_BT_BUF_EVT_RX_SIZE=255 +CONFIG_BT_BUF_ACL_RX_SIZE=255 +CONFIG_BT_BUF_ACL_TX_SIZE=251 +CONFIG_BT_BUF_CMD_TX_SIZE=255 + +# Tx/Rx Thread Stack Sizes +CONFIG_BT_HCI_TX_STACK_SIZE_WITH_PROMPT=y +CONFIG_BT_HCI_TX_STACK_SIZE=1152 +CONFIG_BT_RX_STACK_SIZE=640 +CONFIG_BT_CTLR_RX_PRIO_STACK_SIZE=448 + +# Host features +CONFIG_BT_EXT_ADV=y +CONFIG_BT_PER_ADV=y +CONFIG_BT_PER_ADV_SYNC=y +CONFIG_BT_PER_ADV_SYNC_MAX=2 + +# Broadcast and Connected ISO +CONFIG_BT_ISO_BROADCASTER=y +CONFIG_BT_ISO_SYNC_RECEIVER=y +CONFIG_BT_ISO_CENTRAL=y +CONFIG_BT_ISO_PERIPHERAL=y + +# ISO Streams +CONFIG_BT_ISO_MAX_CHAN=4 + +# Controller +CONFIG_BT_LL_SW_SPLIT=y +CONFIG_BT_CTLR_ASSERT_HANDLER=y +CONFIG_BT_CTLR_DTM_HCI=y + +# Rx ACL and Adv Reports +CONFIG_BT_CTLR_RX_BUFFERS=9 +CONFIG_BT_CTLR_DATA_LENGTH_MAX=251 + +# Coded PHY support +CONFIG_BT_CTLR_PHY_CODED=n + +# Advertising Sets and Extended Scanning +CONFIG_BT_CTLR_ADV_EXT=y +CONFIG_BT_CTLR_ADV_SET=3 +CONFIG_BT_CTLR_ADV_DATA_LEN_MAX=191 +CONFIG_BT_CTLR_SCAN_DATA_LEN_MAX=1650 + +CONFIG_BT_CTLR_ADVANCED_FEATURES=y +CONFIG_BT_CTLR_ADV_AUX_SET=3 +CONFIG_BT_CTLR_ADV_AUX_PDU_BACK2BACK=y +CONFIG_BT_CTLR_ADV_SYNC_SET=3 +CONFIG_BT_CTLR_ADV_SYNC_PDU_BACK2BACK=y +CONFIG_BT_CTLR_ADV_DATA_BUF_MAX=6 + +# Increase the below to receive interleaved advertising chains +CONFIG_BT_CTLR_SCAN_AUX_SET=1 + +CONFIG_BT_CTLR_ADV_RESERVE_MAX=n +CONFIG_BT_CTLR_CENTRAL_RESERVE_MAX=n +# CONFIG_BT_CTLR_CENTRAL_SPACING=10000 +CONFIG_BT_CTLR_CENTRAL_SPACING=0 +CONFIG_BT_CTLR_SLOT_RESERVATION_UPDATE=n +CONFIG_BT_CTLR_SCAN_UNRESERVED=n +CONFIG_BT_TICKER_NEXT_SLOT_GET_MATCH=y +CONFIG_BT_TICKER_EXT=y +CONFIG_BT_TICKER_EXT_SLOT_WINDOW_YIELD=y + +# Control Procedure +CONFIG_BT_CTLR_LLCP_LOCAL_PROC_CTX_BUF_NUM=9 + +# ISO Broadcaster Controller +CONFIG_BT_CTLR_ADV_EXT=y +CONFIG_BT_CTLR_ADV_PERIODIC=y +CONFIG_BT_CTLR_ADV_ISO=y +CONFIG_BT_CTLR_ADV_ISO_PDU_LEN_MAX=251 +CONFIG_BT_CTLR_ADV_ISO_STREAM_MAX=2 + +# ISO Receive Controller +CONFIG_BT_CTLR_ADV_EXT=y +CONFIG_BT_CTLR_SYNC_PERIODIC=y +CONFIG_BT_CTLR_SYNC_ISO=y +CONFIG_BT_CTLR_SYNC_ISO_PDU_LEN_MAX=251 +CONFIG_BT_CTLR_SYNC_ISO_STREAM_MAX=2 + +# ISO Connection Oriented +CONFIG_BT_CTLR_CENTRAL_ISO=y +CONFIG_BT_CTLR_PERIPHERAL_ISO=y +CONFIG_BT_CTLR_CONN_ISO_SDU_LEN_MAX=251 +CONFIG_BT_CTLR_CONN_ISO_PDU_LEN_MAX=251 +CONFIG_BT_CTLR_CONN_ISO_STREAMS=4 +CONFIG_BT_CTLR_CONN_ISO_STREAMS_PER_GROUP=4 + +# ISO Transmissions +CONFIG_BT_CTLR_ISO_TX_BUFFERS=18 +CONFIG_BT_CTLR_ISO_TX_BUFFER_SIZE=251 +CONFIG_BT_CTLR_ISOAL_SOURCES=4 + +# ISO Receptions +CONFIG_BT_CTLR_ISO_RX_BUFFERS=8 +CONFIG_BT_CTLR_ISOAL_SINKS=4 + +# Tx Power Dynamic Control +CONFIG_BT_CTLR_TX_PWR_DYNAMIC_CONTROL=y From 473cc03c38000696d82b679a0792d329b8441b2d Mon Sep 17 00:00:00 2001 From: Pieter De Gendt Date: Fri, 24 Nov 2023 11:09:40 +0100 Subject: [PATCH 0332/3723] net: ip: icmp: Cleanup packet on failed priority check A network memory leak would occur if the priority check fails. Signed-off-by: Pieter De Gendt --- subsys/net/ip/icmp.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/subsys/net/ip/icmp.c b/subsys/net/ip/icmp.c index 97902c1e4f5..322801132df 100644 --- a/subsys/net/ip/icmp.c +++ b/subsys/net/ip/icmp.c @@ -149,7 +149,8 @@ static int send_icmpv4_echo_request(struct net_icmp_ctx *ctx, params->priority >= NET_MAX_PRIORITIES) { NET_ERR("Priority %d is too large, maximum allowed is %d", params->priority, NET_MAX_PRIORITIES - 1); - return -EINVAL; + ret = -EINVAL; + goto drop; } if (params->priority < 0) { @@ -269,7 +270,8 @@ static int send_icmpv6_echo_request(struct net_icmp_ctx *ctx, params->priority >= NET_MAX_PRIORITIES) { NET_ERR("Priority %d is too large, maximum allowed is %d", params->priority, NET_MAX_PRIORITIES - 1); - return -EINVAL; + ret = -EINVAL; + goto drop; } if (params->priority < 0) { From d3ffe6f4040af9019e0efab8960926bb4e958861 Mon Sep 17 00:00:00 2001 From: Arnaud MAZIN Date: Fri, 24 Nov 2023 15:13:43 +0100 Subject: [PATCH 0333/3723] driver: display: sdl: Introduce de CLI option display_zoom_pct This option let specify at startup the zoom factor to apply on the SDL window. See CONFIG_SDL_DISPLAY_ZOOM_PCT. Signed-off-by: Arnaud MAZIN --- drivers/display/display_sdl.c | 28 +++++++++++++++++++++++++++- 1 file changed, 27 insertions(+), 1 deletion(-) diff --git a/drivers/display/display_sdl.c b/drivers/display/display_sdl.c index b813ee34872..b411896b5b1 100644 --- a/drivers/display/display_sdl.c +++ b/drivers/display/display_sdl.c @@ -13,11 +13,14 @@ #include #include #include "display_sdl_bottom.h" +#include "cmdline.h" #define LOG_LEVEL CONFIG_DISPLAY_LOG_LEVEL #include LOG_MODULE_REGISTER(display_sdl); +static uint32_t sdl_display_zoom_pct; + struct sdl_display_config { uint16_t height; uint16_t width; @@ -54,8 +57,12 @@ static int sdl_display_init(const struct device *dev) #endif /* SDL_DISPLAY_DEFAULT_PIXEL_FORMAT */ ; + if (sdl_display_zoom_pct == UINT32_MAX) { + sdl_display_zoom_pct = CONFIG_SDL_DISPLAY_ZOOM_PCT; + } + int rc = sdl_display_init_bottom(config->height, config->width, - CONFIG_SDL_DISPLAY_ZOOM_PCT, + sdl_display_zoom_pct, &disp_data->window, &disp_data->renderer, &disp_data->texture); @@ -388,3 +395,22 @@ static const struct display_driver_api sdl_display_api = { NATIVE_TASK(sdl_display_cleanup_##n, ON_EXIT, 1); DT_INST_FOREACH_STATUS_OKAY(DISPLAY_SDL_DEFINE) + +static void display_sdl_native_posix_options(void) +{ + static struct args_struct_t sdl_display_options[] = { + { .option = "display_zoom_pct", + .name = "pct", + .type = 'u', + .dest = (void *)&sdl_display_zoom_pct, + .descript = "Display zoom percentage (100 == 1:1 scale), " + "by default " STRINGIFY(CONFIG_SDL_DISPLAY_ZOOM_PCT) + " = CONFIG_SDL_DISPLAY_ZOOM_PCT" + }, + ARG_TABLE_ENDMARKER + }; + + native_add_command_line_opts(sdl_display_options); +} + +NATIVE_TASK(display_sdl_native_posix_options, PRE_BOOT_1, 1); From ca346ba21690aa643da61a44c0eee04c9f2f8b2a Mon Sep 17 00:00:00 2001 From: Sylvio Alves Date: Thu, 23 Nov 2023 09:35:12 -0300 Subject: [PATCH 0334/3723] soc: esp32: call reset cause reason init Reset cause reason was not initalized properly, making hwinfo feature not to work as expected. Fixes #65634 Signed-off-by: Sylvio Alves --- soc/riscv/espressif_esp32/esp32c3/soc.c | 4 ++++ soc/xtensa/espressif_esp32/esp32/soc.c | 3 +++ soc/xtensa/espressif_esp32/esp32s2/soc.c | 3 +++ soc/xtensa/espressif_esp32/esp32s3/soc.c | 3 +++ west.yml | 2 +- 5 files changed, 14 insertions(+), 1 deletion(-) diff --git a/soc/riscv/espressif_esp32/esp32c3/soc.c b/soc/riscv/espressif_esp32/esp32c3/soc.c index 8bb32a5febd..c125450a4d9 100644 --- a/soc/riscv/espressif_esp32/esp32c3/soc.c +++ b/soc/riscv/espressif_esp32/esp32c3/soc.c @@ -30,6 +30,8 @@ #include "bootloader_init.h" #endif /* CONFIG_MCUBOOT */ +extern void esp_reset_reason_init(void); + /* * This is written in C rather than assembly since, during the port bring up, * Zephyr is being booted by the Espressif bootloader. With it, the C stack @@ -56,6 +58,8 @@ void __attribute__((section(".iram1"))) __esp_platform_start(void) /* Disable normal interrupts. */ csr_read_clear(mstatus, MSTATUS_MIE); + esp_reset_reason_init(); + #ifdef CONFIG_MCUBOOT /* MCUboot early initialisation. */ diff --git a/soc/xtensa/espressif_esp32/esp32/soc.c b/soc/xtensa/espressif_esp32/esp32/soc.c index 2abd0f6a88a..7834406f37b 100644 --- a/soc/xtensa/espressif_esp32/esp32/soc.c +++ b/soc/xtensa/espressif_esp32/esp32/soc.c @@ -41,6 +41,7 @@ #include extern void z_cstart(void); +extern void esp_reset_reason_init(void); #ifdef CONFIG_ESP32_NETWORK_CORE extern const unsigned char esp32_net_fw_array[]; @@ -119,6 +120,8 @@ void __attribute__((section(".iram1"))) __esp_platform_start(void) */ __asm__ volatile("wsr.MISC0 %0; rsync" : : "r"(&_kernel.cpus[0])); + esp_reset_reason_init(); + #ifdef CONFIG_MCUBOOT /* MCUboot early initialisation. */ if (bootloader_init()) { diff --git a/soc/xtensa/espressif_esp32/esp32s2/soc.c b/soc/xtensa/espressif_esp32/esp32s2/soc.c index 45edde47178..5e1ec21c075 100644 --- a/soc/xtensa/espressif_esp32/esp32s2/soc.c +++ b/soc/xtensa/espressif_esp32/esp32s2/soc.c @@ -37,6 +37,7 @@ #endif /* CONFIG_MCUBOOT */ extern void rtc_clk_cpu_freq_set_xtal(void); +extern void esp_reset_reason_init(void); #if CONFIG_ESP_SPIRAM extern int _ext_ram_bss_start; @@ -91,6 +92,8 @@ void __attribute__((section(".iram1"))) __esp_platform_start(void) */ __asm__ volatile("wsr.MISC0 %0; rsync" : : "r"(&_kernel.cpus[0])); + esp_reset_reason_init(); + #ifdef CONFIG_MCUBOOT /* MCUboot early initialisation. */ if (bootloader_init()) { diff --git a/soc/xtensa/espressif_esp32/esp32s3/soc.c b/soc/xtensa/espressif_esp32/esp32s3/soc.c index ad971b907b2..d250657c49e 100644 --- a/soc/xtensa/espressif_esp32/esp32s3/soc.c +++ b/soc/xtensa/espressif_esp32/esp32s3/soc.c @@ -47,6 +47,7 @@ extern int _ext_ram_bss_end; #endif extern void z_cstart(void); +extern void esp_reset_reason_init(void); #ifdef CONFIG_SOC_ESP32S3_PROCPU extern const unsigned char esp32s3_appcpu_fw_array[]; @@ -184,6 +185,8 @@ void IRAM_ATTR __esp_platform_start(void) wdt_hal_disable(&rtc_wdt_ctx); wdt_hal_write_protect_enable(&rtc_wdt_ctx); + esp_reset_reason_init(); + esp_clk_init(); esp_timer_early_init(); diff --git a/west.yml b/west.yml index 71cbf94efb2..afaa1203891 100644 --- a/west.yml +++ b/west.yml @@ -152,7 +152,7 @@ manifest: groups: - hal - name: hal_espressif - revision: b3cb13f06586543ae1d156dc3e84b2fd3dc2f1fb + revision: ca3be152414bb269647806c4d3091e04168d1add path: modules/hal/espressif west-commands: west/west-commands.yml groups: From e971363648a527e844a4751cac892e5b1e0745ff Mon Sep 17 00:00:00 2001 From: Balsundar Ponnusamy Date: Fri, 20 Oct 2023 06:00:47 +0000 Subject: [PATCH 0335/3723] drivers: watchdog: wdt_dw: use mmio address in RAM mmu enabled platform needs mapping of physical address ranges to the virtual address at runtime. So using DEVICE_MMIO_* helper macros to map physical csr address space to RAM runtime if MMU is enabled Signed-off-by: Balsundar Ponnusamy --- drivers/watchdog/wdt_dw.c | 38 ++++++++++++++++++++++++++------------ 1 file changed, 26 insertions(+), 12 deletions(-) diff --git a/drivers/watchdog/wdt_dw.c b/drivers/watchdog/wdt_dw.c index f41b3b1b2cd..6ee2cd13033 100644 --- a/drivers/watchdog/wdt_dw.c +++ b/drivers/watchdog/wdt_dw.c @@ -23,6 +23,8 @@ LOG_MODULE_REGISTER(wdt_dw, CONFIG_WDT_LOG_LEVEL); /* Device run time data */ struct dw_wdt_dev_data { + /* MMIO mapping information for watchdog register base address */ + DEVICE_MMIO_RAM; uint32_t config; #if WDT_DW_INTERRUPT_SUPPORT wdt_callback_t callback; @@ -31,7 +33,8 @@ struct dw_wdt_dev_data { /* Device constant configuration parameters */ struct dw_wdt_dev_cfg { - uint32_t base; + DEVICE_MMIO_ROM; + uint32_t clk_freq; #if WDT_DW_INTERRUPT_SUPPORT void (*irq_config)(void); @@ -41,23 +44,31 @@ struct dw_wdt_dev_cfg { static int dw_wdt_setup(const struct device *dev, uint8_t options) { - const struct dw_wdt_dev_cfg *const dev_config = dev->config; struct dw_wdt_dev_data *const dev_data = dev->data; + uintptr_t reg_base = DEVICE_MMIO_GET(dev); dw_wdt_check_options(options); #if WDT_DW_INTERRUPT_SUPPORT /* Configure response mode */ - dw_wdt_response_mode_set(dev_config->base, !!dev_data->callback); + dw_wdt_response_mode_set((uint32_t)reg_base, !!dev_data->callback); #endif - return dw_wdt_configure(dev_config->base, dev_data->config); + return dw_wdt_configure((uint32_t)reg_base, dev_data->config); } static int dw_wdt_install_timeout(const struct device *dev, const struct wdt_timeout_cfg *config) { +#if WDT_DW_INTERRUPT_SUPPORT const struct dw_wdt_dev_cfg *const dev_config = dev->config; +#endif struct dw_wdt_dev_data *const dev_data = dev->data; + uintptr_t reg_base = DEVICE_MMIO_GET(dev); + + if (config == NULL) { + LOG_ERR("watchdog timeout configuration missing"); + return -ENODATA; + } #if WDT_DW_INTERRUPT_SUPPORT if (config->callback && !dev_config->irq_config) { @@ -77,20 +88,20 @@ static int dw_wdt_install_timeout(const struct device *dev, const struct wdt_tim dev_data->callback = config->callback; #endif - return dw_wdt_calc_period(dev_config->base, dev_config->clk_freq, config, + return dw_wdt_calc_period((uint32_t)reg_base, dev_config->clk_freq, config, &dev_data->config); } static int dw_wdt_feed(const struct device *dev, int channel_id) { - const struct dw_wdt_dev_cfg *const dev_config = dev->config; + uintptr_t reg_base = DEVICE_MMIO_GET(dev); /* Only channel 0 is supported */ if (channel_id) { return -EINVAL; } - dw_wdt_counter_restart(dev_config->base); + dw_wdt_counter_restart((uint32_t)reg_base); return 0; } @@ -104,10 +115,12 @@ static const struct wdt_driver_api dw_wdt_api = { static int dw_wdt_init(const struct device *dev) { + DEVICE_MMIO_MAP(dev, K_MEM_CACHE_NONE); const struct dw_wdt_dev_cfg *const dev_config = dev->config; int ret; + uintptr_t reg_base = DEVICE_MMIO_GET(dev); - ret = dw_wdt_probe(dev_config->base, dev_config->reset_pulse_length); + ret = dw_wdt_probe((uint32_t)reg_base, dev_config->reset_pulse_length); if (ret) return ret; @@ -123,11 +136,12 @@ static int dw_wdt_init(const struct device *dev) #if WDT_DW_INTERRUPT_SUPPORT static void dw_wdt_isr(const struct device *dev) { - const struct dw_wdt_dev_cfg *const dev_config = dev->config; struct dw_wdt_dev_data *const dev_data = dev->data; + uintptr_t reg_base = DEVICE_MMIO_GET(dev); + + if (dw_wdt_interrupt_status_register_get((uint32_t)reg_base)) { - if (dw_wdt_interrupt_status_register_get(dev_config->base)) { - dw_wdt_clear_interrupt(dev_config->base); + dw_wdt_clear_interrupt((uint32_t)reg_base); if (dev_data->callback) { dev_data->callback(dev, 0); @@ -155,7 +169,7 @@ static void dw_wdt_isr(const struct device *dev) IF_ENABLED(WDT_IS_INST_IRQ_EN(inst), (IRQ_CONFIG(inst))) \ \ static const struct dw_wdt_dev_cfg wdt_dw##inst##_config = { \ - .base = DT_INST_REG_ADDR(inst), \ + DEVICE_MMIO_ROM_INIT(DT_DRV_INST(inst)), \ COND_CODE_1(DT_INST_NODE_HAS_PROP(inst, clock_frequency), \ (.clk_freq = DT_INST_PROP(inst, clock_frequency)), \ (.clk_freq = DT_INST_PROP_BY_PHANDLE(inst, clocks, clock_frequency)) \ From a89768cec4067835a7e96de3cb02e289396f9752 Mon Sep 17 00:00:00 2001 From: Balsundar Ponnusamy Date: Fri, 20 Oct 2023 06:04:17 +0000 Subject: [PATCH 0336/3723] drivers: watchdog: wdt_dw: bug fix and modify conditional macro check clearing interrupt flag will not assert the system reset as per IP spec, so interrupt flag should not be cleared in isr use #if macro check directly with DT_ANY_INST_HAS_PROP_STATUS_OKAY for interrupt Signed-off-by: Balsundar Ponnusamy --- drivers/watchdog/wdt_dw.c | 42 ++++++++++++++++++++++----------------- 1 file changed, 24 insertions(+), 18 deletions(-) diff --git a/drivers/watchdog/wdt_dw.c b/drivers/watchdog/wdt_dw.c index 6ee2cd13033..618ff69941d 100644 --- a/drivers/watchdog/wdt_dw.c +++ b/drivers/watchdog/wdt_dw.c @@ -17,16 +17,12 @@ LOG_MODULE_REGISTER(wdt_dw, CONFIG_WDT_LOG_LEVEL); -#define WDT_IS_INST_IRQ_EN(inst) DT_NODE_HAS_PROP(DT_DRV_INST(inst), interrupts) -#define WDT_CHECK_INTERRUPT_USED(inst) WDT_IS_INST_IRQ_EN(inst) || -#define WDT_DW_INTERRUPT_SUPPORT DT_INST_FOREACH_STATUS_OKAY(WDT_CHECK_INTERRUPT_USED) 0 - /* Device run time data */ struct dw_wdt_dev_data { /* MMIO mapping information for watchdog register base address */ DEVICE_MMIO_RAM; uint32_t config; -#if WDT_DW_INTERRUPT_SUPPORT +#if DT_ANY_INST_HAS_PROP_STATUS_OKAY(interrupts) wdt_callback_t callback; #endif }; @@ -36,7 +32,7 @@ struct dw_wdt_dev_cfg { DEVICE_MMIO_ROM; uint32_t clk_freq; -#if WDT_DW_INTERRUPT_SUPPORT +#if DT_ANY_INST_HAS_PROP_STATUS_OKAY(interrupts) void (*irq_config)(void); #endif uint8_t reset_pulse_length; @@ -46,10 +42,14 @@ static int dw_wdt_setup(const struct device *dev, uint8_t options) { struct dw_wdt_dev_data *const dev_data = dev->data; uintptr_t reg_base = DEVICE_MMIO_GET(dev); + int ret; - dw_wdt_check_options(options); + ret = dw_wdt_check_options(options); + if (ret != 0) { + return ret; + } -#if WDT_DW_INTERRUPT_SUPPORT +#if DT_ANY_INST_HAS_PROP_STATUS_OKAY(interrupts) /* Configure response mode */ dw_wdt_response_mode_set((uint32_t)reg_base, !!dev_data->callback); #endif @@ -59,7 +59,7 @@ static int dw_wdt_setup(const struct device *dev, uint8_t options) static int dw_wdt_install_timeout(const struct device *dev, const struct wdt_timeout_cfg *config) { -#if WDT_DW_INTERRUPT_SUPPORT +#if DT_ANY_INST_HAS_PROP_STATUS_OKAY(interrupts) const struct dw_wdt_dev_cfg *const dev_config = dev->config; #endif struct dw_wdt_dev_data *const dev_data = dev->data; @@ -70,7 +70,7 @@ static int dw_wdt_install_timeout(const struct device *dev, const struct wdt_tim return -ENODATA; } -#if WDT_DW_INTERRUPT_SUPPORT +#if DT_ANY_INST_HAS_PROP_STATUS_OKAY(interrupts) if (config->callback && !dev_config->irq_config) { #else if (config->callback) { @@ -84,7 +84,7 @@ static int dw_wdt_install_timeout(const struct device *dev, const struct wdt_tim return -ENOTSUP; } -#ifdef WDT_DW_INTERRUPT_SUPPORT +#if DT_ANY_INST_HAS_PROP_STATUS_OKAY(interrupts) dev_data->callback = config->callback; #endif @@ -124,7 +124,7 @@ static int dw_wdt_init(const struct device *dev) if (ret) return ret; -#if WDT_DW_INTERRUPT_SUPPORT +#if DT_ANY_INST_HAS_PROP_STATUS_OKAY(interrupts) if (dev_config->irq_config) { dev_config->irq_config(); } @@ -133,7 +133,7 @@ static int dw_wdt_init(const struct device *dev) return 0; } -#if WDT_DW_INTERRUPT_SUPPORT +#if DT_ANY_INST_HAS_PROP_STATUS_OKAY(interrupts) static void dw_wdt_isr(const struct device *dev) { struct dw_wdt_dev_data *const dev_data = dev->data; @@ -141,8 +141,10 @@ static void dw_wdt_isr(const struct device *dev) if (dw_wdt_interrupt_status_register_get((uint32_t)reg_base)) { - dw_wdt_clear_interrupt((uint32_t)reg_base); - + /* + * Clearing interrupt here will not assert system reset, so interrupt + * will not be cleared here. + */ if (dev_data->callback) { dev_data->callback(dev, 0); } @@ -157,16 +159,20 @@ static void dw_wdt_isr(const struct device *dev) #error Clock frequency not configured! #endif +/* Bindings to the platform */ +#define DW_WDT_IRQ_FLAGS(inst) \ + COND_CODE_1(DT_INST_IRQ_HAS_CELL(inst, sense), (DT_INST_IRQ(inst, sense)), (0)) + #define IRQ_CONFIG(inst) \ static void dw_wdt##inst##_irq_config(void) \ { \ IRQ_CONNECT(DT_INST_IRQN(inst), DT_INST_IRQ(inst, priority), dw_wdt_isr, \ - DEVICE_DT_INST_GET(inst), DT_INST_IRQ(inst, sense)); \ + DEVICE_DT_INST_GET(inst), DW_WDT_IRQ_FLAGS(inst)); \ irq_enable(DT_INST_IRQN(inst)); \ } #define DW_WDT_INIT(inst) \ - IF_ENABLED(WDT_IS_INST_IRQ_EN(inst), (IRQ_CONFIG(inst))) \ + IF_ENABLED(DT_NODE_HAS_PROP(DT_DRV_INST(inst), interrupts), (IRQ_CONFIG(inst))) \ \ static const struct dw_wdt_dev_cfg wdt_dw##inst##_config = { \ DEVICE_MMIO_ROM_INIT(DT_DRV_INST(inst)), \ @@ -175,7 +181,7 @@ static void dw_wdt_isr(const struct device *dev) (.clk_freq = DT_INST_PROP_BY_PHANDLE(inst, clocks, clock_frequency)) \ ), \ .reset_pulse_length = ilog2(DT_INST_PROP_OR(inst, reset_pulse_length, 2)) - 1, \ - IF_ENABLED(WDT_IS_INST_IRQ_EN(inst), \ + IF_ENABLED(DT_NODE_HAS_PROP(DT_DRV_INST(inst), interrupts), \ (.irq_config = dw_wdt##inst##_irq_config,) \ ) \ }; \ From 63b666ac0aa9b17c28f5691119123e43c6cb8ff0 Mon Sep 17 00:00:00 2001 From: Balsundar Ponnusamy Date: Fri, 20 Oct 2023 05:04:11 +0000 Subject: [PATCH 0337/3723] drivers: watchdog: wdt_dw: get clock rate from clock manager added support for getting clock rate at runtime from clock manager Signed-off-by: Balsundar Ponnusamy --- drivers/watchdog/wdt_dw.c | 49 +++++++++++++++++++++++++++++++-------- 1 file changed, 39 insertions(+), 10 deletions(-) diff --git a/drivers/watchdog/wdt_dw.c b/drivers/watchdog/wdt_dw.c index 618ff69941d..f5829e30922 100644 --- a/drivers/watchdog/wdt_dw.c +++ b/drivers/watchdog/wdt_dw.c @@ -11,6 +11,7 @@ #include #include #include +#include #include "wdt_dw.h" #include "wdt_dw_common.h" @@ -21,6 +22,8 @@ LOG_MODULE_REGISTER(wdt_dw, CONFIG_WDT_LOG_LEVEL); struct dw_wdt_dev_data { /* MMIO mapping information for watchdog register base address */ DEVICE_MMIO_RAM; + /* Clock frequency */ + uint32_t clk_freq; uint32_t config; #if DT_ANY_INST_HAS_PROP_STATUS_OKAY(interrupts) wdt_callback_t callback; @@ -31,7 +34,12 @@ struct dw_wdt_dev_data { struct dw_wdt_dev_cfg { DEVICE_MMIO_ROM; - uint32_t clk_freq; +#if DT_ANY_INST_HAS_PROP_STATUS_OKAY(clocks) + /* Clock controller dev instance */ + const struct device *clk_dev; + /* Identifier for timer to get clock freq from clk manager */ + clock_control_subsys_t clkid; +#endif #if DT_ANY_INST_HAS_PROP_STATUS_OKAY(interrupts) void (*irq_config)(void); #endif @@ -59,9 +67,7 @@ static int dw_wdt_setup(const struct device *dev, uint8_t options) static int dw_wdt_install_timeout(const struct device *dev, const struct wdt_timeout_cfg *config) { -#if DT_ANY_INST_HAS_PROP_STATUS_OKAY(interrupts) - const struct dw_wdt_dev_cfg *const dev_config = dev->config; -#endif + __maybe_unused const struct dw_wdt_dev_cfg *const dev_config = dev->config; struct dw_wdt_dev_data *const dev_data = dev->data; uintptr_t reg_base = DEVICE_MMIO_GET(dev); @@ -88,7 +94,7 @@ static int dw_wdt_install_timeout(const struct device *dev, const struct wdt_tim dev_data->callback = config->callback; #endif - return dw_wdt_calc_period((uint32_t)reg_base, dev_config->clk_freq, config, + return dw_wdt_calc_period((uint32_t)reg_base, dev_data->clk_freq, config, &dev_data->config); } @@ -120,6 +126,22 @@ static int dw_wdt_init(const struct device *dev) int ret; uintptr_t reg_base = DEVICE_MMIO_GET(dev); + /* Get clock frequency from the clock manager if supported */ +#if DT_ANY_INST_HAS_PROP_STATUS_OKAY(clocks) + struct dw_wdt_dev_data *const dev_data = dev->data; + + if (!device_is_ready(dev_config->clk_dev)) { + LOG_ERR("Clock controller device not ready"); + return -ENODEV; + } + + ret = clock_control_get_rate(dev_config->clk_dev, dev_config->clkid, + &dev_data->clk_freq); + if (ret != 0) { + LOG_ERR("Failed to get watchdog clock rate"); + return ret; + } +#endif ret = dw_wdt_probe((uint32_t)reg_base, dev_config->reset_pulse_length); if (ret) return ret; @@ -176,17 +198,24 @@ static void dw_wdt_isr(const struct device *dev) \ static const struct dw_wdt_dev_cfg wdt_dw##inst##_config = { \ DEVICE_MMIO_ROM_INIT(DT_DRV_INST(inst)), \ - COND_CODE_1(DT_INST_NODE_HAS_PROP(inst, clock_frequency), \ - (.clk_freq = DT_INST_PROP(inst, clock_frequency)), \ - (.clk_freq = DT_INST_PROP_BY_PHANDLE(inst, clocks, clock_frequency)) \ - ), \ .reset_pulse_length = ilog2(DT_INST_PROP_OR(inst, reset_pulse_length, 2)) - 1, \ + IF_ENABLED(DT_PHA_HAS_CELL(DT_DRV_INST(inst), clocks, clkid), \ + ( \ + .clk_dev = DEVICE_DT_GET(DT_INST_CLOCKS_CTLR(inst)), \ + .clkid = (clock_control_subsys_t)DT_INST_CLOCKS_CELL(inst, clkid), \ + )) \ IF_ENABLED(DT_NODE_HAS_PROP(DT_DRV_INST(inst), interrupts), \ (.irq_config = dw_wdt##inst##_irq_config,) \ ) \ }; \ \ - static struct dw_wdt_dev_data wdt_dw##inst##_data; \ + static struct dw_wdt_dev_data wdt_dw##inst##_data = { \ + COND_CODE_1(DT_INST_NODE_HAS_PROP(inst, clock_frequency), \ + (.clk_freq = DT_INST_PROP(inst, clock_frequency)), \ + (COND_CODE_1(DT_PHA_HAS_CELL(DT_DRV_INST(inst), clocks, clkid), \ + (.clk_freq = 0), \ + (.clk_freq = DT_INST_PROP_BY_PHANDLE(inst, clocks, clock_frequency))))), \ + }; \ \ DEVICE_DT_INST_DEFINE(inst, &dw_wdt_init, NULL, &wdt_dw##inst##_data, \ &wdt_dw##inst##_config, POST_KERNEL, \ From ba3a71eda7d333f86c19240722fb56767f4b9f28 Mon Sep 17 00:00:00 2001 From: Balsundar Ponnusamy Date: Wed, 18 Oct 2023 06:01:16 +0000 Subject: [PATCH 0338/3723] drivers: watchdog: wdt_dw: support for resetting watchdog add support for resetting watchdog IP through reset manager driver Signed-off-by: Balsundar Ponnusamy --- drivers/watchdog/wdt_dw.c | 49 +++++++++++++++++++ drivers/watchdog/wdt_dw_common.c | 5 -- drivers/watchdog/wdt_intel_adsp.c | 5 ++ .../watchdog/snps,designware-watchdog.yaml | 2 +- 4 files changed, 55 insertions(+), 6 deletions(-) diff --git a/drivers/watchdog/wdt_dw.c b/drivers/watchdog/wdt_dw.c index f5829e30922..e9d758b6713 100644 --- a/drivers/watchdog/wdt_dw.c +++ b/drivers/watchdog/wdt_dw.c @@ -11,6 +11,7 @@ #include #include #include +#include #include #include "wdt_dw.h" @@ -44,6 +45,10 @@ struct dw_wdt_dev_cfg { void (*irq_config)(void); #endif uint8_t reset_pulse_length; +#if DT_ANY_INST_HAS_PROP_STATUS_OKAY(resets) + /* Reset controller device configurations */ + struct reset_dt_spec reset_spec; +#endif }; static int dw_wdt_setup(const struct device *dev, uint8_t options) @@ -112,6 +117,37 @@ static int dw_wdt_feed(const struct device *dev, int channel_id) return 0; } +int dw_wdt_disable(const struct device *dev) +{ + int ret = -ENOTSUP; + /* + * Once watchdog is enabled by setting WDT_EN bit watchdog cannot be disabled by clearing + * WDT_EN bit and to disable/clear WDT_EN bit watchdog IP should undergo reset + */ +#if DT_ANY_INST_HAS_PROP_STATUS_OKAY(resets) + const struct dw_wdt_dev_cfg *const dev_config = dev->config; + + /* + * Assert and de-assert reset only if the reset prop is defined in the device + * tree node for this dev instance + */ + if (dev_config->reset_spec.dev != NULL) { + if (!device_is_ready(dev_config->reset_spec.dev)) { + LOG_ERR("reset controller device not ready"); + return -ENODEV; + } + + /* Assert and de-assert reset watchdog */ + ret = reset_line_toggle(dev_config->reset_spec.dev, dev_config->reset_spec.id); + if (ret != 0) { + LOG_ERR("watchdog disable/reset failed"); + return ret; + } + } +#endif + return ret; +} + static const struct wdt_driver_api dw_wdt_api = { .setup = dw_wdt_setup, .disable = dw_wdt_disable, @@ -126,6 +162,14 @@ static int dw_wdt_init(const struct device *dev) int ret; uintptr_t reg_base = DEVICE_MMIO_GET(dev); + /* Reset watchdog controller if reset controller is supported */ +#if DT_ANY_INST_HAS_PROP_STATUS_OKAY(resets) + ret = dw_wdt_disable(dev); + if (ret != 0) { + return ret; + } +#endif + /* Get clock frequency from the clock manager if supported */ #if DT_ANY_INST_HAS_PROP_STATUS_OKAY(clocks) struct dw_wdt_dev_data *const dev_data = dev->data; @@ -185,6 +229,9 @@ static void dw_wdt_isr(const struct device *dev) #define DW_WDT_IRQ_FLAGS(inst) \ COND_CODE_1(DT_INST_IRQ_HAS_CELL(inst, sense), (DT_INST_IRQ(inst, sense)), (0)) +#define DW_WDT_RESET_SPEC_INIT(inst) \ + .reset_spec = RESET_DT_SPEC_INST_GET(inst), + #define IRQ_CONFIG(inst) \ static void dw_wdt##inst##_irq_config(void) \ { \ @@ -199,6 +246,8 @@ static void dw_wdt_isr(const struct device *dev) static const struct dw_wdt_dev_cfg wdt_dw##inst##_config = { \ DEVICE_MMIO_ROM_INIT(DT_DRV_INST(inst)), \ .reset_pulse_length = ilog2(DT_INST_PROP_OR(inst, reset_pulse_length, 2)) - 1, \ + IF_ENABLED(DT_INST_NODE_HAS_PROP(inst, resets), \ + (DW_WDT_RESET_SPEC_INIT(inst))) \ IF_ENABLED(DT_PHA_HAS_CELL(DT_DRV_INST(inst), clocks, clkid), \ ( \ .clk_dev = DEVICE_DT_GET(DT_INST_CLOCKS_CTLR(inst)), \ diff --git a/drivers/watchdog/wdt_dw_common.c b/drivers/watchdog/wdt_dw_common.c index 7c7a1532d15..230f272ec40 100644 --- a/drivers/watchdog/wdt_dw_common.c +++ b/drivers/watchdog/wdt_dw_common.c @@ -103,8 +103,3 @@ int dw_wdt_probe(const uint32_t base, const uint32_t reset_pulse_length) return 0; } - -int dw_wdt_disable(const struct device *dev) -{ - return -ENOTSUP; -} diff --git a/drivers/watchdog/wdt_intel_adsp.c b/drivers/watchdog/wdt_intel_adsp.c index c0e2c0a7d36..a44136d09b8 100644 --- a/drivers/watchdog/wdt_intel_adsp.c +++ b/drivers/watchdog/wdt_intel_adsp.c @@ -211,6 +211,11 @@ int intel_adsp_watchdog_resume(const struct device *dev, const int channel_id) return 0; } +int dw_wdt_disable(const struct device *dev) +{ + return -ENOTSUP; +} + static const struct wdt_driver_api intel_adsp_wdt_api = { .setup = intel_adsp_wdt_setup, .disable = dw_wdt_disable, diff --git a/dts/bindings/watchdog/snps,designware-watchdog.yaml b/dts/bindings/watchdog/snps,designware-watchdog.yaml index 654fb3b2aa1..58ce467f9b2 100644 --- a/dts/bindings/watchdog/snps,designware-watchdog.yaml +++ b/dts/bindings/watchdog/snps,designware-watchdog.yaml @@ -2,7 +2,7 @@ description: Synopsys Designware Watchdog compatible: "snps,designware-watchdog" -include: base.yaml +include: [base.yaml, reset-device.yaml] properties: # This properties is also supported: From f0330892b60027c564de05d39e52f916ba65d125 Mon Sep 17 00:00:00 2001 From: Balsundar Ponnusamy Date: Tue, 17 Oct 2023 15:36:12 +0000 Subject: [PATCH 0339/3723] drivers: watchdog: wdt_dw: add watchdog disable at boot and pause by debug added support for watchdog enable/disable at boot Pausing watchdog timer when CPU is halted by the debugger and pausing watchdog timer when CPU is in sleep state is not configurable through application, so added warning log with return success Signed-off-by: Balsundar Ponnusamy --- drivers/watchdog/wdt_dw.c | 9 +++++++++ drivers/watchdog/wdt_dw_common.c | 6 ++---- 2 files changed, 11 insertions(+), 4 deletions(-) diff --git a/drivers/watchdog/wdt_dw.c b/drivers/watchdog/wdt_dw.c index e9d758b6713..7ef23910562 100644 --- a/drivers/watchdog/wdt_dw.c +++ b/drivers/watchdog/wdt_dw.c @@ -196,6 +196,15 @@ static int dw_wdt_init(const struct device *dev) } #endif + /* + * Enable watchdog if it needs to be enabled at boot. + * watchdog timer will be started with maximum timeout + * that is the default value. + */ + if (!IS_ENABLED(CONFIG_WDT_DISABLE_AT_BOOT)) { + dw_wdt_enable((uint32_t)reg_base); + } + return 0; } diff --git a/drivers/watchdog/wdt_dw_common.c b/drivers/watchdog/wdt_dw_common.c index 230f272ec40..3f8bce57ce6 100644 --- a/drivers/watchdog/wdt_dw_common.c +++ b/drivers/watchdog/wdt_dw_common.c @@ -20,13 +20,11 @@ LOG_MODULE_REGISTER(wdt_dw_common, CONFIG_WDT_LOG_LEVEL); int dw_wdt_check_options(const uint8_t options) { if (options & WDT_OPT_PAUSE_HALTED_BY_DBG) { - LOG_ERR("Pausing watchdog by debugger is not supported."); - return -ENOTSUP; + LOG_WRN("Pausing watchdog by debugger is not configurable"); } if (options & WDT_OPT_PAUSE_IN_SLEEP) { - LOG_ERR("Pausing watchdog in sleep is not supported."); - return -ENOTSUP; + LOG_WRN("Pausing watchdog in sleep is not configurable"); } return 0; From ffffab6ba606a624b2295b74e49af01a66f5a128 Mon Sep 17 00:00:00 2001 From: Balsundar Ponnusamy Date: Mon, 16 Oct 2023 12:54:06 +0000 Subject: [PATCH 0340/3723] drivers: watchdog: wdt_dw: resetting CPU or SoC is not configurable specific to platform, watchdog reset line can be connected either to CPU, SOC or none of the entity. These resets cannot be configured from the application. So added a warning message when application configures this option Signed-off-by: Balsundar Ponnusamy --- drivers/watchdog/wdt_dw.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/drivers/watchdog/wdt_dw.c b/drivers/watchdog/wdt_dw.c index 7ef23910562..657001b1b5c 100644 --- a/drivers/watchdog/wdt_dw.c +++ b/drivers/watchdog/wdt_dw.c @@ -91,8 +91,7 @@ static int dw_wdt_install_timeout(const struct device *dev, const struct wdt_tim } if (config->flags) { - LOG_ERR("Watchdog behavior is not configurable."); - return -ENOTSUP; + LOG_WRN("Watchdog behavior is not configurable."); } #if DT_ANY_INST_HAS_PROP_STATUS_OKAY(interrupts) From 5df70f8a63ec317e79eb4ccffddcbe1f75a39c2d Mon Sep 17 00:00:00 2001 From: Balsundar Ponnusamy Date: Thu, 27 Jul 2023 15:01:30 +0000 Subject: [PATCH 0341/3723] dts: arm64: intel: intel_socfpga: Adding nodes for watchdog add dts support for watchdog to accomodate watchdog driver bringup on aglex and agilex5 Signed-off-by: Balsundar Ponnusamy --- dts/arm64/intel/intel_socfpga_agilex.dtsi | 27 +++++++++++++++ dts/arm64/intel/intel_socfpga_agilex5.dtsi | 39 ++++++++++++++++++++++ 2 files changed, 66 insertions(+) diff --git a/dts/arm64/intel/intel_socfpga_agilex.dtsi b/dts/arm64/intel/intel_socfpga_agilex.dtsi index 19957a19988..e3b3e9b17ca 100644 --- a/dts/arm64/intel/intel_socfpga_agilex.dtsi +++ b/dts/arm64/intel/intel_socfpga_agilex.dtsi @@ -155,6 +155,33 @@ IRQ_DEFAULT_PRIORITY>; reg = <0xffd00100 0x100>; clock-frequency = < 100000000 >; + }; + + watchdog0: watchdog@ffd00200 { + compatible = "snps,designware-watchdog"; + reg = <0xffd00200 0x100>; + clocks = <&clock INTEL_SOCFPGA_CLOCK_WDT>; + status = "disabled"; + }; + + watchdog1: watchdog@ffd00300 { + compatible = "snps,designware-watchdog"; + reg = <0xffd00300 0x100>; + clocks = <&clock INTEL_SOCFPGA_CLOCK_WDT>; + status = "disabled"; + }; + + watchdog2: watchdog@ffd00400 { + compatible = "snps,designware-watchdog"; + reg = <0xffd00400 0x100>; + clocks = <&clock INTEL_SOCFPGA_CLOCK_WDT>; + status = "disabled"; + }; + + watchdog3: watchdog@ffd00500 { + compatible = "snps,designware-watchdog"; + reg = <0xffd00500 0x100>; + clocks = <&clock INTEL_SOCFPGA_CLOCK_WDT>; status = "disabled"; }; }; diff --git a/dts/arm64/intel/intel_socfpga_agilex5.dtsi b/dts/arm64/intel/intel_socfpga_agilex5.dtsi index 6a98aa34df9..6a177c1047b 100644 --- a/dts/arm64/intel/intel_socfpga_agilex5.dtsi +++ b/dts/arm64/intel/intel_socfpga_agilex5.dtsi @@ -158,6 +158,45 @@ reg = <0x10D00100 0x100>; clock-frequency = <100000000>; resets = <&reset RSTMGR_L4SYSTIMER1_RSTLINE>; + }; + + watchdog0: watchdog@10d00200 { + compatible = "snps,designware-watchdog"; + reg = <0x10d00200 0x100>; + clock-frequency = <100000000>; + resets = <&reset RSTMGR_WATCHDOG0_RSTLINE>; + status = "disabled"; + }; + + watchdog1: watchdog@10d00300 { + compatible = "snps,designware-watchdog"; + reg = <0x10d00300 0x100>; + clock-frequency = <100000000>; + resets = <&reset RSTMGR_WATCHDOG1_RSTLINE>; + status = "disabled"; + }; + + watchdog2: watchdog@10d00400 { + compatible = "snps,designware-watchdog"; + reg = <0x10d00400 0x100>; + clock-frequency = <100000000>; + resets = <&reset RSTMGR_WATCHDOG2_RSTLINE>; + status = "disabled"; + }; + + watchdog3: watchdog@10d00500 { + compatible = "snps,designware-watchdog"; + reg = <0x10d00500 0x100>; + clock-frequency = <100000000>; + resets = <&reset RSTMGR_WATCHDOG3_RSTLINE>; + status = "disabled"; + }; + + watchdog4: watchdog@10d00600 { + compatible = "snps,designware-watchdog"; + reg = <0x10d00600 0x100>; + clock-frequency = <100000000>; + resets = <&reset RSTMGR_WATCHDOG4_RSTLINE>; status = "disabled"; }; From 1e7b75d047f223107c0c72defa79b5ac50cb1418 Mon Sep 17 00:00:00 2001 From: Balsundar Ponnusamy Date: Mon, 10 Jul 2023 11:36:10 +0000 Subject: [PATCH 0342/3723] samples: drivers: watchdog: add sample application support add agilex and agilex5 board support in watchdog sample application Signed-off-by: Balsundar Ponnusamy --- .../boards/intel_socfpga_agilex5_socdk.overlay | 18 ++++++++++++++++++ .../boards/intel_socfpga_agilex_socdk.overlay | 18 ++++++++++++++++++ 2 files changed, 36 insertions(+) create mode 100644 samples/drivers/watchdog/boards/intel_socfpga_agilex5_socdk.overlay create mode 100644 samples/drivers/watchdog/boards/intel_socfpga_agilex_socdk.overlay diff --git a/samples/drivers/watchdog/boards/intel_socfpga_agilex5_socdk.overlay b/samples/drivers/watchdog/boards/intel_socfpga_agilex5_socdk.overlay new file mode 100644 index 00000000000..6bcb1dc5909 --- /dev/null +++ b/samples/drivers/watchdog/boards/intel_socfpga_agilex5_socdk.overlay @@ -0,0 +1,18 @@ +/* + * Copyright (C) 2023 Intel Corporation + * + * SPDX-License-Identifier: Apache-2.0 + */ + +/ { + aliases { + watchdog0 = &watchdog0; + }; +}; + +&watchdog0 { + interrupt-parent = <&gic>; + interrupts = ; + status = "okay"; +}; diff --git a/samples/drivers/watchdog/boards/intel_socfpga_agilex_socdk.overlay b/samples/drivers/watchdog/boards/intel_socfpga_agilex_socdk.overlay new file mode 100644 index 00000000000..6bcb1dc5909 --- /dev/null +++ b/samples/drivers/watchdog/boards/intel_socfpga_agilex_socdk.overlay @@ -0,0 +1,18 @@ +/* + * Copyright (C) 2023 Intel Corporation + * + * SPDX-License-Identifier: Apache-2.0 + */ + +/ { + aliases { + watchdog0 = &watchdog0; + }; +}; + +&watchdog0 { + interrupt-parent = <&gic>; + interrupts = ; + status = "okay"; +}; From c2dc103101a5d4c5153e39b3571cd2b543bf317a Mon Sep 17 00:00:00 2001 From: Balsundar Ponnusamy Date: Tue, 11 Jul 2023 06:04:25 +0000 Subject: [PATCH 0343/3723] CODEOWNERS: update codeowner for watchdog adding code owner for snps designware watchdog Signed-off-by: Balsundar Ponnusamy --- CODEOWNERS | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CODEOWNERS b/CODEOWNERS index 8872e7381c5..6b8919a6a84 100644 --- a/CODEOWNERS +++ b/CODEOWNERS @@ -398,7 +398,7 @@ /drivers/watchdog/Kconfig.it8xxx2 @RuibinChang /drivers/watchdog/wdt_counter.c @nordic-krch /drivers/watchdog/*rpi_pico* @thedjnK -/drivers/watchdog/*dw* @softwarecki +/drivers/watchdog/*dw* @softwarecki @pbalsundar /drivers/watchdog/*ifx* @sreeramIfx /drivers/wifi/esp_at/ @mniestroj /drivers/wifi/eswifi/ @loicpoulain @nandojve From 5cd2e17424e1bedef410a2f0917f4d3a72da7c72 Mon Sep 17 00:00:00 2001 From: Christopher Friedt Date: Mon, 27 Nov 2023 18:14:45 -0500 Subject: [PATCH 0344/3723] posix: pthread: fix warning about uninitialized variable Initialize the variable to zero. I don't think there is any way out of this function without it being initialized, so IMHO it's a false positive. Signed-off-by: Christopher Friedt --- lib/posix/pthread.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/posix/pthread.c b/lib/posix/pthread.c index 3cc4413949b..46d0ffeae4d 100644 --- a/lib/posix/pthread.c +++ b/lib/posix/pthread.c @@ -468,7 +468,7 @@ int pthread_create(pthread_t *th, const pthread_attr_t *_attr, void *(*threadrou int pthread_getconcurrency(void) { - int ret; + int ret = 0; K_SPINLOCK(&pthread_pool_lock) { ret = pthread_concurrency; From a51bd53cef2b2b6cacb1dc7a366adb45565659f3 Mon Sep 17 00:00:00 2001 From: Peter Mitsis Date: Thu, 23 Nov 2023 14:01:08 -0500 Subject: [PATCH 0345/3723] tests: Update posix common test for Xtensa Updates the posix common test so that it will pass on Xtensa SMP boards such as intel_adsp_ace15_mtpm. This involves ensuring that a newly created thread does not attempt access/modify the stack of a thread that is currently running on a different CPU. Signed-off-by: Peter Mitsis --- tests/posix/common/src/mutex.c | 6 +++--- tests/posix/common/src/pthread.c | 7 ++++--- 2 files changed, 7 insertions(+), 6 deletions(-) diff --git a/tests/posix/common/src/mutex.c b/tests/posix/common/src/mutex.c index 5ddcd68c93a..01c49220727 100644 --- a/tests/posix/common/src/mutex.c +++ b/tests/posix/common/src/mutex.c @@ -17,6 +17,7 @@ static K_THREAD_STACK_DEFINE(stack, STACK_SIZE); pthread_mutex_t mutex1; pthread_mutex_t mutex2; +pthread_mutex_t mutex; void *normal_mutex_entry(void *p1) { @@ -213,12 +214,12 @@ static void timespec_add_ms(struct timespec *ts, uint32_t ms) static void *test_mutex_timedlock_fn(void *arg) { struct timespec time_point; - pthread_mutex_t *mutex = (pthread_mutex_t *)arg; + pthread_mutex_t *mtx = (pthread_mutex_t *)arg; zassume_ok(clock_gettime(CLOCK_MONOTONIC, &time_point)); timespec_add_ms(&time_point, TIMEDLOCK_TIMEOUT_MS); - return INT_TO_POINTER(pthread_mutex_timedlock(mutex, &time_point)); + return INT_TO_POINTER(pthread_mutex_timedlock(mtx, &time_point)); } /** @brief Test to verify @ref pthread_mutex_timedlock returns ETIMEDOUT */ @@ -226,7 +227,6 @@ ZTEST(posix_apis, test_mutex_timedlock) { void *ret; pthread_t th; - pthread_t mutex; pthread_attr_t attr; zassert_ok(pthread_attr_init(&attr)); diff --git a/tests/posix/common/src/pthread.c b/tests/posix/common/src/pthread.c index 0276afd6045..bcb09da8602 100644 --- a/tests/posix/common/src/pthread.c +++ b/tests/posix/common/src/pthread.c @@ -53,6 +53,8 @@ static int barrier_failed; static int barrier_done[N_THR_E]; static int barrier_return[N_THR_E]; +static uint32_t param; + /* First phase bounces execution between two threads using a condition * variable, continuously testing that no other thread is mucking with * the protected state. This ends with all threads going back to @@ -827,15 +829,14 @@ static void *fun(void *arg) ZTEST(posix_apis, test_pthread_dynamic_stacks) { pthread_t th; - uint32_t x = 0; if (!IS_ENABLED(CONFIG_DYNAMIC_THREAD)) { ztest_test_skip(); } - zassert_ok(pthread_create(&th, NULL, fun, &x)); + zassert_ok(pthread_create(&th, NULL, fun, ¶m)); zassert_ok(pthread_join(th, NULL)); - zassert_equal(BIOS_FOOD, x); + zassert_equal(BIOS_FOOD, param); } static void *non_null_retval(void *arg) From 91fdef0783e0355c85344617bbf202d7fe67831a Mon Sep 17 00:00:00 2001 From: Jun Lin Date: Thu, 23 Nov 2023 14:37:18 +0800 Subject: [PATCH 0346/3723] soc: npcx: add support for npcx9mfp Add new SoC npcx9mfp support for npcx9 series. Signed-off-by: Jun Lin --- dts/arm/nuvoton/npcx9mfp.dtsi | 48 +++++++++++++++++++ soc/arm/nuvoton_npcx/Kconfig | 1 + soc/arm/nuvoton_npcx/common/ecst/ecst_args.py | 1 + .../npcx9/Kconfig.defconfig.npcx9mfp | 11 +++++ soc/arm/nuvoton_npcx/npcx9/Kconfig.soc | 3 ++ 5 files changed, 64 insertions(+) create mode 100644 dts/arm/nuvoton/npcx9mfp.dtsi create mode 100644 soc/arm/nuvoton_npcx/npcx9/Kconfig.defconfig.npcx9mfp diff --git a/dts/arm/nuvoton/npcx9mfp.dtsi b/dts/arm/nuvoton/npcx9mfp.dtsi new file mode 100644 index 00000000000..fb646513f43 --- /dev/null +++ b/dts/arm/nuvoton/npcx9mfp.dtsi @@ -0,0 +1,48 @@ +/* + * Copyright (c) 2023 Nuvoton Technology Corporation. + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include +#include "npcx/npcx9.dtsi" + +/ { + flash0: flash@10058000 { + reg = <0x10058000 DT_SIZE_K(416)>; + }; + + flash1: flash@64000000 { + reg = <0x64000000 DT_SIZE_K(1024)>; + }; + + sram0: memory@200c0000 { + compatible = "mmio-sram"; + reg = <0x200C0000 DT_SIZE_K(92)>; + }; + + /* RAM space used by Booter */ + bootloader_ram: memory@200d7000 { + compatible = "mmio-sram"; + reg = <0x200D7000 DT_SIZE_K(4)>; + }; + + soc-id { + device-id = <0x2b>; + }; +}; + +&qspi_fiu0 { + int_flash: w25q80@0 { + compatible ="nuvoton,npcx-fiu-nor"; + size = ; + reg = <0>; + status = "okay"; + + /* quad spi bus configuration of nor flash device */ + qspi-flags = ; + mapped-addr = <0x64000000>; + pinctrl-0 = <&int_flash_sl>; + pinctrl-names = "default"; + }; +}; diff --git a/soc/arm/nuvoton_npcx/Kconfig b/soc/arm/nuvoton_npcx/Kconfig index 27b260025cc..1e27a6c4608 100644 --- a/soc/arm/nuvoton_npcx/Kconfig +++ b/soc/arm/nuvoton_npcx/Kconfig @@ -42,6 +42,7 @@ config NPCX_HEADER_CHIP default "npcx9m3" if SOC_NPCX9M3F default "npcx9m6" if SOC_NPCX9M6F default "npcx9m7" if SOC_NPCX9M7F + default "npcx9mfp" if SOC_NPCX9MFP default "npcx4m3" if SOC_NPCX4M3F default "npcx4m8" if SOC_NPCX4M8F diff --git a/soc/arm/nuvoton_npcx/common/ecst/ecst_args.py b/soc/arm/nuvoton_npcx/common/ecst/ecst_args.py index e580758f274..ab1aad770d8 100755 --- a/soc/arm/nuvoton_npcx/common/ecst/ecst_args.py +++ b/soc/arm/nuvoton_npcx/common/ecst/ecst_args.py @@ -53,6 +53,7 @@ 'npcx9m3': {'ram_address': 0x10080000, 'ram_size': 0x50000}, 'npcx9m6': {'ram_address': 0x10090000, 'ram_size': 0x40000}, 'npcx9m7': {'ram_address': 0x10070000, 'ram_size': 0x60000}, + 'npcx9mfp': {'ram_address': 0x10058000, 'ram_size': 0x80000}, 'npcx4m3': {'ram_address': 0x10088000, 'ram_size': 0x50000}, 'npcx4m8': {'ram_address': 0x10060000, 'ram_size': 0x7c800}, } diff --git a/soc/arm/nuvoton_npcx/npcx9/Kconfig.defconfig.npcx9mfp b/soc/arm/nuvoton_npcx/npcx9/Kconfig.defconfig.npcx9mfp new file mode 100644 index 00000000000..170c3deceaa --- /dev/null +++ b/soc/arm/nuvoton_npcx/npcx9/Kconfig.defconfig.npcx9mfp @@ -0,0 +1,11 @@ +# Nuvoton Cortex-M4 Embedded Controller + +# Copyright (c) 2023 Nuvoton Technology Corporation. +# SPDX-License-Identifier: Apache-2.0 + +if SOC_NPCX9MFP + +config SOC + default "npcx9mfp" + +endif # SOC_NPCX9MFP diff --git a/soc/arm/nuvoton_npcx/npcx9/Kconfig.soc b/soc/arm/nuvoton_npcx/npcx9/Kconfig.soc index e198c44698a..dbebc40d52d 100644 --- a/soc/arm/nuvoton_npcx/npcx9/Kconfig.soc +++ b/soc/arm/nuvoton_npcx/npcx9/Kconfig.soc @@ -16,4 +16,7 @@ config SOC_NPCX9M6F config SOC_NPCX9M7F bool "NPCX9M7F" +config SOC_NPCX9MFP + bool "NPCX9MFP" + endchoice From c2ddfa2bd25fe8cdf674466f38b58ba7042746ce Mon Sep 17 00:00:00 2001 From: Aaron Ye Date: Fri, 24 Nov 2023 11:41:52 +0800 Subject: [PATCH 0347/3723] MAINTAINERS: Add more collaborators for Ambiq platforms. Add Ambiq engineers responsible for maintaining Zephyr on Ambiq platforms. Signed-off-by: Aaron Ye --- MAINTAINERS.yml | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/MAINTAINERS.yml b/MAINTAINERS.yml index 3393ef145e5..f3962556064 100644 --- a/MAINTAINERS.yml +++ b/MAINTAINERS.yml @@ -222,6 +222,8 @@ Ambiq Platforms: collaborators: - tgorochowik - msobkowski + - aaronyegx + - RichardSWheatley files: - soc/arm/ambiq/ - boards/arm/apollo*/ @@ -3273,6 +3275,8 @@ West: collaborators: - tgorochowik - msobkowski + - aaronyegx + - RichardSWheatley files: - modules/hal_ambiq/ labels: From d3af185acd65ecd98e76667338b2f435a1ce454d Mon Sep 17 00:00:00 2001 From: Anas Nashif Date: Thu, 23 Nov 2023 14:22:59 -0500 Subject: [PATCH 0348/3723] twister: add --aggressive-no-clean option Useful option during development and when applying smaller change to the code and verifying changes using tests. This works fine as long as no dependencies or major changes are done, i.e. when editing few files and in a subsystem. Use with caution and use on your own risk :-) When building multiple tests, this provide significant boost, up to 300% faster than when rebuilding everything from scratch or when re-running cmake every single time. Signed-off-by: Anas Nashif --- scripts/pylib/twister/twisterlib/environment.py | 12 ++++++++++++ scripts/pylib/twister/twisterlib/runner.py | 7 ++++++- 2 files changed, 18 insertions(+), 1 deletion(-) diff --git a/scripts/pylib/twister/twisterlib/environment.py b/scripts/pylib/twister/twisterlib/environment.py index b7e11406cd4..fcf5c436733 100644 --- a/scripts/pylib/twister/twisterlib/environment.py +++ b/scripts/pylib/twister/twisterlib/environment.py @@ -452,6 +452,15 @@ def add_parse_arguments(parser = None): help="Re-use the outdir before building. Will result in " "faster compilation since builds will be incremental.") + parser.add_argument( + "--aggressive-no-clean", action="store_true", + help="Re-use the outdir before building and do not re-run cmake. Will result in " + "much faster compilation since builds will be incremental. This option might " + " result in build failures and inconsistencies if dependencies change or when " + " applied on a significantly changed code base. Use on your own " + " risk. It is recommended to only use this option for local " + " development and when testing localized change in a subsystem.") + parser.add_argument( '--detailed-test-id', action='store_true', help="Include paths to tests' locations in tests' names. Names will follow " @@ -740,6 +749,9 @@ def parse_arguments(parser, args, options = None): if options.show_footprint or options.compare_report: options.enable_size_report = True + if options.aggressive_no_clean: + options.no_clean = True + if options.coverage: options.enable_coverage = True diff --git a/scripts/pylib/twister/twisterlib/runner.py b/scripts/pylib/twister/twisterlib/runner.py index e3e6562d437..2d948336f50 100644 --- a/scripts/pylib/twister/twisterlib/runner.py +++ b/scripts/pylib/twister/twisterlib/runner.py @@ -1250,12 +1250,17 @@ def add_tasks_to_queue(self, pipeline, build_only=False, test_only=False, retry_ instance.filter_stages = [] if instance.testsuite.filter: instance.filter_stages = self.get_cmake_filter_stages(instance.testsuite.filter, expr_parser.reserved.keys()) + if test_only and instance.run: pipeline.put({"op": "run", "test": instance}) elif instance.filter_stages and "full" not in instance.filter_stages: pipeline.put({"op": "filter", "test": instance}) else: - pipeline.put({"op": "cmake", "test": instance}) + cache_file = os.path.join(instance.build_dir, "CMakeCache.txt") + if os.path.exists(cache_file) and self.env.options.aggressive_no_clean: + pipeline.put({"op": "build", "test": instance}) + else: + pipeline.put({"op": "cmake", "test": instance}) def pipeline_mgr(self, pipeline, done_queue, lock, results): From 0d535010cd3928b521b536f18cf433423dd808b6 Mon Sep 17 00:00:00 2001 From: Anas Nashif Date: Fri, 24 Nov 2023 08:07:45 -0500 Subject: [PATCH 0349/3723] twister: tests: adapt test for new option mock build_dir of instance. Signed-off-by: Anas Nashif --- scripts/tests/twister/test_runner.py | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/scripts/tests/twister/test_runner.py b/scripts/tests/twister/test_runner.py index e4d886191fd..8b98e79a5a3 100644 --- a/scripts/tests/twister/test_runner.py +++ b/scripts/tests/twister/test_runner.py @@ -2529,11 +2529,11 @@ def mock_get_cmake_filter_stages(filter, keys): return [filter] instances = { - 'dummy1': mock.Mock(run=True, retries=0, status='passed'), - 'dummy2': mock.Mock(run=True, retries=0, status='skipped'), - 'dummy3': mock.Mock(run=True, retries=0, status='filtered'), - 'dummy4': mock.Mock(run=True, retries=0, status='error'), - 'dummy5': mock.Mock(run=True, retries=0, status='failed') + 'dummy1': mock.Mock(run=True, retries=0, status='passed', build_dir="/tmp"), + 'dummy2': mock.Mock(run=True, retries=0, status='skipped', build_dir="/tmp"), + 'dummy3': mock.Mock(run=True, retries=0, status='filtered', build_dir="/tmp"), + 'dummy4': mock.Mock(run=True, retries=0, status='error', build_dir="/tmp"), + 'dummy5': mock.Mock(run=True, retries=0, status='failed', build_dir="/tmp") } instances['dummy4'].testsuite.filter = 'some' instances['dummy5'].testsuite.filter = 'full' From 362924a6939814fe527987c4a6d27a728bb2e1eb Mon Sep 17 00:00:00 2001 From: Pavel Vasilyev Date: Thu, 23 Nov 2023 15:48:11 +0100 Subject: [PATCH 0350/3723] Bluetooth: Mesh: Use ATOMIC_DEFINE instead of atomic_t atomic_*_bit functions work with atomic_t arg as with array, therefore the atomic variable should be declared using ATOMIC_DEFINE. Coverity-CID: 333358 Fixes #65588 Signed-off-by: Pavel Vasilyev --- subsys/bluetooth/mesh/rpl.c | 15 ++++++++------- 1 file changed, 8 insertions(+), 7 deletions(-) diff --git a/subsys/bluetooth/mesh/rpl.c b/subsys/bluetooth/mesh/rpl.c index b3113530854..e19df33908f 100644 --- a/subsys/bluetooth/mesh/rpl.c +++ b/subsys/bluetooth/mesh/rpl.c @@ -41,8 +41,9 @@ static ATOMIC_DEFINE(store, CONFIG_BT_MESH_CRPL); enum { PENDING_CLEAR, PENDING_RESET, + RPL_FLAGS_COUNT, }; -static atomic_t rpl_flags; +static ATOMIC_DEFINE(rpl_flags, RPL_FLAGS_COUNT); static inline int rpl_idx(const struct bt_mesh_rpl *rpl) { @@ -133,7 +134,7 @@ bool bt_mesh_rpl_check(struct bt_mesh_net_rx *rx, /* Existing slot for given address */ if (rpl->src == rx->ctx.addr) { if (!rpl->old_iv && - atomic_test_bit(&rpl_flags, PENDING_RESET) && + atomic_test_bit(rpl_flags, PENDING_RESET) && !atomic_test_bit(store, i)) { /* Until rpl reset is finished, entry with old_iv == false and * without "store" bit set will be removed, therefore it can be @@ -178,7 +179,7 @@ void bt_mesh_rpl_clear(void) return; } - atomic_set_bit(&rpl_flags, PENDING_CLEAR); + atomic_set_bit(rpl_flags, PENDING_CLEAR); bt_mesh_settings_store_schedule(BT_MESH_SETTINGS_RPL_PENDING); } @@ -233,7 +234,7 @@ void bt_mesh_rpl_reset(void) } if (i != 0) { - atomic_set_bit(&rpl_flags, PENDING_RESET); + atomic_set_bit(rpl_flags, PENDING_RESET); bt_mesh_settings_store_schedule(BT_MESH_SETTINGS_RPL_PENDING); } } else { @@ -358,8 +359,8 @@ void bt_mesh_rpl_pending_store(uint16_t addr) bt_mesh_settings_store_cancel(BT_MESH_SETTINGS_RPL_PENDING); } - clr = atomic_test_and_clear_bit(&rpl_flags, PENDING_CLEAR); - rst = atomic_test_bit(&rpl_flags, PENDING_RESET); + clr = atomic_test_and_clear_bit(rpl_flags, PENDING_CLEAR); + rst = atomic_test_bit(rpl_flags, PENDING_RESET); for (int i = 0; i < ARRAY_SIZE(replay_list); i++) { struct bt_mesh_rpl *rpl = &replay_list[i]; @@ -398,7 +399,7 @@ void bt_mesh_rpl_pending_store(uint16_t addr) } } - atomic_clear_bit(&rpl_flags, PENDING_RESET); + atomic_clear_bit(rpl_flags, PENDING_RESET); if (addr == BT_MESH_ADDR_ALL_NODES) { (void)memset(&replay_list[last - shift + 1], 0, sizeof(struct bt_mesh_rpl) * shift); From 161aadd5909e610fa5e25a5912c882403718e21e Mon Sep 17 00:00:00 2001 From: Pavel Vasilyev Date: Thu, 23 Nov 2023 16:12:06 +0100 Subject: [PATCH 0351/3723] Bluetooth: Mesh: Return immediately if labels not supported This avoid unnecessary triggering of settings work. Signed-off-by: Pavel Vasilyev --- subsys/bluetooth/mesh/va.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/subsys/bluetooth/mesh/va.c b/subsys/bluetooth/mesh/va.c index 6db9194da47..b69c22f40e9 100644 --- a/subsys/bluetooth/mesh/va.c +++ b/subsys/bluetooth/mesh/va.c @@ -306,6 +306,10 @@ void bt_mesh_va_clear(void) { int i; + if (CONFIG_BT_MESH_LABEL_COUNT == 0) { + return; + } + for (i = 0; i < ARRAY_SIZE(virtual_addrs); i++) { if (virtual_addrs[i].ref) { virtual_addrs[i].ref = 0U; From d2ea18722859dc43a895230bce88e8a0a38d07ac Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Manuel=20Arg=C3=BCelles?= Date: Sat, 25 Nov 2023 12:06:39 +0700 Subject: [PATCH 0352/3723] drivers: mdio: add support for NXP S32 GMAC MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit MDIO controller is part of GMAC and it requires GMAC ethernet driver to initialize first because it will reset the whole GMAC hw block during initialization. Both C22 and C45 APIs are supported. Co-authored-by: Benjamin Perseghetti Signed-off-by: Manuel Argüelles Signed-off-by: Benjamin Perseghetti --- drivers/mdio/CMakeLists.txt | 1 + drivers/mdio/Kconfig | 3 +- drivers/mdio/Kconfig.nxp_s32_gmac | 21 ++ .../{Kconfig.nxp_s32 => Kconfig.nxp_s32_netc} | 0 drivers/mdio/mdio_nxp_s32_gmac.c | 185 ++++++++++++++++++ drivers/mdio/mdio_shell.c | 2 + dts/bindings/mdio/mdio-controller.yaml | 7 + dts/bindings/mdio/nxp,s32-gmac-mdio.yaml | 23 +++ west.yml | 2 +- 9 files changed, 242 insertions(+), 2 deletions(-) create mode 100644 drivers/mdio/Kconfig.nxp_s32_gmac rename drivers/mdio/{Kconfig.nxp_s32 => Kconfig.nxp_s32_netc} (100%) create mode 100644 drivers/mdio/mdio_nxp_s32_gmac.c create mode 100644 dts/bindings/mdio/nxp,s32-gmac-mdio.yaml diff --git a/drivers/mdio/CMakeLists.txt b/drivers/mdio/CMakeLists.txt index 4972626cdb5..360111f0c08 100644 --- a/drivers/mdio/CMakeLists.txt +++ b/drivers/mdio/CMakeLists.txt @@ -6,5 +6,6 @@ zephyr_library_sources_ifdef(CONFIG_MDIO_SHELL mdio_shell.c) zephyr_library_sources_ifdef(CONFIG_MDIO_ATMEL_SAM mdio_sam.c) zephyr_library_sources_ifdef(CONFIG_MDIO_ESP32 mdio_esp32.c) zephyr_library_sources_ifdef(CONFIG_MDIO_NXP_S32_NETC mdio_nxp_s32_netc.c) +zephyr_library_sources_ifdef(CONFIG_MDIO_NXP_S32_GMAC mdio_nxp_s32_gmac.c) zephyr_library_sources_ifdef(CONFIG_MDIO_ADIN2111 mdio_adin2111.c) zephyr_library_sources_ifdef(CONFIG_MDIO_GPIO mdio_gpio.c) diff --git a/drivers/mdio/Kconfig b/drivers/mdio/Kconfig index b3831b2c2d7..37721e885a6 100644 --- a/drivers/mdio/Kconfig +++ b/drivers/mdio/Kconfig @@ -26,7 +26,8 @@ config MDIO_SHELL # overridden (by defining symbols in multiple locations) source "drivers/mdio/Kconfig.esp32" source "drivers/mdio/Kconfig.sam" -source "drivers/mdio/Kconfig.nxp_s32" +source "drivers/mdio/Kconfig.nxp_s32_netc" +source "drivers/mdio/Kconfig.nxp_s32_gmac" source "drivers/mdio/Kconfig.adin2111" source "drivers/mdio/Kconfig.gpio" diff --git a/drivers/mdio/Kconfig.nxp_s32_gmac b/drivers/mdio/Kconfig.nxp_s32_gmac new file mode 100644 index 00000000000..01927b6a642 --- /dev/null +++ b/drivers/mdio/Kconfig.nxp_s32_gmac @@ -0,0 +1,21 @@ +# Copyright 2023 NXP +# SPDX-License-Identifier: Apache-2.0 + +menuconfig MDIO_NXP_S32_GMAC + bool "NXP S32 GMAC MDIO driver" + default y + depends on DT_HAS_NXP_S32_GMAC_MDIO_ENABLED + select CLOCK_CONTROL + select NOCACHE_MEMORY if ARCH_HAS_NOCACHE_MEMORY_SUPPORT + help + Enable GMAC MDIO driver for NXP S32 SoCs. + +if MDIO_NXP_S32_GMAC + +config MDIO_NXP_S32_TIMEOUT + int "Timeout for read/write operations in milliseconds" + default 2 + help + Timeout (in milliseconds) for read/write operations over MDIO. + +endif # MDIO_NXP_S32_GMAC diff --git a/drivers/mdio/Kconfig.nxp_s32 b/drivers/mdio/Kconfig.nxp_s32_netc similarity index 100% rename from drivers/mdio/Kconfig.nxp_s32 rename to drivers/mdio/Kconfig.nxp_s32_netc diff --git a/drivers/mdio/mdio_nxp_s32_gmac.c b/drivers/mdio/mdio_nxp_s32_gmac.c new file mode 100644 index 00000000000..afd7c8ccedb --- /dev/null +++ b/drivers/mdio/mdio_nxp_s32_gmac.c @@ -0,0 +1,185 @@ +/* + * Copyright 2023 NXP + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#define DT_DRV_COMPAT nxp_s32_gmac_mdio + +#include +LOG_MODULE_REGISTER(nxp_s32_mdio, CONFIG_MDIO_LOG_LEVEL); + +#include +#include +#include +#include +#include + +#include + +#define GMAC_MDIO_REG_OFFSET (0x200) + +#define GMAC_STATUS_TO_ERRNO(x) \ + ((x) == GMAC_STATUS_SUCCESS ? 0 : ((x) == GMAC_STATUS_TIMEOUT ? -ETIMEDOUT : -EIO)) + +struct mdio_nxp_s32_config { + uint8_t instance; + bool suppress_preamble; + const struct pinctrl_dev_config *pincfg; + const struct device *clock_dev; + clock_control_subsys_t clock_subsys; +}; + +struct mdio_nxp_s32_data { + struct k_mutex bus_mutex; + uint32_t clock_freq; +}; + +static int mdio_nxp_s32_read_c45(const struct device *dev, uint8_t prtad, uint8_t devad, + uint16_t regad, uint16_t *regval) +{ + const struct mdio_nxp_s32_config *const cfg = dev->config; + struct mdio_nxp_s32_data *data = dev->data; + Gmac_Ip_StatusType status; + + k_mutex_lock(&data->bus_mutex, K_FOREVER); + + /* Configure MDIO controller before initiating a transmission */ + Gmac_Ip_EnableMDIO(cfg->instance, cfg->suppress_preamble, data->clock_freq); + + status = Gmac_Ip_MDIOReadMMD(cfg->instance, prtad, devad, regad, regval, + CONFIG_MDIO_NXP_S32_TIMEOUT); + + k_mutex_unlock(&data->bus_mutex); + + return GMAC_STATUS_TO_ERRNO(status); +} + +static int mdio_nxp_s32_write_c45(const struct device *dev, uint8_t prtad, uint8_t devad, + uint16_t regad, uint16_t regval) +{ + const struct mdio_nxp_s32_config *const cfg = dev->config; + struct mdio_nxp_s32_data *data = dev->data; + Gmac_Ip_StatusType status; + + k_mutex_lock(&data->bus_mutex, K_FOREVER); + + /* Configure MDIO controller before initiating a transmission */ + Gmac_Ip_EnableMDIO(cfg->instance, cfg->suppress_preamble, data->clock_freq); + + status = Gmac_Ip_MDIOWriteMMD(cfg->instance, prtad, devad, regad, regval, + CONFIG_MDIO_NXP_S32_TIMEOUT); + + k_mutex_unlock(&data->bus_mutex); + + return GMAC_STATUS_TO_ERRNO(status); +} + +static int mdio_nxp_s32_read_c22(const struct device *dev, uint8_t prtad, + uint8_t regad, uint16_t *regval) +{ + const struct mdio_nxp_s32_config *const cfg = dev->config; + struct mdio_nxp_s32_data *data = dev->data; + Gmac_Ip_StatusType status; + + k_mutex_lock(&data->bus_mutex, K_FOREVER); + + /* Configure MDIO controller before initiating a transmission */ + Gmac_Ip_EnableMDIO(cfg->instance, cfg->suppress_preamble, data->clock_freq); + + status = Gmac_Ip_MDIORead(cfg->instance, prtad, regad, regval, + CONFIG_MDIO_NXP_S32_TIMEOUT); + + k_mutex_unlock(&data->bus_mutex); + + return GMAC_STATUS_TO_ERRNO(status); +} + +static int mdio_nxp_s32_write_c22(const struct device *dev, uint8_t prtad, + uint8_t regad, uint16_t regval) +{ + const struct mdio_nxp_s32_config *const cfg = dev->config; + struct mdio_nxp_s32_data *data = dev->data; + Gmac_Ip_StatusType status; + + k_mutex_lock(&data->bus_mutex, K_FOREVER); + + /* Configure MDIO controller before initiating a transmission */ + Gmac_Ip_EnableMDIO(cfg->instance, cfg->suppress_preamble, data->clock_freq); + + status = Gmac_Ip_MDIOWrite(cfg->instance, prtad, regad, regval, + CONFIG_MDIO_NXP_S32_TIMEOUT); + + k_mutex_unlock(&data->bus_mutex); + + return GMAC_STATUS_TO_ERRNO(status); +} + +static int mdio_nxp_s32_init(const struct device *dev) +{ + const struct mdio_nxp_s32_config *const cfg = dev->config; + struct mdio_nxp_s32_data *data = dev->data; + int err; + + if (!device_is_ready(cfg->clock_dev)) { + LOG_ERR("Clock control device not ready"); + return -ENODEV; + } + + if (clock_control_get_rate(cfg->clock_dev, cfg->clock_subsys, &data->clock_freq)) { + LOG_ERR("Failed to get clock frequency"); + return -EIO; + } + + err = pinctrl_apply_state(cfg->pincfg, PINCTRL_STATE_DEFAULT); + if (err != 0) { + return err; + } + + k_mutex_init(&data->bus_mutex); + + return 0; +} + +static void mdio_nxp_s32_noop(const struct device *dev) +{ + ARG_UNUSED(dev); + /* Controller does not support enabling/disabling MDIO bus */ +} + +static const struct mdio_driver_api mdio_nxp_s32_driver_api = { + .read = mdio_nxp_s32_read_c22, + .write = mdio_nxp_s32_write_c22, + .read_c45 = mdio_nxp_s32_read_c45, + .write_c45 = mdio_nxp_s32_write_c45, + .bus_enable = mdio_nxp_s32_noop, + .bus_disable = mdio_nxp_s32_noop, +}; + +#define MDIO_NXP_S32_HW_INSTANCE_CHECK(i, n) \ + (((DT_INST_REG_ADDR(n) - GMAC_MDIO_REG_OFFSET) == IP_GMAC_##i##_BASE) ? i : 0) + +#define MDIO_NXP_S32_HW_INSTANCE(n) \ + LISTIFY(__DEBRACKET FEATURE_GMAC_NUM_INSTANCES, \ + MDIO_NXP_S32_HW_INSTANCE_CHECK, (|), n) + +#define MDIO_NXP_S32_DEVICE(n) \ + PINCTRL_DT_INST_DEFINE(n); \ + static struct mdio_nxp_s32_data mdio_nxp_s32_data_##n; \ + static const struct mdio_nxp_s32_config mdio_nxp_s32_config_##n = { \ + .instance = MDIO_NXP_S32_HW_INSTANCE(n), \ + .suppress_preamble = (bool)DT_INST_PROP(n, suppress_preamble), \ + .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, \ + &mdio_nxp_s32_init, \ + NULL, \ + &mdio_nxp_s32_data_##n, \ + &mdio_nxp_s32_config_##n, \ + POST_KERNEL, \ + CONFIG_MDIO_INIT_PRIORITY, \ + &mdio_nxp_s32_driver_api); + +DT_INST_FOREACH_STATUS_OKAY(MDIO_NXP_S32_DEVICE) diff --git a/drivers/mdio/mdio_shell.c b/drivers/mdio/mdio_shell.c index b70ff7bc1a0..d0fa925ef36 100644 --- a/drivers/mdio/mdio_shell.c +++ b/drivers/mdio/mdio_shell.c @@ -21,6 +21,8 @@ LOG_MODULE_REGISTER(mdio_shell, CONFIG_LOG_DEFAULT_LEVEL); #define DT_DRV_COMPAT espressif_esp32_mdio #elif DT_HAS_COMPAT_STATUS_OKAY(nxp_s32_netc_emdio) #define DT_DRV_COMPAT nxp_s32_netc_emdio +#elif DT_HAS_COMPAT_STATUS_OKAY(nxp_s32_gmac_mdio) +#define DT_DRV_COMPAT nxp_s32_gmac_mdio #elif DT_HAS_COMPAT_STATUS_OKAY(adi_adin2111_mdio) #define DT_DRV_COMPAT adi_adin2111_mdio #elif DT_HAS_COMPAT_STATUS_OKAY(smsc_lan91c111_mdio) diff --git a/dts/bindings/mdio/mdio-controller.yaml b/dts/bindings/mdio/mdio-controller.yaml index 9a2a6782d53..9259bbf3afa 100644 --- a/dts/bindings/mdio/mdio-controller.yaml +++ b/dts/bindings/mdio/mdio-controller.yaml @@ -15,3 +15,10 @@ properties: "#size-cells": required: true const: 0 + + suppress-preamble: + type: boolean + description: | + When present, the SMA suppresses the 32-bit preamble and transmits + MDIO frames with only 1 preamble bit. By default, the MDIO frame + always has 32 bits of preamble as defined in the IEEE 802.3 specs. diff --git a/dts/bindings/mdio/nxp,s32-gmac-mdio.yaml b/dts/bindings/mdio/nxp,s32-gmac-mdio.yaml new file mode 100644 index 00000000000..7e7f7273c0b --- /dev/null +++ b/dts/bindings/mdio/nxp,s32-gmac-mdio.yaml @@ -0,0 +1,23 @@ +# Copyright 2023 NXP +# SPDX-License-Identifier: Apache-2.0 + +description: | + NXP S32 GMAC MDIO controller. + + Driver for the GMAC Station Management Agent (SMA), which is a two wire + interface (MDC/MDIO), implemented as per IEEE 802.3 specification. SMA + supports both MDIO Clause 45 and Clause 22 frame structure. + +compatible: "nxp,s32-gmac-mdio" + +include: [mdio-controller.yaml, pinctrl-device.yaml] + +properties: + pinctrl-0: + required: true + + pinctrl-names: + required: true + + clocks: + required: true diff --git a/west.yml b/west.yml index afaa1203891..d0590f17a3b 100644 --- a/west.yml +++ b/west.yml @@ -193,7 +193,7 @@ manifest: groups: - hal - name: hal_nxp - revision: 69046233b7a7fac3138ae4dd5bcf6158e82529bb + revision: 1ed023da7f5541b78099b5a030507a2839ce554f path: modules/hal/nxp groups: - hal From 0fa204b9fd790216736acc8c4a41b7f3f7973a98 Mon Sep 17 00:00:00 2001 From: Benjamin Perseghetti Date: Fri, 24 Nov 2023 21:39:21 -0500 Subject: [PATCH 0353/3723] drivers: net: phy: add tja1103 MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Adds the tja1103 enet phy for setting phy options on the mr_canhubk3. Co-authored-by: Manuel Argüelles Co-authored-by: Peter van der Perk Signed-off-by: Benjamin Perseghetti --- boards/arm/mr_canhubk3/Kconfig.defconfig | 3 + boards/arm/mr_canhubk3/doc/index.rst | 7 +- .../arm/mr_canhubk3/mr_canhubk3-pinctrl.dtsi | 12 + boards/arm/mr_canhubk3/mr_canhubk3.dts | 14 +- drivers/ethernet/phy/CMakeLists.txt | 1 + drivers/ethernet/phy/Kconfig | 8 + drivers/ethernet/phy/phy_tja1103.c | 247 ++++++++++++++++++ dts/arm/nxp/nxp_s32k344_m7.dtsi | 10 + dts/bindings/ethernet/nxp,tja1103.yaml | 24 ++ include/zephyr/net/mdio.h | 6 + 10 files changed, 326 insertions(+), 6 deletions(-) create mode 100644 drivers/ethernet/phy/phy_tja1103.c create mode 100644 dts/bindings/ethernet/nxp,tja1103.yaml diff --git a/boards/arm/mr_canhubk3/Kconfig.defconfig b/boards/arm/mr_canhubk3/Kconfig.defconfig index 6cf6f085492..e20f3cc3d6f 100644 --- a/boards/arm/mr_canhubk3/Kconfig.defconfig +++ b/boards/arm/mr_canhubk3/Kconfig.defconfig @@ -25,6 +25,9 @@ if NETWORKING config NET_L2_ETHERNET default y if !NET_LOOPBACK && !NET_TEST +config MDIO + default y if NET_L2_ETHERNET + endif # NETWORKING endif # BOARD_MR_CANHUBK3 diff --git a/boards/arm/mr_canhubk3/doc/index.rst b/boards/arm/mr_canhubk3/doc/index.rst index 63dbb36666b..711ee43a0ca 100644 --- a/boards/arm/mr_canhubk3/doc/index.rst +++ b/boards/arm/mr_canhubk3/doc/index.rst @@ -31,7 +31,7 @@ Hardware - Console UART - 6x CAN FD - 100Base-T1 Ethernet - - DroneCode standard JST-GH connectors and I/O headers for I2C, SPI, GPIO, + - JST-GH connectors and I/O headers for I2C, SPI, GPIO, PWM, etc. More information about the hardware and design resources can be found at @@ -57,6 +57,7 @@ ADC SAR on-chip adc LPSPI on-chip spi WDT FS26 SBC watchdog EMAC on-chip ethernet + mdio eMIOS on-chip pwm EDMA on-chip dma ============ ========== ================================ @@ -252,9 +253,9 @@ Ethernet This board has a single instance of Ethernet Media Access Controller (EMAC) interfacing with a `NXP TJA1103`_ 100Base-T1 Ethernet PHY. Currently, there is -no driver for this PHY and this board default pin strapping configuration for +limited driver for this PHY that allows for overiding the default pin strapping configuration for the PHY (RMII, master, autonomous mode enabled, polarity correction enabled) -allows to use it without software configuration. +to slave mode. The 100Base-T1 signals are available in connector ``P9`` and can be converted to 100Base-T using a Ethernet media converter such as `RDDRONE-T1ADAPT`_. diff --git a/boards/arm/mr_canhubk3/mr_canhubk3-pinctrl.dtsi b/boards/arm/mr_canhubk3/mr_canhubk3-pinctrl.dtsi index 1c3ff008508..0b2906f2982 100644 --- a/boards/arm/mr_canhubk3/mr_canhubk3-pinctrl.dtsi +++ b/boards/arm/mr_canhubk3/mr_canhubk3-pinctrl.dtsi @@ -270,6 +270,18 @@ }; }; + mdio0_default: mdio0_default { + group1 { + pinmux = <(PTD16_EMAC_MII_RMII_MDIO_O | PTD16_EMAC_MII_RMII_MDIO_I)>; + input-enable; + output-enable; + }; + group2 { + pinmux = ; + output-enable; + }; + }; + emios0_default: emios0_default { group1 { pinmux = , , diff --git a/boards/arm/mr_canhubk3/mr_canhubk3.dts b/boards/arm/mr_canhubk3/mr_canhubk3.dts index ec5eb1ece43..50b72338da2 100644 --- a/boards/arm/mr_canhubk3/mr_canhubk3.dts +++ b/boards/arm/mr_canhubk3/mr_canhubk3.dts @@ -409,10 +409,18 @@ phy-connection-type = "rmii"; local-mac-address = [02 04 9f aa bb cc]; status = "okay"; +}; - fixed-link { - speed = <100>; - full-duplex; +&mdio0 { + pinctrl-0 = <&mdio0_default>; + pinctrl-names = "default"; + status = "okay"; + + phy: ethernet-phy@12 { + compatible = "nxp,tja1103"; + status = "okay"; + reg = <0x12>; + master-slave = "slave"; }; }; diff --git a/drivers/ethernet/phy/CMakeLists.txt b/drivers/ethernet/phy/CMakeLists.txt index ce4cbe3e715..d3a7777ae24 100644 --- a/drivers/ethernet/phy/CMakeLists.txt +++ b/drivers/ethernet/phy/CMakeLists.txt @@ -2,3 +2,4 @@ zephyr_library_sources_ifdef(CONFIG_PHY_GENERIC_MII phy_mii.c) zephyr_library_sources_ifdef(CONFIG_PHY_ADIN2111 phy_adin2111.c) +zephyr_library_sources_ifdef(CONFIG_PHY_TJA1103 phy_tja1103.c) diff --git a/drivers/ethernet/phy/Kconfig b/drivers/ethernet/phy/Kconfig index ae1229de1fc..b148d1c37d1 100644 --- a/drivers/ethernet/phy/Kconfig +++ b/drivers/ethernet/phy/Kconfig @@ -39,6 +39,14 @@ config PHY_ADIN2111 help Enable ADIN2111 PHY driver. +config PHY_TJA1103 + bool "TJA1103 PHY driver" + default y + depends on DT_HAS_NXP_TJA1103_ENABLED + depends on MDIO + help + Enable TJA1103 PHY driver. + config PHY_AUTONEG_TIMEOUT_MS int "Auto-negotiation timeout value in milliseconds" default 4000 diff --git a/drivers/ethernet/phy/phy_tja1103.c b/drivers/ethernet/phy/phy_tja1103.c new file mode 100644 index 00000000000..946a4d16200 --- /dev/null +++ b/drivers/ethernet/phy/phy_tja1103.c @@ -0,0 +1,247 @@ +/* + * Copyright 2023 NXP + * Copyright 2023 CogniPilot Foundation + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#define DT_DRV_COMPAT nxp_tja1103 + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +LOG_MODULE_REGISTER(phy_tja1103, CONFIG_PHY_LOG_LEVEL); + +/* PHYs out of reset check retry delay */ +#define TJA1103_AWAIT_DELAY_POLL_US 15000U +/* Number of retries for PHYs out of reset check */ +#define TJA1103_AWAIT_RETRY_COUNT 200U + +/* TJA1103 PHY identifier */ +#define TJA1103_ID 0x1BB013 + +/* MMD30 - Device status register */ +#define TJA1103_DEVICE_CONTROL (0x0040U) +#define TJA1103_DEVICE_CONTROL_GLOBAL_CFG_EN BIT(14) +#define TJA1103_DEVICE_CONTROL_SUPER_CFG_EN BIT(13) +/* Shared - PHY control register */ +#define TJA1103_PHY_CONTROL (0x8100U) +#define TJA1103_PHY_CONTROL_CFG_EN BIT(14) +/* Shared - PHY status register */ +#define TJA1103_PHY_STATUS (0x8102U) +#define TJA1103_PHY_STATUS_LINK_STAT BIT(2) + +struct phy_tja1103_config { + const struct device *mdio; + uint8_t phy_addr; + uint8_t master_slave; +}; + +struct phy_tja1103_data { + struct phy_link_state state; + struct k_sem sem; +}; + +static inline int phy_tja1103_c22_read(const struct device *dev, uint16_t reg, uint16_t *val) +{ + const struct phy_tja1103_config *const cfg = dev->config; + + return mdio_read(cfg->mdio, cfg->phy_addr, reg, val); +} + +static inline int phy_tja1103_c22_write(const struct device *dev, uint16_t reg, uint16_t val) +{ + const struct phy_tja1103_config *const cfg = dev->config; + + return mdio_write(cfg->mdio, cfg->phy_addr, reg, val); +} + +static inline int phy_tja1103_c45_write(const struct device *dev, uint16_t devad, uint16_t reg, + uint16_t val) +{ + const struct phy_tja1103_config *cfg = dev->config; + + return mdio_write_c45(cfg->mdio, cfg->phy_addr, devad, reg, val); +} + +static inline int phy_tja1103_c45_read(const struct device *dev, uint16_t devad, uint16_t reg, + uint16_t *val) +{ + const struct phy_tja1103_config *cfg = dev->config; + + return mdio_read_c45(cfg->mdio, cfg->phy_addr, devad, reg, val); +} + +static int phy_tja1103_reg_read(const struct device *dev, uint16_t reg_addr, uint32_t *data) +{ + const struct phy_tja1103_config *cfg = dev->config; + int ret; + + mdio_bus_enable(cfg->mdio); + + ret = phy_tja1103_c22_read(dev, reg_addr, (uint16_t *)data); + + mdio_bus_disable(cfg->mdio); + + return ret; +} + +static int phy_tja1103_reg_write(const struct device *dev, uint16_t reg_addr, uint32_t data) +{ + const struct phy_tja1103_config *cfg = dev->config; + int ret; + + mdio_bus_enable(cfg->mdio); + + ret = phy_tja1103_c22_write(dev, reg_addr, (uint16_t)data); + + mdio_bus_disable(cfg->mdio); + + return ret; +} + +static int phy_tja1103_id(const struct device *dev, uint32_t *phy_id) +{ + uint16_t val; + + if (phy_tja1103_c22_read(dev, MII_PHYID1R, &val) < 0) { + return -EIO; + } + + *phy_id = (val & UINT16_MAX) << 16; + + if (phy_tja1103_c22_read(dev, MII_PHYID2R, &val) < 0) { + return -EIO; + } + + *phy_id |= (val & UINT16_MAX); + + return 0; +} + +static int phy_tja1103_get_link_state(const struct device *dev, struct phy_link_state *state) +{ + struct phy_tja1103_data *const data = dev->data; + uint16_t val; + + k_sem_take(&data->sem, K_FOREVER); + + if (phy_tja1103_c45_read(dev, MDIO_MMD_VENDOR_SPECIFIC1, TJA1103_PHY_STATUS, &val) >= 0) { + + data->state.is_up = (val & TJA1103_PHY_STATUS_LINK_STAT) != 0; + + memcpy(state, &data->state, sizeof(struct phy_link_state)); + } + + k_sem_give(&data->sem); + + return 0; +} + +static int phy_tja1103_cfg_link(const struct device *dev, enum phy_link_speed adv_speeds) +{ + ARG_UNUSED(dev); + + if (adv_speeds & LINK_FULL_100BASE_T) { + return 0; + } + + return -ENOTSUP; +} + +static int phy_tja1103_init(const struct device *dev) +{ + const struct phy_tja1103_config *const cfg = dev->config; + struct phy_tja1103_data *const data = dev->data; + uint32_t phy_id = 0; + uint16_t val; + int ret; + + data->state.is_up = false; + data->state.speed = LINK_FULL_100BASE_T; + + ret = WAIT_FOR(!phy_tja1103_id(dev, &phy_id) && phy_id == TJA1103_ID, + TJA1103_AWAIT_RETRY_COUNT * TJA1103_AWAIT_DELAY_POLL_US, + k_sleep(K_USEC(TJA1103_AWAIT_DELAY_POLL_US))); + if (ret < 0) { + LOG_ERR("Unable to obtain PHY ID for device 0x%x", cfg->phy_addr); + return -ENODEV; + } + + /* enable config registers */ + ret = phy_tja1103_c45_write(dev, MDIO_MMD_VENDOR_SPECIFIC1, TJA1103_DEVICE_CONTROL, + TJA1103_DEVICE_CONTROL_GLOBAL_CFG_EN | + TJA1103_DEVICE_CONTROL_SUPER_CFG_EN); + if (ret < 0) { + return ret; + } + + ret = phy_tja1103_c45_write(dev, MDIO_MMD_VENDOR_SPECIFIC1, TJA1103_PHY_CONTROL, + TJA1103_PHY_CONTROL_CFG_EN); + if (ret < 0) { + return ret; + } + + ret = phy_tja1103_c45_read(dev, MDIO_MMD_PMAPMD, MDIO_PMA_PMD_BT1_CTRL, &val); + if (ret < 0) { + return ret; + } + + /* Change master/slave mode if need */ + if (cfg->master_slave == 1) { + val |= MDIO_PMA_PMD_BT1_CTRL_CFG_MST; + } else if (cfg->master_slave == 2) { + val &= ~MDIO_PMA_PMD_BT1_CTRL_CFG_MST; + } + + ret = phy_tja1103_c45_write(dev, MDIO_MMD_PMAPMD, MDIO_PMA_PMD_BT1_CTRL, val); + if (ret < 0) { + return ret; + } + + /* Wait for settings to go in affect before checking link */ + k_sleep(K_MSEC(400)); + + phy_tja1103_get_link_state(dev, &data->state); + return ret; +} + +static int phy_tja1103_link_cb_set(const struct device *dev, phy_callback_t cb, void *user_data) +{ + ARG_UNUSED(dev); + ARG_UNUSED(cb); + ARG_UNUSED(user_data); + return -ENOTSUP; +} + +static const struct ethphy_driver_api phy_tja1103_api = { + .get_link = phy_tja1103_get_link_state, + .cfg_link = phy_tja1103_cfg_link, + .link_cb_set = phy_tja1103_link_cb_set, + .read = phy_tja1103_reg_read, + .write = phy_tja1103_reg_write, +}; + +#define TJA1103_INITIALIZE(n) \ + static const struct phy_tja1103_config phy_tja1103_config_##n = { \ + .phy_addr = DT_INST_REG_ADDR(n), \ + .mdio = DEVICE_DT_GET(DT_INST_BUS(n)), \ + .master_slave = DT_INST_ENUM_IDX(n, master_slave), \ + }; \ + static struct phy_tja1103_data phy_tja1103_data_##n = { \ + .sem = Z_SEM_INITIALIZER(phy_tja1103_data_##n.sem, 1, 1), \ + }; \ + DEVICE_DT_INST_DEFINE(n, &phy_tja1103_init, NULL, &phy_tja1103_data_##n, \ + &phy_tja1103_config_##n, POST_KERNEL, CONFIG_PHY_INIT_PRIORITY, \ + &phy_tja1103_api); + +DT_INST_FOREACH_STATUS_OKAY(TJA1103_INITIALIZE) diff --git a/dts/arm/nxp/nxp_s32k344_m7.dtsi b/dts/arm/nxp/nxp_s32k344_m7.dtsi index 60196628a57..f5e96aba8e1 100644 --- a/dts/arm/nxp/nxp_s32k344_m7.dtsi +++ b/dts/arm/nxp/nxp_s32k344_m7.dtsi @@ -631,6 +631,16 @@ compatible = "nxp,s32-gmac"; interrupts = <105 0>, <106 0>, <107 0>, <108 0>; interrupt-names = "common", "tx", "rx", "safety"; + status = "disabled"; + }; + + mdio0: mdio@40480200 { + reg = <0x40480200 0x8>; + compatible = "nxp,s32-gmac-mdio"; + clocks = <&clock NXP_S32_AIPS_PLAT_CLK>; + #address-cells = <1>; + #size-cells = <0>; + status = "disabled"; }; edma0: dma-controller@4020c000 { diff --git a/dts/bindings/ethernet/nxp,tja1103.yaml b/dts/bindings/ethernet/nxp,tja1103.yaml new file mode 100644 index 00000000000..a15c9be3aba --- /dev/null +++ b/dts/bindings/ethernet/nxp,tja1103.yaml @@ -0,0 +1,24 @@ +# Copyright (c) 2023 NXP +# SPDX-License-Identifier: Apache-2.0 + +description: TJA1103 PHY + +compatible: "nxp,tja1103" + +include: phy.yaml + +properties: + reg: + required: true + description: PHY address + + master-slave: + type: string + required: true + description: | + 100BASE-T1 Specifies that either phy has to run in master / slave mode + Default selects the mode set by the pinstrapping on the hardware design. + enum: + - "default" + - "master" + - "slave" diff --git a/include/zephyr/net/mdio.h b/include/zephyr/net/mdio.h index e7161a7a766..8d1998f7cec 100644 --- a/include/zephyr/net/mdio.h +++ b/include/zephyr/net/mdio.h @@ -110,6 +110,8 @@ enum mdio_opcode { #define MDIO_AN_T1_ADV_M 0x0203U /** BASE-T1 Auto-negotiation advertisement register [47:32] */ #define MDIO_AN_T1_ADV_H 0x0204U +/* BASE-T1 PMA/PMD control register */ +#define MDIO_PMA_PMD_BT1_CTRL 0x0834U /* BASE-T1 Auto-negotiation Control register */ /** Auto-negotiation Restart */ @@ -155,6 +157,10 @@ enum mdio_opcode { /* 10BASE-T1L High Level Transmit Operating Mode Ability */ #define MDIO_AN_T1_ADV_H_10L_TX_HI BIT(13) +/* BASE-T1 PMA/PMD control register */ +/** BASE-T1 master/slave configuration */ +#define MDIO_PMA_PMD_BT1_CTRL_CFG_MST BIT(14) + /* 10BASE-T1L registers */ /** 10BASE-T1L PMA control */ From c0cb995bceabb18bd8ba9b4f195dcf2d8bb3ab7a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Diego=20Elio=20Petten=C3=B2?= Date: Sun, 26 Nov 2023 20:06:13 +0000 Subject: [PATCH 0354/3723] ev11l78a: minimize memory usage in the default config. MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The ATSAMD20E16 used in this board only has 8KiB SRAM, so the defaults are not really suitable for anything close to useful, particularly the sink sample that most closely resembles the original demo for the board. This should also allow more tests not to be skipped for this board as otherwise they overflow RAM usage. Signed-off-by: Diego Elio Pettenò --- boards/arm/ev11l78a/ev11l78a_defconfig | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/boards/arm/ev11l78a/ev11l78a_defconfig b/boards/arm/ev11l78a/ev11l78a_defconfig index 51b5780ea70..5d9a8a9d651 100644 --- a/boards/arm/ev11l78a/ev11l78a_defconfig +++ b/boards/arm/ev11l78a/ev11l78a_defconfig @@ -11,3 +11,16 @@ CONFIG_GPIO=y CONFIG_SERIAL=y CONFIG_UART_CONSOLE=y CONFIG_UART_INTERRUPT_DRIVEN=y + +# Kernel Options due to Low Memory (4k) +CONFIG_LOG_BUFFER_SIZE=256 +CONFIG_MAIN_STACK_SIZE=640 +CONFIG_IDLE_STACK_SIZE=200 +CONFIG_ISR_STACK_SIZE=512 +CONFIG_USBC_STACK_SIZE=512 +# Prevent Interrupt Vector Table in RAM +CONFIG_SRAM_VECTOR_TABLE=n + +# This board only supports the sink role, so +# no need to ever implement source for it. +CONFIG_USBC_CSM_SINK_ONLY=y From 00d8263a935dbfed3088f0fdc911aab7eb801587 Mon Sep 17 00:00:00 2001 From: Marek Pieta Date: Mon, 27 Nov 2023 19:31:30 +0100 Subject: [PATCH 0355/3723] soc: arm: nrf52: Configurable EGU instance for anomaly 109 workaround Change makes EGU instance used for anomaly 109 workaround configurable. The default EGU instance (5) may be used for other purpose. Signed-off-by: Marek Pieta --- modules/hal_nordic/nrfx/nrfx_config.h | 2 ++ soc/arm/nordic_nrf/nrf52/Kconfig.soc | 8 ++++++++ 2 files changed, 10 insertions(+) diff --git a/modules/hal_nordic/nrfx/nrfx_config.h b/modules/hal_nordic/nrfx/nrfx_config.h index aaf31751004..b5b09b96078 100644 --- a/modules/hal_nordic/nrfx/nrfx_config.h +++ b/modules/hal_nordic/nrfx/nrfx_config.h @@ -586,6 +586,8 @@ #define NRFX_SPIS_NRF52_ANOMALY_109_WORKAROUND_ENABLED 1 #define NRFX_TWIM_NRF52_ANOMALY_109_WORKAROUND_ENABLED 1 #define NRFX_PWM_NRF52_ANOMALY_109_WORKAROUND_ENABLED 1 +#define NRFX_PWM_NRF52_ANOMALY_109_EGU_INSTANCE \ + CONFIG_NRF52_ANOMALY_109_WORKAROUND_EGU_INSTANCE #endif #if defined(CONFIG_SOC_SERIES_BSIM_NRFXX) diff --git a/soc/arm/nordic_nrf/nrf52/Kconfig.soc b/soc/arm/nordic_nrf/nrf52/Kconfig.soc index 517b4ce2baa..de6a16129d3 100644 --- a/soc/arm/nordic_nrf/nrf52/Kconfig.soc +++ b/soc/arm/nordic_nrf/nrf52/Kconfig.soc @@ -147,4 +147,12 @@ config NRF52_ANOMALY_109_WORKAROUND 64MHz clock at the same time as the peripheral that is using DMA is started. This anomaly applies to IC revisions up to "3", the most recent one. +config NRF52_ANOMALY_109_WORKAROUND_EGU_INSTANCE + int "Anomaly 109 workaround EGU instance" + depends on NRF52_ANOMALY_109_WORKAROUND + range 0 5 + default 5 + help + EGU instance used by the nRF52 Anomaly 109 workaround for PWM. + endif # SOC_SERIES_NRF52X From d14066b061b0aeb0834473c0d991009388591656 Mon Sep 17 00:00:00 2001 From: Fabio Baltieri Date: Sat, 23 Sep 2023 13:41:34 +0100 Subject: [PATCH 0356/3723] drivers: gnss: add a generic NMEA GNSS driver Add a generic NMEA GNSS driver. Signed-off-by: Fabio Baltieri --- drivers/gnss/CMakeLists.txt | 1 + drivers/gnss/Kconfig | 1 + drivers/gnss/Kconfig.generic | 26 ++++ drivers/gnss/gnss_nmea_generic.c | 176 +++++++++++++++++++++++ dts/bindings/gnss/gnss-nmea-generic.yaml | 32 +++++ 5 files changed, 236 insertions(+) create mode 100644 drivers/gnss/Kconfig.generic create mode 100644 drivers/gnss/gnss_nmea_generic.c create mode 100644 dts/bindings/gnss/gnss-nmea-generic.yaml diff --git a/drivers/gnss/CMakeLists.txt b/drivers/gnss/CMakeLists.txt index 6c24df4903e..cfa5c6ed210 100644 --- a/drivers/gnss/CMakeLists.txt +++ b/drivers/gnss/CMakeLists.txt @@ -7,4 +7,5 @@ zephyr_library_sources_ifdef(CONFIG_GNSS_DUMP gnss_dump.c) zephyr_library_sources_ifdef(CONFIG_GNSS_PARSE gnss_parse.c) zephyr_library_sources_ifdef(CONFIG_GNSS_NMEA0183 gnss_nmea0183.c) zephyr_library_sources_ifdef(CONFIG_GNSS_NMEA0183_MATCH gnss_nmea0183_match.c) +zephyr_library_sources_ifdef(CONFIG_GNSS_NMEA_GENERIC gnss_nmea_generic.c) zephyr_library_sources_ifdef(CONFIG_GNSS_QUECTEL_LCX6G gnss_quectel_lcx6g.c) diff --git a/drivers/gnss/Kconfig b/drivers/gnss/Kconfig index 5bdc0f530d8..2ff552940a3 100644 --- a/drivers/gnss/Kconfig +++ b/drivers/gnss/Kconfig @@ -64,6 +64,7 @@ module = GNSS module-str = gnss source "subsys/logging/Kconfig.template.log_config" +rsource "Kconfig.generic" rsource "Kconfig.quectel_lcx6g" endif diff --git a/drivers/gnss/Kconfig.generic b/drivers/gnss/Kconfig.generic new file mode 100644 index 00000000000..47fbd4a7c6c --- /dev/null +++ b/drivers/gnss/Kconfig.generic @@ -0,0 +1,26 @@ +# Copyright 2023 Google LLC +# SPDX-License-Identifier: Apache-2.0 + +config GNSS_NMEA_GENERIC + bool "Generic GNSS NMEA device" + default y + depends on GNSS + depends on DT_HAS_GNSS_NMEA_GENERIC_ENABLED + select MODEM_MODULES + select MODEM_BACKEND_UART + select MODEM_CHAT + select GNSS_PARSE + select GNSS_NMEA0183 + select GNSS_NMEA0183_MATCH + help + Generic NMEA based GNSS device. + +config GNSS_NMEA_GENERIC_SATELLITES_COUNT + int "Maximum satellite count" + depends on GNSS_SATELLITES + default 24 + help + Maximum number of satellite that the driver that can be decoded from + the GNSS device. This does not affect the number of devices that the + device is actually tracking, just how many of those can be reported + in the satellites callback. diff --git a/drivers/gnss/gnss_nmea_generic.c b/drivers/gnss/gnss_nmea_generic.c new file mode 100644 index 00000000000..d24ee2b034d --- /dev/null +++ b/drivers/gnss/gnss_nmea_generic.c @@ -0,0 +1,176 @@ +/* + * Copyright (c) 2023 Trackunit Corporation + * Copyright (c) 2023 Bjarki Arge Andreasen + * Copyright 2023 Google LLC + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include +#include +#include +#include +#include +#include + +#include "gnss_publish.h" +#include "gnss_nmea0183.h" +#include "gnss_nmea0183_match.h" +#include "gnss_parse.h" + +#include +LOG_MODULE_REGISTER(gnss_nmea_generic, CONFIG_GNSS_LOG_LEVEL); + +#define DT_DRV_COMPAT gnss_nmea_generic + +#define UART_RECV_BUF_SZ 128 +#define CHAT_RECV_BUF_SZ 256 +#define CHAT_ARGV_SZ 32 + +struct gnss_nmea_generic_config { + const struct device *uart; + uint16_t nmea_timeout_ms; +}; + +struct gnss_nmea_generic_data { + struct gnss_nmea0183_match_data match_data; +#if CONFIG_GNSS_SATELLITES + struct gnss_satellite satellites[CONFIG_GNSS_NMEA_GENERIC_SATELLITES_COUNT]; +#endif + + /* UART backend */ + struct modem_pipe *uart_pipe; + struct modem_backend_uart uart_backend; + uint8_t uart_backend_receive_buf[UART_RECV_BUF_SZ]; + + /* Modem chat */ + struct modem_chat chat; + uint8_t chat_receive_buf[CHAT_RECV_BUF_SZ]; + uint8_t *chat_argv[CHAT_ARGV_SZ]; + + struct k_spinlock lock; +}; + +MODEM_CHAT_MATCHES_DEFINE(unsol_matches, + MODEM_CHAT_MATCH_WILDCARD("$??GGA,", ",*", gnss_nmea0183_match_gga_callback), + MODEM_CHAT_MATCH_WILDCARD("$??RMC,", ",*", gnss_nmea0183_match_rmc_callback), +#if CONFIG_GNSS_SATELLITES + MODEM_CHAT_MATCH_WILDCARD("$??GSV,", ",*", gnss_nmea0183_match_gsv_callback), +#endif +); + +static int gnss_nmea_generic_resume(const struct device *dev) +{ + struct gnss_nmea_generic_data *data = dev->data; + int ret; + + ret = modem_pipe_open(data->uart_pipe); + if (ret < 0) { + return ret; + } + + ret = modem_chat_attach(&data->chat, data->uart_pipe); + if (ret < 0) { + modem_pipe_close(data->uart_pipe); + return ret; + } + + return ret; +} + +static struct gnss_driver_api gnss_api = { +}; + +static int gnss_nmea_generic_init_nmea0183_match(const struct device *dev) +{ + const struct gnss_nmea_generic_config *cfg = dev->config; + struct gnss_nmea_generic_data *data = dev->data; + + const struct gnss_nmea0183_match_config match_config = { + .gnss = dev, +#if CONFIG_GNSS_SATELLITES + .satellites = data->satellites, + .satellites_size = ARRAY_SIZE(data->satellites), +#endif + .timeout_ms = cfg->nmea_timeout_ms, + }; + + return gnss_nmea0183_match_init(&data->match_data, &match_config); +} + +static void gnss_nmea_generic_init_pipe(const struct device *dev) +{ + const struct gnss_nmea_generic_config *cfg = dev->config; + struct gnss_nmea_generic_data *data = dev->data; + + const struct modem_backend_uart_config uart_backend_config = { + .uart = cfg->uart, + .receive_buf = data->uart_backend_receive_buf, + .receive_buf_size = sizeof(data->uart_backend_receive_buf), + }; + + data->uart_pipe = modem_backend_uart_init(&data->uart_backend, &uart_backend_config); +} + +static uint8_t gnss_nmea_generic_char_delimiter[] = {'\r', '\n'}; + +static int gnss_nmea_generic_init_chat(const struct device *dev) +{ + struct gnss_nmea_generic_data *data = dev->data; + + const struct modem_chat_config chat_config = { + .user_data = data, + .receive_buf = data->chat_receive_buf, + .receive_buf_size = sizeof(data->chat_receive_buf), + .delimiter = gnss_nmea_generic_char_delimiter, + .delimiter_size = ARRAY_SIZE(gnss_nmea_generic_char_delimiter), + .filter = NULL, + .filter_size = 0, + .argv = data->chat_argv, + .argv_size = ARRAY_SIZE(data->chat_argv), + .unsol_matches = unsol_matches, + .unsol_matches_size = ARRAY_SIZE(unsol_matches), + .process_timeout = K_MSEC(2), + }; + + return modem_chat_init(&data->chat, &chat_config); +} + +static int gnss_nmea_generic_init(const struct device *dev) +{ + int ret; + + ret = gnss_nmea_generic_init_nmea0183_match(dev); + if (ret < 0) { + return ret; + } + + gnss_nmea_generic_init_pipe(dev); + + ret = gnss_nmea_generic_init_chat(dev); + if (ret < 0) { + return ret; + } + + ret = gnss_nmea_generic_resume(dev); + if (ret < 0) { + return ret; + } + + return 0; +} + +#define GNSS_NMEA_GENERIC(inst) \ + static struct gnss_nmea_generic_config gnss_nmea_generic_cfg_##inst = { \ + .uart = DEVICE_DT_GET(DT_INST_BUS(inst)), \ + .nmea_timeout_ms = DT_INST_PROP(inst, nmea_timeout_ms), \ + }; \ + \ + static struct gnss_nmea_generic_data gnss_nmea_generic_data_##inst; \ + \ + DEVICE_DT_INST_DEFINE(inst, gnss_nmea_generic_init, NULL, \ + &gnss_nmea_generic_data_##inst, \ + &gnss_nmea_generic_cfg_##inst, \ + POST_KERNEL, CONFIG_GNSS_INIT_PRIORITY, &gnss_api); + +DT_INST_FOREACH_STATUS_OKAY(GNSS_NMEA_GENERIC) diff --git a/dts/bindings/gnss/gnss-nmea-generic.yaml b/dts/bindings/gnss/gnss-nmea-generic.yaml new file mode 100644 index 00000000000..4be7bde1186 --- /dev/null +++ b/dts/bindings/gnss/gnss-nmea-generic.yaml @@ -0,0 +1,32 @@ +# Copyright 2023 Google LLC +# SPDX-License-Identifier: Apache-2.0 + +description: | + Generic GNSS NMEA receiver + + Implement a generic NMEA based GNSS device. + + Example configuration: + + &uart0 { + current-speed = <9600>; + ... + gnss: gnss-nmea-generic { + compatible = "gnss-nmea-generic"; + }; + }; + +compatible: "gnss-nmea-generic" + +include: + - uart-device.yaml + +properties: + nmea-timeout-ms: + type: int + default: 500 + description: | + Synchronization timeout for NMEA sentences. The NMEA parser is expecting + to receive a GGA and RMC sentences within this time frame to publish a + location data. Set accordingly to the UART datarate and location + reporting frequency. Defaults to 500ms if unspecified. From 407e9a4c74d610f57a1e1b54d3a9f5adf724495d Mon Sep 17 00:00:00 2001 From: Fabio Baltieri Date: Wed, 22 Nov 2023 23:13:18 +0000 Subject: [PATCH 0357/3723] test: add a gnss build_all test Add a generic test for GNSS devices. Signed-off-by: Fabio Baltieri --- MAINTAINERS.yml | 1 + tests/drivers/build_all/gnss/CMakeLists.txt | 8 ++++++++ tests/drivers/build_all/gnss/app.overlay | 22 +++++++++++++++++++++ tests/drivers/build_all/gnss/prj.conf | 3 +++ tests/drivers/build_all/gnss/src/main.c | 10 ++++++++++ tests/drivers/build_all/gnss/testcase.yaml | 8 ++++++++ 6 files changed, 52 insertions(+) create mode 100644 tests/drivers/build_all/gnss/CMakeLists.txt create mode 100644 tests/drivers/build_all/gnss/app.overlay create mode 100644 tests/drivers/build_all/gnss/prj.conf create mode 100644 tests/drivers/build_all/gnss/src/main.c create mode 100644 tests/drivers/build_all/gnss/testcase.yaml diff --git a/MAINTAINERS.yml b/MAINTAINERS.yml index f3962556064..1f059854509 100644 --- a/MAINTAINERS.yml +++ b/MAINTAINERS.yml @@ -1103,6 +1103,7 @@ Release Notes: - doc/hardware/peripherals/gnss.rst - drivers/gnss/ - include/zephyr/drivers/gnss.h + - tests/drivers/build_all/gnss/ - tests/drivers/gnss/ labels: - "area: GNSS" diff --git a/tests/drivers/build_all/gnss/CMakeLists.txt b/tests/drivers/build_all/gnss/CMakeLists.txt new file mode 100644 index 00000000000..518596a02f7 --- /dev/null +++ b/tests/drivers/build_all/gnss/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(build_all) + +FILE(GLOB app_sources src/*.c) +target_sources(app PRIVATE ${app_sources}) diff --git a/tests/drivers/build_all/gnss/app.overlay b/tests/drivers/build_all/gnss/app.overlay new file mode 100644 index 00000000000..1d43fa61525 --- /dev/null +++ b/tests/drivers/build_all/gnss/app.overlay @@ -0,0 +1,22 @@ +/* + * Copyright 2023 Google LLC + * + * SPDX-License-Identifier: Apache-2.0 + */ + +/ { + test { + #address-cells = <1>; + #size-cells = <1>; + + test_uart: uart@0 { + compatible = "vnd,serial"; + reg = <0x0 0x1000>; + status = "okay"; + + gnss: gnss-nmea-generic { + compatible = "gnss-nmea-generic"; + }; + }; + }; +}; diff --git a/tests/drivers/build_all/gnss/prj.conf b/tests/drivers/build_all/gnss/prj.conf new file mode 100644 index 00000000000..945eb0df717 --- /dev/null +++ b/tests/drivers/build_all/gnss/prj.conf @@ -0,0 +1,3 @@ +CONFIG_SERIAL=y +CONFIG_UART_INTERRUPT_DRIVEN=y +CONFIG_GNSS=y diff --git a/tests/drivers/build_all/gnss/src/main.c b/tests/drivers/build_all/gnss/src/main.c new file mode 100644 index 00000000000..ccbdca6d36b --- /dev/null +++ b/tests/drivers/build_all/gnss/src/main.c @@ -0,0 +1,10 @@ +/* + * Copyright 2023 Google LLC + * + * SPDX-License-Identifier: Apache-2.0 + */ + +int main(void) +{ + return 0; +} diff --git a/tests/drivers/build_all/gnss/testcase.yaml b/tests/drivers/build_all/gnss/testcase.yaml new file mode 100644 index 00000000000..faaec12c745 --- /dev/null +++ b/tests/drivers/build_all/gnss/testcase.yaml @@ -0,0 +1,8 @@ +common: + tags: + - drivers + - gnss + build_only: true + platform_allow: native_sim +tests: + drivers.gnss.default: {} From ce812c1b25f8c47f12245880d335175c0c26231d Mon Sep 17 00:00:00 2001 From: Bartosz Bilas Date: Wed, 22 Nov 2023 20:03:30 +0100 Subject: [PATCH 0358/3723] zbus: rework buffer allocation Kconfig options Add a name for the Kconfig choice symbol indicating the Zbus subscriber buffer allocation and adjust the name of the existing choices. Signed-off-by: Bartosz Bilas --- doc/releases/migration-guide-3.6.rst | 5 +++++ doc/releases/release-notes-3.6.rst | 5 +++++ doc/services/zbus/index.rst | 4 ++-- samples/subsys/zbus/msg_subscriber/sample.yaml | 2 +- samples/subsys/zbus/msg_subscriber/src/main.c | 8 ++++---- subsys/zbus/Kconfig | 11 ++++++----- subsys/zbus/zbus.c | 4 ++-- 7 files changed, 25 insertions(+), 14 deletions(-) diff --git a/doc/releases/migration-guide-3.6.rst b/doc/releases/migration-guide-3.6.rst index aed44043e3f..e585fb7482c 100644 --- a/doc/releases/migration-guide-3.6.rst +++ b/doc/releases/migration-guide-3.6.rst @@ -158,6 +158,11 @@ Other Subsystems respective ``reset-gpios``. This has been fixed so those signals now have to be flagged as :c:macro:`GPIO_ACTIVE_LOW` in the devicetree. (:github:`64800`) +* The :kconfig:option:`ZBUS_MSG_SUBSCRIBER_NET_BUF_DYNAMIC` + and :kconfig:option:`ZBUS_MSG_SUBSCRIBER_NET_BUF_STATIC` + zbus options are renamed. Instead, the new :kconfig:option:`ZBUS_MSG_SUBSCRIBER_BUF_ALLOC_DYNAMIC` + and :kconfig:option:`ZBUS_MSG_SUBSCRIBER_BUF_ALLOC_STATIC` options should be used. + Recommended Changes ******************* diff --git a/doc/releases/release-notes-3.6.rst b/doc/releases/release-notes-3.6.rst index 676e16fa77c..84b28a9b517 100644 --- a/doc/releases/release-notes-3.6.rst +++ b/doc/releases/release-notes-3.6.rst @@ -272,6 +272,11 @@ Libraries / Subsystems * ZBus + * Renamed :kconfig:option:`ZBUS_MSG_SUBSCRIBER_NET_BUF_DYNAMIC` and + :kconfig:option:`ZBUS_MSG_SUBSCRIBER_NET_BUF_STATIC` + with :kconfig:option:`ZBUS_MSG_SUBSCRIBER_BUF_ALLOC_DYNAMIC` and + :kconfig:option:`ZBUS_MSG_SUBSCRIBER_BUF_ALLOC_STATIC` + HALs **** diff --git a/doc/services/zbus/index.rst b/doc/services/zbus/index.rst index 6f9378ba5c3..82851ee1234 100644 --- a/doc/services/zbus/index.rst +++ b/doc/services/zbus/index.rst @@ -823,9 +823,9 @@ Related configuration options: * :kconfig:option:`CONFIG_ZBUS_OBSERVER_NAME` enables the name of observers to be available inside the channels metadata; * :kconfig:option:`CONFIG_ZBUS_MSG_SUBSCRIBER` enables the message subscriber observer type; -* :kconfig:option:`CONFIG_ZBUS_MSG_SUBSCRIBER_NET_BUF_DYNAMIC` uses the heap to allocate message +* :kconfig:option:`CONFIG_ZBUS_MSG_SUBSCRIBER_BUF_ALLOC_DYNAMIC` uses the heap to allocate message buffers; -* :kconfig:option:`CONFIG_ZBUS_MSG_SUBSCRIBER_NET_BUF_STATIC` uses the stack to allocate message +* :kconfig:option:`CONFIG_ZBUS_MSG_SUBSCRIBER_BUF_ALLOC_STATIC` uses the stack to allocate message buffers; * :kconfig:option:`CONFIG_ZBUS_MSG_SUBSCRIBER_NET_BUF_POOL_SIZE` the available number of message buffers to be used simultaneously; diff --git a/samples/subsys/zbus/msg_subscriber/sample.yaml b/samples/subsys/zbus/msg_subscriber/sample.yaml index a344a9ee087..716ffd9b829 100644 --- a/samples/subsys/zbus/msg_subscriber/sample.yaml +++ b/samples/subsys/zbus/msg_subscriber/sample.yaml @@ -95,7 +95,7 @@ tests: harness: console extra_configs: - CONFIG_ZBUS_LOG_LEVEL_DBG=y - - CONFIG_ZBUS_MSG_SUBSCRIBER_NET_BUF_STATIC=y + - CONFIG_ZBUS_MSG_SUBSCRIBER_BUF_ALLOC_STATIC=y - CONFIG_ZBUS_MSG_SUBSCRIBER_NET_BUF_STATIC_DATA_SIZE=16 harness_config: type: multi_line diff --git a/samples/subsys/zbus/msg_subscriber/src/main.c b/samples/subsys/zbus/msg_subscriber/src/main.c index 03f9cead113..16022b011de 100644 --- a/samples/subsys/zbus/msg_subscriber/src/main.c +++ b/samples/subsys/zbus/msg_subscriber/src/main.c @@ -26,14 +26,14 @@ void on_heap_free(uintptr_t heap_id, void *mem, size_t bytes) (unsigned int)total_allocated); } -#if defined(CONFIG_ZBUS_MSG_SUBSCRIBER_NET_BUF_DYNAMIC) +#if defined(CONFIG_ZBUS_MSG_SUBSCRIBER_BUF_ALLOC_DYNAMIC) HEAP_LISTENER_ALLOC_DEFINE(my_heap_listener_alloc, HEAP_ID_FROM_POINTER(&_system_heap), on_heap_alloc); HEAP_LISTENER_FREE_DEFINE(my_heap_listener_free, HEAP_ID_FROM_POINTER(&_system_heap), on_heap_free); -#endif /* CONFIG_ZBUS_MSG_SUBSCRIBER_NET_BUF_DYNAMIC */ +#endif /* CONFIG_ZBUS_MSG_SUBSCRIBER_BUF_ALLOC_DYNAMIC */ struct acc_msg { int x; int y; @@ -173,12 +173,12 @@ int main(void) total_allocated = 0; -#if defined(CONFIG_ZBUS_MSG_SUBSCRIBER_NET_BUF_DYNAMIC) +#if defined(CONFIG_ZBUS_MSG_SUBSCRIBER_BUF_ALLOC_DYNAMIC) heap_listener_register(&my_heap_listener_alloc); heap_listener_register(&my_heap_listener_free); -#endif /* CONFIG_ZBUS_MSG_SUBSCRIBER_NET_BUF_DYNAMIC */ +#endif /* CONFIG_ZBUS_MSG_SUBSCRIBER_BUF_ALLOC_DYNAMIC */ while (1) { LOG_INF("----> Publishing to %s channel", zbus_chan_name(&acc_data_chan)); diff --git a/subsys/zbus/Kconfig b/subsys/zbus/Kconfig index ba1c9dd08d0..c40f9187e57 100644 --- a/subsys/zbus/Kconfig +++ b/subsys/zbus/Kconfig @@ -25,13 +25,14 @@ config ZBUS_MSG_SUBSCRIBER if ZBUS_MSG_SUBSCRIBER -choice +choice ZBUS_MSG_SUBSCRIBER_BUF_ALLOC prompt "ZBus msg_subscribers buffer allocation" + default ZBUS_MSG_SUBSCRIBER_BUF_ALLOC_DYNAMIC -config ZBUS_MSG_SUBSCRIBER_NET_BUF_DYNAMIC +config ZBUS_MSG_SUBSCRIBER_BUF_ALLOC_DYNAMIC bool "Use heap to allocate msg_subscriber buffers data" -config ZBUS_MSG_SUBSCRIBER_NET_BUF_STATIC +config ZBUS_MSG_SUBSCRIBER_BUF_ALLOC_STATIC bool "Use fixed data size for msg_subscriber buffers pool" endchoice @@ -40,12 +41,12 @@ config ZBUS_MSG_SUBSCRIBER_NET_BUF_POOL_SIZE default 16 int "The count of net_buf available to be used simutaneously." -if ZBUS_MSG_SUBSCRIBER_NET_BUF_STATIC +if ZBUS_MSG_SUBSCRIBER_BUF_ALLOC_STATIC config ZBUS_MSG_SUBSCRIBER_NET_BUF_STATIC_DATA_SIZE int "The size of the biggest message used with ZBus." -endif # ZBUS_MSG_SUBSCRIBER_NET_BUF_STATIC +endif # ZBUS_MSG_SUBSCRIBER_BUF_ALLOC_STATIC endif # ZBUS_MSG_SUBSCRIBER diff --git a/subsys/zbus/zbus.c b/subsys/zbus/zbus.c index b1178b1fea7..440d4c09315 100644 --- a/subsys/zbus/zbus.c +++ b/subsys/zbus/zbus.c @@ -14,7 +14,7 @@ LOG_MODULE_REGISTER(zbus, CONFIG_ZBUS_LOG_LEVEL); #if defined(CONFIG_ZBUS_MSG_SUBSCRIBER) -#if defined(CONFIG_ZBUS_MSG_SUBSCRIBER_NET_BUF_DYNAMIC) +#if defined(CONFIG_ZBUS_MSG_SUBSCRIBER_BUF_ALLOC_DYNAMIC) NET_BUF_POOL_HEAP_DEFINE(_zbus_msg_subscribers_pool, CONFIG_ZBUS_MSG_SUBSCRIBER_NET_BUF_POOL_SIZE, sizeof(struct zbus_channel *), NULL); @@ -42,7 +42,7 @@ static inline struct net_buf *_zbus_create_net_buf(struct net_buf_pool *pool, si (int)size); return net_buf_alloc(&_zbus_msg_subscribers_pool, timeout); } -#endif /* CONFIG_ZBUS_MSG_SUBSCRIBER_NET_BUF_DYNAMIC */ +#endif /* CONFIG_ZBUS_MSG_SUBSCRIBER_BUF_ALLOC_DYNAMIC */ #endif /* CONFIG_ZBUS_MSG_SUBSCRIBER */ From fcee384aadbbaffaaab4a040059c53c4c12c8fa7 Mon Sep 17 00:00:00 2001 From: Bartosz Bilas Date: Wed, 22 Nov 2023 20:07:18 +0100 Subject: [PATCH 0359/3723] zbus: remove superflous default n from runtime observers By default, it is set to n, so remove that line. Signed-off-by: Bartosz Bilas --- subsys/zbus/Kconfig | 1 - 1 file changed, 1 deletion(-) diff --git a/subsys/zbus/Kconfig b/subsys/zbus/Kconfig index c40f9187e57..72f6c0c5614 100644 --- a/subsys/zbus/Kconfig +++ b/subsys/zbus/Kconfig @@ -52,7 +52,6 @@ endif # ZBUS_MSG_SUBSCRIBER config ZBUS_RUNTIME_OBSERVERS bool "Runtime observers support." - default n config ZBUS_ASSERT_MOCK bool "Zbus assert mock for test purposes." From 34d2c4d6b23c429a8316f4af9acd6117245415bf Mon Sep 17 00:00:00 2001 From: Chen Xingyu Date: Sun, 26 Nov 2023 12:58:23 +0800 Subject: [PATCH 0360/3723] soc: riscv: privileged: Conditionally override `arch_cpu_idle()` The current configuration comes with a common implementation of `arch_cpu_idle()` for the whole riscv-privileged family, utilizing the `WFI` instruction to place the CPU into a light sleep state, with the assumption that it will be awakened later by interrupts such as SYSTICK. However, this approach is not always effective, particularly in scenarios where the SYSTICK is not a valid wake source. This commit uses `CONFIG_RISCV_HAS_CPU_IDLE` as the build condition of the family-level `idle.c`, allowing CPUs that do not enable this option to fallback to a generic arch-level implementation in `arch/riscv/core/cpu_idle.c`. Signed-off-by: Chen Xingyu --- soc/riscv/riscv-privileged/common/CMakeLists.txt | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/soc/riscv/riscv-privileged/common/CMakeLists.txt b/soc/riscv/riscv-privileged/common/CMakeLists.txt index 50ee91a2c33..d1ec3daceb5 100644 --- a/soc/riscv/riscv-privileged/common/CMakeLists.txt +++ b/soc/riscv/riscv-privileged/common/CMakeLists.txt @@ -3,8 +3,9 @@ zephyr_include_directories(.) zephyr_sources( - idle.c soc_irq.S soc_common_irq.c vector.S ) + +zephyr_sources_ifdef(CONFIG_RISCV_HAS_CPU_IDLE idle.c) From 3f7e73416de99bdc35819e0af394ed9dc74e2a2a Mon Sep 17 00:00:00 2001 From: Chen Xingyu Date: Sun, 26 Nov 2023 13:08:45 +0800 Subject: [PATCH 0361/3723] soc: riscv: privileged: efinix-sapphire: Enable CONFIG_RISCV_HAS_CPU_IDLE In an earlier commit, the riscv-privileged level implementation of `arch_cpu_idle()` is not included unless `CONFIG_RISCV_HAS_CPU_IDLE` is enabled. This commit ensures the option is enabled on all the existing CPUs, thereby maintaining the existing behavior. Signed-off-by: Chen Xingyu --- .../riscv-privileged/efinix-sapphire/Kconfig.defconfig.series | 1 + 1 file changed, 1 insertion(+) diff --git a/soc/riscv/riscv-privileged/efinix-sapphire/Kconfig.defconfig.series b/soc/riscv/riscv-privileged/efinix-sapphire/Kconfig.defconfig.series index 233428931a3..e2f31e91a7b 100644 --- a/soc/riscv/riscv-privileged/efinix-sapphire/Kconfig.defconfig.series +++ b/soc/riscv/riscv-privileged/efinix-sapphire/Kconfig.defconfig.series @@ -11,6 +11,7 @@ config SYS_CLOCK_HW_CYCLES_PER_SEC config RISCV_HAS_CPU_IDLE bool + default y config RISCV_SOC_INTERRUPT_INIT bool From b85f1cc246a23114add30186a869bf8b7ff309cf Mon Sep 17 00:00:00 2001 From: Olexander Grin Date: Sat, 25 Nov 2023 17:59:34 +0000 Subject: [PATCH 0362/3723] dts: boards: nucleo_f446re: add support pwm led to nucleo_f446re board add support fade_led, blinky_pwm sample to nucleo_f446re board Signed-off-by: Olexander Grin --- boards/arm/nucleo_f446re/nucleo_f446re.dts | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) diff --git a/boards/arm/nucleo_f446re/nucleo_f446re.dts b/boards/arm/nucleo_f446re/nucleo_f446re.dts index e03b91c0ad9..6afc2996acc 100644 --- a/boards/arm/nucleo_f446re/nucleo_f446re.dts +++ b/boards/arm/nucleo_f446re/nucleo_f446re.dts @@ -31,6 +31,13 @@ }; }; + pwmleds { + compatible = "pwm-leds"; + green_pwm_led: green_pwm_led { + pwms = <&pwm2 1 PWM_MSEC(20) PWM_POLARITY_NORMAL>; + }; + }; + gpio_keys { compatible = "gpio-keys"; user_button: button { @@ -42,6 +49,7 @@ aliases { led0 = &green_led_2; + pwm-led0 = &green_pwm_led; sw0 = &user_button; }; }; @@ -115,6 +123,16 @@ status = "okay"; }; +&timers2 { + status = "okay"; + + pwm2: pwm { + status = "okay"; + pinctrl-0 = <&tim2_ch1_pa5>; + pinctrl-names = "default"; + }; +}; + &rtc { clocks = <&rcc STM32_CLOCK_BUS_APB1 0x10000000>, <&rcc STM32_SRC_LSI RTC_SEL(2)>; From b782b11f16a9bf96a842d533b977a1fb1ca87759 Mon Sep 17 00:00:00 2001 From: Troels Nilsson Date: Wed, 22 Nov 2023 16:59:25 +0100 Subject: [PATCH 0363/3723] Bluetooth: L2CAP: l2cap_create_le_sig_pdu() no longer uses buf The l2cap_create_le_sig_pdu function no longer uses the buf argument; Remove it from the function Signed-off-by: Troels Nilsson --- subsys/bluetooth/host/l2cap.c | 30 +++++++++++++++--------------- 1 file changed, 15 insertions(+), 15 deletions(-) diff --git a/subsys/bluetooth/host/l2cap.c b/subsys/bluetooth/host/l2cap.c index e6fbe2144f8..4f6b0c78175 100644 --- a/subsys/bluetooth/host/l2cap.c +++ b/subsys/bluetooth/host/l2cap.c @@ -427,12 +427,12 @@ void bt_l2cap_disconnected(struct bt_conn *conn) } } -static struct net_buf *l2cap_create_le_sig_pdu(struct net_buf *buf, - uint8_t code, uint8_t ident, +static struct net_buf *l2cap_create_le_sig_pdu(uint8_t code, uint8_t ident, uint16_t len) { struct bt_l2cap_sig_hdr *hdr; struct net_buf_pool *pool = NULL; + struct net_buf *buf; #if defined(CONFIG_BT_L2CAP_DYNAMIC_CHANNEL) if (code == BT_L2CAP_DISCONN_REQ) { @@ -497,7 +497,7 @@ static int l2cap_le_conn_req(struct bt_l2cap_le_chan *ch) ch->ident = get_ident(); - buf = l2cap_create_le_sig_pdu(NULL, BT_L2CAP_LE_CONN_REQ, + buf = l2cap_create_le_sig_pdu(BT_L2CAP_LE_CONN_REQ, ch->ident, sizeof(*req)); if (!buf) { return -ENOMEM; @@ -532,7 +532,7 @@ static int l2cap_ecred_conn_req(struct bt_l2cap_chan **chan, int channels) ident = get_ident(); - buf = l2cap_create_le_sig_pdu(NULL, BT_L2CAP_ECRED_CONN_REQ, ident, + buf = l2cap_create_le_sig_pdu(BT_L2CAP_ECRED_CONN_REQ, ident, sizeof(*req) + (channels * sizeof(uint16_t))); @@ -667,7 +667,7 @@ static void l2cap_send_reject(struct bt_conn *conn, uint8_t ident, struct bt_l2cap_cmd_reject *rej; struct net_buf *buf; - buf = l2cap_create_le_sig_pdu(NULL, BT_L2CAP_CMD_REJECT, ident, + buf = l2cap_create_le_sig_pdu(BT_L2CAP_CMD_REJECT, ident, sizeof(*rej) + data_len); if (!buf) { return; @@ -728,7 +728,7 @@ static void le_conn_param_update_req(struct bt_l2cap *l2cap, uint8_t ident, LOG_DBG("min 0x%04x max 0x%04x latency: 0x%04x timeout: 0x%04x", param.interval_min, param.interval_max, param.latency, param.timeout); - buf = l2cap_create_le_sig_pdu(buf, BT_L2CAP_CONN_PARAM_RSP, ident, + buf = l2cap_create_le_sig_pdu(BT_L2CAP_CONN_PARAM_RSP, ident, sizeof(*rsp)); if (!buf) { return; @@ -1149,7 +1149,7 @@ static void le_conn_req(struct bt_l2cap *l2cap, uint8_t ident, return; } - buf = l2cap_create_le_sig_pdu(buf, BT_L2CAP_LE_CONN_RSP, ident, + buf = l2cap_create_le_sig_pdu(BT_L2CAP_LE_CONN_RSP, ident, sizeof(*rsp)); if (!buf) { return; @@ -1292,7 +1292,7 @@ static void le_ecred_conn_req(struct bt_l2cap *l2cap, uint8_t ident, } response: - buf = l2cap_create_le_sig_pdu(buf, BT_L2CAP_ECRED_CONN_RSP, ident, + buf = l2cap_create_le_sig_pdu(BT_L2CAP_ECRED_CONN_RSP, ident, sizeof(*rsp) + (sizeof(scid) * req_cid_count)); if (!buf) { @@ -1414,7 +1414,7 @@ static void le_ecred_reconf_req(struct bt_l2cap *l2cap, uint8_t ident, LOG_DBG("mtu %u mps %u", mtu, mps); response: - buf = l2cap_create_le_sig_pdu(buf, BT_L2CAP_ECRED_RECONF_RSP, ident, + buf = l2cap_create_le_sig_pdu(BT_L2CAP_ECRED_RECONF_RSP, ident, sizeof(*rsp)); rsp = net_buf_add(buf, sizeof(*rsp)); @@ -1513,7 +1513,7 @@ static void le_disconn_req(struct bt_l2cap *l2cap, uint8_t ident, return; } - buf = l2cap_create_le_sig_pdu(buf, BT_L2CAP_DISCONN_RSP, ident, + buf = l2cap_create_le_sig_pdu(BT_L2CAP_DISCONN_RSP, ident, sizeof(*rsp)); if (!buf) { return; @@ -2301,7 +2301,7 @@ static void l2cap_chan_send_credits(struct bt_l2cap_le_chan *chan, __ASSERT_NO_MSG(bt_l2cap_chan_get_state(&chan->chan) == BT_L2CAP_CONNECTED); - buf = l2cap_create_le_sig_pdu(NULL, BT_L2CAP_LE_CREDITS, get_ident(), + buf = l2cap_create_le_sig_pdu(BT_L2CAP_LE_CREDITS, get_ident(), sizeof(*ev)); if (!buf) { LOG_ERR("Unable to send credits update"); @@ -2331,7 +2331,7 @@ static int l2cap_chan_send_credits_pdu(struct bt_conn *conn, uint16_t cid, uint1 struct net_buf *buf; struct bt_l2cap_le_credits *ev; - buf = l2cap_create_le_sig_pdu(NULL, BT_L2CAP_LE_CREDITS, get_ident(), sizeof(*ev)); + buf = l2cap_create_le_sig_pdu(BT_L2CAP_LE_CREDITS, get_ident(), sizeof(*ev)); if (!buf) { return -ENOBUFS; } @@ -2767,7 +2767,7 @@ int bt_l2cap_update_conn_param(struct bt_conn *conn, struct net_buf *buf; int err; - buf = l2cap_create_le_sig_pdu(NULL, BT_L2CAP_CONN_PARAM_REQ, + buf = l2cap_create_le_sig_pdu(BT_L2CAP_CONN_PARAM_REQ, get_ident(), sizeof(*req)); if (!buf) { return -ENOMEM; @@ -3027,7 +3027,7 @@ int bt_l2cap_ecred_chan_reconfigure(struct bt_l2cap_chan **chans, uint16_t mtu) ident = get_ident(); - buf = l2cap_create_le_sig_pdu(NULL, BT_L2CAP_ECRED_RECONF_REQ, + buf = l2cap_create_le_sig_pdu(BT_L2CAP_ECRED_RECONF_REQ, ident, sizeof(*req) + (i * sizeof(uint16_t))); if (!buf) { @@ -3114,7 +3114,7 @@ int bt_l2cap_chan_disconnect(struct bt_l2cap_chan *chan) le_chan->ident = get_ident(); - buf = l2cap_create_le_sig_pdu(NULL, BT_L2CAP_DISCONN_REQ, + buf = l2cap_create_le_sig_pdu(BT_L2CAP_DISCONN_REQ, le_chan->ident, sizeof(*req)); if (!buf) { return -ENOMEM; From f0032a369da6a9cf4e3cc1608abed8ff2531cdb1 Mon Sep 17 00:00:00 2001 From: Troels Nilsson Date: Wed, 22 Nov 2023 16:16:29 +0100 Subject: [PATCH 0364/3723] Bluetooth: L2CAP: Fix leaking tx metadata Fix l2cap error handling generally not properly disposing of tx buffers for enhanced channels; Any callbacks have to be called and the l2cap_tx_meta_data has to be freed Signed-off-by: Troels Nilsson --- subsys/bluetooth/host/l2cap.c | 27 ++++++++++++++++++++++----- 1 file changed, 22 insertions(+), 5 deletions(-) diff --git a/subsys/bluetooth/host/l2cap.c b/subsys/bluetooth/host/l2cap.c index 4f6b0c78175..99e9d1de988 100644 --- a/subsys/bluetooth/host/l2cap.c +++ b/subsys/bluetooth/host/l2cap.c @@ -99,6 +99,20 @@ static void free_tx_meta_data(struct l2cap_tx_meta_data *data) static sys_slist_t servers; +static void l2cap_tx_buf_destroy(struct bt_conn *conn, struct net_buf *buf, int err) +{ + struct l2cap_tx_meta_data *data = l2cap_tx_meta_data(buf); + bt_conn_tx_cb_t cb = data->cb; + void *cb_user_data = data->user_data; + + free_tx_meta_data(data); + net_buf_unref(buf); + + /* Make sure to call associated callback, if any */ + if (cb) { + cb(conn, cb_user_data, err); + } +} #endif /* CONFIG_BT_L2CAP_DYNAMIC_CHANNEL */ /* L2CAP signalling channel specific context */ @@ -933,7 +947,7 @@ static void l2cap_chan_tx_process(struct k_work *work) */ k_work_schedule(&ch->tx_work, K_MSEC(CONFIG_BT_L2CAP_RESCHED_MS)); } else { - net_buf_unref(buf); + l2cap_tx_buf_destroy(ch->chan.conn, buf, sent); } break; } @@ -984,13 +998,13 @@ static void l2cap_chan_destroy(struct bt_l2cap_chan *chan) } if (le_chan->tx_buf) { - net_buf_unref(le_chan->tx_buf); + l2cap_tx_buf_destroy(chan->conn, le_chan->tx_buf, -ESHUTDOWN); le_chan->tx_buf = NULL; } /* Remove buffers on the TX queue */ while ((buf = net_buf_get(&le_chan->tx_queue, K_NO_WAIT))) { - net_buf_unref(buf); + l2cap_tx_buf_destroy(chan->conn, buf, -ESHUTDOWN); } /* Remove buffers on the RX queue */ @@ -1910,6 +1924,9 @@ static void l2cap_chan_sdu_sent(struct bt_conn *conn, void *user_data, int err) chan = bt_l2cap_le_lookup_tx_cid(conn, cid); if (!chan) { /* Received SDU sent callback for disconnected channel */ + if (cb) { + cb(conn, cb_user_data, -ESHUTDOWN); + } return; } @@ -2257,13 +2274,13 @@ static void l2cap_chan_shutdown(struct bt_l2cap_chan *chan) /* Cleanup outstanding request */ if (le_chan->tx_buf) { - net_buf_unref(le_chan->tx_buf); + l2cap_tx_buf_destroy(chan->conn, le_chan->tx_buf, -ESHUTDOWN); le_chan->tx_buf = NULL; } /* Remove buffers on the TX queue */ while ((buf = net_buf_get(&le_chan->tx_queue, K_NO_WAIT))) { - net_buf_unref(buf); + l2cap_tx_buf_destroy(chan->conn, buf, -ESHUTDOWN); } /* Remove buffers on the RX queue */ From afd2e9561c08fa691a712ca25ecfb68ffe526334 Mon Sep 17 00:00:00 2001 From: Robert Lubos Date: Thu, 23 Nov 2023 12:26:13 +0100 Subject: [PATCH 0365/3723] net: tls_credentials: Add missing include dir for PSA API Protected credential storage makes use of the PSA API, therefore it must be present in the library include path. This was missed during the recent CMakeLists.txt rework of this library. Signed-off-by: Robert Lubos --- subsys/net/lib/tls_credentials/CMakeLists.txt | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/subsys/net/lib/tls_credentials/CMakeLists.txt b/subsys/net/lib/tls_credentials/CMakeLists.txt index 490a558953d..9a605e0832b 100644 --- a/subsys/net/lib/tls_credentials/CMakeLists.txt +++ b/subsys/net/lib/tls_credentials/CMakeLists.txt @@ -15,3 +15,9 @@ zephyr_library_sources_ifdef(CONFIG_TLS_CREDENTIALS_SHELL ) zephyr_library_link_libraries_ifdef(CONFIG_MBEDTLS mbedTLS) + +if (CONFIG_TLS_CREDENTIALS_BACKEND_PROTECTED_STORAGE AND CONFIG_BUILD_WITH_TFM) + target_include_directories(${ZEPHYR_CURRENT_LIBRARY} PRIVATE + $/install/interface/include + ) +endif() From 903f6281ace3f58adc96d26d04cbae212c3968bb Mon Sep 17 00:00:00 2001 From: Christopher Friedt Date: Wed, 4 Oct 2023 13:46:54 -0400 Subject: [PATCH 0366/3723] iterable_sections: define iterable_named_alternate variant Add STRUCT_SECTION_ITERABLE_NAMED_ALTERNATE() for structures ordered by name in a custom section. Signed-off-by: Christopher Friedt --- include/zephyr/sys/iterable_sections.h | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/include/zephyr/sys/iterable_sections.h b/include/zephyr/sys/iterable_sections.h index fe1976363ca..3ec4af5e9a0 100644 --- a/include/zephyr/sys/iterable_sections.h +++ b/include/zephyr/sys/iterable_sections.h @@ -234,6 +234,16 @@ extern "C" { #define STRUCT_SECTION_ITERABLE_NAMED(struct_type, name, varname) \ TYPE_SECTION_ITERABLE(struct struct_type, varname, struct_type, name) +/** + * @brief Defines a new element for an iterable section with a custom name, + * placed in a custom section. + * + * The name can be used to customize how iterable section entries are sorted. + * @see STRUCT_SECTION_ITERABLE_NAMED() + */ +#define STRUCT_SECTION_ITERABLE_NAMED_ALTERNATE(struct_type, secname, name, varname) \ + TYPE_SECTION_ITERABLE(struct struct_type, varname, secname, name) + /** * @brief Iterate over a specified iterable section (alternate). * From 28dccf236b2e34ad8567db2bf708f472e02ce8ee Mon Sep 17 00:00:00 2001 From: Christopher Friedt Date: Wed, 4 Oct 2023 13:40:29 -0400 Subject: [PATCH 0367/3723] tests: misc: iterable_sections: add named alternate tests Add tests for the newly added STRUCT_SECTION_ITERABLE_NAMED_ALTERNATE(). This type of section should be iterated with STRUCT_SECTION_FOREACH_ALTERNATE(). Signed-off-by: Christopher Friedt --- tests/misc/iterable_sections/CMakeLists.txt | 2 ++ tests/misc/iterable_sections/sections-ram.ld | 1 + tests/misc/iterable_sections/sections-rom.ld | 1 + tests/misc/iterable_sections/src/main.c | 24 ++++++++++++++++++++ 4 files changed, 28 insertions(+) diff --git a/tests/misc/iterable_sections/CMakeLists.txt b/tests/misc/iterable_sections/CMakeLists.txt index 24472eb8574..1a187eace6d 100644 --- a/tests/misc/iterable_sections/CMakeLists.txt +++ b/tests/misc/iterable_sections/CMakeLists.txt @@ -12,9 +12,11 @@ zephyr_iterable_section(NAME test_ram GROUP DATA_REGION ${XIP_ALIGN_WITH_INPUT} zephyr_iterable_section(NAME test_ram2 GROUP DATA_REGION ${XIP_ALIGN_WITH_INPUT} SUBALIGN 4) zephyr_iterable_section(NAME test_ram_named GROUP DATA_REGION ${XIP_ALIGN_WITH_INPUT} SUBALIGN 4) zephyr_iterable_section(NAME test_ram_numeric NUMERIC GROUP DATA_REGION ${XIP_ALIGN_WITH_INPUT} SUBALIGN 4) +zephyr_iterable_section(NAME ramn_alt GROUP DATA_REGION ${XIP_ALIGN_WITH_INPUT} SUBALIGN 4) zephyr_linker_sources(SECTIONS sections-rom.ld) zephyr_iterable_section(NAME test_rom KVMA RAM_REGION GROUP RODATA_REGION SUBALIGN 4) zephyr_iterable_section(NAME test_rom2 KVMA RAM_REGION GROUP RODATA_REGION SUBALIGN 4) zephyr_iterable_section(NAME test_rom_named KVMA RAM_REGION GROUP RODATA_REGION SUBALIGN 4) zephyr_iterable_section(NAME test_rom_numeric NUMERIC KVMA RAM_REGION GROUP RODATA_REGION SUBALIGN 4) +zephyr_iterable_section(NAME romn_alt KVMA RAM_REGION GROUP RODATA_REGION SUBALIGN 4) diff --git a/tests/misc/iterable_sections/sections-ram.ld b/tests/misc/iterable_sections/sections-ram.ld index c7c86a8d97c..96454fb282d 100644 --- a/tests/misc/iterable_sections/sections-ram.ld +++ b/tests/misc/iterable_sections/sections-ram.ld @@ -4,3 +4,4 @@ ITERABLE_SECTION_RAM(test_ram, 4) ITERABLE_SECTION_RAM(test_ram2, 4) ITERABLE_SECTION_RAM(test_ram_named, 4) ITERABLE_SECTION_RAM_NUMERIC(test_ram_numeric, 4) +ITERABLE_SECTION_RAM(ramn_alt, 4) diff --git a/tests/misc/iterable_sections/sections-rom.ld b/tests/misc/iterable_sections/sections-rom.ld index c837cbfbc4b..525c480c7bf 100644 --- a/tests/misc/iterable_sections/sections-rom.ld +++ b/tests/misc/iterable_sections/sections-rom.ld @@ -4,3 +4,4 @@ ITERABLE_SECTION_ROM(test_rom, 4) ITERABLE_SECTION_ROM(test_rom2, 4) ITERABLE_SECTION_ROM(test_rom_named, 4) ITERABLE_SECTION_ROM_NUMERIC(test_rom_numeric, 4) +ITERABLE_SECTION_ROM(romn_alt, 4) diff --git a/tests/misc/iterable_sections/src/main.c b/tests/misc/iterable_sections/src/main.c index e5d697b8a80..a2dde51bd23 100644 --- a/tests/misc/iterable_sections/src/main.c +++ b/tests/misc/iterable_sections/src/main.c @@ -44,6 +44,12 @@ const STRUCT_SECTION_ITERABLE(test_ram_numeric, ramn_10) = {0x03}; const STRUCT_SECTION_ITERABLE(test_ram_numeric, ramn_11) = {0x04}; const STRUCT_SECTION_ITERABLE(test_ram_numeric, ramn_3) = {0x02}; +#define NAMED_ALT_EXPECT 0x4273 + +/* alternate naming */ +const STRUCT_SECTION_ITERABLE_NAMED_ALTERNATE(test_ram_named, ramn_alt, R, ramn_42) = {0x42}; +const STRUCT_SECTION_ITERABLE_NAMED_ALTERNATE(test_ram_named, ramn_alt, W, ramn_73) = {0x73}; + /** * * @brief Test iterable in read write section. @@ -89,6 +95,13 @@ ZTEST(iterable_sections, test_ram) } zassert_equal(out, RAM_EXPECT, "Check value incorrect (got: 0x%x)", out); + + out = 0; + STRUCT_SECTION_FOREACH_ALTERNATE(ramn_alt, test_ram_named, t) { + out = (out << 8) | t->i; + } + + zassert_equal(out, NAMED_ALT_EXPECT, "Check value incorrect (got: 0x%x)", out); } struct test_rom { @@ -126,6 +139,10 @@ const STRUCT_SECTION_ITERABLE(test_rom_numeric, romn_10) = {0x30}; const STRUCT_SECTION_ITERABLE(test_rom_numeric, romn_11) = {0x40}; const STRUCT_SECTION_ITERABLE(test_rom_numeric, romn_3) = {0x20}; +/* alternate naming */ +const STRUCT_SECTION_ITERABLE_NAMED_ALTERNATE(test_rom_named, romn_alt, R, romn_73) = {0x73}; +const STRUCT_SECTION_ITERABLE_NAMED_ALTERNATE(test_rom_named, romn_alt, O, romn_42) = {0x42}; + /** * * @brief Test iterable in read only section. @@ -161,6 +178,13 @@ ZTEST(iterable_sections, test_rom) } zassert_equal(out, ROM_EXPECT, "Check value incorrect (got: 0x%x)", out); + + out = 0; + STRUCT_SECTION_FOREACH_ALTERNATE(romn_alt, test_rom_named, t) { + out = (out << 8) | t->i; + } + + zassert_equal(out, NAMED_ALT_EXPECT, "Check value incorrect (got: 0x%x)", out); } ZTEST_SUITE(iterable_sections, NULL, NULL, NULL, NULL, NULL); From afc59112a96c884abf39100b06e89bde4effea29 Mon Sep 17 00:00:00 2001 From: Christopher Friedt Date: Fri, 22 Sep 2023 15:08:11 -0400 Subject: [PATCH 0368/3723] device: support for mutable devices Add support for mutable devices. Mutable devices are those which can be modified after declaration, in-place, in kernel mode. In order for a device to be mutable, the following must be true * `CONFIG_DEVICE_MUTABLE` must be y-selected * the Devicetree bindings for the device must include `mutable.yaml` * the Devicetree node must include the `zephyr,mutable` property Signed-off-by: Christopher Friedt --- cmake/linker_script/common/common-ram.cmake | 4 +++ dts/bindings/base/mutable.yaml | 13 +++++++ include/zephyr/device.h | 40 ++++++++++++--------- include/zephyr/init.h | 18 +++++++++- include/zephyr/linker/common-ram.ld | 4 +++ kernel/Kconfig | 7 ++++ 6 files changed, 68 insertions(+), 18 deletions(-) create mode 100644 dts/bindings/base/mutable.yaml diff --git a/cmake/linker_script/common/common-ram.cmake b/cmake/linker_script/common/common-ram.cmake index a116977ce8c..7e639043bce 100644 --- a/cmake/linker_script/common/common-ram.cmake +++ b/cmake/linker_script/common/common-ram.cmake @@ -128,3 +128,7 @@ if(CONFIG_USB_HOST_STACK) zephyr_iterable_section(NAME usbh_contex GROUP DATA_REGION ${XIP_ALIGN_WITH_INPUT} SUBALIGN 4) zephyr_iterable_section(NAME usbh_class_data GROUP DATA_REGION ${XIP_ALIGN_WITH_INPUT} SUBALIGN 4) endif() + +if(CONFIG_DEVICE_MUTABLE) + zephyr_iterable_section(NAME device_mutable GROUP DATA_REGION ${XIP_ALIGN_WITH_INPUT} SUBALIGN 4) +endif() diff --git a/dts/bindings/base/mutable.yaml b/dts/bindings/base/mutable.yaml new file mode 100644 index 00000000000..0e2d1cad3b0 --- /dev/null +++ b/dts/bindings/base/mutable.yaml @@ -0,0 +1,13 @@ +# Copyright (c) 2023, Meta +# SPDX-License-Identifier: Apache-2.0 + +# Properties for Mutable devices + +properties: + zephyr,mutable: + type: boolean + description: | + True iff the device structure may be mutated. + + Inherit this binding for devices that are runtime-modifiable, in-place. + This places the device structure into SRAM rather than Flash. diff --git a/include/zephyr/device.h b/include/zephyr/device.h index 630a059c155..77c0537ffdf 100644 --- a/include/zephyr/device.h +++ b/include/zephyr/device.h @@ -41,6 +41,10 @@ extern "C" { */ #define Z_DEVICE_DEPS_ENDS INT16_MAX +/** @brief Determine if a DT node is mutable */ +#define Z_DEVICE_IS_MUTABLE(node_id) \ + COND_CODE_1(IS_ENABLED(CONFIG_DEVICE_MUTABLE), (DT_PROP(node_id, zephyr_mutable)), (0)) + /** @endcond */ /** @@ -924,12 +928,13 @@ static inline bool z_impl_device_is_ready(const struct device *dev) * @param api Reference to device API. * @param ... Optional dependencies, manually specified. */ -#define Z_DEVICE_BASE_DEFINE(node_id, dev_id, name, pm, data, config, level, \ - prio, api, state, deps) \ - COND_CODE_1(DT_NODE_EXISTS(node_id), (), (static)) \ - const STRUCT_SECTION_ITERABLE_NAMED(device, \ - Z_DEVICE_SECTION_NAME(level, prio), \ - DEVICE_NAME_GET(dev_id)) = \ +#define Z_DEVICE_BASE_DEFINE(node_id, dev_id, name, pm, data, config, level, prio, api, state, \ + deps) \ + COND_CODE_1(DT_NODE_EXISTS(node_id), (), (static)) \ + COND_CODE_1(Z_DEVICE_IS_MUTABLE(node_id), (), (const)) \ + STRUCT_SECTION_ITERABLE_NAMED_ALTERNATE( \ + device, COND_CODE_1(Z_DEVICE_IS_MUTABLE(node_id), (device_mutable), (device)), \ + Z_DEVICE_SECTION_NAME(level, prio), DEVICE_NAME_GET(dev_id)) = \ Z_DEVICE_INIT(name, pm, data, config, api, state, deps) /* deprecated device initialization levels */ @@ -961,15 +966,15 @@ static inline bool z_impl_device_is_ready(const struct device *dev) * @param level Initialization level. * @param prio Initialization priority. */ -#define Z_DEVICE_INIT_ENTRY_DEFINE(node_id, dev_id, init_fn_, level, prio) \ - Z_DEVICE_LEVEL_CHECK_DEPRECATED_LEVEL(level) \ - \ - static const Z_DECL_ALIGN(struct init_entry) __used __noasan \ - Z_INIT_ENTRY_SECTION(level, prio, \ - Z_DEVICE_INIT_SUB_PRIO(node_id)) \ - Z_INIT_ENTRY_NAME(DEVICE_NAME_GET(dev_id)) = { \ - .init_fn = {.dev = (init_fn_)}, \ - .dev = &DEVICE_NAME_GET(dev_id), \ +#define Z_DEVICE_INIT_ENTRY_DEFINE(node_id, dev_id, init_fn_, level, prio) \ + Z_DEVICE_LEVEL_CHECK_DEPRECATED_LEVEL(level) \ + \ + static const Z_DECL_ALIGN(struct init_entry) __used __noasan Z_INIT_ENTRY_SECTION( \ + level, prio, Z_DEVICE_INIT_SUB_PRIO(node_id)) \ + Z_INIT_ENTRY_NAME(DEVICE_NAME_GET(dev_id)) = { \ + .init_fn = {COND_CODE_1(Z_DEVICE_IS_MUTABLE(node_id), (.dev_rw), (.dev)) = \ + (init_fn_)}, \ + .dev = &DEVICE_NAME_GET(dev_id), \ } /** @@ -1015,8 +1020,9 @@ static inline bool z_impl_device_is_ready(const struct device *dev) * don't have a corresponding @ref device allocated. There's no way to figure * that out until after we've built the zephyr image, though. */ -#define Z_MAYBE_DEVICE_DECLARE_INTERNAL(node_id) \ - extern const struct device DEVICE_DT_NAME_GET(node_id); +#define Z_MAYBE_DEVICE_DECLARE_INTERNAL(node_id) \ + extern COND_CODE_1(Z_DEVICE_IS_MUTABLE(node_id), (), \ + (const)) struct device DEVICE_DT_NAME_GET(node_id); DT_FOREACH_STATUS_OKAY_NODE(Z_MAYBE_DEVICE_DECLARE_INTERNAL) diff --git a/include/zephyr/init.h b/include/zephyr/init.h index 9b0d2993d62..7882b207b8d 100644 --- a/include/zephyr/init.h +++ b/include/zephyr/init.h @@ -73,6 +73,17 @@ union init_function { * @retval -errno If device initialization fails. */ int (*dev)(const struct device *dev); +#ifdef CONFIG_DEVICE_MUTABLE + /** + * Device initialization function (rw). + * + * @param dev Device instance. + * + * @retval 0 On success + * @retval -errno If device initialization fails. + */ + int (*dev_rw)(struct device *dev); +#endif }; /** @@ -96,7 +107,12 @@ struct init_entry { * If the init entry belongs to a device, this fields stores a * reference to it, otherwise it is set to NULL. */ - const struct device *dev; + union { + const struct device *dev; +#ifdef CONFIG_DEVICE_MUTABLE + struct device *dev_rw; +#endif + }; }; /** @cond INTERNAL_HIDDEN */ diff --git a/include/zephyr/linker/common-ram.ld b/include/zephyr/linker/common-ram.ld index c03351abf98..7bb6e55f1c1 100644 --- a/include/zephyr/linker/common-ram.ld +++ b/include/zephyr/linker/common-ram.ld @@ -137,6 +137,10 @@ ITERABLE_SECTION_RAM(zbus_channel_observation_mask, 1) #endif /* CONFIG_ZBUS */ +#if defined(CONFIG_DEVICE_MUTABLE) + ITERABLE_SECTION_RAM(device_mutable, 4) +#endif + #ifdef CONFIG_USERSPACE _static_kernel_objects_end = .; #endif diff --git a/kernel/Kconfig b/kernel/Kconfig index 4a72d76da67..bd157d8bcc7 100644 --- a/kernel/Kconfig +++ b/kernel/Kconfig @@ -1274,6 +1274,13 @@ config DEVICE_DEPS_DYNAMIC Option that makes it possible to manipulate device dependencies at runtime. +config DEVICE_MUTABLE + bool "Mutable devices [EXPERIMENTAL]" + select EXPERIMENTAL + help + Support mutable devices. Mutable devices are instantiated in SRAM + instead of Flash and are runtime modifiable in kernel mode. + endmenu rsource "Kconfig.vm" From 37e19451ec2d8cf3e48edb6c8bf9333cb796ab6c Mon Sep 17 00:00:00 2001 From: Christopher Friedt Date: Fri, 22 Sep 2023 15:26:11 -0400 Subject: [PATCH 0369/3723] drivers: misc: devmux: a device multiplexer pseudo-device The Device Multiplexer (devmux) is a pseudo-device that can be used to select between multiple included sub-devices. It is experimental, but its current use is in system remediation. Take for example, the scenario where the system console and log subsystem both have the uart backend enabled. The case may arise, where the chosen backing uart could be an abstraction of another very high-bandwidth bus - such as a PCIe BAR, a UDP socket, or even even just memory. If the "service" (for lack of a better term) that backs this abstract "uart" experiences an error, it is of critical importance to be able to switch the system console, uart log backend, or whatever to another uart (semi-transparently) in order to bring up a shell, continue to view system logs, or even just support user console I/O. Signed-off-by: Christopher Friedt --- drivers/misc/CMakeLists.txt | 1 + drivers/misc/Kconfig | 1 + drivers/misc/devmux/CMakeLists.txt | 10 ++ drivers/misc/devmux/Kconfig | 23 +++ drivers/misc/devmux/devmux.c | 179 ++++++++++++++++++++ dts/bindings/misc/zephyr,devmux.yaml | 33 ++++ include/zephyr/drivers/misc/devmux/devmux.h | 90 ++++++++++ 7 files changed, 337 insertions(+) create mode 100644 drivers/misc/devmux/CMakeLists.txt create mode 100644 drivers/misc/devmux/Kconfig create mode 100644 drivers/misc/devmux/devmux.c create mode 100644 dts/bindings/misc/zephyr,devmux.yaml create mode 100644 include/zephyr/drivers/misc/devmux/devmux.h diff --git a/drivers/misc/CMakeLists.txt b/drivers/misc/CMakeLists.txt index 863f839184e..6c4ec2384d9 100644 --- a/drivers/misc/CMakeLists.txt +++ b/drivers/misc/CMakeLists.txt @@ -6,3 +6,4 @@ add_subdirectory_ifdef(CONFIG_GROVE_LCD_RGB grove_lcd_rgb) add_subdirectory_ifdef(CONFIG_PIO_RPI_PICO pio_rpi_pico) add_subdirectory_ifdef(CONFIG_NXP_S32_EMIOS nxp_s32_emios) add_subdirectory_ifdef(CONFIG_TIMEAWARE_GPIO timeaware_gpio) +add_subdirectory_ifdef(CONFIG_DEVMUX devmux) diff --git a/drivers/misc/Kconfig b/drivers/misc/Kconfig index 66d83fc693d..52c77b4c7ec 100644 --- a/drivers/misc/Kconfig +++ b/drivers/misc/Kconfig @@ -10,5 +10,6 @@ source "drivers/misc/grove_lcd_rgb/Kconfig" source "drivers/misc/pio_rpi_pico/Kconfig" source "drivers/misc/nxp_s32_emios/Kconfig" source "drivers/misc/timeaware_gpio/Kconfig" +source "drivers/misc/devmux/Kconfig" endmenu diff --git a/drivers/misc/devmux/CMakeLists.txt b/drivers/misc/devmux/CMakeLists.txt new file mode 100644 index 00000000000..94f74ea57ce --- /dev/null +++ b/drivers/misc/devmux/CMakeLists.txt @@ -0,0 +1,10 @@ +# Copyright (c) 2023, Meta +# SPDX-License-Identifier: Apache-2.0 + +zephyr_library() + +zephyr_syscall_header( + ${ZEPHYR_BASE}/include/zephyr/drivers/misc/devmux/devmux.h +) + +zephyr_library_sources(devmux.c) diff --git a/drivers/misc/devmux/Kconfig b/drivers/misc/devmux/Kconfig new file mode 100644 index 00000000000..4f848b4e06c --- /dev/null +++ b/drivers/misc/devmux/Kconfig @@ -0,0 +1,23 @@ +# Copyright (c) 2023, Meta +# SPDX-License-Identifier: Apache-2.0 + +config DEVMUX + bool "Device Multiplexer (devmux) [EXPERIMENTAL]" + depends on DT_HAS_ZEPHYR_DEVMUX_ENABLED + depends on DEVICE_MUTABLE + select EXPERIMENTAL + help + Devmux is a pseudo-device that operates as a device switch. It allows + software to select the data, config, and api from a number of linked + devices. + +if DEVMUX + +config DEVMUX_INIT_PRIORITY + int "Devmux init priority" + default 51 + help + Init priority for the devmux driver. It must be + greater than the priority of the initially selected muxed device. + +endif diff --git a/drivers/misc/devmux/devmux.c b/drivers/misc/devmux/devmux.c new file mode 100644 index 00000000000..653236f903d --- /dev/null +++ b/drivers/misc/devmux/devmux.c @@ -0,0 +1,179 @@ +/* + * Copyright (c) 2023, Meta + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#define DT_DRV_COMPAT zephyr_devmux + +#include +#include +#include +#include + +struct devmux_config { + const struct device **devs; + const size_t n_devs; +}; + +struct devmux_data { + struct k_spinlock lock; + size_t selected; +}; + +/* The number of devmux devices */ +#define N DT_NUM_INST_STATUS_OKAY(DT_DRV_COMPAT) + +static const struct device *devmux_devices[N]; +static const struct devmux_config *devmux_configs[N]; +static struct devmux_data *devmux_datas[N]; + +static bool devmux_device_is_valid(const struct device *dev) +{ + for (size_t i = 0; i < N; ++i) { + if (dev == devmux_devices[i]) { + return true; + } + } + + return false; +} + +static size_t devmux_inst_get(const struct device *dev) +{ + for (size_t i = 0; i < N; i++) { + if (dev == devmux_devices[i]) { + return i; + } + } + + return SIZE_MAX; +} + +const struct devmux_config *devmux_config_get(const struct device *dev) +{ + for (size_t i = 0; i < N; i++) { + if (dev == devmux_devices[i]) { + return devmux_configs[i]; + } + } + + return NULL; +} + +struct devmux_data *devmux_data_get(const struct device *dev) +{ + for (size_t i = 0; i < N; i++) { + if (dev == devmux_devices[i]) { + return devmux_datas[i]; + } + } + + return NULL; +} + +ssize_t z_impl_devmux_select_get(const struct device *dev) +{ + ssize_t index; + struct devmux_data *const data = devmux_data_get(dev); + + if (!devmux_device_is_valid(dev)) { + return -EINVAL; + } + + K_SPINLOCK(&data->lock) + { + index = data->selected; + } + + return index; +} + +#ifdef CONFIG_USERSPACE +ssize_t z_vrfy_devmux_select_get(const struct device *dev) +{ + return z_impl_devmux_select_get(dev); +} +#include +#endif + +int z_impl_devmux_select_set(struct device *dev, size_t index) +{ + struct devmux_data *const data = devmux_data_get(dev); + const struct devmux_config *config = devmux_config_get(dev); + + if (!devmux_device_is_valid(dev) || index >= config->n_devs) { + return -EINVAL; + } + + if (!device_is_ready(config->devs[index])) { + return -ENODEV; + } + + K_SPINLOCK(&data->lock) + { + *dev = *config->devs[index]; + data->selected = index; + } + + return 0; +} + +#ifdef CONFIG_USERSPACE +int z_vrfy_devmux_select_set(struct device *dev, size_t index) +{ + return z_impl_devmux_select_set(dev, index); +} +#include +#endif + +static int devmux_init(struct device *const dev) +{ + size_t inst = devmux_inst_get(dev); + struct devmux_data *const data = dev->data; + const struct devmux_config *config = dev->config; + size_t sel = data->selected; + + devmux_configs[inst] = config; + devmux_datas[inst] = data; + + if (!device_is_ready(config->devs[sel])) { + return -ENODEV; + } + + *dev = *config->devs[sel]; + + return 0; +} + +#define DEVMUX_PHANDLE_TO_DEVICE(node_id, prop, idx) \ + DEVICE_DT_GET(DT_PHANDLE_BY_IDX(node_id, prop, idx)) + +#define DEVMUX_PHANDLE_DEVICES(_n) \ + DT_INST_FOREACH_PROP_ELEM_SEP(_n, devices, DEVMUX_PHANDLE_TO_DEVICE, (,)) + +#define DEVMUX_SELECTED(_n) DT_INST_PROP(_n, selected) + +#define DEVMUX_DEFINE(_n) \ + BUILD_ASSERT(DT_INST_PROP_OR(_n, zephyr_mutable, 0), \ + "devmux nodes must contain the 'zephyr,mutable' property"); \ + BUILD_ASSERT(DT_INST_PROP_LEN(_n, devices) > 0, "devices array must have non-zero size"); \ + BUILD_ASSERT(DEVMUX_SELECTED(_n) >= 0, "selected must be > 0"); \ + BUILD_ASSERT(DEVMUX_SELECTED(_n) < DT_INST_PROP_LEN(_n, devices), \ + "selected must be within bounds of devices phandle array"); \ + static const struct device *demux_devs_##_n[] = {DEVMUX_PHANDLE_DEVICES(_n)}; \ + static const struct devmux_config devmux_config_##_n = { \ + .devs = demux_devs_##_n, \ + .n_devs = DT_INST_PROP_LEN(_n, devices), \ + }; \ + static struct devmux_data devmux_data_##_n = { \ + .selected = DEVMUX_SELECTED(_n), \ + }; \ + \ + DEVICE_DT_INST_DEFINE(_n, devmux_init, NULL, &devmux_data_##_n, &devmux_config_##_n, \ + PRE_KERNEL_1, CONFIG_DEVMUX_INIT_PRIORITY, NULL); + +DT_INST_FOREACH_STATUS_OKAY(DEVMUX_DEFINE) + +#define DEVMUX_DEVICE_GET(_n) DEVICE_DT_INST_GET(_n), +static const struct device *devmux_devices[] = {DT_INST_FOREACH_STATUS_OKAY(DEVMUX_DEVICE_GET)}; diff --git a/dts/bindings/misc/zephyr,devmux.yaml b/dts/bindings/misc/zephyr,devmux.yaml new file mode 100644 index 00000000000..744daaca120 --- /dev/null +++ b/dts/bindings/misc/zephyr,devmux.yaml @@ -0,0 +1,33 @@ +# Copyright (c) 2023, Meta +# SPDX-License-Identifier: Apache-2.0 + +description: Generic Device Multiplexer + +compatible: "zephyr,devmux" + +include: [base.yaml, mutable.yaml] + +properties: + + devices: + type: phandles + required: true + description: | + Devices to be multiplexed. + + selected: + type: int + default: 0 + description: | + Initial multiplexer selection. + + This must be in the range [0, N-1], where N is the length of the + 'devices' phandle list. + + If unspecified, the default selection is zero in order to ensure that + the multiplexer is ready for use (i.e. one of the [0, N-1] multiplexed + devices is selected). Zero is, necessarily, the only possible valid + default value since the phandle list must have length >= 1. + + Note: Specifying a value of 'selected' outside the range [0, N-1] + results in a compile-time error. diff --git a/include/zephyr/drivers/misc/devmux/devmux.h b/include/zephyr/drivers/misc/devmux/devmux.h new file mode 100644 index 00000000000..1772d719d96 --- /dev/null +++ b/include/zephyr/drivers/misc/devmux/devmux.h @@ -0,0 +1,90 @@ +/* + * Copyright (c) 2023, Meta + * + * SPDX-License-Identifier: Apache-2.0 + */ + +/** + * @file + * @brief Public APIs for the Device Multiplexer driver + */ + +#ifndef INCLUDE_ZEPHYR_DRIVERS_MISC_DEVMUX_H_ +#define INCLUDE_ZEPHYR_DRIVERS_MISC_DEVMUX_H_ + +#include + +#include +#include + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * @brief Devmux Driver APIs + * @defgroup demux_interface Devmux Driver APIs + * @ingroup misc_interfaces + * + * @details + * Devmux operates as a device multiplexer, forwarding the characteristics of + * the selected device. + * + * ``` + * +----------+ +----------+ + * | devmux | | devmux | + * | | | | + * dev0 | | dev0 | | + * +----------> \ | +----------> | + * | \ | | | + * dev1 | \ | dev0 dev1 | | dev2 + * +----------> O +----------> +----------> O +----------> + * | | | / | + * dev2 | | dev2 | / | + * +----------> | +----------> / | + * | | | | + * | | | | + * | | | | + * +-----^----+ +-----^----+ + * | | + * select == 0 | select == 2 | + * +--------------+ +---------------+ + * ``` + * @{ + */ + +/** + * @brief Get the current selection of a devmux device. + * + * Return the index of the currently selected device. + * + * @param dev the devmux device + * @return The index (>= 0) of the currently active multiplexed device on success + * @retval -EINVAL If @p dev is invalid + */ +__syscall ssize_t devmux_select_get(const struct device *dev); + +/** + * @brief Set the selection of a devmux device. + * + * Select the device at @p index. + * + * @param[in] dev the devmux device + * @param index the index representing the desired selection + * @retval 0 On success + * @retval -EINVAL If @p dev is invalid + * @retval -ENODEV If the multiplexed device at @p index is not ready + */ +__syscall int devmux_select_set(struct device *dev, size_t index); + +/** + * @} + */ + +#ifdef __cplusplus +} +#endif + +#include + +#endif /* INCLUDE_ZEPHYR_DRIVERS_MISC_DEVMUX_H_ */ From b13ec704d0dcb3cb2d99f8c7236b4baa13833639 Mon Sep 17 00:00:00 2001 From: Christopher Friedt Date: Fri, 22 Sep 2023 15:36:43 -0400 Subject: [PATCH 0370/3723] tests: drivers: console: add console_switching test This testsuite exercises a number of things. Namely * `mutable` devices (i.e. those backed in SRAM) * `uart_emul` support for interrupt mode (receive only) * `devmux` capabilities of multiplexing several uarts * switching the system console between several uart backends Testing Done: ``` west build -p auto -b qemu_riscv64 -t run \ tests/drivers/console_switching/ ... *** Booting Zephyr OS build zephyr-v3.4.0-3988-gaaefb2d764ea *** Running TESTSUITE console_switching ================================================================ START - test_read read "Hello, uart_emul0!" from uart_emul0 read "Hello, uart_emul1!" from uart_emul1 read "Hello, uart_emul0!" from uart_emul0 read "Hello, uart_emul1!" from uart_emul1 PASS - test_read in 0.005 seconds ================================================================ START - test_write wrote "Hello, uart_emul0!" to uart_emul0 wrote "Hello, uart_emul1!" to uart_emul1 wrote "Hello, uart_emul0!" to uart_emul0 wrote "Hello, uart_emul1!" to uart_emul1 PASS - test_write in 0.003 seconds ================================================================ TESTSUITE console_switching succeeded ------ TESTSUITE SUMMARY START ------ SUITE PASS - 100.00% [console_switching]: pass = 2, fail = 0,... - PASS - [console_switching.test_read] duration = 0.005 seconds - PASS - [console_switching.test_write] duration = 0.003 seconds ------ TESTSUITE SUMMARY END ------ =============================================================== PROJECT EXECUTION SUCCESSFUL ``` Signed-off-by: Christopher Friedt --- .../drivers/console_switching/CMakeLists.txt | 9 ++ .../boards/qemu_riscv64.overlay | 39 ++++++ tests/drivers/console_switching/prj.conf | 9 ++ tests/drivers/console_switching/src/main.c | 124 ++++++++++++++++++ tests/drivers/console_switching/testcase.yaml | 16 +++ 5 files changed, 197 insertions(+) create mode 100644 tests/drivers/console_switching/CMakeLists.txt create mode 100644 tests/drivers/console_switching/boards/qemu_riscv64.overlay create mode 100644 tests/drivers/console_switching/prj.conf create mode 100644 tests/drivers/console_switching/src/main.c create mode 100644 tests/drivers/console_switching/testcase.yaml diff --git a/tests/drivers/console_switching/CMakeLists.txt b/tests/drivers/console_switching/CMakeLists.txt new file mode 100644 index 00000000000..3ba70cc081e --- /dev/null +++ b/tests/drivers/console_switching/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(uart_console_switching) + +target_sources(app PRIVATE + src/main.c + ) diff --git a/tests/drivers/console_switching/boards/qemu_riscv64.overlay b/tests/drivers/console_switching/boards/qemu_riscv64.overlay new file mode 100644 index 00000000000..47bd7945189 --- /dev/null +++ b/tests/drivers/console_switching/boards/qemu_riscv64.overlay @@ -0,0 +1,39 @@ +/* + * Copyright (c) 2023, Meta + * + * SPDX-License-Identifier: Apache-2.0 + */ + +/ { + chosen { + zephyr,console = &devmux0; + zephyr,shell_uart = &devmux0; + }; + + euart0: uart_emul0 { + compatible = "zephyr,uart-emul"; + current-speed = <0>; + status = "okay"; + }; + + euart1: uart_emul1 { + compatible = "zephyr,uart-emul"; + current-speed = <0>; + status = "okay"; + }; + + devmux0: dev_mux_0 { + compatible = "zephyr,devmux"; + devices = <&uart0 &euart0 &euart1>; + zephyr,mutable; + status = "okay"; + }; + + devmux1: dev_mux_1 { + compatible = "zephyr,devmux"; + devices = <&uart0 &euart0 &euart1>; + zephyr,mutable; + selected = <2>; + status = "okay"; + }; +}; diff --git a/tests/drivers/console_switching/prj.conf b/tests/drivers/console_switching/prj.conf new file mode 100644 index 00000000000..fcdd67928c4 --- /dev/null +++ b/tests/drivers/console_switching/prj.conf @@ -0,0 +1,9 @@ +CONFIG_ZTEST=y +CONFIG_ZTEST_NEW_API=y +CONFIG_SERIAL=y +CONFIG_CONSOLE=y +CONFIG_CONSOLE_SUBSYS=y +CONFIG_CONSOLE_GETLINE=y +CONFIG_DEVICE_MUTABLE=y +CONFIG_DEVMUX=y +CONFIG_UART_EMUL=y diff --git a/tests/drivers/console_switching/src/main.c b/tests/drivers/console_switching/src/main.c new file mode 100644 index 00000000000..95cde150c9b --- /dev/null +++ b/tests/drivers/console_switching/src/main.c @@ -0,0 +1,124 @@ +/* + * Copyright (c) 2023, Meta + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include +#include +#include +#include +#include + +#define BUF_SIZE 32 + +/* array of const struct device* */ +#define PHANDLE_TO_DEVICE(node_id, prop, idx) DEVICE_DT_GET(DT_PHANDLE_BY_IDX(node_id, prop, idx)) +static const struct device *devs[] = { + DT_FOREACH_PROP_ELEM_SEP(DT_NODELABEL(devmux0), devices, PHANDLE_TO_DEVICE, (,))}; + +/* array of names, e.g. "euart0" */ +#define PHANDLE_TO_NAME(node_id, prop, idx) DT_NODE_FULL_NAME(DT_PHANDLE_BY_IDX(node_id, prop, idx)) +static const char *const name[] = { + DT_FOREACH_PROP_ELEM_SEP(DT_NODELABEL(devmux0), devices, PHANDLE_TO_NAME, (,))}; + +/* array of greetings, e.g. "Hello, euart0!" */ +#define PHANDLE_TO_TEXT(node_id, prop, idx) \ + "Hello, " DT_NODE_FULL_NAME(DT_PHANDLE_BY_IDX(node_id, prop, idx)) "!" +static const char *const text[] = { + DT_FOREACH_PROP_ELEM_SEP(DT_NODELABEL(devmux0), devices, PHANDLE_TO_TEXT, (,))}; + +ZTEST(console_switching, test_write) +{ + size_t normal_uart = DT_PROP(DT_NODELABEL(devmux0), selected); + struct device *const devmux_dev = DEVICE_DT_GET(DT_NODELABEL(devmux0)); + + /* for each uart_emul device */ + for (size_t i = 0, j = 0, N = ARRAY_SIZE(devs); i < 2 * N; i++, j++, j %= N) { + if (j == normal_uart) { + /* skip testing non-emul uart */ + continue; + } + + int ret[4]; + char buf[BUF_SIZE] = {0}; + + /* write text[j] to dev[j] */ + ret[0] = devmux_select_set(devmux_dev, j); + printk("%s", text[j]); + ret[1] = uart_emul_get_tx_data(devs[j], buf, ARRAY_SIZE(buf)); + ret[2] = devmux_select_set(devmux_dev, normal_uart); + + zassert_ok(ret[0], "Failed to select devmux %zu", j); + zassert_ok(ret[2], "Switching back to selection %zu failed", normal_uart); + + /* verify that text[j] was written to dev[j] */ + TC_PRINT("wrote '%s' to %s\n", buf, name[j]); + + zassert_equal(ret[1], strlen(text[j]), "Only wrote %zu/%zu bytes of '%s'", + ret[1], strlen(text[j]), text[j]); + zassert_equal(0, strcmp(text[j], buf), "Strings '%s' and '%s' do not match", + text[j], buf); + } +} + +ZTEST(console_switching, test_read) +{ + size_t normal_uart = DT_PROP(DT_NODELABEL(devmux0), selected); + struct device *const devmux_dev = DEVICE_DT_GET(DT_NODELABEL(devmux0)); + + /* for each uart_emul device */ + for (size_t i = 0, j = 0, N = ARRAY_SIZE(devs); i < 2 * N; i++, j++, j %= N) { + if (j == normal_uart) { + /* skip testing non-emul uart */ + continue; + } + + int ret[4]; + char buf[BUF_SIZE] = {0}; + + /* read text[j] from dev[j] */ + ret[0] = devmux_select_set(devmux_dev, j); + console_getline_init(); + ret[1] = uart_emul_put_rx_data(devs[j], (uint8_t *)text[j], strlen(text[j])); + ret[3] = uart_emul_put_rx_data(devs[j], "\n", 1); + snprintf(buf, BUF_SIZE, "%s", console_getline()); + ret[2] = devmux_select_set(devmux_dev, normal_uart); + + zassert_ok(ret[0], "Failed to select devmux %zu", j); + zassert_ok(ret[2], "Switching back to selection %zu failed", normal_uart); + + /* verify that text[j] was written to dev[j] */ + TC_PRINT("read '%s' from %s\n", buf, name[j]); + + zassert_equal(ret[1], strlen(text[j]), "Only put %zu/%zu bytes of '%s'", + ret[1], strlen(text[j]), text[j]); + zassert_equal(0, strcmp(text[j], buf), "Strings '%s' and '%s' do not match", + text[j], buf); + } +} + +static void *setup(void) +{ + size_t selected = DT_PROP(DT_NODELABEL(devmux1), selected); + struct device *const devmux_dev = DEVICE_DT_GET(DT_NODELABEL(devmux1)); + + /* ensure that non-default initial selection via DT works */ + zassert_equal(devmux_select_get(devmux_dev), selected); + + return NULL; +} + +static void before(void *arg) +{ + struct device *const devmux_dev = DEVICE_DT_GET(DT_NODELABEL(devmux0)); + + zassert_ok(devmux_select_set(devmux_dev, 0)); + zassert_ok(devmux_select_get(devmux_dev)); + + for (size_t i = 1; i < ARRAY_SIZE(devs); ++i) { + uart_emul_flush_tx_data(devs[i]); + } +} + +ZTEST_SUITE(console_switching, NULL, setup, before, NULL, NULL); diff --git a/tests/drivers/console_switching/testcase.yaml b/tests/drivers/console_switching/testcase.yaml new file mode 100644 index 00000000000..0d24b5e596e --- /dev/null +++ b/tests/drivers/console_switching/testcase.yaml @@ -0,0 +1,16 @@ +common: + tags: + - drivers + - console + - emul + platform_allow: + - qemu_riscv64 + integration_platforms: + - qemu_riscv64 + +tests: + drivers.console_switching: {} + drivers.console_switching.user: + tags: userspace + extra_configs: + - CONFIG_USERSPACE=y From 0670609bc6e805950352361fbbfa95526481b9d5 Mon Sep 17 00:00:00 2001 From: Fabio Baltieri Date: Tue, 28 Nov 2023 14:47:25 +0000 Subject: [PATCH 0371/3723] tests: console_switching: drop CONFIG_ZTEST_NEW_API The option is long gone, PR was sitting for a long time so this got merged and now it's failing compliance check. Signed-off-by: Fabio Baltieri --- tests/drivers/console_switching/prj.conf | 1 - 1 file changed, 1 deletion(-) diff --git a/tests/drivers/console_switching/prj.conf b/tests/drivers/console_switching/prj.conf index fcdd67928c4..0c30f023843 100644 --- a/tests/drivers/console_switching/prj.conf +++ b/tests/drivers/console_switching/prj.conf @@ -1,5 +1,4 @@ CONFIG_ZTEST=y -CONFIG_ZTEST_NEW_API=y CONFIG_SERIAL=y CONFIG_CONSOLE=y CONFIG_CONSOLE_SUBSYS=y From a157898098fc3e1e473280946c510e1588131054 Mon Sep 17 00:00:00 2001 From: Benjamin Perseghetti Date: Mon, 27 Nov 2023 23:50:05 -0500 Subject: [PATCH 0372/3723] mr_canhubk3: change SPI and WD_FS26 init priority Changes the FS26 watchdog init priority to avoid boot-looping. Requires SPI priority to be changed as well. Signed-off-by: Benjamin Perseghetti --- boards/arm/mr_canhubk3/Kconfig.defconfig | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/boards/arm/mr_canhubk3/Kconfig.defconfig b/boards/arm/mr_canhubk3/Kconfig.defconfig index e20f3cc3d6f..53e554da88f 100644 --- a/boards/arm/mr_canhubk3/Kconfig.defconfig +++ b/boards/arm/mr_canhubk3/Kconfig.defconfig @@ -13,6 +13,19 @@ config UART_CONSOLE endif # SERIAL +if SPI + +config SPI_INIT_PRIORITY + default 50 + +if WDT_NXP_FS26 + +config WDT_NXP_FS26_INIT_PRIORITY + default 51 + +endif # WDT_NXP_FS26 +endif # SPI + if CAN config GPIO From 163e9ba9a356e1a891dafd1c9c76449c3e4c913f Mon Sep 17 00:00:00 2001 From: Hake Huang Date: Mon, 27 Nov 2023 16:04:22 +0800 Subject: [PATCH 0373/3723] samples: disable usermode for ip_k66f in ip_k66f platfrom, we using rtt as debug port, which is conflicted with usermode. see below: warning: LOG_PRINTK (defined at subsys/logging/Kconfig.processing:8) has direct dependencies !USERSPACE && !LOG_MODE_MINIMAL && LOG with value n, but is currently being y-selected by the following symbols: - LOG_BACKEND_RTT_FORCE_PRINTK (defined at subsys/logging/backends/Kconfig.rtt:103), with value y, direct dependencies LOG_BACKEND_RTT && !LOG_FRONTEND_ONLY && !LOG_MODE_MINIMAL && LOG (value: y), and select condition LOG_BACKEND_RTT && !LOG_FRONTEND_ONLY && !LOG_MODE_MINIMAL && LOG (value: y) Signed-off-by: Hake Huang --- samples/net/sockets/net_mgmt/sample.yaml | 2 ++ 1 file changed, 2 insertions(+) diff --git a/samples/net/sockets/net_mgmt/sample.yaml b/samples/net/sockets/net_mgmt/sample.yaml index 7199cb2614a..337e8d08a75 100644 --- a/samples/net/sockets/net_mgmt/sample.yaml +++ b/samples/net/sockets/net_mgmt/sample.yaml @@ -17,3 +17,5 @@ tests: tags: userspace extra_configs: - CONFIG_USERSPACE=y + platform_exclude: + - ip_k66f From 776519075b0a4a1f6ab7c0fed7bf0b40dfc82184 Mon Sep 17 00:00:00 2001 From: Emilio Benavente Date: Tue, 29 Aug 2023 13:26:38 -0500 Subject: [PATCH 0374/3723] drivers: spi: Kconfig.mcux_lpspi: Added RTIO Kconfig for lpspi Added Kconfig that switches RTIO Support in the LPSPI driver. Signed-off-by: Emilio Benavente --- drivers/spi/Kconfig.mcux_lpspi | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/drivers/spi/Kconfig.mcux_lpspi b/drivers/spi/Kconfig.mcux_lpspi index 1b1cc4675fb..8f5a0a3bbd1 100644 --- a/drivers/spi/Kconfig.mcux_lpspi +++ b/drivers/spi/Kconfig.mcux_lpspi @@ -19,4 +19,18 @@ config SPI_MCUX_LPSPI_DMA help Enable the SPI DMA mode for SPI instances that enable dma channels in their device tree node. + +if SPI_RTIO +config SPI_MCUX_RTIO_SQ_SIZE + int "number of avialable submission queue entries" + default 8 # sensible default that covers most common spi transactions + help + when rtio is use with spi each driver holds a context with which blocking + api calls use to perform spi transactions. this queue needs to be as deep + as the longest set of spi_buf_sets used, where normal spi operations are + used (equal length buffers). it may need to be slightly deeper where the + spi buffer sets for transmit/receive are not always matched equally in + length as these are transformed into normal transceives. +endif # SPI_RTIO + endif # SPI_MCUX_LPSPI From 2f68ad7f892692b080833c9de22b9376c4f9bb7b Mon Sep 17 00:00:00 2001 From: Emilio Benavente Date: Tue, 29 Aug 2023 15:18:49 -0500 Subject: [PATCH 0375/3723] drivers: spi: spi_mcux_lpspi: Added RTIO Support for LPSPI Provided APIs to support RTIO with the LPSPI driver. Signed-off-by: Emilio Benavente --- drivers/spi/spi_mcux_lpspi.c | 185 ++++++++++++++++++++++++++++++++++- 1 file changed, 184 insertions(+), 1 deletion(-) diff --git a/drivers/spi/spi_mcux_lpspi.c b/drivers/spi/spi_mcux_lpspi.c index 9b230d1c53f..16d840992cc 100644 --- a/drivers/spi/spi_mcux_lpspi.c +++ b/drivers/spi/spi_mcux_lpspi.c @@ -16,6 +16,10 @@ #include #endif #include +#ifdef CONFIG_SPI_RTIO +#include +#include +#endif LOG_MODULE_REGISTER(spi_mcux_lpspi, CONFIG_SPI_LOG_LEVEL); @@ -56,6 +60,16 @@ struct spi_mcux_data { lpspi_master_handle_t handle; struct spi_context ctx; size_t transfer_len; + +#ifdef CONFIG_SPI_RTIO + struct rtio *r; + struct rtio_iodev iodev; + struct rtio_iodev_sqe *txn_head; + struct rtio_iodev_sqe *txn_curr; + struct spi_dt_spec dt_spec; + struct k_spinlock lock; +#endif + #ifdef CONFIG_SPI_MCUX_LPSPI_DMA volatile uint32_t status_flags; struct stream dma_rx; @@ -143,11 +157,21 @@ static void spi_mcux_isr(const struct device *dev) LPSPI_MasterTransferHandleIRQ(base, &data->handle); } +#ifdef CONFIG_SPI_RTIO +static void spi_mcux_iodev_complete(const struct device *dev, int status); +#endif + static void spi_mcux_master_transfer_callback(LPSPI_Type *base, lpspi_master_handle_t *handle, status_t status, void *userData) { struct spi_mcux_data *data = userData; +#ifdef CONFIG_SPI_RTIO + if (data->txn_head != NULL) { + spi_mcux_iodev_complete(data->dev, status); + return; + } +#endif spi_context_update_tx(&data->ctx, 1, data->transfer_len); spi_context_update_rx(&data->ctx, 1, data->transfer_len); @@ -642,6 +666,13 @@ static int spi_mcux_init(const struct device *dev) } #endif /* CONFIG_SPI_MCUX_LPSPI_DMA */ +#ifdef CONFIG_SPI_RTIO + data->dt_spec.bus = dev; + data->iodev.api = &spi_iodev_api; + data->iodev.data = &data->dt_spec; + rtio_mpsc_init(&data->iodev.iodev_sq); +#endif + err = pinctrl_apply_state(config->pincfg, PINCTRL_STATE_DEFAULT); if (err) { return err; @@ -652,14 +683,162 @@ static int spi_mcux_init(const struct device *dev) return 0; } +#ifdef CONFIG_SPI_RTIO +static inline k_spinlock_key_t spi_spin_lock(const struct device *dev) +{ + struct spi_mcux_data *data = dev->data; + + return k_spin_lock(&data->lock); +} + +static inline void spi_spin_unlock(const struct device *dev, k_spinlock_key_t key) +{ + struct spi_mcux_data *data = dev->data; + + k_spin_unlock(&data->lock, key); +} + + +static void spi_mcux_iodev_next(const struct device *dev, bool completion); + +static void spi_mcux_iodev_start(const struct device *dev) +{ + const struct spi_mcux_config *config = dev->config; + struct spi_mcux_data *data = dev->data; + struct rtio_sqe *sqe = &data->txn_curr->sqe; + struct spi_dt_spec *spi_dt_spec = sqe->iodev->data; + struct spi_config *spi_cfg = &spi_dt_spec->config; + struct rtio_iodev_sqe *txn_head = data->txn_head; + + LPSPI_Type *base = config->base; + lpspi_transfer_t transfer; + status_t status; + + transfer.configFlags = kLPSPI_MasterPcsContinuous | + (spi_cfg->slave << LPSPI_MASTER_PCS_SHIFT); + + switch (sqe->op) { + case RTIO_OP_RX: + transfer.txData = NULL; + transfer.rxData = sqe->buf; + transfer.dataSize = sqe->buf_len; + break; + case RTIO_OP_TX: + transfer.rxData = NULL; + transfer.txData = sqe->buf; + transfer.dataSize = sqe->buf_len; + break; + case RTIO_OP_TINY_TX: + transfer.rxData = NULL; + transfer.txData = sqe->tiny_buf; + transfer.dataSize = sqe->tiny_buf_len; + break; + case RTIO_OP_TXRX: + transfer.txData = sqe->tx_buf; + transfer.rxData = sqe->rx_buf; + transfer.dataSize = sqe->txrx_buf_len; + break; + default: + LOG_ERR("Invalid op code %d for submission %p\n", sqe->op, (void *)sqe); + + spi_mcux_iodev_next(dev, true); + rtio_iodev_sqe_err(txn_head, -EINVAL); + spi_mcux_iodev_complete(dev, 0); + return; + } + + data->transfer_len = transfer.dataSize; + + k_spinlock_key_t key = spi_spin_lock(dev); + + status = LPSPI_MasterTransferNonBlocking(base, &data->handle, + &transfer); + spi_spin_unlock(dev, key); + if (status != kStatus_Success) { + LOG_ERR("Transfer could not start"); + rtio_iodev_sqe_err(txn_head, -EIO); + } +} + +static void spi_mcux_iodev_next(const struct device *dev, bool completion) +{ + struct spi_mcux_data *data = dev->data; + + k_spinlock_key_t key = spi_spin_lock(dev); + + if (!completion && data->txn_curr != NULL) { + spi_spin_unlock(dev, key); + return; + } + + struct rtio_mpsc_node *next = rtio_mpsc_pop(&data->iodev.iodev_sq); + + if (next != NULL) { + struct rtio_iodev_sqe *next_sqe = CONTAINER_OF(next, struct rtio_iodev_sqe, q); + + data->txn_head = next_sqe; + data->txn_curr = next_sqe; + } else { + data->txn_head = NULL; + data->txn_curr = NULL; + } + + spi_spin_unlock(dev, key); + + if (data->txn_curr != NULL) { + struct spi_dt_spec *spi_dt_spec = data->txn_curr->sqe.iodev->data; + struct spi_config *spi_cfg = &spi_dt_spec->config; + + spi_mcux_configure(dev, spi_cfg); + spi_context_cs_control(&data->ctx, true); + spi_mcux_iodev_start(dev); + } +} + +static void spi_mcux_iodev_submit(const struct device *dev, + struct rtio_iodev_sqe *iodev_sqe) +{ + struct spi_mcux_data *data = dev->data; + + rtio_mpsc_push(&data->iodev.iodev_sq, &iodev_sqe->q); + spi_mcux_iodev_next(dev, false); +} + +static void spi_mcux_iodev_complete(const struct device *dev, int status) +{ + struct spi_mcux_data *data = dev->data; + + if (data->txn_curr->sqe.flags & RTIO_SQE_TRANSACTION) { + data->txn_curr = rtio_txn_next(data->txn_curr); + spi_mcux_iodev_start(dev); + } else { + struct rtio_iodev_sqe *txn_head = data->txn_head; + + spi_context_cs_control(&data->ctx, false); + spi_mcux_iodev_next(dev, true); + rtio_iodev_sqe_ok(txn_head, status); + } +} + + +#endif + + static const struct spi_driver_api spi_mcux_driver_api = { .transceive = spi_mcux_transceive, #ifdef CONFIG_SPI_ASYNC .transceive_async = spi_mcux_transceive_async, +#endif +#ifdef CONFIG_SPI_RTIO + .iodev_submit = spi_mcux_iodev_submit, #endif .release = spi_mcux_release, }; + +#define SPI_MCUX_RTIO_DEFINE(n) RTIO_DEFINE(spi_mcux_rtio_##n, CONFIG_SPI_MCUX_RTIO_SQ_SIZE, \ + CONFIG_SPI_MCUX_RTIO_SQ_SIZE) + #ifdef CONFIG_SPI_MCUX_LPSPI_DMA #define SPI_DMA_CHANNELS(n) \ IF_ENABLED(DT_INST_DMAS_HAS_NAME(n, tx), \ @@ -692,7 +871,7 @@ static const struct spi_driver_api spi_mcux_driver_api = { .block_count = 1, \ .dma_slot = DT_INST_DMAS_CELL_BY_NAME(n, rx, source) \ } \ - } \ + }, \ )) #else #define SPI_DMA_CHANNELS(n) @@ -700,6 +879,7 @@ static const struct spi_driver_api spi_mcux_driver_api = { #define SPI_MCUX_LPSPI_INIT(n) \ PINCTRL_DT_INST_DEFINE(n); \ + COND_CODE_1(CONFIG_SPI_RTIO, (SPI_MCUX_RTIO_DEFINE(n)), ()); \ \ static void spi_mcux_config_func_##n(const struct device *dev); \ \ @@ -727,6 +907,9 @@ static const struct spi_driver_api spi_mcux_driver_api = { SPI_CONTEXT_INIT_SYNC(spi_mcux_data_##n, ctx), \ SPI_CONTEXT_CS_GPIOS_INITIALIZE(DT_DRV_INST(n), ctx) \ SPI_DMA_CHANNELS(n) \ + IF_ENABLED(CONFIG_SPI_RTIO, \ + (.r = &spi_mcux_rtio_##n,)) \ + \ }; \ \ DEVICE_DT_INST_DEFINE(n, &spi_mcux_init, NULL, \ From 617cb789c34585921c07c883d9739faa62d75ce1 Mon Sep 17 00:00:00 2001 From: Emilio Benavente Date: Tue, 29 Aug 2023 15:22:59 -0500 Subject: [PATCH 0376/3723] tests: drivers: spi: spi_loopback: added overlay file for mimxrt1170 Added an overlay file for mimxrt1170_evk_cm33 to test rtio with the spi_loopback test. Added mimxrt1170_evk_cm7 to the testcase.yml file Signed-off-by: Emilio Benavente --- .../drivers/spi/spi_loopback/boards/mimxrt1170_evk_cm7.conf | 1 + .../spi/spi_loopback/boards/mimxrt1170_evk_cm7.overlay | 3 +++ tests/drivers/spi/spi_loopback/testcase.yaml | 5 ++++- 3 files changed, 8 insertions(+), 1 deletion(-) diff --git a/tests/drivers/spi/spi_loopback/boards/mimxrt1170_evk_cm7.conf b/tests/drivers/spi/spi_loopback/boards/mimxrt1170_evk_cm7.conf index 1ce2ad49200..7652fe0f65f 100644 --- a/tests/drivers/spi/spi_loopback/boards/mimxrt1170_evk_cm7.conf +++ b/tests/drivers/spi/spi_loopback/boards/mimxrt1170_evk_cm7.conf @@ -4,3 +4,4 @@ # SPDX-License-Identifier: Apache-2.0 # CONFIG_SPI_MCUX_LPSPI_DMA=y +CONFIG_SPI_ASYNC=n diff --git a/tests/drivers/spi/spi_loopback/boards/mimxrt1170_evk_cm7.overlay b/tests/drivers/spi/spi_loopback/boards/mimxrt1170_evk_cm7.overlay index fa2b906bbd7..bbddef98ad6 100644 --- a/tests/drivers/spi/spi_loopback/boards/mimxrt1170_evk_cm7.overlay +++ b/tests/drivers/spi/spi_loopback/boards/mimxrt1170_evk_cm7.overlay @@ -5,6 +5,9 @@ */ &lpspi1 { + dmas = <&edma0 0 36>, <&edma0 1 37>; + dma-names = "rx", "tx"; + slow@0 { compatible = "test-spi-loopback-slow"; reg = <0>; diff --git a/tests/drivers/spi/spi_loopback/testcase.yaml b/tests/drivers/spi/spi_loopback/testcase.yaml index 3c6995e37cd..fef5e5b361d 100644 --- a/tests/drivers/spi/spi_loopback/testcase.yaml +++ b/tests/drivers/spi/spi_loopback/testcase.yaml @@ -30,7 +30,10 @@ tests: drivers.spi.loopback.rtio: extra_configs: - CONFIG_SPI_RTIO=y - platform_allow: tdk_robokit1 + platform_allow: + - tdk_robokit1 + - mimxrt1170_evk_cm7 + - vmu_rt1170 drivers.spi.mcux_dspi_dma.loopback: extra_args: - OVERLAY_CONFIG="overlay-mcux-dspi-dma.conf" From 77abd6f89d8499dd7e69a3ee7b1908790d2f074c Mon Sep 17 00:00:00 2001 From: Peter Mitsis Date: Thu, 23 Nov 2023 09:42:04 -0500 Subject: [PATCH 0377/3723] tests: Allow thrd test to run on xtensa On some SMP platforms (such as intel_adsp_ace15_mtpm) it is not safe to access the stack of a thread that is currently executing on another CPU. This requires that tests be written such that objects and data that are shared between threads that may execute concurrently on different CPUs be placed into memory that is not a thread's stack. Signed-off-by: Peter Mitsis --- tests/lib/c_lib/thrd/src/mtx.c | 33 +++++++++++++-------------------- tests/lib/c_lib/thrd/src/thrd.c | 29 ++++++++++++++--------------- tests/lib/c_lib/thrd/src/tss.c | 5 +++-- 3 files changed, 30 insertions(+), 37 deletions(-) diff --git a/tests/lib/c_lib/thrd/src/mtx.c b/tests/lib/c_lib/thrd/src/mtx.c index 433ea0e64e4..21dc3d0c1c7 100644 --- a/tests/lib/c_lib/thrd/src/mtx.c +++ b/tests/lib/c_lib/thrd/src/mtx.c @@ -19,10 +19,11 @@ static const int valid_mtx_types[] = { mtx_timed | mtx_recursive, }; +static mtx_t mutex; +static thrd_t th; + ZTEST(libc_mtx, test_mtx_init) { - mtx_t mutex; - zassert_not_equal(thrd_success, mtx_init(NULL, FORTY_TWO)); zassert_not_equal(thrd_success, mtx_init(&mutex, FORTY_TWO)); @@ -42,8 +43,6 @@ ZTEST(libc_mtx, test_mtx_init) ZTEST(libc_mtx, test_mtx_destroy) { - mtx_t mutex; - if (false) { /* degenerate cases */ /* pthread_mutex_destroy() is not hardened against these */ @@ -57,8 +56,6 @@ ZTEST(libc_mtx, test_mtx_destroy) ZTEST(libc_mtx, test_mtx_lock) { - mtx_t mutex; - if (false) { /* pthread_mutex_lock() is not hardened against this */ zassert_not_equal(thrd_success, mtx_lock(NULL)); @@ -95,19 +92,17 @@ BUILD_ASSERT(TIMEDLOCK_TIMEOUT_MS >= 2 * TIMEDLOCK_TIMEOUT_DELAY_MS, static int mtx_timedlock_fn(void *arg) { struct timespec time_point; - mtx_t *mutex = (mtx_t *)arg; + mtx_t *mtx = (mtx_t *)arg; zassume_ok(clock_gettime(CLOCK_MONOTONIC, &time_point)); timespec_add_ms(&time_point, TIMEDLOCK_TIMEOUT_MS); - return mtx_timedlock(mutex, &time_point); + return mtx_timedlock(mtx, &time_point); } ZTEST(libc_mtx, test_mtx_timedlock) { int ret; - thrd_t th; - mtx_t mutex; /* * mtx_timed here is technically unnecessary, because all pthreads can @@ -138,16 +133,14 @@ ZTEST(libc_mtx, test_mtx_timedlock) static int mtx_trylock_fn(void *arg) { - mtx_t *mutex = (mtx_t *)arg; + mtx_t *mtx = (mtx_t *)arg; - return mtx_trylock(mutex); + return mtx_trylock(mtx); } ZTEST(libc_mtx, test_mtx_trylock) { int ret; - thrd_t th; - mtx_t mutex; zassert_equal(thrd_success, mtx_init(&mutex, mtx_plain)); @@ -163,15 +156,15 @@ ZTEST(libc_mtx, test_mtx_trylock) ZTEST(libc_mtx, test_mtx_unlock) { - mtx_t mutex = (mtx_t)BIOS_FOOD; + mtx_t mtx = (mtx_t)BIOS_FOOD; /* degenerate case */ - zassert_not_equal(thrd_success, mtx_unlock(&mutex)); + zassert_not_equal(thrd_success, mtx_unlock(&mtx)); - zassert_equal(thrd_success, mtx_init(&mutex, mtx_plain)); - zassert_equal(thrd_success, mtx_lock(&mutex)); - zassert_equal(thrd_success, mtx_unlock(&mutex)); - mtx_destroy(&mutex); + zassert_equal(thrd_success, mtx_init(&mtx, mtx_plain)); + zassert_equal(thrd_success, mtx_lock(&mtx)); + zassert_equal(thrd_success, mtx_unlock(&mtx)); + mtx_destroy(&mtx); } ZTEST_SUITE(libc_mtx, NULL, NULL, NULL, NULL, NULL); diff --git a/tests/lib/c_lib/thrd/src/thrd.c b/tests/lib/c_lib/thrd/src/thrd.c index 55cd1841c13..70dca94b4a9 100644 --- a/tests/lib/c_lib/thrd/src/thrd.c +++ b/tests/lib/c_lib/thrd/src/thrd.c @@ -12,6 +12,9 @@ #include #include +static thrd_t thr; +static uintptr_t param; + ZTEST(libc_thrd, test_thrd_sleep) { int64_t end; @@ -51,27 +54,27 @@ static int thrd_create_join_fn(void *arg) ZTEST(libc_thrd, test_thrd_create_join) { - thrd_t thr; int res = 0; - uintptr_t x = 0; thrd_start_t fun = thrd_create_join_fn; + param = 0; + if (false) { /* pthread_create() is not hardened for degenerate cases like this */ zassert_equal(thrd_error, thrd_create(NULL, NULL, NULL)); - zassert_equal(thrd_error, thrd_create(NULL, NULL, &x)); + zassert_equal(thrd_error, thrd_create(NULL, NULL, ¶m)); zassert_equal(thrd_error, thrd_create(NULL, fun, NULL)); - zassert_equal(thrd_error, thrd_create(NULL, fun, &x)); + zassert_equal(thrd_error, thrd_create(NULL, fun, ¶m)); zassert_equal(thrd_error, thrd_create(&thr, NULL, NULL)); - zassert_equal(thrd_error, thrd_create(&thr, NULL, &x)); + zassert_equal(thrd_error, thrd_create(&thr, NULL, ¶m)); } zassert_equal(thrd_success, thrd_create(&thr, fun, NULL)); zassert_equal(thrd_success, thrd_join(thr, NULL)); - zassert_equal(thrd_success, thrd_create(&thr, fun, &x)); + zassert_equal(thrd_success, thrd_create(&thr, fun, ¶m)); zassert_equal(thrd_success, thrd_join(thr, &res)); - zassert_equal(BIOS_FOOD, x, "expected: %d actual: %d", BIOS_FOOD, x); + zassert_equal(BIOS_FOOD, param, "expected: %d actual: %d", BIOS_FOOD, param); zassert_equal(FORTY_TWO, res); } @@ -90,13 +93,13 @@ static int thrd_exit_fn(void *arg) ZTEST(libc_thrd, test_thrd_exit) { - thrd_t thr; int res = 0; - uintptr_t x = 0; - zassert_equal(thrd_success, thrd_create(&thr, thrd_exit_fn, &x)); + param = 0; + + zassert_equal(thrd_success, thrd_create(&thr, thrd_exit_fn, ¶m)); zassert_equal(thrd_success, thrd_join(thr, &res)); - zassert_equal(BIOS_FOOD, x); + zassert_equal(BIOS_FOOD, param); zassert_equal(SEVENTY_THREE, res); } @@ -141,8 +144,6 @@ static int thrd_detach_fn(void *arg) ZTEST(libc_thrd, test_thrd_detach) { - thrd_t thr; - zassert_equal(thrd_success, thrd_create(&thr, thrd_detach_fn, NULL)); zassert_equal(thrd_success, thrd_detach(thr)); zassert_equal(thrd_error, thrd_join(thr, NULL)); @@ -156,8 +157,6 @@ ZTEST(libc_thrd, test_thrd_detach) ZTEST(libc_thrd, test_thrd_reuse) { - thrd_t thr; - for (int i = 0; i < FORTY_TWO; ++i) { zassert_equal(thrd_success, thrd_create(&thr, thrd_create_join_fn, NULL)); zassert_equal(thrd_success, thrd_join(thr, NULL)); diff --git a/tests/lib/c_lib/thrd/src/tss.c b/tests/lib/c_lib/thrd/src/tss.c index d68a6489dc5..463532809aa 100644 --- a/tests/lib/c_lib/thrd/src/tss.c +++ b/tests/lib/c_lib/thrd/src/tss.c @@ -16,6 +16,9 @@ static int32_t destroyed_values[2]; static const int32_t forty_two = FORTY_TWO; static const int32_t seventy_three = SEVENTY_THREE; +static thrd_t thread1; +static thrd_t thread2; + static void destroy_fn(void *arg) { int32_t val = *(int32_t *)arg; @@ -59,8 +62,6 @@ static int thread_fn(void *arg) /* test out separate threads doing tss_get() / tss_set() */ ZTEST(libc_tss, test_tss_get_set) { - thrd_t thread1; - thrd_t thread2; int res1 = BIOS_FOOD; int res2 = BIOS_FOOD; From 9f703b88f9fe9523796a8f6e583908eaac56875a Mon Sep 17 00:00:00 2001 From: Keith Packard Date: Tue, 28 Nov 2023 11:22:36 -0800 Subject: [PATCH 0378/3723] tests/log_output: Avoid printf stack overflow with old picolibc Before picolibc version 1.8.5, the only version of printf available with long long output support was the version including full support for floating point numbers and positional parameters. That version uses more stack space than the limited version causing an overflow. Increase the ztest stack space by 128 bytes. Signed-off-by: Keith Packard --- tests/subsys/logging/log_output/prj.conf | 1 + 1 file changed, 1 insertion(+) diff --git a/tests/subsys/logging/log_output/prj.conf b/tests/subsys/logging/log_output/prj.conf index b02eb949445..1d715c5167f 100644 --- a/tests/subsys/logging/log_output/prj.conf +++ b/tests/subsys/logging/log_output/prj.conf @@ -3,3 +3,4 @@ CONFIG_TEST_LOGGING_DEFAULTS=n CONFIG_LOG=y CONFIG_LOG_OUTPUT=y CONFIG_LOG_PRINTK=n +CONFIG_ZTEST_STACK_SIZE=1152 From 4a8d9a1ef3d239b475382837ed9ab319a83cb28b Mon Sep 17 00:00:00 2001 From: Declan Snyder Date: Mon, 17 Jul 2023 19:43:22 -0500 Subject: [PATCH 0379/3723] drivers: clock_control: mcux_ccm: Add ENET clock Add ENET clock value to the CCM clock decoder for both RT10XX and RT11XX CCM versions. Signed-off-by: Declan Snyder --- drivers/clock_control/clock_control_mcux_ccm.c | 6 ++++++ drivers/clock_control/clock_control_mcux_ccm_rev2.c | 7 +++++++ include/zephyr/dt-bindings/clock/imx_ccm.h | 2 ++ include/zephyr/dt-bindings/clock/imx_ccm_rev2.h | 3 +++ 4 files changed, 18 insertions(+) diff --git a/drivers/clock_control/clock_control_mcux_ccm.c b/drivers/clock_control/clock_control_mcux_ccm.c index ab90602d2a4..8ba1cb7221e 100644 --- a/drivers/clock_control/clock_control_mcux_ccm.c +++ b/drivers/clock_control/clock_control_mcux_ccm.c @@ -231,6 +231,12 @@ static int mcux_ccm_get_subsys_rate(const struct device *dev, break; #endif +#ifdef CONFIG_ETH_NXP_ENET + case IMX_CCM_ENET_CLK: + *rate = CLOCK_GetIpgFreq(); + break; +#endif + #ifdef CONFIG_UART_MCUX_IUART case IMX_CCM_UART1_CLK: case IMX_CCM_UART2_CLK: diff --git a/drivers/clock_control/clock_control_mcux_ccm_rev2.c b/drivers/clock_control/clock_control_mcux_ccm_rev2.c index 9a88a36823a..bcf61353b1f 100644 --- a/drivers/clock_control/clock_control_mcux_ccm_rev2.c +++ b/drivers/clock_control/clock_control_mcux_ccm_rev2.c @@ -103,6 +103,13 @@ static int mcux_ccm_get_subsys_rate(const struct device *dev, clock_root = kCLOCK_Root_Sai4; break; #endif + +#ifdef CONFIG_ETH_NXP_ENET + case IMX_CCM_ENET_CLK: + clock_root = kCLOCK_Root_Bus; + break; +#endif + default: return -EINVAL; } diff --git a/include/zephyr/dt-bindings/clock/imx_ccm.h b/include/zephyr/dt-bindings/clock/imx_ccm.h index 93c3b0b3b15..f5b697e415d 100644 --- a/include/zephyr/dt-bindings/clock/imx_ccm.h +++ b/include/zephyr/dt-bindings/clock/imx_ccm.h @@ -55,4 +55,6 @@ #define IMX_CCM_QTMR_CLK 0x0D00UL +#define IMX_CCM_ENET_CLK 0x0E00UL + #endif /* ZEPHYR_INCLUDE_DT_BINDINGS_CLOCK_IMX_CCM_H_ */ diff --git a/include/zephyr/dt-bindings/clock/imx_ccm_rev2.h b/include/zephyr/dt-bindings/clock/imx_ccm_rev2.h index fb105454377..75de126bd29 100644 --- a/include/zephyr/dt-bindings/clock/imx_ccm_rev2.h +++ b/include/zephyr/dt-bindings/clock/imx_ccm_rev2.h @@ -84,5 +84,8 @@ #define IMX_CCM_SAI3_CLK 0x2002UL #define IMX_CCM_SAI4_CLK 0x2003UL +/* ENET */ +#define IMX_CCM_ENET_CLK 0x3000UL + #endif /* ZEPHYR_INCLUDE_DT_BINDINGS_CLOCK_IMX_CCM_REV2_H_ */ From 7e88ab54e239252fc65a968270ef66680bbf9c81 Mon Sep 17 00:00:00 2001 From: Declan Snyder Date: Wed, 27 Sep 2023 12:08:32 -0500 Subject: [PATCH 0380/3723] dts: bindings: ethernet-controller: Add phy mode Add a property to the ethernet controller binding indicating what type of connection the MAC has with the PHY device. Signed-off-by: Declan Snyder --- drivers/ethernet/eth_esp32.c | 4 +++- drivers/ethernet/eth_sam_gmac.c | 12 +++++++++++- dts/bindings/ethernet/atmel,gmac-common.yaml | 16 +++------------- dts/bindings/ethernet/espressif,esp32-eth.yaml | 13 +++---------- dts/bindings/ethernet/ethernet-controller.yaml | 9 +++++++++ dts/bindings/ethernet/nxp,s32-gmac.yaml | 10 ---------- 6 files changed, 29 insertions(+), 35 deletions(-) diff --git a/drivers/ethernet/eth_esp32.c b/drivers/ethernet/eth_esp32.c index 0b1744efe6c..d7e9382c9c9 100644 --- a/drivers/ethernet/eth_esp32.c +++ b/drivers/ethernet/eth_esp32.c @@ -217,7 +217,9 @@ int eth_esp32_initialize(const struct device *dev) /* Configure phy for Media-Independent Interface (MII) or * Reduced Media-Independent Interface (RMII) mode */ - const char *phy_connection_type = DT_INST_PROP(0, phy_connection_type); + const char *phy_connection_type = DT_INST_PROP_OR(0, + phy_connection_type, + "rmii"); if (strcmp(phy_connection_type, "rmii") == 0) { emac_hal_iomux_init_rmii(); diff --git a/drivers/ethernet/eth_sam_gmac.c b/drivers/ethernet/eth_sam_gmac.c index dec6ea6df20..b4746e4e743 100644 --- a/drivers/ethernet/eth_sam_gmac.c +++ b/drivers/ethernet/eth_sam_gmac.c @@ -133,6 +133,8 @@ static inline void dcache_clean(uint32_t addr, uint32_t size) #endif #endif /* !CONFIG_NET_TEST */ +BUILD_ASSERT(DT_INST_ENUM_IDX(0, phy_connection_type) <= 1, "Invalid PHY connection"); + /* RX descriptors list */ static struct gmac_desc rx_desc_que0[MAIN_QUEUE_RX_DESC_COUNT] __nocache __aligned(GMAC_DESC_ALIGNMENT); @@ -1113,7 +1115,15 @@ static int gmac_init(Gmac *gmac, uint32_t gmac_ncfgr_val) /* Setup Network Configuration Register */ gmac->GMAC_NCFGR = gmac_ncfgr_val | mck_divisor; - gmac->GMAC_UR = DT_INST_ENUM_IDX(0, phy_connection_type); + switch (DT_INST_ENUM_IDX_OR(0, phy_connection_type, 1)) { + case 0: /* mii */ + gmac->GMAC_UR = 0x1; + case 1: /* rmii */ + gmac->GMAC_UR = 0x0; + default: + /* Build assert at top of file should catch this case */ + return -EINVAL; + } #if defined(CONFIG_PTP_CLOCK_SAM_GMAC) /* Initialize PTP Clock Registers */ diff --git a/dts/bindings/ethernet/atmel,gmac-common.yaml b/dts/bindings/ethernet/atmel,gmac-common.yaml index f17d78df696..0975647e187 100644 --- a/dts/bindings/ethernet/atmel,gmac-common.yaml +++ b/dts/bindings/ethernet/atmel,gmac-common.yaml @@ -43,19 +43,9 @@ properties: gmac driver supports 10Mbit/s and 100Mbit/s. Using 100, as default value, enables driver to configure 10 and 100Mbit/s speeds. - phy-connection-type: - type: string - enum: - - "rmii" - - "mii" - default: "rmii" - description: | - Phy connection type define the physical interface connection between - PHY and MAC. The default value uses gmac register reset value, which - represents Reduced Media-Independent Interface (RMII) mode. - - This property must be used with pinctrl-0. - mac-eeprom: type: phandle description: phandle to I2C eeprom device node. + + phy-connection-type: + default: "rmii" diff --git a/dts/bindings/ethernet/espressif,esp32-eth.yaml b/dts/bindings/ethernet/espressif,esp32-eth.yaml index 3ffd12cdc50..f7687eb0f78 100644 --- a/dts/bindings/ethernet/espressif,esp32-eth.yaml +++ b/dts/bindings/ethernet/espressif,esp32-eth.yaml @@ -9,15 +9,8 @@ include: - name: ethernet-controller.yaml properties: - phy-connection-type: - type: string - enum: - - "rmii" - - "mii" - default: "rmii" - description: | - Phy connection type define the physical interface connection between - PHY and MAC. The default value uses Reduced Media-Independent - Interface (RMII) mode. phy-handle: required: true + + phy-connection-type: + default: "rmii" diff --git a/dts/bindings/ethernet/ethernet-controller.yaml b/dts/bindings/ethernet/ethernet-controller.yaml index a5a9cec2700..8823459d3a9 100644 --- a/dts/bindings/ethernet/ethernet-controller.yaml +++ b/dts/bindings/ethernet/ethernet-controller.yaml @@ -27,3 +27,12 @@ properties: type: phandle description: | Specifies a reference to a node representing a PHY device. + + phy-connection-type: + type: string + description: | + Specifies the interface connection type between ethernet MAC and PHY. + enum: + - "mii" + - "rmii" + - "gmii" diff --git a/dts/bindings/ethernet/nxp,s32-gmac.yaml b/dts/bindings/ethernet/nxp,s32-gmac.yaml index 357a5eb1521..7767a755f39 100644 --- a/dts/bindings/ethernet/nxp,s32-gmac.yaml +++ b/dts/bindings/ethernet/nxp,s32-gmac.yaml @@ -16,13 +16,3 @@ properties: interrupt-names: required: true - - phy-connection-type: - type: string - enum: - - "mii" - - "rmii" - - "rgmii" - description: | - Specifies interface type between the Ethernet device and a physical - layer (PHY) device. From e7dac64ce1d3adc121db3439156191db443eb1b8 Mon Sep 17 00:00:00 2001 From: Declan Snyder Date: Tue, 18 Jul 2023 11:36:49 -0500 Subject: [PATCH 0381/3723] dts: bindings: Add binding for KSZ8081 PHY Add DT Binding for Microchip KSZ8081 PHY Signed-off-by: Declan Snyder --- .../ethernet/phy_microchip_ksz8081.yaml | 27 +++++++++++++++++++ 1 file changed, 27 insertions(+) create mode 100644 dts/bindings/ethernet/phy_microchip_ksz8081.yaml diff --git a/dts/bindings/ethernet/phy_microchip_ksz8081.yaml b/dts/bindings/ethernet/phy_microchip_ksz8081.yaml new file mode 100644 index 00000000000..14ccfe7cc78 --- /dev/null +++ b/dts/bindings/ethernet/phy_microchip_ksz8081.yaml @@ -0,0 +1,27 @@ +# Copyright 2023 NXP +# SPDX-License-Identifier: Apache-2.0 + +description: Microchip KSZ8081 Ethernet PHY device + +compatible: "microchip,ksz8081" + +include: ethernet-phy.yaml + +properties: + mc,reset-gpio: + type: phandle-array + required: true + specifier-space: gpio + description: GPIO connected to PHY reset signal pin. Reset is active low. + mc,interrupt-gpio: + type: phandle-array + required: true + specifier-space: gpio + description: GPIO for interrupt signal indicating PHY state change. + mc,interface-type: + type: string + required: true + description: Which type of phy connection the phy is set up for + enum: + - "mii" + - "rmii" From 5724ce78fcc69a094870eb8a6394848b1c44dcf7 Mon Sep 17 00:00:00 2001 From: Declan Snyder Date: Tue, 18 Jul 2023 10:01:59 -0500 Subject: [PATCH 0382/3723] drivers: ethernet: phy: Add KSZ8081 PHY Driver Add Driver for KSZ8081 Ethernet PHY. The Generic MII Driver is not sufficient to use for this PHY chip which has special vendor implemented behaviors. Signed-off-by: Declan Snyder --- drivers/ethernet/phy/CMakeLists.txt | 1 + drivers/ethernet/phy/Kconfig | 12 +- drivers/ethernet/phy/phy_microchip_ksz8081.c | 443 ++++++++++++++++++ ...ip_ksz8081.yaml => microchip,ksz8081.yaml} | 0 4 files changed, 454 insertions(+), 2 deletions(-) create mode 100644 drivers/ethernet/phy/phy_microchip_ksz8081.c rename dts/bindings/ethernet/{phy_microchip_ksz8081.yaml => microchip,ksz8081.yaml} (100%) diff --git a/drivers/ethernet/phy/CMakeLists.txt b/drivers/ethernet/phy/CMakeLists.txt index d3a7777ae24..ff25a9a4fa3 100644 --- a/drivers/ethernet/phy/CMakeLists.txt +++ b/drivers/ethernet/phy/CMakeLists.txt @@ -3,3 +3,4 @@ zephyr_library_sources_ifdef(CONFIG_PHY_GENERIC_MII phy_mii.c) zephyr_library_sources_ifdef(CONFIG_PHY_ADIN2111 phy_adin2111.c) zephyr_library_sources_ifdef(CONFIG_PHY_TJA1103 phy_tja1103.c) +zephyr_library_sources_ifdef(CONFIG_PHY_MICROCHIP_KSZ8081 phy_microchip_ksz8081.c) diff --git a/drivers/ethernet/phy/Kconfig b/drivers/ethernet/phy/Kconfig index b148d1c37d1..ad7cef7bc17 100644 --- a/drivers/ethernet/phy/Kconfig +++ b/drivers/ethernet/phy/Kconfig @@ -23,8 +23,7 @@ config PHY_INIT_PRIORITY config PHY_GENERIC_MII bool "Generic MII PHY Driver" - default y - depends on DT_HAS_ETHERNET_PHY_ENABLED + default y if DT_HAS_ETHERNET_PHY_ENABLED depends on MDIO help This is a generic MII PHY interface that communicates with the @@ -47,6 +46,15 @@ config PHY_TJA1103 help Enable TJA1103 PHY driver. +config PHY_MICROCHIP_KSZ8081 + bool "Microchip KSZ8081 Phy Driver" + default y + depends on DT_HAS_MICROCHIP_KSZ8081_ENABLED + depends on MDIO + depends on GPIO + help + Enable Microchip KSZ8081 Ethernet Phy Driver + config PHY_AUTONEG_TIMEOUT_MS int "Auto-negotiation timeout value in milliseconds" default 4000 diff --git a/drivers/ethernet/phy/phy_microchip_ksz8081.c b/drivers/ethernet/phy/phy_microchip_ksz8081.c new file mode 100644 index 00000000000..46382a37df6 --- /dev/null +++ b/drivers/ethernet/phy/phy_microchip_ksz8081.c @@ -0,0 +1,443 @@ +/* + * Copyright 2023 NXP + * + * Inspiration from phy_mii.c, which is: + * Copyright (c) 2021 IP-Logix Inc. + * Copyright 2022 NXP + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#define DT_DRV_COMPAT microchip_ksz8081 + +#include +#include +#include +#include +#include +#include +#include + +#define LOG_MODULE_NAME phy_mc_ksz8081 +#define LOG_LEVEL CONFIG_PHY_LOG_LEVEL +#include +LOG_MODULE_REGISTER(LOG_MODULE_NAME); + +#define PHY_MC_KSZ8081_OMSO_REG 0x16 +#define PHY_MC_KSZ8081_OMSO_FACTORY_MODE_MASK BIT(15) +#define PHY_MC_KSZ8081_OMSO_NAND_TREE_MASK BIT(5) + +#define PHY_MC_KSZ8081_CTRL2_REG 0x1F +#define PHY_MC_KSZ8081_CTRL2_REF_CLK_SEL BIT(7) + +#define PHY_MC_KSZ8081_RESET_HOLD_TIME + +enum ksz8081_interface { + KSZ8081_MII, + KSZ8081_RMII, +}; + +struct mc_ksz8081_config { + uint8_t addr; + const struct device *mdio_dev; + enum ksz8081_interface phy_iface; + const struct gpio_dt_spec reset_gpio; + const struct gpio_dt_spec interrupt_gpio; +}; + +struct mc_ksz8081_data { + const struct device *dev; + struct phy_link_state state; + phy_callback_t cb; + void *cb_data; + struct k_mutex mutex; + struct k_work_delayable phy_monitor_work; +}; + +static int phy_mc_ksz8081_read(const struct device *dev, + uint16_t reg_addr, uint32_t *data) +{ + const struct mc_ksz8081_config *config = dev->config; + int ret; + + ret = mdio_read(config->mdio_dev, config->addr, reg_addr, (uint16_t *)data); + if (ret) { + return ret; + } + + return 0; +} + +static int phy_mc_ksz8081_write(const struct device *dev, + uint16_t reg_addr, uint32_t data) +{ + const struct mc_ksz8081_config *config = dev->config; + int ret; + + ret = mdio_write(config->mdio_dev, config->addr, reg_addr, (uint16_t)data); + if (ret) { + return ret; + } + + return 0; +} + +static int phy_mc_ksz8081_autonegotiate(const struct device *dev) +{ + const struct mc_ksz8081_config *config = dev->config; + int ret; + uint32_t bmcr = 0; + uint32_t bmsr = 0; + uint16_t timeout = CONFIG_PHY_AUTONEG_TIMEOUT_MS / 100; + + /* Read control register to write back with autonegotiation bit */ + ret = phy_mc_ksz8081_read(dev, MII_BMCR, &bmcr); + if (ret) { + LOG_ERR("Error reading phy (%d) basic control register", config->addr); + return ret; + } + + /* (re)start autonegotiation */ + LOG_DBG("PHY (%d) is entering autonegotiation sequence", config->addr); + bmcr |= MII_BMCR_AUTONEG_ENABLE | MII_BMCR_AUTONEG_RESTART; + bmcr &= ~MII_BMCR_ISOLATE; + + ret = phy_mc_ksz8081_write(dev, MII_BMCR, bmcr); + if (ret) { + LOG_ERR("Error writing phy (%d) basic control register", config->addr); + return ret; + } + + /* TODO change this to GPIO interrupt driven */ + do { + if (timeout-- == 0) { + LOG_DBG("PHY (%d) autonegotiation timed out", config->addr); + return -ETIMEDOUT; + } + k_msleep(100); + + ret = phy_mc_ksz8081_read(dev, MII_BMSR, &bmsr); + if (ret) { + LOG_ERR("Error reading phy (%d) basic status register", config->addr); + return ret; + } + } while (!(bmsr & MII_BMSR_AUTONEG_COMPLETE)); + + LOG_DBG("PHY (%d) autonegotiation completed", config->addr); + + return 0; +} + +static int phy_mc_ksz8081_get_link(const struct device *dev, + struct phy_link_state *state) +{ + const struct mc_ksz8081_config *config = dev->config; + struct mc_ksz8081_data *data = dev->data; + int ret; + uint32_t bmsr = 0; + uint32_t anar = 0; + uint32_t anlpar = 0; + + /* Lock mutex */ + ret = k_mutex_lock(&data->mutex, K_FOREVER); + if (ret) { + LOG_ERR("PHY mutex lock error"); + return ret; + } + + /* Read link state */ + ret = phy_mc_ksz8081_read(dev, MII_BMSR, &bmsr); + if (ret) { + LOG_ERR("Error reading phy (%d) basic status register", config->addr); + k_mutex_unlock(&data->mutex); + return ret; + } + state->is_up = bmsr & MII_BMSR_LINK_STATUS; + + LOG_DBG("PHY %d is %s", config->addr, data->state.is_up ? "up" : "down"); + + /* Read currently configured advertising options */ + ret = phy_mc_ksz8081_read(dev, MII_ANAR, &anar); + if (ret) { + LOG_ERR("Error reading phy (%d) advertising register", config->addr); + k_mutex_unlock(&data->mutex); + return ret; + } + + /* Read link partner capability */ + ret = phy_mc_ksz8081_read(dev, MII_ANLPAR, &anlpar); + if (ret) { + LOG_ERR("Error reading phy (%d) link partner register", config->addr); + k_mutex_unlock(&data->mutex); + return ret; + } + + /* Unlock mutex */ + k_mutex_unlock(&data->mutex); + + uint32_t mutual_capabilities = anar & anlpar; + + if (mutual_capabilities & MII_ADVERTISE_100_FULL) { + state->speed = LINK_FULL_100BASE_T; + } else if (mutual_capabilities & MII_ADVERTISE_100_HALF) { + state->speed = LINK_HALF_100BASE_T; + } else if (mutual_capabilities & MII_ADVERTISE_10_FULL) { + state->speed = LINK_FULL_10BASE_T; + } else if (mutual_capabilities & MII_ADVERTISE_10_HALF) { + state->speed = LINK_HALF_10BASE_T; + } else { + LOG_ERR("No valid PHY %d capabilities", config->addr); + return -EIO; + } + + LOG_DBG("PHY (%d) Link speed %s Mb, %s duplex\n", config->addr, + (PHY_LINK_IS_SPEED_100M(state->speed) ? "100" : "10"), + PHY_LINK_IS_FULL_DUPLEX(state->speed) ? "full" : "half"); + + return 0; +} + +/* + * Configuration set statically (DT) that should never change + * This function is needed in case the PHY is reset then the next call + * to configure the phy will ensure this configuration will be redone + */ +static int phy_mc_ksz8081_static_cfg(const struct device *dev) +{ + const struct mc_ksz8081_config *config = dev->config; + uint32_t omso = 0; + uint32_t ctrl2 = 0; + int ret = 0; + + /* Force normal operation in the case of factory mode */ + ret = phy_mc_ksz8081_read(dev, PHY_MC_KSZ8081_OMSO_REG, (uint32_t *)&omso); + if (ret) { + return ret; + } + + omso &= ~PHY_MC_KSZ8081_OMSO_FACTORY_MODE_MASK & + ~PHY_MC_KSZ8081_OMSO_NAND_TREE_MASK; + + ret = phy_mc_ksz8081_write(dev, PHY_MC_KSZ8081_OMSO_REG, (uint32_t)omso); + if (ret) { + return ret; + } + + /* Select correct reference clock mode depending on interface setup */ + ret = phy_mc_ksz8081_read(dev, PHY_MC_KSZ8081_CTRL2_REG, (uint32_t *)&ctrl2); + if (ret) { + return ret; + } + + if (config->phy_iface == KSZ8081_RMII) { + ctrl2 |= PHY_MC_KSZ8081_CTRL2_REF_CLK_SEL; + } else { + ctrl2 &= ~PHY_MC_KSZ8081_CTRL2_REF_CLK_SEL; + } + + ret = phy_mc_ksz8081_write(dev, PHY_MC_KSZ8081_CTRL2_REG, (uint32_t)ctrl2); + if (ret) { + return ret; + } + + return 0; +} + +static int phy_mc_ksz8081_cfg_link(const struct device *dev, + enum phy_link_speed speeds) +{ + const struct mc_ksz8081_config *config = dev->config; + struct mc_ksz8081_data *data = dev->data; + int ret; + uint32_t anar; + + /* Lock mutex */ + ret = k_mutex_lock(&data->mutex, K_FOREVER); + if (ret) { + LOG_ERR("PHY mutex lock error"); + return ret; + } + + /* We are going to reconfigure the phy, don't need to monitor until done */ + k_work_cancel_delayable(&data->phy_monitor_work); + + /* DT configurations */ + ret = phy_mc_ksz8081_static_cfg(dev); + if (ret) { + k_mutex_unlock(&data->mutex); + return ret; + } + + /* Read ANAR register to write back */ + ret = phy_mc_ksz8081_read(dev, MII_ANAR, &anar); + if (ret) { + LOG_ERR("Error reading phy (%d) advertising register", config->addr); + k_mutex_unlock(&data->mutex); + return -EIO; + } + + /* Setup advertising register */ + if (speeds & LINK_FULL_100BASE_T) { + anar |= MII_ADVERTISE_100_FULL; + } else { + anar &= ~MII_ADVERTISE_100_FULL; + } + if (speeds & LINK_HALF_100BASE_T) { + anar |= MII_ADVERTISE_100_HALF; + } else { + anar &= ~MII_ADVERTISE_100_HALF; + } + if (speeds & LINK_FULL_10BASE_T) { + anar |= MII_ADVERTISE_10_FULL; + } else { + anar &= ~MII_ADVERTISE_10_FULL; + } + if (speeds & LINK_HALF_10BASE_T) { + anar |= MII_ADVERTISE_10_HALF; + } else { + anar &= ~MII_ADVERTISE_10_HALF; + } + + /* Write capabilities to advertising register */ + ret = phy_mc_ksz8081_write(dev, MII_ANAR, anar); + if (ret) { + LOG_ERR("Error writing phy (%d) advertising register", config->addr); + k_mutex_unlock(&data->mutex); + return ret; + } + + /* (re)do autonegotiation */ + ret = phy_mc_ksz8081_autonegotiate(dev); + if (ret) { + LOG_ERR("Error in autonegotiation"); + k_mutex_unlock(&data->mutex); + return ret; + } + + /* Unlock mutex */ + k_mutex_unlock(&data->mutex); + + + /* Get link status */ + ret = phy_mc_ksz8081_get_link(dev, &data->state); + if (ret) { + return ret; + } + + /* Start monitoring */ + k_work_schedule(&data->phy_monitor_work, + K_MSEC(CONFIG_PHY_MONITOR_PERIOD)); + + /* Log the results of the configuration */ + LOG_INF("PHY %d is %s", config->addr, data->state.is_up ? "up" : "down"); + LOG_INF("PHY (%d) Link speed %s Mb, %s duplex\n", config->addr, + (PHY_LINK_IS_SPEED_100M(data->state.speed) ? "100" : "10"), + PHY_LINK_IS_FULL_DUPLEX(data->state.speed) ? "full" : "half"); + + return 0; +} + +static int phy_mc_ksz8081_link_cb_set(const struct device *dev, + phy_callback_t cb, void *user_data) +{ + struct mc_ksz8081_data *data = dev->data; + + data->cb = cb; + data->cb_data = user_data; + + phy_mc_ksz8081_get_link(dev, &data->state); + + data->cb(dev, &data->state, data->cb_data); + + return 0; +} + +static void phy_mc_ksz8081_monitor_work_handler(struct k_work *work) +{ + struct k_work_delayable *dwork = k_work_delayable_from_work(work); + struct mc_ksz8081_data *data = + CONTAINER_OF(dwork, struct mc_ksz8081_data, phy_monitor_work); + const struct device *dev = data->dev; + struct phy_link_state state; + int rc; + + rc = phy_mc_ksz8081_get_link(dev, &state); + + if (rc == 0 && memcmp(&state, &data->state, sizeof(struct phy_link_state)) != 0) { + memcpy(&data->state, &state, sizeof(struct phy_link_state)); + if (data->cb) { + data->cb(dev, &data->state, data->cb_data); + } + } + + /* TODO change this to GPIO interrupt driven */ + k_work_reschedule(&data->phy_monitor_work, K_MSEC(CONFIG_PHY_MONITOR_PERIOD)); +} + +static int phy_mc_ksz8081_init(const struct device *dev) +{ + const struct mc_ksz8081_config *config = dev->config; + struct mc_ksz8081_data *data = dev->data; + int ret; + + data->dev = dev; + + ret = k_mutex_init(&data->mutex); + if (ret) { + return ret; + } + + mdio_bus_enable(config->mdio_dev); + + /* Prevent NAND TREE mode */ + ret = gpio_pin_configure_dt(&config->interrupt_gpio, GPIO_OUTPUT_ACTIVE); + if (ret) { + return ret; + } + + /* Start reset */ + ret = gpio_pin_configure_dt(&config->reset_gpio, GPIO_OUTPUT_INACTIVE); + if (ret) { + return ret; + } + + /* Wait for 500 ms as specified by datasheet */ + k_busy_wait(USEC_PER_MSEC * 500); + + /* Reset over */ + ret = gpio_pin_set_dt(&config->reset_gpio, 1); + if (ret) { + return ret; + } + + k_work_init_delayable(&data->phy_monitor_work, + phy_mc_ksz8081_monitor_work_handler); + + return 0; +} + +static const struct ethphy_driver_api mc_ksz8081_phy_api = { + .get_link = phy_mc_ksz8081_get_link, + .cfg_link = phy_mc_ksz8081_cfg_link, + .link_cb_set = phy_mc_ksz8081_link_cb_set, + .read = phy_mc_ksz8081_read, + .write = phy_mc_ksz8081_write, +}; + +#define MICROCHIP_KSZ8081_INIT(n) \ + static const struct mc_ksz8081_config mc_ksz8081_##n##_config = { \ + .addr = DT_INST_REG_ADDR(n), \ + .mdio_dev = DEVICE_DT_GET(DT_INST_PARENT(n)), \ + .phy_iface = DT_INST_ENUM_IDX(n, mc_interface_type), \ + .reset_gpio = GPIO_DT_SPEC_INST_GET(n, mc_reset_gpio), \ + .interrupt_gpio = GPIO_DT_SPEC_INST_GET(n, mc_interrupt_gpio), \ + }; \ + \ + static struct mc_ksz8081_data mc_ksz8081_##n##_data; \ + \ + DEVICE_DT_INST_DEFINE(n, &phy_mc_ksz8081_init, NULL, \ + &mc_ksz8081_##n##_data, &mc_ksz8081_##n##_config, \ + POST_KERNEL, CONFIG_PHY_INIT_PRIORITY, \ + &mc_ksz8081_phy_api); + +DT_INST_FOREACH_STATUS_OKAY(MICROCHIP_KSZ8081_INIT) diff --git a/dts/bindings/ethernet/phy_microchip_ksz8081.yaml b/dts/bindings/ethernet/microchip,ksz8081.yaml similarity index 100% rename from dts/bindings/ethernet/phy_microchip_ksz8081.yaml rename to dts/bindings/ethernet/microchip,ksz8081.yaml From 57dd852fda7ac7a4c19ffea3c498bc37b1b83fff Mon Sep 17 00:00:00 2001 From: Declan Snyder Date: Mon, 17 Jul 2023 14:34:15 -0500 Subject: [PATCH 0383/3723] dts: bindings: Add NXP ENET bindings Add bindings for compatibles related to NXP ENET IP. Signed-off-by: Declan Snyder --- dts/bindings/ethernet/nxp,enet-mac.yaml | 18 ++++++++++++++++++ dts/bindings/ethernet/nxp,enet.yaml | 15 +++++++++++++++ dts/bindings/mdio/nxp,enet-mdio.yaml | 15 +++++++++++++++ include/zephyr/dt-bindings/ethernet/nxp_enet.h | 14 ++++++++++++++ 4 files changed, 62 insertions(+) create mode 100644 dts/bindings/ethernet/nxp,enet-mac.yaml create mode 100644 dts/bindings/ethernet/nxp,enet.yaml create mode 100644 dts/bindings/mdio/nxp,enet-mdio.yaml create mode 100644 include/zephyr/dt-bindings/ethernet/nxp_enet.h diff --git a/dts/bindings/ethernet/nxp,enet-mac.yaml b/dts/bindings/ethernet/nxp,enet-mac.yaml new file mode 100644 index 00000000000..af0363b28df --- /dev/null +++ b/dts/bindings/ethernet/nxp,enet-mac.yaml @@ -0,0 +1,18 @@ +# Copyright 2023 NXP +# SPDX-License-Identifier: Apache-2.0 + +description: NXP ENET MAC/L2 Device + +compatible: "nxp,enet-mac" + +include: ["ethernet-controller.yaml", "ethernet,fixed-link.yaml", "pinctrl-device.yaml"] + +properties: + interrupts: + required: true + + nxp,mdio: + type: phandle + required: true + description: | + Corresponding mdio device diff --git a/dts/bindings/ethernet/nxp,enet.yaml b/dts/bindings/ethernet/nxp,enet.yaml new file mode 100644 index 00000000000..f98af9f002b --- /dev/null +++ b/dts/bindings/ethernet/nxp,enet.yaml @@ -0,0 +1,15 @@ +# Copyright 2023 NXP +# SPDX-License-Identifier: Apache-2.0 + +description: NXP ENET IP Module + +compatible: "nxp,enet" + +include: ["base.yaml"] + +properties: + reg: + required: true + + clocks: + required: true diff --git a/dts/bindings/mdio/nxp,enet-mdio.yaml b/dts/bindings/mdio/nxp,enet-mdio.yaml new file mode 100644 index 00000000000..68bc917444a --- /dev/null +++ b/dts/bindings/mdio/nxp,enet-mdio.yaml @@ -0,0 +1,15 @@ +# Copyright 2023 NXP +# SPDX-License-Identifier: Apache-2.0 + +description: NXP ENET MDIO Features + +compatible: "nxp,enet-mdio" + +include: [mdio-controller.yaml, pinctrl-device.yaml] + +properties: + pinctrl-0: + required: true + + pinctrl-names: + required: true diff --git a/include/zephyr/dt-bindings/ethernet/nxp_enet.h b/include/zephyr/dt-bindings/ethernet/nxp_enet.h new file mode 100644 index 00000000000..e084825da4c --- /dev/null +++ b/include/zephyr/dt-bindings/ethernet/nxp_enet.h @@ -0,0 +1,14 @@ +/* + * Copyright 2023 NXP + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#ifndef ZEPHYR_INCLUDE_DT_BINDINGS_NXP_ENET_H_ +#define ZEPHYR_INCLUDE_DT_BINDINGS_NXP_ENET_H_ + +#define NXP_ENET_MII_MODE 0 +#define NXP_ENET_RMII_MODE 1 +#define NXP_ENET_INVALID_MII_MODE 100 + +#endif /* ZEPHYR_INCLUDE_DT_BINDINGS_NXP_ENET_H_ */ From f5bbcf2e486ef498a6f51dc51a51fe665559a795 Mon Sep 17 00:00:00 2001 From: Declan Snyder Date: Mon, 17 Jul 2023 16:31:39 -0500 Subject: [PATCH 0384/3723] include: NXP ENET driver include header Create an include header to be used by NXP ENET drivers. Signed-off-by: Declan Snyder --- .../zephyr/drivers/ethernet/eth_nxp_enet.h | 40 +++++++++++++++++++ 1 file changed, 40 insertions(+) create mode 100644 include/zephyr/drivers/ethernet/eth_nxp_enet.h diff --git a/include/zephyr/drivers/ethernet/eth_nxp_enet.h b/include/zephyr/drivers/ethernet/eth_nxp_enet.h new file mode 100644 index 00000000000..1a0be56495b --- /dev/null +++ b/include/zephyr/drivers/ethernet/eth_nxp_enet.h @@ -0,0 +1,40 @@ +/* + * Copyright 2023 NXP + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#ifndef ZEPHYR_INCLUDE_DRIVERS_ETH_NXP_ENET_H__ +#define ZEPHYR_INCLUDE_DRIVERS_ETH_NXP_ENET_H__ + +#include + +#ifdef __cplusplus +extern "C" { +#endif + +/* + * Reasons for callback to a driver: + * + * Module reset: The ENET module was reset, perhaps because of power management + * actions, and subdriver should reinitialize part of the module. + * Interrupt: An interrupt of a type relevant to the subdriver occurred. + * Interrupt enable: The driver's relevant interrupt was enabled in NVIC + */ +enum nxp_enet_callback_reason { + nxp_enet_module_reset, + nxp_enet_interrupt, + nxp_enet_interrupt_enabled, +}; + +/* Calback for mdio device called from mac driver */ +void nxp_enet_mdio_callback(const struct device *mdio_dev, + enum nxp_enet_callback_reason event); + + +#ifdef __cplusplus +} +#endif + + +#endif /* ZEPHYR_INCLUDE_DRIVERS_ETH_NXP_ENET_H__ */ From b669d58337e83b19822b27e13748ede844bd3335 Mon Sep 17 00:00:00 2001 From: Declan Snyder Date: Mon, 17 Jul 2023 19:42:33 -0500 Subject: [PATCH 0385/3723] drivers: mdio: Add NXP ENET MDIO driver Add driver for NXP ENET MDIO functionalities Signed-off-by: Declan Snyder --- drivers/mdio/CMakeLists.txt | 1 + drivers/mdio/Kconfig | 1 + drivers/mdio/Kconfig.nxp_enet | 21 +++ drivers/mdio/mdio_nxp_enet.c | 297 ++++++++++++++++++++++++++++++++++ drivers/mdio/mdio_shell.c | 2 + 5 files changed, 322 insertions(+) create mode 100644 drivers/mdio/Kconfig.nxp_enet create mode 100644 drivers/mdio/mdio_nxp_enet.c diff --git a/drivers/mdio/CMakeLists.txt b/drivers/mdio/CMakeLists.txt index 360111f0c08..03391788187 100644 --- a/drivers/mdio/CMakeLists.txt +++ b/drivers/mdio/CMakeLists.txt @@ -9,3 +9,4 @@ zephyr_library_sources_ifdef(CONFIG_MDIO_NXP_S32_NETC mdio_nxp_s32_netc.c) zephyr_library_sources_ifdef(CONFIG_MDIO_NXP_S32_GMAC mdio_nxp_s32_gmac.c) zephyr_library_sources_ifdef(CONFIG_MDIO_ADIN2111 mdio_adin2111.c) zephyr_library_sources_ifdef(CONFIG_MDIO_GPIO mdio_gpio.c) +zephyr_library_sources_ifdef(CONFIG_MDIO_NXP_ENET mdio_nxp_enet.c) diff --git a/drivers/mdio/Kconfig b/drivers/mdio/Kconfig index 37721e885a6..7e72b50ceb1 100644 --- a/drivers/mdio/Kconfig +++ b/drivers/mdio/Kconfig @@ -30,6 +30,7 @@ source "drivers/mdio/Kconfig.nxp_s32_netc" source "drivers/mdio/Kconfig.nxp_s32_gmac" source "drivers/mdio/Kconfig.adin2111" source "drivers/mdio/Kconfig.gpio" +source "drivers/mdio/Kconfig.nxp_enet" config MDIO_INIT_PRIORITY int "Init priority" diff --git a/drivers/mdio/Kconfig.nxp_enet b/drivers/mdio/Kconfig.nxp_enet new file mode 100644 index 00000000000..dd3c734e1b3 --- /dev/null +++ b/drivers/mdio/Kconfig.nxp_enet @@ -0,0 +1,21 @@ +# Copyright 2023 NXP +# SPDX-License-Identifier: Apache-2.0 + +config MDIO_NXP_ENET + bool "NXP ENET MDIO Driver" + default y + depends on DT_HAS_NXP_ENET_MDIO_ENABLED + help + Enable NXP ENET MDIO Driver. This Kconfig can be disabled manually + if all ethernet PHYs being used with ENET are not managed by MDIO bus. + +if MDIO_NXP_ENET + +config MDIO_NXP_ENET_TIMEOUT + int "NXP ENET MDIO Timeout time" + default 1 + help + Time in milliseconds before an MDIO transaction that has not + finished is considered to have timed out. + +endif # MDIO_NXP_ENET diff --git a/drivers/mdio/mdio_nxp_enet.c b/drivers/mdio/mdio_nxp_enet.c new file mode 100644 index 00000000000..c1a3df31692 --- /dev/null +++ b/drivers/mdio/mdio_nxp_enet.c @@ -0,0 +1,297 @@ +/* + * Copyright 2023 NXP + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#define DT_DRV_COMPAT nxp_enet_mdio + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +/* Target MDC frequency 2.5 MHz */ +#define NXP_ENET_MDIO_MDC_FREQ 25000000U + +struct nxp_enet_mdio_config { + ENET_Type *base; + const struct pinctrl_dev_config *pincfg; + const struct device *clock_dev; + clock_control_subsys_t clock_subsys; + uint16_t timeout; + bool disable_preamble; +}; + +struct nxp_enet_mdio_data { + struct k_mutex mdio_mutex; + struct k_sem mdio_sem; + bool interrupt_up; +}; + +/* + * This function is used for both read and write operations + * in order to wait for the completion of an MDIO transaction. + * It returns -ETIMEDOUT if timeout occurs as specified in DT, + * otherwise returns 0 if EIR MII bit is set indicting completed + * operation, otherwise -EIO. + */ +static int nxp_enet_mdio_wait_xfer(const struct device *dev) +{ + const struct nxp_enet_mdio_config *config = dev->config; + struct nxp_enet_mdio_data *data = dev->data; + ENET_Type *base = config->base; + int ret = 0; + + /* This function will not make sense from IRQ context */ + if (k_is_in_isr()) { + return -EWOULDBLOCK; + } + + /* Enable the interrupt */ + base->EIMR |= ENET_EIMR_MII_MASK; + + /* Wait for operation to complete or time out */ + if (!data->interrupt_up) { + /* In the case where the interrupt has not been enabled yet because + * ethernet driver has not initiaized, just do a busy wait + */ + k_busy_wait(USEC_PER_MSEC * config->timeout); + if (base->EIR && ENET_EIR_MII_MASK == ENET_EIR_MII_MASK) { + ret = 0; + } else { + ret = -ETIMEDOUT; + } + } else if (k_sem_take(&data->mdio_sem, K_MSEC(config->timeout))) { + /* Interrupt was enabled but did not occur in time */ + ret = -ETIMEDOUT; + } else if (base->EIR && ENET_EIR_MII_MASK == ENET_EIR_MII_MASK) { + /* Interrupt happened meaning mdio transaction completed */ + ret = 0; + } else { + /* No idea what happened */ + ret = -EIO; + } + + return ret; +} + +/* MDIO Read API implementation */ +static int nxp_enet_mdio_read(const struct device *dev, + uint8_t prtad, uint8_t regad, uint16_t *read_data) +{ + const struct nxp_enet_mdio_config *config = dev->config; + struct nxp_enet_mdio_data *data = dev->data; + int ret; + + /* Only one MDIO bus operation attempt at a time */ + (void)k_mutex_lock(&data->mdio_mutex, K_FOREVER); + + /* + * Clear the bit (W1C) that indicates MDIO transfer is ready to + * prepare to wait for it to be set once this read is done + */ + config->base->EIR |= ENET_EIR_MII_MASK; + + /* + * Write MDIO frame to MII management register which will + * send the read command and data out to the MDIO bus as this frame: + * ST = start, 1 means start + * OP = operation, 2 means read + * PA = PHY/Port address + * RA = Register/Device Address + * TA = Turnaround, must be 2 to be valid + * data = data to be written to the PHY register + */ + config->base->MMFR = ENET_MMFR_ST(0x1U) | + ENET_MMFR_OP(MDIO_OP_C22_READ) | + ENET_MMFR_PA(prtad) | + ENET_MMFR_RA(regad) | + ENET_MMFR_TA(0x2U); + + ret = nxp_enet_mdio_wait_xfer(dev); + if (ret) { + (void)k_mutex_unlock(&data->mdio_mutex); + return ret; + } + + /* The data is received in the same register that we wrote the command to */ + *read_data = (config->base->MMFR & ENET_MMFR_DATA_MASK) >> ENET_MMFR_DATA_SHIFT; + + /* Clear the same bit as before because the event has been handled */ + config->base->EIR |= ENET_EIR_MII_MASK; + + /* This MDIO interaction is finished */ + (void)k_mutex_unlock(&data->mdio_mutex); + + return ret; +} + +/* MDIO Write API implementation */ +static int nxp_enet_mdio_write(const struct device *dev, + uint8_t prtad, uint8_t regad, uint16_t write_data) +{ + const struct nxp_enet_mdio_config *config = dev->config; + struct nxp_enet_mdio_data *data = dev->data; + int ret; + + /* Only one MDIO bus operation attempt at a time */ + (void)k_mutex_lock(&data->mdio_mutex, K_FOREVER); + + /* + * Clear the bit (W1C) that indicates MDIO transfer is ready to + * prepare to wait for it to be set once this write is done + */ + config->base->EIR |= ENET_EIR_MII_MASK; + + /* + * Write MDIO frame to MII management register which will + * send the write command and data out to the MDIO bus as this frame: + * ST = start, 1 means start + * OP = operation, 1 means write + * PA = PHY/Port address + * RA = Register/Device Address + * TA = Turnaround, must be 2 to be valid + * data = data to be written to the PHY register + */ + config->base->MMFR = ENET_MMFR_ST(0x1U) | + ENET_MMFR_OP(MDIO_OP_C22_WRITE) | + ENET_MMFR_PA(prtad) | + ENET_MMFR_RA(regad) | + ENET_MMFR_TA(0x2U) | + write_data; + + ret = nxp_enet_mdio_wait_xfer(dev); + if (ret) { + (void)k_mutex_unlock(&data->mdio_mutex); + return ret; + } + + /* Clear the same bit as before because the event has been handled */ + config->base->EIR |= ENET_EIR_MII_MASK; + + /* This MDIO interaction is finished */ + (void)k_mutex_unlock(&data->mdio_mutex); + + return ret; +} + +/* MDIO bus enable/disable "implementation" */ +static void nxp_enet_mdio_bus_fn(const struct device *dev) +{ + /* + * MDIO bus device is actually part of ethernet device, and + * does not support ability to disable/enable MDIO bus hardware + * independently of the ethernet/MAC hardware, so do nothing. + */ +} + +static const struct mdio_driver_api nxp_enet_mdio_api = { + .read = nxp_enet_mdio_read, + .write = nxp_enet_mdio_write, + .bus_enable = nxp_enet_mdio_bus_fn, + .bus_disable = nxp_enet_mdio_bus_fn, +}; + +static void nxp_enet_mdio_isr_cb(const struct device *dev) +{ + const struct nxp_enet_mdio_config *config = dev->config; + struct nxp_enet_mdio_data *data = dev->data; + + /* Signal that operation finished */ + k_sem_give(&data->mdio_sem); + + /* Disable the interrupt */ + config->base->EIMR &= ~ENET_EIMR_MII_MASK; +} + +static void nxp_enet_mdio_post_module_reset_init(const struct device *dev) +{ + const struct nxp_enet_mdio_config *config = dev->config; + uint32_t enet_module_clock_rate; + + /* Set up MSCR register */ + (void) clock_control_get_rate(config->clock_dev, config->clock_subsys, + &enet_module_clock_rate); + uint32_t mii_speed = (enet_module_clock_rate + 2 * NXP_ENET_MDIO_MDC_FREQ - 1) / + (2 * NXP_ENET_MDIO_MDC_FREQ) - 1; + uint32_t holdtime = (10 + NSEC_PER_SEC / enet_module_clock_rate - 1) / + (NSEC_PER_SEC / enet_module_clock_rate) - 1; + uint32_t mscr = ENET_MSCR_MII_SPEED(mii_speed) | ENET_MSCR_HOLDTIME(holdtime) | + (config->disable_preamble ? ENET_MSCR_DIS_PRE_MASK : 0); + config->base->MSCR = mscr; +} + +void nxp_enet_mdio_callback(const struct device *dev, + enum nxp_enet_callback_reason event) +{ + struct nxp_enet_mdio_data *data = dev->data; + + switch (event) { + case nxp_enet_module_reset: + nxp_enet_mdio_post_module_reset_init(dev); + break; + case nxp_enet_interrupt: + nxp_enet_mdio_isr_cb(dev); + break; + case nxp_enet_interrupt_enabled: + data->interrupt_up = true; + break; + default: + } +} + +static int nxp_enet_mdio_init(const struct device *dev) +{ + const struct nxp_enet_mdio_config *config = dev->config; + struct nxp_enet_mdio_data *data = dev->data; + int ret = 0; + + ret = pinctrl_apply_state(config->pincfg, PINCTRL_STATE_DEFAULT); + if (ret) { + return ret; + } + + ret = k_mutex_init(&data->mdio_mutex); + if (ret) { + return ret; + } + + ret = k_sem_init(&data->mdio_sem, 0, 1); + if (ret) { + return ret; + } + + /* All operations done after module reset should be done during device init too */ + nxp_enet_mdio_post_module_reset_init(dev); + + return ret; +} + +#define NXP_ENET_MDIO_INIT(inst) \ + PINCTRL_DT_INST_DEFINE(inst); \ + \ + static const struct nxp_enet_mdio_config nxp_enet_mdio_cfg_##inst = { \ + .base = (ENET_Type *) DT_REG_ADDR(DT_INST_PARENT(inst)), \ + .pincfg = PINCTRL_DT_INST_DEV_CONFIG_GET(inst), \ + .timeout = CONFIG_MDIO_NXP_ENET_TIMEOUT, \ + .clock_dev = DEVICE_DT_GET(DT_CLOCKS_CTLR(DT_INST_PARENT(inst))), \ + .clock_subsys = (void *) DT_CLOCKS_CELL_BY_IDX( \ + DT_INST_PARENT(inst), 0, name), \ + .disable_preamble = DT_INST_PROP(inst, suppress_preamble), \ + }; \ + \ + static struct nxp_enet_mdio_data nxp_enet_mdio_data_##inst; \ + \ + DEVICE_DT_INST_DEFINE(inst, &nxp_enet_mdio_init, NULL, \ + &nxp_enet_mdio_data_##inst, &nxp_enet_mdio_cfg_##inst, \ + POST_KERNEL, CONFIG_MDIO_INIT_PRIORITY, \ + &nxp_enet_mdio_api); + + +DT_INST_FOREACH_STATUS_OKAY(NXP_ENET_MDIO_INIT) diff --git a/drivers/mdio/mdio_shell.c b/drivers/mdio/mdio_shell.c index d0fa925ef36..4cde88a009f 100644 --- a/drivers/mdio/mdio_shell.c +++ b/drivers/mdio/mdio_shell.c @@ -29,6 +29,8 @@ LOG_MODULE_REGISTER(mdio_shell, CONFIG_LOG_DEFAULT_LEVEL); #define DT_DRV_COMPAT smsc_lan91c111_mdio #elif DT_HAS_COMPAT_STATUS_OKAY(zephyr_mdio_gpio) #define DT_DRV_COMPAT zephyr_mdio_gpio +#elif DT_HAS_COMPAT_STATUS_OKAY(nxp_enet_mdio) +#define DT_DRV_COMPAT nxp_enet_mdio #else #error "No known devicetree compatible match for MDIO shell" #endif From fe809c8b24dd2daf7257116fe9a141b6d4c33b07 Mon Sep 17 00:00:00 2001 From: Declan Snyder Date: Mon, 24 Jul 2023 14:06:43 -0500 Subject: [PATCH 0386/3723] drivers: ethernet: Add NXP ENET Driver Add driver for NXP ENET which is a rework of the old eth_mcux.c driver which had become unmaintainable due to fundamental problems with the lack of PHY abstraction. eth_mcux.c and the corresponding compatible nxp,kinetis-ethernet will be deprecated and this new driver will be supported instead. Signed-off-by: Declan Snyder --- drivers/ethernet/CMakeLists.txt | 1 + drivers/ethernet/Kconfig | 1 + drivers/ethernet/Kconfig.nxp_enet | 54 ++ drivers/ethernet/eth_nxp_enet.c | 860 ++++++++++++++++++++++++++++++ 4 files changed, 916 insertions(+) create mode 100644 drivers/ethernet/Kconfig.nxp_enet create mode 100644 drivers/ethernet/eth_nxp_enet.c diff --git a/drivers/ethernet/CMakeLists.txt b/drivers/ethernet/CMakeLists.txt index 8c8795509fd..7b925b3730a 100644 --- a/drivers/ethernet/CMakeLists.txt +++ b/drivers/ethernet/CMakeLists.txt @@ -35,6 +35,7 @@ zephyr_library_sources_ifdef(CONFIG_ETH_SMSC91X eth_smsc91x.c) zephyr_library_sources_ifdef(CONFIG_ETH_IVSHMEM eth_ivshmem.c eth_ivshmem_queue.c) zephyr_library_sources_ifdef(CONFIG_ETH_ADIN2111 eth_adin2111.c) zephyr_library_sources_ifdef(CONFIG_ETH_LAN865X eth_lan865x.c oa_tc6.c) +zephyr_library_sources_ifdef(CONFIG_ETH_NXP_ENET eth_nxp_enet.c) if(CONFIG_ETH_NXP_S32_NETC) zephyr_library_sources(eth_nxp_s32_netc.c) diff --git a/drivers/ethernet/Kconfig b/drivers/ethernet/Kconfig index 69b60e09bc2..e26c0bafb6d 100644 --- a/drivers/ethernet/Kconfig +++ b/drivers/ethernet/Kconfig @@ -63,6 +63,7 @@ source "drivers/ethernet/Kconfig.ivshmem" source "drivers/ethernet/Kconfig.adin2111" source "drivers/ethernet/Kconfig.numaker" source "drivers/ethernet/Kconfig.lan865x" +source "drivers/ethernet/Kconfig.nxp_enet" source "drivers/ethernet/phy/Kconfig" diff --git a/drivers/ethernet/Kconfig.nxp_enet b/drivers/ethernet/Kconfig.nxp_enet new file mode 100644 index 00000000000..a6182ade32d --- /dev/null +++ b/drivers/ethernet/Kconfig.nxp_enet @@ -0,0 +1,54 @@ +# NXP ENET Ethernet driver configuration options + +# Copyright 2023 NXP +# SPDX-License-Identifier: Apache-2.0 + +menuconfig ETH_NXP_ENET + bool "NXP ENET Ethernet driver" + default y + depends on DT_HAS_NXP_ENET_MAC_ENABLED + select NOCACHE_MEMORY if HAS_MCUX_CACHE + select ARM_MPU if CPU_CORTEX_M7 + select MDIO if DT_HAS_NXP_ENET_MDIO_ENABLED + select EXPERIMENTAL + help + Enable NXP ENET Ethernet driver. + +if ETH_NXP_ENET + +config ETH_NXP_ENET_HW_ACCELERATION + bool "Hardware acceleration" + default y + depends on !NET_IPV6 + help + Enable hardware acceleration for the following: + - IPv4, UDP and TCP checksum (both Rx and Tx) + +config ETH_NXP_ENET_USE_DTCM_FOR_DMA_BUFFER + bool "Use DTCM for hardware DMA buffers" + default y + help + Place the hardware DMA buffers into DTCM for better + networking performance. + +config ETH_NXP_ENET_RX_THREAD_STACK_SIZE + int "NXP ENET RX thread stack size" + default 1600 + help + ENET RX thread stack size in bytes. + +config ETH_NXP_ENET_RX_BUFFERS + int "Number of RX buffers for ethernet driver" + default 6 + range 6 16 + help + Set the number of RX buffers provided to the NXP ENET driver. + +config ETH_NXP_ENET_TX_BUFFERS + int "Number of TX buffers for ethernet driver" + default 1 + range 1 16 + help + Set the number of TX buffers provided to the NXP ENET driver. + +endif # ETH_NXP_ENET diff --git a/drivers/ethernet/eth_nxp_enet.c b/drivers/ethernet/eth_nxp_enet.c new file mode 100644 index 00000000000..6dc14bfe8bb --- /dev/null +++ b/drivers/ethernet/eth_nxp_enet.c @@ -0,0 +1,860 @@ +/* NXP ENET MAC Driver + * + * Copyright 2023 NXP + * + * Inspiration from eth_mcux.c, which is: + * Copyright (c) 2016-2017 ARM Ltd + * Copyright (c) 2016 Linaro Ltd + * Copyright (c) 2018 Intel Corporation + * Copyright 2023 NXP + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#define DT_DRV_COMPAT nxp_enet_mac + +/* Set up logging module for this driver */ +#define LOG_MODULE_NAME eth_nxp_enet_mac +#define LOG_LEVEL CONFIG_ETHERNET_LOG_LEVEL +#include +LOG_MODULE_REGISTER(LOG_MODULE_NAME); + +/* + ************ + * Includes * + ************ + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#if defined(CONFIG_NET_DSA) +#include +#endif + +#include "fsl_enet.h" + +/* + *********** + * Defines * + *********** + */ + +#define RING_ID 0 + +/* + ********************* + * Driver Structures * + ********************* + */ + +struct nxp_enet_mac_config { + ENET_Type *base; + const struct device *clock_dev; + clock_control_subsys_t clock_subsys; + void (*generate_mac)(uint8_t *mac_addr); + const struct pinctrl_dev_config *pincfg; + enet_buffer_config_t buffer_config; + uint8_t phy_mode; + void (*irq_config_func)(void); + const struct device *phy_dev; + const struct device *mdio; +}; + +struct nxp_enet_mac_data { + struct net_if *iface; + uint8_t mac_addr[6]; + enet_handle_t enet_handle; + struct k_sem tx_buf_sem; + + K_KERNEL_STACK_MEMBER(rx_thread_stack, CONFIG_ETH_NXP_ENET_RX_THREAD_STACK_SIZE); + + struct k_thread rx_thread; + struct k_sem rx_thread_sem; + struct k_mutex tx_frame_buf_mutex; + struct k_mutex rx_frame_buf_mutex; + /* TODO: FIXME. This Ethernet frame sized buffer is used for + * interfacing with MCUX. How it works is that hardware uses + * DMA scatter buffers to receive a frame, and then public + * MCUX call gathers them into this buffer (there's no other + * public interface). All this happens only for this driver + * to scatter this buffer again into Zephyr fragment buffers. + * This is not efficient, but proper resolution of this issue + * depends on introduction of zero-copy networking support + * in Zephyr, and adding needed interface to MCUX (or + * bypassing it and writing a more complex driver working + * directly with hardware). + * + * Note that we do not copy FCS into this buffer thus the + * size is 1514 bytes. + */ + uint8_t *tx_frame_buf; /* Max MTU + ethernet header */ + uint8_t *rx_frame_buf; /* Max MTU + ethernet header */ +}; + +/* + ******************** + * Helper Functions * + ******************** + */ + +extern void nxp_enet_mdio_callback(const struct device *mdio_dev, + enum nxp_enet_callback_reason event); + +static inline struct net_if *get_iface(struct nxp_enet_mac_data *data, uint16_t vlan_tag) +{ +#if defined(CONFIG_NET_VLAN) + struct net_if *iface; + + iface = net_eth_get_vlan_iface(data->iface, vlan_tag); + if (!iface) { + return data->iface; + } + + return iface; +#else + ARG_UNUSED(vlan_tag); + + return data->iface; +#endif +} + +#if defined(CONFIG_NET_NATIVE_IPV4) || defined(CONFIG_NET_NATIVE_IPV6) +static void net_if_mcast_cb(struct net_if *iface, + const struct net_addr *addr, + bool is_joined) +{ + const struct device *dev = net_if_get_device(iface); + const struct nxp_enet_mac_config *config = dev->config; + struct net_eth_addr mac_addr; + + if (IS_ENABLED(CONFIG_NET_IPV4) && addr->family == AF_INET) { + net_eth_ipv4_mcast_to_mac_addr(&addr->in_addr, &mac_addr); + } else if (IS_ENABLED(CONFIG_NET_IPV6) && addr->family == AF_INET6) { + net_eth_ipv6_mcast_to_mac_addr(&addr->in6_addr, &mac_addr); + } else { + return; + } + + if (is_joined) { + ENET_AddMulticastGroup(config->base, mac_addr.addr); + } else { + ENET_LeaveMulticastGroup(config->base, mac_addr.addr); + } +} +#endif /* CONFIG_NET_NATIVE_IPV4 || CONFIG_NET_NATIVE_IPV6 */ + +/* + ************************************** + * L2 Networking Driver API Functions * + ************************************** + */ + + +static int eth_nxp_enet_tx(const struct device *dev, struct net_pkt *pkt) +{ + const struct nxp_enet_mac_config *config = dev->config; + struct nxp_enet_mac_data *data = dev->data; + uint16_t total_len = net_pkt_get_len(pkt); + status_t status; + + /* Wait for a TX buffer descriptor to be available */ + k_sem_take(&data->tx_buf_sem, K_FOREVER); + + /* Enter critical section for TX frame buffer access */ + k_mutex_lock(&data->tx_frame_buf_mutex, K_FOREVER); + + /* Read network packet from upper layer into frame buffer */ + if (net_pkt_read(pkt, data->tx_frame_buf, total_len)) { + k_sem_give(&data->tx_buf_sem); + k_mutex_unlock(&data->tx_frame_buf_mutex); + return -EIO; + } + + /* Send frame to ring buffer for transmit */ + status = ENET_SendFrame(config->base, &data->enet_handle, + data->tx_frame_buf, total_len, RING_ID, false, NULL); + + if (status) { + LOG_ERR("ENET_SendFrame error: %d", (int)status); + k_mutex_unlock(&data->tx_frame_buf_mutex); + ENET_ReclaimTxDescriptor(config->base, + &data->enet_handle, RING_ID); + return -1; + } + + /* Leave critical section for TX frame buffer access */ + k_mutex_unlock(&data->tx_frame_buf_mutex); + + return 0; +} + +static void eth_nxp_enet_iface_init(struct net_if *iface) +{ + const struct device *dev = net_if_get_device(iface); + struct nxp_enet_mac_data *data = dev->data; + const struct nxp_enet_mac_config *config = dev->config; +#if defined(CONFIG_NET_NATIVE_IPV4) || defined(CONFIG_NET_NATIVE_IPV6) + static struct net_if_mcast_monitor mon; + + net_if_mcast_mon_register(&mon, iface, net_if_mcast_cb); +#endif /* CONFIG_NET_NATIVE_IPV4 || CONFIG_NET_NATIVE_IPV6 */ + + net_if_set_link_addr(iface, data->mac_addr, + sizeof(data->mac_addr), + NET_LINK_ETHERNET); + + /* For VLAN, this value is only used to get the correct L2 driver. + * The iface pointer in context should contain the main interface + * if the VLANs are enabled. + */ + if (data->iface == NULL) { + data->iface = iface; + } + +#if defined(CONFIG_NET_DSA) + dsa_register_master_tx(iface, ð_nxp_enet_tx); +#endif + ethernet_init(iface); + net_eth_carrier_off(data->iface); + + config->irq_config_func(); +} + +static enum ethernet_hw_caps eth_nxp_enet_get_capabilities(const struct device *dev) +{ + ARG_UNUSED(dev); + + return ETHERNET_HW_VLAN | ETHERNET_LINK_10BASE_T | +#if defined(CONFIG_NET_DSA) + ETHERNET_DSA_MASTER_PORT | +#endif +#if defined(CONFIG_ETH_NXP_ENET_HW_ACCELERATION) + ETHERNET_HW_TX_CHKSUM_OFFLOAD | + ETHERNET_HW_RX_CHKSUM_OFFLOAD | +#endif + ETHERNET_LINK_100BASE_T; +} + +static int eth_nxp_enet_set_config(const struct device *dev, + enum ethernet_config_type type, + const struct ethernet_config *cfg) +{ + struct nxp_enet_mac_data *data = dev->data; + const struct nxp_enet_mac_config *config = dev->config; + + switch (type) { + case ETHERNET_CONFIG_TYPE_MAC_ADDRESS: + memcpy(data->mac_addr, + cfg->mac_address.addr, + sizeof(data->mac_addr)); + ENET_SetMacAddr(config->base, data->mac_addr); + net_if_set_link_addr(data->iface, data->mac_addr, + sizeof(data->mac_addr), + NET_LINK_ETHERNET); + LOG_DBG("%s MAC set to %02x:%02x:%02x:%02x:%02x:%02x", + dev->name, + data->mac_addr[0], data->mac_addr[1], + data->mac_addr[2], data->mac_addr[3], + data->mac_addr[4], data->mac_addr[5]); + return 0; + default: + break; + } + + return -ENOTSUP; +} + +/* + ***************************** + * Ethernet RX Functionality * + ***************************** + */ + +static int eth_nxp_enet_rx(const struct device *dev) +{ + const struct nxp_enet_mac_config *config = dev->config; + struct nxp_enet_mac_data *data = dev->data; + uint16_t vlan_tag = NET_VLAN_TAG_UNSPEC; + uint32_t frame_length = 0U; + struct net_if *iface; + struct net_pkt *pkt; + status_t status; + uint32_t ts; + + status = ENET_GetRxFrameSize(&data->enet_handle, + (uint32_t *)&frame_length, RING_ID); + if (status == kStatus_ENET_RxFrameEmpty) { + return 0; + } else if (status == kStatus_ENET_RxFrameError) { + enet_data_error_stats_t error_stats; + + LOG_ERR("ENET_GetRxFrameSize return: %d", (int)status); + + ENET_GetRxErrBeforeReadFrame(&data->enet_handle, + &error_stats, RING_ID); + goto flush; + } + + if (frame_length > NET_ETH_MAX_FRAME_SIZE) { + LOG_ERR("frame too large (%d)", frame_length); + goto flush; + } + + /* Using root iface. It will be updated in net_recv_data() */ + pkt = net_pkt_rx_alloc_with_buffer(data->iface, frame_length, + AF_UNSPEC, 0, K_NO_WAIT); + if (!pkt) { + goto flush; + } + + /* in case multiply thread access + * we need to protect it with mutex. + */ + k_mutex_lock(&data->rx_frame_buf_mutex, K_FOREVER); + + status = ENET_ReadFrame(config->base, &data->enet_handle, + data->rx_frame_buf, frame_length, RING_ID, &ts); + if (status) { + LOG_ERR("ENET_ReadFrame failed: %d", (int)status); + net_pkt_unref(pkt); + + k_mutex_unlock(&data->rx_frame_buf_mutex); + goto error; + } + + if (net_pkt_write(pkt, data->rx_frame_buf, frame_length)) { + LOG_ERR("Unable to write frame into the pkt"); + net_pkt_unref(pkt); + k_mutex_unlock(&data->rx_frame_buf_mutex); + goto error; + } + + k_mutex_unlock(&data->rx_frame_buf_mutex); + +#if defined(CONFIG_NET_VLAN) + { + struct net_eth_hdr *hdr = NET_ETH_HDR(pkt); + + if (ntohs(hdr->type) == NET_ETH_PTYPE_VLAN) { + struct net_eth_vlan_hdr *hdr_vlan = + (struct net_eth_vlan_hdr *)NET_ETH_HDR(pkt); + + net_pkt_set_vlan_tci(pkt, ntohs(hdr_vlan->vlan.tci)); + vlan_tag = net_pkt_vlan_tag(pkt); + +#if CONFIG_NET_TC_RX_COUNT > 1 + { + enum net_priority prio; + + prio = net_vlan2priority( + net_pkt_vlan_priority(pkt)); + net_pkt_set_priority(pkt, prio); + } +#endif /* CONFIG_NET_TC_RX_COUNT > 1 */ + } + } +#endif /* CONFIG_NET_VLAN */ + + iface = get_iface(data, vlan_tag); +#if defined(CONFIG_NET_DSA) + iface = dsa_net_recv(iface, &pkt); +#endif + if (net_recv_data(iface, pkt) < 0) { + net_pkt_unref(pkt); + goto error; + } + + return 1; +flush: + /* Flush the current read buffer. This operation can + * only report failure if there is no frame to flush, + * which cannot happen in this context. + */ + status = ENET_ReadFrame(config->base, &data->enet_handle, NULL, + 0, RING_ID, NULL); + __ASSERT_NO_MSG(status == kStatus_Success); +error: + eth_stats_update_errors_rx(get_iface(data, vlan_tag)); + return -EIO; +} + +static void eth_nxp_enet_rx_thread(void *arg1, void *unused1, void *unused2) +{ + const struct device *dev = arg1; + const struct nxp_enet_mac_config *config = dev->config; + struct nxp_enet_mac_data *data = dev->data; + + while (1) { + if (k_sem_take(&data->rx_thread_sem, K_FOREVER) == 0) { + while (eth_nxp_enet_rx(dev) == 1) { + ; + } + /* enable the IRQ for RX */ + ENET_EnableInterrupts(config->base, + kENET_RxFrameInterrupt | kENET_RxBufferInterrupt); + } + } +} + +/* + **************************** + * PHY management functions * + **************************** + */ + +static int nxp_enet_phy_reset_and_configure(const struct device *phy) +{ + int ret = 0; + + /* Reset the PHY */ + ret = phy_write(phy, MII_BMCR, MII_BMCR_RESET); + if (ret) { + return ret; + } + + /* 802.3u standard says reset takes up to 0.5s */ + k_busy_wait(500000); + + /* Configure the PHY */ + ret = phy_configure_link(phy, LINK_HALF_10BASE_T | + LINK_FULL_10BASE_T | + LINK_HALF_100BASE_T | + LINK_FULL_100BASE_T); + if (ret) { + return ret; + } + + return ret; +} + +static void nxp_enet_phy_cb(const struct device *phy, + struct phy_link_state *state, + void *eth_dev) +{ + const struct device *dev = eth_dev; + struct nxp_enet_mac_data *data = dev->data; + + if (!data->iface) { + return; + } + + if (!state->is_up) { + net_eth_carrier_off(data->iface); + nxp_enet_phy_reset_and_configure(phy); + } else { + net_eth_carrier_on(data->iface); + } +} + + +static int nxp_enet_phy_init(const struct device *dev) +{ + const struct nxp_enet_mac_config *config = dev->config; + int ret = 0; + + ret = nxp_enet_phy_reset_and_configure(config->phy_dev); + if (ret) { + return ret; + } + + ret = phy_link_callback_set(config->phy_dev, nxp_enet_phy_cb, (void *)dev); + if (ret) { + return ret; + } + + return ret; +} + +/* + **************************** + * Callbacks and interrupts * + **************************** + */ + +static void eth_callback(ENET_Type *base, enet_handle_t *handle, +#if FSL_FEATURE_ENET_QUEUE > 1 + uint32_t ringId, +#endif /* FSL_FEATURE_ENET_QUEUE > 1 */ + enet_event_t event, enet_frame_info_t *frameinfo, void *param) +{ + const struct device *dev = param; + const struct nxp_enet_mac_config *config = dev->config; + struct nxp_enet_mac_data *data = dev->data; + + switch (event) { + case kENET_RxEvent: + k_sem_give(&data->rx_thread_sem); + break; + case kENET_TxEvent: + /* Free the TX buffer. */ + k_sem_give(&data->tx_buf_sem); + break; + case kENET_ErrEvent: + /* Error event: BABR/BABT/EBERR/LC/RL/UN/PLR. */ + break; + case kENET_WakeUpEvent: + /* Wake up from sleep mode event. */ + break; + case kENET_TimeStampEvent: + /* Time stamp event. */ + /* Reset periodic timer to default value. */ + config->base->ATPER = NSEC_PER_SEC; + break; + case kENET_TimeStampAvailEvent: + /* Time stamp available event. */ + break; + } +} + +static void eth_nxp_enet_isr(const struct device *dev) +{ + const struct nxp_enet_mac_config *config = dev->config; + struct nxp_enet_mac_data *data = dev->data; + unsigned int irq_lock_key = irq_lock(); + + uint32_t eir = ENET_GetInterruptStatus(config->base); + + if (eir & (kENET_RxBufferInterrupt | kENET_RxFrameInterrupt)) { +#if FSL_FEATURE_ENET_QUEUE > 1 + /* Only use ring 0 in this driver */ + ENET_ReceiveIRQHandler(config->base, &data->enet_handle, 0); +#else + ENET_ReceiveIRQHandler(config->base, &data->enet_handle); +#endif + ENET_DisableInterrupts(config->base, kENET_RxFrameInterrupt | + kENET_RxBufferInterrupt); + } + + if (eir & kENET_TxFrameInterrupt) { +#if FSL_FEATURE_ENET_QUEUE > 1 + ENET_TransmitIRQHandler(config->base, &data->enet_handle, 0); +#else + ENET_TransmitIRQHandler(config->base, &data->enet_handle); +#endif + } + + if (eir & kENET_TxBufferInterrupt) { + ENET_ClearInterruptStatus(config->base, kENET_TxBufferInterrupt); + ENET_DisableInterrupts(config->base, kENET_TxBufferInterrupt); + } + + if (eir & ENET_EIR_MII_MASK) { + /* Callback to MDIO driver for relevant interrupt */ + nxp_enet_mdio_callback(config->mdio, nxp_enet_interrupt); + } + + irq_unlock(irq_lock_key); +} + + +/* + ****************** + * Initialization * + ****************** + */ + +static int eth_nxp_enet_init(const struct device *dev) +{ + struct nxp_enet_mac_data *data = dev->data; + const struct nxp_enet_mac_config *config = dev->config; + enet_config_t enet_config; + uint32_t enet_module_clock_rate; + int err; + + err = pinctrl_apply_state(config->pincfg, PINCTRL_STATE_DEFAULT); + if (err) { + return err; + } + + /* Initialize kernel objects */ + k_mutex_init(&data->rx_frame_buf_mutex); + k_mutex_init(&data->tx_frame_buf_mutex); + k_sem_init(&data->rx_thread_sem, 0, CONFIG_ETH_NXP_ENET_RX_BUFFERS); + k_sem_init(&data->tx_buf_sem, + CONFIG_ETH_NXP_ENET_TX_BUFFERS, CONFIG_ETH_NXP_ENET_TX_BUFFERS); + + if (config->generate_mac) { + config->generate_mac(data->mac_addr); + } + + /* Start interruption-poll thread */ + k_thread_create(&data->rx_thread, data->rx_thread_stack, + K_KERNEL_STACK_SIZEOF(data->rx_thread_stack), + eth_nxp_enet_rx_thread, (void *) dev, NULL, NULL, + K_PRIO_COOP(2), + 0, K_NO_WAIT); + k_thread_name_set(&data->rx_thread, "eth_nxp_enet_rx"); + + /* Get ENET IP module clock rate */ + err = clock_control_get_rate(config->clock_dev, config->clock_subsys, + &enet_module_clock_rate); + if (err) { + return err; + } + + /* Use HAL to set up MAC configuration */ + ENET_GetDefaultConfig(&enet_config); + + if (IS_ENABLED(CONFIG_NET_PROMISCUOUS_MODE)) { + enet_config.macSpecialConfig |= kENET_ControlPromiscuousEnable; + } + + if (IS_ENABLED(CONFIG_NET_VLAN)) { + enet_config.macSpecialConfig |= kENET_ControlVLANTagEnable; + } + +#if defined(CONFIG_ETH_NXP_ENET_HW_ACCELERATION) + enet_config.txAccelerConfig |= + kENET_TxAccelIpCheckEnabled | kENET_TxAccelProtoCheckEnabled; + enet_config.rxAccelerConfig |= + kENET_RxAccelIpCheckEnabled | kENET_RxAccelProtoCheckEnabled; +#endif + + enet_config.interrupt |= kENET_RxFrameInterrupt; + enet_config.interrupt |= kENET_TxFrameInterrupt; + + if (config->phy_mode == NXP_ENET_MII_MODE) { + enet_config.miiMode = kENET_MiiMode; + } else if (config->phy_mode == NXP_ENET_RMII_MODE) { + enet_config.miiMode = kENET_RmiiMode; + } else { + return -EINVAL; + } + + enet_config.callback = eth_callback; + enet_config.userData = (void *)dev; + + ENET_Init(config->base, + &data->enet_handle, + &enet_config, + &config->buffer_config, + data->mac_addr, + enet_module_clock_rate); + + nxp_enet_mdio_callback(config->mdio, nxp_enet_module_reset); + + ENET_ActiveRead(config->base); + + err = nxp_enet_phy_init(dev); + if (err) { + return err; + } + + LOG_DBG("%s MAC %02x:%02x:%02x:%02x:%02x:%02x", + dev->name, + data->mac_addr[0], data->mac_addr[1], + data->mac_addr[2], data->mac_addr[3], + data->mac_addr[4], data->mac_addr[5]); + + return 0; +} + +static const struct ethernet_api api_funcs = { + .iface_api.init = eth_nxp_enet_iface_init, + .get_capabilities = eth_nxp_enet_get_capabilities, + .set_config = eth_nxp_enet_set_config, + .send = eth_nxp_enet_tx, +#if defined(CONFIG_NET_DSA) + .send = dsa_tx, +#else +}; + +#define NXP_ENET_CONNECT_IRQ(node_id, irq_names, idx) \ + do { \ + IRQ_CONNECT(DT_IRQ_BY_IDX(node_id, idx, irq), \ + DT_IRQ_BY_IDX(node_id, idx, priority), \ + eth_nxp_enet_isr, \ + DEVICE_DT_GET(node_id), \ + 0); \ + irq_enable(DT_IRQ_BY_IDX(node_id, idx, irq)); \ + } while (false); + +#define FREESCALE_OUI_B0 0x00 +#define FREESCALE_OUI_B1 0x04 +#define FREESCALE_OUI_B2 0x9f + +#if defined(CONFIG_SOC_SERIES_IMX_RT10XX) +#define ETH_NXP_ENET_UNIQUE_ID (OCOTP->CFG1 ^ OCOTP->CFG2) +#elif defined(CONFIG_SOC_SERIES_IMX_RT11XX) +#define ETH_NXP_ENET_UNIQUE_ID (OCOTP->FUSEN[40].FUSE) +#elif defined(CONFIG_SOC_SERIES_KINETIS_K6X) +#define ETH_NXP_ENET_UNIQUE_ID (SIM->UIDH ^ SIM->UIDMH ^ SIM->UIDML ^ SIM->UIDL) +#else +#error "Unsupported SOC" +#endif + +#define NXP_ENET_GENERATE_MAC_RANDOM(n) \ + static void generate_eth_##n##_mac(uint8_t *mac_addr) \ + { \ + gen_random_mac(mac_addr, \ + FREESCALE_OUI_B0, \ + FREESCALE_OUI_B1, \ + FREESCALE_OUI_B2); \ + } + +#define NXP_ENET_GENERATE_MAC_UNIQUE(n) \ + static void generate_eth_##n##_mac(uint8_t *mac_addr) \ + { \ + uint32_t id = ETH_NXP_ENET_UNIQUE_ID; \ + \ + mac_addr[0] = FREESCALE_OUI_B0; \ + mac_addr[0] |= 0x02; /* force LAA bit */ \ + mac_addr[1] = FREESCALE_OUI_B1; \ + mac_addr[2] = FREESCALE_OUI_B2; \ + mac_addr[3] = id >> 8; \ + mac_addr[4] = id >> 16; \ + mac_addr[5] = id >> 0; \ + mac_addr[5] += n; \ + } + +#define NXP_ENET_GENERATE_MAC(n) \ + COND_CODE_1(DT_INST_PROP(n, zephyr_random_mac_address), \ + (NXP_ENET_GENERATE_MAC_RANDOM(n)), \ + (NXP_ENET_GENERATE_MAC_UNIQUE(n))) + +#define NXP_ENET_DECIDE_MAC_ADDR(n) \ + COND_CODE_1(NODE_HAS_VALID_MAC_ADDR(DT_DRV_INST(n)), \ + (NXP_ENET_MAC_ADDR_LOCAL(n)), \ + (NXP_ENET_MAC_ADDR_GENERATED(n))) + +#define NXP_ENET_DECIDE_MAC_GEN_FUNC(n) \ + COND_CODE_1(NODE_HAS_VALID_MAC_ADDR(DT_DRV_INST(n)), \ + (NXP_ENET_GEN_MAC_FUNCTION_NO(n)), \ + (NXP_ENET_GEN_MAC_FUNCTION_YES(n))) + +#define NXP_ENET_MAC_ADDR_LOCAL(n) \ + .mac_addr = DT_INST_PROP(n, local_mac_address), + +#define NXP_ENET_MAC_ADDR_GENERATED(n) \ + .mac_addr = {0}, + +#define NXP_ENET_GEN_MAC_FUNCTION_NO(n) \ + .generate_mac = NULL, + +#define NXP_ENET_GEN_MAC_FUNCTION_YES(n) \ + .generate_mac = generate_eth_##n##_mac, + +#define NXP_ENET_DT_PHY_DEV(node_id, phy_phandle, idx) \ + DEVICE_DT_GET(DT_PHANDLE_BY_IDX(node_id, phy_phandle, idx)) + +#if DT_NODE_HAS_STATUS(DT_CHOSEN(zephyr_dtcm), okay) && \ + CONFIG_ETH_NXP_ENET_USE_DTCM_FOR_DMA_BUFFER +/* Use DTCM for hardware DMA buffers */ +#define _nxp_enet_dma_desc_section __dtcm_bss_section +#define _nxp_enet_dma_buffer_section __dtcm_noinit_section +#define _nxp_enet_driver_buffer_section __dtcm_noinit_section +#elif defined(CONFIG_NOCACHE_MEMORY) +#define _nxp_enet_dma_desc_section __nocache +#define _nxp_enet_dma_buffer_section __nocache +#define _nxp_enet_driver_buffer_section +#else +#define _nxp_enet_dma_desc_section +#define _nxp_enet_dma_buffer_section +#define _nxp_enet_driver_buffer_section +#endif + + /* Use ENET_FRAME_MAX_VLANFRAMELEN for VLAN frame size + * Use ENET_FRAME_MAX_FRAMELEN for Ethernet frame size + */ +#if defined(CONFIG_NET_VLAN) +#if !defined(ENET_FRAME_MAX_VLANFRAMELEN) +#define ENET_FRAME_MAX_VLANFRAMELEN (ENET_FRAME_MAX_FRAMELEN + 4) +#endif +#define ETH_NXP_ENET_BUFFER_SIZE \ + ROUND_UP(ENET_FRAME_MAX_VLANFRAMELEN, ENET_BUFF_ALIGNMENT) +#else +#define ETH_NXP_ENET_BUFFER_SIZE \ + ROUND_UP(ENET_FRAME_MAX_FRAMELEN, ENET_BUFF_ALIGNMENT) +#endif /* CONFIG_NET_VLAN */ + +#define NXP_ENET_PHY_MODE(node_id) \ + DT_ENUM_HAS_VALUE(node_id, phy_connection_type, mii) ? NXP_ENET_MII_MODE : \ + (DT_ENUM_HAS_VALUE(node_id, phy_connection_type, rmii) ? NXP_ENET_RMII_MODE : \ + NXP_ENET_INVALID_MII_MODE) + +#define NXP_ENET_INIT(n) \ + NXP_ENET_GENERATE_MAC(n) \ + \ + PINCTRL_DT_INST_DEFINE(n); \ + \ + static void nxp_enet_##n##_irq_config_func(void) \ + { \ + DT_INST_FOREACH_PROP_ELEM(n, interrupt_names, \ + NXP_ENET_CONNECT_IRQ); \ + } \ + \ + volatile static __aligned(ENET_BUFF_ALIGNMENT) \ + _nxp_enet_dma_desc_section \ + enet_rx_bd_struct_t \ + nxp_enet_##n##_rx_buffer_desc[CONFIG_ETH_NXP_ENET_RX_BUFFERS]; \ + \ + volatile static __aligned(ENET_BUFF_ALIGNMENT) \ + _nxp_enet_dma_desc_section \ + enet_tx_bd_struct_t \ + nxp_enet_##n##_tx_buffer_desc[CONFIG_ETH_NXP_ENET_TX_BUFFERS]; \ + \ + static uint8_t __aligned(ENET_BUFF_ALIGNMENT) \ + _nxp_enet_dma_buffer_section \ + nxp_enet_##n##_rx_buffer[CONFIG_ETH_NXP_ENET_RX_BUFFERS] \ + [ETH_NXP_ENET_BUFFER_SIZE]; \ + \ + static uint8_t __aligned(ENET_BUFF_ALIGNMENT) \ + _nxp_enet_dma_buffer_section \ + nxp_enet_##n##_tx_buffer[CONFIG_ETH_NXP_ENET_TX_BUFFERS] \ + [ETH_NXP_ENET_BUFFER_SIZE]; \ + \ + const struct nxp_enet_mac_config nxp_enet_##n##_config = { \ + .base = (ENET_Type *)DT_REG_ADDR(DT_INST_PARENT(n)), \ + .irq_config_func = nxp_enet_##n##_irq_config_func, \ + .clock_dev = DEVICE_DT_GET(DT_CLOCKS_CTLR(DT_INST_PARENT(n))), \ + .clock_subsys = (void *)DT_CLOCKS_CELL_BY_IDX( \ + DT_INST_PARENT(n), 0, name), \ + .pincfg = PINCTRL_DT_INST_DEV_CONFIG_GET(n), \ + .buffer_config = { \ + .rxBdNumber = CONFIG_ETH_NXP_ENET_RX_BUFFERS, \ + .txBdNumber = CONFIG_ETH_NXP_ENET_TX_BUFFERS, \ + .rxBuffSizeAlign = ETH_NXP_ENET_BUFFER_SIZE, \ + .txBuffSizeAlign = ETH_NXP_ENET_BUFFER_SIZE, \ + .rxBdStartAddrAlign = nxp_enet_##n##_rx_buffer_desc, \ + .txBdStartAddrAlign = nxp_enet_##n##_tx_buffer_desc, \ + .rxBufferAlign = nxp_enet_##n##_rx_buffer[0], \ + .txBufferAlign = nxp_enet_##n##_tx_buffer[0], \ + .rxMaintainEnable = true, \ + .txMaintainEnable = true, \ + .txFrameInfo = NULL, \ + }, \ + .phy_mode = NXP_ENET_PHY_MODE(DT_DRV_INST(n)), \ + .phy_dev = DEVICE_DT_GET(DT_INST_PHANDLE(n, phy_handle)), \ + .mdio = DEVICE_DT_GET(DT_INST_PHANDLE(n, nxp_mdio)), \ + NXP_ENET_DECIDE_MAC_GEN_FUNC(n) \ + }; \ + \ + static _nxp_enet_driver_buffer_section uint8_t \ + nxp_enet_##n##_tx_frame_buf[NET_ETH_MAX_FRAME_SIZE]; \ + static _nxp_enet_driver_buffer_section uint8_t \ + nxp_enet_##n##_rx_frame_buf[NET_ETH_MAX_FRAME_SIZE]; \ + \ + struct nxp_enet_mac_data nxp_enet_##n##_data = { \ + NXP_ENET_DECIDE_MAC_ADDR(n) \ + .tx_frame_buf = nxp_enet_##n##_tx_frame_buf, \ + .rx_frame_buf = nxp_enet_##n##_rx_frame_buf, \ + }; \ + \ + ETH_NET_DEVICE_DT_INST_DEFINE(n, eth_nxp_enet_init, NULL, \ + &nxp_enet_##n##_data, &nxp_enet_##n##_config, \ + CONFIG_ETH_INIT_PRIORITY, \ + &api_funcs, NET_ETH_MTU); + +DT_INST_FOREACH_STATUS_OKAY(NXP_ENET_INIT) From 0e935ea18097955a5038f29c8eb09c744bda9998 Mon Sep 17 00:00:00 2001 From: Declan Snyder Date: Thu, 24 Aug 2023 11:10:41 -0500 Subject: [PATCH 0387/3723] soc: rt10xx: enable phy clock with new driver when using either old or new driver for nxp enet, enable the phy clock Signed-off-by: Declan Snyder --- soc/arm/nxp_imx/rt/soc_rt10xx.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/soc/arm/nxp_imx/rt/soc_rt10xx.c b/soc/arm/nxp_imx/rt/soc_rt10xx.c index 91ec748a61a..01075ce3582 100644 --- a/soc/arm/nxp_imx/rt/soc_rt10xx.c +++ b/soc/arm/nxp_imx/rt/soc_rt10xx.c @@ -55,7 +55,7 @@ const clock_enet_pll_config_t ethPllConfig = { defined(CONFIG_SOC_MIMXRT1024) .enableClkOutput500M = true, #endif -#ifdef CONFIG_ETH_MCUX +#if defined(CONFIG_ETH_NXP_ENET) || defined(CONFIG_ETH_MCUX) #if DT_NODE_HAS_STATUS(DT_NODELABEL(enet), okay) .enableClkOutput = true, #endif From c8375659fb1fb74cc6562bb61d847de80b05666e Mon Sep 17 00:00:00 2001 From: Declan Snyder Date: Fri, 8 Sep 2023 15:31:05 -0500 Subject: [PATCH 0388/3723] soc: nxp: rt10xx: Increase workqueue size for enet Increase the size of the system workqueue stack if using nxp ethernet driver Signed-off-by: Declan Snyder --- soc/arm/nxp_imx/rt/Kconfig.defconfig.series | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/soc/arm/nxp_imx/rt/Kconfig.defconfig.series b/soc/arm/nxp_imx/rt/Kconfig.defconfig.series index b4e8aeb7422..f8467559d37 100644 --- a/soc/arm/nxp_imx/rt/Kconfig.defconfig.series +++ b/soc/arm/nxp_imx/rt/Kconfig.defconfig.series @@ -75,6 +75,13 @@ config PM_MCUX_PMU endif # SOC_SERIES_IMX_RT10XX && PM +if ETH_NXP_ENET + +config SYSTEM_WORKQUEUE_STACK_SIZE + default 1560 + +endif # ETH_NXP_ENET + DT_CHOSEN_Z_FLASH := zephyr,flash DT_COMPAT_FLEXSPI := nxp,imx-flexspi From 809e936c5e6fae361627ca0e4681ebc28501ba00 Mon Sep 17 00:00:00 2001 From: Declan Snyder Date: Tue, 29 Aug 2023 11:05:46 -0500 Subject: [PATCH 0389/3723] drivers: clock_control_mcux_ccm: Add ENET PLL clk Add subsys value for ENET PLL / ENET Ref clk to CCM Driver Signed-off-by: Declan Snyder --- drivers/clock_control/clock_control_mcux_ccm.c | 5 +++++ include/zephyr/dt-bindings/clock/imx_ccm.h | 1 + 2 files changed, 6 insertions(+) diff --git a/drivers/clock_control/clock_control_mcux_ccm.c b/drivers/clock_control/clock_control_mcux_ccm.c index 8ba1cb7221e..1918673142f 100644 --- a/drivers/clock_control/clock_control_mcux_ccm.c +++ b/drivers/clock_control/clock_control_mcux_ccm.c @@ -236,6 +236,11 @@ static int mcux_ccm_get_subsys_rate(const struct device *dev, *rate = CLOCK_GetIpgFreq(); break; #endif +#ifdef CONFIG_PTP_CLOCK_NXP_ENET + case IMX_CCM_ENET_PLL: + *rate = CLOCK_GetPllFreq(kCLOCK_PllEnet); + break; +#endif #ifdef CONFIG_UART_MCUX_IUART case IMX_CCM_UART1_CLK: diff --git a/include/zephyr/dt-bindings/clock/imx_ccm.h b/include/zephyr/dt-bindings/clock/imx_ccm.h index f5b697e415d..3535c06935e 100644 --- a/include/zephyr/dt-bindings/clock/imx_ccm.h +++ b/include/zephyr/dt-bindings/clock/imx_ccm.h @@ -56,5 +56,6 @@ #define IMX_CCM_QTMR_CLK 0x0D00UL #define IMX_CCM_ENET_CLK 0x0E00UL +#define IMX_CCM_ENET_PLL 0x0E01UL #endif /* ZEPHYR_INCLUDE_DT_BINDINGS_CLOCK_IMX_CCM_H_ */ From 39d056b3c3b76e977ef4d5cd6c1b4c16704b0bfa Mon Sep 17 00:00:00 2001 From: Declan Snyder Date: Tue, 29 Aug 2023 11:02:18 -0500 Subject: [PATCH 0390/3723] dts: bindings: Add NXP ENET PTP binding Add binding for NXP ENET PTP Clock device Signed-off-by: Declan Snyder --- dts/bindings/ethernet/nxp,enet-ptp-clock.yaml | 12 ++++++++++++ 1 file changed, 12 insertions(+) create mode 100644 dts/bindings/ethernet/nxp,enet-ptp-clock.yaml diff --git a/dts/bindings/ethernet/nxp,enet-ptp-clock.yaml b/dts/bindings/ethernet/nxp,enet-ptp-clock.yaml new file mode 100644 index 00000000000..f77e30b3035 --- /dev/null +++ b/dts/bindings/ethernet/nxp,enet-ptp-clock.yaml @@ -0,0 +1,12 @@ +# Copyright 2023 NXP +# SPDX-License-Identifier: Apache-2.0 + +description: NXP ENET PTP (Precision Time Protocol) Clock + +compatible: "nxp,enet-ptp-clock" + +include: ["base.yaml", "pinctrl-device.yaml"] + +properties: + interrupts: + required: true From cc5bd511779d6ae1b117bd89fc76d16eb9347419 Mon Sep 17 00:00:00 2001 From: Declan Snyder Date: Tue, 29 Aug 2023 11:03:10 -0500 Subject: [PATCH 0391/3723] drivers: ptp_clock: Add init priority Kconfig Add ptp clock driver init priority kconfig Signed-off-by: Declan Snyder --- drivers/ptp_clock/Kconfig | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/drivers/ptp_clock/Kconfig b/drivers/ptp_clock/Kconfig index 9417d7f0633..fc3f7c61f8c 100644 --- a/drivers/ptp_clock/Kconfig +++ b/drivers/ptp_clock/Kconfig @@ -5,3 +5,13 @@ config PTP_CLOCK bool "Precision Time Protocol (PTP) Clock drivers" help Enable options for Precision Time Protocol Clock drivers. + +if PTP_CLOCK + +config PTP_CLOCK_INIT_PRIORITY + int "Init priority" + default 75 + help + PTP Clock device driver initialization priority + +endif # PTP_CLOCK From d85171fe6f794bcb71192f3c437a376eb2b26527 Mon Sep 17 00:00:00 2001 From: Declan Snyder Date: Tue, 29 Aug 2023 11:04:27 -0500 Subject: [PATCH 0392/3723] drivers: ptp_clock: Add NXP ENET PTP Clock Driver Add Driver for NXP ENET PTP Clock device Signed-off-by: Declan Snyder --- drivers/ptp_clock/CMakeLists.txt | 1 + drivers/ptp_clock/Kconfig | 2 + drivers/ptp_clock/Kconfig.nxp_enet | 9 + drivers/ptp_clock/ptp_clock_nxp_enet.c | 268 ++++++++++++++++++ .../zephyr/drivers/ethernet/eth_nxp_enet.h | 19 ++ 5 files changed, 299 insertions(+) create mode 100644 drivers/ptp_clock/Kconfig.nxp_enet create mode 100644 drivers/ptp_clock/ptp_clock_nxp_enet.c diff --git a/drivers/ptp_clock/CMakeLists.txt b/drivers/ptp_clock/CMakeLists.txt index 7987b588cea..3dfde253e09 100644 --- a/drivers/ptp_clock/CMakeLists.txt +++ b/drivers/ptp_clock/CMakeLists.txt @@ -5,3 +5,4 @@ zephyr_syscall_header(${ZEPHYR_BASE}/include/zephyr/drivers/ptp_clock.h) zephyr_library() zephyr_library_sources_ifdef(CONFIG_PTP_CLOCK ptp_clock.c) +zephyr_library_sources_ifdef(CONFIG_PTP_CLOCK_NXP_ENET ptp_clock_nxp_enet.c) diff --git a/drivers/ptp_clock/Kconfig b/drivers/ptp_clock/Kconfig index fc3f7c61f8c..74ab3e14eb8 100644 --- a/drivers/ptp_clock/Kconfig +++ b/drivers/ptp_clock/Kconfig @@ -8,6 +8,8 @@ config PTP_CLOCK if PTP_CLOCK +source "drivers/ptp_clock/Kconfig.nxp_enet" + config PTP_CLOCK_INIT_PRIORITY int "Init priority" default 75 diff --git a/drivers/ptp_clock/Kconfig.nxp_enet b/drivers/ptp_clock/Kconfig.nxp_enet new file mode 100644 index 00000000000..aa9c8d5e41b --- /dev/null +++ b/drivers/ptp_clock/Kconfig.nxp_enet @@ -0,0 +1,9 @@ +# Copyright 2023 NXP +# SPDX-License-Identifier: Apache-2.0 + +config PTP_CLOCK_NXP_ENET + bool "NXP ENET PTP Clock driver" + default y if DT_HAS_NXP_ENET_PTP_CLOCK_ENABLED && \ + (PTP_CLOCK || NET_L2_PTP) + help + Enable NXP ENET PTP clock support. diff --git a/drivers/ptp_clock/ptp_clock_nxp_enet.c b/drivers/ptp_clock/ptp_clock_nxp_enet.c new file mode 100644 index 00000000000..67f561e9bc0 --- /dev/null +++ b/drivers/ptp_clock/ptp_clock_nxp_enet.c @@ -0,0 +1,268 @@ +/* + * Copyright 2023 NXP + * + * Based on a commit to drivers/ethernet/eth_mcux.c which was: + * Copyright (c) 2018 Intel Coporation + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#define DT_DRV_COMPAT nxp_enet_ptp_clock + +#include +#include +#include +#include +#include +#include + +#include "fsl_enet.h" + +struct ptp_clock_nxp_enet_config { + ENET_Type *base; + const struct pinctrl_dev_config *pincfg; + const struct device *port; + const struct device *clock_dev; + struct device *clock_subsys; + void (*irq_config_func)(void); +}; + +struct ptp_clock_nxp_enet_data { + double clock_ratio; + enet_handle_t enet_handle; + struct k_mutex ptp_mutex; +}; + +static int ptp_clock_nxp_enet_set(const struct device *dev, + struct net_ptp_time *tm) +{ + const struct ptp_clock_nxp_enet_config *config = dev->config; + struct ptp_clock_nxp_enet_data *data = dev->data; + enet_ptp_time_t enet_time; + + enet_time.second = tm->second; + enet_time.nanosecond = tm->nanosecond; + + ENET_Ptp1588SetTimer(config->base, &data->enet_handle, &enet_time); + + return 0; +} + +static int ptp_clock_nxp_enet_get(const struct device *dev, + struct net_ptp_time *tm) +{ + const struct ptp_clock_nxp_enet_config *config = dev->config; + struct ptp_clock_nxp_enet_data *data = dev->data; + enet_ptp_time_t enet_time; + + ENET_Ptp1588GetTimer(config->base, &data->enet_handle, &enet_time); + + tm->second = enet_time.second; + tm->nanosecond = enet_time.nanosecond; + + return 0; +} + +static int ptp_clock_nxp_enet_adjust(const struct device *dev, + int increment) +{ + const struct ptp_clock_nxp_enet_config *config = dev->config; + int ret = 0; + int key; + + if ((increment <= (int32_t)(-NSEC_PER_SEC)) || + (increment >= (int32_t)NSEC_PER_SEC)) { + ret = -EINVAL; + } else { + key = irq_lock(); + if (config->base->ATPER != NSEC_PER_SEC) { + ret = -EBUSY; + } else { + /* Seconds counter is handled by software. Change the + * period of one software second to adjust the clock. + */ + config->base->ATPER = NSEC_PER_SEC - increment; + ret = 0; + } + irq_unlock(key); + } + + return ret; + +} + +static int ptp_clock_nxp_enet_rate_adjust(const struct device *dev, + double ratio) +{ + const struct ptp_clock_nxp_enet_config *config = dev->config; + struct ptp_clock_nxp_enet_data *data = dev->data; + int corr; + int32_t mul; + double val; + uint32_t enet_ref_pll_rate; + + (void) clock_control_get_rate(config->clock_dev, config->clock_subsys, + &enet_ref_pll_rate); + int hw_inc = NSEC_PER_SEC / enet_ref_pll_rate; + + /* No change needed. */ + if ((ratio > 1.0 && ratio - 1.0 < 0.00000001) || + (ratio < 1.0 && 1.0 - ratio < 0.00000001)) { + return 0; + } + + ratio *= data->clock_ratio; + + /* Limit possible ratio. */ + if ((ratio > 1.0 + 1.0/(2 * hw_inc)) || + (ratio < 1.0 - 1.0/(2 * hw_inc))) { + return -EINVAL; + } + + /* Save new ratio. */ + data->clock_ratio = ratio; + + if (ratio < 1.0) { + corr = hw_inc - 1; + val = 1.0 / (hw_inc * (1.0 - ratio)); + } else if (ratio > 1.0) { + corr = hw_inc + 1; + val = 1.0 / (hw_inc * (ratio - 1.0)); + } else { + val = 0; + corr = hw_inc; + } + + if (val >= INT32_MAX) { + /* Value is too high. + * It is not possible to adjust the rate of the clock. + */ + mul = 0; + } else { + mul = val; + } + + k_mutex_lock(&data->ptp_mutex, K_FOREVER); + + ENET_Ptp1588AdjustTimer(config->base, corr, mul); + + k_mutex_unlock(&data->ptp_mutex); + + return 0; +} + +void nxp_enet_ptp_clock_callback(const struct device *dev, + enum nxp_enet_callback_reason event, + union nxp_enet_ptp_data *ptp_data) +{ + const struct ptp_clock_nxp_enet_config *config = dev->config; + struct ptp_clock_nxp_enet_data *data = dev->data; + + if (event == nxp_enet_module_reset) { + enet_ptp_config_t ptp_config; + uint32_t enet_ref_pll_rate; + uint8_t ptp_multicast[6] = { 0x01, 0x1B, 0x19, 0x00, 0x00, 0x00 }; + uint8_t ptp_peer_multicast[6] = { 0x01, 0x80, 0xC2, 0x00, 0x00, 0x0E }; + + (void) clock_control_get_rate(config->clock_dev, config->clock_subsys, + &enet_ref_pll_rate); + + ENET_AddMulticastGroup(config->base, ptp_multicast); + ENET_AddMulticastGroup(config->base, ptp_peer_multicast); + + /* only for ERRATA_2579 */ + ptp_config.channel = kENET_PtpTimerChannel3; + ptp_config.ptp1588ClockSrc_Hz = enet_ref_pll_rate; + data->clock_ratio = 1.0; + + ENET_Ptp1588SetChannelMode(config->base, kENET_PtpTimerChannel3, + kENET_PtpChannelPulseHighonCompare, true); + ENET_Ptp1588Configure(config->base, &data->enet_handle, + &ptp_config); + } + + if (ptp_data != NULL) { + /* Share the mutex with mac driver */ + ptp_data->for_mac.ptp_mutex = &data->ptp_mutex; + } +} + +static int ptp_clock_nxp_enet_init(const struct device *port) +{ + const struct ptp_clock_nxp_enet_config *config = port->config; + struct ptp_clock_nxp_enet_data *data = port->data; + int ret; + + ret = pinctrl_apply_state(config->pincfg, PINCTRL_STATE_DEFAULT); + if (ret) { + return ret; + } + + k_mutex_init(&data->ptp_mutex); + + config->irq_config_func(); + + return 0; +} + +static void ptp_clock_nxp_enet_isr(const struct device *dev) +{ + const struct ptp_clock_nxp_enet_config *config = dev->config; + struct ptp_clock_nxp_enet_data *data = dev->data; + enet_ptp_timer_channel_t channel; + + unsigned int irq_lock_key = irq_lock(); + + /* clear channel */ + for (channel = kENET_PtpTimerChannel1; channel <= kENET_PtpTimerChannel4; channel++) { + if (ENET_Ptp1588GetChannelStatus(config->base, channel)) { + ENET_Ptp1588ClearChannelStatus(config->base, channel); + } + } + + ENET_TimeStampIRQHandler(config->base, &data->enet_handle); + + irq_unlock(irq_lock_key); +} + +static const struct ptp_clock_driver_api ptp_clock_nxp_enet_api = { + .set = ptp_clock_nxp_enet_set, + .get = ptp_clock_nxp_enet_get, + .adjust = ptp_clock_nxp_enet_adjust, + .rate_adjust = ptp_clock_nxp_enet_rate_adjust, +}; + +#define PTP_CLOCK_NXP_ENET_INIT(n) \ + static void nxp_enet_ptp_clock_##n##_irq_config_func(void) \ + { \ + IRQ_CONNECT(DT_INST_IRQ_BY_IDX(n, 0, irq), \ + DT_INST_IRQ_BY_IDX(n, 0, priority), \ + ptp_clock_nxp_enet_isr, \ + DEVICE_DT_INST_GET(n), \ + 0); \ + irq_enable(DT_INST_IRQ_BY_IDX(n, 0, irq)); \ + } \ + \ + PINCTRL_DT_INST_DEFINE(n); \ + \ + static const struct ptp_clock_nxp_enet_config \ + ptp_clock_nxp_enet_##n##_config = { \ + .base = (ENET_Type *) DT_REG_ADDR(DT_INST_PARENT(n)), \ + .pincfg = PINCTRL_DT_INST_DEV_CONFIG_GET(n), \ + .port = DEVICE_DT_INST_GET(n), \ + .clock_dev = DEVICE_DT_GET(DT_INST_CLOCKS_CTLR(n)), \ + .clock_subsys = (void *) \ + DT_INST_CLOCKS_CELL_BY_IDX(n, 0, name), \ + .irq_config_func = \ + nxp_enet_ptp_clock_##n##_irq_config_func, \ + }; \ + \ + static struct ptp_clock_nxp_enet_data ptp_clock_nxp_enet_##n##_data; \ + \ + DEVICE_DT_INST_DEFINE(n, &ptp_clock_nxp_enet_init, NULL, \ + &ptp_clock_nxp_enet_##n##_data, \ + &ptp_clock_nxp_enet_##n##_config, \ + POST_KERNEL, CONFIG_PTP_CLOCK_INIT_PRIORITY, \ + &ptp_clock_nxp_enet_api); + +DT_INST_FOREACH_STATUS_OKAY(PTP_CLOCK_NXP_ENET_INIT) diff --git a/include/zephyr/drivers/ethernet/eth_nxp_enet.h b/include/zephyr/drivers/ethernet/eth_nxp_enet.h index 1a0be56495b..8dcb5f31c01 100644 --- a/include/zephyr/drivers/ethernet/eth_nxp_enet.h +++ b/include/zephyr/drivers/ethernet/eth_nxp_enet.h @@ -7,7 +7,14 @@ #ifndef ZEPHYR_INCLUDE_DRIVERS_ETH_NXP_ENET_H__ #define ZEPHYR_INCLUDE_DRIVERS_ETH_NXP_ENET_H__ +/* + * This header is for NXP ENET driver development + * and has definitions for internal implementations + * not to be used by application + */ + #include +#include #ifdef __cplusplus extern "C" { @@ -27,10 +34,22 @@ enum nxp_enet_callback_reason { nxp_enet_interrupt_enabled, }; +struct nxp_enet_ptp_data_for_mac { + struct k_mutex *ptp_mutex; +}; + +union nxp_enet_ptp_data { + struct nxp_enet_ptp_data_for_mac for_mac; +}; + /* Calback for mdio device called from mac driver */ void nxp_enet_mdio_callback(const struct device *mdio_dev, enum nxp_enet_callback_reason event); +void nxp_enet_ptp_clock_callback(const struct device *dev, + enum nxp_enet_callback_reason event, + union nxp_enet_ptp_data *ptp_data); + #ifdef __cplusplus } From fa7369773543cf1a1f124dd86ead44a037545cba Mon Sep 17 00:00:00 2001 From: Declan Snyder Date: Tue, 29 Aug 2023 11:08:20 -0500 Subject: [PATCH 0393/3723] drivers: eth_nxp_enet: Support PTP Support PTP functionality in NXP ENET MAC driver Signed-off-by: Declan Snyder --- drivers/ethernet/eth_nxp_enet.c | 193 +++++++++++++++++++++++- dts/bindings/ethernet/nxp,enet-mac.yaml | 6 + 2 files changed, 194 insertions(+), 5 deletions(-) diff --git a/drivers/ethernet/eth_nxp_enet.c b/drivers/ethernet/eth_nxp_enet.c index 6dc14bfe8bb..6620049fcba 100644 --- a/drivers/ethernet/eth_nxp_enet.c +++ b/drivers/ethernet/eth_nxp_enet.c @@ -70,6 +70,9 @@ struct nxp_enet_mac_config { void (*irq_config_func)(void); const struct device *phy_dev; const struct device *mdio; +#ifdef CONFIG_PTP_CLOCK_NXP_ENET + const struct device *ptp_clock; +#endif }; struct nxp_enet_mac_data { @@ -84,6 +87,10 @@ struct nxp_enet_mac_data { struct k_sem rx_thread_sem; struct k_mutex tx_frame_buf_mutex; struct k_mutex rx_frame_buf_mutex; +#ifdef CONFIG_PTP_CLOCK_NXP_ENET + struct k_sem ptp_ts_sem; + struct k_mutex *ptp_mutex; +#endif /* TODO: FIXME. This Ethernet frame sized buffer is used for * interfacing with MCUX. How it works is that hardware uses * DMA scatter buffers to receive a frame, and then public @@ -112,6 +119,10 @@ struct nxp_enet_mac_data { extern void nxp_enet_mdio_callback(const struct device *mdio_dev, enum nxp_enet_callback_reason event); +extern void nxp_enet_ptp_clock_callback(const struct device *dev, + enum nxp_enet_callback_reason event, + union nxp_enet_ptp_data *ptp_data); + static inline struct net_if *get_iface(struct nxp_enet_mac_data *data, uint16_t vlan_tag) { #if defined(CONFIG_NET_VLAN) @@ -155,6 +166,86 @@ static void net_if_mcast_cb(struct net_if *iface, } #endif /* CONFIG_NET_NATIVE_IPV4 || CONFIG_NET_NATIVE_IPV6 */ +/* + ***************** + * PTP Functions * + ***************** + */ + +#if defined(CONFIG_PTP_CLOCK_NXP_ENET) +static bool eth_get_ptp_data(struct net_if *iface, struct net_pkt *pkt) +{ + int eth_hlen; + +#if defined(CONFIG_NET_VLAN) + struct net_eth_vlan_hdr *hdr_vlan; + struct ethernet_context *eth_ctx; + bool vlan_enabled = false; + + eth_ctx = net_if_l2_data(iface); + if (net_eth_is_vlan_enabled(eth_ctx, iface)) { + hdr_vlan = (struct net_eth_vlan_hdr *)NET_ETH_HDR(pkt); + vlan_enabled = true; + + if (ntohs(hdr_vlan->type) != NET_ETH_PTYPE_PTP) { + return false; + } + + eth_hlen = sizeof(struct net_eth_vlan_hdr); + } else +#endif /* CONFIG_NET_VLAN */ + { + if (ntohs(NET_ETH_HDR(pkt)->type) != NET_ETH_PTYPE_PTP) { + return false; + } + + eth_hlen = sizeof(struct net_eth_hdr); + } + + net_pkt_set_priority(pkt, NET_PRIORITY_CA); + + return true; +} + + +#if defined(CONFIG_NET_L2_PTP) +static inline void ts_register_tx_event(const struct device *dev, + enet_frame_info_t *frameinfo) +{ + struct nxp_enet_mac_data *data = dev->data; + struct net_pkt *pkt; + + pkt = frameinfo->context; + if (pkt && atomic_get(&pkt->atomic_ref) > 0) { + if (eth_get_ptp_data(net_pkt_iface(pkt), pkt)) { + if (frameinfo->isTsAvail) { + k_mutex_lock(data->ptp_mutex, K_FOREVER); + + pkt->timestamp.nanosecond = + frameinfo->timeStamp.nanosecond; + pkt->timestamp.second = + frameinfo->timeStamp.second; + + net_if_add_tx_timestamp(pkt); + k_sem_give(&data->ptp_ts_sem); + k_mutex_unlock(data->ptp_mutex); + } + } + + net_pkt_unref(pkt); + } +} +#endif /* CONFIG_NET_L2_PTP */ + +static const struct device *eth_nxp_enet_get_ptp_clock(const struct device *dev) +{ + const struct nxp_enet_mac_config *config = dev->config; + + return config->ptp_clock; +} + +#endif /* CONFIG_PTP_CLOCK_NXP_ENET */ + /* ************************************** * L2 Networking Driver API Functions * @@ -169,6 +260,10 @@ static int eth_nxp_enet_tx(const struct device *dev, struct net_pkt *pkt) uint16_t total_len = net_pkt_get_len(pkt); status_t status; +#if defined(CONFIG_PTP_CLOCK_NXP_ENET) + bool timestamped_frame; +#endif + /* Wait for a TX buffer descriptor to be available */ k_sem_take(&data->tx_buf_sem, K_FOREVER); @@ -182,9 +277,30 @@ static int eth_nxp_enet_tx(const struct device *dev, struct net_pkt *pkt) return -EIO; } - /* Send frame to ring buffer for transmit */ - status = ENET_SendFrame(config->base, &data->enet_handle, - data->tx_frame_buf, total_len, RING_ID, false, NULL); +#if defined(CONFIG_PTP_CLOCK_NXP_ENET) + timestamped_frame = eth_get_ptp_data(net_pkt_iface(pkt), pkt); + if (timestamped_frame) { + status = ENET_SendFrame(config->base, &data->enet_handle, + data->tx_frame_buf, total_len, RING_ID, true, pkt); + if (!status) { + net_pkt_ref(pkt); + /* + * Network stack will modify the packet upon return, + * so wait for the packet to be timestamped, + * which will occur within the TX ISR, before + * returning + */ + k_sem_take(&data->ptp_ts_sem, K_FOREVER); + } + + } else +#endif + { + /* Send frame to ring buffer for transmit */ + status = ENET_SendFrame(config->base, &data->enet_handle, + data->tx_frame_buf, total_len, + RING_ID, false, NULL); + } if (status) { LOG_ERR("ENET_SendFrame error: %d", (int)status); @@ -237,6 +353,9 @@ static enum ethernet_hw_caps eth_nxp_enet_get_capabilities(const struct device * ARG_UNUSED(dev); return ETHERNET_HW_VLAN | ETHERNET_LINK_10BASE_T | +#if defined(CONFIG_PTP_CLOCK_NXP_ENET) + ETHERNET_PTP | +#endif #if defined(CONFIG_NET_DSA) ETHERNET_DSA_MASTER_PORT | #endif @@ -293,6 +412,10 @@ static int eth_nxp_enet_rx(const struct device *dev) status_t status; uint32_t ts; +#if defined(CONFIG_PTP_CLOCK_NXP_ENET) + enet_ptp_time_t ptp_time_data; +#endif + status = ENET_GetRxFrameSize(&data->enet_handle, (uint32_t *)&frame_length, RING_ID); if (status == kStatus_ENET_RxFrameEmpty) { @@ -367,6 +490,32 @@ static int eth_nxp_enet_rx(const struct device *dev) } #endif /* CONFIG_NET_VLAN */ + /* + * Use MAC timestamp + */ +#if defined(CONFIG_PTP_CLOCK_NXP_ENET) + k_mutex_lock(data->ptp_mutex, K_FOREVER); + if (eth_get_ptp_data(get_iface(data, vlan_tag), pkt)) { + ENET_Ptp1588GetTimer(config->base, &data->enet_handle, + &ptp_time_data); + /* If latest timestamp reloads after getting from Rx BD, + * then second - 1 to make sure the actual Rx timestamp is + * accurate + */ + if (ptp_time_data.nanosecond < ts) { + ptp_time_data.second--; + } + + pkt->timestamp.nanosecond = ts; + pkt->timestamp.second = ptp_time_data.second; + } else { + /* Invalid value. */ + pkt->timestamp.nanosecond = UINT32_MAX; + pkt->timestamp.second = UINT64_MAX; + } + k_mutex_unlock(data->ptp_mutex); +#endif /* CONFIG_PTP_CLOCK_NXP_ENET */ + iface = get_iface(data, vlan_tag); #if defined(CONFIG_NET_DSA) iface = dsa_net_recv(iface, &pkt); @@ -498,6 +647,9 @@ static void eth_callback(ENET_Type *base, enet_handle_t *handle, k_sem_give(&data->rx_thread_sem); break; case kENET_TxEvent: +#if defined(CONFIG_PTP_CLOCK_NXP_ENET) && defined(CONFIG_NET_L2_PTP) + ts_register_tx_event(dev, frameinfo); +#endif /* Free the TX buffer. */ k_sem_give(&data->tx_buf_sem); break; @@ -584,6 +736,9 @@ static int eth_nxp_enet_init(const struct device *dev) k_sem_init(&data->rx_thread_sem, 0, CONFIG_ETH_NXP_ENET_RX_BUFFERS); k_sem_init(&data->tx_buf_sem, CONFIG_ETH_NXP_ENET_TX_BUFFERS, CONFIG_ETH_NXP_ENET_TX_BUFFERS); +#if defined(CONFIG_PTP_CLOCK_NXP_ENET) + k_sem_init(&data->ptp_ts_sem, 0, 1); +#endif if (config->generate_mac) { config->generate_mac(data->mac_addr); @@ -645,6 +800,14 @@ static int eth_nxp_enet_init(const struct device *dev) nxp_enet_mdio_callback(config->mdio, nxp_enet_module_reset); +#if defined(CONFIG_PTP_CLOCK_NXP_ENET) + union nxp_enet_ptp_data ptp_data; + + nxp_enet_ptp_clock_callback(config->ptp_clock, nxp_enet_module_reset, &ptp_data); + data->ptp_mutex = ptp_data.for_mac.ptp_mutex; + ENET_SetTxReclaim(&data->enet_handle, true, 0); +#endif + ENET_ActiveRead(config->base); err = nxp_enet_phy_init(dev); @@ -663,12 +826,15 @@ static int eth_nxp_enet_init(const struct device *dev) static const struct ethernet_api api_funcs = { .iface_api.init = eth_nxp_enet_iface_init, +#if defined(CONFIG_PTP_CLOCK_NXP_ENET) + .get_ptp_clock = eth_nxp_enet_get_ptp_clock, +#endif .get_capabilities = eth_nxp_enet_get_capabilities, .set_config = eth_nxp_enet_set_config, .send = eth_nxp_enet_tx, #if defined(CONFIG_NET_DSA) .send = dsa_tx, -#else +#endif }; #define NXP_ENET_CONNECT_IRQ(node_id, irq_names, idx) \ @@ -784,11 +950,27 @@ static const struct ethernet_api api_funcs = { (DT_ENUM_HAS_VALUE(node_id, phy_connection_type, rmii) ? NXP_ENET_RMII_MODE : \ NXP_ENET_INVALID_MII_MODE) +#ifdef CONFIG_PTP_CLOCK_NXP_ENET +#define NXP_ENET_PTP_DEV(n) .ptp_clock = DEVICE_DT_GET(DT_INST_PHANDLE(n, nxp_ptp_clock)), +#define NXP_ENET_FRAMEINFO_ARRAY(n) \ + static enet_frame_info_t \ + nxp_enet_##n##_tx_frameinfo_array[CONFIG_ETH_NXP_ENET_TX_BUFFERS]; +#define NXP_ENET_FRAMEINFO(n) \ + .txFrameInfo = nxp_enet_##n##_tx_frameinfo_array, +#else +#define NXP_ENET_PTP_DEV(n) +#define NXP_ENET_FRAMEINFO_ARRAY(n) +#define NXP_ENET_FRAMEINFO(n) \ + .txFrameInfo = NULL +#endif + #define NXP_ENET_INIT(n) \ NXP_ENET_GENERATE_MAC(n) \ \ PINCTRL_DT_INST_DEFINE(n); \ \ + NXP_ENET_FRAMEINFO_ARRAY(n) \ + \ static void nxp_enet_##n##_irq_config_func(void) \ { \ DT_INST_FOREACH_PROP_ELEM(n, interrupt_names, \ @@ -833,11 +1015,12 @@ static const struct ethernet_api api_funcs = { .txBufferAlign = nxp_enet_##n##_tx_buffer[0], \ .rxMaintainEnable = true, \ .txMaintainEnable = true, \ - .txFrameInfo = NULL, \ + NXP_ENET_FRAMEINFO(n) \ }, \ .phy_mode = NXP_ENET_PHY_MODE(DT_DRV_INST(n)), \ .phy_dev = DEVICE_DT_GET(DT_INST_PHANDLE(n, phy_handle)), \ .mdio = DEVICE_DT_GET(DT_INST_PHANDLE(n, nxp_mdio)), \ + NXP_ENET_PTP_DEV(n) \ NXP_ENET_DECIDE_MAC_GEN_FUNC(n) \ }; \ \ diff --git a/dts/bindings/ethernet/nxp,enet-mac.yaml b/dts/bindings/ethernet/nxp,enet-mac.yaml index af0363b28df..8ca42e769f3 100644 --- a/dts/bindings/ethernet/nxp,enet-mac.yaml +++ b/dts/bindings/ethernet/nxp,enet-mac.yaml @@ -16,3 +16,9 @@ properties: required: true description: | Corresponding mdio device + + nxp,ptp-clock: + type: phandle + required: true + description: | + Corresponding ptp clock device From 789addb02f6cd7479601ed3b487bcf57c2a3919c Mon Sep 17 00:00:00 2001 From: Declan Snyder Date: Tue, 19 Sep 2023 16:25:54 -0500 Subject: [PATCH 0394/3723] boards: mimxrt10xx_evk: Add new enet overlay Add overlay to show how to use new experimental nxp enet driver Also make any eth_mcux related kconfigs dependent on eth_mcux in the boards' defconfigs. Signed-off-by: Declan Snyder --- boards/arm/mimxrt1024_evk/Kconfig.defconfig | 4 + .../dts/mimxrt1024_evk-enet-experimental.dtsi | 135 ++++++++++++++++++ boards/arm/mimxrt1050_evk/Kconfig.defconfig | 4 + .../dts/mimxrt1050_evk-enet-experimental.dtsi | 122 ++++++++++++++++ boards/arm/mimxrt1060_evk/Kconfig.defconfig | 4 + .../dts/mimxrt1060_evk-enet-experimental.dtsi | 122 ++++++++++++++++ boards/arm/mimxrt1064_evk/Kconfig.defconfig | 4 + .../dts/mimxrt1064_evk-enet-experimental.dtsi | 122 ++++++++++++++++ 8 files changed, 517 insertions(+) create mode 100644 boards/arm/mimxrt1024_evk/dts/mimxrt1024_evk-enet-experimental.dtsi create mode 100644 boards/arm/mimxrt1050_evk/dts/mimxrt1050_evk-enet-experimental.dtsi create mode 100644 boards/arm/mimxrt1060_evk/dts/mimxrt1060_evk-enet-experimental.dtsi create mode 100644 boards/arm/mimxrt1064_evk/dts/mimxrt1064_evk-enet-experimental.dtsi diff --git a/boards/arm/mimxrt1024_evk/Kconfig.defconfig b/boards/arm/mimxrt1024_evk/Kconfig.defconfig index 704743ded71..db0a2eb1fed 100644 --- a/boards/arm/mimxrt1024_evk/Kconfig.defconfig +++ b/boards/arm/mimxrt1024_evk/Kconfig.defconfig @@ -27,9 +27,13 @@ if NETWORKING config NET_L2_ETHERNET default y +if ETH_MCUX + config ETH_MCUX_PHY_RESET default y +endif # ETH_MCUX + endif # NETWORKING endif # BOARD_MIMXRT1024_EVK diff --git a/boards/arm/mimxrt1024_evk/dts/mimxrt1024_evk-enet-experimental.dtsi b/boards/arm/mimxrt1024_evk/dts/mimxrt1024_evk-enet-experimental.dtsi new file mode 100644 index 00000000000..2229b2a9b70 --- /dev/null +++ b/boards/arm/mimxrt1024_evk/dts/mimxrt1024_evk-enet-experimental.dtsi @@ -0,0 +1,135 @@ +/* + * Copyright 2023 NXP + * + * Experimental ENET binding overlay + */ + + +/ { + soc { + /delete-node/ ethernet@402d8000; + + enet: enet@402d8000 { + compatible = "nxp,enet"; + reg = <0x402D8000 0x628>; + clocks = <&ccm IMX_CCM_ENET_CLK 0 0>; + enet_mac: ethernet { + compatible = "nxp,enet-mac"; + interrupts = <114 0>; + interrupt-names = "COMMON"; + nxp,mdio = <&enet_mdio>; + nxp,ptp-clock = <&enet_ptp_clock>; + phy-connection-type = "rmii"; + status = "disabled"; + }; + enet_mdio: mdio { + compatible = "nxp,enet-mdio"; + status = "disabled"; + #address-cells = <1>; + #size-cells = <0>; + }; + enet_ptp_clock: ptp_clock { + compatible = "nxp,enet-ptp-clock"; + interrupts = <115 0>; + status = "disabled"; + clocks = <&ccm IMX_CCM_ENET_PLL 0 0>; + }; + }; + }; +}; + +&enet_mac { + status = "okay"; + pinctrl-0 = <&pinmux_enet>; + pinctrl-names = "default"; + phy-handle = <&phy>; +}; + +&enet_mdio { + status = "okay"; + pinctrl-0 = <&pinmux_enet_mdio>; + pinctrl-names = "default"; + phy: phy@0 { + compatible = "microchip,ksz8081"; + reg = <0>; + status = "okay"; + mc,reset-gpio = <&gpio1 4 GPIO_ACTIVE_HIGH>; + mc,interrupt-gpio = <&gpio1 22 GPIO_ACTIVE_HIGH>; + mc,interface-type = "rmii"; + }; +}; + +&enet_ptp_clock { + status = "okay"; + pinctrl-0 = <&pinmux_ptp>; + pinctrl-names = "default"; +}; + + + +&pinctrl { + /delete-node/ pinmux_ptp; + /delete-node/ pinmux_enet; + + pinmux_enet: pinmux_enet { + group0 { + pinmux = <&iomuxc_gpio_ad_b0_08_enet_ref_clk>; + bias-disable; + drive-strength = "r0-6"; + slew-rate = "fast"; + nxp,speed = "50-mhz"; + input-enable; + }; + group1 { + pinmux = <&iomuxc_gpio_ad_b0_09_enet_rx_data1>, + <&iomuxc_gpio_ad_b0_11_enet_rx_en>, + <&iomuxc_gpio_ad_b0_14_enet_tx_data0>, + <&iomuxc_gpio_ad_b0_15_enet_tx_data1>, + <&iomuxc_gpio_ad_b0_13_enet_tx_en>, + <&iomuxc_gpio_ad_b0_12_enet_rx_er>; + drive-strength = "r0-5"; + bias-pull-up; + bias-pull-up-value = "100k"; + slew-rate = "fast"; + nxp,speed = "200-mhz"; + }; + group2 { + pinmux = <&iomuxc_gpio_ad_b0_10_enet_rx_data0>; + drive-strength = "r0-6"; + slew-rate = "slow"; + nxp,speed = "100-mhz"; + }; + }; + + pinmux_enet_mdio: pinmux_enet_mdio { + group0 { + pinmux = <&iomuxc_gpio_emc_40_enet_mdio>, + <&iomuxc_gpio_emc_41_enet_mdc>; + drive-strength = "r0-5"; + bias-pull-up; + bias-pull-up-value = "100k"; + slew-rate = "fast"; + nxp,speed = "200-mhz"; + }; + group1 { + pinmux = <&iomuxc_gpio_ad_b1_06_gpio1_io22>; + drive-strength = "r0-5"; + bias-pull-up; + bias-pull-up-value = "100k"; + slew-rate = "slow"; + nxp,speed = "100-mhz"; + }; + group2 { + pinmux = <&iomuxc_gpio_ad_b0_04_gpio1_io04>; + drive-strength = "r0-5"; + bias-pull-up; + bias-pull-up-value = "100k"; + slew-rate = "fast"; + nxp,speed = "100-mhz"; + }; + }; + + pinmux_ptp: pinmux_ptp { + /* Intentionally empty */ + }; +}; diff --git a/boards/arm/mimxrt1050_evk/Kconfig.defconfig b/boards/arm/mimxrt1050_evk/Kconfig.defconfig index 104c6d77100..79660c08e78 100644 --- a/boards/arm/mimxrt1050_evk/Kconfig.defconfig +++ b/boards/arm/mimxrt1050_evk/Kconfig.defconfig @@ -46,9 +46,13 @@ if NETWORKING config NET_L2_ETHERNET default y +if ETH_MCUX + config ETH_MCUX_PHY_RESET default y +endif # ETH_MCUX + endif # NETWORKING if LVGL diff --git a/boards/arm/mimxrt1050_evk/dts/mimxrt1050_evk-enet-experimental.dtsi b/boards/arm/mimxrt1050_evk/dts/mimxrt1050_evk-enet-experimental.dtsi new file mode 100644 index 00000000000..7fe69f0d52e --- /dev/null +++ b/boards/arm/mimxrt1050_evk/dts/mimxrt1050_evk-enet-experimental.dtsi @@ -0,0 +1,122 @@ +/* + * Copyright 2023 NXP + * + * Experimental ENET binding overlay + */ + + +/ { + soc { + /delete-node/ ethernet@402d8000; + + enet: enet@402d8000 { + compatible = "nxp,enet"; + reg = <0x402D8000 0x628>; + clocks = <&ccm IMX_CCM_ENET_CLK 0 0>; + enet_mac: ethernet { + compatible = "nxp,enet-mac"; + interrupts = <114 0>; + interrupt-names = "COMMON"; + nxp,mdio = <&enet_mdio>; + nxp,ptp-clock = <&enet_ptp_clock>; + phy-connection-type = "rmii"; + status = "disabled"; + }; + enet_mdio: mdio { + compatible = "nxp,enet-mdio"; + status = "disabled"; + #address-cells = <1>; + #size-cells = <0>; + }; + enet_ptp_clock: ptp_clock { + compatible = "nxp,enet-ptp-clock"; + interrupts = <115 0>; + status = "disabled"; + clocks = <&ccm IMX_CCM_ENET_PLL 0 0>; + }; + }; + }; +}; + +&enet_mac { + status = "okay"; + pinctrl-0 = <&pinmux_enet>; + pinctrl-names = "default"; + phy-handle = <&phy>; +}; + +&enet_mdio { + status = "okay"; + pinctrl-0 = <&pinmux_enet_mdio>; + pinctrl-names = "default"; + phy: phy@0 { + compatible = "microchip,ksz8081"; + reg = <0>; + status = "okay"; + mc,reset-gpio = <&gpio1 9 GPIO_ACTIVE_HIGH>; + mc,interrupt-gpio = <&gpio1 10 GPIO_ACTIVE_HIGH>; + mc,interface-type = "rmii"; + }; +}; + +&enet_ptp_clock { + status = "okay"; + pinctrl-0 = <&pinmux_ptp>; + pinctrl-names = "default"; +}; + + + +&pinctrl { + /delete-node/ pinmux_ptp; + /delete-node/ pinmux_enet; + + pinmux_enet: pinmux_enet { + group0 { + pinmux = <&iomuxc_gpio_b1_10_enet_ref_clk>; + bias-disable; + drive-strength = "r0-6"; + slew-rate = "fast"; + nxp,speed = "50-mhz"; + input-enable; + }; + group1 { + pinmux = <&iomuxc_gpio_b1_04_enet_rx_data0>, + <&iomuxc_gpio_b1_05_enet_rx_data1>, + <&iomuxc_gpio_b1_06_enet_rx_en>, + <&iomuxc_gpio_b1_07_enet_tx_data0>, + <&iomuxc_gpio_b1_08_enet_tx_data1>, + <&iomuxc_gpio_b1_09_enet_tx_en>, + <&iomuxc_gpio_b1_11_enet_rx_er>; + drive-strength = "r0-5"; + bias-pull-up; + bias-pull-up-value = "100k"; + slew-rate = "fast"; + nxp,speed = "200-mhz"; + }; + }; + + pinmux_enet_mdio: pinmux_enet_mdio { + group0 { + pinmux = <&iomuxc_gpio_emc_40_enet_mdc>, + <&iomuxc_gpio_emc_41_enet_mdio>, + <&iomuxc_gpio_ad_b0_10_gpio1_io10>, + <&iomuxc_gpio_ad_b0_09_gpio1_io09>; + drive-strength = "r0-5"; + bias-pull-up; + bias-pull-up-value = "100k"; + slew-rate = "fast"; + nxp,speed = "200-mhz"; + }; + }; + + pinmux_ptp: pinmux_ptp { + group0 { + pinmux = <&iomuxc_gpio_ad_b1_02_enet_1588_event2_out>, + <&iomuxc_gpio_ad_b1_03_enet_1588_event2_in>; + drive-strength = "r0-6"; + slew-rate = "slow"; + nxp,speed = "100-mhz"; + }; + }; +}; diff --git a/boards/arm/mimxrt1060_evk/Kconfig.defconfig b/boards/arm/mimxrt1060_evk/Kconfig.defconfig index aef6f37c03b..b3b325805fa 100644 --- a/boards/arm/mimxrt1060_evk/Kconfig.defconfig +++ b/boards/arm/mimxrt1060_evk/Kconfig.defconfig @@ -49,9 +49,13 @@ if NETWORKING config NET_L2_ETHERNET default y +if ETH_MCUX + config ETH_MCUX_PHY_RESET default y +endif # ETH_MCUX + endif # NETWORKING if LVGL diff --git a/boards/arm/mimxrt1060_evk/dts/mimxrt1060_evk-enet-experimental.dtsi b/boards/arm/mimxrt1060_evk/dts/mimxrt1060_evk-enet-experimental.dtsi new file mode 100644 index 00000000000..7fe69f0d52e --- /dev/null +++ b/boards/arm/mimxrt1060_evk/dts/mimxrt1060_evk-enet-experimental.dtsi @@ -0,0 +1,122 @@ +/* + * Copyright 2023 NXP + * + * Experimental ENET binding overlay + */ + + +/ { + soc { + /delete-node/ ethernet@402d8000; + + enet: enet@402d8000 { + compatible = "nxp,enet"; + reg = <0x402D8000 0x628>; + clocks = <&ccm IMX_CCM_ENET_CLK 0 0>; + enet_mac: ethernet { + compatible = "nxp,enet-mac"; + interrupts = <114 0>; + interrupt-names = "COMMON"; + nxp,mdio = <&enet_mdio>; + nxp,ptp-clock = <&enet_ptp_clock>; + phy-connection-type = "rmii"; + status = "disabled"; + }; + enet_mdio: mdio { + compatible = "nxp,enet-mdio"; + status = "disabled"; + #address-cells = <1>; + #size-cells = <0>; + }; + enet_ptp_clock: ptp_clock { + compatible = "nxp,enet-ptp-clock"; + interrupts = <115 0>; + status = "disabled"; + clocks = <&ccm IMX_CCM_ENET_PLL 0 0>; + }; + }; + }; +}; + +&enet_mac { + status = "okay"; + pinctrl-0 = <&pinmux_enet>; + pinctrl-names = "default"; + phy-handle = <&phy>; +}; + +&enet_mdio { + status = "okay"; + pinctrl-0 = <&pinmux_enet_mdio>; + pinctrl-names = "default"; + phy: phy@0 { + compatible = "microchip,ksz8081"; + reg = <0>; + status = "okay"; + mc,reset-gpio = <&gpio1 9 GPIO_ACTIVE_HIGH>; + mc,interrupt-gpio = <&gpio1 10 GPIO_ACTIVE_HIGH>; + mc,interface-type = "rmii"; + }; +}; + +&enet_ptp_clock { + status = "okay"; + pinctrl-0 = <&pinmux_ptp>; + pinctrl-names = "default"; +}; + + + +&pinctrl { + /delete-node/ pinmux_ptp; + /delete-node/ pinmux_enet; + + pinmux_enet: pinmux_enet { + group0 { + pinmux = <&iomuxc_gpio_b1_10_enet_ref_clk>; + bias-disable; + drive-strength = "r0-6"; + slew-rate = "fast"; + nxp,speed = "50-mhz"; + input-enable; + }; + group1 { + pinmux = <&iomuxc_gpio_b1_04_enet_rx_data0>, + <&iomuxc_gpio_b1_05_enet_rx_data1>, + <&iomuxc_gpio_b1_06_enet_rx_en>, + <&iomuxc_gpio_b1_07_enet_tx_data0>, + <&iomuxc_gpio_b1_08_enet_tx_data1>, + <&iomuxc_gpio_b1_09_enet_tx_en>, + <&iomuxc_gpio_b1_11_enet_rx_er>; + drive-strength = "r0-5"; + bias-pull-up; + bias-pull-up-value = "100k"; + slew-rate = "fast"; + nxp,speed = "200-mhz"; + }; + }; + + pinmux_enet_mdio: pinmux_enet_mdio { + group0 { + pinmux = <&iomuxc_gpio_emc_40_enet_mdc>, + <&iomuxc_gpio_emc_41_enet_mdio>, + <&iomuxc_gpio_ad_b0_10_gpio1_io10>, + <&iomuxc_gpio_ad_b0_09_gpio1_io09>; + drive-strength = "r0-5"; + bias-pull-up; + bias-pull-up-value = "100k"; + slew-rate = "fast"; + nxp,speed = "200-mhz"; + }; + }; + + pinmux_ptp: pinmux_ptp { + group0 { + pinmux = <&iomuxc_gpio_ad_b1_02_enet_1588_event2_out>, + <&iomuxc_gpio_ad_b1_03_enet_1588_event2_in>; + drive-strength = "r0-6"; + slew-rate = "slow"; + nxp,speed = "100-mhz"; + }; + }; +}; diff --git a/boards/arm/mimxrt1064_evk/Kconfig.defconfig b/boards/arm/mimxrt1064_evk/Kconfig.defconfig index 9ebf3eaa71b..e0604d39621 100644 --- a/boards/arm/mimxrt1064_evk/Kconfig.defconfig +++ b/boards/arm/mimxrt1064_evk/Kconfig.defconfig @@ -33,9 +33,13 @@ if NETWORKING config NET_L2_ETHERNET default y +if ETH_MCUX + config ETH_MCUX_PHY_RESET default y +endif # ETH_MCUX + endif # NETWORKING if LVGL diff --git a/boards/arm/mimxrt1064_evk/dts/mimxrt1064_evk-enet-experimental.dtsi b/boards/arm/mimxrt1064_evk/dts/mimxrt1064_evk-enet-experimental.dtsi new file mode 100644 index 00000000000..7fe69f0d52e --- /dev/null +++ b/boards/arm/mimxrt1064_evk/dts/mimxrt1064_evk-enet-experimental.dtsi @@ -0,0 +1,122 @@ +/* + * Copyright 2023 NXP + * + * Experimental ENET binding overlay + */ + + +/ { + soc { + /delete-node/ ethernet@402d8000; + + enet: enet@402d8000 { + compatible = "nxp,enet"; + reg = <0x402D8000 0x628>; + clocks = <&ccm IMX_CCM_ENET_CLK 0 0>; + enet_mac: ethernet { + compatible = "nxp,enet-mac"; + interrupts = <114 0>; + interrupt-names = "COMMON"; + nxp,mdio = <&enet_mdio>; + nxp,ptp-clock = <&enet_ptp_clock>; + phy-connection-type = "rmii"; + status = "disabled"; + }; + enet_mdio: mdio { + compatible = "nxp,enet-mdio"; + status = "disabled"; + #address-cells = <1>; + #size-cells = <0>; + }; + enet_ptp_clock: ptp_clock { + compatible = "nxp,enet-ptp-clock"; + interrupts = <115 0>; + status = "disabled"; + clocks = <&ccm IMX_CCM_ENET_PLL 0 0>; + }; + }; + }; +}; + +&enet_mac { + status = "okay"; + pinctrl-0 = <&pinmux_enet>; + pinctrl-names = "default"; + phy-handle = <&phy>; +}; + +&enet_mdio { + status = "okay"; + pinctrl-0 = <&pinmux_enet_mdio>; + pinctrl-names = "default"; + phy: phy@0 { + compatible = "microchip,ksz8081"; + reg = <0>; + status = "okay"; + mc,reset-gpio = <&gpio1 9 GPIO_ACTIVE_HIGH>; + mc,interrupt-gpio = <&gpio1 10 GPIO_ACTIVE_HIGH>; + mc,interface-type = "rmii"; + }; +}; + +&enet_ptp_clock { + status = "okay"; + pinctrl-0 = <&pinmux_ptp>; + pinctrl-names = "default"; +}; + + + +&pinctrl { + /delete-node/ pinmux_ptp; + /delete-node/ pinmux_enet; + + pinmux_enet: pinmux_enet { + group0 { + pinmux = <&iomuxc_gpio_b1_10_enet_ref_clk>; + bias-disable; + drive-strength = "r0-6"; + slew-rate = "fast"; + nxp,speed = "50-mhz"; + input-enable; + }; + group1 { + pinmux = <&iomuxc_gpio_b1_04_enet_rx_data0>, + <&iomuxc_gpio_b1_05_enet_rx_data1>, + <&iomuxc_gpio_b1_06_enet_rx_en>, + <&iomuxc_gpio_b1_07_enet_tx_data0>, + <&iomuxc_gpio_b1_08_enet_tx_data1>, + <&iomuxc_gpio_b1_09_enet_tx_en>, + <&iomuxc_gpio_b1_11_enet_rx_er>; + drive-strength = "r0-5"; + bias-pull-up; + bias-pull-up-value = "100k"; + slew-rate = "fast"; + nxp,speed = "200-mhz"; + }; + }; + + pinmux_enet_mdio: pinmux_enet_mdio { + group0 { + pinmux = <&iomuxc_gpio_emc_40_enet_mdc>, + <&iomuxc_gpio_emc_41_enet_mdio>, + <&iomuxc_gpio_ad_b0_10_gpio1_io10>, + <&iomuxc_gpio_ad_b0_09_gpio1_io09>; + drive-strength = "r0-5"; + bias-pull-up; + bias-pull-up-value = "100k"; + slew-rate = "fast"; + nxp,speed = "200-mhz"; + }; + }; + + pinmux_ptp: pinmux_ptp { + group0 { + pinmux = <&iomuxc_gpio_ad_b1_02_enet_1588_event2_out>, + <&iomuxc_gpio_ad_b1_03_enet_1588_event2_in>; + drive-strength = "r0-6"; + slew-rate = "slow"; + nxp,speed = "100-mhz"; + }; + }; +}; From 91a6af3e8f74eaa390ef3cef15e088f46186d9f2 Mon Sep 17 00:00:00 2001 From: Peter Mitsis Date: Fri, 24 Nov 2023 14:14:36 -0500 Subject: [PATCH 0395/3723] kernel: mmu: Fix static analysis issue Instead of performing a set of relative address comparisons using pointers of type 'uint8_t *', we leverage the existing IN_RANGE() macro and perform the comparisons with 'uintptr_t'. Signed-off-by: Peter Mitsis --- kernel/mmu.c | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/kernel/mmu.c b/kernel/mmu.c index a58bc77189b..f3133926a42 100644 --- a/kernel/mmu.c +++ b/kernel/mmu.c @@ -781,10 +781,13 @@ void z_phys_map(uint8_t **virt_ptr, uintptr_t phys, size_t size, uint32_t flags) * Basically if either end of region is within * virtual memory space, we need to mark the bits. */ - if (((dest_addr >= Z_VIRT_RAM_START) && - (dest_addr < Z_VIRT_RAM_END)) || - (((dest_addr + aligned_size) >= Z_VIRT_RAM_START) && - ((dest_addr + aligned_size) < Z_VIRT_RAM_END))) { + + if (IN_RANGE(aligned_phys, + (uintptr_t)Z_VIRT_RAM_START, + (uintptr_t)(Z_VIRT_RAM_END - 1)) || + IN_RANGE(aligned_phys + aligned_size - 1, + (uintptr_t)Z_VIRT_RAM_START, + (uintptr_t)(Z_VIRT_RAM_END - 1))) { uint8_t *adjusted_start = MAX(dest_addr, Z_VIRT_RAM_START); uint8_t *adjusted_end = MIN(dest_addr + aligned_size, Z_VIRT_RAM_END); From 15b2f7166a3c44978ffcbc3be6b140e6faa2092c Mon Sep 17 00:00:00 2001 From: Alberto Escolar Piedras Date: Fri, 24 Nov 2023 13:44:56 +0100 Subject: [PATCH 0396/3723] tests/bsim/compile: Add option to pass extra cmake arguments Add an extra optional input to the script which can be used to pass more options to cmake. Background: With sysbuild needing to pass extra options is quite normal. Users would normally want to add options, without necessarily wanting to change the default cmake_args, so this new options provides that. Signed-off-by: Alberto Escolar Piedras --- tests/bsim/compile.source | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/tests/bsim/compile.source b/tests/bsim/compile.source index 5cababeaefa..85470e78717 100644 --- a/tests/bsim/compile.source +++ b/tests/bsim/compile.source @@ -19,6 +19,7 @@ function _compile(){ local cmake_args="${cmake_args:-"-DCONFIG_COVERAGE=y \ -DCMAKE_EXPORT_COMPILE_COMMANDS=ON"}" + local cmake_extra_args="${cmake_extra_args:-""}" local ninja_args="${ninja_args:-""}" local cc_flags="${cc_flags:-"-Werror"}" @@ -47,7 +48,7 @@ function _compile(){ fi local cmake_cmd+=( -DOVERLAY_CONFIG="${conf_overlay}" \ ${modules_arg} \ - ${cmake_args} -DCMAKE_C_FLAGS=\"${cc_flags}\") + ${cmake_args} -DCMAKE_C_FLAGS=\"${cc_flags}\" ${cmake_extra_args}) if [ -v sysbuild ]; then local cmake_cmd+=( -DAPP_DIR=${app_root}/${app} ${ZEPHYR_BASE}/share/sysbuild/) else From 340d42f31d128a27ddc4c1131da3766970c3169f Mon Sep 17 00:00:00 2001 From: Dawid Niedzwiecki Date: Tue, 21 Nov 2023 09:58:29 +0100 Subject: [PATCH 0397/3723] google_dragonclaw: update exposed GPIO ports Enable gpioc and gpioh devices by default as these ports are exposed in the UFQFPN48 package. Signed-off-by: Dawid Niedzwiecki --- boards/arm/google_dragonclaw/google_dragonclaw.dts | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/boards/arm/google_dragonclaw/google_dragonclaw.dts b/boards/arm/google_dragonclaw/google_dragonclaw.dts index ff8dadacfa4..fb8acce4b2c 100644 --- a/boards/arm/google_dragonclaw/google_dragonclaw.dts +++ b/boards/arm/google_dragonclaw/google_dragonclaw.dts @@ -92,12 +92,10 @@ }; /* - * The board uses STM32F412CG in UFQFPN48 package in which gpio[c-h] is not + * The board uses STM32F412CG in UFQFPN48 package in which gpio[d-g] is not * exposed, so disable it. */ -&gpioc {status = "disabled";}; &gpiod {status = "disabled";}; &gpioe {status = "disabled";}; &gpiof {status = "disabled";}; &gpiog {status = "disabled";}; -&gpioh {status = "disabled";}; From 04854b2b5e7e125f1ff6e14c9232434b75365506 Mon Sep 17 00:00:00 2001 From: Dawid Niedzwiecki Date: Tue, 21 Nov 2023 09:59:53 +0100 Subject: [PATCH 0398/3723] google_dragonclaw: add gpio-hog for unused pins Configure the unused pin as GPIO_DISCONNECTED for saving the power consumption with the gpio-hog feature. The STM32 GPIO driver will configure the pins as analog. Signed-off-by: Dawid Niedzwiecki --- .../google_dragonclaw/google_dragonclaw.dts | 28 +++++++++++++++++++ 1 file changed, 28 insertions(+) diff --git a/boards/arm/google_dragonclaw/google_dragonclaw.dts b/boards/arm/google_dragonclaw/google_dragonclaw.dts index fb8acce4b2c..2f17124747d 100644 --- a/boards/arm/google_dragonclaw/google_dragonclaw.dts +++ b/boards/arm/google_dragonclaw/google_dragonclaw.dts @@ -91,6 +91,34 @@ }; }; +/* + * Set flags of unused pins as GPIO_ACTIVE_HIGH (0 << 0), which will be + * interpreted by GPIO driver as GPIO_DISCONNECTED, without setting the gpio as + * either input or output. The STM32 GPIO driver will set these pins as analog + * to reduce power consumption. + */ +&gpiob { + unused { + gpio-hog; + gpios = <2 GPIO_ACTIVE_HIGH>, <5 GPIO_ACTIVE_HIGH>; + }; +}; + +&gpioc { + unused { + gpio-hog; + gpios = <13 GPIO_ACTIVE_HIGH>, <14 GPIO_ACTIVE_HIGH>, + <15 GPIO_ACTIVE_HIGH>; + }; +}; + +&gpioh { + unused { + gpio-hog; + gpios = <0 GPIO_ACTIVE_HIGH>, <1 GPIO_ACTIVE_HIGH>; + }; +}; + /* * The board uses STM32F412CG in UFQFPN48 package in which gpio[d-g] is not * exposed, so disable it. From 6c6712d104c17d5d0014fb934160e8cc6d742313 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?B=C3=B8rre=20A=2E=20Opedal=20Lunde?= Date: Sun, 26 Nov 2023 13:58:19 +0100 Subject: [PATCH 0399/3723] doc: timers: correct grammar and typos MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Minor grammatical errors and mistyped words were corrected to improve clarity. Signed-off-by: Børre A. Opedal Lunde --- doc/kernel/services/timing/timers.rst | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/doc/kernel/services/timing/timers.rst b/doc/kernel/services/timing/timers.rst index c5f6beca358..9b1e424921d 100644 --- a/doc/kernel/services/timing/timers.rst +++ b/doc/kernel/services/timing/timers.rst @@ -28,10 +28,10 @@ A timer has the following key properties: * A **period** specifying the time interval between all timer expirations after the first one, also a ``k_timeout_t``. It must be non-negative. A period of ``K_NO_WAIT`` (i.e. zero) or - ``K_FOREVER`` means that the timer is a one shot timer that stops + ``K_FOREVER`` means that the timer is a one-shot timer that stops after a single expiration. (For example then, if a timer is started with a duration of 200 and a period of 75, it will first expire - after 200ms and then every 75ms after that.) + after 200 ms and then every 75 ms after that.) * An **expiry function** that is executed each time the timer expires. The function is executed by the system clock interrupt handler. @@ -49,7 +49,7 @@ expiry function and stop function values, sets the timer's status to zero, and puts the timer into the **stopped** state. A timer is **started** by specifying a duration and a period. -The timer's status is reset to zero, then the timer enters +The timer's status is reset to zero, and then the timer enters the **running** state and begins counting down towards expiry. Note that the timer's duration and period parameters specify @@ -63,7 +63,7 @@ When a running timer expires its status is incremented and the timer executes its expiry function, if one exists; If a thread is waiting on the timer, it is unblocked. If the timer's period is zero the timer enters the stopped state; -otherwise the timer restarts with a new duration equal to its period. +otherwise, the timer restarts with a new duration equal to its period. A running timer can be stopped in mid-countdown, if desired. The timer's status is left unchanged, then the timer enters the stopped state @@ -128,7 +128,7 @@ Using a Timer Expiry Function ============================= The following code uses a timer to perform a non-trivial action on a periodic -basis. Since the required work cannot be done at interrupt level, +basis. Since the required work cannot be done at the interrupt level, the timer's expiry function submits a work item to the :ref:`system workqueue `, whose thread performs the work. @@ -151,14 +151,14 @@ the timer's expiry function submits a work item to the ... - /* start periodic timer that expires once every second */ + /* start a periodic timer that expires once every second */ k_timer_start(&my_timer, K_SECONDS(1), K_SECONDS(1)); Reading Timer Status ==================== The following code reads a timer's status directly to determine -if the timer has expired on not. +if the timer has expired or not. .. code-block:: c @@ -166,7 +166,7 @@ if the timer has expired on not. ... - /* start one shot timer that expires after 200 ms */ + /* start a one-shot timer that expires after 200 ms */ k_timer_start(&my_status_timer, K_MSEC(200), K_NO_WAIT); /* do work */ @@ -197,7 +197,7 @@ are separated by the specified time interval. /* do first protocol operation */ ... - /* start one shot timer that expires after 500 ms */ + /* start a one-shot timer that expires after 500 ms */ k_timer_start(&my_sync_timer, K_MSEC(500), K_NO_WAIT); /* do other work */ From 6901f6c587d3dbb3fb8f61b3b620f4f5de12254b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Benjamin=20Cab=C3=A9?= Date: Thu, 23 Nov 2023 08:40:30 +0100 Subject: [PATCH 0400/3723] modbus: Document exception codes MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Add Doxygen comments for modbus exception codes. Signed-off-by: Benjamin Cabé --- include/zephyr/modbus/modbus.h | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/include/zephyr/modbus/modbus.h b/include/zephyr/modbus/modbus.h index 1fba0ac669d..7043594b8ec 100644 --- a/include/zephyr/modbus/modbus.h +++ b/include/zephyr/modbus/modbus.h @@ -44,16 +44,25 @@ extern "C" { /** @name Modbus exception codes * @{ */ -/* Modbus exception codes */ +/** No exception */ #define MODBUS_EXC_NONE 0 +/** Illegal function code */ #define MODBUS_EXC_ILLEGAL_FC 1 +/** Illegal data address */ #define MODBUS_EXC_ILLEGAL_DATA_ADDR 2 +/** Illegal data value */ #define MODBUS_EXC_ILLEGAL_DATA_VAL 3 +/** Server device failure */ #define MODBUS_EXC_SERVER_DEVICE_FAILURE 4 +/** Acknowledge */ #define MODBUS_EXC_ACK 5 +/** Server device busy */ #define MODBUS_EXC_SERVER_DEVICE_BUSY 6 +/** Memory parity error */ #define MODBUS_EXC_MEM_PARITY_ERROR 8 +/** Gateway path unavailable */ #define MODBUS_EXC_GW_PATH_UNAVAILABLE 10 +/** Gateway target device failed to respond */ #define MODBUS_EXC_GW_TARGET_FAILED_TO_RESP 11 /** @} */ From 9521371157c23e70cfb58b6a76aa9b65c93868a9 Mon Sep 17 00:00:00 2001 From: Fabio Baltieri Date: Wed, 25 Oct 2023 16:50:56 +0000 Subject: [PATCH 0401/3723] ci: twister: store the list of python packages Add a step to the first twister shard to upload the list of Python packages used with the build. Signed-off-by: Fabio Baltieri --- .github/workflows/twister.yaml | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) diff --git a/.github/workflows/twister.yaml b/.github/workflows/twister.yaml index 23174d7ab7c..abf19ee3d93 100644 --- a/.github/workflows/twister.yaml +++ b/.github/workflows/twister.yaml @@ -273,6 +273,24 @@ jobs: module_tests/twister.xml testplan.json + - if: matrix.subset == 1 && github.event_name == 'push' + name: Save the list of Python packages + shell: bash + run: | + FREEZE_FILE="frozen-requirements.txt" + timestamp="$(date)" + version="$(git describe --abbrev=12 --always)" + echo -e "# Generated at $timestamp ($version)\n" > $FREEZE_FILE + pip3 freeze | tee -a $FREEZE_FILE + + - if: matrix.subset == 1 && github.event_name == 'push' + name: Upload the list of Python packages + uses: actions/upload-artifact@v3 + with: + name: Frozen PIP package set + path: | + frozen-requirements.txt + twister-test-results: name: "Publish Unit Tests Results" env: From 56a59019559f6bb7237b50644e765306a8b3d527 Mon Sep 17 00:00:00 2001 From: Kyra Lengfeld Date: Fri, 24 Nov 2023 15:44:38 +0100 Subject: [PATCH 0402/3723] Bluetooth: Controller: Add Kconfig for LE Power Control Request Feature Add the controller Kconfig to use in Zephyr. Signed-off-by: Kyra Lengfeld --- subsys/bluetooth/controller/Kconfig | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/subsys/bluetooth/controller/Kconfig b/subsys/bluetooth/controller/Kconfig index 742534beff3..7d430ded1e1 100644 --- a/subsys/bluetooth/controller/Kconfig +++ b/subsys/bluetooth/controller/Kconfig @@ -101,6 +101,9 @@ config BT_CTLR_READ_ISO_LINK_QUALITY_SUPPORT BT_CTLR_PERIPHERAL_ISO_SUPPORT bool +config BT_CTLR_LE_POWER_CONTROL_SUPPORT + bool + config BT_CTLR bool "Bluetooth Controller" help @@ -484,6 +487,14 @@ config BT_CTLR_CONN_RSSI help Enable connection RSSI measurement. +config BT_CTLR_LE_POWER_CONTROL + bool "LE Power Control Request Feature" + depends on BT_CTLR_LE_POWER_CONTROL_SUPPORT + default y if BT_TRANSMIT_POWER_CONTROL + help + Enable support for LE Power Control Request feature that is defined in the + Bluetooth Core specification, Version 5.4 | Vol 6, Part B, Section 4.6.31. + endif # BT_CONN config BT_CTLR_FILTER_ACCEPT_LIST From 93e5cf6e6183ea87eefe3a028a0c39e683446677 Mon Sep 17 00:00:00 2001 From: Kyra Lengfeld Date: Thu, 16 Nov 2023 09:09:26 +0100 Subject: [PATCH 0403/3723] Bluetooth: Host: Add LE Power Control Request Procedure APIs This commits adds the LE API's for the LE Power Control Request Feature in Zephyr. The support of feature is provided with the controller-based feature selection with BT_CTLR_LE_POWER_CONTROL_SUPPORT and is selectable via BT_TRANSMIT_POWER_CONTROL. With the new APIs, the applications will: get improved reading of local and remote tx power be aware of changes in remote or local tx power Defined HCI commands in Core Spec v5.4: 7.8.117 LE Enhanced Read Transmit Power Level command: improvement to existing local tx power reading. 7.8.118 LE Read Remote Transmit Power Level command: Remote tx power is read through an event (LE Transmit Power Reporting) 7.8.121 LE Set Transmit Power Reporting Enable command: Enables local or remote tx power reporting to monitor changes in tx power 7.7.65.33 LE Transmit Power Reporting event Note: to utilize the Feature fully Nordic-LL-only vendor-specific commands are needed. These will not be added in RTOS zephyr but instead implemented in a maintainable way in sdk. Signed-off-by: Kyra Lengfeld --- include/zephyr/bluetooth/conn.h | 87 +++++++++++++++++++++ include/zephyr/bluetooth/hci_types.h | 49 ++++++++++++ subsys/bluetooth/Kconfig | 8 ++ subsys/bluetooth/host/conn.c | 108 +++++++++++++++++++++++++- subsys/bluetooth/host/conn_internal.h | 3 + subsys/bluetooth/host/hci_core.c | 34 ++++++++ 6 files changed, 285 insertions(+), 4 deletions(-) diff --git a/include/zephyr/bluetooth/conn.h b/include/zephyr/bluetooth/conn.h index 09b8321d685..bdc644d82e9 100644 --- a/include/zephyr/bluetooth/conn.h +++ b/include/zephyr/bluetooth/conn.h @@ -479,6 +479,42 @@ struct bt_conn_le_tx_power { int8_t max_level; }; + +/** LE Transmit Power Reporting Structure */ +struct bt_conn_le_tx_power_report { + + /** Reason for Transmit power reporting, + * as documented in Core Spec. Version 5.4 Vol. 4, Part E, 7.7.65.33. + */ + uint8_t reason; + + /** Phy of Transmit power reporting. */ + enum bt_conn_le_tx_power_phy phy; + + /** Transmit power level + * - 0xXX - Transmit power level + * + Range: -127 to 20 + * + Units: dBm + * + * - 0x7E - Remote device is not managing power levels on this PHY. + * - 0x7F - Transmit power level is not available + */ + int8_t tx_power_level; + + /** Bit 0: Transmit power level is at minimum level. + * Bit 1: Transmit power level is at maximum level. + */ + uint8_t tx_power_level_flag; + + /** Change in transmit power level + * - 0xXX - Change in transmit power level (positive indicates increased + * power, negative indicates decreased power, zero indicates unchanged) + * Units: dB + * - 0x7F - Change is not available or is out of range. + */ + int8_t delta; +}; + /** @brief Passkey Keypress Notification type * * The numeric values are the same as in the Core specification for Pairing @@ -530,6 +566,41 @@ int bt_conn_get_remote_info(struct bt_conn *conn, int bt_conn_le_get_tx_power_level(struct bt_conn *conn, struct bt_conn_le_tx_power *tx_power_level); +/** @brief Get local enhanced connection transmit power level. + * + * @param conn Connection object. + * @param tx_power Transmit power level descriptor. + * + * @return Zero on success or (negative) error code on failure. + * @retval -ENOBUFS HCI command buffer is not available. + */ +int bt_conn_le_enhanced_get_tx_power_level(struct bt_conn *conn, + struct bt_conn_le_tx_power *tx_power); + +/** @brief Get remote (peer) transmit power level. + * + * @param conn Connection object. + * @param phy PHY information. + * + * @return Zero on success or (negative) error code on failure. + * @retval -ENOBUFS HCI command buffer is not available. + */ +int bt_conn_le_get_remote_tx_power_level(struct bt_conn *conn, + enum bt_conn_le_tx_power_phy phy); + +/** @brief Enable transmit power reporting. + * + * @param conn Connection object. + * @param local_enable Enable/disable reporting for local. + * @param remote_enable Enable/disable reporting for remote. + * + * @return Zero on success or (negative) error code on failure. + * @retval -ENOBUFS HCI command buffer is not available. + */ +int bt_conn_le_set_tx_power_report_enable(struct bt_conn *conn, + bool local_enable, + bool remote_enable); + /** @brief Update the connection parameters. * * If the local device is in the peripheral role then updating the connection @@ -1052,6 +1123,22 @@ struct bt_conn_cb { const struct bt_df_conn_iq_samples_report *iq_report); #endif /* CONFIG_BT_DF_CONNECTION_CTE_RX */ +#if defined(CONFIG_BT_TRANSMIT_POWER_CONTROL) + /** @brief LE Read Remote Transmit Power Level procedure has completed or LE + * Transmit Power Reporting event. + * + * This callback notifies the application that either the remote transmit power level + * has been read from the peer or transmit power level has changed for the local or + * remote controller when transmit power reporting is enabled for the respective side + * using @ref bt_conn_le_set_tx_power_report_enable. + * + * @param conn Connection object. + * @param report Transmit power report. + */ + void (*tx_power_report)(struct bt_conn *conn, + const struct bt_conn_le_tx_power_report *report); +#endif /* CONFIG_BT_TRANSMIT_POWER_CONTROL */ + struct bt_conn_cb *_next; }; diff --git a/include/zephyr/bluetooth/hci_types.h b/include/zephyr/bluetooth/hci_types.h index 4d637bbe4e2..f1cb92f372c 100644 --- a/include/zephyr/bluetooth/hci_types.h +++ b/include/zephyr/bluetooth/hci_types.h @@ -571,6 +571,35 @@ struct bt_hci_rp_read_tx_power_level { int8_t tx_power_level; } __packed; +#define BT_HCI_LE_TX_POWER_PHY_1M 0x01 +#define BT_HCI_LE_TX_POWER_PHY_2M 0x02 +#define BT_HCI_LE_TX_POWER_PHY_CODED_S8 0x03 +#define BT_HCI_LE_TX_POWER_PHY_CODED_S2 0x04 +#define BT_HCI_OP_LE_ENH_READ_TX_POWER_LEVEL BT_OP(BT_OGF_LE, 0x0076) +struct bt_hci_cp_le_read_tx_power_level { + uint16_t handle; + uint8_t phy; +} __packed; + +struct bt_hci_rp_le_read_tx_power_level { + uint8_t status; + uint16_t handle; + uint8_t phy; + int8_t current_tx_power_level; + int8_t max_tx_power_level; +} __packed; + +#define BT_HCI_OP_LE_READ_REMOTE_TX_POWER_LEVEL BT_OP(BT_OGF_LE, 0x0077) + +#define BT_HCI_LE_TX_POWER_REPORT_DISABLE 0x00 +#define BT_HCI_LE_TX_POWER_REPORT_ENABLE 0x01 +#define BT_HCI_OP_LE_SET_TX_POWER_REPORT_ENABLE BT_OP(BT_OGF_LE, 0x007A) +struct bt_hci_cp_le_set_tx_power_report_enable { + uint16_t handle; + uint8_t local_enable; + uint8_t remote_enable; +} __packed; + #define BT_HCI_CTL_TO_HOST_FLOW_DISABLE 0x00 #define BT_HCI_CTL_TO_HOST_FLOW_ENABLE 0x01 #define BT_HCI_OP_SET_CTL_TO_HOST_FLOW BT_OP(BT_OGF_BASEBAND, 0x0031) @@ -2905,6 +2934,26 @@ struct bt_hci_evt_le_req_peer_sca_complete { uint8_t sca; } __packed; +/** Reason for Transmit power reporting. + */ +/* Local Transmit power changed. */ +#define BT_HCI_LE_TX_POWER_REPORT_REASON_LOCAL_CHANGED 0x00 +/* Remote Transmit power changed. */ +#define BT_HCI_LE_TX_POWER_REPORT_REASON_REMOTE_CHANGED 0x01 +/* HCI_LE_Read_Remote_Transmit_Power_Level command completed. */ +#define BT_HCI_LE_TX_POWER_REPORT_REASON_READ_REMOTE_COMPLETED 0x02 + +#define BT_HCI_EVT_LE_TRANSMIT_POWER_REPORT 0x21 +struct bt_hci_evt_le_transmit_power_report { + uint8_t status; + uint16_t handle; + uint8_t reason; + uint8_t phy; + int8_t tx_power_level; + uint8_t tx_power_level_flag; + int8_t delta; +} __packed; + #define BT_HCI_EVT_LE_BIGINFO_ADV_REPORT 0x22 struct bt_hci_evt_le_biginfo_adv_report { uint16_t sync_handle; diff --git a/subsys/bluetooth/Kconfig b/subsys/bluetooth/Kconfig index e02901cd906..912846e4cda 100644 --- a/subsys/bluetooth/Kconfig +++ b/subsys/bluetooth/Kconfig @@ -175,6 +175,14 @@ config BT_SCA_UPDATE depends on !BT_CTLR || BT_CTLR_SCA_UPDATE_SUPPORT help Enable support for Bluetooth 5.1 Sleep Clock Accuracy Update Procedure + +config BT_TRANSMIT_POWER_CONTROL + bool "LE Power Control" + depends on !BT_CTLR || BT_CTLR_LE_POWER_CONTROL_SUPPORT + help + Enable support for LE Power Control Request feature that is defined in the + Bluetooth Core specification, Version 5.4 | Vol 6, Part B, Section 4.6.31. + endif # BT_CONN rsource "Kconfig.iso" diff --git a/subsys/bluetooth/host/conn.c b/subsys/bluetooth/host/conn.c index 1fd2f5fbc49..06a3e7553a2 100644 --- a/subsys/bluetooth/host/conn.c +++ b/subsys/bluetooth/host/conn.c @@ -2619,16 +2619,116 @@ static int bt_conn_get_tx_power_level(struct bt_conn *conn, uint8_t type, return 0; } +#if defined(CONFIG_BT_TRANSMIT_POWER_CONTROL) +void notify_tx_power_report(struct bt_conn *conn, + struct bt_conn_le_tx_power_report report) +{ + for (struct bt_conn_cb *cb = callback_list; cb; cb = cb->_next) { + if (cb->tx_power_report) { + cb->tx_power_report(conn, &report); + } + } + + STRUCT_SECTION_FOREACH(bt_conn_cb, cb) + { + if (cb->tx_power_report) { + cb->tx_power_report(conn, &report); + } + } +} + +int bt_conn_le_enhanced_get_tx_power_level(struct bt_conn *conn, + struct bt_conn_le_tx_power *tx_power) +{ + int err; + struct bt_hci_rp_le_read_tx_power_level *rp; + struct net_buf *rsp; + struct bt_hci_cp_le_read_tx_power_level *cp; + struct net_buf *buf; + + if (!tx_power->phy) { + return -EINVAL; + } + + buf = bt_hci_cmd_create(BT_HCI_OP_LE_ENH_READ_TX_POWER_LEVEL, sizeof(*cp)); + if (!buf) { + return -ENOBUFS; + } + + cp = net_buf_add(buf, sizeof(*cp)); + cp->handle = sys_cpu_to_le16(conn->handle); + cp->phy = tx_power->phy; + + err = bt_hci_cmd_send_sync(BT_HCI_OP_LE_ENH_READ_TX_POWER_LEVEL, buf, &rsp); + if (err) { + return err; + } + + rp = (void *) rsp->data; + tx_power->phy = rp->phy; + tx_power->current_level = rp->current_tx_power_level; + tx_power->max_level = rp->max_tx_power_level; + net_buf_unref(rsp); + + return 0; +} + +int bt_conn_le_get_remote_tx_power_level(struct bt_conn *conn, + enum bt_conn_le_tx_power_phy phy) +{ + struct bt_hci_cp_le_read_tx_power_level *cp; + struct net_buf *buf; + + if (!phy) { + return -EINVAL; + } + + buf = bt_hci_cmd_create(BT_HCI_OP_LE_READ_REMOTE_TX_POWER_LEVEL, sizeof(*cp)); + if (!buf) { + return -ENOBUFS; + } + + cp = net_buf_add(buf, sizeof(*cp)); + cp->handle = sys_cpu_to_le16(conn->handle); + cp->phy = phy; + + return bt_hci_cmd_send_sync(BT_HCI_OP_LE_READ_REMOTE_TX_POWER_LEVEL, buf, NULL); +} + +int bt_conn_le_set_tx_power_report_enable(struct bt_conn *conn, + bool local_enable, + bool remote_enable) +{ + struct bt_hci_cp_le_set_tx_power_report_enable *cp; + struct net_buf *buf; + + buf = bt_hci_cmd_create(BT_HCI_OP_LE_SET_TX_POWER_REPORT_ENABLE, sizeof(*cp)); + if (!buf) { + return -ENOBUFS; + } + + cp = net_buf_add(buf, sizeof(*cp)); + cp->handle = sys_cpu_to_le16(conn->handle); + cp->local_enable = local_enable ? BT_HCI_LE_TX_POWER_REPORT_ENABLE : + BT_HCI_LE_TX_POWER_REPORT_DISABLE; + cp->remote_enable = remote_enable ? BT_HCI_LE_TX_POWER_REPORT_ENABLE : + BT_HCI_LE_TX_POWER_REPORT_DISABLE; + + return bt_hci_cmd_send_sync(BT_HCI_OP_LE_SET_TX_POWER_REPORT_ENABLE, buf, NULL); +} +#endif /* CONFIG_BT_TRANSMIT_POWER_CONTROL */ + int bt_conn_le_get_tx_power_level(struct bt_conn *conn, struct bt_conn_le_tx_power *tx_power_level) { int err; if (tx_power_level->phy != 0) { - /* Extend the implementation when LE Enhanced Read Transmit - * Power Level HCI command is available for use. - */ - return -ENOTSUP; + if (IS_ENABLED(CONFIG_BT_TRANSMIT_POWER_CONTROL)) { + return bt_conn_le_enhanced_get_tx_power_level(conn, tx_power_level); + } else { + return -ENOTSUP; + } } err = bt_conn_get_tx_power_level(conn, BT_TX_POWER_LEVEL_CURRENT, diff --git a/subsys/bluetooth/host/conn_internal.h b/subsys/bluetooth/host/conn_internal.h index 7741e259a61..a13adff704a 100644 --- a/subsys/bluetooth/host/conn_internal.h +++ b/subsys/bluetooth/host/conn_internal.h @@ -364,6 +364,9 @@ void notify_le_phy_updated(struct bt_conn *conn); bool le_param_req(struct bt_conn *conn, struct bt_le_conn_param *param); +void notify_tx_power_report(struct bt_conn *conn, + struct bt_conn_le_tx_power_report report); + #if defined(CONFIG_BT_SMP) /* If role specific LTK is present */ bool bt_conn_ltk_present(const struct bt_conn *conn); diff --git a/subsys/bluetooth/host/hci_core.c b/subsys/bluetooth/host/hci_core.c index de4fb637b49..b37cd45e1ae 100644 --- a/subsys/bluetooth/host/hci_core.c +++ b/subsys/bluetooth/host/hci_core.c @@ -2399,6 +2399,33 @@ int bt_hci_register_vnd_evt_cb(bt_hci_vnd_evt_cb_t cb) } #endif /* CONFIG_BT_HCI_VS_EVT_USER */ +#if defined(CONFIG_BT_TRANSMIT_POWER_CONTROL) +void bt_hci_le_transmit_power_report(struct net_buf *buf) +{ + struct bt_hci_evt_le_transmit_power_report *evt; + struct bt_conn_le_tx_power_report report; + struct bt_conn *conn; + + evt = net_buf_pull_mem(buf, sizeof(*evt)); + conn = bt_conn_lookup_handle(sys_le16_to_cpu(evt->handle), BT_CONN_TYPE_LE); + if (!conn) { + LOG_ERR("Unknown conn handle 0x%04X for transmit power report", + sys_le16_to_cpu(evt->handle)); + return; + } + + report.reason = evt->reason; + report.phy = evt->phy; + report.tx_power_level = evt->tx_power_level; + report.tx_power_level_flag = evt->tx_power_level_flag; + report.delta = evt->delta; + + notify_tx_power_report(conn, report); + + bt_conn_unref(conn); +} +#endif /* CONFIG_BT_TRANSMIT_POWER_CONTROL */ + static const struct event_handler vs_events[] = { #if defined(CONFIG_BT_DF_VS_CL_IQ_REPORT_16_BITS_IQ_SAMPLES) EVENT_HANDLER(BT_HCI_EVT_VS_LE_CONNECTIONLESS_IQ_REPORT, @@ -2544,6 +2571,10 @@ static const struct event_handler meta_events[] = { EVENT_HANDLER(BT_HCI_EVT_LE_CTE_REQUEST_FAILED, bt_hci_le_df_cte_req_failed, sizeof(struct bt_hci_evt_le_cte_req_failed)), #endif /* CONFIG_BT_DF_CONNECTION_CTE_REQ */ +#if defined(CONFIG_BT_TRANSMIT_POWER_CONTROL) + EVENT_HANDLER(BT_HCI_EVT_LE_TRANSMIT_POWER_REPORT, bt_hci_le_transmit_power_report, + sizeof(struct bt_hci_evt_le_transmit_power_report)), +#endif /* CONFIG_BT_TRANSMIT_POWER_CONTROL */ #if defined(CONFIG_BT_PER_ADV_SYNC_RSP) EVENT_HANDLER(BT_HCI_EVT_LE_PER_ADVERTISING_REPORT_V2, bt_hci_le_per_adv_report_v2, sizeof(struct bt_hci_evt_le_per_advertising_report_v2)), @@ -3089,6 +3120,9 @@ static int le_set_event_mask(void) BT_FEAT_LE_PHY_CODED(bt_dev.le.features))) { mask |= BT_EVT_MASK_LE_PHY_UPDATE_COMPLETE; } + if (IS_ENABLED(CONFIG_BT_TRANSMIT_POWER_CONTROL)) { + mask |= BT_EVT_MASK_LE_TRANSMIT_POWER_REPORTING; + } } if (IS_ENABLED(CONFIG_BT_SMP) && From 2c9af855bc6ef00160712cf0b71c953c4d13f196 Mon Sep 17 00:00:00 2001 From: Kyra Lengfeld Date: Fri, 24 Nov 2023 15:39:01 +0100 Subject: [PATCH 0404/3723] Bluetooth: Host: Add bt shell functions LE Power Control Request Feature To use LE commands of Le Power Control Request Feature one must utilize the BT_TRANSMIT_POWER_CONTROL config. Signed-off-by: Kyra Lengfeld --- subsys/bluetooth/shell/bt.c | 178 ++++++++++++++++++++++++++++++++++++ 1 file changed, 178 insertions(+) diff --git a/subsys/bluetooth/shell/bt.c b/subsys/bluetooth/shell/bt.c index 3f1af44de6f..f9bdd8f8094 100644 --- a/subsys/bluetooth/shell/bt.c +++ b/subsys/bluetooth/shell/bt.c @@ -123,6 +123,67 @@ static void print_le_addr(const char *desc, const bt_addr_le_t *addr) } #endif /* CONFIG_BT_CONN || (CONFIG_BT_BROADCASTER && CONFIG_BT_EXT_ADV) */ +#if defined(CONFIG_BT_TRANSMIT_POWER_CONTROL) +static const char *tx_power_flag2str(int8_t flag) +{ + switch (flag) { + case 0: + return "Neither Max nor Min Tx Power"; + case 1: + return "Tx Power Level is at minimum"; + case 2: + return "Tx Power Level is at maximum"; + /* Current Tx Power Level is the only available one*/ + case 3: + return "Tx Power Level is at minimum & maximum."; + default: + return "Unknown"; + } +} + +static const char *tx_power_report_reason2str(uint8_t reason) +{ + switch (reason) { + case BT_HCI_LE_TX_POWER_REPORT_REASON_LOCAL_CHANGED: + return "Local Tx Power changed"; + case BT_HCI_LE_TX_POWER_REPORT_REASON_REMOTE_CHANGED: + return "Remote Tx Power changed"; + case BT_HCI_LE_TX_POWER_REPORT_REASON_READ_REMOTE_COMPLETED: + return "Completed to read remote Tx Power"; + default: + return "Unknown"; + } +} + +static const char *tx_pwr_ctrl_phy2str(enum bt_conn_le_tx_power_phy phy) +{ + switch (phy) { + case BT_CONN_LE_TX_POWER_PHY_NONE: + return "None"; + case BT_CONN_LE_TX_POWER_PHY_1M: + return "LE 1M"; + case BT_CONN_LE_TX_POWER_PHY_2M: + return "LE 2M"; + case BT_CONN_LE_TX_POWER_PHY_CODED_S8: + return "LE Coded S8"; + case BT_CONN_LE_TX_POWER_PHY_CODED_S2: + return "LE Coded S2"; + default: + return "Unknown"; + } +} + +static const char *enabled2str(bool enabled) +{ + if (enabled) { + return "Enabled"; + } else { + return "Disabled"; + } +} + +#endif /* CONFIG_BT_TRANSMIT_POWER_CONTROL */ + #if defined(CONFIG_BT_CENTRAL) static int cmd_scan_off(const struct shell *sh); static int cmd_connect_le(const struct shell *sh, size_t argc, char *argv[]); @@ -809,6 +870,19 @@ void le_phy_updated(struct bt_conn *conn, } #endif +#if defined(CONFIG_BT_TRANSMIT_POWER_CONTROL) +void tx_power_report(struct bt_conn *conn, + const struct bt_conn_le_tx_power_report *report) +{ + shell_print(ctx_shell, "Tx Power Report: Reason: %s, PHY: %s, Tx Power Level: %d", + tx_power_report_reason2str(report->reason), tx_pwr_ctrl_phy2str(report->phy), + report->tx_power_level); + shell_print(ctx_shell, "Tx Power Level Flag Info: %s, Delta: %d", + tx_power_flag2str(report->tx_power_level_flag), report->delta); +} +#endif + + static struct bt_conn_cb conn_callbacks = { .connected = connected, .disconnected = disconnected, @@ -829,6 +903,9 @@ static struct bt_conn_cb conn_callbacks = { #if defined(CONFIG_BT_USER_PHY_UPDATE) .le_phy_updated = le_phy_updated, #endif +#if defined(CONFIG_BT_TRANSMIT_POWER_CONTROL) + .tx_power_report = tx_power_report, +#endif }; #endif /* CONFIG_BT_CONN */ @@ -2608,6 +2685,102 @@ static int cmd_per_adv_set_info_transfer(const struct shell *sh, size_t argc, } #endif /* CONFIG_BT_PER_ADV_SYNC_TRANSFER_SENDER && CONFIG_BT_PER_ADV */ +#if defined(CONFIG_BT_TRANSMIT_POWER_CONTROL) +static int cmd_read_remote_tx_power(const struct shell *sh, size_t argc, char *argv[]) +{ + if (argc < 3) { + int err = 0; + enum bt_conn_le_tx_power_phy phy = strtoul(argv[1], NULL, 16); + + err = bt_conn_le_get_remote_tx_power_level(default_conn, phy); + + if (!err) { + shell_print(sh, "Read Remote TX Power for PHY %s", + tx_pwr_ctrl_phy2str(phy)); + } else { + shell_print(sh, "error %d", err); + } + } else { + shell_help(sh); + return SHELL_CMD_HELP_PRINTED; + } + return 0; +} + +static int cmd_read_local_tx_power(const struct shell *sh, size_t argc, char *argv[]) +{ + int err = 0; + + if (argc < 3) { + struct bt_conn_le_tx_power tx_power_level; + + tx_power_level.phy = strtoul(argv[1], NULL, 16); + + int8_t unachievable_current_level = -100; + /* Arbitrary, these are output parameters.*/ + tx_power_level.current_level = unachievable_current_level; + tx_power_level.max_level = 6; + + if (default_conn == NULL) { + shell_error(sh, "Conn handle error, at least one connection is required."); + return -ENOEXEC; + } + err = bt_conn_le_get_tx_power_level(default_conn, &tx_power_level); + if (err) { + shell_print(sh, "Commad returned error error %d", err); + return err; + } + if (tx_power_level.current_level == unachievable_current_level) { + shell_print(sh, "We received no current tx power level."); + return -EIO; + } + shell_print(sh, "Read local TX Power: current level: %d, PHY: %s, Max Level: %d", + tx_power_level.current_level, + tx_pwr_ctrl_phy2str((enum bt_conn_le_tx_power_phy)tx_power_level.phy), + tx_power_level.max_level); + } else { + shell_help(sh); + return SHELL_CMD_HELP_PRINTED; + } + + return err; +} + +static int cmd_set_power_report_enable(const struct shell *sh, size_t argc, char *argv[]) +{ + if (argc < 4) { + int err = 0; + bool local_enable = 0; + bool remote_enable = 0; + + if (*argv[1] == '1') { + local_enable = 1; + } + if (*argv[2] == '1') { + remote_enable = 1; + } + if (default_conn == NULL) { + shell_error(sh, "Conn handle error, at least one connection is required."); + return -ENOEXEC; + } + err = bt_conn_le_set_tx_power_report_enable(default_conn, local_enable, + remote_enable); + if (!err) { + shell_print(sh, "Tx Power Report: local: %s, remote: %s", + enabled2str(local_enable), enabled2str(remote_enable)); + } else { + shell_print(sh, "error %d", err); + } + } else { + shell_help(sh); + return SHELL_CMD_HELP_PRINTED; + } + return 0; +} + +#endif + + #if defined(CONFIG_BT_CONN) #if defined(CONFIG_BT_CENTRAL) static int cmd_connect_le(const struct shell *sh, size_t argc, char *argv[]) @@ -4015,6 +4188,11 @@ SHELL_STATIC_SUBCMD_SET_CREATE(bt_cmds, cmd_default_handler), SHELL_CMD_ARG(scan-verbose-output, NULL, "", cmd_scan_verbose_output, 2, 0), #endif /* CONFIG_BT_OBSERVER */ +#if defined(CONFIG_BT_TRANSMIT_POWER_CONTROL) + SHELL_CMD_ARG(read-remote-tx-power, NULL, HELP_NONE, cmd_read_remote_tx_power, 2, 0), + SHELL_CMD_ARG(read-local-tx-power, NULL, HELP_NONE, cmd_read_local_tx_power, 2, 0), + SHELL_CMD_ARG(set-power-report-enable, NULL, HELP_NONE, cmd_set_power_report_enable, 3, 0), +#endif #if defined(CONFIG_BT_BROADCASTER) SHELL_CMD_ARG(advertise, NULL, " [mode: discov, non_discov] " From 77ab683dc6253e2b3bf5107ca7bb43d569150332 Mon Sep 17 00:00:00 2001 From: Kyra Lengfeld Date: Mon, 27 Nov 2023 12:32:01 +0100 Subject: [PATCH 0405/3723] Bluetooth: Host: Align return lines of bt shell helper function phy2str As other helper functions were introduced for the LE Power Control Request Feature (see CONFIG_BT_TRANSMIT_POWER_CONTROL), it was noticed that the return statements of switch cases should be on the next line generally. This will align phy2str with the rest in bt.c. Signed-off-by: Kyra Lengfeld --- subsys/bluetooth/shell/bt.c | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/subsys/bluetooth/shell/bt.c b/subsys/bluetooth/shell/bt.c index f9bdd8f8094..4e0111fa757 100644 --- a/subsys/bluetooth/shell/bt.c +++ b/subsys/bluetooth/shell/bt.c @@ -99,10 +99,14 @@ static const char *phy2str(uint8_t phy) { switch (phy) { case 0: return "No packets"; - case BT_GAP_LE_PHY_1M: return "LE 1M"; - case BT_GAP_LE_PHY_2M: return "LE 2M"; - case BT_GAP_LE_PHY_CODED: return "LE Coded"; - default: return "Unknown"; + case BT_GAP_LE_PHY_1M: + return "LE 1M"; + case BT_GAP_LE_PHY_2M: + return "LE 2M"; + case BT_GAP_LE_PHY_CODED: + return "LE Coded"; + default: + return "Unknown"; } } #endif From 07d04b0f40b1569eafbfe8cf15184686f2faccc2 Mon Sep 17 00:00:00 2001 From: Kyra Lengfeld Date: Tue, 28 Nov 2023 17:29:44 +0100 Subject: [PATCH 0406/3723] Bluetooth: Host: build shell power_control_request (Not to mistake it for the dynamic power control nor the zephyr LL vendor-specific commands controlling local tx power) this yaml addition will build the shell code for the LE Power Control Feature API's, acting as verification. Signed-off-by: Kyra Lengfeld --- tests/bluetooth/shell/testcase.yaml | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/tests/bluetooth/shell/testcase.yaml b/tests/bluetooth/shell/testcase.yaml index 9dae1a53868..b0c7dc15aad 100644 --- a/tests/bluetooth/shell/testcase.yaml +++ b/tests/bluetooth/shell/testcase.yaml @@ -22,6 +22,13 @@ tests: tags: bluetooth harness: keyboard min_flash: 145 + bluetooth.shell.power_control_request: + extra_configs: + - CONFIG_BT_TRANSMIT_POWER_CONTROL=y + - CONFIG_BT_CTLR=n + platform_allow: + - native_posix + build_only: true bluetooth.shell.cdc_acm: extra_args: - OVERLAY_CONFIG=cdc_acm.conf From 9d8100f43f2aef31f8763537c61e9f6542bd7067 Mon Sep 17 00:00:00 2001 From: Lukasz Majewski Date: Tue, 14 Nov 2023 16:19:19 +0100 Subject: [PATCH 0407/3723] drivers: net: lan865x: Move PLCA configuration to dedicated structure This change allows modification of the PLCA configuration in the lan865x driver. Values in this structure can be set via device tree as well as modified by the user program. Without this change the latter use case would not be possible as the struct lan865x_config structure is defined as read only and its data is only provided by device tree. Signed-off-by: Lukasz Majewski --- drivers/ethernet/eth_lan865x.c | 26 +++++++++++++++----------- drivers/ethernet/eth_lan865x_priv.h | 16 ++++++++++------ 2 files changed, 25 insertions(+), 17 deletions(-) diff --git a/drivers/ethernet/eth_lan865x.c b/drivers/ethernet/eth_lan865x.c index 91af1980f55..8964bb2294b 100644 --- a/drivers/ethernet/eth_lan865x.c +++ b/drivers/ethernet/eth_lan865x.c @@ -337,11 +337,11 @@ static int lan865x_default_config(const struct device *dev, uint8_t silicon_rev) if (ret < 0) return ret; - if (cfg->plca_enable) { - ret = lan865x_config_plca(dev, cfg->plca_node_id, - cfg->plca_node_count, - cfg->plca_burst_count, - cfg->plca_burst_timer); + if (cfg->plca->enable) { + ret = lan865x_config_plca(dev, cfg->plca->node_id, + cfg->plca->node_count, + cfg->plca->burst_count, + cfg->plca->burst_timer); if (ret < 0) { return ret; } @@ -540,17 +540,21 @@ static const struct ethernet_api lan865x_api_func = { }; #define LAN865X_DEFINE(inst) \ + static struct lan865x_config_plca lan865x_config_plca_##inst = { \ + .node_id = DT_INST_PROP(inst, plca_node_id), \ + .node_count = DT_INST_PROP(inst, plca_node_count), \ + .burst_count = DT_INST_PROP(inst, plca_burst_count), \ + .burst_timer = DT_INST_PROP(inst, plca_burst_timer), \ + .to_timer = DT_INST_PROP(inst, plca_to_timer), \ + .enable = DT_INST_PROP(inst, plca_enable), \ + }; \ + \ static const struct lan865x_config lan865x_config_##inst = { \ .spi = SPI_DT_SPEC_INST_GET(inst, SPI_WORD_SET(8), 0), \ .interrupt = GPIO_DT_SPEC_INST_GET(inst, int_gpios), \ .reset = GPIO_DT_SPEC_INST_GET(inst, rst_gpios), \ .timeout = CONFIG_ETH_LAN865X_TIMEOUT, \ - .plca_node_id = DT_INST_PROP(inst, plca_node_id), \ - .plca_node_count = DT_INST_PROP(inst, plca_node_count), \ - .plca_burst_count = DT_INST_PROP(inst, plca_burst_count), \ - .plca_burst_timer = DT_INST_PROP(inst, plca_burst_timer), \ - .plca_to_timer = DT_INST_PROP(inst, plca_to_timer), \ - .plca_enable = DT_INST_PROP(inst, plca_enable), \ + .plca = &lan865x_config_plca_##inst, \ }; \ \ struct oa_tc6 oa_tc6_##inst = { \ diff --git a/drivers/ethernet/eth_lan865x_priv.h b/drivers/ethernet/eth_lan865x_priv.h index fa4af1a949a..8f1b767595b 100644 --- a/drivers/ethernet/eth_lan865x_priv.h +++ b/drivers/ethernet/eth_lan865x_priv.h @@ -38,6 +38,15 @@ /* Memory Map Sector (MMS) 10 (0xA) */ #define LAN865x_DEVID MMS_REG(0xA, 0x094) +struct lan865x_config_plca { + bool enable : 1; /* 1 - PLCA enable, 0 - CSMA/CD enable */ + uint8_t node_id /* PLCA node id range: 0 to 254 */; + uint8_t node_count; /* PLCA node count range: 1 to 255 */ + uint8_t burst_count; /* PLCA burst count range: 0x0 to 0xFF */ + uint8_t burst_timer; /* PLCA burst timer */ + uint8_t to_timer; /* PLCA TO value */ +}; + struct lan865x_config { struct spi_dt_spec spi; struct gpio_dt_spec interrupt; @@ -45,12 +54,7 @@ struct lan865x_config { int32_t timeout; /* PLCA */ - bool plca_enable : 1; /* 1 - PLCA enable, 0 - CSMA/CD enable */ - uint8_t plca_node_id /* PLCA node id range: 0 to 254 */; - uint8_t plca_node_count; /* PLCA node count range: 1 to 255 */ - uint8_t plca_burst_count; /* PLCA burst count range: 0x0 to 0xFF */ - uint8_t plca_burst_timer; /* PLCA burst timer */ - uint8_t plca_to_timer; /* PLCA TO value */ + struct lan865x_config_plca *plca; /* MAC */ bool tx_cut_through_mode; /* 1 - tx cut through, 0 - Store and forward */ From 5cdf2f0eb7cd5ca82d6b460a6f0e239d6fa3024f Mon Sep 17 00:00:00 2001 From: Lukasz Majewski Date: Wed, 22 Nov 2023 14:05:09 +0100 Subject: [PATCH 0408/3723] drivers: net: lan865x: Move reset setup code to dedicated function The ctx->reset member of struct lan865x_data shall be cleared each time one wants to reset the LAN8651 device. Before this change this value was only initialized in the lan865x_init(). Signed-off-by: Lukasz Majewski --- drivers/ethernet/eth_lan865x.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/ethernet/eth_lan865x.c b/drivers/ethernet/eth_lan865x.c index 8964bb2294b..2f0f3606ad9 100644 --- a/drivers/ethernet/eth_lan865x.c +++ b/drivers/ethernet/eth_lan865x.c @@ -121,7 +121,9 @@ static int lan865x_wait_for_reset(const struct device *dev) static int lan865x_gpio_reset(const struct device *dev) { const struct lan865x_config *cfg = dev->config; + struct lan865x_data *ctx = dev->data; + ctx->reset = false; /* Perform (GPIO based) HW reset */ /* assert RESET_N low for 10 µs (5 µs min) */ gpio_pin_set_dt(&cfg->reset, 1); @@ -496,8 +498,6 @@ static int lan865x_init(const struct device *dev) 0, K_NO_WAIT); k_thread_name_set(ctx->tid_int, "lan865x_interrupt"); - ctx->reset = false; - /* Perform HW reset - 'rst-gpios' required property set in DT */ if (!gpio_is_ready_dt(&cfg->reset)) { LOG_ERR("Reset GPIO device %s is not ready", From dd5027067a4823c95ce4abe0ce4439f9cbb48358 Mon Sep 17 00:00:00 2001 From: Lukasz Majewski Date: Wed, 22 Nov 2023 14:18:16 +0100 Subject: [PATCH 0409/3723] drivers: net: lan865x: Disable protected transmission mode before reset The LAN865x device after HW reset supports only the non-protected control transmission mode. When it is reset alone - without resetting already configured HOST system - one must assure that in HOST's OA TC6 driver the protection SPI transmission support is disabled. Signed-off-by: Lukasz Majewski --- drivers/ethernet/eth_lan865x.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/drivers/ethernet/eth_lan865x.c b/drivers/ethernet/eth_lan865x.c index 2f0f3606ad9..eec35c33358 100644 --- a/drivers/ethernet/eth_lan865x.c +++ b/drivers/ethernet/eth_lan865x.c @@ -124,6 +124,8 @@ static int lan865x_gpio_reset(const struct device *dev) struct lan865x_data *ctx = dev->data; ctx->reset = false; + ctx->tc6->protected = false; + /* Perform (GPIO based) HW reset */ /* assert RESET_N low for 10 µs (5 µs min) */ gpio_pin_set_dt(&cfg->reset, 1); From 25addd09842a05675b68e72d73acf3d616d4548b Mon Sep 17 00:00:00 2001 From: Lukasz Majewski Date: Tue, 14 Nov 2023 16:28:11 +0100 Subject: [PATCH 0410/3723] net: ethernet: Add support for setting T1S PLCA parameters The Zephyr's core ethernet code had to be adjusted to support setting T1S PLCA parameters from user Zephyr programs. Such approach allows more flexibility, as T1S network configuration; especially PLCA node numbers, can be assigned not only via device tree at compile time. For example user can read them from EEPROM and then configure the network accordingly. For now - the union in struct ethernet_t1s_param only consists of plca structure. This can change in the future, when other T1S OA parameters - like Receive/Transmit Cut-Through Enable (bits RXCTE/TXCTE in OA_CONFIG0 register) are made adjustable from user program. Signed-off-by: Lukasz Majewski --- include/zephyr/net/ethernet.h | 48 ++++++++++++++++++++++++++ include/zephyr/net/ethernet_mgmt.h | 7 ++++ subsys/net/l2/ethernet/ethernet_mgmt.c | 11 ++++++ 3 files changed, 66 insertions(+) diff --git a/include/zephyr/net/ethernet.h b/include/zephyr/net/ethernet.h index a47ec767a60..181503140a7 100644 --- a/include/zephyr/net/ethernet.h +++ b/include/zephyr/net/ethernet.h @@ -196,6 +196,7 @@ enum ethernet_config_type { ETHERNET_CONFIG_TYPE_PRIORITY_QUEUES_NUM, ETHERNET_CONFIG_TYPE_FILTER, ETHERNET_CONFIG_TYPE_PORTS_NUM, + ETHERNET_CONFIG_TYPE_T1S_PARAM, }; enum ethernet_qav_param_type { @@ -206,7 +207,53 @@ enum ethernet_qav_param_type { ETHERNET_QAV_PARAM_TYPE_STATUS, }; +enum ethernet_t1s_param_type { + ETHERNET_T1S_PARAM_TYPE_PLCA_CONFIG, +}; + /** @endcond */ +struct ethernet_t1s_param { + /** Type of T1S parameter */ + enum ethernet_t1s_param_type type; + union { + /* PLCA is the Physical Layer (PHY) Collision + * Avoidance technique employed with multidrop + * 10Base-T1S standard. + * + * The PLCA parameters are described in standard [1] + * as registers in memory map 4 (MMS = 4) (point 9.6). + * + * IDVER (PLCA ID Version) + * CTRL0 (PLCA Control 0) + * CTRL1 (PLCA Control 1) + * STATUS (PLCA Status) + * TOTMR (PLCA TO Control) + * BURST (PLCA Burst Control) + * + * Those registers are implemented by each OA TC6 + * compliant vendor (like for e.g. LAN865x - e.g. [2]). + * + * Documents: + * [1] - "OPEN Alliance 10BASE-T1x MAC-PHY Serial + * Interface" (ver. 1.1) + * [2] - "DS60001734C" - LAN865x data sheet + */ + struct { + /** T1S PLCA enabled */ + bool enable; + /** T1S PLCA node id range: 0 to 254 */ + uint8_t node_id; + /** T1S PLCA node count range: 1 to 255 */ + uint8_t node_count; + /** T1S PLCA burst count range: 0x0 to 0xFF */ + uint8_t burst_count; + /** T1S PLCA burst timer */ + uint8_t burst_timer; + /** T1S PLCA TO value */ + uint8_t to_timer; + } plca; + }; +}; struct ethernet_qav_param { /** ID of the priority queue to use */ @@ -404,6 +451,7 @@ struct ethernet_config { struct net_eth_addr mac_address; + struct ethernet_t1s_param t1s_param; struct ethernet_qav_param qav_param; struct ethernet_qbv_param qbv_param; struct ethernet_qbu_param qbu_param; diff --git a/include/zephyr/net/ethernet_mgmt.h b/include/zephyr/net/ethernet_mgmt.h index 9d95fa7a42e..32a38f2df88 100644 --- a/include/zephyr/net/ethernet_mgmt.h +++ b/include/zephyr/net/ethernet_mgmt.h @@ -51,6 +51,7 @@ enum net_request_ethernet_cmd { NET_REQUEST_ETHERNET_CMD_GET_QBV_PARAM, NET_REQUEST_ETHERNET_CMD_GET_QBU_PARAM, NET_REQUEST_ETHERNET_CMD_GET_TXTIME_PARAM, + NET_REQUEST_ETHERNET_CMD_SET_T1S_PARAM, }; #define NET_REQUEST_ETHERNET_SET_AUTO_NEGOTIATION \ @@ -128,6 +129,11 @@ NET_MGMT_DEFINE_REQUEST_HANDLER(NET_REQUEST_ETHERNET_GET_QBU_PARAM); NET_MGMT_DEFINE_REQUEST_HANDLER(NET_REQUEST_ETHERNET_GET_TXTIME_PARAM); +#define NET_REQUEST_ETHERNET_SET_T1S_PARAM \ + (_NET_ETHERNET_BASE | NET_REQUEST_ETHERNET_CMD_SET_T1S_PARAM) + +NET_MGMT_DEFINE_REQUEST_HANDLER(NET_REQUEST_ETHERNET_SET_T1S_PARAM); + struct net_eth_addr; struct ethernet_qav_param; struct ethernet_qbv_param; @@ -152,6 +158,7 @@ struct ethernet_req_params { struct ethernet_qbv_param qbv_param; struct ethernet_qbu_param qbu_param; struct ethernet_txtime_param txtime_param; + struct ethernet_t1s_param t1s_param; int priority_queues_num; int ports_num; diff --git a/subsys/net/l2/ethernet/ethernet_mgmt.c b/subsys/net/l2/ethernet/ethernet_mgmt.c index e7fcae8ac99..3e957e52c1e 100644 --- a/subsys/net/l2/ethernet/ethernet_mgmt.c +++ b/subsys/net/l2/ethernet/ethernet_mgmt.c @@ -192,6 +192,14 @@ static int ethernet_set_config(uint32_t mgmt_request, config.promisc_mode = params->promisc_mode; type = ETHERNET_CONFIG_TYPE_PROMISC_MODE; + } else if (mgmt_request == NET_REQUEST_ETHERNET_SET_T1S_PARAM) { + if (net_if_is_up(iface)) { + return -EACCES; + } + + memcpy(&config.t1s_param, ¶ms->t1s_param, + sizeof(struct ethernet_t1s_param)); + type = ETHERNET_CONFIG_TYPE_T1S_PARAM; } else { return -EINVAL; } @@ -226,6 +234,9 @@ NET_MGMT_REGISTER_REQUEST_HANDLER(NET_REQUEST_ETHERNET_SET_TXTIME_PARAM, NET_MGMT_REGISTER_REQUEST_HANDLER(NET_REQUEST_ETHERNET_SET_PROMISC_MODE, ethernet_set_config); +NET_MGMT_REGISTER_REQUEST_HANDLER(NET_REQUEST_ETHERNET_SET_T1S_PARAM, + ethernet_set_config); + static int ethernet_get_config(uint32_t mgmt_request, struct net_if *iface, void *data, size_t len) From f4a039e21843039a2002c457b5bd23c4a2b51175 Mon Sep 17 00:00:00 2001 From: Lukasz Majewski Date: Wed, 22 Nov 2023 14:29:36 +0100 Subject: [PATCH 0411/3723] drivers: net: lan865x: Add support for setting T1S PLCA configuration This commit provides support for changing PLCA parameters stored in lan865x_config_plca structure. After values are updated, the LAN865x needs to be reset and then configured with new values. Signed-off-by: Lukasz Majewski --- drivers/ethernet/eth_lan865x.c | 21 +++++++++++++++++++++ 1 file changed, 21 insertions(+) diff --git a/drivers/ethernet/eth_lan865x.c b/drivers/ethernet/eth_lan865x.c index eec35c33358..88141f9d98c 100644 --- a/drivers/ethernet/eth_lan865x.c +++ b/drivers/ethernet/eth_lan865x.c @@ -57,10 +57,12 @@ static enum ethernet_hw_caps lan865x_port_get_capabilities(const struct device * return ETHERNET_LINK_10BASE_T | ETHERNET_PROMISC_MODE; } +static int lan865x_gpio_reset(const struct device *dev); static void lan865x_write_macaddress(const struct device *dev); static int lan865x_set_config(const struct device *dev, enum ethernet_config_type type, const struct ethernet_config *config) { + const struct lan865x_config *cfg = dev->config; struct lan865x_data *ctx = dev->data; int ret = -ENOTSUP; @@ -97,6 +99,25 @@ static int lan865x_set_config(const struct device *dev, enum ethernet_config_typ return lan865x_mac_rxtx_control(dev, LAN865x_MAC_TXRX_ON); } + if (type == ETHERNET_CONFIG_TYPE_T1S_PARAM) { + ret = lan865x_mac_rxtx_control(dev, LAN865x_MAC_TXRX_OFF); + if (ret) { + return ret; + } + + if (config->t1s_param.type == ETHERNET_T1S_PARAM_TYPE_PLCA_CONFIG) { + cfg->plca->enable = config->t1s_param.plca.enable; + cfg->plca->node_id = config->t1s_param.plca.node_id; + cfg->plca->node_count = config->t1s_param.plca.node_count; + cfg->plca->burst_count = config->t1s_param.plca.burst_count; + cfg->plca->burst_timer = config->t1s_param.plca.burst_timer; + cfg->plca->to_timer = config->t1s_param.plca.to_timer; + } + + /* Reset is required to re-program PLCA new configuration */ + lan865x_gpio_reset(dev); + } + return ret; } From fb695c42fbeaf9187db69d228127ca612003af79 Mon Sep 17 00:00:00 2001 From: Christopher Friedt Date: Thu, 23 Nov 2023 12:04:16 -0500 Subject: [PATCH 0412/3723] posix: pthread: implement pthread_cleanup_push() / pop() pthread_cleanup_push() and pthread_cleanup_pop() are required by the POSIX_THREADS_BASE Option Group as detailed in Section E.1 of IEEE-1003.1-2017. The POSIX_THREADS_BASE Option Group is required for PSE51, PSE52, PSE53, and PSE54 conformance, and is otherwise mandatory for any POSIX conforming system as per Section A.2.1.3 of IEEE-1003-1.2017. In this change, we require the addition of a dedicated pthread_key_t that will not be available for applilcation usage. Rather than including that as part of CONFIG_MAX_PTHREAD_KEY_COUNT, we increase the storage by 1 in order to be least invasive from the application perspective. Signed-off-by: Christopher Friedt --- include/zephyr/posix/pthread.h | 12 +++++++++ lib/posix/posix_internal.h | 3 +++ lib/posix/pthread.c | 47 ++++++++++++++++++++++++++++++++++ 3 files changed, 62 insertions(+) diff --git a/include/zephyr/posix/pthread.h b/include/zephyr/posix/pthread.h index d61c46c5116..7d7536ef0db 100644 --- a/include/zephyr/posix/pthread.h +++ b/include/zephyr/posix/pthread.h @@ -480,6 +480,18 @@ int pthread_atfork(void (*prepare)(void), void (*parent)(void), void (*child)(vo int pthread_getconcurrency(void); int pthread_setconcurrency(int new_level); +void __z_pthread_cleanup_push(void *cleanup[3], void (*routine)(void *arg), void *arg); +void __z_pthread_cleanup_pop(int execute); + +#define pthread_cleanup_push(_rtn, _arg) \ + do /* enforce '{'-like behaviour */ { \ + void *_z_pthread_cleanup[3]; \ + __z_pthread_cleanup_push(_z_pthread_cleanup, _rtn, _arg) + +#define pthread_cleanup_pop(_ex) \ + __z_pthread_cleanup_pop(_ex); \ + } /* enforce '}'-like behaviour */ while (0) + /* Glibc / Oracle Extension Functions */ /** diff --git a/lib/posix/posix_internal.h b/lib/posix/posix_internal.h index 4ce000e5147..1acabb47262 100644 --- a/lib/posix/posix_internal.h +++ b/lib/posix/posix_internal.h @@ -24,6 +24,9 @@ struct posix_thread { struct k_thread thread; + /* List nodes for pthread_cleanup_push() / pthread_cleanup_pop() */ + sys_slist_t cleanup_list; + /* List node for ready_q, run_q, or done_q */ sys_dnode_t q_node; diff --git a/lib/posix/pthread.c b/lib/posix/pthread.c index 46d0ffeae4d..a47d0f2c8e0 100644 --- a/lib/posix/pthread.c +++ b/lib/posix/pthread.c @@ -30,6 +30,12 @@ LOG_MODULE_REGISTER(pthread, CONFIG_PTHREAD_LOG_LEVEL); #define PTHREAD_INIT_FLAGS PTHREAD_CANCEL_ENABLE +struct __pthread_cleanup { + void (*routine)(void *arg); + void *arg; + sys_snode_t node; +}; + enum posix_thread_qid { /* ready to be started via pthread_create() */ POSIX_THREAD_READY_Q, @@ -142,6 +148,46 @@ int pthread_equal(pthread_t pt1, pthread_t pt2) return (pt1 == pt2); } +static inline void __z_pthread_cleanup_init(struct __pthread_cleanup *c, void (*routine)(void *arg), + void *arg) +{ + *c = (struct __pthread_cleanup){ + .routine = routine, + .arg = arg, + .node = {0}, + }; +} + +void __z_pthread_cleanup_push(void *cleanup[3], void (*routine)(void *arg), void *arg) +{ + struct posix_thread *const t = to_posix_thread(pthread_self()); + struct __pthread_cleanup *const c = (struct __pthread_cleanup *)cleanup; + + BUILD_ASSERT(3 * sizeof(void *) == sizeof(*c)); + __ASSERT_NO_MSG(t != NULL); + __ASSERT_NO_MSG(c != NULL); + __ASSERT_NO_MSG(routine != NULL); + __z_pthread_cleanup_init(c, routine, arg); + sys_slist_prepend(&t->cleanup_list, &c->node); +} + +void __z_pthread_cleanup_pop(int execute) +{ + sys_snode_t *node; + struct __pthread_cleanup *c; + struct posix_thread *const t = to_posix_thread(pthread_self()); + + __ASSERT_NO_MSG(t != NULL); + node = sys_slist_get(&t->cleanup_list); + __ASSERT_NO_MSG(node != NULL); + c = CONTAINER_OF(node, struct __pthread_cleanup, node); + __ASSERT_NO_MSG(c != NULL); + __ASSERT_NO_MSG(c->routine != NULL); + if (execute) { + c->routine(c->arg); + } +} + static bool is_posix_policy_prio_valid(uint32_t priority, int policy) { if (priority >= sched_get_priority_min(policy) && @@ -414,6 +460,7 @@ int pthread_create(pthread_t *th, const pthread_attr_t *_attr, void *(*threadrou } t->cancel_pending = false; sys_slist_init(&t->key_list); + sys_slist_init(&t->cleanup_list); t->dynamic_stack = _attr == NULL ? attr->stack : NULL; } k_spin_unlock(&pthread_pool_lock, key); From fe456ee5be7d5fe859495a16ecabce79b0d486df Mon Sep 17 00:00:00 2001 From: Christopher Friedt Date: Thu, 23 Nov 2023 12:06:27 -0500 Subject: [PATCH 0413/3723] tests: posix: test pthread_cleanup_push() / pop() Add a test for pthread_cleanup_push() and pthread_cleanup_pop(). Signed-off-by: Christopher Friedt --- tests/posix/common/src/pthread.c | 30 ++++++++++++++++++++++++++++++ 1 file changed, 30 insertions(+) diff --git a/tests/posix/common/src/pthread.c b/tests/posix/common/src/pthread.c index bcb09da8602..120ac2b32dd 100644 --- a/tests/posix/common/src/pthread.c +++ b/tests/posix/common/src/pthread.c @@ -906,3 +906,33 @@ ZTEST(posix_apis, test_pthread_set_get_concurrency) /* EAGAIN if the a system resource to be exceeded */ zassert_equal(EAGAIN, pthread_setconcurrency(CONFIG_MP_MAX_NUM_CPUS + 1)); } + +static void cleanup_handler(void *arg) +{ + bool *boolp = (bool *)arg; + + *boolp = true; +} + +static void *test_pthread_cleanup_entry(void *arg) +{ + bool executed[2] = {0}; + + pthread_cleanup_push(cleanup_handler, &executed[0]); + pthread_cleanup_push(cleanup_handler, &executed[1]); + pthread_cleanup_pop(false); + pthread_cleanup_pop(true); + + zassert_true(executed[0]); + zassert_false(executed[1]); + + return NULL; +} + +ZTEST(posix_apis, test_pthread_cleanup) +{ + pthread_t th; + + zassert_ok(pthread_create(&th, NULL, test_pthread_cleanup_entry, NULL)); + zassert_ok(pthread_join(th, NULL)); +} From e260201204338c477abf1e5c0cccc03f860101d8 Mon Sep 17 00:00:00 2001 From: Christopher Friedt Date: Thu, 23 Nov 2023 12:10:50 -0500 Subject: [PATCH 0414/3723] doc: posix: mark pthread_cleanup_push() and pop() as supported Update docs to reflect additional support of pthread_cleanup_push() and pthread_cleanup_pop(). Signed-off-by: Christopher Friedt --- doc/services/portability/posix/option_groups/index.rst | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/doc/services/portability/posix/option_groups/index.rst b/doc/services/portability/posix/option_groups/index.rst index 65b96a4d201..b58a9e2ce38 100644 --- a/doc/services/portability/posix/option_groups/index.rst +++ b/doc/services/portability/posix/option_groups/index.rst @@ -32,8 +32,8 @@ multiple processes. pthread_barrierattr_init(),yes pthread_barrierattr_setpshared(),yes pthread_cancel(),yes - pthread_cleanup_pop(), - pthread_cleanup_push(), + pthread_cleanup_pop(),yes + pthread_cleanup_push(),yes pthread_cond_broadcast(),yes pthread_cond_destroy(),yes pthread_cond_init(),yes From 29d027a47b8cb8bccfbed32f1f98e3d4d1ebe114 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?J=C4=99drzej=20Ciupis?= Date: Mon, 27 Nov 2023 09:21:29 +0100 Subject: [PATCH 0415/3723] modules: hal_nordic: nrf_802154: lengthen serialization ring buffer MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This commit increases the length of ring buffer that holds serialized nRF 802.15.4 API calls so that it can simultaneously store all notifications the driver is capable of issuing. Currently that's not the case, which creates a possibility of the serialization buffers running out while the driver is issuing notifications. Signed-off-by: Jędrzej Ciupis --- .../serialization/platform/nrf_802154_spinel_backend_ipc.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/modules/hal_nordic/nrf_802154/serialization/platform/nrf_802154_spinel_backend_ipc.c b/modules/hal_nordic/nrf_802154/serialization/platform/nrf_802154_spinel_backend_ipc.c index 06ad1f003e6..8a9cd8739b2 100644 --- a/modules/hal_nordic/nrf_802154/serialization/platform/nrf_802154_spinel_backend_ipc.c +++ b/modules/hal_nordic/nrf_802154/serialization/platform/nrf_802154_spinel_backend_ipc.c @@ -71,9 +71,11 @@ nrf_802154_ser_err_t nrf_802154_backend_init(void) } /* Send packet thread details */ -#define RING_BUFFER_LEN 16 #define SEND_THREAD_STACK_SIZE 1024 +/* Make the ring buffer long enough to hold all notifications that the driver can produce */ +#define RING_BUFFER_LEN (CONFIG_NRF_802154_RX_BUFFERS + 10) + static K_SEM_DEFINE(send_sem, 0, RING_BUFFER_LEN); K_THREAD_STACK_DEFINE(send_thread_stack, SEND_THREAD_STACK_SIZE); struct k_thread send_thread_data; From a9cebb5033be186b82599e24291b31adafb53ff8 Mon Sep 17 00:00:00 2001 From: Franciszek Pindel Date: Thu, 23 Nov 2023 12:21:51 +0100 Subject: [PATCH 0416/3723] boards: efr32_radio: Add USART configuration for brd4180a and brd4187c This commits provides USART PINCTRL configuration for efr32_radio_brd4180a and efr32_radio_brd4187c boards. Signed-off-by: Franciszek Pindel Signed-off-by: Mateusz Holenko --- .../efr32_radio_brd4180a-pinctrl.dtsi | 18 ++++++++++++++++++ .../arm/efr32_radio/efr32_radio_brd4180a.dts | 5 +++-- .../efr32_radio_brd4187c-pinctrl.dtsi | 18 ++++++++++++++++++ .../arm/efr32_radio/efr32_radio_brd4187c.dts | 5 +++-- 4 files changed, 42 insertions(+), 4 deletions(-) create mode 100644 boards/arm/efr32_radio/efr32_radio_brd4180a-pinctrl.dtsi create mode 100644 boards/arm/efr32_radio/efr32_radio_brd4187c-pinctrl.dtsi diff --git a/boards/arm/efr32_radio/efr32_radio_brd4180a-pinctrl.dtsi b/boards/arm/efr32_radio/efr32_radio_brd4180a-pinctrl.dtsi new file mode 100644 index 00000000000..74723695d86 --- /dev/null +++ b/boards/arm/efr32_radio/efr32_radio_brd4180a-pinctrl.dtsi @@ -0,0 +1,18 @@ +/* + * Copyright (c) 2023 Antmicro + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include +#include + +&pinctrl { + usart0_default: usart0_default { + group1 { + psels = , + , + ; + }; + }; +}; diff --git a/boards/arm/efr32_radio/efr32_radio_brd4180a.dts b/boards/arm/efr32_radio/efr32_radio_brd4180a.dts index 0687b206adb..43f4290ff84 100644 --- a/boards/arm/efr32_radio/efr32_radio_brd4180a.dts +++ b/boards/arm/efr32_radio/efr32_radio_brd4180a.dts @@ -7,6 +7,7 @@ /dts-v1/; #include #include +#include "efr32_radio_brd4180a-pinctrl.dtsi" / { model = "Silicon Labs BRD4180A (Mighty Gecko Radio Board)"; @@ -65,8 +66,8 @@ &usart0 { current-speed = <115200>; - location-rx = ; - location-tx = ; + pinctrl-0 = <&usart0_default>; + pinctrl-names = "default"; status = "okay"; }; diff --git a/boards/arm/efr32_radio/efr32_radio_brd4187c-pinctrl.dtsi b/boards/arm/efr32_radio/efr32_radio_brd4187c-pinctrl.dtsi new file mode 100644 index 00000000000..0ea520ce13f --- /dev/null +++ b/boards/arm/efr32_radio/efr32_radio_brd4187c-pinctrl.dtsi @@ -0,0 +1,18 @@ +/* + * Copyright (c) 2023 Antmicro + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include +#include + +&pinctrl { + usart0_default: usart0_default { + group1 { + psels = , + , + ; + }; + }; +}; diff --git a/boards/arm/efr32_radio/efr32_radio_brd4187c.dts b/boards/arm/efr32_radio/efr32_radio_brd4187c.dts index 1f065fb15b1..6e8703fabbe 100644 --- a/boards/arm/efr32_radio/efr32_radio_brd4187c.dts +++ b/boards/arm/efr32_radio/efr32_radio_brd4187c.dts @@ -7,6 +7,7 @@ /dts-v1/; #include #include +#include "efr32_radio_brd4187c-pinctrl.dtsi" / { model = "Silicon Labs BRD4187C (Mighty Gecko Radio Board)"; @@ -67,8 +68,8 @@ &usart0 { current-speed = <115200>; - location-rx = ; - location-tx = ; + pinctrl-0 = <&usart0_default>; + pinctrl-names = "default"; status = "okay"; }; From 64cac83b4830fc7cad9ea89dd47cb2afe2e94c38 Mon Sep 17 00:00:00 2001 From: Francois Ramu Date: Mon, 27 Nov 2023 10:51:51 +0100 Subject: [PATCH 0417/3723] samples: sensor: hts221 no trigger on stm32u585 disco kit The b_u585i_iot02a stm32 board has no HTS221 DRDY pin to trig the HTS221 relative humidity and temperature sensor So that sample.sensor.hts221.trigger is not applicable. Signed-off-by: Francois Ramu --- samples/sensor/hts221/sample.yaml | 2 ++ 1 file changed, 2 insertions(+) diff --git a/samples/sensor/hts221/sample.yaml b/samples/sensor/hts221/sample.yaml index beffa273cfd..472986177a1 100644 --- a/samples/sensor/hts221/sample.yaml +++ b/samples/sensor/hts221/sample.yaml @@ -23,3 +23,5 @@ tests: sample.sensor.hts221.trigger: extra_configs: - CONFIG_HTS221_TRIGGER_OWN_THREAD=y + platform_exclude: + - b_u585i_iot02a From c8d53445841f6d17e905b4a0d3e33b782edd34ee Mon Sep 17 00:00:00 2001 From: Jamie McCrae Date: Mon, 27 Nov 2023 10:56:45 +0000 Subject: [PATCH 0418/3723] doc: release: 3.6: Fix wrong list character Fixes wrongly using a dash instead of an asterisk for a list Signed-off-by: Jamie McCrae --- doc/releases/release-notes-3.6.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/doc/releases/release-notes-3.6.rst b/doc/releases/release-notes-3.6.rst index 84b28a9b517..2084f3bd39d 100644 --- a/doc/releases/release-notes-3.6.rst +++ b/doc/releases/release-notes-3.6.rst @@ -110,7 +110,7 @@ Boards & SoC Support Build system and infrastructure ******************************* -- Dropped the ``COMPAT_INCLUDES`` option, it was unused since 3.0. +* Dropped the ``COMPAT_INCLUDES`` option, it was unused since 3.0. Drivers and Sensors ******************* From b32b228697393f6c4c68b6cd4fd076e01434488c Mon Sep 17 00:00:00 2001 From: Jamie McCrae Date: Mon, 27 Nov 2023 10:57:54 +0000 Subject: [PATCH 0419/3723] doc: release: 3.6: Add note on fixed board revision 0 Adds a note that board revision 0 now correctly has the overlay file included Signed-off-by: Jamie McCrae --- doc/releases/release-notes-3.6.rst | 2 ++ 1 file changed, 2 insertions(+) diff --git a/doc/releases/release-notes-3.6.rst b/doc/releases/release-notes-3.6.rst index 2084f3bd39d..5dded69d236 100644 --- a/doc/releases/release-notes-3.6.rst +++ b/doc/releases/release-notes-3.6.rst @@ -112,6 +112,8 @@ Build system and infrastructure * Dropped the ``COMPAT_INCLUDES`` option, it was unused since 3.0. +* Fixed an issue whereby board revision ``0`` did not include overlay files for that revision. + Drivers and Sensors ******************* From 55dbe1e42b7a22a310b6b36dc69b63d19a74f912 Mon Sep 17 00:00:00 2001 From: Jamie McCrae Date: Mon, 27 Nov 2023 10:58:42 +0000 Subject: [PATCH 0420/3723] doc: release: 3.6: Add note on Nordic implying XIP Adds a note that nordic SoCs now imply the XIP Kconfig option instead of selecting it Signed-off-by: Jamie McCrae --- doc/releases/release-notes-3.6.rst | 3 +++ 1 file changed, 3 insertions(+) diff --git a/doc/releases/release-notes-3.6.rst b/doc/releases/release-notes-3.6.rst index 5dded69d236..3f1742d3ab4 100644 --- a/doc/releases/release-notes-3.6.rst +++ b/doc/releases/release-notes-3.6.rst @@ -63,6 +63,9 @@ Boards & SoC Support * Made these changes in other SoC series: + * Nordic SoCs now imply :kconfig:option:`CONFIG_XIP` instead of selecting it, this allows for + creating RAM-based applicatins by disabling it. + * Added support for these ARC boards: * Added support for these ARM boards: From 78a819bb3391f1635bc2237aa1ceca477b24b898 Mon Sep 17 00:00:00 2001 From: Jamie McCrae Date: Mon, 27 Nov 2023 10:59:17 +0000 Subject: [PATCH 0421/3723] doc: release: 3.6: Add note on fixed MCUmgr UART console FIFO Adds a note that the UART FIFO is no longer read when the driver is configured Signed-off-by: Jamie McCrae --- doc/releases/release-notes-3.6.rst | 3 +++ 1 file changed, 3 insertions(+) diff --git a/doc/releases/release-notes-3.6.rst b/doc/releases/release-notes-3.6.rst index 3f1742d3ab4..daae0c64a6e 100644 --- a/doc/releases/release-notes-3.6.rst +++ b/doc/releases/release-notes-3.6.rst @@ -255,6 +255,9 @@ Libraries / Subsystems * Implemented datetime functionality in MCUmgr OS management group, this makes use of the RTC driver API. + * Fixes an issue in MCUmgr console UART input whereby the FIFO would be read outside of an ISR, + which is not supported in the next USB stack. + * File systems * Modem modules From 76c8bf0f7c3dc049e7a8ccdf060e8c20e6e002c8 Mon Sep 17 00:00:00 2001 From: Wojciech Sipak Date: Mon, 27 Nov 2023 12:10:10 +0100 Subject: [PATCH 0422/3723] drivers: interrupt_controller: intc_plic: rewrite `get_plic_dev_from_irq` There's a ternary operator that depends on configuration-defined macro: `CONFIG_DYNAMIC_INTERRUPTS` is not enabled by default for any of the platforms that use PLIC, it is possbile to set it to `=y` though. This triggered the Coverity check to report it as dead code. Fixes #65576. Signed-off-by: Wojciech Sipak --- drivers/interrupt_controller/intc_plic.c | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/drivers/interrupt_controller/intc_plic.c b/drivers/interrupt_controller/intc_plic.c index c579d28dad2..434274e8c41 100644 --- a/drivers/interrupt_controller/intc_plic.c +++ b/drivers/interrupt_controller/intc_plic.c @@ -116,10 +116,11 @@ static inline mem_addr_t get_threshold_priority_addr(const struct device *dev) */ static inline const struct device *get_plic_dev_from_irq(uint32_t irq) { - const struct device *dev = COND_CODE_1(IS_ENABLED(CONFIG_DYNAMIC_INTERRUPTS), - (z_get_sw_isr_device_from_irq(irq)), (NULL)); - - return dev == NULL ? DEVICE_DT_INST_GET(0) : dev; +#ifdef CONFIG_DYNAMIC_INTERRUPTS + return z_get_sw_isr_device_from_irq(irq); +#else + return DEVICE_DT_INST_GET(0); +#endif } /** From e49ca8b9679326a49b388f8b49749b06f53c6ebb Mon Sep 17 00:00:00 2001 From: Dominik Ermel Date: Mon, 27 Nov 2023 15:52:37 +0000 Subject: [PATCH 0423/3723] settings: Remove leftover duplicate and unused declarations Removed duplicated and unused code. Signed-off-by: Dominik Ermel --- subsys/settings/src/settings_priv.h | 16 +--------------- 1 file changed, 1 insertion(+), 15 deletions(-) diff --git a/subsys/settings/src/settings_priv.h b/subsys/settings/src/settings_priv.h index 6cb55ccefa7..b732bcef2d8 100644 --- a/subsys/settings/src/settings_priv.h +++ b/subsys/settings/src/settings_priv.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2018 Nordic Semiconductor ASA + * Copyright (c) 2018-2023 Nordic Semiconductor ASA * Copyright (c) 2015 Runtime Inc * * SPDX-License-Identifier: Apache-2.0 @@ -17,20 +17,6 @@ extern "C" { #endif -int settings_cli_register(void); -int settings_nmgr_register(void); - -struct mgmt_cbuf; -int settings_cbor_line(struct mgmt_cbuf *cb, char *name, int nlen, char *value, - int vlen); - -void settings_line_io_init(int (*read_cb)(void *ctx, off_t off, char *buf, - size_t *len), - int (*write_cb)(void *ctx, off_t off, - char const *buf, size_t len), - size_t (*get_len_cb)(void *ctx), - uint8_t io_rwbs); - int settings_line_write(const char *name, const char *value, size_t val_len, off_t w_loc, void *cb_arg); From abba8050dae1ed8b7062c294c2f1f27327b89142 Mon Sep 17 00:00:00 2001 From: Jukka Rissanen Date: Tue, 28 Nov 2023 17:37:51 +0200 Subject: [PATCH 0424/3723] net: socket: Fix v6only option documentation The v6only option is currently supported so fix the documentation in socket.h Signed-off-by: Jukka Rissanen --- include/zephyr/net/socket.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/include/zephyr/net/socket.h b/include/zephyr/net/socket.h index 756688d9b86..40458986be8 100644 --- a/include/zephyr/net/socket.h +++ b/include/zephyr/net/socket.h @@ -1113,7 +1113,7 @@ struct in_pktinfo { }; /* Socket options for IPPROTO_IPV6 level */ -/** sockopt: Don't support IPv4 access (ignored, for compatibility) */ +/** sockopt: Don't support IPv4 access */ #define IPV6_V6ONLY 26 /** sockopt: Pass an IPV6_RECVPKTINFO ancillary message that contains a From 8d8e2b0f427eb211d4a3215837be16f9b20bee9a Mon Sep 17 00:00:00 2001 From: Marek Pieta Date: Tue, 28 Nov 2023 13:31:01 +0100 Subject: [PATCH 0425/3723] drivers: usb: nrf_usbd_common: Remove unneeded assertion Code uses local RAM buffer to properly handle the case where provided USB transfer TX data is not in RAM. Signed-off-by: Marek Pieta --- drivers/usb/common/nrf_usbd_common/nrf_usbd_common.c | 2 -- 1 file changed, 2 deletions(-) diff --git a/drivers/usb/common/nrf_usbd_common/nrf_usbd_common.c b/drivers/usb/common/nrf_usbd_common/nrf_usbd_common.c index 9045e1ded70..3db193ee2f0 100644 --- a/drivers/usb/common/nrf_usbd_common/nrf_usbd_common.c +++ b/drivers/usb/common/nrf_usbd_common/nrf_usbd_common.c @@ -376,8 +376,6 @@ static bool nrf_usbd_common_feeder(nrf_usbd_common_ep_transfer_t *p_next, nrf_usbd_common_transfer_t *p_transfer, size_t ep_size) { - __ASSERT_NO_MSG(nrfx_is_in_ram(p_transfer->p_data.tx)); - size_t tx_size = p_transfer->size; if (tx_size > ep_size) { From a8d2feef83ab4ca13fbcdf74e84c9e9362f329d3 Mon Sep 17 00:00:00 2001 From: Christopher Friedt Date: Tue, 28 Nov 2023 07:21:48 -0500 Subject: [PATCH 0426/3723] maintainers: remove cfriedt as ti collaborator Just in an effort to reduce notifications in areas that I'm not super actively involved in. I was getting a lot of false positive notifications for sensors. Feel free to ping me for individual reviews on simplelink parts or TI HAL or radio drivers. Signed-off-by: Christopher Friedt --- MAINTAINERS.yml | 3 --- 1 file changed, 3 deletions(-) diff --git a/MAINTAINERS.yml b/MAINTAINERS.yml index 1f059854509..78f3cceb38d 100644 --- a/MAINTAINERS.yml +++ b/MAINTAINERS.yml @@ -2867,7 +2867,6 @@ TI SimpleLink Platforms: - vaishnavachath collaborators: - vanti - - cfriedt files: - boards/arm/cc13*/ - boards/arm/cc26*/ @@ -3491,8 +3490,6 @@ West: status: maintained maintainers: - vaishnavachath - collaborators: - - cfriedt files: [] labels: - "platform: TI" From 1e91453005d154da2e37b5f0611ddfd268dc28c5 Mon Sep 17 00:00:00 2001 From: Ryan McClelland Date: Sun, 26 Nov 2023 10:52:52 -0800 Subject: [PATCH 0427/3723] drivers: i3c: cdns: use deterministic timeout for idle Previously, the idle bit would be read for X amount of times. This could vary alot depend on the CPU speed. Timeout is now to happen from the cycle time. Signed-off-by: Ryan McClelland --- drivers/i3c/i3c_cdns.c | 71 ++++++++++++++++++------------------------ 1 file changed, 31 insertions(+), 40 deletions(-) diff --git a/drivers/i3c/i3c_cdns.c b/drivers/i3c/i3c_cdns.c index cad71e5cae6..4f99e8da886 100644 --- a/drivers/i3c/i3c_cdns.c +++ b/drivers/i3c/i3c_cdns.c @@ -375,9 +375,11 @@ #define I3C_MAX_MSGS 10 #define I3C_SIR_DEFAULT_DA 0x7F #define I3C_MAX_IDLE_CANCEL_WAIT_RETRIES 50 -#define I3C_MAX_IDLE_WAIT_RETRIES 5000 #define I3C_PRESCL_REG_SCALE (4) #define I2C_PRESCL_REG_SCALE (5) +#define I3C_WAIT_FOR_IDLE_STATE_US 100 +#define I3C_IDLE_TIMEOUT_CYC \ + (I3C_WAIT_FOR_IDLE_STATE_US * (sys_clock_hw_cycles_per_sec() / USEC_PER_SEC)) /* Target T_LOW period in open-drain mode. */ #define I3C_BUS_TLOW_OD_MIN_NS 200 @@ -613,6 +615,25 @@ static int cdns_i3c_read_rx_fifo(const struct cdns_i3c_config *config, void *buf return 0; } +static inline int cdns_i3c_wait_for_idle(const struct device *dev) +{ + const struct cdns_i3c_config *config = dev->config; + uint32_t start_time = k_cycle_get_32(); + + /** + * Spin waiting for device to go idle. It is unlikely that this will + * actually take any time unless if the last transaction came immediately + * after an error condition. + */ + while (!(sys_read32(config->base + MST_STATUS0) & MST_STATUS0_IDLE)) { + if (k_cycle_get_32() - start_time > I3C_IDLE_TIMEOUT_CYC) { + return -EAGAIN; + } + } + + return 0; +} + static void cdns_i3c_set_prescalers(const struct device *dev) { struct cdns_i3c_data *data = dev->data; @@ -995,19 +1016,9 @@ static int cdns_i3c_do_ccc(const struct device *dev, struct i3c_ccc_payload *pay k_mutex_lock(&data->bus_lock, K_FOREVER); - /** - * Spin waiting for device to go idle. It is unlikely that this will - * actually take any time unless if the last transaction came immediately - * after an error condition. - */ - uint32_t retry_count = I3C_MAX_IDLE_WAIT_RETRIES; - - while (!(sys_read32(config->base + MST_STATUS0) & MST_STATUS0_IDLE) && (retry_count > 0)) { - retry_count--; - } - if (retry_count == 0) { - LOG_ERR("%s: Unable to start transfer, device not idle", dev->name); - ret = -EAGAIN; + /* wait for idle */ + ret = cdns_i3c_wait_for_idle(dev); + if (ret != 0) { goto error; } @@ -1383,19 +1394,9 @@ static int cdns_i3c_i2c_transfer(const struct device *dev, struct i3c_i2c_device k_mutex_lock(&data->bus_lock, K_FOREVER); - /** - * Spin waiting for device to go idle. It is unlikely that this will - * actually take any time unless if the last transaction came immediately - * after an error condition. - */ - uint32_t retry_count = I3C_MAX_IDLE_WAIT_RETRIES; - - while (!(sys_read32(config->base + MST_STATUS0) & MST_STATUS0_IDLE) && (retry_count > 0)) { - retry_count--; - } - if (retry_count == 0) { - LOG_ERR("%s: Unable to start transfer, device not idle", dev->name); - ret = -EAGAIN; + /* wait for idle */ + ret = cdns_i3c_wait_for_idle(dev); + if (ret != 0) { goto error; } @@ -1676,19 +1677,9 @@ static int cdns_i3c_transfer(const struct device *dev, struct i3c_device_desc *t k_mutex_lock(&data->bus_lock, K_FOREVER); - /** - * Spin waiting for device to go idle. It is unlikely that this will - * actually take any time unless if the last transaction came immediately - * after an error condition. - */ - uint32_t retry_count = I3C_MAX_IDLE_WAIT_RETRIES; - - while (!(sys_read32(config->base + MST_STATUS0) & MST_STATUS0_IDLE) && (retry_count > 0)) { - retry_count--; - } - if (retry_count == 0) { - LOG_ERR("%s: Unable to start transfer, device not idle", dev->name); - ret = -EAGAIN; + /* wait for idle */ + ret = cdns_i3c_wait_for_idle(dev); + if (ret != 0) { goto error; } From 5b1b260f8079dcbc23bc6e0857d7e633f89e1ab9 Mon Sep 17 00:00:00 2001 From: Armin Brauns Date: Wed, 15 Nov 2023 15:13:49 +0000 Subject: [PATCH 0428/3723] bluetooth: add HCI driver parameter to set controller's public address This allows HCI drivers to expose vendor-specific functions to set the public address. Signed-off-by: Armin Brauns --- doc/releases/migration-guide-3.6.rst | 5 +++ drivers/bluetooth/hci/Kconfig | 10 +++++ drivers/bluetooth/hci/h4.c | 4 +- drivers/bluetooth/hci/hci_psoc6_bless.c | 3 +- include/zephyr/bluetooth/bluetooth.h | 6 +++ include/zephyr/drivers/bluetooth/hci_driver.h | 12 +++++- subsys/bluetooth/host/hci_core.c | 12 +++++- subsys/bluetooth/host/id.c | 25 ++++++++----- tests/bluetooth/host/id/bt_id_create/Kconfig | 11 ++++++ .../bluetooth/host/id/bt_id_create/src/main.c | 37 +++++++++++++++++++ .../src/test_suite_invalid_inputs.c | 4 ++ .../host/id/bt_id_create/testcase.yaml | 6 +++ 12 files changed, 122 insertions(+), 13 deletions(-) create mode 100644 tests/bluetooth/host/id/bt_id_create/Kconfig diff --git a/doc/releases/migration-guide-3.6.rst b/doc/releases/migration-guide-3.6.rst index e585fb7482c..f0353d2ceaa 100644 --- a/doc/releases/migration-guide-3.6.rst +++ b/doc/releases/migration-guide-3.6.rst @@ -52,6 +52,11 @@ Device Drivers and Device Tree drdy-pin = <2>; }; }; +* The optional :c:func:`setup()` function in the Bluetooth HCI driver API (enabled through + :kconfig:option:`CONFIG_BT_HCI_SETUP`) has gained a function parameter of type + :c:struct:`bt_hci_setup_params`. By default, the struct is empty, but drivers can opt-in to + :kconfig:option:`CONFIG_BT_HCI_SET_PUBLIC_ADDR` if they support setting the controller's public + identity address, which will then be passed in the ``public_addr`` field. (:github:`62994`) diff --git a/drivers/bluetooth/hci/Kconfig b/drivers/bluetooth/hci/Kconfig index 60326ec7cf8..96c8f1ed4ef 100644 --- a/drivers/bluetooth/hci/Kconfig +++ b/drivers/bluetooth/hci/Kconfig @@ -164,6 +164,16 @@ config BT_DRIVER_QUIRK_NO_AUTO_DLE This has to be enabled when the BLE controller connected is Zephyr open source controller. +config BT_HCI_SET_PUBLIC_ADDR + bool + select BT_HCI_SETUP + help + Pass the controller's public address to the HCI driver in setup() + + This option should be enabled by drivers for controllers that support setting the + public identity through vendor-specific commands. They can then implement the + setup() HCI driver API function and get the address to set from the public_addr field. + config BT_HCI_SETUP bool help diff --git a/drivers/bluetooth/hci/h4.c b/drivers/bluetooth/hci/h4.c index c263c3f0c5d..cc4c346d602 100644 --- a/drivers/bluetooth/hci/h4.c +++ b/drivers/bluetooth/hci/h4.c @@ -529,8 +529,10 @@ static int h4_open(void) } #if defined(CONFIG_BT_HCI_SETUP) -static int h4_setup(void) +static int h4_setup(const struct bt_hci_setup_params *params) { + ARG_UNUSED(params); + /* Extern bt_h4_vnd_setup function. * This function executes vendor-specific commands sequence to * initialize BT Controller before BT Host executes Reset sequence. diff --git a/drivers/bluetooth/hci/hci_psoc6_bless.c b/drivers/bluetooth/hci/hci_psoc6_bless.c index 3a5fddb1000..9f56eba7f60 100644 --- a/drivers/bluetooth/hci/hci_psoc6_bless.c +++ b/drivers/bluetooth/hci/hci_psoc6_bless.c @@ -196,8 +196,9 @@ static int psoc6_bless_send(struct net_buf *buf) return 0; } -static int psoc6_bless_setup(void) +static int psoc6_bless_setup(const struct bt_hci_setup_params *params) { + ARG_UNUSED(params); struct net_buf *buf; int err; uint8_t *addr = (uint8_t *)&SFLASH_BLE_DEVICE_ADDRESS[0]; diff --git a/include/zephyr/bluetooth/bluetooth.h b/include/zephyr/bluetooth/bluetooth.h index c97e1445cb3..c93cf4a5f25 100644 --- a/include/zephyr/bluetooth/bluetooth.h +++ b/include/zephyr/bluetooth/bluetooth.h @@ -340,6 +340,12 @@ void bt_id_get(bt_addr_le_t *addrs, size_t *count); * If an insufficient amount of identities were recovered the app may then * call bt_id_create() to create new ones. * + * If supported by the HCI driver (indicated by setting + * @kconfig{CONFIG_BT_HCI_SET_PUBLIC_ADDR}), the first call to this function can be + * used to set the controller's public identity address. This call must happen + * before calling bt_enable(). Subsequent calls always add/generate random + * static addresses. + * * @param addr Address to use for the new identity. If NULL or initialized * to BT_ADDR_LE_ANY the stack will generate a new random * static address for the identity and copy it to the given diff --git a/include/zephyr/drivers/bluetooth/hci_driver.h b/include/zephyr/drivers/bluetooth/hci_driver.h index b318ad55ffb..e8a26b2cb94 100644 --- a/include/zephyr/drivers/bluetooth/hci_driver.h +++ b/include/zephyr/drivers/bluetooth/hci_driver.h @@ -139,6 +139,16 @@ enum bt_hci_driver_bus { BT_HCI_DRIVER_BUS_IPM = 9, }; +#if defined(CONFIG_BT_HCI_SETUP) || defined(__DOXYGEN__) +struct bt_hci_setup_params { + /** The public identity address to give to the controller. This field is used when the + * driver selects @kconfig{CONFIG_BT_HCI_SET_PUBLIC_ADDR} to indicate that it supports + * setting the controller's public address. + */ + bt_addr_t public_addr; +}; +#endif + /** * @brief Abstraction which represents the HCI transport to the controller. * @@ -213,7 +223,7 @@ struct bt_hci_driver { * * @return 0 on success or negative error number on failure. */ - int (*setup)(void); + int (*setup)(const struct bt_hci_setup_params *params); #endif /* defined(CONFIG_BT_HCI_SETUP) || defined(__DOXYGEN__)*/ }; diff --git a/subsys/bluetooth/host/hci_core.c b/subsys/bluetooth/host/hci_core.c index b37cd45e1ae..e4ea19c6dce 100644 --- a/subsys/bluetooth/host/hci_core.c +++ b/subsys/bluetooth/host/hci_core.c @@ -3668,9 +3668,19 @@ static void hci_vs_init(void) static int hci_init(void) { int err; + #if defined(CONFIG_BT_HCI_SETUP) + struct bt_hci_setup_params setup_params = { 0 }; + + bt_addr_copy(&setup_params.public_addr, BT_ADDR_ANY); +#if defined(CONFIG_BT_HCI_SET_PUBLIC_ADDR) + if (bt_dev.id_count > 0 && bt_dev.id_addr[BT_ID_DEFAULT].type == BT_ADDR_LE_PUBLIC) { + bt_addr_copy(&setup_params.public_addr, &bt_dev.id_addr[BT_ID_DEFAULT].a); + } +#endif /* defined(CONFIG_BT_HCI_SET_PUBLIC_ADDR) */ + if (bt_dev.drv->setup) { - err = bt_dev.drv->setup(); + err = bt_dev.drv->setup(&setup_params); if (err) { return err; } diff --git a/subsys/bluetooth/host/id.c b/subsys/bluetooth/host/id.c index 6b5fcbd5d17..8b492184458 100644 --- a/subsys/bluetooth/host/id.c +++ b/subsys/bluetooth/host/id.c @@ -1281,20 +1281,27 @@ int bt_id_create(bt_addr_le_t *addr, uint8_t *irk) { int new_id, err; - if (addr && !bt_addr_le_eq(addr, BT_ADDR_LE_ANY)) { - if (addr->type != BT_ADDR_LE_RANDOM || - !BT_ADDR_IS_STATIC(&addr->a)) { - LOG_ERR("Only static random identity address supported"); - return -EINVAL; - } + if (!IS_ENABLED(CONFIG_BT_PRIVACY) && irk) { + return -EINVAL; + } + if (addr && !bt_addr_le_eq(addr, BT_ADDR_LE_ANY)) { if (id_find(addr) >= 0) { return -EALREADY; } - } - if (!IS_ENABLED(CONFIG_BT_PRIVACY) && irk) { - return -EINVAL; + if (addr->type == BT_ADDR_LE_PUBLIC && IS_ENABLED(CONFIG_BT_HCI_SET_PUBLIC_ADDR)) { + /* set the single public address */ + if (bt_dev.id_count != 0) { + return -EALREADY; + } + bt_addr_le_copy(&bt_dev.id_addr[BT_ID_DEFAULT], addr); + bt_dev.id_count++; + return BT_ID_DEFAULT; + } else if (addr->type != BT_ADDR_LE_RANDOM || !BT_ADDR_IS_STATIC(&addr->a)) { + LOG_ERR("Only random static identity address supported"); + return -EINVAL; + } } if (bt_dev.id_count == ARRAY_SIZE(bt_dev.id_addr)) { diff --git a/tests/bluetooth/host/id/bt_id_create/Kconfig b/tests/bluetooth/host/id/bt_id_create/Kconfig new file mode 100644 index 00000000000..4dbe3e79c9f --- /dev/null +++ b/tests/bluetooth/host/id/bt_id_create/Kconfig @@ -0,0 +1,11 @@ +# Copyright (c) 2023 Nordic Semiconductor ASA +# +# SPDX-License-Identifier: Apache-2.0 + +config SELECT_BT_HCI_SET_PUBLIC_ADDR + bool "dummy kconfig" + select BT_HCI_SET_PUBLIC_ADDR + help + dummy kconfig + +source "Kconfig.zephyr" diff --git a/tests/bluetooth/host/id/bt_id_create/src/main.c b/tests/bluetooth/host/id/bt_id_create/src/main.c index f9919d78da1..0c8b3d08bfe 100644 --- a/tests/bluetooth/host/id/bt_id_create/src/main.c +++ b/tests/bluetooth/host/id/bt_id_create/src/main.c @@ -215,3 +215,40 @@ ZTEST(bt_id_create, test_create_id_valid_input_address) zassert_mem_equal(&bt_dev.id_addr[new_id], BT_STATIC_RANDOM_LE_ADDR_1, sizeof(bt_addr_le_t), "Incorrect address was set"); } + +/* + * Test creating a new public identity. + * + * Constraints: + * - A valid address of type public is used + * - Input IRK is NULL + * - 'BT_DEV_ENABLE' flag is set in bt_dev.flags + * + * Expected behaviour: + * - The public address is loaded to bt_dev.id_addr[BT_ID_DEFAULT] + * - bt_dev.id_count is incremented + */ +ZTEST(bt_id_create, test_public_address) +{ + int id_count, new_id; + bt_addr_le_t addr = *BT_LE_ADDR; + + if (!IS_ENABLED(CONFIG_BT_HCI_SET_PUBLIC_ADDR)) { + ztest_test_skip(); + } + + id_count = bt_dev.id_count; + atomic_set_bit(bt_dev.flags, BT_DEV_ENABLE); + /* Calling bt_addr_le_create_static() isn't expected */ + bt_addr_le_create_static_fake.return_val = -1; + + new_id = bt_id_create(&addr, NULL); + + expect_not_called_bt_addr_le_create_static(); + + zassert_true(new_id == BT_ID_DEFAULT, "Unexpected error code '%d' was returned", new_id); + zassert_true(bt_dev.id_count == (id_count + 1), "Incorrect ID count %d was set", + bt_dev.id_count); + zassert_mem_equal(&bt_dev.id_addr[new_id], BT_LE_ADDR, sizeof(bt_addr_le_t), + "Incorrect address was set"); +} diff --git a/tests/bluetooth/host/id/bt_id_create/src/test_suite_invalid_inputs.c b/tests/bluetooth/host/id/bt_id_create/src/test_suite_invalid_inputs.c index c363a735da9..ed97c06ce8a 100644 --- a/tests/bluetooth/host/id/bt_id_create/src/test_suite_invalid_inputs.c +++ b/tests/bluetooth/host/id/bt_id_create/src/test_suite_invalid_inputs.c @@ -93,6 +93,10 @@ ZTEST(bt_id_create_invalid_inputs, test_public_address) { int err; + if (IS_ENABLED(CONFIG_BT_HCI_SET_PUBLIC_ADDR)) { + ztest_test_skip(); + } + err = bt_id_create(BT_LE_ADDR, NULL); zassert_true(err == -EINVAL, "Unexpected error code '%d' was returned", err); diff --git a/tests/bluetooth/host/id/bt_id_create/testcase.yaml b/tests/bluetooth/host/id/bt_id_create/testcase.yaml index 03d016e39a5..6d9d713f10e 100644 --- a/tests/bluetooth/host/id/bt_id_create/testcase.yaml +++ b/tests/bluetooth/host/id/bt_id_create/testcase.yaml @@ -5,6 +5,12 @@ common: tests: bluetooth.host.bt_id_create.default: type: unit + bluetooth.host.bt_id_create.bt_set_public_addr: + type: unit + extra_configs: + - CONFIG_BT_SMP=y + - CONFIG_BT_PRIVACY=y + - CONFIG_SELECT_BT_HCI_SET_PUBLIC_ADDR=y bluetooth.host.bt_id_create.bt_privacy_enabled: type: unit extra_configs: From 57b04c1eb0d70de92998f0d5de7794876a803101 Mon Sep 17 00:00:00 2001 From: Armin Brauns Date: Tue, 14 Nov 2023 14:15:10 +0000 Subject: [PATCH 0429/3723] drivers: refactor BlueNRG SPI driver for more config options "LL only" is not the only config option of potential interest, e.g. the public address is also important. Signed-off-by: Armin Brauns --- drivers/bluetooth/hci/spi.c | 38 +++++++++++++++++-------------------- 1 file changed, 17 insertions(+), 21 deletions(-) diff --git a/drivers/bluetooth/hci/spi.c b/drivers/bluetooth/hci/spi.c index a61920b0745..891fb5184bd 100644 --- a/drivers/bluetooth/hci/spi.c +++ b/drivers/bluetooth/hci/spi.c @@ -95,15 +95,10 @@ static uint8_t attempts; #if defined(CONFIG_BT_BLUENRG_ACI) #define BLUENRG_ACI_WRITE_CONFIG_DATA BT_OP(BT_OGF_VS, 0x000C) -#define BLUENRG_ACI_WRITE_CONFIG_CMD_LL 0x2C -#define BLUENRG_ACI_LL_MODE 0x01 +#define BLUENRG_CONFIG_LL_ONLY_OFFSET 0x2C +#define BLUENRG_CONFIG_LL_ONLY_LEN 0x01 -struct bluenrg_aci_cmd_ll_param { - uint8_t cmd; - uint8_t length; - uint8_t value; -}; -static int bt_spi_send_aci_config_data_controller_mode(void); +static int bt_spi_send_aci_config(uint8_t offset, const uint8_t *value, size_t value_len); #endif /* CONFIG_BT_BLUENRG_ACI */ static const struct spi_dt_spec bus = SPI_DT_SPEC_INST_GET( @@ -154,13 +149,16 @@ static bool bt_spi_handle_vendor_evt(uint8_t *msg) bool handled = false; switch (bt_spi_get_evt(msg)) { - case EVT_BLUE_INITIALIZED: + case EVT_BLUE_INITIALIZED: { k_sem_give(&sem_initialised); #if defined(CONFIG_BT_BLUENRG_ACI) /* force BlueNRG to be on controller mode */ - bt_spi_send_aci_config_data_controller_mode(); + uint8_t data = 1; + + bt_spi_send_aci_config(BLUENRG_CONFIG_LL_ONLY_OFFSET, &data, 1); #endif handled = true; + } default: break; } @@ -224,25 +222,23 @@ static bool exit_irq_high_loop(void) #endif /* CONFIG_BT_SPI_BLUENRG */ #if defined(CONFIG_BT_BLUENRG_ACI) -static int bt_spi_send_aci_config_data_controller_mode(void) +static int bt_spi_send_aci_config(uint8_t offset, const uint8_t *value, size_t value_len) { - struct bluenrg_aci_cmd_ll_param *param; struct net_buf *buf; + uint8_t *cmd_data; + size_t data_len = 2 + value_len; - buf = bt_hci_cmd_create(BLUENRG_ACI_WRITE_CONFIG_DATA, sizeof(*param)); + buf = bt_hci_cmd_create(BLUENRG_ACI_WRITE_CONFIG_DATA, data_len); if (!buf) { return -ENOBUFS; } - param = net_buf_add(buf, sizeof(*param)); - param->cmd = BLUENRG_ACI_WRITE_CONFIG_CMD_LL; - param->length = 0x1; - /* Force BlueNRG-MS roles to Link Layer only mode */ - param->value = BLUENRG_ACI_LL_MODE; + cmd_data = net_buf_add(buf, data_len); + cmd_data[0] = offset; + cmd_data[1] = value_len; + memcpy(&cmd_data[2], value, value_len); - bt_hci_cmd_send(BLUENRG_ACI_WRITE_CONFIG_DATA, buf); - - return 0; + return bt_hci_cmd_send(BLUENRG_ACI_WRITE_CONFIG_DATA, buf); } #endif /* CONFIG_BT_BLUENRG_ACI */ From 4321f86f1e62dca3f5afcc546fc3e2753191cd34 Mon Sep 17 00:00:00 2001 From: Armin Brauns Date: Tue, 14 Nov 2023 14:27:55 +0000 Subject: [PATCH 0430/3723] drivers: allow setting BlueNRG public address The zephyr bluetooth stack expects the controller to know its public address, if any. At least for BlueNRG, the public address is forgotten with every reset/power cycle, so there needs to be a way to set it from within zephyr. This is accomplished using the `Aci_Hal_Write_Config_Data` HCI command, as described in PM0237. Signed-off-by: Armin Brauns --- drivers/bluetooth/hci/Kconfig | 1 + drivers/bluetooth/hci/spi.c | 24 ++++++++++++++++++++++++ 2 files changed, 25 insertions(+) diff --git a/drivers/bluetooth/hci/Kconfig b/drivers/bluetooth/hci/Kconfig index 96c8f1ed4ef..9964b57036f 100644 --- a/drivers/bluetooth/hci/Kconfig +++ b/drivers/bluetooth/hci/Kconfig @@ -120,6 +120,7 @@ config BT_SPI_INIT_PRIORITY config BT_BLUENRG_ACI bool "ACI message with with BlueNRG-based devices" + select BT_HCI_SET_PUBLIC_ADDR help Enable support for devices compatible with the BlueNRG Bluetooth Stack. Current driver supports: ST BLUENRG-MS. diff --git a/drivers/bluetooth/hci/spi.c b/drivers/bluetooth/hci/spi.c index 891fb5184bd..8b5bbc4bd46 100644 --- a/drivers/bluetooth/hci/spi.c +++ b/drivers/bluetooth/hci/spi.c @@ -95,6 +95,8 @@ static uint8_t attempts; #if defined(CONFIG_BT_BLUENRG_ACI) #define BLUENRG_ACI_WRITE_CONFIG_DATA BT_OP(BT_OGF_VS, 0x000C) +#define BLUENRG_CONFIG_PUBADDR_OFFSET 0x00 +#define BLUENRG_CONFIG_PUBADDR_LEN 0x06 #define BLUENRG_CONFIG_LL_ONLY_OFFSET 0x2C #define BLUENRG_CONFIG_LL_ONLY_LEN 0x01 @@ -240,6 +242,27 @@ static int bt_spi_send_aci_config(uint8_t offset, const uint8_t *value, size_t v return bt_hci_cmd_send(BLUENRG_ACI_WRITE_CONFIG_DATA, buf); } + +int bt_spi_bluenrg_setup(const struct bt_hci_setup_params *params) +{ + int ret; + const bt_addr_t addr = params->public_addr; + + if (bt_addr_eq(&addr, BT_ADDR_NONE) || bt_addr_eq(&addr, BT_ADDR_ANY)) { + return -EINVAL; + } + + ret = bt_spi_send_aci_config( + BLUENRG_CONFIG_PUBADDR_OFFSET, + addr.val, sizeof(addr.val)); + + if (ret != 0) { + LOG_ERR("Failed to set BlueNRG public address (%d)", ret); + return ret; + } + + return 0; +} #endif /* CONFIG_BT_BLUENRG_ACI */ static struct net_buf *bt_spi_rx_buf_construct(uint8_t *msg) @@ -516,6 +539,7 @@ static const struct bt_hci_driver drv = { .bus = BT_HCI_DRIVER_BUS_SPI, #if defined(CONFIG_BT_BLUENRG_ACI) .quirks = BT_QUIRK_NO_RESET, + .setup = bt_spi_bluenrg_setup, #endif /* CONFIG_BT_BLUENRG_ACI */ .open = bt_spi_open, .send = bt_spi_send, From 4c035af05c0791bc8499a933a00124451c8f6896 Mon Sep 17 00:00:00 2001 From: Paszkiet Kamil Date: Tue, 7 Nov 2023 15:15:06 +0100 Subject: [PATCH 0431/3723] scripts: tests: twister_blackbox: Add test test_report.py add test to test_report.py: -platform_reports -report_suffix -report_name -report_dir -outdir Signed-off-by: Paszkiet Kamil --- scripts/tests/twister_blackbox/test_report.py | 301 ++++++++++++++++++ 1 file changed, 301 insertions(+) create mode 100644 scripts/tests/twister_blackbox/test_report.py diff --git a/scripts/tests/twister_blackbox/test_report.py b/scripts/tests/twister_blackbox/test_report.py new file mode 100644 index 00000000000..aa5a541ff3d --- /dev/null +++ b/scripts/tests/twister_blackbox/test_report.py @@ -0,0 +1,301 @@ +#!/usr/bin/env python3 +# Copyright (c) 2023 Intel Corporation +# +# SPDX-License-Identifier: Apache-2.0 +""" +Blackbox tests for twister's command line functions +""" + +import importlib +import mock +import os +import shutil +import pytest +import sys +from lxml import etree +import json + +from conftest import TEST_DATA, ZEPHYR_BASE, testsuite_filename_mock +from twisterlib.testplan import TestPlan + + +@mock.patch.object(TestPlan, 'TESTSUITE_FILENAME', testsuite_filename_mock) +class TestReport: + TESTDATA_1 = [ + ( + os.path.join(TEST_DATA, 'tests', 'dummy', 'agnostic'), + ['qemu_x86', 'qemu_x86_64'], + [ + 'qemu_x86_64.xml', 'qemu_x86.xml', + 'testplan.json', 'twister.json', + 'twister.log', 'twister_report.xml', + 'twister_suite_report.xml', 'twister.xml' + ] + ), + ] + TESTDATA_2 = [ + ( + os.path.join(TEST_DATA, 'tests', 'dummy', 'agnostic'), + ['qemu_x86', 'qemu_x86_64'], + [ + 'qemu_x86_64_TEST.xml', 'qemu_x86_TEST.xml', + 'twister_TEST.json', 'twister_TEST_report.xml', + 'twister_TEST_suite_report.xml', 'twister_TEST.xml' + ] + ), + ] + TESTDATA_3 = [ + ( + os.path.join(TEST_DATA, 'tests', 'dummy', 'agnostic'), + ['qemu_x86', 'qemu_x86_64'], + ['--report-name', 'abcd'], + [ + 'abcd.json', 'abcd_report.xml', + 'abcd_suite_report.xml', 'abcd.xml' + ] + ), + ( + os.path.join(TEST_DATA, 'tests', 'dummy', 'agnostic'), + ['qemu_x86', 'qemu_x86_64'], + ['--report-name', '1234', '--platform-reports'], + [ + 'qemu_x86_64.xml', 'qemu_x86.xml', + '1234.json', '1234_report.xml', + '1234_suite_report.xml', '1234.xml' + ] + ), + ( + os.path.join(TEST_DATA, 'tests', 'dummy', 'agnostic'), + ['qemu_x86', 'qemu_x86_64'], + ['--report-name', 'Final', '--platform-reports', '--report-suffix=Test'], + [ + 'qemu_x86_64_Test.xml', 'qemu_x86_Test.xml', + 'Final_Test.json', 'Final_Test_report.xml', + 'Final_Test_suite_report.xml', 'Final_Test.xml' + ] + ), + ] + TESTDATA_4 = [ + ( + os.path.join(TEST_DATA, 'tests', 'dummy', 'agnostic'), + ['qemu_x86'], + [ + 'twister.json', 'twister_report.xml', + 'twister_suite_report.xml', 'twister.xml' + ], + "TEST_DIR" + ), + ] + TESTDATA_5 = [ + ( + os.path.join(TEST_DATA, 'tests', 'dummy', 'agnostic'), + ['qemu_x86'], + [ + 'testplan.json', 'twister.log', + 'twister.json', 'twister_report.xml', + 'twister_suite_report.xml', 'twister.xml' + ], + "OUT_DIR" + ), + ] + + @classmethod + def setup_class(cls): + apath = os.path.join(ZEPHYR_BASE, 'scripts', 'twister') + cls.loader = importlib.machinery.SourceFileLoader('__main__', apath) + cls.spec = importlib.util.spec_from_loader(cls.loader.name, cls.loader) + cls.twister_module = importlib.util.module_from_spec(cls.spec) + + @classmethod + def teardown_class(cls): + pass + + @pytest.mark.usefixtures("clear_log") + @pytest.mark.parametrize( + 'test_path, test_platforms, file_name', + TESTDATA_1, + ids=[ + 'platform_reports' + ] + ) + def test_platform_reports(self, capfd, test_path, test_platforms, file_name): + args = ['-i', '-T', test_path, '--platform-reports'] + \ + [val for pair in zip( + ['-p'] * len(test_platforms), test_platforms + ) for val in pair] + twister_path = os.path.join(ZEPHYR_BASE, "twister-out") + if os.path.exists(twister_path): + shutil.rmtree(twister_path) + + with mock.patch.object(sys, 'argv', [sys.argv[0]] + args), \ + pytest.raises(SystemExit) as sys_exit: + self.loader.exec_module(self.twister_module) + + out, err = capfd.readouterr() + sys.stdout.write(out) + sys.stderr.write(err) + + for f_name in file_name: + path = os.path.join(twister_path, f_name) + assert os.path.exists(path), 'file not found' + + if path.endswith(".json"): + with open(path, "r") as json_file: + data = json.load(json_file) + assert data, f"JSON file '{path}' is empty" + + elif path.endswith(".xml"): + tree = etree.parse(path) + xml_text = etree.tostring(tree, encoding="utf-8").decode("utf-8") + assert xml_text.strip(), f"XML file '{path}' is empty" + + elif path.endswith(".log"): + with open(path, "r") as log_file: + text_content = log_file.read() + assert text_content.strip(), f"LOG file '{path}' is empty" + + else: + pytest.fail(f"Unsupported file type: '{path}'") + + for f_platform in test_platforms: + platform_path = os.path.join(twister_path, f_platform) + assert os.path.exists(platform_path), f'file not found {f_platform}' + + assert str(sys_exit.value) == '0' + + @pytest.mark.usefixtures("clear_log") + @pytest.mark.parametrize( + 'test_path, test_platforms, file_name', + TESTDATA_2, + ids=[ + 'report_suffix', + ] + ) + def test_report_suffix(self, capfd, test_path, test_platforms, file_name): + args = ['-i', '-T', test_path, '--platform-reports', '--report-suffix=TEST'] + \ + [val for pair in zip( + ['-p'] * len(test_platforms), test_platforms + ) for val in pair] + + twister_path = os.path.join(ZEPHYR_BASE, "twister-out") + if os.path.exists(twister_path): + shutil.rmtree(twister_path) + + with mock.patch.object(sys, 'argv', [sys.argv[0]] + args), \ + pytest.raises(SystemExit) as sys_exit: + self.loader.exec_module(self.twister_module) + + out, err = capfd.readouterr() + sys.stdout.write(out) + sys.stderr.write(err) + + for f_name in file_name: + path = os.path.join(twister_path, f_name) + assert os.path.exists(path), f'file not found {f_name}' + + assert str(sys_exit.value) == '0' + + @pytest.mark.usefixtures("clear_log") + @pytest.mark.parametrize( + 'test_path, test_platforms, report_arg, file_name', + TESTDATA_3, + ids=[ + 'only_report_name', + 'report_name + platform_reports', + 'report-name + platform-reports + report-suffix' + ] + ) + def test_report_name(self, capfd, test_path, test_platforms, report_arg, file_name): + args = ['-i', '-T', test_path] + \ + [val for pair in zip( + ['-p'] * len(test_platforms), test_platforms + ) for val in pair] + \ + [val for pair in zip( + report_arg + ) for val in pair] + + twister_path = os.path.join(ZEPHYR_BASE, "twister-out") + if os.path.exists(twister_path): + shutil.rmtree(twister_path) + + with mock.patch.object(sys, 'argv', [sys.argv[0]] + args), \ + pytest.raises(SystemExit) as sys_exit: + self.loader.exec_module(self.twister_module) + + out, err = capfd.readouterr() + sys.stdout.write(out) + sys.stderr.write(err) + + for f_name in file_name: + path = os.path.join(twister_path, f_name) + assert os.path.exists(path), f'file not found {f_name}' + + assert str(sys_exit.value) == '0' + + @pytest.mark.usefixtures("clear_log") + @pytest.mark.parametrize( + 'test_path, test_platforms, file_name, dir_name', + TESTDATA_4, + ids=[ + 'report_dir', + ] + ) + def test_report_dir(self, capfd, test_path, test_platforms, file_name, dir_name): + args = ['-i', '-T', test_path, "--report-dir", dir_name] + \ + [val for pair in zip( + ['-p'] * len(test_platforms), test_platforms + ) for val in pair] + + twister_path = os.path.join(ZEPHYR_BASE, dir_name) + if os.path.exists(twister_path): + shutil.rmtree(twister_path) + + with mock.patch.object(sys, 'argv', [sys.argv[0]] + args), \ + pytest.raises(SystemExit) as sys_exit: + self.loader.exec_module(self.twister_module) + + out, err = capfd.readouterr() + sys.stdout.write(out) + sys.stderr.write(err) + + for f_name in file_name: + path = os.path.join(twister_path, f_name) + assert os.path.exists(path), f'file not found {f_name}' + + assert str(sys_exit.value) == '0' + + @pytest.mark.usefixtures("clear_log") + @pytest.mark.parametrize( + 'test_path, test_platforms, file_name, dir_name', + TESTDATA_5, + ids=[ + 'outdir', + ] + ) + def test_outdir(self, capfd, test_path, test_platforms, file_name, dir_name): + args = ['-i', '-T', test_path, "--outdir", dir_name] + \ + [val for pair in zip( + ['-p'] * len(test_platforms), test_platforms + ) for val in pair] + + twister_path = os.path.join(ZEPHYR_BASE, dir_name) + if os.path.exists(twister_path): + shutil.rmtree(twister_path) + + with mock.patch.object(sys, 'argv', [sys.argv[0]] + args), \ + pytest.raises(SystemExit) as sys_exit: + self.loader.exec_module(self.twister_module) + + out, err = capfd.readouterr() + sys.stdout.write(out) + sys.stderr.write(err) + + for f_name in file_name: + path = os.path.join(twister_path, f_name) + assert os.path.exists(path), 'file not found {f_name}' + + for f_platform in test_platforms: + platform_path = os.path.join(twister_path, f_platform) + assert os.path.exists(platform_path), f'file not found {f_platform}' + + assert str(sys_exit.value) == '0' From 447bdaa5061360ef523dd1fe7e90a6c851380d85 Mon Sep 17 00:00:00 2001 From: Andriy Gelman Date: Mon, 27 Nov 2023 14:58:17 -0500 Subject: [PATCH 0432/3723] drivers: ethernet: eth_sam_gmac: Fix ptp adjust NSEC_PER_SEC is an unsigned literal which will promote variable increment to unsigned for the comparison operation, thus returning -EINVAL for negative increment values. For positive increment, -NSEC_PER_SEC becomes a large unsigned value which will also return -EINVAL. Fix by casting NSEC_PER_SEC to an int. Signed-off-by: Andriy Gelman --- drivers/ethernet/eth_sam_gmac.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/ethernet/eth_sam_gmac.c b/drivers/ethernet/eth_sam_gmac.c index b4746e4e743..8d82c317cd5 100644 --- a/drivers/ethernet/eth_sam_gmac.c +++ b/drivers/ethernet/eth_sam_gmac.c @@ -2449,7 +2449,7 @@ static int ptp_clock_sam_gmac_adjust(const struct device *dev, int increment) const struct eth_sam_dev_cfg *const cfg = ptp_context->eth_dev->config; Gmac *gmac = cfg->regs; - if ((increment <= -NSEC_PER_SEC) || (increment >= NSEC_PER_SEC)) { + if ((increment <= -(int)NSEC_PER_SEC) || (increment >= (int)NSEC_PER_SEC)) { return -EINVAL; } From e6bcc986bf2aef30936c4d9c518673ae3cfdfa1a Mon Sep 17 00:00:00 2001 From: Adam Wojasinski Date: Thu, 5 Oct 2023 09:09:30 +0200 Subject: [PATCH 0433/3723] drivers: spi: spi_nrfx_spim: Include nrf_clock.h only for nRF5340 The CLOCK HAL header is only needed for nRF5340 SoC. It's used when user wants to configure SPIM instance to 32 Mbps. The HAL checks if is running at 128 MHz as only then 32 Mbps is supported. Signed-off-by: Adam Wojasinski --- drivers/spi/spi_nrfx_spim.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/drivers/spi/spi_nrfx_spim.c b/drivers/spi/spi_nrfx_spim.c index 8b187f54c52..7c5a93237d2 100644 --- a/drivers/spi/spi_nrfx_spim.c +++ b/drivers/spi/spi_nrfx_spim.c @@ -12,8 +12,10 @@ #include #include #endif -#include +#ifdef CONFIG_SOC_NRF5340_CPUAPP #include +#endif +#include #include #include From 058eebe4797a1ba17a6a9cc2d3a449dddcfce6de Mon Sep 17 00:00:00 2001 From: Adam Wojasinski Date: Thu, 5 Oct 2023 09:15:24 +0200 Subject: [PATCH 0434/3723] drivers: spi: spi_nrfx_spim: Add additional symbol check for frequency Some targets may not have `NRF_SPIM_HAS_32_MHZ_FREQ` or `NRF_SPIM_HAS_16_MHZ_FREQ` symbols but have `NRF_SPIM_HAS_PRESCALER` symbol defined. The symbol informs that target supports 32 MHz and 16 MHz frequencies for SPIM instances. Signed-off-by: Adam Wojasinski --- drivers/spi/spi_nrfx_spim.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/spi/spi_nrfx_spim.c b/drivers/spi/spi_nrfx_spim.c index 7c5a93237d2..59008252cb6 100644 --- a/drivers/spi/spi_nrfx_spim.c +++ b/drivers/spi/spi_nrfx_spim.c @@ -71,9 +71,9 @@ static inline uint32_t get_nrf_spim_frequency(uint32_t frequency) { /* Get the highest supported frequency not exceeding the requested one. */ - if (frequency >= MHZ(32) && NRF_SPIM_HAS_32_MHZ_FREQ) { + if (frequency >= MHZ(32) && (NRF_SPIM_HAS_32_MHZ_FREQ || NRF_SPIM_HAS_PRESCALER)) { return MHZ(32); - } else if (frequency >= MHZ(16) && NRF_SPIM_HAS_16_MHZ_FREQ) { + } else if (frequency >= MHZ(16) && (NRF_SPIM_HAS_16_MHZ_FREQ || NRF_SPIM_HAS_PRESCALER)) { return MHZ(16); } else if (frequency >= MHZ(8)) { return MHZ(8); From 2c0f121727456f01422833b5e7b3ef2a29976a45 Mon Sep 17 00:00:00 2001 From: Chaitanya Tata Date: Fri, 25 Aug 2023 18:27:52 +0530 Subject: [PATCH 0435/3723] drivers: spi: spi_nrfx_spim: Use generic macro for RAM address check Instead of assuming only RAM is accessible by EasyDMA, use the generic DMA accessible function. Signed-off-by: Chaitanya Tata --- drivers/spi/spi_nrfx_spim.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/drivers/spi/spi_nrfx_spim.c b/drivers/spi/spi_nrfx_spim.c index 59008252cb6..e3e327cfa61 100644 --- a/drivers/spi/spi_nrfx_spim.c +++ b/drivers/spi/spi_nrfx_spim.c @@ -313,7 +313,8 @@ static void transfer_next_chunk(const struct device *dev) nrfx_err_t result; const uint8_t *tx_buf = ctx->tx_buf; #if (CONFIG_SPI_NRFX_RAM_BUFFER_SIZE > 0) - if (spi_context_tx_buf_on(ctx) && !nrfx_is_in_ram(tx_buf)) { + if (spi_context_tx_buf_on(ctx) && + !nrf_dma_accessible_check(&dev_config->spim.p_reg, tx_buf)) { if (chunk_len > CONFIG_SPI_NRFX_RAM_BUFFER_SIZE) { chunk_len = CONFIG_SPI_NRFX_RAM_BUFFER_SIZE; } From 0a1eff8d97f88546d07d4f0715628ffe0f06aaf6 Mon Sep 17 00:00:00 2001 From: Chaitanya Tata Date: Fri, 25 Aug 2023 17:45:17 +0530 Subject: [PATCH 0436/3723] drivers: spim: Move the length check to beginning This check has to be done independent of whether RAM is used for buffers or not and depends on device maximum length property. Signed-off-by: Chaitanya Tata --- drivers/spi/spi_nrfx_spim.c | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/drivers/spi/spi_nrfx_spim.c b/drivers/spi/spi_nrfx_spim.c index e3e327cfa61..8122af39a6b 100644 --- a/drivers/spi/spi_nrfx_spim.c +++ b/drivers/spi/spi_nrfx_spim.c @@ -312,6 +312,11 @@ static void transfer_next_chunk(const struct device *dev) nrfx_spim_xfer_desc_t xfer; nrfx_err_t result; const uint8_t *tx_buf = ctx->tx_buf; + + if (chunk_len > dev_config->max_chunk_len) { + chunk_len = dev_config->max_chunk_len; + } + #if (CONFIG_SPI_NRFX_RAM_BUFFER_SIZE > 0) if (spi_context_tx_buf_on(ctx) && !nrf_dma_accessible_check(&dev_config->spim.p_reg, tx_buf)) { @@ -323,10 +328,6 @@ static void transfer_next_chunk(const struct device *dev) tx_buf = dev_data->buffer; } #endif - if (chunk_len > dev_config->max_chunk_len) { - chunk_len = dev_config->max_chunk_len; - } - dev_data->chunk_len = chunk_len; xfer.p_tx_buffer = tx_buf; From 2a38230a31c6ef6333444578bc7b5c7e6aad6c52 Mon Sep 17 00:00:00 2001 From: Marcin Szymczyk Date: Fri, 11 Mar 2022 12:26:24 +0100 Subject: [PATCH 0437/3723] drivers: spi: nrfx: add dependency to PPI for PAN 58 on nRF52832 While enabling workaround for PAN 58 the PPI driver is used. This requires the nrfx PPI driver to be enabled thus CONFIG_NRFX_PPI Kconfig symbol needs to be set. Jira: NRFX-1616 Signed-off-by: Marcin Szymczyk --- drivers/spi/Kconfig.nrfx | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/spi/Kconfig.nrfx b/drivers/spi/Kconfig.nrfx index c185efa9f8f..611bad822b2 100644 --- a/drivers/spi/Kconfig.nrfx +++ b/drivers/spi/Kconfig.nrfx @@ -54,6 +54,7 @@ config SPI_NRFX_SPIS config SOC_NRF52832_ALLOW_SPIM_DESPITE_PAN_58 depends on SOC_NRF52832 + select NRFX_PPI bool "Allow enabling the SPIM driver despite PAN 58" help Allow enabling the nRF SPI Master with EasyDMA, despite From 38739368dd449064325ab5ea773390d0becc09f7 Mon Sep 17 00:00:00 2001 From: Adam Wojasinski Date: Wed, 15 Nov 2023 14:01:59 +0100 Subject: [PATCH 0438/3723] modules: hal_nordic: watchdog: Add Kconfig symbols for new WDT instances This commit is a part of introduction of new WTD instances. It adds new Kconfig symbols that can be used in WDT shim and nrfx driver. Signed-off-by: Adam Wojasinski --- modules/hal_nordic/nrfx/Kconfig | 15 +++++++++++++++ modules/hal_nordic/nrfx/nrfx_config.h | 9 +++++++++ soc/arm/nordic_nrf/Kconfig.peripherals | 9 +++++++++ 3 files changed, 33 insertions(+) diff --git a/modules/hal_nordic/nrfx/Kconfig b/modules/hal_nordic/nrfx/Kconfig index 5dcda73c9be..c4bfcc2d60e 100644 --- a/modules/hal_nordic/nrfx/Kconfig +++ b/modules/hal_nordic/nrfx/Kconfig @@ -561,6 +561,21 @@ config NRFX_WDT1 depends on $(dt_nodelabel_has_compat,wdt1,$(DT_COMPAT_NORDIC_NRF_WDT)) select NRFX_WDT +config NRFX_WDT30 + bool "WDT30 driver instance" + depends on $(dt_nodelabel_has_compat,wdt30,$(DT_COMPAT_NORDIC_NRF_WDT)) + select NRFX_WDT + +config NRFX_WDT31 + bool "WDT31 driver instance" + depends on $(dt_nodelabel_has_compat,wdt31,$(DT_COMPAT_NORDIC_NRF_WDT)) + select NRFX_WDT + +config NRFX_WDT130 + bool "WDT130 driver instance" + depends on $(dt_nodelabel_has_compat,wdt130,$(DT_COMPAT_NORDIC_NRF_WDT)) + select NRFX_WDT + menu "Peripheral Resource Sharing module" config NRFX_PRS diff --git a/modules/hal_nordic/nrfx/nrfx_config.h b/modules/hal_nordic/nrfx/nrfx_config.h index b5b09b96078..a285d1c86db 100644 --- a/modules/hal_nordic/nrfx/nrfx_config.h +++ b/modules/hal_nordic/nrfx/nrfx_config.h @@ -580,6 +580,15 @@ #ifdef CONFIG_NRFX_WDT1 #define NRFX_WDT1_ENABLED 1 #endif +#ifdef CONFIG_NRFX_WDT30 +#define NRFX_WDT30_ENABLED 1 +#endif +#ifdef CONFIG_NRFX_WDT31 +#define NRFX_WDT31_ENABLED 1 +#endif +#ifdef CONFIG_NRFX_WDT130 +#define NRFX_WDT130_ENABLED 1 +#endif #ifdef CONFIG_NRF52_ANOMALY_109_WORKAROUND #define NRFX_SPIM_NRF52_ANOMALY_109_WORKAROUND_ENABLED 1 diff --git a/soc/arm/nordic_nrf/Kconfig.peripherals b/soc/arm/nordic_nrf/Kconfig.peripherals index 3aacc35a08a..55f44ccbc21 100644 --- a/soc/arm/nordic_nrf/Kconfig.peripherals +++ b/soc/arm/nordic_nrf/Kconfig.peripherals @@ -401,3 +401,12 @@ config HAS_HW_NRF_WDT0 config HAS_HW_NRF_WDT1 def_bool $(dt_nodelabel_enabled_with_compat,wdt1,$(DT_COMPAT_NORDIC_NRF_WDT)) + +config HAS_HW_NRF_WDT30 + def_bool $(dt_nodelabel_enabled_with_compat,wdt30,$(DT_COMPAT_NORDIC_NRF_WDT)) + +config HAS_HW_NRF_WDT31 + def_bool $(dt_nodelabel_enabled_with_compat,wdt31,$(DT_COMPAT_NORDIC_NRF_WDT)) + +config HAS_HW_NRF_WDT130 + def_bool $(dt_nodelabel_enabled_with_compat,wdt130,$(DT_COMPAT_NORDIC_NRF_WDT)) From e654cb65b8943cdf5c66c4ad285ca26481a7da69 Mon Sep 17 00:00:00 2001 From: Adam Wojasinski Date: Wed, 19 Jul 2023 15:36:00 +0200 Subject: [PATCH 0439/3723] drivers: watchdog: wdt_nrfx: Add support for new instances Add support for WDT30, WDT31, and WDT130 Signed-off-by: Adam Wojasinski --- drivers/watchdog/Kconfig.nrfx | 4 ++++ drivers/watchdog/wdt_nrfx.c | 12 ++++++++++++ 2 files changed, 16 insertions(+) diff --git a/drivers/watchdog/Kconfig.nrfx b/drivers/watchdog/Kconfig.nrfx index 52cf45dc068..2967fe86489 100644 --- a/drivers/watchdog/Kconfig.nrfx +++ b/drivers/watchdog/Kconfig.nrfx @@ -9,5 +9,9 @@ config WDT_NRFX depends on DT_HAS_NORDIC_NRF_WDT_ENABLED select NRFX_WDT0 if HAS_HW_NRF_WDT0 select NRFX_WDT1 if HAS_HW_NRF_WDT1 + select NRFX_WDT30 if HAS_HW_NRF_WDT30 + select NRFX_WDT31 if HAS_HW_NRF_WDT31 + select NRFX_WDT130 if HAS_HW_NRF_WDT130 + help Enable support for nrfx WDT driver for nRF MCU series. diff --git a/drivers/watchdog/wdt_nrfx.c b/drivers/watchdog/wdt_nrfx.c index 98fcb713b81..363a1174e91 100644 --- a/drivers/watchdog/wdt_nrfx.c +++ b/drivers/watchdog/wdt_nrfx.c @@ -202,3 +202,15 @@ WDT_NRFX_WDT_DEVICE(0); #ifdef CONFIG_HAS_HW_NRF_WDT1 WDT_NRFX_WDT_DEVICE(1); #endif + +#ifdef CONFIG_HAS_HW_NRF_WDT30 +WDT_NRFX_WDT_DEVICE(30); +#endif + +#ifdef CONFIG_HAS_HW_NRF_WDT31 +WDT_NRFX_WDT_DEVICE(31); +#endif + +#ifdef CONFIG_HAS_HW_NRF_WDT130 +WDT_NRFX_WDT_DEVICE(130); +#endif From 7d567438b2d6dbc2dd23450348a4eda2da463cc3 Mon Sep 17 00:00:00 2001 From: Jamie McCrae Date: Tue, 28 Nov 2023 09:31:58 +0000 Subject: [PATCH 0440/3723] west.yml: MCUboot synchronization from upstream Update Zephyr fork of MCUboot to revision: 05d11942774fc15b90af101232ec5305051216ec Brings following Zephyr relevant fixes: - 215345f7 zephyr: Add firmware loader MCUboot operation style - 433b8480 zephyr: Move IO functions out of main to separate file - 5e6cffbf boot: boot_serial: Fix single slot encrypted image list - 3f0b89d6 boot: zephyr: add support for mimxrt101x_evk Signed-off-by: Jamie McCrae --- west.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/west.yml b/west.yml index d0590f17a3b..5daa5e4768b 100644 --- a/west.yml +++ b/west.yml @@ -282,7 +282,7 @@ manifest: groups: - crypto - name: mcuboot - revision: 47b34362552835621bc289d53d2127691088cb7c + revision: 05d11942774fc15b90af101232ec5305051216ec path: bootloader/mcuboot - name: mipi-sys-t path: modules/debug/mipi-sys-t From 93f537552d68f063e6dfe3d09f3cdf6dad9a5de2 Mon Sep 17 00:00:00 2001 From: Jamie McCrae Date: Tue, 28 Nov 2023 11:11:16 +0000 Subject: [PATCH 0441/3723] soc: arm: nordic_nrf: Remove deprecated GPREGRET Kconfig option Removes the Kconfig NRF_STORE_REBOOT_TYPE_GPREGRET which was deprecated in zephyr 3.4 Signed-off-by: Jamie McCrae --- soc/arm/nordic_nrf/Kconfig | 13 ------------- soc/arm/nordic_nrf/nrf51/soc.c | 13 ------------- soc/arm/nordic_nrf/nrf52/soc.c | 13 ------------- 3 files changed, 39 deletions(-) diff --git a/soc/arm/nordic_nrf/Kconfig b/soc/arm/nordic_nrf/Kconfig index 19e49c05454..21f59f458f3 100644 --- a/soc/arm/nordic_nrf/Kconfig +++ b/soc/arm/nordic_nrf/Kconfig @@ -167,17 +167,4 @@ config NRF_TRACE_PORT Unit) for tracing using a hardware probe. If disabled, the trace pins will be used as GPIO. -config NRF_STORE_REBOOT_TYPE_GPREGRET - bool "Set GPREGRET to reboot type (DEPRECATED)" - depends on SOC_SERIES_NRF51X || SOC_SERIES_NRF52X - depends on REBOOT - depends on !RETENTION_BOOT_MODE - select DEPRECATED - help - If this option is enabled, then the parameter supplied to the - sys_reboot() function will be set in the GPREGRET register. - - This has been replaced with the bootmode part of the retention - subsystem, which should be used instead. - endif # SOC_FAMILY_NRF diff --git a/soc/arm/nordic_nrf/nrf51/soc.c b/soc/arm/nordic_nrf/nrf51/soc.c index 2b22c95679f..af14f6f3003 100644 --- a/soc/arm/nordic_nrf/nrf51/soc.c +++ b/soc/arm/nordic_nrf/nrf51/soc.c @@ -21,19 +21,6 @@ #define LOG_LEVEL CONFIG_SOC_LOG_LEVEL LOG_MODULE_REGISTER(soc); -#ifdef CONFIG_NRF_STORE_REBOOT_TYPE_GPREGRET -/* Overrides the weak ARM implementation: - * Set general purpose retention register and reboot - * This is deprecated and has been replaced with the boot mode retention - * subsystem - */ -void sys_arch_reboot(int type) -{ - nrf_power_gpregret_set(NRF_POWER, 0, (uint8_t)type); - NVIC_SystemReset(); -} -#endif - #define DELAY_CALL_OVERHEAD_US 2 void arch_busy_wait(uint32_t time_us) diff --git a/soc/arm/nordic_nrf/nrf52/soc.c b/soc/arm/nordic_nrf/nrf52/soc.c index 5f310e5f945..a6ef22468b1 100644 --- a/soc/arm/nordic_nrf/nrf52/soc.c +++ b/soc/arm/nordic_nrf/nrf52/soc.c @@ -23,19 +23,6 @@ #define LOG_LEVEL CONFIG_SOC_LOG_LEVEL LOG_MODULE_REGISTER(soc); -#ifdef CONFIG_NRF_STORE_REBOOT_TYPE_GPREGRET -/* Overrides the weak ARM implementation: - * Set general purpose retention register and reboot - * This is deprecated and has been replaced with the boot mode retention - * subsystem - */ -void sys_arch_reboot(int type) -{ - nrf_power_gpregret_set(NRF_POWER, 0, (uint8_t)type); - NVIC_SystemReset(); -} -#endif - static int nordicsemi_nrf52_init(void) { #ifdef CONFIG_NRF_ENABLE_ICACHE From b35cd5f7b8bfaf725a674e50a01a01b3353b4d2e Mon Sep 17 00:00:00 2001 From: Jamie McCrae Date: Tue, 28 Nov 2023 11:15:58 +0000 Subject: [PATCH 0442/3723] doc: migration-guide: 3.6: Add note on nrf Kconfig removal Adds a note on a now removed Nordic GPREGRET Kconfig which was deprecated in Zephyr 3.4 Signed-off-by: Jamie McCrae --- doc/releases/migration-guide-3.6.rst | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/doc/releases/migration-guide-3.6.rst b/doc/releases/migration-guide-3.6.rst index f0353d2ceaa..812beba9a70 100644 --- a/doc/releases/migration-guide-3.6.rst +++ b/doc/releases/migration-guide-3.6.rst @@ -14,6 +14,12 @@ the :ref:`release notes`. Required changes **************** +Boards +====== + + * The deprecated Nordic SoC Kconfig option ``NRF_STORE_REBOOT_TYPE_GPREGRET`` has been removed, + applications that use this should switch to using the :ref:`boot_mode_api` instead. + Kernel ====== From b3cba84dcdb3ce52ce71c4d4db915e8c603a2fa4 Mon Sep 17 00:00:00 2001 From: Joshua Lilly Date: Mon, 27 Nov 2023 18:42:10 -0800 Subject: [PATCH 0443/3723] testsuite: coverage: allow access to gcov internals This allows external applications wishing to report coverage data over different interfaces the ability to do so by exposing the gcov list. Signed-off-by: Joshua Lilly --- subsys/testsuite/CMakeLists.txt | 1 + subsys/testsuite/coverage/coverage.c | 9 +++++++-- subsys/testsuite/coverage/coverage.h | 8 ++++++++ 3 files changed, 16 insertions(+), 2 deletions(-) diff --git a/subsys/testsuite/CMakeLists.txt b/subsys/testsuite/CMakeLists.txt index a44a6c4914d..b2b691fc8c9 100644 --- a/subsys/testsuite/CMakeLists.txt +++ b/subsys/testsuite/CMakeLists.txt @@ -6,5 +6,6 @@ if(CONFIG_TEST) zephyr_include_directories(${ZEPHYR_BASE}/subsys/testsuite/include) endif() add_subdirectory_ifdef(CONFIG_COVERAGE_GCOV coverage) +zephyr_include_directories_ifdef(CONFIG_COVERAGE_GCOV ${zephyr_BASE}/subsys/testsuite/coverage) zephyr_library_sources_ifdef(CONFIG_TEST_BUSY_SIM busy_sim/busy_sim.c) diff --git a/subsys/testsuite/coverage/coverage.c b/subsys/testsuite/coverage/coverage.c index dc120c14605..ac13596116b 100644 --- a/subsys/testsuite/coverage/coverage.c +++ b/subsys/testsuite/coverage/coverage.c @@ -84,7 +84,7 @@ static inline void write_u32(void *buffer, size_t *off, uint32_t v) *off = *off + sizeof(uint32_t); } -size_t calculate_buff_size(struct gcov_info *info) +size_t gcov_calculate_buff_size(struct gcov_info *info) { uint32_t iter; uint32_t iter_1; @@ -266,7 +266,7 @@ void gcov_coverage_dump(void) while (gcov_list) { dump_on_console_start(gcov_list->filename); - size = calculate_buff_size(gcov_list); + size = gcov_calculate_buff_size(gcov_list); buffer = k_heap_alloc(&gcov_heap, size, K_NO_WAIT); if (CONFIG_COVERAGE_GCOV_HEAP_SIZE > 0 && !buffer) { @@ -294,6 +294,11 @@ void gcov_coverage_dump(void) return; } +struct gcov_info *gcov_get_list_head(void) +{ + /* Locking someway before getting this is recommended. */ + return gcov_info_head; +} /* Initialize the gcov by calling the required constructors */ void gcov_static_init(void) diff --git a/subsys/testsuite/coverage/coverage.h b/subsys/testsuite/coverage/coverage.h index 395d03075ca..ec1d25dae8a 100644 --- a/subsys/testsuite/coverage/coverage.h +++ b/subsys/testsuite/coverage/coverage.h @@ -117,4 +117,12 @@ struct gcov_info { }; +/* + * These functions are in the header for easy access for external interface + * reporting since they aren't useful without the structs in this header. + */ +struct gcov_info *gcov_get_list_head(void); +size_t gcov_populate_buffer(uint8_t *buffer, struct gcov_info *info); +size_t gcov_calculate_buff_size(struct gcov_info *info); + #endif /* _COVERAGE_H_ */ From 874e973446a72f2c7945744f6fe2f00173bd6733 Mon Sep 17 00:00:00 2001 From: Fabio Baltieri Date: Wed, 22 Nov 2023 23:15:23 +0000 Subject: [PATCH 0444/3723] bindings: gnss: renmae quectel,lc76g.yaml This was probably meant to have a comma, not a dash. Signed-off-by: Fabio Baltieri --- dts/bindings/gnss/{quectel-lc76g.yaml => quectel,lc76g.yaml} | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename dts/bindings/gnss/{quectel-lc76g.yaml => quectel,lc76g.yaml} (100%) diff --git a/dts/bindings/gnss/quectel-lc76g.yaml b/dts/bindings/gnss/quectel,lc76g.yaml similarity index 100% rename from dts/bindings/gnss/quectel-lc76g.yaml rename to dts/bindings/gnss/quectel,lc76g.yaml From 96b9bd472068a80c727febbc87c553b168f91299 Mon Sep 17 00:00:00 2001 From: Fabio Baltieri Date: Wed, 22 Nov 2023 23:20:52 +0000 Subject: [PATCH 0445/3723] drivers: gnss: use absolute values for signed fractionals Printing fractionals currently put the sign on integer values on the fractional part, for example: longitude : -6.-207483333 Run an extra abs to get rid of the sign there for latitude, longitude and altitude, compute the sign separately so it works for numbers between -1 and 0 as well. Signed-off-by: Fabio Baltieri --- drivers/gnss/gnss_dump.c | 31 +++++++++++++++++-------------- 1 file changed, 17 insertions(+), 14 deletions(-) diff --git a/drivers/gnss/gnss_dump.c b/drivers/gnss/gnss_dump.c index 1946d65ea2e..f87b64a4946 100644 --- a/drivers/gnss/gnss_dump.c +++ b/drivers/gnss/gnss_dump.c @@ -5,6 +5,7 @@ */ #include "gnss_dump.h" +#include #include #include @@ -94,20 +95,22 @@ int gnss_dump_info(char *str, uint16_t strsize, const struct gnss_info *info) int gnss_dump_nav_data(char *str, uint16_t strsize, const struct navigation_data *nav_data) { int ret; - int32_t altitude_int; - int32_t altitude_fraction; - const char *fmt = "navigation_data: {latitude: %lli.%lli, longitude : %lli.%lli, " - "bearing %u.%u, speed %u.%u, altitude: %i.%i}"; - - altitude_int = nav_data->altitude / 1000; - altitude_fraction = nav_data->altitude % 1000; - altitude_fraction = (altitude_fraction < 0) ? -altitude_fraction : altitude_fraction; - - ret = snprintk(str, strsize, fmt, nav_data->latitude / 1000000000, - nav_data->latitude % 1000000000, nav_data->longitude / 1000000000, - nav_data->longitude % 1000000000, nav_data->bearing / 1000, - nav_data->bearing % 1000, nav_data->speed / 1000, nav_data->speed % 1000, - altitude_int, altitude_fraction); + const char *fmt = "navigation_data: {latitude: %s%lli.%09lli, longitude : %s%lli.%09lli, " + "bearing %u.%03u, speed %u.%03u, altitude: %s%i.%03i}"; + char *lat_sign = nav_data->latitude < 0 ? "-" : ""; + char *lon_sign = nav_data->longitude < 0 ? "-" : ""; + char *alt_sign = nav_data->altitude < 0 ? "-" : ""; + + ret = snprintk(str, strsize, fmt, + lat_sign, + llabs(nav_data->latitude) / 1000000000, + llabs(nav_data->latitude) % 1000000000, + lon_sign, + llabs(nav_data->longitude) / 1000000000, + llabs(nav_data->longitude) % 1000000000, + nav_data->bearing / 1000, nav_data->bearing % 1000, + nav_data->speed / 1000, nav_data->speed % 1000, + alt_sign, abs(nav_data->altitude) / 1000, abs(nav_data->altitude) % 1000); return (strsize < ret) ? -ENOMEM : 0; } From f9ab0503069ab7456ed11df0c5af4c013482663f Mon Sep 17 00:00:00 2001 From: Fabio Baltieri Date: Sun, 26 Nov 2023 15:35:04 +0000 Subject: [PATCH 0446/3723] drivers: gnss: move gnss_publish.h in include/ Move gnss_publish.h in include/ so that out of tree drivers and tests can use it. Signed-off-by: Fabio Baltieri --- MAINTAINERS.yml | 1 + drivers/gnss/gnss_nmea0183_match.c | 2 +- drivers/gnss/gnss_nmea_generic.c | 2 +- drivers/gnss/gnss_publish.c | 2 +- drivers/gnss/gnss_quectel_lcx6g.c | 2 +- {drivers => include/zephyr/drivers}/gnss/gnss_publish.h | 0 6 files changed, 5 insertions(+), 4 deletions(-) rename {drivers => include/zephyr/drivers}/gnss/gnss_publish.h (100%) diff --git a/MAINTAINERS.yml b/MAINTAINERS.yml index 78f3cceb38d..e7ebf5d1c05 100644 --- a/MAINTAINERS.yml +++ b/MAINTAINERS.yml @@ -1103,6 +1103,7 @@ Release Notes: - doc/hardware/peripherals/gnss.rst - drivers/gnss/ - include/zephyr/drivers/gnss.h + - include/zephyr/drivers/gnss/ - tests/drivers/build_all/gnss/ - tests/drivers/gnss/ labels: diff --git a/drivers/gnss/gnss_nmea0183_match.c b/drivers/gnss/gnss_nmea0183_match.c index 3fe3b159fdb..2b971937c8d 100644 --- a/drivers/gnss/gnss_nmea0183_match.c +++ b/drivers/gnss/gnss_nmea0183_match.c @@ -4,6 +4,7 @@ * SPDX-License-Identifier: Apache-2.0 */ +#include #include #include @@ -11,7 +12,6 @@ #include "gnss_nmea0183.h" #include "gnss_nmea0183_match.h" -#include "gnss_publish.h" static bool gnss_nmea0183_match_timed_out(struct gnss_nmea0183_match_data *data) { diff --git a/drivers/gnss/gnss_nmea_generic.c b/drivers/gnss/gnss_nmea_generic.c index d24ee2b034d..0e7611ba495 100644 --- a/drivers/gnss/gnss_nmea_generic.c +++ b/drivers/gnss/gnss_nmea_generic.c @@ -7,13 +7,13 @@ */ #include +#include #include #include #include #include #include -#include "gnss_publish.h" #include "gnss_nmea0183.h" #include "gnss_nmea0183_match.h" #include "gnss_parse.h" diff --git a/drivers/gnss/gnss_publish.c b/drivers/gnss/gnss_publish.c index 98e3a2e5e19..7ddfa5e09fe 100644 --- a/drivers/gnss/gnss_publish.c +++ b/drivers/gnss/gnss_publish.c @@ -4,7 +4,7 @@ * SPDX-License-Identifier: Apache-2.0 */ -#include "gnss_publish.h" +#include #include #include diff --git a/drivers/gnss/gnss_quectel_lcx6g.c b/drivers/gnss/gnss_quectel_lcx6g.c index 0ca7f5203ac..9565d46cdfb 100644 --- a/drivers/gnss/gnss_quectel_lcx6g.c +++ b/drivers/gnss/gnss_quectel_lcx6g.c @@ -6,6 +6,7 @@ */ #include +#include #include #include #include @@ -14,7 +15,6 @@ #include #include -#include "gnss_publish.h" #include "gnss_nmea0183.h" #include "gnss_nmea0183_match.h" #include "gnss_parse.h" diff --git a/drivers/gnss/gnss_publish.h b/include/zephyr/drivers/gnss/gnss_publish.h similarity index 100% rename from drivers/gnss/gnss_publish.h rename to include/zephyr/drivers/gnss/gnss_publish.h From 35de07a528e4084e697f2e213722e29d6d367b6e Mon Sep 17 00:00:00 2001 From: Fabio Baltieri Date: Sun, 26 Nov 2023 15:51:31 +0000 Subject: [PATCH 0447/3723] tests: gnss: add some tests for gnss_dump Add a testsuite for gnss_dump, testing that various values are printed correctly. Signed-off-by: Fabio Baltieri --- tests/drivers/gnss/gnss_dump/CMakeLists.txt | 8 ++ tests/drivers/gnss/gnss_dump/prj.conf | 8 ++ tests/drivers/gnss/gnss_dump/src/main.c | 85 +++++++++++++++++++++ tests/drivers/gnss/gnss_dump/testcase.yaml | 38 +++++++++ 4 files changed, 139 insertions(+) create mode 100644 tests/drivers/gnss/gnss_dump/CMakeLists.txt create mode 100644 tests/drivers/gnss/gnss_dump/prj.conf create mode 100644 tests/drivers/gnss/gnss_dump/src/main.c create mode 100644 tests/drivers/gnss/gnss_dump/testcase.yaml diff --git a/tests/drivers/gnss/gnss_dump/CMakeLists.txt b/tests/drivers/gnss/gnss_dump/CMakeLists.txt new file mode 100644 index 00000000000..7ef54477c7d --- /dev/null +++ b/tests/drivers/gnss/gnss_dump/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(gnss_dump) + +target_sources(app PRIVATE src/main.c) diff --git a/tests/drivers/gnss/gnss_dump/prj.conf b/tests/drivers/gnss/gnss_dump/prj.conf new file mode 100644 index 00000000000..3bba00d223e --- /dev/null +++ b/tests/drivers/gnss/gnss_dump/prj.conf @@ -0,0 +1,8 @@ +# SPDX-License-Identifier: Apache-2.0 + +CONFIG_LOG=y +CONFIG_LOG_MODE_MINIMAL=y + +CONFIG_GNSS=y +CONFIG_GNSS_SATELLITES=y +CONFIG_GNSS_DUMP_TO_LOG=y diff --git a/tests/drivers/gnss/gnss_dump/src/main.c b/tests/drivers/gnss/gnss_dump/src/main.c new file mode 100644 index 00000000000..4a07d424046 --- /dev/null +++ b/tests/drivers/gnss/gnss_dump/src/main.c @@ -0,0 +1,85 @@ +/* + * Copyright 2023 Google LLC + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include +#include +#include + +DEVICE_DEFINE(gnss_dev, "gnss_dev", NULL, NULL, NULL, NULL, + POST_KERNEL, CONFIG_KERNEL_INIT_PRIORITY_DEFAULT, NULL); + +static const struct device *gnss_dev = &DEVICE_NAME_GET(gnss_dev); +static struct gnss_data test_data; +static struct gnss_satellite test_satellite; + +static void test_gnss_data(void) +{ + gnss_publish_data(gnss_dev, &test_data); + + /* positive values */ + test_data.nav_data.latitude = 10000000001; + test_data.nav_data.longitude = 20000000002; + test_data.nav_data.bearing = 3003; + test_data.nav_data.speed = 4004; + test_data.nav_data.altitude = 5005; + + test_data.info.satellites_cnt = 6; + test_data.info.hdop = 7; + test_data.info.fix_status = GNSS_FIX_STATUS_GNSS_FIX; + test_data.info.fix_quality = GNSS_FIX_QUALITY_GNSS_PPS; + + test_data.utc.hour = 1; + test_data.utc.minute = 2; + test_data.utc.millisecond = 3; + test_data.utc.month_day = 4; + test_data.utc.month = 5; + test_data.utc.century_year = 6; + + gnss_publish_data(gnss_dev, &test_data); + + /* small positive values */ + test_data.nav_data.latitude = 1; + test_data.nav_data.longitude = 2; + test_data.nav_data.bearing = 3; + test_data.nav_data.speed = 4; + test_data.nav_data.altitude = 5; + + gnss_publish_data(gnss_dev, &test_data); + + /* negative values */ + test_data.nav_data.latitude = -10000000001; + test_data.nav_data.longitude = -20000000002; + test_data.nav_data.altitude = -5005; + + gnss_publish_data(gnss_dev, &test_data); + + /* small negative values */ + test_data.nav_data.latitude = -1; + test_data.nav_data.longitude = -2; + test_data.nav_data.altitude = -5; + + gnss_publish_data(gnss_dev, &test_data); +} + +static void test_satellites_data(void) +{ + gnss_publish_satellites(gnss_dev, &test_satellite, 1); + + test_satellite.prn = 1; + test_satellite.snr = 2; + test_satellite.azimuth = 3; + test_satellite.system = GNSS_SYSTEM_GALILEO; + test_satellite.is_tracked = 1; + + gnss_publish_satellites(gnss_dev, &test_satellite, 1); +} +int main(void) +{ + test_gnss_data(); + test_satellites_data(); + + return 0; +} diff --git a/tests/drivers/gnss/gnss_dump/testcase.yaml b/tests/drivers/gnss/gnss_dump/testcase.yaml new file mode 100644 index 00000000000..74a652e2bfd --- /dev/null +++ b/tests/drivers/gnss/gnss_dump/testcase.yaml @@ -0,0 +1,38 @@ +# SPDX-License-Identifier: Apache-2.0 + +tests: + gnss.gnss_dump: + tags: gnss + platform_allow: + - native_posix + - native_posix_64 + - native_sim + - native_sim_64 + integration_platforms: + - native_sim + harness: console + harness_config: + type: multi_line + regex: + - "gnss_dev: gnss_info: {satellites_cnt: 0, hdop: 0.0, \ + fix_status: NO_FIX, fix_quality: INVALID}" + - "gnss_dev: navigation_data: {latitude: 0.000000000, longitude : 0.000000000, \ + bearing 0.000, speed 0.000, altitude: 0.000}" + - "gnss_dev: gnss_time: {hour: 0, minute: 0, millisecond 0, month_day 0, month: 0, \ + century_year: 0}" + - "gnss_dev: gnss_info: {satellites_cnt: 6, hdop: 0.7, \ + fix_status: GNSS_FIX, fix_quality: GNSS_PPS}" + - "gnss_dev: navigation_data: {latitude: 10.000000001, longitude : 20.000000002, \ + bearing 3.003, speed 4.004, altitude: 5.005}" + - "gnss_dev: gnss_time: {hour: 1, minute: 2, millisecond 3, month_day 4, month: 5, \ + century_year: 6}" + - "gnss_dev: navigation_data: {latitude: 0.000000001, longitude : 0.000000002, \ + bearing 0.003, speed 0.004, altitude: 0.005}" + - "gnss_dev: navigation_data: {latitude: -10.000000001, longitude : -20.000000002, \ + bearing 0.003, speed 0.004, altitude: -5.005}" + - "gnss_dev: navigation_data: {latitude: -0.000000001, longitude : -0.000000002, \ + bearing 0.003, speed 0.004, altitude: -0.005}" + - "gnss_dev: gnss_satellite: {prn: 0, snr: 0, elevation 0, azimuth 0, system: unknown, \ + is_tracked: 0}" + - "gnss_dev: gnss_satellite: {prn: 1, snr: 2, elevation 0, azimuth 3, system: GALILEO, \ + is_tracked: 1}" From 81773c99056e7b30821dc4a05fe7b9b89afd45dd Mon Sep 17 00:00:00 2001 From: Daniel Leung Date: Tue, 28 Nov 2023 10:29:03 -0800 Subject: [PATCH 0448/3723] MAINTAINERS: fix missing asterisk for STM32 driver matching There is a missing asterisk for one of the driver matching pattern for STM32. So fix that. Signed-off-by: Daniel Leung --- MAINTAINERS.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/MAINTAINERS.yml b/MAINTAINERS.yml index e7ebf5d1c05..5523a720ea5 100644 --- a/MAINTAINERS.yml +++ b/MAINTAINERS.yml @@ -2807,7 +2807,7 @@ STM32 Platforms: - drivers/*/*stm32*.c - drivers/*/*stm32*.h - drivers/*/*/*stm32* - - drivers/*/*stm32 + - drivers/*/*stm32* - dts/arm/st/ - dts/bindings/*/*stm32* - soc/arm/st_stm32/ From f74f309ec79fd5a5d54353a34f738c6704bd20ae Mon Sep 17 00:00:00 2001 From: Jeppe Odgaard Date: Wed, 22 Nov 2023 15:09:34 +0100 Subject: [PATCH 0449/3723] valgrind: Update `POSIX soc no cpu cleanup` suppression Add `possible` to match-leak-kinds to prevent false positives caused by POSIX soc no cpu cleanup. The leak can be reproduced by adding CONFIG_NETWORKING=y to tests/lib/cpp/libcxx/prj.conf and run twister: twister -p native_sim -s tests/lib/cpp/libcxx/cpp.libcxx.host --enable-valgrind Signed-off-by: Jeppe Odgaard --- scripts/valgrind.supp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/scripts/valgrind.supp b/scripts/valgrind.supp index b161e09fa01..330ec51fefd 100644 --- a/scripts/valgrind.supp +++ b/scripts/valgrind.supp @@ -18,7 +18,7 @@ { POSIX soc no cpu cleanup Memcheck:Leak - match-leak-kinds: reachable + match-leak-kinds: reachable,possible ... fun:posix_boot_cpu ... From 153f38a412f87aa652a1857ab83df2f4f9746326 Mon Sep 17 00:00:00 2001 From: Fabio Baltieri Date: Wed, 29 Nov 2023 10:32:41 +0000 Subject: [PATCH 0450/3723] device: add braces around dev/dev_rw initializer The init_entry struct got modified to add a union with a non const dev pointer in afc59112a9. Some old compiler (such as GCC 4) seems to require a pair of brackets to correctly initialize the field in the union. Add those brackets to the initializers in device.h and init.h to maintain compatibility. Signed-off-by: Fabio Baltieri --- include/zephyr/device.h | 5 ++++- include/zephyr/init.h | 5 +---- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/include/zephyr/device.h b/include/zephyr/device.h index 77c0537ffdf..c55958924ff 100644 --- a/include/zephyr/device.h +++ b/include/zephyr/device.h @@ -974,7 +974,10 @@ static inline bool z_impl_device_is_ready(const struct device *dev) Z_INIT_ENTRY_NAME(DEVICE_NAME_GET(dev_id)) = { \ .init_fn = {COND_CODE_1(Z_DEVICE_IS_MUTABLE(node_id), (.dev_rw), (.dev)) = \ (init_fn_)}, \ - .dev = &DEVICE_NAME_GET(dev_id), \ + { \ + COND_CODE_1(Z_DEVICE_IS_MUTABLE(node_id), (.dev_rw), (.dev)) = \ + &DEVICE_NAME_GET(dev_id), \ + }, \ } /** diff --git a/include/zephyr/init.h b/include/zephyr/init.h index 7882b207b8d..78ec454f27c 100644 --- a/include/zephyr/init.h +++ b/include/zephyr/init.h @@ -205,10 +205,7 @@ struct init_entry { #define SYS_INIT_NAMED(name, init_fn_, level, prio) \ static const Z_DECL_ALIGN(struct init_entry) \ Z_INIT_ENTRY_SECTION(level, prio, 0) __used __noasan \ - Z_INIT_ENTRY_NAME(name) = { \ - .init_fn = {.sys = (init_fn_)}, \ - .dev = NULL, \ - } + Z_INIT_ENTRY_NAME(name) = {.init_fn = {.sys = (init_fn_)}} /** @} */ From 53df6efeb649f959d4a5c4331e3a550d0891eb6a Mon Sep 17 00:00:00 2001 From: Adrian Bonislawski Date: Tue, 31 Oct 2023 14:02:11 +0100 Subject: [PATCH 0451/3723] watchdog: intel_adsp: fix num cpus This will allow to init watchdog on HW's supporting different number of cpus and watchdogs based on runtime arch_num_cpus Signed-off-by: Adrian Bonislawski --- drivers/watchdog/wdt_intel_adsp.c | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/drivers/watchdog/wdt_intel_adsp.c b/drivers/watchdog/wdt_intel_adsp.c index a44136d09b8..9a30ea4f45b 100644 --- a/drivers/watchdog/wdt_intel_adsp.c +++ b/drivers/watchdog/wdt_intel_adsp.c @@ -72,7 +72,7 @@ static int intel_adsp_wdt_setup(const struct device *dev, uint8_t options) return ret; } - for (i = 0; i < CONFIG_MP_MAX_NUM_CPUS; i++) { + for (i = 0; i < arch_num_cpus(); i++) { ret = dw_wdt_configure(dev_data->core_wdt[i], dev_data->period_cfg); if (ret) { return ret; @@ -120,7 +120,7 @@ static int intel_adsp_wdt_feed(const struct device *dev, int channel_id) { struct intel_adsp_wdt_dev_data *const dev_data = dev->data; - if (channel_id >= CONFIG_MP_MAX_NUM_CPUS) { + if (channel_id >= arch_num_cpus()) { return -EINVAL; } @@ -154,7 +154,7 @@ static int intel_adsp_wdt_init(const struct device *dev) unsigned int i; int ret; - for (i = 0; i < CONFIG_MP_MAX_NUM_CPUS; i++) { + for (i = 0; i < arch_num_cpus(); i++) { dev_data->core_wdt[i] = intel_adsp_wdt_pointer_get(dev_config->base, i); ret = dw_wdt_probe(dev_data->core_wdt[i], reset_pulse_length); if (ret) { @@ -183,7 +183,7 @@ int intel_adsp_watchdog_pause(const struct device *dev, const int channel_id) { const struct intel_adsp_wdt_dev_cfg *const dev_config = dev->config; - if (channel_id >= CONFIG_MP_MAX_NUM_CPUS) { + if (channel_id >= arch_num_cpus()) { return -EINVAL; } @@ -203,7 +203,7 @@ int intel_adsp_watchdog_resume(const struct device *dev, const int channel_id) { const struct intel_adsp_wdt_dev_cfg *const dev_config = dev->config; - if (channel_id >= CONFIG_MP_MAX_NUM_CPUS) { + if (channel_id >= arch_num_cpus()) { return -EINVAL; } From 9e4b57398f9f1af569a0edc762d6c3cc02eaf092 Mon Sep 17 00:00:00 2001 From: Daniel DeGrasse Date: Mon, 27 Nov 2023 14:20:18 -0600 Subject: [PATCH 0452/3723] dts: arm: nxp: rt1015: correct FlexRAM bank allocation Although the RT1015 only supports 128 KB of FlexRAM being used at once, the default fusemap overallocates 160KB of FlexRAM. The JLink flashloader algorithm appears to rely on the 64KB of DTCM in the default fusemap being configured. Reducing the DTCM allocation resulted in JLink failing to flash the SOC. To resolve this, utilize the default fusemap of {O, O, D, D, I} for the RT1015 FlexRAM setup. Add a note about the restrictions on using overallocated FlexRAM to the SOC DTSI. Fixes #65889 Signed-off-by: Daniel DeGrasse --- dts/arm/nxp/nxp_rt1015.dtsi | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/dts/arm/nxp/nxp_rt1015.dtsi b/dts/arm/nxp/nxp_rt1015.dtsi index 59c62eb4452..bf905168e10 100644 --- a/dts/arm/nxp/nxp_rt1015.dtsi +++ b/dts/arm/nxp/nxp_rt1015.dtsi @@ -8,11 +8,14 @@ #include &flexram { - flexram,num-ram-banks = <4>; - /* default fuse */ + flexram,num-ram-banks = <5>; + /* Note: RT1015 has five flexram banks, but only 4 of the 5 can + * be used at the same time, for a total of 128KB of RAM. + */ flexram,bank-spec = , , , + , ; }; @@ -25,7 +28,7 @@ }; &dtcm { - reg = <0x20000000 DT_SIZE_K(32)>; + reg = <0x20000000 DT_SIZE_K(64)>; }; &ocram { From 76791cd708279692d198e03c51c8b2ff559fa7e5 Mon Sep 17 00:00:00 2001 From: Fabio Baltieri Date: Tue, 21 Nov 2023 14:48:48 +0000 Subject: [PATCH 0453/3723] input: kbd_matrix: add a input_kbd_matrix_drive_column_hook option Add an option to call an application specific hook when setting the column to scan. This makes it possible to handle application specific quirks. Signed-off-by: Fabio Baltieri --- drivers/input/Kconfig.kbd_matrix | 7 +++++++ drivers/input/input_kbd_matrix.c | 18 +++++++++++++++--- include/zephyr/input/input_kbd_matrix.h | 15 +++++++++++++++ 3 files changed, 37 insertions(+), 3 deletions(-) diff --git a/drivers/input/Kconfig.kbd_matrix b/drivers/input/Kconfig.kbd_matrix index 002c7f3cb8a..4c121fe959b 100644 --- a/drivers/input/Kconfig.kbd_matrix +++ b/drivers/input/Kconfig.kbd_matrix @@ -20,4 +20,11 @@ config INPUT_KBD_MATRIX_16_BIT_ROW Use a 16 bit type for the internal structure, allow using a matrix with up to 16 rows if the driver supports it. +config INPUT_KBD_DRIVE_COLUMN_HOOK + bool + help + Call an application specific hook after the driver specific + drive_column implementation. The application must implement the + input_kbd_matrix_drive_column_hook function. + endif # INPUT_KBD_MATRIX diff --git a/drivers/input/input_kbd_matrix.c b/drivers/input/input_kbd_matrix.c index 07e3c4c0545..921117f4663 100644 --- a/drivers/input/input_kbd_matrix.c +++ b/drivers/input/input_kbd_matrix.c @@ -68,6 +68,18 @@ static bool input_kbd_matrix_ghosting(const struct device *dev) return false; } +static void input_kbd_matrix_drive_column(const struct device *dev, int col) +{ + const struct input_kbd_matrix_common_config *cfg = dev->config; + const struct input_kbd_matrix_api *api = cfg->api; + + api->drive_column(dev, col); + +#ifdef CONFIG_INPUT_KBD_DRIVE_COLUMN_HOOK + input_kbd_matrix_drive_column_hook(dev, col); +#endif +} + static bool input_kbd_matrix_scan(const struct device *dev) { const struct input_kbd_matrix_common_config *cfg = dev->config; @@ -76,7 +88,7 @@ static bool input_kbd_matrix_scan(const struct device *dev) kbd_row_t key_event = 0U; for (int col = 0; col < cfg->col_size; col++) { - api->drive_column(dev, col); + input_kbd_matrix_drive_column(dev, col); /* Allow the matrix to stabilize before reading it */ k_busy_wait(cfg->settle_time_us); @@ -86,7 +98,7 @@ static bool input_kbd_matrix_scan(const struct device *dev) key_event |= row; } - api->drive_column(dev, INPUT_KBD_MATRIX_COLUMN_DRIVE_NONE); + input_kbd_matrix_drive_column(dev, INPUT_KBD_MATRIX_COLUMN_DRIVE_NONE); return key_event != 0U; } @@ -260,7 +272,7 @@ static void input_kbd_matrix_polling_thread(void *arg1, void *unused2, void *unu ARG_UNUSED(unused3); while (true) { - api->drive_column(dev, INPUT_KBD_MATRIX_COLUMN_DRIVE_ALL); + input_kbd_matrix_drive_column(dev, INPUT_KBD_MATRIX_COLUMN_DRIVE_ALL); api->set_detect_mode(dev, true); k_sem_take(&data->poll_lock, K_FOREVER); diff --git a/include/zephyr/input/input_kbd_matrix.h b/include/zephyr/input/input_kbd_matrix.h index a8e85b08855..7df8ad96e45 100644 --- a/include/zephyr/input/input_kbd_matrix.h +++ b/include/zephyr/input/input_kbd_matrix.h @@ -238,6 +238,21 @@ struct input_kbd_matrix_common_data { */ void input_kbd_matrix_poll_start(const struct device *dev); +#ifdef CONFIG_INPUT_KBD_DRIVE_COLUMN_HOOK +/** + * @brief Drive column hook + * + * This can be implemented by the application to handle column selection + * quirks. Called after the driver specific drive_column function. + * + * @param dev Keyboard matrix device instance. + * @param col The column to drive, or + * @ref INPUT_KBD_MATRIX_COLUMN_DRIVE_NONE or + * @ref INPUT_KBD_MATRIX_COLUMN_DRIVE_ALL. + */ +void input_kbd_matrix_drive_column_hook(const struct device *dev, int col); +#endif + /** * @brief Common function to initialize a keyboard matrix device at init time. * From 2fa6a440ae5fab9db94f57ec7770e7e1da079ea7 Mon Sep 17 00:00:00 2001 From: Rodrigo Peixoto Date: Wed, 29 Nov 2023 12:36:37 -0300 Subject: [PATCH 0454/3723] tests: zbus: replacing K_NO_WAIT with K_FOREVER in integration tests The zbus_chan_read with K_NO_WAIT was generating a fail in the qemu_riscv32_smp board. This fix replaces the K_NO_WAIT with a K_FOREVER on the test, which would not affect the test execution for other platforms/boards. Signed-off-by: Rodrigo Peixoto --- tests/subsys/zbus/integration/src/main.c | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/tests/subsys/zbus/integration/src/main.c b/tests/subsys/zbus/integration/src/main.c index 9539a0c7206..9241f6b7763 100644 --- a/tests/subsys/zbus/integration/src/main.c +++ b/tests/subsys/zbus/integration/src/main.c @@ -40,7 +40,7 @@ static void core_thread(void) struct sensor_data_msg data; - zbus_chan_read(&sensor_data_chan, &data, K_NO_WAIT); + zbus_chan_read(&sensor_data_chan, &data, K_FOREVER); struct net_pkt_msg pkt = {.total = data.a + data.b}; @@ -66,8 +66,7 @@ static void net_thread(void) while (1) { if (!zbus_sub_wait(&net_sub, &chan, K_FOREVER)) { count_net++; - - zbus_chan_read(&net_pkt_chan, &pkt, K_NO_WAIT); + zbus_chan_read(&net_pkt_chan, &pkt, K_FOREVER); LOG_DBG("[Net] Total %d", pkt.total); From 3c39f7efd972430cc5b5f7fc1c5eee403f19d68c Mon Sep 17 00:00:00 2001 From: Konrad Derda Date: Wed, 18 Oct 2023 17:46:35 +0200 Subject: [PATCH 0455/3723] net: hostname: trigger an event when the hostname changes This commit introduces new network event that is triggered on every change of the hostname. Signed-off-by: Konrad Derda --- include/zephyr/net/hostname.h | 6 ++++++ include/zephyr/net/net_event.h | 17 +++++++++++++++-- subsys/net/hostname.c | 18 +++++++++++++++++- subsys/net/ip/net_private.h | 3 +++ 4 files changed, 41 insertions(+), 3 deletions(-) diff --git a/include/zephyr/net/hostname.h b/include/zephyr/net/hostname.h index e34c1df31ac..292c4d62d72 100644 --- a/include/zephyr/net/hostname.h +++ b/include/zephyr/net/hostname.h @@ -27,6 +27,12 @@ extern "C" { (IS_ENABLED(CONFIG_NET_HOSTNAME_UNIQUE) ? \ sizeof("0011223344556677") - 1 : 0)) +#if defined(CONFIG_NET_HOSTNAME_ENABLE) +#define NET_HOSTNAME_SIZE NET_HOSTNAME_MAX_LEN + 1 +#else +#define NET_HOSTNAME_SIZE 1 +#endif + /** * @brief Get the device hostname * diff --git a/include/zephyr/net/net_event.h b/include/zephyr/net/net_event.h index 34856aec6af..b717c2eec45 100644 --- a/include/zephyr/net/net_event.h +++ b/include/zephyr/net/net_event.h @@ -13,6 +13,7 @@ #define ZEPHYR_INCLUDE_NET_NET_EVENT_H_ #include +#include #ifdef __cplusplus extern "C" { @@ -38,7 +39,6 @@ enum net_event_if_cmd { NET_EVENT_IF_CMD_UP, NET_EVENT_IF_CMD_ADMIN_DOWN, NET_EVENT_IF_CMD_ADMIN_UP, - }; #define NET_EVENT_IF_DOWN \ @@ -53,7 +53,6 @@ enum net_event_if_cmd { #define NET_EVENT_IF_ADMIN_UP \ (_NET_EVENT_IF_BASE | NET_EVENT_IF_CMD_ADMIN_UP) - /* IPv6 Events */ #define _NET_IPV6_LAYER NET_MGMT_LAYER_L3 #define _NET_IPV6_CORE_CODE 0x060 @@ -210,6 +209,7 @@ enum net_event_l4_cmd { NET_EVENT_L4_CMD_DISCONNECTED, NET_EVENT_L4_CMD_DNS_SERVER_ADD, NET_EVENT_L4_CMD_DNS_SERVER_DEL, + NET_EVENT_L4_CMD_HOSTNAME_CHANGED, }; #define NET_EVENT_L4_CONNECTED \ @@ -224,6 +224,9 @@ enum net_event_l4_cmd { #define NET_EVENT_DNS_SERVER_DEL \ (_NET_EVENT_L4_BASE | NET_EVENT_L4_CMD_DNS_SERVER_DEL) +#define NET_EVENT_HOSTNAME_CHANGED \ + (_NET_EVENT_L4_BASE | NET_EVENT_L4_CMD_HOSTNAME_CHANGED) + /** @endcond */ /** @@ -282,6 +285,16 @@ struct net_event_ipv6_prefix { uint32_t lifetime; }; +/** + * @brief Network Management event information structure + * Used to pass information on NET_EVENT_HOSTNAME_CHANGED event when + * CONFIG_NET_MGMT_EVENT_INFO is enabled and event generator pass the + * information. + */ +struct net_event_l4_hostname { + char hostname[NET_HOSTNAME_SIZE]; +}; + #ifdef __cplusplus } #endif diff --git a/subsys/net/hostname.c b/subsys/net/hostname.c index 84146a74bf6..073756eb077 100644 --- a/subsys/net/hostname.c +++ b/subsys/net/hostname.c @@ -15,8 +15,22 @@ LOG_MODULE_REGISTER(net_hostname, CONFIG_NET_HOSTNAME_LOG_LEVEL); #include #include +#include -static char hostname[NET_HOSTNAME_MAX_LEN + 1]; +static char hostname[NET_HOSTNAME_SIZE]; + +static void trigger_net_event(void) +{ + if (IS_ENABLED(CONFIG_NET_MGMT_EVENT_INFO)) { + struct net_event_l4_hostname info; + + memcpy(info.hostname, hostname, sizeof(hostname)); + net_mgmt_event_notify_with_info(NET_EVENT_HOSTNAME_CHANGED, NULL, + &info, sizeof(info)); + } else { + net_mgmt_event_notify(NET_EVENT_HOSTNAME_CHANGED, NULL); + } +} const char *net_hostname_get(void) { @@ -57,6 +71,7 @@ int net_hostname_set_postfix(const uint8_t *hostname_postfix, #if !defined(CONFIG_NET_HOSTNAME_UNIQUE_UPDATE) postfix_set = true; #endif + trigger_net_event(); return 0; } @@ -67,4 +82,5 @@ void net_hostname_init(void) memcpy(hostname, CONFIG_NET_HOSTNAME, sizeof(CONFIG_NET_HOSTNAME) - 1); NET_DBG("Hostname set to %s", CONFIG_NET_HOSTNAME); + trigger_net_event(); } diff --git a/subsys/net/ip/net_private.h b/subsys/net/ip/net_private.h index 780b9fbea04..f39049c2c60 100644 --- a/subsys/net/ip/net_private.h +++ b/subsys/net/ip/net_private.h @@ -43,6 +43,9 @@ union net_mgmt_events { struct net_event_ipv6_route ipv6_route; #endif /* CONFIG_NET_IPV6_MLD */ #endif /* CONFIG_NET_IPV6 */ +#if defined(CONFIG_NET_HOSTNAME_ENABLE) + struct net_event_l4_hostname hostname; +#endif /* CONFIG_NET_HOSTNAME_ENABLE */ char default_event[DEFAULT_NET_EVENT_INFO_SIZE]; }; From f9c4ae6cf6da110c0d7478c724f459034d54a683 Mon Sep 17 00:00:00 2001 From: Konrad Derda Date: Wed, 18 Oct 2023 17:52:11 +0200 Subject: [PATCH 0456/3723] tests: net: hostname: test hostname related events Add test case to ensure that NET_EVENT_IF_HOSTNAME_CHANGED event is triggered properly when the hostname changes. Signed-off-by: Konrad Derda --- tests/net/hostname/src/main.c | 61 +++++++++++++++++++++++++++++++- tests/net/hostname/testcase.yaml | 10 ++++++ 2 files changed, 70 insertions(+), 1 deletion(-) diff --git a/tests/net/hostname/src/main.c b/tests/net/hostname/src/main.c index d2a56ca2782..58a7db6b9ae 100644 --- a/tests/net/hostname/src/main.c +++ b/tests/net/hostname/src/main.c @@ -54,8 +54,17 @@ static struct net_if *iface1; static bool test_started; static struct k_sem wait_data; +#ifdef CONFIG_NET_MGMT_EVENT +static struct k_sem wait_hostname; +static struct net_mgmt_event_callback hostname_cb; +#endif + #define WAIT_TIME 250 +#define EVENT_HANDLER_INIT_PRIO 55 + +BUILD_ASSERT(EVENT_HANDLER_INIT_PRIO < CONFIG_NET_INIT_PRIO); + struct net_if_test { uint8_t idx; uint8_t mac_addr[sizeof(struct net_eth_addr)]; @@ -90,6 +99,24 @@ static void net_iface_init(struct net_if *iface) NET_LINK_ETHERNET); } +#ifdef CONFIG_NET_MGMT_EVENT +static void hostname_changed(struct net_mgmt_event_callback *cb, + uint32_t mgmt_event, struct net_if *iface) +{ + if (mgmt_event == NET_EVENT_HOSTNAME_CHANGED) { +#ifdef CONFIG_NET_MGMT_EVENT_INFO + const struct net_event_l4_hostname *info = cb->info; + + if (strncmp(net_hostname_get(), info->hostname, sizeof(info->hostname))) { + /** Invalid value - do not give the semaphore **/ + return; + } +#endif + k_sem_give(&wait_hostname); + } +} +#endif + static int sender_iface(const struct device *dev, struct net_pkt *pkt) { if (!pkt->buffer) { @@ -310,6 +337,19 @@ static int bytes_from_hostname_unique(uint8_t *buf, int buf_len, const char *src return 0; } +#ifdef CONFIG_NET_MGMT_EVENT +static int init_event_handler(void) +{ + k_sem_init(&wait_hostname, 0, K_SEM_MAX_LIMIT); + + net_mgmt_init_event_callback(&hostname_cb, hostname_changed, + NET_EVENT_HOSTNAME_CHANGED); + net_mgmt_add_event_callback(&hostname_cb); + + return 0; +} +#endif + ZTEST(net_hostname, test_hostname_get) { const char *hostname; @@ -327,7 +367,6 @@ ZTEST(net_hostname, test_hostname_get) ret = bytes_from_hostname_unique(mac, sizeof(mac), hostname + sizeof(CONFIG_NET_HOSTNAME) - 1); zassert_equal(ret, 0, ""); - zassert_mem_equal(mac, net_if_get_link_addr(iface1)->addr, net_if_get_link_addr(iface1)->len, ""); } @@ -344,4 +383,24 @@ ZTEST(net_hostname, test_hostname_set) } } +#ifdef CONFIG_NET_MGMT_EVENT +ZTEST(net_hostname, test_hostname_event) +{ + if (IS_ENABLED(CONFIG_NET_MGMT_EVENT)) { + int ret; + + ret = k_sem_take(&wait_hostname, K_NO_WAIT); + zassert_equal(ret, 0, ""); + + if (IS_ENABLED(CONFIG_NET_HOSTNAME_UNIQUE)) { + ret = k_sem_take(&wait_hostname, K_NO_WAIT); + zassert_equal(ret, 0, ""); + } + } +} + +/** Make sure that hostname related events are caught from the beginning **/ +SYS_INIT(init_event_handler, POST_KERNEL, EVENT_HANDLER_INIT_PRIO); +#endif + ZTEST_SUITE(net_hostname, NULL, test_iface_setup, NULL, NULL, NULL); diff --git a/tests/net/hostname/testcase.yaml b/tests/net/hostname/testcase.yaml index b54edde847d..67c02bc418a 100644 --- a/tests/net/hostname/testcase.yaml +++ b/tests/net/hostname/testcase.yaml @@ -11,3 +11,13 @@ tests: net.hostname.unique: extra_configs: - CONFIG_NET_HOSTNAME_UNIQUE=y + net.hostname.event: + extra_configs: + - CONFIG_NET_MGMT=y + - CONFIG_NET_MGMT_EVENT_INFO=y + net.hostname.event.unique: + extra_configs: + - CONFIG_NET_HOSTNAME_UNIQUE=y + - CONFIG_NET_MGMT=y + - CONFIG_NET_MGMT_EVENT=y + - CONFIG_NET_MGMT_EVENT_INFO=n From 56bb73d7c76ccc7ec67932fbafccaae06c20b96c Mon Sep 17 00:00:00 2001 From: Jakub Michalski Date: Tue, 29 Aug 2023 14:11:04 +0200 Subject: [PATCH 0457/3723] console: fix '\r' and '\n' handling in uart_console_isr() Receiving uart messages like: "\r*\n*\n" ('*' is a wildcard here) resulted in invalid echo and invalid console_getline() output. For example after receiving "\rabc\nd\n" uart_console_isr() echoes "\r\nabcd\r\n" (note that "\r\n" before 'd' is missing) and after calling console_getline() twice we received "" and "abcd". uart_console_isr() changes single occurences of '\n' and '\r' to "\r\n" and to avoid outputting "\r\n\r\n" after receiving "\r\n" it keeps track of the last character. But it was tracking only the control characters not all characters so in case of inputs like "\r*\n" the '\n' was omitted because the last tracked character was '\r'. Its fixed by tracking last character no matter of its type Signed-off-by: Jakub Michalski Signed-off-by: Mateusz Sierszulski --- drivers/console/uart_console.c | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) diff --git a/drivers/console/uart_console.c b/drivers/console/uart_console.c index 21df7fd3455..5214bbada3e 100644 --- a/drivers/console/uart_console.c +++ b/drivers/console/uart_console.c @@ -545,14 +545,12 @@ static void uart_console_isr(const struct device *unused, void *user_data) break; } - last_char = byte; - continue; - } - /* Ignore characters if there's no more buffer space */ - if (cur + end < sizeof(cmd->line) - 1) { + } else if (cur + end < sizeof(cmd->line) - 1) { insert_char(&cmd->line[cur++], byte, end); } + + last_char = byte; } } From 685b45be941041d03147b6959aed78ca90d9fea0 Mon Sep 17 00:00:00 2001 From: Jakub Michalski Date: Wed, 30 Aug 2023 11:46:42 +0200 Subject: [PATCH 0458/3723] tests: console: add line splitting tests Add tests for line splitting in console echo and console_getline() Signed-off-by: Jakub Michalski Signed-off-by: Mateusz Sierszulski --- .../console/{ => hello_world}/CMakeLists.txt | 0 .../console/{ => hello_world}/prj.conf | 0 .../{ => hello_world}/prj_semihost.conf | 0 .../console/{ => hello_world}/src/main.c | 0 .../console/{ => hello_world}/testcase.yaml | 0 .../console/line_splitting/CMakeLists.txt | 9 ++++++++ .../line_splitting/line_splitting.robot | 14 +++++++++++++ tests/drivers/console/line_splitting/prj.conf | 4 ++++ .../drivers/console/line_splitting/src/main.c | 21 +++++++++++++++++++ .../console/line_splitting/testcase.yaml | 11 ++++++++++ 10 files changed, 59 insertions(+) rename tests/drivers/console/{ => hello_world}/CMakeLists.txt (100%) rename tests/drivers/console/{ => hello_world}/prj.conf (100%) rename tests/drivers/console/{ => hello_world}/prj_semihost.conf (100%) rename tests/drivers/console/{ => hello_world}/src/main.c (100%) rename tests/drivers/console/{ => hello_world}/testcase.yaml (100%) create mode 100644 tests/drivers/console/line_splitting/CMakeLists.txt create mode 100644 tests/drivers/console/line_splitting/line_splitting.robot create mode 100644 tests/drivers/console/line_splitting/prj.conf create mode 100644 tests/drivers/console/line_splitting/src/main.c create mode 100644 tests/drivers/console/line_splitting/testcase.yaml diff --git a/tests/drivers/console/CMakeLists.txt b/tests/drivers/console/hello_world/CMakeLists.txt similarity index 100% rename from tests/drivers/console/CMakeLists.txt rename to tests/drivers/console/hello_world/CMakeLists.txt diff --git a/tests/drivers/console/prj.conf b/tests/drivers/console/hello_world/prj.conf similarity index 100% rename from tests/drivers/console/prj.conf rename to tests/drivers/console/hello_world/prj.conf diff --git a/tests/drivers/console/prj_semihost.conf b/tests/drivers/console/hello_world/prj_semihost.conf similarity index 100% rename from tests/drivers/console/prj_semihost.conf rename to tests/drivers/console/hello_world/prj_semihost.conf diff --git a/tests/drivers/console/src/main.c b/tests/drivers/console/hello_world/src/main.c similarity index 100% rename from tests/drivers/console/src/main.c rename to tests/drivers/console/hello_world/src/main.c diff --git a/tests/drivers/console/testcase.yaml b/tests/drivers/console/hello_world/testcase.yaml similarity index 100% rename from tests/drivers/console/testcase.yaml rename to tests/drivers/console/hello_world/testcase.yaml diff --git a/tests/drivers/console/line_splitting/CMakeLists.txt b/tests/drivers/console/line_splitting/CMakeLists.txt new file mode 100644 index 00000000000..f33d2c4cbb3 --- /dev/null +++ b/tests/drivers/console/line_splitting/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(console) + +FILE(GLOB app_sources src/*.c) +target_sources(app PRIVATE ${app_sources}) diff --git a/tests/drivers/console/line_splitting/line_splitting.robot b/tests/drivers/console/line_splitting/line_splitting.robot new file mode 100644 index 00000000000..6947d6d0bf4 --- /dev/null +++ b/tests/drivers/console/line_splitting/line_splitting.robot @@ -0,0 +1,14 @@ +# SPDX-License-Identifier: Apache-2.0 + +*** Settings *** +Resource ${KEYWORDS} + +*** Test Cases *** +Should Split Lines + Prepare Machine + Start Emulation + Wait For Next Line On Uart + Write Line To Uart \rabc\nd\n waitForEcho=false + Wait For Line On Uart getline: abc; + Write Line To Uart \rabc\nd\n waitForEcho=false + Wait For Line On Uart ^abc$ treatAsRegex=true diff --git a/tests/drivers/console/line_splitting/prj.conf b/tests/drivers/console/line_splitting/prj.conf new file mode 100644 index 00000000000..6733ba3be92 --- /dev/null +++ b/tests/drivers/console/line_splitting/prj.conf @@ -0,0 +1,4 @@ +CONFIG_TEST=y +CONFIG_CONSOLE=y +CONFIG_CONSOLE_SUBSYS=y +CONFIG_CONSOLE_GETLINE=y diff --git a/tests/drivers/console/line_splitting/src/main.c b/tests/drivers/console/line_splitting/src/main.c new file mode 100644 index 00000000000..590008584f7 --- /dev/null +++ b/tests/drivers/console/line_splitting/src/main.c @@ -0,0 +1,21 @@ +/* + * Copyright (c) 2023 Antmicro + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include +#include +#include + +int main(void) +{ + console_getline_init(); + + while (1) { + char *s = console_getline(); + + printk("getline: %s;\n", s); + } + return 0; +} diff --git a/tests/drivers/console/line_splitting/testcase.yaml b/tests/drivers/console/line_splitting/testcase.yaml new file mode 100644 index 00000000000..a7c0f1b8e67 --- /dev/null +++ b/tests/drivers/console/line_splitting/testcase.yaml @@ -0,0 +1,11 @@ +common: + tags: + - drivers + - console + platform_allow: hifive1 hifive_unleashed + harness: robot + +tests: + drivers.console.line_splitting: + harness_config: + robot_test_path: line_splitting.robot From df2ff3a850509693821c54fa4b8569f27beb394e Mon Sep 17 00:00:00 2001 From: Declan Snyder Date: Wed, 29 Nov 2023 11:25:36 -0600 Subject: [PATCH 0459/3723] boards: rt10xx: Rename ENET overlay & document Rename the experimental driver overlay to be the same for all the platforms, and document about it in the boards' index.rst. Signed-off-by: Declan Snyder --- boards/arm/mimxrt1024_evk/doc/index.rst | 10 ++++++++++ ...experimental.dtsi => nxp,enet-experimental.overlay} | 0 boards/arm/mimxrt1050_evk/doc/index.rst | 10 ++++++++++ ...experimental.dtsi => nxp,enet-experimental.overlay} | 0 boards/arm/mimxrt1060_evk/doc/index.rst | 10 ++++++++++ ...experimental.dtsi => nxp,enet-experimental.overlay} | 0 ...experimental.dtsi => nxp,enet-experimental.overlay} | 0 7 files changed, 30 insertions(+) rename boards/arm/mimxrt1024_evk/dts/{mimxrt1024_evk-enet-experimental.dtsi => nxp,enet-experimental.overlay} (100%) rename boards/arm/mimxrt1050_evk/dts/{mimxrt1050_evk-enet-experimental.dtsi => nxp,enet-experimental.overlay} (100%) rename boards/arm/mimxrt1060_evk/dts/{mimxrt1060_evk-enet-experimental.dtsi => nxp,enet-experimental.overlay} (100%) rename boards/arm/mimxrt1064_evk/dts/{mimxrt1064_evk-enet-experimental.dtsi => nxp,enet-experimental.overlay} (100%) diff --git a/boards/arm/mimxrt1024_evk/doc/index.rst b/boards/arm/mimxrt1024_evk/doc/index.rst index 303dad37538..c04a3f5d090 100644 --- a/boards/arm/mimxrt1024_evk/doc/index.rst +++ b/boards/arm/mimxrt1024_evk/doc/index.rst @@ -299,3 +299,13 @@ should see the following message in the terminal: .. _i.MX RT1024 Reference Manual: https://www.nxp.com/webapp/Download?colCode=IMXRT1024RM + +Experimental ENET Driver +======================== + +Current default ethernet driver is eth_mcux, with binding `nxp,kinetis-ethernet`. There is a new +driver with binding `nxp,enet`, which is experimental and undergoing development, but will have +enhanced capability, such as not hardcoding code for only one phy in the driver like eth_mcux. + +To build for this EVK with the new driver, include the experimental overlay to west build with +the option `-DEXTRA_DTC_OVERLAY_FILE=nxp,enet-experimental.overlay`. diff --git a/boards/arm/mimxrt1024_evk/dts/mimxrt1024_evk-enet-experimental.dtsi b/boards/arm/mimxrt1024_evk/dts/nxp,enet-experimental.overlay similarity index 100% rename from boards/arm/mimxrt1024_evk/dts/mimxrt1024_evk-enet-experimental.dtsi rename to boards/arm/mimxrt1024_evk/dts/nxp,enet-experimental.overlay diff --git a/boards/arm/mimxrt1050_evk/doc/index.rst b/boards/arm/mimxrt1050_evk/doc/index.rst index 5d48e823f79..15ce2678736 100644 --- a/boards/arm/mimxrt1050_evk/doc/index.rst +++ b/boards/arm/mimxrt1050_evk/doc/index.rst @@ -472,3 +472,13 @@ Current Zephyr build supports the new MIMXRT1050-EVKB .. _Enable QSPI flash support in SEGGER JLink: https://wiki.segger.com/i.MXRT1050#QSPI_flash + +Experimental ENET Driver +======================== + +Current default ethernet driver is eth_mcux, with binding `nxp,kinetis-ethernet`. There is a new +driver with binding `nxp,enet`, which is experimental and undergoing development, but will have +enhanced capability, such as not hardcoding code for only one phy in the driver like eth_mcux. + +To build for this EVK with the new driver, include the experimental overlay to west build with +the option `-DEXTRA_DTC_OVERLAY_FILE=nxp,enet-experimental.overlay`. diff --git a/boards/arm/mimxrt1050_evk/dts/mimxrt1050_evk-enet-experimental.dtsi b/boards/arm/mimxrt1050_evk/dts/nxp,enet-experimental.overlay similarity index 100% rename from boards/arm/mimxrt1050_evk/dts/mimxrt1050_evk-enet-experimental.dtsi rename to boards/arm/mimxrt1050_evk/dts/nxp,enet-experimental.overlay diff --git a/boards/arm/mimxrt1060_evk/doc/index.rst b/boards/arm/mimxrt1060_evk/doc/index.rst index 45d10009570..cfd546e5b37 100644 --- a/boards/arm/mimxrt1060_evk/doc/index.rst +++ b/boards/arm/mimxrt1060_evk/doc/index.rst @@ -472,3 +472,13 @@ connected to the EVK properly. See :ref:`Using J-Link RT1060` for more details. .. _Using J-Link with MIMXRT1060-EVKB: https://community.nxp.com/t5/i-MX-RT-Knowledge-Base/Using-J-Link-with-MIMXRT1060-EVKB/ta-p/1452717 + +Experimental ENET Driver +======================== + +Current default ethernet driver is eth_mcux, with binding `nxp,kinetis-ethernet`. There is a new +driver with binding `nxp,enet`, which is experimental and undergoing development, but will have +enhanced capability, such as not hardcoding code for only one phy in the driver like eth_mcux. + +To build for this EVK with the new driver, include the experimental overlay to west build with +the option `-DEXTRA_DTC_OVERLAY_FILE=nxp,enet-experimental.overlay`. diff --git a/boards/arm/mimxrt1060_evk/dts/mimxrt1060_evk-enet-experimental.dtsi b/boards/arm/mimxrt1060_evk/dts/nxp,enet-experimental.overlay similarity index 100% rename from boards/arm/mimxrt1060_evk/dts/mimxrt1060_evk-enet-experimental.dtsi rename to boards/arm/mimxrt1060_evk/dts/nxp,enet-experimental.overlay diff --git a/boards/arm/mimxrt1064_evk/dts/mimxrt1064_evk-enet-experimental.dtsi b/boards/arm/mimxrt1064_evk/dts/nxp,enet-experimental.overlay similarity index 100% rename from boards/arm/mimxrt1064_evk/dts/mimxrt1064_evk-enet-experimental.dtsi rename to boards/arm/mimxrt1064_evk/dts/nxp,enet-experimental.overlay From ef1bcb7aeee316eea3b85d72da349f453f2d6b56 Mon Sep 17 00:00:00 2001 From: Seppo Takalo Date: Mon, 27 Nov 2023 17:08:50 +0200 Subject: [PATCH 0460/3723] manifest: Update net-tools * Few fixes in net-tools scripts * Fixed release URI for Leshan demo server Signed-off-by: Seppo Takalo --- west.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/west.yml b/west.yml index 5daa5e4768b..0a19d5f2dbe 100644 --- a/west.yml +++ b/west.yml @@ -290,7 +290,7 @@ manifest: - debug revision: a819419603a2dfcb47f7f39092e1bc112e45d1ef - name: net-tools - revision: d68ee9d17648a1bb3729c2023abfcb735dfe92fa + revision: 3a677d355cc7f73e444801a6280d0ccec80a1957 path: tools/net-tools groups: - tools From 9e4328cdcd7fbd13c738e962fd9832de9e14f4ac Mon Sep 17 00:00:00 2001 From: Adam Bozanich Date: Tue, 28 Nov 2023 23:51:06 -0800 Subject: [PATCH 0461/3723] doc: build: dts: bindings-syntax: compatible typo The discussion and bindings for this node assume that it is compatible with `"bar,pwm"`. Signed-off-by: Adam Bozanich --- doc/build/dts/bindings-syntax.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/doc/build/dts/bindings-syntax.rst b/doc/build/dts/bindings-syntax.rst index aff8bb64105..4cdadf62631 100644 --- a/doc/build/dts/bindings-syntax.rst +++ b/doc/build/dts/bindings-syntax.rst @@ -632,7 +632,7 @@ property, like the PWM controllers ``pwm1`` and ``pwm2`` in this example: }; pwm2: pwm@deadbeef { - compatible = "foo,pwm"; + compatible = "bar,pwm"; #pwm-cells = <1>; }; From d6329386e99066912f64f9c989ec8bf0107c91a0 Mon Sep 17 00:00:00 2001 From: Daniel Baluta Date: Thu, 23 Nov 2023 17:21:21 +0200 Subject: [PATCH 0462/3723] ci: use zephyr SDK 0.16.4 This commit update CI workflows to use CI image v0.26.6 in order to pull Zephyr SDK 0.16.4 Signed-off-by: Daniel Baluta --- .github/workflows/bsim-tests.yaml | 4 ++-- .github/workflows/clang.yaml | 4 ++-- .github/workflows/codecov.yaml | 4 ++-- .github/workflows/errno.yml | 4 ++-- .github/workflows/footprint-tracking.yml | 4 ++-- .github/workflows/footprint.yml | 4 ++-- .github/workflows/twister.yaml | 8 ++++---- .github/workflows/twister_tests_blackbox.yml | 4 ++-- 8 files changed, 18 insertions(+), 18 deletions(-) diff --git a/.github/workflows/bsim-tests.yaml b/.github/workflows/bsim-tests.yaml index f52a0439d20..e4f76dec506 100644 --- a/.github/workflows/bsim-tests.yaml +++ b/.github/workflows/bsim-tests.yaml @@ -30,13 +30,13 @@ jobs: if: github.repository_owner == 'zephyrproject-rtos' runs-on: zephyr-runner-linux-x64-4xlarge container: - image: ghcr.io/zephyrproject-rtos/ci:v0.26.5 + image: ghcr.io/zephyrproject-rtos/ci:v0.26.6 options: '--entrypoint /bin/bash' volumes: - /repo-cache/zephyrproject:/github/cache/zephyrproject env: ZEPHYR_TOOLCHAIN_VARIANT: zephyr - ZEPHYR_SDK_INSTALL_DIR: /opt/toolchains/zephyr-sdk-0.16.3 + ZEPHYR_SDK_INSTALL_DIR: /opt/toolchains/zephyr-sdk-0.16.4 BSIM_OUT_PATH: /opt/bsim/ BSIM_COMPONENTS_PATH: /opt/bsim/components EDTT_PATH: ../tools/edtt diff --git a/.github/workflows/clang.yaml b/.github/workflows/clang.yaml index 0aa8d5cd690..58e9fdd4d2c 100644 --- a/.github/workflows/clang.yaml +++ b/.github/workflows/clang.yaml @@ -11,7 +11,7 @@ jobs: if: github.repository_owner == 'zephyrproject-rtos' runs-on: zephyr-runner-linux-x64-4xlarge container: - image: ghcr.io/zephyrproject-rtos/ci:v0.26.5 + image: ghcr.io/zephyrproject-rtos/ci:v0.26.6 options: '--entrypoint /bin/bash' volumes: - /repo-cache/zephyrproject:/github/cache/zephyrproject @@ -20,7 +20,7 @@ jobs: matrix: platform: ["native_posix"] env: - ZEPHYR_SDK_INSTALL_DIR: /opt/toolchains/zephyr-sdk-0.16.3 + ZEPHYR_SDK_INSTALL_DIR: /opt/toolchains/zephyr-sdk-0.16.4 LLVM_TOOLCHAIN_PATH: /usr/lib/llvm-16 COMMIT_RANGE: ${{ github.event.pull_request.base.sha }}..${{ github.event.pull_request.head.sha }} BASE_REF: ${{ github.base_ref }} diff --git a/.github/workflows/codecov.yaml b/.github/workflows/codecov.yaml index 92cf90b8299..ad668636c56 100644 --- a/.github/workflows/codecov.yaml +++ b/.github/workflows/codecov.yaml @@ -13,7 +13,7 @@ jobs: if: github.repository == 'zephyrproject-rtos/zephyr' runs-on: zephyr-runner-linux-x64-4xlarge container: - image: ghcr.io/zephyrproject-rtos/ci:v0.26.5 + image: ghcr.io/zephyrproject-rtos/ci:v0.26.6 options: '--entrypoint /bin/bash' volumes: - /repo-cache/zephyrproject:/github/cache/zephyrproject @@ -22,7 +22,7 @@ jobs: matrix: platform: ["native_posix", "qemu_x86", "unit_testing"] env: - ZEPHYR_SDK_INSTALL_DIR: /opt/toolchains/zephyr-sdk-0.16.3 + ZEPHYR_SDK_INSTALL_DIR: /opt/toolchains/zephyr-sdk-0.16.4 steps: - name: Apply container owner mismatch workaround run: | diff --git a/.github/workflows/errno.yml b/.github/workflows/errno.yml index 537470f0a22..cea3f6f747c 100644 --- a/.github/workflows/errno.yml +++ b/.github/workflows/errno.yml @@ -10,9 +10,9 @@ jobs: check-errno: runs-on: ubuntu-22.04 container: - image: ghcr.io/zephyrproject-rtos/ci:v0.26.5 + image: ghcr.io/zephyrproject-rtos/ci:v0.26.6 env: - ZEPHYR_SDK_INSTALL_DIR: /opt/toolchains/zephyr-sdk-0.16.3 + ZEPHYR_SDK_INSTALL_DIR: /opt/toolchains/zephyr-sdk-0.16.4 steps: - name: Apply container owner mismatch workaround diff --git a/.github/workflows/footprint-tracking.yml b/.github/workflows/footprint-tracking.yml index fee3a00449f..f35dd2e6759 100644 --- a/.github/workflows/footprint-tracking.yml +++ b/.github/workflows/footprint-tracking.yml @@ -25,12 +25,12 @@ jobs: runs-on: zephyr-runner-linux-x64-4xlarge if: github.repository_owner == 'zephyrproject-rtos' container: - image: ghcr.io/zephyrproject-rtos/ci:v0.26.5 + image: ghcr.io/zephyrproject-rtos/ci:v0.26.6 options: '--entrypoint /bin/bash' strategy: fail-fast: false env: - ZEPHYR_SDK_INSTALL_DIR: /opt/toolchains/zephyr-sdk-0.16.3 + ZEPHYR_SDK_INSTALL_DIR: /opt/toolchains/zephyr-sdk-0.16.4 ZEPHYR_TOOLCHAIN_VARIANT: zephyr steps: - name: Apply container owner mismatch workaround diff --git a/.github/workflows/footprint.yml b/.github/workflows/footprint.yml index 685c5644b0c..be5a77c13e6 100644 --- a/.github/workflows/footprint.yml +++ b/.github/workflows/footprint.yml @@ -11,12 +11,12 @@ jobs: runs-on: zephyr-runner-linux-x64-4xlarge if: github.repository == 'zephyrproject-rtos/zephyr' container: - image: ghcr.io/zephyrproject-rtos/ci:v0.26.5 + image: ghcr.io/zephyrproject-rtos/ci:v0.26.6 options: '--entrypoint /bin/bash' strategy: fail-fast: false env: - ZEPHYR_SDK_INSTALL_DIR: /opt/toolchains/zephyr-sdk-0.16.3 + ZEPHYR_SDK_INSTALL_DIR: /opt/toolchains/zephyr-sdk-0.16.4 ZEPHYR_TOOLCHAIN_VARIANT: zephyr steps: - name: Apply container owner mismatch workaround diff --git a/.github/workflows/twister.yaml b/.github/workflows/twister.yaml index abf19ee3d93..49a30e09cda 100644 --- a/.github/workflows/twister.yaml +++ b/.github/workflows/twister.yaml @@ -24,7 +24,7 @@ jobs: if: github.repository_owner == 'zephyrproject-rtos' runs-on: zephyr-runner-linux-x64-4xlarge container: - image: ghcr.io/zephyrproject-rtos/ci:v0.26.5 + image: ghcr.io/zephyrproject-rtos/ci:v0.26.6 options: '--entrypoint /bin/bash' volumes: - /repo-cache/zephyrproject:/github/cache/zephyrproject @@ -36,7 +36,7 @@ jobs: MATRIX_SIZE: 10 PUSH_MATRIX_SIZE: 15 DAILY_MATRIX_SIZE: 80 - ZEPHYR_SDK_INSTALL_DIR: /opt/toolchains/zephyr-sdk-0.16.3 + ZEPHYR_SDK_INSTALL_DIR: /opt/toolchains/zephyr-sdk-0.16.4 BSIM_OUT_PATH: /opt/bsim/ BSIM_COMPONENTS_PATH: /opt/bsim/components TESTS_PER_BUILDER: 700 @@ -122,7 +122,7 @@ jobs: needs: twister-build-prep if: needs.twister-build-prep.outputs.size != 0 container: - image: ghcr.io/zephyrproject-rtos/ci:v0.26.5 + image: ghcr.io/zephyrproject-rtos/ci:v0.26.6 options: '--entrypoint /bin/bash' volumes: - /repo-cache/zephyrproject:/github/cache/zephyrproject @@ -131,7 +131,7 @@ jobs: matrix: subset: ${{fromJSON(needs.twister-build-prep.outputs.subset)}} env: - ZEPHYR_SDK_INSTALL_DIR: /opt/toolchains/zephyr-sdk-0.16.3 + ZEPHYR_SDK_INSTALL_DIR: /opt/toolchains/zephyr-sdk-0.16.4 BSIM_OUT_PATH: /opt/bsim/ BSIM_COMPONENTS_PATH: /opt/bsim/components TWISTER_COMMON: ' --force-color --inline-logs -v -N -M --retry-failed 3 ' diff --git a/.github/workflows/twister_tests_blackbox.yml b/.github/workflows/twister_tests_blackbox.yml index a18f79ae455..5e5a880a1a9 100644 --- a/.github/workflows/twister_tests_blackbox.yml +++ b/.github/workflows/twister_tests_blackbox.yml @@ -22,9 +22,9 @@ jobs: python-version: [3.8, 3.9, '3.10', '3.11', '3.12'] os: [ubuntu-22.04] container: - image: ghcr.io/zephyrproject-rtos/ci:v0.26.5 + image: ghcr.io/zephyrproject-rtos/ci:v0.26.6 env: - ZEPHYR_SDK_INSTALL_DIR: /opt/toolchains/zephyr-sdk-0.16.3 + ZEPHYR_SDK_INSTALL_DIR: /opt/toolchains/zephyr-sdk-0.16.4 steps: - name: Apply Container Owner Mismatch Workaround From 915f8a10b62b24b244d2da00793e2b670f677763 Mon Sep 17 00:00:00 2001 From: Daniel Baluta Date: Thu, 23 Nov 2023 17:28:41 +0200 Subject: [PATCH 0463/3723] doc: point to new zephyr sdk: 0.16.4 Change docs to point to new Zephyr SDK. Signed-off-by: Daniel Baluta --- .../getting_started/installation_linux.rst | 16 +++---- doc/develop/toolchains/zephyr_sdk.rst | 46 +++++++++---------- 2 files changed, 31 insertions(+), 31 deletions(-) diff --git a/doc/develop/getting_started/installation_linux.rst b/doc/develop/getting_started/installation_linux.rst index f507a8d823c..1d96ec1060f 100644 --- a/doc/develop/getting_started/installation_linux.rst +++ b/doc/develop/getting_started/installation_linux.rst @@ -228,14 +228,14 @@ The Zephyr SDK supports the following target architectures: Follow these steps to install the Zephyr SDK: #. Download and verify the `Zephyr SDK bundle - `_: + `_: .. code-block:: bash - wget https://github.com/zephyrproject-rtos/sdk-ng/releases/download/v0.16.3/zephyr-sdk-0.16.3_linux-x86_64.tar.xz - wget -O - https://github.com/zephyrproject-rtos/sdk-ng/releases/download/v0.16.3/sha256.sum | shasum --check --ignore-missing + wget https://github.com/zephyrproject-rtos/sdk-ng/releases/download/v0.16.4/zephyr-sdk-0.16.4_linux-x86_64.tar.xz + wget -O - https://github.com/zephyrproject-rtos/sdk-ng/releases/download/v0.16.4/sha256.sum | shasum --check --ignore-missing - You can change ``0.16.3`` to another version if needed; the `Zephyr SDK + You can change ``0.16.4`` to another version if needed; the `Zephyr SDK Releases`_ page contains all available SDK releases. If your host architecture is 64-bit ARM (for example, Raspberry Pi), replace @@ -246,13 +246,13 @@ Follow these steps to install the Zephyr SDK: .. code-block:: bash cd - tar xvf zephyr-sdk-0.16.3_linux-x86_64.tar.xz + tar xvf zephyr-sdk-0.16.4_linux-x86_64.tar.xz #. Run the Zephyr SDK bundle setup script: .. code-block:: bash - cd zephyr-sdk-0.16.3 + cd zephyr-sdk-0.16.4 ./setup.sh If this fails, make sure Zephyr's dependencies were installed as described @@ -271,9 +271,9 @@ If you relocate the SDK directory, you need to re-run the setup script. * ``/opt`` * ``/usr/local`` - The Zephyr SDK bundle archive contains the ``zephyr-sdk-0.16.3`` directory and, when + The Zephyr SDK bundle archive contains the ``zephyr-sdk-0.16.4`` directory and, when extracted under ``$HOME``, the resulting installation path will be - ``$HOME/zephyr-sdk-0.16.3``. + ``$HOME/zephyr-sdk-0.16.4``. If you install the Zephyr SDK outside any of these locations, you must register the Zephyr SDK in the CMake package registry by running the setup diff --git a/doc/develop/toolchains/zephyr_sdk.rst b/doc/develop/toolchains/zephyr_sdk.rst index fc6add9d3eb..3574ca85bdd 100644 --- a/doc/develop/toolchains/zephyr_sdk.rst +++ b/doc/develop/toolchains/zephyr_sdk.rst @@ -74,7 +74,7 @@ Zephyr SDK installation .. toolchain_zephyr_sdk_install_start -.. note:: You can change ``0.16.3`` to another version in the instructions below +.. note:: You can change ``0.16.4`` to another version in the instructions below if needed; the `Zephyr SDK Releases`_ page contains all available SDK releases. @@ -88,13 +88,13 @@ Zephyr SDK installation .. _ubuntu_zephyr_sdk: #. Download and verify the `Zephyr SDK bundle - `_: + `_: .. code-block:: bash cd ~ - wget https://github.com/zephyrproject-rtos/sdk-ng/releases/download/v0.16.3/zephyr-sdk-0.16.3_linux-x86_64.tar.xz - wget -O - https://github.com/zephyrproject-rtos/sdk-ng/releases/download/v0.16.3/sha256.sum | shasum --check --ignore-missing + wget https://github.com/zephyrproject-rtos/sdk-ng/releases/download/v0.16.4/zephyr-sdk-0.16.4_linux-x86_64.tar.xz + wget -O - https://github.com/zephyrproject-rtos/sdk-ng/releases/download/v0.16.4/sha256.sum | shasum --check --ignore-missing If your host architecture is 64-bit ARM (for example, Raspberry Pi), replace ``x86_64`` with ``aarch64`` in order to download the 64-bit ARM Linux SDK. @@ -103,7 +103,7 @@ Zephyr SDK installation .. code-block:: bash - tar xvf zephyr-sdk-0.16.3_linux-x86_64.tar.xz + tar xvf zephyr-sdk-0.16.4_linux-x86_64.tar.xz .. note:: It is recommended to extract the Zephyr SDK bundle at one of the following locations: @@ -115,15 +115,15 @@ Zephyr SDK installation * ``/opt`` * ``/usr/local`` - The Zephyr SDK bundle archive contains the ``zephyr-sdk-0.16.3`` directory and, when + The Zephyr SDK bundle archive contains the ``zephyr-sdk-0.16.4`` directory and, when extracted under ``$HOME``, the resulting installation path will be - ``$HOME/zephyr-sdk-0.16.3``. + ``$HOME/zephyr-sdk-0.16.4``. #. Run the Zephyr SDK bundle setup script: .. code-block:: bash - cd zephyr-sdk-0.16.3 + cd zephyr-sdk-0.16.4 ./setup.sh .. note:: @@ -137,7 +137,7 @@ Zephyr SDK installation .. code-block:: bash - sudo cp ~/zephyr-sdk-0.16.3/sysroots/x86_64-pokysdk-linux/usr/share/openocd/contrib/60-openocd.rules /etc/udev/rules.d + sudo cp ~/zephyr-sdk-0.16.4/sysroots/x86_64-pokysdk-linux/usr/share/openocd/contrib/60-openocd.rules /etc/udev/rules.d sudo udevadm control --reload .. group-tab:: macOS @@ -145,13 +145,13 @@ Zephyr SDK installation .. _macos_zephyr_sdk: #. Download and verify the `Zephyr SDK bundle - `_: + `_: .. code-block:: bash cd ~ - curl -L -O https://github.com/zephyrproject-rtos/sdk-ng/releases/download/v0.16.3/zephyr-sdk-0.16.3_macos-x86_64.tar.xz - curl -L https://github.com/zephyrproject-rtos/sdk-ng/releases/download/v0.16.3/sha256.sum | shasum --check --ignore-missing + curl -L -O https://github.com/zephyrproject-rtos/sdk-ng/releases/download/v0.16.4/zephyr-sdk-0.16.4_macos-x86_64.tar.xz + curl -L https://github.com/zephyrproject-rtos/sdk-ng/releases/download/v0.16.4/sha256.sum | shasum --check --ignore-missing If your host architecture is 64-bit ARM (Apple Silicon, also known as M1), replace ``x86_64`` with ``aarch64`` in order to download the 64-bit ARM macOS SDK. @@ -160,7 +160,7 @@ Zephyr SDK installation .. code-block:: bash - tar xvf zephyr-sdk-0.16.3_macos-x86_64.tar.xz + tar xvf zephyr-sdk-0.16.4_macos-x86_64.tar.xz .. note:: It is recommended to extract the Zephyr SDK bundle at one of the following locations: @@ -172,15 +172,15 @@ Zephyr SDK installation * ``/opt`` * ``/usr/local`` - The Zephyr SDK bundle archive contains the ``zephyr-sdk-0.16.3`` directory and, when + The Zephyr SDK bundle archive contains the ``zephyr-sdk-0.16.4`` directory and, when extracted under ``$HOME``, the resulting installation path will be - ``$HOME/zephyr-sdk-0.16.3``. + ``$HOME/zephyr-sdk-0.16.4``. #. Run the Zephyr SDK bundle setup script: .. code-block:: bash - cd zephyr-sdk-0.16.3 + cd zephyr-sdk-0.16.4 ./setup.sh .. note:: @@ -196,18 +196,18 @@ Zephyr SDK installation #. Open a ``cmd.exe`` terminal window **as a regular user** #. Download the `Zephyr SDK bundle - `_: + `_: .. code-block:: bat cd %HOMEPATH% - wget https://github.com/zephyrproject-rtos/sdk-ng/releases/download/v0.16.3/zephyr-sdk-0.16.3_windows-x86_64.7z + wget https://github.com/zephyrproject-rtos/sdk-ng/releases/download/v0.16.4/zephyr-sdk-0.16.4_windows-x86_64.7z #. Extract the Zephyr SDK bundle archive: .. code-block:: bat - 7z x zephyr-sdk-0.16.3_windows-x86_64.7z + 7z x zephyr-sdk-0.16.4_windows-x86_64.7z .. note:: It is recommended to extract the Zephyr SDK bundle at one of the following locations: @@ -215,15 +215,15 @@ Zephyr SDK installation * ``%HOMEPATH%`` * ``%PROGRAMFILES%`` - The Zephyr SDK bundle archive contains the ``zephyr-sdk-0.16.3`` directory and, when + The Zephyr SDK bundle archive contains the ``zephyr-sdk-0.16.4`` directory and, when extracted under ``%HOMEPATH%``, the resulting installation path will be - ``%HOMEPATH%\zephyr-sdk-0.16.3``. + ``%HOMEPATH%\zephyr-sdk-0.16.4``. #. Run the Zephyr SDK bundle setup script: .. code-block:: bat - cd zephyr-sdk-0.16.3 + cd zephyr-sdk-0.16.4 setup.cmd .. note:: @@ -232,7 +232,7 @@ Zephyr SDK installation You must rerun the setup script if you relocate the Zephyr SDK bundle directory after the initial setup. -.. _Zephyr SDK bundle: https://github.com/zephyrproject-rtos/sdk-ng/releases/tag/v0.16.3 +.. _Zephyr SDK bundle: https://github.com/zephyrproject-rtos/sdk-ng/releases/tag/v0.16.4 .. _Zephyr SDK Releases: https://github.com/zephyrproject-rtos/sdk-ng/tags .. _Zephyr SDK Version Compatibility Matrix: https://github.com/zephyrproject-rtos/sdk-ng/wiki/Zephyr-SDK-Version-Compatibility-Matrix From 1204aa25c82735b6359fbe79ec95a2186d612e30 Mon Sep 17 00:00:00 2001 From: Marc Desvaux Date: Tue, 12 Sep 2023 11:21:26 +0200 Subject: [PATCH 0464/3723] drivers: usb: device: fix Rx FIFO min size the FIFO Rx need to have a Minimum memory to works distributed the rest of the ram_size memory between the different TX FIFOs except the first which is a control endtype with max data payload of 64 bytes Signed-off-by: Marc Desvaux --- drivers/usb/device/usb_dc_stm32.c | 28 +++++++++++++++++++--------- 1 file changed, 19 insertions(+), 9 deletions(-) diff --git a/drivers/usb/device/usb_dc_stm32.c b/drivers/usb/device/usb_dc_stm32.c index c5516b73aef..de0a8bc2a27 100644 --- a/drivers/usb/device/usb_dc_stm32.c +++ b/drivers/usb/device/usb_dc_stm32.c @@ -127,14 +127,18 @@ static const struct gpio_dt_spec ulpi_reset = #define EP_MPS USB_OTG_FS_MAX_PACKET_SIZE #endif -/* We need one RX FIFO and n TX-IN FIFOs */ -#define FIFO_NUM (1 + USB_NUM_BIDIR_ENDPOINTS) +/* We need n TX IN FIFOs */ +#define TX_FIFO_NUM USB_NUM_BIDIR_ENDPOINTS -/* 4-byte words FIFO */ -#define FIFO_WORDS (USB_RAM_SIZE / 4) +/* We need a minimum size for RX FIFO */ +#define USB_FIFO_RX_MIN 160 -/* Allocate FIFO memory evenly between the FIFOs */ -#define FIFO_EP_WORDS (FIFO_WORDS / FIFO_NUM) +/* 4-byte words TX FIFO */ +#define TX_FIFO_WORDS ((USB_RAM_SIZE - USB_FIFO_RX_MIN - 64) / 4) + +/* Allocate FIFO memory evenly between the TX FIFOs */ +/* except the first TX endpoint need only 64 bytes */ +#define TX_FIFO_EP_WORDS (TX_FIFO_WORDS / (TX_FIFO_NUM - 1)) #endif /* USB */ @@ -436,11 +440,17 @@ static int usb_dc_stm32_init(void) k_sem_init(&usb_dc_stm32_state.in_ep_state[i].write_sem, 1, 1); } #else /* USB_OTG_FS */ + /* TODO: make this dynamic (depending usage) */ - HAL_PCDEx_SetRxFiFo(&usb_dc_stm32_state.pcd, FIFO_EP_WORDS); + HAL_PCDEx_SetRxFiFo(&usb_dc_stm32_state.pcd, USB_FIFO_RX_MIN); for (i = 0U; i < USB_NUM_BIDIR_ENDPOINTS; i++) { - HAL_PCDEx_SetTxFiFo(&usb_dc_stm32_state.pcd, i, - FIFO_EP_WORDS); + if (i == 0) { + /* first endpoint need only 64 byte for EP_TYPE_CTRL */ + HAL_PCDEx_SetTxFiFo(&usb_dc_stm32_state.pcd, i, 16); + } else { + HAL_PCDEx_SetTxFiFo(&usb_dc_stm32_state.pcd, i, + TX_FIFO_EP_WORDS); + } k_sem_init(&usb_dc_stm32_state.in_ep_state[i].write_sem, 1, 1); } #endif /* USB */ From 2effd8cce7a9fb802d5b3e3a2ab24e620775000f Mon Sep 17 00:00:00 2001 From: Daniel Gaston Ochoa Date: Sat, 9 Sep 2023 15:46:15 +0100 Subject: [PATCH 0465/3723] drivers: spi: stm32h7: Move startMasterTransfer to transceive Avoind calling startMasterTransfer multiple times in a transaction by moving it to the transceive() function. Signed-off-by: Daniel Gaston Ochoa --- drivers/spi/spi_ll_stm32.c | 28 ++++++++++++++-------------- 1 file changed, 14 insertions(+), 14 deletions(-) diff --git a/drivers/spi/spi_ll_stm32.c b/drivers/spi/spi_ll_stm32.c index 0241dbde254..8a1d11b4308 100644 --- a/drivers/spi/spi_ll_stm32.c +++ b/drivers/spi/spi_ll_stm32.c @@ -306,20 +306,6 @@ static void spi_stm32_shift_m(SPI_TypeDef *spi, struct spi_stm32_data *data) /* NOP */ } -#if DT_HAS_COMPAT_STATUS_OKAY(st_stm32h7_spi) - /* With the STM32MP1, STM32U5 and the STM32H7, - * if the device is the SPI master, - * we need to enable the start of the transfer with - * LL_SPI_StartMasterTransfer(spi) - */ - if (LL_SPI_GetMode(spi) == LL_SPI_MODE_MASTER) { - LL_SPI_StartMasterTransfer(spi); - while (!LL_SPI_IsActiveMasterTransfer(spi)) { - /* NOP */ - } - } -#endif - if (SPI_WORD_SIZE_GET(data->ctx.config->operation) == 8) { if (spi_context_tx_buf_on(&data->ctx)) { tx_frame = UNALIGNED_GET((uint8_t *)(data->ctx.tx_buf)); @@ -691,6 +677,20 @@ static int transceive(const struct device *dev, LL_SPI_Enable(spi); +#if DT_HAS_COMPAT_STATUS_OKAY(st_stm32h7_spi) + /* With the STM32MP1, STM32U5 and the STM32H7, + * if the device is the SPI master, + * we need to enable the start of the transfer with + * LL_SPI_StartMasterTransfer(spi) + */ + if (LL_SPI_GetMode(spi) == LL_SPI_MODE_MASTER) { + LL_SPI_StartMasterTransfer(spi); + while (!LL_SPI_IsActiveMasterTransfer(spi)) { + /* NOP */ + } + } +#endif /* DT_HAS_COMPAT_STATUS_OKAY(st_stm32h7_spi) */ + #if CONFIG_SOC_SERIES_STM32H7X /* * Add a small delay after enabling to prevent transfer stalling at high From 02f46fb1f27f7ce77376fadb41fa05ae4dc73b3f Mon Sep 17 00:00:00 2001 From: Daniel Gaston Ochoa Date: Sat, 9 Sep 2023 14:38:19 +0100 Subject: [PATCH 0466/3723] drivers: spi: stm32h7: Use a better name for ll_func_tx_is_empty In H7, TXP indicates when its FIFO has room for, at least, one packet. Thus, rename ll_func_tx_is_empty as ll_func_tx_is_not_full, to be consistent in all platforms. Signed-off-by: Daniel Gaston Ochoa --- drivers/spi/spi_ll_stm32.c | 4 ++-- drivers/spi/spi_ll_stm32.h | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/drivers/spi/spi_ll_stm32.c b/drivers/spi/spi_ll_stm32.c index 8a1d11b4308..c1e86635e04 100644 --- a/drivers/spi/spi_ll_stm32.c +++ b/drivers/spi/spi_ll_stm32.c @@ -302,7 +302,7 @@ static void spi_stm32_shift_m(SPI_TypeDef *spi, struct spi_stm32_data *data) uint16_t tx_frame = SPI_STM32_TX_NOP; uint16_t rx_frame; - while (!ll_func_tx_is_empty(spi)) { + while (!ll_func_tx_is_not_full(spi)) { /* NOP */ } @@ -344,7 +344,7 @@ static void spi_stm32_shift_m(SPI_TypeDef *spi, struct spi_stm32_data *data) /* Shift a SPI frame as slave. */ static void spi_stm32_shift_s(SPI_TypeDef *spi, struct spi_stm32_data *data) { - if (ll_func_tx_is_empty(spi) && spi_context_tx_on(&data->ctx)) { + if (ll_func_tx_is_not_full(spi) && spi_context_tx_on(&data->ctx)) { uint16_t tx_frame; if (SPI_WORD_SIZE_GET(data->ctx.config->operation) == 8) { diff --git a/drivers/spi/spi_ll_stm32.h b/drivers/spi/spi_ll_stm32.h index 949b8882dd7..a90b41311af 100644 --- a/drivers/spi/spi_ll_stm32.h +++ b/drivers/spi/spi_ll_stm32.h @@ -94,7 +94,7 @@ static inline uint32_t ll_func_spi_dma_busy(SPI_TypeDef *spi) } #endif /* CONFIG_SPI_STM32_DMA */ -static inline uint32_t ll_func_tx_is_empty(SPI_TypeDef *spi) +static inline uint32_t ll_func_tx_is_not_full(SPI_TypeDef *spi) { #if DT_HAS_COMPAT_STATUS_OKAY(st_stm32h7_spi) return LL_SPI_IsActiveFlag_TXP(spi); From cb4f54535f71fd2d5f9c766e20461fc5f44819d5 Mon Sep 17 00:00:00 2001 From: Daniel Gaston Ochoa Date: Sat, 9 Sep 2023 14:35:33 +0100 Subject: [PATCH 0467/3723] drivers: spi: stm32h7: Simplify long function in small ones Simplify and clarify spi_stm32_shift_m by splitting it in 3 smaller functions with clear names. Signed-off-by: Daniel Gaston Ochoa --- drivers/spi/spi_ll_stm32.c | 75 ++++++++++++++++++++++---------------- 1 file changed, 44 insertions(+), 31 deletions(-) diff --git a/drivers/spi/spi_ll_stm32.c b/drivers/spi/spi_ll_stm32.c index c1e86635e04..5299554a353 100644 --- a/drivers/spi/spi_ll_stm32.c +++ b/drivers/spi/spi_ll_stm32.c @@ -272,6 +272,48 @@ static int spi_dma_move_buffers(const struct device *dev, size_t len) /* Value to shift out when no application data needs transmitting. */ #define SPI_STM32_TX_NOP 0x00 +static void spi_stm32_send_next_frame(SPI_TypeDef *spi, + struct spi_stm32_data *data) +{ + const uint8_t frame_size = SPI_WORD_SIZE_GET(data->ctx.config->operation); + uint32_t tx_frame = SPI_STM32_TX_NOP; + + if (frame_size == 8) { + if (spi_context_tx_buf_on(&data->ctx)) { + tx_frame = UNALIGNED_GET((uint8_t *)(data->ctx.tx_buf)); + } + LL_SPI_TransmitData8(spi, tx_frame); + spi_context_update_tx(&data->ctx, 1, 1); + } else { + if (spi_context_tx_buf_on(&data->ctx)) { + tx_frame = UNALIGNED_GET((uint16_t *)(data->ctx.tx_buf)); + } + LL_SPI_TransmitData16(spi, tx_frame); + spi_context_update_tx(&data->ctx, 2, 1); + } +} + +static void spi_stm32_read_next_frame(SPI_TypeDef *spi, + struct spi_stm32_data *data) +{ + const uint8_t frame_size = SPI_WORD_SIZE_GET(data->ctx.config->operation); + uint32_t rx_frame = 0; + + if (frame_size == 8) { + rx_frame = LL_SPI_ReceiveData8(spi); + if (spi_context_rx_buf_on(&data->ctx)) { + UNALIGNED_PUT(rx_frame, (uint8_t *)data->ctx.rx_buf); + } + spi_context_update_rx(&data->ctx, 1, 1); + } else { + rx_frame = LL_SPI_ReceiveData16(spi); + if (spi_context_rx_buf_on(&data->ctx)) { + UNALIGNED_PUT(rx_frame, (uint16_t *)data->ctx.rx_buf); + } + spi_context_update_rx(&data->ctx, 2, 1); + } +} + static bool spi_stm32_transfer_ongoing(struct spi_stm32_data *data) { return spi_context_tx_on(&data->ctx) || spi_context_rx_on(&data->ctx); @@ -299,46 +341,17 @@ static int spi_stm32_get_err(SPI_TypeDef *spi) /* Shift a SPI frame as master. */ static void spi_stm32_shift_m(SPI_TypeDef *spi, struct spi_stm32_data *data) { - uint16_t tx_frame = SPI_STM32_TX_NOP; - uint16_t rx_frame; - while (!ll_func_tx_is_not_full(spi)) { /* NOP */ } - if (SPI_WORD_SIZE_GET(data->ctx.config->operation) == 8) { - if (spi_context_tx_buf_on(&data->ctx)) { - tx_frame = UNALIGNED_GET((uint8_t *)(data->ctx.tx_buf)); - } - LL_SPI_TransmitData8(spi, tx_frame); - /* The update is ignored if TX is off. */ - spi_context_update_tx(&data->ctx, 1, 1); - } else { - if (spi_context_tx_buf_on(&data->ctx)) { - tx_frame = UNALIGNED_GET((uint16_t *)(data->ctx.tx_buf)); - } - LL_SPI_TransmitData16(spi, tx_frame); - /* The update is ignored if TX is off. */ - spi_context_update_tx(&data->ctx, 2, 1); - } + spi_stm32_send_next_frame(spi, data); while (!ll_func_rx_is_not_empty(spi)) { /* NOP */ } - if (SPI_WORD_SIZE_GET(data->ctx.config->operation) == 8) { - rx_frame = LL_SPI_ReceiveData8(spi); - if (spi_context_rx_buf_on(&data->ctx)) { - UNALIGNED_PUT(rx_frame, (uint8_t *)data->ctx.rx_buf); - } - spi_context_update_rx(&data->ctx, 1, 1); - } else { - rx_frame = LL_SPI_ReceiveData16(spi); - if (spi_context_rx_buf_on(&data->ctx)) { - UNALIGNED_PUT(rx_frame, (uint16_t *)data->ctx.rx_buf); - } - spi_context_update_rx(&data->ctx, 2, 1); - } + spi_stm32_read_next_frame(spi, data); } /* Shift a SPI frame as slave. */ From 50f64eaebaac99f069eee598ba81b5dfca030c97 Mon Sep 17 00:00:00 2001 From: Daniel Gaston Ochoa Date: Thu, 16 Nov 2023 10:47:49 +0000 Subject: [PATCH 0468/3723] drivers: spi: stm32h7: Use FIFO Use H7 SPI FIFO to improve performance. Signed-off-by: Daniel Gaston Ochoa --- drivers/spi/spi_ll_stm32.c | 50 +++++++++++++++++++++++++++++++------- 1 file changed, 41 insertions(+), 9 deletions(-) diff --git a/drivers/spi/spi_ll_stm32.c b/drivers/spi/spi_ll_stm32.c index 5299554a353..c5df1e249cd 100644 --- a/drivers/spi/spi_ll_stm32.c +++ b/drivers/spi/spi_ll_stm32.c @@ -273,7 +273,7 @@ static int spi_dma_move_buffers(const struct device *dev, size_t len) #define SPI_STM32_TX_NOP 0x00 static void spi_stm32_send_next_frame(SPI_TypeDef *spi, - struct spi_stm32_data *data) + struct spi_stm32_data *data) { const uint8_t frame_size = SPI_WORD_SIZE_GET(data->ctx.config->operation); uint32_t tx_frame = SPI_STM32_TX_NOP; @@ -338,20 +338,52 @@ static int spi_stm32_get_err(SPI_TypeDef *spi) return 0; } -/* Shift a SPI frame as master. */ -static void spi_stm32_shift_m(SPI_TypeDef *spi, struct spi_stm32_data *data) +static bool spi_stm32_can_use_fifo(void) { - while (!ll_func_tx_is_not_full(spi)) { - /* NOP */ +#if DT_HAS_COMPAT_STATUS_OKAY(st_stm32h7_spi) + return true; +#else + /* + * TODO Test the FIFO usage in other FIFO-enabled STM32 SPI devices. + */ + return false; +#endif /* DT_HAS_COMPAT_STATUS_OKAY(st_stm32h7_spi) */ +} + +static void spi_stm32_shift_fifo(SPI_TypeDef *spi, struct spi_stm32_data *data) +{ + while (ll_func_rx_is_not_empty(spi)) { + spi_stm32_read_next_frame(spi, data); } - spi_stm32_send_next_frame(spi, data); + while (ll_func_tx_is_not_full(spi) && spi_stm32_transfer_ongoing(data)) { + spi_stm32_send_next_frame(spi, data); - while (!ll_func_rx_is_not_empty(spi)) { - /* NOP */ + if (ll_func_rx_is_not_empty(spi)) { + /* Break as soon as a frame is ready to read to avoid overruns */ + break; + } } +} + +/* Shift a SPI frame as master. */ +static void spi_stm32_shift_m(SPI_TypeDef *spi, struct spi_stm32_data *data) +{ + if (spi_stm32_can_use_fifo()) { + spi_stm32_shift_fifo(spi, data); + } else { + while (!ll_func_tx_is_not_full(spi)) { + /* NOP */ + } - spi_stm32_read_next_frame(spi, data); + spi_stm32_send_next_frame(spi, data); + + while (!ll_func_rx_is_not_empty(spi)) { + /* NOP */ + } + + spi_stm32_read_next_frame(spi, data); + } } /* Shift a SPI frame as slave. */ From e91e65b5fde347304876cb1d5c65fb69fceea698 Mon Sep 17 00:00:00 2001 From: Piotr Narajowski Date: Tue, 17 Oct 2023 10:18:30 +0200 Subject: [PATCH 0469/3723] bluetooth: tester: GMCS Server tests Add support for Generic Media Control Service tests Signed-off-by: Piotr Narajowski --- tests/bluetooth/tester/CMakeLists.txt | 2 +- tests/bluetooth/tester/overlay-le-audio.conf | 16 ++ tests/bluetooth/tester/src/btp/btp.h | 4 +- tests/bluetooth/tester/src/btp/btp_mcs.h | 38 +++ tests/bluetooth/tester/src/btp/bttester.h | 3 + tests/bluetooth/tester/src/btp_core.c | 13 + tests/bluetooth/tester/src/btp_mcp.c | 248 +++++++++++++++++++ 7 files changed, 322 insertions(+), 2 deletions(-) create mode 100644 tests/bluetooth/tester/src/btp/btp_mcs.h diff --git a/tests/bluetooth/tester/CMakeLists.txt b/tests/bluetooth/tester/CMakeLists.txt index 842b6ebe5d8..24b3353b513 100644 --- a/tests/bluetooth/tester/CMakeLists.txt +++ b/tests/bluetooth/tester/CMakeLists.txt @@ -60,6 +60,6 @@ if (CONFIG_BT_CAP_ACCEPTOR) target_sources(app PRIVATE src/btp_cas.c) endif() -if(CONFIG_BT_MCC) +if(CONFIG_BT_MCC OR CONFIG_BT_MCS) target_sources(app PRIVATE src/btp_mcp.c) endif() diff --git a/tests/bluetooth/tester/overlay-le-audio.conf b/tests/bluetooth/tester/overlay-le-audio.conf index 4a7fc4e606c..92739656e8c 100644 --- a/tests/bluetooth/tester/overlay-le-audio.conf +++ b/tests/bluetooth/tester/overlay-le-audio.conf @@ -106,3 +106,19 @@ CONFIG_BT_CAP_ACCEPTOR_SET_MEMBER=y CONFIG_BT_MCC=y CONFIG_BT_OTS_CLIENT=y CONFIG_BT_MCC_OTS=y + +#MCS +CONFIG_MCTL=y +CONFIG_MCTL_LOCAL_PLAYER_CONTROL=y +CONFIG_MCTL_LOCAL_PLAYER_REMOTE_CONTROL=y +CONFIG_BT_MPL_LOG_LEVEL_DBG=y +CONFIG_BT_MPL_OBJECTS=y +CONFIG_BT_OTS=y +CONFIG_BT_OTS_SECONDARY_SVC=y +CONFIG_BT_OTS_MAX_OBJ_CNT=0x30 +CONFIG_BT_MCS=y +CONFIG_MCTL_LOCAL_PLAYER_LOCAL_CONTROL=y +CONFIG_MCTL_REMOTE_PLAYER_CONTROL_OBJECTS=y +CONFIG_MCTL_REMOTE_PLAYER_CONTROL=y +CONFIG_BT_MPL=y +CONFIG_UTF8=y diff --git a/tests/bluetooth/tester/src/btp/btp.h b/tests/bluetooth/tester/src/btp/btp.h index c7781932801..a88118e895d 100644 --- a/tests/bluetooth/tester/src/btp/btp.h +++ b/tests/bluetooth/tester/src/btp/btp.h @@ -31,6 +31,7 @@ #include "btp_vcp.h" #include "btp_cas.h" #include "btp_mcp.h" +#include "btp_mcs.h" #define BTP_MTU 1024 #define BTP_DATA_MAX_SIZE (BTP_MTU - sizeof(struct btp_hdr)) @@ -61,8 +62,9 @@ #define BTP_SERVICE_ID_VCP 20 #define BTP_SERVICE_ID_CAS 21 #define BTP_SERVICE_ID_MCP 22 +#define BTP_SERVICE_ID_GMCS 23 -#define BTP_SERVICE_ID_MAX BTP_SERVICE_ID_MCP +#define BTP_SERVICE_ID_MAX BTP_SERVICE_ID_GMCS #define BTP_STATUS_SUCCESS 0x00 #define BTP_STATUS_FAILED 0x01 diff --git a/tests/bluetooth/tester/src/btp/btp_mcs.h b/tests/bluetooth/tester/src/btp/btp_mcs.h new file mode 100644 index 00000000000..d2395216d3f --- /dev/null +++ b/tests/bluetooth/tester/src/btp/btp_mcs.h @@ -0,0 +1,38 @@ +/* btp_mcs.h - Bluetooth tester headers */ + +/* + * Copyright (c) 2023 Codecoup + * + * SPDX-License-Identifier: Apache-2.0 + */ +#include + +/* MCS commands */ +#define BTP_MCS_READ_SUPPORTED_COMMANDS 0x01 +struct btp_mcs_read_supported_commands_rp { + uint8_t data[0]; +} __packed; + +#define BTP_MCS_CMD_SEND 0x02 +struct btp_mcs_send_cmd { + uint8_t opcode; + uint8_t use_param; + int32_t param; +} __packed; + +#define BTP_MCS_CURRENT_TRACK_OBJ_ID_GET 0x03 +struct btp_mcs_current_track_obj_id_rp { + uint8_t id[BT_OTS_OBJ_ID_SIZE]; +} __packed; + +#define BTP_MCS_NEXT_TRACK_OBJ_ID_GET 0x04 +struct btp_mcs_next_track_obj_id_rp { + uint8_t id[BT_OTS_OBJ_ID_SIZE]; +} __packed; + +#define BTP_MCS_INACTIVE_STATE_SET 0x05 +struct btp_mcs_state_set_rp { + uint8_t state; +} __packed; + +#define BTP_MCS_PARENT_GROUP_SET 0x06 diff --git a/tests/bluetooth/tester/src/btp/bttester.h b/tests/bluetooth/tester/src/btp/bttester.h index ce8b1259a42..9c545cd4a46 100644 --- a/tests/bluetooth/tester/src/btp/bttester.h +++ b/tests/bluetooth/tester/src/btp/bttester.h @@ -117,3 +117,6 @@ uint8_t tester_unregister_cas(void); uint8_t tester_init_mcp(void); uint8_t tester_unregister_mcp(void); + +uint8_t tester_init_mcs(void); +uint8_t tester_unregister_mcs(void); diff --git a/tests/bluetooth/tester/src/btp_core.c b/tests/bluetooth/tester/src/btp_core.c index 8c157a5eccb..757d8816c8e 100644 --- a/tests/bluetooth/tester/src/btp_core.c +++ b/tests/bluetooth/tester/src/btp_core.c @@ -95,6 +95,9 @@ static uint8_t supported_services(const void *cmd, uint16_t cmd_len, #if defined(CONFIG_BT_MCC) tester_set_bit(rp->data, BTP_SERVICE_ID_MCP); #endif /* CONFIG_BT_MCC */ +#if defined(CONFIG_BT_MCS) + tester_set_bit(rp->data, BTP_SERVICE_ID_GMCS); +#endif /* CONFIG_BT_MCS */ *rsp_len = sizeof(*rp) + 2; @@ -203,6 +206,11 @@ static uint8_t register_service(const void *cmd, uint16_t cmd_len, status = tester_init_mcp(); break; #endif /* CONFIG_BT_MCC */ +#if defined(CONFIG_BT_MCS) + case BTP_SERVICE_ID_GMCS: + status = tester_init_mcs(); + break; +#endif /* CONFIG_BT_MCS */ default: LOG_WRN("unknown id: 0x%02x", cp->id); status = BTP_STATUS_FAILED; @@ -315,6 +323,11 @@ static uint8_t unregister_service(const void *cmd, uint16_t cmd_len, status = tester_unregister_mcp(); break; #endif /* CONFIG_BT_MCC */ +#if defined(CONFIG_BT_MCS) + case BTP_SERVICE_ID_GMCS: + status = tester_unregister_mcs(); + break; +#endif /* CONFIG_BT_MCS */ default: LOG_WRN("unknown id: 0x%x", cp->id); status = BTP_STATUS_FAILED; diff --git a/tests/bluetooth/tester/src/btp_mcp.c b/tests/bluetooth/tester/src/btp_mcp.c index d04dca35dc0..f189db909ee 100644 --- a/tests/bluetooth/tester/src/btp_mcp.c +++ b/tests/bluetooth/tester/src/btp_mcp.c @@ -17,6 +17,8 @@ #include #include #include +#include <../../subsys/bluetooth/audio/mpl_internal.h> +#include #include #include @@ -29,6 +31,13 @@ #define LOG_MODULE_NAME bttester_mcp LOG_MODULE_REGISTER(LOG_MODULE_NAME, CONFIG_BTTESTER_LOG_LEVEL); +static struct media_player *mcs_media_player; +static uint64_t current_track_obj_id; +static uint64_t next_track_obj_id; +static uint8_t media_player_state; +static uint64_t current_id; +static uint64_t parent_id; + #define SEARCH_LEN_MAX 64 static struct net_buf_simple *rx_ev_buf = NET_BUF_SIMPLE(SEARCH_LEN_MAX + @@ -1317,3 +1326,242 @@ uint8_t tester_unregister_mcp(void) { return BTP_STATUS_SUCCESS; } + +/* Media Control Service */ +static uint8_t mcs_supported_commands(const void *cmd, uint16_t cmd_len, void *rsp, + uint16_t *rsp_len) +{ + struct btp_mcs_read_supported_commands_rp *rp = rsp; + + /* octet 0 */ + tester_set_bit(rp->data, BTP_MCS_READ_SUPPORTED_COMMANDS); + tester_set_bit(rp->data, BTP_MCS_CMD_SEND); + tester_set_bit(rp->data, BTP_MCS_CURRENT_TRACK_OBJ_ID_GET); + tester_set_bit(rp->data, BTP_MCS_NEXT_TRACK_OBJ_ID_GET); + tester_set_bit(rp->data, BTP_MCS_INACTIVE_STATE_SET); + tester_set_bit(rp->data, BTP_MCS_PARENT_GROUP_SET); + + *rsp_len = sizeof(*rp) + 1; + + return BTP_STATUS_SUCCESS; +} + +static uint8_t mcs_cmd_send(const void *cmd, uint16_t cmd_len, void *rsp, uint16_t *rsp_len) +{ + const struct btp_mcs_send_cmd *cp = cmd; + struct mpl_cmd mcp_cmd; + int err; + + LOG_DBG("MCS Send Command"); + + mcp_cmd.opcode = cp->opcode; + mcp_cmd.use_param = cp->use_param; + mcp_cmd.param = (cp->use_param != 0) ? sys_le32_to_cpu(cp->param) : 0; + + err = media_proxy_ctrl_send_command(mcs_media_player, &mcp_cmd); + if (err) { + return BTP_STATUS_FAILED; + } + + return BTP_STATUS_SUCCESS; +} + +static uint8_t mcs_next_track_obj_id_get(const void *cmd, uint16_t cmd_len, void *rsp, + uint16_t *rsp_len) +{ + struct btp_mcs_next_track_obj_id_rp *rp = rsp; + int err; + + LOG_DBG("MCS Read Next Track Obj Id"); + + err = media_proxy_ctrl_get_next_track_id(mcs_media_player); + if (err) { + return BTP_STATUS_FAILED; + } + + sys_put_le48(next_track_obj_id, rp->id); + + *rsp_len = sizeof(*rp); + + return BTP_STATUS_SUCCESS; +} + +static uint8_t mcs_current_track_obj_id_get(const void *cmd, uint16_t cmd_len, void *rsp, + uint16_t *rsp_len) +{ + struct btp_mcs_current_track_obj_id_rp *rp = rsp; + int err; + + LOG_DBG("MCS Read Current Track Obj Id"); + + err = media_proxy_ctrl_get_current_track_id(mcs_media_player); + if (err) { + return BTP_STATUS_FAILED; + } + + sys_put_le48(current_track_obj_id, rp->id); + + *rsp_len = sizeof(*rp); + + return BTP_STATUS_SUCCESS; +} + +static uint8_t mcs_parent_group_set(const void *cmd, uint16_t cmd_len, void *rsp, + uint16_t *rsp_len) +{ + int err; + + LOG_DBG("MCS Set Current Group to be it's own parent"); + + err = media_proxy_ctrl_get_current_group_id(mcs_media_player); + if (err) { + return BTP_STATUS_FAILED; + } + + /* Setting current group to be it's own parent */ + mpl_test_unset_parent_group(); + + err = media_proxy_ctrl_get_parent_group_id(mcs_media_player); + if (err) { + return BTP_STATUS_FAILED; + } + + if (current_id != parent_id) { + return BTP_STATUS_FAILED; + } + + return BTP_STATUS_SUCCESS; +} + +static uint8_t mcs_inactive_state_set(const void *cmd, uint16_t cmd_len, void *rsp, + uint16_t *rsp_len) +{ + struct btp_mcs_state_set_rp *rp = rsp; + + LOG_DBG("MCS Set Media Player to inactive state"); + + mpl_test_media_state_set(MEDIA_PROXY_STATE_INACTIVE); + + rp->state = media_player_state; + + *rsp_len = sizeof(*rp); + + return BTP_STATUS_SUCCESS; +} + +static void mcs_player_instance_cb(struct media_player *plr, int err) +{ + mcs_media_player = plr; + + LOG_DBG("Media PLayer Instance cb"); +} + +static void mcs_command_send_cb(struct media_player *player, int err, const struct mpl_cmd *cmd) +{ + LOG_DBG("Media PLayer Send Command cb"); +} + +static void mcs_current_track_obj_id_cb(struct media_player *player, int err, uint64_t id) +{ + LOG_DBG("Media Player Current Track Object Id cb"); + + current_track_obj_id = id; +} + +static void mcs_next_track_obj_id_cb(struct media_player *player, int err, uint64_t id) +{ + LOG_DBG("Media PLayer Next Track Object ID cb"); + + next_track_obj_id = id; +} + +static void mcs_media_state_cb(struct media_player *player, int err, uint8_t state) +{ + LOG_DBG("Media Player State cb"); + + media_player_state = state; +} + +static void mcs_current_group_id_cb(struct media_player *player, int err, uint64_t id) +{ + LOG_DBG("Media Player Current Group ID cb"); + + current_id = id; +} + +static void mcs_parent_group_id_cb(struct media_player *player, int err, uint64_t id) +{ + LOG_DBG("Media Player Parent Group ID cb"); + + parent_id = id; +} + +static struct media_proxy_ctrl_cbs mcs_cbs = { + .local_player_instance = mcs_player_instance_cb, + .command_send = mcs_command_send_cb, + .current_track_id_recv = mcs_current_track_obj_id_cb, + .next_track_id_recv = mcs_next_track_obj_id_cb, + .media_state_recv = mcs_media_state_cb, + .current_group_id_recv = mcs_current_group_id_cb, + .parent_group_id_recv = mcs_parent_group_id_cb, +}; + +static const struct btp_handler mcs_handlers[] = { + { + .opcode = BTP_MCS_READ_SUPPORTED_COMMANDS, + .index = BTP_INDEX_NONE, + .expect_len = 0, + .func = mcs_supported_commands, + }, + { + .opcode = BTP_MCS_CMD_SEND, + .expect_len = BTP_HANDLER_LENGTH_VARIABLE, + .func = mcs_cmd_send, + }, + { + .opcode = BTP_MCS_CURRENT_TRACK_OBJ_ID_GET, + .expect_len = 0, + .func = mcs_current_track_obj_id_get, + }, + { + .opcode = BTP_MCS_NEXT_TRACK_OBJ_ID_GET, + .expect_len = 0, + .func = mcs_next_track_obj_id_get, + }, + { + .opcode = BTP_MCS_INACTIVE_STATE_SET, + .expect_len = 0, + .func = mcs_inactive_state_set, + }, + { + .opcode = BTP_MCS_PARENT_GROUP_SET, + .expect_len = 0, + .func = mcs_parent_group_set, + }, +}; + +uint8_t tester_init_mcs(void) +{ + int err; + + err = media_proxy_pl_init(); + if (err) { + LOG_DBG("Failed to initialize Media Player: %d", err); + return BTP_STATUS_FAILED; + } + + err = media_proxy_ctrl_register(&mcs_cbs); + if (err) { + return BTP_STATUS_FAILED; + } + + tester_register_command_handlers(BTP_SERVICE_ID_GMCS, mcs_handlers, + ARRAY_SIZE(mcs_handlers)); + + return BTP_STATUS_SUCCESS; +} + +uint8_t tester_unregister_mcs(void) +{ + return BTP_STATUS_SUCCESS; +} From 77b49ab58717d93949c5fb461175fa6a27b7e366 Mon Sep 17 00:00:00 2001 From: Patryk Koscik Date: Wed, 15 Nov 2023 15:39:33 +0100 Subject: [PATCH 0470/3723] dts: arm: rpi_pico: Add compat string to rp2040 This commit adds compatible string to the `rp2040` SoC node. Signed-off-by: Patryk Koscik --- dts/arm/rpi_pico/rp2040.dtsi | 2 ++ 1 file changed, 2 insertions(+) diff --git a/dts/arm/rpi_pico/rp2040.dtsi b/dts/arm/rpi_pico/rp2040.dtsi index 1e4211075f8..34a09a24dc9 100644 --- a/dts/arm/rpi_pico/rp2040.dtsi +++ b/dts/arm/rpi_pico/rp2040.dtsi @@ -34,6 +34,8 @@ }; soc { + compatible = "raspberrypi,rp2040", "simple-bus"; + sram0: memory@20000000 { compatible = "mmio-sram"; reg = <0x20000000 DT_SIZE_K(264)>; From 90978b9f4093e34999c1a2cf6929e82008864194 Mon Sep 17 00:00:00 2001 From: Arkadiusz Wadowski Date: Thu, 23 Nov 2023 11:13:50 +0100 Subject: [PATCH 0471/3723] mgmt/osdp: Make OSDP slab init safer slab_buff size is calculated based on size of osdp_ephemeral_data union so it is safer to use same structure for slab init. Changes in osdp_event or osd_cmd structures can cause crashes without this. Signed-off-by: Arkadiusz Wadowski --- subsys/mgmt/osdp/src/osdp.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/subsys/mgmt/osdp/src/osdp.c b/subsys/mgmt/osdp/src/osdp.c index f38d6444176..e1a0f7f1167 100644 --- a/subsys/mgmt/osdp/src/osdp.c +++ b/subsys/mgmt/osdp/src/osdp.c @@ -156,8 +156,7 @@ static struct osdp *osdp_build_ctx(struct osdp_channel *channel) SET_FLAG(pd, PD_FLAG_PKT_SKIP_MARK); } memcpy(&pd->channel, channel, sizeof(struct osdp_channel)); - k_mem_slab_init(&pd->cmd.slab, - pd->cmd.slab_buf, sizeof(struct osdp_cmd), + k_mem_slab_init(&pd->cmd.slab, pd->cmd.slab_buf, sizeof(union osdp_ephemeral_data), CONFIG_OSDP_PD_COMMAND_QUEUE_SIZE); } return ctx; From 052f0994d458d0f2b51fe8546c9e6e4800d247c6 Mon Sep 17 00:00:00 2001 From: Bartosz Bilas Date: Sun, 26 Nov 2023 09:49:48 +0100 Subject: [PATCH 0472/3723] west: bump hal_espressif It contains a fix for a typo within emac_hal module. Signed-off-by: Bartosz Bilas --- west.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/west.yml b/west.yml index 0a19d5f2dbe..78bede760fd 100644 --- a/west.yml +++ b/west.yml @@ -152,7 +152,7 @@ manifest: groups: - hal - name: hal_espressif - revision: ca3be152414bb269647806c4d3091e04168d1add + revision: ffbe58815808af98d1e3241defa552a0fcc6d28a path: modules/hal/espressif west-commands: west/west-commands.yml groups: From 55f2d72cd44d939e2594fe2e0b858e625992a8bf Mon Sep 17 00:00:00 2001 From: Bartosz Bilas Date: Sat, 25 Nov 2023 14:34:47 +0100 Subject: [PATCH 0473/3723] drivers: eth_esp32: allow selecting ref clk source In case of boards where REF_CLK signal is not connected to the GPIO0 by default add the possibility to use the optional GPIO16/GPIO17 as a REF CLK source. Signed-off-by: Bartosz Bilas --- drivers/ethernet/eth_esp32.c | 12 ++++++++++++ dts/bindings/ethernet/espressif,esp32-eth.yaml | 5 +++++ 2 files changed, 17 insertions(+) diff --git a/drivers/ethernet/eth_esp32.c b/drivers/ethernet/eth_esp32.c index d7e9382c9c9..6cf6ba44813 100644 --- a/drivers/ethernet/eth_esp32.c +++ b/drivers/ethernet/eth_esp32.c @@ -17,6 +17,7 @@ #include #include #include +#include #include "eth.h" @@ -223,8 +224,19 @@ int eth_esp32_initialize(const struct device *dev) if (strcmp(phy_connection_type, "rmii") == 0) { emac_hal_iomux_init_rmii(); +#if DT_INST_NODE_HAS_PROP(0, ref_clk_output_gpios) + BUILD_ASSERT(DT_INST_GPIO_PIN(0, ref_clk_output_gpios) == 16 || + DT_INST_GPIO_PIN(0, ref_clk_output_gpios) == 17, + "Only GPIO16/17 are allowed as a GPIO REF_CLK source!"); + int ref_clk_gpio = DT_INST_GPIO_PIN(0, ref_clk_output_gpios); + + emac_hal_iomux_rmii_clk_output(ref_clk_gpio); + emac_ll_clock_enable_rmii_output(dev_data->hal.ext_regs); + rtc_clk_apll_enable(true, 0, 0, 6, 2); +#else emac_hal_iomux_rmii_clk_input(); emac_ll_clock_enable_rmii_input(dev_data->hal.ext_regs); +#endif } else if (strcmp(phy_connection_type, "mii") == 0) { emac_hal_iomux_init_mii(); emac_ll_clock_enable_mii(dev_data->hal.ext_regs); diff --git a/dts/bindings/ethernet/espressif,esp32-eth.yaml b/dts/bindings/ethernet/espressif,esp32-eth.yaml index f7687eb0f78..ea973265ab2 100644 --- a/dts/bindings/ethernet/espressif,esp32-eth.yaml +++ b/dts/bindings/ethernet/espressif,esp32-eth.yaml @@ -14,3 +14,8 @@ properties: phy-connection-type: default: "rmii" + + ref-clk-output-gpios: + type: phandle-array + description: | + GPIO to output RMII Clock. From 2aa7ef1d653af5befe7ecff663a60712f5796997 Mon Sep 17 00:00:00 2001 From: Andrej Butok Date: Mon, 27 Nov 2023 15:09:27 +0100 Subject: [PATCH 0474/3723] boards: mimxrt101x_evk: add boot and slot partitions Add boot_partition and slot1_partition for mimxrt1010_evk and mimxrt1015_evk. Enable MCUBoot & Flash support for them. Signed-off-by: Andrej Butok --- boards/arm/mimxrt1010_evk/mimxrt1010_evk.dts | 28 ++++++++++++++++- boards/arm/mimxrt1015_evk/mimxrt1015_evk.dts | 33 ++++++++++++++++++-- 2 files changed, 57 insertions(+), 4 deletions(-) diff --git a/boards/arm/mimxrt1010_evk/mimxrt1010_evk.dts b/boards/arm/mimxrt1010_evk/mimxrt1010_evk.dts index 71f755bacde..48070152665 100644 --- a/boards/arm/mimxrt1010_evk/mimxrt1010_evk.dts +++ b/boards/arm/mimxrt1010_evk/mimxrt1010_evk.dts @@ -1,6 +1,6 @@ /* * Copyright (c) 2023 TiaC Systems - * Copyright (c) 2019, NXP + * Copyright 2019,2023 NXP * * SPDX-License-Identifier: Apache-2.0 */ @@ -26,6 +26,8 @@ zephyr,console = &lpuart1; zephyr,shell-uart = &lpuart1; zephyr,flash = &at25sf128a; + zephyr,flash-controller = &at25sf128a; + zephyr,code-partition = &slot0_partition; }; leds { @@ -93,6 +95,30 @@ arduino_serial: &lpuart1 {}; spi-max-frequency = <133000000>; status = "okay"; jedec-id = [1f 89 01]; + erase-block-size = <4096>; + write-block-size = <1>; + + partitions { + compatible = "fixed-partitions"; + #address-cells = <1>; + #size-cells = <1>; + boot_partition: partition@0 { + label = "mcuboot"; + reg = <0x00000000 DT_SIZE_K(64)>; + }; + slot0_partition: partition@10000 { + label = "image-0"; + reg = <0x00010000 DT_SIZE_M(7)>; + }; + slot1_partition: partition@710000 { + label = "image-1"; + reg = <0x00710000 DT_SIZE_M(7)>; + }; + storage_partition: partition@E10000 { + label = "storage"; + reg = <0x00E10000 DT_SIZE_K(1984)>; + }; + }; }; }; diff --git a/boards/arm/mimxrt1015_evk/mimxrt1015_evk.dts b/boards/arm/mimxrt1015_evk/mimxrt1015_evk.dts index a3df588c9af..4f68dd0b4c8 100644 --- a/boards/arm/mimxrt1015_evk/mimxrt1015_evk.dts +++ b/boards/arm/mimxrt1015_evk/mimxrt1015_evk.dts @@ -1,5 +1,5 @@ /* - * Copyright (c) 2019, NXP + * Copyright 2019,2023 NXP * * SPDX-License-Identifier: Apache-2.0 */ @@ -20,11 +20,13 @@ }; chosen { - zephyr,sram = &dtcm; + zephyr,sram = &ocram; zephyr,itcm = &itcm; zephyr,console = &lpuart1; zephyr,shell-uart = &lpuart1; zephyr,flash = &at25sf128a; + zephyr,flash-controller = &at25sf128a; + zephyr,code-partition = &slot0_partition; }; leds { @@ -81,14 +83,39 @@ arduino_serial: &lpuart4 { }; &flexspi { + status = "okay"; reg = <0x402a8000 0x4000>, <0x60000000 DT_SIZE_M(16)>; at25sf128a: at25sf128a@0 { compatible = "nxp,imx-flexspi-nor"; - size = <134217728>; + size = ; reg = <0>; spi-max-frequency = <133000000>; status = "okay"; jedec-id = [1f 89 01]; + erase-block-size = <4096>; + write-block-size = <1>; + + partitions { + compatible = "fixed-partitions"; + #address-cells = <1>; + #size-cells = <1>; + boot_partition: partition@0 { + label = "mcuboot"; + reg = <0x00000000 DT_SIZE_K(64)>; + }; + slot0_partition: partition@10000 { + label = "image-0"; + reg = <0x00010000 DT_SIZE_M(7)>; + }; + slot1_partition: partition@710000 { + label = "image-1"; + reg = <0x00710000 DT_SIZE_M(7)>; + }; + storage_partition: partition@E10000 { + label = "storage"; + reg = <0x00E10000 DT_SIZE_K(1984)>; + }; + }; }; }; From ffcf9c59875d8d921f4bf441a27ab80d4f2e63a0 Mon Sep 17 00:00:00 2001 From: Anas Nashif Date: Mon, 27 Nov 2023 22:13:55 +0000 Subject: [PATCH 0475/3723] twister: do not add a platform to keyed tests if previously filtered If a platform is fitlered, do not add it to keyed test map, otherwise we will end up skipping all platforms from the same class without any coverage. Signed-off-by: Anas Nashif --- scripts/pylib/twister/twisterlib/testplan.py | 27 +++++++++++--------- 1 file changed, 15 insertions(+), 12 deletions(-) diff --git a/scripts/pylib/twister/twisterlib/testplan.py b/scripts/pylib/twister/twisterlib/testplan.py index 64de8864711..002180dc675 100755 --- a/scripts/pylib/twister/twisterlib/testplan.py +++ b/scripts/pylib/twister/twisterlib/testplan.py @@ -841,6 +841,17 @@ def apply_filters(self, **kwargs): instance.add_filter("Snippet not supported", Filters.PLATFORM) break + # handle quarantined tests + if self.quarantine: + matched_quarantine = self.quarantine.get_matched_quarantine( + instance.testsuite.id, plat.name, plat.arch, plat.simulation + ) + if matched_quarantine and not self.options.quarantine_verify: + instance.add_filter("Quarantine: " + matched_quarantine, Filters.QUARENTINE) + if not matched_quarantine and self.options.quarantine_verify: + instance.add_filter("Not under quarantine", Filters.QUARENTINE) + + # platform_key is a list of unique platform attributes that form a unique key a test # will match against to determine if it should be scheduled to run. A key containing a # field name that the platform does not have will filter the platform. @@ -862,22 +873,14 @@ def apply_filters(self, **kwargs): keyed_test = keyed_tests.get(test_key) if keyed_test is not None: plat_key = {key_field: getattr(keyed_test['plat'], key_field) for key_field in key_fields} - instance.add_filter(f"Excluded test already covered for key {tuple(key)} by platform {keyed_test['plat'].name} having key {plat_key}", Filters.PLATFORM_KEY) + instance.add_filter(f"Already covered for key {tuple(key)} by platform {keyed_test['plat'].name} having key {plat_key}", Filters.PLATFORM_KEY) else: - keyed_tests[test_key] = {'plat': plat, 'ts': ts} + # do not add a platform to keyed tests if previously filtered + if not instance.filters: + keyed_tests[test_key] = {'plat': plat, 'ts': ts} else: instance.add_filter(f"Excluded platform missing key fields demanded by test {key_fields}", Filters.PLATFORM) - # handle quarantined tests - if self.quarantine: - matched_quarantine = self.quarantine.get_matched_quarantine( - instance.testsuite.id, plat.name, plat.arch, plat.simulation - ) - if matched_quarantine and not self.options.quarantine_verify: - instance.add_filter("Quarantine: " + matched_quarantine, Filters.QUARENTINE) - if not matched_quarantine and self.options.quarantine_verify: - instance.add_filter("Not under quarantine", Filters.QUARENTINE) - # if nothing stopped us until now, it means this configuration # needs to be added. instance_list.append(instance) From 10ec2b129c9102a867d1ce26eb8cb986f95b6d98 Mon Sep 17 00:00:00 2001 From: Ederson de Souza Date: Mon, 27 Nov 2023 17:09:07 -0800 Subject: [PATCH 0476/3723] scripts/pylib/twister/twisterlib: Support multiple `--pytest-args` One can not even replace sucessfully pytest basic sample `pytest-args` with command line "--pytest-args", as all it does is to append a single string to current list of commands, making it impossible to send several arguments. This patch fixes that by allowing several instances of `--pytest-args` to compose the whole list of arguments to be passed to pytest. Signed-off-by: Ederson de Souza --- doc/develop/test/pytest.rst | 2 ++ .../pylib/twister/twisterlib/environment.py | 3 ++- scripts/pylib/twister/twisterlib/harness.py | 19 ++++++++++--------- .../pytest_integration/test_harness_pytest.py | 5 +++-- 4 files changed, 17 insertions(+), 12 deletions(-) diff --git a/doc/develop/test/pytest.rst b/doc/develop/test/pytest.rst index f3db6fcee89..f6ba54fa52e 100644 --- a/doc/develop/test/pytest.rst +++ b/doc/develop/test/pytest.rst @@ -67,6 +67,8 @@ For instance, one can use a command: --pytest-args='-k test_shell_print_version' +Note that ``--pytest-args`` can be passed multiple times to pass several arguments to the pytest. + Helpers & fixtures ================== diff --git a/scripts/pylib/twister/twisterlib/environment.py b/scripts/pylib/twister/twisterlib/environment.py index fcf5c436733..03ac103b894 100644 --- a/scripts/pylib/twister/twisterlib/environment.py +++ b/scripts/pylib/twister/twisterlib/environment.py @@ -216,7 +216,8 @@ def add_parse_arguments(parser = None): and 'fifo_loop' is a name of a function found in main.c without test prefix. """) - parser.add_argument("--pytest-args", + parser.add_argument( + "--pytest-args", action="append", help="""Pass additional arguments to the pytest subprocess. This parameter will override the pytest_args from the harness_config in YAML file. """) diff --git a/scripts/pylib/twister/twisterlib/harness.py b/scripts/pylib/twister/twisterlib/harness.py index dece1673c7a..8b8ad92fc51 100644 --- a/scripts/pylib/twister/twisterlib/harness.py +++ b/scripts/pylib/twister/twisterlib/harness.py @@ -326,15 +326,6 @@ def generate_command(self): command.extend([os.path.normpath(os.path.join( self.source_dir, os.path.expanduser(os.path.expandvars(src)))) for src in pytest_root]) - if handler.options.pytest_args: - command.append(handler.options.pytest_args) - if pytest_args_yaml: - logger.warning(f'The pytest_args ({handler.options.pytest_args}) specified ' - 'in the command line will override the pytest_args defined ' - f'in the YAML file {pytest_args_yaml}') - else: - command.extend(pytest_args_yaml) - if pytest_dut_scope: command.append(f'--dut-scope={pytest_dut_scope}') @@ -354,6 +345,16 @@ def generate_command(self): command.append('--device-type=custom') else: raise PytestHarnessException(f'Handling of handler {handler.type_str} not implemented yet') + + if handler.options.pytest_args: + command.extend(handler.options.pytest_args) + if pytest_args_yaml: + logger.warning(f'The pytest_args ({handler.options.pytest_args}) specified ' + 'in the command line will override the pytest_args defined ' + f'in the YAML file {pytest_args_yaml}') + else: + command.extend(pytest_args_yaml) + return command def _generate_parameters_for_hardware(self, handler: Handler): diff --git a/scripts/tests/twister/pytest_integration/test_harness_pytest.py b/scripts/tests/twister/pytest_integration/test_harness_pytest.py index fc60b99e0d1..befd384be37 100644 --- a/scripts/tests/twister/pytest_integration/test_harness_pytest.py +++ b/scripts/tests/twister/pytest_integration/test_harness_pytest.py @@ -71,12 +71,13 @@ def test_pytest_command_extra_args(testinstance: TestInstance): def test_pytest_command_extra_args_in_options(testinstance: TestInstance): pytest_harness = Pytest() pytest_args_from_yaml = '-k test_from_yaml' - pytest_args_from_cmd = '-k test_from_cmd' + pytest_args_from_cmd = ['-k', 'test_from_cmd'] testinstance.testsuite.harness_config['pytest_args'] = [pytest_args_from_yaml] testinstance.handler.options.pytest_args = pytest_args_from_cmd pytest_harness.configure(testinstance) command = pytest_harness.generate_command() - assert pytest_args_from_cmd in command + assert pytest_args_from_cmd[0] in command + assert pytest_args_from_cmd[1] in command assert pytest_args_from_yaml not in command From e6f77f9b735e67d38e8b8625fc2bdba1948e71ac Mon Sep 17 00:00:00 2001 From: Yong Cong Sin Date: Tue, 28 Nov 2023 13:04:32 +0800 Subject: [PATCH 0477/3723] driver: intc: plic: fix trigger type register bit calculation The bit position calculation for the trigger type is wrong, fix that. Signed-off-by: Yong Cong Sin --- drivers/interrupt_controller/intc_plic.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/interrupt_controller/intc_plic.c b/drivers/interrupt_controller/intc_plic.c index 434274e8c41..b8ca3234d12 100644 --- a/drivers/interrupt_controller/intc_plic.c +++ b/drivers/interrupt_controller/intc_plic.c @@ -140,7 +140,7 @@ static int riscv_plic_is_edge_irq(const struct device *dev, uint32_t local_irq) const struct plic_config *config = dev->config; mem_addr_t trig_addr = config->trig + local_irq_to_reg_offset(local_irq); - return sys_read32(trig_addr) & BIT(local_irq); + return sys_read32(trig_addr) & BIT(local_irq & PLIC_REG_MASK); } static void plic_irq_enable_set_state(uint32_t irq, bool enable) From 7388970c858b72e53d7d2b85f271d5187fae21e4 Mon Sep 17 00:00:00 2001 From: Dawid Niedzwiecki Date: Tue, 28 Nov 2023 06:46:17 +0100 Subject: [PATCH 0478/3723] serial: stm32: do not clear TC flag in async mode The Transfer Complete flag (TC) is used to check if a transfer is complete. This mechanism is used before suspending the UART module to make sure that all data are sent before the suspend procedure. The UART ISR clears this flag after completion of a async transfer which causes a hang during UART device suspend setup. There is just no need to clear this flag in ISR, it is cleared every time we start a new async transfer. Signed-off-by: Dawid Niedzwiecki --- drivers/serial/uart_stm32.c | 1 - 1 file changed, 1 deletion(-) diff --git a/drivers/serial/uart_stm32.c b/drivers/serial/uart_stm32.c index 097ba70c1b6..f2c05da357e 100644 --- a/drivers/serial/uart_stm32.c +++ b/drivers/serial/uart_stm32.c @@ -1257,7 +1257,6 @@ static void uart_stm32_isr(const struct device *dev) LL_USART_IsActiveFlag_TC(config->usart)) { LL_USART_DisableIT_TC(config->usart); - LL_USART_ClearFlag_TC(config->usart); /* Generate TX_DONE event when transmission is done */ async_evt_tx_done(data); From 55958d851f0854b28ac6602edfe42e07f0ccf4cf Mon Sep 17 00:00:00 2001 From: Jukka Rissanen Date: Tue, 28 Nov 2023 09:27:50 +0200 Subject: [PATCH 0479/3723] net: context: Refactor option getters Set separate option getters for bool, uint8_t and uint16_t values. Use those generic getters when fetching the desired option value. Noticed mixed usage (bool vs int) for txtime option. Changed the code to use int type like in other options. The uint16_t option getter gets the value from uint16_t variable but returns int value to the caller, and also expects that user supplies int value. For uint8_t value, it is expected that uint8_t value is supplied instead of int. Signed-off-by: Jukka Rissanen --- subsys/net/ip/net_context.c | 169 +++++++++++++------------------- tests/net/socket/udp/src/main.c | 4 +- 2 files changed, 69 insertions(+), 104 deletions(-) diff --git a/subsys/net/ip/net_context.c b/subsys/net/ip/net_context.c index f92cd5c0875..aa99414219c 100644 --- a/subsys/net/ip/net_context.c +++ b/subsys/net/ip/net_context.c @@ -1352,18 +1352,61 @@ int net_context_accept(struct net_context *context, return ret; } +__maybe_unused static int get_bool_option(bool option, int *value, size_t *len) +{ + if (value == NULL) { + return -EINVAL; + } -static int get_context_priority(struct net_context *context, - void *value, size_t *len) + if (len != NULL) { + if (*len != sizeof(int)) { + return -EINVAL; + } + + *len = sizeof(int); + } + + *((int *)value) = (int)option; + + return 0; +} + +__maybe_unused static int get_uint8_option(uint8_t option, uint8_t *value, size_t *len) { -#if defined(CONFIG_NET_CONTEXT_PRIORITY) - *((uint8_t *)value) = context->options.priority; + if (value == NULL) { + return -EINVAL; + } - if (len) { + *value = option; + + if (len != NULL) { *len = sizeof(uint8_t); } return 0; +} + +__maybe_unused static int get_uint16_option(uint16_t option, int *value, size_t *len) +{ + if (value == NULL) { + return -EINVAL; + } + + *value = option; + + if (len != NULL) { + *len = sizeof(int); + } + + return 0; +} + +static int get_context_priority(struct net_context *context, + void *value, size_t *len) +{ +#if defined(CONFIG_NET_CONTEXT_PRIORITY) + return get_uint8_option(context->options.priority, + value, len); #else return -ENOTSUP; #endif @@ -1397,13 +1440,8 @@ static int get_context_txtime(struct net_context *context, void *value, size_t *len) { #if defined(CONFIG_NET_CONTEXT_TXTIME) - *((bool *)value) = context->options.txtime; - - if (len) { - *len = sizeof(bool); - } - - return 0; + return get_bool_option(context->options.txtime, + value, len); #else return -ENOTSUP; #endif @@ -1445,12 +1483,8 @@ static int get_context_rcvbuf(struct net_context *context, void *value, size_t *len) { #if defined(CONFIG_NET_CONTEXT_RCVBUF) - *((int *)value) = context->options.rcvbuf; - - if (len) { - *len = sizeof(int); - } - return 0; + return get_uint16_option(context->options.rcvbuf, + value, len); #else return -ENOTSUP; #endif @@ -1460,12 +1494,8 @@ static int get_context_sndbuf(struct net_context *context, void *value, size_t *len) { #if defined(CONFIG_NET_CONTEXT_SNDBUF) - *((int *)value) = context->options.sndbuf; - - if (len) { - *len = sizeof(int); - } - return 0; + return get_uint16_option(context->options.sndbuf, + value, len); #else return -ENOTSUP; #endif @@ -1475,13 +1505,8 @@ static int get_context_dscp_ecn(struct net_context *context, void *value, size_t *len) { #if defined(CONFIG_NET_CONTEXT_DSCP_ECN) - *((int *)value) = context->options.dscp_ecn; - - if (len) { - *len = sizeof(int); - } - - return 0; + return get_uint8_option(context->options.dscp_ecn, + value, len); #else return -ENOTSUP; #endif @@ -1491,23 +1516,8 @@ static int get_context_reuseaddr(struct net_context *context, void *value, size_t *len) { #if defined(CONFIG_NET_CONTEXT_REUSEADDR) - if (!value || !len) { - return -EINVAL; - } - - if (*len != sizeof(int)) { - return -EINVAL; - } - - if (context->options.reuseaddr == true) { - *((int *)value) = (int) true; - } else { - *((int *)value) = (int) false; - } - - *len = sizeof(int); - - return 0; + return get_bool_option(context->options.reuseaddr, + value, len); #else return -ENOTSUP; #endif @@ -1517,23 +1527,8 @@ static int get_context_reuseport(struct net_context *context, void *value, size_t *len) { #if defined(CONFIG_NET_CONTEXT_REUSEPORT) - if (!value || !len) { - return -EINVAL; - } - - if (*len != sizeof(int)) { - return -EINVAL; - } - - if (context->options.reuseport == true) { - *((int *)value) = (int) true; - } else { - *((int *)value) = (int) false; - } - - *len = sizeof(int); - - return 0; + return get_bool_option(context->options.reuseport, + value, len); #else return -ENOTSUP; #endif @@ -1543,23 +1538,8 @@ static int get_context_ipv6_v6only(struct net_context *context, void *value, size_t *len) { #if defined(CONFIG_NET_IPV4_MAPPING_TO_IPV6) - if (!value || !len) { - return -EINVAL; - } - - if (*len != sizeof(int)) { - return -EINVAL; - } - - if (context->options.ipv6_v6only == true) { - *((int *)value) = (int) true; - } else { - *((int *)value) = (int) false; - } - - *len = sizeof(int); - - return 0; + return get_bool_option(context->options.ipv6_v6only, + value, len); #else ARG_UNUSED(context); ARG_UNUSED(value); @@ -1573,23 +1553,8 @@ static int get_context_recv_pktinfo(struct net_context *context, void *value, size_t *len) { #if defined(CONFIG_NET_CONTEXT_RECV_PKTINFO) - if (!value || !len) { - return -EINVAL; - } - - if (*len != sizeof(int)) { - return -EINVAL; - } - - if (context->options.recv_pktinfo == true) { - *((int *)value) = (int) true; - } else { - *((int *)value) = (int) false; - } - - *len = sizeof(int); - - return 0; + return get_bool_option(context->options.recv_pktinfo, + value, len); #else ARG_UNUSED(context); ARG_UNUSED(value); @@ -2028,7 +1993,7 @@ static int context_sendto(struct net_context *context, */ if (msghdr && msghdr->msg_control && msghdr->msg_controllen) { if (IS_ENABLED(CONFIG_NET_CONTEXT_TXTIME)) { - bool is_txtime; + int is_txtime; get_context_txtime(context, &is_txtime, NULL); if (is_txtime) { @@ -2536,11 +2501,11 @@ static int set_context_txtime(struct net_context *context, const void *value, size_t len) { #if defined(CONFIG_NET_CONTEXT_TXTIME) - if (len > sizeof(bool)) { + if (len != sizeof(int)) { return -EINVAL; } - context->options.txtime = *((bool *)value); + context->options.txtime = !!*((int *)value); return 0; #else diff --git a/tests/net/socket/udp/src/main.c b/tests/net/socket/udp/src/main.c index 48162d634b2..f220c1bfca8 100644 --- a/tests/net/socket/udp/src/main.c +++ b/tests/net/socket/udp/src/main.c @@ -731,7 +731,7 @@ ZTEST(net_socket_udp, test_08_so_txtime) struct sockaddr_in6 bind_addr6; int sock1, sock2, rv; socklen_t optlen; - bool optval; + int optval; prepare_sock_udp_v4(MY_IPV4_ADDR, 55555, &sock1, &bind_addr4); prepare_sock_udp_v6(MY_IPV6_ADDR, 55555, &sock2, &bind_addr6); @@ -1039,7 +1039,7 @@ ZTEST_USER(net_socket_udp, test_18_v6_sendmsg_with_txtime) { int rv; int client_sock; - bool optval; + int optval; net_time_t txtime; struct sockaddr_in6 client_addr; struct msghdr msg; From 77e522a5a243717bee869a5a932e91873ee03281 Mon Sep 17 00:00:00 2001 From: Jukka Rissanen Date: Tue, 28 Nov 2023 10:04:10 +0200 Subject: [PATCH 0480/3723] net: context: Refactor option setters Set separate option setters for bool, uint8_t and uint16_t values. Use those generic setters when storing the desired option value. The uint16_t option setter stores the value to uint16_t variable and expects that user supplies int value. For uint8_t value, it is expected that uint8_t value is supplied instead of int. Signed-off-by: Jukka Rissanen --- subsys/net/ip/net_context.c | 161 ++++++++++++++---------------------- 1 file changed, 60 insertions(+), 101 deletions(-) diff --git a/subsys/net/ip/net_context.c b/subsys/net/ip/net_context.c index aa99414219c..6ea1a4cd2af 100644 --- a/subsys/net/ip/net_context.c +++ b/subsys/net/ip/net_context.c @@ -2481,33 +2481,75 @@ int net_context_update_recv_wnd(struct net_context *context, return ret; } -static int set_context_priority(struct net_context *context, - const void *value, size_t len) +__maybe_unused static int set_bool_option(bool *option, const void *value, size_t len) { -#if defined(CONFIG_NET_CONTEXT_PRIORITY) + if (value == NULL) { + return -EINVAL; + } + + if (len != sizeof(int)) { + return -EINVAL; + } + + *option = !!*((int *)value); + + return 0; +} + +__maybe_unused static int set_uint8_option(uint8_t *option, const void *value, size_t len) +{ + if (value == NULL) { + return -EINVAL; + } + if (len > sizeof(uint8_t)) { return -EINVAL; } - context->options.priority = *((uint8_t *)value); + *option = *((uint8_t *)value); return 0; -#else - return -ENOTSUP; -#endif } -static int set_context_txtime(struct net_context *context, - const void *value, size_t len) +__maybe_unused static int set_uint16_option(uint16_t *option, const void *value, size_t len) { -#if defined(CONFIG_NET_CONTEXT_TXTIME) + int v; + + if (value == NULL) { + return -EINVAL; + } + if (len != sizeof(int)) { return -EINVAL; } - context->options.txtime = !!*((int *)value); + v = *((int *)value); + + if (v < 0 || v > UINT16_MAX) { + return -EINVAL; + } + + *option = (uint16_t)v; return 0; + +} + +static int set_context_priority(struct net_context *context, + const void *value, size_t len) +{ +#if defined(CONFIG_NET_CONTEXT_PRIORITY) + return set_uint8_option(&context->options.priority, value, len); +#else + return -ENOTSUP; +#endif +} + +static int set_context_txtime(struct net_context *context, + const void *value, size_t len) +{ +#if defined(CONFIG_NET_CONTEXT_TXTIME) + return set_bool_option(&context->options.txtime, value, len); #else return -ENOTSUP; #endif @@ -2572,19 +2614,7 @@ static int set_context_rcvbuf(struct net_context *context, const void *value, size_t len) { #if defined(CONFIG_NET_CONTEXT_RCVBUF) - int rcvbuf_value = *((int *)value); - - if (len != sizeof(int)) { - return -EINVAL; - } - - if ((rcvbuf_value < 0) || (rcvbuf_value > UINT16_MAX)) { - return -EINVAL; - } - - context->options.rcvbuf = (uint16_t) rcvbuf_value; - - return 0; + return set_uint16_option(&context->options.rcvbuf, value, len); #else return -ENOTSUP; #endif @@ -2594,18 +2624,7 @@ static int set_context_sndbuf(struct net_context *context, const void *value, size_t len) { #if defined(CONFIG_NET_CONTEXT_SNDBUF) - int sndbuf_value = *((int *)value); - - if (len != sizeof(int)) { - return -EINVAL; - } - - if ((sndbuf_value < 0) || (sndbuf_value > UINT16_MAX)) { - return -EINVAL; - } - - context->options.sndbuf = (uint16_t) sndbuf_value; - return 0; + return set_uint16_option(&context->options.sndbuf, value, len); #else return -ENOTSUP; #endif @@ -2615,19 +2634,7 @@ static int set_context_dscp_ecn(struct net_context *context, const void *value, size_t len) { #if defined(CONFIG_NET_CONTEXT_DSCP_ECN) - int dscp_ecn = *((int *)value); - - if (len != sizeof(int)) { - return -EINVAL; - } - - if ((dscp_ecn < 0) || (dscp_ecn > UINT8_MAX)) { - return -EINVAL; - } - - context->options.dscp_ecn = (uint8_t)dscp_ecn; - - return 0; + return set_uint8_option(&context->options.dscp_ecn, value, len); #else return -ENOTSUP; #endif @@ -2637,19 +2644,7 @@ static int set_context_reuseaddr(struct net_context *context, const void *value, size_t len) { #if defined(CONFIG_NET_CONTEXT_REUSEADDR) - bool reuseaddr = false; - - if (len != sizeof(int)) { - return -EINVAL; - } - - if (*((int *) value) != 0) { - reuseaddr = true; - } - - context->options.reuseaddr = reuseaddr; - - return 0; + return set_bool_option(&context->options.reuseaddr, value, len); #else return -ENOTSUP; #endif @@ -2659,19 +2654,7 @@ static int set_context_reuseport(struct net_context *context, const void *value, size_t len) { #if defined(CONFIG_NET_CONTEXT_REUSEPORT) - bool reuseport = false; - - if (len != sizeof(int)) { - return -EINVAL; - } - - if (*((int *) value) != 0) { - reuseport = true; - } - - context->options.reuseport = reuseport; - - return 0; + return set_bool_option(&context->options.reuseport, value, len); #else return -ENOTSUP; #endif @@ -2681,19 +2664,7 @@ static int set_context_ipv6_v6only(struct net_context *context, const void *value, size_t len) { #if defined(CONFIG_NET_IPV4_MAPPING_TO_IPV6) - bool v6only = false; - - if (len != sizeof(int)) { - return -EINVAL; - } - - if (*((int *) value) != 0) { - v6only = true; - } - - context->options.ipv6_v6only = v6only; - - return 0; + return set_bool_option(&context->options.ipv6_v6only, value, len); #else ARG_UNUSED(context); ARG_UNUSED(value); @@ -2707,19 +2678,7 @@ static int set_context_recv_pktinfo(struct net_context *context, const void *value, size_t len) { #if defined(CONFIG_NET_CONTEXT_RECV_PKTINFO) - bool pktinfo = false; - - if (len != sizeof(int)) { - return -EINVAL; - } - - if (*((int *) value) != 0) { - pktinfo = true; - } - - context->options.recv_pktinfo = pktinfo; - - return 0; + return set_bool_option(&context->options.recv_pktinfo, value, len); #else ARG_UNUSED(context); ARG_UNUSED(value); From 1f1712a89f0484e7b4fa16591194d1a112457a0d Mon Sep 17 00:00:00 2001 From: Jukka Rissanen Date: Tue, 28 Nov 2023 09:35:35 +0200 Subject: [PATCH 0481/3723] net: context: Add ARG_UNUSED to relevant places in opt handling If some specific option is not enabled, then add missing ARG_UNUSED() calls in relevant functions. Signed-off-by: Jukka Rissanen --- subsys/net/ip/net_context.c | 80 +++++++++++++++++++++++++++++++++++++ 1 file changed, 80 insertions(+) diff --git a/subsys/net/ip/net_context.c b/subsys/net/ip/net_context.c index 6ea1a4cd2af..6c2258fcd90 100644 --- a/subsys/net/ip/net_context.c +++ b/subsys/net/ip/net_context.c @@ -1408,6 +1408,10 @@ static int get_context_priority(struct net_context *context, return get_uint8_option(context->options.priority, value, len); #else + ARG_UNUSED(context); + ARG_UNUSED(value); + ARG_UNUSED(len); + return -ENOTSUP; #endif } @@ -1432,6 +1436,10 @@ static int get_context_proxy(struct net_context *context, return 0; #else + ARG_UNUSED(context); + ARG_UNUSED(value); + ARG_UNUSED(len); + return -ENOTSUP; #endif } @@ -1443,6 +1451,10 @@ static int get_context_txtime(struct net_context *context, return get_bool_option(context->options.txtime, value, len); #else + ARG_UNUSED(context); + ARG_UNUSED(value); + ARG_UNUSED(len); + return -ENOTSUP; #endif } @@ -1459,6 +1471,10 @@ static int get_context_rcvtimeo(struct net_context *context, return 0; #else + ARG_UNUSED(context); + ARG_UNUSED(value); + ARG_UNUSED(len); + return -ENOTSUP; #endif } @@ -1475,6 +1491,10 @@ static int get_context_sndtimeo(struct net_context *context, return 0; #else + ARG_UNUSED(context); + ARG_UNUSED(value); + ARG_UNUSED(len); + return -ENOTSUP; #endif } @@ -1486,6 +1506,10 @@ static int get_context_rcvbuf(struct net_context *context, return get_uint16_option(context->options.rcvbuf, value, len); #else + ARG_UNUSED(context); + ARG_UNUSED(value); + ARG_UNUSED(len); + return -ENOTSUP; #endif } @@ -1497,6 +1521,10 @@ static int get_context_sndbuf(struct net_context *context, return get_uint16_option(context->options.sndbuf, value, len); #else + ARG_UNUSED(context); + ARG_UNUSED(value); + ARG_UNUSED(len); + return -ENOTSUP; #endif } @@ -1508,6 +1536,10 @@ static int get_context_dscp_ecn(struct net_context *context, return get_uint8_option(context->options.dscp_ecn, value, len); #else + ARG_UNUSED(context); + ARG_UNUSED(value); + ARG_UNUSED(len); + return -ENOTSUP; #endif } @@ -1519,6 +1551,10 @@ static int get_context_reuseaddr(struct net_context *context, return get_bool_option(context->options.reuseaddr, value, len); #else + ARG_UNUSED(context); + ARG_UNUSED(value); + ARG_UNUSED(len); + return -ENOTSUP; #endif } @@ -1530,6 +1566,10 @@ static int get_context_reuseport(struct net_context *context, return get_bool_option(context->options.reuseport, value, len); #else + ARG_UNUSED(context); + ARG_UNUSED(value); + ARG_UNUSED(len); + return -ENOTSUP; #endif } @@ -2541,6 +2581,10 @@ static int set_context_priority(struct net_context *context, #if defined(CONFIG_NET_CONTEXT_PRIORITY) return set_uint8_option(&context->options.priority, value, len); #else + ARG_UNUSED(context); + ARG_UNUSED(value); + ARG_UNUSED(len); + return -ENOTSUP; #endif } @@ -2551,6 +2595,10 @@ static int set_context_txtime(struct net_context *context, #if defined(CONFIG_NET_CONTEXT_TXTIME) return set_bool_option(&context->options.txtime, value, len); #else + ARG_UNUSED(context); + ARG_UNUSED(value); + ARG_UNUSED(len); + return -ENOTSUP; #endif } @@ -2574,6 +2622,10 @@ static int set_context_proxy(struct net_context *context, return 0; #else + ARG_UNUSED(context); + ARG_UNUSED(value); + ARG_UNUSED(len); + return -ENOTSUP; #endif } @@ -2590,6 +2642,10 @@ static int set_context_rcvtimeo(struct net_context *context, return 0; #else + ARG_UNUSED(context); + ARG_UNUSED(value); + ARG_UNUSED(len); + return -ENOTSUP; #endif } @@ -2606,6 +2662,10 @@ static int set_context_sndtimeo(struct net_context *context, return 0; #else + ARG_UNUSED(context); + ARG_UNUSED(value); + ARG_UNUSED(len); + return -ENOTSUP; #endif } @@ -2616,6 +2676,10 @@ static int set_context_rcvbuf(struct net_context *context, #if defined(CONFIG_NET_CONTEXT_RCVBUF) return set_uint16_option(&context->options.rcvbuf, value, len); #else + ARG_UNUSED(context); + ARG_UNUSED(value); + ARG_UNUSED(len); + return -ENOTSUP; #endif } @@ -2626,6 +2690,10 @@ static int set_context_sndbuf(struct net_context *context, #if defined(CONFIG_NET_CONTEXT_SNDBUF) return set_uint16_option(&context->options.sndbuf, value, len); #else + ARG_UNUSED(context); + ARG_UNUSED(value); + ARG_UNUSED(len); + return -ENOTSUP; #endif } @@ -2636,6 +2704,10 @@ static int set_context_dscp_ecn(struct net_context *context, #if defined(CONFIG_NET_CONTEXT_DSCP_ECN) return set_uint8_option(&context->options.dscp_ecn, value, len); #else + ARG_UNUSED(context); + ARG_UNUSED(value); + ARG_UNUSED(len); + return -ENOTSUP; #endif } @@ -2646,6 +2718,10 @@ static int set_context_reuseaddr(struct net_context *context, #if defined(CONFIG_NET_CONTEXT_REUSEADDR) return set_bool_option(&context->options.reuseaddr, value, len); #else + ARG_UNUSED(context); + ARG_UNUSED(value); + ARG_UNUSED(len); + return -ENOTSUP; #endif } @@ -2656,6 +2732,10 @@ static int set_context_reuseport(struct net_context *context, #if defined(CONFIG_NET_CONTEXT_REUSEPORT) return set_bool_option(&context->options.reuseport, value, len); #else + ARG_UNUSED(context); + ARG_UNUSED(value); + ARG_UNUSED(len); + return -ENOTSUP; #endif } From e504ab521716b61645154b2d8561928dd1cffb99 Mon Sep 17 00:00:00 2001 From: Eduardo Montoya Date: Tue, 28 Nov 2023 09:12:31 +0100 Subject: [PATCH 0482/3723] net: openthread: add Link Metrics noise floor initialization It was missing. Signed-off-by: Eduardo Montoya --- modules/openthread/platform/radio.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/modules/openthread/platform/radio.c b/modules/openthread/platform/radio.c index 98eab182aad..62b26ae1076 100644 --- a/modules/openthread/platform/radio.c +++ b/modules/openthread/platform/radio.c @@ -361,6 +361,10 @@ void platformRadioInit(void) cfg.event_handler = handle_radio_event; radio_api->configure(radio_dev, IEEE802154_CONFIG_EVENT_HANDLER, &cfg); + +#if defined(CONFIG_OPENTHREAD_LINK_METRICS_SUBJECT) + otLinkMetricsInit(otPlatRadioGetReceiveSensitivity()); +#endif } void transmit_message(struct k_work *tx_job) From 75f7ffb2c925fa183c4e29a90a5654c48e630785 Mon Sep 17 00:00:00 2001 From: Dawid Niedzwiecki Date: Tue, 28 Nov 2023 13:09:27 +0100 Subject: [PATCH 0483/3723] Revert "timer: cortex_m_systick: handle cycle count overflow with idle timer" This reverts commit 2ae09993cae8a8892d0f586877c8ce1e65f50387. Signed-off-by: Dawid Niedzwiecki --- drivers/timer/cortex_m_systick.c | 15 ++------------- 1 file changed, 2 insertions(+), 13 deletions(-) diff --git a/drivers/timer/cortex_m_systick.c b/drivers/timer/cortex_m_systick.c index abd60f5ad7a..b5f859ae57c 100644 --- a/drivers/timer/cortex_m_systick.c +++ b/drivers/timer/cortex_m_systick.c @@ -366,13 +366,13 @@ void sys_clock_idle_exit(void) { #ifdef CONFIG_CORTEX_M_SYSTICK_IDLE_TIMER if (timeout_idle) { - cycle_t cycle_post_idle, systick_diff, missed_cycles; + cycle_t systick_diff, missed_cycles; uint32_t idle_timer_diff, idle_timer_post, dcycles, dticks; uint64_t systick_us, idle_timer_us; /* Get current values for both timers */ counter_get_value(idle_timer, &idle_timer_post); - cycle_post_idle = cycle_count + elapsed(); + systick_diff = cycle_count + elapsed() - cycle_pre_idle; /* Calculate has much time has pasted since last measurement for both timers */ /* Check IDLE timer overflow */ @@ -385,17 +385,6 @@ void sys_clock_idle_exit(void) idle_timer_diff = idle_timer_post - idle_timer_pre_idle; } idle_timer_us = counter_ticks_to_us(idle_timer, idle_timer_diff); - -#ifndef CONFIG_CORTEX_M_SYSTICK_64BIT_CYCLE_COUNTER - /* Check cycle counter overflow when using uint32_t */ - if (cycle_pre_idle > cycle_post_idle) { - systick_diff = (UINT32_MAX - cycle_pre_idle) + cycle_post_idle + 1; - } else { - systick_diff = cycle_post_idle - cycle_pre_idle; - } -#else - systick_diff = cycle_post_idle - cycle_pre_idle; -#endif /* !CONFIG_CORTEX_M_SYSTICK_64BIT_CYCLE_COUNTER */ systick_us = ((uint64_t)systick_diff * USEC_PER_SEC) / sys_clock_hw_cycles_per_sec(); From 72f7a05a8b51524960a3ea5b7114249b10e715ba Mon Sep 17 00:00:00 2001 From: Andreas Chmielewski Date: Thu, 26 Jan 2023 14:25:46 +0100 Subject: [PATCH 0484/3723] tests: lwm2m_rd_client: Added more fff tests If the rdclient is suspended or deregistered any network errors caused by lwm2m_engine and forwarded by socket_fault handler should not change the rd client state. Signed-off-by: Andreas Chmielewski Signed-off-by: Seppo Takalo --- .../net/lib/lwm2m/lwm2m_rd_client/src/main.c | 70 +++++++++++++++++++ .../net/lib/lwm2m/lwm2m_rd_client/src/stubs.c | 14 ++++ .../net/lib/lwm2m/lwm2m_rd_client/src/stubs.h | 3 + 3 files changed, 87 insertions(+) diff --git a/tests/net/lib/lwm2m/lwm2m_rd_client/src/main.c b/tests/net/lib/lwm2m/lwm2m_rd_client/src/main.c index 931f6f15904..208298512d4 100644 --- a/tests/net/lib/lwm2m/lwm2m_rd_client/src/main.c +++ b/tests/net/lib/lwm2m/lwm2m_rd_client/src/main.c @@ -698,3 +698,73 @@ ZTEST(lwm2m_rd_client, test_bootstrap_no_srv_fallback_to_register) zassert_true(expect_lwm2m_rd_client_event(LWM2M_RD_CLIENT_EVENT_REGISTRATION_COMPLETE), NULL); } + +ZTEST(lwm2m_rd_client, test_start_stop_ignore_engine_fault) +{ + struct lwm2m_ctx ctx; + + (void)memset(&ctx, 0x0, sizeof(ctx)); + + test_prepare_pending_message_cb(&message_reply_cb_default); + + lwm2m_rd_client_init(); + test_lwm2m_engine_start_service(); + wait_for_service(1); + + lwm2m_engine_context_init_fake.custom_fake = lwm2m_engine_context_init_fake1; + lwm2m_get_bool_fake.custom_fake = lwm2m_get_bool_fake_default; + lwm2m_sprint_ip_addr_fake.custom_fake = lwm2m_sprint_ip_addr_fake_default; + lwm2m_init_message_fake.custom_fake = lwm2m_init_message_fake_default; + coap_header_get_code_fake.custom_fake = coap_header_get_code_fake_created; + coap_find_options_fake.custom_fake = coap_find_options_do_registration_reply_cb_ok; + zassert_true(lwm2m_rd_client_start(&ctx, "Test", 0, lwm2m_event_cb, lwm2m_observe_cb) == 0, + NULL); + zassert_true(expect_lwm2m_rd_client_event(LWM2M_RD_CLIENT_EVENT_REGISTRATION_COMPLETE), + NULL); + + coap_header_get_code_fake.custom_fake = coap_header_get_code_fake_deleted; + zassert_true(lwm2m_rd_client_stop(&ctx, lwm2m_event_cb, true) == 0, NULL); + zassert_true(expect_lwm2m_rd_client_event(LWM2M_RD_CLIENT_EVENT_DISCONNECT), NULL); + + int c = show_lwm2m_event_fake.call_count; + + test_throw_network_error_from_engine(EIO); + wait_for_service(10); + zassert_equal(show_lwm2m_event_fake.call_count, c, + "Should not enter any other state and throw an event"); +} + +ZTEST(lwm2m_rd_client, test_start_suspend_ignore_engine_fault) +{ + struct lwm2m_ctx ctx; + + (void)memset(&ctx, 0x0, sizeof(ctx)); + + test_prepare_pending_message_cb(&message_reply_cb_default); + + lwm2m_rd_client_init(); + test_lwm2m_engine_start_service(); + wait_for_service(1); + + lwm2m_engine_context_init_fake.custom_fake = lwm2m_engine_context_init_fake1; + lwm2m_get_bool_fake.custom_fake = lwm2m_get_bool_fake_default; + lwm2m_sprint_ip_addr_fake.custom_fake = lwm2m_sprint_ip_addr_fake_default; + lwm2m_init_message_fake.custom_fake = lwm2m_init_message_fake_default; + coap_header_get_code_fake.custom_fake = coap_header_get_code_fake_created; + coap_find_options_fake.custom_fake = coap_find_options_do_registration_reply_cb_ok; + zassert_true(lwm2m_rd_client_start(&ctx, "Test", 0, lwm2m_event_cb, lwm2m_observe_cb) == 0, + NULL); + zassert_true(expect_lwm2m_rd_client_event(LWM2M_RD_CLIENT_EVENT_REGISTRATION_COMPLETE), + NULL); + + coap_header_get_code_fake.custom_fake = coap_header_get_code_fake_deleted; + zassert_true(lwm2m_rd_client_pause() == 0, NULL); + zassert_true(expect_lwm2m_rd_client_event(LWM2M_RD_CLIENT_EVENT_ENGINE_SUSPENDED), NULL); + + int c = show_lwm2m_event_fake.call_count; + + test_throw_network_error_from_engine(EIO); + wait_for_service(10); + zassert_equal(show_lwm2m_event_fake.call_count, c, + "Should not enter any other state and throw an event"); +} diff --git a/tests/net/lib/lwm2m/lwm2m_rd_client/src/stubs.c b/tests/net/lib/lwm2m/lwm2m_rd_client/src/stubs.c index 41789e20340..3cbde9060ce 100644 --- a/tests/net/lib/lwm2m/lwm2m_rd_client/src/stubs.c +++ b/tests/net/lib/lwm2m/lwm2m_rd_client/src/stubs.c @@ -86,6 +86,10 @@ int lwm2m_get_u32_val(const struct lwm2m_obj_path *path, uint32_t *val) /* subsys/net/lib/lwm2m/lwm2m_engine.h */ DEFINE_FAKE_VALUE_FUNC(int, lwm2m_socket_start, struct lwm2m_ctx *); +int lwm2m_socket_start_fake_fail(struct lwm2m_ctx *client_ctx) +{ + return -1; +} DEFINE_FAKE_VALUE_FUNC(int, lwm2m_socket_close, struct lwm2m_ctx *); DEFINE_FAKE_VALUE_FUNC(int, lwm2m_close_socket, struct lwm2m_ctx *); DEFINE_FAKE_VALUE_FUNC(int, lwm2m_socket_suspend, struct lwm2m_ctx *); @@ -93,6 +97,16 @@ DEFINE_FAKE_VALUE_FUNC(int, lwm2m_security_inst_id_to_index, uint16_t); DEFINE_FAKE_VALUE_FUNC(int, lwm2m_engine_connection_resume, struct lwm2m_ctx *); DEFINE_FAKE_VALUE_FUNC(int, lwm2m_push_queued_buffers, struct lwm2m_ctx *); DEFINE_FAKE_VOID_FUNC(lwm2m_engine_context_init, struct lwm2m_ctx *); +struct lwm2m_ctx *client_ctx_fake; +void lwm2m_engine_context_init_fake1(struct lwm2m_ctx *client_ctx) +{ + client_ctx_fake = client_ctx; +} +void test_throw_network_error_from_engine(int err) +{ + client_ctx_fake->fault_cb(err); +} + DEFINE_FAKE_VOID_FUNC(lwm2m_engine_context_close, struct lwm2m_ctx *); DEFINE_FAKE_VALUE_FUNC(char *, lwm2m_sprint_ip_addr, const struct sockaddr *); char *lwm2m_sprint_ip_addr_fake_default(const struct sockaddr *addr) diff --git a/tests/net/lib/lwm2m/lwm2m_rd_client/src/stubs.h b/tests/net/lib/lwm2m/lwm2m_rd_client/src/stubs.h index 620e4d8fc12..1276dd5c109 100644 --- a/tests/net/lib/lwm2m/lwm2m_rd_client/src/stubs.h +++ b/tests/net/lib/lwm2m/lwm2m_rd_client/src/stubs.h @@ -54,6 +54,7 @@ int lwm2m_get_u32_val(const struct lwm2m_obj_path *path, uint32_t *val); /* subsys/net/lib/lwm2m/lwm2m_engine.h */ DECLARE_FAKE_VALUE_FUNC(int, lwm2m_socket_start, struct lwm2m_ctx *); +int lwm2m_socket_start_fake_fail(struct lwm2m_ctx *client_ctx); DECLARE_FAKE_VALUE_FUNC(int, lwm2m_socket_close, struct lwm2m_ctx *); DECLARE_FAKE_VALUE_FUNC(int, lwm2m_close_socket, struct lwm2m_ctx *); DECLARE_FAKE_VALUE_FUNC(int, lwm2m_socket_suspend, struct lwm2m_ctx *); @@ -61,6 +62,8 @@ DECLARE_FAKE_VALUE_FUNC(int, lwm2m_security_inst_id_to_index, uint16_t); DECLARE_FAKE_VALUE_FUNC(int, lwm2m_engine_connection_resume, struct lwm2m_ctx *); DECLARE_FAKE_VALUE_FUNC(int, lwm2m_push_queued_buffers, struct lwm2m_ctx *); DECLARE_FAKE_VOID_FUNC(lwm2m_engine_context_init, struct lwm2m_ctx *); +void lwm2m_engine_context_init_fake1(struct lwm2m_ctx *client_ctx); +void test_throw_network_error_from_engine(int err); DECLARE_FAKE_VOID_FUNC(lwm2m_engine_context_close, struct lwm2m_ctx *); DECLARE_FAKE_VALUE_FUNC(char *, lwm2m_sprint_ip_addr, const struct sockaddr *); char *lwm2m_sprint_ip_addr_fake_default(const struct sockaddr *addr); From 01760ab2f5fa4edf7fbf8d22c881cce48d1c9558 Mon Sep 17 00:00:00 2001 From: Henrik Brix Andersen Date: Tue, 28 Nov 2023 11:20:19 +0100 Subject: [PATCH 0485/3723] bluetooth: audio: cap: remove stray list item bullets Remove stray list item bullets as they confuse Doxygen. Also fix wrong Doxygen comment block intro. Signed-off-by: Henrik Brix Andersen --- include/zephyr/bluetooth/audio/cap.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/include/zephyr/bluetooth/audio/cap.h b/include/zephyr/bluetooth/audio/cap.h index 06da5700506..06b148ce461 100644 --- a/include/zephyr/bluetooth/audio/cap.h +++ b/include/zephyr/bluetooth/audio/cap.h @@ -427,7 +427,7 @@ struct bt_cap_initiator_broadcast_create_param { * @brief Create a Common Audio Profile broadcast source. * * Create a new audio broadcast source with one or more audio streams. - * * * + * * @note @kconfig{CONFIG_BT_CAP_INITIATOR} and * @kconfig{CONFIG_BT_BAP_BROADCAST_SOURCE} must be enabled for this function * to be enabled. @@ -493,7 +493,7 @@ int bt_cap_initiator_broadcast_audio_update(struct bt_cap_broadcast_source *broa */ int bt_cap_initiator_broadcast_audio_stop(struct bt_cap_broadcast_source *broadcast_source); -/* +/** * @brief Delete Common Audio Profile broadcast source * * This can only be done after the broadcast source has been stopped by calling From 53d8c71ed39cbe5e78c1e5aa079259fbee59822a Mon Sep 17 00:00:00 2001 From: Henrik Brix Andersen Date: Tue, 28 Nov 2023 11:21:50 +0100 Subject: [PATCH 0486/3723] drivers: interrupt_controller: esp32: use backticks for code identifiers Use double backticks for code identifiers as the wildcards confuse Doxygen. Signed-off-by: Henrik Brix Andersen --- include/zephyr/drivers/interrupt_controller/intc_esp32.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/include/zephyr/drivers/interrupt_controller/intc_esp32.h b/include/zephyr/drivers/interrupt_controller/intc_esp32.h index 6c489723d7e..c1e86068ad3 100644 --- a/include/zephyr/drivers/interrupt_controller/intc_esp32.h +++ b/include/zephyr/drivers/interrupt_controller/intc_esp32.h @@ -249,7 +249,7 @@ int esp_intr_get_intno(struct intr_handle_data_t *handle); * @brief Disable the interrupt associated with the handle * * @note - * 1. For local interrupts (ESP_INTERNAL_* sources), this function has to be called on the + * 1. For local interrupts (``ESP_INTERNAL_*`` sources), this function has to be called on the * CPU the interrupt is allocated on. Other interrupts have no such restriction. * 2. When several handlers sharing a same interrupt source, interrupt status bits, which are * handled in the handler to be disabled, should be masked before the disabling, or handled @@ -266,7 +266,7 @@ int esp_intr_disable(struct intr_handle_data_t *handle); /** * @brief Enable the interrupt associated with the handle * - * @note For local interrupts (ESP_INTERNAL_* sources), this function has to be called on the + * @note For local interrupts (``ESP_INTERNAL_*`` sources), this function has to be called on the * CPU the interrupt is allocated on. Other interrupts have no such restriction. * * @param handle The handle, as obtained by esp_intr_alloc or esp_intr_alloc_intrstatus From bc011c39ea1e992f4334085268f3fcdd7ee0005e Mon Sep 17 00:00:00 2001 From: Henrik Brix Andersen Date: Tue, 28 Nov 2023 11:28:40 +0100 Subject: [PATCH 0487/3723] drivers: rtc: ds3231: use backticks for code identifiers Use double backticks for code identifiers as the wildcards confuse Doxygen. Signed-off-by: Henrik Brix Andersen --- include/zephyr/drivers/rtc/maxim_ds3231.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/include/zephyr/drivers/rtc/maxim_ds3231.h b/include/zephyr/drivers/rtc/maxim_ds3231.h index 6e9a4a1cb39..2e8b9fe60ec 100644 --- a/include/zephyr/drivers/rtc/maxim_ds3231.h +++ b/include/zephyr/drivers/rtc/maxim_ds3231.h @@ -15,7 +15,7 @@ * * The core Zephyr API to this device is as a counter, with the * following limitations: - * * counter_read() and counter_*_alarm() cannot be invoked from + * * ``counter_read()`` and ``counter_*_alarm()`` cannot be invoked from * interrupt context, as they require communication with the device * over an I2C bus. * * many other counter APIs, such as start/stop/set_top_value are not From 34b6247910609d62f5e07e87564324b19f618a39 Mon Sep 17 00:00:00 2001 From: Henrik Brix Andersen Date: Tue, 28 Nov 2023 11:29:34 +0100 Subject: [PATCH 0488/3723] drivers: i3c: fix nested list item formatting The formatting of the nested list in the I3C header somehow confuses Doxygen. Explicitly terminate each of the nested lists to avoid this. Signed-off-by: Henrik Brix Andersen --- include/zephyr/drivers/i3c.h | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/include/zephyr/drivers/i3c.h b/include/zephyr/drivers/i3c.h index 36a93fc01de..04aedf8c05b 100644 --- a/include/zephyr/drivers/i3c.h +++ b/include/zephyr/drivers/i3c.h @@ -35,27 +35,34 @@ extern "C" { * - 1: I3C Controller capable * - 2: Reserved * - 3: Reserved + * . * - BCR[5]: Advanced Capabilities * - 0: Does not support optional advanced capabilities. * - 1: Supports optional advanced capabilities which * can be viewed via GETCAPS CCC. - * - BCR[4}: Virtual Target Support + * . + * - BCR[4]: Virtual Target Support * - 0: Is not a virtual target. * - 1: Is a virtual target. + * . * - BCR[3]: Offline Capable * - 0: Will always response to I3C commands. * - 1: Will not always response to I3C commands. + * . * - BCR[2]: IBI Payload * - 0: No data bytes following the accepted IBI. * - 1: One data byte (MDB, Mandatory Data Byte) follows * the accepted IBI. Additional data bytes may also * follows. + * . * - BCR[1]: IBI Request Capable * - 0: Not capable * - 1: Capable + * . * - BCR[0]: Max Data Speed Limitation * - 0: No Limitation * - 1: Limitation obtained via GETMXDS CCC. + * . * * @{ */ From 3fe9aaa0f15707216eb498106aa6a73a3959b82a Mon Sep 17 00:00:00 2001 From: Jonathan Rico Date: Mon, 27 Nov 2023 15:46:23 +0100 Subject: [PATCH 0489/3723] tests: Bluetooth: add ATT clopen test Open. Close. Do it a bunch of times. Cry a lot. Signed-off-by: Jonathan Rico --- .../host/att/open_close/CMakeLists.txt | 23 ++ .../bluetooth/host/att/open_close/_build.sh | 16 ++ .../bluetooth/host/att/open_close/prj.conf | 28 +++ .../bsim/bluetooth/host/att/open_close/run.sh | 36 +++ .../host/att/open_close/src/bs_macro.h | 26 ++ .../host/att/open_close/src/bs_main.c | 31 +++ .../host/att/open_close/src/bs_sync.c | 107 ++++++++ .../host/att/open_close/src/bs_sync.h | 5 + .../bluetooth/host/att/open_close/src/main.c | 234 ++++++++++++++++++ tests/bsim/bluetooth/host/compile.sh | 1 + 10 files changed, 507 insertions(+) create mode 100644 tests/bsim/bluetooth/host/att/open_close/CMakeLists.txt create mode 100755 tests/bsim/bluetooth/host/att/open_close/_build.sh create mode 100644 tests/bsim/bluetooth/host/att/open_close/prj.conf create mode 100755 tests/bsim/bluetooth/host/att/open_close/run.sh create mode 100644 tests/bsim/bluetooth/host/att/open_close/src/bs_macro.h create mode 100644 tests/bsim/bluetooth/host/att/open_close/src/bs_main.c create mode 100644 tests/bsim/bluetooth/host/att/open_close/src/bs_sync.c create mode 100644 tests/bsim/bluetooth/host/att/open_close/src/bs_sync.h create mode 100644 tests/bsim/bluetooth/host/att/open_close/src/main.c diff --git a/tests/bsim/bluetooth/host/att/open_close/CMakeLists.txt b/tests/bsim/bluetooth/host/att/open_close/CMakeLists.txt new file mode 100644 index 00000000000..53a62e84c4a --- /dev/null +++ b/tests/bsim/bluetooth/host/att/open_close/CMakeLists.txt @@ -0,0 +1,23 @@ +# SPDX-License-Identifier: Apache-2.0 + +cmake_minimum_required(VERSION 3.20.0) + +find_package(Zephyr HINTS $ENV{ZEPHYR_BASE}) +project(app) + +add_subdirectory(${ZEPHYR_BASE}/tests/bluetooth/common/testlib testlib) + +target_sources(app PRIVATE + src/bs_main.c + src/bs_sync.c + src/main.c +) + +zephyr_include_directories( + ${BSIM_COMPONENTS_PATH}/libPhyComv1/src/ + ${BSIM_COMPONENTS_PATH}/libUtilv1/src/ +) + +target_link_libraries(app PRIVATE + testlib +) diff --git a/tests/bsim/bluetooth/host/att/open_close/_build.sh b/tests/bsim/bluetooth/host/att/open_close/_build.sh new file mode 100755 index 00000000000..649682554f5 --- /dev/null +++ b/tests/bsim/bluetooth/host/att/open_close/_build.sh @@ -0,0 +1,16 @@ +#!/usr/bin/env bash +# Copyright (c) 2023 Nordic Semiconductor +# SPDX-License-Identifier: Apache-2.0 + +set -eu +dotslash="$(realpath "$(dirname "${BASH_SOURCE[0]}")")" +bin_dir="${BSIM_OUT_PATH}/bin" +BOARD="${BOARD:-nrf52_bsim}" + +cd "${dotslash}" + +compile_path="${bin_dir}/bs_${BOARD}_" +compile_path+="$(realpath --relative-to "$(west topdir)"/zephyr prj.conf | tr /. _)" + +west build -b nrf52_bsim +cp -v build/zephyr/zephyr.exe "${compile_path}" diff --git a/tests/bsim/bluetooth/host/att/open_close/prj.conf b/tests/bsim/bluetooth/host/att/open_close/prj.conf new file mode 100644 index 00000000000..f898c5238cc --- /dev/null +++ b/tests/bsim/bluetooth/host/att/open_close/prj.conf @@ -0,0 +1,28 @@ +CONFIG_ASSERT=y +CONFIG_BOOT_BANNER=n +CONFIG_BT_BUF_ACL_RX_SIZE=204 +CONFIG_BT_CENTRAL=y +CONFIG_BT_DEVICE_NAME_DYNAMIC=y +CONFIG_BT_EATT=y +CONFIG_BT_EXT_ADV=y +CONFIG_BT_GATT_CLIENT=y +CONFIG_BT_GATT_DYNAMIC_DB=y +CONFIG_BT_L2CAP_DYNAMIC_CHANNEL=y +CONFIG_BT_L2CAP_ECRED=y +CONFIG_BT_L2CAP_TX_MTU=200 +CONFIG_BT_MAX_CONN=3 +CONFIG_BT_MAX_PAIRED=2 +CONFIG_BT_PERIPHERAL=y +CONFIG_BT_PRIVACY=n +CONFIG_BT_SMP=y +CONFIG_BT_TESTING=y +CONFIG_BT=y +CONFIG_FLASH_MAP=y +CONFIG_FLASH_PAGE_LAYOUT=y +CONFIG_FLASH=y +CONFIG_LOG_BACKEND_FORMAT_TIMESTAMP=n +CONFIG_LOG_RUNTIME_FILTERING=y +CONFIG_LOG_TAG_MAX_LEN=20 +CONFIG_LOG=y + +CONFIG_BT_BUF_ACL_TX_COUNT=3 diff --git a/tests/bsim/bluetooth/host/att/open_close/run.sh b/tests/bsim/bluetooth/host/att/open_close/run.sh new file mode 100755 index 00000000000..3d8372e08ae --- /dev/null +++ b/tests/bsim/bluetooth/host/att/open_close/run.sh @@ -0,0 +1,36 @@ +#!/usr/bin/env bash +# Copyright (c) 2023 Nordic Semiconductor +# SPDX-License-Identifier: Apache-2.0 + +set -eu + +dotslash="$(realpath "$(dirname "${BASH_SOURCE[0]}")")" +bin_dir="${BSIM_OUT_PATH}/bin" +BOARD="${BOARD:-nrf52_bsim}" + +source ${ZEPHYR_BASE}/tests/bsim/sh_common.source + +cd "${dotslash}" + +compile_name="bs_${BOARD}_" +compile_name+="$(realpath --relative-to "$(west topdir)"/zephyr prj.conf | tr /. _)" + +compile_path="${bin_dir}/${compile_name}" +simulation_id="${compile_name}_$(basename "${BASH_SOURCE[0]}" | tr /. _)" + +args_all=(-s="${simulation_id}" -D=2) +args_dev=(-v=2 -RealEncryption=1 -testid=the_test) +sim_seconds=200 + +echo "Simulation time: $sim_seconds seconds" + +EXECUTE_TIMEOUT=60 + +# bs_2G4_phy_v1 requires pwd to at its location +cd "${BSIM_OUT_PATH}/bin" + +Execute "${compile_path}" "${args_all[@]}" "${args_dev[@]}" -d=1 +Execute ./bs_2G4_phy_v1 "${args_all[@]}" -v=6 -sim_length=$((sim_seconds * 10 ** 6)) +Execute "${compile_path}" "${args_all[@]}" "${args_dev[@]}" -d=0 + +wait_for_background_jobs diff --git a/tests/bsim/bluetooth/host/att/open_close/src/bs_macro.h b/tests/bsim/bluetooth/host/att/open_close/src/bs_macro.h new file mode 100644 index 00000000000..0d19babf357 --- /dev/null +++ b/tests/bsim/bluetooth/host/att/open_close/src/bs_macro.h @@ -0,0 +1,26 @@ +/* Copyright (c) 2023 Nordic Semiconductor ASA + * SPDX-License-Identifier: Apache-2.0 + */ + +#include +#include + +#define PASS(...) \ + do { \ + extern enum bst_result_t bst_result; \ + bst_result = Passed; \ + bs_trace_info_time(1, __VA_ARGS__); \ + } while (0) + +static inline void bt_testlib_expect_zero(int err, char *where_file, int where_line) +{ + if (err) { + bs_trace_print(BS_TRACE_ERROR, where_file, where_line, 0, BS_TRACE_AUTOTIME, 0, + "err %d\n", err); + } +} + +#define FAIL(...) \ + bs_trace_print(BS_TRACE_ERROR, __FILE__, __LINE__, 0, BS_TRACE_AUTOTIME, 0, __VA_ARGS__); + +#define EXPECT_ZERO(expr) bt_testlib_expect_zero((expr), __FILE__, __LINE__) diff --git a/tests/bsim/bluetooth/host/att/open_close/src/bs_main.c b/tests/bsim/bluetooth/host/att/open_close/src/bs_main.c new file mode 100644 index 00000000000..26985a8d415 --- /dev/null +++ b/tests/bsim/bluetooth/host/att/open_close/src/bs_main.c @@ -0,0 +1,31 @@ +/* Copyright (c) 2023 Nordic Semiconductor ASA + * SPDX-License-Identifier: Apache-2.0 + */ + +#include +#include +#include + +void the_test(void); + +static const struct bst_test_instance test_to_add[] = { + { + .test_id = "the_test", + .test_main_f = the_test, + }, + BSTEST_END_MARKER, +}; + +static struct bst_test_list *install(struct bst_test_list *tests) +{ + return bst_add_tests(tests, test_to_add); +}; + +bst_test_install_t test_installers[] = {install, NULL}; + +int main(void) +{ + bst_main(); + + return 0; +} diff --git a/tests/bsim/bluetooth/host/att/open_close/src/bs_sync.c b/tests/bsim/bluetooth/host/att/open_close/src/bs_sync.c new file mode 100644 index 00000000000..c7c432c74b7 --- /dev/null +++ b/tests/bsim/bluetooth/host/att/open_close/src/bs_sync.c @@ -0,0 +1,107 @@ +/* Copyright (c) 2023 Nordic Semiconductor ASA + * SPDX-License-Identifier: Apache-2.0 + */ + +#include +#include +#include +#include + +#include +#include +#include +#include +LOG_MODULE_REGISTER(bs_sync, LOG_LEVEL_INF); + +static int n_devs; + +static void register_more_cmd_args(void) +{ + static bs_args_struct_t args_struct_toadd[] = { + { + .option = "D", + .name = "number_devices", + .type = 'i', + .dest = (void *)&n_devs, + .descript = "Number of devices which will connect in this phy", + .is_mandatory = true, + }, + ARG_TABLE_ENDMARKER, + }; + + bs_add_extra_dynargs(args_struct_toadd); +} +NATIVE_TASK(register_more_cmd_args, PRE_BOOT_1, 100); + +static uint *backchannels; +static void setup_backchannels(void) +{ + __ASSERT_NO_MSG(n_devs > 0); + uint self = get_device_nbr(); + uint device_nbrs[n_devs]; + uint channel_numbers[n_devs]; + + for (int i = 0; i < n_devs; i++) { + device_nbrs[i] = i; + channel_numbers[i] = 0; + } + + backchannels = + bs_open_back_channel(self, device_nbrs, channel_numbers, ARRAY_SIZE(device_nbrs)); + __ASSERT_NO_MSG(backchannels != NULL); +} +NATIVE_TASK(setup_backchannels, PRE_BOOT_3, 100); + +void bs_bc_receive_msg_sync(uint ch, size_t size, uint8_t *data) +{ + while (bs_bc_is_msg_received(ch) < size) { + k_msleep(1); + } + bs_bc_receive_msg(ch, data, size); +} + +void bs_bc_send_uint(uint ch, uint64_t data) +{ + uint8_t data_bytes[sizeof(data)]; + + sys_put_le64(data, data_bytes); + bs_bc_send_msg(ch, data_bytes, sizeof(data_bytes)); +} + +uint64_t bs_bc_recv_uint(uint ch) +{ + uint8_t data[sizeof(uint64_t)]; + + bs_bc_receive_msg_sync(ch, sizeof(data), data); + return sys_get_le64(data); +} + +void bt_testlib_bs_sync_all(void) +{ + static uint64_t counter; + + LOG_DBG("%llu d%u enter", counter, get_device_nbr()); + + /* Device 0 acts as hub. */ + if (get_device_nbr() == 0) { + for (int i = 1; i < n_devs; i++) { + uint64_t counter_cfm; + + counter_cfm = bs_bc_recv_uint(backchannels[i]); + __ASSERT(counter_cfm == counter, "%luu %luu", counter_cfm, counter); + } + for (int i = 1; i < n_devs; i++) { + bs_bc_send_uint(backchannels[i], counter); + } + } else { + uint64_t counter_cfm; + + bs_bc_send_uint(backchannels[0], counter); + counter_cfm = bs_bc_recv_uint(backchannels[0]); + __ASSERT(counter_cfm == counter, "%luu %luu", counter_cfm, counter); + } + + LOG_DBG("%llu d%u exit", counter, get_device_nbr()); + + counter++; +} diff --git a/tests/bsim/bluetooth/host/att/open_close/src/bs_sync.h b/tests/bsim/bluetooth/host/att/open_close/src/bs_sync.h new file mode 100644 index 00000000000..f69336cb1c2 --- /dev/null +++ b/tests/bsim/bluetooth/host/att/open_close/src/bs_sync.h @@ -0,0 +1,5 @@ +/* Copyright (c) 2023 Nordic Semiconductor ASA + * SPDX-License-Identifier: Apache-2.0 + */ + +void bt_testlib_bs_sync_all(void); diff --git a/tests/bsim/bluetooth/host/att/open_close/src/main.c b/tests/bsim/bluetooth/host/att/open_close/src/main.c new file mode 100644 index 00000000000..42fdee6824a --- /dev/null +++ b/tests/bsim/bluetooth/host/att/open_close/src/main.c @@ -0,0 +1,234 @@ +/* Copyright (c) 2023 Nordic Semiconductor ASA + * SPDX-License-Identifier: Apache-2.0 + */ + +#include +#include +#include +#include +#include +#include +#include + +#include "testlib/adv.h" +#include "testlib/att_read.h" +#include "testlib/att_write.h" +#include "bs_macro.h" +#include "bs_sync.h" +#include +#include "testlib/log_utils.h" +#include "testlib/scan.h" +#include "testlib/security.h" + +/* This test uses system asserts to fail tests. */ +BUILD_ASSERT(__ASSERT_ON); + +#define CENTRAL_DEVICE_NBR 0 +#define PERIPHERAL_DEVICE_NBR 1 + +LOG_MODULE_REGISTER(main, LOG_LEVEL_DBG); + +#define UUID_1 \ + BT_UUID_DECLARE_128(0xdb, 0x1f, 0xe2, 0x52, 0xf3, 0xc6, 0x43, 0x66, 0xb3, 0x92, 0x5d, \ + 0xc6, 0xe7, 0xc9, 0x59, 0x9d) + +#define UUID_2 \ + BT_UUID_DECLARE_128(0x3f, 0xa4, 0x7f, 0x44, 0x2e, 0x2a, 0x43, 0x05, 0xab, 0x38, 0x07, \ + 0x8d, 0x16, 0xbf, 0x99, 0xf1) + +static ssize_t read_mtu_validation_chrc(struct bt_conn *conn, const struct bt_gatt_attr *attr, + void *buf, uint16_t buf_len, uint16_t offset) +{ + + LOG_DBG("Server side buf_len %u", buf_len); + + k_msleep(100); + + LOG_DBG("============================> trigger disconnect"); + bt_conn_disconnect(conn, BT_HCI_ERR_REMOTE_POWER_OFF); + + /* We ain't read nothin' */ + return 0; +} + +static struct bt_gatt_attr attrs[] = { + BT_GATT_PRIMARY_SERVICE(UUID_1), + BT_GATT_CHARACTERISTIC(UUID_2, BT_GATT_CHRC_READ, BT_GATT_PERM_READ, + read_mtu_validation_chrc, NULL, NULL), +}; + +static struct bt_gatt_service svc = { + .attrs = attrs, + .attr_count = ARRAY_SIZE(attrs), +}; + +static void find_the_chrc(struct bt_conn *conn, uint16_t *chrc_value_handle) +{ + uint16_t svc_handle; + uint16_t svc_end_handle; + uint16_t chrc_end_handle; + + EXPECT_ZERO(bt_testlib_gatt_discover_primary(&svc_handle, &svc_end_handle, conn, UUID_1, 1, + 0xffff)); + + LOG_DBG("svc_handle: %u, svc_end_handle: %u", svc_handle, svc_end_handle); + + EXPECT_ZERO(bt_testlib_gatt_discover_characteristic(chrc_value_handle, &chrc_end_handle, + NULL, conn, UUID_2, (svc_handle + 1), + svc_end_handle)); + + LOG_DBG("chrc_value_handle: %u, chrc_end_handle: %u", *chrc_value_handle, chrc_end_handle); +} + +static void bs_sync_all_log(char *log_msg) +{ + /* Everyone meets here. */ + bt_testlib_bs_sync_all(); + + if (get_device_nbr() == 0) { + LOG_WRN("Sync point: %s", log_msg); + } + + /* Everyone waits for d0 to finish logging. */ + bt_testlib_bs_sync_all(); +} + +static inline void bt_enable_quiet(void) +{ + bt_testlib_log_level_set("bt_hci_core", LOG_LEVEL_ERR); + bt_testlib_log_level_set("bt_id", LOG_LEVEL_ERR); + + EXPECT_ZERO(bt_enable(NULL)); + + bt_testlib_log_level_set("bt_hci_core", LOG_LEVEL_INF); + bt_testlib_log_level_set("bt_id", LOG_LEVEL_INF); +} + +#define ITERATIONS 20 +#define READ_PARAMS_COUNT 20 +static struct bt_gatt_read_params closet[READ_PARAMS_COUNT]; + +static volatile int outstanding; + +static uint8_t gatt_read_cb(struct bt_conn *conn, uint8_t err, + struct bt_gatt_read_params *params, const void *data, + uint16_t length) +{ + LOG_DBG("<------------------------- read done: err %d", err); + + outstanding--; + + return 0; +} + +void a_test_iteration(int i) +{ + bool central = (get_device_nbr() == CENTRAL_DEVICE_NBR); + bool peripheral = (get_device_nbr() == PERIPHERAL_DEVICE_NBR); + bt_addr_le_t adva; + uint16_t chrc_value_handle = 0; + struct bt_conn *conn = NULL; + int err; + + LOG_DBG("############################## start iteration %d", i); + + bs_sync_all_log("Start iteration"); + + if (peripheral) { + EXPECT_ZERO(bt_set_name("peripheral")); + EXPECT_ZERO(bt_testlib_adv_conn( + &conn, BT_ID_DEFAULT, + (BT_LE_ADV_OPT_USE_NAME | BT_LE_ADV_OPT_FORCE_NAME_IN_AD))); + } + + if (central) { + EXPECT_ZERO(bt_testlib_scan_find_name(&adva, "peripheral")); + EXPECT_ZERO(bt_testlib_connect(&adva, &conn)); + + /* Establish EATT bearers. */ + EXPECT_ZERO(bt_testlib_secure(conn, BT_SECURITY_L2)); + + while (bt_eatt_count(conn) == 0) { + k_msleep(100); + }; + } + + bs_sync_all_log("Connected"); + + /* Perform discovery. */ + if (central) { + find_the_chrc(conn, &chrc_value_handle); + } else { + /* Peripheral will use handle 0. + * + * This will return a permission denied from the central's + * server. It doesn't matter as the only thing we want as the + * peripheral is to also be trying to fill the TX queue with ATT + * PDUs. + */ + } + + /* Test purpose: verify no allocated resource leaks when disconnecting + * abruptly with non-empty queues. + * + * Test procedure (in a nutshell): + * - open channels + * - queue up lots of ATT bufs from both sides + * - disconnect ACL + * - see if anything stalls or leaks + * + * Run this procedure more times than there are said resources. + */ + for (int p = 0; p < ARRAY_SIZE(closet); p++) { + memset(&closet[p], 0, sizeof(struct bt_gatt_read_params)); + + closet[p].handle_count = 1; + closet[p].single.handle = chrc_value_handle; + closet[p].func = gatt_read_cb; + + /* A disconnected channel (or ACL conn) can end up with + * gatt_read returning -ENOMEM instead of -ENOTCONN. sometimes. + */ + LOG_DBG("-------------------------> gatt_read %d", p); + err = bt_gatt_read(conn, &closet[p]); + switch (err) { + case -ENOMEM: + case -ENOTCONN: + LOG_DBG("not connected"); + break; + case 0: + outstanding++; + break; + default: + FAIL("unexpected error: %d\n", err); + break; + } + } + + bt_testlib_wait_disconnected(conn); + bt_testlib_conn_unref(&conn); + + k_msleep(1000); /* beauty rest */ + EXPECT_ZERO(outstanding); + + LOG_DBG("ended iteration %d", i); +} + +void the_test(void) +{ + bool peripheral = (get_device_nbr() == PERIPHERAL_DEVICE_NBR); + + if (peripheral) { + EXPECT_ZERO(bt_gatt_service_register(&svc)); + } + + bt_enable_quiet(); + + for (int i = 0; i < ITERATIONS; i++) { + a_test_iteration(i); + } + + bs_sync_all_log("Test Complete"); + + PASS("Test complete\n"); +} diff --git a/tests/bsim/bluetooth/host/compile.sh b/tests/bsim/bluetooth/host/compile.sh index ff42fd27adf..405586143e3 100755 --- a/tests/bsim/bluetooth/host/compile.sh +++ b/tests/bsim/bluetooth/host/compile.sh @@ -40,6 +40,7 @@ app=tests/bsim/bluetooth/host/att/retry_on_sec_err/server compile app=tests/bsim/bluetooth/host/att/sequential/dut compile app=tests/bsim/bluetooth/host/att/sequential/tester compile app=tests/bsim/bluetooth/host/att/long_read compile +app=tests/bsim/bluetooth/host/att/open_close compile app=tests/bsim/bluetooth/host/gatt/caching compile app=tests/bsim/bluetooth/host/gatt/general compile From 535e003a00699e15064ac99bcf3179a111450f88 Mon Sep 17 00:00:00 2001 From: Aleksander Wasaznik Date: Tue, 4 Jul 2023 11:17:17 +0200 Subject: [PATCH 0490/3723] Bluetooth: Use `CONFIG_BT_CONN_TX_USER_DATA_SIZE` Replace hardcoded value `8` with `CONFIG_BT_CONN_TX_USER_DATA_SIZE`, that is `8` but is going to change. Signed-off-by: Aleksander Wasaznik --- subsys/bluetooth/audio/shell/bap.c | 2 +- subsys/bluetooth/host/conn.c | 5 +++-- subsys/bluetooth/host/l2cap.c | 2 +- subsys/bluetooth/host/sdp.c | 4 ++-- subsys/bluetooth/services/ots/ots_l2cap.c | 5 ++--- subsys/bluetooth/shell/l2cap.c | 4 ++-- tests/bsim/bluetooth/host/l2cap/credits/src/main.c | 2 +- tests/bsim/bluetooth/host/l2cap/credits_seg_recv/src/main.c | 2 +- .../bluetooth/host/l2cap/general/src/main_l2cap_ecred.c | 6 ++++-- .../l2cap/send_on_connect/src/main_l2cap_send_on_connect.c | 2 +- tests/bsim/bluetooth/host/l2cap/stress/src/main.c | 4 ++-- tests/bsim/bluetooth/ll/cis/src/main.c | 3 ++- 12 files changed, 22 insertions(+), 19 deletions(-) diff --git a/subsys/bluetooth/audio/shell/bap.c b/subsys/bluetooth/audio/shell/bap.c index bbddb0d3ee6..69ff3342ab3 100644 --- a/subsys/bluetooth/audio/shell/bap.c +++ b/subsys/bluetooth/audio/shell/bap.c @@ -2561,7 +2561,7 @@ static int cmd_init(const struct shell *sh, size_t argc, char *argv[]) #if defined(CONFIG_BT_AUDIO_TX) #define DATA_MTU CONFIG_BT_ISO_TX_MTU -NET_BUF_POOL_FIXED_DEFINE(tx_pool, 1, DATA_MTU, 8, NULL); +NET_BUF_POOL_FIXED_DEFINE(tx_pool, 1, DATA_MTU, CONFIG_BT_CONN_TX_USER_DATA_SIZE, NULL); static int cmd_send(const struct shell *sh, size_t argc, char *argv[]) { diff --git a/subsys/bluetooth/host/conn.c b/subsys/bluetooth/host/conn.c index 06a3e7553a2..58c39136ef9 100644 --- a/subsys/bluetooth/host/conn.c +++ b/subsys/bluetooth/host/conn.c @@ -447,9 +447,10 @@ int bt_conn_send_cb(struct bt_conn *conn, struct net_buf *buf, user_data); if (buf->user_data_size < CONFIG_BT_CONN_TX_USER_DATA_SIZE) { - LOG_ERR("not enough room in user_data %d < %d", + LOG_ERR("not enough room in user_data %d < %d pool %u", buf->user_data_size, - CONFIG_BT_CONN_TX_USER_DATA_SIZE); + CONFIG_BT_CONN_TX_USER_DATA_SIZE, + buf->pool_id); return -EINVAL; } diff --git a/subsys/bluetooth/host/l2cap.c b/subsys/bluetooth/host/l2cap.c index 99e9d1de988..a76cd189fce 100644 --- a/subsys/bluetooth/host/l2cap.c +++ b/subsys/bluetooth/host/l2cap.c @@ -65,7 +65,7 @@ NET_BUF_POOL_FIXED_DEFINE(disc_pool, 1, BT_L2CAP_BUF_SIZE( sizeof(struct bt_l2cap_sig_hdr) + sizeof(struct bt_l2cap_disconn_req)), - 8, NULL); + CONFIG_BT_CONN_TX_USER_DATA_SIZE, NULL); #define l2cap_lookup_ident(conn, ident) __l2cap_lookup_ident(conn, ident, false) #define l2cap_remove_ident(conn, ident) __l2cap_lookup_ident(conn, ident, true) diff --git a/subsys/bluetooth/host/sdp.c b/subsys/bluetooth/host/sdp.c index bd36187d43c..d663ee5123f 100644 --- a/subsys/bluetooth/host/sdp.c +++ b/subsys/bluetooth/host/sdp.c @@ -70,8 +70,8 @@ static uint8_t num_services; static struct bt_sdp bt_sdp_pool[CONFIG_BT_MAX_CONN]; /* Pool for outgoing SDP packets */ -NET_BUF_POOL_FIXED_DEFINE(sdp_pool, CONFIG_BT_MAX_CONN, - BT_L2CAP_BUF_SIZE(SDP_MTU), 8, NULL); +NET_BUF_POOL_FIXED_DEFINE(sdp_pool, CONFIG_BT_MAX_CONN, BT_L2CAP_BUF_SIZE(SDP_MTU), + CONFIG_BT_CONN_TX_USER_DATA_SIZE, NULL); #define SDP_CLIENT_CHAN(_ch) CONTAINER_OF(_ch, struct bt_sdp_client, chan.chan) diff --git a/subsys/bluetooth/services/ots/ots_l2cap.c b/subsys/bluetooth/services/ots/ots_l2cap.c index 923f2c8a593..ad169c5aee0 100644 --- a/subsys/bluetooth/services/ots/ots_l2cap.c +++ b/subsys/bluetooth/services/ots/ots_l2cap.c @@ -33,10 +33,9 @@ LOG_MODULE_REGISTER(bt_ots, CONFIG_BT_OTS_LOG_LEVEL); */ #define BT_GATT_OTS_L2CAP_PSM 0x0025 - NET_BUF_POOL_FIXED_DEFINE(ot_chan_tx_pool, 1, - BT_L2CAP_SDU_BUF_SIZE(CONFIG_BT_OTS_L2CAP_CHAN_TX_MTU), 8, - NULL); + BT_L2CAP_SDU_BUF_SIZE(CONFIG_BT_OTS_L2CAP_CHAN_TX_MTU), + CONFIG_BT_CONN_TX_USER_DATA_SIZE, NULL); #if (CONFIG_BT_OTS_L2CAP_CHAN_RX_MTU > BT_L2CAP_SDU_RX_MTU) NET_BUF_POOL_FIXED_DEFINE(ot_chan_rx_pool, 1, CONFIG_BT_OTS_L2CAP_CHAN_RX_MTU, 8, diff --git a/subsys/bluetooth/shell/l2cap.c b/subsys/bluetooth/shell/l2cap.c index fe594fb0127..45e45f518b1 100644 --- a/subsys/bluetooth/shell/l2cap.c +++ b/subsys/bluetooth/shell/l2cap.c @@ -38,8 +38,8 @@ #define L2CAP_POLICY_ALLOWLIST 0x01 #define L2CAP_POLICY_16BYTE_KEY 0x02 -NET_BUF_POOL_FIXED_DEFINE(data_tx_pool, 1, - BT_L2CAP_SDU_BUF_SIZE(DATA_MTU), 8, NULL); +NET_BUF_POOL_FIXED_DEFINE(data_tx_pool, 1, BT_L2CAP_SDU_BUF_SIZE(DATA_MTU), + CONFIG_BT_CONN_TX_USER_DATA_SIZE, NULL); NET_BUF_POOL_FIXED_DEFINE(data_rx_pool, 1, DATA_MTU, 8, NULL); static uint8_t l2cap_policy; diff --git a/tests/bsim/bluetooth/host/l2cap/credits/src/main.c b/tests/bsim/bluetooth/host/l2cap/credits/src/main.c index 570693ae98b..48d1ac7902c 100644 --- a/tests/bsim/bluetooth/host/l2cap/credits/src/main.c +++ b/tests/bsim/bluetooth/host/l2cap/credits/src/main.c @@ -23,7 +23,7 @@ CREATE_FLAG(flag_l2cap_connected); #define L2CAP_MTU (2 * SDU_LEN) /* Only one SDU transmitted or received at a time */ -NET_BUF_POOL_DEFINE(sdu_pool, 1, L2CAP_MTU, 8, NULL); +NET_BUF_POOL_DEFINE(sdu_pool, 1, L2CAP_MTU, CONFIG_BT_CONN_TX_USER_DATA_SIZE, NULL); static uint8_t tx_data[SDU_LEN]; static uint16_t rx_cnt; diff --git a/tests/bsim/bluetooth/host/l2cap/credits_seg_recv/src/main.c b/tests/bsim/bluetooth/host/l2cap/credits_seg_recv/src/main.c index deead1a8b10..8e927002da1 100644 --- a/tests/bsim/bluetooth/host/l2cap/credits_seg_recv/src/main.c +++ b/tests/bsim/bluetooth/host/l2cap/credits_seg_recv/src/main.c @@ -21,7 +21,7 @@ CREATE_FLAG(flag_l2cap_connected); #define L2CAP_MTU (2 * SDU_LEN) /* Only one SDU transmitted or received at a time */ -NET_BUF_POOL_DEFINE(sdu_pool, 1, L2CAP_MTU, 8, NULL); +NET_BUF_POOL_DEFINE(sdu_pool, 1, L2CAP_MTU, CONFIG_BT_CONN_TX_USER_DATA_SIZE, NULL); static uint8_t tx_data[SDU_LEN]; static uint16_t rx_cnt; diff --git a/tests/bsim/bluetooth/host/l2cap/general/src/main_l2cap_ecred.c b/tests/bsim/bluetooth/host/l2cap/general/src/main_l2cap_ecred.c index d89e71d327f..ecb4fa320ae 100644 --- a/tests/bsim/bluetooth/host/l2cap/general/src/main_l2cap_ecred.c +++ b/tests/bsim/bluetooth/host/l2cap/general/src/main_l2cap_ecred.c @@ -33,8 +33,10 @@ static const struct bt_data ad[] = { #define SHORT_MSG_CHAN_IDX 1 NET_BUF_POOL_FIXED_DEFINE(rx_data_pool, L2CAP_CHANNELS, BT_L2CAP_BUF_SIZE(DATA_BUF_SIZE), 8, NULL); -NET_BUF_POOL_FIXED_DEFINE(tx_data_pool_0, 1, BT_L2CAP_BUF_SIZE(DATA_MTU), 8, NULL); -NET_BUF_POOL_FIXED_DEFINE(tx_data_pool_1, 1, BT_L2CAP_BUF_SIZE(DATA_MTU), 8, NULL); +NET_BUF_POOL_FIXED_DEFINE(tx_data_pool_0, 1, BT_L2CAP_BUF_SIZE(DATA_MTU), + CONFIG_BT_CONN_TX_USER_DATA_SIZE, NULL); +NET_BUF_POOL_FIXED_DEFINE(tx_data_pool_1, 1, BT_L2CAP_BUF_SIZE(DATA_MTU), + CONFIG_BT_CONN_TX_USER_DATA_SIZE, NULL); static struct bt_l2cap_server servers[SERVERS]; void send_sdu_chan_worker(struct k_work *item); diff --git a/tests/bsim/bluetooth/host/l2cap/send_on_connect/src/main_l2cap_send_on_connect.c b/tests/bsim/bluetooth/host/l2cap/send_on_connect/src/main_l2cap_send_on_connect.c index 485c97c11dc..ac01dbcc38a 100644 --- a/tests/bsim/bluetooth/host/l2cap/send_on_connect/src/main_l2cap_send_on_connect.c +++ b/tests/bsim/bluetooth/host/l2cap/send_on_connect/src/main_l2cap_send_on_connect.c @@ -22,7 +22,7 @@ CREATE_FLAG(data_received); #define DATA_BYTE_VAL 0xBB /* L2CAP channel buffer pool */ -NET_BUF_POOL_DEFINE(buf_pool, 1, BT_L2CAP_SDU_BUF_SIZE(16), 8, NULL); +NET_BUF_POOL_DEFINE(buf_pool, 1, BT_L2CAP_SDU_BUF_SIZE(16), CONFIG_BT_CONN_TX_USER_DATA_SIZE, NULL); static void chan_connected_cb(struct bt_l2cap_chan *l2cap_chan) { diff --git a/tests/bsim/bluetooth/host/l2cap/stress/src/main.c b/tests/bsim/bluetooth/host/l2cap/stress/src/main.c index 244d69b7fa2..08e988fcd36 100644 --- a/tests/bsim/bluetooth/host/l2cap/stress/src/main.c +++ b/tests/bsim/bluetooth/host/l2cap/stress/src/main.c @@ -26,12 +26,12 @@ CREATE_FLAG(flag_l2cap_connected); /* Only one SDU per link will be transmitted at a time */ NET_BUF_POOL_DEFINE(sdu_tx_pool, CONFIG_BT_MAX_CONN, BT_L2CAP_SDU_BUF_SIZE(SDU_LEN), - 8, NULL); + CONFIG_BT_CONN_TX_USER_DATA_SIZE, NULL); NET_BUF_POOL_DEFINE(segment_pool, /* MTU + 4 l2cap hdr + 4 ACL hdr */ NUM_SEGMENTS, BT_L2CAP_BUF_SIZE(CONFIG_BT_L2CAP_TX_MTU), - 8, NULL); + CONFIG_BT_CONN_TX_USER_DATA_SIZE, NULL); /* Only one SDU per link will be received at a time */ NET_BUF_POOL_DEFINE(sdu_rx_pool, diff --git a/tests/bsim/bluetooth/ll/cis/src/main.c b/tests/bsim/bluetooth/ll/cis/src/main.c index fe0530eba05..90243354158 100644 --- a/tests/bsim/bluetooth/ll/cis/src/main.c +++ b/tests/bsim/bluetooth/ll/cis/src/main.c @@ -106,7 +106,8 @@ static bt_addr_le_t peer_addr; #define BUF_ALLOC_TIMEOUT (50) /* milliseconds */ NET_BUF_POOL_FIXED_DEFINE(tx_pool, CONFIG_BT_ISO_TX_BUF_COUNT, - BT_ISO_SDU_BUF_SIZE(CONFIG_BT_ISO_TX_MTU), 8, NULL); + BT_ISO_SDU_BUF_SIZE(CONFIG_BT_ISO_TX_MTU), + CONFIG_BT_CONN_TX_USER_DATA_SIZE, NULL); static bool data_cb(struct bt_data *data, void *user_data) { From 8a3201c2235e6a6572b389d2716ccbc6eb0474c7 Mon Sep 17 00:00:00 2001 From: Aleksander Wasaznik Date: Thu, 13 Jul 2023 10:48:57 +0200 Subject: [PATCH 0491/3723] Bluetooth: att: Remove att use of bt_l2cap_chan_send_cb EATT is the only user of `bt_l2cap_chan_send_cb`, and not necessary. We can maintain the same functionality without it. Instead of passing and storing the callback into l2cap, we can store it in a callback queue in the ATT bearer struct. This will allow us to remove that internal API later, in order to streamline the l2cap API. Signed-off-by: Aleksander Wasaznik --- subsys/bluetooth/host/att.c | 111 ++++++++++++++++++++++++++---------- 1 file changed, 82 insertions(+), 29 deletions(-) diff --git a/subsys/bluetooth/host/att.c b/subsys/bluetooth/host/att.c index 130b4ab0853..70fc717aff6 100644 --- a/subsys/bluetooth/host/att.c +++ b/subsys/bluetooth/host/att.c @@ -83,12 +83,31 @@ enum { ATT_NUM_FLAGS, }; +struct bt_att_tx_meta_data; +typedef void (*bt_att_tx_cb_t)(struct bt_conn *conn, + struct bt_att_tx_meta_data *user_data); + +struct bt_att_tx_meta_data { + sys_snode_t tx_cb_queue_node; + bt_att_tx_cb_t chan_cb; + struct bt_att_chan *att_chan; + uint16_t attr_count; + bt_gatt_complete_func_t func; + void *user_data; + enum bt_att_chan_opt chan_opt; +}; + +struct bt_att_tx_meta { + struct bt_att_tx_meta_data *data; +}; + /* ATT channel specific data */ struct bt_att_chan { /* Connection this channel is associated with */ struct bt_att *att; struct bt_l2cap_le_chan chan; ATOMIC_DEFINE(flags, ATT_NUM_FLAGS); + sys_slist_t tx_cb_queue; struct bt_att_req *req; struct k_fifo tx_queue; struct k_work_delayable timeout_work; @@ -159,21 +178,9 @@ static struct bt_att_req cancel; */ static k_tid_t att_handle_rsp_thread; -struct bt_att_tx_meta_data { - struct bt_att_chan *att_chan; - uint16_t attr_count; - bt_gatt_complete_func_t func; - void *user_data; - enum bt_att_chan_opt chan_opt; -}; - -struct bt_att_tx_meta { - struct bt_att_tx_meta_data *data; -}; - #define bt_att_tx_meta_data(buf) (((struct bt_att_tx_meta *)net_buf_user_data(buf))->data) -static struct bt_att_tx_meta_data tx_meta_data[CONFIG_BT_CONN_TX_MAX]; +static struct bt_att_tx_meta_data tx_meta_data_storage[CONFIG_BT_CONN_TX_MAX]; K_FIFO_DEFINE(free_att_tx_meta_data); static struct bt_att_tx_meta_data *tx_meta_data_alloc(k_timeout_t timeout) @@ -198,7 +205,7 @@ static inline void tx_meta_data_free(struct bt_att_tx_meta_data *data) } static int bt_att_chan_send(struct bt_att_chan *chan, struct net_buf *buf); -static bt_conn_tx_cb_t chan_cb(const struct net_buf *buf); +static bt_att_tx_cb_t chan_cb(const struct net_buf *buf); static bt_conn_tx_cb_t att_cb(const struct net_buf *buf); static void att_chan_mtu_updated(struct bt_att_chan *updated_chan); @@ -220,6 +227,27 @@ void att_sent(struct bt_conn *conn, void *user_data) } } +static int att_chan_send_cb(struct bt_att_chan *att_chan, + struct net_buf *buf, + bt_att_tx_cb_t cb, + struct bt_att_tx_meta_data *data) +{ + int err; + + data->chan_cb = chan_cb(buf); + sys_slist_append(&att_chan->tx_cb_queue, &data->tx_cb_queue_node); + + err = bt_l2cap_chan_send(&att_chan->chan.chan, buf); + if (err < 0) { + LOG_WRN("Failed to send ATT PDU: %d", err); + + sys_slist_find_and_remove(&att_chan->tx_cb_queue, + &data->tx_cb_queue_node); + } + + return err; +} + /* In case of success the ownership of the buffer is transferred to the stack * which takes care of releasing it when it completes transmitting to the * controller. @@ -277,7 +305,7 @@ static int chan_send(struct bt_att_chan *chan, struct net_buf *buf) /* bt_l2cap_chan_send does actually return the number of bytes * that could be sent immediately. */ - err = bt_l2cap_chan_send_cb(&chan->chan.chan, buf, chan_cb(buf), data); + err = att_chan_send_cb(chan, buf, chan_cb(buf), data); if (err < 0) { data->att_chan = prev_chan; atomic_clear_bit(chan->flags, ATT_PENDING_SENT); @@ -452,9 +480,24 @@ static int chan_req_send(struct bt_att_chan *chan, struct bt_att_req *req) static void bt_att_sent(struct bt_l2cap_chan *ch) { struct bt_att_chan *chan = ATT_CHAN(ch); + sys_snode_t *tx_meta_data_node = sys_slist_get(&chan->tx_cb_queue); struct bt_att *att = chan->att; int err; + /* EATT channels should always set metadata and a callback */ + __ASSERT_NO_MSG(!tx_meta_data_node == !bt_att_is_enhanced(chan)); + + if (tx_meta_data_node) { + struct bt_att_tx_meta_data *tx_meta_data = CONTAINER_OF( + tx_meta_data_node, struct bt_att_tx_meta_data, tx_cb_queue_node); + + if (tx_meta_data->chan_cb) { + tx_meta_data->chan_cb(ch->conn, tx_meta_data); + } + } else { + LOG_DBG("No tx meta data node"); + } + LOG_DBG("chan %p", chan); atomic_clear_bit(chan->flags, ATT_PENDING_SENT); @@ -490,7 +533,7 @@ static void bt_att_sent(struct bt_l2cap_chan *ch) (void)process_queue(chan, &att->tx_queue); } -static void chan_cfm_sent(struct bt_conn *conn, void *user_data, int err) +static void chan_cfm_sent(struct bt_conn *conn, struct bt_att_tx_meta_data *user_data) { struct bt_att_tx_meta_data *data = user_data; struct bt_att_chan *chan = data->att_chan; @@ -504,7 +547,7 @@ static void chan_cfm_sent(struct bt_conn *conn, void *user_data, int err) tx_meta_data_free(data); } -static void chan_rsp_sent(struct bt_conn *conn, void *user_data, int err) +static void chan_rsp_sent(struct bt_conn *conn, struct bt_att_tx_meta_data *user_data) { struct bt_att_tx_meta_data *data = user_data; struct bt_att_chan *chan = data->att_chan; @@ -518,7 +561,7 @@ static void chan_rsp_sent(struct bt_conn *conn, void *user_data, int err) tx_meta_data_free(data); } -static void chan_req_sent(struct bt_conn *conn, void *user_data, int err) +static void chan_req_sent(struct bt_conn *conn, struct bt_att_tx_meta_data *user_data) { struct bt_att_tx_meta_data *data = user_data; struct bt_att_chan *chan = data->att_chan; @@ -533,7 +576,7 @@ static void chan_req_sent(struct bt_conn *conn, void *user_data, int err) tx_meta_data_free(user_data); } -static void chan_tx_complete(struct bt_conn *conn, void *user_data, int err) +static void chan_tx_complete(struct bt_conn *conn, struct bt_att_tx_meta_data *user_data) { struct bt_att_tx_meta_data *data = user_data; struct bt_att_chan *chan = data->att_chan; @@ -545,19 +588,19 @@ static void chan_tx_complete(struct bt_conn *conn, void *user_data, int err) tx_meta_data_free(data); - if (!err && func) { + if (func) { for (uint16_t i = 0; i < attr_count; i++) { func(conn, ud); } } } -static void chan_unknown(struct bt_conn *conn, void *user_data, int err) +static void chan_unknown(struct bt_conn *conn, struct bt_att_tx_meta_data *user_data) { tx_meta_data_free(user_data); } -static bt_conn_tx_cb_t chan_cb(const struct net_buf *buf) +static bt_att_tx_cb_t chan_cb(const struct net_buf *buf) { const att_type_t op_type = att_op_get_type(buf->data[0]); @@ -585,7 +628,7 @@ static void att_cfm_sent(struct bt_conn *conn, void *user_data, int err) att_sent(conn, user_data); } - chan_cfm_sent(conn, user_data, err); + chan_cfm_sent(conn, user_data); } static void att_rsp_sent(struct bt_conn *conn, void *user_data, int err) @@ -594,7 +637,7 @@ static void att_rsp_sent(struct bt_conn *conn, void *user_data, int err) att_sent(conn, user_data); } - chan_rsp_sent(conn, user_data, err); + chan_rsp_sent(conn, user_data); } static void att_req_sent(struct bt_conn *conn, void *user_data, int err) @@ -603,7 +646,7 @@ static void att_req_sent(struct bt_conn *conn, void *user_data, int err) att_sent(conn, user_data); } - chan_req_sent(conn, user_data, err); + chan_req_sent(conn, user_data); } static void att_tx_complete(struct bt_conn *conn, void *user_data, int err) @@ -612,7 +655,7 @@ static void att_tx_complete(struct bt_conn *conn, void *user_data, int err) att_sent(conn, user_data); } - chan_tx_complete(conn, user_data, err); + chan_tx_complete(conn, user_data); } static void att_unknown(struct bt_conn *conn, void *user_data, int err) @@ -621,7 +664,7 @@ static void att_unknown(struct bt_conn *conn, void *user_data, int err) att_sent(conn, user_data); } - chan_unknown(conn, user_data, err); + chan_unknown(conn, user_data); } static bt_conn_tx_cb_t att_cb(const struct net_buf *buf) @@ -3229,6 +3272,15 @@ static void bt_att_released(struct bt_l2cap_chan *ch) { struct bt_att_chan *chan = ATT_CHAN(ch); + /* Traverse the ATT bearer's TX queue and free the metadata. */ + while (!sys_slist_is_empty(&chan->tx_cb_queue)) { + sys_snode_t *tx_meta_data_node = sys_slist_get(&chan->tx_cb_queue); + struct bt_att_tx_meta_data *tx_meta_data = CONTAINER_OF( + tx_meta_data_node, struct bt_att_tx_meta_data, tx_cb_queue_node); + + tx_meta_data_free(tx_meta_data); + } + LOG_DBG("chan %p", chan); k_mem_slab_free(&chan_slab, (void *)chan); @@ -3282,6 +3334,7 @@ static struct bt_att_chan *att_chan_new(struct bt_att *att, atomic_val_t flags) (void)memset(chan, 0, sizeof(*chan)); chan->chan.chan.ops = &ops; + sys_slist_init(&chan->tx_cb_queue); k_fifo_init(&chan->tx_queue); atomic_set(chan->flags, flags); chan->att = att; @@ -3717,8 +3770,8 @@ static void bt_eatt_init(void) void bt_att_init(void) { k_fifo_init(&free_att_tx_meta_data); - for (size_t i = 0; i < ARRAY_SIZE(tx_meta_data); i++) { - k_fifo_put(&free_att_tx_meta_data, &tx_meta_data[i]); + for (size_t i = 0; i < ARRAY_SIZE(tx_meta_data_storage); i++) { + k_fifo_put(&free_att_tx_meta_data, &tx_meta_data_storage[i]); } bt_gatt_init(); From dc834cb21716468405ff7d0234d4f841a9363e12 Mon Sep 17 00:00:00 2001 From: Aleksander Wasaznik Date: Thu, 13 Jul 2023 14:50:51 +0200 Subject: [PATCH 0492/3723] Bluetooth: l2cap: remove bt_l2cap_chan_send_cb It has no more users and was an internal API. Signed-off-by: Aleksander Wasaznik --- subsys/bluetooth/host/l2cap.c | 13 ++++--------- subsys/bluetooth/host/l2cap_internal.h | 3 --- 2 files changed, 4 insertions(+), 12 deletions(-) diff --git a/subsys/bluetooth/host/l2cap.c b/subsys/bluetooth/host/l2cap.c index a76cd189fce..ba632c1875a 100644 --- a/subsys/bluetooth/host/l2cap.c +++ b/subsys/bluetooth/host/l2cap.c @@ -3147,8 +3147,7 @@ int bt_l2cap_chan_disconnect(struct bt_l2cap_chan *chan) return 0; } -int bt_l2cap_chan_send_cb(struct bt_l2cap_chan *chan, struct net_buf *buf, bt_conn_tx_cb_t cb, - void *user_data) +int bt_l2cap_chan_send(struct bt_l2cap_chan *chan, struct net_buf *buf) { struct bt_l2cap_le_chan *le_chan = BT_L2CAP_LE_CHAN(chan); struct l2cap_tx_meta_data *data; @@ -3171,7 +3170,7 @@ int bt_l2cap_chan_send_cb(struct bt_l2cap_chan *chan, struct net_buf *buf, bt_co if (IS_ENABLED(CONFIG_BT_BREDR) && chan->conn->type == BT_CONN_TYPE_BR) { - return bt_l2cap_br_chan_send_cb(chan, buf, cb, user_data); + return bt_l2cap_br_chan_send_cb(chan, buf, NULL, NULL); } data = alloc_tx_meta_data(); @@ -3182,8 +3181,8 @@ int bt_l2cap_chan_send_cb(struct bt_l2cap_chan *chan, struct net_buf *buf, bt_co data->sent = 0; data->cid = le_chan->tx.cid; - data->cb = cb; - data->user_data = user_data; + data->cb = NULL; + data->user_data = NULL; l2cap_tx_meta_data(buf) = data; /* Queue if there are pending segments left from previous packet or @@ -3214,8 +3213,4 @@ int bt_l2cap_chan_send_cb(struct bt_l2cap_chan *chan, struct net_buf *buf, bt_co return err; } -int bt_l2cap_chan_send(struct bt_l2cap_chan *chan, struct net_buf *buf) -{ - return bt_l2cap_chan_send_cb(chan, buf, NULL, NULL); -} #endif /* CONFIG_BT_L2CAP_DYNAMIC_CHANNEL */ diff --git a/subsys/bluetooth/host/l2cap_internal.h b/subsys/bluetooth/host/l2cap_internal.h index 9fdab336fa9..a6ecac9a016 100644 --- a/subsys/bluetooth/host/l2cap_internal.h +++ b/subsys/bluetooth/host/l2cap_internal.h @@ -316,9 +316,6 @@ static inline int bt_l2cap_send(struct bt_conn *conn, uint16_t cid, return bt_l2cap_send_cb(conn, cid, buf, NULL, NULL); } -int bt_l2cap_chan_send_cb(struct bt_l2cap_chan *chan, struct net_buf *buf, bt_conn_tx_cb_t cb, - void *user_data); - /* Receive a new L2CAP PDU from a connection */ void bt_l2cap_recv(struct bt_conn *conn, struct net_buf *buf, bool complete); From 530e3670bc4cbd250ed0db18377ab715a4917c74 Mon Sep 17 00:00:00 2001 From: Szymon Janc Date: Fri, 24 Nov 2023 14:32:08 +0100 Subject: [PATCH 0493/3723] bluetooth: tester: Allow to use filter list for advertising If there is any element on filter list it is used for advertising. This allows to test all scenarios involving allow list (empty, peer on list, peer not on list). Signed-off-by: Szymon Janc --- tests/bluetooth/tester/src/btp_gap.c | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/tests/bluetooth/tester/src/btp_gap.c b/tests/bluetooth/tester/src/btp_gap.c index e09e90a06e1..fd5307fcc37 100644 --- a/tests/bluetooth/tester/src/btp_gap.c +++ b/tests/bluetooth/tester/src/btp_gap.c @@ -36,6 +36,8 @@ static atomic_t current_settings; struct bt_conn_auth_cb cb; static uint8_t oob_legacy_tk[16] = { 0 }; +static bool filter_list_in_use; + #if !defined(CONFIG_BT_SMP_OOB_LEGACY_PAIR_ONLY) static struct bt_le_oob oob_sc_local = { 0 }; static struct bt_le_oob oob_sc_remote = { 0 }; @@ -578,6 +580,14 @@ int tester_gap_create_adv_instance(struct bt_le_adv_param *param, uint8_t own_ad if (atomic_test_bit(¤t_settings, BTP_GAP_SETTINGS_CONNECTABLE)) { param->options |= BT_LE_ADV_OPT_CONNECTABLE; + + if (filter_list_in_use) { + param->options |= BT_LE_ADV_OPT_FILTER_CONN; + } + } + + if (filter_list_in_use) { + param->options |= BT_LE_ADV_OPT_FILTER_SCAN_REQ; } switch (own_addr_type) { @@ -1305,6 +1315,8 @@ static uint8_t set_filter_list(const void *cmd, uint16_t cmd_len, } } + filter_list_in_use = cp->cnt != 0; + return BTP_STATUS_SUCCESS; } From 37d39425ee18ddb0424bec1a005f54b8967864c9 Mon Sep 17 00:00:00 2001 From: Robert Lubos Date: Tue, 28 Nov 2023 14:30:28 +0100 Subject: [PATCH 0494/3723] net: tcp: Fix possible race between TCP work items and context unref Fix the possible race between TCP work items already scheduled for execution, and tcp_conn_unref(), by moving the actual TCP context releasing to the workqueue itself. That way we can be certain, that when the work items are cancelled, they won't execute. It could be the case, that the work item was already being processed by the work queue, so clearing the context could lead to a crash. Remove the comments around the mutex lock in the work handlers regarding the race, as it's not the case anymore. I've kept the locks however, as they do make sense in those places. Signed-off-by: Robert Lubos --- subsys/net/ip/tcp.c | 82 +++++++++++++++---------------------- subsys/net/ip/tcp_private.h | 1 + 2 files changed, 35 insertions(+), 48 deletions(-) diff --git a/subsys/net/ip/tcp.c b/subsys/net/ip/tcp.c index 6ffd688a20f..cd739d138d3 100644 --- a/subsys/net/ip/tcp.c +++ b/subsys/net/ip/tcp.c @@ -519,32 +519,11 @@ static void tcp_send_queue_flush(struct tcp *conn) } } - -static int tcp_conn_unref(struct tcp *conn) +static void tcp_conn_release(struct k_work *work) { - int ref_count = atomic_get(&conn->ref_count); + struct tcp *conn = CONTAINER_OF(work, struct tcp, conn_release); struct net_pkt *pkt; - NET_DBG("conn: %p, ref_count=%d", conn, ref_count); - - k_mutex_lock(&conn->lock, K_FOREVER); - -#if !defined(CONFIG_NET_TEST_PROTOCOL) - if (conn->in_connect) { - conn->in_connect = false; - k_sem_reset(&conn->connect_sem); - } -#endif /* CONFIG_NET_TEST_PROTOCOL */ - - k_mutex_unlock(&conn->lock); - - ref_count = atomic_dec(&conn->ref_count) - 1; - if (ref_count != 0) { - tp_out(net_context_get_family(conn->context), conn->iface, - "TP_TRACE", "event", "CONN_DELETE"); - return ref_count; - } - k_mutex_lock(&tcp_lock, K_FOREVER); /* If there is any pending data, pass that to application */ @@ -569,19 +548,6 @@ static int tcp_conn_unref(struct tcp *conn) tcp_send_queue_flush(conn); - /* Cancel all possible delayed work and prevent any execution of newly scheduled work - * in one of the work item handlers - * Essential because the work items are destructed at the bottom of this method. - * A current ongoing execution might access the connection and schedule new work - * Solution: - * While holding the lock, cancel all delayable work. - * Because every delayable work execution takes the same lock and releases the lock, - * we're either here, or currently executing one of the workers. - * Then, after cancelling the workers within the lock, either those workers have finished - * or have been cancelled and will not execute anymore - */ - k_mutex_lock(&conn->lock, K_FOREVER); - (void)k_work_cancel_delayable(&conn->send_data_timer); tcp_pkt_unref(conn->send_data); @@ -596,8 +562,6 @@ static int tcp_conn_unref(struct tcp *conn) (void)k_work_cancel_delayable(&conn->send_timer); (void)k_work_cancel_delayable(&conn->recv_queue_timer); - k_mutex_unlock(&conn->lock); - sys_slist_find_and_remove(&tcp_conns, &conn->next); memset(conn, 0, sizeof(*conn)); @@ -605,6 +569,37 @@ static int tcp_conn_unref(struct tcp *conn) k_mem_slab_free(&tcp_conns_slab, (void *)conn); k_mutex_unlock(&tcp_lock); +} + +static int tcp_conn_unref(struct tcp *conn) +{ + int ref_count = atomic_get(&conn->ref_count); + + NET_DBG("conn: %p, ref_count=%d", conn, ref_count); + + k_mutex_lock(&conn->lock, K_FOREVER); + +#if !defined(CONFIG_NET_TEST_PROTOCOL) + if (conn->in_connect) { + conn->in_connect = false; + k_sem_reset(&conn->connect_sem); + } +#endif /* CONFIG_NET_TEST_PROTOCOL */ + + k_mutex_unlock(&conn->lock); + + ref_count = atomic_dec(&conn->ref_count) - 1; + if (ref_count != 0) { + tp_out(net_context_get_family(conn->context), conn->iface, + "TP_TRACE", "event", "CONN_DELETE"); + return ref_count; + } + + /* Release the TCP context from the TCP workqueue. This will ensure, + * that all pending TCP works are cancelled properly, when the context + * is released. + */ + k_work_submit_to_queue(&tcp_work_q, &conn->conn_release); return ref_count; } @@ -714,12 +709,10 @@ static void tcp_send_process(struct k_work *work) struct tcp *conn = CONTAINER_OF(dwork, struct tcp, send_timer); bool unref; - /* take the lock to prevent a race-condition with tcp_conn_unref */ k_mutex_lock(&conn->lock, K_FOREVER); unref = tcp_send_process_no_lock(conn); - /* release the lock only after possible scheduling of work */ k_mutex_unlock(&conn->lock); if (unref) { @@ -1545,7 +1538,6 @@ static void tcp_cleanup_recv_queue(struct k_work *work) struct k_work_delayable *dwork = k_work_delayable_from_work(work); struct tcp *conn = CONTAINER_OF(dwork, struct tcp, recv_queue_timer); - /* take the lock to prevent a race-condition with tcp_conn_unref */ k_mutex_lock(&conn->lock, K_FOREVER); NET_DBG("Cleanup recv queue conn %p len %zd seq %u", conn, @@ -1555,7 +1547,6 @@ static void tcp_cleanup_recv_queue(struct k_work *work) net_buf_unref(conn->queue_recv_data->buffer); conn->queue_recv_data->buffer = NULL; - /* release the lock only after possible scheduling of work */ k_mutex_unlock(&conn->lock); } @@ -1567,7 +1558,6 @@ static void tcp_resend_data(struct k_work *work) int ret; int exp_tcp_rto; - /* take the lock to prevent a race-condition with tcp_conn_unref */ k_mutex_lock(&conn->lock, K_FOREVER); NET_DBG("send_data_retries=%hu", conn->send_data_retries); @@ -1631,7 +1621,6 @@ static void tcp_resend_data(struct k_work *work) K_MSEC(exp_tcp_rto)); out: - /* release the lock only after possible scheduling of work */ k_mutex_unlock(&conn->lock); if (conn_unref) { @@ -1680,7 +1669,6 @@ static void tcp_send_zwp(struct k_work *work) struct k_work_delayable *dwork = k_work_delayable_from_work(work); struct tcp *conn = CONTAINER_OF(dwork, struct tcp, persist_timer); - /* take the lock to prevent a race-condition with tcp_conn_unref */ k_mutex_lock(&conn->lock, K_FOREVER); (void)tcp_out_ext(conn, ACK, NULL, conn->seq - 1); @@ -1704,7 +1692,6 @@ static void tcp_send_zwp(struct k_work *work) &tcp_work_q, &conn->persist_timer, K_MSEC(timeout)); } - /* release the lock only after possible scheduling of work */ k_mutex_unlock(&conn->lock); } @@ -1713,12 +1700,10 @@ static void tcp_send_ack(struct k_work *work) struct k_work_delayable *dwork = k_work_delayable_from_work(work); struct tcp *conn = CONTAINER_OF(dwork, struct tcp, ack_timer); - /* take the lock to prevent a race-condition with tcp_conn_unref */ k_mutex_lock(&conn->lock, K_FOREVER); tcp_out(conn, ACK); - /* release the lock only after possible scheduling of work */ k_mutex_unlock(&conn->lock); } @@ -1793,6 +1778,7 @@ static struct tcp *tcp_conn_alloc(void) k_work_init_delayable(&conn->recv_queue_timer, tcp_cleanup_recv_queue); k_work_init_delayable(&conn->persist_timer, tcp_send_zwp); k_work_init_delayable(&conn->ack_timer, tcp_send_ack); + k_work_init(&conn->conn_release, tcp_conn_release); tcp_conn_ref(conn); diff --git a/subsys/net/ip/tcp_private.h b/subsys/net/ip/tcp_private.h index 7dddf75c7b7..6d13c8cf6fd 100644 --- a/subsys/net/ip/tcp_private.h +++ b/subsys/net/ip/tcp_private.h @@ -274,6 +274,7 @@ struct tcp { /* TCP connection */ struct k_work_delayable timewait_timer; struct k_work_delayable persist_timer; struct k_work_delayable ack_timer; + struct k_work conn_release; union { /* Because FIN and establish timers are never happening From 95155c1fae3ed89863ea91c8604eca6b0e393a18 Mon Sep 17 00:00:00 2001 From: Robert Lubos Date: Tue, 28 Nov 2023 17:48:03 +0100 Subject: [PATCH 0495/3723] tests: net: tcp: Add small delay when checking context dereference Since the TCP context (and thus net_context) is not dereferenced directly from the test thread anymore, add a small delay so that TCP work queue have a chance to run, before checking net_context count or reusing the port on new allocation. Signed-off-by: Robert Lubos --- tests/net/socket/tcp/src/main.c | 8 +++----- tests/net/tcp/src/main.c | 3 +++ 2 files changed, 6 insertions(+), 5 deletions(-) diff --git a/tests/net/socket/tcp/src/main.c b/tests/net/socket/tcp/src/main.c index 90de450ac11..30f49c7f0bc 100644 --- a/tests/net/socket/tcp/src/main.c +++ b/tests/net/socket/tcp/src/main.c @@ -1060,12 +1060,10 @@ ZTEST(net_socket_tcp, test_connect_timeout) test_close(c_sock); - /* If we have preemptive option set, then sleep here in order to allow - * other part of the system to run and update itself. + /* Sleep here in order to allow other part of the system to run and + * update itself. */ - if (IS_ENABLED(CONFIG_NET_TC_THREAD_PREEMPTIVE)) { - k_sleep(K_MSEC(10)); - } + k_sleep(K_MSEC(10)); /* After the client socket closing, the context count should be 0 */ net_context_foreach(calc_net_context, &count_after); diff --git a/tests/net/tcp/src/main.c b/tests/net/tcp/src/main.c index aafa3937ce0..e935cb4d40e 100644 --- a/tests/net/tcp/src/main.c +++ b/tests/net/tcp/src/main.c @@ -1718,6 +1718,9 @@ static void check_rst_succeed(struct net_context *ctx, net_context_put(ctx); net_context_put(accepted_ctx); + + /* Let other threads run (so the TCP context is actually freed) */ + k_msleep(10); } ZTEST(net_tcp, test_client_invalid_rst) From 5bbf898905a171e198f994265371f855102f6dec Mon Sep 17 00:00:00 2001 From: Robert Lubos Date: Tue, 28 Nov 2023 17:50:52 +0100 Subject: [PATCH 0496/3723] tests: net: socket: tcp: Fix FD leak in fionread tests Socket close was missing in fionread tests, causing file descriptor leak. Signed-off-by: Robert Lubos --- tests/net/socket/tcp/src/main.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/tests/net/socket/tcp/src/main.c b/tests/net/socket/tcp/src/main.c index 30f49c7f0bc..6ab2ca97c70 100644 --- a/tests/net/socket/tcp/src/main.c +++ b/tests/net/socket/tcp/src/main.c @@ -2189,6 +2189,10 @@ static void test_ioctl_fionread_common(int af) zassert_ok(ioctl(fd[i], ZFD_IOCTL_FIONREAD, &avail)); zassert_equal(0, avail, "exp: %d: act: %d", 0, avail); } + + close(fd[SERVER]); + close(fd[CLIENT]); + close(fd[ACCEPT]); } ZTEST(net_socket_tcp, test_ioctl_fionread_v4) From 283a9ef95969cc5c7e1b9e8679e91446be3242f7 Mon Sep 17 00:00:00 2001 From: Aastha Grover Date: Fri, 9 Jun 2023 17:10:20 -0400 Subject: [PATCH 0497/3723] tests: cpp: Exclude cpp2B testcase for xt-clang toolchain c++2B standard is not supported for xt clang compiler so exclude cpp2B testcase for xt-clang toolchain. Signed-off-by: Aastha Grover Signed-off-by: Anas Nashif --- tests/lib/cpp/cxx/testcase.yaml | 2 ++ 1 file changed, 2 insertions(+) diff --git a/tests/lib/cpp/cxx/testcase.yaml b/tests/lib/cpp/cxx/testcase.yaml index 77d1b06dbb2..404d9a3a970 100644 --- a/tests/lib/cpp/cxx/testcase.yaml +++ b/tests/lib/cpp/cxx/testcase.yaml @@ -60,6 +60,8 @@ tests: - CONFIG_STD_CPP20=y cpp.main.cpp2B: arch_exclude: posix + toolchain_exclude: + - xt-clang build_only: true extra_configs: - CONFIG_STD_CPP2B=y From 40c2e08e821101ec067a2bd5aec96cddf00e2ef3 Mon Sep 17 00:00:00 2001 From: Marc Herbert Date: Tue, 28 Nov 2023 21:39:57 +0000 Subject: [PATCH 0498/3723] xcc/cmake: don't discard stderr; don't (ever!) use ERROR_QUIET Remove ERROR_QUIET which is a bad idea 99.9% of the time. When any program makes the effort of using stderr, we _really_ don't want to lose those error messages. Using ERROR_QUIET in XCC is even worse because of how high maintenance XCC is; see another example in 4cba9e6d425e ("cmake: warn the user that the toolchain cache hides errors") No one expects error messages to be silently discarded and especially not people not familiar with CMake (= most people); so hiding the following error stalled progress for a couple days: ``` Error: there is no Xtensa core registered as the default. You need to either specify the name of a registered Xtensa core (with the --xtensa-core option or the XTENSA_CORE environment variable) or specify a different registry of Xtensa cores (with the --xtensa-system option or the XTENSA_SYSTEM environment variable). Executing the below command failed. Are permissions set correctly? ``` Also capture stdout and print it on failure because you never know. Indent the ` ${CMAKE_C_COMPILER} --version` line in the error message so CMake does not split that line. Signed-off-by: Marc Herbert --- cmake/compiler/xcc/generic.cmake | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/cmake/compiler/xcc/generic.cmake b/cmake/compiler/xcc/generic.cmake index ca96eb93809..c9cc643e3dd 100644 --- a/cmake/compiler/xcc/generic.cmake +++ b/cmake/compiler/xcc/generic.cmake @@ -18,12 +18,12 @@ endif() execute_process( COMMAND ${CMAKE_C_COMPILER} --version RESULT_VARIABLE ret - OUTPUT_QUIET - ERROR_QUIET + OUTPUT_VARIABLE stdoutput ) if(ret) message(FATAL_ERROR "Executing the below command failed. Are permissions set correctly? -'${CMAKE_C_COMPILER} --version' + ${CMAKE_C_COMPILER} --version + ${stdoutput} " ) endif() From 8252ec7570b7b7182880d2982d70858860156e98 Mon Sep 17 00:00:00 2001 From: Pieter De Gendt Date: Wed, 29 Nov 2023 10:02:10 +0100 Subject: [PATCH 0499/3723] net: lib: coap: Translate handler errors to CoAP response codes The CoAP request handler returns errno codes in the following cases: * ENOENT if no handler found; respond with 4.04 * ENOTSUP if an unknown request code received; respond with 4.00 * EPERM no handler found for the method; respond with 4.05 Signed-off-by: Pieter De Gendt --- subsys/net/lib/coap/coap_server.c | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/subsys/net/lib/coap/coap_server.c b/subsys/net/lib/coap/coap_server.c index 4b4f1719f46..ac179f5545e 100644 --- a/subsys/net/lib/coap/coap_server.c +++ b/subsys/net/lib/coap/coap_server.c @@ -220,6 +220,19 @@ static int coap_server_process(int sock_fd) COAP_SERVICE_RESOURCE_COUNT(service), options, opt_num, &client_addr, client_addr_len); + /* Translate errors to response codes */ + switch (ret) { + case -ENOENT: + ret = COAP_RESPONSE_CODE_NOT_FOUND; + break; + case -ENOTSUP: + ret = COAP_RESPONSE_CODE_BAD_REQUEST; + break; + case -EPERM: + ret = COAP_RESPONSE_CODE_NOT_ALLOWED; + break; + } + /* Shortcut for replying a code without a body */ if (ret > 0 && type == COAP_TYPE_CON) { /* Minimal sized ack buffer */ From 222fa42609fdec71896d692aad177f8fa34afbc1 Mon Sep 17 00:00:00 2001 From: Robert Lubos Date: Wed, 29 Nov 2023 10:45:13 +0100 Subject: [PATCH 0500/3723] net: icmp: Fix Echo Replies with unspecified address Fix two issues with sending ICMP Echo Reply for requests sent for multicast address: * Use the originator IP address instead of multicast when selecting source address for the reply * In case no address match is found, drop the packet, instead of replying with unspecified address. Signed-off-by: Robert Lubos --- subsys/net/ip/icmpv4.c | 7 ++++++- subsys/net/ip/icmpv6.c | 7 ++++++- 2 files changed, 12 insertions(+), 2 deletions(-) diff --git a/subsys/net/ip/icmpv4.c b/subsys/net/ip/icmpv4.c index 0ea8d40ba46..308ebd21256 100644 --- a/subsys/net/ip/icmpv4.c +++ b/subsys/net/ip/icmpv4.c @@ -455,7 +455,12 @@ static int icmpv4_handle_echo_request(struct net_icmp_ctx *ctx, net_ipv4_is_addr_bcast(net_pkt_iface(pkt), (struct in_addr *)ip_hdr->dst)) { src = net_if_ipv4_select_src_addr(net_pkt_iface(pkt), - (struct in_addr *)ip_hdr->dst); + (struct in_addr *)ip_hdr->src); + + if (net_ipv4_is_addr_unspecified(src)) { + NET_DBG("DROP: No src address match"); + goto drop; + } } else { src = (struct in_addr *)ip_hdr->dst; } diff --git a/subsys/net/ip/icmpv6.c b/subsys/net/ip/icmpv6.c index 65c01a510c7..b380a5f4558 100644 --- a/subsys/net/ip/icmpv6.c +++ b/subsys/net/ip/icmpv6.c @@ -130,7 +130,12 @@ static int icmpv6_handle_echo_request(struct net_icmp_ctx *ctx, if (net_ipv6_is_addr_mcast((struct in6_addr *)ip_hdr->dst)) { src = net_if_ipv6_select_src_addr(net_pkt_iface(pkt), - (struct in6_addr *)ip_hdr->dst); + (struct in6_addr *)ip_hdr->src); + + if (net_ipv6_is_addr_unspecified(src)) { + NET_DBG("DROP: No src address match"); + goto drop; + } } else { src = (struct in6_addr *)ip_hdr->dst; } From c8f4455ef8f9ac781dd0aca77de739b605b80642 Mon Sep 17 00:00:00 2001 From: Fabio Baltieri Date: Wed, 29 Nov 2023 15:41:18 +0000 Subject: [PATCH 0501/3723] tests: input: api: dedup some test properties Move some common properties in the common field. Signed-off-by: Fabio Baltieri --- tests/subsys/input/api/testcase.yaml | 11 +++++------ 1 file changed, 5 insertions(+), 6 deletions(-) diff --git a/tests/subsys/input/api/testcase.yaml b/tests/subsys/input/api/testcase.yaml index f92bf450946..9ed7d8bd068 100644 --- a/tests/subsys/input/api/testcase.yaml +++ b/tests/subsys/input/api/testcase.yaml @@ -1,16 +1,15 @@ # SPDX-License-Identifier: Apache-2.0 +common: + tags: + - input + integration_platforms: + - native_posix tests: input.api.thread: - tags: input - integration_platforms: - - native_posix extra_configs: - CONFIG_INPUT_MODE_THREAD=y - CONFIG_INPUT_THREAD_STACK_SIZE=1024 input.api.synchronous: - tags: input - integration_platforms: - - native_posix extra_configs: - CONFIG_INPUT_MODE_SYNCHRONOUS=y From de1bfd6a6eeb9973c702a12e586e287da156b849 Mon Sep 17 00:00:00 2001 From: Francois Ramu Date: Fri, 24 Nov 2023 17:18:35 +0100 Subject: [PATCH 0502/3723] drivers: adc: stm32 adc fixing calibration for the stm32F1 serie Configure the sw trigger just after calibration So the conversion can start on regular channel on the software control bit. Signed-off-by: Francois Ramu --- drivers/adc/adc_stm32.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/adc/adc_stm32.c b/drivers/adc/adc_stm32.c index 767308a396b..1710ec011bc 100644 --- a/drivers/adc/adc_stm32.c +++ b/drivers/adc/adc_stm32.c @@ -1379,6 +1379,7 @@ static int adc_stm32_init(const struct device *dev) #if defined(HAS_CALIBRATION) adc_stm32_calibrate(dev); + LL_ADC_REG_SetTriggerSource(adc, LL_ADC_REG_TRIG_SOFTWARE); #endif /* HAS_CALIBRATION */ adc_context_unlock_unconditionally(&data->ctx); From 3d29c9fe546cd42554becee9dddcbe2e9e73d5cc Mon Sep 17 00:00:00 2001 From: Qipeng Zha Date: Tue, 28 Nov 2023 12:17:42 +0800 Subject: [PATCH 0503/3723] kernel: timeout: fix issue with z_timeout_expires - issue found with Ztest case of test_thread_timeout_remaining_expires on Intel ISH platform when adjust CONFIG_SYS_CLOCK_TICKS_PER_SEC to 10k. - timeout_rem() return exact remaining ticks which is calibrated by decrease elapsed(), while z_timeout_expires try to get expire ticks to be timeout using current tick as base, so need get exact current ticks by plus elasped(). Signed-off-by: Qipeng Zha --- kernel/timeout.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/kernel/timeout.c b/kernel/timeout.c index 16429bbba20..29f15898035 100644 --- a/kernel/timeout.c +++ b/kernel/timeout.c @@ -190,7 +190,7 @@ k_ticks_t z_timeout_expires(const struct _timeout *timeout) k_ticks_t ticks = 0; K_SPINLOCK(&timeout_lock) { - ticks = curr_tick + timeout_rem(timeout); + ticks = curr_tick + timeout_rem(timeout) + elapsed(); } return ticks; From 2094183d8113c3ad89840cd4b3dd5eff185ecbcd Mon Sep 17 00:00:00 2001 From: Magdalena Kasenberg Date: Tue, 31 Oct 2023 20:30:33 +0100 Subject: [PATCH 0504/3723] bluetooth: bap: Fix shift of BIS_Sync parameter of notification bis_sync contains BIS index bitfield which is shifted by 1 bit relative to the BIS_Sync parameter of Broadcast Receive State notification. Signed-off-by: Magdalena Kasenberg --- subsys/bluetooth/audio/bap_scan_delegator.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/subsys/bluetooth/audio/bap_scan_delegator.c b/subsys/bluetooth/audio/bap_scan_delegator.c index 3cef96bd1b8..3e31408b450 100644 --- a/subsys/bluetooth/audio/bap_scan_delegator.c +++ b/subsys/bluetooth/audio/bap_scan_delegator.c @@ -177,7 +177,7 @@ static void net_buf_put_recv_state(const struct bass_recv_state_internal *recv_s for (int i = 0; i < state->num_subgroups; i++) { const struct bt_bap_scan_delegator_subgroup *subgroup = &state->subgroups[i]; - (void)net_buf_simple_add_le32(&read_buf, subgroup->bis_sync); + (void)net_buf_simple_add_le32(&read_buf, subgroup->bis_sync >> 1); (void)net_buf_simple_add_u8(&read_buf, subgroup->metadata_len); (void)net_buf_simple_add_mem(&read_buf, subgroup->metadata, subgroup->metadata_len); From c94cd30cecbf8247e1f1c776d065a07b59b0fc25 Mon Sep 17 00:00:00 2001 From: Magdalena Kasenberg Date: Tue, 31 Oct 2023 20:31:48 +0100 Subject: [PATCH 0505/3723] bluetooth: bap: Fix shift of requested_bis_sync The BIS_Sync bitfiled received over the air in Add Source and Modify Source operations uses BIT(0) for BIS Index 1. Shift it when storing it to match bis_sync bitfield where BIS Index 1 is at BIT(1). Signed-off-by: Magdalena Kasenberg --- subsys/bluetooth/audio/bap_broadcast_assistant.c | 6 ++++-- subsys/bluetooth/audio/bap_scan_delegator.c | 9 +++++++++ 2 files changed, 13 insertions(+), 2 deletions(-) diff --git a/subsys/bluetooth/audio/bap_broadcast_assistant.c b/subsys/bluetooth/audio/bap_broadcast_assistant.c index 36c8c46171f..07f83bd7c13 100644 --- a/subsys/bluetooth/audio/bap_broadcast_assistant.c +++ b/subsys/bluetooth/audio/bap_broadcast_assistant.c @@ -768,7 +768,8 @@ int bt_bap_broadcast_assistant_add_src(struct bt_conn *conn, subgroup = net_buf_simple_add(&cp_buf, subgroup_size); - subgroup->bis_sync = param->subgroups[i].bis_sync; + /* The BIS Index bitfield to be sent must use BIT(0) for BIS Index 1 */ + subgroup->bis_sync = param->subgroups[i].bis_sync >> 1; CHECKIF(param->pa_sync == 0 && subgroup->bis_sync != 0) { LOG_DBG("Only syncing to BIS is not allowed"); @@ -860,7 +861,8 @@ int bt_bap_broadcast_assistant_mod_src(struct bt_conn *conn, } subgroup = net_buf_simple_add(&cp_buf, subgroup_size); - subgroup->bis_sync = param->subgroups[i].bis_sync; + /* The BIS Index bitfield to be sent must use BIT(0) for BIS Index 1 */ + subgroup->bis_sync = param->subgroups[i].bis_sync >> 1; CHECKIF(param->pa_sync == 0 && subgroup->bis_sync != 0) { LOG_DBG("Only syncing to BIS is not allowed"); diff --git a/subsys/bluetooth/audio/bap_scan_delegator.c b/subsys/bluetooth/audio/bap_scan_delegator.c index 3e31408b450..296a8f47f65 100644 --- a/subsys/bluetooth/audio/bap_scan_delegator.c +++ b/subsys/bluetooth/audio/bap_scan_delegator.c @@ -514,6 +514,10 @@ static int scan_delegator_add_source(struct bt_conn *conn, } internal_state->requested_bis_sync[i] = net_buf_simple_pull_le32(buf); + if (internal_state->requested_bis_sync[i] != BT_BAP_BIS_SYNC_NO_PREF) { + /* Received BIS Index bitfield uses BIT(0) for BIS Index 1 */ + internal_state->requested_bis_sync[i] <<= 1; + } if (internal_state->requested_bis_sync[i] && pa_sync == BT_BAP_BASS_PA_REQ_NO_SYNC) { @@ -670,6 +674,11 @@ static int scan_delegator_mod_src(struct bt_conn *conn, old_bis_sync_req = internal_state->requested_bis_sync[i]; internal_state->requested_bis_sync[i] = net_buf_simple_pull_le32(buf); + if (internal_state->requested_bis_sync[i] != BT_BAP_BIS_SYNC_NO_PREF) { + /* Received BIS Index bitfield uses BIT(0) for BIS Index 1 */ + internal_state->requested_bis_sync[i] <<= 1; + } + if (internal_state->requested_bis_sync[i] && pa_sync == BT_BAP_BASS_PA_REQ_NO_SYNC) { LOG_DBG("Cannot sync to BIS without PA"); From 0f6a3d033448249c9f97a796a84076982180ce1f Mon Sep 17 00:00:00 2001 From: Alberto Escolar Piedras Date: Tue, 28 Nov 2023 11:05:19 +0100 Subject: [PATCH 0506/3723] boards native: Switch default testing platform native_posix->native_sim Set native_sim as the default testing platform instead of native_posix. This continues the agreed strategy described in #58305 Signed-off-by: Alberto Escolar Piedras --- boards/posix/native_posix/native_posix.yaml | 2 -- boards/posix/native_sim/native_sim.yaml | 2 ++ 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/boards/posix/native_posix/native_posix.yaml b/boards/posix/native_posix/native_posix.yaml index a1fb897eb75..a7899f1fccd 100644 --- a/boards/posix/native_posix/native_posix.yaml +++ b/boards/posix/native_posix/native_posix.yaml @@ -19,6 +19,4 @@ supported: - spi - gpio - rtc -testing: - default: true vendor: zephyr diff --git a/boards/posix/native_sim/native_sim.yaml b/boards/posix/native_sim/native_sim.yaml index e2defe1ce40..999b52aa16b 100644 --- a/boards/posix/native_sim/native_sim.yaml +++ b/boards/posix/native_sim/native_sim.yaml @@ -19,4 +19,6 @@ supported: - spi - gpio - rtc +testing: + default: true vendor: zephyr From 6fce48b02821882009f7c78b0b3c7e54180ab24c Mon Sep 17 00:00:00 2001 From: Alberto Escolar Piedras Date: Tue, 28 Nov 2023 11:18:46 +0100 Subject: [PATCH 0507/3723] tests/drivers/flash_simulator: Switch to native_sim Switch the native overlays to be based on the native_sim one, and set native_sim as the integration_platform instead of native_posix Signed-off-by: Alberto Escolar Piedras --- .../boards/native_64_ev_0x00.overlay | 7 +++++++ ..._64_ev_0x00.overlay => native_ev_0x00.overlay} | 0 .../flash_simulator/boards/native_posix.overlay | 8 ++------ .../boards/native_posix_ev_0x00.overlay | 15 --------------- .../flash_simulator/boards/native_sim.overlay | 8 ++++++-- tests/drivers/flash_simulator/testcase.yaml | 12 ++++++------ 6 files changed, 21 insertions(+), 29 deletions(-) create mode 100644 tests/drivers/flash_simulator/boards/native_64_ev_0x00.overlay rename tests/drivers/flash_simulator/boards/{native_posix_64_ev_0x00.overlay => native_ev_0x00.overlay} (100%) delete mode 100644 tests/drivers/flash_simulator/boards/native_posix_ev_0x00.overlay diff --git a/tests/drivers/flash_simulator/boards/native_64_ev_0x00.overlay b/tests/drivers/flash_simulator/boards/native_64_ev_0x00.overlay new file mode 100644 index 00000000000..27d39edbe56 --- /dev/null +++ b/tests/drivers/flash_simulator/boards/native_64_ev_0x00.overlay @@ -0,0 +1,7 @@ +/* + * Copyright (c) 2020 Nordic Semiconductor ASA + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include "native_ev_0x00.overlay" diff --git a/tests/drivers/flash_simulator/boards/native_posix_64_ev_0x00.overlay b/tests/drivers/flash_simulator/boards/native_ev_0x00.overlay similarity index 100% rename from tests/drivers/flash_simulator/boards/native_posix_64_ev_0x00.overlay rename to tests/drivers/flash_simulator/boards/native_ev_0x00.overlay diff --git a/tests/drivers/flash_simulator/boards/native_posix.overlay b/tests/drivers/flash_simulator/boards/native_posix.overlay index d1964951d65..59b29bd8512 100644 --- a/tests/drivers/flash_simulator/boards/native_posix.overlay +++ b/tests/drivers/flash_simulator/boards/native_posix.overlay @@ -1,11 +1,7 @@ /* - * Copyright (c) 2020 Jan Van Winkel + * Copyright (c) 2023 Nordic Semiconductor ASA * * SPDX-License-Identifier: Apache-2.0 */ -&flash0 { - erase-block-size = <1024>; - write-block-size = <4>; - reg = <0x00000000 DT_SIZE_K(1024)>; -}; +#include "native_sim.overlay" diff --git a/tests/drivers/flash_simulator/boards/native_posix_ev_0x00.overlay b/tests/drivers/flash_simulator/boards/native_posix_ev_0x00.overlay deleted file mode 100644 index 5a7030b3937..00000000000 --- a/tests/drivers/flash_simulator/boards/native_posix_ev_0x00.overlay +++ /dev/null @@ -1,15 +0,0 @@ -/* - * Copyright (c) 2020 Nordic Semiconductor ASA - * - * SPDX-License-Identifier: Apache-2.0 - */ - -&flashcontroller0 { - erase-value = < 0x00 >; -}; - -&flash0 { - erase-block-size = <1024>; - write-block-size = <4>; - reg = <0x00000000 DT_SIZE_K(1024)>; -}; diff --git a/tests/drivers/flash_simulator/boards/native_sim.overlay b/tests/drivers/flash_simulator/boards/native_sim.overlay index 3467d3e6b38..d1964951d65 100644 --- a/tests/drivers/flash_simulator/boards/native_sim.overlay +++ b/tests/drivers/flash_simulator/boards/native_sim.overlay @@ -1,7 +1,11 @@ /* - * Copyright (c) 2023 Nordic Semiconductor ASA + * Copyright (c) 2020 Jan Van Winkel * * SPDX-License-Identifier: Apache-2.0 */ -#include "native_posix.overlay" +&flash0 { + erase-block-size = <1024>; + write-block-size = <4>; + reg = <0x00000000 DT_SIZE_K(1024)>; +}; diff --git a/tests/drivers/flash_simulator/testcase.yaml b/tests/drivers/flash_simulator/testcase.yaml index c963a8e99fb..04b435c4942 100644 --- a/tests/drivers/flash_simulator/testcase.yaml +++ b/tests/drivers/flash_simulator/testcase.yaml @@ -18,13 +18,13 @@ tests: platform_allow: qemu_x86 integration_platforms: - qemu_x86 - drivers.flash.flash_simulator.posix_erase_value_0x00: - extra_args: DTC_OVERLAY_FILE=boards/native_posix_ev_0x00.overlay + drivers.flash.flash_simulator.native_erase_value_0x00: + extra_args: DTC_OVERLAY_FILE=boards/native_ev_0x00.overlay platform_allow: native_posix native_sim integration_platforms: - - native_posix - drivers.flash.flash_simulator.posix_64_erase_value_0x00: - extra_args: DTC_OVERLAY_FILE=boards/native_posix_64_ev_0x00.overlay + - native_sim + drivers.flash.flash_simulator.native_64_erase_value_0x00: + extra_args: DTC_OVERLAY_FILE=boards/native_64_ev_0x00.overlay platform_allow: native_posix_64 native_sim_64 integration_platforms: - - native_posix_64 + - native_sim_64 From 188cdd95c5595bc40b5425abb4535d28ffa764cf Mon Sep 17 00:00:00 2001 From: Alberto Escolar Piedras Date: Tue, 28 Nov 2023 11:29:57 +0100 Subject: [PATCH 0508/3723] twister tests: Replace native_posix with native_sim As native_sim is replacing native_posix overall and becoming the default test platform. Signed-off-by: Alberto Escolar Piedras --- .../tests/dummy/agnostic/group1/subgroup1/test_data.yaml | 4 ++-- .../tests/dummy/agnostic/group1/subgroup2/test_data.yaml | 4 ++-- .../test_data/tests/dummy/agnostic/group2/test_data.yaml | 4 ++-- 3 files changed, 6 insertions(+), 6 deletions(-) diff --git a/scripts/tests/twister_blackbox/test_data/tests/dummy/agnostic/group1/subgroup1/test_data.yaml b/scripts/tests/twister_blackbox/test_data/tests/dummy/agnostic/group1/subgroup1/test_data.yaml index 1e468dc9b97..5bd1d3d4b06 100644 --- a/scripts/tests/twister_blackbox/test_data/tests/dummy/agnostic/group1/subgroup1/test_data.yaml +++ b/scripts/tests/twister_blackbox/test_data/tests/dummy/agnostic/group1/subgroup1/test_data.yaml @@ -1,11 +1,11 @@ tests: dummy.agnostic.group1.subgroup1: platform_allow: - - native_posix + - native_sim - qemu_x86 - qemu_x86_64 integration_platforms: - - native_posix + - native_sim tags: - agnostic - subgrouped diff --git a/scripts/tests/twister_blackbox/test_data/tests/dummy/agnostic/group1/subgroup2/test_data.yaml b/scripts/tests/twister_blackbox/test_data/tests/dummy/agnostic/group1/subgroup2/test_data.yaml index 35f48d68648..9bf2f046885 100644 --- a/scripts/tests/twister_blackbox/test_data/tests/dummy/agnostic/group1/subgroup2/test_data.yaml +++ b/scripts/tests/twister_blackbox/test_data/tests/dummy/agnostic/group1/subgroup2/test_data.yaml @@ -2,11 +2,11 @@ tests: dummy.agnostic.group1.subgroup2: build_only: true platform_allow: - - native_posix + - native_sim - qemu_x86 - qemu_x86_64 integration_platforms: - - native_posix + - native_sim tags: - agnostic - subgrouped diff --git a/scripts/tests/twister_blackbox/test_data/tests/dummy/agnostic/group2/test_data.yaml b/scripts/tests/twister_blackbox/test_data/tests/dummy/agnostic/group2/test_data.yaml index f0aa17acbde..f53a0d29948 100644 --- a/scripts/tests/twister_blackbox/test_data/tests/dummy/agnostic/group2/test_data.yaml +++ b/scripts/tests/twister_blackbox/test_data/tests/dummy/agnostic/group2/test_data.yaml @@ -1,9 +1,9 @@ tests: dummy.agnostic.group2: platform_allow: - - native_posix + - native_sim - qemu_x86 - qemu_x86_64 integration_platforms: - - native_posix + - native_sim tags: agnostic From f591d0a54dda5665d866c2343028a78e1a520241 Mon Sep 17 00:00:00 2001 From: Alberto Escolar Piedras Date: Tue, 28 Nov 2023 11:41:54 +0100 Subject: [PATCH 0509/3723] tests/lib/cmsis_dsp: Switch integration_platform to native_sim Switch integration_platform from native_posix to native_sim Signed-off-by: Alberto Escolar Piedras --- tests/lib/cmsis_dsp/bayes/testcase.yaml | 2 +- tests/lib/cmsis_dsp/complexmath/testcase.yaml | 2 +- tests/lib/cmsis_dsp/distance/testcase.yaml | 2 +- tests/lib/cmsis_dsp/fastmath/testcase.yaml | 2 +- tests/lib/cmsis_dsp/filtering/testcase.yaml | 8 ++++---- .../lib/cmsis_dsp/interpolation/testcase.yaml | 2 +- tests/lib/cmsis_dsp/matrix/testcase.yaml | 20 +++++++++---------- .../cmsis_dsp/quaternionmath/testcase.yaml | 2 +- tests/lib/cmsis_dsp/statistics/testcase.yaml | 2 +- tests/lib/cmsis_dsp/support/testcase.yaml | 2 +- tests/lib/cmsis_dsp/svm/testcase.yaml | 2 +- tests/lib/cmsis_dsp/transform/testcase.yaml | 16 +++++++-------- 12 files changed, 31 insertions(+), 31 deletions(-) diff --git a/tests/lib/cmsis_dsp/bayes/testcase.yaml b/tests/lib/cmsis_dsp/bayes/testcase.yaml index 8bc620caac7..121a8785532 100644 --- a/tests/lib/cmsis_dsp/bayes/testcase.yaml +++ b/tests/lib/cmsis_dsp/bayes/testcase.yaml @@ -6,7 +6,7 @@ tests: - frdm_k64f - sam_e70_xplained - mps2_an521 - - native_posix + - native_sim tags: cmsis_dsp min_flash: 64 min_ram: 32 diff --git a/tests/lib/cmsis_dsp/complexmath/testcase.yaml b/tests/lib/cmsis_dsp/complexmath/testcase.yaml index 13f98d88b2b..9a2c847e400 100644 --- a/tests/lib/cmsis_dsp/complexmath/testcase.yaml +++ b/tests/lib/cmsis_dsp/complexmath/testcase.yaml @@ -6,7 +6,7 @@ tests: - frdm_k64f - sam_e70_xplained - mps2_an521 - - native_posix + - native_sim tags: cmsis_dsp min_flash: 128 min_ram: 144 diff --git a/tests/lib/cmsis_dsp/distance/testcase.yaml b/tests/lib/cmsis_dsp/distance/testcase.yaml index cbc956055fb..2e00016efb3 100644 --- a/tests/lib/cmsis_dsp/distance/testcase.yaml +++ b/tests/lib/cmsis_dsp/distance/testcase.yaml @@ -6,7 +6,7 @@ tests: - frdm_k64f - sam_e70_xplained - mps2_an521 - - native_posix + - native_sim tags: cmsis_dsp min_flash: 64 min_ram: 32 diff --git a/tests/lib/cmsis_dsp/fastmath/testcase.yaml b/tests/lib/cmsis_dsp/fastmath/testcase.yaml index d63115edc42..ded000fe752 100644 --- a/tests/lib/cmsis_dsp/fastmath/testcase.yaml +++ b/tests/lib/cmsis_dsp/fastmath/testcase.yaml @@ -6,7 +6,7 @@ tests: - frdm_k64f - sam_e70_xplained - mps2_an521 - - native_posix + - native_sim tags: cmsis_dsp min_flash: 128 min_ram: 64 diff --git a/tests/lib/cmsis_dsp/filtering/testcase.yaml b/tests/lib/cmsis_dsp/filtering/testcase.yaml index 115367cdfc4..84662306db5 100644 --- a/tests/lib/cmsis_dsp/filtering/testcase.yaml +++ b/tests/lib/cmsis_dsp/filtering/testcase.yaml @@ -14,7 +14,7 @@ tests: - frdm_k64f - sam_e70_xplained - mps2_an521 - - native_posix + - native_sim tags: cmsis_dsp min_flash: 128 min_ram: 64 @@ -43,7 +43,7 @@ tests: - frdm_k64f - sam_e70_xplained - mps2_an521 - - native_posix + - native_sim tags: cmsis_dsp min_flash: 128 min_ram: 64 @@ -72,7 +72,7 @@ tests: - frdm_k64f - sam_e70_xplained - mps2_an521 - - native_posix + - native_sim tags: cmsis_dsp min_flash: 128 min_ram: 64 @@ -101,7 +101,7 @@ tests: - frdm_k64f - sam_e70_xplained - mps2_an521 - - native_posix + - native_sim tags: cmsis_dsp min_flash: 256 min_ram: 64 diff --git a/tests/lib/cmsis_dsp/interpolation/testcase.yaml b/tests/lib/cmsis_dsp/interpolation/testcase.yaml index 358a683c7ce..06973fa2158 100644 --- a/tests/lib/cmsis_dsp/interpolation/testcase.yaml +++ b/tests/lib/cmsis_dsp/interpolation/testcase.yaml @@ -6,7 +6,7 @@ tests: - frdm_k64f - sam_e70_xplained - mps2_an521 - - native_posix + - native_sim tags: cmsis_dsp min_flash: 128 min_ram: 64 diff --git a/tests/lib/cmsis_dsp/matrix/testcase.yaml b/tests/lib/cmsis_dsp/matrix/testcase.yaml index 4a6912505e0..04411e4c02f 100644 --- a/tests/lib/cmsis_dsp/matrix/testcase.yaml +++ b/tests/lib/cmsis_dsp/matrix/testcase.yaml @@ -11,7 +11,7 @@ tests: - frdm_k64f - sam_e70_xplained - mps2_an521 - - native_posix + - native_sim tags: cmsis_dsp min_flash: 128 min_ram: 64 @@ -40,7 +40,7 @@ tests: - frdm_k64f - sam_e70_xplained - mps2_an521 - - native_posix + - native_sim tags: cmsis_dsp min_flash: 128 min_ram: 64 @@ -69,7 +69,7 @@ tests: - frdm_k64f - sam_e70_xplained - mps2_an521 - - native_posix + - native_sim tags: cmsis_dsp min_flash: 128 min_ram: 64 @@ -126,7 +126,7 @@ tests: - frdm_k64f - sam_e70_xplained - mps2_an521 - - native_posix + - native_sim tags: cmsis_dsp min_flash: 128 min_ram: 64 @@ -155,7 +155,7 @@ tests: - frdm_k64f - sam_e70_xplained - mps2_an521 - - native_posix + - native_sim tags: cmsis_dsp min_flash: 128 min_ram: 72 @@ -184,7 +184,7 @@ tests: - frdm_k64f - sam_e70_xplained - mps2_an521 - - native_posix + - native_sim tags: cmsis_dsp platform_exclude: frdm_kw41z min_flash: 128 @@ -215,7 +215,7 @@ tests: - frdm_k64f - sam_e70_xplained - mps2_an521 - - native_posix + - native_sim tags: cmsis_dsp platform_exclude: frdm_kw41z min_flash: 128 @@ -246,7 +246,7 @@ tests: - frdm_k64f - sam_e70_xplained - mps2_an521 - - native_posix + - native_sim tags: cmsis_dsp platform_exclude: frdm_kw41z min_flash: 128 @@ -305,7 +305,7 @@ tests: - frdm_k64f - sam_e70_xplained - mps2_an521 - - native_posix + - native_sim tags: cmsis_dsp platform_exclude: frdm_kw41z min_flash: 128 @@ -336,7 +336,7 @@ tests: - frdm_k64f - sam_e70_xplained - mps2_an521 - - native_posix + - native_sim tags: cmsis_dsp platform_exclude: frdm_kw41z min_flash: 128 diff --git a/tests/lib/cmsis_dsp/quaternionmath/testcase.yaml b/tests/lib/cmsis_dsp/quaternionmath/testcase.yaml index 3d005e8a343..07e747f388f 100644 --- a/tests/lib/cmsis_dsp/quaternionmath/testcase.yaml +++ b/tests/lib/cmsis_dsp/quaternionmath/testcase.yaml @@ -6,7 +6,7 @@ tests: - frdm_k64f - sam_e70_xplained - mps2_an521 - - native_posix + - native_sim tags: cmsis_dsp min_flash: 128 min_ram: 64 diff --git a/tests/lib/cmsis_dsp/statistics/testcase.yaml b/tests/lib/cmsis_dsp/statistics/testcase.yaml index 9082e8edf5f..473f030d505 100644 --- a/tests/lib/cmsis_dsp/statistics/testcase.yaml +++ b/tests/lib/cmsis_dsp/statistics/testcase.yaml @@ -6,7 +6,7 @@ tests: - frdm_k64f - sam_e70_xplained - mps2_an521 - - native_posix + - native_sim tags: cmsis_dsp min_flash: 128 min_ram: 64 diff --git a/tests/lib/cmsis_dsp/support/testcase.yaml b/tests/lib/cmsis_dsp/support/testcase.yaml index 1fed8894b42..26ef2893ab1 100644 --- a/tests/lib/cmsis_dsp/support/testcase.yaml +++ b/tests/lib/cmsis_dsp/support/testcase.yaml @@ -6,7 +6,7 @@ tests: - frdm_k64f - sam_e70_xplained - mps2_an521 - - native_posix + - native_sim tags: cmsis_dsp min_flash: 128 min_ram: 128 diff --git a/tests/lib/cmsis_dsp/svm/testcase.yaml b/tests/lib/cmsis_dsp/svm/testcase.yaml index c107678e449..d0d59f7b70b 100644 --- a/tests/lib/cmsis_dsp/svm/testcase.yaml +++ b/tests/lib/cmsis_dsp/svm/testcase.yaml @@ -6,7 +6,7 @@ tests: - frdm_k64f - sam_e70_xplained - mps2_an521 - - native_posix + - native_sim tags: cmsis_dsp min_flash: 128 min_ram: 64 diff --git a/tests/lib/cmsis_dsp/transform/testcase.yaml b/tests/lib/cmsis_dsp/transform/testcase.yaml index 030eb5b2f77..2d93d48d09b 100644 --- a/tests/lib/cmsis_dsp/transform/testcase.yaml +++ b/tests/lib/cmsis_dsp/transform/testcase.yaml @@ -11,7 +11,7 @@ tests: - frdm_k64f - sam_e70_xplained - mps2_an521 - - native_posix + - native_sim tags: cmsis_dsp min_flash: 512 min_ram: 64 @@ -39,7 +39,7 @@ tests: - frdm_k64f - sam_e70_xplained - mps2_an521 - - native_posix + - native_sim tags: cmsis_dsp min_flash: 512 min_ram: 64 @@ -67,7 +67,7 @@ tests: - frdm_k64f - sam_e70_xplained - mps2_an521 - - native_posix + - native_sim tags: cmsis_dsp min_flash: 1024 min_ram: 64 @@ -93,7 +93,7 @@ tests: - frdm_k64f - sam_e70_xplained - mps2_an521 - - native_posix + - native_sim tags: cmsis_dsp min_flash: 1024 min_ram: 64 @@ -173,7 +173,7 @@ tests: - frdm_k64f - sam_e70_xplained - mps2_an521 - - native_posix + - native_sim tags: cmsis_dsp min_flash: 1024 min_ram: 64 @@ -199,7 +199,7 @@ tests: - frdm_k64f - sam_e70_xplained - mps2_an521 - - native_posix + - native_sim tags: cmsis_dsp min_flash: 512 min_ram: 64 @@ -227,7 +227,7 @@ tests: - frdm_k64f - sam_e70_xplained - mps2_an521 - - native_posix + - native_sim tags: cmsis_dsp min_flash: 1024 min_ram: 160 @@ -253,7 +253,7 @@ tests: - frdm_k64f - sam_e70_xplained - mps2_an521 - - native_posix + - native_sim tags: cmsis_dsp min_flash: 1024 min_ram: 64 From 799cd60745ff7cc1e968d048ea6b08f139044901 Mon Sep 17 00:00:00 2001 From: Alberto Escolar Piedras Date: Tue, 28 Nov 2023 11:48:38 +0100 Subject: [PATCH 0510/3723] tests/drivers/charger/sbs_charger: Fix test filter Fix the test filter, to allow any POSIX arch board, instead of just native_posix, as this test runs fine on all of them. Signed-off-by: Alberto Escolar Piedras --- tests/drivers/charger/sbs_charger/testcase.yaml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/tests/drivers/charger/sbs_charger/testcase.yaml b/tests/drivers/charger/sbs_charger/testcase.yaml index 1cc4904010b..7256c6530e9 100644 --- a/tests/drivers/charger/sbs_charger/testcase.yaml +++ b/tests/drivers/charger/sbs_charger/testcase.yaml @@ -6,7 +6,7 @@ tests: - charger filter: > dt_compat_enabled("sbs,sbs-charger") and - (CONFIG_QEMU_TARGET or CONFIG_BOARD_NATIVE_POSIX) + (CONFIG_QEMU_TARGET or CONFIG_ARCH_POSIX) extra_args: CONF_FILE="prj.conf;boards/emulated_board.conf" DTC_OVERLAY_FILE="boards/emulated_board.overlay" @@ -26,7 +26,7 @@ tests: - charger filter: > dt_compat_enabled("sbs,sbs-charger") and - (CONFIG_QEMU_TARGET or CONFIG_BOARD_NATIVE_POSIX) + (CONFIG_QEMU_TARGET or CONFIG_ARCH_POSIX) platform_allow: - qemu_cortex_a53 - qemu_cortex_a53_smp From ff30ad15cde7f194a8a7029d5c0c42d97dbe7cdf Mon Sep 17 00:00:00 2001 From: Alberto Escolar Piedras Date: Tue, 28 Nov 2023 11:50:55 +0100 Subject: [PATCH 0511/3723] tests/drivers/*: Switch integration platform to native_sim Swith integration_platforms from native_posix(_64) to native_sim(_64). Signed-off-by: Alberto Escolar Piedras --- tests/drivers/build_all/led/testcase.yaml | 2 +- tests/drivers/can/shell/testcase.yaml | 4 ++-- tests/drivers/rtc/shell/testcase.yaml | 4 ++-- tests/drivers/uart/uart_async_rx/testcase.yaml | 2 +- 4 files changed, 6 insertions(+), 6 deletions(-) diff --git a/tests/drivers/build_all/led/testcase.yaml b/tests/drivers/build_all/led/testcase.yaml index 3062a707903..0e1f40b4057 100644 --- a/tests/drivers/build_all/led/testcase.yaml +++ b/tests/drivers/build_all/led/testcase.yaml @@ -6,4 +6,4 @@ tests: - drivers - led integration_platforms: - - native_posix + - native_sim diff --git a/tests/drivers/can/shell/testcase.yaml b/tests/drivers/can/shell/testcase.yaml index 692acd0d05f..6261e8fcb8f 100644 --- a/tests/drivers/can/shell/testcase.yaml +++ b/tests/drivers/can/shell/testcase.yaml @@ -1,8 +1,8 @@ tests: drivers.can.shell: integration_platforms: - - native_posix - - native_posix_64 + - native_sim + - native_sim_64 tags: - drivers - can diff --git a/tests/drivers/rtc/shell/testcase.yaml b/tests/drivers/rtc/shell/testcase.yaml index 156f5394e94..f8af8b53153 100644 --- a/tests/drivers/rtc/shell/testcase.yaml +++ b/tests/drivers/rtc/shell/testcase.yaml @@ -1,8 +1,8 @@ tests: drivers.rtc.shell: integration_platforms: - - native_posix - - native_posix_64 + - native_sim + - native_sim_64 tags: - drivers - rtc diff --git a/tests/drivers/uart/uart_async_rx/testcase.yaml b/tests/drivers/uart/uart_async_rx/testcase.yaml index 64311dc1eb7..23a1b154975 100644 --- a/tests/drivers/uart/uart_async_rx/testcase.yaml +++ b/tests/drivers/uart/uart_async_rx/testcase.yaml @@ -3,7 +3,7 @@ tests: filter: CONFIG_SERIAL tags: drivers uart integration_platforms: - - native_posix + - native_sim drivers.uart.async_rx.ztress: filter: CONFIG_SERIAL tags: drivers uart From 12bf3bae0f6c3b3ee8d8dd04d11ccbbf73dab1f1 Mon Sep 17 00:00:00 2001 From: Alberto Escolar Piedras Date: Tue, 28 Nov 2023 11:59:34 +0100 Subject: [PATCH 0512/3723] tests/lib/c_lib/common: Do not skip part of test for all posix boards It is not just native_posix that supports the sqrt test, but all posix arch based ones. Signed-off-by: Alberto Escolar Piedras --- tests/lib/c_lib/common/src/test_sqrt.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/tests/lib/c_lib/common/src/test_sqrt.c b/tests/lib/c_lib/common/src/test_sqrt.c index 59edad9c193..fba12cce59b 100644 --- a/tests/lib/c_lib/common/src/test_sqrt.c +++ b/tests/lib/c_lib/common/src/test_sqrt.c @@ -109,10 +109,10 @@ int32_t *p_root_squared = (int32_t *)&root_squared; /* Conversion not supported with minimal_libc without * CBPRINTF_FP_SUPPORT. * - * Conversion not supported without FPU except on native POSIX. + * Conversion not supported without FPU except on POSIX arch based targets. */ if (!(IS_ENABLED(CONFIG_FPU) - || IS_ENABLED(CONFIG_BOARD_NATIVE_POSIX))) { + || IS_ENABLED(CONFIG_ARCH_POSIX))) { ztest_test_skip(); return; } @@ -176,10 +176,10 @@ int64_t *p_root_squared = (int64_t *)&root_squared; max_error = 0; /* - * sqrt is not supported without FPU except on native POSIX. + * sqrt is not supported without FPU except on POSIX arch based targets. */ if (!(IS_ENABLED(CONFIG_FPU) - || IS_ENABLED(CONFIG_BOARD_NATIVE_POSIX))) { + || IS_ENABLED(CONFIG_ARCH_POSIX))) { ztest_test_skip(); return; } From 6db47c70fabf4c9e44c4978425292bf78ad2209b Mon Sep 17 00:00:00 2001 From: Alberto Escolar Piedras Date: Tue, 28 Nov 2023 12:01:31 +0100 Subject: [PATCH 0513/3723] tests/lib/heap: Minor fix in a comment That comment applies to all posix arch based boards, not just native_posix. Signed-off-by: Alberto Escolar Piedras --- tests/lib/heap/src/main.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/tests/lib/heap/src/main.c b/tests/lib/heap/src/main.c index 62899f6d7d6..7db993dc035 100644 --- a/tests/lib/heap/src/main.c +++ b/tests/lib/heap/src/main.c @@ -21,8 +21,8 @@ */ # define MEMSZ (192 * 1024) #elif defined(CONFIG_ARCH_POSIX) -/* native_posix doesn't support CONFIG_SRAM_SIZE at all (because - * it can link anything big enough to fit on the host), so just use a +/* POSIX arch based targets don't support CONFIG_SRAM_SIZE at all (because + * they can link anything big enough to fit on the host), so just use a * reasonable value. */ # define MEMSZ (2 * 1024 * 1024) From 1a3ba0ec82529409f82f74b1a06a94bfbd9fb33f Mon Sep 17 00:00:00 2001 From: Alberto Escolar Piedras Date: Tue, 28 Nov 2023 12:02:08 +0100 Subject: [PATCH 0514/3723] tests/lib/*: Switch integration platform to native_sim Swith integration_platforms from native_posix(_64) to native_sim(_64). Signed-off-by: Alberto Escolar Piedras --- tests/lib/cbprintf_package/testcase.yaml | 28 ++++++++++++------------ tests/lib/cpp/libcxx/testcase.yaml | 4 ++-- tests/lib/hash_function/testcase.yaml | 2 +- tests/lib/hash_map/testcase.yaml | 2 +- tests/lib/heap/testcase.yaml | 2 +- tests/lib/heap_align/testcase.yaml | 2 +- tests/lib/json/testcase.yaml | 2 +- tests/lib/linear_range/testcase.yaml | 2 +- tests/lib/mem_blocks/testcase.yaml | 2 +- tests/lib/mem_blocks_stats/testcase.yaml | 2 +- tests/lib/notify/testcase.yaml | 2 +- tests/lib/onoff/testcase.yaml | 2 +- tests/lib/p4workq/testcase.yaml | 2 +- tests/lib/ringbuffer/testcase.yaml | 4 ++-- tests/lib/smf/testcase.yaml | 2 +- tests/lib/spsc_pbuf/testcase.yaml | 8 +++---- tests/lib/sys_util/testcase.yaml | 2 +- 17 files changed, 35 insertions(+), 35 deletions(-) diff --git a/tests/lib/cbprintf_package/testcase.yaml b/tests/lib/cbprintf_package/testcase.yaml index 61545936181..4a07f4ec788 100644 --- a/tests/lib/cbprintf_package/testcase.yaml +++ b/tests/lib/cbprintf_package/testcase.yaml @@ -9,14 +9,14 @@ tests: extra_configs: - CONFIG_CBPRINTF_COMPLETE=y integration_platforms: - - native_posix + - native_sim libraries.cbprintf.package_no_generic: extra_configs: - CONFIG_CBPRINTF_COMPLETE=y - CONFIG_COMPILER_OPT="-DZ_C_GENERIC=0" integration_platforms: - - native_posix + - native_sim libraries.cbprintf.package_fp: filter: CONFIG_CPU_HAS_FPU @@ -25,7 +25,7 @@ tests: - CONFIG_CBPRINTF_COMPLETE=y - CONFIG_FPU=y integration_platforms: - - native_posix + - native_sim libraries.cbprintf.package_fp_align_offset: filter: CONFIG_CPU_HAS_FPU @@ -35,7 +35,7 @@ tests: - CONFIG_COMPILER_OPT="-DCBPRINTF_PACKAGE_ALIGN_OFFSET=1" - CONFIG_FPU=y integration_platforms: - - native_posix + - native_sim libraries.cbprintf.package_long_double: filter: CONFIG_CPU_HAS_FPU @@ -46,7 +46,7 @@ tests: - CONFIG_FPU=y - CONFIG_MINIMAL_LIBC=y integration_platforms: - - native_posix + - native_sim libraries.cbprintf.package_long_double_align_offset: filter: CONFIG_CPU_HAS_FPU @@ -58,13 +58,13 @@ tests: - CONFIG_FPU=y - CONFIG_MINIMAL_LIBC=y integration_platforms: - - native_posix + - native_sim libraries.cbprintf.package_nano: extra_configs: - CONFIG_CBPRINTF_NANO=y integration_platforms: - - native_posix + - native_sim # Same test but with test compiled as C++ libraries.cbprintf.package_cpp: @@ -72,7 +72,7 @@ tests: - CONFIG_CPP=y - CONFIG_CBPRINTF_COMPLETE=y integration_platforms: - - native_posix + - native_sim libraries.cbprintf.package_no_generic_cpp: extra_configs: @@ -80,7 +80,7 @@ tests: - CONFIG_CBPRINTF_COMPLETE=y - CONFIG_COMPILER_OPT="-DZ_C_GENERIC=0" integration_platforms: - - native_posix + - native_sim libraries.cbprintf.package_fp_cpp: filter: CONFIG_CPU_HAS_FPU @@ -90,7 +90,7 @@ tests: - CONFIG_CBPRINTF_COMPLETE=y - CONFIG_FPU=y integration_platforms: - - native_posix + - native_sim libraries.cbprintf.package_fp_align_offset_cpp: filter: CONFIG_CPU_HAS_FPU @@ -101,7 +101,7 @@ tests: - CONFIG_COMPILER_OPT="-DCBPRINTF_PACKAGE_ALIGN_OFFSET=1" - CONFIG_FPU=y integration_platforms: - - native_posix + - native_sim libraries.cbprintf.package_long_double_cpp: filter: CONFIG_CPU_HAS_FPU @@ -113,7 +113,7 @@ tests: - CONFIG_FPU=y - CONFIG_MINIMAL_LIBC=y integration_platforms: - - native_posix + - native_sim libraries.cbprintf.package_long_double_align_offset_cpp: filter: CONFIG_CPU_HAS_FPU @@ -126,14 +126,14 @@ tests: - CONFIG_FPU=y - CONFIG_MINIMAL_LIBC=y integration_platforms: - - native_posix + - native_sim libraries.cbprintf.package_nano_cpp: extra_configs: - CONFIG_CPP=y - CONFIG_CBPRINTF_NANO=y integration_platforms: - - native_posix + - native_sim libraries.cbprintf.package.picolibc: filter: CONFIG_PICOLIBC_SUPPORTED diff --git a/tests/lib/cpp/libcxx/testcase.yaml b/tests/lib/cpp/libcxx/testcase.yaml index fb21def8b3b..a75430644c8 100644 --- a/tests/lib/cpp/libcxx/testcase.yaml +++ b/tests/lib/cpp/libcxx/testcase.yaml @@ -48,5 +48,5 @@ tests: - CONFIG_EXTERNAL_LIBCPP=y - CONFIG_CPP_EXCEPTIONS=y integration_platforms: - - native_posix - - native_posix_64 + - native_sim + - native_sim_64 diff --git a/tests/lib/hash_function/testcase.yaml b/tests/lib/hash_function/testcase.yaml index 45bca8c663d..5c4b3918b61 100644 --- a/tests/lib/hash_function/testcase.yaml +++ b/tests/lib/hash_function/testcase.yaml @@ -4,7 +4,7 @@ common: integration_platforms: - - native_posix + - native_sim tests: libraries.hash_function.identity: # RNG seems to be broken on qemu_cortex_a53 diff --git a/tests/lib/hash_map/testcase.yaml b/tests/lib/hash_map/testcase.yaml index d952bb28887..f5a32ea2a00 100644 --- a/tests/lib/hash_map/testcase.yaml +++ b/tests/lib/hash_map/testcase.yaml @@ -5,7 +5,7 @@ common: min_ram: 24 integration_platforms: - - native_posix + - native_sim tests: libraries.hash_map.separate_chaining.djb2: diff --git a/tests/lib/heap/testcase.yaml b/tests/lib/heap/testcase.yaml index 8f8a282f09c..4427788fb07 100644 --- a/tests/lib/heap/testcase.yaml +++ b/tests/lib/heap/testcase.yaml @@ -17,5 +17,5 @@ tests: filter: not CONFIG_SOC_NSIM timeout: 480 integration_platforms: - - native_posix + - native_sim - qemu_x86 diff --git a/tests/lib/heap_align/testcase.yaml b/tests/lib/heap_align/testcase.yaml index b80e18d70b0..3dba0fad765 100644 --- a/tests/lib/heap_align/testcase.yaml +++ b/tests/lib/heap_align/testcase.yaml @@ -4,5 +4,5 @@ tests: - heap - heap_align integration_platforms: - - native_posix + - native_sim - mps2_an521 diff --git a/tests/lib/json/testcase.yaml b/tests/lib/json/testcase.yaml index 00dcfbfd428..87b7ee2bf1a 100644 --- a/tests/lib/json/testcase.yaml +++ b/tests/lib/json/testcase.yaml @@ -4,4 +4,4 @@ tests: min_flash: 34 tags: json integration_platforms: - - native_posix + - native_sim diff --git a/tests/lib/linear_range/testcase.yaml b/tests/lib/linear_range/testcase.yaml index fd64edfdea9..9e96383b0ea 100644 --- a/tests/lib/linear_range/testcase.yaml +++ b/tests/lib/linear_range/testcase.yaml @@ -4,4 +4,4 @@ tests: libraries.linear_range: integration_platforms: - - native_posix + - native_sim diff --git a/tests/lib/mem_blocks/testcase.yaml b/tests/lib/mem_blocks/testcase.yaml index f214d4643e7..ae0b795822a 100644 --- a/tests/lib/mem_blocks/testcase.yaml +++ b/tests/lib/mem_blocks/testcase.yaml @@ -4,4 +4,4 @@ tests: - heap - mem_blocks integration_platforms: - - native_posix + - native_sim diff --git a/tests/lib/mem_blocks_stats/testcase.yaml b/tests/lib/mem_blocks_stats/testcase.yaml index 4814ddfdc83..696dc9a5fac 100644 --- a/tests/lib/mem_blocks_stats/testcase.yaml +++ b/tests/lib/mem_blocks_stats/testcase.yaml @@ -4,4 +4,4 @@ tests: - heap - mem_blocks.stats integration_platforms: - - native_posix + - native_sim diff --git a/tests/lib/notify/testcase.yaml b/tests/lib/notify/testcase.yaml index 2cc3c3ca825..359ab991f4a 100644 --- a/tests/lib/notify/testcase.yaml +++ b/tests/lib/notify/testcase.yaml @@ -2,4 +2,4 @@ tests: libraries.data_structures: tags: notify integration_platforms: - - native_posix + - native_sim diff --git a/tests/lib/onoff/testcase.yaml b/tests/lib/onoff/testcase.yaml index ad1df70b286..a57688d5004 100644 --- a/tests/lib/onoff/testcase.yaml +++ b/tests/lib/onoff/testcase.yaml @@ -4,4 +4,4 @@ tests: - onoff - timer integration_platforms: - - native_posix + - native_sim diff --git a/tests/lib/p4workq/testcase.yaml b/tests/lib/p4workq/testcase.yaml index b897fc09ab9..d8ba5c85480 100644 --- a/tests/lib/p4workq/testcase.yaml +++ b/tests/lib/p4workq/testcase.yaml @@ -4,4 +4,4 @@ tests: - kernel integration_platforms: - qemu_x86 - - native_posix + - native_sim diff --git a/tests/lib/ringbuffer/testcase.yaml b/tests/lib/ringbuffer/testcase.yaml index b2f11681616..851735384f5 100644 --- a/tests/lib/ringbuffer/testcase.yaml +++ b/tests/lib/ringbuffer/testcase.yaml @@ -7,8 +7,8 @@ common: tests: libraries.ring_buffer: integration_platforms: - - native_posix - - native_posix_64 + - native_sim + - native_sim_64 libraries.ring_buffer.concurrent: platform_allow: qemu_x86 diff --git a/tests/lib/smf/testcase.yaml b/tests/lib/smf/testcase.yaml index 4ca5a511c7e..761f86e8fff 100644 --- a/tests/lib/smf/testcase.yaml +++ b/tests/lib/smf/testcase.yaml @@ -1,6 +1,6 @@ common: integration_platforms: - - native_posix + - native_sim tags: - smf tests: diff --git a/tests/lib/spsc_pbuf/testcase.yaml b/tests/lib/spsc_pbuf/testcase.yaml index daff2fc46f2..be39414e73e 100644 --- a/tests/lib/spsc_pbuf/testcase.yaml +++ b/tests/lib/spsc_pbuf/testcase.yaml @@ -1,14 +1,14 @@ tests: libraries.spsc_pbuf: integration_platforms: - - native_posix + - native_sim # Exclude platform which does not link with cache functions platform_exclude: ast1030_evb timeout: 120 libraries.spsc_pbuf.cache: integration_platforms: - - native_posix + - native_sim # Exclude platform which does not link with cache functions platform_exclude: ast1030_evb timeout: 120 @@ -17,7 +17,7 @@ tests: libraries.spsc_pbuf.nocache.: integration_platforms: - - native_posix + - native_sim # Exclude platform which does not link with cache functions platform_exclude: ast1030_evb timeout: 120 @@ -26,7 +26,7 @@ tests: libraries.spsc_pbuf.utilization: integration_platforms: - - native_posix + - native_sim # Exclude platform which does not link with cache functions platform_exclude: ast1030_evb timeout: 120 diff --git a/tests/lib/sys_util/testcase.yaml b/tests/lib/sys_util/testcase.yaml index 251663d707d..3408f77c74f 100644 --- a/tests/lib/sys_util/testcase.yaml +++ b/tests/lib/sys_util/testcase.yaml @@ -2,4 +2,4 @@ tests: libraries.sys_util: tags: sys_util integration_platforms: - - native_posix + - native_sim From 345c25659cb3bd06f6d4e991526643cdca946f94 Mon Sep 17 00:00:00 2001 From: Alberto Escolar Piedras Date: Tue, 28 Nov 2023 13:17:46 +0100 Subject: [PATCH 0515/3723] tests/subsys/bindesc/definition: Enable for native_sim Enable bindesc.define also for native_sim. Signed-off-by: Alberto Escolar Piedras --- tests/subsys/bindesc/definition/testcase.yaml | 18 ++++++++++++++---- 1 file changed, 14 insertions(+), 4 deletions(-) diff --git a/tests/subsys/bindesc/definition/testcase.yaml b/tests/subsys/bindesc/definition/testcase.yaml index 3da2484a15b..0f447941374 100644 --- a/tests/subsys/bindesc/definition/testcase.yaml +++ b/tests/subsys/bindesc/definition/testcase.yaml @@ -7,10 +7,20 @@ common: tags: bindesc tests: bindesc.define: - platform_allow: > - native_posix qemu_x86 qemu_cortex_m0 qemu_cortex_m3 - qemu_cortex_r5 qemu_arc_em qemu_arc_hs qemu_arc_hs5x - qemu_arc_hs6x qemu_riscv32 qemu_riscv32e qemu_riscv64 + platform_allow: + - native_posix + - native_sim + - qemu_x86 + - qemu_cortex_m0 + - qemu_cortex_m3 + - qemu_cortex_r5 + - qemu_arc_em + - qemu_arc_hs + - qemu_arc_hs5x + - qemu_arc_hs6x + - qemu_riscv32 + - qemu_riscv32e + - qemu_riscv64 bindesc.define.c99: extra_args: CSTD="c99" bindesc.define.c11: From 0f5a0327e6938e5609a062343e7d7c24a9506898 Mon Sep 17 00:00:00 2001 From: Alberto Escolar Piedras Date: Tue, 28 Nov 2023 13:18:39 +0100 Subject: [PATCH 0516/3723] tests/subsys/canbus/isotp/conformance: Replace native_posix in comment Replace native_posix with native_sim in a comment. Signed-off-by: Alberto Escolar Piedras --- tests/subsys/canbus/isotp/conformance/testcase.yaml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/tests/subsys/canbus/isotp/conformance/testcase.yaml b/tests/subsys/canbus/isotp/conformance/testcase.yaml index ce9c838ab97..e29419881e1 100644 --- a/tests/subsys/canbus/isotp/conformance/testcase.yaml +++ b/tests/subsys/canbus/isotp/conformance/testcase.yaml @@ -5,8 +5,8 @@ # +--------+------------------------+----------------------+----------------+ # | 1 | Classical CAN only | CONFIG_CAN_FD_MODE=n | nucleo_f072 | # | 2 | Classical CAN only | CONFIG_CAN_FD_MODE=y | nucleo_f072 | -# | 3 | Classical CAN + CAN FD | CONFIG_CAN_FD_MODE=n | native_posix | -# | 4 | Classical CAN + CAN FD | CONFIG_CAN_FD_MODE=y | native_posix | +# | 3 | Classical CAN + CAN FD | CONFIG_CAN_FD_MODE=n | native_sim | +# | 4 | Classical CAN + CAN FD | CONFIG_CAN_FD_MODE=y | native_sim | # # The test-specific CONFIG_TEST_USE_CAN_FD_MODE is used to decide if the test should use # CAN FD independent of CONFIG_CAN_FD_MODE configuration. From f981bf2fa0abbc8cc0ffa291602e1580b1258a27 Mon Sep 17 00:00:00 2001 From: Alberto Escolar Piedras Date: Tue, 28 Nov 2023 13:19:17 +0100 Subject: [PATCH 0517/3723] tests/subsys/*: Switch integration platform to native_sim Swith integration_platforms from native_posix(_64) to native_sim(_64). Signed-off-by: Alberto Escolar Piedras --- tests/subsys/dsp/basicmath/testcase.yaml | 2 +- tests/subsys/input/api/testcase.yaml | 2 +- tests/subsys/ipc/pbuf/testcase.yaml | 2 +- tests/subsys/portability/cmsis_rtos_v1/testcase.yaml | 2 +- tests/subsys/portability/cmsis_rtos_v2/testcase.yaml | 2 +- tests/subsys/rtio/rtio_api/testcase.yaml | 4 ++-- tests/subsys/shell/shell/testcase.yaml | 2 +- tests/subsys/shell/shell_history/testcase.yaml | 2 +- tests/subsys/zbus/dyn_channel/testcase.yaml | 2 +- tests/subsys/zbus/integration/testcase.yaml | 2 +- .../subsys/zbus/runtime_observers_registration/testcase.yaml | 2 +- tests/subsys/zbus/unittests/testcase.yaml | 2 +- tests/subsys/zbus/user_data/testcase.yaml | 2 +- 13 files changed, 14 insertions(+), 14 deletions(-) diff --git a/tests/subsys/dsp/basicmath/testcase.yaml b/tests/subsys/dsp/basicmath/testcase.yaml index ef0996a4b38..cb8dd1a2765 100644 --- a/tests/subsys/dsp/basicmath/testcase.yaml +++ b/tests/subsys/dsp/basicmath/testcase.yaml @@ -5,7 +5,7 @@ tests: - frdm_k64f - sam_e70_xplained - mps2_an521 - - native_posix + - native_sim tags: zdsp min_flash: 128 min_ram: 64 diff --git a/tests/subsys/input/api/testcase.yaml b/tests/subsys/input/api/testcase.yaml index 9ed7d8bd068..1df02cf009e 100644 --- a/tests/subsys/input/api/testcase.yaml +++ b/tests/subsys/input/api/testcase.yaml @@ -4,7 +4,7 @@ common: tags: - input integration_platforms: - - native_posix + - native_sim tests: input.api.thread: extra_configs: diff --git a/tests/subsys/ipc/pbuf/testcase.yaml b/tests/subsys/ipc/pbuf/testcase.yaml index 4113335403a..ef5fac615f8 100644 --- a/tests/subsys/ipc/pbuf/testcase.yaml +++ b/tests/subsys/ipc/pbuf/testcase.yaml @@ -1,5 +1,5 @@ tests: ipc.icmsg_pbuf: integration_platforms: - - native_posix + - native_sim timeout: 120 diff --git a/tests/subsys/portability/cmsis_rtos_v1/testcase.yaml b/tests/subsys/portability/cmsis_rtos_v1/testcase.yaml index 3887fe8a732..14dca3ad836 100644 --- a/tests/subsys/portability/cmsis_rtos_v1/testcase.yaml +++ b/tests/subsys/portability/cmsis_rtos_v1/testcase.yaml @@ -4,4 +4,4 @@ tests: min_ram: 32 min_flash: 34 integration_platforms: - - native_posix + - native_sim diff --git a/tests/subsys/portability/cmsis_rtos_v2/testcase.yaml b/tests/subsys/portability/cmsis_rtos_v2/testcase.yaml index 0b198c71297..9de4ef3c939 100644 --- a/tests/subsys/portability/cmsis_rtos_v2/testcase.yaml +++ b/tests/subsys/portability/cmsis_rtos_v2/testcase.yaml @@ -5,4 +5,4 @@ tests: min_ram: 32 min_flash: 34 integration_platforms: - - native_posix + - native_sim diff --git a/tests/subsys/rtio/rtio_api/testcase.yaml b/tests/subsys/rtio/rtio_api/testcase.yaml index 2eb29026efa..52480644fc0 100644 --- a/tests/subsys/rtio/rtio_api/testcase.yaml +++ b/tests/subsys/rtio/rtio_api/testcase.yaml @@ -8,14 +8,14 @@ tests: filter: not CONFIG_ARCH_HAS_USERSPACE tags: rtio integration_platforms: - - native_posix + - native_sim rtio.api.submit_sem: filter: not CONFIG_ARCH_HAS_USERSPACE tags: rtio extra_configs: - CONFIG_RTIO_SUBMIT_SEM=y integration_platforms: - - native_posix + - native_sim rtio.api.userspace: filter: CONFIG_ARCH_HAS_USERSPACE extra_configs: diff --git a/tests/subsys/shell/shell/testcase.yaml b/tests/subsys/shell/shell/testcase.yaml index 506fae09c1d..7a5b4170af4 100644 --- a/tests/subsys/shell/shell/testcase.yaml +++ b/tests/subsys/shell/shell/testcase.yaml @@ -2,7 +2,7 @@ common: tags: shell min_ram: 32 integration_platforms: - - native_posix + - native_sim tests: shell.core: diff --git a/tests/subsys/shell/shell_history/testcase.yaml b/tests/subsys/shell/shell_history/testcase.yaml index 9cd51226ff0..4cc5189539d 100644 --- a/tests/subsys/shell/shell_history/testcase.yaml +++ b/tests/subsys/shell/shell_history/testcase.yaml @@ -1,7 +1,7 @@ tests: shell.history: integration_platforms: - - native_posix + - native_sim min_flash: 64 min_ram: 32 filter: ( CONFIG_SHELL ) diff --git a/tests/subsys/zbus/dyn_channel/testcase.yaml b/tests/subsys/zbus/dyn_channel/testcase.yaml index c295630ca10..8bdee772571 100644 --- a/tests/subsys/zbus/dyn_channel/testcase.yaml +++ b/tests/subsys/zbus/dyn_channel/testcase.yaml @@ -3,4 +3,4 @@ tests: platform_exclude: fvp_base_revc_2xaemv8a_smp_ns tags: zbus integration_platforms: - - native_posix + - native_sim diff --git a/tests/subsys/zbus/integration/testcase.yaml b/tests/subsys/zbus/integration/testcase.yaml index ae918fcfb0f..410280b1b0d 100644 --- a/tests/subsys/zbus/integration/testcase.yaml +++ b/tests/subsys/zbus/integration/testcase.yaml @@ -7,4 +7,4 @@ tests: - fvp_baser_aemv8r_aarch32_smp tags: zbus integration_platforms: - - native_posix + - native_sim diff --git a/tests/subsys/zbus/runtime_observers_registration/testcase.yaml b/tests/subsys/zbus/runtime_observers_registration/testcase.yaml index caa967edd5c..bad6075a143 100644 --- a/tests/subsys/zbus/runtime_observers_registration/testcase.yaml +++ b/tests/subsys/zbus/runtime_observers_registration/testcase.yaml @@ -2,4 +2,4 @@ tests: message_bus.zbus.runtime_obs_reg.add_and_remove_observers: tags: zbus integration_platforms: - - native_posix + - native_sim diff --git a/tests/subsys/zbus/unittests/testcase.yaml b/tests/subsys/zbus/unittests/testcase.yaml index 8912a089d80..342bfd5f30f 100644 --- a/tests/subsys/zbus/unittests/testcase.yaml +++ b/tests/subsys/zbus/unittests/testcase.yaml @@ -3,4 +3,4 @@ tests: platform_exclude: fvp_base_revc_2xaemv8a_smp_ns tags: zbus integration_platforms: - - native_posix + - native_sim diff --git a/tests/subsys/zbus/user_data/testcase.yaml b/tests/subsys/zbus/user_data/testcase.yaml index 52ee20bfcc1..4f21a9c35c8 100644 --- a/tests/subsys/zbus/user_data/testcase.yaml +++ b/tests/subsys/zbus/user_data/testcase.yaml @@ -3,4 +3,4 @@ tests: platform_exclude: fvp_base_revc_2xaemv8a_smp_ns tags: zbus integration_platforms: - - native_posix + - native_sim From fbf1c19bd648ddc3897adb49cca7bb8f000bc68c Mon Sep 17 00:00:00 2001 From: Alberto Escolar Piedras Date: Tue, 28 Nov 2023 13:25:12 +0100 Subject: [PATCH 0518/3723] tests/kernel/common: Enable errno test on native_sim Enable this test also on native_sim when not using the host C library Signed-off-by: Alberto Escolar Piedras --- tests/kernel/common/src/errno.c | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/tests/kernel/common/src/errno.c b/tests/kernel/common/src/errno.c index 72240a40d92..9155a5bd418 100644 --- a/tests/kernel/common/src/errno.c +++ b/tests/kernel/common/src/errno.c @@ -118,9 +118,8 @@ ZTEST(common_errno, test_thread_context) void thread_entry_user(void *p1, void *p2, void *p3) { -#ifdef CONFIG_ARCH_POSIX - /* The errno in native posix will be handled by native - * operation system, so we skip it. +#ifdef CONFIG_NATIVE_LIBC + /* The errno when using the host C library will be handled by it, so we skip it. */ ztest_test_skip(); #else From 700a2513661b9fbf928074371655956572089a52 Mon Sep 17 00:00:00 2001 From: Alberto Escolar Piedras Date: Tue, 28 Nov 2023 13:31:16 +0100 Subject: [PATCH 0519/3723] tests/kernel/sched/schedule_api: Replace delay with Z_SPIN_DELAY() This macro was introduced for this purpose Signed-off-by: Alberto Escolar Piedras --- tests/kernel/sched/schedule_api/src/main.c | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/tests/kernel/sched/schedule_api/src/main.c b/tests/kernel/sched/schedule_api/src/main.c index 053d3b002a3..645ee558a69 100644 --- a/tests/kernel/sched/schedule_api/src/main.c +++ b/tests/kernel/sched/schedule_api/src/main.c @@ -21,9 +21,7 @@ void spin_for_ms(int ms) /* In the posix arch, a busy loop takes no time, so * let's make it take some */ - if (IS_ENABLED(CONFIG_ARCH_POSIX)) { - k_busy_wait(50); - } + Z_SPIN_DELAY(50); } } From 7a778ebc2d474f0d13e4e187da1267d172a0e341 Mon Sep 17 00:00:00 2001 From: Alberto Escolar Piedras Date: Tue, 28 Nov 2023 13:31:56 +0100 Subject: [PATCH 0520/3723] tests/kernel/*: Switch integration platform to native_sim Swith integration_platforms from native_posix(_64) to native_sim(_64). And replace it also in a comment. Signed-off-by: Alberto Escolar Piedras --- tests/kernel/common/testcase.yaml | 2 +- tests/kernel/device/testcase.yaml | 2 +- tests/kernel/timer/cycle64/testcase.yaml | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/tests/kernel/common/testcase.yaml b/tests/kernel/common/testcase.yaml index 721d4bb9c3d..7ed13606b86 100644 --- a/tests/kernel/common/testcase.yaml +++ b/tests/kernel/common/testcase.yaml @@ -20,7 +20,7 @@ tests: # Some configurations are known-incompliant and won't build filter: not ((CONFIG_I2C or CONFIG_SPI) and CONFIG_USERSPACE) integration_platforms: - - native_posix + - native_sim extra_configs: - CONFIG_MISRA_SANE=y kernel.common.minimallibc: diff --git a/tests/kernel/device/testcase.yaml b/tests/kernel/device/testcase.yaml index 40aee98fa57..931f2635d60 100644 --- a/tests/kernel/device/testcase.yaml +++ b/tests/kernel/device/testcase.yaml @@ -3,7 +3,7 @@ common: - device - userspace integration_platforms: - - native_posix + - native_sim tests: kernel.device: tags: diff --git a/tests/kernel/timer/cycle64/testcase.yaml b/tests/kernel/timer/cycle64/testcase.yaml index b050d8f1027..f1a65dbb00a 100644 --- a/tests/kernel/timer/cycle64/testcase.yaml +++ b/tests/kernel/timer/cycle64/testcase.yaml @@ -1,6 +1,6 @@ # Note: Re: slow vs fast # -# Some platforms such as native_posix, qemu_riscv32, qemu_riscv64 +# Some platforms such as native_sim, qemu_riscv32, qemu_riscv64 # complete these tests almost instantaneously because of qemu timer # quirks ("time warp") even though the test reports that it completes # in e.g. 14 s. We can take advantage of that for fast tests on each PR From 690479fc36ff4f87265d457654cad431f41e2d4f Mon Sep 17 00:00:00 2001 From: Alberto Escolar Piedras Date: Tue, 28 Nov 2023 13:33:16 +0100 Subject: [PATCH 0521/3723] tests/*: Switch integration platform to native_sim Swith integration_platforms from native_posix(_64) to native_sim(_64). Signed-off-by: Alberto Escolar Piedras --- tests/application_development/gen_inc_file/testcase.yaml | 2 +- tests/benchmarks/data_structure_perf/dlist_perf/testcase.yaml | 2 +- .../benchmarks/data_structure_perf/rbtree_perf/testcase.yaml | 2 +- tests/misc/check_init_priorities/testcase.yaml | 2 +- tests/modules/nanopb/testcase.yaml | 4 ++-- 5 files changed, 6 insertions(+), 6 deletions(-) diff --git a/tests/application_development/gen_inc_file/testcase.yaml b/tests/application_development/gen_inc_file/testcase.yaml index b2fad859660..3ddba087775 100644 --- a/tests/application_development/gen_inc_file/testcase.yaml +++ b/tests/application_development/gen_inc_file/testcase.yaml @@ -1,5 +1,5 @@ tests: buildsystem.include_file: integration_platforms: - - native_posix + - native_sim tags: gen_inc_file diff --git a/tests/benchmarks/data_structure_perf/dlist_perf/testcase.yaml b/tests/benchmarks/data_structure_perf/dlist_perf/testcase.yaml index f772594cf51..87abef0773f 100644 --- a/tests/benchmarks/data_structure_perf/dlist_perf/testcase.yaml +++ b/tests/benchmarks/data_structure_perf/dlist_perf/testcase.yaml @@ -5,4 +5,4 @@ tests: - dlist - kernel integration_platforms: - - native_posix + - native_sim diff --git a/tests/benchmarks/data_structure_perf/rbtree_perf/testcase.yaml b/tests/benchmarks/data_structure_perf/rbtree_perf/testcase.yaml index bee6b9994aa..d8b48be3acf 100644 --- a/tests/benchmarks/data_structure_perf/rbtree_perf/testcase.yaml +++ b/tests/benchmarks/data_structure_perf/rbtree_perf/testcase.yaml @@ -5,4 +5,4 @@ tests: - rbtree - kernel integration_platforms: - - native_posix + - native_sim diff --git a/tests/misc/check_init_priorities/testcase.yaml b/tests/misc/check_init_priorities/testcase.yaml index 1484ae9c100..5d4a2a4e9a4 100644 --- a/tests/misc/check_init_priorities/testcase.yaml +++ b/tests/misc/check_init_priorities/testcase.yaml @@ -9,4 +9,4 @@ tests: - native_posix integration_platforms: - native_sim - - native_posix + - native_sim diff --git a/tests/modules/nanopb/testcase.yaml b/tests/modules/nanopb/testcase.yaml index 23956de2091..33547630064 100644 --- a/tests/modules/nanopb/testcase.yaml +++ b/tests/modules/nanopb/testcase.yaml @@ -5,5 +5,5 @@ tests: tags: - nanopb integration_platforms: - - native_posix - - native_posix_64 + - native_sim + - native_sim_64 From a905292eb0f1e609933f4024c40c10c878fe1a72 Mon Sep 17 00:00:00 2001 From: Alberto Escolar Piedras Date: Tue, 28 Nov 2023 13:39:00 +0100 Subject: [PATCH 0522/3723] tests/boards/native_sim/rtc: Rename testcase As it is not just targetting native_posix anymore. Signed-off-by: Alberto Escolar Piedras --- tests/boards/native_sim/rtc/testcase.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/boards/native_sim/rtc/testcase.yaml b/tests/boards/native_sim/rtc/testcase.yaml index 02da1cd41be..cbffa6103dd 100644 --- a/tests/boards/native_sim/rtc/testcase.yaml +++ b/tests/boards/native_sim/rtc/testcase.yaml @@ -1,6 +1,6 @@ # Test of the native_posix real timeness and RTC model tests: - boards.native_posix.rtc: + boards.native.rtc: platform_allow: - native_posix - native_posix_64 From 9971027d0b0f8da19db7d9cc089840d264b073d8 Mon Sep 17 00:00:00 2001 From: Alberto Escolar Piedras Date: Tue, 28 Nov 2023 15:04:41 +0100 Subject: [PATCH 0523/3723] CI clang workflow: Switch to native_sim Switch from native_posix to native_sim as test platform for this workflow. Signed-off-by: Alberto Escolar Piedras --- .github/workflows/clang.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/clang.yaml b/.github/workflows/clang.yaml index 58e9fdd4d2c..210617c8e56 100644 --- a/.github/workflows/clang.yaml +++ b/.github/workflows/clang.yaml @@ -18,7 +18,7 @@ jobs: strategy: fail-fast: false matrix: - platform: ["native_posix"] + platform: ["native_sim"] env: ZEPHYR_SDK_INSTALL_DIR: /opt/toolchains/zephyr-sdk-0.16.4 LLVM_TOOLCHAIN_PATH: /usr/lib/llvm-16 From 861131795c3c474c6d8623cbb42fdf615238aeb9 Mon Sep 17 00:00:00 2001 From: Alberto Escolar Piedras Date: Tue, 28 Nov 2023 15:05:27 +0100 Subject: [PATCH 0524/3723] CI codecov workflow: Switch to native_sim Switch from native_posix to native_sim as test platform for this workflow. Signed-off-by: Alberto Escolar Piedras --- .github/workflows/codecov.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/codecov.yaml b/.github/workflows/codecov.yaml index ad668636c56..0ea3641d1e7 100644 --- a/.github/workflows/codecov.yaml +++ b/.github/workflows/codecov.yaml @@ -20,7 +20,7 @@ jobs: strategy: fail-fast: false matrix: - platform: ["native_posix", "qemu_x86", "unit_testing"] + platform: ["native_sim", "qemu_x86", "unit_testing"] env: ZEPHYR_SDK_INSTALL_DIR: /opt/toolchains/zephyr-sdk-0.16.4 steps: From 3e1855e5038e90cc5d1003d45368ac125e897268 Mon Sep 17 00:00:00 2001 From: Andrej Butok Date: Mon, 20 Nov 2023 09:50:54 +0100 Subject: [PATCH 0525/3723] boards: lpcxpresso55s28: add boot and slot1 partitions Add boot_partition and slot1_partition to lpcxpresso55s28.dts. Make MCUBoot compiled. Signed-off-by: Andrej Butok --- .../arm/lpcxpresso55s28/lpcxpresso55s28.dts | 22 +++++++++++++------ 1 file changed, 15 insertions(+), 7 deletions(-) diff --git a/boards/arm/lpcxpresso55s28/lpcxpresso55s28.dts b/boards/arm/lpcxpresso55s28/lpcxpresso55s28.dts index 7f311be98db..a71ffb15157 100644 --- a/boards/arm/lpcxpresso55s28/lpcxpresso55s28.dts +++ b/boards/arm/lpcxpresso55s28/lpcxpresso55s28.dts @@ -1,5 +1,6 @@ /* * Copyright (c) 2020 Lemonbeat GmbH + * Copyright 2023 NXP * * SPDX-License-Identifier: Apache-2.0 */ @@ -25,9 +26,11 @@ chosen { zephyr,sram = &sram0; zephyr,flash = &flash0; + zephyr,code-partition = &slot0_partition; zephyr,console = &flexcomm0; zephyr,shell-uart = &flexcomm0; zephyr,entropy = &rng; + zephyr,flash-controller = &iap; }; gpio_keys { @@ -95,22 +98,27 @@ }; &flash0 { - /* - * LPC flash controller requires minimum 512 byte write to flash, - * so MCUBoot is not supported. Just provide storage and code partition. - */ partitions { compatible = "fixed-partitions"; #address-cells = <1>; #size-cells = <1>; - slot0_partition: partition@0 { + boot_partition: partition@0 { + label = "mcuboot"; + reg = <0x0 DT_SIZE_K(32)>; + }; + slot0_partition: partition@8000 { label = "image-0"; - reg = <0x00000000 DT_SIZE_K(448)>; + reg = <0x00008000 DT_SIZE_K(208)>; + }; + slot1_partition: partition@3C000 { + label = "image-1"; + reg = <0x0003C000 DT_SIZE_K(208)>; }; storage_partition: partition@70000 { label = "storage"; - reg = <0x00070000 DT_SIZE_K(64)>; + reg = <0x00070000 DT_SIZE_K(52)>; }; + /* The last 12KBs are reserved for PFR. */ }; }; From 91293187d8a333e875e53815c0bc0ef648160508 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Manuel=20Arg=C3=BCelles?= Date: Thu, 16 Nov 2023 21:48:32 +0700 Subject: [PATCH 0526/3723] soc: nxp_s32: introduce support for S32K1 devices MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Introduce support for NXP S32K1 family of 32-bit MCUs, and particularly for S32K146 devices. S32K1 share a fair amount of similarities with Kinetis family, so most of the peripheral drivers can be reused. Signed-off-by: Manuel Argüelles --- soc/arm/nxp_s32/common/osif.c | 6 + soc/arm/nxp_s32/s32k1/CMakeLists.txt | 10 + .../nxp_s32/s32k1/Kconfig.defconfig.s32k146 | 14 + .../nxp_s32/s32k1/Kconfig.defconfig.series | 32 ++ soc/arm/nxp_s32/s32k1/Kconfig.series | 18 + soc/arm/nxp_s32/s32k1/Kconfig.soc | 446 ++++++++++++++++++ soc/arm/nxp_s32/s32k1/flash_config.ld | 9 + soc/arm/nxp_s32/s32k1/flash_configuration.c | 32 ++ soc/arm/nxp_s32/s32k1/nxp_mpu_regions.c | 60 +++ soc/arm/nxp_s32/s32k1/pinctrl_soc.h | 48 ++ soc/arm/nxp_s32/s32k1/soc.c | 86 ++++ soc/arm/nxp_s32/s32k1/soc.h | 39 ++ west.yml | 2 +- 13 files changed, 801 insertions(+), 1 deletion(-) create mode 100644 soc/arm/nxp_s32/s32k1/CMakeLists.txt create mode 100644 soc/arm/nxp_s32/s32k1/Kconfig.defconfig.s32k146 create mode 100644 soc/arm/nxp_s32/s32k1/Kconfig.defconfig.series create mode 100644 soc/arm/nxp_s32/s32k1/Kconfig.series create mode 100644 soc/arm/nxp_s32/s32k1/Kconfig.soc create mode 100644 soc/arm/nxp_s32/s32k1/flash_config.ld create mode 100644 soc/arm/nxp_s32/s32k1/flash_configuration.c create mode 100644 soc/arm/nxp_s32/s32k1/nxp_mpu_regions.c create mode 100644 soc/arm/nxp_s32/s32k1/pinctrl_soc.h create mode 100644 soc/arm/nxp_s32/s32k1/soc.c create mode 100644 soc/arm/nxp_s32/s32k1/soc.h diff --git a/soc/arm/nxp_s32/common/osif.c b/soc/arm/nxp_s32/common/osif.c index 970e127fe13..73b5c6c1d1f 100644 --- a/soc/arm/nxp_s32/common/osif.c +++ b/soc/arm/nxp_s32/common/osif.c @@ -8,6 +8,12 @@ #include #include +#if defined(CONFIG_SOC_SERIES_S32K1XX) +/* Aliases needed to build with different SoC-specific HAL versions */ +#define CPXNUM CPxNUM +#define MSCM_CPXNUM_CPN_MASK MSCM_CPxNUM_CPN_MASK +#endif + /* Required by OsIf timer initialization but not used with Zephyr, so no values configured */ static const OsIf_ConfigType osif_config; const OsIf_ConfigType *const OsIf_apxPredefinedConfig[OSIF_MAX_COREIDX_SUPPORTED] = { diff --git a/soc/arm/nxp_s32/s32k1/CMakeLists.txt b/soc/arm/nxp_s32/s32k1/CMakeLists.txt new file mode 100644 index 00000000000..ff8085fc5c1 --- /dev/null +++ b/soc/arm/nxp_s32/s32k1/CMakeLists.txt @@ -0,0 +1,10 @@ +# Copyright 2023 NXP +# SPDX-License-Identifier: Apache-2.0 + +set(SOC_LINKER_SCRIPT ${ZEPHYR_BASE}/include/zephyr/arch/arm/cortex_m/scripts/linker.ld CACHE INTERNAL "") + +zephyr_sources(soc.c) +zephyr_sources_ifdef(CONFIG_ARM_MPU nxp_mpu_regions.c) + +zephyr_sources_ifdef(CONFIG_NXP_S32_FLASH_CONFIG flash_configuration.c) +zephyr_linker_sources_ifdef(CONFIG_NXP_S32_FLASH_CONFIG ROM_START SORT_KEY 0x1 flash_config.ld) diff --git a/soc/arm/nxp_s32/s32k1/Kconfig.defconfig.s32k146 b/soc/arm/nxp_s32/s32k1/Kconfig.defconfig.s32k146 new file mode 100644 index 00000000000..522710112dc --- /dev/null +++ b/soc/arm/nxp_s32/s32k1/Kconfig.defconfig.s32k146 @@ -0,0 +1,14 @@ +# NXP S32K146 + +# Copyright 2023 NXP +# SPDX-License-Identifier: Apache-2.0 + +if SOC_S32K146 + +config SOC + default "s32k146" + +config FPU + default y + +endif # SOC_S32K146 diff --git a/soc/arm/nxp_s32/s32k1/Kconfig.defconfig.series b/soc/arm/nxp_s32/s32k1/Kconfig.defconfig.series new file mode 100644 index 00000000000..49dfd9f31cf --- /dev/null +++ b/soc/arm/nxp_s32/s32k1/Kconfig.defconfig.series @@ -0,0 +1,32 @@ +# NXP S32K1XX MCU series + +# Copyright 2023 NXP +# SPDX-License-Identifier: Apache-2.0 + +if SOC_SERIES_S32K1XX + +config SOC_SERIES + default "s32k1" + +config SYS_CLOCK_HW_CYCLES_PER_SEC + default 80000000 + +config NUM_IRQS + default 239 if CPU_CORTEX_M4 + default 47 if CPU_CORTEX_M0PLUS + +if !XIP +config FLASH_SIZE + default 0 +config FLASH_BASE_ADDRESS + default 0 +endif + +# The S32K1xx have 8 MPU regions, which is not enough for both HW stack protection +# and userspace. Only enable HW stack protection if userspace is not enabled. +config HW_STACK_PROTECTION + default y if !USERSPACE + +source "soc/arm/nxp_s32/s32k1/Kconfig.defconfig.s32k1*" + +endif # SOC_SERIES_S32K1XX diff --git a/soc/arm/nxp_s32/s32k1/Kconfig.series b/soc/arm/nxp_s32/s32k1/Kconfig.series new file mode 100644 index 00000000000..e12df1c488f --- /dev/null +++ b/soc/arm/nxp_s32/s32k1/Kconfig.series @@ -0,0 +1,18 @@ +# NXP S32K1XX MCU series + +# Copyright 2023 NXP +# SPDX-License-Identifier: Apache-2.0 + +config SOC_SERIES_S32K1XX + bool "NXP S32K1XX MCU series" + select ARM + select SOC_FAMILY_NXP_S32 + select HAS_NXP_S32_HAL + select HAS_MCUX + select CPU_HAS_NXP_MPU + select CPU_HAS_CUSTOM_FIXED_SOC_MPU_REGIONS + select MPU_ALLOW_FLASH_WRITE if !XIP + select CLOCK_CONTROL + select HAS_MCUX_LPUART + help + Enable support for NXP S32K1XX MCU series. diff --git a/soc/arm/nxp_s32/s32k1/Kconfig.soc b/soc/arm/nxp_s32/s32k1/Kconfig.soc new file mode 100644 index 00000000000..83a2b59d67c --- /dev/null +++ b/soc/arm/nxp_s32/s32k1/Kconfig.soc @@ -0,0 +1,446 @@ +# NXP S32K1XX MCUs line + +# Copyright 2023 NXP +# SPDX-License-Identifier: Apache-2.0 + +choice + prompt "NXP S32K1XX MCU selection" + depends on SOC_SERIES_S32K1XX + +config SOC_S32K116 + bool "S32K116" + select CPU_CORTEX_M0PLUS + +config SOC_S32K118 + bool "S32K118" + select CPU_CORTEX_M0PLUS + +config SOC_S32K142 + bool "S32K142" + select CPU_CORTEX_M4 + select CPU_CORTEX_M_HAS_DWT + select CPU_HAS_FPU + select CPU_HAS_DCACHE + select CPU_HAS_ICACHE + +config SOC_S32K142W + bool "S32K142W" + select CPU_CORTEX_M4 + select CPU_CORTEX_M_HAS_DWT + select CPU_HAS_FPU + select CPU_HAS_DCACHE + select CPU_HAS_ICACHE + +config SOC_S32K144 + bool "S32K144" + select CPU_CORTEX_M4 + select CPU_CORTEX_M_HAS_DWT + select CPU_HAS_FPU + select CPU_HAS_DCACHE + select CPU_HAS_ICACHE + +config SOC_S32K144W + bool "S32K144W" + select CPU_CORTEX_M4 + select CPU_CORTEX_M_HAS_DWT + select CPU_HAS_FPU + select CPU_HAS_DCACHE + select CPU_HAS_ICACHE + +config SOC_S32K146 + bool "S32K146" + select CPU_CORTEX_M4 + select CPU_CORTEX_M_HAS_DWT + select CPU_HAS_FPU + select CPU_HAS_DCACHE + select CPU_HAS_ICACHE + +config SOC_S32K148 + bool "S32K148" + select CPU_CORTEX_M4 + select CPU_CORTEX_M_HAS_DWT + select CPU_HAS_FPU + select CPU_HAS_DCACHE + select CPU_HAS_ICACHE + +endchoice + +if SOC_SERIES_S32K1XX + +config SOC_PART_NUMBER_FS32K116LAT0MFMT + bool + +config SOC_PART_NUMBER_FS32K116LAT0MLFR + bool + +config SOC_PART_NUMBER_FS32K116LAT0MLFT + bool + +config SOC_PART_NUMBER_FS32K116LIT0VFMT + bool + +config SOC_PART_NUMBER_FS32K116LIT0VLFT + bool + +config SOC_PART_NUMBER_FS32K118LAT0MLFR + bool + +config SOC_PART_NUMBER_FS32K118LAT0MLFT + bool + +config SOC_PART_NUMBER_FS32K118LAT0MLHR + bool + +config SOC_PART_NUMBER_FS32K118LAT0MLHT + bool + +config SOC_PART_NUMBER_FS32K118LIT0VLFT + bool + +config SOC_PART_NUMBER_FS32K142HAT0MLFT + bool + +config SOC_PART_NUMBER_FS32K142HAT0MLHT + bool + +config SOC_PART_NUMBER_FS32K142HAT0MLLR + bool + +config SOC_PART_NUMBER_FS32K142HAT0MLLT + bool + +config SOC_PART_NUMBER_FS32K142HVT0VLHT + bool + +config SOC_PART_NUMBER_FS32K142UAT0VLFT + bool + +config SOC_PART_NUMBER_FS32K142UAT0VLHR + bool + +config SOC_PART_NUMBER_FS32K142UAT0VLHT + bool + +config SOC_PART_NUMBER_FS32K142UAT0VLLR + bool + +config SOC_PART_NUMBER_FS32K142UAT0VLLT + bool + +config SOC_PART_NUMBER_FS32K142UIT0VLHT + bool + +config SOC_PART_NUMBER_FS32K142WAT0WLFT + bool + +config SOC_PART_NUMBER_FS32K142WAT0WLHT + bool + +config SOC_PART_NUMBER_FS32K144HAT0MLFT + bool + +config SOC_PART_NUMBER_FS32K144HAT0MLHR + bool + +config SOC_PART_NUMBER_FS32K144HAT0MLHT + bool + +config SOC_PART_NUMBER_FS32K144HAT0MLLR + bool + +config SOC_PART_NUMBER_FS32K144HAT0MLLT + bool + +config SOC_PART_NUMBER_FS32K144HAT0MMHR + bool + +config SOC_PART_NUMBER_FS32K144HAT0MMHT + bool + +config SOC_PART_NUMBER_FS32K144HVT0VLHR + bool + +config SOC_PART_NUMBER_FS32K144HVT0VLHT + bool + +config SOC_PART_NUMBER_FS32K144HXT0VLHT + bool + +config SOC_PART_NUMBER_FS32K144HXT0VLLT + bool + +config SOC_PART_NUMBER_FS32K144UAT0VLFT + bool + +config SOC_PART_NUMBER_FS32K144UAT0VLHR + bool + +config SOC_PART_NUMBER_FS32K144UAT0VLHT + bool + +config SOC_PART_NUMBER_FS32K144UAT0VLLT + bool + +config SOC_PART_NUMBER_FS32K144UAT0VMHR + bool + +config SOC_PART_NUMBER_FS32K144UAT0VMHT + bool + +config SOC_PART_NUMBER_FS32K144UIT0VLHT + bool + +config SOC_PART_NUMBER_FS32K144ULT0VLHT + bool + +config SOC_PART_NUMBER_FS32K144ULT0VLLR + bool + +config SOC_PART_NUMBER_FS32K144ULT0VLLT + bool + +config SOC_PART_NUMBER_FS32K144WAT0WLFT + bool + +config SOC_PART_NUMBER_FS32K144WAT0WLHT + bool + +config SOC_PART_NUMBER_FS32K146HAT0MLHR + bool + +config SOC_PART_NUMBER_FS32K146HAT0MLHT + bool + +config SOC_PART_NUMBER_FS32K146HAT0MLLR + bool + +config SOC_PART_NUMBER_FS32K146HAT0MLLT + bool + +config SOC_PART_NUMBER_FS32K146HAT0MLQR + bool + +config SOC_PART_NUMBER_FS32K146HAT0MLQT + bool + +config SOC_PART_NUMBER_FS32K146HAT0MMHR + bool + +config SOC_PART_NUMBER_FS32K146HAT0MMHT + bool + +config SOC_PART_NUMBER_FS32K146HVT0VLHT + bool + +config SOC_PART_NUMBER_FS32K146HXT0VLLT + bool + +config SOC_PART_NUMBER_FS32K146UAT0VLHR + bool + +config SOC_PART_NUMBER_FS32K146UAT0VLHT + bool + +config SOC_PART_NUMBER_FS32K146UAT0VLLR + bool + +config SOC_PART_NUMBER_FS32K146UAT0VLLT + bool + +config SOC_PART_NUMBER_FS32K146UAT0VLQR + bool + +config SOC_PART_NUMBER_FS32K146UAT0VLQT + bool + +config SOC_PART_NUMBER_FS32K146UAT0VMHR + bool + +config SOC_PART_NUMBER_FS32K146UAT0VMHT + bool + +config SOC_PART_NUMBER_FS32K146UIT0VLLT + bool + +config SOC_PART_NUMBER_FS32K146ULT0VLLT + bool + +config SOC_PART_NUMBER_FS32K148HAT0MLLR + bool + +config SOC_PART_NUMBER_FS32K148HAT0MLLT + bool + +config SOC_PART_NUMBER_FS32K148HAT0MLQR + bool + +config SOC_PART_NUMBER_FS32K148HAT0MLQT + bool + +config SOC_PART_NUMBER_FS32K148HAT0MLUT + bool + +config SOC_PART_NUMBER_FS32K148HAT0MMHT + bool + +config SOC_PART_NUMBER_FS32K148UGT0VLQT + bool + +config SOC_PART_NUMBER_FS32K148UIT0VLQT + bool + +config SOC_PART_NUMBER_FS32K148UJT0VLLT + bool + +config SOC_PART_NUMBER_FS32K148UJT0VLQT + bool + +config SOC_PART_NUMBER_FS32K148UJT0VLUT + bool + +config SOC_PART_NUMBER_FS32K148UJT0VMHR + bool + +config SOC_PART_NUMBER_FS32K148UJT0VMHT + bool + +config SOC_PART_NUMBER_S32K1XX + string + default "FS32K116LAT0MFMT" if SOC_PART_NUMBER_FS32K116LAT0MFMT + default "FS32K116LAT0MLFR" if SOC_PART_NUMBER_FS32K116LAT0MLFR + default "FS32K116LAT0MLFT" if SOC_PART_NUMBER_FS32K116LAT0MLFT + default "FS32K116LIT0VFMT" if SOC_PART_NUMBER_FS32K116LIT0VFMT + default "FS32K116LIT0VLFT" if SOC_PART_NUMBER_FS32K116LIT0VLFT + default "FS32K118LAT0MLFR" if SOC_PART_NUMBER_FS32K118LAT0MLFR + default "FS32K118LAT0MLFT" if SOC_PART_NUMBER_FS32K118LAT0MLFT + default "FS32K118LAT0MLHR" if SOC_PART_NUMBER_FS32K118LAT0MLHR + default "FS32K118LAT0MLHT" if SOC_PART_NUMBER_FS32K118LAT0MLHT + default "FS32K118LIT0VLFT" if SOC_PART_NUMBER_FS32K118LIT0VLFT + default "FS32K142HAT0MLFT" if SOC_PART_NUMBER_FS32K142HAT0MLFT + default "FS32K142HAT0MLHT" if SOC_PART_NUMBER_FS32K142HAT0MLHT + default "FS32K142HAT0MLLR" if SOC_PART_NUMBER_FS32K142HAT0MLLR + default "FS32K142HAT0MLLT" if SOC_PART_NUMBER_FS32K142HAT0MLLT + default "FS32K142HVT0VLHT" if SOC_PART_NUMBER_FS32K142HVT0VLHT + default "FS32K142UAT0VLFT" if SOC_PART_NUMBER_FS32K142UAT0VLFT + default "FS32K142UAT0VLHR" if SOC_PART_NUMBER_FS32K142UAT0VLHR + default "FS32K142UAT0VLHT" if SOC_PART_NUMBER_FS32K142UAT0VLHT + default "FS32K142UAT0VLLR" if SOC_PART_NUMBER_FS32K142UAT0VLLR + default "FS32K142UAT0VLLT" if SOC_PART_NUMBER_FS32K142UAT0VLLT + default "FS32K142UIT0VLHT" if SOC_PART_NUMBER_FS32K142UIT0VLHT + default "FS32K142WAT0WLFT" if SOC_PART_NUMBER_FS32K142WAT0WLFT + default "FS32K142WAT0WLHT" if SOC_PART_NUMBER_FS32K142WAT0WLHT + default "FS32K144HAT0MLFT" if SOC_PART_NUMBER_FS32K144HAT0MLFT + default "FS32K144HAT0MLHR" if SOC_PART_NUMBER_FS32K144HAT0MLHR + default "FS32K144HAT0MLHT" if SOC_PART_NUMBER_FS32K144HAT0MLHT + default "FS32K144HAT0MLLR" if SOC_PART_NUMBER_FS32K144HAT0MLLR + default "FS32K144HAT0MLLT" if SOC_PART_NUMBER_FS32K144HAT0MLLT + default "FS32K144HAT0MMHR" if SOC_PART_NUMBER_FS32K144HAT0MMHR + default "FS32K144HAT0MMHT" if SOC_PART_NUMBER_FS32K144HAT0MMHT + default "FS32K144HVT0VLHR" if SOC_PART_NUMBER_FS32K144HVT0VLHR + default "FS32K144HVT0VLHT" if SOC_PART_NUMBER_FS32K144HVT0VLHT + default "FS32K144HXT0VLHT" if SOC_PART_NUMBER_FS32K144HXT0VLHT + default "FS32K144HXT0VLLT" if SOC_PART_NUMBER_FS32K144HXT0VLLT + default "FS32K144UAT0VLFT" if SOC_PART_NUMBER_FS32K144UAT0VLFT + default "FS32K144UAT0VLHR" if SOC_PART_NUMBER_FS32K144UAT0VLHR + default "FS32K144UAT0VLHT" if SOC_PART_NUMBER_FS32K144UAT0VLHT + default "FS32K144UAT0VLLT" if SOC_PART_NUMBER_FS32K144UAT0VLLT + default "FS32K144UAT0VMHR" if SOC_PART_NUMBER_FS32K144UAT0VMHR + default "FS32K144UAT0VMHT" if SOC_PART_NUMBER_FS32K144UAT0VMHT + default "FS32K144UIT0VLHT" if SOC_PART_NUMBER_FS32K144UIT0VLHT + default "FS32K144ULT0VLHT" if SOC_PART_NUMBER_FS32K144ULT0VLHT + default "FS32K144ULT0VLLR" if SOC_PART_NUMBER_FS32K144ULT0VLLR + default "FS32K144ULT0VLLT" if SOC_PART_NUMBER_FS32K144ULT0VLLT + default "FS32K144WAT0WLFT" if SOC_PART_NUMBER_FS32K144WAT0WLFT + default "FS32K144WAT0WLHT" if SOC_PART_NUMBER_FS32K144WAT0WLHT + default "FS32K146HAT0MLHR" if SOC_PART_NUMBER_FS32K146HAT0MLHR + default "FS32K146HAT0MLHT" if SOC_PART_NUMBER_FS32K146HAT0MLHT + default "FS32K146HAT0MLLR" if SOC_PART_NUMBER_FS32K146HAT0MLLR + default "FS32K146HAT0MLLT" if SOC_PART_NUMBER_FS32K146HAT0MLLT + default "FS32K146HAT0MLQR" if SOC_PART_NUMBER_FS32K146HAT0MLQR + default "FS32K146HAT0MLQT" if SOC_PART_NUMBER_FS32K146HAT0MLQT + default "FS32K146HAT0MMHR" if SOC_PART_NUMBER_FS32K146HAT0MMHR + default "FS32K146HAT0MMHT" if SOC_PART_NUMBER_FS32K146HAT0MMHT + default "FS32K146HVT0VLHT" if SOC_PART_NUMBER_FS32K146HVT0VLHT + default "FS32K146HXT0VLLT" if SOC_PART_NUMBER_FS32K146HXT0VLLT + default "FS32K146UAT0VLHR" if SOC_PART_NUMBER_FS32K146UAT0VLHR + default "FS32K146UAT0VLHT" if SOC_PART_NUMBER_FS32K146UAT0VLHT + default "FS32K146UAT0VLLR" if SOC_PART_NUMBER_FS32K146UAT0VLLR + default "FS32K146UAT0VLLT" if SOC_PART_NUMBER_FS32K146UAT0VLLT + default "FS32K146UAT0VLQR" if SOC_PART_NUMBER_FS32K146UAT0VLQR + default "FS32K146UAT0VLQT" if SOC_PART_NUMBER_FS32K146UAT0VLQT + default "FS32K146UAT0VMHR" if SOC_PART_NUMBER_FS32K146UAT0VMHR + default "FS32K146UAT0VMHT" if SOC_PART_NUMBER_FS32K146UAT0VMHT + default "FS32K146UIT0VLLT" if SOC_PART_NUMBER_FS32K146UIT0VLLT + default "FS32K146ULT0VLLT" if SOC_PART_NUMBER_FS32K146ULT0VLLT + default "FS32K148HAT0MLLR" if SOC_PART_NUMBER_FS32K148HAT0MLLR + default "FS32K148HAT0MLLT" if SOC_PART_NUMBER_FS32K148HAT0MLLT + default "FS32K148HAT0MLQR" if SOC_PART_NUMBER_FS32K148HAT0MLQR + default "FS32K148HAT0MLQT" if SOC_PART_NUMBER_FS32K148HAT0MLQT + default "FS32K148HAT0MLUT" if SOC_PART_NUMBER_FS32K148HAT0MLUT + default "FS32K148HAT0MMHT" if SOC_PART_NUMBER_FS32K148HAT0MMHT + default "FS32K148UGT0VLQT" if SOC_PART_NUMBER_FS32K148UGT0VLQT + default "FS32K148UIT0VLQT" if SOC_PART_NUMBER_FS32K148UIT0VLQT + default "FS32K148UJT0VLLT" if SOC_PART_NUMBER_FS32K148UJT0VLLT + default "FS32K148UJT0VLQT" if SOC_PART_NUMBER_FS32K148UJT0VLQT + default "FS32K148UJT0VLUT" if SOC_PART_NUMBER_FS32K148UJT0VLUT + default "FS32K148UJT0VMHR" if SOC_PART_NUMBER_FS32K148UJT0VMHR + default "FS32K148UJT0VMHT" if SOC_PART_NUMBER_FS32K148UJT0VMHT + help + This string holds the full part number of the SoC. It is a hidden option + that you should not set directly. The part number selection choice defines + the default value for this string. + +config WDOG_INIT + bool + default y + +config NXP_S32_FLASH_CONFIG + bool "NXP S32 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 FTFx module. + +if NXP_S32_FLASH_CONFIG + +config NXP_S32_FLASH_CONFIG_OFFSET + hex "NXP S32 flash configuration field offset" + default 0x400 + +config NXP_S32_FLASH_CONFIG_FSEC + hex "Flash security byte (FSEC)" + range 0 0xff + default 0xfe + help + Configures the reset value of the FSEC register, which includes + backdoor key access, mass erase, factory access, and flash security + options. + +config NXP_S32_FLASH_CONFIG_FOPT + hex "Flash nonvolatile option byte (FOPT)" + range 0 0xff + default 0xff + help + Configures the reset value of the FOPT register, which includes boot, + NMI, and EzPort options. + +config NXP_S32_FLASH_CONFIG_FEPROT + hex "EEPROM protection byte (FEPROT)" + range 0 0xff + default 0xff + help + Configures the reset value of the FEPROT register for FlexNVM + devices. For program flash only devices, this byte is reserved. + +config NXP_S32_FLASH_CONFIG_FDPROT + hex "Data flash protection byte (FDPROT)" + range 0 0xff + default 0xff + help + Configures the reset value of the FDPROT register for FlexNVM + devices. For program flash only devices, this byte is reserved. + +endif # NXP_S32_FLASH_CONFIG + +endif # SOC_SERIES_S32K1XX diff --git a/soc/arm/nxp_s32/s32k1/flash_config.ld b/soc/arm/nxp_s32/s32k1/flash_config.ld new file mode 100644 index 00000000000..6ff64221be4 --- /dev/null +++ b/soc/arm/nxp_s32/s32k1/flash_config.ld @@ -0,0 +1,9 @@ +/* + * Copyright 2023 NXP + * + * SPDX-License-Identifier: Apache-2.0 + */ + +. = CONFIG_NXP_S32_FLASH_CONFIG_OFFSET; +KEEP(*(.kinetis_flash_config)) +KEEP(*(".kinetis_flash_config.*")) diff --git a/soc/arm/nxp_s32/s32k1/flash_configuration.c b/soc/arm/nxp_s32/s32k1/flash_configuration.c new file mode 100644 index 00000000000..af1ec998ebb --- /dev/null +++ b/soc/arm/nxp_s32/s32k1/flash_configuration.c @@ -0,0 +1,32 @@ +/* + * Copyright 2023 NXP + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include +#include + +uint8_t __kinetis_flash_config_section __kinetis_flash_config[] = { + /* Backdoor Comparison Key (unused) */ + 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 + */ + CONFIG_NXP_S32_FLASH_CONFIG_FSEC, + + /* Flash nonvolatile option register (FOPT) enables/disables NMI, + * EzPort, and boot options + */ + CONFIG_NXP_S32_FLASH_CONFIG_FOPT, + + /* EEPROM protection register (FEPROT) for FlexNVM devices */ + CONFIG_NXP_S32_FLASH_CONFIG_FEPROT, + + /* Data flash protection register (FDPROT) for FlexNVM devices */ + CONFIG_NXP_S32_FLASH_CONFIG_FDPROT, +}; diff --git a/soc/arm/nxp_s32/s32k1/nxp_mpu_regions.c b/soc/arm/nxp_s32/s32k1/nxp_mpu_regions.c new file mode 100644 index 00000000000..5c8ac8de3b9 --- /dev/null +++ b/soc/arm/nxp_s32/s32k1/nxp_mpu_regions.c @@ -0,0 +1,60 @@ +/* + * Copyright 2023 NXP + * + * Based on soc/arm/nxp_kinetis/ke1xf/nxp_mpu_regions.c, which is: + * Copyright (c) 2017 Linaro Limited. + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include +#include + +static const struct nxp_mpu_region mpu_regions[] = { + /* Region 0 */ + MPU_REGION_ENTRY("DEBUGGER", + 0, + 0xFFFFFFFF, + REGION_DEBUGGER_AND_DEVICE_ATTR), + + /* Region 1 */ + MPU_REGION_ENTRY("BACKGROUND_0", + 0, + CONFIG_SRAM_BASE_ADDRESS-1, + REGION_BACKGROUND_ATTR), + /* Region 2 */ + MPU_REGION_ENTRY("BACKGROUND_1", + CONFIG_SRAM_BASE_ADDRESS + + (CONFIG_SRAM_SIZE * 1024), + 0xFFFFFFFF, + REGION_BACKGROUND_ATTR), + +#if defined(CONFIG_XIP) + /* Region 3 */ + MPU_REGION_ENTRY("SRAM", + CONFIG_SRAM_BASE_ADDRESS, + (CONFIG_SRAM_BASE_ADDRESS + + (CONFIG_SRAM_SIZE * 1024) - 1), + REGION_RAM_ATTR), + + /* Region 4 */ + MPU_REGION_ENTRY("FLASH", + CONFIG_FLASH_BASE_ADDRESS, + (CONFIG_FLASH_BASE_ADDRESS + + (CONFIG_FLASH_SIZE * 1024) - 1), + REGION_FLASH_ATTR), +#else + /* Region 3 */ + MPU_REGION_ENTRY("SRAM", + CONFIG_SRAM_BASE_ADDRESS, + (CONFIG_SRAM_BASE_ADDRESS + + (CONFIG_SRAM_SIZE * 1024) - 1), + REGION_FLASH_ATTR), +#endif +}; + +const struct nxp_mpu_config mpu_config = { + .num_regions = ARRAY_SIZE(mpu_regions), + .mpu_regions = mpu_regions, + .sram_region = 3, +}; diff --git a/soc/arm/nxp_s32/s32k1/pinctrl_soc.h b/soc/arm/nxp_s32/s32k1/pinctrl_soc.h new file mode 100644 index 00000000000..fde3c12954f --- /dev/null +++ b/soc/arm/nxp_s32/s32k1/pinctrl_soc.h @@ -0,0 +1,48 @@ +/* + * Copyright 2023 NXP + * + * SPDX-License-Identifier: Apache-2.0 + */ + +/* + * @file + * NXP S32K1 SOC specific helpers for pinctrl driver + */ + +#ifndef ZEPHYR_SOC_ARM_NXP_S32_S32K1_PINCTRL_SOC_H_ +#define ZEPHYR_SOC_ARM_NXP_S32_S32K1_PINCTRL_SOC_H_ + +#include +#include + +#ifdef __cplusplus +extern "C" { +#endif + +/** @cond INTERNAL_HIDDEN */ + +typedef uint32_t pinctrl_soc_pin_t; + +#define Z_PINCTRL_KINETIS_PINCFG(node_id) \ + (PORT_PCR_DSE(DT_ENUM_IDX(node_id, drive_strength)) | \ + PORT_PCR_PS(DT_PROP(node_id, bias_pull_up)) | \ + PORT_PCR_PE(DT_PROP(node_id, bias_pull_up)) | \ + PORT_PCR_PE(DT_PROP(node_id, bias_pull_down)) | \ + PORT_PCR_PFE(DT_PROP(node_id, nxp_passive_filter))) + +#define Z_PINCTRL_KINETIS_PCR_MASK \ + (PORT_PCR_MUX_MASK | PORT_PCR_DSE_MASK | PORT_PCR_PFE_MASK | \ + PORT_PCR_PE_MASK | PORT_PCR_PS_MASK) + +#define Z_PINCTRL_STATE_PIN_INIT(group, pin_prop, idx) \ + DT_PROP_BY_IDX(group, pin_prop, idx) | Z_PINCTRL_KINETIS_PINCFG(group), + +#define Z_PINCTRL_STATE_PINS_INIT(node_id, prop) \ + {DT_FOREACH_CHILD_VARGS(DT_PHANDLE(node_id, prop), \ + DT_FOREACH_PROP_ELEM, pinmux, Z_PINCTRL_STATE_PIN_INIT)}; + +#ifdef __cplusplus +} +#endif + +#endif /* ZEPHYR_SOC_ARM_NXP_S32_S32K1_PINCTRL_SOC_H_ */ diff --git a/soc/arm/nxp_s32/s32k1/soc.c b/soc/arm/nxp_s32/s32k1/soc.c new file mode 100644 index 00000000000..8c73b4fa6f5 --- /dev/null +++ b/soc/arm/nxp_s32/s32k1/soc.c @@ -0,0 +1,86 @@ +/* + * Copyright 2023 NXP + * + * Based on zephyr/soc/arm/nxp_kinetis/ke1xf/soc.c, which is: + * Copyright (c) 2019-2021 Vestas Wind Systems A/S + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include +#include +#include +#include + +#include +#include + +#if defined(CONFIG_WDOG_INIT) +#define WDOG_UPDATE_KEY 0xD928C520U + +void z_arm_watchdog_init(void) +{ + /* + * NOTE: DO NOT SINGLE STEP THROUGH THIS SECTION!!! Watchdog + * reconfiguration must take place within 128 bus clocks from + * unlocking. Single stepping through the code will cause the + * watchdog to close the unlock window again. + */ + if ((IP_WDOG->CS & WDOG_CS_CMD32EN_MASK) != 0U) { + IP_WDOG->CNT = WDOG_UPDATE_KEY; + } else { + IP_WDOG->CNT = WDOG_UPDATE_KEY & 0xFFFFU; + IP_WDOG->CNT = (WDOG_UPDATE_KEY >> 16U) & 0xFFFFU; + } + while (!(IP_WDOG->CS & WDOG_CS_ULK_MASK)) { + ; + } + + IP_WDOG->TOVAL = 0xFFFFU; + IP_WDOG->CS = (uint32_t) ((IP_WDOG->CS) & ~WDOG_CS_EN_MASK) | WDOG_CS_UPDATE_MASK; + + /* Wait for new configuration to take effect */ + while (!(IP_WDOG->CS & WDOG_CS_RCS_MASK)) { + ; + } +} +#endif /* CONFIG_WDOG_INIT */ + +static int soc_init(void) +{ +#if !defined(CONFIG_ARM_MPU) + uint32_t tmp; + + /* + * Disable memory protection and clear slave port errors. + * Note that the S32K1xx does not implement the optional Arm MPU but + * instead the Soc includes its own NXP MPU module. + */ + tmp = IP_MPU->CESR; + tmp &= ~MPU_CESR_VLD_MASK; + tmp |= MPU_CESR_SPERR0_MASK | MPU_CESR_SPERR1_MASK + | MPU_CESR_SPERR2_MASK | MPU_CESR_SPERR3_MASK; + IP_MPU->CESR = tmp; +#endif /* !CONFIG_ARM_MPU */ + +#if defined(CONFIG_DCACHE) && defined(CONFIG_ICACHE) + /* Invalidate all ways */ + IP_LMEM->PCCCR |= LMEM_PCCCR_INVW1_MASK | LMEM_PCCCR_INVW0_MASK; + IP_LMEM->PCCCR |= LMEM_PCCCR_GO_MASK; + + /* Wait until the command completes */ + while (IP_LMEM->PCCCR & LMEM_PCCCR_GO_MASK) { + ; + } + + /* Enable cache */ + IP_LMEM->PCCCR |= (LMEM_PCCCR_ENCACHE_MASK); + barrier_isync_fence_full(); +#endif + + OsIf_Init(NULL); + + return 0; +} + +SYS_INIT(soc_init, PRE_KERNEL_1, 0); diff --git a/soc/arm/nxp_s32/s32k1/soc.h b/soc/arm/nxp_s32/s32k1/soc.h new file mode 100644 index 00000000000..b58a49ab256 --- /dev/null +++ b/soc/arm/nxp_s32/s32k1/soc.h @@ -0,0 +1,39 @@ +/* + * Copyright 2023 NXP + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#ifndef _NXP_S32_S32K1_SOC_H_ +#define _NXP_S32_S32K1_SOC_H_ + +#include + +#if defined(CONFIG_SOC_S32K116) +#include +#elif defined(CONFIG_SOC_S32K118) +#include +#elif defined(CONFIG_SOC_S32K142) +#include +#elif defined(CONFIG_SOC_S32K142W) +#include +#elif defined(CONFIG_SOC_S32K144) +#include +#elif defined(CONFIG_SOC_S32K144W) +#include +#elif defined(CONFIG_SOC_S32K146) +#include +#elif defined(CONFIG_SOC_S32K148) +#include +#else +#error "SoC not supported" +#endif + +#if defined(CONFIG_CMSIS_RTOS_V2) +#include +#endif + +/* GPIO setting for the Port Mux Register */ +#define PORT_MUX_GPIO kPORT_MuxAsGpio + +#endif /* _NXP_S32_S32K1_SOC_H_ */ diff --git a/west.yml b/west.yml index 78bede760fd..10042a7a5ff 100644 --- a/west.yml +++ b/west.yml @@ -193,7 +193,7 @@ manifest: groups: - hal - name: hal_nxp - revision: 1ed023da7f5541b78099b5a030507a2839ce554f + revision: 2796169ee23dc838311b65758806eb94546a7bc2 path: modules/hal/nxp groups: - hal From 81de2af68f8947d05295b3dfbb034d90a9d02b75 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Manuel=20Arg=C3=BCelles?= Date: Thu, 16 Nov 2023 21:51:56 +0700 Subject: [PATCH 0527/3723] dts: arm: introduce support for NXP S32K146 MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Add minimal support for S32K146 devices including clocks, MPU, pin control, GPIO and UART. Signed-off-by: Manuel Argüelles --- dts/arm/nxp/nxp_s32k146.dtsi | 51 ++++++ dts/arm/nxp/nxp_s32k1xx.dtsi | 156 ++++++++++++++++++ .../dt-bindings/clock/nxp_s32k146_clock.h | 99 +++++++++++ 3 files changed, 306 insertions(+) create mode 100644 dts/arm/nxp/nxp_s32k146.dtsi create mode 100644 dts/arm/nxp/nxp_s32k1xx.dtsi create mode 100644 include/zephyr/dt-bindings/clock/nxp_s32k146_clock.h diff --git a/dts/arm/nxp/nxp_s32k146.dtsi b/dts/arm/nxp/nxp_s32k146.dtsi new file mode 100644 index 00000000000..834c0ad360d --- /dev/null +++ b/dts/arm/nxp/nxp_s32k146.dtsi @@ -0,0 +1,51 @@ +/* + * Copyright 2023 NXP + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include +#include + +/ { + cpus { + cpu@0 { + compatible = "arm,cortex-m4f"; + }; + }; + + soc { + /* + * SRAM_L and SRAM_U ranges form a contiguous block but misaligned + * and burst accesses cannot occur across the 0x20000000 boundary + * that separates the two SRAM arrays. Hence, treat the two arrays + * as separate memory ranges. + */ + sram_l: sram@1fff0000 { + compatible = "mmio-sram"; + reg = <0x1fff0000 DT_SIZE_K(64)>; + }; + + sram_u: sram@20000000 { + compatible = "mmio-sram"; + reg = <0x20000000 DT_SIZE_K(60)>; + }; + }; +}; + +&nvic { + arm,num-irq-priority-bits = <4>; +}; + +&ftfc { + flash0: flash@0 { + compatible = "soc-nv-flash"; + reg = <0 DT_SIZE_M(1)>; + erase-block-size = ; + write-block-size = <8>; + }; +}; + +&lpuart2 { + clocks = <&clock NXP_S32_LPUART2_CLK>; +}; diff --git a/dts/arm/nxp/nxp_s32k1xx.dtsi b/dts/arm/nxp/nxp_s32k1xx.dtsi new file mode 100644 index 00000000000..e7a49f3fa17 --- /dev/null +++ b/dts/arm/nxp/nxp_s32k1xx.dtsi @@ -0,0 +1,156 @@ +/* + * Copyright 2023 NXP + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include +#include + +/ { + cpus { + #address-cells = <1>; + #size-cells = <0>; + + cpu@0 { + device_type = "cpu"; + reg = <0>; + }; + }; + + /* Dummy pinctrl node, filled with pin mux options at board level */ + pinctrl: pinctrl { + compatible = "nxp,kinetis-pinctrl"; + status = "okay"; + }; + + soc { + interrupt-parent = <&nvic>; + + mpu: mpu@4000d000 { + compatible = "nxp,kinetis-mpu"; + reg = <0x4000d000 0x1000>; + status = "disabled"; + }; + + 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"; + }; + + porta: pinmux@40049000 { + compatible = "nxp,kinetis-pinmux"; + reg = <0x40049000 0x1000>; + clocks = <&clock NXP_S32_PORTA_CLK>; + }; + + portb: pinmux@4004a000 { + compatible = "nxp,kinetis-pinmux"; + reg = <0x4004a000 0x1000>; + clocks = <&clock NXP_S32_PORTB_CLK>; + }; + + portc: pinmux@4004b000 { + compatible = "nxp,kinetis-pinmux"; + reg = <0x4004b000 0x1000>; + clocks = <&clock NXP_S32_PORTC_CLK>; + }; + + portd: pinmux@4004c000 { + compatible = "nxp,kinetis-pinmux"; + reg = <0x4004c000 0x1000>; + clocks = <&clock NXP_S32_PORTD_CLK>; + }; + + porte: pinmux@4004d000 { + compatible = "nxp,kinetis-pinmux"; + reg = <0x4004d000 0x1000>; + clocks = <&clock NXP_S32_PORTE_CLK>; + }; + + clock: clock-controller@40064000 { + compatible = "nxp,s32-clock"; + reg = <0x40064000 0x1000>, <0x40065000 0x1000>; + #clock-cells = <1>; + status = "okay"; + }; + + lpuart0: uart@4006a000 { + compatible = "nxp,kinetis-lpuart"; + reg = <0x4006a000 0x1000>; + interrupts = <31 0>; + clocks = <&clock NXP_S32_LPUART0_CLK>; + status = "disabled"; + }; + + lpuart1: uart@4006b000 { + compatible = "nxp,kinetis-lpuart"; + reg = <0x4006b000 0x1000>; + interrupts = <33 0>; + clocks = <&clock NXP_S32_LPUART1_CLK>; + status = "disabled"; + }; + + lpuart2: uart@4006c000 { + compatible = "nxp,kinetis-lpuart"; + reg = <0x4006c000 0x1000>; + interrupts = <35 0>; + 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"; + }; + }; +}; diff --git a/include/zephyr/dt-bindings/clock/nxp_s32k146_clock.h b/include/zephyr/dt-bindings/clock/nxp_s32k146_clock.h new file mode 100644 index 00000000000..f3a11104e74 --- /dev/null +++ b/include/zephyr/dt-bindings/clock/nxp_s32k146_clock.h @@ -0,0 +1,99 @@ +/* + * Copyright 2023 NXP + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#ifndef ZEPHYR_INCLUDE_DT_BINDINGS_CLOCK_NXP_S32K146_CLOCK_H_ +#define ZEPHYR_INCLUDE_DT_BINDINGS_CLOCK_NXP_S32K146_CLOCK_H_ + +#define NXP_S32_LPO_128K_CLK 1U +#define NXP_S32_SIRC_CLK 2U +#define NXP_S32_SIRC_VLP_CLK 3U +#define NXP_S32_SIRC_STOP_CLK 4U +#define NXP_S32_FIRC_CLK 5U +#define NXP_S32_FIRC_VLP_CLK 6U +#define NXP_S32_FIRC_STOP_CLK 7U +#define NXP_S32_SOSC_CLK 8U +#define NXP_S32_SPLL_CLK 9U +#define NXP_S32_SIRCDIV1_CLK 10U +#define NXP_S32_SIRCDIV2_CLK 11U +#define NXP_S32_FIRCDIV1_CLK 12U +#define NXP_S32_FIRCDIV2_CLK 13U +#define NXP_S32_SOSCDIV1_CLK 14U +#define NXP_S32_SOSCDIV2_CLK 15U +#define NXP_S32_SPLLDIV1_CLK 16U +#define NXP_S32_SPLLDIV2_CLK 17U +#define NXP_S32_LPO_32K_CLK 18U +#define NXP_S32_LPO_1K_CLK 19U +#define NXP_S32_TCLK0_REF_CLK 20U +#define NXP_S32_TCLK1_REF_CLK 21U +#define NXP_S32_TCLK2_REF_CLK 22U +#define NXP_S32_SCS_CLK 24U +#define NXP_S32_SCS_RUN_CLK 25U +#define NXP_S32_SCS_VLPR_CLK 26U +#define NXP_S32_SCS_HSRUN_CLK 27U +#define NXP_S32_CORE_CLK 28U +#define NXP_S32_CORE_RUN_CLK 29U +#define NXP_S32_CORE_VLPR_CLK 30U +#define NXP_S32_CORE_HSRUN_CLK 31U +#define NXP_S32_BUS_CLK 32U +#define NXP_S32_BUS_RUN_CLK 33U +#define NXP_S32_BUS_VLPR_CLK 34U +#define NXP_S32_BUS_HSRUN_CLK 35U +#define NXP_S32_SLOW_CLK 36U +#define NXP_S32_SLOW_RUN_CLK 37U +#define NXP_S32_SLOW_VLPR_CLK 38U +#define NXP_S32_SLOW_HSRUN_CLK 39U +#define NXP_S32_RTC_CLK 40U +#define NXP_S32_LPO_CLK 41U +#define NXP_S32_SCG_CLKOUT_CLK 42U +#define NXP_S32_FTM0_EXT_CLK 43U +#define NXP_S32_FTM1_EXT_CLK 44U +#define NXP_S32_FTM2_EXT_CLK 45U +#define NXP_S32_FTM3_EXT_CLK 46U +#define NXP_S32_FTM4_EXT_CLK 47U +#define NXP_S32_FTM5_EXT_CLK 48U +#define NXP_S32_ADC0_CLK 50U +#define NXP_S32_ADC1_CLK 51U +#define NXP_S32_CLKOUT0_CLK 52U +#define NXP_S32_CMP0_CLK 53U +#define NXP_S32_CRC0_CLK 54U +#define NXP_S32_DMA0_CLK 55U +#define NXP_S32_DMAMUX0_CLK 56U +#define NXP_S32_EIM0_CLK 57U +#define NXP_S32_ERM0_CLK 58U +#define NXP_S32_EWM0_CLK 59U +#define NXP_S32_FLEXCAN0_CLK 60U +#define NXP_S32_FLEXCAN1_CLK 61U +#define NXP_S32_FLEXCAN2_CLK 62U +#define NXP_S32_FLEXIO_CLK 63U +#define NXP_S32_FTFC_CLK 64U +#define NXP_S32_FTM0_CLK 65U +#define NXP_S32_FTM1_CLK 66U +#define NXP_S32_FTM2_CLK 67U +#define NXP_S32_FTM3_CLK 68U +#define NXP_S32_FTM4_CLK 69U +#define NXP_S32_FTM5_CLK 70U +#define NXP_S32_LPI2C0_CLK 71U +#define NXP_S32_LPIT0_CLK 72U +#define NXP_S32_LPSPI0_CLK 73U +#define NXP_S32_LPSPI1_CLK 74U +#define NXP_S32_LPSPI2_CLK 75U +#define NXP_S32_LPTMR0_CLK 76U +#define NXP_S32_LPUART0_CLK 77U +#define NXP_S32_LPUART1_CLK 78U +#define NXP_S32_LPUART2_CLK 79U +#define NXP_S32_MPU0_CLK 80U +#define NXP_S32_MSCM0_CLK 81U +#define NXP_S32_PDB0_CLK 82U +#define NXP_S32_PDB1_CLK 83U +#define NXP_S32_PORTA_CLK 84U +#define NXP_S32_PORTB_CLK 85U +#define NXP_S32_PORTC_CLK 86U +#define NXP_S32_PORTD_CLK 87U +#define NXP_S32_PORTE_CLK 88U +#define NXP_S32_RTC0_CLK 89U +#define NXP_S32_TRACE_CLK 90U + +#endif /* ZEPHYR_INCLUDE_DT_BINDINGS_CLOCK_NXP_S32K146_CLOCK_H_ */ From 23053cfea5dd230cf279e50e64ac1077abaf8b29 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Manuel=20Arg=C3=BCelles?= Date: Thu, 16 Nov 2023 21:55:49 +0700 Subject: [PATCH 0528/3723] boards: arm: introduce support for NXP UCANS32K1SIC MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Introduce minimal support for NXP UCANS32K1SIC board based on S32K146 MCUs. This includes support to run from internal Flash or SRAM, multiple west runners for TRACE32 and J-Link, and the minimal set of drivers. Signed-off-by: Manuel Argüelles --- boards/arm/ucans32k1sic/Kconfig.board | 7 + boards/arm/ucans32k1sic/Kconfig.defconfig | 16 ++ boards/arm/ucans32k1sic/board.cmake | 21 +++ .../doc/img/ucans32k1sic_top.webp | Bin 0 -> 49592 bytes boards/arm/ucans32k1sic/doc/index.rst | 176 ++++++++++++++++++ boards/arm/ucans32k1sic/support/debug.cmm | 13 ++ boards/arm/ucans32k1sic/support/flash.cmm | 13 ++ boards/arm/ucans32k1sic/support/startup.cmm | 128 +++++++++++++ .../ucans32k1sic/ucans32k1sic-pinctrl.dtsi | 23 +++ boards/arm/ucans32k1sic/ucans32k1sic.dts | 91 +++++++++ boards/arm/ucans32k1sic/ucans32k1sic.yaml | 17 ++ .../arm/ucans32k1sic/ucans32k1sic_defconfig | 20 ++ 12 files changed, 525 insertions(+) create mode 100644 boards/arm/ucans32k1sic/Kconfig.board create mode 100644 boards/arm/ucans32k1sic/Kconfig.defconfig create mode 100644 boards/arm/ucans32k1sic/board.cmake create mode 100644 boards/arm/ucans32k1sic/doc/img/ucans32k1sic_top.webp create mode 100644 boards/arm/ucans32k1sic/doc/index.rst create mode 100644 boards/arm/ucans32k1sic/support/debug.cmm create mode 100644 boards/arm/ucans32k1sic/support/flash.cmm create mode 100644 boards/arm/ucans32k1sic/support/startup.cmm create mode 100644 boards/arm/ucans32k1sic/ucans32k1sic-pinctrl.dtsi create mode 100644 boards/arm/ucans32k1sic/ucans32k1sic.dts create mode 100644 boards/arm/ucans32k1sic/ucans32k1sic.yaml create mode 100644 boards/arm/ucans32k1sic/ucans32k1sic_defconfig diff --git a/boards/arm/ucans32k1sic/Kconfig.board b/boards/arm/ucans32k1sic/Kconfig.board new file mode 100644 index 00000000000..314c7f98d5e --- /dev/null +++ b/boards/arm/ucans32k1sic/Kconfig.board @@ -0,0 +1,7 @@ +# Copyright 2023 NXP +# SPDX-License-Identifier: Apache-2.0 + +config BOARD_UCANS32K1SIC + bool "ucans32k1sic" + depends on SOC_SERIES_S32K1XX + select SOC_PART_NUMBER_FS32K146UAT0VLHT diff --git a/boards/arm/ucans32k1sic/Kconfig.defconfig b/boards/arm/ucans32k1sic/Kconfig.defconfig new file mode 100644 index 00000000000..88941a6f64a --- /dev/null +++ b/boards/arm/ucans32k1sic/Kconfig.defconfig @@ -0,0 +1,16 @@ +# Copyright 2023 NXP +# SPDX-License-Identifier: Apache-2.0 + +if BOARD_UCANS32K1SIC + +config BOARD + default "ucans32k1sic" + +if SERIAL + +config UART_CONSOLE + default y + +endif # SERIAL + +endif # BOARD_UCANS32K1SIC diff --git a/boards/arm/ucans32k1sic/board.cmake b/boards/arm/ucans32k1sic/board.cmake new file mode 100644 index 00000000000..5cb17a1b6c2 --- /dev/null +++ b/boards/arm/ucans32k1sic/board.cmake @@ -0,0 +1,21 @@ +# Copyright 2023 NXP +# SPDX-License-Identifier: Apache-2.0 + +board_runner_args(jlink + "--device=S32K146" + "--speed=4000" + "--iface=swd" + "--reset" +) + +board_runner_args(trace32 + "--startup-args" "elfFile=${PROJECT_BINARY_DIR}/${KERNEL_ELF_NAME}" +) +if(${CONFIG_XIP}) + board_runner_args(trace32 "loadTo=flash") +else() + board_runner_args(trace32 "loadTo=sram") +endif() + +include(${ZEPHYR_BASE}/boards/common/jlink.board.cmake) +include(${ZEPHYR_BASE}/boards/common/trace32.board.cmake) diff --git a/boards/arm/ucans32k1sic/doc/img/ucans32k1sic_top.webp b/boards/arm/ucans32k1sic/doc/img/ucans32k1sic_top.webp new file mode 100644 index 0000000000000000000000000000000000000000..ddd2bdafb8fd04a6dc3f612bf5c78fa13a9f7e0b GIT binary patch literal 49592 zcmV)5K*_&SNk&Gn!2kePMM6+kP&go@!2kddyaAm7DnJ7F06t|Xjzy#*p&7lVU_b^$ zq&llzI^D@#(W`#URL9tDRDS{M<6|F3e?#_f)Fa(H^Z(!VXZ_RE7y9RyU+urVU+(|< zy-#_<|K|O}_iO#r)JOa`q|g5k|NiQK;Xm{L|MwdG*!7|R>+J9TAOBycAE*ca|86dk ze^c@C(T@aw9`+{vZ6$?w8W%`rrBg)Bmvj z+4h_I5Bxv-Kjr_^|M&k%|NrnG`M>(F`9I#*p=iS7l zm*iLXCF>z*_CpIti{>}#TcEkvn&6Ic>fMwzBLMfsj+0XqvlU007sub4#yLX}@x`OusKH!=72aQ!AT(4RG?2E=y zJtYYh5z`@x-n?+5;$(ZS;z1J6Vp{TiH*k0%vMX)z=*WzW%6XnB)+n&g|LXB|1GxIP z+IFp`JCj*hl=1V~CKRvesBtmVMIMeC=1FH1FDh@}T1j#%Wk)l~-5rty{C_qd_OC_S z*picW`#_zp3#Xn`P1?_UD50Es@Brak0dQhxr-ZQfMIif$-A0BoY$#Y_NAmR6UoO&P z8nS&MZ5(4cO{wqf5cgUWflF&O#VklfPJo9k&jDz_aHIYRavRSbMc_$)E8H!I3}}KQ zePLVugGB+tJKy=8PJIqc)s&d4k+@uhecrR~yb;04;GhonxGgRsx4pN>MG-GGQcao+I8JK$>@;Er(ME=@##8A zn_WeQ`zqGGyG5|*iXQ7WXEYM}&q_h|WY27^I!T%QZUOdl)*c^3{ar06$(g)yj&4)i z5TmtyxLs*I+8Qc8uD_Wg=*Fva&>N~fLHddLGjOPeDRD>j3f#cITs`ygK+<)*gtFpq z;A#fL7xW9xQt=NLKQPi~ACwri{5;-^()XAk&OQZhYGw)hx|7q#XS^$0%?g`6Wr4=y z@Xf3&N_av?|L6tQ6V^uKTuTWi*hG-g%vB!sS+CNc${;RMZ*@ zfV?CEC=5re@L$W6A-YY^Bt9;^YYmrZIRVhB*P4vaL#-LsC9ieDNkFpVBXB5YGG(Sp zpHIFo$jvTz`1g#5G(x-VgNasnj?ZE&%qs=1uRJ){bj8`%IXhw0M?Hy)p1CbKrvn=$ zJxf*qsGv_)c}8YAgGhy`5tdH41ifMijAR}D6Qao@&d16)DUS%TCUbI1CmSOQV7VkR z3~DSacd$Z(&iIi_RVMRNryRg%1M`Tfidn}6ivzUhCH=E$Y z9I#1cTq*WKm+FeCI1=KmBPWw3FOAseD+@2S4v+G;`Zw*hn;(1J9ldfZzQig)VKYDh zG;6)~^ zUP+u$mRfQsRb$?TOA{cI(5uUlF9_QvJ+^A1O9N3zd(Pn*KYmBac!u?HA6-Ty8fRD} zwfTsStbljw@}|bjk$@#=&m`9Li7xCchZIJF5!y$jmSKPHHL?Ot-4O>akcP|ta6}V^ zIfeTZrwl)UqW<=kgcID`*`~gpl1!A4%a!ioX131q>)Bo%N z#fteUtH-{$HdOe_vK>Pgq{~v;wd8DS@t#;l#VdP#Ma^ z-1@NyZO@)KyXNe{TzcD^7YG(!oYw)M$ z73vVN()|wg*#zUar6|!_X2qzIjgy&LKnPPS$1>O159Kz~Z*}VK2jqxA%5r3Zy@y5& zH{{or@&Vl_Vu;uJxfA#Lm(W{8&Q^u4S9ru@qzZ|gziU;$UD`3lXE6I(f?C?FMWSbB zFY(>04(o<H zS6TbezTUvV>cw9M-$EP!PAR+W|-k$%| z3Ek&;U~HbHok0`LIG;U5MC#dk)5Q_v(sTuzy3gy7(iP%)ta2bE;jY&oJDj$1l+|?T z!U5A^r|KyUUpu0{0ia$K+igK^J^R?ec!ar6n!p#&PyUMR_u@&xb zT}sL$s8nr&VE95k4Y3lNuvuI=m``x$^!nEMjI031dfi&FNQjUr6LwKSQByO1&)z6In96l`{nO{fY zB{(%_+T{T=1tks0A3O4Q4rpO|>j3Z9jbv@pW2#^bSC$qhiLO3ID63C2QmCw6pc$+| z?1Q5RyXj>lFq!|-U|2?0Az&ty$A8QyZr<9bXsB7}%~a8iX?kaPER(#O4MI9EhNRl1 zUnid*&V}_XD@q%PFM3+&Z2!X07v2aMY5RM$PlBj#_&I_{Mr&>h+s0rT5P89!VqBPu zmJb@${BH~#@!n$EKnE3pjv-UbL~7mi^!uAoC)4zGg;1tjvn4;966;d6eV5cOWn&=b zR?FZ7voul?RMHI1YhsbNKNQx z`d=7a_~KfWq-Ao_7Ju012_#xKfvsZH4tCEZgyz_SJ~@l?7FXwXhvE2M9z!ZT;o6k%kgnnD# z90#@m1^G3u|(af-};~=^*_iiF5eucTH({vLqRYtz{@v5$2F5nzz_k?h9w?{RQGcA7xt15vg{AfLO8CF1Z4 zRN_8~?;6Xjb7kE6y()DX0grd!p2@WI_0KXtzr$4*5+?#^L+>Ns>?K|rz4e0EDH zy=3|jd541{WrO&q+9)i>x11oq#B5~CQ5yD3ovvJMXR;x^{D5l4R;^aQ5q&D(bWVCq zmEsNPGYmMMvEmPDauGOL9hLj~-Ax{$`%ltdx1k6O1N~3v%Wf_spBw$*GM&-gJ~);V zT)rcJx!F3~vCJwm20MSDjnL}4yAGw-s8!KTqrcYFigE^=$pjZ7p3sUr70oxHMaKle z{|zC4Sx)J1Z`S>9*8OkR@v;C5D)Y+oD)Y+oD)Y+oD)ZYtv)eth%JVAo+dZ?}Jg+fG z0RI2R0K%gI{eg)F*MhkXKu86TvdPo(?v6C@ z^&d*Q(fGdKYq)9qrqW9m*Y0h+-Ei9k7biOCVieh^*Z!9MBiQfOEM{a)5 zt&bq;g{}?7)=xB-VkejMmz!gZCUZ~yG?0pW9!d?_+y2*7Q)pZte!QIf8$PGBQ)K6P ztPTPY)ZCrL5Vm*1l&?Fkk>%e>Q>&g;4j>;1gmUm1J=qzFUHuo& zPGN1{oUPj`;Wh{0IsiAJbXI!(^eWJFFsmP9_m)B$z5XjLEe6fZ@d!uyW48yTev!Ab z0Sw2WuzmlNrjZ91QK!V}c>aAtQG)sbay}I0MXRP?=oOBfe?kC?mJRZkhXiYv0e22nY3(wnXL;=}2KJNS;M5TOhTaBV|KA z6~$oY*IMB#vTZgOC`3c*ylB`=C z&!(6GvZO~(P=s|}t2pH2HU_+yjdpl>GK+OA-JkIyJUeblRH+Vhh6RAh##N*eaFFSM z_59suvQ@w5+zv+EfaJ*go^Xb)2NLogfbtH1U6oVNbFC6QuT$wBO>!>Xva~|!ixig^ zUWbw%JUl-nV}m<WBU;t0sHR zK~-BtdHfzJefa@8l}u=lmr(R%o{pKQzVL|-ML?Eq{g@Bp=!gO8ZpiB*7vinG6hM_O z0m3}}vRk|c+H$rWUY_K=$^KDT89%|+#g!UAjjYC5)&-2#42)HS_v+K`w2PS2Rh^Ta z`(;;NPHJ3mfd9xrF$*HIa9}>dHc4)OE1=r{#1dHG$aMukuU3B@0iBXt9Ka@8UU*KV zmuNUP7b=aIUy3m^=g!Be^9C=hO()Kbk=CR6###^6tb6z&&0kLFY0(R<$q&e3VTVwD4tvq+QPWs|?~dGFaxXvU zoIi`2b|k{3`F+NoOdkQio$3}AeacKfh~ng1nD(2<)w%Z#63gD3P|XWz#-qN29rASdf>+_?=iinrQ!ut;-&){UxyiOa1#@G%|g* zVl`ZE#pIhjm@g*OQe}Mw~_Ln$4_uTlNg>zuKg0EP%q3Nf+TkDu^x zcSCq7358Ba768cM?^0gy@1Co4wI*>>UzUHD@=>XhzWpW{tCzMQe(? zv!5&qsaKt05RdR4mSUn&@vOQ}N|VRaXuO!6MKYB~O+7-ag~2rCCdQK7A!trYqcn5w&v zfo+=uM|tw^L@?RvIBz(8Y~tc1)%CY~;FZ5?XV4iB_UE0!X1}d0RS_UuKUeeYD(N(+(pq&!gVN8$vT$V0f+tL1P<`$>QwQc2R25tbEc(a$qaa!PC>e7Pxr2 zKq$h4ptIHK5?O&ZTHKRYr6MjWWlEVib>;gSi9Gn@m zwJQgW`?XPUfNX5U8Ij3|9U2x~bgoeKXkiSK3zRAaw?e?lAK+Zq6nlJ~1(s&ciFBg(B>NJ%LBDgzrt2cohX5R^ zb;^0<{z&v34{wD{!*%-obMM7j)>Jph-#thQQi+Sy+h2q2&vQo>S6yv!MEy$SAt+xC zla!1f=dHydNpeE*-VFFuV?adKo|rxu4fVHt;whIP3_CRf$Bo`DOX?))NHPU>qw&m= z_e4U(JB_NBfWxZ7*jtXZIWBLWl1ILKuw{O+PEoBkc2lD3F z66*k5bhVSEKbkVWcr}V)jHZsFX=dX>>zPD8;2|yMqj>*jzHCnv{Ll9QwM|Vgmaf{q zky9IHFOUX}Pe=_STTl6O_C-Jj&AI44a90PR6R}|UaI_}-GbS024QEOJgigoe8ihtV z{;~8wilS`Nub(Pb}#Vtjh)$QiJRpNtl6M;u89<2)5 zC;y8cV-*`%4!Jc+%feJ&kCiQ9;<8IuOLPnWgQg7H9Dng8n6ELkNaYzVF{w4egl6G7 zN>yb~Z^URBxJ6}EF7ec<7mdPox*>Q65V*RD4G!W8x|{B3{?P!hM!ohJ+Jo}H;{RC?QL%{aV5h5lJHg^f8gqDRW#2V*Wt8tDeh zAq{hAiJy_<&RYH5;`A6mj~{p^WK3Qm#aA z;nB~itfc6s%7j7tp-IVZ3!sXyqNS2AMqQd*EV`LIZGCg#vS=q~ZpU*yqDJ3~Z#}`i zLm;2uZeo&z)xS+Ql0q2<^2{~7$~FV-ul?YSOchJUwb)terxpRJGYEnmX{YY?>`%-n zZ@CaY**6&|)sq%Eiy_Ibcs=x)5{Q;VRZT&eQy9O+U1ci)L5l1b(LYizbQn1wAWA^^ z!;W(l5&v!e-_i~}n3yCtXH^K^FH@ zV4xqEb>AnC`PxT$FQ3JPYL^OU&(7z}+zQYI-zp#5&^-;7-{BMZXR^E*mr92+Q0CUx znEv}CDQ_-^6EQ@_o1S;G%$;(qxX}=b147SaV4T@Hp{q6`dm}ej@nmb6s+rd#{5-M3 z2kB(!xaC097q(l?cJChU3fTl|P$$F2TGZmLA{0Y1Cr>+b(GbqD^QFHMemgD&AulKf zF%OyD$fqi0&@74rOJeH2~uyp`EyT|Zo+iKhu&y5XDC*x!yFLcYMN(vV`oM{ zveJ}PG+<=TuZ^>ff7tT`vnl~yeod*8mD78mud27%Xoz8)dcRYFoW7{o2;X|OlU%pt z$6G;MO)_~531JJ#e#=oN&t6%=dXV@40_0n?)GP`1iD+(3_i^aeX__j(1kAUplQ#3q zr7k<<2plUw|I;6@hO+$noB>W!{T2_~^V@M;waDuAW_BXTyGo>6tbSZsCNpyo&iB@q z_?3BC)j0k2C;LRy@e_OXPHwut)v#5W4f@FF%ia%&6GP^<+O1KC(dNcYQ@>_4ANj{Y z4zZM?bC~%d7cKVeBGe!qmnaVwu&i?t=K5B?5-{E?r^SAx8kq9iJa+Cxv=;i+ zndwo8lF|F6G37k2zm=FA-6IU4@s{NEaI|OuRPS#0C=k7{3a2?f+)n@-VIYK+zt=MwzXG!PDxG`wj{we}l-|}?r zJiKJL0wwGej4RMsJ{8@e4Fn22j2ev=l4*=M$F>=wdXywS$d%h7D- z<$k;7i@rCHZ{JzPY}F5DvdXGhJzi|PKm5tNkZ($x;YarVaCXf>9={@{i1WrC6L+0? z)%nf@Vmtufuj1B)tl^Z2Gv3dO$8Q#xAR!xE#e<7@p>~~M1XMyGkE8AFrJgP8ADPyC z6QWau2?fPqKN%42p-q4wZYr7)p2^ah(3{yUQm6`f2iINd(l_|%tupMS1Bk`?&YZ;C zdMiF#FLCr~QP3Fi2N#lGv#ziAk)Xdm;=wrr@Jb@3|cI&-9KlC6F5 znE(W!GYuxJL@xkmg8Ai63E>5zm1V0%)TWU3H2NzX!sp)pRkCh2B|OR*jO6-K!W8~D zcw*S&(f(O(3%EO8jqTNo_Y$;1A~)W~pZ;MtFvH3=)&7Vj^5OA8SNtzFAoBl%@Q73M z4T5TC4eI9?4v%UE;75=SB5S0!p%7blh9gm*WnbyQ(kVcEyk(?-+h(xw$4rfzib+Q< z63aiy>p#<M#`u#@jcXjG^Dd$Y7EJ`qA2 zW#sl;be%JoM2d*ZUI;x{%YL$JA>%=>yW>FuH%meiauDUHV?3j-p16jf|34x_$yJGk zud`b<$+I_u#!W_F%du9`&<0E8H!BZ&g-C#6gXY?h$UIN{<@F%r$;j%U=_Fhn_!KG* z55*vIDMa4J@5HSXuDi{T3b_Fsvm8a%e-U7YWap3;{i8Z`(1uC$!>K2K#>&^_>^7@W zVhRwU0TkUne3c`_n?Fs8s?V{FnMr*tciC>Kkkma-?bjIfye|Vmf~khEnkgJs4}F$z%`iqqMxS;Ii+>syTB?wvD!f* zG*Nd^8hy*rzp8oBg(L`@*!j0d>^@p%S-elL@J#TRIms`qnt{mWA>`W0sKeoAL^_F9 z*7`Lrj%${Xk(}O~$OK;M58W}bDt&|`f~zWHS%ap)n~jzTvvq`-G;9L%$E88SDn|su zB~Tm3SI4xa_&1ErIbW))IR+wa=PtEEHe}^F9oprSpNlHT1xOGu+gA+ho|D~214yU9 zC{}3Re9lVgxz(rY1W$I;?iRDD9yBqF#7r-i;I3u1xE21MM}h0D=!YMObK#Di#5+SJ zG7TnA6^kxg2Q$Q9ntLt5T4V5=$55&prau3 zuMtS$9A!}PQ~;nkhZKDGBELUZ4@M?#@O(l_k9Wf$tQ1CppUt3DcO?F=A@_{-s|njD zzTN4z3no7IMG)7ahD3NQ>53>D zjo}l+h0K5iD3mzTNIMknRer6?4Jf3rJLL5JihT4U)?0@^dL$|`!=Q}qODX9=1)nsYp6f0Pe)@dzA@P#2~&F05y>@UE`W}>i0#vH1E z0`#3Jn*$%|r|7gp;R}}RTusqDjyr4~? zlC=5JCi<0CU#=DOrYW7vxNA^KMnvO_3$fpU8Sk3&$1o&dUe08^hMli76Rs0Ipsz8e zuF4;y!2K=8Ys`Hhj-e?+#h&l8xeog^bQlnE9%<=);X(JRkDGPe)zN=|KlRun7aiM6U{^A+%@#(O zf7k)FyWrBUTBG4KUY@go*d?;+WX#5iI=@JPfmD%GflD8iJuB8liM}#hH>v%P8WDM( zPv!BLGmD5#11>cqsekJx_n}M&0}9FsC>#;?X1` z_VF8>8s!WX)UmFWb0z~^dPy6(>f%bZvPLoe+LQ55>yE5@%AY;68bPhKY2>|p2sapw zt5yjHhUKJ?e(yzKc55Cs zIsUI%pl0(~IY>-b7tfbXXFurktMOTL8rYPtVQ;wwwNg<&94SAtfIvH;M1F@XC&&JsTZ;O@B4dFc8(N|FWVemw} z(g^Dcrno!Ly$a$k^iydub}haETMMc+^BdZSK1hXe^C^sb6aSVu0OVt_C~MYY8yOzf zXh^NCMwP?S3`woU;8WPW6BLdjMALbvsZ;9J)L~^Q-YLBHav#D90!@JLHwQi~EUk@f zq&Q;s^q_Gv1VFV7xqfC2f^q_9HYlw-*p*ZYSN@ZCe4g%aB>G}Qlq{1NwhNx{AWk7d zn4|}^54Pl=*_U%&)M|>(2*Tn*WpVz6YXcJDk!(I1nZ*0tXdI)Mp60InYCo$WKZ7?0 zR#GI^+^C~mZtO|fi@k(Ua&m+_`*CJup0kK)O zQ200?MujyX)iGm9k(v1MwEqGOk)?jb-0e}rF-G~sRKX-e%nhpj6!+{vby@|Iw^p@k z4Bzo9SMB+Ut!M6_uMP9KdavQ%|k%=2$zuwS5;6le&V4s z;Z|A{?Zg~IAz!dLp@LW-*JCWI8Z3KVsV}Rw!$OS2o4V96e1_yfFnfAPL6;jiq?-g5 z{3Y6rT1j~7kEX*9n~WuoCZ&cQ;fR-otFB#(3gn3xKL$X6Xl$Eu$xfls$pCVi;e_cg z8V7GLPp4ZDSOCaH0DIbd_o_-?U@>?f;6@xzUHRB$Mu}}TxQvA zSuFukK4!*9rm;aPW=77Kb6kdR<@;KB(FSu8Spo+wSi+A64U;6W@j2hTXnU558&$Xs z-zrI>2X;lYq3;~P;65l~2b~y$)4SaHRzq6sohU$-4;|7z6&VygV9*b1A{mHp!s@I1 zGS?ux0a@|o*h}o5VXb^X+hWh^a)p;Kwo?B%i!kw6HPxJMI0OJRBX71$fQ363Tq{8k z?BA7&2k$ZuAs2L$}TZ+xjYr`+PpRx z_Wzz!x%*y$*NU0_ybA!s{cF6V zic&iB<_IwI~2|hhz9}@K7eQfR`G@0g1o*49#Q~2=kg=2jrSN;(QP$-aM^yx2n!%;7gC-@ zpGV8;s2Q;BHu~G2r6m5e-OoOm@@`pd32w6FNRj7JikuvNg+DSpbRc}(eE{j$r!AGF z3M{Uo%yb12k*6L0GQh*sS3tPdgs}-he^5ZcGfDAH3DgsJd@V!i)~#?QLx;*aI1#+n z{Z&TK{_T>`47V8w#2av>ShHGSKpj3&U`sSFITCw`ei60hYXBl~aGZiHh(!76oJ@opB3rx=kk-qm{Z_bl zt_xJj8}$hMgKUo6j36ca=)#O2b1B$;Y#$iP3D>K-o?Le49yitYP7;I&TuYLZb_9_X z0dAj;0V>}eR`Wgs3CTWppg;x;Im&99oi2y=&)Vzt_8;J~(d5)cv-Gi)za zQi&)LavI)FfH3A$(8DhmqYoy`>4ux5>Xm``xPB#0gA(+5rcoLsa>^dNhByqJ1oZ5_ zEu_GfQc_>UXrt7T?!U>pKl;i_Rse}L)6XV){qinkIMkWMV{fyo5ndB?abPu{k3DyK_mU*+pX&S7`iSz={- zLDyEDLRRof_k6U_#UUI)R3vS^LK{FuoLXuAej}wXFK$8jHx6|kxObC4ELSn|my8jwz zLvUR9W15%yrjny5!`4vPP)DdhBxq_m(yaDM1DT>;QE&E8yvu(0ERBx&692*sr#y9M zv~0J@L$dZnO}dHZlP(Qp6#^!CDlhzodMF1tSig^*ti_@r%BRL~GAT)_kbUMek9V^@lCs9YnoSI8uk~xJA$gbI&9^3!i zlusd9>802kxsJ`+$r@BY6!JTHSua<+i=W{@eRV;K)z{1+!JRbdU`_OU+*diTxWJ3mUy%%8B_S%HCqW&=AQZ5^*WciN;cJ7fC8dNVE zaU|&8Mtl=y7#m`5qqTPBAPSsQW@CsBd$9Bl)rBNuG?L)A&BMOzU3%%r9nCzo$j* z0pZQ}x%)*H$1|6il)&0B2pgf|>bm$reNom!s)&krY?DK~0HQ()XhmZ~{@+diHQgm` z9M^*;_0%#L>rb>*8)i>t&d*8&vw|~&bUp8Rg%ZUrrh=5 zKgrZ>-ntZ-+I;#VOHcB;e9I(?X?Ojy`dE|jsh+X@1Rpscj;&|$+w2H#?4mGG2J@liZUN1zr^a3brAys zZk|i$ZT{*-Fv=PG`V7vHsbZY&4>zwlteSc}o~5$IbgP0APz5{7EeT{5vx}Ahs=@lq zD02Ui*&~LszLIe(ug`g~tX-f8FDw4;@_D~+t?4Cr9ltjD0|ksbu8!PA1{XAtzAH;s zv{6gBBHcQt7NwL!u=@;10#{xBM7y9I{!l=4Y{k`2mA&HC11+}S_mtl0$x+pf!!9Im zb#~>%erf{&tAs4+{Xn!H5|u)5BIu$u4o8KKAp+tR#0kVfWu6hMygd|;vDQf=Fk;!f zgS;-?sHq^pKjV(2QoyY$oD4Gzl2D`F^cj@l9`+m3afmx!S)VAqH`ogl;w0hQ+&_i3 z_oTgN?$pqJ(Ii3n1p20<_vzRvp-E8CGMHn6P#1Tup1IdM03<}&Kv;VU`uRbPpF!pk zXoQ3qSHDhS_zTG-9(=J%OX>2JAS3GPasjHzt!g7@`1qq7yl&n56Ta>hGSEYo#6+FZ z7c~TRTq3S^e}99@r@$>)41FavaZ5w56;63rP4yk$6>4y~BPZ)hqE+M~cfk?ikH;i5 zg&ZFSkay8k^S#WfqL$px4;<(FZP{P`4#5TRM;3#ZM@?=;iw$|t)Y_T39XY{znRxn> zW#B)k*mtS1Nj^a}40Jq#1Gl@K{<^IQQZct;27r7Lhh;R;UxoF6KUt6K|wn4WR0g0h9@fTQ(pZcai1Wgu~Z_(?IbqL%`C@F+nU;OJ&-iHaUL zwVKvN0Dt z=%@u`%{*M{ zBTJQH_-4u@Eek=wXJM1(o-;ZwnO1$`3zy;A7VZ7we3!?kcd9gWkE2l_;bo*k8=Xsu zjhW-g7fav*I@|HpmN#Jg{17FTZ`)u@xF`sC3W6lmi#E2=On+S#e;;$|I+S_8?OOIA zPac-MV2CK3AIwhQ#DFIiH40R*YcyCCOCdzETYb_G?%BuiLPWgw0Tlq3md z?7R5#daHu8vLdj$G;7ah`*n6MQTI{)@eB_)!6cU0{{|-? z80(v8!&W4L!IBBt@#Hxn;SD3J+MVl0BAIYfpUD?8ez zY_|&2e-r#1y-`kGJJ0tYl=CU?HABUlA~*?wlQXh~g`aq5p~CB9^$2l()=fQzcO=fG zw;`TuR(T@3XbfT&FRf&JgBI80Bqv;dbM8p4_(i>FM6)k-VuAElUQgXGI{I=`BtnVj z;TXd6jWD$^JsI6`2@zA~+4sF1!%)BdS70#{&Yg+S7lWW&}CXX91Ho*$UO(-Y*z&zv6xCj0|DV*td*& zU&T`8$$rh%h4Vw5ik?vE6Mb4-7h_q3Rl^C0VDa2@W6)poIYA+P-{gALG(qax1)#%> z0|IfBwsGD%>U63S5orLcYET^cUonBS=EAl1l?&%~wp_O-O%Z#MPA5|DDx8Cst;%zV z3Tq>Az4zc#K(f=C{|>zGml5-fOQeZ}!Ej1Wv3 z7`=B71#VHoVCL_2N~`rYTkdk2{NVRJNe3G-d)P0-g|g`*k9KNtCw!H7G*e=11r>KO=;> ztBBUkie>>%iLfEoKX+J%F2CvhK;$V)-+A03x*_)h?QcC??o@dapF(~4wxt7Jp6%-w zn%{`&u`K-Tkv^x~aZ%Y4t4*s>BzxtM)p%}Zki_$n5jS#Y?Cfj*{2gP0ktf*{L9@PlW~1lq{4TA~r*}cS4M? zm*XGpXuBmvPL#6DBqxIdAj?mPOA`#uUKP>}&Eg9^^Oze|(>qFTGGY>>@v~~_ zUN_QLm#BUr%IT@+gcEl7Q-`}AKH9m0_B2i(-0k2MQ|<-$VN5mHnY~y^r6Tt(y+u== zwH*KemtVYr`1ANV%kjo8WIbW2yMQ>}S0D$BIHY)LG%AGkVS+XF{%2A#r`E9Le>N@K z4WoJvM?w;WSn0dh1MDh>VG`^~9y0x#(5j~o*pMMu8Vs3LigItrK^LEnq2(|O-Gvq+ zXwA`X<1O8dae+-d*T^8~{-l~Ja~dw?t3NQcU3G_b<_L{hV z7UJ#vKyfc@y7K{L?LaT4rS*v2gi^wav4Pg7Nk1g&x^BN8!DUyR^8`%CpGYGhR_xf7%Me1l*dTus#%?OCcI)86I>&8Y>|Sn zNLApoG{C_|8fEfrIsGG|&t@uu3tT?_38-s9-;Ho$Mr6ebhtPE#TY@t2-1{uO9hY;u zQxIUXHtCuX(16s@@EKL=%WFM-)_4#KoCYyh_q-$WpT|VNA6V0i`p!w;IBG<*6XB!8 zHew@Io>6sf%F68g^s_zzpGEM48>-(`J9OBv{aAxNgZ_vIRjzcavx2=cFrHO5vnGa5%W)9RE*71Prlkx};l27d8NWEJML3Ep%s$~m~$(5DTWZ3wD`jiklglYe*nXH8)d{}UYR zWNE!{Lf8MkJ}#o6|KmF&wM>wd6qGQP|KsU?7}@C4 zRST`BP1X^!!uLTD*=?kt$4IjJPe$8V-ihK*^P_@FhxF?!9k0!V(SgVTz4RSzs%S<> z@!%r=;#>vY7X{jMy#{3R%EjI=A__A6=VxCL{4QN`0j4ka=5Ax6fFgX=&YX^LlUw-N zQ4#LA7KVN9UQ_y3>*>(OfZ)K_^>~EI7#5kp(PltR3!M3q~heuHLzc~{|m4RQ3SZ^>-3 zZg@CQ7OMU9Y9Vn;F3$+Vn*Wypn1H?cH;T|0nRibp;C;RVPd0OJu%D`fs*Oop_!Y@z zsdlS6NF!wI{q3yNtHQ&83+FFg;yib!zS+-YiN=RNz+*TcHN1xm|6%ISc&l=dd=wv8 zad8~TaCH%0<11)n;v84v(lgLkBo0uA=I#KRnF8%wKZu7bl@{vrUoL5+BslfYmIipA z!HIfo9&{Bsn)8E^)&M6!*uP}7X94dr2u~df5ed!Sw&$fWq`|3MYHSvj8Jt_^E!rj| zG5{r5nKuc7c|#%#8@nw!WNGCAc#4?*Zn!#Dkj&z+%ya!?kF1FW;wK$6cIT>67O~(U zFlg0c?l}Byi;ic8AHL5V^#bpv!fb6njA^o`>=43t_v4Z62xjbuckQ40e=JdfL4F5G z8PY)fvSuYfG2UVBZ<=V!0m;r=R7!-?wCn!!v+2J}`b09i4yne(;fLrK>9qFN+SJk< zn7vPNko2$4e#`7zg}p0K)r7R@QWme5&}d<`tS%I|$MTHYe5^uCg`(d=+9=?HFKXgr zy6oU(zUMG!+(EN+eiG{*l@xSuVc2$XLTC$6InSRQ_*g4^DrY}Oc%2n1f#GMcI&M}c zX-(2)Aovx9^KgdU&P3bj{s8^xG|arC=4re}d1o4X4D|qNM8q(80dEe{aVp=E4qlYfeP+^`RMFuy~}QjL&`UbM0#q z?D`|)o+@JE)A12LXtO+hZNrk4Wc*jHv*v}-yGR)m+UMj!XAFsHyzOCnB!yzdqo~N} zM>xZURJ}eiSrj%CHLe|@Qm7L?cXQ%MMjo0^!uvotjG|NtIFr*&tr~xmls&&-My!XT z(_kH9voK(K8a~6auG1_CtO-4&F?7zqz|1|Pj~%pm=TvaWcy>wU)k0*IDImwc4^@@_ zKZJO7aOKr?#NZ8o`_?y}QxkV6bvwbCGoW1WfC18hd=FD!_g6r07wihl&>;Z3obHhp#j*)m}u{z$@g~9U2z`cT~*iDbMohD#C=_w0bET7a7ZXi&!DGNe2 zeToK#+ne61H)g*nuI$$x`(Xd9&FwW)%!&+AcJB5L$>v+Cs(Bz-iv8Zw*P2gPS?$Wp z9I!MU61LBB#F(j^z4*Iy3^!80X*V>sQr?~P>y@Mv(Ub7jR(OPO+-%_R<&@l8jM4;S zxGUqZfzM;FDJo($Nd>K&@?&UU@pFiWV9oGKk7?XK%+h&FS$}4m`5pnLUxs^!7k;SG zezFhvBiSiKY)QSE=HPVhdRw2D;BFlpN&YIA&?iqhA3i)D)EQ1hEmfVqTgT;49{|v( zOZ(Wuzqx# zf7cBnd%DWPE?7s^EiKXlO#M(V@N1mXgCUL;gDlaJFzX<~Flm*ZoL~6j&T`cs@Lq{l z>lX+;H8{EV(9yB`pWim%+!*L$XdgJ1w9abjTUfJLey24ldB+TU$?)Oz{5~t_Q~q1Y z&6?_z8ECx1rGN#1=Cv8Xi@EW14{g-md_IwDFa&jo9QE^lHmm^ip~U8^8w4MwiBtq_ zgZ}IN)zAyaic$4%;z!vuyG@SS*FaGoHVKVr7GG7V-X}nutAccwx~gOZ6t=zji!kZ{q$mP6 zL4I;8l6yrq%TtAPu1|aB#x1yV4sr6YTkN`|JwY@bJk`DMo?|$oN>-nTGX%;l(OF^$ z-0I1yeuG*Oxv>v-G?%u4t3vU%4l;CE8cv6KvQ|Vnf#mb3^5XqAJxlgD+cYn;3V#^ z3b9CsK8+ca#OCWoFYXj<=5w~aO-?4q>|dAIPH{}}K3?@@_~;{zEWobP+77$>9h)u7~l!|?Ra0)peS2VPDtSL~~&GwfV7<6C-Iv;caF zhmSEb?cI|yl^MF!n8}ZdT;ZPBRp=dvXYPLP{4@NAt6J$o5^-=S(o0-dn|vSR_&y#n zp5k(rSiXI7x)%;HfG}O>cY@c2XmRtj$}oJ;LQeLbuaDatmy$ zFk=NXx-K#Jnd`gK)wc!}7rLVLy@Xvo_@j^BUYn2NZeSt%&7 z=Dw#HzpC5{5*+mkPFyf&*x14G#-?&<8~A4oC%$y4vMHyv^E@@CRuyBFi#FU2wLcSy4#V_6`cj{2+M6e97k!Uq>B ze$7@R24)ZG)j+X*^cg8T5f;qg@%%q*^ly5c8=iTCT28;Zi89YL2MfY${~(-xNb7`{ z$-7C+80}M5?5!B`oKEwy#ERP6b8o71cNwfrz><+3oFI=*{jba|Tj8*iyZx@qDyU_@ z=TkVa`nIs6s)dTS)6QXRv3|IoI5hX3q=O=Ex)2j5-JkQ>G%#>DI)AI!=Zo-1EOV%x zDo)chZ5ud81{HL$)i30O-zm;0?2RUTIh%pQH9X~AcDfKh>2Zk||6(GTpR@t$X0lh7M3aEcfOiuA2T%NZ3B{O8J zj^Nfp6{?9j8bvl%8FRe0n14{gE>IPumtZuTMsuJKb$hK?U+hmPxrlb(EA#f%&1}*( zmSp=SDQ|MJig=fXNU-}YE#(;;)2$LNdkqP}A4K=vv^tVn5<~4;Xa#x%R(7r3r}oY5 zoL+w(r0#`+0jH{U=1yekK6+PHUF?xe9}W9#HRZ$59TWB5jmflijun@&flR&v+c;Sk zpqz33T*aQ_sZXVFLiJbkoUhnQMjw+;NdksF6sqO!nIvFWVh@*dQ-SrPpi!V8NT zvfHnd1F5?{6QZ%H9G95#Piii0XAf>{h$+H~gs9g%64L$&q%xdXhwy(2>pZ^~!B2=W z^d>je+cKMQkbwVgHJZ_*#nS;ZqAmA>n|k$!^*7I{r2L>`U;bZ<0M^9E__#ub*n%C$ zl_|?VsYy1gDy-&r!_3E-0@I z1`&kF2TtY=qD1-9XjSrJrNJRm(#sqjMwRHb$p6~6_0Tvk?PAoX^NL9 zT;nh-MIonHAQ`1Z>7zy5Z4=kTcg7N!1PUZZ9v>Qt{rK)#Ne2|HVi2L>c3-=9McG7~ zrdb9qLq^Tf=4~#MahF(gn3Uk=ldLY?S~`d!*td^HYkfI6KRz7i$?u>*Tb=z?u0692 z?*=?Mr&O9gP4iplYTlDAZ-Wbnrs7AeAd2RJ?rw~oW%QZ7seX9feWD4 zh+jH^4Mj?Z2JYF+m-of4@IBOJ;kaCk9yo-1EVTV)K!ojX$05Fu2*fb_FJ?uAdbzaj zxW`d{ml?Eov|)g(c`d8L0#6Gdz)KhJTuFYu$#{(>G7Z@n{5Yj>NU#G52PxWAb(I16 zM$4J=tXcwEbTX^{Nu6`8I_b396al?XBNCQ=oIkNN)-DkgcPVCmZ(l+f!xn$(PeYF* z7~O6Ql=alqi+1$E*`om)|6q4}C!7~GiGGa;Qbj~yhGCD(6_D!cnPvS&Qp7(ei5<>2 zlRDiUq_!H>tX{!xMR)r@xXatK|7y(i)vL>x#f(3%V68C<;h`)0BpRCovlBxSdE99n z>(2NcS^fP!(Nd6gAp2bql|O(y;2wVO7U(8CGPoSZwnNzyr|^q+pHNnAL)tn@xgH;Y zt*t-}GRB!2DKZYQ&~{;ixsjx=TY$+K!tRNRs)#`sEg zi1|r1B5k_yhv1Nsz(S{Yp2@ou4Q);@F3jhqz@AC4lfNiqfU%@F{d8${+xFT2JgmtK zcz@Ctc>UD&k3-&7(7R?bM<9=b$uq zWtOb!W$&kR7@>`i?FI(|aN7i!!@)q<$>gj$52o?jP6{&azZ0H@$H^87oU2dBrOA}Y zd=UvkeV1j5#wVD$A z>^*TqWlMk?Qzyr^nP%0Ay!HSg3wC-~#C3{Q`px$h6@R~HLjtDaqDhNc!phbe+u4nF zib6XGRs+j*8-ImtiESq~uNj!xzH>aNdZ9eI{b225?%{Sx(OqWl^;F?o+>Y-!N9TXi znX?mGx$~1~p7L(QIN~!5*>$`gRan%+BX$$FKdTPL!X2IGnfV@roD@~Ce{AU_GCl6& z2mi*Bhc(E|oCMiKRvs%6+Gx@8aDOzX{DB?t{LEk8q%H3eV3`FLDSV9;6fz53=5bM{ z@e|K@xbE$)C1)mTvApgx6a70SYlMoZAAxvH(&szWHsa9(YqH;y#KxjhAQr z;J)*+e)}vB00`q}Li*OrGh2&Oz`)Lmpc!eKr5btB9;mzv-OLVBBBhI1g7xnU56cLT z(FMaIsJX5oZEsnqF=fn`rny5~O~FJ6<=0S2AkNkwE_Krowx-%YWcT%f{Y-BXOh2k+`dpf=U9aD<2NRe4I@g}ksA&2= z+5mAkp8Ul|lr57g_~;YfvpR#c-Y1h0cQsn=G-(SsSXStUC*2+xllnh4b;JaL(R`;I zO&;=ttvBqiIUugI{eDZ}RCYEyxceZ|zn(+M;Q^T}Gp>#PV~kAC&W;bGU$Y^i6)AZD zGF`B2lU{RIRg?kvk1ik3i`D-ZvJ>q^rR-v-=J!iy8|{m$sJRv)_`Db{amqXBc&t;J zsYW6zU&5~+HeA79bL`KZ3XMx9{s$Zd0SA?1) z*V*`+d|f7`-W9syRF|>+17sPJi;=TC3h;ba*CY72OZQ##j<+9X9G|Ld)a1M2<%Z z>H$obcWZ(lUFt$!2ebr?QN(v?f1h=QN%$ozqsFF>V%*lxdz<^p&bE$WoxOOEFn7LD zw27v!XkWNT&8xyC>eAc`OqNJ|5F1 z%!eNbbN9l~qz4|oQHMq8XOh~-_#Ia{5w-|8Ao!&36p3xqDi2#gyKHDeaU<~=ber-m zir8Sfdhr)=ezN;>hqP#Rap+9-UTr-5D)Pd*zFW{{x{+S1TZg5F7}tSxV+#D9UPQ^+ zRdLONei=;%lPl$u6I${PH4J|GC=%SdbgW`S`K3fiqNOXt!6QCVDxLLS?qQ(^JI!DQ%Wm zMs`vhY2D43n;KHIUgb$KKfX*XNS+Ub}c6Nx{{Xu$@}s)iF*z&G-_EZS{)i3d&o$yX9#f)4+} zQQkVqbbNQB{uWN)Q51`e@|8lS1;SHv$~nq(17P4)MUT8ks{~iTx0s!54EvMOS!O?3 zC(4r~t3FWSdTw^plsNq2?gdoZIwS)lE}>}Cc{A>Sq#z#Xe+WtX1$Un=O0TNow_X7- zK&Mzhn)~7B$n*n3p)?=Lr4Aw#Q(gjW)^OY%!88t;`hMalqiyV(3{&X4|}|1&d#TG8|N(>I{}bd>7+Y`T04#*2XN zO<9fyclpYg5@`!BOzM2c72Ti^#fEm(nZt4;SNfT7W=BxELcHClF=AJhVBcD?cUvc= zAi>LaBM;lKn|nJ8_^|EoZ1zw$TR5qj<7)08@7kN|t<-WGow2;5vhIRZ2iJ_AR!WaA zp;Z@vLnn+XXa_7eVtzYSc(TgCbKIsF^33LDJo<91!Bf9c^2DvnRf3~ zK541hAI+enOQZJY9Nq=Wm|M%KU=>GP88Zk$#=zWt;XAmoG!!Z>35L7rouwz zusGyX(FA?VTCF!qF(I1ds!q;8eVa2^Bq)CSb}GK&iCynO(`3=6823YBX8p#YBfac{ zFy02c1=O{$wlJ}g&d+K98_SG#I!vdFc>g~$Y@scMhZ&!vMZI0b$?Y0d02?tK-SYSS z8AMf^woKyqx~Bc8y}>qd!Zu@zuPcw(XR?k(EUr7#@Z=usV&8_C_qK5k9?0qpRf|rG zhE1|$cv64W>0pB75S2xcxV{urr;^$^5H z$Y4@4M;vzqI&_;cvX#1`bfa`C2p(14^Z^V)x7Hjv>QQ}q3*8@t*6Cv!jQ3m>51}SU_wueAwzsWhE=&;i^S}P8VhO0 zHK(+WnDxQHv0|oFBG1GWr5kW-VGD-;l%{mpeBY7IEK5iVPZwc1i-OH zXn(&L5R0^WMv^8msF8fdB^1yz8k>wpdCgeur`j|vrLBEA8(vw zN+m<{#9#s2f?muCm_ZG|7eI{w>d839RQ67=00}3n$C4EB+;XWcKkHeYaMP*y#8<~4 zWxVJH*fvpvqjnQv@loiu9A2Z!D9W)aS@w?&kuB9(_#mGj_*c=X@#q=m$gF*JsxE_1 za_9d?{-cPK&A!ineLK#hwxSKN8a;oHs@e8Z@rp#MjnI9->QuCfy{A^dH0B=j@F5me zJC@iq7l-}W7tgit% zuLVvyq5V*cZ7$0wgMUcxy9Wt-d`~v~8Q+tW`V}*mx|It=D-R%#vtmaBI9MtJiax#j|5_I7P0U6j$uf8MW7xVdqb*HK$ZDC6hU#o4g@8qr9 z9jZNliB`+=WIxq^gMU9@uIi)}bact7{Tfa`1{}?Cc5_sD?B!q8Je95pu{?45`nJ3v z^^UsN#SR)u$F|wo85R#%aD)w`{ z3+`A2rmPKLyD79J1H%}hRdq-UkWwju41#8>Itcr}78jxdI2@lJ%yCj{9e;~qhIKa) zGx_a>Zs}rn#{hS$IUq#mXugm|QQ`xkw}Cbu0s)b(55Q8Z43FfDa9yj{#^5PNR6m*Q zPp#XAgk+a&v$(QOGLT|x9ZA~*z3mKA0Ee!*W8VDA9M~R|(CN}XZ>EKT_*E>+5Duye zW_1#z6;;84+{ z6Ja6!r$|oEMnEi^9678IfwD-1`}b{}GnC84%>|YFf$MvNoN6Q9uml4R1+(7u!e6Wa zy$-ZvvNhQBb*NR8a7KD>Sva^&DnNH_GRJ-Iy=LJx?OAfbs&l&x`)Gg`6d>PS8wRhZ zT+E}tWy&&x7oNPfd@(CMsQrCJ7nNhJz__)E$gR#~1=rt_n*=n;XNiQ&d_TnF#fkbI zZbbr7Hj%rmZz?bTQlk>(pWu%+Jh&o^?}u->8{yOQ$ZO1@!6R}LE*(OQF2<@(UA!EU zX;Ww7vBNCU&C_=K`*S3(`Z;STHDvEqU-pCIW?WHAvP6)V$%b~=&*M`!lyQ<3yNnqv z6v06z6J{D=-r3>W)!j}6+sCg8QKy#-p49`oV7J0IBAql_sC@V%?X*L$#HhgNVzQfo(5I!ZHV zw)$bmCHr_)FQ%gUh1u$e-6{cp1NunJ!KQ$8TgW3>oC^A2jsLdV=E!!1==Z#btoJ%p zcz_@44>~a=2Tq-`Zv1s2oIznxM-JmpQ+W)h0s=25s!h)KvIE?Dz_@u>T2=L1LJY~z zo}#H`GA}!c=&1XHA=YjxuKJonWY$sgIlpP)DUL|{2zfw~gnP`kb*%1`?Bj#oUM2~Y zo>HiaWZ={-+g0U^XD6=d=G)e0MrP$oU^_l>a*slpm@bXNiNcURW$hHAz(8BeI)g<( z;zv#S$9x$g6I?a}vuS~OYINYT?@MT$SPcWEfE_L_&? z>-j6}6_YkX#3jR1`630>A$a$Eht6=PSz>)?-m*j&$gPz@%21xNS)r-4cE zkA!gMG&k4mWNRz$`f5q|jvW@z$w}7)vWO~_D^AXB4sVPlv;iR;3`1%{T1qsL-D|Wg z%=>=ulnTh+$65e>^V(I5y3Vx6+TQUlxtRzXv9G1Qa8T^p>EZ#La+8=poctUp&*q%f z4ac08sCpJPlG_a*q_yJTHm+S$xbG7#D6VVhyx{ZeczL`TQ1TNb9%rQGHnZANDp6RJ z$YDCK%{E-RnsLL{C@u2;_AyXw=I}n}>&Es{3$f~xJ8ef7tZZ3*XP(!);%$INB0XOD zDI%6*{7n8SW^VG5Ar}A4i0yagC!GocoV0ZxbY&>avA`f$b$n7)58YG7^^%UQMNo8}uNX+CfZ#0P6nqRfpDt;= z`Et+L-<;YEnUO5-&mFgbp)U6lv66FHD*^@kVq+amn@}%~pST96PWxruu-CU2nAO)O z_!4oDk)H9d0qAbJM&GvxaZlBu$}I!Ygw-ypNA&m5#`&{WO`zXXH=D&`)z}#uw$}eu z1kukKVj;e++<>iss3D9|70#sZ!khfRc@+R6Rfo}Rnk)d%E^rY(|;$t+s}{&8)ma^EG6AxPj?_ z|C{5zqD%)bv0!nYf(p*n%Gq?+)rc5G6IOj1*y5AD1y?OMng{btJdGJa)f1jFh3QUJ zr(%#>K*139PrsV{)eRHd!ZswymRd1q|7TczummWPP}H4QwRk+1*z}+&kvzCIMV3bbJ;@N)GJ>qmsWk z4`!TT@S>boV9n5h>ldLn#vrSYYPYrz%e=^QB>`|7SNA|RP*aR5HAS`aS`$5hR@+~? z{r80IRVO?lR}L1^HEqAeS`C|Np|>i%0?W-pX5L=NSiowA8tsn7T{}CiQJkkYlmpGV zC{Z0V0}{u^a}2X zSi@ypEA=zcA>kfT9O+)-aBIWWhB^|&kBK7h7ss&-Ruvr;rACO_EEP=l@C4MExQ?nW z475qjuS=`1T3P9AGOZ@3QXu+&G!2AxhH|Xx7Yg2ouM$OSFXyCk*Ao!2lZi}am-o~G ziO(UmkK8m&mji-xf`}?Y1&*1=OH_Lb^;|y8$=dD|js8>+oFCqEo{B_UGM6glHTH$! zv96<4AAS-jiN4D`vSTQoqK^VogH4^YfB8xu1c~ekaOr;9LQ!j41BQ_8iu}^%c3v}@ z^dX|iP==U6*1R{zIy4~huPDH>$G2|4x4d-_9EF}CgGoE&Sp+mka&G1JS{b0ffg3Oz znbPhU`t=P^OI;Lm-E3e$HkGpEGazf-EI3m z8Z{7T&o9c0orz&`mC%B){%8!v0H!_LBW$`-hgOTdQWepxv8~r*4oMqvRnrg{gD-5l zw*eF5jcDUb2RIv=wnj+n*p|j47~PPF;&dY$GpyS{4)Yf;aSOFm<#dN7@C_f~rp?(A zTNKjUfFUr45Uc>wGzgG(2*XmKZ`$xku|U&~1Ss~`U`cv;5x75e>cIxxc}dm_76M9z zMj44Qv~_%|q-a0vRCGC{ra9*hIy}1PT98(Hp~sNR=L%kv+hLLtN+Y6NB}V9ShQI>W zi6WX6zWVh**J1|p*LbjA-q68t;#*AmEz>!~+|Tg@WhYWQ%5s_7YE%<*J+CA_DOq^! zUzAOogc*_8?Aih|N^R7lP_K=Lv)oX!?6hPzetI5)f_%qy{*6=jpruF^bC2E56J^R0 zwxe%ftpnz@pIu&0#-u-V@+=CXfqt8Fcl80qrqNzk(9n3dz0R4IzPlxES*7%G5B3k{ zk)Oe@qpuZTp^HrG(u(rdJZMX^A{rnhDW0AZ`>O<8N%bhmDyyYWacoV3x$ewdktQwUw-wr!N&DxsepYOIE5G&M@9h0N06_j8n z-puuU^H+GA#TX!%r%Z~Il8onN@c9V3&$K0WzP2v@^ug!d>%0!}7dY0d+y87`0Z?Sd zB{)W?AdC45xt^|_IhTkHoZrY$2x99)Qph9(tuSuTkNULB0d5O>1V1LeZHnzb@mG6#?>LkF_6sTHG2YJtQs|MPr#`rx?Mub}pC?NzMZ?56L z;pvPh@#pVB)C)~((6<23-CoFXtBmLaR25BqAsrsi*BuBtmFw(LCK}>O#L2~ zeEkg`A2K(=%_>bXsk87>g@~-Ka9*10>Dl=wT)U|L;(wz3%+9uPp)s$7Efd`&#u=*0 zoIH{6+z_;%!(7pLDD6o_UWGd;WBbWQpTaNiH>np&zWR3!Z7G^0W6?BO zXTVNlCN!Y)EtR6u-AA>qL-+a^hFgO$FMr4_ywc*hRiPxqdsyKbA~XUQtA;kX`=UkS zdH+_%9#=x8OzX4ucgX>Cmx~{(|FjU_&RPdX;&D@^SD{z15u-;*!3uw7rTw%SGVhU3 z8tX=mm&IyT=V7lwt#7rm1>OQKI1FZgUnGQ+C@Z4W0-H!_2$1dhD8~3{`f}V?g64bZw|YyEKIJq6i4X3t+e{`jriV7|J0YY^HnQ7qhIua28>n14mV z^>?#6HoZ5lv{v`>3=$ggv55~|u6FP_b%Rm3BJ^N!ikkmI&_Y?c`G}d|I0jWukPcL; zSQYFV9RvC8pK~Lq6%h8rdG-_suN0Kr_k1Yz&r&W5@4{dO!9n=u49-55>e{gLYa3#k z@1YSV4UY>mxg_Kl|E7LyORguwtHxVplu7r;p|=%39Q1~s5JUgTG9@aqD83w=>m;r9 z5^8NC?Prwo@{*C|{t~CTy$ZSw z|Hneqz`35>`Ttq@vMt#dh`H20oBvK1re;H)D@$?I)94(*#_~jOA1di2g~rq-woCkK zb;d@mB)ATnKi}$gf2g}P)^{n^H5?10Sh#kRQplgD%ErfUJsF6>i$8bMXkAoWq2q7DF;e)ro4(_tU>WG7 zU$KCuU8ymIM@i6Fxk$Vq{xCmh#JO=ql|ZIZ`H((S!aMwkq(rSP*y4hs)7iE_HCgCl zw1+?QOmZ!J`r)botTMQ!Aqp9lstM>)nF zeM0XQb6h2Lm)|=Zw)_Etu{szo6~Jt65MTGgp;;LpDi3kQhTt85HGl=@KG)#6eGA=3 zYrn?JOYxKe!5?y}m)YMW^{iqlm8u{sqj5z`NcP@Y2wtH@MCE9G491jYYo~-JU#SXw zGfL=S4wRe}m30QF14{_I=;W2_Vc@N#q)REnm!xp7xSio(tfg-{Y=S)!v@tsqgPZCP zE^}*nzj*z!M-IW##D1QeiH~fWk`o(nD@D(|%eljJo!P?1e=g{PxLSc$B!fGT`v@J3 zuB&>hh%nOJzFehBQ#0U8;~~h~x>7BNH_M z7i`O>rzJlUX8;QT5qm-KZ1q~)c31OVWC=j|w2~&PElmBGOJ0t_Hwxqo7^OBTiKG(K zZPhFJ`~U0EjHCjg20m5cf`vW#6k>o()r>-4+O-BBlPyP2zreq)vC^C1HeNmT%^*2H zq|>WRn&q$}$&HuZk;Z+GAKI&llX1TFipkLmpQL)9XA0hcg=o4I zX{Z-%<3JSmkn_$0`&pfP?ousw)P(L)Awf8Kd{*)AdAKDSbq8{)G*DXQx(o|no_@@A z4Ur?FhJ_ z>dNFUm+o*d0z7d&ov}V@W7k^&H@VZWJQExac}FD{JU_ zm4#u7p5t?r)3GBa(^)gon^z&H53I!BISj^&MLMRM_t)H(1=N@c8PeeZNo6%$dMl-_ ztj2@^FZ|Gv@RzwSAkpLh_47Jd{5M&#M{^-+RgU^eMc4A=U~QcT?S|*aJN9mP9?4%v z5%Go1ifULu!P?j9)1-zKR2OQZB8H2!nz$6s=12ykBBs8@GdWQDM+|=y%A$B}ENIpr zte#5wjX*ma7_aM|WBve9|FBlj7(NRt|AU_oam9tn)=-5`>RuqlWcH^&!^9xrhHX!u zoW1d`|5->Ba5-6w>je`kzf}L-Zd%wLV}A!fB)>}{_$^5#CigBxYWpKlj&X_f9gFNQM)Sna|L>N@;n@} zeKwHaI^|w5#rEg&nZfEcoW5T&8M;w%?k}o*8X+_;Yy(hpKn$!Oh5ywBi*b0ON!ky}G>yqF^;db1+`F{y;;YT-6ujIm34F1<7vh$O=@h^Lhx zp&!RGMVM`&gznHDl61Jre#+(LKyE;XvyO$Y(*ybR7bgs?ZYI}VX9iu6pR#8|EgBGe&2R=9% zee@*a@6`IK5~5>`+aWl|DH4wKU%Ne!+pOwYP~O(ZMdKSF*3*r}bFe=|07Qkh8%bB& z_dK^m0L$AWr3k9_SvS~;3UeQj^X@GjpbJj}1^U~br{*>Fbxy9gjtUyM0}CCMUjk26 zxh^}y3I%}I96oqEubvmo@Kt%-tjy@CSb@dba^B0t9r-u1t=@CYJ-udNgQS#R5xFG#$^j3EBwoH=|}~ z-U5Q%k-mCH)-F+X{OvN$J^bz6Z;4dZ^{Y8Iy2Zwu^~+N9Wv*@|&FefwTAlL^)GjOz zVx!N@JZA#N$T_+)IR#bqt|1@#e(y@OW^1@Vc;9n{4w^66i*gcz93In$>JSPHq5LE; z_R|ne3G0T=uLM^7KKLoQxf2;5hOtk(JF@xc?r*5|fZ2>A<8I8A1GYp}$Afx>a*|OU z_+Ke#D5)GoSi#S`EIDAhlMrG3UHtg4-wh>_Vfb}ePrC6V|XMyQcz9KJ$S442Ms+!aU9#~;OuR)06e_V=g{S=cbee18$Si>IL;F-+<8-Zpl(eQYR(mzb zbic6j9d!eB!6uM34b-qm&W$mI_>#u^ZAJ4~??~Gk6NpZGY`NZ&Lv@}0%WdK3^Ctwm zdfJeQch53E)9bjba8F-tKabslcvFSLqJkzc@xYx0|gG0?&pPO4@x zC6(~Hs@ARPpA4GB64-u0p0*aSSM5yT{As0KBdpl+(j1K(cD(PYa6wgEi;oaFW6wR1 zzp)EV#_uRO;N!N6e!5jaiI)0RaqMEhLu~by&q6M03k$PX_dFbO8NaZR-H+%XZS_4? zaDfV0T~U2=U)pat)JZyts(DDC>nIA$ILW2H`HiY@V`YWV*sw9E)T88h{0sz4cnY*p1z(zHbpXzE>2j|maU1qlZiWqIV_sKZBgqv`nj{aX02n^`FA>+{ zC)Xfy+hLl;^CzY8zB4eOVxaop)ml~P4{Pco8&Anuf*2R(@I@A)85~3S&($%N{4F0> z$xe$5nF#7I52!qth2t>Y{P$ca^SSbcmbVj%93&R18v*dWGXVXV0SAvR)_2N<4Hg&L zk1Ye1E{&-h>lL2ZBzHKKp%C$?hCVixwv5l$UB&y=h+`erzvopc7pF)BirI-SvCaz!!Hj z-CXr^!YuSaHHtlBAxZJ4s(ThMAVFU#j6aGVtyomSY$5k1*;O``h0Sqi7lb+96upWrWRWG+Y6pxv8Qd=JSkC z`;Wea;c>E(9;hz)uf5>PL-i~BSC!%vp&v<2(s@z9SWqBmHg=-*^Sn9p7#f&{Q)x5I z$5@zS_00%dox#y|EA|T(Nz(i;j^j$iq~sO?;KxWidy_&qC$-%^V}4N+sbbLS>=YFO z{jKUX&Op;z^#F|D=5evBHQ{=YVd`FyfSkyA4) zpOuHg@~!4<>pFnP%&UG5i0U5R@sx=zXQ0V9K1{K>u2YGH1<*--d05W7d0&0z$Dw9o ztYGRx(mfs4DZDoH=}bV`%*pl_Tum5FnvI-%;?kCQPRoWr6Kuarh+~sIV{*uH>XB2n zI#>(NHms{U0e?C2A86bU_YN0Tb@P-&)993BU7vSR!da~Nxs;Bz+RwyUf(0PDV746)1j_t2rqgX6a0de=VXe{VLu+C|=#BgwxkIq<8mU1w#~Pkv z_rR@mw$N@%St_!}bNfC_ALpO=j5b&C+vtwn96=MU23COKBx?|!@oR1l9A-9ijw-B` z(Dg1hh5C(cd0OHV>^u57_&&);U!MS0GPb!RvnE!tlPs4mqem2%g5^B6Wro!@GlGCL6&0|Ja*zsr?|zXQyq6 z{Ee^HR`XH%?SOMtzO%R~IzQZU&^Q%pK4NcL`w}SBRHQ~XNlyO!?2<&cA(-^UE}ox) zY*VEnA7n1y4h@pA5|)Asw^OAeSzQ`UnN`wLk64wZ5%$c{JB24e0ne@PbtM?97G%cR z+?0+WPt%qFGNX0^JNmivUqmv&qa)U($2}RbtEF7qwj+K93-W|~!5a7y2uA-$dA~dN z>F`NAkKodeXQrFx(5_|El`%W)x7z+I2b+}n`+V$dW}on~sLUmec$vi`2g4v(r)z!M zp6l>5*@H*x2d|{atb*f~?YY6G555cjVVn%og8FL~&ux9g71c~K{L&zbrW9@3M3>7I zS9BXSX#Fstunh~3Vob+Z^0;F*)T{k~6QP=8G*X_w4@9mal-&w&y5){H)cDyD-;)D} z)*COa*FaP*Xw+3Xr@b6;J3oCxJOJ{gQ%0H=F~W!O+zC5G*F7JCp?P_(WQo6t8fY2| z;R<%Zcu@?GBRP8G1@pL@$-ZOmV-nzCJou8NbniLT3D4RpKumd8tDIlNVY+lXwErvC zM7-$h9J?A5;693_)h|lZ(IsvRl}$R%>-7WE3wCMa!@_GbUYDCa%B)Hg9MzU^AYC!ARF^im z9ziti_w{&6^paWzah9Ldz0T@Sh>pRctAAv*%gGbeqZFT%MUpKRhWh{@nwZ5< z#Bstit4-yUH<|dokOf4tDYi6*Ohwfs)2vX7D28!v>3#JA7litprKq<=p!dI&?sW5+ z>Wg6hVXceWd;L8GUdNTy-dPFFWiW??CUYrvp5;V*&$C|rQ$1#4fwmhcWa-zruC_0& zH|B>Qj&acQ!gHrArn|2jX3`Qbq|O2)T59$+kRA5Lp+T*kv0`|ozPmU#hSQBYF+q5H z&%!%9mlCw=d;{mbW@ZNdQP|kwBM_uVejjXX1q<(YIWHX#2{KrxcqTUWb%H*^7)e_~*!r0n`vmG{L7 zNKFb$%{Q~FL&Qu?|9>am-N2Ib*-dvycpjS9DAbuC+xt2c2*;Fhgb&%_bE@=eT2ORs zr4Xd_)quW)dz0%xivcu(J=n1D^<0S|%L?x#nq^sf@)V(I6-oUv$%!WA#fZc&cbUso zYsZ_pu}dfEp$t@^qr;3HI51sC{s5excrDmNlZpVG=CJsaxgUXkzvc6AQQfOpL@-X7P33tf9&AEi(=$_^_7d!MqABm`nZcz=~U$u%wF zf||MkazW)T$kxT_L3wjr3+$$0Uq@JZvzc7Hg&yWZI}MU@5ez+Nl_feFZH9d(vK!c8n}M^5nlZ`!D4SjJ4oA z9a~O1K$+zngJg96Zd0~8(H}G47Q^9QJHM>&IUHm#xLm_53wF9@L#M71xVCa8l(X^hP()y)QdnxHwwz(JzWo(?BD zGV+g;htgPHaFO|gn-NRqIyYF=t5lEw)9U*V8@_z6KZY_>zx~`B&Z1A6z9JD+FQ)x` zY*`zc!7eyo3kHU&X1&PEmet$eXwJQ+6^Z5P8@^yv!NZ+$Y|o3^bYb0JP{Ik3oI$Ja zD36Lnf@O-!0<;q`Q?+sqEp|5|f1#s8NQwIJ1LjZ6Ybl#;7hbGG+u_X)wk?4!99sc; zh7ilUm%YD&KIN$9de_dRHD#|_yOulHZyx~SQo6{nJ44sNaKB!Cp+?@FJl=O)!}h5l z5*~gx*Jbi?Vez*iwm#mGUoF_r=Wp9-r7=ajuE&-3?Fc#op^(Gu@oC+k&iq^ss+FBL z8s53GvwWUY&jkY4?vaRnOpAKFjx+q<+uFA<65F&@3VhWn>3%x!`DGl)1}9i1&Opfa z_BTS_c0vl^F#tzExWC_l-OWnJLJzc_M+4dokdK7{FmM@q!Hq>fUBbXc>AQouB)5o*4S@M2khsPqdb6%hk$a_*~>eQAdvO?<)fXDE>%ZKs1 z@MWIu8TY3xTSqp#_6kr#yaUi0xLXtjlQVW&65Ohx2)m|0+8+QPJ+kPssXo5&ZkRW03=M8;430gVR%x5>pgL=ehG`N*@)7e;R@)G z`pX3o`-rPQ`oggAZ#YhWunCo))??fv5L+3M;qDm32y|Trj_hL9HF|y!qSc+uh|o{- zP_EQG@UFboYNu{n1K6rzZ}+)L#($%HG5AS%K{jf7ePh~{`FgUe@{c_-e&Ag`bF(4b z7&#G;SYzI6L8hT{F2#$a5=P&7n>K7mhdl*7k!j5HNl~&KS5XDp-+q7uf{r4Z1DASDN!j*ywgrVx2 z#VYVE-bAJ{2dxOpWx41M&4pbe6Fmh>x>O$D@Uz*BTj@K1&MXtpOf7JDhW%R0)LjKU zV%;#z;roG!H+XI4w9aa)A-MDjAra?-iv7^$_1j)Vm3X`@Aqxhf%PU&MK;?pDoBi0riS!TqfvfCEq~ptI|%> zY#1iIoiEyYY>j;_kWQqYSeZI;s51EMK-}YTt+!`BUrEQM&hN+GKExGT4synk-#)RG z_#JRK5p#6_G?#gIs^2P0`oUx3E~`{@=4-!c#2XXPP;oty#;C~s0R`Ysp)EdK8vU_p zAj5y%40o#-VTm9|>keZRJQZB~zN!-Et7L2mv^<$q-RBuP=k|8~e>hAXoW_xzYGW z=1Na6k5oW9pm^~?j${~eF8-DY*XA83T|%9h4!PPWBYX+r?C(bXmLeEL2OcL5*q-Q4 zTeaFZc=|--b8Xe{ii8HYU7NwQwh38&S&Jzy%rxo@g3R={DiCe^RSzgGYhtw&c@2Qb zsF-gpyy)uy^IS*n0A&9-pS{w?0lNgoM`RAD@mIf+#Cw}9j-+2)d+o?(hhT^C(_Kgz zrmhwSj9r|0iZ*LBB`FHpO@4`pB1?UPVzUA0g$a4H2wE9~XIPt=m(#oGwz*N1j$Cic zM(DQh2`JMDrGYE_c`Zoc z6jte#G6u0XNwZHg1w4PRy(>pu;ILx9bCLc!s?$D+*I#kYuy-Ea%fB#w^>*p3G|g+Y z5W_z3r@&I)4;u9xcJ)5ZAtj*+8VC+qV1oTOdjRu4Ca_BqM#be)CFTJOwz zn#bkvs_z^a$#-J+ghn1qN(3au(v-P+S{MCf7I?I-vGd(Tk8`Iqsg`vo?iHgwc^V2UXEh^dy^M@cc(MGa4R)rkO>f>mBQ_{}I{JbZ;CH^VAQtH^hVwYF)s(t3*=33sDQSI@LT*j(8SyNdEuL0sXtz z+^*tS9hi+@g<{`|WxD%e}h^)9c&iA6RYhX)OMY;3q_UtRHM75&*Bqva&Qs=uY|fFSgqF+P;O>1 z@DKCDUfUMKQ|5*&c!$?r&wrp_YF1hRU=uCJ9zzT7fhq*YB+W&E_GD4*Isl3lfB*Xd z!NO8W@Gt0YqeR^fhg@Ad6t^TOOQX&fG}+r`d$ICuQ-ZjM5J~F3|NLo}`2smglh8RP z=$RxyB~2-JMfwc`)a}_ok0WDL8dN@2Kk=D+t9$pVY8e|NSn4p2A}6?znqVjoR;d^S zr#bgot~oGqjw7T!v@^2r0T31T7h9$#JfZpP1q zUHe+?UXIw-2{kCE)*SQ(rX?8=W6r^byC=#N3OIz10Bk*+t4AF2?P-GoESO?tqe&}A z(Uo%vveqW154~ePo`z7xfkzRBa}LFfk=_(_5>`Y{#_iNHqr8&HjF(VUVj02vVT7@ar*FOW=qzY<}u8w=X(Z4 zICD78!5x4{n)?%)H5v{s*+gL>Ffr-l9L=J5;nU11P0u;`5@n+b;oJ&y0!fWO_o2ac zai^LXdn9V?wi0$pxW4l;ek*4_$)NZ`zA?%ZEovnvrilq$da^zdP_|?zNW-58({44t z?ow`4$9|#mV!FOA{5I~Gx_0QA-xK6EhyS|S@>}#8gYu*Y^iuzsbkdC87z5%8I0HU# zhLz>tk7tEZ!uXug4JV)o-z{euo(8Zb@fjbu-su`JwS&|mAWProPo1)2Y?Q)E8}mJ) z;`W{`Rtdzi+Fan{p)6uOzwW8FEwFbfP**QM6Bi(EoJ5a9ig8}E>o`=jY+62&J)k6T z`tjpgsM{xm0jm@nxA7qKY{`y7O1f|9fNa~{+vLWB<;n+{f6y>W8e^t(`GnNBl=Lgz zz#d1Njgy@iKfk%Lf@K`eZFNWcf`!T%7p|GDp%T4&I<}hwZ#}1IVo4`Q_<9v1BQ3+~K&!JWeF$)x9vYkg#rX{Q z?CS=JG_yaJ=rE4}`I$D!_Nin;zZVM8Xl-H{Ip_wU<1C`@Yi$pC1{@aLV{`ERXaKEtH;`^m9VYr-&oAjb;dXZn4HOGOG z!|g905lwdM7=OW8=`U@8fAYNZZ zk#MT}KXJbH5jy?lczO9oY|@-*S_H%eX(|MZiXa8gm;ZzDS4 z2aB;3-`r|+>m3lG8vy2i?ae{Wx?&qpegk6Dn-v8W_2Dl{~$IJo;$uK7SxLf zvY>+Ea1S4knhs-QDQ;iA08G6qJQjRe8}?2d8U4qt_%y>!=Ip{WNg*YycM+7Z=yGG= z#+5m;+^Kh{v646>%YF{hxIOfK^vRY$o^M15=ZH5UZ5t;CqAKVF>6FpaF}~*sK9hAi zj&4!6*OX`58(D5{VSumzIHR)89kXzC{-C(e)(*Da+jyph zGOt82ex1PiwV?^+4&aDEl-GKut=E&|Kn3nk&?;PDRTl7K{=m6R62I(Y*O;14fgj>x z3&Cal;fOt@yW5$$Enn?6t{)=+op|utH~Yb^UoqaXsL#?CvHY}g3*51^mZ*B zm<#)t7LPc-1T;1P$&I}S@9Dk0dSwP8nQD!DWmX((Hs4HsnG5N#vpXvJuR$(sF0l!~ zy(czc%fY~j^TZrZ)MRZMVO9@Q@H~Q-3RwWZ3=2HJ`cL7`&#obPGfTt z;DJB7xUv86Ym5r-6i^!Ie%)IN8Tvjr>p>55hJ&PoC0Ts|@>c(h@_bSZhGga2hRDJ< z{mQvs<}m~{SED63ujBr!-V!xW`W;|OJ?iQDRA?rftRmMmEB5bx9}^GL5{8d87}A<6 zRcsS*W*|y6mJdx^54(Kf){uRrD4;3133!CEhBo7Ni333y5{&x?iYTK%U?lZN;Jz%0}VWpER`q`hcTsbwX6fn z(de>hm3!z~>E}O&yHr^&*-AsjY`ktGSzhW?I-it-t^m^KIqRA)gxg^3M28*TDjKuq zI6B|W>DT2fD%qJCC5@!#6p3b~F;Mf(l;tuY^2PiIjuJApk%w$qsAjEzgB_P(Lh|nh z^e`)-SNa*7#Vj)7FLXSA3&Qx1fI16V)O~(#^Sts3Jb$hmPr49pknb_ zKhDsGSn4;Lz0LkI@I=~@AjQdKA!DunhgI?mX`83G|AuFz4=3C3(U|%9+u2E3jd9C| z(xz>ylcIC!nqGB3_f7$xbp<}9zSRZl7jZ!GHTAy1`FjWTGfp4%Yo;W&@H8u9+Dw=P zEtE4gs>Pj9qEEz14c=O`+1YmKOuM!=8qZdsZ^V|}Ntr=^mvH%Z0QBhZYJbIZ5S6-r&PwcHK=QbC5=7Mz zjvP2*z(bSu@Pop<>0x}7{t4u7W-k{dw&pNW8?bEr(XLisTt{?q<3P5rskzKIOcx|l zFEYU-#CY}HrVde!qhIu^k8I8oQZ>>_TFVSFvRDWje>7xmB}YoBT*ZS%ej#1uzHDF0 zd*k#~I=!t`PvdS5Q;HuFUFN6*#}y<5*goNDl2eOo0$)qXm!AweJqsHpEvaW~BWaxF z{CCGsgIa5mkTS*9Ds@>|0WGHLg$b{SX2E*rzb(IKe4iju|I5I++NYZ_m%Zv=xiY*h4NGLywGc~B2Db9kPy z+_w<4(fO8p5CR!c9%O`8bJOVw6FO2Wlo%=DTolFmaWw2@JAYY?3r|VZ{**Sh8Rb zt?w$Gx|{}GtCpE3CP+?*rJMT&Q@mFV@3^olIju+6rYFYgn-T`eLL zNqhHnsz-@rG$lH3{Eq^Dv=|Rgl5l1`D)Q6ld9FbvVo~$AiOnK=t7*?*sR38e_{1DX z&e98H5mINRo_k$Ru)ZimVhBnkA2<;18XXrEv#pjwR9Ci@tyjf2IV%2+C#`V~#uu&^+h`*%DEy7IaPx~ zZUUl@?DjYOh{PHH17_(a8QbE6H~psshDa~9SzVu{C?+kfnkeb*zdl-1@)BGkqFIw( zJ1}vcDKz0OI}F63j%s9*gpSEz!-}Lbl^;HJ`uf}?KdLd=RgRC1VFqnHIh&%1rQ@EF z;Gg5YHW025@wC>^Yx@+dbv19*TRaLoX*@-6WLo(lpxWQh1rxHWCth^ZDiEjsHN9}z#bheqX z6m1?hykdY!CAn}NCMTChM#kUbUQS_zw?#L7oN!Pu_EN5G3`+31KNa>a_DEg&6@BOn z@+Rg#7=|dGw%}zw&WYqW5nZE7exT<%4#kvJRxZh^)e3&{3J9mIAh@~dy9%(`BG&5S zpr3#N7~`VCIbK%VPsj|HFIzC)$lisVJ0{e>1!YK1iBjysitDcdQoKv-o_zsSLyqKU zuyQP8n^#iS8Ibh>DnQ{V0KYN@0h)Q0&)Uk5$77|8$AMu7ZF0KE)kOLqWQa)n&JCSO zKweCS49qx$xZ8o&*zL_E2$B=}w5s1Ht}jcNdkSA)_pLQxQSwap^)!HNG60ZGfYc-8 zBT^cw2IoS5dSyO8>QToxKn%FePiZA6(vLg=*K zr)5AE0#+amN44KAGsJEi#*^p&cJ(r0`ea(i3=AtX?`5e7BG_XoGa8`-!Qe1ARD^%` zNv{$FJZnv9(OWvJ>0q=O0k}UpWqUy5Lu3zw9^m6{-GgTRbWs$U6xM%`)LAHo3gF7s269z1>u;4lGe7_=ZcV}`zfo4}3uG)iRUA)>CcRSm{<~esgUni{qmrC0sOL5%jCzNTXCh4(%e~etuY@ zqFH!)>gyz!!na?>d2`1%`)-cLK=7aAx1cZ;kA&~q_+mEGq?HeUprjUda@AXYxjn6R zh?5CBv6gnTks_|GA*Kao}-WZy66wQ}8vGkGK?aFF%-D41J z*0hU>$GY-e!>Y7gOg=1T5*qh zno#~QV_{8}!)Y&yj9BKMs(^^tC8#vu;PMtqG*d7`2Sp4cnBAJoG9cM+6CmpYEUX9M zv0I@RX16Px?0$Zkr&Ta`egd;s8MxUvy1dXjWMzhxefFRnr@wln-!tz-!xHYG&cy0z zJr^U`b#IRZFtx$J>fc#-50nItC8e|Nc03@SMq!ylmY4O#CcAesHH6khlS$ zicXGmkR1^wBe9m%u^iEA{ctw~AM+!0La=+KINd&6xT5b{2ilCMgNc&J;wO?)e;klU zx{56g-O%Q5vTz4hC>+0~Zz;|Uu#f@nV5zD4b=}ZFlC=)D96BhL~Axb!!*FtG}q6PWr9q#Xoa!z zrdZNy*PA;)b`{&ymN*B8!Y)pe@+BtgJg$?0TuPa*9fx0qi{p-*aW}cywQYN6cMXj2 z>Y=VHW#q{=y--2rY?~PKPN3fNk*jFQT(VGYB- z?E>r{??mukku3BQy;#T)xzT>-h#A@BS*-sABi6A{pW&Xq=rsKOmXdRS$PdnW*f0m9 ztu1=?i-beT=b{8V?ncTxr5&1js zFg0>NiEhV)-p>BPAJQcpAUBtQM6uC9?AWkd-TJSecALMFM&@1m)k)rAN2EAsGb*`5 zl!bl)0?!5Td4#?X0Hhx}@2cUfRG*ctXkPZW`s3GF_K3F_%SJ^t!|E{Y>m}=9xdN}q zyztyw0SxEry&B;ADBZ9CO+~tZSTJsYZFA6!;&5 z1?~ycbG*9fl;Q!u5g8*uL2_PCyQ}WEQImw~7~bB`BtuC#lsp>>;b27^KBpIS!GNxj z>+z|+iv*;!;?wxdd0*swEcU!X`_82_URU=kAVHUzgN4x>NC>P+BDTnsJs*k*#$6$+4$EsUd9+6s64; zsdBlT6Z4FwIN!FZw|u~l`|3*RiYl&I0x2Y(U$EtwDV{YPpp60l_%x!;e*d1bOqMSp zhs{hDL{*wMG}z?|eN3@?Vp!0pSv!ia7g4cVWgi1{4BjwZ4RSMAP6VputnjF;-}51> zhKXCFK`O3=zxbN&aMHYPL1oDXT30x&3IM&(RtLL=@z9BXAai=Lbc{6D-67I-s$sO~ z0Dr!p1Rv@qiTGx}i;>14c{+RSW*lE{K}L*Bl>NZJyT=Fhe)qKI-qD@~zi#?shdMe= zW2j1DzSKQcO6Qfj%6nh}jHt#n#VbujNN#~@U`^@@L&;gs0uK6)inJUjv&iccGZMjp z&!D)gbEQ-B$obPEn}qM3f-E9JSj*fFr|UwI!_ZC_k=pvWj zvA|1gE}2Tvv`^2>UZwj?o3Nz%%Dxe1V|nL3mnOdXBec#v|A3<2qdmN&kQ8NO3_H> z6^Eh*tQC&A=Yn!IDT=x9I>2_k>mRjleqJrJ`dz!w>mmHK>9prZu zQF~|JjQd&-Fu-n;(q(n>EFQM6sEACtU(6lTC*6j`KS9jslYqqJRdmzrO}1hK?X-Vz zdp`P66P>RP{!bHlCE^(LFTf1x^JPo-PqjpXMk!Pc2db?}W_*97!D{Kk4Vr&SgbW)H zf#4YlGBw9s@icJF9tfptA-ze#yfWEEs1@zzv>@JB=2o2P^P>6Fckf8p_XJmey zDC%U-$d^WCL1i&aW9Vu#CJ-MC5 ze*|zGt=g%qxbEeBM(wSQ!WB3wn5^yigjq;OV)%@ho2Qo?v8-xW(h@{^ZEY;GVc{Q; zUx1yNEX6B-9g06C0DYx~)t0RvK9ZFi)jmC_>cPaG1Fl(Dn`&pBhA+v}Iv_iIm*wjL zcSgxVE1tr*UltZf=&{4XXl?F1Kmxn7fNjUPxaIY&o$yfM!U*yET9jHLvP+!VwuZ14 zJWi8ONK8Y44hhw>ysKz|bX|*4ZPq)OP$m{?F_CM<$mrxez2#S^3DXR)Z5Hdi{(aC| zQffh^wmNlqrNC?8p*cM%V+j`4KLt#^5xTf=_xRs% zS0`TmsQ!Z##)Qly_R2?XCKy#6eb?r7dELEu4#g*YKjfW3*x}_o(m6}_9k*b3r^@Gk z%cL6+TP+&rsj=%%PUj~DachU@Sv~Cy9Ja=asboMI5(fmN-6%TqVe)kfNs1h*EK0UI z464s|cE8|ktQppQ%v#6>xQH0CynFojW~XVJvukz=+? zmU!l2T;iH)k~eBeUfNZ+8<4zE(QvQp8>n_jxaopPMaht2s*3JnX~iuKn)SFX3`f)m z66@p_7PBGQSSBEo^bolQz0--621x(4()NKDgRNqOM$$2mkU{XDS@O{mP%5PEXSg@Nnw|ubsB!p*(osJb ze&~Iap?C&f4YCEKHz$`y?SjifqQ7mJ^8nhxie-}tHA)x5L@;h?{2h0|8D6^3zhr5hlFzerDNX;DX zU*;?4ZC|+MuOZ0%=z(|>xh363Y7G0F#;=W{opl39YXoH3$E=~~c&Yn>Aj;K?q_reo z0@(__0W`a=BCY2Sol&v489%_99aX=4r6I!?7vyd?+SQ{MPA)*z>CZ)Ys^MM?Edc^mQ|AgJCTXv*%d`78=eHHd@{Z zU*c*ETFyZ-Q#vzH^VC~-$3gYDv4}4d*}q!}ke9i|4}%aFnj1wQe`n!O3-qnU0NH?! z=C4)fO>k0&#GNEg$qkh>cF#Q4)VdkYtTnx%i$J&NM;xB#G`@}15u`->5&CMUl5ju$QYg$Q5J+nlmefZu7Hdr{S#mg(gCx!q-m2ERKI1b;71o%T@|n#JIHKLE>Tjmm<)V^m)W)F#92JNlhIbATdta1vC9)}u% z47~-?cv}>Dw*lHw-{Z-FD)C^WnZhcp&&rSuayVv&lP?%EmftV3O%G72jM&YU9)e8H zeY9pfhEhJ!#p7R8t#7dcDZ$>eenC+PU&Z$y51)^ndZRO|@Tfpt|g9uI1mJC76j^;Kvh z?n(N1s#{@Ad4~VjPxL9y+W>Rb&&0cpvjXF!s@2oN{(PYhR1G~F9h3f05)EI!rP7wc z+N(vIHWwW-QHMx?>zdczY|6T_&K7Gc@P}D^m*()S9wuE zHJ7lTKhm+vOm~$?&hjl=Rv)x;9`(+Qs4=;Ok(?39#O*|R=AWe#z{cBtj*p*dKfw!i#(aSTXKt4UOfSR#>;ERh|H zA7wV0;KX2B&1jcHANJ-i*Dp@m&4TB*;Hv}+KZDt8i`-N;y2JPa1=tM=giNYEN4oI) z-+o238T{zuvmEXKs4&%MM+^~4KzMAFd1k{C0FF!21AD)D%X@771dcvOu>__BqRQCE zS~duuj~kV){Jt-}X<0^3#F@alSe=?&lg=l28`%F+AB4J{>@56O5)3v@VOz}KsH)yi z6#CsFtgHT{Dn(quJQub0A(YilPVd5Gf{;WGm{iZ*?-m_sRF~*k_?c~*{otayhd0xz zm)+63rTq6I?fy3UZ*1ItB9VR~P89SPej~g%sm2PxRO5`gY<}k1Rg*N@c;m9YP*|&f zTUD?Q97uX`YQ=v1sF0sgMOve`u!Ku%k(b~nKi00B&Q|W=kMi-CyI(&cf9!Qfxv_Z% z4hkPXz~Omv>~Z+NNk_cM1;Q)m^KYi;s#!Wy6VjG#Bso6OlNGxNPFIbFt~t$8GuR;> zU^$4vii|HXfzp*$EIAVp4P8smK14;(EcF_5yaK&Sh+-V8_b zLylWF8oaK$On*m?Q&KC@M(4fMd@B!0oYea1t3g}@fe0>VxHTdIJzy{uy|Oj=riAai z=;Zfq_Ai_&59nVZHxJ`_Rvt~O9~5Z)d(`)y@Bs+Uc{PGa3r91(?q>$+_yZOTaXy=% z0wVz}5b;p3Rsg2hzsuGR*O6Q(Z--1)lDzjrTUm0pkgYhqnXJZ-uYCQuS|t8PV&?jm z+jTg zEa7A3kM9wEaE4t;Zn| z*K^3N{3nLh5Fs<^ZW7L}mU4}2tyjVZ5gM}LIO~&>e3(U3SI_RXDWaL99&;Y_+i#t7 z;Ro6%91?c($EUZxJ|LB#Rcotf4$=r&p?kNLwe2dYEFV5rf z!8>KyGHqEIF?l2MzuLiG=nGmB^aWL1Xf;1$fbbn#g_a1}i(|_Z6rM0nRN>n*(01grcPfxEJhE*&@Ej55C&Che4_k4I6YZI=SSw^eV>~ugs1kcC}xAb<)gQ?E+&`!|mIH zz+_E2SBZ*M4dUVj7018J-C{!1trZlLW-XGHugBSh^H?pZ~ z+46V@>Y4bX1I|bLT%dOJigz-Ei~H6;!3$z6`MO+MqSM=4{|*xkA9j_x9xsMNJ|^5u zSOw7CsstC6w1qbpl8>1y-5EiIxU@QB6Fl;_67S;*`>pfNILO~|^#1zqeLz;r6|+|? zcWYIlrHdONLP*70ii2~*A3N()25-oR(GD8Mp@AB^?Wi4cfLm-$E#4tqiG3}SI#T{f zn-06^g-fdsWJ@=fw`H<1unz=Q-SmsLi5)<1P6GH=DR#nB4B4`Wlk?7a^tYM`q2@IpHwTrq(! z{`A?tx94B7)YcAZl?!IC_XjVFsw(L+~ib{;y=~lKs58XOiMeC|XN@ zJ{=U&Au6aJnyh)&PH-bC$*B@dSR(NE3M~X_OYVEeBvb$*sRgaQTmE9FHk(l^p{$OB zQa7xP%HUAkcZ>!}Zi=QT1_Na;0%(WmptH$uc97Ur{`n3s+DawZJpn!3|L$%Spcg{( z4vw?rHM2BKQTIXGqa^%NMuGjO4;(EsJ4UivNI%-Er#?!Pgl|7d)$qVvJ;h3duieFI zpVK1{st}R=)3&HCkLBa-4F0XuHJu>9wNFXl?s(l5spXiv<{Y9fPhST@o?*5ILK)C7 z{?E|I5lJE#0C7;f2i|?+eVsKILv6bj*Sfl2R_>Ofzpr^e4f=JdIMux@3*KvD+p(R+ zL#@cRp>~m|%ON~8N0Fw)NHV8h_RM8G3kSb;0VeKocj2y|?8vx#U z!sR`KdG0Hjv#6`no{2nrv(?EVDE|6tb04AXfT|O9ZXX$;C^dl*FfeygB4(2PlB z{A;+nAvg_m{!j5aTn-0k`^K@N4GZR=nPV3{U`FwYKL6Oyhv3^NO^qSgM()ZXTF^KZG;RX*ETiWX{uI>D%PhgXqtn&_>GL8PlSTtPywg#+c-w3-$vh=5m=&cesp% znlw!urc~#pxLNO#*DMEvLy8Gls5CE!9!1 zeQ1b}I=YPe0X^~t!0cNm98Br&I!EP=JGlWBF`jkvtiZiO4?9miuq7$7OK#0Rq*&$+ zi|hZd9b3b!UB)o%vpqW+4P(t2dsK-;4cjl~*kID7?<|1GW(Lw?lGd<-vl)wJ11-A` z`ebPE%^33LT!qCaYg!*{2sKf+yN_Xvum0+nuAICp%cfGXY5~wiaYhFI_oL)@BL|l1kj^o!hcPFZ9y(=aK zo1B9D?+L{UZv{1Rn4eaCZr@kptOX!jE~|n^0MG;eMzPM)(hJ3qOg^Kf4`0B6pBU%9 zl8NIKA%(LHOP>)<*6EBD#0rhs%X?=Q@QtqJZef&z#JvfC{=YVgOzv8lcIQ1-Q3S?7 zXc6L)lZidZAYdm5S?TO2vBDs&pzY4j4o~w=fuc^*hUfuWsKi4r-+kYxQ}k4TsqbC* zFUN_SxT$b)2+v} z^4aiZsS?e5pvfj}s#tZ;GhJ)KB^;jNybk@4YE=uKvL*0TusFS1B@M5#wDv&_+q8vV zsP)9)r1y{L7)_R}&Z=LQjQlcPVqwA0=sMWqUym=_^ArZ4tFrieC!&mok9Vxx)OsZN z!iSm*H*x%ZH*&=}Gp}jk#858!2k!gujIKc&OjZ2#7(jq()F)ylA+!4@J!s9pjCgTT zLRi+wAHcAjO+B)@qV%mX-XEB~+bUdWtkTwzE}6o)(#)tPR4Fze;F%7N*!gprmtM%G zL;lWJj0J}|r3PhanAzvZq`BZ7b{UAz3?0fZ!l)f7bbwcTeqdX!E@M@OC01B7_H0mX zE}3K58=q)=l#(bCeNOa~lc$A|#8ccSjCkOL{2X%J+yhGZjEG;$bn~cvkzY9R@80f* zB5jzdP zzjABOFSlhmX`(N*VZ8i0QWM{;)Vx3xS4u=w=hSf%kt4-wV3#T!?@!k ztLI}w8}Re{u7;4v76qKu=C%JN8zEX2hQseJp~e4&;3ZIRR=9nmiL1}IuGVu$rAzHt z5_bTgCAQOo(p(G_B*rTXxAg(f3Nd1!Ds8MDD6DSxpjp-t=v>&LdW9z)+%W*8yKq%R zTd(51%b~tGE!iZ?(==!;R5~0OeQ9p+Ev;RXWbBu2I#X`B<{EFJa|IjRP8(u?v?_9~ z<1YmY->am`XAI)Q0r4VpsqlEkbx_3Rer5n&PMlK8OhU&qg;GI)G4A1UlJsUonKk17J9PDQZ+ z3Czfw#aX{^y|9&!iRhAwm)|=Dtj$j1!t-bgu0X9pY2jUOYHGiK8Q=W6;_eb2swd`o zS9tio!61g?V^=)>AIlhgmx2Ah^c1Y%8)=LJaT&`-nATr~Z#{cn$ewJHSY3W4>T%UU z6abs~oR&7T7)kmq+gT&iyZFz~*8$KBqgS7Hr3-noAp<8vq+)!Jl&6aNk4v2^BCSiv zs%_l#$+=Z-($Uq@0=GA*rh<+sXSiLI-}*S0e6X;kwHObtYi7;?6&xChR@PX3=rl>; zIbje{>vn=b?+OUj+bwUuOa6AQN+t3_`;|&f!dFWEP(Q2;BsjvU595avcflqz3j!F? z&*rfSw3@UivYN;zVL{Cn97O0Frf&G=T9s``cN~kgaC-p>XgfzTuY^ulIl;hBkn;ao zLDK>sz=T__hQ9>qe(O-9lY#}upcWh7iT6gq1iqP^@RWpFc$I(*1ScvN4bD7*S2yYe zypq>HqGfubX=SrVe^dhA8BB(qw>=-~@JH?AW}FFb5>{8CKDoR?A4XK-S?2U<7J5RD9EN`q1RY zgIHBme|U6HPY}d3@>Fu-?^{?oyN*necEyf`9pd@BD+^q>qUY4DHDM`dU5;1oprZF@ zrg#gae9hV$WDu4uX=fK#LHIcIEReDE&&4W*Ff7=ucBc+3h)t)c4Aw)MWW&oRaEPo% zam^9{d7jCl!pLvZIXwg3@H1E=M{;CebVkM@m2-FR?L}j3++eLEZrY2(!RNp+-F7QA zR+NzH^bV-uGp*aDU`*f-DF%qO3CTGc_|Lfq=PT^EG}kRZjke?es5d?!Jp4l0>Qw=z zXfpn`f2Ch;$<(sM(AGYV+$t1nuLy;ew&DG=?~y~dRN7C}9@lh1YY;+v#+#I+nd_Qq zE1x-1&E?|d8m?tuoi#{+wxl7AR49xUUA8NWcl-a1;xkh(_~7c};An#eIv@AmK3q#= z*w>O35cO^qJt`=U7bqhrB>EVlr&76tV3+&}p6yt9K>wCS`lx&6l{-K4p>ce1iz+wU zGz*9pJ=h1w-wzM4aRkYoibc?ZiETJBO}+lOpg_9^vD5ed{s;Us;b@DKr&bj2Pni(# zD1!AeT$?%-Vaz0-nW!}WBmg4rEAwXHZQ(4xcG8l|ziwp3!Hbmq%vXFoBtjjR(-C-b z%z34w+)kGfPt}njQXH#DZxC^n^5(mn$psyBqnYdvc!Y{q_QgxAlCVy3+u#PcpDYRZ zg9~vVK!Z@Fiwo#M`TX4dv~tmEEFCFGI1NeP*K717%}O)%)PTZ1tk!a19%esRaw3(6 ziSKuO7Aj{q7u6PKOB_>e<;rdSu$kjCQCyy4BNu%?2kQS4HH)E8WKeD^5;MXbN_1;d z#(5+Gdr@mwPqGLQk8d$yyPAmg1DK4ZQPFe)r%U<> z*BlFUyBvR7dL0R%5tyH?s%8qtC)^#6Af&Y^+V+#E5CA&3Am8@5k_+Ki6^2p<0q)=dYe*WL6*Ur&O5CmErba&EoyG@jDXq=bmcg zCBdV*z@UkosJY2{tVLFc=E++(_l|PSl$6m@AXT`mG*(@6<@*~FG?)K!e=>4@=)hOs z4UuMj>t~I)y2<-J%x&o};!Qb83xj~((>sTI) zCzXMh1KSR88bvB!^w0ofDml^!BMCVS_L>TR)s7kpUC|>;7MO_+jpwwsYX{ z0`Ir97p08MU3E6{;2;D$Xhn(53pGVAp%#&NdG#H{A~<)4bmnn0Ju=%xUoc!G*)6$j6Snbsea7M{Fonz8%u z3v+7RQh!Ucx5V6%>ibXZZ JB loadTo= + eraseFlash= verifyFlash= + +Where: + +- ```` is the path to the Zephyr application ELF in the output + directory +- ``loadTo=flash`` loads the application to the SoC internal program flash + (:kconfig:option:`CONFIG_XIP` must be set), and ``loadTo=sram`` load the + application to SRAM. The default is ``flash``. +- ``eraseFlash=yes`` erases the whole content of SoC internal flash before the + application is downloaded to either Flash or SRAM. This routine takes time to + execute. The default is ``no``. +- ``verifyFlash=yes`` verify the SoC internal flash content after programming + (use together with ``loadTo=flash``). The default is ``no``. + +For example, to erase and verify flash content: + +.. code-block:: console + + west flash -r trace32 --startup-args elfFile=build/zephyr/zephyr.elf loadTo=flash eraseFlash=yes verifyFlash=yes + +Debugging +========= + +Run the ``west debug`` command to start a GDB session using SEGGER J-Link. +Alternatively, run ``west debug -r trace32`` to launch the Lauterbach TRACE32 +software debugging interface. + +References +********** + +.. target-notes:: + +.. _NXP UCANS32K1SIC: + https://www.nxp.com/design/development-boards/analog-toolbox/can-sic-evaluation-board:UCANS32K1SIC + +.. _NXP S32K146: + https://www.nxp.com/products/processors-and-microcontrollers/s32-automotive-platform/s32k-auto-general-purpose-mcus/s32k1-microcontrollers-for-automotive-general-purpose:S32K1 + +.. _Lauterbach TRACE32: + https://www.lauterbach.com + +.. _SEGGER J-Link: + https://wiki.segger.com/S32Kxxx diff --git a/boards/arm/ucans32k1sic/support/debug.cmm b/boards/arm/ucans32k1sic/support/debug.cmm new file mode 100644 index 00000000000..d2c30dc5661 --- /dev/null +++ b/boards/arm/ucans32k1sic/support/debug.cmm @@ -0,0 +1,13 @@ +;******************************************************************************* +; Copyright 2023 NXP * +; SPDX-License-Identifier: Apache-2.0 * +; * +; Lauterbach TRACE32 start-up script for debugging ucans32k1sic * +; * +;******************************************************************************* + +ENTRY %LINE &args + +DO ~~~~/startup.cmm command=debug &args + +ENDDO diff --git a/boards/arm/ucans32k1sic/support/flash.cmm b/boards/arm/ucans32k1sic/support/flash.cmm new file mode 100644 index 00000000000..941d2c03954 --- /dev/null +++ b/boards/arm/ucans32k1sic/support/flash.cmm @@ -0,0 +1,13 @@ +;******************************************************************************* +; Copyright 2023 NXP * +; SPDX-License-Identifier: Apache-2.0 * +; * +; Lauterbach TRACE32 start-up script for flashing ucans32k1sic * +; * +;******************************************************************************* + +ENTRY %LINE &args + +DO ~~~~/startup.cmm command=flash &args + +ENDDO diff --git a/boards/arm/ucans32k1sic/support/startup.cmm b/boards/arm/ucans32k1sic/support/startup.cmm new file mode 100644 index 00000000000..db901876f1d --- /dev/null +++ b/boards/arm/ucans32k1sic/support/startup.cmm @@ -0,0 +1,128 @@ +;******************************************************************************* +; Copyright 2023 NXP * +; SPDX-License-Identifier: Apache-2.0 * +; * +; Lauterbach Trace32 start-up script for S32K146 / Cortex-M4F * +; * +; Parameters: * +; - command operation to execute * +; valid values: flash, debug * +; - elfFile filepath of ELF to load * +; - loadTo if "flash", the application will be downloaded to SoC * +; program flash by a flash programming routine; if "sram" it * +; will be downloaded to SoC SRAM. * +; valid values: flash, sram * +; default: flash * +; - eraseFlash if set to "yes", the whole content in Flash device will be * +; erased before the application is downloaded to either Flash * +; or SRAM. This routine takes time to execute * +; default: "no" * +; - verifyFlash if set to "yes", verify after program application to Flash * +; default: "no" * +;******************************************************************************* + +ENTRY %LINE &args + +&command=STRing.SCANAndExtract("&args","command=","") +&elfFile=STRing.SCANAndExtract("&args","elfFile=","") +&loadTo=STRing.SCANAndExtract("&args","loadTo=","flash") +&eraseFlash=STRing.SCANAndExtract("&args","eraseFlash=","no") +&verifyFlash=STRing.SCANAndExtract("&args","verifyFlash=","no") + +IF ("&elfFile"=="") +( + AREA.view + PRINT %ERROR "Missing ELF file path" + PLIST + STOP + ENDDO +) + +; Initialize debugger +RESet +SYStem.RESet +SYStem.CPU S32K146 +SYStem.CONFIG.DEBUGPORTTYPE SWD +SYStem.Option DUALPORT ON +SYStem.MemAccess DAP +SYStem.JtagClock CTCK 10MHz +Trace.DISable +SYStem.Up + +GOSUB DisableBootrom + +; Only declares flash, does not execute flash programming +DO ~~/demo/arm/flash/s32k.cmm PREPAREONLY + +IF ("&eraseFlash"=="yes") +( + FLASH.Erase ALL +) + +IF ("&loadTo"=="flash") +( + ; Switch target flash to reprogramming state, erase virtual flash programming memory, + ; all target non-empty flash sectors are marked as pending, to be reprogrammed. + FLASH.ReProgram ALL /Erase + + ; Write contents of the file to virtual Flash programming memory + Data.LOAD.Elf &elfFile + + ; Program only changed sectors to target flash and erase obsolete code + FLASH.ReProgram off + + IF ("&verifyFlash"=="yes") + ( + Data.LOAD.Elf &elfFile /DIFF + + IF FOUND() + ( + AREA.view + PRINT %ERROR "Failed to download the code to flash" + Data.LOAD.Elf &elfFile /ComPare + ENDDO + ) + ) + + ; Reset the processor again + SYStem.Up + GOSUB DisableBootrom +) +ELSE +( + ; Load program to SRAM + Data.LOAD.Elf &elfFile +) + +IF ("&command"=="flash") +( + ; Execute the application and quit + Go + QUIT +) +ELSE IF ("&command"=="debug") +( + ; Setup minimal debug environment + WinCLEAR + SETUP.Var.%SpotLight + WinPOS 0. 0. 120. 30. + List.auto + WinPOS 125. 0. 80. 10. + Frame.view + WinPOS 125. 18. + Register.view /SpotLight +) +ELSE +( + AREA.view + PRINT %ERROR "Invalid command: &command" +) + +ENDDO + +DisableBootrom: +( + Data.Set SD:0x4007F010 %LE %Long 0x6 + Data.Set SD:0x4007F014 %LE %Long 0x0 + RETURN +) diff --git a/boards/arm/ucans32k1sic/ucans32k1sic-pinctrl.dtsi b/boards/arm/ucans32k1sic/ucans32k1sic-pinctrl.dtsi new file mode 100644 index 00000000000..9f5eadadf36 --- /dev/null +++ b/boards/arm/ucans32k1sic/ucans32k1sic-pinctrl.dtsi @@ -0,0 +1,23 @@ +/* + * Copyright 2023 NXP + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include + +&pinctrl { + lpuart0_default: lpuart0_default { + group0 { + pinmux = , ; + drive-strength = "low"; + }; + }; + + lpuart1_default: lpuart1_default { + group0 { + pinmux = , ; + drive-strength = "low"; + }; + }; +}; diff --git a/boards/arm/ucans32k1sic/ucans32k1sic.dts b/boards/arm/ucans32k1sic/ucans32k1sic.dts new file mode 100644 index 00000000000..fc304249546 --- /dev/null +++ b/boards/arm/ucans32k1sic/ucans32k1sic.dts @@ -0,0 +1,91 @@ +/* + * Copyright 2023 NXP + * + * SPDX-License-Identifier: Apache-2.0 + */ + +/dts-v1/; +#include +#include +#include +#include "ucans32k1sic-pinctrl.dtsi" + +/ { + model = "NXP UCANS32K1SIC"; + compatible = "nxp,ucans32k1sic"; + + chosen { + zephyr,sram = &sram_l; + zephyr,flash = &flash0; + zephyr,console = &lpuart1; + zephyr,shell-uart = &lpuart1; + zephyr,uart-pipe = &lpuart1; + }; + + aliases { + led0 = &led1_red; + led1 = &led1_green; + led2 = &led1_blue; + sw0 = &button_3; + }; + + leds { + compatible = "gpio-leds"; + + led1_red: led_0 { + gpios = <&gpiod 15 GPIO_ACTIVE_LOW>; + label = "LED1_RGB_RED"; + }; + led1_green: led_1 { + gpios = <&gpiod 16 GPIO_ACTIVE_LOW>; + label = "LED1_RGB_GREEN"; + }; + led1_blue: led_2 { + gpios = <&gpiod 0 GPIO_ACTIVE_LOW>; + label = "LED1_RGB_BLUE"; + }; + }; + + gpio_keys { + compatible = "gpio-keys"; + + button_3: button_0 { + label = "SW3"; + gpios = <&gpioc 14 GPIO_ACTIVE_LOW>; + zephyr,code = ; + }; + }; +}; + +&gpioa { + status = "okay"; +}; + +&gpiob { + status = "okay"; +}; + +&gpioc { + status = "okay"; +}; + +&gpiod { + status = "okay"; +}; + +&gpioe { + status = "okay"; +}; + +&lpuart0 { + pinctrl-0 = <&lpuart0_default>; + pinctrl-names = "default"; + current-speed = <115200>; +}; + +&lpuart1 { + pinctrl-0 = <&lpuart1_default>; + pinctrl-names = "default"; + current-speed = <115200>; + status = "okay"; +}; diff --git a/boards/arm/ucans32k1sic/ucans32k1sic.yaml b/boards/arm/ucans32k1sic/ucans32k1sic.yaml new file mode 100644 index 00000000000..03054d7ed9d --- /dev/null +++ b/boards/arm/ucans32k1sic/ucans32k1sic.yaml @@ -0,0 +1,17 @@ +# Copyright 2023 NXP +# SPDX-License-Identifier: Apache-2.0 + +identifier: ucans32k1sic +name: NXP UCANS32K1SIC +vendor: nxp +type: mcu +arch: arm +ram: 124 +flash: 1024 +toolchain: + - zephyr +supported: + - mpu + - gpio + - uart + - pinctrl diff --git a/boards/arm/ucans32k1sic/ucans32k1sic_defconfig b/boards/arm/ucans32k1sic/ucans32k1sic_defconfig new file mode 100644 index 00000000000..8580c7155cb --- /dev/null +++ b/boards/arm/ucans32k1sic/ucans32k1sic_defconfig @@ -0,0 +1,20 @@ +# Copyright 2023 NXP +# SPDX-License-Identifier: Apache-2.0 + +CONFIG_BOARD_UCANS32K1SIC=y +CONFIG_SOC_SERIES_S32K1XX=y +CONFIG_SOC_S32K146=y +CONFIG_BUILD_OUTPUT_HEX=y + +# Use Systick as system clock +CONFIG_SYS_CLOCK_HW_CYCLES_PER_SEC=80000000 + +# Run from internal program flash +CONFIG_XIP=y + +# Enable MPU +CONFIG_ARM_MPU=y + +CONFIG_PINCTRL=y +CONFIG_SERIAL=y +CONFIG_CONSOLE=y From de93777d14ca80c7515fbfb42b17834aac83dbf6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Manuel=20Arg=C3=BCelles?= Date: Sat, 18 Nov 2023 15:57:57 +0700 Subject: [PATCH 0529/3723] tests: drivers: gpio: enable tests for ucans32k1sic MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Add DT overlays for running GPIO tests on ucans32k1sic board. Signed-off-by: Manuel Argüelles --- .../boards/ucans32k1sic.overlay | 13 +++++++ .../gpio_hogs/boards/ucans32k1sic.overlay | 35 +++++++++++++++++++ 2 files changed, 48 insertions(+) create mode 100644 tests/drivers/gpio/gpio_basic_api/boards/ucans32k1sic.overlay create mode 100644 tests/drivers/gpio/gpio_hogs/boards/ucans32k1sic.overlay diff --git a/tests/drivers/gpio/gpio_basic_api/boards/ucans32k1sic.overlay b/tests/drivers/gpio/gpio_basic_api/boards/ucans32k1sic.overlay new file mode 100644 index 00000000000..4b6ec98718b --- /dev/null +++ b/tests/drivers/gpio/gpio_basic_api/boards/ucans32k1sic.overlay @@ -0,0 +1,13 @@ +/* + * Copyright 2023 NXP + * + * SPDX-License-Identifier: Apache-2.0 + */ + +/ { + resources { + compatible = "test-gpio-basic-api"; + out-gpios = <&gpioa 0 0>; /* P12.1 (silk PWM1) */ + in-gpios = <&gpioa 1 0>; /* P14.1 (silk PWM2) */ + }; +}; diff --git a/tests/drivers/gpio/gpio_hogs/boards/ucans32k1sic.overlay b/tests/drivers/gpio/gpio_hogs/boards/ucans32k1sic.overlay new file mode 100644 index 00000000000..7b4324fb920 --- /dev/null +++ b/tests/drivers/gpio/gpio_hogs/boards/ucans32k1sic.overlay @@ -0,0 +1,35 @@ +/* + * Copyright 2023 NXP + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include + +/ { + zephyr,user { + output-high-gpios = <&gpioa 3 GPIO_ACTIVE_LOW>; + output-low-gpios = <&gpioa 2 GPIO_ACTIVE_HIGH>; + input-gpios = <&gpioa 1 GPIO_ACTIVE_HIGH>; + }; +}; + +&gpioa { + hog1 { + gpio-hog; + gpios = <3 GPIO_ACTIVE_LOW>; + output-high; + }; + + hog2 { + gpio-hog; + gpios = <1 GPIO_ACTIVE_HIGH>; + input; + }; + + hog3 { + gpio-hog; + gpios = <2 GPIO_ACTIVE_HIGH>; + output-low; + }; +}; From e11a71dea0c8c3691f52a6c6cfb067f2cfd7211b Mon Sep 17 00:00:00 2001 From: Anas Nashif Date: Tue, 28 Nov 2023 08:33:14 -0500 Subject: [PATCH 0530/3723] tests: posix: remove unrelated tags Remove unrelated tags: net, socket. Signed-off-by: Anas Nashif --- tests/posix/headers/testcase.yaml | 2 -- 1 file changed, 2 deletions(-) diff --git a/tests/posix/headers/testcase.yaml b/tests/posix/headers/testcase.yaml index 1f36d130bc5..1a91d193001 100644 --- a/tests/posix/headers/testcase.yaml +++ b/tests/posix/headers/testcase.yaml @@ -2,8 +2,6 @@ common: filter: not (CONFIG_NATIVE_BUILD and CONFIG_EXTERNAL_LIBC) tags: - posix - - net - - socket min_ram: 32 tests: portability.posix.headers.with_posix_api: From 589d36adcf5caa6c3d05bec0257577844c247072 Mon Sep 17 00:00:00 2001 From: Anas Nashif Date: Tue, 28 Nov 2023 08:36:17 -0500 Subject: [PATCH 0531/3723] tests: crc: remove unrelated tag Remove net tag from tests. Signed-off-by: Anas Nashif --- tests/unit/crc/testcase.yaml | 1 - 1 file changed, 1 deletion(-) diff --git a/tests/unit/crc/testcase.yaml b/tests/unit/crc/testcase.yaml index 1aacb193f4c..747bbc63fcb 100644 --- a/tests/unit/crc/testcase.yaml +++ b/tests/unit/crc/testcase.yaml @@ -1,6 +1,5 @@ tests: utilities.crc: tags: - - net - crc type: unit From 5dc561f1b49b4656ed0565cf0d8b43b4401ef879 Mon Sep 17 00:00:00 2001 From: Christopher Friedt Date: Tue, 28 Nov 2023 09:35:46 -0500 Subject: [PATCH 0532/3723] posix: key: remove unnecessary else / indent Remove the unnecessary else clause and indentation in pthread_setspecific(). Signed-off-by: Christopher Friedt --- lib/posix/key.c | 19 ++++++++----------- 1 file changed, 8 insertions(+), 11 deletions(-) diff --git a/lib/posix/key.c b/lib/posix/key.c index 1a3f2b92a13..698088e340a 100644 --- a/lib/posix/key.c +++ b/lib/posix/key.c @@ -204,20 +204,17 @@ int pthread_setspecific(pthread_key_t key, const void *value) if (key_data == NULL) { retval = ENOMEM; goto out; + } - } else { - /* Associate thread specific data, initialize new key */ - key_data->thread_data.key = key_obj; - key_data->thread_data.spec_data = (void *)value; + /* Associate thread specific data, initialize new key */ + key_data->thread_data.key = key_obj; + key_data->thread_data.spec_data = (void *)value; - /* Append new thread key data to thread's key list */ - sys_slist_append((&thread->key_list), - (sys_snode_t *)(&key_data->thread_data)); + /* Append new thread key data to thread's key list */ + sys_slist_append((&thread->key_list), (sys_snode_t *)(&key_data->thread_data)); - /* Append new key data to the key object's list */ - sys_slist_append(&(key_obj->key_data_l), - (sys_snode_t *)key_data); - } + /* Append new key data to the key object's list */ + sys_slist_append(&(key_obj->key_data_l), (sys_snode_t *)key_data); } out: From 742de21eef248c52a24ea37495edbbc4e37c43ea Mon Sep 17 00:00:00 2001 From: Christopher Friedt Date: Thu, 23 Nov 2023 12:01:52 -0500 Subject: [PATCH 0533/3723] posix: pthread: add logging to pthread key To align with other supported POSIX features, add logging to pthread key to provide better error reporting and diagnostics. Signed-off-by: Christopher Friedt --- lib/posix/key.c | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) diff --git a/lib/posix/key.c b/lib/posix/key.c index 698088e340a..9c32c95f043 100644 --- a/lib/posix/key.c +++ b/lib/posix/key.c @@ -7,6 +7,7 @@ #include "posix_internal.h" #include +#include #include #include #include @@ -17,6 +18,8 @@ struct pthread_key_data { pthread_thread_data thread_data; }; +LOG_MODULE_REGISTER(pthread_key, CONFIG_PTHREAD_KEY_LOG_LEVEL); + static struct k_spinlock pthread_key_lock; /* This is non-standard (i.e. an implementation detail) */ @@ -50,16 +53,19 @@ static pthread_key_obj *get_posix_key(pthread_key_t key) /* if the provided cond does not claim to be initialized, its invalid */ if (!is_pthread_obj_initialized(key)) { + LOG_ERR("Key is uninitialized (%x)", key); return NULL; } /* Mask off the MSB to get the actual bit index */ if (sys_bitarray_test_bit(&posix_key_bitarray, bit, &actually_initialized) < 0) { + LOG_ERR("Key is invalid (%x)", key); return NULL; } if (actually_initialized == 0) { /* The cond claims to be initialized but is actually not */ + LOG_ERR("Key claims to be initialized (%x)", key); return NULL; } @@ -110,6 +116,7 @@ int pthread_key_create(pthread_key_t *key, sys_slist_init(&(new_key->key_data_l)); new_key->destructor = destructor; + LOG_DBG("Initialized key %p (%x)", new_key, *key); return 0; } @@ -146,6 +153,7 @@ int pthread_key_delete(pthread_key_t key) /* Deallocate the object's memory */ k_free((void *)key_data); + LOG_DBG("Freed key data %p for key %x in thread %x", key_data, key, pthread_self()); } bit = posix_key_to_offset(key_obj); @@ -154,6 +162,8 @@ int pthread_key_delete(pthread_key_t key) k_spin_unlock(&pthread_key_lock, key_key); + LOG_DBG("Deleted key %p (%x)", key_obj, key); + return 0; } @@ -194,6 +204,8 @@ int pthread_setspecific(pthread_key_t key, const void *value) * associate thread specific data */ thread_spec_data->spec_data = (void *)value; + LOG_DBG("Paired key %x to value %p for thread %x", key, value, + pthread_self()); goto out; } } @@ -202,10 +214,14 @@ int pthread_setspecific(pthread_key_t key, const void *value) key_data = k_malloc(sizeof(struct pthread_key_data)); if (key_data == NULL) { + LOG_ERR("Failed to allocate key data for key %x", key); retval = ENOMEM; goto out; } + LOG_DBG("Allocated key data %p for key %x in thread %x", key_data, key, + pthread_self()); + /* Associate thread specific data, initialize new key */ key_data->thread_data.key = key_obj; key_data->thread_data.spec_data = (void *)value; @@ -215,6 +231,8 @@ int pthread_setspecific(pthread_key_t key, const void *value) /* Append new key data to the key object's list */ sys_slist_append(&(key_obj->key_data_l), (sys_snode_t *)key_data); + + LOG_DBG("Paired key %x to value %p for thread %x", key, value, pthread_self()); } out: From ac3d8ebd9e190868863f6259c24f8a6bb485cf3e Mon Sep 17 00:00:00 2001 From: Maciej Perkowski Date: Wed, 22 Nov 2023 16:56:02 +0100 Subject: [PATCH 0534/3723] twister: tests: Use inheritance in test_config.yaml There is no need of repeating the same entries in a scope that is supposed to extend another one. Signed-off-by: Maciej Perkowski --- tests/test_config.yaml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/tests/test_config.yaml b/tests/test_config.yaml index 927c489221f..3e0243159e1 100644 --- a/tests/test_config.yaml +++ b/tests/test_config.yaml @@ -13,7 +13,7 @@ levels: - name: acceptance description: > More coverage + inherits: + - smoke adds: - kernel.* - - arch.interrupt - - boards.* From 4733a89c506dd8d65d3452d6b40ed622b96926ff Mon Sep 17 00:00:00 2001 From: Maciej Perkowski Date: Wed, 22 Nov 2023 17:00:35 +0100 Subject: [PATCH 0535/3723] twister: tests: Add some generic driver tests to the scope The added tests should be generic enough to run on all reference platforms. Signed-off-by: Maciej Perkowski --- tests/test_config.yaml | 3 +++ 1 file changed, 3 insertions(+) diff --git a/tests/test_config.yaml b/tests/test_config.yaml index 3e0243159e1..72556252a72 100644 --- a/tests/test_config.yaml +++ b/tests/test_config.yaml @@ -10,6 +10,9 @@ levels: - kernel.timer.behavior - arch.interrupt - boards.* + - drivers.gpio.1pin + - drivers.console.uart + - drivers.entropy - name: acceptance description: > More coverage From e3aa22bfda6d3b2e4791976a839b449aaf5e4477 Mon Sep 17 00:00:00 2001 From: Daniel Leung Date: Mon, 27 Nov 2023 13:10:46 -0800 Subject: [PATCH 0536/3723] doc: porting/arch: fixed missing stack object memory map The stack object memory map was missing from the doc due to incorrect indentation. Fix it so that it shows up in the doc. Signed-off-by: Daniel Leung --- doc/hardware/porting/arch.rst | 31 +++++++++++++++---------------- 1 file changed, 15 insertions(+), 16 deletions(-) diff --git a/doc/hardware/porting/arch.rst b/doc/hardware/porting/arch.rst index 0e31a62707b..7a39d0acbbb 100644 --- a/doc/hardware/porting/arch.rst +++ b/doc/hardware/porting/arch.rst @@ -537,22 +537,21 @@ account storage for TLS and ASLR random offsets. .. code-block:: none - +---------------------+ <- thread.stack_obj - | Reserved Memory | } K_(THREAD|KERNEL)_STACK_RESERVED - +---------------------+ - | Carved-out memory | - |.....................| <- thread.stack_info.start - | Unused stack buffer | - | | - |.....................| <- thread's current stack pointer - | Used stack buffer | - | | - |.....................| <- Initial stack pointer. Computable - | ASLR Random offset | with thread.stack_info.delta - +---------------------| <- thread.userspace_local_data - | Thread-local data | - +---------------------+ <- thread.stack_info.start + - thread.stack_info.size + +---------------------+ <- thread.stack_obj + | Reserved Memory | } K_(THREAD|KERNEL)_STACK_RESERVED + +---------------------+ + | Carved-out memory | + |.....................| <- thread.stack_info.start + | Unused stack buffer | + | | + |.....................| <- thread's current stack pointer + | Used stack buffer | + | | + |.....................| <- Initial stack pointer. Computable + | ASLR Random offset | with thread.stack_info.delta + +---------------------| <- thread.userspace_local_data + | Thread-local data | + +---------------------+ <- thread.stack_info.start + thread.stack_info.size At present, Zephyr does not support stacks that grow upward. From 34c6b17680a7c3d540f7f70019c01e6f70777556 Mon Sep 17 00:00:00 2001 From: Daniel Leung Date: Mon, 27 Nov 2023 13:48:29 -0800 Subject: [PATCH 0537/3723] doc: fixed already renamed _Cstart to z_cstart The function _Cstart has already been renamed to z_cstart, so change the remaining references of it in various docs. Signed-off-by: Daniel Leung --- boards/nios2/altera_max10/doc/index.rst | 2 +- doc/hardware/porting/arch.rst | 4 ++-- kernel/include/kernel_arch_interface.h | 2 +- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/boards/nios2/altera_max10/doc/index.rst b/boards/nios2/altera_max10/doc/index.rst index c3a91d2ec9c..302c10c1cff 100644 --- a/boards/nios2/altera_max10/doc/index.rst +++ b/boards/nios2/altera_max10/doc/index.rst @@ -240,7 +240,7 @@ You will see output similar to the following: (gdb) c Continuing. - Breakpoint 2, _Cstart () at /projects/zephyr/kernel/init.c:348 + Breakpoint 2, z_cstart () at /projects/zephyr/kernel/init.c:348 348 { (gdb) diff --git a/doc/hardware/porting/arch.rst b/doc/hardware/porting/arch.rst index 7a39d0acbbb..3928244ec64 100644 --- a/doc/hardware/porting/arch.rst +++ b/doc/hardware/porting/arch.rst @@ -61,9 +61,9 @@ Common steps for all architectures: * If running an :abbr:`XIP (eXecute-In-Place)` kernel, copy initialized data from ROM to RAM. * If not using an ELF loader, zero the BSS section. -* Jump to :code:`_Cstart()`, the early kernel initialization +* Jump to :code:`z_cstart()`, the early kernel initialization - * :code:`_Cstart()` is responsible for context switching out of the fake + * :code:`z_cstart()` is responsible for context switching out of the fake context running at startup into the main thread. Some examples of architecture-specific steps that have to be taken: diff --git a/kernel/include/kernel_arch_interface.h b/kernel/include/kernel_arch_interface.h index 0173a4ae398..5d11521ab8b 100644 --- a/kernel/include/kernel_arch_interface.h +++ b/kernel/include/kernel_arch_interface.h @@ -560,7 +560,7 @@ int arch_printk_char_out(int c); /** * Architecture-specific kernel initialization hook * - * This function is invoked near the top of _Cstart, for additional + * This function is invoked near the top of z_cstart, for additional * architecture-specific setup before the rest of the kernel is brought up. */ static inline void arch_kernel_init(void); From 8f9fd239eb26dacc7d124c3b1831acf7c079be28 Mon Sep 17 00:00:00 2001 From: Daniel Leung Date: Mon, 27 Nov 2023 14:20:34 -0800 Subject: [PATCH 0538/3723] doc: porting/arch: add missing sections to overview list The section overview list at the beginning of the document is missing a few sections which were added after the list was first created. So add them. Signed-off-by: Daniel Leung --- doc/hardware/porting/arch.rst | 14 ++++++++++++-- 1 file changed, 12 insertions(+), 2 deletions(-) diff --git a/doc/hardware/porting/arch.rst b/doc/hardware/porting/arch.rst index 3928244ec64..62b79cdb032 100644 --- a/doc/hardware/porting/arch.rst +++ b/doc/hardware/porting/arch.rst @@ -47,6 +47,16 @@ some are optional: * **Linker scripts and toolchains**: architecture-specific details will most likely be needed in the build system and when linking the image (required). +* **Memory Management and Memory Mapping**: for architecture-specific details + on supporting memory management and memory mapping. + +* **Stack Objects**: for architecture-specific details on memory protection + hardware regarding stack objects. + +* **User Mode Threads**: for supporting threads in user mode. + +* **GDB Stub**: for supporting GDB stub to enable remote debugging. + Early Boot Sequence ******************* @@ -467,8 +477,8 @@ be derived from the linker scripts of other architectures. Some sections might be specific to the new architecture, for example the SCB section on ARM and the IDT section on x86. -Memory Management -***************** +Memory Management and Memory Mapping +************************************ If the target platform enables paging and requires drivers to memory-map their I/O regions, :kconfig:option:`CONFIG_MMU` needs to be enabled and the From e9e430c40d3338b3fb708bb38053cd43f333105f Mon Sep 17 00:00:00 2001 From: Parthiban Nallathambi Date: Thu, 30 Nov 2023 18:27:23 +0530 Subject: [PATCH 0539/3723] can: mcp251xfd: fix compilation Either switching to CAN_DEVICE_DT_INST_DEFINE with [1] missed updating mcp251xfd or missed in merge. Fix using function pointer for init in mcp251xfd. [1]: https://github.com/zephyrproject-rtos/zephyr/pull/62925 Signed-off-by: Parthiban Nallathambi --- drivers/can/can_mcp251xfd.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/can/can_mcp251xfd.c b/drivers/can/can_mcp251xfd.c index 7b788ec2b6c..2bb4f7e2cb5 100644 --- a/drivers/can/can_mcp251xfd.c +++ b/drivers/can/can_mcp251xfd.c @@ -1769,7 +1769,7 @@ static const struct can_driver_api mcp251xfd_api_funcs = { MCP251XFD_SET_CLOCK(inst) \ }; \ \ - CAN_DEVICE_DT_INST_DEFINE(inst, &mcp251xfd_init, NULL, &mcp251xfd_data_##inst, \ + CAN_DEVICE_DT_INST_DEFINE(inst, mcp251xfd_init, NULL, &mcp251xfd_data_##inst, \ &mcp251xfd_config_##inst, POST_KERNEL, CONFIG_CAN_INIT_PRIORITY, \ &mcp251xfd_api_funcs); From 44aaa0381896b04f579ce7a87659bd6459288af1 Mon Sep 17 00:00:00 2001 From: Alberto Escolar Piedras Date: Tue, 28 Nov 2023 14:17:53 +0100 Subject: [PATCH 0540/3723] release_notes: native_sim replaces native_posix Note that native_sim is replacing native_posix as default test platform. Signed-off-by: Alberto Escolar Piedras --- doc/releases/release-notes-3.6.rst | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/doc/releases/release-notes-3.6.rst b/doc/releases/release-notes-3.6.rst index daae0c64a6e..e8368857b9d 100644 --- a/doc/releases/release-notes-3.6.rst +++ b/doc/releases/release-notes-3.6.rst @@ -306,5 +306,10 @@ Documentation Tests and Samples ***************** +* :ref:`native_sim` has replaced :ref:`native_posix` as the default + test platform. + :ref:`native_posix` remains supported and used in testing but will be deprecated + in a future release. + * Fixed an issue in :zephyr:code-sample:`smp-svr` sample whereby if USB was already initialised, application would fail to boot properly. From 3fcc505b410771120c13166e0b03844165200e90 Mon Sep 17 00:00:00 2001 From: Wilfried Chauveau Date: Tue, 25 Jul 2023 10:25:53 +0100 Subject: [PATCH 0541/3723] dts: bindings: mmu_mpu: Mark arm,num-mpu-regions as optional The C code does not required this parameter to be defined and falls back to the MPU_TYPE's register to return the appropriate value. Signed-off-by: Wilfried Chauveau --- dts/bindings/mmu_mpu/arm,armv6m-mpu.yaml | 1 - dts/bindings/mmu_mpu/arm,armv7m-mpu.yaml | 1 - dts/bindings/mmu_mpu/arm,armv8.1m-mpu.yaml | 1 - dts/bindings/mmu_mpu/arm,armv8m-mpu.yaml | 1 - 4 files changed, 4 deletions(-) diff --git a/dts/bindings/mmu_mpu/arm,armv6m-mpu.yaml b/dts/bindings/mmu_mpu/arm,armv6m-mpu.yaml index 6534ec07874..00bc8927f58 100644 --- a/dts/bindings/mmu_mpu/arm,armv6m-mpu.yaml +++ b/dts/bindings/mmu_mpu/arm,armv6m-mpu.yaml @@ -12,7 +12,6 @@ properties: required: true arm,num-mpu-regions: - required: true type: int const: 8 description: number of MPU regions supported by hardware diff --git a/dts/bindings/mmu_mpu/arm,armv7m-mpu.yaml b/dts/bindings/mmu_mpu/arm,armv7m-mpu.yaml index 36de0b9f711..09c2388a7a2 100644 --- a/dts/bindings/mmu_mpu/arm,armv7m-mpu.yaml +++ b/dts/bindings/mmu_mpu/arm,armv7m-mpu.yaml @@ -9,6 +9,5 @@ properties: required: true arm,num-mpu-regions: - required: true type: int description: number of MPU regions supported by hardware diff --git a/dts/bindings/mmu_mpu/arm,armv8.1m-mpu.yaml b/dts/bindings/mmu_mpu/arm,armv8.1m-mpu.yaml index fd924284de8..407d23a8d78 100644 --- a/dts/bindings/mmu_mpu/arm,armv8.1m-mpu.yaml +++ b/dts/bindings/mmu_mpu/arm,armv8.1m-mpu.yaml @@ -9,6 +9,5 @@ properties: required: true arm,num-mpu-regions: - required: true type: int description: number of MPU regions supported by hardware diff --git a/dts/bindings/mmu_mpu/arm,armv8m-mpu.yaml b/dts/bindings/mmu_mpu/arm,armv8m-mpu.yaml index 10321622891..15c5085a33d 100644 --- a/dts/bindings/mmu_mpu/arm,armv8m-mpu.yaml +++ b/dts/bindings/mmu_mpu/arm,armv8m-mpu.yaml @@ -9,6 +9,5 @@ properties: required: true arm,num-mpu-regions: - required: true type: int description: number of MPU regions supported by hardware From 784355aeb37d17f473a834b51aa9f23bd0d037d1 Mon Sep 17 00:00:00 2001 From: Wilfried Chauveau Date: Tue, 25 Jul 2023 10:30:26 +0100 Subject: [PATCH 0542/3723] boards: arm: mps2_an521: remove the arm,num-mpu-regions property MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The SSE-200 implementation on AN521 only has 8 regions. Although the AN521 FPGA image implements the documented value, qemu-system-arm currently shows in MPU_TYPE the incorrect value of 16. Removing the property definition allows the code to rely on the register read value and work on both qemu-system-arm & the physical board. Signed-off-by: Wilfried Chauveau --- boards/arm/mps2_an521/mps2_an521.dts | 1 - 1 file changed, 1 deletion(-) diff --git a/boards/arm/mps2_an521/mps2_an521.dts b/boards/arm/mps2_an521/mps2_an521.dts index d69228b235a..2bb956645ca 100644 --- a/boards/arm/mps2_an521/mps2_an521.dts +++ b/boards/arm/mps2_an521/mps2_an521.dts @@ -79,7 +79,6 @@ mpu: mpu@e000ed90 { compatible = "arm,armv8m-mpu"; reg = <0xe000ed90 0x40>; - arm,num-mpu-regions = <16>; }; }; }; From 5b3d4598a7e25062b54cef675f6ca6c36e46a5f8 Mon Sep 17 00:00:00 2001 From: Wilfried Chauveau Date: Wed, 26 Jul 2023 09:17:03 +0100 Subject: [PATCH 0543/3723] dts: arm: Blanket remove all usages of arm,num-mpu-regions This removes all occurrences of arm,num-mpu-regions relying on the value reported by the register instead. A user may still define this property if they need to have a compile time definition for it. Signed-off-by: Wilfried Chauveau --- boards/arm/arty/arty_a7_arm_designstart_m3.dts | 1 - boards/arm/mps2_an521/mps2_an521_ns.dts | 1 - boards/arm/mps2_an521/mps2_an521_remote.dts | 1 - boards/arm/mps3_an547/mps3_an547.dts | 1 - boards/arm/mps3_an547/mps3_an547_ns.dts | 1 - boards/arm/scobc_module1/scobc_module1.dts | 1 - boards/arm/v2m_musca_b1/v2m_musca_b1.dts | 1 - boards/arm/v2m_musca_b1/v2m_musca_b1_ns.dts | 1 - boards/arm/v2m_musca_s1/v2m_musca_s1.dts | 1 - boards/arm/v2m_musca_s1/v2m_musca_s1_ns.dts | 1 - dts/arm/atmel/sam4e.dtsi | 1 - dts/arm/atmel/sam4l.dtsi | 1 - dts/arm/atmel/sam4s.dtsi | 1 - dts/arm/atmel/samd5x.dtsi | 1 - dts/arm/atmel/same70.dtsi | 1 - dts/arm/broadcom/valkyrie.dtsi | 1 - dts/arm/broadcom/viper-m7.dtsi | 1 - dts/arm/gigadevice/gd32a50x/gd32a50x.dtsi | 1 - dts/arm/gigadevice/gd32e50x/gd32e50x.dtsi | 1 - dts/arm/gigadevice/gd32f403/gd32f403.dtsi | 1 - dts/arm/gigadevice/gd32f4xx/gd32f4xx.dtsi | 1 - dts/arm/nordic/nrf5340_cpuapp_qkaa.dtsi | 4 ---- dts/arm/nordic/nrf5340_cpuappns_qkaa.dtsi | 4 ---- dts/arm/nordic/nrf5340_cpunet_qkaa.dtsi | 4 ---- dts/arm/nordic/nrf91.dtsi | 1 - dts/arm/nordic/nrf91ns.dtsi | 1 - dts/arm/nxp/nxp_imx8ml_m7.dtsi | 1 - dts/arm/nxp/nxp_lpc55S0x_common.dtsi | 1 - dts/arm/nxp/nxp_lpc55S1x_common.dtsi | 1 - dts/arm/nxp/nxp_lpc55S2x_common.dtsi | 1 - dts/arm/nxp/nxp_lpc55S3x_common.dtsi | 1 - dts/arm/nxp/nxp_lpc55S6x_common.dtsi | 1 - dts/arm/nxp/nxp_rt10xx.dtsi | 1 - dts/arm/nxp/nxp_rt11xx.dtsi | 2 -- dts/arm/nxp/nxp_rt5xx_common.dtsi | 1 - dts/arm/nxp/nxp_rt6xx_common.dtsi | 1 - dts/arm/nxp/nxp_s32k344_m7.dtsi | 1 - dts/arm/quicklogic/quicklogic_eos_s3.dtsi | 1 - dts/arm/silabs/efr32mg21.dtsi | 1 - dts/arm/st/f7/stm32f7.dtsi | 1 - dts/arm/st/h5/stm32h5.dtsi | 1 - dts/arm/st/h7/stm32h7.dtsi | 1 - dts/arm/st/l5/stm32l5.dtsi | 1 - dts/arm/st/u5/stm32u5.dtsi | 1 - dts/arm/st/wba/stm32wba.dtsi | 1 - 45 files changed, 55 deletions(-) diff --git a/boards/arm/arty/arty_a7_arm_designstart_m3.dts b/boards/arm/arty/arty_a7_arm_designstart_m3.dts index 59a5ed88fa8..4191febff6e 100644 --- a/boards/arm/arty/arty_a7_arm_designstart_m3.dts +++ b/boards/arm/arty/arty_a7_arm_designstart_m3.dts @@ -25,7 +25,6 @@ mpu: mpu@e000ed90 { compatible = "arm,armv7m-mpu"; reg = <0xe000ed90 0x40>; - arm,num-mpu-regions = <8>; }; }; }; diff --git a/boards/arm/mps2_an521/mps2_an521_ns.dts b/boards/arm/mps2_an521/mps2_an521_ns.dts index 80e235244a1..e2b24cd9ba5 100644 --- a/boards/arm/mps2_an521/mps2_an521_ns.dts +++ b/boards/arm/mps2_an521/mps2_an521_ns.dts @@ -71,7 +71,6 @@ mpu: mpu@e000ed90 { compatible = "arm,armv8m-mpu"; reg = <0xe000ed90 0x40>; - arm,num-mpu-regions = <16>; }; }; }; diff --git a/boards/arm/mps2_an521/mps2_an521_remote.dts b/boards/arm/mps2_an521/mps2_an521_remote.dts index a52b88ff447..311694ca399 100644 --- a/boards/arm/mps2_an521/mps2_an521_remote.dts +++ b/boards/arm/mps2_an521/mps2_an521_remote.dts @@ -71,7 +71,6 @@ mpu: mpu@e000ed90 { compatible = "arm,armv8m-mpu"; reg = <0xe000ed90 0x40>; - arm,num-mpu-regions = <16>; }; }; }; diff --git a/boards/arm/mps3_an547/mps3_an547.dts b/boards/arm/mps3_an547/mps3_an547.dts index 53168a4de2d..50700e8278e 100644 --- a/boards/arm/mps3_an547/mps3_an547.dts +++ b/boards/arm/mps3_an547/mps3_an547.dts @@ -118,7 +118,6 @@ mpu: mpu@e000ed90 { compatible = "arm,armv8.1m-mpu"; reg = <0xe000ed90 0x40>; - arm,num-mpu-regions = <16>; }; }; }; diff --git a/boards/arm/mps3_an547/mps3_an547_ns.dts b/boards/arm/mps3_an547/mps3_an547_ns.dts index ac6531441eb..dd8c9c4571c 100644 --- a/boards/arm/mps3_an547/mps3_an547_ns.dts +++ b/boards/arm/mps3_an547/mps3_an547_ns.dts @@ -70,7 +70,6 @@ mpu: mpu@e000ed90 { compatible = "arm,armv8.1m-mpu"; reg = <0xe000ed90 0x40>; - arm,num-mpu-regions = <16>; }; }; }; diff --git a/boards/arm/scobc_module1/scobc_module1.dts b/boards/arm/scobc_module1/scobc_module1.dts index 1cfa73bc91b..3f704e1113d 100644 --- a/boards/arm/scobc_module1/scobc_module1.dts +++ b/boards/arm/scobc_module1/scobc_module1.dts @@ -31,7 +31,6 @@ mpu: mpu@e000ed90 { compatible = "arm,armv7m-mpu"; reg = <0xe000ed90 0x40>; - arm,num-mpu-regions = <8>; }; }; }; diff --git a/boards/arm/v2m_musca_b1/v2m_musca_b1.dts b/boards/arm/v2m_musca_b1/v2m_musca_b1.dts index 2c260552f07..e5bf38ec422 100644 --- a/boards/arm/v2m_musca_b1/v2m_musca_b1.dts +++ b/boards/arm/v2m_musca_b1/v2m_musca_b1.dts @@ -56,7 +56,6 @@ mpu: mpu@e000ed90 { compatible = "arm,armv8m-mpu"; reg = <0xe000ed90 0x40>; - arm,num-mpu-regions = <8>; }; }; }; diff --git a/boards/arm/v2m_musca_b1/v2m_musca_b1_ns.dts b/boards/arm/v2m_musca_b1/v2m_musca_b1_ns.dts index a54a2829cd7..4aef3b4c066 100644 --- a/boards/arm/v2m_musca_b1/v2m_musca_b1_ns.dts +++ b/boards/arm/v2m_musca_b1/v2m_musca_b1_ns.dts @@ -37,7 +37,6 @@ mpu: mpu@e000ed90 { compatible = "arm,armv8m-mpu"; reg = <0xe000ed90 0x40>; - arm,num-mpu-regions = <8>; }; }; }; diff --git a/boards/arm/v2m_musca_s1/v2m_musca_s1.dts b/boards/arm/v2m_musca_s1/v2m_musca_s1.dts index 619d63eb60e..5f60afdddb5 100644 --- a/boards/arm/v2m_musca_s1/v2m_musca_s1.dts +++ b/boards/arm/v2m_musca_s1/v2m_musca_s1.dts @@ -56,7 +56,6 @@ mpu: mpu@e000ed90 { compatible = "arm,armv8m-mpu"; reg = <0xe000ed90 0x40>; - arm,num-mpu-regions = <8>; }; }; }; diff --git a/boards/arm/v2m_musca_s1/v2m_musca_s1_ns.dts b/boards/arm/v2m_musca_s1/v2m_musca_s1_ns.dts index 23e75ab03aa..5ea0bde7748 100644 --- a/boards/arm/v2m_musca_s1/v2m_musca_s1_ns.dts +++ b/boards/arm/v2m_musca_s1/v2m_musca_s1_ns.dts @@ -37,7 +37,6 @@ mpu: mpu@e000ed90 { compatible = "arm,armv8m-mpu"; reg = <0xe000ed90 0x40>; - arm,num-mpu-regions = <8>; }; }; }; diff --git a/dts/arm/atmel/sam4e.dtsi b/dts/arm/atmel/sam4e.dtsi index 2e9e916eef2..21d6f2d2846 100644 --- a/dts/arm/atmel/sam4e.dtsi +++ b/dts/arm/atmel/sam4e.dtsi @@ -33,7 +33,6 @@ mpu: mpu@e000ed90 { compatible = "arm,armv7m-mpu"; reg = <0xe000ed90 0x40>; - arm,num-mpu-regions = <8>; }; }; }; diff --git a/dts/arm/atmel/sam4l.dtsi b/dts/arm/atmel/sam4l.dtsi index 1f11478044f..7f19f8d21a4 100644 --- a/dts/arm/atmel/sam4l.dtsi +++ b/dts/arm/atmel/sam4l.dtsi @@ -29,7 +29,6 @@ mpu: mpu@e000ed90 { compatible = "arm,armv7m-mpu"; reg = <0xe000ed90 0x40>; - arm,num-mpu-regions = <8>; }; }; }; diff --git a/dts/arm/atmel/sam4s.dtsi b/dts/arm/atmel/sam4s.dtsi index 8c7cf1acc2a..768f5351817 100644 --- a/dts/arm/atmel/sam4s.dtsi +++ b/dts/arm/atmel/sam4s.dtsi @@ -35,7 +35,6 @@ mpu: mpu@e000ed90 { compatible = "arm,armv7m-mpu"; reg = <0xe000ed90 0x40>; - arm,num-mpu-regions = <8>; }; }; }; diff --git a/dts/arm/atmel/samd5x.dtsi b/dts/arm/atmel/samd5x.dtsi index 5af30c4680b..b64abc5de45 100644 --- a/dts/arm/atmel/samd5x.dtsi +++ b/dts/arm/atmel/samd5x.dtsi @@ -29,7 +29,6 @@ mpu: mpu@e000ed90 { compatible = "arm,armv7m-mpu"; reg = <0xe000ed90 0x40>; - arm,num-mpu-regions = <8>; }; }; }; diff --git a/dts/arm/atmel/same70.dtsi b/dts/arm/atmel/same70.dtsi index 8c378d90d0d..d15d6baf83e 100644 --- a/dts/arm/atmel/same70.dtsi +++ b/dts/arm/atmel/same70.dtsi @@ -39,7 +39,6 @@ mpu: mpu@e000ed90 { compatible = "arm,armv7m-mpu"; reg = <0xe000ed90 0x40>; - arm,num-mpu-regions = <16>; }; }; }; diff --git a/dts/arm/broadcom/valkyrie.dtsi b/dts/arm/broadcom/valkyrie.dtsi index e413018022c..03df61fcdae 100644 --- a/dts/arm/broadcom/valkyrie.dtsi +++ b/dts/arm/broadcom/valkyrie.dtsi @@ -21,7 +21,6 @@ mpu: mpu@e000ed90 { compatible = "arm,armv7m-mpu"; reg = <0xe000ed90 0x40>; - arm,num-mpu-regions = <16>; }; }; }; diff --git a/dts/arm/broadcom/viper-m7.dtsi b/dts/arm/broadcom/viper-m7.dtsi index 2c0e7e3b25d..85e38616e8b 100644 --- a/dts/arm/broadcom/viper-m7.dtsi +++ b/dts/arm/broadcom/viper-m7.dtsi @@ -23,7 +23,6 @@ mpu: mpu@e000ed90 { compatible = "arm,armv7m-mpu"; reg = <0xe000ed90 0x40>; - arm,num-mpu-regions = <16>; }; }; }; diff --git a/dts/arm/gigadevice/gd32a50x/gd32a50x.dtsi b/dts/arm/gigadevice/gd32a50x/gd32a50x.dtsi index 3a3f1bfed49..00f70dfc96b 100644 --- a/dts/arm/gigadevice/gd32a50x/gd32a50x.dtsi +++ b/dts/arm/gigadevice/gd32a50x/gd32a50x.dtsi @@ -28,7 +28,6 @@ mpu: mpu@e000ed90 { compatible = "arm,armv8m-mpu"; reg = <0xe000ed90 0x40>; - arm,num-mpu-regions = <8>; }; }; }; diff --git a/dts/arm/gigadevice/gd32e50x/gd32e50x.dtsi b/dts/arm/gigadevice/gd32e50x/gd32e50x.dtsi index e073dd8ff4e..a02dd5df866 100644 --- a/dts/arm/gigadevice/gd32e50x/gd32e50x.dtsi +++ b/dts/arm/gigadevice/gd32e50x/gd32e50x.dtsi @@ -74,7 +74,6 @@ mpu: mpu@e000ed90 { compatible = "arm,armv8m-mpu"; reg = <0xe000ed90 0x40>; - arm,num-mpu-regions = <8>; }; usart0: usart@40013800 { diff --git a/dts/arm/gigadevice/gd32f403/gd32f403.dtsi b/dts/arm/gigadevice/gd32f403/gd32f403.dtsi index e4e57417307..0b6ac33245c 100644 --- a/dts/arm/gigadevice/gd32f403/gd32f403.dtsi +++ b/dts/arm/gigadevice/gd32f403/gd32f403.dtsi @@ -28,7 +28,6 @@ mpu: mpu@e000ed90 { compatible = "arm,armv7m-mpu"; reg = <0xe000ed90 0x40>; - arm,num-mpu-regions = <8>; }; }; }; diff --git a/dts/arm/gigadevice/gd32f4xx/gd32f4xx.dtsi b/dts/arm/gigadevice/gd32f4xx/gd32f4xx.dtsi index 5a0d2aa85ab..f2e35e981e4 100644 --- a/dts/arm/gigadevice/gd32f4xx/gd32f4xx.dtsi +++ b/dts/arm/gigadevice/gd32f4xx/gd32f4xx.dtsi @@ -26,7 +26,6 @@ mpu: mpu@e000ed90 { compatible = "arm,armv7m-mpu"; reg = <0xe000ed90 0x40>; - arm,num-mpu-regions = <8>; }; }; }; diff --git a/dts/arm/nordic/nrf5340_cpuapp_qkaa.dtsi b/dts/arm/nordic/nrf5340_cpuapp_qkaa.dtsi index 9a730a39406..a543ffe906b 100644 --- a/dts/arm/nordic/nrf5340_cpuapp_qkaa.dtsi +++ b/dts/arm/nordic/nrf5340_cpuapp_qkaa.dtsi @@ -15,10 +15,6 @@ reg = <0x20000000 DT_SIZE_K(512)>; }; -&mpu { - arm,num-mpu-regions = <8>; -}; - / { soc { compatible = "nordic,nrf5340-cpuapp-qkaa", "nordic,nrf5340-cpuapp", diff --git a/dts/arm/nordic/nrf5340_cpuappns_qkaa.dtsi b/dts/arm/nordic/nrf5340_cpuappns_qkaa.dtsi index e4f38769d8f..80d5706232f 100644 --- a/dts/arm/nordic/nrf5340_cpuappns_qkaa.dtsi +++ b/dts/arm/nordic/nrf5340_cpuappns_qkaa.dtsi @@ -15,10 +15,6 @@ reg = <0x20000000 DT_SIZE_K(512)>; }; -&mpu { - arm,num-mpu-regions = <8>; -}; - / { soc { compatible = "nordic,nrf5340-cpuapp-qkaa", "nordic,nrf5340-cpuapp", diff --git a/dts/arm/nordic/nrf5340_cpunet_qkaa.dtsi b/dts/arm/nordic/nrf5340_cpunet_qkaa.dtsi index c8047ebf905..19eb682ddfc 100644 --- a/dts/arm/nordic/nrf5340_cpunet_qkaa.dtsi +++ b/dts/arm/nordic/nrf5340_cpunet_qkaa.dtsi @@ -19,10 +19,6 @@ reg = <0x21000000 DT_SIZE_K(64)>; }; -&mpu { - arm,num-mpu-regions = <8>; -}; - / { soc { compatible = "nordic,nrf5340-cpunet-qkaa", "nordic,nrf5340-cpunet", diff --git a/dts/arm/nordic/nrf91.dtsi b/dts/arm/nordic/nrf91.dtsi index 46024011166..d166059c01d 100644 --- a/dts/arm/nordic/nrf91.dtsi +++ b/dts/arm/nordic/nrf91.dtsi @@ -22,7 +22,6 @@ mpu: mpu@e000ed90 { compatible = "arm,armv8m-mpu"; reg = <0xe000ed90 0x40>; - arm,num-mpu-regions = <16>; }; }; }; diff --git a/dts/arm/nordic/nrf91ns.dtsi b/dts/arm/nordic/nrf91ns.dtsi index 910f45ec706..cff60f5f3c6 100644 --- a/dts/arm/nordic/nrf91ns.dtsi +++ b/dts/arm/nordic/nrf91ns.dtsi @@ -22,7 +22,6 @@ mpu: mpu@e000ed90 { compatible = "arm,armv8m-mpu"; reg = <0xe000ed90 0x40>; - arm,num-mpu-regions = <16>; }; }; }; diff --git a/dts/arm/nxp/nxp_imx8ml_m7.dtsi b/dts/arm/nxp/nxp_imx8ml_m7.dtsi index f9406fc7546..df4636bc72a 100644 --- a/dts/arm/nxp/nxp_imx8ml_m7.dtsi +++ b/dts/arm/nxp/nxp_imx8ml_m7.dtsi @@ -24,7 +24,6 @@ mpu: mpu@e000ed90 { compatible = "arm,armv7m-mpu"; reg = <0xe000ed90 0x40>; - arm,num-mpu-regions = <16>; }; }; }; diff --git a/dts/arm/nxp/nxp_lpc55S0x_common.dtsi b/dts/arm/nxp/nxp_lpc55S0x_common.dtsi index ca7a25b765e..b7a13229e00 100644 --- a/dts/arm/nxp/nxp_lpc55S0x_common.dtsi +++ b/dts/arm/nxp/nxp_lpc55S0x_common.dtsi @@ -23,7 +23,6 @@ mpu: mpu@e000ed90 { compatible = "arm,armv8m-mpu"; reg = <0xe000ed90 0x40>; - arm,num-mpu-regions = <8>; }; }; }; diff --git a/dts/arm/nxp/nxp_lpc55S1x_common.dtsi b/dts/arm/nxp/nxp_lpc55S1x_common.dtsi index 76d551555ef..8a62b6fe5af 100644 --- a/dts/arm/nxp/nxp_lpc55S1x_common.dtsi +++ b/dts/arm/nxp/nxp_lpc55S1x_common.dtsi @@ -25,7 +25,6 @@ mpu: mpu@e000ed90 { compatible = "arm,armv8m-mpu"; reg = <0xe000ed90 0x40>; - arm,num-mpu-regions = <8>; }; }; }; diff --git a/dts/arm/nxp/nxp_lpc55S2x_common.dtsi b/dts/arm/nxp/nxp_lpc55S2x_common.dtsi index 16d9c1312c3..6ec0240b2f1 100644 --- a/dts/arm/nxp/nxp_lpc55S2x_common.dtsi +++ b/dts/arm/nxp/nxp_lpc55S2x_common.dtsi @@ -34,7 +34,6 @@ mpu: mpu@e000ed90 { compatible = "arm,armv8m-mpu"; reg = <0xe000ed90 0x40>; - arm,num-mpu-regions = <8>; }; }; }; diff --git a/dts/arm/nxp/nxp_lpc55S3x_common.dtsi b/dts/arm/nxp/nxp_lpc55S3x_common.dtsi index dd011ece96d..348b5e6083d 100644 --- a/dts/arm/nxp/nxp_lpc55S3x_common.dtsi +++ b/dts/arm/nxp/nxp_lpc55S3x_common.dtsi @@ -30,7 +30,6 @@ mpu: mpu@e000ed90 { compatible = "arm,armv8m-mpu"; reg = <0xe000ed90 0x40>; - arm,num-mpu-regions = <8>; }; }; }; diff --git a/dts/arm/nxp/nxp_lpc55S6x_common.dtsi b/dts/arm/nxp/nxp_lpc55S6x_common.dtsi index 5095a96738f..00cbb8fa0a5 100644 --- a/dts/arm/nxp/nxp_lpc55S6x_common.dtsi +++ b/dts/arm/nxp/nxp_lpc55S6x_common.dtsi @@ -35,7 +35,6 @@ mpu: mpu@e000ed90 { compatible = "arm,armv8m-mpu"; reg = <0xe000ed90 0x40>; - arm,num-mpu-regions = <8>; }; }; cpu@1 { diff --git a/dts/arm/nxp/nxp_rt10xx.dtsi b/dts/arm/nxp/nxp_rt10xx.dtsi index e7e4e6448b2..73e108f1005 100644 --- a/dts/arm/nxp/nxp_rt10xx.dtsi +++ b/dts/arm/nxp/nxp_rt10xx.dtsi @@ -35,7 +35,6 @@ mpu: mpu@e000ed90 { compatible = "arm,armv7m-mpu"; reg = <0xe000ed90 0x40>; - arm,num-mpu-regions = <16>; }; itm: itm@e0000000 { diff --git a/dts/arm/nxp/nxp_rt11xx.dtsi b/dts/arm/nxp/nxp_rt11xx.dtsi index eb14d37f834..9e92a3e0226 100644 --- a/dts/arm/nxp/nxp_rt11xx.dtsi +++ b/dts/arm/nxp/nxp_rt11xx.dtsi @@ -34,7 +34,6 @@ mpu: mpu@e000ed90 { compatible = "arm,armv7m-mpu"; reg = <0xe000ed90 0x40>; - arm,num-mpu-regions = <16>; }; }; cpu1: cpu@1 { @@ -49,7 +48,6 @@ mpu: mpu@e000ed90 { compatible = "arm,armv7m-mpu"; reg = <0xe000ed90 0x40>; - arm,num-mpu-regions = <16>; }; }; diff --git a/dts/arm/nxp/nxp_rt5xx_common.dtsi b/dts/arm/nxp/nxp_rt5xx_common.dtsi index 8a1a1aa3c3d..42f3951ab20 100644 --- a/dts/arm/nxp/nxp_rt5xx_common.dtsi +++ b/dts/arm/nxp/nxp_rt5xx_common.dtsi @@ -33,7 +33,6 @@ mpu: mpu@e000ed90 { compatible = "arm,armv8m-mpu"; reg = <0xe000ed90 0x40>; - arm,num-mpu-regions = <8>; }; }; diff --git a/dts/arm/nxp/nxp_rt6xx_common.dtsi b/dts/arm/nxp/nxp_rt6xx_common.dtsi index 0c81f71d140..97a664845ec 100644 --- a/dts/arm/nxp/nxp_rt6xx_common.dtsi +++ b/dts/arm/nxp/nxp_rt6xx_common.dtsi @@ -31,7 +31,6 @@ mpu: mpu@e000ed90 { compatible = "arm,armv8m-mpu"; reg = <0xe000ed90 0x40>; - arm,num-mpu-regions = <8>; }; }; diff --git a/dts/arm/nxp/nxp_s32k344_m7.dtsi b/dts/arm/nxp/nxp_s32k344_m7.dtsi index f5e96aba8e1..036b89a540d 100644 --- a/dts/arm/nxp/nxp_s32k344_m7.dtsi +++ b/dts/arm/nxp/nxp_s32k344_m7.dtsi @@ -29,7 +29,6 @@ mpu: mpu@e000ed90 { compatible = "arm,armv7m-mpu"; reg = <0xe000ed90 0x40>; - arm,num-mpu-regions = <16>; }; }; diff --git a/dts/arm/quicklogic/quicklogic_eos_s3.dtsi b/dts/arm/quicklogic/quicklogic_eos_s3.dtsi index f29b1c482ff..bdc4ecfe87d 100644 --- a/dts/arm/quicklogic/quicklogic_eos_s3.dtsi +++ b/dts/arm/quicklogic/quicklogic_eos_s3.dtsi @@ -23,7 +23,6 @@ mpu: mpu@e000ed90 { compatible = "arm,armv7m-mpu"; reg = <0xe000ed90 0x40>; - arm,num-mpu-regions = <8>; }; }; }; diff --git a/dts/arm/silabs/efr32mg21.dtsi b/dts/arm/silabs/efr32mg21.dtsi index 4ada3f6ff60..217830f7265 100644 --- a/dts/arm/silabs/efr32mg21.dtsi +++ b/dts/arm/silabs/efr32mg21.dtsi @@ -30,7 +30,6 @@ mpu: mpu@e000ed90 { compatible = "arm,armv8m-mpu"; reg = <0xe000ed90 0x40>; - arm,num-mpu-regions = <16>; }; }; }; diff --git a/dts/arm/st/f7/stm32f7.dtsi b/dts/arm/st/f7/stm32f7.dtsi index 6569d35c49f..e59b41a7744 100644 --- a/dts/arm/st/f7/stm32f7.dtsi +++ b/dts/arm/st/f7/stm32f7.dtsi @@ -40,7 +40,6 @@ mpu: mpu@e000ed90 { compatible = "arm,armv7m-mpu"; reg = <0xe000ed90 0x40>; - arm,num-mpu-regions = <8>; }; }; }; diff --git a/dts/arm/st/h5/stm32h5.dtsi b/dts/arm/st/h5/stm32h5.dtsi index d8a93a58619..43266cfbe2c 100644 --- a/dts/arm/st/h5/stm32h5.dtsi +++ b/dts/arm/st/h5/stm32h5.dtsi @@ -36,7 +36,6 @@ mpu: mpu@e000ed90 { compatible = "arm,armv8m-mpu"; reg = <0xe000ed90 0x40>; - arm,num-mpu-regions = <8>; }; }; }; diff --git a/dts/arm/st/h7/stm32h7.dtsi b/dts/arm/st/h7/stm32h7.dtsi index 58a01b962b2..ecbe8f419a6 100644 --- a/dts/arm/st/h7/stm32h7.dtsi +++ b/dts/arm/st/h7/stm32h7.dtsi @@ -41,7 +41,6 @@ mpu: mpu@e000ed90 { compatible = "arm,armv7m-mpu"; reg = <0xe000ed90 0x40>; - arm,num-mpu-regions = <16>; }; }; }; diff --git a/dts/arm/st/l5/stm32l5.dtsi b/dts/arm/st/l5/stm32l5.dtsi index c8c94319353..3886de37631 100644 --- a/dts/arm/st/l5/stm32l5.dtsi +++ b/dts/arm/st/l5/stm32l5.dtsi @@ -40,7 +40,6 @@ mpu: mpu@e000ed90 { compatible = "arm,armv8m-mpu"; reg = <0xe000ed90 0x40>; - arm,num-mpu-regions = <8>; }; }; diff --git a/dts/arm/st/u5/stm32u5.dtsi b/dts/arm/st/u5/stm32u5.dtsi index ae9dd9d9c8c..7bfe52780b2 100644 --- a/dts/arm/st/u5/stm32u5.dtsi +++ b/dts/arm/st/u5/stm32u5.dtsi @@ -41,7 +41,6 @@ mpu: mpu@e000ed90 { compatible = "arm,armv8m-mpu"; reg = <0xe000ed90 0x40>; - arm,num-mpu-regions = <8>; }; }; diff --git a/dts/arm/st/wba/stm32wba.dtsi b/dts/arm/st/wba/stm32wba.dtsi index 6c5cc8f869a..5e0f67625ee 100644 --- a/dts/arm/st/wba/stm32wba.dtsi +++ b/dts/arm/st/wba/stm32wba.dtsi @@ -38,7 +38,6 @@ mpu: mpu@e000ed90 { compatible = "arm,armv8m-mpu"; reg = <0xe000ed90 0x40>; - arm,num-mpu-regions = <8>; }; }; From 85af32e16ee1fbcb77c2bcbdda73b1b2e55d6b08 Mon Sep 17 00:00:00 2001 From: Wilfried Chauveau Date: Fri, 29 Sep 2023 23:15:38 +0100 Subject: [PATCH 0544/3723] arch: arm: remove num-mpu-regions Remove this property presumably unused. Signed-off-by: Wilfried Chauveau --- arch/arm/core/mpu/arm_mpu.c | 9 --------- arch/arm/core/mpu/arm_mpu_v8_internal.h | 5 ----- arch/arm/core/mpu/cortex_a_r/arm_mpu_internal.h | 5 ----- arch/arm/core/mpu/cortex_m/arm_mpu_internal.h | 12 ------------ dts/bindings/mmu_mpu/arm,armv6m-mpu.yaml | 5 ----- dts/bindings/mmu_mpu/arm,armv7m-mpu.yaml | 4 ---- dts/bindings/mmu_mpu/arm,armv8.1m-mpu.yaml | 4 ---- dts/bindings/mmu_mpu/arm,armv8m-mpu.yaml | 4 ---- 8 files changed, 48 deletions(-) diff --git a/arch/arm/core/mpu/arm_mpu.c b/arch/arm/core/mpu/arm_mpu.c index 9b2feffe5ee..94c92edbc5c 100644 --- a/arch/arm/core/mpu/arm_mpu.c +++ b/arch/arm/core/mpu/arm_mpu.c @@ -30,10 +30,6 @@ LOG_MODULE_DECLARE(mpu); #define MPU_NODEID DT_INST(0, arm_armv6m_mpu) #endif -#if DT_NODE_HAS_PROP(MPU_NODEID, arm_num_mpu_regions) -#define NUM_MPU_REGIONS DT_PROP(MPU_NODEID, arm_num_mpu_regions) -#endif - #define NODE_HAS_PROP_AND_OR(node_id, prop) \ DT_NODE_HAS_PROP(node_id, prop) || @@ -527,11 +523,6 @@ int z_arm_mpu_init(void) __ASSERT( (MPU->TYPE & MPU_TYPE_DREGION_Msk) >> MPU_TYPE_DREGION_Pos == 8, "Invalid number of MPU regions\n"); -#elif defined(NUM_MPU_REGIONS) - __ASSERT( - (MPU->TYPE & MPU_TYPE_DREGION_Msk) >> MPU_TYPE_DREGION_Pos == - NUM_MPU_REGIONS, - "Invalid number of MPU regions\n"); #endif /* CORTEX_M0PLUS || CPU_CORTEX_M3 || CPU_CORTEX_M4 */ return 0; diff --git a/arch/arm/core/mpu/arm_mpu_v8_internal.h b/arch/arm/core/mpu/arm_mpu_v8_internal.h index 1f7cb04839e..751786d5a4c 100644 --- a/arch/arm/core/mpu/arm_mpu_v8_internal.h +++ b/arch/arm/core/mpu/arm_mpu_v8_internal.h @@ -720,12 +720,7 @@ static int mpu_mark_areas_for_dynamic_regions( */ static inline uint8_t get_num_regions(void) { -#if defined(NUM_MPU_REGIONS) - /* Retrieve the number of regions from DTS configuration. */ - return NUM_MPU_REGIONS; -#else return mpu_get_num_regions(); -#endif /* NUM_MPU_REGIONS */ } /* This internal function programs the dynamic MPU regions. diff --git a/arch/arm/core/mpu/cortex_a_r/arm_mpu_internal.h b/arch/arm/core/mpu/cortex_a_r/arm_mpu_internal.h index a0f7d174436..636bce50fae 100644 --- a/arch/arm/core/mpu/cortex_a_r/arm_mpu_internal.h +++ b/arch/arm/core/mpu/cortex_a_r/arm_mpu_internal.h @@ -10,10 +10,6 @@ */ static inline uint8_t get_num_regions(void) { -#if defined(NUM_MPU_REGIONS) - /* Retrieve the number of regions from DTS configuration. */ - return NUM_MPU_REGIONS; -#else uint32_t type; __asm__ volatile("mrc p15, 0, %0, c0, c0, 4" : "=r" (type) ::); @@ -21,7 +17,6 @@ static inline uint8_t get_num_regions(void) type = (type & MPU_TYPE_DREGION_Msk) >> MPU_TYPE_DREGION_Pos; return (uint8_t)type; -#endif /* NUM_MPU_REGIONS */ } static inline uint32_t get_region_attributes(void) diff --git a/arch/arm/core/mpu/cortex_m/arm_mpu_internal.h b/arch/arm/core/mpu/cortex_m/arm_mpu_internal.h index 337f7ac3657..297eb38bf65 100644 --- a/arch/arm/core/mpu/cortex_m/arm_mpu_internal.h +++ b/arch/arm/core/mpu/cortex_m/arm_mpu_internal.h @@ -10,23 +10,11 @@ */ static inline uint8_t get_num_regions(void) { -#if defined(CONFIG_CPU_CORTEX_M0PLUS) || \ - defined(CONFIG_CPU_CORTEX_M3) || \ - defined(CONFIG_CPU_CORTEX_M4) - /* Cortex-M0+, Cortex-M3, and Cortex-M4 MCUs may - * have a fixed number of 8 MPU regions. - */ - return 8; -#elif defined(NUM_MPU_REGIONS) - /* Retrieve the number of regions from DTS configuration. */ - return NUM_MPU_REGIONS; -#else uint32_t type = MPU->TYPE; type = (type & MPU_TYPE_DREGION_Msk) >> MPU_TYPE_DREGION_Pos; return (uint8_t)type; -#endif /* CPU_CORTEX_M0PLUS | CPU_CORTEX_M3 | CPU_CORTEX_M4 */ } static inline void set_region_number(uint32_t index) diff --git a/dts/bindings/mmu_mpu/arm,armv6m-mpu.yaml b/dts/bindings/mmu_mpu/arm,armv6m-mpu.yaml index 00bc8927f58..16bdac395e4 100644 --- a/dts/bindings/mmu_mpu/arm,armv6m-mpu.yaml +++ b/dts/bindings/mmu_mpu/arm,armv6m-mpu.yaml @@ -10,8 +10,3 @@ include: base.yaml properties: reg: required: true - - arm,num-mpu-regions: - type: int - const: 8 - description: number of MPU regions supported by hardware diff --git a/dts/bindings/mmu_mpu/arm,armv7m-mpu.yaml b/dts/bindings/mmu_mpu/arm,armv7m-mpu.yaml index 09c2388a7a2..e0c6c3b4cec 100644 --- a/dts/bindings/mmu_mpu/arm,armv7m-mpu.yaml +++ b/dts/bindings/mmu_mpu/arm,armv7m-mpu.yaml @@ -7,7 +7,3 @@ include: base.yaml properties: reg: required: true - - arm,num-mpu-regions: - type: int - description: number of MPU regions supported by hardware diff --git a/dts/bindings/mmu_mpu/arm,armv8.1m-mpu.yaml b/dts/bindings/mmu_mpu/arm,armv8.1m-mpu.yaml index 407d23a8d78..7800e36d7a1 100644 --- a/dts/bindings/mmu_mpu/arm,armv8.1m-mpu.yaml +++ b/dts/bindings/mmu_mpu/arm,armv8.1m-mpu.yaml @@ -7,7 +7,3 @@ include: base.yaml properties: reg: required: true - - arm,num-mpu-regions: - type: int - description: number of MPU regions supported by hardware diff --git a/dts/bindings/mmu_mpu/arm,armv8m-mpu.yaml b/dts/bindings/mmu_mpu/arm,armv8m-mpu.yaml index 15c5085a33d..0e7c12bf1b0 100644 --- a/dts/bindings/mmu_mpu/arm,armv8m-mpu.yaml +++ b/dts/bindings/mmu_mpu/arm,armv8m-mpu.yaml @@ -7,7 +7,3 @@ include: base.yaml properties: reg: required: true - - arm,num-mpu-regions: - type: int - description: number of MPU regions supported by hardware From 48e514f66257413be633a1e1210d63fbff4465b7 Mon Sep 17 00:00:00 2001 From: Ryan McClelland Date: Sat, 28 Oct 2023 11:16:52 -0700 Subject: [PATCH 0545/3723] drivers: i3c: rename dcr i2c mode macro to lvr This renames the I2C 'DCR' mode to 'LVR' as that is the variable it should be looking at and not the dcr value. This also fixes the get 'lvr' mode argument. Signed-off-by: Ryan McClelland --- drivers/i3c/i3c_cdns.c | 8 ++++---- include/zephyr/drivers/i3c.h | 36 ++++++++++++++++++------------------ 2 files changed, 22 insertions(+), 22 deletions(-) diff --git a/drivers/i3c/i3c_cdns.c b/drivers/i3c/i3c_cdns.c index 4f99e8da886..c541f104369 100644 --- a/drivers/i3c/i3c_cdns.c +++ b/drivers/i3c/i3c_cdns.c @@ -2291,18 +2291,18 @@ static enum i3c_bus_mode i3c_bus_mode(const struct i3c_dev_list *dev_list) enum i3c_bus_mode mode = I3C_BUS_MODE_PURE; for (int i = 0; i < dev_list->num_i2c; i++) { - switch (I3C_DCR_I2C_DEV_IDX(dev_list->i2c[i].lvr)) { - case I3C_DCR_I2C_DEV_IDX_0: + switch (I3C_LVR_I2C_DEV_IDX(dev_list->i2c[i].lvr)) { + case I3C_LVR_I2C_DEV_IDX_0: if (mode < I3C_BUS_MODE_MIXED_FAST) { mode = I3C_BUS_MODE_MIXED_FAST; } break; - case I3C_DCR_I2C_DEV_IDX_1: + case I3C_LVR_I2C_DEV_IDX_1: if (mode < I3C_BUS_MODE_MIXED_LIMITED) { mode = I3C_BUS_MODE_MIXED_LIMITED; } break; - case I3C_DCR_I2C_DEV_IDX_2: + case I3C_LVR_I2C_DEV_IDX_2: if (mode < I3C_BUS_MODE_MIXED_SLOW) { mode = I3C_BUS_MODE_MIXED_SLOW; } diff --git a/include/zephyr/drivers/i3c.h b/include/zephyr/drivers/i3c.h index 04aedf8c05b..9129b15d0c3 100644 --- a/include/zephyr/drivers/i3c.h +++ b/include/zephyr/drivers/i3c.h @@ -137,7 +137,7 @@ extern "C" { /** @} */ /** - * @name Device Characteristic Register (DCR) + * @name Legacy Virtual Register (LVR) * * Legacy Virtual Register (LVR) * - LVR[7:5]: I2C device index: @@ -156,26 +156,26 @@ extern "C" { */ /** I2C FM+ Mode. */ -#define I3C_DCR_I2C_FM_PLUS_MODE 0 +#define I3C_LVR_I2C_FM_PLUS_MODE 0 /** I2C FM Mode. */ -#define I3C_DCR_I2C_FM_MODE 1 +#define I3C_LVR_I2C_FM_MODE 1 /** I2C Mode Indicator bit shift value. */ -#define I3C_DCR_I2C_MODE_SHIFT 4 +#define I3C_LVR_I2C_MODE_SHIFT 4 /** I2C Mode Indicator bitmask. */ -#define I3C_DCR_I2C_MODE_MASK BIT(4) +#define I3C_LVR_I2C_MODE_MASK BIT(4) /** * @brief I2C Mode * - * Obtain I2C Mode value from the DCR value obtained via GETDCR. + * Obtain I2C Mode value from the LVR value. * - * @param dcr DCR value + * @param lvr LVR value */ -#define I3C_DCR_I2C_MODE(dcr) \ - (((mode) & I3C_DCR_I2C_MODE_MASK) >> I3C_DCR_I2C_MODE_SHIFT) +#define I3C_LVR_I2C_MODE(lvr) \ + (((lvr) & I3C_LVR_I2C_MODE_MASK) >> I3C_LVR_I2C_MODE_SHIFT) /** * @brief I2C Device Index 0. @@ -183,7 +183,7 @@ extern "C" { * I2C device has a 50 ns spike filter where it is not affected by high * frequency on SCL. */ -#define I3C_DCR_I2C_DEV_IDX_0 0 +#define I3C_LVR_I2C_DEV_IDX_0 0 /** * @brief I2C Device Index 1. @@ -191,7 +191,7 @@ extern "C" { * I2C device does not have a 50 ns spike filter but can work with high * frequency on SCL. */ -#define I3C_DCR_I2C_DEV_IDX_1 1 +#define I3C_LVR_I2C_DEV_IDX_1 1 /** * @brief I2C Device Index 2. @@ -199,23 +199,23 @@ extern "C" { * I2C device does not have a 50 ns spike filter and cannot work with high * frequency on SCL. */ -#define I3C_DCR_I2C_DEV_IDX_2 2 +#define I3C_LVR_I2C_DEV_IDX_2 2 /** I2C Device Index bit shift value. */ -#define I3C_DCR_I2C_DEV_IDX_SHIFT 5 +#define I3C_LVR_I2C_DEV_IDX_SHIFT 5 /** I2C Device Index bitmask. */ -#define I3C_DCR_I2C_DEV_IDX_MASK (0x07U << I3C_DCR_I2C_DEV_IDX_SHIFT) +#define I3C_LVR_I2C_DEV_IDX_MASK (0x07U << I3C_LVR_I2C_DEV_IDX_SHIFT) /** * @brief I2C Device Index * - * Obtain I2C Device Index value from the DCR value obtained via GETDCR. + * Obtain I2C Device Index value from the LVR value. * - * @param dcr DCR value + * @param lvr LVR value */ -#define I3C_DCR_I2C_DEV_IDX(dcr) \ - (((dcr) & I3C_DCR_I2C_DEV_IDX_MASK) >> I3C_DCR_I2C_DEV_IDX_SHIFT) +#define I3C_LVR_I2C_DEV_IDX(lvr) \ + (((lvr) & I3C_LVR_I2C_DEV_IDX_MASK) >> I3C_LVR_I2C_DEV_IDX_SHIFT) /** @} */ From c6b935f4f8248c58c6f9d15c9f315c71bb7b69c6 Mon Sep 17 00:00:00 2001 From: Ryan McClelland Date: Mon, 13 Nov 2023 09:46:24 -0800 Subject: [PATCH 0546/3723] doc: releases: add i3c dcr/lvr rename note Add a note to the v3.6 release notes about renaming the I3C_DCR_I2C_* to I3C_LVR_I2C_*. Signed-off-by: Ryan McClelland --- doc/releases/release-notes-3.6.rst | 3 +++ 1 file changed, 3 insertions(+) diff --git a/doc/releases/release-notes-3.6.rst b/doc/releases/release-notes-3.6.rst index e8368857b9d..1fe962c0a3c 100644 --- a/doc/releases/release-notes-3.6.rst +++ b/doc/releases/release-notes-3.6.rst @@ -152,6 +152,9 @@ Drivers and Sensors * I3C + * The Legacy Virtual Register defines have been renamed from ``I3C_DCR_I2C_*`` + to ``I3C_LVR_I2C_*``. + * IEEE 802.15.4 * Interrupt Controller From c3e2be43145b71af29dd2e124123d1f2494dd174 Mon Sep 17 00:00:00 2001 From: Andries Kruithof Date: Mon, 6 Nov 2023 10:41:58 +0100 Subject: [PATCH 0547/3723] Bluetooth: audio: host: call the stream disable callback Even though the ASCS Sink ASE state machine does not enter the disabling state according to ASCS spec, it still makes sense to do so. the state transition unit tests are updated to verify calling or not calling the disable callback, depending on the transition of the state fixes #63230 Signed-off-by: Andries Kruithof --- subsys/bluetooth/audio/ascs.c | 41 +++++++++++++++++++ tests/bluetooth/audio/ascs/src/main.c | 6 +++ .../ascs/src/test_ase_state_transition.c | 32 +++++++++++++++ 3 files changed, 79 insertions(+) diff --git a/subsys/bluetooth/audio/ascs.c b/subsys/bluetooth/audio/ascs.c index e30c467df49..c20320aa411 100644 --- a/subsys/bluetooth/audio/ascs.c +++ b/subsys/bluetooth/audio/ascs.c @@ -339,6 +339,8 @@ static void ase_exit_state_streaming(struct bt_ascs_ase *ase) { struct bt_bap_stream *stream = ase->ep.stream; struct bt_bap_stream_ops *ops; + const enum bt_bap_ep_state next_state = ascs_ep_get_state(&ase->ep); + uint8_t reason = ase->ep.reason; __ASSERT_NO_MSG(stream != NULL); @@ -354,6 +356,42 @@ static void ase_exit_state_streaming(struct bt_ascs_ase *ase) } else { LOG_WRN("No callback for stopped set"); } + + /* + * On link-loss we go from streaming state to QOS configured state, + * and it makes sense to do the disabled callback before entering the + * QOS configured state + */ + if (next_state == BT_BAP_EP_STATE_QOS_CONFIGURED) { + if (ops != NULL && ops->disabled != NULL) { + ops->disabled(stream); + } else { + LOG_WRN("No callback for disabled set"); + } + } +} + +static void ase_exit_state_enabling(struct bt_ascs_ase *ase) +{ + struct bt_bap_stream *stream = ase->ep.stream; + struct bt_bap_stream_ops *ops; + const enum bt_bap_ep_state next_state = ascs_ep_get_state(&ase->ep); + + ops = stream->ops; + + /* + * When the EP direction is BT_AUDIO_DIR_SOURCE the state machine goes from + * enabled to disabled where the disabled calback will be called, + * for BT_AUDIO_DIR_SINK we go from enabled to qos_configured, + * and logically we have to do the disabled callback first + */ + if (next_state == BT_BAP_EP_STATE_QOS_CONFIGURED && ase->ep.dir == BT_AUDIO_DIR_SINK) { + if (ops != NULL && ops->disabled != NULL) { + ops->disabled(stream); + } else { + LOG_WRN("No callback for disabled set"); + } + } } static void ase_enter_state_disabling(struct bt_ascs_ase *ase) @@ -452,6 +490,9 @@ static void state_transition_work_handler(struct k_work *work) case BT_BAP_EP_STATE_STREAMING: ase_exit_state_streaming(ase); break; + case BT_BAP_EP_STATE_ENABLING: + ase_exit_state_enabling(ase); + break; default: break; } diff --git a/tests/bluetooth/audio/ascs/src/main.c b/tests/bluetooth/audio/ascs/src/main.c index 2937bd6d916..84ed14cde5a 100644 --- a/tests/bluetooth/audio/ascs/src/main.c +++ b/tests/bluetooth/audio/ascs/src/main.c @@ -500,6 +500,7 @@ ZTEST_F(ascs_test_suite, test_cis_link_loss_in_streaming_state) /* Expected to notify the upper layers */ expect_bt_bap_stream_ops_qos_set_called_once(stream); + expect_bt_bap_stream_ops_disabled_called_once(stream); expect_bt_bap_stream_ops_released_not_called(); bt_bap_unicast_server_unregister_cb(&mock_bap_unicast_server_cb); @@ -533,6 +534,9 @@ static void test_cis_link_loss_in_disabling_state(struct ascs_test_suite_fixture } test_ase_control_client_disable(conn, ase_id); + + expect_bt_bap_stream_ops_disabled_called_once(stream); + test_mocks_reset(); /* Mock CIS disconnection */ @@ -540,6 +544,7 @@ static void test_cis_link_loss_in_disabling_state(struct ascs_test_suite_fixture /* Expected to notify the upper layers */ expect_bt_bap_stream_ops_qos_set_called_once(stream); + expect_bt_bap_stream_ops_disabled_not_called(); expect_bt_bap_stream_ops_released_not_called(); bt_bap_unicast_server_unregister_cb(&mock_bap_unicast_server_cb); @@ -594,6 +599,7 @@ ZTEST_F(ascs_test_suite, test_cis_link_loss_in_enabling_state) if (IS_ENABLED(CONFIG_BT_ASCS_ASE_SNK)) { expect_bt_bap_stream_ops_qos_set_called_once(stream); + expect_bt_bap_stream_ops_disabled_called_once(stream); } else { /* Server-initiated disable operation that shall not cause transition to QoS */ expect_bt_bap_stream_ops_qos_set_not_called(); diff --git a/tests/bluetooth/audio/ascs/src/test_ase_state_transition.c b/tests/bluetooth/audio/ascs/src/test_ase_state_transition.c index d29175b6c73..4f7914b1f23 100644 --- a/tests/bluetooth/audio/ascs/src/test_ase_state_transition.c +++ b/tests/bluetooth/audio/ascs/src/test_ase_state_transition.c @@ -106,6 +106,7 @@ ZTEST_F(test_sink_ase_state_transition, test_client_codec_configured_to_qos_conf /* Verification */ expect_bt_bap_unicast_server_cb_qos_called_once(stream, EMPTY); expect_bt_bap_stream_ops_qos_set_called_once(stream); + expect_bt_bap_stream_ops_disabled_not_called(); } ZTEST_F(test_sink_ase_state_transition, test_client_qos_configured_to_enabling) @@ -140,6 +141,7 @@ ZTEST_F(test_sink_ase_state_transition, test_client_enabling_to_qos_configured) /* Verification */ expect_bt_bap_unicast_server_cb_disable_called_once(stream); expect_bt_bap_stream_ops_qos_set_called_once(stream); + expect_bt_bap_stream_ops_disabled_called_once(stream); } ZTEST_F(test_sink_ase_state_transition, test_client_qos_configured_to_releasing) @@ -192,6 +194,7 @@ ZTEST_F(test_sink_ase_state_transition, test_client_qos_configured_to_qos_config /* Verification */ expect_bt_bap_unicast_server_cb_qos_called_once(stream, EMPTY); expect_bt_bap_stream_ops_qos_set_called_once(stream); + expect_bt_bap_stream_ops_disabled_not_called(); } ZTEST_F(test_sink_ase_state_transition, test_client_qos_configured_to_codec_configured) @@ -243,6 +246,7 @@ ZTEST_F(test_sink_ase_state_transition, test_client_enabling_to_releasing) /* Verification */ expect_bt_bap_unicast_server_cb_release_called_once(stream); expect_bt_bap_stream_ops_released_called_once(stream); + expect_bt_bap_stream_ops_disabled_not_called(); } ZTEST_F(test_sink_ase_state_transition, test_client_enabling_to_enabling) @@ -260,6 +264,7 @@ ZTEST_F(test_sink_ase_state_transition, test_client_enabling_to_enabling) /* Verification */ expect_bt_bap_unicast_server_cb_metadata_called_once(stream, EMPTY, EMPTY); expect_bt_bap_stream_ops_metadata_updated_called_once(stream); + expect_bt_bap_stream_ops_disabled_not_called(); } ZTEST_F(test_sink_ase_state_transition, test_client_streaming_to_releasing) @@ -282,6 +287,7 @@ ZTEST_F(test_sink_ase_state_transition, test_client_streaming_to_releasing) expect_bt_bap_unicast_server_cb_release_called_once(stream); expect_bt_bap_stream_ops_stopped_called_once(stream, BT_HCI_ERR_REMOTE_USER_TERM_CONN); expect_bt_bap_stream_ops_released_called_once(stream); + expect_bt_bap_stream_ops_disabled_not_called(); } ZTEST_F(test_sink_ase_state_transition, test_client_streaming_to_streaming) @@ -300,6 +306,7 @@ ZTEST_F(test_sink_ase_state_transition, test_client_streaming_to_streaming) /* Verification */ expect_bt_bap_unicast_server_cb_metadata_called_once(stream, EMPTY, EMPTY); expect_bt_bap_stream_ops_metadata_updated_called_once(stream); + expect_bt_bap_stream_ops_disabled_not_called(); } ZTEST_F(test_sink_ase_state_transition, test_client_streaming_to_qos_configured) @@ -319,6 +326,7 @@ ZTEST_F(test_sink_ase_state_transition, test_client_streaming_to_qos_configured) expect_bt_bap_unicast_server_cb_disable_called_once(stream); expect_bt_bap_stream_ops_stopped_called_once(stream, BT_HCI_ERR_REMOTE_USER_TERM_CONN); expect_bt_bap_stream_ops_qos_set_called_once(stream); + expect_bt_bap_stream_ops_disabled_called_once(stream); } ZTEST_F(test_sink_ase_state_transition, test_server_idle_to_codec_configured) @@ -436,6 +444,7 @@ ZTEST_F(test_sink_ase_state_transition, test_server_enabling_to_releasing) /* Verification */ expect_bt_bap_unicast_server_cb_release_called_once(stream); expect_bt_bap_stream_ops_released_called_once(stream); + expect_bt_bap_stream_ops_disabled_not_called(); } ZTEST_F(test_sink_ase_state_transition, test_server_enabling_to_enabling) @@ -459,6 +468,7 @@ ZTEST_F(test_sink_ase_state_transition, test_server_enabling_to_enabling) /* Verification */ expect_bt_bap_unicast_server_cb_metadata_called_once(stream, EMPTY, EMPTY); expect_bt_bap_stream_ops_metadata_updated_called_once(stream); + expect_bt_bap_stream_ops_disabled_not_called(); } ZTEST_F(test_sink_ase_state_transition, test_server_enabling_to_qos_configured) @@ -478,6 +488,7 @@ ZTEST_F(test_sink_ase_state_transition, test_server_enabling_to_qos_configured) /* Verification */ expect_bt_bap_unicast_server_cb_disable_called_once(stream); expect_bt_bap_stream_ops_qos_set_called_once(stream); + expect_bt_bap_stream_ops_disabled_called_once(stream); } ZTEST_F(test_sink_ase_state_transition, test_server_enabling_to_streaming) @@ -500,6 +511,7 @@ ZTEST_F(test_sink_ase_state_transition, test_server_enabling_to_streaming) /* Verification */ expect_bt_bap_stream_ops_started_called_once(stream); + expect_bt_bap_stream_ops_disabled_not_called(); /* XXX: unicast_server_cb->start is not called for Sink ASE */ } @@ -525,6 +537,7 @@ ZTEST_F(test_sink_ase_state_transition, test_server_streaming_to_streaming) /* Verification */ expect_bt_bap_unicast_server_cb_metadata_called_once(stream, EMPTY, EMPTY); expect_bt_bap_stream_ops_metadata_updated_called_once(stream); + expect_bt_bap_stream_ops_disabled_not_called(); } ZTEST_F(test_sink_ase_state_transition, test_server_streaming_to_qos_configured) @@ -546,6 +559,7 @@ ZTEST_F(test_sink_ase_state_transition, test_server_streaming_to_qos_configured) expect_bt_bap_unicast_server_cb_disable_called_once(stream); expect_bt_bap_stream_ops_stopped_called_once(stream, BT_HCI_ERR_LOCALHOST_TERM_CONN); expect_bt_bap_stream_ops_qos_set_called_once(stream); + expect_bt_bap_stream_ops_disabled_called_once(stream); } ZTEST_F(test_sink_ase_state_transition, test_server_streaming_to_releasing) @@ -570,6 +584,7 @@ ZTEST_F(test_sink_ase_state_transition, test_server_streaming_to_releasing) expect_bt_bap_unicast_server_cb_release_called_once(stream); expect_bt_bap_stream_ops_stopped_called_once(stream, BT_HCI_ERR_LOCALHOST_TERM_CONN); expect_bt_bap_stream_ops_released_called_once(stream); + expect_bt_bap_stream_ops_disabled_not_called(); } static void *test_source_ase_state_transition_setup(void) @@ -623,6 +638,7 @@ ZTEST_F(test_source_ase_state_transition, test_client_codec_configured_to_qos_co /* Verification */ expect_bt_bap_unicast_server_cb_qos_called_once(stream, EMPTY); expect_bt_bap_stream_ops_qos_set_called_once(stream); + expect_bt_bap_stream_ops_disabled_not_called(); } ZTEST_F(test_source_ase_state_transition, test_client_qos_configured_to_enabling) @@ -696,6 +712,7 @@ ZTEST_F(test_source_ase_state_transition, test_client_enabling_to_streaming) /* Verification */ expect_bt_bap_unicast_server_cb_start_called_once(stream); expect_bt_bap_stream_ops_started_called_once(stream); + expect_bt_bap_stream_ops_disabled_not_called(); } ZTEST_F(test_source_ase_state_transition, test_client_codec_configured_to_codec_configured) @@ -730,6 +747,7 @@ ZTEST_F(test_source_ase_state_transition, test_client_qos_configured_to_qos_conf /* Verification */ expect_bt_bap_unicast_server_cb_qos_called_once(stream, EMPTY); expect_bt_bap_stream_ops_qos_set_called_once(stream); + expect_bt_bap_stream_ops_disabled_not_called(); } ZTEST_F(test_source_ase_state_transition, test_client_qos_configured_to_codec_configured) @@ -781,6 +799,7 @@ ZTEST_F(test_source_ase_state_transition, test_client_enabling_to_releasing) /* Verification */ expect_bt_bap_unicast_server_cb_release_called_once(stream); expect_bt_bap_stream_ops_released_called_once(stream); + expect_bt_bap_stream_ops_disabled_not_called(); } ZTEST_F(test_source_ase_state_transition, test_client_enabling_to_enabling) @@ -798,6 +817,7 @@ ZTEST_F(test_source_ase_state_transition, test_client_enabling_to_enabling) /* Verification */ expect_bt_bap_unicast_server_cb_metadata_called_once(stream, EMPTY, EMPTY); expect_bt_bap_stream_ops_metadata_updated_called_once(stream); + expect_bt_bap_stream_ops_disabled_not_called(); } ZTEST_F(test_source_ase_state_transition, test_client_streaming_to_releasing) @@ -820,6 +840,7 @@ ZTEST_F(test_source_ase_state_transition, test_client_streaming_to_releasing) expect_bt_bap_unicast_server_cb_release_called_once(stream); expect_bt_bap_stream_ops_stopped_called_once(stream, BT_HCI_ERR_REMOTE_USER_TERM_CONN); expect_bt_bap_stream_ops_released_called_once(stream); + expect_bt_bap_stream_ops_disabled_not_called(); } ZTEST_F(test_source_ase_state_transition, test_client_streaming_to_streaming) @@ -838,6 +859,7 @@ ZTEST_F(test_source_ase_state_transition, test_client_streaming_to_streaming) /* Verification */ expect_bt_bap_unicast_server_cb_metadata_called_once(stream, EMPTY, EMPTY); expect_bt_bap_stream_ops_metadata_updated_called_once(stream); + expect_bt_bap_stream_ops_disabled_not_called(); } ZTEST_F(test_source_ase_state_transition, test_client_streaming_to_disabling) @@ -869,6 +891,8 @@ ZTEST_F(test_source_ase_state_transition, test_client_enabling_to_disabling_to_q test_preamble_state_enabling(conn, ase_id, stream); test_ase_control_client_disable(conn, ase_id); + expect_bt_bap_stream_ops_disabled_called_once(stream); + test_mocks_reset(); test_ase_control_client_receiver_stop_ready(conn, ase_id); @@ -876,6 +900,7 @@ ZTEST_F(test_source_ase_state_transition, test_client_enabling_to_disabling_to_q /* Verification */ expect_bt_bap_unicast_server_cb_stop_called_once(stream); expect_bt_bap_stream_ops_qos_set_called_once(stream); + expect_bt_bap_stream_ops_disabled_not_called(); } ZTEST_F(test_source_ase_state_transition, test_client_streaming_to_disabling_to_qos_configured) @@ -891,8 +916,10 @@ ZTEST_F(test_source_ase_state_transition, test_client_streaming_to_disabling_to_ test_ase_control_client_disable(conn, ase_id); /* Verify that stopped callback was called by disable */ + expect_bt_bap_stream_ops_disabled_called_once(stream); expect_bt_bap_stream_ops_stopped_called_once(stream, BT_HCI_ERR_REMOTE_USER_TERM_CONN); + test_mocks_reset(); test_ase_control_client_receiver_stop_ready(conn, ase_id); @@ -900,6 +927,7 @@ ZTEST_F(test_source_ase_state_transition, test_client_streaming_to_disabling_to_ /* Verification */ expect_bt_bap_unicast_server_cb_stop_called_once(stream); expect_bt_bap_stream_ops_qos_set_called_once(stream); + expect_bt_bap_stream_ops_disabled_not_called(); } ZTEST_F(test_source_ase_state_transition, test_server_idle_to_codec_configured) @@ -1017,6 +1045,7 @@ ZTEST_F(test_source_ase_state_transition, test_server_enabling_to_releasing) /* Verification */ expect_bt_bap_unicast_server_cb_release_called_once(stream); expect_bt_bap_stream_ops_released_called_once(stream); + expect_bt_bap_stream_ops_disabled_not_called(); } ZTEST_F(test_source_ase_state_transition, test_server_enabling_to_enabling) @@ -1040,6 +1069,7 @@ ZTEST_F(test_source_ase_state_transition, test_server_enabling_to_enabling) /* Verification */ expect_bt_bap_unicast_server_cb_metadata_called_once(stream, EMPTY, EMPTY); expect_bt_bap_stream_ops_metadata_updated_called_once(stream); + expect_bt_bap_stream_ops_disabled_not_called(); } ZTEST_F(test_source_ase_state_transition, test_server_enabling_to_disabling) @@ -1083,6 +1113,7 @@ ZTEST_F(test_source_ase_state_transition, test_server_streaming_to_streaming) /* Verification */ expect_bt_bap_unicast_server_cb_metadata_called_once(stream, EMPTY, EMPTY); expect_bt_bap_stream_ops_metadata_updated_called_once(stream); + expect_bt_bap_stream_ops_disabled_not_called(); } ZTEST_F(test_source_ase_state_transition, test_server_streaming_to_disabling) @@ -1128,4 +1159,5 @@ ZTEST_F(test_source_ase_state_transition, test_server_streaming_to_releasing) expect_bt_bap_unicast_server_cb_release_called_once(stream); expect_bt_bap_stream_ops_stopped_called_once(stream, BT_HCI_ERR_LOCALHOST_TERM_CONN); expect_bt_bap_stream_ops_released_called_once(stream); + expect_bt_bap_stream_ops_disabled_not_called(); } From 4b1a8cb95b99eb62e1bcf20809a97e518491e26b Mon Sep 17 00:00:00 2001 From: Pieter De Gendt Date: Wed, 8 Nov 2023 14:45:25 +0100 Subject: [PATCH 0548/3723] modules: nanopb: Add custom target for generated header files Nanopb generates header files that need to be available before being included. This isn't an issue for a target where the files were added with zephyr_nanopb_sources. But if another target wants to include these generated files we need a cmake dependency chain. The nanopb_generated_headers custom target been added for this purpose. Signed-off-by: Pieter De Gendt --- modules/nanopb/nanopb.cmake | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/modules/nanopb/nanopb.cmake b/modules/nanopb/nanopb.cmake index 24263c825e4..5158090aae9 100644 --- a/modules/nanopb/nanopb.cmake +++ b/modules/nanopb/nanopb.cmake @@ -15,6 +15,8 @@ else() message(STATUS "Found protoc: ${PROTOBUF_PROTOC_EXECUTABLE}") endif() +add_custom_target(nanopb_generated_headers) + # Usage: # list(APPEND CMAKE_MODULE_PATH ${ZEPHYR_BASE}/modules/nanopb) # include(nanopb) @@ -31,4 +33,11 @@ function(zephyr_nanopb_sources target) target_include_directories(${target} PUBLIC ${CMAKE_CURRENT_BINARY_DIR}) target_sources(${target} PRIVATE ${proto_srcs} ${proto_hdrs}) + + # Create unique target name for generated header list + string(MD5 unique_chars "${proto_hdrs}") + set(gen_target_name ${target}_proto_${unique_chars}) + + add_custom_target(${gen_target_name} DEPENDS ${proto_hdrs}) + add_dependencies(nanopb_generated_headers ${gen_target_name}) endfunction() From e816fc5a81c2058dc0670ec11b301f38403e29fd Mon Sep 17 00:00:00 2001 From: Pieter De Gendt Date: Wed, 8 Nov 2023 14:56:32 +0100 Subject: [PATCH 0549/3723] tests: modules: nanopb: Add a custom nested library Add a library to the Nanopb test to demonstrate building with a dependency on the generated header files. Signed-off-by: Pieter De Gendt --- tests/modules/nanopb/CMakeLists.txt | 5 +++++ tests/modules/nanopb/lib/CMakeLists.txt | 12 ++++++++++++ tests/modules/nanopb/lib/lib.c | 15 +++++++++++++++ tests/modules/nanopb/lib/lib.h | 17 +++++++++++++++++ tests/modules/nanopb/src/main.c | 13 +++++++++++++ 5 files changed, 62 insertions(+) create mode 100644 tests/modules/nanopb/lib/CMakeLists.txt create mode 100644 tests/modules/nanopb/lib/lib.c create mode 100644 tests/modules/nanopb/lib/lib.h diff --git a/tests/modules/nanopb/CMakeLists.txt b/tests/modules/nanopb/CMakeLists.txt index bbe95de0bf2..702958aeaad 100644 --- a/tests/modules/nanopb/CMakeLists.txt +++ b/tests/modules/nanopb/CMakeLists.txt @@ -17,3 +17,8 @@ zephyr_nanopb_sources(app FILE(GLOB app_sources src/*.c) target_sources(app PRIVATE ${app_sources}) + +# Process our own library +add_subdirectory(lib) +target_include_directories(app PRIVATE lib) +target_link_libraries(app PRIVATE mylib) diff --git a/tests/modules/nanopb/lib/CMakeLists.txt b/tests/modules/nanopb/lib/CMakeLists.txt new file mode 100644 index 00000000000..8de22b17f82 --- /dev/null +++ b/tests/modules/nanopb/lib/CMakeLists.txt @@ -0,0 +1,12 @@ +# SPDX-License-Identifier: Apache-2.0 + +add_library(mylib lib.c) + +# Demonstrate that our library includes a generated header so we need the following dependency +add_dependencies(mylib nanopb_generated_headers) + +# Add include directory to find the generated headers +target_include_directories(mylib PRIVATE ${CMAKE_BINARY_DIR}) + +# Link against zephyr +target_link_libraries(mylib zephyr) diff --git a/tests/modules/nanopb/lib/lib.c b/tests/modules/nanopb/lib/lib.c new file mode 100644 index 00000000000..083ae25ef05 --- /dev/null +++ b/tests/modules/nanopb/lib/lib.c @@ -0,0 +1,15 @@ +/* + * Copyright (c) 2023 Basalte bv + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include "lib.h" + +void lib_fill_message(SimpleMessage *msg) +{ + /* Reversed numbers */ + for (size_t i = 0; i < sizeof(msg->buffer); ++i) { + msg->buffer[i] = sizeof(msg->buffer) - i; + } +} diff --git a/tests/modules/nanopb/lib/lib.h b/tests/modules/nanopb/lib/lib.h new file mode 100644 index 00000000000..7193d1f5912 --- /dev/null +++ b/tests/modules/nanopb/lib/lib.h @@ -0,0 +1,17 @@ +/* + * Copyright (c) 2023 Basalte bv + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#ifndef __LIB_H_ +#define __LIB_H_ + +#include + +/** + * Some sample library function that fills a SimpleMessage struct + */ +void lib_fill_message(SimpleMessage *msg); + +#endif diff --git a/tests/modules/nanopb/src/main.c b/tests/modules/nanopb/src/main.c index cd68298960e..798b11e6f16 100644 --- a/tests/modules/nanopb/src/main.c +++ b/tests/modules/nanopb/src/main.c @@ -14,6 +14,8 @@ #include #include +#include "lib.h" + ZTEST(nanopb_tests, test_nanopb_simple) { uint8_t buffer[SimpleMessage_size]; @@ -68,4 +70,15 @@ ZTEST(nanopb_tests, test_nanopb_nested) zassert_equal(0, strcmp(msg.nested.name, "Test name")); } +ZTEST(nanopb_tests, test_nanopb_lib) +{ + SimpleMessage msg = SimpleMessage_init_zero; + + lib_fill_message(&msg); + + for (size_t i = 0; i < sizeof(msg.buffer); ++i) { + zassert_equal(msg.buffer[i], sizeof(msg.buffer) - i); + } +} + ZTEST_SUITE(nanopb_tests, NULL, NULL, NULL, NULL, NULL); From 640b6911d6d31286bc009d4b25b12e87bfffe7f5 Mon Sep 17 00:00:00 2001 From: Benedikt Schmidt Date: Wed, 8 Nov 2023 16:36:28 +0100 Subject: [PATCH 0550/3723] drivers: adc: improve logging of ADS114s0x Improve the logging of the ADC driver ADS114s0x. Signed-off-by: Benedikt Schmidt --- drivers/adc/adc_ads114s0x.c | 168 +++++++++++++++++++----------------- 1 file changed, 90 insertions(+), 78 deletions(-) diff --git a/drivers/adc/adc_ads114s0x.c b/drivers/adc/adc_ads114s0x.c index e5ab699bcbd..8e95e79c79c 100644 --- a/drivers/adc/adc_ads114s0x.c +++ b/drivers/adc/adc_ads114s0x.c @@ -442,9 +442,10 @@ static void ads114s0x_data_ready_handler(const struct device *dev, struct gpio_c k_sem_give(&data->data_ready_signal); } -static int ads114s0x_read_register(const struct spi_dt_spec *bus, +static int ads114s0x_read_register(const struct device *dev, enum ads114s0x_register register_address, uint8_t *value) { + const struct ads114s0x_config *config = dev->config; uint8_t buffer_tx[3]; uint8_t buffer_rx[ARRAY_SIZE(buffer_tx)]; const struct spi_buf tx_buf[] = {{ @@ -468,22 +469,23 @@ static int ads114s0x_read_register(const struct spi_dt_spec *bus, /* read one register */ buffer_tx[1] = 0x00; - int result = spi_transceive_dt(bus, &tx, &rx); + int result = spi_transceive_dt(&config->bus, &tx, &rx); if (result != 0) { - LOG_ERR("spi_transceive failed with error %i", result); + LOG_ERR("%s: spi_transceive failed with error %i", dev->name, result); return result; } *value = buffer_rx[2]; - LOG_DBG("read from register 0x%02X value 0x%02X", register_address, *value); + LOG_DBG("%s: read from register 0x%02X value 0x%02X", dev->name, register_address, *value); return 0; } -static int ads114s0x_write_register(const struct spi_dt_spec *bus, +static int ads114s0x_write_register(const struct device *dev, enum ads114s0x_register register_address, uint8_t value) { + const struct ads114s0x_config *config = dev->config; uint8_t buffer_tx[3]; const struct spi_buf tx_buf[] = {{ .buf = buffer_tx, @@ -499,21 +501,22 @@ static int ads114s0x_write_register(const struct spi_dt_spec *bus, buffer_tx[1] = 0x00; buffer_tx[2] = value; - LOG_DBG("writing to register 0x%02X value 0x%02X", register_address, value); - int result = spi_write_dt(bus, &tx); + LOG_DBG("%s: writing to register 0x%02X value 0x%02X", dev->name, register_address, value); + int result = spi_write_dt(&config->bus, &tx); if (result != 0) { - LOG_ERR("spi_write failed with error %i", result); + LOG_ERR("%s: spi_write failed with error %i", dev->name, result); return result; } return 0; } -static int ads114s0x_write_multiple_registers(const struct spi_dt_spec *bus, +static int ads114s0x_write_multiple_registers(const struct device *dev, enum ads114s0x_register *register_addresses, uint8_t *values, size_t count) { + const struct ads114s0x_config *config = dev->config; uint8_t buffer_tx[2]; const struct spi_buf tx_buf[] = { { @@ -531,7 +534,7 @@ static int ads114s0x_write_multiple_registers(const struct spi_dt_spec *bus, }; if (count == 0) { - LOG_WRN("ignoring the command to write 0 registers"); + LOG_WRN("%s: ignoring the command to write 0 registers", dev->name); return -EINVAL; } @@ -547,18 +550,19 @@ static int ads114s0x_write_multiple_registers(const struct spi_dt_spec *bus, "register addresses are not consecutive"); } - int result = spi_write_dt(bus, &tx); + int result = spi_write_dt(&config->bus, &tx); if (result != 0) { - LOG_ERR("spi_write failed with error %i", result); + LOG_ERR("%s: spi_write failed with error %i", dev->name, result); return result; } return 0; } -static int ads114s0x_send_command(const struct spi_dt_spec *bus, enum ads114s0x_command command) +static int ads114s0x_send_command(const struct device *dev, enum ads114s0x_command command) { + const struct ads114s0x_config *config = dev->config; uint8_t buffer_tx[1]; const struct spi_buf tx_buf[] = {{ .buf = buffer_tx, @@ -571,11 +575,11 @@ static int ads114s0x_send_command(const struct spi_dt_spec *bus, enum ads114s0x_ buffer_tx[0] = (uint8_t)command; - LOG_DBG("sending command 0x%02X", command); - int result = spi_write_dt(bus, &tx); + LOG_DBG("%s: sending command 0x%02X", dev->name, command); + int result = spi_write_dt(&config->bus, &tx); if (result != 0) { - LOG_ERR("spi_write failed with error %i", result); + LOG_ERR("%s: spi_write failed with error %i", dev->name, result); return result; } @@ -608,7 +612,7 @@ static int ads114s0x_channel_setup(const struct device *dev, ADS114S0X_REGISTER_IDACMUX_SET_DEFAULTS(idac_mux); if (channel_cfg->channel_id != 0) { - LOG_ERR("only one channel is supported"); + LOG_ERR("%s: only one channel is supported", dev->name); return -EINVAL; } @@ -619,7 +623,8 @@ static int ads114s0x_channel_setup(const struct device *dev, */ if (channel_cfg->acquisition_time != ADC_ACQ_TIME_DEFAULT && acquisition_time_unit != ADC_ACQ_TIME_TICKS) { - LOG_ERR("invalid acquisition time %i", channel_cfg->acquisition_time); + LOG_ERR("%s: invalid acquisition time %i", dev->name, + channel_cfg->acquisition_time); return -EINVAL; } @@ -655,25 +660,29 @@ static int ads114s0x_channel_setup(const struct device *dev, ADS114S0X_REGISTER_REF_REFSEL_SET(reference_control, 0b01); break; default: - LOG_ERR("reference %i is not supported", channel_cfg->reference); + LOG_ERR("%s: reference %i is not supported", dev->name, channel_cfg->reference); return -EINVAL; } if (channel_cfg->differential) { + LOG_DBG("%s: configuring channel for a differential measurement from the pins (p, " + "n) (%i, %i)", + dev->name, channel_cfg->input_positive, channel_cfg->input_negative); if (channel_cfg->input_positive >= ADS114S0X_INPUT_SELECTION_AINCOM) { - LOG_ERR("positive channel input %i is invalid", + LOG_ERR("%s: positive channel input %i is invalid", dev->name, channel_cfg->input_positive); return -EINVAL; } if (channel_cfg->input_negative >= ADS114S0X_INPUT_SELECTION_AINCOM) { - LOG_ERR("negative channel input %i is invalid", + LOG_ERR("%s: negative channel input %i is invalid", dev->name, channel_cfg->input_negative); return -EINVAL; } if (channel_cfg->input_positive == channel_cfg->input_negative) { - LOG_ERR("negative and positive channel inputs must be different"); + LOG_ERR("%s: negative and positive channel inputs must be different", + dev->name); return -EINVAL; } @@ -682,8 +691,11 @@ static int ads114s0x_channel_setup(const struct device *dev, pin_selections[0] = channel_cfg->input_positive; pin_selections[1] = channel_cfg->input_negative; } else { + LOG_DBG("%s: configuring channel for single ended measurement from input %i", + dev->name, channel_cfg->input_positive); if (channel_cfg->input_positive >= ADS114S0X_INPUT_SELECTION_AINCOM) { - LOG_ERR("channel input %i is invalid", channel_cfg->input_positive); + LOG_ERR("%s: channel input %i is invalid", dev->name, + channel_cfg->input_positive); return -EINVAL; } @@ -720,7 +732,7 @@ static int ads114s0x_channel_setup(const struct device *dev, ADS114S0X_REGISTER_PGA_GAIN_SET(gain, 0b111); break; default: - LOG_ERR("gain value %i not supported", channel_cfg->gain); + LOG_ERR("%s: gain value %i not supported", dev->name, channel_cfg->gain); return -EINVAL; } @@ -761,19 +773,21 @@ static int ads114s0x_channel_setup(const struct device *dev, ADS114S0X_REGISTER_IDACMAG_IMAG_SET(idac_magnitude, 0b1001); break; default: - LOG_ERR("IDAC magnitude %i not supported", config->idac_current); + LOG_ERR("%s: IDAC magnitude %i not supported", dev->name, config->idac_current); return -EINVAL; } if (channel_cfg->current_source_pin_set) { + LOG_DBG("%s: current source pin set to %i and %i", dev->name, + channel_cfg->current_source_pin[0], channel_cfg->current_source_pin[1]); if (channel_cfg->current_source_pin[0] > 0b1111) { - LOG_ERR("invalid selection %i for I1MUX", + LOG_ERR("%s: invalid selection %i for I1MUX", dev->name, channel_cfg->current_source_pin[0]); return -EINVAL; } if (channel_cfg->current_source_pin[1] > 0b1111) { - LOG_ERR("invalid selection %i for I2MUX", + LOG_ERR("%s: invalid selection %i for I2MUX", dev->name, channel_cfg->current_source_pin[1]); return -EINVAL; } @@ -784,6 +798,7 @@ static int ads114s0x_channel_setup(const struct device *dev, pin_selections[3] = channel_cfg->current_source_pin[1]; pin_selections_size = 4; } else { + LOG_DBG("%s: current source pins not set", dev->name); pin_selections_size = 2; } @@ -798,7 +813,8 @@ static int ads114s0x_channel_setup(const struct device *dev, } if (pin_selections[i] == pin_selections[j]) { - LOG_ERR("pins for inputs and current sources must be different"); + LOG_ERR("%s: pins for inputs and current sources must be different", + dev->name); return -EINVAL; } } @@ -819,11 +835,11 @@ static int ads114s0x_channel_setup(const struct device *dev, values[5] = idac_mux; BUILD_ASSERT(ARRAY_SIZE(values) == 6); - result = ads114s0x_write_multiple_registers(&config->bus, register_addresses, values, + result = ads114s0x_write_multiple_registers(dev, register_addresses, values, ARRAY_SIZE(values)); if (result != 0) { - LOG_ERR("unable to configure registers"); + LOG_ERR("%s: unable to configure registers", dev->name); return result; } @@ -849,17 +865,17 @@ static int ads114s0x_validate_sequence(const struct device *dev, const struct adc_sequence *sequence) { if (sequence->resolution != ADS114S0X_RESOLUTION) { - LOG_ERR("invalid resolution"); + LOG_ERR("%s: invalid resolution", dev->name); return -EINVAL; } if (sequence->channels != BIT(0)) { - LOG_ERR("invalid channel"); + LOG_ERR("%s: invalid channel", dev->name); return -EINVAL; } if (sequence->oversampling) { - LOG_ERR("oversampling is not supported"); + LOG_ERR("%s: oversampling is not supported", dev->name); return -EINVAL; } @@ -892,7 +908,7 @@ static int ads114s0x_adc_start_read(const struct device *dev, const struct adc_s result = ads114s0x_validate_sequence(dev, sequence); if (result != 0) { - LOG_ERR("sequence validation failed"); + LOG_ERR("%s: sequence validation failed", dev->name); return result; } @@ -913,16 +929,16 @@ static int ads114s0x_send_start_read(const struct device *dev) int result; if (config->gpio_start_sync.port == 0) { - result = ads114s0x_send_command(&config->bus, ADS114S0X_COMMAND_START); + result = ads114s0x_send_command(dev, ADS114S0X_COMMAND_START); if (result != 0) { - LOG_ERR("unable to send START/SYNC command"); + LOG_ERR("%s: unable to send START/SYNC command", dev->name); return result; } } else { result = gpio_pin_set_dt(&config->gpio_start_sync, 1); if (result != 0) { - LOG_ERR("unable to start ADC operation"); + LOG_ERR("%s: unable to start ADC operation", dev->name); return result; } @@ -932,7 +948,7 @@ static int ads114s0x_send_start_read(const struct device *dev) result = gpio_pin_set_dt(&config->gpio_start_sync, 0); if (result != 0) { - LOG_ERR("unable to start ADC operation"); + LOG_ERR("%s: unable to start ADC operation", dev->name); return result; } } @@ -974,11 +990,12 @@ static int ads114s0x_read_sample(const struct device *dev, uint16_t *buffer) int result = spi_transceive_dt(&config->bus, &tx, &rx); if (result != 0) { - LOG_ERR("spi_transceive failed with error %i", result); + LOG_ERR("%s: spi_transceive failed with error %i", dev->name, result); return result; } *buffer = sys_get_be16(buffer_rx + 1); + LOG_DBG("%s: read ADC sample %i", dev->name, *buffer); return 0; } @@ -992,21 +1009,21 @@ static int ads114s0x_adc_perform_read(const struct device *dev) result = ads114s0x_send_start_read(dev); if (result != 0) { - LOG_ERR("unable to start ADC conversion"); + LOG_ERR("%s: unable to start ADC conversion", dev->name); adc_context_complete(&data->ctx, result); return result; } result = ads114s0x_wait_data_ready(dev); if (result != 0) { - LOG_ERR("waiting for data to be ready failed"); + LOG_ERR("%s: waiting for data to be ready failed", dev->name); adc_context_complete(&data->ctx, result); return result; } result = ads114s0x_read_sample(dev, data->buffer); if (result != 0) { - LOG_ERR("reading sample failed"); + LOG_ERR("%s: reading sample failed", dev->name); adc_context_complete(&data->ctx, result); return result; } @@ -1079,7 +1096,6 @@ static void ads114s0x_acquisition_thread(void *p1, void *p2, void *p3) static int ads114s0x_gpio_write_config(const struct device *dev) { struct ads114s0x_data *data = dev->data; - const struct ads114s0x_config *config = dev->config; enum ads114s0x_register register_addresses[2]; uint8_t register_values[ARRAY_SIZE(register_addresses)]; uint8_t gpio_dat = 0; @@ -1093,20 +1109,19 @@ static int ads114s0x_gpio_write_config(const struct device *dev) register_values[1] = gpio_con; register_addresses[0] = ADS114S0X_REGISTER_GPIODAT; register_addresses[1] = ADS114S0X_REGISTER_GPIOCON; - return ads114s0x_write_multiple_registers(&config->bus, register_addresses, register_values, + return ads114s0x_write_multiple_registers(dev, register_addresses, register_values, ARRAY_SIZE(register_values)); } static int ads114s0x_gpio_write_value(const struct device *dev) { struct ads114s0x_data *data = dev->data; - const struct ads114s0x_config *config = dev->config; uint8_t gpio_dat = 0; ADS114S0X_REGISTER_GPIODAT_DAT_SET(gpio_dat, data->gpio_value); ADS114S0X_REGISTER_GPIODAT_DIR_SET(gpio_dat, data->gpio_direction); - return ads114s0x_write_register(&config->bus, ADS114S0X_REGISTER_GPIODAT, gpio_dat); + return ads114s0x_write_register(dev, ADS114S0X_REGISTER_GPIODAT, gpio_dat); } int ads114s0x_gpio_set_output(const struct device *dev, uint8_t pin, bool initial_value) @@ -1115,7 +1130,7 @@ int ads114s0x_gpio_set_output(const struct device *dev, uint8_t pin, bool initia int result = 0; if (pin > ADS114S0X_GPIO_MAX) { - LOG_ERR("invalid pin %i", pin); + LOG_ERR("%s: invalid pin %i", dev->name, pin); return -EINVAL; } @@ -1143,7 +1158,7 @@ int ads114s0x_gpio_set_input(const struct device *dev, uint8_t pin) int result = 0; if (pin > ADS114S0X_GPIO_MAX) { - LOG_ERR("invalid pin %i", pin); + LOG_ERR("%s: invalid pin %i", dev->name, pin); return -EINVAL; } @@ -1166,7 +1181,7 @@ int ads114s0x_gpio_deconfigure(const struct device *dev, uint8_t pin) int result = 0; if (pin > ADS114S0X_GPIO_MAX) { - LOG_ERR("invalid pin %i", pin); + LOG_ERR("%s: invalid pin %i", dev->name, pin); return -EINVAL; } @@ -1189,17 +1204,17 @@ int ads114s0x_gpio_set_pin_value(const struct device *dev, uint8_t pin, bool val int result = 0; if (pin > ADS114S0X_GPIO_MAX) { - LOG_ERR("invalid pin %i", pin); + LOG_ERR("%s: invalid pin %i", dev->name, pin); return -EINVAL; } k_mutex_lock(&data->gpio_lock, K_FOREVER); if ((BIT(pin) & data->gpio_enabled) == 0) { - LOG_ERR("gpio pin %i not configured", pin); + LOG_ERR("%s: gpio pin %i not configured", dev->name, pin); result = -EINVAL; } else if ((BIT(pin) & data->gpio_direction) != 0) { - LOG_ERR("gpio pin %i not configured as output", pin); + LOG_ERR("%s: gpio pin %i not configured as output", dev->name, pin); result = -EINVAL; } else { data->gpio_value |= BIT(pin); @@ -1215,26 +1230,24 @@ int ads114s0x_gpio_set_pin_value(const struct device *dev, uint8_t pin, bool val int ads114s0x_gpio_get_pin_value(const struct device *dev, uint8_t pin, bool *value) { struct ads114s0x_data *data = dev->data; - const struct ads114s0x_config *config = dev->config; int result = 0; uint8_t gpio_dat; if (pin > ADS114S0X_GPIO_MAX) { - LOG_ERR("invalid pin %i", pin); + LOG_ERR("%s: invalid pin %i", dev->name, pin); return -EINVAL; } k_mutex_lock(&data->gpio_lock, K_FOREVER); if ((BIT(pin) & data->gpio_enabled) == 0) { - LOG_ERR("gpio pin %i not configured", pin); + LOG_ERR("%s: gpio pin %i not configured", dev->name, pin); result = -EINVAL; } else if ((BIT(pin) & data->gpio_direction) == 0) { - LOG_ERR("gpio pin %i not configured as input", pin); + LOG_ERR("%s: gpio pin %i not configured as input", dev->name, pin); result = -EINVAL; } else { - result = ads114s0x_read_register(&config->bus, ADS114S0X_REGISTER_GPIODAT, - &gpio_dat); + result = ads114s0x_read_register(dev, ADS114S0X_REGISTER_GPIODAT, &gpio_dat); data->gpio_value = ADS114S0X_REGISTER_GPIODAT_DAT_GET(gpio_dat); *value = (BIT(pin) & data->gpio_value) != 0; } @@ -1247,13 +1260,12 @@ int ads114s0x_gpio_get_pin_value(const struct device *dev, uint8_t pin, bool *va int ads114s0x_gpio_port_get_raw(const struct device *dev, gpio_port_value_t *value) { struct ads114s0x_data *data = dev->data; - const struct ads114s0x_config *config = dev->config; int result = 0; uint8_t gpio_dat; k_mutex_lock(&data->gpio_lock, K_FOREVER); - result = ads114s0x_read_register(&config->bus, ADS114S0X_REGISTER_GPIODAT, &gpio_dat); + result = ads114s0x_read_register(dev, ADS114S0X_REGISTER_GPIODAT, &gpio_dat); data->gpio_value = ADS114S0X_REGISTER_GPIODAT_DAT_GET(gpio_dat); *value = data->gpio_value; @@ -1315,14 +1327,14 @@ static int ads114s0x_init(const struct device *dev) #endif /* CONFIG_ADC_ADS114S0X_GPIO */ if (!spi_is_ready_dt(&config->bus)) { - LOG_ERR("SPI device is not ready"); + LOG_ERR("%s: SPI device is not ready", dev->name); return -ENODEV; } if (config->gpio_reset.port != NULL) { result = gpio_pin_configure_dt(&config->gpio_reset, GPIO_OUTPUT_ACTIVE); if (result != 0) { - LOG_ERR("failed to initialize GPIO for reset"); + LOG_ERR("%s: failed to initialize GPIO for reset", dev->name); return result; } } @@ -1330,20 +1342,20 @@ static int ads114s0x_init(const struct device *dev) if (config->gpio_start_sync.port != NULL) { result = gpio_pin_configure_dt(&config->gpio_start_sync, GPIO_OUTPUT_INACTIVE); if (result != 0) { - LOG_ERR("failed to initialize GPIO for start/sync"); + LOG_ERR("%s: failed to initialize GPIO for start/sync", dev->name); return result; } } result = gpio_pin_configure_dt(&config->gpio_data_ready, GPIO_INPUT); if (result != 0) { - LOG_ERR("failed to initialize GPIO for data ready"); + LOG_ERR("%s: failed to initialize GPIO for data ready", dev->name); return result; } result = gpio_pin_interrupt_configure_dt(&config->gpio_data_ready, GPIO_INT_EDGE_TO_ACTIVE); if (result != 0) { - LOG_ERR("failed to configure data ready interrupt"); + LOG_ERR("%s: failed to configure data ready interrupt", dev->name); return -EIO; } @@ -1351,7 +1363,7 @@ static int ads114s0x_init(const struct device *dev) BIT(config->gpio_data_ready.pin)); result = gpio_add_callback(config->gpio_data_ready.port, &data->callback_data_ready); if (result != 0) { - LOG_ERR("failed to add data ready callback"); + LOG_ERR("%s: failed to add data ready callback", dev->name); return -EIO; } @@ -1366,9 +1378,9 @@ static int ads114s0x_init(const struct device *dev) k_busy_wait(ADS114S0X_POWER_ON_RESET_TIME_IN_US); if (config->gpio_reset.port == NULL) { - result = ads114s0x_send_command(&config->bus, ADS114S0X_COMMAND_RESET); + result = ads114s0x_send_command(dev, ADS114S0X_COMMAND_RESET); if (result != 0) { - LOG_ERR("unable to send RESET command"); + LOG_ERR("%s: unable to send RESET command", dev->name); return result; } } else { @@ -1378,14 +1390,14 @@ static int ads114s0x_init(const struct device *dev) k_busy_wait(ADS114S0X_RESET_DELAY_TIME_IN_US); - result = ads114s0x_read_register(&config->bus, ADS114S0X_REGISTER_STATUS, &status); + result = ads114s0x_read_register(dev, ADS114S0X_REGISTER_STATUS, &status); if (result != 0) { - LOG_ERR("unable to read status register"); + LOG_ERR("%s: unable to read status register", dev->name); return result; } if (ADS114S0X_REGISTER_STATUS_NOT_RDY_GET(status) == 0x01) { - LOG_ERR("ADS114 is not yet ready"); + LOG_ERR("%s: ADS114 is not yet ready", dev->name); return -EBUSY; } @@ -1395,24 +1407,24 @@ static int ads114s0x_init(const struct device *dev) */ ADS114S0X_REGISTER_REF_SET_DEFAULTS(reference_control); - result = ads114s0x_write_register(&config->bus, ADS114S0X_REGISTER_REF, reference_control); + result = ads114s0x_write_register(dev, ADS114S0X_REGISTER_REF, reference_control); if (result != 0) { - LOG_ERR("unable to set default reference control values"); + LOG_ERR("%s: unable to set default reference control values", dev->name); return result; } /* * Ensure that the internal voltage reference is active. */ - result = ads114s0x_read_register(&config->bus, ADS114S0X_REGISTER_REF, - &reference_control_read); + result = ads114s0x_read_register(dev, ADS114S0X_REGISTER_REF, &reference_control_read); if (result != 0) { - LOG_ERR("unable to read reference control values"); + LOG_ERR("%s: unable to read reference control values", dev->name); return result; } if (reference_control != reference_control_read) { - LOG_ERR("reference control register is incorrect: 0x%02X", reference_control_read); + LOG_ERR("%s: reference control register is incorrect: 0x%02X", dev->name, + reference_control_read); return -EIO; } @@ -1424,7 +1436,7 @@ static int ads114s0x_init(const struct device *dev) result = ads114s0x_gpio_write_config(dev); if (result != 0) { - LOG_ERR("unable to configure defaults for GPIOs"); + LOG_ERR("%s: unable to configure defaults for GPIOs", dev->name); return result; } #endif From 08bf74a82595bea693bf45125395f6d3295a4670 Mon Sep 17 00:00:00 2001 From: Benedikt Schmidt Date: Thu, 30 Nov 2023 07:18:23 +0100 Subject: [PATCH 0551/3723] drivers: adc: cleanup whitespaces in ADS114s0x Cleanup the whitespaces with clang-format in the driver of the ADS114s0x. Signed-off-by: Benedikt Schmidt --- drivers/adc/adc_ads114s0x.c | 58 ++++++++++++++++++------------------- 1 file changed, 29 insertions(+), 29 deletions(-) diff --git a/drivers/adc/adc_ads114s0x.c b/drivers/adc/adc_ads114s0x.c index 8e95e79c79c..936aecf6f1a 100644 --- a/drivers/adc/adc_ads114s0x.c +++ b/drivers/adc/adc_ads114s0x.c @@ -23,15 +23,15 @@ LOG_MODULE_REGISTER(ads114s0x, CONFIG_ADC_LOG_LEVEL); -#define ADS114S0X_CLK_FREQ_IN_KHZ 4096 -#define ADS114S0X_RESET_LOW_TIME_IN_CLOCK_CYCLES 4 +#define ADS114S0X_CLK_FREQ_IN_KHZ 4096 +#define ADS114S0X_RESET_LOW_TIME_IN_CLOCK_CYCLES 4 #define ADS114S0X_START_SYNC_PULSE_DURATION_IN_CLOCK_CYCLES 4 -#define ADS114S0X_SETUP_TIME_IN_CLOCK_CYCLES 32 -#define ADS114S0X_INPUT_SELECTION_AINCOM 12 -#define ADS114S0X_RESOLUTION 16 -#define ADS114S0X_REF_INTERNAL 2500 -#define ADS114S0X_GPIO_MAX 3 -#define ADS114S0X_POWER_ON_RESET_TIME_IN_US 2200 +#define ADS114S0X_SETUP_TIME_IN_CLOCK_CYCLES 32 +#define ADS114S0X_INPUT_SELECTION_AINCOM 12 +#define ADS114S0X_RESOLUTION 16 +#define ADS114S0X_REF_INTERNAL 2500 +#define ADS114S0X_GPIO_MAX 3 +#define ADS114S0X_POWER_ON_RESET_TIME_IN_US 2200 /* Not mentioned in the datasheet, but instead determined experimentally. */ #define ADS114S0X_RESET_DELAY_TIME_SAFETY_MARGIN_IN_US 1000 @@ -94,7 +94,7 @@ enum ads114s0x_register { ADS114S0X_REGISTER_SET_VALUE(target, value, ADS114S0X_REGISTER_ID_DEV_ID_POS, \ ADS114S0X_REGISTER_ID_DEV_ID_LENGTH) #define ADS114S0X_REGISTER_STATUS_FL_POR_LENGTH 1 -#define ADS114S0X_REGISTER_STATUS_FL_POR_POS 7 +#define ADS114S0X_REGISTER_STATUS_FL_POR_POS 7 #define ADS114S0X_REGISTER_STATUS_FL_POR_GET(value) \ ADS114S0X_REGISTER_GET_VALUE(value, ADS114S0X_REGISTER_STATUS_FL_POR_POS, \ ADS114S0X_REGISTER_STATUS_FL_POR_LENGTH) @@ -102,7 +102,7 @@ enum ads114s0x_register { ADS114S0X_REGISTER_SET_VALUE(target, value, ADS114S0X_REGISTER_STATUS_FL_POR_POS, \ ADS114S0X_REGISTER_STATUS_FL_POR_LENGTH) #define ADS114S0X_REGISTER_STATUS_NOT_RDY_LENGTH 1 -#define ADS114S0X_REGISTER_STATUS_NOT_RDY_POS 6 +#define ADS114S0X_REGISTER_STATUS_NOT_RDY_POS 6 #define ADS114S0X_REGISTER_STATUS_NOT_RDY_GET(value) \ ADS114S0X_REGISTER_GET_VALUE(value, ADS114S0X_REGISTER_STATUS_NOT_RDY_POS, \ ADS114S0X_REGISTER_STATUS_NOT_RDY_LENGTH) @@ -142,7 +142,7 @@ enum ads114s0x_register { ADS114S0X_REGISTER_SET_VALUE(target, value, ADS114S0X_REGISTER_STATUS_FL_N_RAILN_POS, \ ADS114S0X_REGISTER_STATUS_FL_N_RAILN_LENGTH) #define ADS114S0X_REGISTER_STATUS_FL_REF_L1_LENGTH 1 -#define ADS114S0X_REGISTER_STATUS_FL_REF_L1_POS 1 +#define ADS114S0X_REGISTER_STATUS_FL_REF_L1_POS 1 #define ADS114S0X_REGISTER_STATUS_FL_REF_L1_GET(value) \ ADS114S0X_REGISTER_GET_VALUE(value, ADS114S0X_REGISTER_STATUS_FL_REF_L1_POS, \ ADS114S0X_REGISTER_STATUS_FL_REF_L1_LENGTH) @@ -150,7 +150,7 @@ enum ads114s0x_register { ADS114S0X_REGISTER_SET_VALUE(target, value, ADS114S0X_REGISTER_STATUS_FL_REF_L1_POS, \ ADS114S0X_REGISTER_STATUS_FL_REF_L1_LENGTH) #define ADS114S0X_REGISTER_STATUS_FL_REF_L0_LENGTH 1 -#define ADS114S0X_REGISTER_STATUS_FL_REF_L0_POS 0 +#define ADS114S0X_REGISTER_STATUS_FL_REF_L0_POS 0 #define ADS114S0X_REGISTER_STATUS_FL_REF_L0_GET(value) \ ADS114S0X_REGISTER_GET_VALUE(value, ADS114S0X_REGISTER_STATUS_FL_REF_L0_POS, \ ADS114S0X_REGISTER_STATUS_FL_REF_L0_LENGTH) @@ -190,7 +190,7 @@ enum ads114s0x_register { ADS114S0X_REGISTER_SET_VALUE(target, value, ADS114S0X_REGISTER_PGA_PGA_EN_POS, \ ADS114S0X_REGISTER_PGA_PGA_EN_LENGTH) #define ADS114S0X_REGISTER_PGA_GAIN_LENGTH 3 -#define ADS114S0X_REGISTER_PGA_GAIN_POS 0 +#define ADS114S0X_REGISTER_PGA_GAIN_POS 0 #define ADS114S0X_REGISTER_PGA_GAIN_GET(value) \ ADS114S0X_REGISTER_GET_VALUE(value, ADS114S0X_REGISTER_PGA_GAIN_POS, \ ADS114S0X_REGISTER_PGA_GAIN_LENGTH) @@ -198,7 +198,7 @@ enum ads114s0x_register { ADS114S0X_REGISTER_SET_VALUE(target, value, ADS114S0X_REGISTER_PGA_GAIN_POS, \ ADS114S0X_REGISTER_PGA_GAIN_LENGTH) #define ADS114S0X_REGISTER_DATARATE_G_CHOP_LENGTH 1 -#define ADS114S0X_REGISTER_DATARATE_G_CHOP_POS 7 +#define ADS114S0X_REGISTER_DATARATE_G_CHOP_POS 7 #define ADS114S0X_REGISTER_DATARATE_G_CHOP_GET(value) \ ADS114S0X_REGISTER_GET_VALUE(value, ADS114S0X_REGISTER_DATARATE_G_CHOP_POS, \ ADS114S0X_REGISTER_DATARATE_G_CHOP_LENGTH) @@ -214,7 +214,7 @@ enum ads114s0x_register { ADS114S0X_REGISTER_SET_VALUE(target, value, ADS114S0X_REGISTER_DATARATE_CLK_POS, \ ADS114S0X_REGISTER_DATARATE_CLK_LENGTH) #define ADS114S0X_REGISTER_DATARATE_MODE_LENGTH 1 -#define ADS114S0X_REGISTER_DATARATE_MODE_POS 5 +#define ADS114S0X_REGISTER_DATARATE_MODE_POS 5 #define ADS114S0X_REGISTER_DATARATE_MODE_GET(value) \ ADS114S0X_REGISTER_GET_VALUE(value, ADS114S0X_REGISTER_DATARATE_MODE_POS, \ ADS114S0X_REGISTER_DATARATE_MODE_LENGTH) @@ -222,7 +222,7 @@ enum ads114s0x_register { ADS114S0X_REGISTER_SET_VALUE(target, value, ADS114S0X_REGISTER_DATARATE_MODE_POS, \ ADS114S0X_REGISTER_DATARATE_MODE_LENGTH) #define ADS114S0X_REGISTER_DATARATE_FILTER_LENGTH 1 -#define ADS114S0X_REGISTER_DATARATE_FILTER_POS 4 +#define ADS114S0X_REGISTER_DATARATE_FILTER_POS 4 #define ADS114S0X_REGISTER_DATARATE_FILTER_GET(value) \ ADS114S0X_REGISTER_GET_VALUE(value, ADS114S0X_REGISTER_DATARATE_FILTER_POS, \ ADS114S0X_REGISTER_DATARATE_FILTER_LENGTH) @@ -238,7 +238,7 @@ enum ads114s0x_register { ADS114S0X_REGISTER_SET_VALUE(target, value, ADS114S0X_REGISTER_DATARATE_DR_POS, \ ADS114S0X_REGISTER_DATARATE_DR_LENGTH) #define ADS114S0X_REGISTER_REF_FL_REF_EN_LENGTH 2 -#define ADS114S0X_REGISTER_REF_FL_REF_EN_POS 6 +#define ADS114S0X_REGISTER_REF_FL_REF_EN_POS 6 #define ADS114S0X_REGISTER_REF_FL_REF_EN_GET(value) \ ADS114S0X_REGISTER_GET_VALUE(value, ADS114S0X_REGISTER_REF_FL_REF_EN_POS, \ ADS114S0X_REGISTER_REF_FL_REF_EN_LENGTH) @@ -246,7 +246,7 @@ enum ads114s0x_register { ADS114S0X_REGISTER_SET_VALUE(target, value, ADS114S0X_REGISTER_REF_FL_REF_EN_POS, \ ADS114S0X_REGISTER_REF_FL_REF_EN_LENGTH) #define ADS114S0X_REGISTER_REF_NOT_REFP_BUF_LENGTH 1 -#define ADS114S0X_REGISTER_REF_NOT_REFP_BUF_POS 5 +#define ADS114S0X_REGISTER_REF_NOT_REFP_BUF_POS 5 #define ADS114S0X_REGISTER_REF_NOT_REFP_BUF_GET(value) \ ADS114S0X_REGISTER_GET_VALUE(value, ADS114S0X_REGISTER_REF_NOT_REFP_BUF_POS, \ ADS114S0X_REGISTER_REF_NOT_REFP_BUF_LENGTH) @@ -254,7 +254,7 @@ enum ads114s0x_register { ADS114S0X_REGISTER_SET_VALUE(target, value, ADS114S0X_REGISTER_REF_NOT_REFP_BUF_POS, \ ADS114S0X_REGISTER_REF_NOT_REFP_BUF_LENGTH) #define ADS114S0X_REGISTER_REF_NOT_REFN_BUF_LENGTH 1 -#define ADS114S0X_REGISTER_REF_NOT_REFN_BUF_POS 4 +#define ADS114S0X_REGISTER_REF_NOT_REFN_BUF_POS 4 #define ADS114S0X_REGISTER_REF_NOT_REFN_BUF_GET(value) \ ADS114S0X_REGISTER_GET_VALUE(value, ADS114S0X_REGISTER_REF_NOT_REFN_BUF_POS, \ ADS114S0X_REGISTER_REF_NOT_REFN_BUF_LENGTH) @@ -302,7 +302,7 @@ enum ads114s0x_register { ADS114S0X_REGISTER_SET_VALUE(target, value, ADS114S0X_REGISTER_IDACMAG_IMAG_POS, \ ADS114S0X_REGISTER_IDACMAG_IMAG_LENGTH) #define ADS114S0X_REGISTER_IDACMUX_I2MUX_LENGTH 4 -#define ADS114S0X_REGISTER_IDACMUX_I2MUX_POS 4 +#define ADS114S0X_REGISTER_IDACMUX_I2MUX_POS 4 #define ADS114S0X_REGISTER_IDACMUX_I2MUX_GET(value) \ ADS114S0X_REGISTER_GET_VALUE(value, ADS114S0X_REGISTER_IDACMUX_I2MUX_POS, \ ADS114S0X_REGISTER_IDACMUX_I2MUX_LENGTH) @@ -310,7 +310,7 @@ enum ads114s0x_register { ADS114S0X_REGISTER_SET_VALUE(target, value, ADS114S0X_REGISTER_IDACMUX_I2MUX_POS, \ ADS114S0X_REGISTER_IDACMUX_I2MUX_LENGTH) #define ADS114S0X_REGISTER_IDACMUX_I1MUX_LENGTH 4 -#define ADS114S0X_REGISTER_IDACMUX_I1MUX_POS 0 +#define ADS114S0X_REGISTER_IDACMUX_I1MUX_POS 0 #define ADS114S0X_REGISTER_IDACMUX_I1MUX_GET(value) \ ADS114S0X_REGISTER_GET_VALUE(value, ADS114S0X_REGISTER_IDACMUX_I1MUX_POS, \ ADS114S0X_REGISTER_IDACMUX_I1MUX_LENGTH) @@ -424,10 +424,10 @@ struct ads114s0x_data { int16_t *buffer_ptr; #if CONFIG_ADC_ADS114S0X_GPIO struct k_mutex gpio_lock; - uint8_t gpio_enabled; /* one bit per GPIO, 1 = enabled */ + uint8_t gpio_enabled; /* one bit per GPIO, 1 = enabled */ uint8_t gpio_direction; /* one bit per GPIO, 1 = input */ - uint8_t gpio_value; /* one bit per GPIO, 1 = high */ -#endif /* CONFIG_ADC_ADS114S0X_GPIO */ + uint8_t gpio_value; /* one bit per GPIO, 1 = high */ +#endif /* CONFIG_ADC_ADS114S0X_GPIO */ }; static void ads114s0x_data_ready_handler(const struct device *dev, struct gpio_callback *gpio_cb, @@ -1368,10 +1368,10 @@ static int ads114s0x_init(const struct device *dev) } #if CONFIG_ADC_ASYNC - k_tid_t tid = k_thread_create( - &data->thread, config->stack, CONFIG_ADC_ADS114S0X_ACQUISITION_THREAD_STACK_SIZE, - ads114s0x_acquisition_thread, (void *)dev, NULL, NULL, - CONFIG_ADC_ADS114S0X_ASYNC_THREAD_INIT_PRIO, 0, K_NO_WAIT); + k_tid_t tid = k_thread_create(&data->thread, config->stack, + CONFIG_ADC_ADS114S0X_ACQUISITION_THREAD_STACK_SIZE, + ads114s0x_acquisition_thread, (void *)dev, NULL, NULL, + CONFIG_ADC_ADS114S0X_ASYNC_THREAD_INIT_PRIO, 0, K_NO_WAIT); k_thread_name_set(tid, "adc_ads114s0x"); #endif @@ -1472,7 +1472,7 @@ BUILD_ASSERT(CONFIG_ADC_INIT_PRIORITY > CONFIG_SPI_INIT_PRIORITY, .gpio_reset = GPIO_DT_SPEC_INST_GET_OR(n, reset_gpios, {0}), \ .gpio_data_ready = GPIO_DT_SPEC_INST_GET(n, drdy_gpios), \ .gpio_start_sync = GPIO_DT_SPEC_INST_GET_OR(n, start_sync_gpios, {0}), \ - .idac_current = DT_INST_PROP(n, idac_current), \ + .idac_current = DT_INST_PROP(n, idac_current), \ }; \ static struct ads114s0x_data data_##n; \ DEVICE_DT_INST_DEFINE(n, ads114s0x_init, NULL, &data_##n, &config_##n, POST_KERNEL, \ From 79c2fafe6a6beac219462213b2f96d6fcc39437e Mon Sep 17 00:00:00 2001 From: Emil Lindqvist Date: Thu, 9 Nov 2023 14:09:57 +0100 Subject: [PATCH 0552/3723] modem: modem_cellular: add PAP authentication support Some modems or networks require PAP authentication for successful LCP handshake. Tested on U-blox SARA-R5 with zephyr,gsm-ppp. Signed-off-by: Emil Lindqvist --- drivers/modem/Kconfig.cellular | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/modem/Kconfig.cellular b/drivers/modem/Kconfig.cellular index 7817fb599e3..72e6a74acbb 100644 --- a/drivers/modem/Kconfig.cellular +++ b/drivers/modem/Kconfig.cellular @@ -11,6 +11,7 @@ config MODEM_CELLULAR select MODEM_BACKEND_UART select RING_BUFFER select NET_L2_PPP_OPTION_MRU + select NET_L2_PPP_PAP depends on (DT_HAS_QUECTEL_BG95_ENABLED || DT_HAS_ZEPHYR_GSM_PPP_ENABLED || \ DT_HAS_SIMCOM_SIM7080_ENABLED || DT_HAS_U_BLOX_SARA_R4_ENABLED || \ DT_HAS_SWIR_HL7800_ENABLED || DT_HAS_TELIT_ME910G1_ENABLED || \ From ba476c4b8ae57f5d0c56b6abf108dd2ec9173c25 Mon Sep 17 00:00:00 2001 From: HaiLong Yang Date: Thu, 30 Nov 2023 11:43:36 +0800 Subject: [PATCH 0553/3723] drivers: flash: update gd32 fmc v2 This fix some incorrect implement in gd32 flash v2 driver, also add support to gd32a503 series. Signed-off-by: HaiLong Yang --- drivers/flash/flash_gd32_v2.c | 46 ++++++++++++++++------- dts/arm/gigadevice/gd32a50x/gd32a50x.dtsi | 2 +- 2 files changed, 33 insertions(+), 15 deletions(-) diff --git a/drivers/flash/flash_gd32_v2.c b/drivers/flash/flash_gd32_v2.c index 20a27b3d17b..645e40fd546 100644 --- a/drivers/flash/flash_gd32_v2.c +++ b/drivers/flash/flash_gd32_v2.c @@ -15,6 +15,7 @@ LOG_MODULE_DECLARE(flash_gd32); #define GD32_NV_FLASH_V2_NODE DT_INST(0, gd_gd32_nv_flash_v2) #define GD32_NV_FLASH_V2_TIMEOUT DT_PROP(GD32_NV_FLASH_V2_NODE, max_erase_time_ms) +#if !defined(CONFIG_SOC_GD32A503) /** * @brief GD32 FMC v2 flash memory has 2 banks. * Bank0 holds the first 512KB, bank1 is used give capacity for reset. @@ -30,6 +31,23 @@ LOG_MODULE_DECLARE(flash_gd32); #define GD32_NV_FLASH_V2_BANK1_PAGE_SIZE DT_PROP(GD32_NV_FLASH_V2_NODE, bank1_page_size) #endif +#elif defined(CONFIG_SOC_GD32A503) +/** + * @brief GD32A503 series flash memory has 2 banks. + * Bank0 holds the first 256KB, bank1 is used give capacity for reset. + * The page size is 1KB for all banks. + */ +#if (PRE_KB(256) >= SOC_NV_FLASH_SIZE) +#define GD32_NV_FLASH_V2_BANK0_SIZE SOC_NV_FLASH_SIZE +#define GD32_NV_FLASH_V2_BANK0_PAGE_SIZE DT_PROP(GD32_NV_FLASH_V2_NODE, bank0_page_size) +#else +#define GD32_NV_FLASH_V2_BANK0_SIZE KB(256) +#define GD32_NV_FLASH_V2_BANK0_PAGE_SIZE DT_PROP(GD32_NV_FLASH_V2_NODE, bank0_page_size) +#define GD32_NV_FLASH_V2_BANK1_SIZE (SOC_NV_FLASH_SIZE - KB(256)) +#define GD32_NV_FLASH_V2_BANK1_PAGE_SIZE DT_PROP(GD32_NV_FLASH_V2_NODE, bank1_page_size) +#endif +#endif + #define GD32_FMC_V2_BANK0_WRITE_ERR (FMC_STAT0_PGERR | FMC_STAT0_WPERR) #define GD32_FMC_V2_BANK0_ERASE_ERR FMC_STAT0_WPERR @@ -42,7 +60,7 @@ static struct flash_pages_layout gd32_fmc_v2_layout[] = { .pages_size = GD32_NV_FLASH_V2_BANK0_PAGE_SIZE, .pages_count = GD32_NV_FLASH_V2_BANK0_SIZE / GD32_NV_FLASH_V2_BANK0_PAGE_SIZE }, -#ifdef FLASH_GD32_BANK1_SIZE +#ifdef GD32_NV_FLASH_V2_BANK1_SIZE { .pages_size = GD32_NV_FLASH_V2_BANK1_PAGE_SIZE, .pages_count = GD32_NV_FLASH_V2_BANK1_SIZE / GD32_NV_FLASH_V2_BANK1_PAGE_SIZE @@ -77,7 +95,7 @@ static int gd32_fmc_v2_bank0_wait_idle(void) static int gd32_fmc_v2_bank0_write(off_t offset, const void *data, size_t len) { - flash_prg_t *prg_flash = (flash_prg_t *)((uint8_t *)SOC_NV_FLASH_SIZE + offset); + flash_prg_t *prg_flash = (flash_prg_t *)((uint8_t *)SOC_NV_FLASH_ADDR + offset); flash_prg_t *prg_data = (flash_prg_t *)data; int ret = 0; @@ -158,14 +176,14 @@ static int gd32_fmc_v2_bank0_erase_block(off_t offset, size_t size) return ret; } - size -= GD32_NV_FLASH_V2_BANK0_SIZE; - page_addr += GD32_NV_FLASH_V2_BANK0_SIZE; + size -= GD32_NV_FLASH_V2_BANK0_PAGE_SIZE; + page_addr += GD32_NV_FLASH_V2_BANK0_PAGE_SIZE; } return 0; } -#ifdef FLASH_GD32_BANK1_SIZE +#ifdef GD32_NV_FLASH_V2_BANK1_SIZE static inline void gd32_fmc_v2_bank1_unlock(void) { FMC_KEY1 = UNLOCK_KEY0; @@ -179,7 +197,7 @@ static inline void gd32_fmc_v2_bank1_lock(void) static int gd32_fmc_v2_bank1_wait_idle(void) { - const int64_t expired_time = k_uptime_get() + FLASH_GD32_TIMEOUT; + const int64_t expired_time = k_uptime_get() + GD32_NV_FLASH_V2_TIMEOUT; while (FMC_STAT1 & FMC_STAT1_BUSY) { if (k_uptime_get() > expired_time) { @@ -279,7 +297,7 @@ static int gd32_fmc_v2_bank1_erase_block(off_t offset, size_t size) return 0; } -#endif /* FLASH_GD32_BANK1_SIZE */ +#endif /* GD32_NV_FLASH_V2_BANK1_SIZE */ bool flash_gd32_valid_range(off_t offset, uint32_t len, bool write) { @@ -297,17 +315,17 @@ bool flash_gd32_valid_range(off_t offset, uint32_t len, bool write) } else { if (offset < GD32_NV_FLASH_V2_BANK0_SIZE) { - if (offset % GD32_NV_FLASH_V2_BANK0_SIZE) { + if (offset % GD32_NV_FLASH_V2_BANK0_PAGE_SIZE) { return false; } if (((offset + len) <= GD32_NV_FLASH_V2_BANK0_SIZE) && - (len % GD32_NV_FLASH_V2_BANK0_SIZE)) { + (len % GD32_NV_FLASH_V2_BANK0_PAGE_SIZE)) { return false; } } -#ifdef FLASH_GD32_BANK1_SIZE +#ifdef GD32_NV_FLASH_V2_BANK1_SIZE /* Remove bank0 info from offset and len. */ if ((offset < GD32_NV_FLASH_V2_BANK0_SIZE) && ((offset + len) > GD32_NV_FLASH_V2_BANK0_SIZE)) { @@ -316,8 +334,8 @@ bool flash_gd32_valid_range(off_t offset, uint32_t len, bool write) } if (offset >= GD32_NV_FLASH_V2_BANK0_SIZE) { - if ((offset % GD32_NV_FLASH_V2_BANK1_SIZE) || - (len % GD32_NV_FLASH_V2_BANK1_SIZE)) { + if ((offset % GD32_NV_FLASH_V2_BANK1_PAGE_SIZE) || + (len % GD32_NV_FLASH_V2_BANK1_PAGE_SIZE)) { return false; } } @@ -345,7 +363,7 @@ int flash_gd32_write_range(off_t offset, const void *data, size_t len) } } -#ifdef FLASH_GD32_BANK1_SIZE +#ifdef GD32_NV_FLASH_V2_BANK1_SIZE size_t len1 = len - len0; if (len1 == 0U) { @@ -384,7 +402,7 @@ int flash_gd32_erase_block(off_t offset, size_t size) } } -#ifdef FLASH_GD32_BANK1_SIZE +#ifdef GD32_NV_FLASH_V2_BANK1_SIZE size_t size1 = size - size0; if (size1 == 0U) { diff --git a/dts/arm/gigadevice/gd32a50x/gd32a50x.dtsi b/dts/arm/gigadevice/gd32a50x/gd32a50x.dtsi index 00f70dfc96b..af54b98f716 100644 --- a/dts/arm/gigadevice/gd32a50x/gd32a50x.dtsi +++ b/dts/arm/gigadevice/gd32a50x/gd32a50x.dtsi @@ -64,7 +64,7 @@ flash0: flash@8000000 { compatible = "gd,gd32-nv-flash-v2", "soc-nv-flash"; - write-block-size = <2>; + write-block-size = <4>; max-erase-time-ms = <2578>; bank0-page-size = ; bank1-page-size = ; From f5e871d5e0d8d092d9bb97f23bb62a53a418428d Mon Sep 17 00:00:00 2001 From: HaiLong Yang Date: Thu, 30 Nov 2023 17:25:43 +0800 Subject: [PATCH 0554/3723] test: flash: add gd32 boards This add gd32vf103v_eval, gd32a503v_eval and gd32f470i_eval boards to flash common test. Boards | Flash Type ------------------------------- gd32vf103v_eval | gd32 fmc v1 gd32a503v_eval | gd32 fmc v2 gd32f470i_eval | gd32 fmc v3 Signed-off-by: HaiLong Yang --- boards/arm/gd32a503v_eval/gd32a503v_eval.yaml | 1 + boards/arm/gd32f470i_eval/gd32f470i_eval.yaml | 1 + .../gd32vf103v_eval/gd32vf103v_eval.yaml | 7 +++--- .../common/boards/gd32a503v_eval.overlay | 24 +++++++++++++++++++ .../common/boards/gd32f470i_eval.overlay | 24 +++++++++++++++++++ .../common/boards/gd32vf103v_eval.overlay | 24 +++++++++++++++++++ tests/drivers/flash/common/testcase.yaml | 5 ++++ 7 files changed, 83 insertions(+), 3 deletions(-) create mode 100644 tests/drivers/flash/common/boards/gd32a503v_eval.overlay create mode 100644 tests/drivers/flash/common/boards/gd32f470i_eval.overlay create mode 100644 tests/drivers/flash/common/boards/gd32vf103v_eval.overlay diff --git a/boards/arm/gd32a503v_eval/gd32a503v_eval.yaml b/boards/arm/gd32a503v_eval/gd32a503v_eval.yaml index 396e68d24b6..e2e2145d9af 100644 --- a/boards/arm/gd32a503v_eval/gd32a503v_eval.yaml +++ b/boards/arm/gd32a503v_eval/gd32a503v_eval.yaml @@ -16,6 +16,7 @@ supported: - counter - dac - dma + - flash - gpio - pwm - spi diff --git a/boards/arm/gd32f470i_eval/gd32f470i_eval.yaml b/boards/arm/gd32f470i_eval/gd32f470i_eval.yaml index 868e4907f3f..9537f9aef30 100644 --- a/boards/arm/gd32f470i_eval/gd32f470i_eval.yaml +++ b/boards/arm/gd32f470i_eval/gd32f470i_eval.yaml @@ -14,6 +14,7 @@ toolchain: supported: - counter - dac + - flash - gpio - i2c - pwm diff --git a/boards/riscv/gd32vf103v_eval/gd32vf103v_eval.yaml b/boards/riscv/gd32vf103v_eval/gd32vf103v_eval.yaml index 306d3e11498..857fe8adf6d 100644 --- a/boards/riscv/gd32vf103v_eval/gd32vf103v_eval.yaml +++ b/boards/riscv/gd32vf103v_eval/gd32vf103v_eval.yaml @@ -10,10 +10,11 @@ flash: 128 toolchain: - zephyr supported: - - uart + - dma + - flash - gpio - pwm - - watchdog - - dma - spi + - uart + - watchdog vendor: gd diff --git a/tests/drivers/flash/common/boards/gd32a503v_eval.overlay b/tests/drivers/flash/common/boards/gd32a503v_eval.overlay new file mode 100644 index 00000000000..de16cdec869 --- /dev/null +++ b/tests/drivers/flash/common/boards/gd32a503v_eval.overlay @@ -0,0 +1,24 @@ +/* + * Copyright (c) 2023, BrainCo Inc. + * + * SPDX-License-Identifier: Apache-2.0 + */ + +&flash0 { + partitions { + compatible = "fixed-partitions"; + #address-cells = <1>; + #size-cells = <1>; + + /* Set 4KB of storage at the border of bank0(256KB) and bank1(128KB). */ + storage_partition: partition@3f800 { + label = "storage"; + reg = <0x0003f800 DT_SIZE_K(4)>; + }; + }; +}; + +/* To avoid test on nor_flash, disable it. */ +&nor_flash { + status = "disabled"; +}; diff --git a/tests/drivers/flash/common/boards/gd32f470i_eval.overlay b/tests/drivers/flash/common/boards/gd32f470i_eval.overlay new file mode 100644 index 00000000000..7d4fb75475e --- /dev/null +++ b/tests/drivers/flash/common/boards/gd32f470i_eval.overlay @@ -0,0 +1,24 @@ +/* + * Copyright (c) 2023, BrainCo Inc. + * + * SPDX-License-Identifier: Apache-2.0 + */ + +&flash0 { + partitions { + compatible = "fixed-partitions"; + #address-cells = <1>; + #size-cells = <1>; + + /* Set 512KB of storage at the end of 3072KB flash */ + storage_partition: partition@280000 { + label = "storage"; + reg = <0x00280000 DT_SIZE_K(512)>; + }; + }; +}; + +/* To avoid test on nor_flash, disable it. */ +&nor_flash { + status = "disabled"; +}; diff --git a/tests/drivers/flash/common/boards/gd32vf103v_eval.overlay b/tests/drivers/flash/common/boards/gd32vf103v_eval.overlay new file mode 100644 index 00000000000..7c2952d1155 --- /dev/null +++ b/tests/drivers/flash/common/boards/gd32vf103v_eval.overlay @@ -0,0 +1,24 @@ +/* + * Copyright (c) 2023, BrainCo Inc. + * + * SPDX-License-Identifier: Apache-2.0 + */ + +&flash0 { + partitions { + compatible = "fixed-partitions"; + #address-cells = <1>; + #size-cells = <1>; + + /* Set 2KB of storage at the end of 128KB flash */ + storage_partition: partition@1f800 { + label = "storage"; + reg = <0x0001f800 DT_SIZE_K(2)>; + }; + }; +}; + +/* To avoid test on nor_flash, disable it. */ +&nor_flash { + status = "disabled"; +}; diff --git a/tests/drivers/flash/common/testcase.yaml b/tests/drivers/flash/common/testcase.yaml index b0b0c9af91a..a3624f76be2 100644 --- a/tests/drivers/flash/common/testcase.yaml +++ b/tests/drivers/flash/common/testcase.yaml @@ -92,3 +92,8 @@ tests: - atsamd20_xpro - atsamr21_xpro - atsame54_xpro + drivers.flash.common.gd32: + platform_allow: + - gd32vf103v_eval + - gd32a503v_eval + - gd32f470i_eval From df100d45987258d01f00c745c0628e32a568b3a5 Mon Sep 17 00:00:00 2001 From: Alberto Escolar Piedras Date: Tue, 28 Nov 2023 09:52:24 +0100 Subject: [PATCH 0555/3723] boards native: Add not supported features Add a section with the most significant not supported features. Signed-off-by: Alberto Escolar Piedras --- boards/posix/doc/arch_soc.rst | 20 ++++++++++++++++++++ boards/posix/doc/bsim_boards_design.rst | 7 +++++-- boards/posix/native_sim/doc/index.rst | 10 ++++++++-- 3 files changed, 33 insertions(+), 4 deletions(-) diff --git a/boards/posix/doc/arch_soc.rst b/boards/posix/doc/arch_soc.rst index f0e469308ab..3e548139f4b 100644 --- a/boards/posix/doc/arch_soc.rst +++ b/boards/posix/doc/arch_soc.rst @@ -169,6 +169,24 @@ In the previous example, modifying the code as follows would work: #endif } +.. _posix_arch_unsupported: + +Significant unsupported features +******************************** + +Currently, these are the most significant features which are not supported in this architecture: + +* :ref:`User mode/userspace `: When building for these targets, + :kconfig:option:`CONFIG_USERSPACE` will always be disabled, + and all calls into the kernel will be done as normal calls. + +* Stack checks: :kconfig:option:`CONFIG_HW_STACK_PROTECTION`, + :kconfig:option:`CONFIG_STACK_CANARIES`, and + :kconfig:option:`CONFIG_THREAD_ANALYZER`. + This is due to how Zephyr allocated threads' stacks are not `actually` being used like they are + in other architectures. Check + :ref:`the architecture section's architecture layer paragraph ` + for more information. .. _posix_arch_rationale: @@ -294,6 +312,8 @@ Architecture and design Zephyr layering when built against an embedded target (left), and targeting a POSIX arch based board (right) +.. _posix_arch_design_archl: + Arch layer ========== diff --git a/boards/posix/doc/bsim_boards_design.rst b/boards/posix/doc/bsim_boards_design.rst index 9b6bcfc0bca..6165f76a438 100644 --- a/boards/posix/doc/bsim_boards_design.rst +++ b/boards/posix/doc/bsim_boards_design.rst @@ -167,13 +167,16 @@ The basic architecture layering of these boards is as follows: Overall architecture in a Zephyr application in an embedded target vs a bsim target -Important limitations -===================== +Important limitations and unsupported features +============================================== All native and bsim boards share the same set of :ref:`important limitations which` are inherited from the POSIX arch and `inf_clock` design. +Similarly, they inherit the POSIX architecture +:ref:`unsupported features set `. + .. _Threading: Threading and overall scheduling of CPU and HW models diff --git a/boards/posix/native_sim/doc/index.rst b/boards/posix/native_sim/doc/index.rst index 5d4ab7b8b8c..f441316a1c9 100644 --- a/boards/posix/native_sim/doc/index.rst +++ b/boards/posix/native_sim/doc/index.rst @@ -38,12 +38,18 @@ Please check the .. _nativesim_important_limitations: -Important limitations -********************* +Important limitations and unsupported features +********************************************** ``native_sim`` is based on the :ref:`POSIX architecture`, and therefore :ref:`its limitations ` and considerations apply to it. +Similarly, it inherits the POSIX architecture +:ref:`unsupported features set `. + +Note that some drivers may have limitations, or may not support their whole driver API optional +functionality. + .. _native_sim_how_to_use: How to use it From 44b8971e48ea6decf7fb81f74b42bb2d55f9af17 Mon Sep 17 00:00:00 2001 From: Alberto Escolar Piedras Date: Tue, 28 Nov 2023 09:54:03 +0100 Subject: [PATCH 0556/3723] native_sim: Improve instructions for i386 packages To the instructions that install "foreign architecture" (i386) packages on a x86-64 system, add the commands to ensure the architecture is added if it wasn't already. Signed-off-by: Alberto Escolar Piedras --- boards/posix/native_sim/doc/index.rst | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/boards/posix/native_sim/doc/index.rst b/boards/posix/native_sim/doc/index.rst index f441316a1c9..9d9206e2203 100644 --- a/boards/posix/native_sim/doc/index.rst +++ b/boards/posix/native_sim/doc/index.rst @@ -412,6 +412,8 @@ The following peripherals are currently provided with this board: .. code-block:: console + $ sudo dpkg --add-architecture i386 + $ sudo apt update $ sudo apt-get install pkg-config libsdl2-dev:i386 $ export PKG_CONFIG_PATH=/usr/lib/i386-linux-gnu/pkgconfig @@ -595,6 +597,8 @@ these commands: .. code-block:: console + $ sudo dpkg --add-architecture i386 + $ sudo apt update $ sudo apt-get install pkg-config libfuse-dev:i386 $ export PKG_CONFIG_PATH=/usr/lib/i386-linux-gnu/pkgconfig From be6b12e0128e7ddc9368286d6e2d6dffe0a08000 Mon Sep 17 00:00:00 2001 From: Marc Desvaux Date: Tue, 28 Nov 2023 10:48:28 +0100 Subject: [PATCH 0557/3723] tests: drivers: adc: adc_dma: add nucleo_l476rg Add nucleo_l476rg in drivers.adc.dma test case for twister test Signed-off-by: Marc Desvaux --- tests/drivers/adc/adc_dma/testcase.yaml | 1 + 1 file changed, 1 insertion(+) diff --git a/tests/drivers/adc/adc_dma/testcase.yaml b/tests/drivers/adc/adc_dma/testcase.yaml index 6db57d4be6c..de9557b430d 100644 --- a/tests/drivers/adc/adc_dma/testcase.yaml +++ b/tests/drivers/adc/adc_dma/testcase.yaml @@ -13,5 +13,6 @@ tests: - frdm_k64f - nucleo_h743zi - nucleo_u575zi_q + - nucleo_l476rg integration_platforms: - frdm_k82f From 0c541d7ad0f58fd0146f652c90ed292c06d7e641 Mon Sep 17 00:00:00 2001 From: Erwan Gouriou Date: Mon, 27 Nov 2023 11:34:29 +0100 Subject: [PATCH 0558/3723] drivers: uart: stm32: Allow enabling FIFO mode Add required bits to allow FIFO mode enabling. Signed-off-by: Erwan Gouriou --- drivers/serial/uart_stm32.c | 7 +++++++ drivers/serial/uart_stm32.h | 2 ++ dts/bindings/serial/st,stm32-uart-base.yaml | 10 ++++++++++ 3 files changed, 19 insertions(+) diff --git a/drivers/serial/uart_stm32.c b/drivers/serial/uart_stm32.c index f2c05da357e..edaff82e033 100644 --- a/drivers/serial/uart_stm32.c +++ b/drivers/serial/uart_stm32.c @@ -1956,6 +1956,12 @@ static int uart_stm32_registers_configure(const struct device *dev) } #endif +#ifdef USART_CR1_FIFOEN + if (config->fifo_enable) { + LL_USART_EnableFIFO(config->usart); + } +#endif + LL_USART_Enable(config->usart); #ifdef USART_ISR_TEACK @@ -2334,6 +2340,7 @@ static const struct uart_stm32_config uart_stm32_cfg_##index = { \ .de_assert_time = DT_INST_PROP(index, de_assert_time), \ .de_deassert_time = DT_INST_PROP(index, de_deassert_time), \ .de_invert = DT_INST_PROP(index, de_invert), \ + .fifo_enable = DT_INST_PROP(index, fifo_enable), \ STM32_UART_IRQ_HANDLER_FUNC(index) \ STM32_UART_PM_WAKEUP(index) \ }; \ diff --git a/drivers/serial/uart_stm32.h b/drivers/serial/uart_stm32.h index ed8e8584cd6..7c6f432a504 100644 --- a/drivers/serial/uart_stm32.h +++ b/drivers/serial/uart_stm32.h @@ -49,6 +49,8 @@ struct uart_stm32_config { uint8_t de_deassert_time; /* enable de pin inversion */ bool de_invert; + /* enable fifo */ + bool fifo_enable; /* pin muxing */ const struct pinctrl_dev_config *pcfg; #if defined(CONFIG_UART_INTERRUPT_DRIVEN) || defined(CONFIG_UART_ASYNC_API) || \ diff --git a/dts/bindings/serial/st,stm32-uart-base.yaml b/dts/bindings/serial/st,stm32-uart-base.yaml index ed8a6e1e3a9..230c384906a 100644 --- a/dts/bindings/serial/st,stm32-uart-base.yaml +++ b/dts/bindings/serial/st,stm32-uart-base.yaml @@ -86,3 +86,13 @@ properties: description: | Invert the binary logic of the de pin. When enabled, physical logic levels are inverted and we use 1=Low, 0=High instead of 1=High, 0=Low. + + fifo-enable: + type: boolean + description: | + Enables transmit and receive FIFO using default FIFO confugration (typically threasholds + set to 1/8). + In TX, FIFO allows to work in burst mode, easing scheduling of loaded applications. It also + allows more reliable communication with UART devices sensitive to variation of inter-frames + delays. + In RX, FIFO reduces overrun occurences. From 17c099872fe214474c97ce8232613d983ae77dc2 Mon Sep 17 00:00:00 2001 From: Erwan Gouriou Date: Tue, 28 Nov 2023 14:36:41 +0100 Subject: [PATCH 0559/3723] tests: uart: Enable fifo on nucleo_wba2cg for async tests This will allow compiling/testing fifo in CI. Signed-off-by: Erwan Gouriou --- tests/drivers/uart/uart_async_api/boards/nucleo_wba52cg.overlay | 1 + 1 file changed, 1 insertion(+) diff --git a/tests/drivers/uart/uart_async_api/boards/nucleo_wba52cg.overlay b/tests/drivers/uart/uart_async_api/boards/nucleo_wba52cg.overlay index c495168048b..9fc34bb26a2 100644 --- a/tests/drivers/uart/uart_async_api/boards/nucleo_wba52cg.overlay +++ b/tests/drivers/uart/uart_async_api/boards/nucleo_wba52cg.overlay @@ -8,6 +8,7 @@ dut: &lpuart1 { dmas = <&gpdma1 0 16 STM32_DMA_PERIPH_TX &gpdma1 1 15 STM32_DMA_PERIPH_RX>; dma-names = "tx", "rx"; + fifo-enable; }; &gpdma1 { From ad1594ee758b82e57b16b24ddd2ad1dcbffa6a0a Mon Sep 17 00:00:00 2001 From: Erwan Gouriou Date: Tue, 28 Nov 2023 14:38:54 +0100 Subject: [PATCH 0560/3723] drivers: serial: stm32: Small code refactoring Wakeup-source configuration is about configuring registers. It belongs to uart_stm32_registers_configure(). Signed-off-by: Erwan Gouriou --- drivers/serial/uart_stm32.c | 44 ++++++++++++++++++------------------- 1 file changed, 21 insertions(+), 23 deletions(-) diff --git a/drivers/serial/uart_stm32.c b/drivers/serial/uart_stm32.c index edaff82e033..e36e13b3631 100644 --- a/drivers/serial/uart_stm32.c +++ b/drivers/serial/uart_stm32.c @@ -1962,6 +1962,27 @@ static int uart_stm32_registers_configure(const struct device *dev) } #endif +#if defined(CONFIG_PM) && defined(IS_UART_WAKEUP_FROMSTOP_INSTANCE) + if (config->wakeup_source) { + /* Enable ability to wakeup device in Stop mode + * Effect depends on CONFIG_PM_DEVICE status: + * CONFIG_PM_DEVICE=n : Always active + * CONFIG_PM_DEVICE=y : Controlled by pm_device_wakeup_enable() + */ +#ifdef USART_CR3_WUFIE + LL_USART_SetWKUPType(config->usart, LL_USART_WAKEUP_ON_RXNE); + LL_USART_EnableIT_WKUP(config->usart); + LL_USART_ClearFlag_WKUP(config->usart); +#endif + LL_USART_EnableInStopMode(config->usart); + + if (config->wakeup_line != STM32_EXTI_LINE_NONE) { + /* Prepare the WAKEUP with the expected EXTI line */ + LL_EXTI_EnableIT_0_31(BIT(config->wakeup_line)); + } + } +#endif /* CONFIG_PM */ + LL_USART_Enable(config->usart); #ifdef USART_ISR_TEACK @@ -2016,29 +2037,6 @@ static int uart_stm32_init(const struct device *dev) config->irq_config_func(dev); #endif /* CONFIG_PM || CONFIG_UART_INTERRUPT_DRIVEN || CONFIG_UART_ASYNC_API */ -#if defined(CONFIG_PM) && defined(IS_UART_WAKEUP_FROMSTOP_INSTANCE) - if (config->wakeup_source) { - /* Enable ability to wakeup device in Stop mode - * Effect depends on CONFIG_PM_DEVICE status: - * CONFIG_PM_DEVICE=n : Always active - * CONFIG_PM_DEVICE=y : Controlled by pm_device_wakeup_enable() - */ -#ifdef USART_CR3_WUFIE - LL_USART_Disable(config->usart); - LL_USART_SetWKUPType(config->usart, LL_USART_WAKEUP_ON_RXNE); - LL_USART_EnableIT_WKUP(config->usart); - LL_USART_ClearFlag_WKUP(config->usart); - LL_USART_Enable(config->usart); -#endif - LL_USART_EnableInStopMode(config->usart); - - if (config->wakeup_line != STM32_EXTI_LINE_NONE) { - /* Prepare the WAKEUP with the expected EXTI line */ - LL_EXTI_EnableIT_0_31(BIT(config->wakeup_line)); - } - } -#endif /* CONFIG_PM */ - #ifdef CONFIG_UART_ASYNC_API return uart_stm32_async_init(dev); #else From d2ea9e48068f6c18f3b999dd3ecb1c2376fc7fc4 Mon Sep 17 00:00:00 2001 From: Erwan Gouriou Date: Thu, 30 Nov 2023 11:35:11 +0100 Subject: [PATCH 0561/3723] drivers: serial: stm32wba: Suspension required before stop in DMA Tx abort In a previous change, STM32U5 GPDMA specific behavior was set into a specific configuration applying only to few devices impacted by a specific silicon erratum. As part of this change, dma suspension before dma stop was set to apply to the specific erratum workaround. It appears, this was wrong and dma suspension before dma stop should be done on all devices compatible with stm32u5 dma. This fix re-instantiate the correct behavior. Signed-off-by: Erwan Gouriou --- drivers/serial/uart_stm32.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/serial/uart_stm32.c b/drivers/serial/uart_stm32.c index e36e13b3631..638343528fe 100644 --- a/drivers/serial/uart_stm32.c +++ b/drivers/serial/uart_stm32.c @@ -1633,7 +1633,7 @@ static int uart_stm32_async_tx_abort(const struct device *dev) data->dma_tx.counter = tx_buffer_length - stat.pending_length; } -#ifdef CONFIG_UART_STM32U5_ERRATA_DMAT +#if DT_HAS_COMPAT_STATUS_OKAY(st_stm32u5_dma) dma_suspend(data->dma_tx.dma_dev, data->dma_tx.dma_channel); #endif dma_stop(data->dma_tx.dma_dev, data->dma_tx.dma_channel); From 3754a4b315170d5a385da9fc95906accc52f060b Mon Sep 17 00:00:00 2001 From: Kamil Paszkiet Date: Wed, 29 Nov 2023 09:35:54 +0100 Subject: [PATCH 0562/3723] tests/kernel/timer/timer_behavior: Add possibility to set ip address added ip address parameter for saleae_logic2.py Signed-off-by: Kamil Paszkiet --- tests/kernel/timer/timer_behavior/pytest/saleae_logic2.py | 7 ++++--- tests/kernel/timer/timer_behavior/testcase.yaml | 2 +- 2 files changed, 5 insertions(+), 4 deletions(-) diff --git a/tests/kernel/timer/timer_behavior/pytest/saleae_logic2.py b/tests/kernel/timer/timer_behavior/pytest/saleae_logic2.py index 7ec141dabd3..428677a4376 100644 --- a/tests/kernel/timer/timer_behavior/pytest/saleae_logic2.py +++ b/tests/kernel/timer/timer_behavior/pytest/saleae_logic2.py @@ -16,9 +16,9 @@ from saleae.automation import (CaptureConfiguration, LogicDeviceConfiguration, DigitalTriggerCaptureMode, DigitalTriggerType) -def do_collection(device_id, port, channel, sample_rate, threshold_volts, +def do_collection(device_id, address, port, channel, sample_rate, threshold_volts, seconds, output_dir): - with automation.Manager.connect(port=port) as manager: + with automation.Manager.connect(address=address, port=port) as manager: device_configuration = LogicDeviceConfiguration( enabled_digital_channels=[channel], @@ -74,6 +74,7 @@ def run(seconds, options): options = dict(zip(options[::2], options[1::2])) device_id = options.get('device-id') + address = str(options.get('address')) port = int(options.get('port')) channel = int(options.get('channel')) sample_rate = int(options.get('sample-rate')) @@ -82,7 +83,7 @@ def run(seconds, options): with tempfile.TemporaryDirectory() as output_dir: output_dir = tempfile.mkdtemp() # Add one second to ensure all data is captured - do_collection(device_id, port, channel, sample_rate, threshold_volts, + do_collection(device_id, address, port, channel, sample_rate, threshold_volts, seconds + 1, output_dir) return do_analysis(output_dir) diff --git a/tests/kernel/timer/timer_behavior/testcase.yaml b/tests/kernel/timer/timer_behavior/testcase.yaml index cf761006b73..96a8eb937d4 100644 --- a/tests/kernel/timer/timer_behavior/testcase.yaml +++ b/tests/kernel/timer/timer_behavior/testcase.yaml @@ -22,7 +22,7 @@ tests: harness: pytest harness_config: pytest_args: ['--tool', 'saleae_logic2', '--tool-options', - 'port=10430,channel=1,sample-rate=6_250_000,threshold-volts=3.3'] + 'address=127.0.0.1,port=10430,channel=1,sample-rate=6_250_000,threshold-volts=3.3'] fixture: gpio_timerout extra_configs: - CONFIG_TIMER_EXTERNAL_TEST=y From 953c5f2d32b1d930146c48d9868c039f2538ee06 Mon Sep 17 00:00:00 2001 From: Lukasz Majewski Date: Fri, 24 Nov 2023 15:31:43 +0100 Subject: [PATCH 0563/3723] drivers: net: lan865x: Always read at least one chunk on IRQ received According to the OPEN Alliance 10Base-T1x standard (point 7.7), it is mandatory to read at least single data chunk (no matter if received data is valid or not) to deassert the interrupt in the LAN865x (then the tc6 structure fields are also updated from the footer). Current approach with reading OA_BUFSTS register was providing the required information (RCA and TXC), but could cause transmission "stalls" as this operation (i.e. control, not data transmission) is not causing deassertion of the interrupt IRQ_N line from OA TC6 compliant device. With this patch - the transmission is always performed at least once, so interrupt is always deasserted. As the functionality of oa_tc6_update_buf_info() - i.e reading value of RCA and TXC - has been replaced with extracting data from footer, this function can be safely removed. Signed-off-by: Lukasz Majewski --- drivers/ethernet/eth_lan865x.c | 15 ++++++------ drivers/ethernet/oa_tc6.c | 42 +++------------------------------- drivers/ethernet/oa_tc6.h | 9 -------- 3 files changed, 10 insertions(+), 56 deletions(-) diff --git a/drivers/ethernet/eth_lan865x.c b/drivers/ethernet/eth_lan865x.c index 88141f9d98c..a58bb05a7d6 100644 --- a/drivers/ethernet/eth_lan865x.c +++ b/drivers/ethernet/eth_lan865x.c @@ -449,16 +449,15 @@ static void lan865x_int_thread(const struct device *dev) } /* - * The IRQ_N is asserted when RCA becomes > 0, so update its value - * before reading chunks. + * The IRQ_N is asserted when RCA becomes > 0. As described in + * OPEN Alliance 10BASE-T1x standard it is deasserted when first + * data header is received by LAN865x. + * + * Hence, it is mandatory to ALWAYS read at least one data chunk! */ - if (oa_tc6_update_buf_info(tc6) < 0) { - continue; - } - - while (tc6->rca > 0) { + do { lan865x_read_chunks(dev); - } + } while (tc6->rca > 0); oa_tc6_check_status(tc6); } diff --git a/drivers/ethernet/oa_tc6.c b/drivers/ethernet/oa_tc6.c index 5de831babdc..82a59341e0f 100644 --- a/drivers/ethernet/oa_tc6.c +++ b/drivers/ethernet/oa_tc6.c @@ -257,42 +257,6 @@ static void oa_tc6_update_status(struct oa_tc6 *tc6, uint32_t ftr) tc6->txc = FIELD_GET(OA_DATA_FTR_TXC, ftr); } -int oa_tc6_update_buf_info(struct oa_tc6 *tc6) -{ - uint32_t val; - int ret; - - ret = oa_tc6_reg_read(tc6, OA_BUFSTS, &val); - if (ret < 0) { - return ret; - } - - tc6->rca = FIELD_GET(OA_BUFSTS_RCA, val); - tc6->txc = FIELD_GET(OA_BUFSTS_TXC, val); - - /* - * There is a mismatch in the max value of RBA(RCA) and TXC provided by the - * OA TC6 standard. - * - * The OA_BUFSTS register has 8 bits for RBA(RCA) and TXC (max value is 0x30) - * - * However, with footer, the RBA(RCA) and TXC are saturated to 0x1F maximal - * value (due to 32 bit constrain of footer size). - * - * To avoid any issues, the number read directly from OA_BUFSTS is saturated - * as well. - */ - if (tc6->rca >= OA_TC6_FTR_RCA_MAX) { - tc6->rca = OA_TC6_FTR_RCA_MAX; - } - - if (tc6->txc >= OA_TC6_FTR_TXC_MAX) { - tc6->txc = OA_TC6_FTR_TXC_MAX; - } - - return 0; -} - int oa_tc6_chunk_spi_transfer(struct oa_tc6 *tc6, uint8_t *buf_rx, uint8_t *buf_tx, uint32_t hdr, uint32_t *ftr) { @@ -346,8 +310,8 @@ int oa_tc6_read_status(struct oa_tc6 *tc6, uint32_t *ftr) int oa_tc6_read_chunks(struct oa_tc6 *tc6, struct net_pkt *pkt) { struct net_buf *buf_rx = NULL; - uint8_t chunks, sbo, ebo; uint32_t hdr, ftr; + uint8_t sbo, ebo; int ret; /* @@ -359,7 +323,7 @@ int oa_tc6_read_chunks(struct oa_tc6 *tc6, struct net_pkt *pkt) tc6->concat_buf = NULL; } - for (chunks = tc6->rca; chunks; chunks--) { + do { buf_rx = net_pkt_get_frag(pkt, tc6->cps, OA_TC6_BUF_ALLOC_TIMEOUT); if (!buf_rx) { LOG_ERR("OA RX: Can't allocate RX buffer fordata!"); @@ -443,7 +407,7 @@ int oa_tc6_read_chunks(struct oa_tc6 *tc6, struct net_pkt *pkt) */ break; } - } + } while (tc6->rca > 0); return 0; diff --git a/drivers/ethernet/oa_tc6.h b/drivers/ethernet/oa_tc6.h index 7e82e9db748..0918e1382fa 100644 --- a/drivers/ethernet/oa_tc6.h +++ b/drivers/ethernet/oa_tc6.h @@ -225,15 +225,6 @@ int oa_tc6_chunk_spi_transfer(struct oa_tc6 *tc6, uint8_t *buf_rx, uint8_t *buf_ */ int oa_tc6_read_status(struct oa_tc6 *tc6, uint32_t *ftr); -/** - * @brief Read from OA TC6 device and update buffer information - * - * @param tc6 OA TC6 specific data - * - * @return 0 if successful, <0 otherwise. - */ -int oa_tc6_update_buf_info(struct oa_tc6 *tc6); - /** * @brief Read, modify and write control register from OA TC6 device * From 384ba59c5be27df75e6173b62c269ced8102aaaa Mon Sep 17 00:00:00 2001 From: Lukasz Majewski Date: Mon, 27 Nov 2023 11:15:11 +0100 Subject: [PATCH 0564/3723] drivers: net: tc6: Change LOG_ERR to LOG_DBG when received data not valid As part of IRQ service routine, there is at least one data transmission performed between OA TC6 compliant device and HOST uC. As this transmission can happen when there is no valid data to be read (and its only purpose is to deassert the interrupt) the DV bit in footer may be cleared. As this situation is expected with this approach - the LOG level can be safely lowered from error to debug. Signed-off-by: Lukasz Majewski --- drivers/ethernet/oa_tc6.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/ethernet/oa_tc6.c b/drivers/ethernet/oa_tc6.c index 82a59341e0f..ccb9461be8d 100644 --- a/drivers/ethernet/oa_tc6.c +++ b/drivers/ethernet/oa_tc6.c @@ -351,7 +351,7 @@ int oa_tc6_read_chunks(struct oa_tc6 *tc6, struct net_pkt *pkt) } if (!FIELD_GET(OA_DATA_FTR_DV, ftr)) { - LOG_ERR("OA RX: Data chunk not valid, skip!"); + LOG_DBG("OA RX: Data chunk not valid, skip!"); goto unref_buf; } From 32e64cb8c55c0e9d63ebfd9c430e5dd860278a8d Mon Sep 17 00:00:00 2001 From: Lukasz Majewski Date: Tue, 28 Nov 2023 12:16:40 +0100 Subject: [PATCH 0565/3723] drivers: net: tc6: Handle lost of device synchronization (SYNC == 0) Handle the situation when OA TC6 compliant device signals to the host that its configuration is lost - i.e. the SYNC bit in the footer is cleared. In this (unlikely happen) situation the device is reset and reconfigured. Signed-off-by: Lukasz Majewski --- drivers/ethernet/eth_lan865x.c | 6 +++++- drivers/ethernet/oa_tc6.c | 5 +++++ 2 files changed, 10 insertions(+), 1 deletion(-) diff --git a/drivers/ethernet/eth_lan865x.c b/drivers/ethernet/eth_lan865x.c index a58bb05a7d6..f8dd9327d44 100644 --- a/drivers/ethernet/eth_lan865x.c +++ b/drivers/ethernet/eth_lan865x.c @@ -425,6 +425,7 @@ static void lan865x_int_thread(const struct device *dev) struct lan865x_data *ctx = dev->data; struct oa_tc6 *tc6 = ctx->tc6; uint32_t sts, val, ftr; + int ret; while (true) { k_sem_take(&ctx->int_sem, K_FOREVER); @@ -459,7 +460,10 @@ static void lan865x_int_thread(const struct device *dev) lan865x_read_chunks(dev); } while (tc6->rca > 0); - oa_tc6_check_status(tc6); + ret = oa_tc6_check_status(tc6); + if (ret == -EIO) { + lan865x_gpio_reset(dev); + } } } diff --git a/drivers/ethernet/oa_tc6.c b/drivers/ethernet/oa_tc6.c index ccb9461be8d..e28f31046fc 100644 --- a/drivers/ethernet/oa_tc6.c +++ b/drivers/ethernet/oa_tc6.c @@ -227,6 +227,11 @@ int oa_tc6_check_status(struct oa_tc6 *tc6) { uint32_t sts; + if (!tc6->sync) { + LOG_ERR("SYNC: Configuration lost, reset IC!"); + return -EIO; + } + if (tc6->exst) { /* * Just clear any pending interrupts. From d3c0537ade55d53b39d40f5fa797a549375d4b23 Mon Sep 17 00:00:00 2001 From: Lukasz Majewski Date: Tue, 28 Nov 2023 12:36:50 +0100 Subject: [PATCH 0566/3723] drivers: net: lan865x: Select NET_L2_ETHERNET_MGMT when LAN865x used The NET_L2_ETHERNET_MGMT configuration option is required to allow setting MAC address or PLCA parameters with the LAN865x driver. To avoid mistakes with per-board configuration files - it has been moved to Kconfig and automatically selected when the driver support is enabled. Signed-off-by: Lukasz Majewski --- drivers/ethernet/Kconfig.lan865x | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/ethernet/Kconfig.lan865x b/drivers/ethernet/Kconfig.lan865x index c3bdc2f9b73..d96e5ea68e1 100644 --- a/drivers/ethernet/Kconfig.lan865x +++ b/drivers/ethernet/Kconfig.lan865x @@ -6,6 +6,7 @@ menuconfig ETH_LAN865X default y depends on DT_HAS_MICROCHIP_LAN865X_ENABLED select SPI + select NET_L2_ETHERNET_MGMT help The LAN865X is a low power, 10BASE-T1S transceiver compliant with the IEEE® 802.3cg-2019™ Ethernet standard for long reach, 10 From 8001ca7de4c4f14ed27aecaa7892fd6e9e032bd6 Mon Sep 17 00:00:00 2001 From: Lukasz Majewski Date: Tue, 28 Nov 2023 14:28:15 +0100 Subject: [PATCH 0567/3723] drivers: net: tc6: cosmetic: Remove extra space at oa_tc6_send_chunks Cleanup the extra space. Signed-off-by: Lukasz Majewski --- drivers/ethernet/oa_tc6.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/ethernet/oa_tc6.c b/drivers/ethernet/oa_tc6.c index e28f31046fc..942de4bfb1e 100644 --- a/drivers/ethernet/oa_tc6.c +++ b/drivers/ethernet/oa_tc6.c @@ -197,7 +197,7 @@ int oa_tc6_send_chunks(struct oa_tc6 *tc6, struct net_pkt *pkt) FIELD_PREP(OA_DATA_HDR_SWO, 0); if (i == 1) { - hdr |= FIELD_PREP(OA_DATA_HDR_SV, 1); + hdr |= FIELD_PREP(OA_DATA_HDR_SV, 1); } if (i == chunks) { From 17d9275467fbf8966d54f2a1a060ecff6ab9c280 Mon Sep 17 00:00:00 2001 From: Tomasz Bursztyka Date: Wed, 29 Nov 2023 11:50:48 +0100 Subject: [PATCH 0568/3723] arch/x86: Fix building early console driver io_mapped seems to always exist even though it's not set anywhere, so testing if it is different to 0 to actually define UART_IS_IOPORT_ACCESS. Signed-off-by: Tomasz Bursztyka --- arch/x86/core/early_serial.c | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/arch/x86/core/early_serial.c b/arch/x86/core/early_serial.c index 572b71cf5a0..3a0bc7465e1 100644 --- a/arch/x86/core/early_serial.c +++ b/arch/x86/core/early_serial.c @@ -11,10 +11,11 @@ #include -#define UART_IS_IOPORT_ACCESS \ - DT_NODE_HAS_PROP(DT_CHOSEN(zephyr_console), io_mapped) +#if DT_PROP_OR(DT_CHOSEN(zephyr_console), io_mapped, 0) != 0 +#define UART_IS_IOPORT_ACCESS 1 +#endif -#if UART_IS_IOPORT_ACCESS +#if defined(UART_IS_IOPORT_ACCESS) /* Legacy I/O Port Access to a NS16550 UART */ #define IN(reg) sys_in8(reg + DT_REG_ADDR(DT_CHOSEN(zephyr_console))) #define OUT(reg, val) sys_out8(val, reg + DT_REG_ADDR(DT_CHOSEN(zephyr_console))) @@ -89,7 +90,7 @@ int arch_printk_char_out(int c) void z_x86_early_serial_init(void) { -#if defined(DEVICE_MMIO_IS_IN_RAM) && !UART_IS_IOPORT_ACCESS +#if defined(DEVICE_MMIO_IS_IN_RAM) && !defined(UART_IS_IOPORT_ACCESS) #ifdef X86_SOC_EARLY_SERIAL_PCIDEV struct pcie_bar mbar; pcie_get_mbar(X86_SOC_EARLY_SERIAL_PCIDEV, 0, &mbar); From 9f7209241b6b32a4619127d9c6535fca782bd0cb Mon Sep 17 00:00:00 2001 From: Andrei Emeltchenko Date: Wed, 29 Nov 2023 12:24:39 +0200 Subject: [PATCH 0569/3723] tests: acpi: Refactor ACPi test Use helpers to print scope also for not found entries. Signed-off-by: Andrei Emeltchenko --- tests/arch/x86/info/src/acpi.c | 38 +++++++++++++++------------------- 1 file changed, 17 insertions(+), 21 deletions(-) diff --git a/tests/arch/x86/info/src/acpi.c b/tests/arch/x86/info/src/acpi.c index eae7d560c7d..b09bc8d5bb5 100644 --- a/tests/arch/x86/info/src/acpi.c +++ b/tests/arch/x86/info/src/acpi.c @@ -10,35 +10,30 @@ static const uint32_t dmar_scope[] = {ACPI_DMAR_SCOPE_TYPE_ENDPOINT, ACPI_DMAR_S ACPI_DMAR_SCOPE_TYPE_IOAPIC, ACPI_DMAR_SCOPE_TYPE_HPET, ACPI_DMAR_SCOPE_TYPE_NAMESPACE}; -static void vtd_dev_scope_info(int type, struct acpi_dmar_device_scope *dev_scope, - union acpi_dmar_id *dmar_id, int num_inst) +static const char *get_dmar_scope_type(int type) { - int i = 0; - - printk("\t\t\t. Type: "); - switch (type) { case ACPI_DMAR_SCOPE_TYPE_ENDPOINT: - printk("PCI Endpoint"); - break; + return "PCI Endpoint"; case ACPI_DMAR_SCOPE_TYPE_BRIDGE: - printk("PCI Sub-hierarchy"); - break; + return "PCI Sub-hierarchy"; case ACPI_DMAR_SCOPE_TYPE_IOAPIC: - - break; + return "IOAPIC"; case ACPI_DMAR_SCOPE_TYPE_HPET: - printk("MSI Capable HPET"); - break; + return "MSI Capable HPET"; case ACPI_DMAR_SCOPE_TYPE_NAMESPACE: - printk("ACPI name-space enumerated"); - break; + return "ACPI name-space enumerated"; default: - printk("unknown\n"); - return; + return "unknown"; } +} - printk("\n"); +static void vtd_dev_scope_info(int type, struct acpi_dmar_device_scope *dev_scope, + union acpi_dmar_id *dmar_id, int num_inst) +{ + int i = 0; + + printk("\t\t\t. Type: %s\n", get_dmar_scope_type(type)); printk("\t\t\t. Enumeration ID %u\n", dev_scope->EnumerationId); printk("\t\t\t. PCI Bus %u\n", dev_scope->Bus); @@ -69,9 +64,10 @@ static void vtd_drhd_info(struct acpi_dmar_hardware_unit *drhd) printk("\t\t- Base Address 0x%llx\n", drhd->Address); printk("\t\t- Device Scopes:\n"); - for (i = 0; i < 5; i++) { + for (i = 0; i < ARRAY_SIZE(dmar_scope); i++) { if (acpi_drhd_get(dmar_scope[i], &dev_scope, dmar_id, &num_inst, 4u)) { - printk(" No DRHD entry found for scope type:%d\n", dmar_scope[i]); + printk(" No DRHD entry found for scope type: %s\n", + get_dmar_scope_type(dmar_scope[i])); continue; } From 25599df05e4b060d83d6ccf03ded7b2b411bb7a4 Mon Sep 17 00:00:00 2001 From: Alberto Escolar Piedras Date: Wed, 29 Nov 2023 13:36:27 +0100 Subject: [PATCH 0570/3723] boards nrf5340bsim_cpuapp: Define chosen entropy source Override the chosen entropy source irrespectively of what the SOC may chose. This is to avoid problems as the SOC may select the cryptocell, but we do not support it in the simulated target. Signed-off-by: Alberto Escolar Piedras --- boards/posix/nrf_bsim/nrf5340bsim_nrf5340_cpuapp.dts | 1 + 1 file changed, 1 insertion(+) diff --git a/boards/posix/nrf_bsim/nrf5340bsim_nrf5340_cpuapp.dts b/boards/posix/nrf_bsim/nrf5340bsim_nrf5340_cpuapp.dts index 36cbf9691b3..a7c3d39ace5 100644 --- a/boards/posix/nrf_bsim/nrf5340bsim_nrf5340_cpuapp.dts +++ b/boards/posix/nrf_bsim/nrf5340bsim_nrf5340_cpuapp.dts @@ -45,6 +45,7 @@ }; chosen { + zephyr,entropy = &rng_hci; zephyr,flash = &flash0; zephyr,bt-hci-ipc = &ipc0; nordic,802154-spinel-ipc = &ipc0; From 0bcad093927267f5dc3b4f7d08409265baf82f23 Mon Sep 17 00:00:00 2001 From: Mia Koen Date: Wed, 29 Nov 2023 13:33:33 +0100 Subject: [PATCH 0571/3723] bluetooth: mesh: Doc fix Bluetooth mesh to Mesh SIG has changed Bluetooth mesh to Bluetooth Mesh Updating zephyr docs accordingly Leaving out old release notes Signed-off-by: Mia Koen --- boards/arm/nrf52840_mdk/doc/index.rst | 2 +- boards/riscv/esp32c3_devkitm/doc/index.rst | 2 +- .../riscv/esp32c3_luatos_core/doc/index.rst | 2 +- doc/connectivity/bluetooth/api/mesh.rst | 4 +-- .../bluetooth/api/mesh/access.rst | 4 +-- doc/connectivity/bluetooth/api/mesh/blob.rst | 6 ++-- .../bluetooth/api/mesh/blob_cli.rst | 2 +- .../bluetooth/api/mesh/blob_srv.rst | 2 +- doc/connectivity/bluetooth/api/mesh/cfg.rst | 2 +- .../bluetooth/api/mesh/cfg_cli.rst | 2 +- .../bluetooth/api/mesh/cfg_srv.rst | 4 +-- doc/connectivity/bluetooth/api/mesh/core.rst | 4 +-- doc/connectivity/bluetooth/api/mesh/dfu.rst | 24 ++++++------- .../bluetooth/api/mesh/dfu_srv.rst | 8 ++--- .../bluetooth/api/mesh/health_srv.rst | 4 +-- .../bluetooth/api/mesh/heartbeat.rst | 2 +- .../bluetooth/api/mesh/lcd_cli.rst | 2 +- .../bluetooth/api/mesh/lcd_srv.rst | 2 +- .../bluetooth/api/mesh/models.rst | 4 +-- doc/connectivity/bluetooth/api/mesh/msg.rst | 2 +- .../bluetooth/api/mesh/od_cli.rst | 2 +- .../bluetooth/api/mesh/od_srv.rst | 2 +- .../bluetooth/api/mesh/op_agg_cli.rst | 2 +- .../bluetooth/api/mesh/priv_beacon_cli.rst | 2 +- .../bluetooth/api/mesh/priv_beacon_srv.rst | 2 +- .../bluetooth/api/mesh/provisioning.rst | 8 ++--- doc/connectivity/bluetooth/api/mesh/proxy.rst | 2 +- .../bluetooth/api/mesh/sar_cfg.rst | 4 +-- .../bluetooth/api/mesh/sar_cfg_cli.rst | 2 +- .../bluetooth/api/mesh/sar_cfg_srv.rst | 4 +-- doc/connectivity/bluetooth/api/mesh/shell.rst | 34 +++++++++---------- doc/connectivity/bluetooth/bluetooth-arch.rst | 2 +- doc/connectivity/bluetooth/overview.rst | 2 +- doc/introduction/index.rst | 2 +- doc/kernel/timeutil.rst | 2 +- doc/security/vulnerabilities.rst | 4 +-- include/zephyr/bluetooth/mesh.h | 2 +- include/zephyr/bluetooth/mesh/blob_srv.h | 2 +- include/zephyr/bluetooth/mesh/cfg.h | 2 +- include/zephyr/bluetooth/mesh/dfu_cli.h | 2 +- include/zephyr/bluetooth/mesh/dfu_metadata.h | 4 +-- include/zephyr/bluetooth/mesh/dfu_srv.h | 4 +-- include/zephyr/bluetooth/mesh/main.h | 6 ++-- samples/bluetooth/mesh/README.rst | 2 +- samples/bluetooth/mesh_demo/README.rst | 2 +- samples/bluetooth/mesh_provisioner/README.rst | 2 +- samples/boards/nrf/mesh/onoff-app/README.rst | 2 +- .../onoff_level_lighting_vnd_app/README.rst | 2 +- .../boards/reel_board/mesh_badge/README.rst | 4 +-- subsys/bluetooth/Kconfig.logging | 26 +++++++------- subsys/bluetooth/common/Kconfig | 2 +- subsys/bluetooth/mesh/Kconfig | 20 +++++------ subsys/bluetooth/mesh/access.h | 2 +- subsys/bluetooth/mesh/settings.c | 2 +- subsys/bluetooth/mesh/shell/Kconfig | 10 +++--- subsys/bluetooth/mesh/shell/shell.c | 2 +- tests/bsim/bluetooth/mesh/README.rst | 14 ++++---- tests/bsim/bluetooth/mesh/prj.conf | 2 +- tests/bsim/bluetooth/mesh/prj_mesh1d1.conf | 2 +- tests/bsim/bluetooth/mesh/src/mesh_test.h | 2 +- 60 files changed, 140 insertions(+), 140 deletions(-) diff --git a/boards/arm/nrf52840_mdk/doc/index.rst b/boards/arm/nrf52840_mdk/doc/index.rst index fce05bee593..6e0b24b65f2 100644 --- a/boards/arm/nrf52840_mdk/doc/index.rst +++ b/boards/arm/nrf52840_mdk/doc/index.rst @@ -7,7 +7,7 @@ Overview ******** The nRF52840-MDK is a versatile, easy-to-use IoT hardware platform for -Bluetooth 5, Bluetooth mesh, Thread, IEEE 802.15.4, ANT and 2.4GHz proprietary +Bluetooth 5, Bluetooth Mesh, Thread, IEEE 802.15.4, ANT and 2.4GHz proprietary applications using the nRF52840 SoC. The development kit comes with a fully integrated debugger (also known as diff --git a/boards/riscv/esp32c3_devkitm/doc/index.rst b/boards/riscv/esp32c3_devkitm/doc/index.rst index 6d21b2918c3..26f1521e087 100644 --- a/boards/riscv/esp32c3_devkitm/doc/index.rst +++ b/boards/riscv/esp32c3_devkitm/doc/index.rst @@ -18,7 +18,7 @@ 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 +- A Bluetooth LE subsystem that supports features of Bluetooth 5 and Bluetooth Mesh - Various peripherals: - 12-bit ADC with up to 6 channels diff --git a/boards/riscv/esp32c3_luatos_core/doc/index.rst b/boards/riscv/esp32c3_luatos_core/doc/index.rst index c943931a9e6..fae8e2eb178 100644 --- a/boards/riscv/esp32c3_luatos_core/doc/index.rst +++ b/boards/riscv/esp32c3_luatos_core/doc/index.rst @@ -18,7 +18,7 @@ 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 +- A Bluetooth LE subsystem that supports features of Bluetooth 5 and Bluetooth Mesh - Various peripherals: - 12-bit ADC with up to 6 channels diff --git a/doc/connectivity/bluetooth/api/mesh.rst b/doc/connectivity/bluetooth/api/mesh.rst index 457aa5b6895..f234ff7cedc 100644 --- a/doc/connectivity/bluetooth/api/mesh.rst +++ b/doc/connectivity/bluetooth/api/mesh.rst @@ -3,14 +3,14 @@ Bluetooth Mesh Profile ###################### -The Bluetooth mesh profile adds secure wireless multi-hop communication for +The Bluetooth Mesh profile adds secure wireless multi-hop communication for Bluetooth Low Energy. This module implements the `Bluetooth Mesh Profile Specification v1.0.1 `_. Implementation of the `Bluetooth Mesh Protocol Specification v1.1 `_ is in experimental state. -Read more about Bluetooth mesh on the +Read more about Bluetooth Mesh on the `Bluetooth SIG Website `_. .. toctree:: diff --git a/doc/connectivity/bluetooth/api/mesh/access.rst b/doc/connectivity/bluetooth/api/mesh/access.rst index 2af8e6a03b8..e4a94440556 100644 --- a/doc/connectivity/bluetooth/api/mesh/access.rst +++ b/doc/connectivity/bluetooth/api/mesh/access.rst @@ -3,7 +3,7 @@ Access layer ############ -The access layer is the application's interface to the Bluetooth mesh network. +The access layer is the application's interface to the Bluetooth Mesh network. The access layer provides mechanisms for compartmentalizing the node behavior into elements and models, which are implemented by the application. @@ -113,7 +113,7 @@ number within one publication interval. Extended models =============== -The Bluetooth mesh specification allows the mesh models to extend each other. +The Bluetooth Mesh specification allows the mesh models to extend each other. When a model extends another, it inherits that model's functionality, and extension can be used to construct complex models out of simple ones, leveraging the existing model functionality to avoid defining new opcodes. diff --git a/doc/connectivity/bluetooth/api/mesh/blob.rst b/doc/connectivity/bluetooth/api/mesh/blob.rst index 31f45289560..8395026afe4 100644 --- a/doc/connectivity/bluetooth/api/mesh/blob.rst +++ b/doc/connectivity/bluetooth/api/mesh/blob.rst @@ -5,7 +5,7 @@ BLOB Transfer models The Binary Large Object (BLOB) Transfer models implement the Bluetooth Mesh Binary Large Object Transfer Model specification version 1.0 and provide functionality for sending large binary objects -from a single source to many Target nodes over the Bluetooth mesh network. It is the underlying +from a single source to many Target nodes over the Bluetooth Mesh network. It is the underlying transport method for the :ref:`bluetooth_mesh_dfu`, but may be used for other object transfer purposes. The implementation is in experimental state. @@ -50,7 +50,7 @@ structure of the BLOB, and applications are free to define any encoding or compr on the data itself. The BLOB transfer protocol does not provide any built-in integrity checks, encryption or -authentication of the BLOB data. However, the underlying encryption of the Bluetooth mesh protocol +authentication of the BLOB data. However, the underlying encryption of the Bluetooth Mesh protocol provides data integrity checks and protects the contents of the BLOB from third parties using network and application level encryption. @@ -68,7 +68,7 @@ Chunks ------ Each block is divided into chunks. A chunk is the smallest data unit in the BLOB transfer, and must -fit inside a single Bluetooth mesh access message excluding the opcode (379 bytes or less). The +fit inside a single Bluetooth Mesh access message excluding the opcode (379 bytes or less). The mechanism for transferring chunks depends on the transfer mode. When operating in Push BLOB Transfer Mode, the chunks are sent as unacknowledged packets from the diff --git a/doc/connectivity/bluetooth/api/mesh/blob_cli.rst b/doc/connectivity/bluetooth/api/mesh/blob_cli.rst index 25b90c281c4..b4193d50334 100644 --- a/doc/connectivity/bluetooth/api/mesh/blob_cli.rst +++ b/doc/connectivity/bluetooth/api/mesh/blob_cli.rst @@ -67,7 +67,7 @@ Target nodes having the BLOB Transfer Server model subscribe to this group addre Using group addresses for transferring the BLOBs can generally increase the transfer speed, as the BLOB Transfer Client sends each message to all Target nodes at the same time. However, sending -large, segmented messages to group addresses in Bluetooth mesh is generally less reliable than +large, segmented messages to group addresses in Bluetooth Mesh is generally less reliable than sending them to unicast addresses, as there is no transport layer acknowledgment mechanism for groups. This can lead to longer recovery periods at the end of each block, and increases the risk of losing Target nodes. Using group addresses for BLOB transfers will generally only pay off if the diff --git a/doc/connectivity/bluetooth/api/mesh/blob_srv.rst b/doc/connectivity/bluetooth/api/mesh/blob_srv.rst index 918b9493ff9..0d13e92148e 100644 --- a/doc/connectivity/bluetooth/api/mesh/blob_srv.rst +++ b/doc/connectivity/bluetooth/api/mesh/blob_srv.rst @@ -77,7 +77,7 @@ Transfer recovery ***************** The state of the BLOB transfer is stored persistently. If a reboot occurs, the BLOB Transfer Server -will attempt to recover the transfer. When the Bluetooth mesh subsystem is started (for instance by +will attempt to recover the transfer. When the Bluetooth Mesh subsystem is started (for instance by calling :c:func:`bt_mesh_init`), the BLOB Transfer Server will check for aborted transfers, and call the :c:member:`recover ` callback if there is any. In the recover callback, the user must provide a BLOB stream to use for the rest of the transfer. If the recover diff --git a/doc/connectivity/bluetooth/api/mesh/cfg.rst b/doc/connectivity/bluetooth/api/mesh/cfg.rst index 01d3c9ca2e5..e178984210d 100644 --- a/doc/connectivity/bluetooth/api/mesh/cfg.rst +++ b/doc/connectivity/bluetooth/api/mesh/cfg.rst @@ -6,7 +6,7 @@ Runtime Configuration The runtime configuration API allows applications to change their runtime configuration directly, without going through the Configuration models. -Bluetooth mesh nodes should generally be configured by a central network +Bluetooth Mesh nodes should generally be configured by a central network configurator device with a :ref:`bluetooth_mesh_models_cfg_cli` model. Each mesh node instantiates a :ref:`bluetooth_mesh_models_cfg_srv` model that the Configuration Client can communicate with to change the node configuration. In some diff --git a/doc/connectivity/bluetooth/api/mesh/cfg_cli.rst b/doc/connectivity/bluetooth/api/mesh/cfg_cli.rst index bf84edc6b86..300c8ee3bc1 100644 --- a/doc/connectivity/bluetooth/api/mesh/cfg_cli.rst +++ b/doc/connectivity/bluetooth/api/mesh/cfg_cli.rst @@ -3,7 +3,7 @@ Configuration Client #################### -The Configuration Client model is a foundation model defined by the Bluetooth mesh +The Configuration Client model is a foundation model defined by the Bluetooth Mesh specification. It provides functionality for configuring most parameters of a mesh node, including encryption keys, model configuration and feature enabling. diff --git a/doc/connectivity/bluetooth/api/mesh/cfg_srv.rst b/doc/connectivity/bluetooth/api/mesh/cfg_srv.rst index 84f174df88b..8f595bf9b11 100644 --- a/doc/connectivity/bluetooth/api/mesh/cfg_srv.rst +++ b/doc/connectivity/bluetooth/api/mesh/cfg_srv.rst @@ -3,7 +3,7 @@ Configuration Server #################### -The Configuration Server model is a foundation model defined by the Bluetooth mesh +The Configuration Server model is a foundation model defined by the Bluetooth Mesh specification. The Configuration Server model controls most parameters of the mesh node. It does not have an API of its own, but relies on a :ref:`bluetooth_mesh_models_cfg_cli` to control it. @@ -14,7 +14,7 @@ mesh node. It does not have an API of its own, but relies on a should be set through Kconfig, and the Heartbeat feature should be controlled through the :ref:`bluetooth_mesh_heartbeat` API. -The Configuration Server model is mandatory on all Bluetooth mesh nodes, and +The Configuration Server model is mandatory on all Bluetooth Mesh nodes, and must only be instantiated on the primary element. API reference diff --git a/doc/connectivity/bluetooth/api/mesh/core.rst b/doc/connectivity/bluetooth/api/mesh/core.rst index b9fdd164257..94e2b8a6e5e 100644 --- a/doc/connectivity/bluetooth/api/mesh/core.rst +++ b/doc/connectivity/bluetooth/api/mesh/core.rst @@ -3,7 +3,7 @@ Core #### -The core provides functionality for managing the general Bluetooth mesh +The core provides functionality for managing the general Bluetooth Mesh state. .. _bluetooth_mesh_lpn: @@ -117,7 +117,7 @@ Advertisement identity All mesh stack bearers advertise data with the :c:macro:`BT_ID_DEFAULT` local identity. The value is preset in the mesh stack implementation. When Bluetooth® Low Energy (LE) -and Bluetooth mesh coexist on the same device, the application should allocate and +and Bluetooth Mesh coexist on the same device, the application should allocate and configure another local identity for Bluetooth LE purposes before starting the communication. API reference diff --git a/doc/connectivity/bluetooth/api/mesh/dfu.rst b/doc/connectivity/bluetooth/api/mesh/dfu.rst index 9cf55e244d6..6718b3ea0ce 100644 --- a/doc/connectivity/bluetooth/api/mesh/dfu.rst +++ b/doc/connectivity/bluetooth/api/mesh/dfu.rst @@ -3,16 +3,16 @@ Device Firmware Update (DFU) ############################ -Bluetooth mesh supports the distribution of firmware images across a mesh network. The Bluetooth +Bluetooth Mesh supports the distribution of firmware images across a mesh network. The Bluetooth mesh DFU subsystem implements the Bluetooth Mesh Device Firmware Update Model specification version 1.0. The implementation is in experimental state. -Bluetooth mesh DFU implements a distribution mechanism for firmware images, and does not put any +Bluetooth Mesh DFU implements a distribution mechanism for firmware images, and does not put any restrictions on the size, format or usage of the images. The primary design goal of the subsystem is -to provide the qualifiable parts of the Bluetooth mesh DFU specification, and leave the usage, +to provide the qualifiable parts of the Bluetooth Mesh DFU specification, and leave the usage, firmware validation and deployment to the application. -The DFU specification is implemented in the Zephyr Bluetooth mesh DFU subsystem as three separate +The DFU specification is implemented in the Zephyr Bluetooth Mesh DFU subsystem as three separate models: .. toctree:: @@ -28,7 +28,7 @@ Overview DFU roles ========= -The Bluetooth mesh DFU subsystem defines three different roles the mesh nodes have to assume in the +The Bluetooth Mesh DFU subsystem defines three different roles the mesh nodes have to assume in the distribution of firmware images: Target node @@ -47,20 +47,20 @@ Distributor image to the Target nodes. Initiator - The Initiator role is typically implemented by the same device that implements the Bluetooth mesh + The Initiator role is typically implemented by the same device that implements the Bluetooth Mesh :ref:`Provisioner ` and :ref:`Configurator ` roles. The Initiator needs a full overview of the potential Target nodes and their firmware, and will control (and initiate) all firmware updates. The - Initiator role is not implemented in the Zephyr Bluetooth mesh DFU subsystem. + Initiator role is not implemented in the Zephyr Bluetooth Mesh DFU subsystem. .. figure:: images/dfu_roles_mesh.svg :align: center :alt: Graphic overview of the DFU roles mesh nodes can have during the process of image distribution - DFU roles and the associated Bluetooth mesh models + DFU roles and the associated Bluetooth Mesh models -Bluetooth mesh applications may combine the DFU roles in any way they'd like, and even take on +Bluetooth Mesh applications may combine the DFU roles in any way they'd like, and even take on multiple instances of the same role by instantiating the models on separate elements. For instance, the Distributor and Initiator role can be combined by instantiating the :ref:`bluetooth_mesh_dfu_cli` on the Initiator node and calling its API directly. @@ -76,7 +76,7 @@ Firmware Update Client model directly, e.g. over a serial protocol. Stages ====== -The Bluetooth mesh DFU process is designed to act in three stages: +The Bluetooth Mesh DFU process is designed to act in three stages: Upload stage First, the image is uploaded to a Distributor in a mesh network by an external entity, such as a @@ -131,7 +131,7 @@ Firmware metadata Target node. The firmware metadata is optional, and its maximum length is determined by :kconfig:option:`CONFIG_BT_MESH_DFU_METADATA_MAXLEN`. - The Bluetooth mesh DFU subsystem in Zephyr provides its own metadata format + The Bluetooth Mesh DFU subsystem in Zephyr provides its own metadata format (:c:struct:`bt_mesh_dfu_metadata`) together with a set of related functions that can be used by an end product. The support for it is enabled using the :kconfig:option:`CONFIG_BT_MESH_DFU_METADATA` option. The format of the metadata is presented in @@ -299,7 +299,7 @@ following steps: node firmware image index and the firmware image metadata. Each Target node performs a metadata check and prepares their BLOB Transfer Server model for the transfer, before sending a status response to the Firmware Update Client, indicating if the firmware update will have any effect on - the Bluetooth mesh state of the node. + the Bluetooth Mesh state of the node. #. The Distributor's BLOB Transfer Client model transfers the firmware image to all Target nodes. #. Once the BLOB transfer has been received, the Target nodes' applications verify that the firmware is valid by performing checks such as signature verification or image checksums against the image diff --git a/doc/connectivity/bluetooth/api/mesh/dfu_srv.rst b/doc/connectivity/bluetooth/api/mesh/dfu_srv.rst index 2642dec8cc9..105bdecb86c 100644 --- a/doc/connectivity/bluetooth/api/mesh/dfu_srv.rst +++ b/doc/connectivity/bluetooth/api/mesh/dfu_srv.rst @@ -16,7 +16,7 @@ Firmware images The Firmware Update Server holds a list of all the updatable firmware images on the device. The full list shall be passed to the server through the ``_imgs`` parameter in -:c:macro:`BT_MESH_DFU_SRV_INIT`, and must be populated before the Bluetooth mesh subsystem is +:c:macro:`BT_MESH_DFU_SRV_INIT`, and must be populated before the Bluetooth Mesh subsystem is started. Each firmware image in the image list must be independently updatable, and should have its own firmware ID. @@ -33,9 +33,9 @@ application is described below: .. figure:: images/dfu_srv.svg :align: center - :alt: Bluetooth mesh Firmware Update Server transfer + :alt: Bluetooth Mesh Firmware Update Server transfer - Bluetooth mesh Firmware Update Server transfer + Bluetooth Mesh Firmware Update Server transfer Transfer check ============== @@ -118,7 +118,7 @@ updated image. When the transfer applies to the mesh application itself, the device might have to reboot as part of the swap. This restart can be performed from inside the apply callback, or done asynchronously. After booting up with the new firmware, the firmware image table should be updated before the -Bluetooth mesh subsystem is started. +Bluetooth Mesh subsystem is started. The Distributor will read out the firmware image table to confirm that the transfer was successfully applied. If the metadata check indicated that the device would become unprovisioned, the Target node diff --git a/doc/connectivity/bluetooth/api/mesh/health_srv.rst b/doc/connectivity/bluetooth/api/mesh/health_srv.rst index 84c543b4766..6f7b1fc3f33 100644 --- a/doc/connectivity/bluetooth/api/mesh/health_srv.rst +++ b/doc/connectivity/bluetooth/api/mesh/health_srv.rst @@ -21,7 +21,7 @@ necessarily damaging to the device. Errors indicate conditions that are outside of the node's design limits, and may have caused invalid behavior or permanent damage to the device. -Fault values ``0x01`` to ``0x7f`` are reserved for the Bluetooth mesh +Fault values ``0x01`` to ``0x7f`` are reserved for the Bluetooth Mesh specification, and the full list of specification defined faults are available in :ref:`bluetooth_mesh_health_faults`. Fault values ``0x80`` to ``0xff`` are vendor specific. The list of faults are always reported with a company ID to @@ -57,6 +57,6 @@ API reference Health faults ============= -Fault values defined by the Bluetooth mesh specification. +Fault values defined by the Bluetooth Mesh specification. .. doxygengroup:: bt_mesh_health_faults diff --git a/doc/connectivity/bluetooth/api/mesh/heartbeat.rst b/doc/connectivity/bluetooth/api/mesh/heartbeat.rst index 16c2bfa7840..706625849c1 100644 --- a/doc/connectivity/bluetooth/api/mesh/heartbeat.rst +++ b/doc/connectivity/bluetooth/api/mesh/heartbeat.rst @@ -3,7 +3,7 @@ Heartbeat ######### -The Heartbeat feature provides functionality for monitoring Bluetooth mesh nodes +The Heartbeat feature provides functionality for monitoring Bluetooth Mesh nodes and determining the distance between nodes. The Heartbeat feature is configured through the :ref:`bluetooth_mesh_models_cfg_srv` model. diff --git a/doc/connectivity/bluetooth/api/mesh/lcd_cli.rst b/doc/connectivity/bluetooth/api/mesh/lcd_cli.rst index 0eca28f1b2a..96189e21dd3 100644 --- a/doc/connectivity/bluetooth/api/mesh/lcd_cli.rst +++ b/doc/connectivity/bluetooth/api/mesh/lcd_cli.rst @@ -3,7 +3,7 @@ Large Composition Data Client ############################# -The Large Composition Data Client model is a foundation model defined by the Bluetooth mesh +The Large Composition Data Client model is a foundation model defined by the Bluetooth Mesh specification. The model is optional, and is enabled through the :kconfig:option:`CONFIG_BT_MESH_LARGE_COMP_DATA_CLI` option. diff --git a/doc/connectivity/bluetooth/api/mesh/lcd_srv.rst b/doc/connectivity/bluetooth/api/mesh/lcd_srv.rst index f96436138b7..f67b31c27f8 100644 --- a/doc/connectivity/bluetooth/api/mesh/lcd_srv.rst +++ b/doc/connectivity/bluetooth/api/mesh/lcd_srv.rst @@ -3,7 +3,7 @@ Large Composition Data Server ############################# -The Large Composition Data Server model is a foundation model defined by the Bluetooth mesh +The Large Composition Data Server model is a foundation model defined by the Bluetooth Mesh specification. The model is optional, and is enabled through the :kconfig:option:`CONFIG_BT_MESH_LARGE_COMP_DATA_SRV` option. diff --git a/doc/connectivity/bluetooth/api/mesh/models.rst b/doc/connectivity/bluetooth/api/mesh/models.rst index 3f5f94152ce..94c3914ca53 100644 --- a/doc/connectivity/bluetooth/api/mesh/models.rst +++ b/doc/connectivity/bluetooth/api/mesh/models.rst @@ -6,7 +6,7 @@ Mesh models Foundation models ***************** -The Bluetooth mesh specification defines foundation models that can be +The Bluetooth Mesh specification defines foundation models that can be used by network administrators to configure and diagnose mesh nodes. .. toctree:: @@ -34,7 +34,7 @@ used by network administrators to configure and diagnose mesh nodes. Model specification models ************************** -In addition to the foundation models defined in the Bluetooth mesh specification, the Bluetooth Mesh +In addition to the foundation models defined in the Bluetooth Mesh specification, the Bluetooth Mesh Model Specification defines several models, some of which are implemented in Zephyr: .. toctree:: diff --git a/doc/connectivity/bluetooth/api/mesh/msg.rst b/doc/connectivity/bluetooth/api/mesh/msg.rst index ae8b968198a..614d2604d90 100644 --- a/doc/connectivity/bluetooth/api/mesh/msg.rst +++ b/doc/connectivity/bluetooth/api/mesh/msg.rst @@ -3,7 +3,7 @@ Message ####### -The Bluetooth mesh message provides set of structures, macros and functions used +The Bluetooth Mesh message provides set of structures, macros and functions used for preparing message buffers, managing message and acknowledged message contexts. diff --git a/doc/connectivity/bluetooth/api/mesh/od_cli.rst b/doc/connectivity/bluetooth/api/mesh/od_cli.rst index 5fc841716ce..e419acb7572 100644 --- a/doc/connectivity/bluetooth/api/mesh/od_cli.rst +++ b/doc/connectivity/bluetooth/api/mesh/od_cli.rst @@ -3,7 +3,7 @@ On-Demand Private Proxy Client ############################## -The On-Demand Private Proxy Client model is a foundation model defined by the Bluetooth mesh +The On-Demand Private Proxy Client model is a foundation model defined by the Bluetooth Mesh specification. The model is optional, and is enabled with the :kconfig:option:`CONFIG_BT_MESH_OD_PRIV_PROXY_CLI` option. diff --git a/doc/connectivity/bluetooth/api/mesh/od_srv.rst b/doc/connectivity/bluetooth/api/mesh/od_srv.rst index 700517e4283..3c2f993bb30 100644 --- a/doc/connectivity/bluetooth/api/mesh/od_srv.rst +++ b/doc/connectivity/bluetooth/api/mesh/od_srv.rst @@ -3,7 +3,7 @@ On-Demand Private Proxy Server ############################## -The On-Demand Private Proxy Server model is a foundation model defined by the Bluetooth mesh +The On-Demand Private Proxy Server model is a foundation model defined by the Bluetooth Mesh specification. It is enabled with the :kconfig:option:`CONFIG_BT_MESH_OD_PRIV_PROXY_SRV` option. The On-Demand Private Proxy Server model was introduced in the Bluetooth Mesh Protocol Specification diff --git a/doc/connectivity/bluetooth/api/mesh/op_agg_cli.rst b/doc/connectivity/bluetooth/api/mesh/op_agg_cli.rst index 148557a4e81..4648b4495cd 100644 --- a/doc/connectivity/bluetooth/api/mesh/op_agg_cli.rst +++ b/doc/connectivity/bluetooth/api/mesh/op_agg_cli.rst @@ -3,7 +3,7 @@ Opcodes Aggregator Client ######################### -The Opcodes Aggregator Client model is a foundation model defined by the Bluetooth mesh +The Opcodes Aggregator Client model is a foundation model defined by the Bluetooth Mesh specification. It is an optional model, enabled with the :kconfig:option:`CONFIG_BT_MESH_OP_AGG_CLI` option. diff --git a/doc/connectivity/bluetooth/api/mesh/priv_beacon_cli.rst b/doc/connectivity/bluetooth/api/mesh/priv_beacon_cli.rst index cb531a4c3c8..c9bcc8e5eb1 100644 --- a/doc/connectivity/bluetooth/api/mesh/priv_beacon_cli.rst +++ b/doc/connectivity/bluetooth/api/mesh/priv_beacon_cli.rst @@ -11,7 +11,7 @@ The Private Beacon Client model is introduced in the Bluetooth Mesh Protocol Specification version 1.1, and provides functionality for configuring the :ref:`bluetooth_mesh_models_priv_beacon_srv` models. -The Private Beacons feature adds privacy to the different Bluetooth mesh +The Private Beacons feature adds privacy to the different Bluetooth Mesh beacons by periodically randomizing the beacon input data. This protects the mesh node from being tracked by devices outside the mesh network, and hides the network's IV index, IV update and the Key Refresh state. diff --git a/doc/connectivity/bluetooth/api/mesh/priv_beacon_srv.rst b/doc/connectivity/bluetooth/api/mesh/priv_beacon_srv.rst index 3c17cc44675..62450634a31 100644 --- a/doc/connectivity/bluetooth/api/mesh/priv_beacon_srv.rst +++ b/doc/connectivity/bluetooth/api/mesh/priv_beacon_srv.rst @@ -11,7 +11,7 @@ The Private Beacon Server model is introduced in the Bluetooth Mesh Protocol Specification version 1.1, and controls the mesh node's Private Beacon state, Private GATT Proxy state and Private Node Identity state. -The Private Beacons feature adds privacy to the different Bluetooth mesh +The Private Beacons feature adds privacy to the different Bluetooth Mesh beacons by periodically randomizing the beacon input data. This protects the mesh node from being tracked by devices outside the mesh network, and hides the network's IV index, IV update and the Key Refresh state. The Private Beacon Server diff --git a/doc/connectivity/bluetooth/api/mesh/provisioning.rst b/doc/connectivity/bluetooth/api/mesh/provisioning.rst index 36fa38927a3..685c9dda455 100644 --- a/doc/connectivity/bluetooth/api/mesh/provisioning.rst +++ b/doc/connectivity/bluetooth/api/mesh/provisioning.rst @@ -12,15 +12,15 @@ two devices operating in the following roles: Provisioning process. Before the provisioning process starts, the provisionee is an *unprovisioned device*. -The Provisioning module in the Zephyr Bluetooth mesh stack supports both the +The Provisioning module in the Zephyr Bluetooth Mesh stack supports both the Advertising and GATT Provisioning bearers for the provisionee role, as well as the Advertising Provisioning bearer for the provisioner role. The Provisioning process ************************ -All Bluetooth mesh nodes must be provisioned before they can participate in a -Bluetooth mesh network. The Provisioning API provides all the functionality +All Bluetooth Mesh nodes must be provisioned before they can participate in a +Bluetooth Mesh network. The Provisioning API provides all the functionality necessary for a device to become a provisioned mesh node. Provisioning is a five-step process, involving the following steps: @@ -176,7 +176,7 @@ Depending on the choice of public key exchange mechanism and authentication meth the provisioning process can be secure or insecure. On May 24th 2021, ANSSI `disclosed `_ -a set of vulnerabilities in the Bluetooth mesh provisioning protocol that showcased +a set of vulnerabilities in the Bluetooth Mesh provisioning protocol that showcased how the low entropy provided by the Blink, Vibrate, Push, Twist and Input/Output numeric OOB methods could be exploited in impersonation and MITM attacks. In response, the Bluetooth SIG has reclassified these OOB methods as diff --git a/doc/connectivity/bluetooth/api/mesh/proxy.rst b/doc/connectivity/bluetooth/api/mesh/proxy.rst index 823401c9571..5e905f2c9ef 100644 --- a/doc/connectivity/bluetooth/api/mesh/proxy.rst +++ b/doc/connectivity/bluetooth/api/mesh/proxy.rst @@ -3,7 +3,7 @@ Proxy ##### -The Proxy feature allows legacy devices like phones to access the Bluetooth mesh network through +The Proxy feature allows legacy devices like phones to access the Bluetooth Mesh network through GATT. The Proxy feature is only compiled in if the :kconfig:option:`CONFIG_BT_MESH_GATT_PROXY` option is set. The Proxy feature state is controlled by the :ref:`bluetooth_mesh_models_cfg_srv`, and the initial value can be set with :c:member:`bt_mesh_cfg_srv.gatt_proxy`. diff --git a/doc/connectivity/bluetooth/api/mesh/sar_cfg.rst b/doc/connectivity/bluetooth/api/mesh/sar_cfg.rst index a0aa2b46a3e..4f3354945c9 100644 --- a/doc/connectivity/bluetooth/api/mesh/sar_cfg.rst +++ b/doc/connectivity/bluetooth/api/mesh/sar_cfg.rst @@ -4,7 +4,7 @@ Segmentation and reassembly (SAR) ################################# Segmentation and reassembly (SAR) provides a way of handling larger upper transport layer messages -in a mesh network, with a purpose of enhancing the Bluetooth mesh throughput. The segmentation and +in a mesh network, with a purpose of enhancing the Bluetooth Mesh throughput. The segmentation and reassembly mechanism is used by the lower transport layer. The lower transport layer defines how the upper transport layer PDUs are segmented and reassembled @@ -23,7 +23,7 @@ required. Set the ``send rel`` flag (see :c:struct:`bt_mesh_msg_ctx`) to use the transmission and acknowledge single-segment segmented messages. The transport layer is able to transport up to 32 segments with its SAR mechanism, with a maximum -message (PDU) size of 384 octets. To configure message size for the Bluetooth mesh stack, use the +message (PDU) size of 384 octets. To configure message size for the Bluetooth Mesh stack, use the following Kconfig options: * :kconfig:option:`CONFIG_BT_MESH_RX_SEG_MAX` to set the maximum number of segments in an incoming message. diff --git a/doc/connectivity/bluetooth/api/mesh/sar_cfg_cli.rst b/doc/connectivity/bluetooth/api/mesh/sar_cfg_cli.rst index b017b53a01a..1e2ab6c47a1 100644 --- a/doc/connectivity/bluetooth/api/mesh/sar_cfg_cli.rst +++ b/doc/connectivity/bluetooth/api/mesh/sar_cfg_cli.rst @@ -3,7 +3,7 @@ SAR Configuration Client ######################## -The SAR Configuration Client model is a foundation model defined by the Bluetooth mesh +The SAR Configuration Client model is a foundation model defined by the Bluetooth Mesh specification. It is an optional model, enabled with the :kconfig:option:`CONFIG_BT_MESH_SAR_CFG_CLI` configuration option. diff --git a/doc/connectivity/bluetooth/api/mesh/sar_cfg_srv.rst b/doc/connectivity/bluetooth/api/mesh/sar_cfg_srv.rst index 2ea1446c9ea..4280fae1350 100644 --- a/doc/connectivity/bluetooth/api/mesh/sar_cfg_srv.rst +++ b/doc/connectivity/bluetooth/api/mesh/sar_cfg_srv.rst @@ -3,13 +3,13 @@ SAR Configuration Server ######################## -The SAR Configuration Server model is a foundation model defined by the Bluetooth mesh +The SAR Configuration Server model is a foundation model defined by the Bluetooth Mesh specification. It is an optional model, enabled with the :kconfig:option:`CONFIG_BT_MESH_SAR_CFG_SRV` configuration option. The SAR Configuration Server model is introduced in the Bluetooth Mesh Protocol Specification version 1.1, and it supports the configuration of the -:ref:`segmentation and reassembly (SAR) ` behavior of a Bluetooth mesh node. +:ref:`segmentation and reassembly (SAR) ` behavior of a Bluetooth Mesh node. The model defines a set of states and messages for the SAR configuration. The SAR Configuration Server model defines two states, SAR Transmitter state and SAR Receiver state. diff --git a/doc/connectivity/bluetooth/api/mesh/shell.rst b/doc/connectivity/bluetooth/api/mesh/shell.rst index 66bfcdf6168..9d5829fe380 100644 --- a/doc/connectivity/bluetooth/api/mesh/shell.rst +++ b/doc/connectivity/bluetooth/api/mesh/shell.rst @@ -3,32 +3,32 @@ Bluetooth Mesh Shell #################### -The Bluetooth mesh shell subsystem provides a set of Bluetooth mesh shell commands for the -:ref:`shell_api` module. It allows for testing and exploring the Bluetooth mesh API through an +The Bluetooth Mesh shell subsystem provides a set of Bluetooth Mesh shell commands for the +:ref:`shell_api` module. It allows for testing and exploring the Bluetooth Mesh API through an interactive interface, without having to write an application. -The Bluetooth mesh shell interface provides access to most Bluetooth mesh features, including +The Bluetooth Mesh shell interface provides access to most Bluetooth Mesh features, including provisioning, configuration, and message sending. Prerequisites ************* -The Bluetooth mesh shell subsystem depends on the application to create the composition data and do +The Bluetooth Mesh shell subsystem depends on the application to create the composition data and do the mesh initialization. Application *********** -The Bluetooth mesh shell subsystem is most easily used through the Bluetooth mesh shell application +The Bluetooth Mesh shell subsystem is most easily used through the Bluetooth Mesh shell application under ``tests/bluetooth/mesh_shell``. See :ref:`shell_api` for information on how to connect and -interact with the Bluetooth mesh shell application. +interact with the Bluetooth Mesh shell application. Basic usage *********** -The Bluetooth mesh shell subsystem adds a single ``mesh`` command, which holds a set of +The Bluetooth Mesh shell subsystem adds a single ``mesh`` command, which holds a set of sub-commands. Every time the device boots up, make sure to call ``mesh init`` before any of the -other Bluetooth mesh shell commands can be called:: +other Bluetooth Mesh shell commands can be called:: uart:~$ mesh init @@ -82,7 +82,7 @@ Message sending =============== With an application key added (see above), the mesh node's transition parameters are all valid, and -the Bluetooth mesh shell can send raw mesh messages through the network. +the Bluetooth Mesh shell can send raw mesh messages through the network. For example, to send a Generic OnOff Set message, call:: @@ -107,7 +107,7 @@ configured network and application keys will receive and process the messages we Sending raw mesh packets is a good way to test model message handler implementations during development, as it can be done without having to implement the sending model. By default, only the -reception of the model messages can be tested this way, as the Bluetooth mesh shell only includes +reception of the model messages can be tested this way, as the Bluetooth Mesh shell only includes the foundation models. To receive a packet in the mesh node, you have to add a model with a valid opcode handler list to the composition data in ``subsys/bluetooth/mesh/shell.c``, and print the incoming message to the shell in the handler callback. @@ -115,7 +115,7 @@ incoming message to the shell in the handler callback. Parameter formats ***************** -The Bluetooth mesh shell commands are parsed with a variety of formats: +The Bluetooth Mesh shell commands are parsed with a variety of formats: .. list-table:: Parameter formats :widths: 1 4 2 @@ -139,12 +139,12 @@ The Bluetooth mesh shell commands are parsed with a variety of formats: Commands ******** -The Bluetooth mesh shell implements a large set of commands. Some of the commands accept parameters, +The Bluetooth Mesh shell implements a large set of commands. Some of the commands accept parameters, which are mentioned in brackets after the command name. For example, ``mesh lpn set ``. Mandatory parameters are marked with angle brackets (e.g. ````), and optional parameters are marked with square brackets (e.g. ``[DstAddr]``). -The Bluetooth mesh shell commands are divided into the following groups: +The Bluetooth Mesh shell commands are divided into the following groups: .. contents:: :depth: 1 @@ -500,10 +500,10 @@ application. This shell module can be used for configuring itself and other node network. The Configuration Client uses general message parameters set by ``mesh target dst`` and ``mesh -target net`` to target specific nodes. When the Bluetooth mesh shell node is provisioned, given that +target net`` to target specific nodes. When the Bluetooth Mesh shell node is provisioned, given that the :kconfig:option:`CONFIG_BT_MESH_SHELL_PROV_CTX_INSTANCE` option is enabled with the shell provisioning context initialized, the Configuration Client model targets itself by default. -Similarly, when another node has been provisioned by the Bluetooth mesh shell, the Configuration +Similarly, when another node has been provisioned by the Bluetooth Mesh shell, the Configuration Client model targets the new node. In most common use-cases, the Configuration Client is depending on the provisioning features and the Configuration database to be fully functional. The Configuration Client always sends messages using the Device key bound to the destination address, so @@ -1645,7 +1645,7 @@ The Private Beacon Client model is an optional mesh subsystem that can be enable Opcodes Aggregator Client ------------------------- -The Opcodes Aggregator client is an optional Bluetooth mesh model that can be enabled through the +The Opcodes Aggregator client is an optional Bluetooth Mesh model that can be enabled through the :kconfig:option:`CONFIG_BT_MESH_OP_AGG_CLI` configuration option. The Opcodes Aggregator Client model is used to support the functionality of dispatching a sequence of access layer messages to nodes supporting the Opcodes Aggregator Server model. @@ -1675,7 +1675,7 @@ nodes supporting the Opcodes Aggregator Server model. Remote Provisioning Client -------------------------- -The Remote Provisioning Client is an optional Bluetooth mesh model enabled through the +The Remote Provisioning Client is an optional Bluetooth Mesh model enabled through the :kconfig:option:`CONFIG_BT_MESH_RPR_CLI` configuration option. The Remote Provisioning Client model provides support for remote provisioning of devices into a mesh network by using the Remote Provisioning Server model. diff --git a/doc/connectivity/bluetooth/bluetooth-arch.rst b/doc/connectivity/bluetooth/bluetooth-arch.rst index 9b455e680d0..ed0cf1ea9f6 100644 --- a/doc/connectivity/bluetooth/bluetooth-arch.rst +++ b/doc/connectivity/bluetooth/bluetooth-arch.rst @@ -248,7 +248,7 @@ Each role comes with its own build-time configuration option: connection-oriented roles central implicitly enables observer role, and peripheral implicitly enables broadcaster role. Usually the first step when creating an application is to decide which roles are needed and go -from there. Bluetooth mesh is a slightly special case, requiring at +from there. Bluetooth Mesh is a slightly special case, requiring at least the observer and broadcaster roles, and possibly also the Peripheral role. This will be described in more detail in a later section. diff --git a/doc/connectivity/bluetooth/overview.rst b/doc/connectivity/bluetooth/overview.rst index fece4ade496..1f727736b2d 100644 --- a/doc/connectivity/bluetooth/overview.rst +++ b/doc/connectivity/bluetooth/overview.rst @@ -76,7 +76,7 @@ Bluetooth stack. * Non-volatile storage support for permanent storage of Bluetooth-specific settings and data - * Bluetooth mesh support + * Bluetooth Mesh support * Relay, Friend Node, Low-Power Node (LPN) and GATT Proxy features * Both Provisioning roles and bearers supported (PB-ADV & PB-GATT) diff --git a/doc/introduction/index.rst b/doc/introduction/index.rst index 985ffe8e002..f8b841ae300 100644 --- a/doc/introduction/index.rst +++ b/doc/introduction/index.rst @@ -125,7 +125,7 @@ Zephyr offers a large and ever growing number of features including: **Bluetooth Low Energy 5.0 support** Bluetooth 5.0 compliant (ESR10) and Bluetooth Low Energy Controller support - (LE Link Layer). Includes Bluetooth mesh and a Bluetooth qualification-ready + (LE Link Layer). Includes Bluetooth Mesh and a Bluetooth qualification-ready Bluetooth controller. * Generic Access Profile (GAP) with all possible LE roles diff --git a/doc/kernel/timeutil.rst b/doc/kernel/timeutil.rst index d41c5b48b89..203d52ea9af 100644 --- a/doc/kernel/timeutil.rst +++ b/doc/kernel/timeutil.rst @@ -223,7 +223,7 @@ include: - GPS time: epoch of 1980-01-06T00:00:00Z, continuous following TAI with an offset of TAI-GPS=19 s. -- Bluetooth mesh time: epoch of 2000-01-01T00:00:00Z, continuous following TAI +- Bluetooth Mesh time: epoch of 2000-01-01T00:00:00Z, continuous following TAI with an offset of -32. - UNIX Leap Time: epoch of 1970-01-01T00:00:00Z, continuous following TAI with an offset of -8. diff --git a/doc/security/vulnerabilities.rst b/doc/security/vulnerabilities.rst index eb2e4e47229..d8e4a2a56ca 100644 --- a/doc/security/vulnerabilities.rst +++ b/doc/security/vulnerabilities.rst @@ -1176,7 +1176,7 @@ This has been fixed in main for v3.0.0 CVE-2022-1041 -------------- -Out-of-bound write vulnerability in the Bluetooth mesh core stack can be triggered during provisioning +Out-of-bound write vulnerability in the Bluetooth Mesh core stack can be triggered during provisioning This has been fixed in main for v3.1.0 @@ -1195,7 +1195,7 @@ This has been fixed in main for v3.1.0 CVE-2022-1042 -------------- -Out-of-bound write vulnerability in the Bluetooth mesh core stack can be triggered during provisioning +Out-of-bound write vulnerability in the Bluetooth Mesh core stack can be triggered during provisioning This has been fixed in main for v3.1.0 diff --git a/include/zephyr/bluetooth/mesh.h b/include/zephyr/bluetooth/mesh.h index a4ef70dc6de..fc84814fa44 100644 --- a/include/zephyr/bluetooth/mesh.h +++ b/include/zephyr/bluetooth/mesh.h @@ -1,5 +1,5 @@ /** @file - * @brief Bluetooth mesh Profile APIs. + * @brief Bluetooth Mesh Profile APIs. */ /* diff --git a/include/zephyr/bluetooth/mesh/blob_srv.h b/include/zephyr/bluetooth/mesh/blob_srv.h index bf807bad92f..92c809bd6b5 100644 --- a/include/zephyr/bluetooth/mesh/blob_srv.h +++ b/include/zephyr/bluetooth/mesh/blob_srv.h @@ -108,7 +108,7 @@ struct bt_mesh_blob_srv_cb { /** @brief Transfer recovery callback. * - * Called when the Bluetooth mesh subsystem is started if the device is rebooted + * Called when the Bluetooth Mesh subsystem is started if the device is rebooted * in the middle of a transfer. * * Transfers will not be resumed after a reboot if this callback is not diff --git a/include/zephyr/bluetooth/mesh/cfg.h b/include/zephyr/bluetooth/mesh/cfg.h index 7d1ca4e868f..9bfd067da9b 100644 --- a/include/zephyr/bluetooth/mesh/cfg.h +++ b/include/zephyr/bluetooth/mesh/cfg.h @@ -26,7 +26,7 @@ extern "C" { #endif -/** Bluetooth mesh feature states */ +/** Bluetooth Mesh feature states */ enum bt_mesh_feat_state { /** Feature is supported, but disabled. */ BT_MESH_FEATURE_DISABLED, diff --git a/include/zephyr/bluetooth/mesh/dfu_cli.h b/include/zephyr/bluetooth/mesh/dfu_cli.h index 3cbc220d825..ad8881ebc26 100644 --- a/include/zephyr/bluetooth/mesh/dfu_cli.h +++ b/include/zephyr/bluetooth/mesh/dfu_cli.h @@ -9,7 +9,7 @@ * @defgroup bt_mesh_dfu_cli Firmware Uppdate Client model * @ingroup bt_mesh_dfu * @{ - * @brief API for the Bluetooth mesh Firmware Update Client model + * @brief API for the Bluetooth Mesh Firmware Update Client model */ #ifndef ZEPHYR_INCLUDE_BLUETOOTH_MESH_DFU_CLI_H__ diff --git a/include/zephyr/bluetooth/mesh/dfu_metadata.h b/include/zephyr/bluetooth/mesh/dfu_metadata.h index bec65897ac7..21d032236a7 100644 --- a/include/zephyr/bluetooth/mesh/dfu_metadata.h +++ b/include/zephyr/bluetooth/mesh/dfu_metadata.h @@ -6,10 +6,10 @@ /** * @file - * @defgroup bt_mesh_dfu_metadata Bluetooth mesh Device Firmware Update (DFU) metadata + * @defgroup bt_mesh_dfu_metadata Bluetooth Mesh Device Firmware Update (DFU) metadata * @ingroup bt_mesh_dfu * @{ - * @brief Common types and functions for the Bluetooth mesh DFU metadata. + * @brief Common types and functions for the Bluetooth Mesh DFU metadata. */ #ifndef ZEPHYR_INCLUDE_BLUETOOTH_MESH_DFU_METADATA_H__ diff --git a/include/zephyr/bluetooth/mesh/dfu_srv.h b/include/zephyr/bluetooth/mesh/dfu_srv.h index e136701e664..2beaf2d9772 100644 --- a/include/zephyr/bluetooth/mesh/dfu_srv.h +++ b/include/zephyr/bluetooth/mesh/dfu_srv.h @@ -9,7 +9,7 @@ * @defgroup bt_mesh_dfu_srv Firmware Update Server model * @ingroup bt_mesh_dfu * @{ - * @brief API for the Bluetooth mesh Firmware Update Server model + * @brief API for the Bluetooth Mesh Firmware Update Server model */ #ifndef ZEPHYR_INCLUDE_BLUETOOTH_MESH_DFU_SRV_H__ @@ -136,7 +136,7 @@ struct bt_mesh_dfu_srv_cb { /** @brief Transfer recovery callback. * * If the device reboots in the middle of a transfer, the Firmware Update Server - * calls this function when the Bluetooth mesh subsystem is started. + * calls this function when the Bluetooth Mesh subsystem is started. * * This callback is optional, but transfers will not be recovered after * a reboot without it. diff --git a/include/zephyr/bluetooth/mesh/main.h b/include/zephyr/bluetooth/mesh/main.h index a4e98b97f8c..8e7445fae6f 100644 --- a/include/zephyr/bluetooth/mesh/main.h +++ b/include/zephyr/bluetooth/mesh/main.h @@ -1,5 +1,5 @@ /** @file - * @brief Bluetooth mesh Protocol APIs. + * @brief Bluetooth Mesh Protocol APIs. */ /* @@ -550,8 +550,8 @@ bool bt_mesh_is_provisioned(void); */ /** - * @brief Bluetooth mesh - * @defgroup bt_mesh Bluetooth mesh + * @brief Bluetooth Mesh + * @defgroup bt_mesh Bluetooth Mesh * @ingroup bluetooth * @{ */ diff --git a/samples/bluetooth/mesh/README.rst b/samples/bluetooth/mesh/README.rst index e6ee78ba3a7..58532a0600b 100644 --- a/samples/bluetooth/mesh/README.rst +++ b/samples/bluetooth/mesh/README.rst @@ -6,7 +6,7 @@ Bluetooth: Mesh Overview ******** -This sample demonstrates Bluetooth mesh functionality. It has several +This sample demonstrates Bluetooth Mesh functionality. It has several standard mesh models, and supports provisioning over both the Advertising and the GATT Provisioning Bearers (i.e. PB-ADV and PB-GATT). The application also needs a functioning serial console, since that's diff --git a/samples/bluetooth/mesh_demo/README.rst b/samples/bluetooth/mesh_demo/README.rst index 7fe7f0908ce..2edb690ab19 100644 --- a/samples/bluetooth/mesh_demo/README.rst +++ b/samples/bluetooth/mesh_demo/README.rst @@ -6,7 +6,7 @@ Bluetooth: Mesh Demo Overview ******** -This sample is a Bluetooth mesh application intended for demonstration +This sample is a Bluetooth Mesh application intended for demonstration purposes only. The application provisions and configures itself (i.e. no external provisioner needed) with hard-coded network and application key values. The local unicast address can be set using a NODE_ADDR build diff --git a/samples/bluetooth/mesh_provisioner/README.rst b/samples/bluetooth/mesh_provisioner/README.rst index 6da113afc1b..1b37a04a4a8 100644 --- a/samples/bluetooth/mesh_provisioner/README.rst +++ b/samples/bluetooth/mesh_provisioner/README.rst @@ -6,7 +6,7 @@ Bluetooth: Mesh Provisioner Overview ******** -This sample demonstrates how to use the Bluetooth mesh APIs related to +This sample demonstrates how to use the Bluetooth Mesh APIs related to provisioning and using the Configuration Database (CDB). It is intended to be tested together with a device capable of being provisioned. For example, one could use the sample in diff --git a/samples/boards/nrf/mesh/onoff-app/README.rst b/samples/boards/nrf/mesh/onoff-app/README.rst index e8cadccd53c..35e37d6a599 100644 --- a/samples/boards/nrf/mesh/onoff-app/README.rst +++ b/samples/boards/nrf/mesh/onoff-app/README.rst @@ -6,7 +6,7 @@ Bluetooth: Mesh OnOff Model Overview ******** -This is a simple application demonstrating a Bluetooth mesh multi-element node. +This is a simple application demonstrating a Bluetooth Mesh multi-element node. Each element has a mesh onoff client and server model which controls one of the 4 sets of buttons and LEDs . diff --git a/samples/boards/nrf/mesh/onoff_level_lighting_vnd_app/README.rst b/samples/boards/nrf/mesh/onoff_level_lighting_vnd_app/README.rst index 05b8d896e77..f33bf1e7761 100644 --- a/samples/boards/nrf/mesh/onoff_level_lighting_vnd_app/README.rst +++ b/samples/boards/nrf/mesh/onoff_level_lighting_vnd_app/README.rst @@ -4,7 +4,7 @@ Bluetooth: Mesh Generic OnOff, Generic Level, Lighting & Vendor Models ###################################################################### Overview ******** -This is a application demonstrating a Bluetooth mesh node in +This is a application demonstrating a Bluetooth Mesh node in which Root element has following models - Generic OnOff Server diff --git a/samples/boards/reel_board/mesh_badge/README.rst b/samples/boards/reel_board/mesh_badge/README.rst index d5973ab8e9c..ccfc7e771ae 100644 --- a/samples/boards/reel_board/mesh_badge/README.rst +++ b/samples/boards/reel_board/mesh_badge/README.rst @@ -6,7 +6,7 @@ Mesh Badge Overview ******** -This sample app for the reel board showcases Bluetooth mesh +This sample app for the reel board showcases Bluetooth Mesh The app starts off as a regular Bluetooth GATT peripheral application. Install the "nRF Connect" app on your phone (available both for @@ -34,7 +34,7 @@ Steps to set up you're not happy with it you can try writing something else. #. When you're happy with the text, disconnect from the board (exit the app or go back to the device scan page) -#. Once disconnected the board switches over to Bluetooth mesh mode, and you +#. Once disconnected the board switches over to Bluetooth Mesh mode, and you can't connect to it anymore over GATT. If you configure multiple boards like this they can communicate with diff --git a/subsys/bluetooth/Kconfig.logging b/subsys/bluetooth/Kconfig.logging index ec95ddad10e..6d8b999e03c 100644 --- a/subsys/bluetooth/Kconfig.logging +++ b/subsys/bluetooth/Kconfig.logging @@ -469,56 +469,56 @@ config BT_MESH_DEBUG_NET select DEPRECATED help Use this option to enable Network layer debug logs for the - Bluetooth mesh functionality. + Bluetooth Mesh functionality. config BT_MESH_DEBUG_RPL bool "[DEPRECATED] Replay protection list debug" select DEPRECATED help Use this option to enable Replay protection list debug logs - for the Bluetooth mesh functionality. + for the Bluetooth Mesh functionality. config BT_MESH_DEBUG_TRANS bool "[DEPRECATED] Transport layer debug" select DEPRECATED help Use this option to enable Transport layer debug logs for the - Bluetooth mesh functionality. + Bluetooth Mesh functionality. config BT_MESH_DEBUG_BEACON bool "[DEPRECATED] Beacon debug" select DEPRECATED help Use this option to enable Beacon-related debug logs for the - Bluetooth mesh functionality. + Bluetooth Mesh functionality. config BT_MESH_DEBUG_CRYPTO bool "[DEPRECATED] Crypto debug" select DEPRECATED help Use this option to enable cryptographic debug logs for the - Bluetooth mesh functionality. + Bluetooth Mesh functionality. config BT_MESH_DEBUG_KEYS bool "[DEPRECATED] Key management debug" select DEPRECATED help Use this option to enable key management debug logs for the - Bluetooth mesh functionality. + Bluetooth Mesh functionality. config BT_MESH_DEBUG_PROV bool "[DEPRECATED] Provisioning debug" select DEPRECATED help Use this option to enable Provisioning debug logs for the - Bluetooth mesh functionality. + Bluetooth Mesh functionality. config BT_MESH_DEBUG_PROVISIONER bool "[DEPRECATED] Provisioner debug" select DEPRECATED help Use this option to enable Provisioner debug logs for the - Bluetooth mesh functionality. + Bluetooth Mesh functionality. config BT_MESH_DEBUG_PROV_DEVICE bool "[DEPRECATED] Provisioning device debug" @@ -532,7 +532,7 @@ config BT_MESH_DEBUG_ACCESS select DEPRECATED help Use this option to enable Access layer and device composition - related debug logs for Bluetooth mesh. + related debug logs for Bluetooth Mesh. config BT_MESH_DEBUG_MODEL bool "[DEPRECATED] Foundation model debug" @@ -546,21 +546,21 @@ config BT_MESH_DEBUG_ADV select DEPRECATED help Use this option to enable advertising debug logs for - the Bluetooth mesh functionality. + the Bluetooth Mesh functionality. config BT_MESH_DEBUG_LOW_POWER bool "[DEPRECATED] Low Power debug" select DEPRECATED help Use this option to enable Low Power debug logs for the - Bluetooth mesh functionality. + Bluetooth Mesh functionality. config BT_MESH_DEBUG_FRIEND bool "[DEPRECATED] Friend debug" select DEPRECATED help Use this option to enable Friend debug logs for the - Bluetooth mesh functionality. + Bluetooth Mesh functionality. config BT_MESH_DEBUG_PROXY bool "[DEPRECATED] Proxy debug" @@ -588,7 +588,7 @@ config BT_MESH_DEBUG_CFG select DEPRECATED help Use this option to enable node configuration debug logs for the - Bluetooth mesh functionality. + Bluetooth Mesh functionality. endmenu # [DEPRECATED] Mesh diff --git a/subsys/bluetooth/common/Kconfig b/subsys/bluetooth/common/Kconfig index 7b6bc839b89..2fdc98694b1 100644 --- a/subsys/bluetooth/common/Kconfig +++ b/subsys/bluetooth/common/Kconfig @@ -243,7 +243,7 @@ config BT_HCI_MESH_EXT bool "Mesh HCI Command support" depends on BT_BROADCASTER && BT_OBSERVER && !BT_LL_SW_SPLIT help - Enable support for the Bluetooth mesh HCI Commands. + Enable support for the Bluetooth Mesh HCI Commands. config BT_WAIT_NOP bool "Wait for \"NOP\" Command Complete event during init" diff --git a/subsys/bluetooth/mesh/Kconfig b/subsys/bluetooth/mesh/Kconfig index de409e9c53c..ae7b25a6dd7 100644 --- a/subsys/bluetooth/mesh/Kconfig +++ b/subsys/bluetooth/mesh/Kconfig @@ -1,13 +1,13 @@ -# Bluetooth mesh configuration options +# Bluetooth Mesh configuration options # Copyright (c) 2017 Intel Corporation # SPDX-License-Identifier: Apache-2.0 menuconfig BT_MESH - bool "Bluetooth mesh support" + bool "Bluetooth Mesh support" depends on BT_OBSERVER && BT_BROADCASTER help - This option enables Bluetooth mesh support. The specific + This option enables Bluetooth Mesh support. The specific features that are available may depend on other features that have been enabled in the stack, such as GATT support. @@ -598,7 +598,7 @@ config BT_MESH_ACCESS_LAYER_MSG help This option allows the application to directly access Bluetooth access layer messages without the need to - instantiate Bluetooth mesh models. + instantiate Bluetooth Mesh models. config BT_MESH_MODEL_VND_MSG_CID_FORCE bool "Force vendor model to use the corresponding CID field message" @@ -1049,9 +1049,9 @@ config BT_MESH_FRIEND_ADV_LATENCY endif # BT_MESH_FRIEND menuconfig BT_MESH_V1d1 - bool "Bluetooth mesh v1.1 support" + bool "Bluetooth Mesh v1.1 support" help - This option enables Bluetooth mesh v1.1 support. Bluetooth mesh v1.1 + This option enables Bluetooth Mesh v1.1 support. Bluetooth Mesh v1.1 is backward compatible with v1.0.1. config BT_MESH_ECDH_P256_CMAC_AES128_AES_CCM @@ -1201,7 +1201,7 @@ config BT_MESH_DFU_METADATA bool "Support for the default metadata format" help This option adds a set of functions that can be used to encode and decode a firmware - metadata using the format defined in the Bluetooth mesh DFU subsystem. + metadata using the format defined in the Bluetooth Mesh DFU subsystem. config BT_MESH_DFU_URI_MAXLEN int "DFU URI max length" @@ -1734,16 +1734,16 @@ config BT_MESH_RPL_STORE_TIMEOUT endif # BT_MESH_RPL_STORAGE_MODE_SETTINGS && BT_SETTINGS config BT_MESH_SETTINGS_WORKQ - bool "Store the Bluetooth mesh settings in a separate work queue" + bool "Store the Bluetooth Mesh settings in a separate work queue" default y help This option enables a separate cooperative thread which is used to - store Bluetooth mesh configuration. When this option is disabled, + store Bluetooth Mesh configuration. When this option is disabled, the stack's configuration is stored in the system workqueue. This means that the system workqueue will be blocked for the time needed to store the pending data. This time may significantly increase if the flash driver does the erase operation. Enabling this option - allows Bluetooth mesh not to block the system workqueue, and thus + allows Bluetooth Mesh not to block the system workqueue, and thus process the incoming and outgoing messages while the flash driver waits for the controller to allocate the time needed to write the data and/or erase the required flash pages. diff --git a/subsys/bluetooth/mesh/access.h b/subsys/bluetooth/mesh/access.h index b7ce1abd0ea..48e0eadec10 100644 --- a/subsys/bluetooth/mesh/access.h +++ b/subsys/bluetooth/mesh/access.h @@ -94,7 +94,7 @@ void bt_mesh_msg_cb_set(void (*cb)(uint32_t opcode, struct bt_mesh_msg_ctx *ctx, * Send a mesh model layer message out into the mesh network without having instantiated * the relevant mesh models. * - * @param ctx The Bluetooth mesh message context. + * @param ctx The Bluetooth Mesh message context. * @param buf The message payload. * * @return 0 on success or negative error code on failure. diff --git a/subsys/bluetooth/mesh/settings.c b/subsys/bluetooth/mesh/settings.c index 771aad9b946..9cfcb3f5c2c 100644 --- a/subsys/bluetooth/mesh/settings.c +++ b/subsys/bluetooth/mesh/settings.c @@ -88,7 +88,7 @@ static int mesh_commit(void) } if (!atomic_test_bit(bt_dev.flags, BT_DEV_ENABLE)) { - /* The Bluetooth mesh settings loader calls bt_mesh_start() immediately + /* The Bluetooth Mesh settings loader calls bt_mesh_start() immediately * after loading the settings. This is not intended to work before * bt_enable(). The doc on @ref bt_enable requires the "bt/" settings * tree to be loaded after @ref bt_enable is completed, so this handler diff --git a/subsys/bluetooth/mesh/shell/Kconfig b/subsys/bluetooth/mesh/shell/Kconfig index 5e1e43f0057..46671c3bfaa 100644 --- a/subsys/bluetooth/mesh/shell/Kconfig +++ b/subsys/bluetooth/mesh/shell/Kconfig @@ -1,13 +1,13 @@ -# Bluetooth mesh shell configuration options +# Bluetooth Mesh shell configuration options # Copyright (c) 2022 Nordic Semiconductor # SPDX-License-Identifier: Apache-2.0 menuconfig BT_MESH_SHELL - bool "Bluetooth mesh shell" + bool "Bluetooth Mesh shell" select SHELL help - Activate shell module that provides Bluetooth mesh commands to + Activate shell module that provides Bluetooth Mesh commands to the console. if BT_MESH_SHELL @@ -24,7 +24,7 @@ config BT_MESH_SHELL_PROV_CTX_INSTANCE depends on BT_MESH_SHELL_PROV help This option enables the provisioning context instance in the - Bluetooth mesh shell module together with several provisioning + Bluetooth Mesh shell module together with several provisioning commands and target utility features. To use the provisioning context instance, use bt_mesh_shell_prov in the initialization of mesh. @@ -54,7 +54,7 @@ config BT_MESH_SHELL_HEALTH_SRV_INSTANCE depends on BT_MESH_SHELL_TEST help This option enables Health Server model instance in the - Bluetooth mesh shell module together with fault controlling + Bluetooth Mesh shell module together with fault controlling shell commands. To use the model instance, add bt_mesh_shell_health_srv to the device composition data. Use BT_MESH_SHELL_HEALTH_PUB_DEFINE to instantiate publication context. diff --git a/subsys/bluetooth/mesh/shell/shell.c b/subsys/bluetooth/mesh/shell/shell.c index a169bb16422..bb9892eb355 100644 --- a/subsys/bluetooth/mesh/shell/shell.c +++ b/subsys/bluetooth/mesh/shell/shell.c @@ -1814,5 +1814,5 @@ SHELL_STATIC_SUBCMD_SET_CREATE(mesh_cmds, SHELL_SUBCMD_SET_END ); -SHELL_CMD_ARG_REGISTER(mesh, &mesh_cmds, "Bluetooth mesh shell commands", +SHELL_CMD_ARG_REGISTER(mesh, &mesh_cmds, "Bluetooth Mesh shell commands", bt_mesh_shell_mdl_cmds_help, 1, 1); diff --git a/tests/bsim/bluetooth/mesh/README.rst b/tests/bsim/bluetooth/mesh/README.rst index 787b0084f0b..1ae78887b71 100644 --- a/tests/bsim/bluetooth/mesh/README.rst +++ b/tests/bsim/bluetooth/mesh/README.rst @@ -1,7 +1,7 @@ -Bluetooth mesh BabbleSim tests +Bluetooth Mesh BabbleSim tests ############################## -This directory contains a set of high level system tests for the Bluetooth mesh +This directory contains a set of high level system tests for the Bluetooth Mesh subsystem. The tests run on the BabbleSim simulator, using the BabbleSim test framework. @@ -10,7 +10,7 @@ subfolder of test_scripts contains tests for a specific module in the Bluetooth mesh subsystem, and each folder has a corresponding test_.c under the src/ directory containing the necessary test harnesses to execute the tests. -There's only a single test application for all the Bluetooth mesh BabbleSim +There's only a single test application for all the Bluetooth Mesh BabbleSim tests. The test application is built from this directory, and includes all test harnesses in every build. The overlying bsim test framework selects the harness to use at runtime, using the test identifiers passed in the test scripts. @@ -18,7 +18,7 @@ to use at runtime, using the test identifiers passed in the test scripts. Running the tests ***************** -The Bluetooth mesh tests have no extra requirements, and can be run using the +The Bluetooth Mesh tests have no extra requirements, and can be run using the procedure described in the parent folder. To only run the mesh tests, set ``SEARCH_PATH`` to point to this folder before @@ -57,13 +57,13 @@ Then separately, call Framework ********* -The Bluetooth mesh BabbleSim tests mainly operate on the test framework for the +The Bluetooth Mesh BabbleSim tests mainly operate on the test framework for the BabbleSim platform, but with some mesh specific additions: mesh_test.sh ============= -All test scripts in the Bluetooth mesh BabbleSim test suite follow a common +All test scripts in the Bluetooth Mesh BabbleSim test suite follow a common pattern for running a single test across N devices with different test harnesses. ``mesh_test.sh`` is sourced in each test script, and its ``RunTest`` function is called once in each script with the following parameters: @@ -113,6 +113,6 @@ has been called - otherwise, it will fail. The Bluetooth stack must be initialized in the ``test_main_f`` function of the harness, as the previous callbacks are all executed in hardware threads. -The Bluetooth mesh tests include the entire Bluetooth host and controller +The Bluetooth Mesh tests include the entire Bluetooth host and controller subsystems, so timing requirements should generally be kept fairly liberal to avoid regressions on changes in the underlying layers. diff --git a/tests/bsim/bluetooth/mesh/prj.conf b/tests/bsim/bluetooth/mesh/prj.conf index b0738c4fa05..a45bef89775 100644 --- a/tests/bsim/bluetooth/mesh/prj.conf +++ b/tests/bsim/bluetooth/mesh/prj.conf @@ -15,7 +15,7 @@ CONFIG_BT_BROADCASTER=y CONFIG_BT_CTLR_DUP_FILTER_LEN=0 CONFIG_BT_CTLR_PRIVACY=n -# Bluetooth mesh configuration +# Bluetooth Mesh configuration CONFIG_BT_MESH=y CONFIG_BT_MESH_LOG_LEVEL_DBG=y CONFIG_BT_MESH_RELAY=y diff --git a/tests/bsim/bluetooth/mesh/prj_mesh1d1.conf b/tests/bsim/bluetooth/mesh/prj_mesh1d1.conf index ab6066e01bf..11059c03da4 100644 --- a/tests/bsim/bluetooth/mesh/prj_mesh1d1.conf +++ b/tests/bsim/bluetooth/mesh/prj_mesh1d1.conf @@ -15,7 +15,7 @@ CONFIG_BT_BROADCASTER=y CONFIG_BT_CTLR_DUP_FILTER_LEN=0 CONFIG_BT_CTLR_PRIVACY=n -# Bluetooth mesh configuration +# Bluetooth Mesh configuration CONFIG_BT_MESH=y CONFIG_BT_MESH_V1d1=y CONFIG_BT_MESH_LOG_LEVEL_DBG=y diff --git a/tests/bsim/bluetooth/mesh/src/mesh_test.h b/tests/bsim/bluetooth/mesh/src/mesh_test.h index a5c8694947b..3dcaa5f784a 100644 --- a/tests/bsim/bluetooth/mesh/src/mesh_test.h +++ b/tests/bsim/bluetooth/mesh/src/mesh_test.h @@ -1,5 +1,5 @@ /** @file - * @brief Common functionality for Bluetooth mesh BabbleSim tests. + * @brief Common functionality for Bluetooth Mesh BabbleSim tests. */ /* From 5d915398a4ca662c6ba1236638e9eeacd4212a53 Mon Sep 17 00:00:00 2001 From: Jukka Rissanen Date: Wed, 29 Nov 2023 16:11:51 +0200 Subject: [PATCH 0572/3723] net: sockets: Add additional checks to recvmsg() Add extra checks that make sure that msg_iov is set as we cannot receive anything if receive buffers are not set. Signed-off-by: Jukka Rissanen --- subsys/net/lib/sockets/sockets.c | 10 ++++++++++ tests/net/socket/udp/src/main.c | 7 ++++++- 2 files changed, 16 insertions(+), 1 deletion(-) diff --git a/subsys/net/lib/sockets/sockets.c b/subsys/net/lib/sockets/sockets.c index 00f55299583..02fa21675eb 100644 --- a/subsys/net/lib/sockets/sockets.c +++ b/subsys/net/lib/sockets/sockets.c @@ -1748,6 +1748,11 @@ ssize_t zsock_recvmsg_ctx(struct net_context *ctx, struct msghdr *msg, return -1; } + if (msg->msg_iov == NULL) { + errno = ENOMEM; + return -1; + } + for (i = 0; i < msg->msg_iovlen; i++) { max_len += msg->msg_iov[i].iov_len; } @@ -1790,6 +1795,11 @@ ssize_t z_vrfy_zsock_recvmsg(int sock, struct msghdr *msg, int flags) return -1; } + if (msg->msg_iov == NULL) { + errno = ENOMEM; + return -1; + } + K_OOPS(k_usermode_from_copy(&msg_copy, (void *)msg, sizeof(msg_copy))); k_usermode_from_copy(&iovlen, &msg->msg_iovlen, sizeof(iovlen)); diff --git a/tests/net/socket/udp/src/main.c b/tests/net/socket/udp/src/main.c index f220c1bfca8..418e82dd480 100644 --- a/tests/net/socket/udp/src/main.c +++ b/tests/net/socket/udp/src/main.c @@ -1415,7 +1415,7 @@ ZTEST_USER(net_socket_udp, test_26_recvmsg_invalid) msg.msg_control = &cmsgbuf.buf; ret = recvmsg(0, &msg, 0); - zassert_true(ret < 0, "recvmsg() succeed"); + zassert_true(ret < 0 && errno == ENOMEM, "Wrong errno (%d)", errno); msg.msg_iov = io_vector; msg.msg_iovlen = 1; @@ -1463,6 +1463,11 @@ static void comm_sendmsg_recvmsg(int client_sock, sent = sendmsg(client_sock, client_msg, 0); zassert_true(sent > 0, "sendmsg failed, %s (%d)", strerror(errno), -errno); + /* One negative test with invalid msg_iov */ + memset(msg, 0, sizeof(*msg)); + recved = recvmsg(server_sock, msg, 0); + zassert_true(recved < 0 && errno == ENOMEM, "Wrong errno (%d)", errno); + for (i = 0, len = 0; i < client_msg->msg_iovlen; i++) { len += client_msg->msg_iov[i].iov_len; } From b500f7216e976a6237ff307246d00cf4a1879d20 Mon Sep 17 00:00:00 2001 From: Pieter De Gendt Date: Wed, 29 Nov 2023 15:33:19 +0100 Subject: [PATCH 0573/3723] tests: net: lib: coap_server: Do not autostart service B with port 0 A race condition for the test occurs as the service might have started when booting. Do not autostart the service to verify the port stays 0. Signed-off-by: Pieter De Gendt --- tests/net/lib/coap_server/common/src/main.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/tests/net/lib/coap_server/common/src/main.c b/tests/net/lib/coap_server/common/src/main.c index 7af940c5360..20c4b7c0317 100644 --- a/tests/net/lib/coap_server/common/src/main.c +++ b/tests/net/lib/coap_server/common/src/main.c @@ -48,7 +48,7 @@ COAP_RESOURCE_DEFINE(resource_1, service_A, { }); static uint16_t service_B_port; -COAP_SERVICE_DEFINE(service_B, "b.service.com", &service_B_port, COAP_SERVICE_AUTOSTART); +COAP_SERVICE_DEFINE(service_B, "b.service.com", &service_B_port, 0); static const char * const resource_2_path[] = { "res2", "sub", NULL }; COAP_RESOURCE_DEFINE(resource_2, service_B, { @@ -132,7 +132,7 @@ ZTEST(coap_service, test_COAP_SERVICE_FOREACH) zassert_equal(svc->flags & COAP_SERVICE_AUTOSTART, COAP_SERVICE_AUTOSTART); } else if (svc == &service_B) { have_service_B = 1; - zassert_equal(svc->flags & COAP_SERVICE_AUTOSTART, COAP_SERVICE_AUTOSTART); + zassert_equal(svc->flags & COAP_SERVICE_AUTOSTART, 0); } else if (svc == &service_C) { have_service_C = 1; zassert_equal(svc->flags & COAP_SERVICE_AUTOSTART, 0); From 4ff8080b65494eac5525de43dd67e3509de1a697 Mon Sep 17 00:00:00 2001 From: Pieter De Gendt Date: Wed, 29 Nov 2023 14:45:53 +0100 Subject: [PATCH 0574/3723] net: lib: coap: Init CoAP service socket fd to -1 Set the static initialiser socket file descriptor to -1 to make sure it is invalid before using coap_service_send. Signed-off-by: Pieter De Gendt --- include/zephyr/net/coap_service.h | 4 +++- subsys/net/lib/coap/coap_server.c | 3 --- 2 files changed, 3 insertions(+), 4 deletions(-) diff --git a/include/zephyr/net/coap_service.h b/include/zephyr/net/coap_service.h index 3e3201308b9..377c89a7bef 100644 --- a/include/zephyr/net/coap_service.h +++ b/include/zephyr/net/coap_service.h @@ -57,7 +57,9 @@ struct coap_service { }; #define __z_coap_service_define(_name, _host, _port, _flags, _res_begin, _res_end) \ - static struct coap_service_data coap_service_data_##_name; \ + static struct coap_service_data coap_service_data_##_name = { \ + .sock_fd = -1, \ + }; \ const STRUCT_SECTION_ITERABLE(coap_service, _name) = { \ .name = STRINGIFY(_name), \ .host = _host, \ diff --git a/subsys/net/lib/coap/coap_server.c b/subsys/net/lib/coap/coap_server.c index ac179f5545e..009a0fe0274 100644 --- a/subsys/net/lib/coap/coap_server.c +++ b/subsys/net/lib/coap/coap_server.c @@ -707,9 +707,6 @@ static void coap_server_thread(void *p1, void *p2, void *p3) } COAP_SERVICE_FOREACH(svc) { - /* Init all file descriptors to -1 */ - svc->data->sock_fd = -1; - if (svc->flags & COAP_SERVICE_AUTOSTART) { ret = coap_service_start(svc); if (ret < 0) { From f2a256a4c9db9767cf50dc570e88fe5354047c81 Mon Sep 17 00:00:00 2001 From: Pieter De Gendt Date: Wed, 29 Nov 2023 14:57:06 +0100 Subject: [PATCH 0575/3723] net: lib: coap: Fix return value documentation coap_service_start Corrected a return value in the doxygen description for coap_service_start. Signed-off-by: Pieter De Gendt --- include/zephyr/net/coap_service.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/include/zephyr/net/coap_service.h b/include/zephyr/net/coap_service.h index 377c89a7bef..92a276d0d48 100644 --- a/include/zephyr/net/coap_service.h +++ b/include/zephyr/net/coap_service.h @@ -199,7 +199,7 @@ struct coap_service { * @param service Pointer to CoAP service * @retval 0 in case of success. * @retval -EALREADY in case of an already running service. - * @retval -ENOMEM in case the server has no available context. + * @retval -ENOTSUP in case the server has no valid host and port configuration. */ int coap_service_start(const struct coap_service *service); From 266181b0825c63adb48acafbb15e42191c4fc3ff Mon Sep 17 00:00:00 2001 From: Pieter De Gendt Date: Wed, 29 Nov 2023 14:58:12 +0100 Subject: [PATCH 0576/3723] net: lib: coap: Add coap_service_is_running Add a CoAP service API function to query the running state of the provided service. Signed-off-by: Pieter De Gendt --- include/zephyr/net/coap_service.h | 12 ++++++++++++ subsys/net/lib/coap/coap_server.c | 18 ++++++++++++++++++ 2 files changed, 30 insertions(+) diff --git a/include/zephyr/net/coap_service.h b/include/zephyr/net/coap_service.h index 92a276d0d48..6f038ce61e1 100644 --- a/include/zephyr/net/coap_service.h +++ b/include/zephyr/net/coap_service.h @@ -214,6 +214,18 @@ int coap_service_start(const struct coap_service *service); */ int coap_service_stop(const struct coap_service *service); +/** + * @brief Query the provided @p service running state. + * + * @note This function is suitable for a @p service defined with @ref COAP_SERVICE_DEFINE. + * + * @param service Pointer to CoAP service + * @retval 1 if the service is running + * @retval 0 if the service is stopped + * @retval negative in case of an error. + */ +int coap_service_is_running(const struct coap_service *service); + /** * @brief Send a CoAP message from the provided @p service . * diff --git a/subsys/net/lib/coap/coap_server.c b/subsys/net/lib/coap/coap_server.c index 009a0fe0274..386bc2081bb 100644 --- a/subsys/net/lib/coap/coap_server.c +++ b/subsys/net/lib/coap/coap_server.c @@ -483,6 +483,24 @@ int coap_service_stop(const struct coap_service *service) return ret; } +int coap_service_is_running(const struct coap_service *service) +{ + int ret; + + if (!coap_service_in_section(service)) { + __ASSERT_NO_MSG(false); + return -EINVAL; + } + + k_mutex_lock(&lock, K_FOREVER); + + ret = (service->data->sock_fd < 0) ? 0 : 1; + + k_mutex_unlock(&lock); + + return ret; +} + int coap_service_send(const struct coap_service *service, const struct coap_packet *cpkt, const struct sockaddr *addr, socklen_t addr_len) { From eb9587596b080a31edd20436e0dba4520543593e Mon Sep 17 00:00:00 2001 From: Chaitanya Tata Date: Wed, 29 Nov 2023 21:18:46 +0530 Subject: [PATCH 0577/3723] wifi: Check WPA-PSK passphrase length When WPA-PSK was introduced the passphrase length check was missed. Signed-off-by: Chaitanya Tata --- subsys/net/l2/wifi/wifi_mgmt.c | 1 + 1 file changed, 1 insertion(+) diff --git a/subsys/net/l2/wifi/wifi_mgmt.c b/subsys/net/l2/wifi/wifi_mgmt.c index 6eb8a6682c2..1a866d4c47c 100644 --- a/subsys/net/l2/wifi/wifi_mgmt.c +++ b/subsys/net/l2/wifi/wifi_mgmt.c @@ -274,6 +274,7 @@ static int wifi_connect(uint32_t mgmt_request, struct net_if *iface, (params->ssid_length > WIFI_SSID_MAX_LEN) || (params->ssid_length == 0U) || ((params->security == WIFI_SECURITY_TYPE_PSK || + params->security == WIFI_SECURITY_TYPE_WPA_PSK || params->security == WIFI_SECURITY_TYPE_PSK_SHA256) && ((params->psk_length < 8) || (params->psk_length > 64) || (params->psk_length == 0U) || !params->psk)) || From be5a341467f29ad8e94ab6ce72afcbf20e858f28 Mon Sep 17 00:00:00 2001 From: Peter Johanson Date: Wed, 29 Nov 2023 12:01:14 -0800 Subject: [PATCH 0578/3723] bluetooth: Add CPF attribute to BAS battery level. BAS v1.1, section 3.1.2.1 notes that a CPF should be added if the device has more that one instance of the Battery Service, so add one with the `main` description so that apps can add additional Battery Level services with other descriptions, e.g. `auxiliary`. Signed-off-by: Peter Johanson --- subsys/bluetooth/services/bas.c | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/subsys/bluetooth/services/bas.c b/subsys/bluetooth/services/bas.c index cc96815b384..1896136681c 100644 --- a/subsys/bluetooth/services/bas.c +++ b/subsys/bluetooth/services/bas.c @@ -47,6 +47,17 @@ static ssize_t read_blvl(struct bt_conn *conn, sizeof(lvl8)); } +/* Constant values from the Assigned Numbers specification: + * https://www.bluetooth.com/wp-content/uploads/Files/Specification/Assigned_Numbers.pdf?id=89 + */ +static const struct bt_gatt_cpf level_cpf = { + .format = 0x04, /* uint8 */ + .exponent = 0x0, + .unit = 0x27AD, /* Percentage */ + .name_space = 0x01, /* Bluetooth SIG */ + .description = 0x0106, /* "main" */ +}; + BT_GATT_SERVICE_DEFINE(bas, BT_GATT_PRIMARY_SERVICE(BT_UUID_BAS), BT_GATT_CHARACTERISTIC(BT_UUID_BAS_BATTERY_LEVEL, @@ -55,6 +66,7 @@ BT_GATT_SERVICE_DEFINE(bas, &battery_level), BT_GATT_CCC(blvl_ccc_cfg_changed, BT_GATT_PERM_READ | BT_GATT_PERM_WRITE), + BT_GATT_CPF(&level_cpf), ); static int bas_init(void) From 7ee86fcfa2c747d0c73cf45bae4dd435cfe11589 Mon Sep 17 00:00:00 2001 From: Hake Huang Date: Thu, 30 Nov 2023 15:00:13 +0800 Subject: [PATCH 0579/3723] tfm: lpcxpersso55s69_ns: add tfm runner support enable TFM the final image used is tfm_merged.hex not zephyr.hex Signed-off-by: Hake Huang --- boards/arm/lpcxpresso55s69/board.cmake | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/boards/arm/lpcxpresso55s69/board.cmake b/boards/arm/lpcxpresso55s69/board.cmake index 21ed8e82672..ed9aedf4f4e 100644 --- a/boards/arm/lpcxpresso55s69/board.cmake +++ b/boards/arm/lpcxpresso55s69/board.cmake @@ -19,6 +19,10 @@ endif() board_runner_args(pyocd "--target=lpc55s69") +if(CONFIG_BUILD_WITH_TFM) + set_property(TARGET runners_yaml_props_target PROPERTY hex_file tfm_merged.hex) +endif() + include(${ZEPHYR_BASE}/boards/common/jlink.board.cmake) include(${ZEPHYR_BASE}/boards/common/pyocd.board.cmake) include(${ZEPHYR_BASE}/boards/common/linkserver.board.cmake) From 265e1d222fb61ff1fa4b03d617356f19541230c4 Mon Sep 17 00:00:00 2001 From: Andrei Emeltchenko Date: Thu, 30 Nov 2023 12:24:41 +0200 Subject: [PATCH 0580/3723] doc: usermode: Improve documentation The documentation related to dynamic object is hidden. Affects k_object_alloc(), etc functions. Signed-off-by: Andrei Emeltchenko --- include/zephyr/sys/kobject.h | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/include/zephyr/sys/kobject.h b/include/zephyr/sys/kobject.h index 628bb967551..50577ac7c02 100644 --- a/include/zephyr/sys/kobject.h +++ b/include/zephyr/sys/kobject.h @@ -195,7 +195,7 @@ static inline bool k_object_is_valid(const void *obj, enum k_objects otype) /* LCOV_EXCL_STOP */ #endif /* !CONFIG_USERSPACE */ -#ifdef CONFIG_DYNAMIC_OBJECTS +#if defined(CONFIG_DYNAMIC_OBJECTS) || defined(__DOXYGEN__) /** * Allocate a kernel object of a designated type * @@ -204,6 +204,9 @@ static inline bool k_object_is_valid(const void *obj, enum k_objects otype) * state, with the calling thread being granted permission on it. The memory * for the object will be allocated out of the calling thread's resource pool. * + * @note This function is available only if @kconfig{CONFIG_DYNAMIC_OBJECTS} + * is selected. + * * @note Thread stack object has to use k_object_alloc_size() since stacks may * have different sizes. * @@ -224,6 +227,9 @@ __syscall void *k_object_alloc(enum k_objects otype); * This function is specially helpful for thread stack objects because * their sizes can vary. Other objects should probably look k_object_alloc(). * + * @note This function is available only if @kconfig{CONFIG_DYNAMIC_OBJECTS} + * is selected. + * * @param otype Requested kernel object type * @param size Requested kernel object size * @return A pointer to the allocated kernel object, or NULL if memory wasn't @@ -238,6 +244,9 @@ __syscall void *k_object_alloc_size(enum k_objects otype, size_t size); * allocated from. Care must be exercised that the object will not be used * during or after when this call is made. * + * @note This function is available only if @kconfig{CONFIG_DYNAMIC_OBJECTS} + * is selected. + * * @param obj Pointer to the kernel object memory address. */ void k_object_free(void *obj); From 85d76f970fcc26cbdb25cfac5ebe37ecc5968f97 Mon Sep 17 00:00:00 2001 From: Mateusz Karlic Date: Thu, 30 Nov 2023 12:27:40 +0100 Subject: [PATCH 0581/3723] dts: boards: mercury_xu: Select shell-uart Select shell-uart for mercury_xu, to use shell_module sample. Signed-off-by: Mateusz Karlic --- boards/arm/mercury_xu/mercury_xu.dts | 1 + 1 file changed, 1 insertion(+) diff --git a/boards/arm/mercury_xu/mercury_xu.dts b/boards/arm/mercury_xu/mercury_xu.dts index c58e48e31f9..f6af2ca3018 100644 --- a/boards/arm/mercury_xu/mercury_xu.dts +++ b/boards/arm/mercury_xu/mercury_xu.dts @@ -13,6 +13,7 @@ chosen { zephyr,console = &uart0; + zephyr,shell-uart = &uart0; zephyr,sram = &sram0; zephyr,flash = &flash0; }; From fa69f472aa89899d2beb59b933480aed0e944f5e Mon Sep 17 00:00:00 2001 From: Declan Snyder Date: Thu, 30 Nov 2023 17:18:59 -0600 Subject: [PATCH 0582/3723] drivers: mdio_nxp_enet: fix ampersands typo Fix code typo with &&->& and redundant operation Signed-off-by: Declan Snyder --- drivers/mdio/mdio_nxp_enet.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/mdio/mdio_nxp_enet.c b/drivers/mdio/mdio_nxp_enet.c index c1a3df31692..2ea43e48424 100644 --- a/drivers/mdio/mdio_nxp_enet.c +++ b/drivers/mdio/mdio_nxp_enet.c @@ -62,7 +62,7 @@ static int nxp_enet_mdio_wait_xfer(const struct device *dev) * ethernet driver has not initiaized, just do a busy wait */ k_busy_wait(USEC_PER_MSEC * config->timeout); - if (base->EIR && ENET_EIR_MII_MASK == ENET_EIR_MII_MASK) { + if (base->EIR & ENET_EIR_MII_MASK) { ret = 0; } else { ret = -ETIMEDOUT; @@ -70,7 +70,7 @@ static int nxp_enet_mdio_wait_xfer(const struct device *dev) } else if (k_sem_take(&data->mdio_sem, K_MSEC(config->timeout))) { /* Interrupt was enabled but did not occur in time */ ret = -ETIMEDOUT; - } else if (base->EIR && ENET_EIR_MII_MASK == ENET_EIR_MII_MASK) { + } else if (base->EIR & ENET_EIR_MII_MASK) { /* Interrupt happened meaning mdio transaction completed */ ret = 0; } else { From 6b644dff676e56e1402e72db8efe121c1d6b5b43 Mon Sep 17 00:00:00 2001 From: Mario Paja Date: Fri, 1 Dec 2023 07:59:04 +0100 Subject: [PATCH 0583/3723] net: gptp: Fix announce message len This fix addresses wrong announce message length warning message. TLV is a variable length (4+8N) based on the 802.1AS-2011 (table 10-8). In Zephyr TLV is fixed to 12 bytes. TLV type and length are already taken into account in the announcement message length. Signed-off-by: Mario Paja --- subsys/net/l2/ethernet/gptp/gptp_messages.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/subsys/net/l2/ethernet/gptp/gptp_messages.h b/subsys/net/l2/ethernet/gptp/gptp_messages.h index 35c5fea2798..38c4f60349c 100644 --- a/subsys/net/l2/ethernet/gptp/gptp_messages.h +++ b/subsys/net/l2/ethernet/gptp/gptp_messages.h @@ -68,7 +68,7 @@ extern "C" { #define GPTP_ANNOUNCE_LEN(pkt) \ (sizeof(struct gptp_hdr) + sizeof(struct gptp_announce) \ + ntohs(GPTP_ANNOUNCE(pkt)->tlv.len) \ - - sizeof(struct gptp_path_trace_tlv) + 4) + - sizeof(struct gptp_path_trace_tlv)) #define GPTP_CHECK_LEN(pkt, len) \ ((GPTP_PACKET_LEN(pkt) != len) && (GPTP_VALID_LEN(pkt, len))) From cb7b650b923f160540943f0724b79b79fd8e51f4 Mon Sep 17 00:00:00 2001 From: Kapil Bhatt Date: Fri, 1 Dec 2023 13:36:39 +0530 Subject: [PATCH 0584/3723] net: l2: wifi: Fix Print of SSID in WIFI status MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit While printing SSID in wifi status command, If the length is maximum(32 character). It leads to buffer overflow. It required one character for null terminator ‘\0’. Changing the Format Specifiers to print proper SSID. Signed-off-by: Kapil Bhatt --- subsys/net/l2/wifi/wifi_shell.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/subsys/net/l2/wifi/wifi_shell.c b/subsys/net/l2/wifi/wifi_shell.c index ed85b015971..5f7eb5ba0ee 100644 --- a/subsys/net/l2/wifi/wifi_shell.c +++ b/subsys/net/l2/wifi/wifi_shell.c @@ -647,7 +647,7 @@ static int cmd_wifi_status(const struct shell *sh, size_t argc, char *argv[]) wifi_mode_txt(status.iface_mode)); shell_fprintf(sh, SHELL_NORMAL, "Link Mode: %s\n", wifi_link_mode_txt(status.link_mode)); - shell_fprintf(sh, SHELL_NORMAL, "SSID: %-32s\n", status.ssid); + shell_fprintf(sh, SHELL_NORMAL, "SSID: %.32s\n", status.ssid); shell_fprintf(sh, SHELL_NORMAL, "BSSID: %s\n", net_sprint_ll_addr_buf(status.bssid, WIFI_MAC_ADDR_LEN, mac_string_buf, From ca3c970a1dca7af1859893e647df05ae8caf4343 Mon Sep 17 00:00:00 2001 From: Aymeric Aillet Date: Tue, 28 Nov 2023 14:27:01 +0100 Subject: [PATCH 0585/3723] doc: release: 3.6: Add new R-Car Gen4 SoC series Added support to R-Car Gen4 SoCs & boards Existing drivers now supports Gen4 SoCs Signed-off-by: Aymeric Aillet --- doc/releases/release-notes-3.6.rst | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/doc/releases/release-notes-3.6.rst b/doc/releases/release-notes-3.6.rst index 1fe962c0a3c..43d1b306eb9 100644 --- a/doc/releases/release-notes-3.6.rst +++ b/doc/releases/release-notes-3.6.rst @@ -59,6 +59,8 @@ Boards & SoC Support * Added support for these SoC series: + * Added support for Renesas R-Car Gen4 series + * Removed support for these SoC series: * Made these changes in other SoC series: @@ -70,6 +72,8 @@ Boards & SoC Support * Added support for these ARM boards: + * Added support for Renesas R-Car Spider board CR52: ``rcar_spider_cr52`` + * Added support for these ARM64 boards: * Added support for these RISC-V boards: @@ -126,6 +130,8 @@ Drivers and Sensors * Clock control + * Renesas R-Car clock control driver now supports Gen4 SoCs + * Counter * DAC @@ -146,6 +152,8 @@ Drivers and Sensors * GPIO + * Renesas R-Car GPIO driver now supports Gen4 SoCs + * I2C * I2S @@ -167,6 +175,8 @@ Drivers and Sensors * Pin control + * Renesas R-Car pinctrl driver now supports Gen4 SoCs + * PWM * Regulators From 08e42b147edb4d1f52d297b02df8497b0b962c9d Mon Sep 17 00:00:00 2001 From: Tim Lin Date: Thu, 23 Nov 2023 14:17:15 +0800 Subject: [PATCH 0586/3723] ITE: drivers/gpio: Correct the wake up control input The wake-up control input is IT8XXX2_IRQ_WU66. Testing the wake-up functionality on GPF6 is normal. Signed-off-by: Tim Lin --- drivers/gpio/gpio_ite_it8xxx2.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/gpio/gpio_ite_it8xxx2.c b/drivers/gpio/gpio_ite_it8xxx2.c index 754a3b773f1..1171c5b3391 100644 --- a/drivers/gpio/gpio_ite_it8xxx2.c +++ b/drivers/gpio/gpio_ite_it8xxx2.c @@ -149,7 +149,7 @@ static const struct { [IT8XXX2_IRQ_WU63] = {BIT(3), 6, BIT(3)}, [IT8XXX2_IRQ_WU64] = {BIT(4), 6, BIT(4)}, [IT8XXX2_IRQ_WU65] = {BIT(5), 6, BIT(5)}, - [IT8XXX2_IRQ_WU65] = {BIT(6), 6, BIT(6)}, + [IT8XXX2_IRQ_WU66] = {BIT(6), 6, BIT(6)}, [IT8XXX2_IRQ_WU67] = {BIT(7), 6, BIT(7)}, [IT8XXX2_IRQ_WU70] = {BIT(0), 7, BIT(0)}, [IT8XXX2_IRQ_WU71] = {BIT(1), 7, BIT(1)}, From ad485866b083f470c01e1b07575866423a00dc45 Mon Sep 17 00:00:00 2001 From: Adam Cavender Date: Mon, 27 Nov 2023 10:55:45 +0000 Subject: [PATCH 0587/3723] Bluetooth: Host: Fix bt_le_set_chan_map Allow the channel map to be set when periodic advertising or acting as an ISO source. Signed-off-by: Adam Cavender --- subsys/bluetooth/host/hci_core.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/subsys/bluetooth/host/hci_core.c b/subsys/bluetooth/host/hci_core.c index e4ea19c6dce..ae716406c2b 100644 --- a/subsys/bluetooth/host/hci_core.c +++ b/subsys/bluetooth/host/hci_core.c @@ -4320,7 +4320,7 @@ int bt_le_set_chan_map(uint8_t chan_map[5]) struct bt_hci_cp_le_set_host_chan_classif *cp; struct net_buf *buf; - if (!IS_ENABLED(CONFIG_BT_CENTRAL)) { + if (!(IS_ENABLED(CONFIG_BT_CENTRAL) || IS_ENABLED(CONFIG_BT_BROADCASTER))) { return -ENOTSUP; } From ac4f9a6962e17cf1e34b7238aec44b6f7b0f1417 Mon Sep 17 00:00:00 2001 From: Adam Cavender Date: Mon, 27 Nov 2023 12:39:15 +0000 Subject: [PATCH 0588/3723] Bluetooth: Shell: Fix cmd_chan_map Allow the channel map to be set when periodic advertising or acting as an ISO source. Signed-off-by: Adam Cavender --- subsys/bluetooth/shell/bt.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/subsys/bluetooth/shell/bt.c b/subsys/bluetooth/shell/bt.c index 4e0111fa757..ac1d78c44df 100644 --- a/subsys/bluetooth/shell/bt.c +++ b/subsys/bluetooth/shell/bt.c @@ -4286,7 +4286,7 @@ SHELL_STATIC_SUBCMD_SET_CREATE(bt_cmds, SHELL_CMD_ARG(phy-update, NULL, " [rx_phy] [s2] [s8]", cmd_conn_phy_update, 2, 3), #endif -#if defined(CONFIG_BT_CENTRAL) +#if defined(CONFIG_BT_CENTRAL) || defined(CONFIG_BT_BROADCASTER) SHELL_CMD_ARG(channel-map, NULL, " (36-0)", cmd_chan_map, 2, 1), #endif /* CONFIG_BT_CENTRAL */ From 20fd6a10e1f293686e8f06931c5cb7f26cb143e9 Mon Sep 17 00:00:00 2001 From: Guillaume Gautier Date: Wed, 15 Nov 2023 15:46:28 +0100 Subject: [PATCH 0589/3723] drivers: adc: stm32: prevent pm while measurement in progress Prevent PM while ADC measurement in progress. Signed-off-by: Guillaume Gautier --- drivers/adc/adc_stm32.c | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/drivers/adc/adc_stm32.c b/drivers/adc/adc_stm32.c index 1710ec011bc..7c97958c8f2 100644 --- a/drivers/adc/adc_stm32.c +++ b/drivers/adc/adc_stm32.c @@ -20,6 +20,7 @@ #include #include #include +#include #include #if defined(CONFIG_SOC_SERIES_STM32U5X) #include @@ -760,6 +761,8 @@ static void dma_callback(const struct device *dev, void *user_data, * the address is in a non-cacheable SRAM region. */ adc_context_on_sampling_done(&data->ctx, dev); + pm_policy_state_lock_put(PM_STATE_SUSPEND_TO_IDLE, + PM_ALL_SUBSTATES); } else if (status < 0) { LOG_ERR("DMA sampling complete, but DMA reported error %d", status); data->dma_error = status; @@ -1060,6 +1063,8 @@ static void adc_stm32_isr(const struct device *dev) if (++data->samples_count == data->channel_count) { data->samples_count = 0; adc_context_on_sampling_done(&data->ctx, dev); + pm_policy_state_lock_put(PM_STATE_SUSPEND_TO_IDLE, + PM_ALL_SUBSTATES); } } @@ -1098,6 +1103,7 @@ static int adc_stm32_read(const struct device *dev, int error; adc_context_lock(&data->ctx, false, NULL); + pm_policy_state_lock_get(PM_STATE_SUSPEND_TO_IDLE, PM_ALL_SUBSTATES); error = start_read(dev, sequence); adc_context_release(&data->ctx, error); @@ -1113,6 +1119,7 @@ static int adc_stm32_read_async(const struct device *dev, int error; adc_context_lock(&data->ctx, true, async); + pm_policy_state_lock_get(PM_STATE_SUSPEND_TO_IDLE, PM_ALL_SUBSTATES); error = start_read(dev, sequence); adc_context_release(&data->ctx, error); From 4ed761d8b4e3c9cfe35eaa79e0b799a926fbaf2c Mon Sep 17 00:00:00 2001 From: Guillaume Gautier Date: Thu, 9 Nov 2023 14:49:04 +0100 Subject: [PATCH 0590/3723] samples: boards: stm32: pm: adc: add adc channel for stm32wba Add ADC channel for STM32WBA power management sample Signed-off-by: Guillaume Gautier --- .../power_mgmt/adc/boards/nucleo_wba52cg.overlay | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/samples/boards/stm32/power_mgmt/adc/boards/nucleo_wba52cg.overlay b/samples/boards/stm32/power_mgmt/adc/boards/nucleo_wba52cg.overlay index 3cd6cb64bf5..f92c541e298 100644 --- a/samples/boards/stm32/power_mgmt/adc/boards/nucleo_wba52cg.overlay +++ b/samples/boards/stm32/power_mgmt/adc/boards/nucleo_wba52cg.overlay @@ -10,3 +10,17 @@ io-channels = <&adc4 8>; }; }; + +&adc4 { + pinctrl-0 = <&adc4_in8_pa1>; + #address-cells = <1>; + #size-cells = <0>; + + channel@8 { + reg = <8>; + zephyr,gain = "ADC_GAIN_1"; + zephyr,reference = "ADC_REF_INTERNAL"; + zephyr,acquisition-time = ; + zephyr,resolution = <12>; + }; +}; From fdc1cbf833a6376c491c47f5e1a0740c9d811a9d Mon Sep 17 00:00:00 2001 From: Wojciech Slenska Date: Thu, 14 Sep 2023 14:15:44 +0200 Subject: [PATCH 0591/3723] drivers: sensor: bmi323 interrupt fix Interupts should be enabled after int line configuration in bmi. When the device goes to a suspended state interrupts must be disabled. Signed-off-by: Wojciech Slenska --- drivers/sensor/bmi323/bmi323.c | 17 ++++++++++++++++- 1 file changed, 16 insertions(+), 1 deletion(-) diff --git a/drivers/sensor/bmi323/bmi323.c b/drivers/sensor/bmi323/bmi323.c index a77e4271070..65bdef619ec 100644 --- a/drivers/sensor/bmi323/bmi323.c +++ b/drivers/sensor/bmi323/bmi323.c @@ -1142,7 +1142,7 @@ static int bosch_bmi323_init_irq(const struct device *dev) return ret; } - return gpio_pin_interrupt_configure_dt(&config->int_gpio, GPIO_INT_EDGE_TO_ACTIVE); + return gpio_pin_interrupt_configure_dt(&config->int_gpio, GPIO_INT_DISABLE); } static int bosch_bmi323_init_int1(const struct device *dev) @@ -1172,6 +1172,7 @@ static void bosch_bmi323_irq_callback_handler(struct k_work *item) static int bosch_bmi323_pm_resume(const struct device *dev) { + const struct bosch_bmi323_config *config = (const struct bosch_bmi323_config *)dev->config; int ret; ret = bosch_bmi323_bus_init(dev); @@ -1218,6 +1219,12 @@ static int bosch_bmi323_pm_resume(const struct device *dev) if (ret < 0) { LOG_WRN("Failed to enable INT1"); + return ret; + } + + ret = gpio_pin_interrupt_configure_dt(&config->int_gpio, GPIO_INT_EDGE_TO_ACTIVE); + if (ret < 0) { + LOG_WRN("Failed to configure int"); } return ret; @@ -1226,6 +1233,14 @@ static int bosch_bmi323_pm_resume(const struct device *dev) #ifdef CONFIG_PM_DEVICE static int bosch_bmi323_pm_suspend(const struct device *dev) { + const struct bosch_bmi323_config *config = (const struct bosch_bmi323_config *)dev->config; + int ret; + + ret = gpio_pin_interrupt_configure_dt(&config->int_gpio, GPIO_INT_DISABLE); + if (ret < 0) { + LOG_WRN("Failed to disable int"); + } + /* Soft reset device to put it into suspend */ return bosch_bmi323_soft_reset(dev); } From d6a5a6e04c0a6f64b93d341af4b8f04bd698401c Mon Sep 17 00:00:00 2001 From: Guennadi Liakhovetski Date: Thu, 7 Sep 2023 17:53:19 +0200 Subject: [PATCH 0592/3723] llext: add support for shared objects Add support for linking PIC shared object, which only require linking, using their PLT and GOT lists and don't need any relocation otherwise. Signed-off-by: Guennadi Liakhovetski --- subsys/llext/llext.c | 112 +++++++++++++++++++++++++++++++++++++++++-- 1 file changed, 109 insertions(+), 3 deletions(-) diff --git a/subsys/llext/llext.c b/subsys/llext/llext.c index 3d99c8af4fa..7b8099a9190 100644 --- a/subsys/llext/llext.c +++ b/subsys/llext/llext.c @@ -446,6 +446,105 @@ static int llext_copy_symbols(struct llext_loader *ldr, struct llext *ext) return 0; } +/* + * Find the section, containing the supplied offset and return file offset for + * that value + */ +static size_t llext_file_offset(struct llext_loader *ldr, size_t offset) +{ + unsigned int i; + + for (i = 0; i < LLEXT_SECT_COUNT; i++) + if (ldr->sects[i].sh_addr <= offset && + ldr->sects[i].sh_addr + ldr->sects[i].sh_size > offset) + return offset - ldr->sects[i].sh_addr + ldr->sects[i].sh_offset; + + return offset; +} + +static void llext_link_plt(struct llext_loader *ldr, struct llext *ext, elf_shdr_t *shdr) +{ + unsigned int sh_cnt = shdr->sh_size / shdr->sh_entsize; + /* + * CPU address where the .text section is stored, we use .text just as a + * reference point + */ + uint8_t *text = ext->mem[LLEXT_MEM_TEXT]; + + LOG_DBG("Found %p in PLT %u size %u cnt %u text %p", + (void *)llext_string(ldr, ext, LLEXT_MEM_SHSTRTAB, shdr->sh_name), + shdr->sh_type, shdr->sh_entsize, sh_cnt, (void *)text); + + const elf_shdr_t *sym_shdr = ldr->sects + LLEXT_SECT_SYMTAB; + unsigned int sym_cnt = sym_shdr->sh_size / sym_shdr->sh_entsize; + + for (unsigned int i = 0; i < sh_cnt; i++) { + elf_rela_t rela; + + int ret = llext_seek(ldr, shdr->sh_offset + i * shdr->sh_entsize); + + if (!ret) { + ret = llext_read(ldr, &rela, sizeof(rela)); + } + + if (ret < 0) { + LOG_ERR("PLT: failed to read RELA #%u, trying to continue", i); + continue; + } + + /* Index in the symbol table */ + unsigned int j = ELF32_R_SYM(rela.r_info); + + if (j >= sym_cnt) { + LOG_WRN("PLT: idx %u >= %u", j, sym_cnt); + continue; + } + + elf_sym_t sym_tbl; + + ret = llext_seek(ldr, sym_shdr->sh_offset + j * sizeof(elf_sym_t)); + if (!ret) { + ret = llext_read(ldr, &sym_tbl, sizeof(sym_tbl)); + } + + if (ret < 0) { + LOG_ERR("PLT: failed to read symbol table #%u RELA #%u, trying to continue", + j, i); + continue; + } + + uint32_t stt = ELF_ST_TYPE(sym_tbl.st_info); + const char *name = llext_string(ldr, ext, LLEXT_MEM_STRTAB, sym_tbl.st_name); + /* + * Both r_offset and sh_addr are addresses for which the extension + * has been built. + */ + size_t got_offset = llext_file_offset(ldr, rela.r_offset) - + ldr->sects[LLEXT_SECT_TEXT].sh_offset; + + if (stt == STT_NOTYPE && sym_tbl.st_shndx == SHN_UNDEF && name[0] != '\0') { + const void *link_addr = llext_find_sym(NULL, name); + + if (!link_addr) { + LOG_WRN("PLT: cannot find idx %u name %s", j, name); + continue; + } + + if (!rela.r_offset) { + LOG_WRN("PLT: zero offset idx %u name %s", j, name); + continue; + } + + LOG_DBG("symbol %s offset %#x r-offset %#x .text offset %#x", + name, got_offset, + rela.r_offset, ldr->sects[LLEXT_SECT_TEXT].sh_offset); + + /* Resolve the symbol */ + *(const void **)(text + got_offset) = link_addr; + } + } +} + __weak void arch_elf_relocate(elf_rela_t *rel, uintptr_t opaddr, uintptr_t opval) { } @@ -486,12 +585,19 @@ static int llext_link(struct llext_loader *ldr, struct llext *ext) if (strcmp(name, ".rel.text") == 0 || strcmp(name, ".rela.text") == 0) { loc = (uintptr_t)ext->mem[LLEXT_MEM_TEXT]; - } else if (strcmp(name, ".rel.bss") == 0) { + } else if (strcmp(name, ".rel.bss") == 0 || + strcmp(name, ".rela.bss") == 0) { loc = (uintptr_t)ext->mem[LLEXT_MEM_BSS]; - } else if (strcmp(name, ".rel.rodata") == 0) { + } else if (strcmp(name, ".rel.rodata") == 0 || + strcmp(name, ".rela.rodata") == 0) { loc = (uintptr_t)ext->mem[LLEXT_MEM_RODATA]; - } else if (strcmp(name, ".rel.data") == 0) { + } else if (strcmp(name, ".rel.data") == 0 || + strcmp(name, ".rela.data") == 0) { loc = (uintptr_t)ext->mem[LLEXT_MEM_DATA]; + } else if (strcmp(name, ".rela.plt") == 0 || + strcmp(name, ".rela.dyn") == 0) { + llext_link_plt(ldr, ext, &shdr); + continue; } LOG_DBG("relocation section %s (%d) linked to section %d has %d relocations", From 03519afb841f30cb9743c271050ce69245fe4210 Mon Sep 17 00:00:00 2001 From: Guennadi Liakhovetski Date: Thu, 28 Sep 2023 13:59:53 +0200 Subject: [PATCH 0593/3723] llext: xtensa: add support for local symbol relocations Add support for relocating local symbols, as specified in the .rela.dyn section. Signed-off-by: Guennadi Liakhovetski --- arch/xtensa/core/CMakeLists.txt | 1 + arch/xtensa/core/elf.c | 44 +++++++++++++++++++++++++++++++++ include/zephyr/llext/llext.h | 11 +++++++++ subsys/llext/llext.c | 19 ++++++++++++-- 4 files changed, 73 insertions(+), 2 deletions(-) create mode 100644 arch/xtensa/core/elf.c diff --git a/arch/xtensa/core/CMakeLists.txt b/arch/xtensa/core/CMakeLists.txt index f3122c1a550..b415aec2e9c 100644 --- a/arch/xtensa/core/CMakeLists.txt +++ b/arch/xtensa/core/CMakeLists.txt @@ -24,6 +24,7 @@ zephyr_library_sources_ifdef(CONFIG_GDBSTUB gdbstub.c) zephyr_library_sources_ifdef(CONFIG_XTENSA_MMU ptables.c mmu.c) zephyr_library_sources_ifdef(CONFIG_USERSPACE userspace.S) zephyr_library_sources_ifdef(CONFIG_XTENSA_SYSCALL_USE_HELPER syscall_helper.c) +zephyr_library_sources_ifdef(CONFIG_LLEXT elf.c) zephyr_library_sources_ifdef( CONFIG_KERNEL_VM_USE_CUSTOM_MEM_RANGE_CHECK diff --git a/arch/xtensa/core/elf.c b/arch/xtensa/core/elf.c new file mode 100644 index 00000000000..959f374888c --- /dev/null +++ b/arch/xtensa/core/elf.c @@ -0,0 +1,44 @@ +/* + * Copyright (c) 2023 Intel Corporation + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include +#include +#include + +LOG_MODULE_DECLARE(llext); + +#define R_XTENSA_NONE 0 +#define R_XTENSA_32 1 +#define R_XTENSA_RTLD 2 +#define R_XTENSA_GLOB_DAT 3 +#define R_XTENSA_JMP_SLOT 4 +#define R_XTENSA_RELATIVE 5 +#define R_XTENSA_PLT 6 + +/** + * @brief Architecture specific function for relocating shared elf + * + * Elf files contain a series of relocations described in multiple sections. + * These relocation instructions are architecture specific and each architecture + * supporting modules must implement this. + */ +void arch_elf_relocate_local(struct llext_loader *ldr, struct llext *ext, + elf_rela_t *rel, size_t got_offset) +{ + uint8_t *text = ext->mem[LLEXT_MEM_TEXT]; + int type = ELF32_R_TYPE(rel->r_info); + + if (type == R_XTENSA_RELATIVE) { + elf_word ptr_offset = *(elf_word *)(text + got_offset); + + LOG_DBG("relocation type %u offset %#x value %#x", + type, got_offset, ptr_offset); + + /* Relocate a local symbol: Xtensa specific */ + *(elf_word *)(text + got_offset) = (elf_word)(text + ptr_offset - + ldr->sects[LLEXT_SECT_TEXT].sh_addr); + } +} diff --git a/include/zephyr/llext/llext.h b/include/zephyr/llext/llext.h index a4458a05468..60ce1cae47a 100644 --- a/include/zephyr/llext/llext.h +++ b/include/zephyr/llext/llext.h @@ -142,6 +142,17 @@ int llext_call_fn(struct llext *ext, const char *sym_name); */ void arch_elf_relocate(elf_rela_t *rel, uintptr_t opaddr, uintptr_t opval); +/** + * @brief Architecture specific function for updating addresses via relocation table + * + * @param[in] loader Extension loader data and context + * @param[in] ext Extension to call function in + * @param[in] rel Relocation data provided by elf + * @param[in] got_offset Offset within a relocation table + */ +void arch_elf_relocate_local(struct llext_loader *loader, struct llext *ext, + elf_rela_t *rel, size_t got_offset); + /** * @} */ diff --git a/subsys/llext/llext.c b/subsys/llext/llext.c index 7b8099a9190..57e8fb2e828 100644 --- a/subsys/llext/llext.c +++ b/subsys/llext/llext.c @@ -462,6 +462,11 @@ static size_t llext_file_offset(struct llext_loader *ldr, size_t offset) return offset; } +__weak void arch_elf_relocate_local(struct llext_loader *ldr, struct llext *ext, + elf_rela_t *rel, size_t got_offset) +{ +} + static void llext_link_plt(struct llext_loader *ldr, struct llext *ext, elf_shdr_t *shdr) { unsigned int sh_cnt = shdr->sh_size / shdr->sh_entsize; @@ -514,6 +519,7 @@ static void llext_link_plt(struct llext_loader *ldr, struct llext *ext, elf_shdr } uint32_t stt = ELF_ST_TYPE(sym_tbl.st_info); + uint32_t stb = ELF_ST_BIND(sym_tbl.st_info); const char *name = llext_string(ldr, ext, LLEXT_MEM_STRTAB, sym_tbl.st_name); /* * Both r_offset and sh_addr are addresses for which the extension @@ -522,8 +528,14 @@ static void llext_link_plt(struct llext_loader *ldr, struct llext *ext, elf_shdr size_t got_offset = llext_file_offset(ldr, rela.r_offset) - ldr->sects[LLEXT_SECT_TEXT].sh_offset; - if (stt == STT_NOTYPE && sym_tbl.st_shndx == SHN_UNDEF && name[0] != '\0') { - const void *link_addr = llext_find_sym(NULL, name); + if (stt != STT_NOTYPE || sym_tbl.st_shndx != SHN_UNDEF) + continue; + + const void *link_addr; + + switch (stb) { + case STB_GLOBAL: + link_addr = llext_find_sym(NULL, name); if (!link_addr) { LOG_WRN("PLT: cannot find idx %u name %s", j, name); @@ -541,6 +553,9 @@ static void llext_link_plt(struct llext_loader *ldr, struct llext *ext, elf_shdr /* Resolve the symbol */ *(const void **)(text + got_offset) = link_addr; + break; + case STB_LOCAL: + arch_elf_relocate_local(ldr, ext, &rela, got_offset); } } } From f98b8bb48fdb0df4cc4ea2f8fe4b75b70245a520 Mon Sep 17 00:00:00 2001 From: Guennadi Liakhovetski Date: Fri, 22 Sep 2023 16:15:18 +0200 Subject: [PATCH 0594/3723] llext: add a function for finding ELF sections Applications can use custom ELF sections for their own purposes, add a function for finding them. Signed-off-by: Guennadi Liakhovetski --- include/zephyr/llext/llext.h | 9 +++++++++ subsys/llext/llext.c | 27 +++++++++++++++++++++++++++ 2 files changed, 36 insertions(+) diff --git a/include/zephyr/llext/llext.h b/include/zephyr/llext/llext.h index 60ce1cae47a..96bd64d2854 100644 --- a/include/zephyr/llext/llext.h +++ b/include/zephyr/llext/llext.h @@ -142,6 +142,15 @@ int llext_call_fn(struct llext *ext, const char *sym_name); */ void arch_elf_relocate(elf_rela_t *rel, uintptr_t opaddr, uintptr_t opval); +/** + * @brief Find an ELF section + * + * @param loader Extension loader data and context + * @param search_name Section name to search for + * @retval Section offset or a negative error code + */ +ssize_t llext_find_section(struct llext_loader *loader, const char *search_name); + /** * @brief Architecture specific function for updating addresses via relocation table * diff --git a/subsys/llext/llext.c b/subsys/llext/llext.c index 57e8fb2e828..6598652840b 100644 --- a/subsys/llext/llext.c +++ b/subsys/llext/llext.c @@ -47,6 +47,33 @@ sys_slist_t *llext_list(void) return &_llext_list; } +ssize_t llext_find_section(struct llext_loader *ldr, const char *search_name) +{ + elf_shdr_t *shdr; + unsigned int i; + size_t pos; + + for (i = 0, pos = ldr->hdr.e_shoff; + i < ldr->hdr.e_shnum; + i++, pos += ldr->hdr.e_shentsize) { + shdr = llext_peek(ldr, pos); + if (!shdr) { + /* The peek() method isn't supported */ + return -EOPNOTSUPP; + } + + const char *name = llext_peek(ldr, + ldr->sects[LLEXT_SECT_SHSTRTAB].sh_offset + + shdr->sh_name); + + if (!strcmp(name, search_name)) { + return shdr->sh_offset; + } + } + + return -ENOENT; +} + struct llext *llext_by_name(const char *name) { sys_slist_t *mlist = llext_list(); From 69cdc3289279f476a495e6920a954fc194eec043 Mon Sep 17 00:00:00 2001 From: Guennadi Liakhovetski Date: Wed, 6 Sep 2023 15:52:46 +0200 Subject: [PATCH 0595/3723] llext: export some symbols Export some symbols for loadable modules. Also add an EXPORT_SYSCALL() helper macro for exporting system calls by their official names. Signed-off-by: Guennadi Liakhovetski --- include/zephyr/llext/symbol.h | 10 ++++++++++ kernel/mutex.c | 3 +++ kernel/thread.c | 2 ++ lib/os/assert.c | 4 +++- subsys/llext/CMakeLists.txt | 3 +-- subsys/llext/llext_export.c | 17 +++++++++++++++++ subsys/logging/log_msg.c | 2 ++ 7 files changed, 38 insertions(+), 3 deletions(-) create mode 100644 subsys/llext/llext_export.c diff --git a/include/zephyr/llext/symbol.h b/include/zephyr/llext/symbol.h index b1aef67413e..84e43d22b5b 100644 --- a/include/zephyr/llext/symbol.h +++ b/include/zephyr/llext/symbol.h @@ -78,6 +78,16 @@ struct llext_symtable { .name = STRINGIFY(x), .addr = &x, \ } +/** + * @brief Export a system call to a table of symbols + * + * Takes a system call name and uses @a EXPORT_SYMBOL() to export the respective + * function. + * + * @param x System call to export + */ +#define EXPORT_SYSCALL(x) EXPORT_SYMBOL(z_impl_ ## x) + /** * @} */ diff --git a/kernel/mutex.c b/kernel/mutex.c index 6d22ce83f22..622422aef7b 100644 --- a/kernel/mutex.c +++ b/kernel/mutex.c @@ -37,6 +37,7 @@ #include #include #include +#include LOG_MODULE_DECLARE(os, CONFIG_KERNEL_LOG_LEVEL); /* We use a global spinlock here because some of the synchronization @@ -195,6 +196,7 @@ int z_impl_k_mutex_lock(struct k_mutex *mutex, k_timeout_t timeout) return -EAGAIN; } +EXPORT_SYSCALL(k_mutex_lock); #ifdef CONFIG_USERSPACE static inline int z_vrfy_k_mutex_lock(struct k_mutex *mutex, @@ -280,6 +282,7 @@ int z_impl_k_mutex_unlock(struct k_mutex *mutex) return 0; } +EXPORT_SYSCALL(k_mutex_unlock); #ifdef CONFIG_USERSPACE static inline int z_vrfy_k_mutex_unlock(struct k_mutex *mutex) diff --git a/kernel/thread.c b/kernel/thread.c index 8f60054e798..fc31f4b36d8 100644 --- a/kernel/thread.c +++ b/kernel/thread.c @@ -29,6 +29,7 @@ #include #include #include +#include #include LOG_MODULE_DECLARE(os, CONFIG_KERNEL_LOG_LEVEL); @@ -141,6 +142,7 @@ bool k_is_in_isr(void) { return arch_is_in_isr(); } +EXPORT_SYMBOL(k_is_in_isr); /* * This function tags the current thread as essential to system operation. diff --git a/lib/os/assert.c b/lib/os/assert.c index b6a33ae7320..1fee487bff6 100644 --- a/lib/os/assert.c +++ b/lib/os/assert.c @@ -7,7 +7,7 @@ #include #include #include - +#include /** * @brief Assert Action Handler @@ -42,6 +42,7 @@ __weak void assert_post_action(const char *file, unsigned int line) k_panic(); } +EXPORT_SYMBOL(assert_post_action); void assert_print(const char *fmt, ...) { @@ -53,3 +54,4 @@ void assert_print(const char *fmt, ...) va_end(ap); } +EXPORT_SYMBOL(assert_print); diff --git a/subsys/llext/CMakeLists.txt b/subsys/llext/CMakeLists.txt index ac54f3172c3..b129dc7f943 100644 --- a/subsys/llext/CMakeLists.txt +++ b/subsys/llext/CMakeLists.txt @@ -1,6 +1,5 @@ if(CONFIG_LLEXT) zephyr_library() - zephyr_library_sources(llext.c) - zephyr_library_sources(buf_loader.c) + zephyr_library_sources(llext.c llext_export.c buf_loader.c) zephyr_library_sources_ifdef(CONFIG_LLEXT_SHELL shell.c) endif() diff --git a/subsys/llext/llext_export.c b/subsys/llext/llext_export.c new file mode 100644 index 00000000000..0ec7fe4ac0a --- /dev/null +++ b/subsys/llext/llext_export.c @@ -0,0 +1,17 @@ +/* + * Copyright (c) 2023 Intel Corporation + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include +#include + +EXPORT_SYMBOL(strcpy); +EXPORT_SYMBOL(strncpy); +EXPORT_SYMBOL(strlen); +EXPORT_SYMBOL(strcmp); +EXPORT_SYMBOL(strncmp); +EXPORT_SYMBOL(memcmp); +EXPORT_SYMBOL(memcpy); +EXPORT_SYMBOL(memset); diff --git a/subsys/logging/log_msg.c b/subsys/logging/log_msg.c index 8023cefbf8c..da9dffdc62e 100644 --- a/subsys/logging/log_msg.c +++ b/subsys/logging/log_msg.c @@ -10,6 +10,7 @@ #include #include #include +#include LOG_MODULE_DECLARE(log); BUILD_ASSERT(sizeof(struct log_msg_desc) == sizeof(uint32_t), @@ -270,6 +271,7 @@ void z_impl_z_log_msg_static_create(const void *source, z_log_msg_finalize(msg, source, out_desc, data); } +EXPORT_SYSCALL(z_log_msg_static_create); #ifdef CONFIG_USERSPACE static inline void z_vrfy_z_log_msg_static_create(const void *source, From b0b4b0baa004d7f0d448f389454ba50a6604955e Mon Sep 17 00:00:00 2001 From: Guennadi Liakhovetski Date: Tue, 26 Sep 2023 13:02:25 +0200 Subject: [PATCH 0596/3723] llext: make local relocations optional Some applications can decide to link their loadable objects for exactly the same addresses, where they will be loaded. In those cases local relocations aren't needed any more and can in fact break the object if applied while the object is in a temporary storage. Add a parameter to skip such local relocations. Signed-off-by: Guennadi Liakhovetski --- include/zephyr/llext/llext.h | 17 +++++++++- subsys/llext/llext.c | 37 +++++++++++++--------- subsys/llext/shell.c | 3 +- tests/subsys/llext/src/test_llext_simple.c | 3 +- 4 files changed, 42 insertions(+), 18 deletions(-) diff --git a/include/zephyr/llext/llext.h b/include/zephyr/llext/llext.h index 96bd64d2854..5376e2cf13a 100644 --- a/include/zephyr/llext/llext.h +++ b/include/zephyr/llext/llext.h @@ -78,6 +78,19 @@ sys_slist_t *llext_list(void); */ struct llext *llext_by_name(const char *name); +/** + * @brief llext loader parameters + * + * These are parameters, not saved in the permanent llext context, needed only + * for the loader + */ +struct llext_load_param { + /** Should local relocation be performed */ + bool relocate_local; +}; + +#define LLEXT_LOAD_PARAM_DEFAULT {.relocate_local = true,} + /** * @brief Load and link an extension * @@ -88,12 +101,14 @@ struct llext *llext_by_name(const char *name); * @param[in] loader An extension loader that provides input data and context * @param[in] name A string identifier for the extension * @param[out] ext A pointer to a statically allocated llext struct + * @param[in] ldr_parm Loader parameters * * @retval 0 Success * @retval -ENOMEM Not enough memory * @retval -EINVAL Invalid ELF stream */ -int llext_load(struct llext_loader *loader, const char *name, struct llext **ext); +int llext_load(struct llext_loader *loader, const char *name, struct llext **ext, + struct llext_load_param *ldr_parm); /** * @brief Unload an extension diff --git a/subsys/llext/llext.c b/subsys/llext/llext.c index 6598652840b..d71f2a2a102 100644 --- a/subsys/llext/llext.c +++ b/subsys/llext/llext.c @@ -494,7 +494,8 @@ __weak void arch_elf_relocate_local(struct llext_loader *ldr, struct llext *ext, { } -static void llext_link_plt(struct llext_loader *ldr, struct llext *ext, elf_shdr_t *shdr) +static void llext_link_plt(struct llext_loader *ldr, struct llext *ext, + elf_shdr_t *shdr, bool do_local) { unsigned int sh_cnt = shdr->sh_size / shdr->sh_entsize; /* @@ -547,6 +548,11 @@ static void llext_link_plt(struct llext_loader *ldr, struct llext *ext, elf_shdr uint32_t stt = ELF_ST_TYPE(sym_tbl.st_info); uint32_t stb = ELF_ST_BIND(sym_tbl.st_info); + + if (stt != STT_NOTYPE || sym_tbl.st_shndx != SHN_UNDEF) { + continue; + } + const char *name = llext_string(ldr, ext, LLEXT_MEM_STRTAB, sym_tbl.st_name); /* * Both r_offset and sh_addr are addresses for which the extension @@ -555,9 +561,6 @@ static void llext_link_plt(struct llext_loader *ldr, struct llext *ext, elf_shdr size_t got_offset = llext_file_offset(ldr, rela.r_offset) - ldr->sects[LLEXT_SECT_TEXT].sh_offset; - if (stt != STT_NOTYPE || sym_tbl.st_shndx != SHN_UNDEF) - continue; - const void *link_addr; switch (stb) { @@ -574,16 +577,18 @@ static void llext_link_plt(struct llext_loader *ldr, struct llext *ext, elf_shdr continue; } - LOG_DBG("symbol %s offset %#x r-offset %#x .text offset %#x", - name, got_offset, - rela.r_offset, ldr->sects[LLEXT_SECT_TEXT].sh_offset); - /* Resolve the symbol */ *(const void **)(text + got_offset) = link_addr; break; case STB_LOCAL: - arch_elf_relocate_local(ldr, ext, &rela, got_offset); + if (do_local) { + arch_elf_relocate_local(ldr, ext, &rela, got_offset); + } } + + LOG_DBG("symbol %s offset %#x r-offset %#x .text offset %#x stb %u", + name, got_offset, + rela.r_offset, ldr->sects[LLEXT_SECT_TEXT].sh_offset, stb); } } @@ -591,7 +596,7 @@ __weak void arch_elf_relocate(elf_rela_t *rel, uintptr_t opaddr, uintptr_t opval { } -static int llext_link(struct llext_loader *ldr, struct llext *ext) +static int llext_link(struct llext_loader *ldr, struct llext *ext, bool do_local) { uintptr_t loc = 0; elf_shdr_t shdr; @@ -638,7 +643,7 @@ static int llext_link(struct llext_loader *ldr, struct llext *ext) loc = (uintptr_t)ext->mem[LLEXT_MEM_DATA]; } else if (strcmp(name, ".rela.plt") == 0 || strcmp(name, ".rela.dyn") == 0) { - llext_link_plt(ldr, ext, &shdr); + llext_link_plt(ldr, ext, &shdr, do_local); continue; } @@ -724,7 +729,8 @@ static int llext_link(struct llext_loader *ldr, struct llext *ext) /* * Load a valid ELF as an extension */ -static int do_llext_load(struct llext_loader *ldr, struct llext *ext) +static int do_llext_load(struct llext_loader *ldr, struct llext *ext, + struct llext_load_param *ldr_parm) { int ret = 0; @@ -793,7 +799,7 @@ static int do_llext_load(struct llext_loader *ldr, struct llext *ext) } LOG_DBG("Linking ELF..."); - ret = llext_link(ldr, ext); + ret = llext_link(ldr, ext, ldr_parm ? ldr_parm->relocate_local : true); if (ret != 0) { LOG_ERR("Failed to link, ret %d", ret); goto out; @@ -818,7 +824,8 @@ static int do_llext_load(struct llext_loader *ldr, struct llext *ext) return ret; } -int llext_load(struct llext_loader *ldr, const char *name, struct llext **ext) +int llext_load(struct llext_loader *ldr, const char *name, struct llext **ext, + struct llext_load_param *ldr_parm) { int ret; elf_ehdr_t ehdr; @@ -857,7 +864,7 @@ int llext_load(struct llext_loader *ldr, const char *name, struct llext **ext) } ldr->hdr = ehdr; - ret = do_llext_load(ldr, *ext); + ret = do_llext_load(ldr, *ext, ldr_parm); break; default: LOG_ERR("Unsupported elf file type %x", ehdr.e_type); diff --git a/subsys/llext/shell.c b/subsys/llext/shell.c index b9a4121acc6..289ebaa4d35 100644 --- a/subsys/llext/shell.c +++ b/subsys/llext/shell.c @@ -117,8 +117,9 @@ static int cmd_llext_load_hex(const struct shell *sh, size_t argc, char *argv[]) hex_len, CONFIG_LLEXT_SHELL_MAX_SIZE, llext_buf_len); LOG_HEXDUMP_DBG(llext_buf, 4, "4 byte MAGIC"); + struct llext_load_param ldr_parm = LLEXT_LOAD_PARAM_DEFAULT; struct llext *ext; - int res = llext_load(ldr, name, &ext); + int res = llext_load(ldr, name, &ext, &ldr_parm); if (res == 0) { shell_print(sh, "Successfully loaded extension %s, addr %p\n", ext->name, ext); diff --git a/tests/subsys/llext/src/test_llext_simple.c b/tests/subsys/llext/src/test_llext_simple.c index ef0e62b93b5..0b002c79e71 100644 --- a/tests/subsys/llext/src/test_llext_simple.c +++ b/tests/subsys/llext/src/test_llext_simple.c @@ -28,12 +28,13 @@ ZTEST(llext, test_llext_simple) struct llext_buf_loader buf_loader = LLEXT_BUF_LOADER(hello_world_elf, ARRAY_SIZE(hello_world_elf)); struct llext_loader *loader = &buf_loader.loader; + struct llext_load_param ldr_parm = LLEXT_LOAD_PARAM_DEFAULT; struct llext *ext; const void * const printk_fn = llext_find_sym(NULL, "printk"); zassert_equal(printk_fn, printk, "printk should be an exported symbol"); - int res = llext_load(loader, name, &ext); + int res = llext_load(loader, name, &ext, &ldr_parm); zassert_ok(res, "load should succeed"); From a2a62b46a32bb6f4dcf8a21ee229e8eeea2c594d Mon Sep 17 00:00:00 2001 From: Guennadi Liakhovetski Date: Thu, 28 Sep 2023 16:45:34 +0200 Subject: [PATCH 0597/3723] llext: make buffer access functions accessible externally llext_seek(), llext_read() and llext_peek() are needed outside of the extension code too, move them to a header. Signed-off-by: Guennadi Liakhovetski --- include/zephyr/llext/loader.h | 19 +++++++++++++++++++ subsys/llext/llext.c | 19 ------------------- 2 files changed, 19 insertions(+), 19 deletions(-) diff --git a/include/zephyr/llext/loader.h b/include/zephyr/llext/loader.h index 3cc53da7d88..3102f17cf1a 100644 --- a/include/zephyr/llext/loader.h +++ b/include/zephyr/llext/loader.h @@ -97,6 +97,25 @@ struct llext_loader { /** @endcond */ }; +static inline int llext_read(struct llext_loader *l, void *buf, size_t len) +{ + return l->read(l, buf, len); +} + +static inline int llext_seek(struct llext_loader *l, size_t pos) +{ + return l->seek(l, pos); +} + +static inline void *llext_peek(struct llext_loader *l, size_t pos) +{ + if (l->peek) { + return l->peek(l, pos); + } + + return NULL; +} + /** * @} */ diff --git a/subsys/llext/llext.c b/subsys/llext/llext.c index d71f2a2a102..e09539c6155 100644 --- a/subsys/llext/llext.c +++ b/subsys/llext/llext.c @@ -21,25 +21,6 @@ K_HEAP_DEFINE(llext_heap, CONFIG_LLEXT_HEAP_SIZE * 1024); static const char ELF_MAGIC[] = {0x7f, 'E', 'L', 'F'}; -static inline int llext_read(struct llext_loader *l, void *buf, size_t len) -{ - return l->read(l, buf, len); -} - -static inline int llext_seek(struct llext_loader *l, size_t pos) -{ - return l->seek(l, pos); -} - -static inline void *llext_peek(struct llext_loader *l, size_t pos) -{ - if (l->peek) { - return l->peek(l, pos); - } - - return NULL; -} - static sys_slist_t _llext_list = SYS_SLIST_STATIC_INIT(&_llext_list); sys_slist_t *llext_list(void) From e5c8d181d46f948e35851dd826637e32e48b77f6 Mon Sep 17 00:00:00 2001 From: Guennadi Liakhovetski Date: Fri, 29 Sep 2023 09:56:47 +0200 Subject: [PATCH 0598/3723] llext: add Xtensa test support Add support for running a modular "Hello world" example on Xtensa. Signed-off-by: Guennadi Liakhovetski --- tests/subsys/llext/hello_world/CMakeLists.txt | 23 +++++++++++++++---- tests/subsys/llext/src/test_llext_simple.c | 4 ++-- tests/subsys/llext/testcase.yaml | 5 ++++ 3 files changed, 26 insertions(+), 6 deletions(-) diff --git a/tests/subsys/llext/hello_world/CMakeLists.txt b/tests/subsys/llext/hello_world/CMakeLists.txt index 1a16d4be26b..6519075e2f4 100644 --- a/tests/subsys/llext/hello_world/CMakeLists.txt +++ b/tests/subsys/llext/hello_world/CMakeLists.txt @@ -6,11 +6,26 @@ find_package(Zephyr REQUIRED HINTS $ENV{ZEPHYR_BASE}) project(hello_world) # TODO check which architecture is being used -set(CMAKE_C_FLAGS "-mlong-calls" "-mthumb") +if(CONFIG_ARM) + set(CMAKE_C_FLAGS "-mlong-calls" "-mthumb") -add_custom_command(OUTPUT ${PROJECT_BINARY_DIR}/hello_world.llext - COMMAND ${CMAKE_C_COMPILER} ${CMAKE_C_FLAGS} -c -o ${PROJECT_BINARY_DIR}/hello_world.llext ${PROJECT_SOURCE_DIR}/hello_world.c -) + add_custom_command(OUTPUT ${PROJECT_BINARY_DIR}/hello_world.llext + COMMAND ${CMAKE_C_COMPILER} ${CMAKE_C_FLAGS} -c + -o ${PROJECT_BINARY_DIR}/hello_world.llext + ${PROJECT_SOURCE_DIR}/hello_world.c + ) +elseif(CONFIG_XTENSA) + set(CMAKE_C_FLAGS "-shared" "-fPIC" "-nostdlib" "-nodefaultlibs") + + add_custom_command(OUTPUT ${PROJECT_BINARY_DIR}/hello_world.llext + COMMAND ${CMAKE_C_COMPILER} ${CMAKE_C_FLAGS} + -o ${PROJECT_BINARY_DIR}/hello_world.pre.llext + ${PROJECT_SOURCE_DIR}/hello_world.c + COMMAND ${CROSS_COMPILE}strip -R .xt.* + -o ${PROJECT_BINARY_DIR}/hello_world.llext + ${PROJECT_BINARY_DIR}/hello_world.pre.llext + ) +endif() set(HELLO_WORLD_LLEXT ${PROJECT_BINARY_DIR}/hello_world.llext PARENT_SCOPE) diff --git a/tests/subsys/llext/src/test_llext_simple.c b/tests/subsys/llext/src/test_llext_simple.c index 0b002c79e71..bdceb0368f1 100644 --- a/tests/subsys/llext/src/test_llext_simple.c +++ b/tests/subsys/llext/src/test_llext_simple.c @@ -9,7 +9,7 @@ #include #include -#ifdef CONFIG_ARM /* ARMV7 */ +#if defined(CONFIG_ARM) /* ARMV7 */ || defined(CONFIG_XTENSA) const static uint8_t hello_world_elf[] __aligned(4) = { #include "hello_world.inc" }; @@ -24,7 +24,7 @@ const static uint8_t hello_world_elf[] __aligned(4) = { */ ZTEST(llext, test_llext_simple) { - const char name[16] = {'h', 'e', 'l', 'l', 'o', 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; + const char name[16] = "hello"; struct llext_buf_loader buf_loader = LLEXT_BUF_LOADER(hello_world_elf, ARRAY_SIZE(hello_world_elf)); struct llext_loader *loader = &buf_loader.loader; diff --git a/tests/subsys/llext/testcase.yaml b/tests/subsys/llext/testcase.yaml index 79d8f5a1fd9..0bbccd5e1ca 100644 --- a/tests/subsys/llext/testcase.yaml +++ b/tests/subsys/llext/testcase.yaml @@ -9,3 +9,8 @@ tests: # Broken platforms platform_exclude: - nuvoton_pfm_m487 # See #63167 + llext.simple.xtensa: + arch_allow: xtensa + # Broken platforms + platform_exclude: + - qemu_xtensa_mmu # ELF sections are read-only, and without peek() .text copy isn't executable From 0b5bfd22e39cae54d8f2ca795fd752fa57e579ba Mon Sep 17 00:00:00 2001 From: Guennadi Liakhovetski Date: Tue, 24 Oct 2023 17:49:58 +0200 Subject: [PATCH 0599/3723] llext: add support for global functions Loadable modules can contain global (not "static") functions, even if they aren't exported for use by other modules, e.g. when a module is built from multiple .c files. Such functions are then also included in link tables and have to be re-linked. Signed-off-by: Guennadi Liakhovetski --- subsys/llext/llext.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/subsys/llext/llext.c b/subsys/llext/llext.c index e09539c6155..42a704bebb2 100644 --- a/subsys/llext/llext.c +++ b/subsys/llext/llext.c @@ -530,7 +530,7 @@ static void llext_link_plt(struct llext_loader *ldr, struct llext *ext, uint32_t stt = ELF_ST_TYPE(sym_tbl.st_info); uint32_t stb = ELF_ST_BIND(sym_tbl.st_info); - if (stt != STT_NOTYPE || sym_tbl.st_shndx != SHN_UNDEF) { + if (stt != STT_FUNC && (stt != STT_NOTYPE || sym_tbl.st_shndx != SHN_UNDEF)) { continue; } @@ -547,6 +547,8 @@ static void llext_link_plt(struct llext_loader *ldr, struct llext *ext, switch (stb) { case STB_GLOBAL: link_addr = llext_find_sym(NULL, name); + if (!link_addr) + link_addr = llext_find_sym(&ext->sym_tab, name); if (!link_addr) { LOG_WRN("PLT: cannot find idx %u name %s", j, name); From a2acd7b2fbde5f5febf38c3efb960488bfdbc31a Mon Sep 17 00:00:00 2001 From: Guennadi Liakhovetski Date: Fri, 3 Nov 2023 14:16:16 +0100 Subject: [PATCH 0600/3723] llext: add reference counting Extend the llext_load() / llext_unload() API to let it be called repeatedly for the same extension to increment or decrement its reference counter respectively. We use a mutex to protect the counter and make both llext_load() and llext_unload() return the use-count to let the caller identify when the first loading and the last unloading took place. Signed-off-by: Guennadi Liakhovetski --- include/zephyr/llext/llext.h | 5 +- subsys/llext/llext.c | 63 ++++++++++++++++------ subsys/llext/shell.c | 2 +- tests/subsys/llext/src/test_llext_simple.c | 4 +- 4 files changed, 54 insertions(+), 20 deletions(-) diff --git a/include/zephyr/llext/llext.h b/include/zephyr/llext/llext.h index 5376e2cf13a..5dc5b6b0b72 100644 --- a/include/zephyr/llext/llext.h +++ b/include/zephyr/llext/llext.h @@ -62,6 +62,9 @@ struct llext { /** Exported symbols from the llext, may be linked against by other llext */ struct llext_symtable sym_tab; + + /** Extension use counter, prevents unloading while in use */ + unsigned int use_count; }; /** @@ -115,7 +118,7 @@ int llext_load(struct llext_loader *loader, const char *name, struct llext **ext * * @param[in] ext Extension to unload */ -void llext_unload(struct llext *ext); +int llext_unload(struct llext **ext); /** * @brief Find the address for an arbitrary symbol name. diff --git a/subsys/llext/llext.c b/subsys/llext/llext.c index 42a704bebb2..60ecf60ec77 100644 --- a/subsys/llext/llext.c +++ b/subsys/llext/llext.c @@ -807,12 +807,25 @@ static int do_llext_load(struct llext_loader *ldr, struct llext *ext, return ret; } +static struct k_mutex llext_lock = Z_MUTEX_INITIALIZER(llext_lock); + int llext_load(struct llext_loader *ldr, const char *name, struct llext **ext, struct llext_load_param *ldr_parm) { int ret; elf_ehdr_t ehdr; + k_mutex_lock(&llext_lock, K_FOREVER); + + if (*ext) { + /* The use count is at least 1 */ + ret = (*ext)->use_count++; + k_mutex_unlock(&llext_lock); + return ret; + } + + k_mutex_unlock(&llext_lock); + ret = llext_seek(ldr, 0); if (ret != 0) { LOG_ERR("Failed to seek for ELF header"); @@ -848,40 +861,58 @@ int llext_load(struct llext_loader *ldr, const char *name, struct llext **ext, ldr->hdr = ehdr; ret = do_llext_load(ldr, *ext, ldr_parm); - break; - default: - LOG_ERR("Unsupported elf file type %x", ehdr.e_type); - *ext = NULL; - return -EINVAL; - } + if (ret < 0) + return ret; - if (ret == 0) { strncpy((*ext)->name, name, sizeof((*ext)->name)); (*ext)->name[sizeof((*ext)->name) - 1] = '\0'; + (*ext)->use_count++; + sys_slist_append(&_llext_list, &(*ext)->_llext_list); LOG_INF("Loaded extension %s", (*ext)->name); + + break; + default: + LOG_ERR("Unsupported elf file type %x", ehdr.e_type); + return -EINVAL; } - return ret; + return 0; } -void llext_unload(struct llext *ext) +int llext_unload(struct llext **ext) { - __ASSERT(ext, "Expected non-null extension"); + __ASSERT(*ext, "Expected non-null extension"); + struct llext *tmp = *ext; + + k_mutex_lock(&llext_lock, K_FOREVER); + __ASSERT(tmp->use_count, "A valid LLEXT cannot have a zero use-count!"); - sys_slist_find_and_remove(&_llext_list, &ext->_llext_list); + if (tmp->use_count-- != 1) { + unsigned int ret = tmp->use_count; + + k_mutex_unlock(&llext_lock); + return ret; + } + + /* FIXME: protect the global list */ + sys_slist_find_and_remove(&_llext_list, &tmp->_llext_list); + + *ext = NULL; + k_mutex_unlock(&llext_lock); for (int i = 0; i < LLEXT_MEM_COUNT; i++) { - if (ext->mem_on_heap[i]) { + if (tmp->mem_on_heap[i]) { LOG_DBG("freeing memory region %d", i); - k_heap_free(&llext_heap, ext->mem[i]); - ext->mem[i] = NULL; + k_heap_free(&llext_heap, tmp->mem[i]); + tmp->mem[i] = NULL; } } - k_heap_free(&llext_heap, ext->sym_tab.syms); + k_heap_free(&llext_heap, tmp->sym_tab.syms); + k_heap_free(&llext_heap, tmp); - k_heap_free(&llext_heap, ext); + return 0; } int llext_call_fn(struct llext *ext, const char *sym_name) diff --git a/subsys/llext/shell.c b/subsys/llext/shell.c index 289ebaa4d35..0e3448d6637 100644 --- a/subsys/llext/shell.c +++ b/subsys/llext/shell.c @@ -139,7 +139,7 @@ static int cmd_llext_unload(const struct shell *sh, size_t argc, char *argv[]) return -EINVAL; } - llext_unload(ext); + llext_unload(&ext); shell_print(sh, "Unloaded extension %s\n", argv[1]); return 0; diff --git a/tests/subsys/llext/src/test_llext_simple.c b/tests/subsys/llext/src/test_llext_simple.c index bdceb0368f1..dde8e674d11 100644 --- a/tests/subsys/llext/src/test_llext_simple.c +++ b/tests/subsys/llext/src/test_llext_simple.c @@ -29,7 +29,7 @@ ZTEST(llext, test_llext_simple) LLEXT_BUF_LOADER(hello_world_elf, ARRAY_SIZE(hello_world_elf)); struct llext_loader *loader = &buf_loader.loader; struct llext_load_param ldr_parm = LLEXT_LOAD_PARAM_DEFAULT; - struct llext *ext; + struct llext *ext = NULL; const void * const printk_fn = llext_find_sym(NULL, "printk"); zassert_equal(printk_fn, printk, "printk should be an exported symbol"); @@ -46,7 +46,7 @@ ZTEST(llext, test_llext_simple) zassert_ok(res, "calling hello world should succeed"); - llext_unload(ext); + llext_unload(&ext); } ZTEST_SUITE(llext, NULL, NULL, NULL, NULL, NULL); From 86da7840bda24c71b0bfae8d1817bc35e99f3d64 Mon Sep 17 00:00:00 2001 From: Guennadi Liakhovetski Date: Thu, 9 Nov 2023 14:19:05 +0100 Subject: [PATCH 0601/3723] llext: fix a memory leak in an error case If a function fails it should release all the resources it has managed to acquire. Fix llext_load() to free memory that it has allocated in case of an error. Signed-off-by: Guennadi Liakhovetski --- subsys/llext/llext.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/subsys/llext/llext.c b/subsys/llext/llext.c index 60ecf60ec77..05878b5c72f 100644 --- a/subsys/llext/llext.c +++ b/subsys/llext/llext.c @@ -861,8 +861,11 @@ int llext_load(struct llext_loader *ldr, const char *name, struct llext **ext, ldr->hdr = ehdr; ret = do_llext_load(ldr, *ext, ldr_parm); - if (ret < 0) + if (ret < 0) { + k_heap_free(&llext_heap, *ext); + *ext = NULL; return ret; + } strncpy((*ext)->name, name, sizeof((*ext)->name)); (*ext)->name[sizeof((*ext)->name) - 1] = '\0'; From b9bdae8c07a3be0ac365bd7ec2ed0b58cd4f7adc Mon Sep 17 00:00:00 2001 From: Guennadi Liakhovetski Date: Thu, 9 Nov 2023 14:28:47 +0100 Subject: [PATCH 0602/3723] llext: add support for exporting symbols from extensions Extensions should be able to selectively export their global symbols. Add a LL_EXTENSION_SYMBOL() macro for that. Change the present .sym_tab to be a temporary symbol table of all global symbols in an extensions, used only during linking for internal purposes. Add a new .exp_tab symbol table to store symbols, exported by an extension permanently. Signed-off-by: Guennadi Liakhovetski --- include/zephyr/llext/llext.h | 12 +++- include/zephyr/llext/loader.h | 2 + include/zephyr/llext/symbol.h | 3 + subsys/llext/llext.c | 61 +++++++++++++++++-- tests/subsys/llext/hello_world/CMakeLists.txt | 4 ++ tests/subsys/llext/hello_world/hello_world.c | 4 +- tests/subsys/llext/src/test_llext_simple.c | 2 +- 7 files changed, 80 insertions(+), 8 deletions(-) diff --git a/include/zephyr/llext/llext.h b/include/zephyr/llext/llext.h index 5dc5b6b0b72..c097ec2b329 100644 --- a/include/zephyr/llext/llext.h +++ b/include/zephyr/llext/llext.h @@ -33,6 +33,7 @@ enum llext_mem { LLEXT_MEM_DATA, LLEXT_MEM_RODATA, LLEXT_MEM_BSS, + LLEXT_MEM_EXPORT, LLEXT_MEM_SYMTAB, LLEXT_MEM_STRTAB, LLEXT_MEM_SHSTRTAB, @@ -60,9 +61,18 @@ struct llext { /** Total size of the llext memory usage */ size_t mem_size; - /** Exported symbols from the llext, may be linked against by other llext */ + /* + * These are all global symbols in the extension, all of them don't + * have to be exported to other extensions, but this table is needed for + * faster internal linking, e.g. if the extension is built out of + * several files, if any symbols are referenced between files, this + * table will be used to link them. + */ struct llext_symtable sym_tab; + /** Exported symbols from the llext, may be linked against by other llext */ + struct llext_symtable exp_tab; + /** Extension use counter, prevents unloading while in use */ unsigned int use_count; }; diff --git a/include/zephyr/llext/loader.h b/include/zephyr/llext/loader.h index 3102f17cf1a..bef29524471 100644 --- a/include/zephyr/llext/loader.h +++ b/include/zephyr/llext/loader.h @@ -35,6 +35,8 @@ enum llext_section { LLEXT_SECT_REL_RODATA, LLEXT_SECT_REL_BSS, + LLEXT_SECT_EXPORT, + LLEXT_SECT_SYMTAB, LLEXT_SECT_STRTAB, LLEXT_SECT_SHSTRTAB, diff --git a/include/zephyr/llext/symbol.h b/include/zephyr/llext/symbol.h index 84e43d22b5b..2c6505ee12f 100644 --- a/include/zephyr/llext/symbol.h +++ b/include/zephyr/llext/symbol.h @@ -78,6 +78,9 @@ struct llext_symtable { .name = STRINGIFY(x), .addr = &x, \ } +#define LL_EXTENSION_SYMBOL(x) struct llext_symbol __attribute__((section(".exported_sym"), used)) \ + symbol_##x = {STRINGIFY(x), &x} + /** * @brief Export a system call to a table of symbols * diff --git a/subsys/llext/llext.c b/subsys/llext/llext.c index 05878b5c72f..281f5d1047f 100644 --- a/subsys/llext/llext.c +++ b/subsys/llext/llext.c @@ -75,7 +75,7 @@ struct llext *llext_by_name(const char *name) const void * const llext_find_sym(const struct llext_symtable *sym_table, const char *sym_name) { if (sym_table == NULL) { - /* Buildin symbol table */ + /* Built-in symbol table */ STRUCT_SECTION_FOREACH(llext_const_symbol, sym) { if (strcmp(sym->name, sym_name) == 0) { return sym->addr; @@ -214,6 +214,9 @@ static int llext_map_sections(struct llext_loader *ldr, struct llext *ext) } else if (strcmp(name, ".bss") == 0) { sect_idx = LLEXT_SECT_BSS; mem_idx = LLEXT_MEM_BSS; + } else if (strcmp(name, ".exported_sym") == 0) { + sect_idx = LLEXT_SECT_EXPORT; + mem_idx = LLEXT_MEM_EXPORT; } else { LOG_DBG("Not copied section %s", name); continue; @@ -240,6 +243,9 @@ static enum llext_section llext_sect_from_mem(enum llext_mem m) case LLEXT_MEM_RODATA: s = LLEXT_SECT_RODATA; break; + case LLEXT_MEM_EXPORT: + s = LLEXT_SECT_EXPORT; + break; case LLEXT_MEM_TEXT: s = LLEXT_SECT_TEXT; break; @@ -401,6 +407,37 @@ static int llext_allocate_symtab(struct llext_loader *ldr, struct llext *ext) return 0; } +static int llext_export_symbols(struct llext_loader *ldr, struct llext *ext) +{ + elf_shdr_t *shdr = ldr->sects + LLEXT_SECT_EXPORT; + struct llext_symbol *sym; + unsigned int i; + + if (shdr->sh_size < sizeof(struct llext_symbol)) { + /* Not found, no symbols exported */ + return 0; + } + + struct llext_symtable *exp_tab = &ext->exp_tab; + + exp_tab->sym_cnt = shdr->sh_size / sizeof(struct llext_symbol); + exp_tab->syms = k_heap_alloc(&llext_heap, exp_tab->sym_cnt * sizeof(struct llext_symbol), + K_NO_WAIT); + if (!exp_tab->syms) { + return -ENOMEM; + } + + for (i = 0, sym = ext->mem[LLEXT_MEM_EXPORT]; + i < exp_tab->sym_cnt; + i++, sym++) { + exp_tab->syms[i].name = sym->name; + exp_tab->syms[i].addr = sym->addr; + LOG_DBG("sym %p name %s in %p", sym->addr, sym->name, exp_tab->syms + i); + } + + return 0; +} + static int llext_copy_symbols(struct llext_loader *ldr, struct llext *ext) { size_t ent_size = ldr->sects[LLEXT_SECT_SYMTAB].sh_entsize; @@ -624,6 +661,8 @@ static int llext_link(struct llext_loader *ldr, struct llext *ext, bool do_local } else if (strcmp(name, ".rel.data") == 0 || strcmp(name, ".rela.data") == 0) { loc = (uintptr_t)ext->mem[LLEXT_MEM_DATA]; + } else if (strcmp(name, ".rel.exported_sym") == 0) { + loc = (uintptr_t)ext->mem[LLEXT_MEM_EXPORT]; } else if (strcmp(name, ".rela.plt") == 0 || strcmp(name, ".rela.dyn") == 0) { llext_link_plt(ldr, ext, &shdr, do_local); @@ -679,7 +718,8 @@ static int llext_link(struct llext_loader *ldr, struct llext *ext, bool do_local name, rel.r_offset, shdr.sh_link); return -ENODATA; } - } else if (ELF_ST_TYPE(sym.st_info) == STT_SECTION) { + } else if (ELF_ST_TYPE(sym.st_info) == STT_SECTION || + ELF_ST_TYPE(sym.st_info) == STT_FUNC) { /* Current relocation location holds an offset into the section */ link_addr = (uintptr_t)ext->mem[ldr->sect_map[sym.st_shndx]] + sym.st_value @@ -719,6 +759,7 @@ static int do_llext_load(struct llext_loader *ldr, struct llext *ext, memset(ldr->sects, 0, sizeof(ldr->sects)); ldr->sect_cnt = 0; + ext->sym_tab.sym_cnt = 0; size_t sect_map_sz = ldr->hdr.e_shnum * sizeof(uint32_t); @@ -788,6 +829,12 @@ static int do_llext_load(struct llext_loader *ldr, struct llext *ext, goto out; } + ret = llext_export_symbols(ldr, ext); + if (ret != 0) { + LOG_ERR("Failed to export, ret %d", ret); + goto out; + } + out: k_heap_free(&llext_heap, ldr->sect_map); @@ -798,12 +845,16 @@ static int do_llext_load(struct llext_loader *ldr, struct llext *ext, k_heap_free(&llext_heap, ext->mem[mem_idx]); } } - k_heap_free(&llext_heap, ext->sym_tab.syms); + k_heap_free(&llext_heap, ext->exp_tab.syms); } else { LOG_DBG("loaded module, .text at %p, .rodata at %p", ext->mem[LLEXT_MEM_TEXT], ext->mem[LLEXT_MEM_RODATA]); } + ext->sym_tab.sym_cnt = 0; + k_heap_free(&llext_heap, ext->sym_tab.syms); + ext->sym_tab.syms = NULL; + return ret; } @@ -912,7 +963,7 @@ int llext_unload(struct llext **ext) } } - k_heap_free(&llext_heap, tmp->sym_tab.syms); + k_heap_free(&llext_heap, tmp->exp_tab.syms); k_heap_free(&llext_heap, tmp); return 0; @@ -922,7 +973,7 @@ int llext_call_fn(struct llext *ext, const char *sym_name) { void (*fn)(void); - fn = llext_find_sym(&ext->sym_tab, sym_name); + fn = llext_find_sym(&ext->exp_tab, sym_name); if (fn == NULL) { return -EINVAL; } diff --git a/tests/subsys/llext/hello_world/CMakeLists.txt b/tests/subsys/llext/hello_world/CMakeLists.txt index 6519075e2f4..833d8c56ccd 100644 --- a/tests/subsys/llext/hello_world/CMakeLists.txt +++ b/tests/subsys/llext/hello_world/CMakeLists.txt @@ -11,6 +11,8 @@ if(CONFIG_ARM) add_custom_command(OUTPUT ${PROJECT_BINARY_DIR}/hello_world.llext COMMAND ${CMAKE_C_COMPILER} ${CMAKE_C_FLAGS} -c + -I ${PROJECT_SOURCE_DIR}/../../../../include + -imacros${PROJECT_BINARY_DIR}/../zephyr/include/generated/autoconf.h -o ${PROJECT_BINARY_DIR}/hello_world.llext ${PROJECT_SOURCE_DIR}/hello_world.c ) @@ -19,6 +21,8 @@ elseif(CONFIG_XTENSA) add_custom_command(OUTPUT ${PROJECT_BINARY_DIR}/hello_world.llext COMMAND ${CMAKE_C_COMPILER} ${CMAKE_C_FLAGS} + -I ${PROJECT_SOURCE_DIR}/../../../../include + -imacros${PROJECT_BINARY_DIR}/../zephyr/include/generated/autoconf.h -o ${PROJECT_BINARY_DIR}/hello_world.pre.llext ${PROJECT_SOURCE_DIR}/hello_world.c COMMAND ${CROSS_COMPILE}strip -R .xt.* diff --git a/tests/subsys/llext/hello_world/hello_world.c b/tests/subsys/llext/hello_world/hello_world.c index 93d55ed5422..7ed688d2461 100644 --- a/tests/subsys/llext/hello_world/hello_world.c +++ b/tests/subsys/llext/hello_world/hello_world.c @@ -12,13 +12,15 @@ */ #include +#include extern void printk(char *fmt, ...); static const uint32_t number = 42; -extern void hello_world(void) +void hello_world(void) { printk("hello world\n"); printk("A number is %lu\n", number); } +LL_EXTENSION_SYMBOL(hello_world); diff --git a/tests/subsys/llext/src/test_llext_simple.c b/tests/subsys/llext/src/test_llext_simple.c index dde8e674d11..28a51a092b2 100644 --- a/tests/subsys/llext/src/test_llext_simple.c +++ b/tests/subsys/llext/src/test_llext_simple.c @@ -38,7 +38,7 @@ ZTEST(llext, test_llext_simple) zassert_ok(res, "load should succeed"); - const void * const hello_world_fn = llext_find_sym(&ext->sym_tab, "hello_world"); + const void * const hello_world_fn = llext_find_sym(&ext->exp_tab, "hello_world"); zassert_not_null(hello_world_fn, "hello_world should be an exported symbol"); From b5ce5012e29d5c1c2e2d5c1dac7fa15766db79e5 Mon Sep 17 00:00:00 2001 From: Guennadi Liakhovetski Date: Wed, 15 Nov 2023 17:19:57 +0100 Subject: [PATCH 0603/3723] llext: clarify section map allocation size Use an element size explicitly when calculating the array size and use the calculated size for memset(). Signed-off-by: Guennadi Liakhovetski --- subsys/llext/llext.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/subsys/llext/llext.c b/subsys/llext/llext.c index 281f5d1047f..15436bb43ab 100644 --- a/subsys/llext/llext.c +++ b/subsys/llext/llext.c @@ -761,7 +761,7 @@ static int do_llext_load(struct llext_loader *ldr, struct llext *ext, ldr->sect_cnt = 0; ext->sym_tab.sym_cnt = 0; - size_t sect_map_sz = ldr->hdr.e_shnum * sizeof(uint32_t); + size_t sect_map_sz = ldr->hdr.e_shnum * sizeof(ldr->sect_map[0]); ldr->sect_map = k_heap_alloc(&llext_heap, sect_map_sz, K_NO_WAIT); if (!ldr->sect_map) { @@ -769,7 +769,8 @@ static int do_llext_load(struct llext_loader *ldr, struct llext *ext, ret = -ENOMEM; goto out; } - memset(ldr->sect_map, 0, ldr->hdr.e_shnum*sizeof(uint32_t)); + memset(ldr->sect_map, 0, sect_map_sz); + ldr->sect_cnt = ldr->hdr.e_shnum; ext->mem_size += sect_map_sz; From ee4540c46c2a1c9bead87862dd7bcaee9a7efa20 Mon Sep 17 00:00:00 2001 From: Guennadi Liakhovetski Date: Tue, 21 Nov 2023 17:22:40 +0100 Subject: [PATCH 0604/3723] llext: remove llext list scanning from shell.c The llext list should be internal to llext.c, remove its scanning from shell.c, export a function for that instead. Signed-off-by: Guennadi Liakhovetski --- include/zephyr/llext/llext.h | 13 ++++++++ subsys/llext/llext.c | 20 +++++++++++++ subsys/llext/shell.c | 58 ++++++++++++++++++++++-------------- 3 files changed, 68 insertions(+), 23 deletions(-) diff --git a/include/zephyr/llext/llext.h b/include/zephyr/llext/llext.h index c097ec2b329..b3897bd5e05 100644 --- a/include/zephyr/llext/llext.h +++ b/include/zephyr/llext/llext.h @@ -91,6 +91,19 @@ sys_slist_t *llext_list(void); */ struct llext *llext_by_name(const char *name); +/** + * @brief Iterate overall registered llext instances + * + * Calls a provided callback function for each registered extension or until the + * callback function returns a non-0 value. + * + * @param[in] fn callback function + * @param[in] arg a private argument to be provided to the callback function + * @retval 0 if no extensions are registered + * @retval value returned by the most recent callback invocation + */ +int llext_iterate(int (*fn)(struct llext *ext, void *arg), void *arg); + /** * @brief llext loader parameters * diff --git a/subsys/llext/llext.c b/subsys/llext/llext.c index 15436bb43ab..3d711af957d 100644 --- a/subsys/llext/llext.c +++ b/subsys/llext/llext.c @@ -72,6 +72,26 @@ struct llext *llext_by_name(const char *name) return NULL; } +int llext_iterate(int (*fn)(struct llext *ext, void *arg), void *arg) +{ + sys_snode_t *node; + unsigned int i; + int ret = 0; + + for (node = sys_slist_peek_head(&_llext_list), i = 0; + node; + node = sys_slist_peek_next(node), i++) { + struct llext *ext = CONTAINER_OF(node, struct llext, _llext_list); + + ret = fn(ext, arg); + if (ret) { + break; + } + } + + return ret; +} + const void * const llext_find_sym(const struct llext_symtable *sym_table, const char *sym_name) { if (sym_table == NULL) { diff --git a/subsys/llext/shell.c b/subsys/llext/shell.c index 0e3448d6637..57f5b1d131b 100644 --- a/subsys/llext/shell.c +++ b/subsys/llext/shell.c @@ -52,45 +52,57 @@ static int cmd_llext_list_symbols(const struct shell *sh, size_t argc, char *arg return 0; } -static void llext_name_get(size_t idx, struct shell_static_entry *entry) +struct llext_shell_cmd { + unsigned int tgt; + unsigned int idx; + struct llext *ext; +}; + +static int llext_shell_name_cb(struct llext *ext, void *arg) { - sys_slist_t *ext_list = llext_list(); - sys_snode_t *node = sys_slist_peek_head(ext_list); + struct llext_shell_cmd *cmd = arg; - entry->syntax = NULL; + if (cmd->tgt == cmd->idx) { + cmd->ext = ext; + return 1; + } - for (int i = 0; i < idx; i++) { - node = sys_slist_peek_next(node); + cmd->idx++; - if (node == NULL) { - goto out; - } - } + return 0; +} - struct llext *ext = CONTAINER_OF(node, struct llext, _llext_list); +static void llext_name_get(size_t idx, struct shell_static_entry *entry) +{ + struct llext_shell_cmd cmd = {.tgt = idx}; - entry->syntax = ext->name; -out: - entry->syntax = NULL; + llext_iterate(llext_shell_name_cb, &cmd); + + entry->syntax = cmd.ext ? cmd.ext->name : NULL; entry->help = NULL; entry->subcmd = NULL; - } SHELL_DYNAMIC_CMD_CREATE(msub_llext_name, llext_name_get); +struct llext_shell_list { + const struct shell *sh; +}; + +static int llext_shell_list_cb(struct llext *ext, void *arg) +{ + struct llext_shell_list *sl = arg; + + shell_print(sl->sh, "| %16s | %12d |", ext->name, ext->mem_size); + return 0; +} + static int cmd_llext_list(const struct shell *sh, size_t argc, char *argv[]) { - sys_snode_t *node; - struct llext *ext; + struct llext_shell_list sl = {.sh = sh}; shell_print(sh, "| Name | Size |"); - SYS_SLIST_FOR_EACH_NODE(llext_list(), node) { - ext = CONTAINER_OF(node, struct llext, _llext_list); - shell_print(sh, "| %16s | %12d |", ext->name, ext->mem_size); - } - - return 0; + return llext_iterate(llext_shell_list_cb, &sl); } static uint8_t llext_buf[CONFIG_LLEXT_SHELL_MAX_SIZE]; From 7af6dea7990073c9277c5cf3a72a40bbc3befacd Mon Sep 17 00:00:00 2001 From: Guennadi Liakhovetski Date: Mon, 20 Nov 2023 15:19:58 +0100 Subject: [PATCH 0605/3723] llext: remove llext_list() llext_list() is an exported function that returns a pointer to the llext internal extension list. That list should only be accessible directly inside llext, while holding a lock. Remove the function. Signed-off-by: Guennadi Liakhovetski --- include/zephyr/llext/llext.h | 5 ----- subsys/llext/llext.c | 8 +------- 2 files changed, 1 insertion(+), 12 deletions(-) diff --git a/include/zephyr/llext/llext.h b/include/zephyr/llext/llext.h index b3897bd5e05..af215e6acc0 100644 --- a/include/zephyr/llext/llext.h +++ b/include/zephyr/llext/llext.h @@ -77,11 +77,6 @@ struct llext { unsigned int use_count; }; -/** - * @brief List head of loaded extensions - */ -sys_slist_t *llext_list(void); - /** * @brief Find an llext by name * diff --git a/subsys/llext/llext.c b/subsys/llext/llext.c index 3d711af957d..15d798fb8a9 100644 --- a/subsys/llext/llext.c +++ b/subsys/llext/llext.c @@ -23,11 +23,6 @@ static const char ELF_MAGIC[] = {0x7f, 'E', 'L', 'F'}; static sys_slist_t _llext_list = SYS_SLIST_STATIC_INIT(&_llext_list); -sys_slist_t *llext_list(void) -{ - return &_llext_list; -} - ssize_t llext_find_section(struct llext_loader *ldr, const char *search_name) { elf_shdr_t *shdr; @@ -57,8 +52,7 @@ ssize_t llext_find_section(struct llext_loader *ldr, const char *search_name) struct llext *llext_by_name(const char *name) { - sys_slist_t *mlist = llext_list(); - sys_snode_t *node = sys_slist_peek_head(mlist); + sys_snode_t *node = sys_slist_peek_head(&_llext_list); struct llext *ext = CONTAINER_OF(node, struct llext, _llext_list); while (node != NULL) { From b5506feed5a6fc3c1b9a44343deb62ce4445b240 Mon Sep 17 00:00:00 2001 From: Guennadi Liakhovetski Date: Mon, 20 Nov 2023 15:21:46 +0100 Subject: [PATCH 0606/3723] llext: remove redundant initialisation a new llext object is completely initialised with zeros after allocation, no need to additionally set members of an embedded into it array to NULL. Signed-off-by: Guennadi Liakhovetski --- subsys/llext/llext.c | 4 ---- 1 file changed, 4 deletions(-) diff --git a/subsys/llext/llext.c b/subsys/llext/llext.c index 15d798fb8a9..be2507ca63d 100644 --- a/subsys/llext/llext.c +++ b/subsys/llext/llext.c @@ -921,10 +921,6 @@ int llext_load(struct llext_loader *ldr, const char *name, struct llext **ext, } memset(*ext, 0, sizeof(struct llext)); - for (int i = 0; i < LLEXT_MEM_COUNT; i++) { - (*ext)->mem[i] = NULL; - } - ldr->hdr = ehdr; ret = do_llext_load(ldr, *ext, ldr_parm); if (ret < 0) { From 4e3e9a618e9015c1ac79d8d094e17315b45ccd00 Mon Sep 17 00:00:00 2001 From: Guennadi Liakhovetski Date: Mon, 20 Nov 2023 15:45:13 +0100 Subject: [PATCH 0607/3723] llext: protect the global llext list Use an existing mutex to also protect the global llext list. Signed-off-by: Guennadi Liakhovetski --- subsys/llext/llext.c | 49 ++++++++++++++++++++++++++++---------------- 1 file changed, 31 insertions(+), 18 deletions(-) diff --git a/subsys/llext/llext.c b/subsys/llext/llext.c index be2507ca63d..1bc56f4d23b 100644 --- a/subsys/llext/llext.c +++ b/subsys/llext/llext.c @@ -23,6 +23,8 @@ static const char ELF_MAGIC[] = {0x7f, 'E', 'L', 'F'}; static sys_slist_t _llext_list = SYS_SLIST_STATIC_INIT(&_llext_list); +static struct k_mutex llext_lock = Z_MUTEX_INITIALIZER(llext_lock); + ssize_t llext_find_section(struct llext_loader *ldr, const char *search_name) { elf_shdr_t *shdr; @@ -50,19 +52,28 @@ ssize_t llext_find_section(struct llext_loader *ldr, const char *search_name) return -ENOENT; } +/* + * Note, that while we protect the global llext list while searching, we release + * the lock before returning the found extension to the caller. Therefore it's + * a responsibility of the caller to protect against races with a freeing + * context when calling this function. + */ struct llext *llext_by_name(const char *name) { - sys_snode_t *node = sys_slist_peek_head(&_llext_list); - struct llext *ext = CONTAINER_OF(node, struct llext, _llext_list); + k_mutex_lock(&llext_lock, K_FOREVER); + + for (sys_snode_t *node = sys_slist_peek_head(&_llext_list); + node != NULL; + node = sys_slist_peek_next(node)) { + struct llext *ext = CONTAINER_OF(node, struct llext, _llext_list); - while (node != NULL) { if (strncmp(ext->name, name, sizeof(ext->name)) == 0) { + k_mutex_unlock(&llext_lock); return ext; } - node = sys_slist_peek_next(node); - ext = CONTAINER_OF(node, struct llext, _llext_list); } + k_mutex_unlock(&llext_lock); return NULL; } @@ -72,6 +83,8 @@ int llext_iterate(int (*fn)(struct llext *ext, void *arg), void *arg) unsigned int i; int ret = 0; + k_mutex_lock(&llext_lock, K_FOREVER); + for (node = sys_slist_peek_head(&_llext_list), i = 0; node; node = sys_slist_peek_next(node), i++) { @@ -83,6 +96,7 @@ int llext_iterate(int (*fn)(struct llext *ext, void *arg), void *arg) } } + k_mutex_unlock(&llext_lock); return ret; } @@ -873,8 +887,6 @@ static int do_llext_load(struct llext_loader *ldr, struct llext *ext, return ret; } -static struct k_mutex llext_lock = Z_MUTEX_INITIALIZER(llext_lock); - int llext_load(struct llext_loader *ldr, const char *name, struct llext **ext, struct llext_load_param *ldr_parm) { @@ -886,28 +898,26 @@ int llext_load(struct llext_loader *ldr, const char *name, struct llext **ext, if (*ext) { /* The use count is at least 1 */ ret = (*ext)->use_count++; - k_mutex_unlock(&llext_lock); - return ret; + goto out; } - k_mutex_unlock(&llext_lock); - ret = llext_seek(ldr, 0); if (ret != 0) { LOG_ERR("Failed to seek for ELF header"); - return ret; + goto out; } ret = llext_read(ldr, &ehdr, sizeof(ehdr)); if (ret != 0) { LOG_ERR("Failed to read ELF header"); - return ret; + goto out; } /* check whether this is an valid elf file */ if (memcmp(ehdr.e_ident, ELF_MAGIC, sizeof(ELF_MAGIC)) != 0) { LOG_HEXDUMP_ERR(ehdr.e_ident, 16, "Invalid ELF, magic does not match"); - return -EINVAL; + ret = -EINVAL; + goto out; } switch (ehdr.e_type) { @@ -917,7 +927,8 @@ int llext_load(struct llext_loader *ldr, const char *name, struct llext **ext, *ext = k_heap_alloc(&llext_heap, sizeof(struct llext), K_NO_WAIT); if (*ext == NULL) { LOG_ERR("Not enough memory for extension metadata"); - return -ENOMEM; + ret = -ENOMEM; + goto out; } memset(*ext, 0, sizeof(struct llext)); @@ -926,7 +937,7 @@ int llext_load(struct llext_loader *ldr, const char *name, struct llext **ext, if (ret < 0) { k_heap_free(&llext_heap, *ext); *ext = NULL; - return ret; + goto out; } strncpy((*ext)->name, name, sizeof((*ext)->name)); @@ -939,10 +950,12 @@ int llext_load(struct llext_loader *ldr, const char *name, struct llext **ext, break; default: LOG_ERR("Unsupported elf file type %x", ehdr.e_type); - return -EINVAL; + ret = -EINVAL; } - return 0; +out: + k_mutex_unlock(&llext_lock); + return ret; } int llext_unload(struct llext **ext) From dbea13a1c7b10afdb6293b643e3cede34dfa3345 Mon Sep 17 00:00:00 2001 From: Guennadi Liakhovetski Date: Thu, 23 Nov 2023 16:50:20 +0100 Subject: [PATCH 0608/3723] llext: fix read-only extension image When using the LLEXT buffer loader we now avoid copying extensions from storage to allocated memory by pointing directly into the stored image. We then also perform linking and relocation in that memory, which modifies its contents. However, this is impossible if that storage is read-only. Add a Kconfig flag to distinguish between writable and read-only storage types. Also use that flag to decide, whether the extension image in test_llext_simple.c should be defined as const or not. Signed-off-by: Guennadi Liakhovetski --- subsys/llext/Kconfig | 6 ++++++ subsys/llext/llext.c | 3 ++- tests/subsys/llext/src/test_llext_simple.c | 5 ++++- tests/subsys/llext/testcase.yaml | 2 ++ 4 files changed, 14 insertions(+), 2 deletions(-) diff --git a/subsys/llext/Kconfig b/subsys/llext/Kconfig index 9fec16cb230..b1210b8f2e8 100644 --- a/subsys/llext/Kconfig +++ b/subsys/llext/Kconfig @@ -27,6 +27,12 @@ config LLEXT_SHELL_MAX_SIZE help When loading llext with shell it is stored in a temporary buffer of this size +config LLEXT_STORAGE_WRITABLE + bool "llext storage is writable" + help + Select if LLEXT storage is writable, i.e. if extensions are stored in + RAM and can be modified in place + module = LLEXT module-str = llext source "subsys/logging/Kconfig.template.log_config" diff --git a/subsys/llext/llext.c b/subsys/llext/llext.c index 1bc56f4d23b..77a741f0636 100644 --- a/subsys/llext/llext.c +++ b/subsys/llext/llext.c @@ -303,7 +303,8 @@ static int llext_copy_section(struct llext_loader *ldr, struct llext *ext, return 0; } - if (ldr->sects[sect_idx].sh_type != SHT_NOBITS) { + if (ldr->sects[sect_idx].sh_type != SHT_NOBITS && + IS_ENABLED(CONFIG_LLEXT_STORAGE_WRITABLE)) { ext->mem[mem_idx] = llext_peek(ldr, ldr->sects[sect_idx].sh_offset); if (ext->mem[mem_idx]) { ext->mem_on_heap[mem_idx] = false; diff --git a/tests/subsys/llext/src/test_llext_simple.c b/tests/subsys/llext/src/test_llext_simple.c index 28a51a092b2..b78f2809009 100644 --- a/tests/subsys/llext/src/test_llext_simple.c +++ b/tests/subsys/llext/src/test_llext_simple.c @@ -10,7 +10,10 @@ #include #if defined(CONFIG_ARM) /* ARMV7 */ || defined(CONFIG_XTENSA) -const static uint8_t hello_world_elf[] __aligned(4) = { +#ifndef CONFIG_LLEXT_STORAGE_WRITABLE +const +#endif +static uint8_t hello_world_elf[] __aligned(4) = { #include "hello_world.inc" }; #endif diff --git a/tests/subsys/llext/testcase.yaml b/tests/subsys/llext/testcase.yaml index 0bbccd5e1ca..2747edf8d0c 100644 --- a/tests/subsys/llext/testcase.yaml +++ b/tests/subsys/llext/testcase.yaml @@ -11,6 +11,8 @@ tests: - nuvoton_pfm_m487 # See #63167 llext.simple.xtensa: arch_allow: xtensa + extra_configs: + - CONFIG_LLEXT_STORAGE_WRITABLE=y # Broken platforms platform_exclude: - qemu_xtensa_mmu # ELF sections are read-only, and without peek() .text copy isn't executable From fb016b6843d7efe14e37aca6b7308d6ca302aa67 Mon Sep 17 00:00:00 2001 From: Mateusz Sierszulski Date: Thu, 30 Nov 2023 15:58:32 +0800 Subject: [PATCH 0609/3723] drivers: gpio: add Ambiq GPIO driver This commit adds GPIO driver for Apollo4 SoCs. Signed-off-by: Mateusz Sierszulski --- drivers/gpio/CMakeLists.txt | 1 + drivers/gpio/Kconfig | 2 + drivers/gpio/Kconfig.ambiq | 14 ++ drivers/gpio/gpio_ambiq.c | 354 ++++++++++++++++++++++++++++++ dts/bindings/gpio/ambiq,gpio.yaml | 20 ++ 5 files changed, 391 insertions(+) create mode 100644 drivers/gpio/Kconfig.ambiq create mode 100644 drivers/gpio/gpio_ambiq.c create mode 100644 dts/bindings/gpio/ambiq,gpio.yaml diff --git a/drivers/gpio/CMakeLists.txt b/drivers/gpio/CMakeLists.txt index b1cd06978bb..34bdaebae27 100644 --- a/drivers/gpio/CMakeLists.txt +++ b/drivers/gpio/CMakeLists.txt @@ -89,6 +89,7 @@ zephyr_library_sources_ifdef(CONFIG_GPIO_ALTERA_PIO gpio_altera_pio.c) zephyr_library_sources_ifdef(CONFIG_GPIO_BCM2711 gpio_bcm2711.c) zephyr_library_sources_ifdef(CONFIG_GPIO_RA gpio_ra.c) zephyr_library_sources_ifdef(CONFIG_GPIO_RZT2M gpio_rzt2m.c) +zephyr_library_sources_ifdef(CONFIG_GPIO_AMBIQ gpio_ambiq.c) if (CONFIG_GPIO_EMUL_SDL) zephyr_library_sources(gpio_emul_sdl.c) diff --git a/drivers/gpio/Kconfig b/drivers/gpio/Kconfig index c49e2aa1167..960c7eb540e 100644 --- a/drivers/gpio/Kconfig +++ b/drivers/gpio/Kconfig @@ -236,4 +236,6 @@ source "drivers/gpio/Kconfig.ra" source "drivers/gpio/Kconfig.rzt2m" +source "drivers/gpio/Kconfig.ambiq" + endif # GPIO diff --git a/drivers/gpio/Kconfig.ambiq b/drivers/gpio/Kconfig.ambiq new file mode 100644 index 00000000000..924028e6f27 --- /dev/null +++ b/drivers/gpio/Kconfig.ambiq @@ -0,0 +1,14 @@ +# Ambiq SDK GPIO +# +# Copyright (c) 2023 Antmicro +# +# SPDX-License-Identifier: Apache-2.0 +# + +config GPIO_AMBIQ + bool "AMBIQ GPIO driver" + default y + depends on DT_HAS_AMBIQ_GPIO_ENABLED + select AMBIQ_HAL + help + Enable driver for Ambiq gpio. diff --git a/drivers/gpio/gpio_ambiq.c b/drivers/gpio/gpio_ambiq.c new file mode 100644 index 00000000000..ebf2176ff32 --- /dev/null +++ b/drivers/gpio/gpio_ambiq.c @@ -0,0 +1,354 @@ +/* + * Copyright (c) 2023 Antmicro + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#define DT_DRV_COMPAT ambiq_gpio + +#include +#include +#include +#include +#include +#include + +#include + +typedef void (*ambiq_gpio_cfg_func_t)(void); + +struct ambiq_gpio_config { + struct gpio_driver_config common; + uint32_t base; + uint32_t pin_offset; + uint32_t irq_num; + ambiq_gpio_cfg_func_t cfg_func; + uint8_t ngpios; +}; + +struct ambiq_gpio_data { + struct gpio_driver_data common; + sys_slist_t cb; + struct k_spinlock lock; +}; + +static int ambiq_gpio_pin_configure(const struct device *dev, gpio_pin_t pin, gpio_flags_t flags) +{ + const struct ambiq_gpio_config *const dev_cfg = dev->config; + + pin += dev_cfg->pin_offset; + + am_hal_gpio_pincfg_t pincfg = am_hal_gpio_pincfg_default; + + if (flags & GPIO_INPUT) { + pincfg = am_hal_gpio_pincfg_input; + if (flags & GPIO_PULL_UP) { + pincfg.GP.cfg_b.ePullup = AM_HAL_GPIO_PIN_PULLUP_50K; + } else if (flags & GPIO_PULL_DOWN) { + pincfg.GP.cfg_b.ePullup = AM_HAL_GPIO_PIN_PULLDOWN_50K; + } + } + if (flags & GPIO_OUTPUT) { + if (flags & GPIO_SINGLE_ENDED) { + if (flags & GPIO_LINE_OPEN_DRAIN) { + pincfg.GP.cfg_b.eGPOutCfg = AM_HAL_GPIO_PIN_OUTCFG_OPENDRAIN; + } + } else { + pincfg.GP.cfg_b.eGPOutCfg = AM_HAL_GPIO_PIN_OUTCFG_PUSHPULL; + } + } + if (flags & GPIO_DISCONNECTED) { + pincfg = am_hal_gpio_pincfg_disabled; + } + + if (flags & GPIO_OUTPUT_INIT_HIGH) { + pincfg.GP.cfg_b.eCEpol = AM_HAL_GPIO_PIN_CEPOL_ACTIVEHIGH; + am_hal_gpio_state_write(pin, AM_HAL_GPIO_OUTPUT_SET); + + } else if (flags & GPIO_OUTPUT_INIT_LOW) { + pincfg.GP.cfg_b.eCEpol = AM_HAL_GPIO_PIN_CEPOL_ACTIVELOW; + am_hal_gpio_state_write(pin, AM_HAL_GPIO_OUTPUT_CLEAR); + } + + am_hal_gpio_pinconfig(pin, pincfg); + + return 0; +} + +#ifdef CONFIG_GPIO_GET_CONFIG +static int ambiq_gpio_get_config(const struct device *dev, gpio_pin_t pin, gpio_flags_t *out_flags) +{ + const struct ambiq_gpio_config *const dev_cfg = dev->config; + am_hal_gpio_pincfg_t pincfg; + + pin += dev_cfg->pin_offset; + + am_hal_gpio_pinconfig_get(pin, &pincfg); + + if (pincfg.GP.cfg_b.eGPOutCfg == AM_HAL_GPIO_PIN_OUTCFG_DISABLE && + pincfg.GP.cfg_b.eGPInput == AM_HAL_GPIO_PIN_INPUT_NONE) { + *out_flags = GPIO_DISCONNECTED; + } + if (pincfg.GP.cfg_b.eGPInput == AM_HAL_GPIO_PIN_INPUT_ENABLE) { + *out_flags = GPIO_INPUT; + if (pincfg.GP.cfg_b.ePullup == AM_HAL_GPIO_PIN_PULLUP_50K) { + *out_flags |= GPIO_PULL_UP; + } else if (pincfg.GP.cfg_b.ePullup == AM_HAL_GPIO_PIN_PULLDOWN_50K) { + *out_flags |= GPIO_PULL_DOWN; + } + } + if (pincfg.GP.cfg_b.eGPOutCfg == AM_HAL_GPIO_PIN_OUTCFG_PUSHPULL) { + *out_flags = GPIO_OUTPUT | GPIO_PUSH_PULL; + if (pincfg.GP.cfg_b.eCEpol == AM_HAL_GPIO_PIN_CEPOL_ACTIVEHIGH) { + *out_flags |= GPIO_OUTPUT_HIGH; + } else if (pincfg.GP.cfg_b.eCEpol == AM_HAL_GPIO_PIN_CEPOL_ACTIVELOW) { + *out_flags |= GPIO_OUTPUT_LOW; + } + } + if (pincfg.GP.cfg_b.eGPOutCfg == AM_HAL_GPIO_PIN_OUTCFG_OPENDRAIN) { + *out_flags = GPIO_OUTPUT | GPIO_OPEN_DRAIN; + if (pincfg.GP.cfg_b.eCEpol == AM_HAL_GPIO_PIN_CEPOL_ACTIVEHIGH) { + *out_flags |= GPIO_OUTPUT_HIGH; + } else if (pincfg.GP.cfg_b.eCEpol == AM_HAL_GPIO_PIN_CEPOL_ACTIVELOW) { + *out_flags |= GPIO_OUTPUT_LOW; + } + } + + return 0; +} +#endif + +#ifdef CONFIG_GPIO_GET_DIRECTION +static int ambiq_gpio_port_get_direction(const struct device *dev, gpio_port_pins_t map, + gpio_port_pins_t *inputs, gpio_port_pins_t *outputs) +{ + const struct ambiq_gpio_config *const dev_cfg = dev->config; + am_hal_gpio_pincfg_t pincfg; + gpio_port_pins_t ip = 0; + gpio_port_pins_t op = 0; + + if (inputs != NULL) { + for (int i = 0; i < dev_cfg->ngpios; i++) { + if ((map >> i) & 1) { + am_hal_gpio_pinconfig_get(i + dev_cfg->pin_offset, &pincfg); + if (pincfg.GP.cfg_b.eGPInput == AM_HAL_GPIO_PIN_INPUT_ENABLE) { + ip |= BIT(i); + } + } + } + *inputs = ip; + } + if (outputs != NULL) { + for (int i = 0; i < dev_cfg->ngpios; i++) { + if ((map >> i) & 1) { + am_hal_gpio_pinconfig_get(i + dev_cfg->pin_offset, &pincfg); + if (pincfg.GP.cfg_b.eGPOutCfg == AM_HAL_GPIO_PIN_OUTCFG_PUSHPULL || + pincfg.GP.cfg_b.eGPOutCfg == AM_HAL_GPIO_PIN_OUTCFG_OPENDRAIN) { + op |= BIT(i); + } + } + } + *outputs = op; + } + + return 0; +} +#endif + +static int ambiq_gpio_port_get_raw(const struct device *dev, gpio_port_value_t *value) +{ + const struct ambiq_gpio_config *const dev_cfg = dev->config; + + *value = (*AM_HAL_GPIO_RDn(dev_cfg->pin_offset)); + + return 0; +} + +static int ambiq_gpio_port_set_masked_raw(const struct device *dev, gpio_port_pins_t mask, + gpio_port_value_t value) +{ + const struct ambiq_gpio_config *const dev_cfg = dev->config; + + for (int i = 0; i < dev_cfg->ngpios; i++) { + if ((mask >> i) & 1) { + am_hal_gpio_state_write(i + dev_cfg->pin_offset, ((value >> i) & 1)); + } + } + + return 0; +} + +static int ambiq_gpio_port_set_bits_raw(const struct device *dev, gpio_port_pins_t pins) +{ + const struct ambiq_gpio_config *const dev_cfg = dev->config; + + for (int i = 0; i < dev_cfg->ngpios; i++) { + if ((pins >> i) & 1) { + am_hal_gpio_state_write(i + dev_cfg->pin_offset, AM_HAL_GPIO_OUTPUT_SET); + } + } + + return 0; +} + +static int ambiq_gpio_port_clear_bits_raw(const struct device *dev, gpio_port_pins_t pins) +{ + const struct ambiq_gpio_config *const dev_cfg = dev->config; + + for (int i = 0; i < dev_cfg->ngpios; i++) { + if ((pins >> i) & 1) { + am_hal_gpio_state_write(i + dev_cfg->pin_offset, AM_HAL_GPIO_OUTPUT_CLEAR); + } + } + + return 0; +} + +static int ambiq_gpio_port_toggle_bits(const struct device *dev, gpio_port_pins_t pins) +{ + const struct ambiq_gpio_config *const dev_cfg = dev->config; + + for (int i = 0; i < dev_cfg->ngpios; i++) { + if ((pins >> i) & 1) { + am_hal_gpio_state_write(i + dev_cfg->pin_offset, AM_HAL_GPIO_OUTPUT_TOGGLE); + } + } + + return 0; +} + +static void ambiq_gpio_isr(const struct device *dev) +{ + struct ambiq_gpio_data *const data = dev->data; + const struct ambiq_gpio_config *const dev_cfg = dev->config; + + uint32_t int_status; + + am_hal_gpio_interrupt_irq_status_get(dev_cfg->irq_num, false, &int_status); + am_hal_gpio_interrupt_irq_clear(dev_cfg->irq_num, int_status); + + gpio_fire_callbacks(&data->cb, dev, int_status); +} + +static int ambiq_gpio_pin_interrupt_configure(const struct device *dev, gpio_pin_t pin, + enum gpio_int_mode mode, enum gpio_int_trig trig) +{ + const struct ambiq_gpio_config *const dev_cfg = dev->config; + struct ambiq_gpio_data *const data = dev->data; + + am_hal_gpio_pincfg_t pincfg; + int gpio_pin = pin + dev_cfg->pin_offset; + uint32_t int_status; + int ret; + + ret = am_hal_gpio_pinconfig_get(gpio_pin, &pincfg); + + if (mode == GPIO_INT_MODE_DISABLED) { + pincfg.GP.cfg_b.eIntDir = AM_HAL_GPIO_PIN_INTDIR_NONE; + ret = am_hal_gpio_pinconfig(gpio_pin, pincfg); + + irq_disable(dev_cfg->irq_num); + + k_spinlock_key_t key = k_spin_lock(&data->lock); + + ret = am_hal_gpio_interrupt_irq_status_get(dev_cfg->irq_num, false, &int_status); + ret = am_hal_gpio_interrupt_irq_clear(dev_cfg->irq_num, int_status); + ret = am_hal_gpio_interrupt_control(AM_HAL_GPIO_INT_CHANNEL_0, + AM_HAL_GPIO_INT_CTRL_INDV_DISABLE, + (void *)&gpio_pin); + k_spin_unlock(&data->lock, key); + + } else { + if (mode == GPIO_INT_MODE_LEVEL) { + return -ENOTSUP; + } + switch (trig) { + case GPIO_INT_TRIG_LOW: + pincfg.GP.cfg_b.eIntDir = AM_HAL_GPIO_PIN_INTDIR_HI2LO; + break; + case GPIO_INT_TRIG_HIGH: + pincfg.GP.cfg_b.eIntDir = AM_HAL_GPIO_PIN_INTDIR_LO2HI; + break; + case GPIO_INT_TRIG_BOTH: + return -ENOTSUP; + } + ret = am_hal_gpio_pinconfig(gpio_pin, pincfg); + + irq_enable(dev_cfg->irq_num); + + k_spinlock_key_t key = k_spin_lock(&data->lock); + + ret = am_hal_gpio_interrupt_irq_status_get(dev_cfg->irq_num, false, &int_status); + ret = am_hal_gpio_interrupt_irq_clear(dev_cfg->irq_num, int_status); + ret = am_hal_gpio_interrupt_control(AM_HAL_GPIO_INT_CHANNEL_0, + AM_HAL_GPIO_INT_CTRL_INDV_ENABLE, + (void *)&gpio_pin); + k_spin_unlock(&data->lock, key); + } + return ret; +} + +static int ambiq_gpio_manage_callback(const struct device *dev, struct gpio_callback *callback, + bool set) +{ + struct ambiq_gpio_data *const data = dev->data; + + return gpio_manage_callback(&data->cb, callback, set); +} + +static int ambiq_gpio_init(const struct device *port) +{ + const struct ambiq_gpio_config *const dev_cfg = port->config; + + NVIC_ClearPendingIRQ(dev_cfg->irq_num); + + dev_cfg->cfg_func(); + + return 0; +} + +static const struct gpio_driver_api ambiq_gpio_drv_api = { + .pin_configure = ambiq_gpio_pin_configure, +#ifdef CONFIG_GPIO_GET_CONFIG + .pin_get_config = ambiq_gpio_get_config, +#endif + .port_get_raw = ambiq_gpio_port_get_raw, + .port_set_masked_raw = ambiq_gpio_port_set_masked_raw, + .port_set_bits_raw = ambiq_gpio_port_set_bits_raw, + .port_clear_bits_raw = ambiq_gpio_port_clear_bits_raw, + .port_toggle_bits = ambiq_gpio_port_toggle_bits, + .pin_interrupt_configure = ambiq_gpio_pin_interrupt_configure, + .manage_callback = ambiq_gpio_manage_callback, +#ifdef CONFIG_GPIO_GET_DIRECTION + .port_get_direction = ambiq_gpio_port_get_direction, +#endif +}; + +#define AMBIQ_GPIO_DEFINE(n) \ + static struct ambiq_gpio_data ambiq_gpio_data_##n; \ + static void ambiq_gpio_cfg_func_##n(void); \ + \ + static const struct ambiq_gpio_config ambiq_gpio_config_##n = { \ + .common = \ + { \ + .port_pin_mask = GPIO_PORT_PIN_MASK_FROM_DT_INST(n), \ + }, \ + .base = DT_REG_ADDR(DT_INST_PARENT(n)), \ + .pin_offset = DT_INST_REG_ADDR(n), \ + .ngpios = DT_INST_PROP(n, ngpios), \ + .irq_num = DT_INST_IRQN(n), \ + .cfg_func = ambiq_gpio_cfg_func_##n}; \ + static void ambiq_gpio_cfg_func_##n(void) \ + { \ + \ + IRQ_CONNECT(DT_INST_IRQN(n), DT_INST_IRQ(n, priority), ambiq_gpio_isr, \ + DEVICE_DT_INST_GET(n), 0); \ + \ + return; \ + }; \ + \ + DEVICE_DT_INST_DEFINE(n, &ambiq_gpio_init, NULL, &ambiq_gpio_data_##n, \ + &ambiq_gpio_config_##n, PRE_KERNEL_1, CONFIG_GPIO_INIT_PRIORITY, \ + &ambiq_gpio_drv_api); + +DT_INST_FOREACH_STATUS_OKAY(AMBIQ_GPIO_DEFINE) diff --git a/dts/bindings/gpio/ambiq,gpio.yaml b/dts/bindings/gpio/ambiq,gpio.yaml new file mode 100644 index 00000000000..b6e090ad064 --- /dev/null +++ b/dts/bindings/gpio/ambiq,gpio.yaml @@ -0,0 +1,20 @@ +# Copyright (c) 2023 Antmicro +# SPDX-License-Identifier: Apache-2.0 + +description: Ambiq GPIO + +compatible: "ambiq,gpio" + +include: [gpio-controller.yaml, base.yaml] + +properties: + reg: + required: true + description: GPIO pin offset + + "#gpio-cells": + const: 2 + +gpio-cells: + - pin + - flags From e0eadd5f6b6bd7efc0324bd45984784da33f05bd Mon Sep 17 00:00:00 2001 From: Mateusz Sierszulski Date: Thu, 30 Nov 2023 15:58:33 +0800 Subject: [PATCH 0610/3723] dts: arm: ambiq: Add GPIO instances to SoC This commit instantiates the GPIO peripherals. Signed-off-by: Mateusz Sierszulski --- boards/arm/apollo4p_evb/apollo4p_evb.dts | 16 ++++++++++ dts/arm/ambiq/ambiq_apollo4p.dtsi | 39 ++++++++++++++++++++++++ 2 files changed, 55 insertions(+) diff --git a/boards/arm/apollo4p_evb/apollo4p_evb.dts b/boards/arm/apollo4p_evb/apollo4p_evb.dts index 059b880388d..2b55bc7c654 100644 --- a/boards/arm/apollo4p_evb/apollo4p_evb.dts +++ b/boards/arm/apollo4p_evb/apollo4p_evb.dts @@ -55,3 +55,19 @@ pinctrl-names = "default"; status = "okay"; }; + +&gpio0_31 { + status = "okay"; +}; + +&gpio32_63 { + status = "okay"; +}; + +&gpio64_95 { + status = "okay"; +}; + +&gpio96_127 { + status = "okay"; +}; diff --git a/dts/arm/ambiq/ambiq_apollo4p.dtsi b/dts/arm/ambiq/ambiq_apollo4p.dtsi index 3f722ae282f..ff50962d1b9 100644 --- a/dts/arm/ambiq/ambiq_apollo4p.dtsi +++ b/dts/arm/ambiq/ambiq_apollo4p.dtsi @@ -3,6 +3,7 @@ #include #include #include +#include / { clocks { @@ -206,6 +207,44 @@ pinctrl: pin-controller@40010000 { compatible = "ambiq,apollo4-pinctrl"; reg = <0x40010000 0x800>; + #address-cells = <1>; + #size-cells = <0>; + + gpio0_31: gpio0_31@0 { + compatible = "ambiq,gpio"; + gpio-controller; + #gpio-cells = <2>; + reg = <0>; + interrupts = <56 0>; + status = "disabled"; + }; + + gpio32_63: gpio32_63@20 { + compatible = "ambiq,gpio"; + gpio-controller; + #gpio-cells = <2>; + reg = <32>; + interrupts = <57 0>; + status = "disabled"; + }; + + gpio64_95: gpio64_95@40 { + compatible = "ambiq,gpio"; + gpio-controller; + #gpio-cells = <2>; + reg = <64>; + interrupts = <58 0>; + status = "disabled"; + }; + + gpio96_127: gpio96_127@60 { + compatible = "ambiq,gpio"; + gpio-controller; + #gpio-cells = <2>; + reg = <96>; + interrupts = <59 0>; + status = "disabled"; + }; }; wdt0: watchdog@40024000 { From c8a9b6190979637e2422af43212821ab56af5d5d Mon Sep 17 00:00:00 2001 From: Mateusz Sierszulski Date: Thu, 30 Nov 2023 15:58:33 +0800 Subject: [PATCH 0611/3723] boards: arm: apollo4p_evb: Enable LEDs This commit adds leds instances and aliases for them on apollo4p_evb board. Signed-off-by: Mateusz Sierszulski --- boards/arm/apollo4p_evb/apollo4p_evb.dts | 22 ++++++++++++++++++++++ 1 file changed, 22 insertions(+) diff --git a/boards/arm/apollo4p_evb/apollo4p_evb.dts b/boards/arm/apollo4p_evb/apollo4p_evb.dts index 2b55bc7c654..d9742072dc5 100644 --- a/boards/arm/apollo4p_evb/apollo4p_evb.dts +++ b/boards/arm/apollo4p_evb/apollo4p_evb.dts @@ -6,6 +6,7 @@ / { model = "Ambiq Apollo4 Plus evaluation board"; compatible = "ambiq,apollo4p_evb"; + chosen { zephyr,itcm = &tcm; zephyr,sram = &sram0; @@ -14,9 +15,30 @@ zephyr,shell-uart = &uart0; zephyr,uart-pipe = &uart0; }; + aliases { watchdog0 = &wdt0; + led0 = &led0; + led1 = &led1; + led2 = &led2; }; + + leds { + compatible = "gpio-leds"; + led0: led_0 { + gpios = <&gpio0_31 30 GPIO_ACTIVE_LOW>; + label = "LED 0"; + }; + led1: led_1 { + gpios = <&gpio64_95 26 GPIO_ACTIVE_LOW>; + label = "LED 1"; + }; + led2: led_2 { + gpios = <&gpio96_127 1 GPIO_ACTIVE_LOW>; + label = "LED 2"; + }; + }; + }; &uart0 { From bfecd1220d991f4f4803a114bb068d481890be6b Mon Sep 17 00:00:00 2001 From: Mateusz Sierszulski Date: Thu, 30 Nov 2023 15:58:33 +0800 Subject: [PATCH 0612/3723] boards: arm: apollo4p_evb: Enable buttons This commit adds buttons instances and aliases for them on apollo4p_evb boards. Signed-off-by: Mateusz Sierszulski --- boards/arm/apollo4p_evb/apollo4p_evb.dts | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/boards/arm/apollo4p_evb/apollo4p_evb.dts b/boards/arm/apollo4p_evb/apollo4p_evb.dts index d9742072dc5..5a4f9d26228 100644 --- a/boards/arm/apollo4p_evb/apollo4p_evb.dts +++ b/boards/arm/apollo4p_evb/apollo4p_evb.dts @@ -21,6 +21,8 @@ led0 = &led0; led1 = &led1; led2 = &led2; + sw0 = &button0; + sw1 = &button1; }; leds { @@ -39,6 +41,17 @@ }; }; + buttons { + compatible = "gpio-keys"; + button0: button_0 { + gpios = <&gpio0_31 18 GPIO_ACTIVE_LOW>; + label = "BTN0"; + }; + button1: button_1 { + gpios = <&gpio0_31 19 GPIO_ACTIVE_LOW>; + label = "BTN1"; + }; + }; }; &uart0 { From a24f0f0b1d4b069c489fd622652de1993d7a8758 Mon Sep 17 00:00:00 2001 From: Aaron Ye Date: Fri, 1 Dec 2023 20:02:26 +0800 Subject: [PATCH 0613/3723] dts: binding: gpio: Add Ambiq gpio and gpio-bank bindings. This Ambiq gpio binding provides the GPIO pin mapping for GPIO child nodes tosolve the limitation of the maximum 32 pins handling in GPIO driver API. The gpio-bank nodes can be created under the gpio parent node. Signed-off-by: Aaron Ye --- dts/bindings/gpio/ambiq,gpio-bank.yaml | 24 +++++++ dts/bindings/gpio/ambiq,gpio.yaml | 90 ++++++++++++++++++++++---- 2 files changed, 101 insertions(+), 13 deletions(-) create mode 100644 dts/bindings/gpio/ambiq,gpio-bank.yaml diff --git a/dts/bindings/gpio/ambiq,gpio-bank.yaml b/dts/bindings/gpio/ambiq,gpio-bank.yaml new file mode 100644 index 00000000000..8d9114acc5b --- /dev/null +++ b/dts/bindings/gpio/ambiq,gpio-bank.yaml @@ -0,0 +1,24 @@ +# Copyright (c) 2023 Antmicro +# Copyright (c) 2023 Ambiq Micro Inc. +# SPDX-License-Identifier: Apache-2.0 + +description: Ambiq GPIO bank node + +compatible: "ambiq,gpio-bank" + +include: [gpio-controller.yaml, base.yaml] + +properties: + reg: + required: true + description: | + This property indicates the register address offset of each GPIO child node + under the "ambiq,gpio" parent node. The register address of pin described in + gpio-cells can be obtained by: base address + child address offset + (pin << 2). + + "#gpio-cells": + const: 2 + +gpio-cells: + - pin + - flags diff --git a/dts/bindings/gpio/ambiq,gpio.yaml b/dts/bindings/gpio/ambiq,gpio.yaml index b6e090ad064..9ce7c7c8779 100644 --- a/dts/bindings/gpio/ambiq,gpio.yaml +++ b/dts/bindings/gpio/ambiq,gpio.yaml @@ -1,20 +1,84 @@ -# Copyright (c) 2023 Antmicro +# Copyright (c) 2023 Ambiq Micro Inc. # SPDX-License-Identifier: Apache-2.0 -description: Ambiq GPIO +description: | + Ambiq GPIO provides the GPIO pin mapping for GPIO child nodes. -compatible: "ambiq,gpio" + The Ambiq Apollo4x soc designs a single GPIO port with 128 pins. + It uses 128 continuous 32-bit registers to configure the GPIO pins. + This binding provides a pin mapping to solve the limitation of the maximum + 32 pins handling in GPIO driver API. + + The Ambiq Apollo4x soc should define one "ambiq,gpio" parent node in soc + devicetree and some child nodes which are compatible with "ambiq,gpio-bank" + under this parent node. + + Here is an example of how a "ambiq,gpio" node can be used with the combined + gpio child nodes: + + gpio: gpio@40010000 { + compatible = "ambiq,gpio"; + gpio-map-mask = <0xffffffe0 0xffffffc0>; + gpio-map-pass-thru = <0x1f 0x3f>; + gpio-map = < + 0x00 0x0 &gpio0_31 0x0 0x0 + 0x20 0x0 &gpio32_63 0x0 0x0 + 0x40 0x0 &gpio64_95 0x0 0x0 + 0x60 0x0 &gpio96_127 0x0 0x0 + >; + reg = <0x40010000>; + #gpio-cells = <2>; + #address-cells = <1>; + #size-cells = <0>; + ranges; -include: [gpio-controller.yaml, base.yaml] + gpio0_31: gpio0_31@0 { + compatible = "ambiq,gpio-bank"; + gpio-controller; + #gpio-cells = <2>; + reg = <0>; + interrupts = <56 0>; + status = "disabled"; + }; -properties: - reg: - required: true - description: GPIO pin offset + gpio32_63: gpio32_63@80 { + compatible = "ambiq,gpio-bank"; + gpio-controller; + #gpio-cells = <2>; + reg = <0x80>; + interrupts = <57 0>; + status = "disabled"; + }; - "#gpio-cells": - const: 2 + gpio64_95: gpio64_95@100 { + compatible = "ambiq,gpio-bank"; + gpio-controller; + #gpio-cells = <2>; + reg = <0x100>; + interrupts = <58 0>; + status = "disabled"; + }; + + gpio96_127: gpio96_127@180 { + compatible = "ambiq,gpio-bank"; + gpio-controller; + #gpio-cells = <2>; + reg = <0x180>; + interrupts = <59 0>; + status = "disabled"; + }; + }; + + In the above example, the gpio@40010000 is a "ambiq,gpio" parent node which + provides the base register address 0x40010000. It has four "ambiq,gpio-bank" + child nodes. Each of them covers 32 pins (the default value of "ngpios" + property is 32). The "reg" property of child nodes defines the register + address offset. The register address of pin described in gpio-cells can be + obtained by: base address + child address offset + (pin << 2). For example: + the address of pin 20 of gpio32_63@80 node is (0x40010000 + 0x80 + (20 << 2)) + = 0x400100D0 and the real GPIO pin number of this pin in soc is (20 + 32) + = 52. + +compatible: "ambiq,gpio" -gpio-cells: - - pin - - flags +include: [gpio-nexus.yaml, base.yaml] From 70ce5e4c6b50dae0ffc54017433e3c59a2a0d625 Mon Sep 17 00:00:00 2001 From: Aaron Ye Date: Fri, 1 Dec 2023 20:05:52 +0800 Subject: [PATCH 0614/3723] dts: arm: ambiq: Update the GPIO instances Use the "ambiq,gpio" binding to combine the "ambiq,gpio-bank" child nodes for Apollo4 Plus soc. Also update the GPIO driver accordingly. Signed-off-by: Aaron Ye --- drivers/gpio/gpio_ambiq.c | 32 +++++++------ dts/arm/ambiq/ambiq_apollo4p.dtsi | 75 +++++++++++++++++++------------ 2 files changed, 65 insertions(+), 42 deletions(-) diff --git a/drivers/gpio/gpio_ambiq.c b/drivers/gpio/gpio_ambiq.c index ebf2176ff32..c0023c0df27 100644 --- a/drivers/gpio/gpio_ambiq.c +++ b/drivers/gpio/gpio_ambiq.c @@ -1,10 +1,11 @@ /* * Copyright (c) 2023 Antmicro + * Copyright (c) 2023 Ambiq Micro Inc. * * SPDX-License-Identifier: Apache-2.0 */ -#define DT_DRV_COMPAT ambiq_gpio +#define DT_DRV_COMPAT ambiq_gpio_bank #include #include @@ -20,7 +21,7 @@ typedef void (*ambiq_gpio_cfg_func_t)(void); struct ambiq_gpio_config { struct gpio_driver_config common; uint32_t base; - uint32_t pin_offset; + uint32_t offset; uint32_t irq_num; ambiq_gpio_cfg_func_t cfg_func; uint8_t ngpios; @@ -36,7 +37,7 @@ static int ambiq_gpio_pin_configure(const struct device *dev, gpio_pin_t pin, gp { const struct ambiq_gpio_config *const dev_cfg = dev->config; - pin += dev_cfg->pin_offset; + pin += (dev_cfg->offset >> 2); am_hal_gpio_pincfg_t pincfg = am_hal_gpio_pincfg_default; @@ -81,7 +82,7 @@ static int ambiq_gpio_get_config(const struct device *dev, gpio_pin_t pin, gpio_ const struct ambiq_gpio_config *const dev_cfg = dev->config; am_hal_gpio_pincfg_t pincfg; - pin += dev_cfg->pin_offset; + pin += (dev_cfg->offset >> 2); am_hal_gpio_pinconfig_get(pin, &pincfg); @@ -126,11 +127,12 @@ static int ambiq_gpio_port_get_direction(const struct device *dev, gpio_port_pin am_hal_gpio_pincfg_t pincfg; gpio_port_pins_t ip = 0; gpio_port_pins_t op = 0; + uint32_t pin_offset = dev_cfg->offset >> 2; if (inputs != NULL) { for (int i = 0; i < dev_cfg->ngpios; i++) { if ((map >> i) & 1) { - am_hal_gpio_pinconfig_get(i + dev_cfg->pin_offset, &pincfg); + am_hal_gpio_pinconfig_get(i + pin_offset, &pincfg); if (pincfg.GP.cfg_b.eGPInput == AM_HAL_GPIO_PIN_INPUT_ENABLE) { ip |= BIT(i); } @@ -141,7 +143,7 @@ static int ambiq_gpio_port_get_direction(const struct device *dev, gpio_port_pin if (outputs != NULL) { for (int i = 0; i < dev_cfg->ngpios; i++) { if ((map >> i) & 1) { - am_hal_gpio_pinconfig_get(i + dev_cfg->pin_offset, &pincfg); + am_hal_gpio_pinconfig_get(i + pin_offset, &pincfg); if (pincfg.GP.cfg_b.eGPOutCfg == AM_HAL_GPIO_PIN_OUTCFG_PUSHPULL || pincfg.GP.cfg_b.eGPOutCfg == AM_HAL_GPIO_PIN_OUTCFG_OPENDRAIN) { op |= BIT(i); @@ -159,7 +161,7 @@ static int ambiq_gpio_port_get_raw(const struct device *dev, gpio_port_value_t * { const struct ambiq_gpio_config *const dev_cfg = dev->config; - *value = (*AM_HAL_GPIO_RDn(dev_cfg->pin_offset)); + *value = (*AM_HAL_GPIO_RDn(dev_cfg->offset >> 2)); return 0; } @@ -168,10 +170,11 @@ static int ambiq_gpio_port_set_masked_raw(const struct device *dev, gpio_port_pi gpio_port_value_t value) { const struct ambiq_gpio_config *const dev_cfg = dev->config; + uint32_t pin_offset = dev_cfg->offset >> 2; for (int i = 0; i < dev_cfg->ngpios; i++) { if ((mask >> i) & 1) { - am_hal_gpio_state_write(i + dev_cfg->pin_offset, ((value >> i) & 1)); + am_hal_gpio_state_write(i + pin_offset, ((value >> i) & 1)); } } @@ -181,10 +184,11 @@ static int ambiq_gpio_port_set_masked_raw(const struct device *dev, gpio_port_pi static int ambiq_gpio_port_set_bits_raw(const struct device *dev, gpio_port_pins_t pins) { const struct ambiq_gpio_config *const dev_cfg = dev->config; + uint32_t pin_offset = dev_cfg->offset >> 2; for (int i = 0; i < dev_cfg->ngpios; i++) { if ((pins >> i) & 1) { - am_hal_gpio_state_write(i + dev_cfg->pin_offset, AM_HAL_GPIO_OUTPUT_SET); + am_hal_gpio_state_write(i + pin_offset, AM_HAL_GPIO_OUTPUT_SET); } } @@ -194,10 +198,11 @@ static int ambiq_gpio_port_set_bits_raw(const struct device *dev, gpio_port_pins static int ambiq_gpio_port_clear_bits_raw(const struct device *dev, gpio_port_pins_t pins) { const struct ambiq_gpio_config *const dev_cfg = dev->config; + uint32_t pin_offset = dev_cfg->offset >> 2; for (int i = 0; i < dev_cfg->ngpios; i++) { if ((pins >> i) & 1) { - am_hal_gpio_state_write(i + dev_cfg->pin_offset, AM_HAL_GPIO_OUTPUT_CLEAR); + am_hal_gpio_state_write(i + pin_offset, AM_HAL_GPIO_OUTPUT_CLEAR); } } @@ -207,10 +212,11 @@ static int ambiq_gpio_port_clear_bits_raw(const struct device *dev, gpio_port_pi static int ambiq_gpio_port_toggle_bits(const struct device *dev, gpio_port_pins_t pins) { const struct ambiq_gpio_config *const dev_cfg = dev->config; + uint32_t pin_offset = dev_cfg->offset >> 2; for (int i = 0; i < dev_cfg->ngpios; i++) { if ((pins >> i) & 1) { - am_hal_gpio_state_write(i + dev_cfg->pin_offset, AM_HAL_GPIO_OUTPUT_TOGGLE); + am_hal_gpio_state_write(i + pin_offset, AM_HAL_GPIO_OUTPUT_TOGGLE); } } @@ -237,7 +243,7 @@ static int ambiq_gpio_pin_interrupt_configure(const struct device *dev, gpio_pin struct ambiq_gpio_data *const data = dev->data; am_hal_gpio_pincfg_t pincfg; - int gpio_pin = pin + dev_cfg->pin_offset; + int gpio_pin = pin + (dev_cfg->offset >> 2); uint32_t int_status; int ret; @@ -334,7 +340,7 @@ static const struct gpio_driver_api ambiq_gpio_drv_api = { .port_pin_mask = GPIO_PORT_PIN_MASK_FROM_DT_INST(n), \ }, \ .base = DT_REG_ADDR(DT_INST_PARENT(n)), \ - .pin_offset = DT_INST_REG_ADDR(n), \ + .offset = DT_INST_REG_ADDR(n), \ .ngpios = DT_INST_PROP(n, ngpios), \ .irq_num = DT_INST_IRQN(n), \ .cfg_func = ambiq_gpio_cfg_func_##n}; \ diff --git a/dts/arm/ambiq/ambiq_apollo4p.dtsi b/dts/arm/ambiq/ambiq_apollo4p.dtsi index ff50962d1b9..666acda801a 100644 --- a/dts/arm/ambiq/ambiq_apollo4p.dtsi +++ b/dts/arm/ambiq/ambiq_apollo4p.dtsi @@ -210,40 +210,57 @@ #address-cells = <1>; #size-cells = <0>; - gpio0_31: gpio0_31@0 { + gpio: gpio@40010000 { compatible = "ambiq,gpio"; - gpio-controller; + gpio-map-mask = <0xffffffe0 0xffffffc0>; + gpio-map-pass-thru = <0x1f 0x3f>; + gpio-map = < + 0x00 0x0 &gpio0_31 0x0 0x0 + 0x20 0x0 &gpio32_63 0x0 0x0 + 0x40 0x0 &gpio64_95 0x0 0x0 + 0x60 0x0 &gpio96_127 0x0 0x0 + >; + reg = <0x40010000>; #gpio-cells = <2>; - reg = <0>; - interrupts = <56 0>; - status = "disabled"; - }; + #address-cells = <1>; + #size-cells = <0>; + ranges; - gpio32_63: gpio32_63@20 { - compatible = "ambiq,gpio"; - gpio-controller; - #gpio-cells = <2>; - reg = <32>; - interrupts = <57 0>; - status = "disabled"; - }; + gpio0_31: gpio0_31@0 { + compatible = "ambiq,gpio-bank"; + gpio-controller; + #gpio-cells = <2>; + reg = <0>; + interrupts = <56 0>; + status = "disabled"; + }; - gpio64_95: gpio64_95@40 { - compatible = "ambiq,gpio"; - gpio-controller; - #gpio-cells = <2>; - reg = <64>; - interrupts = <58 0>; - status = "disabled"; - }; + gpio32_63: gpio32_63@80 { + compatible = "ambiq,gpio-bank"; + gpio-controller; + #gpio-cells = <2>; + reg = <0x80>; + interrupts = <57 0>; + status = "disabled"; + }; - gpio96_127: gpio96_127@60 { - compatible = "ambiq,gpio"; - gpio-controller; - #gpio-cells = <2>; - reg = <96>; - interrupts = <59 0>; - status = "disabled"; + gpio64_95: gpio64_95@100 { + compatible = "ambiq,gpio-bank"; + gpio-controller; + #gpio-cells = <2>; + reg = <0x100>; + interrupts = <58 0>; + status = "disabled"; + }; + + gpio96_127: gpio96_127@180 { + compatible = "ambiq,gpio-bank"; + gpio-controller; + #gpio-cells = <2>; + reg = <0x180>; + interrupts = <59 0>; + status = "disabled"; + }; }; }; From 1268251fafbd6905ef610622ae9ee0244838748f Mon Sep 17 00:00:00 2001 From: Aaron Ye Date: Thu, 30 Nov 2023 15:58:34 +0800 Subject: [PATCH 0615/3723] drivers: gpio: ambiq: Fix the incorrect IRQ disablement. For the Ambiq Apollo4x soc, every 32 pins share the same IRQ number. irq_disable() should not be called for the pin interrupt disablement, otherwise the interrupt of pins in the same GPIO group will be disabled as well. Signed-off-by: Aaron Ye --- drivers/gpio/gpio_ambiq.c | 2 -- 1 file changed, 2 deletions(-) diff --git a/drivers/gpio/gpio_ambiq.c b/drivers/gpio/gpio_ambiq.c index c0023c0df27..7a1bb5e0fb0 100644 --- a/drivers/gpio/gpio_ambiq.c +++ b/drivers/gpio/gpio_ambiq.c @@ -253,8 +253,6 @@ static int ambiq_gpio_pin_interrupt_configure(const struct device *dev, gpio_pin pincfg.GP.cfg_b.eIntDir = AM_HAL_GPIO_PIN_INTDIR_NONE; ret = am_hal_gpio_pinconfig(gpio_pin, pincfg); - irq_disable(dev_cfg->irq_num); - k_spinlock_key_t key = k_spin_lock(&data->lock); ret = am_hal_gpio_interrupt_irq_status_get(dev_cfg->irq_num, false, &int_status); From 034a3e3f91533cef6db4f0ecff8aff3bffd559df Mon Sep 17 00:00:00 2001 From: Peter Ujfalusi Date: Mon, 30 Oct 2023 14:00:58 +0200 Subject: [PATCH 0616/3723] drivers: dai: intel: ssp: Ignore TX/RX or DMA request enable bits from blob When loading the SSP configuration from a blob ignore the bits which would enable the TX/RX or DMA requests at configuration phase. The TX/RX enable and DMA request is handled by the driver itself. If the blob wrongly enables any of the bits can have runtime (startup time) seemingly random issues. Signed-off-by: Peter Ujfalusi --- drivers/dai/intel/ssp/ssp.c | 20 +++++++++++++++----- 1 file changed, 15 insertions(+), 5 deletions(-) diff --git a/drivers/dai/intel/ssp/ssp.c b/drivers/dai/intel/ssp/ssp.c index 809cc9833eb..b98556dafac 100644 --- a/drivers/dai/intel/ssp/ssp.c +++ b/drivers/dai/intel/ssp/ssp.c @@ -1759,15 +1759,25 @@ static void dai_ssp_set_reg_config(struct dai_intel_ssp *dp, const struct dai_co const struct dai_intel_ipc4_ssp_config *regs) { struct dai_intel_ssp_pdata *ssp = dai_get_drvdata(dp); - uint32_t ssc0, sstsa, ssrsa; + uint32_t ssc0, sstsa, ssrsa, sscr1; ssc0 = regs->ssc0; - sstsa = regs->sstsa; - ssrsa = regs->ssrsa; + sstsa = SSTSA_GET(regs->sstsa); + ssrsa = SSRSA_GET(regs->ssrsa); + sscr1 = regs->ssc1 & ~(SSCR1_RSRE | SSCR1_TSRE); + + if (regs->sstsa & SSTSA_TXEN || regs->ssrsa & SSRSA_RXEN || + regs->ssc1 & (SSCR1_RSRE | SSCR1_TSRE)) { + LOG_INF("%s: Ignoring %s%s%s%sfrom blob", __func__, + regs->sstsa & SSTSA_TXEN ? "SSTSA:TXEN " : "", + regs->ssrsa & SSRSA_RXEN ? "SSRSA:RXEN " : "", + regs->ssc1 & SSCR1_TSRE ? "SSCR1:TSRE " : "", + regs->ssc1 & SSCR1_RSRE ? "SSCR1:RSRE " : ""); + } sys_write32(ssc0, dai_base(dp) + SSCR0); sys_write32(regs->ssc2 & ~SSCR2_SFRMEN, dai_base(dp) + SSCR2); /* hardware specific flow */ - sys_write32(regs->ssc1, dai_base(dp) + SSCR1); + sys_write32(sscr1, dai_base(dp) + SSCR1); sys_write32(regs->ssc2 | SSCR2_SFRMEN, dai_base(dp) + SSCR2); /* hardware specific flow */ sys_write32(regs->ssc2, dai_base(dp) + SSCR2); sys_write32(regs->ssc3, dai_base(dp) + SSCR3); @@ -1779,7 +1789,7 @@ static void dai_ssp_set_reg_config(struct dai_intel_ssp *dp, const struct dai_co sys_write32(ssrsa, dai_base(dp) + SSRSA); LOG_INF("%s sscr0 = 0x%08x, sscr1 = 0x%08x, ssto = 0x%08x, sspsp = 0x%0x", __func__, - ssc0, regs->ssc1, regs->sscto, regs->sspsp); + ssc0, sscr1, regs->sscto, regs->sspsp); LOG_INF("%s sscr2 = 0x%08x, sspsp2 = 0x%08x, sscr3 = 0x%08x", __func__, regs->ssc2, regs->sspsp2, regs->ssc3); LOG_INF("%s ssioc = 0x%08x, ssrsa = 0x%08x, sstsa = 0x%08x", __func__, From eb49756d869aae034033080e2c13a1576d7d4b56 Mon Sep 17 00:00:00 2001 From: Peter Ujfalusi Date: Wed, 13 Sep 2023 14:53:14 +0300 Subject: [PATCH 0617/3723] drivers: dai: intel: ssp: Correct FIFO depth value The actual FIFO depth is 32 and not 16 on CAV2.5 and AVS platforms. Signed-off-by: Peter Ujfalusi --- drivers/dai/intel/ssp/ssp.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/dai/intel/ssp/ssp.h b/drivers/dai/intel/ssp/ssp.h index 1d37b9a3335..0d53c0c6159 100644 --- a/drivers/dai/intel/ssp/ssp.h +++ b/drivers/dai/intel/ssp/ssp.h @@ -29,7 +29,7 @@ #define DAI_INTEL_SSP_DEFAULT_IDX 1 /* the SSP port fifo depth */ -#define DAI_INTEL_SSP_FIFO_DEPTH 16 +#define DAI_INTEL_SSP_FIFO_DEPTH 32 /* the watermark for the SSP fifo depth setting */ #define DAI_INTEL_SSP_FIFO_WATERMARK 8 From aa18bb2b6e04ebbfe4f5d6d422a00fff1d2505b2 Mon Sep 17 00:00:00 2001 From: Peter Ujfalusi Date: Wed, 13 Sep 2023 14:54:37 +0300 Subject: [PATCH 0618/3723] drivers: dai: intel: ssp: Revise receive FIFO draining The receive FIFO needs to be drained in a different way depending when it is done. - before start If the RX FIFO is in overflow state then we must read all the entries out to empty it (it was after all full). - before stop The DMA might be already running to read out data. Check the FIFO level change in one sample time which gives us the needed information to decide to wait for another loop for the DMA burst to finish, wait for the DMA to start it's burst (DMA request was asserted) or drain the FIFO directly. No need to drain the RX fifo at probe time. Signed-off-by: Peter Ujfalusi --- drivers/dai/intel/ssp/ssp.c | 89 ++++++++++++++++++++++++++----------- 1 file changed, 64 insertions(+), 25 deletions(-) diff --git a/drivers/dai/intel/ssp/ssp.c b/drivers/dai/intel/ssp/ssp.c index b98556dafac..da332feabe8 100644 --- a/drivers/dai/intel/ssp/ssp.c +++ b/drivers/dai/intel/ssp/ssp.c @@ -837,36 +837,73 @@ static void dai_ssp_empty_tx_fifo(struct dai_intel_ssp *dp) } } -/* empty SSP receive FIFO */ -static void dai_ssp_empty_rx_fifo(struct dai_intel_ssp *dp) +static void ssp_empty_rx_fifo_on_start(struct dai_intel_ssp *dp) { - struct dai_intel_ssp_pdata *ssp = dai_get_drvdata(dp); uint32_t retry = DAI_INTEL_SSP_RX_FLUSH_RETRY_MAX; - uint32_t entries; - uint32_t i; + uint32_t i, sssr; - /* - * To make sure all the RX FIFO entries are read out for the flushing, - * we need to wait a minimal SSP port delay after entries are all read, - * and then re-check to see if there is any subsequent entries written - * to the FIFO. This will help to make sure there is no sample mismatched - * issue for the next run with the SSP RX. - */ - while ((sys_read32(dai_base(dp) + SSSR) & SSSR_RNE) && retry--) { - entries = SSCR3_RFL_VAL(sys_read32(dai_base(dp) + SSCR3)); - LOG_DBG("%s before flushing, entries %d", __func__, entries); - for (i = 0; i < entries + 1; i++) { - /* read to try empty fifo */ + sssr = sys_read32(dai_base(dp) + SSSR); + + if (sssr & SSSR_ROR) { + /* The RX FIFO is in overflow condition, empty it */ + for (i = 0; i < DAI_INTEL_SSP_FIFO_DEPTH; i++) sys_read32(dai_base(dp) + SSDR); + + /* Clear the overflow status */ + dai_ssp_update_bits(dp, SSSR, SSSR_ROR, SSSR_ROR); + /* Re-read the SSSR register */ + sssr = sys_read32(dai_base(dp) + SSSR); + } + + while ((sssr & SSSR_RNE) && retry--) { + uint32_t entries = SSCR3_RFL_VAL(sys_read32(dai_base(dp) + SSCR3)); + + /* Empty the RX FIFO (the DMA is not running at this point) */ + for (i = 0; i < entries + 1; i++) + sys_read32(dai_base(dp) + SSDR); + + sssr = sys_read32(dai_base(dp) + SSSR); + } +} + +static void ssp_empty_rx_fifo_on_stop(struct dai_intel_ssp *dp) +{ + struct dai_intel_ssp_pdata *ssp = dai_get_drvdata(dp); + uint64_t sample_ticks = ssp->params.fsync_rate ? 1000000 / ssp->params.fsync_rate : 0; + uint32_t retry = DAI_INTEL_SSP_RX_FLUSH_RETRY_MAX; + uint32_t entries[2]; + uint32_t i, sssr; + + sssr = sys_read32(dai_base(dp) + SSSR); + entries[0] = SSCR3_RFL_VAL(sys_read32(dai_base(dp) + SSCR3)); + + while ((sssr & SSSR_RNE) && retry--) { + /* Wait one sample time */ + k_busy_wait(sample_ticks); + + entries[1] = SSCR3_RFL_VAL(sys_read32(dai_base(dp) + SSCR3)); + sssr = sys_read32(dai_base(dp) + SSSR); + + if (entries[0] > entries[1]) { + /* + * The DMA is reading the FIFO, check the status in the + * next loop + */ + entries[0] = entries[1]; + } else if (!(sssr & SSSR_RFS)) { + /* + * The DMA request is not asserted, read the FIFO + * directly, otherwise let the next loop iteration to + * check the status + */ + for (i = 0; i < entries[1] + 1; i++) + sys_read32(dai_base(dp) + SSDR); } - /* wait to get valid fifo status and re-check */ - k_busy_wait(ssp->params.fsync_rate ? 1000000 / ssp->params.fsync_rate : 0); - entries = SSCR3_RFL_VAL(sys_read32(dai_base(dp) + SSCR3)); - LOG_DBG("%s after flushing, entries %d", __func__, entries); + sssr = sys_read32(dai_base(dp) + SSSR); } - /* clear interrupt */ + /* Just in case clear the overflow status */ dai_ssp_update_bits(dp, SSSR, SSSR_ROR, SSSR_ROR); } @@ -1911,6 +1948,10 @@ static void dai_ssp_early_start(struct dai_intel_ssp *dp, int direction) key = k_spin_lock(&dp->lock); + /* RX fifo must be cleared before start */ + if (direction == DAI_DIR_CAPTURE) + ssp_empty_rx_fifo_on_start(dp); + /* request mclk/bclk */ dai_ssp_pre_start(dp); @@ -1991,7 +2032,7 @@ static void dai_ssp_stop(struct dai_intel_ssp *dp, int direction) if (direction == DAI_DIR_CAPTURE && ssp->state[DAI_DIR_CAPTURE] != DAI_STATE_PRE_RUNNING) { dai_ssp_update_bits(dp, SSRSA, SSRSA_RXEN, 0); - dai_ssp_empty_rx_fifo(dp); + ssp_empty_rx_fifo_on_stop(dp); ssp->state[DAI_DIR_CAPTURE] = DAI_STATE_PRE_RUNNING; LOG_INF("%s RX stop", __func__); } @@ -2169,8 +2210,6 @@ static int dai_ssp_probe(struct dai_intel_ssp *dp) /* Disable dynamic clock gating before touching any register */ dai_ssp_pm_runtime_dis_ssp_clk_gating(dp, dp->index); - dai_ssp_empty_rx_fifo(dp); - return 0; } From 6b548ee5aef510a1c6e639ed274fde9fa35114df Mon Sep 17 00:00:00 2001 From: Peter Ujfalusi Date: Fri, 27 Oct 2023 15:08:34 +0300 Subject: [PATCH 0619/3723] drivers: dai: intel: ssp: Manage the DMA request enable/disable dynamically Do not keep both DMA request enabled whenever the SSP is in use. Manage the SSCR1_TSRE and SSCR1_RSRE bits in sync with the enabled directions. When only playback is used there is no need to have the RX DMA request enabled for example. Signed-off-by: Peter Ujfalusi --- drivers/dai/intel/ssp/ssp.c | 37 +++++++++---------------------------- 1 file changed, 9 insertions(+), 28 deletions(-) diff --git a/drivers/dai/intel/ssp/ssp.c b/drivers/dai/intel/ssp/ssp.c index da332feabe8..34f93ff01d6 100644 --- a/drivers/dai/intel/ssp/ssp.c +++ b/drivers/dai/intel/ssp/ssp.c @@ -1561,12 +1561,6 @@ static int dai_ssp_set_config_tplg(struct dai_intel_ssp *dp, const struct dai_co ssp->clk_active |= SSP_CLK_BCLK_ES_REQ; if (enable_sse) { - - /* enable TRSE/RSRE before SSE */ - dai_ssp_update_bits(dp, SSCR1, - SSCR1_TSRE | SSCR1_RSRE, - SSCR1_TSRE | SSCR1_RSRE); - /* enable port */ dai_ssp_update_bits(dp, SSCR0, SSCR0_SSE, SSCR0_SSE); @@ -1590,11 +1584,6 @@ static int dai_ssp_set_config_tplg(struct dai_intel_ssp *dp, const struct dai_co LOG_INF("%s hw_free stage: releasing BCLK clocks for SSP%d...", __func__, dp->index); if (ssp->clk_active & SSP_CLK_BCLK_ACTIVE) { - /* clear TRSE/RSRE before SSE */ - dai_ssp_update_bits(dp, SSCR1, - SSCR1_TSRE | SSCR1_RSRE, - 0); - dai_ssp_update_bits(dp, SSCR0, SSCR0_SSE, 0); LOG_INF("%s SSE clear for SSP%d", __func__, dp->index); } @@ -1875,8 +1864,6 @@ static int dai_ssp_set_config_blob(struct dai_intel_ssp *dp, const struct dai_co } ssp->clk_active |= SSP_CLK_MCLK_ES_REQ; - /* enable TRSE/RSRE before SSE */ - dai_ssp_update_bits(dp, SSCR1, SSCR1_TSRE | SSCR1_RSRE, SSCR1_TSRE | SSCR1_RSRE); /* enable port */ dai_ssp_update_bits(dp, SSCR0, SSCR0_SSE, SSCR0_SSE); @@ -1956,11 +1943,6 @@ static void dai_ssp_early_start(struct dai_intel_ssp *dp, int direction) dai_ssp_pre_start(dp); if (!(ssp->clk_active & SSP_CLK_BCLK_ES_REQ)) { - /* enable TRSE/RSRE before SSE */ - dai_ssp_update_bits(dp, SSCR1, - SSCR1_TSRE | SSCR1_RSRE, - SSCR1_TSRE | SSCR1_RSRE); - /* enable port */ dai_ssp_update_bits(dp, SSCR0, SSCR0_SSE, SSCR0_SSE); LOG_INF("%s SSE set for SSP%d", __func__, dp->index); @@ -1981,8 +1963,10 @@ static void dai_ssp_start(struct dai_intel_ssp *dp, int direction) /* enable DMA */ if (direction == DAI_DIR_PLAYBACK) { + dai_ssp_update_bits(dp, SSCR1, SSCR1_TSRE, SSCR1_TSRE); dai_ssp_update_bits(dp, SSTSA, SSTSA_TXEN, SSTSA_TXEN); } else { + dai_ssp_update_bits(dp, SSCR1, SSCR1_RSRE, SSCR1_RSRE); dai_ssp_update_bits(dp, SSRSA, SSRSA_RXEN, SSRSA_RXEN); } @@ -2032,6 +2016,7 @@ static void dai_ssp_stop(struct dai_intel_ssp *dp, int direction) if (direction == DAI_DIR_CAPTURE && ssp->state[DAI_DIR_CAPTURE] != DAI_STATE_PRE_RUNNING) { dai_ssp_update_bits(dp, SSRSA, SSRSA_RXEN, 0); + dai_ssp_update_bits(dp, SSCR1, SSCR1_RSRE, 0); ssp_empty_rx_fifo_on_stop(dp); ssp->state[DAI_DIR_CAPTURE] = DAI_STATE_PRE_RUNNING; LOG_INF("%s RX stop", __func__); @@ -2040,6 +2025,7 @@ static void dai_ssp_stop(struct dai_intel_ssp *dp, int direction) /* stop Tx if needed */ if (direction == DAI_DIR_PLAYBACK && ssp->state[DAI_DIR_PLAYBACK] != DAI_STATE_PRE_RUNNING) { + dai_ssp_update_bits(dp, SSCR1, SSCR1_TSRE, 0); dai_ssp_empty_tx_fifo(dp); dai_ssp_update_bits(dp, SSTSA, SSTSA_TXEN, 0); ssp->state[DAI_DIR_PLAYBACK] = DAI_STATE_PRE_RUNNING; @@ -2048,16 +2034,11 @@ static void dai_ssp_stop(struct dai_intel_ssp *dp, int direction) /* disable SSP port if no users */ if (ssp->state[DAI_DIR_CAPTURE] == DAI_STATE_PRE_RUNNING && - ssp->state[DAI_DIR_PLAYBACK] == DAI_STATE_PRE_RUNNING) { - bool clear_rse_bits = COND_CODE_1(CONFIG_INTEL_ADSP_CAVS, - (!(ssp->clk_active & SSP_CLK_BCLK_ES_REQ)), - (true)); - if (clear_rse_bits) { - /* clear TRSE/RSRE before SSE */ - dai_ssp_update_bits(dp, SSCR1, SSCR1_TSRE | SSCR1_RSRE, 0); - dai_ssp_update_bits(dp, SSCR0, SSCR0_SSE, 0); - LOG_INF("%s SSE clear SSP%d", __func__, dp->index); - } + ssp->state[DAI_DIR_PLAYBACK] == DAI_STATE_PRE_RUNNING && + COND_CODE_1(CONFIG_INTEL_ADSP_CAVS, + (!(ssp->clk_active & SSP_CLK_BCLK_ES_REQ)), (true))) { + dai_ssp_update_bits(dp, SSCR0, SSCR0_SSE, 0); + LOG_INF("%s SSE clear for SSP%d", __func__, dp->index); } dai_ssp_post_stop(dp); From 5174e94c91c560de8961da3e81a4b001473daa6d Mon Sep 17 00:00:00 2001 From: Mariusz Skamra Date: Tue, 21 Nov 2023 09:15:15 +0100 Subject: [PATCH 0620/3723] Bluetooth: audio: has: Fix coverity issues This fixes issues discovered by coverity check. Fixes: #65325 Fixes: #65326 Signed-off-by: Mariusz Skamra --- subsys/bluetooth/audio/has.c | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) diff --git a/subsys/bluetooth/audio/has.c b/subsys/bluetooth/audio/has.c index 6013cadd014..26f719b753b 100644 --- a/subsys/bluetooth/audio/has.c +++ b/subsys/bluetooth/audio/has.c @@ -205,6 +205,8 @@ static struct has_client { static struct client_context *context_find(const bt_addr_le_t *addr) { + __ASSERT_NO_MSG(addr != NULL); + for (size_t i = 0; i < ARRAY_SIZE(contexts); i++) { if (bt_addr_le_eq(&contexts[i].addr, addr)) { return &contexts[i]; @@ -218,6 +220,8 @@ static struct client_context *context_alloc(const bt_addr_le_t *addr) { struct client_context *context; + __ASSERT_NO_MSG(addr != NULL); + /* Free contexts has BT_ADDR_LE_ANY as the address */ context = context_find(BT_ADDR_LE_ANY); if (context == NULL) { @@ -262,6 +266,7 @@ static struct has_client *client_alloc(struct bt_conn *conn) { struct bt_conn_info info = { 0 }; struct has_client *client = NULL; + int err; for (size_t i = 0; i < ARRAY_SIZE(has_client_list); i++) { if (conn == has_client_list[i].conn) { @@ -284,7 +289,12 @@ static struct has_client *client_alloc(struct bt_conn *conn) k_work_init_delayable(&client->notify_work, notify_work_handler); #endif /* CONFIG_BT_HAS_PRESET_SUPPORT || CONFIG_BT_HAS_FEATURES_NOTIFIABLE */ - bt_conn_get_info(conn, &info); + err = bt_conn_get_info(conn, &info); + if (err != 0) { + LOG_DBG("Could not get conn info: %d", err); + + return NULL; + } client->context = context_find(info.le.dst); if (client->context == NULL) { From 7a2fcc419e2264d49c12145d44acd32d0b7ee8de Mon Sep 17 00:00:00 2001 From: Jonas Remmert Date: Thu, 16 Nov 2023 23:26:25 +0100 Subject: [PATCH 0621/3723] drivers/sensor: add support to LPS28DFW pressure sensor The LPS28DFW is an ultracompact, piezoresistive, absolute pressure sensor. Compared to the LPS22DF, the LPS28DFW is waterproof and has a Dual FS capability and does not have SPI. This commit extends the LPS22DF driver to be compatible with the LPS28DFW device. Signed-off-by: Jonas Remmert --- drivers/sensor/CMakeLists.txt | 2 +- drivers/sensor/Kconfig | 2 +- drivers/sensor/lps22df/CMakeLists.txt | 12 - drivers/sensor/lps22df/Kconfig | 59 --- drivers/sensor/lps22df/lps22df.c | 338 ------------------ drivers/sensor/lps22df/lps22df.h | 99 ----- drivers/sensor/lps22df/lps22df_trigger.c | 251 ------------- drivers/sensor/lps2xdf/CMakeLists.txt | 15 + drivers/sensor/lps2xdf/Kconfig | 63 ++++ drivers/sensor/lps2xdf/lps22df.c | 233 ++++++++++++ drivers/sensor/lps2xdf/lps22df.h | 23 ++ drivers/sensor/lps2xdf/lps28dfw.c | 240 +++++++++++++ drivers/sensor/lps2xdf/lps28dfw.h | 23 ++ drivers/sensor/lps2xdf/lps2xdf.c | 223 ++++++++++++ drivers/sensor/lps2xdf/lps2xdf.h | 136 +++++++ drivers/sensor/lps2xdf/lps2xdf_trigger.c | 206 +++++++++++ dts/bindings/sensor/st,lps28dfw-common.yaml | 23 ++ dts/bindings/sensor/st,lps28dfw-i2c.yaml | 11 + dts/bindings/sensor/st,lps28dfw-i3c.yaml | 11 + modules/Kconfig.st | 3 + .../sensors-on-board/prj.conf | 2 +- .../sensors-on-board/src/main.c | 8 +- tests/drivers/build_all/sensor/i2c.dtsi | 19 +- tests/drivers/build_all/sensor/i3c.dtsi | 7 + .../sensor/sensors_trigger_global.conf | 2 +- .../sensor/sensors_trigger_none.conf | 2 +- .../build_all/sensor/sensors_trigger_own.conf | 2 +- 27 files changed, 1242 insertions(+), 773 deletions(-) delete mode 100644 drivers/sensor/lps22df/CMakeLists.txt delete mode 100644 drivers/sensor/lps22df/Kconfig delete mode 100644 drivers/sensor/lps22df/lps22df.c delete mode 100644 drivers/sensor/lps22df/lps22df.h delete mode 100644 drivers/sensor/lps22df/lps22df_trigger.c create mode 100644 drivers/sensor/lps2xdf/CMakeLists.txt create mode 100644 drivers/sensor/lps2xdf/Kconfig create mode 100644 drivers/sensor/lps2xdf/lps22df.c create mode 100644 drivers/sensor/lps2xdf/lps22df.h create mode 100644 drivers/sensor/lps2xdf/lps28dfw.c create mode 100644 drivers/sensor/lps2xdf/lps28dfw.h create mode 100644 drivers/sensor/lps2xdf/lps2xdf.c create mode 100644 drivers/sensor/lps2xdf/lps2xdf.h create mode 100644 drivers/sensor/lps2xdf/lps2xdf_trigger.c create mode 100644 dts/bindings/sensor/st,lps28dfw-common.yaml create mode 100644 dts/bindings/sensor/st,lps28dfw-i2c.yaml create mode 100644 dts/bindings/sensor/st,lps28dfw-i3c.yaml diff --git a/drivers/sensor/CMakeLists.txt b/drivers/sensor/CMakeLists.txt index 2fa37289ac2..76bb17bc822 100644 --- a/drivers/sensor/CMakeLists.txt +++ b/drivers/sensor/CMakeLists.txt @@ -73,7 +73,7 @@ add_subdirectory_ifdef(CONFIG_LIS2MDL lis2mdl) add_subdirectory_ifdef(CONFIG_LIS3MDL lis3mdl) add_subdirectory_ifdef(CONFIG_LM75 lm75) add_subdirectory_ifdef(CONFIG_LM77 lm77) -add_subdirectory_ifdef(CONFIG_LPS22DF lps22df) +add_subdirectory_ifdef(CONFIG_LPS2XDF lps2xdf) add_subdirectory_ifdef(CONFIG_LPS22HB lps22hb) add_subdirectory_ifdef(CONFIG_LPS22HH lps22hh) add_subdirectory_ifdef(CONFIG_LPS25HB lps25hb) diff --git a/drivers/sensor/Kconfig b/drivers/sensor/Kconfig index 08d04774dcd..fba7501bad9 100644 --- a/drivers/sensor/Kconfig +++ b/drivers/sensor/Kconfig @@ -145,7 +145,7 @@ source "drivers/sensor/lis2mdl/Kconfig" source "drivers/sensor/lis3mdl/Kconfig" source "drivers/sensor/lm75/Kconfig" source "drivers/sensor/lm77/Kconfig" -source "drivers/sensor/lps22df/Kconfig" +source "drivers/sensor/lps2xdf/Kconfig" source "drivers/sensor/lps22hb/Kconfig" source "drivers/sensor/lps22hh/Kconfig" source "drivers/sensor/lps25hb/Kconfig" diff --git a/drivers/sensor/lps22df/CMakeLists.txt b/drivers/sensor/lps22df/CMakeLists.txt deleted file mode 100644 index bb5194cf9ba..00000000000 --- a/drivers/sensor/lps22df/CMakeLists.txt +++ /dev/null @@ -1,12 +0,0 @@ -# ST Microelectronics LPS22DF pressure and temperature sensor -# -# Copyright (c) 2023 STMicroelectronics -# -# SPDX-License-Identifier: Apache-2.0 -# -zephyr_library() - -zephyr_library_sources(lps22df.c) -zephyr_library_sources_ifdef(CONFIG_LPS22DF_TRIGGER lps22df_trigger.c) - -zephyr_library_include_directories(../stmemsc) diff --git a/drivers/sensor/lps22df/Kconfig b/drivers/sensor/lps22df/Kconfig deleted file mode 100644 index 843c6e755c4..00000000000 --- a/drivers/sensor/lps22df/Kconfig +++ /dev/null @@ -1,59 +0,0 @@ -# ST Microelectronics LPS22DF pressure and temperature sensor - -# Copyright (c) 2023 STMicroelectronics -# SPDX-License-Identifier: Apache-2.0 - -menuconfig LPS22DF - bool "LPS22DF pressure and temperature" - default y - depends on DT_HAS_ST_LPS22DF_ENABLED - select I2C if $(dt_compat_on_bus,$(DT_COMPAT_ST_LPS22DF),i2c) - select I3C if $(dt_compat_on_bus,$(DT_COMPAT_ST_LPS22DF),i3c) - select SPI if $(dt_compat_on_bus,$(DT_COMPAT_ST_LPS22DF),spi) - select HAS_STMEMSC - select USE_STDC_LPS22DF - help - Enable driver for LPS22DF I2C-based pressure and temperature - sensor. - -if LPS22DF - -choice LPS22DF_TRIGGER_MODE - prompt "Trigger mode" - default LPS22DF_TRIGGER_GLOBAL_THREAD - help - Specify the type of triggering to be used by the driver. - -config LPS22DF_TRIGGER_NONE - bool "No trigger" - -config LPS22DF_TRIGGER_GLOBAL_THREAD - bool "Use global thread" - depends on GPIO - select LPS22DF_TRIGGER - -config LPS22DF_TRIGGER_OWN_THREAD - bool "Use own thread" - depends on GPIO - select LPS22DF_TRIGGER - -endchoice # LPS22DF_TRIGGER_MODE - -config LPS22DF_TRIGGER - bool - -config LPS22DF_THREAD_PRIORITY - int "Thread priority" - depends on LPS22DF_TRIGGER_OWN_THREAD - default 10 - help - Priority of thread used by the driver to handle interrupts. - -config LPS22DF_THREAD_STACK_SIZE - int "Thread stack size" - depends on LPS22DF_TRIGGER_OWN_THREAD - default 1024 - help - Stack size of thread used by the driver to handle interrupts. - -endif # LPS22DF diff --git a/drivers/sensor/lps22df/lps22df.c b/drivers/sensor/lps22df/lps22df.c deleted file mode 100644 index a74ef75c245..00000000000 --- a/drivers/sensor/lps22df/lps22df.c +++ /dev/null @@ -1,338 +0,0 @@ -/* ST Microelectronics LPS22DF pressure and temperature sensor - * - * Copyright (c) 2023 STMicroelectronics - * - * SPDX-License-Identifier: Apache-2.0 - * - * Datasheet: - * https://www.st.com/resource/en/datasheet/lps22df.pdf - */ - -#define DT_DRV_COMPAT st_lps22df - -#include -#include -#include -#include -#include -#include -#include - -#include "lps22df.h" - -#define LPS22DF_SWRESET_WAIT_TIME 50 - -LOG_MODULE_REGISTER(LPS22DF, CONFIG_SENSOR_LOG_LEVEL); - -static inline int lps22df_set_odr_raw(const struct device *dev, uint8_t odr) -{ - const struct lps22df_config * const cfg = dev->config; - stmdev_ctx_t *ctx = (stmdev_ctx_t *)&cfg->ctx; - lps22df_md_t md; - - md.odr = odr; - md.avg = cfg->avg; - md.lpf = cfg->lpf; - - return lps22df_mode_set(ctx, &md); -} - -static int lps22df_sample_fetch(const struct device *dev, - enum sensor_channel chan) -{ - struct lps22df_data *data = dev->data; - const struct lps22df_config * const cfg = dev->config; - stmdev_ctx_t *ctx = (stmdev_ctx_t *)&cfg->ctx; - lps22df_data_t raw_data; - - __ASSERT_NO_MSG(chan == SENSOR_CHAN_ALL); - - if (lps22df_data_get(ctx, &raw_data) < 0) { - LOG_DBG("Failed to read sample"); - return -EIO; - } - - data->sample_press = raw_data.pressure.raw; - data->sample_temp = raw_data.heat.raw; - - return 0; -} - -static inline void lps22df_press_convert(struct sensor_value *val, - int32_t raw_val) -{ - int32_t press_tmp = raw_val >> 8; /* raw value is left aligned (24 msb) */ - - /* Pressure sensitivity is 4096 LSB/hPa */ - /* Also convert hPa into kPa */ - - val->val1 = press_tmp / 40960; - - /* For the decimal part use (3125 / 128) as a factor instead of - * (1000000 / 40960) to avoid int32 overflow - */ - val->val2 = (press_tmp % 40960) * 3125 / 128; -} - -static inline void lps22df_temp_convert(struct sensor_value *val, - int16_t raw_val) -{ - /* Temperature sensitivity is 100 LSB/deg C */ - val->val1 = raw_val / 100; - val->val2 = ((int32_t)raw_val % 100) * 10000; -} - -static int lps22df_channel_get(const struct device *dev, - enum sensor_channel chan, - struct sensor_value *val) -{ - struct lps22df_data *data = dev->data; - - if (chan == SENSOR_CHAN_PRESS) { - lps22df_press_convert(val, data->sample_press); - } else if (chan == SENSOR_CHAN_AMBIENT_TEMP) { - lps22df_temp_convert(val, data->sample_temp); - } else { - return -ENOTSUP; - } - - return 0; -} - -static const uint16_t lps22df_map[] = {0, 1, 4, 10, 25, 50, 75, 100, 200}; - -static int lps22df_odr_set(const struct device *dev, uint16_t freq) -{ - int odr; - - for (odr = 0; odr < ARRAY_SIZE(lps22df_map); odr++) { - if (freq == lps22df_map[odr]) { - break; - } - } - - if (odr == ARRAY_SIZE(lps22df_map)) { - LOG_DBG("bad frequency"); - return -EINVAL; - } - - if (lps22df_set_odr_raw(dev, odr) < 0) { - LOG_DBG("failed to set sampling rate"); - return -EIO; - } - - return 0; -} - -static int lps22df_attr_set(const struct device *dev, - enum sensor_channel chan, - enum sensor_attribute attr, - const struct sensor_value *val) -{ - if (chan != SENSOR_CHAN_ALL) { - LOG_WRN("attr_set() not supported on this channel."); - return -ENOTSUP; - } - - switch (attr) { - case SENSOR_ATTR_SAMPLING_FREQUENCY: - return lps22df_odr_set(dev, val->val1); - default: - LOG_DBG("operation not supported."); - return -ENOTSUP; - } - - return 0; -} - -static const struct sensor_driver_api lps22df_driver_api = { - .attr_set = lps22df_attr_set, - .sample_fetch = lps22df_sample_fetch, - .channel_get = lps22df_channel_get, -#if CONFIG_LPS22DF_TRIGGER - .trigger_set = lps22df_trigger_set, -#endif -}; - -static int lps22df_init_chip(const struct device *dev) -{ - const struct lps22df_config * const cfg = dev->config; - __maybe_unused struct lps22df_data *data = dev->data; - stmdev_ctx_t *ctx = (stmdev_ctx_t *)&cfg->ctx; - lps22df_id_t id; - lps22df_stat_t status; - uint8_t tries = 10; - int ret; - -#if DT_ANY_INST_ON_BUS_STATUS_OKAY(i3c) - if (cfg->i3c.bus != NULL) { - /* - * Need to grab the pointer to the I3C device descriptor - * before we can talk to the sensor. - */ - data->i3c_dev = i3c_device_find(cfg->i3c.bus, &cfg->i3c.dev_id); - if (data->i3c_dev == NULL) { - LOG_ERR("Cannot find I3C device descriptor"); - return -ENODEV; - } - } -#endif - - if (lps22df_id_get(ctx, &id) < 0) { - LOG_ERR("%s: Not able to read dev id", dev->name); - return -EIO; - } - - if (id.whoami != LPS22DF_ID) { - LOG_ERR("%s: Invalid chip ID 0x%02x", dev->name, id.whoami); - return -EIO; - } - - LOG_DBG("%s: chip id 0x%x", dev->name, id.whoami); - - /* Restore default configuration */ - if (lps22df_init_set(ctx, LPS22DF_RESET) < 0) { - LOG_ERR("%s: Not able to reset device", dev->name); - return -EIO; - } - - do { - if (!--tries) { - LOG_DBG("sw reset timed out"); - return -ETIMEDOUT; - } - k_usleep(LPS22DF_SWRESET_WAIT_TIME); - - if (lps22df_status_get(ctx, &status) < 0) { - return -EIO; - } - } while (status.sw_reset); - - /* Set bdu and if_inc recommended for driver usage */ - if (lps22df_init_set(ctx, LPS22DF_DRV_RDY) < 0) { - LOG_ERR("%s: Not able to set device to ready state", dev->name); - return -EIO; - } - - if (ON_I3C_BUS(cfg)) { - lps22df_bus_mode_t bus_mode; - - /* Select bus interface */ - bus_mode.filter = LPS22DF_AUTO; - bus_mode.interface = LPS22DF_SEL_BY_HW; - lps22df_bus_mode_set(ctx, &bus_mode); - - } - - /* set sensor default odr */ - LOG_DBG("%s: odr: %d", dev->name, cfg->odr); - ret = lps22df_set_odr_raw(dev, cfg->odr); - if (ret < 0) { - LOG_ERR("%s: Failed to set odr %d", dev->name, cfg->odr); - return ret; - } - - return 0; -} - -static int lps22df_init(const struct device *dev) -{ - if (lps22df_init_chip(dev) < 0) { - LOG_DBG("Failed to initialize chip"); - return -EIO; - } - -#ifdef CONFIG_LPS22DF_TRIGGER - if (lps22df_init_interrupt(dev) < 0) { - LOG_ERR("Failed to initialize interrupt."); - return -EIO; - } -#endif - - return 0; -} - -/* - * Instantiation macros used when a device is on a SPI bus. - */ - -#ifdef CONFIG_LPS22DF_TRIGGER -#define LPS22DF_CFG_IRQ(inst) \ - .gpio_int = GPIO_DT_SPEC_INST_GET(inst, drdy_gpios), -#else -#define LPS22DF_CFG_IRQ(inst) -#endif /* CONFIG_LPS22DF_TRIGGER */ - -#define LPS22DF_CONFIG_COMMON(inst) \ - .odr = DT_INST_PROP(inst, odr), \ - .lpf = DT_INST_PROP(inst, lpf), \ - .avg = DT_INST_PROP(inst, avg), \ - .drdy_pulsed = DT_INST_PROP(inst, drdy_pulsed), \ - COND_CODE_1(DT_INST_NODE_HAS_PROP(inst, drdy_gpios), \ - (LPS22DF_CFG_IRQ(inst)), ()) - -#define LPS22DF_SPI_OPERATION (SPI_WORD_SET(8) | SPI_OP_MODE_MASTER | \ - SPI_MODE_CPOL | SPI_MODE_CPHA) \ - -#define LPS22DF_CONFIG_SPI(inst) \ - { \ - STMEMSC_CTX_SPI(&lps22df_config_##inst.stmemsc_cfg), \ - .stmemsc_cfg = { \ - .spi = SPI_DT_SPEC_INST_GET(inst, \ - LPS22DF_SPI_OPERATION, \ - 0), \ - }, \ - LPS22DF_CONFIG_COMMON(inst) \ - } - -/* - * Instantiation macros used when a device is on an I2C bus. - */ - -#define LPS22DF_CONFIG_I2C(inst) \ - { \ - STMEMSC_CTX_I2C(&lps22df_config_##inst.stmemsc_cfg), \ - .stmemsc_cfg = { \ - .i2c = I2C_DT_SPEC_INST_GET(inst), \ - }, \ - LPS22DF_CONFIG_COMMON(inst) \ - } - -/* - * Instantiation macros used when a device is on an I#C bus. - */ - -#define LPS22DF_CONFIG_I3C(inst) \ - { \ - STMEMSC_CTX_I3C(&lps22df_config_##inst.stmemsc_cfg), \ - .stmemsc_cfg = { \ - .i3c = &lps22df_data_##inst.i3c_dev, \ - }, \ - .i3c.bus = DEVICE_DT_GET(DT_INST_BUS(inst)), \ - .i3c.dev_id = I3C_DEVICE_ID_DT_INST(inst), \ - LPS22DF_CONFIG_COMMON(inst) \ - } - -#define LPS22DF_CONFIG_I3C_OR_I2C(inst) \ - COND_CODE_0(DT_INST_PROP_BY_IDX(inst, reg, 1), \ - (LPS22DF_CONFIG_I2C(inst)), \ - (LPS22DF_CONFIG_I3C(inst))) - -/* - * Main instantiation macro. Use of COND_CODE_1() selects the right - * bus-specific macro at preprocessor time. - */ - -#define LPS22DF_DEFINE(inst) \ - static struct lps22df_data lps22df_data_##inst; \ - static const struct lps22df_config lps22df_config_##inst = \ - COND_CODE_1(DT_INST_ON_BUS(inst, spi), \ - (LPS22DF_CONFIG_SPI(inst)), \ - (COND_CODE_1(DT_INST_ON_BUS(inst, i3c), \ - (LPS22DF_CONFIG_I3C_OR_I2C(inst)), \ - (LPS22DF_CONFIG_I2C(inst))))); \ - SENSOR_DEVICE_DT_INST_DEFINE(inst, lps22df_init, NULL, &lps22df_data_##inst, \ - &lps22df_config_##inst, POST_KERNEL, \ - CONFIG_SENSOR_INIT_PRIORITY, &lps22df_driver_api); - -DT_INST_FOREACH_STATUS_OKAY(LPS22DF_DEFINE) diff --git a/drivers/sensor/lps22df/lps22df.h b/drivers/sensor/lps22df/lps22df.h deleted file mode 100644 index 044c08cbd93..00000000000 --- a/drivers/sensor/lps22df/lps22df.h +++ /dev/null @@ -1,99 +0,0 @@ -/* ST Microelectronics LPS22DF pressure and temperature sensor - * - * Copyright (c) 2023 STMicroelectronics - * - * SPDX-License-Identifier: Apache-2.0 - * - * Datasheet: - * https://www.st.com/resource/en/datasheet/lps22df.pdf - */ - -#ifndef ZEPHYR_DRIVERS_SENSOR_LPS22DF_LPS22DF_H_ -#define ZEPHYR_DRIVERS_SENSOR_LPS22DF_LPS22DF_H_ - -#include -#include -#include "lps22df_reg.h" - -#if DT_ANY_INST_ON_BUS_STATUS_OKAY(spi) -#include -#endif /* DT_ANY_INST_ON_BUS_STATUS_OKAY(spi) */ - -#if DT_ANY_INST_ON_BUS_STATUS_OKAY(i2c) -#include -#endif /* DT_ANY_INST_ON_BUS_STATUS_OKAY(i2c) */ - -#if DT_ANY_INST_ON_BUS_STATUS_OKAY(i3c) -#include -#endif /* DT_ANY_INST_ON_BUS_STATUS_OKAY(i3c) */ - -#if DT_ANY_INST_ON_BUS_STATUS_OKAY(i3c) - #define ON_I3C_BUS(cfg) (cfg->i3c.bus != NULL) -#else - #define ON_I3C_BUS(cfg) (false) -#endif - -struct lps22df_config { - stmdev_ctx_t ctx; - union { -#if DT_ANY_INST_ON_BUS_STATUS_OKAY(i2c) - const struct i2c_dt_spec i2c; -#endif -#if DT_ANY_INST_ON_BUS_STATUS_OKAY(spi) - const struct spi_dt_spec spi; -#endif -#if DT_ANY_INST_ON_BUS_STATUS_OKAY(i3c) - struct i3c_device_desc **i3c; -#endif - } stmemsc_cfg; - uint8_t odr; - uint8_t lpf; - uint8_t avg; - uint8_t drdy_pulsed; -#ifdef CONFIG_LPS22DF_TRIGGER - struct gpio_dt_spec gpio_int; -#endif - -#if DT_ANY_INST_ON_BUS_STATUS_OKAY(i3c) - struct { - const struct device *bus; - const struct i3c_device_id dev_id; - } i3c; -#endif -}; - -struct lps22df_data { - int32_t sample_press; - int16_t sample_temp; - -#ifdef CONFIG_LPS22DF_TRIGGER - struct gpio_callback gpio_cb; - - const struct sensor_trigger *data_ready_trigger; - sensor_trigger_handler_t handler_drdy; - const struct device *dev; - -#if defined(CONFIG_LPS22DF_TRIGGER_OWN_THREAD) - K_KERNEL_STACK_MEMBER(thread_stack, CONFIG_LPS22DF_THREAD_STACK_SIZE); - struct k_thread thread; - struct k_sem intr_sem; -#elif defined(CONFIG_LPS22DF_TRIGGER_GLOBAL_THREAD) - struct k_work work; -#endif - -#endif /* CONFIG_LPS22DF_TRIGGER */ - -#if DT_ANY_INST_ON_BUS_STATUS_OKAY(i3c) - struct i3c_device_desc *i3c_dev; -#endif -}; - -#ifdef CONFIG_LPS22DF_TRIGGER -int lps22df_trigger_set(const struct device *dev, - const struct sensor_trigger *trig, - sensor_trigger_handler_t handler); - -int lps22df_init_interrupt(const struct device *dev); -#endif - -#endif /* ZEPHYR_DRIVERS_SENSOR_LPS22DF_LPS22DF_H_ */ diff --git a/drivers/sensor/lps22df/lps22df_trigger.c b/drivers/sensor/lps22df/lps22df_trigger.c deleted file mode 100644 index c5d6a91dba8..00000000000 --- a/drivers/sensor/lps22df/lps22df_trigger.c +++ /dev/null @@ -1,251 +0,0 @@ -/* ST Microelectronics LPS22DF pressure and temperature sensor - * - * Copyright (c) 2023 STMicroelectronics - * - * SPDX-License-Identifier: Apache-2.0 - * - * Datasheet: - * https://www.st.com/resource/en/datasheet/lps22df.pdf - */ - -#define DT_DRV_COMPAT st_lps22df - -#include -#include -#include -#include - -#include "lps22df.h" - -LOG_MODULE_DECLARE(LPS22DF, CONFIG_SENSOR_LOG_LEVEL); - -/** - * lps22df_enable_int - enable selected int pin to generate interrupt - */ -static int lps22df_enable_int(const struct device *dev, int enable) -{ - const struct lps22df_config * const cfg = dev->config; - stmdev_ctx_t *ctx = (stmdev_ctx_t *)&cfg->ctx; - lps22df_pin_int_route_t int_route; - - /* set interrupt */ - lps22df_pin_int_route_get(ctx, &int_route); - int_route.drdy_pres = enable; - return lps22df_pin_int_route_set(ctx, &int_route); -} - -/** - * lps22df_trigger_set - link external trigger to event data ready - */ -int lps22df_trigger_set(const struct device *dev, - const struct sensor_trigger *trig, - sensor_trigger_handler_t handler) -{ - struct lps22df_data *lps22df = dev->data; - const struct lps22df_config * const cfg = dev->config; - stmdev_ctx_t *ctx = (stmdev_ctx_t *)&cfg->ctx; - lps22df_data_t raw_data; - - if (trig->chan != SENSOR_CHAN_ALL) { - LOG_WRN("trigger set not supported on this channel."); - return -ENOTSUP; - } - - lps22df->handler_drdy = handler; - lps22df->data_ready_trigger = trig; - if (handler) { - /* dummy read: re-trigger interrupt */ - if (lps22df_data_get(ctx, &raw_data) < 0) { - LOG_DBG("Failed to read sample"); - return -EIO; - } - return lps22df_enable_int(dev, 1); - } else { - return lps22df_enable_int(dev, 0); - } - - return -ENOTSUP; -} - -/** - * lps22df_handle_interrupt - handle the drdy event - * read data and call handler if registered any - */ -static void lps22df_handle_interrupt(const struct device *dev) -{ - int ret; - struct lps22df_data *lps22df = dev->data; - const struct lps22df_config *cfg = dev->config; - stmdev_ctx_t *ctx = (stmdev_ctx_t *)&cfg->ctx; - lps22df_all_sources_t status; - - if (lps22df_all_sources_get(ctx, &status) < 0) { - LOG_DBG("failed reading status reg"); - goto exit; - } - - if (status.drdy_pres == 0) { - goto exit; /* spurious interrupt */ - } - - if (lps22df->handler_drdy != NULL) { - lps22df->handler_drdy(dev, lps22df->data_ready_trigger); - } - - if (ON_I3C_BUS(cfg)) { - /* - * I3C IBI does not rely on GPIO. - * So no need to enable GPIO pin for interrupt trigger. - */ - return; - } - -exit: - ret = gpio_pin_interrupt_configure_dt(&cfg->gpio_int, - GPIO_INT_EDGE_TO_ACTIVE); - if (ret < 0) { - LOG_ERR("%s: Not able to configure pin_int", dev->name); - } -} - -static void lps22df_intr_callback(struct lps22df_data *lps22df) -{ -#if defined(CONFIG_LPS22DF_TRIGGER_OWN_THREAD) - k_sem_give(&lps22df->intr_sem); -#elif defined(CONFIG_LPS22DF_TRIGGER_GLOBAL_THREAD) - k_work_submit(&lps22df->work); -#endif /* CONFIG_LPS22DF_TRIGGER_OWN_THREAD */ -} - -static void lps22df_gpio_callback(const struct device *dev, - struct gpio_callback *cb, uint32_t pins) -{ - struct lps22df_data *lps22df = - CONTAINER_OF(cb, struct lps22df_data, gpio_cb); - - ARG_UNUSED(pins); - const struct lps22df_config *cfg = lps22df->dev->config; - int ret; - - ret = gpio_pin_interrupt_configure_dt(&cfg->gpio_int, GPIO_INT_DISABLE); - if (ret < 0) { - LOG_ERR("%s: Not able to configure pin_int", dev->name); - } - - lps22df_intr_callback(lps22df); -} - -#ifdef CONFIG_LPS22DF_TRIGGER_OWN_THREAD -static void lps22df_thread(struct lps22df_data *lps22df) -{ - while (1) { - k_sem_take(&lps22df->intr_sem, K_FOREVER); - lps22df_handle_interrupt(lps22df->dev); - } -} -#endif /* CONFIG_LPS22DF_TRIGGER_OWN_THREAD */ - -#ifdef CONFIG_LPS22DF_TRIGGER_GLOBAL_THREAD -static void lps22df_work_cb(struct k_work *work) -{ - struct lps22df_data *lps22df = - CONTAINER_OF(work, struct lps22df_data, work); - - lps22df_handle_interrupt(lps22df->dev); -} -#endif /* CONFIG_LPS22DF_TRIGGER_GLOBAL_THREAD */ - -#if DT_ANY_INST_ON_BUS_STATUS_OKAY(i3c) -static int lps22df_ibi_cb(struct i3c_device_desc *target, - struct i3c_ibi_payload *payload) -{ - const struct device *dev = target->dev; - struct lps22df_data *lps22df = dev->data; - - ARG_UNUSED(payload); - - lps22df_intr_callback(lps22df); - - return 0; -} -#endif - -int lps22df_init_interrupt(const struct device *dev) -{ - struct lps22df_data *lps22df = dev->data; - const struct lps22df_config *cfg = dev->config; - stmdev_ctx_t *ctx = (stmdev_ctx_t *)&cfg->ctx; - lps22df_int_mode_t mode; - int ret; - - /* setup data ready gpio interrupt */ - if (!gpio_is_ready_dt(&cfg->gpio_int) && !ON_I3C_BUS(cfg)) { - if (cfg->gpio_int.port) { - LOG_ERR("%s: device %s is not ready", dev->name, - cfg->gpio_int.port->name); - return -ENODEV; - } - - LOG_DBG("%s: gpio_int not defined in DT", dev->name); - return 0; - } - - lps22df->dev = dev; - -#if defined(CONFIG_LPS22DF_TRIGGER_OWN_THREAD) - k_sem_init(&lps22df->intr_sem, 0, K_SEM_MAX_LIMIT); - - k_thread_create(&lps22df->thread, lps22df->thread_stack, - CONFIG_LPS22DF_THREAD_STACK_SIZE, - (k_thread_entry_t)lps22df_thread, lps22df, - NULL, NULL, K_PRIO_COOP(CONFIG_LPS22DF_THREAD_PRIORITY), - 0, K_NO_WAIT); -#elif defined(CONFIG_LPS22DF_TRIGGER_GLOBAL_THREAD) - lps22df->work.handler = lps22df_work_cb; -#endif /* CONFIG_LPS22DF_TRIGGER_OWN_THREAD */ - - if (!ON_I3C_BUS(cfg)) { - ret = gpio_pin_configure_dt(&cfg->gpio_int, GPIO_INPUT); - if (ret < 0) { - LOG_ERR("Could not configure gpio"); - return ret; - } - - LOG_INF("%s: int on %s.%02u", dev->name, cfg->gpio_int.port->name, - cfg->gpio_int.pin); - - gpio_init_callback(&lps22df->gpio_cb, - lps22df_gpio_callback, - BIT(cfg->gpio_int.pin)); - - ret = gpio_add_callback(cfg->gpio_int.port, &lps22df->gpio_cb); - if (ret < 0) { - LOG_ERR("Could not set gpio callback"); - return ret; - } - } - - /* enable drdy in pulsed/latched mode */ - LOG_DBG("drdy_pulsed is %d", (int)cfg->drdy_pulsed); - mode.drdy_latched = ~cfg->drdy_pulsed; - if (lps22df_interrupt_mode_set(ctx, &mode) < 0) { - return -EIO; - } - -#if DT_ANY_INST_ON_BUS_STATUS_OKAY(i3c) - if (cfg->i3c.bus != NULL) { - /* I3C IBI does not utilize GPIO interrupt. */ - lps22df->i3c_dev->ibi_cb = lps22df_ibi_cb; - - if (i3c_ibi_enable(lps22df->i3c_dev) != 0) { - LOG_DBG("Could not enable I3C IBI"); - return -EIO; - } - - return 0; - } -#endif - - return gpio_pin_interrupt_configure_dt(&cfg->gpio_int, - GPIO_INT_EDGE_TO_ACTIVE); -} diff --git a/drivers/sensor/lps2xdf/CMakeLists.txt b/drivers/sensor/lps2xdf/CMakeLists.txt new file mode 100644 index 00000000000..24a1b5844a8 --- /dev/null +++ b/drivers/sensor/lps2xdf/CMakeLists.txt @@ -0,0 +1,15 @@ +# ST Microelectronics LPS22DF pressure and temperature sensor +# +# Copyright (c) 2023 STMicroelectronics +# Copyright (c) 2023 PHYTEC Messtechnik GmbH +# +# SPDX-License-Identifier: Apache-2.0 +# +zephyr_library() + +zephyr_library_sources(lps2xdf.c) +zephyr_library_sources_ifdef(CONFIG_DT_HAS_ST_LPS22DF_ENABLED lps22df.c ) +zephyr_library_sources_ifdef(CONFIG_DT_HAS_ST_LPS28DFW_ENABLED lps28dfw.c ) +zephyr_library_sources_ifdef(CONFIG_LPS2XDF_TRIGGER lps2xdf_trigger.c) + +zephyr_library_include_directories(../stmemsc) diff --git a/drivers/sensor/lps2xdf/Kconfig b/drivers/sensor/lps2xdf/Kconfig new file mode 100644 index 00000000000..9ea7b94200e --- /dev/null +++ b/drivers/sensor/lps2xdf/Kconfig @@ -0,0 +1,63 @@ +# ST Microelectronics LPS2xDF pressure and temperature sensor + +# Copyright (c) 2023 STMicroelectronics +# Copyright (c) 2023 PHYTEC Messtechnik GmbH +# SPDX-License-Identifier: Apache-2.0 + +menuconfig LPS2XDF + bool "LPS2xDF pressure and temperature" + default y + depends on DT_HAS_ST_LPS22DF_ENABLED || DT_HAS_ST_LPS28DFW_ENABLED + select I2C if $(dt_compat_on_bus,$(DT_COMPAT_ST_LPS22DF),i2c) ||\ + $(dt_compat_on_bus,$(DT_COMPAT_ST_LPS28DFW),i2c) + select I2C if $(dt_compat_on_bus,$(DT_COMPAT_ST_LPS22DF),i3c) ||\ + $(dt_compat_on_bus,$(DT_COMPAT_ST_LPS28DFW),i3c) + select SPI if $(dt_compat_on_bus,$(DT_COMPAT_ST_LPS22DF),spi) + select HAS_STMEMSC + select USE_STDC_LPS22DF if DT_HAS_ST_LPS22DF_ENABLED + select USE_STDC_LPS28DFW if DT_HAS_ST_LPS28DFW_ENABLED + help + Enable driver for LPS2xDF I2C-based pressure and temperature + sensor. + +if LPS2XDF + +choice LPS2XDF_TRIGGER_MODE + prompt "Trigger mode" + default LPS2XDF_TRIGGER_GLOBAL_THREAD + help + Specify the type of triggering to be used by the driver. + +config LPS2XDF_TRIGGER_NONE + bool "No trigger" + +config LPS2XDF_TRIGGER_GLOBAL_THREAD + bool "Use global thread" + depends on GPIO + select LPS2XDF_TRIGGER + +config LPS2XDF_TRIGGER_OWN_THREAD + bool "Use own thread" + depends on GPIO + select LPS2XDF_TRIGGER + +endchoice # LPS2XDF_TRIGGER_MODE + +config LPS2XDF_TRIGGER + bool + +config LPS2XDF_THREAD_PRIORITY + int "Thread priority" + depends on LPS2XDF_TRIGGER_OWN_THREAD + default 10 + help + Priority of thread used by the driver to handle interrupts. + +config LPS2XDF_THREAD_STACK_SIZE + int "Thread stack size" + depends on LPS2XDF_TRIGGER_OWN_THREAD + default 1024 + help + Stack size of thread used by the driver to handle interrupts. + +endif # LPS2XDF diff --git a/drivers/sensor/lps2xdf/lps22df.c b/drivers/sensor/lps2xdf/lps22df.c new file mode 100644 index 00000000000..627d02a55b9 --- /dev/null +++ b/drivers/sensor/lps2xdf/lps22df.c @@ -0,0 +1,233 @@ +/* ST Microelectronics LPS22DF pressure and temperature sensor + * + * Copyright (c) 2023 STMicroelectronics + * Copyright (c) 2023 PHYTEC Messtechnik GmbH + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include "lps2xdf.h" +#include "lps22df.h" +#include + +LOG_MODULE_DECLARE(LPS2XDF, CONFIG_SENSOR_LOG_LEVEL); + +static inline int lps22df_mode_set_odr_raw(const struct device *dev, uint8_t odr) +{ + const struct lps2xdf_config *const cfg = dev->config; + stmdev_ctx_t *ctx = (stmdev_ctx_t *)&cfg->ctx; + lps22df_md_t md; + + md.odr = odr; + md.avg = cfg->avg; + md.lpf = cfg->lpf; + + return lps22df_mode_set(ctx, &md); +} + +static int lps22df_sample_fetch(const struct device *dev, enum sensor_channel chan) +{ + struct lps2xdf_data *data = dev->data; + const struct lps2xdf_config *const cfg = dev->config; + stmdev_ctx_t *ctx = (stmdev_ctx_t *)&cfg->ctx; + lps22df_data_t raw_data; + + if (lps22df_data_get(ctx, &raw_data) < 0) { + LOG_DBG("Failed to read sample"); + return -EIO; + } + + data->sample_press = raw_data.pressure.raw; + data->sample_temp = raw_data.heat.raw; + + return 0; +} + +/** + * lps22df_handle_interrupt - handle the drdy event + * read data and call handler if registered any + */ +#ifdef CONFIG_LPS2XDF_TRIGGER +static void lps22df_handle_interrupt(const struct device *dev) +{ + int ret; + struct lps2xdf_data *lps22df = dev->data; + const struct lps2xdf_config *cfg = dev->config; + stmdev_ctx_t *ctx = (stmdev_ctx_t *)&cfg->ctx; + lps22df_all_sources_t status; + + if (lps22df_all_sources_get(ctx, &status) < 0) { + LOG_DBG("failed reading status reg"); + goto exit; + } + + if (status.drdy_pres == 0) { + goto exit; /* spurious interrupt */ + } + + if (lps22df->handler_drdy != NULL) { + lps22df->handler_drdy(dev, lps22df->data_ready_trigger); + } + + if (ON_I3C_BUS(cfg)) { + /* + * I3C IBI does not rely on GPIO. + * So no need to enable GPIO pin for interrupt trigger. + */ + return; + } + +exit: + ret = gpio_pin_interrupt_configure_dt(&cfg->gpio_int, + GPIO_INT_EDGE_TO_ACTIVE); + if (ret < 0) { + LOG_ERR("%s: Not able to configure pin_int", dev->name); + } +} + +/** + * lps22df_enable_int - enable selected int pin to generate interrupt + */ +static int lps22df_enable_int(const struct device *dev, int enable) +{ + const struct lps2xdf_config * const cfg = dev->config; + stmdev_ctx_t *ctx = (stmdev_ctx_t *)&cfg->ctx; + lps22df_pin_int_route_t int_route; + + /* set interrupt */ + lps22df_pin_int_route_get(ctx, &int_route); + int_route.drdy_pres = enable; + return lps22df_pin_int_route_set(ctx, &int_route); +} + +/** + * lps22df_trigger_set - link external trigger to event data ready + */ +static int lps22df_trigger_set(const struct device *dev, + const struct sensor_trigger *trig, + sensor_trigger_handler_t handler) +{ + struct lps2xdf_data *lps22df = dev->data; + const struct lps2xdf_config * const cfg = dev->config; + stmdev_ctx_t *ctx = (stmdev_ctx_t *)&cfg->ctx; + lps22df_data_t raw_data; + + if (trig->chan != SENSOR_CHAN_ALL) { + LOG_WRN("trigger set not supported on this channel."); + return -ENOTSUP; + } + + lps22df->handler_drdy = handler; + lps22df->data_ready_trigger = trig; + if (handler) { + /* dummy read: re-trigger interrupt */ + if (lps22df_data_get(ctx, &raw_data) < 0) { + LOG_DBG("Failed to read sample"); + return -EIO; + } + return lps22df_enable_int(dev, 1); + } else { + return lps22df_enable_int(dev, 0); + } + + return -ENOTSUP; +} +#endif /* CONFIG_LPS2XDF_TRIGGER */ + +const struct lps2xdf_chip_api st_lps22df_chip_api = { + .mode_set_odr_raw = lps22df_mode_set_odr_raw, + .sample_fetch = lps22df_sample_fetch, +#if CONFIG_LPS2XDF_TRIGGER + .handle_interrupt = lps22df_handle_interrupt, + .trigger_set = lps22df_trigger_set, +#endif +}; + +int st_lps22df_init(const struct device *dev) +{ + const struct lps2xdf_config *const cfg = dev->config; + stmdev_ctx_t *ctx = (stmdev_ctx_t *)&cfg->ctx; + lps22df_id_t id; + lps22df_stat_t status; + uint8_t tries = 10; + int ret; + +#if DT_HAS_COMPAT_ON_BUS_STATUS_OKAY(st_lps22df, i3c) + if (cfg->i3c.bus != NULL) { + struct lps2xdf_data *data = dev->data; + /* + * Need to grab the pointer to the I3C device descriptor + * before we can talk to the sensor. + */ + data->i3c_dev = i3c_device_find(cfg->i3c.bus, &cfg->i3c.dev_id); + if (data->i3c_dev == NULL) { + LOG_ERR("Cannot find I3C device descriptor"); + return -ENODEV; + } + } +#endif + + if (lps22df_id_get(ctx, &id) < 0) { + LOG_ERR("%s: Not able to read dev id", dev->name); + return -EIO; + } + + if (id.whoami != LPS22DF_ID) { + LOG_ERR("%s: Invalid chip ID 0x%02x", dev->name, id.whoami); + return -EIO; + } + + LOG_DBG("%s: chip id 0x%x", dev->name, id.whoami); + + /* Restore default configuration */ + if (lps22df_init_set(ctx, LPS22DF_RESET) < 0) { + LOG_ERR("%s: Not able to reset device", dev->name); + return -EIO; + } + + do { + if (!--tries) { + LOG_DBG("sw reset timed out"); + return -ETIMEDOUT; + } + k_usleep(LPS2XDF_SWRESET_WAIT_TIME_US); + + if (lps22df_status_get(ctx, &status) < 0) { + return -EIO; + } + } while (status.sw_reset); + + /* Set bdu and if_inc recommended for driver usage */ + if (lps22df_init_set(ctx, LPS22DF_DRV_RDY) < 0) { + LOG_ERR("%s: Not able to set device to ready state", dev->name); + return -EIO; + } + + if (ON_I3C_BUS(cfg)) { + lps22df_bus_mode_t bus_mode; + + /* Select bus interface */ + bus_mode.filter = LPS22DF_AUTO; + bus_mode.interface = LPS22DF_SEL_BY_HW; + lps22df_bus_mode_set(ctx, &bus_mode); + } + + /* set sensor default odr */ + LOG_DBG("%s: odr: %d", dev->name, cfg->odr); + ret = lps22df_mode_set_odr_raw(dev, cfg->odr); + if (ret < 0) { + LOG_ERR("%s: Failed to set odr %d", dev->name, cfg->odr); + return ret; + } + +#ifdef CONFIG_LPS2XDF_TRIGGER + if (cfg->trig_enabled) { + if (lps2xdf_init_interrupt(dev, DEVICE_VARIANT_LPS22DF) < 0) { + LOG_ERR("Failed to initialize interrupt."); + return -EIO; + } + } +#endif + + return 0; +} diff --git a/drivers/sensor/lps2xdf/lps22df.h b/drivers/sensor/lps2xdf/lps22df.h new file mode 100644 index 00000000000..bb03423ea8a --- /dev/null +++ b/drivers/sensor/lps2xdf/lps22df.h @@ -0,0 +1,23 @@ +/* ST Microelectronics LPS22DF pressure and temperature sensor + * + * Copyright (c) 2023 STMicroelectronics + * Copyright (c) 2023 PHYTEC Messtechnik GmbH + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include +#include + +#include "lps22df_reg.h" + +#include + +#ifndef ZEPHYR_DRIVERS_SENSOR_LPS22DF_LPS22DF_H_ +#define ZEPHYR_DRIVERS_SENSOR_LPS22DF_LPS22DF_H_ + +extern const struct lps2xdf_chip_api st_lps22df_chip_api; + +int st_lps22df_init(const struct device *dev); + +#endif /* ZEPHYR_DRIVERS_SENSOR_LPS22DF_H_ */ diff --git a/drivers/sensor/lps2xdf/lps28dfw.c b/drivers/sensor/lps2xdf/lps28dfw.c new file mode 100644 index 00000000000..86d0ab4edf5 --- /dev/null +++ b/drivers/sensor/lps2xdf/lps28dfw.c @@ -0,0 +1,240 @@ +/* ST Microelectronics LPS28DFW pressure and temperature sensor + * + * Copyright (c) 2023 STMicroelectronics + * Copyright (c) 2023 PHYTEC Messtechnik GmbH + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include "lps2xdf.h" +#include "lps28dfw.h" +#include + +LOG_MODULE_DECLARE(LPS2XDF, CONFIG_SENSOR_LOG_LEVEL); + +static inline int lps28dfw_mode_set_odr_raw(const struct device *dev, uint8_t odr) +{ + const struct lps2xdf_config *const cfg = dev->config; + stmdev_ctx_t *ctx = (stmdev_ctx_t *)&cfg->ctx; + lps28dfw_md_t md; + + md.odr = odr; + md.avg = cfg->avg; + md.lpf = cfg->lpf; + md.fs = cfg->fs; + + return lps28dfw_mode_set(ctx, &md); +} + +static int lps28dfw_sample_fetch(const struct device *dev, enum sensor_channel chan) +{ + struct lps2xdf_data *data = dev->data; + const struct lps2xdf_config *const cfg = dev->config; + stmdev_ctx_t *ctx = (stmdev_ctx_t *)&cfg->ctx; + lps28dfw_data_t raw_data; + lps28dfw_md_t md; + + md.fs = cfg->fs; + + if (lps28dfw_data_get(ctx, &md, &raw_data) < 0) { + LOG_DBG("Failed to read sample"); + return -EIO; + } + + data->sample_press = raw_data.pressure.raw; + data->sample_temp = raw_data.heat.raw; + + return 0; +} + +/** + * lps28dfw_handle_interrupt - handle the drdy event + * read data and call handler if registered any + */ +#ifdef CONFIG_LPS2XDF_TRIGGER +static void lps28dfw_handle_interrupt(const struct device *dev) +{ + int ret; + struct lps2xdf_data *lps28dfw = dev->data; + const struct lps2xdf_config *cfg = dev->config; + stmdev_ctx_t *ctx = (stmdev_ctx_t *)&cfg->ctx; + lps28dfw_all_sources_t status; + + if (lps28dfw_all_sources_get(ctx, &status) < 0) { + LOG_DBG("failed reading status reg"); + goto exit; + } + + if (status.drdy_pres == 0) { + goto exit; /* spurious interrupt */ + } + + if (lps28dfw->handler_drdy != NULL) { + lps28dfw->handler_drdy(dev, lps28dfw->data_ready_trigger); + } + + if (ON_I3C_BUS(cfg)) { + /* + * I3C IBI does not rely on GPIO. + * So no need to enable GPIO pin for interrupt trigger. + */ + return; + } + +exit: + ret = gpio_pin_interrupt_configure_dt(&cfg->gpio_int, + GPIO_INT_EDGE_TO_ACTIVE); + if (ret < 0) { + LOG_ERR("%s: Not able to configure pin_int", dev->name); + } +} + +/** + * lps28dfw_enable_int - enable selected int pin to generate interrupt + */ +static int lps28dfw_enable_int(const struct device *dev, int enable) +{ + const struct lps2xdf_config * const cfg = dev->config; + stmdev_ctx_t *ctx = (stmdev_ctx_t *)&cfg->ctx; + lps28dfw_pin_int_route_t int_route; + + /* set interrupt */ + lps28dfw_pin_int_route_get(ctx, &int_route); + int_route.drdy_pres = enable; + return lps28dfw_pin_int_route_set(ctx, &int_route); +} + +/** + * lps22df_trigger_set - link external trigger to event data ready + */ +static int lps28dfw_trigger_set(const struct device *dev, + const struct sensor_trigger *trig, + sensor_trigger_handler_t handler) +{ + struct lps2xdf_data *lps28dfw = dev->data; + const struct lps2xdf_config * const cfg = dev->config; + stmdev_ctx_t *ctx = (stmdev_ctx_t *)&cfg->ctx; + lps28dfw_data_t raw_data; + lps28dfw_md_t md; + + md.fs = cfg->fs; + + if (trig->chan != SENSOR_CHAN_ALL) { + LOG_WRN("trigger set not supported on this channel."); + return -ENOTSUP; + } + + lps28dfw->handler_drdy = handler; + lps28dfw->data_ready_trigger = trig; + if (handler) { + /* dummy read: re-trigger interrupt */ + if (lps28dfw_data_get(ctx, &md, &raw_data) < 0) { + LOG_DBG("Failed to read sample"); + return -EIO; + } + return lps28dfw_enable_int(dev, 1); + } else { + return lps28dfw_enable_int(dev, 0); + } + + return -ENOTSUP; +} +#endif /* CONFIG_LPS2XDF_TRIGGER */ + +const struct lps2xdf_chip_api st_lps28dfw_chip_api = { + .mode_set_odr_raw = lps28dfw_mode_set_odr_raw, + .sample_fetch = lps28dfw_sample_fetch, +#if CONFIG_LPS2XDF_TRIGGER + .handle_interrupt = lps28dfw_handle_interrupt, + .trigger_set = lps28dfw_trigger_set, +#endif +}; + +int st_lps28dfw_init(const struct device *dev) +{ + const struct lps2xdf_config *const cfg = dev->config; + stmdev_ctx_t *ctx = (stmdev_ctx_t *)&cfg->ctx; + lps28dfw_id_t id; + lps28dfw_stat_t status; + uint8_t tries = 10; + int ret; + +#if DT_HAS_COMPAT_ON_BUS_STATUS_OKAY(st_lps28dfw, i3c) + if (cfg->i3c.bus != NULL) { + struct lps2xdf_data *data = dev->data; + /* + * Need to grab the pointer to the I3C device descriptor + * before we can talk to the sensor. + */ + data->i3c_dev = i3c_device_find(cfg->i3c.bus, &cfg->i3c.dev_id); + if (data->i3c_dev == NULL) { + LOG_ERR("Cannot find I3C device descriptor"); + return -ENODEV; + } + } +#endif + + if (lps28dfw_id_get(ctx, &id) < 0) { + LOG_ERR("%s: Not able to read dev id", dev->name); + return -EIO; + } + + if (id.whoami != LPS28DFW_ID) { + LOG_ERR("%s: Invalid chip ID 0x%02x", dev->name, id.whoami); + return -EIO; + } + + LOG_DBG("%s: chip id 0x%x", dev->name, id.whoami); + + /* Restore default configuration */ + if (lps28dfw_init_set(ctx, LPS28DFW_RESET) < 0) { + LOG_ERR("%s: Not able to reset device", dev->name); + return -EIO; + } + + do { + if (!--tries) { + LOG_DBG("sw reset timed out"); + return -ETIMEDOUT; + } + k_usleep(LPS2XDF_SWRESET_WAIT_TIME_US); + + if (lps28dfw_status_get(ctx, &status) < 0) { + return -EIO; + } + } while (status.sw_reset); + + /* Set bdu and if_inc recommended for driver usage */ + if (lps28dfw_init_set(ctx, LPS28DFW_DRV_RDY) < 0) { + LOG_ERR("%s: Not able to set device to ready state", dev->name); + return -EIO; + } + + if (ON_I3C_BUS(cfg)) { + lps28dfw_bus_mode_t bus_mode; + + /* Select bus interface */ + bus_mode.filter = LPS28DFW_AUTO; + bus_mode.interface = LPS28DFW_SEL_BY_HW; + lps28dfw_bus_mode_set(ctx, &bus_mode); + } + + /* set sensor default odr */ + LOG_DBG("%s: odr: %d", dev->name, cfg->odr); + ret = lps28dfw_mode_set_odr_raw(dev, cfg->odr); + if (ret < 0) { + LOG_ERR("%s: Failed to set odr %d", dev->name, cfg->odr); + return ret; + } + +#ifdef CONFIG_LPS2XDF_TRIGGER + if (cfg->trig_enabled) { + if (lps2xdf_init_interrupt(dev, DEVICE_VARIANT_LPS28DFW) < 0) { + LOG_ERR("Failed to initialize interrupt."); + return -EIO; + } + } +#endif + + return 0; +} diff --git a/drivers/sensor/lps2xdf/lps28dfw.h b/drivers/sensor/lps2xdf/lps28dfw.h new file mode 100644 index 00000000000..ba87caab094 --- /dev/null +++ b/drivers/sensor/lps2xdf/lps28dfw.h @@ -0,0 +1,23 @@ +/* ST Microelectronics LPS28DFW pressure and temperature sensor + * + * Copyright (c) 2023 STMicroelectronics + * Copyright (c) 2023 PHYTEC Messtechnik GmbH + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include +#include + +#include + +#include "lps28dfw_reg.h" + +#ifndef ZEPHYR_DRIVERS_SENSOR_LPS28DFW_LPS28DFW_H_ +#define ZEPHYR_DRIVERS_SENSOR_LPS28DFW_LPS28DFW_H_ + +extern const struct lps2xdf_chip_api st_lps28dfw_chip_api; + +int st_lps28dfw_init(const struct device *dev); + +#endif /* ZEPHYR_DRIVERS_SENSOR_LPS28DFW_H_ */ diff --git a/drivers/sensor/lps2xdf/lps2xdf.c b/drivers/sensor/lps2xdf/lps2xdf.c new file mode 100644 index 00000000000..33d909dfbf6 --- /dev/null +++ b/drivers/sensor/lps2xdf/lps2xdf.c @@ -0,0 +1,223 @@ +/* ST Microelectronics LPS2XDF pressure and temperature sensor + * + * Copyright (c) 2023 STMicroelectronics + * Copyright (c) 2023 PHYTEC Messtechnik GmbH + * + * SPDX-License-Identifier: Apache-2.0 + * + * Datasheet: + * https://www.st.com/resource/en/datasheet/lps22df.pdf + * https://www.st.com/resource/en/datasheet/lps28df.pdf + */ + +#include +#include +#include +#include +#include +#include +#include + +#include "lps2xdf.h" + +#if DT_HAS_COMPAT_STATUS_OKAY(st_lps22df) +#include "lps22df.h" +#endif + +#if DT_HAS_COMPAT_STATUS_OKAY(st_lps28dfw) +#include "lps28dfw.h" +#endif + +LOG_MODULE_REGISTER(LPS2XDF, CONFIG_SENSOR_LOG_LEVEL); + +static const uint16_t lps2xdf_map[] = {0, 1, 4, 10, 25, 50, 75, 100, 200}; + +static int lps2xdf_odr_set(const struct device *dev, uint16_t freq) +{ + int odr; + const struct lps2xdf_config *const cfg = dev->config; + const struct lps2xdf_chip_api *chip_api = cfg->chip_api; + + for (odr = 0; odr < ARRAY_SIZE(lps2xdf_map); odr++) { + if (freq == lps2xdf_map[odr]) { + break; + } + } + + if (odr == ARRAY_SIZE(lps2xdf_map)) { + LOG_DBG("bad frequency"); + return -EINVAL; + } + + if (chip_api->mode_set_odr_raw(dev, odr)) { + LOG_DBG("failed to set sampling rate"); + return -EIO; + } + + return 0; +} + +static int lps2xdf_attr_set(const struct device *dev, enum sensor_channel chan, + enum sensor_attribute attr, const struct sensor_value *val) +{ + if (chan != SENSOR_CHAN_ALL) { + LOG_WRN("attr_set() not supported on this channel."); + return -ENOTSUP; + } + + switch (attr) { + case SENSOR_ATTR_SAMPLING_FREQUENCY: + return lps2xdf_odr_set(dev, val->val1); + default: + LOG_DBG("operation not supported."); + return -ENOTSUP; + } + + return 0; +} + +static inline void lps2xdf_press_convert(const struct device *dev, + struct sensor_value *val, + int32_t raw_val) +{ + const struct lps2xdf_config *const cfg = dev->config; + int32_t press_tmp = raw_val >> 8; /* raw value is left aligned (24 msb) */ + int divider; + + /* Pressure sensitivity is: + * - 4096 LSB/hPa for Full-Scale of 260 - 1260 hPa: + * - 2048 LSB/hPa for Full-Scale of 260 - 4060 hPa: + * Also convert hPa into kPa + */ + if (cfg->fs == 0) { + divider = 40960; + } else { + divider = 20480; + } + val->val1 = press_tmp / divider; + + /* For the decimal part use (3125 / 128) as a factor instead of + * (1000000 / 40960) to avoid int32 overflow + */ + val->val2 = (press_tmp % divider) * 3125 / 128; +} + + +static inline void lps2xdf_temp_convert(struct sensor_value *val, int16_t raw_val) +{ + /* Temperature sensitivity is 100 LSB/deg C */ + val->val1 = raw_val / 100; + val->val2 = ((int32_t)raw_val % 100) * 10000; +} + +static int lps2xdf_channel_get(const struct device *dev, enum sensor_channel chan, + struct sensor_value *val) +{ + struct lps2xdf_data *data = dev->data; + + if (chan == SENSOR_CHAN_PRESS) { + lps2xdf_press_convert(dev, val, data->sample_press); + } else if (chan == SENSOR_CHAN_AMBIENT_TEMP) { + lps2xdf_temp_convert(val, data->sample_temp); + } else { + return -ENOTSUP; + } + + return 0; +} + +static int lps2xdf_sample_fetch(const struct device *dev, enum sensor_channel chan) +{ + const struct lps2xdf_config *const cfg = dev->config; + const struct lps2xdf_chip_api *chip_api = cfg->chip_api; + + __ASSERT_NO_MSG(chan == SENSOR_CHAN_ALL); + + return chip_api->sample_fetch(dev, chan); +} + +static const struct sensor_driver_api lps2xdf_driver_api = { + .attr_set = lps2xdf_attr_set, + .sample_fetch = lps2xdf_sample_fetch, + .channel_get = lps2xdf_channel_get, +#if CONFIG_LPS2XDF_TRIGGER + .trigger_set = lps2xdf_trigger_set, +#endif +}; + +#ifdef CONFIG_LPS2XDF_TRIGGER +#define LPS2XDF_CFG_IRQ(inst) \ + .trig_enabled = true, \ + .gpio_int = GPIO_DT_SPEC_INST_GET(inst, drdy_gpios), \ + .drdy_pulsed = DT_INST_PROP(inst, drdy_pulsed) +#else +#define LPS2XDF_CFG_IRQ(inst) +#endif /* CONFIG_LPS2XDF_TRIGGER */ + +#define LPS2XDF_CONFIG_COMMON(inst, name) \ + .odr = DT_INST_PROP(inst, odr), \ + .lpf = DT_INST_PROP(inst, lpf), \ + .avg = DT_INST_PROP(inst, avg), \ + .chip_api = &name##_chip_api, \ + IF_ENABLED(DT_NODE_HAS_COMPAT(DT_DRV_INST(inst), st_lps28dfw), \ + (.fs = DT_INST_PROP(inst, fs),)) \ + IF_ENABLED(DT_INST_NODE_HAS_PROP(inst, drdy_gpios), \ + (LPS2XDF_CFG_IRQ(inst))) + +#define LPS2XDF_SPI_OPERATION (SPI_WORD_SET(8) | SPI_OP_MODE_MASTER | \ + SPI_MODE_CPOL | SPI_MODE_CPHA) + +#define LPS2XDF_CONFIG_SPI(inst, name) \ +{ \ + STMEMSC_CTX_SPI(&lps2xdf_config_##name##_##inst.stmemsc_cfg), \ + .stmemsc_cfg = { \ + .spi = SPI_DT_SPEC_INST_GET(inst, LPS2XDF_SPI_OPERATION, 0), \ + }, \ + LPS2XDF_CONFIG_COMMON(inst, name) \ +} + +#define LPS2XDF_CONFIG_I2C(inst, name) \ +{ \ + STMEMSC_CTX_I2C(&lps2xdf_config_##name##_##inst.stmemsc_cfg), \ + .stmemsc_cfg = { \ + .i2c = I2C_DT_SPEC_INST_GET(inst), \ + }, \ + LPS2XDF_CONFIG_COMMON(inst, name) \ +} + +#define LPS2XDF_CONFIG_I3C(inst, name) \ +{ \ + STMEMSC_CTX_I3C(&lps2xdf_config_##name##_##inst.stmemsc_cfg), \ + .stmemsc_cfg = { \ + .i3c = &lps2xdf_data_##name##_##inst.i3c_dev, \ + }, \ + .i3c.bus = DEVICE_DT_GET(DT_INST_BUS(inst)), \ + .i3c.dev_id = I3C_DEVICE_ID_DT_INST(inst), \ + LPS2XDF_CONFIG_COMMON(inst, name) \ +} + +#define LPS2XDF_CONFIG_I3C_OR_I2C(inst, name) \ + COND_CODE_0(DT_INST_PROP_BY_IDX(inst, reg, 1), \ + (LPS2XDF_CONFIG_I2C(inst, name)), \ + (LPS2XDF_CONFIG_I3C(inst, name))) + +#define LPS2XDF_DEFINE(inst, name) \ + static struct lps2xdf_data lps2xdf_data_##name##_##inst; \ + static const struct lps2xdf_config lps2xdf_config_##name##_##inst = COND_CODE_1( \ + DT_INST_ON_BUS(inst, spi), \ + (LPS2XDF_CONFIG_SPI(inst, name)), \ + (COND_CODE_1(DT_INST_ON_BUS(inst, i3c), \ + (LPS2XDF_CONFIG_I3C_OR_I2C(inst, name)), \ + (LPS2XDF_CONFIG_I2C(inst, name))))); \ + \ + SENSOR_DEVICE_DT_INST_DEFINE(inst, name##_init, NULL, &lps2xdf_data_##name##_##inst, \ + &lps2xdf_config_##name##_##inst, POST_KERNEL, \ + CONFIG_SENSOR_INIT_PRIORITY, &lps2xdf_driver_api); + +#define DT_DRV_COMPAT st_lps22df +DT_INST_FOREACH_STATUS_OKAY_VARGS(LPS2XDF_DEFINE, DT_DRV_COMPAT) +#undef DT_DRV_COMPAT + +#define DT_DRV_COMPAT st_lps28dfw +DT_INST_FOREACH_STATUS_OKAY_VARGS(LPS2XDF_DEFINE, DT_DRV_COMPAT) +#undef DT_DRV_COMPAT diff --git a/drivers/sensor/lps2xdf/lps2xdf.h b/drivers/sensor/lps2xdf/lps2xdf.h new file mode 100644 index 00000000000..10a38a5a133 --- /dev/null +++ b/drivers/sensor/lps2xdf/lps2xdf.h @@ -0,0 +1,136 @@ +/* ST Microelectronics LPS2XDF pressure and temperature sensor + * + * Copyright (c) 2023 STMicroelectronics + * Copyright (c) 2023 PHYTEC Messtechnik GmbH + * + * SPDX-License-Identifier: Apache-2.0 + * + * Datasheets: + * https://www.st.com/resource/en/datasheet/lps22df.pdf + * https://www.st.com/resource/en/datasheet/lps28dfw.pdf + */ + +#ifndef ZEPHYR_DRIVERS_SENSOR_LPS2XDF_LPS2XDF_H_ +#define ZEPHYR_DRIVERS_SENSOR_LPS2XDF_LPS2XDF_H_ + +#include +#include + +#if DT_HAS_COMPAT_STATUS_OKAY(st_lps28dfw) +#include "lps28dfw_reg.h" +#endif + +#if DT_HAS_COMPAT_STATUS_OKAY(st_lps22df) +#include "lps22df_reg.h" +#endif + +#include +#include +#include +#include + +#define LPS2XDF_SWRESET_WAIT_TIME_US 50 + +#if (DT_HAS_COMPAT_ON_BUS_STATUS_OKAY(st_lps22df, i3c) || \ + DT_HAS_COMPAT_ON_BUS_STATUS_OKAY(st_lps28dfw, i3c)) + #define ON_I3C_BUS(cfg) (cfg->i3c.bus != NULL) +#else + #define ON_I3C_BUS(cfg) (false) +#endif + +typedef int32_t (*api_lps2xdf_mode_set_odr_raw)(const struct device *dev, uint8_t odr); +typedef int32_t (*api_lps2xdf_sample_fetch)(const struct device *dev, enum sensor_channel chan); +typedef void (*api_lps2xdf_handle_interrupt)(const struct device *dev); +#ifdef CONFIG_LPS2XDF_TRIGGER +typedef int (*api_lps2xdf_trigger_set)(const struct device *dev, + const struct sensor_trigger *trig, + sensor_trigger_handler_t handler); +#endif + +struct lps2xdf_chip_api { + api_lps2xdf_mode_set_odr_raw mode_set_odr_raw; + api_lps2xdf_sample_fetch sample_fetch; + api_lps2xdf_handle_interrupt handle_interrupt; +#ifdef CONFIG_LPS2XDF_TRIGGER + api_lps2xdf_trigger_set trigger_set; +#endif +}; + + +enum sensor_variant { + DEVICE_VARIANT_LPS22DF = 0, + DEVICE_VARIANT_LPS28DFW = 1, +}; + + +struct lps2xdf_config { + stmdev_ctx_t ctx; + union { +#if (DT_HAS_COMPAT_ON_BUS_STATUS_OKAY(st_lps22df, i2c) || \ + DT_HAS_COMPAT_ON_BUS_STATUS_OKAY(st_lps28dfw, i2c)) + const struct i2c_dt_spec i2c; +#endif +#if DT_HAS_COMPAT_ON_BUS_STATUS_OKAY(st_lps22df, spi) + const struct spi_dt_spec spi; +#endif +#if (DT_HAS_COMPAT_ON_BUS_STATUS_OKAY(st_lps22df, i3c) || \ + DT_HAS_COMPAT_ON_BUS_STATUS_OKAY(st_lps28dfw, i3c)) + struct i3c_device_desc **i3c; +#endif + } stmemsc_cfg; + uint8_t odr; + uint8_t lpf; + uint8_t avg; + uint8_t drdy_pulsed; + bool fs; +#ifdef CONFIG_LPS2XDF_TRIGGER + struct gpio_dt_spec gpio_int; + bool trig_enabled; +#endif + +#if (DT_HAS_COMPAT_ON_BUS_STATUS_OKAY(st_lps22df, i3c) || \ + DT_HAS_COMPAT_ON_BUS_STATUS_OKAY(st_lps28dfw, i3c)) + struct { + const struct device *bus; + const struct i3c_device_id dev_id; + } i3c; +#endif + const struct lps2xdf_chip_api *chip_api; +}; + +struct lps2xdf_data { + int32_t sample_press; + int16_t sample_temp; + +#ifdef CONFIG_LPS2XDF_TRIGGER + struct gpio_callback gpio_cb; + + const struct sensor_trigger *data_ready_trigger; + sensor_trigger_handler_t handler_drdy; + const struct device *dev; + +#if defined(CONFIG_LPS2XDF_TRIGGER_OWN_THREAD) + K_KERNEL_STACK_MEMBER(thread_stack, CONFIG_LPS2XDF_THREAD_STACK_SIZE); + struct k_thread thread; + struct k_sem intr_sem; +#elif defined(CONFIG_LPS2XDF_TRIGGER_GLOBAL_THREAD) + struct k_work work; +#endif + +#endif /* CONFIG_LPS2XDF_TRIGGER */ + +#if (DT_HAS_COMPAT_ON_BUS_STATUS_OKAY(st_lps22df, i3c) || \ + DT_HAS_COMPAT_ON_BUS_STATUS_OKAY(st_lps28dfw, i3c)) + struct i3c_device_desc *i3c_dev; +#endif +}; + +#ifdef CONFIG_LPS2XDF_TRIGGER +int lps2xdf_trigger_set(const struct device *dev, + const struct sensor_trigger *trig, + sensor_trigger_handler_t handler); + +int lps2xdf_init_interrupt(const struct device *dev, enum sensor_variant variant); +#endif + +#endif /* ZEPHYR_DRIVERS_SENSOR_LPS2XDF_H_ */ diff --git a/drivers/sensor/lps2xdf/lps2xdf_trigger.c b/drivers/sensor/lps2xdf/lps2xdf_trigger.c new file mode 100644 index 00000000000..2c3aa76124b --- /dev/null +++ b/drivers/sensor/lps2xdf/lps2xdf_trigger.c @@ -0,0 +1,206 @@ +/* ST Microelectronics LPS2XDF pressure and temperature sensor + * + * Copyright (c) 2023 STMicroelectronics + * Copyright (c) 2023 PHYTEC Messtechnik GmbH + * + * SPDX-License-Identifier: Apache-2.0 + * + * Datasheet: + * https://www.st.com/resource/en/datasheet/lps22df.pdf + * https://www.st.com/resource/en/datasheet/lps28dfw.pdf + */ + +#include +#include +#include +#include + +#include "lps2xdf.h" + +#if DT_HAS_COMPAT_STATUS_OKAY(st_lps22df) +#include "lps22df.h" +#endif + +#if DT_HAS_COMPAT_STATUS_OKAY(st_lps28dfw) +#include "lps28dfw.h" +#endif + +LOG_MODULE_DECLARE(LPS2XDF, CONFIG_SENSOR_LOG_LEVEL); + +int lps2xdf_trigger_set(const struct device *dev, + const struct sensor_trigger *trig, + sensor_trigger_handler_t handler) +{ + const struct lps2xdf_config *const cfg = dev->config; + const struct lps2xdf_chip_api *chip_api = cfg->chip_api; + + return chip_api->trigger_set(dev, trig, handler); +} + +static void lps2xdf_intr_callback(struct lps2xdf_data *lps2xdf) +{ +#if defined(CONFIG_LPS2XDF_TRIGGER_OWN_THREAD) + k_sem_give(&lps2xdf->intr_sem); +#elif defined(CONFIG_LPS2XDF_TRIGGER_GLOBAL_THREAD) + k_work_submit(&lps2xdf->work); +#endif /* CONFIG_LPS2XDF_TRIGGER_OWN_THREAD */ +} + +static void lps2xdf_gpio_callback(const struct device *dev, + struct gpio_callback *cb, uint32_t pins) +{ + struct lps2xdf_data *lps2xdf = + CONTAINER_OF(cb, struct lps2xdf_data, gpio_cb); + + ARG_UNUSED(pins); + const struct lps2xdf_config *cfg = lps2xdf->dev->config; + int ret; + + ret = gpio_pin_interrupt_configure_dt(&cfg->gpio_int, GPIO_INT_DISABLE); + if (ret < 0) { + LOG_ERR("%s: Not able to configure pin_int", dev->name); + } + + lps2xdf_intr_callback(lps2xdf); +} + +#ifdef CONFIG_LPS2XDF_TRIGGER_OWN_THREAD +static void lps2xdf_thread(struct lps2xdf_data *lps2xdf) +{ + const struct device *dev = lps2xdf->dev; + const struct lps2xdf_config *const cfg = dev->config; + const struct lps2xdf_chip_api *chip_api = cfg->chip_api; + + while (1) { + k_sem_take(&lps2xdf->intr_sem, K_FOREVER); + chip_api->handle_interrupt(dev); + } +} +#endif /* CONFIG_LPS2XDF_TRIGGER_OWN_THREAD */ + +#ifdef CONFIG_LPS2XDF_TRIGGER_GLOBAL_THREAD +static void lps2xdf_work_cb(struct k_work *work) +{ + struct lps2xdf_data *lps2xdf = + CONTAINER_OF(work, struct lps2xdf_data, work); + const struct device *dev = lps2xdf->dev; + const struct lps2xdf_config *const cfg = dev->config; + const struct lps2xdf_chip_api *chip_api = cfg->chip_api; + + chip_api->handle_interrupt(dev); +} +#endif /* CONFIG_LPS2XDF_TRIGGER_GLOBAL_THREAD */ + +#if (DT_HAS_COMPAT_ON_BUS_STATUS_OKAY(st_lps22df, i3c) ||\ + DT_HAS_COMPAT_ON_BUS_STATUS_OKAY(st_lps28dfw, i3c)) +static int lps2xdf_ibi_cb(struct i3c_device_desc *target, + struct i3c_ibi_payload *payload) +{ + const struct device *dev = target->dev; + struct lps2xdf_data *lps2xdf = dev->data; + + ARG_UNUSED(payload); + + lps2xdf_intr_callback(lps2xdf); + + return 0; +} +#endif + +int lps2xdf_init_interrupt(const struct device *dev, enum sensor_variant variant) +{ + struct lps2xdf_data *lps2xdf = dev->data; + const struct lps2xdf_config *cfg = dev->config; + stmdev_ctx_t *ctx = (stmdev_ctx_t *)&cfg->ctx; + int ret; + + /* setup data ready gpio interrupt */ + if (!gpio_is_ready_dt(&cfg->gpio_int) && !ON_I3C_BUS(cfg)) { + if (cfg->gpio_int.port) { + LOG_ERR("%s: device %s is not ready", dev->name, + cfg->gpio_int.port->name); + return -ENODEV; + } + + LOG_DBG("%s: gpio_int not defined in DT", dev->name); + return 0; + } + + lps2xdf->dev = dev; + +#if defined(CONFIG_LPS2XDF_TRIGGER_OWN_THREAD) + k_sem_init(&lps2xdf->intr_sem, 0, K_SEM_MAX_LIMIT); + + k_thread_create(&lps2xdf->thread, lps2xdf->thread_stack, + CONFIG_LPS2XDF_THREAD_STACK_SIZE, + (k_thread_entry_t)lps2xdf_thread, lps2xdf, + NULL, NULL, K_PRIO_COOP(CONFIG_LPS2XDF_THREAD_PRIORITY), + 0, K_NO_WAIT); +#elif defined(CONFIG_LPS2XDF_TRIGGER_GLOBAL_THREAD) + lps2xdf->work.handler = lps2xdf_work_cb; +#endif /* CONFIG_LPS2XDF_TRIGGER_OWN_THREAD */ + + if (!ON_I3C_BUS(cfg)) { + ret = gpio_pin_configure_dt(&cfg->gpio_int, GPIO_INPUT); + if (ret < 0) { + LOG_ERR("Could not configure gpio"); + return ret; + } + + LOG_INF("%s: int on %s.%02u", dev->name, cfg->gpio_int.port->name, + cfg->gpio_int.pin); + + gpio_init_callback(&lps2xdf->gpio_cb, + lps2xdf_gpio_callback, + BIT(cfg->gpio_int.pin)); + + ret = gpio_add_callback(cfg->gpio_int.port, &lps2xdf->gpio_cb); + if (ret < 0) { + LOG_ERR("Could not set gpio callback"); + return ret; + } + } + + LOG_DBG("drdy_pulsed is %d", (int)cfg->drdy_pulsed); + + /* enable drdy in pulsed/latched mode */ + if (variant == DEVICE_VARIANT_LPS22DF) { +#if DT_HAS_COMPAT_STATUS_OKAY(st_lps22df) + lps22df_int_mode_t mode; + + mode.drdy_latched = ~cfg->drdy_pulsed; + if (lps22df_interrupt_mode_set(ctx, &mode) < 0) { + return -EIO; + } +#endif + } else if (variant == DEVICE_VARIANT_LPS28DFW) { +#if DT_HAS_COMPAT_STATUS_OKAY(st_lps28dfw) + lps28dfw_int_mode_t mode; + + mode.drdy_latched = ~cfg->drdy_pulsed; + if (lps28dfw_interrupt_mode_set(ctx, &mode) < 0) { + return -EIO; + } +#endif + } else { + return -ENOTSUP; + } + +#if (DT_HAS_COMPAT_ON_BUS_STATUS_OKAY(st_lps22df, i3c) ||\ + DT_HAS_COMPAT_ON_BUS_STATUS_OKAY(st_lps28dfw, i3c)) + if (cfg->i3c.bus == NULL) { + /* I3C IBI does not utilize GPIO interrupt. */ + lps2xdf->i3c_dev->ibi_cb = lps2xdf_ibi_cb; + + if (i3c_ibi_enable(lps2xdf->i3c_dev) != 0) { + LOG_DBG("Could not enable I3C IBI"); + return -EIO; + } + + return 0; + } +#endif + + return gpio_pin_interrupt_configure_dt(&cfg->gpio_int, + GPIO_INT_EDGE_TO_ACTIVE); +} diff --git a/dts/bindings/sensor/st,lps28dfw-common.yaml b/dts/bindings/sensor/st,lps28dfw-common.yaml new file mode 100644 index 00000000000..cf33148390a --- /dev/null +++ b/dts/bindings/sensor/st,lps28dfw-common.yaml @@ -0,0 +1,23 @@ +# Copyright (c) 2023 STMicroelectronics +# Copyright (c) 2023 PHYTEC Messtechnik GmbH +# SPDX-License-Identifier: Apache-2.0 + +description: | + STMicroelectronics LPS28DFW pressure and temperature sensor. This is an + extension of st,lps22df driver binding. + +include: st,lps22df-common.yaml + +properties: + fs: + type: int + default: 0 + description: | + Specify the full-scale mode. + The default is the power-on reset value. + + 0 = Mode 0, full scale up to 1260 hPa + 1 = Mode 1, full scale up to 4060 hPa + enum: + - 0 + - 1 diff --git a/dts/bindings/sensor/st,lps28dfw-i2c.yaml b/dts/bindings/sensor/st,lps28dfw-i2c.yaml new file mode 100644 index 00000000000..0c47d7b27f6 --- /dev/null +++ b/dts/bindings/sensor/st,lps28dfw-i2c.yaml @@ -0,0 +1,11 @@ +# Copyright (c) 2023 STMicroelectronics +# Copyright (c) 2023 PHYTEC Messtechnik GmbH +# SPDX-License-Identifier: Apache-2.0 + +description: | + STMicroelectronics LPS28DFW pressure and temperature sensor connected to + I2C bus + +compatible: "st,lps28dfw" + +include: ["i2c-device.yaml", "st,lps28dfw-common.yaml"] diff --git a/dts/bindings/sensor/st,lps28dfw-i3c.yaml b/dts/bindings/sensor/st,lps28dfw-i3c.yaml new file mode 100644 index 00000000000..8c3fdb1946d --- /dev/null +++ b/dts/bindings/sensor/st,lps28dfw-i3c.yaml @@ -0,0 +1,11 @@ +# Copyright (c) 2023 STMicroelectronics +# Copyright (c) 2023 PHYTEC Messtechnik GmbH +# SPDX-License-Identifier: Apache-2.0 + +description: | + STMicroelectronics LPS28DFW pressure and temperature sensor connected to + I3C bus + +compatible: "st,lps28dfw" + +include: ["i3c-device.yaml", "st,lps28dfw-common.yaml"] diff --git a/modules/Kconfig.st b/modules/Kconfig.st index fd90aee0b17..371f1063349 100644 --- a/modules/Kconfig.st +++ b/modules/Kconfig.st @@ -130,6 +130,9 @@ config USE_STDC_LPS25HB config USE_STDC_LPS27HHW bool +config USE_STDC_LPS28DFW + bool + config USE_STDC_LPS33HW bool diff --git a/samples/boards/sensortile_box_pro/sensors-on-board/prj.conf b/samples/boards/sensortile_box_pro/sensors-on-board/prj.conf index a7c57f2f746..a618f6ebece 100644 --- a/samples/boards/sensortile_box_pro/sensors-on-board/prj.conf +++ b/samples/boards/sensortile_box_pro/sensors-on-board/prj.conf @@ -8,7 +8,7 @@ CONFIG_GPIO=y CONFIG_SENSOR=y CONFIG_SENSOR_LOG_LEVEL_DBG=y CONFIG_HTS221_TRIGGER_NONE=y -CONFIG_LPS22DF_TRIGGER_OWN_THREAD=y +CONFIG_LPS2XDF_TRIGGER_OWN_THREAD=y CONFIG_LSM6DSV16X_TRIGGER_OWN_THREAD=y CONFIG_LIS2MDL_TRIGGER_OWN_THREAD=y diff --git a/samples/boards/sensortile_box_pro/sensors-on-board/src/main.c b/samples/boards/sensortile_box_pro/sensors-on-board/src/main.c index 7aab1f36b13..80c44f7ff0c 100644 --- a/samples/boards/sensortile_box_pro/sensors-on-board/src/main.c +++ b/samples/boards/sensortile_box_pro/sensors-on-board/src/main.c @@ -15,7 +15,7 @@ #include -#ifdef CONFIG_LPS22DF_TRIGGER +#ifdef CONFIG_LPS2XDF_TRIGGER static int lps22df_trig_cnt; static void lps22df_trigger_handler(const struct device *dev, @@ -78,7 +78,7 @@ static void lps22df_config(const struct device *lps22df) return; } -#ifdef CONFIG_LPS22DF_TRIGGER +#ifdef CONFIG_LPS2XDF_TRIGGER struct sensor_trigger trig; trig.type = SENSOR_TRIG_DATA_READY; @@ -278,7 +278,7 @@ int main(void) } #endif -#ifndef CONFIG_LPS22DF_TRIGGER +#ifndef CONFIG_LPS2XDF_TRIGGER if (sensor_sample_fetch(lps22df) < 0) { printf("LPS22DF Sensor sample update error\n"); return 0; @@ -343,7 +343,7 @@ int main(void) printf("LIS2MDL: Temperature: %.1f C\n", sensor_value_to_double(&lis2mdl_temp)); -#ifdef CONFIG_LPS22DF_TRIGGER +#ifdef CONFIG_LPS2XDF_TRIGGER printk("%d:: lps22df trig %d\n", cnt, lps22df_trig_cnt); #endif diff --git a/tests/drivers/build_all/sensor/i2c.dtsi b/tests/drivers/build_all/sensor/i2c.dtsi index 4e79590ce99..23abb1a47a4 100644 --- a/tests/drivers/build_all/sensor/i2c.dtsi +++ b/tests/drivers/build_all/sensor/i2c.dtsi @@ -10,7 +10,7 @@ #include #include #include -#include +#include #include #include #include @@ -849,12 +849,23 @@ test_i2c_lps22df: lps22df@79 { reg = <0x79>; drdy-gpios = <&test_gpio 0 0>; status = "okay"; - odr = ; - lpf = ; - avg = ; + odr = ; + lpf = ; + avg = ; }; test_i2c_hs300x: hs300x@7a { compatible = "renesas,hs300x"; reg = <0x7a>; }; + +test_i2c_lps28dfw: lps28dfw@7b { + compatible = "st,lps28dfw"; + reg = <0x7b>; + drdy-gpios = <&test_gpio 0 0>; + status = "okay"; + odr = ; + lpf = ; + avg = ; + fs = ; +}; diff --git a/tests/drivers/build_all/sensor/i3c.dtsi b/tests/drivers/build_all/sensor/i3c.dtsi index 42adb3fb175..4e44a80fb37 100644 --- a/tests/drivers/build_all/sensor/i3c.dtsi +++ b/tests/drivers/build_all/sensor/i3c.dtsi @@ -23,3 +23,10 @@ test_i3c_lps22df: lps22df@200000803E0000002 { assigned-address = <0x2>; drdy-gpios = <&test_gpio 0 0>; }; + +test_i3c_lps28dfw: lps28dfw@200000803E0000003 { + compatible = "st,lps28dfw"; + reg = <0x3 0x00000803 0xE0000003>; + assigned-address = <0x3>; + drdy-gpios = <&test_gpio 0 0>; +}; diff --git a/tests/drivers/build_all/sensor/sensors_trigger_global.conf b/tests/drivers/build_all/sensor/sensors_trigger_global.conf index c42b4fa951e..197f61bd74d 100644 --- a/tests/drivers/build_all/sensor/sensors_trigger_global.conf +++ b/tests/drivers/build_all/sensor/sensors_trigger_global.conf @@ -36,7 +36,7 @@ CONFIG_LIS2DS12_TRIGGER_GLOBAL_THREAD=y CONFIG_LIS2DW12_TRIGGER_GLOBAL_THREAD=y CONFIG_LIS2MDL_TRIGGER_GLOBAL_THREAD=y CONFIG_LIS3MDL_TRIGGER_GLOBAL_THREAD=y -CONFIG_LPS22DF_TRIGGER_GLOBAL_THREAD=y +CONFIG_LPS2XDF_TRIGGER_GLOBAL_THREAD=y CONFIG_LPS22HH_TRIGGER_GLOBAL_THREAD=y CONFIG_LSM6DSL_TRIGGER_GLOBAL_THREAD=y CONFIG_LSM6DSO_TRIGGER_GLOBAL_THREAD=y diff --git a/tests/drivers/build_all/sensor/sensors_trigger_none.conf b/tests/drivers/build_all/sensor/sensors_trigger_none.conf index 9c46cb3637e..cd9dfac3915 100644 --- a/tests/drivers/build_all/sensor/sensors_trigger_none.conf +++ b/tests/drivers/build_all/sensor/sensors_trigger_none.conf @@ -36,7 +36,7 @@ CONFIG_LIS2DS12_TRIGGER_NONE=y CONFIG_LIS2DW12_TRIGGER_NONE=y CONFIG_LIS2MDL_TRIGGER_NONE=y CONFIG_LIS3MDL_TRIGGER_NONE=y -CONFIG_LPS22DF_TRIGGER_NONE=y +CONFIG_LPS2XDF_TRIGGER_NONE=y CONFIG_LPS22HH_TRIGGER_NONE=y CONFIG_LSM6DSL_TRIGGER_NONE=y CONFIG_LSM6DSO_TRIGGER_NONE=y diff --git a/tests/drivers/build_all/sensor/sensors_trigger_own.conf b/tests/drivers/build_all/sensor/sensors_trigger_own.conf index 5ecacb03d9a..05ed9500fe3 100644 --- a/tests/drivers/build_all/sensor/sensors_trigger_own.conf +++ b/tests/drivers/build_all/sensor/sensors_trigger_own.conf @@ -34,7 +34,7 @@ CONFIG_LIS2DS12_TRIGGER_OWN_THREAD=y CONFIG_LIS2DW12_TRIGGER_OWN_THREAD=y CONFIG_LIS2MDL_TRIGGER_OWN_THREAD=y CONFIG_LIS3MDL_TRIGGER_OWN_THREAD=y -CONFIG_LPS22DF_TRIGGER_OWN_THREAD=y +CONFIG_LPS2XDF_TRIGGER_OWN_THREAD=y CONFIG_LPS22HH_TRIGGER_OWN_THREAD=y CONFIG_LSM6DSL_TRIGGER_OWN_THREAD=y CONFIG_LSM6DSO_TRIGGER_OWN_THREAD=y From a004cb4b7536b99d134dc4355642fd1335633e50 Mon Sep 17 00:00:00 2001 From: Jonas Remmert Date: Wed, 22 Nov 2023 14:45:34 +0100 Subject: [PATCH 0622/3723] dt-bindings: sensor: lps2xdf: make macros sensor agnostic The possible settings for the lps22df and lps28dfw sensor are overlapping, except the Full-Scale mode setting. Threrefore we can change the macros from LPS22DF_DT_[..] to LPS2xDF_DT_[..]. Signed-off-by: Jonas Remmert --- dts/bindings/sensor/st,lps22df-common.yaml | 47 +++++++++++---------- dts/bindings/sensor/st,lps28dfw-common.yaml | 19 ++++++--- include/zephyr/dt-bindings/sensor/lps22df.h | 35 --------------- include/zephyr/dt-bindings/sensor/lps2xdf.h | 40 ++++++++++++++++++ 4 files changed, 78 insertions(+), 63 deletions(-) delete mode 100644 include/zephyr/dt-bindings/sensor/lps22df.h create mode 100644 include/zephyr/dt-bindings/sensor/lps2xdf.h diff --git a/dts/bindings/sensor/st,lps22df-common.yaml b/dts/bindings/sensor/st,lps22df-common.yaml index f8b54960648..779d877f901 100644 --- a/dts/bindings/sensor/st,lps22df-common.yaml +++ b/dts/bindings/sensor/st,lps22df-common.yaml @@ -1,4 +1,5 @@ # Copyright (c) 2023 STMicroelectronics +# Copyright (c) 2023 PHYTEC Messtechnik GmbH # SPDX-License-Identifier: Apache-2.0 description: | @@ -11,9 +12,9 @@ description: | lps22df@5d { ... - odr = ; - lpf = ; - avg = ; + odr = ; + lpf = ; + avg = ; }; include: sensor-device.yaml @@ -41,15 +42,15 @@ properties: Specify the output data rate expressed in samples per second (Hz). The default is the power-on reset value. - - 0 # LPS22DF_DT_ODR_POWER_DOWN - - 1 # LPS22DF_DT_ODR_1HZ - - 2 # LPS22DF_DT_ODR_4HZ - - 3 # LPS22DF_DT_ODR_10HZ - - 4 # LPS22DF_DT_ODR_25HZ - - 5 # LPS22DF_DT_ODR_50HZ - - 6 # LPS22DF_DT_ODR_75HZ - - 7 # LPS22DF_DT_ODR_100HZ - - 8 # LPS22DF_DT_ODR_200HZ + - 0 # LPS2xDF_DT_ODR_POWER_DOWN + - 1 # LPS2xDF_DT_ODR_1HZ + - 2 # LPS2xDF_DT_ODR_4HZ + - 3 # LPS2xDF_DT_ODR_10HZ + - 4 # LPS2xDF_DT_ODR_25HZ + - 5 # LPS2xDF_DT_ODR_50HZ + - 6 # LPS2xDF_DT_ODR_75HZ + - 7 # LPS2xDF_DT_ODR_100HZ + - 8 # LPS2xDF_DT_ODR_200HZ enum: [0, 1, 2, 3, 4, 5, 6, 7, 8] @@ -60,9 +61,9 @@ properties: Specify the low pass filter value to be applied to pressure data. The default is the power-on reset value. - - 0 # LPS22DF_DT_LP_FILTER_OFF - - 1 # LPS22DF_DT_LP_FILTER_ODR_4 - - 3 # LPS22DF_DT_LP_FILTER_ODR_9 + - 0 # LPS2xDF_DT_LP_FILTER_OFF + - 1 # LPS2xDF_DT_LP_FILTER_ODR_4 + - 3 # LPS2xDF_DT_LP_FILTER_ODR_9 enum: [0, 1, 3] @@ -74,13 +75,13 @@ properties: to pressure and temperature data. The default is the power-on reset value. - - 0 # LPS22DF_DT_AVG_4_SAMPLES - - 1 # LPS22DF_DT_AVG_8_SAMPLES - - 2 # LPS22DF_DT_AVG_16_SAMPLES - - 3 # LPS22DF_DT_AVG_32_SAMPLES - - 4 # LPS22DF_DT_AVG_64_SAMPLES - - 5 # LPS22DF_DT_AVG_128_SAMPLES - - 6 # LPS22DF_DT_AVG_256_SAMPLES - - 7 # LPS22DF_DT_AVG_512_SAMPLES + - 0 # LPS2xDF_DT_AVG_4_SAMPLES + - 1 # LPS2xDF_DT_AVG_8_SAMPLES + - 2 # LPS2xDF_DT_AVG_16_SAMPLES + - 3 # LPS2xDF_DT_AVG_32_SAMPLES + - 4 # LPS2xDF_DT_AVG_64_SAMPLES + - 5 # LPS2xDF_DT_AVG_128_SAMPLES + - 6 # LPS2xDF_DT_AVG_256_SAMPLES + - 7 # LPS2xDF_DT_AVG_512_SAMPLES enum: [0, 1, 2, 3, 4, 5, 6, 7] diff --git a/dts/bindings/sensor/st,lps28dfw-common.yaml b/dts/bindings/sensor/st,lps28dfw-common.yaml index cf33148390a..1ca646fab66 100644 --- a/dts/bindings/sensor/st,lps28dfw-common.yaml +++ b/dts/bindings/sensor/st,lps28dfw-common.yaml @@ -6,6 +6,17 @@ description: | STMicroelectronics LPS28DFW pressure and temperature sensor. This is an extension of st,lps22df driver binding. + Example: + #include + + lps28dfw@5d { + ... + + odr = ; + lpf = ; + avg = ; + }; + include: st,lps22df-common.yaml properties: @@ -16,8 +27,6 @@ properties: Specify the full-scale mode. The default is the power-on reset value. - 0 = Mode 0, full scale up to 1260 hPa - 1 = Mode 1, full scale up to 4060 hPa - enum: - - 0 - - 1 + - 0 # LPS28DFW_DT_FS_MODE_1_1260 + - 1 # LPS28DFW_DT_FS_MODE_2_4060 + enum: [0, 1] diff --git a/include/zephyr/dt-bindings/sensor/lps22df.h b/include/zephyr/dt-bindings/sensor/lps22df.h deleted file mode 100644 index 95668ae6390..00000000000 --- a/include/zephyr/dt-bindings/sensor/lps22df.h +++ /dev/null @@ -1,35 +0,0 @@ -/* - * Copyright (c) 2023 STMicroelectronics - * - * SPDX-License-Identifier: Apache-2.0 - */ -#ifndef ZEPHYR_INCLUDE_DT_BINDINGS_ST_LPS22DF_H_ -#define ZEPHYR_INCLUDE_DT_BINDINGS_ST_LPS22DF_H_ - -/* Data rate */ -#define LPS22DF_DT_ODR_POWER_DOWN 0 -#define LPS22DF_DT_ODR_1HZ 1 -#define LPS22DF_DT_ODR_4HZ 2 -#define LPS22DF_DT_ODR_10HZ 3 -#define LPS22DF_DT_ODR_25HZ 4 -#define LPS22DF_DT_ODR_50HZ 5 -#define LPS22DF_DT_ODR_75HZ 6 -#define LPS22DF_DT_ODR_100HZ 7 -#define LPS22DF_DT_ODR_200HZ 8 - -/* Low Pass filter */ -#define LPS22DF_DT_LP_FILTER_OFF 0 -#define LPS22DF_DT_LP_FILTER_ODR_4 1 -#define LPS22DF_DT_LP_FILTER_ODR_9 3 - -/* Average (number of samples) filter */ -#define LPS22DF_DT_AVG_4_SAMPLES 0 -#define LPS22DF_DT_AVG_8_SAMPLES 1 -#define LPS22DF_DT_AVG_16_SAMPLES 2 -#define LPS22DF_DT_AVG_32_SAMPLES 3 -#define LPS22DF_DT_AVG_64_SAMPLES 4 -#define LPS22DF_DT_AVG_128_SAMPLES 5 -#define LPS22DF_DT_AVG_256_SAMPLES 6 -#define LPS22DF_DT_AVG_512_SAMPLES 7 - -#endif /* ZEPHYR_INCLUDE_DT_BINDINGS_ST_LPS22DF_H_ */ diff --git a/include/zephyr/dt-bindings/sensor/lps2xdf.h b/include/zephyr/dt-bindings/sensor/lps2xdf.h new file mode 100644 index 00000000000..bcbb831bae5 --- /dev/null +++ b/include/zephyr/dt-bindings/sensor/lps2xdf.h @@ -0,0 +1,40 @@ +/* + * Copyright (c) 2023 STMicroelectronics + * Copyright (c) 2023 PHYTEC Messtechnik GmbH + * + * SPDX-License-Identifier: Apache-2.0 + */ +#ifndef ZEPHYR_INCLUDE_DT_BINDINGS_ST_LPS2xDF_H_ +#define ZEPHYR_INCLUDE_DT_BINDINGS_ST_LPS2xDF_H_ + +/* Data rate */ +#define LPS2xDF_DT_ODR_POWER_DOWN 0 +#define LPS2xDF_DT_ODR_1HZ 1 +#define LPS2xDF_DT_ODR_4HZ 2 +#define LPS2xDF_DT_ODR_10HZ 3 +#define LPS2xDF_DT_ODR_25HZ 4 +#define LPS2xDF_DT_ODR_50HZ 5 +#define LPS2xDF_DT_ODR_75HZ 6 +#define LPS2xDF_DT_ODR_100HZ 7 +#define LPS2xDF_DT_ODR_200HZ 8 + +/* Low Pass filter */ +#define LPS2xDF_DT_LP_FILTER_OFF 0 +#define LPS2xDF_DT_LP_FILTER_ODR_4 1 +#define LPS2xDF_DT_LP_FILTER_ODR_9 3 + +/* Average (number of samples) filter */ +#define LPS2xDF_DT_AVG_4_SAMPLES 0 +#define LPS2xDF_DT_AVG_8_SAMPLES 1 +#define LPS2xDF_DT_AVG_16_SAMPLES 2 +#define LPS2xDF_DT_AVG_32_SAMPLES 3 +#define LPS2xDF_DT_AVG_64_SAMPLES 4 +#define LPS2xDF_DT_AVG_128_SAMPLES 5 +#define LPS2xDF_DT_AVG_256_SAMPLES 6 +#define LPS2xDF_DT_AVG_512_SAMPLES 7 + +/* Full Scale Pressure Mode */ +#define LPS28DFW_DT_FS_MODE_1_1260 0 +#define LPS28DFW_DT_FS_MODE_2_4060 1 + +#endif /* ZEPHYR_INCLUDE_DT_BINDINGS_ST_LPS22DF_H_ */ From b1532ce44914a9c7495d0bd1cdf198ed0e6d1cb8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mart=C3=AD=20Bol=C3=ADvar?= Date: Thu, 30 Nov 2023 15:57:37 -0800 Subject: [PATCH 0623/3723] devicetree: remove label property accessors MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit These were first deprecated in v3.2. We have kept support for them for as long as we can, but now their presence is causing CI failures in some configurations. Specifically, using the deprecated 'label' property is causing a warning which is promoted to an error in some twister runs. This is blocking other forward progress in the devicetree API. I tried to rework the tests to avoid this, but it was too much effort for the time I had to work on the task. Removing the APIs is therefore unfortunately the best way forward to unblocking other work. Re-work the test suite a bit to maintain coverage where we are using the label property to test other macros. Add a migration guide section to help with the transition. Signed-off-by: Martí Bolívar --- doc/releases/migration-guide-3.6.rst | 46 ++++ .../test/vnd,non-deprecated-label.yaml | 14 ++ include/zephyr/devicetree.h | 39 --- include/zephyr/devicetree/gpio.h | 82 ------- include/zephyr/devicetree/spi.h | 54 ----- tests/lib/devicetree/api/app.overlay | 13 +- tests/lib/devicetree/api/src/main.c | 225 +++++------------- 7 files changed, 129 insertions(+), 344 deletions(-) create mode 100644 dts/bindings/test/vnd,non-deprecated-label.yaml diff --git a/doc/releases/migration-guide-3.6.rst b/doc/releases/migration-guide-3.6.rst index 812beba9a70..bb04e864c2b 100644 --- a/doc/releases/migration-guide-3.6.rst +++ b/doc/releases/migration-guide-3.6.rst @@ -66,6 +66,52 @@ Device Drivers and Device Tree (:github:`62994`) +* Various deprecated macros related to the deprecated devicetree label property + were removed. These are listed in the following table. The table also + provides replacements. + + However, if you are still using code like + ``device_get_binding(DT_LABEL(node_id))``, consider replacing it with + something like ``DEVICE_DT_GET(node_id)`` instead. The ``DEVICE_DT_GET()`` + macro avoids run-time string comparisons, and is also safer because it will + fail the build if the device does not exist. + + .. list-table:: + :header-rows: 1 + + * - Removed macro + - Replacement + + * - ``DT_GPIO_LABEL(node_id, gpio_pha)`` + - ``DT_PROP(DT_GPIO_CTLR(node_id, gpio_pha), label)`` + + * - ``DT_GPIO_LABEL_BY_IDX(node_id, gpio_pha, idx)`` + - ``DT_PROP(DT_GPIO_CTLR_BY_IDX(node_id, gpio_pha, idx), label)`` + + * - ``DT_INST_GPIO_LABEL(inst, gpio_pha)`` + - ``DT_PROP(DT_GPIO_CTLR(DT_DRV_INST(inst), gpio_pha), label)`` + + * - ``DT_INST_GPIO_LABEL_BY_IDX(inst, gpio_pha, idx)`` + - ``DT_PROP(DT_GPIO_CTLR_BY_IDX(DT_DRV_INST(inst), gpio_pha, idx), label)`` + + * - ``DT_SPI_DEV_CS_GPIOS_LABEL(spi_dev)`` + - ``DT_PROP(DT_SPI_DEV_CS_GPIOS_CTLR(spi_dev), label)`` + + * - ``DT_INST_SPI_DEV_CS_GPIOS_LABEL(inst)`` + - ``DT_PROP(DT_SPI_DEV_CS_GPIOS_CTLR(DT_DRV_INST(inst)), label)`` + + * - ``DT_LABEL(node_id)`` + - ``DT_PROP(node_id, label)`` + + * - ``DT_BUS_LABEL(node_id)`` + - ``DT_PROP(DT_BUS(node_id), label)`` + + * - ``DT_INST_LABEL(inst)`` + - ``DT_INST_PROP(inst, label)`` + + * - ``DT_INST_BUS_LABEL(inst)`` + - ``DT_PROP(DT_BUS(DT_DRV_INST(inst)), label)`` + Power Management ================ diff --git a/dts/bindings/test/vnd,non-deprecated-label.yaml b/dts/bindings/test/vnd,non-deprecated-label.yaml new file mode 100644 index 00000000000..760b683b470 --- /dev/null +++ b/dts/bindings/test/vnd,non-deprecated-label.yaml @@ -0,0 +1,14 @@ +# Copyright 2023 Ampere Computing +# SPDX-License-Identifier: Apache-2.0 + +description: | + This can be used when we need a label property in tests without risk + of generating deprecation warnings, which are errors in some + configurations. + +compatible: vnd,non-deprecated-label + +properties: + label: + type: string + required: true diff --git a/include/zephyr/devicetree.h b/include/zephyr/devicetree.h index 017bcab442a..397deaa9fab 100644 --- a/include/zephyr/devicetree.h +++ b/include/zephyr/devicetree.h @@ -778,17 +778,6 @@ COND_CODE_1(DT_NODE_HAS_PROP(node_id, prop), \ (DT_PROP(node_id, prop)), (default_value)) -/** - * @deprecated Use DT_PROP(node_id, label) - * @brief Equivalent to DT_PROP(node_id, label) - * - * This is a convenience for the Zephyr device API, which uses label - * properties as device_get_binding() arguments. - * @param node_id node identifier - * @return node's label property value - */ -#define DT_LABEL(node_id) DT_PROP(node_id, label) __DEPRECATED_MACRO - /** * @brief Get a property value's index into its enumeration values * @@ -3260,16 +3249,6 @@ */ #define DT_BUS(node_id) DT_CAT(node_id, _BUS) -/** - * @deprecated If used to obtain a device instance with device_get_binding, - * consider using @c DEVICE_DT_GET(DT_BUS(node)). - * - * @brief Node's bus controller's `label` property - * @param node_id node identifier - * @return the label property of the node's bus controller DT_BUS(node) - */ -#define DT_BUS_LABEL(node_id) DT_PROP(DT_BUS(node_id), label) __DEPRECATED_MACRO - /** * @brief Is a node on a bus of a given type? * @@ -3581,14 +3560,6 @@ #define DT_INST_PROP_LEN_OR(inst, prop, default_value) \ DT_PROP_LEN_OR(DT_DRV_INST(inst), prop, default_value) -/** - * @deprecated Use DT_INST_PROP(inst, label) - * @brief Get a `DT_DRV_COMPAT` instance's `label` property - * @param inst instance number - * @return instance's label property value - */ -#define DT_INST_LABEL(inst) DT_INST_PROP(inst, label) __DEPRECATED_MACRO - /** * @brief Get a `DT_DRV_COMPAT` instance's string property's value as a * token. @@ -3914,16 +3885,6 @@ */ #define DT_INST_BUS(inst) DT_BUS(DT_DRV_INST(inst)) -/** - * @deprecated If used to obtain a device instance with device_get_binding, - * consider using @c DEVICE_DT_GET(DT_INST_BUS(inst)). - * - * @brief Get a `DT_DRV_COMPAT`'s bus node's label property - * @param inst instance number - * @return the label property of the instance's bus controller - */ -#define DT_INST_BUS_LABEL(inst) DT_BUS_LABEL(DT_DRV_INST(inst)) __DEPRECATED_MACRO - /** * @brief Test if a `DT_DRV_COMPAT`'s bus type is a given type * @param inst instance number diff --git a/include/zephyr/devicetree/gpio.h b/include/zephyr/devicetree/gpio.h index 965de6f7149..93426796f89 100644 --- a/include/zephyr/devicetree/gpio.h +++ b/include/zephyr/devicetree/gpio.h @@ -65,60 +65,6 @@ extern "C" { #define DT_GPIO_CTLR(node_id, gpio_pha) \ DT_GPIO_CTLR_BY_IDX(node_id, gpio_pha, 0) -/** - * @deprecated If used to obtain a device instance with device_get_binding, - * consider using @c DEVICE_DT_GET(DT_GPIO_CTLR_BY_IDX(node, gpio_pha, idx)). - * - * @brief Get a label property from a gpio phandle-array property - * at an index - * - * It's an error if the GPIO controller node referenced by the phandle - * in node_id's "gpio_pha" property at index "idx" has no label - * property. - * - * Example devicetree fragment: - * - * gpio1: gpio@... { - * label = "GPIO_1"; - * }; - * - * gpio2: gpio@... { - * label = "GPIO_2"; - * }; - * - * n: node { - * gpios = <&gpio1 10 GPIO_ACTIVE_LOW>, - * <&gpio2 30 GPIO_ACTIVE_HIGH>; - * }; - * - * Example usage: - * - * DT_GPIO_LABEL_BY_IDX(DT_NODELABEL(n), gpios, 1) // "GPIO_2" - * - * @param node_id node identifier - * @param gpio_pha lowercase-and-underscores GPIO property with - * type "phandle-array" - * @param idx logical index into "gpio_pha" - * @return the label property of the node referenced at index "idx" - * @see DT_PHANDLE_BY_IDX() - */ -#define DT_GPIO_LABEL_BY_IDX(node_id, gpio_pha, idx) \ - DT_PROP(DT_GPIO_CTLR_BY_IDX(node_id, gpio_pha, idx), label) __DEPRECATED_MACRO - -/** - * @deprecated If used to obtain a device instance with device_get_binding, - * consider using @c DEVICE_DT_GET(DT_GPIO_CTLR(node, gpio_pha)). - * - * @brief Equivalent to DT_GPIO_LABEL_BY_IDX(node_id, gpio_pha, 0) - * @param node_id node identifier - * @param gpio_pha lowercase-and-underscores GPIO property with - * type "phandle-array" - * @return the label property of the node referenced at index 0 - * @see DT_GPIO_LABEL_BY_IDX() - */ -#define DT_GPIO_LABEL(node_id, gpio_pha) \ - DT_GPIO_LABEL_BY_IDX(node_id, gpio_pha, 0) __DEPRECATED_MACRO - /** * @brief Get a GPIO specifier's pin cell at an index * @@ -362,34 +308,6 @@ extern "C" { COND_CODE_1(IS_ENABLED(DT_CAT4(node_id, _GPIO_HOGS_IDX_, idx, _VAL_flags_EXISTS)), \ (DT_CAT4(node_id, _GPIO_HOGS_IDX_, idx, _VAL_flags)), (0)) -/** - * @deprecated If used to obtain a device instance with device_get_binding, - * consider using @c DEVICE_DT_GET(DT_INST_GPIO_CTLR_BY_IDX(node, gpio_pha, idx)). - * - * @brief Get a label property from a DT_DRV_COMPAT instance's GPIO - * property at an index - * @param inst DT_DRV_COMPAT instance number - * @param gpio_pha lowercase-and-underscores GPIO property with - * type "phandle-array" - * @param idx logical index into "gpio_pha" - * @return the label property of the node referenced at index "idx" - */ -#define DT_INST_GPIO_LABEL_BY_IDX(inst, gpio_pha, idx) \ - DT_GPIO_LABEL_BY_IDX(DT_DRV_INST(inst), gpio_pha, idx) __DEPRECATED_MACRO - -/** - * @deprecated If used to obtain a device instance with device_get_binding, - * consider using @c DEVICE_DT_GET(DT_INST_GPIO_CTLR(node, gpio_pha)). - * - * @brief Equivalent to DT_INST_GPIO_LABEL_BY_IDX(inst, gpio_pha, 0) - * @param inst DT_DRV_COMPAT instance number - * @param gpio_pha lowercase-and-underscores GPIO property with - * type "phandle-array" - * @return the label property of the node referenced at index 0 - */ -#define DT_INST_GPIO_LABEL(inst, gpio_pha) \ - DT_INST_GPIO_LABEL_BY_IDX(inst, gpio_pha, 0) __DEPRECATED_MACRO - /** * @brief Get a DT_DRV_COMPAT instance's GPIO specifier's pin cell value * at an index diff --git a/include/zephyr/devicetree/spi.h b/include/zephyr/devicetree/spi.h index e7994982a7e..d1f916c3df9 100644 --- a/include/zephyr/devicetree/spi.h +++ b/include/zephyr/devicetree/spi.h @@ -150,47 +150,6 @@ extern "C" { #define DT_SPI_DEV_CS_GPIOS_CTLR(spi_dev) \ DT_GPIO_CTLR_BY_IDX(DT_BUS(spi_dev), cs_gpios, DT_REG_ADDR(spi_dev)) -/** - * @deprecated If used to obtain a device instance with device_get_binding, - * consider using @c DEVICE_DT_GET(DT_SPI_DEV_CS_GPIOS_CTLR(node)). - * - * @brief Get a SPI device's chip select GPIO controller's label property - * - * Example devicetree fragment: - * - * gpio1: gpio@... { - * label = "GPIO_1"; - * }; - * - * gpio2: gpio@... { - * label = "GPIO_2"; - * }; - * - * spi1: spi@... { - * compatible = "vnd,spi"; - * cs-gpios = <&gpio1 10 GPIO_ACTIVE_LOW>, - * <&gpio2 20 GPIO_ACTIVE_LOW>; - * - * a: spi-dev-a@0 { - * reg = <0>; - * }; - * - * b: spi-dev-b@1 { - * reg = <1>; - * }; - * }; - * - * Example usage: - * - * DT_SPI_DEV_CS_GPIOS_LABEL(DT_NODELABEL(a)) // "GPIO_1" - * DT_SPI_DEV_CS_GPIOS_LABEL(DT_NODELABEL(b)) // "GPIO_2" - * - * @param spi_dev a SPI device node identifier - * @return label property of spi_dev's chip select GPIO controller - */ -#define DT_SPI_DEV_CS_GPIOS_LABEL(spi_dev) \ - DT_GPIO_LABEL_BY_IDX(DT_BUS(spi_dev), cs_gpios, DT_REG_ADDR(spi_dev)) __DEPRECATED_MACRO - /** * @brief Get a SPI device's chip select GPIO pin number * @@ -272,19 +231,6 @@ extern "C" { #define DT_INST_SPI_DEV_CS_GPIOS_CTLR(inst) \ DT_SPI_DEV_CS_GPIOS_CTLR(DT_DRV_INST(inst)) -/** - * @deprecated If used to obtain a device instance with device_get_binding, - * consider using @c DEVICE_DT_GET(DT_INST_SPI_DEV_CS_GPIOS_CTLR(node)). - * - * @brief Get GPIO controller name for a SPI device instance - * This is equivalent to DT_SPI_DEV_CS_GPIOS_LABEL(DT_DRV_INST(inst)). - * @param inst DT_DRV_COMPAT instance number - * @return label property of the instance's chip select GPIO controller - * @see DT_SPI_DEV_CS_GPIOS_LABEL() - */ -#define DT_INST_SPI_DEV_CS_GPIOS_LABEL(inst) \ - DT_SPI_DEV_CS_GPIOS_LABEL(DT_DRV_INST(inst)) __DEPRECATED_MACRO - /** * @brief Equivalent to DT_SPI_DEV_CS_GPIOS_PIN(DT_DRV_INST(inst)). * @param inst DT_DRV_COMPAT instance number diff --git a/tests/lib/devicetree/api/app.overlay b/tests/lib/devicetree/api/app.overlay index 64010f0c8ef..66ff605bfcd 100644 --- a/tests/lib/devicetree/api/app.overlay +++ b/tests/lib/devicetree/api/app.overlay @@ -49,13 +49,16 @@ }; test_phandles: phandle-holder-0 { + /* + * There should only be one vnd,phandle-holder in the entire DTS. + */ compatible = "vnd,phandle-holder"; /* * At least one of these phandles must refer to * test_gpio_1, or dependency ordinal tests may fail. */ ph = <&test_gpio_1>; - phs = <&test_gpio_1 &test_gpio_2 &test_i2c>; + phs = <&test_i2c &test_spi>; phs-or = <&test_enum_default_0 &test_enum_default_1>; gpios = <&test_gpio_1 10 20>, <&test_gpio_2 30 40>; pha-gpios = <&test_gpio_1 50 60>, <0>, <&test_gpio_3 70>, <&test_gpio_2 80 90>; @@ -126,7 +129,6 @@ reg = < 0x0 0x1000 >; interrupts = <3 1>; #gpio-cells = < 0x2 >; - label = "TEST_GPIO_0"; status = "disabled"; }; @@ -157,6 +159,7 @@ label = "TEST_GPIO_1"; interrupts = <4 3>; status = "okay"; + ngpios = <100>; test_gpio_hog_1 { gpio-hog; @@ -182,6 +185,7 @@ interrupts = <5 2>; label = "TEST_GPIO_2"; status = "okay"; + ngpios = <200>; test_gpio_hog_3 { gpio-hog; @@ -697,4 +701,9 @@ reg-names = "test_name"; }; }; + + non-deprecated-label { + compatible = "vnd,non-deprecated-label"; + label = "FOO"; + }; }; diff --git a/tests/lib/devicetree/api/src/main.c b/tests/lib/devicetree/api/src/main.c index 019f5845a38..72c5426e01a 100644 --- a/tests/lib/devicetree/api/src/main.c +++ b/tests/lib/devicetree/api/src/main.c @@ -4,21 +4,6 @@ * SPDX-License-Identifier: Apache-2.0 */ -/* Override __DEPRECATED_MACRO so we don't get twister failures for - * deprecated macros: - * - DT_LABEL - * - DT_BUS_LABEL - * - DT_SPI_DEV_CS_GPIOS_LABEL - * - DT_GPIO_LABEL - * - DT_GPIO_LABEL_BY_IDX - * - DT_INST_LABEL - * - DT_INST_BUS_LABEL - * - DT_INST_SPI_DEV_CS_GPIOS_LABEL - * - DT_INST_GPIO_LABEL - * - DT_INST_GPIO_LABEL_BY_IDX - */ -#define __DEPRECATED_MACRO - #include #include #include @@ -109,12 +94,11 @@ ZTEST(devicetree_api, test_path_props) { - zassert_true(!strcmp(DT_LABEL(TEST_DEADBEEF), "TEST_GPIO_1"), ""); zassert_equal(DT_NUM_REGS(TEST_DEADBEEF), 1, ""); zassert_equal(DT_REG_ADDR(TEST_DEADBEEF), 0xdeadbeef, ""); zassert_equal(DT_REG_SIZE(TEST_DEADBEEF), 0x1000, ""); zassert_equal(DT_PROP(TEST_DEADBEEF, gpio_controller), 1, ""); - zassert_equal(DT_PROP(TEST_DEADBEEF, ngpios), 32, ""); + zassert_equal(DT_PROP(TEST_DEADBEEF, ngpios), 100, ""); zassert_true(!strcmp(DT_PROP(TEST_DEADBEEF, status), "okay"), ""); zassert_equal(DT_PROP_LEN(TEST_DEADBEEF, compatible), 1, ""); zassert_true(!strcmp(DT_PROP_BY_IDX(TEST_DEADBEEF, compatible, 0), @@ -125,7 +109,7 @@ ZTEST(devicetree_api, test_path_props) zassert_true(DT_SAME_NODE(TEST_ABCD1234, TEST_GPIO_2), ""); zassert_equal(DT_NUM_REGS(TEST_ABCD1234), 2, ""); zassert_equal(DT_PROP(TEST_ABCD1234, gpio_controller), 1, ""); - zassert_equal(DT_PROP(TEST_ABCD1234, ngpios), 32, ""); + zassert_equal(DT_PROP(TEST_ABCD1234, ngpios), 200, ""); zassert_true(!strcmp(DT_PROP(TEST_ABCD1234, status), "okay"), ""); zassert_equal(DT_PROP_LEN(TEST_ABCD1234, compatible), 1, ""); zassert_equal(DT_PROP_LEN_OR(TEST_ABCD1234, compatible, 4), 1, ""); @@ -141,7 +125,7 @@ ZTEST(devicetree_api, test_alias_props) zassert_equal(DT_REG_SIZE(TEST_ALIAS), 0x1000, ""); zassert_true(DT_SAME_NODE(TEST_ALIAS, TEST_GPIO_1), ""); zassert_equal(DT_PROP(TEST_ALIAS, gpio_controller), 1, ""); - zassert_equal(DT_PROP(TEST_ALIAS, ngpios), 32, ""); + zassert_equal(DT_PROP(TEST_ALIAS, ngpios), 100, ""); zassert_true(!strcmp(DT_PROP(TEST_ALIAS, status), "okay"), ""); zassert_equal(DT_PROP_LEN(TEST_ALIAS, compatible), 1, ""); zassert_true(!strcmp(DT_PROP_BY_IDX(TEST_ALIAS, compatible, 0), @@ -153,9 +137,8 @@ ZTEST(devicetree_api, test_nodelabel_props) zassert_equal(DT_NUM_REGS(TEST_NODELABEL), 1, ""); zassert_equal(DT_REG_ADDR(TEST_NODELABEL), 0xdeadbeef, ""); zassert_equal(DT_REG_SIZE(TEST_NODELABEL), 0x1000, ""); - zassert_true(!strcmp(DT_LABEL(TEST_NODELABEL), "TEST_GPIO_1"), ""); zassert_equal(DT_PROP(TEST_NODELABEL, gpio_controller), 1, ""); - zassert_equal(DT_PROP(TEST_NODELABEL, ngpios), 32, ""); + zassert_equal(DT_PROP(TEST_NODELABEL, ngpios), 100, ""); zassert_true(!strcmp(DT_PROP(TEST_NODELABEL, status), "okay"), ""); zassert_equal(DT_PROP_LEN(TEST_NODELABEL, compatible), 1, ""); zassert_true(!strcmp(DT_PROP_BY_IDX(TEST_NODELABEL, compatible, 0), @@ -167,8 +150,6 @@ ZTEST(devicetree_api, test_nodelabel_props) #define DT_DRV_COMPAT vnd_gpio_device ZTEST(devicetree_api, test_inst_props) { - const char *label_startswith = "TEST_GPIO_"; - /* * Careful: * @@ -192,8 +173,6 @@ ZTEST(devicetree_api, test_inst_props) zassert_equal(DT_INST_PROP_LEN(0, compatible), 1, ""); zassert_true(!strcmp(DT_INST_PROP_BY_IDX(0, compatible, 0), "vnd,gpio-device"), ""); - zassert_true(!strncmp(label_startswith, DT_INST_LABEL(0), - strlen(label_startswith)), ""); } #undef DT_DRV_COMPAT @@ -349,16 +328,6 @@ ZTEST(devicetree_api, test_has_status) ZTEST(devicetree_api, test_bus) { - /* common prefixes of expected labels: */ - const char *i2c_bus = "TEST_I2C_CTLR"; - const char *i2c_dev = "TEST_I2C_DEV"; - const char *i3c_bus = "TEST_I3C_CTLR"; - const char *i3c_dev = "TEST_I3C_DEV"; - const char *i3c_i2c_bus = "TEST_I3C_CTLR"; - const char *i3c_i2c_dev = "TEST_I3C_I2C_DEV"; - const char *spi_bus = "TEST_SPI_CTLR"; - const char *spi_dev = "TEST_SPI_DEV"; - const char *gpio = "TEST_GPIO_"; int pin, flags; zassert_true(DT_SAME_NODE(TEST_I3C_BUS, TEST_I3C), ""); @@ -396,9 +365,6 @@ ZTEST(devicetree_api, test_bus) DT_SAME_NODE(CTLR_NODE, DT_NODELABEL(test_gpio_2)), ""); #undef CTLR_NODE - zassert_true(!strncmp(gpio, DT_INST_SPI_DEV_CS_GPIOS_LABEL(0), - strlen(gpio)), ""); - pin = DT_INST_SPI_DEV_CS_GPIOS_PIN(0); zassert_true((pin == 0x10) || (pin == 0x30), ""); @@ -413,8 +379,6 @@ ZTEST(devicetree_api, test_bus) zassert_equal(DT_ON_BUS(TEST_I2C_DEV, i3c), 0, ""); zassert_equal(DT_ON_BUS(TEST_I2C_DEV, spi), 0, ""); - zassert_true(!strcmp(DT_BUS_LABEL(TEST_I2C_DEV), "TEST_I2C_CTLR"), ""); - #undef DT_DRV_COMPAT #define DT_DRV_COMPAT vnd_spi_device zassert_equal(DT_NUM_INST_STATUS_OKAY(DT_DRV_COMPAT), 2, ""); @@ -427,10 +391,6 @@ ZTEST(devicetree_api, test_bus) zassert_equal(DT_ANY_INST_ON_BUS_STATUS_OKAY(i2c), 0, ""); zassert_equal(DT_ANY_INST_ON_BUS_STATUS_OKAY(i3c), 0, ""); - zassert_true(!strncmp(spi_dev, DT_INST_LABEL(0), strlen(spi_dev)), ""); - zassert_true(!strncmp(spi_bus, DT_INST_BUS_LABEL(0), strlen(spi_bus)), - ""); - #undef DT_DRV_COMPAT #define DT_DRV_COMPAT vnd_i2c_device zassert_equal(DT_NUM_INST_STATUS_OKAY(DT_DRV_COMPAT), 2, ""); @@ -443,10 +403,6 @@ ZTEST(devicetree_api, test_bus) zassert_equal(DT_ANY_INST_ON_BUS_STATUS_OKAY(i3c), 0, ""); zassert_equal(DT_ANY_INST_ON_BUS_STATUS_OKAY(spi), 0, ""); - zassert_true(!strncmp(i2c_dev, DT_INST_LABEL(0), strlen(i2c_dev)), ""); - zassert_true(!strncmp(i2c_bus, DT_INST_BUS_LABEL(0), strlen(i2c_bus)), - ""); - #undef DT_DRV_COMPAT #define DT_DRV_COMPAT vnd_i3c_device zassert_equal(DT_NUM_INST_STATUS_OKAY(DT_DRV_COMPAT), 1, ""); @@ -459,10 +415,6 @@ ZTEST(devicetree_api, test_bus) zassert_equal(DT_ANY_INST_ON_BUS_STATUS_OKAY(i3c), 1, ""); zassert_equal(DT_ANY_INST_ON_BUS_STATUS_OKAY(spi), 0, ""); - zassert_true(!strncmp(i3c_dev, DT_INST_LABEL(0), strlen(i3c_dev)), ""); - zassert_true(!strncmp(i3c_bus, DT_INST_BUS_LABEL(0), strlen(i3c_bus)), - ""); - #undef DT_DRV_COMPAT #define DT_DRV_COMPAT vnd_i3c_i2c_device zassert_equal(DT_NUM_INST_STATUS_OKAY(DT_DRV_COMPAT), 1, ""); @@ -475,10 +427,6 @@ ZTEST(devicetree_api, test_bus) zassert_equal(DT_ANY_INST_ON_BUS_STATUS_OKAY(i3c), 1, ""); zassert_equal(DT_ANY_INST_ON_BUS_STATUS_OKAY(spi), 0, ""); - zassert_true(!strncmp(i3c_i2c_dev, DT_INST_LABEL(0), strlen(i3c_i2c_dev)), ""); - zassert_true(!strncmp(i3c_i2c_bus, DT_INST_BUS_LABEL(0), strlen(i3c_i2c_bus)), - ""); - #undef DT_DRV_COMPAT /* @@ -799,27 +747,16 @@ ZTEST(devicetree_api, test_irq) } struct gpios_struct { - const char *name; gpio_pin_t pin; gpio_flags_t flags; }; -/* Helper macro that UTIL_LISTIFY can use and produces an element with comma */ -#define DT_PROP_ELEM_BY_PHANDLE(idx, node_id, ph_prop, prop) \ - DT_PROP_BY_PHANDLE_IDX(node_id, ph_prop, idx, prop) -#define DT_PHANDLE_LISTIFY(node_id, ph_prop, prop) \ - { \ - LISTIFY(DT_PROP_LEN(node_id, ph_prop), \ - DT_PROP_ELEM_BY_PHANDLE, (,), \ - node_id, \ - ph_prop, \ - label) \ - } +#define CLOCK_FREQUENCY_AND_COMMA(node_id, prop, idx) \ + DT_PROP_BY_PHANDLE_IDX(node_id, prop, idx, clock_frequency), /* Helper macro that UTIL_LISTIFY can use and produces an element with comma */ #define DT_GPIO_ELEM(idx, node_id, prop) \ { \ - DT_PROP(DT_PHANDLE_BY_IDX(node_id, prop, idx), label), \ DT_PHA_BY_IDX(node_id, prop, idx, pin),\ DT_PHA_BY_IDX(node_id, prop, idx, flags),\ } @@ -831,8 +768,8 @@ struct gpios_struct { #define DT_DRV_COMPAT vnd_phandle_holder ZTEST(devicetree_api, test_phandles) { - const char *ph_label = DT_PROP_BY_PHANDLE(TEST_PH, ph, label); - const char *phs_labels[] = DT_PHANDLE_LISTIFY(TEST_PH, phs, label); + bool gpio_controller = DT_PROP_BY_PHANDLE(TEST_PH, ph, gpio_controller); + size_t phs_freqs[] = { DT_FOREACH_PROP_ELEM(TEST_PH, phs, CLOCK_FREQUENCY_AND_COMMA) }; struct gpios_struct gps[] = DT_GPIO_LISTIFY(TEST_PH, gpios); /* phandle */ @@ -843,33 +780,34 @@ ZTEST(devicetree_api, test_phandles) zassert_true(DT_SAME_NODE(DT_PROP_BY_IDX(TEST_PH, ph, 0), DT_NODELABEL(test_gpio_1)), ""); /* DT_PROP_BY_PHANDLE */ - zassert_true(!strcmp(ph_label, "TEST_GPIO_1"), ""); + zassert_equal(gpio_controller, true, ""); /* phandles */ zassert_true(DT_NODE_HAS_PROP(TEST_PH, phs), ""); - zassert_equal(ARRAY_SIZE(phs_labels), 3, ""); - zassert_equal(DT_PROP_LEN(TEST_PH, phs), 3, ""); + zassert_equal(ARRAY_SIZE(phs_freqs), 2, ""); + zassert_equal(DT_PROP_LEN(TEST_PH, phs), 2, ""); zassert_true(DT_SAME_NODE(DT_PROP_BY_IDX(TEST_PH, phs, 1), - DT_NODELABEL(test_gpio_2)), ""); - - /* DT_PROP_BY_PHANDLE_IDX */ - zassert_true(!strcmp(DT_PROP_BY_PHANDLE_IDX(TEST_PH, phs, 0, label), - "TEST_GPIO_1"), ""); - zassert_true(!strcmp(DT_PROP_BY_PHANDLE_IDX(TEST_PH, phs, 1, label), - "TEST_GPIO_2"), ""); - zassert_true(!strcmp(DT_PROP_BY_PHANDLE_IDX(TEST_PH, phs, 2, label), - "TEST_I2C_CTLR"), ""); - zassert_true(!strcmp(phs_labels[0], "TEST_GPIO_1"), ""); - zassert_true(!strcmp(phs_labels[1], "TEST_GPIO_2"), ""); - zassert_true(!strcmp(phs_labels[2], "TEST_I2C_CTLR"), ""); + TEST_SPI), ""); + + /* DT_FOREACH_PROP_ELEM on a phandles type property */ + zassert_equal(phs_freqs[0], 100000, ""); + zassert_equal(phs_freqs[1], 2000000, ""); + + /* DT_PROP_BY_PHANDLE_IDX on a phandles type property */ + zassert_equal(DT_PROP_BY_PHANDLE_IDX(TEST_PH, phs, 0, clock_frequency), + 100000, ""); + zassert_equal(DT_PROP_BY_PHANDLE_IDX(TEST_PH, phs, 1, clock_frequency), + 2000000, ""); + + /* DT_PROP_BY_PHANDLE_IDX on a phandle-array type property */ zassert_equal(DT_PROP_BY_PHANDLE_IDX(TEST_PH, gpios, 0, - gpio_controller), 1, ""); + ngpios), 100, ""); zassert_equal(DT_PROP_BY_PHANDLE_IDX(TEST_PH, gpios, 1, - gpio_controller), 1, ""); - zassert_true(!strcmp(DT_PROP_BY_PHANDLE_IDX(TEST_PH, gpios, 0, label), - "TEST_GPIO_1"), ""); - zassert_true(!strcmp(DT_PROP_BY_PHANDLE_IDX(TEST_PH, gpios, 1, label), - "TEST_GPIO_2"), ""); + ngpios), 200, ""); + zassert_true(!strcmp(DT_PROP_BY_PHANDLE_IDX(TEST_PH, gpios, 0, status), + "okay"), ""); + zassert_true(!strcmp(DT_PROP_BY_PHANDLE_IDX(TEST_PH, gpios, 1, status), + "okay"), ""); /* DT_PROP_BY_PHANDLE_IDX_OR */ zassert_true(!strcmp(DT_PROP_BY_PHANDLE_IDX_OR(TEST_PH, phs_or, 0, @@ -943,11 +881,9 @@ ZTEST(devicetree_api, test_phandles) zassert_true(DT_SAME_NODE(DT_PHANDLE_BY_NAME(TEST_PH, foos, b_c), TEST_GPIO_2), ""); /* array initializers */ - zassert_true(!strcmp(gps[0].name, "TEST_GPIO_1"), ""); zassert_equal(gps[0].pin, 10, ""); zassert_equal(gps[0].flags, 20, ""); - zassert_true(!strcmp(gps[1].name, "TEST_GPIO_2"), ""); zassert_equal(gps[1].pin, 30, ""); zassert_equal(gps[1].flags, 40, ""); @@ -955,31 +891,23 @@ ZTEST(devicetree_api, test_phandles) zassert_equal(DT_NUM_INST_STATUS_OKAY(DT_DRV_COMPAT), 1, ""); /* DT_INST_PROP_BY_PHANDLE */ - zassert_true(!strcmp(DT_INST_PROP_BY_PHANDLE(0, ph, label), - "TEST_GPIO_1"), ""); - - zassert_true(!strcmp(ph_label, "TEST_GPIO_1"), ""); + zassert_equal(DT_INST_PROP_BY_PHANDLE(0, ph, ngpios), 100, ""); /* DT_INST_PROP_BY_PHANDLE_IDX */ - zassert_true(!strcmp(DT_INST_PROP_BY_PHANDLE_IDX(0, phs, 0, label), - "TEST_GPIO_1"), ""); - zassert_true(!strcmp(DT_INST_PROP_BY_PHANDLE_IDX(0, phs, 1, label), - "TEST_GPIO_2"), ""); - zassert_true(!strcmp(DT_INST_PROP_BY_PHANDLE_IDX(0, phs, 2, label), - "TEST_I2C_CTLR"), ""); - zassert_true(!strcmp(phs_labels[0], "TEST_GPIO_1"), ""); - zassert_true(!strcmp(phs_labels[1], "TEST_GPIO_2"), ""); - zassert_true(!strcmp(phs_labels[2], "TEST_I2C_CTLR"), ""); + zassert_equal(DT_INST_PROP_BY_PHANDLE_IDX(0, phs, 0, clock_frequency), + 100000, ""); + zassert_equal(DT_INST_PROP_BY_PHANDLE_IDX(0, phs, 1, clock_frequency), + 2000000, ""); zassert_equal(DT_INST_PROP_BY_PHANDLE_IDX(0, gpios, 0, gpio_controller), 1, ""); zassert_equal(DT_INST_PROP_BY_PHANDLE_IDX(0, gpios, 1, gpio_controller), 1, ""); - zassert_true(!strcmp(DT_INST_PROP_BY_PHANDLE_IDX(0, gpios, 0, label), - "TEST_GPIO_1"), ""); - zassert_true(!strcmp(DT_INST_PROP_BY_PHANDLE_IDX(0, gpios, 1, label), - "TEST_GPIO_2"), ""); + zassert_equal(DT_INST_PROP_BY_PHANDLE_IDX(0, gpios, 0, ngpios), + 100, ""); + zassert_equal(DT_INST_PROP_BY_PHANDLE_IDX(0, gpios, 1, ngpios), + 200, ""); /* DT_INST_PROP_HAS_IDX */ zassert_true(DT_INST_PROP_HAS_IDX(0, gpios, 0), ""); @@ -1054,15 +982,6 @@ ZTEST(devicetree_api, test_gpio) zassert_true(!strcmp(TO_STRING(DT_GPIO_CTLR(TEST_PH, gpios)), TO_STRING(DT_NODELABEL(test_gpio_1))), ""); - /* DT_GPIO_LABEL_BY_IDX */ - zassert_true(!strcmp(DT_GPIO_LABEL_BY_IDX(TEST_PH, gpios, 0), - "TEST_GPIO_1"), ""); - zassert_true(!strcmp(DT_GPIO_LABEL_BY_IDX(TEST_PH, gpios, 1), - "TEST_GPIO_2"), ""); - - /* DT_GPIO_LABEL */ - zassert_true(!strcmp(DT_GPIO_LABEL(TEST_PH, gpios), "TEST_GPIO_1"), ""); - /* DT_GPIO_PIN_BY_IDX */ zassert_equal(DT_GPIO_PIN_BY_IDX(TEST_PH, gpios, 0), 10, ""); zassert_equal(DT_GPIO_PIN_BY_IDX(TEST_PH, gpios, 1), 30, ""); @@ -1097,15 +1016,6 @@ ZTEST(devicetree_api, test_gpio) /* DT_INST */ zassert_equal(DT_NUM_INST_STATUS_OKAY(DT_DRV_COMPAT), 1, ""); - /* DT_INST_GPIO_LABEL_BY_IDX */ - zassert_true(!strcmp(DT_INST_GPIO_LABEL_BY_IDX(0, gpios, 0), - "TEST_GPIO_1"), ""); - zassert_true(!strcmp(DT_INST_GPIO_LABEL_BY_IDX(0, gpios, 1), - "TEST_GPIO_2"), ""); - - /* DT_INST_GPIO_LABEL */ - zassert_true(!strcmp(DT_INST_GPIO_LABEL(0, gpios), "TEST_GPIO_1"), ""); - /* DT_INST_GPIO_PIN_BY_IDX */ zassert_equal(DT_INST_GPIO_PIN_BY_IDX(0, gpios, 0), 10, ""); zassert_equal(DT_INST_GPIO_PIN_BY_IDX(0, gpios, 1), 30, ""); @@ -1633,10 +1543,9 @@ ZTEST(devicetree_api, test_foreach_prop_elem) DT_FOREACH_PROP_ELEM(TEST_PH, phs, PATH_COMMA) }; - zassert_equal(ARRAY_SIZE(array_phs), 3, ""); - zassert_true(!strcmp(array_phs[0], DT_NODE_PATH(TEST_GPIO_1)), ""); - zassert_true(!strcmp(array_phs[1], DT_NODE_PATH(TEST_GPIO_2)), ""); - zassert_true(!strcmp(array_phs[2], DT_NODE_PATH(TEST_I2C)), ""); + zassert_equal(ARRAY_SIZE(array_phs), 2, ""); + zassert_true(!strcmp(array_phs[0], DT_NODE_PATH(TEST_I2C)), ""); + zassert_true(!strcmp(array_phs[1], DT_NODE_PATH(TEST_SPI)), ""); #undef PATH_COMMA @@ -1753,7 +1662,6 @@ static int test_gpio_init(const struct device *dev) return 0; } -#define INST(num) DT_INST(num, vnd_gpio_device) #undef DT_DRV_COMPAT #define DT_DRV_COMPAT vnd_gpio_device @@ -1761,28 +1669,27 @@ static const struct gpio_driver_api test_api; #define TEST_GPIO_INIT(num) \ static struct test_gpio_data gpio_data_##num = { \ - .is_gpio_ctlr = DT_PROP(INST(num), \ - gpio_controller), \ + .is_gpio_ctlr = DT_INST_PROP(num, \ + gpio_controller), \ }; \ static const struct test_gpio_info gpio_info_##num = { \ - .reg_addr = DT_REG_ADDR(INST(num)), \ - .reg_len = DT_REG_SIZE(INST(num)), \ + .reg_addr = DT_INST_REG_ADDR(num), \ + .reg_len = DT_INST_REG_SIZE(num), \ }; \ - DEVICE_DT_DEFINE(INST(num), \ - test_gpio_init, \ - NULL, \ - &gpio_data_##num, \ - &gpio_info_##num, \ - POST_KERNEL, \ - CONFIG_APPLICATION_INIT_PRIORITY, \ - &test_api); + DEVICE_DT_INST_DEFINE(num, \ + test_gpio_init, \ + NULL, \ + &gpio_data_##num, \ + &gpio_info_##num, \ + POST_KERNEL, \ + CONFIG_APPLICATION_INIT_PRIORITY, \ + &test_api); DT_INST_FOREACH_STATUS_OKAY(TEST_GPIO_INIT) ZTEST(devicetree_api, test_devices) { - const struct device *devs[3]; - int i = 0; + const struct device *devs[2] = { DEVICE_DT_INST_GET(0), DEVICE_DT_INST_GET(1) }; const struct device *dev_abcd; struct test_gpio_data *data_dev0; struct test_gpio_data *data_dev1; @@ -1790,25 +1697,11 @@ ZTEST(devicetree_api, test_devices) zassert_equal(DT_NUM_INST_STATUS_OKAY(vnd_gpio_device), 2, ""); - devs[i] = device_get_binding(DT_LABEL(INST(0))); - if (devs[i]) { - i++; - } - devs[i] = device_get_binding(DT_LABEL(INST(1))); - if (devs[i]) { - i++; - } - devs[i] = device_get_binding(DT_LABEL(INST(2))); - if (devs[i]) { - i++; - } - data_dev0 = devs[0]->data; data_dev1 = devs[1]->data; zassert_not_null(devs[0], ""); zassert_not_null(devs[1], ""); - zassert_true(devs[2] == NULL, ""); zassert_true(data_dev0->is_gpio_ctlr, ""); zassert_true(data_dev1->is_gpio_ctlr, ""); @@ -1833,8 +1726,6 @@ ZTEST(devicetree_api, test_cs_gpios) zassert_equal(DT_DEP_ORD(DT_SPI_DEV_CS_GPIOS_CTLR(TEST_SPI_DEV_0)), DT_DEP_ORD(DT_NODELABEL(test_gpio_1)), "dev 0 cs gpio controller"); - zassert_true(!strcmp(DT_SPI_DEV_CS_GPIOS_LABEL(TEST_SPI_DEV_0), - "TEST_GPIO_1"), ""); zassert_equal(DT_SPI_DEV_CS_GPIOS_PIN(TEST_SPI_DEV_0), 0x10, ""); zassert_equal(DT_SPI_DEV_CS_GPIOS_FLAGS(TEST_SPI_DEV_0), 0x20, ""); } @@ -2777,9 +2668,9 @@ ZTEST(devicetree_api, test_fixed_partitions) zassert_false(DT_HAS_FIXED_PARTITION_LABEL(test_partition_3)); zassert_false(DT_NODE_EXISTS(DT_NODE_BY_FIXED_PARTITION_LABEL(test_partition_3))); - /* There is a node with `label = "TEST_GPIO_0"`, but it is not a fixed partition. */ - zassert_false(DT_HAS_FIXED_PARTITION_LABEL(TEST_GPIO_0)); - zassert_false(DT_NODE_EXISTS(DT_NODE_BY_FIXED_PARTITION_LABEL(TEST_GPIO_0))); + /* There is a node with `label = "FOO"`, but it is not a fixed partition. */ + zassert_false(DT_HAS_FIXED_PARTITION_LABEL(FOO)); + zassert_false(DT_NODE_EXISTS(DT_NODE_BY_FIXED_PARTITION_LABEL(FOO))); /* Test DT_MTD_FROM_FIXED_PARTITION. */ zassert_true(DT_NODE_EXISTS(DT_MTD_FROM_FIXED_PARTITION(TEST_PARTITION_0))); From 690011498c53f2412599e6145ff688969415b587 Mon Sep 17 00:00:00 2001 From: Maciej Perkowski Date: Thu, 30 Nov 2023 14:28:59 +0100 Subject: [PATCH 0624/3723] twister: Add target reports in json format Using --platform-reports will also generate json reports with results from a single platform. Needed for on-target results publishing process. Signed-off-by: Maciej Perkowski --- scripts/pylib/twister/twisterlib/reports.py | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/scripts/pylib/twister/twisterlib/reports.py b/scripts/pylib/twister/twisterlib/reports.py index 4895fdfe170..7425841a723 100644 --- a/scripts/pylib/twister/twisterlib/reports.py +++ b/scripts/pylib/twister/twisterlib/reports.py @@ -232,7 +232,7 @@ def xunit_report(self, json_file, filename, selected_platform=None, full_report= with open(filename, 'wb') as report: report.write(result) - def json_report(self, filename, version="NA"): + def json_report(self, filename, version="NA", platform=None): logger.info(f"Writing JSON report {filename}") report = {} report["environment"] = {"os": os.name, @@ -244,6 +244,8 @@ def json_report(self, filename, version="NA"): suites = [] for instance in self.instances.values(): + if platform and platform != instance.platform.name: + continue suite = {} handler_log = os.path.join(instance.build_dir, "handler.log") pytest_log = os.path.join(instance.build_dir, "twister_harness.log") @@ -543,6 +545,9 @@ def target_report(self, json_file, outdir, suffix): for platform in platforms: if suffix: filename = os.path.join(outdir,"{}_{}.xml".format(platform, suffix)) + json_platform_file = os.path.join(outdir,"{}_{}.json".format(platform, suffix)) else: filename = os.path.join(outdir,"{}.xml".format(platform)) + json_platform_file = os.path.join(outdir,"{}.json".format(platform)) self.xunit_report(json_file, filename, platform, full_report=True) + self.json_report(json_platform_file, version=self.env.version, platform=platform) From 37ef725c9bd467e8f717cf36f14197cd4fd54f9d Mon Sep 17 00:00:00 2001 From: Marc Herbert Date: Thu, 30 Nov 2023 07:55:34 +0000 Subject: [PATCH 0625/3723] time_units.h: never return zero from z_tmcvt_divisor(a, b) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Since commit ea61c8c1bd93 ("sys/time_units.h: Work around clang div-by-zero warning") `z_tmcvt_divisor(a, b)` started to "cheat" and never return 0; but only when `#ifdef __clang__`. After some very tedious experiments and "reverse-engineering" of pre-processor output (the horror...), I finally found why xt-xc++ 12.0.8 (based on gcc 4.2.0) produces the same warnings and I discovered this clang-specific workaround. Rather than adding gcc to a list of "privileged" compilers, make the code more consistent and predictable: make `z_tmcvt_divisor(a, b)` never return zero for _all_ compilers. Drop the usage of the non-standard "Elvis" operator `?: 1` to be compatible with any compiler; everything is evaluated at compile-time anyway (and the pre-processor output is almost impossible to read already anyway) Surprisingly, only C++ files (_every_ C++ file) emitted the divide-by-zero warning with that xt-xc++ version. The very same code compiled by xt-gcc in the same toolchain never showed that warning. Probably due to the abuse of macros, the warning was super cryptic: ``` from every.cpp: include/zephyr/kernel.h: In function ‘int32_t k_msleep(int32_t)’: include/zephyr/kernel.h: warning: division by zero in ‘(((uint64_t)(ms 0)) + 0xffffffffffffffffull) / 0’ ``` I didn't find any `0xffffffffffffffffull` anywhere in the code and I still have no idea what is. Signed-off-by: Marc Herbert --- include/zephyr/sys/time_units.h | 27 +++++++++++++++++++-------- 1 file changed, 19 insertions(+), 8 deletions(-) diff --git a/include/zephyr/sys/time_units.h b/include/zephyr/sys/time_units.h index 7f2db1a1f55..62c199bc488 100644 --- a/include/zephyr/sys/time_units.h +++ b/include/zephyr/sys/time_units.h @@ -135,15 +135,26 @@ static inline int z_impl_sys_clock_hw_cycles_per_sec_runtime_get(void) (__round_up) ? ((__from_hz) / (__to_hz)) - 1 : \ 0) -/* Clang emits a divide-by-zero warning even though the int_div macro - * results are only used when the divisor will not be zero. Work - * around this by substituting 1 to make the compiler happy. +/* + * All users of this macro MUST ensure its output is never used when a/b + * is zero because it incorrectly but by design never returns zero. + * + * Some compiler versions emit a divide-by-zero warning for this code: + * "false ? 42/0 : 43". Dealing with (generated) dead code is hard: + * https://github.com/zephyrproject-rtos/zephyr/issues/63564 + * https://blog.llvm.org/2011/05/what-every-c-programmer-should-know_21.html + * + * To silence such divide-by-zero warnings, "cheat" and never return + * zero. Return 1 instead. Use octal "01u" as a breadcrumb to ease a + * little bit the huge pain of "reverse-engineering" pre-processor + * output. + * + * The "Elvis" operator "a/b ?: 1" is tempting because it avoids + * evaluating the same expression twice. However: 1. it's a non-standard + * GNU extension; 2. everything in this file is designed to be computed + * at compile time anyway. */ -#ifdef __clang__ -#define z_tmcvt_divisor(a, b) ((a) / (b) ?: 1) -#else -#define z_tmcvt_divisor(a, b) ((a) / (b)) -#endif +#define z_tmcvt_divisor(a, b) ((a)/(b) ? (a)/(b) : 01u) /* * Compute the offset needed to round the result correctly when From 94cdfa60dc17cd4fea77f73b9654e0c0f3263175 Mon Sep 17 00:00:00 2001 From: Alberto Escolar Piedras Date: Wed, 29 Nov 2023 16:50:37 +0100 Subject: [PATCH 0626/3723] sysbuild: Add extensions for native_simulator based targets Add 3 new functions to perform functions typically needed for native_simulator based targes and reduce the amount of boilerplate. Signed-off-by: Alberto Escolar Piedras --- share/sysbuild/CMakeLists.txt | 7 ++- .../native_simulator_sb_extensions.cmake | 62 +++++++++++++++++++ 2 files changed, 67 insertions(+), 2 deletions(-) create mode 100644 share/sysbuild/cmake/modules/native_simulator_sb_extensions.cmake diff --git a/share/sysbuild/CMakeLists.txt b/share/sysbuild/CMakeLists.txt index 7bbfe138760..8a15da9cef5 100644 --- a/share/sysbuild/CMakeLists.txt +++ b/share/sysbuild/CMakeLists.txt @@ -1,4 +1,4 @@ -# Copyright (c) 2021-2023 Nordic Semiconductor +# Copyright (c) 2023 Nordic Semiconductor # # SPDX-License-Identifier: Apache-2.0 @@ -18,7 +18,10 @@ set(APP_DIR ${APP_DIR} CACHE PATH "Main Application Source Directory") list(APPEND CMAKE_MODULE_PATH ${CMAKE_CURRENT_LIST_DIR}/cmake/modules) # List of Zephyr and sysbuild CMake modules we need for sysbuild. # Note: sysbuild_kconfig will internally load kconfig CMake module. -set(zephyr_modules extensions sysbuild_extensions python west root zephyr_module boards shields sysbuild_kconfig) +set(zephyr_modules extensions + sysbuild_extensions python west root zephyr_module boards shields + sysbuild_kconfig native_simulator_sb_extensions + ) find_package(Zephyr REQUIRED HINTS $ENV{ZEPHYR_BASE} COMPONENTS ${zephyr_modules}) diff --git a/share/sysbuild/cmake/modules/native_simulator_sb_extensions.cmake b/share/sysbuild/cmake/modules/native_simulator_sb_extensions.cmake new file mode 100644 index 00000000000..3d888d1775e --- /dev/null +++ b/share/sysbuild/cmake/modules/native_simulator_sb_extensions.cmake @@ -0,0 +1,62 @@ +# Copyright (c) 2023 Nordic Semiconductor +# +# SPDX-License-Identifier: Apache-2.0 + +# Usage: +# native_simulator_set_final_executable() +# +# When building for a native_simulator based target (including bsim targets), +# this function adds an extra build target which will copy the executable produced by +# `` to the top level, as zephyr/zephyr.exe +# +# This final image is expected to have been set to assemble other dependent images into +# itself if necessary, by calling native_simulator_set_child_images() +# This will allow other tools, like twister, or the bsim test scripts, as well as users to find +# this final executable in the same place as for non-sysbuild builds. +# +function(native_simulator_set_final_executable final_image) + if(("${BOARD}" MATCHES "native") OR ("${BOARD}" MATCHES "bsim")) + add_custom_target(final_executable + ALL + COMMAND + ${CMAKE_COMMAND} -E copy + ${CMAKE_BINARY_DIR}/${final_image}/zephyr/zephyr.exe + ${CMAKE_BINARY_DIR}/zephyr/zephyr.exe + DEPENDS ${final_image} + ) + endif() +endfunction() + +# Usage: +# native_simulator_set_child_images( ) +# +# When building for a native_simulator based target (including bsim targets), +# this function sets a `` as dependencies of `` +# and configures the final image to assemble the child images into its final executable. +# +function(native_simulator_set_child_images final_image child_image) + if(("${BOARD}" MATCHES "native") OR ("${BOARD}" MATCHES "bsim")) + add_dependencies(${final_image} ${child_image}) + + set(CHILD_LIBRARY_PATH ${CMAKE_BINARY_DIR}/${child_image}/zephyr/zephyr.elf) + set_property(TARGET ${final_image} APPEND_STRING PROPERTY CONFIG + "CONFIG_NATIVE_SIMULATOR_EXTRA_IMAGE_PATHS=\"${CHILD_LIBRARY_PATH}\"\n" + ) + endif() +endfunction() + +# Usage: +# native_simulator_set_primary_mcu_index( [ ...]) +# +# Propagate the SB_CONFIG_NATIVE_SIMULATOR_PRIMARY_MCU_INDEX setting, +# if it is set, to each given image CONFIG_NATIVE_SIMULATOR_PRIMARY_MCU_INDEX +# +function(native_simulator_set_primary_mcu_index) + if (NOT ("${SB_CONFIG_NATIVE_SIMULATOR_PRIMARY_MCU_INDEX}" STREQUAL "")) + foreach(arg IN LISTS ARGV) + set_property(TARGET ${arg} APPEND_STRING PROPERTY CONFIG + "CONFIG_NATIVE_SIMULATOR_PRIMARY_MCU_INDEX=${SB_CONFIG_NATIVE_SIMULATOR_PRIMARY_MCU_INDEX}\n" + ) + endforeach() + endif() +endfunction() From 8b70d98dcb1eb4f24ea5971cf81204f942c2804e Mon Sep 17 00:00:00 2001 From: Alberto Escolar Piedras Date: Wed, 29 Nov 2023 18:44:30 +0100 Subject: [PATCH 0627/3723] samples/bluetooth: Reduce sysbuild boilerplate Reduce the sysbuild boilerplate required for the nrf5340bsim targets. Signed-off-by: Alberto Escolar Piedras --- .../broadcast_audio_sink/sysbuild.cmake | 24 ++----------------- .../broadcast_audio_source/sysbuild.cmake | 24 ++----------------- .../unicast_audio_client/sysbuild.cmake | 24 ++----------------- .../unicast_audio_server/sysbuild.cmake | 24 ++----------------- 4 files changed, 8 insertions(+), 88 deletions(-) diff --git a/samples/bluetooth/broadcast_audio_sink/sysbuild.cmake b/samples/bluetooth/broadcast_audio_sink/sysbuild.cmake index ed30d7f31f3..2523aac8ea7 100644 --- a/samples/bluetooth/broadcast_audio_sink/sysbuild.cmake +++ b/samples/bluetooth/broadcast_audio_sink/sysbuild.cmake @@ -18,27 +18,7 @@ if(SB_CONFIG_NET_CORE_IMAGE_HCI_IPC) CACHE INTERNAL "" ) - # Let's build the net core library first - add_dependencies(${DEFAULT_IMAGE} ${NET_APP}) - - if("${BOARD}" STREQUAL "nrf5340bsim_nrf5340_cpuapp") - # For the simulated board, the application core build will produce the final executable - # for that, we give it the path to the netcore image - set(NET_LIBRARY_PATH ${CMAKE_BINARY_DIR}/${NET_APP}/zephyr/zephyr.elf) - set_property(TARGET ${DEFAULT_IMAGE} APPEND_STRING PROPERTY CONFIG - "CONFIG_NATIVE_SIMULATOR_EXTRA_IMAGE_PATHS=\"${NET_LIBRARY_PATH}\"\n" - ) - endif() + native_simulator_set_child_images(${DEFAULT_IMAGE} ${NET_APP}) endif() -if(("${BOARD}" MATCHES "native") OR ("${BOARD}" MATCHES "bsim")) - # Let's meet the expectation of finding the final executable in zephyr/zephyr.exe - add_custom_target(final_executable - ALL - COMMAND - ${CMAKE_COMMAND} -E copy - ${CMAKE_BINARY_DIR}/${DEFAULT_IMAGE}/zephyr/zephyr.exe - ${CMAKE_BINARY_DIR}/zephyr/zephyr.exe - DEPENDS ${DEFAULT_IMAGE} - ) -endif() +native_simulator_set_final_executable(${DEFAULT_IMAGE}) diff --git a/samples/bluetooth/broadcast_audio_source/sysbuild.cmake b/samples/bluetooth/broadcast_audio_source/sysbuild.cmake index ed30d7f31f3..2523aac8ea7 100644 --- a/samples/bluetooth/broadcast_audio_source/sysbuild.cmake +++ b/samples/bluetooth/broadcast_audio_source/sysbuild.cmake @@ -18,27 +18,7 @@ if(SB_CONFIG_NET_CORE_IMAGE_HCI_IPC) CACHE INTERNAL "" ) - # Let's build the net core library first - add_dependencies(${DEFAULT_IMAGE} ${NET_APP}) - - if("${BOARD}" STREQUAL "nrf5340bsim_nrf5340_cpuapp") - # For the simulated board, the application core build will produce the final executable - # for that, we give it the path to the netcore image - set(NET_LIBRARY_PATH ${CMAKE_BINARY_DIR}/${NET_APP}/zephyr/zephyr.elf) - set_property(TARGET ${DEFAULT_IMAGE} APPEND_STRING PROPERTY CONFIG - "CONFIG_NATIVE_SIMULATOR_EXTRA_IMAGE_PATHS=\"${NET_LIBRARY_PATH}\"\n" - ) - endif() + native_simulator_set_child_images(${DEFAULT_IMAGE} ${NET_APP}) endif() -if(("${BOARD}" MATCHES "native") OR ("${BOARD}" MATCHES "bsim")) - # Let's meet the expectation of finding the final executable in zephyr/zephyr.exe - add_custom_target(final_executable - ALL - COMMAND - ${CMAKE_COMMAND} -E copy - ${CMAKE_BINARY_DIR}/${DEFAULT_IMAGE}/zephyr/zephyr.exe - ${CMAKE_BINARY_DIR}/zephyr/zephyr.exe - DEPENDS ${DEFAULT_IMAGE} - ) -endif() +native_simulator_set_final_executable(${DEFAULT_IMAGE}) diff --git a/samples/bluetooth/unicast_audio_client/sysbuild.cmake b/samples/bluetooth/unicast_audio_client/sysbuild.cmake index ed30d7f31f3..2523aac8ea7 100644 --- a/samples/bluetooth/unicast_audio_client/sysbuild.cmake +++ b/samples/bluetooth/unicast_audio_client/sysbuild.cmake @@ -18,27 +18,7 @@ if(SB_CONFIG_NET_CORE_IMAGE_HCI_IPC) CACHE INTERNAL "" ) - # Let's build the net core library first - add_dependencies(${DEFAULT_IMAGE} ${NET_APP}) - - if("${BOARD}" STREQUAL "nrf5340bsim_nrf5340_cpuapp") - # For the simulated board, the application core build will produce the final executable - # for that, we give it the path to the netcore image - set(NET_LIBRARY_PATH ${CMAKE_BINARY_DIR}/${NET_APP}/zephyr/zephyr.elf) - set_property(TARGET ${DEFAULT_IMAGE} APPEND_STRING PROPERTY CONFIG - "CONFIG_NATIVE_SIMULATOR_EXTRA_IMAGE_PATHS=\"${NET_LIBRARY_PATH}\"\n" - ) - endif() + native_simulator_set_child_images(${DEFAULT_IMAGE} ${NET_APP}) endif() -if(("${BOARD}" MATCHES "native") OR ("${BOARD}" MATCHES "bsim")) - # Let's meet the expectation of finding the final executable in zephyr/zephyr.exe - add_custom_target(final_executable - ALL - COMMAND - ${CMAKE_COMMAND} -E copy - ${CMAKE_BINARY_DIR}/${DEFAULT_IMAGE}/zephyr/zephyr.exe - ${CMAKE_BINARY_DIR}/zephyr/zephyr.exe - DEPENDS ${DEFAULT_IMAGE} - ) -endif() +native_simulator_set_final_executable(${DEFAULT_IMAGE}) diff --git a/samples/bluetooth/unicast_audio_server/sysbuild.cmake b/samples/bluetooth/unicast_audio_server/sysbuild.cmake index ed30d7f31f3..2523aac8ea7 100644 --- a/samples/bluetooth/unicast_audio_server/sysbuild.cmake +++ b/samples/bluetooth/unicast_audio_server/sysbuild.cmake @@ -18,27 +18,7 @@ if(SB_CONFIG_NET_CORE_IMAGE_HCI_IPC) CACHE INTERNAL "" ) - # Let's build the net core library first - add_dependencies(${DEFAULT_IMAGE} ${NET_APP}) - - if("${BOARD}" STREQUAL "nrf5340bsim_nrf5340_cpuapp") - # For the simulated board, the application core build will produce the final executable - # for that, we give it the path to the netcore image - set(NET_LIBRARY_PATH ${CMAKE_BINARY_DIR}/${NET_APP}/zephyr/zephyr.elf) - set_property(TARGET ${DEFAULT_IMAGE} APPEND_STRING PROPERTY CONFIG - "CONFIG_NATIVE_SIMULATOR_EXTRA_IMAGE_PATHS=\"${NET_LIBRARY_PATH}\"\n" - ) - endif() + native_simulator_set_child_images(${DEFAULT_IMAGE} ${NET_APP}) endif() -if(("${BOARD}" MATCHES "native") OR ("${BOARD}" MATCHES "bsim")) - # Let's meet the expectation of finding the final executable in zephyr/zephyr.exe - add_custom_target(final_executable - ALL - COMMAND - ${CMAKE_COMMAND} -E copy - ${CMAKE_BINARY_DIR}/${DEFAULT_IMAGE}/zephyr/zephyr.exe - ${CMAKE_BINARY_DIR}/zephyr/zephyr.exe - DEPENDS ${DEFAULT_IMAGE} - ) -endif() +native_simulator_set_final_executable(${DEFAULT_IMAGE}) From 41f4826f272ae38dd1043bfda0c38cc8b6e7128f Mon Sep 17 00:00:00 2001 From: Alberto Escolar Piedras Date: Wed, 29 Nov 2023 18:46:21 +0100 Subject: [PATCH 0628/3723] tests/bsim/bluetooth: Reduce sysbuild boilerplate Reduce the sysbuild boilerplate required for the nrf5340bsim targets. Signed-off-by: Alberto Escolar Piedras --- .../broadcast_audio_sink/sysbuild.cmake | 9 +----- .../unicast_audio_client/sysbuild.cmake | 9 +----- tests/bsim/bluetooth/ll/bis/sysbuild.cmake | 29 ++----------------- tests/bsim/bluetooth/ll/cis/sysbuild.cmake | 29 ++----------------- tests/bsim/bluetooth/ll/conn/sysbuild.cmake | 29 ++----------------- 5 files changed, 11 insertions(+), 94 deletions(-) diff --git a/tests/bsim/bluetooth/audio_samples/broadcast_audio_sink/sysbuild.cmake b/tests/bsim/bluetooth/audio_samples/broadcast_audio_sink/sysbuild.cmake index a922830546d..2bf2920a476 100644 --- a/tests/bsim/bluetooth/audio_samples/broadcast_audio_sink/sysbuild.cmake +++ b/tests/bsim/bluetooth/audio_samples/broadcast_audio_sink/sysbuild.cmake @@ -3,11 +3,4 @@ include(${ZEPHYR_BASE}/samples/bluetooth/broadcast_audio_sink/sysbuild.cmake) -if (NOT ("${SB_CONFIG_NATIVE_SIMULATOR_PRIMARY_MCU_INDEX}" STREQUAL "")) - set_property(TARGET ${NET_APP} APPEND_STRING PROPERTY CONFIG - "CONFIG_NATIVE_SIMULATOR_PRIMARY_MCU_INDEX=${SB_CONFIG_NATIVE_SIMULATOR_PRIMARY_MCU_INDEX}\n" - ) - set_property(TARGET ${DEFAULT_IMAGE} APPEND_STRING PROPERTY CONFIG - "CONFIG_NATIVE_SIMULATOR_PRIMARY_MCU_INDEX=${SB_CONFIG_NATIVE_SIMULATOR_PRIMARY_MCU_INDEX}\n" - ) -endif() +native_simulator_set_primary_mcu_index(${DEFAULT_IMAGE} ${NET_APP}) diff --git a/tests/bsim/bluetooth/audio_samples/unicast_audio_client/sysbuild.cmake b/tests/bsim/bluetooth/audio_samples/unicast_audio_client/sysbuild.cmake index 9686cde1bce..85b85b7cb63 100644 --- a/tests/bsim/bluetooth/audio_samples/unicast_audio_client/sysbuild.cmake +++ b/tests/bsim/bluetooth/audio_samples/unicast_audio_client/sysbuild.cmake @@ -3,11 +3,4 @@ include(${ZEPHYR_BASE}/samples/bluetooth/unicast_audio_client/sysbuild.cmake) -if (NOT ("${SB_CONFIG_NATIVE_SIMULATOR_PRIMARY_MCU_INDEX}" STREQUAL "")) - set_property(TARGET ${NET_APP} APPEND_STRING PROPERTY CONFIG - "CONFIG_NATIVE_SIMULATOR_PRIMARY_MCU_INDEX=${SB_CONFIG_NATIVE_SIMULATOR_PRIMARY_MCU_INDEX}\n" - ) - set_property(TARGET ${DEFAULT_IMAGE} APPEND_STRING PROPERTY CONFIG - "CONFIG_NATIVE_SIMULATOR_PRIMARY_MCU_INDEX=${SB_CONFIG_NATIVE_SIMULATOR_PRIMARY_MCU_INDEX}\n" - ) -endif() +native_simulator_set_primary_mcu_index(${DEFAULT_IMAGE} ${NET_APP}) diff --git a/tests/bsim/bluetooth/ll/bis/sysbuild.cmake b/tests/bsim/bluetooth/ll/bis/sysbuild.cmake index eb75debccd3..69397264edf 100644 --- a/tests/bsim/bluetooth/ll/bis/sysbuild.cmake +++ b/tests/bsim/bluetooth/ll/bis/sysbuild.cmake @@ -16,32 +16,9 @@ if(NOT("${SB_CONFIG_NET_CORE_BOARD}" STREQUAL "")) CACHE INTERNAL "" ) - # For the simulated board, the application core build will produce the final executable - # for that, we give it the path to the netcore image - set(NET_LIBRARY_PATH ${CMAKE_BINARY_DIR}/${NET_APP}/zephyr/zephyr.elf) - set_property(TARGET ${DEFAULT_IMAGE} APPEND_STRING PROPERTY CONFIG - "CONFIG_NATIVE_SIMULATOR_EXTRA_IMAGE_PATHS=\"${NET_LIBRARY_PATH}\"\n" - ) - - if (NOT ("${SB_CONFIG_NATIVE_SIMULATOR_PRIMARY_MCU_INDEX}" STREQUAL "")) - set_property(TARGET ${NET_APP} APPEND_STRING PROPERTY CONFIG - "CONFIG_NATIVE_SIMULATOR_PRIMARY_MCU_INDEX=${SB_CONFIG_NATIVE_SIMULATOR_PRIMARY_MCU_INDEX}\n" - ) - set_property(TARGET ${DEFAULT_IMAGE} APPEND_STRING PROPERTY CONFIG - "CONFIG_NATIVE_SIMULATOR_PRIMARY_MCU_INDEX=${SB_CONFIG_NATIVE_SIMULATOR_PRIMARY_MCU_INDEX}\n" - ) - endif() + native_simulator_set_primary_mcu_index(${DEFAULT_IMAGE} ${NET_APP}) - # Let's build the net core library first - add_dependencies(${DEFAULT_IMAGE} ${NET_APP}) + native_simulator_set_child_images(${DEFAULT_IMAGE} ${NET_APP}) endif() -# Let's meet the expectation of finding the final executable in zephyr/zephyr.exe -add_custom_target(final_executable - ALL - COMMAND - ${CMAKE_COMMAND} -E copy - ${CMAKE_BINARY_DIR}/${DEFAULT_IMAGE}/zephyr/zephyr.exe - ${CMAKE_BINARY_DIR}/zephyr/zephyr.exe - DEPENDS ${DEFAULT_IMAGE} -) +native_simulator_set_final_executable(${DEFAULT_IMAGE}) diff --git a/tests/bsim/bluetooth/ll/cis/sysbuild.cmake b/tests/bsim/bluetooth/ll/cis/sysbuild.cmake index 495c3f4a20d..a1258ecf1f2 100644 --- a/tests/bsim/bluetooth/ll/cis/sysbuild.cmake +++ b/tests/bsim/bluetooth/ll/cis/sysbuild.cmake @@ -16,32 +16,9 @@ if(NOT("${SB_CONFIG_NET_CORE_BOARD}" STREQUAL "")) CACHE INTERNAL "" ) - # For the simulated board, the application core build will produce the final executable - # for that, we give it the path to the netcore image - set(NET_LIBRARY_PATH ${CMAKE_BINARY_DIR}/${NET_APP}/zephyr/zephyr.elf) - set_property(TARGET ${DEFAULT_IMAGE} APPEND_STRING PROPERTY CONFIG - "CONFIG_NATIVE_SIMULATOR_EXTRA_IMAGE_PATHS=\"${NET_LIBRARY_PATH}\"\n" - ) - - if (NOT ("${SB_CONFIG_NATIVE_SIMULATOR_PRIMARY_MCU_INDEX}" STREQUAL "")) - set_property(TARGET ${NET_APP} APPEND_STRING PROPERTY CONFIG - "CONFIG_NATIVE_SIMULATOR_PRIMARY_MCU_INDEX=${SB_CONFIG_NATIVE_SIMULATOR_PRIMARY_MCU_INDEX}\n" - ) - set_property(TARGET ${DEFAULT_IMAGE} APPEND_STRING PROPERTY CONFIG - "CONFIG_NATIVE_SIMULATOR_PRIMARY_MCU_INDEX=${SB_CONFIG_NATIVE_SIMULATOR_PRIMARY_MCU_INDEX}\n" - ) - endif() + native_simulator_set_primary_mcu_index(${DEFAULT_IMAGE} ${NET_APP}) - # Let's build the net core library first - add_dependencies(${DEFAULT_IMAGE} ${NET_APP}) + native_simulator_set_child_images(${DEFAULT_IMAGE} ${NET_APP}) endif() -# Let's meet the expectation of finding the final executable in zephyr/zephyr.exe -add_custom_target(final_executable - ALL - COMMAND - ${CMAKE_COMMAND} -E copy - ${CMAKE_BINARY_DIR}/${DEFAULT_IMAGE}/zephyr/zephyr.exe - ${CMAKE_BINARY_DIR}/zephyr/zephyr.exe - DEPENDS ${DEFAULT_IMAGE} -) +native_simulator_set_final_executable(${DEFAULT_IMAGE}) diff --git a/tests/bsim/bluetooth/ll/conn/sysbuild.cmake b/tests/bsim/bluetooth/ll/conn/sysbuild.cmake index 2294fd5bb5e..4dfa34ef519 100644 --- a/tests/bsim/bluetooth/ll/conn/sysbuild.cmake +++ b/tests/bsim/bluetooth/ll/conn/sysbuild.cmake @@ -11,32 +11,9 @@ if(NOT("${SB_CONFIG_NET_CORE_BOARD}" STREQUAL "")) BOARD ${SB_CONFIG_NET_CORE_BOARD} ) - # For the simulated board, the application core build will produce the final executable - # for that, we give it the path to the netcore image - set(NET_LIBRARY_PATH ${CMAKE_BINARY_DIR}/${NET_APP}/zephyr/zephyr.elf) - set_property(TARGET ${DEFAULT_IMAGE} APPEND_STRING PROPERTY CONFIG - "CONFIG_NATIVE_SIMULATOR_EXTRA_IMAGE_PATHS=\"${NET_LIBRARY_PATH}\"\n" - ) - - if (NOT ("${SB_CONFIG_NATIVE_SIMULATOR_PRIMARY_MCU_INDEX}" STREQUAL "")) - set_property(TARGET ${NET_APP} APPEND_STRING PROPERTY CONFIG - "CONFIG_NATIVE_SIMULATOR_PRIMARY_MCU_INDEX=${SB_CONFIG_NATIVE_SIMULATOR_PRIMARY_MCU_INDEX}\n" - ) - set_property(TARGET ${DEFAULT_IMAGE} APPEND_STRING PROPERTY CONFIG - "CONFIG_NATIVE_SIMULATOR_PRIMARY_MCU_INDEX=${SB_CONFIG_NATIVE_SIMULATOR_PRIMARY_MCU_INDEX}\n" - ) - endif() + native_simulator_set_primary_mcu_index(${DEFAULT_IMAGE} ${NET_APP}) - # Let's build the net core library first - add_dependencies(${DEFAULT_IMAGE} ${NET_APP}) + native_simulator_set_child_images(${DEFAULT_IMAGE} ${NET_APP}) endif() -# Let's meet the expectation of finding the final executable in zephyr/zephyr.exe -add_custom_target(final_executable - ALL - COMMAND - ${CMAKE_COMMAND} -E copy - ${CMAKE_BINARY_DIR}/${DEFAULT_IMAGE}/zephyr/zephyr.exe - ${CMAKE_BINARY_DIR}/zephyr/zephyr.exe - DEPENDS ${DEFAULT_IMAGE} -) +native_simulator_set_final_executable(${DEFAULT_IMAGE}) From b02fc27464c46076a62e2401e51ce7ae0302de95 Mon Sep 17 00:00:00 2001 From: Alberto Escolar Piedras Date: Wed, 29 Nov 2023 18:46:52 +0100 Subject: [PATCH 0629/3723] samples/subsys/logging/multidomain: Reduce sysbuild boilerplate Reduce the sysbuild boilerplate required for the nrf5340bsim targets Signed-off-by: Alberto Escolar Piedras --- .../subsys/logging/multidomain/sysbuild.cmake | 22 ++----------------- 1 file changed, 2 insertions(+), 20 deletions(-) diff --git a/samples/subsys/logging/multidomain/sysbuild.cmake b/samples/subsys/logging/multidomain/sysbuild.cmake index e50f47b6db1..496a7a03f9d 100644 --- a/samples/subsys/logging/multidomain/sysbuild.cmake +++ b/samples/subsys/logging/multidomain/sysbuild.cmake @@ -15,24 +15,6 @@ ExternalZephyrProject_Add( BOARD ${SB_CONFIG_NET_CORE_BOARD} ) -if("${BOARD}" STREQUAL "nrf5340bsim_nrf5340_cpuapp") - # For the simulated board, the application core build will produce the final executable - # for that, we give it the path to the netcore image - set(NET_LIBRARY_PATH ${CMAKE_BINARY_DIR}/${NET_APP}/zephyr/zephyr.elf) - set_property(TARGET ${DEFAULT_IMAGE} APPEND_STRING PROPERTY CONFIG - "CONFIG_NATIVE_SIMULATOR_EXTRA_IMAGE_PATHS=\"${NET_LIBRARY_PATH}\"\n" - ) +native_simulator_set_child_images(${DEFAULT_IMAGE} ${NET_APP}) - # Let's build the net core library first - add_dependencies(${DEFAULT_IMAGE} ${NET_APP}) - - # Let's meet users expectations of finding the final executable in zephyr/zephyr.exe - add_custom_target(final_executable - ALL - COMMAND - ${CMAKE_COMMAND} -E copy - ${CMAKE_BINARY_DIR}/${DEFAULT_IMAGE}/zephyr/zephyr.exe - ${CMAKE_BINARY_DIR}/zephyr/zephyr.exe - DEPENDS ${DEFAULT_IMAGE} - ) -endif() +native_simulator_set_final_executable(${DEFAULT_IMAGE}) From cbce3383d1e7cbdb23c6caac6d1bf9a5d8236091 Mon Sep 17 00:00:00 2001 From: Alberto Escolar Piedras Date: Wed, 29 Nov 2023 18:47:45 +0100 Subject: [PATCH 0630/3723] samples/boards/nrf/nrf53_sync_rtc: Reduce sysbuild boilerplate Reduce the sysbuild boilerplate required for the nrf5340bsim targets Signed-off-by: Alberto Escolar Piedras --- .../boards/nrf/nrf53_sync_rtc/sysbuild.cmake | 22 ++----------------- 1 file changed, 2 insertions(+), 20 deletions(-) diff --git a/samples/boards/nrf/nrf53_sync_rtc/sysbuild.cmake b/samples/boards/nrf/nrf53_sync_rtc/sysbuild.cmake index a5d1eb9874f..0c97244fd7b 100644 --- a/samples/boards/nrf/nrf53_sync_rtc/sysbuild.cmake +++ b/samples/boards/nrf/nrf53_sync_rtc/sysbuild.cmake @@ -15,24 +15,6 @@ ExternalZephyrProject_Add( BOARD ${SB_CONFIG_NET_CORE_BOARD} ) -if("${BOARD}" STREQUAL "nrf5340bsim_nrf5340_cpuapp") - # For the simulated board, the application core build will produce the final executable - # for that, we give it the path to the netcore image - set(NET_LIBRARY_PATH ${CMAKE_BINARY_DIR}/${REMOTE_APP}/zephyr/zephyr.elf) - set_property(TARGET ${DEFAULT_IMAGE} APPEND_STRING PROPERTY CONFIG - "CONFIG_NATIVE_SIMULATOR_EXTRA_IMAGE_PATHS=\"${NET_LIBRARY_PATH}\"\n" - ) +native_simulator_set_child_images(${DEFAULT_IMAGE} ${REMOTE_APP}) - # Let's build the net core library first - add_dependencies(${DEFAULT_IMAGE} ${REMOTE_APP}) - - # Let's meet users expectations of finding the final executable in zephyr/zephyr.exe - add_custom_target(final_executable - ALL - COMMAND - ${CMAKE_COMMAND} -E copy - ${CMAKE_BINARY_DIR}/${DEFAULT_IMAGE}/zephyr/zephyr.exe - ${CMAKE_BINARY_DIR}/zephyr/zephyr.exe - DEPENDS ${DEFAULT_IMAGE} - ) -endif() +native_simulator_set_final_executable(${DEFAULT_IMAGE}) From d2151aa114cbf389fdec972119b218f7b39f3c9b Mon Sep 17 00:00:00 2001 From: Alberto Escolar Piedras Date: Wed, 29 Nov 2023 18:48:02 +0100 Subject: [PATCH 0631/3723] samples/drivers/mbox: Reduce sysbuild boilerplate Reduce the sysbuild boilerplate required for the nrf5340bsim targets Signed-off-by: Alberto Escolar Piedras --- samples/drivers/mbox/sysbuild.cmake | 22 ++-------------------- 1 file changed, 2 insertions(+), 20 deletions(-) diff --git a/samples/drivers/mbox/sysbuild.cmake b/samples/drivers/mbox/sysbuild.cmake index 1bd6a00ae9e..a8dfb8ebdf4 100644 --- a/samples/drivers/mbox/sysbuild.cmake +++ b/samples/drivers/mbox/sysbuild.cmake @@ -15,24 +15,6 @@ ExternalZephyrProject_Add( BOARD ${SB_CONFIG_REMOTE_BOARD} ) -if("${BOARD}" STREQUAL "nrf5340bsim_nrf5340_cpuapp") - # For the simulated board, the application core build will produce the final executable - # for that, we give it the path to the netcore image - set(NET_LIBRARY_PATH ${CMAKE_BINARY_DIR}/${REMOTE_APP}/zephyr/zephyr.elf) - set_property(TARGET ${DEFAULT_IMAGE} APPEND_STRING PROPERTY CONFIG - "CONFIG_NATIVE_SIMULATOR_EXTRA_IMAGE_PATHS=\"${NET_LIBRARY_PATH}\"\n" - ) +native_simulator_set_child_images(${DEFAULT_IMAGE} ${REMOTE_APP}) - # Let's build the net core library first - add_dependencies(${DEFAULT_IMAGE} ${REMOTE_APP}) - - # Let's meet users expectations of finding the final executable in zephyr/zephyr.exe - add_custom_target(final_executable - ALL - COMMAND - ${CMAKE_COMMAND} -E copy - ${CMAKE_BINARY_DIR}/${DEFAULT_IMAGE}/zephyr/zephyr.exe - ${CMAKE_BINARY_DIR}/zephyr/zephyr.exe - DEPENDS ${DEFAULT_IMAGE} - ) -endif() +native_simulator_set_final_executable(${DEFAULT_IMAGE}) From e2cd8d64167b00ebc328a1459355df2cc84d3394 Mon Sep 17 00:00:00 2001 From: Christopher Friedt Date: Sun, 28 May 2023 12:27:06 -0400 Subject: [PATCH 0632/3723] dts: bindings: dma: add bindings for an emulated dma controller Many driver APIs are opting to provide an `emul` driver implementation that can be used for a number of purposes. - providing an ideal / model driver for reference - configurable backends - seamless integration with device tree - support for native posix, qemu, and any other board - fast regression testing of app and library code Provide an initial set of bindings for `zephyr,dma-emul` devices. Signed-off-by: Christopher Friedt --- dts/bindings/dma/zephyr,dma-emul.yaml | 20 ++++++++++++++++++++ 1 file changed, 20 insertions(+) create mode 100644 dts/bindings/dma/zephyr,dma-emul.yaml diff --git a/dts/bindings/dma/zephyr,dma-emul.yaml b/dts/bindings/dma/zephyr,dma-emul.yaml new file mode 100644 index 00000000000..b055062cb72 --- /dev/null +++ b/dts/bindings/dma/zephyr,dma-emul.yaml @@ -0,0 +1,20 @@ +# Copyright 2023 Meta +# SPDX-License-Identifier: Apache-2.0 + +description: Emulated DMA Controller + +include: dma-controller.yaml + +compatible: zephyr,dma-emul + +properties: + stack-size: + type: int + required: true + description: > + Stack size (in bytes) for the instance-specific work_q thread. + + priority: + type: int + description: > + Priority for the instance-specific work_q thread. From 86fc43c939c623472c512914cd2631579d89d768 Mon Sep 17 00:00:00 2001 From: Christopher Friedt Date: Sun, 28 May 2023 12:34:14 -0400 Subject: [PATCH 0633/3723] drivers: dma: add emulated dma driver Add an emulated DMA driver. Emulation drivers are great to have for each driver API for multiple reasons: - providing an ideal / model driver for reference - potential for configurable backend support - seamless integration with device tree - multi-instance, etc, for all supported boards - fast regression testing of app and library code Since many other drivers and lbraries depend on DMA, this might help us to increase test coverage. Signed-off-by: Christopher Friedt --- drivers/dma/CMakeLists.txt | 1 + drivers/dma/Kconfig | 2 + drivers/dma/Kconfig.emul | 9 + drivers/dma/dma_emul.c | 617 +++++++++++++++++++++++++++++++++++++ 4 files changed, 629 insertions(+) create mode 100644 drivers/dma/Kconfig.emul create mode 100644 drivers/dma/dma_emul.c diff --git a/drivers/dma/CMakeLists.txt b/drivers/dma/CMakeLists.txt index e65c3726622..75eef49a32c 100644 --- a/drivers/dma/CMakeLists.txt +++ b/drivers/dma/CMakeLists.txt @@ -38,3 +38,4 @@ zephyr_library_sources_ifdef(CONFIG_DMA_ANDES_ATCDMAC300 dma_andes_atcdmac300.c) zephyr_library_sources_ifdef(CONFIG_DMA_SEDI dma_sedi.c) zephyr_library_sources_ifdef(CONFIG_DMA_SMARTBOND dma_smartbond.c) zephyr_library_sources_ifdef(CONFIG_DMA_NXP_SOF_HOST_DMA dma_nxp_sof_host_dma.c) +zephyr_library_sources_ifdef(CONFIG_DMA_EMUL dma_emul.c) diff --git a/drivers/dma/Kconfig b/drivers/dma/Kconfig index e24386558cd..7d2b7f94d90 100644 --- a/drivers/dma/Kconfig +++ b/drivers/dma/Kconfig @@ -72,4 +72,6 @@ source "drivers/dma/Kconfig.smartbond" source "drivers/dma/Kconfig.nxp_sof_host_dma" +source "drivers/dma/Kconfig.emul" + endif # DMA diff --git a/drivers/dma/Kconfig.emul b/drivers/dma/Kconfig.emul new file mode 100644 index 00000000000..595f577f3d1 --- /dev/null +++ b/drivers/dma/Kconfig.emul @@ -0,0 +1,9 @@ +# Copyright (c) 2023 Meta +# SPDX-License-Identifier: Apache-2.0 + +config DMA_EMUL + bool "Emulated DMA driver [EXPERIMENTAL]" + depends on DT_HAS_ZEPHYR_DMA_EMUL_ENABLED + select EXPERIMENTAL + help + Emulated DMA Driver diff --git a/drivers/dma/dma_emul.c b/drivers/dma/dma_emul.c new file mode 100644 index 00000000000..235593df624 --- /dev/null +++ b/drivers/dma/dma_emul.c @@ -0,0 +1,617 @@ +/* + * Copyright (c) 2023, Meta + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include +#include +#include + +#include +#include +#include +#include +#include +#include + +#define DT_DRV_COMPAT zephyr_dma_emul + +#ifdef CONFIG_DMA_64BIT +#define dma_addr_t uint64_t +#else +#define dma_addr_t uint32_t +#endif + +enum dma_emul_channel_state { + DMA_EMUL_CHANNEL_UNUSED, + DMA_EMUL_CHANNEL_LOADED, + DMA_EMUL_CHANNEL_STARTED, + DMA_EMUL_CHANNEL_STOPPED, +}; + +struct dma_emul_xfer_desc { + struct dma_config config; +}; + +struct dma_emul_work { + const struct device *dev; + uint32_t channel; + struct k_work work; +}; + +struct dma_emul_config { + uint32_t channel_mask; + size_t num_channels; + size_t num_requests; + size_t addr_align; + size_t size_align; + size_t copy_align; + + k_thread_stack_t *work_q_stack; + size_t work_q_stack_size; + int work_q_priority; + + /* points to an array of size num_channels */ + struct dma_emul_xfer_desc *xfer; + /* points to an array of size num_channels * num_requests */ + struct dma_block_config *block; +}; + +struct dma_emul_data { + struct dma_context dma_ctx; + atomic_t *channels_atomic; + struct k_spinlock lock; + struct k_work_q work_q; + struct dma_emul_work work; +}; + +static void dma_emul_work_handler(struct k_work *work); + +LOG_MODULE_REGISTER(dma_emul, CONFIG_DMA_LOG_LEVEL); + +static inline bool dma_emul_xfer_is_error_status(int status) +{ + return status < 0; +} + +static inline const char *const dma_emul_channel_state_to_string(enum dma_emul_channel_state state) +{ + switch (state) { + case DMA_EMUL_CHANNEL_UNUSED: + return "UNUSED"; + case DMA_EMUL_CHANNEL_LOADED: + return "LOADED"; + case DMA_EMUL_CHANNEL_STARTED: + return "STARTED"; + case DMA_EMUL_CHANNEL_STOPPED: + return "STOPPED"; + default: + return "(invalid)"; + }; +} + +/* + * Repurpose the "_reserved" field for keeping track of internal + * channel state. + * + * Note: these must be called with data->lock locked! + */ +static enum dma_emul_channel_state dma_emul_get_channel_state(const struct device *dev, + uint32_t channel) +{ + const struct dma_emul_config *config = dev->config; + + __ASSERT_NO_MSG(channel < config->num_channels); + + return (enum dma_emul_channel_state)config->xfer[channel].config._reserved; +} + +static void dma_emul_set_channel_state(const struct device *dev, uint32_t channel, + enum dma_emul_channel_state state) +{ + const struct dma_emul_config *config = dev->config; + + LOG_DBG("setting channel %u state to %s", channel, dma_emul_channel_state_to_string(state)); + + __ASSERT_NO_MSG(channel < config->num_channels); + __ASSERT_NO_MSG(state >= DMA_EMUL_CHANNEL_UNUSED && state <= DMA_EMUL_CHANNEL_STOPPED); + + config->xfer[channel].config._reserved = state; +} + +static const char *dma_emul_xfer_config_to_string(const struct dma_config *cfg) +{ + static char buffer[1024]; + + snprintf(buffer, sizeof(buffer), + "{" + "\n\tslot: %u" + "\n\tchannel_direction: %u" + "\n\tcomplete_callback_en: %u" + "\n\terror_callback_en: %u" + "\n\tsource_handshake: %u" + "\n\tdest_handshake: %u" + "\n\tchannel_priority: %u" + "\n\tsource_chaining_en: %u" + "\n\tdest_chaining_en: %u" + "\n\tlinked_channel: %u" + "\n\tcyclic: %u" + "\n\t_reserved: %u" + "\n\tsource_data_size: %u" + "\n\tdest_data_size: %u" + "\n\tsource_burst_length: %u" + "\n\tdest_burst_length: %u" + "\n\tblock_count: %u" + "\n\thead_block: %p" + "\n\tuser_data: %p" + "\n\tdma_callback: %p" + "\n}", + cfg->dma_slot, cfg->channel_direction, cfg->complete_callback_en, + cfg->error_callback_en, cfg->source_handshake, cfg->dest_handshake, + cfg->channel_priority, cfg->source_chaining_en, cfg->dest_chaining_en, + cfg->linked_channel, cfg->cyclic, cfg->_reserved, cfg->source_data_size, + cfg->dest_data_size, cfg->source_burst_length, cfg->dest_burst_length, + cfg->block_count, cfg->head_block, cfg->user_data, cfg->dma_callback); + + return buffer; +} + +static const char *dma_emul_block_config_to_string(const struct dma_block_config *cfg) +{ + static char buffer[1024]; + + snprintf(buffer, sizeof(buffer), + "{" + "\n\tsource_address: %p" + "\n\tdest_address: %p" + "\n\tsource_gather_interval: %u" + "\n\tdest_scatter_interval: %u" + "\n\tdest_scatter_count: %u" + "\n\tsource_gather_count: %u" + "\n\tblock_size: %u" + "\n\tnext_block: %p" + "\n\tsource_gather_en: %u" + "\n\tdest_scatter_en: %u" + "\n\tsource_addr_adj: %u" + "\n\tdest_addr_adj: %u" + "\n\tsource_reload_en: %u" + "\n\tdest_reload_en: %u" + "\n\tfifo_mode_control: %u" + "\n\tflow_control_mode: %u" + "\n\t_reserved: %u" + "\n}", + (void *)cfg->source_address, (void *)cfg->dest_address, + cfg->source_gather_interval, cfg->dest_scatter_interval, cfg->dest_scatter_count, + cfg->source_gather_count, cfg->block_size, cfg->next_block, cfg->source_gather_en, + cfg->dest_scatter_en, cfg->source_addr_adj, cfg->dest_addr_adj, + cfg->source_reload_en, cfg->dest_reload_en, cfg->fifo_mode_control, + cfg->flow_control_mode, cfg->_reserved + + ); + + return buffer; +} + +static void dma_emul_work_handler(struct k_work *work) +{ + size_t i; + size_t bytes; + uint32_t channel; + k_spinlock_key_t key; + struct dma_block_config block; + struct dma_config xfer_config; + enum dma_emul_channel_state state; + struct dma_emul_xfer_desc *xfer; + struct dma_emul_work *dma_work = CONTAINER_OF(work, struct dma_emul_work, work); + const struct device *dev = dma_work->dev; + struct dma_emul_data *data = dev->data; + const struct dma_emul_config *config = dev->config; + + channel = dma_work->channel; + + do { + key = k_spin_lock(&data->lock); + xfer = &config->xfer[channel]; + /* + * copy the dma_config so we don't have to worry about + * it being asynchronously updated. + */ + memcpy(&xfer_config, &xfer->config, sizeof(xfer_config)); + k_spin_unlock(&data->lock, key); + + LOG_DBG("processing xfer %p for channel %u", xfer, channel); + for (i = 0; i < xfer_config.block_count; ++i) { + + LOG_DBG("processing block %zu", i); + + key = k_spin_lock(&data->lock); + /* + * copy the dma_block_config so we don't have to worry about + * it being asynchronously updated. + */ + memcpy(&block, + &config->block[channel * config->num_requests + + xfer_config.dma_slot + i], + sizeof(block)); + k_spin_unlock(&data->lock, key); + + /* transfer data in bursts */ + for (bytes = MIN(block.block_size, xfer_config.dest_burst_length); + bytes > 0; block.block_size -= bytes, block.source_address += bytes, + block.dest_address += bytes, + bytes = MIN(block.block_size, xfer_config.dest_burst_length)) { + + key = k_spin_lock(&data->lock); + state = dma_emul_get_channel_state(dev, channel); + k_spin_unlock(&data->lock, key); + + if (state == DMA_EMUL_CHANNEL_STOPPED) { + LOG_DBG("asynchronously canceled"); + if (xfer_config.error_callback_en) { + xfer_config.dma_callback(dev, xfer_config.user_data, + channel, -ECANCELED); + } else { + LOG_DBG("error_callback_en is not set (async " + "cancel)"); + } + goto out; + } + + __ASSERT_NO_MSG(state == DMA_EMUL_CHANNEL_STARTED); + + /* + * FIXME: create a backend API (memcpy, TCP/UDP socket, etc) + * Simple copy for now + */ + memcpy((void *)(uintptr_t)block.dest_address, + (void *)(uintptr_t)block.source_address, bytes); + } + } + + key = k_spin_lock(&data->lock); + dma_emul_set_channel_state(dev, channel, DMA_EMUL_CHANNEL_STOPPED); + k_spin_unlock(&data->lock, key); + + /* FIXME: tests/drivers/dma/chan_blen_transfer/ does not set complete_callback_en */ + if (true) { + xfer_config.dma_callback(dev, xfer_config.user_data, channel, + DMA_STATUS_COMPLETE); + } else { + LOG_DBG("complete_callback_en is not set"); + } + + if (xfer_config.source_chaining_en || xfer_config.dest_chaining_en) { + LOG_DBG("%s(): Linked channel %u -> %u", __func__, channel, + xfer_config.linked_channel); + __ASSERT_NO_MSG(channel != xfer_config.linked_channel); + channel = xfer_config.linked_channel; + } else { + LOG_DBG("%s(): done!", __func__); + break; + } + } while (true); + +out: + return; +} + +static bool dma_emul_config_valid(const struct device *dev, uint32_t channel, + const struct dma_config *xfer_config) +{ + size_t i; + struct dma_block_config *block; + const struct dma_emul_config *config = dev->config; + + if (xfer_config->dma_slot >= config->num_requests) { + LOG_ERR("invalid dma_slot %u", xfer_config->dma_slot); + return false; + } + + if (channel >= config->num_channels) { + LOG_ERR("invalid DMA channel %u", channel); + return false; + } + + if (xfer_config->dest_burst_length != xfer_config->source_burst_length) { + LOG_ERR("burst length does not agree. source: %u dest: %u ", + xfer_config->source_burst_length, xfer_config->dest_burst_length); + return false; + } + + for (i = 0, block = xfer_config->head_block; i < xfer_config->block_count; + ++i, block = block->next_block) { + if (block == NULL) { + LOG_ERR("block %zu / %u is NULL", i + 1, xfer_config->block_count); + return false; + } + + if (i >= config->num_requests) { + LOG_ERR("not enough slots to store block %zu / %u", i + 1, + xfer_config->block_count); + return false; + } + } + + /* + * FIXME: + * + * Need to verify all of the fields in struct dma_config with different DT + * configurations so that the driver model is at least consistent and + * verified by CI. + */ + + return true; +} + +static int dma_emul_configure(const struct device *dev, uint32_t channel, + struct dma_config *xfer_config) +{ + size_t i; + int ret = 0; + size_t block_idx; + k_spinlock_key_t key; + struct dma_block_config *block; + struct dma_block_config *block_it; + enum dma_emul_channel_state state; + struct dma_emul_xfer_desc *xfer; + struct dma_emul_data *data = dev->data; + const struct dma_emul_config *config = dev->config; + + if (!dma_emul_config_valid(dev, channel, xfer_config)) { + return -EINVAL; + } + + key = k_spin_lock(&data->lock); + xfer = &config->xfer[channel]; + + LOG_DBG("%s():\nchannel: %u\nconfig: %s", __func__, channel, + dma_emul_xfer_config_to_string(xfer_config)); + + block_idx = channel * config->num_requests + xfer_config->dma_slot; + + block = &config->block[channel * config->num_requests + xfer_config->dma_slot]; + state = dma_emul_get_channel_state(dev, channel); + switch (state) { + case DMA_EMUL_CHANNEL_UNUSED: + case DMA_EMUL_CHANNEL_STOPPED: + /* copy the configuration into the driver */ + memcpy(&xfer->config, xfer_config, sizeof(xfer->config)); + + /* copy all blocks into slots */ + for (i = 0, block_it = xfer_config->head_block; i < xfer_config->block_count; + ++i, block_it = block_it->next_block, ++block) { + __ASSERT_NO_MSG(block_it != NULL); + + LOG_DBG("block_config %s", dma_emul_block_config_to_string(block_it)); + + memcpy(block, block_it, sizeof(*block)); + } + dma_emul_set_channel_state(dev, channel, DMA_EMUL_CHANNEL_LOADED); + + break; + default: + LOG_ERR("attempt to configure DMA in state %d", state); + ret = -EBUSY; + } + k_spin_unlock(&data->lock, key); + + return ret; +} + +static int dma_emul_reload(const struct device *dev, uint32_t channel, dma_addr_t src, + dma_addr_t dst, size_t size) +{ + LOG_DBG("%s()", __func__); + + return -ENOSYS; +} + +static int dma_emul_start(const struct device *dev, uint32_t channel) +{ + int ret = 0; + k_spinlock_key_t key; + enum dma_emul_channel_state state; + struct dma_emul_xfer_desc *xfer; + struct dma_config *xfer_config; + struct dma_emul_data *data = dev->data; + const struct dma_emul_config *config = dev->config; + + LOG_DBG("%s(channel: %u)", __func__, channel); + + if (channel >= config->num_channels) { + return -EINVAL; + } + + key = k_spin_lock(&data->lock); + xfer = &config->xfer[channel]; + state = dma_emul_get_channel_state(dev, channel); + switch (state) { + case DMA_EMUL_CHANNEL_STARTED: + /* start after being started already is a no-op */ + break; + case DMA_EMUL_CHANNEL_LOADED: + case DMA_EMUL_CHANNEL_STOPPED: + data->work.channel = channel; + while (true) { + dma_emul_set_channel_state(dev, channel, DMA_EMUL_CHANNEL_STARTED); + + xfer_config = &config->xfer[channel].config; + if (xfer_config->source_chaining_en || xfer_config->dest_chaining_en) { + LOG_DBG("%s(): Linked channel %u -> %u", __func__, channel, + xfer_config->linked_channel); + channel = xfer_config->linked_channel; + } else { + break; + } + } + ret = k_work_submit_to_queue(&data->work_q, &data->work.work); + ret = (ret < 0) ? ret : 0; + break; + default: + LOG_ERR("attempt to start dma in invalid state %d", state); + ret = -EIO; + break; + } + k_spin_unlock(&data->lock, key); + + return ret; +} + +static int dma_emul_stop(const struct device *dev, uint32_t channel) +{ + k_spinlock_key_t key; + struct dma_emul_data *data = dev->data; + + key = k_spin_lock(&data->lock); + dma_emul_set_channel_state(dev, channel, DMA_EMUL_CHANNEL_STOPPED); + k_spin_unlock(&data->lock, key); + + return 0; +} + +static int dma_emul_suspend(const struct device *dev, uint32_t channel) +{ + LOG_DBG("%s()", __func__); + + return -ENOSYS; +} + +static int dma_emul_resume(const struct device *dev, uint32_t channel) +{ + LOG_DBG("%s()", __func__); + + return -ENOSYS; +} + +static int dma_emul_get_status(const struct device *dev, uint32_t channel, + struct dma_status *status) +{ + LOG_DBG("%s()", __func__); + + return -ENOSYS; +} + +static int dma_emul_get_attribute(const struct device *dev, uint32_t type, uint32_t *value) +{ + LOG_DBG("%s()", __func__); + + return -ENOSYS; +} + +static bool dma_emul_chan_filter(const struct device *dev, int channel, void *filter_param) +{ + bool success; + k_spinlock_key_t key; + struct dma_emul_data *data = dev->data; + + key = k_spin_lock(&data->lock); + /* lets assume the struct dma_context handles races properly */ + success = dma_emul_get_channel_state(dev, channel) == DMA_EMUL_CHANNEL_UNUSED; + k_spin_unlock(&data->lock, key); + + return success; +} + +static const struct dma_driver_api dma_emul_driver_api = { + .config = dma_emul_configure, + .reload = dma_emul_reload, + .start = dma_emul_start, + .stop = dma_emul_stop, + .suspend = dma_emul_suspend, + .resume = dma_emul_resume, + .get_status = dma_emul_get_status, + .get_attribute = dma_emul_get_attribute, + .chan_filter = dma_emul_chan_filter, +}; + +#ifdef CONFIG_PM_DEVICE +static int gpio_emul_pm_device_pm_action(const struct device *dev, enum pm_device_action action) +{ + ARG_UNUSED(dev); + ARG_UNUSED(action); + + return 0; +} +#endif + +static int dma_emul_init(const struct device *dev) +{ + struct dma_emul_data *data = dev->data; + const struct dma_emul_config *config = dev->config; + + data->work.dev = dev; + data->dma_ctx.magic = DMA_MAGIC; + data->dma_ctx.dma_channels = config->num_channels; + data->dma_ctx.atomic = data->channels_atomic; + + k_work_queue_init(&data->work_q); + k_work_init(&data->work.work, dma_emul_work_handler); + k_work_queue_start(&data->work_q, config->work_q_stack, config->work_q_stack_size, + config->work_q_priority, NULL); + + return 0; +} + +#define DMA_EMUL_INST_HAS_PROP(_inst, _prop) DT_NODE_HAS_PROP(DT_DRV_INST(_inst), _prop) + +#define DMA_EMUL_INST_CHANNEL_MASK(_inst) \ + DT_INST_PROP_OR(_inst, dma_channel_mask, \ + DMA_EMUL_INST_HAS_PROP(_inst, dma_channels) \ + ? ((DT_INST_PROP(_inst, dma_channels) > 0) \ + ? BIT_MASK(DT_INST_PROP_OR(_inst, dma_channels, 0)) \ + : 0) \ + : 0) + +#define DMA_EMUL_INST_NUM_CHANNELS(_inst) \ + DT_INST_PROP_OR(_inst, dma_channels, \ + DMA_EMUL_INST_HAS_PROP(_inst, dma_channel_mask) \ + ? POPCOUNT(DT_INST_PROP_OR(_inst, dma_channel_mask, 0)) \ + : 0) + +#define DMA_EMUL_INST_NUM_REQUESTS(_inst) DT_INST_PROP_OR(_inst, dma_requests, 1) + +#define DEFINE_DMA_EMUL(_inst) \ + BUILD_ASSERT(DMA_EMUL_INST_HAS_PROP(_inst, dma_channel_mask) || \ + DMA_EMUL_INST_HAS_PROP(_inst, dma_channels), \ + "at least one of dma_channel_mask or dma_channels must be provided"); \ + \ + BUILD_ASSERT(DMA_EMUL_INST_NUM_CHANNELS(_inst) <= 32, "invalid dma-channels property"); \ + \ + static K_THREAD_STACK_DEFINE(work_q_stack_##_inst, DT_INST_PROP(_inst, stack_size)); \ + \ + static struct dma_emul_xfer_desc \ + dma_emul_xfer_desc_##_inst[DMA_EMUL_INST_NUM_CHANNELS(_inst)]; \ + \ + static struct dma_block_config \ + dma_emul_block_config_##_inst[DMA_EMUL_INST_NUM_CHANNELS(_inst) * \ + DMA_EMUL_INST_NUM_REQUESTS(_inst)]; \ + \ + static const struct dma_emul_config dma_emul_config_##_inst = { \ + .channel_mask = DMA_EMUL_INST_CHANNEL_MASK(_inst), \ + .num_channels = DMA_EMUL_INST_NUM_CHANNELS(_inst), \ + .num_requests = DMA_EMUL_INST_NUM_REQUESTS(_inst), \ + .addr_align = DT_INST_PROP_OR(_inst, dma_buf_addr_alignment, 1), \ + .size_align = DT_INST_PROP_OR(_inst, dma_buf_size_alignment, 1), \ + .copy_align = DT_INST_PROP_OR(_inst, dma_copy_alignment, 1), \ + .work_q_stack = (k_thread_stack_t *)&work_q_stack_##_inst, \ + .work_q_stack_size = K_THREAD_STACK_SIZEOF(work_q_stack_##_inst), \ + .work_q_priority = DT_INST_PROP_OR(_inst, priority, 0), \ + .xfer = dma_emul_xfer_desc_##_inst, \ + .block = dma_emul_block_config_##_inst, \ + }; \ + \ + static ATOMIC_DEFINE(dma_emul_channels_atomic_##_inst, \ + DT_INST_PROP_OR(_inst, dma_channels, 0)); \ + \ + static struct dma_emul_data dma_emul_data_##_inst = { \ + .channels_atomic = dma_emul_channels_atomic_##_inst, \ + }; \ + \ + PM_DEVICE_DT_INST_DEFINE(_inst, dma_emul_pm_device_pm_action); \ + \ + DEVICE_DT_INST_DEFINE(_inst, dma_emul_init, PM_DEVICE_DT_INST_GET(_inst), \ + &dma_emul_data_##_inst, &dma_emul_config_##_inst, POST_KERNEL, \ + CONFIG_DMA_INIT_PRIORITY, &dma_emul_driver_api); + +DT_INST_FOREACH_STATUS_OKAY(DEFINE_DMA_EMUL) From 09ff569c9ec766e3fd5f34fab69b7e1649157d3a Mon Sep 17 00:00:00 2001 From: Christopher Friedt Date: Sun, 28 May 2023 12:40:23 -0400 Subject: [PATCH 0634/3723] boards: posix: add dma support to native_posix boards Like other driver APIs, we can add an `emul` variant to `native_posix` and `native_posix_64` that should allow us to simplify applilcation and library development and to also increase test coverage in CI. Signed-off-by: Christopher Friedt --- boards/posix/native_posix/native_posix.yaml | 1 + boards/posix/native_posix/native_posix_64.yaml | 1 + boards/posix/native_sim/native_sim.dts | 6 ++++++ 3 files changed, 8 insertions(+) diff --git a/boards/posix/native_posix/native_posix.yaml b/boards/posix/native_posix/native_posix.yaml index a7899f1fccd..d3ba08cc9a6 100644 --- a/boards/posix/native_posix/native_posix.yaml +++ b/boards/posix/native_posix/native_posix.yaml @@ -11,6 +11,7 @@ toolchain: supported: - can - counter + - dma - eeprom - netif:eth - usb_device diff --git a/boards/posix/native_posix/native_posix_64.yaml b/boards/posix/native_posix/native_posix_64.yaml index 56ad340f176..544dac9cc2a 100644 --- a/boards/posix/native_posix/native_posix_64.yaml +++ b/boards/posix/native_posix/native_posix_64.yaml @@ -11,6 +11,7 @@ toolchain: supported: - can - counter + - dma - eeprom - netif:eth - usb_device diff --git a/boards/posix/native_sim/native_sim.dts b/boards/posix/native_sim/native_sim.dts index 73c703ece0b..26a38593484 100644 --- a/boards/posix/native_sim/native_sim.dts +++ b/boards/posix/native_sim/native_sim.dts @@ -216,4 +216,10 @@ #io-channel-cells = <1>; status = "okay"; }; + + dma: dma { + compatible = "zephyr,dma-emul"; + #dma-cells = <1>; + stack-size = <4096>; + }; }; From 88425fe3bba191162df4ab798aad4f0938d079a7 Mon Sep 17 00:00:00 2001 From: Christopher Friedt Date: Sun, 28 May 2023 12:42:23 -0400 Subject: [PATCH 0635/3723] tests: drivers: dma: test dma_emul driver on native_posix boards Add support for testing the `dma_emul` driver which simply uses software emulation (i.e. asynchronous memcpy in a workqueue) for performing DMA operations. Signed-off-by: Christopher Friedt --- .../dma/chan_blen_transfer/boards/native_posix.conf | 1 + .../chan_blen_transfer/boards/native_posix.overlay | 12 ++++++++++++ .../chan_blen_transfer/boards/native_posix_64.conf | 2 ++ .../boards/native_posix_64.overlay | 12 ++++++++++++ tests/drivers/dma/chan_blen_transfer/testcase.yaml | 3 +++ .../dma/chan_link_transfer/boards/native_posix.conf | 1 + .../chan_link_transfer/boards/native_posix.overlay | 12 ++++++++++++ .../chan_link_transfer/boards/native_posix_64.conf | 2 ++ .../boards/native_posix_64.overlay | 12 ++++++++++++ tests/drivers/dma/chan_link_transfer/testcase.yaml | 4 ++++ .../dma/loop_transfer/boards/native_posix.conf | 1 + .../dma/loop_transfer/boards/native_posix.overlay | 12 ++++++++++++ .../dma/loop_transfer/boards/native_posix_64.conf | 2 ++ .../loop_transfer/boards/native_posix_64.overlay | 12 ++++++++++++ tests/drivers/dma/loop_transfer/testcase.yaml | 3 +++ .../dma/scatter_gather/boards/native_posix.conf | 1 + .../dma/scatter_gather/boards/native_posix.overlay | 13 +++++++++++++ .../dma/scatter_gather/boards/native_posix_64.conf | 2 ++ .../scatter_gather/boards/native_posix_64.overlay | 13 +++++++++++++ tests/drivers/dma/scatter_gather/testcase.yaml | 4 ++++ 20 files changed, 124 insertions(+) create mode 100644 tests/drivers/dma/chan_blen_transfer/boards/native_posix.conf create mode 100644 tests/drivers/dma/chan_blen_transfer/boards/native_posix.overlay create mode 100644 tests/drivers/dma/chan_blen_transfer/boards/native_posix_64.conf create mode 100644 tests/drivers/dma/chan_blen_transfer/boards/native_posix_64.overlay create mode 100644 tests/drivers/dma/chan_link_transfer/boards/native_posix.conf create mode 100644 tests/drivers/dma/chan_link_transfer/boards/native_posix.overlay create mode 100644 tests/drivers/dma/chan_link_transfer/boards/native_posix_64.conf create mode 100644 tests/drivers/dma/chan_link_transfer/boards/native_posix_64.overlay create mode 100644 tests/drivers/dma/loop_transfer/boards/native_posix.conf create mode 100644 tests/drivers/dma/loop_transfer/boards/native_posix.overlay create mode 100644 tests/drivers/dma/loop_transfer/boards/native_posix_64.conf create mode 100644 tests/drivers/dma/loop_transfer/boards/native_posix_64.overlay create mode 100644 tests/drivers/dma/scatter_gather/boards/native_posix.conf create mode 100644 tests/drivers/dma/scatter_gather/boards/native_posix.overlay create mode 100644 tests/drivers/dma/scatter_gather/boards/native_posix_64.conf create mode 100644 tests/drivers/dma/scatter_gather/boards/native_posix_64.overlay diff --git a/tests/drivers/dma/chan_blen_transfer/boards/native_posix.conf b/tests/drivers/dma/chan_blen_transfer/boards/native_posix.conf new file mode 100644 index 00000000000..399c0de78db --- /dev/null +++ b/tests/drivers/dma/chan_blen_transfer/boards/native_posix.conf @@ -0,0 +1 @@ +CONFIG_DMA_EMUL=y diff --git a/tests/drivers/dma/chan_blen_transfer/boards/native_posix.overlay b/tests/drivers/dma/chan_blen_transfer/boards/native_posix.overlay new file mode 100644 index 00000000000..a93d9923627 --- /dev/null +++ b/tests/drivers/dma/chan_blen_transfer/boards/native_posix.overlay @@ -0,0 +1,12 @@ +/* + * Copyright (c) 2023 Meta + * + * SPDX-License-Identifier: Apache-2.0 + */ + +&dma { + dma-channels = <2>; + status = "okay"; +}; + +test_dma0: &dma { }; diff --git a/tests/drivers/dma/chan_blen_transfer/boards/native_posix_64.conf b/tests/drivers/dma/chan_blen_transfer/boards/native_posix_64.conf new file mode 100644 index 00000000000..d76c9f7b918 --- /dev/null +++ b/tests/drivers/dma/chan_blen_transfer/boards/native_posix_64.conf @@ -0,0 +1,2 @@ +CONFIG_DMA_EMUL=y +CONFIG_DMA_64BIT=y diff --git a/tests/drivers/dma/chan_blen_transfer/boards/native_posix_64.overlay b/tests/drivers/dma/chan_blen_transfer/boards/native_posix_64.overlay new file mode 100644 index 00000000000..a93d9923627 --- /dev/null +++ b/tests/drivers/dma/chan_blen_transfer/boards/native_posix_64.overlay @@ -0,0 +1,12 @@ +/* + * Copyright (c) 2023 Meta + * + * SPDX-License-Identifier: Apache-2.0 + */ + +&dma { + dma-channels = <2>; + status = "okay"; +}; + +test_dma0: &dma { }; diff --git a/tests/drivers/dma/chan_blen_transfer/testcase.yaml b/tests/drivers/dma/chan_blen_transfer/testcase.yaml index b87f7bb9d34..374ae8e6d48 100644 --- a/tests/drivers/dma/chan_blen_transfer/testcase.yaml +++ b/tests/drivers/dma/chan_blen_transfer/testcase.yaml @@ -5,6 +5,9 @@ tests: - dma tags: - dma + integration_platforms: + - native_posix + - native_posix_64 filter: dt_nodelabel_enabled("test_dma0") drivers.dma.chan_blen_transfer.low_footprint: tags: diff --git a/tests/drivers/dma/chan_link_transfer/boards/native_posix.conf b/tests/drivers/dma/chan_link_transfer/boards/native_posix.conf new file mode 100644 index 00000000000..399c0de78db --- /dev/null +++ b/tests/drivers/dma/chan_link_transfer/boards/native_posix.conf @@ -0,0 +1 @@ +CONFIG_DMA_EMUL=y diff --git a/tests/drivers/dma/chan_link_transfer/boards/native_posix.overlay b/tests/drivers/dma/chan_link_transfer/boards/native_posix.overlay new file mode 100644 index 00000000000..082fc972cab --- /dev/null +++ b/tests/drivers/dma/chan_link_transfer/boards/native_posix.overlay @@ -0,0 +1,12 @@ +/* + * Copyright (c) 2023 Meta + * + * SPDX-License-Identifier: Apache-2.0 + */ + +&dma { + dma-channels = <2>; + status = "okay"; +}; + +dma0: &dma { }; diff --git a/tests/drivers/dma/chan_link_transfer/boards/native_posix_64.conf b/tests/drivers/dma/chan_link_transfer/boards/native_posix_64.conf new file mode 100644 index 00000000000..d76c9f7b918 --- /dev/null +++ b/tests/drivers/dma/chan_link_transfer/boards/native_posix_64.conf @@ -0,0 +1,2 @@ +CONFIG_DMA_EMUL=y +CONFIG_DMA_64BIT=y diff --git a/tests/drivers/dma/chan_link_transfer/boards/native_posix_64.overlay b/tests/drivers/dma/chan_link_transfer/boards/native_posix_64.overlay new file mode 100644 index 00000000000..082fc972cab --- /dev/null +++ b/tests/drivers/dma/chan_link_transfer/boards/native_posix_64.overlay @@ -0,0 +1,12 @@ +/* + * Copyright (c) 2023 Meta + * + * SPDX-License-Identifier: Apache-2.0 + */ + +&dma { + dma-channels = <2>; + status = "okay"; +}; + +dma0: &dma { }; diff --git a/tests/drivers/dma/chan_link_transfer/testcase.yaml b/tests/drivers/dma/chan_link_transfer/testcase.yaml index ea35f8c9533..930ab1067eb 100644 --- a/tests/drivers/dma/chan_link_transfer/testcase.yaml +++ b/tests/drivers/dma/chan_link_transfer/testcase.yaml @@ -16,5 +16,9 @@ tests: - mimxrt1024_evk - lpcxpresso55s69_cpu0 - lpcxpresso55s36 + - native_posix + - native_posix_64 integration_platforms: - frdm_k64f + - native_posix + - native_posix_64 diff --git a/tests/drivers/dma/loop_transfer/boards/native_posix.conf b/tests/drivers/dma/loop_transfer/boards/native_posix.conf new file mode 100644 index 00000000000..399c0de78db --- /dev/null +++ b/tests/drivers/dma/loop_transfer/boards/native_posix.conf @@ -0,0 +1 @@ +CONFIG_DMA_EMUL=y diff --git a/tests/drivers/dma/loop_transfer/boards/native_posix.overlay b/tests/drivers/dma/loop_transfer/boards/native_posix.overlay new file mode 100644 index 00000000000..a93d9923627 --- /dev/null +++ b/tests/drivers/dma/loop_transfer/boards/native_posix.overlay @@ -0,0 +1,12 @@ +/* + * Copyright (c) 2023 Meta + * + * SPDX-License-Identifier: Apache-2.0 + */ + +&dma { + dma-channels = <2>; + status = "okay"; +}; + +test_dma0: &dma { }; diff --git a/tests/drivers/dma/loop_transfer/boards/native_posix_64.conf b/tests/drivers/dma/loop_transfer/boards/native_posix_64.conf new file mode 100644 index 00000000000..d76c9f7b918 --- /dev/null +++ b/tests/drivers/dma/loop_transfer/boards/native_posix_64.conf @@ -0,0 +1,2 @@ +CONFIG_DMA_EMUL=y +CONFIG_DMA_64BIT=y diff --git a/tests/drivers/dma/loop_transfer/boards/native_posix_64.overlay b/tests/drivers/dma/loop_transfer/boards/native_posix_64.overlay new file mode 100644 index 00000000000..a93d9923627 --- /dev/null +++ b/tests/drivers/dma/loop_transfer/boards/native_posix_64.overlay @@ -0,0 +1,12 @@ +/* + * Copyright (c) 2023 Meta + * + * SPDX-License-Identifier: Apache-2.0 + */ + +&dma { + dma-channels = <2>; + status = "okay"; +}; + +test_dma0: &dma { }; diff --git a/tests/drivers/dma/loop_transfer/testcase.yaml b/tests/drivers/dma/loop_transfer/testcase.yaml index 53d13d8943f..9bb8ed2f7ea 100644 --- a/tests/drivers/dma/loop_transfer/testcase.yaml +++ b/tests/drivers/dma/loop_transfer/testcase.yaml @@ -4,4 +4,7 @@ tests: tags: - drivers - dma + integration_platforms: + - native_posix + - native_posix_64 filter: dt_nodelabel_enabled("test_dma0") diff --git a/tests/drivers/dma/scatter_gather/boards/native_posix.conf b/tests/drivers/dma/scatter_gather/boards/native_posix.conf new file mode 100644 index 00000000000..399c0de78db --- /dev/null +++ b/tests/drivers/dma/scatter_gather/boards/native_posix.conf @@ -0,0 +1 @@ +CONFIG_DMA_EMUL=y diff --git a/tests/drivers/dma/scatter_gather/boards/native_posix.overlay b/tests/drivers/dma/scatter_gather/boards/native_posix.overlay new file mode 100644 index 00000000000..8afb0753c10 --- /dev/null +++ b/tests/drivers/dma/scatter_gather/boards/native_posix.overlay @@ -0,0 +1,13 @@ +/* + * Copyright (c) 2023 Meta + * + * SPDX-License-Identifier: Apache-2.0 + */ + +&dma { + dma-channels = <2>; + dma-requests = <4>; + status = "okay"; +}; + +test_dma0: &dma { }; diff --git a/tests/drivers/dma/scatter_gather/boards/native_posix_64.conf b/tests/drivers/dma/scatter_gather/boards/native_posix_64.conf new file mode 100644 index 00000000000..d76c9f7b918 --- /dev/null +++ b/tests/drivers/dma/scatter_gather/boards/native_posix_64.conf @@ -0,0 +1,2 @@ +CONFIG_DMA_EMUL=y +CONFIG_DMA_64BIT=y diff --git a/tests/drivers/dma/scatter_gather/boards/native_posix_64.overlay b/tests/drivers/dma/scatter_gather/boards/native_posix_64.overlay new file mode 100644 index 00000000000..8afb0753c10 --- /dev/null +++ b/tests/drivers/dma/scatter_gather/boards/native_posix_64.overlay @@ -0,0 +1,13 @@ +/* + * Copyright (c) 2023 Meta + * + * SPDX-License-Identifier: Apache-2.0 + */ + +&dma { + dma-channels = <2>; + dma-requests = <4>; + status = "okay"; +}; + +test_dma0: &dma { }; diff --git a/tests/drivers/dma/scatter_gather/testcase.yaml b/tests/drivers/dma/scatter_gather/testcase.yaml index 880f09267b7..6b05448a96c 100644 --- a/tests/drivers/dma/scatter_gather/testcase.yaml +++ b/tests/drivers/dma/scatter_gather/testcase.yaml @@ -9,6 +9,10 @@ tests: - frdm_k64f - mimxrt1060_evk - lpcxpresso55s36 + - native_posix + - native_posix_64 filter: dt_alias_exists("dma0") integration_platforms: - intel_adsp_cavs25 + - native_posix + - native_posix_64 From 5d72075d974ff4afc4aa3e872e0cf217ee517adc Mon Sep 17 00:00:00 2001 From: Alberto Escolar Piedras Date: Fri, 1 Dec 2023 11:01:10 +0100 Subject: [PATCH 0636/3723] doc: migration-guide: 3.6: Add recommended change to native_sim native_sim is superceeding native_posix. Let's recommend users to use it instead. Signed-off-by: Alberto Escolar Piedras --- doc/releases/migration-guide-3.6.rst | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/doc/releases/migration-guide-3.6.rst b/doc/releases/migration-guide-3.6.rst index bb04e864c2b..bbedcf39cca 100644 --- a/doc/releases/migration-guide-3.6.rst +++ b/doc/releases/migration-guide-3.6.rst @@ -226,3 +226,7 @@ Recommended Changes * New macros available for ST sensor DT properties setting. These macros have a self-explanatory name that helps in recognizing what the property setting means (e.g. LSM6DSV16X_DT_ODR_AT_60Hz). (:github:`65410`) + +* Users of :ref:`native_posix` are recommended to migrate to + :ref:`native_sim`. :ref:`native_sim` supports all its use cases, + and should be a drop-in replacement for most. From 3783a7eccd00d7462409ad36e44655c6439d9ef0 Mon Sep 17 00:00:00 2001 From: Jukka Rissanen Date: Fri, 1 Dec 2023 16:12:39 +0200 Subject: [PATCH 0637/3723] tests: net: dns_sd: Increase the number of contexts Issue seen in frdm-k64f + some other boards. Fixes #66033 Signed-off-by: Jukka Rissanen --- tests/net/lib/dns_sd/prj.conf | 2 ++ 1 file changed, 2 insertions(+) diff --git a/tests/net/lib/dns_sd/prj.conf b/tests/net/lib/dns_sd/prj.conf index 52c1916e210..f53083ff72d 100644 --- a/tests/net/lib/dns_sd/prj.conf +++ b/tests/net/lib/dns_sd/prj.conf @@ -19,3 +19,5 @@ CONFIG_ZTEST_STACK_SIZE=2048 # Maybe avoid stack overflow on mps2_an385? CONFIG_MAIN_STACK_SIZE=2048 + +CONFIG_NET_MAX_CONTEXTS=8 From af610bb2074c17e9736359eb5670460ec640ccb9 Mon Sep 17 00:00:00 2001 From: Jukka Rissanen Date: Fri, 1 Dec 2023 16:13:37 +0200 Subject: [PATCH 0638/3723] tests: net: shell: Increase number of IP address structs A warning is printed in start of the test about this. Increase CONFIG_NET_IF_MAX_IPV6_COUNT=2 and CONFIG_NET_IF_MAX_IPV4_COUNT=2 so that the tests pass in frdm_k64f and some other boards. Fixes #66020 Signed-off-by: Jukka Rissanen --- tests/net/shell/prj.conf | 2 ++ 1 file changed, 2 insertions(+) diff --git a/tests/net/shell/prj.conf b/tests/net/shell/prj.conf index f6aef9e72c2..18e783c62ed 100644 --- a/tests/net/shell/prj.conf +++ b/tests/net/shell/prj.conf @@ -21,3 +21,5 @@ CONFIG_NET_SHELL=y CONFIG_LOG_PRINTK=n CONFIG_SHELL_BACKEND_DUMMY=y CONFIG_MAIN_STACK_SIZE=2048 +CONFIG_NET_IF_MAX_IPV6_COUNT=2 +CONFIG_NET_IF_MAX_IPV4_COUNT=2 From 0f44d62740176f5e42dbf2d2b014fd6aaf7abd9a Mon Sep 17 00:00:00 2001 From: Michele Sardo Date: Sat, 2 Dec 2023 13:44:15 +0100 Subject: [PATCH 0639/3723] drivers: bluetooth: hci: handle event with high priority flag Make sure that events flagged as high priority are handled when CONFIG_BT_RECV_BLOCKING is not defined. Fix for #65892. Signed-off-by: Michele Sardo --- drivers/bluetooth/hci/h4.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/drivers/bluetooth/hci/h4.c b/drivers/bluetooth/hci/h4.c index cc4c346d602..e5cd81a06b8 100644 --- a/drivers/bluetooth/hci/h4.c +++ b/drivers/bluetooth/hci/h4.c @@ -346,7 +346,8 @@ static inline void read_payload(void) bt_recv_prio(buf); } - if (evt_flags & BT_HCI_EVT_FLAG_RECV) { + if ((evt_flags & BT_HCI_EVT_FLAG_RECV) || + !IS_ENABLED(CONFIG_BT_RECV_BLOCKING)) { LOG_DBG("Putting buf %p to rx fifo", buf); net_buf_put(&rx.fifo, buf); } From 8e4c70750add9e948d02af5c1c35fc2f5bd3d7b8 Mon Sep 17 00:00:00 2001 From: Noah Luskey Date: Fri, 1 Dec 2023 17:55:24 -0500 Subject: [PATCH 0640/3723] net: don't overwrite net_if name after iface is initialized When interface names are enabled, a default name is applied after initialization. Unintuitively, this overwrites any name that is set during the net_if init. This change sets a default name first, and then allows net_if init to overwrite that default name if it chooses to. Signed-off-by: Noah Luskey Signed-off-by: Noah Luskey --- subsys/net/ip/net_if.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/subsys/net/ip/net_if.c b/subsys/net/ip/net_if.c index 00c9c74495d..f69fc2b871b 100644 --- a/subsys/net/ip/net_if.c +++ b/subsys/net/ip/net_if.c @@ -4860,8 +4860,6 @@ void net_if_init(void) net_tc_tx_init(); STRUCT_SECTION_FOREACH(net_if, iface) { - init_iface(iface); - if_count++; #if defined(CONFIG_NET_INTERFACE_NAME) memset(net_if_get_config(iface)->name, 0, @@ -4869,6 +4867,9 @@ void net_if_init(void) set_default_name(iface); #endif + + init_iface(iface); + if_count++; } if (if_count == 0) { From e0fd9f6cdede1bcfcbddc7218c300a0b1b447fc4 Mon Sep 17 00:00:00 2001 From: Mahesh Mahadevan Date: Wed, 18 Oct 2023 17:40:37 +0100 Subject: [PATCH 0641/3723] drivers: dma_mcux_lpc: Call callback only when provided Add a check to ensure the dma_callback is provided before calling the callback function. Signed-off-by: Mahesh Mahadevan --- drivers/dma/dma_mcux_lpc.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/drivers/dma/dma_mcux_lpc.c b/drivers/dma/dma_mcux_lpc.c index ef0a164d4af..9aa1eae9c61 100644 --- a/drivers/dma/dma_mcux_lpc.c +++ b/drivers/dma/dma_mcux_lpc.c @@ -93,7 +93,9 @@ static void nxp_lpc_dma_callback(dma_handle_t *handle, void *param, data->busy = DMA_ChannelIsBusy(data->dma_handle.base, channel); - data->dma_callback(data->dev, data->user_data, channel, ret); + if (data->dma_callback) { + data->dma_callback(data->dev, data->user_data, channel, ret); + } } /* Handles DMA interrupts and dispatches to the individual channel */ From c4e1807cdf4d4a868995bcbe51716ac7fef78d3d Mon Sep 17 00:00:00 2001 From: Alberto Escolar Piedras Date: Fri, 1 Dec 2023 17:02:47 +0100 Subject: [PATCH 0642/3723] manifest: Update nrf hw models to latest * Update the HW models module to 9b985ea6bc237b6ae06f48eb228f2ac7f6e3b96b Including the following: * 9b985ea nrf_ccm: Add RATEOVERRIDE subscribe support * 8592230 nrf_hack: Add comments * 5775f4c docs: Very minor typo and grammar fixes Signed-off-by: Alberto Escolar Piedras --- west.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/west.yml b/west.yml index 10042a7a5ff..65ea74174eb 100644 --- a/west.yml +++ b/west.yml @@ -295,7 +295,7 @@ manifest: groups: - tools - name: nrf_hw_models - revision: a715dcc179f1a71f51c574165958b72fe932ae3f + revision: 9b985ea6bc237b6ae06f48eb228f2ac7f6e3b96b path: modules/bsim_hw_models/nrf_hw_models - name: open-amp revision: 214f9fc1539f8e5937c0474cb6ee29b6dcb2d4b8 From 47b7eaece9419214fb2065cba4b9c520dc807ca6 Mon Sep 17 00:00:00 2001 From: Alberto Escolar Piedras Date: Fri, 1 Dec 2023 16:52:19 +0100 Subject: [PATCH 0643/3723] boards nrf5340bsim_cpuapp: Select approprite 802154 radio in DT Set the chosen 802154 radio in DT for the nrf5340bsim_nrf5340_cpuapp so we can build with the radio driver built into the net core. Signed-off-by: Alberto Escolar Piedras --- boards/posix/nrf_bsim/nrf5340bsim_nrf5340_cpuapp.dts | 1 + 1 file changed, 1 insertion(+) diff --git a/boards/posix/nrf_bsim/nrf5340bsim_nrf5340_cpuapp.dts b/boards/posix/nrf_bsim/nrf5340bsim_nrf5340_cpuapp.dts index a7c3d39ace5..c5ec3c95af5 100644 --- a/boards/posix/nrf_bsim/nrf5340bsim_nrf5340_cpuapp.dts +++ b/boards/posix/nrf_bsim/nrf5340bsim_nrf5340_cpuapp.dts @@ -49,6 +49,7 @@ zephyr,flash = &flash0; zephyr,bt-hci-ipc = &ipc0; nordic,802154-spinel-ipc = &ipc0; + zephyr,ieee802154 = &ieee802154; }; soc { From 6a4edeeeab92cf0760ab8c37ef0ce264c424c2e7 Mon Sep 17 00:00:00 2001 From: Derek Snell Date: Fri, 1 Dec 2023 09:18:08 -0500 Subject: [PATCH 0644/3723] boards: arm: mimxrt1040_evk: document USER_LED and jumper J80 Document need to remove J80 when using USER_LED D8. Signed-off-by: Derek Snell --- boards/arm/mimxrt1040_evk/doc/index.rst | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/boards/arm/mimxrt1040_evk/doc/index.rst b/boards/arm/mimxrt1040_evk/doc/index.rst index f5ca4ed99cd..a17a87fe632 100644 --- a/boards/arm/mimxrt1040_evk/doc/index.rst +++ b/boards/arm/mimxrt1040_evk/doc/index.rst @@ -291,6 +291,13 @@ should see the following message in the terminal: Troubleshooting =============== +USER_LED D8 +----------- +The MIMXRT1040-EVK board ships with the wireless module in the M.2 connector, +and with jumper J80 shorted. This causes a conflict with the USER_LED D8, +and the LED will not turn off. Samples and applications using USER_LED D8, +like blinky, require removal of J80 jumper. + Boot Header ----------- From eea56d208087bd59ebe682fed5af0db062206412 Mon Sep 17 00:00:00 2001 From: Marc Herbert Date: Fri, 1 Dec 2023 08:07:48 +0000 Subject: [PATCH 0645/3723] scripts/build/elf_parser.py: add __lt__() method to base class This allows sorting objects consistently without having to specific a key. No functional change yet. Signed-off-by: Marc Herbert --- scripts/build/elf_parser.py | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/scripts/build/elf_parser.py b/scripts/build/elf_parser.py index bd7a970431c..07ca6f07806 100644 --- a/scripts/build/elf_parser.py +++ b/scripts/build/elf_parser.py @@ -24,6 +24,9 @@ def __init__(self, elf, sym): self.sym = sym self.data = self.elf.symbol_data(sym) + def __lt__(self, other): + return self.sym.entry.st_value < other.sym.entry.st_value + def _data_native_read(self, offset): (format, size) = self.elf.native_struct_format return struct.unpack(format, self.data[offset:offset + size])[0] @@ -238,8 +241,8 @@ def _on_device(sym): self.devices.append(Device(self, sym)) self._object_find_named('__device_', _on_device) - # Sort the device array by address for handle calculation - self.devices = sorted(self.devices, key = lambda k: k.sym.entry.st_value) + # Sort the device array by address (st_value) for handle calculation + self.devices = sorted(self.devices) # Assign handles to the devices for idx, dev in enumerate(self.devices): From fb8d41b123337b505e704f28592635d63b8cff5c Mon Sep 17 00:00:00 2001 From: Marc Herbert Date: Fri, 1 Dec 2023 08:12:13 +0000 Subject: [PATCH 0646/3723] scripts/build/elf_parser.py: make dependency graph output deterministic Python's sets are not deterministic. `devices` were already sorted but `dev_supports` is still a non-deterministic set. Sort dev_supports to make the graph output deterministic. Fixes commit 29942475c5ce ("scripts: gen_handles: output dependency graph") It is quite ironic that this initial and non-deterministic graph commit was concurrent with and slightly delayed other commit f896fc2306a0 ("scripts: gen_handles: Sort the device handles") which fixed another, similar non-determinism issue in the same area. A true "whack-a-mole"! Signed-off-by: Marc Herbert --- scripts/build/elf_parser.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/scripts/build/elf_parser.py b/scripts/build/elf_parser.py index 07ca6f07806..101e61dbadf 100644 --- a/scripts/build/elf_parser.py +++ b/scripts/build/elf_parser.py @@ -283,6 +283,6 @@ def device_dependency_graph(self, title, comment): ) dot.node(str(dev.ordinal), text) for dev in self.devices: - for sup in dev.devs_supports: + for sup in sorted(dev.devs_supports): dot.edge(str(dev.ordinal), str(sup.ordinal)) return dot From 3e6f751891150649d878d912f95b5cbc28a1d801 Mon Sep 17 00:00:00 2001 From: Lingao Meng Date: Fri, 1 Dec 2023 15:16:21 +0800 Subject: [PATCH 0647/3723] Bluetooth: Mesh: Align some code Align tab 8. Signed-off-by: Lingao Meng --- include/zephyr/bluetooth/mesh/access.h | 4 ++-- include/zephyr/bluetooth/mesh/blob_cli.h | 8 ++++---- include/zephyr/bluetooth/mesh/cdb.h | 2 +- include/zephyr/bluetooth/mesh/cfg_cli.h | 20 ++++++++++---------- 4 files changed, 17 insertions(+), 17 deletions(-) diff --git a/include/zephyr/bluetooth/mesh/access.h b/include/zephyr/bluetooth/mesh/access.h index 817fba918ef..d57f30f8f05 100644 --- a/include/zephyr/bluetooth/mesh/access.h +++ b/include/zephyr/bluetooth/mesh/access.h @@ -1011,7 +1011,7 @@ const struct bt_mesh_elem *bt_mesh_model_elem(const struct bt_mesh_model *mod); * if no SIG model with the given ID exists in the given element. */ const struct bt_mesh_model *bt_mesh_model_find(const struct bt_mesh_elem *elem, - uint16_t id); + uint16_t id); /** @brief Find a vendor model. * @@ -1023,7 +1023,7 @@ const struct bt_mesh_model *bt_mesh_model_find(const struct bt_mesh_elem *elem, * if no vendor model with the given ID exists in the given element. */ const struct bt_mesh_model *bt_mesh_model_find_vnd(const struct bt_mesh_elem *elem, - uint16_t company, uint16_t id); + uint16_t company, uint16_t id); /** @brief Get whether the model is in the primary element of the device. * diff --git a/include/zephyr/bluetooth/mesh/blob_cli.h b/include/zephyr/bluetooth/mesh/blob_cli.h index 8e239b31457..9b591cfdd35 100644 --- a/include/zephyr/bluetooth/mesh/blob_cli.h +++ b/include/zephyr/bluetooth/mesh/blob_cli.h @@ -265,10 +265,10 @@ struct blob_cli_broadcast_ctx { void (*send)(struct bt_mesh_blob_cli *cli, uint16_t dst); /** Called after every @ref blob_cli_broadcast_ctx::send callback. */ void (*send_complete)(struct bt_mesh_blob_cli *cli, uint16_t dst); - /** If @ref blob_cli_broadcast_ctx::acked is true, called after all Target nodes - * have confirmed reception by @ref blob_cli_broadcast_rsp. Otherwise, called - * after transmission has been completed. - */ + /** If @ref blob_cli_broadcast_ctx::acked is true, called after all Target nodes + * have confirmed reception by @ref blob_cli_broadcast_rsp. Otherwise, called + * after transmission has been completed. + */ void (*next)(struct bt_mesh_blob_cli *cli); /** If true, every transmission needs to be confirmed by @ref blob_cli_broadcast_rsp before * @ref blob_cli_broadcast_ctx::next is called. diff --git a/include/zephyr/bluetooth/mesh/cdb.h b/include/zephyr/bluetooth/mesh/cdb.h index 800ae07edc4..8ea35ec2e55 100644 --- a/include/zephyr/bluetooth/mesh/cdb.h +++ b/include/zephyr/bluetooth/mesh/cdb.h @@ -231,7 +231,7 @@ enum { * or BT_MESH_CDB_ITER_STOP to stop. */ typedef uint8_t (*bt_mesh_cdb_node_func_t)(struct bt_mesh_cdb_node *node, - void *user_data); + void *user_data); /** @brief Node iterator. * diff --git a/include/zephyr/bluetooth/mesh/cfg_cli.h b/include/zephyr/bluetooth/mesh/cfg_cli.h index 0e8c26131ff..4aca0c17451 100644 --- a/include/zephyr/bluetooth/mesh/cfg_cli.h +++ b/include/zephyr/bluetooth/mesh/cfg_cli.h @@ -96,8 +96,8 @@ struct bt_mesh_cfg_cli_cb { * @param buf Message buffer containing subscription addresses. */ void (*mod_sub_list)(struct bt_mesh_cfg_cli *cli, uint16_t addr, uint8_t status, - uint16_t elem_addr, uint16_t mod_id, uint16_t cid, - struct net_buf_simple *buf); + uint16_t elem_addr, uint16_t mod_id, uint16_t cid, + struct net_buf_simple *buf); /** @brief Optional callback for Node Reset Status messages. * @@ -128,7 +128,7 @@ struct bt_mesh_cfg_cli_cb { * @param status Status Code for requesting message. */ void (*ttl_status)(struct bt_mesh_cfg_cli *cli, uint16_t addr, - uint8_t status); + uint8_t status); /** @brief Optional callback for Friend Status messages. * @@ -139,7 +139,7 @@ struct bt_mesh_cfg_cli_cb { * @param status Status Code for requesting message. */ void (*friend_status)(struct bt_mesh_cfg_cli *cli, uint16_t addr, - uint8_t status); + uint8_t status); /** @brief Optional callback for GATT Proxy Status messages. * @@ -150,7 +150,7 @@ struct bt_mesh_cfg_cli_cb { * @param status Status Code for requesting message. */ void (*gatt_proxy_status)(struct bt_mesh_cfg_cli *cli, uint16_t addr, - uint8_t status); + uint8_t status); /** @brief Optional callback for Network Transmit Status messages. * @@ -199,7 +199,7 @@ struct bt_mesh_cfg_cli_cb { * @param buf Message buffer containing key indexes. */ void (*net_key_list)(struct bt_mesh_cfg_cli *cli, uint16_t addr, - struct net_buf_simple *buf); + struct net_buf_simple *buf); /** @brief Optional callback for AppKey Status messages. * @@ -229,7 +229,7 @@ struct bt_mesh_cfg_cli_cb { * @param buf Message buffer containing key indexes. */ void (*app_key_list)(struct bt_mesh_cfg_cli *cli, uint16_t addr, uint8_t status, - uint16_t net_idx, struct net_buf_simple *buf); + uint16_t net_idx, struct net_buf_simple *buf); /** @brief Optional callback for Model App Status messages. * @@ -262,8 +262,8 @@ struct bt_mesh_cfg_cli_cb { * @param buf Message buffer containing key indexes. */ void (*mod_app_list)(struct bt_mesh_cfg_cli *cli, uint16_t addr, uint8_t status, - uint16_t elem_addr, uint16_t mod_id, uint16_t cid, - struct net_buf_simple *buf); + uint16_t elem_addr, uint16_t mod_id, uint16_t cid, + struct net_buf_simple *buf); /** @brief Optional callback for Node Identity Status messages. * @@ -326,7 +326,7 @@ struct bt_mesh_cfg_cli_cb { * @param sub HB subscription configuration parameters. */ void (*hb_sub_status)(struct bt_mesh_cfg_cli *cli, uint16_t addr, uint8_t status, - struct bt_mesh_cfg_cli_hb_sub *sub); + struct bt_mesh_cfg_cli_hb_sub *sub); }; /** Mesh Configuration Client Model Context */ From 8a4f7c02c0745550e29956290812e929bfbf4ae3 Mon Sep 17 00:00:00 2001 From: Chaitanya Tata Date: Fri, 1 Dec 2023 10:29:53 +0530 Subject: [PATCH 0648/3723] wifi: shell: Fix unbalanced braces Fix the typo in braces for help. Signed-off-by: Chaitanya Tata --- subsys/net/l2/wifi/wifi_shell.c | 42 ++++++++++++++++----------------- 1 file changed, 21 insertions(+), 21 deletions(-) diff --git a/subsys/net/l2/wifi/wifi_shell.c b/subsys/net/l2/wifi/wifi_shell.c index 5f7eb5ba0ee..c50175e086f 100644 --- a/subsys/net/l2/wifi/wifi_shell.c +++ b/subsys/net/l2/wifi/wifi_shell.c @@ -1673,15 +1673,15 @@ SHELL_STATIC_SUBCMD_SET_CREATE(wifi_commands, SHELL_CMD(mode, NULL, "mode operational setting\n" "This command may be used to set the Wi-Fi device into a specific mode of operation\n" "parameters:" - "[-i : Interface index - optional argument\n" - "[-s : Station mode.\n" - "[-m : Monitor mode.\n" - "[-p : Promiscuous mode.\n" - "[-t : TX-Injection mode.\n" - "[-a : AP mode.\n" - "[-k : Softap mode.\n" - "[-h : Help.\n" - "[-g : Get current mode for a specific interface index.\n" + "[-i] : Interface index - optional argument\n" + "[-s] : Station mode.\n" + "[-m] : Monitor mode.\n" + "[-p] : Promiscuous mode.\n" + "[-t] : TX-Injection mode.\n" + "[-a] : AP mode.\n" + "[-k] : Softap mode.\n" + "[-h] : Help.\n" + "[-g] : Get current mode for a specific interface index.\n" "Usage: Get operation example for interface index 1\n" "wifi mode -g -i1\n" "Set operation example for interface index 1 - set station+promiscuous\n" @@ -1692,14 +1692,14 @@ SHELL_STATIC_SUBCMD_SET_CREATE(wifi_commands, "monitor, TX-Injection and promiscuous mode is enabled.\n" "The different packet filter modes are control, management, data and enable all filters\n" "parameters:" - "[-i : Interface index - optional argument.\n" - "[-a : Enable all packet filter modes\n" - "[-m : Enable management packets to allowed up the stack.\n" - "[-c : Enable control packets to be allowed up the stack.\n" - "[-d : Enable Data packets to be allowed up the stack.\n" - "[-g : Get current filter settings for a specific interface index.\n" - "<-b : Capture length buffer size for each packet to be captured - optional argument.\n" - "<-h : Help.\n" + "[-i] : Interface index - optional argument.\n" + "[-a] : Enable all packet filter modes\n" + "[-m] : Enable management packets to allowed up the stack.\n" + "[-c] : Enable control packets to be allowed up the stack.\n" + "[-d] : Enable Data packets to be allowed up the stack.\n" + "[-g] : Get current filter settings for a specific interface index.\n" + "<-b> : Capture length buffer size for each packet to be captured - optional argument.\n" + "<-h> : Help.\n" "Usage: Get operation example for interface index 1\n" "wifi packet_filter -g -i1\n" "Set operation example for interface index 1 - set data+management frame filter\n" @@ -1710,10 +1710,10 @@ SHELL_STATIC_SUBCMD_SET_CREATE(wifi_commands, "monitor or TX-Injection mode is enabled.\n" "Currently 20 MHz is only supported and no BW parameter is provided\n" "parameters:" - "[-i : Interface index - optional argument.\n" - "[-c : Set a specific channel number to the lower layer.\n" - "[-g : Get current set channel number from the lower layer.\n" - "[-h : Help.\n" + "[-i] : Interface index - optional argument.\n" + "[-c] : Set a specific channel number to the lower layer.\n" + "[-g] : Get current set channel number from the lower layer.\n" + "[-h] : Help.\n" "Usage: Get operation example for interface index 1\n" "wifi channel -g -i1\n" "Set operation example for interface index 1 (setting channel 5)\n" From 95e52c9c63fa85fc38a091e9c9834e1a7cecb5e4 Mon Sep 17 00:00:00 2001 From: Chaitanya Tata Date: Fri, 1 Dec 2023 10:36:06 +0530 Subject: [PATCH 0649/3723] wifi: shell: Fix brackets type for optional params General notation for Optional params is to use square brackets. Signed-off-by: Chaitanya Tata --- subsys/net/l2/wifi/wifi_shell.c | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/subsys/net/l2/wifi/wifi_shell.c b/subsys/net/l2/wifi/wifi_shell.c index c50175e086f..64f125dea01 100644 --- a/subsys/net/l2/wifi/wifi_shell.c +++ b/subsys/net/l2/wifi/wifi_shell.c @@ -1631,11 +1631,11 @@ SHELL_STATIC_SUBCMD_SET_CREATE(wifi_commands, SHELL_CMD(connect, NULL, "Connect to a Wi-Fi AP\n" "\"\"\n" - "\n" - "\n" - "\n" + "[channel number: 0 means all]\n" + "[PSK: valid only for secure SSIDs]\n" + "[Security type: valid only for secure SSIDs]\n" "0:None, 1:PSK, 2:PSK-256, 3:SAE\n" - "\n" + "[MFP (optional: needs security type to be specified)]\n" ": 0:Disable, 1:Optional, 2:Required", cmd_wifi_connect), SHELL_CMD(disconnect, NULL, "Disconnect from the Wi-Fi AP", @@ -1667,7 +1667,7 @@ SHELL_STATIC_SUBCMD_SET_CREATE(wifi_commands, SHELL_CMD(reg_domain, NULL, "Set or Get Wi-Fi regulatory domain\n" "Usage: wifi reg_domain [ISO/IEC 3166-1 alpha2] [-f]\n" - "-f: Force to use this regulatory hint over any other regulatory hints\n" + "[-f]: Force to use this regulatory hint over any other regulatory hints\n" "Note: This may cause regulatory compliance issues, use it at your own risk.", cmd_wifi_reg_domain), SHELL_CMD(mode, NULL, "mode operational setting\n" From 8ad78a4bb4517bf9d975443b852ae8a237e52e18 Mon Sep 17 00:00:00 2001 From: Chaitanya Tata Date: Fri, 1 Dec 2023 10:37:21 +0530 Subject: [PATCH 0650/3723] wifi: shell: Fix PS mode help There is only a single parameter called "mode" that takes two possible values. Signed-off-by: Chaitanya Tata --- subsys/net/l2/wifi/wifi_shell.c | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/subsys/net/l2/wifi/wifi_shell.c b/subsys/net/l2/wifi/wifi_shell.c index 64f125dea01..cd3390828d1 100644 --- a/subsys/net/l2/wifi/wifi_shell.c +++ b/subsys/net/l2/wifi/wifi_shell.c @@ -1644,8 +1644,7 @@ SHELL_STATIC_SUBCMD_SET_CREATE(wifi_commands, cmd_wifi_ps), SHELL_CMD_ARG(ps_mode, NULL, - "\n" - "", + "\n", cmd_wifi_ps_mode, 2, 0), @@ -1733,8 +1732,7 @@ SHELL_STATIC_SUBCMD_SET_CREATE(wifi_commands, 0), SHELL_CMD_ARG(ps_wakeup_mode, NULL, - " : Set PS wake up mode to DTIM interval\n" - " : Set PS wake up mode to listen interval", + "\n", cmd_wifi_ps_wakeup_mode, 2, 0), From 1c46e52bf8c47e2f75967a9e263e02c7c4859ad6 Mon Sep 17 00:00:00 2001 From: Chaitanya Tata Date: Fri, 1 Dec 2023 10:40:25 +0530 Subject: [PATCH 0651/3723] wifi: shell: Add missing security options Newly added security types are missing from the help. Also, now that we have two variants of PSK, use the prefix to disambiguate. Signed-off-by: Chaitanya Tata --- subsys/net/l2/wifi/wifi_shell.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/subsys/net/l2/wifi/wifi_shell.c b/subsys/net/l2/wifi/wifi_shell.c index cd3390828d1..767ac3eaf05 100644 --- a/subsys/net/l2/wifi/wifi_shell.c +++ b/subsys/net/l2/wifi/wifi_shell.c @@ -1634,7 +1634,7 @@ SHELL_STATIC_SUBCMD_SET_CREATE(wifi_commands, "[channel number: 0 means all]\n" "[PSK: valid only for secure SSIDs]\n" "[Security type: valid only for secure SSIDs]\n" - "0:None, 1:PSK, 2:PSK-256, 3:SAE\n" + "0:None, 1:WPA2-PSK, 2:WPA2-PSK-256, 3:SAE, 4:WAPI, 5:EAP, 6:WEP, 7: WPA-PSK\n" "[MFP (optional: needs security type to be specified)]\n" ": 0:Disable, 1:Optional, 2:Required", cmd_wifi_connect), From 95b8ae37e32d74ced297e7f11d72eea608b7b95c Mon Sep 17 00:00:00 2001 From: Chaitanya Tata Date: Fri, 1 Dec 2023 10:57:40 +0530 Subject: [PATCH 0652/3723] wifi: shell: Enforce argument count checks Use the proper API to enforce argument count checks as per mandatory or optional params. Signed-off-by: Chaitanya Tata --- subsys/net/l2/wifi/wifi_shell.c | 74 ++++++++++++++++++++------------- 1 file changed, 44 insertions(+), 30 deletions(-) diff --git a/subsys/net/l2/wifi/wifi_shell.c b/subsys/net/l2/wifi/wifi_shell.c index 767ac3eaf05..d0cd0551897 100644 --- a/subsys/net/l2/wifi/wifi_shell.c +++ b/subsys/net/l2/wifi/wifi_shell.c @@ -1598,37 +1598,43 @@ static int cmd_wifi_packet_filter(const struct shell *sh, size_t argc, char *arg } SHELL_STATIC_SUBCMD_SET_CREATE(wifi_cmd_ap, - SHELL_CMD(disable, NULL, + SHELL_CMD_ARG(disable, NULL, "Disable Access Point mode", - cmd_wifi_ap_disable), - SHELL_CMD(enable, NULL, " [channel] [PSK]", - cmd_wifi_ap_enable), + cmd_wifi_ap_disable, + 1, 0), + SHELL_CMD_ARG(enable, NULL, " [channel] [PSK]", + cmd_wifi_ap_enable, + 2, 1), SHELL_SUBCMD_SET_END ); SHELL_STATIC_SUBCMD_SET_CREATE(wifi_twt_ops, - SHELL_CMD(quick_setup, NULL, " Start a TWT flow with defaults:\n" + SHELL_CMD_ARG(quick_setup, NULL, " Start a TWT flow with defaults:\n" " \n", - cmd_wifi_twt_setup_quick), - SHELL_CMD(setup, NULL, " Start a TWT flow:\n" + cmd_wifi_twt_setup_quick, + 3, 0), + SHELL_CMD_ARG(setup, NULL, " Start a TWT flow:\n" "\n" "\n" " " " \n", - cmd_wifi_twt_setup), - SHELL_CMD(teardown, NULL, " Teardown a TWT flow:\n" + cmd_wifi_twt_setup, + 11, 0), + SHELL_CMD_ARG(teardown, NULL, " Teardown a TWT flow:\n" "\n" "\n" " \n", - cmd_wifi_twt_teardown), - SHELL_CMD(teardown_all, NULL, " Teardown all TWT flows\n", - cmd_wifi_twt_teardown_all), + cmd_wifi_twt_teardown, + 5, 0), + SHELL_CMD_ARG(teardown_all, NULL, " Teardown all TWT flows\n", + cmd_wifi_twt_teardown_all, + 1, 0), SHELL_SUBCMD_SET_END ); SHELL_STATIC_SUBCMD_SET_CREATE(wifi_commands, SHELL_CMD(ap, &wifi_cmd_ap, "Access Point mode commands", NULL), - SHELL_CMD(connect, NULL, + SHELL_CMD_ARG(connect, NULL, "Connect to a Wi-Fi AP\n" "\"\"\n" "[channel number: 0 means all]\n" @@ -1637,18 +1643,21 @@ SHELL_STATIC_SUBCMD_SET_CREATE(wifi_commands, "0:None, 1:WPA2-PSK, 2:WPA2-PSK-256, 3:SAE, 4:WAPI, 5:EAP, 6:WEP, 7: WPA-PSK\n" "[MFP (optional: needs security type to be specified)]\n" ": 0:Disable, 1:Optional, 2:Required", - cmd_wifi_connect), - SHELL_CMD(disconnect, NULL, "Disconnect from the Wi-Fi AP", - cmd_wifi_disconnect), - SHELL_CMD(ps, NULL, "Configure Wi-F PS on/off, no arguments will dump config", - cmd_wifi_ps), + cmd_wifi_connect, + 2, 5), + SHELL_CMD_ARG(disconnect, NULL, "Disconnect from the Wi-Fi AP", + cmd_wifi_disconnect, + 1, 0), + SHELL_CMD_ARG(ps, NULL, "Configure Wi-F PS on/off, no arguments will dump config", + cmd_wifi_ps, + 1, 1), SHELL_CMD_ARG(ps_mode, NULL, "\n", cmd_wifi_ps_mode, 2, 0), - SHELL_CMD(scan, NULL, + SHELL_CMD_ARG(scan, NULL, "Scan for Wi-Fi APs\n" "OPTIONAL PARAMETERS:\n" "[-t, --type ] : Preferred mode of scan. The actual mode of scan can depend on factors such as the Wi-Fi chip implementation, regulatory domain restrictions. Default type is active.\n" @@ -1659,17 +1668,19 @@ SHELL_STATIC_SUBCMD_SET_CREATE(wifi_commands, "[-m, --max_bss ] : Maximum BSSes to scan for. Range 1 - 65535.\n" "[-c, --chans ] : Channels to be scanned. The channels must be specified in the form band1:chan1,chan2_band2:chan3,..etc. band1, band2 must be valid band values and chan1, chan2, chan3 must be specified as a list of comma separated values where each value is either a single channel or a channel range specified as chan_start-chan_end. Each band channel set has to be separated by a _. For example, a valid channel specification can be 2:1,6-11,14_5:36,149-165,44\n" "[-h, --help] : Print out the help for the scan command.", - cmd_wifi_scan), - SHELL_CMD(statistics, NULL, "Wi-Fi interface statistics", cmd_wifi_stats), - SHELL_CMD(status, NULL, "Status of the Wi-Fi interface", cmd_wifi_status), + cmd_wifi_scan, + 1, 8), + SHELL_CMD_ARG(statistics, NULL, "Wi-Fi interface statistics", cmd_wifi_stats, 1, 0), + SHELL_CMD_ARG(status, NULL, "Status of the Wi-Fi interface", cmd_wifi_status, 1, 0), SHELL_CMD(twt, &wifi_twt_ops, "Manage TWT flows", NULL), - SHELL_CMD(reg_domain, NULL, + SHELL_CMD_ARG(reg_domain, NULL, "Set or Get Wi-Fi regulatory domain\n" "Usage: wifi reg_domain [ISO/IEC 3166-1 alpha2] [-f]\n" "[-f]: Force to use this regulatory hint over any other regulatory hints\n" "Note: This may cause regulatory compliance issues, use it at your own risk.", - cmd_wifi_reg_domain), - SHELL_CMD(mode, NULL, "mode operational setting\n" + cmd_wifi_reg_domain, + 2, 1), + SHELL_CMD_ARG(mode, NULL, "mode operational setting\n" "This command may be used to set the Wi-Fi device into a specific mode of operation\n" "parameters:" "[-i] : Interface index - optional argument\n" @@ -1685,8 +1696,9 @@ SHELL_STATIC_SUBCMD_SET_CREATE(wifi_commands, "wifi mode -g -i1\n" "Set operation example for interface index 1 - set station+promiscuous\n" "wifi mode -i1 -sp\n", - cmd_wifi_mode), - SHELL_CMD(packet_filter, NULL, "mode filter setting\n" + cmd_wifi_mode, + 1, 9), + SHELL_CMD_ARG(packet_filter, NULL, "mode filter setting\n" "This command is used to set packet filter setting when\n" "monitor, TX-Injection and promiscuous mode is enabled.\n" "The different packet filter modes are control, management, data and enable all filters\n" @@ -1703,8 +1715,9 @@ SHELL_STATIC_SUBCMD_SET_CREATE(wifi_commands, "wifi packet_filter -g -i1\n" "Set operation example for interface index 1 - set data+management frame filter\n" "wifi packet_filter -i1 -md\n", - cmd_wifi_packet_filter), - SHELL_CMD(channel, NULL, "wifi channel setting\n" + cmd_wifi_packet_filter, + 1, 8), + SHELL_CMD_ARG(channel, NULL, "wifi channel setting\n" "This command is used to set the channel when\n" "monitor or TX-Injection mode is enabled.\n" "Currently 20 MHz is only supported and no BW parameter is provided\n" @@ -1717,7 +1730,8 @@ SHELL_STATIC_SUBCMD_SET_CREATE(wifi_commands, "wifi channel -g -i1\n" "Set operation example for interface index 1 (setting channel 5)\n" "wifi -i1 -c5\n", - cmd_wifi_channel), + cmd_wifi_channel, + 1, 4), SHELL_CMD_ARG(ps_timeout, NULL, " - PS inactivity timer(in ms)", From 07e3869809949aff6344128a7cc251dead486ee1 Mon Sep 17 00:00:00 2001 From: Chaitanya Tata Date: Fri, 1 Dec 2023 11:06:51 +0530 Subject: [PATCH 0653/3723] wifi: shell: Add long arguments to help Long arguments are handy for new users. Also use hyphen's rather than underscore to follow the convention. Signed-off-by: Chaitanya Tata --- subsys/net/l2/wifi/wifi_shell.c | 52 ++++++++++++++++----------------- 1 file changed, 26 insertions(+), 26 deletions(-) diff --git a/subsys/net/l2/wifi/wifi_shell.c b/subsys/net/l2/wifi/wifi_shell.c index d0cd0551897..c5b8f60d933 100644 --- a/subsys/net/l2/wifi/wifi_shell.c +++ b/subsys/net/l2/wifi/wifi_shell.c @@ -1275,10 +1275,10 @@ void parse_mode_args_to_params(const struct shell *sh, int argc, int opt; int option_index = 0; - static struct option long_options[] = {{"if_index", optional_argument, 0, 'i'}, + static struct option long_options[] = {{"if-index", optional_argument, 0, 'i'}, {"sta", no_argument, 0, 's'}, {"monitor", no_argument, 0, 'm'}, - {"TX-injection", no_argument, 0, 't'}, + {"tx-injection", no_argument, 0, 't'}, {"promiscuous", no_argument, 0, 'p'}, {"ap", no_argument, 0, 'a'}, {"softap", no_argument, 0, 'k'}, @@ -1385,7 +1385,7 @@ void parse_channel_args_to_params(const struct shell *sh, int argc, int opt; int option_index = 0; - static struct option long_options[] = {{"if_index", optional_argument, 0, 'i'}, + static struct option long_options[] = {{"if-index", optional_argument, 0, 'i'}, {"channel", required_argument, 0, 'c'}, {"get", no_argument, 0, 'g'}, {"help", no_argument, 0, 'h'}, @@ -1491,8 +1491,8 @@ void parse_filter_args_to_params(const struct shell *sh, int argc, int opt; int option_index = 0; - static struct option long_options[] = {{"if_index", optional_argument, 0, 'i'}, - {"capture_len", optional_argument, 0, 'b'}, + static struct option long_options[] = {{"if-index", optional_argument, 0, 'i'}, + {"capture-len", optional_argument, 0, 'b'}, {"all", no_argument, 0, 'a'}, {"mgmt", no_argument, 0, 'm'}, {"ctrl", no_argument, 0, 'c'}, @@ -1683,15 +1683,15 @@ SHELL_STATIC_SUBCMD_SET_CREATE(wifi_commands, SHELL_CMD_ARG(mode, NULL, "mode operational setting\n" "This command may be used to set the Wi-Fi device into a specific mode of operation\n" "parameters:" - "[-i] : Interface index - optional argument\n" - "[-s] : Station mode.\n" - "[-m] : Monitor mode.\n" - "[-p] : Promiscuous mode.\n" - "[-t] : TX-Injection mode.\n" - "[-a] : AP mode.\n" - "[-k] : Softap mode.\n" - "[-h] : Help.\n" - "[-g] : Get current mode for a specific interface index.\n" + "[-i, --if-index ] : Interface index.\n" + "[-s, --sta] : Station mode.\n" + "[-m, --monitor] : Monitor mode.\n" + "[-p, --promiscuous] : Promiscuous mode.\n" + "[-t, --tx-injection] : TX-Injection mode.\n" + "[-a, --ap] : AP mode.\n" + "[-k, --softap] : Softap mode.\n" + "[-h, --help] : Help.\n" + "[-g, --get] : Get current mode for a specific interface index.\n" "Usage: Get operation example for interface index 1\n" "wifi mode -g -i1\n" "Set operation example for interface index 1 - set station+promiscuous\n" @@ -1703,14 +1703,14 @@ SHELL_STATIC_SUBCMD_SET_CREATE(wifi_commands, "monitor, TX-Injection and promiscuous mode is enabled.\n" "The different packet filter modes are control, management, data and enable all filters\n" "parameters:" - "[-i] : Interface index - optional argument.\n" - "[-a] : Enable all packet filter modes\n" - "[-m] : Enable management packets to allowed up the stack.\n" - "[-c] : Enable control packets to be allowed up the stack.\n" - "[-d] : Enable Data packets to be allowed up the stack.\n" - "[-g] : Get current filter settings for a specific interface index.\n" - "<-b> : Capture length buffer size for each packet to be captured - optional argument.\n" - "<-h> : Help.\n" + "[-i, --if-index ] : Interface index.\n" + "[-a, --all] : Enable all packet filter modes\n" + "[-m, --mgmt] : Enable management packets to allowed up the stack.\n" + "[-c, --ctrl] : Enable control packets to be allowed up the stack.\n" + "[-d, --data] : Enable Data packets to be allowed up the stack.\n" + "[-g, --get] : Get current filter settings for a specific interface index.\n" + "[-b, --capture-len ] : Capture length buffer size for each packet to be captured\n" + "[-h, --help] : Help.\n" "Usage: Get operation example for interface index 1\n" "wifi packet_filter -g -i1\n" "Set operation example for interface index 1 - set data+management frame filter\n" @@ -1722,10 +1722,10 @@ SHELL_STATIC_SUBCMD_SET_CREATE(wifi_commands, "monitor or TX-Injection mode is enabled.\n" "Currently 20 MHz is only supported and no BW parameter is provided\n" "parameters:" - "[-i] : Interface index - optional argument.\n" - "[-c] : Set a specific channel number to the lower layer.\n" - "[-g] : Get current set channel number from the lower layer.\n" - "[-h] : Help.\n" + "[-i, --if-index ] : Interface index.\n" + "[-c, --channel ] : Set a specific channel number to the lower layer.\n" + "[-g, --get] : Get current set channel number from the lower layer.\n" + "[-h, --help] : Help.\n" "Usage: Get operation example for interface index 1\n" "wifi channel -g -i1\n" "Set operation example for interface index 1 (setting channel 5)\n" From 213471f2ad0189c1871c1e0d3f15ecfaf896cc18 Mon Sep 17 00:00:00 2001 From: Declan Snyder Date: Thu, 30 Nov 2023 16:13:44 -0600 Subject: [PATCH 0654/3723] drivers: nxp_enet: simplify driver header Simplify the driver header implementation, so that there are not structs and unions different per each situtaion, and make just one function for the enet module drivers to call on each other. Also, capitalize existing enums. Signed-off-by: Declan Snyder --- drivers/ethernet/eth_nxp_enet.c | 33 +++++++++------- drivers/mdio/mdio_nxp_enet.c | 10 +++-- drivers/ptp_clock/ptp_clock_nxp_enet.c | 8 ++-- .../zephyr/drivers/ethernet/eth_nxp_enet.h | 38 ++++++++++++------- 4 files changed, 54 insertions(+), 35 deletions(-) diff --git a/drivers/ethernet/eth_nxp_enet.c b/drivers/ethernet/eth_nxp_enet.c index 6620049fcba..6537ea1c840 100644 --- a/drivers/ethernet/eth_nxp_enet.c +++ b/drivers/ethernet/eth_nxp_enet.c @@ -116,13 +116,6 @@ struct nxp_enet_mac_data { ******************** */ -extern void nxp_enet_mdio_callback(const struct device *mdio_dev, - enum nxp_enet_callback_reason event); - -extern void nxp_enet_ptp_clock_callback(const struct device *dev, - enum nxp_enet_callback_reason event, - union nxp_enet_ptp_data *ptp_data); - static inline struct net_if *get_iface(struct nxp_enet_mac_data *data, uint16_t vlan_tag) { #if defined(CONFIG_NET_VLAN) @@ -632,6 +625,22 @@ static int nxp_enet_phy_init(const struct device *dev) **************************** */ +void nxp_enet_driver_cb(const struct device *dev, + enum nxp_enet_driver dev_type, + enum nxp_enet_callback_reason event, + void *data) +{ + if (dev_type == NXP_ENET_MDIO) { + nxp_enet_mdio_callback(dev, event, data); + } + +#ifdef CONFIG_PTP_CLOCK_NXP_ENET + if (dev_type == NXP_ENET_PTP_CLOCK) { + nxp_enet_ptp_clock_callback(dev, event, data); + } +#endif +} + static void eth_callback(ENET_Type *base, enet_handle_t *handle, #if FSL_FEATURE_ENET_QUEUE > 1 uint32_t ringId, @@ -704,7 +713,7 @@ static void eth_nxp_enet_isr(const struct device *dev) if (eir & ENET_EIR_MII_MASK) { /* Callback to MDIO driver for relevant interrupt */ - nxp_enet_mdio_callback(config->mdio, nxp_enet_interrupt); + nxp_enet_driver_cb(config->mdio, NXP_ENET_MDIO, NXP_ENET_INTERRUPT, NULL); } irq_unlock(irq_lock_key); @@ -798,13 +807,11 @@ static int eth_nxp_enet_init(const struct device *dev) data->mac_addr, enet_module_clock_rate); - nxp_enet_mdio_callback(config->mdio, nxp_enet_module_reset); + nxp_enet_driver_cb(config->mdio, NXP_ENET_MDIO, NXP_ENET_MODULE_RESET, NULL); #if defined(CONFIG_PTP_CLOCK_NXP_ENET) - union nxp_enet_ptp_data ptp_data; - - nxp_enet_ptp_clock_callback(config->ptp_clock, nxp_enet_module_reset, &ptp_data); - data->ptp_mutex = ptp_data.for_mac.ptp_mutex; + nxp_enet_driver_cb(config->ptp_clock, NXP_ENET_PTP_CLOCK, + NXP_ENET_MODULE_RESET, &data->ptp_mutex); ENET_SetTxReclaim(&data->enet_handle, true, 0); #endif diff --git a/drivers/mdio/mdio_nxp_enet.c b/drivers/mdio/mdio_nxp_enet.c index 2ea43e48424..88a25f8c981 100644 --- a/drivers/mdio/mdio_nxp_enet.c +++ b/drivers/mdio/mdio_nxp_enet.c @@ -228,18 +228,20 @@ static void nxp_enet_mdio_post_module_reset_init(const struct device *dev) } void nxp_enet_mdio_callback(const struct device *dev, - enum nxp_enet_callback_reason event) + enum nxp_enet_callback_reason event, void *cb_data) { struct nxp_enet_mdio_data *data = dev->data; + ARG_UNUSED(cb_data); + switch (event) { - case nxp_enet_module_reset: + case NXP_ENET_MODULE_RESET: nxp_enet_mdio_post_module_reset_init(dev); break; - case nxp_enet_interrupt: + case NXP_ENET_INTERRUPT: nxp_enet_mdio_isr_cb(dev); break; - case nxp_enet_interrupt_enabled: + case NXP_ENET_INTERRUPT_ENABLED: data->interrupt_up = true; break; default: diff --git a/drivers/ptp_clock/ptp_clock_nxp_enet.c b/drivers/ptp_clock/ptp_clock_nxp_enet.c index 67f561e9bc0..821557cf79d 100644 --- a/drivers/ptp_clock/ptp_clock_nxp_enet.c +++ b/drivers/ptp_clock/ptp_clock_nxp_enet.c @@ -153,12 +153,12 @@ static int ptp_clock_nxp_enet_rate_adjust(const struct device *dev, void nxp_enet_ptp_clock_callback(const struct device *dev, enum nxp_enet_callback_reason event, - union nxp_enet_ptp_data *ptp_data) + void *data) { const struct ptp_clock_nxp_enet_config *config = dev->config; struct ptp_clock_nxp_enet_data *data = dev->data; - if (event == nxp_enet_module_reset) { + if (event == NXP_ENET_MODULE_RESET) { enet_ptp_config_t ptp_config; uint32_t enet_ref_pll_rate; uint8_t ptp_multicast[6] = { 0x01, 0x1B, 0x19, 0x00, 0x00, 0x00 }; @@ -181,9 +181,9 @@ void nxp_enet_ptp_clock_callback(const struct device *dev, &ptp_config); } - if (ptp_data != NULL) { + if (data != NULL) { /* Share the mutex with mac driver */ - ptp_data->for_mac.ptp_mutex = &data->ptp_mutex; + *(struct k_mutex *)data = &data->ptp_mutex; } } diff --git a/include/zephyr/drivers/ethernet/eth_nxp_enet.h b/include/zephyr/drivers/ethernet/eth_nxp_enet.h index 8dcb5f31c01..5fc5564b328 100644 --- a/include/zephyr/drivers/ethernet/eth_nxp_enet.h +++ b/include/zephyr/drivers/ethernet/eth_nxp_enet.h @@ -29,27 +29,37 @@ extern "C" { * Interrupt enable: The driver's relevant interrupt was enabled in NVIC */ enum nxp_enet_callback_reason { - nxp_enet_module_reset, - nxp_enet_interrupt, - nxp_enet_interrupt_enabled, + NXP_ENET_MODULE_RESET, + NXP_ENET_INTERRUPT, + NXP_ENET_INTERRUPT_ENABLED, }; -struct nxp_enet_ptp_data_for_mac { - struct k_mutex *ptp_mutex; +enum nxp_enet_driver { + NXP_ENET_MAC, + NXP_ENET_MDIO, + NXP_ENET_PTP_CLOCK, }; -union nxp_enet_ptp_data { - struct nxp_enet_ptp_data_for_mac for_mac; -}; - -/* Calback for mdio device called from mac driver */ -void nxp_enet_mdio_callback(const struct device *mdio_dev, - enum nxp_enet_callback_reason event); +extern void nxp_enet_mdio_callback(const struct device *mdio_dev, + enum nxp_enet_callback_reason event, + void *data); -void nxp_enet_ptp_clock_callback(const struct device *dev, +extern void nxp_enet_ptp_clock_callback(const struct device *dev, enum nxp_enet_callback_reason event, - union nxp_enet_ptp_data *ptp_data); + void *data); +/* + * Internal implementation, inter-driver communication function + * + * dev: target device to call back + * dev_type: which driver to call back + * event: reason/cause of callback + * data: opaque data, will be interpreted based on reason and target driver + */ +extern void nxp_enet_driver_cb(const struct device *dev, + enum nxp_enet_driver dev_type, + enum nxp_enet_callback_reason event, + void *data); #ifdef __cplusplus } From 67082289e1380294dc3266549db55468736814f8 Mon Sep 17 00:00:00 2001 From: Robert Lubos Date: Thu, 30 Nov 2023 13:45:35 +0100 Subject: [PATCH 0655/3723] net: l2: ethernet: Fix error handling after ARP prepare Commit 55802e5e8637949b113a9f225c9f9a11f7f9b49d fixed error handling of TX errors, in case ARP request was generated. There are however also other places where post-ARP cleanup should be done on the TX path (like running out of buffers for Ethernet L2 header allocation). This commit fixes those cases in ethernet_send(), where function would exit early and report error after ARP prepare stage. Signed-off-by: Robert Lubos --- subsys/net/l2/ethernet/ethernet.c | 36 +++++++++++++++++-------------- 1 file changed, 20 insertions(+), 16 deletions(-) diff --git a/subsys/net/l2/ethernet/ethernet.c b/subsys/net/l2/ethernet/ethernet.c index 2be3c5f2820..dd4d1e1bdbc 100644 --- a/subsys/net/l2/ethernet/ethernet.c +++ b/subsys/net/l2/ethernet/ethernet.c @@ -700,7 +700,7 @@ static int ethernet_send(struct net_if *iface, struct net_pkt *pkt) (IS_ENABLED(CONFIG_NET_GPTP_VLAN) || ptype != htons(NET_ETH_PTYPE_PTP))) { if (set_vlan_tag(ctx, iface, pkt) == NET_DROP) { ret = -EINVAL; - goto error; + goto arp_error; } set_vlan_priority(ctx, pkt); @@ -710,7 +710,7 @@ static int ethernet_send(struct net_if *iface, struct net_pkt *pkt) */ if (!ethernet_fill_header(ctx, pkt, ptype)) { ret = -ENOMEM; - goto error; + goto arp_error; } net_pkt_cursor_init(pkt); @@ -720,20 +720,7 @@ static int ethernet_send(struct net_if *iface, struct net_pkt *pkt) if (ret != 0) { eth_stats_update_errors_tx(iface); ethernet_remove_l2_header(pkt); - if (IS_ENABLED(CONFIG_NET_ARP) && ptype == htons(NET_ETH_PTYPE_ARP)) { - /* Original packet was added to ARP's pending Q, so, to avoid it - * being freed, take a reference, the reference is dropped when we - * clear the pending Q in ARP and then it will be freed by net_if. - */ - net_pkt_ref(orig_pkt); - if (net_arp_clear_pending(iface, - (struct in_addr *)NET_IPV4_HDR(pkt)->dst)) { - NET_DBG("Could not find pending ARP entry"); - } - /* Free the ARP request */ - net_pkt_unref(pkt); - } - goto error; + goto arp_error; } ethernet_update_tx_stats(iface, pkt); @@ -744,6 +731,23 @@ static int ethernet_send(struct net_if *iface, struct net_pkt *pkt) net_pkt_unref(pkt); error: return ret; + +arp_error: + if (IS_ENABLED(CONFIG_NET_ARP) && ptype == htons(NET_ETH_PTYPE_ARP)) { + /* Original packet was added to ARP's pending Q, so, to avoid it + * being freed, take a reference, the reference is dropped when we + * clear the pending Q in ARP and then it will be freed by net_if. + */ + net_pkt_ref(orig_pkt); + if (net_arp_clear_pending( + iface, (struct in_addr *)NET_IPV4_HDR(pkt)->dst)) { + NET_DBG("Could not find pending ARP entry"); + } + /* Free the ARP request */ + net_pkt_unref(pkt); + } + + return ret; } static inline int ethernet_enable(struct net_if *iface, bool state) From 839553a7d9e1155931c88633be412c7c602f3489 Mon Sep 17 00:00:00 2001 From: Robert Lubos Date: Thu, 30 Nov 2023 13:49:50 +0100 Subject: [PATCH 0656/3723] net: shell: ping: Fix double packet unref in ping reply handler This was somehow missed, but since ICMP rework, message handlers should not dereference the packet, as it's done by the ICMP lib. Signed-off-by: Robert Lubos --- subsys/net/lib/shell/ping.c | 2 -- 1 file changed, 2 deletions(-) diff --git a/subsys/net/lib/shell/ping.c b/subsys/net/lib/shell/ping.c index 8b52df110be..b31f6f686fd 100644 --- a/subsys/net/lib/shell/ping.c +++ b/subsys/net/lib/shell/ping.c @@ -104,7 +104,6 @@ static int handle_ipv6_echo_reply(struct net_icmp_ctx *ctx, ping_done(&ping_ctx); } - net_pkt_unref(pkt); return 0; } #else @@ -179,7 +178,6 @@ static int handle_ipv4_echo_reply(struct net_icmp_ctx *ctx, ping_done(&ping_ctx); } - net_pkt_unref(pkt); return 0; } #else From 8f0b1f642482cc61f6b021a42c7d9464a4125ee8 Mon Sep 17 00:00:00 2001 From: Henrik Eriksen Date: Wed, 22 Nov 2023 14:34:56 +0100 Subject: [PATCH 0657/3723] bluetooth: tester: HAS Preset initialization done by auto-pts client. - Removed preset initializations. Done in auto-pts client. - Added one additional preset in overlay-le-audio.conf. Signed-off-by: Henrik Eriksen --- tests/bluetooth/tester/overlay-le-audio.conf | 2 +- tests/bluetooth/tester/src/btp/btp_has.h | 1 + tests/bluetooth/tester/src/btp_has.c | 58 +++++--------------- 3 files changed, 16 insertions(+), 45 deletions(-) diff --git a/tests/bluetooth/tester/overlay-le-audio.conf b/tests/bluetooth/tester/overlay-le-audio.conf index 92739656e8c..1501365dd76 100644 --- a/tests/bluetooth/tester/overlay-le-audio.conf +++ b/tests/bluetooth/tester/overlay-le-audio.conf @@ -87,7 +87,7 @@ CONFIG_BT_IAS_CLIENT=y # HAS CONFIG_BT_HAS=y -CONFIG_BT_HAS_PRESET_COUNT=5 +CONFIG_BT_HAS_PRESET_COUNT=6 CONFIG_BT_HAS_PRESET_NAME_DYNAMIC=y # CSIS diff --git a/tests/bluetooth/tester/src/btp/btp_has.h b/tests/bluetooth/tester/src/btp/btp_has.h index fc87a3f3239..fe9f7dcb5f4 100644 --- a/tests/bluetooth/tester/src/btp/btp_has.h +++ b/tests/bluetooth/tester/src/btp/btp_has.h @@ -5,6 +5,7 @@ * * SPDX-License-Identifier: Apache-2.0 */ +#include /* HAS commands */ #define BTP_HAS_READ_SUPPORTED_COMMANDS 0x01 diff --git a/tests/bluetooth/tester/src/btp_has.c b/tests/bluetooth/tester/src/btp_has.c index d33d51f54ea..d90a635377a 100644 --- a/tests/bluetooth/tester/src/btp_has.c +++ b/tests/bluetooth/tester/src/btp_has.c @@ -21,8 +21,12 @@ static uint8_t has_supported_commands(const void *cmd, uint16_t cmd_len, { struct btp_has_read_supported_commands_rp *rp = rsp; - /* octet 0 */ tester_set_bit(rp->data, BTP_HAS_READ_SUPPORTED_COMMANDS); + tester_set_bit(rp->data, BTP_HAS_SET_ACTIVE_INDEX); + tester_set_bit(rp->data, BTP_HAS_SET_PRESET_NAME); + tester_set_bit(rp->data, BTP_HAS_REMOVE_PRESET); + tester_set_bit(rp->data, BTP_HAS_ADD_PRESET); + tester_set_bit(rp->data, BTP_HAS_SET_PROPERTIES); *rsp_len = sizeof(*rp) + 1; @@ -35,7 +39,7 @@ static uint8_t has_set_active_index(const void *cmd, uint16_t cmd_len, const struct btp_has_set_active_index_cmd *cp = cmd; int err = bt_has_preset_active_set(cp->index); - return (err) ? BTP_STATUS_FAILED : BTP_STATUS_SUCCESS; + return BTP_STATUS_VAL(err); } static uint16_t has_presets; @@ -55,7 +59,7 @@ static uint8_t has_set_preset_name(const void *cmd, uint16_t cmd_len, temp_name[name_len] = '\0'; err = bt_has_preset_name_change(cp->index, temp_name); } - return (err) ? BTP_STATUS_FAILED : BTP_STATUS_SUCCESS; + return BTP_STATUS_VAL(err); } static uint8_t has_remove_preset(const void *cmd, uint16_t cmd_len, @@ -80,7 +84,7 @@ static uint8_t has_remove_preset(const void *cmd, uint16_t cmd_len, has_presets &= ~(1 << (cp->index - 1)); } } - return (err) ? BTP_STATUS_FAILED : BTP_STATUS_SUCCESS; + return BTP_STATUS_VAL(err); } static int has_preset_selected(unsigned char index, bool sync) @@ -112,7 +116,7 @@ static uint8_t has_add_preset(const void *cmd, uint16_t cmd_len, has_presets |= 1 << (cp->index - 1); } } - return (err) ? BTP_STATUS_FAILED : BTP_STATUS_SUCCESS; + return BTP_STATUS_VAL(err); } static uint8_t has_set_properties(const void *cmd, uint16_t cmd_len, @@ -123,7 +127,7 @@ static uint8_t has_set_properties(const void *cmd, uint16_t cmd_len, bt_has_preset_available(cp->index) : bt_has_preset_unavailable(cp->index); - return (err) ? BTP_STATUS_FAILED : BTP_STATUS_SUCCESS; + return BTP_STATUS_VAL(err); } static const struct btp_handler has_handlers[] = { @@ -160,53 +164,19 @@ static const struct btp_handler has_handlers[] = { } }; -static const char *preset_name(uint8_t index) -{ - switch (index) { - case 0: return "PRESET_0"; - case 1: return "PRESET_1"; - case 2: return "PRESET_2"; - case 3: return "PRESET_3"; - case 4: return "PRESET_4"; - case 5: return "PRESET_5"; - case 6: return "PRESET_6"; - case 7: return "PRESET_7"; - default: return "PRESET_?"; - } -} - -#define PRESETS_CONFIGURED 3 -#define LAST_PRESET MIN(PRESETS_CONFIGURED, CONFIG_BT_HAS_PRESET_COUNT) - uint8_t tester_init_has(void) { tester_register_command_handlers(BTP_SERVICE_ID_HAS, has_handlers, ARRAY_SIZE(has_handlers)); struct bt_has_features_param params = { - BT_HAS_HEARING_AID_TYPE_BINAURAL, false, true + .type = BT_HAS_HEARING_AID_TYPE_BINAURAL, + .preset_sync_support = false, + .independent_presets = IS_ENABLED(CONFIG_BT_HAS_PRESET_SUPPORT) }; int err = bt_has_register(¶ms); - if (!err) { - for (uint8_t index = 1; index <= LAST_PRESET; index++) { - enum bt_has_properties properties = (index < PRESETS_CONFIGURED) ? - BT_HAS_PROP_WRITABLE | BT_HAS_PROP_AVAILABLE : - BT_HAS_PROP_WRITABLE; - struct bt_has_preset_register_param preset_params = { - index, properties, preset_name(index), &has_preset_ops - }; - - err = bt_has_preset_register(&preset_params); - if (!err) { - has_presets |= 1 << (index - 1); - } else { - break; - } - } - } - - return (err) ? BTP_STATUS_FAILED : BTP_STATUS_SUCCESS; + return BTP_STATUS_VAL(err); } uint8_t tester_unregister_has(void) From 47d9bad9627e6b77a083bc97a6df2ae93585f581 Mon Sep 17 00:00:00 2001 From: Marcio Ribeiro Date: Thu, 30 Nov 2023 08:49:51 -0300 Subject: [PATCH 0658/3723] manifest: esp32: update hal_espressif Update hal to cover latest features and fixes. Signed-off-by: Marcio Ribeiro --- west.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/west.yml b/west.yml index 65ea74174eb..cc1b69f83a5 100644 --- a/west.yml +++ b/west.yml @@ -152,7 +152,7 @@ manifest: groups: - hal - name: hal_espressif - revision: ffbe58815808af98d1e3241defa552a0fcc6d28a + revision: eb7e415dc115e57afe96f552493b19d49dfc8c0e path: modules/hal/espressif west-commands: west/west-commands.yml groups: From 76c4187bb0ec20de834f996342bb46a59b4fcc89 Mon Sep 17 00:00:00 2001 From: Marcio Ribeiro Date: Tue, 24 Oct 2023 10:30:13 -0300 Subject: [PATCH 0659/3723] drivers: sensor: esp32s3 internal temperature sensor Support for esp32s3 internal temperature sensor on Zephyr Signed-off-by: Marcio Ribeiro --- dts/bindings/sensor/espressif,esp32-temp.yaml | 8 ++++---- dts/xtensa/espressif/esp32s3/esp32s3_common.dtsi | 12 ++++++++++++ 2 files changed, 16 insertions(+), 4 deletions(-) diff --git a/dts/bindings/sensor/espressif,esp32-temp.yaml b/dts/bindings/sensor/espressif,esp32-temp.yaml index 32bf13a3013..31509f40251 100644 --- a/dts/bindings/sensor/espressif,esp32-temp.yaml +++ b/dts/bindings/sensor/espressif,esp32-temp.yaml @@ -11,10 +11,10 @@ properties: range: type: int description: | - The temperature sensor is available on the ESP32-S2, ESP32-C3. Note - that it is unavailable on the ESP32 due to missing offset calibration. - Temperature range is defined by the temperature offset which is used - during calculation of the output temperature from the measured value. + The temperature sensor is available on the ESP32-S2, ESP32-S3, ESP32-C3. + Note that it is unavailable on the ESP32 due to missing offset calibration. + Temperature range is defined by the temperature offset which is used during + calculation of the output temperature from the measured value. default: 2 enum: - 0 # measure range: 50°C ~ 125°C, error < 3°C diff --git a/dts/xtensa/espressif/esp32s3/esp32s3_common.dtsi b/dts/xtensa/espressif/esp32s3/esp32s3_common.dtsi index 3c373272593..65880b3afbc 100644 --- a/dts/xtensa/espressif/esp32s3/esp32s3_common.dtsi +++ b/dts/xtensa/espressif/esp32s3/esp32s3_common.dtsi @@ -13,6 +13,11 @@ #include / { + + aliases { + die-temp0 = &coretemp; + }; + chosen { zephyr,canbus = &twai; zephyr,entropy = &trng0; @@ -237,6 +242,13 @@ status = "disabled"; }; + coretemp: coretemp@60008800 { + compatible = "espressif,esp32-temp"; + friendly-name = "coretemp"; + reg = <0x60008800 0x4>; + status = "disabled"; + }; + adc0: adc@60040000 { compatible = "espressif,esp32-adc"; reg = <0x60040000 4>; From a8c8b46e23e75840039e48870fb60681e92883ff Mon Sep 17 00:00:00 2001 From: Marcio Ribeiro Date: Wed, 29 Nov 2023 14:33:35 -0300 Subject: [PATCH 0660/3723] samples: sensors: espressif board added to die_temp_polling Added board overlay file to permit internal temperature sensor testing: - esp32s3_devkitm Signed-off-by: Marcio Ribeiro --- .../die_temp_polling/boards/esp32s3_devkitm.overlay | 11 +++++++++++ 1 file changed, 11 insertions(+) create mode 100644 samples/sensor/die_temp_polling/boards/esp32s3_devkitm.overlay diff --git a/samples/sensor/die_temp_polling/boards/esp32s3_devkitm.overlay b/samples/sensor/die_temp_polling/boards/esp32s3_devkitm.overlay new file mode 100644 index 00000000000..aeb8043f621 --- /dev/null +++ b/samples/sensor/die_temp_polling/boards/esp32s3_devkitm.overlay @@ -0,0 +1,11 @@ +/* + * Copyright (c) 2023 Espressif Systems (Shanghai) Co., Ltd. + * + * SPDX-License-Identifier: Apache-2.0 + * + * Application overlay for enabling temperature sensor device instance + */ + +&coretemp { + status = "okay"; +}; From e3162c80d45f281e9615913571548d5a8b0b1bed Mon Sep 17 00:00:00 2001 From: Joakim Andersson Date: Mon, 27 Nov 2023 17:46:17 +0100 Subject: [PATCH 0661/3723] tfm: Add pin-control configuration for UART1 pin assignments Add pin-control configurations for UART1 pin assignments. The GPIO pins matches the ones used in Laird Connectivity TF-M boards RTE_Device.h file. Signed-off-by: Joakim Andersson --- .../bl5340_dvk_cpuapp_common-pinctrl.dtsi | 19 +++++++++++++++++++ .../bl5340_dvk/bl5340_dvk_cpuapp_common.dtsi | 7 +++++++ 2 files changed, 26 insertions(+) diff --git a/boards/arm/bl5340_dvk/bl5340_dvk_cpuapp_common-pinctrl.dtsi b/boards/arm/bl5340_dvk/bl5340_dvk_cpuapp_common-pinctrl.dtsi index 5020c9a7af9..a5d9b72b62e 100644 --- a/boards/arm/bl5340_dvk/bl5340_dvk_cpuapp_common-pinctrl.dtsi +++ b/boards/arm/bl5340_dvk/bl5340_dvk_cpuapp_common-pinctrl.dtsi @@ -89,6 +89,25 @@ }; }; + uart1_default: uart1_default { + group1 { + psels = , + , + , + ; + }; + }; + + uart1_sleep: uart1_sleep { + group1 { + psels = , + , + , + ; + low-power-enable; + }; + }; + pwm0_default: pwm0_default { group1 { psels = ; diff --git a/boards/arm/bl5340_dvk/bl5340_dvk_cpuapp_common.dtsi b/boards/arm/bl5340_dvk/bl5340_dvk_cpuapp_common.dtsi index 78d1f2debf7..04039294b76 100644 --- a/boards/arm/bl5340_dvk/bl5340_dvk_cpuapp_common.dtsi +++ b/boards/arm/bl5340_dvk/bl5340_dvk_cpuapp_common.dtsi @@ -244,6 +244,13 @@ pinctrl-names = "default", "sleep"; }; +&uart1 { + current-speed = <115200>; + pinctrl-0 = <&uart1_default>; + pinctrl-1 = <&uart1_sleep>; + pinctrl-names = "default", "sleep"; +}; + &pwm0 { status = "okay"; pinctrl-0 = <&pwm0_default>; From 8caae66eaef9df4cb94a1e96d7792818e2b4ddb1 Mon Sep 17 00:00:00 2001 From: Joakim Andersson Date: Mon, 27 Nov 2023 17:49:37 +0100 Subject: [PATCH 0662/3723] Kconfig: tfm: Switch BOARD_BL5340_DVK_CPUAPP_NS TF-M board selection Switch BOARD_BL5340_DVK_CPUAPP_NS TF-M board selection from using the platform support that is built-in to TF-M module, and instead use the generic nRF5340 cpuapp platform support that all other nrf5340 SoC related boards use. Signed-off-by: Joakim Andersson --- modules/trusted-firmware-m/Kconfig.tfm | 1 - 1 file changed, 1 deletion(-) diff --git a/modules/trusted-firmware-m/Kconfig.tfm b/modules/trusted-firmware-m/Kconfig.tfm index d29b7093de0..6c8db28c098 100644 --- a/modules/trusted-firmware-m/Kconfig.tfm +++ b/modules/trusted-firmware-m/Kconfig.tfm @@ -17,7 +17,6 @@ config TFM_BOARD default "stm/stm32l562e_dk" if BOARD_STM32L562E_DK default "arm/musca_b1" if BOARD_MUSCA_B1 default "arm/musca_s1" if BOARD_MUSCA_S1 - default "lairdconnectivity/bl5340_dvk_cpuapp" if BOARD_BL5340_DVK_CPUAPP_NS default "${ZEPHYR_BASE}/modules/trusted-firmware-m/nordic_nrf/nrf9160" if SOC_NRF9160 default "${ZEPHYR_BASE}/modules/trusted-firmware-m/nordic_nrf/nrf9120" if SOC_NRF9120 default "${ZEPHYR_BASE}/modules/trusted-firmware-m/nordic_nrf/nrf5340_cpuapp" if SOC_NRF5340_CPUAPP From 83ada28178dfa24ff0136bc1061ea397b97671b5 Mon Sep 17 00:00:00 2001 From: Joakim Andersson Date: Mon, 27 Nov 2023 17:51:07 +0100 Subject: [PATCH 0663/3723] boards: arm: bl5340_dvk: Remove disabling of QSPI for BL5340 DVS NS Remove disable of QSPI for BL5340 DVK cpuapp NS build. The QSPI is not configured as a secure peripheral in the generic nrf5340 platform support. Signed-off-by: Joakim Andersson --- boards/arm/bl5340_dvk/bl5340_dvk_cpuapp_ns.dts | 9 --------- 1 file changed, 9 deletions(-) diff --git a/boards/arm/bl5340_dvk/bl5340_dvk_cpuapp_ns.dts b/boards/arm/bl5340_dvk/bl5340_dvk_cpuapp_ns.dts index b943c5bdfbf..b0c2935e621 100644 --- a/boards/arm/bl5340_dvk/bl5340_dvk_cpuapp_ns.dts +++ b/boards/arm/bl5340_dvk/bl5340_dvk_cpuapp_ns.dts @@ -28,12 +28,3 @@ zephyr_udc0: &usbd { compatible = "nordic,nrf-usbd"; status = "okay"; }; - -&qspi { - status = "disabled"; - - /* Drop the flash and partitions to avoid the config being used for DFU - * samples. - */ - /delete-node/ mx25r6435f@0; -}; From 9781d13f19f33bb89cf384ce56f76d23b5ba1182 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Benjamin=20Bj=C3=B6rnsson?= Date: Fri, 17 Nov 2023 18:47:08 +0100 Subject: [PATCH 0664/3723] sensor: max17055: add missing return value check MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This commit adds a missing return value check during register read. Added an imidiate return to remove the seemingly unwanted side effect of also waiting for the bus read to work. Fixes #65383 Signed-off-by: Benjamin Björnsson --- drivers/sensor/max17055/max17055.c | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/drivers/sensor/max17055/max17055.c b/drivers/sensor/max17055/max17055.c index c2db8255623..530c152798d 100644 --- a/drivers/sensor/max17055/max17055.c +++ b/drivers/sensor/max17055/max17055.c @@ -427,6 +427,7 @@ static int max17055_gauge_init(const struct device *dev) { int16_t tmp; const struct max17055_config *const config = dev->config; + int ret; if (!device_is_ready(config->i2c.bus)) { LOG_ERR("Bus device is not ready"); @@ -445,7 +446,10 @@ static int max17055_gauge_init(const struct device *dev) /* Wait for FSTAT_DNR to be cleared */ tmp = FSTAT_DNR; while (tmp & FSTAT_DNR) { - max17055_reg_read(dev, FSTAT, &tmp); + ret = max17055_reg_read(dev, FSTAT, &tmp); + if (ret) { + return ret; + } } if (max17055_init_config(dev)) { From 0cec0dc7498c318b4d43e1a5586d0cdbb5b7b3d4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Benjamin=20Bj=C3=B6rnsson?= Date: Fri, 17 Nov 2023 20:37:00 +0100 Subject: [PATCH 0665/3723] sensor: max17055: add missing return value check MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This commit adds a missing return value check during register read. Added an imidiate return to remove the seemingly unwanted side effect of also waiting for the bus read to work. Fixes #65374 Signed-off-by: Benjamin Björnsson --- drivers/sensor/max17055/max17055.c | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/drivers/sensor/max17055/max17055.c b/drivers/sensor/max17055/max17055.c index 530c152798d..139cef36a5d 100644 --- a/drivers/sensor/max17055/max17055.c +++ b/drivers/sensor/max17055/max17055.c @@ -348,6 +348,7 @@ static int max17055_write_config(const struct device *dev) uint16_t d_pacc = d_qacc * 44138 / design_capacity; uint16_t i_chg_term = current_ma_to_max17055(config->rsense_mohms, config->i_chg_term); uint16_t v_empty; + int ret; LOG_DBG("Writing configuration parameters"); LOG_DBG("DesignCap: %u, dQAcc: %u, IChgTerm: %u, dPAcc: %u", @@ -386,7 +387,10 @@ static int max17055_write_config(const struct device *dev) uint16_t model_cfg = MODELCFG_REFRESH; while (model_cfg & MODELCFG_REFRESH) { - max17055_reg_read(dev, MODEL_CFG, &model_cfg); + ret = max17055_reg_read(dev, MODEL_CFG, &model_cfg); + if (ret) { + return ret; + } k_sleep(K_MSEC(10)); } From dc257830a518871c4ce3555a0d52e523a5f3876c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Benjamin=20Bj=C3=B6rnsson?= Date: Sat, 18 Nov 2023 01:27:45 +0100 Subject: [PATCH 0666/3723] sensor: adltc29990: add missing return value check MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This commit adds a missing return value check for a register read. The affected function was updated to use the regular errno return value and to pass the result through a pointer instead. Fixes #65346 Signed-off-by: Benjamin Björnsson --- drivers/sensor/adltc2990/adltc2990.c | 23 +++++++++++++++++++---- 1 file changed, 19 insertions(+), 4 deletions(-) diff --git a/drivers/sensor/adltc2990/adltc2990.c b/drivers/sensor/adltc2990/adltc2990.c index d9ac1643306..343c52eb6bd 100644 --- a/drivers/sensor/adltc2990/adltc2990.c +++ b/drivers/sensor/adltc2990/adltc2990.c @@ -93,13 +93,20 @@ static enum adltc2990_monitoring_type adltc2990_get_v3_v4_measurement_modes(uint return type; } -static bool adltc2990_is_busy(const struct device *dev) +static int adltc2990_is_busy(const struct device *dev, bool *is_busy) { const struct adltc2990_config *cfg = dev->config; uint8_t status_reg = 0; + int ret; - i2c_reg_read_byte_dt(&cfg->bus, ADLTC2990_REG_STATUS, &status_reg); - return status_reg & BIT(0); + ret = i2c_reg_read_byte_dt(&cfg->bus, ADLTC2990_REG_STATUS, &status_reg); + if (ret) { + return ret; + } + + *is_busy = status_reg & BIT(0); + + return 0; } static void adltc2990_get_v1_v2_val(const struct device *dev, struct sensor_value *val, @@ -240,6 +247,7 @@ static int adltc2990_sample_fetch(const struct device *dev, enum sensor_channel cfg->measurement_mode[1], cfg->measurement_mode[0]); float voltage_divider_ratio; + int ret; switch (chan) { case SENSOR_CHAN_DIE_TEMP: { @@ -334,7 +342,14 @@ static int adltc2990_sample_fetch(const struct device *dev, enum sensor_channel break; } case SENSOR_CHAN_ALL: { - if (adltc2990_is_busy(dev)) { + bool is_busy; + + ret = adltc2990_is_busy(dev, &is_busy); + if (ret) { + return ret; + } + + if (is_busy) { LOG_INF("ADLTC2990 conversion ongoing"); return -EBUSY; } From 445b43d40757b4bfd4586a5f460c2ebad92423fb Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Benjamin=20Bj=C3=B6rnsson?= Date: Sat, 18 Nov 2023 01:59:24 +0100 Subject: [PATCH 0667/3723] sensor: tsl2540: add missing return value check MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This commit adds a missing return value check. Since the I2C write failed we release the semaphore and returning immediatly instead of using goto exit. Fixes #65352 Signed-off-by: Benjamin Björnsson --- drivers/sensor/tsl2540/tsl2540.c | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/drivers/sensor/tsl2540/tsl2540.c b/drivers/sensor/tsl2540/tsl2540.c index fb3060d136e..1fc24ed6be3 100644 --- a/drivers/sensor/tsl2540/tsl2540.c +++ b/drivers/sensor/tsl2540/tsl2540.c @@ -162,8 +162,12 @@ static int tsl2540_attr_set(const struct device *dev, enum sensor_channel chan, k_sem_take(&data->sem, K_FOREVER); - i2c_reg_write_byte_dt(&cfg->i2c_spec, TSL2540_ENABLE_ADDR, TSL2540_ENABLE_MASK & - ~TSL2540_ENABLE_CONF); + ret = i2c_reg_write_byte_dt(&cfg->i2c_spec, TSL2540_ENABLE_ADDR, TSL2540_ENABLE_MASK & + ~TSL2540_ENABLE_CONF); + if (ret) { + k_sem_give(&data->sem); + return ret; + } #if CONFIG_TSL2540_TRIGGER if (chan == SENSOR_CHAN_LIGHT) { From ef871058aafe93b6a1bb1ac426916c8d134d263b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Benjamin=20Bj=C3=B6rnsson?= Date: Sat, 18 Nov 2023 09:58:33 +0100 Subject: [PATCH 0668/3723] sensor: tsl2540: add missing return value check MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This commit adds missing return value checks in driver initialization. Fixes #65345 Signed-off-by: Benjamin Björnsson --- drivers/sensor/tsl2540/tsl2540.c | 16 +++++++++++++--- 1 file changed, 13 insertions(+), 3 deletions(-) diff --git a/drivers/sensor/tsl2540/tsl2540.c b/drivers/sensor/tsl2540/tsl2540.c index 1fc24ed6be3..98516d5f296 100644 --- a/drivers/sensor/tsl2540/tsl2540.c +++ b/drivers/sensor/tsl2540/tsl2540.c @@ -292,6 +292,7 @@ static int tsl2540_init(const struct device *dev) { const struct tsl2540_config *cfg = dev->config; struct tsl2540_data *data = dev->data; + int ret; data->enable_mode = TSL2540_ENABLE_DISABLE; @@ -302,9 +303,18 @@ static int tsl2540_init(const struct device *dev) return -ENODEV; } - i2c_reg_write_byte_dt(&cfg->i2c_spec, TSL2540_REG_PERS, 1); - i2c_reg_update_byte_dt(&cfg->i2c_spec, TSL2540_CFG3_ADDR, TSL2540_CFG3_MASK, - TSL2540_CFG3_DFLT); + ret = i2c_reg_write_byte_dt(&cfg->i2c_spec, TSL2540_REG_PERS, 1); + if (ret) { + LOG_ERR("Failed to setup interrupt persistence filter"); + return ret; + } + + ret = i2c_reg_update_byte_dt(&cfg->i2c_spec, TSL2540_CFG3_ADDR, TSL2540_CFG3_MASK, + TSL2540_CFG3_DFLT); + if (ret) { + LOG_ERR("Failed to set configuration"); + return ret; + } if (tsl2540_setup(dev)) { LOG_ERR("Failed to setup ambient light functionality"); From 773257dda4e3e96f2e1be015fdcd0a0d49afc92b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Benjamin=20Bj=C3=B6rnsson?= Date: Sat, 18 Nov 2023 12:33:35 +0100 Subject: [PATCH 0669/3723] sensor: adltc2990: separate function return values MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This commit reworks the adltc2990_fetch_property_value function to pass its result through a variable pointer instead of direct return. This is done in part to separate the errno value being return in the default case of the switch from the result of the function, but also to make it easier the fix a Coverity issue regarding the unhandled return values of i2c reads. Signed-off-by: Benjamin Björnsson --- drivers/sensor/adltc2990/adltc2990.c | 103 ++++++++++++++++++--------- 1 file changed, 70 insertions(+), 33 deletions(-) diff --git a/drivers/sensor/adltc2990/adltc2990.c b/drivers/sensor/adltc2990/adltc2990.c index 343c52eb6bd..3fdfda24851 100644 --- a/drivers/sensor/adltc2990/adltc2990.c +++ b/drivers/sensor/adltc2990/adltc2990.c @@ -141,9 +141,10 @@ static int adltc2990_trigger_measurement(const struct device *dev) return i2c_reg_write_byte_dt(&cfg->bus, ADLTC2990_REG_TRIGGER, 0x1); } -static int32_t adltc2990_fetch_property_value(const struct device *dev, +static int adltc2990_fetch_property_value(const struct device *dev, enum adltc2990_monitoring_type type, - enum adltc2990_monitor_pins pin) + enum adltc2990_monitor_pins pin, + int32_t *output) { const struct adltc2990_config *cfg = dev->config; @@ -211,7 +212,9 @@ static int32_t adltc2990_fetch_property_value(const struct device *dev, int32_t voltage_value = (value << (31 - negative_bit_index)) >> (31 - negative_bit_index); - return (voltage_value * conversion_factor) / sensor_val_divisor; + *output = (voltage_value * conversion_factor) / sensor_val_divisor; + + return 0; } static int adltc2990_init(const struct device *dev) @@ -248,11 +251,16 @@ static int adltc2990_sample_fetch(const struct device *dev, enum sensor_channel float voltage_divider_ratio; int ret; + int32_t value; switch (chan) { case SENSOR_CHAN_DIE_TEMP: { - data->internal_temperature = - adltc2990_fetch_property_value(dev, TEMPERATURE, INTERNAL_TEMPERATURE); + ret = adltc2990_fetch_property_value(dev, TEMPERATURE, INTERNAL_TEMPERATURE, + &value); + if (ret) { + return ret; + } + data->internal_temperature = value; break; } case SENSOR_CHAN_CURRENT: { @@ -261,68 +269,91 @@ static int adltc2990_sample_fetch(const struct device *dev, enum sensor_channel return -EINVAL; } if (mode_v1_v2 == VOLTAGE_DIFFERENTIAL) { + ret = adltc2990_fetch_property_value(dev, VOLTAGE_DIFFERENTIAL, V1, &value); + if (ret) { + return ret; + } data->pins_v1_v2_values[0] = - adltc2990_fetch_property_value(dev, VOLTAGE_DIFFERENTIAL, V1) * - (ADLTC2990_MICROOHM_CONVERSION_FACTOR / + value * (ADLTC2990_MICROOHM_CONVERSION_FACTOR / (float)cfg->pins_v1_v2.pins_current_resistor); } if (mode_v3_v4 == VOLTAGE_DIFFERENTIAL) { - data->pins_v3_v4_values[0] = - adltc2990_fetch_property_value(dev, VOLTAGE_DIFFERENTIAL, V3) * - (ADLTC2990_MICROOHM_CONVERSION_FACTOR / + ret = adltc2990_fetch_property_value(dev, VOLTAGE_DIFFERENTIAL, V3, &value); + if (ret) { + return ret; + } + data->pins_v3_v4_values[0] = value * (ADLTC2990_MICROOHM_CONVERSION_FACTOR / (float)cfg->pins_v3_v4.pins_current_resistor); } break; } case SENSOR_CHAN_VOLTAGE: { - data->supply_voltage = - adltc2990_fetch_property_value(dev, VOLTAGE_SINGLEENDED, SUPPLY_VOLTAGE) + - 2500000; + ret = adltc2990_fetch_property_value(dev, VOLTAGE_SINGLEENDED, SUPPLY_VOLTAGE, + &value); + if (ret) { + return ret; + } + data->supply_voltage = value + 2500000; if (mode_v1_v2 == VOLTAGE_DIFFERENTIAL) { - data->pins_v1_v2_values[0] = - adltc2990_fetch_property_value(dev, VOLTAGE_DIFFERENTIAL, V1); + ret = adltc2990_fetch_property_value(dev, VOLTAGE_DIFFERENTIAL, V1, &value); + if (ret) { + return ret; + } + data->pins_v1_v2_values[0] = value; } else if (mode_v1_v2 == VOLTAGE_SINGLEENDED) { uint32_t v1_r1 = cfg->pins_v1_v2.voltage_divider_resistors.v1_r1_r2[0]; uint32_t v1_r2 = cfg->pins_v1_v2.voltage_divider_resistors.v1_r1_r2[1]; voltage_divider_ratio = (v1_r1 + v1_r2) / (float)v1_r2; - data->pins_v1_v2_values[0] = - adltc2990_fetch_property_value(dev, VOLTAGE_SINGLEENDED, V1) * - voltage_divider_ratio; + ret = adltc2990_fetch_property_value(dev, VOLTAGE_SINGLEENDED, V1, &value); + if (ret) { + return ret; + } + data->pins_v1_v2_values[0] = value * voltage_divider_ratio; uint32_t v2_r1 = cfg->pins_v1_v2.voltage_divider_resistors.v2_r1_r2[0]; uint32_t v2_r2 = cfg->pins_v1_v2.voltage_divider_resistors.v2_r1_r2[1]; voltage_divider_ratio = (v2_r1 + v2_r2) / (float)v2_r2; - data->pins_v1_v2_values[1] = - adltc2990_fetch_property_value(dev, VOLTAGE_SINGLEENDED, V2) * - voltage_divider_ratio; + ret = adltc2990_fetch_property_value(dev, VOLTAGE_SINGLEENDED, V2, &value); + if (ret) { + return ret; + } + data->pins_v1_v2_values[1] = value * voltage_divider_ratio; } if (mode_v3_v4 == VOLTAGE_DIFFERENTIAL) { - data->pins_v3_v4_values[0] = - adltc2990_fetch_property_value(dev, VOLTAGE_DIFFERENTIAL, V3); + ret = adltc2990_fetch_property_value(dev, VOLTAGE_DIFFERENTIAL, V3, &value); + if (ret) { + return ret; + } + data->pins_v3_v4_values[0] = value; } else if (mode_v3_v4 == VOLTAGE_SINGLEENDED) { uint32_t v3_r1 = cfg->pins_v3_v4.voltage_divider_resistors.v3_r1_r2[0]; uint32_t v3_r2 = cfg->pins_v3_v4.voltage_divider_resistors.v3_r1_r2[1]; voltage_divider_ratio = (v3_r1 + v3_r2) / (float)v3_r2; - data->pins_v3_v4_values[0] = - adltc2990_fetch_property_value(dev, VOLTAGE_SINGLEENDED, V3) * - voltage_divider_ratio; + ret = adltc2990_fetch_property_value(dev, VOLTAGE_SINGLEENDED, V3, &value); + if (ret) { + return ret; + } + data->pins_v3_v4_values[0] = value * voltage_divider_ratio; uint32_t v4_r1 = cfg->pins_v3_v4.voltage_divider_resistors.v4_r1_r2[0]; uint32_t v4_r2 = cfg->pins_v3_v4.voltage_divider_resistors.v4_r1_r2[1]; voltage_divider_ratio = (v4_r1 + v4_r2) / (float)v4_r2; - data->pins_v3_v4_values[1] = - adltc2990_fetch_property_value(dev, VOLTAGE_SINGLEENDED, V4) * - voltage_divider_ratio; + + ret = adltc2990_fetch_property_value(dev, VOLTAGE_SINGLEENDED, V4, &value); + if (ret) { + return ret; + } + data->pins_v3_v4_values[1] = value * voltage_divider_ratio; } break; } @@ -332,12 +363,18 @@ static int adltc2990_sample_fetch(const struct device *dev, enum sensor_channel return -EINVAL; } if (mode_v1_v2 == TEMPERATURE) { - data->pins_v1_v2_values[0] = - adltc2990_fetch_property_value(dev, TEMPERATURE, V1); + ret = adltc2990_fetch_property_value(dev, TEMPERATURE, V1, &value); + if (ret) { + return ret; + } + data->pins_v1_v2_values[0] = value; } if (mode_v3_v4 == TEMPERATURE) { - data->pins_v3_v4_values[0] = - adltc2990_fetch_property_value(dev, TEMPERATURE, V3); + ret = adltc2990_fetch_property_value(dev, TEMPERATURE, V3, &value); + if (ret) { + return ret; + } + data->pins_v3_v4_values[0] = value; } break; } From 8c0b3ca2fd51edb9aa2b4e7e4db84ee26366fa89 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Benjamin=20Bj=C3=B6rnsson?= Date: Sat, 18 Nov 2023 12:35:59 +0100 Subject: [PATCH 0670/3723] sensor: adltc2990: add missing return value checks MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This commit adds two missing return value checks for i2c reads. Fixes #65328 Signed-off-by: Benjamin Björnsson --- drivers/sensor/adltc2990/adltc2990.c | 14 +++++++++++--- 1 file changed, 11 insertions(+), 3 deletions(-) diff --git a/drivers/sensor/adltc2990/adltc2990.c b/drivers/sensor/adltc2990/adltc2990.c index 3fdfda24851..ea56065ede6 100644 --- a/drivers/sensor/adltc2990/adltc2990.c +++ b/drivers/sensor/adltc2990/adltc2990.c @@ -142,7 +142,7 @@ static int adltc2990_trigger_measurement(const struct device *dev) } static int adltc2990_fetch_property_value(const struct device *dev, - enum adltc2990_monitoring_type type, + enum adltc2990_monitoring_type type, enum adltc2990_monitor_pins pin, int32_t *output) { @@ -187,9 +187,17 @@ static int adltc2990_fetch_property_value(const struct device *dev, return -EINVAL; } } + int ret; + + ret = i2c_reg_read_byte_dt(&cfg->bus, msb_address, &msb_value); + if (ret) { + return ret; + } - i2c_reg_read_byte_dt(&cfg->bus, msb_address, &msb_value); - i2c_reg_read_byte_dt(&cfg->bus, lsb_address, &lsb_value); + ret = i2c_reg_read_byte_dt(&cfg->bus, lsb_address, &lsb_value); + if (ret) { + return ret; + } uint16_t conversion_factor; uint8_t negative_bit_index = 14U, sensor_val_divisor = 100U; From 3be26c4cb9f02ad0799ea6cc20df401d5c1fa7d2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?H=C3=A5vard=20Reierstad?= Date: Thu, 23 Nov 2023 12:09:17 +0100 Subject: [PATCH 0671/3723] Bluetooth: Mesh: advertiser: add disable function MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Adds a disable function for the extended advertising which stops and deletes the advertising instances, allowing them to be properly reinitialized when calling `bt_mesh_adv_enable()` after bluetooth has been disabled and re-enabled. For the legacy advertising, the function terminates the advertising thread. If legacy advertising is used, `bt_mesh_adv_init()` must be called before `bt_mesh_adv_enable()` to properly resume advertising after suspension. Signed-off-by: Håvard Reierstad --- include/zephyr/bluetooth/mesh/main.h | 4 ++++ subsys/bluetooth/mesh/adv.h | 3 +++ subsys/bluetooth/mesh/adv_ext.c | 30 ++++++++++++++++++++++++++++ subsys/bluetooth/mesh/adv_legacy.c | 21 ++++++++++++++++--- 4 files changed, 55 insertions(+), 3 deletions(-) diff --git a/include/zephyr/bluetooth/mesh/main.h b/include/zephyr/bluetooth/mesh/main.h index 8e7445fae6f..a213e8ce22c 100644 --- a/include/zephyr/bluetooth/mesh/main.h +++ b/include/zephyr/bluetooth/mesh/main.h @@ -607,6 +607,10 @@ void bt_mesh_reset(void); * If at all possible, the Friendship feature should be used instead, to * make the node into a Low Power Node. * + * @note Should not be called from work queue due to undefined behavior. + * This is due to k_work_flush_delayable() being used in disabling of the + * extended advertising. + * * @return 0 on success, or (negative) error code on failure. */ int bt_mesh_suspend(void); diff --git a/subsys/bluetooth/mesh/adv.h b/subsys/bluetooth/mesh/adv.h index a80ff7e8d4b..42b07601ad5 100644 --- a/subsys/bluetooth/mesh/adv.h +++ b/subsys/bluetooth/mesh/adv.h @@ -80,6 +80,9 @@ int bt_mesh_scan_disable(void); int bt_mesh_adv_enable(void); +/* Should not be called from work queue due to undefined behavior */ +int bt_mesh_adv_disable(void); + void bt_mesh_adv_buf_local_ready(void); void bt_mesh_adv_buf_relay_ready(void); diff --git a/subsys/bluetooth/mesh/adv_ext.c b/subsys/bluetooth/mesh/adv_ext.c index 0bfc2041c7d..38efbb4901c 100644 --- a/subsys/bluetooth/mesh/adv_ext.c +++ b/subsys/bluetooth/mesh/adv_ext.c @@ -506,6 +506,36 @@ int bt_mesh_adv_enable(void) return 0; } +int bt_mesh_adv_disable(void) +{ + int err; + struct k_work_sync sync; + + for (int i = 0; i < ARRAY_SIZE(advs); i++) { + k_work_flush_delayable(&advs[i].work, &sync); + + err = bt_le_ext_adv_stop(advs[i].instance); + if (err) { + LOG_ERR("Failed to stop adv %d", err); + return err; + } + + /* `adv_sent` is called to finish transmission of an adv buffer that was pushed to + * the host before the advertiser was stopped, but did not finish. + */ + adv_sent(advs[i].instance, NULL); + + err = bt_le_ext_adv_delete(advs[i].instance); + if (err) { + LOG_ERR("Failed to delete adv %d", err); + return err; + } + advs[i].instance = NULL; + } + + return 0; +} + int bt_mesh_adv_gatt_start(const struct bt_le_adv_param *param, int32_t duration, const struct bt_data *ad, size_t ad_len, diff --git a/subsys/bluetooth/mesh/adv_legacy.c b/subsys/bluetooth/mesh/adv_legacy.c index a7d7dd1a320..aef13864131 100644 --- a/subsys/bluetooth/mesh/adv_legacy.c +++ b/subsys/bluetooth/mesh/adv_legacy.c @@ -39,6 +39,7 @@ LOG_MODULE_REGISTER(bt_mesh_adv_legacy); static struct k_thread adv_thread_data; static K_KERNEL_STACK_DEFINE(adv_thread_stack, CONFIG_BT_MESH_ADV_STACK_SIZE); static int32_t adv_timeout; +static bool enabled; static int bt_data_send(uint8_t num_events, uint16_t adv_int, const struct bt_data *ad, size_t ad_len, @@ -144,10 +145,9 @@ static inline void buf_send(struct net_buf *buf) static void adv_thread(void *p1, void *p2, void *p3) { LOG_DBG("started"); + struct net_buf *buf; - while (1) { - struct net_buf *buf; - + while (enabled) { if (IS_ENABLED(CONFIG_BT_MESH_GATT_SERVER)) { buf = bt_mesh_adv_buf_get(K_NO_WAIT); if (IS_ENABLED(CONFIG_BT_MESH_PROXY_SOLICITATION) && !buf) { @@ -188,6 +188,12 @@ static void adv_thread(void *p1, void *p2, void *p3) /* Give other threads a chance to run */ k_yield(); } + + /* Empty the advertising pool when advertising is disabled */ + while ((buf = bt_mesh_adv_buf_get(K_NO_WAIT))) { + bt_mesh_adv_send_start(0, -ENODEV, BT_MESH_ADV(buf)); + net_buf_unref(buf); + } } void bt_mesh_adv_buf_local_ready(void) @@ -221,10 +227,19 @@ void bt_mesh_adv_init(void) int bt_mesh_adv_enable(void) { + enabled = true; k_thread_start(&adv_thread_data); return 0; } +int bt_mesh_adv_disable(void) +{ + enabled = false; + k_thread_join(&adv_thread_data, K_FOREVER); + LOG_DBG("Advertising disabled"); + return 0; +} + int bt_mesh_adv_gatt_start(const struct bt_le_adv_param *param, int32_t duration, const struct bt_data *ad, size_t ad_len, const struct bt_data *sd, size_t sd_len) From 897a1d0d1cec1ba8bc811a335fc414f8fe1960f0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?H=C3=A5vard=20Reierstad?= Date: Thu, 23 Nov 2023 12:09:18 +0100 Subject: [PATCH 0672/3723] Bluetooth: Mesh: suspend/resume advertising MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Disables Mesh advertising when suspending, and enables advertising when resuming Mesh. Signed-off-by: Håvard Reierstad --- subsys/bluetooth/mesh/main.c | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) diff --git a/subsys/bluetooth/mesh/main.c b/subsys/bluetooth/mesh/main.c index 2c78ea227de..24bbd7c7e94 100644 --- a/subsys/bluetooth/mesh/main.c +++ b/subsys/bluetooth/mesh/main.c @@ -460,6 +460,13 @@ int bt_mesh_suspend(void) bt_mesh_model_foreach(model_suspend, NULL); + err = bt_mesh_adv_disable(); + if (err) { + atomic_clear_bit(bt_mesh.flags, BT_MESH_SUSPENDED); + LOG_WRN("Disabling advertisers failed (err %d)", err); + return err; + } + return 0; } @@ -488,6 +495,17 @@ int bt_mesh_resume(void) return -EALREADY; } + if (!IS_ENABLED(CONFIG_BT_EXT_ADV)) { + bt_mesh_adv_init(); + } + + err = bt_mesh_adv_enable(); + if (err) { + atomic_set_bit(bt_mesh.flags, BT_MESH_SUSPENDED); + LOG_WRN("Re-enabling advertisers failed (err %d)", err); + return err; + } + err = bt_mesh_scan_enable(); if (err) { LOG_WRN("Re-enabling scanning failed (err %d)", err); From 10259063315de6d9532cf9f60ef5af2fad6380f8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?H=C3=A5vard=20Reierstad?= Date: Thu, 23 Nov 2023 12:09:18 +0100 Subject: [PATCH 0673/3723] bsim: Bluetooth: Mesh: Add suspension test MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Adds two test-cases; one for suspending and resuming Mesh, and one for suspending Mesh and disabling Bluetooth before re-enabling Bluetooth and resuming Mesh. Both tests checks that periodic publication is stopped during suspension. Signed-off-by: Håvard Reierstad --- tests/bsim/bluetooth/mesh/CMakeLists.txt | 2 + tests/bsim/bluetooth/mesh/src/main.c | 4 + tests/bsim/bluetooth/mesh/src/test_suspend.c | 312 ++++++++++++++++++ .../suspend/suspend_disable_resume.sh | 33 ++ .../tests_scripts/suspend/suspend_resume.sh | 32 ++ 5 files changed, 383 insertions(+) create mode 100644 tests/bsim/bluetooth/mesh/src/test_suspend.c create mode 100755 tests/bsim/bluetooth/mesh/tests_scripts/suspend/suspend_disable_resume.sh create mode 100755 tests/bsim/bluetooth/mesh/tests_scripts/suspend/suspend_resume.sh diff --git a/tests/bsim/bluetooth/mesh/CMakeLists.txt b/tests/bsim/bluetooth/mesh/CMakeLists.txt index 44c72dd9cbb..c6e09abe9c8 100644 --- a/tests/bsim/bluetooth/mesh/CMakeLists.txt +++ b/tests/bsim/bluetooth/mesh/CMakeLists.txt @@ -58,6 +58,7 @@ elseif(CONFIG_BT_CTLR_LOW_LAT) target_sources(app PRIVATE src/test_friendship.c src/test_transport.c + src/test_suspend.c ) else() @@ -72,6 +73,7 @@ else() src/test_access.c src/test_iv_index.c src/test_advertiser.c + src/test_suspend.c ) if(CONFIG_BT_MESH_V1d1) diff --git a/tests/bsim/bluetooth/mesh/src/main.c b/tests/bsim/bluetooth/mesh/src/main.c index 127e52faa49..67544e494d0 100644 --- a/tests/bsim/bluetooth/mesh/src/main.c +++ b/tests/bsim/bluetooth/mesh/src/main.c @@ -26,6 +26,7 @@ extern struct bst_test_list *test_beacon_install(struct bst_test_list *tests); #elif defined(CONFIG_BT_CTLR_LOW_LAT) extern struct bst_test_list *test_transport_install(struct bst_test_list *tests); extern struct bst_test_list *test_friendship_install(struct bst_test_list *tests); +extern struct bst_test_list *test_suspend_install(struct bst_test_list *test); #else extern struct bst_test_list *test_transport_install(struct bst_test_list *tests); extern struct bst_test_list *test_friendship_install(struct bst_test_list *tests); @@ -36,6 +37,7 @@ extern struct bst_test_list *test_heartbeat_install(struct bst_test_list *test); extern struct bst_test_list *test_access_install(struct bst_test_list *test); extern struct bst_test_list *test_ivi_install(struct bst_test_list *test); extern struct bst_test_list *test_adv_install(struct bst_test_list *test); +extern struct bst_test_list *test_suspend_install(struct bst_test_list *test); #if defined(CONFIG_BT_MESH_V1d1) extern struct bst_test_list *test_blob_install(struct bst_test_list *test); extern struct bst_test_list *test_op_agg_install(struct bst_test_list *test); @@ -63,6 +65,7 @@ bst_test_install_t test_installers[] = { #elif defined(CONFIG_BT_CTLR_LOW_LAT) test_transport_install, test_friendship_install, + test_suspend_install, #else test_transport_install, test_friendship_install, @@ -73,6 +76,7 @@ bst_test_install_t test_installers[] = { test_access_install, test_ivi_install, test_adv_install, + test_suspend_install, #if defined(CONFIG_BT_MESH_V1d1) test_blob_install, test_op_agg_install, diff --git a/tests/bsim/bluetooth/mesh/src/test_suspend.c b/tests/bsim/bluetooth/mesh/src/test_suspend.c new file mode 100644 index 00000000000..a83ee025909 --- /dev/null +++ b/tests/bsim/bluetooth/mesh/src/test_suspend.c @@ -0,0 +1,312 @@ +/* + * Copyright (c) 2023 Nordic Semiconductor + * + * SPDX-License-Identifier: Apache-2.0 + * + */ + +#include "mesh_test.h" + +#include +#include +#include + +#include +LOG_MODULE_REGISTER(test_suspend, LOG_LEVEL_INF); + +#define WAIT_TIME 60 /* seconds */ +#define SUSPEND_DURATION 15 /* seconds */ +#define NUM_PUB 4 /* Times the transmitter will publish per interval. */ + +#define TEST_MODEL_ID_1 0x2a2a +#define TEST_MODEL_ID_2 0x2b2b +#define TEST_MESSAGE_OP 0x1f + +static int model_1_init(const struct bt_mesh_model *model); +static int model_2_init(const struct bt_mesh_model *model); + +static uint8_t app_key[16] = {0xaa}; +static uint8_t net_key[16] = {0xcc}; + +static const struct bt_mesh_test_cfg tx_cfg = { + .addr = 0x00a0, + .dev_key = {0x01}, +}; +static const struct bt_mesh_test_cfg rx_cfg = { + .addr = 0x00b0, + .dev_key = {0x02}, +}; + +static struct bt_mesh_prov prov; +static struct k_sem publish_sem; +static bool suspended; + +static int model_1_update(const struct bt_mesh_model *model) +{ + model->pub->msg->data[1]++; + LOG_INF("Model 1 publishing..., n: %d", model->pub->msg->data[1]); + k_sem_give(&publish_sem); + return 0; +} + +static int msg_handler(const struct bt_mesh_model *model, struct bt_mesh_msg_ctx *ctx, + struct net_buf_simple *buf) +{ + static uint8_t prev_num; + uint8_t num = net_buf_simple_pull_u8(buf); + + LOG_INF("Received msg, n: %d", num); + + /* Ensure that payload changes. */ + ASSERT_TRUE(prev_num != num); + prev_num = num; + + /* Ensure that no message is received while Mesh is suspended or disabled. */ + ASSERT_FALSE_MSG(suspended, "Received publication while Mesh is suspended."); + + k_sem_give(&publish_sem); + return 0; +} + +BT_MESH_MODEL_PUB_DEFINE(model_1_pub, model_1_update, 4); + +static const struct bt_mesh_model_cb model_1_cb = { + .init = model_1_init, +}; + +static const struct bt_mesh_model_cb model_2_cb = { + .init = model_2_init, +}; + +static const struct bt_mesh_model_op model_op_1[] = {BT_MESH_MODEL_OP_END}; + +static const struct bt_mesh_model_op model_op_2[] = {{TEST_MESSAGE_OP, 0, msg_handler}, + BT_MESH_MODEL_OP_END}; + +static struct bt_mesh_cfg_cli cfg_cli_tx; +static struct bt_mesh_model tx_models[] = { + BT_MESH_MODEL_CFG_SRV, + BT_MESH_MODEL_CFG_CLI(&cfg_cli_tx), + BT_MESH_MODEL_CB(TEST_MODEL_ID_1, model_op_1, &model_1_pub, NULL, &model_1_cb), +}; + +static struct bt_mesh_elem tx_elems[] = { + BT_MESH_ELEM(0, tx_models, BT_MESH_MODEL_NONE), +}; + +static const struct bt_mesh_comp tx_comp = { + .cid = TEST_VND_COMPANY_ID, + .vid = 0xeeee, + .pid = 0xaaaa, + .elem = tx_elems, + .elem_count = ARRAY_SIZE(tx_elems), +}; + +static struct bt_mesh_cfg_cli cfg_cli_rx; +static struct bt_mesh_model rx_models[] = { + BT_MESH_MODEL_CFG_SRV, + BT_MESH_MODEL_CFG_CLI(&cfg_cli_rx), + BT_MESH_MODEL_CB(TEST_MODEL_ID_2, model_op_2, NULL, NULL, &model_2_cb), +}; + +static struct bt_mesh_elem rx_elems[] = { + BT_MESH_ELEM(0, rx_models, BT_MESH_MODEL_NONE), +}; + +static const struct bt_mesh_comp rx_comp = { + .cid = TEST_VND_COMPANY_ID, + .vid = 0xbaaa, + .pid = 0xb000, + .elem = rx_elems, + .elem_count = ARRAY_SIZE(rx_elems), +}; + +static int model_1_init(const struct bt_mesh_model *model) +{ + bt_mesh_model_msg_init(model->pub->msg, TEST_MESSAGE_OP); + net_buf_simple_add_u8(model->pub->msg, 1); + + return 0; +} + +static int model_2_init(const struct bt_mesh_model *model) +{ + return 0; +} + +static void provision_and_configure(struct bt_mesh_test_cfg cfg, bool rx) +{ + int err; + uint8_t status; + + ASSERT_OK(bt_mesh_provision(net_key, 0, 0, 0, cfg.addr, cfg.dev_key)); + + err = bt_mesh_cfg_cli_app_key_add(0, cfg.addr, 0, 0, app_key, &status); + if (err || status) { + FAIL("AppKey add failed (err %d, status %u)", err, status); + } + + const struct bt_mesh_test_cfg *pcfg = rx ? &rx_cfg : &tx_cfg; + uint16_t model_id = rx ? TEST_MODEL_ID_2 : TEST_MODEL_ID_1; + + err = bt_mesh_cfg_cli_mod_app_bind(0, pcfg->addr, pcfg->addr, 0, model_id, &status); + if (err || status) { + FAIL("Model %#4x bind failed (err %d, status %u)", model_id, err, status); + } +} + +struct bt_mesh_cfg_cli_mod_pub pub_params = { + .addr = rx_cfg.addr, + .uuid = NULL, + .cred_flag = false, + .app_idx = 0, + .ttl = 5, + .period = BT_MESH_PUB_PERIOD_SEC(1), + .transmit = 0, +}; + +static void test_tx_suspend_resume(void) +{ + bt_mesh_test_cfg_set(NULL, WAIT_TIME); + bt_mesh_device_setup(&prov, &tx_comp); + provision_and_configure(tx_cfg, 0); + + k_sem_init(&publish_sem, 0, 1); + suspended = false; + uint8_t status; + int err; + + err = bt_mesh_cfg_cli_mod_pub_set(0, tx_cfg.addr, tx_cfg.addr, TEST_MODEL_ID_1, &pub_params, + &status); + if (err || status) { + FAIL("Mod pub set failed (err %d, status %u)", err, status); + } + + /* Wait until node has published before suspending. */ + for (int i = 0; i < NUM_PUB; i++) { + ASSERT_OK_MSG(k_sem_take(&publish_sem, K_SECONDS(30)), "Pub timed out"); + } + + ASSERT_OK(bt_mesh_suspend()); + suspended = true; + LOG_INF("Mesh suspended."); + + k_sleep(K_SECONDS(SUSPEND_DURATION)); + + ASSERT_OK(bt_mesh_resume()); + suspended = false; + LOG_INF("Mesh resumed."); + + for (int i = 0; i < NUM_PUB; i++) { + ASSERT_OK_MSG(k_sem_take(&publish_sem, K_SECONDS(30)), "Pub timed out"); + } + + /* Allow publishing to finish before suspending. */ + k_sleep(K_MSEC(100)); + ASSERT_OK(bt_mesh_suspend()); + + PASS(); +} + +static void test_rx_suspend_resume(void) +{ + bt_mesh_test_cfg_set(NULL, WAIT_TIME); + bt_mesh_device_setup(&prov, &rx_comp); + provision_and_configure(rx_cfg, 1); + k_sem_init(&publish_sem, 0, 1); + + /* Receive messages before and after suspending. A publication may get lost + * when suspending immeditiately after publication, thus the "-1". + */ + for (int i = 0; i < NUM_PUB * 2 - 1; i++) { + ASSERT_OK_MSG(k_sem_take(&publish_sem, K_SECONDS(30)), "Receiver timed out"); + } + + PASS(); +} + +static void test_tx_suspend_disable_resume(void) +{ + bt_mesh_test_cfg_set(NULL, WAIT_TIME); + bt_mesh_device_setup(&prov, &tx_comp); + provision_and_configure(tx_cfg, 0); + + k_sem_init(&publish_sem, 0, 1); + suspended = false; + uint8_t status; + int err; + + err = bt_mesh_cfg_cli_mod_pub_set(0, tx_cfg.addr, tx_cfg.addr, TEST_MODEL_ID_1, &pub_params, + &status); + if (err || status) { + FAIL("Mod pub set failed (err %d, status %u)", err, status); + } + + /* Wait until node has published before suspending. */ + for (int i = 0; i < NUM_PUB; i++) { + ASSERT_OK_MSG(k_sem_take(&publish_sem, K_SECONDS(30)), "Pub timed out"); + } + + ASSERT_OK(bt_mesh_suspend()); + suspended = true; + LOG_INF("Mesh suspended."); + + ASSERT_OK(bt_disable()); + LOG_INF("Bluetooth disabled."); + + k_sleep(K_SECONDS(SUSPEND_DURATION)); + + ASSERT_OK(bt_enable(NULL)); + LOG_INF("Bluetooth enabled."); + + ASSERT_OK(bt_mesh_resume()); + suspended = false; + LOG_INF("Mesh resumed."); + + for (int i = 0; i < NUM_PUB; i++) { + ASSERT_OK_MSG(k_sem_take(&publish_sem, K_SECONDS(30)), "Pub timed out"); + } + + /* Allow publishing to finish before suspending. */ + k_sleep(K_MSEC(100)); + ASSERT_OK(bt_mesh_suspend()); + PASS(); +} + +static void test_rx_suspend_disable_resume(void) +{ + bt_mesh_test_cfg_set(NULL, WAIT_TIME); + bt_mesh_device_setup(&prov, &rx_comp); + provision_and_configure(rx_cfg, 1); + k_sem_init(&publish_sem, 0, 1); + + /* Receive messages before and after suspending. A publication may get lost + * when suspending immeditiately after publication, thus the "-1". + */ + for (int i = 0; i < NUM_PUB * 2 - 1; i++) { + ASSERT_OK_MSG(k_sem_take(&publish_sem, K_SECONDS(30)), "Receiver timed out"); + } + + PASS(); +} + +#define TEST_CASE(role, name, description) \ + { \ + .test_id = "suspend_" #role "_" #name, .test_descr = description, \ + .test_tick_f = bt_mesh_test_timeout, .test_main_f = test_##role##_##name, \ + } + +static const struct bst_test_instance test_suspend[] = { + TEST_CASE(tx, suspend_resume, "tx suspend resume"), + TEST_CASE(tx, suspend_disable_resume, "tx suspend, disable resume"), + + TEST_CASE(rx, suspend_resume, "rx suspend resume"), + TEST_CASE(rx, suspend_disable_resume, "rx suspend, disable resume"), + + BSTEST_END_MARKER}; + +struct bst_test_list *test_suspend_install(struct bst_test_list *tests) +{ + tests = bst_add_tests(tests, test_suspend); + return tests; +} diff --git a/tests/bsim/bluetooth/mesh/tests_scripts/suspend/suspend_disable_resume.sh b/tests/bsim/bluetooth/mesh/tests_scripts/suspend/suspend_disable_resume.sh new file mode 100755 index 00000000000..6390b2e193c --- /dev/null +++ b/tests/bsim/bluetooth/mesh/tests_scripts/suspend/suspend_disable_resume.sh @@ -0,0 +1,33 @@ +#!/usr/bin/env bash +# Copyright 2023 Nordic Semiconductor +# SPDX-License-Identifier: Apache-2.0 + +source $(dirname "${BASH_SOURCE[0]}")/../../_mesh_test.sh + +# Test that periodic publication is stopped when suspending Mesh and disabling +# Bluetooth, and that it is started again when Bluetooth is re-enabled and Mesh is resumed. +# The test will fail under two conditions; if no publication is received while +# Mesh is enabled, or if a publication is received while Mesh is suspended. +# +# Test procedure: +# 0. Provisioning and setup. +# 1. Start publication. +# 2. Suspend Mesh and disable Bluetooth, checking that publication stops. +# 3. Enable Bluetooth and resume Mesh a specified time after suspension. +# Check that publication resumes. + +RunTest mesh_suspend_disable_resume \ + suspend_tx_suspend_disable_resume suspend_rx_suspend_disable_resume + +conf=prj_mesh1d1_conf +RunTest mesh_suspend_disable_resume_1d1 \ + suspend_tx_suspend_disable_resume suspend_rx_suspend_disable_resume + +overlay=overlay_low_lat_conf +RunTest mesh_suspend_disable_resume_low_lat \ + suspend_tx_suspend_disable_resume suspend_rx_suspend_disable_resume + +conf=prj_mesh1d1_conf +overlay=overlay_psa_conf +RunTest mesh_suspend_disable_resume_psa \ + suspend_tx_suspend_disable_resume suspend_rx_suspend_disable_resume diff --git a/tests/bsim/bluetooth/mesh/tests_scripts/suspend/suspend_resume.sh b/tests/bsim/bluetooth/mesh/tests_scripts/suspend/suspend_resume.sh new file mode 100755 index 00000000000..5d4da84a165 --- /dev/null +++ b/tests/bsim/bluetooth/mesh/tests_scripts/suspend/suspend_resume.sh @@ -0,0 +1,32 @@ +#!/usr/bin/env bash +# Copyright 2023 Nordic Semiconductor +# SPDX-License-Identifier: Apache-2.0 + +source $(dirname "${BASH_SOURCE[0]}")/../../_mesh_test.sh + +# Test that periodic publication is stopped when suspending Mesh, and that it +# is started again when Mesh is resumed. The test will fail under two +# conditions; if no publication is received while Mesh is enabled, +# or if a publication is received while Mesh is suspended. +# +# Test procedure: +# 0. Provisioning and setup. +# 1. Start publication. +# 2. Suspend Mesh, checking that publication stops. +# 3. Resume Mesh a specified time after suspension. Check that publication resumes. + +RunTest mesh_suspend_resume \ + suspend_tx_suspend_resume suspend_rx_suspend_resume + +conf=prj_mesh1d1_conf +RunTest mesh_suspend_resume_1d1 \ + suspend_tx_suspend_resume suspend_rx_suspend_resume + +overlay=overlay_low_lat_conf +RunTest mesh_suspend_resume_low_lat \ + suspend_tx_suspend_resume suspend_rx_suspend_resume + +conf=prj_mesh1d1_conf +overlay=overlay_psa_conf +RunTest mesh_suspend_resume_psa \ + suspend_tx_suspend_resume suspend_rx_suspend_resume From c1bbd4865965429a92dab5ae6e4712e35d4b2507 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?H=C3=A5vard=20Reierstad?= Date: Thu, 23 Nov 2023 12:09:18 +0100 Subject: [PATCH 0674/3723] bsim: Bluetooth: Mesh: fix provision timeout MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Adapts the `pb_remote_timeout` test to the updated `bt_mesh_suspend` API. Suspension is scheduled with a small delay to allow publications to be sent before suspending Mesh. Signed-off-by: Håvard Reierstad --- tests/bsim/bluetooth/mesh/src/test_provision.c | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) diff --git a/tests/bsim/bluetooth/mesh/src/test_provision.c b/tests/bsim/bluetooth/mesh/src/test_provision.c index f2c98778a3b..0d7f1811833 100644 --- a/tests/bsim/bluetooth/mesh/src/test_provision.c +++ b/tests/bsim/bluetooth/mesh/src/test_provision.c @@ -152,14 +152,20 @@ static const struct bt_mesh_comp rpr_cli_srv_comp = { .elem_count = 1, }; -static int mock_pdu_send(const struct bt_mesh_model *model, struct bt_mesh_msg_ctx *ctx, - struct net_buf_simple *buf) +/* Delayed work to suspend device to allow publication to finish. */ +static struct k_work_delayable suspend_work; +static void delayed_suspend(struct k_work *work) { /* Device becomes unresponsive and doesn't communicate with other nodes anymore */ bt_mesh_suspend(); k_sem_give(&pdu_send_sem); +} +static int mock_pdu_send(const struct bt_mesh_model *model, struct bt_mesh_msg_ctx *ctx, + struct net_buf_simple *buf) +{ + k_work_schedule(&suspend_work, K_MSEC(100)); return 0; } @@ -1271,6 +1277,7 @@ static void test_device_pb_remote_server_unproved(void) */ static void test_device_pb_remote_server_unproved_unresponsive(void) { + k_work_init_delayable(&suspend_work, delayed_suspend); device_pb_remote_server_setup_unproved(&rpr_srv_comp_unresponsive, NULL); k_sem_init(&pdu_send_sem, 0, 1); From 04c165ad4d1ea3b19fd5645289ccb876ebaeae82 Mon Sep 17 00:00:00 2001 From: Martin Kiepfer Date: Sun, 26 Nov 2023 16:27:41 +0100 Subject: [PATCH 0675/3723] m5stack_core2: SDHC: SD card support added * SD card support via sdhc-spi driver added. SPI speed is configured to 20MHz for stability reasons. Some cards seem to not working properly with 25HMz or even higher speeds. * Pinmux ctrl for SPI3 pins reworked. Native cs removed as gpio chip-selects are required. Signed-off-by: Martin Kiepfer --- .../m5stack_core2/m5stack_core2-pinctrl.dtsi | 15 +-------------- boards/xtensa/m5stack_core2/m5stack_core2.dts | 16 +++++++++++++++- 2 files changed, 16 insertions(+), 15 deletions(-) diff --git a/boards/xtensa/m5stack_core2/m5stack_core2-pinctrl.dtsi b/boards/xtensa/m5stack_core2/m5stack_core2-pinctrl.dtsi index ac0908ac62a..05db025471f 100644 --- a/boards/xtensa/m5stack_core2/m5stack_core2-pinctrl.dtsi +++ b/boards/xtensa/m5stack_core2/m5stack_core2-pinctrl.dtsi @@ -39,8 +39,7 @@ spim3_default: spim3_default { group1 { pinmux = , - , - ; + ; }; group2 { pinmux = ; @@ -48,18 +47,6 @@ }; }; - spim2_default: spim2_default { - group1 { - pinmux = , - , - ; - }; - group2 { - pinmux = ; - output-low; - }; - }; - i2c0_default: i2c0_default { group1 { pinmux = , diff --git a/boards/xtensa/m5stack_core2/m5stack_core2.dts b/boards/xtensa/m5stack_core2/m5stack_core2.dts index 41ccb5be074..5aa8e88bf2c 100644 --- a/boards/xtensa/m5stack_core2/m5stack_core2.dts +++ b/boards/xtensa/m5stack_core2/m5stack_core2.dts @@ -182,10 +182,12 @@ pinctrl-names = "default"; dma-enabled; clock-frequency = <20000000>; - cs-gpios = <&gpio0 5 GPIO_ACTIVE_LOW>; + cs-gpios = <&gpio0 5 GPIO_ACTIVE_LOW>, + <&gpio0 4 GPIO_ACTIVE_LOW>; ili9342c: ili9342c@0 { compatible = "ilitek,ili9342c"; + status = "okay"; spi-max-frequency = <30000000>; reg = <0>; cmd-data-gpios = <&gpio0 15 GPIO_ACTIVE_LOW>; @@ -197,6 +199,18 @@ height = <240>; rotation = <0>; }; + + sdhc0: sdhc@1 { + compatible = "zephyr,sdhc-spi-slot"; + reg = <1>; + status = "okay"; + spi-max-frequency = <20000000>; + mmc { + compatible = "zephyr,sdmmc-disk"; + status = "okay"; + }; + + }; }; From 0a962b8893477845dee077338dad84091c5e2ffa Mon Sep 17 00:00:00 2001 From: Martin Kiepfer Date: Sun, 26 Nov 2023 16:27:41 +0100 Subject: [PATCH 0676/3723] m5stack_core2: doc: SD-card status documented Added support column for all features of m5stack_core2 board. Link to m5stack_core2_ext added. Signed-off-by: Martin Kiepfer --- boards/xtensa/m5stack_core2/doc/index.rst | 64 ++++++++++++----------- 1 file changed, 33 insertions(+), 31 deletions(-) diff --git a/boards/xtensa/m5stack_core2/doc/index.rst b/boards/xtensa/m5stack_core2/doc/index.rst index 4ca27c546f5..11fd9b9826e 100644 --- a/boards/xtensa/m5stack_core2/doc/index.rst +++ b/boards/xtensa/m5stack_core2/doc/index.rst @@ -50,37 +50,39 @@ of the M5Stack Core2 board. .. _PMU-AXP192: https://m5stack.oss-cn-shenzhen.aliyuncs.com/resource/docs/datasheet/core/AXP192_datasheet_en.pdf .. _VIB-1072_RFN01: https://m5stack.oss-cn-shenzhen.aliyuncs.com/resource/docs/datasheet/core/1027RFN01-33d.pdf -+------------------+--------------------------------------------------------------------------+ -| Key Component | Description | -+==================+==========================================================================+ -|| ESP32-D0WDQ6-V2 || This `MPU-ESP32`_ module provides complete Wi-Fi and Bluetooth | -|| module || functionalities and integrates a 16-MB SPI flash. | -+------------------+--------------------------------------------------------------------------+ -|| 32.768 kHz RTC || External precision 32.768 kHz crystal oscillator serves as a clock with | -|| || low-power consumption while the chip is in Deep-sleep mode. | -+------------------+--------------------------------------------------------------------------+ -| Status LED | One user LED connected to the GPIO pin. | -+------------------+--------------------------------------------------------------------------+ -|| USB Port || USB interface. Power supply for the board as well as the | -|| || communication interface between a computer and the board. | -|| || Contains: TypeC x 1, GROVE(I2C+I/O+UART) x 1 | -+------------------+--------------------------------------------------------------------------+ -| Reset button | Reset button | -+------------------+--------------------------------------------------------------------------+ -| Power Switch | Power on/off button. | -+------------------+--------------------------------------------------------------------------+ -|| LCD screen || Built-in LCD TFT display \(`LCD-ILI9342C`_, 2", 320x240 px\) | -|| || controlled via SPI interface | -+------------------+--------------------------------------------------------------------------+ -|| 6-axis IMU || The `MPU-6886`_ is a 6-axis motion tracker (6DOF IMU) device that | -|| MPU6886 || combines a 3-axis gyroscope and a 3-axis accelerometer. | -|| || For details please refer to :ref:`m5stack_core2_ext` | -+------------------+--------------------------------------------------------------------------+ -|| Built-in || The `SPM-1423`_ I2S driven microphone. | -|| microphone || | -+------------------+--------------------------------------------------------------------------+ -| Built-in speaker | 1W speaker for audio output via I2S interface. | -+------------------+--------------------------------------------------------------------------+ ++------------------+--------------------------------------------------------------------------+------------+ +| Key Component | Description | Status | ++==================+==========================================================================+============+ +|| ESP32-D0WDQ6-V2 || This `MPU-ESP32`_ module provides complete Wi-Fi and Bluetooth || supported | +|| module || functionalities and integrates a 16-MB SPI flash. || | ++------------------+--------------------------------------------------------------------------+------------+ +|| 32.768 kHz RTC || External precision 32.768 kHz crystal oscillator serves as a clock with || supported | +|| || low-power consumption while the chip is in Deep-sleep mode. || | ++------------------+--------------------------------------------------------------------------+------------+ +| Status LED | One user LED connected to the GPIO pin. | supported | ++------------------+--------------------------------------------------------------------------+------------+ +|| USB Port || USB interface. Power supply for the board as well as the || supported | +|| || communication interface between a computer and the board. || | +|| || Contains: TypeC x 1, GROVE(I2C+I/O+UART) x 1 || | ++------------------+--------------------------------------------------------------------------+------------+ +| Reset button | Reset button | supported | ++------------------+--------------------------------------------------------------------------+------------+ +| Power Switch | Power on/off button. | supported | ++------------------+--------------------------------------------------------------------------+------------+ +|| LCD screen || Built-in LCD TFT display \(`LCD-ILI9342C`_, 2", 320x240 px\) || supported | +|| || controlled via SPI interface || | ++------------------+--------------------------------------------------------------------------+------------+ +| SD-Card slot | SD-Card connection via SPI-mode. | supported | ++------------------+--------------------------------------------------------------------------+------------+ +|| 6-axis IMU || The `MPU-6886`_ is a 6-axis motion tracker (6DOF IMU) device that || todo | +|| MPU6886 || combines a 3-axis gyroscope and a 3-axis accelerometer. || | +|| || For details please refer to :ref:`m5stack_core2_ext` || | ++------------------+--------------------------------------------------------------------------+------------+ +|| Built-in || The `SPM-1423`_ I2S driven microphone. || todo | +|| microphone || || | ++------------------+--------------------------------------------------------------------------+------------+ +| Built-in speaker | 1W speaker for audio output via I2S interface. | todo | ++------------------+--------------------------------------------------------------------------+------------+ Supported Features ================== From 535ca1c76258dec9e2db8d168ad5b509dde19ca1 Mon Sep 17 00:00:00 2001 From: Lukas Jung Date: Tue, 11 Jul 2023 15:26:00 +0200 Subject: [PATCH 0677/3723] boards: arm: add the Adafruit Grand Central M4 Express The Adafruit Grand Central M4 Express is an ARM development board with the form factor of an Arduino Mega. It features 70 GPIO pins, a microSDHC slot and 8MiB of QSPI Flash. Signed-off-by: Lukas Jung --- .../Kconfig.board | 8 + .../Kconfig.defconfig | 8 + ...ruit_grand_central_m4_express-pinctrl.dtsi | 45 ++++ .../adafruit_grand_central_m4_express.dts | 133 ++++++++++++ .../adafruit_grand_central_m4_express.yaml | 17 ++ ...dafruit_grand_central_m4_express_defconfig | 19 ++ .../board.cmake | 5 + .../adafruit_grand_central_m4_express.webp | Bin 0 -> 39286 bytes .../doc/index.rst | 195 ++++++++++++++++++ .../support/openocd.cfg | 18 ++ 10 files changed, 448 insertions(+) create mode 100644 boards/arm/adafruit_grand_central_m4_express/Kconfig.board create mode 100644 boards/arm/adafruit_grand_central_m4_express/Kconfig.defconfig create mode 100644 boards/arm/adafruit_grand_central_m4_express/adafruit_grand_central_m4_express-pinctrl.dtsi create mode 100644 boards/arm/adafruit_grand_central_m4_express/adafruit_grand_central_m4_express.dts create mode 100644 boards/arm/adafruit_grand_central_m4_express/adafruit_grand_central_m4_express.yaml create mode 100644 boards/arm/adafruit_grand_central_m4_express/adafruit_grand_central_m4_express_defconfig create mode 100644 boards/arm/adafruit_grand_central_m4_express/board.cmake create mode 100644 boards/arm/adafruit_grand_central_m4_express/doc/img/adafruit_grand_central_m4_express.webp create mode 100644 boards/arm/adafruit_grand_central_m4_express/doc/index.rst create mode 100644 boards/arm/adafruit_grand_central_m4_express/support/openocd.cfg diff --git a/boards/arm/adafruit_grand_central_m4_express/Kconfig.board b/boards/arm/adafruit_grand_central_m4_express/Kconfig.board new file mode 100644 index 00000000000..4ca7a712697 --- /dev/null +++ b/boards/arm/adafruit_grand_central_m4_express/Kconfig.board @@ -0,0 +1,8 @@ +# Adafruit Grand Central M4 Express board configuration + +# Copyright (c) 2023 Lukas Jung +# SPDX-License-Identifier: Apache-2.0 + +config BOARD_ADAFRUIT_GRAND_CENTRAL_M4_EXPRESS + bool "Adafruit Grand Central M4 Express" + depends on SOC_PART_NUMBER_SAMD51P20A diff --git a/boards/arm/adafruit_grand_central_m4_express/Kconfig.defconfig b/boards/arm/adafruit_grand_central_m4_express/Kconfig.defconfig new file mode 100644 index 00000000000..72266e97bac --- /dev/null +++ b/boards/arm/adafruit_grand_central_m4_express/Kconfig.defconfig @@ -0,0 +1,8 @@ +# Adafruit Grand Central M4 Express board configuration + +# Copyright (c) 2023 Lukas Jung +# SPDX-License-Identifier: Apache-2.0 + +config BOARD + default "adafruit_grand_central_m4_express" + depends on BOARD_ADAFRUIT_GRAND_CENTRAL_M4_EXPRESS diff --git a/boards/arm/adafruit_grand_central_m4_express/adafruit_grand_central_m4_express-pinctrl.dtsi b/boards/arm/adafruit_grand_central_m4_express/adafruit_grand_central_m4_express-pinctrl.dtsi new file mode 100644 index 00000000000..6dcd448bebd --- /dev/null +++ b/boards/arm/adafruit_grand_central_m4_express/adafruit_grand_central_m4_express-pinctrl.dtsi @@ -0,0 +1,45 @@ +/* + * Copyright (c) 2023 Lukas Jung + * SPDX-License-Identifier: Apache-2.0 + */ + +#include + +&pinctrl { + sercom0_uart_default: sercom0_uart_default { + group1 { + pinmux = , + ; + }; + }; + + sercom2_spi_default: sercom2_spi_default { + group1 { + pinmux = , + , + ; + }; + }; + + sercom3_i2c_default: sercom3_i2c_default { + group1 { + pinmux = , + ; + }; + }; + + sercom7_spi_default: sercom7_spi_default { + group1 { + pinmux = , + , + ; + }; + }; + + usb_dc_default: usb_dc_default { + group1 { + pinmux = , + ; + }; + }; +}; diff --git a/boards/arm/adafruit_grand_central_m4_express/adafruit_grand_central_m4_express.dts b/boards/arm/adafruit_grand_central_m4_express/adafruit_grand_central_m4_express.dts new file mode 100644 index 00000000000..5cc038332b1 --- /dev/null +++ b/boards/arm/adafruit_grand_central_m4_express/adafruit_grand_central_m4_express.dts @@ -0,0 +1,133 @@ +/* + * Copyright (c) 2023 Lukas Jung + * SPDX-License-Identifier: Apache-2.0 + */ + +/dts-v1/; +#include +#include "adafruit_grand_central_m4_express-pinctrl.dtsi" + +/ { + model = "Adafruit Grand Central M4 Express"; + compatible = "adafruit,grand-central-m4-express"; + + chosen { + zephyr,console = &sercom0; + zephyr,shell-uart = &sercom0; + zephyr,sram = &sram0; + zephyr,flash = &flash0; + zephyr,code-partition = &code_partition; + }; + + /* These aliases are provided for compatibility with samples */ + aliases { + led0 = &led0; + sdhc0 = &sdhc0; + }; + + leds { + compatible = "gpio-leds"; + led0: led_0 { + gpios = <&portb 1 0>; + label = "LED"; + }; + }; +}; + +&cpu0 { + clock-frequency = <120000000>; +}; + +&sercom0 { + status = "okay"; + compatible = "atmel,sam0-uart"; + current-speed = <115200>; + rxpo = <1>; + txpo = <0>; + + pinctrl-0 = <&sercom0_uart_default>; + pinctrl-names = "default"; +}; + +&sercom2 { + status = "okay"; + compatible = "atmel,sam0-spi"; + dipo = <3>; + dopo = <0>; + + #address-cells = <1>; + #size-cells = <0>; + + pinctrl-0 = <&sercom2_spi_default>; + pinctrl-names = "default"; + + cs-gpios = <&portb 28 GPIO_ACTIVE_LOW>; + + /* microSD Card */ + sdhc0: sdhc@0 { + status = "okay"; + compatible = "zephyr,sdhc-spi-slot"; + reg = <0>; + spi-max-frequency = <20000000>; + mmc { + status = "okay"; + compatible = "zephyr,sdmmc-disk"; + }; + }; +}; + +&sercom3 { + status = "okay"; + compatible = "atmel,sam0-i2c"; + clock-frequency = ; + + #address-cells = <1>; + #size-cells = <0>; + + pinctrl-0 = <&sercom3_i2c_default>; + pinctrl-names = "default"; +}; + +&sercom7 { + status = "okay"; + compatible = "atmel,sam0-spi"; + dipo = <3>; + dopo = <0>; + + #address-cells = <1>; + #size-cells = <0>; + + pinctrl-0 = <&sercom7_spi_default>; + pinctrl-names = "default"; +}; + +zephyr_udc0: &usb0 { + status = "okay"; + + pinctrl-0 = <&usb_dc_default>; + pinctrl-names = "default"; +}; + +&dmac { + status = "okay"; +}; + +&flash0 { + partitions { + compatible = "fixed-partitions"; + #address-cells = <1>; + #size-cells = <1>; + + boot_partition: partition@0 { + label = "uf2"; + reg = <0x00000000 DT_SIZE_K(16)>; + read-only; + }; + + code_partition: partition@4000 { + label = "code"; + reg = <0x4000 DT_SIZE_K(1024-16)>; + read-only; + }; + }; +}; diff --git a/boards/arm/adafruit_grand_central_m4_express/adafruit_grand_central_m4_express.yaml b/boards/arm/adafruit_grand_central_m4_express/adafruit_grand_central_m4_express.yaml new file mode 100644 index 00000000000..0afd44c0af8 --- /dev/null +++ b/boards/arm/adafruit_grand_central_m4_express/adafruit_grand_central_m4_express.yaml @@ -0,0 +1,17 @@ +identifier: adafruit_grand_central_m4_express +name: Adafruit Grand Central M4 Express +type: mcu +arch: arm +ram: 256 +flash: 1024 +toolchain: + - zephyr + - gnuarmemb +supported: + - dma + - gpio + - i2c + - spi + - uart + - usb_device + - watchdog diff --git a/boards/arm/adafruit_grand_central_m4_express/adafruit_grand_central_m4_express_defconfig b/boards/arm/adafruit_grand_central_m4_express/adafruit_grand_central_m4_express_defconfig new file mode 100644 index 00000000000..b5bfafe5b18 --- /dev/null +++ b/boards/arm/adafruit_grand_central_m4_express/adafruit_grand_central_m4_express_defconfig @@ -0,0 +1,19 @@ +# SPDX-License-Identifier: Apache-2.0 + +CONFIG_SOC_SERIES_SAMD51=y +CONFIG_SOC_PART_NUMBER_SAMD51P20A=y +CONFIG_BOARD_ADAFRUIT_GRAND_CENTRAL_M4_EXPRESS=y +CONFIG_SOC_ATMEL_SAMD5X_XOSC32K=y +CONFIG_SOC_ATMEL_SAMD5X_XOSC32K_AS_MAIN=y +CONFIG_ARM_MPU=y +CONFIG_HW_STACK_PROTECTION=y +CONFIG_CONSOLE=y +CONFIG_UART_CONSOLE=y +CONFIG_UART_INTERRUPT_DRIVEN=y +CONFIG_SERIAL=y +CONFIG_GPIO=y + +CONFIG_BOOTLOADER_BOSSA=y +CONFIG_BOOTLOADER_BOSSA_ADAFRUIT_UF2=y +CONFIG_BUILD_OUTPUT_UF2=y +CONFIG_BUILD_OUTPUT_HEX=y diff --git a/boards/arm/adafruit_grand_central_m4_express/board.cmake b/boards/arm/adafruit_grand_central_m4_express/board.cmake new file mode 100644 index 00000000000..c5e25934fa5 --- /dev/null +++ b/boards/arm/adafruit_grand_central_m4_express/board.cmake @@ -0,0 +1,5 @@ +# Copyright (c) 2023 Lukas Jung +# SPDX-License-Identifier: Apache-2.0 + +include(${ZEPHYR_BASE}/boards/common/bossac.board.cmake) +include(${ZEPHYR_BASE}/boards/common/openocd.board.cmake) diff --git a/boards/arm/adafruit_grand_central_m4_express/doc/img/adafruit_grand_central_m4_express.webp b/boards/arm/adafruit_grand_central_m4_express/doc/img/adafruit_grand_central_m4_express.webp new file mode 100644 index 0000000000000000000000000000000000000000..33e0a97394acd07cf7f6197484bb9a0a622120eb GIT binary patch literal 39286 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 z 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 uX(cbiFqh5! Date: Mon, 4 Dec 2023 09:21:08 +0100 Subject: [PATCH 0678/3723] dts: arm: stm32f7 vref calibration address fixed This PR set the correct value for the stm32F7 devices. And change vrefint-cal-addr to <0x1FF07A2A> for stm32F722-F723 soc serie. Signed-off-by: Francois Ramu --- dts/arm/st/f7/stm32f7.dtsi | 2 +- dts/arm/st/f7/stm32f723.dtsi | 5 +++++ 2 files changed, 6 insertions(+), 1 deletion(-) diff --git a/dts/arm/st/f7/stm32f7.dtsi b/dts/arm/st/f7/stm32f7.dtsi index e59b41a7744..f2d336d7b6d 100644 --- a/dts/arm/st/f7/stm32f7.dtsi +++ b/dts/arm/st/f7/stm32f7.dtsi @@ -860,7 +860,7 @@ vref: vref { compatible = "st,stm32-vref"; - vrefint-cal-addr = <0x1FFF7A2A>; + vrefint-cal-addr = <0x1FF0F44A>; vrefint-cal-mv = <3300>; io-channels = <&adc1 17>; status = "disabled"; diff --git a/dts/arm/st/f7/stm32f723.dtsi b/dts/arm/st/f7/stm32f723.dtsi index e47698a1dea..2b2031d89b5 100644 --- a/dts/arm/st/f7/stm32f723.dtsi +++ b/dts/arm/st/f7/stm32f723.dtsi @@ -51,6 +51,11 @@ }; }; + vref: vref { + compatible = "st,stm32-vref"; + vrefint-cal-addr = <0x1FF07A2A>; + }; + die_temp: dietemp { ts-cal1-addr = <0x1FF07A2C>; ts-cal2-addr = <0x1FF07A2E>; From de0268def0c38df8b85fa465cadf9441a6b11e6b Mon Sep 17 00:00:00 2001 From: Jukka Rissanen Date: Mon, 27 Nov 2023 17:23:15 +0200 Subject: [PATCH 0679/3723] net: context: Add support for adjusting IPv4 multicast ttl Add option support for adjusting the IPv4 multicast time-to-live value. Fixes #60299 Signed-off-by: Jukka Rissanen --- include/zephyr/net/net_context.h | 17 +++++++++- include/zephyr/net/net_if.h | 20 ++++++++++++ include/zephyr/net/socket.h | 3 ++ subsys/net/ip/Kconfig.ipv4 | 21 +++++++++++-- subsys/net/ip/igmp.c | 11 +++++-- subsys/net/ip/ipv4.c | 26 +++++++++++----- subsys/net/ip/ipv4.h | 8 ++--- subsys/net/ip/net_context.c | 52 +++++++++++++++++++++++++++++++ subsys/net/ip/net_if.c | 42 +++++++++++++++++++++++++ subsys/net/l2/virtual/ipip/ipip.c | 2 +- subsys/net/lib/sockets/sockets.c | 20 ++++++++++++ tests/net/icmp/src/main.c | 4 ++- 12 files changed, 205 insertions(+), 21 deletions(-) diff --git a/include/zephyr/net/net_context.h b/include/zephyr/net/net_context.h index 7e73bf8eee7..f089658df31 100644 --- a/include/zephyr/net/net_context.h +++ b/include/zephyr/net/net_context.h @@ -349,7 +349,10 @@ __net_socket struct net_context { /** IPv6 hop limit or IPv4 ttl for packets sent via this context. */ union { uint8_t ipv6_hop_limit; - uint8_t ipv4_ttl; + struct { + uint8_t ipv4_ttl; + uint8_t ipv4_mcast_ttl; + }; }; #if defined(CONFIG_SOCKS) @@ -703,6 +706,17 @@ static inline void net_context_set_ipv4_ttl(struct net_context *context, context->ipv4_ttl = ttl; } +static inline uint8_t net_context_get_ipv4_mcast_ttl(struct net_context *context) +{ + return context->ipv4_mcast_ttl; +} + +static inline void net_context_set_ipv4_mcast_ttl(struct net_context *context, + uint8_t ttl) +{ + context->ipv4_mcast_ttl = ttl; +} + static inline uint8_t net_context_get_ipv6_hop_limit(struct net_context *context) { return context->ipv6_hop_limit; @@ -1106,6 +1120,7 @@ enum net_context_option { NET_OPT_REUSEPORT = 10, NET_OPT_IPV6_V6ONLY = 11, NET_OPT_RECV_PKTINFO = 12, + NET_OPT_MCAST_TTL = 13, }; /** diff --git a/include/zephyr/net/net_if.h b/include/zephyr/net/net_if.h index 1780adeb5ca..e5557b97fbb 100644 --- a/include/zephyr/net/net_if.h +++ b/include/zephyr/net/net_if.h @@ -380,6 +380,9 @@ struct net_if_ipv4 { /** IPv4 time-to-live */ uint8_t ttl; + + /** IPv4 time-to-live for multicast packets */ + uint8_t mcast_ttl; }; #if defined(CONFIG_NET_DHCPV4) && defined(CONFIG_NET_NATIVE_IPV4) @@ -1916,6 +1919,23 @@ uint8_t net_if_ipv4_get_ttl(struct net_if *iface); */ void net_if_ipv4_set_ttl(struct net_if *iface, uint8_t ttl); +/** + * @brief Get IPv4 multicast time-to-live value specified for a given interface + * + * @param iface Network interface + * + * @return Time-to-live + */ +uint8_t net_if_ipv4_get_mcast_ttl(struct net_if *iface); + +/** + * @brief Set IPv4 multicast time-to-live value specified to a given interface + * + * @param iface Network interface + * @param ttl Time-to-live value + */ +void net_if_ipv4_set_mcast_ttl(struct net_if *iface, uint8_t ttl); + /** * @brief Check if this IPv4 address belongs to one of the interfaces. * diff --git a/include/zephyr/net/socket.h b/include/zephyr/net/socket.h index 40458986be8..70d7eb9a1e2 100644 --- a/include/zephyr/net/socket.h +++ b/include/zephyr/net/socket.h @@ -1112,6 +1112,9 @@ struct in_pktinfo { struct in_addr ipi_addr; /* Header Destination address */ }; +/** sockopt: Set IPv4 multicast TTL value. */ +#define IP_MULTICAST_TTL 33 + /* Socket options for IPPROTO_IPV6 level */ /** sockopt: Don't support IPv4 access */ #define IPV6_V6ONLY 26 diff --git a/subsys/net/ip/Kconfig.ipv4 b/subsys/net/ip/Kconfig.ipv4 index e5d30cfc27c..69b0c260cae 100644 --- a/subsys/net/ip/Kconfig.ipv4 +++ b/subsys/net/ip/Kconfig.ipv4 @@ -12,10 +12,27 @@ menuconfig NET_IPV4 if NET_IPV4 config NET_INITIAL_TTL - int "Initial time to live for a connection" + int "Initial IPv4 time to live value for unicast packets" default 64 + range 0 255 help - The value should be > 0 + The value should normally be > 0. The device receiving the IPv4 + packet will decrement the value and will drop the packet if the TTL + value is 0. When sending, the packet is dropped before transmitting + to network if TTL is 0. + +config NET_INITIAL_MCAST_TTL + int "Initial IPv4 time to live value for multicast packets" + default 1 + range 0 255 + help + The value should normally be > 0. The device receiving the IPv4 + packet will decrement the value and will drop the packet if the TTL + value is 0. When sending, the packet is dropped before transmitting + to network if TTL is 0. + The default is 1 (same as in Linux) which means that multicast packets + don't leave the local network unless the application explicitly + requests it. config NET_IF_MAX_IPV4_COUNT int "Max number of IPv4 network interfaces in the system" diff --git a/subsys/net/ip/igmp.c b/subsys/net/ip/igmp.c index 3cd7be7de49..91a7a4cad5c 100644 --- a/subsys/net/ip/igmp.c +++ b/subsys/net/ip/igmp.c @@ -191,6 +191,9 @@ static int igmp_v2_create_packet(struct net_pkt *pkt, const struct in_addr *dst, const uint32_t router_alert = 0x94040000; /* RFC 2213 ch 2.1 */ int ret; + /* TTL set to 1, RFC 3376 ch 2 */ + net_pkt_set_ipv4_ttl(pkt, 1U); + ret = net_ipv4_create_full(pkt, net_if_ipv4_select_src_addr( net_pkt_iface(pkt), @@ -199,8 +202,7 @@ static int igmp_v2_create_packet(struct net_pkt *pkt, const struct in_addr *dst, 0U, 0U, 0U, - 0U, - 1U); /* TTL set to 1, RFC 3376 ch 2 */ + 0U); if (ret) { return -ENOBUFS; } @@ -222,8 +224,11 @@ static int igmp_v3_create_packet(struct net_pkt *pkt, const struct in_addr *dst, const uint32_t router_alert = 0x94040000; /* RFC 2213 ch 2.1 */ int ret; + /* TTL set to 1, RFC 3376 ch 2 */ + net_pkt_set_ipv4_ttl(pkt, 1U); + ret = net_ipv4_create_full(pkt, net_if_ipv4_select_src_addr(net_pkt_iface(pkt), dst), dst, - 0U, 0U, 0U, 0U, 1U); /* TTL set to 1, RFC 3376 ch 2 */ + 0U, 0U, 0U, 0U); if (ret) { return -ENOBUFS; } diff --git a/subsys/net/ip/ipv4.c b/subsys/net/ip/ipv4.c index ce5c1e9986c..fad04229c97 100644 --- a/subsys/net/ip/ipv4.c +++ b/subsys/net/ip/ipv4.c @@ -37,8 +37,7 @@ int net_ipv4_create_full(struct net_pkt *pkt, uint8_t tos, uint16_t id, uint8_t flags, - uint16_t offset, - uint8_t ttl) + uint16_t offset) { NET_PKT_DATA_ACCESS_CONTIGUOUS_DEFINE(ipv4_access, struct net_ipv4_hdr); struct net_ipv4_hdr *ipv4_hdr; @@ -55,10 +54,24 @@ int net_ipv4_create_full(struct net_pkt *pkt, ipv4_hdr->id[1] = id; ipv4_hdr->offset[0] = (offset >> 8) | (flags << 5); ipv4_hdr->offset[1] = offset; - ipv4_hdr->ttl = ttl; - if (ttl == 0U) { - ipv4_hdr->ttl = net_if_ipv4_get_ttl(net_pkt_iface(pkt)); + ipv4_hdr->ttl = net_pkt_ipv4_ttl(pkt); + if (ipv4_hdr->ttl == 0U) { + if (net_ipv4_is_addr_mcast(dst)) { + if (net_pkt_context(pkt) != NULL) { + ipv4_hdr->ttl = + net_context_get_ipv4_mcast_ttl(net_pkt_context(pkt)); + } else { + ipv4_hdr->ttl = net_if_ipv4_get_mcast_ttl(net_pkt_iface(pkt)); + } + } else { + if (net_pkt_context(pkt) != NULL) { + ipv4_hdr->ttl = + net_context_get_ipv4_ttl(net_pkt_context(pkt)); + } else { + ipv4_hdr->ttl = net_if_ipv4_get_ttl(net_pkt_iface(pkt)); + } + } } ipv4_hdr->proto = 0U; @@ -83,8 +96,7 @@ int net_ipv4_create(struct net_pkt *pkt, net_ipv4_set_ecn(&tos, net_pkt_ip_ecn(pkt)); } - return net_ipv4_create_full(pkt, src, dst, tos, 0U, 0U, 0U, - net_pkt_ipv4_ttl(pkt)); + return net_ipv4_create_full(pkt, src, dst, tos, 0U, 0U, 0U); } int net_ipv4_finalize(struct net_pkt *pkt, uint8_t next_header_proto) diff --git a/subsys/net/ip/ipv4.h b/subsys/net/ip/ipv4.h index 1d7d64fd0b5..162faca24b5 100644 --- a/subsys/net/ip/ipv4.h +++ b/subsys/net/ip/ipv4.h @@ -127,7 +127,6 @@ struct net_ipv4_igmp_v3_report { * @param id Fragment id * @param flags Fragmentation flags * @param offset Fragment offset - * @param ttl Time-to-live value * * @return 0 on success, negative errno otherwise. */ @@ -138,8 +137,7 @@ int net_ipv4_create_full(struct net_pkt *pkt, uint8_t tos, uint16_t id, uint8_t flags, - uint16_t offset, - uint8_t ttl); + uint16_t offset); #else static inline int net_ipv4_create_full(struct net_pkt *pkt, const struct in_addr *src, @@ -147,8 +145,7 @@ static inline int net_ipv4_create_full(struct net_pkt *pkt, uint8_t tos, uint16_t id, uint8_t flags, - uint16_t offset, - uint8_t ttl) + uint16_t offset) { ARG_UNUSED(pkt); ARG_UNUSED(src); @@ -157,7 +154,6 @@ static inline int net_ipv4_create_full(struct net_pkt *pkt, ARG_UNUSED(id); ARG_UNUSED(flags); ARG_UNUSED(offset); - ARG_UNUSED(ttl); return -ENOTSUP; } diff --git a/subsys/net/ip/net_context.c b/subsys/net/ip/net_context.c index 6c2258fcd90..b62035496af 100644 --- a/subsys/net/ip/net_context.c +++ b/subsys/net/ip/net_context.c @@ -42,6 +42,12 @@ LOG_MODULE_REGISTER(net_ctx, CONFIG_NET_CONTEXT_LOG_LEVEL); #include "tcp.h" #endif +#ifdef CONFIG_NET_INITIAL_MCAST_TTL +#define INITIAL_MCAST_TTL CONFIG_NET_INITIAL_MCAST_TTL +#else +#define INITIAL_MCAST_TTL 1 +#endif + #ifndef EPFNOSUPPORT /* Some old versions of newlib haven't got this defined in errno.h, * Just use EPROTONOSUPPORT in this case @@ -479,6 +485,8 @@ int net_context_get(sa_family_t family, enum net_sock_type type, uint16_t proto, ret = -EADDRINUSE; break; } + + contexts[i].ipv4_mcast_ttl = INITIAL_MCAST_TTL; } } @@ -1544,6 +1552,26 @@ static int get_context_dscp_ecn(struct net_context *context, #endif } +static int get_context_mcast_ttl(struct net_context *context, + void *value, size_t *len) +{ +#if defined(CONFIG_NET_IPV4) + *((int *)value) = context->ipv4_mcast_ttl; + + if (len) { + *len = sizeof(int); + } + + return 0; +#else + ARG_UNUSED(context); + ARG_UNUSED(value); + ARG_UNUSED(len); + + return -ENOTSUP; +#endif +} + static int get_context_reuseaddr(struct net_context *context, void *value, size_t *len) { @@ -2712,6 +2740,24 @@ static int set_context_dscp_ecn(struct net_context *context, #endif } +static int set_context_mcast_ttl(struct net_context *context, + const void *value, size_t len) +{ +#if defined(CONFIG_NET_IPV4) + uint8_t mcast_ttl = *((int *)value); + + len = sizeof(context->ipv4_mcast_ttl); + + return set_uint8_option(&context->ipv4_mcast_ttl, &mcast_ttl, len); +#else + ARG_UNUSED(context); + ARG_UNUSED(value); + ARG_UNUSED(len); + + return -ENOTSUP; +#endif +} + static int set_context_reuseaddr(struct net_context *context, const void *value, size_t len) { @@ -2807,6 +2853,9 @@ int net_context_set_option(struct net_context *context, case NET_OPT_DSCP_ECN: ret = set_context_dscp_ecn(context, value, len); break; + case NET_OPT_MCAST_TTL: + ret = set_context_mcast_ttl(context, value, len); + break; case NET_OPT_REUSEADDR: ret = set_context_reuseaddr(context, value, len); break; @@ -2865,6 +2914,9 @@ int net_context_get_option(struct net_context *context, case NET_OPT_DSCP_ECN: ret = get_context_dscp_ecn(context, value, len); break; + case NET_OPT_MCAST_TTL: + ret = get_context_mcast_ttl(context, value, len); + break; case NET_OPT_REUSEADDR: ret = get_context_reuseaddr(context, value, len); break; diff --git a/subsys/net/ip/net_if.c b/subsys/net/ip/net_if.c index f69fc2b871b..1721ee0de55 100644 --- a/subsys/net/ip/net_if.c +++ b/subsys/net/ip/net_if.c @@ -3151,6 +3151,47 @@ void net_if_ipv4_set_ttl(struct net_if *iface, uint8_t ttl) #endif } +uint8_t net_if_ipv4_get_mcast_ttl(struct net_if *iface) +{ +#if defined(CONFIG_NET_NATIVE_IPV4) + int ret = 0; + + net_if_lock(iface); + + if (!iface->config.ip.ipv4) { + goto out; + } + + ret = iface->config.ip.ipv4->mcast_ttl; +out: + net_if_unlock(iface); + + return ret; +#else + ARG_UNUSED(iface); + + return 0; +#endif +} + +void net_if_ipv4_set_mcast_ttl(struct net_if *iface, uint8_t ttl) +{ +#if defined(CONFIG_NET_NATIVE_IPV4) + net_if_lock(iface); + + if (!iface->config.ip.ipv4) { + goto out; + } + + iface->config.ip.ipv4->mcast_ttl = ttl; +out: + net_if_unlock(iface); +#else + ARG_UNUSED(iface); + ARG_UNUSED(ttl); +#endif +} + struct net_if_router *net_if_ipv4_router_lookup(struct net_if *iface, struct in_addr *addr) { @@ -4035,6 +4076,7 @@ static void iface_ipv4_init(int if_count) for (i = 0; i < ARRAY_SIZE(ipv4_addresses); i++) { ipv4_addresses[i].ipv4.ttl = CONFIG_NET_INITIAL_TTL; + ipv4_addresses[i].ipv4.mcast_ttl = CONFIG_NET_INITIAL_MCAST_TTL; } } diff --git a/subsys/net/l2/virtual/ipip/ipip.c b/subsys/net/l2/virtual/ipip/ipip.c index 41c3b8f41f2..e3514ea82d2 100644 --- a/subsys/net/l2/virtual/ipip/ipip.c +++ b/subsys/net/l2/virtual/ipip/ipip.c @@ -207,7 +207,7 @@ static int interface_send(struct net_if *iface, struct net_pkt *pkt) ret = net_ipv4_create_full(tmp, ctx->my4addr, &ctx->peer.in_addr, tos, 0U, NET_IPV4_DF, - 0U, net_pkt_ipv4_ttl(tmp)); + 0U); if (ret < 0) { goto out; } diff --git a/subsys/net/lib/sockets/sockets.c b/subsys/net/lib/sockets/sockets.c index 02fa21675eb..ac2f26c16ac 100644 --- a/subsys/net/lib/sockets/sockets.c +++ b/subsys/net/lib/sockets/sockets.c @@ -2517,6 +2517,16 @@ int zsock_getsockopt_ctx(struct net_context *ctx, int level, int optname, } break; + + case IP_MULTICAST_TTL: + ret = net_context_get_option(ctx, NET_OPT_MCAST_TTL, + optval, optlen); + if (ret < 0) { + errno = -ret; + return -1; + } + + return 0; } break; @@ -2885,6 +2895,16 @@ int zsock_setsockopt_ctx(struct net_context *ctx, int level, int optname, } break; + + case IP_MULTICAST_TTL: + ret = net_context_set_option(ctx, NET_OPT_MCAST_TTL, + optval, optlen); + if (ret < 0) { + errno = -ret; + return -1; + } + + return 0; } break; diff --git a/tests/net/icmp/src/main.c b/tests/net/icmp/src/main.c index 61a749c27ef..1e1dd690a07 100644 --- a/tests/net/icmp/src/main.c +++ b/tests/net/icmp/src/main.c @@ -207,8 +207,10 @@ static int get_ipv4_reply(struct net_if *iface, ipv4_hdr = net_pkt_cursor_get_pos(reply); *hdr_ipv4 = ipv4_hdr; + net_pkt_set_ipv4_ttl(reply, 1U); + ret = net_ipv4_create_full(reply, src4, dest4, params->tc_tos, - params->identifier, 0, 0, 1); + params->identifier, 0, 0); if (ret < 0) { LOG_ERR("Cannot create IPv4 pkt (%d)", ret); return ret; From cee2b3ae26ba09adb0e3252954e23d9fc7101689 Mon Sep 17 00:00:00 2001 From: Jukka Rissanen Date: Tue, 28 Nov 2023 08:23:58 +0200 Subject: [PATCH 0680/3723] tests: net: udp: Add IPv4 time-to-live multicast tests Make sure that setting IPv4 multicast TTL works as expected. Signed-off-by: Jukka Rissanen --- tests/net/socket/udp/src/main.c | 193 ++++++++++++++++++++++++++++- tests/net/socket/udp/testcase.yaml | 3 + 2 files changed, 195 insertions(+), 1 deletion(-) diff --git a/tests/net/socket/udp/src/main.c b/tests/net/socket/udp/src/main.c index 418e82dd480..ee7889cbe20 100644 --- a/tests/net/socket/udp/src/main.c +++ b/tests/net/socket/udp/src/main.c @@ -44,6 +44,7 @@ static const char test_str_all_tx_bufs[] = #define MY_IPV4_ADDR "127.0.0.1" #define MY_IPV6_ADDR "::1" +#define MY_MCAST_IPV4_ADDR "224.0.0.1" #define ANY_PORT 0 #define SERVER_PORT 4242 @@ -935,10 +936,12 @@ static ZTEST_BMEM struct sockaddr_in6 udp_server_addr; static ZTEST_BMEM SYS_MUTEX_DEFINE(wait_data); static struct net_if *eth_iface; +static struct net_if *lo0; static ZTEST_BMEM bool test_started; static ZTEST_BMEM bool test_failed; static struct in6_addr my_addr1 = { { { 0x20, 0x01, 0x0d, 0xb8, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0x1 } } }; +static struct in_addr my_addr2 = { { { 192, 0, 2, 2 } } }; static uint8_t server_lladdr[] = { 0x01, 0x02, 0x03, 0xff, 0xfe, 0x04, 0x05, 0x06 }; static struct net_linkaddr server_link_addr = { @@ -1004,9 +1007,13 @@ static void iface_cb(struct net_if *iface, void *user_data) *my_iface = iface; } } + + if (net_if_l2(iface) == &NET_L2_GET_NAME(DUMMY)) { + lo0 = iface; + } } -ZTEST(net_socket_udp, test_17_setup_eth) +ZTEST(net_socket_udp, test_17_setup_eth_for_ipv6) { struct net_if_addr *ifaddr; int ret; @@ -1859,6 +1866,190 @@ ZTEST_USER(net_socket_udp, test_29_recvmsg_ancillary_ipv6_pktinfo_data_user) sizeof(server_addr)); } +ZTEST(net_socket_udp, test_30_setup_eth_for_ipv4) +{ + struct net_if_addr *ifaddr; + + net_if_foreach(iface_cb, ð_iface); + zassert_not_null(eth_iface, "No ethernet interface found"); + + net_if_down(eth_iface); + + ifaddr = net_if_ipv4_addr_add(eth_iface, &my_addr2, + NET_ADDR_MANUAL, 0); + if (!ifaddr) { + DBG("Cannot add IPv4 address %s\n", + net_sprint_ipv4_addr(&my_addr2)); + zassert_not_null(ifaddr, "addr2"); + } + + net_if_up(eth_iface); +} + +static int bind_socket(int sock, struct net_if *iface) +{ + struct sockaddr_ll addr; + + memset(&addr, 0, sizeof(addr)); + + addr.sll_ifindex = net_if_get_by_iface(iface); + addr.sll_family = AF_PACKET; + + return bind(sock, (struct sockaddr *)&addr, sizeof(addr)); +} + +static void test_check_ttl(int sock_c, int sock_s, int sock_p, + struct sockaddr *addr_c, socklen_t addrlen_c, + struct sockaddr *addr_s, socklen_t addrlen_s, + struct sockaddr *addr_sendto, socklen_t addrlen_sendto, + sa_family_t family, uint8_t expected_ttl, + uint8_t expected_mcast_ttl) +{ + uint8_t tx_buf = 0xab; + uint8_t rx_buf; + int ret, count = 10; +#define IPV4_HDR_SIZE sizeof(struct net_ipv4_hdr) +#define IPV6_HDR_SIZE sizeof(struct net_ipv6_hdr) +#define UDP_HDR_SIZE sizeof(struct net_udp_hdr) +#define V4_HDR_SIZE (IPV4_HDR_SIZE + UDP_HDR_SIZE) +#define V6_HDR_SIZE (IPV6_HDR_SIZE + UDP_HDR_SIZE) +#define MAX_HDR_SIZE (IPV6_HDR_SIZE + UDP_HDR_SIZE) + uint8_t data_to_receive[sizeof(tx_buf) + MAX_HDR_SIZE]; + struct sockaddr_ll src; + socklen_t addrlen; + char ifname[CONFIG_NET_INTERFACE_NAME_LEN]; + struct ifreq ifreq = { 0 }; + struct timeval timeo_optval = { + .tv_sec = 0, + .tv_usec = 100000, + }; + + Z_TEST_SKIP_IFNDEF(CONFIG_NET_INTERFACE_NAME); + + ret = bind(sock_c, addr_c, addrlen_c); + zassert_equal(ret, 0, "client bind failed"); + + ret = net_if_get_name(lo0, ifname, sizeof(ifname)); + zassert_true(ret > 0, "cannot get interface name (%d)", ret); + + strncpy(ifreq.ifr_name, ifname, sizeof(ifreq.ifr_name)); + ret = setsockopt(sock_c, SOL_SOCKET, SO_BINDTODEVICE, &ifreq, + sizeof(ifreq)); + zassert_equal(ret, 0, "SO_BINDTODEVICE failed, %d", -errno); + + ret = connect(sock_c, addr_s, addrlen_s); + zassert_equal(ret, 0, "connect failed"); + + ret = setsockopt(sock_s, SOL_SOCKET, SO_RCVTIMEO, + &timeo_optval, sizeof(timeo_optval)); + zassert_equal(ret, 0, "Cannot set receive timeout (%d)", -errno); + + while (count > 0) { + ret = sendto(sock_c, &tx_buf, sizeof(tx_buf), 0, + addr_sendto, addrlen_sendto); + zassert_equal(ret, sizeof(tx_buf), "send failed (%d)", -errno); + + ret = recv(sock_s, &rx_buf, sizeof(rx_buf), MSG_DONTWAIT); + if (ret > 0) { + zassert_equal(ret, sizeof(rx_buf), "recv failed (%d)", ret); + zassert_equal(rx_buf, tx_buf, "wrong data"); + } + + ret = recvfrom(sock_p, data_to_receive, sizeof(data_to_receive), 0, + (struct sockaddr *)&src, &addrlen); + if (ret > 0) { + int hdr_size = family == AF_INET ? + V4_HDR_SIZE : V6_HDR_SIZE; + zassert_equal(ret, sizeof(tx_buf) + hdr_size, + "Cannot receive all data (%d vs %zd) (%d)", + ret, sizeof(tx_buf), -errno); + zassert_mem_equal(&data_to_receive[hdr_size], &tx_buf, + sizeof(tx_buf), + "Sent and received buffers do not match"); + + if (family == AF_INET) { + struct net_ipv4_hdr *ipv4 = + (struct net_ipv4_hdr *)&data_to_receive[0]; + + if (expected_ttl > 0) { + zassert_equal(ipv4->ttl, expected_ttl, + "Invalid ttl (%d vs %d)", + ipv4->ttl, expected_ttl); + } else if (expected_mcast_ttl > 0) { + zassert_equal(ipv4->ttl, expected_mcast_ttl, + "Invalid mcast ttl (%d vs %d)", + ipv4->ttl, expected_mcast_ttl); + } + } else { + zassert_true(false, "Invalid address family (%d)", + family); + } + + break; + } + + count--; + } + + zassert_true(count > 0, "timeout while waiting data"); + + ret = close(sock_c); + zassert_equal(ret, 0, "close failed"); + ret = close(sock_s); + zassert_equal(ret, 0, "close failed"); + ret = close(sock_p); + zassert_equal(ret, 0, "close failed"); +} + +ZTEST(net_socket_udp, test_31_v4_mcast_ttl) +{ + int ret; + int client_sock; + int server_sock; + int packet_sock; + int mcast_ttl, verify; + socklen_t optlen; + struct sockaddr_in client_addr; + struct sockaddr_in server_addr; + struct sockaddr_in sendto_addr; + + Z_TEST_SKIP_IFNDEF(CONFIG_NET_SOCKETS_PACKET); + + prepare_sock_udp_v4(MY_IPV4_ADDR, CLIENT_PORT, &client_sock, &client_addr); + prepare_sock_udp_v4(MY_IPV4_ADDR, SERVER_PORT, &server_sock, &server_addr); + + packet_sock = socket(AF_PACKET, SOCK_RAW, ETH_P_ALL); + zassert_true(packet_sock >= 0, "Cannot create packet socket (%d)", -errno); + + ret = bind_socket(packet_sock, lo0); + zassert_equal(ret, 0, "packet socket bind failed"); + + zassert_not_null(lo0->config.ip.ipv4, + "Interface %d (%p) no IPv4 configured", + net_if_get_by_iface(lo0), lo0); + + mcast_ttl = 8; + ret = setsockopt(client_sock, IPPROTO_IP, IP_MULTICAST_TTL, &mcast_ttl, + sizeof(mcast_ttl)); + zassert_equal(ret, 0, "Cannot set multicast ttl (%d)", -errno); + + optlen = sizeof(verify); + ret = getsockopt(client_sock, IPPROTO_IP, IP_MULTICAST_TTL, &verify, + &optlen); + zassert_equal(ret, 0, "Cannot get multicast ttl (%d)", -errno); + zassert_equal(verify, mcast_ttl, "Different multicast TTLs (%d vs %d)", + mcast_ttl, verify); + + ret = net_addr_pton(AF_INET, MY_MCAST_IPV4_ADDR, &sendto_addr.sin_addr); + zassert_equal(ret, 0, "Cannot get IPv4 address (%d)", ret); + + test_check_ttl(client_sock, server_sock, packet_sock, + (struct sockaddr *)&client_addr, sizeof(client_addr), + (struct sockaddr *)&server_addr, sizeof(server_addr), + (struct sockaddr *)&sendto_addr, sizeof(sendto_addr), + AF_INET, 0, mcast_ttl); +} + static void after(void *arg) { ARG_UNUSED(arg); diff --git a/tests/net/socket/udp/testcase.yaml b/tests/net/socket/udp/testcase.yaml index aa541a84598..2b319cbb033 100644 --- a/tests/net/socket/udp/testcase.yaml +++ b/tests/net/socket/udp/testcase.yaml @@ -19,3 +19,6 @@ tests: net.socket.udp.pktinfo: extra_configs: - CONFIG_NET_CONTEXT_RECV_PKTINFO=y + net.socket.udp.ttl: + extra_configs: + - CONFIG_NET_SOCKETS_PACKET=y From 1c684bc360cef89ac581fba85c1c3fcdfafee991 Mon Sep 17 00:00:00 2001 From: Jukka Rissanen Date: Tue, 28 Nov 2023 16:41:44 +0200 Subject: [PATCH 0681/3723] net: Add support for adjusting IPv6 multicast hop limit Add option support for adjusting the IPv6 multicast multicast hop limit value. Signed-off-by: Jukka Rissanen --- include/zephyr/net/net_context.h | 17 +++++++- include/zephyr/net/net_if.h | 21 ++++++++++ include/zephyr/net/socket.h | 3 ++ subsys/net/ip/Kconfig.ipv6 | 21 +++++++++- subsys/net/ip/ipv6.c | 24 +++++++++-- subsys/net/ip/net_context.c | 70 ++++++++++++++++++++++++++++++++ subsys/net/ip/net_if.c | 42 +++++++++++++++++++ subsys/net/lib/sockets/sockets.c | 22 ++++++++++ 8 files changed, 214 insertions(+), 6 deletions(-) diff --git a/include/zephyr/net/net_context.h b/include/zephyr/net/net_context.h index f089658df31..ab609f41cf6 100644 --- a/include/zephyr/net/net_context.h +++ b/include/zephyr/net/net_context.h @@ -348,7 +348,10 @@ __net_socket struct net_context { /** IPv6 hop limit or IPv4 ttl for packets sent via this context. */ union { - uint8_t ipv6_hop_limit; + struct { + uint8_t ipv6_hop_limit; + uint8_t ipv6_mcast_hop_limit; + }; struct { uint8_t ipv4_ttl; uint8_t ipv4_mcast_ttl; @@ -728,6 +731,17 @@ static inline void net_context_set_ipv6_hop_limit(struct net_context *context, context->ipv6_hop_limit = hop_limit; } +static inline uint8_t net_context_get_ipv6_mcast_hop_limit(struct net_context *context) +{ + return context->ipv6_mcast_hop_limit; +} + +static inline void net_context_set_ipv6_mcast_hop_limit(struct net_context *context, + uint8_t hop_limit) +{ + context->ipv6_mcast_hop_limit = hop_limit; +} + #if defined(CONFIG_SOCKS) static inline void net_context_set_proxy_enabled(struct net_context *context, bool enable) @@ -1121,6 +1135,7 @@ enum net_context_option { NET_OPT_IPV6_V6ONLY = 11, NET_OPT_RECV_PKTINFO = 12, NET_OPT_MCAST_TTL = 13, + NET_OPT_MCAST_HOP_LIMIT = 14, }; /** diff --git a/include/zephyr/net/net_if.h b/include/zephyr/net/net_if.h index e5557b97fbb..8e674c98855 100644 --- a/include/zephyr/net/net_if.h +++ b/include/zephyr/net/net_if.h @@ -290,6 +290,9 @@ struct net_if_ipv6 { /** IPv6 hop limit */ uint8_t hop_limit; + + /** IPv6 multicast hop limit */ + uint8_t mcast_hop_limit; }; #if defined(CONFIG_NET_DHCPV6) && defined(CONFIG_NET_NATIVE_IPV6) @@ -1677,6 +1680,24 @@ uint8_t net_if_ipv6_get_hop_limit(struct net_if *iface); */ void net_ipv6_set_hop_limit(struct net_if *iface, uint8_t hop_limit); +/** + * @brief Get IPv6 multicast hop limit specified for a given interface. This is the + * default value but can be overridden by the user. + * + * @param iface Network interface + * + * @return Hop limit + */ +uint8_t net_if_ipv6_get_mcast_hop_limit(struct net_if *iface); + +/** + * @brief Set the default IPv6 multicast hop limit of a given interface. + * + * @param iface Network interface + * @param hop_limit New hop limit + */ +void net_if_ipv6_set_mcast_hop_limit(struct net_if *iface, uint8_t hop_limit); + /** * @brief Set IPv6 reachable time for a given interface * diff --git a/include/zephyr/net/socket.h b/include/zephyr/net/socket.h index 70d7eb9a1e2..684643b6dc0 100644 --- a/include/zephyr/net/socket.h +++ b/include/zephyr/net/socket.h @@ -1116,6 +1116,9 @@ struct in_pktinfo { #define IP_MULTICAST_TTL 33 /* Socket options for IPPROTO_IPV6 level */ +/** sockopt: Set the multicast hop limit for the socket. */ +#define IPV6_MULTICAST_HOPS 18 + /** sockopt: Don't support IPv4 access */ #define IPV6_V6ONLY 26 diff --git a/subsys/net/ip/Kconfig.ipv6 b/subsys/net/ip/Kconfig.ipv6 index 18fb4b0ccc4..38b954a319c 100644 --- a/subsys/net/ip/Kconfig.ipv6 +++ b/subsys/net/ip/Kconfig.ipv6 @@ -40,10 +40,27 @@ config NET_IF_IPV6_PREFIX_COUNT if NET_NATIVE_IPV6 config NET_INITIAL_HOP_LIMIT - int "Initial hop limit for a connection" + int "Initial IPv6 hop limit value for unicast packets" default 64 + range 0 255 help - The value should be > 0 + The value should normally be > 0. The device receiving the IPv6 + packet will decrement the value and will drop the packet if the hop + limit value is 0. When sending, the packet is dropped before + transmitting to network if hop limit is 0. + +config NET_INITIAL_MCAST_HOP_LIMIT + int "Initial IPv6 hop limit value for multicast packets" + default 1 + range 0 255 + help + The value should normally be > 0. The device receiving the IPv6 + packet will decrement the value and will drop the packet if the hop + limit value is 0. When sending, the packet is dropped before + transmitting to network if hop limit is 0. + The default is 1 (same as in IPv4) which means that multicast packets + don't leave the local network unless the application explicitly + requests it. config NET_IPV6_MAX_NEIGHBORS int "How many IPv6 neighbors are supported" diff --git a/subsys/net/ip/ipv6.c b/subsys/net/ip/ipv6.c index 4957f1cb557..1be86c4d157 100644 --- a/subsys/net/ip/ipv6.c +++ b/subsys/net/ip/ipv6.c @@ -74,11 +74,29 @@ int net_ipv6_create(struct net_pkt *pkt, ipv6_hdr->len = 0U; ipv6_hdr->nexthdr = 0U; - /* User can tweak the default hop limit if needed */ + /* Set the hop limit by default from net_pkt as that could + * be set for example when sending NS. If the limit is 0, + * then take the value from socket. + */ ipv6_hdr->hop_limit = net_pkt_ipv6_hop_limit(pkt); if (ipv6_hdr->hop_limit == 0U) { - ipv6_hdr->hop_limit = - net_if_ipv6_get_hop_limit(net_pkt_iface(pkt)); + if (net_ipv6_is_addr_mcast(dst)) { + if (net_pkt_context(pkt) != NULL) { + ipv6_hdr->hop_limit = + net_context_get_ipv6_mcast_hop_limit(net_pkt_context(pkt)); + } else { + ipv6_hdr->hop_limit = + net_if_ipv6_get_mcast_hop_limit(net_pkt_iface(pkt)); + } + } else { + if (net_pkt_context(pkt) != NULL) { + ipv6_hdr->hop_limit = + net_context_get_ipv6_hop_limit(net_pkt_context(pkt)); + } else { + ipv6_hdr->hop_limit = + net_if_ipv6_get_hop_limit(net_pkt_iface(pkt)); + } + } } net_ipv6_addr_copy_raw(ipv6_hdr->dst, (uint8_t *)dst); diff --git a/subsys/net/ip/net_context.c b/subsys/net/ip/net_context.c index b62035496af..bd344a07016 100644 --- a/subsys/net/ip/net_context.c +++ b/subsys/net/ip/net_context.c @@ -48,6 +48,12 @@ LOG_MODULE_REGISTER(net_ctx, CONFIG_NET_CONTEXT_LOG_LEVEL); #define INITIAL_MCAST_TTL 1 #endif +#ifdef CONFIG_NET_INITIAL_MCAST_HOP_LIMIT +#define INITIAL_MCAST_HOP_LIMIT CONFIG_NET_INITIAL_MCAST_HOP_LIMIT +#else +#define INITIAL_MCAST_HOP_LIMIT 1 +#endif + #ifndef EPFNOSUPPORT /* Some old versions of newlib haven't got this defined in errno.h, * Just use EPROTONOSUPPORT in this case @@ -474,6 +480,8 @@ int net_context_get(sa_family_t family, enum net_sock_type type, uint16_t proto, ret = -EADDRINUSE; break; } + + contexts[i].ipv6_mcast_hop_limit = INITIAL_MCAST_HOP_LIMIT; } if (IS_ENABLED(CONFIG_NET_IPV4) && family == AF_INET) { struct sockaddr_in *addr = (struct sockaddr_in *)&contexts[i].local; @@ -1572,6 +1580,26 @@ static int get_context_mcast_ttl(struct net_context *context, #endif } +static int get_context_mcast_hop_limit(struct net_context *context, + void *value, size_t *len) +{ +#if defined(CONFIG_NET_IPV6) + *((int *)value) = context->ipv6_mcast_hop_limit; + + if (len) { + *len = sizeof(int); + } + + return 0; +#else + ARG_UNUSED(context); + ARG_UNUSED(value); + ARG_UNUSED(len); + + return -ENOTSUP; +#endif +} + static int get_context_reuseaddr(struct net_context *context, void *value, size_t *len) { @@ -2758,6 +2786,42 @@ static int set_context_mcast_ttl(struct net_context *context, #endif } +static int set_context_mcast_hop_limit(struct net_context *context, + const void *value, size_t len) +{ +#if defined(CONFIG_NET_IPV6) + int mcast_hop_limit = *((int *)value); + + if (len != sizeof(int)) { + return -EINVAL; + } + + if (mcast_hop_limit == -1) { + /* If value is -1 then use the system default. + * This is done same way as in Linux. + */ + if (net_if_get_by_index(context->iface) == NULL) { + mcast_hop_limit = INITIAL_MCAST_HOP_LIMIT; + } else { + mcast_hop_limit = net_if_ipv6_get_mcast_hop_limit( + net_if_get_by_index(context->iface)); + } + } else if (mcast_hop_limit < 0 || mcast_hop_limit > 255) { + return -EINVAL; + } + + context->ipv6_mcast_hop_limit = mcast_hop_limit; + + return 0; +#else + ARG_UNUSED(context); + ARG_UNUSED(value); + ARG_UNUSED(len); + + return -ENOTSUP; +#endif +} + static int set_context_reuseaddr(struct net_context *context, const void *value, size_t len) { @@ -2856,6 +2920,9 @@ int net_context_set_option(struct net_context *context, case NET_OPT_MCAST_TTL: ret = set_context_mcast_ttl(context, value, len); break; + case NET_OPT_MCAST_HOP_LIMIT: + ret = set_context_mcast_hop_limit(context, value, len); + break; case NET_OPT_REUSEADDR: ret = set_context_reuseaddr(context, value, len); break; @@ -2917,6 +2984,9 @@ int net_context_get_option(struct net_context *context, case NET_OPT_MCAST_TTL: ret = get_context_mcast_ttl(context, value, len); break; + case NET_OPT_MCAST_HOP_LIMIT: + ret = get_context_mcast_hop_limit(context, value, len); + break; case NET_OPT_REUSEADDR: ret = get_context_reuseaddr(context, value, len); break; diff --git a/subsys/net/ip/net_if.c b/subsys/net/ip/net_if.c index 1721ee0de55..949db871504 100644 --- a/subsys/net/ip/net_if.c +++ b/subsys/net/ip/net_if.c @@ -2638,6 +2638,47 @@ bool net_if_ipv6_router_rm(struct net_if_router *router) return iface_router_rm(router); } +uint8_t net_if_ipv6_get_mcast_hop_limit(struct net_if *iface) +{ +#if defined(CONFIG_NET_NATIVE_IPV6) + int ret = 0; + + net_if_lock(iface); + + if (!iface->config.ip.ipv6) { + goto out; + } + + ret = iface->config.ip.ipv6->mcast_hop_limit; +out: + net_if_unlock(iface); + + return ret; +#else + ARG_UNUSED(iface); + + return 0; +#endif +} + +void net_if_ipv6_set_mcast_hop_limit(struct net_if *iface, uint8_t hop_limit) +{ +#if defined(CONFIG_NET_NATIVE_IPV6) + net_if_lock(iface); + + if (!iface->config.ip.ipv6) { + goto out; + } + + iface->config.ip.ipv6->mcast_hop_limit = hop_limit; +out: + net_if_unlock(iface); +#else + ARG_UNUSED(iface); + ARG_UNUSED(hop_limit); +#endif +} + uint8_t net_if_ipv6_get_hop_limit(struct net_if *iface) { #if defined(CONFIG_NET_NATIVE_IPV6) @@ -2980,6 +3021,7 @@ static void iface_ipv6_init(int if_count) for (i = 0; i < ARRAY_SIZE(ipv6_addresses); i++) { ipv6_addresses[i].ipv6.hop_limit = CONFIG_NET_INITIAL_HOP_LIMIT; + ipv6_addresses[i].ipv6.mcast_hop_limit = CONFIG_NET_INITIAL_MCAST_HOP_LIMIT; ipv6_addresses[i].ipv6.base_reachable_time = REACHABLE_TIME; net_if_ipv6_set_reachable_time(&ipv6_addresses[i].ipv6); diff --git a/subsys/net/lib/sockets/sockets.c b/subsys/net/lib/sockets/sockets.c index ac2f26c16ac..092ce309e0c 100644 --- a/subsys/net/lib/sockets/sockets.c +++ b/subsys/net/lib/sockets/sockets.c @@ -2564,6 +2564,17 @@ int zsock_getsockopt_ctx(struct net_context *ctx, int level, int optname, } break; + + case IPV6_MULTICAST_HOPS: + ret = net_context_get_option(ctx, + NET_OPT_MCAST_HOP_LIMIT, + optval, optlen); + if (ret < 0) { + errno = -ret; + return -1; + } + + return 0; } break; @@ -2957,6 +2968,17 @@ int zsock_setsockopt_ctx(struct net_context *ctx, int level, int optname, } break; + + case IPV6_MULTICAST_HOPS: + ret = net_context_set_option(ctx, + NET_OPT_MCAST_HOP_LIMIT, + optval, optlen); + if (ret < 0) { + errno = -ret; + return -1; + } + + return 0; } break; From 8bd612c5223b1dfe879a759602fca5fd6d353617 Mon Sep 17 00:00:00 2001 From: Jukka Rissanen Date: Tue, 28 Nov 2023 16:43:26 +0200 Subject: [PATCH 0682/3723] tests: net: udp: Add IPv6 multicast hop limit tests Make sure that setting IPv6 multicast hop limit works as expected. Signed-off-by: Jukka Rissanen --- tests/net/socket/udp/src/main.c | 82 +++++++++++++++++++++++++++++++++ 1 file changed, 82 insertions(+) diff --git a/tests/net/socket/udp/src/main.c b/tests/net/socket/udp/src/main.c index ee7889cbe20..b2974d2dfd4 100644 --- a/tests/net/socket/udp/src/main.c +++ b/tests/net/socket/udp/src/main.c @@ -45,6 +45,7 @@ static const char test_str_all_tx_bufs[] = #define MY_IPV4_ADDR "127.0.0.1" #define MY_IPV6_ADDR "::1" #define MY_MCAST_IPV4_ADDR "224.0.0.1" +#define MY_MCAST_IPV6_ADDR "ff00::1" #define ANY_PORT 0 #define SERVER_PORT 4242 @@ -1980,6 +1981,19 @@ static void test_check_ttl(int sock_c, int sock_s, int sock_p, "Invalid mcast ttl (%d vs %d)", ipv4->ttl, expected_mcast_ttl); } + } else if (family == AF_INET6) { + struct net_ipv6_hdr *ipv6 = + (struct net_ipv6_hdr *)&data_to_receive[0]; + + if (expected_ttl > 0) { + zassert_equal(ipv6->hop_limit, expected_ttl, + "Invalid hop limit (%d vs %d)", + ipv6->hop_limit, expected_ttl); + } else if (expected_mcast_ttl > 0) { + zassert_equal(ipv6->hop_limit, expected_mcast_ttl, + "Invalid mcast hop limit (%d vs %d)", + ipv6->hop_limit, expected_mcast_ttl); + } } else { zassert_true(false, "Invalid address family (%d)", family); @@ -2050,6 +2064,74 @@ ZTEST(net_socket_udp, test_31_v4_mcast_ttl) AF_INET, 0, mcast_ttl); } +ZTEST(net_socket_udp, test_33_v6_mcast_hops) +{ + int ret; + int client_sock; + int server_sock; + int packet_sock; + int mcast_hops, if_mcast_hops; + int verify, opt; + socklen_t optlen; + struct sockaddr_in6 client_addr; + struct sockaddr_in6 server_addr; + struct sockaddr_in6 sendto_addr; + + Z_TEST_SKIP_IFNDEF(CONFIG_NET_SOCKETS_PACKET); + + prepare_sock_udp_v6(MY_IPV6_ADDR, CLIENT_PORT, &client_sock, &client_addr); + prepare_sock_udp_v6(MY_IPV6_ADDR, SERVER_PORT, &server_sock, &server_addr); + + packet_sock = socket(AF_PACKET, SOCK_RAW, ETH_P_ALL); + zassert_true(packet_sock >= 0, "Cannot create packet socket (%d)", -errno); + + ret = bind_socket(packet_sock, lo0); + zassert_equal(ret, 0, "packet socket bind failed"); + + zassert_not_null(lo0->config.ip.ipv6, + "Interface %d (%p) no IPv6 configured", + net_if_get_by_iface(lo0), lo0); + + /* First make sure setting hop limit to -1 works as expected (route default + * value should be used). + */ + if_mcast_hops = net_if_ipv6_get_mcast_hop_limit(lo0); + + opt = -1; + ret = setsockopt(client_sock, IPPROTO_IPV6, IPV6_MULTICAST_HOPS, &opt, + sizeof(opt)); + zassert_equal(ret, 0, "Cannot set multicast hop limit (%d)", -errno); + + optlen = sizeof(verify); + ret = getsockopt(client_sock, IPPROTO_IPV6, IPV6_MULTICAST_HOPS, &verify, + &optlen); + zassert_equal(ret, 0, "Cannot get multicast hop limit (%d)", -errno); + zassert_equal(verify, if_mcast_hops, "Different multicast hop limit (%d vs %d)", + if_mcast_hops, verify); + + /* Then test the normal case where we set the value */ + mcast_hops = 8; + ret = setsockopt(client_sock, IPPROTO_IPV6, IPV6_MULTICAST_HOPS, &mcast_hops, + sizeof(mcast_hops)); + zassert_equal(ret, 0, "Cannot set multicast hop limit (%d)", -errno); + + optlen = sizeof(verify); + ret = getsockopt(client_sock, IPPROTO_IPV6, IPV6_MULTICAST_HOPS, &verify, + &optlen); + zassert_equal(ret, 0, "Cannot get multicast hop limit (%d)", -errno); + zassert_equal(verify, mcast_hops, "Different multicast hop limit (%d vs %d)", + mcast_hops, verify); + + ret = net_addr_pton(AF_INET6, MY_MCAST_IPV6_ADDR, &sendto_addr.sin6_addr); + zassert_equal(ret, 0, "Cannot get IPv6 address (%d)", ret); + + test_check_ttl(client_sock, server_sock, packet_sock, + (struct sockaddr *)&client_addr, sizeof(client_addr), + (struct sockaddr *)&server_addr, sizeof(server_addr), + (struct sockaddr *)&sendto_addr, sizeof(sendto_addr), + AF_INET6, 0, mcast_hops); +} + static void after(void *arg) { ARG_UNUSED(arg); From e397d199b1ac2b401db3e7ddfff06eedac5399ef Mon Sep 17 00:00:00 2001 From: Jukka Rissanen Date: Tue, 28 Nov 2023 17:03:10 +0200 Subject: [PATCH 0683/3723] net: if: Fix typo in IPv6 hop limit API name The net_if_ipv6_set_hop_limit() API was missing the "_if_" part in it. Fix this so that the network interface API is consistent. The old function is deprecated and should not be used. The old function is left to the code and it calls the new properly named function. Signed-off-by: Jukka Rissanen --- include/zephyr/net/net_if.h | 13 ++++++++++++- subsys/net/ip/ipv6_nbr.c | 4 ++-- subsys/net/ip/net_if.c | 2 +- subsys/net/l2/virtual/ipip/ipip.c | 2 +- 4 files changed, 16 insertions(+), 5 deletions(-) diff --git a/include/zephyr/net/net_if.h b/include/zephyr/net/net_if.h index 8e674c98855..4f61a14a8c0 100644 --- a/include/zephyr/net/net_if.h +++ b/include/zephyr/net/net_if.h @@ -1678,7 +1678,18 @@ uint8_t net_if_ipv6_get_hop_limit(struct net_if *iface); * @param iface Network interface * @param hop_limit New hop limit */ -void net_ipv6_set_hop_limit(struct net_if *iface, uint8_t hop_limit); +void net_if_ipv6_set_hop_limit(struct net_if *iface, uint8_t hop_limit); + +/* The old hop limit setter function is deprecated because the naming + * of it was incorrect. The API name was missing "_if_" so this function + * should not be used. + */ +__deprecated +static inline void net_ipv6_set_hop_limit(struct net_if *iface, + uint8_t hop_limit) +{ + net_if_ipv6_set_hop_limit(iface, hop_limit); +} /** * @brief Get IPv6 multicast hop limit specified for a given interface. This is the diff --git a/subsys/net/ip/ipv6_nbr.c b/subsys/net/ip/ipv6_nbr.c index ebf8a6bc5b7..02c0932acf3 100644 --- a/subsys/net/ip/ipv6_nbr.c +++ b/subsys/net/ip/ipv6_nbr.c @@ -2438,8 +2438,8 @@ static int handle_ra_input(struct net_icmp_ctx *ctx, retrans_timer = ntohl(ra_hdr->retrans_timer); if (ra_hdr->cur_hop_limit) { - net_ipv6_set_hop_limit(net_pkt_iface(pkt), - ra_hdr->cur_hop_limit); + net_if_ipv6_set_hop_limit(net_pkt_iface(pkt), + ra_hdr->cur_hop_limit); NET_DBG("New hop limit %d", net_if_ipv6_get_hop_limit(net_pkt_iface(pkt))); } diff --git a/subsys/net/ip/net_if.c b/subsys/net/ip/net_if.c index 949db871504..69b2241d69d 100644 --- a/subsys/net/ip/net_if.c +++ b/subsys/net/ip/net_if.c @@ -2702,7 +2702,7 @@ uint8_t net_if_ipv6_get_hop_limit(struct net_if *iface) #endif } -void net_ipv6_set_hop_limit(struct net_if *iface, uint8_t hop_limit) +void net_if_ipv6_set_hop_limit(struct net_if *iface, uint8_t hop_limit) { #if defined(CONFIG_NET_NATIVE_IPV6) net_if_lock(iface); diff --git a/subsys/net/l2/virtual/ipip/ipip.c b/subsys/net/l2/virtual/ipip/ipip.c index e3514ea82d2..3fc64151b91 100644 --- a/subsys/net/l2/virtual/ipip/ipip.c +++ b/subsys/net/l2/virtual/ipip/ipip.c @@ -464,7 +464,7 @@ static int interface_set_config(struct net_if *iface, ctx->family = AF_INET6; net_virtual_set_name(iface, "IPv6 tunnel"); - net_ipv6_set_hop_limit(iface, 64); + net_if_ipv6_set_hop_limit(iface, 64); if (ctx->attached_to == NULL) { (void)net_virtual_interface_attach(iface, From 96ac91d1c90931ddd77184b38e0a9979fc2123d6 Mon Sep 17 00:00:00 2001 From: Jukka Rissanen Date: Tue, 28 Nov 2023 17:12:33 +0200 Subject: [PATCH 0684/3723] net: Add support for adjusting IPv6 unicast hop limit Add option support for adjusting the IPv6 unicast hop limit value. Signed-off-by: Jukka Rissanen --- include/zephyr/net/net_context.h | 29 ++++++++--------- include/zephyr/net/socket.h | 3 ++ subsys/net/ip/net_context.c | 54 ++++++++++++++++++++++++++++++-- subsys/net/lib/sockets/sockets.c | 22 +++++++++++++ 4 files changed, 92 insertions(+), 16 deletions(-) diff --git a/include/zephyr/net/net_context.h b/include/zephyr/net/net_context.h index ab609f41cf6..5db26b119b9 100644 --- a/include/zephyr/net/net_context.h +++ b/include/zephyr/net/net_context.h @@ -1122,20 +1122,21 @@ int net_context_update_recv_wnd(struct net_context *context, int32_t delta); enum net_context_option { - NET_OPT_PRIORITY = 1, - NET_OPT_TXTIME = 2, - NET_OPT_SOCKS5 = 3, - NET_OPT_RCVTIMEO = 4, - NET_OPT_SNDTIMEO = 5, - NET_OPT_RCVBUF = 6, - NET_OPT_SNDBUF = 7, - NET_OPT_DSCP_ECN = 8, - NET_OPT_REUSEADDR = 9, - NET_OPT_REUSEPORT = 10, - NET_OPT_IPV6_V6ONLY = 11, - NET_OPT_RECV_PKTINFO = 12, - NET_OPT_MCAST_TTL = 13, - NET_OPT_MCAST_HOP_LIMIT = 14, + NET_OPT_PRIORITY = 1, + NET_OPT_TXTIME = 2, + NET_OPT_SOCKS5 = 3, + NET_OPT_RCVTIMEO = 4, + NET_OPT_SNDTIMEO = 5, + NET_OPT_RCVBUF = 6, + NET_OPT_SNDBUF = 7, + NET_OPT_DSCP_ECN = 8, + NET_OPT_REUSEADDR = 9, + NET_OPT_REUSEPORT = 10, + NET_OPT_IPV6_V6ONLY = 11, + NET_OPT_RECV_PKTINFO = 12, + NET_OPT_MCAST_TTL = 13, + NET_OPT_MCAST_HOP_LIMIT = 14, + NET_OPT_UNICAST_HOP_LIMIT = 15, }; /** diff --git a/include/zephyr/net/socket.h b/include/zephyr/net/socket.h index 684643b6dc0..41b9c9ae857 100644 --- a/include/zephyr/net/socket.h +++ b/include/zephyr/net/socket.h @@ -1116,6 +1116,9 @@ struct in_pktinfo { #define IP_MULTICAST_TTL 33 /* Socket options for IPPROTO_IPV6 level */ +/** sockopt: Set the unicast hop limit for the socket. */ +#define IPV6_UNICAST_HOPS 16 + /** sockopt: Set the multicast hop limit for the socket. */ #define IPV6_MULTICAST_HOPS 18 diff --git a/subsys/net/ip/net_context.c b/subsys/net/ip/net_context.c index bd344a07016..a75d4d6fafb 100644 --- a/subsys/net/ip/net_context.c +++ b/subsys/net/ip/net_context.c @@ -54,6 +54,12 @@ LOG_MODULE_REGISTER(net_ctx, CONFIG_NET_CONTEXT_LOG_LEVEL); #define INITIAL_MCAST_HOP_LIMIT 1 #endif +#ifdef CONFIG_NET_INITIAL_HOP_LIMIT +#define INITIAL_HOP_LIMIT CONFIG_NET_INITIAL_HOP_LIMIT +#else +#define INITIAL_HOP_LIMIT 1 +#endif + #ifndef EPFNOSUPPORT /* Some old versions of newlib haven't got this defined in errno.h, * Just use EPROTONOSUPPORT in this case @@ -481,6 +487,7 @@ int net_context_get(sa_family_t family, enum net_sock_type type, uint16_t proto, break; } + contexts[i].ipv6_hop_limit = INITIAL_HOP_LIMIT; contexts[i].ipv6_mcast_hop_limit = INITIAL_MCAST_HOP_LIMIT; } if (IS_ENABLED(CONFIG_NET_IPV4) && family == AF_INET) { @@ -1124,8 +1131,6 @@ int net_context_create_ipv6_new(struct net_context *context, (struct in6_addr *)dst); } - net_pkt_set_ipv6_hop_limit(pkt, - net_context_get_ipv6_hop_limit(context)); #if defined(CONFIG_NET_CONTEXT_DSCP_ECN) net_pkt_set_ip_dscp(pkt, net_ipv6_get_dscp(context->options.dscp_ecn)); net_pkt_set_ip_ecn(pkt, net_ipv6_get_ecn(context->options.dscp_ecn)); @@ -1600,6 +1605,26 @@ static int get_context_mcast_hop_limit(struct net_context *context, #endif } +static int get_context_unicast_hop_limit(struct net_context *context, + void *value, size_t *len) +{ +#if defined(CONFIG_NET_IPV6) + *((int *)value) = context->ipv6_hop_limit; + + if (len) { + *len = sizeof(int); + } + + return 0; +#else + ARG_UNUSED(context); + ARG_UNUSED(value); + ARG_UNUSED(len); + + return -ENOTSUP; +#endif +} + static int get_context_reuseaddr(struct net_context *context, void *value, size_t *len) { @@ -2822,6 +2847,25 @@ static int set_context_mcast_hop_limit(struct net_context *context, #endif } +static int set_context_unicast_hop_limit(struct net_context *context, + const void *value, size_t len) +{ +#if defined(CONFIG_NET_IPV6) + uint8_t unicast_hop_limit = *((int *)value); + + len = sizeof(context->ipv6_hop_limit); + + return set_uint8_option(&context->ipv6_hop_limit, + &unicast_hop_limit, len); +#else + ARG_UNUSED(context); + ARG_UNUSED(value); + ARG_UNUSED(len); + + return -ENOTSUP; +#endif +} + static int set_context_reuseaddr(struct net_context *context, const void *value, size_t len) { @@ -2923,6 +2967,9 @@ int net_context_set_option(struct net_context *context, case NET_OPT_MCAST_HOP_LIMIT: ret = set_context_mcast_hop_limit(context, value, len); break; + case NET_OPT_UNICAST_HOP_LIMIT: + ret = set_context_unicast_hop_limit(context, value, len); + break; case NET_OPT_REUSEADDR: ret = set_context_reuseaddr(context, value, len); break; @@ -2987,6 +3034,9 @@ int net_context_get_option(struct net_context *context, case NET_OPT_MCAST_HOP_LIMIT: ret = get_context_mcast_hop_limit(context, value, len); break; + case NET_OPT_UNICAST_HOP_LIMIT: + ret = get_context_unicast_hop_limit(context, value, len); + break; case NET_OPT_REUSEADDR: ret = get_context_reuseaddr(context, value, len); break; diff --git a/subsys/net/lib/sockets/sockets.c b/subsys/net/lib/sockets/sockets.c index 092ce309e0c..792f72bab20 100644 --- a/subsys/net/lib/sockets/sockets.c +++ b/subsys/net/lib/sockets/sockets.c @@ -2565,6 +2565,17 @@ int zsock_getsockopt_ctx(struct net_context *ctx, int level, int optname, break; + case IPV6_UNICAST_HOPS: + ret = net_context_get_option(ctx, + NET_OPT_UNICAST_HOP_LIMIT, + optval, optlen); + if (ret < 0) { + errno = -ret; + return -1; + } + + return 0; + case IPV6_MULTICAST_HOPS: ret = net_context_get_option(ctx, NET_OPT_MCAST_HOP_LIMIT, @@ -2969,6 +2980,17 @@ int zsock_setsockopt_ctx(struct net_context *ctx, int level, int optname, break; + case IPV6_UNICAST_HOPS: + ret = net_context_set_option(ctx, + NET_OPT_UNICAST_HOP_LIMIT, + optval, optlen); + if (ret < 0) { + errno = -ret; + return -1; + } + + return 0; + case IPV6_MULTICAST_HOPS: ret = net_context_set_option(ctx, NET_OPT_MCAST_HOP_LIMIT, From 7474007e64e77c6b842ceb85d85fa5cb3d992e03 Mon Sep 17 00:00:00 2001 From: Jukka Rissanen Date: Tue, 28 Nov 2023 17:13:14 +0200 Subject: [PATCH 0685/3723] tests: net: udp: Add IPv6 unicast hop limit tests Make sure that setting IPv6 unicast hop limit works as expected. Signed-off-by: Jukka Rissanen --- tests/net/socket/udp/src/main.c | 50 +++++++++++++++++++++++++++++++++ 1 file changed, 50 insertions(+) diff --git a/tests/net/socket/udp/src/main.c b/tests/net/socket/udp/src/main.c index b2974d2dfd4..1d9dd1a5b15 100644 --- a/tests/net/socket/udp/src/main.c +++ b/tests/net/socket/udp/src/main.c @@ -2132,6 +2132,56 @@ ZTEST(net_socket_udp, test_33_v6_mcast_hops) AF_INET6, 0, mcast_hops); } +ZTEST(net_socket_udp, test_34_v6_hops) +{ + int ret; + int client_sock; + int server_sock; + int packet_sock; + int hops, verify; + socklen_t optlen; + struct sockaddr_in6 client_addr; + struct sockaddr_in6 server_addr; + + Z_TEST_SKIP_IFNDEF(CONFIG_NET_SOCKETS_PACKET); + + prepare_sock_udp_v6(MY_IPV6_ADDR, CLIENT_PORT, &client_sock, &client_addr); + prepare_sock_udp_v6(MY_IPV6_ADDR, SERVER_PORT, &server_sock, &server_addr); + + packet_sock = socket(AF_PACKET, SOCK_RAW, ETH_P_ALL); + zassert_true(packet_sock >= 0, "Cannot create packet socket (%d)", -errno); + + ret = bind_socket(packet_sock, lo0); + zassert_equal(ret, 0, "packet socket bind failed"); + + zassert_not_null(lo0->config.ip.ipv6, + "Interface %d (%p) no IPv6 configured", + net_if_get_by_iface(lo0), lo0); + + hops = 16; + net_if_ipv6_set_hop_limit(lo0, hops); + verify = net_if_ipv6_get_hop_limit(lo0); + zassert_equal(verify, hops, "Different hop limit (%d vs %d)", hops, verify); + + hops = 8; + ret = setsockopt(client_sock, IPPROTO_IPV6, IPV6_UNICAST_HOPS, &hops, + sizeof(hops)); + zassert_equal(ret, 0, "Cannot set unicast hops (%d)", -errno); + + optlen = sizeof(verify); + ret = getsockopt(client_sock, IPPROTO_IPV6, IPV6_UNICAST_HOPS, &verify, + &optlen); + zassert_equal(ret, 0, "Cannot get unicast hops (%d)", -errno); + zassert_equal(verify, hops, "Different unicast hops (%d vs %d)", + hops, verify); + + test_check_ttl(client_sock, server_sock, packet_sock, + (struct sockaddr *)&client_addr, sizeof(client_addr), + (struct sockaddr *)&server_addr, sizeof(server_addr), + (struct sockaddr *)&server_addr, sizeof(server_addr), + AF_INET6, hops, 0); +} + static void after(void *arg) { ARG_UNUSED(arg); From b4a8e3ffffe5034640ff1940db900fedef7279b1 Mon Sep 17 00:00:00 2001 From: Jukka Rissanen Date: Wed, 29 Nov 2023 17:23:40 +0200 Subject: [PATCH 0686/3723] net: socket: Add support for adjusting IPv4 TTL The IPv4 TTL could only manipulated via net_context interface. It makes sense to allow the same from socket interface via the setsockopt/getsockopt calls. Signed-off-by: Jukka Rissanen --- include/zephyr/net/net_context.h | 1 + include/zephyr/net/socket.h | 3 ++ subsys/net/ip/net_context.c | 52 +++++++++++++++++++++++++++++++- subsys/net/lib/sockets/sockets.c | 20 ++++++++++++ 4 files changed, 75 insertions(+), 1 deletion(-) diff --git a/include/zephyr/net/net_context.h b/include/zephyr/net/net_context.h index 5db26b119b9..937cc9cf2a7 100644 --- a/include/zephyr/net/net_context.h +++ b/include/zephyr/net/net_context.h @@ -1137,6 +1137,7 @@ enum net_context_option { NET_OPT_MCAST_TTL = 13, NET_OPT_MCAST_HOP_LIMIT = 14, NET_OPT_UNICAST_HOP_LIMIT = 15, + NET_OPT_TTL = 16, }; /** diff --git a/include/zephyr/net/socket.h b/include/zephyr/net/socket.h index 41b9c9ae857..bdd0e0ad41e 100644 --- a/include/zephyr/net/socket.h +++ b/include/zephyr/net/socket.h @@ -1100,6 +1100,9 @@ struct ifreq { /** sockopt: Set or receive the Type-Of-Service value for an outgoing packet. */ #define IP_TOS 1 +/** sockopt: Set or receive the Time-To-Live value for an outgoing packet. */ +#define IP_TTL 2 + /** sockopt: Pass an IP_PKTINFO ancillary message that contains a * pktinfo structure that supplies some information about the * incoming packet. diff --git a/subsys/net/ip/net_context.c b/subsys/net/ip/net_context.c index a75d4d6fafb..0d4b8ea60c9 100644 --- a/subsys/net/ip/net_context.c +++ b/subsys/net/ip/net_context.c @@ -48,6 +48,12 @@ LOG_MODULE_REGISTER(net_ctx, CONFIG_NET_CONTEXT_LOG_LEVEL); #define INITIAL_MCAST_TTL 1 #endif +#ifdef CONFIG_NET_INITIAL_TTL +#define INITIAL_TTL CONFIG_NET_INITIAL_TTL +#else +#define INITIAL_TTL 1 +#endif + #ifdef CONFIG_NET_INITIAL_MCAST_HOP_LIMIT #define INITIAL_MCAST_HOP_LIMIT CONFIG_NET_INITIAL_MCAST_HOP_LIMIT #else @@ -501,6 +507,7 @@ int net_context_get(sa_family_t family, enum net_sock_type type, uint16_t proto, break; } + contexts[i].ipv4_ttl = INITIAL_TTL; contexts[i].ipv4_mcast_ttl = INITIAL_MCAST_TTL; } } @@ -1097,7 +1104,6 @@ int net_context_create_ipv4_new(struct net_context *context, } } - net_pkt_set_ipv4_ttl(pkt, net_context_get_ipv4_ttl(context)); #if defined(CONFIG_NET_CONTEXT_DSCP_ECN) net_pkt_set_ip_dscp(pkt, net_ipv4_get_dscp(context->options.dscp_ecn)); net_pkt_set_ip_ecn(pkt, net_ipv4_get_ecn(context->options.dscp_ecn)); @@ -1565,6 +1571,26 @@ static int get_context_dscp_ecn(struct net_context *context, #endif } +static int get_context_ttl(struct net_context *context, + void *value, size_t *len) +{ +#if defined(CONFIG_NET_IPV4) + *((int *)value) = context->ipv4_ttl; + + if (len) { + *len = sizeof(int); + } + + return 0; +#else + ARG_UNUSED(context); + ARG_UNUSED(value); + ARG_UNUSED(len); + + return -ENOTSUP; +#endif +} + static int get_context_mcast_ttl(struct net_context *context, void *value, size_t *len) { @@ -2793,6 +2819,24 @@ static int set_context_dscp_ecn(struct net_context *context, #endif } +static int set_context_ttl(struct net_context *context, + const void *value, size_t len) +{ +#if defined(CONFIG_NET_IPV4) + uint8_t ttl = *((int *)value); + + len = sizeof(context->ipv4_ttl); + + return set_uint8_option(&context->ipv4_ttl, &ttl, len); +#else + ARG_UNUSED(context); + ARG_UNUSED(value); + ARG_UNUSED(len); + + return -ENOTSUP; +#endif +} + static int set_context_mcast_ttl(struct net_context *context, const void *value, size_t len) { @@ -2961,6 +3005,9 @@ int net_context_set_option(struct net_context *context, case NET_OPT_DSCP_ECN: ret = set_context_dscp_ecn(context, value, len); break; + case NET_OPT_TTL: + ret = set_context_ttl(context, value, len); + break; case NET_OPT_MCAST_TTL: ret = set_context_mcast_ttl(context, value, len); break; @@ -3028,6 +3075,9 @@ int net_context_get_option(struct net_context *context, case NET_OPT_DSCP_ECN: ret = get_context_dscp_ecn(context, value, len); break; + case NET_OPT_TTL: + ret = get_context_ttl(context, value, len); + break; case NET_OPT_MCAST_TTL: ret = get_context_mcast_ttl(context, value, len); break; diff --git a/subsys/net/lib/sockets/sockets.c b/subsys/net/lib/sockets/sockets.c index 792f72bab20..697c94e8808 100644 --- a/subsys/net/lib/sockets/sockets.c +++ b/subsys/net/lib/sockets/sockets.c @@ -2518,6 +2518,16 @@ int zsock_getsockopt_ctx(struct net_context *ctx, int level, int optname, break; + case IP_TTL: + ret = net_context_get_option(ctx, NET_OPT_TTL, + optval, optlen); + if (ret < 0) { + errno = -ret; + return -1; + } + + return 0; + case IP_MULTICAST_TTL: ret = net_context_get_option(ctx, NET_OPT_MCAST_TTL, optval, optlen); @@ -2926,6 +2936,16 @@ int zsock_setsockopt_ctx(struct net_context *ctx, int level, int optname, return -1; } + return 0; + + case IP_TTL: + ret = net_context_set_option(ctx, NET_OPT_TTL, + optval, optlen); + if (ret < 0) { + errno = -ret; + return -1; + } + return 0; } From 27d4c5d49199d46eb944b2cfb6af6ded1661ba9e Mon Sep 17 00:00:00 2001 From: Jukka Rissanen Date: Wed, 29 Nov 2023 17:33:24 +0200 Subject: [PATCH 0687/3723] tests: net: udp: Add IPv4 unicast TTL tests Make sure that setting IPv4 unicast TTL works as expected. Signed-off-by: Jukka Rissanen --- tests/net/socket/udp/src/main.c | 50 ++++++++++++++++++++++++++++++++- 1 file changed, 49 insertions(+), 1 deletion(-) diff --git a/tests/net/socket/udp/src/main.c b/tests/net/socket/udp/src/main.c index 1d9dd1a5b15..044650e6d98 100644 --- a/tests/net/socket/udp/src/main.c +++ b/tests/net/socket/udp/src/main.c @@ -2015,7 +2015,55 @@ static void test_check_ttl(int sock_c, int sock_s, int sock_p, zassert_equal(ret, 0, "close failed"); } -ZTEST(net_socket_udp, test_31_v4_mcast_ttl) +ZTEST(net_socket_udp, test_31_v4_ttl) +{ + int ret; + int client_sock; + int server_sock; + int packet_sock; + int ttl, verify; + socklen_t optlen; + struct sockaddr_in client_addr; + struct sockaddr_in server_addr; + + Z_TEST_SKIP_IFNDEF(CONFIG_NET_SOCKETS_PACKET); + + prepare_sock_udp_v4(MY_IPV4_ADDR, CLIENT_PORT, &client_sock, &client_addr); + prepare_sock_udp_v4(MY_IPV4_ADDR, SERVER_PORT, &server_sock, &server_addr); + + packet_sock = socket(AF_PACKET, SOCK_RAW, ETH_P_ALL); + zassert_true(packet_sock >= 0, "Cannot create packet socket (%d)", -errno); + + ret = bind_socket(packet_sock, lo0); + zassert_equal(ret, 0, "packet socket bind failed"); + + zassert_not_null(lo0->config.ip.ipv4, + "Interface %d (%p) no IPv4 configured", + net_if_get_by_iface(lo0), lo0); + + ttl = 16; + net_if_ipv4_set_ttl(lo0, ttl); + verify = net_if_ipv4_get_ttl(lo0); + zassert_equal(verify, ttl, "Different TTLs (%d vs %d)", ttl, verify); + + ttl = 128; + ret = setsockopt(client_sock, IPPROTO_IP, IP_TTL, &ttl, sizeof(ttl)); + zassert_equal(ret, 0, "Cannot set unicast TTL (%d)", -errno); + + optlen = sizeof(verify); + ret = getsockopt(client_sock, IPPROTO_IP, IP_TTL, &verify, &optlen); + zassert_equal(ret, 0, "Cannot get unicast TTL (%d)", -errno); + zassert_equal(verify, ttl, "Different unicast TTL (%d vs %d)", + ttl, verify); + + test_check_ttl(client_sock, server_sock, packet_sock, + (struct sockaddr *)&client_addr, sizeof(client_addr), + (struct sockaddr *)&server_addr, sizeof(server_addr), + (struct sockaddr *)&server_addr, sizeof(server_addr), + AF_INET, ttl, 0); +} + +ZTEST(net_socket_udp, test_32_v4_mcast_ttl) { int ret; int client_sock; From d44b72355b05d9ab1883a19da7737c4476ad8082 Mon Sep 17 00:00:00 2001 From: Jukka Rissanen Date: Tue, 28 Nov 2023 23:31:01 +0200 Subject: [PATCH 0688/3723] net: Refactor IP checks just before sending packets * Check IPv4 TTL or IPv6 hop limit and drop the packet if the value is 0 * Check the IP addresses so that we do the loopback check at runtime if the packet is destined to loopback interface. * Update the statistics properly for dropped packets. * Do not update sent packets if we drop packets. Signed-off-by: Jukka Rissanen --- subsys/net/ip/net_core.c | 132 +++++++++++++++++++++++++++++---------- 1 file changed, 98 insertions(+), 34 deletions(-) diff --git a/subsys/net/ip/net_core.c b/subsys/net/ip/net_core.c index baa8cd695c5..92e35013efc 100644 --- a/subsys/net/ip/net_core.c +++ b/subsys/net/ip/net_core.c @@ -203,14 +203,6 @@ static void init_rx_queues(void) net_post_init(); } -/* If loopback driver is enabled, then direct packets to it so the address - * check is not needed. - */ -#if defined(CONFIG_NET_IP) && defined(CONFIG_NET_IP_ADDR_CHECK) && !defined(CONFIG_NET_LOOPBACK) -/* Check if the IPv{4|6} addresses are proper. As this can be expensive, - * make this optional. - */ - static inline void copy_ll_addr(struct net_pkt *pkt) { memcpy(net_pkt_lladdr_src(pkt), net_pkt_lladdr_if(pkt), @@ -219,15 +211,47 @@ static inline void copy_ll_addr(struct net_pkt *pkt) sizeof(struct net_linkaddr)); } -static inline int check_ip_addr(struct net_pkt *pkt) +/* Check if the IPv{4|6} addresses are proper. As this can be expensive, + * make this optional. We still check the IPv4 TTL and IPv6 hop limit + * if the corresponding protocol family is enabled. + */ +static inline int check_ip(struct net_pkt *pkt) { - uint8_t family = net_pkt_family(pkt); + uint8_t family; + int ret; + + if (!IS_ENABLED(CONFIG_NET_IP)) { + return 0; + } + + family = net_pkt_family(pkt); + ret = 0; if (IS_ENABLED(CONFIG_NET_IPV6) && family == AF_INET6) { + /* Drop IPv6 packet if hop limit is 0 */ + if (NET_IPV6_HDR(pkt)->hop_limit == 0) { + NET_DBG("DROP: IPv6 hop limit"); + ret = -ENOMSG; /* silently drop the pkt, not an error */ + goto drop; + } + + if (!IS_ENABLED(CONFIG_NET_IP_ADDR_CHECK)) { + return 0; + } + +#if defined(CONFIG_NET_LOOPBACK) + /* If loopback driver is enabled, then send packets to it + * as the address check is not needed. + */ + if (net_if_l2(net_pkt_iface(pkt)) == &NET_L2_GET_NAME(DUMMY)) { + return 0; + } +#endif if (net_ipv6_addr_cmp((struct in6_addr *)NET_IPV6_HDR(pkt)->dst, net_ipv6_unspecified_address())) { - NET_DBG("IPv6 dst address missing"); - return -EADDRNOTAVAIL; + NET_DBG("DROP: IPv6 dst address missing"); + ret = -EADDRNOTAVAIL; + goto drop; } /* If the destination address is our own, then route it @@ -270,14 +294,36 @@ static inline int check_ip_addr(struct net_pkt *pkt) */ if (net_ipv6_is_addr_loopback( (struct in6_addr *)NET_IPV6_HDR(pkt)->src)) { - NET_DBG("IPv6 loopback src address"); - return -EADDRNOTAVAIL; + NET_DBG("DROP: IPv6 loopback src address"); + ret = -EADDRNOTAVAIL; + goto drop; } + } else if (IS_ENABLED(CONFIG_NET_IPV4) && family == AF_INET) { + /* Drop IPv4 packet if ttl is 0 */ + if (NET_IPV4_HDR(pkt)->ttl == 0) { + NET_DBG("DROP: IPv4 ttl"); + ret = -ENOMSG; /* silently drop the pkt, not an error */ + goto drop; + } + + if (!IS_ENABLED(CONFIG_NET_IP_ADDR_CHECK)) { + return 0; + } + +#if defined(CONFIG_NET_LOOPBACK) + /* If loopback driver is enabled, then send packets to it + * as the address check is not needed. + */ + if (net_if_l2(net_pkt_iface(pkt)) == &NET_L2_GET_NAME(DUMMY)) { + return 0; + } +#endif if (net_ipv4_addr_cmp((struct in_addr *)NET_IPV4_HDR(pkt)->dst, net_ipv4_unspecified_address())) { - NET_DBG("IPv4 dst address missing"); - return -EADDRNOTAVAIL; + NET_DBG("DROP: IPv4 dst address missing"); + ret = -EADDRNOTAVAIL; + goto drop; } /* If the destination address is our own, then route it @@ -308,16 +354,25 @@ static inline int check_ip_addr(struct net_pkt *pkt) * localhost subnet too. */ if (net_ipv4_is_addr_loopback((struct in_addr *)NET_IPV4_HDR(pkt)->src)) { - NET_DBG("IPv4 loopback src address"); - return -EADDRNOTAVAIL; + NET_DBG("DROP: IPv4 loopback src address"); + ret = -EADDRNOTAVAIL; + goto drop; } } - return 0; + return ret; + +drop: + if (IS_ENABLED(CONFIG_NET_STATISTICS)) { + if (family == AF_INET6) { + net_stats_update_ipv6_drop(net_pkt_iface(pkt)); + } else { + net_stats_update_ipv4_drop(net_pkt_iface(pkt)); + } + } + + return ret; } -#else -#define check_ip_addr(pkt) 0 -#endif /* Called when data needs to be sent to network */ int net_send_data(struct net_pkt *pkt) @@ -332,22 +387,20 @@ int net_send_data(struct net_pkt *pkt) return -EINVAL; } -#if defined(CONFIG_NET_STATISTICS) - switch (net_pkt_family(pkt)) { - case AF_INET: - net_stats_update_ipv4_sent(net_pkt_iface(pkt)); - break; - case AF_INET6: - net_stats_update_ipv6_sent(net_pkt_iface(pkt)); - break; - } -#endif - net_pkt_trim_buffer(pkt); net_pkt_cursor_init(pkt); - status = check_ip_addr(pkt); + status = check_ip(pkt); if (status < 0) { + /* Special handling for ENOMSG which is returned if packet + * TTL is 0 or hop limit is 0. This is not an error as it is + * perfectly valid case to set the limit to 0. In this case + * we just silently drop the packet by returning 0. + */ + if (status == -ENOMSG) { + return 0; + } + return status; } else if (status > 0) { /* Packet is destined back to us so send it directly @@ -362,6 +415,17 @@ int net_send_data(struct net_pkt *pkt) return -EIO; } + if (IS_ENABLED(CONFIG_NET_STATISTICS)) { + switch (net_pkt_family(pkt)) { + case AF_INET: + net_stats_update_ipv4_sent(net_pkt_iface(pkt)); + break; + case AF_INET6: + net_stats_update_ipv6_sent(net_pkt_iface(pkt)); + break; + } + } + return 0; } From 28a8c6c00d7dbdd7d527231193ad516011af7da1 Mon Sep 17 00:00:00 2001 From: Jukka Rissanen Date: Wed, 29 Nov 2023 17:12:38 +0200 Subject: [PATCH 0689/3723] tests: net: udp: Add IPv4 TTL 0 test Make sure packet is dropped if TTL 0 packet is tried to send. Signed-off-by: Jukka Rissanen --- tests/net/socket/udp/src/main.c | 28 +++++++++++++++++++++++++++- 1 file changed, 27 insertions(+), 1 deletion(-) diff --git a/tests/net/socket/udp/src/main.c b/tests/net/socket/udp/src/main.c index 044650e6d98..e0a25841748 100644 --- a/tests/net/socket/udp/src/main.c +++ b/tests/net/socket/udp/src/main.c @@ -1908,7 +1908,7 @@ static void test_check_ttl(int sock_c, int sock_s, int sock_p, { uint8_t tx_buf = 0xab; uint8_t rx_buf; - int ret, count = 10; + int ret, count = 10, opt; #define IPV4_HDR_SIZE sizeof(struct net_ipv4_hdr) #define IPV6_HDR_SIZE sizeof(struct net_ipv6_hdr) #define UDP_HDR_SIZE sizeof(struct net_udp_hdr) @@ -2007,6 +2007,32 @@ static void test_check_ttl(int sock_c, int sock_s, int sock_p, zassert_true(count > 0, "timeout while waiting data"); + if (family == AF_INET) { + /* Set TTL to 0 and make sure the packet is dropped and not + * received + */ + int option; + + if (expected_ttl > 0) { + option = IP_TTL; + } else { + option = IP_MULTICAST_TTL; + } + + opt = 0; + ret = setsockopt(sock_c, IPPROTO_IP, option, &opt, sizeof(opt)); + zassert_equal(ret, 0, "Cannot set %s TTL (%d)", + option == IP_TTL ? "unicast" : "multicast", + -errno); + + ret = sendto(sock_c, &tx_buf, sizeof(tx_buf), 0, + addr_sendto, addrlen_sendto); + zassert_equal(ret, sizeof(tx_buf), "send failed (%d)", -errno); + + ret = recv(sock_s, &rx_buf, sizeof(rx_buf), 0); + zassert_true(ret < 0 && errno == EAGAIN, "recv succeed (%d)", -errno); + } + ret = close(sock_c); zassert_equal(ret, 0, "close failed"); ret = close(sock_s); From c32e06fcb5eff9a8acc35bd133c14d566e858bba Mon Sep 17 00:00:00 2001 From: Jukka Rissanen Date: Wed, 29 Nov 2023 18:38:37 +0200 Subject: [PATCH 0690/3723] tests: net: udp: Add IPv6 hop limit 0 test Make sure packet is dropped if IPv6 hop limit 0 packet is tried to send. Signed-off-by: Jukka Rissanen --- tests/net/socket/udp/src/main.c | 27 +++++++++++++++++++++++++++ 1 file changed, 27 insertions(+) diff --git a/tests/net/socket/udp/src/main.c b/tests/net/socket/udp/src/main.c index e0a25841748..23335b7367c 100644 --- a/tests/net/socket/udp/src/main.c +++ b/tests/net/socket/udp/src/main.c @@ -2033,6 +2033,33 @@ static void test_check_ttl(int sock_c, int sock_s, int sock_p, zassert_true(ret < 0 && errno == EAGAIN, "recv succeed (%d)", -errno); } + if (family == AF_INET6) { + /* Set hoplimit to 0 and make sure the packet is dropped and not + * received. + */ + int option; + + if (expected_ttl > 0) { + option = IPV6_UNICAST_HOPS; + } else { + option = IPV6_MULTICAST_HOPS; + } + + opt = 0; + ret = setsockopt(sock_c, IPPROTO_IPV6, option, + &opt, sizeof(opt)); + zassert_equal(ret, 0, "Cannot set %s hops (%d)", + option == IPV6_UNICAST_HOPS ? "unicast" : "multicast", + -errno); + + ret = sendto(sock_c, &tx_buf, sizeof(tx_buf), 0, + addr_sendto, addrlen_sendto); + zassert_equal(ret, sizeof(tx_buf), "send failed (%d)", -errno); + + ret = recv(sock_s, &rx_buf, sizeof(rx_buf), 0); + zassert_true(ret < 0 && errno == EAGAIN, "recv succeed (%d)", -errno); + } + ret = close(sock_c); zassert_equal(ret, 0, "close failed"); ret = close(sock_s); From 921c945dab7e9474ff46fb6b3f088fd3a34245c0 Mon Sep 17 00:00:00 2001 From: Jukka Rissanen Date: Wed, 29 Nov 2023 18:17:21 +0200 Subject: [PATCH 0691/3723] tests: net: udp: Verify that packet is dropped from stats Make sure that statistics is properly update for dropped packets when IPv4 TTL is 0 or IPv6 hop limit is 0. Signed-off-by: Jukka Rissanen --- tests/net/socket/udp/src/main.c | 41 ++++++++++++++++++++++++++++++ tests/net/socket/udp/testcase.yaml | 6 +++++ 2 files changed, 47 insertions(+) diff --git a/tests/net/socket/udp/src/main.c b/tests/net/socket/udp/src/main.c index 23335b7367c..690512785eb 100644 --- a/tests/net/socket/udp/src/main.c +++ b/tests/net/socket/udp/src/main.c @@ -14,6 +14,8 @@ LOG_MODULE_REGISTER(net_test, CONFIG_NET_SOCKETS_LOG_LEVEL); #include #include +#include +#include #include "ipv6.h" #include "net_private.h" @@ -1924,6 +1926,10 @@ static void test_check_ttl(int sock_c, int sock_s, int sock_p, .tv_sec = 0, .tv_usec = 100000, }; +#if defined(CONFIG_NET_STATISTICS) + struct net_stats_ip ipv4_stats_before, ipv4_stats_after; + struct net_stats_ip ipv6_stats_before, ipv6_stats_after; +#endif Z_TEST_SKIP_IFNDEF(CONFIG_NET_INTERFACE_NAME); @@ -2025,10 +2031,27 @@ static void test_check_ttl(int sock_c, int sock_s, int sock_p, option == IP_TTL ? "unicast" : "multicast", -errno); +#if defined(CONFIG_NET_STATISTICS) + /* Get IPv4 stats and verify they are updated for dropped + * packets. + */ + net_mgmt(NET_REQUEST_STATS_GET_IPV4, lo0, + &ipv4_stats_before, sizeof(ipv4_stats_before)); +#endif ret = sendto(sock_c, &tx_buf, sizeof(tx_buf), 0, addr_sendto, addrlen_sendto); zassert_equal(ret, sizeof(tx_buf), "send failed (%d)", -errno); +#if defined(CONFIG_NET_STATISTICS) + net_mgmt(NET_REQUEST_STATS_GET_IPV4, lo0, + &ipv4_stats_after, sizeof(ipv4_stats_after)); + + zassert_equal(ipv4_stats_before.drop + 1, + ipv4_stats_after.drop, + "Dropped statistics not updated (%d vs %d)", + ipv4_stats_before.drop + 1, + ipv4_stats_after.drop); +#endif ret = recv(sock_s, &rx_buf, sizeof(rx_buf), 0); zassert_true(ret < 0 && errno == EAGAIN, "recv succeed (%d)", -errno); } @@ -2052,12 +2075,30 @@ static void test_check_ttl(int sock_c, int sock_s, int sock_p, option == IPV6_UNICAST_HOPS ? "unicast" : "multicast", -errno); +#if defined(CONFIG_NET_STATISTICS) + /* Get IPv6 stats and verify they are updated for dropped + * packets. + */ + net_mgmt(NET_REQUEST_STATS_GET_IPV6, lo0, + &ipv6_stats_before, sizeof(ipv6_stats_before)); +#endif ret = sendto(sock_c, &tx_buf, sizeof(tx_buf), 0, addr_sendto, addrlen_sendto); zassert_equal(ret, sizeof(tx_buf), "send failed (%d)", -errno); +#if defined(CONFIG_NET_STATISTICS) + net_mgmt(NET_REQUEST_STATS_GET_IPV6, lo0, + &ipv6_stats_after, sizeof(ipv6_stats_after)); + + zassert_equal(ipv6_stats_before.drop + 1, + ipv6_stats_after.drop, + "Dropped statistics not updated (%d vs %d)", + ipv6_stats_before.drop + 1, + ipv6_stats_after.drop); +#endif ret = recv(sock_s, &rx_buf, sizeof(rx_buf), 0); zassert_true(ret < 0 && errno == EAGAIN, "recv succeed (%d)", -errno); + } ret = close(sock_c); diff --git a/tests/net/socket/udp/testcase.yaml b/tests/net/socket/udp/testcase.yaml index 2b319cbb033..f8a881823da 100644 --- a/tests/net/socket/udp/testcase.yaml +++ b/tests/net/socket/udp/testcase.yaml @@ -22,3 +22,9 @@ tests: net.socket.udp.ttl: extra_configs: - CONFIG_NET_SOCKETS_PACKET=y + - CONFIG_NET_STATISTICS=y + - CONFIG_NET_STATISTICS_IPV4=y + - CONFIG_NET_STATISTICS_IPV6=y + - CONFIG_NET_STATISTICS_USER_API=y + - CONFIG_NET_MGMT_EVENT=y + - CONFIG_NET_MGMT=y From fc006d7daa3462d3bb5b81dee704a9b85f514971 Mon Sep 17 00:00:00 2001 From: Jukka Rissanen Date: Thu, 30 Nov 2023 21:47:16 +0200 Subject: [PATCH 0692/3723] net: dns: Do not pass 0 as TTL or hop limit We specifically set TTL/hoplimit to 1 for LLMNR, but only want to set it if in that specific case. We must not pass TTL/hoplimit value 0 as that would cause the packet to be dropped. Signed-off-by: Jukka Rissanen --- subsys/net/lib/dns/resolve.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/subsys/net/lib/dns/resolve.c b/subsys/net/lib/dns/resolve.c index 2741ed13a97..12336654ece 100644 --- a/subsys/net/lib/dns/resolve.c +++ b/subsys/net/lib/dns/resolve.c @@ -906,10 +906,12 @@ static int dns_write(struct dns_resolve_context *ctx, dns_qname->len + 2); if (IS_ENABLED(CONFIG_NET_IPV6) && - net_context_get_family(net_ctx) == AF_INET6) { + net_context_get_family(net_ctx) == AF_INET6 && + hop_limit > 0) { net_context_set_ipv6_hop_limit(net_ctx, hop_limit); } else if (IS_ENABLED(CONFIG_NET_IPV4) && - net_context_get_family(net_ctx) == AF_INET) { + net_context_get_family(net_ctx) == AF_INET && + hop_limit > 0) { net_context_set_ipv4_ttl(net_ctx, hop_limit); } From 060295c63b6b9cb64ff85d6a6bbf9cd4b6cfe287 Mon Sep 17 00:00:00 2001 From: Jukka Rissanen Date: Thu, 30 Nov 2023 22:01:09 +0200 Subject: [PATCH 0693/3723] net: dns: responders: Set the multicast TTL or hoplimit We are creating a multicast address in mDNS or LLMNR responder so set the TTL or hoplimit using the multicast variant API. Signed-off-by: Jukka Rissanen --- subsys/net/lib/dns/llmnr_responder.c | 4 ++-- subsys/net/lib/dns/mdns_responder.c | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/subsys/net/lib/dns/llmnr_responder.c b/subsys/net/lib/dns/llmnr_responder.c index 0c41b7df424..b5442904a74 100644 --- a/subsys/net/lib/dns/llmnr_responder.c +++ b/subsys/net/lib/dns/llmnr_responder.c @@ -339,7 +339,7 @@ static int create_ipv4_answer(struct net_context *ctx, return -ENOMEM; } - net_context_set_ipv4_ttl(ctx, 255); + net_context_set_ipv4_mcast_ttl(ctx, 255); return 0; } @@ -389,7 +389,7 @@ static int create_ipv6_answer(struct net_context *ctx, return -ENOMEM; } - net_context_set_ipv6_hop_limit(ctx, 255); + net_context_set_ipv6_mcast_hop_limit(ctx, 255); #endif /* CONFIG_NET_IPV6 */ return 0; diff --git a/subsys/net/lib/dns/mdns_responder.c b/subsys/net/lib/dns/mdns_responder.c index 4b8ad11dc1b..ce9e14511e5 100644 --- a/subsys/net/lib/dns/mdns_responder.c +++ b/subsys/net/lib/dns/mdns_responder.c @@ -110,11 +110,11 @@ int setup_dst_addr(struct net_context *ctx, sa_family_t family, if (IS_ENABLED(CONFIG_NET_IPV4) && family == AF_INET) { create_ipv4_addr(net_sin(dst)); *dst_len = sizeof(struct sockaddr_in); - net_context_set_ipv4_ttl(ctx, 255); + net_context_set_ipv4_mcast_ttl(ctx, 255); } else if (IS_ENABLED(CONFIG_NET_IPV6) && family == AF_INET6) { create_ipv6_addr(net_sin6(dst)); *dst_len = sizeof(struct sockaddr_in6); - net_context_set_ipv6_hop_limit(ctx, 255); + net_context_set_ipv6_mcast_hop_limit(ctx, 255); } else { return -EPFNOSUPPORT; } From f8c88a3fa6653c4ec5dd3b3300183759c0065fd7 Mon Sep 17 00:00:00 2001 From: Jukka Rissanen Date: Fri, 1 Dec 2023 09:28:06 +0200 Subject: [PATCH 0694/3723] tests: net: dns-sd: Fix IPv4 TTL and IPv6 hop limit checking We need to use multicast TTL/hoplimit instead of unicast one in the test. Signed-off-by: Jukka Rissanen --- tests/net/lib/dns_sd/src/main.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/tests/net/lib/dns_sd/src/main.c b/tests/net/lib/dns_sd/src/main.c index 53a1f07c578..31b7a6699a1 100644 --- a/tests/net/lib/dns_sd/src/main.c +++ b/tests/net/lib/dns_sd/src/main.c @@ -684,7 +684,7 @@ ZTEST(dns_sd, test_setup_dst_addr) zassert_equal(ret, 0, "Create IPv4 UDP context failed"); zassert_equal(0, setup_dst_addr(ctx_v4, AF_INET, &dst, &dst_len), ""); - zassert_equal(255, ctx_v4->ipv4_ttl, ""); + zassert_equal(255, ctx_v4->ipv4_mcast_ttl, ""); zassert_true(net_ipv4_addr_cmp(&addr_v4_expect, &net_sin(&dst)->sin_addr), ""); zassert_equal(8, dst_len, ""); @@ -701,7 +701,7 @@ ZTEST(dns_sd, test_setup_dst_addr) zassert_equal(ret, 0, "Create IPv6 UDP context failed"); zassert_equal(0, setup_dst_addr(ctx_v6, AF_INET6, &dst, &dst_len), ""); - zassert_equal(255, ctx_v6->ipv6_hop_limit, ""); + zassert_equal(255, ctx_v6->ipv6_mcast_hop_limit, ""); zassert_true(net_ipv6_addr_cmp(&addr_v6_expect, &net_sin6(&dst)->sin6_addr), ""); zassert_equal(24, dst_len, ""); From 7582160623d522dd90df97fe7b54fb6300cad672 Mon Sep 17 00:00:00 2001 From: Jukka Rissanen Date: Fri, 1 Dec 2023 14:52:18 +0200 Subject: [PATCH 0695/3723] doc: migration-guide: 3.6: IPv4 TTL and IPv6 hoplimit changes Add information about IPv4 TTL and IPv6 hoplimit changes for unicast and multicast packets. Signed-off-by: Jukka Rissanen --- doc/releases/migration-guide-3.6.rst | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/doc/releases/migration-guide-3.6.rst b/doc/releases/migration-guide-3.6.rst index bbedcf39cca..36ef77f1deb 100644 --- a/doc/releases/migration-guide-3.6.rst +++ b/doc/releases/migration-guide-3.6.rst @@ -203,6 +203,11 @@ Networking a NULL pointer. IGMPv3 can be enabled using the Kconfig ``CONFIG_NET_IPV4_IGMPV3``. (:github:`65293`) +* The network stack now uses a separate IPv4 TTL (time-to-live) value for multicast packets. + Before, the same TTL value was used for unicast and multicast packets. + The IPv6 hop limit value is also changed so that unicast and multicast packets can have a + different one. (:github:`65886`) + Other Subsystems ================ From ae8c3283ebd20941b637cd78e6457ca93a41a334 Mon Sep 17 00:00:00 2001 From: Jukka Rissanen Date: Fri, 1 Dec 2023 15:40:31 +0200 Subject: [PATCH 0696/3723] doc: release: 3.6: IPv4 TTL and IPv6 hoplimit changes Add information about IPv4 TTL and IPv6 hoplimit changes for unicast and multicast packets. Signed-off-by: Jukka Rissanen --- doc/releases/release-notes-3.6.rst | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/doc/releases/release-notes-3.6.rst b/doc/releases/release-notes-3.6.rst index 43d1b306eb9..18394f75ac9 100644 --- a/doc/releases/release-notes-3.6.rst +++ b/doc/releases/release-notes-3.6.rst @@ -222,6 +222,10 @@ Networking * Misc: + * It is now possible to have separate IPv4 TTL value and IPv6 hop limit value for + unicast and multicast packets. This can be controlled in each socket via + :c:func:`setsockopt` API. + * MQTT-SN: * OpenThread: From 51a011bbd31aa5b0390fa80329cbd20b2b6cca71 Mon Sep 17 00:00:00 2001 From: Christopher Friedt Date: Sun, 15 Oct 2023 10:03:01 -0400 Subject: [PATCH 0697/3723] tests: logging: add log_blocking testsuite to demonstrate bugfix Add a testsuite to demonstrate proper functionality of blocking in the log processing thread. This serves to demonstrate the previous bugfix, to provide missing test coverage for the option, and also to document what pitfalls to avoid when blocking in the log processing thread. Signed-off-by: Christopher Friedt --- .../logging/log_blocking/CMakeLists.txt | 7 + tests/subsys/logging/log_blocking/Kconfig | 22 ++ tests/subsys/logging/log_blocking/REAME.md | 97 +++++++ tests/subsys/logging/log_blocking/prj.conf | 28 ++ tests/subsys/logging/log_blocking/src/main.c | 241 ++++++++++++++++++ .../subsys/logging/log_blocking/testcase.yaml | 28 ++ 6 files changed, 423 insertions(+) create mode 100644 tests/subsys/logging/log_blocking/CMakeLists.txt create mode 100644 tests/subsys/logging/log_blocking/Kconfig create mode 100644 tests/subsys/logging/log_blocking/REAME.md create mode 100644 tests/subsys/logging/log_blocking/prj.conf create mode 100644 tests/subsys/logging/log_blocking/src/main.c create mode 100644 tests/subsys/logging/log_blocking/testcase.yaml diff --git a/tests/subsys/logging/log_blocking/CMakeLists.txt b/tests/subsys/logging/log_blocking/CMakeLists.txt new file mode 100644 index 00000000000..ca0f6392d69 --- /dev/null +++ b/tests/subsys/logging/log_blocking/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(log_blocking) + +target_sources(app PRIVATE src/main.c) diff --git a/tests/subsys/logging/log_blocking/Kconfig b/tests/subsys/logging/log_blocking/Kconfig new file mode 100644 index 00000000000..ef650c97550 --- /dev/null +++ b/tests/subsys/logging/log_blocking/Kconfig @@ -0,0 +1,22 @@ +# Copyright (c) 2023 Meta +# SPDX-License-Identifier: Apache-2.0 + +source "Kconfig.zephyr" + +config TEST_NUM_LOGS + int "Number of log messages per test" + default 5000 + +config TEST_INPUT_LOG_RATE + int "Maximal input log rate for the test (in msg/s)" + default 1000 + help + Specify the maximum rate at which messages will be logged from the + application. + +config TEST_OUTPUT_LOG_RATE + int "Maximal output log rate for the test (in msg/s)" + default 1000 + help + Specify the maximum rate at which log messages will be handled by + the log backend. diff --git a/tests/subsys/logging/log_blocking/REAME.md b/tests/subsys/logging/log_blocking/REAME.md new file mode 100644 index 00000000000..05c53174a04 --- /dev/null +++ b/tests/subsys/logging/log_blocking/REAME.md @@ -0,0 +1,97 @@ +# Blocking the Log Processing Thread + +## Overview + +When the core log buffer becomes full, the logging subsystem can be configured to + +* Drop older log messages with `CONFIG_LOG_MODE_OVERFLOW=y` (**default**) +* Drop newer log messages with `CONFIG_LOG_MODE_OVERFLOW=n`, or +* Drop no log messages at all with `CONFIG_LOG_BLOCK_IN_THREAD=y`, `CONFIG_LOG_BLOCK_IN_THREAD_TIMEOUT_MS=-1`. + +In the last configuration, the log processing thread will block until space +becomes available again in the core log buffer. + +> Warning ⚠️: Blocking the log processing thread is generally not recommended +> and should only be attempted in advanced use cases. + +## Logging and Flow Rates + +There are roughly 4 scenarios we care about testing with +`CONFIG_LOG_BLOCK_IN_THREAD`, and they can all be characterized by comparing +log message flow rates. Typically, one would describe log message flow rates +with units such as `[msg/s]`. However, in the table below, we are mainly +concerned with the ratio of the Output Rate to the Input Rate, and in that +case, the units themselves cancel-out. In the table we assume there exists an +`N` such that `N > 1`. + +| Name | Input Rate | Output Rate | Rate | +|----------------|------------|-------------|------| +| Input-Limited | 1 | N | 1 | +| Matched | 1 | 1 | 1 | +| Output-Limited | 1 | 1/N | 1/N | +| Stalled | 0 | 0 | 0 | + +The resultant _Rate_ is always `Rate = MIN(Input Rate, Output Rate)`. + +Rate-limiting of any kind can be described approximately as _back pressure_. +Back pressure is fine in short bursts but it can cause delays in application +and driver code if the pressure is not relieved promptly. + +## Physical Sources of Backpressure + +Many log backends, such as UARTs, have a built-in hardware FIFO that +inherently provides back-pressure; output log processing is rate-limited +based on the baud rate of the UART. Other backends, such as UDP sockets or +DMA, can provide significantly higher throughput but are still inherently +rate-limited by the physical layer over which they operate, be it Gigabit +Ethernet or PCI express. + +Even a trivial _message source_ or _message sink_ is still rate-limited by +memory or the CPU. From that perspective, we can infer that there is a finite +limit in the log processing rate for practical systems. That may be +comforting to know, even if it is something astronomical like 1G `[msg/s]`. + +## Input-Limited Log Rate + +The ideal scenario is when the output "bandwidth" exceeds the input rate. If +so configured, we minimize the liklihood that the log processing thread will +stall. We can also be sure that the output will be able to relieve +backpressure (i.e. the core log buffer usage will tend to zero over time). + +## Rate-Matched Input and Output + +When the input rate and output rates are equal, one might think this is the +ideal scenario. In reality, it is not. The rates could be matched, but a +sustained increase (or several small increases) in the input log rate, could +cause the core log buffer to approach 100% capacity. Since the output log rate +is still only matched with the input log rate, the core log buffer capacity +would not decrease from 100%, and it would remain saturated. + +Logging has a tendency to be bursty, so it is definitely preferable to +operate in the _Input-limited Log Rate_ regime. + +## Output-Limited Log Rate + +If the rate of output processing is less than the rate of input processing, +the core log buffer will approach 100% capacity and, eventually, stall the +log processing thread. + +## Stalling the Log Processing Thread + +When any log backend is unable to process logs for whatever reason, +the output rate approaches 0 `[msg/s]`. If application or +driver code continue to submit logs, the core log buffer approaches 100% +capacity. Once the core log buffer is full, the log processing thread is +unable to allocate new log messages and it will be stalled. + +Stalling a real-time application produces unexpected behaviour, so it is +advised to avoid this for any non-negligible amount of time. + +It is absolutely critical that the log backend is capable of operating +correctly _even when the log processing thread is blocking_ in order to +automatically recover from a stall. + +On a live system, it may be necessary to manually perform remediation of log +backends that are unable to recover from stalling the log processing thread. +Remediation could involve disabling the log backend and freeing any in-use +buffers. diff --git a/tests/subsys/logging/log_blocking/prj.conf b/tests/subsys/logging/log_blocking/prj.conf new file mode 100644 index 00000000000..7dd3a696768 --- /dev/null +++ b/tests/subsys/logging/log_blocking/prj.conf @@ -0,0 +1,28 @@ +CONFIG_ZTEST=y + +CONFIG_TEST_LOGGING_DEFAULTS=n +CONFIG_LOG=y +CONFIG_LOG_PRINTK=n +CONFIG_LOG_BUFFER_SIZE=512 +CONFIG_ASSERT=y +CONFIG_MAIN_STACK_SIZE=2048 + +# Disable any logs that could interfere. +CONFIG_KERNEL_LOG_LEVEL_OFF=y +CONFIG_SOC_LOG_LEVEL_OFF=y +CONFIG_ARCH_LOG_LEVEL_OFF=y +CONFIG_LOG_FUNC_NAME_PREFIX_DBG=n +CONFIG_LOG_PROCESS_THREAD=y + +# Disable all potential default backends +CONFIG_LOG_BACKEND_UART=n +CONFIG_LOG_BACKEND_NATIVE_POSIX=n +CONFIG_LOG_BACKEND_RTT=n +CONFIG_LOG_BACKEND_XTENSA_SIM=n + +# Enable blocking in thread +CONFIG_LOG_MODE_DEFERRED=y +CONFIG_LOG_BLOCK_IN_THREAD=y + +# Block in thread indefinitely +CONFIG_LOG_BLOCK_IN_THREAD_TIMEOUT_MS=-1 diff --git a/tests/subsys/logging/log_blocking/src/main.c b/tests/subsys/logging/log_blocking/src/main.c new file mode 100644 index 00000000000..8ce30a5c5f5 --- /dev/null +++ b/tests/subsys/logging/log_blocking/src/main.c @@ -0,0 +1,241 @@ +/* + * Copyright (c) 2022 Nordic Semiconductor ASA + * Copyright (c) 2023 Meta + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include + +/* maximum time to wait before aborting thread in case of 0 log messages / second */ +#define MAX_STALL_TIMEOUT_S 3 +/* maximum time (seconds) to wait for logging thread to finish */ +#define MAX_JOIN_TIMEOUT_S 1 + +#define WILL_STALL (CONFIG_TEST_INPUT_LOG_RATE == 0 || CONFIG_TEST_OUTPUT_LOG_RATE == 0) + +#define MODULE_NAME test + +LOG_MODULE_REGISTER(MODULE_NAME); + +struct mock_log_backend { + uint32_t dropped; + uint32_t handled; +}; + +static uint32_t end_ms; +static uint32_t start_ms; +static uint32_t test_source_id; +static struct mock_log_backend mock_backend; + +static inline uint32_t then(void) +{ + return start_ms; +} + +static inline uint32_t now(void) +{ + /* some platforms currently _not_ starting uptime at 0!! */ + return k_uptime_get_32(); +} + +static inline uint32_t end(void) +{ + return end_ms; +} + +static inline void create_start_end(void) +{ + start_ms = k_uptime_get_32(); + end_ms = start_ms; + /* some "fuzz" in ms to account for odd variances */ + end_ms += MAX_STALL_TIMEOUT_S * MSEC_PER_SEC; + +#if WILL_STALL + end_ms += MAX_STALL_TIMEOUT_S * MSEC_PER_SEC; +#elif CONFIG_TEST_INPUT_LOG_RATE > 0 && CONFIG_TEST_INPUT_LOG_RATE <= CONFIG_TEST_OUTPUT_LOG_RATE + end_ms += MSEC_PER_SEC * DIV_ROUND_UP(CONFIG_TEST_NUM_LOGS, CONFIG_TEST_INPUT_LOG_RATE); +#elif CONFIG_TEST_OUTPUT_LOG_RATE > 0 && CONFIG_TEST_INPUT_LOG_RATE > CONFIG_TEST_OUTPUT_LOG_RATE + end_ms += MSEC_PER_SEC * DIV_ROUND_UP(CONFIG_TEST_NUM_LOGS, CONFIG_TEST_OUTPUT_LOG_RATE); +#else +#error "Impossible scenario" +#endif + + TC_PRINT("Start time: %u ms\n", start_ms); + TC_PRINT("End time: %u ms\n", end_ms); +} + +static void handle_output(uint32_t i) +{ + while (true) { + if (i + 1 <= (CONFIG_TEST_OUTPUT_LOG_RATE * (now() - then())) / MSEC_PER_SEC) { + break; + } + k_msleep(1); + } + + ++mock_backend.handled; +} + +static void handle_input(void) +{ + for (int i = 0; i < CONFIG_TEST_NUM_LOGS; i++) { + while (true) { + if (i + 1 <= CONFIG_TEST_INPUT_LOG_RATE * (now() - then()) / MSEC_PER_SEC) { + break; + } + zassert_true(now() <= end()); + k_msleep(1); + } + + LOG_INF("%u", i); + } +} + +static void process(const struct log_backend *const backend, union log_msg_generic *msg) +{ + size_t len; + uint8_t *package = log_msg_get_package(&msg->log, &len); + + package += 2 * sizeof(void *); + + handle_output(*(uint32_t *)package); +} + +static void mock_init(struct log_backend const *const backend) +{ +} + +static void panic(struct log_backend const *const backend) +{ +#if WILL_STALL + /* Don't panic! */ + return; +#endif + + zassert_true(false); +} + +static void dropped(const struct log_backend *const backend, uint32_t cnt) +{ + mock_backend.dropped += cnt; +} + +static const struct log_backend_api log_blocking_api = { + .process = process, + .panic = panic, + .init = mock_init, + .dropped = dropped, +}; + +LOG_BACKEND_DEFINE(blocking_log_backend, log_blocking_api, true, NULL); + +BUILD_ASSERT(CONFIG_TEST_INPUT_LOG_RATE >= 0); +BUILD_ASSERT(CONFIG_TEST_OUTPUT_LOG_RATE >= 0); + +static void print_input(void) +{ + TC_PRINT("CONFIG_TEST_NUM_LOGS: %d\n", CONFIG_TEST_NUM_LOGS); + TC_PRINT("CONFIG_TEST_INPUT_LOG_RATE: %d\n", CONFIG_TEST_INPUT_LOG_RATE); + TC_PRINT("CONFIG_TEST_OUTPUT_LOG_RATE: %d\n", CONFIG_TEST_OUTPUT_LOG_RATE); +} + +static void print_output(void) +{ + TC_PRINT("Log backend dropped %u messages\n", mock_backend.dropped); + TC_PRINT("Log backend handled %u messages\n", mock_backend.handled); +} + +static void test_blocking_thread_entry(void *p1, void *p2, void *p3) +{ + ARG_UNUSED(p1); + ARG_UNUSED(p2); + ARG_UNUSED(p3); + + handle_input(); +} +K_THREAD_DEFINE(test_blocking_thread, 4096, test_blocking_thread_entry, NULL, NULL, NULL, + K_HIGHEST_THREAD_PRIO, 0, UINT32_MAX); + +#if WILL_STALL +ZTEST_EXPECT_FAIL(log_blocking, test_blocking); +#endif +ZTEST(log_blocking, test_blocking) +{ +#if WILL_STALL + /* + * This is a workaround for a possible bug in the testing subsys: + * - comment-out ztest_test_fail() below + * - run with: + * west build -p auto -b qemu_riscv64 -t run \ + * -T tests/subsys/logging/log_blocking/logging.blocking.rate.stalled + * - observe "Assertion failed at..." + * - technically, testsuite should pass. Since ZTEST_EXPECT_FAIL() is set. Never gets there. + * - run with: + * twister -i -p qemu_riscv64 -T tests/subsys/logging/log_blocking/ + * - observe "..FAILED : Timeout" + * - possible conclusions: + * - test thread has not properly longjumped? + * - twister not detecting assertion failures? + * - twister expecting some other string and never sees it? + */ + ztest_test_fail(); +#endif + + create_start_end(); + k_thread_start(test_blocking_thread); + k_msleep(end() - now()); + +#if WILL_STALL + k_thread_abort(test_blocking_thread); +#endif + zassert_ok(k_thread_join(test_blocking_thread, K_SECONDS(MAX_JOIN_TIMEOUT_S))); + + print_output(); + + zassert_equal(mock_backend.dropped, 0, "dropped %u / %u logs", mock_backend.dropped, + CONFIG_TEST_NUM_LOGS); + + zassert_equal(mock_backend.handled, CONFIG_TEST_NUM_LOGS, "handled %u / %u logs", + mock_backend.handled, CONFIG_TEST_NUM_LOGS); +} + +static void *setup(void) +{ + /* + * This testsuite was added mainly to address a regression caused + * by this subtle, but very different interpretation. + */ + __ASSERT(K_TIMEOUT_EQ(K_NO_WAIT, K_MSEC(-1)), "K_NO_WAIT should be equal to K_MSEC(-1)"); + __ASSERT(!K_TIMEOUT_EQ(K_FOREVER, K_MSEC(-1)), + "K_FOREVER should not be equal to K_MSEC(-1)"); + + test_source_id = log_source_id_get(STRINGIFY(MODULE_NAME)); + + print_input(); + + return NULL; +} + +static void before(void *arg) +{ + memset(&mock_backend, 0, sizeof(mock_backend)); +} + +static void teardown(void *data) +{ + ARG_UNUSED(data); + log_backend_disable(&blocking_log_backend); +} + +ZTEST_SUITE(log_blocking, NULL, setup, before, NULL, teardown); diff --git a/tests/subsys/logging/log_blocking/testcase.yaml b/tests/subsys/logging/log_blocking/testcase.yaml new file mode 100644 index 00000000000..7d2880115bb --- /dev/null +++ b/tests/subsys/logging/log_blocking/testcase.yaml @@ -0,0 +1,28 @@ +common: + filter: CONFIG_QEMU_TARGET and not CONFIG_SMP + tags: + - log_api + - logging + integration_platforms: + - qemu_x86 +tests: + logging.blocking.rate.input_limited: + extra_configs: + - CONFIG_TEST_INPUT_LOG_RATE=500 + - CONFIG_TEST_OUTPUT_LOG_RATE=1000 + logging.blocking.rate.matched: + extra_configs: + - CONFIG_TEST_INPUT_LOG_RATE=1000 + - CONFIG_TEST_OUTPUT_LOG_RATE=1000 + logging.blocking.rate.output_limited: + extra_configs: + - CONFIG_TEST_INPUT_LOG_RATE=1000 + - CONFIG_TEST_OUTPUT_LOG_RATE=500 + logging.blocking.rate.stalled: + platform_exclude: + # twister fails with "unexpected eof" even though the test passes + - qemu_cortex_r5 + timeout: 5 + extra_configs: + - CONFIG_TEST_INPUT_LOG_RATE=1000 + - CONFIG_TEST_OUTPUT_LOG_RATE=0 From 78e961998aa7ea17560e934b08b8489b4a300ea8 Mon Sep 17 00:00:00 2001 From: Ryan McClelland Date: Mon, 13 Nov 2023 13:57:21 -0800 Subject: [PATCH 0698/3723] drivers: i3c: add additional variable for num xfer for i3c With I3C, when a controller does a read whether, through a private transfer or a CCC, the target is responsible for issuing the End of Data through the T bit, but the way the API is currently implemented, there is no way to communicate this back up. For example, if a controller tries to read 100 Bytes (where the controller is to do an abort after 100 (or 101 bytes)) from a Target and the Target gives the EoD at the 42nd Byte, then there is no way to currently know where the EoD occurred and how far it can be read up to in the provided buffers. This implements a num_xfer for `i3c_msg` and `i3c_ccc_payload` which the driver is responsible for writing the total number of bytes transferred. Signed-off-by: Ryan McClelland --- include/zephyr/drivers/i3c.h | 10 ++++++++++ include/zephyr/drivers/i3c/ccc.h | 18 ++++++++++++++++++ 2 files changed, 28 insertions(+) diff --git a/include/zephyr/drivers/i3c.h b/include/zephyr/drivers/i3c.h index 9129b15d0c3..a814b7d436b 100644 --- a/include/zephyr/drivers/i3c.h +++ b/include/zephyr/drivers/i3c.h @@ -1,5 +1,6 @@ /* * Copyright 2022 Intel Corporation + * Copyright 2023 Meta Platforms, Inc. and its affiliates * * SPDX-License-Identifier: Apache-2.0 */ @@ -476,6 +477,15 @@ struct i3c_msg { /** Length of buffer in bytes */ uint32_t len; + /** + * Total number of bytes transferred + * + * A Target can issue an EoD or the Controller can abort a transfer + * before the length of the buffer. It is expected for the driver to + * write to this after the transfer. + */ + uint32_t num_xfer; + /** Flags for this message */ uint8_t flags; diff --git a/include/zephyr/drivers/i3c/ccc.h b/include/zephyr/drivers/i3c/ccc.h index 606d44f79ae..116750bcac5 100644 --- a/include/zephyr/drivers/i3c/ccc.h +++ b/include/zephyr/drivers/i3c/ccc.h @@ -1,5 +1,6 @@ /* * Copyright 2022 Intel Corporation + * Copyright 2023 Meta Platforms, Inc. and its affiliates * * SPDX-License-Identifier: Apache-2.0 */ @@ -248,6 +249,15 @@ struct i3c_ccc_target_payload { /** Length in bytes for @p data. */ size_t data_len; + + /** + * Total number of bytes transferred + * + * A Target can issue an EoD or the Controller can abort a transfer + * before the length of the buffer. It is expected for the driver to + * write to this after the transfer. + */ + size_t num_xfer; }; /** @@ -270,6 +280,14 @@ struct i3c_ccc_payload { /** Length in bytes for optional data array. */ size_t data_len; + + /** + * Total number of bytes transferred + * + * A Controller can abort a transfer before the length of the buffer. + * It is expected for the driver to write to this after the transfer. + */ + size_t num_xfer; } ccc; struct { From 1e663dbedca4dee9e892c3e318e5bd539346cee0 Mon Sep 17 00:00:00 2001 From: Ryan McClelland Date: Mon, 13 Nov 2023 14:00:46 -0800 Subject: [PATCH 0699/3723] drivers: i3c: cdns: write back total number of bytes transferred The command response buffer will return the total number of bytes transfered. This will write back to the pointer which is to contain the number of bytes sent or received. Signed-off-by: Ryan McClelland --- drivers/i3c/i3c_cdns.c | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+) diff --git a/drivers/i3c/i3c_cdns.c b/drivers/i3c/i3c_cdns.c index c541f104369..27f6b1af8da 100644 --- a/drivers/i3c/i3c_cdns.c +++ b/drivers/i3c/i3c_cdns.c @@ -433,6 +433,7 @@ struct cdns_i3c_cmd { uint32_t cmd0; uint32_t cmd1; uint32_t len; + uint32_t *num_xfer; void *buf; uint32_t error; }; @@ -1033,6 +1034,8 @@ static int cdns_i3c_do_ccc(const struct device *dev, struct i3c_ccc_payload *pay dcmd->buf = payload->ccc.data; dcmd->len = payload->ccc.data_len; dcmd->cmd0 |= CMD0_FIFO_PL_LEN(payload->ccc.data_len); + /* write the address of num_xfer which is to be updated upon message completion */ + dcmd->num_xfer = &(payload->ccc.num_xfer); } else if (payload->targets.num_targets > 0) { dcmd->buf = payload->targets.payloads[0].data; dcmd->len = payload->targets.payloads[0].data_len; @@ -1041,6 +1044,8 @@ static int cdns_i3c_do_ccc(const struct device *dev, struct i3c_ccc_payload *pay if (payload->targets.payloads[0].rnw) { dcmd->cmd0 |= CMD0_FIFO_RNW; } + /* write the address of num_xfer which is to be updated upon message completion */ + dcmd->num_xfer = &(payload->targets.payloads[0].num_xfer); idx++; } num_cmds++; @@ -1066,6 +1071,11 @@ static int cdns_i3c_do_ccc(const struct device *dev, struct i3c_ccc_payload *pay cmd->buf = tgt_payload->data; cmd->len = tgt_payload->data_len; + /* + * write the address of num_xfer which is to be updated upon message + * completion + */ + cmd->num_xfer = &(tgt_payload->num_xfer); idx++; } @@ -1299,6 +1309,9 @@ static void cdns_i3c_complete_transfer(const struct device *dev) /* Read any rx data into buffer */ if (cmd->cmd0 & CMD0_FIFO_RNW) { rx = MIN(CMDR_XFER_BYTES(cmdr), cmd->len); + if (cmd->num_xfer != NULL) { + *cmd->num_xfer = rx; + } ret = cdns_i3c_read_rx_fifo(config, cmd->buf, rx); } @@ -1422,6 +1435,9 @@ static int cdns_i3c_i2c_transfer(const struct device *dev, struct i3c_i2c_device if ((msgs[i].flags & I2C_MSG_RW_MASK) == I2C_MSG_READ) { cmd->cmd0 |= CMD0_FIFO_RNW; } + + /* i2c transfers are a don't care for num_xfer */ + cmd->num_xfer = NULL; } data->xfer.ret = -ETIMEDOUT; @@ -1723,6 +1739,9 @@ static int cdns_i3c_transfer(const struct device *dev, struct i3c_device_desc *t } else { send_broadcast = true; } + + /* write the address of num_xfer which is to be updated upon message completion */ + cmd->num_xfer = &(msgs[i].num_xfer); } data->xfer.ret = -ETIMEDOUT; From 07557e3c62f7436596b1af48e2ee23d76082d579 Mon Sep 17 00:00:00 2001 From: Ryan McClelland Date: Mon, 13 Nov 2023 14:02:53 -0800 Subject: [PATCH 0700/3723] drivers: i3c: mcux: write back total number of bytes transferred Write back the total number of bytes actually transferred. Signed-off-by: Ryan McClelland --- drivers/i3c/i3c_mcux.c | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/drivers/i3c/i3c_mcux.c b/drivers/i3c/i3c_mcux.c index d996639dab0..a9b9ad305f1 100644 --- a/drivers/i3c/i3c_mcux.c +++ b/drivers/i3c/i3c_mcux.c @@ -1131,6 +1131,9 @@ static int mcux_i3c_transfer(const struct device *dev, goto out_xfer_i3c_stop_unlock; } + /* write back the total number of bytes transferred */ + msgs[i].num_xfer = ret; + if (emit_stop) { /* After a STOP, send broadcast header before next msg */ send_broadcast = true; @@ -1371,6 +1374,9 @@ static int mcux_i3c_do_ccc(const struct device *dev, goto out_ccc_stop; } + + /* write back the total number of bytes transferred */ + payload->ccc.num_xfer = ret; } /* Wait for controller to say the operation is done */ @@ -1402,6 +1408,9 @@ static int mcux_i3c_do_ccc(const struct device *dev, goto out_ccc_stop; } + + /* write back the total number of bytes transferred */ + tgt_payload->num_xfer = ret; } } From 0dab59ab8e75668fab5d4b15d2c57038752ace48 Mon Sep 17 00:00:00 2001 From: Laurentiu Mihalcea Date: Wed, 20 Sep 2023 17:06:51 +0300 Subject: [PATCH 0701/3723] manifest: Bump up hal_nxp revision Bump up hal_nxp revision to contain the IRQ_STEER-related changes. Signed-off-by: Laurentiu Mihalcea --- west.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/west.yml b/west.yml index cc1b69f83a5..bb943b245d7 100644 --- a/west.yml +++ b/west.yml @@ -193,7 +193,7 @@ manifest: groups: - hal - name: hal_nxp - revision: 2796169ee23dc838311b65758806eb94546a7bc2 + revision: d0c424e1c6ef0acac3099a07280a46a24951a47a path: modules/hal/nxp groups: - hal From fd8ac9e6cddf5b8ff69d7a5eabd62311aecb42d7 Mon Sep 17 00:00:00 2001 From: Laurentiu Mihalcea Date: Mon, 18 Sep 2023 16:09:58 +0300 Subject: [PATCH 0702/3723] drivers: interrupt_controller: Add driver for NXP's IRQ_STEER IP This commit introduces a new interrupt controller driver used for NXP's IRQ_STEER IP. Apart from introducing the driver itself, this commit contains the following changes: 1) Switch i.MX8MP to using the XTENSA core interrupt controller instead of the dummy irqsteer one. * this is required because the binding for the irqsteer driver is no longer a dummy one (since it's being used by the irqsteer driver). As such, to avoid having problems, switch to using another dummy binding. 2) Modify the irqsteer dummy binding such that it serves the IRQ_STEER driver's needs. Signed-off-by: Laurentiu Mihalcea --- drivers/interrupt_controller/CMakeLists.txt | 1 + drivers/interrupt_controller/Kconfig | 2 + .../interrupt_controller/Kconfig.nxp_irqsteer | 14 + .../interrupt_controller/intc_nxp_irqsteer.c | 480 ++++++++++++++++++ .../nxp,irqsteer-intc.yaml | 10 +- .../nxp,irqsteer-master.yaml | 15 + dts/xtensa/nxp/nxp_imx8m.dtsi | 24 +- 7 files changed, 529 insertions(+), 17 deletions(-) create mode 100644 drivers/interrupt_controller/Kconfig.nxp_irqsteer create mode 100644 drivers/interrupt_controller/intc_nxp_irqsteer.c create mode 100644 dts/bindings/interrupt-controller/nxp,irqsteer-master.yaml diff --git a/drivers/interrupt_controller/CMakeLists.txt b/drivers/interrupt_controller/CMakeLists.txt index 7ef0a5e161e..989a75ab6dc 100644 --- a/drivers/interrupt_controller/CMakeLists.txt +++ b/drivers/interrupt_controller/CMakeLists.txt @@ -37,6 +37,7 @@ zephyr_library_sources_ifdef(CONFIG_NXP_S32_WKPU intc_wkpu_nxp_s32.c) zephyr_library_sources_ifdef(CONFIG_XMC4XXX_INTC intc_xmc4xxx.c) zephyr_library_sources_ifdef(CONFIG_NXP_PINT intc_nxp_pint.c) zephyr_library_sources_ifdef(CONFIG_RENESAS_RA_ICU intc_ra_icu.c) +zephyr_library_sources_ifdef(CONFIG_NXP_IRQSTEER intc_nxp_irqsteer.c) if(CONFIG_INTEL_VTD_ICTL) zephyr_library_include_directories(${ZEPHYR_BASE}/arch/x86/include) diff --git a/drivers/interrupt_controller/Kconfig b/drivers/interrupt_controller/Kconfig index 2a79a998c02..fca4b32e6a4 100644 --- a/drivers/interrupt_controller/Kconfig +++ b/drivers/interrupt_controller/Kconfig @@ -104,4 +104,6 @@ source "drivers/interrupt_controller/Kconfig.vim" source "drivers/interrupt_controller/Kconfig.ra" +source "drivers/interrupt_controller/Kconfig.nxp_irqsteer" + endmenu diff --git a/drivers/interrupt_controller/Kconfig.nxp_irqsteer b/drivers/interrupt_controller/Kconfig.nxp_irqsteer new file mode 100644 index 00000000000..b2dbc9b2afa --- /dev/null +++ b/drivers/interrupt_controller/Kconfig.nxp_irqsteer @@ -0,0 +1,14 @@ +# Copyright 2023 NXP +# SPDX-License-Identifier: Apache-2.0 + +config NXP_IRQSTEER + bool "IRQ_STEER interrupt controller for NXP chips" + default y + depends on DT_HAS_NXP_IRQSTEER_INTC_ENABLED + depends on MULTI_LEVEL_INTERRUPTS + depends on XTENSA + help + The IRQSTEER INTC provides support for MUX-ing + multiple interrupts from peripheral to one or + more CPU interrupt lines. This is used for CPUs + such as XTENSA DSPs. diff --git a/drivers/interrupt_controller/intc_nxp_irqsteer.c b/drivers/interrupt_controller/intc_nxp_irqsteer.c new file mode 100644 index 00000000000..a456c17545e --- /dev/null +++ b/drivers/interrupt_controller/intc_nxp_irqsteer.c @@ -0,0 +1,480 @@ +/* + * Copyright 2023 NXP + * + * SPDX-License-Identifier: Apache-2.0 + */ + +/** + * @file + * @brief Driver for NXP's IRQ_STEER IP. + * + * Below you may find some useful information that will help you better understand how the + * driver works. The ">" sign is used to mark ideas that are considered important and should + * be taken note of. + * + * 1) What is the IRQ_STEER IP? + * - in Zephyr terminology, the IRQ_STEER can be considered an interrupt aggregator. As such, + * its main goal is to multiplex multiple interrupt lines into a single/multiple ones. + * + * 2) How does the IRQ_STEER IP work? + * - below you may find a diagram meant to give you an intuition regarding the IP's structure + * and how it works (all of the information below is applicable to i.MX8MP but it can be + * extended to any NXP SoC using the IRQ_STEER IP): + * + * SYSTEM_INTID[0:159] + * | + * MASK[0:4]------ | + * | | + * +------+ + * | | + * |32 AND| + * | | + * +------+ + * | + * SET[0:4]------ | + * | | + * +------+ + * | | + * |32 OR | + * | | + * +------+ + * |__________ STATUS[0:4] + * | + * +------+ + * |GROUP | + * | BY | + * | 64 | + * +------+ + * | | | + * _____________| | |________________ + * | | | + * MASTER_IN[0] MASTER_IN[1] MASTER_IN[2] + * | | | + * | | | + * |_____________ | _______________| + * | | | + * +------+ + * | | + * | AND | ---------- MINTDIS[0:2] + * | | + * +------+ + * | | | + * _____________| | |________________ + * | | | + * MASTER_OUT[0] MASTER_OUT[1] MASTER_OUT[2] + * + * - initially, all SYSTEM_INTID are grouped by 32 => 5 groups. + * + * > each of these groups is controlled by a MASK, SET and STATUS index as follows: + * + * MASK/SET/STATUS[0] => SYSTEM_INTID[159:128] + * MASK/SET/STATUS[1] => SYSTEM_INTID[127:96] + * MASK/SET/STATUS[2] => SYSTEM_INTID[95:64] + * MASK/SET/STATUS[3] => SYSTEM_INTID[63:32] + * MASK/SET/STATUS[4] => SYSTEM_INTID[31:0] + * + * > after that, all SYSTEM_INTID are grouped by 64 as follows: + * + * SYSTEM_INTID[159:96] => MASTER_IN[2] + * SYSTEM_INTID[95:32] => MASTER_IN[1] + * SYSTEM_INTID[31:0] => MASTER_IN[0] + * + * note: MASTER_IN[0] is only responsible for 32 interrupts + * + * > the value of MASTER_IN[x] is obtained by OR'ing the input interrupt lines. + * + * > the value of MASTER_OUT[x] is obtained by AND'ing MASTER_IN[x] with !MINTDIS[x]. + * + * - whenever a SYSTEM_INTID is asserted, its corresponding MASTER_OUT signal will also + * be asserted, thus signaling the target processor. + * + * > please note the difference between an IRQ_STEER channel and an IRQ_STEER master output. + * An IRQ_STEER channel refers to an IRQ_STEER instance (e.g: the DSP uses IRQ_STEER channel + * 0 a.k.a instance 0). An IRQ_STEER channel has multiple master outputs. For example, in + * the case of i.MX8MP each IRQ_STEER channel has 3 master outputs since an IRQ_STEER channel + * routes 160 interrupts (32 for first master output, 64 for second master output, and 64 for + * the third master output). + * + * 3) Using Zephyr's multi-level interrupt support + * - since Zephyr supports organizing interrupts on multiple levels, we can use this to + * separate the interrupts in 2 levels: + * 1) LEVEL 1 INTERRUPTS + * - these are the interrupts that go directly to the processor (for example, + * on i.MX8MP the MU can directly assert the DSP's interrupt line 7) + * + * 2) LEVEL 2 INTERRUPTS + * - these interrupts go through IRQ_STEER and are signaled by a single + * processor interrupt line. + * - e.g: for i.MX8MP, INTID 34 (SDMA3) goes through IRQ_STEER and is signaled + * to the DSP by INTID 20 which is a direct interrupt (or LEVEL 1 interrupt). + * + * - the following diagram (1) shows the interrupt organization on i.MX8MP: + * +------------+ + * | | + * SYSTEM_INTID[31:0] ------ IRQ_STEER_MASTER_0 ---- | 19 | + * | | + * SYSTEM_INTID[95:32] ----- IRQ_STEER_MASTER_1 ---- | 20 DSP | + * | | + * SYSTEM_INTID[159:96] ---- IRQ_STEER_MASTER_2 ---- | 21 | + * | | + * +------------+ + * + * - as such, asserting a system interrupt will lead to asserting its corresponding DSP + * interrupt line (for example, if system interrupt 34 is asserted, that would lead to + * interrupt 20 being asserted) + * + * - in the above diagram, SYSTEM_INTID[x] are LEVEL 2 interrupts, while 19, 20, and 21 are + * LEVEL 1 interrupts. + * + * - INTID 19 is the parent of SYSTEM_INTID[31:0] and so on. + * + * > before going into how the INTIDs are encoded, we need to distinguish between 3 types of + * INTIDs: + * 1) System INTIDs + * - these are the values that can be found in NXP's TRMs for different + * SoCs (usually they have the same IDs as the GIC SPIs) + * - for example, INTID 34 is a system INTID for SDMA3 (i.MX8MP). + * + * 2) Zephyr INTIDs + * - these are the Zephyr-specific encodings of the system INTIDs. + * - these are used to encode multi-level interrupts (for more information + * please see [1]) + * > if you need to register an interrupt dynamically, you need to use this + * encoding when specifying the interrupt. + * + * 3) DTS INTIDs + * - these are the encodings of the system INTIDs used in the DTS. + * - all of these INTIDs are relative to IRQ_STEER's MASTER_OUTs. + * + * > encoding an INTID: + * 1) SYSTEM INTID => ZEPHYR INTID + * - the following steps need to be performed: + * + * a) Find out which IRQ_STEER MASTER + * is in charge of aggregating this interrupt. + * * for instance, SYSTEM_INTID 34 (SDMA3 on i.MX8MP) is + * aggregated by MASTER 1 as depicted in diagram (1). + * + * b) After finding the MASTER aggregator, you need + * to find the corresponding parent interrupt. + * * for example, SYSTEM_INTID 34 (SDMA3 on i.MX8MP) is + * aggregated by MASTER 1, which has the parent INTID 20 + * as depicted in diagram (1) => PARENT_INTID(34) = 20. + * + * c) Find the INTID relative to the MASTER aggregator. This is done + * by subtracting the number of interrupts each of the previous + * master aggregators is in charge of. If the master aggregator is + * MASTER 0 then RELATIVE_INTID=SYSTEM_INTID. + * * for example, SYSTEM_ID 34 is aggregated by MASTER 1. + * As such, we need to subtract 32 from 34 (because the + * previous master - MASTER 0 - is in charge of aggregating + * 32 interrupts) => RELATIVE_INTID(34) = 2. + * + * * generally speaking, RELATIVE_INTID can be computed using + * the following formula (assuming SYSTEM_INTID belongs to + * MASTER y): + * RELATIVE_INTID(x) = x - + * \sum{i=0}^{y - 1} GET_MASTER_INT_NUM(i) + * where: + * 1) GET_MASTER_INT_NUM(x) computes the number of + * interrupts master x aggregates + * 2) x is the system interrupt + * + * * to make sure your computation is correct use the + * following restriction: + * 0 <= RELATIVE_INTID(x) < GET_MASTER_INT_NUM(y) + * + * d) To the obtained RELATIVE_INTID you need to add the value of 1, + * left shift the result by the number of bits used to encode the + * level 1 interrupts (see [1] for details) and OR the parent ID. + * * for example, RELATIVE_INTID(34) = 2 (i.MX8MP), + * PARENT_INTID(34) = 20 => ZEPHYR_INTID = ((2 + 1) << 8) | 20 + * + * * generally speaking, ZEPHYR_INTID can be computed using + * the following formula: + * ZEPHYR_INTID(x) = ((RELATIVE_INTID(x) + 1) << + * NUM_LVL1_BITS) | PARENT_INTID(x) + * where: + * 1) RELATIVE_INTID(x) computes the relative INTID + * of system interrupt x (step c). + * + * 2) NUM_LVL1_BITS is the number of bits used to + * encode level 1 interrupts. + * + * 3) PARENT_INTID(x) computes the parent INTID of a + * system interrupt x (step b) + * + * - all of these steps are performed by to_zephyr_irq(). + * > for interrupts aggregated by MASTER 0 you may skip step c) as + * RELATIVE_INTID(x) = x. + * + * 2) SYSTEM INTID => DTS INTID + * - for this you just have to compute RELATIVE_INTID as described above in + * step c). + * - for example, if an IP uses INTID 34 you'd write its interrupts property + * as follows (i.MX8MP): + * interrupts = <&master1 2>; + * + * 4) Notes and comments + * > PLEASE DON'T MISTAKE THE ZEPHYR MULTI-LEVEL INTERRUPT ORGANIZATION WITH THE XTENSA ONE. + * THEY ARE DIFFERENT THINGS. + * + * [1]: https://docs.zephyrproject.org/latest/kernel/services/interrupts.html#multi-level-interrupt-handling + */ + +#include +#include +#include +#include + +#include "sw_isr_common.h" + +/* used for driver binding */ +#define DT_DRV_COMPAT nxp_irqsteer_intc + +/* macros used for DTS parsing */ +#define _IRQSTEER_REGISTER_DISPATCHER(node_id) \ + IRQ_CONNECT(DT_IRQN(node_id), \ + DT_IRQ(node_id, priority), \ + irqsteer_isr_dispatcher, \ + &dispatchers[DT_REG_ADDR(node_id)], \ + 0) + +#define _IRQSTEER_DECLARE_DISPATCHER(node_id) \ +{ \ + .dev = DEVICE_DT_GET(DT_PARENT(node_id)), \ + .master_index = DT_REG_ADDR(node_id), \ + .irq = DT_IRQN(node_id), \ +} + +#define IRQSTEER_DECLARE_DISPATCHERS(parent_id)\ + DT_FOREACH_CHILD_STATUS_OKAY_SEP(parent_id, _IRQSTEER_DECLARE_DISPATCHER, (,)) + +#define IRQSTEER_REGISTER_DISPATCHERS(parent_id)\ + DT_FOREACH_CHILD_STATUS_OKAY_SEP(parent_id, _IRQSTEER_REGISTER_DISPATCHER, (;)) + +/* utility macros */ +#define UINT_TO_IRQSTEER(x) ((IRQSTEER_Type *)(x)) + +struct irqsteer_config { + uint32_t regmap_phys; + uint32_t regmap_size; + struct irqsteer_dispatcher *dispatchers; +}; + +struct irqsteer_dispatcher { + const struct device *dev; + /* which set of interrupts is the dispatcher in charge of? */ + uint32_t master_index; + /* which interrupt line is the dispatcher tied to? */ + uint32_t irq; +}; + +static struct irqsteer_dispatcher dispatchers[] = { + IRQSTEER_DECLARE_DISPATCHERS(DT_NODELABEL(irqsteer)) +}; + +/* used to convert system INTID to zephyr INTID */ +static int to_zephyr_irq(uint32_t regmap, uint32_t irq, + struct irqsteer_dispatcher *dispatcher) +{ + int i, idx; + + idx = irq; + + for (i = dispatcher->master_index - 1; i >= 0; i--) { + idx -= IRQSTEER_GetMasterIrqCount(UINT_TO_IRQSTEER(regmap), i); + } + + return irq_to_level_2(idx) | dispatcher->irq; +} + +/* used to convert master-relative INTID to system INTID */ +static int to_system_irq(uint32_t regmap, int irq, int master_index) +{ + int i; + + for (i = master_index - 1; i >= 0; i--) { + irq += IRQSTEER_GetMasterIrqCount(UINT_TO_IRQSTEER(regmap), i); + } + + return irq; +} + +/* used to convert zephyr INTID to system INTID */ +static int from_zephyr_irq(uint32_t regmap, uint32_t irq, uint32_t master_index) +{ + int i, idx; + + idx = irq; + + for (i = 0; i < master_index; i++) { + idx += IRQSTEER_GetMasterIrqCount(UINT_TO_IRQSTEER(regmap), i); + } + + return idx; +} + +void z_soc_irq_enable_disable(uint32_t irq, bool enable) +{ + uint32_t parent_irq; + int i, system_irq, level2_irq; + const struct irqsteer_config *cfg; + + if (irq_get_level(irq) == 1) { + /* LEVEL 1 interrupts are DSP direct */ + if (enable) { + z_xtensa_irq_enable(XTENSA_IRQ_NUMBER(irq)); + } else { + z_xtensa_irq_disable(XTENSA_IRQ_NUMBER(irq)); + } + return; + } + + parent_irq = irq_parent_level_2(irq); + level2_irq = irq_from_level_2(irq); + + /* find dispatcher responsible for this interrupt */ + for (i = 0; i < ARRAY_SIZE(dispatchers); i++) { + if (dispatchers[i].irq != parent_irq) { + continue; + } + + cfg = dispatchers[i].dev->config; + + system_irq = from_zephyr_irq(cfg->regmap_phys, level2_irq, + dispatchers[i].master_index); + + if (enable) { + IRQSTEER_EnableInterrupt(UINT_TO_IRQSTEER(cfg->regmap_phys), + system_irq); + } else { + IRQSTEER_DisableInterrupt(UINT_TO_IRQSTEER(cfg->regmap_phys), + system_irq); + } + + return; + } +} + +void z_soc_irq_enable(uint32_t irq) +{ + z_soc_irq_enable_disable(irq, true); +} + +void z_soc_irq_disable(uint32_t irq) +{ + z_soc_irq_enable_disable(irq, false); +} + +int z_soc_irq_is_enabled(unsigned int irq) +{ + uint32_t parent_irq; + int i, system_irq, level2_irq; + const struct irqsteer_config *cfg; + + if (irq_get_level(irq) == 1) { + /* LEVEL 1 interrupts are DSP direct */ + return z_xtensa_irq_is_enabled(XTENSA_IRQ_NUMBER(irq)); + } + + parent_irq = irq_parent_level_2(irq); + level2_irq = irq_from_level_2(irq); + + /* find dispatcher responsible for this interrupt */ + for (i = 0; i < ARRAY_SIZE(dispatchers); i++) { + if (dispatchers[i].irq != parent_irq) { + continue; + } + + cfg = dispatchers[i].dev->config; + + system_irq = from_zephyr_irq(cfg->regmap_phys, level2_irq, + dispatchers[i].master_index); + + return IRQSTEER_InterruptIsEnabled(UINT_TO_IRQSTEER(cfg->regmap_phys), system_irq); + } + + return false; +} + + +static void irqsteer_isr_dispatcher(const void *data) +{ + struct irqsteer_dispatcher *dispatcher; + const struct irqsteer_config *cfg; + uint32_t table_idx; + int system_irq, zephyr_irq, i; + uint64_t status; + + dispatcher = (struct irqsteer_dispatcher *)data; + cfg = dispatcher->dev->config; + + /* fetch master interrupts status */ + status = IRQSTEER_GetMasterInterruptsStatus(UINT_TO_IRQSTEER(cfg->regmap_phys), + dispatcher->master_index); + + for (i = 0; status; i++) { + /* if bit 0 is set then that means relative INTID i is asserted */ + if (status & 1) { + /* convert master-relative INTID to a system INTID */ + system_irq = to_system_irq(cfg->regmap_phys, i, + dispatcher->master_index); + + /* convert system INTID to a Zephyr INTID */ + zephyr_irq = to_zephyr_irq(cfg->regmap_phys, system_irq, dispatcher); + + /* compute index in the SW ISR table */ + table_idx = z_get_sw_isr_table_idx(zephyr_irq); + + /* call child's ISR */ + _sw_isr_table[table_idx].isr(_sw_isr_table[table_idx].arg); + } + + status >>= 1; + } +} + +static void irqsteer_enable_dispatchers(const struct device *dev) +{ + int i; + struct irqsteer_dispatcher *dispatcher; + const struct irqsteer_config *cfg; + + cfg = dev->config; + + for (i = 0; i < ARRAY_SIZE(dispatchers); i++) { + dispatcher = &dispatchers[i]; + + IRQSTEER_EnableMasterInterrupt(UINT_TO_IRQSTEER(cfg->regmap_phys), + dispatcher->irq); + + z_xtensa_irq_enable(XTENSA_IRQ_NUMBER(dispatcher->irq)); + } +} + +static int irqsteer_init(const struct device *dev) +{ + IRQSTEER_REGISTER_DISPATCHERS(DT_NODELABEL(irqsteer)); + + /* enable all dispatchers */ + irqsteer_enable_dispatchers(dev); + + return 0; +} + + +/* TODO: do we need to add support for MMU-based SoCs? */ +static struct irqsteer_config irqsteer_config = { + .regmap_phys = DT_REG_ADDR(DT_NODELABEL(irqsteer)), + .regmap_size = DT_REG_SIZE(DT_NODELABEL(irqsteer)), + .dispatchers = dispatchers, +}; + +/* assumption: only 1 IRQ_STEER instance */ +DEVICE_DT_INST_DEFINE(0, + &irqsteer_init, + NULL, + NULL, &irqsteer_config, + PRE_KERNEL_1, CONFIG_INTC_INIT_PRIORITY, + NULL); diff --git a/dts/bindings/interrupt-controller/nxp,irqsteer-intc.yaml b/dts/bindings/interrupt-controller/nxp,irqsteer-intc.yaml index 03b5d3b39e0..f3300ae6821 100644 --- a/dts/bindings/interrupt-controller/nxp,irqsteer-intc.yaml +++ b/dts/bindings/interrupt-controller/nxp,irqsteer-intc.yaml @@ -2,12 +2,8 @@ description: i.MX DSP interrupt controller compatible: "nxp,irqsteer-intc" -include: [interrupt-controller.yaml, base.yaml] +include: [base.yaml] properties: - "#interrupt-cells": - const: 2 - -interrupt-cells: - - irq - - priority + reg: + required: true diff --git a/dts/bindings/interrupt-controller/nxp,irqsteer-master.yaml b/dts/bindings/interrupt-controller/nxp,irqsteer-master.yaml new file mode 100644 index 00000000000..18c3fac42db --- /dev/null +++ b/dts/bindings/interrupt-controller/nxp,irqsteer-master.yaml @@ -0,0 +1,15 @@ +description: i.MX IRQ_STEER master + +compatible: "nxp,irqsteer-master" + +include: [interrupt-controller.yaml, base.yaml] + +properties: + "#interrupt-cells": + const: 1 + + reg: + required: true + +interrupt-cells: + - irq diff --git a/dts/xtensa/nxp/nxp_imx8m.dtsi b/dts/xtensa/nxp/nxp_imx8m.dtsi index 21a094c0461..70bfd500798 100644 --- a/dts/xtensa/nxp/nxp_imx8m.dtsi +++ b/dts/xtensa/nxp/nxp_imx8m.dtsi @@ -17,6 +17,16 @@ device_type = "cpu"; compatible = "cdns,tensilica-xtensa-lx6"; reg = <0>; + + #address-cells = <1>; + #size-cells = <0>; + + clic: interrupt-controller@0 { + compatible = "cdns,xtensa-core-intc"; + reg = <0>; + interrupt-controller; + #interrupt-cells = <3>; + }; }; }; @@ -33,14 +43,6 @@ }; soc { - interrupt-parent = <&irqsteer>; - - irqsteer: interrupt-controller { - compatible = "nxp,irqsteer-intc"; - interrupt-controller; - #interrupt-cells = <2>; - }; - ccm: ccm@30380000 { compatible = "nxp,imx-ccm"; reg = <0x30380000 DT_SIZE_K(64)>; @@ -67,7 +69,8 @@ /* TODO: This INTID is just a dummy * until we can support UART interrupts */ - interrupts = <29 0>; + interrupt-parent = <&clic>; + interrupts = <29 0 0>; clocks = <&ccm IMX_CCM_UART4_CLK 0x6c 24>; status = "disabled"; }; @@ -75,7 +78,8 @@ mailbox0: mailbox@30e70000 { compatible = "nxp,imx-mu"; reg = <0x30e70000 0x10000>; - interrupts = <7 0>; + interrupt-parent = <&clic>; + interrupts = <7 0 0>; rdc = <0>; status = "disabled"; }; From d3a0c769b01ebe3474969b55386557271479c879 Mon Sep 17 00:00:00 2001 From: Aleksander Wasaznik Date: Wed, 22 Nov 2023 14:37:30 +0100 Subject: [PATCH 0703/3723] Bluetooth: Shell: Workaround coverity uint comparation The current code triggers a false positive from the heuristic "Macro compares unsigned to 0". It's triggered because of a use of `IN_RANGE` that checks against the extremal values of a enum type. This patch replaces the use of `IN_RANGE` with an explicit list of the possible values of the enum. Fixes: https://github.com/zephyrproject-rtos/zephyr/issues/65575 Signed-off-by: Aleksander Wasaznik --- subsys/bluetooth/shell/bt.c | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/subsys/bluetooth/shell/bt.c b/subsys/bluetooth/shell/bt.c index ac1d78c44df..774ab6fc291 100644 --- a/subsys/bluetooth/shell/bt.c +++ b/subsys/bluetooth/shell/bt.c @@ -4071,9 +4071,12 @@ static int cmd_auth_passkey_notify(const struct shell *sh, err = 0; type = shell_strtoul(argv[1], 0, &err); - if (err || !IN_RANGE(type, BT_CONN_AUTH_KEYPRESS_ENTRY_STARTED, - BT_CONN_AUTH_KEYPRESS_ENTRY_COMPLETED)) { - shell_error(sh, " must be a value in range of enum bt_conn_auth_keypress"); + if (err || + (type != BT_CONN_AUTH_KEYPRESS_ENTRY_STARTED && + type != BT_CONN_AUTH_KEYPRESS_DIGIT_ENTERED && + type != BT_CONN_AUTH_KEYPRESS_DIGIT_ERASED && type != BT_CONN_AUTH_KEYPRESS_CLEARED && + type != BT_CONN_AUTH_KEYPRESS_ENTRY_COMPLETED)) { + shell_error(sh, " must be a value of enum bt_conn_auth_keypress"); return -EINVAL; } From 837698b93583853bcbe56e251fecd99b96888130 Mon Sep 17 00:00:00 2001 From: Marc Herbert Date: Thu, 30 Nov 2023 23:55:26 +0000 Subject: [PATCH 0704/3723] cmake/compiler/: drop ERROR_QUIET when looking for compiler --version Commit 40c2e08e8211 ("xcc/cmake: don't discard stderr; don't (ever!) use ERROR_QUIET") fixed xcc but the corresponding code is duplicated. Fix the duplicates too. See that commit for the issue description, longer commit message and rationale. Signed-off-by: Marc Herbert --- cmake/compiler/arcmwdt/generic.cmake | 4 ++-- cmake/compiler/armclang/generic.cmake | 4 ++-- cmake/compiler/gcc/generic.cmake | 6 +++--- 3 files changed, 7 insertions(+), 7 deletions(-) diff --git a/cmake/compiler/arcmwdt/generic.cmake b/cmake/compiler/arcmwdt/generic.cmake index c7ab586b3f3..d28ad81ea04 100644 --- a/cmake/compiler/arcmwdt/generic.cmake +++ b/cmake/compiler/arcmwdt/generic.cmake @@ -17,12 +17,12 @@ execute_process( COMMAND ${CMAKE_C_COMPILER} --version RESULT_VARIABLE ret OUTPUT_VARIABLE full_version_output - ERROR_QUIET ) if(ret) message(FATAL_ERROR "Executing the below command failed. Are permissions set correctly? - '${CMAKE_C_COMPILER} --version'" + '${CMAKE_C_COMPILER} --version' + ${full_version_output}" ) else() set(ARCMWDT_MIN_REQUIRED_VERS "2022.09") diff --git a/cmake/compiler/armclang/generic.cmake b/cmake/compiler/armclang/generic.cmake index 7804cd0e640..0f12abce247 100644 --- a/cmake/compiler/armclang/generic.cmake +++ b/cmake/compiler/armclang/generic.cmake @@ -28,13 +28,13 @@ endif() execute_process( COMMAND ${CMAKE_C_COMPILER} --version RESULT_VARIABLE ret - OUTPUT_QUIET - ERROR_QUIET + OUTPUT_VARIABLE stdoutput ) if(ret) message(FATAL_ERROR "Executing the below command failed. " "Are permissions set correctly? '${CMAKE_C_COMPILER} --version' " + "${stdoutput}" "And is the license setup correctly ?" ) endif() diff --git a/cmake/compiler/gcc/generic.cmake b/cmake/compiler/gcc/generic.cmake index ca96eb93809..c9cc643e3dd 100644 --- a/cmake/compiler/gcc/generic.cmake +++ b/cmake/compiler/gcc/generic.cmake @@ -18,12 +18,12 @@ endif() execute_process( COMMAND ${CMAKE_C_COMPILER} --version RESULT_VARIABLE ret - OUTPUT_QUIET - ERROR_QUIET + OUTPUT_VARIABLE stdoutput ) if(ret) message(FATAL_ERROR "Executing the below command failed. Are permissions set correctly? -'${CMAKE_C_COMPILER} --version' + ${CMAKE_C_COMPILER} --version + ${stdoutput} " ) endif() From b58bddb85c107fffa3f22206d613391e4a3f94ce Mon Sep 17 00:00:00 2001 From: Jukka Rissanen Date: Thu, 30 Nov 2023 21:31:02 +0200 Subject: [PATCH 0705/3723] net: socket: Add IPv4 multicast join/leave via socket Zephyr has its own multicast join/leave API but for interoperability, it is possible to use the multicast socket API and IP_ADD_MEMBERSHIP and IP_DROP_MEMBERSHIP socket options. Signed-off-by: Jukka Rissanen --- include/zephyr/net/socket.h | 10 +++++ subsys/net/lib/sockets/sockets.c | 74 ++++++++++++++++++++++++++++++++ 2 files changed, 84 insertions(+) diff --git a/include/zephyr/net/socket.h b/include/zephyr/net/socket.h index bdd0e0ad41e..a165e1fc101 100644 --- a/include/zephyr/net/socket.h +++ b/include/zephyr/net/socket.h @@ -1117,6 +1117,16 @@ struct in_pktinfo { /** sockopt: Set IPv4 multicast TTL value. */ #define IP_MULTICAST_TTL 33 +/** sockopt: Join IPv4 multicast group. */ +#define IP_ADD_MEMBERSHIP 35 +/** sockopt: Leave IPv4 multicast group. */ +#define IP_DROP_MEMBERSHIP 36 + +struct ip_mreqn { + struct in_addr imr_multiaddr; /* IP multicast group address */ + struct in_addr imr_address; /* IP address of local interface */ + int imr_ifindex; /* interface index */ +}; /* Socket options for IPPROTO_IPV6 level */ /** sockopt: Set the unicast hop limit for the socket. */ diff --git a/subsys/net/lib/sockets/sockets.c b/subsys/net/lib/sockets/sockets.c index 697c94e8808..c9b3affcf90 100644 --- a/subsys/net/lib/sockets/sockets.c +++ b/subsys/net/lib/sockets/sockets.c @@ -29,6 +29,8 @@ LOG_MODULE_REGISTER(net_sock, CONFIG_NET_SOCKETS_LOG_LEVEL); #include "socks.h" #endif +#include + #include "../../ip/net_stats.h" #include "sockets_internal.h" @@ -2642,6 +2644,62 @@ int z_vrfy_zsock_getsockopt(int sock, int level, int optname, #include #endif /* CONFIG_USERSPACE */ +static int ipv4_multicast_group(struct net_context *ctx, const void *optval, + socklen_t optlen, bool do_join) +{ + struct ip_mreqn *mreqn; + struct net_if *iface; + int ifindex, ret; + + if (optval == NULL || optlen != sizeof(struct ip_mreqn)) { + errno = EINVAL; + return -1; + } + + mreqn = (struct ip_mreqn *)optval; + + if (mreqn->imr_multiaddr.s_addr == INADDR_ANY) { + errno = EINVAL; + return -1; + } + + if (mreqn->imr_ifindex != 0) { + iface = net_if_get_by_index(mreqn->imr_ifindex); + } else { + ifindex = net_if_ipv4_addr_lookup_by_index(&mreqn->imr_address); + iface = net_if_get_by_index(ifindex); + } + + if (iface == NULL) { + /* Check if ctx has already an interface and if not, + * then select the default interface. + */ + if (ctx->iface <= 0) { + iface = net_if_get_default(); + } else { + iface = net_if_get_by_index(ctx->iface); + } + + if (iface == NULL) { + errno = EINVAL; + return -1; + } + } + + if (do_join) { + ret = net_ipv4_igmp_join(iface, &mreqn->imr_multiaddr, NULL); + } else { + ret = net_ipv4_igmp_leave(iface, &mreqn->imr_multiaddr); + } + + if (ret < 0) { + errno = -ret; + return -1; + } + + return 0; +} + int zsock_setsockopt_ctx(struct net_context *ctx, int level, int optname, const void *optval, socklen_t optlen) { @@ -2947,6 +3005,22 @@ int zsock_setsockopt_ctx(struct net_context *ctx, int level, int optname, } return 0; + + case IP_ADD_MEMBERSHIP: + if (IS_ENABLED(CONFIG_NET_IPV4)) { + return ipv4_multicast_group(ctx, optval, + optlen, true); + } + + break; + + case IP_DROP_MEMBERSHIP: + if (IS_ENABLED(CONFIG_NET_IPV4)) { + return ipv4_multicast_group(ctx, optval, + optlen, false); + } + + break; } break; From 36f5cfae2c37f8181d23c09764b48cc350687bb9 Mon Sep 17 00:00:00 2001 From: Jukka Rissanen Date: Fri, 1 Dec 2023 11:29:25 +0200 Subject: [PATCH 0706/3723] tests: net: igmp: Add socket based join/leave tests Make sure the IP_ADD_MEMBERSHIP and IP_DROP_MEMBERSHIP work as expected. Signed-off-by: Jukka Rissanen --- tests/net/igmp/prj.conf | 1 + tests/net/igmp/src/main.c | 153 ++++++++++++++++++++++++++++++++++++++ 2 files changed, 154 insertions(+) diff --git a/tests/net/igmp/prj.conf b/tests/net/igmp/prj.conf index b9119257232..4f9f9e59769 100644 --- a/tests/net/igmp/prj.conf +++ b/tests/net/igmp/prj.conf @@ -20,3 +20,4 @@ CONFIG_NET_MGMT_EVENT=y CONFIG_NET_IF_UNICAST_IPV4_ADDR_COUNT=2 CONFIG_NET_IF_MCAST_IPV4_ADDR_COUNT=2 CONFIG_NET_IF_MAX_IPV4_COUNT=2 +CONFIG_NET_SOCKETS=y diff --git a/tests/net/igmp/src/main.c b/tests/net/igmp/src/main.c index ca43c33d164..d6f3ce7e7cd 100644 --- a/tests/net/igmp/src/main.c +++ b/tests/net/igmp/src/main.c @@ -27,6 +27,7 @@ LOG_MODULE_REGISTER(net_test, CONFIG_NET_IPV4_LOG_LEVEL); #include #include #include +#include #include @@ -45,6 +46,7 @@ LOG_MODULE_REGISTER(net_test, CONFIG_NET_IPV4_LOG_LEVEL); static struct in_addr my_addr = { { { 192, 0, 2, 1 } } }; static struct in_addr mcast_addr = { { { 224, 0, 2, 63 } } }; +static struct in_addr any_addr = INADDR_ANY_INIT; static struct net_if *net_iface; static bool is_group_joined; @@ -355,4 +357,155 @@ ZTEST(net_igmp, test_igmp_verify_catch_join) verify_leave_group(); } +static void socket_group_with_address(struct in_addr *local_addr, bool do_join) +{ + struct ip_mreqn mreqn = { 0 }; + int option; + int ret, fd; + + if (do_join) { + option = IP_ADD_MEMBERSHIP; + } else { + option = IP_DROP_MEMBERSHIP; + } + + fd = zsock_socket(AF_INET, SOCK_DGRAM, 0); + zassert_true(fd >= 0, "Cannot get socket (%d)", -errno); + + ret = zsock_setsockopt(fd, IPPROTO_IP, option, + NULL, sizeof(mreqn)); + zassert_true(ret == -1 && errno == EINVAL, + "Incorrect return value (%d)", -errno); + + ret = zsock_setsockopt(fd, IPPROTO_IP, option, + (void *)&mreqn, 1); + zassert_true(ret == -1 && errno == EINVAL, + "Incorrect return value (%d)", -errno); + + /* First try with empty mreqn */ + ret = zsock_setsockopt(fd, IPPROTO_IP, option, + (void *)&mreqn, sizeof(mreqn)); + zassert_true(ret == -1 && errno == EINVAL, + "Incorrect return value (%d)", -errno); + + memcpy(&mreqn.imr_address, local_addr, sizeof(mreqn.imr_address)); + memcpy(&mreqn.imr_multiaddr, &mcast_addr, sizeof(mreqn.imr_multiaddr)); + + ret = zsock_setsockopt(fd, IPPROTO_IP, option, + (void *)&mreqn, sizeof(mreqn)); + + if (do_join) { + if (ignore_already) { + zassert_true(ret == 0 || ret == -EALREADY, + "Cannot join IPv4 multicast group (%d)", + -errno); + } else { + zassert_equal(ret, 0, + "Cannot join IPv4 multicast group (%d) " + "with local addr %s", + -errno, net_sprint_ipv4_addr(local_addr)); + } + } else { + zassert_equal(ret, 0, "Cannot leave IPv4 multicast group (%d)", + -errno); + + if (IS_ENABLED(CONFIG_NET_TC_THREAD_PREEMPTIVE)) { + /* Let the network stack to proceed */ + k_msleep(THREAD_SLEEP); + } else { + k_yield(); + } + } + + zsock_close(fd); + + /* Let the network stack to proceed */ + k_msleep(THREAD_SLEEP); +} + +static void socket_group_with_index(struct in_addr *local_addr, bool do_join) +{ + struct ip_mreqn mreqn = { 0 }; + int option; + int ret, fd; + + if (do_join) { + option = IP_ADD_MEMBERSHIP; + } else { + option = IP_DROP_MEMBERSHIP; + } + + fd = zsock_socket(AF_INET, SOCK_DGRAM, 0); + zassert_true(fd >= 0, "Cannot get socket (%d)", -errno); + + mreqn.imr_ifindex = net_if_ipv4_addr_lookup_by_index(local_addr); + memcpy(&mreqn.imr_multiaddr, &mcast_addr, sizeof(mreqn.imr_multiaddr)); + + ret = zsock_setsockopt(fd, IPPROTO_IP, option, + (void *)&mreqn, sizeof(mreqn)); + + if (do_join) { + if (ignore_already) { + zassert_true(ret == 0 || ret == -EALREADY, + "Cannot join IPv4 multicast group (%d)", + -errno); + } else { + zassert_equal(ret, 0, + "Cannot join IPv4 multicast group (%d)", + -errno); + } + } else { + zassert_equal(ret, 0, "Cannot leave IPv4 multicast group (%d)", + -errno); + + if (IS_ENABLED(CONFIG_NET_TC_THREAD_PREEMPTIVE)) { + /* Let the network stack to proceed */ + k_msleep(THREAD_SLEEP); + } else { + k_yield(); + } + } + + zsock_close(fd); + + /* Let the network stack to proceed */ + k_msleep(THREAD_SLEEP); +} + +static void socket_join_group_with_address(struct in_addr *addr) +{ + socket_group_with_address(addr, true); +} + +static void socket_leave_group_with_address(struct in_addr *addr) +{ + socket_group_with_address(addr, false); +} + +static void socket_join_group_with_index(struct in_addr *addr) +{ + socket_group_with_index(addr, true); +} + +static void socket_leave_group_with_index(struct in_addr *addr) +{ + socket_group_with_index(addr, false); +} + +ZTEST_USER(net_igmp, test_socket_catch_join_with_address) +{ + socket_join_group_with_address(&any_addr); + socket_leave_group_with_address(&any_addr); + socket_join_group_with_address(&my_addr); + socket_leave_group_with_address(&my_addr); +} + +ZTEST_USER(net_igmp, test_socket_catch_join_with_index) +{ + socket_join_group_with_index(&any_addr); + socket_leave_group_with_index(&any_addr); + socket_join_group_with_index(&my_addr); + socket_leave_group_with_index(&my_addr); +} + ZTEST_SUITE(net_igmp, NULL, igmp_setup, NULL, NULL, igmp_teardown); From bed63764d67e3e9ed87844ef7bceec30e759b1ca Mon Sep 17 00:00:00 2001 From: Jukka Rissanen Date: Fri, 1 Dec 2023 11:49:33 +0200 Subject: [PATCH 0707/3723] net: socket: Add IPv6 multicast join/leave via socket Zephyr has its own multicast join/leave API but for interoperability, it is possible to use the multicast socket API and IPV6_ADD_MEMBERSHIP and IPV6_DROP_MEMBERSHIP socket options. Signed-off-by: Jukka Rissanen --- include/zephyr/net/socket.h | 14 +++++++ subsys/net/lib/sockets/sockets.c | 69 ++++++++++++++++++++++++++++++++ 2 files changed, 83 insertions(+) diff --git a/include/zephyr/net/socket.h b/include/zephyr/net/socket.h index a165e1fc101..5336f11e886 100644 --- a/include/zephyr/net/socket.h +++ b/include/zephyr/net/socket.h @@ -1135,6 +1135,20 @@ struct ip_mreqn { /** sockopt: Set the multicast hop limit for the socket. */ #define IPV6_MULTICAST_HOPS 18 +/** sockopt: Join IPv6 multicast group. */ +#define IPV6_ADD_MEMBERSHIP 20 + +/** sockopt: Leave IPv6 multicast group. */ +#define IPV6_DROP_MEMBERSHIP 21 + +struct ipv6_mreq { + /* IPv6 multicast address of group */ + struct in6_addr ipv6mr_multiaddr; + + /* Interface index of the local IPv6 address */ + int ipv6mr_ifindex; +}; + /** sockopt: Don't support IPv4 access */ #define IPV6_V6ONLY 26 diff --git a/subsys/net/lib/sockets/sockets.c b/subsys/net/lib/sockets/sockets.c index c9b3affcf90..56a456aa89b 100644 --- a/subsys/net/lib/sockets/sockets.c +++ b/subsys/net/lib/sockets/sockets.c @@ -30,6 +30,7 @@ LOG_MODULE_REGISTER(net_sock, CONFIG_NET_SOCKETS_LOG_LEVEL); #endif #include +#include "../../ip/ipv6.h" #include "../../ip/net_stats.h" @@ -2700,6 +2701,58 @@ static int ipv4_multicast_group(struct net_context *ctx, const void *optval, return 0; } +static int ipv6_multicast_group(struct net_context *ctx, const void *optval, + socklen_t optlen, bool do_join) +{ + struct ipv6_mreq *mreq; + struct net_if *iface; + int ret; + + if (optval == NULL || optlen != sizeof(struct ipv6_mreq)) { + errno = EINVAL; + return -1; + } + + mreq = (struct ipv6_mreq *)optval; + + if (memcmp(&mreq->ipv6mr_multiaddr, + net_ipv6_unspecified_address(), + sizeof(mreq->ipv6mr_multiaddr)) == 0) { + errno = EINVAL; + return -1; + } + + iface = net_if_get_by_index(mreq->ipv6mr_ifindex); + if (iface == NULL) { + /* Check if ctx has already an interface and if not, + * then select the default interface. + */ + if (ctx->iface <= 0) { + iface = net_if_get_default(); + } else { + iface = net_if_get_by_index(ctx->iface); + } + + if (iface == NULL) { + errno = ENOENT; + return -1; + } + } + + if (do_join) { + ret = net_ipv6_mld_join(iface, &mreq->ipv6mr_multiaddr); + } else { + ret = net_ipv6_mld_leave(iface, &mreq->ipv6mr_multiaddr); + } + + if (ret < 0) { + errno = -ret; + return -1; + } + + return 0; +} + int zsock_setsockopt_ctx(struct net_context *ctx, int level, int optname, const void *optval, socklen_t optlen) { @@ -3095,6 +3148,22 @@ int zsock_setsockopt_ctx(struct net_context *ctx, int level, int optname, } return 0; + + case IPV6_ADD_MEMBERSHIP: + if (IS_ENABLED(CONFIG_NET_IPV6)) { + return ipv6_multicast_group(ctx, optval, + optlen, true); + } + + break; + + case IPV6_DROP_MEMBERSHIP: + if (IS_ENABLED(CONFIG_NET_IPV6)) { + return ipv6_multicast_group(ctx, optval, + optlen, false); + } + + break; } break; From 0bc1423335937bca42150622c72eb07d10011d7d Mon Sep 17 00:00:00 2001 From: Jukka Rissanen Date: Fri, 1 Dec 2023 11:50:31 +0200 Subject: [PATCH 0708/3723] tests: net: mld: Add socket based join/leave tests Make sure the IPV6_ADD_MEMBERSHIP and IPV4_DROP_MEMBERSHIP work as expected. Signed-off-by: Jukka Rissanen --- tests/net/mld/prj.conf | 1 + tests/net/mld/src/main.c | 85 ++++++++++++++++++++++++++++++++++++++++ 2 files changed, 86 insertions(+) diff --git a/tests/net/mld/prj.conf b/tests/net/mld/prj.conf index 5eeab7f81ec..3ce6478f4c8 100644 --- a/tests/net/mld/prj.conf +++ b/tests/net/mld/prj.conf @@ -22,3 +22,4 @@ CONFIG_NET_MGMT=y CONFIG_NET_MGMT_EVENT=y CONFIG_NET_IF_UNICAST_IPV6_ADDR_COUNT=4 CONFIG_NET_IF_MCAST_IPV6_ADDR_COUNT=4 +CONFIG_NET_SOCKETS=y diff --git a/tests/net/mld/src/main.c b/tests/net/mld/src/main.c index d374b207cbd..171418b21a8 100644 --- a/tests/net/mld/src/main.c +++ b/tests/net/mld/src/main.c @@ -26,6 +26,7 @@ LOG_MODULE_REGISTER(net_test, CONFIG_NET_IPV6_LOG_LEVEL); #include #include #include +#include #include @@ -589,4 +590,88 @@ ZTEST(net_mld_test_suite, test_no_mld_flag) net_if_flag_clear(net_iface, NET_IF_IPV6_NO_MLD); } +static void socket_group_with_index(const struct in6_addr *local_addr, bool do_join) +{ + struct ipv6_mreq mreq = { 0 }; + int option; + int ret, fd; + + if (do_join) { + option = IPV6_ADD_MEMBERSHIP; + } else { + option = IPV6_DROP_MEMBERSHIP; + } + + fd = zsock_socket(AF_INET6, SOCK_DGRAM, 0); + zassert_true(fd >= 0, "Cannot get socket (%d)", -errno); + + ret = zsock_setsockopt(fd, IPPROTO_IPV6, option, + NULL, sizeof(mreq)); + zassert_true(ret == -1 && errno == EINVAL, + "Incorrect return value (%d)", -errno); + + ret = zsock_setsockopt(fd, IPPROTO_IPV6, option, + (void *)&mreq, 1); + zassert_true(ret == -1 && errno == EINVAL, + "Incorrect return value (%d)", -errno); + + /* First try with empty mreq */ + ret = zsock_setsockopt(fd, IPPROTO_IPV6, option, + (void *)&mreq, sizeof(mreq)); + zassert_true(ret == -1 && errno == EINVAL, + "Incorrect return value (%d)", -errno); + + mreq.ipv6mr_ifindex = net_if_ipv6_addr_lookup_by_index(local_addr); + memcpy(&mreq.ipv6mr_multiaddr, &mcast_addr, + sizeof(mreq.ipv6mr_multiaddr)); + + ret = zsock_setsockopt(fd, IPPROTO_IPV6, option, + (void *)&mreq, sizeof(mreq)); + + if (do_join) { + if (ignore_already) { + zassert_true(ret == 0 || ret == -EALREADY, + "Cannot join IPv6 multicast group (%d)", + -errno); + } else { + zassert_equal(ret, 0, + "Cannot join IPv6 multicast group (%d)", + -errno); + } + } else { + zassert_equal(ret, 0, "Cannot leave IPv6 multicast group (%d)", + -errno); + + if (IS_ENABLED(CONFIG_NET_TC_THREAD_PREEMPTIVE)) { + /* Let the network stack to proceed */ + k_msleep(THREAD_SLEEP); + } else { + k_yield(); + } + } + + zsock_close(fd); + + /* Let the network stack to proceed */ + k_msleep(THREAD_SLEEP); +} + +static void socket_join_group_with_index(const struct in6_addr *addr) +{ + socket_group_with_index(addr, true); +} + +static void socket_leave_group_with_index(const struct in6_addr *addr) +{ + socket_group_with_index(addr, false); +} + +ZTEST_USER(net_mld_test_suite, test_socket_catch_join_with_index) +{ + socket_join_group_with_index(net_ipv6_unspecified_address()); + socket_leave_group_with_index(net_ipv6_unspecified_address()); + socket_join_group_with_index(&my_addr); + socket_leave_group_with_index(&my_addr); +} + ZTEST_SUITE(net_mld_test_suite, NULL, test_mld_setup, NULL, NULL, NULL); From 1aac715c234899256ccc19b410de4dd1ba16732c Mon Sep 17 00:00:00 2001 From: Jukka Rissanen Date: Mon, 4 Dec 2023 16:13:19 +0200 Subject: [PATCH 0709/3723] doc: release: 3.6: Add info for IPv4/6 multicast socket options Add information about the IPv4 multicast IP_ADD_MEMBERSHIP and IP_DROP_MEMBERSHIP socket options. Add information about the IPv6 multicast IPV6_ADD_MEMBERSHIP and IPV6_DROP_MEMBERSHIP socket options. Signed-off-by: Jukka Rissanen --- doc/releases/release-notes-3.6.rst | 3 +++ 1 file changed, 3 insertions(+) diff --git a/doc/releases/release-notes-3.6.rst b/doc/releases/release-notes-3.6.rst index 18394f75ac9..2ec4afe0c57 100644 --- a/doc/releases/release-notes-3.6.rst +++ b/doc/releases/release-notes-3.6.rst @@ -234,6 +234,9 @@ Networking * Sockets: + * Added support for IPv4 multicast ``IP_ADD_MEMBERSHIP`` and ``IP_DROP_MEMBERSHIP`` socket options. + * Added support for IPv6 multicast ``IPV6_ADD_MEMBERSHIP`` and ``IPV6_DROP_MEMBERSHIP`` socket options. + * TCP: * TFTP: From bc97d1ead04f39cea0d9c20159ff8e8f6c576713 Mon Sep 17 00:00:00 2001 From: Szymon Janc Date: Fri, 1 Dec 2023 11:11:34 +0100 Subject: [PATCH 0710/3723] bluetooth: tester: Add support for flags in BTP_GAP_PADV_CREATE_SYNC This allows for more tuning regarding Periodic Advertising Sync behavior. Required by GAP/PADV/PASE/BV-01-C qualification test case. Signed-off-by: Szymon Janc --- tests/bluetooth/tester/src/btp/btp_gap.h | 3 +++ tests/bluetooth/tester/src/btp_gap.c | 10 +++++++++- 2 files changed, 12 insertions(+), 1 deletion(-) diff --git a/tests/bluetooth/tester/src/btp/btp_gap.h b/tests/bluetooth/tester/src/btp/btp_gap.h index a727ffce4e4..fd7826aab0f 100644 --- a/tests/bluetooth/tester/src/btp/btp_gap.h +++ b/tests/bluetooth/tester/src/btp/btp_gap.h @@ -286,6 +286,9 @@ struct btp_gap_padv_set_data_cmd { uint8_t data[]; } __packed; +#define BTP_GAP_PADV_CREATE_SYNC_FLAG_REPORTS_DISABLED 0x01 +#define BTP_GAP_PADV_CREATE_SYNC_FLAG_FILTER_DUPLICATES 0x02 + #define BTP_GAP_PADV_CREATE_SYNC 0x26 struct btp_gap_padv_create_sync_cmd { bt_addr_le_t address; diff --git a/tests/bluetooth/tester/src/btp_gap.c b/tests/bluetooth/tester/src/btp_gap.c index fd5307fcc37..db179c8f2f1 100644 --- a/tests/bluetooth/tester/src/btp_gap.c +++ b/tests/bluetooth/tester/src/btp_gap.c @@ -1592,11 +1592,19 @@ static uint8_t padv_create_sync(const void *cmd, uint16_t cmd_len, struct bt_le_per_adv_sync_param create_params = {0}; bt_addr_le_copy(&create_params.addr, &cp->address); - create_params.options = BT_LE_PER_ADV_SYNC_OPT_FILTER_DUPLICATE; + create_params.options = BT_LE_PER_ADV_SYNC_OPT_NONE; create_params.sid = cp->advertiser_sid; create_params.skip = cp->skip; create_params.timeout = cp->sync_timeout; + if (cp->flags & BTP_GAP_PADV_CREATE_SYNC_FLAG_REPORTS_DISABLED) { + create_params.options |= BT_LE_PER_ADV_SYNC_OPT_REPORTING_INITIALLY_DISABLED; + } + + if (cp->flags & BTP_GAP_PADV_CREATE_SYNC_FLAG_FILTER_DUPLICATES) { + create_params.options |= BT_LE_PER_ADV_SYNC_OPT_FILTER_DUPLICATE; + } + err = tester_gap_padv_create_sync(&create_params); if (err != 0) { return BTP_STATUS_FAILED; From ae15a059a8bda1eb46c26193e79b87b34b65d288 Mon Sep 17 00:00:00 2001 From: Szymon Janc Date: Fri, 1 Dec 2023 11:23:43 +0100 Subject: [PATCH 0711/3723] bluetooth: tester: Fix missing LE to CPU convertion in BTP SYnc timeout and skip are 16 bit values and shall be converted to CPU order before use. Signed-off-by: Szymon Janc --- tests/bluetooth/tester/src/btp_gap.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/tests/bluetooth/tester/src/btp_gap.c b/tests/bluetooth/tester/src/btp_gap.c index db179c8f2f1..7f923571885 100644 --- a/tests/bluetooth/tester/src/btp_gap.c +++ b/tests/bluetooth/tester/src/btp_gap.c @@ -1594,8 +1594,8 @@ static uint8_t padv_create_sync(const void *cmd, uint16_t cmd_len, bt_addr_le_copy(&create_params.addr, &cp->address); create_params.options = BT_LE_PER_ADV_SYNC_OPT_NONE; create_params.sid = cp->advertiser_sid; - create_params.skip = cp->skip; - create_params.timeout = cp->sync_timeout; + create_params.skip = sys_le16_to_cpu(cp->skip); + create_params.timeout = sys_le16_to_cpu(cp->sync_timeout); if (cp->flags & BTP_GAP_PADV_CREATE_SYNC_FLAG_REPORTS_DISABLED) { create_params.options |= BT_LE_PER_ADV_SYNC_OPT_REPORTING_INITIALLY_DISABLED; From ce45c0ac573a011fc68d03b93dc2d8bcfada96d0 Mon Sep 17 00:00:00 2001 From: Szymon Janc Date: Fri, 1 Dec 2023 13:15:01 +0100 Subject: [PATCH 0712/3723] tester: bluetooth: Add support for reporting sync status Implements sync established and sync lost BTP events. This was affecting GAP/PADV/PASE/BV-01-C test case. Signed-off-by: Szymon Janc --- tests/bluetooth/tester/src/btp_gap.c | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+) diff --git a/tests/bluetooth/tester/src/btp_gap.c b/tests/bluetooth/tester/src/btp_gap.c index 7f923571885..93958720d30 100644 --- a/tests/bluetooth/tester/src/btp_gap.c +++ b/tests/bluetooth/tester/src/btp_gap.c @@ -1355,6 +1355,17 @@ static void pa_sync_synced_cb(struct bt_le_per_adv_sync *sync, struct bt_le_per_adv_sync_synced_info *info) { LOG_DBG(""); + + if (sync == pa_sync) { + struct btp_gap_ev_periodic_sync_established_ev ev; + + bt_addr_le_copy(&ev.address, info->addr); + ev.sync_handle = sys_cpu_to_le16(sync->handle); + ev.status = 0; + + tester_event(BTP_SERVICE_ID_GAP, BTP_GAP_EV_PERIODIC_SYNC_ESTABLISHED, + &ev, sizeof(ev)); + } } static void pa_sync_terminated_cb(struct bt_le_per_adv_sync *sync, @@ -1363,8 +1374,16 @@ static void pa_sync_terminated_cb(struct bt_le_per_adv_sync *sync, LOG_DBG(""); if (sync == pa_sync) { + struct btp_gap_ev_periodic_sync_lost_ev ev; + LOG_DBG("PA sync lost with reason %u", info->reason); pa_sync = NULL; + + ev.sync_handle = sys_cpu_to_le16(sync->handle); + ev.reason = info->reason; + + tester_event(BTP_SERVICE_ID_GAP, BTP_GAP_EV_PERIODIC_SYNC_LOST, + &ev, sizeof(ev)); } } From 753602159964ce9e0725b6515df499c66fe91655 Mon Sep 17 00:00:00 2001 From: Andrej Butok Date: Mon, 4 Dec 2023 13:41:51 +0100 Subject: [PATCH 0713/3723] doc: blobs: fix double 'command' Fix double 'command' in the "Fetching blobs" chapter. Signed-off-by: Andrej Butok --- doc/contribute/bin_blobs.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/doc/contribute/bin_blobs.rst b/doc/contribute/bin_blobs.rst index 661007927a0..efc25b609e1 100644 --- a/doc/contribute/bin_blobs.rst +++ b/doc/contribute/bin_blobs.rst @@ -43,7 +43,7 @@ Fetching blobs ============== Blobs are fetched from official third-party sources by the :ref:`west blobs -command ` command. +` command. The blobs themselves must be specified in the :ref:`module.yml ` files included in separate Zephyr :ref:`module repositories From 0290ae92b2bf999a31ad2ab40920e03d44fbf670 Mon Sep 17 00:00:00 2001 From: Andrei Emeltchenko Date: Mon, 4 Dec 2023 15:02:32 +0200 Subject: [PATCH 0714/3723] tests: acpi: Fix getting APIC id Fixes accessing wrong memory. Fixes: #66085 Signed-off-by: Andrei Emeltchenko --- tests/arch/x86/info/src/acpi.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/arch/x86/info/src/acpi.c b/tests/arch/x86/info/src/acpi.c index b09bc8d5bb5..35ee5f460c3 100644 --- a/tests/arch/x86/info/src/acpi.c +++ b/tests/arch/x86/info/src/acpi.c @@ -130,7 +130,7 @@ void acpi(void) for (int i = 0; i < nr_cpus; ++i) { struct acpi_madt_local_apic *cpu = acpi_local_apic_get(i); - printk("\tCPU #%d: APIC ID 0x%02x\n", i, cpu[i].Id); + printk("\tCPU #%d: APIC ID 0x%02x\n", i, cpu->Id); } } From e13c2cd693a40efce00e53b718fc58f1649177f8 Mon Sep 17 00:00:00 2001 From: Wojciech Sipak Date: Mon, 4 Dec 2023 15:56:50 +0100 Subject: [PATCH 0715/3723] boards: arm: rzt2m_starterkit: fix documentation rendering As reported in #66094, the documentation used section headers wrongly. Fixes #66094. Signed-off-by: Wojciech Sipak --- boards/arm/rzt2m_starterkit/doc/index.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/boards/arm/rzt2m_starterkit/doc/index.rst b/boards/arm/rzt2m_starterkit/doc/index.rst index e965585f6cb..1fa6a13b6f9 100644 --- a/boards/arm/rzt2m_starterkit/doc/index.rst +++ b/boards/arm/rzt2m_starterkit/doc/index.rst @@ -1,7 +1,7 @@ .. _rzt2m_starterkit: Renesas Starter Kit+ for RZ/T2M -=============================== +############################### Overview ******** From 506ede0c5958648c35e4e552c9ff100086a68ca9 Mon Sep 17 00:00:00 2001 From: Fabio Baltieri Date: Mon, 27 Nov 2023 16:33:15 +0000 Subject: [PATCH 0716/3723] input: kbd_matrix: fix a debouncing timing issue Fix a debouncing timing unit mismatch when comparing us to ms. Signed-off-by: Fabio Baltieri --- drivers/input/input_kbd_matrix.c | 4 ++-- include/zephyr/input/input_kbd_matrix.h | 8 ++++---- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/drivers/input/input_kbd_matrix.c b/drivers/input/input_kbd_matrix.c index 921117f4663..7f708e7a0e9 100644 --- a/drivers/input/input_kbd_matrix.c +++ b/drivers/input/input_kbd_matrix.c @@ -166,10 +166,10 @@ static void input_kbd_matrix_update_state(const struct device *dev) uint8_t scan_clk_cycle = data->scan_clk_cycle[scan_cyc_idx]; /* Convert the clock cycle differences to usec */ - uint32_t debt = k_cyc_to_us_floor32(cycles_now - scan_clk_cycle); + uint32_t deb_t_us = k_cyc_to_us_floor32(cycles_now - scan_clk_cycle); /* Does the key requires more time to be debounced? */ - if (debt < (row_bit ? cfg->debounce_down_ms : cfg->debounce_up_ms)) { + if (deb_t_us < (row_bit ? cfg->debounce_down_us : cfg->debounce_up_us)) { /* Need more time to debounce */ continue; } diff --git a/include/zephyr/input/input_kbd_matrix.h b/include/zephyr/input/input_kbd_matrix.h index 7df8ad96e45..93f16963afe 100644 --- a/include/zephyr/input/input_kbd_matrix.h +++ b/include/zephyr/input/input_kbd_matrix.h @@ -84,8 +84,8 @@ struct input_kbd_matrix_common_config { uint8_t col_size; uint32_t poll_period_us; uint32_t poll_timeout_ms; - uint32_t debounce_down_ms; - uint32_t debounce_up_ms; + uint32_t debounce_down_us; + uint32_t debounce_up_us; uint32_t settle_time_us; bool ghostkey_check; @@ -155,8 +155,8 @@ struct input_kbd_matrix_common_config { .col_size = _col_size, \ .poll_period_us = DT_PROP(node_id, poll_period_ms) * USEC_PER_MSEC, \ .poll_timeout_ms = DT_PROP(node_id, poll_timeout_ms), \ - .debounce_down_ms = DT_PROP(node_id, debounce_down_ms), \ - .debounce_up_ms = DT_PROP(node_id, debounce_up_ms), \ + .debounce_down_us = DT_PROP(node_id, debounce_down_ms) * USEC_PER_MSEC, \ + .debounce_up_us = DT_PROP(node_id, debounce_up_ms) * USEC_PER_MSEC, \ .settle_time_us = DT_PROP(node_id, settle_time_us), \ .ghostkey_check = !DT_PROP(node_id, no_ghostkey_check), \ \ From 71e5c66ea4368144ac271fcd0aa3c7cc5c8b037c Mon Sep 17 00:00:00 2001 From: Fabio Baltieri Date: Mon, 27 Nov 2023 17:26:17 +0000 Subject: [PATCH 0717/3723] input: kbd_matrix: fix a typing issue for a cycle counter scan_clk_cycle is used to store values from k_cycle_get_32(), it very much needs to be a uint32_t. Signed-off-by: Fabio Baltieri --- drivers/input/input_kbd_matrix.c | 2 +- include/zephyr/input/input_kbd_matrix.h | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/input/input_kbd_matrix.c b/drivers/input/input_kbd_matrix.c index 7f708e7a0e9..1d8a3a6e1ce 100644 --- a/drivers/input/input_kbd_matrix.c +++ b/drivers/input/input_kbd_matrix.c @@ -163,7 +163,7 @@ static void input_kbd_matrix_update_state(const struct device *dev) uint8_t cyc_idx = c * cfg->row_size + r; uint8_t scan_cyc_idx = cfg->scan_cycle_idx[cyc_idx]; - uint8_t scan_clk_cycle = data->scan_clk_cycle[scan_cyc_idx]; + uint32_t scan_clk_cycle = data->scan_clk_cycle[scan_cyc_idx]; /* Convert the clock cycle differences to usec */ uint32_t deb_t_us = k_cyc_to_us_floor32(cycles_now - scan_clk_cycle); diff --git a/include/zephyr/input/input_kbd_matrix.h b/include/zephyr/input/input_kbd_matrix.h index 93f16963afe..996aba12ff1 100644 --- a/include/zephyr/input/input_kbd_matrix.h +++ b/include/zephyr/input/input_kbd_matrix.h @@ -205,7 +205,7 @@ struct input_kbd_matrix_common_config { */ struct input_kbd_matrix_common_data { /* Track previous cycles, used for debouncing. */ - uint8_t scan_clk_cycle[INPUT_KBD_MATRIX_SCAN_OCURRENCES]; + uint32_t scan_clk_cycle[INPUT_KBD_MATRIX_SCAN_OCURRENCES]; uint8_t scan_cycles_idx; struct k_sem poll_lock; From f4bf74e4029647533b7e8553e1aafa4b979b2fbc Mon Sep 17 00:00:00 2001 From: Fabio Baltieri Date: Mon, 27 Nov 2023 18:35:06 +0000 Subject: [PATCH 0718/3723] input: kbd_matrix: clear unstable state correctly on release The state variable to tracking the unstable state of a key is currently being cleared based on the bit value, which means that on release it's not being cleared at all. Fix that by clearing using the bit mask instead. Signed-off-by: Fabio Baltieri --- drivers/input/input_kbd_matrix.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/input/input_kbd_matrix.c b/drivers/input/input_kbd_matrix.c index 1d8a3a6e1ce..51092f530e4 100644 --- a/drivers/input/input_kbd_matrix.c +++ b/drivers/input/input_kbd_matrix.c @@ -174,7 +174,7 @@ static void input_kbd_matrix_update_state(const struct device *dev) continue; } - cfg->matrix_unstable_state[c] &= ~row_bit; + cfg->matrix_unstable_state[c] &= ~mask; /* Check if there was a change in the stable state */ if ((cfg->matrix_stable_state[c] & mask) == row_bit) { From 56d73a8b0c1ec5f4c77acc48addbe83e14d52654 Mon Sep 17 00:00:00 2001 From: Fabio Baltieri Date: Sat, 25 Nov 2023 18:19:54 +0000 Subject: [PATCH 0719/3723] input: kbd_matrix: always poll if poll_timeout_ms is 0 Tweak the polling mode so that the driver never exit polling mode if poll_timeout_ms is 0. This is useful if the specific driver does not support idle mode. Signed-off-by: Fabio Baltieri --- drivers/input/input_kbd_matrix.c | 15 +++++++++++++-- dts/bindings/input/kbd-matrix-common.yaml | 4 ++-- 2 files changed, 15 insertions(+), 4 deletions(-) diff --git a/drivers/input/input_kbd_matrix.c b/drivers/input/input_kbd_matrix.c index 51092f530e4..eb969acdbb7 100644 --- a/drivers/input/input_kbd_matrix.c +++ b/drivers/input/input_kbd_matrix.c @@ -224,6 +224,17 @@ static bool input_kbd_matrix_check_key_events(const struct device *dev) return key_pressed; } +static k_timepoint_t input_kbd_matrix_poll_timeout(const struct device *dev) +{ + const struct input_kbd_matrix_common_config *cfg = dev->config; + + if (cfg->poll_timeout_ms == 0) { + return sys_timepoint_calc(K_FOREVER); + } + + return sys_timepoint_calc(K_MSEC(cfg->poll_timeout_ms)); +} + static void input_kbd_matrix_poll(const struct device *dev) { const struct input_kbd_matrix_common_config *cfg = dev->config; @@ -232,13 +243,13 @@ static void input_kbd_matrix_poll(const struct device *dev) uint32_t cycles_diff; uint32_t wait_period_us; - poll_time_end = sys_timepoint_calc(K_MSEC(cfg->poll_timeout_ms)); + poll_time_end = input_kbd_matrix_poll_timeout(dev); while (true) { uint32_t start_period_cycles = k_cycle_get_32(); if (input_kbd_matrix_check_key_events(dev)) { - poll_time_end = sys_timepoint_calc(K_MSEC(cfg->poll_timeout_ms)); + poll_time_end = input_kbd_matrix_poll_timeout(dev); } else if (sys_timepoint_expired(poll_time_end)) { break; } diff --git a/dts/bindings/input/kbd-matrix-common.yaml b/dts/bindings/input/kbd-matrix-common.yaml index e399bd4431f..25b70d162db 100644 --- a/dts/bindings/input/kbd-matrix-common.yaml +++ b/dts/bindings/input/kbd-matrix-common.yaml @@ -20,8 +20,8 @@ properties: type: int default: 5 description: | - Defines the poll period in msecs between between matrix scans. Defaults - to 5ms if unsepcified. + Defines the poll period in msecs between between matrix scans, set to 0 + to never exit poll mode. Defaults to 5ms if unspecified. poll-timeout-ms: type: int From 3862c227d4dfdb0264597072c7a5ea5986ce6c08 Mon Sep 17 00:00:00 2001 From: Fabio Baltieri Date: Fri, 17 Nov 2023 09:59:31 +0000 Subject: [PATCH 0720/3723] input: gpio_kbd_matrix: add poll and scan mode support Add a poll and scan mode for the driver. If any of these are set, the driver does not use the GPIO interrupts to detect when the matrix has to switch to polling mode. Instead, it keeps polling it all the time, either by enabling all the columns and poll the rows for activity, or just keep scanning all the time. Poll mode is useful if the specific SoC used does not support GPIO interrupt on all the row GPIOs at the same time, scan mode if it does not even support selecting all the columns at the same time. Signed-off-by: Fabio Baltieri --- drivers/input/input_gpio_kbd_matrix.c | 99 ++++++++++++++++++++++--- dts/bindings/input/gpio-kbd-matrix.yaml | 18 ++++- 2 files changed, 104 insertions(+), 13 deletions(-) diff --git a/drivers/input/input_gpio_kbd_matrix.c b/drivers/input/input_gpio_kbd_matrix.c index 2c0d22bbaaa..988320e61f1 100644 --- a/drivers/input/input_gpio_kbd_matrix.c +++ b/drivers/input/input_gpio_kbd_matrix.c @@ -22,8 +22,13 @@ struct gpio_kbd_matrix_config { struct input_kbd_matrix_common_config common; const struct gpio_dt_spec *row_gpio; const struct gpio_dt_spec *col_gpio; + struct gpio_callback *gpio_cb; - gpio_callback_handler_t handler; + gpio_callback_handler_t gpio_cb_handler; + + struct k_work_delayable *idle_poll_dwork; + k_work_handler_t idle_poll_handler; + bool col_drive_inactive; }; @@ -109,6 +114,20 @@ static kbd_row_t gpio_kbd_matrix_read_row(const struct device *dev) return val; } +static __maybe_unused void gpio_kbd_matrix_idle_poll_handler(const struct device *dev) +{ + const struct gpio_kbd_matrix_config *cfg = dev->config; + const struct input_kbd_matrix_common_config *common = &cfg->common; + + if (gpio_kbd_matrix_read_row(dev) == 0) { + k_work_reschedule(cfg->idle_poll_dwork, + K_USEC(common->poll_period_us)); + return; + } + + input_kbd_matrix_poll_start(dev); +} + static void gpio_kbd_matrix_set_detect_mode(const struct device *dev, bool enabled) { const struct gpio_kbd_matrix_config *cfg = dev->config; @@ -116,6 +135,14 @@ static void gpio_kbd_matrix_set_detect_mode(const struct device *dev, bool enabl unsigned int flags = enabled ? GPIO_INT_EDGE_BOTH : GPIO_INT_DISABLE; int ret; + if (cfg->idle_poll_dwork != NULL) { + if (enabled) { + k_work_reschedule(cfg->idle_poll_dwork, + K_USEC(common->poll_period_us)); + } + return; + } + for (int i = 0; i < common->row_size; i++) { const struct gpio_dt_spec *gpio = &cfg->row_gpio[i]; @@ -143,6 +170,17 @@ static bool gpio_kbd_matrix_is_gpio_coherent( return true; } +static bool gpio_kbd_continuous_scan_mode(const struct device *dev) +{ + const struct gpio_kbd_matrix_config *cfg = dev->config; + + if (cfg->gpio_cb == NULL && cfg->idle_poll_dwork == NULL) { + return true; + } + + return false; +} + static int gpio_kbd_matrix_init(const struct device *dev) { const struct gpio_kbd_matrix_config *cfg = dev->config; @@ -172,7 +210,7 @@ static int gpio_kbd_matrix_init(const struct device *dev) for (i = 0; i < common->row_size; i++) { const struct gpio_dt_spec *gpio = &cfg->row_gpio[i]; - struct gpio_callback *gpio_cb = &cfg->gpio_cb[i]; + struct gpio_callback *gpio_cb; if (!gpio_is_ready_dt(gpio)) { LOG_ERR("%s is not ready", gpio->port->name); @@ -185,7 +223,13 @@ static int gpio_kbd_matrix_init(const struct device *dev) return ret; } - gpio_init_callback(gpio_cb, cfg->handler, BIT(gpio->pin)); + if (cfg->gpio_cb == NULL) { + continue; + } + gpio_cb = &cfg->gpio_cb[i]; + + gpio_init_callback(gpio_cb, cfg->gpio_cb_handler, + BIT(gpio->pin)); ret = gpio_add_callback_dt(gpio, gpio_cb); if (ret < 0) { @@ -194,6 +238,11 @@ static int gpio_kbd_matrix_init(const struct device *dev) } } + if (cfg->idle_poll_dwork != NULL) { + k_work_init_delayable(cfg->idle_poll_dwork, + cfg->idle_poll_handler); + } + data->direct_read = gpio_kbd_matrix_is_gpio_coherent( cfg->row_gpio, common->row_size); @@ -205,7 +254,16 @@ static int gpio_kbd_matrix_init(const struct device *dev) LOG_DBG("direct_read: %d direct_write: %d", data->direct_read, data->direct_write); - return input_kbd_matrix_common_init(dev); + ret = input_kbd_matrix_common_init(dev); + if (ret != 0) { + return ret; + } + + if (gpio_kbd_continuous_scan_mode(dev)) { + input_kbd_matrix_poll_start(dev); + } + + return 0; } static const struct input_kbd_matrix_api gpio_kbd_matrix_api = { @@ -220,12 +278,6 @@ static const struct input_kbd_matrix_api gpio_kbd_matrix_api = { INPUT_KBD_MATRIX_DT_INST_DEFINE_ROW_COL( \ n, DT_INST_PROP_LEN(n, row_gpios), DT_INST_PROP_LEN(n, col_gpios)); \ \ - static void gpio_kbd_matrix_cb_##n(const struct device *gpio_dev, \ - struct gpio_callback *cb, uint32_t pins) \ - { \ - input_kbd_matrix_poll_start(DEVICE_DT_INST_GET(n)); \ - } \ - \ static const struct gpio_dt_spec gpio_kbd_matrix_row_gpio_##n[DT_INST_PROP_LEN( \ n, row_gpios)] = { \ DT_INST_FOREACH_PROP_ELEM_SEP(n, row_gpios, GPIO_DT_SPEC_GET_BY_IDX, (,)) \ @@ -234,7 +286,26 @@ static const struct input_kbd_matrix_api gpio_kbd_matrix_api = { n, col_gpios)] = { \ DT_INST_FOREACH_PROP_ELEM_SEP(n, col_gpios, GPIO_DT_SPEC_GET_BY_IDX, (,)) \ }; \ + \ + IF_ENABLED(DT_INST_ENUM_HAS_VALUE(n, idle_mode, interrupt), ( \ static struct gpio_callback gpio_kbd_matrix_gpio_cb_##n[DT_INST_PROP_LEN(n, row_gpios)];\ + static void gpio_kbd_matrix_cb_##n(const struct device *gpio_dev, \ + struct gpio_callback *cb, uint32_t pins) \ + { \ + input_kbd_matrix_poll_start(DEVICE_DT_INST_GET(n)); \ + } \ + )) \ + IF_ENABLED(DT_INST_ENUM_HAS_VALUE(n, idle_mode, poll), ( \ + static struct k_work_delayable gpio_kbd_matrix_idle_poll_dwork_##n; \ + static void gpio_kbd_matrix_idle_poll_handler_##n(struct k_work *work) \ + { \ + gpio_kbd_matrix_idle_poll_handler(DEVICE_DT_INST_GET(n)); \ + } \ + )) \ + IF_ENABLED(DT_INST_ENUM_HAS_VALUE(n, idle_mode, scan), ( \ + BUILD_ASSERT(DT_INST_PROP(n, poll_timeout_ms) == 0, \ + "poll-timeout-ms must be set to 0 for scan mode to work correctly"); \ + )) \ \ static const struct gpio_kbd_matrix_config gpio_kbd_matrix_cfg_##n = { \ .common = INPUT_KBD_MATRIX_DT_INST_COMMON_CONFIG_INIT_ROW_COL( \ @@ -242,8 +313,14 @@ static const struct input_kbd_matrix_api gpio_kbd_matrix_api = { DT_INST_PROP_LEN(n, row_gpios), DT_INST_PROP_LEN(n, col_gpios)), \ .row_gpio = gpio_kbd_matrix_row_gpio_##n, \ .col_gpio = gpio_kbd_matrix_col_gpio_##n, \ + IF_ENABLED(DT_INST_ENUM_HAS_VALUE(n, idle_mode, interrupt), ( \ .gpio_cb = gpio_kbd_matrix_gpio_cb_##n, \ - .handler = gpio_kbd_matrix_cb_##n, \ + .gpio_cb_handler = gpio_kbd_matrix_cb_##n, \ + )) \ + IF_ENABLED(DT_INST_ENUM_HAS_VALUE(n, idle_mode, poll), ( \ + .idle_poll_dwork = &gpio_kbd_matrix_idle_poll_dwork_##n, \ + .idle_poll_handler = gpio_kbd_matrix_idle_poll_handler_##n, \ + )) \ .col_drive_inactive = DT_INST_PROP(n, col_drive_inactive), \ }; \ \ diff --git a/dts/bindings/input/gpio-kbd-matrix.yaml b/dts/bindings/input/gpio-kbd-matrix.yaml index 7cdc07dd4dd..c8bad93d767 100644 --- a/dts/bindings/input/gpio-kbd-matrix.yaml +++ b/dts/bindings/input/gpio-kbd-matrix.yaml @@ -31,8 +31,9 @@ properties: type: phandle-array required: true description: | - GPIO for the keyboard matrix rows, up to 8 different GPIOs. All row GPIO - pins must have interrupt support. + GPIO for the keyboard matrix rows, up to 8 different GPIOs. All row GPIO + pins must have interrupt support if idle-mode is set to "interrupt" + (default). col-gpios: type: phandle-array @@ -48,3 +49,16 @@ properties: description: | If enabled, unselected column GPIOs will be driven to inactive state. Default to configure unselected column GPIOs to high impedance. + + idle-mode: + type: string + default: "interrupt" + enum: + - "interrupt" + - "poll" + - "scan" + description: | + Controls the driver behavior on idle, "interrupt" waits for a new key + press using GPIO interrupts on the row lines, "poll" periodically polls + the row lines with all the columns selected, "scan" just keep scanning + the matrix continuously, requires "poll-timeout-ms" to be set to 0. From 7ce03134f547f49eefe0a8ba97222275092e15f9 Mon Sep 17 00:00:00 2001 From: Fabio Baltieri Date: Fri, 17 Nov 2023 10:22:25 +0000 Subject: [PATCH 0721/3723] tests: build_all: input: add few more gpio-kbd-matrix cases The driver has some non trivial macro setup, add another two test cases so those gets build tested as well. Signed-off-by: Fabio Baltieri --- tests/drivers/build_all/input/app.overlay | 24 ++++++++++++++++++++++- 1 file changed, 23 insertions(+), 1 deletion(-) diff --git a/tests/drivers/build_all/input/app.overlay b/tests/drivers/build_all/input/app.overlay index cf826cfe4fa..50f9b508387 100644 --- a/tests/drivers/build_all/input/app.overlay +++ b/tests/drivers/build_all/input/app.overlay @@ -26,7 +26,7 @@ }; }; - kbd-matrix { + kbd-matrix-0 { compatible = "gpio-kbd-matrix"; row-gpios = <&test_gpio 0 (GPIO_PULL_UP | GPIO_ACTIVE_LOW)>, <&test_gpio 1 (GPIO_PULL_UP | GPIO_ACTIVE_LOW)>; @@ -35,6 +35,28 @@ <&test_gpio 4 GPIO_ACTIVE_LOW>; }; + kbd-matrix-1 { + compatible = "gpio-kbd-matrix"; + row-gpios = <&test_gpio 0 (GPIO_PULL_DOWN | GPIO_ACTIVE_HIGH)>, + <&test_gpio 1 (GPIO_PULL_DOWN | GPIO_ACTIVE_HIGH)>, + <&test_gpio 2 (GPIO_PULL_DOWN | GPIO_ACTIVE_HIGH)>; + col-gpios = <&test_gpio 3 GPIO_ACTIVE_HIGH>, + <&test_gpio 4 GPIO_ACTIVE_HIGH>; + col-drive-inactive; + idle-mode = "poll"; + }; + + kbd-matrix-2 { + compatible = "gpio-kbd-matrix"; + row-gpios = <&test_gpio 0 (GPIO_PULL_DOWN | GPIO_ACTIVE_HIGH)>, + <&test_gpio 1 (GPIO_PULL_DOWN | GPIO_ACTIVE_HIGH)>, + <&test_gpio 2 (GPIO_PULL_DOWN | GPIO_ACTIVE_HIGH)>; + col-gpios = <&test_gpio 3 GPIO_ACTIVE_HIGH>, + <&test_gpio 4 GPIO_ACTIVE_HIGH>; + poll-timeout-ms = <0>; + idle-mode = "scan"; + }; + qdec-gpio { compatible = "gpio-qdec"; gpios = <&test_gpio 0 0>, <&test_gpio 1 0>; From 8bcc4f2c12348a8042770bcbc04583203a32b4c9 Mon Sep 17 00:00:00 2001 From: Zhang Peng Date: Fri, 3 Nov 2023 13:28:31 +0800 Subject: [PATCH 0722/3723] boards: xtensa: adsp: add support for imx8ulp board Add support for i.MX8ULP board by defining defconfig, board configuration and device tree. Signed-off-by: Zhang Peng --- boards/xtensa/nxp_adsp_imx8ulp/Kconfig.board | 7 +++++++ .../xtensa/nxp_adsp_imx8ulp/Kconfig.defconfig | 10 ++++++++++ boards/xtensa/nxp_adsp_imx8ulp/board.cmake | 6 ++++++ .../nxp_adsp_imx8ulp/nxp_adsp_imx8ulp.dts | 18 ++++++++++++++++++ .../nxp_adsp_imx8ulp/nxp_adsp_imx8ulp.yaml | 10 ++++++++++ .../nxp_adsp_imx8ulp_defconfig | 11 +++++++++++ 6 files changed, 62 insertions(+) create mode 100644 boards/xtensa/nxp_adsp_imx8ulp/Kconfig.board create mode 100644 boards/xtensa/nxp_adsp_imx8ulp/Kconfig.defconfig create mode 100644 boards/xtensa/nxp_adsp_imx8ulp/board.cmake create mode 100644 boards/xtensa/nxp_adsp_imx8ulp/nxp_adsp_imx8ulp.dts create mode 100644 boards/xtensa/nxp_adsp_imx8ulp/nxp_adsp_imx8ulp.yaml create mode 100644 boards/xtensa/nxp_adsp_imx8ulp/nxp_adsp_imx8ulp_defconfig diff --git a/boards/xtensa/nxp_adsp_imx8ulp/Kconfig.board b/boards/xtensa/nxp_adsp_imx8ulp/Kconfig.board new file mode 100644 index 00000000000..d9a1ff65953 --- /dev/null +++ b/boards/xtensa/nxp_adsp_imx8ulp/Kconfig.board @@ -0,0 +1,7 @@ +# Xtensa board configuration + +# Copyright (c) 2023 NXP +# SPDX-License-Identifier: Apache-2.0 + +config BOARD_NXP_ADSP_IMX8ULP + bool "NXP ADSP i.MX8ULP" diff --git a/boards/xtensa/nxp_adsp_imx8ulp/Kconfig.defconfig b/boards/xtensa/nxp_adsp_imx8ulp/Kconfig.defconfig new file mode 100644 index 00000000000..431515d5961 --- /dev/null +++ b/boards/xtensa/nxp_adsp_imx8ulp/Kconfig.defconfig @@ -0,0 +1,10 @@ +# Copyright (c) 2023 NXP +# +# SPDX-License-Identifier: Apache-2.0 + +if BOARD_NXP_ADSP_IMX8ULP + +config BOARD + default "nxp_adsp_imx8ulp" + +endif # BOARD_NXP_ADSP_IMX8ULP diff --git a/boards/xtensa/nxp_adsp_imx8ulp/board.cmake b/boards/xtensa/nxp_adsp_imx8ulp/board.cmake new file mode 100644 index 00000000000..e05fbc891e5 --- /dev/null +++ b/boards/xtensa/nxp_adsp_imx8ulp/board.cmake @@ -0,0 +1,6 @@ +# SPDX-License-Identifier: Apache-2.0 + +board_set_flasher_ifnset(misc-flasher) +board_finalize_runner_args(misc-flasher) + +board_set_rimage_target(imx8ulp) diff --git a/boards/xtensa/nxp_adsp_imx8ulp/nxp_adsp_imx8ulp.dts b/boards/xtensa/nxp_adsp_imx8ulp/nxp_adsp_imx8ulp.dts new file mode 100644 index 00000000000..d584097cb03 --- /dev/null +++ b/boards/xtensa/nxp_adsp_imx8ulp/nxp_adsp_imx8ulp.dts @@ -0,0 +1,18 @@ +/* + * Copyright (c) 2023 NXP + * + * SPDX-License-Identifier: Apache-2.0 + */ + +/dts-v1/; + +#include + +/ { + model = "nxp_adsp_imx8ulp"; + compatible = "nxp"; + + chosen { + zephyr,sram = &sram0; + }; +}; diff --git a/boards/xtensa/nxp_adsp_imx8ulp/nxp_adsp_imx8ulp.yaml b/boards/xtensa/nxp_adsp_imx8ulp/nxp_adsp_imx8ulp.yaml new file mode 100644 index 00000000000..e71105631da --- /dev/null +++ b/boards/xtensa/nxp_adsp_imx8ulp/nxp_adsp_imx8ulp.yaml @@ -0,0 +1,10 @@ +identifier: nxp_adsp_imx8ulp +name: i.MX8ULP DSP +type: mcu +arch: xtensa +toolchain: + - zephyr +testing: + only_tags: + - kernel + - sof diff --git a/boards/xtensa/nxp_adsp_imx8ulp/nxp_adsp_imx8ulp_defconfig b/boards/xtensa/nxp_adsp_imx8ulp/nxp_adsp_imx8ulp_defconfig new file mode 100644 index 00000000000..cc1911c615c --- /dev/null +++ b/boards/xtensa/nxp_adsp_imx8ulp/nxp_adsp_imx8ulp_defconfig @@ -0,0 +1,11 @@ +# SPDX-License-Identifier: Apache-2.0 + +CONFIG_SOC_SERIES_NXP_IMX8ULP=y +CONFIG_SOC_NXP_IMX8ULP=y +CONFIG_BOARD_NXP_ADSP_IMX8ULP=y + +CONFIG_BUILD_OUTPUT_BIN=n + +CONFIG_DYNAMIC_INTERRUPTS=y + +CONFIG_LOG=y From a7b7364c4ef8e2786d8b5da5e634b879444858ae Mon Sep 17 00:00:00 2001 From: Zhang Peng Date: Fri, 3 Nov 2023 13:30:50 +0800 Subject: [PATCH 0723/3723] dts/xtensa/nxp: Add dtsi for imx8ulp Add file nxp_imx8ulp.dtsi for imx8ulp Signed-off-by: Zhang Peng --- dts/xtensa/nxp/nxp_imx8ulp.dtsi | 33 +++++++++++++++++++++++++++++++++ 1 file changed, 33 insertions(+) create mode 100644 dts/xtensa/nxp/nxp_imx8ulp.dtsi diff --git a/dts/xtensa/nxp/nxp_imx8ulp.dtsi b/dts/xtensa/nxp/nxp_imx8ulp.dtsi new file mode 100644 index 00000000000..71f3de1958b --- /dev/null +++ b/dts/xtensa/nxp/nxp_imx8ulp.dtsi @@ -0,0 +1,33 @@ +/* + * Copyright (c) 2023 NXP + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include +#include + +/ { + cpus { + #address-cells = <1>; + #size-cells = <0>; + + cpu0: cpu@0 { + device_type = "cpu"; + compatible = "cdns,tensilica-xtensa-lx7"; + reg = <0>; + }; + }; + + sram0: memory@8e000000 { + device_type = "memory"; + compatible = "mmio-sram"; + reg = <0x8e000000 DT_SIZE_K(512)>; + }; + + sram1: memory@8e800000 { + device_type = "memory"; + compatible = "mmio-sram"; + reg = <0x8e800000 DT_SIZE_K(512)>; + }; +}; From 9dd10c2f3ceca6984a64d6888e794b2b185efd19 Mon Sep 17 00:00:00 2001 From: Zhang Peng Date: Fri, 3 Nov 2023 13:33:04 +0800 Subject: [PATCH 0724/3723] soc: xtensa: adsp: add support for NXP ADSP for i.MX8ULP Add support for i.MX8ULP target. Signed-off-by: Zhang Peng --- .../nxp_adsp/imx8ulp/Kconfig.defconfig.series | 30 + soc/xtensa/nxp_adsp/imx8ulp/Kconfig.series | 15 + soc/xtensa/nxp_adsp/imx8ulp/Kconfig.soc | 11 + .../imx8ulp/include/_soc_inthandlers.h | 393 +++++++++++++ soc/xtensa/nxp_adsp/imx8ulp/include/memory.h | 159 ++++++ soc/xtensa/nxp_adsp/imx8ulp/linker.ld | 517 ++++++++++++++++++ 6 files changed, 1125 insertions(+) create mode 100644 soc/xtensa/nxp_adsp/imx8ulp/Kconfig.defconfig.series create mode 100644 soc/xtensa/nxp_adsp/imx8ulp/Kconfig.series create mode 100644 soc/xtensa/nxp_adsp/imx8ulp/Kconfig.soc create mode 100644 soc/xtensa/nxp_adsp/imx8ulp/include/_soc_inthandlers.h create mode 100644 soc/xtensa/nxp_adsp/imx8ulp/include/memory.h create mode 100644 soc/xtensa/nxp_adsp/imx8ulp/linker.ld diff --git a/soc/xtensa/nxp_adsp/imx8ulp/Kconfig.defconfig.series b/soc/xtensa/nxp_adsp/imx8ulp/Kconfig.defconfig.series new file mode 100644 index 00000000000..ebd9377660b --- /dev/null +++ b/soc/xtensa/nxp_adsp/imx8ulp/Kconfig.defconfig.series @@ -0,0 +1,30 @@ +# Copyright (c) 2023 NXP +# SPDX-License-Identifier: Apache-2.0 + +if SOC_SERIES_NXP_IMX8ULP + +config SOC_SERIES + string + default "imx8ulp" + +config SOC_TOOLCHAIN_NAME + string + default "nxp_imx8ulp_adsp" + +config SOC + string + default "nxp_imx8ulp" + +config SYS_CLOCK_HW_CYCLES_PER_SEC + default 528000000 if XTENSA_TIMER + +config SYS_CLOCK_TICKS_PER_SEC + default 50000 + +config DCACHE_LINE_SIZE + default 128 + +config GEN_IRQ_VECTOR_TABLE + default n + +endif # SOC_SERIES_NXP_IMX8ULP diff --git a/soc/xtensa/nxp_adsp/imx8ulp/Kconfig.series b/soc/xtensa/nxp_adsp/imx8ulp/Kconfig.series new file mode 100644 index 00000000000..34e9b3a1a1d --- /dev/null +++ b/soc/xtensa/nxp_adsp/imx8ulp/Kconfig.series @@ -0,0 +1,15 @@ +# Copyright (c) 2023 NXP +# SPDX-License-Identifier: Apache-2.0 + +config SOC_SERIES_NXP_IMX8ULP + bool "NXP i.MX8ULP Audio DSP Series" + select SOC_FAMILY_NXP_ADSP + select XTENSA + select XTENSA_HAL if ("$(ZEPHYR_TOOLCHAIN_VARIANT)" != "xcc" && "$(ZEPHYR_TOOLCHAIN_VARIANT)" != "xt-clang") + select XTENSA_RESET_VECTOR + select XTENSA_USE_CORE_CRT1 + select ATOMIC_OPERATIONS_BUILTIN + select GEN_ISR_TABLES + select XTENSA_SMALL_VECTOR_TABLE_ENTRY + help + Enable support for NXP i.MX8ULP Audio DSP diff --git a/soc/xtensa/nxp_adsp/imx8ulp/Kconfig.soc b/soc/xtensa/nxp_adsp/imx8ulp/Kconfig.soc new file mode 100644 index 00000000000..b90fada22d4 --- /dev/null +++ b/soc/xtensa/nxp_adsp/imx8ulp/Kconfig.soc @@ -0,0 +1,11 @@ +# Copyright (c) 2023 NXP +# SPDX-License-Identifier: Apache-2.0 + +choice + prompt "NXP i.MX8ULP Audio DSP Selection" + depends on SOC_SERIES_NXP_IMX8ULP + + config SOC_NXP_IMX8ULP + bool "NXP i.MX8ULP Audio DSP" + +endchoice diff --git a/soc/xtensa/nxp_adsp/imx8ulp/include/_soc_inthandlers.h b/soc/xtensa/nxp_adsp/imx8ulp/include/_soc_inthandlers.h new file mode 100644 index 00000000000..28129b65758 --- /dev/null +++ b/soc/xtensa/nxp_adsp/imx8ulp/include/_soc_inthandlers.h @@ -0,0 +1,393 @@ +/* + * Copyright (c) 2023 NXP + * + * SPDX-License-Identifier: Apache-2.0 + */ +/* + * THIS FILE WAS AUTOMATICALLY GENERATED. DO NOT EDIT. + * + * Functions here are designed to produce efficient code to + * search an Xtensa bitmask of interrupts, inspecting only those bits + * declared to be associated with a given interrupt level. Each + * dispatcher will handle exactly one flagged interrupt, in numerical + * order (low bits first) and will return a mask of that bit that can + * then be cleared by the calling code. Unrecognized bits for the + * level will invoke an error handler. + */ + +#include +#include +#include + +#if !defined(XCHAL_INT0_LEVEL) || XCHAL_INT0_LEVEL != 5 +#error core-isa.h interrupt level does not match dispatcher! +#endif +#if !defined(XCHAL_INT1_LEVEL) || XCHAL_INT1_LEVEL != 2 +#error core-isa.h interrupt level does not match dispatcher! +#endif +#if !defined(XCHAL_INT2_LEVEL) || XCHAL_INT2_LEVEL != 2 +#error core-isa.h interrupt level does not match dispatcher! +#endif +#if !defined(XCHAL_INT16_LEVEL) || XCHAL_INT16_LEVEL != 2 +#error core-isa.h interrupt level does not match dispatcher! +#endif +#if !defined(XCHAL_INT17_LEVEL) || XCHAL_INT17_LEVEL != 2 +#error core-isa.h interrupt level does not match dispatcher! +#endif +#if !defined(XCHAL_INT18_LEVEL) || XCHAL_INT18_LEVEL != 2 +#error core-isa.h interrupt level does not match dispatcher! +#endif +#if !defined(XCHAL_INT19_LEVEL) || XCHAL_INT19_LEVEL != 2 +#error core-isa.h interrupt level does not match dispatcher! +#endif +#if !defined(XCHAL_INT20_LEVEL) || XCHAL_INT20_LEVEL != 2 +#error core-isa.h interrupt level does not match dispatcher! +#endif +#if !defined(XCHAL_INT21_LEVEL) || XCHAL_INT21_LEVEL != 2 +#error core-isa.h interrupt level does not match dispatcher! +#endif +#if !defined(XCHAL_INT22_LEVEL) || XCHAL_INT22_LEVEL != 2 +#error core-isa.h interrupt level does not match dispatcher! +#endif +#if !defined(XCHAL_INT23_LEVEL) || XCHAL_INT23_LEVEL != 2 +#error core-isa.h interrupt level does not match dispatcher! +#endif +#if !defined(XCHAL_INT3_LEVEL) || XCHAL_INT3_LEVEL != 3 +#error core-isa.h interrupt level does not match dispatcher! +#endif +#if !defined(XCHAL_INT4_LEVEL) || XCHAL_INT4_LEVEL != 3 +#error core-isa.h interrupt level does not match dispatcher! +#endif +#if !defined(XCHAL_INT5_LEVEL) || XCHAL_INT5_LEVEL != 3 +#error core-isa.h interrupt level does not match dispatcher! +#endif +#if !defined(XCHAL_INT24_LEVEL) || XCHAL_INT24_LEVEL != 3 +#error core-isa.h interrupt level does not match dispatcher! +#endif +#if !defined(XCHAL_INT25_LEVEL) || XCHAL_INT25_LEVEL != 3 +#error core-isa.h interrupt level does not match dispatcher! +#endif +#if !defined(XCHAL_INT26_LEVEL) || XCHAL_INT26_LEVEL != 3 +#error core-isa.h interrupt level does not match dispatcher! +#endif +#if !defined(XCHAL_INT27_LEVEL) || XCHAL_INT27_LEVEL != 3 +#error core-isa.h interrupt level does not match dispatcher! +#endif +#if !defined(XCHAL_INT28_LEVEL) || XCHAL_INT28_LEVEL != 3 +#error core-isa.h interrupt level does not match dispatcher! +#endif +#if !defined(XCHAL_INT29_LEVEL) || XCHAL_INT29_LEVEL != 3 +#error core-isa.h interrupt level does not match dispatcher! +#endif +#if !defined(XCHAL_INT30_LEVEL) || XCHAL_INT30_LEVEL != 3 +#error core-isa.h interrupt level does not match dispatcher! +#endif +#if !defined(XCHAL_INT31_LEVEL) || XCHAL_INT31_LEVEL != 3 +#error core-isa.h interrupt level does not match dispatcher! +#endif +#if !defined(XCHAL_INT6_LEVEL) || XCHAL_INT6_LEVEL != 1 +#error core-isa.h interrupt level does not match dispatcher! +#endif +#if !defined(XCHAL_INT7_LEVEL) || XCHAL_INT7_LEVEL != 1 +#error core-isa.h interrupt level does not match dispatcher! +#endif +#if !defined(XCHAL_INT8_LEVEL) || XCHAL_INT8_LEVEL != 1 +#error core-isa.h interrupt level does not match dispatcher! +#endif +#if !defined(XCHAL_INT9_LEVEL) || XCHAL_INT9_LEVEL != 1 +#error core-isa.h interrupt level does not match dispatcher! +#endif +#if !defined(XCHAL_INT10_LEVEL) || XCHAL_INT10_LEVEL != 1 +#error core-isa.h interrupt level does not match dispatcher! +#endif +#if !defined(XCHAL_INT11_LEVEL) || XCHAL_INT11_LEVEL != 1 +#error core-isa.h interrupt level does not match dispatcher! +#endif +#if !defined(XCHAL_INT12_LEVEL) || XCHAL_INT12_LEVEL != 1 +#error core-isa.h interrupt level does not match dispatcher! +#endif +#if !defined(XCHAL_INT13_LEVEL) || XCHAL_INT13_LEVEL != 1 +#error core-isa.h interrupt level does not match dispatcher! +#endif +#if !defined(XCHAL_INT14_LEVEL) || XCHAL_INT14_LEVEL != 1 +#error core-isa.h interrupt level does not match dispatcher! +#endif +#if !defined(XCHAL_INT15_LEVEL) || XCHAL_INT15_LEVEL != 1 +#error core-isa.h interrupt level does not match dispatcher! +#endif + +static inline int _xtensa_handle_one_int5(unsigned int mask) +{ + int irq; + + if (mask & BIT(0)) { + mask = BIT(0); + irq = 0; + goto handle_irq; + } + return 0; +handle_irq: + _sw_isr_table[irq].isr(_sw_isr_table[irq].arg); + return mask; +} + +static inline int _xtensa_handle_one_int2(unsigned int mask) +{ + int irq; + + if (mask & 0x70006) { + if (mask & 0x6) { + if (mask & BIT(1)) { + mask = BIT(1); + irq = 1; + goto handle_irq; + } + if (mask & BIT(2)) { + mask = BIT(2); + irq = 2; + goto handle_irq; + } + } else { + if (mask & BIT(16)) { + mask = BIT(16); + irq = 16; + goto handle_irq; + } + if (mask & BIT(17)) { + mask = BIT(17); + irq = 17; + goto handle_irq; + } + if (mask & BIT(18)) { + mask = BIT(18); + irq = 18; + goto handle_irq; + } + } + } else { + if (mask & 0x180000) { + if (mask & BIT(19)) { + mask = BIT(19); + irq = 19; + goto handle_irq; + } + if (mask & BIT(20)) { + mask = BIT(20); + irq = 20; + goto handle_irq; + } + } else { + if (mask & BIT(21)) { + mask = BIT(21); + irq = 21; + goto handle_irq; + } + if (mask & BIT(22)) { + mask = BIT(22); + irq = 22; + goto handle_irq; + } + if (mask & BIT(23)) { + mask = BIT(23); + irq = 23; + goto handle_irq; + } + } + } + return 0; +handle_irq: + _sw_isr_table[irq].isr(_sw_isr_table[irq].arg); + return mask; +} + +static inline int _xtensa_handle_one_int3(unsigned int mask) +{ + int irq; + + if (mask & 0x3000038) { + if (mask & 0x18) { + if (mask & BIT(3)) { + mask = BIT(3); + irq = 3; + goto handle_irq; + } + if (mask & BIT(4)) { + mask = BIT(4); + irq = 4; + goto handle_irq; + } + } else { + if (mask & BIT(5)) { + mask = BIT(5); + irq = 5; + goto handle_irq; + } + if (mask & BIT(24)) { + mask = BIT(24); + irq = 24; + goto handle_irq; + } + if (mask & BIT(25)) { + mask = BIT(25); + irq = 25; + goto handle_irq; + } + } + } else { + if (mask & 0x1c000000) { + if (mask & BIT(26)) { + mask = BIT(26); + irq = 26; + goto handle_irq; + } + if (mask & BIT(27)) { + mask = BIT(27); + irq = 27; + goto handle_irq; + } + if (mask & BIT(28)) { + mask = BIT(28); + irq = 28; + goto handle_irq; + } + } else { + if (mask & BIT(29)) { + mask = BIT(29); + irq = 29; + goto handle_irq; + } + if (mask & BIT(30)) { + mask = BIT(30); + irq = 30; + goto handle_irq; + } + if (mask & BIT(31)) { + mask = BIT(31); + irq = 31; + goto handle_irq; + } + } + } + return 0; +handle_irq: + _sw_isr_table[irq].isr(_sw_isr_table[irq].arg); + return mask; +} + +static inline int _xtensa_handle_one_int1(unsigned int mask) +{ + int irq; + + if (mask & 0x7c0) { + if (mask & 0xc0) { + if (mask & BIT(6)) { + mask = BIT(6); + irq = 6; + goto handle_irq; + } + if (mask & BIT(7)) { + mask = BIT(7); + irq = 7; + goto handle_irq; + } + } else { + if (mask & BIT(8)) { + mask = BIT(8); + irq = 8; + goto handle_irq; + } + if (mask & BIT(9)) { + mask = BIT(9); + irq = 9; + goto handle_irq; + } + if (mask & BIT(10)) { + mask = BIT(10); + irq = 10; + goto handle_irq; + } + } + } else { + if (mask & 0x1800) { + if (mask & BIT(11)) { + mask = BIT(11); + irq = 11; + goto handle_irq; + } + if (mask & BIT(12)) { + mask = BIT(12); + irq = 12; + goto handle_irq; + } + } else { + if (mask & BIT(13)) { + mask = BIT(13); + irq = 13; + goto handle_irq; + } + if (mask & BIT(14)) { + mask = BIT(14); + irq = 14; + goto handle_irq; + } + if (mask & BIT(15)) { + mask = BIT(15); + irq = 15; + goto handle_irq; + } + } + } + return 0; +handle_irq: + _sw_isr_table[irq].isr(_sw_isr_table[irq].arg); + return mask; +} + +static inline int _xtensa_handle_one_int0(unsigned int mask) +{ + return 0; +} +static inline int _xtensa_handle_one_int4(unsigned int mask) +{ + return 0; +} +static inline int _xtensa_handle_one_int6(unsigned int mask) +{ + return 0; +} +static inline int _xtensa_handle_one_int7(unsigned int mask) +{ + return 0; +} +static inline int _xtensa_handle_one_int8(unsigned int mask) +{ + return 0; +} +static inline int _xtensa_handle_one_int9(unsigned int mask) +{ + return 0; +} +static inline int _xtensa_handle_one_int10(unsigned int mask) +{ + return 0; +} +static inline int _xtensa_handle_one_int11(unsigned int mask) +{ + return 0; +} +static inline int _xtensa_handle_one_int12(unsigned int mask) +{ + return 0; +} +static inline int _xtensa_handle_one_int13(unsigned int mask) +{ + return 0; +} +static inline int _xtensa_handle_one_int14(unsigned int mask) +{ + return 0; +} +static inline int _xtensa_handle_one_int15(unsigned int mask) +{ + return 0; +} diff --git a/soc/xtensa/nxp_adsp/imx8ulp/include/memory.h b/soc/xtensa/nxp_adsp/imx8ulp/include/memory.h new file mode 100644 index 00000000000..d6384477e71 --- /dev/null +++ b/soc/xtensa/nxp_adsp/imx8ulp/include/memory.h @@ -0,0 +1,159 @@ +/* + * Copyright (c) 2023 NXP + * + * SPDX-License-Identifier: Apache-2.0 + */ +#ifndef ZEPHYR_SOC_NXP_ADSP_MEMORY_H_ +#define ZEPHYR_SOC_NXP_ADSP_MEMORY_H_ + +#define IRAM_RESERVE_HEADER_SPACE 0x400 + +#define IRAM_BASE 0x21170000 +#define IRAM_SIZE 0x10000 + +#define SDRAM0_BASE 0x1a000000 +#define SDRAM0_SIZE 0x800000 + +#define SDRAM1_BASE 0x1a800000 +#define SDRAM1_SIZE 0x800000 + +/* The reset vector address in SRAM and its size */ +#define MEM_RESET_TEXT_SIZE 0x2e0 +#define MEM_RESET_LIT_SIZE 0x120 + +/* This is the base address of all the vectors defined in IRAM */ +#define XCHAL_VECBASE_RESET_PADDR_IRAM \ + (IRAM_BASE + IRAM_RESERVE_HEADER_SPACE) + +#define MEM_VECBASE_LIT_SIZE 0x178 + +/* + * EXCEPTIONS and VECTORS + */ +#define XCHAL_RESET_VECTOR0_PADDR_IRAM 0x21170000 + +/* Vector and literal sizes */ +#define MEM_VECT_LIT_SIZE 0x4 +#define MEM_VECT_TEXT_SIZE 0x1C +#define MEM_VECT_SIZE (MEM_VECT_TEXT_SIZE +\ + MEM_VECT_LIT_SIZE) + +/* The addresses of the vectors. + * Only the mem_error vector continues to point to its ROM address. + */ +#define XCHAL_INTLEVEL2_VECTOR_PADDR_IRAM \ + (XCHAL_VECBASE_RESET_PADDR_IRAM + 0x17C) + +#define XCHAL_INTLEVEL3_VECTOR_PADDR_IRAM \ + (XCHAL_VECBASE_RESET_PADDR_IRAM + 0x19C) + +#define XCHAL_INTLEVEL4_VECTOR_PADDR_IRAM \ + (XCHAL_VECBASE_RESET_PADDR_IRAM + 0x1BC) + +#define XCHAL_INTLEVEL5_VECTOR_PADDR_IRAM \ + (XCHAL_VECBASE_RESET_PADDR_IRAM + 0x1DC) + +#define XCHAL_KERNEL_VECTOR_PADDR_IRAM \ + (XCHAL_VECBASE_RESET_PADDR_IRAM + 0x1FC) + +#define XCHAL_USER_VECTOR_PADDR_IRAM \ + (XCHAL_VECBASE_RESET_PADDR_IRAM + 0x21C) + +#define XCHAL_DOUBLEEXC_VECTOR_PADDR_IRAM \ + (XCHAL_VECBASE_RESET_PADDR_IRAM + 0x23C) + +/* Location for the intList section which is later used to construct the + * Interrupt Descriptor Table (IDT). This is a bogus address as this + * section will be stripped off in the final image. + */ +#define IDT_BASE (IRAM_BASE + IRAM_SIZE) + +/* size of the Interrupt Descriptor Table (IDT) */ +#define IDT_SIZE 0x2000 + +/* physical DSP addresses */ +#define IRAM_BASE 0x21170000 +#define IRAM_SIZE 0x10000 + +#define DRAM0_BASE 0x21180000 +#define DRAM0_SIZE 0x10000 + +#define SDRAM0_BASE 0x1a000000 +#define SDRAM0_SIZE 0x800000 + +#define SDRAM1_BASE 0x1a800000 +#define SDRAM1_SIZE 0x800000 + +#define XSHAL_MU13_SIDEB_BYPASS_PADDR 0x2DA20000 +#define MU_BASE XSHAL_MU13_SIDEB_BYPASS_PADDR + +#define EDMA2_BASE 0x2D810000 +#define EDMA2_SIZE 0x10000 + +#define SAI_5_BASE 0x29890000 +#define SAI_5_SIZE 0x00010000 +#define SAI_6_BASE 0x2DA90000 +#define SAI_6_SIZE 0x00010000 +#define SAI_7_BASE 0x2DAA0000 +#define SAI_7_SIZE 0x00010000 + +#define UUID_ENTRY_ELF_BASE 0x1FFFA000 +#define UUID_ENTRY_ELF_SIZE 0x6000 + +#define LOG_ENTRY_ELF_BASE 0x20000000 +#define LOG_ENTRY_ELF_SIZE 0x2000000 + +#define EXT_MANIFEST_ELF_BASE (LOG_ENTRY_ELF_BASE + LOG_ENTRY_ELF_SIZE) +#define EXT_MANIFEST_ELF_SIZE 0x2000000 + +/* + * The Heap and Stack on i.MX8 are organized like this :- + * + * +--------------------------------------------------------------------------+ + * | Offset | Region | Size | + * +---------------------+----------------+-----------------------------------+ + * | SDRAM_BASE | RO Data | SOF_DATA_SIZE | + * | | Data | | + * | | BSS | | + * +---------------------+----------------+-----------------------------------+ + * | HEAP_SYSTEM_BASE | System Heap | HEAP_SYSTEM_SIZE | + * +---------------------+----------------+-----------------------------------+ + * | HEAP_RUNTIME_BASE | Runtime Heap | HEAP_RUNTIME_SIZE | + * +---------------------+----------------+-----------------------------------+ + * | HEAP_BUFFER_BASE | Module Buffers | HEAP_BUFFER_SIZE | + * +---------------------+----------------+-----------------------------------+ + * | SOF_STACK_END | Stack | SOF_STACK_SIZE | + * +---------------------+----------------+-----------------------------------+ + * | SOF_STACK_BASE | | | + * +---------------------+----------------+-----------------------------------+ + */ + +#define SRAM_OUTBOX_BASE SDRAM1_BASE +#define SRAM_OUTBOX_SIZE 0x1000 +#define SRAM_OUTBOX_OFFSET 0 + +#define SRAM_INBOX_BASE (SRAM_OUTBOX_BASE + SRAM_OUTBOX_SIZE) +#define SRAM_INBOX_SIZE 0x1000 +#define SRAM_INBOX_OFFSET SRAM_OUTBOX_SIZE + +#define SRAM_DEBUG_BASE (SRAM_INBOX_BASE + SRAM_INBOX_SIZE) +#define SRAM_DEBUG_SIZE 0x2800 +#define SRAM_DEBUG_OFFSET (SRAM_INBOX_OFFSET + SRAM_INBOX_SIZE) + +#define SRAM_EXCEPT_BASE (SRAM_DEBUG_BASE + SRAM_DEBUG_SIZE) +#define SRAM_EXCEPT_SIZE 0x800 +#define SRAM_EXCEPT_OFFSET (SRAM_DEBUG_OFFSET + SRAM_DEBUG_SIZE) + +#define SRAM_STREAM_BASE (SRAM_EXCEPT_BASE + SRAM_EXCEPT_SIZE) +#define SRAM_STREAM_SIZE 0x1000 +#define SRAM_STREAM_OFFSET (SRAM_EXCEPT_OFFSET + SRAM_EXCEPT_SIZE) + +#define SRAM_TRACE_BASE (SRAM_STREAM_BASE + SRAM_STREAM_SIZE) +#define SRAM_TRACE_SIZE 0x1000 +#define SRAM_TRACE_OFFSET (SRAM_STREAM_OFFSET + SRAM_STREAM_SIZE) + +#define SOF_MAILBOX_SIZE (SRAM_INBOX_SIZE + SRAM_OUTBOX_SIZE \ + + SRAM_DEBUG_SIZE + SRAM_EXCEPT_SIZE \ + + SRAM_STREAM_SIZE + SRAM_TRACE_SIZE) + +#endif /* ZEPHYR_SOC_NXP_ADSP_MEMORY_H_ */ diff --git a/soc/xtensa/nxp_adsp/imx8ulp/linker.ld b/soc/xtensa/nxp_adsp/imx8ulp/linker.ld new file mode 100644 index 00000000000..4b5aec29742 --- /dev/null +++ b/soc/xtensa/nxp_adsp/imx8ulp/linker.ld @@ -0,0 +1,517 @@ +/* + * Copyright (c) 2023 NXP + * + * SPDX-License-Identifier: Apache-2.0 + */ + +/** + * @file + * @brief Linker command/script file + * + * Linker script for the NXP i.MX8ULP platform + */ + +OUTPUT_ARCH(xtensa) + +#include +#include +#include +#include + +#include +#include + +PROVIDE(__memctl_default = 0x00000000); +PROVIDE(_MemErrorHandler = 0x00000000); + +#define RAMABLE_REGION sdram0 :sdram0_phdr +#define ROMABLE_REGION sdram0 :sdram0_phdr + +MEMORY +{ + vector_reset_text : + org = XCHAL_RESET_VECTOR0_PADDR_IRAM, + len = MEM_RESET_TEXT_SIZE + vector_reset_lit : + org = XCHAL_RESET_VECTOR0_PADDR_IRAM + MEM_RESET_TEXT_SIZE, + len = MEM_RESET_LIT_SIZE + vector_base_text : + org = XCHAL_VECBASE_RESET_PADDR_IRAM, + len = MEM_VECBASE_LIT_SIZE + vector_int2_lit : + org = XCHAL_INTLEVEL2_VECTOR_PADDR_IRAM - MEM_VECT_LIT_SIZE, + len = MEM_VECT_LIT_SIZE + vector_int2_text : + org = XCHAL_INTLEVEL2_VECTOR_PADDR_IRAM, + len = MEM_VECT_TEXT_SIZE + vector_int3_lit : + org = XCHAL_INTLEVEL3_VECTOR_PADDR_IRAM - MEM_VECT_LIT_SIZE, + len = MEM_VECT_LIT_SIZE + vector_int3_text : + org = XCHAL_INTLEVEL3_VECTOR_PADDR_IRAM, + len = MEM_VECT_TEXT_SIZE + vector_int4_lit : + org = XCHAL_INTLEVEL4_VECTOR_PADDR_IRAM - MEM_VECT_LIT_SIZE, + len = MEM_VECT_LIT_SIZE + vector_int4_text : + org = XCHAL_INTLEVEL4_VECTOR_PADDR_IRAM, + len = MEM_VECT_TEXT_SIZE + vector_int5_lit : + org = XCHAL_INTLEVEL5_VECTOR_PADDR_IRAM - MEM_VECT_LIT_SIZE, + len = MEM_VECT_LIT_SIZE + vector_int5_text : + org = XCHAL_INTLEVEL5_VECTOR_PADDR_IRAM, + len = MEM_VECT_TEXT_SIZE + vector_kernel_lit : + org = XCHAL_KERNEL_VECTOR_PADDR_IRAM - MEM_VECT_LIT_SIZE, + len = MEM_VECT_LIT_SIZE + vector_kernel_text : + org = XCHAL_KERNEL_VECTOR_PADDR_IRAM, + len = MEM_VECT_TEXT_SIZE + vector_user_lit : + org = XCHAL_USER_VECTOR_PADDR_IRAM - MEM_VECT_LIT_SIZE, + len = MEM_VECT_LIT_SIZE + vector_user_text : + org = XCHAL_USER_VECTOR_PADDR_IRAM, + len = MEM_VECT_TEXT_SIZE + vector_double_lit : + org = XCHAL_DOUBLEEXC_VECTOR_PADDR_IRAM - MEM_VECT_LIT_SIZE, + len = MEM_VECT_LIT_SIZE + vector_double_text : + org = XCHAL_DOUBLEEXC_VECTOR_PADDR_IRAM, + len = MEM_VECT_TEXT_SIZE + iram_text_start : + org = XCHAL_DOUBLEEXC_VECTOR_PADDR_IRAM + MEM_VECT_TEXT_SIZE, + len = (IRAM_BASE + IRAM_SIZE) - (XCHAL_DOUBLEEXC_VECTOR_PADDR + MEM_VECT_TEXT_SIZE) + sdram0 : + org = SDRAM0_BASE, + len = SDRAM0_SIZE + sdram1 : + org = SDRAM1_BASE + SOF_MAILBOX_SIZE, + len = SDRAM1_SIZE - SOF_MAILBOX_SIZE +#ifdef CONFIG_GEN_ISR_TABLES + IDT_LIST : + org = IDT_BASE, + len = IDT_SIZE +#endif + + static_uuid_entries_seg (!ari) : + org = UUID_ENTRY_ELF_BASE, + len = UUID_ENTRY_ELF_SIZE + static_log_entries_seg (!ari) : + org = LOG_ENTRY_ELF_BASE, + len = LOG_ENTRY_ELF_SIZE + fw_metadata_seg (!ari) : + org = EXT_MANIFEST_ELF_BASE, + len = EXT_MANIFEST_ELF_SIZE +} + +PHDRS +{ + vector_reset_text_phdr PT_LOAD; + vector_reset_lit_phdr PT_LOAD; + vector_base_text_phdr PT_LOAD; + vector_base_lit_phdr PT_LOAD; + vector_int2_text_phdr PT_LOAD; + vector_int2_lit_phdr PT_LOAD; + vector_int3_text_phdr PT_LOAD; + vector_int3_lit_phdr PT_LOAD; + vector_int4_text_phdr PT_LOAD; + vector_int4_lit_phdr PT_LOAD; + vector_int5_text_phdr PT_LOAD; + vector_int5_lit_phdr PT_LOAD; + vector_kernel_text_phdr PT_LOAD; + vector_kernel_lit_phdr PT_LOAD; + vector_user_text_phdr PT_LOAD; + vector_user_lit_phdr PT_LOAD; + vector_double_text_phdr PT_LOAD; + vector_double_lit_phdr PT_LOAD; + iram_text_start_phdr PT_LOAD; + sdram0_phdr PT_LOAD; + sdram1_phdr PT_LOAD; + static_uuid_entries_phdr PT_NOTE; + static_log_entries_phdr PT_NOTE; + metadata_entries_phdr PT_NOTE; +} + +_rom_store_table = 0; + +PROVIDE(_memmap_vecbase_reset = XCHAL_VECBASE_RESET_PADDR); + +ENTRY(CONFIG_KERNEL_ENTRY) + +/* Various memory-map dependent cache attribute settings: */ +_memmap_cacheattr_wb_base = 0x44024000; +_memmap_cacheattr_wt_base = 0x11021000; +_memmap_cacheattr_bp_base = 0x22022000; +_memmap_cacheattr_unused_mask = 0x00F00FFF; +_memmap_cacheattr_wb_trapnull = 0x4422422F; +_memmap_cacheattr_wba_trapnull = 0x4422422F; +_memmap_cacheattr_wbna_trapnull = 0x25222222; +_memmap_cacheattr_wt_trapnull = 0x1122122F; +_memmap_cacheattr_bp_trapnull = 0x2222222F; +_memmap_cacheattr_wb_strict = 0x44F24FFF; +_memmap_cacheattr_wt_strict = 0x11F21FFF; +_memmap_cacheattr_bp_strict = 0x22F22FFF; +_memmap_cacheattr_wb_allvalid = 0x44224222; +_memmap_cacheattr_wt_allvalid = 0x11221222; +_memmap_cacheattr_bp_allvalid = 0x22222222; +/* + * Every 512M in 4GB space has dedicate cache attribute. + * 1: write through + * 2: cache bypass + * 4: write back + * F: invalid access + */ +_memmap_cacheattr_imx8_wt_allvalid = 0x222222221; +PROVIDE(_memmap_cacheattr_reset = _memmap_cacheattr_imx8_wt_allvalid); + +_EXT_MAN_ALIGN_ = 16; +EXTERN(ext_man_fw_ver) + +SECTIONS +{ + +#include + .ResetVector.text : ALIGN(4) + { + _ResetVector_text_start = ABSOLUTE(.); + KEEP (*(.ResetVector.text)) + _ResetVector_text_end = ABSOLUTE(.); + } >vector_reset_text :vector_reset_text_phdr + + .ResetVector.literal : ALIGN(4) + { + _ResetVector_literal_start = ABSOLUTE(.); + *(.ResetVector.literal) + _ResetVector_literal_end = ABSOLUTE(.); + } >vector_reset_lit :vector_reset_lit_phdr + + .WindowVectors.text : ALIGN(4) + { + _WindowVectors_text_start = ABSOLUTE(.); + KEEP (*(.WindowVectors.text)) + _WindowVectors_text_end = ABSOLUTE(.); + } >vector_base_text :vector_base_text_phdr + + .Level2InterruptVector.literal : ALIGN(4) + { + _Level2InterruptVector_literal_start = ABSOLUTE(.); + *(.Level2InterruptVector.literal) + _Level2InterruptVector_literal_end = ABSOLUTE(.); + } >vector_int2_lit :vector_int2_lit_phdr + + .Level2InterruptVector.text : ALIGN(4) + { + _Level2InterruptVector_text_start = ABSOLUTE(.); + KEEP (*(.Level2InterruptVector.text)) + _Level2InterruptVector_text_end = ABSOLUTE(.); + } >vector_int2_text :vector_int2_text_phdr + + .Level3InterruptVector.literal : ALIGN(4) + { + _Level3InterruptVector_literal_start = ABSOLUTE(.); + *(.Level3InterruptVector.literal) + _Level3InterruptVector_literal_end = ABSOLUTE(.); + } >vector_int3_lit :vector_int3_lit_phdr + + .Level3InterruptVector.text : ALIGN(4) + { + _Level3InterruptVector_text_start = ABSOLUTE(.); + KEEP (*(.Level3InterruptVector.text)) + _Level3InterruptVector_text_end = ABSOLUTE(.); + } >vector_int3_text :vector_int3_text_phdr + + .DebugExceptionVector.literal : ALIGN(4) + { + _DebugExceptionVector_literal_start = ABSOLUTE(.); + *(.DebugExceptionVector.literal) + _DebugExceptionVector_literal_end = ABSOLUTE(.); + } >vector_int4_lit :vector_int4_lit_phdr + + .DebugExceptionVector.text : ALIGN(4) + { + _DebugExceptionVector_text_start = ABSOLUTE(.); + KEEP (*(.DebugExceptionVector.text)) + _DebugExceptionVector_text_end = ABSOLUTE(.); + } >vector_int4_text :vector_int4_text_phdr + + .NMIExceptionVector.literal : ALIGN(4) + { + _NMIExceptionVector_literal_start = ABSOLUTE(.); + *(.NMIExceptionVector.literal) + _NMIExceptionVector_literal_end = ABSOLUTE(.); + } >vector_int5_lit :vector_int5_lit_phdr + + .NMIExceptionVector.text : ALIGN(4) + { + _NMIExceptionVector_text_start = ABSOLUTE(.); + KEEP (*(.NMIExceptionVector.text)) + _NMIExceptionVector_text_end = ABSOLUTE(.); + } >vector_int5_text :vector_int5_text_phdr + + .KernelExceptionVector.literal : ALIGN(4) + { + _KernelExceptionVector_literal_start = ABSOLUTE(.); + *(.KernelExceptionVector.literal) + _KernelExceptionVector_literal_end = ABSOLUTE(.); + } >vector_kernel_lit :vector_kernel_lit_phdr + + .KernelExceptionVector.text : ALIGN(4) + { + _KernelExceptionVector_text_start = ABSOLUTE(.); + KEEP (*(.KernelExceptionVector.text)) + _KernelExceptionVector_text_end = ABSOLUTE(.); + } >vector_kernel_text :vector_kernel_text_phdr + + .UserExceptionVector.literal : ALIGN(4) + { + _UserExceptionVector_literal_start = ABSOLUTE(.); + *(.UserExceptionVector.literal) + _UserExceptionVector_literal_end = ABSOLUTE(.); + } >vector_user_lit :vector_user_lit_phdr + + .UserExceptionVector.text : ALIGN(4) + { + _UserExceptionVector_text_start = ABSOLUTE(.); + KEEP (*(.UserExceptionVector.text)) + _UserExceptionVector_text_end = ABSOLUTE(.); + } >vector_user_text :vector_user_text_phdr + + .DoubleExceptionVector.literal : ALIGN(4) + { + _DoubleExceptionVector_literal_start = ABSOLUTE(.); + *(.DoubleExceptionVector.literal) + _DoubleExceptionVector_literal_end = ABSOLUTE(.); + } >vector_double_lit :vector_double_lit_phdr + + .DoubleExceptionVector.text : ALIGN(4) + { + _DoubleExceptionVector_text_start = ABSOLUTE(.); + KEEP (*(.DoubleExceptionVector.text)) + _DoubleExceptionVector_text_end = ABSOLUTE(.); + } >vector_double_text :vector_double_text_phdr + + .iram.text : ALIGN(4) + { + _stext = .; + _iram_text_start = ABSOLUTE(.); + *(.iram0.literal .iram.literal .iram.text.literal .iram0.text .iram.text) + _iram_text_end = ABSOLUTE(.); + } >iram_text_start :iram_text_start_phdr + + .rodata : ALIGN(4) + { + __rodata_region_start = ABSOLUTE(.); + *(.rodata) + *(.rodata.*) + *(.gnu.linkonce.r.*) + *(.rodata1) + __XT_EXCEPTION_TABLE__ = ABSOLUTE(.); + KEEP (*(.xt_except_table)) + KEEP (*(.gcc_except_table .gcc_except_table.*)) + *(.gnu.linkonce.e.*) + *(.gnu.version_r) + KEEP (*(.eh_frame)) + KEEP (*crtbegin.o(.ctors)) + KEEP (*(EXCLUDE_FILE (*crtend.o) .ctors)) + KEEP (*(SORT(.ctors.*))) + KEEP (*(.ctors)) + KEEP (*crtbegin.o(.dtors)) + KEEP (*(EXCLUDE_FILE (*crtend.o) .dtors)) + KEEP (*(SORT(.dtors.*))) + KEEP (*(.dtors)) + __XT_EXCEPTION_DESCS__ = ABSOLUTE(.); + *(.xt_except_desc) + *(.gnu.linkonce.h.*) + __XT_EXCEPTION_DESCS_END__ = ABSOLUTE(.); + *(.xt_except_desc_end) + *(.dynamic) + *(.gnu.version_d) + . = ALIGN(4); + _bss_table_start = ABSOLUTE(.); + LONG(_bss_start) + LONG(_bss_end) + _bss_table_end = ABSOLUTE(.); + __rodata_region_end = ABSOLUTE(.); + } >sdram0 :sdram0_phdr + + .module_init : ALIGN(4) + { + _module_init_start = ABSOLUTE(.); + *(*.initcall) + _module_init_end = ABSOLUTE(.); + } >sdram0 :sdram0_phdr + + .text : ALIGN(4) + { + _stext = .; + _text_start = ABSOLUTE(.); + KEEP (*(.ResetVector.text)) + *(.ResetVector.literal) + *(.entry.text) + *(.init.literal) + KEEP(*(.init)) + *(.literal .text .literal.* .text.* .stub .gnu.warning .gnu.linkonce.literal.* .gnu.linkonce.t.*.literal .gnu.linkonce.t.*) + *(.fini.literal) + KEEP(*(.fini)) + *(.gnu.version) + _text_end = ABSOLUTE(.); + _etext = .; + } >sdram0 :sdram0_phdr + +#include + + .fw_ready : ALIGN(4) + { + KEEP(*(".fw_ready")); + KEEP (*(.fw_ready_metadata)) + } >sdram0 :sdram0_phdr + + .noinit : ALIGN(4) + { + *(.noinit) + *(.noinit.*) + } >sdram0 :sdram0_phdr + + .data : ALIGN(4) + { + __data_start = ABSOLUTE(.); + *(.data) + *(.data.*) + *(.gnu.linkonce.d.*) + KEEP(*(.gnu.linkonce.d.*personality*)) + *(.data1) + *(.sdata) + *(.sdata.*) + *(.gnu.linkonce.s.*) + *(.sdata2) + *(.sdata2.*) + *(.gnu.linkonce.s2.*) + KEEP(*(.jcr)) + _trace_ctx_start = ABSOLUTE(.); + *(.trace_ctx) + _trace_ctx_end = ABSOLUTE(.); + . = ALIGN(4); + *(.gna_model) + __data_end = ABSOLUTE(.); + . = ALIGN(4096); + } >sdram0 :sdram0_phdr + + .lit4 : ALIGN(4) + { + _lit4_start = ABSOLUTE(.); + *(*.lit4) + *(.lit4.*) + *(.gnu.linkonce.lit4.*) + _lit4_end = ABSOLUTE(.); + } >sdram0 :sdram0_phdr + +#include + + .bss (NOLOAD) : ALIGN(8) + { + . = ALIGN (8); + _bss_start = ABSOLUTE(.); + *(.dynsbss) + *(.sbss) + *(.sbss.*) + *(.gnu.linkonce.sb.*) + *(.scommon) + *(.sbss2) + *(.sbss2.*) + *(.gnu.linkonce.sb2.*) + *(.dynbss) + *(.bss) + *(.bss.*) + *(.gnu.linkonce.b.*) + *(COMMON) + . = ALIGN (8); + _bss_end = ABSOLUTE(.); + } >sdram0 :sdram0_phdr + + .heap_mem (NOLOAD) : ALIGN(8) + { + . = ALIGN (8); + _heap_mem_start = ABSOLUTE(.); + *(*.heap_mem) + _heap_mem_end = ABSOLUTE(.); + } >sdram1 :sdram1_phdr + + /* stack */ + _end = ALIGN (8); + PROVIDE(end = ALIGN (8)); + + __stack = SDRAM1_BASE + SDRAM1_SIZE; + .comment 0 : { *(.comment) } + .debug 0 : { *(.debug) } + .line 0 : { *(.line) } + .debug_srcinfo 0 : { *(.debug_srcinfo) } + .debug_sfnames 0 : { *(.debug_sfnames) } + .debug_aranges 0 : { *(.debug_aranges) } + .debug_pubnames 0 : { *(.debug_pubnames) } + .debug_info 0 : { *(.debug_info) } + .debug_abbrev 0 : { *(.debug_abbrev) } + .debug_line 0 : { *(.debug_line) } + .debug_frame 0 : { *(.debug_frame) } + .debug_str 0 : { *(.debug_str) } + .debug_loc 0 : { *(.debug_loc) } + .debug_macinfo 0 : { *(.debug_macinfo) } + .debug_weaknames 0 : { *(.debug_weaknames) } + .debug_funcnames 0 : { *(.debug_funcnames) } + .debug_typenames 0 : { *(.debug_typenames) } + .debug_varnames 0 : { *(.debug_varnames) } + .debug_ranges 0 : { *(.debug_ranges) } + .xtensa.info 0 : { *(.xtensa.info) } + .xt.insn 0 : + { + KEEP (*(.xt.insn)) + KEEP (*(.gnu.linkonce.x.*)) + } + .xt.prop 0 : + { + KEEP (*(.xt.prop)) + KEEP (*(.xt.prop.*)) + KEEP (*(.gnu.linkonce.prop.*)) + } + .xt.lit 0 : + { + KEEP (*(.xt.lit)) + KEEP (*(.xt.lit.*)) + KEEP (*(.gnu.linkonce.p.*)) + } + .xt.profile_range 0 : + { + KEEP (*(.xt.profile_range)) + KEEP (*(.gnu.linkonce.profile_range.*)) + } + .xt.profile_ranges 0 : + { + KEEP (*(.xt.profile_ranges)) + KEEP (*(.gnu.linkonce.xt.profile_ranges.*)) + } + .xt.profile_files 0 : + { + KEEP (*(.xt.profile_files)) + KEEP (*(.gnu.linkonce.xt.profile_files.*)) + } +#ifdef CONFIG_GEN_ISR_TABLES +#include +#endif + + .static_uuid_entries (COPY) : ALIGN(1024) + { + *(*.static_uuids) + } > static_uuid_entries_seg :static_uuid_entries_phdr + + .static_log_entries (COPY) : ALIGN(1024) + { + *(*.static_log*) + } > static_log_entries_seg :static_log_entries_phdr + + .fw_metadata (COPY) : ALIGN(1024) + { + KEEP (*(.fw_metadata)) + . = ALIGN(_EXT_MAN_ALIGN_); + } >fw_metadata_seg :metadata_entries_phdr +} From a47aa23129747f15dee6b528f84cd983c7750b40 Mon Sep 17 00:00:00 2001 From: Zhang Peng Date: Fri, 3 Nov 2023 13:37:21 +0800 Subject: [PATCH 0725/3723] west: sign: add support for NXP i.MX8ULP board Add support for signing i.MX8ULP SOF with Zephyr images with rimage. Signed-off-by: Zhang Peng --- scripts/west_commands/sign.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/scripts/west_commands/sign.py b/scripts/west_commands/sign.py index bdf9d353685..0ad4c678398 100644 --- a/scripts/west_commands/sign.py +++ b/scripts/west_commands/sign.py @@ -441,7 +441,7 @@ def sign(self, command, build_dir, build_conf, formats): kernel_name = build_conf.get('CONFIG_KERNEL_BIN_NAME', 'zephyr') # TODO: make this a new sign.py --bootloader option. - if target in ('imx8', 'imx8m'): + if target in ('imx8', 'imx8m', 'imx8ulp'): bootloader = None kernel = str(b / 'zephyr' / f'{kernel_name}.elf') out_bin = str(b / 'zephyr' / f'{kernel_name}.ri') From 3832c676773c0f479721d7a23655027ba1f84b36 Mon Sep 17 00:00:00 2001 From: Armando Visconti Date: Mon, 4 Dec 2023 17:36:06 +0100 Subject: [PATCH 0726/3723] tests: drivers: build_all: sensor: fix i3c typo for LPS28DFW Fix typo in LPS28DFW driver i3c build test. Signed-off-by: Armando Visconti --- tests/drivers/build_all/sensor/i3c.dtsi | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/drivers/build_all/sensor/i3c.dtsi b/tests/drivers/build_all/sensor/i3c.dtsi index 4e44a80fb37..d90c72bc154 100644 --- a/tests/drivers/build_all/sensor/i3c.dtsi +++ b/tests/drivers/build_all/sensor/i3c.dtsi @@ -24,7 +24,7 @@ test_i3c_lps22df: lps22df@200000803E0000002 { drdy-gpios = <&test_gpio 0 0>; }; -test_i3c_lps28dfw: lps28dfw@200000803E0000003 { +test_i3c_lps28dfw: lps28dfw@300000803E0000003 { compatible = "st,lps28dfw"; reg = <0x3 0x00000803 0xE0000003>; assigned-address = <0x3>; From 3c2a89679602314ee2b4e4fb42ee160336fccb4c Mon Sep 17 00:00:00 2001 From: Mike Voytovich Date: Thu, 23 Nov 2023 12:06:15 -0800 Subject: [PATCH 0727/3723] drivers: sensor: lsm6dsv16x: fix gyro range The range and sensitivity tables don't match the datasheet or the DTS binding file. This changes the array lookup tables to match the datasheet and binding file. Signed-off-by: Mike Voytovich --- drivers/sensor/lsm6dsv16x/lsm6dsv16x.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/drivers/sensor/lsm6dsv16x/lsm6dsv16x.c b/drivers/sensor/lsm6dsv16x/lsm6dsv16x.c index e507a2165b0..d4f9a2c850d 100644 --- a/drivers/sensor/lsm6dsv16x/lsm6dsv16x.c +++ b/drivers/sensor/lsm6dsv16x/lsm6dsv16x.c @@ -83,8 +83,9 @@ static int lsm6dsv16x_accel_range_to_fs_val(int32_t range) return -EINVAL; } -static const uint16_t lsm6dsv16x_gyro_fs_map[] = {250, 125, 500, 0, 1000, 0, 2000}; -static const uint16_t lsm6dsv16x_gyro_fs_sens[] = {2, 1, 4, 0, 8, 0, 16}; +static const uint16_t lsm6dsv16x_gyro_fs_map[] = {125, 250, 500, 1000, 2000, 0, 0, + 0, 0, 0, 0, 0, 4000}; +static const uint16_t lsm6dsv16x_gyro_fs_sens[] = {1, 2, 4, 8, 16, 0, 0, 0, 0, 0, 0, 0, 32}; static int lsm6dsv16x_gyro_range_to_fs_val(int32_t range) { From e867c6f36d0b4469f60da6c51a9cc67598d6e3f2 Mon Sep 17 00:00:00 2001 From: Christopher Friedt Date: Sat, 2 Dec 2023 10:40:23 -0500 Subject: [PATCH 0728/3723] tests: posix: pthread: use MIN instead of min MIN() has been defined in sys/util.h for a long time. It doesn't make sense to separately define a lowercase version. Signed-off-by: Christopher Friedt --- tests/posix/common/src/pthread.c | 7 +------ 1 file changed, 1 insertion(+), 6 deletions(-) diff --git a/tests/posix/common/src/pthread.c b/tests/posix/common/src/pthread.c index 120ac2b32dd..974e13d2ac2 100644 --- a/tests/posix/common/src/pthread.c +++ b/tests/posix/common/src/pthread.c @@ -10,10 +10,6 @@ #include #include -#ifndef min -#define min(a, b) ((a) < (b)) ? (a) : (b) -#endif - #define N_THR_E 3 #define N_THR_T 4 #define BOUNCES 64 @@ -402,8 +398,7 @@ ZTEST(posix_apis, test_pthread_execution) zassert_false(ret, "Get thread name failed!"); /* TESTPOINT: Thread names match */ - ret = strncmp(thr_name, thr_name_buf, min(strlen(thr_name), - strlen(thr_name_buf))); + ret = strncmp(thr_name, thr_name_buf, MIN(strlen(thr_name), strlen(thr_name_buf))); zassert_false(ret, "Thread names don't match!"); while (!bounce_test_done()) { From 73930c25f2f1d017cedbe822ee6f472898d44fcb Mon Sep 17 00:00:00 2001 From: Christopher Friedt Date: Sat, 2 Dec 2023 14:50:43 -0500 Subject: [PATCH 0729/3723] posix: signal: define max rt signals as zero when not enabled When CONFIG_POSIX_SIGNAL=n, default CONFIG_POSIX_RTSIG_MAX to 0 so that the `sigset_t` type can be defined. Also define RTSIG_MAX. This allows native_sim and other platforms to build without error. Signed-off-by: Christopher Friedt --- include/zephyr/posix/signal.h | 23 ++++++++++++----------- lib/posix/Kconfig.signal | 15 +++++++++------ 2 files changed, 21 insertions(+), 17 deletions(-) diff --git a/include/zephyr/posix/signal.h b/include/zephyr/posix/signal.h index b31147306c2..c326fa948df 100644 --- a/include/zephyr/posix/signal.h +++ b/include/zephyr/posix/signal.h @@ -12,7 +12,6 @@ extern "C" { #endif -#ifdef CONFIG_POSIX_SIGNAL #define SIGHUP 1 /**< Hangup */ #define SIGINT 2 /**< Interrupt */ #define SIGQUIT 3 /**< Quit */ @@ -45,24 +44,17 @@ extern "C" { /* 30 not used */ #define SIGSYS 31 /**< Bad system call */ +#define RTSIG_MAX CONFIG_POSIX_RTSIG_MAX #define SIGRTMIN 32 -#define SIGRTMAX (SIGRTMIN + CONFIG_POSIX_RTSIG_MAX) +#define SIGRTMAX (SIGRTMIN + RTSIG_MAX) #define _NSIG (SIGRTMAX + 1) -BUILD_ASSERT(CONFIG_POSIX_RTSIG_MAX >= 0); +BUILD_ASSERT(RTSIG_MAX >= 0); typedef struct { unsigned long sig[DIV_ROUND_UP(_NSIG, BITS_PER_LONG)]; } sigset_t; -char *strsignal(int signum); -int sigemptyset(sigset_t *set); -int sigfillset(sigset_t *set); -int sigaddset(sigset_t *set, int signo); -int sigdelset(sigset_t *set, int signo); -int sigismember(const sigset_t *set, int signo); -#endif /* CONFIG_POSIX_SIGNAL */ - #ifndef SIGEV_NONE #define SIGEV_NONE 1 #endif @@ -90,6 +82,15 @@ struct sigevent { pthread_attr_t *sigev_notify_attributes; }; +#ifdef CONFIG_POSIX_SIGNAL +char *strsignal(int signum); +int sigemptyset(sigset_t *set); +int sigfillset(sigset_t *set); +int sigaddset(sigset_t *set, int signo); +int sigdelset(sigset_t *set, int signo); +int sigismember(const sigset_t *set, int signo); +#endif /* CONFIG_POSIX_SIGNAL */ + #ifdef __cplusplus } #endif diff --git a/lib/posix/Kconfig.signal b/lib/posix/Kconfig.signal index c51e68f1f36..4f29080c0ee 100644 --- a/lib/posix/Kconfig.signal +++ b/lib/posix/Kconfig.signal @@ -9,12 +9,6 @@ config POSIX_SIGNAL Enable support for POSIX signal APIs. if POSIX_SIGNAL -config POSIX_RTSIG_MAX - int "Maximum number of realtime signals" - default 31 - help - Define the maximum number of realtime signals (RTSIG_MAX). - The range of realtime signals is [SIGRTMIN .. (SIGRTMIN+RTSIG_MAX)] config POSIX_SIGNAL_STRING_DESC bool "Use full description for the strsignal API" @@ -24,3 +18,12 @@ config POSIX_SIGNAL_STRING_DESC Will use 256 bytes of ROM. endif + +# needed outside of if clause above to define constants & types in signal.h +config POSIX_RTSIG_MAX + int "Maximum number of realtime signals" + default 31 if POSIX_SIGNAL + default 0 if !POSIX_SIGNAL + help + Define the maximum number of realtime signals (RTSIG_MAX). + The range of realtime signals is [SIGRTMIN .. (SIGRTMIN+RTSIG_MAX)] From c2721805f0afe3c84307c7d3746553b4f9230090 Mon Sep 17 00:00:00 2001 From: Christopher Friedt Date: Sat, 2 Dec 2023 12:26:13 -0500 Subject: [PATCH 0730/3723] posix: pthread: implement pthread_sigmask() pthread_sigmask() is required by the POSIX_THREADS_BASE Option Group as detailed in Section E.1 of IEEE-1003.1-2017. The POSIX_THREADS_BASE Option Group is required for PSE51, PSE52, PSE53, and PSE54 conformance, and is otherwise mandatory for any POSIX conforming system as per Section A.2.1.3 of IEEE-1003-1.2017. Currently, setting a pthread signal mask has no effect. Signed-off-by: Christopher Friedt --- include/zephyr/posix/signal.h | 12 ++++++++++ lib/posix/Kconfig.signal | 2 +- lib/posix/posix_internal.h | 4 ++++ lib/posix/pthread.c | 43 +++++++++++++++++++++++++++++++++++ 4 files changed, 60 insertions(+), 1 deletion(-) diff --git a/include/zephyr/posix/signal.h b/include/zephyr/posix/signal.h index c326fa948df..327ca20edc0 100644 --- a/include/zephyr/posix/signal.h +++ b/include/zephyr/posix/signal.h @@ -67,6 +67,16 @@ typedef struct { #define SIGEV_THREAD 3 #endif +#ifndef SIG_BLOCK +#define SIG_BLOCK 0 +#endif +#ifndef SIG_SETMASK +#define SIG_SETMASK 1 +#endif +#ifndef SIG_UNBLOCK +#define SIG_UNBLOCK 2 +#endif + typedef int sig_atomic_t; /* Atomic entity type (ANSI) */ union sigval { @@ -89,6 +99,8 @@ int sigfillset(sigset_t *set); int sigaddset(sigset_t *set, int signo); int sigdelset(sigset_t *set, int signo); int sigismember(const sigset_t *set, int signo); + +int pthread_sigmask(int how, const sigset_t *ZRESTRICT set, sigset_t *ZRESTRICT oset); #endif /* CONFIG_POSIX_SIGNAL */ #ifdef __cplusplus diff --git a/lib/posix/Kconfig.signal b/lib/posix/Kconfig.signal index 4f29080c0ee..1df8cf3ab16 100644 --- a/lib/posix/Kconfig.signal +++ b/lib/posix/Kconfig.signal @@ -23,7 +23,7 @@ endif config POSIX_RTSIG_MAX int "Maximum number of realtime signals" default 31 if POSIX_SIGNAL - default 0 if !POSIX_SIGNAL + default 0 help Define the maximum number of realtime signals (RTSIG_MAX). The range of realtime signals is [SIGRTMIN .. (SIGRTMIN+RTSIG_MAX)] diff --git a/lib/posix/posix_internal.h b/lib/posix/posix_internal.h index 1acabb47262..4fcafaa58cf 100644 --- a/lib/posix/posix_internal.h +++ b/lib/posix/posix_internal.h @@ -12,6 +12,7 @@ #include #include +#include #include #include @@ -39,6 +40,9 @@ struct posix_thread { /* Exit status */ void *retval; + /* Signal mask */ + sigset_t sigset; + /* Pthread cancellation */ uint8_t cancel_state; uint8_t cancel_type; diff --git a/lib/posix/pthread.c b/lib/posix/pthread.c index a47d0f2c8e0..f8c62a233f1 100644 --- a/lib/posix/pthread.c +++ b/lib/posix/pthread.c @@ -1073,6 +1073,49 @@ int pthread_atfork(void (*prepare)(void), void (*parent)(void), void (*child)(vo return ENOSYS; } +/* this should probably go into signal.c but we need access to the lock */ +int pthread_sigmask(int how, const sigset_t *ZRESTRICT set, sigset_t *ZRESTRICT oset) +{ + struct posix_thread *t; + + if (!(how == SIG_BLOCK || how == SIG_SETMASK || how == SIG_UNBLOCK)) { + return EINVAL; + } + + t = to_posix_thread(pthread_self()); + if (t == NULL) { + return ESRCH; + } + + K_SPINLOCK(&pthread_pool_lock) { + if (oset != NULL) { + *oset = t->sigset; + } + + if (set == NULL) { + K_SPINLOCK_BREAK; + } + + switch (how) { + case SIG_BLOCK: + for (size_t i = 0; i < ARRAY_SIZE(set->sig); ++i) { + t->sigset.sig[i] |= set->sig[i]; + } + break; + case SIG_SETMASK: + t->sigset = *set; + break; + case SIG_UNBLOCK: + for (size_t i = 0; i < ARRAY_SIZE(set->sig); ++i) { + t->sigset.sig[i] &= ~set->sig[i]; + } + break; + } + } + + return 0; +} + static int posix_thread_pool_init(void) { size_t i; From c2ab4020b02998e968d12b32f54135645143532e Mon Sep 17 00:00:00 2001 From: Christopher Friedt Date: Sat, 2 Dec 2023 12:28:42 -0500 Subject: [PATCH 0731/3723] tests: posix: pthread: add test for pthread_sigmask() Add a test for pthread_sigmask(). Signed-off-by: Christopher Friedt --- tests/posix/common/src/signal.c | 89 ++++++++++++++++++++++++++++++++- 1 file changed, 88 insertions(+), 1 deletion(-) diff --git a/tests/posix/common/src/signal.c b/tests/posix/common/src/signal.c index e565554c881..5fc7cd16e48 100644 --- a/tests/posix/common/src/signal.c +++ b/tests/posix/common/src/signal.c @@ -5,10 +5,11 @@ */ #include +#include #include #include -#include +#include #include ZTEST(posix_apis, test_signal_emptyset) @@ -217,3 +218,89 @@ ZTEST(posix_apis, test_signal_strsignal) zassert_mem_equal(strsignal(SIGSYS), "Signal 31", sizeof("Signal 31")); #endif } + +static void *test_pthread_sigmask_entry(void *arg) +{ +/* for clarity */ +#define SIG_GETMASK SIG_SETMASK + + enum { + NEW, + OLD, + }; + static sigset_t set[2]; + const int invalid_how = 0x9a2ba9e; + + ARG_UNUSED(arg); + + /* invalid how results in EINVAL */ + zassert_equal(pthread_sigmask(invalid_how, NULL, NULL), EINVAL); + zassert_equal(pthread_sigmask(invalid_how, &set[NEW], &set[OLD]), EINVAL); + + /* verify setting / getting masks */ + zassert_ok(sigemptyset(&set[NEW])); + zassert_ok(pthread_sigmask(SIG_SETMASK, &set[NEW], NULL)); + zassert_ok(sigfillset(&set[OLD])); + zassert_ok(pthread_sigmask(SIG_GETMASK, NULL, &set[OLD])); + zassert_mem_equal(&set[OLD], &set[NEW], sizeof(set[OLD])); + + zassert_ok(sigfillset(&set[NEW])); + zassert_ok(pthread_sigmask(SIG_SETMASK, &set[NEW], NULL)); + zassert_ok(sigemptyset(&set[OLD])); + zassert_ok(pthread_sigmask(SIG_GETMASK, NULL, &set[OLD])); + zassert_mem_equal(&set[OLD], &set[NEW], sizeof(set[OLD])); + + /* start with an empty mask */ + zassert_ok(sigemptyset(&set[NEW])); + zassert_ok(pthread_sigmask(SIG_SETMASK, &set[NEW], NULL)); + + /* verify SIG_BLOCK: expect (SIGUSR1 | SIGUSR2 | SIGHUP) */ + zassert_ok(sigemptyset(&set[NEW])); + zassert_ok(sigaddset(&set[NEW], SIGUSR1)); + zassert_ok(pthread_sigmask(SIG_BLOCK, &set[NEW], NULL)); + + zassert_ok(sigemptyset(&set[NEW])); + zassert_ok(sigaddset(&set[NEW], SIGUSR2)); + zassert_ok(sigaddset(&set[NEW], SIGHUP)); + zassert_ok(pthread_sigmask(SIG_BLOCK, &set[NEW], NULL)); + + zassert_ok(sigemptyset(&set[OLD])); + zassert_ok(sigaddset(&set[OLD], SIGUSR1)); + zassert_ok(sigaddset(&set[OLD], SIGUSR2)); + zassert_ok(sigaddset(&set[OLD], SIGHUP)); + + zassert_ok(pthread_sigmask(SIG_GETMASK, NULL, &set[NEW])); + zassert_mem_equal(&set[NEW], &set[OLD], sizeof(set[NEW])); + + /* start with full mask */ + zassert_ok(sigfillset(&set[NEW])); + zassert_ok(pthread_sigmask(SIG_SETMASK, &set[NEW], NULL)); + + /* verify SIG_UNBLOCK: expect ~(SIGUSR1 | SIGUSR2 | SIGHUP) */ + zassert_ok(sigemptyset(&set[NEW])); + zassert_ok(sigaddset(&set[NEW], SIGUSR1)); + zassert_ok(pthread_sigmask(SIG_UNBLOCK, &set[NEW], NULL)); + + zassert_ok(sigemptyset(&set[NEW])); + zassert_ok(sigaddset(&set[NEW], SIGUSR2)); + zassert_ok(sigaddset(&set[NEW], SIGHUP)); + zassert_ok(pthread_sigmask(SIG_UNBLOCK, &set[NEW], NULL)); + + zassert_ok(sigfillset(&set[OLD])); + zassert_ok(sigdelset(&set[OLD], SIGUSR1)); + zassert_ok(sigdelset(&set[OLD], SIGUSR2)); + zassert_ok(sigdelset(&set[OLD], SIGHUP)); + + zassert_ok(pthread_sigmask(SIG_GETMASK, NULL, &set[NEW])); + zassert_mem_equal(&set[NEW], &set[OLD], sizeof(set[NEW])); + + return NULL; +} + +ZTEST(posix_apis, test_pthread_sigmask) +{ + pthread_t th; + + zassert_ok(pthread_create(&th, NULL, test_pthread_sigmask_entry, NULL)); + zassert_ok(pthread_join(th, NULL)); +} From 4153a396f81f58c9fabce90e0bec3cd5b87aaf33 Mon Sep 17 00:00:00 2001 From: Christopher Friedt Date: Sat, 2 Dec 2023 14:53:53 -0500 Subject: [PATCH 0732/3723] tests: posix: headers: enable tests for signal.h entities Enable existsence checks for newl(-ish)ly added signal.h definitions. Signed-off-by: Christopher Friedt --- tests/posix/headers/src/signal_h.c | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/tests/posix/headers/src/signal_h.c b/tests/posix/headers/src/signal_h.c index 852cddf3df0..58c17dd623e 100644 --- a/tests/posix/headers/src/signal_h.c +++ b/tests/posix/headers/src/signal_h.c @@ -24,7 +24,7 @@ ZTEST(posix_headers, test_signal_h) /* zassert_not_equal(-1, SIG_HOLD); */ /* not implemented */ /* zassert_not_equal(-1, SIG_IGN); */ /* not implemented */ - /* zassert_not_equal((sig_atomic_t)-1, (sig_atomic_t)0); */ /* not implemented */ + zassert_not_equal((sig_atomic_t)-1, (sig_atomic_t)0); /* zassert_not_equal((pid_t)-1, (pid_t)0); */ /* not implemented */ zassert_not_equal(-1, offsetof(struct sigevent, sigev_notify)); @@ -40,12 +40,12 @@ ZTEST(posix_headers, test_signal_h) zassert_not_equal(-1, offsetof(union sigval, sival_int)); zassert_not_equal(-1, offsetof(union sigval, sival_ptr)); - /* zassert_not_equal(-1, RTSIG_MAX); */ /* not implemented */ - /* zassert_true(SIGRTMAX - SIGRTMIN >= RTSIG_MAX); */ /* not implemented */ + zassert_not_equal(-1, RTSIG_MAX); + zassert_true(SIGRTMAX - SIGRTMIN >= RTSIG_MAX); - /* zassert_not_equal(-1, SIG_BLOCK); */ /* not implemented */ - /* zassert_not_equal(-1, SIG_UNBLOCK); */ /* not implemented */ - /* zassert_not_equal(-1, SIG_SETMASK); */ /* not implemented */ + zassert_not_equal(-1, SIG_BLOCK); + zassert_not_equal(-1, SIG_UNBLOCK); + zassert_not_equal(-1, SIG_SETMASK); /* zassert_not_equal(-1, SA_NOCLDSTOP); */ /* not implemented */ /* zassert_not_equal(-1, SA_ONSTACK); */ /* not implemented */ @@ -164,6 +164,7 @@ ZTEST(posix_headers, test_signal_h) zassert_not_null(sigdelset); zassert_not_null(sigismember); zassert_not_null(strsignal); + zassert_not_null(pthread_sigmask); #endif /* CONFIG_POSIX_SIGNAL */ if (IS_ENABLED(CONFIG_POSIX_API)) { @@ -172,7 +173,6 @@ ZTEST(posix_headers, test_signal_h) /* zassert_not_null(psiginfo); */ /* not implemented */ /* zassert_not_null(psignal); */ /* not implemented */ /* zassert_not_null(pthread_kill); */ /* not implemented */ - /* zassert_not_null(pthread_sigmask); */ /* not implemented */ /* zassert_not_null(raise); */ /* not implemented */ /* zassert_not_null(sigaction); */ /* not implemented */ /* zassert_not_null(sigaltstack); */ /* not implemented */ From 25ad0283769d2165838cbddaf4be446dc816e97f Mon Sep 17 00:00:00 2001 From: Christopher Friedt Date: Sat, 2 Dec 2023 12:33:36 -0500 Subject: [PATCH 0733/3723] doc: posix: denote pthread_sigmask() as implemented Mark pthread_sigmask() as implemented in POSIX_THREADS_BASE. Signed-off-by: Christopher Friedt --- doc/services/portability/posix/option_groups/index.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/doc/services/portability/posix/option_groups/index.rst b/doc/services/portability/posix/option_groups/index.rst index b58a9e2ce38..5e13aea0bc9 100644 --- a/doc/services/portability/posix/option_groups/index.rst +++ b/doc/services/portability/posix/option_groups/index.rst @@ -63,7 +63,7 @@ multiple processes. pthread_setcancelstate(),yes pthread_setcanceltype(),yes pthread_setspecific(),yes - pthread_sigmask(), + pthread_sigmask(),yes pthread_testcancel(), .. _posix_option_group_posix_threads_ext: From 9f42537fc7e08149d08c0b4df95ca4bf9398bea2 Mon Sep 17 00:00:00 2001 From: Keith Packard Date: Mon, 4 Dec 2023 10:33:28 -0800 Subject: [PATCH 0734/3723] kernel: Use k_us_to_cyc_ceil32 in k_busy_wait Replace open-coded time conversion with the macro which as that will usually use a constant divide or multiply. Signed-off-by: Keith Packard --- kernel/busy_wait.c | 8 +------- 1 file changed, 1 insertion(+), 7 deletions(-) diff --git a/kernel/busy_wait.c b/kernel/busy_wait.c index 4bb94ca04d5..cb7c993437d 100644 --- a/kernel/busy_wait.c +++ b/kernel/busy_wait.c @@ -21,13 +21,7 @@ void z_impl_k_busy_wait(uint32_t usec_to_wait) arch_busy_wait(usec_to_wait); #elif defined(CONFIG_SYS_CLOCK_EXISTS) uint32_t start_cycles = k_cycle_get_32(); - - /* use 64-bit math to prevent overflow when multiplying */ - uint32_t cycles_to_wait = (uint32_t)( - (uint64_t)usec_to_wait * - (uint64_t)sys_clock_hw_cycles_per_sec() / - (uint64_t)USEC_PER_SEC - ); + uint32_t cycles_to_wait = k_us_to_cyc_ceil32(usec_to_wait); for (;;) { uint32_t current_cycles = k_cycle_get_32(); From d70e8d5a8f918ef5e355a2b4cf81975ce3beec5f Mon Sep 17 00:00:00 2001 From: Keith Packard Date: Mon, 4 Dec 2023 10:30:35 -0800 Subject: [PATCH 0735/3723] =?UTF-8?q?tests/thread=5Fapis:=20Allow=2020?= =?UTF-8?q?=C2=B5s=20slop=20in=20k=5Fbusy=5Fwait=20test?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit When testing k_busy_wait(100), don't require that at least 100µs of CPU time be consumed by the thread itself; some of that time may be used elsewhere in the system. Instead, just make sure that at least 80µs is accounted to the thread and allow 20µs to get used elsewhere. Signed-off-by: Keith Packard --- tests/kernel/threads/thread_apis/src/main.c | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/tests/kernel/threads/thread_apis/src/main.c b/tests/kernel/threads/thread_apis/src/main.c index 86add19a5c7..b68c4331101 100644 --- a/tests/kernel/threads/thread_apis/src/main.c +++ b/tests/kernel/threads/thread_apis/src/main.c @@ -572,7 +572,13 @@ ZTEST(threads_lifecycle, test_k_busy_wait) /* execution_cycles increases correctly */ dt = test_stats.execution_cycles - cycles; - zassert_true(dt >= k_us_to_cyc_floor64(100)); + + /* execution cycles may not increase by the full 100µs as the + * system may be doing something else during the busy + * wait. Experimentally, we see at least 80% of the cycles + * consumed in the busy wait loop on current test targets. + */ + zassert_true(dt >= k_us_to_cyc_floor64(80)); } static void tp_entry(void *p1, void *p2, void *p3) From 7b1008c64c9d523394ff87da130d08bd17c18bac Mon Sep 17 00:00:00 2001 From: Andrej Butok Date: Mon, 4 Dec 2023 15:27:11 +0100 Subject: [PATCH 0736/3723] boards: mimxrt101x_evk: add chosen dtcm Add the chosen dtcm memory region for mimxrt1010_evk and mimxrt1015_evk. To be consistent with other rt10xx platforms. Signed-off-by: Andrej Butok --- boards/arm/mimxrt1010_evk/mimxrt1010_evk.dts | 1 + boards/arm/mimxrt1015_evk/mimxrt1015_evk.dts | 1 + 2 files changed, 2 insertions(+) diff --git a/boards/arm/mimxrt1010_evk/mimxrt1010_evk.dts b/boards/arm/mimxrt1010_evk/mimxrt1010_evk.dts index 48070152665..330de94d692 100644 --- a/boards/arm/mimxrt1010_evk/mimxrt1010_evk.dts +++ b/boards/arm/mimxrt1010_evk/mimxrt1010_evk.dts @@ -23,6 +23,7 @@ chosen { zephyr,sram = &ocram; zephyr,itcm = &itcm; + zephyr,dtcm = &dtcm; zephyr,console = &lpuart1; zephyr,shell-uart = &lpuart1; zephyr,flash = &at25sf128a; diff --git a/boards/arm/mimxrt1015_evk/mimxrt1015_evk.dts b/boards/arm/mimxrt1015_evk/mimxrt1015_evk.dts index 4f68dd0b4c8..0a28acc04ca 100644 --- a/boards/arm/mimxrt1015_evk/mimxrt1015_evk.dts +++ b/boards/arm/mimxrt1015_evk/mimxrt1015_evk.dts @@ -22,6 +22,7 @@ chosen { zephyr,sram = &ocram; zephyr,itcm = &itcm; + zephyr,dtcm = &dtcm; zephyr,console = &lpuart1; zephyr,shell-uart = &lpuart1; zephyr,flash = &at25sf128a; From a29473c38ea84b4fd8b0338b7ca7d3376eea6cb8 Mon Sep 17 00:00:00 2001 From: Aleksander Wasaznik Date: Thu, 30 Nov 2023 12:23:49 +0100 Subject: [PATCH 0737/3723] Bluetooth: Testlib: att_read allow ignoring `result_size` Allow passing in NULL as `result_size` to ignore it. Signed-off-by: Aleksander Wasaznik --- tests/bluetooth/common/testlib/src/att_read.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/tests/bluetooth/common/testlib/src/att_read.c b/tests/bluetooth/common/testlib/src/att_read.c index d7dd17ee07c..bb02fea1a59 100644 --- a/tests/bluetooth/common/testlib/src/att_read.c +++ b/tests/bluetooth/common/testlib/src/att_read.c @@ -86,6 +86,10 @@ static int bt_testlib_sync_bt_gatt_read(struct bt_testlib_att_read_closure *ctx) { int api_err; + if (ctx->result_size) { + *ctx->result_size = 0; + } + ctx->params.func = att_read_cb; k_mutex_init(&ctx->lock); @@ -156,8 +160,6 @@ int bt_testlib_att_read_by_handle_sync(struct net_buf_simple *result_data, uint1 __ASSERT(IS_ENABLED(CONFIG_BT_EATT), "EATT not complied in"); } - *result_size = 0; - return bt_testlib_sync_bt_gatt_read(&ctx); } From bbdcf4be7a4c2a32fd8dda08b5abe388de3a9395 Mon Sep 17 00:00:00 2001 From: Aleksander Wasaznik Date: Thu, 30 Nov 2023 12:27:06 +0100 Subject: [PATCH 0738/3723] Bluetooth: testlib: att_read: Fix assert on zero-sized read `read_data` can be NULL even on success if `read_size` is `0`. Signed-off-by: Aleksander Wasaznik --- tests/bluetooth/common/testlib/src/att_read.c | 11 ++--------- 1 file changed, 2 insertions(+), 9 deletions(-) diff --git a/tests/bluetooth/common/testlib/src/att_read.c b/tests/bluetooth/common/testlib/src/att_read.c index bb02fea1a59..011acd29809 100644 --- a/tests/bluetooth/common/testlib/src/att_read.c +++ b/tests/bluetooth/common/testlib/src/att_read.c @@ -39,13 +39,6 @@ static uint8_t att_read_cb(struct bt_conn *conn, uint8_t att_err, k_mutex_lock(&ctx->lock, K_FOREVER); - if (read_data == NULL) { - __ASSERT_NO_MSG(ctx->long_read); - k_condvar_signal(&ctx->done); - k_mutex_unlock(&ctx->lock); - return BT_GATT_ITER_STOP; - } - ctx->att_err = att_err; if (!att_err && ctx->result_handle) { @@ -60,7 +53,7 @@ static uint8_t att_read_cb(struct bt_conn *conn, uint8_t att_err, } } - if (!att_err && ctx->result_data) { + if (read_data && ctx->result_data) { uint16_t result_data_size = MIN(read_len, net_buf_simple_tailroom(ctx->result_data)); @@ -71,7 +64,7 @@ static uint8_t att_read_cb(struct bt_conn *conn, uint8_t att_err, *ctx->att_mtu = params->_att_mtu; } - if (ctx->long_read) { + if (ctx->long_read && read_data) { /* Don't signal `&ctx->done` */ k_mutex_unlock(&ctx->lock); return BT_GATT_ITER_CONTINUE; From b52d59dd57f29f1c3393d4da3464fe3aad4c756a Mon Sep 17 00:00:00 2001 From: Aleksander Wasaznik Date: Thu, 30 Nov 2023 15:57:59 +0100 Subject: [PATCH 0739/3723] Bluetooth: testlib: Clang format fix This reformats some code on main branch that was not clang formated. The syntax is changed from initializer list to multiple statements because there is a conflict in formating requirements between clang format and checkpatch. Signed-off-by: Aleksander Wasaznik --- tests/bluetooth/common/testlib/src/att_read.c | 41 +++++++++---------- 1 file changed, 20 insertions(+), 21 deletions(-) diff --git a/tests/bluetooth/common/testlib/src/att_read.c b/tests/bluetooth/common/testlib/src/att_read.c index 011acd29809..cba79cf0f48 100644 --- a/tests/bluetooth/common/testlib/src/att_read.c +++ b/tests/bluetooth/common/testlib/src/att_read.c @@ -138,16 +138,16 @@ int bt_testlib_att_read_by_handle_sync(struct net_buf_simple *result_data, uint1 enum bt_att_chan_opt bearer, uint16_t handle, uint16_t offset) { - struct bt_testlib_att_read_closure ctx = { - .result_size = result_size, - .conn = conn, - .att_mtu = result_att_mtu, - .result_data = result_data, - .params = { - .handle_count = 1, - .single = {.handle = handle, .offset = offset}, - IF_ENABLED(CONFIG_BT_EATT, (.chan_opt = bearer,)) - }}; + struct bt_testlib_att_read_closure ctx = {}; + + ctx.att_mtu = result_att_mtu; + ctx.conn = conn; + ctx.params.handle_count = 1; + ctx.params.single.handle = handle; + ctx.params.single.offset = offset; + ctx.result_data = result_data; + ctx.result_size = result_size; + IF_ENABLED(CONFIG_BT_EATT, (ctx.params.chan_opt = bearer)); if (bearer == BT_ATT_CHAN_OPT_ENHANCED_ONLY) { __ASSERT(IS_ENABLED(CONFIG_BT_EATT), "EATT not complied in"); @@ -162,17 +162,16 @@ int bt_testlib_gatt_long_read(struct net_buf_simple *result_data, uint16_t *resu { int err; uint16_t _result_data_size = 0; - - struct bt_testlib_att_read_closure ctx = { - .long_read = true, - .result_size = &_result_data_size, - .conn = conn, - .result_data = result_data, - .params = { - .handle_count = 1, - .single = {.handle = handle, .offset = offset}, - IF_ENABLED(CONFIG_BT_EATT, (.chan_opt = bearer,)) - }}; + struct bt_testlib_att_read_closure ctx = {}; + + ctx.att_mtu = result_att_mtu; + ctx.conn = conn; + ctx.long_read = true, ctx.params.handle_count = 1; + ctx.params.single.handle = handle; + ctx.params.single.offset = offset; + ctx.result_data = result_data; + ctx.result_size = &_result_data_size; + IF_ENABLED(CONFIG_BT_EATT, (ctx.params.chan_opt = bearer)); if (bearer == BT_ATT_CHAN_OPT_ENHANCED_ONLY) { __ASSERT(IS_ENABLED(CONFIG_BT_EATT), "EATT not complied in"); From f6fced8ecc058d1412a656335d6a4ec5f752587e Mon Sep 17 00:00:00 2001 From: Aleksander Wasaznik Date: Mon, 4 Dec 2023 12:42:32 +0100 Subject: [PATCH 0740/3723] Bluetooth: Testlib: Add comments This patch just adds some comments and asserts to clarify the testlibs att read code. Signed-off-by: Aleksander Wasaznik --- tests/bluetooth/common/testlib/src/att_read.c | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/tests/bluetooth/common/testlib/src/att_read.c b/tests/bluetooth/common/testlib/src/att_read.c index cba79cf0f48..6a678919885 100644 --- a/tests/bluetooth/common/testlib/src/att_read.c +++ b/tests/bluetooth/common/testlib/src/att_read.c @@ -30,6 +30,11 @@ struct bt_testlib_att_read_closure { bool long_read; }; +static bool bt_gatt_read_params_is_by_uuid(const struct bt_gatt_read_params *params) +{ + return params->handle_count == 0; +} + static uint8_t att_read_cb(struct bt_conn *conn, uint8_t att_err, struct bt_gatt_read_params *params, const void *read_data, uint16_t read_len) @@ -42,6 +47,7 @@ static uint8_t att_read_cb(struct bt_conn *conn, uint8_t att_err, ctx->att_err = att_err; if (!att_err && ctx->result_handle) { + __ASSERT_NO_MSG(bt_gatt_read_params_is_by_uuid(params)); *ctx->result_handle = params->by_uuid.start_handle; } @@ -79,12 +85,18 @@ static int bt_testlib_sync_bt_gatt_read(struct bt_testlib_att_read_closure *ctx) { int api_err; + /* `result_size` is initialized here so that it can be plussed on in + * the callback. The result of a long read comes in multiple + * callbacks and must be added up. + */ if (ctx->result_size) { *ctx->result_size = 0; } + /* `att_read_cb` is smart and does the right thing based on `ctx`. */ ctx->params.func = att_read_cb; + /* Setup synchronization between the cb and the current function. */ k_mutex_init(&ctx->lock); k_condvar_init(&ctx->done); From 64153a7910d2f654ceaaf05c2db34eb718bade5a Mon Sep 17 00:00:00 2001 From: Tomasz Bursztyka Date: Thu, 30 Nov 2023 11:50:50 +0100 Subject: [PATCH 0741/3723] tests/x86: Clarify DMAR output Cleaning the messy output Signed-off-by: Tomasz Bursztyka --- tests/arch/x86/info/src/acpi.c | 20 ++++++++------------ 1 file changed, 8 insertions(+), 12 deletions(-) diff --git a/tests/arch/x86/info/src/acpi.c b/tests/arch/x86/info/src/acpi.c index 35ee5f460c3..a9f6eb4638b 100644 --- a/tests/arch/x86/info/src/acpi.c +++ b/tests/arch/x86/info/src/acpi.c @@ -28,22 +28,18 @@ static const char *get_dmar_scope_type(int type) } } -static void vtd_dev_scope_info(int type, struct acpi_dmar_device_scope *dev_scope, +static void vtd_dev_scope_info(struct acpi_dmar_device_scope *dev_scope, union acpi_dmar_id *dmar_id, int num_inst) { int i = 0; - printk("\t\t\t. Type: %s\n", get_dmar_scope_type(type)); - printk("\t\t\t. Enumeration ID %u\n", dev_scope->EnumerationId); - printk("\t\t\t. PCI Bus %u\n", dev_scope->Bus); for (; num_inst > 0; num_inst--, i++) { - printk("Info: Bus: %d, dev:%d, fun:%d\n", dmar_id[i].bits.bus, - dmar_id[i].bits.device, dmar_id[i].bits.function); + printk("\t\t\t. BDF 0x%x:0x%x:0x%x\n", + dmar_id[i].bits.bus, dmar_id[i].bits.device, + dmar_id[i].bits.function); } - - printk("\n"); } static void vtd_drhd_info(struct acpi_dmar_hardware_unit *drhd) @@ -66,14 +62,14 @@ static void vtd_drhd_info(struct acpi_dmar_hardware_unit *drhd) printk("\t\t- Device Scopes:\n"); for (i = 0; i < ARRAY_SIZE(dmar_scope); i++) { if (acpi_drhd_get(dmar_scope[i], &dev_scope, dmar_id, &num_inst, 4u)) { - printk(" No DRHD entry found for scope type: %s\n", + printk("\t\tNo DRHD type: %s\n", get_dmar_scope_type(dmar_scope[i])); continue; } - printk("Found DRHD entry: %d\n", i); + printk("\t\tDRHD type %s\n", get_dmar_scope_type(dmar_scope[i])); - vtd_dev_scope_info(dmar_scope[i], &dev_scope, dmar_id, num_inst); + vtd_dev_scope_info(&dev_scope, dmar_id, num_inst); } printk("\n"); @@ -105,7 +101,7 @@ static void vtd_info(void) if (acpi_dmar_entry_get(ACPI_DMAR_TYPE_HARDWARE_UNIT, (struct acpi_subtable_header **)&drhd)) { - printk("error in retrieve DHRD!!\n"); + printk("\tError in retrieving DHRD!!\n"); return; } vtd_drhd_info(drhd); From 4217920d7cbe2dd431b7218a60e023d81537a609 Mon Sep 17 00:00:00 2001 From: Joakim Andersson Date: Wed, 15 Nov 2023 16:24:25 +0100 Subject: [PATCH 0742/3723] arch: arm: Use returned reason from secure fault handle function Use the returned reason from the secure fault handle function. I see no reason why this was ignored, and it is used in the hardfault handler. Signed-off-by: Joakim Andersson --- arch/arm/core/cortex_m/fault.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/arch/arm/core/cortex_m/fault.c b/arch/arm/core/cortex_m/fault.c index 1d9feff2e52..5090381fa31 100644 --- a/arch/arm/core/cortex_m/fault.c +++ b/arch/arm/core/cortex_m/fault.c @@ -863,7 +863,7 @@ static uint32_t fault_handle(z_arch_esf_t *esf, int fault, bool *recoverable) break; #if defined(CONFIG_ARM_SECURE_FIRMWARE) case 7: - secure_fault(esf); + reason = secure_fault(esf); break; #endif /* CONFIG_ARM_SECURE_FIRMWARE */ case 12: From a00aa3bcfaeae0bfa69d6154920200ea7a7ab5eb Mon Sep 17 00:00:00 2001 From: Wilfried Chauveau Date: Tue, 31 Oct 2023 23:15:26 +0000 Subject: [PATCH 0743/3723] arch: arm: cortex_m: add config for PMU This adds kconfig entries for Performance Monitoring Unit (PMU). Signed-off-by: Wilfried Chauveau --- arch/arm/core/cortex_m/Kconfig | 15 ++++++++++++++- soc/arm/arm/mps3/Kconfig.soc | 5 +++++ 2 files changed, 19 insertions(+), 1 deletion(-) diff --git a/arch/arm/core/cortex_m/Kconfig b/arch/arm/core/cortex_m/Kconfig index 95e05604783..61dd3dbba3c 100644 --- a/arch/arm/core/cortex_m/Kconfig +++ b/arch/arm/core/cortex_m/Kconfig @@ -283,7 +283,20 @@ config ARMV8_1_M_MVEF supporting the M-Profile Vector Extension (MVE) floating-point instruction set. -menu "ARM Cortex-M0/M0+/M1/M3/M4/M7/M23/M33 options" +config ARMV8_1_M_PMU + bool + help + This option is enabled when the CPU implements ARMv8-M Performance + Monitoring Unit (PMU). + +config ARMV8_M_PMU_EVENTCNT + int "Number of event counters in the Performance Monitoring Unit" + depends on ARMV8_1_M_PMU + range 2 8 + help + The number of event counters implemented. + +menu "ARM Cortex-M0/M0+/M1/M3/M4/M7/M23/M33/M55 options" depends on ARMV6_M_ARMV8_M_BASELINE || ARMV7_M_ARMV8_M_MAINLINE config GEN_ISR_TABLES diff --git a/soc/arm/arm/mps3/Kconfig.soc b/soc/arm/arm/mps3/Kconfig.soc index 86970e288cc..ae577fa549b 100644 --- a/soc/arm/arm/mps3/Kconfig.soc +++ b/soc/arm/arm/mps3/Kconfig.soc @@ -14,5 +14,10 @@ config SOC_MPS3_AN547 select ARMV8_M_DSP select ARMV8_1_M_MVEI select ARMV8_1_M_MVEF + select ARMV8_1_M_PMU endchoice + +config ARMV8_1_M_PMU_EVENTCNT + int + default 8 if SOC_MPS3_AN547 From 8d91ba200fa3460c51c4c4da6e0b2fc2a7676f3c Mon Sep 17 00:00:00 2001 From: Wilfried Chauveau Date: Mon, 6 Nov 2023 13:58:00 +0000 Subject: [PATCH 0744/3723] modules: cmsis: Move cortex_m default configuration to its own file MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Kconfig parameters, header’s default & silicon vendor’s SDK configuration for CMSIS Core, must be consistent. Depending on the inclusion order of the headers, this is currently not always the case. This change introduces consistency checks & enusers defaults match their Kconfig settings. Signed-off-by: Wilfried Chauveau --- modules/cmsis/cmsis_core_m.h | 88 +--------------- modules/cmsis/cmsis_core_m_defaults.h | 142 ++++++++++++++++++++++++++ soc/arm/arm/mps2/soc.h | 10 +- soc/arm/arm/mps3/soc.h | 15 +-- 4 files changed, 145 insertions(+), 110 deletions(-) create mode 100644 modules/cmsis/cmsis_core_m_defaults.h diff --git a/modules/cmsis/cmsis_core_m.h b/modules/cmsis/cmsis_core_m.h index 880ff614b5b..dc468ada364 100644 --- a/modules/cmsis/cmsis_core_m.h +++ b/modules/cmsis/cmsis_core_m.h @@ -1,5 +1,6 @@ /* * Copyright (c) 2017 Nordic Semiconductor ASA + * Copyright (c) 2023 Arm Limited * * SPDX-License-Identifier: Apache-2.0 */ @@ -18,91 +19,4 @@ #include -#ifdef __cplusplus -extern "C" { -#endif - -/* Fill in CMSIS required values for non-CMSIS compliant SoCs. - * Use __NVIC_PRIO_BITS as it is required and simple to check, but - * ultimately all SoCs will define their own CMSIS types and constants. - */ -#ifndef __NVIC_PRIO_BITS -typedef enum { - Reset_IRQn = -15, - NonMaskableInt_IRQn = -14, - HardFault_IRQn = -13, -#if defined(CONFIG_ARMV7_M_ARMV8_M_MAINLINE) - MemoryManagement_IRQn = -12, - BusFault_IRQn = -11, - UsageFault_IRQn = -10, -#if defined(CONFIG_ARM_SECURE_FIRMWARE) - SecureFault_IRQn = -9, -#endif /* CONFIG_ARM_SECURE_FIRMWARE */ -#endif /* CONFIG_ARMV7_M_ARMV8_M_MAINLINE */ - SVCall_IRQn = -5, - DebugMonitor_IRQn = -4, - PendSV_IRQn = -2, - SysTick_IRQn = -1, - Max_IRQn = CONFIG_NUM_IRQS, -} IRQn_Type; - -#if defined(CONFIG_CPU_CORTEX_M0) -#define __CM0_REV 0 -#elif defined(CONFIG_CPU_CORTEX_M0PLUS) -#define __CM0PLUS_REV 0 -#elif defined(CONFIG_CPU_CORTEX_M1) -#define __CM1_REV 0 -#elif defined(CONFIG_CPU_CORTEX_M3) -#define __CM3_REV 0 -#elif defined(CONFIG_CPU_CORTEX_M4) -#define __CM4_REV 0 -#elif defined(CONFIG_CPU_CORTEX_M7) -#define __CM7_REV 0 -#elif defined(CONFIG_CPU_CORTEX_M23) -#define __CM23_REV 0 -#elif defined(CONFIG_CPU_CORTEX_M33) -#define __CM33_REV 0 -#elif defined(CONFIG_CPU_CORTEX_M55) -#define __CM55_REV 0 -#else -#error "Unknown Cortex-M device" -#endif - -#ifndef __MPU_PRESENT -#define __MPU_PRESENT 0U -#endif -#define __NVIC_PRIO_BITS NUM_IRQ_PRIO_BITS -#define __Vendor_SysTickConfig 0 /* Default to standard SysTick */ -#endif /* __NVIC_PRIO_BITS */ - -#if __NVIC_PRIO_BITS != NUM_IRQ_PRIO_BITS -#error "NUM_IRQ_PRIO_BITS and __NVIC_PRIO_BITS are not set to the same value" -#endif - -#ifdef __cplusplus -} -#endif - -#if defined(CONFIG_CPU_CORTEX_M0) -#include -#elif defined(CONFIG_CPU_CORTEX_M0PLUS) -#include -#elif defined(CONFIG_CPU_CORTEX_M1) -#include -#elif defined(CONFIG_CPU_CORTEX_M3) -#include -#elif defined(CONFIG_CPU_CORTEX_M4) -#include -#elif defined(CONFIG_CPU_CORTEX_M7) -#include -#elif defined(CONFIG_CPU_CORTEX_M23) -#include -#elif defined(CONFIG_CPU_CORTEX_M33) -#include -#elif defined(CONFIG_CPU_CORTEX_M55) -#include -#else -#error "Unknown Cortex-M device" -#endif - #endif /* ZEPHYR_MODULES_CMSIS_CMSIS_M_H_ */ diff --git a/modules/cmsis/cmsis_core_m_defaults.h b/modules/cmsis/cmsis_core_m_defaults.h new file mode 100644 index 00000000000..bef62665493 --- /dev/null +++ b/modules/cmsis/cmsis_core_m_defaults.h @@ -0,0 +1,142 @@ +/* + * Copyright (c) 2017 Nordic Semiconductor ASA + * Copyright (c) 2023 Arm Limited + * + * SPDX-License-Identifier: Apache-2.0 + */ + +/** + * @file + * @brief CMSIS interface file + * + * This header populates the default values required to configure the + * ARM CMSIS Core headers. + */ + +#ifndef ZEPHYR_MODULES_CMSIS_CMSIS_M_DEFAULTS_H_ +#define ZEPHYR_MODULES_CMSIS_CMSIS_M_DEFAULTS_H_ + +#include + +#ifdef __cplusplus +extern "C" { +#endif + +/* Fill in CMSIS required values for non-CMSIS compliant SoCs. + * Use __NVIC_PRIO_BITS as it is required and simple to check, but + * ultimately all SoCs will define their own CMSIS types and constants. + */ +#ifndef __NVIC_PRIO_BITS +typedef enum { + Reset_IRQn = -15, + NonMaskableInt_IRQn = -14, + HardFault_IRQn = -13, +#if defined(CONFIG_ARMV7_M_ARMV8_M_MAINLINE) + MemoryManagement_IRQn = -12, + BusFault_IRQn = -11, + UsageFault_IRQn = -10, +#if defined(CONFIG_ARM_SECURE_FIRMWARE) + SecureFault_IRQn = -9, +#endif /* CONFIG_ARM_SECURE_FIRMWARE */ +#endif /* CONFIG_ARMV7_M_ARMV8_M_MAINLINE */ + SVCall_IRQn = -5, + DebugMonitor_IRQn = -4, + PendSV_IRQn = -2, + SysTick_IRQn = -1, + Max_IRQn = CONFIG_NUM_IRQS, +} IRQn_Type; + +#if defined(CONFIG_CPU_CORTEX_M0) +#define __CM0_REV 0 +#elif defined(CONFIG_CPU_CORTEX_M0PLUS) +#define __CM0PLUS_REV 0 +#elif defined(CONFIG_CPU_CORTEX_M1) +#define __CM1_REV 0 +#elif defined(CONFIG_CPU_CORTEX_M3) +#define __CM3_REV 0 +#elif defined(CONFIG_CPU_CORTEX_M4) +#define __CM4_REV 0 +#elif defined(CONFIG_CPU_CORTEX_M7) +#define __CM7_REV 0 +#elif defined(CONFIG_CPU_CORTEX_M23) +#define __CM23_REV 0 +#elif defined(CONFIG_CPU_CORTEX_M33) +#define __CM33_REV 0 +#elif defined(CONFIG_CPU_CORTEX_M55) +#define __CM55_REV 0 +#else +#error "Unknown Cortex-M device" +#endif + +#define __NVIC_PRIO_BITS NUM_IRQ_PRIO_BITS +#define __Vendor_SysTickConfig 0 /* Default to standard SysTick */ +#endif /* __NVIC_PRIO_BITS */ + +#ifndef __MPU_PRESENT +#define __MPU_PRESENT CONFIG_CPU_HAS_ARM_MPU +#endif + +#ifndef __FPU_PRESENT +#define __FPU_PRESENT CONFIG_CPU_HAS_FPU +#endif + +#ifndef __FPU_DP +#define __FPU_DP CONFIG_CPU_HAS_FPU_DOUBLE_PRECISION +#endif + +#ifndef __VTOR_PRESENT +#define __VTOR_PRESENT CONFIG_CPU_CORTEX_M_HAS_VTOR +#endif + +#ifndef __DSP_PRESENT +#define __DSP_PRESENT CONFIG_ARMV8_M_DSP +#endif + +#ifndef __ICACHE_PRESENT +#define __ICACHE_PRESENT CONFIG_CPU_HAS_ICACHE +#endif + +#ifndef __DCACHE_PRESENT +#define __DCACHE_PRESENT CONFIG_CPU_HAS_DCACHE +#endif + +#ifndef __MVE_PRESENT +#define __MVE_PRESENT CONFIG_ARMV8_1_M_MVEI +#endif + +#ifndef __SAUREGION_PRESENT +#define __SAUREGION_PRESENT CONFIG_CPU_HAS_ARM_SAU +#endif + +#ifndef __PMU_PRESENT +#define __PMU_PRESENT CONFIG_ARMV8_1_M_PMU +#define __PMU_NUM_EVENTCNT CONFIG_ARMV8_1_M_PMU_EVENTCNT +#endif + +#ifdef __cplusplus +} +#endif + +#if defined(CONFIG_CPU_CORTEX_M0) +#include +#elif defined(CONFIG_CPU_CORTEX_M0PLUS) +#include +#elif defined(CONFIG_CPU_CORTEX_M1) +#include +#elif defined(CONFIG_CPU_CORTEX_M3) +#include +#elif defined(CONFIG_CPU_CORTEX_M4) +#include +#elif defined(CONFIG_CPU_CORTEX_M7) +#include +#elif defined(CONFIG_CPU_CORTEX_M23) +#include +#elif defined(CONFIG_CPU_CORTEX_M33) +#include +#elif defined(CONFIG_CPU_CORTEX_M55) +#include +#else +#error "Unknown Cortex-M device" +#endif + +#endif /* ZEPHYR_MODULES_CMSIS_CMSIS_M_DEFAULTS_H_ */ diff --git a/soc/arm/arm/mps2/soc.h b/soc/arm/arm/mps2/soc.h index 594d3d084c1..822c7ee01bd 100644 --- a/soc/arm/arm/mps2/soc.h +++ b/soc/arm/arm/mps2/soc.h @@ -7,15 +7,7 @@ #ifndef _SOC_H_ #define _SOC_H_ -#define __MPU_PRESENT 1 - -#if defined(CONFIG_SOC_MPS2_AN521) -#define __SAUREGION_PRESENT CONFIG_CPU_HAS_ARM_SAU -#define __FPU_PRESENT CONFIG_CPU_HAS_FPU -#define __DSP_PRESENT CONFIG_ARMV8_M_DSP - -#endif - +#include #include extern void wakeup_cpu1(void); diff --git a/soc/arm/arm/mps3/soc.h b/soc/arm/arm/mps3/soc.h index 6a325074cf2..c3a59da1c0d 100644 --- a/soc/arm/arm/mps3/soc.h +++ b/soc/arm/arm/mps3/soc.h @@ -7,19 +7,6 @@ #ifndef _SOC_H_ #define _SOC_H_ -#define __MPU_PRESENT 1 - -#if defined(CONFIG_SOC_MPS3_AN547) -#define __SAUREGION_PRESENT 1U /* SAU regions present */ -#define __FPU_PRESENT CONFIG_CPU_HAS_FPU -#define __DSP_PRESENT 1U /* DSP extension present */ -#define __MVE_PRESENT 1U /* MVE extensions present */ -#define __MVE_FP 1U /* MVE floating point present */ -#define __ICACHE_PRESENT 1U /* ICACHE present */ -#define __DCACHE_PRESENT 1U /* DCACHE present */ -#define __PMU_PRESENT 1U /* PMU present */ -#define __PMU_NUM_EVENTCNT 8U /* PMU Event Counters */ -#endif - +#include #endif /* _SOC_H_ */ From 3599fb47e12dd1f16fc620f5915eb408c1ada427 Mon Sep 17 00:00:00 2001 From: Wilfried Chauveau Date: Mon, 6 Nov 2023 14:23:19 +0000 Subject: [PATCH 0745/3723] modules: cmsis: Add consistency checks MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This change adds checks to validate consistency between Zephyr’s Kconfig settings and cmsis configuration defined in SiP’s sdk provided headers. This change also introduces a config to enable cmsis’ own checks which emits warnings if a parameter relies on auto-populated default values. Signed-off-by: Wilfried Chauveau --- modules/cmsis/Kconfig | 7 ++++++ modules/cmsis/cmsis_core_m.h | 49 ++++++++++++++++++++++++++++++++++++ 2 files changed, 56 insertions(+) diff --git a/modules/cmsis/Kconfig b/modules/cmsis/Kconfig index 4b5a8ee2855..eff0be6f40c 100644 --- a/modules/cmsis/Kconfig +++ b/modules/cmsis/Kconfig @@ -21,4 +21,11 @@ config HAS_CMSIS_CORE_R config HAS_CMSIS_CORE_M bool +config CMSIS_M_CHECK_DEVICE_DEFINES + bool "Check device defines" + default n + depends on HAS_CMSIS_CORE_M + help + This options enables the validation of CMSIS configuration flags. + endif diff --git a/modules/cmsis/cmsis_core_m.h b/modules/cmsis/cmsis_core_m.h index dc468ada364..e7382633945 100644 --- a/modules/cmsis/cmsis_core_m.h +++ b/modules/cmsis/cmsis_core_m.h @@ -15,8 +15,57 @@ #ifndef ZEPHYR_MODULES_CMSIS_CMSIS_M_H_ #define ZEPHYR_MODULES_CMSIS_CMSIS_M_H_ +#if defined(CONFIG_CMSIS_M_CHECK_DEVICE_DEFINES) && CONFIG_CMSIS_M_CHECK_DEVICE_DEFINES == 1U +#define __CHECK_DEVICE_DEFINES 1U +#endif + #include #include +#if __NVIC_PRIO_BITS != NUM_IRQ_PRIO_BITS +#error "NUM_IRQ_PRIO_BITS and __NVIC_PRIO_BITS are not set to the same value" +#endif + +#if __MPU_PRESENT != CONFIG_CPU_HAS_ARM_MPU +#error "__MPU_PRESENT and CONFIG_CPU_HAS_ARM_MPU are not set to the same value" +#endif + +#if __FPU_PRESENT != CONFIG_CPU_HAS_FPU +#error "__FPU_PRESENT and CONFIG_CPU_HAS_FPU are not set to the same value" +#endif + + +/* VTOR is only optional on armv6-m and armv8-m baseline. __VTOR_PRESENT is often + * left undefined on platform where it is not optional. + */ +#if defined(CONFIG_ARMV6_M_ARMV8_M_BASELINE) && \ + (__VTOR_PRESENT != CONFIG_CPU_CORTEX_M_HAS_VTOR) +#error "__VTOR_PRESENT and CONFIG_CPU_CORTEX_M_HAS_VTOR are not set to the same value." +#endif + +/* Some platform’s sdk incorrectly define __DSP_PRESENT for Cortex-M4 & Cortex-M7 + * DSP extension. __ARM_FEATURE_DSP is set by the compiler for these. So ignore + * __DSP_PRESENT discrepancy when __ARM_FEATURE_DSP is defined. + */ +#if !defined(__ARM_FEATURE_DSP) && (__DSP_PRESENT != CONFIG_ARMV8_M_DSP) +#error "__DSP_PRESENT and CONFIG_ARMV8_M_DSP are not set to the same value" +#endif + +#if __ICACHE_PRESENT != CONFIG_CPU_HAS_ICACHE +#error "__ICACHE_PRESENT and CONFIG_CPU_HAS_ICACHE are not set to the same value" +#endif + +#if __DCACHE_PRESENT != CONFIG_CPU_HAS_DCACHE +#error "__DCACHE_PRESENT and CONFIG_CPU_HAS_DCACHE are not set to the same value" +#endif + +#if __MVE_PRESENT != CONFIG_ARMV8_1_M_MVEI +#error "__MVE_PRESENT and CONFIG_ARMV8_1_M_MVEI are not set to the same value" +#endif + +#if __SAUREGION_PRESENT != CONFIG_CPU_HAS_ARM_SAU +#error "__SAUREGION_PRESENT and CONFIG_CPU_HAS_ARM_SAU are not set to the same value" +#endif + #endif /* ZEPHYR_MODULES_CMSIS_CMSIS_M_H_ */ From 7226f985fccb3d378b267e8d8fc0b4d92385872e Mon Sep 17 00:00:00 2001 From: Wilfried Chauveau Date: Tue, 31 Oct 2023 23:35:38 +0000 Subject: [PATCH 0746/3723] soc: arm: nxp_kinetis: remove unecessary includes MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This changes remove extraneous includes causing issues with cycles in includes subsequently having code requiring definitions from CMSIS while it’s configuration hasn’t completed yet. Signed-off-by: Wilfried Chauveau --- soc/arm/nxp_kinetis/k2x/soc.h | 3 --- 1 file changed, 3 deletions(-) diff --git a/soc/arm/nxp_kinetis/k2x/soc.h b/soc/arm/nxp_kinetis/k2x/soc.h index cb88009a49d..88a93b62ef6 100644 --- a/soc/arm/nxp_kinetis/k2x/soc.h +++ b/soc/arm/nxp_kinetis/k2x/soc.h @@ -33,9 +33,6 @@ extern "C" { #ifndef _ASMLANGUAGE #include -#include -#include -#include #endif /* !_ASMLANGUAGE */ From 29ffaaa0b6adcc6d690f1a1ae6f894d2aeb102e8 Mon Sep 17 00:00:00 2001 From: Wilfried Chauveau Date: Sun, 5 Nov 2023 04:09:36 +0000 Subject: [PATCH 0747/3723] arch: arm: cortex_m: Remove CPU_HAS_*CACHE from CPU_CORTEX_M7 Caches are optional on cortex-m7, having CPU_HAS_*CACHE in CPU_CORTEX_M7 definition renders them mandatory. Signed-off-by: Wilfried Chauveau --- arch/arm/core/cortex_m/Kconfig | 2 -- soc/arm/atmel_sam/same70/Kconfig.series | 2 ++ soc/arm/atmel_sam/samv71/Kconfig.series | 2 ++ soc/arm/nxp_imx/mimx8ml8_m7/Kconfig.series | 2 ++ soc/arm/nxp_imx/rt/Kconfig.soc | 8 ++++++ soc/arm/nxp_kinetis/kv5x/Kconfig.series | 2 ++ soc/arm/nxp_s32/s32k3/Kconfig.series | 2 ++ soc/arm/st_stm32/stm32f7/Kconfig.series | 2 ++ soc/arm/st_stm32/stm32h7/Kconfig.soc | 32 ++++++++++++++++++++++ 9 files changed, 52 insertions(+), 2 deletions(-) diff --git a/arch/arm/core/cortex_m/Kconfig b/arch/arm/core/cortex_m/Kconfig index 61dd3dbba3c..e2a0fbb42da 100644 --- a/arch/arm/core/cortex_m/Kconfig +++ b/arch/arm/core/cortex_m/Kconfig @@ -78,8 +78,6 @@ config CPU_CORTEX_M7 select CPU_CORTEX_M select ARMV7_M_ARMV8_M_MAINLINE select ARMV7_M_ARMV8_M_FP if CPU_HAS_FPU - select CPU_HAS_DCACHE - select CPU_HAS_ICACHE help This option signifies the use of a Cortex-M7 CPU diff --git a/soc/arm/atmel_sam/same70/Kconfig.series b/soc/arm/atmel_sam/same70/Kconfig.series index 0e19a2197ba..66ceeb6ca3e 100644 --- a/soc/arm/atmel_sam/same70/Kconfig.series +++ b/soc/arm/atmel_sam/same70/Kconfig.series @@ -11,6 +11,8 @@ config SOC_SERIES_SAME70 select CPU_CORTEX_M_HAS_DWT select CPU_HAS_ARM_MPU select CPU_HAS_FPU_DOUBLE_PRECISION + select CPU_HAS_ICACHE + select CPU_HAS_DCACHE select SOC_FAMILY_SAM select PLATFORM_SPECIFIC_INIT select ASF diff --git a/soc/arm/atmel_sam/samv71/Kconfig.series b/soc/arm/atmel_sam/samv71/Kconfig.series index 49de040aff8..543def9d9a2 100644 --- a/soc/arm/atmel_sam/samv71/Kconfig.series +++ b/soc/arm/atmel_sam/samv71/Kconfig.series @@ -11,6 +11,8 @@ config SOC_SERIES_SAMV71 select CPU_CORTEX_M_HAS_DWT select CPU_HAS_ARM_MPU select CPU_HAS_FPU_DOUBLE_PRECISION + select CPU_HAS_ICACHE + select CPU_HAS_DCACHE select SOC_FAMILY_SAM select PLATFORM_SPECIFIC_INIT select ASF diff --git a/soc/arm/nxp_imx/mimx8ml8_m7/Kconfig.series b/soc/arm/nxp_imx/mimx8ml8_m7/Kconfig.series index fc55afd4aae..f1eb1fd40fd 100644 --- a/soc/arm/nxp_imx/mimx8ml8_m7/Kconfig.series +++ b/soc/arm/nxp_imx/mimx8ml8_m7/Kconfig.series @@ -9,6 +9,8 @@ config SOC_SERIES_IMX8ML_M7 select CPU_CORTEX_M7 select SOC_FAMILY_IMX select CPU_HAS_FPU + select CPU_HAS_ICACHE + select CPU_HAS_DCACHE select INIT_VIDEO_PLL help Enable support for i.MX8ML M7 MCU series diff --git a/soc/arm/nxp_imx/rt/Kconfig.soc b/soc/arm/nxp_imx/rt/Kconfig.soc index 0058993e825..f3c2395cefe 100644 --- a/soc/arm/nxp_imx/rt/Kconfig.soc +++ b/soc/arm/nxp_imx/rt/Kconfig.soc @@ -22,6 +22,8 @@ config SOC_MIMXRT1011 select HAS_MCUX_GPT select HAS_MCUX_TRNG select CPU_HAS_ARM_MPU + select CPU_HAS_ICACHE + select CPU_HAS_DCACHE select INIT_ENET_PLL select HAS_MCUX_USB_EHCI select HAS_MCUX_EDMA @@ -338,6 +340,8 @@ config SOC_MIMXRT1176_CM7 select INIT_ENET_PLL if NET_L2_ETHERNET && ETH_DRIVER select INIT_VIDEO_PLL select HAS_MCUX_EDMA + select CPU_HAS_ICACHE + select CPU_HAS_DCACHE select CPU_HAS_FPU_DOUBLE_PRECISION select BYPASS_LDO_LPSR select ADJUST_LDO @@ -402,6 +406,8 @@ config SOC_MIMXRT1166_CM7 select HAS_MCUX_GPT select HAS_MCUX_FLEXCAN select CPU_HAS_ARM_MPU + select CPU_HAS_ICACHE + select CPU_HAS_DCACHE select INIT_ARM_PLL select INIT_ENET_PLL if NET_L2_ETHERNET && ETH_DRIVER select INIT_VIDEO_PLL @@ -659,6 +665,8 @@ config SOC_SERIES_IMX_RT10XX bool "i.MX RT 10XX Series" select CPU_CORTEX_M7 select CPU_CORTEX_M_HAS_DWT + select CPU_HAS_ICACHE + select CPU_HAS_DCACHE select PLATFORM_SPECIFIC_INIT config SOC_SERIES_IMX_RT11XX diff --git a/soc/arm/nxp_kinetis/kv5x/Kconfig.series b/soc/arm/nxp_kinetis/kv5x/Kconfig.series index 009d31ea350..0df355a5823 100644 --- a/soc/arm/nxp_kinetis/kv5x/Kconfig.series +++ b/soc/arm/nxp_kinetis/kv5x/Kconfig.series @@ -11,6 +11,8 @@ config SOC_SERIES_KINETIS_KV5X select SOC_FAMILY_KINETIS select CPU_HAS_ARM_MPU select CPU_HAS_FPU + select CPU_HAS_ICACHE + select CPU_HAS_DCACHE select CLOCK_CONTROL select HAS_MCUX select HAS_MCUX_ADC16 diff --git a/soc/arm/nxp_s32/s32k3/Kconfig.series b/soc/arm/nxp_s32/s32k3/Kconfig.series index 50be01fe690..ac90439b644 100644 --- a/soc/arm/nxp_s32/s32k3/Kconfig.series +++ b/soc/arm/nxp_s32/s32k3/Kconfig.series @@ -11,6 +11,8 @@ config SOC_SERIES_S32K3XX select HAS_NXP_S32_HAL select CPU_HAS_FPU select CPU_HAS_ARM_MPU + select CPU_HAS_ICACHE + select CPU_HAS_DCACHE select CPU_HAS_CUSTOM_FIXED_SOC_MPU_REGIONS select PLATFORM_SPECIFIC_INIT if XIP select USE_DT_CODE_PARTITION if XIP diff --git a/soc/arm/st_stm32/stm32f7/Kconfig.series b/soc/arm/st_stm32/stm32f7/Kconfig.series index 860aea7e716..a298fa2b579 100644 --- a/soc/arm/st_stm32/stm32f7/Kconfig.series +++ b/soc/arm/st_stm32/stm32f7/Kconfig.series @@ -9,6 +9,8 @@ config SOC_SERIES_STM32F7X select CPU_CORTEX_M7 select CPU_CORTEX_M_HAS_DWT select CPU_HAS_FPU + select CPU_HAS_ICACHE + select CPU_HAS_DCACHE select SOC_FAMILY_STM32 select HAS_STM32CUBE select CPU_HAS_ARM_MPU diff --git a/soc/arm/st_stm32/stm32h7/Kconfig.soc b/soc/arm/st_stm32/stm32h7/Kconfig.soc index 7856c52652a..4f7441a6fdc 100644 --- a/soc/arm/st_stm32/stm32h7/Kconfig.soc +++ b/soc/arm/st_stm32/stm32h7/Kconfig.soc @@ -16,81 +16,113 @@ choice config SOC_STM32H723XX bool "STM32H723XX" select CPU_CORTEX_M7 + select CPU_HAS_ICACHE + select CPU_HAS_DCACHE select CPU_HAS_FPU_DOUBLE_PRECISION config SOC_STM32H725XX bool "STM32H725XX" select CPU_CORTEX_M7 + select CPU_HAS_ICACHE + select CPU_HAS_DCACHE select CPU_HAS_FPU_DOUBLE_PRECISION config SOC_STM32H730XX bool "STM32H730XX" select CPU_CORTEX_M7 + select CPU_HAS_ICACHE + select CPU_HAS_DCACHE select CPU_HAS_FPU_DOUBLE_PRECISION config SOC_STM32H730XXQ bool "STM32H730XXQ" select CPU_CORTEX_M7 + select CPU_HAS_ICACHE + select CPU_HAS_DCACHE select CPU_HAS_FPU_DOUBLE_PRECISION config SOC_STM32H735XX bool "STM32H735XX" select CPU_CORTEX_M7 + select CPU_HAS_ICACHE + select CPU_HAS_DCACHE select CPU_HAS_FPU_DOUBLE_PRECISION config SOC_STM32H743XX bool "STM32H743XX" select CPU_CORTEX_M7 + select CPU_HAS_ICACHE + select CPU_HAS_DCACHE select CPU_HAS_FPU_DOUBLE_PRECISION config SOC_STM32H745XX bool "STM32H745XX" select CPU_HAS_FPU_DOUBLE_PRECISION if CPU_CORTEX_M7 + select CPU_HAS_ICACHE if CPU_CORTEX_M7 + select CPU_HAS_DCACHE if CPU_CORTEX_M7 select STM32H7_DUAL_CORE config SOC_STM32H747XX bool "STM32H747XX" select CPU_HAS_FPU_DOUBLE_PRECISION if CPU_CORTEX_M7 + select CPU_HAS_ICACHE if CPU_CORTEX_M7 + select CPU_HAS_DCACHE if CPU_CORTEX_M7 select STM32H7_DUAL_CORE config SOC_STM32H750XX bool "STM32H750XX" select CPU_CORTEX_M7 + select CPU_HAS_ICACHE + select CPU_HAS_DCACHE select CPU_HAS_FPU_DOUBLE_PRECISION config SOC_STM32H753XX bool "STM32H753XX" select CPU_CORTEX_M7 + select CPU_HAS_ICACHE + select CPU_HAS_DCACHE select CPU_HAS_FPU_DOUBLE_PRECISION config SOC_STM32H7A3XX bool "STM32H7A3XX" select CPU_CORTEX_M7 + select CPU_HAS_ICACHE + select CPU_HAS_DCACHE select CPU_HAS_FPU_DOUBLE_PRECISION config SOC_STM32H7A3XXQ bool "STM32H7A3XXQ" select CPU_CORTEX_M7 + select CPU_HAS_ICACHE + select CPU_HAS_DCACHE select CPU_HAS_FPU_DOUBLE_PRECISION config SOC_STM32H7B0XX bool "STM32H7B0XX" select CPU_CORTEX_M7 + select CPU_HAS_ICACHE + select CPU_HAS_DCACHE select CPU_HAS_FPU_DOUBLE_PRECISION config SOC_STM32H7B0XXQ bool "STM32H7B0XXQ" select CPU_CORTEX_M7 + select CPU_HAS_ICACHE + select CPU_HAS_DCACHE select CPU_HAS_FPU_DOUBLE_PRECISION config SOC_STM32H7B3XX bool "STM32H7B3XX" select CPU_CORTEX_M7 + select CPU_HAS_ICACHE + select CPU_HAS_DCACHE select CPU_HAS_FPU_DOUBLE_PRECISION config SOC_STM32H7B3XXQ bool "STM32H7B3XXQ" select CPU_CORTEX_M7 + select CPU_HAS_ICACHE + select CPU_HAS_DCACHE select CPU_HAS_FPU_DOUBLE_PRECISION endchoice From af3a19106afe494f9ca7616e923e2b069e880c71 Mon Sep 17 00:00:00 2001 From: Wilfried Chauveau Date: Tue, 7 Nov 2023 12:57:29 +0000 Subject: [PATCH 0748/3723] soc: arm: fix missing configs & defines Some SoC have missing feature selections in their Kconfig. Some others are missing includes of CMSIS-Core headers. Signed-off-by: Wilfried Chauveau --- soc/arm/ambiq/apollo4x/Kconfig.series | 1 + soc/arm/arm/designstart/soc.h | 3 +-- soc/arm/arm/musca_s1/Kconfig.soc | 2 ++ soc/arm/aspeed/ast10x0/soc.h | 2 ++ soc/arm/atmel_sam0/samc21/Kconfig.series | 1 + soc/arm/bcm_vk/valkyrie/soc.h | 2 ++ soc/arm/bcm_vk/viper/soc.h | 4 +++- soc/arm/cypress/Kconfig | 3 +++ soc/arm/gigadevice/gd32a50x/Kconfig.series | 1 + soc/arm/gigadevice/gd32e50x/Kconfig.series | 1 + soc/arm/gigadevice/gd32l23x/Kconfig.series | 1 + soc/arm/microchip_mec/mec1501/Kconfig.series | 1 + soc/arm/microchip_mec/mec172x/soc.h | 2 ++ soc/arm/nuvoton_npcx/npcx4/soc.h | 4 +--- soc/arm/nuvoton_npcx/npcx7/soc.h | 4 +--- soc/arm/nuvoton_npcx/npcx9/soc.h | 4 +--- soc/arm/nxp_imx/mcimx6x_m4/Kconfig.series | 1 + soc/arm/nxp_imx/mcimx7_m4/Kconfig.series | 1 + soc/arm/nxp_imx/mimx8mm6_m4/Kconfig.series | 1 + soc/arm/nxp_imx/mimx8mq6_m4/Kconfig.series | 1 + soc/arm/nxp_imx/rt/Kconfig.soc | 4 ++++ soc/arm/nxp_kinetis/kl2x/Kconfig.series | 1 + soc/arm/nxp_kinetis/kwx/Kconfig.series | 1 + soc/arm/nxp_lpc/lpc11u6x/soc.h | 1 + soc/arm/nxp_lpc/lpc51u68/Kconfig.series | 1 + soc/arm/nxp_lpc/lpc51u68/soc.h | 2 ++ soc/arm/nxp_lpc/lpc54xxx/Kconfig.soc | 1 + soc/arm/nxp_lpc/lpc55xxx/Kconfig.soc | 1 + soc/arm/nxp_s32/s32k3/soc.h | 1 + soc/arm/quicklogic_eos_s3/Kconfig.soc | 1 + soc/arm/renesas_ra/common/ra_common_soc.h | 2 ++ soc/arm/renesas_smartbond/da1469x/Kconfig.series | 1 + soc/arm/rpi_pico/rp2/soc.h | 4 +--- soc/arm/silabs_exx32/efm32hg/Kconfig.series | 1 + soc/arm/silabs_exx32/efr32mg21/Kconfig.series | 1 + soc/arm/st_stm32/stm32mp1/Kconfig.series | 1 + soc/arm/ti_k3/am62x_m4/soc.h | 2 ++ soc/arm/ti_lm3s6965/soc.h | 1 + soc/arm/ti_simplelink/cc13x2_cc26x2/soc.h | 4 ++++ soc/arm/ti_simplelink/cc32xx/soc.h | 4 ++++ soc/arm/ti_simplelink/msp432p4xx/Kconfig.series | 1 + 41 files changed, 61 insertions(+), 15 deletions(-) diff --git a/soc/arm/ambiq/apollo4x/Kconfig.series b/soc/arm/ambiq/apollo4x/Kconfig.series index b7982d3609e..a9e72567206 100644 --- a/soc/arm/ambiq/apollo4x/Kconfig.series +++ b/soc/arm/ambiq/apollo4x/Kconfig.series @@ -10,6 +10,7 @@ config SOC_SERIES_APOLLO4X select CPU_CORTEX_M4 select CPU_CORTEX_M_HAS_DWT select CPU_HAS_FPU + select CPU_HAS_ARM_MPU select SOC_FAMILY_AMBIQ select HAS_SWO select AMBIQ_HAL diff --git a/soc/arm/arm/designstart/soc.h b/soc/arm/arm/designstart/soc.h index ec58467f923..a9bcdb4e9cd 100644 --- a/soc/arm/arm/designstart/soc.h +++ b/soc/arm/arm/designstart/soc.h @@ -7,7 +7,6 @@ #ifndef _SOC_H_ #define _SOC_H_ - -#define __MPU_PRESENT CONFIG_CPU_HAS_ARM_MPU +#include #endif /* _SOC_H_ */ diff --git a/soc/arm/arm/musca_s1/Kconfig.soc b/soc/arm/arm/musca_s1/Kconfig.soc index 9bf02614308..0c0763fae2a 100644 --- a/soc/arm/arm/musca_s1/Kconfig.soc +++ b/soc/arm/arm/musca_s1/Kconfig.soc @@ -11,5 +11,7 @@ config SOC_V2M_MUSCA_S1 select CPU_HAS_ARM_SAU select CPU_HAS_ARM_MPU select CPU_CORTEX_M_HAS_DWT + select CPU_HAS_FPU + select ARMV8_M_DSP endchoice diff --git a/soc/arm/aspeed/ast10x0/soc.h b/soc/arm/aspeed/ast10x0/soc.h index f45df84c128..be1cced5da2 100644 --- a/soc/arm/aspeed/ast10x0/soc.h +++ b/soc/arm/aspeed/ast10x0/soc.h @@ -25,4 +25,6 @@ void aspeed_print_sysrst_info(void); +#include + #endif /* ZEPHYR_SOC_ARM_ASPEED_AST10X0_SOC_H_*/ diff --git a/soc/arm/atmel_sam0/samc21/Kconfig.series b/soc/arm/atmel_sam0/samc21/Kconfig.series index 044a7aea229..acb83679e18 100644 --- a/soc/arm/atmel_sam0/samc21/Kconfig.series +++ b/soc/arm/atmel_sam0/samc21/Kconfig.series @@ -10,6 +10,7 @@ config SOC_SERIES_SAMC21 select CPU_CORTEX_M0PLUS select CPU_CORTEX_M_HAS_SYSTICK select CPU_CORTEX_M_HAS_VTOR + select CPU_HAS_ARM_MPU select SOC_FAMILY_SAM0 select PLATFORM_SPECIFIC_INIT select ASF diff --git a/soc/arm/bcm_vk/valkyrie/soc.h b/soc/arm/bcm_vk/valkyrie/soc.h index 26863fbfea0..c3e21a89581 100644 --- a/soc/arm/bcm_vk/valkyrie/soc.h +++ b/soc/arm/bcm_vk/valkyrie/soc.h @@ -292,4 +292,6 @@ typedef enum IRQn { #define PCIE0_PERST_FE_INTR BIT(1) #define PCIE0_PERST_INB_FE_INTR BIT(3) +#include + #endif diff --git a/soc/arm/bcm_vk/viper/soc.h b/soc/arm/bcm_vk/viper/soc.h index 6695e92ef5c..06bf59fb24d 100644 --- a/soc/arm/bcm_vk/viper/soc.h +++ b/soc/arm/bcm_vk/viper/soc.h @@ -9,10 +9,10 @@ #include #include +#include #ifndef _ASMLANGUAGE - /* Interrupt Number Definition */ typedef enum IRQn { /* CORTEX-M7 Processor Exceptions Numbers */ @@ -301,4 +301,6 @@ typedef enum IRQn { #define LS_ICFG_PMON_LITE_SW_RESETN 0x482f0120 #define PCIE_PMON_LITE_SW_RESETN BIT(0) +#include + #endif diff --git a/soc/arm/cypress/Kconfig b/soc/arm/cypress/Kconfig index 352c66b4e76..cb76ccb1090 100644 --- a/soc/arm/cypress/Kconfig +++ b/soc/arm/cypress/Kconfig @@ -12,12 +12,15 @@ config SOC_PSOC6_M0 select CPU_CORTEX_M0PLUS select CPU_CORTEX_M_HAS_SYSTICK select CPU_CORTEX_M_HAS_VTOR + select CPU_HAS_ARM_MPU config SOC_PSOC6_M4 bool "SOC_PSOC6_M4" select CPU_CORTEX_M4 select CPU_CORTEX_M_HAS_DWT select CPU_CORTEX_M_HAS_SYSTICK + select CPU_HAS_ARM_MPU + select CPU_HAS_FPU endchoice diff --git a/soc/arm/gigadevice/gd32a50x/Kconfig.series b/soc/arm/gigadevice/gd32a50x/Kconfig.series index 96fc8c1d0af..2488c643727 100644 --- a/soc/arm/gigadevice/gd32a50x/Kconfig.series +++ b/soc/arm/gigadevice/gd32a50x/Kconfig.series @@ -6,6 +6,7 @@ config SOC_SERIES_GD32A50X select ARM select CPU_HAS_ARM_MPU select CPU_HAS_FPU + select ARMV8_M_DSP select CPU_CORTEX_M33 select SOC_FAMILY_GD32_ARM select GD32_HAS_AF_PINMUX diff --git a/soc/arm/gigadevice/gd32e50x/Kconfig.series b/soc/arm/gigadevice/gd32e50x/Kconfig.series index 8bc3f71118e..546ca456793 100644 --- a/soc/arm/gigadevice/gd32e50x/Kconfig.series +++ b/soc/arm/gigadevice/gd32e50x/Kconfig.series @@ -7,6 +7,7 @@ config SOC_SERIES_GD32E50X select CPU_HAS_ARM_MPU select CPU_HAS_FPU select CPU_CORTEX_M33 + select ARMV8_M_DSP select SOC_FAMILY_GD32_ARM select GD32_HAS_AFIO_PINMUX select GD32_HAS_IRC_40K diff --git a/soc/arm/gigadevice/gd32l23x/Kconfig.series b/soc/arm/gigadevice/gd32l23x/Kconfig.series index 5bdb0dba7d3..d6125ca4152 100644 --- a/soc/arm/gigadevice/gd32l23x/Kconfig.series +++ b/soc/arm/gigadevice/gd32l23x/Kconfig.series @@ -6,6 +6,7 @@ config SOC_SERIES_GD32L23X select ARM select CPU_CORTEX_M23 select CPU_CORTEX_M_HAS_SYSTICK + select CPU_CORTEX_M_HAS_VTOR select SOC_FAMILY_GD32_ARM select GD32_HAS_AF_PINMUX select GD32_HAS_IRC_32K diff --git a/soc/arm/microchip_mec/mec1501/Kconfig.series b/soc/arm/microchip_mec/mec1501/Kconfig.series index d3b679bb557..92dc6f3f8f9 100644 --- a/soc/arm/microchip_mec/mec1501/Kconfig.series +++ b/soc/arm/microchip_mec/mec1501/Kconfig.series @@ -8,6 +8,7 @@ config SOC_SERIES_MEC1501X select ARM select CPU_CORTEX_M4 select CPU_CORTEX_M_HAS_DWT + select CPU_HAS_ARM_MPU select SOC_FAMILY_MEC select HAS_PM help diff --git a/soc/arm/microchip_mec/mec172x/soc.h b/soc/arm/microchip_mec/mec172x/soc.h index 3bf4f533fdb..19afc4e920a 100644 --- a/soc/arm/microchip_mec/mec172x/soc.h +++ b/soc/arm/microchip_mec/mec172x/soc.h @@ -242,6 +242,8 @@ typedef enum { MAX_IRQn } IRQn_Type; +#include + #include /* chip specific register defines */ diff --git a/soc/arm/nuvoton_npcx/npcx4/soc.h b/soc/arm/nuvoton_npcx/npcx4/soc.h index a9d4e88424b..9c780ca034a 100644 --- a/soc/arm/nuvoton_npcx/npcx4/soc.h +++ b/soc/arm/nuvoton_npcx/npcx4/soc.h @@ -7,9 +7,7 @@ #ifndef _NUVOTON_NPCX_SOC_H_ #define _NUVOTON_NPCX_SOC_H_ -/* CMSIS required definitions */ -#define __FPU_PRESENT CONFIG_CPU_HAS_FPU -#define __MPU_PRESENT CONFIG_CPU_HAS_ARM_MPU +#include /* NPCX4 SCFG multi-registers */ #define NPCX_DEVALT_OFFSET(n) (0x010 + n) diff --git a/soc/arm/nuvoton_npcx/npcx7/soc.h b/soc/arm/nuvoton_npcx/npcx7/soc.h index 7099552cec3..9b523ce1b8f 100644 --- a/soc/arm/nuvoton_npcx/npcx7/soc.h +++ b/soc/arm/nuvoton_npcx/npcx7/soc.h @@ -7,9 +7,7 @@ #ifndef _NUVOTON_NPCX_SOC_H_ #define _NUVOTON_NPCX_SOC_H_ -/* CMSIS required definitions */ -#define __FPU_PRESENT CONFIG_CPU_HAS_FPU -#define __MPU_PRESENT CONFIG_CPU_HAS_ARM_MPU +#include /* NPCX7 SCFG multi-registers offset */ #define NPCX_DEVALT_OFFSET(n) (0x010 + n) diff --git a/soc/arm/nuvoton_npcx/npcx9/soc.h b/soc/arm/nuvoton_npcx/npcx9/soc.h index 6b6c3f30a44..2ce745650fb 100644 --- a/soc/arm/nuvoton_npcx/npcx9/soc.h +++ b/soc/arm/nuvoton_npcx/npcx9/soc.h @@ -7,9 +7,7 @@ #ifndef _NUVOTON_NPCX_SOC_H_ #define _NUVOTON_NPCX_SOC_H_ -/* CMSIS required definitions */ -#define __FPU_PRESENT CONFIG_CPU_HAS_FPU -#define __MPU_PRESENT CONFIG_CPU_HAS_ARM_MPU +#include /* NPCX9 SCFG multi-registers */ #define NPCX_DEVALT_OFFSET(n) (0x010 + n) diff --git a/soc/arm/nxp_imx/mcimx6x_m4/Kconfig.series b/soc/arm/nxp_imx/mcimx6x_m4/Kconfig.series index ac0428eff53..7279ac8596e 100644 --- a/soc/arm/nxp_imx/mcimx6x_m4/Kconfig.series +++ b/soc/arm/nxp_imx/mcimx6x_m4/Kconfig.series @@ -11,6 +11,7 @@ config SOC_SERIES_IMX_6X_M4 select HAS_IMX_HAL select SOC_FAMILY_IMX select CPU_HAS_FPU + select CPU_HAS_ARM_MPU select CLOCK_CONTROL help Enable support for M4 core of i.MX 6SoloX MCU series diff --git a/soc/arm/nxp_imx/mcimx7_m4/Kconfig.series b/soc/arm/nxp_imx/mcimx7_m4/Kconfig.series index be0065cb373..e7ae54bcbda 100644 --- a/soc/arm/nxp_imx/mcimx7_m4/Kconfig.series +++ b/soc/arm/nxp_imx/mcimx7_m4/Kconfig.series @@ -11,5 +11,6 @@ config SOC_SERIES_IMX7_M4 select SOC_FAMILY_IMX select CLOCK_CONTROL select CPU_HAS_FPU + select CPU_HAS_ARM_MPU help Enable support for i.MX7 M4 MCU series diff --git a/soc/arm/nxp_imx/mimx8mm6_m4/Kconfig.series b/soc/arm/nxp_imx/mimx8mm6_m4/Kconfig.series index dddb12d1b70..f860a7fbd26 100644 --- a/soc/arm/nxp_imx/mimx8mm6_m4/Kconfig.series +++ b/soc/arm/nxp_imx/mimx8mm6_m4/Kconfig.series @@ -9,5 +9,6 @@ config SOC_SERIES_IMX8MM_M4 select CPU_CORTEX_M4 select SOC_FAMILY_IMX select CPU_HAS_FPU + select CPU_HAS_ARM_MPU help Enable support for i.MX8MM M4 MCU series diff --git a/soc/arm/nxp_imx/mimx8mq6_m4/Kconfig.series b/soc/arm/nxp_imx/mimx8mq6_m4/Kconfig.series index c4b16d3fb5c..3933037c3a0 100644 --- a/soc/arm/nxp_imx/mimx8mq6_m4/Kconfig.series +++ b/soc/arm/nxp_imx/mimx8mq6_m4/Kconfig.series @@ -9,5 +9,6 @@ config SOC_SERIES_IMX8MQ_M4 select CPU_CORTEX_M4 select SOC_FAMILY_IMX select CPU_HAS_FPU + select CPU_HAS_ARM_MPU help Enable support for i.MX8MQ M4 MCU series diff --git a/soc/arm/nxp_imx/rt/Kconfig.soc b/soc/arm/nxp_imx/rt/Kconfig.soc index f3c2395cefe..844fd27e9fb 100644 --- a/soc/arm/nxp_imx/rt/Kconfig.soc +++ b/soc/arm/nxp_imx/rt/Kconfig.soc @@ -21,6 +21,7 @@ config SOC_MIMXRT1011 select HAS_MCUX_LPUART select HAS_MCUX_GPT select HAS_MCUX_TRNG + select CPU_HAS_FPU select CPU_HAS_ARM_MPU select CPU_HAS_ICACHE select CPU_HAS_DCACHE @@ -47,6 +48,7 @@ config SOC_MIMXRT1015 select HAS_MCUX_LPUART select HAS_MCUX_GPT select HAS_MCUX_TRNG + select CPU_HAS_FPU select CPU_HAS_FPU_DOUBLE_PRECISION select CPU_HAS_ARM_MPU select INIT_ENET_PLL @@ -372,6 +374,7 @@ config SOC_MIMXRT1176_CM4 select HAS_MCUX_FLEXSPI select HAS_MCUX_LPUART select HAS_MCUX_GPT + select CPU_HAS_FPU select CPU_HAS_ARM_MPU select INIT_ARM_PLL select INIT_ENET_PLL if NET_L2_ETHERNET && ETH_DRIVER @@ -441,6 +444,7 @@ config SOC_MIMXRT1166_CM4 select HAS_MCUX_FLEXSPI select HAS_MCUX_GPT select CPU_HAS_ARM_MPU + select CPU_HAS_FPU select INIT_ARM_PLL select INIT_ENET_PLL if NET_L2_ETHERNET && ETH_DRIVER select INIT_VIDEO_PLL diff --git a/soc/arm/nxp_kinetis/kl2x/Kconfig.series b/soc/arm/nxp_kinetis/kl2x/Kconfig.series index 53558c81648..3c606c7db27 100644 --- a/soc/arm/nxp_kinetis/kl2x/Kconfig.series +++ b/soc/arm/nxp_kinetis/kl2x/Kconfig.series @@ -9,6 +9,7 @@ config SOC_SERIES_KINETIS_KL2X select CPU_CORTEX_M0PLUS select SOC_FAMILY_KINETIS select CPU_CORTEX_M_HAS_SYSTICK + select CPU_CORTEX_M_HAS_VTOR select CLOCK_CONTROL select PLATFORM_SPECIFIC_INIT help diff --git a/soc/arm/nxp_kinetis/kwx/Kconfig.series b/soc/arm/nxp_kinetis/kwx/Kconfig.series index 4b00dd997a9..36ba7b54c21 100644 --- a/soc/arm/nxp_kinetis/kwx/Kconfig.series +++ b/soc/arm/nxp_kinetis/kwx/Kconfig.series @@ -8,6 +8,7 @@ config SOC_SERIES_KINETIS_KWX select ARM select SOC_FAMILY_KINETIS select CPU_CORTEX_M_HAS_SYSTICK + select CPU_CORTEX_M_HAS_VTOR select CLOCK_CONTROL select PLATFORM_SPECIFIC_INIT help diff --git a/soc/arm/nxp_lpc/lpc11u6x/soc.h b/soc/arm/nxp_lpc/lpc11u6x/soc.h index fd7ffbd5400..ec0abb4faf1 100644 --- a/soc/arm/nxp_lpc/lpc11u6x/soc.h +++ b/soc/arm/nxp_lpc/lpc11u6x/soc.h @@ -19,6 +19,7 @@ #ifndef _ASMLANGUAGE #include +#include #endif /* !_ASMLANGUAGE */ diff --git a/soc/arm/nxp_lpc/lpc51u68/Kconfig.series b/soc/arm/nxp_lpc/lpc51u68/Kconfig.series index 6995de0917a..8b1a9dd18b1 100644 --- a/soc/arm/nxp_lpc/lpc51u68/Kconfig.series +++ b/soc/arm/nxp_lpc/lpc51u68/Kconfig.series @@ -13,6 +13,7 @@ config SOC_SERIES_LPC51U68 select HAS_MCUX_SCTIMER select SOC_FAMILY_LPC select CPU_CORTEX_M_HAS_SYSTICK + select CPU_CORTEX_M_HAS_VTOR select PLATFORM_SPECIFIC_INIT help Enable support for LPC LPC51U68 MCU Series diff --git a/soc/arm/nxp_lpc/lpc51u68/soc.h b/soc/arm/nxp_lpc/lpc51u68/soc.h index 45355fb148e..9135c3fed71 100644 --- a/soc/arm/nxp_lpc/lpc51u68/soc.h +++ b/soc/arm/nxp_lpc/lpc51u68/soc.h @@ -10,6 +10,8 @@ #ifndef _ASMLANGUAGE #include +#include + #endif /* !_ASMLANGUAGE*/ #define IOCON_PIO_DIGITAL_EN 0x80u diff --git a/soc/arm/nxp_lpc/lpc54xxx/Kconfig.soc b/soc/arm/nxp_lpc/lpc54xxx/Kconfig.soc index 099dc832d5b..e71bc8f451e 100644 --- a/soc/arm/nxp_lpc/lpc54xxx/Kconfig.soc +++ b/soc/arm/nxp_lpc/lpc54xxx/Kconfig.soc @@ -12,6 +12,7 @@ config SOC_LPC54114_M4 select CPU_CORTEX_M4 select CPU_CORTEX_M_HAS_DWT select CPU_HAS_ARM_MPU + select CPU_HAS_FPU select PLATFORM_SPECIFIC_INIT select CLOCK_CONTROL select HAS_MCUX_IAP_LEGACY diff --git a/soc/arm/nxp_lpc/lpc55xxx/Kconfig.soc b/soc/arm/nxp_lpc/lpc55xxx/Kconfig.soc index c0341a8e9c5..a80374f2d81 100644 --- a/soc/arm/nxp_lpc/lpc55xxx/Kconfig.soc +++ b/soc/arm/nxp_lpc/lpc55xxx/Kconfig.soc @@ -35,6 +35,7 @@ config SOC_LPC55S16 config SOC_LPC55S28 bool "SOC_LPC55S28 M33" select CPU_CORTEX_M33 + select CPU_HAS_ARM_SAU select CPU_HAS_ARM_MPU select CPU_HAS_FPU select ARMV8_M_DSP diff --git a/soc/arm/nxp_s32/s32k3/soc.h b/soc/arm/nxp_s32/s32k3/soc.h index ef2734554df..86af70cc9c6 100644 --- a/soc/arm/nxp_s32/s32k3/soc.h +++ b/soc/arm/nxp_s32/s32k3/soc.h @@ -8,6 +8,7 @@ #define _NXP_S32_S32K_SOC_H_ #include +#include #if defined(CONFIG_CMSIS_RTOS_V2) #include diff --git a/soc/arm/quicklogic_eos_s3/Kconfig.soc b/soc/arm/quicklogic_eos_s3/Kconfig.soc index cb5fd170870..e555933430b 100644 --- a/soc/arm/quicklogic_eos_s3/Kconfig.soc +++ b/soc/arm/quicklogic_eos_s3/Kconfig.soc @@ -7,4 +7,5 @@ config SOC_EOS_S3 select CPU_CORTEX_M4 select CPU_CORTEX_M_HAS_SYSTICK select CPU_HAS_ARM_MPU + select CPU_HAS_FPU select EOS_S3_HAL diff --git a/soc/arm/renesas_ra/common/ra_common_soc.h b/soc/arm/renesas_ra/common/ra_common_soc.h index 60559793743..f76c4c26fc0 100644 --- a/soc/arm/renesas_ra/common/ra_common_soc.h +++ b/soc/arm/renesas_ra/common/ra_common_soc.h @@ -11,6 +11,8 @@ extern "C" { #endif +#include + #ifdef __cplusplus } #endif diff --git a/soc/arm/renesas_smartbond/da1469x/Kconfig.series b/soc/arm/renesas_smartbond/da1469x/Kconfig.series index a3a9e569460..c3672a9ecaf 100644 --- a/soc/arm/renesas_smartbond/da1469x/Kconfig.series +++ b/soc/arm/renesas_smartbond/da1469x/Kconfig.series @@ -8,6 +8,7 @@ config SOC_SERIES_DA1469X select CPU_HAS_FPU select CPU_HAS_ARM_MPU select CPU_CORTEX_M_HAS_SYSTICK + select ARMV8_M_DSP select SOC_FAMILY_SMARTBOND select HAS_SEGGER_RTT if ZEPHYR_SEGGER_MODULE select CLOCK_CONTROL diff --git a/soc/arm/rpi_pico/rp2/soc.h b/soc/arm/rpi_pico/rp2/soc.h index b38d2edf461..0eef4cf92a2 100644 --- a/soc/arm/rpi_pico/rp2/soc.h +++ b/soc/arm/rpi_pico/rp2/soc.h @@ -12,8 +12,6 @@ #ifndef _RPI_PICO_RP2040_SOC_H_ #define _RPI_PICO_RP2040_SOC_H_ - -#define __VTOR_PRESENT CONFIG_CPU_CORTEX_M_HAS_VTOR -#define __MPU_PRESENT CONFIG_CPU_HAS_ARM_MPU +#include #endif /* _RPI_PICO_RP2040_SOC_H_ */ diff --git a/soc/arm/silabs_exx32/efm32hg/Kconfig.series b/soc/arm/silabs_exx32/efm32hg/Kconfig.series index 33793b5386d..d17c24fbcdb 100644 --- a/soc/arm/silabs_exx32/efm32hg/Kconfig.series +++ b/soc/arm/silabs_exx32/efm32hg/Kconfig.series @@ -9,6 +9,7 @@ config SOC_SERIES_EFM32HG select CPU_CORTEX_M0PLUS select SOC_FAMILY_EXX32 select CPU_CORTEX_M_HAS_SYSTICK + select CPU_CORTEX_M_HAS_VTOR select HAS_SILABS_GECKO select SOC_GECKO_CMU select SOC_GECKO_GPIO diff --git a/soc/arm/silabs_exx32/efr32mg21/Kconfig.series b/soc/arm/silabs_exx32/efr32mg21/Kconfig.series index 146493469e8..731658d29e3 100644 --- a/soc/arm/silabs_exx32/efr32mg21/Kconfig.series +++ b/soc/arm/silabs_exx32/efr32mg21/Kconfig.series @@ -11,6 +11,7 @@ config SOC_SERIES_EFR32MG21 select ARMV8_M_DSP select CPU_HAS_FPU select CPU_HAS_ARM_MPU + select CPU_HAS_ARM_SAU select SOC_FAMILY_EXX32 select SOC_GECKO_HAS_RADIO select SOC_GECKO_SERIES2 diff --git a/soc/arm/st_stm32/stm32mp1/Kconfig.series b/soc/arm/st_stm32/stm32mp1/Kconfig.series index 0c6580e84cc..c1576a7ee17 100644 --- a/soc/arm/st_stm32/stm32mp1/Kconfig.series +++ b/soc/arm/st_stm32/stm32mp1/Kconfig.series @@ -11,6 +11,7 @@ config SOC_SERIES_STM32MP1X select SOC_FAMILY_STM32 select HAS_STM32CUBE select CPU_HAS_ARM_MPU + select CPU_HAS_FPU select OPENAMP_RSC_TABLE if RAM_CONSOLE help Enable support for STM32MP1 MPU series diff --git a/soc/arm/ti_k3/am62x_m4/soc.h b/soc/arm/ti_k3/am62x_m4/soc.h index 01ff4b07080..2fd6537b984 100644 --- a/soc/arm/ti_k3/am62x_m4/soc.h +++ b/soc/arm/ti_k3/am62x_m4/soc.h @@ -7,6 +7,8 @@ #ifndef __SOC_H_ #define __SOC_H_ +#include + #include #endif /* __SOC_H */ diff --git a/soc/arm/ti_lm3s6965/soc.h b/soc/arm/ti_lm3s6965/soc.h index bef939013ba..3c353b1a79b 100644 --- a/soc/arm/ti_lm3s6965/soc.h +++ b/soc/arm/ti_lm3s6965/soc.h @@ -15,6 +15,7 @@ #ifndef _BOARD__H_ #define _BOARD__H_ +#include #include /* default system clock */ diff --git a/soc/arm/ti_simplelink/cc13x2_cc26x2/soc.h b/soc/arm/ti_simplelink/cc13x2_cc26x2/soc.h index a1d3504b986..fdc9214732c 100644 --- a/soc/arm/ti_simplelink/cc13x2_cc26x2/soc.h +++ b/soc/arm/ti_simplelink/cc13x2_cc26x2/soc.h @@ -7,6 +7,8 @@ #ifndef TI_SIMPLELINK_CC13X2_CC26X2_SOC_H_ #define TI_SIMPLELINK_CC13X2_CC26X2_SOC_H_ +#include + /* CMSIS required values */ typedef enum { Reset_IRQn = -15, @@ -27,4 +29,6 @@ typedef enum { #define __Vendor_SysTickConfig 0 #define __FPU_PRESENT 1 +#include + #endif /* TI_SIMPLELINK_CC13X2_CC26X2_SOC_H_ */ diff --git a/soc/arm/ti_simplelink/cc32xx/soc.h b/soc/arm/ti_simplelink/cc32xx/soc.h index 9c841e0e4b0..e18dfce626a 100644 --- a/soc/arm/ti_simplelink/cc32xx/soc.h +++ b/soc/arm/ti_simplelink/cc32xx/soc.h @@ -7,6 +7,8 @@ #ifndef TI_SIMPLELINK_CC32XX_SOC_H_ #define TI_SIMPLELINK_CC32XX_SOC_H_ +#include + #include #include @@ -38,4 +40,6 @@ typedef enum { #define __NVIC_PRIO_BITS NUM_IRQ_PRIO_BITS #define __Vendor_SysTickConfig 0 /* Default to standard SysTick */ +#include + #endif /* TI_SIMPLELINK_CC32XX_SOC_H_ */ diff --git a/soc/arm/ti_simplelink/msp432p4xx/Kconfig.series b/soc/arm/ti_simplelink/msp432p4xx/Kconfig.series index 6bb0043ff90..8af48672ed2 100644 --- a/soc/arm/ti_simplelink/msp432p4xx/Kconfig.series +++ b/soc/arm/ti_simplelink/msp432p4xx/Kconfig.series @@ -11,5 +11,6 @@ config SOC_SERIES_MSP432P4XX select DYNAMIC_INTERRUPTS select SOC_FAMILY_TISIMPLELINK select CPU_HAS_FPU + select CPU_HAS_ARM_MPU help Enable support for TI SimpleLink MSP432P4XX. From 4318140ff5edbbdfeeaa5a61fc22cd07b6573f33 Mon Sep 17 00:00:00 2001 From: Dmitrii Golovanov Date: Wed, 29 Nov 2023 15:58:26 +0100 Subject: [PATCH 0749/3723] twister: qemu: Fix race condition at QEMUHandler A race condition was possible at QEMUHandler which didn't wait for its harness to complete causing false negatives and test suite retries, for example when the console harness has got rather long output from a test application to check for patterns. Signed-off-by: Dmitrii Golovanov --- scripts/pylib/twister/twisterlib/handlers.py | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/scripts/pylib/twister/twisterlib/handlers.py b/scripts/pylib/twister/twisterlib/handlers.py index 3c6498a6ea4..eed3cdae84f 100755 --- a/scripts/pylib/twister/twisterlib/handlers.py +++ b/scripts/pylib/twister/twisterlib/handlers.py @@ -988,6 +988,7 @@ def handle(self, harness): self.thread.daemon = True logger.debug("Spawning QEMUHandler Thread for %s" % self.name) self.thread.start() + thread_max_time = time.time() + self.get_test_timeout() if sys.stdout.isatty(): subprocess.call(["stty", "sane"], stdin=sys.stdout) @@ -1019,8 +1020,8 @@ def handle(self, harness): self.returncode = proc.returncode # Need to wait for harness to finish processing # output from QEMU. Otherwise it might miss some - # error messages. - self.thread.join(0) + # messages. + self.thread.join(max(thread_max_time - time.time(), 0)) if self.thread.is_alive(): logger.debug("Timed out while monitoring QEMU output") From 3b0aaab64a277e08f1ea5e573673bab755492dd6 Mon Sep 17 00:00:00 2001 From: Gerson Fernando Budke Date: Sun, 3 Dec 2023 09:41:52 +0100 Subject: [PATCH 0750/3723] drivers: eth: sam: Fix regression from 62833 The 62833 added a regression at SAM ethernet drivers which always fail to initialize due to a wrong switch case implementation and without review from maintainer. This add more information and fix the issue. Signed-off-by: Gerson Fernando Budke --- drivers/ethernet/eth_sam_gmac.c | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/drivers/ethernet/eth_sam_gmac.c b/drivers/ethernet/eth_sam_gmac.c index 8d82c317cd5..9acefcd833b 100644 --- a/drivers/ethernet/eth_sam_gmac.c +++ b/drivers/ethernet/eth_sam_gmac.c @@ -1115,13 +1115,18 @@ static int gmac_init(Gmac *gmac, uint32_t gmac_ncfgr_val) /* Setup Network Configuration Register */ gmac->GMAC_NCFGR = gmac_ncfgr_val | mck_divisor; - switch (DT_INST_ENUM_IDX_OR(0, phy_connection_type, 1)) { + /* Default (RMII) is defined at atmel,gmac-common.yaml file */ + switch (DT_INST_ENUM_IDX(0, phy_connection_type)) { case 0: /* mii */ gmac->GMAC_UR = 0x1; + break; case 1: /* rmii */ gmac->GMAC_UR = 0x0; + break; default: /* Build assert at top of file should catch this case */ + LOG_ERR("The phy connection type is invalid"); + return -EINVAL; } From afa1bd842cbf404c8aeb92eb0543d246df767edb Mon Sep 17 00:00:00 2001 From: Marc Lasch Date: Sun, 3 Dec 2023 19:27:56 +0100 Subject: [PATCH 0751/3723] drivers: wifi: esp32: Mute implicit function declaration warning Mute the function declaration warning, the compiler was emitting when compiling the esp32 Wi-Fi driver with IPv4 disabled. The net_dhcpv4_start() function was visible during compile time, even when IPv4 was disabled. Signed-off-by: Marc Lasch --- drivers/wifi/esp32/src/esp_wifi_drv.c | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/drivers/wifi/esp32/src/esp_wifi_drv.c b/drivers/wifi/esp32/src/esp_wifi_drv.c index bb89f3e8d2d..4b2f299c123 100644 --- a/drivers/wifi/esp32/src/esp_wifi_drv.c +++ b/drivers/wifi/esp32/src/esp_wifi_drv.c @@ -236,19 +236,19 @@ static void scan_done_handler(void) static void esp_wifi_handle_connect_event(void) { esp32_data.state = ESP32_STA_CONNECTED; - if (IS_ENABLED(CONFIG_ESP32_WIFI_STA_AUTO_DHCPV4)) { - net_dhcpv4_start(esp32_wifi_iface); - } else { - wifi_mgmt_raise_connect_result_event(esp32_wifi_iface, 0); - } +#if defined(CONFIG_ESP32_WIFI_STA_AUTO_DHCPV4) + net_dhcpv4_start(esp32_wifi_iface); +#else + wifi_mgmt_raise_connect_result_event(esp32_wifi_iface, 0); +#endif } static void esp_wifi_handle_disconnect_event(void) { if (esp32_data.state == ESP32_STA_CONNECTED) { - if (IS_ENABLED(CONFIG_ESP32_WIFI_STA_AUTO_DHCPV4)) { - net_dhcpv4_stop(esp32_wifi_iface); - } +#if defined(CONFIG_ESP32_WIFI_STA_AUTO_DHCPV4) + net_dhcpv4_stop(esp32_wifi_iface); +#endif wifi_mgmt_raise_disconnect_result_event(esp32_wifi_iface, 0); } else { wifi_mgmt_raise_disconnect_result_event(esp32_wifi_iface, -1); From 3d3b287b7908625dc8356ac3532d9b6943edbb50 Mon Sep 17 00:00:00 2001 From: Jamie McCrae Date: Fri, 1 Dec 2023 11:44:44 +0000 Subject: [PATCH 0752/3723] dts: arm: nordic: nrf53/nrf91: Fix GPREGRET register addresses Fixes an issue with the register addresses which was caused by a missing `ranges;` option for the power peripheral Signed-off-by: Jamie McCrae --- dts/arm/nordic/nrf5340_cpuapp_peripherals.dtsi | 9 +++++---- dts/arm/nordic/nrf91_peripherals.dtsi | 9 +++++---- 2 files changed, 10 insertions(+), 8 deletions(-) diff --git a/dts/arm/nordic/nrf5340_cpuapp_peripherals.dtsi b/dts/arm/nordic/nrf5340_cpuapp_peripherals.dtsi index e7aa0309f70..5e2e91f20b7 100644 --- a/dts/arm/nordic/nrf5340_cpuapp_peripherals.dtsi +++ b/dts/arm/nordic/nrf5340_cpuapp_peripherals.dtsi @@ -32,24 +32,25 @@ clock: clock@5000 { power: power@5000 { compatible = "nordic,nrf-power"; reg = <0x5000 0x1000>; + ranges = <0x0 0x5000 0x1000>; interrupts = <5 NRF_DEFAULT_IRQ_PRIORITY>; status = "okay"; #address-cells = <1>; #size-cells = <1>; - gpregret1: gpregret1@551c { + gpregret1: gpregret1@51c { #address-cells = <1>; #size-cells = <1>; compatible = "nordic,nrf-gpregret"; - reg = <0x551c 0x1>; + reg = <0x51c 0x1>; status = "okay"; }; - gpregret2: gpregret2@5520 { + gpregret2: gpregret2@520 { #address-cells = <1>; #size-cells = <1>; compatible = "nordic,nrf-gpregret"; - reg = <0x5520 0x1>; + reg = <0x520 0x1>; status = "okay"; }; }; diff --git a/dts/arm/nordic/nrf91_peripherals.dtsi b/dts/arm/nordic/nrf91_peripherals.dtsi index 2e437eb082d..d6078e79120 100644 --- a/dts/arm/nordic/nrf91_peripherals.dtsi +++ b/dts/arm/nordic/nrf91_peripherals.dtsi @@ -345,24 +345,25 @@ clock: clock@5000 { power: power@5000 { compatible = "nordic,nrf-power"; reg = <0x5000 0x1000>; + ranges = <0x0 0x5000 0x1000>; interrupts = <5 NRF_DEFAULT_IRQ_PRIORITY>; status = "okay"; #address-cells = <1>; #size-cells = <1>; - gpregret1: gpregret1@551c { + gpregret1: gpregret1@51c { #address-cells = <1>; #size-cells = <1>; compatible = "nordic,nrf-gpregret"; - reg = <0x551c 0x1>; + reg = <0x51c 0x1>; status = "okay"; }; - gpregret2: gpregret2@5520 { + gpregret2: gpregret2@520 { #address-cells = <1>; #size-cells = <1>; compatible = "nordic,nrf-gpregret"; - reg = <0x5520 0x1>; + reg = <0x520 0x1>; status = "okay"; }; }; From 673f38f3d1ccbb8d66edce195805deae439272d4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Manuel=20Arg=C3=BCelles?= Date: Tue, 5 Dec 2023 18:07:27 +0700 Subject: [PATCH 0753/3723] soc: arm: nxp_s32: s32k1: unselect CPU_HAS_xCACHE MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Following changes in #64978, align CPU_HAS_xCACHE symbols with the CMSIS feature definitions in the device headers so that both have the same value. Fixes #66147 Signed-off-by: Manuel Argüelles --- soc/arm/nxp_s32/s32k1/Kconfig.soc | 12 ------------ 1 file changed, 12 deletions(-) diff --git a/soc/arm/nxp_s32/s32k1/Kconfig.soc b/soc/arm/nxp_s32/s32k1/Kconfig.soc index 83a2b59d67c..dd1cdf77538 100644 --- a/soc/arm/nxp_s32/s32k1/Kconfig.soc +++ b/soc/arm/nxp_s32/s32k1/Kconfig.soc @@ -20,48 +20,36 @@ config SOC_S32K142 select CPU_CORTEX_M4 select CPU_CORTEX_M_HAS_DWT select CPU_HAS_FPU - select CPU_HAS_DCACHE - select CPU_HAS_ICACHE config SOC_S32K142W bool "S32K142W" select CPU_CORTEX_M4 select CPU_CORTEX_M_HAS_DWT select CPU_HAS_FPU - select CPU_HAS_DCACHE - select CPU_HAS_ICACHE config SOC_S32K144 bool "S32K144" select CPU_CORTEX_M4 select CPU_CORTEX_M_HAS_DWT select CPU_HAS_FPU - select CPU_HAS_DCACHE - select CPU_HAS_ICACHE config SOC_S32K144W bool "S32K144W" select CPU_CORTEX_M4 select CPU_CORTEX_M_HAS_DWT select CPU_HAS_FPU - select CPU_HAS_DCACHE - select CPU_HAS_ICACHE config SOC_S32K146 bool "S32K146" select CPU_CORTEX_M4 select CPU_CORTEX_M_HAS_DWT select CPU_HAS_FPU - select CPU_HAS_DCACHE - select CPU_HAS_ICACHE config SOC_S32K148 bool "S32K148" select CPU_CORTEX_M4 select CPU_CORTEX_M_HAS_DWT select CPU_HAS_FPU - select CPU_HAS_DCACHE - select CPU_HAS_ICACHE endchoice From 20057b65649a2ca778f8ab7d0b031027992f3461 Mon Sep 17 00:00:00 2001 From: Jonathan Rico Date: Tue, 5 Dec 2023 11:45:35 +0100 Subject: [PATCH 0754/3723] tests: Bluetooth: add missing param to testlib The lib was refactored, but CI didn't run the tests that used it for some reason. A parameter was forgotten. Signed-off-by: Jonathan Rico --- tests/bluetooth/common/testlib/include/testlib/att_read.h | 4 ++-- tests/bluetooth/common/testlib/src/att_read.c | 4 ++-- tests/bsim/bluetooth/host/att/long_read/main.c | 2 +- 3 files changed, 5 insertions(+), 5 deletions(-) diff --git a/tests/bluetooth/common/testlib/include/testlib/att_read.h b/tests/bluetooth/common/testlib/include/testlib/att_read.h index 6e12d441e4e..4e9034d9876 100644 --- a/tests/bluetooth/common/testlib/include/testlib/att_read.h +++ b/tests/bluetooth/common/testlib/include/testlib/att_read.h @@ -24,8 +24,8 @@ int bt_testlib_att_read_by_handle_sync(struct net_buf_simple *result_data, uint1 uint16_t offset); int bt_testlib_gatt_long_read(struct net_buf_simple *result_data, uint16_t *result_size, - struct bt_conn *conn, enum bt_att_chan_opt bearer, uint16_t handle, - uint16_t offset); + uint16_t *result_att_mtu, struct bt_conn *conn, + enum bt_att_chan_opt bearer, uint16_t handle, uint16_t offset); int bt_testlib_gatt_discover_primary(uint16_t *result_handle, uint16_t *result_end_handle, struct bt_conn *conn, const struct bt_uuid *uuid, diff --git a/tests/bluetooth/common/testlib/src/att_read.c b/tests/bluetooth/common/testlib/src/att_read.c index 6a678919885..8da82ce19b8 100644 --- a/tests/bluetooth/common/testlib/src/att_read.c +++ b/tests/bluetooth/common/testlib/src/att_read.c @@ -169,8 +169,8 @@ int bt_testlib_att_read_by_handle_sync(struct net_buf_simple *result_data, uint1 } int bt_testlib_gatt_long_read(struct net_buf_simple *result_data, uint16_t *result_size, - struct bt_conn *conn, enum bt_att_chan_opt bearer, uint16_t handle, - uint16_t offset) + uint16_t *result_att_mtu, struct bt_conn *conn, + enum bt_att_chan_opt bearer, uint16_t handle, uint16_t offset) { int err; uint16_t _result_data_size = 0; diff --git a/tests/bsim/bluetooth/host/att/long_read/main.c b/tests/bsim/bluetooth/host/att/long_read/main.c index 2f13b346a80..83a1b3afe76 100644 --- a/tests/bsim/bluetooth/host/att/long_read/main.c +++ b/tests/bsim/bluetooth/host/att/long_read/main.c @@ -144,7 +144,7 @@ static void test_long_read(enum bt_att_chan_opt bearer, uint16_t chrc_value_hand NET_BUF_SIMPLE_DEFINE(attr_value_buf, BT_ATT_MAX_ATTRIBUTE_LEN); /* Perform the whole long read operation. */ - EXPECT_ZERO(bt_testlib_gatt_long_read(&attr_value_buf, NULL, conn, bearer, + EXPECT_ZERO(bt_testlib_gatt_long_read(&attr_value_buf, NULL, NULL, conn, bearer, chrc_value_handle, 0)); /* Parse the read attribute value to verify the From 3157aaaddb24b0423189959d6b03bf208246032f Mon Sep 17 00:00:00 2001 From: Pieter De Gendt Date: Thu, 30 Nov 2023 14:53:36 +0100 Subject: [PATCH 0755/3723] net: ip: mgmt: Add support for compile time event handlers Add an iterable section with network event handlers. Signed-off-by: Pieter De Gendt --- .../linker/common-rom/common-rom-net.ld | 4 ++ include/zephyr/net/net_mgmt.h | 50 ++++++++++++++++++- subsys/net/ip/net_mgmt.c | 31 ++++++++++++ 3 files changed, 84 insertions(+), 1 deletion(-) diff --git a/include/zephyr/linker/common-rom/common-rom-net.ld b/include/zephyr/linker/common-rom/common-rom-net.ld index 71c1c1e089f..909d11c6d57 100644 --- a/include/zephyr/linker/common-rom/common-rom-net.ld +++ b/include/zephyr/linker/common-rom/common-rom-net.ld @@ -21,3 +21,7 @@ #if defined(CONFIG_COAP_SERVER) ITERABLE_SECTION_ROM(coap_service, 4) #endif + +#if defined(CONFIG_NET_MGMT_EVENT) + ITERABLE_SECTION_ROM(net_mgmt_event_static_handler, 4) +#endif diff --git a/include/zephyr/net/net_mgmt.h b/include/zephyr/net/net_mgmt.h index 8d8710edd26..f90bc8e1836 100644 --- a/include/zephyr/net/net_mgmt.h +++ b/include/zephyr/net/net_mgmt.h @@ -15,6 +15,7 @@ #include #include #include +#include #ifdef __cplusplus extern "C" { @@ -107,7 +108,7 @@ struct net_mgmt_event_callback; * @brief Define the user's callback handler function signature * @param cb Original struct net_mgmt_event_callback owning this handler. * @param mgmt_event The network event being notified. - * @param iface A pointer on a struct net_if to which the the event belongs to, + * @param iface A pointer on a struct net_if to which the event belongs to, * if it's an event on an iface. NULL otherwise. */ typedef void (*net_mgmt_event_handler_t)(struct net_mgmt_event_callback *cb, @@ -163,6 +164,53 @@ struct net_mgmt_event_callback { }; }; +/** + * @typedef net_mgmt_event_static_handler_t + * @brief Define the user's callback handler function signature + * @param mgmt_event The network event being notified. + * @param iface A pointer on a struct net_if to which the event belongs to, + * if it's an event on an iface. NULL otherwise. + * @param info A valid pointer on a data understood by the handler. + * NULL otherwise. + * @param info_length Length in bytes of the memory pointed by @p info. + * @param user_data Data provided by the user to the handler. + */ +typedef void (*net_mgmt_event_static_handler_t)(uint32_t mgmt_event, + struct net_if *iface, + void *info, size_t info_length, + void *user_data); + +/** @cond INTERNAL_HIDDEN */ + +/* Structure for event handler registered at compile time */ +struct net_mgmt_event_static_handler { + uint32_t event_mask; + net_mgmt_event_static_handler_t handler; + void *user_data; +}; + +/** @endcond */ + +/** + * @brief Define a static network event handler. + * @param _name Name of the event handler. + * @param _event_mask A mask of network events on which the passed handler should + * be called in case those events come. + * Note that only the command part is treated as a mask, + * matching one to several commands. Layer and layer code will + * be made of an exact match. This means that in order to + * receive events from multiple layers, one must have multiple + * listeners registered, one for each layer being listened. + * @param _func The function to be called upon network events being emitted. + * @param _user_data User data passed to the handler being called on network events. + */ +#define NET_MGMT_REGISTER_EVENT_HANDLER(_name, _event_mask, _func, _user_data) \ + const STRUCT_SECTION_ITERABLE(net_mgmt_event_static_handler, _name) = { \ + .event_mask = _event_mask, \ + .handler = _func, \ + .user_data = (void *)_user_data, \ + } + /** * @brief Helper to initialize a struct net_mgmt_event_callback properly * @param cb A valid application's callback structure pointer. diff --git a/subsys/net/ip/net_mgmt.c b/subsys/net/ip/net_mgmt.c index d26503b2858..1ea04fc4791 100644 --- a/subsys/net/ip/net_mgmt.c +++ b/subsys/net/ip/net_mgmt.c @@ -107,6 +107,10 @@ static inline void mgmt_rebuild_global_event_mask(void) global_event_mask = 0U; + STRUCT_SECTION_FOREACH(net_mgmt_event_static_handler, it) { + mgmt_add_event_mask(it->event_mask); + } + SYS_SLIST_FOR_EACH_CONTAINER_SAFE(&event_callbacks, cb, tmp, node) { mgmt_add_event_mask(cb->event_mask); } @@ -189,6 +193,30 @@ static inline void mgmt_run_callbacks(const struct mgmt_event_entry * const mgmt #endif } +static inline void mgmt_run_static_callbacks(const struct mgmt_event_entry * const mgmt_event) +{ + STRUCT_SECTION_FOREACH(net_mgmt_event_static_handler, it) { + if (!(NET_MGMT_GET_LAYER(mgmt_event->event) == + NET_MGMT_GET_LAYER(it->event_mask)) || + !(NET_MGMT_GET_LAYER_CODE(mgmt_event->event) == + NET_MGMT_GET_LAYER_CODE(it->event_mask)) || + (NET_MGMT_GET_COMMAND(mgmt_event->event) && + NET_MGMT_GET_COMMAND(it->event_mask) && + !(NET_MGMT_GET_COMMAND(mgmt_event->event) & + NET_MGMT_GET_COMMAND(it->event_mask)))) { + continue; + } + + it->handler(mgmt_event->event, mgmt_event->iface, +#ifdef CONFIG_NET_MGMT_EVENT_INFO + (void *)mgmt_event->info, mgmt_event->info_length, +#else + NULL, 0U, +#endif + it->user_data); + } +} + static void mgmt_thread(void *p1, void *p2, void *p3) { ARG_UNUSED(p1); @@ -197,6 +225,8 @@ static void mgmt_thread(void *p1, void *p2, void *p3) struct mgmt_event_entry mgmt_event; + mgmt_rebuild_global_event_mask(); + while (1) { mgmt_pop_event(&mgmt_event); @@ -205,6 +235,7 @@ static void mgmt_thread(void *p1, void *p2, void *p3) /* take the lock to prevent changes to the callback structure during use */ (void)k_mutex_lock(&net_mgmt_callback_lock, K_FOREVER); + mgmt_run_static_callbacks(&mgmt_event); mgmt_run_callbacks(&mgmt_event); (void)k_mutex_unlock(&net_mgmt_callback_lock); From b31d73f69cfba7d78cde630dcf88ba217abdd095 Mon Sep 17 00:00:00 2001 From: Pieter De Gendt Date: Thu, 30 Nov 2023 15:50:44 +0100 Subject: [PATCH 0756/3723] tests: net: mgmt: Add test for static event handlers Add a testcase for event handlers in the iterable section. Signed-off-by: Pieter De Gendt --- tests/net/mgmt/src/mgmt.c | 77 ++++++++++++++++++++++++++++++++++++--- 1 file changed, 71 insertions(+), 6 deletions(-) diff --git a/tests/net/mgmt/src/mgmt.c b/tests/net/mgmt/src/mgmt.c index 52be33eb3dc..15c23301b26 100644 --- a/tests/net/mgmt/src/mgmt.c +++ b/tests/net/mgmt/src/mgmt.c @@ -32,6 +32,7 @@ static uint32_t event2throw; static uint32_t throw_times; static uint32_t throw_sleep; static bool with_info; +static bool with_static; static K_THREAD_STACK_DEFINE(thrower_stack, 512 + CONFIG_TEST_EXTRA_STACK_SIZE); static struct k_thread thrower_thread_data; static struct k_sem thrower_lock; @@ -66,6 +67,35 @@ static int test_mgmt_request(uint32_t mgmt_request, NET_MGMT_REGISTER_REQUEST_HANDLER(TEST_MGMT_REQUEST, test_mgmt_request); +static void test_mgmt_event_handler(uint32_t mgmt_event, struct net_if *iface, void *info, + size_t info_length, void *user_data) +{ + if (!with_static) { + return; + } + + TC_PRINT("\t\tReceived static event 0x%08X\n", mgmt_event); + + ARG_UNUSED(user_data); + + if (with_info && info) { + if (info_length != info_length_in_test) { + rx_calls = (uint32_t) -1; + return; + } + + if (memcmp(info_data, info, info_length_in_test)) { + rx_calls = (uint32_t) -1; + return; + } + } + + rx_event = mgmt_event; + rx_calls++; +} + +NET_MGMT_REGISTER_EVENT_HANDLER(my_test_handler, TEST_MGMT_EVENT, test_mgmt_event_handler, NULL); + int fake_dev_init(const struct device *dev) { ARG_UNUSED(dev); @@ -238,6 +268,33 @@ static int test_synchronous_event_listener(uint32_t times, bool on_iface) return TC_PASS; } +static int test_static_event_listener(uint32_t times, bool info) +{ + TC_PRINT("- Static event listener %s\n", info ? "with info" : ""); + + event2throw = TEST_MGMT_EVENT; + throw_times = times; + throw_sleep = 0; + with_info = info; + with_static = true; + + k_sem_give(&thrower_lock); + + /* Let the network stack to proceed */ + k_msleep(THREAD_SLEEP); + + TC_PRINT("\tReceived 0x%08X %u times\n", + rx_event, rx_calls); + + zassert_equal(rx_event, event2throw, "rx_event check failed"); + zassert_equal(rx_calls, times, "rx_calls check failed"); + + rx_event = rx_calls = 0U; + with_static = false; + + return TC_PASS; +} + static void initialize_event_tests(void) { event2throw = 0U; @@ -274,12 +331,8 @@ static int test_core_event(uint32_t event, bool (*func)(void)) zassert_true(func(), "func() check failed"); - if (IS_ENABLED(CONFIG_NET_TC_THREAD_PREEMPTIVE)) { - /* Let the network stack to proceed */ - k_msleep(THREAD_SLEEP); - } else { - k_yield(); - } + /* Let the network stack to proceed */ + k_msleep(THREAD_SLEEP); zassert_true(rx_calls > 0 && rx_calls != -1, "rx_calls empty"); zassert_equal(rx_event, event, "rx_event check failed, " @@ -345,6 +398,18 @@ ZTEST(mgmt_fn_test_suite, test_mgmt) zassert_false(test_sending_event_info(2, true), "test_sending_event failed"); + zassert_false(test_static_event_listener(1, false), + "test_static_event_listener failed"); + + zassert_false(test_static_event_listener(2, false), + "test_static_event_listener failed"); + + zassert_false(test_static_event_listener(1, true), + "test_static_event_listener failed"); + + zassert_false(test_static_event_listener(2, true), + "test_static_event_listener failed"); + zassert_false(test_core_event(NET_EVENT_IPV6_ADDR_ADD, _iface_ip6_add), "test_core_event failed"); From 21ba08c5757cb2d267997fe176de453d3f5b2f67 Mon Sep 17 00:00:00 2001 From: Pieter De Gendt Date: Thu, 30 Nov 2023 20:04:44 +0100 Subject: [PATCH 0757/3723] doc: connectivity: networking: Document NET_MGMT_REGISTER_EVENT_HANDLER Add an example using the macro NET_MGMT_REGISTER_EVENT_HANDLER to the network management documentation. Signed-off-by: Pieter De Gendt --- doc/connectivity/networking/api/net_mgmt.rst | 48 ++++++++++++++++++-- 1 file changed, 44 insertions(+), 4 deletions(-) diff --git a/doc/connectivity/networking/api/net_mgmt.rst b/doc/connectivity/networking/api/net_mgmt.rst index ed6c512a742..2973ee82b04 100644 --- a/doc/connectivity/networking/api/net_mgmt.rst +++ b/doc/connectivity/networking/api/net_mgmt.rst @@ -49,17 +49,19 @@ Listening to network events You can receive notifications on network events by registering a callback function and specifying a set of events used to filter when -your callback is invoked. The callback will have to be unique for a +your callback is invoked. The callback will have to be unique for a pair of layer and code, whereas on the command part it will be a mask of events. -Two functions are available, :c:func:`net_mgmt_add_event_callback` for -registering the callback function, and -:c:func:`net_mgmt_del_event_callback` +At runtime two functions are available, :c:func:`net_mgmt_add_event_callback` +for registering the callback function, and :c:func:`net_mgmt_del_event_callback` for unregistering a callback. A helper function, :c:func:`net_mgmt_init_event_callback`, can be used to ease the initialization of the callback structure. +Additionally :c:macro:`NET_MGMT_REGISTER_EVENT_HANDLER` can be used to +register a callback handler at compile time. + When an event occurs that matches a callback's event set, the associated callback function is invoked with the actual event code. This makes it possible for different events to be handled by the @@ -121,6 +123,44 @@ An example follows. net_mgmt_add_event_callback(&ipv4_callback); } +Or similarly using :c:macro:`NET_MGMT_REGISTER_EVENT_HANDLER`. + +.. note:: + + The ``info`` and ``info_length`` arguments are only usable if + :kconfig:option:`CONFIG_NET_MGMT_EVENT_INFO` is enabled. Otherwise these are + ``NULL`` and zero. + +.. code-block:: c + + /* + * Set of events to handle. + */ + #define EVENT_IFACE_SET (NET_EVENT_IF_xxx | NET_EVENT_IF_yyy) + #define EVENT_IPV4_SET (NET_EVENT_IPV4_xxx | NET_EVENT_IPV4_yyy) + + static void event_handler(uint32_t mgmt_event, struct net_if *iface, + void *info, size_t info_length, + void *user_data) + { + if (mgmt_event == NET_EVENT_IF_xxx) { + /* Handle NET_EVENT_IF_xxx */ + } else if (mgmt_event == NET_EVENT_IF_yyy) { + /* Handle NET_EVENT_IF_yyy */ + } else if (mgmt_event == NET_EVENT_IPV4_xxx) { + /* Handle NET_EVENT_IPV4_xxx */ + } else if (mgmt_event == NET_EVENT_IPV4_yyy) { + /* Handle NET_EVENT_IPV4_yyy */ + } else { + /* Spurious (false positive) invocation. */ + } + } + + NET_MGMT_REGISTER_EVENT_HANDLER(iface_event_handler, EVENT_IFACE_SET, + event_handler, NULL); + NET_MGMT_REGISTER_EVENT_HANDLER(ipv4_event_handler, EVENT_IPV4_SET, + event_handler, NULL); + See :zephyr_file:`include/zephyr/net/net_event.h` for available generic core events that can be listened to. From d7625ce57fda8fc1c10ea978842b38bf8035397b Mon Sep 17 00:00:00 2001 From: Pieter De Gendt Date: Thu, 30 Nov 2023 20:06:14 +0100 Subject: [PATCH 0758/3723] doc: release: 3.6: Add note on NET_MGMT_REGISTER_EVENT_HANDLER Add a release entry to networking/miscellaneous about compile time network event handlers. Signed-off-by: Pieter De Gendt --- doc/releases/release-notes-3.6.rst | 3 +++ 1 file changed, 3 insertions(+) diff --git a/doc/releases/release-notes-3.6.rst b/doc/releases/release-notes-3.6.rst index 2ec4afe0c57..a0be585f618 100644 --- a/doc/releases/release-notes-3.6.rst +++ b/doc/releases/release-notes-3.6.rst @@ -226,6 +226,9 @@ Networking unicast and multicast packets. This can be controlled in each socket via :c:func:`setsockopt` API. + * Added support for compile time network event handlers using the macro + :c:macro:`NET_MGMT_REGISTER_EVENT_HANDLER`. + * MQTT-SN: * OpenThread: From 31b493128f451d51c47cf1c5d322858a460368f4 Mon Sep 17 00:00:00 2001 From: Erwan Gouriou Date: Fri, 1 Dec 2023 16:26:48 +0100 Subject: [PATCH 0759/3723] soc: stm32wba: Introduce STM32WBA55 SoC variant STM32WBA55 is a new STM32WBA SoC variant featuring SMPS. Signed-off-by: Erwan Gouriou --- .../stm32wba/Kconfig.defconfig.stm32wba55xx | 14 ++++++++++++++ soc/arm/st_stm32/stm32wba/Kconfig.soc | 3 +++ 2 files changed, 17 insertions(+) create mode 100644 soc/arm/st_stm32/stm32wba/Kconfig.defconfig.stm32wba55xx diff --git a/soc/arm/st_stm32/stm32wba/Kconfig.defconfig.stm32wba55xx b/soc/arm/st_stm32/stm32wba/Kconfig.defconfig.stm32wba55xx new file mode 100644 index 00000000000..ca745f87471 --- /dev/null +++ b/soc/arm/st_stm32/stm32wba/Kconfig.defconfig.stm32wba55xx @@ -0,0 +1,14 @@ +# ST Microelectronics STM32WBA55XX MCU + +# Copyright (c) 2023 STMicroelectronics +# SPDX-License-Identifier: Apache-2.0 + +if SOC_STM32WBA55XX + +config SOC + default "stm32wba55xx" + +config NUM_IRQS + default 70 + +endif # SOC_STM32WBA55XX diff --git a/soc/arm/st_stm32/stm32wba/Kconfig.soc b/soc/arm/st_stm32/stm32wba/Kconfig.soc index 6e8586d8f3d..75f48454b1c 100644 --- a/soc/arm/st_stm32/stm32wba/Kconfig.soc +++ b/soc/arm/st_stm32/stm32wba/Kconfig.soc @@ -10,4 +10,7 @@ depends on SOC_SERIES_STM32WBAX config SOC_STM32WBA52XX bool "STM32WBA52XX" +config SOC_STM32WBA55XX + bool "STM32WBA55XX" + endchoice From 3bbc2cc9e1418b1db14fd71f2b8054513b303d6d Mon Sep 17 00:00:00 2001 From: Erwan Gouriou Date: Fri, 1 Dec 2023 16:28:34 +0100 Subject: [PATCH 0760/3723] dts: stm32wba: Introduce stm32wba55Xg package Based on stm32wba55, stm32wba55Xg is similar from device tree description to stm32wba52Xg. Take the opportunity to fix stm32wba52Xg descriuption scheme which was missing stm32wba52.dtsi. Signed-off-by: Erwan Gouriou --- dts/arm/st/wba/stm32wba52.dtsi | 12 ++++++++++++ dts/arm/st/wba/stm32wba52Xg.dtsi | 4 +--- dts/arm/st/wba/stm32wba55.dtsi | 12 ++++++++++++ dts/arm/st/wba/stm32wba55Xg.dtsi | 21 +++++++++++++++++++++ 4 files changed, 46 insertions(+), 3 deletions(-) create mode 100644 dts/arm/st/wba/stm32wba52.dtsi create mode 100644 dts/arm/st/wba/stm32wba55.dtsi create mode 100644 dts/arm/st/wba/stm32wba55Xg.dtsi diff --git a/dts/arm/st/wba/stm32wba52.dtsi b/dts/arm/st/wba/stm32wba52.dtsi new file mode 100644 index 00000000000..ef4f4d0f180 --- /dev/null +++ b/dts/arm/st/wba/stm32wba52.dtsi @@ -0,0 +1,12 @@ +/* + * Copyright (c) 2023 STMicroelectronics + * + * SPDX-License-Identifier: Apache-2.0 + */ +#include + +/ { + soc { + compatible = "st,stm32wba52", "st,stm32wba", "simple-bus"; + }; +}; diff --git a/dts/arm/st/wba/stm32wba52Xg.dtsi b/dts/arm/st/wba/stm32wba52Xg.dtsi index f4ddcbbc9e7..ecae645171b 100644 --- a/dts/arm/st/wba/stm32wba52Xg.dtsi +++ b/dts/arm/st/wba/stm32wba52Xg.dtsi @@ -4,7 +4,7 @@ * SPDX-License-Identifier: Apache-2.0 */ #include -#include +#include / { sram0: memory@20000000 { @@ -12,8 +12,6 @@ }; soc { - compatible = "st,stm32wba52", "st,stm32wba", "simple-bus"; - flash-controller@40022000 { flash0: flash@8000000 { reg = <0x08000000 DT_SIZE_M(1)>; diff --git a/dts/arm/st/wba/stm32wba55.dtsi b/dts/arm/st/wba/stm32wba55.dtsi new file mode 100644 index 00000000000..b8a8c6125a7 --- /dev/null +++ b/dts/arm/st/wba/stm32wba55.dtsi @@ -0,0 +1,12 @@ +/* + * Copyright (c) 2023 STMicroelectronics + * + * SPDX-License-Identifier: Apache-2.0 + */ +#include + +/ { + soc { + compatible = "st,stm32wba55", "st,stm32wba", "simple-bus"; + }; +}; diff --git a/dts/arm/st/wba/stm32wba55Xg.dtsi b/dts/arm/st/wba/stm32wba55Xg.dtsi new file mode 100644 index 00000000000..f5c23f031e9 --- /dev/null +++ b/dts/arm/st/wba/stm32wba55Xg.dtsi @@ -0,0 +1,21 @@ +/* + * Copyright (c) 2023 STMicroelectronics + * + * SPDX-License-Identifier: Apache-2.0 + */ +#include +#include + +/ { + sram0: memory@20000000 { + reg = <0x20000000 DT_SIZE_K(128)>; + }; + + soc { + flash-controller@40022000 { + flash0: flash@8000000 { + reg = <0x08000000 DT_SIZE_M(1)>; + }; + }; + }; +}; From 7c96ebc2a8b8444e28904d2d6d79c40336184094 Mon Sep 17 00:00:00 2001 From: Erwan Gouriou Date: Fri, 1 Dec 2023 16:40:45 +0100 Subject: [PATCH 0761/3723] soc: stm32: Make POWER_SUPPLY_CHOICE available for SOC_STM32WBA55XX POWER_SUPPLY_CHOICE is available for SOC_STM32WBA55XX, with two possible options: LDO or SMPS. Signed-off-by: Erwan Gouriou --- soc/arm/st_stm32/common/Kconfig.soc | 17 +++++++++-------- soc/arm/st_stm32/stm32wba/soc.c | 8 ++++++++ 2 files changed, 17 insertions(+), 8 deletions(-) diff --git a/soc/arm/st_stm32/common/Kconfig.soc b/soc/arm/st_stm32/common/Kconfig.soc index 07b2122cefd..8e98514a79e 100644 --- a/soc/arm/st_stm32/common/Kconfig.soc +++ b/soc/arm/st_stm32/common/Kconfig.soc @@ -24,7 +24,8 @@ config USE_STM32_ASSERT choice POWER_SUPPLY_CHOICE prompt "STM32 power supply configuration" default POWER_SUPPLY_LDO - depends on SOC_SERIES_STM32H7X || SOC_SERIES_STM32U5X + depends on SOC_SERIES_STM32H7X || SOC_SERIES_STM32U5X || \ + SOC_STM32WBA55XX config POWER_SUPPLY_LDO bool "LDO supply" @@ -34,30 +35,30 @@ config POWER_SUPPLY_DIRECT_SMPS config POWER_SUPPLY_SMPS_1V8_SUPPLIES_LDO bool "SMPS 1.8V supplies LDO (no external supply)" - depends on !SOC_SERIES_STM32U5X + depends on !SOC_SERIES_STM32U5X && !SOC_SERIES_STM32WBAX config POWER_SUPPLY_SMPS_2V5_SUPPLIES_LDO bool "SMPS 2.5V supplies LDO (no external supply)" - depends on !SOC_SERIES_STM32U5X + depends on !SOC_SERIES_STM32U5X && !SOC_SERIES_STM32WBAX config POWER_SUPPLY_SMPS_1V8_SUPPLIES_EXT_AND_LDO bool "External SMPS 1.8V supply, supplies LDO" - depends on !SOC_SERIES_STM32U5X + depends on !SOC_SERIES_STM32U5X && !SOC_SERIES_STM32WBAX config POWER_SUPPLY_SMPS_2V5_SUPPLIES_EXT_AND_LDO bool "External SMPS 2.5V supply, supplies LDO" - depends on !SOC_SERIES_STM32U5X + depends on !SOC_SERIES_STM32U5X && !SOC_SERIES_STM32WBAX config POWER_SUPPLY_SMPS_1V8_SUPPLIES_EXT bool "External SMPS 1.8V supply and bypass" - depends on !SOC_SERIES_STM32U5X + depends on !SOC_SERIES_STM32U5X && !SOC_SERIES_STM32WBAX config POWER_SUPPLY_SMPS_2V5_SUPPLIES_EXT bool "External SMPS 2.5V supply and bypass" - depends on !SOC_SERIES_STM32U5X + depends on !SOC_SERIES_STM32U5X && !SOC_SERIES_STM32WBAX config POWER_SUPPLY_EXTERNAL_SOURCE bool "Bypass" - depends on !SOC_SERIES_STM32U5X + depends on !SOC_SERIES_STM32U5X && !SOC_SERIES_STM32WBAX endchoice diff --git a/soc/arm/st_stm32/stm32wba/soc.c b/soc/arm/st_stm32/stm32wba/soc.c index 9d027af604f..b0e2a439b5a 100644 --- a/soc/arm/st_stm32/stm32wba/soc.c +++ b/soc/arm/st_stm32/stm32wba/soc.c @@ -13,6 +13,7 @@ #include #include #include +#include #include #include #include @@ -44,6 +45,13 @@ static int stm32wba_init(void) /* Enable PWR */ LL_AHB4_GRP1_EnableClock(LL_AHB4_GRP1_PERIPH_PWR); +#if defined(CONFIG_POWER_SUPPLY_DIRECT_SMPS) + LL_PWR_SetRegulatorSupply(LL_PWR_SMPS_SUPPLY); +#elif defined(CONFIG_POWER_SUPPLY_LDO) + LL_PWR_SetRegulatorSupply(LL_PWR_LDO_SUPPLY); +#endif + + return 0; } From be0208a639528ca738461ee214480c3622969fd1 Mon Sep 17 00:00:00 2001 From: Erwan Gouriou Date: Fri, 1 Dec 2023 17:09:51 +0100 Subject: [PATCH 0762/3723] boards: stm32: Add support for nucleo_wba55cg nucleo_wba55cg is a SMPS version of nucleo_wba52cg Signed-off-by: Erwan Gouriou --- boards/arm/nucleo_wba55cg/Kconfig.board | 8 + boards/arm/nucleo_wba55cg/Kconfig.defconfig | 16 + .../nucleo_wba55cg/arduino_r3_connector.dtsi | 39 +++ boards/arm/nucleo_wba55cg/board.cmake | 3 + .../nucleo_wba55cg/doc/img/nucleowba55cg.jpg | Bin 0 -> 87801 bytes .../arm/nucleo_wba55cg/doc/nucleo_wba55cg.rst | 292 ++++++++++++++++++ boards/arm/nucleo_wba55cg/nucleo_wba55cg.dts | 137 ++++++++ boards/arm/nucleo_wba55cg/nucleo_wba55cg.yaml | 21 ++ .../nucleo_wba55cg/nucleo_wba55cg_defconfig | 33 ++ boards/arm/nucleo_wba55cg/support/openocd.cfg | 26 ++ 10 files changed, 575 insertions(+) create mode 100644 boards/arm/nucleo_wba55cg/Kconfig.board create mode 100644 boards/arm/nucleo_wba55cg/Kconfig.defconfig create mode 100644 boards/arm/nucleo_wba55cg/arduino_r3_connector.dtsi create mode 100644 boards/arm/nucleo_wba55cg/board.cmake create mode 100644 boards/arm/nucleo_wba55cg/doc/img/nucleowba55cg.jpg create mode 100644 boards/arm/nucleo_wba55cg/doc/nucleo_wba55cg.rst create mode 100644 boards/arm/nucleo_wba55cg/nucleo_wba55cg.dts create mode 100644 boards/arm/nucleo_wba55cg/nucleo_wba55cg.yaml create mode 100644 boards/arm/nucleo_wba55cg/nucleo_wba55cg_defconfig create mode 100644 boards/arm/nucleo_wba55cg/support/openocd.cfg diff --git a/boards/arm/nucleo_wba55cg/Kconfig.board b/boards/arm/nucleo_wba55cg/Kconfig.board new file mode 100644 index 00000000000..44bb0e5dcd8 --- /dev/null +++ b/boards/arm/nucleo_wba55cg/Kconfig.board @@ -0,0 +1,8 @@ +# STM32WBA55CG Nucleo board configuration + +# Copyright (c) 2023 STMicroelectronics +# SPDX-License-Identifier: Apache-2.0 + +config BOARD_NUCLEO_WBA55CG + bool "Nucleo WBA55CG Development Board" + depends on SOC_STM32WBA55XX diff --git a/boards/arm/nucleo_wba55cg/Kconfig.defconfig b/boards/arm/nucleo_wba55cg/Kconfig.defconfig new file mode 100644 index 00000000000..ed24776ee4e --- /dev/null +++ b/boards/arm/nucleo_wba55cg/Kconfig.defconfig @@ -0,0 +1,16 @@ +# STM32WBA52CG Nucleo board configuration + +# Copyright (c) 2023 STMicroelectronics + +# SPDX-License-Identifier: Apache-2.0 + +if BOARD_NUCLEO_WBA55CG + +config BOARD + default "nucleo_wba55cg" + +config SPI_STM32_INTERRUPT + default y + depends on SPI + +endif # BOARD_NUCLEO_WBA55CG diff --git a/boards/arm/nucleo_wba55cg/arduino_r3_connector.dtsi b/boards/arm/nucleo_wba55cg/arduino_r3_connector.dtsi new file mode 100644 index 00000000000..619cebea62a --- /dev/null +++ b/boards/arm/nucleo_wba55cg/arduino_r3_connector.dtsi @@ -0,0 +1,39 @@ +/* + * Copyright (c) 2023 STMicroelectronics + * + * SPDX-License-Identifier: Apache-2.0 + */ + +/ { + arduino_header: connector { + compatible = "arduino-header-r3"; + #gpio-cells = <2>; + gpio-map-mask = <0xffffffff 0xffffffc0>; + gpio-map-pass-thru = <0 0x3f>; + gpio-map = <0 0 &gpioa 7 0>, /* A0 */ + <1 0 &gpioa 6 0>, /* A1 */ + <2 0 &gpioa 2 0>, /* A2 */ + <3 0 &gpioa 1 0>, /* A3 */ + <4 0 &gpioa 5 0>, /* A4 */ + <5 0 &gpioa 0 0>, /* A5 */ + <6 0 &gpioa 10 0>, /* D0 */ + <7 0 &gpiob 5 0>, /* D1 */ + <8 0 &gpiob 7 0>, /* D2 */ + <9 0 &gpiob 6 0>, /* D3 */ + <10 0 &gpiob 13 0>, /* D4 */ + <11 0 &gpiob 14 0>, /* D5 */ + <12 0 &gpiob 0 0>, /* D6 */ + <13 0 &gpiob 9 0>, /* D7 */ + <14 0 &gpiob 15 0>, /* D8 */ + <15 0 &gpioa 9 0>, /* D9 */ + <16 0 &gpioa 12 0>, /* D10 */ + <17 0 &gpioa 15 0>, /* D11 */ + <18 0 &gpiob 3 0>, /* D12 */ + <19 0 &gpiob 4 0>, /* D13 */ + <20 0 &gpiob 1 0>, /* D14 */ + <21 0 &gpiob 2 0>; /* D15 */ + }; +}; + +arduino_i2c: &i2c1 {}; +arduino_spi: &spi1 {}; diff --git a/boards/arm/nucleo_wba55cg/board.cmake b/boards/arm/nucleo_wba55cg/board.cmake new file mode 100644 index 00000000000..50f543d4e6a --- /dev/null +++ b/boards/arm/nucleo_wba55cg/board.cmake @@ -0,0 +1,3 @@ +board_runner_args(stm32cubeprogrammer "--port=swd" "--reset-mode=hw") + +include(${ZEPHYR_BASE}/boards/common/stm32cubeprogrammer.board.cmake) diff --git a/boards/arm/nucleo_wba55cg/doc/img/nucleowba55cg.jpg b/boards/arm/nucleo_wba55cg/doc/img/nucleowba55cg.jpg new file mode 100644 index 0000000000000000000000000000000000000000..67c7d351e99626ff47c28cbfc1a402bd43928267 GIT binary patch literal 87801 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 literal 0 HcmV?d00001 diff --git a/boards/arm/nucleo_wba55cg/doc/nucleo_wba55cg.rst b/boards/arm/nucleo_wba55cg/doc/nucleo_wba55cg.rst new file mode 100644 index 00000000000..f4d170040bf --- /dev/null +++ b/boards/arm/nucleo_wba55cg/doc/nucleo_wba55cg.rst @@ -0,0 +1,292 @@ +.. _nucleo_wba55cg_board: + +ST Nucleo WBA55CG +################# + +Overview +******** + +NUCLEO-WBA55CG is a Bluetooth® Low Energy wireless and ultra-low-power board +embedding a powerful and ultra-low-power radio compliant with the Bluetooth® +Low Energy SIG specification v5.3. + +The ARDUINO® Uno V3 connectivity support and the ST morpho headers allow the +easy expansion of the functionality of the STM32 Nucleo open development +platform with a wide choice of specialized shields. + +- Ultra-low-power wireless STM32WBA55CG microcontroller based on the Arm® + Cortex®‑M33 core, featuring 1 Mbyte of flash memory and 128 Kbytes of SRAM in + a UFQFPN48 package + +- MCU RF board (MB1863): + + - 2.4 GHz RF transceiver supporting Bluetooth® specification v5.3 + - Arm® Cortex® M33 CPU with TrustZone®, MPU, DSP, and FPU + - Integrated PCB antenna + +- Three user LEDs +- Three user and one reset push-buttons + +- Board connectors: + + - USB Micro-B + - ARDUINO® Uno V3 expansion connector + - ST morpho headers for full access to all STM32 I/Os + +- Flexible power-supply options: ST-LINK USB VBUS or external sources +- On-board STLINK-V3MODS debugger/programmer with USB re-enumeration capability: + mass storage, Virtual COM port, and debug port + +.. image:: img/nucleowba55cg.jpg + :align: center + :alt: Nucleo WBA55CG + +Hardware +******** + +The STM32WBA55xx multiprotocol wireless and ultralow power devices embed a +powerful and ultralow power radio compliant with the Bluetooth® SIG Low Energy +specification 5.3. They contain a high-performance Arm Cortex-M33 32-bit RISC +core. They operate at a frequency of up to 100 MHz. + +- Includes ST state-of-the-art patented technology + +- Ultra low power radio: + + - 2.4 GHz radio + - RF transceiver supporting Bluetooth® Low Energy 5.3 specification + - Proprietary protocols + - RX sensitivity: -96 dBm (Bluetooth® Low Energy at 1 Mbps) + - Programmable output power, up to +10 dBm with 1 dB steps + - Integrated balun to reduce BOM + - Suitable for systems requiring compliance with radio frequency regulations + ETSI EN 300 328, EN 300 440, FCC CFR47 Part 15 and ARIB STD-T66 + +- Ultra low power platform with FlexPowerControl: + + - 1.71 to 3.6 V power supply + - - 40 °C to 85 °C temperature range + - Autonomous peripherals with DMA, functional down to Stop 1 mode + - 140 nA Standby mode (16 wake-up pins) + - 200 nA Standby mode with RTC + - 2.4 µA Standby mode with 64 KB SRAM + - 16.3 µA Stop mode with 64 KB SRAM + - 45 µA/MHz Run mode at 3.3 V + - Radio: Rx 7.4 mA / Tx at 0 dBm 10.6 mA + +- Core: Arm® 32-bit Cortex®-M33 CPU with TrustZone®, MPU, DSP, and FPU +- ART Accelerator™: 8-Kbyte instruction cache allowing 0-wait-state execution + from flash memory (frequency up to 100 MHz, 150 DMIPS) +- Power management: embedded regulator LDO supporting voltage scaling + +- Benchmarks: + + - 1.5 DMIPS/MHz (Drystone 2.1) + - 407 CoreMark® (4.07 CoreMark/MHz) + +- Clock sources: + + - 32 MHz crystal oscillator + - 32 kHz crystal oscillator (LSE) + - Internal low-power 32 kHz (±5%) RC + - Internal 16 MHz factory trimmed RC (±1%) + - PLL for system clock and ADC + +- Memories: + + - 1 MB flash memory with ECC, including 256 Kbytes with 100 cycles + - 128 KB SRAM, including 64 KB with parity check + - 512-byte (32 rows) OTP + +- Rich analog peripherals (independent supply): + + - 12-bit ADC 2.5 Msps with hardware oversampling + +- Communication peripherals: + + - Three UARTs (ISO 7816, IrDA, modem) + - Two SPIs + - Two I2C Fm+ (1 Mbit/s), SMBus/PMBus® + +- System peripherals: + + - Touch sensing controller, up to 20 sensors, supporting touch key, linear, + rotary touch sensors + - One 16-bit, advanced motor control timer + - Three 16-bit timers + - One 32-bit timer + - Two low-power 16-bit timers (available in Stop mode) + - Two Systick timers + - Two watchdogs + - 8-channel DMA controller, functional in Stop mode + +- Security and cryptography: + + - Arm® TrustZone® and securable I/Os, memories, and peripherals + - Flexible life cycle scheme with RDP and password protected debug + - Root of trust thanks to unique boot entry and secure hide protection area (HDP) + - SFI (secure firmware installation) thanks to embedded RSS (root secure services) + - Secure data storage with root hardware unique key (RHUK) + - Secure firmware upgrade support with TF-M + - Two AES co-processors, including one with DPA resistance + - Public key accelerator, DPA resistant + - HASH hardware accelerator + - True random number generator, NIST SP800-90B compliant + - 96-bit unique ID + - Active tampers + - CRC calculation unit + +- Up to 35 I/Os (most of them 5 V-tolerant) with interrupt capability + +- Development support: + + - Serial wire debug (SWD), JTAG + +- ECOPACK2 compliant package + +More information about STM32WBA series can be found here: + +- `STM32WBA Series on www.st.com`_ + +Supported Features +================== + +The Zephyr nucleo_wba55cg board configuration supports the following hardware features: + ++-----------+------------+-------------------------------------+ +| Interface | Controller | Driver/Component | ++===========+============+=====================================+ +| NVIC | on-chip | nested vector interrupt controller | ++-----------+------------+-------------------------------------+ +| UART | on-chip | serial port-polling; | +| | | serial port-interrupt | ++-----------+------------+-------------------------------------+ +| PINMUX | on-chip | pinmux | ++-----------+------------+-------------------------------------+ +| GPIO | on-chip | gpio | ++-----------+------------+-------------------------------------+ +| I2C | on-chip | i2c | ++-----------+------------+-------------------------------------+ +| SPI | on-chip | spi | ++-----------+------------+-------------------------------------+ +| ADC | on-chip | adc | ++-----------+------------+-------------------------------------+ +| WATCHDOG | on-chip | independent watchdog | ++-----------+------------+-------------------------------------+ +| RNG | on-chip | True Random number generator | ++-----------+------------+-------------------------------------+ + +Other hardware features are not yet supported on this Zephyr port. + +The default configuration can be found in the defconfig file: +``boards/arm/nucleo_wba55cg/nucleo_wba55cg_defconfig`` + +Connections and IOs +=================== + +Nucleo WBA55CG Board has 4 GPIO controllers. These controllers are responsible for pin muxing, +input/output, pull-up, etc. + +Default Zephyr Peripheral Mapping: +---------------------------------- + +.. rst-class:: rst-columns + +- USART_1 TX/RX : PB12/PA8 +- I2C_1_SCL : PB2 +- I2C_1_SDA : PB1 +- USER_PB : PC13 +- LD1 : PB4 +- SPI_1_NSS : PA12 (arduino_spi) +- SPI_1_SCK : PB4 (arduino_spi) +- SPI_1_MISO : PB3 (arduino_spi) +- SPI_1_MOSI : PA15 (arduino_spi) + +System Clock +------------ + +Nucleo WBA55CG System Clock could be driven by internal or external oscillator, +as well as main PLL clock. By default System clock is driven by HSE+PLL clock at 100MHz. + +Serial Port +----------- + +Nucleo WBA55CG board has 1 U(S)ARTs. The Zephyr console output is assigned to USART1. +Default settings are 115500 8N1. + + +Programming and Debugging +************************* + +Nucleo WBA55CG board includes an ST-LINK/V3 embedded debug tool interface. +It could be used for flash and debug using either OpenOCD or STM32Cube ecosystem tools. + +OpenOCD Support +=============== + +For now, openocd support is available only on upstream OpenOCD. You can check +`OpenOCD official Github mirror`_. +In order to use it, you should clone and compile it following usual README +guidelines. +Once it is done, you can set the OPENOCD and OPENOCD_DEFAULT_PATH variables in +:zephyr_file:`boards/arm/nucleo_wba55cg/board.cmake` to point the build +to the paths of the OpenOCD binary and its scripts, before +including the common openocd.board.cmake file: + + .. code-block:: none + + set(OPENOCD "/src/openocd" CACHE FILEPATH "" FORCE) + set(OPENOCD_DEFAULT_PATH /tcl) + include(${ZEPHYR_BASE}/boards/common/openocd.board.cmake) + +Flashing +======== + +STM32CubeProgrammer is configured as flashing tool by default. +If available OpenOCD could be used. Same process applies with both tools. + +Flashing an application to Nucleo WBA55CG +----------------------------------------- + +Here is an example for the :zephyr:code-sample:`blinky` application. + +.. zephyr-app-commands:: + :zephyr-app: samples/basic/blinky + :board: nucleo_wba55cg + :goals: build flash + +You will see the LED blinking every second. + +Debugging +========= + +Debugging using OpenOCD +----------------------- + +You can debug an application in the usual way using OpenOCD. Here is an example for the +:zephyr:code-sample:`blinky` application. + +.. zephyr-app-commands:: + :zephyr-app: samples/basic/blinky + :board: nucleo_wba55cg + :maybe-skip-config: + :goals: debug + +Debugging using STM32CubeIDE +---------------------------- + +You can debug an application using a STM32WBA compatible version of STM32CubeIDE. +For that: +- Create an empty STM32WBA project by going to File > New > STM32 project +- Select your MCU, click Next, and select an Empty project. +- Right click on your project name, select Debug as > Debug configurations +- In the new window, create a new target in STM32 Cortex-M C/C++ Application +- Select the new target and enter the path to zephyr.elf file in the C/C++ Application field +- Check Disable auto build +- Run debug + +.. _STM32WBA Series on www.st.com: + https://www.st.com/en/microcontrollers-microprocessors/stm32wba-series.html + +.. _OpenOCD official Github mirror: + https://github.com/openocd-org/openocd/commit/870769b0ba9f4dae6ada9d8b1a40d75bd83aaa06 diff --git a/boards/arm/nucleo_wba55cg/nucleo_wba55cg.dts b/boards/arm/nucleo_wba55cg/nucleo_wba55cg.dts new file mode 100644 index 00000000000..5f190357a0d --- /dev/null +++ b/boards/arm/nucleo_wba55cg/nucleo_wba55cg.dts @@ -0,0 +1,137 @@ +/* + * Copyright (c) 2023 STMicroelectronics + * + * SPDX-License-Identifier: Apache-2.0 + */ + +/dts-v1/; +#include +/* Todo: Once available, use wba55 dedicated pinctrl.dtsi */ +#include +#include "arduino_r3_connector.dtsi" +#include + +/ { + model = "STMicroelectronics STM32WBA55CG-NUCLEO board"; + compatible = "st,stm32wba55cg-nucleo"; + + #address-cells = <1>; + #size-cells = <1>; + + chosen { + zephyr,console = &usart1; + zephyr,shell-uart = &usart1; + zephyr,sram = &sram0; + zephyr,flash = &flash0; + }; + + leds: leds { + compatible = "gpio-leds"; + blue_led_1: led_1 { + gpios = <&gpiob 4 GPIO_ACTIVE_LOW>; + label = "User LD1"; + }; + }; + + gpio_keys { + compatible = "gpio-keys"; + user_button: button { + label = "User"; + gpios = <&gpioc 13 GPIO_ACTIVE_LOW>; + zephyr,code = ; + }; + }; + + aliases { + led0 = &blue_led_1; + sw0 = &user_button; + }; +}; + +&clk_lsi { + status = "okay"; +}; + +&clk_lse { + status = "okay"; +}; + +&clk_hse { + status = "okay"; +}; + +&pll1 { + div-m = <8>; + mul-n = <48>; + div-q = <2>; + div-r = <2>; + clocks = <&clk_hse>; + status = "okay"; +}; + +&rcc { + clocks = <&pll1>; + clock-frequency = ; + ahb-prescaler = <1>; + ahb5-prescaler = <4>; + apb1-prescaler = <1>; + apb2-prescaler = <1>; + apb7-prescaler = <1>; +}; + +&iwdg { + status = "okay"; +}; + +&rtc { + status = "okay"; + clocks = <&rcc STM32_CLOCK_BUS_APB7 0x00200000>, + <&rcc STM32_SRC_LSE RTC_SEL(1)>; + prescaler = <32768>; +}; + +&usart1 { + pinctrl-0 = <&usart1_tx_pb12 &usart1_rx_pa8>; + pinctrl-names = "default"; + current-speed = <115200>; + status = "okay"; +}; + +&lpuart1 { + pinctrl-0 = <&lpuart1_tx_pb5 &lpuart1_rx_pa10>; + pinctrl-names = "default"; + current-speed = <115200>; + status = "okay"; +}; + +&spi1 { + pinctrl-0 = <&spi1_nss_pa12 &spi1_sck_pb4 + &spi1_miso_pb3 &spi1_mosi_pa15>; + pinctrl-names = "default"; + status = "okay"; +}; + +&i2c1 { + pinctrl-0 = <&i2c1_scl_pb2 &i2c1_sda_pb1>; + pinctrl-names = "default"; + status = "okay"; + clock-frequency = ; +}; + +&adc4 { + pinctrl-0 = <&adc4_in8_pa1>; + pinctrl-names = "default"; + st,adc-clock-source = ; + st,adc-prescaler = <4>; + status = "okay"; +}; + +&lptim1 { + clocks = <&rcc STM32_CLOCK_BUS_APB7 0x00000800>, + <&rcc STM32_SRC_LSE LPTIM1_SEL(3)>; + status = "okay"; +}; + +&rng { + status = "okay"; +}; diff --git a/boards/arm/nucleo_wba55cg/nucleo_wba55cg.yaml b/boards/arm/nucleo_wba55cg/nucleo_wba55cg.yaml new file mode 100644 index 00000000000..0f435e29c75 --- /dev/null +++ b/boards/arm/nucleo_wba55cg/nucleo_wba55cg.yaml @@ -0,0 +1,21 @@ +identifier: nucleo_wba55cg +name: ST Nucleo WBA55CG +type: mcu +arch: arm +toolchain: + - zephyr + - gnuarmemb +supported: + - gpio + - i2c + - spi + - adc + - watchdog + - rng + - arduino_gpio + - arduino_i2c + - arduino_spi + - counter +ram: 128 +flash: 1024 +vendor: st diff --git a/boards/arm/nucleo_wba55cg/nucleo_wba55cg_defconfig b/boards/arm/nucleo_wba55cg/nucleo_wba55cg_defconfig new file mode 100644 index 00000000000..270c9c297f1 --- /dev/null +++ b/boards/arm/nucleo_wba55cg/nucleo_wba55cg_defconfig @@ -0,0 +1,33 @@ +# SPDX-License-Identifier: Apache-2.0 +# Copyright (c) 2023 STMicroelectronics + +CONFIG_SOC_SERIES_STM32WBAX=y +CONFIG_SOC_STM32WBA55XX=y + +# enable uart driver +CONFIG_SERIAL=y + +# enable GPIO +CONFIG_GPIO=y + +# Enable clock +CONFIG_CLOCK_CONTROL=y + +# console +CONFIG_CONSOLE=y +CONFIG_UART_CONSOLE=y + +# Enable MPU +CONFIG_ARM_MPU=y + +# Enable HW stack protection +CONFIG_HW_STACK_PROTECTION=y + +# enable pin controller +CONFIG_PINCTRL=y + +# LSE defined as LPTIM clock source by the DTS +CONFIG_STM32_LPTIM_CLOCK_LSE=y + +# Enable the internal SMPS regulator +CONFIG_POWER_SUPPLY_DIRECT_SMPS=y diff --git a/boards/arm/nucleo_wba55cg/support/openocd.cfg b/boards/arm/nucleo_wba55cg/support/openocd.cfg new file mode 100644 index 00000000000..247de974f39 --- /dev/null +++ b/boards/arm/nucleo_wba55cg/support/openocd.cfg @@ -0,0 +1,26 @@ +# Note: Using OpenOCD using nucloe_wba52cg requires using openocd fork. +# See board documentation for more information + +source [find interface/stlink-dap.cfg] + +set WORKAREASIZE 0x8000 + +transport select "dapdirect_swd" + +# Enable debug when in low power modes +set ENABLE_LOW_POWER 1 + +# Stop Watchdog counters when halt +set STOP_WATCHDOG 1 + +# STlink Debug clock frequency +set CLOCK_FREQ 8000 + +# Reset configuration +# use hardware reset, connect under reset +# connect_assert_srst needed if low power mode application running (WFI...) +reset_config srst_only srst_nogate + +source [find target/stm32wbax.cfg] + +gdb_memory_map disable From bf652b20a9de36c95e24b41128a42d960e92dfbd Mon Sep 17 00:00:00 2001 From: Erwan Gouriou Date: Mon, 4 Dec 2023 11:17:40 +0100 Subject: [PATCH 0763/3723] tests: drivers: adc: Support nucleo_wba55cg Enable adc tests on this board. Signed-off-by: Erwan Gouriou --- .../adc/adc_api/boards/nucleo_wba55cg.overlay | 34 +++++++++++++++++++ 1 file changed, 34 insertions(+) create mode 100644 tests/drivers/adc/adc_api/boards/nucleo_wba55cg.overlay diff --git a/tests/drivers/adc/adc_api/boards/nucleo_wba55cg.overlay b/tests/drivers/adc/adc_api/boards/nucleo_wba55cg.overlay new file mode 100644 index 00000000000..ce78f7b25ce --- /dev/null +++ b/tests/drivers/adc/adc_api/boards/nucleo_wba55cg.overlay @@ -0,0 +1,34 @@ +/* + * SPDX-License-Identifier: Apache-2.0 + * + * Copyright (c) 2023 STMicroelectronics + */ + +/ { + zephyr,user { + /* adjust channel number according to pinmux in board.dts */ + io-channels = <&adc4 7>, <&adc4 8>; + }; +}; + +&adc4 { + pinctrl-0 = <&adc4_in7_pa2 &adc4_in8_pa1>; + #address-cells = <1>; + #size-cells = <0>; + + channel@7 { + reg = <7>; + zephyr,gain = "ADC_GAIN_1"; + zephyr,reference = "ADC_REF_INTERNAL"; + zephyr,acquisition-time = ; + zephyr,resolution = <12>; + }; + + channel@8 { + reg = <8>; + zephyr,gain = "ADC_GAIN_1"; + zephyr,reference = "ADC_REF_INTERNAL"; + zephyr,acquisition-time = ; + zephyr,resolution = <12>; + }; +}; From d65cb1fe12a8fbae94b9449dca131391481c10da Mon Sep 17 00:00:00 2001 From: Yong Cong Sin Date: Tue, 5 Dec 2023 17:53:50 +0800 Subject: [PATCH 0764/3723] shell: fix shell instance name typo Fixing typo from the original implementation in 44705b698c725166834f19d6fd5db2804f9a0d60, which resulted in the name of current shell instance getting print over and over again. Signed-off-by: Yong Cong Sin --- subsys/shell/shell_cmds.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/subsys/shell/shell_cmds.c b/subsys/shell/shell_cmds.c index 0932cd4adfc..b1a29799a88 100644 --- a/subsys/shell/shell_cmds.c +++ b/subsys/shell/shell_cmds.c @@ -231,7 +231,7 @@ static int cmd_backends(const struct shell *sh, size_t argc, char **argv) shell_print(sh, "Active shell backends:"); STRUCT_SECTION_FOREACH(shell, obj) { - shell_print(sh, " %2d. :%s (%s)", cnt++, obj->ctx->prompt, sh->name); + shell_print(sh, " %2d. :%s (%s)", cnt++, obj->ctx->prompt, obj->name); } return 0; From 0d0b17095d824b426b8f406b16a790317cad418a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Martin=20=C3=85berg?= Date: Tue, 3 Oct 2023 13:06:13 +0200 Subject: [PATCH 0765/3723] tests: c_lib: Enable sqrt tests in non-FPU configurations MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This enables the sqrt() and sqrtf() tests also in case of soft-float configurations. It is expected that the tests will link, run and pass also in such configuration. Signed-off-by: Martin Åberg --- tests/lib/c_lib/common/src/test_sqrt.c | 18 ------------------ 1 file changed, 18 deletions(-) diff --git a/tests/lib/c_lib/common/src/test_sqrt.c b/tests/lib/c_lib/common/src/test_sqrt.c index fba12cce59b..cd06e33e7d3 100644 --- a/tests/lib/c_lib/common/src/test_sqrt.c +++ b/tests/lib/c_lib/common/src/test_sqrt.c @@ -106,16 +106,6 @@ int32_t *p_root_squared = (int32_t *)&root_squared; max_error = 0; - /* Conversion not supported with minimal_libc without - * CBPRINTF_FP_SUPPORT. - * - * Conversion not supported without FPU except on POSIX arch based targets. - */ - if (!(IS_ENABLED(CONFIG_FPU) - || IS_ENABLED(CONFIG_ARCH_POSIX))) { - ztest_test_skip(); - return; - } /* test the special cases of 0.0, NAN, -NAN, INF, -INF, and -10.0 */ zassert_true(sqrtf(0.0f) == 0.0f, "sqrtf(0.0)"); @@ -175,14 +165,6 @@ int64_t *p_root_squared = (int64_t *)&root_squared; max_error = 0; - /* - * sqrt is not supported without FPU except on POSIX arch based targets. - */ - if (!(IS_ENABLED(CONFIG_FPU) - || IS_ENABLED(CONFIG_ARCH_POSIX))) { - ztest_test_skip(); - return; - } /* test the special cases of 0.0, NAN, -NAN, INF, -INF, and -10.0 */ zassert_true(sqrt(0.0) == 0.0, "sqrt(0.0)"); From b05148d4857b4f13f9e82e987f056f1af18630bb Mon Sep 17 00:00:00 2001 From: Marek Pieta Date: Tue, 5 Dec 2023 13:30:39 +0100 Subject: [PATCH 0766/3723] logging: Fix using simplified message creation mode Change fixes marcos used to determine if argument types allow simplified message creation mode. Both arguments types must be proper. Signed-off-by: Marek Pieta --- include/zephyr/logging/log_msg.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/include/zephyr/logging/log_msg.h b/include/zephyr/logging/log_msg.h index fabc7a16b0c..39cbf1cedbc 100644 --- a/include/zephyr/logging/log_msg.h +++ b/include/zephyr/logging/log_msg.h @@ -241,7 +241,7 @@ enum z_log_msg_mode { #define LOG_MSG_SIMPLE_ARG_TYPE_CHECK_0(fmt) 1 #define LOG_MSG_SIMPLE_ARG_TYPE_CHECK_1(fmt, arg) Z_CBPRINTF_IS_WORD_NUM(arg) #define LOG_MSG_SIMPLE_ARG_TYPE_CHECK_2(fmt, arg0, arg1) \ - Z_CBPRINTF_IS_WORD_NUM(arg0) || Z_CBPRINTF_IS_WORD_NUM(arg1) + Z_CBPRINTF_IS_WORD_NUM(arg0) && Z_CBPRINTF_IS_WORD_NUM(arg1) /** brief Determine if string arguments types allow to use simplified message creation mode. * From b78bbe409fb4fd818df353bffa456d7bbbc3a34f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Benjamin=20Cab=C3=A9?= Date: Thu, 23 Nov 2023 07:44:19 +0100 Subject: [PATCH 0767/3723] doc: mgmt/osdp: Fix doxygen comments MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - Misc fixes to improperly documented structs - Show all PD and SC API in docs - Document enums Signed-off-by: Benjamin Cabé --- include/zephyr/mgmt/osdp.h | 343 ++++++++++++++++++++++++------------- 1 file changed, 227 insertions(+), 116 deletions(-) diff --git a/include/zephyr/mgmt/osdp.h b/include/zephyr/mgmt/osdp.h index 14080821239..b73314aece2 100644 --- a/include/zephyr/mgmt/osdp.h +++ b/include/zephyr/mgmt/osdp.h @@ -4,6 +4,11 @@ * SPDX-License-Identifier: Apache-2.0 */ +/** + * @file + * @brief Open Supervised Device Protocol (OSDP) public API header file. + */ + #ifndef _OSDP_H_ #define _OSDP_H_ @@ -16,27 +21,35 @@ extern "C" { #endif -#define OSDP_CMD_TEXT_MAX_LEN 32 -#define OSDP_CMD_KEYSET_KEY_MAX_LEN 32 -#define OSDP_EVENT_MAX_DATALEN 64 +#define OSDP_CMD_TEXT_MAX_LEN 32 /**< Max length of text for text command */ +#define OSDP_CMD_KEYSET_KEY_MAX_LEN 32 /**< Max length of key data for keyset command */ +#define OSDP_EVENT_MAX_DATALEN 64 /**< Max length of event data */ /** * @brief Command sent from CP to Control digital output of PD. - * - * @param output_no 0 = First Output, 1 = Second Output, etc. - * @param control_code One of the following: - * 0 - NOP – do not alter this output - * 1 - set the permanent state to OFF, abort timed operation (if any) - * 2 - set the permanent state to ON, abort timed operation (if any) - * 3 - set the permanent state to OFF, allow timed operation to complete - * 4 - set the permanent state to ON, allow timed operation to complete - * 5 - set the temporary state to ON, resume perm state on timeout - * 6 - set the temporary state to OFF, resume permanent state on timeout - * @param timer_count Time in units of 100 ms */ struct osdp_cmd_output { + /** + * Output number. + * + * 0 = First Output, 1 = Second Output, etc. + */ uint8_t output_no; + /** + * Control code. + * + * - 0 - NOP – do not alter this output + * - 1 - set the permanent state to OFF, abort timed operation (if any) + * - 2 - set the permanent state to ON, abort timed operation (if any) + * - 3 - set the permanent state to OFF, allow timed operation to complete + * - 4 - set the permanent state to ON, allow timed operation to complete + * - 5 - set the temporary state to ON, resume perm state on timeout + * - 6 - set the temporary state to OFF, resume permanent state on timeout + */ uint8_t control_code; + /** + * Time in units of 100 ms + */ uint16_t timer_count; }; @@ -44,108 +57,156 @@ struct osdp_cmd_output { * @brief LED Colors as specified in OSDP for the on_color/off_color parameters. */ enum osdp_led_color_e { - OSDP_LED_COLOR_NONE, - OSDP_LED_COLOR_RED, - OSDP_LED_COLOR_GREEN, - OSDP_LED_COLOR_AMBER, - OSDP_LED_COLOR_BLUE, - OSDP_LED_COLOR_SENTINEL + OSDP_LED_COLOR_NONE, /**< No color */ + OSDP_LED_COLOR_RED, /**< Red */ + OSDP_LED_COLOR_GREEN, /**< Green */ + OSDP_LED_COLOR_AMBER, /**< Amber */ + OSDP_LED_COLOR_BLUE, /**< Blue */ + OSDP_LED_COLOR_SENTINEL /**< Max value */ }; /** - * @brief LED params sub-structure. Part of LED command. See struct osdp_cmd_led - * - * @param control_code One of the following: - * Temporary Control Code: - * 0 - NOP - do not alter this LED's temporary settings - * 1 - Cancel any temporary operation and display this LED's permanent state - * immediately - * 2 - Set the temporary state as given and start timer immediately - * Permanent Control Code: - * 0 - NOP - do not alter this LED's permanent settings - * 1 - Set the permanent state as given - * @param on_count The ON duration of the flash, in units of 100 ms - * @param off_count The OFF duration of the flash, in units of 100 ms - * @param on_color Color to set during the ON timer (enum osdp_led_color_e) - * @param off_color Color to set during the OFF timer (enum osdp_led_color_e) - * @param timer_count Time in units of 100 ms (only for temporary mode) + * @brief LED params sub-structure. Part of LED command. See @ref osdp_cmd_led. */ struct osdp_cmd_led_params { + /** Control code. + * + * Temporary Control Code: + * - 0 - NOP - do not alter this LED's temporary settings. + * - 1 - Cancel any temporary operation and display this LED's permanent state immediately. + * - 2 - Set the temporary state as given and start timer immediately. + * + * Permanent Control Code: + * - 0 - NOP - do not alter this LED's permanent settings. + * - 1 - Set the permanent state as given. + */ uint8_t control_code; + /** + * The ON duration of the flash, in units of 100 ms. + */ uint8_t on_count; + /** + * The OFF duration of the flash, in units of 100 ms. + */ uint8_t off_count; + /** + * Color to set during the ON timer (see @ref osdp_led_color_e). + */ uint8_t on_color; + /** + * Color to set during the OFF timer (see @ref osdp_led_color_e). + */ uint8_t off_color; + /** + * Time in units of 100 ms (only for temporary mode). + */ uint16_t timer_count; }; /** * @brief Sent from CP to PD to control the behaviour of it's on-board LEDs - * - * @param reader 0 = First Reader, 1 = Second Reader, etc. - * @param led_number 0 = first LED, 1 = second LED, etc. - * @param temporary ephemeral LED status descriptor - * @param permanent permanent LED status descriptor */ struct osdp_cmd_led { + /** + * Reader number. 0 = First Reader, 1 = Second Reader, etc. + */ uint8_t reader; + /** + * LED number. 0 = first LED, 1 = second LED, etc. + */ uint8_t led_number; + /** + * Ephemeral LED status descriptor. + */ struct osdp_cmd_led_params temporary; + /** + * Permanent LED status descriptor. + */ struct osdp_cmd_led_params permanent; }; /** * @brief Sent from CP to control the behaviour of a buzzer in the PD. - * - * @param reader 0 = First Reader, 1 = Second Reader, etc. - * @param control_code 0: no tone, 1: off, 2: default tone, 3+ is TBD. - * @param on_count The ON duration of the flash, in units of 100 ms - * @param off_count The OFF duration of the flash, in units of 100 ms - * @param rep_count The number of times to repeat the ON/OFF cycle; 0: forever */ struct osdp_cmd_buzzer { + /** + * Reader number. 0 = First Reader, 1 = Second Reader, etc. + */ uint8_t reader; + /** + * Control code. + * - 0 - no tone + * - 1 - off + * - 2 - default tone + * - 3+ - TBD + */ uint8_t control_code; + /** + * The ON duration of the sound, in units of 100 ms. + */ uint8_t on_count; + /** + * The OFF duration of the sound, in units of 100 ms. + */ uint8_t off_count; + /** + * The number of times to repeat the ON/OFF cycle; 0: forever. + */ uint8_t rep_count; }; /** * @brief Command to manipulate any display units that the PD supports. - * - * @param reader 0 = First Reader, 1 = Second Reader, etc. - * @param control_code One of the following: - * 1 - permanent text, no wrap - * 2 - permanent text, with wrap - * 3 - temp text, no wrap - * 4 - temp text, with wrap - * @param temp_time duration to display temporary text, in seconds - * @param offset_row row to display the first character (1 indexed) - * @param offset_col column to display the first character (1 indexed) - * @param length Number of characters in the string - * @param data The string to display */ struct osdp_cmd_text { + /** + * Reader number. 0 = First Reader, 1 = Second Reader, etc. + */ uint8_t reader; + /** + * Control code. + * - 1 - permanent text, no wrap + * - 2 - permanent text, with wrap + * - 3 - temp text, no wrap + * - 4 - temp text, with wrap + */ uint8_t control_code; + /** + * Duration to display temporary text, in seconds + */ uint8_t temp_time; + /** + * Row to display the first character (1-indexed) + */ uint8_t offset_row; + /** + * Column to display the first character (1-indexed) + */ uint8_t offset_col; + /** + * Number of characters in the string + */ uint8_t length; + /** + * The string to display + */ uint8_t data[OSDP_CMD_TEXT_MAX_LEN]; }; /** * @brief Sent in response to a COMSET command. Set communication parameters to * PD. Must be stored in PD non-volatile memory. - * - * @param address Unit ID to which this PD will respond after the change takes - * effect. - * @param baud_rate baud rate value 9600/38400/115200 */ struct osdp_cmd_comset { + /** + * Unit ID to which this PD will respond after the change takes effect. + */ uint8_t address; + /** + * Baud rate. + * + * Valid values: 9600, 19200, 38400, 115200, 230400. + */ uint32_t baud_rate; }; @@ -158,8 +219,18 @@ struct osdp_cmd_comset { * @param data Key data */ struct osdp_cmd_keyset { + /** + * Type of keys: + * - 0x01 – Secure Channel Base Key + */ uint8_t type; + /** + * Number of bytes of key data - (Key Length in bits + 7) / 8 + */ uint8_t length; + /** + * Key data + */ uint8_t data[OSDP_CMD_KEYSET_KEY_MAX_LEN]; }; @@ -167,37 +238,36 @@ struct osdp_cmd_keyset { * @brief OSDP application exposed commands */ enum osdp_cmd_e { - OSDP_CMD_OUTPUT = 1, - OSDP_CMD_LED, - OSDP_CMD_BUZZER, - OSDP_CMD_TEXT, - OSDP_CMD_KEYSET, - OSDP_CMD_COMSET, - OSDP_CMD_SENTINEL + OSDP_CMD_OUTPUT = 1, /**< Output control command */ + OSDP_CMD_LED, /**< Reader LED control command */ + OSDP_CMD_BUZZER, /**< Reader buzzer control command */ + OSDP_CMD_TEXT, /**< Reader text output command */ + OSDP_CMD_KEYSET, /**< Encryption Key Set Command */ + OSDP_CMD_COMSET, /**< PD Communication Configuration Command */ + OSDP_CMD_SENTINEL /**< Max command value */ }; /** * @brief OSDP Command Structure. This is a wrapper for all individual OSDP * commands. - * - * @param id used to select specific commands in union. Type: enum osdp_cmd_e - * @param led LED command structure - * @param buzzer buzzer command structure - * @param text text command structure - * @param output output command structure - * @param comset comset command structure - * @param keyset keyset command structure */ struct osdp_cmd { + /** @cond INTERNAL_HIDDEN */ sys_snode_t node; + /** @endcond */ + /** + * Command ID. + * Used to select specific commands in union. + */ enum osdp_cmd_e id; + /** Command */ union { - struct osdp_cmd_led led; - struct osdp_cmd_buzzer buzzer; - struct osdp_cmd_text text; - struct osdp_cmd_output output; - struct osdp_cmd_comset comset; - struct osdp_cmd_keyset keyset; + struct osdp_cmd_led led; /**< LED command structure */ + struct osdp_cmd_buzzer buzzer; /**< Buzzer command structure */ + struct osdp_cmd_text text; /**< Text command structure */ + struct osdp_cmd_output output; /**< Output command structure */ + struct osdp_cmd_comset comset; /**< Comset command structure */ + struct osdp_cmd_keyset keyset; /**< Keyset command structure */ }; }; @@ -206,49 +276,62 @@ struct osdp_cmd { * when a PD must report a card read. */ enum osdp_event_cardread_format_e { - OSDP_CARD_FMT_RAW_UNSPECIFIED, - OSDP_CARD_FMT_RAW_WIEGAND, - OSDP_CARD_FMT_ASCII, - OSDP_CARD_FMT_SENTINEL + OSDP_CARD_FMT_RAW_UNSPECIFIED, /**< Unspecified card format */ + OSDP_CARD_FMT_RAW_WIEGAND, /**< Wiegand card format */ + OSDP_CARD_FMT_ASCII, /**< ASCII card format */ + OSDP_CARD_FMT_SENTINEL /**< Max card format value */ }; /** * @brief OSDP event cardread * - * @param reader_no In context of readers attached to current PD, this number - * indicated this number. This is not supported by LibOSDP. - * @param format Format of the card being read. - * see `enum osdp_event_cardread_format_e` - * @param direction Card read direction of PD 0 - Forward; 1 - Backward - * @param length Length of card data in bytes or bits depending on `format` - * (see note). - * @param data Card data of `length` bytes or bits bits depending on `format` - * (see note). - * - * @note When `format` is set to OSDP_CARD_FMT_RAW_UNSPECIFIED or + * @note When @a format is set to OSDP_CARD_FMT_RAW_UNSPECIFIED or * OSDP_CARD_FMT_RAW_WIEGAND, the length is expressed in bits. OTOH, when it is * set to OSDP_CARD_FMT_ASCII, the length is in bytes. The number of bytes to - * read from the `data` field must be interpreted accordingly. + * read from the @a data field must be interpreted accordingly. */ struct osdp_event_cardread { + /** + * Reader number. 0 = First Reader, 1 = Second Reader, etc. + */ int reader_no; + /** + * Format of the card being read. + */ enum osdp_event_cardread_format_e format; + /** + * Direction of data in @a data array. + * - 0 - Forward + * - 1 - Backward + */ int direction; + /** + * Length of card data in bytes or bits depending on @a format + */ int length; + /** + * Card data of @a length bytes or bits bits depending on @a format + */ uint8_t data[OSDP_EVENT_MAX_DATALEN]; }; /** * @brief OSDP Event Keypad - * - * @param reader_no In context of readers attached to current PD, this number - * indicated this number. This is not supported by LibOSDP. - * @param length Length of keypress data in bytes - * @param data keypress data of `length` bytes */ struct osdp_event_keypress { + /** + * Reader number. + * In context of readers attached to current PD, this number indicated this number. This is + * not supported by LibOSDP. + */ int reader_no; + /** + * Length of keypress data in bytes + */ int length; + /** + * Keypress data of @a length bytes + */ uint8_t data[OSDP_EVENT_MAX_DATALEN]; }; @@ -256,24 +339,27 @@ struct osdp_event_keypress { * @brief OSDP PD Events */ enum osdp_event_type { - OSDP_EVENT_CARDREAD, - OSDP_EVENT_KEYPRESS, - OSDP_EVENT_SENTINEL + OSDP_EVENT_CARDREAD, /**< Card read event */ + OSDP_EVENT_KEYPRESS, /**< Keypad press event */ + OSDP_EVENT_SENTINEL /**< Max event value */ }; /** * @brief OSDP Event structure. - * - * @param type used to select specific event in union. See: enum osdp_event_type - * @param keypress keypress event structure - * @param cardread cardread event structure */ struct osdp_event { + /** @cond INTERNAL_HIDDEN */ sys_snode_t node; + /** @endcond */ + /** + * Event type. + * Used to select specific event in union. + */ enum osdp_event_type type; + /** Event */ union { - struct osdp_event_keypress keypress; - struct osdp_event_cardread cardread; + struct osdp_event_keypress keypress; /**< Keypress event structure */ + struct osdp_event_cardread cardread; /**< Card read event structure */ }; }; @@ -309,7 +395,13 @@ typedef int (*pd_command_callback_t)(void *arg, struct osdp_cmd *cmd); */ typedef int (*cp_event_callback_t)(void *arg, int pd, struct osdp_event *ev); -#ifdef CONFIG_OSDP_MODE_PD +#if defined(CONFIG_OSDP_MODE_PD) || defined(__DOXYGEN__) + +/** + * @name Peripheral Device mode APIs + * @note These are only available when @kconfig{CONFIG_OSDP_MODE_PD} is enabled. + * @{ + */ /** * @brief Set callback method for PD command notification. This callback is @@ -331,6 +423,10 @@ void osdp_pd_set_command_callback(pd_command_callback_t cb, void *arg); */ int osdp_pd_notify_event(const struct osdp_event *event); +/** + * @} + */ + #else /* CONFIG_OSDP_MODE_PD */ /** @@ -359,10 +455,25 @@ void osdp_cp_set_event_callback(cp_event_callback_t cb, void *arg); #endif /* CONFIG_OSDP_MODE_PD */ -#ifdef CONFIG_OSDP_SC_ENABLED +#if defined(CONFIG_OSDP_SC_ENABLED) || defined(__DOXYGEN__) +/** + * @name OSDP Secure Channel APIs + * @note These are only available when @kconfig{CONFIG_OSDP_SC_ENABLED} is + * enabled. + * @{ + */ + +/** + * Get the current SC status mask. + * @return SC status mask + */ uint32_t osdp_get_sc_status_mask(void); +/** + * @} + */ + #endif #ifdef __cplusplus From 0b32004c09d4aa897e96c5b4260a051e0659f3a0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Manuel=20Arg=C3=BCelles?= Date: Fri, 1 Dec 2023 12:50:36 +0700 Subject: [PATCH 0768/3723] tests: userspace: exclude ucans32k1sic due to lack of MPU regions MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This board have an NXP MPU with 8 configurable regions, of which five of them are already used by the static MPU configuration. Many of these tests are failing due to lack of MPU regions or free partition slots available, even when HW stack protection is disabled when building with userspace support. Signed-off-by: Manuel Argüelles --- samples/userspace/prod_consumer/sample.yaml | 2 ++ samples/userspace/shared_mem/sample.yaml | 1 + subsys/testsuite/Kconfig | 2 +- tests/kernel/fatal/exception/testcase.yaml | 8 ++++++-- tests/kernel/mem_protect/mem_protect/testcase.yaml | 4 +++- tests/kernel/mem_protect/protection/testcase.yaml | 4 +++- tests/kernel/mem_protect/userspace/testcase.yaml | 2 ++ tests/kernel/threads/tls/testcase.yaml | 2 ++ 8 files changed, 20 insertions(+), 5 deletions(-) diff --git a/samples/userspace/prod_consumer/sample.yaml b/samples/userspace/prod_consumer/sample.yaml index cc4aaa5d118..232fdd31f06 100644 --- a/samples/userspace/prod_consumer/sample.yaml +++ b/samples/userspace/prod_consumer/sample.yaml @@ -15,3 +15,5 @@ tests: filter: CONFIG_ARCH_HAS_USERSPACE arch_exclude: - posix + platform_exclude: + - ucans32k1sic diff --git a/samples/userspace/shared_mem/sample.yaml b/samples/userspace/shared_mem/sample.yaml index 954b6a9d3d6..5b42ae2b7e3 100644 --- a/samples/userspace/shared_mem/sample.yaml +++ b/samples/userspace/shared_mem/sample.yaml @@ -20,5 +20,6 @@ tests: - twr_ke18f - cy8cproto_062_4343w - cy8cproto_063_ble + - ucans32k1sic extra_configs: - CONFIG_TEST_HW_STACK_PROTECTION=n diff --git a/subsys/testsuite/Kconfig b/subsys/testsuite/Kconfig index eff533a9da2..5fa2a240f4d 100644 --- a/subsys/testsuite/Kconfig +++ b/subsys/testsuite/Kconfig @@ -143,7 +143,7 @@ config TEST_ENABLE_USERSPACE config TEST_USERSPACE_WITHOUT_HW_STACK_PROTECTION bool "Run User Mode tests without additionally enabling stack protection" depends on TEST_ENABLE_USERSPACE - default y if SOC_SERIES_KINETIS_KE1XF + default y if SOC_SERIES_KINETIS_KE1XF || SOC_SERIES_S32K1XX help A HW platform might not have sufficient MPU/MMU capabilities to support running all test cases with User Mode and HW Stack Protection features diff --git a/tests/kernel/fatal/exception/testcase.yaml b/tests/kernel/fatal/exception/testcase.yaml index 0d5b9e46100..6f95950717d 100644 --- a/tests/kernel/fatal/exception/testcase.yaml +++ b/tests/kernel/fatal/exception/testcase.yaml @@ -3,7 +3,9 @@ common: tests: kernel.common.stack_protection: extra_args: CONF_FILE=prj.conf - platform_exclude: twr_ke18f + platform_exclude: + - twr_ke18f + - ucans32k1sic filter: CONFIG_ARCH_HAS_STACK_PROTECTION arch_exclude: - posix @@ -19,7 +21,9 @@ tests: - memory_protection kernel.common.stack_protection_arm_fpu_sharing: extra_args: CONF_FILE=prj_arm_fpu_sharing.conf - platform_exclude: twr_ke18f + platform_exclude: + - twr_ke18f + - ucans32k1sic arch_allow: arm filter: CONFIG_ARCH_HAS_STACK_PROTECTION and CONFIG_ARMV7_M_ARMV8_M_FP tags: diff --git a/tests/kernel/mem_protect/mem_protect/testcase.yaml b/tests/kernel/mem_protect/mem_protect/testcase.yaml index 20a9e8f7ac8..002b9ae0973 100644 --- a/tests/kernel/mem_protect/mem_protect/testcase.yaml +++ b/tests/kernel/mem_protect/mem_protect/testcase.yaml @@ -9,7 +9,9 @@ tests: filter: CONFIG_ARCH_HAS_USERSPACE arch_exclude: - posix - platform_exclude: twr_ke18f + platform_exclude: + - twr_ke18f + - ucans32k1sic extra_args: - CONFIG_TEST_HW_STACK_PROTECTION=n - CONFIG_MINIMAL_LIBC=y diff --git a/tests/kernel/mem_protect/protection/testcase.yaml b/tests/kernel/mem_protect/protection/testcase.yaml index 6644dda5396..8ade4199e48 100644 --- a/tests/kernel/mem_protect/protection/testcase.yaml +++ b/tests/kernel/mem_protect/protection/testcase.yaml @@ -1,6 +1,8 @@ tests: kernel.memory_protection.protection: - platform_exclude: twr_ke18f + platform_exclude: + - twr_ke18f + - ucans32k1sic filter: CONFIG_SRAM_REGION_PERMISSIONS tags: - kernel diff --git a/tests/kernel/mem_protect/userspace/testcase.yaml b/tests/kernel/mem_protect/userspace/testcase.yaml index b098883c05f..40a80ae13a8 100644 --- a/tests/kernel/mem_protect/userspace/testcase.yaml +++ b/tests/kernel/mem_protect/userspace/testcase.yaml @@ -12,6 +12,8 @@ tests: extra_configs: - CONFIG_TEST_HW_STACK_PROTECTION=n - CONFIG_COMMON_LIBC_MALLOC_ARENA_SIZE=0 + platform_exclude: + - ucans32k1sic kernel.memory_protection.userspace.gap_filling.arc: filter: CONFIG_ARCH_HAS_USERSPACE and CONFIG_MPU_REQUIRES_NON_OVERLAPPING_REGIONS arch_allow: arc diff --git a/tests/kernel/threads/tls/testcase.yaml b/tests/kernel/threads/tls/testcase.yaml index 4206ecdeff2..6261e12eee4 100644 --- a/tests/kernel/threads/tls/testcase.yaml +++ b/tests/kernel/threads/tls/testcase.yaml @@ -16,6 +16,8 @@ tests: CONFIG_TOOLCHAIN_SUPPORTS_THREAD_LOCAL_STORAGE arch_exclude: - posix + platform_exclude: + - ucans32k1sic # ARCMWDT can't handle THREAD_LOCAL_STORAGE with USERSPACE, see #52570 for details toolchain_exclude: arcmwdt extra_configs: From 006ee60afc8e5a61f26419a8853b5b9fe1c8203c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Manuel=20Arg=C3=BCelles?= Date: Tue, 5 Dec 2023 15:27:01 +0700 Subject: [PATCH 0769/3723] tests: kernel: skip kernel.common.stack_sentinel for hifive1 MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Test consistently fails with timeout for board `hifive1`, so exclude this board until fixed. Signed-off-by: Manuel Argüelles --- tests/kernel/fatal/exception/testcase.yaml | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/tests/kernel/fatal/exception/testcase.yaml b/tests/kernel/fatal/exception/testcase.yaml index 6f95950717d..4304040e6ee 100644 --- a/tests/kernel/fatal/exception/testcase.yaml +++ b/tests/kernel/fatal/exception/testcase.yaml @@ -43,8 +43,9 @@ tests: - mps2_an385 kernel.common.stack_sentinel: extra_args: CONF_FILE=sentinel.conf - # FIXME: See issue #39948 - platform_exclude: qemu_cortex_a9 + platform_exclude: + - qemu_cortex_a9 # FIXME: See issue #39948 + - hifive1 # FIXME: See issue #66070 tags: kernel integration_platforms: - qemu_x86 From 07bf0f95fef11f37cf9f84067815485f072171af Mon Sep 17 00:00:00 2001 From: Fabio Baltieri Date: Tue, 28 Nov 2023 15:29:22 +0000 Subject: [PATCH 0770/3723] input: gpio_keys: drop zephyr_code from the callback struct It's not really used from here, guess it was a leftover. Signed-off-by: Fabio Baltieri --- drivers/input/input_gpio_keys.c | 2 -- 1 file changed, 2 deletions(-) diff --git a/drivers/input/input_gpio_keys.c b/drivers/input/input_gpio_keys.c index bf157d59471..f13ff7dbab4 100644 --- a/drivers/input/input_gpio_keys.c +++ b/drivers/input/input_gpio_keys.c @@ -16,7 +16,6 @@ LOG_MODULE_REGISTER(gpio_keys, CONFIG_INPUT_LOG_LEVEL); struct gpio_keys_callback { struct gpio_callback gpio_cb; - uint32_t zephyr_code; int8_t pin_state; }; @@ -106,7 +105,6 @@ static int gpio_keys_interrupt_configure(const struct gpio_dt_spec *gpio_spec, return retval; } - cb->zephyr_code = zephyr_code; cb->pin_state = -1; flags = GPIO_INT_EDGE_BOTH & ~GPIO_INT_MODE_DISABLED; From f6917bca14904de559c220baa97508e0eb6e89de Mon Sep 17 00:00:00 2001 From: Fabio Baltieri Date: Tue, 28 Nov 2023 15:30:04 +0000 Subject: [PATCH 0771/3723] input: gpio_keys: interrupt configure cleanup Use the same ret variable name as the rest of the file, drop a redundant mask, use gpio_pin_interrupt_configure_dt. Signed-off-by: Fabio Baltieri --- drivers/input/input_gpio_keys.c | 18 ++++++++++-------- 1 file changed, 10 insertions(+), 8 deletions(-) diff --git a/drivers/input/input_gpio_keys.c b/drivers/input/input_gpio_keys.c index f13ff7dbab4..28cb8875e42 100644 --- a/drivers/input/input_gpio_keys.c +++ b/drivers/input/input_gpio_keys.c @@ -94,25 +94,27 @@ static void gpio_keys_interrupt(const struct device *dev, struct gpio_callback * static int gpio_keys_interrupt_configure(const struct gpio_dt_spec *gpio_spec, struct gpio_keys_callback *cb, uint32_t zephyr_code) { - int retval; - gpio_flags_t flags; + int ret; gpio_init_callback(&cb->gpio_cb, gpio_keys_interrupt, BIT(gpio_spec->pin)); - retval = gpio_add_callback(gpio_spec->port, &cb->gpio_cb); - if (retval < 0) { + ret = gpio_add_callback(gpio_spec->port, &cb->gpio_cb); + if (ret < 0) { LOG_ERR("Could not set gpio callback"); - return retval; + return ret; } cb->pin_state = -1; - flags = GPIO_INT_EDGE_BOTH & ~GPIO_INT_MODE_DISABLED; LOG_DBG("%s [0x%p, %d]", __func__, gpio_spec->port, gpio_spec->pin); - retval = z_impl_gpio_pin_interrupt_configure(gpio_spec->port, gpio_spec->pin, flags); + ret = gpio_pin_interrupt_configure_dt(gpio_spec, GPIO_INT_EDGE_BOTH); + if (ret < 0) { + LOG_ERR("interrupt configuration failed: %d", ret); + return ret; + } - return retval; + return 0; } static int gpio_keys_init(const struct device *dev) From 9080007ef9c46b813a67e0a5845b052e1fe7b1c5 Mon Sep 17 00:00:00 2001 From: Fabio Baltieri Date: Tue, 28 Nov 2023 15:30:56 +0000 Subject: [PATCH 0772/3723] input: gpio_keys: drop the pin filter from the callback The bit check field is redundant since the callback struct is masked to a single pin already. Drop it, simplify the code a bit. Signed-off-by: Fabio Baltieri --- drivers/input/input_gpio_keys.c | 19 ++++--------------- 1 file changed, 4 insertions(+), 15 deletions(-) diff --git a/drivers/input/input_gpio_keys.c b/drivers/input/input_gpio_keys.c index 28cb8875e42..aca17d466cb 100644 --- a/drivers/input/input_gpio_keys.c +++ b/drivers/input/input_gpio_keys.c @@ -65,30 +65,19 @@ static void gpio_keys_change_deferred(struct k_work *work) } } -static void gpio_keys_change_call_deferred(struct gpio_keys_pin_data *data, uint32_t msec) -{ - int __maybe_unused rv = k_work_reschedule(&data->work, K_MSEC(msec)); - - __ASSERT(rv >= 0, "Set wake mask work queue error"); -} - static void gpio_keys_interrupt(const struct device *dev, struct gpio_callback *cbdata, uint32_t pins) { - ARG_UNUSED(dev); /* This is a pointer to GPIO device, use dev pointer in - * cbdata for pointer to gpio_debounce device node - */ struct gpio_keys_callback *keys_cb = CONTAINER_OF( cbdata, struct gpio_keys_callback, gpio_cb); struct gpio_keys_pin_data *pin_data = CONTAINER_OF( keys_cb, struct gpio_keys_pin_data, cb_data); const struct gpio_keys_config *cfg = pin_data->dev->config; - for (int i = 0; i < cfg->num_keys; i++) { - if (pins & BIT(cfg->pin_cfg[i].spec.pin)) { - gpio_keys_change_call_deferred(pin_data, cfg->debounce_interval_ms); - } - } + ARG_UNUSED(dev); /* GPIO device pointer. */ + ARG_UNUSED(pins); + + k_work_reschedule(&pin_data->work, K_MSEC(cfg->debounce_interval_ms)); } static int gpio_keys_interrupt_configure(const struct gpio_dt_spec *gpio_spec, From c6b5c61667ab6dab28b6eca434c50cee2231c4d7 Mon Sep 17 00:00:00 2001 From: Andriy Gelman Date: Sun, 19 Nov 2023 13:46:16 -0500 Subject: [PATCH 0773/3723] drivers: ethernet: phy_mii: Fix invalid phy_id check When there'is no phy at the address both registers will return 0xFFFF, giving a phy address of UINT32_MAX, not 0x00FFFFFF. Signed-off-by: Andriy Gelman --- drivers/ethernet/phy/phy_mii.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/drivers/ethernet/phy/phy_mii.c b/drivers/ethernet/phy/phy_mii.c index 4ad961089e6..94585708517 100644 --- a/drivers/ethernet/phy/phy_mii.c +++ b/drivers/ethernet/phy/phy_mii.c @@ -39,6 +39,8 @@ struct phy_mii_dev_data { /* Offset to align capabilities bits of 1000BASE-T Control and Status regs */ #define MII_1KSTSR_OFFSET 2 +#define MII_INVALID_PHY_ID UINT32_MAX + static int phy_mii_get_link_state(const struct device *dev, struct phy_link_state *state); @@ -436,7 +438,7 @@ static int phy_mii_initialize(const struct device *dev) } if (get_id(dev, &phy_id) == 0) { - if (phy_id == 0xFFFFFF) { + if (phy_id == MII_INVALID_PHY_ID) { LOG_ERR("No PHY found at address %d", cfg->phy_addr); From bf7d9838ab36386454d3144109441c884bd14fd9 Mon Sep 17 00:00:00 2001 From: Andriy Gelman Date: Sun, 19 Nov 2023 13:47:14 -0500 Subject: [PATCH 0774/3723] drivers: ethernet: phy_mii: Remove unnecessary bitwise operation value is already uint16_t. Signed-off-by: Andriy Gelman --- drivers/ethernet/phy/phy_mii.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/ethernet/phy/phy_mii.c b/drivers/ethernet/phy/phy_mii.c index 94585708517..041be3dafaa 100644 --- a/drivers/ethernet/phy/phy_mii.c +++ b/drivers/ethernet/phy/phy_mii.c @@ -120,13 +120,13 @@ static int get_id(const struct device *dev, uint32_t *phy_id) return -EIO; } - *phy_id = (value & 0xFFFF) << 16; + *phy_id = value << 16; if (reg_read(dev, MII_PHYID2R, &value) < 0) { return -EIO; } - *phy_id |= (value & 0xFFFF); + *phy_id |= value; return 0; } From 9f76adbfa846b7f4b5711644c2c43b69d287220c Mon Sep 17 00:00:00 2001 From: Attie Grande Date: Sun, 26 Nov 2023 15:37:34 +0000 Subject: [PATCH 0775/3723] soc: atmel_sam0: Setup clocks for USB on SAML21 parts GCLK Gen 2 was dedicated to USB, but never setup... this patch configures it for 48 MHz, derrived from DFLL. Signed-off-by: Attie Grande --- soc/arm/atmel_sam0/common/soc_saml2x.c | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/soc/arm/atmel_sam0/common/soc_saml2x.c b/soc/arm/atmel_sam0/common/soc_saml2x.c index c4c1a659dd6..6f29f9c525d 100644 --- a/soc/arm/atmel_sam0/common/soc_saml2x.c +++ b/soc/arm/atmel_sam0/common/soc_saml2x.c @@ -215,6 +215,18 @@ static inline void gclk_main_configure(void) GCLK->GENCTRL[0].bit.SRC = GCLK_GENCTRL_SRC_DFLL48M_Val; } +#if !CONFIG_USB_DC_SAM0 +#define gclk_usb_configure() +#else +static inline void gclk_usb_configure(void) +{ + GCLK->GENCTRL[2].reg = 0 + | GCLK_GENCTRL_SRC_DFLL48M + | GCLK_GENCTRL_DIV(1) + | GCLK_GENCTRL_GENEN; +} +#endif + #if !CONFIG_ADC_SAM0 #define gclk_adc_configure() #else @@ -255,5 +267,6 @@ void z_arm_platform_init(void) flash_waitstates_init(); pm_init(); gclk_main_configure(); + gclk_usb_configure(); gclk_adc_configure(); } From 6a5297c4a9f5df554b44d4900d72d4f352297108 Mon Sep 17 00:00:00 2001 From: Attie Grande Date: Sun, 26 Nov 2023 15:38:09 +0000 Subject: [PATCH 0776/3723] boards: arm: atsaml21: Setup USB for SAML21 Xplained board Set up pinctrl for USB D+/- on pins PA24 and PA25. Signed-off-by: Attie Grande --- boards/arm/atsaml21_xpro/atsaml21_xpro-pinctrl.dtsi | 7 +++++++ boards/arm/atsaml21_xpro/atsaml21_xpro.dts | 3 +++ 2 files changed, 10 insertions(+) diff --git a/boards/arm/atsaml21_xpro/atsaml21_xpro-pinctrl.dtsi b/boards/arm/atsaml21_xpro/atsaml21_xpro-pinctrl.dtsi index eb96b72e339..102e6b2253e 100644 --- a/boards/arm/atsaml21_xpro/atsaml21_xpro-pinctrl.dtsi +++ b/boards/arm/atsaml21_xpro/atsaml21_xpro-pinctrl.dtsi @@ -56,4 +56,11 @@ ; }; }; + + usb0_default: usb0_default { + group1 { + pinmux = , + ; + }; + }; }; diff --git a/boards/arm/atsaml21_xpro/atsaml21_xpro.dts b/boards/arm/atsaml21_xpro/atsaml21_xpro.dts index 0e03a7e96f4..ee800d7ae95 100644 --- a/boards/arm/atsaml21_xpro/atsaml21_xpro.dts +++ b/boards/arm/atsaml21_xpro/atsaml21_xpro.dts @@ -141,4 +141,7 @@ zephyr_udc0: &usb0 { status = "okay"; + + pinctrl-0 = <&usb0_default>; + pinctrl-names = "default"; }; From a60054eb15317d8224c6ff79549d4ae905fe914f Mon Sep 17 00:00:00 2001 From: Attie Grande Date: Sun, 26 Nov 2023 15:38:09 +0000 Subject: [PATCH 0777/3723] boards: arm: atsamr34: Setup USB for SAMR34 Xplained board Set up pinctrl for USB D+/- on pins PA24 and PA25. Signed-off-by: Attie Grande --- boards/arm/atsamr34_xpro/atsamr34_xpro-pinctrl.dtsi | 7 +++++++ boards/arm/atsamr34_xpro/atsamr34_xpro.dts | 3 +++ 2 files changed, 10 insertions(+) diff --git a/boards/arm/atsamr34_xpro/atsamr34_xpro-pinctrl.dtsi b/boards/arm/atsamr34_xpro/atsamr34_xpro-pinctrl.dtsi index 81cfb6a7bca..e7e01a22536 100644 --- a/boards/arm/atsamr34_xpro/atsamr34_xpro-pinctrl.dtsi +++ b/boards/arm/atsamr34_xpro/atsamr34_xpro-pinctrl.dtsi @@ -34,4 +34,11 @@ ; }; }; + + usb0_default: usb0_default { + group1 { + pinmux = , + ; + }; + }; }; diff --git a/boards/arm/atsamr34_xpro/atsamr34_xpro.dts b/boards/arm/atsamr34_xpro/atsamr34_xpro.dts index aba04a1b3e6..fe0ae80ae35 100644 --- a/boards/arm/atsamr34_xpro/atsamr34_xpro.dts +++ b/boards/arm/atsamr34_xpro/atsamr34_xpro.dts @@ -121,4 +121,7 @@ zephyr_udc0: &usb0 { status = "okay"; + + pinctrl-0 = <&usb0_default>; + pinctrl-names = "default"; }; From 78af1c1e3878c410067bd49846771300fa86b840 Mon Sep 17 00:00:00 2001 From: Dawid Niedzwiecki Date: Fri, 1 Dec 2023 11:27:37 +0100 Subject: [PATCH 0778/3723] entropy: stm32: suspend when pool is full Suspend the RNG module when the pool is full to save power. The generated numbers aren't used anyway. Signed-off-by: Dawid Niedzwiecki --- drivers/entropy/entropy_stm32.c | 78 ++++++++++++++++++++++----------- 1 file changed, 53 insertions(+), 25 deletions(-) diff --git a/drivers/entropy/entropy_stm32.c b/drivers/entropy/entropy_stm32.c index 0abedb1940c..75537680bfb 100644 --- a/drivers/entropy/entropy_stm32.c +++ b/drivers/entropy/entropy_stm32.c @@ -103,6 +103,50 @@ static struct entropy_stm32_rng_dev_data entropy_stm32_rng_data = { .rng = (RNG_TypeDef *)DT_INST_REG_ADDR(0), }; +static int entropy_stm32_suspend(const struct device *dev) +{ + struct entropy_stm32_rng_dev_data *dev_data = dev->data; + const struct entropy_stm32_rng_dev_cfg *dev_cfg = dev->config; + RNG_TypeDef *rng = dev_data->rng; + int res; + + LL_RNG_Disable(rng); + +#ifdef CONFIG_SOC_SERIES_STM32WBAX + uint32_t wait_cycles, rng_rate; + + if (clock_control_get_rate(dev_data->clock, + (clock_control_subsys_t) &dev_cfg->pclken[0], + &rng_rate) < 0) { + return -EIO; + } + + wait_cycles = SystemCoreClock / rng_rate * 2; + + for (int i = wait_cycles; i >= 0; i--) { + } +#endif /* CONFIG_SOC_SERIES_STM32WBAX */ + + res = clock_control_off(dev_data->clock, + (clock_control_subsys_t)&dev_cfg->pclken[0]); + + return res; +} + +static int entropy_stm32_resume(const struct device *dev) +{ + struct entropy_stm32_rng_dev_data *dev_data = dev->data; + const struct entropy_stm32_rng_dev_cfg *dev_cfg = dev->config; + RNG_TypeDef *rng = dev_data->rng; + int res; + + res = clock_control_on(dev_data->clock, + (clock_control_subsys_t)&dev_cfg->pclken[0]); + LL_RNG_Enable(rng); + + return res; +} + static void configure_rng(void) { RNG_TypeDef *rng = entropy_stm32_rng_data.rng; @@ -338,6 +382,7 @@ static int start_pool_filling(bool wait) { unsigned int key; bool already_filling; + const struct device *dev = DEVICE_DT_GET(DT_DRV_INST(0)); key = irq_lock(); #if defined(CONFIG_SOC_SERIES_STM32WBX) || defined(CONFIG_STM32H7_DUAL_CORE) @@ -364,6 +409,7 @@ static int start_pool_filling(bool wait) */ pm_policy_state_lock_get(PM_STATE_SUSPEND_TO_IDLE, PM_ALL_SUBSTATES); + entropy_stm32_resume(dev); acquire_rng(); irq_enable(IRQN); @@ -474,6 +520,7 @@ static void rng_pool_init(struct rng_pool *rngp, uint16_t size, static void stm32_rng_isr(const void *arg) { int byte, ret; + const struct device *dev = DEVICE_DT_GET(DT_DRV_INST(0)); ARG_UNUSED(arg); @@ -491,6 +538,7 @@ static void stm32_rng_isr(const void *arg) if (ret < 0) { irq_disable(IRQN); release_rng(); + entropy_stm32_suspend(dev); pm_policy_state_lock_put(PM_STATE_SUSPEND_TO_IDLE, PM_ALL_SUBSTATES); entropy_stm32_rng_data.filling_pools = false; } @@ -637,37 +685,17 @@ static int entropy_stm32_rng_init(const struct device *dev) static int entropy_stm32_rng_pm_action(const struct device *dev, enum pm_device_action action) { - struct entropy_stm32_rng_dev_data *dev_data = dev->data; - const struct entropy_stm32_rng_dev_cfg *dev_cfg = dev->config; - RNG_TypeDef *rng = dev_data->rng; int res = 0; switch (action) { case PM_DEVICE_ACTION_SUSPEND: - LL_RNG_Disable(rng); - -#ifdef CONFIG_SOC_SERIES_STM32WBAX - uint32_t wait_cycles, rng_rate; - - if (clock_control_get_rate(dev_data->clock, - (clock_control_subsys_t) &dev_cfg->pclken[0], - &rng_rate) < 0) { - return -EIO; - } - - wait_cycles = SystemCoreClock / rng_rate * 2; - - for (int i = wait_cycles; i >= 0; i--) { - } -#endif /* CONFIG_SOC_SERIES_STM32WBAX */ - - res = clock_control_off(dev_data->clock, - (clock_control_subsys_t)&dev_cfg->pclken[0]); + res = entropy_stm32_suspend(dev); break; case PM_DEVICE_ACTION_RESUME: - res = clock_control_on(dev_data->clock, - (clock_control_subsys_t)&dev_cfg->pclken[0]); - LL_RNG_Enable(rng); + /* Resume RNG only if it was suspended during filling pool */ + if (entropy_stm32_rng_data.filling_pools) { + res = entropy_stm32_resume(dev); + } break; default: return -ENOTSUP; From 1cd7c55af9758f336d5ed1b453ef61970c1cd125 Mon Sep 17 00:00:00 2001 From: Emil Lindqvist Date: Mon, 4 Dec 2023 10:25:09 +0100 Subject: [PATCH 0779/3723] modem: modem_cellular: add U-blox SARA-R5 as modem U-blox SARA-R4 already exists but the behavior is different, requiring a separate driver instance. For instance, R5 autostarts, so this commit also adds support for skipping power on pulse. Signed-off-by: Emil Lindqvist --- drivers/modem/Kconfig.cellular | 4 +- drivers/modem/modem_cellular.c | 84 ++++++++++++++++++++++++++ dts/bindings/modem/u-blox,sara-r5.yaml | 15 +++++ 3 files changed, 101 insertions(+), 2 deletions(-) create mode 100644 dts/bindings/modem/u-blox,sara-r5.yaml diff --git a/drivers/modem/Kconfig.cellular b/drivers/modem/Kconfig.cellular index 72e6a74acbb..0460cda8d96 100644 --- a/drivers/modem/Kconfig.cellular +++ b/drivers/modem/Kconfig.cellular @@ -14,8 +14,8 @@ config MODEM_CELLULAR select NET_L2_PPP_PAP depends on (DT_HAS_QUECTEL_BG95_ENABLED || DT_HAS_ZEPHYR_GSM_PPP_ENABLED || \ DT_HAS_SIMCOM_SIM7080_ENABLED || DT_HAS_U_BLOX_SARA_R4_ENABLED || \ - DT_HAS_SWIR_HL7800_ENABLED || DT_HAS_TELIT_ME910G1_ENABLED || \ - DT_HAS_QUECTEL_EG25_G_ENABLED) + DT_HAS_U_BLOX_SARA_R5_ENABLED || DT_HAS_SWIR_HL7800_ENABLED || \ + DT_HAS_TELIT_ME910G1_ENABLED || DT_HAS_QUECTEL_EG25_G_ENABLED) help This driver uses the generic 3gpp AT commands, along with the standard protocols CMUX and PPP, to configure diff --git a/drivers/modem/modem_cellular.c b/drivers/modem/modem_cellular.c index c3b97f0b618..a038da1805e 100644 --- a/drivers/modem/modem_cellular.c +++ b/drivers/modem/modem_cellular.c @@ -114,6 +114,7 @@ struct modem_cellular_config { const uint16_t reset_pulse_duration_ms; const uint16_t startup_time_ms; const uint16_t shutdown_time_ms; + const bool autostarts; const struct modem_chat_script *init_chat_script; const struct modem_chat_script *dial_chat_script; const struct modem_chat_script *periodic_chat_script; @@ -444,6 +445,11 @@ static void modem_cellular_idle_event_handler(struct modem_cellular_data *data, switch (evt) { case MODEM_CELLULAR_EVENT_RESUME: + if (config->autostarts) { + modem_cellular_enter_state(data, MODEM_CELLULAR_STATE_AWAIT_POWER_ON); + break; + } + if (modem_cellular_gpio_is_enabled(&config->power_gpio)) { modem_cellular_enter_state(data, MODEM_CELLULAR_STATE_POWER_ON_PULSE); break; @@ -1538,6 +1544,51 @@ MODEM_CHAT_SCRIPT_DEFINE(u_blox_sara_r4_periodic_chat_script, modem_cellular_chat_callback_handler, 4); #endif +#if DT_HAS_COMPAT_STATUS_OKAY(u_blox_sara_r5) +MODEM_CHAT_SCRIPT_CMDS_DEFINE(u_blox_sara_r5_init_chat_script_cmds, + MODEM_CHAT_SCRIPT_CMD_RESP_NONE("AT", 100), + MODEM_CHAT_SCRIPT_CMD_RESP_NONE("AT", 100), + MODEM_CHAT_SCRIPT_CMD_RESP_NONE("AT", 100), + MODEM_CHAT_SCRIPT_CMD_RESP_NONE("AT", 100), + MODEM_CHAT_SCRIPT_CMD_RESP("ATE0", ok_match), + MODEM_CHAT_SCRIPT_CMD_RESP("AT+CFUN=4", ok_match), + MODEM_CHAT_SCRIPT_CMD_RESP("AT+CMEE=1", ok_match), + MODEM_CHAT_SCRIPT_CMD_RESP("AT+CREG=1", ok_match), + MODEM_CHAT_SCRIPT_CMD_RESP("AT+CGREG=1", ok_match), + MODEM_CHAT_SCRIPT_CMD_RESP("AT+CEREG=1", ok_match), + MODEM_CHAT_SCRIPT_CMD_RESP("AT+CREG?", ok_match), + MODEM_CHAT_SCRIPT_CMD_RESP("AT+CEREG?", ok_match), + MODEM_CHAT_SCRIPT_CMD_RESP("AT+CGREG?", ok_match), + MODEM_CHAT_SCRIPT_CMD_RESP("AT+CGSN", imei_match), + MODEM_CHAT_SCRIPT_CMD_RESP("", ok_match), + MODEM_CHAT_SCRIPT_CMD_RESP("AT+CGMM", cgmm_match), + MODEM_CHAT_SCRIPT_CMD_RESP("", ok_match), + MODEM_CHAT_SCRIPT_CMD_RESP("AT+CMUX=0,0,5,127", ok_match)); + +MODEM_CHAT_SCRIPT_DEFINE(u_blox_sara_r5_init_chat_script, u_blox_sara_r5_init_chat_script_cmds, + abort_matches, modem_cellular_chat_callback_handler, 10); + +MODEM_CHAT_SCRIPT_CMDS_DEFINE(u_blox_sara_r5_dial_chat_script_cmds, + MODEM_CHAT_SCRIPT_CMD_RESP_MULT("AT+CGACT=0,1", allow_match), + MODEM_CHAT_SCRIPT_CMD_RESP("AT+CGDCONT=1,\"IP\"," + "\""CONFIG_MODEM_CELLULAR_APN"\"", + ok_match), + MODEM_CHAT_SCRIPT_CMD_RESP("AT+CFUN=1", ok_match), + MODEM_CHAT_SCRIPT_CMD_RESP_NONE("ATD*99***1#", 0),); + +MODEM_CHAT_SCRIPT_DEFINE(u_blox_sara_r5_dial_chat_script, u_blox_sara_r5_dial_chat_script_cmds, + dial_abort_matches, modem_cellular_chat_callback_handler, 10); + +MODEM_CHAT_SCRIPT_CMDS_DEFINE(u_blox_sara_r5_periodic_chat_script_cmds, + MODEM_CHAT_SCRIPT_CMD_RESP("AT+CREG?", ok_match), + MODEM_CHAT_SCRIPT_CMD_RESP("AT+CEREG?", ok_match), + MODEM_CHAT_SCRIPT_CMD_RESP("AT+CGREG?", ok_match)); + +MODEM_CHAT_SCRIPT_DEFINE(u_blox_sara_r5_periodic_chat_script, + u_blox_sara_r5_periodic_chat_script_cmds, abort_matches, + modem_cellular_chat_callback_handler, 4); +#endif + #if DT_HAS_COMPAT_STATUS_OKAY(swir_hl7800) MODEM_CHAT_SCRIPT_CMDS_DEFINE(swir_hl7800_init_chat_script_cmds, MODEM_CHAT_SCRIPT_CMD_RESP_NONE("AT", 100), @@ -1778,6 +1829,35 @@ MODEM_CHAT_SCRIPT_DEFINE(telit_me910g1_periodic_chat_script, &MODEM_CELLULAR_INST_NAME(data, inst), \ &MODEM_CELLULAR_INST_NAME(config, inst), POST_KERNEL, 99, NULL); +#define MODEM_CELLULAR_DEVICE_U_BLOX_SARA_R5(inst) \ + MODEM_PPP_DEFINE(MODEM_CELLULAR_INST_NAME(ppp, inst), NULL, 98, 1500, 64); \ + \ + static struct modem_cellular_data MODEM_CELLULAR_INST_NAME(data, inst) = { \ + .chat_delimiter = {'\r'}, \ + .chat_filter = {'\n'}, \ + .ppp = &MODEM_CELLULAR_INST_NAME(ppp, inst), \ + }; \ + \ + static struct modem_cellular_config MODEM_CELLULAR_INST_NAME(config, inst) = { \ + .uart = DEVICE_DT_GET(DT_INST_BUS(inst)), \ + .power_gpio = GPIO_DT_SPEC_INST_GET_OR(inst, mdm_power_gpios, {}), \ + .reset_gpio = GPIO_DT_SPEC_INST_GET_OR(inst, mdm_reset_gpios, {}), \ + .autostarts = true, \ + .power_pulse_duration_ms = 1500, \ + .reset_pulse_duration_ms = 100, \ + .startup_time_ms = 1500, \ + .shutdown_time_ms = 13000, \ + .init_chat_script = &u_blox_sara_r5_init_chat_script, \ + .dial_chat_script = &u_blox_sara_r5_dial_chat_script, \ + .periodic_chat_script = &u_blox_sara_r5_periodic_chat_script, \ + }; \ + \ + PM_DEVICE_DT_INST_DEFINE(inst, modem_cellular_pm_action); \ + \ + 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, NULL); + #define MODEM_CELLULAR_DEVICE_SWIR_HL7800(inst) \ MODEM_PPP_DEFINE(MODEM_CELLULAR_INST_NAME(ppp, inst), NULL, 98, 1500, 64); \ \ @@ -1854,6 +1934,10 @@ DT_INST_FOREACH_STATUS_OKAY(MODEM_CELLULAR_DEVICE_SIMCOM_SIM7080) DT_INST_FOREACH_STATUS_OKAY(MODEM_CELLULAR_DEVICE_U_BLOX_SARA_R4) #undef DT_DRV_COMPAT +#define DT_DRV_COMPAT u_blox_sara_r5 +DT_INST_FOREACH_STATUS_OKAY(MODEM_CELLULAR_DEVICE_U_BLOX_SARA_R5) +#undef DT_DRV_COMPAT + #define DT_DRV_COMPAT swir_hl7800 DT_INST_FOREACH_STATUS_OKAY(MODEM_CELLULAR_DEVICE_SWIR_HL7800) #undef DT_DRV_COMPAT diff --git a/dts/bindings/modem/u-blox,sara-r5.yaml b/dts/bindings/modem/u-blox,sara-r5.yaml new file mode 100644 index 00000000000..af6c3318fd0 --- /dev/null +++ b/dts/bindings/modem/u-blox,sara-r5.yaml @@ -0,0 +1,15 @@ +# Copyright (c) 2023 Emil Lindqvist +# SPDX-License-Identifier: Apache-2.0 + +description: u-blox SARA-R5 modem + +compatible: "u-blox,sara-r5" + +include: uart-device.yaml + +properties: + mdm-power-gpios: + type: phandle-array + + mdm-reset-gpios: + type: phandle-array From 304d920ef1a18fe514eb4ede22b5b0df569dbd0d Mon Sep 17 00:00:00 2001 From: Seppo Takalo Date: Fri, 24 Nov 2023 13:40:19 +0200 Subject: [PATCH 0780/3723] net: lwm2m: Allow finding security instance by short ID. Add API to find a security instance ID with given Short Server ID. Signed-off-by: Seppo Takalo --- subsys/net/lib/lwm2m/lwm2m_engine.h | 8 ++++++++ subsys/net/lib/lwm2m/lwm2m_obj_security.c | 10 ++++++++++ 2 files changed, 18 insertions(+) diff --git a/subsys/net/lib/lwm2m/lwm2m_engine.h b/subsys/net/lib/lwm2m/lwm2m_engine.h index 2306fced197..2ea3e583242 100644 --- a/subsys/net/lib/lwm2m/lwm2m_engine.h +++ b/subsys/net/lib/lwm2m/lwm2m_engine.h @@ -133,6 +133,14 @@ int lwm2m_engine_call_now(k_work_handler_t service); */ int lwm2m_security_inst_id_to_index(uint16_t obj_inst_id); +/** + * @brief Returns the object instance id of the security having ssid given by @p short_id. + * + * @param[in] short_id ssid of the security object + * @return Object instance id or negative in case not found + */ +int lwm2m_security_short_id_to_inst(uint16_t short_id); + /** * @brief Returns the object instance id of the security object instance at @p index * in the security object list. diff --git a/subsys/net/lib/lwm2m/lwm2m_obj_security.c b/subsys/net/lib/lwm2m/lwm2m_obj_security.c index 874925c39d8..00796648634 100644 --- a/subsys/net/lib/lwm2m/lwm2m_obj_security.c +++ b/subsys/net/lib/lwm2m/lwm2m_obj_security.c @@ -212,6 +212,16 @@ int lwm2m_security_index_to_inst_id(int index) return inst[index].obj_inst_id; } +int lwm2m_security_short_id_to_inst(uint16_t short_id) +{ + for (int i = 0; i < MAX_INSTANCE_COUNT; i++) { + if (short_server_id[i] == short_id) { + return inst[i].obj_inst_id; + } + } + return -ENOENT; +} + int lwm2m_security_mode(struct lwm2m_ctx *ctx) { int ret; From ec962246e9eaf38746e2e895b1e7601896b67de5 Mon Sep 17 00:00:00 2001 From: Seppo Takalo Date: Fri, 24 Nov 2023 15:07:10 +0200 Subject: [PATCH 0781/3723] net: lwm2m: Allow disabling server for a period of time React to disable executable, as well as add callback that allows disabling server for a period of time. Also add API that would find a next server candidate based on the priority and server being not-disabled. Move all server related functions into its own header. Signed-off-by: Seppo Takalo --- subsys/net/lib/lwm2m/lwm2m_engine.h | 40 +--- subsys/net/lib/lwm2m/lwm2m_message_handling.c | 1 + subsys/net/lib/lwm2m/lwm2m_obj_server.c | 224 ++++++++++++------ subsys/net/lib/lwm2m/lwm2m_obj_server.h | 144 +++++++++++ subsys/net/lib/lwm2m/lwm2m_observation.c | 1 + subsys/net/lib/lwm2m/lwm2m_rd_client.c | 1 + 6 files changed, 302 insertions(+), 109 deletions(-) create mode 100644 subsys/net/lib/lwm2m/lwm2m_obj_server.h diff --git a/subsys/net/lib/lwm2m/lwm2m_engine.h b/subsys/net/lib/lwm2m/lwm2m_engine.h index 2ea3e583242..81b28395662 100644 --- a/subsys/net/lib/lwm2m/lwm2m_engine.h +++ b/subsys/net/lib/lwm2m/lwm2m_engine.h @@ -30,6 +30,7 @@ /* length of time in milliseconds to wait for buffer allocations */ #define BUF_ALLOC_TIMEOUT K_SECONDS(1) + /** * @brief Validates that writing is a legal operation on the field given by the object in * @p obj_inst and the resource id in @p msg. Returns the field to obj_field (if it exists). @@ -150,45 +151,6 @@ int lwm2m_security_short_id_to_inst(uint16_t short_id); */ int lwm2m_security_index_to_inst_id(int index); -/** - * @brief Returns the default minimum period for an observation set for the server - * with object instance id given by @p obj_inst_id. - * - * @param[in] obj_inst_id Object instance id of the server object instance - * @return int32_t pmin value - */ -int32_t lwm2m_server_get_pmin(uint16_t obj_inst_id); - -/** - * @brief Returns the default maximum period for an observation set for the server - * with object instance id given by @p obj_inst_id. - * - * @param[in] obj_inst_id Object instance id of the server object instance - * @return int32_t pmax value - */ -int32_t lwm2m_server_get_pmax(uint16_t obj_inst_id); - -/** - * @brief Returns the Short Server ID of the server object instance with - * object instance id given by @p obj_inst_id. - * - * @param[in] obj_inst_id Object instance id of the server object - * @return SSID or negative in case not found - */ -int lwm2m_server_get_ssid(uint16_t obj_inst_id); - -/** - * @brief Returns the object instance id of the server having ssid given by @p short_id. - * - * @param[in] short_id ssid of the server object - * @return Object instance id or negative in case not found - */ -int lwm2m_server_short_id_to_inst(uint16_t short_id); - -#if defined(CONFIG_LWM2M_SERVER_OBJECT_VERSION_1_1) -bool lwm2m_server_get_mute_send(uint16_t obj_inst_id); -#endif - #if defined(CONFIG_LWM2M_FIRMWARE_UPDATE_OBJ_SUPPORT) /** * @brief Sets the update state (as specified in LWM2M SPEC E.6 regarding the firmware update) diff --git a/subsys/net/lib/lwm2m/lwm2m_message_handling.c b/subsys/net/lib/lwm2m/lwm2m_message_handling.c index 6d006b4603e..02c62cee67c 100644 --- a/subsys/net/lib/lwm2m/lwm2m_message_handling.c +++ b/subsys/net/lib/lwm2m/lwm2m_message_handling.c @@ -45,6 +45,7 @@ LOG_MODULE_REGISTER(LOG_MODULE_NAME); #include "lwm2m_engine.h" #include "lwm2m_object.h" #include "lwm2m_obj_access_control.h" +#include "lwm2m_obj_server.h" #include "lwm2m_rw_link_format.h" #include "lwm2m_rw_oma_tlv.h" #include "lwm2m_rw_plain_text.h" diff --git a/subsys/net/lib/lwm2m/lwm2m_obj_server.c b/subsys/net/lib/lwm2m/lwm2m_obj_server.c index a1b2185ef1d..10c7a1a1ea0 100644 --- a/subsys/net/lib/lwm2m/lwm2m_obj_server.c +++ b/subsys/net/lib/lwm2m/lwm2m_obj_server.c @@ -15,8 +15,9 @@ LOG_MODULE_REGISTER(LOG_MODULE_NAME); #include #include "lwm2m_object.h" -#include "lwm2m_engine.h" +#include "lwm2m_obj_server.h" #include "lwm2m_rd_client.h" +#include "lwm2m_registry.h" #define SERVER_VERSION_MAJOR 1 #if defined(CONFIG_LWM2M_SERVER_OBJECT_VERSION_1_1) @@ -27,37 +28,7 @@ LOG_MODULE_REGISTER(LOG_MODULE_NAME); #define SERVER_MAX_ID 9 #endif /* defined(CONFIG_LWM2M_SERVER_OBJECT_VERSION_1_1) */ -/* Server resource IDs */ -#define SERVER_SHORT_SERVER_ID 0 -#define SERVER_LIFETIME_ID 1 -#define SERVER_DEFAULT_MIN_PERIOD_ID 2 -#define SERVER_DEFAULT_MAX_PERIOD_ID 3 -#define SERVER_DISABLE_ID 4 -#define SERVER_DISABLE_TIMEOUT_ID 5 -#define SERVER_STORE_NOTIFY_ID 6 -#define SERVER_TRANSPORT_BINDING_ID 7 -#define SERVER_REG_UPDATE_TRIGGER_ID 8 -#if defined(CONFIG_LWM2M_SERVER_OBJECT_VERSION_1_1) -#define SERVER_BOOTSTRAP_UPDATE_TRIGGER_ID 9 -#define SERVER_APN_LINK_ID 10 -#define SERVER_TLS_DTLS_ALERT_CODE_ID 11 -#define SERVER_LAST_BOOTSTRAPPED_ID 12 -#define SERVER_REGISTRATION_PRIORITY_ORDER_ID 13 -#define SERVER_INITIAL_REGISTRATION_DELAY_TIMER_ID 14 -#define SERVER_REGISTRATION_FAILURE_BLOCK_ID 15 -#define SERVER_BOOTSTRAP_ON_REGISTRATION_FAILURE_ID 16 -#define SERVER_COMMUNICATION_RETRY_COUNT_ID 17 -#define SERVER_COMMUNICATION_RETRY_TIMER_ID 18 -#define SERVER_COMMUNICATION_SEQUENCE_DELAY_TIMER_ID 19 -#define SERVER_COMMUNICATION_SEQUENCE_RETRY_TIMER_ID 20 -#define SERVER_SMS_TRIGGER_ID 21 -#define SERVER_PREFERRED_TRANSPORT_ID 22 -#define SERVER_MUTE_SEND_ID 23 -#endif /* defined(CONFIG_LWM2M_SERVER_OBJECT_VERSION_1_1) */ - - /* Server flags */ -#define SERVER_FLAG_DISABLED 1 #define SERVER_FLAG_STORE_NOTIFY 2 #define MAX_INSTANCE_COUNT CONFIG_LWM2M_SERVER_INSTANCE_COUNT @@ -76,13 +47,14 @@ static uint16_t server_id[MAX_INSTANCE_COUNT]; static uint32_t lifetime[MAX_INSTANCE_COUNT]; static uint32_t default_min_period[MAX_INSTANCE_COUNT]; static uint32_t default_max_period[MAX_INSTANCE_COUNT]; -static uint8_t server_flag_disabled[MAX_INSTANCE_COUNT]; +static k_timepoint_t disabled_until[MAX_INSTANCE_COUNT]; static uint32_t disabled_timeout[MAX_INSTANCE_COUNT]; static uint8_t server_flag_store_notify[MAX_INSTANCE_COUNT]; static char transport_binding[MAX_INSTANCE_COUNT][TRANSPORT_BINDING_LEN]; -#if defined(CONFIG_LWM2M_SERVER_OBJECT_VERSION_1_1) +/* Server object version 1.1 */ +static uint8_t priority[MAX_INSTANCE_COUNT]; static bool mute_send[MAX_INSTANCE_COUNT]; -#endif +static bool boostrap_on_fail[MAX_INSTANCE_COUNT]; static struct lwm2m_engine_obj server; static struct lwm2m_engine_obj_field fields[] = { @@ -101,10 +73,10 @@ static struct lwm2m_engine_obj_field fields[] = { OBJ_FIELD_DATA(SERVER_APN_LINK_ID, RW_OPT, OBJLNK), OBJ_FIELD_DATA(SERVER_TLS_DTLS_ALERT_CODE_ID, R_OPT, U8), OBJ_FIELD_DATA(SERVER_LAST_BOOTSTRAPPED_ID, R_OPT, TIME), - OBJ_FIELD_DATA(SERVER_REGISTRATION_PRIORITY_ORDER_ID, W_OPT, U16), + OBJ_FIELD_DATA(SERVER_REGISTRATION_PRIORITY_ORDER_ID, RW_OPT, U8), OBJ_FIELD_DATA(SERVER_INITIAL_REGISTRATION_DELAY_TIMER_ID, W_OPT, U16), OBJ_FIELD_DATA(SERVER_REGISTRATION_FAILURE_BLOCK_ID, W_OPT, BOOL), - OBJ_FIELD_DATA(SERVER_BOOTSTRAP_ON_REGISTRATION_FAILURE_ID, W_OPT, BOOL), + OBJ_FIELD_DATA(SERVER_BOOTSTRAP_ON_REGISTRATION_FAILURE_ID, RW_OPT, BOOL), OBJ_FIELD_DATA(SERVER_COMMUNICATION_RETRY_COUNT_ID, W_OPT, U16), OBJ_FIELD_DATA(SERVER_COMMUNICATION_RETRY_TIMER_ID, W_OPT, U16), OBJ_FIELD_DATA(SERVER_COMMUNICATION_SEQUENCE_DELAY_TIMER_ID, W_OPT, U16), @@ -128,7 +100,7 @@ static int disable_cb(uint16_t obj_inst_id, uint8_t *args, uint16_t args_len) LOG_DBG("DISABLE %d", obj_inst_id); for (i = 0; i < MAX_INSTANCE_COUNT; i++) { if (inst[i].obj && inst[i].obj_inst_id == obj_inst_id) { - server_flag_disabled[i] = 1U; + disabled_until[i] = sys_timepoint_calc(K_SECONDS(disabled_timeout[i])); return 0; } } @@ -143,7 +115,6 @@ static int update_trigger_cb(uint16_t obj_inst_id, return 0; } -#if defined(CONFIG_LWM2M_SERVER_OBJECT_VERSION_1_1) static int bootstrap_trigger_cb(uint16_t obj_inst_id, uint8_t *args, uint16_t args_len) { @@ -161,7 +132,6 @@ bool lwm2m_server_get_mute_send(uint16_t obj_inst_id) } return false; } -#endif /* defined(CONFIG_LWM2M_SERVER_OBJECT_VERSION_1_1) */ static int lifetime_write_cb(uint16_t obj_inst_id, uint16_t res_id, @@ -233,6 +203,116 @@ int lwm2m_server_short_id_to_inst(uint16_t short_id) return -ENOENT; } +static int lwm2m_server_inst_id_to_index(uint16_t obj_inst_id) +{ + for (int i = 0; i < ARRAY_SIZE(inst); i++) { + if (inst[i].obj && inst[i].obj_inst_id == obj_inst_id) { + return i; + } + } + return -1; +} + +bool lwm2m_server_is_enabled(uint16_t obj_inst_id) +{ + int idx = lwm2m_server_inst_id_to_index(obj_inst_id); + + if (idx < 0) { + return false; + } + return sys_timepoint_expired(disabled_until[idx]); +} + +int lwm2m_server_disable(uint16_t obj_inst_id, k_timeout_t timeout) +{ + int idx = lwm2m_server_inst_id_to_index(obj_inst_id); + + if (idx < 0) { + return -ENOENT; + } + disabled_until[idx] = sys_timepoint_calc(timeout); + return 0; +} + +k_timepoint_t lwm2m_server_get_disabled_time(uint16_t obj_inst_id) +{ + int idx = lwm2m_server_inst_id_to_index(obj_inst_id); + + if (idx < 0) { + return sys_timepoint_calc(K_FOREVER); + } + return disabled_until[idx]; +} + +void lwm2m_server_reset_timestamps(void) +{ + for (int i = 0; i < ARRAY_SIZE(inst); i++) { + disabled_until[i] = sys_timepoint_calc(K_NO_WAIT); + } +} + +bool lwm2m_server_select(uint16_t *obj_inst_id) +{ + uint8_t min = UINT8_MAX; + uint8_t max = 0; + + /* Find priority boundaries */ + if (IS_ENABLED(CONFIG_LWM2M_SERVER_OBJECT_VERSION_1_1)) { + for (int i = 0; i < ARRAY_SIZE(inst); i++) { + if (min > priority[i]) { + min = priority[i]; + } + if (max < priority[i]) { + max = priority[i]; + } + } + } else { + min = max = 0; + } + + for (uint8_t prio = min; prio <= max; prio++) { + for (int i = 0; i < ARRAY_SIZE(inst); i++) { + /* Disabled for a period */ + if (!lwm2m_server_is_enabled(inst[i].obj_inst_id)) { + continue; + } + + /* Invalid short IDs */ + if (server_id[i] == 0 || server_id[i] == UINT16_MAX) { + continue; + } + + /* Check priority */ + if (IS_ENABLED(CONFIG_LWM2M_SERVER_OBJECT_VERSION_1_1)) { + if (priority[i] > prio) { + continue; + } + } + if (obj_inst_id) { + *obj_inst_id = inst[i].obj_inst_id; + } + return true; + } + } + + LOG_ERR("No server candidate found"); + return false; +} + +uint8_t lwm2m_server_get_prio(uint16_t obj_inst_id) +{ + if (IS_ENABLED(CONFIG_LWM2M_SERVER_OBJECT_VERSION_1_1)) { + int idx = lwm2m_server_inst_id_to_index(obj_inst_id); + + if (idx < 0) { + return UINT8_MAX; + } + return priority[idx]; + } + + return (uint8_t)obj_inst_id % UINT8_MAX; +} + static struct lwm2m_engine_obj_inst *server_create(uint16_t obj_inst_id) { int index, i = 0, j = 0; @@ -259,16 +339,14 @@ static struct lwm2m_engine_obj_inst *server_create(uint16_t obj_inst_id) } /* Set default values */ - server_flag_disabled[index] = 0U; + disabled_until[i] = sys_timepoint_calc(K_NO_WAIT); server_flag_store_notify[index] = 0U; server_id[index] = index + 1; lifetime[index] = CONFIG_LWM2M_ENGINE_DEFAULT_LIFETIME; default_min_period[index] = CONFIG_LWM2M_SERVER_DEFAULT_PMIN; default_max_period[index] = CONFIG_LWM2M_SERVER_DEFAULT_PMAX; disabled_timeout[index] = 86400U; -#if defined(CONFIG_LWM2M_SERVER_OBJECT_VERSION_1_1) - mute_send[index] = false; -#endif + boostrap_on_fail[index] = true; lwm2m_engine_get_binding(transport_binding[index]); @@ -305,33 +383,39 @@ static struct lwm2m_engine_obj_inst *server_create(uint16_t obj_inst_id) transport_binding[index], TRANSPORT_BINDING_LEN, strlen(transport_binding[index]) + 1); INIT_OBJ_RES_EXECUTE(SERVER_REG_UPDATE_TRIGGER_ID, res[index], i, update_trigger_cb); -#if defined(CONFIG_LWM2M_SERVER_OBJECT_VERSION_1_1) - INIT_OBJ_RES_EXECUTE(SERVER_BOOTSTRAP_UPDATE_TRIGGER_ID, res[index], i, - bootstrap_trigger_cb); - INIT_OBJ_RES_OPTDATA(SERVER_APN_LINK_ID, res[index], i, res_inst[index], j); - INIT_OBJ_RES_OPTDATA(SERVER_TLS_DTLS_ALERT_CODE_ID, res[index], i, res_inst[index], j); - INIT_OBJ_RES_OPTDATA(SERVER_LAST_BOOTSTRAPPED_ID, res[index], i, res_inst[index], j); - INIT_OBJ_RES_OPTDATA(SERVER_REGISTRATION_PRIORITY_ORDER_ID, res[index], i, res_inst[index], - j); - INIT_OBJ_RES_OPTDATA(SERVER_INITIAL_REGISTRATION_DELAY_TIMER_ID, res[index], i, - res_inst[index], j); - INIT_OBJ_RES_OPTDATA(SERVER_REGISTRATION_FAILURE_BLOCK_ID, res[index], i, res_inst[index], - j); - INIT_OBJ_RES_OPTDATA(SERVER_BOOTSTRAP_ON_REGISTRATION_FAILURE_ID, res[index], i, - res_inst[index], j); - INIT_OBJ_RES_OPTDATA(SERVER_COMMUNICATION_RETRY_COUNT_ID, res[index], i, res_inst[index], - j); - INIT_OBJ_RES_OPTDATA(SERVER_COMMUNICATION_RETRY_TIMER_ID, res[index], i, res_inst[index], - j); - INIT_OBJ_RES_OPTDATA(SERVER_COMMUNICATION_SEQUENCE_DELAY_TIMER_ID, res[index], i, - res_inst[index], j); - INIT_OBJ_RES_OPTDATA(SERVER_COMMUNICATION_SEQUENCE_RETRY_TIMER_ID, res[index], i, - res_inst[index], j); - INIT_OBJ_RES_OPTDATA(SERVER_SMS_TRIGGER_ID, res[index], i, res_inst[index], j); - INIT_OBJ_RES_OPTDATA(SERVER_PREFERRED_TRANSPORT_ID, res[index], i, res_inst[index], j); - INIT_OBJ_RES_DATA(SERVER_MUTE_SEND_ID, res[index], i, res_inst[index], j, &mute_send[index], - sizeof(bool)); -#endif /* defined(CONFIG_LWM2M_SERVER_OBJECT_VERSION_1_1) */ + + if (IS_ENABLED(CONFIG_LWM2M_SERVER_OBJECT_VERSION_1_1)) { + mute_send[index] = false; + priority[index] = 0; + INIT_OBJ_RES_EXECUTE(SERVER_BOOTSTRAP_UPDATE_TRIGGER_ID, res[index], i, + bootstrap_trigger_cb); + INIT_OBJ_RES_OPTDATA(SERVER_APN_LINK_ID, res[index], i, res_inst[index], j); + INIT_OBJ_RES_OPTDATA(SERVER_TLS_DTLS_ALERT_CODE_ID, res[index], i, res_inst[index], + j); + INIT_OBJ_RES_OPTDATA(SERVER_LAST_BOOTSTRAPPED_ID, res[index], i, res_inst[index], + j); + INIT_OBJ_RES_DATA(SERVER_REGISTRATION_PRIORITY_ORDER_ID, res[index], i, + res_inst[index], j, &priority[index], sizeof(uint8_t)); + INIT_OBJ_RES_OPTDATA(SERVER_INITIAL_REGISTRATION_DELAY_TIMER_ID, res[index], i, + res_inst[index], j); + INIT_OBJ_RES_OPTDATA(SERVER_REGISTRATION_FAILURE_BLOCK_ID, res[index], i, + res_inst[index], j); + INIT_OBJ_RES_DATA(SERVER_BOOTSTRAP_ON_REGISTRATION_FAILURE_ID, res[index], i, + res_inst[index], j, &boostrap_on_fail[index], sizeof(bool)); + INIT_OBJ_RES_OPTDATA(SERVER_COMMUNICATION_RETRY_COUNT_ID, res[index], i, + res_inst[index], j); + INIT_OBJ_RES_OPTDATA(SERVER_COMMUNICATION_RETRY_TIMER_ID, res[index], i, + res_inst[index], j); + INIT_OBJ_RES_OPTDATA(SERVER_COMMUNICATION_SEQUENCE_DELAY_TIMER_ID, res[index], i, + res_inst[index], j); + INIT_OBJ_RES_OPTDATA(SERVER_COMMUNICATION_SEQUENCE_RETRY_TIMER_ID, res[index], i, + res_inst[index], j); + INIT_OBJ_RES_OPTDATA(SERVER_SMS_TRIGGER_ID, res[index], i, res_inst[index], j); + INIT_OBJ_RES_OPTDATA(SERVER_PREFERRED_TRANSPORT_ID, res[index], i, res_inst[index], + j); + INIT_OBJ_RES_DATA(SERVER_MUTE_SEND_ID, res[index], i, res_inst[index], j, + &mute_send[index], sizeof(bool)); + } inst[index].resources = res[index]; inst[index].resource_count = i; diff --git a/subsys/net/lib/lwm2m/lwm2m_obj_server.h b/subsys/net/lib/lwm2m/lwm2m_obj_server.h new file mode 100644 index 00000000000..56d7a674071 --- /dev/null +++ b/subsys/net/lib/lwm2m/lwm2m_obj_server.h @@ -0,0 +1,144 @@ +/* + * Copyright (c) 2023 Nordic Semiconductor ASA + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#ifndef LWM2M_OBJ_SERVER_H_ +#define LWM2M_OBJ_SERVER_H_ + +#include +#include +#include + +/* Server resource IDs */ +#define SERVER_SHORT_SERVER_ID 0 +#define SERVER_LIFETIME_ID 1 +#define SERVER_DEFAULT_MIN_PERIOD_ID 2 +#define SERVER_DEFAULT_MAX_PERIOD_ID 3 +#define SERVER_DISABLE_ID 4 +#define SERVER_DISABLE_TIMEOUT_ID 5 +#define SERVER_STORE_NOTIFY_ID 6 +#define SERVER_TRANSPORT_BINDING_ID 7 +#define SERVER_REG_UPDATE_TRIGGER_ID 8 +/* Server object version 1.1 resource IDs */ +#define SERVER_BOOTSTRAP_UPDATE_TRIGGER_ID 9 +#define SERVER_APN_LINK_ID 10 +#define SERVER_TLS_DTLS_ALERT_CODE_ID 11 +#define SERVER_LAST_BOOTSTRAPPED_ID 12 +#define SERVER_REGISTRATION_PRIORITY_ORDER_ID 13 +#define SERVER_INITIAL_REGISTRATION_DELAY_TIMER_ID 14 +#define SERVER_REGISTRATION_FAILURE_BLOCK_ID 15 +#define SERVER_BOOTSTRAP_ON_REGISTRATION_FAILURE_ID 16 +#define SERVER_COMMUNICATION_RETRY_COUNT_ID 17 +#define SERVER_COMMUNICATION_RETRY_TIMER_ID 18 +#define SERVER_COMMUNICATION_SEQUENCE_DELAY_TIMER_ID 19 +#define SERVER_COMMUNICATION_SEQUENCE_RETRY_TIMER_ID 20 +#define SERVER_SMS_TRIGGER_ID 21 +#define SERVER_PREFERRED_TRANSPORT_ID 22 +#define SERVER_MUTE_SEND_ID 23 + +/** + * @brief Returns the default minimum period for an observation set for the server + * with object instance id given by @p obj_inst_id. + * + * @param[in] obj_inst_id Object instance id of the server object instance + * @return int32_t pmin value + */ +int32_t lwm2m_server_get_pmin(uint16_t obj_inst_id); + +/** + * @brief Returns the default maximum period for an observation set for the server + * with object instance id given by @p obj_inst_id. + * + * @param[in] obj_inst_id Object instance id of the server object instance + * @return int32_t pmax value + */ +int32_t lwm2m_server_get_pmax(uint16_t obj_inst_id); + +/** + * @brief Returns the Short Server ID of the server object instance with + * object instance id given by @p obj_inst_id. + * + * @param[in] obj_inst_id Object instance id of the server object + * @return SSID or negative in case not found + */ +int lwm2m_server_get_ssid(uint16_t obj_inst_id); + +/** + * @brief Returns the object instance id of the server having ssid given by @p short_id. + * + * @param[in] short_id ssid of the server object + * @return Object instance id or negative in case not found + */ +int lwm2m_server_short_id_to_inst(uint16_t short_id); + +/** + * @brief Check if given server instance is not disabled + * + * @param[in] obj_inst_id server instance + * @return true if not disabled, false otherwise. + */ +bool lwm2m_server_is_enabled(uint16_t obj_inst_id); + +/** + * @brief Select server instance. + * + * Find possible server instance considering values on server data. + * Server candidates cannot be in disabled state and if priority values are set, + * those are compared and lowest values are considered first. + * + * If @ref obj_inst_id is NULL, this can be used to check if there are any server available. + * + * @param[out] obj_inst_id where selected server instance ID is written. Can be NULL. + * @return true if server instance was found, false otherwise. + */ +bool lwm2m_server_select(uint16_t *obj_inst_id); + +/** + * @brief Disable server instance for a period of time. + * + * Timeout values can be calculated using kernel macros like K_SECONDS(). + * Values like K_FOREVER or K_NO_WAIT are also accepted. + * + * @param timeout Timeout value. + * @return zero on success, negative error code otherwise. + */ +int lwm2m_server_disable(uint16_t obj_inst_id, k_timeout_t timeout); + +/** + * @brief Get timepoint how long server instance is disabled. + * + * If server instance is not disabled, this still returns a valid timepoint + * that have already expired. + * If the instance id is not valid, the timepoint is set to K_FOREVER. + * + * @param obj_inst_id Server instance ID. + * @return timepoint + */ +k_timepoint_t lwm2m_server_get_disabled_time(uint16_t obj_inst_id); + +/** + * @brief Get priority of given server instance. + * + * Lower values mean higher priority. + * If LwM2M server object version 1.1 is not enabled, + * this returns obj_inst_id as priority. + * + * @param obj_inst_id instance ID + * @return priority or UINT8_MAX if instance not found + */ +uint8_t lwm2m_server_get_prio(uint16_t obj_inst_id); + +/** + * @brief Reset all disable-timers for all server instances. + * + */ +void lwm2m_server_reset_timestamps(void); + +#if defined(CONFIG_LWM2M_SERVER_OBJECT_VERSION_1_1) +bool lwm2m_server_get_mute_send(uint16_t obj_inst_id); +#endif + + +#endif /* LWM2M_OBJ_SERVER_H_ */ diff --git a/subsys/net/lib/lwm2m/lwm2m_observation.c b/subsys/net/lib/lwm2m/lwm2m_observation.c index 9ee1fa6eda1..1c8034e6535 100644 --- a/subsys/net/lib/lwm2m/lwm2m_observation.c +++ b/subsys/net/lib/lwm2m/lwm2m_observation.c @@ -37,6 +37,7 @@ LOG_MODULE_REGISTER(LOG_MODULE_NAME); #include #include #include +#include "lwm2m_obj_server.h" #if defined(CONFIG_LWM2M_RW_SENML_JSON_SUPPORT) #include "lwm2m_rw_senml_json.h" diff --git a/subsys/net/lib/lwm2m/lwm2m_rd_client.c b/subsys/net/lib/lwm2m/lwm2m_rd_client.c index d9f2e229edd..6eacba0ee0d 100644 --- a/subsys/net/lib/lwm2m/lwm2m_rd_client.c +++ b/subsys/net/lib/lwm2m/lwm2m_rd_client.c @@ -62,6 +62,7 @@ LOG_MODULE_REGISTER(LOG_MODULE_NAME); #include "lwm2m_rd_client.h" #include "lwm2m_rw_link_format.h" #include "lwm2m_util.h" +#include "lwm2m_obj_server.h" #define LWM2M_RD_CLIENT_URI "rd" #define CLIENT_EP_LEN CONFIG_LWM2M_RD_CLIENT_ENDPOINT_NAME_MAX_LENGTH From dc8f6da53c856c56f9d31fec58b9bea208609c95 Mon Sep 17 00:00:00 2001 From: Seppo Takalo Date: Thu, 30 Nov 2023 17:38:14 +0200 Subject: [PATCH 0782/3723] net: lwm2m: Implement fallback mechanism and support for diable If server registration fails, allow fallback to secondary server, or fallback to bootstrap. Also allow fallback to different bootstrap server. Add API to tell RD client when server have been disabled by executable command. Changes to RD state machine: * All retry logic should be handled in NETWORK_ERROR state. * New state SERVER_DISABLED. * Internally disable servers that reject registration * Temporary disable server on network error. * Clean up all "disable timers" on start. * Select server first, then find security object for it. * State functions return void, error handling is done using states. * DISCONNECT event will only come when client is requested to stop. * NETWORK_ERROR will stop engine. This is generic error for all kinds of registration or network failures. * BOOTSTRAP_REG_FAILURE also stops engine. This is fatal, and we cannot recover. Refactoring: * Server selection logic is inside server object. * sm_handle_timeout_state() does not require msg parameter. Unused. * When bootstrap fail, we should NOT back off to registration. This is a fatal error, and it stops the engine and informs application. Signed-off-by: Seppo Takalo --- include/zephyr/net/lwm2m.h | 1 + samples/net/lwm2m_client/src/lwm2m-client.c | 4 + subsys/net/lib/lwm2m/lwm2m_obj_server.c | 18 +- subsys/net/lib/lwm2m/lwm2m_rd_client.c | 421 +++++++++++------- subsys/net/lib/lwm2m/lwm2m_rd_client.h | 10 + .../net/lib/lwm2m/interop/src/lwm2m-client.c | 4 + .../net/lib/lwm2m/lwm2m_rd_client/src/main.c | 201 +++++++-- .../net/lib/lwm2m/lwm2m_rd_client/src/stubs.c | 22 + .../net/lib/lwm2m/lwm2m_rd_client/src/stubs.h | 9 +- 9 files changed, 495 insertions(+), 195 deletions(-) diff --git a/include/zephyr/net/lwm2m.h b/include/zephyr/net/lwm2m.h index a57b5542f88..6ac0458af87 100644 --- a/include/zephyr/net/lwm2m.h +++ b/include/zephyr/net/lwm2m.h @@ -2075,6 +2075,7 @@ enum lwm2m_rd_client_event { LWM2M_RD_CLIENT_EVENT_NETWORK_ERROR, LWM2M_RD_CLIENT_EVENT_REG_UPDATE, LWM2M_RD_CLIENT_EVENT_DEREGISTER, + LWM2M_RD_CLIENT_EVENT_SERVER_DISABLED, }; /** diff --git a/samples/net/lwm2m_client/src/lwm2m-client.c b/samples/net/lwm2m_client/src/lwm2m-client.c index a120506639d..c610f1ad8dd 100644 --- a/samples/net/lwm2m_client/src/lwm2m-client.c +++ b/samples/net/lwm2m_client/src/lwm2m-client.c @@ -191,6 +191,10 @@ static void rd_client_event(struct lwm2m_ctx *client, /* do nothing */ break; + case LWM2M_RD_CLIENT_EVENT_SERVER_DISABLED: + LOG_DBG("LwM2M server disabled"); + break; + case LWM2M_RD_CLIENT_EVENT_BOOTSTRAP_REG_FAILURE: LOG_DBG("Bootstrap registration failure!"); break; diff --git a/subsys/net/lib/lwm2m/lwm2m_obj_server.c b/subsys/net/lib/lwm2m/lwm2m_obj_server.c index 10c7a1a1ea0..a9432340038 100644 --- a/subsys/net/lib/lwm2m/lwm2m_obj_server.c +++ b/subsys/net/lib/lwm2m/lwm2m_obj_server.c @@ -95,13 +95,21 @@ static struct lwm2m_engine_res_inst static int disable_cb(uint16_t obj_inst_id, uint8_t *args, uint16_t args_len) { - int i; + ARG_UNUSED(args); + ARG_UNUSED(args_len); + + int ret; - LOG_DBG("DISABLE %d", obj_inst_id); - for (i = 0; i < MAX_INSTANCE_COUNT; i++) { + for (int i = 0; i < MAX_INSTANCE_COUNT; i++) { if (inst[i].obj && inst[i].obj_inst_id == obj_inst_id) { - disabled_until[i] = sys_timepoint_calc(K_SECONDS(disabled_timeout[i])); - return 0; + LOG_DBG("DISABLE %d", obj_inst_id); + ret = lwm2m_rd_client_server_disabled(obj_inst_id); + if (ret == 0) { + disabled_until[i] = + sys_timepoint_calc(K_SECONDS(disabled_timeout[i])); + return 0; + } + return ret; } } diff --git a/subsys/net/lib/lwm2m/lwm2m_rd_client.c b/subsys/net/lib/lwm2m/lwm2m_rd_client.c index 6eacba0ee0d..6b3fbcccc68 100644 --- a/subsys/net/lib/lwm2m/lwm2m_rd_client.c +++ b/subsys/net/lib/lwm2m/lwm2m_rd_client.c @@ -72,6 +72,7 @@ LOG_MODULE_REGISTER(LOG_MODULE_NAME); #define DELAY_FOR_ACK 100U #define EXCHANGE_LIFETIME 247U #define MINIMUM_PERIOD 15 +#define DISABLE_TIMEOUT (K_SECONDS(CONFIG_LWM2M_RD_CLIENT_MAX_RETRIES * EXCHANGE_LIFETIME)) static void sm_handle_registration_update_failure(void); static int sm_send_registration_msg(void); @@ -80,6 +81,8 @@ static void lwm2m_rd_client_service(struct k_work *work); static int64_t calc_next_event(void); static void set_sm_state_delayed(uint8_t sm_state, int64_t delay_ms); static void set_sm_state(uint8_t sm_state); +/** Try to fallback to bootstrap. Return true if we did. */ +static bool fallback_to_bootstrap(void); /* The states for the RD client state machine */ /* @@ -101,6 +104,7 @@ enum sm_engine_state { ENGINE_REGISTRATION_DONE_RX_OFF, ENGINE_UPDATE_REGISTRATION, ENGINE_UPDATE_SENT, + ENGINE_SERVER_DISABLED, ENGINE_SUSPENDED, ENGINE_DEREGISTER, ENGINE_DEREGISTER_SENT, @@ -125,11 +129,11 @@ struct lwm2m_rd_client_info { char ep_name[CLIENT_EP_LEN]; char server_ep[CLIENT_EP_LEN]; - bool use_bootstrap : 1; - + bool use_bootstrap : 1; bool trigger_update : 1; bool update_objects : 1; - bool close_socket : 1; + bool close_socket : 1; + bool server_disabled: 1; } client; /* Allocate some data for queries and updates. Make sure it's large enough to @@ -201,23 +205,18 @@ static void set_sm_state_delayed(uint8_t sm_state, int64_t delay_ms) event = LWM2M_RD_CLIENT_EVENT_REGISTRATION_COMPLETE; } else if (sm_state == ENGINE_REGISTRATION_DONE_RX_OFF) { event = LWM2M_RD_CLIENT_EVENT_QUEUE_MODE_RX_OFF; - } else if ((sm_state == ENGINE_INIT || - sm_state == ENGINE_DEREGISTERED) && + } else if (sm_state == ENGINE_DEREGISTERED && (client.engine_state >= ENGINE_DO_REGISTRATION && - client.engine_state <= ENGINE_DEREGISTER_SENT)) { + client.engine_state <= ENGINE_DEREGISTER_SENT) && !client.server_disabled) { event = LWM2M_RD_CLIENT_EVENT_DISCONNECT; - } else if (sm_state == ENGINE_NETWORK_ERROR) { - lwm2m_socket_close(client.ctx); - client.retry_delay = 1 << client.retries; - client.retries++; - if (client.retries > CONFIG_LWM2M_RD_CLIENT_MAX_RETRIES) { - client.retries = 0; - event = LWM2M_RD_CLIENT_EVENT_NETWORK_ERROR; - } } else if (sm_state == ENGINE_UPDATE_REGISTRATION) { event = LWM2M_RD_CLIENT_EVENT_REG_UPDATE; } else if (sm_state == ENGINE_DEREGISTER) { - event = LWM2M_RD_CLIENT_EVENT_DEREGISTER; + if (client.server_disabled) { + event = LWM2M_RD_CLIENT_EVENT_SERVER_DISABLED; + } else { + event = LWM2M_RD_CLIENT_EVENT_DEREGISTER; + } } if (sm_is_suspended()) { @@ -292,27 +291,22 @@ static uint8_t get_sm_state(void) return state; } -static void sm_handle_timeout_state(struct lwm2m_message *msg, - enum sm_engine_state sm_state) +static void sm_handle_timeout_state(enum sm_engine_state sm_state) { k_mutex_lock(&client.mutex, K_FOREVER); enum lwm2m_rd_client_event event = LWM2M_RD_CLIENT_EVENT_NONE; -#if defined(CONFIG_LWM2M_RD_CLIENT_SUPPORT_BOOTSTRAP) - if (client.engine_state == ENGINE_BOOTSTRAP_REG_SENT) { - event = LWM2M_RD_CLIENT_EVENT_BOOTSTRAP_REG_FAILURE; - } else -#endif - { - if (client.engine_state == ENGINE_REGISTRATION_SENT) { - event = LWM2M_RD_CLIENT_EVENT_REG_TIMEOUT; - } else if (client.engine_state == ENGINE_UPDATE_SENT) { - event = LWM2M_RD_CLIENT_EVENT_REG_TIMEOUT; - } else if (client.engine_state == ENGINE_DEREGISTER_SENT) { - event = LWM2M_RD_CLIENT_EVENT_DEREGISTER_FAILURE; - } else { - /* TODO: unknown timeout state */ - } + /* Don't send BOOTSTRAP_REG_FAILURE event, that is only emitted from + * do_network_error() once we are out of retries. + */ + if (client.engine_state == ENGINE_REGISTRATION_SENT) { + event = LWM2M_RD_CLIENT_EVENT_REG_TIMEOUT; + } else if (client.engine_state == ENGINE_UPDATE_SENT) { + event = LWM2M_RD_CLIENT_EVENT_REG_TIMEOUT; + } else if (client.engine_state == ENGINE_DEREGISTER_SENT) { + event = LWM2M_RD_CLIENT_EVENT_DEREGISTER_FAILURE; + } else { + /* TODO: unknown timeout state */ } set_sm_state(sm_state); @@ -374,11 +368,14 @@ static void socket_fault_cb(int error) /* Network error state causes engine to re-register, * so only trigger that state if we are not stopping the * engine. + * Also when engine is going to be disabled, for a while, we might get spurious + * socket errors when closing, so ignore them. */ if (client.engine_state > ENGINE_IDLE && - client.engine_state < ENGINE_SUSPENDED) { - set_sm_state(ENGINE_NETWORK_ERROR); - } else if (client.engine_state != ENGINE_SUSPENDED) { + client.engine_state < ENGINE_SERVER_DISABLED) { + sm_handle_timeout_state(ENGINE_NETWORK_ERROR); + } else if (client.engine_state != ENGINE_SUSPENDED && + !client.server_disabled) { sm_handle_failure_state(ENGINE_IDLE); } } @@ -453,13 +450,7 @@ static int do_bootstrap_reply_cb(const struct coap_packet *response, static void do_bootstrap_reg_timeout_cb(struct lwm2m_message *msg) { LOG_WRN("Bootstrap Timeout"); - - /* TODO: - * Look for the "next" BOOTSTRAP server entry in our security info - */ - - /* Restart from scratch */ - sm_handle_timeout_state(msg, ENGINE_INIT); + sm_handle_timeout_state(ENGINE_NETWORK_ERROR); } #endif @@ -522,6 +513,8 @@ static int do_registration_reply_cb(const struct coap_packet *response, /* remember the last reg time */ client.last_update = k_uptime_get(); + client.server_disabled = false; + client.retries = 0; memcpy(client.server_ep, options[1].value, options[1].len); @@ -533,11 +526,12 @@ static int do_registration_reply_cb(const struct coap_packet *response, return 0; } - LOG_ERR("Failed with code %u.%u (%s). Not Retrying.", + LOG_ERR("Failed with code %u.%u (%s).", COAP_RESPONSE_CODE_CLASS(code), COAP_RESPONSE_CODE_DETAIL(code), code2str(code)); fail: - sm_handle_failure_state(ENGINE_IDLE); + lwm2m_server_disable(client.ctx->srv_obj_inst, DISABLE_TIMEOUT); + sm_handle_failure_state(ENGINE_NETWORK_ERROR); return ret; } @@ -546,8 +540,7 @@ static void do_registration_timeout_cb(struct lwm2m_message *msg) { LOG_WRN("Registration Timeout"); - /* Restart from scratch */ - sm_handle_timeout_state(msg, ENGINE_INIT); + sm_handle_timeout_state(ENGINE_NETWORK_ERROR); } static int do_update_reply_cb(const struct coap_packet *response, @@ -588,7 +581,7 @@ static void do_update_timeout_cb(struct lwm2m_message *msg) client.close_socket = true; } /* Re-do registration */ - sm_handle_timeout_state(msg, ENGINE_DO_REGISTRATION); + sm_handle_timeout_state(ENGINE_DO_REGISTRATION); } static int do_deregister_reply_cb(const struct coap_packet *response, @@ -612,7 +605,7 @@ static int do_deregister_reply_cb(const struct coap_packet *response, COAP_RESPONSE_CODE_CLASS(code), COAP_RESPONSE_CODE_DETAIL(code), code2str(code)); - sm_handle_failure_state(ENGINE_IDLE); + sm_handle_failure_state(ENGINE_DEREGISTERED); return 0; } @@ -621,10 +614,10 @@ static void do_deregister_timeout_cb(struct lwm2m_message *msg) { LOG_WRN("De-Registration Timeout"); - sm_handle_timeout_state(msg, ENGINE_IDLE); + sm_handle_timeout_state(ENGINE_DEREGISTERED); } -static bool sm_bootstrap_verify(bool bootstrap_server, int sec_obj_inst) +static bool is_bootsrap_server(int sec_obj_inst) { bool bootstrap; int ret; @@ -634,12 +627,7 @@ static bool sm_bootstrap_verify(bool bootstrap_server, int sec_obj_inst) LOG_WRN("Failed to check bootstrap, err %d", ret); return false; } - - if (bootstrap == bootstrap_server) { - return true; - } else { - return false; - } + return bootstrap; } static bool sm_update_lifetime(int srv_obj_inst, uint32_t *lifetime) @@ -665,58 +653,40 @@ static bool sm_update_lifetime(int srv_obj_inst, uint32_t *lifetime) return false; } -static int sm_select_server_inst(int sec_obj_inst, int *srv_obj_inst, - uint32_t *lifetime) -{ - uint16_t server_id; - int ret, obj_inst_id; - - ret = lwm2m_get_u16(&LWM2M_OBJ(0, sec_obj_inst, 10), &server_id); - if (ret < 0) { - LOG_WRN("Failed to obtain Short Server ID, err %d", ret); - return -EINVAL; - } - - obj_inst_id = lwm2m_server_short_id_to_inst(server_id); - if (obj_inst_id < 0) { - LOG_WRN("Failed to obtain Server Object instance, err %d", - obj_inst_id); - return -EINVAL; - } - - sm_update_lifetime(obj_inst_id, lifetime); - *srv_obj_inst = obj_inst_id; - - return 0; -} - -static int sm_select_security_inst(bool bootstrap_server, int *sec_obj_inst) +/** + * @brief Find the next security instance for bootstrapping. + * + * Search for the next security instance that has the bootstrap flag set and + * is not the same as current security instance. + * + * @param sec_obj_inst current security instance or -1. + * @return zero on success, negative on error. + */ +static int sm_next_bootstrap_inst(int *sec_obj_inst) { int i, obj_inst_id = -1; - /* lookup existing index */ - i = lwm2m_security_inst_id_to_index(*sec_obj_inst); - if (i >= 0 && sm_bootstrap_verify(bootstrap_server, *sec_obj_inst)) { - return 0; + if (*sec_obj_inst >= 0 && !is_bootsrap_server(*sec_obj_inst)) { + *sec_obj_inst = -1; } - *sec_obj_inst = -1; - /* Iterate over all instances to find the correct one. */ for (i = 0; i < CONFIG_LWM2M_SECURITY_INSTANCE_COUNT; i++) { obj_inst_id = lwm2m_security_index_to_inst_id(i); if (obj_inst_id < 0) { - LOG_WRN("Failed to get inst id for %d", i); + continue; + } + if (obj_inst_id == *sec_obj_inst) { continue; } - if (sm_bootstrap_verify(bootstrap_server, obj_inst_id)) { + if (is_bootsrap_server(obj_inst_id)) { *sec_obj_inst = obj_inst_id; return 0; } } - LOG_WRN("sec_obj_inst: No matching servers found."); + LOG_WRN("No Bootstrap servers found."); return -ENOENT; } @@ -726,24 +696,17 @@ static int sm_select_security_inst(bool bootstrap_server, int *sec_obj_inst) static int sm_do_init(void) { lwm2m_engine_stop(client.ctx); - client.ctx->sec_obj_inst = -1; - client.ctx->srv_obj_inst = -1; client.trigger_update = false; client.lifetime = 0U; - client.retries = 0U; client.last_update = 0U; client.close_socket = false; /* Do bootstrap or registration */ -#if defined(CONFIG_LWM2M_RD_CLIENT_SUPPORT_BOOTSTRAP) - if (client.use_bootstrap) { + if (client.use_bootstrap && IS_ENABLED(CONFIG_LWM2M_RD_CLIENT_SUPPORT_BOOTSTRAP)) { set_sm_state(ENGINE_DO_BOOTSTRAP_REG); } else { set_sm_state(ENGINE_DO_REGISTRATION); } -#else - set_sm_state(ENGINE_DO_REGISTRATION); -#endif return 0; } @@ -814,7 +777,7 @@ static int sm_send_bootstrap_registration(void) return ret; } -static int sm_do_bootstrap_reg(void) +static void sm_do_bootstrap_reg(void) { int ret; @@ -824,23 +787,20 @@ static int sm_do_bootstrap_reg(void) } client.ctx->bootstrap_mode = true; - ret = sm_select_security_inst(client.ctx->bootstrap_mode, - &client.ctx->sec_obj_inst); + ret = sm_next_bootstrap_inst(&client.ctx->sec_obj_inst); if (ret < 0) { - /* no bootstrap server found, let's move to registration */ - LOG_WRN("Bootstrap server not found! Try normal registration."); - set_sm_state(ENGINE_DO_REGISTRATION); - return ret; + set_sm_state(ENGINE_NETWORK_ERROR); + return; } - LOG_INF("Bootstrap started with endpoint '%s' with client lifetime %d", - client.ep_name, client.lifetime); + LOG_INF("Bootstrap started with endpoint '%s' using security object %d", + client.ep_name, client.ctx->sec_obj_inst); ret = lwm2m_engine_start(client.ctx); if (ret < 0) { LOG_ERR("Cannot init LWM2M engine (%d)", ret); set_sm_state(ENGINE_NETWORK_ERROR); - return ret; + return; } ret = sm_send_bootstrap_registration(); @@ -851,7 +811,7 @@ static int sm_do_bootstrap_reg(void) set_sm_state(ENGINE_NETWORK_ERROR); } - return ret; + return; } void engine_bootstrap_finish(void) @@ -1047,8 +1007,9 @@ static int sm_send_registration_msg(void) return ret; } -static int sm_do_registration(void) +static void sm_do_registration(void) { + uint16_t ssid; int ret = 0; if (client.ctx->connection_suspended) { @@ -1056,10 +1017,16 @@ static int sm_do_registration(void) lwm2m_engine_context_close(client.ctx); /* perform full registration */ set_sm_state(ENGINE_DO_REGISTRATION); - return 0; + return; } } else { + bool select_srv = true; + uint16_t srv = (uint16_t) client.ctx->srv_obj_inst; + + client.last_update = 0; + client.ctx->bootstrap_mode = false; + /* clear out existing connection data */ if (client.ctx->sock_fd > -1) { if (client.close_socket) { @@ -1068,43 +1035,58 @@ static int sm_do_registration(void) lwm2m_engine_stop(client.ctx); } else { lwm2m_engine_context_close(client.ctx); + /* Keep current connection, retry registration with same server */ + select_srv = false; } } - client.last_update = 0; + if (select_srv) { + /* Select next one from the list, or fail */ + if (!lwm2m_server_select(&srv)) { + LOG_ERR("Unable to find a valid server instance."); + goto bootstrap_or_retry; + } - client.ctx->bootstrap_mode = false; - ret = sm_select_security_inst(client.ctx->bootstrap_mode, - &client.ctx->sec_obj_inst); - if (ret < 0) { - LOG_ERR("Unable to find a valid security instance."); - set_sm_state(ENGINE_INIT); - return -EINVAL; - } + client.ctx->srv_obj_inst = srv; + sm_update_lifetime(srv, &client.lifetime); - ret = sm_select_server_inst(client.ctx->sec_obj_inst, - &client.ctx->srv_obj_inst, - &client.lifetime); - if (ret < 0) { - LOG_ERR("Unable to find a valid server instance."); - set_sm_state(ENGINE_INIT); - return -EINVAL; + ret = lwm2m_get_u16(&LWM2M_OBJ(1, client.ctx->srv_obj_inst, 0), &ssid); + if (ret < 0) { + LOG_ERR("Failed to read SSID"); + lwm2m_server_disable(srv, K_FOREVER); + goto bootstrap_or_retry; + } + + ret = lwm2m_security_short_id_to_inst(ssid); + if (ret < 0) { + LOG_ERR("Unable to find a valid security instance."); + lwm2m_server_disable(srv, K_FOREVER); + goto bootstrap_or_retry; + } + client.ctx->sec_obj_inst = (uint16_t) ret; } - LOG_INF("RD Client started with endpoint '%s' with client lifetime %d", - client.ep_name, client.lifetime); + LOG_INF("RD Client started with endpoint '%s' with client lifetime %d using server " + "object %d", + client.ep_name, client.lifetime, client.ctx->srv_obj_inst); ret = lwm2m_engine_start(client.ctx); if (ret < 0) { LOG_ERR("Cannot init LWM2M engine (%d)", ret); - set_sm_state(ENGINE_NETWORK_ERROR); - return ret; + goto bootstrap_or_retry; } } - ret = sm_send_registration_msg(); + sm_send_registration_msg(); + return; - return ret; +bootstrap_or_retry: + lwm2m_engine_stop(client.ctx); + if (!client.server_disabled && fallback_to_bootstrap()) { + return; + } + + set_sm_state(ENGINE_NETWORK_ERROR); } static int64_t next_update(void) @@ -1269,32 +1251,116 @@ static int sm_do_deregister(void) return ret; } +static bool fallback_to_bootstrap(void) +{ + if (IS_ENABLED(CONFIG_LWM2M_RD_CLIENT_SUPPORT_BOOTSTRAP)) { + bool fallback = true; + + (void)lwm2m_get_bool(&LWM2M_OBJ(LWM2M_OBJECT_SERVER_ID, client.ctx->srv_obj_inst, + SERVER_BOOTSTRAP_ON_REGISTRATION_FAILURE_ID), + &fallback); + if (fallback) { + client.use_bootstrap = true; + set_sm_state(ENGINE_INIT); + return true; + } + } + return false; +} + static void sm_do_network_error(void) { int err; + LOG_ERR("sm_do_network_error, retries %d", client.retries); + + lwm2m_socket_close(client.ctx); + if (client.retry_delay) { - client.retry_delay = 0; next_event_at(k_uptime_get() + client.retry_delay * MSEC_PER_SEC); + client.retry_delay = 0; return; } + client.retry_delay = 1 << client.retries; + client.retries++; -#if defined(CONFIG_LWM2M_RD_CLIENT_SUPPORT_BOOTSTRAP) - if (client.ctx->bootstrap_mode) { - lwm2m_engine_context_close(client.ctx); - set_sm_state(ENGINE_DO_BOOTSTRAP_REG); - return; + /* Stop retrying and try fallback */ + if (client.retries > CONFIG_LWM2M_RD_CLIENT_MAX_RETRIES) { + LOG_ERR("Network error, max retries reached (%d)", client.retries); + + /* Disable current server for a period so lwm2m_server_select() does not pick it */ + if (client.ctx->srv_obj_inst > -1) { + lwm2m_server_disable(client.ctx->srv_obj_inst, DISABLE_TIMEOUT); + } + + /* Are we in bootstrap? Try if we can fallback to some other BS server */ + if (client.ctx->bootstrap_mode && + IS_ENABLED(CONFIG_LWM2M_RD_CLIENT_SUPPORT_BOOTSTRAP)) { + LOG_DBG("In bootstrap, try fallback srv"); + /* Do we have any other bootstrap server to back off to? */ + if (sm_next_bootstrap_inst(&client.ctx->sec_obj_inst) < 0) { + /* No, we are out of options, stop engine */ + goto stop_engine; + } + set_sm_state(ENGINE_INIT); + return; + } + + /* Try if there are other server to fall back to, + * Only allow fallback to higher priority server (lower value, or lower id) + * if we have successfully registered before. + * This should block us from looping the same list again. + * Instead we should fallback to bootstrap. + */ + uint16_t srv; + + if (lwm2m_server_select(&srv)) { + uint8_t p1, p2; + + p1 = lwm2m_server_get_prio(client.ctx->srv_obj_inst); + p2 = lwm2m_server_get_prio(srv); + if (p1 < p2 || client.last_update != 0) { + set_sm_state(ENGINE_INIT); + return; + } + } + + /* If we have been disabled by some server, don't fall back to bootstrap */ + if (client.server_disabled) { + set_sm_state(ENGINE_SERVER_DISABLED); + return; + } + + if (fallback_to_bootstrap()) { + return; + } + goto stop_engine; + } + + /* Retry bootstrap */ + if (IS_ENABLED(CONFIG_LWM2M_RD_CLIENT_SUPPORT_BOOTSTRAP)) { + if (client.ctx->bootstrap_mode) { + lwm2m_engine_context_close(client.ctx); + /* If we don't have fallback BS server, retry with current one */ + if (sm_next_bootstrap_inst(&client.ctx->sec_obj_inst) < 0) { + client.ctx->sec_obj_inst = -1; + } + set_sm_state(ENGINE_DO_BOOTSTRAP_REG); + return; + } } -#endif if (!client.last_update || (k_uptime_get() - client.last_update) / MSEC_PER_SEC > client.lifetime) { /* do full registration as there is no active registration or lifetime exceeded */ - lwm2m_engine_context_close(client.ctx); + /* Keep the same server until out of retry */ set_sm_state(ENGINE_DO_REGISTRATION); return; } + /* Try if we can recover the DTLS session and try Update. + * This might fallback into full registration on sm_handle_registration_update_failure(). + */ err = lwm2m_socket_start(client.ctx); if (err) { LOG_ERR("Failed to start socket %d", err); @@ -1305,8 +1371,21 @@ static void sm_do_network_error(void) set_sm_state(ENGINE_NETWORK_ERROR); return; } - set_sm_state(ENGINE_UPDATE_REGISTRATION); + return; + +stop_engine: + + /* We are out of options, stop engine */ + if (client.ctx->event_cb) { + if (client.ctx->bootstrap_mode) { + client.ctx->event_cb(client.ctx, + LWM2M_RD_CLIENT_EVENT_BOOTSTRAP_REG_FAILURE); + } else { + client.ctx->event_cb(client.ctx, LWM2M_RD_CLIENT_EVENT_NETWORK_ERROR); + } + } + set_sm_state(ENGINE_IDLE); } static void lwm2m_rd_client_service(struct k_work *work) @@ -1380,6 +1459,19 @@ static void lwm2m_rd_client_service(struct k_work *work) timeout = EXCHANGE_LIFETIME; break; + case ENGINE_SERVER_DISABLED: + if (lwm2m_server_select(NULL)) { + set_sm_state(ENGINE_INIT); + } else { + /* wait for server to be enabled. */ + /* + * TODO: Once engine is converted to use timepoint_t + * this should calculate the next event from the previous server. + */ + next_event_at(k_uptime_get() + SEC_PER_MIN * MSEC_PER_SEC); + } + break; + case ENGINE_DEREGISTER: sm_do_deregister(); break; @@ -1391,7 +1483,11 @@ static void lwm2m_rd_client_service(struct k_work *work) case ENGINE_DEREGISTERED: lwm2m_engine_stop(client.ctx); - set_sm_state(ENGINE_IDLE); + if (client.server_disabled) { + set_sm_state(ENGINE_SERVER_DISABLED); + } else { + set_sm_state(ENGINE_IDLE); + } break; case ENGINE_NETWORK_ERROR: @@ -1408,7 +1504,7 @@ static void lwm2m_rd_client_service(struct k_work *work) if (end < k_uptime_get()) { LOG_DBG("State machine have timed out"); - sm_handle_timeout_state(NULL, ENGINE_INIT); + sm_handle_timeout_state(ENGINE_INIT); } else if (client.next_event > end) { next_event_at(end); } @@ -1442,6 +1538,7 @@ int lwm2m_rd_client_start(struct lwm2m_ctx *client_ctx, const char *ep_name, } /* Init Context */ + lwm2m_server_reset_timestamps(); lwm2m_engine_context_init(client_ctx); client.ctx = client_ctx; @@ -1450,13 +1547,15 @@ int lwm2m_rd_client_start(struct lwm2m_ctx *client_ctx, const char *ep_name, client.ctx->observe_cb = observe_cb; client.ctx->event_cb = event_cb; client.use_bootstrap = flags & LWM2M_RD_CLIENT_FLAG_BOOTSTRAP; + client.ctx->srv_obj_inst = -1; + client.ctx->sec_obj_inst = -1; + client.retries = 0; - set_sm_state(ENGINE_INIT); strncpy(client.ep_name, ep_name, CLIENT_EP_LEN - 1); client.ep_name[CLIENT_EP_LEN - 1] = '\0'; LOG_INF("Start LWM2M Client: %s", client.ep_name); - next_event_at(0); + set_sm_state(ENGINE_INIT); k_mutex_unlock(&client.mutex); @@ -1477,9 +1576,10 @@ int lwm2m_rd_client_stop(struct lwm2m_ctx *client_ctx, client.ctx->event_cb = event_cb; rd_client_message_free(); - if (sm_is_registered() && deregister) { + if (sm_is_registered() && deregister && !client.server_disabled) { set_sm_state(ENGINE_DEREGISTER); } else { + client.server_disabled = false; set_sm_state(ENGINE_DEREGISTERED); } @@ -1557,7 +1657,7 @@ int lwm2m_rd_client_resume(void) #endif /* Or do we resume into registration state */ if (client.engine_state >= ENGINE_DO_REGISTRATION && - client.engine_state <= ENGINE_SUSPENDED) { + client.engine_state <= ENGINE_SERVER_DISABLED) { if (!client.last_update || (client.lifetime <= (k_uptime_get() - client.last_update) / MSEC_PER_SEC)) { /* No lifetime left, register again */ @@ -1575,6 +1675,29 @@ int lwm2m_rd_client_resume(void) return 0; } +int lwm2m_rd_client_server_disabled(uint16_t inst_id) +{ + if (client.ctx->srv_obj_inst != inst_id) { + return -EPERM; + } + + k_mutex_lock(&client.mutex, K_FOREVER); + + client.server_disabled = true; + + if (sm_is_registered()) { + LOG_INF("Server disabled, deregister"); + set_sm_state_delayed(ENGINE_DEREGISTER, DELAY_BEFORE_CLOSING); + } else { + LOG_INF("Server disabled"); + set_sm_state(ENGINE_DEREGISTERED); + } + + k_mutex_unlock(&client.mutex); + + return 0; +} + void lwm2m_rd_client_update(void) { engine_trigger_update(false); diff --git a/subsys/net/lib/lwm2m/lwm2m_rd_client.h b/subsys/net/lib/lwm2m/lwm2m_rd_client.h index 66a3aac20f3..5d71ccb30f6 100644 --- a/subsys/net/lib/lwm2m/lwm2m_rd_client.h +++ b/subsys/net/lib/lwm2m/lwm2m_rd_client.h @@ -56,4 +56,14 @@ int lwm2m_rd_client_connection_resume(struct lwm2m_ctx *client_ctx); void engine_update_tx_time(void); struct lwm2m_message *lwm2m_get_ongoing_rd_msg(void); +/** + * @brief Notify RD client that this server is disabled. + * + * This may return error -EPERM, if RD client is not registered on that server. + * + * @param inst_id server instance id + * @return int 0 on success, negative errno on failure. + */ +int lwm2m_rd_client_server_disabled(uint16_t inst_id); + #endif /* LWM2M_RD_CLIENT_H */ diff --git a/tests/net/lib/lwm2m/interop/src/lwm2m-client.c b/tests/net/lib/lwm2m/interop/src/lwm2m-client.c index 706091659a5..b6634069fbd 100644 --- a/tests/net/lib/lwm2m/interop/src/lwm2m-client.c +++ b/tests/net/lib/lwm2m/interop/src/lwm2m-client.c @@ -119,6 +119,10 @@ static void rd_client_event(struct lwm2m_ctx *client, /* do nothing */ break; + case LWM2M_RD_CLIENT_EVENT_SERVER_DISABLED: + LOG_DBG("LwM2M server disabled"); + break; + case LWM2M_RD_CLIENT_EVENT_BOOTSTRAP_REG_FAILURE: LOG_DBG("Bootstrap registration failure!"); break; diff --git a/tests/net/lib/lwm2m/lwm2m_rd_client/src/main.c b/tests/net/lib/lwm2m/lwm2m_rd_client/src/main.c index 208298512d4..1d6a4e584fa 100644 --- a/tests/net/lib/lwm2m/lwm2m_rd_client/src/main.c +++ b/tests/net/lib/lwm2m/lwm2m_rd_client/src/main.c @@ -21,7 +21,7 @@ DEFINE_FFF_GLOBALS; /* Maximum number of iterations within the state machine of RD Client * service that is waited for until a possible event occurs */ -static const uint8_t RD_CLIENT_MAX_LOOKUP_ITERATIONS = 100; +#define RD_CLIENT_MAX_LOOKUP_ITERATIONS 500 FAKE_VOID_FUNC(show_lwm2m_event, enum lwm2m_rd_client_event); FAKE_VOID_FUNC(show_lwm2m_observe, enum lwm2m_observe_event); @@ -97,6 +97,9 @@ static void lwm2m_event_cb(struct lwm2m_ctx *client, enum lwm2m_rd_client_event case LWM2M_RD_CLIENT_EVENT_QUEUE_MODE_RX_OFF: LOG_INF("*** LWM2M_RD_CLIENT_EVENT_QUEUE_MODE_RX_OFF"); break; + case LWM2M_RD_CLIENT_EVENT_SERVER_DISABLED: + LOG_INF("*** LWM2M_RD_CLIENT_EVENT_SERVER_DISABLED"); + break; case LWM2M_RD_CLIENT_EVENT_ENGINE_SUSPENDED: LOG_INF("*** LWM2M_RD_CLIENT_EVENT_ENGINE_SUSPENDED"); break; @@ -165,6 +168,7 @@ static void my_suite_before(void *data) lwm2m_init_message_fake.custom_fake = lwm2m_init_message_fake_default; coap_header_get_code_fake.custom_fake = coap_header_get_code_fake_created; coap_packet_append_option_fake.custom_fake = NULL; + stub_lwm2m_server_disable(false); } static void my_suite_after(void *data) @@ -198,8 +202,6 @@ ZTEST(lwm2m_rd_client, test_start_registration_ok) (void)memset(&ctx, 0x0, sizeof(ctx)); - test_prepare_pending_message_cb(&message_reply_cb_default); - lwm2m_rd_client_init(); test_lwm2m_engine_start_service(); wait_for_service(1); @@ -207,6 +209,7 @@ ZTEST(lwm2m_rd_client, test_start_registration_ok) coap_find_options_fake.custom_fake = coap_find_options_do_registration_reply_cb_ok; zassert_true(lwm2m_rd_client_start(&ctx, "Test", 0, lwm2m_event_cb, lwm2m_observe_cb) == 0, NULL); + test_prepare_pending_message_cb(&message_reply_cb_default); zassert(lwm2m_rd_client_ctx() == &ctx, ""); zassert_true(expect_lwm2m_rd_client_event(LWM2M_RD_CLIENT_EVENT_REGISTRATION_COMPLETE), NULL); @@ -228,8 +231,6 @@ ZTEST(lwm2m_rd_client, test_register_update_too_small_lifetime_to_default) (void)memset(&ctx, 0x0, sizeof(ctx)); - test_prepare_pending_message_cb(&message_reply_cb_default); - lwm2m_rd_client_init(); test_lwm2m_engine_start_service(); wait_for_service(1); @@ -237,6 +238,7 @@ ZTEST(lwm2m_rd_client, test_register_update_too_small_lifetime_to_default) coap_find_options_fake.custom_fake = coap_find_options_do_registration_reply_cb_ok; zassert_true(lwm2m_rd_client_start(&ctx, "Test", 0, lwm2m_event_cb, lwm2m_observe_cb) == 0, NULL); + test_prepare_pending_message_cb(&message_reply_cb_default); zassert(lwm2m_rd_client_ctx() == &ctx, ""); zassert_true(expect_lwm2m_rd_client_event(LWM2M_RD_CLIENT_EVENT_REGISTRATION_COMPLETE), NULL); @@ -249,14 +251,13 @@ ZTEST(lwm2m_rd_client, test_timeout_resume_registration) (void)memset(&ctx, 0x0, sizeof(ctx)); - test_prepare_pending_message_cb(&message_reply_cb_default); - lwm2m_rd_client_init(); test_lwm2m_engine_start_service(); coap_find_options_fake.custom_fake = coap_find_options_do_registration_reply_cb_ok; zassert_true(lwm2m_rd_client_start(&ctx, "Test", 0, lwm2m_event_cb, lwm2m_observe_cb) == 0, NULL); + test_prepare_pending_message_cb(&message_reply_cb_default); zassert(lwm2m_rd_client_ctx() == &ctx, ""); zassert_true(expect_lwm2m_rd_client_event(LWM2M_RD_CLIENT_EVENT_REGISTRATION_COMPLETE), NULL); @@ -273,16 +274,17 @@ ZTEST(lwm2m_rd_client, test_start_registration_timeout) (void)memset(&ctx, 0x0, sizeof(ctx)); - test_prepare_pending_message_cb(&message_reply_timeout_cb_default); - lwm2m_rd_client_init(); test_lwm2m_engine_start_service(); wait_for_service(1); zassert_true(lwm2m_rd_client_start(&ctx, "Test", 0, lwm2m_event_cb, lwm2m_observe_cb) == 0, NULL); - zassert_true(expect_lwm2m_rd_client_event(LWM2M_RD_CLIENT_EVENT_DISCONNECT), NULL); + test_prepare_pending_message_cb(&message_reply_timeout_cb_default); zassert_true(expect_lwm2m_rd_client_event(LWM2M_RD_CLIENT_EVENT_REG_TIMEOUT), NULL); + zassert_true(expect_lwm2m_rd_client_event(LWM2M_RD_CLIENT_EVENT_REG_TIMEOUT), NULL); + zassert_true(expect_lwm2m_rd_client_event(LWM2M_RD_CLIENT_EVENT_REG_TIMEOUT), NULL); + zassert_true(expect_lwm2m_rd_client_event(LWM2M_RD_CLIENT_EVENT_NETWORK_ERROR), NULL); } ZTEST(lwm2m_rd_client, test_start_registration_fail) @@ -291,8 +293,6 @@ ZTEST(lwm2m_rd_client, test_start_registration_fail) (void)memset(&ctx, 0x0, sizeof(ctx)); - test_prepare_pending_message_cb(&message_reply_cb_default); - lwm2m_rd_client_init(); test_lwm2m_engine_start_service(); wait_for_service(1); @@ -302,8 +302,15 @@ ZTEST(lwm2m_rd_client, test_start_registration_fail) lwm2m_init_message_fake.custom_fake = lwm2m_init_message_fake_default; zassert_true(lwm2m_rd_client_start(&ctx, "Test", 0, lwm2m_event_cb, lwm2m_observe_cb) == 0, NULL); + test_prepare_pending_message_cb(&message_reply_cb_default); + zassert_true(expect_lwm2m_rd_client_event(LWM2M_RD_CLIENT_EVENT_REGISTRATION_FAILURE), + NULL); zassert_true(expect_lwm2m_rd_client_event(LWM2M_RD_CLIENT_EVENT_REGISTRATION_FAILURE), NULL); + zassert_true(expect_lwm2m_rd_client_event(LWM2M_RD_CLIENT_EVENT_REGISTRATION_FAILURE), + NULL); + zassert_true(expect_lwm2m_rd_client_event(LWM2M_RD_CLIENT_EVENT_NETWORK_ERROR), + NULL); } ZTEST(lwm2m_rd_client, test_start_registration_update) @@ -312,8 +319,6 @@ ZTEST(lwm2m_rd_client, test_start_registration_update) (void)memset(&ctx, 0x0, sizeof(ctx)); - test_prepare_pending_message_cb(&message_reply_cb_default); - lwm2m_rd_client_init(); test_lwm2m_engine_start_service(); wait_for_service(1); @@ -321,6 +326,7 @@ ZTEST(lwm2m_rd_client, test_start_registration_update) coap_find_options_fake.custom_fake = coap_find_options_do_registration_reply_cb_ok; zassert_true(lwm2m_rd_client_start(&ctx, "Test", 0, lwm2m_event_cb, lwm2m_observe_cb) == 0, NULL); + test_prepare_pending_message_cb(&message_reply_cb_default); zassert_true(expect_lwm2m_rd_client_event(LWM2M_RD_CLIENT_EVENT_REGISTRATION_COMPLETE), NULL); @@ -335,8 +341,6 @@ ZTEST(lwm2m_rd_client, test_rx_off) (void)memset(&ctx, 0x0, sizeof(ctx)); - test_prepare_pending_message_cb(&message_reply_cb_default); - lwm2m_rd_client_init(); test_lwm2m_engine_start_service(); wait_for_service(1); @@ -344,6 +348,7 @@ ZTEST(lwm2m_rd_client, test_rx_off) coap_find_options_fake.custom_fake = coap_find_options_do_registration_reply_cb_ok; zassert_true(lwm2m_rd_client_start(&ctx, "Test", 0, lwm2m_event_cb, lwm2m_observe_cb) == 0, NULL); + test_prepare_pending_message_cb(&message_reply_cb_default); zassert_true(expect_lwm2m_rd_client_event(LWM2M_RD_CLIENT_EVENT_REGISTRATION_COMPLETE), NULL); @@ -359,8 +364,6 @@ ZTEST(lwm2m_rd_client, test_start_registration_update_fail) (void)memset(&ctx, 0x0, sizeof(ctx)); - test_prepare_pending_message_cb(&message_reply_cb_default); - lwm2m_rd_client_init(); test_lwm2m_engine_start_service(); wait_for_service(1); @@ -368,6 +371,7 @@ ZTEST(lwm2m_rd_client, test_start_registration_update_fail) coap_find_options_fake.custom_fake = coap_find_options_do_registration_reply_cb_ok; zassert_true(lwm2m_rd_client_start(&ctx, "Test", 0, lwm2m_event_cb, lwm2m_observe_cb) == 0, NULL); + test_prepare_pending_message_cb(&message_reply_cb_default); zassert_true(expect_lwm2m_rd_client_event(LWM2M_RD_CLIENT_EVENT_REGISTRATION_COMPLETE), NULL); @@ -384,8 +388,6 @@ ZTEST(lwm2m_rd_client, test_registration_update_timeout) (void)memset(&ctx, 0x0, sizeof(ctx)); - test_prepare_pending_message_cb(&message_reply_cb_default); - lwm2m_rd_client_init(); test_lwm2m_engine_start_service(); wait_for_service(1); @@ -393,6 +395,7 @@ ZTEST(lwm2m_rd_client, test_registration_update_timeout) coap_find_options_fake.custom_fake = coap_find_options_do_registration_reply_cb_ok; zassert_true(lwm2m_rd_client_start(&ctx, "Test", 0, lwm2m_event_cb, lwm2m_observe_cb) == 0, NULL); + test_prepare_pending_message_cb(&message_reply_cb_default); zassert_true(expect_lwm2m_rd_client_event(LWM2M_RD_CLIENT_EVENT_REGISTRATION_COMPLETE), NULL); test_prepare_pending_message_cb(&message_reply_timeout_cb_default); @@ -415,8 +418,6 @@ ZTEST(lwm2m_rd_client, test_deregistration_timeout) (void)memset(&ctx, 0x0, sizeof(ctx)); - test_prepare_pending_message_cb(&message_reply_cb_default); - lwm2m_rd_client_init(); test_lwm2m_engine_start_service(); wait_for_service(1); @@ -424,6 +425,7 @@ ZTEST(lwm2m_rd_client, test_deregistration_timeout) coap_find_options_fake.custom_fake = coap_find_options_do_registration_reply_cb_ok; zassert_true(lwm2m_rd_client_start(&ctx, "Test", 0, lwm2m_event_cb, lwm2m_observe_cb) == 0, NULL); + test_prepare_pending_message_cb(&message_reply_cb_default); zassert_true(expect_lwm2m_rd_client_event(LWM2M_RD_CLIENT_EVENT_REGISTRATION_COMPLETE), NULL); @@ -439,8 +441,6 @@ ZTEST(lwm2m_rd_client, test_error_on_registration_update) (void)memset(&ctx, 0x0, sizeof(ctx)); - test_prepare_pending_message_cb(&message_reply_cb_default); - lwm2m_rd_client_init(); test_lwm2m_engine_start_service(); wait_for_service(1); @@ -449,6 +449,8 @@ ZTEST(lwm2m_rd_client, test_error_on_registration_update) coap_packet_append_option_fake.custom_fake = NULL; zassert_true(lwm2m_rd_client_start(&ctx, "Test", 0, lwm2m_event_cb, lwm2m_observe_cb) == 0, NULL); + test_prepare_pending_message_cb(&message_reply_cb_default); + zassert_true(expect_lwm2m_rd_client_event(LWM2M_RD_CLIENT_EVENT_REGISTRATION_COMPLETE), NULL); @@ -482,8 +484,6 @@ ZTEST(lwm2m_rd_client, test_suspend_resume_registration) (void)memset(&ctx, 0x0, sizeof(ctx)); - test_prepare_pending_message_cb(&message_reply_cb_default); - lwm2m_rd_client_init(); test_lwm2m_engine_start_service(); wait_for_service(1); @@ -491,6 +491,7 @@ ZTEST(lwm2m_rd_client, test_suspend_resume_registration) coap_find_options_fake.custom_fake = coap_find_options_do_registration_reply_cb_ok; zassert_true(lwm2m_rd_client_start(&ctx, "Test", 0, lwm2m_event_cb, lwm2m_observe_cb) == 0, NULL); + test_prepare_pending_message_cb(&message_reply_cb_default); zassert_true(expect_lwm2m_rd_client_event(LWM2M_RD_CLIENT_EVENT_REGISTRATION_COMPLETE), NULL); zassert_true(!lwm2m_rd_client_is_suspended(&ctx), NULL); @@ -517,8 +518,6 @@ ZTEST(lwm2m_rd_client, test_suspend_stop_resume) (void)memset(&ctx, 0x0, sizeof(ctx)); - test_prepare_pending_message_cb(&message_reply_cb_default); - lwm2m_rd_client_init(); test_lwm2m_engine_start_service(); wait_for_service(1); @@ -527,6 +526,7 @@ ZTEST(lwm2m_rd_client, test_suspend_stop_resume) coap_find_options_fake.custom_fake = coap_find_options_do_registration_reply_cb_ok; zassert_true(lwm2m_rd_client_start(&ctx, "Test", 0, lwm2m_event_cb, lwm2m_observe_cb) == 0, NULL); + test_prepare_pending_message_cb(&message_reply_cb_default); zassert_true(expect_lwm2m_rd_client_event(LWM2M_RD_CLIENT_EVENT_REGISTRATION_COMPLETE), NULL); zassert_true(lwm2m_rd_client_pause() == 0, NULL); @@ -544,8 +544,6 @@ ZTEST(lwm2m_rd_client, test_socket_error) (void)memset(&ctx, 0x0, sizeof(ctx)); - test_prepare_pending_message_cb(&message_reply_cb_default); - lwm2m_rd_client_init(); test_lwm2m_engine_start_service(); wait_for_service(1); @@ -554,6 +552,7 @@ ZTEST(lwm2m_rd_client, test_socket_error) coap_find_options_fake.custom_fake = coap_find_options_do_registration_reply_cb_ok; zassert_true(lwm2m_rd_client_start(&ctx, "Test", 0, lwm2m_event_cb, lwm2m_observe_cb) == 0, NULL); + test_prepare_pending_message_cb(&message_reply_cb_default); zassert_true(expect_lwm2m_rd_client_event(LWM2M_RD_CLIENT_EVENT_REGISTRATION_COMPLETE), NULL); @@ -569,8 +568,6 @@ ZTEST(lwm2m_rd_client, test_socket_error_on_stop) (void)memset(&ctx, 0x0, sizeof(ctx)); - test_prepare_pending_message_cb(&message_reply_cb_default); - lwm2m_rd_client_init(); test_lwm2m_engine_start_service(); wait_for_service(1); @@ -579,6 +576,7 @@ ZTEST(lwm2m_rd_client, test_socket_error_on_stop) coap_find_options_fake.custom_fake = coap_find_options_do_registration_reply_cb_ok; zassert_true(lwm2m_rd_client_start(&ctx, "Test", 0, lwm2m_event_cb, lwm2m_observe_cb) == 0, NULL); + test_prepare_pending_message_cb(&message_reply_cb_default); zassert_true(expect_lwm2m_rd_client_event(LWM2M_RD_CLIENT_EVENT_REGISTRATION_COMPLETE), NULL); @@ -608,8 +606,6 @@ ZTEST(lwm2m_rd_client, test_engine_trigger_bootstrap) (void)memset(&ctx, 0x0, sizeof(ctx)); - test_prepare_pending_message_cb(&message_reply_cb_default); - lwm2m_rd_client_init(); test_lwm2m_engine_start_service(); wait_for_service(1); @@ -617,6 +613,7 @@ ZTEST(lwm2m_rd_client, test_engine_trigger_bootstrap) coap_find_options_fake.custom_fake = coap_find_options_do_registration_reply_cb_ok; zassert_true(lwm2m_rd_client_start(&ctx, "Test", 0, lwm2m_event_cb, lwm2m_observe_cb) == 0, NULL); + test_prepare_pending_message_cb(&message_reply_cb_default); zassert_true(expect_lwm2m_rd_client_event(LWM2M_RD_CLIENT_EVENT_REGISTRATION_COMPLETE), NULL); lwm2m_get_bool_fake.custom_fake = lwm2m_get_bool_fake_true; @@ -638,8 +635,6 @@ ZTEST(lwm2m_rd_client, test_bootstrap_timeout) (void)memset(&ctx, 0x0, sizeof(ctx)); - test_prepare_pending_message_cb(&message_reply_timeout_cb_default); - lwm2m_rd_client_init(); test_lwm2m_engine_start_service(); wait_for_service(1); @@ -651,6 +646,7 @@ ZTEST(lwm2m_rd_client, test_bootstrap_timeout) coap_find_options_fake.custom_fake = coap_find_options_do_registration_reply_cb_ok; zassert_true(lwm2m_rd_client_start(&ctx, "Test", 1, lwm2m_event_cb, lwm2m_observe_cb) == 0, NULL); + test_prepare_pending_message_cb(&message_reply_timeout_cb_default); zassert_true(expect_lwm2m_rd_client_event(LWM2M_RD_CLIENT_EVENT_BOOTSTRAP_REG_FAILURE), NULL); } @@ -661,8 +657,6 @@ ZTEST(lwm2m_rd_client, test_bootstrap_fail) (void)memset(&ctx, 0x0, sizeof(ctx)); - test_prepare_pending_message_cb(&message_reply_cb_default); - lwm2m_rd_client_init(); test_lwm2m_engine_start_service(); wait_for_service(1); @@ -674,27 +668,154 @@ ZTEST(lwm2m_rd_client, test_bootstrap_fail) coap_find_options_fake.custom_fake = coap_find_options_do_registration_reply_cb_ok; zassert_true(lwm2m_rd_client_start(&ctx, "Test", 1, lwm2m_event_cb, lwm2m_observe_cb) == 0, NULL); + test_prepare_pending_message_cb(&message_reply_cb_default); zassert_true(expect_lwm2m_rd_client_event(LWM2M_RD_CLIENT_EVENT_BOOTSTRAP_REG_FAILURE), NULL); } -ZTEST(lwm2m_rd_client, test_bootstrap_no_srv_fallback_to_register) +ZTEST(lwm2m_rd_client, test_bootstrap_no_srv) { struct lwm2m_ctx ctx; (void)memset(&ctx, 0x0, sizeof(ctx)); + lwm2m_rd_client_init(); + test_lwm2m_engine_start_service(); + wait_for_service(1); + + coap_find_options_fake.custom_fake = coap_find_options_do_registration_reply_cb_ok; + zassert_true(lwm2m_rd_client_start(&ctx, "Test", 1, lwm2m_event_cb, lwm2m_observe_cb) == 0, + NULL); test_prepare_pending_message_cb(&message_reply_cb_default); + zassert_true(expect_lwm2m_rd_client_event(LWM2M_RD_CLIENT_EVENT_BOOTSTRAP_REG_FAILURE), + NULL); +} + +ZTEST(lwm2m_rd_client, test_disable_server) +{ + struct lwm2m_ctx ctx; + + (void)memset(&ctx, 0x0, sizeof(ctx)); lwm2m_rd_client_init(); test_lwm2m_engine_start_service(); wait_for_service(1); coap_find_options_fake.custom_fake = coap_find_options_do_registration_reply_cb_ok; - zassert_true(lwm2m_rd_client_start(&ctx, "Test", 1, lwm2m_event_cb, lwm2m_observe_cb) == 0, + zassert_true(lwm2m_rd_client_start(&ctx, "Test", 0, lwm2m_event_cb, lwm2m_observe_cb) == 0, NULL); + test_prepare_pending_message_cb(&message_reply_cb_default); + zassert_true(expect_lwm2m_rd_client_event(LWM2M_RD_CLIENT_EVENT_REGISTRATION_COMPLETE), + NULL); + coap_header_get_code_fake.custom_fake = coap_header_get_code_fake_deleted; + stub_lwm2m_server_disable(true); + lwm2m_rd_client_server_disabled(0); + zassert_true(expect_lwm2m_rd_client_event(LWM2M_RD_CLIENT_EVENT_SERVER_DISABLED), + NULL); +} + +ZTEST(lwm2m_rd_client, test_disable_server_stop) +{ + struct lwm2m_ctx ctx; + + (void)memset(&ctx, 0x0, sizeof(ctx)); + + lwm2m_rd_client_init(); + test_lwm2m_engine_start_service(); + wait_for_service(1); + + coap_find_options_fake.custom_fake = coap_find_options_do_registration_reply_cb_ok; + zassert_true(lwm2m_rd_client_start(&ctx, "Test", 0, lwm2m_event_cb, lwm2m_observe_cb) == 0, + NULL); + test_prepare_pending_message_cb(&message_reply_cb_default); + zassert_true(expect_lwm2m_rd_client_event(LWM2M_RD_CLIENT_EVENT_REGISTRATION_COMPLETE), + NULL); + coap_header_get_code_fake.custom_fake = coap_header_get_code_fake_deleted; + stub_lwm2m_server_disable(true); + lwm2m_rd_client_server_disabled(0); + zassert_true(expect_lwm2m_rd_client_event(LWM2M_RD_CLIENT_EVENT_SERVER_DISABLED), + NULL); + wait_for_service(1); + zassert_true(lwm2m_rd_client_stop(&ctx, lwm2m_event_cb, true) == 0, NULL); + zassert_true(expect_lwm2m_rd_client_event(LWM2M_RD_CLIENT_EVENT_DISCONNECT), NULL); +} + +ZTEST(lwm2m_rd_client, test_disable_server_connect) +{ + struct lwm2m_ctx ctx; + + (void)memset(&ctx, 0x0, sizeof(ctx)); + + lwm2m_rd_client_init(); + test_lwm2m_engine_start_service(); + wait_for_service(1); + + coap_find_options_fake.custom_fake = coap_find_options_do_registration_reply_cb_ok; + zassert_true(lwm2m_rd_client_start(&ctx, "Test", 0, lwm2m_event_cb, lwm2m_observe_cb) == 0, + NULL); + test_prepare_pending_message_cb(&message_reply_cb_default); + zassert_true(expect_lwm2m_rd_client_event(LWM2M_RD_CLIENT_EVENT_REGISTRATION_COMPLETE), + NULL); + coap_header_get_code_fake.custom_fake = coap_header_get_code_fake_deleted; + stub_lwm2m_server_disable(true); + lwm2m_rd_client_server_disabled(0); + zassert_true(expect_lwm2m_rd_client_event(LWM2M_RD_CLIENT_EVENT_SERVER_DISABLED), + NULL); + + wait_for_service(500); + + coap_header_get_code_fake.custom_fake = coap_header_get_code_fake_created; + stub_lwm2m_server_disable(false); + zassert_true(expect_lwm2m_rd_client_event(LWM2M_RD_CLIENT_EVENT_REGISTRATION_COMPLETE), + NULL); +} + +ZTEST(lwm2m_rd_client, test_fallback_to_bootstrap) +{ + struct lwm2m_ctx ctx; + + (void)memset(&ctx, 0x0, sizeof(ctx)); + + lwm2m_rd_client_init(); + test_lwm2m_engine_start_service(); + wait_for_service(1); + + lwm2m_get_bool_fake.custom_fake = lwm2m_get_bool_fake_true; + zassert_true(lwm2m_rd_client_start(&ctx, "Test", 0, lwm2m_event_cb, lwm2m_observe_cb) == 0, + NULL); + test_prepare_pending_message_cb(&message_reply_timeout_cb_default); + zassert_true(expect_lwm2m_rd_client_event(LWM2M_RD_CLIENT_EVENT_REG_TIMEOUT), NULL); + zassert_true(expect_lwm2m_rd_client_event(LWM2M_RD_CLIENT_EVENT_REG_TIMEOUT), NULL); + zassert_true(expect_lwm2m_rd_client_event(LWM2M_RD_CLIENT_EVENT_REG_TIMEOUT), NULL); + + zassert_true(expect_lwm2m_rd_client_event(LWM2M_RD_CLIENT_EVENT_BOOTSTRAP_REG_FAILURE), + NULL); +} + +ZTEST(lwm2m_rd_client, test_no_srv_fallback_to_bootstrap) +{ + struct lwm2m_ctx ctx; + + (void)memset(&ctx, 0x0, sizeof(ctx)); + + lwm2m_rd_client_init(); + test_lwm2m_engine_start_service(); + wait_for_service(1); + + coap_header_get_code_fake.custom_fake = coap_header_get_code_fake_changed; + lwm2m_get_bool_fake.custom_fake = lwm2m_get_bool_fake_true; + stub_lwm2m_server_disable(true); + zassert_true(lwm2m_rd_client_start(&ctx, "Test", 0, lwm2m_event_cb, lwm2m_observe_cb) == 0, + NULL); + test_prepare_pending_message_cb(&message_reply_cb_default); + zassert_true(expect_lwm2m_rd_client_event(LWM2M_RD_CLIENT_EVENT_BOOTSTRAP_REG_COMPLETE), + NULL); + coap_header_get_code_fake.custom_fake = coap_header_get_code_fake_created; + coap_find_options_fake.custom_fake = coap_find_options_do_registration_reply_cb_ok; + stub_lwm2m_server_disable(false); + engine_bootstrap_finish(); zassert_true(expect_lwm2m_rd_client_event(LWM2M_RD_CLIENT_EVENT_REGISTRATION_COMPLETE), NULL); } diff --git a/tests/net/lib/lwm2m/lwm2m_rd_client/src/stubs.c b/tests/net/lib/lwm2m/lwm2m_rd_client/src/stubs.c index 3cbde9060ce..621057f8496 100644 --- a/tests/net/lib/lwm2m/lwm2m_rd_client/src/stubs.c +++ b/tests/net/lib/lwm2m/lwm2m_rd_client/src/stubs.c @@ -116,6 +116,24 @@ char *lwm2m_sprint_ip_addr_fake_default(const struct sockaddr *addr) DEFINE_FAKE_VALUE_FUNC(int, lwm2m_server_short_id_to_inst, uint16_t); DEFINE_FAKE_VALUE_FUNC(int, lwm2m_security_index_to_inst_id, int); +DEFINE_FAKE_VALUE_FUNC(int, lwm2m_security_short_id_to_inst, uint16_t); +DEFINE_FAKE_VALUE_FUNC(int, lwm2m_server_disable, uint16_t, k_timeout_t); +DEFINE_FAKE_VALUE_FUNC(uint8_t, lwm2m_server_get_prio, uint16_t); +DEFINE_FAKE_VOID_FUNC(lwm2m_server_reset_timestamps); + +static bool srv_disabled; +bool lwm2m_server_select(uint16_t *obj_inst_id) +{ + if (obj_inst_id) { + *obj_inst_id = 0; + } + return !srv_disabled; +} + +void stub_lwm2m_server_disable(bool disable) +{ + srv_disabled = disable; +} k_work_handler_t service; int64_t next; @@ -177,9 +195,13 @@ void test_lwm2m_engine_start_service(void) void test_lwm2m_engine_stop_service(void) { + struct k_work_sync sync; + pending_message_cb = NULL; + pending_message = NULL; running = false; k_work_cancel(&service_work); + k_work_flush(&service_work, &sync); } /* subsys/net/lib/lwm2m/lwm2m_message_handling.h */ diff --git a/tests/net/lib/lwm2m/lwm2m_rd_client/src/stubs.h b/tests/net/lib/lwm2m/lwm2m_rd_client/src/stubs.h index 1276dd5c109..0a3ce31d9e8 100644 --- a/tests/net/lib/lwm2m/lwm2m_rd_client/src/stubs.h +++ b/tests/net/lib/lwm2m/lwm2m_rd_client/src/stubs.h @@ -59,6 +59,8 @@ DECLARE_FAKE_VALUE_FUNC(int, lwm2m_socket_close, struct lwm2m_ctx *); DECLARE_FAKE_VALUE_FUNC(int, lwm2m_close_socket, struct lwm2m_ctx *); DECLARE_FAKE_VALUE_FUNC(int, lwm2m_socket_suspend, struct lwm2m_ctx *); DECLARE_FAKE_VALUE_FUNC(int, lwm2m_security_inst_id_to_index, uint16_t); +DECLARE_FAKE_VALUE_FUNC(int, lwm2m_security_short_id_to_inst, uint16_t); +DECLARE_FAKE_VALUE_FUNC(int, lwm2m_security_index_to_inst_id, int); DECLARE_FAKE_VALUE_FUNC(int, lwm2m_engine_connection_resume, struct lwm2m_ctx *); DECLARE_FAKE_VALUE_FUNC(int, lwm2m_push_queued_buffers, struct lwm2m_ctx *); DECLARE_FAKE_VOID_FUNC(lwm2m_engine_context_init, struct lwm2m_ctx *); @@ -68,10 +70,15 @@ DECLARE_FAKE_VOID_FUNC(lwm2m_engine_context_close, struct lwm2m_ctx *); DECLARE_FAKE_VALUE_FUNC(char *, lwm2m_sprint_ip_addr, const struct sockaddr *); char *lwm2m_sprint_ip_addr_fake_default(const struct sockaddr *addr); DECLARE_FAKE_VALUE_FUNC(int, lwm2m_server_short_id_to_inst, uint16_t); -DECLARE_FAKE_VALUE_FUNC(int, lwm2m_security_index_to_inst_id, int); +DECLARE_FAKE_VALUE_FUNC(int, lwm2m_server_disable, uint16_t, k_timeout_t); +DECLARE_FAKE_VALUE_FUNC(uint8_t, lwm2m_server_get_prio, uint16_t); +DECLARE_FAKE_VOID_FUNC(lwm2m_server_reset_timestamps); + + void wait_for_service(uint16_t cycles); void test_lwm2m_engine_start_service(void); void test_lwm2m_engine_stop_service(void); +void stub_lwm2m_server_disable(bool disable); /* subsys/net/lib/lwm2m/lwm2m_message_handling.h */ DECLARE_FAKE_VALUE_FUNC(int, lwm2m_init_message, struct lwm2m_message *); From 30dcf1b30979c11f7fbd4b2edfa6d43ea8356667 Mon Sep 17 00:00:00 2001 From: Seppo Takalo Date: Fri, 1 Dec 2023 16:15:13 +0200 Subject: [PATCH 0783/3723] test: lwm2m: Refactor tests to work with fallback changes In fallback refactoring to the LwM2M engine, some changes to the server object are visible in hard-coded test values. Also, add Endpoint wrapper class that ensures the registration state of the returned endpoint. Signed-off-by: Seppo Takalo --- .../net/lib/lwm2m/interop/pytest/conftest.py | 34 +++++++++++++++---- .../lib/lwm2m/interop/pytest/test_lwm2m.py | 9 ++--- 2 files changed, 33 insertions(+), 10 deletions(-) diff --git a/tests/net/lib/lwm2m/interop/pytest/conftest.py b/tests/net/lib/lwm2m/interop/pytest/conftest.py index 9ca971b85c7..7d3ea4e7f80 100644 --- a/tests/net/lib/lwm2m/interop/pytest/conftest.py +++ b/tests/net/lib/lwm2m/interop/pytest/conftest.py @@ -27,6 +27,25 @@ logger = logging.getLogger(__name__) +class Endpoint: + def __init__(self, name: str, shell: Shell, registered: bool = False, bootstrap: bool = False): + self.name = name + self.registered = registered + self.bootstrap = bootstrap + self.shell = shell + self.last_update = 0.0 + + def check_update(self): + if not self.registered: + return + if self.last_update < time.time() - 5: + self.shell.exec_command('lwm2m update') + self.last_update = time.time() + + def __str__(self): + return self.name + + @pytest.fixture(scope='session') def leshan() -> Leshan: """ @@ -89,9 +108,8 @@ def endpoint_nosec(shell: Shell, dut: DeviceAdapter, leshan: Leshan) -> str: shell.exec_command('lwm2m write 1/0/0 -u16 1') shell.exec_command('lwm2m write 1/0/1 -u32 86400') shell.exec_command(f'lwm2m start {ep} -b 0') - dut.readlines_until(regex=f"RD Client started with endpoint '{ep}'", timeout=10.0) - yield ep + yield Endpoint(ep, shell) # All done shell.exec_command('lwm2m stop') @@ -125,7 +143,7 @@ def endpoint_bootstrap(shell: Shell, dut: DeviceAdapter, leshan: Leshan, leshan_ shell.exec_command(f'lwm2m write 0/0/5 -s {bs_passwd}') shell.exec_command(f'lwm2m start {ep} -b 1') - yield ep + yield Endpoint(ep, shell) shell.exec_command('lwm2m stop') dut.readlines_until(regex=r'.*Deregistration success', timeout=10.0) @@ -137,12 +155,16 @@ def endpoint_bootstrap(shell: Shell, dut: DeviceAdapter, leshan: Leshan, leshan_ leshan_bootstrap.delete_bs_device(ep) @pytest.fixture(scope='module') -def endpoint_registered(endpoint_bootstrap, shell: Shell, dut: DeviceAdapter) -> str: +def endpoint_registered(endpoint_bootstrap, dut: DeviceAdapter) -> str: """Fixture that returns an endpoint that is registered.""" - dut.readlines_until(regex='.*Registration Done', timeout=5.0) + if not endpoint_bootstrap.registered: + dut.readlines_until(regex='.*Registration Done', timeout=5.0) + endpoint_bootstrap.bootstrap = True + endpoint_bootstrap.registered = True return endpoint_bootstrap -@pytest.fixture(scope='module') +@pytest.fixture(scope='function') def endpoint(endpoint_registered) -> str: """Fixture that returns an endpoint that is registered.""" + endpoint_registered.check_update() return endpoint_registered diff --git a/tests/net/lib/lwm2m/interop/pytest/test_lwm2m.py b/tests/net/lib/lwm2m/interop/pytest/test_lwm2m.py index 131acb68e14..ed7aaceac20 100644 --- a/tests/net/lib/lwm2m/interop/pytest/test_lwm2m.py +++ b/tests/net/lib/lwm2m/interop/pytest/test_lwm2m.py @@ -171,6 +171,7 @@ def verify_setting_basic_in_format(shell, leshan, endpoint, format): verify_server_object(server_obj) # Remove Read-Only resources, so we don't end up writing those del server_obj[0][0] + del server_obj[0][13] data = { 2: 101, 3: 1010, @@ -208,7 +209,7 @@ def test_LightweightM2M_1_1_int_222(shell: Shell, leshan: Leshan, endpoint: str) """LightweightM2M-1.1-int-222 - Read on Object""" resp = leshan.read(endpoint, '1') assert len(resp) == 1 - assert len(resp[1][0]) == 9 + assert len(resp[1][0]) == 11 resp = leshan.read(endpoint, '3') assert len(resp) == 1 assert len(resp[3]) == 1 @@ -218,7 +219,7 @@ def test_LightweightM2M_1_1_int_222(shell: Shell, leshan: Leshan, endpoint: str) def test_LightweightM2M_1_1_int_223(shell: Shell, leshan: Leshan, endpoint: str): """LightweightM2M-1.1-int-223 - Read on Object Instance""" resp = leshan.read(endpoint, '1/0') - assert len(resp[0]) == 9 + assert len(resp[0]) == 11 resp = leshan.read(endpoint, '3/0') assert len(resp[0]) == 15 assert resp[0][0] == 'Zephyr' @@ -282,7 +283,7 @@ def test_LightweightM2M_1_1_int_229(shell: Shell, leshan: Leshan, endpoint: str) assert resp[3] is not None assert resp[1][0] is not None assert len(resp[3][0]) == 15 - assert len(resp[1][0]) == 9 + assert len(resp[1][0]) == 11 resp = leshan.composite_read(endpoint, ['1/0/1', '/3/0/11/0']) logger.debug(resp) @@ -370,7 +371,7 @@ def test_LightweightM2M_1_1_int_234(shell: Shell, leshan: Leshan, endpoint: str) def test_LightweightM2M_1_1_int_235(leshan: Leshan, endpoint: str): """LightweightM2M-1.1-int-235 - Read-Composite Operation on root path""" resp = leshan.composite_read(endpoint, ['/']) - expected_keys = [16, 1, 3, 5] + expected_keys = [1, 3, 5] missing_keys = [key for key in expected_keys if key not in resp.keys()] assert len(missing_keys) == 0 From 9102821fbe282d1b994ee21c0e3015c885de3d58 Mon Sep 17 00:00:00 2001 From: Seppo Takalo Date: Thu, 30 Nov 2023 20:50:33 +0200 Subject: [PATCH 0784/3723] doc: Clarify documentation of LwM2M events Properly document the actions that application should take on certain events. This clarifies the events that indicate that the LwM2M engine is stopped. Add missing events to the state machine diagram and apply color coding to states. Signed-off-by: Seppo Takalo --- .../api/images/lwm2m_engine_state_machine.png | Bin 217864 -> 0 bytes .../api/images/lwm2m_engine_state_machine.svg | 4 + doc/connectivity/networking/api/lwm2m.rst | 88 +++++++++++++----- 3 files changed, 68 insertions(+), 24 deletions(-) delete mode 100644 doc/connectivity/networking/api/images/lwm2m_engine_state_machine.png create mode 100644 doc/connectivity/networking/api/images/lwm2m_engine_state_machine.svg diff --git a/doc/connectivity/networking/api/images/lwm2m_engine_state_machine.png b/doc/connectivity/networking/api/images/lwm2m_engine_state_machine.png deleted file mode 100644 index b367a17dbeee312a4d6ea44b38796ab50ecde451..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 217864 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
+ uart:~$ gatt exchange-mtu + uart:~$ bap discover + Discover complete: err 0 + uart:~$ cap_initiator discover + discovery completed with CSIS + uart:~$ gmap discover + gmap discovered for conn 0x2001c7d8: + role 0x0f + ugg_feat 0x07 + ugt_feat 0x6f + bgs_feat 0x01 + bgr_feat 0x03 + uart:~$ gmap ac_3 32_2_gr 32_2_gs + Starting 2 streams for AC_3 + stream 0x20020060 config operation rsp_code 0 reason 0 + stream 0x200204d0 config operation rsp_code 0 reason 0 + stream 0x200204d0 qos operation rsp_code 0 reason 0 + stream 0x20020060 qos operation rsp_code 0 reason 0 + Stream 0x20020060 enabled + stream 0x200204d0 enable operation rsp_code 0 reason 0 + Stream 0x200204d0 enabled + stream 0x20020060 enable operation rsp_code 0 reason 0 + Stream 0x20020060 started + stream 0x200204d0 start operation rsp_code 0 reason 0 + Stream 0x200204d0 started + Unicast start completed + uart:~$ bap start_sine + Started transmitting on default_stream 0x20020060 + [0]: stream 0x20020060 : TX LC3: 80 (seq_num 24800) diff --git a/subsys/bluetooth/audio/shell/CMakeLists.txt b/subsys/bluetooth/audio/shell/CMakeLists.txt index a5230278330..11775acc8ab 100644 --- a/subsys/bluetooth/audio/shell/CMakeLists.txt +++ b/subsys/bluetooth/audio/shell/CMakeLists.txt @@ -67,6 +67,10 @@ zephyr_library_sources_ifdef( CONFIG_BT_TMAP tmap.c ) +zephyr_library_sources_ifdef( + CONFIG_BT_GMAP + gmap.c + ) # We use BT_BAP_STREAM as a common ground for audio, as that is set whenever # any audio stream functionality is enabled. zephyr_library_sources_ifdef( diff --git a/subsys/bluetooth/audio/shell/audio.h b/subsys/bluetooth/audio/shell/audio.h index 37959fbe366..d204dc3dc2d 100644 --- a/subsys/bluetooth/audio/shell/audio.h +++ b/subsys/bluetooth/audio/shell/audio.h @@ -29,6 +29,7 @@ ssize_t audio_ad_data_add(struct bt_data *data, const size_t data_size, const bo ssize_t audio_pa_data_add(struct bt_data *data_array, const size_t data_array_size); ssize_t csis_ad_data_add(struct bt_data *data, const size_t data_size, const bool discoverable); size_t cap_acceptor_ad_data_add(struct bt_data data[], size_t data_size, bool discoverable); +size_t gmap_ad_data_add(struct bt_data data[], size_t data_size); #if defined(CONFIG_BT_AUDIO) /* Must guard before including audio.h as audio.h uses Kconfigs guarded by @@ -39,12 +40,21 @@ size_t cap_acceptor_ad_data_add(struct bt_data data[], size_t data_size, bool di #include #include +#define LOCATION BT_AUDIO_LOCATION_FRONT_LEFT | BT_AUDIO_LOCATION_FRONT_RIGHT +#define CONTEXT \ + (BT_AUDIO_CONTEXT_TYPE_CONVERSATIONAL | BT_AUDIO_CONTEXT_TYPE_MEDIA | \ + IS_ENABLED(CONFIG_BT_GMAP) ? BT_AUDIO_CONTEXT_TYPE_GAME : 0U) + +const struct named_lc3_preset *gmap_get_named_preset(bool is_unicast, enum bt_audio_dir dir, + const char *preset_arg); + struct named_lc3_preset { const char *name; struct bt_bap_lc3_preset preset; }; -const struct named_lc3_preset *bap_get_named_preset(bool is_unicast, const char *preset_arg); +const struct named_lc3_preset *bap_get_named_preset(bool is_unicast, enum bt_audio_dir dir, + const char *preset_arg); #if defined(CONFIG_BT_BAP_UNICAST) @@ -224,6 +234,9 @@ struct bap_broadcast_ac_param { size_t chan_cnt; }; +int cap_ac_broadcast(const struct shell *sh, size_t argc, char **argv, + const struct bap_broadcast_ac_param *param); + extern struct shell_stream broadcast_source_streams[CONFIG_BT_BAP_BROADCAST_SRC_STREAM_COUNT]; extern struct broadcast_source default_source; #endif /* CONFIG_BT_BAP_BROADCAST_SOURCE */ diff --git a/subsys/bluetooth/audio/shell/bap.c b/subsys/bluetooth/audio/shell/bap.c index 3e946cf6436..70368226487 100644 --- a/subsys/bluetooth/audio/shell/bap.c +++ b/subsys/bluetooth/audio/shell/bap.c @@ -24,21 +24,19 @@ #include #include #include +#include #include #include "shell/bt.h" #include "audio.h" -#define LOCATION BT_AUDIO_LOCATION_FRONT_LEFT -#define CONTEXT BT_AUDIO_CONTEXT_TYPE_CONVERSATIONAL | BT_AUDIO_CONTEXT_TYPE_MEDIA - #if defined(CONFIG_BT_BAP_UNICAST) struct shell_stream unicast_streams[CONFIG_BT_MAX_CONN * (UNICAST_SERVER_STREAM_COUNT + UNICAST_CLIENT_STREAM_COUNT)]; static const struct bt_audio_codec_qos_pref qos_pref = - BT_AUDIO_CODEC_QOS_PREF(true, BT_GAP_LE_PHY_2M, 0u, 60u, 20000u, 40000u, 20000u, 40000u); + BT_AUDIO_CODEC_QOS_PREF(true, BT_GAP_LE_PHY_2M, 0u, 60u, 10000u, 60000u, 10000u, 60000u); #if defined(CONFIG_BT_BAP_UNICAST_CLIENT) struct bt_bap_unicast_group *default_unicast_group; @@ -400,7 +398,8 @@ void sdu_sent_cb(struct bt_bap_stream *bap_stream) } #endif /* CONFIG_LIBLC3 && CONFIG_BT_AUDIO_TX */ -const struct named_lc3_preset *bap_get_named_preset(bool is_unicast, const char *preset_arg) +const struct named_lc3_preset *bap_get_named_preset(bool is_unicast, enum bt_audio_dir dir, + const char *preset_arg) { if (is_unicast) { for (size_t i = 0U; i < ARRAY_SIZE(lc3_unicast_presets); i++) { @@ -416,6 +415,10 @@ const struct named_lc3_preset *bap_get_named_preset(bool is_unicast, const char } } + if (IS_ENABLED(CONFIG_BT_GMAP)) { + return gmap_get_named_preset(is_unicast, dir, preset_arg); + } + return NULL; } @@ -588,8 +591,7 @@ static int lc3_release(struct bt_bap_stream *stream, struct bt_bap_ascs_rsp *rsp static const struct bt_audio_codec_cap lc3_codec_cap = BT_AUDIO_CODEC_CAP_LC3( BT_AUDIO_CODEC_LC3_FREQ_ANY, BT_AUDIO_CODEC_LC3_DURATION_ANY, - BT_AUDIO_CODEC_LC3_CHAN_COUNT_SUPPORT(1, 2), 30, 240, 2, - (BT_AUDIO_CONTEXT_TYPE_CONVERSATIONAL | BT_AUDIO_CONTEXT_TYPE_MEDIA)); + BT_AUDIO_CODEC_LC3_CHAN_COUNT_SUPPORT(1, 2), 30, 240, 2, CONTEXT); static const struct bt_bap_unicast_server_cb unicast_server_cb = { .config = lc3_config, @@ -996,6 +998,7 @@ static int cmd_config(const struct shell *sh, size_t argc, char *argv[]) struct shell_stream *uni_stream; struct bt_bap_stream *bap_stream; struct bt_bap_ep *ep = NULL; + enum bt_audio_dir dir; unsigned long index; uint8_t conn_index; int err = 0; @@ -1029,6 +1032,7 @@ static int cmd_config(const struct shell *sh, size_t argc, char *argv[]) #if CONFIG_BT_BAP_UNICAST_CLIENT_ASE_SNK_COUNT > 0 } else if (!strcmp(argv[1], "sink")) { + dir = BT_AUDIO_DIR_SINK; ep = snks[conn_index][index]; named_preset = default_sink_preset; @@ -1036,6 +1040,7 @@ static int cmd_config(const struct shell *sh, size_t argc, char *argv[]) #if CONFIG_BT_BAP_UNICAST_CLIENT_ASE_SRC_COUNT > 0 } else if (!strcmp(argv[1], "source")) { + dir = BT_AUDIO_DIR_SOURCE; ep = srcs[conn_index][index]; named_preset = default_source_preset; @@ -1083,7 +1088,7 @@ static int cmd_config(const struct shell *sh, size_t argc, char *argv[]) if (argc > i) { arg = argv[++i]; - named_preset = bap_get_named_preset(true, arg); + named_preset = bap_get_named_preset(true, dir, arg); if (named_preset == NULL) { shell_error(sh, "Unable to parse named_preset %s", arg); return -ENOEXEC; @@ -1422,14 +1427,18 @@ static int cmd_stop(const struct shell *sh, size_t argc, char *argv[]) static int cmd_preset(const struct shell *sh, size_t argc, char *argv[]) { const struct named_lc3_preset *named_preset; + enum bt_audio_dir dir; bool unicast = true; if (!strcmp(argv[1], "sink")) { + dir = BT_AUDIO_DIR_SINK; named_preset = default_sink_preset; } else if (!strcmp(argv[1], "source")) { + dir = BT_AUDIO_DIR_SOURCE; named_preset = default_source_preset; } else if (!strcmp(argv[1], "broadcast")) { unicast = false; + dir = BT_AUDIO_DIR_SOURCE; named_preset = default_broadcast_source_preset; } else { @@ -1438,7 +1447,7 @@ static int cmd_preset(const struct shell *sh, size_t argc, char *argv[]) } if (argc > 2) { - named_preset = bap_get_named_preset(unicast, argv[2]); + named_preset = bap_get_named_preset(unicast, dir, argv[2]); if (named_preset == NULL) { shell_error(sh, "Unable to parse named_preset %s", argv[2]); return -ENOEXEC; @@ -2053,7 +2062,8 @@ static int cmd_create_broadcast(const struct shell *sh, size_t argc, i++; arg = argv[i]; - named_preset = bap_get_named_preset(false, arg); + named_preset = bap_get_named_preset(false, BT_AUDIO_DIR_SOURCE, + arg); if (named_preset == NULL) { shell_error(sh, "Unable to parse named_preset %s", arg); @@ -2932,6 +2942,10 @@ static ssize_t connectable_ad_data_add(struct bt_data *data_array, true); } + if (IS_ENABLED(CONFIG_BT_GMAP)) { + ad_len += gmap_ad_data_add(&data_array[ad_len], data_array_size - ad_len); + } + if (ARRAY_SIZE(ad_ext_uuid16) > 0) { size_t uuid16_size; diff --git a/subsys/bluetooth/audio/shell/cap_initiator.c b/subsys/bluetooth/audio/shell/cap_initiator.c index afdd686160c..0d002b30df3 100644 --- a/subsys/bluetooth/audio/shell/cap_initiator.c +++ b/subsys/bluetooth/audio/shell/cap_initiator.c @@ -689,7 +689,7 @@ int cap_ac_unicast(const struct shell *sh, size_t argc, char **argv, } if (snk_cnt > 0U) { - snk_named_preset = bap_get_named_preset(true, argv[1]); + snk_named_preset = bap_get_named_preset(true, BT_AUDIO_DIR_SINK, argv[1]); if (snk_named_preset == NULL) { shell_error(sh, "Unable to parse snk_named_preset %s", argv[1]); return -ENOEXEC; @@ -699,7 +699,7 @@ int cap_ac_unicast(const struct shell *sh, size_t argc, char **argv, if (src_cnt > 0U) { const char *preset_arg = argc > 2 ? argv[2] : argv[1]; - src_named_preset = bap_get_named_preset(true, preset_arg); + src_named_preset = bap_get_named_preset(true, BT_AUDIO_DIR_SOURCE, preset_arg); if (src_named_preset == NULL) { shell_error(sh, "Unable to parse src_named_preset %s", argv[1]); return -ENOEXEC; @@ -1030,7 +1030,7 @@ static int cmd_cap_ac_11_ii(const struct shell *sh, size_t argc, char **argv) #endif /* CONFIG_BT_BAP_UNICAST_CLIENT */ #if defined(CONFIG_BT_BAP_BROADCAST_SOURCE) -static int cap_ac_broadcast(const struct shell *sh, size_t argc, char **argv, +int cap_ac_broadcast(const struct shell *sh, size_t argc, char **argv, const struct bap_broadcast_ac_param *param) { /* TODO: Use CAP API when the CAP shell has broadcast support */ @@ -1059,7 +1059,7 @@ static int cap_ac_broadcast(const struct shell *sh, size_t argc, char **argv, return -ENOEXEC; } - named_preset = bap_get_named_preset(false, argv[1]); + named_preset = bap_get_named_preset(false, BT_AUDIO_DIR_SOURCE, argv[1]); if (named_preset == NULL) { shell_error(sh, "Unable to parse named_preset %s", argv[1]); return -ENOEXEC; @@ -1135,8 +1135,8 @@ static int cmd_cap_ac_14(const struct shell *sh, size_t argc, char **argv) { const struct bap_broadcast_ac_param param = { .name = "AC_13", - .stream_cnt = 1U, - .chan_cnt = 2U, + .stream_cnt = 2U, + .chan_cnt = 1U, }; return cap_ac_broadcast(sh, argc, argv, ¶m); diff --git a/subsys/bluetooth/audio/shell/gmap.c b/subsys/bluetooth/audio/shell/gmap.c new file mode 100644 index 00000000000..4096fb9be73 --- /dev/null +++ b/subsys/bluetooth/audio/shell/gmap.c @@ -0,0 +1,564 @@ +/** @file + * @brief Bluetooth Gaming Audio Profile shell + * + */ + +/* + * Copyright (c) 2023 Nordic Semiconductor ASA + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include + +#include +#include +#include +#include +#include +#include + +#include "shell/bt.h" +#include "audio.h" + +#define UNICAST_SINK_SUPPORTED (CONFIG_BT_BAP_UNICAST_CLIENT_ASE_SNK_COUNT > 0) +#define UNICAST_SRC_SUPPORTED (CONFIG_BT_BAP_UNICAST_CLIENT_ASE_SRC_COUNT > 0) + +#define GMAP_AC_MAX_CONN 2U +#define GMAP_AC_MAX_SRC (2U * GMAP_AC_MAX_CONN) + +static enum bt_gmap_role gmap_role; + +size_t gmap_ad_data_add(struct bt_data data[], size_t data_size) +{ + static uint8_t ad_gmap[3] = { + BT_UUID_16_ENCODE(BT_UUID_GMAS_VAL), + }; + + if (gmap_role == 0) { + /* Not initialized*/ + + return 0U; + } + + ad_gmap[2] = (uint8_t)gmap_role; + + __ASSERT(data > 0, "No space for ad_gmap"); + data[0].type = BT_DATA_SVC_DATA16; + data[0].data_len = ARRAY_SIZE(ad_gmap); + data[0].data = &ad_gmap[0]; + + return 1U; +} + +static void gmap_discover_cb(struct bt_conn *conn, int err, enum bt_gmap_role role, + struct bt_gmap_feat features) +{ + if (err != 0) { + shell_error(ctx_shell, "gmap discovery (err %d)", err); + return; + } + + shell_print(ctx_shell, + "gmap discovered for conn %p:\n\trole 0x%02x\n\tugg_feat 0x%02x\n\tugt_feat " + "0x%02x\n\tbgs_feat 0x%02x\n\tbgr_feat 0x%02x", + conn, role, features.ugg_feat, features.ugt_feat, features.bgs_feat, + features.bgr_feat); +} + +static const struct bt_gmap_cb gmap_cb = { + .discover = gmap_discover_cb, +}; + +static void set_gmap_features(struct bt_gmap_feat *features) +{ + memset(features, 0, sizeof(*features)); + + if (IS_ENABLED(CONFIG_BT_GMAP_UGG_SUPPORTED)) { +#if CONFIG_BT_BAP_UNICAST_CLIENT_ASE_SRC_COUNT > 0 + features->ugg_feat |= (BT_GMAP_UGG_FEAT_MULTIPLEX | BT_GMAP_UGG_FEAT_96KBPS_SOURCE); +#if CONFIG_BT_BAP_UNICAST_CLIENT_ASE_SRC_COUNT > 1 && \ + CONFIG_BT_BAP_UNICAST_CLIENT_GROUP_STREAM_COUNT > 1 + features->ugg_feat |= BT_GMAP_UGG_FEAT_MULTISINK; +#endif /* CONFIG_BT_BAP_UNICAST_CLIENT_ASE_SRC_COUNT > 1 && > 1 */ +#endif /* CONFIG_BT_BAP_UNICAST_CLIENT_ASE_SRC_COUNT > 0 */ + } + + if (IS_ENABLED(CONFIG_BT_GMAP_UGT_SUPPORTED)) { +#if CONFIG_BT_ASCS_ASE_SRC_COUNT > 0 + features->ugt_feat |= (BT_GMAP_UGT_FEAT_SOURCE | BT_GMAP_UGT_FEAT_80KBPS_SOURCE); +#if CONFIG_BT_ASCS_ASE_SRC_COUNT > 1 + features->ugt_feat |= BT_GMAP_UGT_FEAT_MULTISOURCE; +#endif /* CONFIG_BT_ASCS_ASE_SRC_COUNT > 1 */ +#endif /* CONFIG_BT_ASCS_ASE_SRC_COUNT > 0 */ +#if CONFIG_BT_ASCS_ASE_SNK_COUNT > 0 + features->ugt_feat |= (BT_GMAP_UGT_FEAT_SINK | BT_GMAP_UGT_FEAT_64KBPS_SINK); +#if CONFIG_BT_ASCS_ASE_SNK_COUNT > 1 + features->ugt_feat |= BT_GMAP_UGT_FEAT_MULTISINK; +#endif /* CONFIG_BT_ASCS_ASE_SNK_COUNT > 1 */ +#endif /* CONFIG_BT_ASCS_ASE_SNK_COUNT > 0 */ + } + + if (IS_ENABLED(CONFIG_BT_GMAP_BGS_SUPPORTED)) { + features->bgs_feat |= BT_GMAP_BGS_FEAT_96KBPS; + } + + if (IS_ENABLED(CONFIG_BT_GMAP_BGR_SUPPORTED)) { + features->bgr_feat |= BT_GMAP_BGR_FEAT_MULTISINK; +#if CONFIG_BT_BAP_BROADCAST_SNK_STREAM_COUNT > 1 + features->bgr_feat |= BT_GMAP_BGR_FEAT_MULTIPLEX; +#endif /* CONFIG_BT_BAP_BROADCAST_SNK_STREAM_COUNT > 1 */ + } +} + +static int cmd_gmap_init(const struct shell *sh, size_t argc, char **argv) +{ + struct bt_gmap_feat features; + int err; + + gmap_role = (IS_ENABLED(CONFIG_BT_GMAP_UGG_SUPPORTED) ? BT_GMAP_ROLE_UGG : 0U) | + (IS_ENABLED(CONFIG_BT_GMAP_UGT_SUPPORTED) ? BT_GMAP_ROLE_UGT : 0U) | + (IS_ENABLED(CONFIG_BT_GMAP_BGS_SUPPORTED) ? BT_GMAP_ROLE_BGS : 0U) | + (IS_ENABLED(CONFIG_BT_GMAP_BGR_SUPPORTED) ? BT_GMAP_ROLE_BGR : 0U); + + set_gmap_features(&features); + + err = bt_gmap_register(gmap_role, features); + if (err != 0) { + shell_error(sh, "Failed to register GMAS (err %d)", err); + + return -ENOEXEC; + } + + err = bt_gmap_cb_register(&gmap_cb); + if (err != 0) { + shell_error(sh, "Failed to register callbacks (err %d)", err); + + return -ENOEXEC; + } + + return 0; +} + +static int cmd_gmap_set_role(const struct shell *sh, size_t argc, char **argv) +{ + enum bt_gmap_role role = 0; + struct bt_gmap_feat features; + int err; + + for (size_t i = 1U; i < argc; i++) { + const char *arg = argv[i]; + + if (strcmp(arg, "ugg") == 0) { + role |= BT_GMAP_ROLE_UGG; + } else if (strcmp(arg, "ugt") == 0) { + role |= BT_GMAP_ROLE_UGT; + } else if (strcmp(arg, "bgs") == 0) { + role |= BT_GMAP_ROLE_BGS; + } else if (strcmp(arg, "bgr") == 0) { + role |= BT_GMAP_ROLE_BGR; + } else { + shell_error(sh, "Invalid arg: %s", arg); + shell_help(sh); + + return SHELL_CMD_HELP_PRINTED; + } + } + + set_gmap_features(&features); + + err = bt_gmap_set_role(role, features); + if (err != 0) { + shell_error(sh, "Failed to set new role (err %d)", err); + + return -ENOEXEC; + } + + gmap_role = role; + + return 0; +} + +static int cmd_gmap_discover(const struct shell *sh, size_t argc, char **argv) +{ + int err; + + if (default_conn == NULL) { + shell_error(sh, "Not connected"); + return -ENOEXEC; + } + + if (!ctx_shell) { + ctx_shell = sh; + } + + err = bt_gmap_discover(default_conn); + if (err != 0) { + shell_error(sh, "bt_gmap_discover (err %d)", err); + } + + return err; +} + +static struct named_lc3_preset gmap_unicast_snk_presets[] = { + {"32_1_gr", BT_GMAP_LC3_PRESET_32_1_GR(LOCATION, CONTEXT)}, + {"32_2_gr", BT_GMAP_LC3_PRESET_32_2_GR(LOCATION, CONTEXT)}, + {"48_1_gr", BT_GMAP_LC3_PRESET_48_1_GR(LOCATION, CONTEXT)}, + {"48_2_gr", BT_GMAP_LC3_PRESET_48_2_GR(LOCATION, CONTEXT)}, + {"48_3_gr", BT_GMAP_LC3_PRESET_48_3_GR(LOCATION, CONTEXT)}, + {"48_4_gr", BT_GMAP_LC3_PRESET_48_4_GR(LOCATION, CONTEXT)}, +}; + +static struct named_lc3_preset gmap_unicast_src_presets[] = { + {"16_1_gs", BT_GMAP_LC3_PRESET_16_1_GS(LOCATION, CONTEXT)}, + {"16_2_gs", BT_GMAP_LC3_PRESET_16_2_GS(LOCATION, CONTEXT)}, + {"32_1_gs", BT_GMAP_LC3_PRESET_32_1_GS(LOCATION, CONTEXT)}, + {"32_2_gs", BT_GMAP_LC3_PRESET_32_2_GS(LOCATION, CONTEXT)}, + {"48_1_gs", BT_GMAP_LC3_PRESET_48_1_GS(LOCATION, CONTEXT)}, + {"48_2_gs", BT_GMAP_LC3_PRESET_48_2_GS(LOCATION, CONTEXT)}, +}; + +static struct named_lc3_preset gmap_broadcast_presets[] = { + {"48_1_g", BT_GMAP_LC3_PRESET_48_1_G(LOCATION, CONTEXT)}, + {"48_2_g", BT_GMAP_LC3_PRESET_48_2_G(LOCATION, CONTEXT)}, + {"48_3_g", BT_GMAP_LC3_PRESET_48_3_G(LOCATION, CONTEXT)}, + {"48_4_g", BT_GMAP_LC3_PRESET_48_4_G(LOCATION, CONTEXT)}, +}; + +const struct named_lc3_preset *gmap_get_named_preset(bool is_unicast, enum bt_audio_dir dir, + const char *preset_arg) +{ + if (is_unicast) { + if (dir == BT_AUDIO_DIR_SINK) { + for (size_t i = 0U; i < ARRAY_SIZE(gmap_unicast_snk_presets); i++) { + if (!strcmp(preset_arg, gmap_unicast_snk_presets[i].name)) { + return &gmap_unicast_snk_presets[i]; + } + } + } else if (dir == BT_AUDIO_DIR_SOURCE) { + for (size_t i = 0U; i < ARRAY_SIZE(gmap_unicast_src_presets); i++) { + if (!strcmp(preset_arg, gmap_unicast_src_presets[i].name)) { + return &gmap_unicast_src_presets[i]; + } + } + } + } else { + for (size_t i = 0U; i < ARRAY_SIZE(gmap_broadcast_presets); i++) { + if (!strcmp(preset_arg, gmap_broadcast_presets[i].name)) { + return &gmap_broadcast_presets[i]; + } + } + } + + return NULL; +} + +#if defined(CONFIG_BT_GMAP_UGG_SUPPORTED) +#if UNICAST_SINK_SUPPORTED +static int cmd_gmap_ac_1(const struct shell *sh, size_t argc, char **argv) +{ + const struct bap_unicast_ac_param param = { + .name = "AC_1", + .conn_cnt = 1, + .snk_cnt = {1U}, + .src_cnt = {0U}, + .snk_chan_cnt = 1U, + .src_chan_cnt = 0U, + }; + + return cap_ac_unicast(sh, argc, argv, ¶m); +} +#endif /* UNICAST_SINK_SUPPORTED */ + +#if UNICAST_SRC_SUPPORTED +static int cmd_gmap_ac_2(const struct shell *sh, size_t argc, char **argv) +{ + const struct bap_unicast_ac_param param = { + .name = "AC_2", + .conn_cnt = 1, + .snk_cnt = {0U}, + .src_cnt = {1U}, + .snk_chan_cnt = 0U, + .src_chan_cnt = 1U, + }; + + return cap_ac_unicast(sh, argc, argv, ¶m); +} +#endif /* UNICAST_SRC_SUPPORTED */ + +#if UNICAST_SINK_SUPPORTED && UNICAST_SRC_SUPPORTED +static int cmd_gmap_ac_3(const struct shell *sh, size_t argc, char **argv) +{ + const struct bap_unicast_ac_param param = { + .name = "AC_3", + .conn_cnt = 1U, + .snk_cnt = {1U}, + .src_cnt = {1U}, + .snk_chan_cnt = 1U, + .src_chan_cnt = 1U, + }; + + return cap_ac_unicast(sh, argc, argv, ¶m); +} +#endif /* UNICAST_SINK_SUPPORTED && UNICAST_SRC_SUPPORTED */ + +#if UNICAST_SINK_SUPPORTED +static int cmd_gmap_ac_4(const struct shell *sh, size_t argc, char **argv) +{ + const struct bap_unicast_ac_param param = { + .name = "AC_4", + .conn_cnt = 1U, + .snk_cnt = {1U}, + .src_cnt = {0U}, + .snk_chan_cnt = 2U, + .src_chan_cnt = 0U, + }; + + return cap_ac_unicast(sh, argc, argv, ¶m); +} +#endif /* UNICAST_SINK_SUPPORTED */ + +#if UNICAST_SINK_SUPPORTED && UNICAST_SRC_SUPPORTED +static int cmd_gmap_ac_5(const struct shell *sh, size_t argc, char **argv) +{ + const struct bap_unicast_ac_param param = { + .name = "AC_5", + .conn_cnt = 1U, + .snk_cnt = {1U}, + .src_cnt = {1U}, + .snk_chan_cnt = 1U, + .src_chan_cnt = 1U, + }; + + return cap_ac_unicast(sh, argc, argv, ¶m); +} +#endif /* UNICAST_SINK_SUPPORTED && UNICAST_SRC_SUPPORTED */ + +#if UNICAST_SINK_SUPPORTED +#if CONFIG_BT_BAP_UNICAST_CLIENT_ASE_SNK_COUNT > 1 +static int cmd_gmap_ac_6_i(const struct shell *sh, size_t argc, char **argv) +{ + const struct bap_unicast_ac_param param = { + .name = "AC_6_I", + .conn_cnt = 1U, + .snk_cnt = {2U}, + .src_cnt = {0U}, + .snk_chan_cnt = 1U, + .src_chan_cnt = 0U, + }; + + return cap_ac_unicast(sh, argc, argv, ¶m); +} +#endif /* CONFIG_BT_BAP_UNICAST_CLIENT_ASE_SNK_COUNT > 1 */ + +#if CONFIG_BT_MAX_CONN >= 2 +static int cmd_gmap_ac_6_ii(const struct shell *sh, size_t argc, char **argv) +{ + const struct bap_unicast_ac_param param = { + .name = "AC_6_II", + .conn_cnt = 2, + .snk_cnt = {1U, 1U}, + .src_cnt = {0U, 0U}, + .snk_chan_cnt = 1U, + .src_chan_cnt = 0U, + }; + + return cap_ac_unicast(sh, argc, argv, ¶m); +} +#endif /* CONFIG_BT_MAX_CONN >= 2 */ +#endif /* UNICAST_SINK_SUPPORTED */ + +#if UNICAST_SINK_SUPPORTED && UNICAST_SRC_SUPPORTED +#if CONFIG_BT_MAX_CONN >= 2 +static int cmd_gmap_ac_7_ii(const struct shell *sh, size_t argc, char **argv) +{ + const struct bap_unicast_ac_param param = { + .name = "AC_7_II", + .conn_cnt = 2, + .snk_cnt = {1U, 0U}, + .src_cnt = {0U, 1U}, + .snk_chan_cnt = 1U, + .src_chan_cnt = 1U, + }; + + return cap_ac_unicast(sh, argc, argv, ¶m); +} +#endif /* CONFIG_BT_MAX_CONN >= 2 */ + +#if CONFIG_BT_BAP_UNICAST_CLIENT_ASE_SNK_COUNT > 1 +static int cmd_gmap_ac_8_i(const struct shell *sh, size_t argc, char **argv) +{ + const struct bap_unicast_ac_param param = { + .name = "AC_8_I", + .conn_cnt = 1U, + .snk_cnt = {2U}, + .src_cnt = {1U}, + .snk_chan_cnt = 1U, + .src_chan_cnt = 1U, + }; + + return cap_ac_unicast(sh, argc, argv, ¶m); +} +#endif /* CONFIG_BT_BAP_UNICAST_CLIENT_ASE_SNK_COUNT > 1 */ + +#if CONFIG_BT_MAX_CONN >= 2 +static int cmd_gmap_ac_8_ii(const struct shell *sh, size_t argc, char **argv) +{ + const struct bap_unicast_ac_param param = { + .name = "AC_8_II", + .conn_cnt = 2U, + .snk_cnt = {1U, 1U}, + .src_cnt = {1U, 0U}, + .snk_chan_cnt = 1U, + .src_chan_cnt = 1U, + }; + + return cap_ac_unicast(sh, argc, argv, ¶m); +} +#endif /* CONFIG_BT_MAX_CONN >= 2 */ + +#if CONFIG_BT_BAP_UNICAST_CLIENT_ASE_SNK_COUNT > 1 && CONFIG_BT_BAP_UNICAST_CLIENT_ASE_SRC_COUNT > 1 +static int cmd_gmap_ac_11_i(const struct shell *sh, size_t argc, char **argv) +{ + const struct bap_unicast_ac_param param = { + .name = "AC_11_I", + .conn_cnt = 1U, + .snk_cnt = {2U}, + .src_cnt = {2U}, + .snk_chan_cnt = 1U, + .src_chan_cnt = 1U, + }; + + return cap_ac_unicast(sh, argc, argv, ¶m); +} +#endif /* CONFIG_BT_BAP_UNICAST_CLIENT_ASE_SNK_COUNT > 1 && \ + * CONFIG_BT_BAP_UNICAST_CLIENT_ASE_SRC_COUNT > 1 \ + */ + +#if CONFIG_BT_MAX_CONN >= 2 +static int cmd_gmap_ac_11_ii(const struct shell *sh, size_t argc, char **argv) +{ + const struct bap_unicast_ac_param param = { + .name = "AC_11_II", + .conn_cnt = 2U, + .snk_cnt = {1U, 1U}, + .src_cnt = {1U, 1U}, + .snk_chan_cnt = 1U, + .src_chan_cnt = 1U, + }; + + return cap_ac_unicast(sh, argc, argv, ¶m); +} +#endif /* CONFIG_BT_MAX_CONN >= 2 */ +#endif /* UNICAST_SINK_SUPPORTED && UNICAST_SRC_SUPPORTED */ +#endif /* CONFIG_BT_GMAP_UGG_SUPPORTED */ + +#if defined(CONFIG_BT_GMAP_BGS_SUPPORTED) +static int cmd_gmap_ac_12(const struct shell *sh, size_t argc, char **argv) +{ + const struct bap_broadcast_ac_param param = { + .name = "AC_12", + .stream_cnt = 1U, + .chan_cnt = 1U, + }; + + return cap_ac_broadcast(sh, argc, argv, ¶m); +} + +#if CONFIG_BT_BAP_BROADCAST_SRC_STREAM_COUNT > 1 +static int cmd_gmap_ac_13(const struct shell *sh, size_t argc, char **argv) +{ + const struct bap_broadcast_ac_param param = { + .name = "AC_13", + .stream_cnt = 2U, + .chan_cnt = 1U, + }; + + return cap_ac_broadcast(sh, argc, argv, ¶m); +} +#endif /* CONFIG_BT_BAP_BROADCAST_SRC_STREAM_COUNT > 1 */ + +static int cmd_gmap_ac_14(const struct shell *sh, size_t argc, char **argv) +{ + const struct bap_broadcast_ac_param param = { + .name = "AC_14", + .stream_cnt = 1U, + .chan_cnt = 2U, + }; + + return cap_ac_broadcast(sh, argc, argv, ¶m); +} +#endif /* CONFIG_BT_GMAP_BGS_SUPPORTED */ + +static int cmd_gmap(const struct shell *sh, size_t argc, char **argv) +{ + if (argc > 1) { + shell_error(sh, "%s unknown parameter: %s", argv[0], argv[1]); + } else { + shell_error(sh, "%s missing subcomand", argv[0]); + } + + return -ENOEXEC; +} + +#define HELP_NONE "[none]" + +SHELL_STATIC_SUBCMD_SET_CREATE( + gmap_cmds, SHELL_CMD_ARG(init, NULL, HELP_NONE, cmd_gmap_init, 1, 0), + SHELL_CMD_ARG(set_role, NULL, "[ugt | ugg | bgr | bgs]", cmd_gmap_set_role, 2, 3), + SHELL_CMD_ARG(discover, NULL, HELP_NONE, cmd_gmap_discover, 1, 0), +#if defined(CONFIG_BT_GMAP_UGG_SUPPORTED) +#if UNICAST_SINK_SUPPORTED + SHELL_CMD_ARG(ac_1, NULL, "", cmd_gmap_ac_1, 2, 0), +#endif /* UNICAST_SINK_SUPPORTED */ +#if UNICAST_SRC_SUPPORTED + SHELL_CMD_ARG(ac_2, NULL, "", cmd_gmap_ac_2, 2, 0), +#endif /* UNICAST_SRC_SUPPORTED */ +#if UNICAST_SINK_SUPPORTED && UNICAST_SRC_SUPPORTED + SHELL_CMD_ARG(ac_3, NULL, " ", cmd_gmap_ac_3, 3, 0), +#endif /* UNICAST_SINK_SUPPORTED && UNICAST_SRC_SUPPORTED */ +#if UNICAST_SINK_SUPPORTED + SHELL_CMD_ARG(ac_4, NULL, "", cmd_gmap_ac_4, 2, 0), +#endif /* UNICAST_SINK_SUPPORTED */ +#if UNICAST_SINK_SUPPORTED && UNICAST_SRC_SUPPORTED + SHELL_CMD_ARG(ac_5, NULL, " ", cmd_gmap_ac_5, 3, 0), +#endif /* UNICAST_SINK_SUPPORTED && UNICAST_SRC_SUPPORTED */ +#if UNICAST_SINK_SUPPORTED +#if CONFIG_BT_BAP_UNICAST_CLIENT_ASE_SNK_COUNT > 1 + SHELL_CMD_ARG(ac_6_i, NULL, "", cmd_gmap_ac_6_i, 2, 0), +#endif /* CONFIG_BT_BAP_UNICAST_CLIENT_ASE_SNK_COUNT > 1 */ +#if CONFIG_BT_MAX_CONN >= 2 + SHELL_CMD_ARG(ac_6_ii, NULL, "", cmd_gmap_ac_6_ii, 2, 0), +#endif /* CONFIG_BT_MAX_CONN >= 2 */ +#endif /* UNICAST_SINK_SUPPORTED */ +#if UNICAST_SINK_SUPPORTED && UNICAST_SRC_SUPPORTED +#if CONFIG_BT_MAX_CONN >= 2 + SHELL_CMD_ARG(ac_7_ii, NULL, " ", cmd_gmap_ac_7_ii, 3, 0), +#endif /* CONFIG_BT_MAX_CONN >= 2 */ +#if CONFIG_BT_BAP_UNICAST_CLIENT_ASE_SNK_COUNT > 1 + SHELL_CMD_ARG(ac_8_i, NULL, " ", cmd_gmap_ac_8_i, 3, 0), +#endif /* CONFIG_BT_BAP_UNICAST_CLIENT_ASE_SNK_COUNT > 1 */ +#if CONFIG_BT_MAX_CONN >= 2 + SHELL_CMD_ARG(ac_8_ii, NULL, " ", cmd_gmap_ac_8_ii, 3, 0), +#endif /* CONFIG_BT_MAX_CONN >= 2 */ +#if CONFIG_BT_BAP_UNICAST_CLIENT_ASE_SNK_COUNT > 1 && CONFIG_BT_BAP_UNICAST_CLIENT_ASE_SRC_COUNT > 1 + SHELL_CMD_ARG(ac_11_i, NULL, " ", cmd_gmap_ac_11_i, 3, 0), +#endif /* CONFIG_BT_BAP_UNICAST_CLIENT_ASE_SNK_COUNT > 1 && \ + * CONFIG_BT_BAP_UNICAST_CLIENT_ASE_SRC_COUNT > 1 \ + */ +#if CONFIG_BT_MAX_CONN >= 2 + SHELL_CMD_ARG(ac_11_ii, NULL, " ", cmd_gmap_ac_11_ii, 3, 0), +#endif /* CONFIG_BT_MAX_CONN >= 2 */ +#endif /* UNICAST_SINK_SUPPORTED && UNICAST_SRC_SUPPORTED */ +#endif /* CONFIG_BT_GMAP_UGG_SUPPORTED */ + +#if defined(CONFIG_BT_GMAP_BGS_SUPPORTED) + SHELL_CMD_ARG(ac_12, NULL, "", cmd_gmap_ac_12, 2, 0), +#if CONFIG_BT_BAP_BROADCAST_SRC_STREAM_COUNT > 1 + SHELL_CMD_ARG(ac_13, NULL, "", cmd_gmap_ac_13, 2, 0), +#endif /* CONFIG_BT_BAP_BROADCAST_SRC_STREAM_COUNT > 1 */ + SHELL_CMD_ARG(ac_14, NULL, "", cmd_gmap_ac_14, 2, 0), +#endif /* CONFIG_BT_GMAP_BGS_SUPPORTED*/ + SHELL_SUBCMD_SET_END); + +SHELL_CMD_ARG_REGISTER(gmap, &gmap_cmds, "Bluetooth GMAP shell commands", cmd_gmap, 1, 1); diff --git a/subsys/bluetooth/shell/bt.c b/subsys/bluetooth/shell/bt.c index 1d4c61a84f7..79647ead4ef 100644 --- a/subsys/bluetooth/shell/bt.c +++ b/subsys/bluetooth/shell/bt.c @@ -694,6 +694,8 @@ static void connected(struct bt_conn *conn, uint8_t err) } } + default_conn = bt_conn_ref(conn); + done: /* clear connection reference for sec mode 3 pairing */ if (pairing_conn) { @@ -2843,8 +2845,10 @@ static int cmd_connect_le(const struct shell *sh, size_t argc, char *argv[]) BT_GAP_SCAN_FAST_INTERVAL, BT_GAP_SCAN_FAST_INTERVAL); - err = bt_conn_le_create(&addr, create_params, BT_LE_CONN_PARAM_DEFAULT, - &conn); + err = bt_conn_le_create( + &addr, create_params, + BT_LE_CONN_PARAM(BT_GAP_INIT_CONN_INT_MIN, BT_GAP_INIT_CONN_INT_MIN, 0, 400), + &conn); if (err) { shell_error(sh, "Connection failed (%d)", err); return -ENOEXEC; diff --git a/tests/bluetooth/shell/audio.conf b/tests/bluetooth/shell/audio.conf index 5e441ad7140..902fe3e833e 100644 --- a/tests/bluetooth/shell/audio.conf +++ b/tests/bluetooth/shell/audio.conf @@ -29,6 +29,10 @@ CONFIG_BT_MAX_CONN=3 CONFIG_BT_MAX_PAIRED=3 CONFIG_BT_KEYS_OVERWRITE_OLDEST=y +CONFIG_BT_L2CAP_TX_MTU=128 +CONFIG_BT_BUF_ACL_RX_SIZE=255 +CONFIG_BT_BUF_ACL_TX_SIZE=251 + CONFIG_BT_SETTINGS=y CONFIG_FLASH=y CONFIG_FLASH_MAP=y @@ -166,6 +170,9 @@ CONFIG_BT_PAC_SNK_NOTIFIABLE=y CONFIG_BT_PAC_SNK_LOC_WRITEABLE=y CONFIG_BT_PAC_SRC_LOC_WRITEABLE=y +# Gaming Audio Profile +CONFIG_BT_GMAP=y + # DEBUGGING CONFIG_LOG=y CONFIG_BT_AUDIO_LOG_LEVEL_DBG=y @@ -205,3 +212,4 @@ CONFIG_BT_CAP_INITIATOR_LOG_LEVEL_DBG=y CONFIG_BT_CAP_COMMANDER_LOG_LEVEL_DBG=y CONFIG_BT_CAP_COMMON_LOG_LEVEL_DBG=y CONFIG_BT_TMAP_LOG_LEVEL_DBG=y +CONFIG_BT_GMAP_LOG_LEVEL_DBG=y diff --git a/tests/bluetooth/shell/testcase.yaml b/tests/bluetooth/shell/testcase.yaml index b0c7dc15aad..0ea96cc1b05 100644 --- a/tests/bluetooth/shell/testcase.yaml +++ b/tests/bluetooth/shell/testcase.yaml @@ -303,3 +303,9 @@ tests: build_only: true extra_configs: - CONFIG_BT_CAP_INITIATOR=n + bluetooth.audio_shell.no_gmap: + extra_args: CONF_FILE="audio.conf" + build_only: true + platform_allow: native_posix + extra_configs: + - CONFIG_BT_GMAP=n From cdd4bc6a4806c2c532dfbf1525afc07783e3ebf1 Mon Sep 17 00:00:00 2001 From: Emil Gydesen Date: Thu, 24 Aug 2023 14:59:46 +0200 Subject: [PATCH 1021/3723] Bluetooth: GMAP: Add GMAP BSIM test Add BSIM testing of GMAP, with all spec-specified audio configuration combinations added and tested. Signed-off-by: Emil Gydesen --- tests/bsim/bluetooth/audio/prj.conf | 18 +- .../{bap_unicast_common.c => bap_common.c} | 14 +- tests/bsim/bluetooth/audio/src/bap_common.h | 97 ++ .../audio/src/bap_unicast_client_test.c | 2 +- .../bluetooth/audio/src/bap_unicast_common.h | 39 - .../audio/src/bap_unicast_server_test.c | 2 +- .../bluetooth/audio/src/cap_acceptor_test.c | 40 +- .../audio/src/cap_initiator_unicast_test.c | 26 +- tests/bsim/bluetooth/audio/src/common.c | 3 + tests/bsim/bluetooth/audio/src/common.h | 1 + .../bsim/bluetooth/audio/src/gmap_ugg_test.c | 1226 +++++++++++++++++ .../bsim/bluetooth/audio/src/gmap_ugt_test.c | 471 +++++++ tests/bsim/bluetooth/audio/src/main.c | 6 +- .../bluetooth/audio/test_scripts/_gmap.sh | 22 + .../audio/test_scripts/gmap_unicast_ac_1.sh | 40 + .../test_scripts/gmap_unicast_ac_11_i.sh | 48 + .../test_scripts/gmap_unicast_ac_11_ii.sh | 52 + .../audio/test_scripts/gmap_unicast_ac_2.sh | 41 + .../audio/test_scripts/gmap_unicast_ac_3.sh | 49 + .../audio/test_scripts/gmap_unicast_ac_4.sh | 40 + .../audio/test_scripts/gmap_unicast_ac_5.sh | 47 + .../audio/test_scripts/gmap_unicast_ac_6_i.sh | 40 + .../test_scripts/gmap_unicast_ac_6_ii.sh | 44 + .../test_scripts/gmap_unicast_ac_7_ii.sh | 52 + .../audio/test_scripts/gmap_unicast_ac_8_i.sh | 48 + .../test_scripts/gmap_unicast_ac_8_ii.sh | 52 + 26 files changed, 2408 insertions(+), 112 deletions(-) rename tests/bsim/bluetooth/audio/src/{bap_unicast_common.c => bap_common.c} (82%) create mode 100644 tests/bsim/bluetooth/audio/src/bap_common.h delete mode 100644 tests/bsim/bluetooth/audio/src/bap_unicast_common.h create mode 100644 tests/bsim/bluetooth/audio/src/gmap_ugg_test.c create mode 100644 tests/bsim/bluetooth/audio/src/gmap_ugt_test.c create mode 100755 tests/bsim/bluetooth/audio/test_scripts/_gmap.sh create mode 100755 tests/bsim/bluetooth/audio/test_scripts/gmap_unicast_ac_1.sh create mode 100755 tests/bsim/bluetooth/audio/test_scripts/gmap_unicast_ac_11_i.sh create mode 100755 tests/bsim/bluetooth/audio/test_scripts/gmap_unicast_ac_11_ii.sh create mode 100755 tests/bsim/bluetooth/audio/test_scripts/gmap_unicast_ac_2.sh create mode 100755 tests/bsim/bluetooth/audio/test_scripts/gmap_unicast_ac_3.sh create mode 100755 tests/bsim/bluetooth/audio/test_scripts/gmap_unicast_ac_4.sh create mode 100755 tests/bsim/bluetooth/audio/test_scripts/gmap_unicast_ac_5.sh create mode 100755 tests/bsim/bluetooth/audio/test_scripts/gmap_unicast_ac_6_i.sh create mode 100755 tests/bsim/bluetooth/audio/test_scripts/gmap_unicast_ac_6_ii.sh create mode 100755 tests/bsim/bluetooth/audio/test_scripts/gmap_unicast_ac_7_ii.sh create mode 100755 tests/bsim/bluetooth/audio/test_scripts/gmap_unicast_ac_8_i.sh create mode 100755 tests/bsim/bluetooth/audio/test_scripts/gmap_unicast_ac_8_ii.sh diff --git a/tests/bsim/bluetooth/audio/prj.conf b/tests/bsim/bluetooth/audio/prj.conf index 9d11e1c3dae..01e70dafdce 100644 --- a/tests/bsim/bluetooth/audio/prj.conf +++ b/tests/bsim/bluetooth/audio/prj.conf @@ -14,9 +14,9 @@ CONFIG_BT_MAX_PAIRED=3 CONFIG_BT_EXT_ADV_MAX_ADV_SET=3 CONFIG_BT_GATT_DYNAMIC_DB=y CONFIG_BT_SMP=y -CONFIG_BT_L2CAP_TX_MTU=100 -CONFIG_BT_BUF_ACL_TX_SIZE=104 -CONFIG_BT_BUF_ACL_RX_SIZE=104 +CONFIG_BT_L2CAP_TX_MTU=128 +CONFIG_BT_BUF_ACL_RX_SIZE=255 +CONFIG_BT_BUF_ACL_TX_SIZE=251 CONFIG_BT_AUDIO=y CONFIG_BT_BAP_UNICAST_SERVER=y @@ -145,6 +145,9 @@ CONFIG_BT_PAC_SRC_LOC_WRITEABLE=y CONFIG_BT_GATT_AUTO_DISCOVER_CCC=y CONFIG_BT_GATT_AUTO_RESUBSCRIBE=n +# Gaming Audio Profile +CONFIG_BT_GMAP=y + # DEBUGGING CONFIG_LOG=y CONFIG_LOG_FUNC_NAME_PREFIX_ERR=y @@ -183,20 +186,23 @@ CONFIG_BT_HAS_LOG_LEVEL_DBG=y CONFIG_BT_HAS_CLIENT_LOG_LEVEL_DBG=y CONFIG_BT_CAP_ACCEPTOR_LOG_LEVEL_DBG=y CONFIG_BT_CAP_INITIATOR_LOG_LEVEL_DBG=y +CONFIG_BT_GMAP_LOG_LEVEL_DBG=y # LOGGING CONFIG_LOG_MODE_IMMEDIATE=y -# Controller Broadcast ISO configs +# Controller Settings CONFIG_BT_CTLR_ADV_ISO=y CONFIG_BT_CTLR_SYNC_ISO=y CONFIG_BT_CTLR_SCAN_DATA_LEN_MAX=255 CONFIG_BT_CTLR_ISO_TX_BUFFER_SIZE=251 CONFIG_BT_CTLR_ADV_DATA_LEN_MAX=191 + +# Controller ISO Broadcast Settings CONFIG_BT_CTLR_ADV_ISO_STREAM_COUNT=1 CONFIG_BT_CTLR_SYNC_ISO_STREAM_MAX=1 -# Controller Connected ISO configs +# Controller ISO Unicast Settings CONFIG_BT_CTLR_CENTRAL_ISO=y CONFIG_BT_CTLR_PERIPHERAL_ISO=y CONFIG_BT_CTLR_ISOAL_SOURCES=2 @@ -214,3 +220,5 @@ CONFIG_BT_CTLR_SCAN_UNRESERVED=y CONFIG_BT_TICKER_NEXT_SLOT_GET_MATCH=y CONFIG_BT_TICKER_EXT=y CONFIG_BT_TICKER_EXT_SLOT_WINDOW_YIELD=y +CONFIG_BT_CTLR_CONN_ISO_STREAMS=2 +CONFIG_BT_CTLR_CONN_ISO_STREAMS_PER_GROUP=2 diff --git a/tests/bsim/bluetooth/audio/src/bap_unicast_common.c b/tests/bsim/bluetooth/audio/src/bap_common.c similarity index 82% rename from tests/bsim/bluetooth/audio/src/bap_unicast_common.c rename to tests/bsim/bluetooth/audio/src/bap_common.c index 4a828e2d6a2..503bf98c3ac 100644 --- a/tests/bsim/bluetooth/audio/src/bap_unicast_common.c +++ b/tests/bsim/bluetooth/audio/src/bap_common.c @@ -4,8 +4,10 @@ * SPDX-License-Identifier: Apache-2.0 */ +#include + #include "common.h" -#include "bap_unicast_common.h" +#include "bap_common.h" void print_hex(const uint8_t *ptr, size_t len) { @@ -79,6 +81,12 @@ void print_qos(const struct bt_audio_codec_qos *qos) { printk("QoS: interval %u framing 0x%02x phy 0x%02x sdu %u " "rtn %u latency %u pd %u\n", - qos->interval, qos->framing, qos->phy, qos->sdu, - qos->rtn, qos->latency, qos->pd); + qos->interval, qos->framing, qos->phy, qos->sdu, qos->rtn, qos->latency, qos->pd); +} + +void copy_unicast_stream_preset(struct unicast_stream *stream, + const struct named_lc3_preset *named_preset) +{ + memcpy(&stream->qos, &named_preset->preset.qos, sizeof(stream->qos)); + memcpy(&stream->codec_cfg, &named_preset->preset.codec_cfg, sizeof(stream->codec_cfg)); } diff --git a/tests/bsim/bluetooth/audio/src/bap_common.h b/tests/bsim/bluetooth/audio/src/bap_common.h new file mode 100644 index 00000000000..4bf98bf46da --- /dev/null +++ b/tests/bsim/bluetooth/audio/src/bap_common.h @@ -0,0 +1,97 @@ +/** + * Common functions and helpers for audio BSIM audio tests + * + * Copyright (c) 2021-2023 Nordic Semiconductor ASA + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#ifndef ZEPHYR_TEST_BSIM_BT_AUDIO_TEST_COMMON_ +#define ZEPHYR_TEST_BSIM_BT_AUDIO_TEST_COMMON_ + +#include +#include +#include +#include + +#define LONG_META 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, \ + 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, \ + 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, \ + 0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f, \ + 0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27, \ + 0x28, 0x29, 0x2a, 0x2b, 0x2c, 0x2d, 0x2e, 0x2f, \ + 0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, \ + 0x38, 0x39, 0x3a, 0x3b, 0x3c, 0x3d, 0x3e, 0x3f, \ + 0x40, 0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47, \ + 0x48, 0x49, 0x4a, 0x4b, 0x4c, 0x4d, 0x4e, 0x4f, \ + 0x50, 0x51, 0x52, 0x53, 0x54, 0x55, 0x56, 0x57, \ + 0x58, 0x59, 0x5a, 0x5b, 0x5c, 0x5d, 0x5e, 0x5f, \ + 0x60, 0x61, 0x62, 0x63, 0x64, 0x65, 0x66, 0x67, \ + 0x68, 0x69, 0x6a, 0x6b, 0x6c, 0x6d, 0x6e, 0x6f, \ + 0x70, 0x71, 0x72, 0x73, 0x74, 0x75, 0x76, 0x77, \ + 0x78, 0x79, 0x7a, 0x7b, 0x7c, 0x7d, 0x7e, 0x7f + +#define LONG_META_LEN (sizeof((uint8_t []){LONG_META}) + 1U) /* Size of data + type */ + +struct unicast_stream { + struct bt_cap_stream stream; + struct bt_audio_codec_cfg codec_cfg; + struct bt_audio_codec_qos qos; +}; + +struct named_lc3_preset { + const char *name; + struct bt_bap_lc3_preset preset; +}; + +void print_hex(const uint8_t *ptr, size_t len); +void print_codec_cap(const struct bt_audio_codec_cap *codec_cap); +void print_codec_cfg(const struct bt_audio_codec_cfg *codec_cfg); +void print_qos(const struct bt_audio_codec_qos *qos); +void copy_unicast_stream_preset(struct unicast_stream *stream, + const struct named_lc3_preset *named_preset); + +static inline bool valid_metadata_type(uint8_t type, uint8_t len) +{ + switch (type) { + case BT_AUDIO_METADATA_TYPE_PREF_CONTEXT: + case BT_AUDIO_METADATA_TYPE_STREAM_CONTEXT: + if (len != 2) { + return false; + } + + return true; + case BT_AUDIO_METADATA_TYPE_STREAM_LANG: + if (len != 3) { + return false; + } + + return true; + case BT_AUDIO_METADATA_TYPE_PARENTAL_RATING: + if (len != 1) { + return false; + } + + return true; + case BT_AUDIO_METADATA_TYPE_EXTENDED: /* 1 - 255 octets */ + case BT_AUDIO_METADATA_TYPE_VENDOR: /* 1 - 255 octets */ + if (len < 1) { + return false; + } + + return true; + case BT_AUDIO_METADATA_TYPE_CCID_LIST: /* 2 - 254 octets */ + if (len < 2) { + return false; + } + + return true; + case BT_AUDIO_METADATA_TYPE_PROGRAM_INFO: /* 0 - 255 octets */ + case BT_AUDIO_METADATA_TYPE_PROGRAM_INFO_URI: /* 0 - 255 octets */ + return true; + default: + return false; + } +} + +#endif /* ZEPHYR_TEST_BSIM_BT_AUDIO_TEST_COMMON_ */ diff --git a/tests/bsim/bluetooth/audio/src/bap_unicast_client_test.c b/tests/bsim/bluetooth/audio/src/bap_unicast_client_test.c index 96265267e80..6f2a4b3ab15 100644 --- a/tests/bsim/bluetooth/audio/src/bap_unicast_client_test.c +++ b/tests/bsim/bluetooth/audio/src/bap_unicast_client_test.c @@ -12,7 +12,7 @@ #include #include #include "common.h" -#include "bap_unicast_common.h" +#include "bap_common.h" #define BAP_STREAM_RETRY_WAIT K_MSEC(100) diff --git a/tests/bsim/bluetooth/audio/src/bap_unicast_common.h b/tests/bsim/bluetooth/audio/src/bap_unicast_common.h deleted file mode 100644 index c87e84ccbb9..00000000000 --- a/tests/bsim/bluetooth/audio/src/bap_unicast_common.h +++ /dev/null @@ -1,39 +0,0 @@ -/** - * Common functions and helpers for unicast audio BSIM audio tests - * - * Copyright (c) 2021-2023 Nordic Semiconductor ASA - * - * SPDX-License-Identifier: Apache-2.0 - */ - -#ifndef ZEPHYR_TEST_BSIM_BT_AUDIO_TEST_UNICAST_COMMON_ -#define ZEPHYR_TEST_BSIM_BT_AUDIO_TEST_UNICAST_COMMON_ - -#include -#include - -#define LONG_META 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, \ - 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, \ - 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, \ - 0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f, \ - 0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27, \ - 0x28, 0x29, 0x2a, 0x2b, 0x2c, 0x2d, 0x2e, 0x2f, \ - 0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, \ - 0x38, 0x39, 0x3a, 0x3b, 0x3c, 0x3d, 0x3e, 0x3f, \ - 0x40, 0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47, \ - 0x48, 0x49, 0x4a, 0x4b, 0x4c, 0x4d, 0x4e, 0x4f, \ - 0x50, 0x51, 0x52, 0x53, 0x54, 0x55, 0x56, 0x57, \ - 0x58, 0x59, 0x5a, 0x5b, 0x5c, 0x5d, 0x5e, 0x5f, \ - 0x60, 0x61, 0x62, 0x63, 0x64, 0x65, 0x66, 0x67, \ - 0x68, 0x69, 0x6a, 0x6b, 0x6c, 0x6d, 0x6e, 0x6f, \ - 0x70, 0x71, 0x72, 0x73, 0x74, 0x75, 0x76, 0x77, \ - 0x78, 0x79, 0x7a, 0x7b, 0x7c, 0x7d, 0x7e, 0x7f - -#define LONG_META_LEN (sizeof((uint8_t []){LONG_META}) + 1U) /* Size of data + type */ - -void print_hex(const uint8_t *ptr, size_t len); -void print_codec_cap(const struct bt_audio_codec_cap *codec_cap); -void print_codec_cfg(const struct bt_audio_codec_cfg *codec_cfg); -void print_qos(const struct bt_audio_codec_qos *qos); - -#endif /* ZEPHYR_TEST_BSIM_BT_AUDIO_TEST_UNICAST_COMMON_ */ diff --git a/tests/bsim/bluetooth/audio/src/bap_unicast_server_test.c b/tests/bsim/bluetooth/audio/src/bap_unicast_server_test.c index e9e43a8a14a..abe62c4dd52 100644 --- a/tests/bsim/bluetooth/audio/src/bap_unicast_server_test.c +++ b/tests/bsim/bluetooth/audio/src/bap_unicast_server_test.c @@ -11,7 +11,7 @@ #include #include #include "common.h" -#include "bap_unicast_common.h" +#include "bap_common.h" extern enum bst_result_t bst_result; diff --git a/tests/bsim/bluetooth/audio/src/cap_acceptor_test.c b/tests/bsim/bluetooth/audio/src/cap_acceptor_test.c index a24e8232b8f..92ba6677c76 100644 --- a/tests/bsim/bluetooth/audio/src/cap_acceptor_test.c +++ b/tests/bsim/bluetooth/audio/src/cap_acceptor_test.c @@ -12,7 +12,7 @@ #include #include #include "common.h" -#include "bap_unicast_common.h" +#include "bap_common.h" extern enum bst_result_t bst_result; @@ -62,44 +62,6 @@ static struct bt_cap_stream unicast_streams[CONFIG_BT_ASCS_ASE_SNK_COUNT + CREATE_FLAG(flag_unicast_stream_configured); -static bool valid_metadata_type(uint8_t type, uint8_t len) -{ - switch (type) { - case BT_AUDIO_METADATA_TYPE_PREF_CONTEXT: - case BT_AUDIO_METADATA_TYPE_STREAM_CONTEXT: - if (len != 2) { - return false; - } - - return true; - case BT_AUDIO_METADATA_TYPE_STREAM_LANG: - if (len != 3) { - return false; - } - - return true; - case BT_AUDIO_METADATA_TYPE_PARENTAL_RATING: - if (len != 1) { - return false; - } - - return true; - case BT_AUDIO_METADATA_TYPE_EXTENDED: /* 2 - 255 octets */ - case BT_AUDIO_METADATA_TYPE_VENDOR: /* 2 - 255 octets */ - if (len < 2) { - return false; - } - - return true; - case BT_AUDIO_METADATA_TYPE_CCID_LIST: - case BT_AUDIO_METADATA_TYPE_PROGRAM_INFO: /* 0 - 255 octets */ - case BT_AUDIO_METADATA_TYPE_PROGRAM_INFO_URI: /* 0 - 255 octets */ - return true; - default: - return false; - } -} - static bool subgroup_data_func_cb(struct bt_data *data, void *user_data) { bool *stream_context_found = (bool *)user_data; diff --git a/tests/bsim/bluetooth/audio/src/cap_initiator_unicast_test.c b/tests/bsim/bluetooth/audio/src/cap_initiator_unicast_test.c index 4f3671d3d13..b555af8b99b 100644 --- a/tests/bsim/bluetooth/audio/src/cap_initiator_unicast_test.c +++ b/tests/bsim/bluetooth/audio/src/cap_initiator_unicast_test.c @@ -13,7 +13,7 @@ #include #include #include "common.h" -#include "bap_unicast_common.h" +#include "bap_common.h" #define UNICAST_SINK_SUPPORTED (CONFIG_BT_BAP_UNICAST_CLIENT_ASE_SNK_COUNT > 0) #define UNICAST_SRC_SUPPORTED (CONFIG_BT_BAP_UNICAST_CLIENT_ASE_SRC_COUNT > 0) @@ -27,17 +27,6 @@ #define CONTEXT (BT_AUDIO_CONTEXT_TYPE_UNSPECIFIED) #define LOCATION (BT_AUDIO_LOCATION_FRONT_LEFT | BT_AUDIO_LOCATION_FRONT_RIGHT) -struct unicast_stream { - struct bt_cap_stream stream; - struct bt_audio_codec_cfg codec_cfg; - struct bt_audio_codec_qos qos; -}; - -struct named_lc3_preset { - const char *name; - struct bt_bap_lc3_preset preset; -}; - struct cap_initiator_ac_param { char *name; size_t conn_cnt; @@ -64,8 +53,8 @@ static struct bt_bap_ep static struct unicast_stream unicast_streams[CAP_AC_MAX_STREAM]; static struct bt_conn *connected_conns[CAP_AC_MAX_CONN]; static size_t connected_conn_cnt; -const struct named_lc3_preset *snk_named_preset; -const struct named_lc3_preset *src_named_preset; +static const struct named_lc3_preset *snk_named_preset; +static const struct named_lc3_preset *src_named_preset; CREATE_FLAG(flag_discovered); CREATE_FLAG(flag_codec_found); @@ -940,15 +929,6 @@ const struct named_lc3_preset *cap_get_named_preset(const char *preset_arg) return NULL; } -static inline void copy_unicast_stream_preset(struct unicast_stream *stream, - const struct named_lc3_preset *named_preset) -{ - printk("stream %p\n", stream); - printk("named_preset %p\n", named_preset); - memcpy(&stream->qos, &named_preset->preset.qos, sizeof(stream->qos)); - memcpy(&stream->codec_cfg, &named_preset->preset.codec_cfg, sizeof(stream->codec_cfg)); -} - static int cap_initiator_ac_create_unicast_group(const struct cap_initiator_ac_param *param, struct unicast_stream *snk_uni_streams[], size_t snk_cnt, diff --git a/tests/bsim/bluetooth/audio/src/common.c b/tests/bsim/bluetooth/audio/src/common.c index 3ad69daf9ae..1c74b2ae20a 100644 --- a/tests/bsim/bluetooth/audio/src/common.c +++ b/tests/bsim/bluetooth/audio/src/common.c @@ -15,6 +15,7 @@ extern enum bst_result_t bst_result; struct bt_conn *default_conn; atomic_t flag_connected; +atomic_t flag_disconnected; atomic_t flag_conn_updated; volatile bt_security_t security_level; @@ -100,6 +101,8 @@ void disconnected(struct bt_conn *conn, uint8_t reason) default_conn = NULL; UNSET_FLAG(flag_connected); UNSET_FLAG(flag_conn_updated); + SET_FLAG(flag_disconnected); + security_level = BT_SECURITY_L1; } diff --git a/tests/bsim/bluetooth/audio/src/common.h b/tests/bsim/bluetooth/audio/src/common.h index cc0b8d11a96..5df925412a3 100644 --- a/tests/bsim/bluetooth/audio/src/common.h +++ b/tests/bsim/bluetooth/audio/src/common.h @@ -91,6 +91,7 @@ extern struct bt_le_scan_cb common_scan_cb; extern const struct bt_data ad[AD_SIZE]; extern struct bt_conn *default_conn; extern atomic_t flag_connected; +extern atomic_t flag_disconnected; extern atomic_t flag_conn_updated; extern volatile bt_security_t security_level; diff --git a/tests/bsim/bluetooth/audio/src/gmap_ugg_test.c b/tests/bsim/bluetooth/audio/src/gmap_ugg_test.c new file mode 100644 index 00000000000..adfce597271 --- /dev/null +++ b/tests/bsim/bluetooth/audio/src/gmap_ugg_test.c @@ -0,0 +1,1226 @@ +/* + * Copyright (c) 2023 Nordic Semiconductor ASA + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#if defined(CONFIG_BT_GMAP) + +#include +#include +#include +#include +#include +#include +#include + +#include "common.h" +#include "bap_common.h" + +#define UNICAST_SINK_SUPPORTED (CONFIG_BT_BAP_UNICAST_CLIENT_ASE_SNK_COUNT > 0) +#define UNICAST_SRC_SUPPORTED (CONFIG_BT_BAP_UNICAST_CLIENT_ASE_SRC_COUNT > 0) + +#define CONTEXT (BT_AUDIO_CONTEXT_TYPE_UNSPECIFIED | BT_AUDIO_CONTEXT_TYPE_GAME) +#define LOCATION (BT_AUDIO_LOCATION_FRONT_LEFT | BT_AUDIO_LOCATION_FRONT_RIGHT) + +#define GMAP_AC_MAX_CONN 2U +#define GMAP_AC_MAX_SNK (2U * GMAP_AC_MAX_CONN) +#define GMAP_AC_MAX_SRC (2U * GMAP_AC_MAX_CONN) +#define GMAP_AC_MAX_PAIR MAX(GMAP_AC_MAX_SNK, GMAP_AC_MAX_SRC) +#define GMAP_AC_MAX_STREAM (GMAP_AC_MAX_SNK + GMAP_AC_MAX_SRC) + +#define MAX_CIS_COUNT 2U +#define ISO_ENQUEUE_COUNT 2U +#define TOTAL_BUF_NEEDED (ISO_ENQUEUE_COUNT * MAX_CIS_COUNT) + +BUILD_ASSERT(CONFIG_BT_ISO_TX_BUF_COUNT >= TOTAL_BUF_NEEDED, + "CONFIG_BT_ISO_TX_BUF_COUNT should be at least ISO_ENQUEUE_COUNT * MAX_CIS_COUNT"); + +NET_BUF_POOL_FIXED_DEFINE(tx_pool, TOTAL_BUF_NEEDED, BT_ISO_SDU_BUF_SIZE(CONFIG_BT_ISO_TX_MTU), + CONFIG_BT_CONN_TX_USER_DATA_SIZE, NULL); + +extern enum bst_result_t bst_result; +static const struct named_lc3_preset *snk_named_preset; +static const struct named_lc3_preset *src_named_preset; + +struct gmap_ac_param { + char *name; + size_t conn_cnt; + size_t snk_cnt[GMAP_AC_MAX_CONN]; + size_t src_cnt[GMAP_AC_MAX_CONN]; + size_t snk_chan_cnt; + const struct named_lc3_preset *snk_named_preset; + const struct named_lc3_preset *src_named_preset; +}; + +static struct named_lc3_preset gmap_unicast_snk_presets[] = { + {"32_1_gr", BT_GMAP_LC3_PRESET_32_1_GR(LOCATION, CONTEXT)}, + {"32_2_gr", BT_GMAP_LC3_PRESET_32_2_GR(LOCATION, CONTEXT)}, + {"48_1_gr", BT_GMAP_LC3_PRESET_48_1_GR(LOCATION, CONTEXT)}, + {"48_2_gr", BT_GMAP_LC3_PRESET_48_2_GR(LOCATION, CONTEXT)}, + {"48_3_gr", BT_GMAP_LC3_PRESET_48_3_GR(LOCATION, CONTEXT)}, + {"48_4_gr", BT_GMAP_LC3_PRESET_48_4_GR(LOCATION, CONTEXT)}, +}; + +static struct named_lc3_preset gmap_unicast_src_presets[] = { + {"16_1_gs", BT_GMAP_LC3_PRESET_16_1_GS(LOCATION, CONTEXT)}, + {"16_2_gs", BT_GMAP_LC3_PRESET_16_2_GS(LOCATION, CONTEXT)}, + {"32_1_gs", BT_GMAP_LC3_PRESET_32_1_GS(LOCATION, CONTEXT)}, + {"32_2_gs", BT_GMAP_LC3_PRESET_32_2_GS(LOCATION, CONTEXT)}, + {"48_1_gs", BT_GMAP_LC3_PRESET_48_1_GS(LOCATION, CONTEXT)}, + {"48_2_gs", BT_GMAP_LC3_PRESET_48_2_GS(LOCATION, CONTEXT)}, +}; + +static struct named_lc3_preset gmap_broadcast_presets[] = { + {"48_1_g", BT_GMAP_LC3_PRESET_48_1_G(LOCATION, CONTEXT)}, + {"48_2_g", BT_GMAP_LC3_PRESET_48_2_G(LOCATION, CONTEXT)}, + {"48_3_g", BT_GMAP_LC3_PRESET_48_3_G(LOCATION, CONTEXT)}, + {"48_4_g", BT_GMAP_LC3_PRESET_48_4_G(LOCATION, CONTEXT)}, +}; + +struct named_lc3_preset named_preset; + +static struct unicast_stream unicast_streams[GMAP_AC_MAX_STREAM]; +static struct bt_bap_ep *sink_eps[GMAP_AC_MAX_CONN][CONFIG_BT_BAP_UNICAST_CLIENT_ASE_SNK_COUNT]; +static struct bt_bap_ep *source_eps[GMAP_AC_MAX_CONN][CONFIG_BT_BAP_UNICAST_CLIENT_ASE_SRC_COUNT]; +static struct bt_conn *connected_conns[GMAP_AC_MAX_CONN]; +static size_t connected_conn_cnt; + +static K_SEM_DEFINE(sem_stream_started, 0U, ARRAY_SIZE(unicast_streams)); +static K_SEM_DEFINE(sem_stream_stopped, 0U, ARRAY_SIZE(unicast_streams)); + +CREATE_FLAG(flag_cas_discovered); +CREATE_FLAG(flag_started); +CREATE_FLAG(flag_updated); +CREATE_FLAG(flag_stopped); +CREATE_FLAG(flag_mtu_exchanged); +CREATE_FLAG(flag_sink_discovered); +CREATE_FLAG(flag_source_discovered); +CREATE_FLAG(flag_stream_stopping); +CREATE_FLAG(flag_gmap_discovered); + +const struct named_lc3_preset *gmap_get_named_preset(bool is_unicast, enum bt_audio_dir dir, + const char *preset_arg) +{ + if (is_unicast) { + if (dir == BT_AUDIO_DIR_SINK) { + for (size_t i = 0U; i < ARRAY_SIZE(gmap_unicast_snk_presets); i++) { + if (!strcmp(preset_arg, gmap_unicast_snk_presets[i].name)) { + return &gmap_unicast_snk_presets[i]; + } + } + } else if (dir == BT_AUDIO_DIR_SOURCE) { + for (size_t i = 0U; i < ARRAY_SIZE(gmap_unicast_src_presets); i++) { + if (!strcmp(preset_arg, gmap_unicast_src_presets[i].name)) { + return &gmap_unicast_src_presets[i]; + } + } + } + } else { + + for (size_t i = 0U; i < ARRAY_SIZE(gmap_broadcast_presets); i++) { + if (!strcmp(preset_arg, gmap_broadcast_presets[i].name)) { + return &gmap_broadcast_presets[i]; + } + } + } + + return NULL; +} + +static void stream_sent_cb(struct bt_bap_stream *stream) +{ + static uint8_t mock_data[CONFIG_BT_ISO_TX_MTU]; + static bool mock_data_initialized; + static uint32_t seq_num; + struct net_buf *buf; + int ret; + + if (named_preset.preset.qos.sdu > CONFIG_BT_ISO_TX_MTU) { + FAIL("Invalid SDU %u for the MTU: %d\n", named_preset.preset.qos.sdu, + CONFIG_BT_ISO_TX_MTU); + return; + } + + if (TEST_FLAG(flag_stream_stopping)) { + return; + } + + if (!mock_data_initialized) { + for (size_t i = 0U; i < ARRAY_SIZE(mock_data); i++) { + /* Initialize mock data */ + mock_data[i] = (uint8_t)i; + } + mock_data_initialized = true; + } + + buf = net_buf_alloc(&tx_pool, K_FOREVER); + if (buf == NULL) { + printk("Could not allocate buffer when sending on %p\n", stream); + return; + } + + net_buf_reserve(buf, BT_ISO_CHAN_SEND_RESERVE); + net_buf_add_mem(buf, mock_data, named_preset.preset.qos.sdu); + ret = bt_bap_stream_send(stream, buf, seq_num++, BT_ISO_TIMESTAMP_NONE); + if (ret < 0) { + /* This will end send on this stream. */ + printk("Unable to send data on %p: %d\n", stream, ret); + net_buf_unref(buf); + return; + } +} + +static void stream_configured_cb(struct bt_bap_stream *stream, + const struct bt_audio_codec_qos_pref *pref) +{ + printk("Configured stream %p\n", stream); + + /* TODO: The preference should be used/taken into account when + * setting the QoS + */ +} + +static void stream_qos_set_cb(struct bt_bap_stream *stream) +{ + printk("QoS set stream %p\n", stream); +} + +static void stream_enabled_cb(struct bt_bap_stream *stream) +{ + printk("Enabled stream %p\n", stream); +} + +static void stream_started_cb(struct bt_bap_stream *stream) +{ + printk("Started stream %p\n", stream); + k_sem_give(&sem_stream_started); +} + +static void stream_metadata_updated_cb(struct bt_bap_stream *stream) +{ + printk("Metadata updated stream %p\n", stream); +} + +static void stream_disabled_cb(struct bt_bap_stream *stream) +{ + printk("Disabled stream %p\n", stream); +} + +static void stream_stopped_cb(struct bt_bap_stream *stream, uint8_t reason) +{ + printk("Stream %p stopped with reason 0x%02X\n", stream, reason); + k_sem_give(&sem_stream_stopped); +} + +static void stream_released_cb(struct bt_bap_stream *stream) +{ + printk("Released stream %p\n", stream); +} + +static struct bt_bap_stream_ops stream_ops = { + .configured = stream_configured_cb, + .qos_set = stream_qos_set_cb, + .enabled = stream_enabled_cb, + .started = stream_started_cb, + .metadata_updated = stream_metadata_updated_cb, + .disabled = stream_disabled_cb, + .stopped = stream_stopped_cb, + .released = stream_released_cb, + .sent = stream_sent_cb, +}; + +static void cap_discovery_complete_cb(struct bt_conn *conn, int err, + const struct bt_csip_set_coordinator_csis_inst *csis_inst) +{ + if (err != 0) { + FAIL("Failed to discover CAS: %d\n", err); + + return; + } + + if (IS_ENABLED(CONFIG_BT_CAP_ACCEPTOR_SET_MEMBER)) { + if (csis_inst == NULL) { + FAIL("Failed to discover CAS CSIS\n"); + + return; + } + + printk("Found CAS with CSIS %p\n", csis_inst); + } else { + printk("Found CAS\n"); + } + + SET_FLAG(flag_cas_discovered); +} + +static void unicast_start_complete_cb(struct bt_bap_unicast_group *unicast_group, int err, + struct bt_conn *conn) +{ + if (err != 0) { + FAIL("Failed to start (failing conn %p): %d\n", conn, err); + + return; + } + + SET_FLAG(flag_started); +} + +static void unicast_update_complete_cb(int err, struct bt_conn *conn) +{ + if (err != 0) { + FAIL("Failed to update (failing conn %p): %d\n", conn, err); + + return; + } + + SET_FLAG(flag_updated); +} + +static void unicast_stop_complete_cb(struct bt_bap_unicast_group *unicast_group, int err, + struct bt_conn *conn) +{ + if (err != 0) { + FAIL("Failed to stop (failing conn %p): %d\n", conn, err); + + return; + } + + SET_FLAG(flag_stopped); +} + +static struct bt_cap_initiator_cb cap_cb = { + .unicast_discovery_complete = cap_discovery_complete_cb, + .unicast_start_complete = unicast_start_complete_cb, + .unicast_update_complete = unicast_update_complete_cb, + .unicast_stop_complete = unicast_stop_complete_cb, +}; + +static void add_remote_sink_ep(struct bt_conn *conn, struct bt_bap_ep *ep) +{ + for (size_t i = 0U; i < ARRAY_SIZE(sink_eps[bt_conn_index(conn)]); i++) { + if (sink_eps[bt_conn_index(conn)][i] == NULL) { + printk("Conn %p: Sink #%zu: ep %p\n", conn, i, ep); + sink_eps[bt_conn_index(conn)][i] = ep; + break; + } + } +} + +static void add_remote_source_ep(struct bt_conn *conn, struct bt_bap_ep *ep) +{ + for (size_t i = 0U; i < ARRAY_SIZE(source_eps[bt_conn_index(conn)]); i++) { + if (source_eps[bt_conn_index(conn)][i] == NULL) { + printk("Conn %p: Source #%zu: ep %p\n", conn, i, ep); + source_eps[bt_conn_index(conn)][i] = ep; + break; + } + } +} + +static void bap_pac_record_cb(struct bt_conn *conn, enum bt_audio_dir dir, + const struct bt_audio_codec_cap *codec_cap) +{ + printk("conn %p codec_cap %p dir 0x%02x\n", conn, codec_cap, dir); + + print_codec_cap(codec_cap); +} + +static void bap_endpoint_cb(struct bt_conn *conn, enum bt_audio_dir dir, struct bt_bap_ep *ep) +{ + if (dir == BT_AUDIO_DIR_SINK) { + add_remote_sink_ep(conn, ep); + } else if (dir == BT_AUDIO_DIR_SOURCE) { + add_remote_source_ep(conn, ep); + } +} + +static void bap_discover_cb(struct bt_conn *conn, int err, enum bt_audio_dir dir) +{ + if (err != 0) { + FAIL("Discovery failed for dir %u: %d\n", dir, err); + return; + } + + if (dir == BT_AUDIO_DIR_SINK) { + printk("Sink discover complete\n"); + SET_FLAG(flag_sink_discovered); + } else if (dir == BT_AUDIO_DIR_SOURCE) { + printk("Source discover complete\n"); + SET_FLAG(flag_source_discovered); + } +} + +static struct bt_bap_unicast_client_cb unicast_client_cbs = { + .pac_record = bap_pac_record_cb, + .endpoint = bap_endpoint_cb, + .discover = bap_discover_cb, +}; + +static void att_mtu_updated(struct bt_conn *conn, uint16_t tx, uint16_t rx) +{ + printk("MTU exchanged\n"); + SET_FLAG(flag_mtu_exchanged); +} + +static struct bt_gatt_cb gatt_callbacks = { + .att_mtu_updated = att_mtu_updated, +}; + +static void gmap_discover_cb(struct bt_conn *conn, int err, enum bt_gmap_role role, + struct bt_gmap_feat features) +{ + enum bt_gmap_ugt_feat ugt_feat; + + if (err != 0) { + FAIL("gmap discovery (err %d)\n", err); + return; + } + + printk("GMAP discovered for conn %p:\n\trole 0x%02x\n\tugg_feat 0x%02x\n\tugt_feat " + "0x%02x\n\tbgs_feat 0x%02x\n\tbgr_feat 0x%02x\n", + conn, role, features.ugg_feat, features.ugt_feat, features.bgs_feat, + features.bgr_feat); + + if ((role & BT_GMAP_ROLE_UGT) == 0) { + FAIL("Remote GMAP device is not a UGT\n"); + return; + } + + ugt_feat = features.ugt_feat; + if ((ugt_feat & BT_GMAP_UGT_FEAT_SOURCE) == 0 || + (ugt_feat & BT_GMAP_UGT_FEAT_80KBPS_SOURCE) == 0 || + (ugt_feat & BT_GMAP_UGT_FEAT_SINK) == 0 || + (ugt_feat & BT_GMAP_UGT_FEAT_64KBPS_SINK) == 0 || + (ugt_feat & BT_GMAP_UGT_FEAT_MULTIPLEX) == 0 || + (ugt_feat & BT_GMAP_UGT_FEAT_MULTISINK) == 0 || + (ugt_feat & BT_GMAP_UGT_FEAT_MULTISOURCE) == 0) { + FAIL("Remote GMAP device does not have expected UGT features: %d\n", ugt_feat); + return; + } + + SET_FLAG(flag_gmap_discovered); +} + +static const struct bt_gmap_cb gmap_cb = { + .discover = gmap_discover_cb, +}; + +static void init(void) +{ + const struct bt_gmap_feat features = { + .ugg_feat = (BT_GMAP_UGG_FEAT_MULTIPLEX | BT_GMAP_UGG_FEAT_96KBPS_SOURCE | + BT_GMAP_UGG_FEAT_MULTISINK), + }; + const enum bt_gmap_role role = BT_GMAP_ROLE_UGG; + int err; + + err = bt_enable(NULL); + if (err != 0) { + FAIL("Bluetooth enable failed (err %d)\n", err); + return; + } + + bt_gatt_cb_register(&gatt_callbacks); + + err = bt_bap_unicast_client_register_cb(&unicast_client_cbs); + if (err != 0) { + FAIL("Failed to register BAP callbacks (err %d)\n", err); + return; + } + + err = bt_cap_initiator_register_cb(&cap_cb); + if (err != 0) { + FAIL("Failed to register CAP callbacks (err %d)\n", err); + return; + } + + for (size_t i = 0; i < ARRAY_SIZE(unicast_streams); i++) { + bt_cap_stream_ops_register(&unicast_streams[i].stream, &stream_ops); + } + + err = bt_gmap_register(role, features); + if (err != 0) { + FAIL("Failed to register GMAS (err %d)\n", err); + + return; + } + + err = bt_gmap_cb_register(&gmap_cb); + if (err != 0) { + FAIL("Failed to register callbacks (err %d)\n", err); + + return; + } +} + +static void gmap_device_found(const bt_addr_le_t *addr, int8_t rssi, uint8_t type, + struct net_buf_simple *ad) +{ + char addr_str[BT_ADDR_LE_STR_LEN]; + struct bt_conn *conn; + int err; + + /* We're only interested in connectable events */ + if (type != BT_HCI_ADV_IND && type != BT_HCI_ADV_DIRECT_IND) { + return; + } + + conn = bt_conn_lookup_addr_le(BT_ID_DEFAULT, addr); + if (conn != NULL) { + /* Already connected to this device */ + bt_conn_unref(conn); + return; + } + + bt_addr_le_to_str(addr, addr_str, sizeof(addr_str)); + printk("Device found: %s (RSSI %d)\n", addr_str, rssi); + + /* connect only to devices in close proximity */ + if (rssi < -70) { + FAIL("RSSI too low"); + return; + } + + printk("Stopping scan\n"); + if (bt_le_scan_stop()) { + FAIL("Could not stop scan"); + return; + } + + err = bt_conn_le_create( + addr, BT_CONN_LE_CREATE_CONN, + BT_LE_CONN_PARAM(BT_GAP_INIT_CONN_INT_MIN, BT_GAP_INIT_CONN_INT_MIN, 0, 400), + &connected_conns[connected_conn_cnt]); + if (err) { + FAIL("Could not connect to peer: %d", err); + } +} + +static void scan_and_connect(void) +{ + int err; + + UNSET_FLAG(flag_connected); + + err = bt_le_scan_start(BT_LE_SCAN_PASSIVE, gmap_device_found); + if (err != 0) { + FAIL("Scanning failed to start (err %d)\n", err); + return; + } + + printk("Scanning successfully started\n"); + WAIT_FOR_FLAG(flag_connected); + connected_conn_cnt++; +} + +static void discover_sink(struct bt_conn *conn) +{ + int err; + + UNSET_FLAG(flag_sink_discovered); + + err = bt_bap_unicast_client_discover(conn, BT_AUDIO_DIR_SINK); + if (err != 0) { + printk("Failed to discover sink: %d\n", err); + return; + } + + WAIT_FOR_FLAG(flag_sink_discovered); +} + +static void discover_source(struct bt_conn *conn) +{ + int err; + + UNSET_FLAG(flag_source_discovered); + + err = bt_bap_unicast_client_discover(conn, BT_AUDIO_DIR_SOURCE); + if (err != 0) { + printk("Failed to discover source: %d\n", err); + return; + } + + WAIT_FOR_FLAG(flag_source_discovered); +} + +static void discover_gmas(struct bt_conn *conn) +{ + int err; + + UNSET_FLAG(flag_gmap_discovered); + + err = bt_gmap_discover(conn); + if (err != 0) { + printk("Failed to discover GMAS: %d\n", err); + return; + } + + WAIT_FOR_FLAG(flag_gmap_discovered); +} + +static void discover_cas(struct bt_conn *conn) +{ + int err; + + UNSET_FLAG(flag_cas_discovered); + + err = bt_cap_initiator_unicast_discover(conn); + if (err != 0) { + printk("Failed to discover CAS: %d\n", err); + return; + } + + WAIT_FOR_FLAG(flag_cas_discovered); +} + +static int gmap_ac_create_unicast_group(const struct gmap_ac_param *param, + struct unicast_stream *snk_uni_streams[], size_t snk_cnt, + struct unicast_stream *src_uni_streams[], size_t src_cnt, + struct bt_bap_unicast_group **unicast_group) +{ + struct bt_bap_unicast_group_stream_param snk_group_stream_params[GMAP_AC_MAX_SNK] = {0}; + struct bt_bap_unicast_group_stream_param src_group_stream_params[GMAP_AC_MAX_SRC] = {0}; + struct bt_bap_unicast_group_stream_pair_param pair_params[GMAP_AC_MAX_PAIR] = {0}; + struct bt_bap_unicast_group_param group_param = {0}; + size_t snk_stream_cnt = 0U; + size_t src_stream_cnt = 0U; + size_t pair_cnt = 0U; + + /* Create Group + * + * First setup the individual stream parameters and then match them in pairs by connection + * and direction + */ + for (size_t i = 0U; i < snk_cnt; i++) { + snk_group_stream_params[i].qos = &snk_uni_streams[i]->qos; + snk_group_stream_params[i].stream = &snk_uni_streams[i]->stream.bap_stream; + } + for (size_t i = 0U; i < src_cnt; i++) { + src_group_stream_params[i].qos = &src_uni_streams[i]->qos; + src_group_stream_params[i].stream = &src_uni_streams[i]->stream.bap_stream; + } + + for (size_t i = 0U; i < param->conn_cnt; i++) { + for (size_t j = 0; j < MAX(param->snk_cnt[i], param->src_cnt[i]); j++) { + if (param->snk_cnt[i] > j) { + pair_params[pair_cnt].tx_param = + &snk_group_stream_params[snk_stream_cnt++]; + } else { + pair_params[pair_cnt].tx_param = NULL; + } + + if (param->src_cnt[i] > j) { + pair_params[pair_cnt].rx_param = + &src_group_stream_params[src_stream_cnt++]; + } else { + pair_params[pair_cnt].rx_param = NULL; + } + + pair_cnt++; + } + } + + group_param.packing = BT_ISO_PACKING_SEQUENTIAL; + group_param.params = pair_params; + group_param.params_count = pair_cnt; + + return bt_bap_unicast_group_create(&group_param, unicast_group); +} + +static int gmap_ac_cap_unicast_start(const struct gmap_ac_param *param, + struct unicast_stream *snk_uni_streams[], size_t snk_cnt, + struct unicast_stream *src_uni_streams[], size_t src_cnt, + struct bt_bap_unicast_group *unicast_group) +{ + struct bt_cap_unicast_audio_start_stream_param stream_params[GMAP_AC_MAX_STREAM] = {0}; + struct bt_audio_codec_cfg *snk_codec_cfgs[GMAP_AC_MAX_SNK] = {0}; + struct bt_audio_codec_cfg *src_codec_cfgs[GMAP_AC_MAX_SRC] = {0}; + struct bt_cap_stream *snk_cap_streams[GMAP_AC_MAX_SNK] = {0}; + struct bt_cap_stream *src_cap_streams[GMAP_AC_MAX_SRC] = {0}; + struct bt_cap_unicast_audio_start_param start_param = {0}; + struct bt_bap_ep *snk_eps[GMAP_AC_MAX_SNK] = {0}; + struct bt_bap_ep *src_eps[GMAP_AC_MAX_SRC] = {0}; + size_t snk_stream_cnt = 0U; + size_t src_stream_cnt = 0U; + size_t stream_cnt = 0U; + size_t snk_ep_cnt = 0U; + size_t src_ep_cnt = 0U; + + for (size_t i = 0U; i < param->conn_cnt; i++) { +#if UNICAST_SINK_SUPPORTED + for (size_t j = 0U; j < param->snk_cnt[i]; j++) { + snk_eps[snk_ep_cnt] = sink_eps[bt_conn_index(connected_conns[i])][j]; + if (snk_eps[snk_ep_cnt] == NULL) { + FAIL("No sink[%zu][%zu] endpoint available\n", i, j); + + return -ENODEV; + } + snk_ep_cnt++; + } +#endif /* UNICAST_SINK_SUPPORTED */ + +#if UNICAST_SRC_SUPPORTED + for (size_t j = 0U; j < param->src_cnt[i]; j++) { + src_eps[src_ep_cnt] = source_eps[bt_conn_index(connected_conns[i])][j]; + if (src_eps[src_ep_cnt] == NULL) { + FAIL("No source[%zu][%zu] endpoint available\n", i, j); + + return -ENODEV; + } + src_ep_cnt++; + } +#endif /* UNICAST_SRC_SUPPORTED > 0 */ + } + + if (snk_ep_cnt != snk_cnt) { + FAIL("Sink endpoint and stream count mismatch: %zu != %zu\n", snk_ep_cnt, snk_cnt); + + return -EINVAL; + } + + if (src_ep_cnt != src_cnt) { + FAIL("Source endpoint and stream count mismatch: %zu != %zu\n", src_ep_cnt, + src_cnt); + + return -EINVAL; + } + + /* Setup arrays of parameters based on the preset for easier access. This also copies the + * preset so that we can modify them (e.g. update the metadata) + */ + for (size_t i = 0U; i < snk_cnt; i++) { + snk_cap_streams[i] = &snk_uni_streams[i]->stream; + snk_codec_cfgs[i] = &snk_uni_streams[i]->codec_cfg; + } + + for (size_t i = 0U; i < src_cnt; i++) { + src_cap_streams[i] = &src_uni_streams[i]->stream; + src_codec_cfgs[i] = &src_uni_streams[i]->codec_cfg; + } + + /* CAP Start */ + for (size_t i = 0U; i < param->conn_cnt; i++) { + for (size_t j = 0U; j < param->snk_cnt[i]; j++) { + struct bt_cap_unicast_audio_start_stream_param *stream_param = + &stream_params[stream_cnt]; + + stream_param->member.member = connected_conns[i]; + stream_param->codec_cfg = snk_codec_cfgs[snk_stream_cnt]; + stream_param->ep = snk_eps[snk_stream_cnt]; + stream_param->stream = snk_cap_streams[snk_stream_cnt]; + + snk_stream_cnt++; + stream_cnt++; + + if (param->conn_cnt > 1) { + bt_audio_codec_cfg_set_chan_allocation( + stream_param->codec_cfg, (enum bt_audio_location)BIT(i)); + } + } + + for (size_t j = 0U; j < param->src_cnt[i]; j++) { + struct bt_cap_unicast_audio_start_stream_param *stream_param = + &stream_params[stream_cnt]; + + stream_param->member.member = connected_conns[i]; + stream_param->codec_cfg = src_codec_cfgs[src_stream_cnt]; + stream_param->ep = src_eps[src_stream_cnt]; + stream_param->stream = src_cap_streams[src_stream_cnt]; + + src_stream_cnt++; + stream_cnt++; + + if (param->conn_cnt > 1) { + bt_audio_codec_cfg_set_chan_allocation( + stream_param->codec_cfg, (enum bt_audio_location)BIT(i)); + } + } + } + + start_param.stream_params = stream_params; + start_param.count = stream_cnt; + start_param.type = BT_CAP_SET_TYPE_AD_HOC; + + return bt_cap_initiator_unicast_audio_start(&start_param, unicast_group); +} + +static int gmap_ac_unicast(const struct gmap_ac_param *param, + struct bt_bap_unicast_group **unicast_group) +{ + /* Allocate params large enough for any params, but only use what is required */ + struct unicast_stream *snk_uni_streams[GMAP_AC_MAX_SNK]; + struct unicast_stream *src_uni_streams[GMAP_AC_MAX_SRC]; + size_t snk_cnt = 0; + size_t src_cnt = 0; + int err; + + if (param->conn_cnt > GMAP_AC_MAX_CONN) { + FAIL("Invalid conn_cnt: %zu\n", param->conn_cnt); + + return -EINVAL; + } + + for (size_t i = 0; i < param->conn_cnt; i++) { + /* Verify conn values */ + if (param->snk_cnt[i] > GMAP_AC_MAX_SNK) { + FAIL("Invalid conn_snk_cnt[%zu]: %zu\n", i, param->snk_cnt[i]); + + return -EINVAL; + } + + if (param->src_cnt[i] > GMAP_AC_MAX_SRC) { + FAIL("Invalid conn_src_cnt[%zu]: %zu\n", i, param->src_cnt[i]); + + return -EINVAL; + } + } + + /* Get total count of sink and source streams to setup */ + for (size_t i = 0U; i < param->conn_cnt; i++) { + for (size_t j = 0U; j < param->snk_cnt[i]; j++) { + snk_cnt++; + } + + for (size_t j = 0U; j < param->src_cnt[i]; j++) { + src_cnt++; + } + } + + /* Setup arrays of parameters based on the preset for easier access. This also copies the + * preset so that we can modify them (e.g. update the metadata) + */ + for (size_t i = 0U; i < snk_cnt; i++) { + snk_uni_streams[i] = &unicast_streams[i]; + + copy_unicast_stream_preset(snk_uni_streams[i], param->snk_named_preset); + + /* Some audio configuration requires multiple sink channels, + * so multiply the SDU based on the channel count + */ + snk_uni_streams[i]->qos.sdu *= param->snk_chan_cnt; + } + + for (size_t i = 0U; i < src_cnt; i++) { + src_uni_streams[i] = &unicast_streams[i + snk_cnt]; + copy_unicast_stream_preset(src_uni_streams[i], param->src_named_preset); + } + + err = gmap_ac_create_unicast_group(param, snk_uni_streams, snk_cnt, src_uni_streams, + src_cnt, unicast_group); + if (err != 0) { + FAIL("Failed to create group: %d\n", err); + + return err; + } + + UNSET_FLAG(flag_started); + + printk("Starting %zu streams for %s\n", snk_cnt + src_cnt, param->name); + err = gmap_ac_cap_unicast_start(param, snk_uni_streams, snk_cnt, src_uni_streams, src_cnt, + *unicast_group); + if (err != 0) { + FAIL("Failed to start unicast audio: %d\n\n", err); + + return err; + } + + WAIT_FOR_FLAG(flag_started); + + return 0; +} + +static void unicast_audio_stop(struct bt_bap_unicast_group *unicast_group) +{ + int err; + + UNSET_FLAG(flag_stopped); + + err = bt_cap_initiator_unicast_audio_stop(unicast_group); + if (err != 0) { + FAIL("Failed to start unicast audio: %d\n", err); + return; + } + + WAIT_FOR_FLAG(flag_stopped); +} + +static void unicast_group_delete(struct bt_bap_unicast_group *unicast_group) +{ + int err; + + err = bt_bap_unicast_group_delete(unicast_group); + if (err != 0) { + FAIL("Failed to create group: %d\n", err); + return; + } +} + +static void test_ugg(const struct gmap_ac_param *param) +{ + struct bt_bap_unicast_group *unicast_group; + + printk("Running test for %s with Sink Preset %s and Source Preset %s\n", param->name, + param->snk_named_preset != NULL ? param->snk_named_preset->name : "None", + param->src_named_preset != NULL ? param->src_named_preset->name : "None"); + + if (param->conn_cnt > GMAP_AC_MAX_CONN) { + FAIL("Invalid conn_cnt: %zu\n", param->conn_cnt); + return; + } + + init(); + + for (size_t i = 0U; i < param->conn_cnt; i++) { + UNSET_FLAG(flag_mtu_exchanged); + + scan_and_connect(); + + WAIT_FOR_FLAG(flag_mtu_exchanged); + + printk("Connected %zu/%zu\n", i + 1, param->conn_cnt); + } + + if (connected_conn_cnt < param->conn_cnt) { + FAIL("Only %zu/%u connected devices, please connect additional devices for this " + "audio configuration\n", + connected_conn_cnt, param->conn_cnt); + return; + } + + for (size_t i = 0U; i < param->conn_cnt; i++) { + discover_cas(connected_conns[i]); + + if (param->snk_cnt[i] > 0U) { + discover_sink(connected_conns[i]); + } + + if (param->src_cnt[i] > 0U) { + discover_source(connected_conns[i]); + } + + discover_gmas(connected_conns[i]); + } + + gmap_ac_unicast(param, &unicast_group); + + unicast_audio_stop(unicast_group); + + unicast_group_delete(unicast_group); + unicast_group = NULL; + + for (size_t i = 0U; i < param->conn_cnt; i++) { + const int err = + bt_conn_disconnect(connected_conns[i], BT_HCI_ERR_REMOTE_USER_TERM_CONN); + + if (err != 0) { + FAIL("Failed to disconnect conn[%zu]: %d\n", i, err); + } + + bt_conn_unref(connected_conns[i]); + connected_conns[i] = NULL; + } + + PASS("GMAP UGG passed for %s with Sink Preset %s and Source Preset %s\n", param->name, + param->snk_named_preset != NULL ? param->snk_named_preset->name : "None", + param->src_named_preset != NULL ? param->src_named_preset->name : "None"); +} + +static void test_gmap_ac_1(void) +{ + const struct gmap_ac_param param = { + .name = "ac_1", + .conn_cnt = 1U, + .snk_cnt = {1U}, + .src_cnt = {0U}, + .snk_chan_cnt = 1U, + .snk_named_preset = snk_named_preset, + .src_named_preset = NULL, + }; + + test_ugg(¶m); +} + +static void test_gmap_ac_2(void) +{ + const struct gmap_ac_param param = { + .name = "ac_2", + .conn_cnt = 1U, + .snk_cnt = {0U}, + .src_cnt = {1U}, + .snk_chan_cnt = 1U, + .snk_named_preset = NULL, + .src_named_preset = src_named_preset, + }; + + test_ugg(¶m); +} + +static void test_gmap_ac_3(void) +{ + const struct gmap_ac_param param = { + .name = "ac_3", + .conn_cnt = 1U, + .snk_cnt = {1U}, + .src_cnt = {1U}, + .snk_chan_cnt = 1U, + .snk_named_preset = snk_named_preset, + .src_named_preset = src_named_preset, + }; + + test_ugg(¶m); +} + +static void test_gmap_ac_4(void) +{ + const struct gmap_ac_param param = { + .name = "ac_4", + .conn_cnt = 1U, + .snk_cnt = {1U}, + .src_cnt = {0U}, + .snk_chan_cnt = 2U, + .snk_named_preset = snk_named_preset, + .src_named_preset = NULL, + }; + + test_ugg(¶m); +} + +static void test_gmap_ac_5(void) +{ + const struct gmap_ac_param param = { + .name = "ac_5", + .conn_cnt = 1U, + .snk_cnt = {1U}, + .src_cnt = {1U}, + .snk_chan_cnt = 2U, + .snk_named_preset = snk_named_preset, + .src_named_preset = src_named_preset, + }; + + test_ugg(¶m); +} + +static void test_gmap_ac_6_i(void) +{ + const struct gmap_ac_param param = { + .name = "ac_6_i", + .conn_cnt = 1U, + .snk_cnt = {2U}, + .src_cnt = {0U}, + .snk_chan_cnt = 1U, + .snk_named_preset = snk_named_preset, + .src_named_preset = NULL, + }; + + test_ugg(¶m); +} + +static void test_gmap_ac_6_ii(void) +{ + const struct gmap_ac_param param = { + .name = "ac_6_ii", + .conn_cnt = 2U, + .snk_cnt = {1U, 1U}, + .src_cnt = {0U, 0U}, + .snk_chan_cnt = 1U, + .snk_named_preset = snk_named_preset, + .src_named_preset = NULL, + }; + + test_ugg(¶m); +} + +static void test_gmap_ac_7_ii(void) +{ + const struct gmap_ac_param param = { + .name = "ac_7_ii", + .conn_cnt = 2U, + .snk_cnt = {1U, 0U}, + .src_cnt = {0U, 1U}, + .snk_chan_cnt = 1U, + .snk_named_preset = snk_named_preset, + .src_named_preset = src_named_preset, + }; + + test_ugg(¶m); +} + +static void test_gmap_ac_8_i(void) +{ + const struct gmap_ac_param param = { + .name = "ac_8_i", + .conn_cnt = 1U, + .snk_cnt = {2U}, + .src_cnt = {1U}, + .snk_chan_cnt = 1U, + .snk_named_preset = snk_named_preset, + .src_named_preset = src_named_preset, + }; + + test_ugg(¶m); +} + +static void test_gmap_ac_8_ii(void) +{ + const struct gmap_ac_param param = { + .name = "ac_8_ii", + .conn_cnt = 2U, + .snk_cnt = {1U, 1U}, + .src_cnt = {1U, 0U}, + .snk_chan_cnt = 1U, + .snk_named_preset = snk_named_preset, + .src_named_preset = src_named_preset, + }; + + test_ugg(¶m); +} + +static void test_gmap_ac_11_i(void) +{ + const struct gmap_ac_param param = { + .name = "ac_11_i", + .conn_cnt = 1U, + .snk_cnt = {2U}, + .src_cnt = {2U}, + .snk_chan_cnt = 1U, + .snk_named_preset = snk_named_preset, + .src_named_preset = src_named_preset, + }; + + test_ugg(¶m); +} + +static void test_gmap_ac_11_ii(void) +{ + const struct gmap_ac_param param = { + .name = "ac_11_ii", + .conn_cnt = 2U, + .snk_cnt = {1U, 1U}, + .src_cnt = {1U, 1U}, + .snk_chan_cnt = 1U, + .snk_named_preset = snk_named_preset, + .src_named_preset = src_named_preset, + }; + + test_ugg(¶m); +} + +static void test_args(int argc, char *argv[]) +{ + for (size_t argn = 0; argn < argc; argn++) { + const char *arg = argv[argn]; + + if (strcmp(arg, "sink_preset") == 0) { + snk_named_preset = + gmap_get_named_preset(true, BT_AUDIO_DIR_SINK, argv[++argn]); + } else if (strcmp(arg, "source_preset") == 0) { + src_named_preset = + gmap_get_named_preset(true, BT_AUDIO_DIR_SOURCE, argv[++argn]); + } else { + FAIL("Invalid arg: %s\n", arg); + } + } +} + +static const struct bst_test_instance test_gmap_ugg[] = { + { + .test_id = "gmap_ugg_ac_1", + .test_post_init_f = test_init, + .test_tick_f = test_tick, + .test_main_f = test_gmap_ac_1, + .test_args_f = test_args, + }, + { + .test_id = "gmap_ugg_ac_2", + .test_post_init_f = test_init, + .test_tick_f = test_tick, + .test_main_f = test_gmap_ac_2, + .test_args_f = test_args, + }, + { + .test_id = "gmap_ugg_ac_3", + .test_post_init_f = test_init, + .test_tick_f = test_tick, + .test_main_f = test_gmap_ac_3, + .test_args_f = test_args, + }, + { + .test_id = "gmap_ugg_ac_4", + .test_post_init_f = test_init, + .test_tick_f = test_tick, + .test_main_f = test_gmap_ac_4, + .test_args_f = test_args, + }, + { + .test_id = "gmap_ugg_ac_5", + .test_post_init_f = test_init, + .test_tick_f = test_tick, + .test_main_f = test_gmap_ac_5, + .test_args_f = test_args, + }, + { + .test_id = "gmap_ugg_ac_6_i", + .test_post_init_f = test_init, + .test_tick_f = test_tick, + .test_main_f = test_gmap_ac_6_i, + .test_args_f = test_args, + }, + { + .test_id = "gmap_ugg_ac_6_ii", + .test_post_init_f = test_init, + .test_tick_f = test_tick, + .test_main_f = test_gmap_ac_6_ii, + .test_args_f = test_args, + }, + { + .test_id = "gmap_ugg_ac_7_ii", + .test_post_init_f = test_init, + .test_tick_f = test_tick, + .test_main_f = test_gmap_ac_7_ii, + .test_args_f = test_args, + }, + { + .test_id = "gmap_ugg_ac_8_i", + .test_post_init_f = test_init, + .test_tick_f = test_tick, + .test_main_f = test_gmap_ac_8_i, + .test_args_f = test_args, + }, + { + .test_id = "gmap_ugg_ac_8_ii", + .test_post_init_f = test_init, + .test_tick_f = test_tick, + .test_main_f = test_gmap_ac_8_ii, + .test_args_f = test_args, + }, + { + .test_id = "gmap_ugg_ac_11_i", + .test_post_init_f = test_init, + .test_tick_f = test_tick, + .test_main_f = test_gmap_ac_11_i, + .test_args_f = test_args, + }, + { + .test_id = "gmap_ugg_ac_11_ii", + .test_post_init_f = test_init, + .test_tick_f = test_tick, + .test_main_f = test_gmap_ac_11_ii, + .test_args_f = test_args, + }, + BSTEST_END_MARKER, +}; + +struct bst_test_list *test_gmap_ugg_install(struct bst_test_list *tests) +{ + return bst_add_tests(tests, test_gmap_ugg); +} + +#else /* !(CONFIG_BT_GMAP) */ + +struct bst_test_list *test_gmap_ugg_install(struct bst_test_list *tests) +{ + return tests; +} + +#endif /* CONFIG_BT_GMAP */ diff --git a/tests/bsim/bluetooth/audio/src/gmap_ugt_test.c b/tests/bsim/bluetooth/audio/src/gmap_ugt_test.c new file mode 100644 index 00000000000..c4a02a0a67e --- /dev/null +++ b/tests/bsim/bluetooth/audio/src/gmap_ugt_test.c @@ -0,0 +1,471 @@ +/* + * Copyright (c) 2023 Nordic Semiconductor ASA + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#if defined(CONFIG_BT_CAP_ACCEPTOR) + +#include +#include +#include +#include +#include +#include "common.h" +#include "bap_common.h" + +extern enum bst_result_t bst_result; + +#define CONTEXT (BT_AUDIO_CONTEXT_TYPE_UNSPECIFIED | BT_AUDIO_CONTEXT_TYPE_GAME) +#define LOCATION (BT_AUDIO_LOCATION_FRONT_LEFT | BT_AUDIO_LOCATION_FRONT_RIGHT) + +static uint8_t csis_rank = 1; + +static struct bt_audio_codec_cap codec_cap = + BT_AUDIO_CODEC_CAP_LC3(BT_AUDIO_CODEC_LC3_FREQ_ANY, BT_AUDIO_CODEC_LC3_DURATION_ANY, + BT_AUDIO_CODEC_LC3_CHAN_COUNT_SUPPORT(1, 2), 30, 240, 2, CONTEXT); + +static const struct bt_audio_codec_qos_pref unicast_qos_pref = + BT_AUDIO_CODEC_QOS_PREF(true, BT_GAP_LE_PHY_2M, 0U, 60U, 10000U, 60000U, 10000U, 60000U); + +#define UNICAST_CHANNEL_COUNT_1 BIT(0) + +static struct bt_cap_stream + unicast_streams[CONFIG_BT_ASCS_ASE_SNK_COUNT + CONFIG_BT_ASCS_ASE_SRC_COUNT]; + +CREATE_FLAG(flag_unicast_stream_started); +CREATE_FLAG(flag_gmap_discovered); + +static void unicast_stream_enabled_cb(struct bt_bap_stream *stream) +{ + struct bt_bap_ep_info ep_info; + int err; + + printk("Enabled: stream %p\n", stream); + + err = bt_bap_ep_get_info(stream->ep, &ep_info); + if (err != 0) { + FAIL("Failed to get ep info: %d\n", err); + return; + } + + if (ep_info.dir == BT_AUDIO_DIR_SINK) { + /* Automatically do the receiver start ready operation */ + err = bt_bap_stream_start(stream); + + if (err != 0) { + FAIL("Failed to start stream: %d\n", err); + return; + } + } +} + +static void unicast_stream_started_cb(struct bt_bap_stream *stream) +{ + printk("Started: stream %p\n", stream); + SET_FLAG(flag_unicast_stream_started); +} + +static struct bt_bap_stream_ops unicast_stream_ops = { + .enabled = unicast_stream_enabled_cb, + .started = unicast_stream_started_cb, +}; + +/* TODO: Expand with GMAP service data */ +static const struct bt_data gmap_acceptor_ad[] = { + BT_DATA_BYTES(BT_DATA_FLAGS, (BT_LE_AD_GENERAL | BT_LE_AD_NO_BREDR)), + BT_DATA_BYTES(BT_DATA_UUID16_ALL, BT_UUID_16_ENCODE(BT_UUID_CAS_VAL)), +}; + +static struct bt_csip_set_member_svc_inst *csip_set_member; + +static struct bt_bap_stream *unicast_stream_alloc(void) +{ + for (size_t i = 0; i < ARRAY_SIZE(unicast_streams); i++) { + struct bt_bap_stream *stream = &unicast_streams[i].bap_stream; + + if (!stream->conn) { + return stream; + } + } + + return NULL; +} + +static int unicast_server_config(struct bt_conn *conn, const struct bt_bap_ep *ep, + enum bt_audio_dir dir, const struct bt_audio_codec_cfg *codec_cfg, + struct bt_bap_stream **stream, + struct bt_audio_codec_qos_pref *const pref, + struct bt_bap_ascs_rsp *rsp) +{ + printk("ASE Codec Config: conn %p ep %p dir %u\n", conn, ep, dir); + + print_codec_cfg(codec_cfg); + + *stream = unicast_stream_alloc(); + if (*stream == NULL) { + printk("No streams available\n"); + *rsp = BT_BAP_ASCS_RSP(BT_BAP_ASCS_RSP_CODE_NO_MEM, BT_BAP_ASCS_REASON_NONE); + + return -ENOMEM; + } + + printk("ASE Codec Config stream %p\n", *stream); + + *pref = unicast_qos_pref; + + return 0; +} + +static int unicast_server_reconfig(struct bt_bap_stream *stream, enum bt_audio_dir dir, + const struct bt_audio_codec_cfg *codec_cfg, + struct bt_audio_codec_qos_pref *const pref, + struct bt_bap_ascs_rsp *rsp) +{ + printk("ASE Codec Reconfig: stream %p\n", stream); + + print_codec_cfg(codec_cfg); + + *pref = unicast_qos_pref; + + *rsp = BT_BAP_ASCS_RSP(BT_BAP_ASCS_RSP_CODE_CONF_UNSUPPORTED, BT_BAP_ASCS_REASON_NONE); + + /* We only support one QoS at the moment, reject changes */ + return -ENOEXEC; +} + +static int unicast_server_qos(struct bt_bap_stream *stream, const struct bt_audio_codec_qos *qos, + struct bt_bap_ascs_rsp *rsp) +{ + printk("QoS: stream %p qos %p\n", stream, qos); + + print_qos(qos); + + return 0; +} + +static bool data_func_cb(struct bt_data *data, void *user_data) +{ + struct bt_bap_ascs_rsp *rsp = (struct bt_bap_ascs_rsp *)user_data; + + if (!BT_AUDIO_METADATA_TYPE_IS_KNOWN(data->type)) { + printk("Invalid metadata type %u or length %u\n", data->type, data->data_len); + *rsp = BT_BAP_ASCS_RSP(BT_BAP_ASCS_RSP_CODE_METADATA_REJECTED, data->type); + + return -EINVAL; + } + + return true; +} + +static int unicast_server_enable(struct bt_bap_stream *stream, const uint8_t meta[], + size_t meta_len, struct bt_bap_ascs_rsp *rsp) +{ + printk("Enable: stream %p meta_len %zu\n", stream, meta_len); + + return bt_audio_data_parse(meta, meta_len, data_func_cb, rsp); +} + +static int unicast_server_start(struct bt_bap_stream *stream, struct bt_bap_ascs_rsp *rsp) +{ + printk("Start: stream %p\n", stream); + + return 0; +} + +static int unicast_server_metadata(struct bt_bap_stream *stream, const uint8_t meta[], + size_t meta_len, struct bt_bap_ascs_rsp *rsp) +{ + printk("Metadata: stream %p meta_len %zu\n", stream, meta_len); + + return bt_audio_data_parse(meta, meta_len, data_func_cb, rsp); +} + +static int unicast_server_disable(struct bt_bap_stream *stream, struct bt_bap_ascs_rsp *rsp) +{ + printk("Disable: stream %p\n", stream); + + return 0; +} + +static int unicast_server_stop(struct bt_bap_stream *stream, struct bt_bap_ascs_rsp *rsp) +{ + printk("Stop: stream %p\n", stream); + + return 0; +} + +static int unicast_server_release(struct bt_bap_stream *stream, struct bt_bap_ascs_rsp *rsp) +{ + printk("Release: stream %p\n", stream); + + return 0; +} + +static struct bt_bap_unicast_server_cb unicast_server_cbs = { + .config = unicast_server_config, + .reconfig = unicast_server_reconfig, + .qos = unicast_server_qos, + .enable = unicast_server_enable, + .start = unicast_server_start, + .metadata = unicast_server_metadata, + .disable = unicast_server_disable, + .stop = unicast_server_stop, + .release = unicast_server_release, +}; + +static void set_location(void) +{ + int err; + + if (IS_ENABLED(CONFIG_BT_PAC_SNK_LOC)) { + err = bt_pacs_set_location(BT_AUDIO_DIR_SINK, LOCATION); + if (err != 0) { + FAIL("Failed to set sink location (err %d)\n", err); + return; + } + } + + if (IS_ENABLED(CONFIG_BT_PAC_SRC_LOC)) { + err = bt_pacs_set_location(BT_AUDIO_DIR_SOURCE, LOCATION); + if (err != 0) { + FAIL("Failed to set source location (err %d)\n", err); + return; + } + } + + printk("Location successfully set\n"); +} + +static int set_supported_contexts(void) +{ + int err; + + if (IS_ENABLED(CONFIG_BT_PAC_SNK)) { + err = bt_pacs_set_supported_contexts(BT_AUDIO_DIR_SINK, CONTEXT); + if (err != 0) { + printk("Failed to set sink supported contexts (err %d)\n", err); + + return err; + } + } + + if (IS_ENABLED(CONFIG_BT_PAC_SRC)) { + err = bt_pacs_set_supported_contexts(BT_AUDIO_DIR_SOURCE, CONTEXT); + if (err != 0) { + printk("Failed to set source supported contexts (err %d)\n", err); + + return err; + } + } + + printk("Supported contexts successfully set\n"); + + return 0; +} + +static void set_available_contexts(void) +{ + int err; + + err = bt_pacs_set_available_contexts(BT_AUDIO_DIR_SINK, CONTEXT); + if (IS_ENABLED(CONFIG_BT_PAC_SNK) && err != 0) { + FAIL("Failed to set sink available contexts (err %d)\n", err); + return; + } + + err = bt_pacs_set_available_contexts(BT_AUDIO_DIR_SOURCE, CONTEXT); + if (IS_ENABLED(CONFIG_BT_PAC_SRC) && err != 0) { + FAIL("Failed to set source available contexts (err %d)\n", err); + return; + } + + printk("Available contexts successfully set\n"); +} + +static void gmap_discover_cb(struct bt_conn *conn, int err, enum bt_gmap_role role, + struct bt_gmap_feat features) +{ + enum bt_gmap_ugg_feat ugg_feat; + + if (err != 0) { + FAIL("GMAP discovery (err %d)\n", err); + return; + } + + printk("GMAP discovered for conn %p:\n\trole 0x%02x\n\tugg_feat 0x%02x\n\tugt_feat " + "0x%02x\n\tbgs_feat 0x%02x\n\tbgr_feat 0x%02x\n", + conn, role, features.ugg_feat, features.ugt_feat, features.bgs_feat, + features.bgr_feat); + + if ((role & BT_GMAP_ROLE_UGG) == 0) { + FAIL("Remote GMAP device is not a UGG\n"); + return; + } + + ugg_feat = features.ugg_feat; + if ((ugg_feat & BT_GMAP_UGG_FEAT_MULTIPLEX) == 0 || + (ugg_feat & BT_GMAP_UGG_FEAT_96KBPS_SOURCE) == 0 || + (ugg_feat & BT_GMAP_UGG_FEAT_MULTISINK) == 0) { + FAIL("Remote GMAP device does not have expected UGG features: %d\n", ugg_feat); + return; + } + + SET_FLAG(flag_gmap_discovered); +} + +static const struct bt_gmap_cb gmap_cb = { + .discover = gmap_discover_cb, +}; + +static void discover_gmas(struct bt_conn *conn) +{ + int err; + + UNSET_FLAG(flag_gmap_discovered); + + err = bt_gmap_discover(conn); + if (err != 0) { + printk("Failed to discover GMAS: %d\n", err); + return; + } + + WAIT_FOR_FLAG(flag_gmap_discovered); +} + +static void test_main(void) +{ + /* TODO: Register all GMAP codec capabilities */ + const enum bt_gmap_role role = BT_GMAP_ROLE_UGT; + const struct bt_gmap_feat features = { + .ugt_feat = (BT_GMAP_UGT_FEAT_SOURCE | BT_GMAP_UGT_FEAT_80KBPS_SOURCE | + BT_GMAP_UGT_FEAT_SINK | BT_GMAP_UGT_FEAT_64KBPS_SINK | + BT_GMAP_UGT_FEAT_MULTIPLEX | BT_GMAP_UGT_FEAT_MULTISINK | + BT_GMAP_UGT_FEAT_MULTISOURCE), + }; + static struct bt_pacs_cap unicast_cap = { + .codec_cap = &codec_cap, + }; + int err; + + err = bt_enable(NULL); + if (err != 0) { + FAIL("Bluetooth enable failed (err %d)\n", err); + return; + } + + printk("Bluetooth initialized\n"); + + if (IS_ENABLED(CONFIG_BT_CAP_ACCEPTOR_SET_MEMBER)) { + const struct bt_csip_set_member_register_param csip_set_member_param = { + .set_size = 2, + .rank = csis_rank, + .lockable = true, + /* Using the CSIP_SET_MEMBER test sample SIRK */ + .set_sirk = {0xcd, 0xcc, 0x72, 0xdd, 0x86, 0x8c, 0xcd, 0xce, 0x22, 0xfd, + 0xa1, 0x21, 0x09, 0x7d, 0x7d, 0x45}, + }; + + err = bt_cap_acceptor_register(&csip_set_member_param, &csip_set_member); + if (err != 0) { + FAIL("CAP acceptor failed to register (err %d)\n", err); + return; + } + } + + err = bt_pacs_cap_register(BT_AUDIO_DIR_SINK, &unicast_cap); + if (err != 0) { + FAIL("Capability register failed (err %d)\n", err); + + return; + } + + err = bt_pacs_cap_register(BT_AUDIO_DIR_SOURCE, &unicast_cap); + if (err != 0) { + FAIL("Capability register failed (err %d)\n", err); + + return; + } + + err = bt_bap_unicast_server_register_cb(&unicast_server_cbs); + if (err != 0) { + FAIL("Failed to register unicast server callbacks (err %d)\n", err); + + return; + } + + for (size_t i = 0U; i < ARRAY_SIZE(unicast_streams); i++) { + bt_cap_stream_ops_register(&unicast_streams[i], &unicast_stream_ops); + } + + set_supported_contexts(); + set_available_contexts(); + set_location(); + + err = bt_gmap_register(role, features); + if (err != 0) { + FAIL("Failed to register GMAS (err %d)\n", err); + + return; + } + + err = bt_gmap_cb_register(&gmap_cb); + if (err != 0) { + FAIL("Failed to register callbacks (err %d)\n", err); + + return; + } + + err = bt_le_adv_start(BT_LE_ADV_CONN_NAME, gmap_acceptor_ad, ARRAY_SIZE(gmap_acceptor_ad), + NULL, 0); + if (err != 0) { + FAIL("Advertising failed to start (err %d)\n", err); + return; + } + + WAIT_FOR_FLAG(flag_connected); + + discover_gmas(default_conn); + + WAIT_FOR_FLAG(flag_disconnected); + + PASS("GMAP UGT passed\n"); +} + +static void test_args(int argc, char *argv[]) +{ + for (size_t argn = 0; argn < argc; argn++) { + const char *arg = argv[argn]; + + if (strcmp(arg, "rank") == 0) { + csis_rank = strtoul(argv[++argn], NULL, 10); + } else { + FAIL("Invalid arg: %s\n", arg); + } + } +} + +static const struct bst_test_instance test_gmap_ugt[] = { + { + .test_id = "gmap_ugt", + .test_post_init_f = test_init, + .test_tick_f = test_tick, + .test_main_f = test_main, + .test_args_f = test_args, + }, + BSTEST_END_MARKER, +}; + +struct bst_test_list *test_gmap_ugt_install(struct bst_test_list *tests) +{ + return bst_add_tests(tests, test_gmap_ugt); +} + +#else /* !(CONFIG_BT_CAP_ACCEPTOR) */ + +struct bst_test_list *test_gmap_ugt_install(struct bst_test_list *tests) +{ + return tests; +} + +#endif /* CONFIG_BT_CAP_ACCEPTOR */ diff --git a/tests/bsim/bluetooth/audio/src/main.c b/tests/bsim/bluetooth/audio/src/main.c index f4ef6294545..2213014b251 100644 --- a/tests/bsim/bluetooth/audio/src/main.c +++ b/tests/bsim/bluetooth/audio/src/main.c @@ -37,6 +37,8 @@ extern struct bst_test_list *test_pacs_notify_client_install(struct bst_test_lis extern struct bst_test_list *test_pacs_notify_server_install(struct bst_test_list *tests); extern struct bst_test_list *test_csip_notify_client_install(struct bst_test_list *tests); extern struct bst_test_list *test_csip_notify_server_install(struct bst_test_list *tests); +extern struct bst_test_list *test_gmap_ugg_install(struct bst_test_list *tests); +extern struct bst_test_list *test_gmap_ugt_install(struct bst_test_list *tests); bst_test_install_t test_installers[] = { test_vcp_install, @@ -70,7 +72,9 @@ bst_test_install_t test_installers[] = { test_pacs_notify_server_install, test_csip_notify_client_install, test_csip_notify_server_install, - NULL + test_gmap_ugg_install, + test_gmap_ugt_install, + NULL, }; int main(void) diff --git a/tests/bsim/bluetooth/audio/test_scripts/_gmap.sh b/tests/bsim/bluetooth/audio/test_scripts/_gmap.sh new file mode 100755 index 00000000000..175e453da1b --- /dev/null +++ b/tests/bsim/bluetooth/audio/test_scripts/_gmap.sh @@ -0,0 +1,22 @@ +#!/usr/bin/env bash +# +# Copyright (c) 2023 Nordic Semiconductor ASA +# +# SPDX-License-Identifier: Apache-2.0 + +dir_path=$(dirname "$0") + +set -e # Exit on error + +$dir_path/gmap_unicast_ac_1.sh +$dir_path/gmap_unicast_ac_2.sh +$dir_path/gmap_unicast_ac_3.sh +$dir_path/gmap_unicast_ac_4.sh +$dir_path/gmap_unicast_ac_5.sh +$dir_path/gmap_unicast_ac_6_i.sh +$dir_path/gmap_unicast_ac_6_ii.sh +$dir_path/gmap_unicast_ac_7_ii.sh +$dir_path/gmap_unicast_ac_8_i.sh +$dir_path/gmap_unicast_ac_8_ii.sh +$dir_path/gmap_unicast_ac_11_i.sh +$dir_path/gmap_unicast_ac_11_ii.sh diff --git a/tests/bsim/bluetooth/audio/test_scripts/gmap_unicast_ac_1.sh b/tests/bsim/bluetooth/audio/test_scripts/gmap_unicast_ac_1.sh new file mode 100755 index 00000000000..37664d7c6aa --- /dev/null +++ b/tests/bsim/bluetooth/audio/test_scripts/gmap_unicast_ac_1.sh @@ -0,0 +1,40 @@ +#!/usr/bin/env bash +# +# Copyright (c) 2023 Nordic Semiconductor ASA +# +# SPDX-License-Identifier: Apache-2.0 + +SIMULATION_ID="gmap_unicast_ac_1" +VERBOSITY_LEVEL=2 +EXECUTE_TIMEOUT=60 + +source ${ZEPHYR_BASE}/tests/bsim/sh_common.source + +cd ${BSIM_OUT_PATH}/bin + +function Execute_AC_1() { + printf "\n\n======== Running GMAP AC_1 with %s =========\n\n" $1 + + Execute ./bs_${BOARD}_tests_bsim_bluetooth_audio_prj_conf \ + -v=${VERBOSITY_LEVEL} -s=${SIMULATION_ID} -d=0 -testid=gmap_ugg_ac_1 -RealEncryption=1 \ + -rs=23 -D=2 -argstest sink_preset $1 + + Execute ./bs_${BOARD}_tests_bsim_bluetooth_audio_prj_conf \ + -v=${VERBOSITY_LEVEL} -s=${SIMULATION_ID} -d=1 -testid=gmap_ugt -RealEncryption=1 \ + -rs=46 -D=2 + + # Simulation time should be larger than the WAIT_TIME in common.h + Execute ./bs_2G4_phy_v1 -v=${VERBOSITY_LEVEL} -s=${SIMULATION_ID} \ + -D=2 -sim_length=60e6 ${@:2} + + wait_for_background_jobs +} + +set -e # Exit on error + +Execute_AC_1 32_1_gr +Execute_AC_1 32_2_gr +Execute_AC_1 48_1_gr +Execute_AC_1 48_2_gr +Execute_AC_1 48_3_gr +Execute_AC_1 48_4_gr diff --git a/tests/bsim/bluetooth/audio/test_scripts/gmap_unicast_ac_11_i.sh b/tests/bsim/bluetooth/audio/test_scripts/gmap_unicast_ac_11_i.sh new file mode 100755 index 00000000000..8ba1f94696d --- /dev/null +++ b/tests/bsim/bluetooth/audio/test_scripts/gmap_unicast_ac_11_i.sh @@ -0,0 +1,48 @@ +#!/usr/bin/env bash +# +# Copyright (c) 2023 Nordic Semiconductor ASA +# +# SPDX-License-Identifier: Apache-2.0 + +SIMULATION_ID="gmap_unicast_ac_11_i" +VERBOSITY_LEVEL=2 +EXECUTE_TIMEOUT=60 + +source ${ZEPHYR_BASE}/tests/bsim/sh_common.source + +cd ${BSIM_OUT_PATH}/bin + +function Execute_AC_11_I() { + printf "\n\n======== Running GMAP AC_11_I with %s and %s =========\n\n" $1 $2 + + Execute ./bs_${BOARD}_tests_bsim_bluetooth_audio_prj_conf \ + -v=${VERBOSITY_LEVEL} -s=${SIMULATION_ID} -d=0 -testid=gmap_ugg_ac_11_i -RealEncryption=1 \ + -rs=23 -D=2 -argstest sink_preset $1 source_preset $2 + + Execute ./bs_${BOARD}_tests_bsim_bluetooth_audio_prj_conf \ + -v=${VERBOSITY_LEVEL} -s=${SIMULATION_ID} -d=1 -testid=gmap_ugt -RealEncryption=1 \ + -rs=46 -D=2 + + # Simulation time should be larger than the WAIT_TIME in common.h + Execute ./bs_2G4_phy_v1 -v=${VERBOSITY_LEVEL} -s=${SIMULATION_ID} \ + -D=2 -sim_length=60e6 ${@:3} + + wait_for_background_jobs +} + +set -e # Exit on error + +Execute_AC_11_I 32_1_gr 16_1_gs +Execute_AC_11_I 32_2_gr 16_2_gs +Execute_AC_11_I 48_1_gr 16_1_gs +Execute_AC_11_I 48_2_gr 16_2_gs +Execute_AC_11_I 32_1_gr 32_1_gs +Execute_AC_11_I 32_2_gr 32_2_gs +Execute_AC_11_I 48_1_gr 32_1_gs +Execute_AC_11_I 48_2_gr 32_2_gs +Execute_AC_11_I 48_1_gr 48_1_gs +Execute_AC_11_I 48_2_gr 48_2_gs +Execute_AC_11_I 48_3_gr 32_1_gs +Execute_AC_11_I 48_4_gr 32_2_gs +Execute_AC_11_I 48_3_gr 48_1_gs +Execute_AC_11_I 48_4_gr 48_2_gs diff --git a/tests/bsim/bluetooth/audio/test_scripts/gmap_unicast_ac_11_ii.sh b/tests/bsim/bluetooth/audio/test_scripts/gmap_unicast_ac_11_ii.sh new file mode 100755 index 00000000000..7fcf451cfa8 --- /dev/null +++ b/tests/bsim/bluetooth/audio/test_scripts/gmap_unicast_ac_11_ii.sh @@ -0,0 +1,52 @@ +#!/usr/bin/env bash +# +# Copyright (c) 2023 Nordic Semiconductor ASA +# +# SPDX-License-Identifier: Apache-2.0 + +SIMULATION_ID="gmap_unicast_ac_11_ii" +VERBOSITY_LEVEL=2 +EXECUTE_TIMEOUT=60 + +source ${ZEPHYR_BASE}/tests/bsim/sh_common.source + +cd ${BSIM_OUT_PATH}/bin + +function Execute_AC_11_II() { + printf "\n\n======== Running GMAP AC_11_II with %s and %s =========\n\n" $1 $2 + + Execute ./bs_${BOARD}_tests_bsim_bluetooth_audio_prj_conf \ + -v=${VERBOSITY_LEVEL} -s=${SIMULATION_ID} -d=0 -testid=gmap_ugg_ac_11_ii -RealEncryption=1 \ + -rs=23 -D=3 -argstest sink_preset $1 source_preset $2 + + Execute ./bs_${BOARD}_tests_bsim_bluetooth_audio_prj_conf \ + -v=${VERBOSITY_LEVEL} -s=${SIMULATION_ID} -d=1 -testid=gmap_ugt -RealEncryption=1 \ + -rs=46 -D=3 + + Execute ./bs_${BOARD}_tests_bsim_bluetooth_audio_prj_conf \ + -v=${VERBOSITY_LEVEL} -s=${SIMULATION_ID} -d=2 -testid=gmap_ugt -RealEncryption=1 \ + -rs=69 -D=3 + + # Simulation time should be larger than the WAIT_TIME in common.h + Execute ./bs_2G4_phy_v1 -v=${VERBOSITY_LEVEL} -s=${SIMULATION_ID} \ + -D=3 -sim_length=60e6 ${@:3} + + wait_for_background_jobs +} + +set -e # Exit on error + +Execute_AC_11_II 32_1_gr 16_1_gs +Execute_AC_11_II 32_2_gr 16_2_gs +Execute_AC_11_II 48_1_gr 16_1_gs +Execute_AC_11_II 48_2_gr 16_2_gs +Execute_AC_11_II 32_1_gr 32_1_gs +Execute_AC_11_II 32_2_gr 32_2_gs +Execute_AC_11_II 48_1_gr 32_1_gs +Execute_AC_11_II 48_2_gr 32_2_gs +Execute_AC_11_II 48_1_gr 48_1_gs +Execute_AC_11_II 48_2_gr 48_2_gs +Execute_AC_11_II 48_3_gr 32_1_gs +Execute_AC_11_II 48_4_gr 32_2_gs +Execute_AC_11_II 48_3_gr 48_1_gs +Execute_AC_11_II 48_4_gr 48_2_gs diff --git a/tests/bsim/bluetooth/audio/test_scripts/gmap_unicast_ac_2.sh b/tests/bsim/bluetooth/audio/test_scripts/gmap_unicast_ac_2.sh new file mode 100755 index 00000000000..d297b591a64 --- /dev/null +++ b/tests/bsim/bluetooth/audio/test_scripts/gmap_unicast_ac_2.sh @@ -0,0 +1,41 @@ +#!/usr/bin/env bash +# +# Copyright (c) 2023 Nordic Semiconductor ASA +# +# SPDX-License-Identifier: Apache-2.0 + +SIMULATION_ID="gmap_unicast_ac_2" +VERBOSITY_LEVEL=2 +EXECUTE_TIMEOUT=60 + +source ${ZEPHYR_BASE}/tests/bsim/sh_common.source + +cd ${BSIM_OUT_PATH}/bin + + +function Execute_AC_2() { + printf "\n\n======== Running GMAP AC_2 with %s =========\n\n" $1 + + Execute ./bs_${BOARD}_tests_bsim_bluetooth_audio_prj_conf \ + -v=${VERBOSITY_LEVEL} -s=${SIMULATION_ID} -d=0 -testid=gmap_ugg_ac_2 -RealEncryption=1 \ + -rs=23 -D=2 -argstest source_preset $1 + + Execute ./bs_${BOARD}_tests_bsim_bluetooth_audio_prj_conf \ + -v=${VERBOSITY_LEVEL} -s=${SIMULATION_ID} -d=1 -testid=gmap_ugt -RealEncryption=1 \ + -rs=46 -D=2 + + # Simulation time should be larger than the WAIT_TIME in common.h + Execute ./bs_2G4_phy_v1 -v=${VERBOSITY_LEVEL} -s=${SIMULATION_ID} \ + -D=2 -sim_length=60e6 ${@:2} + + wait_for_background_jobs +} + +set -e # Exit on error + +Execute_AC_2 16_1_gs +Execute_AC_2 16_2_gs +Execute_AC_2 32_1_gs +Execute_AC_2 32_2_gs +Execute_AC_2 48_1_gs +Execute_AC_2 48_2_gs diff --git a/tests/bsim/bluetooth/audio/test_scripts/gmap_unicast_ac_3.sh b/tests/bsim/bluetooth/audio/test_scripts/gmap_unicast_ac_3.sh new file mode 100755 index 00000000000..a23c5f61fa7 --- /dev/null +++ b/tests/bsim/bluetooth/audio/test_scripts/gmap_unicast_ac_3.sh @@ -0,0 +1,49 @@ +#!/usr/bin/env bash +# +# Copyright (c) 2023 Nordic Semiconductor ASA +# +# SPDX-License-Identifier: Apache-2.0 + +SIMULATION_ID="gmap_unicast_ac_3" +VERBOSITY_LEVEL=2 +EXECUTE_TIMEOUT=60 + +source ${ZEPHYR_BASE}/tests/bsim/sh_common.source + +cd ${BSIM_OUT_PATH}/bin + + +function Execute_AC_3() { + printf "\n\n======== Running GMAP AC_3 with %s and %s =========\n\n" $1 $2 + + Execute ./bs_${BOARD}_tests_bsim_bluetooth_audio_prj_conf \ + -v=${VERBOSITY_LEVEL} -s=${SIMULATION_ID} -d=0 -testid=gmap_ugg_ac_3 -RealEncryption=1 \ + -rs=23 -D=2 -argstest sink_preset $1 source_preset $2 + + Execute ./bs_${BOARD}_tests_bsim_bluetooth_audio_prj_conf \ + -v=${VERBOSITY_LEVEL} -s=${SIMULATION_ID} -d=1 -testid=gmap_ugt -RealEncryption=1 \ + -rs=46 -D=2 + + # Simulation time should be larger than the WAIT_TIME in common.h + Execute ./bs_2G4_phy_v1 -v=${VERBOSITY_LEVEL} -s=${SIMULATION_ID} \ + -D=2 -sim_length=60e6 ${@:3} + + wait_for_background_jobs +} + +set -e # Exit on error + +Execute_AC_3 32_1_gr 16_1_gs +Execute_AC_3 32_2_gr 16_2_gs +Execute_AC_3 48_1_gr 16_1_gs +Execute_AC_3 48_2_gr 16_2_gs +Execute_AC_3 32_1_gr 32_1_gs +Execute_AC_3 32_2_gr 32_2_gs +Execute_AC_3 48_1_gr 32_1_gs +Execute_AC_3 48_2_gr 32_2_gs +Execute_AC_3 48_1_gr 48_1_gs +Execute_AC_3 48_2_gr 48_2_gs +Execute_AC_3 48_3_gr 32_1_gs +Execute_AC_3 48_4_gr 32_2_gs +Execute_AC_3 48_3_gr 48_1_gs +Execute_AC_3 48_4_gr 48_2_gs diff --git a/tests/bsim/bluetooth/audio/test_scripts/gmap_unicast_ac_4.sh b/tests/bsim/bluetooth/audio/test_scripts/gmap_unicast_ac_4.sh new file mode 100755 index 00000000000..84a4d425c66 --- /dev/null +++ b/tests/bsim/bluetooth/audio/test_scripts/gmap_unicast_ac_4.sh @@ -0,0 +1,40 @@ +#!/usr/bin/env bash +# +# Copyright (c) 2023 Nordic Semiconductor ASA +# +# SPDX-License-Identifier: Apache-2.0 + +SIMULATION_ID="gmap_unicast_ac_4" +VERBOSITY_LEVEL=2 +EXECUTE_TIMEOUT=60 + +source ${ZEPHYR_BASE}/tests/bsim/sh_common.source + +cd ${BSIM_OUT_PATH}/bin + +function Execute_AC_4() { + printf "\n\n======== Running GMAP AC_4 with %s =========\n\n" $1 + + Execute ./bs_${BOARD}_tests_bsim_bluetooth_audio_prj_conf \ + -v=${VERBOSITY_LEVEL} -s=${SIMULATION_ID} -d=0 -testid=gmap_ugg_ac_4 -RealEncryption=1 \ + -rs=23 -D=2 -argstest sink_preset $1 + + Execute ./bs_${BOARD}_tests_bsim_bluetooth_audio_prj_conf \ + -v=${VERBOSITY_LEVEL} -s=${SIMULATION_ID} -d=1 -testid=gmap_ugt -RealEncryption=1 \ + -rs=46 -D=2 + + # Simulation time should be larger than the WAIT_TIME in common.h + Execute ./bs_2G4_phy_v1 -v=${VERBOSITY_LEVEL} -s=${SIMULATION_ID} \ + -D=2 -sim_length=60e6 ${@:2} + + wait_for_background_jobs +} + +set -e # Exit on error + +Execute_AC_4 32_1_gr +Execute_AC_4 32_2_gr +Execute_AC_4 48_1_gr +Execute_AC_4 48_2_gr +Execute_AC_4 48_3_gr +Execute_AC_4 48_4_gr diff --git a/tests/bsim/bluetooth/audio/test_scripts/gmap_unicast_ac_5.sh b/tests/bsim/bluetooth/audio/test_scripts/gmap_unicast_ac_5.sh new file mode 100755 index 00000000000..1be847e2f64 --- /dev/null +++ b/tests/bsim/bluetooth/audio/test_scripts/gmap_unicast_ac_5.sh @@ -0,0 +1,47 @@ +#!/usr/bin/env bash +# +# Copyright (c) 2023 Nordic Semiconductor ASA +# +# SPDX-License-Identifier: Apache-2.0 + +SIMULATION_ID="gmap_unicast_ac_5" +VERBOSITY_LEVEL=2 +EXECUTE_TIMEOUT=60 + +source ${ZEPHYR_BASE}/tests/bsim/sh_common.source + +cd ${BSIM_OUT_PATH}/bin + + +function Execute_AC_5() { + printf "\n\n======== Running GMAP AC_5 with %s and %s =========\n\n" $1 $2 + + Execute ./bs_${BOARD}_tests_bsim_bluetooth_audio_prj_conf \ + -v=${VERBOSITY_LEVEL} -s=${SIMULATION_ID} -d=0 -testid=gmap_ugg_ac_5 -RealEncryption=1 \ + -rs=23 -D=2 -argstest sink_preset $1 source_preset $2 + + Execute ./bs_${BOARD}_tests_bsim_bluetooth_audio_prj_conf \ + -v=${VERBOSITY_LEVEL} -s=${SIMULATION_ID} -d=1 -testid=gmap_ugt -RealEncryption=1 \ + -rs=46 -D=2 + + # Simulation time should be larger than the WAIT_TIME in common.h + Execute ./bs_2G4_phy_v1 -v=${VERBOSITY_LEVEL} -s=${SIMULATION_ID} \ + -D=2 -sim_length=60e6 ${@:3} + + wait_for_background_jobs +} + +set -e # Exit on error + +Execute_AC_5 32_1_gr 16_1_gs +Execute_AC_5 32_2_gr 16_2_gs +Execute_AC_5 48_1_gr 16_1_gs +Execute_AC_5 48_2_gr 16_2_gs +Execute_AC_5 32_1_gr 32_1_gs +Execute_AC_5 32_2_gr 32_2_gs +Execute_AC_5 48_1_gr 32_1_gs +Execute_AC_5 48_2_gr 32_2_gs +Execute_AC_5 48_1_gr 48_1_gs +Execute_AC_5 48_2_gr 48_2_gs +Execute_AC_5 48_3_gr 32_1_gs +Execute_AC_5 48_4_gr 32_2_gs diff --git a/tests/bsim/bluetooth/audio/test_scripts/gmap_unicast_ac_6_i.sh b/tests/bsim/bluetooth/audio/test_scripts/gmap_unicast_ac_6_i.sh new file mode 100755 index 00000000000..59810ccf940 --- /dev/null +++ b/tests/bsim/bluetooth/audio/test_scripts/gmap_unicast_ac_6_i.sh @@ -0,0 +1,40 @@ +#!/usr/bin/env bash +# +# Copyright (c) 2023 Nordic Semiconductor ASA +# +# SPDX-License-Identifier: Apache-2.0 + +SIMULATION_ID="gmap_unicast_ac_6_i" +VERBOSITY_LEVEL=2 +EXECUTE_TIMEOUT=60 + +source ${ZEPHYR_BASE}/tests/bsim/sh_common.source + +cd ${BSIM_OUT_PATH}/bin + +function Execute_AC_6_I() { + printf "\n\n======== Running GMAP AC_6_I with %s =========\n\n" $1 + + Execute ./bs_${BOARD}_tests_bsim_bluetooth_audio_prj_conf \ + -v=${VERBOSITY_LEVEL} -s=${SIMULATION_ID} -d=0 -testid=gmap_ugg_ac_6_i -RealEncryption=1 \ + -rs=23 -D=2 -argstest sink_preset $1 + + Execute ./bs_${BOARD}_tests_bsim_bluetooth_audio_prj_conf \ + -v=${VERBOSITY_LEVEL} -s=${SIMULATION_ID} -d=1 -testid=gmap_ugt -RealEncryption=1 \ + -rs=46 -D=2 + + # Simulation time should be larger than the WAIT_TIME in common.h + Execute ./bs_2G4_phy_v1 -v=${VERBOSITY_LEVEL} -s=${SIMULATION_ID} \ + -D=2 -sim_length=60e6 ${@:2} + + wait_for_background_jobs +} + +set -e # Exit on error + +Execute_AC_6_I 32_1_gr +Execute_AC_6_I 32_2_gr +Execute_AC_6_I 48_1_gr +Execute_AC_6_I 48_2_gr +Execute_AC_6_I 48_3_gr +Execute_AC_6_I 48_4_gr diff --git a/tests/bsim/bluetooth/audio/test_scripts/gmap_unicast_ac_6_ii.sh b/tests/bsim/bluetooth/audio/test_scripts/gmap_unicast_ac_6_ii.sh new file mode 100755 index 00000000000..355a2f365ac --- /dev/null +++ b/tests/bsim/bluetooth/audio/test_scripts/gmap_unicast_ac_6_ii.sh @@ -0,0 +1,44 @@ +#!/usr/bin/env bash +# +# Copyright (c) 2023 Nordic Semiconductor ASA +# +# SPDX-License-Identifier: Apache-2.0 + +SIMULATION_ID="gmap_unicast_ac_6_ii" +VERBOSITY_LEVEL=2 +EXECUTE_TIMEOUT=60 + +source ${ZEPHYR_BASE}/tests/bsim/sh_common.source + +cd ${BSIM_OUT_PATH}/bin + +function Execute_AC_6_II() { + printf "\n\n======== Running GMAP AC_6_II with %s =========\n\n" $1 + + Execute ./bs_${BOARD}_tests_bsim_bluetooth_audio_prj_conf \ + -v=${VERBOSITY_LEVEL} -s=${SIMULATION_ID} -d=0 -testid=gmap_ugg_ac_6_ii -RealEncryption=1 \ + -rs=23 -D=3 -argstest sink_preset $1 + + Execute ./bs_${BOARD}_tests_bsim_bluetooth_audio_prj_conf \ + -v=${VERBOSITY_LEVEL} -s=${SIMULATION_ID} -d=1 -testid=gmap_ugt -RealEncryption=1 \ + -rs=46 -D=3 + + Execute ./bs_${BOARD}_tests_bsim_bluetooth_audio_prj_conf \ + -v=${VERBOSITY_LEVEL} -s=${SIMULATION_ID} -d=2 -testid=gmap_ugt -RealEncryption=1 \ + -rs=69 -D=3 + + # Simulation time should be larger than the WAIT_TIME in common.h + Execute ./bs_2G4_phy_v1 -v=${VERBOSITY_LEVEL} -s=${SIMULATION_ID} \ + -D=3 -sim_length=60e6 ${@:2} + + wait_for_background_jobs +} + +set -e # Exit on error + +Execute_AC_6_II 32_1_gr +Execute_AC_6_II 32_2_gr +Execute_AC_6_II 48_1_gr +Execute_AC_6_II 48_2_gr +Execute_AC_6_II 48_3_gr +Execute_AC_6_II 48_4_gr diff --git a/tests/bsim/bluetooth/audio/test_scripts/gmap_unicast_ac_7_ii.sh b/tests/bsim/bluetooth/audio/test_scripts/gmap_unicast_ac_7_ii.sh new file mode 100755 index 00000000000..37b60a18cf0 --- /dev/null +++ b/tests/bsim/bluetooth/audio/test_scripts/gmap_unicast_ac_7_ii.sh @@ -0,0 +1,52 @@ +#!/usr/bin/env bash +# +# Copyright (c) 2023 Nordic Semiconductor ASA +# +# SPDX-License-Identifier: Apache-2.0 + +SIMULATION_ID="gmap_unicast_ac_7_ii" +VERBOSITY_LEVEL=2 +EXECUTE_TIMEOUT=60 + +source ${ZEPHYR_BASE}/tests/bsim/sh_common.source + +cd ${BSIM_OUT_PATH}/bin + +function Execute_AC_7_II() { + printf "\n\n======== Running GMAP AC_7_II with %s and %s =========\n\n" $1 $2 + + Execute ./bs_${BOARD}_tests_bsim_bluetooth_audio_prj_conf \ + -v=${VERBOSITY_LEVEL} -s=${SIMULATION_ID} -d=0 -testid=gmap_ugg_ac_7_ii -RealEncryption=1 \ + -rs=23 -D=3 -argstest sink_preset $1 source_preset $2 + + Execute ./bs_${BOARD}_tests_bsim_bluetooth_audio_prj_conf \ + -v=${VERBOSITY_LEVEL} -s=${SIMULATION_ID} -d=1 -testid=gmap_ugt -RealEncryption=1 \ + -rs=46 -D=3 + + Execute ./bs_${BOARD}_tests_bsim_bluetooth_audio_prj_conf \ + -v=${VERBOSITY_LEVEL} -s=${SIMULATION_ID} -d=2 -testid=gmap_ugt -RealEncryption=1 \ + -rs=69 -D=3 + + # Simulation time should be larger than the WAIT_TIME in common.h + Execute ./bs_2G4_phy_v1 -v=${VERBOSITY_LEVEL} -s=${SIMULATION_ID} \ + -D=3 -sim_length=60e6 ${@:3} + + wait_for_background_jobs +} + +set -e # Exit on error + +Execute_AC_7_II 32_1_gr 16_1_gs +Execute_AC_7_II 32_2_gr 16_2_gs +Execute_AC_7_II 48_1_gr 16_1_gs +Execute_AC_7_II 48_2_gr 16_2_gs +Execute_AC_7_II 32_1_gr 32_1_gs +Execute_AC_7_II 32_2_gr 32_2_gs +Execute_AC_7_II 48_1_gr 32_1_gs +Execute_AC_7_II 48_2_gr 32_2_gs +Execute_AC_7_II 48_1_gr 48_1_gs +Execute_AC_7_II 48_2_gr 48_2_gs +Execute_AC_7_II 48_3_gr 32_1_gs +Execute_AC_7_II 48_4_gr 32_2_gs +Execute_AC_7_II 48_3_gr 48_1_gs +Execute_AC_7_II 48_4_gr 48_2_gs diff --git a/tests/bsim/bluetooth/audio/test_scripts/gmap_unicast_ac_8_i.sh b/tests/bsim/bluetooth/audio/test_scripts/gmap_unicast_ac_8_i.sh new file mode 100755 index 00000000000..b8d6ebcbe61 --- /dev/null +++ b/tests/bsim/bluetooth/audio/test_scripts/gmap_unicast_ac_8_i.sh @@ -0,0 +1,48 @@ +#!/usr/bin/env bash +# +# Copyright (c) 2023 Nordic Semiconductor ASA +# +# SPDX-License-Identifier: Apache-2.0 + +SIMULATION_ID="gmap_unicast_ac_8_i" +VERBOSITY_LEVEL=2 +EXECUTE_TIMEOUT=60 + +source ${ZEPHYR_BASE}/tests/bsim/sh_common.source + +cd ${BSIM_OUT_PATH}/bin + +function Execute_AC_8_I() { + printf "\n\n======== Running GMAP AC_8_I with %s and %s =========\n\n" $1 $2 + + Execute ./bs_${BOARD}_tests_bsim_bluetooth_audio_prj_conf \ + -v=${VERBOSITY_LEVEL} -s=${SIMULATION_ID} -d=0 -testid=gmap_ugg_ac_8_i -RealEncryption=1 \ + -rs=23 -D=2 -argstest sink_preset $1 source_preset $2 + + Execute ./bs_${BOARD}_tests_bsim_bluetooth_audio_prj_conf \ + -v=${VERBOSITY_LEVEL} -s=${SIMULATION_ID} -d=1 -testid=gmap_ugt -RealEncryption=1 \ + -rs=46 -D=2 + + # Simulation time should be larger than the WAIT_TIME in common.h + Execute ./bs_2G4_phy_v1 -v=${VERBOSITY_LEVEL} -s=${SIMULATION_ID} \ + -D=2 -sim_length=60e6 ${@:3} + + wait_for_background_jobs +} + +set -e # Exit on error + +Execute_AC_8_I 32_1_gr 16_1_gs +Execute_AC_8_I 32_2_gr 16_2_gs +Execute_AC_8_I 48_1_gr 16_1_gs +Execute_AC_8_I 48_2_gr 16_2_gs +Execute_AC_8_I 32_1_gr 32_1_gs +Execute_AC_8_I 32_2_gr 32_2_gs +Execute_AC_8_I 48_1_gr 32_1_gs +Execute_AC_8_I 48_2_gr 32_2_gs +Execute_AC_8_I 48_1_gr 48_1_gs +Execute_AC_8_I 48_2_gr 48_2_gs +Execute_AC_8_I 48_3_gr 32_1_gs +Execute_AC_8_I 48_4_gr 32_2_gs +Execute_AC_8_I 48_3_gr 48_1_gs +Execute_AC_8_I 48_4_gr 48_2_gs diff --git a/tests/bsim/bluetooth/audio/test_scripts/gmap_unicast_ac_8_ii.sh b/tests/bsim/bluetooth/audio/test_scripts/gmap_unicast_ac_8_ii.sh new file mode 100755 index 00000000000..35c0fba70a1 --- /dev/null +++ b/tests/bsim/bluetooth/audio/test_scripts/gmap_unicast_ac_8_ii.sh @@ -0,0 +1,52 @@ +#!/usr/bin/env bash +# +# Copyright (c) 2023 Nordic Semiconductor ASA +# +# SPDX-License-Identifier: Apache-2.0 + +SIMULATION_ID="gmap_unicast_ac_8_ii" +VERBOSITY_LEVEL=2 +EXECUTE_TIMEOUT=60 + +source ${ZEPHYR_BASE}/tests/bsim/sh_common.source + +cd ${BSIM_OUT_PATH}/bin + +function Execute_AC_8_II() { + printf "\n\n======== Running GMAP AC_8_II with %s and %s =========\n\n" $1 $2 + + Execute ./bs_${BOARD}_tests_bsim_bluetooth_audio_prj_conf \ + -v=${VERBOSITY_LEVEL} -s=${SIMULATION_ID} -d=0 -testid=gmap_ugg_ac_8_ii -RealEncryption=1 \ + -rs=23 -D=3 -argstest sink_preset $1 source_preset $2 + + Execute ./bs_${BOARD}_tests_bsim_bluetooth_audio_prj_conf \ + -v=${VERBOSITY_LEVEL} -s=${SIMULATION_ID} -d=1 -testid=gmap_ugt -RealEncryption=1 \ + -rs=46 -D=3 + + Execute ./bs_${BOARD}_tests_bsim_bluetooth_audio_prj_conf \ + -v=${VERBOSITY_LEVEL} -s=${SIMULATION_ID} -d=2 -testid=gmap_ugt -RealEncryption=1 \ + -rs=69 -D=3 + + # Simulation time should be larger than the WAIT_TIME in common.h + Execute ./bs_2G4_phy_v1 -v=${VERBOSITY_LEVEL} -s=${SIMULATION_ID} \ + -D=3 -sim_length=60e6 ${@:3} + + wait_for_background_jobs +} + +set -e # Exit on error + +Execute_AC_8_II 32_1_gr 16_1_gs +Execute_AC_8_II 32_2_gr 16_2_gs +Execute_AC_8_II 48_1_gr 16_1_gs +Execute_AC_8_II 48_2_gr 16_2_gs +Execute_AC_8_II 32_1_gr 32_1_gs +Execute_AC_8_II 32_2_gr 32_2_gs +Execute_AC_8_II 48_1_gr 32_1_gs +Execute_AC_8_II 48_2_gr 32_2_gs +Execute_AC_8_II 48_1_gr 48_1_gs +Execute_AC_8_II 48_2_gr 48_2_gs +Execute_AC_8_II 48_3_gr 32_1_gs +Execute_AC_8_II 48_4_gr 32_2_gs +Execute_AC_8_II 48_3_gr 48_1_gs +Execute_AC_8_II 48_4_gr 48_2_gs From 220a57b0b1cf31e1c5061d81e1fabd277bdde60b Mon Sep 17 00:00:00 2001 From: Kuno Heltborg Date: Wed, 9 Aug 2023 08:15:22 +0200 Subject: [PATCH 1022/3723] mgmt: mcumgr: improve custom payload types Use a flag in `c:struct:mgmt_handler` to skip the cbor start and end byte, and instead use pure custom user defined payload. Signed-off-by: Kuno Heltborg --- include/zephyr/mgmt/mcumgr/mgmt/mgmt.h | 21 ++++++++++- subsys/mgmt/mcumgr/mgmt/Kconfig | 7 ++++ subsys/mgmt/mcumgr/mgmt/src/mgmt.c | 23 +++++++++--- subsys/mgmt/mcumgr/smp/src/smp.c | 51 +++++++++++++++++--------- 4 files changed, 77 insertions(+), 25 deletions(-) diff --git a/include/zephyr/mgmt/mcumgr/mgmt/mgmt.h b/include/zephyr/mgmt/mcumgr/mgmt/mgmt.h index ed84b037633..7699dd57cc6 100644 --- a/include/zephyr/mgmt/mcumgr/mgmt/mgmt.h +++ b/include/zephyr/mgmt/mcumgr/mgmt/mgmt.h @@ -67,6 +67,7 @@ typedef int (*mgmt_handler_fn)(struct smp_streamer *ctxt); /** * @brief Read handler and write handler for a single command ID. + * Set use_custom_payload to true when using a user defined payload type */ struct mgmt_handler { mgmt_handler_fn mh_read; @@ -96,6 +97,11 @@ struct mgmt_group { */ smp_translate_error_fn mg_translate_error; #endif + +#if defined(CONFIG_MCUMGR_MGMT_CUSTOM_PAYLOAD) + /** Should be true when using user defined payload */ + bool custom_payload; +#endif }; /** @@ -126,13 +132,24 @@ const struct mgmt_handler *mgmt_find_handler(uint16_t group_id, uint16_t command /** * @brief Finds a registered command group. * - * @param group_id The command group id to find. + * @param group_id The group id of the command group to find. * - * @return The requested command group on success; + * @return The requested group on success; * NULL on failure. */ const struct mgmt_group *mgmt_find_group(uint16_t group_id); +/** + * @brief Finds a registered command handler. + * + * @param group The group of the command to find. + * @param command_id The ID of the command to find. + * + * @return The requested command handler on success; + * NULL on failure. + */ +const struct mgmt_handler *mgmt_get_handler(const struct mgmt_group *group, uint16_t command_id); + #if IS_ENABLED(CONFIG_MCUMGR_SMP_SUPPORT_ORIGINAL_PROTOCOL) /** * @brief Finds a registered error translation function for converting from SMP diff --git a/subsys/mgmt/mcumgr/mgmt/Kconfig b/subsys/mgmt/mcumgr/mgmt/Kconfig index a0c889f0c5e..32fc05fed28 100644 --- a/subsys/mgmt/mcumgr/mgmt/Kconfig +++ b/subsys/mgmt/mcumgr/mgmt/Kconfig @@ -31,3 +31,10 @@ config MCUMGR_MGMT_HANDLER_USER_DATA help This will add an extra field to the struct mgmt_handler that will allow a user to pass user_data when the defined handler is called. + +config MCUMGR_MGMT_CUSTOM_PAYLOAD + bool "MCUmgr custom payload" + help + When this config is enabled, a user can use the field `custom_payload` in `mgmt_handler` to + skip the generation of the cbor start- and end byte in `smp_handle_single_payload` and + instead use a user defined payload in SMP messages. diff --git a/subsys/mgmt/mcumgr/mgmt/src/mgmt.c b/subsys/mgmt/mcumgr/mgmt/src/mgmt.c index 56dcbb0254d..adb2c8e4bcb 100644 --- a/subsys/mgmt/mcumgr/mgmt/src/mgmt.c +++ b/subsys/mgmt/mcumgr/mgmt/src/mgmt.c @@ -72,24 +72,35 @@ mgmt_find_handler(uint16_t group_id, uint16_t command_id) const struct mgmt_group * mgmt_find_group(uint16_t group_id) { - struct mgmt_group *group = NULL; sys_snode_t *snp, *sns; /* * Find the group with the specified group id - * from the registered group list, if one exists - * return the matching mgmt group pointer, otherwise return NULL */ SYS_SLIST_FOR_EACH_NODE_SAFE(&mgmt_group_list, snp, sns) { struct mgmt_group *loop_group = CONTAINER_OF(snp, struct mgmt_group, node); if (loop_group->mg_group_id == group_id) { - group = loop_group; - break; + return loop_group; } } - return group; + return NULL; +} + +const struct mgmt_handler * +mgmt_get_handler(const struct mgmt_group *group, uint16_t command_id) +{ + if (command_id >= group->mg_handlers_count) { + return NULL; + } + + if (!group->mg_handlers[command_id].mh_read && + !group->mg_handlers[command_id].mh_write) { + return NULL; + } + + return &group->mg_handlers[command_id]; } #if IS_ENABLED(CONFIG_MCUMGR_SMP_SUPPORT_ORIGINAL_PROTOCOL) diff --git a/subsys/mgmt/mcumgr/smp/src/smp.c b/subsys/mgmt/mcumgr/smp/src/smp.c index a97beebddaa..a0004f6aa68 100644 --- a/subsys/mgmt/mcumgr/smp/src/smp.c +++ b/subsys/mgmt/mcumgr/smp/src/smp.c @@ -156,9 +156,9 @@ static int smp_build_err_rsp(struct smp_streamer *streamer, const struct smp_hdr * * @return A MGMT_ERR_[...] error code. */ -static int smp_handle_single_payload(struct smp_streamer *cbuf, const struct smp_hdr *req_hdr, - bool *handler_found) +static int smp_handle_single_payload(struct smp_streamer *cbuf, const struct smp_hdr *req_hdr) { + const struct mgmt_group *group; const struct mgmt_handler *handler; mgmt_handler_fn handler_fn; int rc; @@ -169,7 +169,12 @@ static int smp_handle_single_payload(struct smp_streamer *cbuf, const struct smp uint16_t err_group; #endif - handler = mgmt_find_handler(req_hdr->nh_group, req_hdr->nh_id); + group = mgmt_find_group(req_hdr->nh_group); + if (group == NULL) { + return MGMT_ERR_ENOTSUP; + } + + handler = mgmt_get_handler(group, req_hdr->nh_id); if (handler == NULL) { return MGMT_ERR_ENOTSUP; } @@ -190,15 +195,20 @@ static int smp_handle_single_payload(struct smp_streamer *cbuf, const struct smp if (handler_fn) { bool ok; - *handler_found = true; - ok = zcbor_map_start_encode(cbuf->writer->zs, - CONFIG_MCUMGR_SMP_CBOR_MAX_MAIN_MAP_ENTRIES); +#if defined(CONFIG_MCUMGR_MGMT_CUSTOM_PAYLOAD) + if (!group->custom_payload) { +#endif + ok = zcbor_map_start_encode(cbuf->writer->zs, + CONFIG_MCUMGR_SMP_CBOR_MAX_MAIN_MAP_ENTRIES); - MGMT_CTXT_SET_RC_RSN(cbuf, NULL); + MGMT_CTXT_SET_RC_RSN(cbuf, NULL); - if (!ok) { - return MGMT_ERR_EMSGSIZE; + if (!ok) { + return MGMT_ERR_EMSGSIZE; + } +#if defined(CONFIG_MCUMGR_MGMT_CUSTOM_PAYLOAD) } +#endif #if defined(CONFIG_MCUMGR_SMP_COMMAND_STATUS_HOOKS) cmd_recv.group = req_hdr->nh_group; @@ -231,12 +241,18 @@ static int smp_handle_single_payload(struct smp_streamer *cbuf, const struct smp #if defined(CONFIG_MCUMGR_SMP_COMMAND_STATUS_HOOKS) end: #endif - /* End response payload. */ - if (!zcbor_map_end_encode(cbuf->writer->zs, - CONFIG_MCUMGR_SMP_CBOR_MAX_MAIN_MAP_ENTRIES) && - rc == 0) { - rc = MGMT_ERR_EMSGSIZE; +#if defined(CONFIG_MCUMGR_MGMT_CUSTOM_PAYLOAD) + if (!group->custom_payload) { +#endif + /* End response payload. */ + if (!zcbor_map_end_encode(cbuf->writer->zs, + CONFIG_MCUMGR_SMP_CBOR_MAX_MAIN_MAP_ENTRIES) && + rc == 0) { + rc = MGMT_ERR_EMSGSIZE; + } +#if defined(CONFIG_MCUMGR_MGMT_CUSTOM_PAYLOAD) } +#endif } else { rc = MGMT_ERR_ENOTSUP; } @@ -256,7 +272,7 @@ static int smp_handle_single_payload(struct smp_streamer *cbuf, const struct smp * @return A MGMT_ERR_[...] error code. */ static int smp_handle_single_req(struct smp_streamer *streamer, const struct smp_hdr *req_hdr, - bool *handler_found, const char **rsn) + const char **rsn) { struct smp_hdr rsp_hdr; struct cbor_nb_writer *nbw = streamer->writer; @@ -279,7 +295,7 @@ static int smp_handle_single_req(struct smp_streamer *streamer, const struct smp } /* Process the request and write the response payload. */ - rc = smp_handle_single_payload(streamer, req_hdr, handler_found); + rc = smp_handle_single_payload(streamer, req_hdr); if (rc != 0) { *rsn = MGMT_CTXT_RC_RSN(streamer); return rc; @@ -411,7 +427,8 @@ int smp_process_request_packet(struct smp_streamer *streamer, void *vreq) cbor_nb_writer_init(streamer->writer, rsp); /* Process the request payload and build the response. */ - rc = smp_handle_single_req(streamer, &req_hdr, &handler_found, &rsn); + rc = smp_handle_single_req(streamer, &req_hdr, &rsn); + handler_found = (rc != MGMT_ERR_ENOTSUP); if (rc != 0) { break; } From 8cb870f7dec20aab62ba41847a7b5e55e66e0710 Mon Sep 17 00:00:00 2001 From: Marcio Ribeiro Date: Tue, 19 Sep 2023 14:57:44 -0300 Subject: [PATCH 1023/3723] driver: input: espressif touch_sensor Espressif touch sensor driver implemented. Signed-off-by: Marcio Ribeiro --- drivers/input/CMakeLists.txt | 1 + drivers/input/Kconfig | 1 + drivers/input/Kconfig.esp32 | 9 + drivers/input/input_esp32_touch_sensor.c | 348 ++++++++++++++++++ .../input/espressif,esp32-touch-sensor.yaml | 131 +++++++ dts/xtensa/espressif/esp32/esp32_common.dtsi | 8 + .../espressif/esp32s2/esp32s2_common.dtsi | 8 + .../espressif/esp32s3/esp32s3_common.dtsi | 8 + .../input/esp32-touch-sensor-input.h | 34 ++ 9 files changed, 548 insertions(+) create mode 100644 drivers/input/Kconfig.esp32 create mode 100644 drivers/input/input_esp32_touch_sensor.c create mode 100644 dts/bindings/input/espressif,esp32-touch-sensor.yaml create mode 100644 include/zephyr/dt-bindings/input/esp32-touch-sensor-input.h diff --git a/drivers/input/CMakeLists.txt b/drivers/input/CMakeLists.txt index d63dc2ae797..04f4878a240 100644 --- a/drivers/input/CMakeLists.txt +++ b/drivers/input/CMakeLists.txt @@ -6,6 +6,7 @@ zephyr_library_property(ALLOW_EMPTY TRUE) # zephyr-keep-sorted-start zephyr_library_sources_ifdef(CONFIG_INPUT_CAP1203 input_cap1203.c) zephyr_library_sources_ifdef(CONFIG_INPUT_CST816S input_cst816s.c) +zephyr_library_sources_ifdef(CONFIG_INPUT_ESP32_TOUCH_SENSOR input_esp32_touch_sensor.c) zephyr_library_sources_ifdef(CONFIG_INPUT_FT5336 input_ft5336.c) zephyr_library_sources_ifdef(CONFIG_INPUT_GPIO_KBD_MATRIX input_gpio_kbd_matrix.c) zephyr_library_sources_ifdef(CONFIG_INPUT_GPIO_KEYS input_gpio_keys.c) diff --git a/drivers/input/Kconfig b/drivers/input/Kconfig index afab00d4259..003f43adc58 100644 --- a/drivers/input/Kconfig +++ b/drivers/input/Kconfig @@ -8,6 +8,7 @@ menu "Input drivers" # zephyr-keep-sorted-start source "drivers/input/Kconfig.cap1203" source "drivers/input/Kconfig.cst816s" +source "drivers/input/Kconfig.esp32" source "drivers/input/Kconfig.ft5336" source "drivers/input/Kconfig.gpio_kbd_matrix" source "drivers/input/Kconfig.gpio_keys" diff --git a/drivers/input/Kconfig.esp32 b/drivers/input/Kconfig.esp32 new file mode 100644 index 00000000000..17460c94c64 --- /dev/null +++ b/drivers/input/Kconfig.esp32 @@ -0,0 +1,9 @@ +# Copyright (c) 2023 Espressif Systems (Shanghai) Co., Ltd. +# SPDX-License-Identifier: Apache-2.0 + +config INPUT_ESP32_TOUCH_SENSOR + bool "Espressif Touch Sensor input driver" + default n + depends on DT_HAS_ESPRESSIF_ESP32_TOUCH_ENABLED + help + Enable support for Espressif Touch Sensor input driver. diff --git a/drivers/input/input_esp32_touch_sensor.c b/drivers/input/input_esp32_touch_sensor.c new file mode 100644 index 00000000000..9f6858da1c7 --- /dev/null +++ b/drivers/input/input_esp32_touch_sensor.c @@ -0,0 +1,348 @@ +/* + * Copyright (c) 2023 Espressif Systems (Shanghai) Co., Ltd. + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#define DT_DRV_COMPAT espressif_esp32_touch + +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include + +LOG_MODULE_REGISTER(espressif_esp32_touch, CONFIG_INPUT_LOG_LEVEL); + +BUILD_ASSERT(!IS_ENABLED(CONFIG_COUNTER_RTC_ESP32), + "Conflict detected: COUNTER_RTC_ESP32 enabled"); + +#define ESP32_SCAN_DONE_MAX_COUNT 5 + +#if defined(CONFIG_SOC_SERIES_ESP32) +#define ESP32_RTC_INTR_MSK RTC_CNTL_TOUCH_INT_ST_M +#elif defined(CONFIG_SOC_SERIES_ESP32S2) || defined(CONFIG_SOC_SERIES_ESP32S3) + +#define ESP32_RTC_INTR_MSK (RTC_CNTL_TOUCH_DONE_INT_ST_M | \ + RTC_CNTL_TOUCH_ACTIVE_INT_ST_M | \ + RTC_CNTL_TOUCH_INACTIVE_INT_ST_M | \ + RTC_CNTL_TOUCH_SCAN_DONE_INT_ST_M | \ + RTC_CNTL_TOUCH_TIMEOUT_INT_ST_M) + +#define ESP32_TOUCH_PAD_INTR_MASK (TOUCH_PAD_INTR_MASK_ACTIVE | \ + TOUCH_PAD_INTR_MASK_INACTIVE | \ + TOUCH_PAD_INTR_MASK_TIMEOUT | \ + TOUCH_PAD_INTR_MASK_SCAN_DONE) + +#endif /* defined(CONFIG_SOC_SERIES_ESP32) */ + +struct esp32_touch_sensor_channel_config { + int32_t channel_num; + int32_t channel_sens; + uint32_t zephyr_code; +}; + +struct esp32_touch_sensor_config { + uint32_t debounce_interval_ms; + int num_channels; + int href_microvolt_enum_idx; + int lref_microvolt_enum_idx; + int href_atten_microvolt_enum_idx; + int filter_mode; + int filter_debounce_cnt; + int filter_noise_thr; + int filter_jitter_step; + int filter_smooth_level; + const struct esp32_touch_sensor_channel_config *channel_cfg; + struct esp32_touch_sensor_channel_data *channel_data; +}; + +struct esp32_touch_sensor_channel_data { + const struct device *dev; + struct k_work_delayable work; + uint32_t status; +#if defined(CONFIG_SOC_SERIES_ESP32S2) || defined(CONFIG_SOC_SERIES_ESP32S3) + uint32_t last_status; +#endif /* defined(CONFIG_SOC_SERIES_ESP32S2) || defined(CONFIG_SOC_SERIES_ESP32S3) */ +}; + +struct esp32_touch_sensor_data { + uint32_t rtc_intr_msk; +}; + +static void esp32_touch_sensor_interrupt_cb(void *arg) +{ + const struct device *dev = arg; + struct esp32_touch_sensor_data *dev_data = dev->data; + const struct esp32_touch_sensor_config *dev_cfg = dev->config; + const struct esp32_touch_sensor_channel_config *channel_cfg; + const int num_channels = dev_cfg->num_channels; + uint32_t pad_status; + +#if defined(CONFIG_SOC_SERIES_ESP32) + touch_hal_intr_clear(); + +#elif defined(CONFIG_SOC_SERIES_ESP32S2) || defined(CONFIG_SOC_SERIES_ESP32S3) + static uint8_t scan_done_counter; + + touch_pad_intr_mask_t intr_mask = touch_hal_read_intr_status_mask(); + + if (intr_mask & TOUCH_PAD_INTR_MASK_SCAN_DONE) { + if (++scan_done_counter == ESP32_SCAN_DONE_MAX_COUNT) { + touch_hal_intr_disable(TOUCH_PAD_INTR_MASK_SCAN_DONE); + for (int i = 0; i < num_channels; i++) { + channel_cfg = &dev_cfg->channel_cfg[i]; + + /* Set interrupt threshold */ + uint32_t benchmark_value; + + touch_hal_read_benchmark(channel_cfg->channel_num, + &benchmark_value); + touch_hal_set_threshold(channel_cfg->channel_num, + channel_cfg->channel_sens * benchmark_value / 100); + } + } + return; + } +#endif /* defined(CONFIG_SOC_SERIES_ESP32) */ + + touch_hal_read_trigger_status_mask(&pad_status); +#if defined(CONFIG_SOC_SERIES_ESP32) + touch_hal_clear_trigger_status_mask(); +#endif /* defined(CONFIG_SOC_SERIES_ESP32) */ + for (int i = 0; i < num_channels; i++) { + uint32_t channel_status; + + channel_cfg = &dev_cfg->channel_cfg[i]; + channel_status = (pad_status >> channel_cfg->channel_num) & 0x01; + +#if defined(CONFIG_SOC_SERIES_ESP32) + if (channel_status != 0) { +#elif defined(CONFIG_SOC_SERIES_ESP32S2) || defined(CONFIG_SOC_SERIES_ESP32S3) + uint32_t channel_num = (uint32_t)touch_hal_get_current_meas_channel(); + + if (channel_cfg->channel_num == channel_num) { +#endif /* CONFIG_SOC_SERIES_ESP32 */ + struct esp32_touch_sensor_channel_data + *channel_data = &dev_cfg->channel_data[i]; + + channel_data->status = channel_status; + (void)k_work_reschedule(&channel_data->work, + K_MSEC(dev_cfg->debounce_interval_ms)); + } + } +} + +static void esp32_rtc_isr(void *arg) +{ + uint32_t status = REG_READ(RTC_CNTL_INT_ST_REG); + + if (arg != NULL) { + const struct device *dev = arg; + struct esp32_touch_sensor_data *dev_data = dev->data; + + if (dev_data->rtc_intr_msk & status) { + esp32_touch_sensor_interrupt_cb(arg); + } + } + + REG_WRITE(RTC_CNTL_INT_CLR_REG, status); +} + +static esp_err_t esp32_rtc_isr_install(intr_handler_t intr_handler, const void *handler_arg) +{ + esp_err_t err; + + REG_WRITE(RTC_CNTL_INT_ENA_REG, 0); + REG_WRITE(RTC_CNTL_INT_CLR_REG, UINT32_MAX); + err = esp_intr_alloc(ETS_RTC_CORE_INTR_SOURCE, 0, intr_handler, (void *)handler_arg, NULL); + + return err; +} + +/** + * Handle debounced touch sensor touch state. + */ +static void esp32_touch_sensor_change_deferred(struct k_work *work) +{ + struct k_work_delayable *dwork = k_work_delayable_from_work(work); + struct esp32_touch_sensor_channel_data *channel_data = + CONTAINER_OF(dwork, struct esp32_touch_sensor_channel_data, work); + const struct device *dev = channel_data->dev; + const struct esp32_touch_sensor_config *dev_cfg = dev->config; + int key_index = channel_data - &dev_cfg->channel_data[0]; + const struct esp32_touch_sensor_channel_config + *channel_cfg = &dev_cfg->channel_cfg[key_index]; + +#if defined(CONFIG_SOC_SERIES_ESP32S2) || defined(CONFIG_SOC_SERIES_ESP32S3) + if (channel_data->last_status != channel_data->status) { +#endif /* defined(CONFIG_SOC_SERIES_ESP32S2) || defined(CONFIG_SOC_SERIES_ESP32S3) */ + input_report_key(dev, channel_cfg->zephyr_code, + channel_data->status, true, K_FOREVER); +#if defined(CONFIG_SOC_SERIES_ESP32S2) || defined(CONFIG_SOC_SERIES_ESP32S3) + channel_data->last_status = channel_data->status; + } +#endif /* defined(CONFIG_SOC_SERIES_ESP32S2) || defined(CONFIG_SOC_SERIES_ESP32S3) */ +} + +static int esp32_touch_sensor_init(const struct device *dev) +{ + struct esp32_touch_sensor_data *dev_data = dev->data; + const struct esp32_touch_sensor_config *dev_cfg = dev->config; + const int num_channels = dev_cfg->num_channels; + + touch_hal_init(); + +#if defined(CONFIG_SOC_SERIES_ESP32) + touch_hal_volt_t volt = { + .refh = dev_cfg->href_microvolt_enum_idx, + .refh = dev_cfg->href_microvolt_enum_idx, + .atten = dev_cfg->href_atten_microvolt_enum_idx + }; + + touch_hal_set_voltage(&volt); + touch_hal_set_fsm_mode(TOUCH_FSM_MODE_TIMER); +#endif /* defined(CONFIG_SOC_SERIES_ESP32) */ + + for (int i = 0; i < num_channels; i++) { + struct esp32_touch_sensor_channel_data *channel_data = &dev_cfg->channel_data[i]; + const struct esp32_touch_sensor_channel_config *channel_cfg = + &dev_cfg->channel_cfg[i]; + + if (!(channel_cfg->channel_num > 0 && + channel_cfg->channel_num < SOC_TOUCH_SENSOR_NUM)) { + LOG_ERR("Touch %d configuration failed: " + "Touch channel error", i); + return -EINVAL; + } + +#if defined(CONFIG_SOC_SERIES_ESP32S2) || defined(CONFIG_SOC_SERIES_ESP32S3) + if (channel_cfg->channel_num == SOC_TOUCH_DENOISE_CHANNEL) { + LOG_ERR("Touch %d configuration failed: " + "TOUCH0 is internal denoise channel", i); + return -EINVAL; + } +#endif /* defined(CONFIG_SOC_SERIES_ESP32S2) || defined(CONFIG_SOC_SERIES_ESP32S3) */ + + gpio_num_t gpio_num = touch_sensor_channel_io_map[channel_cfg->channel_num]; + + rtc_gpio_init(gpio_num); + rtc_gpio_set_direction(gpio_num, RTC_GPIO_MODE_DISABLED); + rtc_gpio_pulldown_dis(gpio_num); + rtc_gpio_pullup_dis(gpio_num); + + touch_hal_config(channel_cfg->channel_num); +#if defined(CONFIG_SOC_SERIES_ESP32) + touch_hal_set_threshold(channel_cfg->channel_num, 0); + touch_hal_set_group_mask(BIT(channel_cfg->channel_num), + BIT(channel_cfg->channel_num)); +#endif /* defined(CONFIG_SOC_SERIES_ESP32) */ + touch_hal_set_channel_mask(BIT(channel_cfg->channel_num)); + + channel_data->status = 0; +#if defined(CONFIG_SOC_SERIES_ESP32S2) || defined(CONFIG_SOC_SERIES_ESP32S3) + channel_data->last_status = 0; +#endif /* defined(CONFIG_SOC_SERIES_ESP32S2) || defined(CONFIG_SOC_SERIES_ESP32S3) */ + channel_data->dev = dev; + + k_work_init_delayable(&channel_data->work, esp32_touch_sensor_change_deferred); + } + +#if defined(CONFIG_SOC_SERIES_ESP32) + for (int i = 0; i < num_channels; i++) { + const struct esp32_touch_sensor_channel_config *channel_cfg = + &dev_cfg->channel_cfg[i]; + uint32_t ref_time; + + ref_time = k_uptime_get_32(); + while (!touch_hal_meas_is_done()) { + if (k_uptime_get_32() - ref_time > 500) { + return -ETIMEDOUT; + } + k_busy_wait(1000); + } + uint16_t touch_value = touch_hal_read_raw_data(channel_cfg->channel_num); + + touch_hal_set_threshold(channel_cfg->channel_num, + touch_value * (100 - channel_cfg->channel_num) / 100); + } + +#elif defined(CONFIG_SOC_SERIES_ESP32S2) || defined(CONFIG_SOC_SERIES_ESP32S3) + touch_filter_config_t filter_info = { + .mode = dev_cfg->filter_mode, + .debounce_cnt = dev_cfg->filter_debounce_cnt, + .noise_thr = dev_cfg->filter_noise_thr, + .jitter_step = dev_cfg->filter_jitter_step, + .smh_lvl = dev_cfg->filter_smooth_level, + }; + touch_hal_filter_set_config(&filter_info); + touch_hal_filter_enable(); + + touch_hal_timeout_enable(); + touch_hal_timeout_set_threshold(SOC_TOUCH_PAD_THRESHOLD_MAX); +#endif /* defined(CONFIG_SOC_SERIES_ESP32) */ + + dev_data->rtc_intr_msk = ESP32_RTC_INTR_MSK; + esp32_rtc_isr_install(&esp32_rtc_isr, dev); +#if defined(CONFIG_SOC_SERIES_ESP32) + touch_hal_intr_enable(); +#elif defined(CONFIG_SOC_SERIES_ESP32S2) || defined(CONFIG_SOC_SERIES_ESP32S3) + touch_hal_intr_enable(ESP32_TOUCH_PAD_INTR_MASK); + touch_hal_set_fsm_mode(TOUCH_FSM_MODE_TIMER); +#endif /* defined(CONFIG_SOC_SERIES_ESP32) */ + + touch_hal_start_fsm(); + + return 0; +} + +#define ESP32_TOUCH_SENSOR_CHANNEL_CFG_INIT(node_id) \ + { \ + .channel_num = DT_PROP(node_id, channel_num), \ + .channel_sens = DT_PROP(node_id, channel_sens), \ + .zephyr_code = DT_PROP(node_id, zephyr_code), \ + } + +#define ESP32_TOUCH_SENSOR_INIT(inst) \ + static const struct esp32_touch_sensor_channel_config \ + esp32_touch_sensor_channel_config_##inst[] = { \ + DT_INST_FOREACH_CHILD_STATUS_OKAY_SEP(inst, \ + ESP32_TOUCH_SENSOR_CHANNEL_CFG_INIT, (,)) \ + }; \ + \ + static struct esp32_touch_sensor_channel_data esp32_touch_sensor_channel_data_##inst \ + [ARRAY_SIZE(esp32_touch_sensor_channel_config_##inst)]; \ + \ + static const struct esp32_touch_sensor_config esp32_touch_sensor_config_##inst = { \ + .debounce_interval_ms = DT_INST_PROP(inst, debounce_interval_ms), \ + .num_channels = ARRAY_SIZE(esp32_touch_sensor_channel_config_##inst), \ + .href_microvolt_enum_idx = DT_INST_ENUM_IDX(inst, href_microvolt), \ + .lref_microvolt_enum_idx = DT_INST_ENUM_IDX(inst, lref_microvolt), \ + .href_atten_microvolt_enum_idx = DT_INST_ENUM_IDX(inst, href_atten_microvolt), \ + .filter_mode = DT_INST_PROP(inst, filter_mode), \ + .filter_debounce_cnt = DT_INST_PROP(inst, filter_debounce_cnt), \ + .filter_noise_thr = DT_INST_PROP(inst, filter_noise_thr), \ + .filter_jitter_step = DT_INST_PROP(inst, filter_jitter_step), \ + .filter_smooth_level = DT_INST_PROP(inst, filter_smooth_level), \ + .channel_cfg = esp32_touch_sensor_channel_config_##inst, \ + .channel_data = esp32_touch_sensor_channel_data_##inst, \ + }; \ + \ + static struct esp32_touch_sensor_data esp32_touch_sensor_data_##inst; \ + \ + DEVICE_DT_INST_DEFINE(inst, \ + &esp32_touch_sensor_init, \ + NULL, \ + &esp32_touch_sensor_data_##inst, \ + &esp32_touch_sensor_config_##inst, \ + POST_KERNEL, CONFIG_INPUT_INIT_PRIORITY, \ + NULL); + +DT_INST_FOREACH_STATUS_OKAY(ESP32_TOUCH_SENSOR_INIT) diff --git a/dts/bindings/input/espressif,esp32-touch-sensor.yaml b/dts/bindings/input/espressif,esp32-touch-sensor.yaml new file mode 100644 index 00000000000..7fe6a01d0c7 --- /dev/null +++ b/dts/bindings/input/espressif,esp32-touch-sensor.yaml @@ -0,0 +1,131 @@ +# Copyright (c) 2023 Espressif Systems (Shanghai) Co., Ltd. +# SPDX-License-Identifier: Apache-2.0 + +description: | + Zephyr input touch sensor parent node + + This defines a group of touch sensors that can generate input events. Each touch + sensor is defined in a child node of the touch-sensor node and defines a specific key + code. + + For example: + + #include + #include + + &touch { + compatible = "espressif,esp32-touch"; + status = "okay"; + + debounce-interval-ms = <30>; + href-microvolt = <27000000>; + lref-microvolt = <500000>; + href-atten-microvolt = <1000000>; + filter-mode = ; + filter-debounce-cnt = <1>; + filter-noise-thr = ; + filter-jitter-step = <4>; + filter-smooth-level = ; + + touch_sensor_0 { + channel_num = <1>; + channel_sens = <20>; + zephyr,code = ; + }; + }; + + +compatible: "espressif,esp32-touch" + +include: base.yaml + +properties: + debounce-interval-ms: + type: int + default: 30 + description: Debouncing interval time in milliseconds. + + href-microvolt: + type: int + enum: + - 2400000 + - 2500000 + - 2500000 + - 2700000 + default: 2700000 + description: Touch sensor high reference voltage. + + lref-microvolt: + type: int + enum: + - 500000 + - 600000 + - 700000 + - 800000 + default: 500000 + description: Touch sensor low reference voltage. + + href-atten-microvolt: + type: int + enum: + - 1500000 + - 1000000 + - 500000 + - 0 + default: 1000000 + description: Touch sensor high reference attenuation voltage. + + filter-mode: + type: int + default: 2 + description: | + Touch sensor IIR filter coefficient. + If not specified defaults to ESP32_TOUCH_FILTER_MODE_IIR_16. + + filter-debounce-cnt: + type: int + default: 1 + description: | + Touch sensor debounce count. + If not specified defaults to 1. + + filter-noise-thr: + type: int + default: 0 + description: | + Touch sensor noise threshold coefficient. + If not specified defaults to ESP32_TOUCH_FILTER_NOISE_THR_4_8TH. + + filter-jitter-step: + type: int + default: 4 + description: | + Touch sensor jitter filter step size. + If not specified defaults to 4. + + filter-smooth-level: + type: int + default: 1 + description: | + Touch sensor level of filter applied on the original data against large noise interference. + If not specified defaults to ESP32_TOUCH_FILTER_SMOOTH_MODE_IIR_2. + +child-binding: + description: Touch sensor child node + properties: + channel-num: + type: int + required: true + description: Touch sensor channel number + + channel-sens: + type: int + default: 20 + description: | + Touch sensor channel sensibility in 100th. + If not specified defaults to 20. + + zephyr,code: + type: int + required: true + description: Key code to emit. diff --git a/dts/xtensa/espressif/esp32/esp32_common.dtsi b/dts/xtensa/espressif/esp32/esp32_common.dtsi index 0f61150cead..b7aba9f2350 100644 --- a/dts/xtensa/espressif/esp32/esp32_common.dtsi +++ b/dts/xtensa/espressif/esp32/esp32_common.dtsi @@ -271,6 +271,14 @@ }; }; + touch: touch@3ff48858 { + compatible = "espressif,esp32-touch"; + reg = <0x3ff48858 0x38>; + interrupts = ; + interrupt-parent = <&intc>; + status = "disabled"; + }; + i2c0: i2c@3ff53000 { compatible = "espressif,esp32-i2c"; #address-cells = <1>; diff --git a/dts/xtensa/espressif/esp32s2/esp32s2_common.dtsi b/dts/xtensa/espressif/esp32s2/esp32s2_common.dtsi index b523ec53364..727b26e4a53 100644 --- a/dts/xtensa/espressif/esp32s2/esp32s2_common.dtsi +++ b/dts/xtensa/espressif/esp32s2/esp32s2_common.dtsi @@ -184,6 +184,14 @@ ngpios = <22>; /* 32..53 */ }; + touch: touch@3f40885c { + compatible = "espressif,esp32-touch"; + reg = <0x3f40885c 0xc0 0x3f408104 0x18>; + interrupts = ; + interrupt-parent = <&intc>; + status = "disabled"; + }; + i2c0: i2c@3f413000 { compatible = "espressif,esp32-i2c"; #address-cells = <1>; diff --git a/dts/xtensa/espressif/esp32s3/esp32s3_common.dtsi b/dts/xtensa/espressif/esp32s3/esp32s3_common.dtsi index 65880b3afbc..27a90f797d0 100644 --- a/dts/xtensa/espressif/esp32s3/esp32s3_common.dtsi +++ b/dts/xtensa/espressif/esp32s3/esp32s3_common.dtsi @@ -198,6 +198,14 @@ }; }; + touch: touch@6000885c { + compatible = "espressif,esp32-touch"; + reg = <0x6000885c 0x88 0x60008908 0x18>; + interrupts = ; + interrupt-parent = <&intc>; + status = "disabled"; + }; + i2c0: i2c@60013000 { compatible = "espressif,esp32-i2c"; #address-cells = <1>; diff --git a/include/zephyr/dt-bindings/input/esp32-touch-sensor-input.h b/include/zephyr/dt-bindings/input/esp32-touch-sensor-input.h new file mode 100644 index 00000000000..83a8035551f --- /dev/null +++ b/include/zephyr/dt-bindings/input/esp32-touch-sensor-input.h @@ -0,0 +1,34 @@ +/* + * Copyright (c) 2023 Espressif Systems (Shanghai) Co., Ltd. + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#ifndef ZEPHYR_INCLUDE_DT_BINDINGS_INPUT_ESP32_TOUCH_SENSOR_INPUT_H_ +#define ZEPHYR_INCLUDE_DT_BINDINGS_INPUT_ESP32_TOUCH_SENSOR_INPUT_H_ + +#include + +/* Touch sensor IIR filter mode */ +#define ESP32_TOUCH_FILTER_MODE_IIR_4 0 +#define ESP32_TOUCH_FILTER_MODE_IIR_8 1 +#define ESP32_TOUCH_FILTER_MODE_IIR_16 2 +#define ESP32_TOUCH_FILTER_MODE_IIR_32 3 +#define ESP32_TOUCH_FILTER_MODE_IIR_64 4 +#define ESP32_TOUCH_FILTER_MODE_IIR_128 5 +#define ESP32_TOUCH_FILTER_MODE_IIR_256 6 +#define ESP32_TOUCH_FILTER_MODE_JITTER 7 + +/* Touch sensor level of filter noise threshold coefficient*/ +#define ESP32_TOUCH_FILTER_NOISE_THR_4_8TH 0 +#define ESP32_TOUCH_FILTER_NOISE_THR_3_8TH 1 +#define ESP32_TOUCH_FILTER_NOISE_THR_2_8TH 2 +#define ESP32_TOUCH_FILTER_NOISE_THR_8_8TH 3 + +/* Touch sensor level of filter applied on the original data */ +#define ESP32_TOUCH_FILTER_SMOOTH_MODE_OFF 0 +#define ESP32_TOUCH_FILTER_SMOOTH_MODE_IIR_2 1 +#define ESP32_TOUCH_FILTER_SMOOTH_MODE_IIR_4 2 +#define ESP32_TOUCH_FILTER_SMOOTH_MODE_IIR_8 3 + +#endif /* ZEPHYR_INCLUDE_DT_BINDINGS_INPUT_ESP32_TOUCH_SENSOR_INPUT_H_ */ From a9eb01ea4f1d07744912b0aaa1b976fe4334e18a Mon Sep 17 00:00:00 2001 From: Marcio Ribeiro Date: Tue, 31 Oct 2023 11:24:59 -0300 Subject: [PATCH 1024/3723] boards: xtensa: esp32 board files update touch_sensors default parameter added to .dts files and input driver added to .yaml supported features array of: - esp32_devkitc_wroom - esp32_devkitc_wrover - esp32s2_saola - esp32s3_devkitm Signed-off-by: Marcio Ribeiro --- .../esp32_devkitc_wroom/esp32_devkitc_wroom.dts | 13 +++++++++++++ .../esp32_devkitc_wroom/esp32_devkitc_wroom.yaml | 1 + .../esp32_devkitc_wrover/esp32_devkitc_wrover.dts | 13 +++++++++++++ .../esp32_devkitc_wrover/esp32_devkitc_wrover.yaml | 1 + boards/xtensa/esp32s2_saola/esp32s2_saola.dts | 13 +++++++++++++ boards/xtensa/esp32s2_saola/esp32s2_saola.yaml | 1 + boards/xtensa/esp32s3_devkitm/esp32s3_devkitm.dts | 13 +++++++++++++ boards/xtensa/esp32s3_devkitm/esp32s3_devkitm.yaml | 1 + 8 files changed, 56 insertions(+) diff --git a/boards/xtensa/esp32_devkitc_wroom/esp32_devkitc_wroom.dts b/boards/xtensa/esp32_devkitc_wroom/esp32_devkitc_wroom.dts index ef6d619676c..a33384c2a5c 100644 --- a/boards/xtensa/esp32_devkitc_wroom/esp32_devkitc_wroom.dts +++ b/boards/xtensa/esp32_devkitc_wroom/esp32_devkitc_wroom.dts @@ -8,6 +8,7 @@ #include #include "esp32_devkitc_wroom-pinctrl.dtsi" #include +#include / { model = "Espressif ESP32-DEVKITC-WROOM-32D"; @@ -74,6 +75,18 @@ status = "okay"; }; +&touch { + debounce-interval-ms = <30>; + href-microvolt = <2700000>; + lref-microvolt = <500000>; + href-atten-microvolt = <1000000>; + filter-mode = ; + filter-debounce-cnt = <1>; + filter-noise-thr = ; + filter-jitter-step = <4>; + filter-smooth-level = ; +}; + &i2c0 { status = "okay"; clock-frequency = ; diff --git a/boards/xtensa/esp32_devkitc_wroom/esp32_devkitc_wroom.yaml b/boards/xtensa/esp32_devkitc_wroom/esp32_devkitc_wroom.yaml index 0481a96df00..19155f8a0d1 100644 --- a/boards/xtensa/esp32_devkitc_wroom/esp32_devkitc_wroom.yaml +++ b/boards/xtensa/esp32_devkitc_wroom/esp32_devkitc_wroom.yaml @@ -17,6 +17,7 @@ supported: - spi - counter - entropy + - input testing: ignore_tags: - net diff --git a/boards/xtensa/esp32_devkitc_wrover/esp32_devkitc_wrover.dts b/boards/xtensa/esp32_devkitc_wrover/esp32_devkitc_wrover.dts index d4cbdce3d90..d62fe5ccfb8 100644 --- a/boards/xtensa/esp32_devkitc_wrover/esp32_devkitc_wrover.dts +++ b/boards/xtensa/esp32_devkitc_wrover/esp32_devkitc_wrover.dts @@ -8,6 +8,7 @@ #include #include "esp32_devkitc_wrover-pinctrl.dtsi" #include +#include / { model = "Espressif ESP32-DEVKITC-WROVER-E"; @@ -73,6 +74,18 @@ status = "okay"; }; +&touch { + debounce-interval-ms = <30>; + href-microvolt = <2700000>; + lref-microvolt = <500000>; + href-atten-microvolt = <1000000>; + filter-mode = ; + filter-debounce-cnt = <1>; + filter-noise-thr = ; + filter-jitter-step = <4>; + filter-smooth-level = ; +}; + &i2c0 { status = "okay"; clock-frequency = ; diff --git a/boards/xtensa/esp32_devkitc_wrover/esp32_devkitc_wrover.yaml b/boards/xtensa/esp32_devkitc_wrover/esp32_devkitc_wrover.yaml index 7ae68f8e9de..df56a1dbc55 100644 --- a/boards/xtensa/esp32_devkitc_wrover/esp32_devkitc_wrover.yaml +++ b/boards/xtensa/esp32_devkitc_wrover/esp32_devkitc_wrover.yaml @@ -17,6 +17,7 @@ supported: - spi - counter - entropy + - input testing: ignore_tags: - net diff --git a/boards/xtensa/esp32s2_saola/esp32s2_saola.dts b/boards/xtensa/esp32s2_saola/esp32s2_saola.dts index 61787f0051a..781f4b758d6 100644 --- a/boards/xtensa/esp32s2_saola/esp32s2_saola.dts +++ b/boards/xtensa/esp32s2_saola/esp32s2_saola.dts @@ -9,6 +9,7 @@ #include #include "esp32s2_saola-pinctrl.dtsi" #include +#include / { model = "esp32s2_saola"; @@ -57,6 +58,18 @@ status = "okay"; }; +&touch { + debounce-interval-ms = <30>; + href-microvolt = <2700000>; + lref-microvolt = <500000>; + href-atten-microvolt = <1000000>; + filter-mode = ; + filter-debounce-cnt = <1>; + filter-noise-thr = ; + filter-jitter-step = <4>; + filter-smooth-level = ; +}; + &timer0 { status = "disabled"; }; diff --git a/boards/xtensa/esp32s2_saola/esp32s2_saola.yaml b/boards/xtensa/esp32s2_saola/esp32s2_saola.yaml index 261d7d0eb8f..1e1e391bb0e 100644 --- a/boards/xtensa/esp32s2_saola/esp32s2_saola.yaml +++ b/boards/xtensa/esp32s2_saola/esp32s2_saola.yaml @@ -16,6 +16,7 @@ supported: - spi - counter - entropy + - input testing: ignore_tags: - net diff --git a/boards/xtensa/esp32s3_devkitm/esp32s3_devkitm.dts b/boards/xtensa/esp32s3_devkitm/esp32s3_devkitm.dts index 5d80b0619e9..640304ee00f 100644 --- a/boards/xtensa/esp32s3_devkitm/esp32s3_devkitm.dts +++ b/boards/xtensa/esp32s3_devkitm/esp32s3_devkitm.dts @@ -8,6 +8,7 @@ #include #include "esp32s3_devkitm-pinctrl.dtsi" #include +#include / { model = "esp32s3_devkitm"; @@ -68,6 +69,18 @@ status = "okay"; }; +&touch { + debounce-interval-ms = <30>; + href-microvolt = <2700000>; + lref-microvolt = <500000>; + href-atten-microvolt = <1000000>; + filter-mode = ; + filter-debounce-cnt = <1>; + filter-noise-thr = ; + filter-jitter-step = <4>; + filter-smooth-level = ; +}; + &i2c0 { clock-frequency = ; pinctrl-0 = <&i2c0_default>; diff --git a/boards/xtensa/esp32s3_devkitm/esp32s3_devkitm.yaml b/boards/xtensa/esp32s3_devkitm/esp32s3_devkitm.yaml index 160e01f4d6e..cce4cb8b82e 100644 --- a/boards/xtensa/esp32s3_devkitm/esp32s3_devkitm.yaml +++ b/boards/xtensa/esp32s3_devkitm/esp32s3_devkitm.yaml @@ -15,6 +15,7 @@ supported: - entropy - pwm - dma + - input testing: ignore_tags: - net From 7543386f83deecda9bed68cfd8575b2a1a0c3f7e Mon Sep 17 00:00:00 2001 From: Marcio Ribeiro Date: Mon, 6 Nov 2023 16:32:50 -0300 Subject: [PATCH 1025/3723] samples: input: espressif boards added to input_dump Added some board overlay files to permit input touch sensor testing: - esp32_devkitc_wroom - esp32_devkitc_wrover - esp32s2_saola - esp32s3_devkitm Signed-off-by: Marcio Ribeiro --- .../boards/esp32_devkitc_wroom.overlay | 36 +++++++++++++++++++ .../boards/esp32_devkitc_wrover.overlay | 36 +++++++++++++++++++ .../input_dump/boards/esp32s2_saola.overlay | 36 +++++++++++++++++++ .../input_dump/boards/esp32s3_devkitm.overlay | 36 +++++++++++++++++++ 4 files changed, 144 insertions(+) create mode 100644 samples/subsys/input/input_dump/boards/esp32_devkitc_wroom.overlay create mode 100644 samples/subsys/input/input_dump/boards/esp32_devkitc_wrover.overlay create mode 100644 samples/subsys/input/input_dump/boards/esp32s2_saola.overlay create mode 100644 samples/subsys/input/input_dump/boards/esp32s3_devkitm.overlay diff --git a/samples/subsys/input/input_dump/boards/esp32_devkitc_wroom.overlay b/samples/subsys/input/input_dump/boards/esp32_devkitc_wroom.overlay new file mode 100644 index 00000000000..3ed71e8b137 --- /dev/null +++ b/samples/subsys/input/input_dump/boards/esp32_devkitc_wroom.overlay @@ -0,0 +1,36 @@ +/* + * Copyright (c) 2023 Espressif Systems (Shanghai) Co., Ltd. + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include +#include + +&touch { + status = "okay"; + + touch_sensor_set: touch_sensor_0 { + channel-num = <9>; + channel-sens = <20>; + zephyr,code = ; + }; + + touch_sensor_play: touch_sensor_1 { + channel-num = <8>; + channel-sens = <20>; + zephyr,code = ; + }; + + touch_sensor_vol_inc: touch_sensor_2 { + channel-num = <6>; + channel-sens = <20>; + zephyr,code = ; + }; + + touch_sensor_vol_dec: touch_sensor_3 { + channel-num = <4>; + channel-sens = <20>; + zephyr,code = ; + }; +}; diff --git a/samples/subsys/input/input_dump/boards/esp32_devkitc_wrover.overlay b/samples/subsys/input/input_dump/boards/esp32_devkitc_wrover.overlay new file mode 100644 index 00000000000..3ed71e8b137 --- /dev/null +++ b/samples/subsys/input/input_dump/boards/esp32_devkitc_wrover.overlay @@ -0,0 +1,36 @@ +/* + * Copyright (c) 2023 Espressif Systems (Shanghai) Co., Ltd. + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include +#include + +&touch { + status = "okay"; + + touch_sensor_set: touch_sensor_0 { + channel-num = <9>; + channel-sens = <20>; + zephyr,code = ; + }; + + touch_sensor_play: touch_sensor_1 { + channel-num = <8>; + channel-sens = <20>; + zephyr,code = ; + }; + + touch_sensor_vol_inc: touch_sensor_2 { + channel-num = <6>; + channel-sens = <20>; + zephyr,code = ; + }; + + touch_sensor_vol_dec: touch_sensor_3 { + channel-num = <4>; + channel-sens = <20>; + zephyr,code = ; + }; +}; diff --git a/samples/subsys/input/input_dump/boards/esp32s2_saola.overlay b/samples/subsys/input/input_dump/boards/esp32s2_saola.overlay new file mode 100644 index 00000000000..3ed71e8b137 --- /dev/null +++ b/samples/subsys/input/input_dump/boards/esp32s2_saola.overlay @@ -0,0 +1,36 @@ +/* + * Copyright (c) 2023 Espressif Systems (Shanghai) Co., Ltd. + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include +#include + +&touch { + status = "okay"; + + touch_sensor_set: touch_sensor_0 { + channel-num = <9>; + channel-sens = <20>; + zephyr,code = ; + }; + + touch_sensor_play: touch_sensor_1 { + channel-num = <8>; + channel-sens = <20>; + zephyr,code = ; + }; + + touch_sensor_vol_inc: touch_sensor_2 { + channel-num = <6>; + channel-sens = <20>; + zephyr,code = ; + }; + + touch_sensor_vol_dec: touch_sensor_3 { + channel-num = <4>; + channel-sens = <20>; + zephyr,code = ; + }; +}; diff --git a/samples/subsys/input/input_dump/boards/esp32s3_devkitm.overlay b/samples/subsys/input/input_dump/boards/esp32s3_devkitm.overlay new file mode 100644 index 00000000000..3ed71e8b137 --- /dev/null +++ b/samples/subsys/input/input_dump/boards/esp32s3_devkitm.overlay @@ -0,0 +1,36 @@ +/* + * Copyright (c) 2023 Espressif Systems (Shanghai) Co., Ltd. + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include +#include + +&touch { + status = "okay"; + + touch_sensor_set: touch_sensor_0 { + channel-num = <9>; + channel-sens = <20>; + zephyr,code = ; + }; + + touch_sensor_play: touch_sensor_1 { + channel-num = <8>; + channel-sens = <20>; + zephyr,code = ; + }; + + touch_sensor_vol_inc: touch_sensor_2 { + channel-num = <6>; + channel-sens = <20>; + zephyr,code = ; + }; + + touch_sensor_vol_dec: touch_sensor_3 { + channel-num = <4>; + channel-sens = <20>; + zephyr,code = ; + }; +}; From 02c5cd28db2ff4ff2144ed536f252897fbab547a Mon Sep 17 00:00:00 2001 From: Joakim Andersson Date: Tue, 28 Nov 2023 15:45:22 +0100 Subject: [PATCH 1026/3723] tfm: Fix indentation of help text for BUILD_WITH_TFM Fix indentation of help text for BUILD_WITH_TFM. Signed-off-by: Joakim Andersson --- modules/trusted-firmware-m/Kconfig.tfm | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/trusted-firmware-m/Kconfig.tfm b/modules/trusted-firmware-m/Kconfig.tfm index 6c8db28c098..3c2e415cb38 100644 --- a/modules/trusted-firmware-m/Kconfig.tfm +++ b/modules/trusted-firmware-m/Kconfig.tfm @@ -44,7 +44,7 @@ menuconfig BUILD_WITH_TFM Notes: Building with the "_ns" BOARD variant (e.g. "mps2_an521_ns") - ensures that CONFIG_TRUSTED_EXECUTION_NONSECURE is enabled. + ensures that CONFIG_TRUSTED_EXECUTION_NONSECURE is enabled. By default we allow Zephyr preemptible threads be preempted while performing a secure function call. From 44106dac56b530d21f3682bfe1f215349f64e3de Mon Sep 17 00:00:00 2001 From: Joakim Andersson Date: Tue, 28 Nov 2023 15:46:31 +0100 Subject: [PATCH 1027/3723] tfm: Update prompt for profile not set Update prompt for profile type not set, make it appear in a similar way as the rest of the options in the choice. Add in parethesis "base", which is how this referred to in the upstream TF-M documentation. Signed-off-by: Joakim Andersson --- modules/trusted-firmware-m/Kconfig.tfm | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/trusted-firmware-m/Kconfig.tfm b/modules/trusted-firmware-m/Kconfig.tfm index 3c2e415cb38..cefd8b85514 100644 --- a/modules/trusted-firmware-m/Kconfig.tfm +++ b/modules/trusted-firmware-m/Kconfig.tfm @@ -91,7 +91,7 @@ choice TFM_PROFILE_TYPE isolation level. config TFM_PROFILE_TYPE_NOT_SET - bool "TF-M build profile is not set" + bool "TF-M build profile: not set (base)" config TFM_PROFILE_TYPE_SMALL bool "TF-M build profile: small" From 3b0b33b726dc7a182b0f8957c20bb74c98826b92 Mon Sep 17 00:00:00 2001 From: Joakim Andersson Date: Tue, 28 Nov 2023 15:48:15 +0100 Subject: [PATCH 1028/3723] tfm: Add profile choice selection for Medium without ARoT enabled Add profile choice selection for Medium without ARoT enabled. Signed-off-by: Joakim Andersson --- modules/trusted-firmware-m/Kconfig.tfm | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/modules/trusted-firmware-m/Kconfig.tfm b/modules/trusted-firmware-m/Kconfig.tfm index cefd8b85514..f6d13a22153 100644 --- a/modules/trusted-firmware-m/Kconfig.tfm +++ b/modules/trusted-firmware-m/Kconfig.tfm @@ -74,6 +74,7 @@ config TFM_PROFILE depends on BUILD_WITH_TFM default "profile_small" if TFM_PROFILE_TYPE_SMALL default "profile_medium" if TFM_PROFILE_TYPE_MEDIUM + default "profile_medium_arotless" if TFM_PROFILE_TYPE_AROTLESS default "profile_large" if TFM_PROFILE_TYPE_LARGE help Build profile used to build tfm_s image. The available values are @@ -99,6 +100,9 @@ config TFM_PROFILE_TYPE_SMALL config TFM_PROFILE_TYPE_MEDIUM bool "TF-M build profile: medium" +config TFM_PROFILE_TYPE_AROTLESS + bool "TF-M build profile: ARoT-less" + config TFM_PROFILE_TYPE_LARGE bool "TF-M build profile: large" From a1358aaedf0d10d5c105a7b0d79e48f16be6cacf Mon Sep 17 00:00:00 2001 From: Burt Silverman Date: Fri, 8 Dec 2023 22:30:22 -0500 Subject: [PATCH 1029/3723] sys: Modify ATOMIC_BITMAP_SIZE macro: num_bits = 0 The macro returned the wrong value for any case in which num_bits<=0, due to a signed/unsigned division. The num_bits=0 case was hit using static analysis in a Nordic Semiconductor SDK case. Signed-off-by: Burt Silverman --- include/zephyr/sys/atomic.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/include/zephyr/sys/atomic.h b/include/zephyr/sys/atomic.h index 8618e1bf903..266f6b1391b 100644 --- a/include/zephyr/sys/atomic.h +++ b/include/zephyr/sys/atomic.h @@ -87,7 +87,7 @@ extern "C" { * * @param num_bits Number of bits. */ -#define ATOMIC_BITMAP_SIZE(num_bits) (1 + ((num_bits) - 1) / ATOMIC_BITS) +#define ATOMIC_BITMAP_SIZE(num_bits) (ROUND_UP(num_bits, ATOMIC_BITS) / ATOMIC_BITS) /** * @brief Define an array of atomic variables. From 157b22e5ec92ed20ae654a3f2e5193fa79cb23f8 Mon Sep 17 00:00:00 2001 From: Pieter De Gendt Date: Mon, 11 Dec 2023 08:44:26 +0100 Subject: [PATCH 1030/3723] doc: connectivity: networking: api: Add doxygengroup for coap_mgmt Make sure the CoAP event doxygen is added to the documentation. Signed-off-by: Pieter De Gendt --- doc/connectivity/networking/api/coap_server.rst | 1 + 1 file changed, 1 insertion(+) diff --git a/doc/connectivity/networking/api/coap_server.rst b/doc/connectivity/networking/api/coap_server.rst index 13b4aa9491e..f80bf42ada7 100644 --- a/doc/connectivity/networking/api/coap_server.rst +++ b/doc/connectivity/networking/api/coap_server.rst @@ -281,3 +281,4 @@ API Reference ************* .. doxygengroup:: coap_service +.. doxygengroup:: coap_mgmt From 0880dbee926d549f5081a5bc1c70728470915993 Mon Sep 17 00:00:00 2001 From: Jukka Rissanen Date: Mon, 11 Dec 2023 16:07:48 +0200 Subject: [PATCH 1031/3723] net: if: Tweak the documentation of multicast monitor API As the API supports both IPv4 and IPv6, mention it clearly in the header documentation. Signed-off-by: Jukka Rissanen --- include/zephyr/net/net_if.h | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/include/zephyr/net/net_if.h b/include/zephyr/net/net_if.h index 4f61a14a8c0..3438709136f 100644 --- a/include/zephyr/net/net_if.h +++ b/include/zephyr/net/net_if.h @@ -1400,13 +1400,12 @@ struct net_if_mcast_addr *net_if_ipv6_maddr_lookup(const struct in6_addr *addr, /** * @typedef net_if_mcast_callback_t - * @brief Define callback that is called whenever IPv6 multicast address group - * is joined or left. - + * @brief Define a callback that is called whenever a IPv6 or IPv4 multicast + * address group is joined or left. * @param iface A pointer to a struct net_if to which the multicast address is * attached. * @param addr IP multicast address. - * @param is_joined True if the address is joined, false if left. + * @param is_joined True if the multicast group is joined, false if group is left. */ typedef void (*net_if_mcast_callback_t)(struct net_if *iface, const struct net_addr *addr, @@ -1455,7 +1454,7 @@ void net_if_mcast_mon_unregister(struct net_if_mcast_monitor *mon); * * @param iface Network interface * @param addr Multicast address - * @param is_joined Is this multicast address joined (true) or not (false) + * @param is_joined Is this multicast address group joined (true) or not (false) */ void net_if_mcast_monitor(struct net_if *iface, const struct net_addr *addr, bool is_joined); From af9f526ccda97be05856b0a44b40121ea5d666b6 Mon Sep 17 00:00:00 2001 From: Mariusz Skamra Date: Wed, 8 Nov 2023 13:24:51 +0100 Subject: [PATCH 1032/3723] Bluetooth: has: Check writable preset support on preset registration This fixes issue where API use is able to register writable preset even if the CONFIG_BT_HAS_PRESET_NAME_DYNAMIC Kconfig option was disabled. Signed-off-by: Mariusz Skamra --- subsys/bluetooth/audio/has.c | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/subsys/bluetooth/audio/has.c b/subsys/bluetooth/audio/has.c index 26f719b753b..72db5946d02 100644 --- a/subsys/bluetooth/audio/has.c +++ b/subsys/bluetooth/audio/has.c @@ -1501,6 +1501,12 @@ int bt_has_preset_register(const struct bt_has_preset_register_param *param) return -EALREADY; } + CHECKIF(!IS_ENABLED(CONFIG_BT_HAS_PRESET_NAME_DYNAMIC) && + (param->properties & BT_HAS_PROP_WRITABLE) > 0) { + LOG_ERR("Writable presets are not supported"); + return -ENOTSUP; + } + preset = preset_alloc(param->index, param->properties, param->name, param->ops); if (preset == NULL) { return -ENOMEM; From 03b702690ae74d951bc6863d5f9a65bd8b775dd2 Mon Sep 17 00:00:00 2001 From: Dat Nguyen Duy Date: Fri, 8 Dec 2023 21:37:23 +0700 Subject: [PATCH 1033/3723] include: arm: mpu: add missing RAM NOCACHE region define for armv8-r Add missing define for a non-cacheable RAM region for MPU on armv8-r aarch32 Signed-off-by: Dat Nguyen Duy --- include/zephyr/arch/arm/mpu/arm_mpu_v8.h | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/include/zephyr/arch/arm/mpu/arm_mpu_v8.h b/include/zephyr/arch/arm/mpu/arm_mpu_v8.h index cf60cca99da..11d4a2e7547 100644 --- a/include/zephyr/arch/arm/mpu/arm_mpu_v8.h +++ b/include/zephyr/arch/arm/mpu/arm_mpu_v8.h @@ -220,7 +220,14 @@ .mair_idx = MPU_MAIR_INDEX_SRAM, \ .r_limit = limit - 1, /* Region Limit */ \ } - +#define REGION_RAM_NOCACHE_ATTR(limit) \ + { \ + .rbar = NOT_EXEC | \ + P_RW_U_NA_Msk | NON_SHAREABLE_Msk, /* AP, XN, SH */ \ + /* Cache-ability */ \ + .mair_idx = MPU_MAIR_INDEX_SRAM_NOCACHE, \ + .r_limit = limit - 1, /* Region Limit */ \ + } #if defined(CONFIG_MPU_ALLOW_FLASH_WRITE) /* Note that the access permissions allow for un-privileged writes, contrary * to ARMv7-M where un-privileged code has Read-Only permissions. From 4a020ecc0263975717ca4f7495109b1f017247c7 Mon Sep 17 00:00:00 2001 From: Anas Nashif Date: Fri, 8 Dec 2023 08:51:02 -0500 Subject: [PATCH 1034/3723] arch: mips: rename expection header Rename exception header and use the same name as all architecture ports. Signed-off-by: Anas Nashif --- include/zephyr/arch/mips/arch.h | 2 +- include/zephyr/arch/mips/{exp.h => exception.h} | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) rename include/zephyr/arch/mips/{exp.h => exception.h} (97%) diff --git a/include/zephyr/arch/mips/arch.h b/include/zephyr/arch/mips/arch.h index 67f6c846041..f99744bf086 100644 --- a/include/zephyr/arch/mips/arch.h +++ b/include/zephyr/arch/mips/arch.h @@ -10,7 +10,7 @@ #define ZEPHYR_INCLUDE_ARCH_MIPS_ARCH_H_ #include -#include +#include #include #include #include diff --git a/include/zephyr/arch/mips/exp.h b/include/zephyr/arch/mips/exception.h similarity index 97% rename from include/zephyr/arch/mips/exp.h rename to include/zephyr/arch/mips/exception.h index 37b2cadb2fa..d08bdbdc53b 100644 --- a/include/zephyr/arch/mips/exp.h +++ b/include/zephyr/arch/mips/exception.h @@ -1,7 +1,7 @@ /* * Copyright (c) 2021 Antony Pavlov * - * based on include/arch/riscv/exp.h + * based on include/arch/riscv/exception.h * * SPDX-License-Identifier: Apache-2.0 */ From 8447700013d092c452900fc53281139d6d717c44 Mon Sep 17 00:00:00 2001 From: Anas Nashif Date: Fri, 8 Dec 2023 08:51:47 -0500 Subject: [PATCH 1035/3723] arch: riscv: rename expection header Rename exception header and use the same name as all architecture ports. Signed-off-by: Anas Nashif --- include/zephyr/arch/riscv/arch.h | 4 ++-- include/zephyr/arch/riscv/error.h | 2 +- include/zephyr/arch/riscv/{exp.h => exception.h} | 0 3 files changed, 3 insertions(+), 3 deletions(-) rename include/zephyr/arch/riscv/{exp.h => exception.h} (100%) diff --git a/include/zephyr/arch/riscv/arch.h b/include/zephyr/arch/riscv/arch.h index 99bccb74a08..1d173102de7 100644 --- a/include/zephyr/arch/riscv/arch.h +++ b/include/zephyr/arch/riscv/arch.h @@ -16,7 +16,7 @@ #define ZEPHYR_INCLUDE_ARCH_RISCV_ARCH_H_ #include -#include +#include #include #include #include @@ -29,7 +29,7 @@ #include #include #include -#include +#include /* stacks, for RISCV architecture stack should be 16byte-aligned */ #define ARCH_STACK_PTR_ALIGN 16 diff --git a/include/zephyr/arch/riscv/error.h b/include/zephyr/arch/riscv/error.h index e6af12f700e..a7c3e02b482 100644 --- a/include/zephyr/arch/riscv/error.h +++ b/include/zephyr/arch/riscv/error.h @@ -15,7 +15,7 @@ #define ZEPHYR_INCLUDE_ARCH_RISCV_ERROR_H_ #include -#include +#include #include #ifdef __cplusplus diff --git a/include/zephyr/arch/riscv/exp.h b/include/zephyr/arch/riscv/exception.h similarity index 100% rename from include/zephyr/arch/riscv/exp.h rename to include/zephyr/arch/riscv/exception.h From 9d1a6b6db5aab42c9f45b09fb0253af1213b27f8 Mon Sep 17 00:00:00 2001 From: Anas Nashif Date: Fri, 8 Dec 2023 08:55:08 -0500 Subject: [PATCH 1036/3723] arch: xtensa: rename expection header Rename exception header and use the same name as all architecture ports. Signed-off-by: Anas Nashif --- include/zephyr/arch/xtensa/arch.h | 2 +- include/zephyr/arch/xtensa/{exc.h => exception.h} | 6 +++--- 2 files changed, 4 insertions(+), 4 deletions(-) rename include/zephyr/arch/xtensa/{exc.h => exception.h} (82%) diff --git a/include/zephyr/arch/xtensa/arch.h b/include/zephyr/arch/xtensa/arch.h index d486bb4d7b6..b8971af41e8 100644 --- a/include/zephyr/arch/xtensa/arch.h +++ b/include/zephyr/arch/xtensa/arch.h @@ -38,7 +38,7 @@ /* Xtensa GPRs are often designated by two different names */ #define sys_define_gpr_with_alias(name1, name2) union { uint32_t name1, name2; } -#include +#include #ifdef __cplusplus extern "C" { diff --git a/include/zephyr/arch/xtensa/exc.h b/include/zephyr/arch/xtensa/exception.h similarity index 82% rename from include/zephyr/arch/xtensa/exc.h rename to include/zephyr/arch/xtensa/exception.h index e207261a027..4d2cb9bda0a 100644 --- a/include/zephyr/arch/xtensa/exc.h +++ b/include/zephyr/arch/xtensa/exception.h @@ -12,8 +12,8 @@ * arch/xtensa/arch.h. */ -#ifndef ZEPHYR_INCLUDE_ARCH_XTENSA_EXC_H_ -#define ZEPHYR_INCLUDE_ARCH_XTENSA_EXC_H_ +#ifndef ZEPHYR_INCLUDE_ARCH_XTENSA_EXCEPTION_H_ +#define ZEPHYR_INCLUDE_ARCH_XTENSA_EXCEPTION_H_ #ifdef __cplusplus extern "C" { @@ -37,4 +37,4 @@ char *z_xtensa_exccause(unsigned int cause_code); #endif -#endif /* ZEPHYR_INCLUDE_ARCH_XTENSA_EXC_H_ */ +#endif /* ZEPHYR_INCLUDE_ARCH_XTENSA_EXCEPTION_H_ */ From 864731acdf760303fd6f5e91993040839b477b8e Mon Sep 17 00:00:00 2001 From: Anas Nashif Date: Fri, 8 Dec 2023 08:56:24 -0500 Subject: [PATCH 1037/3723] arch: arm64: rename expection header Rename exception header and use the same name as all architecture ports. Signed-off-by: Anas Nashif --- include/zephyr/arch/arm64/arch.h | 2 +- include/zephyr/arch/arm64/error.h | 2 +- include/zephyr/arch/arm64/{exc.h => exception.h} | 6 +++--- 3 files changed, 5 insertions(+), 5 deletions(-) rename include/zephyr/arch/arm64/{exc.h => exception.h} (86%) diff --git a/include/zephyr/arch/arm64/arch.h b/include/zephyr/arch/arm64/arch.h index c181b08f55e..1f38bd84a2f 100644 --- a/include/zephyr/arch/arm64/arch.h +++ b/include/zephyr/arch/arm64/arch.h @@ -20,7 +20,7 @@ #include #include -#include +#include #include #include #include diff --git a/include/zephyr/arch/arm64/error.h b/include/zephyr/arch/arm64/error.h index 34565107d08..d4d15fc3e99 100644 --- a/include/zephyr/arch/arm64/error.h +++ b/include/zephyr/arch/arm64/error.h @@ -15,7 +15,7 @@ #define ZEPHYR_INCLUDE_ARCH_ARM64_ERROR_H_ #include -#include +#include #include #ifdef __cplusplus diff --git a/include/zephyr/arch/arm64/exc.h b/include/zephyr/arch/arm64/exception.h similarity index 86% rename from include/zephyr/arch/arm64/exc.h rename to include/zephyr/arch/arm64/exception.h index 5a46671d157..4ccdc41f19c 100644 --- a/include/zephyr/arch/arm64/exc.h +++ b/include/zephyr/arch/arm64/exception.h @@ -11,8 +11,8 @@ * ARM-specific kernel exception handling interface. Included by arm64/arch.h. */ -#ifndef ZEPHYR_INCLUDE_ARCH_ARM64_EXC_H_ -#define ZEPHYR_INCLUDE_ARCH_ARM64_EXC_H_ +#ifndef ZEPHYR_INCLUDE_ARCH_ARM64_EXCEPTION_H_ +#define ZEPHYR_INCLUDE_ARCH_ARM64_EXCEPTION_H_ /* for assembler, only works with constants */ @@ -63,4 +63,4 @@ typedef struct __esf z_arch_esf_t; #endif /* _ASMLANGUAGE */ -#endif /* ZEPHYR_INCLUDE_ARCH_ARM64_EXC_H_ */ +#endif /* ZEPHYR_INCLUDE_ARCH_ARM64_EXCEPTION_H_ */ From 87eb1d842f101b9605750f93aac0d495ef934b82 Mon Sep 17 00:00:00 2001 From: Anas Nashif Date: Fri, 8 Dec 2023 08:57:27 -0500 Subject: [PATCH 1038/3723] arch: arc: rename expection header Rename exception header and use the same name as all architecture ports. Signed-off-by: Anas Nashif --- arch/arc/core/fatal.c | 2 +- include/zephyr/arch/arc/arch.h | 2 +- include/zephyr/arch/arc/v2/error.h | 2 +- include/zephyr/arch/arc/v2/{exc.h => exception.h} | 0 4 files changed, 3 insertions(+), 3 deletions(-) rename include/zephyr/arch/arc/v2/{exc.h => exception.h} (100%) diff --git a/arch/arc/core/fatal.c b/arch/arc/core/fatal.c index df8af4c1b44..22205a0834d 100644 --- a/arch/arc/core/fatal.c +++ b/arch/arc/core/fatal.c @@ -17,7 +17,7 @@ #include #include #include -#include +#include LOG_MODULE_DECLARE(os, CONFIG_KERNEL_LOG_LEVEL); diff --git a/include/zephyr/arch/arc/arch.h b/include/zephyr/arch/arc/arch.h index 1eadf5a14b0..1144faa6ebc 100644 --- a/include/zephyr/arch/arc/arch.h +++ b/include/zephyr/arch/arc/arch.h @@ -23,7 +23,7 @@ #include #include "sys-io-common.h" -#include +#include #include #include #include diff --git a/include/zephyr/arch/arc/v2/error.h b/include/zephyr/arch/arc/v2/error.h index edee6fb6aa0..65a85c3e3a7 100644 --- a/include/zephyr/arch/arc/v2/error.h +++ b/include/zephyr/arch/arc/v2/error.h @@ -15,7 +15,7 @@ #define ZEPHYR_INCLUDE_ARCH_ARC_V2_ERROR_H_ #include -#include +#include #include #ifdef __cplusplus diff --git a/include/zephyr/arch/arc/v2/exc.h b/include/zephyr/arch/arc/v2/exception.h similarity index 100% rename from include/zephyr/arch/arc/v2/exc.h rename to include/zephyr/arch/arc/v2/exception.h From 1813a33108d49433e57bd602175c9c9576d8ee21 Mon Sep 17 00:00:00 2001 From: Anas Nashif Date: Fri, 8 Dec 2023 08:58:12 -0500 Subject: [PATCH 1039/3723] arch: arm: rename expection header Rename exception header and use the same name as all architecture ports. Signed-off-by: Anas Nashif --- arch/arm/core/userspace.S | 2 +- arch/arm/include/cortex_m/exc.h | 2 +- doc/hardware/arch/arm_cortex_m.rst | 2 +- include/zephyr/arch/arm/arch.h | 2 +- include/zephyr/arch/arm/asm_inline_gcc.h | 2 +- include/zephyr/arch/arm/error.h | 2 +- include/zephyr/arch/arm/{exc.h => exception.h} | 0 samples/subsys/debug/debugmon/src/main.c | 2 +- 8 files changed, 7 insertions(+), 7 deletions(-) rename include/zephyr/arch/arm/{exc.h => exception.h} (100%) diff --git a/arch/arm/core/userspace.S b/arch/arm/core/userspace.S index bf89c7d663d..3594940078d 100644 --- a/arch/arm/core/userspace.S +++ b/arch/arm/core/userspace.S @@ -12,7 +12,7 @@ #include #include -#include +#include #if defined(CONFIG_CPU_AARCH32_CORTEX_R) #include diff --git a/arch/arm/include/cortex_m/exc.h b/arch/arm/include/cortex_m/exc.h index b46e74341a9..7561c1a0fea 100644 --- a/arch/arm/include/cortex_m/exc.h +++ b/arch/arm/include/cortex_m/exc.h @@ -23,7 +23,7 @@ #else #include -#include +#include #include #ifdef __cplusplus diff --git a/doc/hardware/arch/arm_cortex_m.rst b/doc/hardware/arch/arm_cortex_m.rst index b037896776f..1c074618567 100644 --- a/doc/hardware/arch/arm_cortex_m.rst +++ b/doc/hardware/arch/arm_cortex_m.rst @@ -262,7 +262,7 @@ interrupt. If the ZLI feature is enabled in Mainline Cortex-M builds (see * Regular HW interrupts are assigned priority levels lower than SVC. The priority level configuration in Cortex-M is implemented in -:file:`include/arch/arm/exc.h`. +:file:`include/arch/arm/exception.h`. Locking and unlocking IRQs -------------------------- diff --git a/include/zephyr/arch/arm/arch.h b/include/zephyr/arch/arm/arch.h index a726bba8502..01284a675c5 100644 --- a/include/zephyr/arch/arm/arch.h +++ b/include/zephyr/arch/arm/arch.h @@ -23,7 +23,7 @@ #define sys_define_gpr_with_alias(name1, name2) union { uint32_t name1, name2; } #include -#include +#include #include #include #include diff --git a/include/zephyr/arch/arm/asm_inline_gcc.h b/include/zephyr/arch/arm/asm_inline_gcc.h index 3b8e8e19c92..604dd4f088f 100644 --- a/include/zephyr/arch/arm/asm_inline_gcc.h +++ b/include/zephyr/arch/arm/asm_inline_gcc.h @@ -20,7 +20,7 @@ #include #include -#include +#include #if defined(CONFIG_CPU_AARCH32_CORTEX_R) || defined(CONFIG_CPU_AARCH32_CORTEX_A) #include diff --git a/include/zephyr/arch/arm/error.h b/include/zephyr/arch/arm/error.h index 603e1d00088..afd3495fcb6 100644 --- a/include/zephyr/arch/arm/error.h +++ b/include/zephyr/arch/arm/error.h @@ -16,7 +16,7 @@ #define ZEPHYR_INCLUDE_ARCH_ARM_AARCH32_ERROR_H_ #include -#include +#include #include #ifdef __cplusplus diff --git a/include/zephyr/arch/arm/exc.h b/include/zephyr/arch/arm/exception.h similarity index 100% rename from include/zephyr/arch/arm/exc.h rename to include/zephyr/arch/arm/exception.h diff --git a/samples/subsys/debug/debugmon/src/main.c b/samples/subsys/debug/debugmon/src/main.c index 9029cc44ae7..8c0c8bc3471 100644 --- a/samples/subsys/debug/debugmon/src/main.c +++ b/samples/subsys/debug/debugmon/src/main.c @@ -8,7 +8,7 @@ #include #include #include -#include +#include #define LED0_NODE DT_ALIAS(led0) static const struct gpio_dt_spec led = GPIO_DT_SPEC_GET(LED0_NODE, gpios); From 4d5fd2edf2ae7dfe2ab8258782a2ac9e48afb059 Mon Sep 17 00:00:00 2001 From: Anas Nashif Date: Fri, 8 Dec 2023 08:59:00 -0500 Subject: [PATCH 1040/3723] arch: arm: cortex_a_r: rename expection header Rename exception header and use the same name as all architecture ports. Signed-off-by: Anas Nashif --- arch/arm/include/cortex_a_r/{exc.h => exception.h} | 0 arch/arm/include/kernel_arch_data.h | 2 +- include/zephyr/arch/arm/cortex_a_r/{exc.h => exception.h} | 0 include/zephyr/arch/arm/exception.h | 2 +- 4 files changed, 2 insertions(+), 2 deletions(-) rename arch/arm/include/cortex_a_r/{exc.h => exception.h} (100%) rename include/zephyr/arch/arm/cortex_a_r/{exc.h => exception.h} (100%) diff --git a/arch/arm/include/cortex_a_r/exc.h b/arch/arm/include/cortex_a_r/exception.h similarity index 100% rename from arch/arm/include/cortex_a_r/exc.h rename to arch/arm/include/cortex_a_r/exception.h diff --git a/arch/arm/include/kernel_arch_data.h b/arch/arm/include/kernel_arch_data.h index 6ae5f643341..81edd3ddfdb 100644 --- a/arch/arm/include/kernel_arch_data.h +++ b/arch/arm/include/kernel_arch_data.h @@ -29,7 +29,7 @@ #include #elif defined(CONFIG_CPU_AARCH32_CORTEX_R) || defined(CONFIG_CPU_AARCH32_CORTEX_A) #include -#include +#include #endif #ifndef _ASMLANGUAGE diff --git a/include/zephyr/arch/arm/cortex_a_r/exc.h b/include/zephyr/arch/arm/cortex_a_r/exception.h similarity index 100% rename from include/zephyr/arch/arm/cortex_a_r/exc.h rename to include/zephyr/arch/arm/cortex_a_r/exception.h diff --git a/include/zephyr/arch/arm/exception.h b/include/zephyr/arch/arm/exception.h index 9cd664e2c6b..62a94ce1b02 100644 --- a/include/zephyr/arch/arm/exception.h +++ b/include/zephyr/arch/arm/exception.h @@ -18,7 +18,7 @@ #if defined(CONFIG_CPU_CORTEX_M) #include #elif defined(CONFIG_CPU_AARCH32_CORTEX_A) || defined(CONFIG_CPU_AARCH32_CORTEX_R) -#include +#include #else #error Unknown ARM architecture #endif /* CONFIG_CPU_CORTEX_M */ From 699880a430fcd9a55bb49e566f8ca48a10ec9800 Mon Sep 17 00:00:00 2001 From: Anas Nashif Date: Fri, 8 Dec 2023 09:21:58 -0500 Subject: [PATCH 1041/3723] arch: arm: cortex_m: rename expection header Rename exception header and use the same name as all architecture ports. Signed-off-by: Anas Nashif --- arch/arm/include/cortex_m/{exc.h => exception.h} | 0 arch/arm/include/kernel_arch_data.h | 2 +- include/zephyr/arch/arm/cortex_m/{exc.h => exception.h} | 0 include/zephyr/arch/arm/exception.h | 2 +- soc/arm/nxp_imx/rt6xx/soc.c | 2 +- soc/arm/nxp_lpc/lpc54xxx/soc.c | 2 +- soc/arm/nxp_lpc/lpc55xxx/soc.c | 2 +- 7 files changed, 5 insertions(+), 5 deletions(-) rename arch/arm/include/cortex_m/{exc.h => exception.h} (100%) rename include/zephyr/arch/arm/cortex_m/{exc.h => exception.h} (100%) diff --git a/arch/arm/include/cortex_m/exc.h b/arch/arm/include/cortex_m/exception.h similarity index 100% rename from arch/arm/include/cortex_m/exc.h rename to arch/arm/include/cortex_m/exception.h diff --git a/arch/arm/include/kernel_arch_data.h b/arch/arm/include/kernel_arch_data.h index 81edd3ddfdb..5ad19db8f84 100644 --- a/arch/arm/include/kernel_arch_data.h +++ b/arch/arm/include/kernel_arch_data.h @@ -26,7 +26,7 @@ #if defined(CONFIG_CPU_CORTEX_M) #include -#include +#include #elif defined(CONFIG_CPU_AARCH32_CORTEX_R) || defined(CONFIG_CPU_AARCH32_CORTEX_A) #include #include diff --git a/include/zephyr/arch/arm/cortex_m/exc.h b/include/zephyr/arch/arm/cortex_m/exception.h similarity index 100% rename from include/zephyr/arch/arm/cortex_m/exc.h rename to include/zephyr/arch/arm/cortex_m/exception.h diff --git a/include/zephyr/arch/arm/exception.h b/include/zephyr/arch/arm/exception.h index 62a94ce1b02..7a25f4b2067 100644 --- a/include/zephyr/arch/arm/exception.h +++ b/include/zephyr/arch/arm/exception.h @@ -16,7 +16,7 @@ #define ZEPHYR_INCLUDE_ARCH_ARM_AARCH32_EXC_H_ #if defined(CONFIG_CPU_CORTEX_M) -#include +#include #elif defined(CONFIG_CPU_AARCH32_CORTEX_A) || defined(CONFIG_CPU_AARCH32_CORTEX_R) #include #else diff --git a/soc/arm/nxp_imx/rt6xx/soc.c b/soc/arm/nxp_imx/rt6xx/soc.c index 2d4eab6854d..165cf92e234 100644 --- a/soc/arm/nxp_imx/rt6xx/soc.c +++ b/soc/arm/nxp_imx/rt6xx/soc.c @@ -19,7 +19,7 @@ #include #include #include -#include +#include #include #include #include diff --git a/soc/arm/nxp_lpc/lpc54xxx/soc.c b/soc/arm/nxp_lpc/lpc54xxx/soc.c index bbc689dbc68..20f2022cd56 100644 --- a/soc/arm/nxp_lpc/lpc54xxx/soc.c +++ b/soc/arm/nxp_lpc/lpc54xxx/soc.c @@ -19,7 +19,7 @@ #include #include #include -#include +#include #include #include #include diff --git a/soc/arm/nxp_lpc/lpc55xxx/soc.c b/soc/arm/nxp_lpc/lpc55xxx/soc.c index 6730c6cfcff..a26aae34d9b 100644 --- a/soc/arm/nxp_lpc/lpc55xxx/soc.c +++ b/soc/arm/nxp_lpc/lpc55xxx/soc.c @@ -18,7 +18,7 @@ #include #include #include -#include +#include #include #include #include From ca3839ca388fb713524ee5889075c5c7c4567e3a Mon Sep 17 00:00:00 2001 From: Anas Nashif Date: Fri, 8 Dec 2023 09:24:39 -0500 Subject: [PATCH 1042/3723] arch: arm64: rename expection header Rename exception header and use the same name as all architecture ports. Signed-off-by: Anas Nashif --- arch/arm64/core/irq_offload.c | 2 +- arch/arm64/include/{exc.h => exception.h} | 0 arch/arm64/include/kernel_arch_data.h | 2 +- 3 files changed, 2 insertions(+), 2 deletions(-) rename arch/arm64/include/{exc.h => exception.h} (100%) diff --git a/arch/arm64/core/irq_offload.c b/arch/arm64/core/irq_offload.c index 26f88aa77e6..1d5e3c829b8 100644 --- a/arch/arm64/core/irq_offload.c +++ b/arch/arm64/core/irq_offload.c @@ -11,7 +11,7 @@ #include #include -#include +#include void arch_irq_offload(irq_offload_routine_t routine, const void *parameter) { diff --git a/arch/arm64/include/exc.h b/arch/arm64/include/exception.h similarity index 100% rename from arch/arm64/include/exc.h rename to arch/arm64/include/exception.h diff --git a/arch/arm64/include/kernel_arch_data.h b/arch/arm64/include/kernel_arch_data.h index 0b2d878537f..ec781fc902d 100644 --- a/arch/arm64/include/kernel_arch_data.h +++ b/arch/arm64/include/kernel_arch_data.h @@ -24,7 +24,7 @@ #include #include -#include +#include #ifndef _ASMLANGUAGE #include From 552f7194e3bb4fe31dc465329b486ac124a86524 Mon Sep 17 00:00:00 2001 From: Anas Nashif Date: Fri, 8 Dec 2023 08:53:19 -0500 Subject: [PATCH 1043/3723] arch: exception: rename header guard Match guard with header file name. Signed-off-by: Anas Nashif --- arch/arm/include/cortex_a_r/exception.h | 6 +++--- arch/arm/include/cortex_m/exception.h | 6 +++--- arch/arm64/include/exception.h | 6 +++--- include/zephyr/arch/arc/v2/exception.h | 6 +++--- include/zephyr/arch/arm/cortex_a_r/exception.h | 6 +++--- include/zephyr/arch/arm/cortex_m/exception.h | 6 +++--- include/zephyr/arch/arm/exception.h | 6 +++--- include/zephyr/arch/mips/exception.h | 6 +++--- include/zephyr/arch/riscv/exception.h | 6 +++--- 9 files changed, 27 insertions(+), 27 deletions(-) diff --git a/arch/arm/include/cortex_a_r/exception.h b/arch/arm/include/cortex_a_r/exception.h index 6cddaa1c72c..7519016176c 100644 --- a/arch/arm/include/cortex_a_r/exception.h +++ b/arch/arm/include/cortex_a_r/exception.h @@ -11,8 +11,8 @@ * Exception/interrupt context helpers. */ -#ifndef ZEPHYR_ARCH_ARM_INCLUDE_AARCH32_CORTEX_A_R_EXC_H_ -#define ZEPHYR_ARCH_ARM_INCLUDE_AARCH32_CORTEX_A_R_EXC_H_ +#ifndef ZEPHYR_ARCH_ARM_INCLUDE_CORTEX_A_R_EXCEPTION_H_ +#define ZEPHYR_ARCH_ARM_INCLUDE_CORTEX_A_R_EXCEPTION_H_ #include @@ -64,4 +64,4 @@ extern void z_arm_cortex_r_svc(void); #endif /* _ASMLANGUAGE */ -#endif /* ZEPHYR_ARCH_ARM_INCLUDE_AARCH32_CORTEX_A_R_EXC_H_ */ +#endif /* ZEPHYR_ARCH_ARM_INCLUDE_CORTEX_A_R_EXCEPTION_H_ */ diff --git a/arch/arm/include/cortex_m/exception.h b/arch/arm/include/cortex_m/exception.h index 7561c1a0fea..bf86abd77c7 100644 --- a/arch/arm/include/cortex_m/exception.h +++ b/arch/arm/include/cortex_m/exception.h @@ -11,8 +11,8 @@ * Exception/interrupt context helpers. */ -#ifndef ZEPHYR_ARCH_ARM_INCLUDE_AARCH32_CORTEX_M_EXC_H_ -#define ZEPHYR_ARCH_ARM_INCLUDE_AARCH32_CORTEX_M_EXC_H_ +#ifndef ZEPHYR_ARCH_ARM_INCLUDE_CORTEX_M_EXCEPTION_H_ +#define ZEPHYR_ARCH_ARM_INCLUDE_CORTEX_M_EXCEPTION_H_ #include @@ -200,4 +200,4 @@ bool z_arm_debug_monitor_event_error_check(void); #endif /* _ASMLANGUAGE */ -#endif /* ZEPHYR_ARCH_ARM_INCLUDE_AARCH32_CORTEX_M_EXC_H_ */ +#endif /* ZEPHYR_ARCH_ARM_INCLUDE_CORTEX_M_EXCEPTION_H_ */ diff --git a/arch/arm64/include/exception.h b/arch/arm64/include/exception.h index 03dacc7c51d..6ab6bbbfeff 100644 --- a/arch/arm64/include/exception.h +++ b/arch/arm64/include/exception.h @@ -11,8 +11,8 @@ * Exception/interrupt context helpers. */ -#ifndef ZEPHYR_ARCH_ARM64_INCLUDE_EXC_H_ -#define ZEPHYR_ARCH_ARM64_INCLUDE_EXC_H_ +#ifndef ZEPHYR_ARCH_ARM64_INCLUDE_EXCEPTION_H_ +#define ZEPHYR_ARCH_ARM64_INCLUDE_EXCEPTION_H_ #include @@ -37,4 +37,4 @@ static ALWAYS_INLINE bool arch_is_in_isr(void) #endif /* _ASMLANGUAGE */ -#endif /* ZEPHYR_ARCH_ARM64_INCLUDE_EXC_H_ */ +#endif /* ZEPHYR_ARCH_ARM64_INCLUDE_EXCEPTION_H_ */ diff --git a/include/zephyr/arch/arc/v2/exception.h b/include/zephyr/arch/arc/v2/exception.h index b5c6a8ddf3e..553024fa3a8 100644 --- a/include/zephyr/arch/arc/v2/exception.h +++ b/include/zephyr/arch/arc/v2/exception.h @@ -11,8 +11,8 @@ * ARC-specific kernel exception handling interface. Included by arc/arch.h. */ -#ifndef ZEPHYR_INCLUDE_ARCH_ARC_V2_EXC_H_ -#define ZEPHYR_INCLUDE_ARCH_ARC_V2_EXC_H_ +#ifndef ZEPHYR_INCLUDE_ARCH_ARC_V2_EXCEPTION_H_ +#define ZEPHYR_INCLUDE_ARCH_ARC_V2_EXCEPTION_H_ #ifdef __cplusplus extern "C" { @@ -44,4 +44,4 @@ typedef struct _irq_stack_frame z_arch_esf_t; #define ARC_EV_MISALIGNED 0xD #define ARC_EV_VEC_UNIT 0xE -#endif /* ZEPHYR_INCLUDE_ARCH_ARC_V2_EXC_H_ */ +#endif /* ZEPHYR_INCLUDE_ARCH_ARC_V2_EXCEPTION_H_ */ diff --git a/include/zephyr/arch/arm/cortex_a_r/exception.h b/include/zephyr/arch/arm/cortex_a_r/exception.h index 92f074f1b36..3bef647566d 100644 --- a/include/zephyr/arch/arm/cortex_a_r/exception.h +++ b/include/zephyr/arch/arm/cortex_a_r/exception.h @@ -9,8 +9,8 @@ * @brief ARM AArch32 Cortex-A and Cortex-R public exception handling */ -#ifndef ZEPHYR_INCLUDE_ARCH_ARM_AARCH32_CORTEX_A_R_EXC_H_ -#define ZEPHYR_INCLUDE_ARCH_ARM_AARCH32_CORTEX_A_R_EXC_H_ +#ifndef ZEPHYR_INCLUDE_ARCH_ARM_CORTEX_A_R_EXCEPTION_H_ +#define ZEPHYR_INCLUDE_ARCH_ARM_CORTEX_A_R_EXCEPTION_H_ #ifdef _ASMLANGUAGE GTEXT(z_arm_exc_exit); @@ -85,4 +85,4 @@ extern void z_arm_exc_exit(bool fatal); #endif /* _ASMLANGUAGE */ -#endif /* ZEPHYR_INCLUDE_ARCH_ARM_AARCH32_CORTEX_A_R_EXC_H_ */ +#endif /* ZEPHYR_INCLUDE_ARCH_ARM_CORTEX_A_R_EXCEPTION_H_ */ diff --git a/include/zephyr/arch/arm/cortex_m/exception.h b/include/zephyr/arch/arm/cortex_m/exception.h index 8a2cfc8cc3f..a9896cea1e4 100644 --- a/include/zephyr/arch/arm/cortex_m/exception.h +++ b/include/zephyr/arch/arm/cortex_m/exception.h @@ -9,8 +9,8 @@ * @brief ARM AArch32 Cortex-M public exception handling */ -#ifndef ZEPHYR_INCLUDE_ARCH_ARM_AARCH32_CORTEX_M_EXC_H_ -#define ZEPHYR_INCLUDE_ARCH_ARM_AARCH32_CORTEX_M_EXC_H_ +#ifndef ZEPHYR_INCLUDE_ARCH_ARM_CORTEX_M_EXCEPTION_H_ +#define ZEPHYR_INCLUDE_ARCH_ARM_CORTEX_M_EXCEPTION_H_ #include @@ -129,4 +129,4 @@ extern void z_arm_exc_exit(void); #endif /* _ASMLANGUAGE */ -#endif /* ZEPHYR_INCLUDE_ARCH_ARM_AARCH32_CORTEX_M_EXC_H_ */ +#endif /* ZEPHYR_INCLUDE_ARCH_ARM_CORTEX_M_EXCEPTION_H_ */ diff --git a/include/zephyr/arch/arm/exception.h b/include/zephyr/arch/arm/exception.h index 7a25f4b2067..cc20225e483 100644 --- a/include/zephyr/arch/arm/exception.h +++ b/include/zephyr/arch/arm/exception.h @@ -12,8 +12,8 @@ * arm/arch.h. */ -#ifndef ZEPHYR_INCLUDE_ARCH_ARM_AARCH32_EXC_H_ -#define ZEPHYR_INCLUDE_ARCH_ARM_AARCH32_EXC_H_ +#ifndef ZEPHYR_INCLUDE_ARCH_ARM_EXCEPTION_H_ +#define ZEPHYR_INCLUDE_ARCH_ARM_EXCEPTION_H_ #if defined(CONFIG_CPU_CORTEX_M) #include @@ -23,4 +23,4 @@ #error Unknown ARM architecture #endif /* CONFIG_CPU_CORTEX_M */ -#endif /* ZEPHYR_INCLUDE_ARCH_ARM_AARCH32_EXC_H_ */ +#endif /* ZEPHYR_INCLUDE_ARCH_ARM_EXCEPTION_H_ */ diff --git a/include/zephyr/arch/mips/exception.h b/include/zephyr/arch/mips/exception.h index d08bdbdc53b..d4403f1d599 100644 --- a/include/zephyr/arch/mips/exception.h +++ b/include/zephyr/arch/mips/exception.h @@ -6,8 +6,8 @@ * SPDX-License-Identifier: Apache-2.0 */ -#ifndef ZEPHYR_INCLUDE_ARCH_MIPS_EXP_H_ -#define ZEPHYR_INCLUDE_ARCH_MIPS_EXP_H_ +#ifndef ZEPHYR_INCLUDE_ARCH_MIPS_EXPCEPTION_H_ +#define ZEPHYR_INCLUDE_ARCH_MIPS_EXPCEPTION_H_ #ifndef _ASMLANGUAGE #include @@ -58,4 +58,4 @@ typedef struct __esf z_arch_esf_t; #endif /* _ASMLANGUAGE */ -#endif /* ZEPHYR_INCLUDE_ARCH_MIPS_EXP_H_ */ +#endif /* ZEPHYR_INCLUDE_ARCH_MIPS_EXPCEPTION_H_ */ diff --git a/include/zephyr/arch/riscv/exception.h b/include/zephyr/arch/riscv/exception.h index e661e5aa86e..644df2cd1fb 100644 --- a/include/zephyr/arch/riscv/exception.h +++ b/include/zephyr/arch/riscv/exception.h @@ -12,8 +12,8 @@ * RISCV-specific kernel exception handling interface. */ -#ifndef ZEPHYR_INCLUDE_ARCH_RISCV_EXP_H_ -#define ZEPHYR_INCLUDE_ARCH_RISCV_EXP_H_ +#ifndef ZEPHYR_INCLUDE_ARCH_RISCV_EXCEPTION_H_ +#define ZEPHYR_INCLUDE_ARCH_RISCV_EXCEPTION_H_ #ifndef _ASMLANGUAGE #include @@ -98,4 +98,4 @@ typedef struct soc_esf soc_esf_t; #endif /* _ASMLANGUAGE */ -#endif /* ZEPHYR_INCLUDE_ARCH_RISCV_EXP_H_ */ +#endif /* ZEPHYR_INCLUDE_ARCH_RISCV_EXCEPTION_H_ */ From 01264d23db0ad2e6bff0a5da64693f65e4e7d8f2 Mon Sep 17 00:00:00 2001 From: Anas Nashif Date: Thu, 7 Dec 2023 14:20:32 -0500 Subject: [PATCH 1044/3723] drivers: intc: manage multi-level interrupt configs Multilevel interrupt configs are leaking into every single build without this option being enabled, so guard the Kconfig and include files to avoid this. Signed-off-by: Anas Nashif --- drivers/interrupt_controller/Kconfig.clic | 1 + drivers/interrupt_controller/Kconfig.multilevel | 5 +++-- include/zephyr/irq_multilevel.h | 2 ++ include/zephyr/irq_nextlevel.h | 2 ++ 4 files changed, 8 insertions(+), 2 deletions(-) diff --git a/drivers/interrupt_controller/Kconfig.clic b/drivers/interrupt_controller/Kconfig.clic index caa9a93a284..729f4e7e0f5 100644 --- a/drivers/interrupt_controller/Kconfig.clic +++ b/drivers/interrupt_controller/Kconfig.clic @@ -5,5 +5,6 @@ config NUCLEI_ECLIC bool "Enhanced Core Local Interrupt Controller (ECLIC)" default y depends on DT_HAS_NUCLEI_ECLIC_ENABLED + select MULTI_LEVEL_INTERRUPTS help Interrupt controller for Nuclei SoC core. diff --git a/drivers/interrupt_controller/Kconfig.multilevel b/drivers/interrupt_controller/Kconfig.multilevel index 501cf0f4a46..0aae541021e 100644 --- a/drivers/interrupt_controller/Kconfig.multilevel +++ b/drivers/interrupt_controller/Kconfig.multilevel @@ -18,6 +18,7 @@ config MULTI_LEVEL_INTERRUPTS by the hardware. (The term "aggregator" here means "interrupt controller".) +if MULTI_LEVEL_INTERRUPTS config 1ST_LEVEL_INTERRUPT_BITS int "Total number of first level interrupt bits" range 1 32 @@ -29,7 +30,6 @@ config 1ST_LEVEL_INTERRUPT_BITS config MAX_IRQ_PER_AGGREGATOR int "Max IRQs per interrupt aggregator" default 0 - depends on MULTI_LEVEL_INTERRUPTS help The maximum number of interrupt inputs to any aggregator in the @@ -37,7 +37,6 @@ config MAX_IRQ_PER_AGGREGATOR config 2ND_LEVEL_INTERRUPTS bool "Second-level interrupt support" - depends on MULTI_LEVEL_INTERRUPTS help Second level interrupts are used to increase the number of addressable interrupts in a system. @@ -142,3 +141,5 @@ aggregator = 6 rsource "Kconfig.multilevel.aggregator_template" aggregator = 7 rsource "Kconfig.multilevel.aggregator_template" + +endif diff --git a/include/zephyr/irq_multilevel.h b/include/zephyr/irq_multilevel.h index 3a2b5116602..25daa030249 100644 --- a/include/zephyr/irq_multilevel.h +++ b/include/zephyr/irq_multilevel.h @@ -19,6 +19,7 @@ extern "C" { #endif +#if defined(CONFIG_MULTI_LEVEL_INTERRUPTS) || defined(__DOXYGEN__) /** * @brief Return IRQ level * This routine returns the interrupt level number of the provided interrupt. @@ -165,6 +166,7 @@ static inline unsigned int irq_parent_level_3(unsigned int irq) BIT_MASK(CONFIG_2ND_LEVEL_INTERRUPT_BITS); } +#endif /* CONFIG_MULTI_LEVEL_INTERRUPTS */ #ifdef __cplusplus } #endif diff --git a/include/zephyr/irq_nextlevel.h b/include/zephyr/irq_nextlevel.h index 20533cdf6e0..e5ab4ffdd8a 100644 --- a/include/zephyr/irq_nextlevel.h +++ b/include/zephyr/irq_nextlevel.h @@ -15,6 +15,7 @@ extern "C" { #endif +#if defined(CONFIG_MULTI_LEVEL_INTERRUPTS) || defined(__DOXYGEN__) /** * @cond INTERNAL_HIDDEN * @@ -134,6 +135,7 @@ static inline unsigned int irq_line_is_enabled_next_level(const struct device *d return api->intr_get_line_state(dev, irq); } +#endif /* CONFIG_MULTI_LEVEL_INTERRUPTS */ #ifdef __cplusplus } #endif From 9f3ed1b2b386f3bf613b9799b5bc384ae2416778 Mon Sep 17 00:00:00 2001 From: Anas Nashif Date: Fri, 8 Dec 2023 07:55:21 -0500 Subject: [PATCH 1045/3723] arch: _PrepC -> z_prep_c Rename to use common naming for z_prep_c applied to all architectures. Signed-off-by: Anas Nashif --- arch/arc/core/prep_c.c | 2 +- arch/arc/core/reset.S | 4 ++-- arch/arc/include/vector_table.h | 2 +- arch/mips/core/prep_c.c | 2 +- arch/mips/core/reset.S | 4 ++-- arch/nios2/core/crt0.S | 6 +++--- arch/nios2/core/prep_c.c | 2 +- arch/riscv/core/prep_c.c | 2 +- arch/riscv/core/reset.S | 6 +++--- arch/sparc/core/prep_c.c | 2 +- arch/sparc/core/reset_trap.S | 2 +- boards/nios2/altera_max10/doc/index.rst | 2 +- 12 files changed, 18 insertions(+), 18 deletions(-) diff --git a/arch/arc/core/prep_c.c b/arch/arc/core/prep_c.c index f0b31a2bb36..a3608717969 100644 --- a/arch/arc/core/prep_c.c +++ b/arch/arc/core/prep_c.c @@ -88,7 +88,7 @@ extern FUNC_NORETURN void z_cstart(void); * This routine prepares for the execution of and runs C code. */ -void _PrepC(void) +void z_prep_c(void) { z_bss_zero(); #ifdef __CCAC__ diff --git a/arch/arc/core/reset.S b/arch/arc/core/reset.S index ba29f44051b..82ea4c4d435 100644 --- a/arch/arc/core/reset.S +++ b/arch/arc/core/reset.S @@ -40,7 +40,7 @@ GTEXT(__start) * * Locking interrupts prevents anything from interrupting the CPU. * - * When these steps are completed, jump to _PrepC(), which will finish setting + * When these steps are completed, jump to z_prep_c(), which will finish setting * up the system for running C code. */ @@ -202,4 +202,4 @@ _master_core_startup: jl z_arc_firq_stack_set #endif - j _PrepC + j z_prep_c diff --git a/arch/arc/include/vector_table.h b/arch/arc/include/vector_table.h index fc828c7ddaf..1d7b1ca1220 100644 --- a/arch/arc/include/vector_table.h +++ b/arch/arc/include/vector_table.h @@ -46,7 +46,7 @@ GTEXT(__ev_div_zero) GTEXT(__ev_dc_error) GTEXT(__ev_maligned) -GTEXT(_PrepC) +GTEXT(z_prep_c) GTEXT(_isr_wrapper) #else diff --git a/arch/mips/core/prep_c.c b/arch/mips/core/prep_c.c index 6f72699cc5b..19673273b8a 100644 --- a/arch/mips/core/prep_c.c +++ b/arch/mips/core/prep_c.c @@ -42,7 +42,7 @@ static void interrupt_init(void) * @return N/A */ -void _PrepC(void) +void z_prep_c(void) { z_bss_zero(); diff --git a/arch/mips/core/reset.S b/arch/mips/core/reset.S index 8daebf85d4a..eec75bc031b 100644 --- a/arch/mips/core/reset.S +++ b/arch/mips/core/reset.S @@ -11,7 +11,7 @@ GTEXT(__initialize) GTEXT(__stack) -GTEXT(_PrepC) +GTEXT(z_prep_c) /* * Remainder of asm-land initialization code before we can jump into @@ -52,6 +52,6 @@ aa_loop: /* * Jump into C domain. */ - la v0, _PrepC + la v0, z_prep_c jal v0 nop /* delay slot */ diff --git a/arch/nios2/core/crt0.S b/arch/nios2/core/crt0.S index 8ecb37fe926..2f708bf26f4 100644 --- a/arch/nios2/core/crt0.S +++ b/arch/nios2/core/crt0.S @@ -12,7 +12,7 @@ GTEXT(__start) GTEXT(__reset) /* imports */ -GTEXT(_PrepC) +GTEXT(z_prep_c) GTEXT(z_interrupt_stacks) /* Allow use of r1/at (the assembler temporary register) in this @@ -140,7 +140,7 @@ SECTION_FUNC(TEXT, __start) * GH-1821 */ - /* Jump into C domain. _PrepC zeroes BSS, copies rw data into RAM, + /* Jump into C domain. z_prep_c zeroes BSS, copies rw data into RAM, * and then enters z_cstart */ - call _PrepC + call z_prep_c diff --git a/arch/nios2/core/prep_c.c b/arch/nios2/core/prep_c.c index da8fcd9d4bc..74a3454af48 100644 --- a/arch/nios2/core/prep_c.c +++ b/arch/nios2/core/prep_c.c @@ -28,7 +28,7 @@ * This routine prepares for the execution of and runs C code. */ -void _PrepC(void) +void z_prep_c(void) { z_bss_zero(); z_data_copy(); diff --git a/arch/riscv/core/prep_c.c b/arch/riscv/core/prep_c.c index 8b9b118b24c..37835402fba 100644 --- a/arch/riscv/core/prep_c.c +++ b/arch/riscv/core/prep_c.c @@ -27,7 +27,7 @@ * This routine prepares for the execution of and runs C code. */ -void _PrepC(void) +void z_prep_c(void) { z_bss_zero(); z_data_copy(); diff --git a/arch/riscv/core/reset.S b/arch/riscv/core/reset.S index e2faa6fe94d..73e2bf923a2 100644 --- a/arch/riscv/core/reset.S +++ b/arch/riscv/core/reset.S @@ -16,7 +16,7 @@ GTEXT(__initialize) GTEXT(__reset) /* imports */ -GTEXT(_PrepC) +GTEXT(z_prep_c) GTEXT(riscv_cpu_wake_flag) GTEXT(riscv_cpu_sp) GTEXT(z_riscv_secondary_cpu_init) @@ -86,10 +86,10 @@ aa_loop: #endif /* - * Jump into C domain. _PrepC zeroes BSS, copies rw data into RAM, + * Jump into C domain. z_prep_c zeroes BSS, copies rw data into RAM, * and then enters kernel z_cstart */ - call _PrepC + call z_prep_c boot_secondary_core: #if CONFIG_MP_MAX_NUM_CPUS > 1 diff --git a/arch/sparc/core/prep_c.c b/arch/sparc/core/prep_c.c index 6858b2fb1fb..9ad3955a190 100644 --- a/arch/sparc/core/prep_c.c +++ b/arch/sparc/core/prep_c.c @@ -17,7 +17,7 @@ * This routine prepares for the execution of and runs C code. */ -void _PrepC(void) +void z_prep_c(void) { z_data_copy(); z_cstart(); diff --git a/arch/sparc/core/reset_trap.S b/arch/sparc/core/reset_trap.S index 66b5aafcf26..dd4046c47bc 100644 --- a/arch/sparc/core/reset_trap.S +++ b/arch/sparc/core/reset_trap.S @@ -48,7 +48,7 @@ SECTION_FUNC(TEXT, __sparc_trap_reset) call z_bss_zero nop - call _PrepC + call z_prep_c nop /* We halt the system by generating a "trap in trap" condition. */ diff --git a/boards/nios2/altera_max10/doc/index.rst b/boards/nios2/altera_max10/doc/index.rst index 302c10c1cff..db4daf5256a 100644 --- a/boards/nios2/altera_max10/doc/index.rst +++ b/boards/nios2/altera_max10/doc/index.rst @@ -233,7 +233,7 @@ You will see output similar to the following: Listening on port 3335 for connection from GDB: accepted isr_tables_syms () at /projects/zephyr/arch/common/isr_tables.c:63 63 GEN_ABSOLUTE_SYM(__ISR_LIST_SIZEOF, sizeof(struct _isr_list)); - (gdb) b _PrepC + (gdb) b z_prep_c Breakpoint 1 at 0xdf0: file /projects/zephyr/arch/nios2/core/prep_c.c, line 36. (gdb) b z_cstart Breakpoint 2 at 0x1254: file /projects/zephyr/kernel/init.c, line 348. From 5a77fc239f4ad4fabaa89f57f9352f0d9d4b3404 Mon Sep 17 00:00:00 2001 From: Anas Nashif Date: Fri, 8 Dec 2023 07:57:28 -0500 Subject: [PATCH 1046/3723] arch: arm: z_arm64_prep_c -> z_prep_c Rename to use common naming for z_prep_c applied to all architectures. Signed-off-by: Anas Nashif --- arch/arm64/core/prep_c.c | 2 +- arch/arm64/core/reset.S | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/arch/arm64/core/prep_c.c b/arch/arm64/core/prep_c.c index c12d5e7d1c4..032881fb6f4 100644 --- a/arch/arm64/core/prep_c.c +++ b/arch/arm64/core/prep_c.c @@ -51,7 +51,7 @@ void z_early_memcpy(void *dst, const void *src, size_t n) * This routine prepares for the execution of and runs C code. * */ -void z_arm64_prep_c(void) +void z_prep_c(void) { /* Initialize tpidrro_el0 with our struct _cpu instance address */ write_tpidrro_el0((uintptr_t)&_kernel.cpus[0]); diff --git a/arch/arm64/core/reset.S b/arch/arm64/core/reset.S index 81f11e6f2c9..cfcffec4ce7 100644 --- a/arch/arm64/core/reset.S +++ b/arch/arm64/core/reset.S @@ -188,7 +188,7 @@ primary_core: #endif /* load primary stack and entry point */ ldr x24, =(z_interrupt_stacks + __z_interrupt_stack_SIZEOF) - ldr x25, =z_arm64_prep_c + ldr x25, =z_prep_c boot: /* Prepare for calling C code */ bl __reset_prep_c @@ -248,4 +248,4 @@ switch_el: msr DAIFClr, #(DAIFCLR_ABT_BIT) isb - ret x25 /* either z_arm64_prep_c or z_arm64_secondary_prep_c */ + ret x25 /* either z_prep_c or z_arm64_secondary_prep_c */ From 4a73fb1b92ab170e51915086ae12753c5181f925 Mon Sep 17 00:00:00 2001 From: Anas Nashif Date: Fri, 8 Dec 2023 08:01:29 -0500 Subject: [PATCH 1047/3723] x86: add CODE_UNREACHABLE after z_cstart Add CODE_UNREACHABLE to be consistent with all other architectures. Signed-off-by: Anas Nashif --- arch/arm64/core/prep_c.c | 2 +- arch/x86/core/prep_c.c | 1 + 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/arch/arm64/core/prep_c.c b/arch/arm64/core/prep_c.c index 032881fb6f4..8ec380296aa 100644 --- a/arch/arm64/core/prep_c.c +++ b/arch/arm64/core/prep_c.c @@ -64,8 +64,8 @@ void z_prep_c(void) #endif z_arm64_mm_init(true); z_arm64_interrupt_init(); - z_cstart(); + z_cstart(); CODE_UNREACHABLE; } diff --git a/arch/x86/core/prep_c.c b/arch/x86/core/prep_c.c index ee095efe33d..e28d7e7a3a1 100644 --- a/arch/x86/core/prep_c.c +++ b/arch/x86/core/prep_c.c @@ -78,4 +78,5 @@ FUNC_NORETURN void z_x86_prep_c(void *arg) #endif z_cstart(); + CODE_UNREACHABLE; } From fb19d532edb177dda56fb0f37c89f361004f41c0 Mon Sep 17 00:00:00 2001 From: Anas Nashif Date: Fri, 8 Dec 2023 08:02:25 -0500 Subject: [PATCH 1048/3723] arch: x86: z_x86_prep_c -> z_prep_c Rename to use common naming for z_prep_c applied to all architectures. Signed-off-by: Anas Nashif --- arch/x86/core/common.S | 2 +- arch/x86/core/ia32/crt0.S | 4 ++-- arch/x86/core/intel64/cpu.c | 4 ++-- arch/x86/core/prep_c.c | 2 +- arch/x86/include/kernel_arch_func.h | 2 +- doc/services/debugging/gdbstub.rst | 2 +- 6 files changed, 8 insertions(+), 8 deletions(-) diff --git a/arch/x86/core/common.S b/arch/x86/core/common.S index 856ae7b2e0e..1f390df42fb 100644 --- a/arch/x86/core/common.S +++ b/arch/x86/core/common.S @@ -17,7 +17,7 @@ * contains MULTIBOOT_EAX_MAGIC and EBX points to a valid 'struct * multiboot_info'; otherwise EBX is just junk. Check EAX early * before it's clobbered and leave a sentinel (0) in EBX if invalid. - * The valid in EBX will be the argument to z_x86_prep_c(), so the + * The valid in EBX will be the argument to z_prep_c(), so the * subsequent code must, of course, be sure to preserve it meanwhile. */ diff --git a/arch/x86/core/ia32/crt0.S b/arch/x86/core/ia32/crt0.S index 75a5402a4b2..32513a95790 100644 --- a/arch/x86/core/ia32/crt0.S +++ b/arch/x86/core/ia32/crt0.S @@ -28,7 +28,7 @@ GTEXT(__start) /* externs */ - GTEXT(z_x86_prep_c) + GTEXT(z_prep_c) GTEXT(z_bss_zero) GTEXT(z_data_copy) @@ -287,7 +287,7 @@ __csSet: /* pointer to multiboot info, or NULL */ movl %ebx, __x86_boot_arg_t_arg_OFFSET(%ebp) pushl $x86_cpu_boot_arg - call z_x86_prep_c /* enter kernel; never returns */ + call z_prep_c /* enter kernel; never returns */ #if defined(CONFIG_X86_SSE) diff --git a/arch/x86/core/intel64/cpu.c b/arch/x86/core/intel64/cpu.c index 204264cbdf9..16d39ea1f1a 100644 --- a/arch/x86/core/intel64/cpu.c +++ b/arch/x86/core/intel64/cpu.c @@ -110,7 +110,7 @@ struct x86_cpuboot x86_cpuboot[] = { Z_KERNEL_STACK_SIZE_ADJUST(CONFIG_ISR_STACK_SIZE), .stack_size = Z_KERNEL_STACK_SIZE_ADJUST(CONFIG_ISR_STACK_SIZE), - .fn = z_x86_prep_c, + .fn = z_prep_c, .arg = &x86_cpu_boot_arg, }, #if CONFIG_MP_MAX_NUM_CPUS > 1 @@ -176,7 +176,7 @@ void arch_start_cpu(int cpu_num, k_thread_stack_t *stack, int sz, #endif } -/* Per-CPU initialization, C domain. On the first CPU, z_x86_prep_c is the +/* Per-CPU initialization, C domain. On the first CPU, z_prep_c is the * next step. For other CPUs it is probably smp_init_top(). */ FUNC_NORETURN void z_x86_cpu_init(struct x86_cpuboot *cpuboot) diff --git a/arch/x86/core/prep_c.c b/arch/x86/core/prep_c.c index e28d7e7a3a1..d067e067641 100644 --- a/arch/x86/core/prep_c.c +++ b/arch/x86/core/prep_c.c @@ -21,7 +21,7 @@ __pinned_data x86_boot_arg_t x86_cpu_boot_arg; * CPU for SMP systems. */ __boot_func -FUNC_NORETURN void z_x86_prep_c(void *arg) +FUNC_NORETURN void z_prep_c(void *arg) { x86_boot_arg_t *cpu_arg = arg; diff --git a/arch/x86/include/kernel_arch_func.h b/arch/x86/include/kernel_arch_func.h index 7c080b8e25b..00b411978ec 100644 --- a/arch/x86/include/kernel_arch_func.h +++ b/arch/x86/include/kernel_arch_func.h @@ -37,7 +37,7 @@ static inline bool arch_is_in_isr(void) struct multiboot_info; -extern FUNC_NORETURN void z_x86_prep_c(void *arg); +extern FUNC_NORETURN void z_prep_c(void *arg); #ifdef CONFIG_X86_VERY_EARLY_CONSOLE /* Setup ultra-minimal serial driver for printk() */ diff --git a/doc/services/debugging/gdbstub.rst b/doc/services/debugging/gdbstub.rst index 50b830fb5b8..c2062ec304d 100644 --- a/doc/services/debugging/gdbstub.rst +++ b/doc/services/debugging/gdbstub.rst @@ -149,7 +149,7 @@ for its implementation as a Twister test. #1 0x00105068 in gdb_init (arg=0x0) at /subsys/debug/gdbstub.c:833 #2 0x00109d6f in z_sys_init_run_level (level=0x1) at /kernel/device.c:72 #3 0x0010a40b in z_cstart () at /kernel/init.c:423 - #4 0x00105383 in z_x86_prep_c (arg=0x9500) at /arch/x86/core/prep_c.c:58 + #4 0x00105383 in z_prep_c (arg=0x9500) at /arch/x86/core/prep_c.c:58 #5 0x001000a9 in __csSet () at /arch/x86/core/ia32/crt0.S:273 #. Use command ``list`` to show the source code and surroundings where From ae39c3f7d784a48254835bae3e47c489eb812b17 Mon Sep 17 00:00:00 2001 From: Anas Nashif Date: Fri, 8 Dec 2023 08:08:54 -0500 Subject: [PATCH 1049/3723] arch: arm: z_arm_prep_c -> z_prep_c Rename to use common naming for z_prep_c applied to all architectures. Signed-off-by: Anas Nashif --- arch/arm/core/cortex_a_r/prep_c.c | 2 +- arch/arm/core/cortex_a_r/reset.S | 4 ++-- arch/arm/core/cortex_a_r/vector_table.h | 2 +- arch/arm/core/cortex_m/prep_c.c | 2 +- arch/arm/core/cortex_m/reset.S | 6 +++--- arch/arm/core/cortex_m/vector_table.h | 2 +- 6 files changed, 9 insertions(+), 9 deletions(-) diff --git a/arch/arm/core/cortex_a_r/prep_c.c b/arch/arm/core/cortex_a_r/prep_c.c index 95dbb49cf1e..e510d06ee95 100644 --- a/arch/arm/core/cortex_a_r/prep_c.c +++ b/arch/arm/core/cortex_a_r/prep_c.c @@ -145,7 +145,7 @@ extern FUNC_NORETURN void z_cstart(void); * This routine prepares for the execution of and runs C code. * */ -void z_arm_prep_c(void) +void z_prep_c(void) { /* Initialize tpidruro with our struct _cpu instance address */ write_tpidruro((uintptr_t)&_kernel.cpus[0]); diff --git a/arch/arm/core/cortex_a_r/reset.S b/arch/arm/core/cortex_a_r/reset.S index ff3c35e0f18..362f4aa214f 100644 --- a/arch/arm/core/cortex_a_r/reset.S +++ b/arch/arm/core/cortex_a_r/reset.S @@ -42,7 +42,7 @@ GTEXT(z_arm_platform_init) * and interrupts are disabled. The processor architectural registers are in * an indeterminate state. * - * When these steps are completed, jump to z_arm_prep_c(), which will finish + * When these steps are completed, jump to z_prep_c(), which will finish * setting up the system for running C code. * */ @@ -229,7 +229,7 @@ EL1_Reset_Handler: _primary_core: #endif - ldr r4, =z_arm_prep_c + ldr r4, =z_prep_c ldr r5, =(z_arm_fiq_stack + CONFIG_ARMV7_FIQ_STACK_SIZE) ldr r6, =(z_interrupt_stacks + CONFIG_ISR_STACK_SIZE) ldr r7, =(z_arm_abort_stack + CONFIG_ARMV7_EXCEPTION_STACK_SIZE) diff --git a/arch/arm/core/cortex_a_r/vector_table.h b/arch/arm/core/cortex_a_r/vector_table.h index 7d2122b4828..449b6044d9c 100644 --- a/arch/arm/core/cortex_a_r/vector_table.h +++ b/arch/arm/core/cortex_a_r/vector_table.h @@ -40,7 +40,7 @@ GTEXT(z_arm_data_abort) GTEXT(z_arm_pendsv) GTEXT(z_arm_reserved) -GTEXT(z_arm_prep_c) +GTEXT(z_prep_c) GTEXT(_isr_wrapper) #else /* _ASMLANGUAGE */ diff --git a/arch/arm/core/cortex_m/prep_c.c b/arch/arm/core/cortex_m/prep_c.c index 329f7f8987d..422d45b57e1 100644 --- a/arch/arm/core/cortex_m/prep_c.c +++ b/arch/arm/core/cortex_m/prep_c.c @@ -179,7 +179,7 @@ extern FUNC_NORETURN void z_cstart(void); * This routine prepares for the execution of and runs C code. * */ -void z_arm_prep_c(void) +void z_prep_c(void) { relocate_vector_table(); #if defined(CONFIG_CPU_HAS_FPU) diff --git a/arch/arm/core/cortex_m/reset.S b/arch/arm/core/cortex_m/reset.S index 6c5599b9fb8..332f1a60c10 100644 --- a/arch/arm/core/cortex_m/reset.S +++ b/arch/arm/core/cortex_m/reset.S @@ -53,7 +53,7 @@ GTEXT(arch_pm_s2ram_resume) * MSP is to be set up to point to the one-and-only interrupt stack during * later boot. That would not be possible if in use for running C code. * - * When these steps are completed, jump to z_arm_prep_c(), which will finish + * When these steps are completed, jump to z_prep_c(), which will finish * setting up the system for running C code. * */ @@ -163,7 +163,7 @@ SECTION_SUBSEC_FUNC(TEXT,_reset_section,__start) /* * 'bl' jumps the furthest of the branch instructions that are - * supported on all platforms. So it is used when jumping to z_arm_prep_c + * supported on all platforms. So it is used when jumping to z_prep_c * (even though we do not intend to return). */ - bl z_arm_prep_c + bl z_prep_c diff --git a/arch/arm/core/cortex_m/vector_table.h b/arch/arm/core/cortex_m/vector_table.h index f79765aefbf..a10663b4821 100644 --- a/arch/arm/core/cortex_m/vector_table.h +++ b/arch/arm/core/cortex_m/vector_table.h @@ -50,7 +50,7 @@ GTEXT(z_arm_debug_monitor) GTEXT(z_arm_pendsv) GTEXT(z_arm_exc_spurious) -GTEXT(z_arm_prep_c) +GTEXT(z_prep_c) #if defined(CONFIG_GEN_ISR_TABLES) GTEXT(_isr_wrapper) #endif /* CONFIG_GEN_ISR_TABLES */ From a9f95f18aaf2b7a0b9c70fe2ce17a6d45e0c2b33 Mon Sep 17 00:00:00 2001 From: Ali Hozhabri Date: Mon, 20 Nov 2023 17:48:47 +0100 Subject: [PATCH 1050/3723] dts: bindings: bluetooth: Add new yaml files for ST SPI protocol V1 and V2 Add "st,hci-spi-v1.yaml" to represent STMicroelectronics SPI protocol V1 which is used by BlueNRG-MS devices. Add "st,hci-spi-v2.yaml" to show STMicroelectronics SPI protocol V2 utilized by BlueNRG-1 and successor devices. Signed-off-by: Ali Hozhabri --- dts/bindings/bluetooth/st,hci-spi-v1.yaml | 6 ++++++ dts/bindings/bluetooth/st,hci-spi-v2.yaml | 6 ++++++ 2 files changed, 12 insertions(+) create mode 100644 dts/bindings/bluetooth/st,hci-spi-v1.yaml create mode 100644 dts/bindings/bluetooth/st,hci-spi-v2.yaml diff --git a/dts/bindings/bluetooth/st,hci-spi-v1.yaml b/dts/bindings/bluetooth/st,hci-spi-v1.yaml new file mode 100644 index 00000000000..d61b936c5b6 --- /dev/null +++ b/dts/bindings/bluetooth/st,hci-spi-v1.yaml @@ -0,0 +1,6 @@ +# Copyright (c) 2023, STMicroelectronics +# SPDX-License-Identifier: Apache-2.0 + +description: STMicroelectronics SPI protocol V1 compatible with BlueNRG-MS devices + +compatible: "st,hci-spi-v1" diff --git a/dts/bindings/bluetooth/st,hci-spi-v2.yaml b/dts/bindings/bluetooth/st,hci-spi-v2.yaml new file mode 100644 index 00000000000..58e91e496e2 --- /dev/null +++ b/dts/bindings/bluetooth/st,hci-spi-v2.yaml @@ -0,0 +1,6 @@ +# Copyright (c) 2023, STMicroelectronics +# SPDX-License-Identifier: Apache-2.0 + +description: STMicroelectronics SPI protocol V2 compatible with BlueNRG-1 and successor devices + +compatible: "st,hci-spi-v2" From d9c4ce7255e60e8472225406b96b56d68573b562 Mon Sep 17 00:00:00 2001 From: Ali Hozhabri Date: Mon, 20 Nov 2023 18:09:02 +0100 Subject: [PATCH 1051/3723] boards: arm: DTS update for ST boards that include BlueNRG-MS Update DTS files of the STMicroelectronics boards which have BlueNRG-MS as a BLE module. Signed-off-by: Ali Hozhabri --- boards/arm/b_l4s5i_iot01a/b_l4s5i_iot01a.dts | 2 +- boards/arm/disco_l475_iot1/disco_l475_iot1.dts | 2 +- boards/arm/stm32l562e_dk/stm32l562e_dk_common.dtsi | 2 +- boards/shields/x_nucleo_idb05a1/x_nucleo_idb05a1.overlay | 2 +- 4 files changed, 4 insertions(+), 4 deletions(-) diff --git a/boards/arm/b_l4s5i_iot01a/b_l4s5i_iot01a.dts b/boards/arm/b_l4s5i_iot01a/b_l4s5i_iot01a.dts index 9f8900921f6..fe6322cc26b 100644 --- a/boards/arm/b_l4s5i_iot01a/b_l4s5i_iot01a.dts +++ b/boards/arm/b_l4s5i_iot01a/b_l4s5i_iot01a.dts @@ -152,7 +152,7 @@ <&gpioe 0 GPIO_ACTIVE_LOW>; spbtle-rf@0 { - compatible = "zephyr,bt-hci-spi"; + compatible = "zephyr,bt-hci-spi", "st,hci-spi-v1"; reg = <0>; reset-gpios = <&gpioa 8 (GPIO_ACTIVE_LOW | GPIO_PULL_UP)>; irq-gpios = <&gpioe 6 (GPIO_ACTIVE_HIGH | GPIO_PULL_DOWN)>; diff --git a/boards/arm/disco_l475_iot1/disco_l475_iot1.dts b/boards/arm/disco_l475_iot1/disco_l475_iot1.dts index a37b801b3e4..c52142cbaff 100644 --- a/boards/arm/disco_l475_iot1/disco_l475_iot1.dts +++ b/boards/arm/disco_l475_iot1/disco_l475_iot1.dts @@ -191,7 +191,7 @@ <&gpioe 0 GPIO_ACTIVE_LOW>; spbtle-rf@0 { - compatible = "zephyr,bt-hci-spi"; + compatible = "zephyr,bt-hci-spi", "st,hci-spi-v1"; reg = <0>; reset-gpios = <&gpioa 8 (GPIO_ACTIVE_LOW | GPIO_PULL_UP)>; irq-gpios = <&gpioe 6 (GPIO_ACTIVE_HIGH | GPIO_PULL_DOWN)>; diff --git a/boards/arm/stm32l562e_dk/stm32l562e_dk_common.dtsi b/boards/arm/stm32l562e_dk/stm32l562e_dk_common.dtsi index 5bb8c567ee6..17b00f6daca 100644 --- a/boards/arm/stm32l562e_dk/stm32l562e_dk_common.dtsi +++ b/boards/arm/stm32l562e_dk/stm32l562e_dk_common.dtsi @@ -115,7 +115,7 @@ status = "okay"; spbtle-rf@0 { - compatible = "zephyr,bt-hci-spi"; + compatible = "zephyr,bt-hci-spi", "st,hci-spi-v1"; reg = <0>; irq-gpios = <&gpiog 6 (GPIO_ACTIVE_HIGH | GPIO_PULL_DOWN)>; reset-gpios = <&gpiog 8 (GPIO_ACTIVE_LOW | GPIO_PULL_UP)>; diff --git a/boards/shields/x_nucleo_idb05a1/x_nucleo_idb05a1.overlay b/boards/shields/x_nucleo_idb05a1/x_nucleo_idb05a1.overlay index 8ccf3d7dbf0..dbb23935f03 100644 --- a/boards/shields/x_nucleo_idb05a1/x_nucleo_idb05a1.overlay +++ b/boards/shields/x_nucleo_idb05a1/x_nucleo_idb05a1.overlay @@ -8,7 +8,7 @@ cs-gpios = <&arduino_header 1 (GPIO_ACTIVE_LOW | GPIO_PULL_UP)>; /* A1 */ spbtle_rf_x_nucleo_idb05a1: spbtle-rf@0 { - compatible = "zephyr,bt-hci-spi"; + compatible = "zephyr,bt-hci-spi", "st,hci-spi-v1"; reg = <0>; reset-gpios = <&arduino_header 13 (GPIO_ACTIVE_LOW | GPIO_PULL_UP)>; /* D7 */ irq-gpios = <&arduino_header 0 (GPIO_ACTIVE_HIGH | GPIO_PULL_DOWN)>; /* A0 */ From 36b0e26e6499a2a223c276548f8ec6ef09cb4749 Mon Sep 17 00:00:00 2001 From: Ali Hozhabri Date: Tue, 21 Nov 2023 10:23:10 +0100 Subject: [PATCH 1052/3723] drivers: bluetooth: hci: Restructure spi.c to handle different protocols Update structure of spi.c to have a better and cleaner separation between STMicroelectronics and Zephyr SPI protocol. Introduce bt_spi_get_header to separate algorithms well for header acquisition in different protocols. Remove header acquisition from bt_spi_rx_thread to make it simpler. Signed-off-by: Ali Hozhabri --- drivers/bluetooth/hci/spi.c | 129 +++++++++++++++++++++--------------- 1 file changed, 75 insertions(+), 54 deletions(-) diff --git a/drivers/bluetooth/hci/spi.c b/drivers/bluetooth/hci/spi.c index a2cabc46215..7891c525248 100644 --- a/drivers/bluetooth/hci/spi.c +++ b/drivers/bluetooth/hci/spi.c @@ -85,14 +85,6 @@ static K_SEM_DEFINE(sem_busy, 1, 1); static K_KERNEL_STACK_DEFINE(spi_rx_stack, CONFIG_BT_DRV_RX_STACK_SIZE); static struct k_thread spi_rx_thread_data; -#if defined(CONFIG_BT_SPI_BLUENRG) -/* Define a limit when reading IRQ high */ -/* It can be required to be increased for */ -/* some particular cases. */ -#define IRQ_HIGH_MAX_READ 3 -static uint8_t attempts; -#endif /* CONFIG_BT_SPI_BLUENRG */ - #if defined(CONFIG_BT_BLUENRG_ACI) #define BLUENRG_ACI_WRITE_CONFIG_DATA BT_OP(BT_OGF_VS, 0x000C) #define BLUENRG_CONFIG_PUBADDR_OFFSET 0x00 @@ -167,16 +159,18 @@ static bool bt_spi_handle_vendor_evt(uint8_t *msg) return handled; } +#define IS_IRQ_HIGH gpio_pin_get_dt(&irq_gpio) + #if defined(CONFIG_BT_SPI_BLUENRG) -/* BlueNRG has a particuliar way to wake up from sleep and be ready. - * All is done through its CS line: - * If it is in sleep mode, the first transaction will not return ready - * status. At this point, it's necessary to release the CS and retry - * within 2ms the same transaction. And again when it's required to - * know the amount of byte to read. - * (See section 5.2 of BlueNRG-MS datasheet) - */ -static void kick_cs(void) +/* Define a limit when reading IRQ high */ +/* It can be required to be increased for */ +/* some particular cases. */ +#define IRQ_HIGH_MAX_READ 3 +/* On BlueNRG-MS, host is expected to read */ +/* as long as IRQ pin is high */ +#define READ_CONDITION IS_IRQ_HIGH + +static void assert_cs(void) { gpio_pin_set_dt(&bus.config.cs.gpio, 0); gpio_pin_set_dt(&bus.config.cs.gpio, 1); @@ -187,40 +181,79 @@ static void release_cs(void) gpio_pin_set_dt(&bus.config.cs.gpio, 0); } -static bool irq_pin_high(void) +static int bt_spi_get_header(uint8_t op, uint8_t *size) { - int pin_state; + uint8_t header_master[5] = {op, 0, 0, 0, 0}; + uint8_t header_slave[5]; + uint8_t size_offset, attempts; + int ret; - pin_state = gpio_pin_get_dt(&irq_gpio); + if (op == SPI_READ) { + if (!IS_IRQ_HIGH) { + *size = 0; + return 0; + } + size_offset = STATUS_HEADER_TOREAD; + } + attempts = IRQ_HIGH_MAX_READ; + do { + if (op == SPI_READ) { + /* Keep checking that IRQ is still high, if we need to read */ + if (!IS_IRQ_HIGH) { + *size = 0; + return 0; + } + } + assert_cs(); + ret = bt_spi_transceive(header_master, 5, header_slave, 5); + if (ret) { + /* SPI transaction failed */ + break; + } - LOG_DBG("IRQ Pin: %d", pin_state); + *size = (header_slave[STATUS_HEADER_READY] == READY_NOW) ? + header_slave[size_offset] : 0; + attempts--; + } while ((*size == 0) && attempts); - return pin_state > 0; + return ret; } -static void init_irq_high_loop(void) -{ - attempts = IRQ_HIGH_MAX_READ; -} +/* Other Boards */ +#else -static bool exit_irq_high_loop(void) -{ - /* Limit attempts on BlueNRG-MS as we might */ - /* enter this loop with nothing to read */ +#define release_cs(...) +#define READ_CONDITION false - attempts--; +static int bt_spi_get_header(uint8_t op, uint8_t *size) +{ + uint8_t header_master[5] = {op, 0, 0, 0, 0}; + uint8_t header_slave[5]; + bool reading = (op == SPI_READ); + bool loop_cond; + uint8_t size_offset; + int ret; - return attempts; -} + if (reading) { + size_offset = STATUS_HEADER_TOREAD; + } -#else + do { + ret = bt_spi_transceive(header_master, 5, header_slave, 5); + if (ret) { + break; + } + if (reading) { + /* When reading, keep looping if read buffer is not valid */ + loop_cond = ((header_slave[STATUS_HEADER_TOREAD] == 0U) || + (header_slave[STATUS_HEADER_TOREAD] == 0xFF)); + } + } while ((header_slave[STATUS_HEADER_READY] != READY_NOW) || loop_cond); -#define kick_cs(...) -#define release_cs(...) -#define irq_pin_high(...) 0 -#define init_irq_high_loop(...) -#define exit_irq_high_loop(...) 1 + *size = (reading ? header_slave[size_offset] : SPI_MAX_MSG_LEN); + return ret; +} #endif /* CONFIG_BT_SPI_BLUENRG */ #if defined(CONFIG_BT_BLUENRG_ACI) @@ -328,8 +361,6 @@ static void bt_spi_rx_thread(void *p1, void *p2, void *p3) ARG_UNUSED(p2); ARG_UNUSED(p3); - uint8_t header_master[5] = { SPI_READ, 0x00, 0x00, 0x00, 0x00 }; - uint8_t header_slave[5]; struct net_buf *buf; uint8_t size = 0U; int ret; @@ -345,18 +376,11 @@ static void bt_spi_rx_thread(void *p1, void *p2, void *p3) do { /* Wait for SPI bus to be available */ k_sem_take(&sem_busy, K_FOREVER); - init_irq_high_loop(); - do { - kick_cs(); - ret = bt_spi_transceive(header_master, 5, - header_slave, 5); - } while ((((header_slave[STATUS_HEADER_TOREAD] == 0U || - header_slave[STATUS_HEADER_TOREAD] == 0xFF) && - !ret)) && exit_irq_high_loop()); + ret = bt_spi_get_header(SPI_READ, &size); /* Delay here is rounded up to next tick */ k_sleep(K_USEC(DATA_DELAY_US)); - size = header_slave[STATUS_HEADER_TOREAD]; + /* Read data */ if (ret == 0 && size != 0) { do { ret = bt_spi_transceive(&txmsg, size, @@ -390,10 +414,7 @@ static void bt_spi_rx_thread(void *p1, void *p2, void *p3) /* Handle the received HCI data */ bt_recv(buf); } - - /* On BlueNRG-MS, host is expected to read */ - /* as long as IRQ pin is high */ - } while (irq_pin_high()); + } while (READ_CONDITION); } } From 810df7cef9bfe3f6a9bbf982524f4adfa25965ec Mon Sep 17 00:00:00 2001 From: Ali Hozhabri Date: Wed, 22 Nov 2023 12:54:21 +0100 Subject: [PATCH 1053/3723] drivers: bluetooth: hci: Remove header acquisition from bt_spi_send Replace the header acquisition scope in bt_spi_send with bt_spi_get_header. Add WRITE_DATA_CONDITION in order not to retransmit data without reading the header as it is meaningless for ST BlueNRG devices. Signed-off-by: Ali Hozhabri --- drivers/bluetooth/hci/spi.c | 36 ++++++++++++++++++++---------------- 1 file changed, 20 insertions(+), 16 deletions(-) diff --git a/drivers/bluetooth/hci/spi.c b/drivers/bluetooth/hci/spi.c index 7891c525248..e055e956502 100644 --- a/drivers/bluetooth/hci/spi.c +++ b/drivers/bluetooth/hci/spi.c @@ -36,6 +36,7 @@ LOG_MODULE_REGISTER(bt_driver); /* Offsets */ #define STATUS_HEADER_READY 0 #define STATUS_HEADER_TOREAD 3 +#define STATUS_HEADER_TOWRITE 1 #define PACKET_TYPE 0 #define EVT_HEADER_TYPE 0 @@ -169,6 +170,8 @@ static bool bt_spi_handle_vendor_evt(uint8_t *msg) /* On BlueNRG-MS, host is expected to read */ /* as long as IRQ pin is high */ #define READ_CONDITION IS_IRQ_HIGH +/* We cannot retry write data without reading again the header */ +#define WRITE_DATA_CONDITION(...) true static void assert_cs(void) { @@ -194,6 +197,8 @@ static int bt_spi_get_header(uint8_t op, uint8_t *size) return 0; } size_offset = STATUS_HEADER_TOREAD; + } else if (op == SPI_WRITE) { + size_offset = STATUS_HEADER_TOWRITE; } attempts = IRQ_HIGH_MAX_READ; do { @@ -224,6 +229,7 @@ static int bt_spi_get_header(uint8_t op, uint8_t *size) #define release_cs(...) #define READ_CONDITION false +#define WRITE_DATA_CONDITION(ret, rx_first) (rx_first != 0U || ret) static int bt_spi_get_header(uint8_t op, uint8_t *size) { @@ -247,6 +253,10 @@ static int bt_spi_get_header(uint8_t op, uint8_t *size) /* When reading, keep looping if read buffer is not valid */ loop_cond = ((header_slave[STATUS_HEADER_TOREAD] == 0U) || (header_slave[STATUS_HEADER_TOREAD] == 0xFF)); + } else { + /* When writing, keep looping if all bytes are zero */ + loop_cond = ((header_slave[1] | header_slave[2] | header_slave[3] | + header_slave[4]) == 0U); } } while ((header_slave[STATUS_HEADER_READY] != READY_NOW) || loop_cond); @@ -420,8 +430,7 @@ static void bt_spi_rx_thread(void *p1, void *p2, void *p3) static int bt_spi_send(struct net_buf *buf) { - uint8_t header_tx[5] = { SPI_WRITE, 0x00, 0x00, 0x00, 0x00 }; - uint8_t header_rx[5]; + uint8_t size; uint8_t rx_first[1]; int ret; @@ -449,33 +458,28 @@ static int bt_spi_send(struct net_buf *buf) return -EINVAL; } - /* Poll sanity values until device has woken-up */ - do { - kick_cs(); - ret = bt_spi_transceive(header_tx, 5, header_rx, 5); + ret = bt_spi_get_header(SPI_WRITE, &size); + size = MIN(buf->len, size); - /* - * RX Header must contain a sanity check Byte and size - * information. If it does not contain BOTH then it is - * sleeping or still in the initialisation stage (waking-up). - */ - } while ((header_rx[STATUS_HEADER_READY] != READY_NOW || - (header_rx[1] | header_rx[2] | header_rx[3] | header_rx[4]) == 0U) && !ret); + if (size < buf->len) { + LOG_WRN("Unable to write full data, skipping"); + ret = -ECANCELED; + } if (!ret) { /* Delay here is rounded up to next tick */ k_sleep(K_USEC(DATA_DELAY_US)); /* Transmit the message */ while (true) { - ret = bt_spi_transceive(buf->data, buf->len, + ret = bt_spi_transceive(buf->data, size, rx_first, 1); - if (rx_first[0] != 0U || ret) { + if (WRITE_DATA_CONDITION(ret, rx_first[0])) { break; } /* Consider increasing controller-data-delay-us * if this message is extremely common. */ - LOG_DBG("Controller not ready for SPI transaction of %d bytes", buf->len); + LOG_DBG("Controller not ready for SPI transaction of %d bytes", size); } } From a67bc25b5f3d9f2dd50e042c030947730c83cc60 Mon Sep 17 00:00:00 2001 From: Ali Hozhabri Date: Wed, 22 Nov 2023 13:01:32 +0100 Subject: [PATCH 1054/3723] drivers: bluetooth: hci: Introduce ST SPI protocol V2 Introduce STMicroelectronics SPI protocol V2 which is used in BlueNRG-1 and successor devices. Change the size of the variable "size" to 16 bits as it is necessary for ST BlueNRG-1 and successor devices. Signed-off-by: Ali Hozhabri --- drivers/bluetooth/hci/spi.c | 86 ++++++++++++++++++++++++++++++++----- 1 file changed, 75 insertions(+), 11 deletions(-) diff --git a/drivers/bluetooth/hci/spi.c b/drivers/bluetooth/hci/spi.c index e055e956502..69a102ae696 100644 --- a/drivers/bluetooth/hci/spi.c +++ b/drivers/bluetooth/hci/spi.c @@ -162,7 +162,7 @@ static bool bt_spi_handle_vendor_evt(uint8_t *msg) #define IS_IRQ_HIGH gpio_pin_get_dt(&irq_gpio) -#if defined(CONFIG_BT_SPI_BLUENRG) +#if DT_HAS_COMPAT_STATUS_OKAY(st_hci_spi_v1) /* Define a limit when reading IRQ high */ /* It can be required to be increased for */ /* some particular cases. */ @@ -179,12 +179,13 @@ static void assert_cs(void) gpio_pin_set_dt(&bus.config.cs.gpio, 1); } -static void release_cs(void) +static void release_cs(bool data_transaction) { + ARG_UNUSED(data_transaction); gpio_pin_set_dt(&bus.config.cs.gpio, 0); } -static int bt_spi_get_header(uint8_t op, uint8_t *size) +static int bt_spi_get_header(uint8_t op, uint16_t *size) { uint8_t header_master[5] = {op, 0, 0, 0, 0}; uint8_t header_slave[5]; @@ -224,6 +225,68 @@ static int bt_spi_get_header(uint8_t op, uint8_t *size) return ret; } +#elif DT_HAS_COMPAT_STATUS_OKAY(st_hci_spi_v2) + +#define READ_CONDITION false +/* We cannot retry writing data without reading the header again */ +#define WRITE_DATA_CONDITION(...) true + +static void assert_cs(uint16_t delay) +{ + gpio_pin_set_dt(&bus.config.cs.gpio, 0); + if (delay) { + k_sleep(K_USEC(delay)); + } + gpio_pin_set_dt(&bus.config.cs.gpio, 1); + gpio_pin_interrupt_configure_dt(&irq_gpio, GPIO_INT_DISABLE); +} + +static void release_cs(bool data_transaction) +{ + /* Consume possible event signals */ + while (k_sem_take(&sem_request, K_NO_WAIT) == 0) { + } + if (data_transaction) { + /* Wait for IRQ to become low only when data phase has been performed */ + while (IS_IRQ_HIGH) { + } + } + gpio_pin_interrupt_configure_dt(&irq_gpio, GPIO_INT_EDGE_TO_ACTIVE); + gpio_pin_set_dt(&bus.config.cs.gpio, 0); +} + +static int bt_spi_get_header(uint8_t op, uint16_t *size) +{ + uint8_t header_master[5] = {op, 0, 0, 0, 0}; + uint8_t header_slave[5]; + uint16_t cs_delay; + uint8_t size_offset; + int ret; + + if (op == SPI_READ) { + if (!IS_IRQ_HIGH) { + *size = 0; + return 0; + } + cs_delay = 0; + size_offset = STATUS_HEADER_TOREAD; + } else if (op == SPI_WRITE) { + /* To make sure we have a minimum delay from previous release cs */ + cs_delay = 100; + size_offset = STATUS_HEADER_TOWRITE; + } + + assert_cs(cs_delay); + /* Wait up to a maximum time of 100 ms */ + if (!WAIT_FOR(IS_IRQ_HIGH, 100000, k_usleep(100))) { + LOG_ERR("IRQ pin did not raise"); + return -EIO; + } + + ret = bt_spi_transceive(header_master, 5, header_slave, 5); + *size = header_slave[size_offset] | (header_slave[size_offset + 1] << 8); + return ret; +} /* Other Boards */ #else @@ -231,7 +294,7 @@ static int bt_spi_get_header(uint8_t op, uint8_t *size) #define READ_CONDITION false #define WRITE_DATA_CONDITION(ret, rx_first) (rx_first != 0U || ret) -static int bt_spi_get_header(uint8_t op, uint8_t *size) +static int bt_spi_get_header(uint8_t op, uint16_t *size) { uint8_t header_master[5] = {op, 0, 0, 0, 0}; uint8_t header_slave[5]; @@ -264,7 +327,7 @@ static int bt_spi_get_header(uint8_t op, uint8_t *size) return ret; } -#endif /* CONFIG_BT_SPI_BLUENRG */ +#endif /* DT_HAS_COMPAT_STATUS_OKAY(st_hci_spi_v1) */ #if defined(CONFIG_BT_BLUENRG_ACI) static int bt_spi_send_aci_config(uint8_t offset, const uint8_t *value, size_t value_len) @@ -372,7 +435,7 @@ static void bt_spi_rx_thread(void *p1, void *p2, void *p3) ARG_UNUSED(p3); struct net_buf *buf; - uint8_t size = 0U; + uint16_t size = 0U; int ret; (void)memset(&txmsg, 0xFF, SPI_MAX_MSG_LEN); @@ -405,7 +468,7 @@ static void bt_spi_rx_thread(void *p1, void *p2, void *p3) } while (rxmsg[0] == 0U && ret == 0); } - release_cs(); + release_cs(size > 0); k_sem_give(&sem_busy); @@ -430,7 +493,7 @@ static void bt_spi_rx_thread(void *p1, void *p2, void *p3) static int bt_spi_send(struct net_buf *buf) { - uint8_t size; + uint16_t size; uint8_t rx_first[1]; int ret; @@ -463,6 +526,7 @@ static int bt_spi_send(struct net_buf *buf) if (size < buf->len) { LOG_WRN("Unable to write full data, skipping"); + size = 0; ret = -ECANCELED; } @@ -483,7 +547,7 @@ static int bt_spi_send(struct net_buf *buf) } } - release_cs(); + release_cs(size > 0); k_sem_give(&sem_busy); @@ -494,7 +558,7 @@ static int bt_spi_send(struct net_buf *buf) LOG_HEXDUMP_DBG(buf->data, buf->len, "SPI TX"); -#if defined(CONFIG_BT_SPI_BLUENRG) +#if (DT_HAS_COMPAT_STATUS_OKAY(st_hci_spi_v1) || DT_HAS_COMPAT_STATUS_OKAY(st_hci_spi_v2)) /* * Since a RESET has been requested, the chip will now restart. * Unfortunately the BlueNRG will reply with "reset received" but @@ -505,7 +569,7 @@ static int bt_spi_send(struct net_buf *buf) if (bt_spi_get_cmd(buf->data) == BT_HCI_OP_RESET) { k_sem_take(&sem_initialised, K_FOREVER); } -#endif /* CONFIG_BT_SPI_BLUENRG */ +#endif /* DT_HAS_COMPAT_STATUS_OKAY(st_hci_spi_v1) || DT_HAS_COMPAT_STATUS_OKAY(st_hci_spi_v2) */ out: net_buf_unref(buf); From 8a32a706899a3733d142ace199cb6f4d6342ea56 Mon Sep 17 00:00:00 2001 From: Ali Hozhabri Date: Tue, 21 Nov 2023 15:31:45 +0100 Subject: [PATCH 1055/3723] boards: arm: sensortile_box: Add BLE support for SensorTile.box board Add BLE support for SensorTile.box board. Signed-off-by: Ali Hozhabri --- boards/arm/sensortile_box/Kconfig.defconfig | 22 ++++++++++++++++--- boards/arm/sensortile_box/sensortile_box.dts | 18 +++++++++++++++ boards/arm/sensortile_box/sensortile_box.yaml | 1 + 3 files changed, 38 insertions(+), 3 deletions(-) diff --git a/boards/arm/sensortile_box/Kconfig.defconfig b/boards/arm/sensortile_box/Kconfig.defconfig index 4287849bf31..1f3d19b39ca 100644 --- a/boards/arm/sensortile_box/Kconfig.defconfig +++ b/boards/arm/sensortile_box/Kconfig.defconfig @@ -8,11 +8,27 @@ if BOARD_SENSORTILE_BOX config BOARD default "sensortile_box" -if SPI +if BT -config SPI_STM32_INTERRUPT +config SPI + default y + +choice BT_HCI_BUS_TYPE + default BT_SPI +endchoice + +config BT_BLUENRG_ACI default y +# Disable Flow control +config BT_HCI_ACL_FLOW_CONTROL + default n +config BT_HCI_VS_EXT + default n -endif # SPI +endif # BT + +config SPI_STM32_INTERRUPT + default y + depends on SPI endif # BOARD_SENSORTILE_BOX diff --git a/boards/arm/sensortile_box/sensortile_box.dts b/boards/arm/sensortile_box/sensortile_box.dts index e622d5c190f..b8622020840 100644 --- a/boards/arm/sensortile_box/sensortile_box.dts +++ b/boards/arm/sensortile_box/sensortile_box.dts @@ -161,6 +161,24 @@ }; }; +&spi2 { + pinctrl-0 = <&spi2_sck_pd1 &spi2_miso_pd3 &spi2_mosi_pc3>; + pinctrl-names = "default"; + status = "okay"; + cs-gpios = <&gpiod 0 (GPIO_ACTIVE_LOW | GPIO_PULL_UP)>; + spbtle_1s_sensortile_box: spbtle-1s@0 { + compatible = "zephyr,bt-hci-spi", "st,hci-spi-v2"; + reg = <0>; + reset-gpios = <&gpioa 8 (GPIO_ACTIVE_LOW | GPIO_PULL_UP)>; + irq-gpios = <&gpiod 4 (GPIO_ACTIVE_HIGH | GPIO_PULL_DOWN)>; + spi-max-frequency = <1000000>; + spi-cpha; + spi-hold-cs; + controller-data-delay-us = <0>; + reset-assert-duration-ms = <6>; + }; +}; + &spi3 { pinctrl-0 = <&spi3_nss_pa15 &spi3_sck_pb3 &spi3_miso_pb4 &spi3_mosi_pb5>; diff --git a/boards/arm/sensortile_box/sensortile_box.yaml b/boards/arm/sensortile_box/sensortile_box.yaml index e67e105021b..aaa655bf84c 100644 --- a/boards/arm/sensortile_box/sensortile_box.yaml +++ b/boards/arm/sensortile_box/sensortile_box.yaml @@ -9,6 +9,7 @@ toolchain: supported: - pwm - spi + - ble - i2c - gpio - usb device From e3ec41e15c7bf36bc214e72d3d7958ace76717af Mon Sep 17 00:00:00 2001 From: Ali Hozhabri Date: Tue, 21 Nov 2023 15:38:44 +0100 Subject: [PATCH 1056/3723] drivers: bluetooth: hci: Remove config BT_SPI_BLUENRG Remove BT_SPI_BLUENRG Kconfig parameter as it is redundant according to the new changes introduced by ST SPI protocol V1 and V2. Remove "config BT_SPI_BLUENRG" from the boards that were using it. Signed-off-by: Ali Hozhabri --- boards/arm/b_l4s5i_iot01a/Kconfig.defconfig | 3 --- boards/arm/disco_l475_iot1/Kconfig.defconfig | 3 --- boards/arm/stm32l562e_dk/Kconfig.defconfig | 3 --- boards/shields/x_nucleo_idb05a1/Kconfig.defconfig | 3 --- drivers/bluetooth/hci/Kconfig | 6 ------ 5 files changed, 18 deletions(-) diff --git a/boards/arm/b_l4s5i_iot01a/Kconfig.defconfig b/boards/arm/b_l4s5i_iot01a/Kconfig.defconfig index 61d4c1167ad..059f36907a2 100644 --- a/boards/arm/b_l4s5i_iot01a/Kconfig.defconfig +++ b/boards/arm/b_l4s5i_iot01a/Kconfig.defconfig @@ -34,9 +34,6 @@ choice BT_HCI_BUS_TYPE default BT_SPI endchoice -config BT_SPI_BLUENRG - default y - config BT_BLUENRG_ACI default y # Disable Flow control diff --git a/boards/arm/disco_l475_iot1/Kconfig.defconfig b/boards/arm/disco_l475_iot1/Kconfig.defconfig index 847c9ec0878..3a53147decf 100644 --- a/boards/arm/disco_l475_iot1/Kconfig.defconfig +++ b/boards/arm/disco_l475_iot1/Kconfig.defconfig @@ -34,9 +34,6 @@ choice BT_HCI_BUS_TYPE default BT_SPI endchoice -config BT_SPI_BLUENRG - default y - config BT_BLUENRG_ACI default y # Disable Flow control diff --git a/boards/arm/stm32l562e_dk/Kconfig.defconfig b/boards/arm/stm32l562e_dk/Kconfig.defconfig index bec20b338f5..3a81889dc71 100644 --- a/boards/arm/stm32l562e_dk/Kconfig.defconfig +++ b/boards/arm/stm32l562e_dk/Kconfig.defconfig @@ -17,9 +17,6 @@ choice BT_HCI_BUS_TYPE default BT_SPI endchoice -config BT_SPI_BLUENRG - default y - config BT_BLUENRG_ACI default y diff --git a/boards/shields/x_nucleo_idb05a1/Kconfig.defconfig b/boards/shields/x_nucleo_idb05a1/Kconfig.defconfig index eb2ec1c1372..430b8a860f7 100644 --- a/boards/shields/x_nucleo_idb05a1/Kconfig.defconfig +++ b/boards/shields/x_nucleo_idb05a1/Kconfig.defconfig @@ -12,9 +12,6 @@ choice BT_HCI_BUS_TYPE default BT_SPI endchoice -config BT_SPI_BLUENRG - default y - config BT_BLUENRG_ACI default y # Disable Flow control diff --git a/drivers/bluetooth/hci/Kconfig b/drivers/bluetooth/hci/Kconfig index 86e450c52c2..b1901d504a8 100644 --- a/drivers/bluetooth/hci/Kconfig +++ b/drivers/bluetooth/hci/Kconfig @@ -125,12 +125,6 @@ config BT_BLUENRG_ACI Enable support for devices compatible with the BlueNRG Bluetooth Stack. Current driver supports: ST BLUENRG-MS. -config BT_SPI_BLUENRG - bool "Compatibility with BlueNRG-based devices" - help - Enable support for devices compatible with the BlueNRG Bluetooth - Stack. Current driver supports: ST BLUENRG-MS. - endif # BT_SPI config BT_STM32_IPM_RX_STACK_SIZE From bd227e19cff9855355468974f1f984ed88f2cf3d Mon Sep 17 00:00:00 2001 From: Anas Nashif Date: Tue, 28 Nov 2023 15:15:52 -0500 Subject: [PATCH 1057/3723] twister: ignore testplan filters for integration mode Testplan filters should be ignored when evaluating correctness of integration configuration. Signed-off-by: Anas Nashif --- scripts/pylib/twister/twisterlib/testplan.py | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/scripts/pylib/twister/twisterlib/testplan.py b/scripts/pylib/twister/twisterlib/testplan.py index 002180dc675..c1db18d44c7 100755 --- a/scripts/pylib/twister/twisterlib/testplan.py +++ b/scripts/pylib/twister/twisterlib/testplan.py @@ -56,6 +56,8 @@ class Filters: CMD_LINE = 'command line filter' # filters in the testsuite yaml definition TESTSUITE = 'testsuite filter' + # filters in the testplan yaml definition + TESTPLAN = 'testplan filter' # filters realted to platform definition PLATFORM = 'Platform related filter' # in case a test suite was quarantined. @@ -717,7 +719,7 @@ def apply_filters(self, **kwargs): tl = self.get_level(self.options.level) planned_scenarios = tl.scenarios if ts.id not in planned_scenarios and not set(ts.levels).intersection(set(tl.levels)): - instance.add_filter("Not part of requested test plan", Filters.TESTSUITE) + instance.add_filter("Not part of requested test plan", Filters.TESTPLAN) if runnable and not instance.run: instance.add_filter("Not runnable on device", Filters.CMD_LINE) @@ -1006,10 +1008,10 @@ def change_skip_to_error_if_integration(options, instance): ''' All skips on integration_platforms are treated as errors.''' if instance.platform.name in instance.testsuite.integration_platforms \ and "quarantine" not in instance.reason.lower(): - # Do not treat this as error if filter type is command line + # Do not treat this as error for a list of filter types. filters = {t['type'] for t in instance.filters} ignore_filters ={Filters.CMD_LINE, Filters.SKIP, Filters.PLATFORM_KEY, - Filters.TOOLCHAIN, Filters.MODULE} + Filters.TOOLCHAIN, Filters.MODULE, Filters.TESTPLAN} if filters.intersection(ignore_filters): return instance.status = "error" From 11d4f8e5e5adec6202a942796ba214d117f9f947 Mon Sep 17 00:00:00 2001 From: Luca Burelli Date: Thu, 30 Nov 2023 14:32:05 +0100 Subject: [PATCH 1058/3723] soc: stm32: unify cache conditionals for F7 and H7 targets The instruction cache in the STM32F7 and H7 was enabled regardless of the value assigned via Kconfig to the CONFIG_ICACHE parameter. This commit adds the missing conditional checks; note that this does not affect the compiled behavior unless CONFIG_ICACHE is explicitly disabled by the user. Remove a redundant low-level check on DCache being already enabled, since it is also performed inside the SCB_EnableDCache function. Signed-off-by: Luca Burelli --- soc/arm/st_stm32/stm32f7/soc.c | 8 ++++---- soc/arm/st_stm32/stm32h7/soc_m7.c | 8 ++++---- 2 files changed, 8 insertions(+), 8 deletions(-) diff --git a/soc/arm/st_stm32/stm32f7/soc.c b/soc/arm/st_stm32/stm32f7/soc.c index b06a894197a..19941c9cee0 100644 --- a/soc/arm/st_stm32/stm32f7/soc.c +++ b/soc/arm/st_stm32/stm32f7/soc.c @@ -30,12 +30,12 @@ static int st_stm32f7_init(void) /* Enable ART Flash cache accelerator */ LL_FLASH_EnableART(); - SCB_EnableICache(); + if (IS_ENABLED(CONFIG_ICACHE)) { + SCB_EnableICache(); + } if (IS_ENABLED(CONFIG_DCACHE)) { - if (!(SCB->CCR & SCB_CCR_DC_Msk)) { - SCB_EnableDCache(); - } + SCB_EnableDCache(); } /* Update CMSIS SystemCoreClock variable (HCLK) */ diff --git a/soc/arm/st_stm32/stm32h7/soc_m7.c b/soc/arm/st_stm32/stm32h7/soc_m7.c index 8e72b3ee390..7ee62921c41 100644 --- a/soc/arm/st_stm32/stm32h7/soc_m7.c +++ b/soc/arm/st_stm32/stm32h7/soc_m7.c @@ -54,12 +54,12 @@ static int stm32h7_m4_wakeup(void) */ static int stm32h7_init(void) { - SCB_EnableICache(); + if (IS_ENABLED(CONFIG_ICACHE)) { + SCB_EnableICache(); + } if (IS_ENABLED(CONFIG_DCACHE)) { - if (!(SCB->CCR & SCB_CCR_DC_Msk)) { - SCB_EnableDCache(); - } + SCB_EnableDCache(); } /* Update CMSIS SystemCoreClock variable (HCLK) */ From fde31c03c58078c56a0414ce8676fae2179d8fe4 Mon Sep 17 00:00:00 2001 From: Jun Lin Date: Fri, 8 Dec 2023 13:36:05 +0800 Subject: [PATCH 1059/3723] driver: crypto: SHA: npcx: fix SHA driver for npcx4 QS chip The commit fixes the SHA driver because the ROM API has the following changes from ES to QS chip: 1. base addres: from 0x13c -> 0x148 2. required SHA context buffer size : from 228 -> 240 bytes This change also adds a check for the pre-allocated buffer size of the SHA context when the driver initiliazes. Signed-off-by: Jun Lin --- drivers/crypto/crypto_npcx_sha.c | 20 +++++++++++++++++--- dts/arm/nuvoton/npcx/npcx4.dtsi | 4 ++-- 2 files changed, 19 insertions(+), 5 deletions(-) diff --git a/drivers/crypto/crypto_npcx_sha.c b/drivers/crypto/crypto_npcx_sha.c index 26403599360..7354ea5877b 100644 --- a/drivers/crypto/crypto_npcx_sha.c +++ b/drivers/crypto/crypto_npcx_sha.c @@ -13,9 +13,9 @@ #include LOG_MODULE_REGISTER(sha_npcx, CONFIG_CRYPTO_LOG_LEVEL); -#define NPCX_HASH_CAPS_SUPPORT (CAP_SEPARATE_IO_BUFS | CAP_SYNC_OPS) +#define NPCX_HASH_CAPS_SUPPORT (CAP_SEPARATE_IO_BUFS | CAP_SYNC_OPS) #define NPCX_SHA256_HANDLE_SIZE DT_INST_PROP(0, context_buffer_size) -#define NPCX_SHA_MAX_SESSION 1 +#define NPCX_SHA_MAX_SESSION 1 /* The status code returns from Nuvoton Cryptographic Library ROM APIs */ enum ncl_status { @@ -204,13 +204,27 @@ static int npcx_query_caps(const struct device *dev) return NPCX_HASH_CAPS_SUPPORT; } +static int npcx_hash_init(const struct device *dev) +{ + uint32_t handle_size_required; + + handle_size_required = NPCX_NCL_SHA->get_context_size(); + if (handle_size_required != NPCX_SHA256_HANDLE_SIZE) { + LOG_ERR("Pre-alloc buf size doesn't match required buf size (%d)", + handle_size_required); + return -ENOSR; + } + + return 0; +} + static struct crypto_driver_api npcx_crypto_api = { .hash_begin_session = npcx_hash_session_setup, .hash_free_session = npcx_hash_session_free, .query_hw_caps = npcx_query_caps, }; -DEVICE_DT_INST_DEFINE(0, NULL, NULL, NULL, NULL, POST_KERNEL, CONFIG_CRYPTO_INIT_PRIORITY, +DEVICE_DT_INST_DEFINE(0, npcx_hash_init, NULL, NULL, NULL, POST_KERNEL, CONFIG_CRYPTO_INIT_PRIORITY, &npcx_crypto_api); BUILD_ASSERT(DT_NUM_INST_STATUS_OKAY(DT_DRV_COMPAT) == 1, "only one 'nuvoton,npcx-sha' compatible node can be supported"); diff --git a/dts/arm/nuvoton/npcx/npcx4.dtsi b/dts/arm/nuvoton/npcx/npcx4.dtsi index 36f6bb579b8..e18bd89f103 100644 --- a/dts/arm/nuvoton/npcx/npcx4.dtsi +++ b/dts/arm/nuvoton/npcx/npcx4.dtsi @@ -291,8 +291,8 @@ sha0: sha@13c { compatible = "nuvoton,npcx-sha"; - reg = <0x13c 0x3c>; - context-buffer-size = <228>; + reg = <0x148 0x4c>; + context-buffer-size = <240>; status = "disabled"; }; From a19eb7cf88d7e9d8a7db2810abceb221e0b7a56d Mon Sep 17 00:00:00 2001 From: Francois Ramu Date: Tue, 17 Oct 2023 09:10:55 +0200 Subject: [PATCH 1060/3723] drivers: timer: stm32 lptimer clock prescaler property Rename to LPTIM_PRESCALER, the prescaler of the stm32 LPTimer. This commit gives better readability than LPTIM_CLOCK_RATIO. Signed-off-by: Francois Ramu --- drivers/timer/stm32_lptim_timer.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/drivers/timer/stm32_lptim_timer.c b/drivers/timer/stm32_lptim_timer.c index ffda551524d..f3d5f64a061 100644 --- a/drivers/timer/stm32_lptim_timer.c +++ b/drivers/timer/stm32_lptim_timer.c @@ -65,7 +65,7 @@ static uint32_t lptim_clock_freq = KHZ(32); static int32_t lptim_time_base; /* The prescaler given by the DTS and to apply to the lptim_clock_freq */ -#define LPTIM_CLOCK_RATIO DT_PROP(DT_DRV_INST(0), st_prescaler) +#define LPTIM_PRESCALER DT_PROP(DT_DRV_INST(0), st_prescaler) /* Minimum nb of clock cycles to have to set autoreload register correctly */ #define LPTIM_GUARD_VALUE 2 @@ -388,7 +388,7 @@ static int sys_clock_driver_init(void) } /* Actual lptim clock freq when the clock source is reduced by the prescaler */ - lptim_clock_freq = lptim_clock_freq / LPTIM_CLOCK_RATIO; + lptim_clock_freq = lptim_clock_freq / LPTIM_PRESCALER; /* Clear the event flag and possible pending interrupt */ IRQ_CONNECT(DT_INST_IRQN(0), @@ -404,7 +404,7 @@ static int sys_clock_driver_init(void) /* configure the LPTIM counter */ LL_LPTIM_SetClockSource(LPTIM, LL_LPTIM_CLK_SOURCE_INTERNAL); /* the LPTIM clock freq is affected by the prescaler */ - LL_LPTIM_SetPrescaler(LPTIM, (__CLZ(__RBIT(LPTIM_CLOCK_RATIO)) << LPTIM_CFGR_PRESC_Pos)); + LL_LPTIM_SetPrescaler(LPTIM, (__CLZ(__RBIT(LPTIM_PRESCALER)) << LPTIM_CFGR_PRESC_Pos)); #if defined(CONFIG_SOC_SERIES_STM32U5X) || \ defined(CONFIG_SOC_SERIES_STM32WBAX) LL_LPTIM_OC_SetPolarity(LPTIM, LL_LPTIM_CHANNEL_CH1, From eeb7a88ff0bcb8436796cf4e76e86859706eb195 Mon Sep 17 00:00:00 2001 From: Francois Ramu Date: Fri, 17 Nov 2023 09:56:07 +0100 Subject: [PATCH 1061/3723] drivers: timer: stm32 lptimer adjust the TICKS_PER_SEC to LPTIM clock With low LPTIM freq when prescaler is set to 16 or 32, the CONFIG_SYS_CLOCK_TICKS_PER_SEC must be reduced to LPTIM CLOCK_/prescaler to avoid spurious timer wakeup activity. Assert error if the CONFIG_SYS_CLOCK_TICKS_PER_SEC is not compatible with the lptim clock freq. Signed-off-by: Francois Ramu --- drivers/timer/stm32_lptim_timer.c | 53 +++++++++++++++++++++---------- 1 file changed, 37 insertions(+), 16 deletions(-) diff --git a/drivers/timer/stm32_lptim_timer.c b/drivers/timer/stm32_lptim_timer.c index f3d5f64a061..0a95c84af58 100644 --- a/drivers/timer/stm32_lptim_timer.c +++ b/drivers/timer/stm32_lptim_timer.c @@ -61,11 +61,26 @@ static const struct device *const clk_ctrl = DEVICE_DT_GET(STM32_CLOCK_CONTROL_N * 0xFFFF / (LSE freq (32768Hz) / 128) */ -static uint32_t lptim_clock_freq = KHZ(32); static int32_t lptim_time_base; - +static uint32_t lptim_clock_freq = CONFIG_STM32_LPTIM_CLOCK; /* The prescaler given by the DTS and to apply to the lptim_clock_freq */ -#define LPTIM_PRESCALER DT_PROP(DT_DRV_INST(0), st_prescaler) +static uint32_t lptim_clock_presc = DT_PROP(DT_DRV_INST(0), st_prescaler); + +#if (CONFIG_STM32_LPTIM_CLOCK_LSI) + +/* Kconfig defines the clock source as LSI : check coherency with DTS */ +#if (DT_INST_CLOCKS_CELL_BY_IDX(0, 1, bus) != STM32_SRC_LSI) +#warning CONFIG_STM32_LPTIM_CLOCK_LSI requires STM32_SRC_LSI defined as LPTIM domain clock +#endif /* STM32_SRC_LSI */ + +#elif (CONFIG_STM32_LPTIM_CLOCK_LSE) + +/* Kconfig defines the clock source as LSE : check coherency with DTS */ +#if (DT_INST_CLOCKS_CELL_BY_IDX(0, 1, bus) != STM32_SRC_LSE) +#warning CONFIG_STM32_LPTIM_CLOCK_LSE requires STM32_SRC_LSE defined as LPTIM domain clock +#endif /* STM32_SRC_LSE */ + +#endif /* CONFIG_STM32_LPTIM_CLOCK_LSI */ /* Minimum nb of clock cycles to have to set autoreload register correctly */ #define LPTIM_GUARD_VALUE 2 @@ -81,17 +96,6 @@ static bool autoreload_ready = true; static struct k_spinlock lock; -/* For tick accuracy, a specific tick to freq ratio is expected */ -/* This check assumes LSI@32KHz or LSE@32768Hz */ -#if !defined(CONFIG_STM32_LPTIM_TICK_FREQ_RATIO_OVERRIDE) -#if (((DT_CLOCKS_CELL_BY_IDX(DT_DRV_INST(0), 1, bus) == STM32_SRC_LSI) && \ - (CONFIG_SYS_CLOCK_TICKS_PER_SEC != 4000)) || \ - ((DT_CLOCKS_CELL_BY_IDX(DT_DRV_INST(0), 1, bus) == STM32_SRC_LSE) && \ - (CONFIG_SYS_CLOCK_TICKS_PER_SEC != 4096))) -#warning Advised tick freq is 4096 for LSE / 4000 for LSI -#endif -#endif /* !CONFIG_STM32_LPTIM_TICK_FREQ_RATIO_OVERRIDE */ - static inline bool arrm_state_get(void) { return (LL_LPTIM_IsActiveFlag_ARRM(LPTIM) && LL_LPTIM_IsEnabledIT_ARRM(LPTIM)); @@ -387,8 +391,24 @@ static int sys_clock_driver_init(void) return -EIO; } +#if !defined(CONFIG_STM32_LPTIM_TICK_FREQ_RATIO_OVERRIDE) + /* + * Check coherency between CONFIG_SYS_CLOCK_TICKS_PER_SEC + * and the lptim_clock_freq which is the CONFIG_STM32_LPTIM_CLOCK reduced + * by the lptim_clock_presc + */ + if (lptim_clock_presc <= 8) { + __ASSERT(CONFIG_STM32_LPTIM_CLOCK / 8 >= CONFIG_SYS_CLOCK_TICKS_PER_SEC, + "It is recommended to set SYS_CLOCK_TICKS_PER_SEC to CONFIG_STM32_LPTIM_CLOCK/8"); + } else { + __ASSERT(CONFIG_STM32_LPTIM_CLOCK / lptim_clock_presc >= + CONFIG_SYS_CLOCK_TICKS_PER_SEC, + "Set SYS_CLOCK_TICKS_PER_SEC to CONFIG_STM32_LPTIM_CLOCK/lptim_clock_presc"); + } +#endif /* !CONFIG_STM32_LPTIM_TICK_FREQ_RATIO_OVERRIDE */ + /* Actual lptim clock freq when the clock source is reduced by the prescaler */ - lptim_clock_freq = lptim_clock_freq / LPTIM_PRESCALER; + lptim_clock_freq = lptim_clock_freq / lptim_clock_presc; /* Clear the event flag and possible pending interrupt */ IRQ_CONNECT(DT_INST_IRQN(0), @@ -404,7 +424,8 @@ static int sys_clock_driver_init(void) /* configure the LPTIM counter */ LL_LPTIM_SetClockSource(LPTIM, LL_LPTIM_CLK_SOURCE_INTERNAL); /* the LPTIM clock freq is affected by the prescaler */ - LL_LPTIM_SetPrescaler(LPTIM, (__CLZ(__RBIT(LPTIM_PRESCALER)) << LPTIM_CFGR_PRESC_Pos)); + LL_LPTIM_SetPrescaler(LPTIM, (__CLZ(__RBIT(lptim_clock_presc)) << LPTIM_CFGR_PRESC_Pos)); + #if defined(CONFIG_SOC_SERIES_STM32U5X) || \ defined(CONFIG_SOC_SERIES_STM32WBAX) LL_LPTIM_OC_SetPolarity(LPTIM, LL_LPTIM_CHANNEL_CH1, From 5bacc2eaac90096df2829ff7fecad85fc3e638bb Mon Sep 17 00:00:00 2001 From: Francois Ramu Date: Thu, 12 Oct 2023 13:25:20 +0200 Subject: [PATCH 1062/3723] soc: arm: stm32 SYS_CLOCK_TICKS_PER_SEC config with STM32_LPTIM_TIMER Configure the SYS_CLOCK_TICKS_PER_SEC directly from the DTS st-prescaler property of the lptim node aka stm32_lp_tick_source Signed-off-by: Francois Ramu --- .../st_stm32/common/Kconfig.defconfig.series | 21 +++++++++++++++++-- 1 file changed, 19 insertions(+), 2 deletions(-) diff --git a/soc/arm/st_stm32/common/Kconfig.defconfig.series b/soc/arm/st_stm32/common/Kconfig.defconfig.series index 40dda7b6fa0..c1d0237e1ee 100644 --- a/soc/arm/st_stm32/common/Kconfig.defconfig.series +++ b/soc/arm/st_stm32/common/Kconfig.defconfig.series @@ -13,6 +13,9 @@ config CORTEX_M_SYSTICK DT_STM32_RCC_PATH := $(dt_nodelabel_path,rcc) DT_STM32_RCC_CLOCK_FREQ := $(dt_node_int_prop_int,$(DT_STM32_RCC_PATH),clock-frequency) +DT_ST_PRESCALER := st,prescaler +DT_STM32_LPTIM_PATH := $(dt_nodelabel_path,stm32_lp_tick_source) + config SYS_CLOCK_HW_CYCLES_PER_SEC default "$(DT_STM32_RCC_CLOCK_FREQ)" if "$(dt_nodelabel_enabled,rcc)" @@ -24,9 +27,23 @@ config LOG_BACKEND_SWO_REF_FREQ_HZ endif # LOG_BACKEND_SWO # set the tick per sec as a divider of the LPTIM clock source +# with a minimum value of 4096 for SYS_CLOCK_TICKS_PER_SEC to keep +# SYS_CLOCK_TICKS_PER_SEC not too high compared to the LPTIM counter clock +config SYS_CLOCK_TICKS_PER_SEC + default 4096 if "$(dt_node_int_prop_int,$(DT_STM32_LPTIM_PATH),$(DT_ST_PRESCALER))" < 16 + default 2048 if "$(dt_node_int_prop_int,$(DT_STM32_LPTIM_PATH),$(DT_ST_PRESCALER))" = 16 + default 1024 if "$(dt_node_int_prop_int,$(DT_STM32_LPTIM_PATH),$(DT_ST_PRESCALER))" = 32 + default 512 if "$(dt_node_int_prop_int,$(DT_STM32_LPTIM_PATH),$(DT_ST_PRESCALER))" = 64 + default 256 if "$(dt_node_int_prop_int,$(DT_STM32_LPTIM_PATH),$(DT_ST_PRESCALER))" = 128 + depends on STM32_LPTIM_TIMER && STM32_LPTIM_CLOCK_LSE + config SYS_CLOCK_TICKS_PER_SEC - default 4096 if STM32_LPTIM_TIMER && STM32_LPTIM_CLOCK_LSE - default 4000 if STM32_LPTIM_TIMER && STM32_LPTIM_CLOCK_LSI + default 4000 if "$(dt_node_int_prop_int,$(DT_STM32_LPTIM_PATH),$(DT_ST_PRESCALER))" < 16 + default 2000 if "$(dt_node_int_prop_int,$(DT_STM32_LPTIM_PATH),$(DT_ST_PRESCALER))" = 16 + default 1000 if "$(dt_node_int_prop_int,$(DT_STM32_LPTIM_PATH),$(DT_ST_PRESCALER))" = 32 + default 500 if "$(dt_node_int_prop_int,$(DT_STM32_LPTIM_PATH),$(DT_ST_PRESCALER))" = 64 + default 250 if "$(dt_node_int_prop_int,$(DT_STM32_LPTIM_PATH),$(DT_ST_PRESCALER))" = 128 + depends on STM32_LPTIM_TIMER && STM32_LPTIM_CLOCK_LSI config CLOCK_CONTROL_STM32_CUBE default y From 759c9b42e385e2e343ab066efc05bbbf37a79a2f Mon Sep 17 00:00:00 2001 From: Francois Ramu Date: Thu, 12 Oct 2023 17:13:14 +0200 Subject: [PATCH 1063/3723] boards: arm: stm32 boards with lptimer set node stm32_lp_tick_source Change the name of the node for the lptim used as lowpower tick source to stm32_lp_tick_source. Once enabled, this node is known as stm32_lp_tick_source That will avoid naming the node lptim1 or lptim2 or lptim, etc. Signed-off-by: Francois Ramu --- boards/arm/b_g474e_dpow1/b_g474e_dpow1.dts | 2 +- boards/arm/b_u585i_iot02a/b_u585i_iot02a-common.dtsi | 2 +- boards/arm/disco_l475_iot1/disco_l475_iot1.dts | 2 +- boards/arm/lora_e5_dev_board/lora_e5_dev_board.dts | 2 +- boards/arm/nucleo_g071rb/nucleo_g071rb.dts | 2 +- boards/arm/nucleo_g0b1re/nucleo_g0b1re.dts | 2 +- boards/arm/nucleo_g431rb/nucleo_g431rb.dts | 2 +- boards/arm/nucleo_g474re/nucleo_g474re.dts | 2 +- boards/arm/nucleo_l073rz/nucleo_l073rz.dts | 6 +++++- boards/arm/nucleo_l476rg/nucleo_l476rg.dts | 2 +- boards/arm/nucleo_wb55rg/nucleo_wb55rg.dts | 2 +- boards/arm/nucleo_wba52cg/nucleo_wba52cg.dts | 2 +- boards/arm/nucleo_wba55cg/nucleo_wba55cg.dts | 2 +- boards/arm/nucleo_wl55jc/nucleo_wl55jc.dts | 2 +- .../olimex_lora_stm32wl_devkit.dts | 2 +- boards/arm/sensortile_box_pro/sensortile_box_pro.dts | 2 +- boards/arm/stm32l562e_dk/stm32l562e_dk_common.dtsi | 2 +- boards/arm/weact_stm32g431_core/weact_stm32g431_core.dts | 2 +- dts/bindings/timer/st,stm32-lptim.yaml | 8 +++++++- 19 files changed, 29 insertions(+), 19 deletions(-) diff --git a/boards/arm/b_g474e_dpow1/b_g474e_dpow1.dts b/boards/arm/b_g474e_dpow1/b_g474e_dpow1.dts index d5dc048b48a..1eb84827718 100644 --- a/boards/arm/b_g474e_dpow1/b_g474e_dpow1.dts +++ b/boards/arm/b_g474e_dpow1/b_g474e_dpow1.dts @@ -95,7 +95,7 @@ status = "okay"; }; -&lptim1 { +stm32_lp_tick_source: &lptim1 { clocks = <&rcc STM32_CLOCK_BUS_APB1 0x80000000>, <&rcc STM32_SRC_LSI LPTIM1_SEL(1)>; status = "okay"; diff --git a/boards/arm/b_u585i_iot02a/b_u585i_iot02a-common.dtsi b/boards/arm/b_u585i_iot02a/b_u585i_iot02a-common.dtsi index b9b07348f3c..f2dd82f9ad1 100644 --- a/boards/arm/b_u585i_iot02a/b_u585i_iot02a-common.dtsi +++ b/boards/arm/b_u585i_iot02a/b_u585i_iot02a-common.dtsi @@ -73,7 +73,7 @@ apb3-prescaler = <1>; }; -&lptim1 { +stm32_lp_tick_source: &lptim1 { clocks = <&rcc STM32_CLOCK_BUS_APB3 0x00000800>, <&rcc STM32_SRC_LSE LPTIM1_SEL(3)>; status = "okay"; diff --git a/boards/arm/disco_l475_iot1/disco_l475_iot1.dts b/boards/arm/disco_l475_iot1/disco_l475_iot1.dts index c52142cbaff..85e0dcea3c2 100644 --- a/boards/arm/disco_l475_iot1/disco_l475_iot1.dts +++ b/boards/arm/disco_l475_iot1/disco_l475_iot1.dts @@ -262,7 +262,7 @@ }; }; -&lptim1 { +stm32_lp_tick_source: &lptim1 { clocks = <&rcc STM32_CLOCK_BUS_APB1 0x80000000>, <&rcc STM32_SRC_LSE LPTIM1_SEL(3)>; status = "okay"; diff --git a/boards/arm/lora_e5_dev_board/lora_e5_dev_board.dts b/boards/arm/lora_e5_dev_board/lora_e5_dev_board.dts index 268573de547..390e949cfce 100644 --- a/boards/arm/lora_e5_dev_board/lora_e5_dev_board.dts +++ b/boards/arm/lora_e5_dev_board/lora_e5_dev_board.dts @@ -79,7 +79,7 @@ }; }; -&lptim1 { +stm32_lp_tick_source: &lptim1 { status = "okay"; clocks = <&rcc STM32_CLOCK_BUS_APB1 0x80000000>, <&rcc STM32_SRC_LSI LPTIM1_SEL(1)>; diff --git a/boards/arm/nucleo_g071rb/nucleo_g071rb.dts b/boards/arm/nucleo_g071rb/nucleo_g071rb.dts index 76b2369280e..9c510e49864 100644 --- a/boards/arm/nucleo_g071rb/nucleo_g071rb.dts +++ b/boards/arm/nucleo_g071rb/nucleo_g071rb.dts @@ -170,7 +170,7 @@ }; }; -&lptim1 { +stm32_lp_tick_source: &lptim1 { clocks = <&rcc STM32_CLOCK_BUS_APB1 0x80000000>, <&rcc STM32_SRC_LSI LPTIM1_SEL(1)>; status = "okay"; diff --git a/boards/arm/nucleo_g0b1re/nucleo_g0b1re.dts b/boards/arm/nucleo_g0b1re/nucleo_g0b1re.dts index 17d22e5e9d4..9e024db953a 100644 --- a/boards/arm/nucleo_g0b1re/nucleo_g0b1re.dts +++ b/boards/arm/nucleo_g0b1re/nucleo_g0b1re.dts @@ -214,7 +214,7 @@ zephyr_udc0: &usb { }; }; -&lptim1 { +stm32_lp_tick_source: &lptim1 { clocks = <&rcc STM32_CLOCK_BUS_APB1 0x80000000>, <&rcc STM32_SRC_LSI LPTIM1_SEL(1)>; status = "okay"; diff --git a/boards/arm/nucleo_g431rb/nucleo_g431rb.dts b/boards/arm/nucleo_g431rb/nucleo_g431rb.dts index 0bdf2b7d301..9303087c1dc 100644 --- a/boards/arm/nucleo_g431rb/nucleo_g431rb.dts +++ b/boards/arm/nucleo_g431rb/nucleo_g431rb.dts @@ -148,7 +148,7 @@ }; }; -&lptim1 { +stm32_lp_tick_source: &lptim1 { clocks = <&rcc STM32_CLOCK_BUS_APB1 0x80000000>, <&rcc STM32_SRC_LSE LPTIM1_SEL(3)>; status = "okay"; diff --git a/boards/arm/nucleo_g474re/nucleo_g474re.dts b/boards/arm/nucleo_g474re/nucleo_g474re.dts index 33c071d0adb..8a87f6e0d01 100644 --- a/boards/arm/nucleo_g474re/nucleo_g474re.dts +++ b/boards/arm/nucleo_g474re/nucleo_g474re.dts @@ -152,7 +152,7 @@ }; }; -&lptim1 { +stm32_lp_tick_source: &lptim1 { clocks = <&rcc STM32_CLOCK_BUS_APB1 0x80000000>, <&rcc STM32_SRC_LSI LPTIM1_SEL(1)>; status = "okay"; diff --git a/boards/arm/nucleo_l073rz/nucleo_l073rz.dts b/boards/arm/nucleo_l073rz/nucleo_l073rz.dts index b5cf07203a6..93571670b7d 100644 --- a/boards/arm/nucleo_l073rz/nucleo_l073rz.dts +++ b/boards/arm/nucleo_l073rz/nucleo_l073rz.dts @@ -89,7 +89,11 @@ apb2-prescaler = <1>; }; -&lptim1 { +stm32_lp_tick_source: &lptim1 { + /* + * LSI freq is 37KHz but stm32_lptim driver is using 32000Hz + * resulting in time running 1.13 faster than reality + */ clocks = <&rcc STM32_CLOCK_BUS_APB1 0x80000000>, <&rcc STM32_SRC_LSI LPTIM1_SEL(1)>; status = "okay"; diff --git a/boards/arm/nucleo_l476rg/nucleo_l476rg.dts b/boards/arm/nucleo_l476rg/nucleo_l476rg.dts index b39a87345e5..573c121dfd1 100644 --- a/boards/arm/nucleo_l476rg/nucleo_l476rg.dts +++ b/boards/arm/nucleo_l476rg/nucleo_l476rg.dts @@ -75,7 +75,7 @@ apb2-prescaler = <1>; }; -&lptim1 { +stm32_lp_tick_source: &lptim1 { clocks = <&rcc STM32_CLOCK_BUS_APB1 0x80000000>, <&rcc STM32_SRC_LSI LPTIM1_SEL(1)>; status = "okay"; diff --git a/boards/arm/nucleo_wb55rg/nucleo_wb55rg.dts b/boards/arm/nucleo_wb55rg/nucleo_wb55rg.dts index eed2cef9368..21806ca24af 100644 --- a/boards/arm/nucleo_wb55rg/nucleo_wb55rg.dts +++ b/boards/arm/nucleo_wb55rg/nucleo_wb55rg.dts @@ -186,7 +186,7 @@ status = "okay"; }; -&lptim1 { +stm32_lp_tick_source: &lptim1 { clocks = <&rcc STM32_CLOCK_BUS_APB1 0x80000000>, <&rcc STM32_SRC_LSE LPTIM1_SEL(3)>; status = "okay"; diff --git a/boards/arm/nucleo_wba52cg/nucleo_wba52cg.dts b/boards/arm/nucleo_wba52cg/nucleo_wba52cg.dts index df2707f4eeb..755454fcff3 100644 --- a/boards/arm/nucleo_wba52cg/nucleo_wba52cg.dts +++ b/boards/arm/nucleo_wba52cg/nucleo_wba52cg.dts @@ -125,7 +125,7 @@ status = "okay"; }; -&lptim1 { +stm32_lp_tick_source: &lptim1 { clocks = <&rcc STM32_CLOCK_BUS_APB7 0x00000800>, <&rcc STM32_SRC_LSE LPTIM1_SEL(3)>; status = "okay"; diff --git a/boards/arm/nucleo_wba55cg/nucleo_wba55cg.dts b/boards/arm/nucleo_wba55cg/nucleo_wba55cg.dts index 5f190357a0d..86d755cba50 100644 --- a/boards/arm/nucleo_wba55cg/nucleo_wba55cg.dts +++ b/boards/arm/nucleo_wba55cg/nucleo_wba55cg.dts @@ -126,7 +126,7 @@ status = "okay"; }; -&lptim1 { +stm32_lp_tick_source: &lptim1 { clocks = <&rcc STM32_CLOCK_BUS_APB7 0x00000800>, <&rcc STM32_SRC_LSE LPTIM1_SEL(3)>; status = "okay"; diff --git a/boards/arm/nucleo_wl55jc/nucleo_wl55jc.dts b/boards/arm/nucleo_wl55jc/nucleo_wl55jc.dts index deff3a96cdc..1a5e0d2e73e 100644 --- a/boards/arm/nucleo_wl55jc/nucleo_wl55jc.dts +++ b/boards/arm/nucleo_wl55jc/nucleo_wl55jc.dts @@ -75,7 +75,7 @@ status = "okay"; }; -&lptim1 { +stm32_lp_tick_source: &lptim1 { clocks = <&rcc STM32_CLOCK_BUS_APB1 0x80000000>, <&rcc STM32_SRC_LSI LPTIM1_SEL(1)>; status = "okay"; diff --git a/boards/arm/olimex_lora_stm32wl_devkit/olimex_lora_stm32wl_devkit.dts b/boards/arm/olimex_lora_stm32wl_devkit/olimex_lora_stm32wl_devkit.dts index b24649edb71..6d26b7c3f19 100644 --- a/boards/arm/olimex_lora_stm32wl_devkit/olimex_lora_stm32wl_devkit.dts +++ b/boards/arm/olimex_lora_stm32wl_devkit/olimex_lora_stm32wl_devkit.dts @@ -45,7 +45,7 @@ }; }; -&lptim1 { +stm32_lp_tick_source: &lptim1 { clocks = <&rcc STM32_CLOCK_BUS_APB1 0x80000000>, <&rcc STM32_SRC_LSI LPTIM1_SEL(1)>; status = "okay"; diff --git a/boards/arm/sensortile_box_pro/sensortile_box_pro.dts b/boards/arm/sensortile_box_pro/sensortile_box_pro.dts index 485ec6b6e7d..dc3f7ba9c64 100644 --- a/boards/arm/sensortile_box_pro/sensortile_box_pro.dts +++ b/boards/arm/sensortile_box_pro/sensortile_box_pro.dts @@ -130,7 +130,7 @@ apb3-prescaler = <1>; }; -&lptim1 { +stm32_lp_tick_source: &lptim1 { clocks = <&rcc STM32_CLOCK_BUS_APB3 0x00000800>, <&rcc STM32_SRC_LSE LPTIM1_SEL(3)>; status = "okay"; diff --git a/boards/arm/stm32l562e_dk/stm32l562e_dk_common.dtsi b/boards/arm/stm32l562e_dk/stm32l562e_dk_common.dtsi index 17b00f6daca..97263620f2e 100644 --- a/boards/arm/stm32l562e_dk/stm32l562e_dk_common.dtsi +++ b/boards/arm/stm32l562e_dk/stm32l562e_dk_common.dtsi @@ -71,7 +71,7 @@ apb2-prescaler = <1>; }; -&lptim1 { +stm32_lp_tick_source: &lptim1 { clocks = <&rcc STM32_CLOCK_BUS_APB1 0x80000000>, <&rcc STM32_SRC_LSE LPTIM1_SEL(3)>; status = "okay"; diff --git a/boards/arm/weact_stm32g431_core/weact_stm32g431_core.dts b/boards/arm/weact_stm32g431_core/weact_stm32g431_core.dts index cdfe959b3fd..ca6dfcf6569 100644 --- a/boards/arm/weact_stm32g431_core/weact_stm32g431_core.dts +++ b/boards/arm/weact_stm32g431_core/weact_stm32g431_core.dts @@ -119,7 +119,7 @@ <&rcc STM32_SRC_LSE RTC_SEL(1)>; }; -&lptim1 { +stm32_lp_tick_source: &lptim1 { status = "okay"; clocks = <&rcc STM32_CLOCK_BUS_APB1 0x80000000>, <&rcc STM32_SRC_LSE LPTIM1_SEL(3)>; diff --git a/dts/bindings/timer/st,stm32-lptim.yaml b/dts/bindings/timer/st,stm32-lptim.yaml index 90db9084800..5792e38ef8d 100644 --- a/dts/bindings/timer/st,stm32-lptim.yaml +++ b/dts/bindings/timer/st,stm32-lptim.yaml @@ -1,7 +1,13 @@ # Copyright (c) 2020, STMicroelectronics # SPDX-License-Identifier: Apache-2.0 -description: STM32 lptim +description: | + STM32 lptim : low power timer + The lptim node to be used for counting ticks during lowpower modes + must be named stm32_lp_tick_source in the DTS, as follows: + stm32_lp_tick_source: &lptim1 { + status = "okay"; + } compatible: "st,stm32-lptim" From 302aae2749ecad108ae412646f249a5669c64993 Mon Sep 17 00:00:00 2001 From: Francois Ramu Date: Fri, 17 Nov 2023 09:51:14 +0100 Subject: [PATCH 1064/3723] doc: releases: add the reference to stm32_lp_tick_source Update migration guide to introduce the stm32_lp_tick_source for stm32 device when choosing the LPTIM fo lowPower modes. Signed-off-by: Francois Ramu --- doc/releases/migration-guide-3.6.rst | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/doc/releases/migration-guide-3.6.rst b/doc/releases/migration-guide-3.6.rst index bd37aa56fb1..f22e921fa15 100644 --- a/doc/releases/migration-guide-3.6.rst +++ b/doc/releases/migration-guide-3.6.rst @@ -118,6 +118,16 @@ Device Drivers and Device Tree * - ``DT_INST_BUS_LABEL(inst)`` - ``DT_PROP(DT_BUS(DT_DRV_INST(inst)), label)`` +* The :dtcompatible:`st,stm32-lptim` lptim which is selected for counting ticks during + low power modes is identified by **stm32_lp_tick_source** in the device tree as follows. + The stm32_lptim_timer driver has been changed to support this. + + .. code-block:: devicetree + + stm32_lp_tick_source: &lptim1 { + status = "okay"; + }; + Power Management ================ From bf2b4675d0bda33cdd12b869b480cdac0635474e Mon Sep 17 00:00:00 2001 From: Francois Ramu Date: Wed, 4 Oct 2023 17:04:26 +0200 Subject: [PATCH 1065/3723] samples: boards: stm32 low power blinky for stm32 boards Set the prescaler for the stm32_lp_tick_source lptim node. When the LPTIM is clocked by the LSE with a prescaler of 16 (lptim freq at 2048Hz) expecting 2048 for the TICKS_PER_SEC. When the LPTIM is clocked by the LSE with a prescaler of 32 (lptim freq at 1024Hz) expecting 1024 for the TICKS_PER_SEC. Signed-off-by: Francois Ramu --- samples/boards/stm32/power_mgmt/blinky/README.rst | 11 ++++++++++- .../power_mgmt/blinky/boards/b_u585i_iot02a.overlay | 9 +++++++++ .../power_mgmt/blinky/boards/nucleo_wb55rg.overlay | 6 +++--- samples/boards/stm32/power_mgmt/blinky/prj.conf | 1 + 4 files changed, 23 insertions(+), 4 deletions(-) create mode 100644 samples/boards/stm32/power_mgmt/blinky/boards/b_u585i_iot02a.overlay diff --git a/samples/boards/stm32/power_mgmt/blinky/README.rst b/samples/boards/stm32/power_mgmt/blinky/README.rst index 4687b07326e..1f75e2bddbc 100644 --- a/samples/boards/stm32/power_mgmt/blinky/README.rst +++ b/samples/boards/stm32/power_mgmt/blinky/README.rst @@ -9,6 +9,12 @@ Overview This sample is a minimum application to demonstrate basic power management behavior in a basic blinking LED set up using the :ref:`GPIO API ` in low power context. +Note that lptim instance selected for the low power timer is named **&stm32_lp_tick_source** +When setting a prescaler to decrease the lptimer input clock frequency, the system can sleep +for a longer timeout value and the CONFIG_SYS_CLOCK_TICKS_PER_SEC is adjusted. +For example, when clocking the low power Timer with LSE clock at 32768Hz and adding a +prescaler of <32>, then the kernel sleep period can reach 65536 * 32/32768 = 64 seconds +CONFIG_SYS_CLOCK_TICKS_PER_SEC is set to 1024. .. _stm32-pm-blinky-sample-requirements: @@ -30,7 +36,10 @@ Build and flash Blinky as follows, changing ``stm32l562e_dk`` for your board: :goals: build flash :compact: -After flashing, the LED starts to blink. +After flashing, the LED starts to blink with a fixed period (SLEEP_TIME_MS). +When LPTIM input clock has a prescaler, longer perdiod (up to 64 seconds) +of low power can be tested. + PM configurations ***************** diff --git a/samples/boards/stm32/power_mgmt/blinky/boards/b_u585i_iot02a.overlay b/samples/boards/stm32/power_mgmt/blinky/boards/b_u585i_iot02a.overlay new file mode 100644 index 00000000000..f6f5d399148 --- /dev/null +++ b/samples/boards/stm32/power_mgmt/blinky/boards/b_u585i_iot02a.overlay @@ -0,0 +1,9 @@ + /* + * give a prescaler to the lptim clock : LSE / 16 = 2048Hz + * so that the sleep period is of 32s in the sample application + * with a LPTIM1 prescaler of <1> to <8>, CONFIG_SYS_CLOCK_TICKS_PER_SEC is 4096 + * with a LPTIM1 prescaler >= <16>, CONFIG_SYS_CLOCK_TICKS_PER_SEC is LSE / prescaler + */ +&stm32_lp_tick_source { + st,prescaler = <16>; +}; diff --git a/samples/boards/stm32/power_mgmt/blinky/boards/nucleo_wb55rg.overlay b/samples/boards/stm32/power_mgmt/blinky/boards/nucleo_wb55rg.overlay index 66bca43ae2f..11767aa004b 100644 --- a/samples/boards/stm32/power_mgmt/blinky/boards/nucleo_wb55rg.overlay +++ b/samples/boards/stm32/power_mgmt/blinky/boards/nucleo_wb55rg.overlay @@ -1,9 +1,9 @@ /* * give a prescaler to the lptim clock : LSE / 32 = 1024Hz * so that the sleep period is of 64s in the sample application - * + * with a LPTIM1 prescaler of <1> to <8>, CONFIG_SYS_CLOCK_TICKS_PER_SEC is 4096 + * with a LPTIM1 prescaler >= <16>, CONFIG_SYS_CLOCK_TICKS_PER_SEC is LSE / prescaler */ - -&lptim1 { +&stm32_lp_tick_source { st,prescaler = <32>; }; diff --git a/samples/boards/stm32/power_mgmt/blinky/prj.conf b/samples/boards/stm32/power_mgmt/blinky/prj.conf index 9ac206bd0f3..fa60e82b4f0 100644 --- a/samples/boards/stm32/power_mgmt/blinky/prj.conf +++ b/samples/boards/stm32/power_mgmt/blinky/prj.conf @@ -2,3 +2,4 @@ CONFIG_PM=y CONFIG_PM_DEVICE=y CONFIG_PM_DEVICE_RUNTIME=y CONFIG_PM_DEVICE_RUNTIME_EXCLUSIVE=n +CONFIG_ASSERT=y From 3650537a9d9dac35922da069157c62e6b5eddc41 Mon Sep 17 00:00:00 2001 From: Christopher Friedt Date: Wed, 8 Nov 2023 15:29:45 -0500 Subject: [PATCH 1066/3723] cmake: calculate the md5 sum using the built-in string command Assuming that all supported releases require at least CMake version 3.0, we should be able to calculate the md5sum in a much simpler way using string(). https://cmake.org/cmake/help/v3.0/command/string.html This avoids writing a temporary file into the source directory and therefore mitigates the possibility of the following warning. share/zephyr-package/cmake/zephyr_export.cmake:19 (string): string sub-command SUBSTRING requires four arguments. Signed-off-by: Christopher Friedt --- share/zephyr-package/cmake/zephyr_export.cmake | 10 +--------- share/zephyrunittest-package/cmake/zephyr_export.cmake | 10 +--------- 2 files changed, 2 insertions(+), 18 deletions(-) diff --git a/share/zephyr-package/cmake/zephyr_export.cmake b/share/zephyr-package/cmake/zephyr_export.cmake index a9493f683b8..8d89483ad9d 100644 --- a/share/zephyr-package/cmake/zephyr_export.cmake +++ b/share/zephyr-package/cmake/zephyr_export.cmake @@ -8,15 +8,7 @@ # # Create the reference by running `cmake -P zephyr_export.cmake` in this directory. -set(MD5_INFILE "current_path.txt") - -# We write CMAKE_CURRENT_LIST_DIR into MD5_INFILE, as the content of that file will be used for MD5 calculation. -# This means we effectively get the MD5 of CMAKE_CURRENT_LIST_DIR which must be used for CMake user package registry. -file(WRITE ${CMAKE_CURRENT_LIST_DIR}/${MD5_INFILE} ${CMAKE_CURRENT_LIST_DIR}) -execute_process(COMMAND ${CMAKE_COMMAND} -E md5sum ${CMAKE_CURRENT_LIST_DIR}/${MD5_INFILE} - OUTPUT_VARIABLE MD5_SUM -) -string(SUBSTRING ${MD5_SUM} 0 32 MD5_SUM) +string(MD5 MD5_SUM ${CMAKE_CURRENT_LIST_DIR}) if(WIN32) execute_process(COMMAND ${CMAKE_COMMAND} -E write_regv diff --git a/share/zephyrunittest-package/cmake/zephyr_export.cmake b/share/zephyrunittest-package/cmake/zephyr_export.cmake index a0a65b2e090..de395c3112f 100644 --- a/share/zephyrunittest-package/cmake/zephyr_export.cmake +++ b/share/zephyrunittest-package/cmake/zephyr_export.cmake @@ -8,15 +8,7 @@ # # Create the reference by running `cmake -P zephyr_export.cmake` in this directory. -set(MD5_INFILE "current_path.txt") - -# We write CMAKE_CURRENT_LIST_DIR into MD5_INFILE, as the content of that file will be used for MD5 calculation. -# This means we effectively get the MD5 of CMAKE_CURRENT_LIST_DIR which must be used for CMake user package registry. -file(WRITE ${CMAKE_CURRENT_LIST_DIR}/${MD5_INFILE} ${CMAKE_CURRENT_LIST_DIR}) -execute_process(COMMAND ${CMAKE_COMMAND} -E md5sum ${CMAKE_CURRENT_LIST_DIR}/${MD5_INFILE} - OUTPUT_VARIABLE MD5_SUM -) -string(SUBSTRING ${MD5_SUM} 0 32 MD5_SUM) +string(MD5 MD5_SUM ${CMAKE_CURRENT_LIST_DIR}) if(WIN32) execute_process(COMMAND ${CMAKE_COMMAND} -E write_regv From 4e825f572c004c71754c0cd6c906afdfa0e98ed8 Mon Sep 17 00:00:00 2001 From: Conor Paxton Date: Wed, 29 Nov 2023 01:59:21 +0000 Subject: [PATCH 1067/3723] drivers: intc_plic: enable contexts for all harts on a platform The plic uses contexts to seperate irq enables, threshold priority and claim complete registers from each core for a given platform. As well as this, each privilege level has its own context. for multi-core platform's, we need to be able to enable/ disable a global interrupt for all the cores that are associated with Zephyr. To do this, we need to make some assumptions: 1. The privilege contexts are contiguous 2. M mode context is first, followed by S mode. We know how many cpus are used in an application and each cpu's hartid, thanks to some very handy inline functions. So we iterate through each cpu and use the hartid of a cpu in the calculation of the context. While we are at it, In an effort to make the driver more readable, allign with the macro naming convention outlined in Linux's PLIC driver Signed-off-by: Conor Paxton --- drivers/interrupt_controller/intc_plic.c | 98 +++++++++++++++++------- 1 file changed, 70 insertions(+), 28 deletions(-) diff --git a/drivers/interrupt_controller/intc_plic.c b/drivers/interrupt_controller/intc_plic.c index 9705380ea7b..c5615648fc9 100644 --- a/drivers/interrupt_controller/intc_plic.c +++ b/drivers/interrupt_controller/intc_plic.c @@ -32,11 +32,12 @@ * These registers' offset are defined in the RISCV PLIC specs, see: * https://github.com/riscv/riscv-plic-spec */ -#define PLIC_REG_PRIO_OFFSET 0x0 -#define PLIC_REG_IRQ_EN_OFFSET 0x2000 -#define PLIC_REG_REGS_OFFSET 0x200000 -#define PLIC_REG_REGS_THRES_PRIORITY_OFFSET 0 -#define PLIC_REG_REGS_CLAIM_COMPLETE_OFFSET sizeof(uint32_t) +#define CONTEXT_BASE 0x200000 +#define CONTEXT_SIZE 0x1000 +#define CONTEXT_THRESHOLD 0x00 +#define CONTEXT_CLAIM 0x04 +#define CONTEXT_ENABLE_BASE 0x2000 +#define CONTEXT_ENABLE_SIZE 0x80 /* * Trigger type is mentioned, but not defined in the RISCV PLIC specs. * However, it is defined and supported by at least the Andes & Telink datasheet, and supported @@ -105,18 +106,50 @@ static inline uint32_t get_plic_enabled_size(const struct device *dev) return local_irq_to_reg_index(config->num_irqs) + 1; } +static inline uint32_t get_first_context(uint32_t hartid) +{ + return hartid == 0 ? 0 : (hartid * 2) - 1; +} + +static inline mem_addr_t get_context_en_addr(const struct device *dev, uint32_t cpu_num) +{ + const struct plic_config *config = dev->config; + uint32_t hartid; + /* + * We want to return the irq_en address for the context of given hart. + * If hartid is 0, we return the devices irq_en property, job done. If it is + * greater than zero, we assume that there are two context's associated with + * each hart: M mode enable, followed by S mode enable. We return the M mode + * enable address. + */ +#if CONFIG_SMP + hartid = _kernel.cpus[cpu_num].arch.hartid; +#else + hartid = arch_proc_id(); +#endif + return config->irq_en + get_first_context(hartid) * CONTEXT_ENABLE_SIZE; +} + static inline mem_addr_t get_claim_complete_addr(const struct device *dev) { const struct plic_config *config = dev->config; - return config->reg + PLIC_REG_REGS_CLAIM_COMPLETE_OFFSET; + return config->reg + CONTEXT_CLAIM; } -static inline mem_addr_t get_threshold_priority_addr(const struct device *dev) + +static inline mem_addr_t get_threshold_priority_addr(const struct device *dev, uint32_t cpu_num) { const struct plic_config *config = dev->config; + uint32_t hartid; + +#if CONFIG_SMP + hartid = _kernel.cpus[cpu_num].arch.hartid; +#else + hartid = arch_proc_id(); +#endif - return config->reg + PLIC_REG_REGS_THRES_PRIORITY_OFFSET; + return config->reg + (get_first_context(hartid) * CONTEXT_SIZE); } /** @@ -163,17 +196,21 @@ static uint32_t __maybe_unused riscv_plic_irq_trig_val(const struct device *dev, static void plic_irq_enable_set_state(uint32_t irq, bool enable) { const struct device *dev = get_plic_dev_from_irq(irq); - const struct plic_config *config = dev->config; const uint32_t local_irq = irq_from_level_2(irq); - mem_addr_t en_addr = config->irq_en + local_irq_to_reg_offset(local_irq); - uint32_t en_value; - uint32_t key; - key = irq_lock(); - en_value = sys_read32(en_addr); - WRITE_BIT(en_value, local_irq & PLIC_REG_MASK, enable); - sys_write32(en_value, en_addr); - irq_unlock(key); + for (uint32_t cpu_num = 0; cpu_num < arch_num_cpus(); cpu_num++) { + mem_addr_t en_addr = + get_context_en_addr(dev, cpu_num) + local_irq_to_reg_offset(local_irq); + + uint32_t en_value; + uint32_t key; + + key = irq_lock(); + en_value = sys_read32(en_addr); + WRITE_BIT(en_value, local_irq & PLIC_REG_MASK, enable); + sys_write32(en_value, en_addr); + irq_unlock(key); + } } /** @@ -355,13 +392,21 @@ static void plic_irq_handler(const struct device *dev) static int plic_init(const struct device *dev) { const struct plic_config *config = dev->config; - mem_addr_t en_addr = config->irq_en; + mem_addr_t en_addr, thres_prio_addr; mem_addr_t prio_addr = config->prio; - mem_addr_t thres_prio_addr = get_threshold_priority_addr(dev); - /* Ensure that all interrupts are disabled initially */ - for (uint32_t i = 0; i < get_plic_enabled_size(dev); i++) { - sys_write32(0U, en_addr + (i * sizeof(uint32_t))); + /* Iterate through each of the contexts, HART + PRIV */ + for (uint32_t cpu_num = 0; cpu_num < arch_num_cpus(); cpu_num++) { + en_addr = get_context_en_addr(dev, cpu_num); + thres_prio_addr = get_threshold_priority_addr(dev, cpu_num); + + /* Ensure that all interrupts are disabled initially */ + for (uint32_t i = 0; i < get_plic_enabled_size(dev); i++) { + sys_write32(0U, en_addr + (i * sizeof(uint32_t))); + } + + /* Set threshold priority to 0 */ + sys_write32(0U, thres_prio_addr); } /* Set priority of each interrupt line to 0 initially */ @@ -369,9 +414,6 @@ static int plic_init(const struct device *dev) sys_write32(0U, prio_addr + (i * sizeof(uint32_t))); } - /* Set threshold priority to 0 */ - sys_write32(0U, thres_prio_addr); - /* Configure IRQ for PLIC driver */ config->irq_config_func(); @@ -514,9 +556,9 @@ SHELL_CMD_ARG_REGISTER(plic, &plic_cmds, "PLIC shell commands", #define PLIC_INTC_CONFIG_INIT(n) \ PLIC_INTC_IRQ_FUNC_DECLARE(n); \ static const struct plic_config plic_config_##n = { \ - .prio = PLIC_BASE_ADDR(n) + PLIC_REG_PRIO_OFFSET, \ - .irq_en = PLIC_BASE_ADDR(n) + PLIC_REG_IRQ_EN_OFFSET, \ - .reg = PLIC_BASE_ADDR(n) + PLIC_REG_REGS_OFFSET, \ + .prio = PLIC_BASE_ADDR(n), \ + .irq_en = PLIC_BASE_ADDR(n) + CONTEXT_ENABLE_BASE, \ + .reg = PLIC_BASE_ADDR(n) + CONTEXT_BASE, \ IF_ENABLED(PLIC_SUPPORTS_TRIG_TYPE, \ (.trig = PLIC_BASE_ADDR(n) + PLIC_REG_TRIG_TYPE_OFFSET,)) \ .max_prio = DT_INST_PROP(n, riscv_max_priority), \ From 7e192e9e279cf3a0d25eed6d874ef7f9d3d4278d Mon Sep 17 00:00:00 2001 From: Conor Paxton Date: Wed, 29 Nov 2023 21:39:33 +0000 Subject: [PATCH 1068/3723] drivers: intc_plic: claim interrupt from hart that serviced it The plic has a very simple mechanism to claim an interrupt as well as to complete and clear it. The same register is read from/ written to to achieve this. Get the ID of the HART that serviced the interrupt and write to the claim complete register in the correct context Signed-off-by: Conor Paxton --- drivers/interrupt_controller/intc_plic.c | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) diff --git a/drivers/interrupt_controller/intc_plic.c b/drivers/interrupt_controller/intc_plic.c index c5615648fc9..df50e7b9d3c 100644 --- a/drivers/interrupt_controller/intc_plic.c +++ b/drivers/interrupt_controller/intc_plic.c @@ -134,7 +134,17 @@ static inline mem_addr_t get_claim_complete_addr(const struct device *dev) { const struct plic_config *config = dev->config; - return config->reg + CONTEXT_CLAIM; + /* + * We want to return the claim complete addr for the hart's context. + * We are making a few assumptions here: + * 1. for hart 0, return the first context claim complete. + * 2. for any other hart, we assume they have two privileged mode contexts + * which are contiguous, where the m mode context is first. + * We return the m mode context. + */ + + return config->reg + get_first_context(arch_proc_id()) * CONTEXT_SIZE + + CONTEXT_CLAIM; } From 69e28939dde528e10ccbd13b46520c2f3d32fd5b Mon Sep 17 00:00:00 2001 From: Juha Ylinen Date: Fri, 1 Dec 2023 10:22:23 +0200 Subject: [PATCH 1069/3723] net: lib: coap: Add new API to configure retransmission settings Add new functions to the public CoAP API to configure CoAP packet retransmission settings. Application may need to re-configure the settings for example when cellular modem changes connection from LTE-M to NB-IoT or vice versa. Signed-off-by: Juha Ylinen --- include/zephyr/net/coap.h | 26 ++++++++++++++++++++++++ subsys/net/lib/coap/Kconfig | 7 +++++++ subsys/net/lib/coap/coap.c | 24 ++++++++++++++++++---- tests/net/lib/coap_client/CMakeLists.txt | 2 ++ 4 files changed, 55 insertions(+), 4 deletions(-) diff --git a/include/zephyr/net/coap.h b/include/zephyr/net/coap.h index dceed869b43..e4374f41e34 100644 --- a/include/zephyr/net/coap.h +++ b/include/zephyr/net/coap.h @@ -1134,6 +1134,32 @@ int coap_resource_notify(struct coap_resource *resource); */ bool coap_request_is_observe(const struct coap_packet *request); +/** + * @brief CoAP transmission parameters. + */ +struct coap_transmission_parameters { + /** Initial AKC timeout. Value is used as a base value to retry pending CoAP packets. */ + uint32_t ack_timeout; + /** Set CoAP retry backoff factor. A value of 200 means a factor of 2.0. */ + uint16_t coap_backoff_percent; + /** Maximum number of retransmissions. */ + uint8_t max_retransmission; +}; + +/** + * @brief Get currently active CoAP transmission parameters. + * + * @return CoAP transmission parameters structure. + */ +struct coap_transmission_parameters coap_get_transmission_parameters(void); + +/** + * @brief Set CoAP transmission parameters. + * + * @param params Pointer to the transmission parameters structure. + */ +void coap_set_transmission_parameters(const struct coap_transmission_parameters *params); + #ifdef __cplusplus } #endif diff --git a/subsys/net/lib/coap/Kconfig b/subsys/net/lib/coap/Kconfig index cc6bee04f53..f4d002d0c5d 100644 --- a/subsys/net/lib/coap/Kconfig +++ b/subsys/net/lib/coap/Kconfig @@ -82,6 +82,13 @@ config COAP_MAX_RETRANSMIT default 4 range 1 10 +config COAP_BACKOFF_PERCENT + int "Retransmission backoff factor for ACK timeout described as percentage" + default 200 + help + Factor described as percentage to extend CoAP ACK timeout for retransmissions. + A value of 200 means a factor of 2.0. + config COAP_URI_WILDCARD bool "Wildcards in CoAP resource path" default y diff --git a/subsys/net/lib/coap/coap.c b/subsys/net/lib/coap/coap.c index c49264e6776..c21e14e5ded 100644 --- a/subsys/net/lib/coap/coap.c +++ b/subsys/net/lib/coap/coap.c @@ -54,6 +54,12 @@ LOG_MODULE_REGISTER(net_coap, CONFIG_COAP_LOG_LEVEL); /* The CoAP message ID that is incremented each time coap_next_id() is called. */ static uint16_t message_id; +static struct coap_transmission_parameters coap_transmission_params = { + .max_retransmission = CONFIG_COAP_MAX_RETRANSMIT, + .ack_timeout = CONFIG_COAP_INIT_ACK_TIMEOUT_MS, + .coap_backoff_percent = CONFIG_COAP_BACKOFF_PERCENT +}; + static int insert_option(struct coap_packet *cpkt, uint16_t code, const uint8_t *value, uint16_t len); @@ -1673,9 +1679,9 @@ struct coap_pending *coap_pending_next_to_expire( static uint32_t init_ack_timeout(void) { #if defined(CONFIG_COAP_RANDOMIZE_ACK_TIMEOUT) - const uint32_t max_ack = CONFIG_COAP_INIT_ACK_TIMEOUT_MS * + const uint32_t max_ack = coap_transmission_params.ack_timeout * CONFIG_COAP_ACK_RANDOM_PERCENT / 100; - const uint32_t min_ack = CONFIG_COAP_INIT_ACK_TIMEOUT_MS; + const uint32_t min_ack = coap_transmission_params.ack_timeout; /* Randomly generated initial ACK timeout * ACK_TIMEOUT < INIT_ACK_TIMEOUT < ACK_TIMEOUT * ACK_RANDOM_FACTOR @@ -1683,7 +1689,7 @@ static uint32_t init_ack_timeout(void) */ return min_ack + (sys_rand32_get() % (max_ack - min_ack)); #else - return CONFIG_COAP_INIT_ACK_TIMEOUT_MS; + return coap_transmission_params.ack_timeout; #endif /* defined(CONFIG_COAP_RANDOMIZE_ACK_TIMEOUT) */ } @@ -1701,7 +1707,7 @@ bool coap_pending_cycle(struct coap_pending *pending) } pending->t0 += pending->timeout; - pending->timeout = pending->timeout << 1; + pending->timeout = pending->timeout * coap_transmission_params.coap_backoff_percent / 100; pending->retries--; return true; @@ -2006,3 +2012,13 @@ uint16_t coap_next_id(void) { return message_id++; } + +struct coap_transmission_parameters coap_get_transmission_parameters(void) +{ + return coap_transmission_params; +} + +void coap_set_transmission_parameters(const struct coap_transmission_parameters *params) +{ + coap_transmission_params = *params; +} diff --git a/tests/net/lib/coap_client/CMakeLists.txt b/tests/net/lib/coap_client/CMakeLists.txt index 2e94112f0b0..cb86d78f611 100644 --- a/tests/net/lib/coap_client/CMakeLists.txt +++ b/tests/net/lib/coap_client/CMakeLists.txt @@ -27,3 +27,5 @@ add_compile_definitions(CONFIG_COAP_LOG_LEVEL=4) add_compile_definitions(CONFIG_COAP_INIT_ACK_TIMEOUT_MS=200) add_compile_definitions(CONFIG_COAP_CLIENT_MAX_REQUESTS=2) add_compile_definitions(CONFIG_COAP_CLIENT_MAX_INSTANCES=2) +add_compile_definitions(CONFIG_COAP_MAX_RETRANSMIT=4) +add_compile_definitions(CONFIG_COAP_BACKOFF_PERCENT=200) From 5767c8d78cc705e0d48a7bb3c2280e48a1acd9c7 Mon Sep 17 00:00:00 2001 From: Andreas Sandberg Date: Mon, 4 Dec 2023 21:08:31 +0000 Subject: [PATCH 1070/3723] dts: stm32g4: Add ITM support The STM32 G4 series has a built-in Arm Instrumentation Trace Macrocell. Set CONFIG_HAS_SWO to enable this. Signed-off-by: Andreas Sandberg --- soc/arm/st_stm32/stm32g4/Kconfig.series | 1 + 1 file changed, 1 insertion(+) diff --git a/soc/arm/st_stm32/stm32g4/Kconfig.series b/soc/arm/st_stm32/stm32g4/Kconfig.series index 6d81e3f1fc1..f04432c3ee3 100644 --- a/soc/arm/st_stm32/stm32g4/Kconfig.series +++ b/soc/arm/st_stm32/stm32g4/Kconfig.series @@ -14,5 +14,6 @@ config SOC_SERIES_STM32G4X select CPU_HAS_ARM_MPU select CLOCK_CONTROL_STM32_CUBE if CLOCK_CONTROL select HAS_PM + select HAS_SWO help Enable support for STM32G4 MCU series From 8ae5031aa5320c9f72e9a03f0c1f8e721cd25395 Mon Sep 17 00:00:00 2001 From: Andreas Sandberg Date: Tue, 5 Dec 2023 22:24:30 +0000 Subject: [PATCH 1071/3723] samples: Add an SWO logger configuration fragment The subsys/logging/logger example can be used to demonstrate how to use SWO for logging. Add a configuration fragment that enables the logger's SWO backend. The default SWO frequency in this example is set to 2 MHz to ensure a well-defined output bit rate instead of the highest possible. Signed-off-by: Andreas Sandberg --- samples/subsys/logging/logger/arm_itm_swo.conf | 4 ++++ 1 file changed, 4 insertions(+) create mode 100644 samples/subsys/logging/logger/arm_itm_swo.conf diff --git a/samples/subsys/logging/logger/arm_itm_swo.conf b/samples/subsys/logging/logger/arm_itm_swo.conf new file mode 100644 index 00000000000..0b3d792e707 --- /dev/null +++ b/samples/subsys/logging/logger/arm_itm_swo.conf @@ -0,0 +1,4 @@ +# SPDX-License-Identifier: Apache-2.0 + +CONFIG_LOG_BACKEND_SWO=y +CONFIG_LOG_BACKEND_SWO_FREQ_HZ=2000000 From 3732aae0e0769f2cff52389f9b3d6f2ee0d031c2 Mon Sep 17 00:00:00 2001 From: Tomasz Leman Date: Thu, 7 Dec 2023 16:13:16 +0100 Subject: [PATCH 1072/3723] intel_adsp: power: clock gating in idle This patch enables DSP clock gating for ACE platforms. By default, clock gating is blocked by the firmware in the hardware configuration. If CONFIG_ADSP_IDLE_CLOCK_GATING is enabled, this prevent is not active and clock can be gated when core is in idle state. WIth this option disabled clock gating will only be enabled in hardware during power gating. Signed-off-by: Tomasz Leman --- soc/xtensa/intel_adsp/Kconfig | 8 ++++++++ soc/xtensa/intel_adsp/ace/multiprocessing.c | 10 +++++++--- soc/xtensa/intel_adsp/ace/power.c | 14 +++++++++++--- 3 files changed, 26 insertions(+), 6 deletions(-) diff --git a/soc/xtensa/intel_adsp/Kconfig b/soc/xtensa/intel_adsp/Kconfig index a3d93d976ea..ed491015fac 100644 --- a/soc/xtensa/intel_adsp/Kconfig +++ b/soc/xtensa/intel_adsp/Kconfig @@ -125,4 +125,12 @@ config XTENSA_WAITI_BUG platforms which prefixes a WAITI entry with 128 NOP instructions followed by an ISYNC and EXTW. +config ADSP_IDLE_CLOCK_GATING + bool "DSP clock gating in Idle" + help + When true, FW will run with enabled clock gating. This options change + HW configuration of a DSP. Evry time core goes to the WAITI state + (wait for interrupt) during idle, the clock can be gated (however, this + does not mean that this will happen). + endif # SOC_FAMILY_INTEL_ADSP diff --git a/soc/xtensa/intel_adsp/ace/multiprocessing.c b/soc/xtensa/intel_adsp/ace/multiprocessing.c index e762245e669..2d3d74fa724 100644 --- a/soc/xtensa/intel_adsp/ace/multiprocessing.c +++ b/soc/xtensa/intel_adsp/ace/multiprocessing.c @@ -161,9 +161,13 @@ void soc_mp_startup(uint32_t cpu) /* Must have this enabled always */ z_xtensa_irq_enable(ACE_INTC_IRQ); - /* Prevent idle from powering us off */ - DSPCS.bootctl[cpu].bctl |= - DSPBR_BCTL_WAITIPCG | DSPBR_BCTL_WAITIPPG; +#if CONFIG_ADSP_IDLE_CLOCK_GATING + /* Disable idle power gating */ + DSPCS.bootctl[cpu].bctl |= DSPBR_BCTL_WAITIPPG; +#else + /* Disable idle power and clock gating */ + DSPCS.bootctl[cpu].bctl |= DSPBR_BCTL_WAITIPCG | DSPBR_BCTL_WAITIPPG; +#endif /* CONFIG_ADSP_IDLE_CLOCK_GATING */ } void arch_sched_ipi(void) diff --git a/soc/xtensa/intel_adsp/ace/power.c b/soc/xtensa/intel_adsp/ace/power.c index 7fe33c3feaf..cee8047d4a2 100644 --- a/soc/xtensa/intel_adsp/ace/power.c +++ b/soc/xtensa/intel_adsp/ace/power.c @@ -26,8 +26,13 @@ __imr void power_init(void) { +#if CONFIG_ADSP_IDLE_CLOCK_GATING /* Disable idle power gating */ + DSPCS.bootctl[0].bctl |= DSPBR_BCTL_WAITIPPG; +#else + /* Disable idle power and clock gating */ DSPCS.bootctl[0].bctl |= DSPBR_BCTL_WAITIPCG | DSPBR_BCTL_WAITIPPG; +#endif /* CONFIG_ADSP_IDLE_CLOCK_GATING */ } #ifdef CONFIG_PM @@ -358,8 +363,11 @@ void pm_state_exit_post_ops(enum pm_state state, uint8_t substate_id) k_panic(); } - DSPCS.bootctl[cpu].bctl |= - DSPBR_BCTL_WAITIPCG | DSPBR_BCTL_WAITIPPG; +#if CONFIG_ADSP_IDLE_CLOCK_GATING + DSPCS.bootctl[cpu].bctl |= DSPBR_BCTL_WAITIPPG; +#else + DSPCS.bootctl[cpu].bctl |= DSPBR_BCTL_WAITIPCG | DSPBR_BCTL_WAITIPPG; +#endif /* CONFIG_ADSP_IDLE_CLOCK_GATING */ if (cpu == 0) { DSPCS.bootctl[cpu].battr &= (~LPSCTL_BATTR_MASK); } @@ -373,4 +381,4 @@ void pm_state_exit_post_ops(enum pm_state state, uint8_t substate_id) z_xt_ints_on(core_desc[cpu].intenable); } -#endif +#endif /* CONFIG_PM */ From 0b365359dc915c664b07e8ebd865daaf6dfabab5 Mon Sep 17 00:00:00 2001 From: Daniel DeGrasse Date: Wed, 6 Dec 2023 10:59:42 -0600 Subject: [PATCH 1073/3723] drivers: sdhc: imx_usdhc: explicitly set host_io fields Explicitly set host_io fields, instead of using memset(). This way the fields should have values that are defined in the enum types for each field. Fixes #63130 Signed-off-by: Daniel DeGrasse --- drivers/sdhc/imx_usdhc.c | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/drivers/sdhc/imx_usdhc.c b/drivers/sdhc/imx_usdhc.c index 8ae8fa9741f..e5954b6afb8 100644 --- a/drivers/sdhc/imx_usdhc.c +++ b/drivers/sdhc/imx_usdhc.c @@ -1031,7 +1031,15 @@ static int imx_usdhc_init(const struct device *dev) } data->dev = dev; k_mutex_init(&data->access_mutex); - memset(&data->host_io, 0, sizeof(data->host_io)); + /* Setup initial host IO values */ + data->host_io.clock = 0; + data->host_io.bus_mode = SDHC_BUSMODE_PUSHPULL; + data->host_io.power_mode = SDHC_POWER_OFF; + data->host_io.bus_width = SDHC_BUS_WIDTH1BIT; + data->host_io.timing = SDHC_TIMING_LEGACY; + data->host_io.driver_type = SD_DRIVER_TYPE_B; + data->host_io.signal_voltage = SD_VOL_3_3_V; + return k_sem_init(&data->transfer_sem, 0, 1); } From 2236eaf52c6b148eab8cf164f29dcccbe5c9b351 Mon Sep 17 00:00:00 2001 From: Daniel DeGrasse Date: Wed, 6 Dec 2023 11:02:32 -0600 Subject: [PATCH 1074/3723] drivers: sdhc: imx_usdhc: add explicit fallthrough to I/O timing setup DDR50/DDR52 modes should use PINCTRL_STATE_SLOW (50MHz), so the lack of a break statement after enabling DDR mode is expected. Add an explicit __fallthrough to resolve the issue flagged by coverity scan Fixes #65324 Signed-off-by: Daniel DeGrasse --- drivers/sdhc/imx_usdhc.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/sdhc/imx_usdhc.c b/drivers/sdhc/imx_usdhc.c index e5954b6afb8..84f8f2aee3b 100644 --- a/drivers/sdhc/imx_usdhc.c +++ b/drivers/sdhc/imx_usdhc.c @@ -404,6 +404,7 @@ static int imx_usdhc_set_io(const struct device *dev, struct sdhc_io *ios) case SDHC_TIMING_DDR52: /* Enable DDR mode */ USDHC_EnableDDRMode(cfg->base, true, 0); + __fallthrough; case SDHC_TIMING_SDR12: case SDHC_TIMING_SDR25: pinctrl_apply_state(cfg->pincfg, PINCTRL_STATE_SLOW); From 0ea173b7747f7d93931d496a8ca4b329edb612b1 Mon Sep 17 00:00:00 2001 From: Flavio Ceolin Date: Wed, 6 Dec 2023 17:52:21 +0000 Subject: [PATCH 1075/3723] pm: device_runtime: Avoid unnecessary resume/suspend We don't need to wait an async put to happen in case it has not started yet. In this case we can simply cancelling the pending work and change the internal state because the device is still active. This way we avoid a suspend and resume cycle. Signed-off-by: Flavio Ceolin --- subsys/pm/device_runtime.c | 16 +++++++++++++++- 1 file changed, 15 insertions(+), 1 deletion(-) diff --git a/subsys/pm/device_runtime.c b/subsys/pm/device_runtime.c index 56f0b066a91..a4b64fbe994 100644 --- a/subsys/pm/device_runtime.c +++ b/subsys/pm/device_runtime.c @@ -177,8 +177,22 @@ int pm_device_runtime_get(const struct device *dev) pm->usage++; + /* + * Check if the device has a pending suspend operation (not started + * yet) and cancel it. This way we avoid unnecessary operations because + * the device is actually active. + */ + if ((pm->state == PM_DEVICE_STATE_SUSPENDING) && + ((k_work_cancel_delayable(&pm->work) & K_WORK_RUNNING) == 0)) { + pm->state = PM_DEVICE_STATE_ACTIVE; + goto unlock; + } + if (!k_is_pre_kernel()) { - /* wait until possible async suspend is completed */ + /* + * If the device is already suspending there is + * nothing else we can do but wait until it finishes. + */ while (pm->state == PM_DEVICE_STATE_SUSPENDING) { k_sem_give(&pm->lock); From b5ca7a06b434055be5c71ecbc013d42c6ee4357a Mon Sep 17 00:00:00 2001 From: Flavio Ceolin Date: Tue, 5 Dec 2023 23:17:56 +0000 Subject: [PATCH 1076/3723] pm: device_runtime: Add delay to async put Add a delay parameter to asynchronous device runtim put. This allows to delay the put operation what is useful to avoid multiple states transitions. Signed-off-by: Flavio Ceolin --- doc/services/pm/device_runtime.rst | 2 +- include/zephyr/pm/device_runtime.h | 7 +++++-- include/zephyr/tracing/tracing.h | 6 ++++-- subsys/pm/device_runtime.c | 16 +++++++++------- subsys/tracing/ctf/tracing_ctf.h | 4 ++-- subsys/tracing/sysview/SYSVIEW_Zephyr.txt | 2 +- subsys/tracing/sysview/tracing_sysview.h | 6 +++--- subsys/tracing/test/tracing_test.h | 4 ++-- subsys/tracing/user/tracing_user.h | 4 ++-- tests/subsys/pm/device_runtime_api/src/main.c | 8 ++++---- 10 files changed, 33 insertions(+), 26 deletions(-) diff --git a/doc/services/pm/device_runtime.rst b/doc/services/pm/device_runtime.rst index 5d9df2d8706..b0dd57db02e 100644 --- a/doc/services/pm/device_runtime.rst +++ b/doc/services/pm/device_runtime.rst @@ -224,5 +224,5 @@ asynchronous API: ... /* "put" device (decreases usage count, schedule suspend if no more users) */ - return pm_device_runtime_put_async(dev); + return pm_device_runtime_put_async(dev, K_NO_WAIT); } diff --git a/include/zephyr/pm/device_runtime.h b/include/zephyr/pm/device_runtime.h index 09bf0c04278..3a320b9ccbc 100644 --- a/include/zephyr/pm/device_runtime.h +++ b/include/zephyr/pm/device_runtime.h @@ -131,6 +131,7 @@ int pm_device_runtime_put(const struct device *dev); * @funcprops \pre_kernel_ok, \async, \isr_ok * * @param dev Device instance. + * @param delay Minimum amount of time before triggering the action. * * @retval 0 If it succeeds. In case device runtime PM is not enabled or not * available this function will be a no-op and will also return 0. @@ -140,7 +141,7 @@ int pm_device_runtime_put(const struct device *dev); * * @see pm_device_runtime_put() */ -int pm_device_runtime_put_async(const struct device *dev); +int pm_device_runtime_put_async(const struct device *dev, k_timeout_t delay); /** * @brief Check if device runtime is enabled for a given device. @@ -188,9 +189,11 @@ static inline int pm_device_runtime_put(const struct device *dev) return 0; } -static inline int pm_device_runtime_put_async(const struct device *dev) +static inline int pm_device_runtime_put_async(const struct device *dev, + k_timeout_t delay) { ARG_UNUSED(dev); + ARG_UNUSED(delay); return 0; } diff --git a/include/zephyr/tracing/tracing.h b/include/zephyr/tracing/tracing.h index baf9632a30d..f1bbddeec51 100644 --- a/include/zephyr/tracing/tracing.h +++ b/include/zephyr/tracing/tracing.h @@ -1954,15 +1954,17 @@ /** * @brief Trace putting a device (asynchronously) call entry. * @param dev Device instance. + * @param delay Time to delay the operation */ -#define sys_port_trace_pm_device_runtime_put_async_enter(dev) +#define sys_port_trace_pm_device_runtime_put_async_enter(dev, delay) /** * @brief Trace putting a device (asynchronously) call exit. * @param dev Device instance. + * @param delay Time to delay the operation. * @param ret Return value. */ -#define sys_port_trace_pm_device_runtime_put_async_exit(dev, ret) +#define sys_port_trace_pm_device_runtime_put_async_exit(dev, delay, ret) /** * @brief Trace enabling device runtime PM call entry. diff --git a/subsys/pm/device_runtime.c b/subsys/pm/device_runtime.c index a4b64fbe994..fb1d3286c54 100644 --- a/subsys/pm/device_runtime.c +++ b/subsys/pm/device_runtime.c @@ -35,6 +35,7 @@ LOG_MODULE_DECLARE(pm_device, CONFIG_PM_DEVICE_LOG_LEVEL); * * @param dev Device instance. * @param async Perform operation asynchronously. + * @param delay Period to delay the asynchronous operation. * * @retval 0 If device has been suspended or queued for suspend. * @retval -EALREADY If device is already suspended (can only happen if get/put @@ -42,7 +43,8 @@ LOG_MODULE_DECLARE(pm_device, CONFIG_PM_DEVICE_LOG_LEVEL); * @retval -EBUSY If the device is busy. * @retval -errno Other negative errno, result of the action callback. */ -static int runtime_suspend(const struct device *dev, bool async) +static int runtime_suspend(const struct device *dev, bool async, + k_timeout_t delay) { int ret = 0; struct pm_device *pm = dev->pm; @@ -77,7 +79,7 @@ static int runtime_suspend(const struct device *dev, bool async) if (async && !k_is_pre_kernel()) { /* queue suspend */ pm->state = PM_DEVICE_STATE_SUSPENDING; - (void)k_work_schedule(&pm->work, K_NO_WAIT); + (void)k_work_schedule(&pm->work, delay); } else { /* suspend now */ ret = pm->action_cb(pm->dev, PM_DEVICE_ACTION_SUSPEND); @@ -233,7 +235,7 @@ int pm_device_runtime_put(const struct device *dev) } SYS_PORT_TRACING_FUNC_ENTER(pm, device_runtime_put, dev); - ret = runtime_suspend(dev, false); + ret = runtime_suspend(dev, false, K_NO_WAIT); /* * Now put the domain @@ -247,7 +249,7 @@ int pm_device_runtime_put(const struct device *dev) return ret; } -int pm_device_runtime_put_async(const struct device *dev) +int pm_device_runtime_put_async(const struct device *dev, k_timeout_t delay) { int ret; @@ -255,9 +257,9 @@ int pm_device_runtime_put_async(const struct device *dev) return 0; } - SYS_PORT_TRACING_FUNC_ENTER(pm, device_runtime_put_async, dev); - ret = runtime_suspend(dev, true); - SYS_PORT_TRACING_FUNC_EXIT(pm, device_runtime_put_async, dev, ret); + SYS_PORT_TRACING_FUNC_ENTER(pm, device_runtime_put_async, dev, delay); + ret = runtime_suspend(dev, true, delay); + SYS_PORT_TRACING_FUNC_EXIT(pm, device_runtime_put_async, dev, delay, ret); return ret; } diff --git a/subsys/tracing/ctf/tracing_ctf.h b/subsys/tracing/ctf/tracing_ctf.h index 6b1b03e97d0..986a314f915 100644 --- a/subsys/tracing/ctf/tracing_ctf.h +++ b/subsys/tracing/ctf/tracing_ctf.h @@ -338,8 +338,8 @@ extern "C" { #define sys_port_trace_pm_device_runtime_get_exit(dev, ret) #define sys_port_trace_pm_device_runtime_put_enter(dev) #define sys_port_trace_pm_device_runtime_put_exit(dev, ret) -#define sys_port_trace_pm_device_runtime_put_async_enter(dev) -#define sys_port_trace_pm_device_runtime_put_async_exit(dev, ret) +#define sys_port_trace_pm_device_runtime_put_async_enter(dev, delay) +#define sys_port_trace_pm_device_runtime_put_async_exit(dev, delay, ret) #define sys_port_trace_pm_device_runtime_enable_enter(dev) #define sys_port_trace_pm_device_runtime_enable_exit(dev, ret) #define sys_port_trace_pm_device_runtime_disable_enter(dev) diff --git a/subsys/tracing/sysview/SYSVIEW_Zephyr.txt b/subsys/tracing/sysview/SYSVIEW_Zephyr.txt index dfad10e404a..758023d19f7 100644 --- a/subsys/tracing/sysview/SYSVIEW_Zephyr.txt +++ b/subsys/tracing/sysview/SYSVIEW_Zephyr.txt @@ -164,7 +164,7 @@ TaskState 0xBF 1=dummy, 2=Waiting, 4=New, 8=Terminated, 16=Suspended, 32=Termina 156 pm_system_suspend ticks=%u | Returns %Bool 157 pm_device_runtime_get dev=%I | Returns %u 158 pm_device_runtime_put dev=%I | Returns %u -159 pm_device_runtime_put_async dev=%I | Returns %u +159 pm_device_runtime_put_async dev=%I, Delay=%TimeOut | Returns %u 160 pm_device_runtime_enable dev=%I | Returns %u 161 pm_device_runtime_disable dev=%I | Returns %u diff --git a/subsys/tracing/sysview/tracing_sysview.h b/subsys/tracing/sysview/tracing_sysview.h index 105cfb1a3ee..8d6e90666f5 100644 --- a/subsys/tracing/sysview/tracing_sysview.h +++ b/subsys/tracing/sysview/tracing_sysview.h @@ -640,10 +640,10 @@ void sys_trace_k_thread_info(struct k_thread *thread); #define sys_port_trace_pm_device_runtime_put_exit(dev, ret) \ SEGGER_SYSVIEW_RecordEndCallU32(TID_PM_DEVICE_RUNTIME_PUT, \ (uint32_t)ret) -#define sys_port_trace_pm_device_runtime_put_async_enter(dev) \ +#define sys_port_trace_pm_device_runtime_put_async_enter(dev, delay) \ SEGGER_SYSVIEW_RecordU32(TID_PM_DEVICE_RUNTIME_PUT_ASYNC, \ - (uint32_t)(uintptr_t)dev) -#define sys_port_trace_pm_device_runtime_put_async_exit(dev, ret) \ + (uint32_t)(uintptr_t)dev, (uint32_t)delay.ticks) +#define sys_port_trace_pm_device_runtime_put_async_exit(dev, delay, ret) \ SEGGER_SYSVIEW_RecordEndCallU32(TID_PM_DEVICE_RUNTIME_PUT_ASYNC, \ (uint32_t)ret) #define sys_port_trace_pm_device_runtime_enable_enter(dev) \ diff --git a/subsys/tracing/test/tracing_test.h b/subsys/tracing/test/tracing_test.h index 6cf3ee6e583..71b63a762c5 100644 --- a/subsys/tracing/test/tracing_test.h +++ b/subsys/tracing/test/tracing_test.h @@ -442,8 +442,8 @@ #define sys_port_trace_pm_device_runtime_get_exit(dev, ret) #define sys_port_trace_pm_device_runtime_put_enter(dev) #define sys_port_trace_pm_device_runtime_put_exit(dev, ret) -#define sys_port_trace_pm_device_runtime_put_async_enter(dev) -#define sys_port_trace_pm_device_runtime_put_async_exit(dev, ret) +#define sys_port_trace_pm_device_runtime_put_async_enter(dev, delay) +#define sys_port_trace_pm_device_runtime_put_async_exit(dev, delay, ret) #define sys_port_trace_pm_device_runtime_enable_enter(dev) #define sys_port_trace_pm_device_runtime_enable_exit(dev, ret) #define sys_port_trace_pm_device_runtime_disable_enter(dev) diff --git a/subsys/tracing/user/tracing_user.h b/subsys/tracing/user/tracing_user.h index ddc6668d68a..c4231503d70 100644 --- a/subsys/tracing/user/tracing_user.h +++ b/subsys/tracing/user/tracing_user.h @@ -329,8 +329,8 @@ void sys_trace_idle(void); #define sys_port_trace_pm_device_runtime_get_exit(dev, ret) #define sys_port_trace_pm_device_runtime_put_enter(dev) #define sys_port_trace_pm_device_runtime_put_exit(dev, ret) -#define sys_port_trace_pm_device_runtime_put_async_enter(dev) -#define sys_port_trace_pm_device_runtime_put_async_exit(dev, ret) +#define sys_port_trace_pm_device_runtime_put_async_enter(dev, delay) +#define sys_port_trace_pm_device_runtime_put_async_exit(dev, delay, ret) #define sys_port_trace_pm_device_runtime_enable_enter(dev) #define sys_port_trace_pm_device_runtime_enable_exit(dev, ret) #define sys_port_trace_pm_device_runtime_disable_enter(dev) diff --git a/tests/subsys/pm/device_runtime_api/src/main.c b/tests/subsys/pm/device_runtime_api/src/main.c index 57fd7d8bcc8..292d90e66cf 100644 --- a/tests/subsys/pm/device_runtime_api/src/main.c +++ b/tests/subsys/pm/device_runtime_api/src/main.c @@ -42,7 +42,7 @@ void test_api_setup(void *data) zassert_equal(ret, 0); ret = pm_device_runtime_put(test_dev); zassert_equal(ret, 0); - ret = pm_device_runtime_put_async(test_dev); + ret = pm_device_runtime_put_async(test_dev, K_NO_WAIT); zassert_equal(ret, 0); /* enable runtime PM */ @@ -138,7 +138,7 @@ ZTEST(device_runtime_api, test_api) test_driver_pm_async(test_dev); /* usage: 1, -1, suspend: yes (queued) */ - ret = pm_device_runtime_put_async(test_dev); + ret = pm_device_runtime_put_async(test_dev, K_NO_WAIT); zassert_equal(ret, 0); (void)pm_device_state_get(test_dev, &state); @@ -149,7 +149,7 @@ ZTEST(device_runtime_api, test_api) zassert_equal(ret, -EALREADY); /* usage: 0, -1, suspend: no (unbalanced call) */ - ret = pm_device_runtime_put_async(test_dev); + ret = pm_device_runtime_put_async(test_dev, K_NO_WAIT); zassert_equal(ret, -EALREADY); /* unblock test driver and let it finish */ @@ -171,7 +171,7 @@ ZTEST(device_runtime_api, test_api) test_driver_pm_async(test_dev); /* usage: 1, -1, suspend: yes (queued) */ - ret = pm_device_runtime_put_async(test_dev); + ret = pm_device_runtime_put_async(test_dev, K_NO_WAIT); zassert_equal(ret, 0); (void)pm_device_state_get(test_dev, &state); From 3f7325e34b342481b847ac1859ad4ae8b91c74be Mon Sep 17 00:00:00 2001 From: Flavio Ceolin Date: Wed, 6 Dec 2023 18:03:30 +0000 Subject: [PATCH 1077/3723] tests: pm: device_runtime: Checks async put with delay Checks that async put respects the given delay. Signed-off-by: Flavio Ceolin --- tests/subsys/pm/device_runtime_api/src/main.c | 22 +++++++++++++++++++ 1 file changed, 22 insertions(+) diff --git a/tests/subsys/pm/device_runtime_api/src/main.c b/tests/subsys/pm/device_runtime_api/src/main.c index 292d90e66cf..c75cd7bbc13 100644 --- a/tests/subsys/pm/device_runtime_api/src/main.c +++ b/tests/subsys/pm/device_runtime_api/src/main.c @@ -200,6 +200,28 @@ ZTEST(device_runtime_api, test_api) (void)pm_device_state_get(test_dev, &state); zassert_equal(state, PM_DEVICE_STATE_ACTIVE); + /* + * test if async put with a delay respects the given time. + */ + ret = pm_device_runtime_put_async(test_dev, K_MSEC(100)); + + (void)pm_device_state_get(test_dev, &state); + zassert_equal(state, PM_DEVICE_STATE_SUSPENDING); + + k_sleep(K_MSEC(80)); + + /* It should still be suspending since we have waited less than + * the delay we've set. + */ + (void)pm_device_state_get(test_dev, &state); + zassert_equal(state, PM_DEVICE_STATE_SUSPENDING); + + k_sleep(K_MSEC(30)); + + /* Now it should be already suspended */ + (void)pm_device_state_get(test_dev, &state); + zassert_equal(state, PM_DEVICE_STATE_SUSPENDED); + /* Put operation should fail due the state be locked. */ ret = pm_device_runtime_disable(test_dev); zassert_equal(ret, 0); From c724a6c5ef9fb1587bce78883684606ae497c299 Mon Sep 17 00:00:00 2001 From: Flavio Ceolin Date: Wed, 6 Dec 2023 18:49:24 +0000 Subject: [PATCH 1078/3723] tests: pm: device_runtime_api: Check async behavior Additional test to check if getting a device while there is a pending async put does not trigger unnecessary device state changes. Signed-off-by: Flavio Ceolin --- tests/subsys/pm/device_runtime_api/src/main.c | 19 +++++++++++++++++++ .../pm/device_runtime_api/src/test_driver.c | 10 ++++++++++ .../pm/device_runtime_api/src/test_driver.h | 9 +++++++++ 3 files changed, 38 insertions(+) diff --git a/tests/subsys/pm/device_runtime_api/src/main.c b/tests/subsys/pm/device_runtime_api/src/main.c index c75cd7bbc13..2288d64675a 100644 --- a/tests/subsys/pm/device_runtime_api/src/main.c +++ b/tests/subsys/pm/device_runtime_api/src/main.c @@ -200,6 +200,25 @@ ZTEST(device_runtime_api, test_api) (void)pm_device_state_get(test_dev, &state); zassert_equal(state, PM_DEVICE_STATE_ACTIVE); + /* Test if getting a device before an async operation starts does + * not trigger any device pm action. + */ + size_t count = test_driver_pm_count(test_dev); + + ret = pm_device_runtime_put_async(test_dev, K_MSEC(10)); + zassert_equal(ret, 0); + + (void)pm_device_state_get(test_dev, &state); + zassert_equal(state, PM_DEVICE_STATE_SUSPENDING); + + ret = pm_device_runtime_get(test_dev); + zassert_equal(ret, 0); + + /* Now lets check if the calls above have triggered a device + * pm action + */ + zassert_equal(count, test_driver_pm_count(test_dev)); + /* * test if async put with a delay respects the given time. */ diff --git a/tests/subsys/pm/device_runtime_api/src/test_driver.c b/tests/subsys/pm/device_runtime_api/src/test_driver.c index cb91cbffc0e..d7c06f9cddb 100644 --- a/tests/subsys/pm/device_runtime_api/src/test_driver.c +++ b/tests/subsys/pm/device_runtime_api/src/test_driver.c @@ -10,6 +10,7 @@ #include struct test_driver_data { + size_t count; bool ongoing; bool async; struct k_sem sync; @@ -29,6 +30,8 @@ static int test_driver_action(const struct device *dev, data->ongoing = false; + data->count++; + return 0; } @@ -53,6 +56,13 @@ bool test_driver_pm_ongoing(const struct device *dev) return data->ongoing; } +size_t test_driver_pm_count(const struct device *dev) +{ + struct test_driver_data *data = dev->data; + + return data->count; +} + int test_driver_init(const struct device *dev) { struct test_driver_data *data = dev->data; diff --git a/tests/subsys/pm/device_runtime_api/src/test_driver.h b/tests/subsys/pm/device_runtime_api/src/test_driver.h index a5305f938c4..4979c7d2cb1 100644 --- a/tests/subsys/pm/device_runtime_api/src/test_driver.h +++ b/tests/subsys/pm/device_runtime_api/src/test_driver.h @@ -36,4 +36,13 @@ void test_driver_pm_done(const struct device *dev); */ bool test_driver_pm_ongoing(const struct device *dev); +/** + * @brief Gets the number of times the device changed state. + * + * @param dev Device instance. + * + * @return The number of state changes the device made. + */ +size_t test_driver_pm_count(const struct device *dev); + #endif /* TESTS_SUBSYS_PM_DEVICE_RUNTIME_TEST_DRIVER_H_ */ From ebf50eee426a3fe080fdb006921cf08f35a438bd Mon Sep 17 00:00:00 2001 From: Flavio Ceolin Date: Wed, 6 Dec 2023 17:57:40 -0800 Subject: [PATCH 1079/3723] soc: stm32f4: Fix PM dependency COUNTER_RTC_STM32_SUBSECONDS depends on DT_HAS_ST_STM32_RTC_ENABLED. Signed-off-by: Flavio Ceolin --- soc/arm/st_stm32/stm32f4/Kconfig.defconfig.series | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/soc/arm/st_stm32/stm32f4/Kconfig.defconfig.series b/soc/arm/st_stm32/stm32f4/Kconfig.defconfig.series index 28ed9cc3a55..067dcfc003f 100644 --- a/soc/arm/st_stm32/stm32f4/Kconfig.defconfig.series +++ b/soc/arm/st_stm32/stm32f4/Kconfig.defconfig.series @@ -19,6 +19,6 @@ config TASK_WDT_HW_FALLBACK_DELAY config PM select COUNTER - select COUNTER_RTC_STM32_SUBSECONDS + select COUNTER_RTC_STM32_SUBSECONDS if DT_HAS_ST_STM32_RTC_ENABLED endif # SOC_SERIES_STM32F4X From a0f547aac49149e696ed6a56922331312ad07e19 Mon Sep 17 00:00:00 2001 From: Benedikt Schmidt Date: Thu, 7 Dec 2023 08:56:48 +0100 Subject: [PATCH 1080/3723] drivers: smbus: add missing includes Add includes which are actually required for the compilation in the headers themselves to avoid include dependencies. Signed-off-by: Benedikt Schmidt --- drivers/smbus/smbus_utils.h | 5 +++++ include/zephyr/drivers/smbus.h | 2 ++ 2 files changed, 7 insertions(+) diff --git a/drivers/smbus/smbus_utils.h b/drivers/smbus/smbus_utils.h index 0158d2c5a52..c3f2023b423 100644 --- a/drivers/smbus/smbus_utils.h +++ b/drivers/smbus/smbus_utils.h @@ -7,6 +7,11 @@ #ifndef ZEPHYR_DRIVERS_SMBUS_SMBUS_UTILS_H_ #define ZEPHYR_DRIVERS_SMBUS_SMBUS_UTILS_H_ +#include +#include +#include +#include + /** * @brief Generic function to insert a callback to a callback list * diff --git a/include/zephyr/drivers/smbus.h b/include/zephyr/drivers/smbus.h index c4995febb7b..c0348c367f1 100644 --- a/include/zephyr/drivers/smbus.h +++ b/include/zephyr/drivers/smbus.h @@ -19,6 +19,8 @@ * @{ */ +#include +#include #include #include From fc86d0c3bcea397e16541749ae25a3c42eb3eabb Mon Sep 17 00:00:00 2001 From: Benedikt Schmidt Date: Thu, 7 Dec 2023 08:58:42 +0100 Subject: [PATCH 1081/3723] drivers: smbus: extract handler function for SMB alert Extract a helper function for handling an SMB alert, as every SMBus implementation will have to loop through the peripheral address which might have triggered the alert. Signed-off-by: Benedikt Schmidt --- drivers/smbus/CMakeLists.txt | 3 +++ drivers/smbus/intel_pch_smbus.c | 28 +-------------------- drivers/smbus/smbus_utils.c | 43 +++++++++++++++++++++++++++++++++ drivers/smbus/smbus_utils.h | 10 ++++++++ 4 files changed, 57 insertions(+), 27 deletions(-) create mode 100644 drivers/smbus/smbus_utils.c diff --git a/drivers/smbus/CMakeLists.txt b/drivers/smbus/CMakeLists.txt index 13a260681f0..b7677a9bf6f 100644 --- a/drivers/smbus/CMakeLists.txt +++ b/drivers/smbus/CMakeLists.txt @@ -4,7 +4,10 @@ zephyr_syscall_header(${ZEPHYR_BASE}/include/zephyr/drivers/smbus.h) zephyr_library() +zephyr_library_sources(smbus_utils.c) + zephyr_library_sources_ifdef(CONFIG_SMBUS_SHELL smbus_shell.c) zephyr_library_sources_ifdef(CONFIG_SMBUS_INTEL_PCH intel_pch_smbus.c) +zephyr_library_sources_ifdef(CONFIG_SMBUS_STM32 smbus_stm32.c) zephyr_library_sources_ifdef(CONFIG_USERSPACE smbus_handlers.c) diff --git a/drivers/smbus/intel_pch_smbus.c b/drivers/smbus/intel_pch_smbus.c index e40fc3d0cb6..9452efecf22 100644 --- a/drivers/smbus/intel_pch_smbus.c +++ b/drivers/smbus/intel_pch_smbus.c @@ -143,33 +143,7 @@ static void smbalert_work(struct k_work *work) smb_alert_work); const struct device *dev = data->dev; - /** - * There might be several peripheral devices and the he highest - * priority (lowest address) device wins arbitration, we need to - * read them all. - * - * The format of the transaction is: - * - * 0 1 2 - * 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 - * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ - * |S| Alert Addr |R|A| Address |X|N|P| - * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ - */ - do { - uint8_t addr; - int ret; - - ret = smbus_byte_read(dev, SMBUS_ADDRESS_ARA, &addr); - if (ret < 0) { - LOG_DBG("Cannot read peripheral address (anymore)"); - return; - } - - LOG_DBG("Read addr 0x%02x, ret %d", addr, ret); - - smbus_fire_callbacks(&data->smbalert_cbs, dev, addr); - } while (true); + smbus_loop_alert_devices(dev, &data->smbalert_cbs); } static int pch_smbus_smbalert_set_sb(const struct device *dev, diff --git a/drivers/smbus/smbus_utils.c b/drivers/smbus/smbus_utils.c new file mode 100644 index 00000000000..5ff3076da9e --- /dev/null +++ b/drivers/smbus/smbus_utils.c @@ -0,0 +1,43 @@ +/* + * Copyright (c) 2022 Intel Corporation + * Copyright (c) 2023 SILA Embedded Solutions GmbH + * SPDX-License-Identifier: Apache-2.0 + */ + +#include "smbus_utils.h" + +#include + +LOG_MODULE_REGISTER(smbus_utils, CONFIG_SMBUS_LOG_LEVEL); + +void smbus_loop_alert_devices(const struct device *dev, sys_slist_t *callbacks) +{ + int result; + uint8_t address; + + /** + * There might be several peripheral devices which could have triggered the alert and + * the one with the highest priority (lowest address) device wins the arbitration. In + * any case, we will have to loop through all of them. + * + * The format of the transaction is: + * + * 0 1 2 + * 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 + * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + * |S| Alert Addr |R|A| Address |X|N|P| + * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + */ + while (true) { + result = smbus_byte_read(dev, SMBUS_ADDRESS_ARA, &address); + if (result != 0) { + LOG_DBG("%s: no more peripheral devices left which triggered an alert", + dev->name); + return; + } + + LOG_DBG("%s: address 0x%02X triggered an alert", dev->name, address); + + smbus_fire_callbacks(callbacks, dev, address); + } +} diff --git a/drivers/smbus/smbus_utils.h b/drivers/smbus/smbus_utils.h index c3f2023b423..a4f7ecd0c72 100644 --- a/drivers/smbus/smbus_utils.h +++ b/drivers/smbus/smbus_utils.h @@ -96,5 +96,15 @@ static inline void smbus_init_callback(struct smbus_callback *callback, callback->addr = addr; } +/** + * @brief Helper for handling an SMB alert + * + * This loops through all devices which triggered the SMB alert and + * fires the callbacks. + * + * @param dev SMBus device + * @param callbacks list of SMB alert callbacks + */ +void smbus_loop_alert_devices(const struct device *dev, sys_slist_t *callbacks); #endif /* ZEPHYR_DRIVERS_SMBUS_SMBUS_UTILS_H_ */ From fc124a144240ef0f15a2f64981efe6aa88b952ee Mon Sep 17 00:00:00 2001 From: Benedikt Schmidt Date: Thu, 7 Dec 2023 09:00:22 +0100 Subject: [PATCH 1082/3723] dts: bindings: add STM32 SMBus Add a dts binding for STM32 SMBus. Signed-off-by: Benedikt Schmidt --- dts/bindings/smbus/st,stm32-smbus.yaml | 14 ++++++++++++++ 1 file changed, 14 insertions(+) create mode 100644 dts/bindings/smbus/st,stm32-smbus.yaml diff --git a/dts/bindings/smbus/st,stm32-smbus.yaml b/dts/bindings/smbus/st,stm32-smbus.yaml new file mode 100644 index 00000000000..2c93189c178 --- /dev/null +++ b/dts/bindings/smbus/st,stm32-smbus.yaml @@ -0,0 +1,14 @@ +# Copyright (c) 2023 SILA Embedded Solutions GmbH +# SPDX-License-Identifier: Apache-2.0 + +description: STM32 SMBus controller + +compatible: "st,stm32-smbus" + +include: [smbus-controller.yaml, pinctrl-device.yaml] + +properties: + i2c: + type: phandle + required: true + description: I2C device which maps to the same address From 0861395713b83c4bc578564683ed461a8fd6e4fb Mon Sep 17 00:00:00 2001 From: Benedikt Schmidt Date: Thu, 7 Dec 2023 09:06:46 +0100 Subject: [PATCH 1083/3723] drivers: smbus: implement SMBus driver for STM32 Implement a SMBus driver for STM32, which reuses the I2C implementation. Signed-off-by: Benedikt Schmidt --- drivers/i2c/i2c_ll_stm32.c | 71 ++++++- drivers/i2c/i2c_ll_stm32.h | 8 + drivers/i2c/i2c_ll_stm32_v1.c | 28 ++- drivers/i2c/i2c_ll_stm32_v2.c | 26 ++- drivers/smbus/Kconfig | 18 ++ drivers/smbus/smbus_stm32.c | 290 +++++++++++++++++++++++++++++ include/zephyr/drivers/i2c/stm32.h | 31 +++ 7 files changed, 462 insertions(+), 10 deletions(-) create mode 100644 drivers/smbus/smbus_stm32.c create mode 100644 include/zephyr/drivers/i2c/stm32.h diff --git a/drivers/i2c/i2c_ll_stm32.c b/drivers/i2c/i2c_ll_stm32.c index 552acfb6ab2..616c89b3dcb 100644 --- a/drivers/i2c/i2c_ll_stm32.c +++ b/drivers/i2c/i2c_ll_stm32.c @@ -94,9 +94,13 @@ int i2c_stm32_runtime_configure(const struct device *dev, uint32_t config) #endif LL_I2C_Disable(i2c); - LL_I2C_SetMode(i2c, LL_I2C_MODE_I2C); + i2c_stm32_set_smbus_mode(dev, data->mode); ret = stm32_i2c_configure_timing(dev, i2c_clock); + if (data->smbalert_active) { + LL_I2C_Enable(i2c); + } + #ifdef CONFIG_PM_DEVICE_RUNTIME ret = clock_control_off(clk, (clock_control_subsys_t)&cfg->pclken[0]); if (ret < 0) { @@ -365,6 +369,7 @@ static int i2c_stm32_init(const struct device *dev) #endif data->is_configured = false; + data->mode = I2CSTM32MODE_I2C; /* * initialize mutex used when multiple transfers @@ -441,6 +446,70 @@ static int i2c_stm32_pm_action(const struct device *dev, enum pm_device_action a #endif +#ifdef CONFIG_SMBUS_STM32_SMBALERT +void i2c_stm32_smbalert_set_callback(const struct device *dev, i2c_stm32_smbalert_cb_func_t func, + const struct device *cb_dev) +{ + struct i2c_stm32_data *data = dev->data; + + data->smbalert_cb_func = func; + data->smbalert_cb_dev = cb_dev; +} +#endif /* CONFIG_SMBUS_STM32_SMBALERT */ + +void i2c_stm32_set_smbus_mode(const struct device *dev, enum i2c_stm32_mode mode) +{ + const struct i2c_stm32_config *cfg = dev->config; + struct i2c_stm32_data *data = dev->data; + I2C_TypeDef *i2c = cfg->i2c; + + data->mode = mode; + + switch (mode) { + case I2CSTM32MODE_I2C: + LL_I2C_SetMode(i2c, LL_I2C_MODE_I2C); + return; +#ifdef CONFIG_SMBUS_STM32 + case I2CSTM32MODE_SMBUSHOST: + LL_I2C_SetMode(i2c, LL_I2C_MODE_SMBUS_HOST); + return; + case I2CSTM32MODE_SMBUSDEVICE: + LL_I2C_SetMode(i2c, LL_I2C_MODE_SMBUS_DEVICE); + return; + case I2CSTM32MODE_SMBUSDEVICEARP: + LL_I2C_SetMode(i2c, LL_I2C_MODE_SMBUS_DEVICE_ARP); + return; +#endif + default: + LOG_ERR("%s: invalid mode %i", dev->name, mode); + return; + } +} + +#ifdef CONFIG_SMBUS_STM32 +void i2c_stm32_smbalert_enable(const struct device *dev) +{ + struct i2c_stm32_data *data = dev->data; + const struct i2c_stm32_config *cfg = dev->config; + + data->smbalert_active = true; + LL_I2C_EnableSMBusAlert(cfg->i2c); + LL_I2C_EnableIT_ERR(cfg->i2c); + LL_I2C_Enable(cfg->i2c); +} + +void i2c_stm32_smbalert_disable(const struct device *dev) +{ + struct i2c_stm32_data *data = dev->data; + const struct i2c_stm32_config *cfg = dev->config; + + data->smbalert_active = false; + LL_I2C_DisableSMBusAlert(cfg->i2c); + LL_I2C_DisableIT_ERR(cfg->i2c); + LL_I2C_Disable(cfg->i2c); +} +#endif /* CONFIG_SMBUS_STM32 */ + /* Macros for I2C instance declaration */ #ifdef CONFIG_I2C_STM32_INTERRUPT diff --git a/drivers/i2c/i2c_ll_stm32.h b/drivers/i2c/i2c_ll_stm32.h index c77b687038d..0a9dc1be350 100644 --- a/drivers/i2c/i2c_ll_stm32.h +++ b/drivers/i2c/i2c_ll_stm32.h @@ -9,6 +9,8 @@ #ifndef ZEPHYR_DRIVERS_I2C_I2C_LL_STM32_H_ #define ZEPHYR_DRIVERS_I2C_I2C_LL_STM32_H_ +#include + #ifdef CONFIG_I2C_STM32_BUS_RECOVERY #include #endif /* CONFIG_I2C_STM32_BUS_RECOVERY */ @@ -79,6 +81,12 @@ struct i2c_stm32_data { bool slave_attached; #endif bool is_configured; + bool smbalert_active; + enum i2c_stm32_mode mode; +#ifdef CONFIG_SMBUS_STM32_SMBALERT + i2c_stm32_smbalert_cb_func_t smbalert_cb_func; + const struct device *smbalert_cb_dev; +#endif }; int32_t stm32_i2c_transaction(const struct device *dev, diff --git a/drivers/i2c/i2c_ll_stm32_v1.c b/drivers/i2c/i2c_ll_stm32_v1.c index d0a0131858f..4730cc15598 100644 --- a/drivers/i2c/i2c_ll_stm32_v1.c +++ b/drivers/i2c/i2c_ll_stm32_v1.c @@ -48,13 +48,17 @@ static void stm32_i2c_generate_start_condition(I2C_TypeDef *i2c) static void stm32_i2c_disable_transfer_interrupts(const struct device *dev) { const struct i2c_stm32_config *cfg = dev->config; + struct i2c_stm32_data *data = dev->data; I2C_TypeDef *i2c = cfg->i2c; LL_I2C_DisableIT_TX(i2c); LL_I2C_DisableIT_RX(i2c); LL_I2C_DisableIT_EVT(i2c); LL_I2C_DisableIT_BUF(i2c); - LL_I2C_DisableIT_ERR(i2c); + + if (!data->smbalert_active) { + LL_I2C_DisableIT_ERR(i2c); + } } static void stm32_i2c_enable_transfer_interrupts(const struct device *dev) @@ -118,6 +122,7 @@ static void stm32_i2c_reset(const struct device *dev) static void stm32_i2c_master_finish(const struct device *dev) { const struct i2c_stm32_config *cfg = dev->config; + struct i2c_stm32_data *data = dev->data; I2C_TypeDef *i2c = cfg->i2c; #ifdef CONFIG_I2C_STM32_INTERRUPT @@ -125,16 +130,17 @@ static void stm32_i2c_master_finish(const struct device *dev) #endif #if defined(CONFIG_I2C_TARGET) - struct i2c_stm32_data *data = dev->data; data->master_active = false; - if (!data->slave_attached) { + if (!data->slave_attached && !data->smbalert_active) { LL_I2C_Disable(i2c); } else { stm32_i2c_enable_transfer_interrupts(dev); LL_I2C_AcknowledgeNextData(i2c, LL_I2C_ACK); } #else - LL_I2C_Disable(i2c); + if (!data->smbalert_active) { + LL_I2C_Disable(i2c); + } #endif } @@ -538,7 +544,9 @@ int i2c_stm32_target_unregister(const struct device *dev, struct i2c_target_conf LL_I2C_ClearFlag_STOP(i2c); LL_I2C_ClearFlag_ADDR(i2c); - LL_I2C_Disable(i2c); + if (!data->smbalert_active) { + LL_I2C_Disable(i2c); + } data->slave_attached = false; @@ -608,6 +616,16 @@ void stm32_i2c_error_isr(void *arg) data->current.is_err = 1U; goto end; } + +#if defined(CONFIG_SMBUS_STM32_SMBALERT) + if (LL_I2C_IsActiveSMBusFlag_ALERT(i2c)) { + LL_I2C_ClearSMBusFlag_ALERT(i2c); + if (data->smbalert_cb_func != NULL) { + data->smbalert_cb_func(data->smbalert_cb_dev); + } + goto end; + } +#endif return; end: stm32_i2c_master_mode_end(dev); diff --git a/drivers/i2c/i2c_ll_stm32_v2.c b/drivers/i2c/i2c_ll_stm32_v2.c index 8292b2f6738..a685ebebeb7 100644 --- a/drivers/i2c/i2c_ll_stm32_v2.c +++ b/drivers/i2c/i2c_ll_stm32_v2.c @@ -74,6 +74,7 @@ static inline void msg_init(const struct device *dev, struct i2c_msg *msg, static void stm32_i2c_disable_transfer_interrupts(const struct device *dev) { const struct i2c_stm32_config *cfg = dev->config; + struct i2c_stm32_data *data = dev->data; I2C_TypeDef *i2c = cfg->i2c; LL_I2C_DisableIT_TX(i2c); @@ -81,7 +82,10 @@ static void stm32_i2c_disable_transfer_interrupts(const struct device *dev) LL_I2C_DisableIT_STOP(i2c); LL_I2C_DisableIT_NACK(i2c); LL_I2C_DisableIT_TC(i2c); - LL_I2C_DisableIT_ERR(i2c); + + if (!data->smbalert_active) { + LL_I2C_DisableIT_ERR(i2c); + } } static void stm32_i2c_enable_transfer_interrupts(const struct device *dev) @@ -109,11 +113,13 @@ static void stm32_i2c_master_mode_end(const struct device *dev) #if defined(CONFIG_I2C_TARGET) data->master_active = false; - if (!data->slave_attached) { + if (!data->slave_attached && !data->smbalert_active) { LL_I2C_Disable(i2c); } #else - LL_I2C_Disable(i2c); + if (!data->smbalert_active) { + LL_I2C_Disable(i2c); + } #endif k_sem_give(&data->device_sync_sem); } @@ -330,7 +336,9 @@ int i2c_stm32_target_unregister(const struct device *dev, LL_I2C_ClearFlag_STOP(i2c); LL_I2C_ClearFlag_ADDR(i2c); - LL_I2C_Disable(i2c); + if (!data->smbalert_active) { + LL_I2C_Disable(i2c); + } #if defined(CONFIG_PM_DEVICE_RUNTIME) if (pm_device_wakeup_is_capable(dev)) { @@ -437,6 +445,16 @@ static int stm32_i2c_error(const struct device *dev) goto end; } +#if defined(CONFIG_SMBUS_STM32_SMBALERT) + if (LL_I2C_IsActiveSMBusFlag_ALERT(i2c)) { + LL_I2C_ClearSMBusFlag_ALERT(i2c); + if (data->smbalert_cb_func != NULL) { + data->smbalert_cb_func(data->smbalert_cb_dev); + } + goto end; + } +#endif + return 0; end: stm32_i2c_master_mode_end(dev); diff --git a/drivers/smbus/Kconfig b/drivers/smbus/Kconfig index 88eff8b0030..74efaae29f1 100644 --- a/drivers/smbus/Kconfig +++ b/drivers/smbus/Kconfig @@ -77,4 +77,22 @@ config SMBUS_INTEL_PCH_SMBALERT endif # SMBUS_INTEL_PCH +config SMBUS_STM32 + bool "STM32 SMBus driver" + default y + depends on DT_HAS_ST_STM32_SMBUS_ENABLED + depends on I2C_STM32 + help + Enable STM32 SMBus driver. + +if SMBUS_STM32 + +config SMBUS_STM32_SMBALERT + bool "SMBus STM32 SMBALERT signal support" + default y + help + Support SMBALERT signal from peripheral devices. + +endif # SMBUS_STM32 + endif # SMBUS diff --git a/drivers/smbus/smbus_stm32.c b/drivers/smbus/smbus_stm32.c new file mode 100644 index 00000000000..56636cc84bf --- /dev/null +++ b/drivers/smbus/smbus_stm32.c @@ -0,0 +1,290 @@ +/* + * Copyright (c) 2023 SILA Embedded Solutions GmbH + * SPDX-License-Identifier: Apache-2.0 + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "smbus_utils.h" + +LOG_MODULE_REGISTER(stm32_smbus, CONFIG_SMBUS_LOG_LEVEL); + +struct smbus_stm32_config { + const struct pinctrl_dev_config *pcfg; + const struct device *i2c_dev; +}; + +struct smbus_stm32_data { + uint32_t config; + const struct device *dev; +#ifdef CONFIG_SMBUS_STM32_SMBALERT + sys_slist_t smbalert_callbacks; + struct k_work smbalert_work; +#endif /* CONFIG_SMBUS_STM32_SMBALERT */ +}; + +#ifdef CONFIG_SMBUS_STM32_SMBALERT +static void smbus_stm32_smbalert_isr(const struct device *dev) +{ + struct smbus_stm32_data *data = dev->data; + + k_work_submit(&data->smbalert_work); +} + +static void smbus_stm32_smbalert_work(struct k_work *work) +{ + struct smbus_stm32_data *data = CONTAINER_OF(work, struct smbus_stm32_data, smbalert_work); + const struct device *dev = data->dev; + + LOG_DBG("%s: got SMB alert", dev->name); + + smbus_loop_alert_devices(dev, &data->smbalert_callbacks); +} + +static int smbus_stm32_smbalert_set_cb(const struct device *dev, struct smbus_callback *cb) +{ + struct smbus_stm32_data *data = dev->data; + + return smbus_callback_set(&data->smbalert_callbacks, cb); +} + +static int smbus_stm32_smbalert_remove_cb(const struct device *dev, struct smbus_callback *cb) +{ + struct smbus_stm32_data *data = dev->data; + + return smbus_callback_remove(&data->smbalert_callbacks, cb); +} +#endif /* CONFIG_SMBUS_STM32_SMBALERT */ + +static int smbus_stm32_init(const struct device *dev) +{ + const struct smbus_stm32_config *config = dev->config; + struct smbus_stm32_data *data = dev->data; + int result; + + data->dev = dev; + + if (!device_is_ready(config->i2c_dev)) { + LOG_ERR("%s: I2C device is not ready", dev->name); + return -ENODEV; + } + + result = pinctrl_apply_state(config->pcfg, PINCTRL_STATE_DEFAULT); + if (result < 0) { + LOG_ERR("%s: pinctrl setup failed (%d)", dev->name, result); + return result; + } + +#ifdef CONFIG_SMBUS_STM32_SMBALERT + k_work_init(&data->smbalert_work, smbus_stm32_smbalert_work); + + i2c_stm32_smbalert_set_callback(config->i2c_dev, smbus_stm32_smbalert_isr, dev); +#endif /* CONFIG_SMBUS_STM32_SMBALERT */ + + return 0; +} + +static int smbus_stm32_configure(const struct device *dev, uint32_t config_value) +{ + const struct smbus_stm32_config *config = dev->config; + struct smbus_stm32_data *data = dev->data; + + if (config_value & SMBUS_MODE_PEC) { + LOG_ERR("%s: not implemented", dev->name); + return -EINVAL; + } + + if (config_value & SMBUS_MODE_HOST_NOTIFY) { + LOG_ERR("%s: not available", dev->name); + return -EINVAL; + } + + if (config_value & SMBUS_MODE_CONTROLLER) { + LOG_DBG("%s: configuring SMB in host mode", dev->name); + i2c_stm32_set_smbus_mode(config->i2c_dev, I2CSTM32MODE_SMBUSHOST); + } else { + LOG_DBG("%s: configuring SMB in device mode", dev->name); + i2c_stm32_set_smbus_mode(config->i2c_dev, I2CSTM32MODE_SMBUSDEVICE); + } + + if (config_value & SMBUS_MODE_SMBALERT) { + LOG_DBG("%s: activating SMB alert", dev->name); + i2c_stm32_smbalert_enable(config->i2c_dev); + } else { + LOG_DBG("%s: deactivating SMB alert", dev->name); + i2c_stm32_smbalert_disable(config->i2c_dev); + } + + data->config = config_value; + return 0; +} + +static int smbus_stm32_get_config(const struct device *dev, uint32_t *config) +{ + struct smbus_stm32_data *data = dev->data; + *config = data->config; + return 0; +} + +static int smbus_stm32_quick(const struct device *dev, uint16_t periph_addr, + enum smbus_direction rw) +{ + const struct smbus_stm32_config *config = dev->config; + + switch (rw) { + case SMBUS_MSG_WRITE: + return i2c_write(config->i2c_dev, NULL, 0, periph_addr); + case SMBUS_MSG_READ: + return i2c_read(config->i2c_dev, NULL, 0, periph_addr); + default: + LOG_ERR("%s: invalid smbus direction %i", dev->name, rw); + return -EINVAL; + } +} + +static int smbus_stm32_byte_write(const struct device *dev, uint16_t periph_addr, uint8_t command) +{ + const struct smbus_stm32_config *config = dev->config; + + return i2c_write(config->i2c_dev, &command, sizeof(command), periph_addr); +} + +static int smbus_stm32_byte_read(const struct device *dev, uint16_t periph_addr, uint8_t *byte) +{ + const struct smbus_stm32_config *config = dev->config; + + return i2c_read(config->i2c_dev, byte, sizeof(*byte), periph_addr); +} + +static int smbus_stm32_byte_data_write(const struct device *dev, uint16_t periph_addr, + uint8_t command, uint8_t byte) +{ + const struct smbus_stm32_config *config = dev->config; + uint8_t buffer[] = { + command, + byte, + }; + + return i2c_write(config->i2c_dev, buffer, ARRAY_SIZE(buffer), periph_addr); +} + +static int smbus_stm32_byte_data_read(const struct device *dev, uint16_t periph_addr, + uint8_t command, uint8_t *byte) +{ + const struct smbus_stm32_config *config = dev->config; + + return i2c_write_read(config->i2c_dev, periph_addr, &command, sizeof(command), byte, + sizeof(*byte)); +} + +static int smbus_stm32_word_data_write(const struct device *dev, uint16_t periph_addr, + uint8_t command, uint16_t word) +{ + const struct smbus_stm32_config *config = dev->config; + uint8_t buffer[sizeof(command) + sizeof(word)]; + + buffer[0] = command; + sys_put_le16(word, buffer + 1); + + return i2c_write(config->i2c_dev, buffer, ARRAY_SIZE(buffer), periph_addr); +} + +static int smbus_stm32_word_data_read(const struct device *dev, uint16_t periph_addr, + uint8_t command, uint16_t *word) +{ + const struct smbus_stm32_config *config = dev->config; + int result; + + result = i2c_write_read(config->i2c_dev, periph_addr, &command, sizeof(command), word, + sizeof(*word)); + *word = sys_le16_to_cpu(*word); + + return result; +} + +static int smbus_stm32_pcall(const struct device *dev, uint16_t periph_addr, uint8_t command, + uint16_t send_word, uint16_t *recv_word) +{ + const struct smbus_stm32_config *config = dev->config; + uint8_t buffer[sizeof(command) + sizeof(send_word)]; + int result; + + buffer[0] = command; + sys_put_le16(send_word, buffer + 1); + + result = i2c_write_read(config->i2c_dev, periph_addr, buffer, ARRAY_SIZE(buffer), recv_word, + sizeof(*recv_word)); + *recv_word = sys_le16_to_cpu(*recv_word); + + return result; +} + +static int smbus_stm32_block_write(const struct device *dev, uint16_t periph_addr, uint8_t command, + uint8_t count, uint8_t *buf) +{ + const struct smbus_stm32_config *config = dev->config; + struct i2c_msg messages[] = { + { + .buf = &command, + .len = sizeof(command), + .flags = 0, + }, + { + .buf = buf, + .len = count, + .flags = 0, + }, + }; + + return i2c_transfer(config->i2c_dev, messages, ARRAY_SIZE(messages), periph_addr); +} + +static const struct smbus_driver_api smbus_stm32_api = { + .configure = smbus_stm32_configure, + .get_config = smbus_stm32_get_config, + .smbus_quick = smbus_stm32_quick, + .smbus_byte_write = smbus_stm32_byte_write, + .smbus_byte_read = smbus_stm32_byte_read, + .smbus_byte_data_write = smbus_stm32_byte_data_write, + .smbus_byte_data_read = smbus_stm32_byte_data_read, + .smbus_word_data_write = smbus_stm32_word_data_write, + .smbus_word_data_read = smbus_stm32_word_data_read, + .smbus_pcall = smbus_stm32_pcall, + .smbus_block_write = smbus_stm32_block_write, +#ifdef CONFIG_SMBUS_STM32_SMBALERT + .smbus_smbalert_set_cb = smbus_stm32_smbalert_set_cb, + .smbus_smbalert_remove_cb = smbus_stm32_smbalert_remove_cb, +#else + .smbus_smbalert_set_cb = NULL, + .smbus_smbalert_remove_cb = NULL, +#endif /* CONFIG_SMBUS_STM32_SMBALERT */ + .smbus_block_read = NULL, + .smbus_block_pcall = NULL, + .smbus_host_notify_set_cb = NULL, + .smbus_host_notify_remove_cb = NULL, +}; + +#define DT_DRV_COMPAT st_stm32_smbus + +#define SMBUS_STM32_DEVICE_INIT(n) \ + PINCTRL_DT_INST_DEFINE(n); \ + static struct smbus_stm32_config smbus_stm32_config_##n = { \ + .i2c_dev = DEVICE_DT_GET(DT_INST_PROP(n, i2c)), \ + .pcfg = PINCTRL_DT_INST_DEV_CONFIG_GET(n), \ + }; \ + \ + static struct smbus_stm32_data smbus_stm32_data_##n; \ + \ + SMBUS_DEVICE_DT_INST_DEFINE(n, smbus_stm32_init, NULL, &smbus_stm32_data_##n, \ + &smbus_stm32_config_##n, POST_KERNEL, \ + CONFIG_SMBUS_INIT_PRIORITY, &smbus_stm32_api); + +DT_INST_FOREACH_STATUS_OKAY(SMBUS_STM32_DEVICE_INIT) diff --git a/include/zephyr/drivers/i2c/stm32.h b/include/zephyr/drivers/i2c/stm32.h new file mode 100644 index 00000000000..ac943d74664 --- /dev/null +++ b/include/zephyr/drivers/i2c/stm32.h @@ -0,0 +1,31 @@ +/* + * Copyright (c) 2023 SILA Embedded Solutions GmbH + * + * SPDX-License-Identifier: Apache-2.0 + * + */ + +#ifndef ZEPHYR_INCLUDE_DRIVERS_I2C_STM32_H_ +#define ZEPHYR_INCLUDE_DRIVERS_I2C_STM32_H_ + +#include + +enum i2c_stm32_mode { + I2CSTM32MODE_I2C, + I2CSTM32MODE_SMBUSHOST, + I2CSTM32MODE_SMBUSDEVICE, + I2CSTM32MODE_SMBUSDEVICEARP, +}; + +void i2c_stm32_set_smbus_mode(const struct device *dev, enum i2c_stm32_mode mode); + +#ifdef CONFIG_SMBUS_STM32_SMBALERT +typedef void (*i2c_stm32_smbalert_cb_func_t)(const struct device *dev); + +void i2c_stm32_smbalert_set_callback(const struct device *dev, i2c_stm32_smbalert_cb_func_t func, + const struct device *cb_dev); +void i2c_stm32_smbalert_enable(const struct device *dev); +void i2c_stm32_smbalert_disable(const struct device *dev); +#endif /* CONFIG_SMBUS_STM32_SMBALERT */ + +#endif /* ZEPHYR_INCLUDE_DRIVERS_I2C_STM32_H_ */ From 4ba3aedfedce5d6a0f5933479ad25538943862ee Mon Sep 17 00:00:00 2001 From: Benedikt Schmidt Date: Thu, 7 Dec 2023 09:48:20 +0100 Subject: [PATCH 1084/3723] dts: arm: st: add SMBus devices Add SMBus devices to all SoCs which have either a st,stm32-i2c-v1 or st,stm32-i2c-v2. Signed-off-by: Benedikt Schmidt --- dts/arm/st/c0/stm32c0.dtsi | 8 ++++++++ dts/arm/st/f0/stm32f0.dtsi | 8 ++++++++ dts/arm/st/f0/stm32f030X8.dtsi | 8 ++++++++ dts/arm/st/f0/stm32f051.dtsi | 8 ++++++++ dts/arm/st/f0/stm32f070Xb.dtsi | 8 ++++++++ dts/arm/st/f1/stm32f1.dtsi | 16 ++++++++++++++++ dts/arm/st/f2/stm32f2.dtsi | 24 ++++++++++++++++++++++++ dts/arm/st/f3/stm32f3.dtsi | 8 ++++++++ dts/arm/st/f3/stm32f302.dtsi | 16 ++++++++++++++++ dts/arm/st/f3/stm32f302Xc.dtsi | 1 + dts/arm/st/f3/stm32f303.dtsi | 8 ++++++++ dts/arm/st/f3/stm32f373.dtsi | 8 ++++++++ dts/arm/st/f4/stm32f4.dtsi | 24 ++++++++++++++++++++++++ dts/arm/st/f7/stm32f7.dtsi | 24 ++++++++++++++++++++++++ dts/arm/st/f7/stm32f745.dtsi | 8 ++++++++ dts/arm/st/f7/stm32f765.dtsi | 8 ++++++++ dts/arm/st/g0/stm32g0.dtsi | 16 ++++++++++++++++ dts/arm/st/g0/stm32g0b0.dtsi | 8 ++++++++ dts/arm/st/g0/stm32g0b1.dtsi | 8 ++++++++ dts/arm/st/g4/stm32g4.dtsi | 24 ++++++++++++++++++++++++ dts/arm/st/g4/stm32g473.dtsi | 8 ++++++++ dts/arm/st/h5/stm32h5.dtsi | 16 ++++++++++++++++ dts/arm/st/h5/stm32h562.dtsi | 16 ++++++++++++++++ dts/arm/st/h7/stm32h7.dtsi | 32 ++++++++++++++++++++++++++++++++ dts/arm/st/l0/stm32l0.dtsi | 8 ++++++++ dts/arm/st/l0/stm32l051.dtsi | 8 ++++++++ dts/arm/st/l0/stm32l071.dtsi | 16 ++++++++++++++++ dts/arm/st/l1/stm32l1.dtsi | 16 ++++++++++++++++ dts/arm/st/l4/stm32l4.dtsi | 16 ++++++++++++++++ dts/arm/st/l4/stm32l412.dtsi | 8 ++++++++ dts/arm/st/l4/stm32l431.dtsi | 8 ++++++++ dts/arm/st/l4/stm32l433.dtsi | 8 ++++++++ dts/arm/st/l4/stm32l451.dtsi | 16 ++++++++++++++++ dts/arm/st/l4/stm32l471.dtsi | 8 ++++++++ dts/arm/st/l4/stm32l496.dtsi | 8 ++++++++ dts/arm/st/l4/stm32l4p5.dtsi | 16 ++++++++++++++++ dts/arm/st/l5/stm32l5.dtsi | 16 ++++++++++++++++ dts/arm/st/mp1/stm32mp157.dtsi | 8 ++++++++ dts/arm/st/u5/stm32u5.dtsi | 32 ++++++++++++++++++++++++++++++++ dts/arm/st/u5/stm32u595.dtsi | 16 ++++++++++++++++ dts/arm/st/wb/stm32wb.dtsi | 16 ++++++++++++++++ dts/arm/st/wba/stm32wba.dtsi | 16 ++++++++++++++++ dts/arm/st/wl/stm32wl.dtsi | 24 ++++++++++++++++++++++++ 43 files changed, 577 insertions(+) diff --git a/dts/arm/st/c0/stm32c0.dtsi b/dts/arm/st/c0/stm32c0.dtsi index ef71f835ba2..fd37b14b5f9 100644 --- a/dts/arm/st/c0/stm32c0.dtsi +++ b/dts/arm/st/c0/stm32c0.dtsi @@ -343,6 +343,14 @@ io-channels = <&adc1 10>; status = "disabled"; }; + + smbus1: smbus1 { + compatible = "st,stm32-smbus"; + #address-cells = <1>; + #size-cells = <0>; + i2c = <&i2c1>; + status = "disabled"; + }; }; &nvic { diff --git a/dts/arm/st/f0/stm32f0.dtsi b/dts/arm/st/f0/stm32f0.dtsi index 3a7e5dac8ce..0371ac75ac6 100644 --- a/dts/arm/st/f0/stm32f0.dtsi +++ b/dts/arm/st/f0/stm32f0.dtsi @@ -364,6 +364,14 @@ io-channels = <&adc1 17>; status = "disabled"; }; + + smbus1: smbus1 { + compatible = "st,stm32-smbus"; + #address-cells = <1>; + #size-cells = <0>; + i2c = <&i2c1>; + status = "disabled"; + }; }; &nvic { diff --git a/dts/arm/st/f0/stm32f030X8.dtsi b/dts/arm/st/f0/stm32f030X8.dtsi index 775b3b3ebe4..9044da82c0a 100644 --- a/dts/arm/st/f0/stm32f030X8.dtsi +++ b/dts/arm/st/f0/stm32f030X8.dtsi @@ -77,4 +77,12 @@ }; }; }; + + smbus2: smbus2 { + compatible = "st,stm32-smbus"; + #address-cells = <1>; + #size-cells = <0>; + i2c = <&i2c2>; + status = "disabled"; + }; }; diff --git a/dts/arm/st/f0/stm32f051.dtsi b/dts/arm/st/f0/stm32f051.dtsi index 45165c31e2b..51d23418207 100644 --- a/dts/arm/st/f0/stm32f051.dtsi +++ b/dts/arm/st/f0/stm32f051.dtsi @@ -77,4 +77,12 @@ #io-channel-cells = <1>; }; }; + + smbus2: smbus2 { + compatible = "st,stm32-smbus"; + #address-cells = <1>; + #size-cells = <0>; + i2c = <&i2c2>; + status = "disabled"; + }; }; diff --git a/dts/arm/st/f0/stm32f070Xb.dtsi b/dts/arm/st/f0/stm32f070Xb.dtsi index 665945738a8..6962a67ba10 100644 --- a/dts/arm/st/f0/stm32f070Xb.dtsi +++ b/dts/arm/st/f0/stm32f070Xb.dtsi @@ -87,4 +87,12 @@ status = "disabled"; }; }; + + smbus2: smbus2 { + compatible = "st,stm32-smbus"; + #address-cells = <1>; + #size-cells = <0>; + i2c = <&i2c2>; + status = "disabled"; + }; }; diff --git a/dts/arm/st/f1/stm32f1.dtsi b/dts/arm/st/f1/stm32f1.dtsi index d3eb976b566..dc9f140370e 100644 --- a/dts/arm/st/f1/stm32f1.dtsi +++ b/dts/arm/st/f1/stm32f1.dtsi @@ -362,6 +362,22 @@ v25 = <1430>; ntc; }; + + smbus1: smbus1 { + compatible = "st,stm32-smbus"; + #address-cells = <1>; + #size-cells = <0>; + i2c = <&i2c1>; + status = "disabled"; + }; + + smbus2: smbus2 { + compatible = "st,stm32-smbus"; + #address-cells = <1>; + #size-cells = <0>; + i2c = <&i2c2>; + status = "disabled"; + }; }; &nvic { diff --git a/dts/arm/st/f2/stm32f2.dtsi b/dts/arm/st/f2/stm32f2.dtsi index 7cef6f2428a..9c913756919 100644 --- a/dts/arm/st/f2/stm32f2.dtsi +++ b/dts/arm/st/f2/stm32f2.dtsi @@ -713,6 +713,30 @@ compatible = "usb-nop-xceiv"; #phy-cells = <0>; }; + + smbus1: smbus1 { + compatible = "st,stm32-smbus"; + #address-cells = <1>; + #size-cells = <0>; + i2c = <&i2c1>; + status = "disabled"; + }; + + smbus2: smbus2 { + compatible = "st,stm32-smbus"; + #address-cells = <1>; + #size-cells = <0>; + i2c = <&i2c2>; + status = "disabled"; + }; + + smbus3: smbus3 { + compatible = "st,stm32-smbus"; + #address-cells = <1>; + #size-cells = <0>; + i2c = <&i2c3>; + status = "disabled"; + }; }; &nvic { diff --git a/dts/arm/st/f3/stm32f3.dtsi b/dts/arm/st/f3/stm32f3.dtsi index 5f5099a90d6..e4a64b24304 100644 --- a/dts/arm/st/f3/stm32f3.dtsi +++ b/dts/arm/st/f3/stm32f3.dtsi @@ -463,6 +463,14 @@ compatible = "usb-nop-xceiv"; #phy-cells = <0>; }; + + smbus1: smbus1 { + compatible = "st,stm32-smbus"; + #address-cells = <1>; + #size-cells = <0>; + i2c = <&i2c1>; + status = "disabled"; + }; }; &nvic { diff --git a/dts/arm/st/f3/stm32f302.dtsi b/dts/arm/st/f3/stm32f302.dtsi index 59f4b2f7077..5d2c40be20b 100644 --- a/dts/arm/st/f3/stm32f302.dtsi +++ b/dts/arm/st/f3/stm32f302.dtsi @@ -117,4 +117,20 @@ st,adc-sequencer = ; }; }; + + smbus2: smbus2 { + compatible = "st,stm32-smbus"; + #address-cells = <1>; + #size-cells = <0>; + i2c = <&i2c2>; + status = "disabled"; + }; + + smbus3: smbus3 { + compatible = "st,stm32-smbus"; + #address-cells = <1>; + #size-cells = <0>; + i2c = <&i2c3>; + status = "disabled"; + }; }; diff --git a/dts/arm/st/f3/stm32f302Xc.dtsi b/dts/arm/st/f3/stm32f302Xc.dtsi index 4c1de5611ee..8d30e7d31d1 100644 --- a/dts/arm/st/f3/stm32f302Xc.dtsi +++ b/dts/arm/st/f3/stm32f302Xc.dtsi @@ -49,3 +49,4 @@ }; /delete-node/ &i2c3; +/delete-node/ &smbus3; diff --git a/dts/arm/st/f3/stm32f303.dtsi b/dts/arm/st/f3/stm32f303.dtsi index 01e5d4233df..5fa8d11b150 100644 --- a/dts/arm/st/f3/stm32f303.dtsi +++ b/dts/arm/st/f3/stm32f303.dtsi @@ -172,4 +172,12 @@ st,adc-sequencer = ; }; }; + + smbus2: smbus2 { + compatible = "st,stm32-smbus"; + #address-cells = <1>; + #size-cells = <0>; + i2c = <&i2c2>; + status = "disabled"; + }; }; diff --git a/dts/arm/st/f3/stm32f373.dtsi b/dts/arm/st/f3/stm32f373.dtsi index 9c42331c36e..73c4de1eafa 100644 --- a/dts/arm/st/f3/stm32f373.dtsi +++ b/dts/arm/st/f3/stm32f373.dtsi @@ -212,4 +212,12 @@ vbat: vbat { io-channels = <&adc1 18>; }; + + smbus2: smbus2 { + compatible = "st,stm32-smbus"; + #address-cells = <1>; + #size-cells = <0>; + i2c = <&i2c2>; + status = "disabled"; + }; }; diff --git a/dts/arm/st/f4/stm32f4.dtsi b/dts/arm/st/f4/stm32f4.dtsi index 4a03abd609b..010868a00f2 100644 --- a/dts/arm/st/f4/stm32f4.dtsi +++ b/dts/arm/st/f4/stm32f4.dtsi @@ -599,6 +599,30 @@ compatible = "usb-nop-xceiv"; #phy-cells = <0>; }; + + smbus1: smbus1 { + compatible = "st,stm32-smbus"; + #address-cells = <1>; + #size-cells = <0>; + i2c = <&i2c1>; + status = "disabled"; + }; + + smbus2: smbus2 { + compatible = "st,stm32-smbus"; + #address-cells = <1>; + #size-cells = <0>; + i2c = <&i2c2>; + status = "disabled"; + }; + + smbus3: smbus3 { + compatible = "st,stm32-smbus"; + #address-cells = <1>; + #size-cells = <0>; + i2c = <&i2c3>; + status = "disabled"; + }; }; &nvic { diff --git a/dts/arm/st/f7/stm32f7.dtsi b/dts/arm/st/f7/stm32f7.dtsi index f2d336d7b6d..cfd98d4bb4d 100644 --- a/dts/arm/st/f7/stm32f7.dtsi +++ b/dts/arm/st/f7/stm32f7.dtsi @@ -882,6 +882,30 @@ compatible = "usb-nop-xceiv"; #phy-cells = <0>; }; + + smbus1: smbus1 { + compatible = "st,stm32-smbus"; + #address-cells = <1>; + #size-cells = <0>; + i2c = <&i2c2>; + status = "disabled"; + }; + + smbus2: smbus2 { + compatible = "st,stm32-smbus"; + #address-cells = <1>; + #size-cells = <0>; + i2c = <&i2c2>; + status = "disabled"; + }; + + smbus3: smbus3 { + compatible = "st,stm32-smbus"; + #address-cells = <1>; + #size-cells = <0>; + i2c = <&i2c3>; + status = "disabled"; + }; }; &nvic { diff --git a/dts/arm/st/f7/stm32f745.dtsi b/dts/arm/st/f7/stm32f745.dtsi index d63ddd881ba..b4e7b55a948 100644 --- a/dts/arm/st/f7/stm32f745.dtsi +++ b/dts/arm/st/f7/stm32f745.dtsi @@ -88,4 +88,12 @@ status = "disabled"; }; }; + + smbus4: smbus4 { + compatible = "st,stm32-smbus"; + #address-cells = <1>; + #size-cells = <0>; + i2c = <&i2c4>; + status = "disabled"; + }; }; diff --git a/dts/arm/st/f7/stm32f765.dtsi b/dts/arm/st/f7/stm32f765.dtsi index fccf74e7355..642a7a75521 100644 --- a/dts/arm/st/f7/stm32f765.dtsi +++ b/dts/arm/st/f7/stm32f765.dtsi @@ -91,4 +91,12 @@ }; }; + + smbus4: smbus4 { + compatible = "st,stm32-smbus"; + #address-cells = <1>; + #size-cells = <0>; + i2c = <&i2c4>; + status = "disabled"; + }; }; diff --git a/dts/arm/st/g0/stm32g0.dtsi b/dts/arm/st/g0/stm32g0.dtsi index 5f37fc667db..bfa023d027d 100644 --- a/dts/arm/st/g0/stm32g0.dtsi +++ b/dts/arm/st/g0/stm32g0.dtsi @@ -460,6 +460,22 @@ io-channels = <&adc1 14>; status = "disabled"; }; + + smbus1: smbus1 { + compatible = "st,stm32-smbus"; + #address-cells = <1>; + #size-cells = <0>; + i2c = <&i2c1>; + status = "disabled"; + }; + + smbus2: smbus2 { + compatible = "st,stm32-smbus"; + #address-cells = <1>; + #size-cells = <0>; + i2c = <&i2c2>; + status = "disabled"; + }; }; &nvic { diff --git a/dts/arm/st/g0/stm32g0b0.dtsi b/dts/arm/st/g0/stm32g0b0.dtsi index f9c26bb0dde..861c70f2d5b 100644 --- a/dts/arm/st/g0/stm32g0b0.dtsi +++ b/dts/arm/st/g0/stm32g0b0.dtsi @@ -110,4 +110,12 @@ compatible = "usb-nop-xceiv"; #phy-cells = <0>; }; + + smbus3: smbus3 { + compatible = "st,stm32-smbus"; + #address-cells = <1>; + #size-cells = <0>; + i2c = <&i2c3>; + status = "disabled"; + }; }; diff --git a/dts/arm/st/g0/stm32g0b1.dtsi b/dts/arm/st/g0/stm32g0b1.dtsi index b99063d67b8..ead49eb0605 100644 --- a/dts/arm/st/g0/stm32g0b1.dtsi +++ b/dts/arm/st/g0/stm32g0b1.dtsi @@ -143,4 +143,12 @@ compatible = "usb-nop-xceiv"; #phy-cells = <0>; }; + + smbus3: smbus3 { + compatible = "st,stm32-smbus"; + #address-cells = <1>; + #size-cells = <0>; + i2c = <&i2c3>; + status = "disabled"; + }; }; diff --git a/dts/arm/st/g4/stm32g4.dtsi b/dts/arm/st/g4/stm32g4.dtsi index 4cc6c26fc02..1b6632f694f 100644 --- a/dts/arm/st/g4/stm32g4.dtsi +++ b/dts/arm/st/g4/stm32g4.dtsi @@ -691,6 +691,30 @@ compatible = "usb-nop-xceiv"; #phy-cells = <0>; }; + + smbus1: smbus1 { + compatible = "st,stm32-smbus"; + #address-cells = <1>; + #size-cells = <0>; + i2c = <&i2c1>; + status = "disabled"; + }; + + smbus2: smbus2 { + compatible = "st,stm32-smbus"; + #address-cells = <1>; + #size-cells = <0>; + i2c = <&i2c2>; + status = "disabled"; + }; + + smbus3: smbus3 { + compatible = "st,stm32-smbus"; + #address-cells = <1>; + #size-cells = <0>; + i2c = <&i2c3>; + status = "disabled"; + }; }; &nvic { diff --git a/dts/arm/st/g4/stm32g473.dtsi b/dts/arm/st/g4/stm32g473.dtsi index 97565c33e73..930e1639795 100644 --- a/dts/arm/st/g4/stm32g473.dtsi +++ b/dts/arm/st/g4/stm32g473.dtsi @@ -108,4 +108,12 @@ status = "disabled"; }; }; + + smbus4: smbus4 { + compatible = "st,stm32-smbus"; + #address-cells = <1>; + #size-cells = <0>; + i2c = <&i2c4>; + status = "disabled"; + }; }; diff --git a/dts/arm/st/h5/stm32h5.dtsi b/dts/arm/st/h5/stm32h5.dtsi index 43266cfbe2c..310b3384f60 100644 --- a/dts/arm/st/h5/stm32h5.dtsi +++ b/dts/arm/st/h5/stm32h5.dtsi @@ -536,6 +536,22 @@ compatible = "usb-nop-xceiv"; #phy-cells = <0>; }; + + smbus1: smbus1 { + compatible = "st,stm32-smbus"; + #address-cells = <1>; + #size-cells = <0>; + i2c = <&i2c1>; + status = "disabled"; + }; + + smbus2: smbus2 { + compatible = "st,stm32-smbus"; + #address-cells = <1>; + #size-cells = <0>; + i2c = <&i2c2>; + status = "disabled"; + }; }; &nvic { diff --git a/dts/arm/st/h5/stm32h562.dtsi b/dts/arm/st/h5/stm32h562.dtsi index 66ed8d3d927..f7cd14f7213 100644 --- a/dts/arm/st/h5/stm32h562.dtsi +++ b/dts/arm/st/h5/stm32h562.dtsi @@ -308,4 +308,20 @@ status = "disabled"; }; }; + + smbus3: smbus3 { + compatible = "st,stm32-smbus"; + #address-cells = <1>; + #size-cells = <0>; + i2c = <&i2c3>; + status = "disabled"; + }; + + smbus4: smbus4 { + compatible = "st,stm32-smbus"; + #address-cells = <1>; + #size-cells = <0>; + i2c = <&i2c4>; + status = "disabled"; + }; }; diff --git a/dts/arm/st/h7/stm32h7.dtsi b/dts/arm/st/h7/stm32h7.dtsi index ecbe8f419a6..9dcd1353132 100644 --- a/dts/arm/st/h7/stm32h7.dtsi +++ b/dts/arm/st/h7/stm32h7.dtsi @@ -1036,6 +1036,38 @@ vrefint-cal-mv = <3300>; status = "disabled"; }; + + smbus1: smbus1 { + compatible = "st,stm32-smbus"; + #address-cells = <1>; + #size-cells = <0>; + i2c = <&i2c1>; + status = "disabled"; + }; + + smbus2: smbus2 { + compatible = "st,stm32-smbus"; + #address-cells = <1>; + #size-cells = <0>; + i2c = <&i2c2>; + status = "disabled"; + }; + + smbus3: smbus3 { + compatible = "st,stm32-smbus"; + #address-cells = <1>; + #size-cells = <0>; + i2c = <&i2c3>; + status = "disabled"; + }; + + smbus4: smbus4 { + compatible = "st,stm32-smbus"; + #address-cells = <1>; + #size-cells = <0>; + i2c = <&i2c4>; + status = "disabled"; + }; }; &nvic { diff --git a/dts/arm/st/l0/stm32l0.dtsi b/dts/arm/st/l0/stm32l0.dtsi index b05dbff210d..7bb62de1f22 100644 --- a/dts/arm/st/l0/stm32l0.dtsi +++ b/dts/arm/st/l0/stm32l0.dtsi @@ -351,6 +351,14 @@ io-channels = <&adc1 17>; status = "disabled"; }; + + smbus1: smbus1 { + compatible = "st,stm32-smbus"; + #address-cells = <1>; + #size-cells = <0>; + i2c = <&i2c1>; + status = "disabled"; + }; }; &nvic { diff --git a/dts/arm/st/l0/stm32l051.dtsi b/dts/arm/st/l0/stm32l051.dtsi index e6209dc531b..9c5bfa1b028 100644 --- a/dts/arm/st/l0/stm32l051.dtsi +++ b/dts/arm/st/l0/stm32l051.dtsi @@ -73,4 +73,12 @@ reg = <0x08080000 DT_SIZE_K(2)>; }; }; + + smbus2: smbus2 { + compatible = "st,stm32-smbus"; + #address-cells = <1>; + #size-cells = <0>; + i2c = <&i2c2>; + status = "disabled"; + }; }; diff --git a/dts/arm/st/l0/stm32l071.dtsi b/dts/arm/st/l0/stm32l071.dtsi index 56d88c5bd51..95a8fdc8424 100644 --- a/dts/arm/st/l0/stm32l071.dtsi +++ b/dts/arm/st/l0/stm32l071.dtsi @@ -161,4 +161,20 @@ reg = <0x08080000 DT_SIZE_K(6)>; }; }; + + smbus2: smbus2 { + compatible = "st,stm32-smbus"; + #address-cells = <1>; + #size-cells = <0>; + i2c = <&i2c2>; + status = "disabled"; + }; + + smbus3: smbus3 { + compatible = "st,stm32-smbus"; + #address-cells = <1>; + #size-cells = <0>; + i2c = <&i2c3>; + status = "disabled"; + }; }; diff --git a/dts/arm/st/l1/stm32l1.dtsi b/dts/arm/st/l1/stm32l1.dtsi index 2f08501a2c1..53dbd64492d 100644 --- a/dts/arm/st/l1/stm32l1.dtsi +++ b/dts/arm/st/l1/stm32l1.dtsi @@ -482,6 +482,22 @@ io-channels = <&adc1 17>; status = "disabled"; }; + + smbus1: smbus1 { + compatible = "st,stm32-smbus"; + #address-cells = <1>; + #size-cells = <0>; + i2c = <&i2c1>; + status = "disabled"; + }; + + smbus2: smbus2 { + compatible = "st,stm32-smbus"; + #address-cells = <1>; + #size-cells = <0>; + i2c = <&i2c2>; + status = "disabled"; + }; }; &nvic { diff --git a/dts/arm/st/l4/stm32l4.dtsi b/dts/arm/st/l4/stm32l4.dtsi index f2b8c1a2ff6..7dcabdf877c 100644 --- a/dts/arm/st/l4/stm32l4.dtsi +++ b/dts/arm/st/l4/stm32l4.dtsi @@ -493,6 +493,22 @@ io-channels = <&adc1 18>; status = "disabled"; }; + + smbus1: smbus1 { + compatible = "st,stm32-smbus"; + #address-cells = <1>; + #size-cells = <0>; + i2c = <&i2c1>; + status = "disabled"; + }; + + smbus3: smbus3 { + compatible = "st,stm32-smbus"; + #address-cells = <1>; + #size-cells = <0>; + i2c = <&i2c3>; + status = "disabled"; + }; }; &nvic { diff --git a/dts/arm/st/l4/stm32l412.dtsi b/dts/arm/st/l4/stm32l412.dtsi index f516ccdc57c..152340889fd 100644 --- a/dts/arm/st/l4/stm32l412.dtsi +++ b/dts/arm/st/l4/stm32l412.dtsi @@ -74,4 +74,12 @@ compatible = "usb-nop-xceiv"; #phy-cells = <0>; }; + + smbus2: smbus2 { + compatible = "st,stm32-smbus"; + #address-cells = <1>; + #size-cells = <0>; + i2c = <&i2c2>; + status = "disabled"; + }; }; diff --git a/dts/arm/st/l4/stm32l431.dtsi b/dts/arm/st/l4/stm32l431.dtsi index 9a9892a0f4d..7fb1d7b4bd4 100644 --- a/dts/arm/st/l4/stm32l431.dtsi +++ b/dts/arm/st/l4/stm32l431.dtsi @@ -129,4 +129,12 @@ status = "disabled"; }; }; + + smbus2: smbus2 { + compatible = "st,stm32-smbus"; + #address-cells = <1>; + #size-cells = <0>; + i2c = <&i2c2>; + status = "disabled"; + }; }; diff --git a/dts/arm/st/l4/stm32l433.dtsi b/dts/arm/st/l4/stm32l433.dtsi index c754097bec9..c0e1f0e18be 100644 --- a/dts/arm/st/l4/stm32l433.dtsi +++ b/dts/arm/st/l4/stm32l433.dtsi @@ -68,4 +68,12 @@ status = "disabled"; }; }; + + smbus2: smbus2 { + compatible = "st,stm32-smbus"; + #address-cells = <1>; + #size-cells = <0>; + i2c = <&i2c2>; + status = "disabled"; + }; }; diff --git a/dts/arm/st/l4/stm32l451.dtsi b/dts/arm/st/l4/stm32l451.dtsi index b566db4336a..c22e4ef0820 100644 --- a/dts/arm/st/l4/stm32l451.dtsi +++ b/dts/arm/st/l4/stm32l451.dtsi @@ -162,4 +162,20 @@ }; }; }; + + smbus2: smbus2 { + compatible = "st,stm32-smbus"; + #address-cells = <1>; + #size-cells = <0>; + i2c = <&i2c2>; + status = "disabled"; + }; + + smbus4: smbus4 { + compatible = "st,stm32-smbus"; + #address-cells = <1>; + #size-cells = <0>; + i2c = <&i2c4>; + status = "disabled"; + }; }; diff --git a/dts/arm/st/l4/stm32l471.dtsi b/dts/arm/st/l4/stm32l471.dtsi index c1f5b5978a0..53a7fe28f02 100644 --- a/dts/arm/st/l4/stm32l471.dtsi +++ b/dts/arm/st/l4/stm32l471.dtsi @@ -274,4 +274,12 @@ die_temp: dietemp { ts-cal2-temp = <110>; }; + + smbus2: smbus2 { + compatible = "st,stm32-smbus"; + #address-cells = <1>; + #size-cells = <0>; + i2c = <&i2c2>; + status = "disabled"; + }; }; diff --git a/dts/arm/st/l4/stm32l496.dtsi b/dts/arm/st/l4/stm32l496.dtsi index c11eba47796..4bba5f13ecc 100644 --- a/dts/arm/st/l4/stm32l496.dtsi +++ b/dts/arm/st/l4/stm32l496.dtsi @@ -82,4 +82,12 @@ die_temp: dietemp { ts-cal2-temp = <130>; }; + + smbus4: smbus4 { + compatible = "st,stm32-smbus"; + #address-cells = <1>; + #size-cells = <0>; + i2c = <&i2c4>; + status = "disabled"; + }; }; diff --git a/dts/arm/st/l4/stm32l4p5.dtsi b/dts/arm/st/l4/stm32l4p5.dtsi index 03973dcf077..648fa936a5f 100644 --- a/dts/arm/st/l4/stm32l4p5.dtsi +++ b/dts/arm/st/l4/stm32l4p5.dtsi @@ -398,4 +398,20 @@ compatible = "usb-nop-xceiv"; #phy-cells = <0>; }; + + smbus2: smbus2 { + compatible = "st,stm32-smbus"; + #address-cells = <1>; + #size-cells = <0>; + i2c = <&i2c2>; + status = "disabled"; + }; + + smbus4: smbus4 { + compatible = "st,stm32-smbus"; + #address-cells = <1>; + #size-cells = <0>; + i2c = <&i2c4>; + status = "disabled"; + }; }; diff --git a/dts/arm/st/l5/stm32l5.dtsi b/dts/arm/st/l5/stm32l5.dtsi index 3886de37631..f9c37b33cd8 100644 --- a/dts/arm/st/l5/stm32l5.dtsi +++ b/dts/arm/st/l5/stm32l5.dtsi @@ -734,6 +734,22 @@ #phy-cells = <0>; }; + smbus1: smbus1 { + compatible = "st,stm32-smbus"; + #address-cells = <1>; + #size-cells = <0>; + i2c = <&i2c1>; + status = "disabled"; + }; + + smbus2: smbus2 { + compatible = "st,stm32-smbus"; + #address-cells = <1>; + #size-cells = <0>; + i2c = <&i2c2>; + status = "disabled"; + }; + }; &nvic { diff --git a/dts/arm/st/mp1/stm32mp157.dtsi b/dts/arm/st/mp1/stm32mp157.dtsi index 1877301b9f2..2eec4faa4da 100644 --- a/dts/arm/st/mp1/stm32mp157.dtsi +++ b/dts/arm/st/mp1/stm32mp157.dtsi @@ -398,6 +398,14 @@ status = "disabled"; }; }; + + smbus5: smbus5 { + compatible = "st,stm32-smbus"; + #address-cells = <1>; + #size-cells = <0>; + i2c = <&i2c5>; + status = "disabled"; + }; }; &nvic { diff --git a/dts/arm/st/u5/stm32u5.dtsi b/dts/arm/st/u5/stm32u5.dtsi index 7bfe52780b2..b97e509c831 100644 --- a/dts/arm/st/u5/stm32u5.dtsi +++ b/dts/arm/st/u5/stm32u5.dtsi @@ -883,6 +883,38 @@ io-channels = <&adc4 14>; status = "disabled"; }; + + smbus1: smbus1 { + compatible = "st,stm32-smbus"; + #address-cells = <1>; + #size-cells = <0>; + i2c = <&i2c1>; + status = "disabled"; + }; + + smbus2: smbus2 { + compatible = "st,stm32-smbus"; + #address-cells = <1>; + #size-cells = <0>; + i2c = <&i2c2>; + status = "disabled"; + }; + + smbus3: smbus3 { + compatible = "st,stm32-smbus"; + #address-cells = <1>; + #size-cells = <0>; + i2c = <&i2c3>; + status = "disabled"; + }; + + smbus4: smbus4 { + compatible = "st,stm32-smbus"; + #address-cells = <1>; + #size-cells = <0>; + i2c = <&i2c4>; + status = "disabled"; + }; }; &nvic { diff --git a/dts/arm/st/u5/stm32u595.dtsi b/dts/arm/st/u5/stm32u595.dtsi index db489205f95..3bc16eb120e 100644 --- a/dts/arm/st/u5/stm32u595.dtsi +++ b/dts/arm/st/u5/stm32u595.dtsi @@ -97,4 +97,20 @@ st,adc-sequencer = ; }; }; + + smbus5: smbus5 { + compatible = "st,stm32-smbus"; + #address-cells = <1>; + #size-cells = <0>; + i2c = <&i2c5>; + status = "disabled"; + }; + + smbus6: smbus6 { + compatible = "st,stm32-smbus"; + #address-cells = <1>; + #size-cells = <0>; + i2c = <&i2c6>; + status = "disabled"; + }; }; diff --git a/dts/arm/st/wb/stm32wb.dtsi b/dts/arm/st/wb/stm32wb.dtsi index f6a1c785b86..d76f2f243f7 100644 --- a/dts/arm/st/wb/stm32wb.dtsi +++ b/dts/arm/st/wb/stm32wb.dtsi @@ -547,6 +547,22 @@ clocks = <&rcc STM32_CLOCK_BUS_AHB3 0x00100000>, <&rcc STM32_SRC_LSE RFWKP_SEL(1)>; }; + + smbus1: smbus1 { + compatible = "st,stm32-smbus"; + #address-cells = <1>; + #size-cells = <0>; + i2c = <&i2c1>; + status = "disabled"; + }; + + smbus3: smbus3 { + compatible = "st,stm32-smbus"; + #address-cells = <1>; + #size-cells = <0>; + i2c = <&i2c3>; + status = "disabled"; + }; }; &nvic { diff --git a/dts/arm/st/wba/stm32wba.dtsi b/dts/arm/st/wba/stm32wba.dtsi index 5e0f67625ee..d9d718a9898 100644 --- a/dts/arm/st/wba/stm32wba.dtsi +++ b/dts/arm/st/wba/stm32wba.dtsi @@ -451,6 +451,22 @@ status = "disabled"; }; }; + + smbus1: smbus1 { + compatible = "st,stm32-smbus"; + #address-cells = <1>; + #size-cells = <0>; + i2c = <&i2c1>; + status = "disabled"; + }; + + smbus3: smbus3 { + compatible = "st,stm32-smbus"; + #address-cells = <1>; + #size-cells = <0>; + i2c = <&i2c3>; + status = "disabled"; + }; }; &nvic { diff --git a/dts/arm/st/wl/stm32wl.dtsi b/dts/arm/st/wl/stm32wl.dtsi index feeb013af6e..3dc4b3fcc3f 100644 --- a/dts/arm/st/wl/stm32wl.dtsi +++ b/dts/arm/st/wl/stm32wl.dtsi @@ -523,6 +523,30 @@ io-channels = <&adc1 14>; status = "disabled"; }; + + smbus1: smbus1 { + compatible = "st,stm32-smbus"; + #address-cells = <1>; + #size-cells = <0>; + i2c = <&i2c1>; + status = "disabled"; + }; + + smbus2: smbus2 { + compatible = "st,stm32-smbus"; + #address-cells = <1>; + #size-cells = <0>; + i2c = <&i2c2>; + status = "disabled"; + }; + + smbus3: smbus3 { + compatible = "st,stm32-smbus"; + #address-cells = <1>; + #size-cells = <0>; + i2c = <&i2c3>; + status = "disabled"; + }; }; &nvic { From 995824ae8047ea8e632203212f508df12fa8c5e0 Mon Sep 17 00:00:00 2001 From: Benedikt Schmidt Date: Thu, 7 Dec 2023 11:00:43 +0100 Subject: [PATCH 1085/3723] tests: drivers: smbus: enable SMBus Enable SMBus for the smbus_emul test. Signed-off-by: Benedikt Schmidt --- tests/drivers/smbus/smbus_emul/prj.conf | 2 ++ tests/drivers/smbus/smbus_emul/src/smbus.c | 2 -- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/tests/drivers/smbus/smbus_emul/prj.conf b/tests/drivers/smbus/smbus_emul/prj.conf index 996a530cd41..99e5c1f89d5 100644 --- a/tests/drivers/smbus/smbus_emul/prj.conf +++ b/tests/drivers/smbus/smbus_emul/prj.conf @@ -1,3 +1,5 @@ CONFIG_ZTEST=y CONFIG_LOG=y CONFIG_ENTROPY_GENERATOR=y +CONFIG_SMBUS=y +CONFIG_SMBUS_LOG_LEVEL_DBG=y diff --git a/tests/drivers/smbus/smbus_emul/src/smbus.c b/tests/drivers/smbus/smbus_emul/src/smbus.c index 1d2a3b5200e..d42a22d1a23 100644 --- a/tests/drivers/smbus/smbus_emul/src/smbus.c +++ b/tests/drivers/smbus/smbus_emul/src/smbus.c @@ -14,8 +14,6 @@ #include "emul.h" -#define CONFIG_SMBUS_LOG_LEVEL LOG_LEVEL_DBG - #define PERIPH_ADDR 0x10 static uint8_t mock_sys_in8(io_port_t port) From 8232dddf1c45fa3ddf8de9be2001a3eb3cd9e45c Mon Sep 17 00:00:00 2001 From: Andriy Gelman Date: Mon, 4 Dec 2023 09:40:49 -0500 Subject: [PATCH 1086/3723] shell: telnet: Don't close the connection on EAGAIN error EAGAIN error is returned if the tcp window size is full. Retry sending the packet instead of closing the connection if this error occurs. Also the full payload may not be sent in a single call to net_context_send(). Keep track of the number of bytes remaining and try to send the full payload. Signed-off-by: Andriy Gelman --- subsys/shell/backends/shell_telnet.c | 57 ++++++++++++++++++++-------- 1 file changed, 42 insertions(+), 15 deletions(-) diff --git a/subsys/shell/backends/shell_telnet.c b/subsys/shell/backends/shell_telnet.c index a4dab627299..cd6f1184773 100644 --- a/subsys/shell/backends/shell_telnet.c +++ b/subsys/shell/backends/shell_telnet.c @@ -33,6 +33,8 @@ struct shell_telnet *sh_telnet; #define TELNET_MIN_COMMAND_LEN 2 #define TELNET_WILL_DO_COMMAND_LEN 3 +#define TELNET_RETRY_SEND_SLEEP_MS 50 + /* Basic TELNET implementation. */ static void telnet_end_client_connection(void) @@ -64,17 +66,29 @@ static void telnet_sent_cb(struct net_context *client, static void telnet_command_send_reply(uint8_t *msg, uint16_t len) { - int err; - if (sh_telnet->client_ctx == NULL) { return; } - err = net_context_send(sh_telnet->client_ctx, msg, len, telnet_sent_cb, - K_FOREVER, NULL); - if (err < 0) { - LOG_ERR("Failed to send command %d, shutting down", err); - telnet_end_client_connection(); + while (len > 0) { + int ret; + + ret = net_context_send(sh_telnet->client_ctx, msg, len, telnet_sent_cb, + K_FOREVER, NULL); + + if (ret == -EAGAIN) { + k_sleep(K_MSEC(TELNET_RETRY_SEND_SLEEP_MS)); + continue; + } + + if (ret < 0) { + LOG_ERR("Failed to send command %d, shutting down", ret); + telnet_end_client_connection(); + break; + } + + msg += ret; + len -= ret; } } @@ -175,7 +189,9 @@ static void telnet_reply_command(struct telnet_simple_command *cmd) static int telnet_send(void) { - int err; + int ret; + uint8_t *msg = sh_telnet->line_out.buf; + uint16_t len = sh_telnet->line_out.len; if (sh_telnet->line_out.len == 0) { return 0; @@ -185,13 +201,24 @@ static int telnet_send(void) return -ENOTCONN; } - err = net_context_send(sh_telnet->client_ctx, sh_telnet->line_out.buf, - sh_telnet->line_out.len, telnet_sent_cb, - K_FOREVER, NULL); - if (err < 0) { - LOG_ERR("Failed to send %d, shutting down", err); - telnet_end_client_connection(); - return err; + while (len > 0) { + ret = net_context_send(sh_telnet->client_ctx, msg, + len, telnet_sent_cb, + K_FOREVER, NULL); + + if (ret == -EAGAIN) { + k_sleep(K_MSEC(TELNET_RETRY_SEND_SLEEP_MS)); + continue; + } + + if (ret < 0) { + LOG_ERR("Failed to send %d, shutting down", ret); + telnet_end_client_connection(); + return ret; + } + + msg += ret; + len -= ret; } /* We reinitialize the line buffer */ From 7382d7052b5d67063dc2ab121d9c9142e0ee024d Mon Sep 17 00:00:00 2001 From: Flavio Ceolin Date: Fri, 8 Dec 2023 15:21:59 -0800 Subject: [PATCH 1087/3723] xtensa: mmu: Fix partition permission The ring field in the pte mapping a memory partition should be based in the partition attribute and not in the domain asid that is used only to set the ASID (in RASID) position for user ring. Signed-off-by: Flavio Ceolin --- arch/xtensa/core/ptables.c | 3 ++- include/zephyr/arch/xtensa/xtensa_mmu.h | 10 ++++++++-- 2 files changed, 10 insertions(+), 3 deletions(-) diff --git a/arch/xtensa/core/ptables.c b/arch/xtensa/core/ptables.c index 17950114544..8900f92b4e9 100644 --- a/arch/xtensa/core/ptables.c +++ b/arch/xtensa/core/ptables.c @@ -928,8 +928,9 @@ int arch_mem_domain_partition_remove(struct k_mem_domain *domain, int arch_mem_domain_partition_add(struct k_mem_domain *domain, uint32_t partition_id) { - uint32_t ring = domain->arch.asid == 0 ? Z_XTENSA_KERNEL_RING : Z_XTENSA_USER_RING; struct k_mem_partition *partition = &domain->partitions[partition_id]; + uint32_t ring = K_MEM_PARTITION_IS_USER(partition->attr) ? Z_XTENSA_USER_RING : + Z_XTENSA_KERNEL_RING; return update_region(domain->arch.ptables, partition->start, partition->size, ring, partition->attr, 0); diff --git a/include/zephyr/arch/xtensa/xtensa_mmu.h b/include/zephyr/arch/xtensa/xtensa_mmu.h index aa00f935a8a..5d72f884a03 100644 --- a/include/zephyr/arch/xtensa/xtensa_mmu.h +++ b/include/zephyr/arch/xtensa/xtensa_mmu.h @@ -14,16 +14,22 @@ #define Z_XTENSA_MMU_CACHED_WB BIT(2) #define Z_XTENSA_MMU_CACHED_WT BIT(3) +/* This bit is used in the HW. We just use it to know + * which ring pte entries should use. + */ +#define Z_XTENSA_MMU_USER BIT(4) + #define K_MEM_PARTITION_IS_EXECUTABLE(attr) (((attr) & Z_XTENSA_MMU_X) != 0) #define K_MEM_PARTITION_IS_WRITABLE(attr) (((attr) & Z_XENSA_MMU_W) != 0) +#define K_MEM_PARTITION_IS_USER(attr) (((attr) & Z_XTENSA_MMU_USER) != 0) /* Read-Write access permission attributes */ #define K_MEM_PARTITION_P_RW_U_RW ((k_mem_partition_attr_t) \ - {Z_XTENSA_MMU_W}) + {Z_XTENSA_MMU_W | Z_XTENSA_MMU_USER}) #define K_MEM_PARTITION_P_RW_U_NA ((k_mem_partition_attr_t) \ {0}) #define K_MEM_PARTITION_P_RO_U_RO ((k_mem_partition_attr_t) \ - {0}) + {Z_XTENSA_MMU_USER}) #define K_MEM_PARTITION_P_RO_U_NA ((k_mem_partition_attr_t) \ {0}) #define K_MEM_PARTITION_P_NA_U_NA ((k_mem_partition_attr_t) \ From a19d415c35001b3e34f9888a9b63712fc64b2286 Mon Sep 17 00:00:00 2001 From: Flavio Ceolin Date: Fri, 8 Dec 2023 17:06:56 -0800 Subject: [PATCH 1088/3723] xtensa: mmu: Fix xtensa_ptevaddr_get We use ptevaddr_get to know the address the page table is set. It happens that for this use, we should just use the ptebase field of ptevaddr register. Signed-off-by: Flavio Ceolin --- arch/xtensa/core/include/xtensa_mmu_priv.h | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/arch/xtensa/core/include/xtensa_mmu_priv.h b/arch/xtensa/core/include/xtensa_mmu_priv.h index 7b1030786f4..08bcb1e5a2e 100644 --- a/arch/xtensa/core/include/xtensa_mmu_priv.h +++ b/arch/xtensa/core/include/xtensa_mmu_priv.h @@ -27,6 +27,8 @@ #define Z_XTENSA_PTE_RING_MASK 0x00000030U #define Z_XTENSA_PTE_RING_SHIFT 4U +#define Z_XTENSA_PTEBASE_MASK 0xFFC00000 + #define Z_XTENSA_PTE(paddr, ring, attr) \ (((paddr) & Z_XTENSA_PTE_PPN_MASK) | \ (((ring) << Z_XTENSA_PTE_RING_SHIFT) & Z_XTENSA_PTE_RING_MASK) | \ @@ -271,7 +273,7 @@ static ALWAYS_INLINE void *xtensa_ptevaddr_get(void) __asm__ volatile("rsr.ptevaddr %0" : "=a" (ptables)); - return (void *)ptables; + return (void *)(ptables & Z_XTENSA_PTEBASE_MASK); } /* * The following functions are helpful when debugging. From 0a7251e365af14acc40aadb5cf745bec2ed84618 Mon Sep 17 00:00:00 2001 From: Flavio Ceolin Date: Fri, 8 Dec 2023 17:13:42 -0800 Subject: [PATCH 1089/3723] xtensa: mmu: Fix tlb shootdown Fix the way we read the current l1 page table set in the mmu. We use it check if the current page table is different from the running thread. Signed-off-by: Flavio Ceolin --- arch/xtensa/core/ptables.c | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) diff --git a/arch/xtensa/core/ptables.c b/arch/xtensa/core/ptables.c index 8900f92b4e9..2d26d83944f 100644 --- a/arch/xtensa/core/ptables.c +++ b/arch/xtensa/core/ptables.c @@ -690,19 +690,21 @@ void z_xtensa_mmu_tlb_shootdown(void) * is different from the currently used one. */ if ((thread->base.user_options & K_USER) == K_USER) { - uint32_t ptevaddr_entry, ptevaddr, thread_ptables; + uint32_t ptevaddr_entry, ptevaddr, + thread_ptables, current_ptables; /* Need to read the currently used L1 page table. * We know that L1 page table is always mapped at way * MMU_PTE_WAY, so we can skip the probing step by * generating the query entry directly. */ - ptevaddr_entry = (uint32_t)xtensa_ptevaddr_get() | Z_XTENSA_MMU_PTE_WAY; - ptevaddr = xtensa_dtlb_paddr_read(ptevaddr_entry); - + ptevaddr = (uint32_t)xtensa_ptevaddr_get(); + ptevaddr_entry = Z_XTENSA_PTE_ENTRY_VADDR(ptevaddr, ptevaddr) + | Z_XTENSA_MMU_PTE_WAY; + current_ptables = xtensa_dtlb_paddr_read(ptevaddr_entry); thread_ptables = (uint32_t)thread->arch.ptables; - if (thread_ptables != ptevaddr) { + if (thread_ptables != current_ptables) { /* Need to remap the thread page tables if the ones * indicated by the current thread are different * than the current mapped page table. From 2f230e89036d9595b1719118a7695db488f3ba14 Mon Sep 17 00:00:00 2001 From: Rodrigo Peixoto Date: Thu, 26 Oct 2023 10:30:16 -0300 Subject: [PATCH 1090/3723] samples: zbus: benchmark: add msg subscriber to benchmark The benchmark sample did not contemplate message subscribers. It adds the msg subscribers and improves the organization of the project. Signed-off-by: Rodrigo Peixoto --- samples/subsys/zbus/benchmark/CMakeLists.txt | 14 +- samples/subsys/zbus/benchmark/Kconfig | 23 ++- samples/subsys/zbus/benchmark/README.rst | 158 +++++++-------- .../zbus/benchmark/benchmark_256KB.robot | 49 +++-- samples/subsys/zbus/benchmark/prj.conf | 2 + samples/subsys/zbus/benchmark/sample.yaml | 30 ++- samples/subsys/zbus/benchmark/src/benchmark.c | 180 +++--------------- samples/subsys/zbus/benchmark/src/lis.c | 48 +++++ samples/subsys/zbus/benchmark/src/msg_sub.c | 57 ++++++ samples/subsys/zbus/benchmark/src/sub.c | 71 +++++++ 10 files changed, 362 insertions(+), 270 deletions(-) create mode 100644 samples/subsys/zbus/benchmark/src/lis.c create mode 100644 samples/subsys/zbus/benchmark/src/msg_sub.c create mode 100644 samples/subsys/zbus/benchmark/src/sub.c diff --git a/samples/subsys/zbus/benchmark/CMakeLists.txt b/samples/subsys/zbus/benchmark/CMakeLists.txt index e66cd1e4ace..548225af792 100644 --- a/samples/subsys/zbus/benchmark/CMakeLists.txt +++ b/samples/subsys/zbus/benchmark/CMakeLists.txt @@ -4,5 +4,17 @@ cmake_minimum_required(VERSION 3.20.0) find_package(Zephyr REQUIRED HINTS $ENV{ZEPHYR_BASE}) project(benchmark) -FILE(GLOB app_sources src/*.c) +set(app_sources src/benchmark.c) + +if(CONFIG_BM_LISTENERS) + list(APPEND app_sources src/lis.c) + +elseif(CONFIG_BM_SUBSCRIBERS) + list(APPEND app_sources src/sub.c) + +elseif(CONFIG_BM_MSG_SUBSCRIBERS) + list(APPEND app_sources src/msg_sub.c) + +endif() + target_sources(app PRIVATE ${app_sources}) diff --git a/samples/subsys/zbus/benchmark/Kconfig b/samples/subsys/zbus/benchmark/Kconfig index 2fdeb3ff76b..3a21c2fd6f8 100644 --- a/samples/subsys/zbus/benchmark/Kconfig +++ b/samples/subsys/zbus/benchmark/Kconfig @@ -9,8 +9,25 @@ config BM_ONE_TO int "Number of consumers" default 8 -config BM_ASYNC - bool "Consuming in asynchronous mode" - default false +choice BM_OBSERVER_TYPE + bool "Observer type to be used in the benchmark" + +config BM_LISTENERS + bool "Synchronous using listeners" + +config BM_SUBSCRIBERS + bool "Asynchronous using subscribers" + +config BM_MSG_SUBSCRIBERS + bool "Asynchronous using message subscribers" + select ZBUS_MSG_SUBSCRIBER + +endchoice + +config BM_FAIRPLAY + bool "Force a comparison with same actions" + help + Forces a message copy on the listeners and subscribers to behave equivalent to + message subscribers. source "Kconfig.zephyr" diff --git a/samples/subsys/zbus/benchmark/README.rst b/samples/subsys/zbus/benchmark/README.rst index 4dd14607623..52a7d864481 100644 --- a/samples/subsys/zbus/benchmark/README.rst +++ b/samples/subsys/zbus/benchmark/README.rst @@ -2,9 +2,10 @@ :name: Benchmarking :relevant-api: zbus_apis - Measure the time for sending 256KB from a producer to X consumers. + Measure the time for sending 256KB from a producer to N consumers. -This sample implements an application to measure the time for sending 256KB from the producer to the consumers. +This sample implements an application to measure the time for sending 256KB from the producer to the +consumers. Building and Running ******************** @@ -13,14 +14,16 @@ Building and Running :zephyr-app: samples/subsys/zbus/dyn_channel :host-os: unix :board: qemu_cortex_m3 - :gen-args: -DCONFIG_BM_MESSAGE_SIZE=1 -DCONFIG_BM_ONE_TO=1 -DCONFIG_BM_ASYNC=y + :gen-args: -DCONFIG_BM_MESSAGE_SIZE=512 -DCONFIG_BM_ONE_TO=1 -DCONFIG_BM_LISTENERS=y :goals: build run Notice we have the following parameters: -* **CONFIG_BM_MESSAGE_SIZE** the size of the message to be transferred (1, 2, 4, 8, 16, 32, 64, 128, or 256); -* **CONFIG_BM_ONE_TO** number of consumers to send (1, 2, 4, or 8); -* **CONFIG_BM_ASYNC** if the execution must be asynchronous or synchronous. Use y to async and n to sync; +* **CONFIG_BM_MESSAGE_SIZE** the size of the message to be transferred (2 to 4096 bytes); +* **CONFIG_BM_ONE_TO** number of consumers to send (1 up to 8 consumers); +* **CONFIG_BM_LISTENERS** Use y to perform the benchmark listeners; +* **CONFIG_BM_SUBSCRIBERS** Use y to perform the benchmark subscribers; +* **CONFIG_BM_MSG_SUBSCRIBERS** Use y to perform the benchmark message subscribers. Sample Output ============= @@ -28,13 +31,13 @@ The result would be something like: .. code-block:: console - *** Booting Zephyr OS build zephyr-v3.3.0 *** - I: Benchmark 1 to 1: Dynamic memory, SYNC transmission and message size 1 - I: Bytes sent = 262144, received = 262144 - I: Average data rate: 0.6MB/s - I: Duration: 4.72020167s + *** Booting Zephyr OS build zephyr-vX.Y.Z *** + I: Benchmark 1 to 1 using LISTENERS to transmit with message size: 512 bytes + I: Bytes sent = 262144, received = 262144 + I: Average data rate: 12.62MB/s + I: Duration: 0.019805908s - @4072020167 + @19805 Running the benchmark automatically @@ -43,91 +46,64 @@ Running the benchmark automatically There is a `Robot framework `_ script called ``benchmark_256KB.robot`` which runs all the input combinations as the complete benchmark. The resulting file, ``zbus_dyn_benchmark_256KB.csv`` is generated in the project root folder. It takes a long time to execute. In the CSV file, we have the following columns: -+------------+---------------------+--------------------------+---------------+-------------+-------------+ -| Style | Number of consumers | Message size (bytes) | Duration (ns) | RAM (bytes) | ROM (bytes) | -+============+=====================+==========================+===============+=============+=============+ -| SYNC/ASYNC | 1,2,4,8 | 1,2,4,8,16,32,64,128,256 | float | int | int | -+------------+---------------------+--------------------------+---------------+-------------+-------------+ ++-----------------+---------------------+--------------------------+---------------+-------------+-------------+ +| Observer type | Number of consumers | Message size (bytes) | Duration (ns) | RAM (bytes) | ROM (bytes) | ++=================+=====================+==========================+===============+=============+=============+ +| LIS/SUB/MSG_SUB | 1,4,8 | 2,8,32,128,512 | float | int | int | ++-----------------+---------------------+--------------------------+---------------+-------------+-------------+ The complete benchmark command using Robot framework is: .. code-block:: console - robot --variable serial_port:/dev/ttyACM0 --variable board:nrf52833dk_nrf52833 -d /tmp/benchmark_out benchmark_256KB.robot + robot --variable serial_port:/dev/ttyACM0 --variable board:nrf52dk_nrf52832 -d /tmp/benchmark_out benchmark_256KB.robot -An example of execution using the ``nrf52833dk_nrf52833`` board would generate a file like this: +An example of execution using the ``nrf52dk_nrf52832`` board would generate a file like this: .. code-block:: - SYNC,1,1,2312815348.3333335,7286,23752 - SYNC,1,2,1172444661.3333333,7287,23760 - SYNC,1,4,602284749.6666666,7289,23768 - SYNC,1,8,323750814.0,7293,23772 - SYNC,1,16,175120035.66666666,7301,23776 - SYNC,1,32,103942871.33333333,7317,23776 - SYNC,1,64,68318685.0,7349,23776 - SYNC,1,128,50567627.333333336,7477,23776 - SYNC,1,256,41656494.0,7733,23776 - SYNC,2,1,1277842204.3333333,7298,23768 - SYNC,2,2,647094726.6666666,7299,23776 - SYNC,2,4,329559326.3333333,7301,23784 - SYNC,2,8,170979817.66666666,7305,23796 - SYNC,2,16,95174153.66666667,7313,23792 - SYNC,2,32,55786133.0,7329,23792 - SYNC,2,64,36173502.333333336,7361,23792 - SYNC,2,128,26326497.666666668,7489,23792 - SYNC,2,256,21280924.333333332,7745,23792 - SYNC,4,1,745513916.0,7322,23800 - SYNC,4,2,374755859.6666667,7323,23808 - SYNC,4,4,191497802.66666666,7325,23816 - SYNC,4,8,101399739.66666667,7329,23820 - SYNC,4,16,54026286.0,7337,23824 - SYNC,4,32,31097412.0,7353,23824 - SYNC,4,64,19643148.333333332,7385,23824 - SYNC,4,128,13936360.333333334,7513,23824 - SYNC,4,256,11047363.333333334,7769,23824 - SYNC,8,1,477518717.3333333,7370,23864 - SYNC,8,2,240773518.66666666,7371,23872 - SYNC,8,4,121897379.33333333,7373,23880 - SYNC,8,8,64015706.333333336,7377,23884 - SYNC,8,16,33681234.0,7385,23888 - SYNC,8,32,18880208.333333332,7401,23888 - SYNC,8,64,11505127.0,7433,23888 - SYNC,8,128,7781982.333333333,7561,23888 - SYNC,8,256,5940755.333333333,7817,23888 - ASYNC,1,1,9422749837.333334,7962,24108 - ASYNC,1,2,4728759765.333333,7963,24116 - ASYNC,1,4,2380554199.3333335,7965,24124 - ASYNC,1,8,1225118001.6666667,7969,24128 - ASYNC,1,16,618764241.6666666,7977,24132 - ASYNC,1,32,326253255.3333333,7993,24132 - ASYNC,1,64,179473876.66666666,8025,24132 - ASYNC,1,128,106170654.33333333,8217,24132 - ASYNC,1,256,69386800.33333333,8601,24136 - ASYNC,2,1,8347330729.0,8650,24288 - ASYNC,2,2,4186747233.3333335,8651,24296 - ASYNC,2,4,2092895507.3333333,8653,24304 - ASYNC,2,8,1049245198.6666666,8657,24316 - ASYNC,2,16,541544596.6666666,8665,24312 - ASYNC,2,32,281127929.6666667,8681,24312 - ASYNC,2,64,150746663.66666666,8713,24312 - ASYNC,2,128,85662842.0,8969,24312 - ASYNC,2,256,48909505.0,9481,24320 - ASYNC,4,1,7854085286.666667,10026,24652 - ASYNC,4,2,3935852050.3333335,10027,24660 - ASYNC,4,4,1972869873.0,10029,24668 - ASYNC,4,8,979451497.6666666,10033,24672 - ASYNC,4,16,499348958.0,10041,24676 - ASYNC,4,32,253712972.0,10057,24676 - ASYNC,4,64,131022135.33333333,10089,24676 - ASYNC,4,128,69610595.66666667,10473,24676 - ASYNC,4,256,38706461.666666664,11241,24692 - ASYNC,8,1,7590311686.666667,12778,25220 - ASYNC,8,2,3800333658.6666665,12779,25228 - ASYNC,8,4,1900014241.6666667,12781,25236 - ASYNC,8,8,940419515.0,12785,25240 - ASYNC,8,16,478739420.6666667,12793,25244 - ASYNC,8,32,241465250.66666666,12809,25244 - ASYNC,8,64,122701009.0,12841,25244 - ASYNC,8,128,63405355.0,13481,25244 - ASYNC,8,256,33752441.666666664,14761,25244 + LISTENERS,1,2,890787.3333333334,9247,23091 + LISTENERS,1,8,237925.0,9253,23091 + LISTENERS,1,32,74513.0,9277,23151 + LISTENERS,1,128,33813.0,9565,23231 + LISTENERS,1,512,35746.0,10717,23623 + LISTENERS,4,2,314198.3333333333,9274,23142 + LISTENERS,4,8,82244.33333333333,9280,23142 + LISTENERS,4,32,24057.333333333332,9304,23202 + LISTENERS,4,128,9816.0,9592,23282 + LISTENERS,4,512,9277.0,10744,23674 + LISTENERS,8,2,211465.66666666666,9310,23202 + LISTENERS,8,8,56294.0,9316,23210 + LISTENERS,8,32,15635.0,9340,23270 + LISTENERS,8,128,5818.0,9628,23350 + LISTENERS,8,512,4862.0,10780,23742 + SUBSCRIBERS,1,2,7804351.333333333,9927,23463 + SUBSCRIBERS,1,8,1978179.3333333333,9933,23463 + SUBSCRIBERS,1,32,514139.3333333333,9957,23523 + SUBSCRIBERS,1,128,146759.0,10309,23603 + SUBSCRIBERS,1,512,55104.0,11845,23995 + SUBSCRIBERS,4,2,5551961.0,11994,24134 + SUBSCRIBERS,4,8,1395009.0,12000,24134 + SUBSCRIBERS,4,32,354583.3333333333,12024,24194 + SUBSCRIBERS,4,128,92976.66666666667,12568,24274 + SUBSCRIBERS,4,512,28015.0,15256,24666 + SUBSCRIBERS,8,2,5449839.0,14750,24858 + SUBSCRIBERS,8,8,1321766.6666666667,14756,24866 + SUBSCRIBERS,8,32,332804.0,14780,24926 + SUBSCRIBERS,8,128,85489.33333333333,15580,25006 + SUBSCRIBERS,8,512,23905.0,19804,25398 + MSG_SUBSCRIBERS,1,2,8783538.333333334,10371,25615 + MSG_SUBSCRIBERS,1,8,2249592.6666666665,10377,25615 + MSG_SUBSCRIBERS,1,32,610168.0,10401,25675 + MSG_SUBSCRIBERS,1,128,207295.0,10753,25755 + MSG_SUBSCRIBERS,1,512,143584.66666666666,12289,26147 + MSG_SUBSCRIBERS,4,2,5787699.0,12318,26126 + MSG_SUBSCRIBERS,4,8,1473907.0,12324,26126 + MSG_SUBSCRIBERS,4,32,396127.6666666667,12348,26186 + MSG_SUBSCRIBERS,4,128,126362.66666666667,12892,26266 + MSG_SUBSCRIBERS,4,512,59040.666666666664,15580,26658 + MSG_SUBSCRIBERS,8,2,5453999.333333333,14914,26610 + MSG_SUBSCRIBERS,8,8,1356312.3333333333,14920,26650 + MSG_SUBSCRIBERS,8,32,361368.3333333333,14944,26710 + MSG_SUBSCRIBERS,8,128,113148.66666666667,15744,26790 + MSG_SUBSCRIBERS,8,512,51218.333333333336,19968,27182 diff --git a/samples/subsys/zbus/benchmark/benchmark_256KB.robot b/samples/subsys/zbus/benchmark/benchmark_256KB.robot index ef637f358f1..db2ab59d6a4 100644 --- a/samples/subsys/zbus/benchmark/benchmark_256KB.robot +++ b/samples/subsys/zbus/benchmark/benchmark_256KB.robot @@ -8,19 +8,23 @@ Suite Teardown Terminate All Processes kill=True *** Variables *** -${csv_file} zbus_dyn_benchmark_256kb.csv -${board} hifive1_revb -${serial_port} /dev/ttyACM0 +${csv_file} zbus_dyn_benchmark_256kb.csv +${board} hifive1_revb +${serial_port} /dev/ttyACM0 + *** Tasks *** Clear Old CSV File Empty Csv File ${csv_file} Zbus Benchmark - FOR ${async} IN "n" "y" - FOR ${consumers} IN 1 2 4 8 - FOR ${msg_size} IN 1 2 4 8 16 32 64 128 256 - Benchmark Report For message_size=${msg_size} one_to=${consumers} asynchronous=${async} + FOR ${obs_type} IN 0 1 2 + FOR ${consumers} IN 1 4 8 + FOR ${msg_size} IN 2 8 32 128 512 + Benchmark Report For + ... message_size=${msg_size} + ... one_to=${consumers} + ... observer_type=${obs_type} END END END @@ -54,30 +58,41 @@ Measure Results [Teardown] Delete All Ports Benchmark - [Arguments] ${message_size}=256 ${one_to}=1 ${asynchronous}=n + [Arguments] ${message_size}=256 ${one_to}=1 ${observer_type}=LISTENERS ${result} Run Process - ... west build -b ${board} -p always -- -DCONFIG_BM_MESSAGE_SIZE\=${message_size} -DCONFIG_BM_ONE_TO\=${one_to} -DCONFIG_BM_ASYNC\=${asynchronous} + ... west build -b ${board} -p always -- -DCONFIG_BM_MESSAGE_SIZE\=${message_size} -DCONFIG_BM_ONE_TO\=${one_to} -DCONFIG_BM_${observer_type}\=y ... shell=True Should Be Equal As Integers ${result.rc} 0 ${duration} Measure Results RETURN ${duration} Benchmark Report For - [Arguments] ${message_size}=256 ${one_to}=1 ${asynchronous}=n - ${duration} Benchmark message_size=${message_size} one_to=${one_to} asynchronous=${asynchronous} + [Arguments] ${message_size}=256 ${one_to}=1 ${observer_type}=0 + + ${obs_type_str} Set Variable LISTENERS + IF ${observer_type} == 1 + ${obs_type_str} Set Variable SUBSCRIBERS + ELSE IF ${observer_type} == 2 + ${obs_type_str} Set Variable MSG_SUBSCRIBERS + END + + ${duration} Benchmark + ... message_size=${message_size} + ... one_to=${one_to} + ... observer_type=${obs_type_str} + ${ram_amount} Run Memory Report ram + ${rom_amount} Run Memory Report rom - IF ${asynchronous} == "y" - ${async_str} Set Variable ASYNC - ELSE - ${async_str} Set Variable SYNC - END + @{results} Create List - ... ${async_str} + ... ${obs_type_str} ... ${one_to} ... ${message_size} ... ${duration} ... ${ram_amount} ... ${rom_amount} + Log To Console \n${results} + Append To Csv File ${csv_file} ${results} diff --git a/samples/subsys/zbus/benchmark/prj.conf b/samples/subsys/zbus/benchmark/prj.conf index 2c2865f3918..d79ae4dffe8 100644 --- a/samples/subsys/zbus/benchmark/prj.conf +++ b/samples/subsys/zbus/benchmark/prj.conf @@ -1,5 +1,7 @@ CONFIG_LOG=y +CONFIG_BOOT_BANNER=n CONFIG_LOG_MODE_MINIMAL=y CONFIG_ASSERT=n CONFIG_ZBUS=y CONFIG_ZBUS_LOG_LEVEL_INF=y +CONFIG_HEAP_MEM_POOL_SIZE=1024 diff --git a/samples/subsys/zbus/benchmark/sample.yaml b/samples/subsys/zbus/benchmark/sample.yaml index b090cc9d467..089d62209e2 100644 --- a/samples/subsys/zbus/benchmark/sample.yaml +++ b/samples/subsys/zbus/benchmark/sample.yaml @@ -10,7 +10,7 @@ tests: type: multi_line ordered: true regex: - - "I: Benchmark 1 to 8: Dynamic memory, ASYNC transmission and message size 256" + - "I: Benchmark 1 to 8 using LISTENERS to transmit with message size: 256 bytes" - "I: Bytes sent = 262144, received = 262144" - "I: Average data rate: (\\d+).(\\d+)MB/s" - "I: Duration: (\\d+).(\\d+)s" @@ -18,7 +18,29 @@ tests: extra_configs: - CONFIG_BM_ONE_TO=8 - CONFIG_BM_MESSAGE_SIZE=256 - - CONFIG_BM_ASYNC=y + - CONFIG_BM_LISTENERS=y + - arch:nios2:CONFIG_SYS_CLOCK_TICKS_PER_SEC=1000 + - CONFIG_IDLE_STACK_SIZE=1024 + integration_platforms: + - qemu_x86 + sample.zbus.benchmark_async_msg_sub: + tags: zbus + min_ram: 16 + filter: CONFIG_SYS_CLOCK_EXISTS and not (CONFIG_ARCH_POSIX and not CONFIG_BOARD_NATIVE_POSIX) + harness: console + harness_config: + type: multi_line + ordered: true + regex: + - "I: Benchmark 1 to 8 using MSG_SUBSCRIBERS to transmit with message size: 256 bytes" + - "I: Bytes sent = 262144, received = 262144" + - "I: Average data rate: (\\d+).(\\d+)MB/s" + - "I: Duration: (\\d+).(\\d+)s" + - "@(.*)" + extra_configs: + - CONFIG_BM_ONE_TO=8 + - CONFIG_BM_MESSAGE_SIZE=256 + - CONFIG_BM_MSG_SUBSCRIBERS=y - arch:nios2:CONFIG_SYS_CLOCK_TICKS_PER_SEC=1000 - CONFIG_IDLE_STACK_SIZE=1024 integration_platforms: @@ -32,7 +54,7 @@ tests: type: multi_line ordered: true regex: - - "I: Benchmark 1 to 8: Dynamic memory, SYNC transmission and message size 256" + - "I: Benchmark 1 to 8 using SUBSCRIBERS to transmit with message size: 256 bytes" - "I: Bytes sent = 262144, received = 262144" - "I: Average data rate: (\\d+).(\\d+)MB/s" - "I: Duration: (\\d+).(\\d+)s" @@ -40,7 +62,7 @@ tests: extra_configs: - CONFIG_BM_ONE_TO=8 - CONFIG_BM_MESSAGE_SIZE=256 - - CONFIG_BM_ASYNC=n + - CONFIG_BM_SUBSCRIBERS=y - arch:nios2:CONFIG_SYS_CLOCK_TICKS_PER_SEC=1000 - CONFIG_IDLE_STACK_SIZE=1024 integration_platforms: diff --git a/samples/subsys/zbus/benchmark/src/benchmark.c b/samples/subsys/zbus/benchmark/src/benchmark.c index ac781a6306f..267c593b4b1 100644 --- a/samples/subsys/zbus/benchmark/src/benchmark.c +++ b/samples/subsys/zbus/benchmark/src/benchmark.c @@ -4,8 +4,6 @@ */ #include "messages.h" -#include - #include #include #include @@ -27,183 +25,57 @@ LOG_MODULE_DECLARE(zbus, CONFIG_ZBUS_LOG_LEVEL); #define CONSUMER_STACK_SIZE (CONFIG_IDLE_STACK_SIZE + CONFIG_BM_MESSAGE_SIZE) #define PRODUCER_STACK_SIZE (CONFIG_MAIN_STACK_SIZE + CONFIG_BM_MESSAGE_SIZE) -ZBUS_CHAN_DEFINE(bm_channel, /* Name */ +ZBUS_CHAN_DEFINE(bm_channel, /* Name */ struct bm_msg, /* Message type */ - NULL, /* Validator */ - NULL, /* User data */ - ZBUS_OBSERVERS(s1 - -#if (CONFIG_BM_ONE_TO >= 2LLU) - , - s2 -#if (CONFIG_BM_ONE_TO > 2LLU) - , - s3, s4 -#if (CONFIG_BM_ONE_TO > 4LLU) - , - s5, s6, s7, s8 -#if (CONFIG_BM_ONE_TO > 8LLU) - , - s9, s10, s11, s12, s13, s14, s15, s16 -#endif -#endif -#endif -#endif - ), /* observers */ - ZBUS_MSG_INIT(0) /* Initial value {0} */ + NULL, /* Validator */ + NULL, /* User data */ + ZBUS_OBSERVERS_EMPTY, /* observers */ + ZBUS_MSG_INIT(0) /* Initial value {0} */ ); #define BYTES_TO_BE_SENT (256LLU * 1024LLU) -static atomic_t count; - -#if (CONFIG_BM_ASYNC == 1) -ZBUS_SUBSCRIBER_DEFINE(s1, 4); -#if (CONFIG_BM_ONE_TO >= 2LLU) -ZBUS_SUBSCRIBER_DEFINE(s2, 4); -#if (CONFIG_BM_ONE_TO > 2LLU) -ZBUS_SUBSCRIBER_DEFINE(s3, 4); -ZBUS_SUBSCRIBER_DEFINE(s4, 4); -#if (CONFIG_BM_ONE_TO > 4LLU) -ZBUS_SUBSCRIBER_DEFINE(s5, 4); -ZBUS_SUBSCRIBER_DEFINE(s6, 4); -ZBUS_SUBSCRIBER_DEFINE(s7, 4); -ZBUS_SUBSCRIBER_DEFINE(s8, 4); -#if (CONFIG_BM_ONE_TO > 8LLU) -ZBUS_SUBSCRIBER_DEFINE(s9, 4); -ZBUS_SUBSCRIBER_DEFINE(s10, 4); -ZBUS_SUBSCRIBER_DEFINE(s11, 4); -ZBUS_SUBSCRIBER_DEFINE(s12, 4); -ZBUS_SUBSCRIBER_DEFINE(s13, 4); -ZBUS_SUBSCRIBER_DEFINE(s14, 4); -ZBUS_SUBSCRIBER_DEFINE(s15, 4); -ZBUS_SUBSCRIBER_DEFINE(s16, 4); -#endif -#endif -#endif -#endif - -#define S_TASK(name) \ - void name##_task(void) \ - { \ - const struct zbus_channel *chan; \ - struct bm_msg *msg_received; \ - \ - while (!zbus_sub_wait(&name, &chan, K_FOREVER)) { \ - zbus_chan_claim(chan, K_NO_WAIT); \ - \ - msg_received = zbus_chan_msg(chan); \ - \ - zbus_chan_finish(chan); \ - \ - atomic_add(&count, CONFIG_BM_MESSAGE_SIZE); \ - } \ - } \ - \ - K_THREAD_DEFINE(name##_id, CONSUMER_STACK_SIZE, name##_task, NULL, NULL, NULL, 3, 0, 0); - -S_TASK(s1) -#if (CONFIG_BM_ONE_TO >= 2LLU) -S_TASK(s2) -#if (CONFIG_BM_ONE_TO > 2LLU) -S_TASK(s3) -S_TASK(s4) -#if (CONFIG_BM_ONE_TO > 4LLU) -S_TASK(s5) -S_TASK(s6) -S_TASK(s7) -S_TASK(s8) -#if (CONFIG_BM_ONE_TO > 8LLU) -S_TASK(s9) -S_TASK(s10) -S_TASK(s11) -S_TASK(s12) -S_TASK(s13) -S_TASK(s14) -S_TASK(s15) -S_TASK(s16) -#endif -#endif -#endif -#endif - -#else /* SYNC */ - -static void s_cb(const struct zbus_channel *chan); - -ZBUS_LISTENER_DEFINE(s1, s_cb); - -#if (CONFIG_BM_ONE_TO >= 2LLU) -ZBUS_LISTENER_DEFINE(s2, s_cb); -#if (CONFIG_BM_ONE_TO > 2LLU) -ZBUS_LISTENER_DEFINE(s3, s_cb); -ZBUS_LISTENER_DEFINE(s4, s_cb); -#if (CONFIG_BM_ONE_TO > 4LLU) -ZBUS_LISTENER_DEFINE(s5, s_cb); -ZBUS_LISTENER_DEFINE(s6, s_cb); -ZBUS_LISTENER_DEFINE(s7, s_cb); -ZBUS_LISTENER_DEFINE(s8, s_cb); -#if (CONFIG_BM_ONE_TO > 8LLU) -ZBUS_LISTENER_DEFINE(s9, s_cb); -ZBUS_LISTENER_DEFINE(s10, s_cb); -ZBUS_LISTENER_DEFINE(s11, s_cb); -ZBUS_LISTENER_DEFINE(s12, s_cb); -ZBUS_LISTENER_DEFINE(s13, s_cb); -ZBUS_LISTENER_DEFINE(s14, s_cb); -ZBUS_LISTENER_DEFINE(s15, s_cb); -ZBUS_LISTENER_DEFINE(s16, s_cb); -#endif -#endif -#endif -#endif - -static void s_cb(const struct zbus_channel *chan) -{ - const struct bm_msg *actual_message_data = zbus_chan_const_msg(chan); - - /* It only illustrates the message is ready to be consumed */ - ARG_UNUSED(actual_message_data); - - count += CONFIG_BM_MESSAGE_SIZE; -} - -#endif /* CONFIG_BM_ASYNC */ +atomic_t count; static void producer_thread(void) { - LOG_INF("Benchmark 1 to %d: Dynamic memory, %sSYNC transmission and message size %u", - CONFIG_BM_ONE_TO, IS_ENABLED(CONFIG_BM_ASYNC) ? "A" : "", CONFIG_BM_MESSAGE_SIZE); + LOG_INF("Benchmark 1 to %d using %s to transmit with message size: %u bytes", + CONFIG_BM_ONE_TO, + IS_ENABLED(CONFIG_BM_LISTENERS) + ? "LISTENERS" + : (IS_ENABLED(CONFIG_BM_SUBSCRIBERS) ? "SUBSCRIBERS" : "MSG_SUBSCRIBERS"), + CONFIG_BM_MESSAGE_SIZE); - struct bm_msg msg; + struct bm_msg msg = {{0}}; - for (uint64_t i = (CONFIG_BM_MESSAGE_SIZE - 1); i > 0; --i) { - msg.bytes[i] = i; - } + uint16_t message_size = CONFIG_BM_MESSAGE_SIZE; + + memcpy(msg.bytes, &message_size, sizeof(message_size)); uint64_t start_ns = GET_ARCH_TIME_NS(); for (uint64_t internal_count = BYTES_TO_BE_SENT / CONFIG_BM_ONE_TO; internal_count > 0; internal_count -= CONFIG_BM_MESSAGE_SIZE) { - zbus_chan_pub(&bm_channel, &msg, K_MSEC(200)); + zbus_chan_pub(&bm_channel, &msg, K_FOREVER); } uint64_t end_ns = GET_ARCH_TIME_NS(); - uint64_t duration = end_ns - start_ns; + uint64_t duration_ns = end_ns - start_ns; - if (duration == 0) { + if (duration_ns == 0) { LOG_ERR("Something wrong. Duration is zero!\n"); k_oops(); } - uint64_t i = ((BYTES_TO_BE_SENT * NSEC_PER_SEC) / MB(1)) / duration; - uint64_t f = ((BYTES_TO_BE_SENT * NSEC_PER_SEC * 100) / MB(1) / duration) % 100; + uint64_t i = ((BYTES_TO_BE_SENT * NSEC_PER_SEC) / MB(1)) / duration_ns; + uint64_t f = ((BYTES_TO_BE_SENT * NSEC_PER_SEC * 100) / MB(1) / duration_ns) % 100; - LOG_INF("Bytes sent = %lld, received = %lu", BYTES_TO_BE_SENT, atomic_get(&count)); + LOG_INF("Bytes sent = %llu, received = %lu", BYTES_TO_BE_SENT, atomic_get(&count)); LOG_INF("Average data rate: %llu.%lluMB/s", i, f); - LOG_INF("Duration: %lld.%09llus", duration / NSEC_PER_SEC, duration % NSEC_PER_SEC); + LOG_INF("Duration: %llu.%09llus", duration_ns / NSEC_PER_SEC, duration_ns % NSEC_PER_SEC); - printk("\n@%llu\n", duration); + printk("\n@%llu\n", duration_ns / 1000); } -K_THREAD_DEFINE(producer_thread_id, PRODUCER_STACK_SIZE, producer_thread, NULL, NULL, NULL, 5, 0, - 0); +K_THREAD_DEFINE(producer_thread_id, PRODUCER_STACK_SIZE * 2, producer_thread, NULL, NULL, NULL, 5, + 0, 0); diff --git a/samples/subsys/zbus/benchmark/src/lis.c b/samples/subsys/zbus/benchmark/src/lis.c new file mode 100644 index 00000000000..0a1e3a7757e --- /dev/null +++ b/samples/subsys/zbus/benchmark/src/lis.c @@ -0,0 +1,48 @@ +/* + * Copyright (c) 2023 Rodrigo Peixoto + * SPDX-License-Identifier: Apache-2.0 + */ +#include "messages.h" + +#include +#include +#include +#include + +#define CONSUMER_STACK_SIZE (CONFIG_IDLE_STACK_SIZE + CONFIG_BM_MESSAGE_SIZE) + +extern atomic_t count; + +static void s_cb(const struct zbus_channel *chan); + +ZBUS_CHAN_DECLARE(bm_channel); + +#define SFY(i, _) s##i + +#define CONSUMERS_NAME_LIST LISTIFY(CONFIG_BM_ONE_TO, SFY, (, /* separator */)) + +#define CREATE_OBSERVER(s) ZBUS_LISTENER_DEFINE(s, s_cb) + +#define CREATE_OBSERVATIONS(s) ZBUS_CHAN_ADD_OBS(bm_channel, s, 3) + +/* clang-format off */ +FOR_EACH(CREATE_OBSERVER, (;), CONSUMERS_NAME_LIST); + +FOR_EACH(CREATE_OBSERVATIONS, (;), CONSUMERS_NAME_LIST); +/* clang-format on */ + +static void s_cb(const struct zbus_channel *chan) +{ + + if (IS_ENABLED(CONFIG_BM_FAIRPLAY)) { + struct bm_msg msg_received; + + memcpy(zbus_chan_msg(chan), &msg_received, chan->message_size); + + atomic_add(&count, *((uint16_t *)msg_received.bytes)); + } else { + const struct bm_msg *msg_received = zbus_chan_const_msg(chan); + + atomic_add(&count, *((uint16_t *)msg_received->bytes)); + } +} diff --git a/samples/subsys/zbus/benchmark/src/msg_sub.c b/samples/subsys/zbus/benchmark/src/msg_sub.c new file mode 100644 index 00000000000..d4edc5db774 --- /dev/null +++ b/samples/subsys/zbus/benchmark/src/msg_sub.c @@ -0,0 +1,57 @@ +/* + * Copyright (c) 2023 Rodrigo Peixoto + * SPDX-License-Identifier: Apache-2.0 + */ +#include "messages.h" + +#include +#include +#include +#include + +#define CONSUMER_STACK_SIZE (CONFIG_IDLE_STACK_SIZE + CONFIG_BM_MESSAGE_SIZE) + +extern atomic_t count; + +ZBUS_CHAN_DECLARE(bm_channel); + +#define SFY(i, _) s##i + +#define CONSUMERS_NAME_LIST LISTIFY(CONFIG_BM_ONE_TO, SFY, (, /* separator */)) + +#define CREATE_OBSERVER(s) ZBUS_MSG_SUBSCRIBER_DEFINE(s) + +#define CREATE_OBSERVATIONS(s) ZBUS_CHAN_ADD_OBS(bm_channel, s, 3) + +/* clang-format off */ +FOR_EACH(CREATE_OBSERVER, (;), CONSUMERS_NAME_LIST); + +FOR_EACH(CREATE_OBSERVATIONS, (;), CONSUMERS_NAME_LIST); +/* clang-format on */ + +static int msg_sub_thread(void *msub_ref, void *ptr2, void *ptr3) +{ + ARG_UNUSED(ptr2); + ARG_UNUSED(ptr3); + + const struct zbus_channel *chan; + struct bm_msg msg_received; + struct zbus_observer *msub = msub_ref; + + while (1) { + if (zbus_sub_wait_msg(msub, &chan, &msg_received, K_FOREVER) == 0) { + atomic_add(&count, *((uint16_t *)msg_received.bytes)); + } else { + k_oops(); + } + } + + return -EFAULT; +} + +#define CREATE_THREADS(name) \ + K_THREAD_DEFINE(name##_msub_id, CONSUMER_STACK_SIZE, msg_sub_thread, &name, NULL, NULL, 3, \ + 0, 0); +/* clang-format off */ +FOR_EACH(CREATE_THREADS, (;), CONSUMERS_NAME_LIST); +/* clang-format on */ diff --git a/samples/subsys/zbus/benchmark/src/sub.c b/samples/subsys/zbus/benchmark/src/sub.c new file mode 100644 index 00000000000..f6a00531260 --- /dev/null +++ b/samples/subsys/zbus/benchmark/src/sub.c @@ -0,0 +1,71 @@ +/* + * Copyright (c) 2023 Rodrigo Peixoto + * SPDX-License-Identifier: Apache-2.0 + */ +#include "messages.h" + +#include +#include +#include +#include + +#define CONSUMER_STACK_SIZE (CONFIG_IDLE_STACK_SIZE + CONFIG_BM_MESSAGE_SIZE) + +extern atomic_t count; + +ZBUS_CHAN_DECLARE(bm_channel); + +#define SFY(i, _) s##i + +#define CONSUMERS_NAME_LIST LISTIFY(CONFIG_BM_ONE_TO, SFY, (, /* separator */)) + +#define CREATE_OBSERVER(s) ZBUS_SUBSCRIBER_DEFINE(s, 4) + +#define CREATE_OBSERVATIONS(s) ZBUS_CHAN_ADD_OBS(bm_channel, s, 3) + +/* clang-format off */ +FOR_EACH(CREATE_OBSERVER, (;), CONSUMERS_NAME_LIST); + +FOR_EACH(CREATE_OBSERVATIONS, (;), CONSUMERS_NAME_LIST); +/* clang-format on */ + +static int sub_thread(void *sub_ref, void *ptr2, void *ptr3) +{ + ARG_UNUSED(ptr2); + ARG_UNUSED(ptr3); + + const struct zbus_channel *chan; + struct zbus_observer *sub = sub_ref; + + while (1) { + if (zbus_sub_wait(sub, &chan, K_FOREVER) == 0) { + if (zbus_chan_claim(chan, K_FOREVER) != 0) { + k_oops(); + } + + if (IS_ENABLED(CONFIG_BM_FAIRPLAY)) { + struct bm_msg message; + + memcpy(zbus_chan_msg(chan), &message, chan->message_size); + + atomic_add(&count, *((uint16_t *)message.bytes)); + } else { + const struct bm_msg *msg_received = zbus_chan_const_msg(chan); + + atomic_add(&count, *((uint16_t *)msg_received->bytes)); + } + + zbus_chan_finish(chan); + } else { + k_oops(); + } + } + return -EFAULT; +} + +#define CREATE_THREADS(name) \ + K_THREAD_DEFINE(name##_sub_id, CONSUMER_STACK_SIZE, sub_thread, &name, NULL, NULL, 3, 0, 0); + +/* clang-format off */ +FOR_EACH(CREATE_THREADS, (;), CONSUMERS_NAME_LIST); +/* clang-format on */ From 7c87ff315e4e305c6e4a609414d8568807dd4cbe Mon Sep 17 00:00:00 2001 From: Aleksandr Khromykh Date: Mon, 11 Dec 2023 12:49:43 +0100 Subject: [PATCH 1091/3723] samples: Bluetooth: Mesh: remove nrf53_ns settings related workaround The issue with non secure storage system has been fixed in nrf53_ns platform: https://github.com/zephyrproject-rtos/zephyr/issues/59376 No need workarounds anymore. Signed-off-by: Aleksandr Khromykh --- .../bluetooth/mesh/boards/nrf5340dk_nrf5340_cpuapp_ns.conf | 4 ---- .../mesh_demo/boards/nrf5340dk_nrf5340_cpuapp_ns.conf | 4 ---- .../mesh_provisioner/boards/nrf5340dk_nrf5340_cpuapp_ns.conf | 4 ---- 3 files changed, 12 deletions(-) diff --git a/samples/bluetooth/mesh/boards/nrf5340dk_nrf5340_cpuapp_ns.conf b/samples/bluetooth/mesh/boards/nrf5340dk_nrf5340_cpuapp_ns.conf index 4693e4d1f78..f56dfa703f1 100644 --- a/samples/bluetooth/mesh/boards/nrf5340dk_nrf5340_cpuapp_ns.conf +++ b/samples/bluetooth/mesh/boards/nrf5340dk_nrf5340_cpuapp_ns.conf @@ -2,7 +2,3 @@ CONFIG_BT_HOST_CRYPTO=n # The option adds GATT caching feature that is based on TinyCrypt. CONFIG_BT_GATT_CACHING=n - -# Known issue: non secure platforms do not work with settings subsystem. -CONFIG_SETTINGS=n -CONFIG_BT_SETTINGS=n diff --git a/samples/bluetooth/mesh_demo/boards/nrf5340dk_nrf5340_cpuapp_ns.conf b/samples/bluetooth/mesh_demo/boards/nrf5340dk_nrf5340_cpuapp_ns.conf index 4693e4d1f78..f56dfa703f1 100644 --- a/samples/bluetooth/mesh_demo/boards/nrf5340dk_nrf5340_cpuapp_ns.conf +++ b/samples/bluetooth/mesh_demo/boards/nrf5340dk_nrf5340_cpuapp_ns.conf @@ -2,7 +2,3 @@ CONFIG_BT_HOST_CRYPTO=n # The option adds GATT caching feature that is based on TinyCrypt. CONFIG_BT_GATT_CACHING=n - -# Known issue: non secure platforms do not work with settings subsystem. -CONFIG_SETTINGS=n -CONFIG_BT_SETTINGS=n diff --git a/samples/bluetooth/mesh_provisioner/boards/nrf5340dk_nrf5340_cpuapp_ns.conf b/samples/bluetooth/mesh_provisioner/boards/nrf5340dk_nrf5340_cpuapp_ns.conf index c3d134592fc..c4aa66d1201 100644 --- a/samples/bluetooth/mesh_provisioner/boards/nrf5340dk_nrf5340_cpuapp_ns.conf +++ b/samples/bluetooth/mesh_provisioner/boards/nrf5340dk_nrf5340_cpuapp_ns.conf @@ -1,6 +1,2 @@ # The option adds TinyCrypt based bt_rand. CONFIG_BT_HOST_CRYPTO=n - -# Known issue: non secure platforms do not work with settings subsystem. -CONFIG_SETTINGS=n -CONFIG_BT_SETTINGS=n From e4cca5145bf340a93e59a05f80e2584265d6d4e4 Mon Sep 17 00:00:00 2001 From: Declan Snyder Date: Mon, 11 Dec 2023 10:19:53 -0600 Subject: [PATCH 1092/3723] net: Add fallback macro for nef_if_mon functions Add empty macro for net_if_mon functions if they are not otherwise defined, like the other functions in the net_if.c file have. Signed-off-by: Declan Snyder --- subsys/net/ip/net_if.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/subsys/net/ip/net_if.c b/subsys/net/ip/net_if.c index 69b2241d69d..551adb50c91 100644 --- a/subsys/net/ip/net_if.c +++ b/subsys/net/ip/net_if.c @@ -1001,6 +1001,10 @@ void net_if_mcast_monitor(struct net_if *iface, k_mutex_unlock(&lock); } +#else +#define net_if_mcast_mon_register(...) +#define net_if_mcast_mon_unregister(...) +#define net_if_mcast_monitor(...) #endif #if defined(CONFIG_NET_NATIVE_IPV6) From 3a1e179c4d5d61d59bbbcbd6b838e6f966520874 Mon Sep 17 00:00:00 2001 From: Markus Swarowsky Date: Mon, 11 Dec 2023 17:03:48 +0100 Subject: [PATCH 1093/3723] modules: mbedtls: Remove check_config.h build_info.h of mbedtls includes the config file for mbedtls but also includes check_config.h so its not needed to have it in the config file Signed-off-by: Markus Swarowsky --- modules/mbedtls/configs/config-tls-generic.h | 15 --------------- 1 file changed, 15 deletions(-) diff --git a/modules/mbedtls/configs/config-tls-generic.h b/modules/mbedtls/configs/config-tls-generic.h index 7cf85731c85..61278858ef2 100644 --- a/modules/mbedtls/configs/config-tls-generic.h +++ b/modules/mbedtls/configs/config-tls-generic.h @@ -486,19 +486,4 @@ #include CONFIG_MBEDTLS_USER_CONFIG_FILE #endif -#if !defined(CONFIG_MBEDTLS_PSA_CRYPTO_C) -/* When PSA API is used the checking header is included over the chain: - * |-psa/crypto.h - * |-psa/crypto_platform.h - * |-mbedtls/build_info.h - * |-mbedtls/check_config.h - * If include this header here then PSA API will be in semiconfigured state - * without considering dependencies from mbedtls/config_psa.h. - * mbedtls/config_psa.h should be included right after config-tls-generic.h before checking. - * Formally, all settings are correct but mbedtls library cannot be built. - * The behavior was introduced after adding mbedTLS 3.4.0 - */ -#include "mbedtls/check_config.h" -#endif - #endif /* MBEDTLS_CONFIG_H */ From b84bab36b94164b87257894b3de873f60bcee5e3 Mon Sep 17 00:00:00 2001 From: Miika Karanki Date: Mon, 30 Oct 2023 18:15:27 +0200 Subject: [PATCH 1094/3723] settings: file: do not unlink the settings file unnecessarily fs_rename can handle the file move atomically without unlinking the file first if the filesystem supports that. This change makes the settings file more power cut resilient so that the whole settings file is not lost with poorly timed power cut. Signed-off-by: Miika Karanki --- subsys/settings/src/settings_file.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/subsys/settings/src/settings_file.c b/subsys/settings/src/settings_file.c index 5f8be73cf74..4f18a75c561 100644 --- a/subsys/settings/src/settings_file.c +++ b/subsys/settings/src/settings_file.c @@ -351,7 +351,7 @@ static int settings_file_save_and_compress(struct settings_file *cf, rc = fs_close(&wf); rc2 = fs_close(&rf); - if (rc == 0 && rc2 == 0 && fs_unlink(cf->cf_name) == 0) { + if (rc == 0 && rc2 == 0) { if (fs_rename(tmp_file, cf->cf_name)) { return -ENOENT; } From 7013b4d7c72038c0643fb3df619cdea7b99fe040 Mon Sep 17 00:00:00 2001 From: Johann Fischer Date: Thu, 14 Sep 2023 23:24:30 +0200 Subject: [PATCH 1095/3723] usb: device_next: add support to set device address directly Not all device controllers expect the device address to be set after the status stage. Add support to directly set a new device address without waiting for the control request status stage. Signed-off-by: Johann Fischer --- include/zephyr/drivers/usb/udc.h | 2 ++ subsys/usb/device_next/usbd_ch9.c | 18 +++++++++++++++--- 2 files changed, 17 insertions(+), 3 deletions(-) diff --git a/include/zephyr/drivers/usb/udc.h b/include/zephyr/drivers/usb/udc.h index 0f01d877e54..73c33b21917 100644 --- a/include/zephyr/drivers/usb/udc.h +++ b/include/zephyr/drivers/usb/udc.h @@ -40,6 +40,8 @@ struct udc_device_caps { uint32_t rwup : 1; /** Controller performs status OUT stage automatically */ uint32_t out_ack : 1; + /** Controller expects device address to be set before status stage */ + uint32_t addr_before_status : 1; /** Maximum packet size for control endpoint */ enum udc_mps0 mps0 : 2; }; diff --git a/subsys/usb/device_next/usbd_ch9.c b/subsys/usb/device_next/usbd_ch9.c index 2d2505af597..66029017e97 100644 --- a/subsys/usb/device_next/usbd_ch9.c +++ b/subsys/usb/device_next/usbd_ch9.c @@ -46,7 +46,7 @@ static int ch9_get_ctrl_type(struct usbd_contex *const uds_ctx) return uds_ctx->ch9_data.ctrl_type; } -static int set_address_after_status_stage(struct usbd_contex *const uds_ctx) +static int post_status_stage(struct usbd_contex *const uds_ctx) { struct usb_setup_packet *setup = usbd_get_setup_pkt(uds_ctx); int ret; @@ -65,6 +65,7 @@ static int set_address_after_status_stage(struct usbd_contex *const uds_ctx) static int sreq_set_address(struct usbd_contex *const uds_ctx) { struct usb_setup_packet *setup = usbd_get_setup_pkt(uds_ctx); + struct udc_device_caps caps = udc_caps(uds_ctx->dev); /* Not specified if wLength is non-zero, treat as error */ if (setup->wValue > 127 || setup->wLength) { @@ -82,7 +83,18 @@ static int sreq_set_address(struct usbd_contex *const uds_ctx) return 0; } - uds_ctx->ch9_data.new_address = true; + if (caps.addr_before_status) { + int ret; + + ret = udc_set_address(uds_ctx->dev, setup->wValue); + if (ret) { + LOG_ERR("Failed to set device address 0x%x", setup->wValue); + return ret; + } + } else { + uds_ctx->ch9_data.new_address = true; + } + if (usbd_state_is_address(uds_ctx) && setup->wValue == 0) { uds_ctx->ch9_data.state = USBD_STATE_DEFAULT; } else { @@ -825,7 +837,7 @@ int usbd_handle_ctrl_xfer(struct usbd_contex *const uds_ctx, if (ch9_get_ctrl_type(uds_ctx) == CTRL_AWAIT_STATUS_STAGE) { LOG_INF("s-(out)-status finished"); if (unlikely(uds_ctx->ch9_data.new_address)) { - return set_address_after_status_stage(uds_ctx); + return post_status_stage(uds_ctx); } } else { LOG_WRN("Awaited s-(out)-status not finished"); From 6a7f43b47b50a4bd1bedc08551e4b6415bd598d0 Mon Sep 17 00:00:00 2001 From: Johann Fischer Date: Thu, 16 Nov 2023 11:42:29 +0100 Subject: [PATCH 1096/3723] usb: device_next: add SetFeature(TEST_MODE) support Add an interface to verify and enable a test mode. The test mode selected in the SetFeature control request must be verified to be supported by the controller and enabled after the status stage is completed. Signed-off-by: Johann Fischer --- include/zephyr/drivers/usb/udc.h | 40 +++++++++++++++++++- include/zephyr/usb/usbd.h | 4 +- subsys/usb/device_next/usbd_ch9.c | 61 +++++++++++++++++++++++++------ 3 files changed, 91 insertions(+), 14 deletions(-) diff --git a/include/zephyr/drivers/usb/udc.h b/include/zephyr/drivers/usb/udc.h index 73c33b21917..7e13d565a73 100644 --- a/include/zephyr/drivers/usb/udc.h +++ b/include/zephyr/drivers/usb/udc.h @@ -217,7 +217,7 @@ typedef int (*udc_event_cb_t)(const struct device *dev, * @brief UDC driver API * This is the mandatory API any USB device controller driver needs to expose * with exception of: - * device_speed() used by udc_device_speed(), not required for FS only devices + * device_speed(), test_mode() are only required for HS controllers */ struct udc_api { enum udc_bus_speed (*device_speed)(const struct device *dev); @@ -239,6 +239,8 @@ struct udc_api { int (*host_wakeup)(const struct device *dev); int (*set_address)(const struct device *dev, const uint8_t addr); + int (*test_mode)(const struct device *dev, + const uint8_t mode, const bool dryrun); int (*enable)(const struct device *dev); int (*disable)(const struct device *dev); int (*init)(const struct device *dev); @@ -446,6 +448,42 @@ static inline int udc_set_address(const struct device *dev, const uint8_t addr) return ret; } +/** + * @brief Enable Test Mode. + * + * For compliance testing, high-speed controllers must support test modes. + * A particular test is enabled by a SetFeature(TEST_MODE) request. + * To disable a test mode, device needs to be power cycled. + * + * @param[in] dev Pointer to device struct of the driver instance + * @param[in] mode Test mode + * @param[in] dryrun Verify that a particular mode can be enabled, but do not + * enable test mode + * + * @return 0 on success, all other values should be treated as error. + * @retval -ENOTSUP Test mode is not supported + */ +static inline int udc_test_mode(const struct device *dev, + const uint8_t mode, const bool dryrun) +{ + const struct udc_api *api = dev->api; + int ret; + + if (!udc_is_enabled(dev)) { + return -EPERM; + } + + if (api->test_mode != NULL) { + api->lock(dev); + ret = api->test_mode(dev, mode, dryrun); + api->unlock(dev); + } else { + ret = -ENOTSUP; + } + + return ret; +} + /** * @brief Initiate host wakeup procedure. * diff --git a/include/zephyr/usb/usbd.h b/include/zephyr/usb/usbd.h index aad53b47550..5048bdd78ee 100644 --- a/include/zephyr/usb/usbd.h +++ b/include/zephyr/usb/usbd.h @@ -134,8 +134,8 @@ struct usbd_ch9_data { uint32_t ep_halt; /** USB device stack selected configuration */ uint8_t configuration; - /** Indicate new device address */ - bool new_address; + /** Post status stage work required, e.g. set new device address */ + bool post_status; /** Array to track interfaces alternate settings */ uint8_t alternate[USBD_NUMOF_INTERFACES_MAX]; }; diff --git a/subsys/usb/device_next/usbd_ch9.c b/subsys/usb/device_next/usbd_ch9.c index 66029017e97..d7b1fccfc2e 100644 --- a/subsys/usb/device_next/usbd_ch9.c +++ b/subsys/usb/device_next/usbd_ch9.c @@ -25,6 +25,9 @@ LOG_MODULE_REGISTER(usbd_ch9, CONFIG_USBD_LOG_LEVEL); #define CTRL_AWAIT_SETUP_DATA 0 #define CTRL_AWAIT_STATUS_STAGE 1 +#define SF_TEST_MODE_SELECTOR(wIndex) ((uint8_t)((wIndex) >> 8)) +#define SF_TEST_LOWER_BYTE(wIndex) ((uint8_t)(wIndex)) + static bool reqtype_is_to_host(const struct usb_setup_packet *const setup) { return setup->wLength && USB_REQTYPE_GET_DIR(setup->bmRequestType); @@ -49,15 +52,26 @@ static int ch9_get_ctrl_type(struct usbd_contex *const uds_ctx) static int post_status_stage(struct usbd_contex *const uds_ctx) { struct usb_setup_packet *setup = usbd_get_setup_pkt(uds_ctx); - int ret; + int ret = 0; - ret = udc_set_address(uds_ctx->dev, setup->wValue); - if (ret) { - LOG_ERR("Failed to set device address 0x%x", setup->wValue); - return ret; + if (setup->bRequest == USB_SREQ_SET_ADDRESS) { + ret = udc_set_address(uds_ctx->dev, setup->wValue); + if (ret) { + LOG_ERR("Failed to set device address 0x%x", setup->wValue); + } + } + + if (setup->bRequest == USB_SREQ_SET_FEATURE && + setup->wValue == USB_SFS_TEST_MODE) { + uint8_t mode = SF_TEST_MODE_SELECTOR(setup->wIndex); + + ret = udc_test_mode(uds_ctx->dev, mode, false); + if (ret) { + LOG_ERR("Failed to enable TEST_MODE %u", mode); + } } - uds_ctx->ch9_data.new_address = false; + uds_ctx->ch9_data.post_status = false; return ret; } @@ -92,7 +106,7 @@ static int sreq_set_address(struct usbd_contex *const uds_ctx) return ret; } } else { - uds_ctx->ch9_data.new_address = true; + uds_ctx->ch9_data.post_status = true; } if (usbd_state_is_address(uds_ctx) && setup->wValue == 0) { @@ -256,6 +270,27 @@ static int sreq_clear_feature(struct usbd_contex *const uds_ctx) return ret; } +static int set_feature_test_mode(struct usbd_contex *const uds_ctx) +{ + struct usb_setup_packet *setup = usbd_get_setup_pkt(uds_ctx); + uint8_t mode = SF_TEST_MODE_SELECTOR(setup->wIndex); + + if (setup->RequestType.recipient != USB_REQTYPE_RECIPIENT_DEVICE || + SF_TEST_LOWER_BYTE(setup->wIndex) != 0) { + errno = -ENOTSUP; + return 0; + } + + if (udc_test_mode(uds_ctx->dev, mode, true) != 0) { + errno = -ENOTSUP; + return 0; + } + + uds_ctx->ch9_data.post_status = true; + + return 0; +} + static int sreq_set_feature(struct usbd_contex *const uds_ctx) { struct usb_setup_packet *setup = usbd_get_setup_pkt(uds_ctx); @@ -268,9 +303,13 @@ static int sreq_set_feature(struct usbd_contex *const uds_ctx) return 0; } + if (unlikely(setup->wValue == USB_SFS_TEST_MODE)) { + return set_feature_test_mode(uds_ctx); + } + /* - * TEST_MODE is not supported yet, other are not specified - * in default state, treat as error. + * Other request behavior is not specified in the default state, treat + * as an error. */ if (usbd_state_is_default(uds_ctx)) { errno = -EPERM; @@ -836,8 +875,8 @@ int usbd_handle_ctrl_xfer(struct usbd_contex *const uds_ctx, if (ch9_get_ctrl_type(uds_ctx) == CTRL_AWAIT_STATUS_STAGE) { LOG_INF("s-(out)-status finished"); - if (unlikely(uds_ctx->ch9_data.new_address)) { - return post_status_stage(uds_ctx); + if (unlikely(uds_ctx->ch9_data.post_status)) { + ret = post_status_stage(uds_ctx); } } else { LOG_WRN("Awaited s-(out)-status not finished"); From d8969904ce2e7732ce5a7cf6b561206db7c119d7 Mon Sep 17 00:00:00 2001 From: Vinayak Kariappa Chettimada Date: Fri, 1 Dec 2023 15:49:40 +0100 Subject: [PATCH 1097/3723] samples: Bluetooth: Broadcast audio source USB headset on nRF52 Series Broadcast audio source USB headset on nRF52 Series with USB support. Signed-off-by: Vinayak Kariappa Chettimada --- samples/bluetooth/broadcast_audio_source/Kconfig | 3 ++- .../boards/nrf52833dk_nrf52833.conf | 5 +++++ .../boards/nrf52833dk_nrf52833.overlay | 15 +++++++++++++++ .../boards/nrf52840dongle_nrf52840.conf | 5 +++++ .../boards/nrf52840dongle_nrf52840.overlay | 15 +++++++++++++++ .../boards/nrf5340_audio_dk_nrf5340_cpuapp.conf | 3 --- samples/bluetooth/broadcast_audio_source/prj.conf | 4 ++-- .../bluetooth/broadcast_audio_source/sample.yaml | 2 ++ .../bluetooth/broadcast_audio_source/src/main.c | 5 +++-- 9 files changed, 49 insertions(+), 8 deletions(-) create mode 100644 samples/bluetooth/broadcast_audio_source/boards/nrf52833dk_nrf52833.conf create mode 100644 samples/bluetooth/broadcast_audio_source/boards/nrf52833dk_nrf52833.overlay create mode 100644 samples/bluetooth/broadcast_audio_source/boards/nrf52840dongle_nrf52840.conf create mode 100644 samples/bluetooth/broadcast_audio_source/boards/nrf52840dongle_nrf52840.overlay diff --git a/samples/bluetooth/broadcast_audio_source/Kconfig b/samples/bluetooth/broadcast_audio_source/Kconfig index d88378d0848..683eeaf9dbf 100644 --- a/samples/bluetooth/broadcast_audio_source/Kconfig +++ b/samples/bluetooth/broadcast_audio_source/Kconfig @@ -24,7 +24,8 @@ config ENABLE_LC3 bool "Enable the LC3 codec" # By default let's enable it in the platforms we know are capable of supporting it default y - depends on (ARCH_POSIX || SOC_NRF5340_CPUAPP) + depends on CPU_HAS_FPU && \ + (ARCH_POSIX || SOC_COMPATIBLE_NRF52X || SOC_COMPATIBLE_NRF5340_CPUAPP) select LIBLC3 select FPU diff --git a/samples/bluetooth/broadcast_audio_source/boards/nrf52833dk_nrf52833.conf b/samples/bluetooth/broadcast_audio_source/boards/nrf52833dk_nrf52833.conf new file mode 100644 index 00000000000..ff68bab6356 --- /dev/null +++ b/samples/bluetooth/broadcast_audio_source/boards/nrf52833dk_nrf52833.conf @@ -0,0 +1,5 @@ +CONFIG_MAIN_STACK_SIZE=4096 + +# Use USB Audio as input +CONFIG_USE_USB_AUDIO_INPUT=y +CONFIG_USB_DEVICE_PRODUCT="Zephyr Broadcast Source" diff --git a/samples/bluetooth/broadcast_audio_source/boards/nrf52833dk_nrf52833.overlay b/samples/bluetooth/broadcast_audio_source/boards/nrf52833dk_nrf52833.overlay new file mode 100644 index 00000000000..b8e72f1b61c --- /dev/null +++ b/samples/bluetooth/broadcast_audio_source/boards/nrf52833dk_nrf52833.overlay @@ -0,0 +1,15 @@ +zephyr_udc0: &usbd { + compatible = "nordic,nrf-usbd"; + status = "okay"; + + hs_0: hs_0 { + compatible = "usb-audio-hs"; + mic-feature-mute; + mic-channel-l; + mic-channel-r; + + hp-feature-mute; + hp-channel-l; + hp-channel-r; + }; +}; diff --git a/samples/bluetooth/broadcast_audio_source/boards/nrf52840dongle_nrf52840.conf b/samples/bluetooth/broadcast_audio_source/boards/nrf52840dongle_nrf52840.conf new file mode 100644 index 00000000000..ff68bab6356 --- /dev/null +++ b/samples/bluetooth/broadcast_audio_source/boards/nrf52840dongle_nrf52840.conf @@ -0,0 +1,5 @@ +CONFIG_MAIN_STACK_SIZE=4096 + +# Use USB Audio as input +CONFIG_USE_USB_AUDIO_INPUT=y +CONFIG_USB_DEVICE_PRODUCT="Zephyr Broadcast Source" diff --git a/samples/bluetooth/broadcast_audio_source/boards/nrf52840dongle_nrf52840.overlay b/samples/bluetooth/broadcast_audio_source/boards/nrf52840dongle_nrf52840.overlay new file mode 100644 index 00000000000..b8e72f1b61c --- /dev/null +++ b/samples/bluetooth/broadcast_audio_source/boards/nrf52840dongle_nrf52840.overlay @@ -0,0 +1,15 @@ +zephyr_udc0: &usbd { + compatible = "nordic,nrf-usbd"; + status = "okay"; + + hs_0: hs_0 { + compatible = "usb-audio-hs"; + mic-feature-mute; + mic-channel-l; + mic-channel-r; + + hp-feature-mute; + hp-channel-l; + hp-channel-r; + }; +}; diff --git a/samples/bluetooth/broadcast_audio_source/boards/nrf5340_audio_dk_nrf5340_cpuapp.conf b/samples/bluetooth/broadcast_audio_source/boards/nrf5340_audio_dk_nrf5340_cpuapp.conf index ff8004f0dc0..ff68bab6356 100644 --- a/samples/bluetooth/broadcast_audio_source/boards/nrf5340_audio_dk_nrf5340_cpuapp.conf +++ b/samples/bluetooth/broadcast_audio_source/boards/nrf5340_audio_dk_nrf5340_cpuapp.conf @@ -3,6 +3,3 @@ CONFIG_MAIN_STACK_SIZE=4096 # Use USB Audio as input CONFIG_USE_USB_AUDIO_INPUT=y CONFIG_USB_DEVICE_PRODUCT="Zephyr Broadcast Source" - -# Two streams in one subgroup (stereo) -CONFIG_BT_BAP_BROADCAST_SRC_SUBGROUP_COUNT=1 diff --git a/samples/bluetooth/broadcast_audio_source/prj.conf b/samples/bluetooth/broadcast_audio_source/prj.conf index d74cbbe50ce..133a376a68b 100644 --- a/samples/bluetooth/broadcast_audio_source/prj.conf +++ b/samples/bluetooth/broadcast_audio_source/prj.conf @@ -7,8 +7,8 @@ CONFIG_BT_BAP_BROADCAST_SOURCE=y CONFIG_BT_ISO_MAX_CHAN=2 CONFIG_BT_BAP_BROADCAST_SRC_STREAM_COUNT=2 -CONFIG_BT_BAP_BROADCAST_SRC_SUBGROUP_COUNT=2 -CONFIG_BT_ISO_TX_BUF_COUNT=4 +# Two streams in one subgroup (stereo) +CONFIG_BT_BAP_BROADCAST_SRC_SUBGROUP_COUNT=1 CONFIG_BT_ISO_TX_MTU=60 diff --git a/samples/bluetooth/broadcast_audio_source/sample.yaml b/samples/bluetooth/broadcast_audio_source/sample.yaml index 1c27238c35f..3c554803409 100644 --- a/samples/bluetooth/broadcast_audio_source/sample.yaml +++ b/samples/bluetooth/broadcast_audio_source/sample.yaml @@ -20,8 +20,10 @@ tests: - nrf52_bsim - nrf52833dk_nrf52820 - nrf52833dk_nrf52833 + - nrf52840dongle_nrf52840 integration_platforms: - nrf52_bsim - nrf52833dk_nrf52833 + - nrf52840dongle_nrf52840 extra_args: OVERLAY_CONFIG=overlay-bt_ll_sw_split.conf tags: bluetooth diff --git a/samples/bluetooth/broadcast_audio_source/src/main.c b/samples/bluetooth/broadcast_audio_source/src/main.c index 8a129e3f361..dcc3ebaf2e2 100644 --- a/samples/bluetooth/broadcast_audio_source/src/main.c +++ b/samples/bluetooth/broadcast_audio_source/src/main.c @@ -465,10 +465,11 @@ int main(void) usb_audio_register(hs_dev, &ops); err = usb_enable(NULL); - if (err) { - printk("Failed to enable USB"); + if (err && err != -EALREADY) { + printk("Failed to enable USB (%d)", err); return 0; } + #endif /* defined(CONFIG_USB_DEVICE_AUDIO) */ k_thread_start(encoder); #endif /* defined(CONFIG_LIBLC3) */ From 5e26cd4fd2e14dc5adefb34bcb8230d9a1e30d49 Mon Sep 17 00:00:00 2001 From: Vinayak Kariappa Chettimada Date: Wed, 6 Dec 2023 11:44:45 +0100 Subject: [PATCH 1098/3723] samples: Bluetooth: Update buffer counts for Broadcast Audio Source Updaye buffer counts and semaphore initial value so that the Broadcast Audio Source can utilize any use of broadcast pre-transmissions. Signed-off-by: Vinayak Kariappa Chettimada --- samples/bluetooth/broadcast_audio_source/prj.conf | 1 + samples/bluetooth/broadcast_audio_source/src/main.c | 4 ++-- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/samples/bluetooth/broadcast_audio_source/prj.conf b/samples/bluetooth/broadcast_audio_source/prj.conf index 133a376a68b..746b7fff423 100644 --- a/samples/bluetooth/broadcast_audio_source/prj.conf +++ b/samples/bluetooth/broadcast_audio_source/prj.conf @@ -10,6 +10,7 @@ CONFIG_BT_BAP_BROADCAST_SRC_STREAM_COUNT=2 # Two streams in one subgroup (stereo) CONFIG_BT_BAP_BROADCAST_SRC_SUBGROUP_COUNT=1 +CONFIG_BT_ISO_TX_BUF_COUNT=6 CONFIG_BT_ISO_TX_MTU=60 CONFIG_BT_DEVICE_NAME="Broadcast Audio Source" diff --git a/samples/bluetooth/broadcast_audio_source/src/main.c b/samples/bluetooth/broadcast_audio_source/src/main.c index dcc3ebaf2e2..bc63b68b700 100644 --- a/samples/bluetooth/broadcast_audio_source/src/main.c +++ b/samples/bluetooth/broadcast_audio_source/src/main.c @@ -25,7 +25,7 @@ /* When BROADCAST_ENQUEUE_COUNT > 1 we can enqueue enough buffers to ensure that * the controller is never idle */ -#define BROADCAST_ENQUEUE_COUNT 2U +#define BROADCAST_ENQUEUE_COUNT 3U #define TOTAL_BUF_NEEDED (BROADCAST_ENQUEUE_COUNT * CONFIG_BT_BAP_BROADCAST_SRC_STREAM_COUNT) BUILD_ASSERT(CONFIG_BT_ISO_TX_BUF_COUNT >= TOTAL_BUF_NEEDED, @@ -145,7 +145,7 @@ static int frame_duration_us; static int frames_per_sdu; static int octets_per_frame; -static K_SEM_DEFINE(lc3_encoder_sem, 0U, ARRAY_SIZE(streams)); +static K_SEM_DEFINE(lc3_encoder_sem, 0U, TOTAL_BUF_NEEDED); #endif static void send_data(struct broadcast_source_stream *source_stream) From f6f8c3f9b775a01b8bd4b37fdd8190d244e07c61 Mon Sep 17 00:00:00 2001 From: Pisit Sawangvonganan Date: Wed, 6 Dec 2023 16:29:33 +0700 Subject: [PATCH 1099/3723] shell: correct z_shell_spaces_trim when len equal to zero Addresses a potential issue when the string contains only '\0', which results in z_shell_strlen(str) returning len as 0. Since the for-loop expects len >= 1, the function now immediately returns when len == 0. As the null check for 'str' is already handled inside z_shell_strlen(), an additional check for 'str' is not needed. Signed-off-by: Pisit Sawangvonganan --- subsys/shell/shell_utils.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/subsys/shell/shell_utils.c b/subsys/shell/shell_utils.c index 06033ec688b..bd7523e4705 100644 --- a/subsys/shell/shell_utils.c +++ b/subsys/shell/shell_utils.c @@ -428,7 +428,7 @@ void z_shell_spaces_trim(char *str) uint16_t len = z_shell_strlen(str); uint16_t shift = 0U; - if (!str) { + if (len == 0U) { return; } From 1dc43605df780c32ae0d1be2f251465ed21c29cb Mon Sep 17 00:00:00 2001 From: Hake Huang Date: Wed, 6 Dec 2023 17:20:03 +0800 Subject: [PATCH 1100/3723] tests: testinstance: enforce utf-8 write as in windows platfrom the format by default is not utf-8, and we will see below error Traceback (most recent call last): File "...zephyr\scripts\twister", line 211, in ret = main(options) ^^^^^^^^^^^^^ File "...scripts/pylib/twister\twisterlib\twister_main.py", tplan.load() File "...scripts/pylib/twister\twisterlib\testplan.py", self.load_from_file(last_run, filter_platform=connected_list) File "...scripts/pylib/twister\twisterlib\testplan.py", instance.create_overlay(platform, self.options.enable_asan, self.options.enable_ubsan, self.options.enable_coverage, self.options.coverage_platform) File "...scripts/pylib/twister\twisterlib\testinstance.py" f.write(content) UnicodeEncodeError: 'gbk' codec can't encode character '\xf8' in position 64: illegal multibyte sequence Signed-off-by: Hake Huang --- scripts/pylib/twister/twisterlib/testinstance.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/scripts/pylib/twister/twisterlib/testinstance.py b/scripts/pylib/twister/twisterlib/testinstance.py index 438572040ca..24ab66ae030 100644 --- a/scripts/pylib/twister/twisterlib/testinstance.py +++ b/scripts/pylib/twister/twisterlib/testinstance.py @@ -287,7 +287,7 @@ def create_overlay(self, platform, enable_asan=False, enable_ubsan=False, enable if content: os.makedirs(subdir, exist_ok=True) file = os.path.join(subdir, "testsuite_extra.conf") - with open(file, "w") as f: + with open(file, "w", encoding='utf-8') as f: f.write(content) return content From f1e7a0dd6c727cdcc27d4e356e8a1eefe68f9d7f Mon Sep 17 00:00:00 2001 From: Jerzy Kasenberg Date: Tue, 5 Dec 2023 14:57:19 +0100 Subject: [PATCH 1101/3723] drivers: clock_control: smartbond: Fix rc32k calibration If RC32K oscillator was on during startup, calibration work was never going to actually calibrate this oscillator. It happen because lpc_clock_state.rc32k_started was only set when oscillator was turned on after if was turned off. Now lpc_clock_state.rc32k_started is also set when rc32k is already started (possible during boot). Signed-off-by: Jerzy Kasenberg --- drivers/clock_control/clock_control_smartbond.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/clock_control/clock_control_smartbond.c b/drivers/clock_control/clock_control_smartbond.c index c5ce8a77f22..60c98f8668a 100644 --- a/drivers/clock_control/clock_control_smartbond.c +++ b/drivers/clock_control/clock_control_smartbond.c @@ -73,8 +73,8 @@ static void smartbond_start_rc32k(void) { if ((CRG_TOP->CLK_RC32K_REG & CRG_TOP_CLK_RC32K_REG_RC32K_ENABLE_Msk) == 0) { CRG_TOP->CLK_RC32K_REG |= CRG_TOP_CLK_RC32K_REG_RC32K_ENABLE_Msk; - lpc_clock_state.rc32k_started = true; } + lpc_clock_state.rc32k_started = true; if (!lpc_clock_state.rc32k_ready && (CALIBRATION_INTERVAL > 0)) { if (!k_work_is_pending(&calibration_work.work)) { k_work_schedule(&calibration_work, From fe74ffe2d51a5e15bb77ecb8cc4f2170d8b1cbde Mon Sep 17 00:00:00 2001 From: Henrik Brix Andersen Date: Sun, 10 Dec 2023 22:03:41 +0100 Subject: [PATCH 1102/3723] drivers: can: drop POSIX from the native Linux SocketCAN driver name Rename the native Linux SocketCAN driver to reflect that it can can now be used in both native_posix and native_sim (with or without an embedded C-library). Signed-off-by: Henrik Brix Andersen --- boards/posix/native_sim/doc/index.rst | 2 +- boards/posix/native_sim/native_sim.dts | 2 +- doc/releases/migration-guide-3.6.rst | 9 ++ doc/releases/release-notes-3.2.rst | 2 +- drivers/can/CMakeLists.txt | 12 +- drivers/can/Kconfig | 2 +- ...ative_posix_linux => Kconfig.native_linux} | 10 +- ...ative_posix_linux.c => can_native_linux.c} | 128 +++++++++--------- ...x_socketcan.c => can_native_linux_adapt.c} | 2 +- ...x_socketcan.h => can_native_linux_adapt.h} | 0 ...-can.yaml => zephyr,native-linux-can.yaml} | 2 +- tests/drivers/build_all/can/testcase.yaml | 2 +- 12 files changed, 92 insertions(+), 81 deletions(-) rename drivers/can/{Kconfig.native_posix_linux => Kconfig.native_linux} (76%) rename drivers/can/{can_native_posix_linux.c => can_native_linux.c} (69%) rename drivers/can/{can_native_posix_linux_socketcan.c => can_native_linux_adapt.c} (98%) rename drivers/can/{can_native_posix_linux_socketcan.h => can_native_linux_adapt.h} (100%) rename dts/bindings/can/{zephyr,native-posix-linux-can.yaml => zephyr,native-linux-can.yaml} (87%) diff --git a/boards/posix/native_sim/doc/index.rst b/boards/posix/native_sim/doc/index.rst index b88f5283dc3..b92d0bf911a 100644 --- a/boards/posix/native_sim/doc/index.rst +++ b/boards/posix/native_sim/doc/index.rst @@ -615,7 +615,7 @@ host libC (:kconfig:option:`CONFIG_EXTERNAL_LIBC`): adc, ADC emul, :kconfig:option:`CONFIG_ADC_EMUL`, all bluetooth, userchan, :kconfig:option:`CONFIG_BT_USERCHAN`, host libC - can, can native posix, :kconfig:option:`CONFIG_CAN_NATIVE_POSIX_LINUX`, all + can, can native Linux, :kconfig:option:`CONFIG_CAN_NATIVE_LINUX`, all console backend, POSIX arch console, :kconfig:option:`CONFIG_POSIX_ARCH_CONSOLE`, all display, display SDL, :kconfig:option:`CONFIG_SDL_DISPLAY`, all entropy, native posix entropy, :kconfig:option:`CONFIG_FAKE_ENTROPY_NATIVE_POSIX`, all diff --git a/boards/posix/native_sim/native_sim.dts b/boards/posix/native_sim/native_sim.dts index 26a38593484..682049c63ca 100644 --- a/boards/posix/native_sim/native_sim.dts +++ b/boards/posix/native_sim/native_sim.dts @@ -195,7 +195,7 @@ can0: can { status = "disabled"; - compatible = "zephyr,native-posix-linux-can"; + compatible = "zephyr,native-linux-can"; /* adjust zcan0 to desired host interface or create an alternative * name, e.g.: sudo ip link property add dev vcan0 altname zcan0 */ diff --git a/doc/releases/migration-guide-3.6.rst b/doc/releases/migration-guide-3.6.rst index f22e921fa15..c944a2ae4c6 100644 --- a/doc/releases/migration-guide-3.6.rst +++ b/doc/releases/migration-guide-3.6.rst @@ -128,6 +128,15 @@ Device Drivers and Device Tree status = "okay"; }; +* The native Linux SocketCAN driver, which can now be used in both :ref:`native_posix` + and :ref:`native_sim` with or without an embedded C-library, has been renamed to + reflect this: + + * The devicetree compatible was renamed from ``zephyr,native-posix-linux-can`` to + :dtcompatible:`zephyr,native-linux-can`. + * The main Kconfig option was renamed from ``CONFIG_CAN_NATIVE_POSIX_LINUX`` to + :kconfig:option:`CONFIG_CAN_NATIVE_LINUX`. + Power Management ================ diff --git a/doc/releases/release-notes-3.2.rst b/doc/releases/release-notes-3.2.rst index d902ac4481b..cf27f017fcb 100644 --- a/doc/releases/release-notes-3.2.rst +++ b/doc/releases/release-notes-3.2.rst @@ -1166,7 +1166,7 @@ Devicetree * :dtcompatible:`zephyr,coredump` * :dtcompatible:`zephyr,ieee802154-uart-pipe` * :dtcompatible:`zephyr,native-posix-counter` - * :dtcompatible:`zephyr,native-posix-linux-can` + * ``zephyr,native-posix-linux-can`` * :dtcompatible:`zephyr,sdl-kscan` * :dtcompatible:`zephyr,sdmmc-disk` * :dtcompatible:`zephyr,w1-serial` diff --git a/drivers/can/CMakeLists.txt b/drivers/can/CMakeLists.txt index 18e3ba67ac8..e704402e1fd 100644 --- a/drivers/can/CMakeLists.txt +++ b/drivers/can/CMakeLists.txt @@ -28,21 +28,21 @@ zephyr_library_sources_ifdef(CONFIG_USERSPACE can_handlers.c) zephyr_library_sources_ifdef(CONFIG_CAN_SHELL can_shell.c) zephyr_library_sources_ifdef(CONFIG_CAN_NXP_S32_CANXL can_nxp_s32_canxl.c) -if(CONFIG_CAN_NATIVE_POSIX_LINUX) +if(CONFIG_CAN_NATIVE_LINUX) if(${CMAKE_HOST_SYSTEM_NAME} STREQUAL Linux) zephyr_library_include_directories(${ZEPHYR_BASE}/subsys/net/l2) - zephyr_library_sources(can_native_posix_linux.c) + zephyr_library_sources(can_native_linux.c) if (CONFIG_NATIVE_APPLICATION) - set_source_files_properties(can_native_posix_linux_socketcan.c + set_source_files_properties(can_native_linux_adapt.c PROPERTIES COMPILE_DEFINITIONS "NO_POSIX_CHEATS;_BSD_SOURCE;_DEFAULT_SOURCE") - zephyr_library_sources(can_native_posix_linux_socketcan.c) + zephyr_library_sources(can_native_linux_adapt.c) else() - target_sources(native_simulator INTERFACE can_native_posix_linux_socketcan.c) + target_sources(native_simulator INTERFACE can_native_linux_adapt.c) endif() else() - message(FATAL_ERROR "CONFIG_CAN_NATIVE_POSIX_LINUX only available on Linux") + message(FATAL_ERROR "CONFIG_CAN_NATIVE_LINUX is only available on Linux") endif() endif() diff --git a/drivers/can/Kconfig b/drivers/can/Kconfig index ed0818d3508..e4fd4709505 100644 --- a/drivers/can/Kconfig +++ b/drivers/can/Kconfig @@ -93,7 +93,7 @@ source "drivers/can/Kconfig.mcan" source "drivers/can/Kconfig.rcar" source "drivers/can/Kconfig.numaker" source "drivers/can/Kconfig.loopback" -source "drivers/can/Kconfig.native_posix_linux" +source "drivers/can/Kconfig.native_linux" source "drivers/can/Kconfig.sja1000" source "drivers/can/Kconfig.esp32" source "drivers/can/Kconfig.kvaser" diff --git a/drivers/can/Kconfig.native_posix_linux b/drivers/can/Kconfig.native_linux similarity index 76% rename from drivers/can/Kconfig.native_posix_linux rename to drivers/can/Kconfig.native_linux index f11006ec6da..54969fd7de1 100644 --- a/drivers/can/Kconfig.native_posix_linux +++ b/drivers/can/Kconfig.native_linux @@ -3,17 +3,17 @@ # Copyright (c) 2022 Martin Jäger # SPDX-License-Identifier: Apache-2.0 -config CAN_NATIVE_POSIX_LINUX +config CAN_NATIVE_LINUX bool "Native Linux SocketCAN Driver" default y - depends on DT_HAS_ZEPHYR_NATIVE_POSIX_LINUX_CAN_ENABLED + depends on DT_HAS_ZEPHYR_NATIVE_LINUX_CAN_ENABLED depends on ARCH_POSIX help Enable native Linux SocketCAN Driver -if CAN_NATIVE_POSIX_LINUX +if CAN_NATIVE_LINUX -config CAN_NATIVE_POSIX_LINUX_RX_THREAD_PRIORITY +config CAN_NATIVE_LINUX_RX_THREAD_PRIORITY int "Priority for internal RX thread" default 2 help @@ -28,4 +28,4 @@ config CAN_MAX_FILTER Defines the array size of the callback/msgq pointers. Must be at least the size of concurrent reads. -endif # CAN_NATIVE_POSIX_LINUX +endif # CAN_NATIVE_LINUX diff --git a/drivers/can/can_native_posix_linux.c b/drivers/can/can_native_linux.c similarity index 69% rename from drivers/can/can_native_posix_linux.c rename to drivers/can/can_native_linux.c index 7f8a0ea494f..5ada2a5b47c 100644 --- a/drivers/can/can_native_posix_linux.c +++ b/drivers/can/can_native_linux.c @@ -4,7 +4,7 @@ * SPDX-License-Identifier: Apache-2.0 */ -#define DT_DRV_COMPAT zephyr_native_posix_linux_can +#define DT_DRV_COMPAT zephyr_native_linux_can #include #include @@ -17,9 +17,9 @@ #include #include -#include "can_native_posix_linux_socketcan.h" +#include "can_native_linux_adapt.h" -LOG_MODULE_REGISTER(can_npl, CONFIG_CAN_LOG_LEVEL); +LOG_MODULE_REGISTER(can_native_linux, CONFIG_CAN_LOG_LEVEL); struct can_filter_context { can_rx_callback_t rx_cb; @@ -27,7 +27,7 @@ struct can_filter_context { struct can_filter filter; }; -struct can_npl_data { +struct can_native_linux_data { struct can_filter_context filters[CONFIG_CAN_MAX_FILTER]; struct k_mutex filter_mutex; struct k_sem tx_idle; @@ -42,13 +42,13 @@ struct can_npl_data { K_KERNEL_STACK_MEMBER(rx_thread_stack, CONFIG_ARCH_POSIX_RECOMMENDED_STACK_SIZE); }; -struct can_npl_config { +struct can_native_linux_config { const char *if_name; }; static void dispatch_frame(const struct device *dev, struct can_frame *frame) { - struct can_npl_data *data = dev->data; + struct can_native_linux_data *data = dev->data; can_rx_callback_t callback; struct can_frame tmp_frame; @@ -76,7 +76,7 @@ static void dispatch_frame(const struct device *dev, struct can_frame *frame) static void rx_thread(void *arg1, void *arg2, void *arg3) { const struct device *dev = arg1; - struct can_npl_data *data = dev->data; + struct can_native_linux_data *data = dev->data; struct socketcan_frame sframe; struct can_frame frame; bool msg_confirm; @@ -113,15 +113,15 @@ static void rx_thread(void *arg1, void *arg2, void *arg3) dispatch_frame(dev, &frame); } - /* short sleep required to avoid blocking the whole native_posix process */ + /* short sleep required to avoid blocking the whole native process */ k_sleep(K_MSEC(1)); } } -static int can_npl_send(const struct device *dev, const struct can_frame *frame, - k_timeout_t timeout, can_tx_callback_t callback, void *user_data) +static int can_native_linux_send(const struct device *dev, const struct can_frame *frame, + k_timeout_t timeout, can_tx_callback_t callback, void *user_data) { - struct can_npl_data *data = dev->data; + struct can_native_linux_data *data = dev->data; struct socketcan_frame sframe; uint8_t max_dlc = CAN_MAX_DLC; size_t mtu = CAN_MTU; @@ -187,10 +187,10 @@ static int can_npl_send(const struct device *dev, const struct can_frame *frame, return 0; } -static int can_npl_add_rx_filter(const struct device *dev, can_rx_callback_t cb, - void *cb_arg, const struct can_filter *filter) +static int can_native_linux_add_rx_filter(const struct device *dev, can_rx_callback_t cb, + void *cb_arg, const struct can_filter *filter) { - struct can_npl_data *data = dev->data; + struct can_native_linux_data *data = dev->data; struct can_filter_context *filter_ctx; int filter_id = -ENOSPC; @@ -234,9 +234,9 @@ static int can_npl_add_rx_filter(const struct device *dev, can_rx_callback_t cb, return filter_id; } -static void can_npl_remove_rx_filter(const struct device *dev, int filter_id) +static void can_native_linux_remove_rx_filter(const struct device *dev, int filter_id) { - struct can_npl_data *data = dev->data; + struct can_native_linux_data *data = dev->data; if (filter_id < 0 || filter_id >= ARRAY_SIZE(data->filters)) { LOG_ERR("filter ID %d out of bounds"); @@ -250,7 +250,7 @@ static void can_npl_remove_rx_filter(const struct device *dev, int filter_id) LOG_DBG("Filter removed. ID: %d", filter_id); } -static int can_npl_get_capabilities(const struct device *dev, can_mode_t *cap) +static int can_native_linux_get_capabilities(const struct device *dev, can_mode_t *cap) { ARG_UNUSED(dev); @@ -263,9 +263,9 @@ static int can_npl_get_capabilities(const struct device *dev, can_mode_t *cap) return 0; } -static int can_npl_start(const struct device *dev) +static int can_native_linux_start(const struct device *dev) { - struct can_npl_data *data = dev->data; + struct can_native_linux_data *data = dev->data; if (data->started) { return -EALREADY; @@ -276,9 +276,9 @@ static int can_npl_start(const struct device *dev) return 0; } -static int can_npl_stop(const struct device *dev) +static int can_native_linux_stop(const struct device *dev) { - struct can_npl_data *data = dev->data; + struct can_native_linux_data *data = dev->data; if (!data->started) { return -EALREADY; @@ -289,9 +289,9 @@ static int can_npl_stop(const struct device *dev) return 0; } -static int can_npl_set_mode(const struct device *dev, can_mode_t mode) +static int can_native_linux_set_mode(const struct device *dev, can_mode_t mode) { - struct can_npl_data *data = dev->data; + struct can_native_linux_data *data = dev->data; #ifdef CONFIG_CAN_FD_MODE if ((mode & ~(CAN_MODE_LOOPBACK | CAN_MODE_FD)) != 0) { @@ -318,9 +318,9 @@ static int can_npl_set_mode(const struct device *dev, can_mode_t mode) return 0; } -static int can_npl_set_timing(const struct device *dev, const struct can_timing *timing) +static int can_native_linux_set_timing(const struct device *dev, const struct can_timing *timing) { - struct can_npl_data *data = dev->data; + struct can_native_linux_data *data = dev->data; ARG_UNUSED(timing); @@ -332,9 +332,10 @@ static int can_npl_set_timing(const struct device *dev, const struct can_timing } #ifdef CONFIG_CAN_FD_MODE -static int can_npl_set_timing_data(const struct device *dev, const struct can_timing *timing) +static int can_native_linux_set_timing_data(const struct device *dev, + const struct can_timing *timing) { - struct can_npl_data *data = dev->data; + struct can_native_linux_data *data = dev->data; ARG_UNUSED(timing); @@ -346,10 +347,10 @@ static int can_npl_set_timing_data(const struct device *dev, const struct can_ti } #endif /* CONFIG_CAN_FD_MODE */ -static int can_npl_get_state(const struct device *dev, enum can_state *state, - struct can_bus_err_cnt *err_cnt) +static int can_native_linux_get_state(const struct device *dev, enum can_state *state, + struct can_bus_err_cnt *err_cnt) { - struct can_npl_data *data = dev->data; + struct can_native_linux_data *data = dev->data; if (state != NULL) { if (!data->started) { @@ -369,9 +370,9 @@ static int can_npl_get_state(const struct device *dev, enum can_state *state, } #ifndef CONFIG_CAN_AUTO_BUS_OFF_RECOVERY -static int can_npl_recover(const struct device *dev, k_timeout_t timeout) +static int can_native_linux_recover(const struct device *dev, k_timeout_t timeout) { - struct can_npl_data *data = dev->data; + struct can_native_linux_data *data = dev->data; ARG_UNUSED(timeout); @@ -383,16 +384,16 @@ static int can_npl_recover(const struct device *dev, k_timeout_t timeout) } #endif /* CONFIG_CAN_AUTO_BUS_OFF_RECOVERY */ -static void can_npl_set_state_change_callback(const struct device *dev, - can_state_change_callback_t cb, - void *user_data) +static void can_native_linux_set_state_change_callback(const struct device *dev, + can_state_change_callback_t cb, + void *user_data) { ARG_UNUSED(dev); ARG_UNUSED(cb); ARG_UNUSED(user_data); } -static int can_npl_get_core_clock(const struct device *dev, uint32_t *rate) +static int can_native_linux_get_core_clock(const struct device *dev, uint32_t *rate) { /* Return 16MHz as an realistic value for the testcases */ *rate = 16000000; @@ -400,29 +401,29 @@ static int can_npl_get_core_clock(const struct device *dev, uint32_t *rate) return 0; } -static int can_npl_get_max_filters(const struct device *dev, bool ide) +static int can_native_linux_get_max_filters(const struct device *dev, bool ide) { ARG_UNUSED(ide); return CONFIG_CAN_MAX_FILTER; } -static const struct can_driver_api can_npl_driver_api = { - .start = can_npl_start, - .stop = can_npl_stop, - .get_capabilities = can_npl_get_capabilities, - .set_mode = can_npl_set_mode, - .set_timing = can_npl_set_timing, - .send = can_npl_send, - .add_rx_filter = can_npl_add_rx_filter, - .remove_rx_filter = can_npl_remove_rx_filter, - .get_state = can_npl_get_state, +static const struct can_driver_api can_native_linux_driver_api = { + .start = can_native_linux_start, + .stop = can_native_linux_stop, + .get_capabilities = can_native_linux_get_capabilities, + .set_mode = can_native_linux_set_mode, + .set_timing = can_native_linux_set_timing, + .send = can_native_linux_send, + .add_rx_filter = can_native_linux_add_rx_filter, + .remove_rx_filter = can_native_linux_remove_rx_filter, + .get_state = can_native_linux_get_state, #ifndef CONFIG_CAN_AUTO_BUS_OFF_RECOVERY - .recover = can_npl_recover, + .recover = can_native_linux_recover, #endif - .set_state_change_callback = can_npl_set_state_change_callback, - .get_core_clock = can_npl_get_core_clock, - .get_max_filters = can_npl_get_max_filters, + .set_state_change_callback = can_native_linux_set_state_change_callback, + .get_core_clock = can_native_linux_get_core_clock, + .get_max_filters = can_native_linux_get_max_filters, .timing_min = { .sjw = 0x1, .prop_seg = 0x01, @@ -438,7 +439,7 @@ static const struct can_driver_api can_npl_driver_api = { .prescaler = 0xFFFF }, #ifdef CONFIG_CAN_FD_MODE - .set_timing_data = can_npl_set_timing_data, + .set_timing_data = can_native_linux_set_timing_data, .timing_data_min = { .sjw = 0x1, .prop_seg = 0x01, @@ -456,10 +457,10 @@ static const struct can_driver_api can_npl_driver_api = { #endif /* CONFIG_CAN_FD_MODE */ }; -static int can_npl_init(const struct device *dev) +static int can_native_linux_init(const struct device *dev) { - const struct can_npl_config *cfg = dev->config; - struct can_npl_data *data = dev->data; + const struct can_native_linux_config *cfg = dev->config; + struct can_native_linux_data *data = dev->data; k_mutex_init(&data->filter_mutex); k_sem_init(&data->tx_idle, 1, 1); @@ -473,7 +474,7 @@ static int can_npl_init(const struct device *dev) k_thread_create(&data->rx_thread, data->rx_thread_stack, K_KERNEL_STACK_SIZEOF(data->rx_thread_stack), rx_thread, (void *)dev, NULL, NULL, - CONFIG_CAN_NATIVE_POSIX_LINUX_RX_THREAD_PRIORITY, + CONFIG_CAN_NATIVE_LINUX_RX_THREAD_PRIORITY, 0, K_NO_WAIT); LOG_DBG("Init of %s done", dev->name); @@ -481,17 +482,18 @@ static int can_npl_init(const struct device *dev) return 0; } -#define CAN_NATIVE_POSIX_LINUX_INIT(inst) \ +#define CAN_NATIVE_LINUX_INIT(inst) \ \ -static const struct can_npl_config can_npl_cfg_##inst = { \ +static const struct can_native_linux_config can_native_linux_cfg_##inst = { \ .if_name = DT_INST_PROP(inst, host_interface), \ }; \ \ -static struct can_npl_data can_npl_data_##inst; \ +static struct can_native_linux_data can_native_linux_data_##inst; \ \ -CAN_DEVICE_DT_INST_DEFINE(inst, can_npl_init, NULL, \ - &can_npl_data_##inst, &can_npl_cfg_##inst, \ +CAN_DEVICE_DT_INST_DEFINE(inst, can_native_linux_init, NULL, \ + &can_native_linux_data_##inst, \ + &can_native_linux_cfg_##inst, \ POST_KERNEL, CONFIG_CAN_INIT_PRIORITY, \ - &can_npl_driver_api); + &can_native_linux_driver_api); -DT_INST_FOREACH_STATUS_OKAY(CAN_NATIVE_POSIX_LINUX_INIT) +DT_INST_FOREACH_STATUS_OKAY(CAN_NATIVE_LINUX_INIT) diff --git a/drivers/can/can_native_posix_linux_socketcan.c b/drivers/can/can_native_linux_adapt.c similarity index 98% rename from drivers/can/can_native_posix_linux_socketcan.c rename to drivers/can/can_native_linux_adapt.c index 63b955e76e3..675dd01de79 100644 --- a/drivers/can/can_native_posix_linux_socketcan.c +++ b/drivers/can/can_native_linux_adapt.c @@ -34,7 +34,7 @@ #error "This driver can only be built on Linux systems" #endif -#include "can_native_posix_linux_socketcan.h" +#include "can_native_linux_adapt.h" #ifndef CANFD_FDF /* Linux kernels before v5.14 do not define CANFD_FDF */ diff --git a/drivers/can/can_native_posix_linux_socketcan.h b/drivers/can/can_native_linux_adapt.h similarity index 100% rename from drivers/can/can_native_posix_linux_socketcan.h rename to drivers/can/can_native_linux_adapt.h diff --git a/dts/bindings/can/zephyr,native-posix-linux-can.yaml b/dts/bindings/can/zephyr,native-linux-can.yaml similarity index 87% rename from dts/bindings/can/zephyr,native-posix-linux-can.yaml rename to dts/bindings/can/zephyr,native-linux-can.yaml index 275019a2c9e..4175617403b 100644 --- a/dts/bindings/can/zephyr,native-posix-linux-can.yaml +++ b/dts/bindings/can/zephyr,native-linux-can.yaml @@ -3,7 +3,7 @@ description: Zephyr CAN driver using Linux SocketCAN -compatible: "zephyr,native-posix-linux-can" +compatible: "zephyr,native-linux-can" include: can-controller.yaml diff --git a/tests/drivers/build_all/can/testcase.yaml b/tests/drivers/build_all/can/testcase.yaml index 6cce877620e..bf38398ed4b 100644 --- a/tests/drivers/build_all/can/testcase.yaml +++ b/tests/drivers/build_all/can/testcase.yaml @@ -19,7 +19,7 @@ tests: drivers.can.build_all.mcp251xfd: extra_args: SHIELD=mikroe_mcp2518fd_click platform_allow: lpcxpresso55s28 - drivers.can.build_all.native_posix_linux: + drivers.can.build_all.native_linux: platform_allow: - native_posix - native_posix_64 From 9104a804b9dc44377998bfe710201498ad973070 Mon Sep 17 00:00:00 2001 From: Jamie McCrae Date: Mon, 30 Oct 2023 17:14:40 +0000 Subject: [PATCH 1103/3723] sysbuild: Add pre_image and post_image hooks Adds hooks that run before and after every image has been configured Signed-off-by: Jamie McCrae --- share/sysbuild/CMakeLists.txt | 2 + .../cmake/modules/sysbuild_extensions.cmake | 41 ++++++++++++++----- 2 files changed, 33 insertions(+), 10 deletions(-) diff --git a/share/sysbuild/CMakeLists.txt b/share/sysbuild/CMakeLists.txt index 8a15da9cef5..9133fe874ef 100644 --- a/share/sysbuild/CMakeLists.txt +++ b/share/sysbuild/CMakeLists.txt @@ -38,7 +38,9 @@ get_property(IMAGES GLOBAL PROPERTY sysbuild_images) sysbuild_module_call(PRE_CMAKE MODULES ${SYSBUILD_MODULE_NAMES} IMAGES ${IMAGES}) sysbuild_images_order(IMAGES_CONFIGURATION_ORDER CONFIGURE IMAGES ${IMAGES}) foreach(image ${IMAGES_CONFIGURATION_ORDER}) + sysbuild_module_call(PRE_IMAGE_CMAKE MODULES ${SYSBUILD_MODULE_NAMES} IMAGES ${IMAGES} IMAGE ${image}) ExternalZephyrProject_Cmake(APPLICATION ${image}) + sysbuild_module_call(POST_IMAGE_CMAKE MODULES ${SYSBUILD_MODULE_NAMES} IMAGES ${IMAGES} IMAGE ${image}) endforeach() sysbuild_module_call(POST_CMAKE MODULES ${SYSBUILD_MODULE_NAMES} IMAGES ${IMAGES}) diff --git a/share/sysbuild/cmake/modules/sysbuild_extensions.cmake b/share/sysbuild/cmake/modules/sysbuild_extensions.cmake index 9250c209c50..980c54ef766 100644 --- a/share/sysbuild/cmake/modules/sysbuild_extensions.cmake +++ b/share/sysbuild/cmake/modules/sysbuild_extensions.cmake @@ -511,34 +511,55 @@ function(ExternalZephyrProject_Cmake) endfunction() # Usage: -# sysbuild_module_call( MODULES [IMAGES ] [EXTRA_ARGS ]) +# sysbuild_module_call( MODULES IMAGES [IMAGE ] [EXTRA_ARGS ]) # # This function invokes the sysbuild hook provided as for . # -# If `IMAGES` is passed, then the provided list of of images will be passed to -# the hook. +# `IMAGES` contains the list of images to the hook, if `IMAGE` is passed, this will be provided +# to the hook. # # `EXTRA_ARGS` can be used to pass extra arguments to the hook. # # Valid values: -# PRE_CMAKE : Invoke pre-CMake call for modules before CMake configure is invoked for images -# POST_CMAKE : Invoke post-CMake call for modules after CMake configure has been invoked for images -# PRE_DOMAINS : Invoke pre-domains call for modules before creating domains yaml. -# POST_DOMAINS: Invoke post-domains call for modules after creation of domains yaml. +# PRE_CMAKE : Invoke pre-CMake call for modules before CMake configure is invoked for images +# POST_CMAKE : Invoke post-CMake call for modules after CMake configure has been invoked for +# PRE_IMAGE_CMAKE : Invoke pre-CMake call for modules before CMake configure is invoked for each +# image +# POST_IMAGE_CMAKE: Invoke post-CMake call for modules after CMake configure has been invoked for +# each image +# PRE_DOMAINS : Invoke pre-domains call for modules before creating domains yaml +# POST_DOMAINS : Invoke post-domains call for modules after creation of domains yaml +# +# For the `PRE_IMAGE_CMAKE` and `POST_IMAGE_CMAKE` hooks, `IMAGE` is provided # function(sysbuild_module_call) - set(options "PRE_CMAKE;POST_CMAKE;PRE_DOMAINS;POST_DOMAINS") - set(multi_args "MODULES;IMAGES;EXTRA_ARGS") + set(options "PRE_CMAKE;POST_CMAKE;PRE_IMAGE_CMAKE;POST_IMAGE_CMAKE;PRE_DOMAINS;POST_DOMAINS") + set(multi_args "MODULES;IMAGES;IMAGE;EXTRA_ARGS") cmake_parse_arguments(SMC "${options}" "${test_args}" "${multi_args}" ${ARGN}) zephyr_check_flags_required("sysbuild_module_call" SMC ${options}) zephyr_check_flags_exclusive("sysbuild_module_call" SMC ${options}) + if(NOT DEFINED SMC_IMAGES) + message(FATAL_ERROR + "sysbuild_module_call(...) missing required IMAGES option") + endif() + + if(DEFINED SMC_IMAGE) + set(IMAGE_ARG IMAGE ${SMC_IMAGE}) + elseif(SMC_PRE_IMAGE_CMAKE) + message(FATAL_ERROR + "sysbuild_module_call(PRE_IMAGE_CMAKE ...) missing required IMAGE option") + elseif(SMC_POST_IMAGE_CMAKE) + message(FATAL_ERROR + "sysbuild_module_call(POST_IMAGE_CMAKE ...) missing required IMAGE option") + endif() + foreach(call ${options}) if(SMC_${call}) foreach(module ${SMC_MODULES}) if(COMMAND ${module}_${call}) - cmake_language(CALL ${module}_${call} IMAGES ${SMC_IMAGES} ${SMC_EXTRA_ARGS}) + cmake_language(CALL ${module}_${call} IMAGES ${SMC_IMAGES} ${IMAGE_ARG} ${SMC_EXTRA_ARGS}) endif() endforeach() endif() From b4640ecf0448e5abc44493113e6caae0c082cacf Mon Sep 17 00:00:00 2001 From: Jamie McCrae Date: Mon, 30 Oct 2023 17:15:19 +0000 Subject: [PATCH 1104/3723] sysbuild: images: mcuboot: Make application depend on bootloader Makes the MCUboot image configuration task run before the application image configuration, this is so information can be generated by MCUboot and then used in the application Signed-off-by: Jamie McCrae --- share/sysbuild/images/bootloader/CMakeLists.txt | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/share/sysbuild/images/bootloader/CMakeLists.txt b/share/sysbuild/images/bootloader/CMakeLists.txt index 2a0f12f958d..c82f0808c66 100644 --- a/share/sysbuild/images/bootloader/CMakeLists.txt +++ b/share/sysbuild/images/bootloader/CMakeLists.txt @@ -10,8 +10,8 @@ if(SB_CONFIG_BOOTLOADER_MCUBOOT) SOURCE_DIR ${ZEPHYR_MCUBOOT_MODULE_DIR}/boot/zephyr/ APP_TYPE BOOTLOADER ) - # MCUBoot default configuration is to perform a full chip erase. - # Placing MCUBoot first in list to ensure it is flashed before other images. + # Place MCUBoot first in list to ensure it is configured and flashed before other images. + sysbuild_add_dependencies(CONFIGURE ${DEFAULT_IMAGE} ${image}) sysbuild_add_dependencies(FLASH ${DEFAULT_IMAGE} ${image}) set_config_string(${image} CONFIG_BOOT_SIGNATURE_KEY_FILE "${SB_CONFIG_BOOT_SIGNATURE_KEY_FILE}") From 6bc93c8016429560cfed8f7f37e6f93c8761ec0e Mon Sep 17 00:00:00 2001 From: Jamie McCrae Date: Mon, 30 Oct 2023 17:13:43 +0000 Subject: [PATCH 1105/3723] west.yml: MCUboot synchronization from upstream Update Zephyr fork of MCUboot to revision: e9131ee8b8ab9306d8f6ad410fd1e3d8a820ce10 Brings following Zephyr relevant fixes: - e9131ee8 zephyr: kconfig: Make saving encrypt TLVs depending on encryption - 4c7942e5 zephyr: Add estimated image footer size to cache in sysbuild - 26d6423b boot: zephyr: esp32: zephyr port Signed-off-by: Jamie McCrae --- west.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/west.yml b/west.yml index 6400a94f14a..261740c1d26 100644 --- a/west.yml +++ b/west.yml @@ -282,7 +282,7 @@ manifest: groups: - crypto - name: mcuboot - revision: 212997395ed34ff1721f5f4461b800e81abeb68d + revision: e9131ee8b8ab9306d8f6ad410fd1e3d8a820ce10 path: bootloader/mcuboot - name: mipi-sys-t path: modules/debug/mipi-sys-t From 7c631f0fac7268b195914e7d0a762f16a46e4900 Mon Sep 17 00:00:00 2001 From: Jamie McCrae Date: Mon, 30 Oct 2023 17:16:31 +0000 Subject: [PATCH 1106/3723] kconfig: Add image size reduction option Adds a Kconfig option that can be used to reduce the available slot size of an application, this is useful for things like bootloaders whereby the bootloader or bootloader configuration reduces the available flash size that the image can occupy Signed-off-by: Jamie McCrae --- Kconfig.zephyr | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/Kconfig.zephyr b/Kconfig.zephyr index e1694173048..8b48eca6fcd 100644 --- a/Kconfig.zephyr +++ b/Kconfig.zephyr @@ -141,6 +141,17 @@ config ROM_START_OFFSET alignment requirements on most ARM targets, although some targets may require smaller or larger values. +config ROM_END_OFFSET + hex "ROM end offset" + default 0 + help + If non-zero, this option reduces the maximum size that the Zephyr image is allowed to + occupy, this is to allow for additional image storage which can be created and used by + other systems such as bootloaders (for MCUboot, this would include the image swap + fields and TLV storage at the end of the image). + + If unsure, leave at the default value 0. + config LD_LINKER_SCRIPT_SUPPORTED bool default y From 5031da95c6abf7f40a43286c946abbe2f65f2ce1 Mon Sep 17 00:00:00 2001 From: Jamie McCrae Date: Wed, 1 Nov 2023 09:55:59 +0000 Subject: [PATCH 1107/3723] cmake: linker: arm: Fix missing flash load size use Fixes a mismatch between the cmake and ld linker scripts whereby the cmake script was missing using the flash load size Kconfig option (if it was said), which would result in images far larger than they should have allowed to be Signed-off-by: Jamie McCrae --- cmake/linker_script/arm/linker.cmake | 15 +++++++++++---- 1 file changed, 11 insertions(+), 4 deletions(-) diff --git a/cmake/linker_script/arm/linker.cmake b/cmake/linker_script/arm/linker.cmake index 0c7310ab905..3610260afaf 100644 --- a/cmake/linker_script/arm/linker.cmake +++ b/cmake/linker_script/arm/linker.cmake @@ -16,10 +16,17 @@ math(EXPR FLASH_ADDR OUTPUT_FORMAT HEXADECIMAL ) -math(EXPR FLASH_SIZE - "(${CONFIG_FLASH_SIZE} + 0) * 1024 - (${CONFIG_FLASH_LOAD_OFFSET} + 0)" - OUTPUT_FORMAT HEXADECIMAL -) +if(CONFIG_FLASH_LOAD_SIZE GREATER 0) + math(EXPR FLASH_SIZE + "(${CONFIG_FLASH_LOAD_SIZE} + 0)" + OUTPUT_FORMAT HEXADECIMAL + ) +else() + math(EXPR FLASH_SIZE + "(${CONFIG_FLASH_SIZE} + 0) * 1024 - (${CONFIG_FLASH_LOAD_OFFSET} + 0)" + OUTPUT_FORMAT HEXADECIMAL + ) +endif() set(RAM_ADDR ${CONFIG_SRAM_BASE_ADDRESS}) math(EXPR RAM_SIZE "(${CONFIG_SRAM_SIZE} + 0) * 1024" OUTPUT_FORMAT HEXADECIMAL) From 2522a7856682ffff7965164c91aae53618d7c4b7 Mon Sep 17 00:00:00 2001 From: Jamie McCrae Date: Mon, 30 Oct 2023 17:17:40 +0000 Subject: [PATCH 1108/3723] linker: Add flash end ROM offset Reduces the size of an image in the linker script by using the ROM end offset Kconfig value Signed-off-by: Jamie McCrae --- cmake/linker_script/arm/linker.cmake | 4 ++-- include/zephyr/arch/arm/cortex_a_r/scripts/linker.ld | 10 ++++++++-- include/zephyr/arch/arm/cortex_m/scripts/linker.ld | 10 ++++++++-- include/zephyr/arch/arm64/scripts/linker.ld | 10 ++++++++-- include/zephyr/arch/nios2/linker.ld | 7 ++++++- include/zephyr/arch/riscv/common/linker.ld | 12 +++++++++--- include/zephyr/arch/x86/memory.ld | 8 +++++++- 7 files changed, 48 insertions(+), 13 deletions(-) diff --git a/cmake/linker_script/arm/linker.cmake b/cmake/linker_script/arm/linker.cmake index 3610260afaf..332d44b2435 100644 --- a/cmake/linker_script/arm/linker.cmake +++ b/cmake/linker_script/arm/linker.cmake @@ -18,12 +18,12 @@ math(EXPR FLASH_ADDR if(CONFIG_FLASH_LOAD_SIZE GREATER 0) math(EXPR FLASH_SIZE - "(${CONFIG_FLASH_LOAD_SIZE} + 0)" + "(${CONFIG_FLASH_LOAD_SIZE} + 0) - (${CONFIG_ROM_END_OFFSET} + 0)" OUTPUT_FORMAT HEXADECIMAL ) else() math(EXPR FLASH_SIZE - "(${CONFIG_FLASH_SIZE} + 0) * 1024 - (${CONFIG_FLASH_LOAD_OFFSET} + 0)" + "(${CONFIG_FLASH_SIZE} + 0) * 1024 - (${CONFIG_FLASH_LOAD_OFFSET} + 0) - (${CONFIG_ROM_END_OFFSET} + 0)" OUTPUT_FORMAT HEXADECIMAL ) endif() diff --git a/include/zephyr/arch/arm/cortex_a_r/scripts/linker.ld b/include/zephyr/arch/arm/cortex_a_r/scripts/linker.ld index a27dd55a8cf..48d0f1820c4 100644 --- a/include/zephyr/arch/arm/cortex_a_r/scripts/linker.ld +++ b/include/zephyr/arch/arm/cortex_a_r/scripts/linker.ld @@ -32,10 +32,16 @@ #define ROM_ADDR (CONFIG_FLASH_BASE_ADDRESS + CONFIG_FLASH_LOAD_OFFSET) #endif +#if defined(CONFIG_ROM_END_OFFSET) +#define ROM_END_OFFSET CONFIG_ROM_END_OFFSET +#else +#define ROM_END_OFFSET 0 +#endif + #if CONFIG_FLASH_LOAD_SIZE > 0 - #define ROM_SIZE CONFIG_FLASH_LOAD_SIZE + #define ROM_SIZE (CONFIG_FLASH_LOAD_SIZE - ROM_END_OFFSET) #else - #define ROM_SIZE (CONFIG_FLASH_SIZE*1K - CONFIG_FLASH_LOAD_OFFSET) + #define ROM_SIZE (CONFIG_FLASH_SIZE*1K - CONFIG_FLASH_LOAD_OFFSET - ROM_END_OFFSET) #endif #if defined(CONFIG_XIP) diff --git a/include/zephyr/arch/arm/cortex_m/scripts/linker.ld b/include/zephyr/arch/arm/cortex_m/scripts/linker.ld index 13c2747f5a3..9ed4009db91 100644 --- a/include/zephyr/arch/arm/cortex_m/scripts/linker.ld +++ b/include/zephyr/arch/arm/cortex_m/scripts/linker.ld @@ -32,10 +32,16 @@ #define ROM_ADDR (CONFIG_FLASH_BASE_ADDRESS + CONFIG_FLASH_LOAD_OFFSET) #endif +#if defined(CONFIG_ROM_END_OFFSET) +#define ROM_END_OFFSET CONFIG_ROM_END_OFFSET +#else +#define ROM_END_OFFSET 0 +#endif + #if CONFIG_FLASH_LOAD_SIZE > 0 -#define ROM_SIZE CONFIG_FLASH_LOAD_SIZE +#define ROM_SIZE (CONFIG_FLASH_LOAD_SIZE - ROM_END_OFFSET) #else -#define ROM_SIZE (CONFIG_FLASH_SIZE * 1024 - CONFIG_FLASH_LOAD_OFFSET) +#define ROM_SIZE (CONFIG_FLASH_SIZE * 1024 - CONFIG_FLASH_LOAD_OFFSET - ROM_END_OFFSET) #endif #if defined(CONFIG_XIP) diff --git a/include/zephyr/arch/arm64/scripts/linker.ld b/include/zephyr/arch/arm64/scripts/linker.ld index fa08b730304..38a7bac297b 100644 --- a/include/zephyr/arch/arm64/scripts/linker.ld +++ b/include/zephyr/arch/arm64/scripts/linker.ld @@ -31,10 +31,16 @@ #define ROM_ADDR (CONFIG_FLASH_BASE_ADDRESS + CONFIG_FLASH_LOAD_OFFSET) #endif +#if defined(CONFIG_ROM_END_OFFSET) +#define ROM_END_OFFSET CONFIG_ROM_END_OFFSET +#else +#define ROM_END_OFFSET 0 +#endif + #if CONFIG_FLASH_LOAD_SIZE > 0 - #define ROM_SIZE CONFIG_FLASH_LOAD_SIZE + #define ROM_SIZE (CONFIG_FLASH_LOAD_SIZE - ROM_END_OFFSET) #else - #define ROM_SIZE (CONFIG_FLASH_SIZE * 1K - CONFIG_FLASH_LOAD_OFFSET) + #define ROM_SIZE (CONFIG_FLASH_SIZE * 1K - CONFIG_FLASH_LOAD_OFFSET - ROM_END_OFFSET) #endif #define RAM_SIZE (CONFIG_SRAM_SIZE * 1K) diff --git a/include/zephyr/arch/nios2/linker.ld b/include/zephyr/arch/nios2/linker.ld index 6958533eaf6..f7ba64088fc 100644 --- a/include/zephyr/arch/nios2/linker.ld +++ b/include/zephyr/arch/nios2/linker.ld @@ -39,6 +39,11 @@ * the exception vector is in RAM */ +#if defined(CONFIG_ROM_END_OFFSET) +#define ROM_END_OFFSET CONFIG_ROM_END_OFFSET +#else +#define ROM_END_OFFSET 0 +#endif #ifdef CONFIG_XIP #define ROMABLE_REGION FLASH @@ -54,7 +59,7 @@ ASSERT(_RESET_VECTOR == _ROM_ADDR, "Reset vector not at beginning of ROM!") MEMORY { RESET (rx) : ORIGIN = _RESET_VECTOR, LENGTH = 0x20 - FLASH (rx) : ORIGIN = _RESET_VECTOR + 0x20 , LENGTH = (_ROM_SIZE - 0x20) + FLASH (rx) : ORIGIN = _RESET_VECTOR + 0x20 , LENGTH = (_ROM_SIZE - 0x20 - ROM_END_OFFSET) RAM (wx) : ORIGIN = _EXC_VECTOR, LENGTH = _RAM_SIZE - (_EXC_VECTOR - _RAM_ADDR) /* Used by and documented in include/linker/intlist.ld */ IDT_LIST (wx) : ORIGIN = 0xFFFFF7FF, LENGTH = 2K diff --git a/include/zephyr/arch/riscv/common/linker.ld b/include/zephyr/arch/riscv/common/linker.ld index eb5c4782441..38a254ba5ff 100644 --- a/include/zephyr/arch/riscv/common/linker.ld +++ b/include/zephyr/arch/riscv/common/linker.ld @@ -30,6 +30,12 @@ #define _EXCEPTION_SECTION_NAME exceptions #define _RESET_SECTION_NAME reset +#if defined(CONFIG_ROM_END_OFFSET) +#define ROM_END_OFFSET CONFIG_ROM_END_OFFSET +#else +#define ROM_END_OFFSET 0 +#endif + #ifdef CONFIG_XIP #if DT_NODE_HAS_COMPAT_STATUS(DT_CHOSEN(zephyr_flash), soc_nv_flash, okay) #ifdef CONFIG_FLASH_LOAD_OFFSET @@ -38,7 +44,7 @@ #else /* !CONFIG_FLASH_LOAD_OFFSET */ #define ROM_BASE DT_REG_ADDR(DT_CHOSEN(zephyr_flash)) #endif /* CONFIG_FLASH_LOAD_OFFSET */ -#define ROM_SIZE DT_REG_SIZE(DT_CHOSEN(zephyr_flash)) +#define ROM_SIZE (DT_REG_SIZE(DT_CHOSEN(zephyr_flash)) - ROM_END_OFFSET) #elif DT_NODE_HAS_COMPAT(DT_CHOSEN(zephyr_flash), jedec_spi_nor) /* For jedec,spi-nor we expect the spi controller to memory map the flash * and for that mapping to be the second register property of the spi @@ -46,11 +52,11 @@ */ #define SPI_CTRL DT_PARENT(DT_CHOSEN(zephyr_flash)) #define ROM_BASE DT_REG_ADDR_BY_IDX(SPI_CTRL, 1) -#define ROM_SIZE DT_REG_SIZE_BY_IDX(SPI_CTRL, 1) +#define ROM_SIZE (DT_REG_SIZE_BY_IDX(SPI_CTRL, 1) - ROM_END_OFFSET) #endif #else /* CONFIG_XIP */ #define ROM_BASE CONFIG_SRAM_BASE_ADDRESS -#define ROM_SIZE KB(CONFIG_SRAM_SIZE) +#define ROM_SIZE (KB(CONFIG_SRAM_SIZE) - ROM_END_OFFSET) #endif /* CONFIG_XIP */ #define RAM_BASE CONFIG_SRAM_BASE_ADDRESS diff --git a/include/zephyr/arch/x86/memory.ld b/include/zephyr/arch/x86/memory.ld index 72b400dd079..c9ede2b9d23 100644 --- a/include/zephyr/arch/x86/memory.ld +++ b/include/zephyr/arch/x86/memory.ld @@ -50,12 +50,18 @@ /* "kernel RAM" for linker VMA allocations starts at the offset */ +#if defined(CONFIG_ROM_END_OFFSET) +#define ROM_END_OFFSET CONFIG_ROM_END_OFFSET +#else +#define ROM_END_OFFSET 0 +#endif + #ifdef CONFIG_XIP /* "ROM" is flash, we leave rodata and text there and just copy in data. * Board-level DTS must specify a flash region that doesn't overlap with * sram0, so that DT_PHYS_LOAD_ADDR is set. */ - #define FLASH_ROM_SIZE DT_REG_SIZE(DT_CHOSEN(zephyr_flash)) + #define FLASH_ROM_SIZE (DT_REG_SIZE(DT_CHOSEN(zephyr_flash)) - ROM_END_OFFSET) #define PHYS_LOAD_ADDR DT_REG_ADDR(DT_CHOSEN(zephyr_flash)) #else /* Physical RAM location where the kernel image is loaded */ From 648e2a3db1c5b71f8aed544caa51068a3aa8591b Mon Sep 17 00:00:00 2001 From: Jamie McCrae Date: Tue, 12 Dec 2023 10:06:44 +0000 Subject: [PATCH 1109/3723] doc: release: 3.6: Add note on changes with build system Adds notes on changes introduced with sysbuild Signed-off-by: Jamie McCrae --- doc/releases/release-notes-3.6.rst | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/doc/releases/release-notes-3.6.rst b/doc/releases/release-notes-3.6.rst index f5f55ecd92b..ec032548a9b 100644 --- a/doc/releases/release-notes-3.6.rst +++ b/doc/releases/release-notes-3.6.rst @@ -126,6 +126,16 @@ Build system and infrastructure * Fixed an issue whereby board revision ``0`` did not include overlay files for that revision. +* Added ``PRE_IMAGE_CMAKE`` and ``POST_IMAGE_CMAKE`` hooks to sysbuild modules, which allows for + modules to run code after and before each image's cmake invocation. + +* Added :kconfig:option:`CONFIG_ROM_END_OFFSET` option which allows reducing the size of an image, + this is intended for use with firmware signing scripts which add additional data to the end of + images outside of the build itself. + +* Added MCUboot image size reduction to sysbuild images which include MCUboot which prevents + issues with building firmware images that are too large for MCUboot to swap. + Drivers and Sensors ******************* From 90770afa23ff234c2b5219b674e931a0935faf28 Mon Sep 17 00:00:00 2001 From: Mariusz Skamra Date: Tue, 5 Dec 2023 10:42:55 +0100 Subject: [PATCH 1110/3723] tests: bsim: gatt: ccc_store: Replace bt_gatt_write with bt_gatt_subscribe This changes the way the GATT Client subscribes to the characteristic value changes. The bt_gatt_write usage was replaced by dedicated bt_gatt_subscribe API function call, so that the test verifies the GATT Client API side as well. Signed-off-by: Mariusz Skamra --- .../host/gatt/ccc_store/src/central.c | 54 +++++++------------ .../host/gatt/ccc_store/src/common.h | 1 + .../host/gatt/ccc_store/src/peripheral.c | 8 ++- 3 files changed, 27 insertions(+), 36 deletions(-) diff --git a/tests/bsim/bluetooth/host/gatt/ccc_store/src/central.c b/tests/bsim/bluetooth/host/gatt/ccc_store/src/central.c index 3b279a50fab..80d64eb646b 100644 --- a/tests/bsim/bluetooth/host/gatt/ccc_store/src/central.c +++ b/tests/bsim/bluetooth/host/gatt/ccc_store/src/central.c @@ -37,57 +37,43 @@ static struct bt_conn *default_conn; static struct bt_conn_cb central_cb; -CREATE_FLAG(gatt_write_flag); -static uint8_t gatt_write_att_err; +CREATE_FLAG(gatt_subscribe_flag); -static void gatt_write_cb(struct bt_conn *conn, uint8_t att_err, - struct bt_gatt_write_params *params) +static uint8_t notify_cb(struct bt_conn *conn, struct bt_gatt_subscribe_params *params, + const void *data, uint16_t length) { - gatt_write_att_err = att_err; - - if (att_err) { - return; - } - - SET_FLAG(gatt_write_flag); + return BT_GATT_ITER_CONTINUE; } -static int gatt_write(struct bt_conn *conn, uint16_t handle, const uint8_t *write_buf, - size_t write_size) +static void subscribe_cb(struct bt_conn *conn, uint8_t err, struct bt_gatt_subscribe_params *params) { - int err; - struct bt_gatt_write_params params; - - params.func = gatt_write_cb; - params.handle = handle; - params.offset = 0; - params.data = write_buf; - params.length = write_size; - - UNSET_FLAG(gatt_write_flag); - - /* `bt_gatt_write` is used instead of `bt_gatt_subscribe` and - * `bt_gatt_unsubscribe` to bypass subscribtion checks of GATT client - */ - err = bt_gatt_write(conn, ¶ms); if (err) { - FAIL("GATT write failed (err %d)", err); + return; } - WAIT_FOR_FLAG(gatt_write_flag); - - return gatt_write_att_err; + SET_FLAG(gatt_subscribe_flag); } +static struct bt_gatt_subscribe_params subscribe_params; + static void ccc_subscribe(void) { int err; - uint8_t buf = 1; - err = gatt_write(default_conn, CCC_HANDLE, &buf, sizeof(buf)); + UNSET_FLAG(gatt_subscribe_flag); + + subscribe_params.notify = notify_cb; + subscribe_params.subscribe = subscribe_cb; + subscribe_params.ccc_handle = CCC_HANDLE; + subscribe_params.value_handle = VAL_HANDLE; + subscribe_params.value = BT_GATT_CCC_NOTIFY; + + err = bt_gatt_subscribe(default_conn, &subscribe_params); if (err) { FAIL("Failed to subscribe (att err %d)", err); } + + WAIT_FOR_FLAG(gatt_subscribe_flag); } static void device_found(const bt_addr_le_t *addr, int8_t rssi, uint8_t type, diff --git a/tests/bsim/bluetooth/host/gatt/ccc_store/src/common.h b/tests/bsim/bluetooth/host/gatt/ccc_store/src/common.h index 2371e976b69..c4c8f9c4ff0 100644 --- a/tests/bsim/bluetooth/host/gatt/ccc_store/src/common.h +++ b/tests/bsim/bluetooth/host/gatt/ccc_store/src/common.h @@ -44,6 +44,7 @@ LOG_MODULE_DECLARE(bt_bsim_ccc_store, LOG_LEVEL_DBG); BT_UUID_128_ENCODE(0x2e2b8dc3, 0x06e0, 0x4f93, 0x9bb2, 0x734091c356f3) #define BT_UUID_DUMMY_SERVICE_NOTIFY BT_UUID_DECLARE_128(DUMMY_SERVICE_NOTIFY_TYPE) +#define VAL_HANDLE 18 #define CCC_HANDLE 19 #define BC_MSG_SIZE 2 diff --git a/tests/bsim/bluetooth/host/gatt/ccc_store/src/peripheral.c b/tests/bsim/bluetooth/host/gatt/ccc_store/src/peripheral.c index 3555e453d55..7efa0220489 100644 --- a/tests/bsim/bluetooth/host/gatt/ccc_store/src/peripheral.c +++ b/tests/bsim/bluetooth/host/gatt/ccc_store/src/peripheral.c @@ -233,10 +233,14 @@ static void check_ccc_handle(void) struct bt_gatt_attr *service_notify_attr = bt_gatt_find_by_uuid(NULL, 0, ¬ify_characteristic_uuid.uuid); + uint16_t actual_val_handle = bt_gatt_attr_get_handle(service_notify_attr); + + __ASSERT(actual_val_handle == VAL_HANDLE, + "Please update the VAL_HANDLE define (actual_val_handle=%d)", actual_val_handle); + struct bt_gatt_attr attr = { .uuid = BT_UUID_GATT_CHRC, - .user_data = &(struct bt_gatt_chrc){ - .value_handle = bt_gatt_attr_get_handle(service_notify_attr)}}; + .user_data = &(struct bt_gatt_chrc){ .value_handle = actual_val_handle }}; struct bt_gatt_attr *ccc_attr = bt_gatt_find_by_uuid(&attr, 0, BT_UUID_GATT_CCC); uint16_t actual_ccc_handle = bt_gatt_attr_get_handle(ccc_attr); From 3b4ce7f8e9677bd43b4522231457ce10057a484c Mon Sep 17 00:00:00 2001 From: Mariusz Skamra Date: Tue, 5 Dec 2023 11:26:41 +0100 Subject: [PATCH 1111/3723] tests: bsim: gatt: ccc_store: Reproduce the subscription lost issue Zephyr by default renews the characteristic value subscription on every reconnection. If the ACL is disconnected in the middle of this procedure, all the subscriptions waiting to be renewed are removed, even if the device was successfully subscribed already. Signed-off-by: Mariusz Skamra --- .../host/gatt/ccc_store/src/central.c | 45 ++++++++++++++++--- .../bluetooth/host/gatt/ccc_store/src/main.c | 19 ++++++-- .../host/gatt/ccc_store/src/peripheral.c | 27 +++++++++-- .../gatt/ccc_store/test_scripts/ccc_store.sh | 8 ++-- .../ccc_store/test_scripts/ccc_store_2.sh | 8 ++-- 5 files changed, 85 insertions(+), 22 deletions(-) diff --git a/tests/bsim/bluetooth/host/gatt/ccc_store/src/central.c b/tests/bsim/bluetooth/host/gatt/ccc_store/src/central.c index 80d64eb646b..0784a5e587d 100644 --- a/tests/bsim/bluetooth/host/gatt/ccc_store/src/central.c +++ b/tests/bsim/bluetooth/host/gatt/ccc_store/src/central.c @@ -29,6 +29,7 @@ CREATE_FLAG(connected_flag); CREATE_FLAG(disconnected_flag); CREATE_FLAG(security_updated_flag); +CREATE_FLAG(notification_received_flag); #define BT_UUID_DUMMY_SERVICE BT_UUID_DECLARE_128(DUMMY_SERVICE_TYPE) #define BT_UUID_DUMMY_SERVICE_NOTIFY BT_UUID_DECLARE_128(DUMMY_SERVICE_NOTIFY_TYPE) @@ -37,11 +38,28 @@ static struct bt_conn *default_conn; static struct bt_conn_cb central_cb; -CREATE_FLAG(gatt_subscribe_flag); +CREATE_FLAG(gatt_subscribed_flag); static uint8_t notify_cb(struct bt_conn *conn, struct bt_gatt_subscribe_params *params, const void *data, uint16_t length) { + uint8_t value; + + if (conn == NULL || data == NULL) { + /* Peer unpaired or subscription was removed */ + UNSET_FLAG(gatt_subscribed_flag); + + return BT_GATT_ITER_STOP; + } + + __ASSERT_NO_MSG(length == sizeof(value)); + + value = *(uint8_t *)data; + + LOG_DBG("#%d notification received", value); + + SET_FLAG(notification_received_flag); + return BT_GATT_ITER_CONTINUE; } @@ -51,7 +69,7 @@ static void subscribe_cb(struct bt_conn *conn, uint8_t err, struct bt_gatt_subsc return; } - SET_FLAG(gatt_subscribe_flag); + SET_FLAG(gatt_subscribed_flag); } static struct bt_gatt_subscribe_params subscribe_params; @@ -60,7 +78,7 @@ static void ccc_subscribe(void) { int err; - UNSET_FLAG(gatt_subscribe_flag); + UNSET_FLAG(gatt_subscribed_flag); subscribe_params.notify = notify_cb; subscribe_params.subscribe = subscribe_cb; @@ -73,7 +91,7 @@ static void ccc_subscribe(void) FAIL("Failed to subscribe (att err %d)", err); } - WAIT_FOR_FLAG(gatt_subscribe_flag); + WAIT_FOR_FLAG(gatt_subscribed_flag); } static void device_found(const bt_addr_le_t *addr, int8_t rssi, uint8_t type, @@ -200,6 +218,9 @@ static void connect_pair_subscribe(void) backchannel_sync_send(SERVER_CHAN, SERVER_ID); /* wait for server to check that the subscribtion is well registered */ backchannel_sync_wait(SERVER_CHAN, SERVER_ID); + + WAIT_FOR_FLAG(notification_received_flag); + UNSET_FLAG(notification_received_flag); } static void connect_restore_sec(void) @@ -219,10 +240,18 @@ static void connect_restore_sec(void) WAIT_FOR_FLAG(security_updated_flag); UNSET_FLAG(security_updated_flag); + /* check local subscription state */ + if (GET_FLAG(gatt_subscribed_flag) == false) { + FAIL("Not subscribed\n"); + } + /* notify the end of security update to server */ backchannel_sync_send(SERVER_CHAN, SERVER_ID); /* wait for server to check that the subscribtion has been restored */ backchannel_sync_wait(SERVER_CHAN, SERVER_ID); + + WAIT_FOR_FLAG(notification_received_flag); + UNSET_FLAG(notification_received_flag); } /* Util functions */ @@ -256,7 +285,7 @@ static void set_public_addr(void) /* Main functions */ -void run_central(void) +void run_central(int times) { int err; @@ -289,8 +318,10 @@ void run_central(void) connect_pair_subscribe(); disconnect(); - connect_restore_sec(); - disconnect(); + for (int i = 0; i < times; i++) { + connect_restore_sec(); + disconnect(); + } PASS("Central test passed\n"); } diff --git a/tests/bsim/bluetooth/host/gatt/ccc_store/src/main.c b/tests/bsim/bluetooth/host/gatt/ccc_store/src/main.c index 62cddb4c96c..c1090382dc6 100644 --- a/tests/bsim/bluetooth/host/gatt/ccc_store/src/main.c +++ b/tests/bsim/bluetooth/host/gatt/ccc_store/src/main.c @@ -30,17 +30,19 @@ extern enum bst_result_t bst_result; #define WAIT_TIME_S 60 #define WAIT_TIME (WAIT_TIME_S * 1e6) -extern void run_peripheral(void); -extern void run_central(void); +static int n_times; + +extern void run_peripheral(int times); +extern void run_central(int times); static void central_main(void) { - run_central(); + run_central(n_times); } static void peripheral_main(void) { - run_peripheral(); + run_peripheral(n_times); } void test_tick(bs_time_t HW_device_time) @@ -52,6 +54,13 @@ void test_tick(bs_time_t HW_device_time) } } +static void test_args(int argc, char **argv) +{ + __ASSERT(argc == 1, "Please specify only 1 test argument\n"); + + n_times = atol(argv[0]); +} + static void test_ccc_store_init(void) { bst_ticker_set_next_tick_absolute(WAIT_TIME); @@ -64,6 +73,7 @@ static const struct bst_test_instance test_def[] = { .test_post_init_f = test_ccc_store_init, .test_tick_f = test_tick, .test_main_f = central_main, + .test_args_f = test_args, }, { .test_id = "peripheral", @@ -71,6 +81,7 @@ static const struct bst_test_instance test_def[] = { .test_post_init_f = test_ccc_store_init, .test_tick_f = test_tick, .test_main_f = peripheral_main, + .test_args_f = test_args, }, BSTEST_END_MARKER}; diff --git a/tests/bsim/bluetooth/host/gatt/ccc_store/src/peripheral.c b/tests/bsim/bluetooth/host/gatt/ccc_store/src/peripheral.c index 7efa0220489..03344852af9 100644 --- a/tests/bsim/bluetooth/host/gatt/ccc_store/src/peripheral.c +++ b/tests/bsim/bluetooth/host/gatt/ccc_store/src/peripheral.c @@ -161,6 +161,21 @@ static bool is_peer_subscribed(struct bt_conn *conn) /* Test steps */ +static void send_value_notification(void) +{ + const struct bt_gatt_attr *attr = bt_gatt_find_by_uuid(NULL, 0, + ¬ify_characteristic_uuid.uuid); + static uint8_t value; + int err; + + err = bt_gatt_notify(default_conn, attr, &value, sizeof(value)); + if (err != 0) { + FAIL("Failed to send notification (err %d)\n", err); + } + + value++; +} + static void connect_pair_check_subscribtion(struct bt_le_ext_adv *adv) { start_adv(adv); @@ -182,6 +197,8 @@ static void connect_pair_check_subscribtion(struct bt_le_ext_adv *adv) /* confirm to client that the subscribtion has been well registered */ backchannel_sync_send(CLIENT_CHAN, CLIENT_ID); + + send_value_notification(); } static void connect_restore_sec_check_subscribtion(struct bt_le_ext_adv *adv) @@ -205,6 +222,8 @@ static void connect_restore_sec_check_subscribtion(struct bt_le_ext_adv *adv) /* confirm to good client that the subscribtion has been well restored */ backchannel_sync_send(CLIENT_CHAN, CLIENT_ID); + + send_value_notification(); } /* Util functions */ @@ -251,7 +270,7 @@ static void check_ccc_handle(void) /* Main function */ -void run_peripheral(void) +void run_peripheral(int times) { int err; struct bt_le_ext_adv *adv = NULL; @@ -288,8 +307,10 @@ void run_peripheral(void) connect_pair_check_subscribtion(adv); WAIT_FOR_FLAG(disconnected_flag); - connect_restore_sec_check_subscribtion(adv); - WAIT_FOR_FLAG(disconnected_flag); + for (int i = 0; i < times; i++) { + connect_restore_sec_check_subscribtion(adv); + WAIT_FOR_FLAG(disconnected_flag); + } PASS("Peripheral test passed\n"); } diff --git a/tests/bsim/bluetooth/host/gatt/ccc_store/test_scripts/ccc_store.sh b/tests/bsim/bluetooth/host/gatt/ccc_store/test_scripts/ccc_store.sh index 240a0771d1e..76480a4ae32 100755 --- a/tests/bsim/bluetooth/host/gatt/ccc_store/test_scripts/ccc_store.sh +++ b/tests/bsim/bluetooth/host/gatt/ccc_store/test_scripts/ccc_store.sh @@ -15,13 +15,13 @@ cd ${BSIM_OUT_PATH}/bin if [ "${1}" != 'debug0' ]; then Execute "./${test_exe}" \ -v=${verbosity_level} -s=${simulation_id} -d=0 -testid=central \ - -flash="${simulation_id}_client.log.bin" -flash_rm + -flash="${simulation_id}_client.log.bin" -flash_rm -argstest 10 fi if [ "${1}" != 'debug1' ]; then Execute "./${test_exe}" \ -v=${verbosity_level} -s=${simulation_id} -d=1 -testid=peripheral \ - -flash="${simulation_id}_server.log.bin" -flash_rm + -flash="${simulation_id}_server.log.bin" -flash_rm -argstest 10 fi Execute ./bs_2G4_phy_v1 -v=${verbosity_level} -s=${simulation_id} \ @@ -30,13 +30,13 @@ Execute ./bs_2G4_phy_v1 -v=${verbosity_level} -s=${simulation_id} \ if [ "${1}" == 'debug0' ]; then gdb --args "./${test_exe}" \ -v=${verbosity_level} -s=${simulation_id} -d=0 -testid=central \ - -flash="${simulation_id}_client.log.bin" -flash_rm + -flash="${simulation_id}_client.log.bin" -flash_rm -argstest 10 fi if [ "${1}" == 'debug1' ]; then gdb --args "./${test_exe}" \ -v=${verbosity_level} -s=${simulation_id} -d=1 -testid=peripheral \ - -flash="${simulation_id}_server.log.bin" -flash_rm + -flash="${simulation_id}_server.log.bin" -flash_rm -argstest 10 fi wait_for_background_jobs diff --git a/tests/bsim/bluetooth/host/gatt/ccc_store/test_scripts/ccc_store_2.sh b/tests/bsim/bluetooth/host/gatt/ccc_store/test_scripts/ccc_store_2.sh index 6c5ec02a5f3..d6bb2a18d73 100755 --- a/tests/bsim/bluetooth/host/gatt/ccc_store/test_scripts/ccc_store_2.sh +++ b/tests/bsim/bluetooth/host/gatt/ccc_store/test_scripts/ccc_store_2.sh @@ -15,13 +15,13 @@ cd ${BSIM_OUT_PATH}/bin if [ "${1}" != 'debug0' ]; then Execute "./${test_exe}" \ -v=${verbosity_level} -s=${simulation_id} -d=0 -testid=central \ - -flash="${simulation_id}_client.log.bin" -flash_rm + -flash="${simulation_id}_client.log.bin" -flash_rm -argstest 10 fi if [ "${1}" != 'debug1' ]; then Execute "./${test_exe}" \ -v=${verbosity_level} -s=${simulation_id} -d=1 -testid=peripheral \ - -flash="${simulation_id}_server.log.bin" -flash_rm + -flash="${simulation_id}_server.log.bin" -flash_rm -argstest 10 fi Execute ./bs_2G4_phy_v1 -v=${verbosity_level} -s=${simulation_id} \ @@ -30,13 +30,13 @@ Execute ./bs_2G4_phy_v1 -v=${verbosity_level} -s=${simulation_id} \ if [ "${1}" == 'debug0' ]; then gdb --args "./${test_exe}" \ -v=${verbosity_level} -s=${simulation_id} -d=0 -testid=central \ - -flash="${simulation_id}_client.log.bin" -flash_rm + -flash="${simulation_id}_client.log.bin" -flash_rm -argstest 10 fi if [ "${1}" == 'debug1' ]; then gdb --args "./${test_exe}" \ -v=${verbosity_level} -s=${simulation_id} -d=1 -testid=peripheral \ - -flash="${simulation_id}_server.log.bin" -flash_rm + -flash="${simulation_id}_server.log.bin" -flash_rm -argstest 10 fi wait_for_background_jobs From ddf172c18714f0ef81e62aa8d702f60825f6b8ca Mon Sep 17 00:00:00 2001 From: Mariusz Skamra Date: Tue, 5 Dec 2023 14:07:45 +0100 Subject: [PATCH 1112/3723] Bluetooth: gatt: Fix automatic resubscription causing CCC removal This fixes CCC subscriptions that were removed if the automatic resubscription was aborted by ACL disconnection. As the client renews subscriptions, there is no point of removing those if the link is disconnected unexpectedly. The API user won't be notified about the failure, as the automatic resubscriptions are implicit, and after reconnection the subscriptions will be still valid. Signed-off-by: Mariusz Skamra --- subsys/bluetooth/host/att.c | 8 +- subsys/bluetooth/host/att_internal.h | 2 +- subsys/bluetooth/host/gatt.c | 120 ++++++++++++++++++--------- 3 files changed, 88 insertions(+), 42 deletions(-) diff --git a/subsys/bluetooth/host/att.c b/subsys/bluetooth/host/att.c index 6bae608ff55..62cce595ec6 100644 --- a/subsys/bluetooth/host/att.c +++ b/subsys/bluetooth/host/att.c @@ -921,12 +921,12 @@ static void att_req_send_process(struct bt_att *att) } static uint8_t att_handle_rsp(struct bt_att_chan *chan, void *pdu, uint16_t len, - uint8_t err) + int err) { bt_att_func_t func = NULL; void *params; - LOG_DBG("chan %p err 0x%02x len %u: %s", chan, err, len, bt_hex(pdu, len)); + LOG_DBG("chan %p err %d len %u: %s", chan, err, len, bt_hex(pdu, len)); /* Cancel timeout if ongoing */ k_work_cancel_delayable(&chan->timeout_work); @@ -3012,7 +3012,7 @@ static void att_reset(struct bt_att *att) node = sys_slist_get_not_empty(&att->reqs); req = CONTAINER_OF(node, struct bt_att_req, node); if (req->func) { - req->func(att->conn, BT_ATT_ERR_UNLIKELY, NULL, 0, + req->func(att->conn, -ECONNRESET, NULL, 0, req->user_data); } @@ -3042,7 +3042,7 @@ static void att_chan_detach(struct bt_att_chan *chan) if (chan->req) { /* Notify outstanding request */ - att_handle_rsp(chan, NULL, 0, BT_ATT_ERR_UNLIKELY); + att_handle_rsp(chan, NULL, 0, -ECONNRESET); } chan->att = NULL; diff --git a/subsys/bluetooth/host/att_internal.h b/subsys/bluetooth/host/att_internal.h index a45184a59c7..de8f49276ad 100644 --- a/subsys/bluetooth/host/att_internal.h +++ b/subsys/bluetooth/host/att_internal.h @@ -270,7 +270,7 @@ struct bt_att_signed_write_cmd { uint8_t value[0]; } __packed; -typedef void (*bt_att_func_t)(struct bt_conn *conn, uint8_t err, +typedef void (*bt_att_func_t)(struct bt_conn *conn, int err, const void *pdu, uint16_t length, void *user_data); diff --git a/subsys/bluetooth/host/gatt.c b/subsys/bluetooth/host/gatt.c index 19295fbde9e..0012fb3b7d5 100644 --- a/subsys/bluetooth/host/gatt.c +++ b/subsys/bluetooth/host/gatt.c @@ -2469,13 +2469,26 @@ static int gatt_notify(struct bt_conn *conn, uint16_t handle, return bt_att_send(conn, buf); } -static void gatt_indicate_rsp(struct bt_conn *conn, uint8_t err, +/* Converts error (negative errno) to ATT Error code */ +static uint8_t att_err_from_int(int err) +{ + LOG_DBG("%d", err); + + /* ATT error codes are 1 byte values, so any value outside the range is unknown */ + if (!IN_RANGE(err, 0, UINT8_MAX)) { + return BT_ATT_ERR_UNLIKELY; + } + + return err; +} + +static void gatt_indicate_rsp(struct bt_conn *conn, int err, const void *pdu, uint16_t length, void *user_data) { struct bt_gatt_indicate_params *params = user_data; if (params->func) { - params->func(conn, params, err); + params->func(conn, params, att_err_from_int(err)); } params->_ref--; @@ -3624,12 +3637,12 @@ static void remove_subscriptions(struct bt_conn *conn) } } -static void gatt_mtu_rsp(struct bt_conn *conn, uint8_t err, const void *pdu, +static void gatt_mtu_rsp(struct bt_conn *conn, int err, const void *pdu, uint16_t length, void *user_data) { struct bt_gatt_exchange_params *params = user_data; - params->func(conn, err, params); + params->func(conn, att_err_from_int(err), params); } static int gatt_exchange_mtu_encode(struct net_buf *buf, size_t len, @@ -3706,7 +3719,7 @@ static void gatt_discover_next(struct bt_conn *conn, uint16_t last_handle, params->func(conn, NULL, params); } -static void gatt_find_type_rsp(struct bt_conn *conn, uint8_t err, +static void gatt_find_type_rsp(struct bt_conn *conn, int err, const void *pdu, uint16_t length, void *user_data) { @@ -3715,7 +3728,7 @@ static void gatt_find_type_rsp(struct bt_conn *conn, uint8_t err, uint8_t count; uint16_t end_handle = 0U, start_handle; - LOG_DBG("err 0x%02x", err); + LOG_DBG("err %d", err); if (err || (length % sizeof(struct bt_att_handle_group) != 0)) { goto done; @@ -3820,7 +3833,7 @@ static int gatt_find_type(struct bt_conn *conn, len, BT_ATT_CHAN_OPT(params)); } -static void read_included_uuid_cb(struct bt_conn *conn, uint8_t err, +static void read_included_uuid_cb(struct bt_conn *conn, int err, const void *pdu, uint16_t length, void *user_data) { @@ -4144,14 +4157,14 @@ static uint16_t parse_read_std_char_desc(struct bt_conn *conn, const void *pdu, return 0; } -static void gatt_read_type_rsp(struct bt_conn *conn, uint8_t err, +static void gatt_read_type_rsp(struct bt_conn *conn, int err, const void *pdu, uint16_t length, void *user_data) { struct bt_gatt_discover_params *params = user_data; uint16_t handle; - LOG_DBG("err 0x%02x", err); + LOG_DBG("err %d", err); if (err) { params->func(conn, NULL, params); @@ -4294,14 +4307,14 @@ static uint16_t parse_service(struct bt_conn *conn, const void *pdu, return 0; } -static void gatt_read_group_rsp(struct bt_conn *conn, uint8_t err, +static void gatt_read_group_rsp(struct bt_conn *conn, int err, const void *pdu, uint16_t length, void *user_data) { struct bt_gatt_discover_params *params = user_data; uint16_t handle; - LOG_DBG("err 0x%02x", err); + LOG_DBG("err %d", err); if (err) { params->func(conn, NULL, params); @@ -4347,7 +4360,7 @@ static int gatt_read_group(struct bt_conn *conn, BT_ATT_CHAN_OPT(params)); } -static void gatt_find_info_rsp(struct bt_conn *conn, uint8_t err, +static void gatt_find_info_rsp(struct bt_conn *conn, int err, const void *pdu, uint16_t length, void *user_data) { @@ -4367,7 +4380,7 @@ static void gatt_find_info_rsp(struct bt_conn *conn, uint8_t err, int i; bool skip = false; - LOG_DBG("err 0x%02x", err); + LOG_DBG("err %d", err); if (err) { goto done; @@ -4592,15 +4605,15 @@ static void parse_read_by_uuid(struct bt_conn *conn, } } -static void gatt_read_rsp(struct bt_conn *conn, uint8_t err, const void *pdu, +static void gatt_read_rsp(struct bt_conn *conn, int err, const void *pdu, uint16_t length, void *user_data) { struct bt_gatt_read_params *params = user_data; - LOG_DBG("err 0x%02x", err); + LOG_DBG("err %d", err); if (err || !length) { - params->func(conn, err, params, NULL, 0); + params->func(conn, att_err_from_int(err), params, NULL, 0); return; } @@ -4691,15 +4704,15 @@ static int gatt_read_uuid(struct bt_conn *conn, } #if defined(CONFIG_BT_GATT_READ_MULTIPLE) -static void gatt_read_mult_rsp(struct bt_conn *conn, uint8_t err, const void *pdu, +static void gatt_read_mult_rsp(struct bt_conn *conn, int err, const void *pdu, uint16_t length, void *user_data) { struct bt_gatt_read_params *params = user_data; - LOG_DBG("err 0x%02x", err); + LOG_DBG("err %d", err); if (err || !length) { - params->func(conn, err, params, NULL, 0); + params->func(conn, att_err_from_int(err), params, NULL, 0); return; } @@ -4742,7 +4755,7 @@ static int gatt_read_mult(struct bt_conn *conn, #endif /* CONFIG_BT_GATT_READ_MULTIPLE */ #if defined(CONFIG_BT_GATT_READ_MULT_VAR_LEN) -static void gatt_read_mult_vl_rsp(struct bt_conn *conn, uint8_t err, +static void gatt_read_mult_vl_rsp(struct bt_conn *conn, int err, const void *pdu, uint16_t length, void *user_data) { @@ -4750,10 +4763,10 @@ static void gatt_read_mult_vl_rsp(struct bt_conn *conn, uint8_t err, const struct bt_att_read_mult_vl_rsp *rsp; struct net_buf_simple buf; - LOG_DBG("err 0x%02x", err); + LOG_DBG("err %d", err); if (err || !length) { - params->func(conn, err, params, NULL, 0); + params->func(conn, att_err_from_int(err), params, NULL, 0); return; } @@ -4858,14 +4871,14 @@ int bt_gatt_read(struct bt_conn *conn, struct bt_gatt_read_params *params) BT_ATT_CHAN_OPT(params)); } -static void gatt_write_rsp(struct bt_conn *conn, uint8_t err, const void *pdu, +static void gatt_write_rsp(struct bt_conn *conn, int err, const void *pdu, uint16_t length, void *user_data) { struct bt_gatt_write_params *params = user_data; - LOG_DBG("err 0x%02x", err); + LOG_DBG("err %d", err); - params->func(conn, err, params); + params->func(conn, att_err_from_int(err), params); } int bt_gatt_write_without_response_cb(struct bt_conn *conn, uint16_t handle, @@ -4961,7 +4974,7 @@ static int gatt_cancel_all_writes(struct bt_conn *conn, BT_ATT_CHAN_OPT(params)); } -static void gatt_prepare_write_rsp(struct bt_conn *conn, uint8_t err, +static void gatt_prepare_write_rsp(struct bt_conn *conn, int err, const void *pdu, uint16_t length, void *user_data) { @@ -4970,11 +4983,11 @@ static void gatt_prepare_write_rsp(struct bt_conn *conn, uint8_t err, size_t len; bool data_valid; - LOG_DBG("err 0x%02x", err); + LOG_DBG("err %d", err); /* Don't continue in case of error */ if (err) { - params->func(conn, err, params); + params->func(conn, att_err_from_int(err), params); return; } @@ -5104,13 +5117,14 @@ int bt_gatt_write(struct bt_conn *conn, struct bt_gatt_write_params *params) BT_ATT_OP_WRITE_REQ, len, BT_ATT_CHAN_OPT(params)); } -static void gatt_write_ccc_rsp(struct bt_conn *conn, uint8_t err, +static void gatt_write_ccc_rsp(struct bt_conn *conn, int err, const void *pdu, uint16_t length, void *user_data) { struct bt_gatt_subscribe_params *params = user_data; + uint8_t att_err; - LOG_DBG("err 0x%02x", err); + LOG_DBG("err %d", err); atomic_clear_bit(params->flags, BT_GATT_SUBSCRIBE_FLAG_WRITE_PENDING); @@ -5138,12 +5152,14 @@ static void gatt_write_ccc_rsp(struct bt_conn *conn, uint8_t err, params->notify(conn, params, NULL, 0); } + att_err = att_err_from_int(err); + if (params->subscribe) { - params->subscribe(conn, err, params); + params->subscribe(conn, att_err, params); } else if (params->write) { /* TODO: Remove after deprecation */ LOG_WRN("write callback is deprecated, use subscribe cb instead"); - params->write(conn, err, NULL); + params->write(conn, att_err, NULL); } } @@ -5163,7 +5179,8 @@ static int gatt_write_ccc_buf(struct net_buf *buf, size_t len, void *user_data) } static int gatt_write_ccc(struct bt_conn *conn, - struct bt_gatt_subscribe_params *params) + struct bt_gatt_subscribe_params *params, + bt_att_func_t rsp) { size_t len = sizeof(struct bt_att_write_req) + sizeof(uint16_t); @@ -5174,7 +5191,7 @@ static int gatt_write_ccc(struct bt_conn *conn, */ atomic_set_bit(params->flags, BT_GATT_SUBSCRIBE_FLAG_SENT); - return gatt_req_send(conn, gatt_write_ccc_rsp, params, + return gatt_req_send(conn, rsp, params, gatt_write_ccc_buf, BT_ATT_OP_WRITE_REQ, len, BT_ATT_CHAN_OPT(params)); } @@ -5289,7 +5306,7 @@ int bt_gatt_subscribe(struct bt_conn *conn, return gatt_ccc_discover(conn, params); } #endif - err = gatt_write_ccc(conn, params); + err = gatt_write_ccc(conn, params, gatt_write_ccc_rsp); if (err) { gatt_sub_remove(conn, sub, NULL, NULL); return err; @@ -5378,7 +5395,7 @@ int bt_gatt_unsubscribe(struct bt_conn *conn, int err; params->value = 0x0000; - err = gatt_write_ccc(conn, params); + err = gatt_write_ccc(conn, params, gatt_write_ccc_rsp); if (err) { return err; } @@ -5419,6 +5436,29 @@ void bt_gatt_cancel(struct bt_conn *conn, void *params) } #if defined(CONFIG_BT_GATT_AUTO_RESUBSCRIBE) +static void gatt_resub_ccc_rsp(struct bt_conn *conn, int err, + const void *pdu, uint16_t length, + void *user_data) +{ + LOG_DBG("err %d", err); + + if (err == -ECONNRESET) { + /* The resubscriptions are implicit, thus in the case of ACL + * disconnection during the CCC value ATT Write, there is no + * need to notify the application. + */ + return; + } + + gatt_write_ccc_rsp(conn, err, pdu, length, user_data); +} + +static int gatt_resub_ccc(struct bt_conn *conn, + struct bt_gatt_subscribe_params *params) +{ + return gatt_write_ccc(conn, params, gatt_resub_ccc_rsp); +} + static void add_subscriptions(struct bt_conn *conn) { struct gatt_sub *sub; @@ -5439,10 +5479,16 @@ static void add_subscriptions(struct bt_conn *conn) BT_GATT_SUBSCRIBE_FLAG_SENT) && !atomic_test_bit(params->flags, BT_GATT_SUBSCRIBE_FLAG_NO_RESUB)) { + int err; + /* Force write to CCC to workaround devices that don't * track it properly. */ - gatt_write_ccc(conn, params); + err = gatt_resub_ccc(conn, params); + if (err < 0) { + LOG_WRN("conn %p params %p resub failed (err %d)", + (void *)conn, params, err); + } } } } From c797f9b5f3dbe0d0a1ecaf91834b51e6538ccdde Mon Sep 17 00:00:00 2001 From: Mariusz Skamra Date: Fri, 8 Dec 2023 11:40:27 +0100 Subject: [PATCH 1113/3723] tests: Bluetooth: ascs: Remove redunadant tests This removes 2 tests related to ASCS handling ACL disconnection. c3c83c7049337f2ab1b6889ad83cb922457a3185 modified the ACL disconection behavior, so that ASE goes directly to idle state, not waiting in releasing state for CIS disconnection. Thus the tests where state machine waits for CIS disconnection can be removed now. Signed-off-by: Mariusz Skamra --- tests/bluetooth/audio/ascs/src/main.c | 110 ++------------------------ 1 file changed, 6 insertions(+), 104 deletions(-) diff --git a/tests/bluetooth/audio/ascs/src/main.c b/tests/bluetooth/audio/ascs/src/main.c index 84ed14cde5a..a38a26c0c4d 100644 --- a/tests/bluetooth/audio/ascs/src/main.c +++ b/tests/bluetooth/audio/ascs/src/main.c @@ -218,44 +218,7 @@ ZTEST_F(ascs_test_suite, test_abort_client_operation_if_callback_not_registered) zassert_equal(0x00, param->reason, "unexpected Reason 0x%02x", param->reason); } -ZTEST_F(ascs_test_suite, test_release_ase_on_acl_disconnection_client_terminates_cis) -{ - struct bt_bap_stream *stream = &fixture->stream; - struct bt_conn *conn = &fixture->conn; - const struct bt_gatt_attr *ase; - struct bt_iso_chan *chan; - uint8_t ase_id; - - if (IS_ENABLED(CONFIG_BT_ASCS_ASE_SNK)) { - ase = fixture->ase_snk.attr; - ase_id = fixture->ase_snk.id; - } else { - ase = fixture->ase_src.attr; - ase_id = fixture->ase_src.id; - } - - zexpect_not_null(ase); - zexpect_true(ase_id != 0x00); - - bt_bap_unicast_server_register_cb(&mock_bap_unicast_server_cb); - - /* Set ASE to non-idle state */ - test_preamble_state_streaming(conn, ase_id, stream, &chan, - !IS_ENABLED(CONFIG_BT_ASCS_ASE_SNK)); - - /* Mock ACL disconnection */ - mock_bt_conn_disconnected(conn, BT_HCI_ERR_REMOTE_USER_TERM_CONN); - - /* Mock CIS disconnection */ - mock_bt_iso_disconnected(chan, BT_HCI_ERR_REMOTE_USER_TERM_CONN); - - /* Expected to notify the upper layers */ - expect_bt_bap_stream_ops_released_called_once(stream); - - bt_bap_unicast_server_unregister_cb(&mock_bap_unicast_server_cb); -} - -ZTEST_F(ascs_test_suite, test_release_ase_on_acl_disconnection_server_terminates_cis) +ZTEST_F(ascs_test_suite, test_release_ase_on_acl_disconnection) { struct bt_bap_stream *stream = &fixture->stream; struct bt_conn *conn = &fixture->conn; @@ -283,77 +246,16 @@ ZTEST_F(ascs_test_suite, test_release_ase_on_acl_disconnection_server_terminates /* Mock ACL disconnection */ mock_bt_conn_disconnected(conn, BT_HCI_ERR_CONN_TIMEOUT); - /* Client does not disconnect the CIS in expected time */ - k_sleep(K_MSEC(CONFIG_BT_ASCS_ISO_DISCONNECT_DELAY)); - /* Expected to notify the upper layers */ expect_bt_bap_stream_ops_released_called_once(stream); - bt_bap_unicast_server_unregister_cb(&mock_bap_unicast_server_cb); -} - -ZTEST_F(ascs_test_suite, test_release_stream_pair_on_acl_disconnection_client_terminates_cis) -{ - const struct bt_gatt_attr *ase_snk, *ase_src; - struct bt_bap_stream snk_stream, src_stream; - struct bt_conn *conn = &fixture->conn; - uint8_t ase_snk_id, ase_src_id; - struct bt_iso_chan *chan; - int err; - - if (CONFIG_BT_ASCS_MAX_ACTIVE_ASES < 2) { - ztest_test_skip(); - } - - Z_TEST_SKIP_IFNDEF(CONFIG_BT_ASCS_ASE_SNK); - memset(&snk_stream, 0, sizeof(snk_stream)); - ase_snk = fixture->ase_snk.attr; - zexpect_not_null(ase_snk); - ase_snk_id = fixture->ase_snk.id; - zexpect_true(ase_snk_id != 0x00); - - Z_TEST_SKIP_IFNDEF(CONFIG_BT_ASCS_ASE_SRC); - memset(&src_stream, 0, sizeof(src_stream)); - ase_src = fixture->ase_src.attr; - zexpect_not_null(ase_src); - ase_src_id = fixture->ase_src.id; - zexpect_true(ase_src_id != 0x00); - - bt_bap_unicast_server_register_cb(&mock_bap_unicast_server_cb); - - test_ase_control_client_config_codec(conn, ase_snk_id, &snk_stream); - test_ase_control_client_config_qos(conn, ase_snk_id); - test_ase_control_client_enable(conn, ase_snk_id); - - test_ase_control_client_config_codec(conn, ase_src_id, &src_stream); - test_ase_control_client_config_qos(conn, ase_src_id); - test_ase_control_client_enable(conn, ase_src_id); - - err = mock_bt_iso_accept(conn, 0x01, 0x01, &chan); - zassert_equal(0, err, "Failed to connect iso: err %d", err); - - test_ase_control_client_receiver_start_ready(conn, ase_src_id); - - err = bt_bap_stream_start(&snk_stream); - zassert_equal(0, err, "bt_bap_stream_start err %d", err); - - test_mocks_reset(); - - /* Mock ACL disconnection */ - mock_bt_conn_disconnected(conn, BT_HCI_ERR_REMOTE_USER_TERM_CONN); - /* Mock CIS disconnection */ - mock_bt_iso_disconnected(chan, BT_HCI_ERR_REMOTE_USER_TERM_CONN); - - /* Expected to notify the upper layers */ - const struct bt_bap_stream *streams[2] = { &snk_stream, &src_stream }; - - expect_bt_bap_stream_ops_released_called_twice(streams); + mock_bt_iso_disconnected(chan, BT_HCI_ERR_CONN_TIMEOUT); bt_bap_unicast_server_unregister_cb(&mock_bap_unicast_server_cb); } -ZTEST_F(ascs_test_suite, test_release_stream_pair_on_acl_disconnection_server_terminates_cis) +ZTEST_F(ascs_test_suite, test_release_ase_pair_on_acl_disconnection) { const struct bt_gatt_attr *ase_snk, *ase_src; struct bt_bap_stream snk_stream, src_stream; @@ -403,14 +305,14 @@ ZTEST_F(ascs_test_suite, test_release_stream_pair_on_acl_disconnection_server_te /* Mock ACL disconnection */ mock_bt_conn_disconnected(conn, BT_HCI_ERR_CONN_TIMEOUT); - /* Client does not disconnect the CIS in expected time */ - k_sleep(K_MSEC(CONFIG_BT_ASCS_ISO_DISCONNECT_DELAY)); - /* Expected to notify the upper layers */ const struct bt_bap_stream *streams[2] = { &snk_stream, &src_stream }; expect_bt_bap_stream_ops_released_called_twice(streams); + /* Mock CIS disconnection */ + mock_bt_iso_disconnected(chan, BT_HCI_ERR_CONN_TIMEOUT); + bt_bap_unicast_server_unregister_cb(&mock_bap_unicast_server_cb); } From e3e567ad82dfcbf97bd6e6e4398d733b83988ac0 Mon Sep 17 00:00:00 2001 From: Mariusz Skamra Date: Fri, 8 Dec 2023 11:47:01 +0100 Subject: [PATCH 1114/3723] tests: Bluetooth: ASCS: Add tests for invalid operations in Releasing state This adds missing tests for invalid operations initiated by locally or by client on ASE in Releasing state. Signed-off-by: Mariusz Skamra --- .../audio/ascs/include/test_common.h | 3 + .../src/test_ase_state_transition_invalid.c | 104 ++++++++++++++++++ tests/bluetooth/audio/ascs/src/test_common.c | 20 ++++ 3 files changed, 127 insertions(+) diff --git a/tests/bluetooth/audio/ascs/include/test_common.h b/tests/bluetooth/audio/ascs/include/test_common.h index beeb6aa37de..23d4a5185ba 100644 --- a/tests/bluetooth/audio/ascs/include/test_common.h +++ b/tests/bluetooth/audio/ascs/include/test_common.h @@ -66,3 +66,6 @@ void test_preamble_state_streaming(struct bt_conn *conn, uint8_t ase_id, bool source); void test_preamble_state_disabling(struct bt_conn *conn, uint8_t ase_id, struct bt_bap_stream *stream, struct bt_iso_chan **chan); +void test_preamble_state_releasing(struct bt_conn *conn, uint8_t ase_id, + struct bt_bap_stream *stream, struct bt_iso_chan **chan, + bool source); diff --git a/tests/bluetooth/audio/ascs/src/test_ase_state_transition_invalid.c b/tests/bluetooth/audio/ascs/src/test_ase_state_transition_invalid.c index 928f097c99e..64eaf24b12c 100644 --- a/tests/bluetooth/audio/ascs/src/test_ase_state_transition_invalid.c +++ b/tests/bluetooth/audio/ascs/src/test_ase_state_transition_invalid.c @@ -333,6 +333,43 @@ ZTEST_F(test_ase_state_transition_invalid, test_sink_client_state_streaming) test_client_receiver_stop_ready_expect_ase_direction_error(conn, ase_id, ase_cp); } +static void expect_ase_state_releasing(struct bt_conn *conn, const struct bt_gatt_attr *ase) +{ + struct test_ase_chrc_value_hdr hdr = { 0xff }; + ssize_t ret; + + zexpect_not_null(conn); + zexpect_not_null(ase); + + ret = ase->read(conn, ase, &hdr, sizeof(hdr), 0); + zassert_false(ret < 0, "attr->read returned unexpected (err 0x%02x)", BT_GATT_ERR(ret)); + zassert_equal(BT_BAP_EP_STATE_RELEASING, hdr.ase_state, + "unexpected ASE_State 0x%02x", hdr.ase_state); +} + +ZTEST_F(test_ase_state_transition_invalid, test_client_sink_state_releasing) +{ + const struct bt_gatt_attr *ase_cp = fixture->ase_cp; + struct bt_bap_stream *stream = &fixture->stream; + struct bt_conn *conn = &fixture->conn; + struct bt_iso_chan *chan; + uint8_t ase_id; + + Z_TEST_SKIP_IFNDEF(CONFIG_BT_ASCS_ASE_SNK); + + ase_id = test_ase_id_get(fixture->ase_snk); + test_preamble_state_releasing(conn, ase_id, stream, &chan, false); + expect_ase_state_releasing(conn, fixture->ase_snk); + + test_client_config_codec_expect_transition_error(conn, ase_id, ase_cp); + test_client_config_qos_expect_transition_error(conn, ase_id, ase_cp); + test_client_enable_expect_transition_error(conn, ase_id, ase_cp); + test_client_receiver_start_ready_expect_ase_direction_error(conn, ase_id, ase_cp); + test_client_receiver_stop_ready_expect_ase_direction_error(conn, ase_id, ase_cp); + test_client_disable_expect_transition_error(conn, ase_id, ase_cp); + test_client_update_metadata_expect_transition_error(conn, ase_id, ase_cp); +} + ZTEST_F(test_ase_state_transition_invalid, test_client_source_state_idle) { const struct bt_gatt_attr *ase_cp = fixture->ase_cp; @@ -448,6 +485,29 @@ ZTEST_F(test_ase_state_transition_invalid, test_client_source_state_disabling) test_client_update_metadata_expect_transition_error(conn, ase_id, ase_cp); } +ZTEST_F(test_ase_state_transition_invalid, test_client_source_state_releasing) +{ + const struct bt_gatt_attr *ase_cp = fixture->ase_cp; + struct bt_bap_stream *stream = &fixture->stream; + struct bt_conn *conn = &fixture->conn; + struct bt_iso_chan *chan; + uint8_t ase_id; + + Z_TEST_SKIP_IFNDEF(CONFIG_BT_ASCS_ASE_SRC); + + ase_id = test_ase_id_get(fixture->ase_src); + test_preamble_state_releasing(conn, ase_id, stream, &chan, true); + expect_ase_state_releasing(conn, fixture->ase_src); + + test_client_config_codec_expect_transition_error(conn, ase_id, ase_cp); + test_client_config_qos_expect_transition_error(conn, ase_id, ase_cp); + test_client_enable_expect_transition_error(conn, ase_id, ase_cp); + test_client_receiver_start_ready_expect_transition_error(conn, ase_id, ase_cp); + test_client_receiver_stop_ready_expect_transition_error(conn, ase_id, ase_cp); + test_client_disable_expect_transition_error(conn, ase_id, ase_cp); + test_client_update_metadata_expect_transition_error(conn, ase_id, ase_cp); +} + static void test_server_config_codec_expect_error(struct bt_bap_stream *stream) { struct bt_audio_codec_cfg codec_cfg = BT_AUDIO_CODEC_LC3_CONFIG_16_2( @@ -600,6 +660,28 @@ ZTEST_F(test_ase_state_transition_invalid, test_server_sink_state_streaming) test_server_receiver_stop_ready_expect_error(stream); } +ZTEST_F(test_ase_state_transition_invalid, test_server_sink_state_releasing) +{ + struct bt_bap_stream *stream = &fixture->stream; + struct bt_conn *conn = &fixture->conn; + struct bt_iso_chan *chan; + uint8_t ase_id; + + Z_TEST_SKIP_IFNDEF(CONFIG_BT_ASCS_ASE_SNK); + + ase_id = test_ase_id_get(fixture->ase_snk); + test_preamble_state_releasing(conn, ase_id, stream, &chan, false); + expect_ase_state_releasing(conn, fixture->ase_snk); + + test_server_config_codec_expect_error(stream); + test_server_config_qos_expect_error(stream); + test_server_enable_expect_error(stream); + test_server_receiver_start_ready_expect_error(stream); + test_server_disable_expect_error(stream); + test_server_receiver_stop_ready_expect_error(stream); + test_server_update_metadata_expect_error(stream); +} + ZTEST_F(test_ase_state_transition_invalid, test_server_source_state_codec_configured) { struct bt_bap_stream *stream = &fixture->stream; @@ -694,3 +776,25 @@ ZTEST_F(test_ase_state_transition_invalid, test_server_source_state_disabling) test_server_receiver_stop_ready_expect_error(stream); test_server_update_metadata_expect_error(stream); } + +ZTEST_F(test_ase_state_transition_invalid, test_server_source_state_releasing) +{ + struct bt_bap_stream *stream = &fixture->stream; + struct bt_conn *conn = &fixture->conn; + struct bt_iso_chan *chan; + uint8_t ase_id; + + Z_TEST_SKIP_IFNDEF(CONFIG_BT_ASCS_ASE_SRC); + + ase_id = test_ase_id_get(fixture->ase_src); + test_preamble_state_releasing(conn, ase_id, stream, &chan, true); + expect_ase_state_releasing(conn, fixture->ase_src); + + test_server_config_codec_expect_error(stream); + test_server_config_qos_expect_error(stream); + test_server_enable_expect_error(stream); + test_server_receiver_start_ready_expect_error(stream); + test_server_disable_expect_error(stream); + test_server_receiver_stop_ready_expect_error(stream); + test_server_update_metadata_expect_error(stream); +} diff --git a/tests/bluetooth/audio/ascs/src/test_common.c b/tests/bluetooth/audio/ascs/src/test_common.c index 17f5bf71e2b..003c8cb52e6 100644 --- a/tests/bluetooth/audio/ascs/src/test_common.c +++ b/tests/bluetooth/audio/ascs/src/test_common.c @@ -347,3 +347,23 @@ void test_preamble_state_disabling(struct bt_conn *conn, uint8_t ase_id, test_mocks_reset(); } + +void test_preamble_state_releasing(struct bt_conn *conn, uint8_t ase_id, + struct bt_bap_stream *stream, struct bt_iso_chan **chan, + bool source) +{ + test_preamble_state_streaming(conn, ase_id, stream, chan, source); + test_ase_control_client_release(conn, ase_id); + + /* Reset the mocks espacially the function call count */ + mock_bap_unicast_server_cleanup(); + mock_bt_iso_cleanup(); + mock_bap_stream_cleanup(); + mock_bt_gatt_cleanup(); + mock_bap_unicast_server_init(); + mock_bt_iso_init(); + mock_bap_stream_init(); + mock_bt_gatt_init(); + + /* At this point, ISO is still connected, thus ASE is in releasing state */ +} From f58f74a091371c72c933bac9ae0590255a734685 Mon Sep 17 00:00:00 2001 From: Mariusz Skamra Date: Fri, 8 Dec 2023 11:48:47 +0100 Subject: [PATCH 1115/3723] tests: Bluetooth: ascs: Fix minor comment issue This fixes opcode comment. Signed-off-by: Mariusz Skamra --- tests/bluetooth/audio/ascs/src/test_common.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/bluetooth/audio/ascs/src/test_common.c b/tests/bluetooth/audio/ascs/src/test_common.c index 003c8cb52e6..429c7edd81d 100644 --- a/tests/bluetooth/audio/ascs/src/test_common.c +++ b/tests/bluetooth/audio/ascs/src/test_common.c @@ -229,7 +229,7 @@ void test_ase_control_client_release(struct bt_conn *conn, uint8_t ase_id) { const struct bt_gatt_attr *attr = test_ase_control_point_get(); const uint8_t buf[] = { - 0x08, /* Opcode = Disable */ + 0x08, /* Opcode = Release */ 0x01, /* Number_of_ASEs */ ase_id, /* ASE_ID[0] */ }; From 025ba06c32976dc87a27680266d29a2c3cedcd2b Mon Sep 17 00:00:00 2001 From: Mariusz Skamra Date: Thu, 7 Dec 2023 17:07:22 +0100 Subject: [PATCH 1116/3723] Bluetooth: ascs: Avoid possible unexpected assert This avoids unexpected assert that may happen when the client tries to QoS configure ASE that is in state which does not allow to be configured. In such case the assert shall not be not be triggered, as it's not stack fauly. The assert check has been moved after the state check, so the ASCS implementation will just return an error code to the client. Signed-off-by: Mariusz Skamra --- subsys/bluetooth/audio/ascs.c | 75 +++++++++++++---------------------- 1 file changed, 27 insertions(+), 48 deletions(-) diff --git a/subsys/bluetooth/audio/ascs.c b/subsys/bluetooth/audio/ascs.c index b1f6a26999a..4118d059586 100644 --- a/subsys/bluetooth/audio/ascs.c +++ b/subsys/bluetooth/audio/ascs.c @@ -1765,23 +1765,15 @@ void bt_ascs_foreach_ep(struct bt_conn *conn, bt_bap_ep_func_t func, void *user_ } } -static int ase_stream_qos(struct bt_bap_stream *stream, struct bt_audio_codec_qos *qos, - struct bt_conn *conn, uint8_t cig_id, uint8_t cis_id, - struct bt_bap_ascs_rsp *rsp) +static void ase_qos(struct bt_ascs_ase *ase, uint8_t cig_id, uint8_t cis_id, + struct bt_audio_codec_qos *qos, struct bt_bap_ascs_rsp *rsp) { - struct bt_bap_ep *ep; - *rsp = BT_BAP_ASCS_RSP(BT_BAP_ASCS_RSP_CODE_SUCCESS, BT_BAP_ASCS_REASON_NONE); - - CHECKIF(stream == NULL || stream->ep == NULL || qos == NULL) { - LOG_DBG("Invalid input stream, ep or qos pointers"); - *rsp = BT_BAP_ASCS_RSP(BT_BAP_ASCS_RSP_CODE_INVALID_ASE_STATE, - BT_BAP_ASCS_REASON_NONE); - return -EINVAL; - } - - LOG_DBG("stream %p ep %p qos %p", stream, stream->ep, qos); + struct bt_bap_ep *ep = &ase->ep; + struct bt_bap_stream *stream; - ep = stream->ep; + LOG_DBG("ase %p cig 0x%02x cis 0x%02x interval %u framing 0x%02x phy 0x%02x sdu %u rtn %u " + "latency %u pd %u", ase, cig_id, cis_id, qos->interval, qos->framing, qos->phy, + qos->sdu, qos->rtn, qos->latency, qos->pd); switch (ep->status.state) { /* Valid only if ASE_State field = 0x01 (Codec Configured) */ @@ -1793,19 +1785,32 @@ static int ase_stream_qos(struct bt_bap_stream *stream, struct bt_audio_codec_qo LOG_WRN("Invalid operation in state: %s", bt_bap_ep_state_str(ep->status.state)); *rsp = BT_BAP_ASCS_RSP(BT_BAP_ASCS_RSP_CODE_INVALID_ASE_STATE, BT_BAP_ASCS_REASON_NONE); - return -EBADMSG; + return; + } + + stream = ep->stream; + if (stream == NULL) { + LOG_ERR("NULL stream"); + *rsp = BT_BAP_ASCS_RSP(BT_BAP_ASCS_RSP_CODE_UNSPECIFIED, BT_BAP_ASCS_REASON_NONE); + return; + } + + if (stream->ep == NULL) { + LOG_ERR("NULL stream->ep"); + *rsp = BT_BAP_ASCS_RSP(BT_BAP_ASCS_RSP_CODE_UNSPECIFIED, BT_BAP_ASCS_REASON_NONE); + return; } rsp->reason = bt_audio_verify_qos(qos); if (rsp->reason != BT_BAP_ASCS_REASON_NONE) { rsp->code = BT_BAP_ASCS_RSP_CODE_CONF_INVALID; - return -EINVAL; + return; } rsp->reason = bt_bap_stream_verify_qos(stream, qos); if (rsp->reason != BT_BAP_ASCS_REASON_NONE) { rsp->code = BT_BAP_ASCS_RSP_CODE_CONF_INVALID; - return -EINVAL; + return; } if (unicast_server_cb != NULL && unicast_server_cb->qos != NULL) { @@ -1819,7 +1824,7 @@ static int ase_stream_qos(struct bt_bap_stream *stream, struct bt_audio_codec_qo LOG_DBG("Application returned error: err %d status %u reason %u", err, rsp->code, rsp->reason); - return err; + return; } } @@ -1831,12 +1836,12 @@ static int ase_stream_qos(struct bt_bap_stream *stream, struct bt_audio_codec_qo if (ep->iso == NULL) { struct bt_bap_iso *iso; - iso = bap_iso_get_or_new(conn, cig_id, cis_id); + iso = bap_iso_get_or_new(ase->conn, cig_id, cis_id); if (iso == NULL) { LOG_ERR("Could not allocate bap_iso"); *rsp = BT_BAP_ASCS_RSP(BT_BAP_ASCS_RSP_CODE_NO_MEM, BT_BAP_ASCS_REASON_NONE); - return -ENOMEM; + return; } if (bt_bap_iso_get_ep(false, iso, ep->dir) != NULL) { @@ -1845,7 +1850,7 @@ static int ase_stream_qos(struct bt_bap_stream *stream, struct bt_audio_codec_qo bt_bap_iso_unref(iso); *rsp = BT_BAP_ASCS_RSP(BT_BAP_ASCS_RSP_CODE_CONF_INVALID, BT_BAP_ASCS_REASON_CIS); - return -EALREADY; + return; } bt_bap_iso_bind_ep(iso, ep); @@ -1871,32 +1876,6 @@ static int ase_stream_qos(struct bt_bap_stream *stream, struct bt_audio_codec_qo ascs_ep_set_state(ep, BT_BAP_EP_STATE_QOS_CONFIGURED); - *rsp = BT_BAP_ASCS_RSP(BT_BAP_ASCS_RSP_CODE_SUCCESS, BT_BAP_ASCS_REASON_NONE); - return 0; -} - -static void ase_qos(struct bt_ascs_ase *ase, uint8_t cig_id, uint8_t cis_id, - struct bt_audio_codec_qos *cqos, struct bt_bap_ascs_rsp *rsp) -{ - struct bt_bap_ep *ep = &ase->ep; - struct bt_bap_stream *stream = ep->stream; - int err; - - LOG_DBG("ase %p cig 0x%02x cis 0x%02x interval %u framing 0x%02x phy 0x%02x sdu %u rtn %u " - "latency %u pd %u", ase, cig_id, cis_id, cqos->interval, cqos->framing, cqos->phy, - cqos->sdu, cqos->rtn, cqos->latency, cqos->pd); - - err = ase_stream_qos(stream, cqos, ase->conn, cig_id, cis_id, rsp); - if (err) { - if (rsp->code == BT_BAP_ASCS_RSP_CODE_SUCCESS) { - *rsp = BT_BAP_ASCS_RSP(BT_BAP_ASCS_RSP_CODE_UNSPECIFIED, - BT_BAP_ASCS_REASON_NONE); - } - - LOG_ERR("QoS failed: err %d, code %u, reason %u", err, rsp->code, rsp->reason); - return; - } - *rsp = BT_BAP_ASCS_RSP(BT_BAP_ASCS_RSP_CODE_SUCCESS, BT_BAP_ASCS_REASON_NONE); } From 09e376068e2fca8611b9cba7683ec874243b109a Mon Sep 17 00:00:00 2001 From: Mariusz Skamra Date: Thu, 7 Dec 2023 15:55:59 +0100 Subject: [PATCH 1117/3723] Bluetooth: audio: bap_stream: Fix potential NULL pointer dereference This fixes potential NULL stream pointer dereference. Signed-off-by: Mariusz Skamra --- subsys/bluetooth/audio/bap_stream.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/subsys/bluetooth/audio/bap_stream.c b/subsys/bluetooth/audio/bap_stream.c index 23e5bb8564b..ec614ce7243 100644 --- a/subsys/bluetooth/audio/bap_stream.c +++ b/subsys/bluetooth/audio/bap_stream.c @@ -412,14 +412,15 @@ void bt_bap_stream_detach(struct bt_bap_stream *stream) int bt_bap_stream_disconnect(struct bt_bap_stream *stream) { - struct bt_iso_chan *iso_chan = bt_bap_stream_iso_chan_get(stream); + struct bt_iso_chan *iso_chan; - LOG_DBG("stream %p iso %p", stream, iso_chan); + LOG_DBG("stream %p", stream); if (stream == NULL) { return -EINVAL; } + iso_chan = bt_bap_stream_iso_chan_get(stream); if (iso_chan == NULL || iso_chan->iso == NULL) { return -ENOTCONN; } From 92d5cdec75259ac0de79ea79c728cfd4cccbc2c1 Mon Sep 17 00:00:00 2001 From: Mariusz Skamra Date: Wed, 6 Dec 2023 14:42:27 +0100 Subject: [PATCH 1118/3723] tests: Bluetooth: ascs: Remove duplicated config setting This removes duplicated CONFIG_BT_ISO_MAX_CHAN config setting and leaves the default value set to 1. Signed-off-by: Mariusz Skamra --- tests/bluetooth/audio/ascs/prj.conf | 1 - 1 file changed, 1 deletion(-) diff --git a/tests/bluetooth/audio/ascs/prj.conf b/tests/bluetooth/audio/ascs/prj.conf index 9dfa71a952a..ecbd5ed97e1 100644 --- a/tests/bluetooth/audio/ascs/prj.conf +++ b/tests/bluetooth/audio/ascs/prj.conf @@ -9,7 +9,6 @@ CONFIG_BT_ASCS_ASE_SNK_COUNT=2 CONFIG_BT_ASCS_ASE_SRC_COUNT=2 CONFIG_BT_ASCS_MAX_ACTIVE_ASES=1 CONFIG_BT_BAP_UNICAST_SERVER=y -CONFIG_BT_ISO_MAX_CHAN=2 # Mandatory to support at least 1 for ASCS CONFIG_BT_ATT_PREPARE_COUNT=1 From cb6c856d768d401f0c084c13fcc2a1fb5f921c74 Mon Sep 17 00:00:00 2001 From: Mariusz Skamra Date: Wed, 6 Dec 2023 14:44:43 +0100 Subject: [PATCH 1119/3723] tests: Bluetooth: ascs: Limit the default number of ASEs This limits the default number of ASEs available to 1. The value can be overwritten in test case specific parameters in testcase.yaml file. Signed-off-by: Mariusz Skamra --- tests/bluetooth/audio/ascs/prj.conf | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/tests/bluetooth/audio/ascs/prj.conf b/tests/bluetooth/audio/ascs/prj.conf index ecbd5ed97e1..714c9bde4df 100644 --- a/tests/bluetooth/audio/ascs/prj.conf +++ b/tests/bluetooth/audio/ascs/prj.conf @@ -5,8 +5,8 @@ CONFIG_BT_MAX_CONN=1 CONFIG_BT_ISO_MAX_CHAN=1 CONFIG_BT_AUDIO=y CONFIG_BT_ASCS=y -CONFIG_BT_ASCS_ASE_SNK_COUNT=2 -CONFIG_BT_ASCS_ASE_SRC_COUNT=2 +CONFIG_BT_ASCS_ASE_SNK_COUNT=1 +CONFIG_BT_ASCS_ASE_SRC_COUNT=1 CONFIG_BT_ASCS_MAX_ACTIVE_ASES=1 CONFIG_BT_BAP_UNICAST_SERVER=y From 874e724492345506a47d00e3a8cc6608231044ef Mon Sep 17 00:00:00 2001 From: Mariusz Skamra Date: Fri, 8 Dec 2023 13:50:20 +0100 Subject: [PATCH 1120/3723] tests: Bluetooth: ascs: Add expect_bt_bap_stream_ops_released_called This adds the expect_bt_bap_stream_ops_released_called function that takes an array of streams to verify as an argument. It's more versatile approach than having expect_bt_bap_stream_ops_released_called_twice erc. functions, that scales bad. The function ignores the arhument list order, so that the user does not have to predict the exact order of function calls. Signed-off-by: Mariusz Skamra --- tests/bluetooth/audio/ascs/src/main.c | 2 +- .../audio/mocks/include/bap_stream_expects.h | 32 ++++++++----------- 2 files changed, 15 insertions(+), 19 deletions(-) diff --git a/tests/bluetooth/audio/ascs/src/main.c b/tests/bluetooth/audio/ascs/src/main.c index a38a26c0c4d..fa1ad698a36 100644 --- a/tests/bluetooth/audio/ascs/src/main.c +++ b/tests/bluetooth/audio/ascs/src/main.c @@ -308,7 +308,7 @@ ZTEST_F(ascs_test_suite, test_release_ase_pair_on_acl_disconnection) /* Expected to notify the upper layers */ const struct bt_bap_stream *streams[2] = { &snk_stream, &src_stream }; - expect_bt_bap_stream_ops_released_called_twice(streams); + expect_bt_bap_stream_ops_released_called(streams, 2); /* Mock CIS disconnection */ mock_bt_iso_disconnected(chan, BT_HCI_ERR_CONN_TIMEOUT); diff --git a/tests/bluetooth/audio/mocks/include/bap_stream_expects.h b/tests/bluetooth/audio/mocks/include/bap_stream_expects.h index 42d4b45b68c..3912f9331d0 100644 --- a/tests/bluetooth/audio/mocks/include/bap_stream_expects.h +++ b/tests/bluetooth/audio/mocks/include/bap_stream_expects.h @@ -114,34 +114,30 @@ static inline void expect_bt_bap_stream_ops_disabled_not_called(void) zexpect_call_count(func_name, 0, mock_bap_stream_disabled_cb_fake.call_count); } -static inline void expect_bt_bap_stream_ops_released_called_twice( - const struct bt_bap_stream *streams[2]) +static inline void expect_bt_bap_stream_ops_released_called(const struct bt_bap_stream *streams[], + unsigned int count) { const char *func_name = "bt_bap_stream_ops.released"; - zexpect_call_count(func_name, 2, mock_bap_stream_released_cb_fake.call_count); + zexpect_call_count(func_name, count, mock_bap_stream_released_cb_fake.call_count); - if (mock_bap_stream_released_cb_fake.call_count > 0) { - zexpect_equal_ptr(streams[0], mock_bap_stream_released_cb_fake.arg0_history[0], - "'%s()' was called with incorrect '%s'", func_name, "stream"); - } + for (unsigned int i = 0; i < count; i++) { + bool found = false; - if (mock_bap_stream_released_cb_fake.call_count > 1) { - zexpect_equal_ptr(streams[1], mock_bap_stream_released_cb_fake.arg0_history[1], - "'%s()' was called with incorrect '%s'", func_name, "stream"); + for (unsigned int j = 0; j < mock_bap_stream_released_cb_fake.call_count; j++) { + found = streams[i] == mock_bap_stream_released_cb_fake.arg0_history[j]; + if (found) { + break; + } + } + + zexpect_true(found, "'%s()' not called with %p stream", func_name, streams[i]); } } static inline void expect_bt_bap_stream_ops_released_called_once(struct bt_bap_stream *stream) { - const char *func_name = "bt_bap_stream_ops.released"; - - zexpect_call_count(func_name, 1, mock_bap_stream_released_cb_fake.call_count); - - if (mock_bap_stream_released_cb_fake.call_count > 0) { - zexpect_equal_ptr(stream, mock_bap_stream_released_cb_fake.arg0_val, - "'%s()' was called with incorrect '%s'", func_name, "stream"); - } + expect_bt_bap_stream_ops_released_called(&stream, 1); } static inline void expect_bt_bap_stream_ops_released_not_called(void) From aad6a81a3bcbdf026f41aeb01cc2149931ffb078 Mon Sep 17 00:00:00 2001 From: Johann Fischer Date: Tue, 14 Nov 2023 12:10:57 +0100 Subject: [PATCH 1121/3723] drivers: udc_nrf: submit resume event after RWUP is initiated Submit resume event after remote wakeup (resume) signalling is initiated. Handle it same way as in the usb_dc_nrfx driver. Signed-off-by: Johann Fischer --- drivers/usb/udc/udc_nrf.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/drivers/usb/udc/udc_nrf.c b/drivers/usb/udc/udc_nrf.c index bca098347d8..d4ecc130587 100644 --- a/drivers/usb/udc/udc_nrf.c +++ b/drivers/usb/udc/udc_nrf.c @@ -436,6 +436,8 @@ static void usbd_event_handler(nrf_usbd_common_evt_t const *const hal_evt) break; case NRF_USBD_COMMON_EVT_WUREQ: LOG_INF("Remote wakeup initiated"); + udc_set_suspended(udc_nrf_dev, false); + udc_submit_event(udc_nrf_dev, UDC_EVT_RESUME, 0); break; case NRF_USBD_COMMON_EVT_RESET: LOG_INF("Reset"); From 0462cc060d4c6dddad02ebfd3ed97ec433456155 Mon Sep 17 00:00:00 2001 From: Sebastian Schlupp Date: Tue, 21 Nov 2023 11:45:12 +0100 Subject: [PATCH 1122/3723] soc: same51 and same54: added DFLL48 frequency information Specified the value 48000000 for the DFLL48 clock source Signed-off-by: Sebastian Schlupp --- soc/arm/atmel_sam0/same51/soc.h | 1 + soc/arm/atmel_sam0/same54/soc.h | 1 + 2 files changed, 2 insertions(+) diff --git a/soc/arm/atmel_sam0/same51/soc.h b/soc/arm/atmel_sam0/same51/soc.h index 64550333855..746a001be69 100644 --- a/soc/arm/atmel_sam0/same51/soc.h +++ b/soc/arm/atmel_sam0/same51/soc.h @@ -37,6 +37,7 @@ #include "../common/atmel_sam0_dt.h" #define SOC_ATMEL_SAM0_OSC32K_FREQ_HZ 32768 +#define SOC_ATMEL_SAM0_DFLL48_FREQ_HZ 48000000 /** Processor Clock (HCLK) Frequency */ #define SOC_ATMEL_SAM0_HCLK_FREQ_HZ CONFIG_SYS_CLOCK_HW_CYCLES_PER_SEC diff --git a/soc/arm/atmel_sam0/same54/soc.h b/soc/arm/atmel_sam0/same54/soc.h index 4f49e68c31f..b62eead707e 100644 --- a/soc/arm/atmel_sam0/same54/soc.h +++ b/soc/arm/atmel_sam0/same54/soc.h @@ -36,6 +36,7 @@ #include "../common/atmel_sam0_dt.h" #define SOC_ATMEL_SAM0_OSC32K_FREQ_HZ 32768 +#define SOC_ATMEL_SAM0_DFLL48_FREQ_HZ 48000000 /** Processor Clock (HCLK) Frequency */ #define SOC_ATMEL_SAM0_HCLK_FREQ_HZ CONFIG_SYS_CLOCK_HW_CYCLES_PER_SEC From c2c05ff7e7b26ab7b25b5f120da6e131ec40917c Mon Sep 17 00:00:00 2001 From: Sebastian Schlupp Date: Thu, 30 Nov 2023 14:17:03 +0100 Subject: [PATCH 1123/3723] dts: arm: atmel: same5x: added CAN(0 and 1) peripheral description Added default parameters for CAN peripherals according to the datasheet. Signed-off-by: Sebastian Schlupp --- dts/arm/atmel/same5x.dtsi | 29 +++++++++++++++++++++++++++++ 1 file changed, 29 insertions(+) diff --git a/dts/arm/atmel/same5x.dtsi b/dts/arm/atmel/same5x.dtsi index 1d11fa32c97..616b408e8ed 100644 --- a/dts/arm/atmel/same5x.dtsi +++ b/dts/arm/atmel/same5x.dtsi @@ -1,5 +1,6 @@ /* * Copyright (c) 2020 Stephanos Ioannidis + * Copyright (c) 2023 Sebastian Schlupp * * SPDX-License-Identifier: Apache-2.0 */ @@ -25,5 +26,33 @@ #address-cells = <1>; #size-cells = <0>; }; + + can0: can@42000000 { + compatible = "atmel,sam0-can"; + reg = <0x42000000 0x400>; + interrupts = <78 0>, <78 0>; + interrupt-names = "LINE_0", "LINE_1"; + clocks = <&gclk 27>, <&mclk 0x10 17>; + clock-names = "GCLK", "MCLK"; + bosch,mram-cfg = <0x0 128 64 64 64 64 32 32>; + divider = <12>; + sample-point = <875>; + sample-point-data = <875>; + status = "disabled"; + }; + + can1: can@42000400 { + compatible = "atmel,sam0-can"; + reg = <0x42000400 0x400>; + interrupts = <79 0>, <79 0>; + interrupt-names = "LINE_0", "LINE_1"; + clocks = <&gclk 28>, <&mclk 0x10 18>; + clock-names = "GCLK", "MCLK"; + bosch,mram-cfg = <0x0 128 64 64 64 64 32 32>; + divider = <12>; + sample-point = <875>; + sample-point-data = <875>; + status = "disabled"; + }; }; }; From b504932ae9b3b1e19aed6002734c2cc39a4f7621 Mon Sep 17 00:00:00 2001 From: Sebastian Schlupp Date: Thu, 30 Nov 2023 14:22:17 +0100 Subject: [PATCH 1124/3723] drivers: can_sam0: added clock configuration for SAME5x devices Added clock source configuration depending on SAM SoC series. Signed-off-by: Sebastian Schlupp --- drivers/can/can_sam0.c | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/drivers/can/can_sam0.c b/drivers/can/can_sam0.c index ac322fe936e..05465de13c1 100644 --- a/drivers/can/can_sam0.c +++ b/drivers/can/can_sam0.c @@ -2,6 +2,7 @@ * Copyright (c) 2022 Vestas Wind Systems A/S * Copyright (c) 2021 Alexander Wachter * Copyright (c) 2022 Kamil Serwus + * Copyright (c) 2023 Sebastian Schlupp * * SPDX-License-Identifier: Apache-2.0 */ @@ -95,7 +96,13 @@ static int can_sam0_get_core_clock(const struct device *dev, uint32_t *rate) const struct can_mcan_config *mcan_cfg = dev->config; const struct can_sam0_config *sam_cfg = mcan_cfg->custom; +#if defined(CONFIG_SOC_SERIES_SAME51) || defined(CONFIG_SOC_SERIES_SAME54) + /*DFFL has to be used as clock source for the ATSAME51/54 family of SoCs*/ + *rate = SOC_ATMEL_SAM0_DFLL48_FREQ_HZ / (sam_cfg->divider); +#elif defined(CONFIG_SOC_SERIES_SAMC21) + /*OSC48M has to be used as clock source for the ATSAMC21 family of SoCs*/ *rate = SOC_ATMEL_SAM0_OSC48M_FREQ_HZ / (sam_cfg->divider); +#endif return 0; } @@ -103,9 +110,17 @@ static int can_sam0_get_core_clock(const struct device *dev, uint32_t *rate) static void can_sam0_clock_enable(const struct can_sam0_config *cfg) { /* Enable the GLCK7 with DIV*/ +#if defined(CONFIG_SOC_SERIES_SAME51) || defined(CONFIG_SOC_SERIES_SAME54) + /*DFFL has to be used as clock source for the ATSAME51/54 family of SoCs*/ + GCLK->GENCTRL[7].reg = GCLK_GENCTRL_SRC(GCLK_GENCTRL_SRC_DFLL) + | GCLK_GENCTRL_DIV(cfg->divider) + | GCLK_GENCTRL_GENEN; +#elif defined(CONFIG_SOC_SERIES_SAMC21) + /*OSC48M has to be used as clock source for the ATSAMC21 family of SoCs*/ GCLK->GENCTRL[7].reg = GCLK_GENCTRL_SRC(GCLK_GENCTRL_SRC_OSC48M) | GCLK_GENCTRL_DIV(cfg->divider) | GCLK_GENCTRL_GENEN; +#endif /* Route channel */ GCLK->PCHCTRL[cfg->gclk_core_id].reg = GCLK_PCHCTRL_GEN_GCLK7 From cb677febb14296d30eeb0b685cb145310fb53e39 Mon Sep 17 00:00:00 2001 From: Mateusz Holenko Date: Mon, 11 Dec 2023 18:17:51 +0100 Subject: [PATCH 1125/3723] dts: riscv: Fix a typo in riscv,isa for mpfs MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The RISC-V ISA extension is called `Zifencei` instead of `Zfencei`. Signed-off-by: Mateusz Hołenko --- dts/riscv/microchip/mpfs.dtsi | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/dts/riscv/microchip/mpfs.dtsi b/dts/riscv/microchip/mpfs.dtsi index e0d206789db..6b81720e095 100644 --- a/dts/riscv/microchip/mpfs.dtsi +++ b/dts/riscv/microchip/mpfs.dtsi @@ -19,7 +19,7 @@ compatible = "riscv"; device_type = "cpu"; reg = < 0x0 >; - riscv,isa = "rv64imac_zicsr_zfencei"; + riscv,isa = "rv64imac_zicsr_zifencei"; hlic0: interrupt-controller { compatible = "riscv,cpu-intc"; #address-cells = <0>; From a451db4981f14ea77f1a11f6b2efd58bbb762442 Mon Sep 17 00:00:00 2001 From: Steffen Jahnke Date: Tue, 5 Dec 2023 09:54:43 +0000 Subject: [PATCH 1126/3723] boards: arm: Fix UART tx/rx pinctrl pan1780_evb/pan1770_evb Changed the tx/rx pins in pinctrl *.dtsi files to match the evaluation board circuit diagram for UART1. Signed-off-by: Steffen Jahnke --- boards/arm/pan1770_evb/pan1770_evb-pinctrl.dtsi | 8 ++++---- boards/arm/pan1780_evb/pan1780_evb-pinctrl.dtsi | 8 ++++---- 2 files changed, 8 insertions(+), 8 deletions(-) diff --git a/boards/arm/pan1770_evb/pan1770_evb-pinctrl.dtsi b/boards/arm/pan1770_evb/pan1770_evb-pinctrl.dtsi index de1bd72e6d0..d8e520eda35 100644 --- a/boards/arm/pan1770_evb/pan1770_evb-pinctrl.dtsi +++ b/boards/arm/pan1770_evb/pan1770_evb-pinctrl.dtsi @@ -30,18 +30,18 @@ uart1_default: uart1_default { group1 { - psels = ; + psels = ; bias-pull-up; }; group2 { - psels = ; + psels = ; }; }; uart1_sleep: uart1_sleep { group1 { - psels = , - ; + psels = , + ; low-power-enable; }; }; diff --git a/boards/arm/pan1780_evb/pan1780_evb-pinctrl.dtsi b/boards/arm/pan1780_evb/pan1780_evb-pinctrl.dtsi index 4643c740884..03ebb8bf8e2 100644 --- a/boards/arm/pan1780_evb/pan1780_evb-pinctrl.dtsi +++ b/boards/arm/pan1780_evb/pan1780_evb-pinctrl.dtsi @@ -29,18 +29,18 @@ uart1_default: uart1_default { group1 { - psels = ; + psels = ; bias-pull-up; }; group2 { - psels = ; + psels = ; }; }; uart1_sleep: uart1_sleep { group1 { - psels = , - ; + psels = , + ; low-power-enable; }; }; From d4ed6bacf03b0905a30fd7979ab2d1092551cef0 Mon Sep 17 00:00:00 2001 From: Ricardo Rivera-Matos Date: Mon, 4 Dec 2023 16:55:29 -0600 Subject: [PATCH 1127/3723] drivers: charger: Adds charge_enable handler Adds a charge_enable handler to facilitate enabling and disabling a charge cycle. This deprecates enabling and disable the charge cycle via the CHARGER_PROP_STATUS property. Signed-off-by: Ricardo Rivera-Matos --- doc/hardware/peripherals/charger.rst | 5 +++++ drivers/charger/charger_handlers.c | 9 +++++++++ include/zephyr/drivers/charger.h | 28 ++++++++++++++++++++++++++++ samples/charger/src/main.c | 2 +- 4 files changed, 43 insertions(+), 1 deletion(-) diff --git a/doc/hardware/peripherals/charger.rst b/doc/hardware/peripherals/charger.rst index b88876058b8..0198fe11f65 100644 --- a/doc/hardware/peripherals/charger.rst +++ b/doc/hardware/peripherals/charger.rst @@ -8,6 +8,11 @@ The charger subsystem exposes an API to uniformly access battery charger devices Basic Operation *************** +Initiating a Charge Cycle +========================= + +A charge cycle is initiated or terminated using :c:func:`charger_charge_enable`. + Properties ========== diff --git a/drivers/charger/charger_handlers.c b/drivers/charger/charger_handlers.c index 417991f9f5f..4fdf6ca7140 100644 --- a/drivers/charger/charger_handlers.c +++ b/drivers/charger/charger_handlers.c @@ -36,3 +36,12 @@ static inline int z_vrfy_charger_set_prop(const struct device *dev, const charge } #include + +static inline int z_vrfy_charger_charge_enable(const struct device *dev, const bool enable) +{ + K_OOPS(K_SYSCALL_DRIVER_CHARGER(dev, charge_enable)); + + return z_impl_charger_charge_enable(dev, enable); +} + +#include diff --git a/include/zephyr/drivers/charger.h b/include/zephyr/drivers/charger.h index 6159f41dcc0..ec40b299d10 100644 --- a/include/zephyr/drivers/charger.h +++ b/include/zephyr/drivers/charger.h @@ -220,6 +220,14 @@ typedef int (*charger_get_property_t)(const struct device *dev, const charger_pr typedef int (*charger_set_property_t)(const struct device *dev, const charger_prop_t prop, const union charger_propval *val); +/** + * @typedef charger_charge_enable_t + * @brief Callback API enabling or disabling a charge cycle. + * + * See charger_charge_enable() for argument description + */ +typedef int (*charger_charge_enable_t)(const struct device *dev, const bool enable); + /** * @brief Charging device API * @@ -228,6 +236,7 @@ typedef int (*charger_set_property_t)(const struct device *dev, const charger_pr __subsystem struct charger_driver_api { charger_get_property_t get_property; charger_set_property_t set_property; + charger_charge_enable_t charge_enable; }; /** @@ -272,6 +281,25 @@ static inline int z_impl_charger_set_prop(const struct device *dev, const charge return api->set_property(dev, prop, val); } +/** + * @brief Enable or disable a charge cycle + * + * @param dev Pointer to the battery charger device + * @param enable true enables a charge cycle, false disables a charge cycle + * + * @retval 0 if successful + * @retval -EIO if communication with the charger failed + * @retval -EINVAL if the conditions for initiating charging are invalid + */ +__syscall int charger_charge_enable(const struct device *dev, const bool enable); + +static inline int z_impl_charger_charge_enable(const struct device *dev, const bool enable) +{ + const struct charger_driver_api *api = (const struct charger_driver_api *)dev->api; + + return api->charge_enable(dev, enable); +} + /** * @} */ diff --git a/samples/charger/src/main.c b/samples/charger/src/main.c index 4f24e1932d9..91961fe15b1 100644 --- a/samples/charger/src/main.c +++ b/samples/charger/src/main.c @@ -45,7 +45,7 @@ int main(void) val.status = CHARGER_STATUS_CHARGING; - ret = charger_set_prop(chgdev, CHARGER_PROP_STATUS, &val); + ret = charger_charge_enable(chgdev, true); if (ret == -ENOTSUP) { printk("Enabling charge not supported, assuming auto charge enable\n"); continue; From 16519a5b3cf84a2da8be234e0e31598496278159 Mon Sep 17 00:00:00 2001 From: Ricardo Rivera-Matos Date: Mon, 4 Dec 2023 17:03:42 -0600 Subject: [PATCH 1128/3723] drivers: charger: Updates drivers to use charge_enable handler Updates existing drivers to make use of the charge_enable handler. Signed-off-by: Ricardo Rivera-Matos --- drivers/charger/charger_max20335.c | 11 +------- drivers/charger/emul_sbs_charger.c | 16 +++++++++-- drivers/charger/sbs_charger.c | 28 +++++++++++-------- .../sbs_charger/src/test_sbs_charger.c | 9 ++---- 4 files changed, 34 insertions(+), 30 deletions(-) diff --git a/drivers/charger/charger_max20335.c b/drivers/charger/charger_max20335.c index 75eae16f888..b4f98de69f2 100644 --- a/drivers/charger/charger_max20335.c +++ b/drivers/charger/charger_max20335.c @@ -235,15 +235,6 @@ static int max20335_set_prop(const struct device *dev, charger_prop_t prop, const union charger_propval *val) { switch (prop) { - case CHARGER_PROP_STATUS: - switch (val->status) { - case CHARGER_STATUS_CHARGING: - return max20335_set_enabled(dev, true); - case CHARGER_STATUS_NOT_CHARGING: - return max20335_set_enabled(dev, false); - default: - return -ENOTSUP; - } case CHARGER_PROP_CONSTANT_CHARGE_CURRENT_UA: return max20335_set_constant_charge_current(dev, val->const_charge_current_ua); @@ -253,7 +244,6 @@ static int max20335_set_prop(const struct device *dev, charger_prop_t prop, default: return -ENOTSUP; } - } static int max20335_init(const struct device *dev) @@ -270,6 +260,7 @@ static int max20335_init(const struct device *dev) static const struct charger_driver_api max20335_driver_api = { .get_property = max20335_get_prop, .set_property = max20335_set_prop, + .charge_enable = max20335_set_enabled, }; #define MAX20335_DEFINE(inst) \ diff --git a/drivers/charger/emul_sbs_charger.c b/drivers/charger/emul_sbs_charger.c index 34d432c8fbb..90c64b908ab 100644 --- a/drivers/charger/emul_sbs_charger.c +++ b/drivers/charger/emul_sbs_charger.c @@ -25,10 +25,20 @@ struct sbs_charger_emul_cfg { uint16_t addr; }; +/** Run-time data used by the emulator */ +struct sbs_charger_emul_data { + uint16_t reg_charger_mode; +}; + static int emul_sbs_charger_reg_write(const struct emul *target, int reg, int val) { + struct sbs_charger_emul_data *data = target->data; + LOG_INF("write %x = %x", reg, val); switch (reg) { + case SBS_CHARGER_REG_CHARGER_MODE: + data->reg_charger_mode = val; + break; default: LOG_ERR("Unknown write %x", reg); return -EIO; @@ -132,10 +142,12 @@ static int emul_sbs_sbs_charger_init(const struct emul *target, const struct dev * Main instantiation macro. SBS Charger Emulator only implemented for I2C */ #define SBS_CHARGER_EMUL(n) \ + static struct sbs_charger_emul_data sbs_charger_emul_data_##n; \ + \ static const struct sbs_charger_emul_cfg sbs_charger_emul_cfg_##n = { \ .addr = DT_INST_REG_ADDR(n), \ }; \ - EMUL_DT_INST_DEFINE(n, emul_sbs_sbs_charger_init, NULL, &sbs_charger_emul_cfg_##n, \ - &sbs_charger_emul_api_i2c, NULL) + EMUL_DT_INST_DEFINE(n, emul_sbs_sbs_charger_init, &sbs_charger_emul_data_##n, \ + &sbs_charger_emul_cfg_##n, &sbs_charger_emul_api_i2c, NULL) DT_INST_FOREACH_STATUS_OKAY(SBS_CHARGER_EMUL) diff --git a/drivers/charger/sbs_charger.c b/drivers/charger/sbs_charger.c index 7cdc99b2a73..9017e1e60b8 100644 --- a/drivers/charger/sbs_charger.c +++ b/drivers/charger/sbs_charger.c @@ -66,6 +66,20 @@ static int sbs_cmd_reg_update(const struct device *dev, uint8_t reg_addr, uint16 return sbs_cmd_reg_write(dev, reg_addr, new_val); } +static int sbs_charger_charge_enable(const struct device *dev, const bool enable) +{ + uint16_t reg_val; + + if (!enable) { + reg_val = SBS_CHARGER_MODE_INHIBIT_CHARGE; + } else { + reg_val = 0; + } + + return sbs_cmd_reg_update(dev, SBS_CHARGER_REG_CHARGER_MODE, + SBS_CHARGER_MODE_INHIBIT_CHARGE, reg_val); +} + static int sbs_charger_get_prop(const struct device *dev, const charger_prop_t prop, union charger_propval *val) { @@ -123,18 +137,7 @@ static int sbs_charger_get_prop(const struct device *dev, const charger_prop_t p static int sbs_charger_set_prop(const struct device *dev, const charger_prop_t prop, const union charger_propval *val) { - uint16_t reg_val = 0; - - switch (prop) { - case CHARGER_PROP_STATUS: - if (val->status != CHARGER_STATUS_CHARGING) { - reg_val = SBS_CHARGER_MODE_INHIBIT_CHARGE; - } - return sbs_cmd_reg_update(dev, SBS_CHARGER_REG_CHARGER_MODE, - SBS_CHARGER_MODE_INHIBIT_CHARGE, reg_val); - default: - return -ENOTSUP; - } + return -ENOTSUP; } /** @@ -157,6 +160,7 @@ static int sbs_charger_init(const struct device *dev) static const struct charger_driver_api sbs_charger_driver_api = { .get_property = &sbs_charger_get_prop, .set_property = &sbs_charger_set_prop, + .charge_enable = &sbs_charger_charge_enable, }; #define SBS_CHARGER_INIT(inst) \ diff --git a/tests/drivers/charger/sbs_charger/src/test_sbs_charger.c b/tests/drivers/charger/sbs_charger/src/test_sbs_charger.c index 9b2b9e66900..fbab9e1a7d0 100644 --- a/tests/drivers/charger/sbs_charger/src/test_sbs_charger.c +++ b/tests/drivers/charger/sbs_charger/src/test_sbs_charger.c @@ -64,14 +64,11 @@ ZTEST_USER_F(sbs_charger, test_set_prop_failed_returns_negative) zassert_equal(ret, -ENOTSUP, "Setting bad property %d has a good status.", prop); } -ZTEST_USER_F(sbs_charger, test_set_prop_success_returns_zero) +ZTEST_USER_F(sbs_charger, test_charge_enable_success_returns_zero) { - union charger_propval val = {.status = CHARGER_STATUS_NOT_CHARGING}; - charger_prop_t prop = CHARGER_PROP_STATUS; + int ret = charger_charge_enable(fixture->dev, true); - int ret = charger_set_prop(fixture->dev, prop, &val); - - zassert_equal(ret, 0, "Setting good property %d has a good status.", prop); + zassert_equal(ret, 0, "Enabling charge has a good status."); } ZTEST_SUITE(sbs_charger, NULL, sbs_charger_setup, NULL, NULL, NULL); From 25787e2df66aef6979503d613c292043ac5f6291 Mon Sep 17 00:00:00 2001 From: Joakim Andersson Date: Fri, 25 Aug 2023 13:44:29 +0200 Subject: [PATCH 1129/3723] tfm: Harded build against TF-M built with unsecure keys Introduce Kconfig option in zephyr build system that reflects the TF-M cmake config variable with the same default value for dummy provisioning and have it satisfy the IAK present requirement. This configuration is not suitable for production, and by having this in zephyr configuration we can have this as part of the hardened configuration check. Signed-off-by: Joakim Andersson --- boards/arm/b_u585i_iot02a/Kconfig.defconfig | 7 +++++++ modules/trusted-firmware-m/CMakeLists.txt | 17 ++++++++++++++++- modules/trusted-firmware-m/Kconfig.tfm | 11 +++++++++++ scripts/kconfig/hardened.csv | 1 + 4 files changed, 35 insertions(+), 1 deletion(-) diff --git a/boards/arm/b_u585i_iot02a/Kconfig.defconfig b/boards/arm/b_u585i_iot02a/Kconfig.defconfig index ae1e57aba8e..e8224106dae 100644 --- a/boards/arm/b_u585i_iot02a/Kconfig.defconfig +++ b/boards/arm/b_u585i_iot02a/Kconfig.defconfig @@ -16,4 +16,11 @@ config SPI_STM32_INTERRUPT config USE_DT_CODE_PARTITION default y if TRUSTED_EXECUTION_NONSECURE +if BUILD_WITH_TFM + +config TFM_DUMMY_PROVISIONING + default n + +endif # BUILD_WITH_TFM + endif # BOARD_B_U585I_IOT02A diff --git a/modules/trusted-firmware-m/CMakeLists.txt b/modules/trusted-firmware-m/CMakeLists.txt index ae5941e5ef6..958c985414e 100644 --- a/modules/trusted-firmware-m/CMakeLists.txt +++ b/modules/trusted-firmware-m/CMakeLists.txt @@ -95,6 +95,12 @@ if (CONFIG_BUILD_WITH_TFM) list(APPEND TFM_CMAKE_ARGS -DMCUBOOT_IMAGE_NUMBER=${CONFIG_TFM_MCUBOOT_IMAGE_NUMBER}) endif() + if (CONFIG_TFM_DUMMY_PROVISIONING) + list(APPEND TFM_CMAKE_ARGS -DTFM_DUMMY_PROVISIONING=ON) + else() + list(APPEND TFM_CMAKE_ARGS -DTFM_DUMMY_PROVISIONING=OFF) + endif() + if (CONFIG_TFM_EXCEPTION_INFO_DUMP) list(APPEND TFM_CMAKE_ARGS -DTFM_EXCEPTION_INFO_DUMP=ON) else() @@ -580,4 +586,13 @@ if (CONFIG_BUILD_WITH_TFM) ${MERGED_FILE} ) endif() -endif() + + if(CONFIG_TFM_DUMMY_PROVISIONING) + message(WARNING + "TFM_DUMMY_PROVISIONING is enabled: + The device will be provisioned using dummy keys and is NOT secure! + This is not suitable for production" + ) + endif() + +endif() # CONFIG_BUILD_WITH_TFM diff --git a/modules/trusted-firmware-m/Kconfig.tfm b/modules/trusted-firmware-m/Kconfig.tfm index f6d13a22153..f1049145b31 100644 --- a/modules/trusted-firmware-m/Kconfig.tfm +++ b/modules/trusted-firmware-m/Kconfig.tfm @@ -180,6 +180,17 @@ config TFM_PARTITION_PLATFORM_CUSTOM_REBOOT Instead the application will have to override the weak ARM implementation of sys_arch_reset(). +config TFM_DUMMY_PROVISIONING + bool "Provision with dummy values. NOT to be used in production" + default y + help + If this option is enabled (as it is by default), a set of dummy + keys / data will be provisioned. The dummy IAK matches the IAK tested + by the TF-M tests, and the dummy bl2 ROTPKs match the dummy bl2 keys + used by default. + This option MUST not be used in production hardware, as the keys are + insecure. + config TFM_BL2_NOT_SUPPORTED bool help diff --git a/scripts/kconfig/hardened.csv b/scripts/kconfig/hardened.csv index ee95b54b3a7..6cc978f7e56 100644 --- a/scripts/kconfig/hardened.csv +++ b/scripts/kconfig/hardened.csv @@ -39,6 +39,7 @@ TEST_RANDOM_GENERATOR,n TEST_SHELL,n TEST_USERSPACE,n TFM_CMAKE_BUILD_TYPE_DEBUG,n +TFM_DUMMY_PROVISIONING,n THREAD_MONITOR,n THREAD_NAME,n TIMER_RANDOM_GENERATOR,n From 2687376effac881c550e2c568c3d4ad10a67385b Mon Sep 17 00:00:00 2001 From: Joakim Andersson Date: Fri, 25 Aug 2023 13:55:49 +0200 Subject: [PATCH 1130/3723] tfm: Enforce initial attestation with required key provisioned Enforce that the initial attestation partition has the required initial attestation key provisioned. If the initial attestation key (IAK) is not present during boot of TF-M the system will panic during initialization. Signed-off-by: Joakim Andersson --- boards/arm/b_u585i_iot02a/Kconfig.defconfig | 4 ++++ modules/trusted-firmware-m/Kconfig.tfm | 8 ++++++++ modules/trusted-firmware-m/Kconfig.tfm.partitions | 1 + 3 files changed, 13 insertions(+) diff --git a/boards/arm/b_u585i_iot02a/Kconfig.defconfig b/boards/arm/b_u585i_iot02a/Kconfig.defconfig index e8224106dae..6b3b72554ff 100644 --- a/boards/arm/b_u585i_iot02a/Kconfig.defconfig +++ b/boards/arm/b_u585i_iot02a/Kconfig.defconfig @@ -18,6 +18,10 @@ config USE_DT_CODE_PARTITION if BUILD_WITH_TFM +# Initial Attestation key provisioned by the BL1 bootloader +config TFM_INITIAL_ATTESTATION_KEY + default y + config TFM_DUMMY_PROVISIONING default n diff --git a/modules/trusted-firmware-m/Kconfig.tfm b/modules/trusted-firmware-m/Kconfig.tfm index f1049145b31..64ffef1fff8 100644 --- a/modules/trusted-firmware-m/Kconfig.tfm +++ b/modules/trusted-firmware-m/Kconfig.tfm @@ -182,6 +182,7 @@ config TFM_PARTITION_PLATFORM_CUSTOM_REBOOT config TFM_DUMMY_PROVISIONING bool "Provision with dummy values. NOT to be used in production" + select TFM_INITIAL_ATTESTATION_KEY default y help If this option is enabled (as it is by default), a set of dummy @@ -191,6 +192,13 @@ config TFM_DUMMY_PROVISIONING This option MUST not be used in production hardware, as the keys are insecure. +config TFM_INITIAL_ATTESTATION_KEY + bool + help + Hidden option to mark that the TF-M platform has an initial + attestation key, which is a requirement for the Initial Attestation + partition. + config TFM_BL2_NOT_SUPPORTED bool help diff --git a/modules/trusted-firmware-m/Kconfig.tfm.partitions b/modules/trusted-firmware-m/Kconfig.tfm.partitions index cd9aaadb1ec..67b46f5328b 100644 --- a/modules/trusted-firmware-m/Kconfig.tfm.partitions +++ b/modules/trusted-firmware-m/Kconfig.tfm.partitions @@ -44,6 +44,7 @@ config TFM_PARTITION_CRYPTO config TFM_PARTITION_INITIAL_ATTESTATION bool "Secure partition 'Initial Attestation'" depends on TFM_PARTITION_CRYPTO + depends on TFM_INITIAL_ATTESTATION_KEY default n help Setting this option will cause '-DTFM_PARTITION_INITIAL_ATTESTATION' From 61dc683b715ae876e287ff69f79056406ec93394 Mon Sep 17 00:00:00 2001 From: Maciej Perkowski Date: Tue, 19 Sep 2023 11:24:32 +0200 Subject: [PATCH 1131/3723] twister: fix typo in filters.QUARANTINE Fix typo filters.QUARENTINE to filters.QUARANTINE Signed-off-by: Maciej Perkowski --- scripts/pylib/twister/twisterlib/testplan.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/scripts/pylib/twister/twisterlib/testplan.py b/scripts/pylib/twister/twisterlib/testplan.py index c1db18d44c7..c0743b7fdee 100755 --- a/scripts/pylib/twister/twisterlib/testplan.py +++ b/scripts/pylib/twister/twisterlib/testplan.py @@ -61,7 +61,7 @@ class Filters: # filters realted to platform definition PLATFORM = 'Platform related filter' # in case a test suite was quarantined. - QUARENTINE = 'Quarantine filter' + QUARANTINE = 'Quarantine filter' # in case a test suite is skipped intentionally . SKIP = 'Skip filter' # in case of incompatibility between selected and allowed toolchains. @@ -849,9 +849,9 @@ def apply_filters(self, **kwargs): instance.testsuite.id, plat.name, plat.arch, plat.simulation ) if matched_quarantine and not self.options.quarantine_verify: - instance.add_filter("Quarantine: " + matched_quarantine, Filters.QUARENTINE) + instance.add_filter("Quarantine: " + matched_quarantine, Filters.QUARANTINE) if not matched_quarantine and self.options.quarantine_verify: - instance.add_filter("Not under quarantine", Filters.QUARENTINE) + instance.add_filter("Not under quarantine", Filters.QUARANTINE) # platform_key is a list of unique platform attributes that form a unique key a test From 2f7364fa0a11a96023678e2796e39e16482cf2f5 Mon Sep 17 00:00:00 2001 From: Maciej Perkowski Date: Tue, 19 Sep 2023 13:20:37 +0200 Subject: [PATCH 1132/3723] twister: Refactor "skip to error" method Use filter statuses instead of string matching in case of quarantine. Signed-off-by: Maciej Perkowski --- scripts/pylib/twister/twisterlib/testplan.py | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/scripts/pylib/twister/twisterlib/testplan.py b/scripts/pylib/twister/twisterlib/testplan.py index c0743b7fdee..32586b7a27b 100755 --- a/scripts/pylib/twister/twisterlib/testplan.py +++ b/scripts/pylib/twister/twisterlib/testplan.py @@ -1006,12 +1006,12 @@ def _create_build_dir_link(self, links_dir_path, instance): def change_skip_to_error_if_integration(options, instance): ''' All skips on integration_platforms are treated as errors.''' - if instance.platform.name in instance.testsuite.integration_platforms \ - and "quarantine" not in instance.reason.lower(): - # Do not treat this as error for a list of filter types. + if instance.platform.name in instance.testsuite.integration_platforms: + # Do not treat this as error if filter type is among ignore_filters filters = {t['type'] for t in instance.filters} ignore_filters ={Filters.CMD_LINE, Filters.SKIP, Filters.PLATFORM_KEY, - Filters.TOOLCHAIN, Filters.MODULE, Filters.TESTPLAN} + Filters.TOOLCHAIN, Filters.MODULE, Filters.TESTPLAN, + Filters.QUARANTINE} if filters.intersection(ignore_filters): return instance.status = "error" From ad011695aba725f6c5887981529e12d101d968a6 Mon Sep 17 00:00:00 2001 From: Bjarki Arge Andreasen Date: Sun, 29 Oct 2023 10:00:28 +0100 Subject: [PATCH 1133/3723] drivers: Add cellular API for network configuration Adds two APIs which allow for configuring the cellular network configuration of a cellular network device. like a cellular modem. The first allows for configuring which access technology to use, and optionally, which bands to use. The second allows for getting all supported access technologies are supported, and which bands for each tech are supported. Signed-off-by: Bjarki Arge Andreasen --- include/zephyr/drivers/cellular.h | 101 ++++++++++++++++++++++++++++++ 1 file changed, 101 insertions(+) create mode 100644 include/zephyr/drivers/cellular.h diff --git a/include/zephyr/drivers/cellular.h b/include/zephyr/drivers/cellular.h new file mode 100644 index 00000000000..303e5237e84 --- /dev/null +++ b/include/zephyr/drivers/cellular.h @@ -0,0 +1,101 @@ +/* + * Copyright (c) 2023 Bjarki Arge Andreasen + * + * SPDX-License-Identifier: Apache-2.0 + */ + +/** + * @file drivers/cellular.h + * @brief Public cellular network API + */ + +#ifndef ZEPHYR_INCLUDE_DRIVERS_CELLULAR_H_ +#define ZEPHYR_INCLUDE_DRIVERS_CELLULAR_H_ + +/** + * @brief Cellular interface + * @defgroup cellular_interface Cellular Interface + * @ingroup io_interfaces + * @{ + */ + +#include +#include +#include + +#ifdef __cplusplus +extern "C" { +#endif + +/** Cellular access technologies */ +enum cellular_access_technology { + CELLULAR_ACCESS_TECHNOLOGY_GSM = 0, + CELLULAR_ACCESS_TECHNOLOGY_GPRS, + CELLULAR_ACCESS_TECHNOLOGY_UMTS, + CELLULAR_ACCESS_TECHNOLOGY_EDGE, + CELLULAR_ACCESS_TECHNOLOGY_LTE, + CELLULAR_ACCESS_TECHNOLOGY_LTE_CAT_M1, + CELLULAR_ACCESS_TECHNOLOGY_LTE_CAT_M2, + CELLULAR_ACCESS_TECHNOLOGY_NB_IOT, +}; + +/** Cellular network structure */ +struct cellular_network { + /** Cellular access technology */ + enum cellular_access_technology technology; + /** + * List of bands, as defined by the specified cellular access technology, + * to enables. All supported bands are enabled if none are provided. + */ + uint16_t *bands; + /** Size of bands */ + uint16_t size; +}; + +/** + * @brief Configure cellular networks for the device + * + * @details Cellular network devices support at least one cellular access technology. + * Each cellular access technology defines a set of bands, of which the cellular device + * will support all or a subset of. + * + * The cellular device can only use one cellular network technology at a time. It must + * exclusively use the cellular network configurations provided, and will prioritize + * the cellular network configurations in the order they are provided in case there are + * multiple (the first cellular network configuration has the highest priority). + * + * @param dev Cellular network device instance. + * @param networks List of cellular network configurations to apply. + * @param size Size of list of cellular network configurations. + * + * @retval 0 if successful. + * @retval -EINVAL if any provided cellular network configuration is invalid or unsupported. + * @retval -ENOTSUP if API is not supported by cellular network device. + * @retval Negative errno-code otherwise. + */ +int cellular_configure_networks(const struct device *dev, const struct cellular_network *networks, + uint8_t size); + +/** + * @brief Get supported cellular networks for the device + * + * @param dev Cellular network device instance + * @param networks Pointer to list of supported cellular network configurations. + * @param size Size of list of cellular network configurations. + * + * @retval 0 if successful. + * @retval -ENOTSUP if API is not supported by cellular network device. + * @retval Negative errno-code otherwise. + */ +int cellular_get_supported_networks(const struct device *dev, + const struct cellular_network **networks, uint8_t *size); + +#ifdef __cplusplus +} +#endif + +/** + * @} + */ + +#endif /* ZEPHYR_INCLUDE_DRIVERS_CELLULAR_H_ */ From d1ba79a070d6939d0bf52fe4f9faf2ad3d89a4f4 Mon Sep 17 00:00:00 2001 From: Lucas Denefle Date: Mon, 6 Nov 2023 16:32:01 +0000 Subject: [PATCH 1134/3723] drivers: cellular: add signal and modem_info API Implement modem info pulling using the init and periodic chat scripts Signed-off-by: Lucas Denefle --- drivers/modem/modem_cellular.c | 231 ++++++++++++++++++++++++++---- include/zephyr/drivers/cellular.h | 53 +++++++ 2 files changed, 259 insertions(+), 25 deletions(-) diff --git a/drivers/modem/modem_cellular.c b/drivers/modem/modem_cellular.c index a038da1805e..ad1bb920cd5 100644 --- a/drivers/modem/modem_cellular.c +++ b/drivers/modem/modem_cellular.c @@ -7,6 +7,7 @@ #include #include #include +#include #include #include #include @@ -25,6 +26,13 @@ LOG_MODULE_REGISTER(modem_cellular, CONFIG_MODEM_LOG_LEVEL); #define MODEM_CELLULAR_PERIODIC_SCRIPT_TIMEOUT \ K_MSEC(CONFIG_MODEM_CELLULAR_PERIODIC_SCRIPT_MS) +#define MODEM_CELLULAR_DATA_IMEI_LEN (15) +#define MODEM_CELLULAR_DATA_MODEL_ID_LEN (64) +#define MODEM_CELLULAR_DATA_IMSI_LEN (22) +#define MODEM_CELLULAR_DATA_ICCID_LEN (22) +#define MODEM_CELLULAR_DATA_MANUFACTURER_LEN (64) +#define MODEM_CELLULAR_DATA_FW_VERSION_LEN (64) + enum modem_cellular_state { MODEM_CELLULAR_STATE_IDLE = 0, MODEM_CELLULAR_STATE_RESET_PULSE, @@ -83,11 +91,16 @@ struct modem_cellular_data { uint8_t *chat_argv[32]; /* Status */ - uint8_t imei[15]; - uint8_t hwinfo[64]; uint8_t registration_status_gsm; uint8_t registration_status_gprs; uint8_t registration_status_lte; + int8_t rssi; + uint8_t imei[MODEM_CELLULAR_DATA_IMEI_LEN]; + uint8_t model_id[MODEM_CELLULAR_DATA_MODEL_ID_LEN]; + uint8_t imsi[MODEM_CELLULAR_DATA_IMSI_LEN]; + uint8_t iccid[MODEM_CELLULAR_DATA_ICCID_LEN]; + uint8_t manufacturer[MODEM_CELLULAR_DATA_MANUFACTURER_LEN]; + uint8_t fw_version[MODEM_CELLULAR_DATA_FW_VERSION_LEN]; /* PPP */ struct modem_ppp *ppp; @@ -118,6 +131,7 @@ struct modem_cellular_config { const struct modem_chat_script *init_chat_script; const struct modem_chat_script *dial_chat_script; const struct modem_chat_script *periodic_chat_script; + const struct modem_chat_script *get_signal_chat_script; }; static const char *modem_cellular_state_str(enum modem_cellular_state state) @@ -276,16 +290,34 @@ static void modem_cellular_chat_on_imei(struct modem_chat *chat, char **argv, ui return; } - if (strlen(argv[1]) != 15) { + strncpy(data->imei, argv[1], sizeof(data->imei)); +} + +static void modem_cellular_chat_on_cgmm(struct modem_chat *chat, char **argv, uint16_t argc, + void *user_data) +{ + struct modem_cellular_data *data = (struct modem_cellular_data *)user_data; + + if (argc != 2) { return; } - for (uint8_t i = 0; i < 15; i++) { - data->imei[i] = argv[1][i] - '0'; + strncpy(data->model_id, argv[1], sizeof(data->model_id)); +} + +static void modem_cellular_chat_on_cgmi(struct modem_chat *chat, char **argv, uint16_t argc, + void *user_data) +{ + struct modem_cellular_data *data = (struct modem_cellular_data *)user_data; + + if (argc != 2) { + return; } + + strncpy(data->manufacturer, argv[1], sizeof(data->manufacturer)); } -static void modem_cellular_chat_on_cgmm(struct modem_chat *chat, char **argv, uint16_t argc, +static void modem_cellular_chat_on_cgmr(struct modem_chat *chat, char **argv, uint16_t argc, void *user_data) { struct modem_cellular_data *data = (struct modem_cellular_data *)user_data; @@ -294,7 +326,50 @@ static void modem_cellular_chat_on_cgmm(struct modem_chat *chat, char **argv, ui return; } - strncpy(data->hwinfo, argv[1], sizeof(data->hwinfo) - 1); + strncpy(data->fw_version, argv[1], sizeof(data->fw_version)); +} + +static void modem_cellular_chat_on_csq(struct modem_chat *chat, char **argv, uint16_t argc, + void *user_data) +{ + uint8_t rssi; + + /* AT+CSQ returns a response +CSQ: , where: + * - rssi is a integer from 0 to 31 whose values describes a signal strength + * between -113 dBm for 0 and -51dbM for 31 or unknown for 99 + * - ber is an integer from 0 to 7 that describes the error rate, it can also + * be 99 for an unknown error rate + */ + struct modem_cellular_data *data = (struct modem_cellular_data *)user_data; + + if (argc != 3) { + return; + } + + /* Read rssi */ + rssi = atoi(argv[1]); + + if (rssi == 99) { + return; + } + + data->rssi = (-113 + (2 * rssi)); +} + +static void modem_cellular_chat_on_imsi(struct modem_chat *chat, char **argv, uint16_t argc, + void *user_data) +{ + struct modem_cellular_data *data = (struct modem_cellular_data *)user_data; + + strncpy(data->imsi, (char *)argv[1], sizeof(data->imsi)); +} + +static void modem_cellular_chat_on_iccid(struct modem_chat *chat, char **argv, uint16_t argc, + void *user_data) +{ + struct modem_cellular_data *data = (struct modem_cellular_data *)user_data; + + strncpy(data->iccid, (char *)argv[1], sizeof(data->iccid)); } static bool modem_cellular_is_registered(struct modem_cellular_data *data) @@ -346,6 +421,11 @@ MODEM_CHAT_MATCHES_DEFINE(allow_match, MODEM_CHAT_MATCH_DEFINE(imei_match, "", "", modem_cellular_chat_on_imei); MODEM_CHAT_MATCH_DEFINE(cgmm_match, "", "", modem_cellular_chat_on_cgmm); +MODEM_CHAT_MATCH_DEFINE(csq_match, "+CSQ: ", ",", modem_cellular_chat_on_csq); +MODEM_CHAT_MATCH_DEFINE(cimi_match, "", "", modem_cellular_chat_on_imsi); +MODEM_CHAT_MATCH_DEFINE(ccid_match, "+QCCID: ", "", modem_cellular_chat_on_iccid); +MODEM_CHAT_MATCH_DEFINE(cgmi_match, "", "", modem_cellular_chat_on_cgmi); +MODEM_CHAT_MATCH_DEFINE(cgmr_match, "", "", modem_cellular_chat_on_cgmr); MODEM_CHAT_MATCHES_DEFINE(unsol_matches, MODEM_CHAT_MATCH("+CREG: ", ",", modem_cellular_chat_on_cxreg), @@ -1336,6 +1416,14 @@ MODEM_CHAT_SCRIPT_CMDS_DEFINE(quectel_bg95_init_chat_script_cmds, MODEM_CHAT_SCRIPT_CMD_RESP("", ok_match), MODEM_CHAT_SCRIPT_CMD_RESP("AT+CGMM", cgmm_match), MODEM_CHAT_SCRIPT_CMD_RESP("", ok_match), + MODEM_CHAT_SCRIPT_CMD_RESP("AT+CGMI", cgmi_match), + MODEM_CHAT_SCRIPT_CMD_RESP("", ok_match), + MODEM_CHAT_SCRIPT_CMD_RESP("AT+CGMR", cgmr_match), + MODEM_CHAT_SCRIPT_CMD_RESP("", ok_match), + MODEM_CHAT_SCRIPT_CMD_RESP("AT+CIMI", cimi_match), + MODEM_CHAT_SCRIPT_CMD_RESP("", ok_match), + MODEM_CHAT_SCRIPT_CMD_RESP("AT+QCCID", ccid_match), + MODEM_CHAT_SCRIPT_CMD_RESP("", ok_match), MODEM_CHAT_SCRIPT_CMD_RESP_NONE("AT+CMUX=0,0,5,127", 300)); MODEM_CHAT_SCRIPT_DEFINE(quectel_bg95_init_chat_script, quectel_bg95_init_chat_script_cmds, @@ -1355,29 +1443,45 @@ MODEM_CHAT_SCRIPT_DEFINE(quectel_bg95_dial_chat_script, quectel_bg95_dial_chat_s MODEM_CHAT_SCRIPT_CMDS_DEFINE(quectel_bg95_periodic_chat_script_cmds, MODEM_CHAT_SCRIPT_CMD_RESP("AT+CREG?", ok_match), MODEM_CHAT_SCRIPT_CMD_RESP("AT+CEREG?", ok_match), - MODEM_CHAT_SCRIPT_CMD_RESP("AT+CGREG?", ok_match)); + MODEM_CHAT_SCRIPT_CMD_RESP("AT+CGREG?", ok_match), + MODEM_CHAT_SCRIPT_CMD_RESP("AT+CSQ", csq_match)); MODEM_CHAT_SCRIPT_DEFINE(quectel_bg95_periodic_chat_script, quectel_bg95_periodic_chat_script_cmds, abort_matches, modem_cellular_chat_callback_handler, 4); + +MODEM_CHAT_SCRIPT_CMDS_DEFINE(quectel_bg95_get_signal_chat_script_cmds, + MODEM_CHAT_SCRIPT_CMD_RESP("AT+CSQ", csq_match)); + +MODEM_CHAT_SCRIPT_DEFINE(quectel_bg95_get_signal_chat_script, + quectel_bg95_get_signal_chat_script_cmds, abort_matches, + modem_cellular_chat_callback_handler, 4); #endif #if DT_HAS_COMPAT_STATUS_OKAY(quectel_eg25_g) -MODEM_CHAT_SCRIPT_CMDS_DEFINE(quectel_eg25_g_init_chat_script_cmds, - MODEM_CHAT_SCRIPT_CMD_RESP("ATE0", ok_match), - MODEM_CHAT_SCRIPT_CMD_RESP("AT+CFUN=4", ok_match), - MODEM_CHAT_SCRIPT_CMD_RESP("AT+CMEE=1", ok_match), - MODEM_CHAT_SCRIPT_CMD_RESP("AT+CREG=1", ok_match), - MODEM_CHAT_SCRIPT_CMD_RESP("AT+CGREG=1", ok_match), - MODEM_CHAT_SCRIPT_CMD_RESP("AT+CEREG=1", ok_match), - MODEM_CHAT_SCRIPT_CMD_RESP("AT+CREG?", ok_match), - MODEM_CHAT_SCRIPT_CMD_RESP("AT+CEREG?", ok_match), - MODEM_CHAT_SCRIPT_CMD_RESP("AT+CGREG?", ok_match), - MODEM_CHAT_SCRIPT_CMD_RESP("AT+CGSN", imei_match), - MODEM_CHAT_SCRIPT_CMD_RESP("", ok_match), - MODEM_CHAT_SCRIPT_CMD_RESP("AT+CGMM", cgmm_match), - MODEM_CHAT_SCRIPT_CMD_RESP_NONE("AT+CMUX=0,0,5,127,10,3,30,10,2", - 100)); +MODEM_CHAT_SCRIPT_CMDS_DEFINE( + quectel_eg25_g_init_chat_script_cmds, MODEM_CHAT_SCRIPT_CMD_RESP("ATE0", ok_match), + MODEM_CHAT_SCRIPT_CMD_RESP("AT+CFUN=4", ok_match), + MODEM_CHAT_SCRIPT_CMD_RESP("AT+CMEE=1", ok_match), + MODEM_CHAT_SCRIPT_CMD_RESP("AT+CREG=1", ok_match), + MODEM_CHAT_SCRIPT_CMD_RESP("AT+CGREG=1", ok_match), + MODEM_CHAT_SCRIPT_CMD_RESP("AT+CEREG=1", ok_match), + MODEM_CHAT_SCRIPT_CMD_RESP("AT+CREG?", ok_match), + MODEM_CHAT_SCRIPT_CMD_RESP("AT+CEREG?", ok_match), + MODEM_CHAT_SCRIPT_CMD_RESP("AT+CGREG?", ok_match), + MODEM_CHAT_SCRIPT_CMD_RESP("AT+CGSN", imei_match), + MODEM_CHAT_SCRIPT_CMD_RESP("", ok_match), + MODEM_CHAT_SCRIPT_CMD_RESP("AT+CGMM", cgmm_match), + MODEM_CHAT_SCRIPT_CMD_RESP("", ok_match), + MODEM_CHAT_SCRIPT_CMD_RESP("AT+CGMI", cgmi_match), + MODEM_CHAT_SCRIPT_CMD_RESP("", ok_match), + MODEM_CHAT_SCRIPT_CMD_RESP("AT+CGMR", cgmr_match), + MODEM_CHAT_SCRIPT_CMD_RESP("", ok_match), + MODEM_CHAT_SCRIPT_CMD_RESP("AT+CIMI", cimi_match), + MODEM_CHAT_SCRIPT_CMD_RESP("", ok_match), + MODEM_CHAT_SCRIPT_CMD_RESP("AT+QCCID", ccid_match), + MODEM_CHAT_SCRIPT_CMD_RESP("", ok_match), + MODEM_CHAT_SCRIPT_CMD_RESP_NONE("AT+CMUX=0,0,5,127,10,3,30,10,2", 100)); MODEM_CHAT_SCRIPT_DEFINE(quectel_eg25_g_init_chat_script, quectel_eg25_g_init_chat_script_cmds, abort_matches, modem_cellular_chat_callback_handler, 10); @@ -1396,11 +1500,19 @@ MODEM_CHAT_SCRIPT_DEFINE(quectel_eg25_g_dial_chat_script, quectel_eg25_g_dial_ch MODEM_CHAT_SCRIPT_CMDS_DEFINE(quectel_eg25_g_periodic_chat_script_cmds, MODEM_CHAT_SCRIPT_CMD_RESP("AT+CREG?", ok_match), MODEM_CHAT_SCRIPT_CMD_RESP("AT+CEREG?", ok_match), - MODEM_CHAT_SCRIPT_CMD_RESP("AT+CGREG?", ok_match)); + MODEM_CHAT_SCRIPT_CMD_RESP("AT+CGREG?", ok_match), + MODEM_CHAT_SCRIPT_CMD_RESP("AT+CSQ", csq_match)); MODEM_CHAT_SCRIPT_DEFINE(quectel_eg25_g_periodic_chat_script, quectel_eg25_g_periodic_chat_script_cmds, abort_matches, modem_cellular_chat_callback_handler, 4); + +MODEM_CHAT_SCRIPT_CMDS_DEFINE(quectel_eg25_g_get_signal_chat_script_cmds, + MODEM_CHAT_SCRIPT_CMD_RESP("AT+CSQ", csq_match)); + +MODEM_CHAT_SCRIPT_DEFINE(quectel_eg25_g_get_signal_chat_script, + quectel_eg25_g_get_signal_chat_script_cmds, abort_matches, + modem_cellular_chat_callback_handler, 4); #endif #if DT_HAS_COMPAT_STATUS_OKAY(zephyr_gsm_ppp) @@ -1708,7 +1820,8 @@ MODEM_CHAT_SCRIPT_DEFINE(telit_me910g1_periodic_chat_script, .shutdown_time_ms = 5000, \ .init_chat_script = &quectel_bg95_init_chat_script, \ .dial_chat_script = &quectel_bg95_dial_chat_script, \ - .periodic_chat_script = &quectel_bg95_periodic_chat_script, \ + .periodic_chat_script = &_CONCAT(DT_DRV_COMPAT, _periodic_chat_script), \ + .get_signal_chat_script = &_CONCAT(DT_DRV_COMPAT, _get_signal_chat_script), \ }; \ \ PM_DEVICE_DT_INST_DEFINE(inst, modem_cellular_pm_action); \ @@ -1737,6 +1850,7 @@ MODEM_CHAT_SCRIPT_DEFINE(telit_me910g1_periodic_chat_script, .init_chat_script = &quectel_eg25_g_init_chat_script, \ .dial_chat_script = &quectel_eg25_g_dial_chat_script, \ .periodic_chat_script = &_CONCAT(DT_DRV_COMPAT, _periodic_chat_script), \ + .get_signal_chat_script = &_CONCAT(DT_DRV_COMPAT, _get_signal_chat_script), \ }; \ \ PM_DEVICE_DT_INST_DEFINE(inst, modem_cellular_pm_action); \ @@ -1945,3 +2059,70 @@ DT_INST_FOREACH_STATUS_OKAY(MODEM_CELLULAR_DEVICE_SWIR_HL7800) #define DT_DRV_COMPAT telit_me910g1 DT_INST_FOREACH_STATUS_OKAY(MODEM_CELLULAR_DEVICE_TELIT_ME910G1) #undef DT_DRV_COMPAT + +int cellular_get_modem_info(const struct device *dev, enum cellular_modem_info_type type, + char *info, size_t size) +{ + int ret = 0; + struct modem_cellular_data *data = (struct modem_cellular_data *)dev->data; + + switch (type) { + case CELLULAR_MODEM_INFO_IMEI: + strncpy(info, &data->imei[0], MIN(size, sizeof(data->imei))); + break; + case CELLULAR_MODEM_INFO_SIM_IMSI: + strncpy(info, &data->imsi[0], MIN(size, sizeof(data->imsi))); + break; + case CELLULAR_MODEM_INFO_SIM_ICCID: + strncpy(info, &data->iccid[0], MIN(size, sizeof(data->iccid))); + break; + case CELLULAR_MODEM_INFO_MANUFACTURER: + strncpy(info, &data->manufacturer[0], MIN(size, sizeof(data->manufacturer))); + break; + case CELLULAR_MODEM_INFO_FW_VERSION: + strncpy(info, &data->fw_version[0], MIN(size, sizeof(data->fw_version))); + break; + case CELLULAR_MODEM_INFO_MODEL_ID: + strncpy(info, &data->model_id[0], MIN(size, sizeof(data->model_id))); + break; + default: + ret = -ENODATA; + break; + } + + return ret; +} + +int cellular_get_signal(const struct device *dev, const enum cellular_signal_type type, + int16_t *value) +{ + int ret; + struct modem_cellular_data *data = (struct modem_cellular_data *)dev->data; + const struct modem_cellular_config *config = (struct modem_cellular_config *)dev->config; + + if (config->get_signal_chat_script == NULL) { + return -ENOTSUP; + } + + if ((data->state != MODEM_CELLULAR_STATE_AWAIT_REGISTERED) && + (data->state != MODEM_CELLULAR_STATE_CARRIER_ON)) { + return -ENODATA; + } + + ret = modem_chat_run_script(&data->chat, config->get_signal_chat_script); + if (ret != 0) { + return ret; + } + + switch (type) { + case CELLULAR_SIGNAL_RSSI: { + *value = data->rssi; + } break; + case CELLULAR_SIGNAL_RSRP: + return -ENOTSUP; + case CELLULAR_SIGNAL_RSRQ: + return -ENOTSUP; + } + + return ret; +} diff --git a/include/zephyr/drivers/cellular.h b/include/zephyr/drivers/cellular.h index 303e5237e84..83135967123 100644 --- a/include/zephyr/drivers/cellular.h +++ b/include/zephyr/drivers/cellular.h @@ -52,6 +52,28 @@ struct cellular_network { uint16_t size; }; +enum cellular_signal_type { + CELLULAR_SIGNAL_RSSI, + CELLULAR_SIGNAL_RSRP, + CELLULAR_SIGNAL_RSRQ, +}; + +/** Cellular modem info type */ +enum cellular_modem_info_type { + /** International Mobile Equipment Identity */ + CELLULAR_MODEM_INFO_IMEI, + /** Modem model ID */ + CELLULAR_MODEM_INFO_MODEL_ID, + /** Modem manufacturer */ + CELLULAR_MODEM_INFO_MANUFACTURER, + /** Modem fw version */ + CELLULAR_MODEM_INFO_FW_VERSION, + /** International Mobile Subscriber Identity */ + CELLULAR_MODEM_INFO_SIM_IMSI, + /** Integrated Circuit Card Identification Number (SIM) */ + CELLULAR_MODEM_INFO_SIM_ICCID, +}; + /** * @brief Configure cellular networks for the device * @@ -90,6 +112,37 @@ int cellular_configure_networks(const struct device *dev, const struct cellular_ int cellular_get_supported_networks(const struct device *dev, const struct cellular_network **networks, uint8_t *size); +/** + * @brief Get signal for the device + * + * @param dev Cellular network device instance + * @param type Type of the signal information requested + * @param value Signal strength destination (one of RSSI, RSRP, RSRQ) + * + * @retval 0 if successful. + * @retval -ENOTSUP if API is not supported by cellular network device. + * @retval -ENODATA if device is not in a state where signal can be polled + * @retval Negative errno-code otherwise. + */ +int cellular_get_signal(const struct device *dev, const enum cellular_signal_type type, + int16_t *value); + +/** + * @brief Get modem info for the device + * + * @param dev Cellular network device instance + * @param type Type of the modem info requested + * @param info Info string destination + * @param size Info string size + * + * @retval 0 if successful. + * @retval -ENOTSUP if API is not supported by cellular network device. + * @retval -ENODATA if modem does not provide info requested + * @retval Negative errno-code from chat module otherwise. + */ +int cellular_get_modem_info(const struct device *dev, const enum cellular_modem_info_type type, + char *info, size_t size); + #ifdef __cplusplus } #endif From b287db8fd3f18a61e1700d8741d6387c7c9555f9 Mon Sep 17 00:00:00 2001 From: Lucas Denefle Date: Wed, 29 Nov 2023 09:50:13 +0000 Subject: [PATCH 1135/3723] samples: net: cellular_modem: polls cellular info Adds an example of polling cellular info to the modem sample Signed-off-by: Lucas Denefle --- samples/net/cellular_modem/src/main.c | 47 +++++++++++++++++++++++++++ 1 file changed, 47 insertions(+) diff --git a/samples/net/cellular_modem/src/main.c b/samples/net/cellular_modem/src/main.c index 95e1c45f160..35a97d3e831 100644 --- a/samples/net/cellular_modem/src/main.c +++ b/samples/net/cellular_modem/src/main.c @@ -13,6 +13,8 @@ #include #include +#include + #define SAMPLE_TEST_ENDPOINT_HOSTNAME ("test-endpoint.com") #define SAMPLE_TEST_ENDPOINT_UDP_ECHO_PORT (7780) #define SAMPLE_TEST_ENDPOINT_UDP_RECEIVE_PORT (7781) @@ -44,6 +46,48 @@ static void init_sample_test_packet(void) } } +static void print_cellular_info(void) +{ + int rc; + int16_t rssi; + char buffer[64]; + + rc = cellular_get_signal(modem, CELLULAR_SIGNAL_RSSI, &rssi); + if (!rc) { + printk("RSSI %d\n", rssi); + } + + rc = cellular_get_modem_info(modem, CELLULAR_MODEM_INFO_IMEI, &buffer[0], sizeof(buffer)); + if (!rc) { + printk("IMEI: %s\n", buffer); + } + rc = cellular_get_modem_info(modem, CELLULAR_MODEM_INFO_MODEL_ID, &buffer[0], + sizeof(buffer)); + if (!rc) { + printk("MODEL_ID: %s\n", buffer); + } + rc = cellular_get_modem_info(modem, CELLULAR_MODEM_INFO_MANUFACTURER, &buffer[0], + sizeof(buffer)); + if (!rc) { + printk("MANUFACTURER: %s\n", buffer); + } + rc = cellular_get_modem_info(modem, CELLULAR_MODEM_INFO_SIM_IMSI, &buffer[0], + sizeof(buffer)); + if (!rc) { + printk("SIM_IMSI: %s\n", buffer); + } + rc = cellular_get_modem_info(modem, CELLULAR_MODEM_INFO_SIM_ICCID, &buffer[0], + sizeof(buffer)); + if (!rc) { + printk("SIM_ICCID: %s\n", buffer); + } + rc = cellular_get_modem_info(modem, CELLULAR_MODEM_INFO_FW_VERSION, &buffer[0], + sizeof(buffer)); + if (!rc) { + printk("FW_VERSION: %s\n", buffer); + } +} + static void sample_dns_request_result(enum dns_resolve_status status, struct dns_addrinfo *info, void *user_data) { @@ -264,6 +308,9 @@ int main(void) NET_EVENT_DNS_SERVER_ADD, &raised_event, &info, &info_len, K_SECONDS(10)); + printk("Retrieving cellular info\n"); + print_cellular_info(); + printk("Performing DNS lookup of %s\n", SAMPLE_TEST_ENDPOINT_HOSTNAME); ret = sample_dns_request(); if (ret < 0) { From 545a3973a8630d5ba15c5e4a82fa12918022f776 Mon Sep 17 00:00:00 2001 From: Xudong Zheng <7pkvm5aw@slicealias.com> Date: Wed, 1 Nov 2023 10:52:51 -0400 Subject: [PATCH 1136/3723] bluetooth: bas: remove select SENSOR Bluetooth battery service does not use sensor. Signed-off-by: Xudong Zheng <7pkvm5aw@slicealias.com> --- subsys/bluetooth/services/Kconfig.bas | 1 - 1 file changed, 1 deletion(-) diff --git a/subsys/bluetooth/services/Kconfig.bas b/subsys/bluetooth/services/Kconfig.bas index 3a8789aad93..2dbff5fcc33 100644 --- a/subsys/bluetooth/services/Kconfig.bas +++ b/subsys/bluetooth/services/Kconfig.bas @@ -5,4 +5,3 @@ config BT_BAS bool "GATT Battery service" - select SENSOR From 6421c7a5fe0f69faaedb450c2ddcc5d1bc2989e4 Mon Sep 17 00:00:00 2001 From: Daniel Leung Date: Wed, 11 Oct 2023 13:05:55 -0700 Subject: [PATCH 1137/3723] os: timing: polish doxygen () Moves the architecture specific timing measurement APIs under the timing measurement APIs group. () Add SoC and board specific API groups. () Document each SoC and board specific API so the doc shows up for them. Signed-off-by: Daniel Leung --- doc/kernel/timing_functions/index.rst | 3 + include/zephyr/sys/arch_interface.h | 22 ++- include/zephyr/timing/timing.h | 226 +++++++++++++++++++++++++- 3 files changed, 244 insertions(+), 7 deletions(-) diff --git a/doc/kernel/timing_functions/index.rst b/doc/kernel/timing_functions/index.rst index 5f21204c4e6..711ce319fcc 100644 --- a/doc/kernel/timing_functions/index.rst +++ b/doc/kernel/timing_functions/index.rst @@ -78,3 +78,6 @@ API documentation ***************** .. doxygengroup:: timing_api +.. doxygengroup:: timing_api_arch +.. doxygengroup:: timing_api_soc +.. doxygengroup:: timing_api_board diff --git a/include/zephyr/sys/arch_interface.h b/include/zephyr/sys/arch_interface.h index dc1d8f2e5a8..d044f578fae 100644 --- a/include/zephyr/sys/arch_interface.h +++ b/include/zephyr/sys/arch_interface.h @@ -1057,7 +1057,13 @@ int arch_gdb_remove_breakpoint(struct gdb_ctx *ctx, uint8_t type, #include /** - * @ingroup arch-timing + * @brief Arch specific Timing Measurement APIs + * @defgroup timing_api_arch Arch specific Timing Measurement APIs + * @ingroup timing_api + * + * Implements the necessary bits to support timing measurement + * using architecture specific timing measurement mechanism. + * * @{ */ @@ -1101,17 +1107,25 @@ void arch_timing_stop(void); /** * @brief Return timing counter. * + * @parblock + * * @note Any call to arch_timing_counter_get() must be done between * calls to arch_timing_start() and arch_timing_stop(), and on the * same CPU core. * - * @note Not all platforms have a timing counter with 64 bit precision. It - * is possible to see this value "go backwards" due to internal + * @endparblock + * + * @parblock + * + * @note Not all architectures have a timing counter with 64 bit precision. + * It is possible to see this value "go backwards" due to internal * rollover. Timing code must be prepared to address the rollover * (with platform-dependent code, e.g. by casting to a uint32_t before * subtraction) or by using arch_timing_cycles_get() which is required * to understand the distinction. * + * @endparblock + * * @return Timing counter. * * @see timing_counter_get() @@ -1121,7 +1135,7 @@ timing_t arch_timing_counter_get(void); /** * @brief Get number of cycles between @p start and @p end. * - * For some architectures or SoCs, the raw numbers from counter need + * @note For some architectures, the raw numbers from counter need * to be scaled to obtain actual number of cycles, or may roll over * internally. This function computes a positive-definite interval * between two returned cycle values. diff --git a/include/zephyr/timing/timing.h b/include/zephyr/timing/timing.h index bf9ee9033e9..a0c4a644abb 100644 --- a/include/zephyr/timing/timing.h +++ b/include/zephyr/timing/timing.h @@ -14,33 +14,253 @@ extern "C" { #endif +/** + * @brief Timing Measurement APIs + * @defgroup timing_api Timing Measurement APIs + * @ingroup os_services + * + * The timing measurement APIs can be used to obtain execution + * time of a section of code to aid in analysis and optimization. + * + * Please note that the timing functions may use a different timer + * than the default kernel timer, where the timer being used is + * specified by architecture, SoC or board configuration. + */ + +/** + * @brief SoC specific Timing Measurement APIs + * @defgroup timing_api_soc SoC specific Timing Measurement APIs + * @ingroup timing_api + * + * Implements the necessary bits to support timing measurement + * using SoC specific timing measurement mechanism. + * + * @{ + */ + +/** + * @brief Initialize the timing subsystem on SoC. + * + * Perform the necessary steps to initialize the timing subsystem. + * + * @see timing_init() + */ void soc_timing_init(void); + +/** + * @brief Signal the start of the timing information gathering. + * + * Signal to the timing subsystem that timing information + * will be gathered from this point forward. + * + * @see timing_start() + */ void soc_timing_start(void); + +/** + * @brief Signal the end of the timing information gathering. + * + * Signal to the timing subsystem that timing information + * is no longer being gathered from this point forward. + * + * @see timing_stop() + */ void soc_timing_stop(void); + +/** + * @brief Return timing counter. + * + * @note Not all SoCs have timing counters with 64 bit precision. It + * is possible to see this value "go backwards" due to internal + * rollover. Timing code must be prepared to address the rollover + * (with SoC dependent code, e.g. by casting to a uint32_t before + * subtraction) or by using soc_timing_cycles_get() which is required + * to understand the distinction. + * + * @return Timing counter. + * + * @see timing_counter_get() + */ timing_t soc_timing_counter_get(void); + +/** + * @brief Get number of cycles between @p start and @p end. + * + * @note The raw numbers from counter need to be scaled to + * obtain actual number of cycles, or may roll over internally. + * This function computes a positive-definite interval between two + * returned cycle values. + * + * @param start Pointer to counter at start of a measured execution. + * @param end Pointer to counter at stop of a measured execution. + * @return Number of cycles between start and end. + * + * @see timing_cycles_get() + */ uint64_t soc_timing_cycles_get(volatile timing_t *const start, volatile timing_t *const end); + +/** + * @brief Get frequency of counter used (in Hz). + * + * @return Frequency of counter used for timing in Hz. + * + * @see timing_freq_get() + */ uint64_t soc_timing_freq_get(void); + +/** + * @brief Convert number of @p cycles into nanoseconds. + * + * @param cycles Number of cycles + * @return Converted time value + * + * @see timing_cycles_to_ns() + */ uint64_t soc_timing_cycles_to_ns(uint64_t cycles); + +/** + * @brief Convert number of @p cycles into nanoseconds with averaging. + * + * @param cycles Number of cycles + * @param count Times of accumulated cycles to average over + * @return Converted time value + * + * @see timing_cycles_to_ns_avg() + */ uint64_t soc_timing_cycles_to_ns_avg(uint64_t cycles, uint32_t count); + +/** + * @brief Get frequency of counter used (in MHz). + * + * @return Frequency of counter used for timing in MHz. + * + * @see timing_freq_get_mhz() + */ uint32_t soc_timing_freq_get_mhz(void); +/** + * @} + */ + +/** + * @brief Board specific Timing Measurement APIs + * @defgroup timing_api_board Board specific Timing Measurement APIs + * @ingroup timing_api + * + * Implements the necessary bits to support timing measurement + * using board specific timing measurement mechanism. + * + * @{ + */ + +/** + * @brief Initialize the timing subsystem. + * + * Perform the necessary steps to initialize the timing subsystem. + * + * @see timing_init() + */ void board_timing_init(void); + +/** + * @brief Signal the start of the timing information gathering. + * + * Signal to the timing subsystem that timing information + * will be gathered from this point forward. + * + * @see timing_start() + */ void board_timing_start(void); + +/** + * @brief Signal the end of the timing information gathering. + * + * Signal to the timing subsystem that timing information + * is no longer being gathered from this point forward. + * + * @see timing_stop() + */ void board_timing_stop(void); + +/** + * @brief Return timing counter. + * + * @note Not all timing counters have 64 bit precision. It is + * possible to see this value "go backwards" due to internal + * rollover. Timing code must be prepared to address the rollover + * (with board dependent code, e.g. by casting to a uint32_t before + * subtraction) or by using board_timing_cycles_get() which is required + * to understand the distinction. + * + * @return Timing counter. + * + * @see timing_counter_get() + */ timing_t board_timing_counter_get(void); + +/** + * @brief Get number of cycles between @p start and @p end. + * + * @note The raw numbers from counter need to be scaled to + * obtain actual number of cycles, or may roll over internally. + * This function computes a positive-definite interval between two + * returned cycle values. + * + * @param start Pointer to counter at start of a measured execution. + * @param end Pointer to counter at stop of a measured execution. + * @return Number of cycles between start and end. + * + * @see timing_cycles_get() + */ uint64_t board_timing_cycles_get(volatile timing_t *const start, volatile timing_t *const end); + +/** + * @brief Get frequency of counter used (in Hz). + * + * @return Frequency of counter used for timing in Hz. + * + * @see timing_freq_get() + */ uint64_t board_timing_freq_get(void); + +/** + * @brief Convert number of @p cycles into nanoseconds. + * + * @param cycles Number of cycles + * @return Converted time value + * + * @see timing_cycles_to_ns() + */ uint64_t board_timing_cycles_to_ns(uint64_t cycles); + +/** + * @brief Convert number of @p cycles into nanoseconds with averaging. + * + * @param cycles Number of cycles + * @param count Times of accumulated cycles to average over + * @return Converted time value + * + * @see timing_cycles_to_ns_avg() + */ uint64_t board_timing_cycles_to_ns_avg(uint64_t cycles, uint32_t count); + +/** + * @brief Get frequency of counter used (in MHz). + * + * @return Frequency of counter used for timing in MHz. + * + * @see timing_freq_get_mhz() + */ uint32_t board_timing_freq_get_mhz(void); +/** + * @} + */ /** - * @brief Timing Measurement APIs - * @defgroup timing_api Timing APIs - * @ingroup os_services + * @addtogroup timing_api * @{ */ From b1cc7312cf97ef8877c8360d5477acccf5e505ac Mon Sep 17 00:00:00 2001 From: Tomasz Bursztyka Date: Mon, 27 Nov 2023 19:24:17 +0100 Subject: [PATCH 1138/3723] arch/x86: Fixing dcache enable/disable code It did not build in x86_64 due to the fact that cr0 is a 64bits register in such architecture, instead of being a 32bits one originaly so the place holder has to follow that size. Such place holder must be initialized to 0 to make sure no upper 32 bits ends up set which would conclude in a general protection error. Operand size specifier (l, q ...) is useless as well in this context. Clearing up the masks by using proper macros. Signed-off-by: Tomasz Bursztyka --- arch/x86/core/cache.c | 30 +++++++++++++++++++----------- 1 file changed, 19 insertions(+), 11 deletions(-) diff --git a/arch/x86/core/cache.c b/arch/x86/core/cache.c index cd0bbb8e16d..e80cb6d1dbf 100644 --- a/arch/x86/core/cache.c +++ b/arch/x86/core/cache.c @@ -18,6 +18,11 @@ #include #include +/* Not Write-through bit */ +#define X86_REG_CR0_NW BIT(29) +/* Cache Disable bit */ +#define X86_REG_CR0_CD BIT(30) + static inline void z_x86_wbinvd(void) { __asm__ volatile("wbinvd;\n\t" : : : "memory"); @@ -25,25 +30,28 @@ static inline void z_x86_wbinvd(void) void arch_dcache_enable(void) { - uint32_t cr0; + unsigned long cr0 = 0; /* Enable write-back caching by clearing the NW and CD bits */ - __asm__ volatile("movl %%cr0, %0;\n\t" - "andl $0x9fffffff, %0;\n\t" - "movl %0, %%cr0;\n\t" - : "=r" (cr0)); + __asm__ volatile("mov %%cr0, %0;\n\t" + "and %1, %0;\n\t" + "mov %0, %%cr0;\n\t" + : "=r" (cr0) + : "i" (~(X86_REG_CR0_NW | X86_REG_CR0_CD))); } void arch_dcache_disable(void) { - uint32_t cr0; + unsigned long cr0 = 0; /* Enter the no-fill mode by setting NW=0 and CD=1 */ - __asm__ volatile("movl %%cr0, %0;\n\t" - "andl $0xdfffffff, %0;\n\t" - "orl $0x40000000, %0;\n\t" - "movl %0, %%cr0;\n\t" - : "=r" (cr0)); + __asm__ volatile("mov %%cr0, %0;\n\t" + "and %1, %0;\n\t" + "or %2, %0;\n\t" + "mov %0, %%cr0;\n\t" + : "=r" (cr0) + : "i" (~(X86_REG_CR0_NW)), + "i" (X86_REG_CR0_CD)); /* Flush all caches */ z_x86_wbinvd(); From daf42fe77aa6f4e1ca9d11397ced131a5ab7f60e Mon Sep 17 00:00:00 2001 From: Tomasz Bursztyka Date: Mon, 27 Nov 2023 20:08:58 +0100 Subject: [PATCH 1139/3723] arch/x86: CPUs expose an unimplemented feature Instruction cache related functions (see include/zephyr/arch/cache.h) are not implemented in x86, thus let's not set CONFIG_CPU_HAS_ICACHE which may end up in build failure if one sets CONFIG_ICACHE. Signed-off-by: Tomasz Bursztyka --- arch/x86/Kconfig | 3 --- 1 file changed, 3 deletions(-) diff --git a/arch/x86/Kconfig b/arch/x86/Kconfig index 7f852742fb8..13030d26a1d 100644 --- a/arch/x86/Kconfig +++ b/arch/x86/Kconfig @@ -23,7 +23,6 @@ config CPU_ATOM select X86_CPU_HAS_SSE2 select X86_CPU_HAS_SSE3 select CPU_HAS_DCACHE - select CPU_HAS_ICACHE help This option signifies the use of a CPU from the Atom family. @@ -41,7 +40,6 @@ config CPU_APOLLO_LAKE select X86_CPU_HAS_SSE41 select X86_CPU_HAS_SSE42 select CPU_HAS_DCACHE - select CPU_HAS_ICACHE help This option signifies the use of a CPU from the Apollo Lake family. @@ -56,7 +54,6 @@ config CPU_LAKEMONT select X86_CPU_HAS_SSE3 select X86_CPU_HAS_SSSE3 select CPU_HAS_DCACHE - select CPU_HAS_ICACHE help This option signifies the use of a CPU from the Lakemont family. From 9be3b8490b13dcfffb6e0b965a14e57548839426 Mon Sep 17 00:00:00 2001 From: Tomasz Bursztyka Date: Tue, 28 Nov 2023 09:44:34 +0100 Subject: [PATCH 1140/3723] boards/x86: Adding clflush CPU capability to qemu_x86 Without this, cache manipulation cannot work in x86. clflush was introduced with SSE2 extension, but may be implemented without this extension and it seems that qemu made this choice a adding sse2 CPU capability does not include clflush. It enabled by default in 64 bits, so let's take care of this capability only for the 32bits version of the board. Signed-off-by: Tomasz Bursztyka --- boards/x86/qemu_x86/board.cmake | 3 +++ 1 file changed, 3 insertions(+) diff --git a/boards/x86/qemu_x86/board.cmake b/boards/x86/qemu_x86/board.cmake index 934b078154e..97a56a92770 100644 --- a/boards/x86/qemu_x86/board.cmake +++ b/boards/x86/qemu_x86/board.cmake @@ -56,6 +56,9 @@ endif() if(CONFIG_X86_SSE4A) string(JOIN "," QEMU_CPU_FLAGS "${QEMU_CPU_FLAGS}" "sse4a") endif() +if(NOT CONFIG_X86_64 AND CONFIG_CACHE_MANAGEMENT) + string(JOIN "," QEMU_CPU_FLAGS "${QEMU_CPU_FLAGS}" "clflush") +endif() set(QEMU_FLAGS_${ARCH} -m ${QEMU_MEMORY_SIZE_MB} From a2be813d99a4c2a9ba51d14810d2ee9bb635db9e Mon Sep 17 00:00:00 2001 From: Tomasz Bursztyka Date: Mon, 27 Nov 2023 20:17:28 +0100 Subject: [PATCH 1141/3723] tests/kernel: Add qemu_x86/x86_64 to cache test and enable cache How cache test could be ran without CONFIG_CACHE_MANAGEMENT? Adding qemu_x86/x86_64 as cache related API in x86 has proven to be very brittle against changes recently: no test was at least verifying it builds properly, not to mention running it. Signed-off-by: Tomasz Bursztyka --- tests/kernel/cache/prj.conf | 1 + tests/kernel/cache/testcase.yaml | 4 ++++ 2 files changed, 5 insertions(+) diff --git a/tests/kernel/cache/prj.conf b/tests/kernel/cache/prj.conf index e39776e7067..d91a1875823 100644 --- a/tests/kernel/cache/prj.conf +++ b/tests/kernel/cache/prj.conf @@ -1,2 +1,3 @@ CONFIG_ZTEST=y CONFIG_TEST_USERSPACE=y +CONFIG_CACHE_MANAGEMENT=y diff --git a/tests/kernel/cache/testcase.yaml b/tests/kernel/cache/testcase.yaml index 31a35f92e1a..84b44c6259b 100644 --- a/tests/kernel/cache/testcase.yaml +++ b/tests/kernel/cache/testcase.yaml @@ -8,6 +8,8 @@ tests: - qemu_xtensa - qemu_cortex_a53 - nsim_em + - qemu_x86 + - qemu_x86_64 kernel.cache.api.minimallibc: tags: - kernel @@ -18,5 +20,7 @@ tests: - qemu_xtensa - qemu_cortex_a53 - nsim_em + - qemu_x86 + - qemu_x86_64 extra_configs: - CONFIG_MINIMAL_LIBC=y From dc49dad7e040ed6fbf91c5f88b9eaab4e6a8d4df Mon Sep 17 00:00:00 2001 From: Tomasz Bursztyka Date: Fri, 1 Dec 2023 10:07:53 +0100 Subject: [PATCH 1142/3723] tests/kernel: Exlude bogus platforms on cache test Until these get fixed. Signed-off-by: Tomasz Bursztyka --- tests/kernel/cache/testcase.yaml | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/tests/kernel/cache/testcase.yaml b/tests/kernel/cache/testcase.yaml index 84b44c6259b..37e277c4be2 100644 --- a/tests/kernel/cache/testcase.yaml +++ b/tests/kernel/cache/testcase.yaml @@ -4,6 +4,10 @@ tests: - kernel - cache filter: CONFIG_CACHE_MANAGEMENT + platform_exclude: + - adp_xc7k_ae350 + - bcm958402m2_m7 + - bcm958401m2 integration_platforms: - qemu_xtensa - qemu_cortex_a53 @@ -16,6 +20,10 @@ tests: - cache - libc filter: CONFIG_CACHE_MANAGEMENT and CONFIG_MINIMAL_LIBC_SUPPORTED + platform_exclude: + - adp_xc7k_ae350 + - bcm958402m2_m7 + - bcm958401m2 integration_platforms: - qemu_xtensa - qemu_cortex_a53 From fa561ccd590cd12c32738c536c40174f9d5b05fb Mon Sep 17 00:00:00 2001 From: Daniel Leung Date: Tue, 3 Oct 2023 11:43:17 -0700 Subject: [PATCH 1143/3723] kernel: mmu: no need to expose z_free_page_count z_free_page_count is only used in one file, so there is no need to expose it, even to other part of kernel. Signed-off-by: Daniel Leung --- kernel/include/mmu.h | 3 --- kernel/mmu.c | 6 ++++-- 2 files changed, 4 insertions(+), 5 deletions(-) diff --git a/kernel/include/mmu.h b/kernel/include/mmu.h index cd290100e40..4920ac39c98 100644 --- a/kernel/include/mmu.h +++ b/kernel/include/mmu.h @@ -215,9 +215,6 @@ static inline void z_mem_assert_virtual_region(uint8_t *addr, size_t size) */ void z_page_frames_dump(void); -/* Number of free page frames. This information may go stale immediately */ -extern size_t z_free_page_count; - /* Convenience macro for iterating over all page frames */ #define Z_PAGE_FRAME_FOREACH(_phys, _pageframe) \ for (_phys = Z_PHYS_RAM_START, _pageframe = z_page_frames; \ diff --git a/kernel/mmu.c b/kernel/mmu.c index eb1d95ec684..cef9b5c18d2 100644 --- a/kernel/mmu.c +++ b/kernel/mmu.c @@ -381,8 +381,10 @@ static void *virt_region_alloc(size_t size, size_t align) */ static sys_slist_t free_page_frame_list; -/* Number of unused and available free page frames */ -size_t z_free_page_count; +/* Number of unused and available free page frames. + * This information may go stale immediately. + */ +static size_t z_free_page_count; #define PF_ASSERT(pf, expr, fmt, ...) \ __ASSERT(expr, "page frame 0x%lx: " fmt, z_page_frame_to_phys(pf), \ From c6773403b1f306eaacfe5244d0229d984c9a7505 Mon Sep 17 00:00:00 2001 From: Daniel Leung Date: Mon, 11 Dec 2023 13:49:43 -0800 Subject: [PATCH 1144/3723] kernel: mm: fix some doxygen issues Fix misplaced in,out in @param. If any parameters are output, mark the others as input for clarity. Signed-off-by: Daniel Leung --- include/zephyr/kernel/internal/mm.h | 8 ++++---- include/zephyr/kernel/mm.h | 10 +++++----- 2 files changed, 9 insertions(+), 9 deletions(-) diff --git a/include/zephyr/kernel/internal/mm.h b/include/zephyr/kernel/internal/mm.h index 2ebf06463f4..b6bcd1aa3b1 100644 --- a/include/zephyr/kernel/internal/mm.h +++ b/include/zephyr/kernel/internal/mm.h @@ -168,10 +168,10 @@ extern "C" { * This API is part of infrastructure still under development and may * change. * - * @param virt [out] Output virtual address storage location - * @param phys Physical address base of the memory region - * @param size Size of the memory region - * @param flags Caching mode and access flags, see K_MAP_* macros + * @param[out] virt Output virtual address storage location + * @param[in] phys Physical address base of the memory region + * @param[in] size Size of the memory region + * @param[in] flags Caching mode and access flags, see K_MAP_* macros */ void z_phys_map(uint8_t **virt_ptr, uintptr_t phys, size_t size, uint32_t flags); diff --git a/include/zephyr/kernel/mm.h b/include/zephyr/kernel/mm.h index 0f6c76e7cdc..715bc94021f 100644 --- a/include/zephyr/kernel/mm.h +++ b/include/zephyr/kernel/mm.h @@ -191,11 +191,11 @@ void k_mem_unmap(void *addr, size_t size); * The returned region will have both its base address and size aligned * to the provided alignment value. * - * @param aligned_addr [out] Aligned address - * @param aligned_size [out] Aligned region size - * @param addr Region base address - * @param size Region size - * @param align What to align the address and size to + * @param[out] aligned_addr Aligned address + * @param[out] aligned_size Aligned region size + * @param[in] addr Region base address + * @param[in] size Region size + * @param[in] align What to align the address and size to * @retval offset between aligned_addr and addr */ size_t k_mem_region_align(uintptr_t *aligned_addr, size_t *aligned_size, From acf0fe82d4e5bb3866ea3063e1da0be3d603e9cc Mon Sep 17 00:00:00 2001 From: Francois Ramu Date: Mon, 11 Dec 2023 17:52:15 +0100 Subject: [PATCH 1145/3723] boards: arm: Add RTC clock source for 96b_aerocore2 The `96b_aerocore2` board doesn't have its RTC node enabled, and is failing the following test: `tests/benchmarks/footprints/benchmark.kernel.footprints.pm` Enabled RTC node and lsi clock source for that platform. Signed-off-by: Francois Ramu --- boards/arm/96b_aerocore2/96b_aerocore2.dts | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/boards/arm/96b_aerocore2/96b_aerocore2.dts b/boards/arm/96b_aerocore2/96b_aerocore2.dts index 4a4e8672f7f..dd5f8d8a895 100644 --- a/boards/arm/96b_aerocore2/96b_aerocore2.dts +++ b/boards/arm/96b_aerocore2/96b_aerocore2.dts @@ -42,6 +42,10 @@ }; +&clk_lsi { + status = "okay"; +}; + &clk_hse { clock-frequency = ; status = "okay"; @@ -180,6 +184,12 @@ zephyr_udc0: &usbotg_fs { status = "okay"; }; +&rtc { + clocks = <&rcc STM32_CLOCK_BUS_APB1 0x10000000>, + <&rcc STM32_SRC_LSI RTC_SEL(2)>; + status = "okay"; +}; + &rng { status = "okay"; }; From 82613c2e3010ef33a83f5b1ddbb4727100061631 Mon Sep 17 00:00:00 2001 From: Francois Ramu Date: Mon, 11 Dec 2023 17:57:53 +0100 Subject: [PATCH 1146/3723] boards: arm: Add RTC clock source for az3166_iotdevkit The `az3166_iotdevkit` board doesn't have its RTC node enabled, and is failing the following test: `tests/benchmarks/footprints/benchmark.kernel.footprints.pm` Enabled RTC node for that platform. Signed-off-by: Francois Ramu --- boards/arm/az3166_iotdevkit/az3166_iotdevkit.dts | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/boards/arm/az3166_iotdevkit/az3166_iotdevkit.dts b/boards/arm/az3166_iotdevkit/az3166_iotdevkit.dts index 13b641719ee..4c77535ce21 100644 --- a/boards/arm/az3166_iotdevkit/az3166_iotdevkit.dts +++ b/boards/arm/az3166_iotdevkit/az3166_iotdevkit.dts @@ -205,3 +205,9 @@ pinctrl-names = "default"; }; }; + +&rtc { + clocks = <&rcc STM32_CLOCK_BUS_APB1 0x10000000>, + <&rcc STM32_SRC_LSI RTC_SEL(2)>; + status = "okay"; +}; From e29452da6411c5e973c581db2e7bedb9ebfdbdff Mon Sep 17 00:00:00 2001 From: Anas Nashif Date: Mon, 11 Dec 2023 19:29:04 -0500 Subject: [PATCH 1147/3723] arch: arm: remove aarch32 from include header guards We follow the path of the header to define the guard, aarch32 was removed some time ago and the guards still had AARCH32 in them, just remove it and keep the guard consistent and short. Signed-off-by: Anas Nashif --- arch/arm/core/mpu/arm_core_mpu_dev.h | 6 +++--- include/zephyr/arch/arm/arch.h | 6 +++--- include/zephyr/arch/arm/arch_inlines.h | 6 +++--- include/zephyr/arch/arm/asm_inline.h | 6 +++--- include/zephyr/arch/arm/asm_inline_gcc.h | 6 +++--- include/zephyr/arch/arm/cortex_a_r/cpu.h | 6 +++--- include/zephyr/arch/arm/cortex_a_r/lib_helpers.h | 6 +++--- include/zephyr/arch/arm/cortex_a_r/sys_io.h | 6 +++--- include/zephyr/arch/arm/cortex_a_r/timer.h | 6 +++--- include/zephyr/arch/arm/cortex_m/fpu.h | 6 +++--- include/zephyr/arch/arm/cortex_m/memory_map.h | 6 +++--- include/zephyr/arch/arm/cortex_m/nvic.h | 6 +++--- include/zephyr/arch/arm/error.h | 6 +++--- include/zephyr/arch/arm/irq.h | 6 +++--- include/zephyr/arch/arm/misc.h | 6 +++--- include/zephyr/arch/arm/mpu/arm_mpu.h | 6 +++--- include/zephyr/arch/arm/mpu/nxp_mpu.h | 6 +++--- include/zephyr/arch/arm/nmi.h | 6 +++--- include/zephyr/arch/arm/syscall.h | 6 +++--- include/zephyr/arch/arm/thread.h | 6 +++--- modules/cmsis/cmsis_core.h | 2 +- 21 files changed, 61 insertions(+), 61 deletions(-) diff --git a/arch/arm/core/mpu/arm_core_mpu_dev.h b/arch/arm/core/mpu/arm_core_mpu_dev.h index ec0126e6e9b..fd56131d7dc 100644 --- a/arch/arm/core/mpu/arm_core_mpu_dev.h +++ b/arch/arm/core/mpu/arm_core_mpu_dev.h @@ -3,8 +3,8 @@ * * SPDX-License-Identifier: Apache-2.0 */ -#ifndef ZEPHYR_INCLUDE_ARCH_ARM_AARCH32_CORTEX_M_MPU_ARM_CORE_MPU_DEV_H_ -#define ZEPHYR_INCLUDE_ARCH_ARM_AARCH32_CORTEX_M_MPU_ARM_CORE_MPU_DEV_H_ +#ifndef ZEPHYR_INCLUDE_ARCH_ARM_CORTEX_M_MPU_ARM_CORE_MPU_DEV_H_ +#define ZEPHYR_INCLUDE_ARCH_ARM_CORTEX_M_MPU_ARM_CORE_MPU_DEV_H_ #include #include @@ -269,4 +269,4 @@ int arm_core_mpu_buffer_validate(void *addr, size_t size, int write); } #endif -#endif /* ZEPHYR_INCLUDE_ARCH_ARM_AARCH32_CORTEX_M_MPU_ARM_CORE_MPU_DEV_H_ */ +#endif /* ZEPHYR_INCLUDE_ARCH_ARM_CORTEX_M_MPU_ARM_CORE_MPU_DEV_H_ */ diff --git a/include/zephyr/arch/arm/arch.h b/include/zephyr/arch/arm/arch.h index 01284a675c5..d3a64e9ef8b 100644 --- a/include/zephyr/arch/arm/arch.h +++ b/include/zephyr/arch/arm/arch.h @@ -13,8 +13,8 @@ * (include/arm/cpu.h) */ -#ifndef ZEPHYR_INCLUDE_ARCH_ARM_AARCH32_ARCH_H_ -#define ZEPHYR_INCLUDE_ARCH_ARM_AARCH32_ARCH_H_ +#ifndef ZEPHYR_INCLUDE_ARCH_ARM_ARCH_H_ +#define ZEPHYR_INCLUDE_ARCH_ARM_ARCH_H_ /* Add include for DTS generated information */ #include @@ -279,4 +279,4 @@ enum k_fatal_error_reason_arch { } #endif -#endif /* ZEPHYR_INCLUDE_ARCH_ARM_AARCH32_ARCH_H_ */ +#endif /* ZEPHYR_INCLUDE_ARCH_ARM_ARCH_H_ */ diff --git a/include/zephyr/arch/arm/arch_inlines.h b/include/zephyr/arch/arm/arch_inlines.h index acc3d2e9588..f5149799adf 100644 --- a/include/zephyr/arch/arm/arch_inlines.h +++ b/include/zephyr/arch/arm/arch_inlines.h @@ -4,8 +4,8 @@ * SPDX-License-Identifier: Apache-2.0 */ -#ifndef ZEPHYR_INCLUDE_ARCH_ARM_AARCH32_ARCH_INLINES_H -#define ZEPHYR_INCLUDE_ARCH_ARM_AARCH32_ARCH_INLINES_H +#ifndef ZEPHYR_INCLUDE_ARCH_ARM_ARCH_INLINES_H +#define ZEPHYR_INCLUDE_ARCH_ARM_ARCH_INLINES_H #include #if defined(CONFIG_CPU_AARCH32_CORTEX_R) || defined(CONFIG_CPU_AARCH32_CORTEX_A) @@ -41,4 +41,4 @@ static ALWAYS_INLINE unsigned int arch_num_cpus(void) return CONFIG_MP_MAX_NUM_CPUS; } -#endif /* ZEPHYR_INCLUDE_ARCH_ARM_AARCH32_ARCH_INLINES_H */ +#endif /* ZEPHYR_INCLUDE_ARCH_ARM_ARCH_INLINES_H */ diff --git a/include/zephyr/arch/arm/asm_inline.h b/include/zephyr/arch/arm/asm_inline.h index c083adcd47a..fe36fb2d0e1 100644 --- a/include/zephyr/arch/arm/asm_inline.h +++ b/include/zephyr/arch/arm/asm_inline.h @@ -6,8 +6,8 @@ * SPDX-License-Identifier: Apache-2.0 */ -#ifndef ZEPHYR_INCLUDE_ARCH_ARM_AARCH32_ASM_INLINE_H_ -#define ZEPHYR_INCLUDE_ARCH_ARM_AARCH32_ASM_INLINE_H_ +#ifndef ZEPHYR_INCLUDE_ARCH_ARM_ASM_INLINE_H_ +#define ZEPHYR_INCLUDE_ARCH_ARM_ASM_INLINE_H_ /* * The file must not be included directly @@ -20,4 +20,4 @@ #include #endif -#endif /* ZEPHYR_INCLUDE_ARCH_ARM_AARCH32_ASM_INLINE_H_ */ +#endif /* ZEPHYR_INCLUDE_ARCH_ARM_ASM_INLINE_H_ */ diff --git a/include/zephyr/arch/arm/asm_inline_gcc.h b/include/zephyr/arch/arm/asm_inline_gcc.h index 604dd4f088f..77729149e36 100644 --- a/include/zephyr/arch/arm/asm_inline_gcc.h +++ b/include/zephyr/arch/arm/asm_inline_gcc.h @@ -8,8 +8,8 @@ /* Either public functions or macros or invoked by public functions */ -#ifndef ZEPHYR_INCLUDE_ARCH_ARM_AARCH32_ASM_INLINE_GCC_H_ -#define ZEPHYR_INCLUDE_ARCH_ARM_AARCH32_ASM_INLINE_GCC_H_ +#ifndef ZEPHYR_INCLUDE_ARCH_ARM_ASM_INLINE_GCC_H_ +#define ZEPHYR_INCLUDE_ARCH_ARM_ASM_INLINE_GCC_H_ /* * The file must not be included directly @@ -126,4 +126,4 @@ static ALWAYS_INLINE bool arch_irq_unlocked(unsigned int key) #endif /* _ASMLANGUAGE */ -#endif /* ZEPHYR_INCLUDE_ARCH_ARM_AARCH32_ASM_INLINE_GCC_H_ */ +#endif /* ZEPHYR_INCLUDE_ARCH_ARM_ASM_INLINE_GCC_H_ */ diff --git a/include/zephyr/arch/arm/cortex_a_r/cpu.h b/include/zephyr/arch/arm/cortex_a_r/cpu.h index 806d28247ac..61e520ffc23 100644 --- a/include/zephyr/arch/arm/cortex_a_r/cpu.h +++ b/include/zephyr/arch/arm/cortex_a_r/cpu.h @@ -4,8 +4,8 @@ * SPDX-License-Identifier: Apache-2.0 */ -#ifndef ZEPHYR_INCLUDE_ARCH_ARM_AARCH32_CORTEX_A_R_CPU_H_ -#define ZEPHYR_INCLUDE_ARCH_ARM_AARCH32_CORTEX_A_R_CPU_H_ +#ifndef ZEPHYR_INCLUDE_ARCH_ARM_CORTEX_A_R_CPU_H_ +#define ZEPHYR_INCLUDE_ARCH_ARM_CORTEX_A_R_CPU_H_ #if defined(CONFIG_ARM_MPU) #include @@ -116,4 +116,4 @@ (((_aff1) & SGIR_AFF_MASK) << SGIR_AFF1_SHIFT) | \ ((_tgt) & SGIR_TGT_MASK)) -#endif /* ZEPHYR_INCLUDE_ARCH_ARM_AARCH32_CORTEX_A_R_CPU_H_ */ +#endif /* ZEPHYR_INCLUDE_ARCH_ARM_CORTEX_A_R_CPU_H_ */ diff --git a/include/zephyr/arch/arm/cortex_a_r/lib_helpers.h b/include/zephyr/arch/arm/cortex_a_r/lib_helpers.h index 7b89ddf515c..983654ce138 100644 --- a/include/zephyr/arch/arm/cortex_a_r/lib_helpers.h +++ b/include/zephyr/arch/arm/cortex_a_r/lib_helpers.h @@ -7,8 +7,8 @@ * */ -#ifndef ZEPHYR_INCLUDE_ARCH_ARM_AARCH32_CORTEX_A_R_LIB_HELPERS_H_ -#define ZEPHYR_INCLUDE_ARCH_ARM_AARCH32_CORTEX_A_R_LIB_HELPERS_H_ +#ifndef ZEPHYR_INCLUDE_ARCH_ARM_CORTEX_A_R_LIB_HELPERS_H_ +#define ZEPHYR_INCLUDE_ARCH_ARM_CORTEX_A_R_LIB_HELPERS_H_ #ifndef _ASMLANGUAGE @@ -103,4 +103,4 @@ MAKE_REG_HELPER(ICC_IGRPEN1_EL1, 0, 12, 12, 7); #define wfe() __asm__ volatile("wfe" : : : "memory") #endif /* !_ASMLANGUAGE */ -#endif /* ZEPHYR_INCLUDE_ARCH_ARM_AARCH32_CORTEX_A_R_LIB_HELPERS_H_ */ +#endif /* ZEPHYR_INCLUDE_ARCH_ARM_CORTEX_A_R_LIB_HELPERS_H_ */ diff --git a/include/zephyr/arch/arm/cortex_a_r/sys_io.h b/include/zephyr/arch/arm/cortex_a_r/sys_io.h index c4598302aae..888e328e6b2 100644 --- a/include/zephyr/arch/arm/cortex_a_r/sys_io.h +++ b/include/zephyr/arch/arm/cortex_a_r/sys_io.h @@ -9,8 +9,8 @@ * gcc builtins) */ -#ifndef ZEPHYR_INCLUDE_ARCH_ARM_AARCH32_CORTEX_A_R_SYS_IO_H_ -#define ZEPHYR_INCLUDE_ARCH_ARM_AARCH32_CORTEX_A_R_SYS_IO_H_ +#ifndef ZEPHYR_INCLUDE_ARCH_ARM_CORTEX_A_R_SYS_IO_H_ +#define ZEPHYR_INCLUDE_ARCH_ARM_CORTEX_A_R_SYS_IO_H_ #ifndef _ASMLANGUAGE @@ -88,4 +88,4 @@ static ALWAYS_INLINE uint64_t sys_read64(mem_addr_t addr) #endif /* _ASMLANGUAGE */ -#endif /* ZEPHYR_INCLUDE_ARCH_ARM_AARCH32_CORTEX_A_R_SYS_IO_H_ */ +#endif /* ZEPHYR_INCLUDE_ARCH_ARM_CORTEX_A_R_SYS_IO_H_ */ diff --git a/include/zephyr/arch/arm/cortex_a_r/timer.h b/include/zephyr/arch/arm/cortex_a_r/timer.h index d513ecdffc8..6cd10c5d8e0 100644 --- a/include/zephyr/arch/arm/cortex_a_r/timer.h +++ b/include/zephyr/arch/arm/cortex_a_r/timer.h @@ -4,8 +4,8 @@ * SPDX-License-Identifier: Apache-2.0 */ -#ifndef ZEPHYR_INCLUDE_ARCH_ARM_AARCH32_CORTEX_A_R_TIMER_H_ -#define ZEPHYR_INCLUDE_ARCH_ARM_AARCH32_CORTEX_A_R_TIMER_H_ +#ifndef ZEPHYR_INCLUDE_ARCH_ARM_CORTEX_A_R_TIMER_H_ +#define ZEPHYR_INCLUDE_ARCH_ARM_CORTEX_A_R_TIMER_H_ #ifdef CONFIG_ARM_ARCH_TIMER @@ -149,4 +149,4 @@ static ALWAYS_INLINE uint64_t arm_arch_timer_count(void) #endif /* CONFIG_ARM_ARCH_TIMER */ -#endif /* ZEPHYR_INCLUDE_ARCH_ARM_AARCH32_CORTEX_A_R_TIMER_H_ */ +#endif /* ZEPHYR_INCLUDE_ARCH_ARM_CORTEX_A_R_TIMER_H_ */ diff --git a/include/zephyr/arch/arm/cortex_m/fpu.h b/include/zephyr/arch/arm/cortex_m/fpu.h index 17f75cec50e..cf01fddf4f9 100644 --- a/include/zephyr/arch/arm/cortex_m/fpu.h +++ b/include/zephyr/arch/arm/cortex_m/fpu.h @@ -4,8 +4,8 @@ * SPDX-License-Identifier: Apache-2.0 */ -#ifndef ZEPHYR_INCLUDE_ARCH_ARM_AARCH32_CORTEX_M_FPU_H_ -#define ZEPHYR_INCLUDE_ARCH_ARM_AARCH32_CORTEX_M_FPU_H_ +#ifndef ZEPHYR_INCLUDE_ARCH_ARM_CORTEX_M_FPU_H_ +#define ZEPHYR_INCLUDE_ARCH_ARM_CORTEX_M_FPU_H_ struct fpu_ctx_full { uint32_t caller_saved[16]; @@ -17,4 +17,4 @@ struct fpu_ctx_full { void z_arm_save_fp_context(struct fpu_ctx_full *buffer); void z_arm_restore_fp_context(const struct fpu_ctx_full *buffer); -#endif /* ZEPHYR_INCLUDE_ARCH_ARM_AARCH32_CORTEX_M_FPU_H_ */ +#endif /* ZEPHYR_INCLUDE_ARCH_ARM_CORTEX_M_FPU_H_ */ diff --git a/include/zephyr/arch/arm/cortex_m/memory_map.h b/include/zephyr/arch/arm/cortex_m/memory_map.h index 82310273019..b73a77f10ea 100644 --- a/include/zephyr/arch/arm/cortex_m/memory_map.h +++ b/include/zephyr/arch/arm/cortex_m/memory_map.h @@ -12,8 +12,8 @@ * processors. */ -#ifndef ZEPHYR_INCLUDE_ARCH_ARM_AARCH32_CORTEX_M_MEMORY_MAP_H_ -#define ZEPHYR_INCLUDE_ARCH_ARM_AARCH32_CORTEX_M_MEMORY_MAP_H_ +#ifndef ZEPHYR_INCLUDE_ARCH_ARM_CORTEX_M_MEMORY_MAP_H_ +#define ZEPHYR_INCLUDE_ARCH_ARM_CORTEX_M_MEMORY_MAP_H_ #include @@ -110,4 +110,4 @@ #define _VENDOR_BASE_ADDR 0xE0100000 #define _VENDOR_END_ADDR 0xFFFFFFFF -#endif /* ZEPHYR_INCLUDE_ARCH_ARM_AARCH32_CORTEX_M_MEMORY_MAP_H_ */ +#endif /* ZEPHYR_INCLUDE_ARCH_ARM_CORTEX_M_MEMORY_MAP_H_ */ diff --git a/include/zephyr/arch/arm/cortex_m/nvic.h b/include/zephyr/arch/arm/cortex_m/nvic.h index caececd3c0d..947bfb6eaf5 100644 --- a/include/zephyr/arch/arm/cortex_m/nvic.h +++ b/include/zephyr/arch/arm/cortex_m/nvic.h @@ -4,8 +4,8 @@ * SPDX-License-Identifier: Apache-2.0 */ -#ifndef ZEPHYR_INCLUDE_ARCH_ARM_AARCH32_CORTEX_M_NVIC_H_ -#define ZEPHYR_INCLUDE_ARCH_ARM_AARCH32_CORTEX_M_NVIC_H_ +#ifndef ZEPHYR_INCLUDE_ARCH_ARM_CORTEX_M_NVIC_H_ +#define ZEPHYR_INCLUDE_ARCH_ARM_CORTEX_M_NVIC_H_ #include @@ -25,4 +25,4 @@ #define NUM_IRQ_PRIO_BITS DT_PROP(NVIC_NODEID, arm_num_irq_priority_bits) -#endif /* ZEPHYR_INCLUDE_ARCH_ARM_AARCH32_CORTEX_M_NVIC_H_ */ +#endif /* ZEPHYR_INCLUDE_ARCH_ARM_CORTEX_M_NVIC_H_ */ diff --git a/include/zephyr/arch/arm/error.h b/include/zephyr/arch/arm/error.h index afd3495fcb6..a30c674c4ff 100644 --- a/include/zephyr/arch/arm/error.h +++ b/include/zephyr/arch/arm/error.h @@ -12,8 +12,8 @@ * arm/arch.h. */ -#ifndef ZEPHYR_INCLUDE_ARCH_ARM_AARCH32_ERROR_H_ -#define ZEPHYR_INCLUDE_ARCH_ARM_AARCH32_ERROR_H_ +#ifndef ZEPHYR_INCLUDE_ARCH_ARM_ERROR_H_ +#define ZEPHYR_INCLUDE_ARCH_ARM_ERROR_H_ #include #include @@ -83,4 +83,4 @@ do { \ } #endif -#endif /* ZEPHYR_INCLUDE_ARCH_ARM_AARCH32_ERROR_H_ */ +#endif /* ZEPHYR_INCLUDE_ARCH_ARM_ERROR_H_ */ diff --git a/include/zephyr/arch/arm/irq.h b/include/zephyr/arch/arm/irq.h index 357c91a83ae..42a2a364fb3 100644 --- a/include/zephyr/arch/arm/irq.h +++ b/include/zephyr/arch/arm/irq.h @@ -13,8 +13,8 @@ * arm/arch.h. */ -#ifndef ZEPHYR_INCLUDE_ARCH_ARM_AARCH32_IRQ_H_ -#define ZEPHYR_INCLUDE_ARCH_ARM_AARCH32_IRQ_H_ +#ifndef ZEPHYR_INCLUDE_ARCH_ARM_IRQ_H_ +#define ZEPHYR_INCLUDE_ARCH_ARM_IRQ_H_ #include #include @@ -254,4 +254,4 @@ typedef enum { } #endif -#endif /* ZEPHYR_INCLUDE_ARCH_ARM_AARCH32_IRQ_H_ */ +#endif /* ZEPHYR_INCLUDE_ARCH_ARM_IRQ_H_ */ diff --git a/include/zephyr/arch/arm/misc.h b/include/zephyr/arch/arm/misc.h index ab67a35e94c..99f99b59b2b 100644 --- a/include/zephyr/arch/arm/misc.h +++ b/include/zephyr/arch/arm/misc.h @@ -11,8 +11,8 @@ * ARM AArch32-specific kernel miscellaneous interface. Included by arm/arch.h. */ -#ifndef ZEPHYR_INCLUDE_ARCH_ARM_AARCH32_MISC_H_ -#define ZEPHYR_INCLUDE_ARCH_ARM_AARCH32_MISC_H_ +#ifndef ZEPHYR_INCLUDE_ARCH_ARM_MISC_H_ +#define ZEPHYR_INCLUDE_ARCH_ARM_MISC_H_ #ifdef __cplusplus extern "C" { @@ -66,4 +66,4 @@ void z_arm_on_enter_cpu_idle_prepare(void); } #endif -#endif /* ZEPHYR_INCLUDE_ARCH_ARM_AARCH32_MISC_H_ */ +#endif /* ZEPHYR_INCLUDE_ARCH_ARM_MISC_H_ */ diff --git a/include/zephyr/arch/arm/mpu/arm_mpu.h b/include/zephyr/arch/arm/mpu/arm_mpu.h index 857465a4824..9a8ffc7a724 100644 --- a/include/zephyr/arch/arm/mpu/arm_mpu.h +++ b/include/zephyr/arch/arm/mpu/arm_mpu.h @@ -3,8 +3,8 @@ * * SPDX-License-Identifier: Apache-2.0 */ -#ifndef ZEPHYR_INCLUDE_ARCH_ARM_AARCH32_MPU_ARM_MPU_H_ -#define ZEPHYR_INCLUDE_ARCH_ARM_AARCH32_MPU_ARM_MPU_H_ +#ifndef ZEPHYR_INCLUDE_ARCH_ARM_MPU_ARM_MPU_H_ +#define ZEPHYR_INCLUDE_ARCH_ARM_MPU_ARM_MPU_H_ #if defined(CONFIG_CPU_CORTEX_M0PLUS) || \ defined(CONFIG_CPU_CORTEX_M3) || \ @@ -74,4 +74,4 @@ extern const struct arm_mpu_config mpu_config; #endif /* _ASMLANGUAGE */ -#endif /* ZEPHYR_INCLUDE_ARCH_ARM_AARCH32_MPU_ARM_MPU_H_ */ +#endif /* ZEPHYR_INCLUDE_ARCH_ARM_MPU_ARM_MPU_H_ */ diff --git a/include/zephyr/arch/arm/mpu/nxp_mpu.h b/include/zephyr/arch/arm/mpu/nxp_mpu.h index d1f5882bfed..b9556565802 100644 --- a/include/zephyr/arch/arm/mpu/nxp_mpu.h +++ b/include/zephyr/arch/arm/mpu/nxp_mpu.h @@ -3,8 +3,8 @@ * * SPDX-License-Identifier: Apache-2.0 */ -#ifndef ZEPHYR_INCLUDE_ARCH_ARM_AARCH32_MPU_NXP_MPU_H_ -#define ZEPHYR_INCLUDE_ARCH_ARM_AARCH32_MPU_NXP_MPU_H_ +#ifndef ZEPHYR_INCLUDE_ARCH_ARM_MPU_NXP_MPU_H_ +#define ZEPHYR_INCLUDE_ARCH_ARM_MPU_NXP_MPU_H_ #ifndef _ASMLANGUAGE @@ -266,4 +266,4 @@ extern const struct nxp_mpu_config mpu_config; "start address of the partition must align with minimum MPU \ region size.") -#endif /* ZEPHYR_INCLUDE_ARCH_ARM_AARCH32_MPU_NXP_MPU_H_ */ +#endif /* ZEPHYR_INCLUDE_ARCH_ARM_MPU_NXP_MPU_H_ */ diff --git a/include/zephyr/arch/arm/nmi.h b/include/zephyr/arch/arm/nmi.h index a4bd85802c1..33f46084248 100644 --- a/include/zephyr/arch/arm/nmi.h +++ b/include/zephyr/arch/arm/nmi.h @@ -10,11 +10,11 @@ * SPDX-License-Identifier: Apache-2.0 */ -#ifndef ZEPHYR_INCLUDE_ARCH_ARM_AARCH32_NMI_H_ -#define ZEPHYR_INCLUDE_ARCH_ARM_AARCH32_NMI_H_ +#ifndef ZEPHYR_INCLUDE_ARCH_ARM_NMI_H_ +#define ZEPHYR_INCLUDE_ARCH_ARM_NMI_H_ #if !defined(_ASMLANGUAGE) && defined(CONFIG_RUNTIME_NMI) extern void z_arm_nmi_set_handler(void (*pHandler)(void)); #endif -#endif /* ZEPHYR_INCLUDE_ARCH_ARM_AARCH32_NMI_H_ */ +#endif /* ZEPHYR_INCLUDE_ARCH_ARM_NMI_H_ */ diff --git a/include/zephyr/arch/arm/syscall.h b/include/zephyr/arch/arm/syscall.h index a4e067307ec..e07dab12a9e 100644 --- a/include/zephyr/arch/arm/syscall.h +++ b/include/zephyr/arch/arm/syscall.h @@ -13,8 +13,8 @@ * (include/arch/syscall.h) */ -#ifndef ZEPHYR_INCLUDE_ARCH_ARM_AARCH32_SYSCALL_H_ -#define ZEPHYR_INCLUDE_ARCH_ARM_AARCH32_SYSCALL_H_ +#ifndef ZEPHYR_INCLUDE_ARCH_ARM_SYSCALL_H_ +#define ZEPHYR_INCLUDE_ARCH_ARM_SYSCALL_H_ #define _SVC_CALL_CONTEXT_SWITCH 0 #define _SVC_CALL_IRQ_OFFLOAD 1 @@ -184,4 +184,4 @@ static inline bool arch_is_user_context(void) #endif /* _ASMLANGUAGE */ #endif /* CONFIG_USERSPACE */ -#endif /* ZEPHYR_INCLUDE_ARCH_ARM_AARCH32_SYSCALL_H_ */ +#endif /* ZEPHYR_INCLUDE_ARCH_ARM_SYSCALL_H_ */ diff --git a/include/zephyr/arch/arm/thread.h b/include/zephyr/arch/arm/thread.h index b4d34b137cb..139f606809f 100644 --- a/include/zephyr/arch/arm/thread.h +++ b/include/zephyr/arch/arm/thread.h @@ -16,8 +16,8 @@ * necessary to instantiate instances of struct k_thread. */ -#ifndef ZEPHYR_INCLUDE_ARCH_ARM_AARCH32_THREAD_H_ -#define ZEPHYR_INCLUDE_ARCH_ARM_AARCH32_THREAD_H_ +#ifndef ZEPHYR_INCLUDE_ARCH_ARM_THREAD_H_ +#define ZEPHYR_INCLUDE_ARCH_ARM_THREAD_H_ #ifndef _ASMLANGUAGE #include @@ -143,4 +143,4 @@ typedef struct _thread_arch _thread_arch_t; #endif /* _ASMLANGUAGE */ -#endif /* ZEPHYR_INCLUDE_ARCH_ARM_AARCH32_THREAD_H_ */ +#endif /* ZEPHYR_INCLUDE_ARCH_ARM_THREAD_H_ */ diff --git a/modules/cmsis/cmsis_core.h b/modules/cmsis/cmsis_core.h index 04e5566cc0a..4f57c682138 100644 --- a/modules/cmsis/cmsis_core.h +++ b/modules/cmsis/cmsis_core.h @@ -12,4 +12,4 @@ #include "cmsis_core_a_r.h" #endif -#endif /* ZEPHYR_INCLUDE_ARCH_ARM_AARCH32_CORTEX_M_CMSIS_H_ */ +#endif /* ZEPHYR_MODULES_CMSIS_CMSIS_H_ */ From 8e5c3ce616467436f3b29be96ed01290b822cc9b Mon Sep 17 00:00:00 2001 From: Anas Nashif Date: Sat, 25 Feb 2023 00:42:14 +0000 Subject: [PATCH 1148/3723] arch: xtensa: check for xt-clang instead of xcc-clang Check against new variant name. xcc-clang usage is deprecated. Signed-off-by: Anas Nashif --- arch/xtensa/Kconfig | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/arch/xtensa/Kconfig b/arch/xtensa/Kconfig index 326c7749e6b..c2c2e6cc8b0 100644 --- a/arch/xtensa/Kconfig +++ b/arch/xtensa/Kconfig @@ -173,7 +173,7 @@ endif # XTENSA_MMU config XTENSA_SYSCALL_USE_HELPER bool "Use userspace syscall helper" - default y if "$(ZEPHYR_TOOLCHAIN_VARIANT)" = "xcc-clang" + default y if "$(ZEPHYR_TOOLCHAIN_VARIANT)" = "xt-clang" depends on USERSPACE help Use syscall helpers for passing more then 3 arguments. From 2dab5dd0a0d2a27426a5d4fffd6874c553eb0ddb Mon Sep 17 00:00:00 2001 From: Jonathan Rico Date: Tue, 28 Nov 2023 14:23:56 +0100 Subject: [PATCH 1149/3723] tests: Bluetooth: add babblesim connection stress test This is supposed to stress the host buffer and metadata handling. It is not really testing any particular thing, ie. the pass criteria is just that each peripheral can send and receive a fixed number of GATT notifications without any device crashing or locking up. Original version by Ahmed Moheib (from cloud2ground). Signed-off-by: Jonathan Rico --- tests/bsim/bluetooth/host/compile.sh | 2 + .../misc/conn_stress/central/CMakeLists.txt | 15 + .../host/misc/conn_stress/central/prj.conf | 43 + .../host/misc/conn_stress/central/src/main.c | 768 ++++++++++++++++++ .../conn_stress/peripheral/CMakeLists.txt | 15 + .../host/misc/conn_stress/peripheral/prj.conf | 38 + .../misc/conn_stress/peripheral/src/main.c | 510 ++++++++++++ .../misc/conn_stress/scripts/_conn_stress.sh | 81 ++ 8 files changed, 1472 insertions(+) create mode 100644 tests/bsim/bluetooth/host/misc/conn_stress/central/CMakeLists.txt create mode 100644 tests/bsim/bluetooth/host/misc/conn_stress/central/prj.conf create mode 100644 tests/bsim/bluetooth/host/misc/conn_stress/central/src/main.c create mode 100644 tests/bsim/bluetooth/host/misc/conn_stress/peripheral/CMakeLists.txt create mode 100644 tests/bsim/bluetooth/host/misc/conn_stress/peripheral/prj.conf create mode 100644 tests/bsim/bluetooth/host/misc/conn_stress/peripheral/src/main.c create mode 100755 tests/bsim/bluetooth/host/misc/conn_stress/scripts/_conn_stress.sh diff --git a/tests/bsim/bluetooth/host/compile.sh b/tests/bsim/bluetooth/host/compile.sh index 9eb87341430..efa02f8dfb8 100755 --- a/tests/bsim/bluetooth/host/compile.sh +++ b/tests/bsim/bluetooth/host/compile.sh @@ -71,6 +71,8 @@ app=tests/bsim/bluetooth/host/l2cap/send_on_connect conf_file=prj_ecred.conf com app=tests/bsim/bluetooth/host/misc/disable compile app=tests/bsim/bluetooth/host/misc/disconnect/dut compile app=tests/bsim/bluetooth/host/misc/disconnect/tester compile +app=tests/bsim/bluetooth/host/misc/conn_stress/central compile +app=tests/bsim/bluetooth/host/misc/conn_stress/peripheral compile app=tests/bsim/bluetooth/host/privacy/central compile app=tests/bsim/bluetooth/host/privacy/peripheral compile diff --git a/tests/bsim/bluetooth/host/misc/conn_stress/central/CMakeLists.txt b/tests/bsim/bluetooth/host/misc/conn_stress/central/CMakeLists.txt new file mode 100644 index 00000000000..84c6ff866b1 --- /dev/null +++ b/tests/bsim/bluetooth/host/misc/conn_stress/central/CMakeLists.txt @@ -0,0 +1,15 @@ +# SPDX-License-Identifier: Apache-2.0 + +cmake_minimum_required(VERSION 3.20.0) + +find_package(Zephyr REQUIRED HINTS $ENV{ZEPHYR_BASE}) +project(conn_stress_central) + +target_sources(app PRIVATE + src/main.c +) + +zephyr_include_directories( + $ENV{BSIM_COMPONENTS_PATH}/libUtilv1/src/ + $ENV{BSIM_COMPONENTS_PATH}/libPhyComv1/src/ +) diff --git a/tests/bsim/bluetooth/host/misc/conn_stress/central/prj.conf b/tests/bsim/bluetooth/host/misc/conn_stress/central/prj.conf new file mode 100644 index 00000000000..3b0835e86df --- /dev/null +++ b/tests/bsim/bluetooth/host/misc/conn_stress/central/prj.conf @@ -0,0 +1,43 @@ +CONFIG_BT=y +CONFIG_BT_DEBUG_LOG=y +CONFIG_BT_CENTRAL=y +CONFIG_BT_MAX_CONN=12 +CONFIG_BT_MAX_PAIRED=12 +CONFIG_BT_SMP=y +CONFIG_BT_PRIVACY=y +CONFIG_BT_GATT_CLIENT=y + +CONFIG_BT_CTLR_DATA_LENGTH_MAX=251 +CONFIG_BT_BUF_ACL_RX_SIZE=251 +CONFIG_BT_BUF_ACL_TX_SIZE=251 + +CONFIG_BT_L2CAP_TX_MTU=247 + +# variations of this =n or =y on central/per produce different errors +CONFIG_BT_AUTO_PHY_UPDATE=y +CONFIG_BT_AUTO_DATA_LEN_UPDATE=y + +CONFIG_ASSERT=y +CONFIG_ASSERT_LEVEL=2 +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 + +# 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 +# CONFIG_BT_RECV_WORKQ_SYS=y + +# errors out getting event flags in hci_core.c +# CONFIG_BT_RECV_BLOCKING=y + +# TODO: remove when test is stable +CONFIG_BT_AUTO_PHY_UPDATE=n +CONFIG_BT_AUTO_DATA_LEN_UPDATE=n +CONFIG_BT_GAP_AUTO_UPDATE_CONN_PARAMS=n + +CONFIG_THREAD_NAME=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 new file mode 100644 index 00000000000..32da1c63df5 --- /dev/null +++ b/tests/bsim/bluetooth/host/misc/conn_stress/central/src/main.c @@ -0,0 +1,768 @@ +/* + * Copyright (c) 2023 Nordic Semiconductor ASA + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +LOG_MODULE_REGISTER(central, LOG_LEVEL_INF); + +#include "bstests.h" +#include "bs_types.h" +#include "bs_tracing.h" +#include "bstests.h" +#include "bs_pc_backchannel.h" + +#define DEFAULT_CONN_INTERVAL 20 +#define PERIPHERAL_DEVICE_NAME "Zephyr Peripheral" +#define PERIPHERAL_DEVICE_NAME_LEN (sizeof(PERIPHERAL_DEVICE_NAME) - 1) + +#define NOTIFICATION_DATA_PREFIX "Counter:" +#define NOTIFICATION_DATA_PREFIX_LEN (sizeof(NOTIFICATION_DATA_PREFIX) - 1) + +#define CHARACTERISTIC_DATA_MAX_LEN 260 +#define NOTIFICATION_DATA_LEN MAX(200, (CONFIG_BT_L2CAP_TX_MTU - 4)) +BUILD_ASSERT(NOTIFICATION_DATA_LEN <= CHARACTERISTIC_DATA_MAX_LEN); + +#define PERIPHERAL_SERVICE_UUID_VAL \ + BT_UUID_128_ENCODE(0x12345678, 0x1234, 0x5678, 0x1234, 0x56789abcdef0) + +#define PERIPHERAL_CHARACTERISTIC_UUID_VAL \ + BT_UUID_128_ENCODE(0x12345678, 0x1234, 0x5678, 0x1234, 0x56789abcdef1) + +#define PERIPHERAL_SERVICE_UUID BT_UUID_DECLARE_128(PERIPHERAL_SERVICE_UUID_VAL) +#define PERIPHERAL_CHARACTERISTIC_UUID BT_UUID_DECLARE_128(PERIPHERAL_CHARACTERISTIC_UUID_VAL) + +static struct bt_uuid_128 vnd_uuid = + BT_UUID_INIT_128(BT_UUID_128_ENCODE(0x12345678, 0x1234, 0x5678, 0x1234, 0x56789abcdea0)); + +static struct bt_uuid_128 vnd_enc_uuid = + BT_UUID_INIT_128(BT_UUID_128_ENCODE(0x12345678, 0x1234, 0x5678, 0x1234, 0x56789abcdea1)); + +enum { + DEVICE_IS_SCANNING, + DEVICE_IS_CONNECTING, + + /* Total number of flags - must be at the end of the enum */ + DEVICE_NUM_FLAGS, +}; + +enum { + CONN_INFO_SENT_MTU_EXCHANGE, + CONN_INFO_MTU_EXCHANGED, + CONN_INFO_DISCOVERING, + CONN_INFO_DISCOVER_PAUSED, + CONN_INFO_SUBSCRIBED, + + /* Total number of flags - must be at the end of the enum */ + CONN_INFO_NUM_FLAGS, +}; + +ATOMIC_DEFINE(status_flags, DEVICE_NUM_FLAGS); +static atomic_t conn_count; +static struct bt_conn *conn_connecting; +static struct bt_gatt_exchange_params mtu_exchange_params; + +struct conn_info { + ATOMIC_DEFINE(flags, CONN_INFO_NUM_FLAGS); + struct bt_conn *conn_ref; + uint32_t notify_counter; + uint32_t tx_notify_counter; + struct bt_uuid_128 uuid; + struct bt_gatt_discover_params discover_params; + struct bt_gatt_subscribe_params subscribe_params; + bt_addr_le_t addr; +}; + +static struct conn_info conn_infos[CONFIG_BT_MAX_CONN] = {0}; + +static uint32_t conn_interval_max, notification_size; +static uint8_t vnd_value[CHARACTERISTIC_DATA_MAX_LEN]; + +void clear_info(struct conn_info *info) +{ + /* clear everything except the address + sub params + uuid (lifetime > connection) */ + memset(&info->flags, 0, sizeof(info->flags)); + memset(&info->conn_ref, 0, sizeof(info->conn_ref)); + memset(&info->notify_counter, 0, sizeof(info->notify_counter)); + memset(&info->tx_notify_counter, 0, sizeof(info->tx_notify_counter)); +} + +static void ccc_cfg_changed(const struct bt_gatt_attr *attr, uint16_t value) +{ + /* TODO: add peer subscription check? */ + LOG_INF("CCC changed: %u", value); +} + +/* Vendor Primary Service Declaration */ +BT_GATT_SERVICE_DEFINE( + vnd_svc, BT_GATT_PRIMARY_SERVICE(&vnd_uuid), + BT_GATT_CHARACTERISTIC(&vnd_enc_uuid.uuid, + BT_GATT_CHRC_READ | BT_GATT_CHRC_WRITE | BT_GATT_CHRC_NOTIFY, + BT_GATT_PERM_READ | BT_GATT_PERM_WRITE, NULL, NULL, + NULL), + BT_GATT_CCC(ccc_cfg_changed, BT_GATT_PERM_READ | BT_GATT_PERM_WRITE), +); + +static struct conn_info *get_new_conn_info_ref(const bt_addr_le_t *addr) +{ + /* try to find per-addr first */ + for (size_t i = 0; i < ARRAY_SIZE(conn_infos); i++) { + if (bt_addr_le_eq(&conn_infos[i].addr, addr)) { + return &conn_infos[i]; + } + } + + /* try to allocate if addr not found */ + for (size_t i = 0; i < ARRAY_SIZE(conn_infos); i++) { + if (conn_infos[i].conn_ref == NULL) { + bt_addr_le_copy(&conn_infos[i].addr, addr); + + return &conn_infos[i]; + } + } + + __ASSERT(0, "ran out of contexts"); +} + +static struct conn_info *get_conn_info_ref(struct bt_conn *conn_ref) +{ + for (size_t i = 0; i < ARRAY_SIZE(conn_infos); i++) { + if (conn_ref == conn_infos[i].conn_ref) { + return &conn_infos[i]; + } + } + + return NULL; +} + +static bool is_connected(struct bt_conn *conn) +{ + struct bt_conn_info info; + int err = bt_conn_get_info(conn, &info); + + __ASSERT(!err, "Couldn't get conn info %d", err); + + return info.state == BT_CONN_STATE_CONNECTED; +} + +static struct conn_info *get_connected_conn_info_ref(struct bt_conn *conn) +{ + if (is_connected(conn)) { + return get_conn_info_ref(conn); + } + + return NULL; +} + +static uint8_t notify_func(struct bt_conn *conn, struct bt_gatt_subscribe_params *params, + const void *data, uint16_t length) +{ + const char *data_ptr = (const char *)data + NOTIFICATION_DATA_PREFIX_LEN; + uint32_t received_counter; + 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)); + + if (!data) { + LOG_INF("[UNSUBSCRIBED] addr %s", addr); + params->value_handle = 0U; + return BT_GATT_ITER_STOP; + } + + conn_info_ref = get_conn_info_ref(conn); + __ASSERT_NO_MSG(conn_info_ref); + + received_counter = strtoul(data_ptr, NULL, 0); + + LOG_DBG("[NOTIFICATION] addr %s data %s length %u cnt %u", + addr, data, length, received_counter); + + LOG_HEXDUMP_DBG(data, length, "RX"); + + __ASSERT(conn_info_ref->notify_counter == received_counter, + "addr %s expected counter : %u , received counter : %u", + addr, conn_info_ref->notify_counter, received_counter); + conn_info_ref->notify_counter++; + + return BT_GATT_ITER_CONTINUE; +} + +static uint8_t discover_func(struct bt_conn *conn, const struct bt_gatt_attr *attr, + struct bt_gatt_discover_params *params) +{ + int err; + char uuid_str[BT_UUID_STR_LEN]; + struct conn_info *conn_info_ref; + + if (!attr) { + /* We might be called from the ATT disconnection callback if we + * have an ongoing procedure. That is ok. + */ + __ASSERT_NO_MSG(!is_connected(conn)); + return BT_GATT_ITER_STOP; + } + __ASSERT(attr, "Did not find requested UUID"); + + bt_uuid_to_str(params->uuid, uuid_str, sizeof(uuid_str)); + LOG_DBG("UUID found : %s", uuid_str); + + LOG_INF("[ATTRIBUTE] handle %u", attr->handle); + + 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, + PERIPHERAL_CHARACTERISTIC_UUID, + sizeof(conn_info_ref->uuid)); + conn_info_ref->discover_params.uuid = &conn_info_ref->uuid.uuid; + conn_info_ref->discover_params.start_handle = attr->handle + 1; + conn_info_ref->discover_params.type = BT_GATT_DISCOVER_CHARACTERISTIC; + + err = bt_gatt_discover(conn, &conn_info_ref->discover_params); + if (err == -ENOMEM || err == -ENOTCONN) { + goto retry; + } + + __ASSERT(!err, "Discover failed (err %d)", err); + + } else if (conn_info_ref->discover_params.type == BT_GATT_DISCOVER_CHARACTERISTIC) { + LOG_DBG("Service Characteristic Found"); + memcpy(&conn_info_ref->uuid, BT_UUID_GATT_CCC, sizeof(conn_info_ref->uuid)); + conn_info_ref->discover_params.uuid = &conn_info_ref->uuid.uuid; + conn_info_ref->discover_params.start_handle = attr->handle + 2; + conn_info_ref->discover_params.type = BT_GATT_DISCOVER_DESCRIPTOR; + conn_info_ref->subscribe_params.value_handle = bt_gatt_attr_value_handle(attr); + + err = bt_gatt_discover(conn, &conn_info_ref->discover_params); + if (err == -ENOMEM || err == -ENOTCONN) { + goto retry; + } + + __ASSERT(!err, "Discover failed (err %d)", err); + + } else { + conn_info_ref->subscribe_params.notify = notify_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) { + 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; + +retry: + /* if we're out of buffers or metadata contexts, continue discovery + * later. + */ + LOG_INF("out of memory/not connected, continuing sub later"); + atomic_set_bit(conn_info_ref->flags, CONN_INFO_DISCOVER_PAUSED); + + return BT_GATT_ITER_STOP; +} + +static void stop_scan(void) +{ + int err; + + __ASSERT(atomic_test_bit(status_flags, DEVICE_IS_SCANNING), + "No scanning procedure is ongoing"); + atomic_clear_bit(status_flags, DEVICE_IS_SCANNING); + + err = bt_le_scan_stop(); + __ASSERT(!err, "Stop LE scan failed (err %d)", err); + + LOG_INF("Stopped scanning"); +} + +static bool check_if_peer_connected(const bt_addr_le_t *addr) +{ + for (size_t i = 0; i < ARRAY_SIZE(conn_infos); i++) { + if (conn_infos[i].conn_ref != NULL) { + if (!bt_addr_le_cmp(bt_conn_get_dst(conn_infos[i].conn_ref), addr)) { + return true; + } + } + } + + return false; +} + +static bool parse_ad(struct bt_data *data, void *user_data) +{ + bt_addr_le_t *addr = user_data; + + LOG_DBG("[AD]: %u data_len %u", data->type, data->data_len); + + switch (data->type) { + case BT_DATA_NAME_SHORTENED: + case BT_DATA_NAME_COMPLETE: + LOG_INF("------------------------------------------------------"); + LOG_INF("Device name : %.*s", data->data_len, data->data); + + if (check_if_peer_connected(addr)) { + LOG_ERR("Peer is already connected or in disconnecting state"); + break; + } + + __ASSERT(!atomic_test_bit(status_flags, DEVICE_IS_CONNECTING), + "A connection procedure is ongoing"); + atomic_set_bit(status_flags, DEVICE_IS_CONNECTING); + + stop_scan(); + + char addr_str[BT_ADDR_LE_STR_LEN]; + + bt_addr_le_to_str(addr, addr_str, sizeof(addr_str)); + LOG_INF("Connecting to %s", addr_str); + + struct bt_le_conn_param *param = BT_LE_CONN_PARAM_DEFAULT; + int err = bt_conn_le_create(addr, BT_CONN_LE_CREATE_CONN, param, + &conn_connecting); + + __ASSERT(!err, "Create conn failed (err %d)", err); + + return false; + + break; + } + + return true; +} + +static void device_found(const bt_addr_le_t *addr, int8_t rssi, uint8_t type, + struct net_buf_simple *ad) +{ + bt_data_parse(ad, parse_ad, (void *)addr); +} + +static void start_scan(void) +{ + int err; + struct bt_le_scan_param scan_param = { + .type = BT_LE_SCAN_TYPE_ACTIVE, + .options = BT_LE_SCAN_OPT_NONE, + .interval = BT_GAP_SCAN_FAST_INTERVAL, + .window = BT_GAP_SCAN_FAST_WINDOW, + }; + + atomic_set_bit(status_flags, DEVICE_IS_SCANNING); + + err = bt_le_scan_start(&scan_param, device_found); + __ASSERT(!err, "Scanning failed to start (err %d)", err); + + LOG_INF("Started scanning"); +} + +static void connected_cb(struct bt_conn *conn, uint8_t conn_err) +{ + 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(conn_err == BT_HCI_ERR_SUCCESS, "Failed to connect to %s (%u)", addr, conn_err); + + LOG_INF("Connection %p established : %s", conn, addr); + + atomic_inc(&conn_count); + LOG_DBG("connected to %u devices", atomic_get(&conn_count)); + + conn_info_ref = get_new_conn_info_ref(bt_conn_get_dst(conn)); + __ASSERT_NO_MSG(conn_info_ref->conn_ref == NULL); + + conn_info_ref->conn_ref = conn_connecting; + +#if defined(CONFIG_BT_SMP) + int err = bt_conn_set_security(conn, BT_SECURITY_L2); + + if (!err) { + LOG_INF("Security level is set to : %u", BT_SECURITY_L2); + } else { + LOG_ERR("Failed to set security (%d).", err); + } +#endif /* CONFIG_BT_SMP */ + + __ASSERT_NO_MSG(conn == conn_connecting); + if (conn == conn_connecting) { + conn_connecting = NULL; + atomic_clear_bit(status_flags, DEVICE_IS_CONNECTING); + } +} + +static void disconnected(struct bt_conn *conn, uint8_t reason) +{ + 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)); + + LOG_INF("Disconnected: %s (reason 0x%02x)", addr, reason); + + conn_info_ref = get_conn_info_ref(conn); + __ASSERT_NO_MSG(conn_info_ref->conn_ref != NULL); + + bool valid_reason = + reason == BT_HCI_ERR_REMOTE_POWER_OFF || + reason == BT_HCI_ERR_LOCALHOST_TERM_CONN; + + __ASSERT(valid_reason, "Disconnected (reason 0x%02x)", reason); + + bt_conn_unref(conn); + clear_info(conn_info_ref); + atomic_dec(&conn_count); +} + +#if defined(CONFIG_BT_SMP) +static void security_changed(struct bt_conn *conn, bt_security_t level, enum bt_security_err err) +{ + char addr[BT_ADDR_LE_STR_LEN]; + + bt_addr_le_to_str(bt_conn_get_dst(conn), addr, sizeof(addr)); + + __ASSERT(!err, "Security for %s failed", addr); + LOG_INF("Security for %s changed: level %u", addr, level); + + if (err) { + LOG_ERR("Security failed, disconnecting"); + bt_conn_disconnect(conn, BT_HCI_ERR_REMOTE_POWER_OFF); + } +} +#endif /* CONFIG_BT_SMP */ + +static void identity_resolved(struct bt_conn *conn, const bt_addr_le_t *rpa, + const bt_addr_le_t *identity) +{ + char addr_identity[BT_ADDR_LE_STR_LEN]; + char addr_rpa[BT_ADDR_LE_STR_LEN]; + struct conn_info *conn_info_ref; + + bt_addr_le_to_str(identity, addr_identity, sizeof(addr_identity)); + bt_addr_le_to_str(rpa, addr_rpa, sizeof(addr_rpa)); + + LOG_ERR("Identity resolved %s -> %s", addr_rpa, addr_identity); + + /* overwrite RPA */ + conn_info_ref = get_conn_info_ref(conn); + bt_addr_le_copy(&conn_info_ref->addr, identity); +} + +BT_CONN_CB_DEFINE(conn_callbacks) = { + .connected = connected_cb, + .disconnected = disconnected, +#if defined(CONFIG_BT_SMP) + .security_changed = security_changed, +#endif /* CONFIG_BT_SMP */ + .identity_resolved = identity_resolved, +}; + +void mtu_updated(struct bt_conn *conn, uint16_t tx, uint16_t rx) +{ + LOG_INF("Updated MTU: TX: %d RX: %d bytes", tx, rx); +} + +static struct bt_gatt_cb gatt_callbacks = {.att_mtu_updated = mtu_updated}; + +static void mtu_exchange_cb(struct bt_conn *conn, uint8_t err, + struct bt_gatt_exchange_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)); + + conn_info_ref = get_conn_info_ref(conn); + __ASSERT_NO_MSG(conn_info_ref); + + LOG_DBG("MTU exchange addr %s conn %s", addr, + err == 0U ? "successful" : "failed"); + + atomic_set_bit(conn_info_ref->flags, CONN_INFO_MTU_EXCHANGED); +} + +static void exchange_mtu(struct bt_conn *conn, void *data) +{ + struct conn_info *conn_info_ref; + char addr[BT_ADDR_LE_STR_LEN]; + int err; + + bt_addr_le_to_str(bt_conn_get_dst(conn), addr, sizeof(addr)); + + conn_info_ref = get_connected_conn_info_ref(conn); + if (conn_info_ref == NULL) { + LOG_DBG("not connected: %s", addr); + return; + } + + if (!atomic_test_bit(conn_info_ref->flags, CONN_INFO_MTU_EXCHANGED) && + !atomic_test_and_set_bit(conn_info_ref->flags, CONN_INFO_SENT_MTU_EXCHANGE)) { + LOG_DBG("Updating MTU for %s to %u", addr, bt_gatt_get_mtu(conn)); + + mtu_exchange_params.func = mtu_exchange_cb; + err = bt_gatt_exchange_mtu(conn, &mtu_exchange_params); + if (err) { + LOG_ERR("MTU exchange failed (err %d)", err); + atomic_clear_bit(conn_info_ref->flags, CONN_INFO_SENT_MTU_EXCHANGE); + } else { + LOG_INF("MTU Exchange pending..."); + } + } +} + +static void subscribe_to_service(struct bt_conn *conn, void *data) +{ + struct conn_info *conn_info_ref; + int err; + int *p_err = (int *)data; + char addr[BT_ADDR_LE_STR_LEN]; + + bt_addr_le_to_str(bt_conn_get_dst(conn), addr, sizeof(addr)); + + conn_info_ref = get_connected_conn_info_ref(conn); + if (conn_info_ref == NULL) { + LOG_DBG("not connected: %s", addr); + return; + } + + /* start subscription procedure if: + * - we haven't started it yet for this conn + * - it was suspended due to a lack of resources + */ + if (!atomic_test_bit(conn_info_ref->flags, CONN_INFO_SUBSCRIBED) && + (!atomic_test_bit(conn_info_ref->flags, CONN_INFO_DISCOVERING) || + atomic_test_bit(conn_info_ref->flags, CONN_INFO_DISCOVER_PAUSED))) { + /* If discovery hasn't started yet, load params. If it was + * already started, then not touching the params will resume + * discovery at the attribute it was stopped at. + */ + if (!atomic_test_and_set_bit(conn_info_ref->flags, CONN_INFO_DISCOVERING)) { + memcpy(&conn_info_ref->uuid, PERIPHERAL_SERVICE_UUID, + sizeof(conn_info_ref->uuid)); + memset(&conn_info_ref->discover_params, 0, + sizeof(conn_info_ref->discover_params)); + + conn_info_ref->discover_params.uuid = &conn_info_ref->uuid.uuid; + conn_info_ref->discover_params.func = discover_func; + conn_info_ref->discover_params.start_handle = BT_ATT_FIRST_ATTRIBUTE_HANDLE; + conn_info_ref->discover_params.end_handle = BT_ATT_LAST_ATTRIBUTE_HANDLE; + conn_info_ref->discover_params.type = BT_GATT_DISCOVER_PRIMARY; + LOG_INF("start discovery of %s", addr); + } else { + LOG_INF("resume discovery of %s", addr); + } + + err = bt_gatt_discover(conn, &conn_info_ref->discover_params); + if (*p_err == 0) { + /* Don't overwrite `err` if it was previously set. it is + * cleared by the caller. + */ + *p_err = err; + } + + if (err != -ENOMEM && err != -ENOTCONN) { + __ASSERT(!err, "Subscribe failed (err %d)", err); + } + } +} + +static void notify_peers(struct bt_conn *conn, void *data) +{ + int err; + struct bt_gatt_attr *vnd_attr = (struct bt_gatt_attr *)data; + 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)); + + conn_info_ref = get_connected_conn_info_ref(conn); + if (conn_info_ref == NULL) { + LOG_DBG("not connected: %s", addr); + return; + } + + if (!atomic_test_bit(conn_info_ref->flags, CONN_INFO_MTU_EXCHANGED)) { + LOG_DBG("can't notify: MTU not yet exchanged"); + /* sleep a bit to allow the exchange to take place */ + k_msleep(100); + return; + } + + memset(vnd_value, 0x00, sizeof(vnd_value)); + snprintk(vnd_value, notification_size, "%s%u", NOTIFICATION_DATA_PREFIX, + conn_info_ref->tx_notify_counter); + LOG_INF("notify: %s", addr); + err = bt_gatt_notify(conn, vnd_attr, vnd_value, notification_size); + if (err) { + LOG_ERR("Couldn't send GATT notification"); + return; + } + + LOG_DBG("central notified: %s %d", addr, conn_info_ref->tx_notify_counter); + + conn_info_ref->tx_notify_counter++; +} + +void test_central_main(void) +{ + int err; + struct bt_gatt_attr *vnd_attr; + char str[BT_UUID_STR_LEN]; + char addr[BT_ADDR_LE_STR_LEN]; + + memset(&conn_infos, 0x00, sizeof(conn_infos)); + + err = bt_enable(NULL); + + if (err) { + LOG_ERR("Bluetooth init failed (err %d)", err); + return; + } + + LOG_DBG("Bluetooth initialized"); + + bt_gatt_cb_register(&gatt_callbacks); + + vnd_attr = bt_gatt_find_by_uuid(vnd_svc.attrs, vnd_svc.attr_count, &vnd_enc_uuid.uuid); + + bt_uuid_to_str(&vnd_enc_uuid.uuid, str, sizeof(str)); + LOG_DBG("Indicate VND attr %p (UUID %s)", vnd_attr, str); + + start_scan(); + + while (true) { + /* reconnect peripherals when they drop out */ + if (atomic_get(&conn_count) < CONFIG_BT_MAX_CONN && + !atomic_test_bit(status_flags, DEVICE_IS_SCANNING) && + !atomic_test_bit(status_flags, DEVICE_IS_CONNECTING)) { + start_scan(); + } else { + if (atomic_test_bit(status_flags, DEVICE_IS_CONNECTING)) { + bt_addr_le_to_str(bt_conn_get_dst(conn_connecting), + addr, sizeof(addr)); + LOG_INF("already connecting to: %s", addr); + } + } + + bt_conn_foreach(BT_CONN_TYPE_LE, exchange_mtu, NULL); + + err = 0; + bt_conn_foreach(BT_CONN_TYPE_LE, subscribe_to_service, &err); + if (!err) { + bt_conn_foreach(BT_CONN_TYPE_LE, notify_peers, vnd_attr); + } else { + /* Allow the sub procedure to complete. Else the + * notifications use up all the buffers and it can never + * complete in time. + */ + LOG_ERR("subscription failed: %d, not notifying", err); + } + k_msleep(10); + } +} + +void test_init(void) +{ + extern enum bst_result_t bst_result; + + LOG_INF("Initializing Test"); + /* The peripherals determines whether the test passed. */ + bst_result = Passed; +} + +static void test_args(int argc, char **argv) +{ + conn_interval_max = DEFAULT_CONN_INTERVAL; + notification_size = NOTIFICATION_DATA_LEN; + + if (argc >= 1) { + char const *ptr; + + ptr = strstr(argv[0], "notify_size="); + if (ptr != NULL) { + ptr += strlen("notify_size="); + notification_size = atol(ptr); + notification_size = MIN(NOTIFICATION_DATA_LEN, notification_size); + } + } + + if (argc == 2) { + char const *ptr; + + ptr = strstr(argv[1], "conn_interval="); + if (ptr != NULL) { + ptr += strlen("conn_interval="); + conn_interval_max = atol(ptr); + } + } + + bs_trace_raw(0, "Connection interval max : %d\n", conn_interval_max); + bs_trace_raw(0, "Notification data size : %d\n", notification_size); +} + +static const struct bst_test_instance test_def[] = { + { + .test_id = "central", + .test_descr = "Central Connection Stress", + .test_args_f = test_args, + .test_post_init_f = test_init, + .test_main_f = test_central_main + }, + BSTEST_END_MARKER +}; + +struct bst_test_list *test_main_conn_stress_install(struct bst_test_list *tests) +{ + return bst_add_tests(tests, test_def); +} + +extern struct bst_test_list *test_main_conn_stress_install(struct bst_test_list *tests); + +bst_test_install_t test_installers[] = { + test_main_conn_stress_install, + NULL +}; + +int main(void) +{ + bst_main(); + + return 0; +} diff --git a/tests/bsim/bluetooth/host/misc/conn_stress/peripheral/CMakeLists.txt b/tests/bsim/bluetooth/host/misc/conn_stress/peripheral/CMakeLists.txt new file mode 100644 index 00000000000..3b18f105292 --- /dev/null +++ b/tests/bsim/bluetooth/host/misc/conn_stress/peripheral/CMakeLists.txt @@ -0,0 +1,15 @@ +# SPDX-License-Identifier: Apache-2.0 + +cmake_minimum_required(VERSION 3.20.0) + +find_package(Zephyr REQUIRED HINTS $ENV{ZEPHYR_BASE}) +project(conn_stress_peripheral) + +target_sources(app PRIVATE + src/main.c +) + +zephyr_include_directories( + $ENV{BSIM_COMPONENTS_PATH}/libUtilv1/src/ + $ENV{BSIM_COMPONENTS_PATH}/libPhyComv1/src/ +) diff --git a/tests/bsim/bluetooth/host/misc/conn_stress/peripheral/prj.conf b/tests/bsim/bluetooth/host/misc/conn_stress/peripheral/prj.conf new file mode 100644 index 00000000000..1c126fac84d --- /dev/null +++ b/tests/bsim/bluetooth/host/misc/conn_stress/peripheral/prj.conf @@ -0,0 +1,38 @@ +# Increased stack due to settings API usage +CONFIG_SYSTEM_WORKQUEUE_STACK_SIZE=2048 + +CONFIG_BT=y +CONFIG_BT_DEBUG_LOG=y +CONFIG_BT_SMP=y +CONFIG_BT_PRIVACY=y +CONFIG_BT_PERIPHERAL=y +CONFIG_BT_GATT_CLIENT=y +CONFIG_BT_ATT_PREPARE_COUNT=5 +CONFIG_BT_MAX_CONN=1 +CONFIG_BT_MAX_PAIRED=1 +CONFIG_BT_ID_MAX=1 +CONFIG_BT_DEVICE_NAME="per-default" +CONFIG_BT_DEVICE_NAME_DYNAMIC=y +CONFIG_BT_DEVICE_APPEARANCE=833 +CONFIG_BT_DEVICE_NAME_DYNAMIC=y +CONFIG_BT_DEVICE_NAME_MAX=65 + +CONFIG_BT_CTLR_DATA_LENGTH_MAX=251 +CONFIG_BT_BUF_ACL_RX_SIZE=251 +CONFIG_BT_BUF_ACL_TX_SIZE=251 + +CONFIG_BT_L2CAP_TX_MTU=247 + +CONFIG_ASSERT=y +CONFIG_ASSERT_LEVEL=2 +CONFIG_ASSERT_VERBOSE=y +CONFIG_ASSERT_ON_ERRORS=y + +CONFIG_BT_LOG_SNIFFER_INFO=y + +# TODO: remove when test is stable +CONFIG_BT_AUTO_PHY_UPDATE=n +CONFIG_BT_AUTO_DATA_LEN_UPDATE=n +CONFIG_BT_GAP_AUTO_UPDATE_CONN_PARAMS=n + +CONFIG_THREAD_NAME=y 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 new file mode 100644 index 00000000000..f78228b0be8 --- /dev/null +++ b/tests/bsim/bluetooth/host/misc/conn_stress/peripheral/src/main.c @@ -0,0 +1,510 @@ +/* + * Copyright (c) 2023 Nordic Semiconductor ASA + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +LOG_MODULE_REGISTER(peripheral, LOG_LEVEL_INF); + +#include "bstests.h" +#include "bs_types.h" +#include "bs_tracing.h" +#include "bstests.h" +#include "bs_pc_backchannel.h" +#include "argparse.h" + +#define TEST_ROUNDS 10 +#define MIN_NOTIFICATIONS 50 + +#define NOTIFICATION_DATA_PREFIX "Counter:" +#define NOTIFICATION_DATA_PREFIX_LEN (sizeof(NOTIFICATION_DATA_PREFIX) - 1) + +#define CHARACTERISTIC_DATA_MAX_LEN 260 +#define NOTIFICATION_DATA_LEN MAX(200, (CONFIG_BT_L2CAP_TX_MTU - 4)) +BUILD_ASSERT(NOTIFICATION_DATA_LEN <= CHARACTERISTIC_DATA_MAX_LEN); + +#define CENTRAL_SERVICE_UUID_VAL \ + BT_UUID_128_ENCODE(0x12345678, 0x1234, 0x5678, 0x1234, 0x56789abcdea0) + +#define CENTRAL_CHARACTERISTIC_UUID_VAL \ + BT_UUID_128_ENCODE(0x12345678, 0x1234, 0x5678, 0x1234, 0x56789abcdea1) + +#define CENTRAL_SERVICE_UUID BT_UUID_DECLARE_128(CENTRAL_SERVICE_UUID_VAL) +#define CENTRAL_CHARACTERISTIC_UUID BT_UUID_DECLARE_128(CENTRAL_CHARACTERISTIC_UUID_VAL) + +/* Custom Service Variables */ +static struct bt_uuid_128 vnd_uuid = + BT_UUID_INIT_128(BT_UUID_128_ENCODE(0x12345678, 0x1234, 0x5678, 0x1234, 0x56789abcdef0)); + +static struct bt_uuid_128 vnd_enc_uuid = + BT_UUID_INIT_128(BT_UUID_128_ENCODE(0x12345678, 0x1234, 0x5678, 0x1234, 0x56789abcdef1)); + +enum { + CONN_INFO_CONNECTED, + CONN_INFO_SECURITY_LEVEL_UPDATED, + CONN_INFO_MTU_EXCHANGED, + CONN_INFO_DISCOVERING, + CONN_INFO_SUBSCRIBED, + /* Total number of flags - must be at the end of the enum */ + CONN_INFO_NUM_FLAGS, +}; + +struct active_conn_info { + ATOMIC_DEFINE(flags, CONN_INFO_NUM_FLAGS); + struct bt_conn *conn_ref; + atomic_t notify_counter; + atomic_t tx_notify_counter; +#if defined(CONFIG_BT_USER_DATA_LEN_UPDATE) + struct bt_conn_le_data_len_param le_data_len_param; +#endif +}; + +static struct active_conn_info conn_info; + +static uint32_t rounds; + +/* This is outside the conn context since it can remain valid across + * connections + */ +static uint8_t central_subscription; +static uint8_t tx_data[CHARACTERISTIC_DATA_MAX_LEN]; +static uint32_t notification_size; /* TODO: does this _need_ to be set in args? */ + +static struct bt_uuid_128 uuid = BT_UUID_INIT_128(0); +static struct bt_gatt_discover_params discover_params; +static struct bt_gatt_subscribe_params subscribe_params; + +static void vnd_ccc_cfg_changed(const struct bt_gatt_attr *attr, uint16_t value) +{ + central_subscription = (value == BT_GATT_CCC_NOTIFY) ? 1 : 0; +} + +/* Vendor Primary Service Declaration */ +BT_GATT_SERVICE_DEFINE( + vnd_svc, BT_GATT_PRIMARY_SERVICE(&vnd_uuid), + BT_GATT_CHARACTERISTIC(&vnd_enc_uuid.uuid, + BT_GATT_CHRC_READ | BT_GATT_CHRC_WRITE | BT_GATT_CHRC_NOTIFY, + BT_GATT_PERM_READ | BT_GATT_PERM_WRITE, NULL, NULL, + NULL), + BT_GATT_CCC(vnd_ccc_cfg_changed, BT_GATT_PERM_READ | BT_GATT_PERM_WRITE), +); + +void mtu_updated(struct bt_conn *conn, uint16_t tx, uint16_t rx) +{ + LOG_INF("Updated MTU: TX: %d RX: %d bytes", tx, rx); + + if (tx == CONFIG_BT_L2CAP_TX_MTU && rx == CONFIG_BT_L2CAP_TX_MTU) { + char addr[BT_ADDR_LE_STR_LEN]; + + bt_addr_le_to_str(bt_conn_get_dst(conn), addr, sizeof(addr)); + + atomic_set_bit(conn_info.flags, CONN_INFO_MTU_EXCHANGED); + LOG_INF("Updating MTU succeeded %s", addr); + } +} + +static struct bt_gatt_cb gatt_callbacks = {.att_mtu_updated = mtu_updated}; + +static void connected(struct bt_conn *conn, uint8_t err) +{ + char addr[BT_ADDR_LE_STR_LEN]; + + if (err) { + memset(&conn_info, 0x00, sizeof(struct active_conn_info)); + LOG_ERR("Connection failed (err 0x%02x)", err); + return; + } + + bt_addr_le_to_str(bt_conn_get_dst(conn), addr, sizeof(addr)); + + rounds++; + conn_info.conn_ref = conn; + + atomic_set(&conn_info.tx_notify_counter, 0); + atomic_set(&conn_info.notify_counter, 0); + atomic_set_bit(conn_info.flags, CONN_INFO_CONNECTED); + + LOG_INF("Connection %p established : %s", conn, addr); +} + +static void disconnected(struct bt_conn *conn, uint8_t reason) +{ + LOG_DBG("Disconnected (reason 0x%02x)", reason); + + /* With a lot of devices, it is possible that the central doesn't see + * the disconnect packet. + */ + bool valid_reason = + reason == BT_HCI_ERR_LOCALHOST_TERM_CONN || + reason == BT_HCI_ERR_CONN_TIMEOUT; + + __ASSERT(valid_reason, "Disconnected (reason 0x%02x)", reason); + + memset(&conn_info, 0x00, sizeof(struct active_conn_info)); + + if (rounds >= TEST_ROUNDS) { + LOG_INF("Number of conn/disconn cycles reached, stopping advertiser..."); + bt_le_adv_stop(); + + LOG_INF("Test passed"); + + extern enum bst_result_t bst_result; + + bst_result = Passed; + } +} + +static bool le_param_req(struct bt_conn *conn, struct bt_le_conn_param *param) +{ + char addr[BT_ADDR_LE_STR_LEN]; + + bt_addr_le_to_str(bt_conn_get_dst(conn), addr, sizeof(addr)); + + LOG_DBG("LE conn param req: %s int (0x%04x (~%u ms), 0x%04x (~%u ms)) lat %d to %d", + addr, param->interval_min, (uint32_t)(param->interval_min * 1.25), + param->interval_max, (uint32_t)(param->interval_max * 1.25), param->latency, + param->timeout); + + return true; +} + +#if defined(CONFIG_BT_SMP) +static void security_changed(struct bt_conn *conn, bt_security_t level, enum bt_security_err err) +{ + char addr[BT_ADDR_LE_STR_LEN]; + + bt_addr_le_to_str(bt_conn_get_dst(conn), addr, sizeof(addr)); + + if (err) { + LOG_ERR("Security for %p failed: %s level %u err %d", conn, addr, level, err); + return; + } + + LOG_INF("Security for %p changed: %s level %u", conn, addr, level); + atomic_set_bit(conn_info.flags, CONN_INFO_SECURITY_LEVEL_UPDATED); +} +#endif /* CONFIG_BT_SMP */ + +BT_CONN_CB_DEFINE(conn_callbacks) = { + .connected = connected, + .disconnected = disconnected, + .le_param_req = le_param_req, +#if defined(CONFIG_BT_SMP) + .security_changed = security_changed, +#endif /* CONFIG_BT_SMP */ +}; + +static uint8_t rx_notification(struct bt_conn *conn, struct bt_gatt_subscribe_params *params, + const void *data, uint16_t length) +{ + const char *data_ptr = (const char *)data + NOTIFICATION_DATA_PREFIX_LEN; + uint32_t received_counter; + char addr[BT_ADDR_LE_STR_LEN]; + + if (!data) { + LOG_INF("[UNSUBSCRIBED]"); + params->value_handle = 0U; + return BT_GATT_ITER_STOP; + } + + /* TODO: enable */ + /* __ASSERT_NO_MSG(atomic_test_bit(conn_info.flags, CONN_INFO_SUBSCRIBED)); */ + + bt_addr_le_to_str(bt_conn_get_dst(conn), addr, sizeof(addr)); + + received_counter = strtoul(data_ptr, NULL, 0); + LOG_INF("RX %d", received_counter); + + __ASSERT(atomic_get(&conn_info.notify_counter) == received_counter, + "expected counter : %u , received counter : %u", + atomic_get(&conn_info.notify_counter), received_counter); + + atomic_inc(&conn_info.notify_counter); + + return BT_GATT_ITER_CONTINUE; +} + +static uint8_t discover_func(struct bt_conn *conn, const struct bt_gatt_attr *attr, + struct bt_gatt_discover_params *params) +{ + int err; + char uuid_str[BT_UUID_STR_LEN]; + + if (!attr) { + LOG_INF("Discover complete"); + (void)memset(params, 0, sizeof(*params)); + return BT_GATT_ITER_STOP; + } + + bt_uuid_to_str(params->uuid, uuid_str, sizeof(uuid_str)); + LOG_DBG("UUID found : %s", uuid_str); + + LOG_DBG("[ATTRIBUTE] handle %u", attr->handle); + + if (discover_params.type == BT_GATT_DISCOVER_PRIMARY) { + LOG_DBG("Primary Service Found"); + memcpy(&uuid, CENTRAL_CHARACTERISTIC_UUID, sizeof(uuid)); + discover_params.uuid = &uuid.uuid; + discover_params.start_handle = attr->handle + 1; + discover_params.type = BT_GATT_DISCOVER_CHARACTERISTIC; + + err = bt_gatt_discover(conn, &discover_params); + if (err == -ENOMEM) { + goto nomem; + } + + __ASSERT(!err, "Discover failed (err %d)", err); + + } else if (discover_params.type == BT_GATT_DISCOVER_CHARACTERISTIC) { + LOG_DBG("Service Characteristic Found"); + memcpy(&uuid, BT_UUID_GATT_CCC, sizeof(uuid)); + params->uuid = &uuid.uuid; + params->start_handle = attr->handle + 2; + params->type = BT_GATT_DISCOVER_DESCRIPTOR; + subscribe_params.value_handle = bt_gatt_attr_value_handle(attr); + + err = bt_gatt_discover(conn, params); + if (err == -ENOMEM) { + goto nomem; + } + + __ASSERT(!err, "Discover failed (err %d)", err); + + } else if (atomic_test_and_clear_bit(conn_info.flags, CONN_INFO_DISCOVERING)) { + + subscribe_params.notify = rx_notification; + subscribe_params.value = BT_GATT_CCC_NOTIFY; + subscribe_params.ccc_handle = attr->handle; + + LOG_ERR("subscribe"); + err = bt_gatt_subscribe(conn, &subscribe_params); + if (err == -ENOMEM) { + goto nomem; + } + + if (err != -EALREADY) { + __ASSERT(!err, "Subscribe failed (err %d)", err); + } + + __ASSERT_NO_MSG(!atomic_test_bit(conn_info.flags, CONN_INFO_SUBSCRIBED)); + atomic_set_bit(conn_info.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; + +nomem: + /* if we're out of buffers or metadata contexts, restart discovery + * later. + */ + LOG_ERR("out of memory, retry sub later"); + atomic_clear_bit(conn_info.flags, CONN_INFO_DISCOVERING); + + return BT_GATT_ITER_STOP; +} + +static void subscribe_to_service(struct bt_conn *conn) +{ + while (!atomic_test_and_set_bit(conn_info.flags, CONN_INFO_DISCOVERING) && + !atomic_test_bit(conn_info.flags, CONN_INFO_SUBSCRIBED)) { + int err; + char addr[BT_ADDR_LE_STR_LEN]; + + bt_addr_le_to_str(bt_conn_get_dst(conn), addr, sizeof(addr)); + + memcpy(&uuid, CENTRAL_SERVICE_UUID, sizeof(uuid)); + discover_params.uuid = &uuid.uuid; + discover_params.func = discover_func; + discover_params.start_handle = BT_ATT_FIRST_ATTRIBUTE_HANDLE; + discover_params.end_handle = BT_ATT_LAST_ATTRIBUTE_HANDLE; + discover_params.type = BT_GATT_DISCOVER_PRIMARY; + + err = bt_gatt_discover(conn, &discover_params); + if (err == -ENOMEM) { + LOG_DBG("out of memory, retry sub later"); + atomic_clear_bit(conn_info.flags, CONN_INFO_DISCOVERING); + } + + __ASSERT(!err, "Subscribe failed (err %d)", err); + + while (atomic_test_bit(conn_info.flags, CONN_INFO_DISCOVERING) && + !atomic_test_bit(conn_info.flags, CONN_INFO_SUBSCRIBED)) { + k_sleep(K_MSEC(10)); + } + } +} + +void set_tx_payload(uint32_t count) +{ + memset(tx_data, 0x00, sizeof(tx_data)); + snprintk(tx_data, notification_size, "%s%u", NOTIFICATION_DATA_PREFIX, count); +} + +void disconnect(void) +{ + /* we should always be the ones doing the disconnecting */ + __ASSERT_NO_MSG(conn_info.conn_ref); + + int err = bt_conn_disconnect(conn_info.conn_ref, + BT_HCI_ERR_REMOTE_POWER_OFF); + + if (err) { + LOG_ERR("Terminating conn failed (err %d)", err); + } + + /* wait for disconnection callback */ + while (atomic_test_bit(conn_info.flags, CONN_INFO_CONNECTED)) { + k_sleep(K_MSEC(10)); + } +} + +void test_peripheral_main(void) +{ + struct bt_gatt_attr *vnd_attr; + char name[10]; + int err; + + err = bt_enable(NULL); + if (err) { + LOG_ERR("Bluetooth init failed (err %d)", err); + return; + } + LOG_DBG("Bluetooth initialized"); + + sprintf(name, "per-%d", get_device_nbr()); + bt_set_name(name); + + err = bt_le_adv_start(BT_LE_ADV_CONN_NAME, NULL, 0, NULL, 0); + if (err) { + LOG_ERR("Advertising failed to start (err %d)", err); + __ASSERT_NO_MSG(err); + } + LOG_INF("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) { + LOG_DBG("Waiting for connection from central.."); + while (!atomic_test_bit(conn_info.flags, CONN_INFO_CONNECTED)) { + k_sleep(K_MSEC(10)); + } + + LOG_DBG("Subscribing to central.."); + subscribe_to_service(conn_info.conn_ref); + + LOG_DBG("Waiting until central subscribes.."); + while (!central_subscription) { + k_sleep(K_MSEC(10)); + } + + while (!atomic_test_bit(conn_info.flags, CONN_INFO_MTU_EXCHANGED)) { + k_sleep(K_MSEC(10)); + } + + LOG_INF("Begin sending notifications to central.."); + while (central_subscription && + atomic_test_bit(conn_info.flags, CONN_INFO_CONNECTED)) { + + set_tx_payload(atomic_get(&conn_info.tx_notify_counter)); + err = bt_gatt_notify(NULL, vnd_attr, tx_data, notification_size); + if (err) { + if (atomic_get(&conn_info.tx_notify_counter) > 0) { + atomic_dec(&conn_info.tx_notify_counter); + } + LOG_DBG("Couldn't send GATT notification"); + k_msleep(10); + } else { + atomic_inc(&conn_info.tx_notify_counter); + LOG_INF("TX %d", atomic_get(&conn_info.tx_notify_counter)); + } + + if (atomic_get(&conn_info.tx_notify_counter) > MIN_NOTIFICATIONS && + atomic_get(&conn_info.notify_counter) > MIN_NOTIFICATIONS) { + LOG_INF("Disconnecting.."); + disconnect(); + } + } + } +} + +void test_init(void) +{ + extern enum bst_result_t bst_result; + + LOG_INF("Initializing Test"); + bst_result = Failed; +} + +static void test_args(int argc, char **argv) +{ + notification_size = NOTIFICATION_DATA_LEN; + + if (argc >= 1) { + char const *ptr; + + ptr = strstr(argv[0], "notify_size="); + if (ptr != NULL) { + ptr += strlen("notify_size="); + notification_size = atol(ptr); + notification_size = MIN(NOTIFICATION_DATA_LEN, notification_size); + } + } + + bs_trace_raw(0, "Notification data size : %d\n", notification_size); +} + +static const struct bst_test_instance test_def[] = { + { + .test_id = "peripheral", + .test_descr = "Peripheral Connection Stress", + .test_args_f = test_args, + .test_post_init_f = test_init, + .test_main_f = test_peripheral_main + }, + BSTEST_END_MARKER +}; + +struct bst_test_list *test_main_conn_stress_install(struct bst_test_list *tests) +{ + return bst_add_tests(tests, test_def); +} + +extern struct bst_test_list *test_main_conn_stress_install(struct bst_test_list *tests); + +bst_test_install_t test_installers[] = { + test_main_conn_stress_install, + NULL +}; + +int main(void) +{ + bst_main(); + + return 0; +} 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 00000000000..94228bdc986 --- /dev/null +++ b/tests/bsim/bluetooth/host/misc/conn_stress/scripts/_conn_stress.sh @@ -0,0 +1,81 @@ +#!/usr/bin/env bash +# Copyright (c) 2023 Nordic Semiconductor +# SPDX-License-Identifier: Apache-2.0 + +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 $@" +} + +: "${BSIM_OUT_PATH:?BSIM_OUT_PATH must be defined}" + +#Give a default value to BOARD if it does not have one yet: +BOARD="${BOARD:-nrf52_bsim}" + +test_path="bsim_bluetooth_host_misc_conn_stress" +bsim_central_exe_name="bs_nrf52_${test_path}_central_prj_conf" +bsim_peripheral_exe_name="bs_nrf52_${test_path}_peripheral_prj_conf" + +# terminate running simulations (if any) +${BSIM_COMPONENTS_PATH}/common/stop_bsim.sh + +# (re)Build the central & peripheral images. Don't continue if build fails. +west build -b ${BOARD} -d build_central central && \ + cp build_central/zephyr/zephyr.exe \ + "${BSIM_OUT_PATH}/bin/${bsim_central_exe_name}" \ + || exit + +west build -b ${BOARD} -d build_peripheral peripheral && \ + cp build_peripheral/zephyr/zephyr.exe \ + "${BSIM_OUT_PATH}/bin/${bsim_peripheral_exe_name}" \ + || exit + +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 From 3af390f6edfffc90ba024cde1475bf489285c109 Mon Sep 17 00:00:00 2001 From: Daniel Leung Date: Thu, 7 Dec 2023 15:54:31 -0800 Subject: [PATCH 1150/3723] xtensa: doxygen: add groups for public and internal APIs This adds two groups for Xtensa public and internal APIs. Signed-off-by: Daniel Leung --- include/zephyr/arch/xtensa/arch.h | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/include/zephyr/arch/xtensa/arch.h b/include/zephyr/arch/xtensa/arch.h index b8971af41e8..4601a675949 100644 --- a/include/zephyr/arch/xtensa/arch.h +++ b/include/zephyr/arch/xtensa/arch.h @@ -35,6 +35,17 @@ #include +/** + * @defgroup xtensa_apis Xtensa APIs + * @{ + * @} + * + * @defgroup xtensa_internal_apis Xtensa Internal APIs + * @ingroup xtensa_apis + * @{ + * @} + */ + /* Xtensa GPRs are often designated by two different names */ #define sys_define_gpr_with_alias(name1, name2) union { uint32_t name1, name2; } From d17524b86cba54266c57ee513232ec045928f7b1 Mon Sep 17 00:00:00 2001 From: Daniel Leung Date: Wed, 6 Dec 2023 11:34:05 -0800 Subject: [PATCH 1151/3723] xtensa: remove CONFIG_SYS_CLOCK_HW_CYCLES_PER_SEC from arch CONFIG_SYS_CLOCK_HW_CYCLES_PER_SEC should be defined at the SoC or the board level since Xtensa cores are high configurable. The default is just for ISS (Instruction Set Simulator). So remove it from the arch level. The xt-sim board is the only one in tree that is targeting the ISS, so add it there. Signed-off-by: Daniel Leung --- arch/xtensa/Kconfig | 7 ------- boards/xtensa/xt-sim/xt-sim_defconfig | 2 ++ doc/releases/migration-guide-3.6.rst | 6 ++++++ 3 files changed, 8 insertions(+), 7 deletions(-) diff --git a/arch/xtensa/Kconfig b/arch/xtensa/Kconfig index c2c2e6cc8b0..bff533f962c 100644 --- a/arch/xtensa/Kconfig +++ b/arch/xtensa/Kconfig @@ -14,13 +14,6 @@ config SIMULATOR_XTENSA help Specify if the board configuration should be treated as a simulator. -config SYS_CLOCK_HW_CYCLES_PER_SEC - prompt "Hardware clock cycles per second, 2000000 for ISS" - default 2000000 - range 1000000 1000000000 - help - This option specifies hardware clock. - config XTENSA_NO_IPC bool "Core has no IPC support" select ATOMIC_OPERATIONS_C diff --git a/boards/xtensa/xt-sim/xt-sim_defconfig b/boards/xtensa/xt-sim/xt-sim_defconfig index ae3d7a6cd91..73700f07275 100644 --- a/boards/xtensa/xt-sim/xt-sim_defconfig +++ b/boards/xtensa/xt-sim/xt-sim_defconfig @@ -8,3 +8,5 @@ CONFIG_CONSOLE=y CONFIG_GEN_ISR_TABLES=y CONFIG_GEN_IRQ_VECTOR_TABLE=n CONFIG_SIMULATOR_XTENSA=y + +CONFIG_SYS_CLOCK_HW_CYCLES_PER_SEC=2000000 diff --git a/doc/releases/migration-guide-3.6.rst b/doc/releases/migration-guide-3.6.rst index c944a2ae4c6..c72c71b00b9 100644 --- a/doc/releases/migration-guide-3.6.rst +++ b/doc/releases/migration-guide-3.6.rst @@ -259,6 +259,12 @@ Other Subsystems zbus options are renamed. Instead, the new :kconfig:option:`ZBUS_MSG_SUBSCRIBER_BUF_ALLOC_DYNAMIC` and :kconfig:option:`ZBUS_MSG_SUBSCRIBER_BUF_ALLOC_STATIC` options should be used. +Xtensa +====== + +* :kconfig:option:`CONFIG_SYS_CLOCK_HW_CYCLES_PER_SEC` no longer has a default in + the architecture layer. Instead, SoCs or boards will need to define it. + Recommended Changes ******************* From fc7ef47ed5926e33f802d43ee1a908f30d1945f1 Mon Sep 17 00:00:00 2001 From: Daniel Leung Date: Wed, 6 Dec 2023 12:17:51 -0800 Subject: [PATCH 1152/3723] xtensa: remove CONFIG_XTENSA_NO_IPC There is no in-tree user. Also, it is misleading as we use SCOMPARE1 for spinlock too, not just IPC. Signed-off-by: Daniel Leung --- arch/xtensa/Kconfig | 7 ------- doc/releases/release-notes-3.6.rst | 2 ++ 2 files changed, 2 insertions(+), 7 deletions(-) diff --git a/arch/xtensa/Kconfig b/arch/xtensa/Kconfig index bff533f962c..76a2984cb30 100644 --- a/arch/xtensa/Kconfig +++ b/arch/xtensa/Kconfig @@ -14,13 +14,6 @@ config SIMULATOR_XTENSA help Specify if the board configuration should be treated as a simulator. -config XTENSA_NO_IPC - bool "Core has no IPC support" - select ATOMIC_OPERATIONS_C - help - Uncheck this if your core does not implement "SCOMPARE1" register and "s32c1i" - instruction. - config XTENSA_RESET_VECTOR bool "Build reset vector code" default y diff --git a/doc/releases/release-notes-3.6.rst b/doc/releases/release-notes-3.6.rst index ec032548a9b..ca442cad3e0 100644 --- a/doc/releases/release-notes-3.6.rst +++ b/doc/releases/release-notes-3.6.rst @@ -37,6 +37,8 @@ Architectures * Xtensa + * Removed the unused Kconfig option ``CONFIG_XTENSA_NO_IPC``. + * x86 * POSIX From 6694390ac8577cc35f29469ebec07874437cfc75 Mon Sep 17 00:00:00 2001 From: Daniel Leung Date: Wed, 6 Dec 2023 11:33:11 -0800 Subject: [PATCH 1153/3723] xtensa: cleanup Kconfig file * Wording on CONFIG_SIMULATOR_XTENSA * Remove "default n" as default is no anyway. * Remove some tabs as we almost never indent inside a if block in Zephyr. Signed-off-by: Daniel Leung --- arch/xtensa/Kconfig | 96 ++++++++++++++++++++++----------------------- 1 file changed, 47 insertions(+), 49 deletions(-) diff --git a/arch/xtensa/Kconfig b/arch/xtensa/Kconfig index 76a2984cb30..4f7643b0cff 100644 --- a/arch/xtensa/Kconfig +++ b/arch/xtensa/Kconfig @@ -10,9 +10,9 @@ config ARCH default "xtensa" config SIMULATOR_XTENSA - bool "Simulator Configuration" + bool "Simulator Target" help - Specify if the board configuration should be treated as a simulator. + Enable if building to run on simulator. config XTENSA_RESET_VECTOR bool "Build reset vector code" @@ -97,7 +97,6 @@ if CPU_HAS_MMU config XTENSA_MMU bool "Xtensa MMU Support" - default n select MMU select ARCH_MEM_DOMAIN_SYNCHRONOUS_API if USERSPACE select XTENSA_SMALL_VECTOR_TABLE_ENTRY @@ -108,52 +107,51 @@ config XTENSA_MMU if XTENSA_MMU - choice - prompt "PageTable virtual adddress" - default XTENSA_MMU_PTEVADDR_20000000 - help - The virtual address for Xtensa page table (PTEVADDR). - - config XTENSA_MMU_PTEVADDR_20000000 - bool "0x20000000" - - endchoice - - config XTENSA_MMU_PTEVADDR - hex - default 0x20000000 if XTENSA_MMU_PTEVADDR_20000000 - help - The virtual address for Xtensa page table (PTEVADDR). - - config XTENSA_MMU_PTEVADDR_SHIFT - int - default 29 if XTENSA_MMU_PTEVADDR_20000000 - help - The bit shift number for the virtual address for Xtensa - page table (PTEVADDR). - - config XTENSA_MMU_NUM_L1_TABLES - int "Number of L1 page tables" - default 1 if !USERSPACE - default 4 - help - This option specifies the maximum number of traslation tables. - Translation tables are directly related to the number of - memory domains in the target, considering the kernel itself requires one. - - config XTENSA_MMU_NUM_L2_TABLES - int "Number of L2 page tables" - default 20 if USERSPACE - default 10 - help - Each table can address up to 4MB memory address. - - config XTENSA_MMU_DOUBLE_MAP - bool "Map memory in cached and uncached region" - default n - help - This option specifies that the memory is mapped in two - distinct region, cached and uncached. +choice + prompt "PageTable virtual address" + default XTENSA_MMU_PTEVADDR_20000000 + help + The virtual address for Xtensa page table (PTEVADDR). + +config XTENSA_MMU_PTEVADDR_20000000 + bool "0x20000000" + +endchoice + +config XTENSA_MMU_PTEVADDR + hex + default 0x20000000 if XTENSA_MMU_PTEVADDR_20000000 + help + The virtual address for Xtensa page table (PTEVADDR). + +config XTENSA_MMU_PTEVADDR_SHIFT + int + default 29 if XTENSA_MMU_PTEVADDR_20000000 + help + The bit shift number for the virtual address for Xtensa + page table (PTEVADDR). + +config XTENSA_MMU_NUM_L1_TABLES + int "Number of L1 page tables" + default 1 if !USERSPACE + default 4 + help + This option specifies the maximum number of traslation tables. + Translation tables are directly related to the number of + memory domains in the target, considering the kernel itself requires one. + +config XTENSA_MMU_NUM_L2_TABLES + int "Number of L2 page tables" + default 20 if USERSPACE + default 10 + help + Each table can address up to 4MB memory address. + +config XTENSA_MMU_DOUBLE_MAP + bool "Map memory in cached and uncached region" + help + This option specifies that the memory is mapped in two + distinct region, cached and uncached. endif # XTENSA_MMU From 43990d1c0e4563df39848a8f5e117d4ec6a551eb Mon Sep 17 00:00:00 2001 From: Daniel Leung Date: Wed, 6 Dec 2023 12:31:00 -0800 Subject: [PATCH 1154/3723] xtensa: remove xtensa-asm2.h xtensa-asm2.h only contains the function declaration of xtensa_init_stack() which is only used in one file. So make the actual implementation a static function in that file. Also there is really no need to expose stack init function as arch public API. So remove xtensa-asm2.h. Signed-off-by: Daniel Leung --- arch/xtensa/core/coredump.c | 2 +- arch/xtensa/core/xtensa-asm2.c | 17 ++++++++++++----- arch/xtensa/include/xtensa-asm2.h | 24 ------------------------ 3 files changed, 13 insertions(+), 30 deletions(-) delete mode 100644 arch/xtensa/include/xtensa-asm2.h diff --git a/arch/xtensa/core/coredump.c b/arch/xtensa/core/coredump.c index 26060dea8c3..d0a17eaa5a1 100644 --- a/arch/xtensa/core/coredump.c +++ b/arch/xtensa/core/coredump.c @@ -6,7 +6,7 @@ #include #include -#include +#include #include #define ARCH_HDR_VER 1 diff --git a/arch/xtensa/core/xtensa-asm2.c b/arch/xtensa/core/xtensa-asm2.c index 88783c178c6..288dfb8175f 100644 --- a/arch/xtensa/core/xtensa-asm2.c +++ b/arch/xtensa/core/xtensa-asm2.c @@ -4,7 +4,7 @@ * SPDX-License-Identifier: Apache-2.0 */ #include -#include +#include #include #include #include @@ -38,7 +38,15 @@ __thread uint32_t is_user_mode; #endif /* CONFIG_USERSPACE */ -void *xtensa_init_stack(struct k_thread *thread, int *stack_top, +/** + * Initializes a stack area such that it can be "restored" later and + * begin running with the specified function and three arguments. The + * entry function takes three arguments to match the signature of + * Zephyr's k_thread_entry_t. Thread will start with EXCM clear and + * INTLEVEL set to zero (i.e. it's a user thread, we don't start with + * anything masked, so don't assume that!). + */ +static void *init_stack(struct k_thread *thread, int *stack_top, void (*entry)(void *, void *, void *), void *arg1, void *arg2, void *arg3) { @@ -120,9 +128,8 @@ void arch_new_thread(struct k_thread *thread, k_thread_stack_t *stack, char *stack_ptr, k_thread_entry_t entry, void *p1, void *p2, void *p3) { - thread->switch_handle = xtensa_init_stack(thread, - (int *)stack_ptr, entry, - p1, p2, p3); + thread->switch_handle = init_stack(thread, (int *)stack_ptr, entry, + p1, p2, p3); #ifdef CONFIG_KERNEL_COHERENCE __ASSERT((((size_t)stack) % XCHAL_DCACHE_LINESIZE) == 0, ""); __ASSERT((((size_t)stack_ptr) % XCHAL_DCACHE_LINESIZE) == 0, ""); diff --git a/arch/xtensa/include/xtensa-asm2.h b/arch/xtensa/include/xtensa-asm2.h deleted file mode 100644 index 25fbb2980ab..00000000000 --- a/arch/xtensa/include/xtensa-asm2.h +++ /dev/null @@ -1,24 +0,0 @@ -/* - * Copyright (c) 2017, Intel Corporation - * - * SPDX-License-Identifier: Apache-2.0 - */ -#ifndef ZEPHYR_ARCH_XTENSA_INCLUDE_XTENSA_ASM2_H_ -#define ZEPHYR_ARCH_XTENSA_INCLUDE_XTENSA_ASM2_H_ - -#include -#include "xtensa-asm2-context.h" - -/** - * Initializes a stack area such that it can be "restored" later and - * begin running with the specified function and three arguments. The - * entry function takes three arguments to match the signature of - * Zephyr's k_thread_entry_t. Thread will start with EXCM clear and - * INTLEVEL set to zero (i.e. it's a user thread, we don't start with - * anything masked, so don't assume that!). - */ -void *xtensa_init_stack(struct k_thread *thread, int *stack_top, - void (*entry)(void *, void *, void *), - void *arg1, void *arg2, void *arg3); - -#endif /* ZEPHYR_ARCH_XTENSA_INCLUDE_XTENSA_ASM2_H_ */ From 106061b307d4f39780b7ac7765b03610235899ac Mon Sep 17 00:00:00 2001 From: Daniel Leung Date: Wed, 6 Dec 2023 13:42:05 -0800 Subject: [PATCH 1155/3723] xtensa: rename files with hyphens to underscores Simply to provide some consistencies on file naming under arch/xtensa. These are all internally used files and are not public. So there is no need to provide a deprecation path for them. Signed-off-by: Daniel Leung --- arch/xtensa/core/CMakeLists.txt | 4 ++-- arch/xtensa/core/{README-MMU.txt => README_MMU.txt} | 0 arch/xtensa/core/{README-WINDOWS.rst => README_WINDOWS.rst} | 0 arch/xtensa/core/coredump.c | 2 +- arch/xtensa/core/debug_helpers_asm.S | 2 +- arch/xtensa/core/gdbstub.c | 2 +- arch/xtensa/core/offsets/offsets.c | 2 +- arch/xtensa/core/startup/CMakeLists.txt | 4 ++-- .../core/startup/{memerror-vector.S => memerror_vector.S} | 0 arch/xtensa/core/startup/{reset-vector.S => reset_vector.S} | 0 arch/xtensa/core/userspace.S | 2 +- arch/xtensa/core/{xtensa-asm2.c => xtensa_asm2.c} | 2 +- arch/xtensa/core/{xtensa-asm2-util.S => xtensa_asm2_util.S} | 2 +- .../{xtensa-asm2-context.h => xtensa_asm2_context.h} | 0 arch/xtensa/include/{xtensa-asm2-s.h => xtensa_asm2_s.h} | 2 +- soc/xtensa/dc233c/include/xtensa-dc233c.ld | 6 +++--- soc/xtensa/espressif_esp32/esp32/gdbstub.c | 2 +- 17 files changed, 16 insertions(+), 16 deletions(-) rename arch/xtensa/core/{README-MMU.txt => README_MMU.txt} (100%) rename arch/xtensa/core/{README-WINDOWS.rst => README_WINDOWS.rst} (100%) rename arch/xtensa/core/startup/{memerror-vector.S => memerror_vector.S} (100%) rename arch/xtensa/core/startup/{reset-vector.S => reset_vector.S} (100%) rename arch/xtensa/core/{xtensa-asm2.c => xtensa_asm2.c} (99%) rename arch/xtensa/core/{xtensa-asm2-util.S => xtensa_asm2_util.S} (99%) rename arch/xtensa/include/{xtensa-asm2-context.h => xtensa_asm2_context.h} (100%) rename arch/xtensa/include/{xtensa-asm2-s.h => xtensa_asm2_s.h} (99%) diff --git a/arch/xtensa/core/CMakeLists.txt b/arch/xtensa/core/CMakeLists.txt index b415aec2e9c..5ec158871dd 100644 --- a/arch/xtensa/core/CMakeLists.txt +++ b/arch/xtensa/core/CMakeLists.txt @@ -8,8 +8,8 @@ zephyr_library_sources( cpu_idle.c fatal.c window_vectors.S - xtensa-asm2-util.S - xtensa-asm2.c + xtensa_asm2_util.S + xtensa_asm2.c irq_manage.c ) diff --git a/arch/xtensa/core/README-MMU.txt b/arch/xtensa/core/README_MMU.txt similarity index 100% rename from arch/xtensa/core/README-MMU.txt rename to arch/xtensa/core/README_MMU.txt diff --git a/arch/xtensa/core/README-WINDOWS.rst b/arch/xtensa/core/README_WINDOWS.rst similarity index 100% rename from arch/xtensa/core/README-WINDOWS.rst rename to arch/xtensa/core/README_WINDOWS.rst diff --git a/arch/xtensa/core/coredump.c b/arch/xtensa/core/coredump.c index d0a17eaa5a1..a2eec620774 100644 --- a/arch/xtensa/core/coredump.c +++ b/arch/xtensa/core/coredump.c @@ -6,7 +6,7 @@ #include #include -#include +#include #include #define ARCH_HDR_VER 1 diff --git a/arch/xtensa/core/debug_helpers_asm.S b/arch/xtensa/core/debug_helpers_asm.S index 8d895ba39dd..ea4df50daeb 100644 --- a/arch/xtensa/core/debug_helpers_asm.S +++ b/arch/xtensa/core/debug_helpers_asm.S @@ -8,7 +8,7 @@ #include #include #include -#include +#include #include diff --git a/arch/xtensa/core/gdbstub.c b/arch/xtensa/core/gdbstub.c index 034b3532866..f3214250f7b 100644 --- a/arch/xtensa/core/gdbstub.c +++ b/arch/xtensa/core/gdbstub.c @@ -9,7 +9,7 @@ #include #include -#include +#include #include static bool not_first_break; diff --git a/arch/xtensa/core/offsets/offsets.c b/arch/xtensa/core/offsets/offsets.c index 8d4022fd81e..8fca6962d3d 100644 --- a/arch/xtensa/core/offsets/offsets.c +++ b/arch/xtensa/core/offsets/offsets.c @@ -7,7 +7,7 @@ #include #include -#include +#include GEN_ABSOLUTE_SYM(___xtensa_irq_bsa_t_SIZEOF, sizeof(_xtensa_irq_bsa_t)); GEN_ABSOLUTE_SYM(___xtensa_irq_stack_frame_raw_t_SIZEOF, sizeof(_xtensa_irq_stack_frame_raw_t)); diff --git a/arch/xtensa/core/startup/CMakeLists.txt b/arch/xtensa/core/startup/CMakeLists.txt index de30172ced2..fc17c5cd990 100644 --- a/arch/xtensa/core/startup/CMakeLists.txt +++ b/arch/xtensa/core/startup/CMakeLists.txt @@ -10,8 +10,8 @@ if(CONFIG_XTENSA_RESET_VECTOR) ) zephyr_library_sources( - memerror-vector.S + memerror_vector.S memctl_default.S - reset-vector.S + reset_vector.S ) endif() diff --git a/arch/xtensa/core/startup/memerror-vector.S b/arch/xtensa/core/startup/memerror_vector.S similarity index 100% rename from arch/xtensa/core/startup/memerror-vector.S rename to arch/xtensa/core/startup/memerror_vector.S diff --git a/arch/xtensa/core/startup/reset-vector.S b/arch/xtensa/core/startup/reset_vector.S similarity index 100% rename from arch/xtensa/core/startup/reset-vector.S rename to arch/xtensa/core/startup/reset_vector.S diff --git a/arch/xtensa/core/userspace.S b/arch/xtensa/core/userspace.S index 1a000d75d57..eff55dec46b 100644 --- a/arch/xtensa/core/userspace.S +++ b/arch/xtensa/core/userspace.S @@ -4,7 +4,7 @@ * SPDX-License-Identifier: Apache-2.0 */ -#include +#include #include #include #include diff --git a/arch/xtensa/core/xtensa-asm2.c b/arch/xtensa/core/xtensa_asm2.c similarity index 99% rename from arch/xtensa/core/xtensa-asm2.c rename to arch/xtensa/core/xtensa_asm2.c index 288dfb8175f..d77302b731f 100644 --- a/arch/xtensa/core/xtensa-asm2.c +++ b/arch/xtensa/core/xtensa_asm2.c @@ -4,7 +4,7 @@ * SPDX-License-Identifier: Apache-2.0 */ #include -#include +#include #include #include #include diff --git a/arch/xtensa/core/xtensa-asm2-util.S b/arch/xtensa/core/xtensa_asm2_util.S similarity index 99% rename from arch/xtensa/core/xtensa-asm2-util.S rename to arch/xtensa/core/xtensa_asm2_util.S index 4f8af894ccb..f47f211057d 100644 --- a/arch/xtensa/core/xtensa-asm2-util.S +++ b/arch/xtensa/core/xtensa_asm2_util.S @@ -3,7 +3,7 @@ * * SPDX-License-Identifier: Apache-2.0 */ -#include +#include #include #include diff --git a/arch/xtensa/include/xtensa-asm2-context.h b/arch/xtensa/include/xtensa_asm2_context.h similarity index 100% rename from arch/xtensa/include/xtensa-asm2-context.h rename to arch/xtensa/include/xtensa_asm2_context.h diff --git a/arch/xtensa/include/xtensa-asm2-s.h b/arch/xtensa/include/xtensa_asm2_s.h similarity index 99% rename from arch/xtensa/include/xtensa-asm2-s.h rename to arch/xtensa/include/xtensa_asm2_s.h index 416a83453a2..5cbb1d8247c 100644 --- a/arch/xtensa/include/xtensa-asm2-s.h +++ b/arch/xtensa/include/xtensa_asm2_s.h @@ -8,7 +8,7 @@ #define ZEPHYR_ARCH_XTENSA_INCLUDE_XTENSA_ASM2_S_H #include -#include "xtensa-asm2-context.h" +#include "xtensa_asm2_context.h" #include diff --git a/soc/xtensa/dc233c/include/xtensa-dc233c.ld b/soc/xtensa/dc233c/include/xtensa-dc233c.ld index 9c120e1b9d8..54701b37ee7 100644 --- a/soc/xtensa/dc233c/include/xtensa-dc233c.ld +++ b/soc/xtensa/dc233c/include/xtensa-dc233c.ld @@ -304,14 +304,14 @@ SECTIONS * TLB multi-hit exception. */ - *libarch__xtensa__core.a:xtensa-asm2-util.S.obj(.literal .text) - *libarch__xtensa__core.a:xtensa-asm2-util.S.obj(.iram.text .iram0.text) + *libarch__xtensa__core.a:xtensa_asm2_util.S.obj(.literal .text) + *libarch__xtensa__core.a:xtensa_asm2_util.S.obj(.iram.text .iram0.text) *libarch__xtensa__core.a:window_vectors.S.obj(.iram.text) *libarch__xtensa__core.a:crt1.S.obj(.literal .text) - LIB_OBJ_FUNC_IN_SECT(libarch__xtensa__core.a,xtensa-asm2.c.obj,*) + LIB_OBJ_FUNC_IN_SECT(libarch__xtensa__core.a,xtensa_asm2.c.obj,*) LIB_OBJ_FUNC_IN_SECT(libarch__xtensa__core.a,fatal.c.obj,*) LIB_OBJ_FUNC_IN_SECT(libarch__xtensa__core.a,cpu_idle.c.obj,*) diff --git a/soc/xtensa/espressif_esp32/esp32/gdbstub.c b/soc/xtensa/espressif_esp32/esp32/gdbstub.c index f7962b61851..c8913b7f5a2 100644 --- a/soc/xtensa/espressif_esp32/esp32/gdbstub.c +++ b/soc/xtensa/espressif_esp32/esp32/gdbstub.c @@ -5,7 +5,7 @@ */ #include -#include +#include #include #include From aa64b1f98e36d953d32396203a6159f583f8ceda Mon Sep 17 00:00:00 2001 From: Daniel Leung Date: Fri, 8 Dec 2023 10:09:31 -0800 Subject: [PATCH 1156/3723] xtensa: move arch_spin_relax into smp.c arch_spin_relax() does not really fit into the scheme of xtensa_asm2.c as it is mainly about handling interrupts and exceptions. So move it into smp.c, similar to other architectures which arch_spin_relax() defined. Signed-off-by: Daniel Leung --- arch/xtensa/core/CMakeLists.txt | 1 + arch/xtensa/core/smp.c | 21 +++++++++++++++++++++ arch/xtensa/core/xtensa_asm2.c | 13 ------------- 3 files changed, 22 insertions(+), 13 deletions(-) create mode 100644 arch/xtensa/core/smp.c diff --git a/arch/xtensa/core/CMakeLists.txt b/arch/xtensa/core/CMakeLists.txt index 5ec158871dd..9e85b2fffdc 100644 --- a/arch/xtensa/core/CMakeLists.txt +++ b/arch/xtensa/core/CMakeLists.txt @@ -25,6 +25,7 @@ zephyr_library_sources_ifdef(CONFIG_XTENSA_MMU ptables.c mmu.c) zephyr_library_sources_ifdef(CONFIG_USERSPACE userspace.S) zephyr_library_sources_ifdef(CONFIG_XTENSA_SYSCALL_USE_HELPER syscall_helper.c) zephyr_library_sources_ifdef(CONFIG_LLEXT elf.c) +zephyr_library_sources_ifdef(CONFIG_SMP smp.c) zephyr_library_sources_ifdef( CONFIG_KERNEL_VM_USE_CUSTOM_MEM_RANGE_CHECK diff --git a/arch/xtensa/core/smp.c b/arch/xtensa/core/smp.c new file mode 100644 index 00000000000..ffd08ab805c --- /dev/null +++ b/arch/xtensa/core/smp.c @@ -0,0 +1,21 @@ +/* + * Copyright (c) 2023 Intel Corporation + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include +#include + +#ifdef CONFIG_XTENSA_MORE_SPIN_RELAX_NOPS +/* Some compilers might "optimize out" (i.e. remove) continuous NOPs. + * So force no optimization to avoid that. + */ +__no_optimization +void arch_spin_relax(void) +{ +#define NOP1(_, __) __asm__ volatile("nop.n;"); + LISTIFY(CONFIG_XTENSA_NUM_SPIN_RELAX_NOPS, NOP1, (;)) +#undef NOP1 +} +#endif /* CONFIG_XTENSA_MORE_SPIN_RELAX_NOPS */ diff --git a/arch/xtensa/core/xtensa_asm2.c b/arch/xtensa/core/xtensa_asm2.c index d77302b731f..1b6089820c1 100644 --- a/arch/xtensa/core/xtensa_asm2.c +++ b/arch/xtensa/core/xtensa_asm2.c @@ -529,19 +529,6 @@ int z_xtensa_irq_is_enabled(unsigned int irq) return (ie & (1 << irq)) != 0U; } -#ifdef CONFIG_XTENSA_MORE_SPIN_RELAX_NOPS -/* Some compilers might "optimize out" (i.e. remove) continuous NOPs. - * So force no optimization to avoid that. - */ -__no_optimization -void arch_spin_relax(void) -{ -#define NOP1(_, __) __asm__ volatile("nop.n;"); - LISTIFY(CONFIG_XTENSA_NUM_SPIN_RELAX_NOPS, NOP1, (;)) -#undef NOP1 -} -#endif /* CONFIG_XTENSA_MORE_SPIN_RELAX_NOPS */ - #ifdef CONFIG_USERSPACE FUNC_NORETURN void arch_user_mode_enter(k_thread_entry_t user_entry, void *p1, void *p2, void *p3) From 264391fe8862191d0236ef19b0961d39ec9ea08c Mon Sep 17 00:00:00 2001 From: Daniel Leung Date: Wed, 6 Dec 2023 13:55:06 -0800 Subject: [PATCH 1157/3723] xtensa: refactor thread related stuff into its own file... ... from xtensa_asm2.c. Everything has been stuffed inside xtensa_asm2.c where they are all mangled together. So extract thread related stuff into its own file. Note that arch_float_*() may not be thread related but most other architectures put them into thread.c. So we also do it here. Signed-off-by: Daniel Leung --- arch/xtensa/core/CMakeLists.txt | 1 + arch/xtensa/core/thread.c | 160 ++++++++++++++++++++++++++++++++ arch/xtensa/core/xtensa_asm2.c | 142 ---------------------------- 3 files changed, 161 insertions(+), 142 deletions(-) create mode 100644 arch/xtensa/core/thread.c diff --git a/arch/xtensa/core/CMakeLists.txt b/arch/xtensa/core/CMakeLists.txt index 9e85b2fffdc..0de05a13a25 100644 --- a/arch/xtensa/core/CMakeLists.txt +++ b/arch/xtensa/core/CMakeLists.txt @@ -11,6 +11,7 @@ zephyr_library_sources( xtensa_asm2_util.S xtensa_asm2.c irq_manage.c + thread.c ) zephyr_library_sources_ifdef(CONFIG_XTENSA_USE_CORE_CRT1 crt1.S) diff --git a/arch/xtensa/core/thread.c b/arch/xtensa/core/thread.c new file mode 100644 index 00000000000..53a4126d6ce --- /dev/null +++ b/arch/xtensa/core/thread.c @@ -0,0 +1,160 @@ +/* + * Copyright (c) 2017, 2023 Intel Corporation + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include + +#include +#include + +#include + +#include +LOG_MODULE_DECLARE(os, CONFIG_KERNEL_LOG_LEVEL); + +#ifdef CONFIG_USERSPACE + +#ifdef CONFIG_THREAD_LOCAL_STORAGE +/* + * Per-thread (TLS) variable indicating whether execution is in user mode. + */ +__thread uint32_t is_user_mode; +#endif + +#endif /* CONFIG_USERSPACE */ + +/** + * Initializes a stack area such that it can be "restored" later and + * begin running with the specified function and three arguments. The + * entry function takes three arguments to match the signature of + * Zephyr's k_thread_entry_t. Thread will start with EXCM clear and + * INTLEVEL set to zero (i.e. it's a user thread, we don't start with + * anything masked, so don't assume that!). + */ +static void *init_stack(struct k_thread *thread, int *stack_top, + void (*entry)(void *, void *, void *), + void *arg1, void *arg2, void *arg3) +{ + void *ret; + _xtensa_irq_stack_frame_a11_t *frame; +#ifdef CONFIG_USERSPACE + struct z_xtensa_thread_stack_header *header = + (struct z_xtensa_thread_stack_header *)thread->stack_obj; + + thread->arch.psp = header->privilege_stack + + sizeof(header->privilege_stack); +#endif + + /* Not-a-cpu ID Ensures that the first time this is run, the + * stack will be invalidated. That covers the edge case of + * restarting a thread on a stack that had previously been run + * on one CPU, but then initialized on this one, and + * potentially run THERE and not HERE. + */ + thread->arch.last_cpu = -1; + + /* We cheat and shave 16 bytes off, the top four words are the + * A0-A3 spill area for the caller of the entry function, + * which doesn't exist. It will never be touched, so we + * arrange to enter the function with a CALLINC of 1 and a + * stack pointer 16 bytes above the top, so its ENTRY at the + * start will decrement the stack pointer by 16. + */ + const int bsasz = sizeof(*frame) - 16; + + frame = (void *)(((char *) stack_top) - bsasz); + + (void)memset(frame, 0, bsasz); + + frame->bsa.ps = PS_WOE | PS_UM | PS_CALLINC(1); +#ifdef CONFIG_USERSPACE + if ((thread->base.user_options & K_USER) == K_USER) { + frame->bsa.pc = (uintptr_t)arch_user_mode_enter; + } else { + frame->bsa.pc = (uintptr_t)z_thread_entry; + } +#else + frame->bsa.pc = (uintptr_t)z_thread_entry; +#endif + +#if XCHAL_HAVE_THREADPTR +#ifdef CONFIG_THREAD_LOCAL_STORAGE + frame->bsa.threadptr = thread->tls; +#elif CONFIG_USERSPACE + frame->bsa.threadptr = (uintptr_t)((thread->base.user_options & K_USER) ? thread : NULL); +#endif +#endif + + /* Arguments to z_thread_entry(). Remember these start at A6, + * which will be rotated into A2 by the ENTRY instruction that + * begins the C function. And A4-A7 and A8-A11 are optional + * quads that live below the BSA! + */ + frame->a7 = (uintptr_t)arg1; /* a7 */ + frame->a6 = (uintptr_t)entry; /* a6 */ + frame->a5 = 0; /* a5 */ + frame->a4 = 0; /* a4 */ + + frame->a11 = 0; /* a11 */ + frame->a10 = 0; /* a10 */ + frame->a9 = (uintptr_t)arg3; /* a9 */ + frame->a8 = (uintptr_t)arg2; /* a8 */ + + /* Finally push the BSA pointer and return the stack pointer + * as the handle + */ + frame->ptr_to_bsa = (void *)&frame->bsa; + ret = &frame->ptr_to_bsa; + + return ret; +} + +void arch_new_thread(struct k_thread *thread, k_thread_stack_t *stack, + char *stack_ptr, k_thread_entry_t entry, + void *p1, void *p2, void *p3) +{ + thread->switch_handle = init_stack(thread, (int *)stack_ptr, entry, + p1, p2, p3); +#ifdef CONFIG_KERNEL_COHERENCE + __ASSERT((((size_t)stack) % XCHAL_DCACHE_LINESIZE) == 0, ""); + __ASSERT((((size_t)stack_ptr) % XCHAL_DCACHE_LINESIZE) == 0, ""); + sys_cache_data_flush_and_invd_range(stack, (char *)stack_ptr - (char *)stack); +#endif +} + +#if defined(CONFIG_FPU) && defined(CONFIG_FPU_SHARING) +int arch_float_disable(struct k_thread *thread) +{ + /* xtensa always has FPU enabled so cannot be disabled */ + return -ENOTSUP; +} + +int arch_float_enable(struct k_thread *thread, unsigned int options) +{ + /* xtensa always has FPU enabled so nothing to do here */ + return 0; +} +#endif /* CONFIG_FPU && CONFIG_FPU_SHARING */ + +#ifdef CONFIG_USERSPACE +FUNC_NORETURN void arch_user_mode_enter(k_thread_entry_t user_entry, + void *p1, void *p2, void *p3) +{ + struct k_thread *current = _current; + size_t stack_end; + + /* Transition will reset stack pointer to initial, discarding + * any old context since this is a one-way operation + */ + stack_end = Z_STACK_PTR_ALIGN(current->stack_info.start + + current->stack_info.size - + current->stack_info.delta); + + z_xtensa_userspace_enter(user_entry, p1, p2, p3, + stack_end, current->stack_info.start); + + CODE_UNREACHABLE; +} +#endif /* CONFIG_USERSPACE */ diff --git a/arch/xtensa/core/xtensa_asm2.c b/arch/xtensa/core/xtensa_asm2.c index 1b6089820c1..0b2eb3117ec 100644 --- a/arch/xtensa/core/xtensa_asm2.c +++ b/arch/xtensa/core/xtensa_asm2.c @@ -28,115 +28,8 @@ Z_EXC_DECLARE(z_xtensa_user_string_nlen); static const struct z_exc_handle exceptions[] = { Z_EXC_HANDLE(z_xtensa_user_string_nlen) }; - -#ifdef CONFIG_THREAD_LOCAL_STORAGE -/* - * Per-thread (TLS) variable indicating whether execution is in user mode. - */ -__thread uint32_t is_user_mode; -#endif - #endif /* CONFIG_USERSPACE */ -/** - * Initializes a stack area such that it can be "restored" later and - * begin running with the specified function and three arguments. The - * entry function takes three arguments to match the signature of - * Zephyr's k_thread_entry_t. Thread will start with EXCM clear and - * INTLEVEL set to zero (i.e. it's a user thread, we don't start with - * anything masked, so don't assume that!). - */ -static void *init_stack(struct k_thread *thread, int *stack_top, - void (*entry)(void *, void *, void *), - void *arg1, void *arg2, void *arg3) -{ - void *ret; - _xtensa_irq_stack_frame_a11_t *frame; -#ifdef CONFIG_USERSPACE - struct z_xtensa_thread_stack_header *header = - (struct z_xtensa_thread_stack_header *)thread->stack_obj; - - thread->arch.psp = header->privilege_stack + - sizeof(header->privilege_stack); -#endif - - /* Not-a-cpu ID Ensures that the first time this is run, the - * stack will be invalidated. That covers the edge case of - * restarting a thread on a stack that had previously been run - * on one CPU, but then initialized on this one, and - * potentially run THERE and not HERE. - */ - thread->arch.last_cpu = -1; - - /* We cheat and shave 16 bytes off, the top four words are the - * A0-A3 spill area for the caller of the entry function, - * which doesn't exist. It will never be touched, so we - * arrange to enter the function with a CALLINC of 1 and a - * stack pointer 16 bytes above the top, so its ENTRY at the - * start will decrement the stack pointer by 16. - */ - const int bsasz = sizeof(*frame) - 16; - - frame = (void *)(((char *) stack_top) - bsasz); - - (void)memset(frame, 0, bsasz); - - frame->bsa.ps = PS_WOE | PS_UM | PS_CALLINC(1); -#ifdef CONFIG_USERSPACE - if ((thread->base.user_options & K_USER) == K_USER) { - frame->bsa.pc = (uintptr_t)arch_user_mode_enter; - } else { - frame->bsa.pc = (uintptr_t)z_thread_entry; - } -#else - frame->bsa.pc = (uintptr_t)z_thread_entry; -#endif - -#if XCHAL_HAVE_THREADPTR -#ifdef CONFIG_THREAD_LOCAL_STORAGE - frame->bsa.threadptr = thread->tls; -#elif CONFIG_USERSPACE - frame->bsa.threadptr = (uintptr_t)((thread->base.user_options & K_USER) ? thread : NULL); -#endif -#endif - - /* Arguments to z_thread_entry(). Remember these start at A6, - * which will be rotated into A2 by the ENTRY instruction that - * begins the C function. And A4-A7 and A8-A11 are optional - * quads that live below the BSA! - */ - frame->a7 = (uintptr_t)arg1; /* a7 */ - frame->a6 = (uintptr_t)entry; /* a6 */ - frame->a5 = 0; /* a5 */ - frame->a4 = 0; /* a4 */ - - frame->a11 = 0; /* a11 */ - frame->a10 = 0; /* a10 */ - frame->a9 = (uintptr_t)arg3; /* a9 */ - frame->a8 = (uintptr_t)arg2; /* a8 */ - - /* Finally push the BSA pointer and return the stack pointer - * as the handle - */ - frame->ptr_to_bsa = (void *)&frame->bsa; - ret = &frame->ptr_to_bsa; - - return ret; -} - -void arch_new_thread(struct k_thread *thread, k_thread_stack_t *stack, - char *stack_ptr, k_thread_entry_t entry, - void *p1, void *p2, void *p3) -{ - thread->switch_handle = init_stack(thread, (int *)stack_ptr, entry, - p1, p2, p3); -#ifdef CONFIG_KERNEL_COHERENCE - __ASSERT((((size_t)stack) % XCHAL_DCACHE_LINESIZE) == 0, ""); - __ASSERT((((size_t)stack_ptr) % XCHAL_DCACHE_LINESIZE) == 0, ""); - sys_cache_data_flush_and_invd_range(stack, (char *)stack_ptr - (char *)stack); -#endif -} - void z_irq_spurious(const void *arg) { int irqs, ie; @@ -277,20 +170,6 @@ static inline void *return_to(void *interrupted) return z_arch_get_next_switch_handle(interrupted); } -#if defined(CONFIG_FPU) && defined(CONFIG_FPU_SHARING) -int arch_float_disable(struct k_thread *thread) -{ - /* xtensa always has FPU enabled so cannot be disabled */ - return -ENOTSUP; -} - -int arch_float_enable(struct k_thread *thread, unsigned int options) -{ - /* xtensa always has FPU enabled so nothing to do here */ - return 0; -} -#endif /* CONFIG_FPU && CONFIG_FPU_SHARING */ - /* The wrapper code lives here instead of in the python script that * generates _xtensa_handle_one_int*(). Seems cleaner, still kind of * ugly. @@ -528,24 +407,3 @@ int z_xtensa_irq_is_enabled(unsigned int irq) return (ie & (1 << irq)) != 0U; } - -#ifdef CONFIG_USERSPACE -FUNC_NORETURN void arch_user_mode_enter(k_thread_entry_t user_entry, - void *p1, void *p2, void *p3) -{ - struct k_thread *current = _current; - size_t stack_end; - - /* Transition will reset stack pointer to initial, discarding - * any old context since this is a one-way operation - */ - stack_end = Z_STACK_PTR_ALIGN(current->stack_info.start + - current->stack_info.size - - current->stack_info.delta); - - z_xtensa_userspace_enter(user_entry, p1, p2, p3, - stack_end, current->stack_info.start); - - CODE_UNREACHABLE; -} -#endif /* CONFIG_USERSPACE */ From d9b34c61089f3b8e10ec90074750f1c77cb79e8d Mon Sep 17 00:00:00 2001 From: Daniel Leung Date: Wed, 6 Dec 2023 15:01:22 -0800 Subject: [PATCH 1158/3723] xtensa: move irq management stuff into irq_manage.c... ... from xtensa_asm2.c. Other architectures have z_irq_spurious() and *_irq_is_enabled() test in irq_manage.c. So follow the trend here. Signed-off-by: Daniel Leung --- arch/xtensa/core/irq_manage.c | 27 +++++++++++++++++++++++++++ arch/xtensa/core/xtensa_asm2.c | 22 ---------------------- 2 files changed, 27 insertions(+), 22 deletions(-) diff --git a/arch/xtensa/core/irq_manage.c b/arch/xtensa/core/irq_manage.c index 1c592734084..32dfc583dc9 100644 --- a/arch/xtensa/core/irq_manage.c +++ b/arch/xtensa/core/irq_manage.c @@ -8,6 +8,11 @@ #include #include +#include + +#include +LOG_MODULE_DECLARE(os, CONFIG_KERNEL_LOG_LEVEL); + /** * @internal * @@ -56,3 +61,25 @@ int z_arch_irq_connect_dynamic(unsigned int irq, unsigned int priority, } #endif /* !CONFIG_MULTI_LEVEL_INTERRUPTS */ #endif /* CONFIG_DYNAMIC_INTERRUPTS */ + +void z_irq_spurious(const void *arg) +{ + int irqs, ie; + + ARG_UNUSED(arg); + + __asm__ volatile("rsr.interrupt %0" : "=r"(irqs)); + __asm__ volatile("rsr.intenable %0" : "=r"(ie)); + LOG_ERR(" ** Spurious INTERRUPT(s) %p, INTENABLE = %p", + (void *)irqs, (void *)ie); + z_xtensa_fatal_error(K_ERR_SPURIOUS_IRQ, NULL); +} + +int z_xtensa_irq_is_enabled(unsigned int irq) +{ + uint32_t ie; + + __asm__ volatile("rsr.intenable %0" : "=r"(ie)); + + return (ie & (1 << irq)) != 0U; +} diff --git a/arch/xtensa/core/xtensa_asm2.c b/arch/xtensa/core/xtensa_asm2.c index 0b2eb3117ec..99b05d8e203 100644 --- a/arch/xtensa/core/xtensa_asm2.c +++ b/arch/xtensa/core/xtensa_asm2.c @@ -30,19 +30,6 @@ static const struct z_exc_handle exceptions[] = { }; #endif /* CONFIG_USERSPACE */ -void z_irq_spurious(const void *arg) -{ - int irqs, ie; - - ARG_UNUSED(arg); - - __asm__ volatile("rsr.interrupt %0" : "=r"(irqs)); - __asm__ volatile("rsr.intenable %0" : "=r"(ie)); - LOG_ERR(" ** Spurious INTERRUPT(s) %p, INTENABLE = %p", - (void *)irqs, (void *)ie); - z_xtensa_fatal_error(K_ERR_SPURIOUS_IRQ, NULL); -} - void z_xtensa_dump_stack(const z_arch_esf_t *stack) { _xtensa_irq_stack_frame_raw_t *frame = (void *)stack; @@ -398,12 +385,3 @@ void *xtensa_debugint_c(int *interrupted_stack) return return_to(interrupted_stack); } #endif - -int z_xtensa_irq_is_enabled(unsigned int irq) -{ - uint32_t ie; - - __asm__ volatile("rsr.intenable %0" : "=r"(ie)); - - return (ie & (1 << irq)) != 0U; -} From 43b0b48de7ab4c14ba64063e6097c76a76358440 Mon Sep 17 00:00:00 2001 From: Daniel Leung Date: Wed, 6 Dec 2023 15:09:23 -0800 Subject: [PATCH 1159/3723] xtensa: move files under core/include/ into include/ Header files under arch/xtensa/include are considered internal to architecture. There is really no need for two places to house architecture internal header files. Signed-off-by: Daniel Leung --- arch/xtensa/core/CMakeLists.txt | 2 -- arch/xtensa/{core => }/include/xtensa_backtrace.h | 0 arch/xtensa/{core => }/include/xtensa_mmu_priv.h | 0 soc/xtensa/dc233c/mmu.c | 2 +- 4 files changed, 1 insertion(+), 3 deletions(-) rename arch/xtensa/{core => }/include/xtensa_backtrace.h (100%) rename arch/xtensa/{core => }/include/xtensa_mmu_priv.h (100%) diff --git a/arch/xtensa/core/CMakeLists.txt b/arch/xtensa/core/CMakeLists.txt index 0de05a13a25..ed430f2d0c4 100644 --- a/arch/xtensa/core/CMakeLists.txt +++ b/arch/xtensa/core/CMakeLists.txt @@ -37,8 +37,6 @@ if("${ZEPHYR_TOOLCHAIN_VARIANT}" STREQUAL "xcc") zephyr_library_sources(xcc_stubs.c) endif() -zephyr_library_include_directories(include) - add_subdirectory(startup) # This produces a preprocessed and regenerated (in the sense of gcc diff --git a/arch/xtensa/core/include/xtensa_backtrace.h b/arch/xtensa/include/xtensa_backtrace.h similarity index 100% rename from arch/xtensa/core/include/xtensa_backtrace.h rename to arch/xtensa/include/xtensa_backtrace.h diff --git a/arch/xtensa/core/include/xtensa_mmu_priv.h b/arch/xtensa/include/xtensa_mmu_priv.h similarity index 100% rename from arch/xtensa/core/include/xtensa_mmu_priv.h rename to arch/xtensa/include/xtensa_mmu_priv.h diff --git a/soc/xtensa/dc233c/mmu.c b/soc/xtensa/dc233c/mmu.c index 8decc952bf2..62c2c4b7f85 100644 --- a/soc/xtensa/dc233c/mmu.c +++ b/soc/xtensa/dc233c/mmu.c @@ -12,7 +12,7 @@ #include #include -#include "../../arch/xtensa/core/include/xtensa_mmu_priv.h" +#include const struct xtensa_mmu_range xtensa_soc_mmu_ranges[] = { { From 86b7210dc76268f1b3375478c9d9bb159d67a948 Mon Sep 17 00:00:00 2001 From: Daniel Leung Date: Fri, 8 Dec 2023 10:32:00 -0800 Subject: [PATCH 1160/3723] soc: xtensa: dc233c: no need to include xtensa_mmu_priv.h It does not use anything inside xtensa_mmu_priv.h so remove the include. Signed-off-by: Daniel Leung --- soc/xtensa/dc233c/mmu.c | 2 -- 1 file changed, 2 deletions(-) diff --git a/soc/xtensa/dc233c/mmu.c b/soc/xtensa/dc233c/mmu.c index 62c2c4b7f85..3486ecc2aa0 100644 --- a/soc/xtensa/dc233c/mmu.c +++ b/soc/xtensa/dc233c/mmu.c @@ -12,8 +12,6 @@ #include #include -#include - const struct xtensa_mmu_range xtensa_soc_mmu_ranges[] = { { .start = (uint32_t)XCHAL_VECBASE_RESET_VADDR, From 004e68ccea644478f296bfcca1ca41c52dc32be4 Mon Sep 17 00:00:00 2001 From: Daniel Leung Date: Wed, 6 Dec 2023 16:22:52 -0800 Subject: [PATCH 1161/3723] xtensa: move exception handling func to arch internal header z_xtensa_dump_stack() and z_xtensa_exccause() are both arch internal functions that should not be exposed in public API. Signed-off-by: Daniel Leung --- arch/xtensa/core/fatal.c | 3 +++ arch/xtensa/core/xtensa_asm2.c | 2 ++ arch/xtensa/include/xtensa_internal.h | 14 ++++++++++++++ include/zephyr/arch/xtensa/exception.h | 3 --- 4 files changed, 19 insertions(+), 3 deletions(-) create mode 100644 arch/xtensa/include/xtensa_internal.h diff --git a/arch/xtensa/core/fatal.c b/arch/xtensa/core/fatal.c index 6e939e243cd..31fea6da02e 100644 --- a/arch/xtensa/core/fatal.c +++ b/arch/xtensa/core/fatal.c @@ -11,6 +11,9 @@ #include #include #include + +#include + #include LOG_MODULE_DECLARE(os, CONFIG_KERNEL_LOG_LEVEL); diff --git a/arch/xtensa/core/xtensa_asm2.c b/arch/xtensa/core/xtensa_asm2.c index 99b05d8e203..88f1acaa734 100644 --- a/arch/xtensa/core/xtensa_asm2.c +++ b/arch/xtensa/core/xtensa_asm2.c @@ -17,6 +17,8 @@ #include #include +#include + LOG_MODULE_DECLARE(os, CONFIG_KERNEL_LOG_LEVEL); extern char xtensa_arch_except_epc[]; diff --git a/arch/xtensa/include/xtensa_internal.h b/arch/xtensa/include/xtensa_internal.h new file mode 100644 index 00000000000..04d9129266a --- /dev/null +++ b/arch/xtensa/include/xtensa_internal.h @@ -0,0 +1,14 @@ +/* + * Copyright (c) 2014 Wind River Systems, Inc. + * Copyright (c) 2016 Cadence Design Systems, Inc. + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#ifndef ZEPHYR_ARCH_XTENSA_INCLUDE_XTENSA_INTERNAL_H_ +#define ZEPHYR_ARCH_XTENSA_INCLUDE_XTENSA_INTERNAL_H_ + +void z_xtensa_dump_stack(const z_arch_esf_t *stack); +char *z_xtensa_exccause(unsigned int cause_code); + +#endif /* ZEPHYR_ARCH_XTENSA_INCLUDE_XTENSA_INTERNAL_H_ */ diff --git a/include/zephyr/arch/xtensa/exception.h b/include/zephyr/arch/xtensa/exception.h index 4d2cb9bda0a..51a5d5aef90 100644 --- a/include/zephyr/arch/xtensa/exception.h +++ b/include/zephyr/arch/xtensa/exception.h @@ -27,9 +27,6 @@ extern "C" { */ typedef int z_arch_esf_t; -void z_xtensa_dump_stack(const z_arch_esf_t *stack); -char *z_xtensa_exccause(unsigned int cause_code); - #endif #ifdef __cplusplus From 711622cbbab1200891692752bf9a9c9e9202271d Mon Sep 17 00:00:00 2001 From: Daniel Leung Date: Thu, 7 Dec 2023 14:48:58 -0800 Subject: [PATCH 1162/3723] xtensa: remove get_sreg macro from fatal.c There is no in-file user. So remove it. Signed-off-by: Daniel Leung --- arch/xtensa/core/fatal.c | 11 ----------- 1 file changed, 11 deletions(-) diff --git a/arch/xtensa/core/fatal.c b/arch/xtensa/core/fatal.c index 31fea6da02e..06eb9ab7fd5 100644 --- a/arch/xtensa/core/fatal.c +++ b/arch/xtensa/core/fatal.c @@ -21,17 +21,6 @@ LOG_MODULE_DECLARE(os, CONFIG_KERNEL_LOG_LEVEL); #include #endif -/* Need to do this as a macro since regnum must be an immediate value */ -#define get_sreg(regnum_p) ({ \ - unsigned int retval; \ - __asm__ volatile( \ - "rsr %[retval], %[regnum]\n\t" \ - : [retval] "=r" (retval) \ - : [regnum] "i" (regnum_p)); \ - retval; \ - }) - - char *z_xtensa_exccause(unsigned int cause_code) { #if defined(CONFIG_PRINTK) || defined(CONFIG_LOG) From 8bf20ee975fe1ed10295dc72970da1b3ad784d60 Mon Sep 17 00:00:00 2001 From: Daniel Leung Date: Thu, 7 Dec 2023 14:54:22 -0800 Subject: [PATCH 1163/3723] xtensa: mmu: rename prefix z_xtensa to xtensa_mmu This follows the idea to remove any z_ prefix. Since MMU has a large number of these, separate out these changes into one commit to ease review effort. Since these are no longer have z_, these need proper doxygen doc. So add them too. Signed-off-by: Daniel Leung --- arch/xtensa/core/mmu.c | 18 +- arch/xtensa/core/ptables.c | 154 ++++---- arch/xtensa/core/xtensa_asm2_util.S | 2 +- arch/xtensa/include/kernel_arch_func.h | 2 +- arch/xtensa/include/xtensa_mmu_priv.h | 328 +++++++++++++----- include/zephyr/arch/xtensa/xtensa_mmu.h | 131 +++++-- soc/xtensa/dc233c/mmu.c | 4 +- tests/kernel/mem_protect/userspace/src/main.c | 2 +- 8 files changed, 432 insertions(+), 209 deletions(-) diff --git a/arch/xtensa/core/mmu.c b/arch/xtensa/core/mmu.c index 5632d05c1ec..45d8619654b 100644 --- a/arch/xtensa/core/mmu.c +++ b/arch/xtensa/core/mmu.c @@ -26,22 +26,22 @@ static void compute_regs(uint32_t user_asid, uint32_t *l1_page, struct tlb_regs __ASSERT_NO_MSG((((uint32_t)l1_page) & 0xfff) == 0); __ASSERT_NO_MSG((user_asid == 0) || ((user_asid > 2) && - (user_asid < Z_XTENSA_MMU_SHARED_ASID))); + (user_asid < XTENSA_MMU_SHARED_ASID))); /* We don't use ring 1, ring 0 ASID must be 1 */ - regs->rasid = (Z_XTENSA_MMU_SHARED_ASID << 24) | + regs->rasid = (XTENSA_MMU_SHARED_ASID << 24) | (user_asid << 16) | 0x000201; /* Derive PTEVADDR from ASID so each domain gets its own PTE area */ regs->ptevaddr = CONFIG_XTENSA_MMU_PTEVADDR + user_asid * 0x400000; /* The ptables code doesn't add the mapping for the l1 page itself */ - l1_page[Z_XTENSA_L1_POS(regs->ptevaddr)] = - (uint32_t)l1_page | Z_XTENSA_PAGE_TABLE_ATTR; + l1_page[XTENSA_MMU_L1_POS(regs->ptevaddr)] = + (uint32_t)l1_page | XTENSA_MMU_PAGE_TABLE_ATTR; regs->ptepin_at = (uint32_t)l1_page; - regs->ptepin_as = Z_XTENSA_PTE_ENTRY_VADDR(regs->ptevaddr, regs->ptevaddr) - | Z_XTENSA_MMU_PTE_WAY; + regs->ptepin_as = XTENSA_MMU_PTE_ENTRY_VADDR(regs->ptevaddr, regs->ptevaddr) + | XTENSA_MMU_PTE_WAY; /* Pin mapping for refilling the vector address into the ITLB * (for handling TLB miss exceptions). Note: this is NOT an @@ -51,11 +51,11 @@ static void compute_regs(uint32_t user_asid, uint32_t *l1_page, struct tlb_regs * hardware doesn't have a 4k pinnable instruction TLB way, * frustratingly. */ - uint32_t vb_pte = l1_page[Z_XTENSA_L1_POS(vecbase)]; + uint32_t vb_pte = l1_page[XTENSA_MMU_L1_POS(vecbase)]; regs->vecpin_at = vb_pte; - regs->vecpin_as = Z_XTENSA_PTE_ENTRY_VADDR(regs->ptevaddr, vecbase) - | Z_XTENSA_MMU_VECBASE_WAY; + regs->vecpin_as = XTENSA_MMU_PTE_ENTRY_VADDR(regs->ptevaddr, vecbase) + | XTENSA_MMU_VECBASE_WAY; } /* Switch to a new page table. There are four items we have to set in diff --git a/arch/xtensa/core/ptables.c b/arch/xtensa/core/ptables.c index 2d26d83944f..a5de406ffd6 100644 --- a/arch/xtensa/core/ptables.c +++ b/arch/xtensa/core/ptables.c @@ -127,9 +127,9 @@ static const struct xtensa_mmu_range mmu_zephyr_ranges[] = { .start = (uint32_t)_image_ram_start, .end = (uint32_t)_image_ram_end, #ifdef CONFIG_XTENSA_RPO_CACHE - .attrs = Z_XTENSA_MMU_W, + .attrs = XTENSA_MMU_PERM_W, #else - .attrs = Z_XTENSA_MMU_W | Z_XTENSA_MMU_CACHED_WB, + .attrs = XTENSA_MMU_PERM_W | XTENSA_MMU_CACHED_WB, #endif .name = "data", }, @@ -139,9 +139,9 @@ static const struct xtensa_mmu_range mmu_zephyr_ranges[] = { .start = (uint32_t)_heap_start, .end = (uint32_t)_heap_end, #ifdef CONFIG_XTENSA_RPO_CACHE - .attrs = Z_XTENSA_MMU_W, + .attrs = XTENSA_MMU_PERM_W, #else - .attrs = Z_XTENSA_MMU_W | Z_XTENSA_MMU_CACHED_WB, + .attrs = XTENSA_MMU_PERM_W | XTENSA_MMU_CACHED_WB, #endif .name = "heap", }, @@ -150,14 +150,14 @@ static const struct xtensa_mmu_range mmu_zephyr_ranges[] = { { .start = (uint32_t)__text_region_start, .end = (uint32_t)__text_region_end, - .attrs = Z_XTENSA_MMU_X | Z_XTENSA_MMU_CACHED_WB | Z_XTENSA_MMU_MAP_SHARED, + .attrs = XTENSA_MMU_PERM_X | XTENSA_MMU_CACHED_WB | XTENSA_MMU_MAP_SHARED, .name = "text", }, /* Mark rodata segment cacheable, read only and non-executable */ { .start = (uint32_t)__rodata_region_start, .end = (uint32_t)__rodata_region_end, - .attrs = Z_XTENSA_MMU_CACHED_WB | Z_XTENSA_MMU_MAP_SHARED, + .attrs = XTENSA_MMU_CACHED_WB | XTENSA_MMU_MAP_SHARED, .name = "rodata", }, }; @@ -180,7 +180,7 @@ static inline uint32_t *thread_page_tables_get(const struct k_thread *thread) */ static inline bool is_pte_illegal(uint32_t pte) { - uint32_t attr = pte & Z_XTENSA_PTE_ATTR_MASK; + uint32_t attr = pte & XTENSA_MMU_PTE_ATTR_MASK; /* * The ISA manual states only 12 and 14 are illegal values. @@ -201,7 +201,7 @@ static void init_page_table(uint32_t *ptable, size_t num_entries) int i; for (i = 0; i < num_entries; i++) { - ptable[i] = Z_XTENSA_MMU_ILLEGAL; + ptable[i] = XTENSA_MMU_PTE_ILLEGAL; } } @@ -224,11 +224,12 @@ static void map_memory_range(const uint32_t start, const uint32_t end, uint32_t page, *table; for (page = start; page < end; page += CONFIG_MMU_PAGE_SIZE) { - uint32_t pte = Z_XTENSA_PTE(page, - shared ? Z_XTENSA_SHARED_RING : Z_XTENSA_KERNEL_RING, - attrs); - uint32_t l2_pos = Z_XTENSA_L2_POS(page); - uint32_t l1_pos = Z_XTENSA_L1_POS(page); + uint32_t pte = XTENSA_MMU_PTE(page, + shared ? XTENSA_MMU_SHARED_RING : + XTENSA_MMU_KERNEL_RING, + attrs); + uint32_t l2_pos = XTENSA_MMU_L2_POS(page); + uint32_t l1_pos = XTENSA_MMU_L1_POS(page); if (is_pte_illegal(z_xtensa_kernel_ptables[l1_pos])) { table = alloc_l2_table(); @@ -239,11 +240,11 @@ static void map_memory_range(const uint32_t start, const uint32_t end, init_page_table(table, XTENSA_L2_PAGE_TABLE_ENTRIES); z_xtensa_kernel_ptables[l1_pos] = - Z_XTENSA_PTE((uint32_t)table, Z_XTENSA_KERNEL_RING, - Z_XTENSA_PAGE_TABLE_ATTR); + XTENSA_MMU_PTE((uint32_t)table, XTENSA_MMU_KERNEL_RING, + XTENSA_MMU_PAGE_TABLE_ATTR); } - table = (uint32_t *)(z_xtensa_kernel_ptables[l1_pos] & Z_XTENSA_PTE_PPN_MASK); + table = (uint32_t *)(z_xtensa_kernel_ptables[l1_pos] & XTENSA_MMU_PTE_PPN_MASK); table[l2_pos] = pte; } } @@ -257,7 +258,7 @@ static void map_memory(const uint32_t start, const uint32_t end, if (arch_xtensa_is_ptr_uncached((void *)start)) { map_memory_range(POINTER_TO_UINT(z_soc_cached_ptr((void *)start)), POINTER_TO_UINT(z_soc_cached_ptr((void *)end)), - attrs | Z_XTENSA_MMU_CACHED_WB, shared); + attrs | XTENSA_MMU_CACHED_WB, shared); } else if (arch_xtensa_is_ptr_cached((void *)start)) { map_memory_range(POINTER_TO_UINT(z_soc_uncached_ptr((void *)start)), POINTER_TO_UINT(z_soc_uncached_ptr((void *)end)), attrs, shared); @@ -277,8 +278,8 @@ static void xtensa_init_page_tables(void) bool shared; uint32_t attrs; - shared = !!(range->attrs & Z_XTENSA_MMU_MAP_SHARED); - attrs = range->attrs & ~Z_XTENSA_MMU_MAP_SHARED; + shared = !!(range->attrs & XTENSA_MMU_MAP_SHARED); + attrs = range->attrs & ~XTENSA_MMU_MAP_SHARED; map_memory(range->start, range->end, attrs, shared); } @@ -301,8 +302,8 @@ static void xtensa_init_page_tables(void) bool shared; uint32_t attrs; - shared = !!(range->attrs & Z_XTENSA_MMU_MAP_SHARED); - attrs = range->attrs & ~Z_XTENSA_MMU_MAP_SHARED; + shared = !!(range->attrs & XTENSA_MMU_MAP_SHARED); + attrs = range->attrs & ~XTENSA_MMU_MAP_SHARED; map_memory(range->start, range->end, attrs, shared); } @@ -316,10 +317,10 @@ static void xtensa_init_page_tables(void) */ map_memory_range((uint32_t) &l1_page_table[0], (uint32_t) &l1_page_table[CONFIG_XTENSA_MMU_NUM_L1_TABLES], - Z_XTENSA_PAGE_TABLE_ATTR | Z_XTENSA_MMU_W, false); + XTENSA_MMU_PAGE_TABLE_ATTR | XTENSA_MMU_PERM_W, false); map_memory_range((uint32_t) &l2_page_tables[0], (uint32_t) &l2_page_tables[CONFIG_XTENSA_MMU_NUM_L2_TABLES], - Z_XTENSA_PAGE_TABLE_ATTR | Z_XTENSA_MMU_W, false); + XTENSA_MMU_PAGE_TABLE_ATTR | XTENSA_MMU_PERM_W, false); sys_cache_data_flush_all(); } @@ -329,7 +330,7 @@ __weak void arch_xtensa_mmu_post_init(bool is_core0) ARG_UNUSED(is_core0); } -void z_xtensa_mmu_init(void) +void xtensa_mmu_init(void) { if (_current_cpu->id == 0) { /* This is normally done via arch_kernel_init() inside z_cstart(). @@ -372,8 +373,8 @@ __weak void arch_reserved_pages_update(void) static bool l2_page_table_map(uint32_t *l1_table, void *vaddr, uintptr_t phys, uint32_t flags, bool is_user) { - uint32_t l1_pos = Z_XTENSA_L1_POS((uint32_t)vaddr); - uint32_t l2_pos = Z_XTENSA_L2_POS((uint32_t)vaddr); + uint32_t l1_pos = XTENSA_MMU_L1_POS((uint32_t)vaddr); + uint32_t l2_pos = XTENSA_MMU_L2_POS((uint32_t)vaddr); uint32_t *table; sys_cache_data_invd_range((void *)&l1_table[l1_pos], sizeof(l1_table[0])); @@ -387,15 +388,16 @@ static bool l2_page_table_map(uint32_t *l1_table, void *vaddr, uintptr_t phys, init_page_table(table, XTENSA_L2_PAGE_TABLE_ENTRIES); - l1_table[l1_pos] = Z_XTENSA_PTE((uint32_t)table, Z_XTENSA_KERNEL_RING, - Z_XTENSA_PAGE_TABLE_ATTR); + l1_table[l1_pos] = XTENSA_MMU_PTE((uint32_t)table, XTENSA_MMU_KERNEL_RING, + XTENSA_MMU_PAGE_TABLE_ATTR); sys_cache_data_flush_range((void *)&l1_table[l1_pos], sizeof(l1_table[0])); } - table = (uint32_t *)(l1_table[l1_pos] & Z_XTENSA_PTE_PPN_MASK); - table[l2_pos] = Z_XTENSA_PTE(phys, is_user ? Z_XTENSA_USER_RING : Z_XTENSA_KERNEL_RING, - flags); + table = (uint32_t *)(l1_table[l1_pos] & XTENSA_MMU_PTE_PPN_MASK); + table[l2_pos] = XTENSA_MMU_PTE(phys, is_user ? XTENSA_MMU_USER_RING : + XTENSA_MMU_KERNEL_RING, + flags); sys_cache_data_flush_range((void *)&table[l2_pos], sizeof(table[0])); xtensa_tlb_autorefill_invalidate(); @@ -427,8 +429,8 @@ static inline void __arch_mem_map(void *va, uintptr_t pa, uint32_t xtensa_flags, paddr_uc = pa; } - flags_uc = (xtensa_flags & ~Z_XTENSA_PTE_ATTR_CACHED_MASK); - flags = flags_uc | Z_XTENSA_MMU_CACHED_WB; + flags_uc = (xtensa_flags & ~XTENSA_MMU_PTE_ATTR_CACHED_MASK); + flags = flags_uc | XTENSA_MMU_CACHED_WB; } else { vaddr = va; paddr = pa; @@ -493,10 +495,10 @@ void arch_mem_map(void *virt, uintptr_t phys, size_t size, uint32_t flags) switch (flags & K_MEM_CACHE_MASK) { case K_MEM_CACHE_WB: - xtensa_flags |= Z_XTENSA_MMU_CACHED_WB; + xtensa_flags |= XTENSA_MMU_CACHED_WB; break; case K_MEM_CACHE_WT: - xtensa_flags |= Z_XTENSA_MMU_CACHED_WT; + xtensa_flags |= XTENSA_MMU_CACHED_WT; break; case K_MEM_CACHE_NONE: __fallthrough; @@ -505,10 +507,10 @@ void arch_mem_map(void *virt, uintptr_t phys, size_t size, uint32_t flags) } if ((flags & K_MEM_PERM_RW) == K_MEM_PERM_RW) { - xtensa_flags |= Z_XTENSA_MMU_W; + xtensa_flags |= XTENSA_MMU_PERM_W; } if ((flags & K_MEM_PERM_EXEC) == K_MEM_PERM_EXEC) { - xtensa_flags |= Z_XTENSA_MMU_X; + xtensa_flags |= XTENSA_MMU_PERM_X; } is_user = (flags & K_MEM_PERM_USER) == K_MEM_PERM_USER; @@ -524,7 +526,7 @@ void arch_mem_map(void *virt, uintptr_t phys, size_t size, uint32_t flags) } #if CONFIG_MP_MAX_NUM_CPUS > 1 - z_xtensa_mmu_tlb_ipi(); + xtensa_mmu_tlb_ipi(); #endif sys_cache_data_flush_and_invd_all(); @@ -537,8 +539,8 @@ void arch_mem_map(void *virt, uintptr_t phys, size_t size, uint32_t flags) */ static bool l2_page_table_unmap(uint32_t *l1_table, void *vaddr) { - uint32_t l1_pos = Z_XTENSA_L1_POS((uint32_t)vaddr); - uint32_t l2_pos = Z_XTENSA_L2_POS((uint32_t)vaddr); + uint32_t l1_pos = XTENSA_MMU_L1_POS((uint32_t)vaddr); + uint32_t l2_pos = XTENSA_MMU_L2_POS((uint32_t)vaddr); uint32_t *l2_table; uint32_t table_pos; bool exec; @@ -552,13 +554,13 @@ static bool l2_page_table_unmap(uint32_t *l1_table, void *vaddr) return true; } - exec = l1_table[l1_pos] & Z_XTENSA_MMU_X; + exec = l1_table[l1_pos] & XTENSA_MMU_PERM_X; - l2_table = (uint32_t *)(l1_table[l1_pos] & Z_XTENSA_PTE_PPN_MASK); + l2_table = (uint32_t *)(l1_table[l1_pos] & XTENSA_MMU_PTE_PPN_MASK); sys_cache_data_invd_range((void *)&l2_table[l2_pos], sizeof(l2_table[0])); - l2_table[l2_pos] = Z_XTENSA_MMU_ILLEGAL; + l2_table[l2_pos] = XTENSA_MMU_PTE_ILLEGAL; sys_cache_data_flush_range((void *)&l2_table[l2_pos], sizeof(l2_table[0])); @@ -568,7 +570,7 @@ static bool l2_page_table_unmap(uint32_t *l1_table, void *vaddr) } } - l1_table[l1_pos] = Z_XTENSA_MMU_ILLEGAL; + l1_table[l1_pos] = XTENSA_MMU_PTE_ILLEGAL; sys_cache_data_flush_range((void *)&l1_table[l1_pos], sizeof(l1_table[0])); table_pos = (l2_table - (uint32_t *)l2_page_tables) / (XTENSA_L2_PAGE_TABLE_ENTRIES); @@ -648,7 +650,7 @@ void arch_mem_unmap(void *addr, size_t size) } #if CONFIG_MP_MAX_NUM_CPUS > 1 - z_xtensa_mmu_tlb_ipi(); + xtensa_mmu_tlb_ipi(); #endif sys_cache_data_flush_and_invd_all(); @@ -658,11 +660,11 @@ void arch_mem_unmap(void *addr, size_t size) /* This should be implemented in the SoC layer. * This weak version is here to avoid build errors. */ -void __weak z_xtensa_mmu_tlb_ipi(void) +void __weak xtensa_mmu_tlb_ipi(void) { } -void z_xtensa_mmu_tlb_shootdown(void) +void xtensa_mmu_tlb_shootdown(void) { unsigned int key; @@ -699,8 +701,8 @@ void z_xtensa_mmu_tlb_shootdown(void) * generating the query entry directly. */ ptevaddr = (uint32_t)xtensa_ptevaddr_get(); - ptevaddr_entry = Z_XTENSA_PTE_ENTRY_VADDR(ptevaddr, ptevaddr) - | Z_XTENSA_MMU_PTE_WAY; + ptevaddr_entry = XTENSA_MMU_PTE_ENTRY_VADDR(ptevaddr, ptevaddr) + | XTENSA_MMU_PTE_WAY; current_ptables = xtensa_dtlb_paddr_read(ptevaddr_entry); thread_ptables = (uint32_t)thread->arch.ptables; @@ -756,11 +758,11 @@ static uint32_t *dup_table(uint32_t *source_table) uint32_t *l2_table, *src_l2_table; if (is_pte_illegal(source_table[i])) { - dst_table[i] = Z_XTENSA_MMU_ILLEGAL; + dst_table[i] = XTENSA_MMU_PTE_ILLEGAL; continue; } - src_l2_table = (uint32_t *)(source_table[i] & Z_XTENSA_PTE_PPN_MASK); + src_l2_table = (uint32_t *)(source_table[i] & XTENSA_MMU_PTE_PPN_MASK); l2_table = alloc_l2_table(); if (l2_table == NULL) { goto err; @@ -773,8 +775,8 @@ static uint32_t *dup_table(uint32_t *source_table) /* The page table is using kernel ASID because we don't * user thread manipulate it. */ - dst_table[i] = Z_XTENSA_PTE((uint32_t)l2_table, Z_XTENSA_KERNEL_RING, - Z_XTENSA_PAGE_TABLE_ATTR); + dst_table[i] = XTENSA_MMU_PTE((uint32_t)l2_table, XTENSA_MMU_KERNEL_RING, + XTENSA_MMU_PAGE_TABLE_ATTR); sys_cache_data_flush_range((void *)l2_table, XTENSA_L2_PAGE_TABLE_SIZE); } @@ -798,7 +800,7 @@ int arch_mem_domain_init(struct k_mem_domain *domain) * For now, lets just assert if we have reached the maximum number * of asid we assert. */ - __ASSERT(asid_count < (Z_XTENSA_MMU_SHARED_ASID), "Reached maximum of ASID available"); + __ASSERT(asid_count < (XTENSA_MMU_SHARED_ASID), "Reached maximum of ASID available"); key = k_spin_lock(&xtensa_mmu_lock); ptables = dup_table(z_xtensa_kernel_ptables); @@ -829,17 +831,17 @@ static int region_map_update(uint32_t *ptables, uintptr_t start, for (size_t offset = 0; offset < size; offset += CONFIG_MMU_PAGE_SIZE) { uint32_t *l2_table, pte; uint32_t page = start + offset; - uint32_t l1_pos = Z_XTENSA_L1_POS(page); - uint32_t l2_pos = Z_XTENSA_L2_POS(page); + uint32_t l1_pos = XTENSA_MMU_L1_POS(page); + uint32_t l2_pos = XTENSA_MMU_L2_POS(page); /* Make sure we grab a fresh copy of L1 page table */ sys_cache_data_invd_range((void *)&ptables[l1_pos], sizeof(ptables[0])); - l2_table = (uint32_t *)(ptables[l1_pos] & Z_XTENSA_PTE_PPN_MASK); + l2_table = (uint32_t *)(ptables[l1_pos] & XTENSA_MMU_PTE_PPN_MASK); sys_cache_data_invd_range((void *)&l2_table[l2_pos], sizeof(l2_table[0])); - pte = Z_XTENSA_PTE_RING_SET(l2_table[l2_pos], ring); - pte = Z_XTENSA_PTE_ATTR_SET(pte, flags); + pte = XTENSA_MMU_PTE_RING_SET(l2_table[l2_pos], ring); + pte = XTENSA_MMU_PTE_ATTR_SET(pte, flags); l2_table[l2_pos] = pte; @@ -872,8 +874,8 @@ static inline int update_region(uint32_t *ptables, uintptr_t start, va_uc = start; } - new_flags_uc = (flags & ~Z_XTENSA_PTE_ATTR_CACHED_MASK); - new_flags = new_flags_uc | Z_XTENSA_MMU_CACHED_WB; + new_flags_uc = (flags & ~XTENSA_MMU_PTE_ATTR_CACHED_MASK); + new_flags = new_flags_uc | XTENSA_MMU_CACHED_WB; ret = region_map_update(ptables, va, size, ring, new_flags); @@ -886,7 +888,7 @@ static inline int update_region(uint32_t *ptables, uintptr_t start, #if CONFIG_MP_MAX_NUM_CPUS > 1 if ((option & OPTION_NO_TLB_IPI) != OPTION_NO_TLB_IPI) { - z_xtensa_mmu_tlb_ipi(); + xtensa_mmu_tlb_ipi(); } #endif @@ -898,7 +900,8 @@ static inline int update_region(uint32_t *ptables, uintptr_t start, static inline int reset_region(uint32_t *ptables, uintptr_t start, size_t size, uint32_t option) { - return update_region(ptables, start, size, Z_XTENSA_KERNEL_RING, Z_XTENSA_MMU_W, option); + return update_region(ptables, start, size, + XTENSA_MMU_KERNEL_RING, XTENSA_MMU_PERM_W, option); } void xtensa_user_stack_perms(struct k_thread *thread) @@ -909,7 +912,7 @@ void xtensa_user_stack_perms(struct k_thread *thread) update_region(thread_page_tables_get(thread), thread->stack_info.start, thread->stack_info.size, - Z_XTENSA_USER_RING, Z_XTENSA_MMU_W | Z_XTENSA_MMU_CACHED_WB, 0); + XTENSA_MMU_USER_RING, XTENSA_MMU_PERM_W | XTENSA_MMU_CACHED_WB, 0); } int arch_mem_domain_max_partitions_get(void) @@ -931,8 +934,8 @@ int arch_mem_domain_partition_add(struct k_mem_domain *domain, uint32_t partition_id) { struct k_mem_partition *partition = &domain->partitions[partition_id]; - uint32_t ring = K_MEM_PARTITION_IS_USER(partition->attr) ? Z_XTENSA_USER_RING : - Z_XTENSA_KERNEL_RING; + uint32_t ring = K_MEM_PARTITION_IS_USER(partition->attr) ? XTENSA_MMU_USER_RING : + XTENSA_MMU_KERNEL_RING; return update_region(domain->arch.ptables, partition->start, partition->size, ring, partition->attr, 0); @@ -959,8 +962,8 @@ int arch_mem_domain_thread_add(struct k_thread *thread) */ update_region(thread_page_tables_get(thread), thread->stack_info.start, thread->stack_info.size, - Z_XTENSA_USER_RING, - Z_XTENSA_MMU_W | Z_XTENSA_MMU_CACHED_WB, + XTENSA_MMU_USER_RING, + XTENSA_MMU_PERM_W | XTENSA_MMU_CACHED_WB, OPTION_NO_TLB_IPI); /* and reset thread's stack permission in * the old page tables. @@ -985,7 +988,7 @@ int arch_mem_domain_thread_add(struct k_thread *thread) * migration as it was sent above during reset_region(). */ if ((thread != _current_cpu->current) && !is_migration) { - z_xtensa_mmu_tlb_ipi(); + xtensa_mmu_tlb_ipi(); } #endif @@ -1026,14 +1029,14 @@ static bool page_validate(uint32_t *ptables, uint32_t page, uint8_t ring, bool w { uint8_t asid_ring; uint32_t rasid, pte, *l2_table; - uint32_t l1_pos = Z_XTENSA_L1_POS(page); - uint32_t l2_pos = Z_XTENSA_L2_POS(page); + uint32_t l1_pos = XTENSA_MMU_L1_POS(page); + uint32_t l2_pos = XTENSA_MMU_L2_POS(page); if (is_pte_illegal(ptables[l1_pos])) { return false; } - l2_table = (uint32_t *)(ptables[l1_pos] & Z_XTENSA_PTE_PPN_MASK); + l2_table = (uint32_t *)(ptables[l1_pos] & XTENSA_MMU_PTE_PPN_MASK); pte = l2_table[l2_pos]; if (is_pte_illegal(pte)) { @@ -1043,8 +1046,7 @@ static bool page_validate(uint32_t *ptables, uint32_t page, uint8_t ring, bool w asid_ring = 0; rasid = xtensa_rasid_get(); for (uint32_t i = 0; i < 4; i++) { - if (Z_XTENSA_PTE_ASID_GET(pte, rasid) == - Z_XTENSA_RASID_ASID_GET(rasid, i)) { + if (XTENSA_MMU_PTE_ASID_GET(pte, rasid) == XTENSA_MMU_RASID_ASID_GET(rasid, i)) { asid_ring = i; break; } @@ -1055,7 +1057,7 @@ static bool page_validate(uint32_t *ptables, uint32_t page, uint8_t ring, bool w } if (write) { - return (Z_XTENSA_PTE_ATTR_GET((pte)) & Z_XTENSA_MMU_W) != 0; + return (XTENSA_MMU_PTE_ATTR_GET((pte)) & XTENSA_MMU_PERM_W) != 0; } return true; @@ -1069,7 +1071,7 @@ int arch_buffer_validate(void *addr, size_t size, int write) const struct k_thread *thread = _current; uint32_t *ptables = thread_page_tables_get(thread); uint8_t ring = ((thread->base.user_options & K_USER) != 0) ? - Z_XTENSA_USER_RING : Z_XTENSA_KERNEL_RING; + XTENSA_MMU_USER_RING : XTENSA_MMU_KERNEL_RING; /* addr/size arbitrary, fix this up into an aligned region */ k_mem_region_align((uintptr_t *)&virt, &aligned_size, diff --git a/arch/xtensa/core/xtensa_asm2_util.S b/arch/xtensa/core/xtensa_asm2_util.S index f47f211057d..32fe783b207 100644 --- a/arch/xtensa/core/xtensa_asm2_util.S +++ b/arch/xtensa/core/xtensa_asm2_util.S @@ -434,7 +434,7 @@ _KernelExceptionVector: j _Level1Vector #ifdef CONFIG_XTENSA_MMU _handle_tlb_miss_kernel: - /* The TLB miss handling is used only during z_xtensa_mmu_init() + /* The TLB miss handling is used only during xtensa_mmu_init() * where vecbase is at a different address, as the offset used * in the jump ('j') instruction will not jump to correct * address (... remember the vecbase is moved). diff --git a/arch/xtensa/include/kernel_arch_func.h b/arch/xtensa/include/kernel_arch_func.h index 080b81d72bf..21354339b07 100644 --- a/arch/xtensa/include/kernel_arch_func.h +++ b/arch/xtensa/include/kernel_arch_func.h @@ -72,7 +72,7 @@ static ALWAYS_INLINE void arch_kernel_init(void) #endif #ifdef CONFIG_XTENSA_MMU - z_xtensa_mmu_init(); + xtensa_mmu_init(); #endif } diff --git a/arch/xtensa/include/xtensa_mmu_priv.h b/arch/xtensa/include/xtensa_mmu_priv.h index 08bcb1e5a2e..b6434e8ff0c 100644 --- a/arch/xtensa/include/xtensa_mmu_priv.h +++ b/arch/xtensa/include/xtensa_mmu_priv.h @@ -15,115 +15,152 @@ #include #include -#define Z_XTENSA_PTE_VPN_MASK 0xFFFFF000U -#define Z_XTENSA_PTE_PPN_MASK 0xFFFFF000U -#define Z_XTENSA_PTE_ATTR_MASK 0x0000000FU -#define Z_XTENSA_PTE_ATTR_CACHED_MASK 0x0000000CU -#define Z_XTENSA_L1_MASK 0x3FF00000U -#define Z_XTENSA_L2_MASK 0x3FFFFFU +/** + * @defgroup xtensa_mmu_internal_apis Xtensa Memory Management Unit (MMU) Internal APIs + * @ingroup xtensa_mmu_apis + * @{ + */ + +/** Mask for VPN in PTE */ +#define XTENSA_MMU_PTE_VPN_MASK 0xFFFFF000U + +/** Mask for PPN in PTE */ +#define XTENSA_MMU_PTE_PPN_MASK 0xFFFFF000U + +/** Mask for attributes in PTE */ +#define XTENSA_MMU_PTE_ATTR_MASK 0x0000000FU + +/** Mask for cache mode in PTE */ +#define XTENSA_MMU_PTE_ATTR_CACHED_MASK 0x0000000CU -#define Z_XTENSA_PPN_SHIFT 12U +/** Mask used to figure out which L1 page table to use */ +#define XTENSA_MMU_L1_MASK 0x3FF00000U -#define Z_XTENSA_PTE_RING_MASK 0x00000030U -#define Z_XTENSA_PTE_RING_SHIFT 4U +/** Mask used to figure out which L2 page table to use */ +#define XTENSA_MMU_L2_MASK 0x3FFFFFU -#define Z_XTENSA_PTEBASE_MASK 0xFFC00000 +#define XTENSA_MMU_PTEBASE_MASK 0xFFC00000 -#define Z_XTENSA_PTE(paddr, ring, attr) \ - (((paddr) & Z_XTENSA_PTE_PPN_MASK) | \ - (((ring) << Z_XTENSA_PTE_RING_SHIFT) & Z_XTENSA_PTE_RING_MASK) | \ - ((attr) & Z_XTENSA_PTE_ATTR_MASK)) +#define XTENSA_MMU_PTE(paddr, ring, attr) \ + (((paddr) & XTENSA_MMU_PTE_PPN_MASK) | \ + (((ring) << XTENSA_MMU_PTE_RING_SHIFT) & XTENSA_MMU_PTE_RING_MASK) | \ + ((attr) & XTENSA_MMU_PTE_ATTR_MASK)) -#define Z_XTENSA_PTE_ATTR_GET(pte) \ - (pte) & Z_XTENSA_PTE_ATTR_MASK +/** Number of bits to shift for PPN in PTE */ +#define XTENSA_MMU_PTE_PPN_SHIFT 12U -#define Z_XTENSA_PTE_ATTR_SET(pte, attr) \ - (((pte) & ~Z_XTENSA_PTE_ATTR_MASK) | (attr)) +/** Mask for ring in PTE */ +#define XTENSA_MMU_PTE_RING_MASK 0x00000030U -#define Z_XTENSA_PTE_RING_SET(pte, ring) \ - (((pte) & ~Z_XTENSA_PTE_RING_MASK) | \ - ((ring) << Z_XTENSA_PTE_RING_SHIFT)) +/** Number of bits to shift for ring in PTE */ +#define XTENSA_MMU_PTE_RING_SHIFT 4U -#define Z_XTENSA_PTE_RING_GET(pte) \ - (((pte) & ~Z_XTENSA_PTE_RING_MASK) >> Z_XTENSA_PTE_RING_SHIFT) +/** Construct a page table entry (PTE) */ +#define XTENSA_MMU_PTE(paddr, ring, attr) \ + (((paddr) & XTENSA_MMU_PTE_PPN_MASK) | \ + (((ring) << XTENSA_MMU_PTE_RING_SHIFT) & XTENSA_MMU_PTE_RING_MASK) | \ + ((attr) & XTENSA_MMU_PTE_ATTR_MASK)) -#define Z_XTENSA_PTE_ASID_GET(pte, rasid) \ - (((rasid) >> ((((pte) & Z_XTENSA_PTE_RING_MASK) \ - >> Z_XTENSA_PTE_RING_SHIFT) * 8)) & 0xFF) +/** Get the attributes from a PTE */ +#define XTENSA_MMU_PTE_ATTR_GET(pte) \ + ((pte) & XTENSA_MMU_PTE_ATTR_MASK) -#define Z_XTENSA_TLB_ENTRY(vaddr, way) \ - (((vaddr) & Z_XTENSA_PTE_PPN_MASK) | (way)) +/** Set the attributes in a PTE */ +#define XTENSA_MMU_PTE_ATTR_SET(pte, attr) \ + (((pte) & ~XTENSA_MMU_PTE_ATTR_MASK) | (attr)) -#define Z_XTENSA_AUTOFILL_TLB_ENTRY(vaddr) \ - (((vaddr) & Z_XTENSA_PTE_PPN_MASK) | \ - (((vaddr) >> Z_XTENSA_PPN_SHIFT) & 0x03U)) +/** Set the ring in a PTE */ +#define XTENSA_MMU_PTE_RING_SET(pte, ring) \ + (((pte) & ~XTENSA_MMU_PTE_RING_MASK) | \ + ((ring) << XTENSA_MMU_PTE_RING_SHIFT)) -#define Z_XTENSA_L2_POS(vaddr) \ - (((vaddr) & Z_XTENSA_L2_MASK) >> 12U) +/** Get the ring from a PTE */ +#define XTENSA_MMU_PTE_RING_GET(pte) \ + (((pte) & ~XTENSA_MMU_PTE_RING_MASK) >> XTENSA_MMU_PTE_RING_SHIFT) -#define Z_XTENSA_L1_POS(vaddr) \ +/** Get the ASID from the RASID register corresponding to the ring in a PTE */ +#define XTENSA_MMU_PTE_ASID_GET(pte, rasid) \ + (((rasid) >> ((((pte) & XTENSA_MMU_PTE_RING_MASK) \ + >> XTENSA_MMU_PTE_RING_SHIFT) * 8)) & 0xFF) + +/** Calculate the L2 page table position from a virtual address */ +#define XTENSA_MMU_L2_POS(vaddr) \ + (((vaddr) & XTENSA_MMU_L2_MASK) >> 12U) + +/** Calculate the L1 page table position from a virtual address */ +#define XTENSA_MMU_L1_POS(vaddr) \ ((vaddr) >> 22U) -/* PTE attributes for entries in the L1 page table. Should never be +/** + * @def XTENSA_MMU_PAGE_TABLE_ATTR + * + * PTE attributes for entries in the L1 page table. Should never be * writable, may be cached in non-SMP contexts only */ #if CONFIG_MP_MAX_NUM_CPUS == 1 -#define Z_XTENSA_PAGE_TABLE_ATTR Z_XTENSA_MMU_CACHED_WB +#define XTENSA_MMU_PAGE_TABLE_ATTR XTENSA_MMU_CACHED_WB #else -#define Z_XTENSA_PAGE_TABLE_ATTR 0 +#define XTENSA_MMU_PAGE_TABLE_ATTR 0 #endif -/* This ASID is shared between all domains and kernel. */ -#define Z_XTENSA_MMU_SHARED_ASID 255 +/** This ASID is shared between all domains and kernel. */ +#define XTENSA_MMU_SHARED_ASID 255 -/* Fixed data TLB way to map the page table */ -#define Z_XTENSA_MMU_PTE_WAY 7 +/** Fixed data TLB way to map the page table */ +#define XTENSA_MMU_PTE_WAY 7 -/* Fixed data TLB way to map the vecbase */ -#define Z_XTENSA_MMU_VECBASE_WAY 8 +/** Fixed data TLB way to map the vecbase */ +#define XTENSA_MMU_VECBASE_WAY 8 -/* Kernel specific ASID. Ring field in the PTE */ -#define Z_XTENSA_KERNEL_RING 0 +/** Kernel specific ASID. Ring field in the PTE */ +#define XTENSA_MMU_KERNEL_RING 0 -/* User specific ASID. Ring field in the PTE */ -#define Z_XTENSA_USER_RING 2 +/** User specific ASID. Ring field in the PTE */ +#define XTENSA_MMU_USER_RING 2 -/* Ring value for MMU_SHARED_ASID */ -#define Z_XTENSA_SHARED_RING 3 +/** Ring value for MMU_SHARED_ASID */ +#define XTENSA_MMU_SHARED_RING 3 -/* Number of data TLB ways [0-9] */ -#define Z_XTENSA_DTLB_WAYS 10 +/** Number of data TLB ways [0-9] */ +#define XTENSA_MMU_NUM_DTLB_WAYS 10 -/* Number of instruction TLB ways [0-6] */ -#define Z_XTENSA_ITLB_WAYS 7 +/** Number of instruction TLB ways [0-6] */ +#define XTENSA_MMU_NUM_ITLB_WAYS 7 -/* Number of auto-refill ways */ -#define Z_XTENSA_TLB_AUTOREFILL_WAYS 4 +/** Number of auto-refill ways */ +#define XTENSA_MMU_NUM_TLB_AUTOREFILL_WAYS 4 +/** Indicate PTE is illegal. */ +#define XTENSA_MMU_PTE_ILLEGAL (BIT(3) | BIT(2)) -/* PITLB HIT bit. For more information see +/** + * PITLB HIT bit. + * + * For more information see * Xtensa Instruction Set Architecture (ISA) Reference Manual * 4.6.5.7 Formats for Probing MMU Option TLB Entries */ -#define Z_XTENSA_PITLB_HIT BIT(3) +#define XTENSA_MMU_PITLB_HIT BIT(3) -/* PDTLB HIT bit. For more information see +/** + * PDTLB HIT bit. + * + * For more information see * Xtensa Instruction Set Architecture (ISA) Reference Manual * 4.6.5.7 Formats for Probing MMU Option TLB Entries */ -#define Z_XTENSA_PDTLB_HIT BIT(4) +#define XTENSA_MMU_PDTLB_HIT BIT(4) -/* +/** * Virtual address where the page table is mapped */ -#define Z_XTENSA_PTEVADDR CONFIG_XTENSA_MMU_PTEVADDR +#define XTENSA_MMU_PTEVADDR CONFIG_XTENSA_MMU_PTEVADDR -/* - * Find the pte entry address of a given vaddr. +/** + * Find the PTE entry address of a given vaddr. * * For example, assuming PTEVADDR in 0xE0000000, * the page spans from 0xE0000000 - 0xE03FFFFF - * * address 0x00 is in 0xE0000000 * address 0x1000 is in 0xE0000004 @@ -134,23 +171,33 @@ * * PTE_ENTRY_ADDRESS = PTEVADDR + ((VADDR / 4096) * 4) */ -#define Z_XTENSA_PTE_ENTRY_VADDR(base, vaddr) \ +#define XTENSA_MMU_PTE_ENTRY_VADDR(base, vaddr) \ ((base) + (((vaddr) / KB(4)) * 4)) -/* - * Get asid for a given ring from rasid register. - * rasid contains four asid, one per ring. +/** + * Get ASID for a given ring from RASID register. + * + * RASID contains four 8-bit ASIDs, one per ring. */ - -#define Z_XTENSA_RASID_ASID_GET(rasid, ring) \ +#define XTENSA_MMU_RASID_ASID_GET(rasid, ring) \ (((rasid) >> ((ring) * 8)) & 0xff) +/** + * @brief Set RASID register. + * + * @param rasid Value to be set. + */ static ALWAYS_INLINE void xtensa_rasid_set(uint32_t rasid) { __asm__ volatile("wsr %0, rasid\n\t" "isync\n" : : "a"(rasid)); } +/** + * @brief Get RASID register. + * + * @return Register value. + */ static ALWAYS_INLINE uint32_t xtensa_rasid_get(void) { uint32_t rasid; @@ -159,22 +206,37 @@ static ALWAYS_INLINE uint32_t xtensa_rasid_get(void) return rasid; } -static ALWAYS_INLINE void xtensa_rasid_asid_set(uint8_t asid, uint8_t pos) +/** + * @brief Set a ring in RASID register to be particular value. + * + * @param asid ASID to be set. + * @param ring ASID of which ring to be manipulated. + */ +static ALWAYS_INLINE void xtensa_rasid_asid_set(uint8_t asid, uint8_t ring) { uint32_t rasid = xtensa_rasid_get(); - rasid = (rasid & ~(0xff << (pos * 8))) | ((uint32_t)asid << (pos * 8)); + rasid = (rasid & ~(0xff << (ring * 8))) | ((uint32_t)asid << (ring * 8)); xtensa_rasid_set(rasid); } - +/** + * @brief Invalidate a particular instruction TLB entry. + * + * @param entry Entry to be invalidated. + */ static ALWAYS_INLINE void xtensa_itlb_entry_invalidate(uint32_t entry) { __asm__ volatile("iitlb %0\n\t" : : "a" (entry)); } +/** + * @brief Synchronously invalidate of a particular instruction TLB entry. + * + * @param entry Entry to be invalidated. + */ static ALWAYS_INLINE void xtensa_itlb_entry_invalidate_sync(uint32_t entry) { __asm__ volatile("iitlb %0\n\t" @@ -182,6 +244,11 @@ static ALWAYS_INLINE void xtensa_itlb_entry_invalidate_sync(uint32_t entry) : : "a" (entry)); } +/** + * @brief Synchronously invalidate of a particular data TLB entry. + * + * @param entry Entry to be invalidated. + */ static ALWAYS_INLINE void xtensa_dtlb_entry_invalidate_sync(uint32_t entry) { __asm__ volatile("idtlb %0\n\t" @@ -189,12 +256,23 @@ static ALWAYS_INLINE void xtensa_dtlb_entry_invalidate_sync(uint32_t entry) : : "a" (entry)); } +/** + * @brief Invalidate a particular data TLB entry. + * + * @param entry Entry to be invalidated. + */ static ALWAYS_INLINE void xtensa_dtlb_entry_invalidate(uint32_t entry) { __asm__ volatile("idtlb %0\n\t" : : "a" (entry)); } +/** + * @brief Synchronously write to a particular data TLB entry. + * + * @param pte Value to be written. + * @param entry Entry to be written. + */ static ALWAYS_INLINE void xtensa_dtlb_entry_write_sync(uint32_t pte, uint32_t entry) { __asm__ volatile("wdtlb %0, %1\n\t" @@ -202,18 +280,36 @@ static ALWAYS_INLINE void xtensa_dtlb_entry_write_sync(uint32_t pte, uint32_t en : : "a" (pte), "a"(entry)); } +/** + * @brief Write to a particular data TLB entry. + * + * @param pte Value to be written. + * @param entry Entry to be written. + */ static ALWAYS_INLINE void xtensa_dtlb_entry_write(uint32_t pte, uint32_t entry) { __asm__ volatile("wdtlb %0, %1\n\t" : : "a" (pte), "a"(entry)); } +/** + * @brief Synchronously write to a particular instruction TLB entry. + * + * @param pte Value to be written. + * @param entry Entry to be written. + */ static ALWAYS_INLINE void xtensa_itlb_entry_write(uint32_t pte, uint32_t entry) { __asm__ volatile("witlb %0, %1\n\t" : : "a" (pte), "a"(entry)); } +/** + * @brief Synchronously write to a particular instruction TLB entry. + * + * @param pte Value to be written. + * @param entry Entry to be written. + */ static ALWAYS_INLINE void xtensa_itlb_entry_write_sync(uint32_t pte, uint32_t entry) { __asm__ volatile("witlb %0, %1\n\t" @@ -239,9 +335,10 @@ static inline void xtensa_tlb_autorefill_invalidate(void) entries = BIT(MAX(XCHAL_ITLB_ARF_ENTRIES_LOG2, XCHAL_DTLB_ARF_ENTRIES_LOG2)); - for (way = 0; way < Z_XTENSA_TLB_AUTOREFILL_WAYS; way++) { + for (way = 0; way < XTENSA_MMU_NUM_TLB_AUTOREFILL_WAYS; way++) { for (i = 0; i < entries; i++) { - uint32_t entry = way + (i << Z_XTENSA_PPN_SHIFT); + uint32_t entry = way + (i << XTENSA_MMU_PTE_PPN_SHIFT); + xtensa_dtlb_entry_invalidate_sync(entry); xtensa_itlb_entry_invalidate_sync(entry); } @@ -273,43 +370,68 @@ static ALWAYS_INLINE void *xtensa_ptevaddr_get(void) __asm__ volatile("rsr.ptevaddr %0" : "=a" (ptables)); - return (void *)(ptables & Z_XTENSA_PTEBASE_MASK); + return (void *)(ptables & XTENSA_MMU_PTEBASE_MASK); } -/* - * The following functions are helpful when debugging. + +/** + * @brief Get the virtual address associated with a particular data TLB entry. + * + * @param entry TLB entry to be queried. */ static ALWAYS_INLINE void *xtensa_dtlb_vaddr_read(uint32_t entry) { uint32_t vaddr; __asm__ volatile("rdtlb0 %0, %1\n\t" : "=a" (vaddr) : "a" (entry)); - return (void *)(vaddr & Z_XTENSA_PTE_VPN_MASK); + return (void *)(vaddr & XTENSA_MMU_PTE_VPN_MASK); } +/** + * @brief Get the physical address associated with a particular data TLB entry. + * + * @param entry TLB entry to be queried. + */ static ALWAYS_INLINE uint32_t xtensa_dtlb_paddr_read(uint32_t entry) { uint32_t paddr; __asm__ volatile("rdtlb1 %0, %1\n\t" : "=a" (paddr) : "a" (entry)); - return (paddr & Z_XTENSA_PTE_PPN_MASK); + return (paddr & XTENSA_MMU_PTE_PPN_MASK); } +/** + * @brief Get the virtual address associated with a particular instruction TLB entry. + * + * @param entry TLB entry to be queried. + */ static ALWAYS_INLINE void *xtensa_itlb_vaddr_read(uint32_t entry) { uint32_t vaddr; __asm__ volatile("ritlb0 %0, %1\n\t" : "=a" (vaddr), "+a" (entry)); - return (void *)(vaddr & Z_XTENSA_PTE_VPN_MASK); + return (void *)(vaddr & XTENSA_MMU_PTE_VPN_MASK); } +/** + * @brief Get the physical address associated with a particular instruction TLB entry. + * + * @param entry TLB entry to be queried. + */ static ALWAYS_INLINE uint32_t xtensa_itlb_paddr_read(uint32_t entry) { uint32_t paddr; __asm__ volatile("ritlb1 %0, %1\n\t" : "=a" (paddr), "+a" (entry)); - return (paddr & Z_XTENSA_PTE_PPN_MASK); + return (paddr & XTENSA_MMU_PTE_PPN_MASK); } +/** + * @brief Probe for instruction TLB entry from a virtual address. + * + * @param vaddr Virtual address. + * + * @return Return of the PITLB instruction. + */ static ALWAYS_INLINE uint32_t xtensa_itlb_probe(void *vaddr) { uint32_t ret; @@ -318,6 +440,13 @@ static ALWAYS_INLINE uint32_t xtensa_itlb_probe(void *vaddr) return ret; } +/** + * @brief Probe for data TLB entry from a virtual address. + * + * @param vaddr Virtual address. + * + * @return Return of the PDTLB instruction. + */ static ALWAYS_INLINE uint32_t xtensa_dtlb_probe(void *vaddr) { uint32_t ret; @@ -326,26 +455,57 @@ static ALWAYS_INLINE uint32_t xtensa_dtlb_probe(void *vaddr) return ret; } +/** + * @brief Invalidate an instruction TLB entry associated with a virtual address. + * + * This invalidated an instruction TLB entry associated with a virtual address + * if such TLB entry exists. Otherwise, do nothing. + * + * @param vaddr Virtual address. + */ static inline void xtensa_itlb_vaddr_invalidate(void *vaddr) { uint32_t entry = xtensa_itlb_probe(vaddr); - if (entry & Z_XTENSA_PITLB_HIT) { + if (entry & XTENSA_MMU_PITLB_HIT) { xtensa_itlb_entry_invalidate_sync(entry); } } +/** + * @brief Invalidate a data TLB entry associated with a virtual address. + * + * This invalidated a data TLB entry associated with a virtual address + * if such TLB entry exists. Otherwise, do nothing. + * + * @param vaddr Virtual address. + */ static inline void xtensa_dtlb_vaddr_invalidate(void *vaddr) { uint32_t entry = xtensa_dtlb_probe(vaddr); - if (entry & Z_XTENSA_PDTLB_HIT) { + if (entry & XTENSA_MMU_PDTLB_HIT) { xtensa_dtlb_entry_invalidate_sync(entry); } } +/** + * @brief Tell hardware to use a page table very first time after boot. + * + * @param l1_page Pointer to the page table to be used. + */ void xtensa_init_paging(uint32_t *l1_page); +/** + * @brief Switch to a new page table. + * + * @param asid The ASID of the memory domain associated with the incoming page table. + * @param l1_page Page table to be switched to. + */ void xtensa_set_paging(uint32_t asid, uint32_t *l1_page); +/** + * @} + */ + #endif /* ZEPHYR_ARCH_XTENSA_XTENSA_MMU_PRIV_H_ */ diff --git a/include/zephyr/arch/xtensa/xtensa_mmu.h b/include/zephyr/arch/xtensa/xtensa_mmu.h index 5d72f884a03..d4deca40b31 100644 --- a/include/zephyr/arch/xtensa/xtensa_mmu.h +++ b/include/zephyr/arch/xtensa/xtensa_mmu.h @@ -4,67 +4,124 @@ * SPDX-License-Identifier: Apache-2.0 */ +#include + #ifndef ZEPHYR_INCLUDE_ARCH_XTENSA_XTENSA_MMU_H #define ZEPHYR_INCLUDE_ARCH_XTENSA_XTENSA_MMU_H -#define Z_XTENSA_MMU_X BIT(0) -#define Z_XTENSA_MMU_W BIT(1) -#define Z_XTENSA_MMU_XW (BIT(1) | BIT(0)) +/** + * @defgroup xtensa_mmu_apis Xtensa Memory Management Unit (MMU) APIs + * @ingroup xtensa_apis + * @{ + */ + +/** + * @name Memory region permission and caching mode. + * @{ + */ + +/** Memory region is executable. */ +#define XTENSA_MMU_PERM_X BIT(0) + +/** Memory region is writable. */ +#define XTENSA_MMU_PERM_W BIT(1) + +/** Memory region is both executable and writable */ +#define XTENSA_MMU_PERM_WX (XTENSA_MMU_PERM_W | XTENSA_MMU_PERM_X) + +/** Memory region has write-back cache. */ +#define XTENSA_MMU_CACHED_WB BIT(2) + +/** Memory region has write-through cache. */ +#define XTENSA_MMU_CACHED_WT BIT(3) -#define Z_XTENSA_MMU_CACHED_WB BIT(2) -#define Z_XTENSA_MMU_CACHED_WT BIT(3) +/** + * @} + */ -/* This bit is used in the HW. We just use it to know - * which ring pte entries should use. +/** + * @name Memory domain and partitions + * @{ */ -#define Z_XTENSA_MMU_USER BIT(4) -#define K_MEM_PARTITION_IS_EXECUTABLE(attr) (((attr) & Z_XTENSA_MMU_X) != 0) -#define K_MEM_PARTITION_IS_WRITABLE(attr) (((attr) & Z_XENSA_MMU_W) != 0) -#define K_MEM_PARTITION_IS_USER(attr) (((attr) & Z_XTENSA_MMU_USER) != 0) +typedef uint32_t k_mem_partition_attr_t; + +#define K_MEM_PARTITION_IS_EXECUTABLE(attr) (((attr) & XTENSA_MMU_PERM_X) != 0) +#define K_MEM_PARTITION_IS_WRITABLE(attr) (((attr) & XTENSA_MMU_PERM_W) != 0) +#define K_MEM_PARTITION_IS_USER(attr) (((attr) & XTENSA_MMU_MAP_USER) != 0) /* Read-Write access permission attributes */ -#define K_MEM_PARTITION_P_RW_U_RW ((k_mem_partition_attr_t) \ - {Z_XTENSA_MMU_W | Z_XTENSA_MMU_USER}) -#define K_MEM_PARTITION_P_RW_U_NA ((k_mem_partition_attr_t) \ - {0}) -#define K_MEM_PARTITION_P_RO_U_RO ((k_mem_partition_attr_t) \ - {Z_XTENSA_MMU_USER}) -#define K_MEM_PARTITION_P_RO_U_NA ((k_mem_partition_attr_t) \ - {0}) -#define K_MEM_PARTITION_P_NA_U_NA ((k_mem_partition_attr_t) \ - {0}) +#define K_MEM_PARTITION_P_RW_U_RW \ + ((k_mem_partition_attr_t) {XTENSA_MMU_PERM_W | XTENSA_MMU_MAP_USER}) +#define K_MEM_PARTITION_P_RW_U_NA \ + ((k_mem_partition_attr_t) {0}) +#define K_MEM_PARTITION_P_RO_U_RO \ + ((k_mem_partition_attr_t) {XTENSA_MMU_MAP_USER}) +#define K_MEM_PARTITION_P_RO_U_NA \ + ((k_mem_partition_attr_t) {0}) +#define K_MEM_PARTITION_P_NA_U_NA \ + ((k_mem_partition_attr_t) {0}) /* Execution-allowed attributes */ -#define K_MEM_PARTITION_P_RX_U_RX ((k_mem_partition_attr_t) \ - {Z_XTENSA_MMU_X}) +#define K_MEM_PARTITION_P_RX_U_RX \ + ((k_mem_partition_attr_t) {XTENSA_MMU_PERM_X}) -/* - * This BIT tells the mapping code whether the uncached pointer should +/** + * @} + */ + +/** + * @brief Software only bit to indicate a memory region can be accessed by user thread(s). + * + * This BIT tells the mapping code which ring PTE entries to use. + */ +#define XTENSA_MMU_MAP_USER BIT(4) + +/** + * @brief Software only bit to indicate a memory region is shared by all threads. + * + * This BIT tells the mapping code whether the memory region should * be shared between all threads. That is not used in the HW, it is * just for the implementation. * - * The pte mapping this memory will use an ASID that is set in the + * The PTE mapping this memory will use an ASID that is set in the * ring 4 spot in RASID. */ -#define Z_XTENSA_MMU_MAP_SHARED BIT(30) - -#define Z_XTENSA_MMU_ILLEGAL (BIT(3) | BIT(2)) +#define XTENSA_MMU_MAP_SHARED BIT(30) -/* Struct used to map a memory region */ +/** + * Struct used to map a memory region. + */ struct xtensa_mmu_range { + /** Name of the memory region. */ const char *name; + + /** Start address of the memory region. */ const uint32_t start; + + /** End address of the memory region. */ const uint32_t end; + + /** Attributes for the memory region. */ const uint32_t attrs; }; -typedef uint32_t k_mem_partition_attr_t; - +/** + * @brief Additional memory regions required by SoC. + * + * These memory regions will be setup by MMU initialization code at boot. + */ extern const struct xtensa_mmu_range xtensa_soc_mmu_ranges[]; + +/** Number of SoC additional memory regions. */ extern int xtensa_soc_mmu_ranges_num; -void z_xtensa_mmu_init(void); +/** + * @brief Initialize hardware MMU. + * + * This initializes the MMU hardware and setup the memory regions at boot. + */ +void xtensa_mmu_init(void); /** * @brief Tell other processors to flush TLBs. @@ -76,7 +133,7 @@ void z_xtensa_mmu_init(void); * * @note This needs to be implemented in the SoC layer. */ -void z_xtensa_mmu_tlb_ipi(void); +void xtensa_mmu_tlb_ipi(void); /** * @brief Invalidate cache to page tables and flush TLBs. @@ -84,6 +141,10 @@ void z_xtensa_mmu_tlb_ipi(void); * This invalidates cache to all page tables and flush TLBs * as they may have been modified by other processors. */ -void z_xtensa_mmu_tlb_shootdown(void); +void xtensa_mmu_tlb_shootdown(void); + +/** + * @} + */ #endif /* ZEPHYR_INCLUDE_ARCH_XTENSA_XTENSA_MMU_H */ diff --git a/soc/xtensa/dc233c/mmu.c b/soc/xtensa/dc233c/mmu.c index 3486ecc2aa0..ed6818b3efb 100644 --- a/soc/xtensa/dc233c/mmu.c +++ b/soc/xtensa/dc233c/mmu.c @@ -16,7 +16,7 @@ const struct xtensa_mmu_range xtensa_soc_mmu_ranges[] = { { .start = (uint32_t)XCHAL_VECBASE_RESET_VADDR, .end = (uint32_t)CONFIG_SRAM_OFFSET, - .attrs = Z_XTENSA_MMU_X | Z_XTENSA_MMU_CACHED_WB | Z_XTENSA_MMU_MAP_SHARED, + .attrs = XTENSA_MMU_PERM_X | XTENSA_MMU_CACHED_WB | XTENSA_MMU_MAP_SHARED, .name = "vecbase", }, { @@ -27,7 +27,7 @@ const struct xtensa_mmu_range xtensa_soc_mmu_ranges[] = { .start = (uint32_t)DT_REG_ADDR(DT_NODELABEL(rom0)), .end = (uint32_t)DT_REG_ADDR(DT_NODELABEL(rom0)) + (uint32_t)DT_REG_SIZE(DT_NODELABEL(rom0)), - .attrs = Z_XTENSA_MMU_X | Z_XTENSA_MMU_CACHED_WB, + .attrs = XTENSA_MMU_PERM_X | XTENSA_MMU_CACHED_WB, .name = "rom", }, }; diff --git a/tests/kernel/mem_protect/userspace/src/main.c b/tests/kernel/mem_protect/userspace/src/main.c index bcf504102db..c1dadbecfaf 100644 --- a/tests/kernel/mem_protect/userspace/src/main.c +++ b/tests/kernel/mem_protect/userspace/src/main.c @@ -267,7 +267,7 @@ ZTEST_USER(userspace, test_disable_mmu_mpu) uint32_t addr = 0U; for (int i = 0; i < 8; i++) { - uint32_t attr = addr | Z_XTENSA_MMU_XW; + uint32_t attr = addr | XTENSA_MMU_PERM_WX; __asm__ volatile("wdtlb %0, %1; witlb %0, %1" :: "r"(attr), "r"(addr)); From 6d5e0c25a62fa4d88199c35357eab9f53b16c0ea Mon Sep 17 00:00:00 2001 From: Daniel Leung Date: Fri, 8 Dec 2023 11:12:49 -0800 Subject: [PATCH 1164/3723] xtensa: rename z_xtensa_irq to simple xtensa_irq This gets rid of the z_ prefix. Note that z_xt_*() are being used by the HAL so they cannot be renamed. Signed-off-by: Daniel Leung --- arch/xtensa/core/gdbstub.c | 3 +- arch/xtensa/core/irq_manage.c | 2 +- drivers/interrupt_controller/intc_dw_ace.c | 8 ++-- .../interrupt_controller/intc_nxp_irqsteer.c | 8 ++-- include/zephyr/arch/xtensa/irq.h | 38 ++++++++++++++++--- soc/xtensa/intel_adsp/ace/multiprocessing.c | 2 +- soc/xtensa/intel_adsp/cavs/irq.c | 10 ++--- soc/xtensa/nxp_adsp/common/soc.c | 6 +-- 8 files changed, 51 insertions(+), 26 deletions(-) diff --git a/arch/xtensa/core/gdbstub.c b/arch/xtensa/core/gdbstub.c index f3214250f7b..4df72f0d355 100644 --- a/arch/xtensa/core/gdbstub.c +++ b/arch/xtensa/core/gdbstub.c @@ -972,8 +972,7 @@ void arch_gdb_init(void) * after level-1 interrupts is for level-2 interrupt. * So need to do an offset by subtraction. */ - z_xtensa_irq_enable(XCHAL_NUM_EXTINTERRUPTS + - XCHAL_DEBUGLEVEL - 2); + xtensa_irq_enable(XCHAL_NUM_EXTINTERRUPTS + XCHAL_DEBUGLEVEL - 2); /* * Break and go into the GDB stub. diff --git a/arch/xtensa/core/irq_manage.c b/arch/xtensa/core/irq_manage.c index 32dfc583dc9..cb3d9914583 100644 --- a/arch/xtensa/core/irq_manage.c +++ b/arch/xtensa/core/irq_manage.c @@ -75,7 +75,7 @@ void z_irq_spurious(const void *arg) z_xtensa_fatal_error(K_ERR_SPURIOUS_IRQ, NULL); } -int z_xtensa_irq_is_enabled(unsigned int irq) +int xtensa_irq_is_enabled(unsigned int irq) { uint32_t ie; diff --git a/drivers/interrupt_controller/intc_dw_ace.c b/drivers/interrupt_controller/intc_dw_ace.c index a876756a34f..9bda4bddcfa 100644 --- a/drivers/interrupt_controller/intc_dw_ace.c +++ b/drivers/interrupt_controller/intc_dw_ace.c @@ -92,7 +92,7 @@ void dw_ace_irq_enable(const struct device *dev, uint32_t irq) ACE_INTC[i].irq_intmask_l &= ~BIT(ACE_IRQ_FROM_ZEPHYR(irq)); } } else if ((irq & ~XTENSA_IRQ_NUM_MASK) == 0U) { - z_xtensa_irq_enable(XTENSA_IRQ_NUMBER(irq)); + xtensa_irq_enable(XTENSA_IRQ_NUMBER(irq)); } } @@ -108,7 +108,7 @@ void dw_ace_irq_disable(const struct device *dev, uint32_t irq) ACE_INTC[i].irq_intmask_l |= BIT(ACE_IRQ_FROM_ZEPHYR(irq)); } } else if ((irq & ~XTENSA_IRQ_NUM_MASK) == 0U) { - z_xtensa_irq_disable(XTENSA_IRQ_NUMBER(irq)); + xtensa_irq_disable(XTENSA_IRQ_NUMBER(irq)); } } @@ -119,7 +119,7 @@ int dw_ace_irq_is_enabled(const struct device *dev, unsigned int irq) if (is_dw_irq(irq)) { return ACE_INTC[0].irq_inten_l & BIT(ACE_IRQ_FROM_ZEPHYR(irq)); } else if ((irq & ~XTENSA_IRQ_NUM_MASK) == 0U) { - return z_xtensa_irq_is_enabled(XTENSA_IRQ_NUMBER(irq)); + return xtensa_irq_is_enabled(XTENSA_IRQ_NUMBER(irq)); } return false; @@ -161,7 +161,7 @@ static int dw_ace_init(const struct device *dev) ARG_UNUSED(dev); IRQ_CONNECT(ACE_INTC_IRQ, 0, dwint_isr, 0, 0); - z_xtensa_irq_enable(ACE_INTC_IRQ); + xtensa_irq_enable(ACE_INTC_IRQ); return 0; } diff --git a/drivers/interrupt_controller/intc_nxp_irqsteer.c b/drivers/interrupt_controller/intc_nxp_irqsteer.c index a456c17545e..cd06b23854a 100644 --- a/drivers/interrupt_controller/intc_nxp_irqsteer.c +++ b/drivers/interrupt_controller/intc_nxp_irqsteer.c @@ -324,9 +324,9 @@ void z_soc_irq_enable_disable(uint32_t irq, bool enable) if (irq_get_level(irq) == 1) { /* LEVEL 1 interrupts are DSP direct */ if (enable) { - z_xtensa_irq_enable(XTENSA_IRQ_NUMBER(irq)); + xtensa_irq_enable(XTENSA_IRQ_NUMBER(irq)); } else { - z_xtensa_irq_disable(XTENSA_IRQ_NUMBER(irq)); + xtensa_irq_disable(XTENSA_IRQ_NUMBER(irq)); } return; } @@ -375,7 +375,7 @@ int z_soc_irq_is_enabled(unsigned int irq) if (irq_get_level(irq) == 1) { /* LEVEL 1 interrupts are DSP direct */ - return z_xtensa_irq_is_enabled(XTENSA_IRQ_NUMBER(irq)); + return xtensa_irq_is_enabled(XTENSA_IRQ_NUMBER(irq)); } parent_irq = irq_parent_level_2(irq); @@ -449,7 +449,7 @@ static void irqsteer_enable_dispatchers(const struct device *dev) IRQSTEER_EnableMasterInterrupt(UINT_TO_IRQSTEER(cfg->regmap_phys), dispatcher->irq); - z_xtensa_irq_enable(XTENSA_IRQ_NUMBER(dispatcher->irq)); + xtensa_irq_enable(XTENSA_IRQ_NUMBER(dispatcher->irq)); } } diff --git a/include/zephyr/arch/xtensa/irq.h b/include/zephyr/arch/xtensa/irq.h index 69cef4e8627..22d4800f8b9 100644 --- a/include/zephyr/arch/xtensa/irq.h +++ b/include/zephyr/arch/xtensa/irq.h @@ -13,6 +13,10 @@ #define CONFIG_GEN_IRQ_START_VECTOR 0 +/** + * @cond INTERNAL_HIDDEN + */ + /* * Call this function to enable the specified interrupts. * @@ -42,6 +46,7 @@ static inline void z_xt_ints_off(unsigned int mask) __asm__ volatile("wsr.intenable %0; rsync" : : "r"(val)); } + /* * Call this function to set the specified (s/w) interrupt. */ @@ -54,6 +59,10 @@ static inline void z_xt_set_intset(unsigned int arg) #endif } +/** + * INTERNAL_HIDDEN @endcond + */ + #ifdef CONFIG_MULTI_LEVEL_INTERRUPTS /* for _soc_irq_*() */ @@ -94,19 +103,29 @@ extern int z_soc_irq_connect_dynamic(unsigned int irq, unsigned int priority, #define CONFIG_NUM_IRQS XCHAL_NUM_INTERRUPTS -#define arch_irq_enable(irq) z_xtensa_irq_enable(irq) -#define arch_irq_disable(irq) z_xtensa_irq_disable(irq) +#define arch_irq_enable(irq) xtensa_irq_enable(irq) +#define arch_irq_disable(irq) xtensa_irq_disable(irq) -#define arch_irq_is_enabled(irq) z_xtensa_irq_is_enabled(irq) +#define arch_irq_is_enabled(irq) xtensa_irq_is_enabled(irq) #endif -static ALWAYS_INLINE void z_xtensa_irq_enable(uint32_t irq) +/** + * @brief Enable interrupt on Xtensa core. + * + * @param irq Interrupt to be enabled. + */ +static ALWAYS_INLINE void xtensa_irq_enable(uint32_t irq) { z_xt_ints_on(1 << irq); } -static ALWAYS_INLINE void z_xtensa_irq_disable(uint32_t irq) +/** + * @brief Disable interrupt on Xtensa core. + * + * @param irq Interrupt to be disabled. + */ +static ALWAYS_INLINE void xtensa_irq_disable(uint32_t irq) { z_xt_ints_off(1 << irq); } @@ -131,7 +150,14 @@ static ALWAYS_INLINE bool arch_irq_unlocked(unsigned int key) return (key & 0xf) == 0; /* INTLEVEL field */ } -extern int z_xtensa_irq_is_enabled(unsigned int irq); +/** + * @brief Query if an interrupt is enabled on Xtensa core. + * + * @param irq Interrupt to be queried. + * + * @return True if interrupt is enabled, false otherwise. + */ +extern int xtensa_irq_is_enabled(unsigned int irq); #include diff --git a/soc/xtensa/intel_adsp/ace/multiprocessing.c b/soc/xtensa/intel_adsp/ace/multiprocessing.c index 2d3d74fa724..750dc06d74e 100644 --- a/soc/xtensa/intel_adsp/ace/multiprocessing.c +++ b/soc/xtensa/intel_adsp/ace/multiprocessing.c @@ -159,7 +159,7 @@ void soc_start_core(int cpu_num) void soc_mp_startup(uint32_t cpu) { /* Must have this enabled always */ - z_xtensa_irq_enable(ACE_INTC_IRQ); + xtensa_irq_enable(ACE_INTC_IRQ); #if CONFIG_ADSP_IDLE_CLOCK_GATING /* Disable idle power gating */ diff --git a/soc/xtensa/intel_adsp/cavs/irq.c b/soc/xtensa/intel_adsp/cavs/irq.c index c273e5252bb..dc9a573a3b1 100644 --- a/soc/xtensa/intel_adsp/cavs/irq.c +++ b/soc/xtensa/intel_adsp/cavs/irq.c @@ -42,7 +42,7 @@ void z_soc_irq_enable(uint32_t irq) break; default: /* regular interrupt */ - z_xtensa_irq_enable(XTENSA_IRQ_NUMBER(irq)); + xtensa_irq_enable(XTENSA_IRQ_NUMBER(irq)); return; } @@ -55,7 +55,7 @@ void z_soc_irq_enable(uint32_t irq) * The specified interrupt is in CAVS interrupt controller. * So enable core interrupt first. */ - z_xtensa_irq_enable(XTENSA_IRQ_NUMBER(irq)); + xtensa_irq_enable(XTENSA_IRQ_NUMBER(irq)); /* Then enable the interrupt in CAVS interrupt controller */ irq_enable_next_level(dev_cavs, CAVS_IRQ_NUMBER(irq)); @@ -80,7 +80,7 @@ void z_soc_irq_disable(uint32_t irq) break; default: /* regular interrupt */ - z_xtensa_irq_disable(XTENSA_IRQ_NUMBER(irq)); + xtensa_irq_disable(XTENSA_IRQ_NUMBER(irq)); return; } @@ -97,7 +97,7 @@ void z_soc_irq_disable(uint32_t irq) /* Then disable the parent IRQ if all children are disabled */ if (!irq_is_enabled_next_level(dev_cavs)) { - z_xtensa_irq_disable(XTENSA_IRQ_NUMBER(irq)); + xtensa_irq_disable(XTENSA_IRQ_NUMBER(irq)); } } @@ -121,7 +121,7 @@ int z_soc_irq_is_enabled(unsigned int irq) break; default: /* regular interrupt */ - ret = z_xtensa_irq_is_enabled(XTENSA_IRQ_NUMBER(irq)); + ret = xtensa_irq_is_enabled(XTENSA_IRQ_NUMBER(irq)); goto out; } diff --git a/soc/xtensa/nxp_adsp/common/soc.c b/soc/xtensa/nxp_adsp/common/soc.c index 8c80ff77308..903dd8e7805 100644 --- a/soc/xtensa/nxp_adsp/common/soc.c +++ b/soc/xtensa/nxp_adsp/common/soc.c @@ -25,7 +25,7 @@ void z_soc_irq_enable(uint32_t irq) /* * enable core interrupt */ - z_xtensa_irq_enable(XTENSA_IRQ_NUMBER(irq)); + xtensa_irq_enable(XTENSA_IRQ_NUMBER(irq)); } void z_soc_irq_disable(uint32_t irq) @@ -33,7 +33,7 @@ void z_soc_irq_disable(uint32_t irq) /* * disable the interrupt in interrupt controller */ - z_xtensa_irq_disable(XTENSA_IRQ_NUMBER(irq)); + xtensa_irq_disable(XTENSA_IRQ_NUMBER(irq)); } int z_soc_irq_is_enabled(unsigned int irq) @@ -41,7 +41,7 @@ int z_soc_irq_is_enabled(unsigned int irq) int ret = 0; /* regular interrupt */ - ret = z_xtensa_irq_is_enabled(XTENSA_IRQ_NUMBER(irq)); + ret = xtensa_irq_is_enabled(XTENSA_IRQ_NUMBER(irq)); return ret; } From a819bfb2d582592c5a1d6663b572ebec3cb36e79 Mon Sep 17 00:00:00 2001 From: Daniel Leung Date: Fri, 8 Dec 2023 11:10:50 -0800 Subject: [PATCH 1165/3723] xtensa: rename z_xtensa to simply xtensa Rename the remaining z_xtensa stuff as these are (mostly) under arch/xtensa. Signed-off-by: Daniel Leung --- arch/xtensa/core/debug_helpers_asm.S | 6 +-- arch/xtensa/core/fatal.c | 8 ++-- arch/xtensa/core/irq_manage.c | 4 +- arch/xtensa/core/ptables.c | 26 +++++------ arch/xtensa/core/thread.c | 9 ++-- arch/xtensa/core/userspace.S | 28 ++++++------ arch/xtensa/core/xtensa_asm2.c | 17 ++++--- arch/xtensa/core/xtensa_asm2_util.S | 4 +- arch/xtensa/core/xtensa_backtrace.c | 36 +++++++-------- arch/xtensa/include/kernel_arch_func.h | 9 ---- arch/xtensa/include/xtensa_asm2_s.h | 2 +- arch/xtensa/include/xtensa_backtrace.h | 23 +++++++--- arch/xtensa/include/xtensa_internal.h | 52 +++++++++++++++++++++- include/zephyr/arch/xtensa/thread_stack.h | 18 ++++---- scripts/coredump/gdbstubs/arch/xtensa.py | 2 +- soc/xtensa/dc233c/include/xtensa-dc233c.ld | 4 +- 16 files changed, 149 insertions(+), 99 deletions(-) diff --git a/arch/xtensa/core/debug_helpers_asm.S b/arch/xtensa/core/debug_helpers_asm.S index ea4df50daeb..3dacc1a4587 100644 --- a/arch/xtensa/core/debug_helpers_asm.S +++ b/arch/xtensa/core/debug_helpers_asm.S @@ -14,9 +14,9 @@ .section .iram1, "ax" .align 4 - .global z_xtensa_backtrace_get_start - .type z_xtensa_backtrace_get_start, @function -z_xtensa_backtrace_get_start: + .global xtensa_backtrace_get_start + .type xtensa_backtrace_get_start, @function +xtensa_backtrace_get_start: entry a1, 32 /* Spill registers onto stack (excluding this function) */ call8 xthal_window_spill diff --git a/arch/xtensa/core/fatal.c b/arch/xtensa/core/fatal.c index 06eb9ab7fd5..4e0f7d41ecd 100644 --- a/arch/xtensa/core/fatal.c +++ b/arch/xtensa/core/fatal.c @@ -21,7 +21,7 @@ LOG_MODULE_DECLARE(os, CONFIG_KERNEL_LOG_LEVEL); #include #endif -char *z_xtensa_exccause(unsigned int cause_code) +char *xtensa_exccause(unsigned int cause_code) { #if defined(CONFIG_PRINTK) || defined(CONFIG_LOG) switch (cause_code) { @@ -85,7 +85,7 @@ char *z_xtensa_exccause(unsigned int cause_code) #endif } -void z_xtensa_fatal_error(unsigned int reason, const z_arch_esf_t *esf) +void xtensa_fatal_error(unsigned int reason, const z_arch_esf_t *esf) { if (esf) { /* Don't want to get elbowed by xtensa_switch @@ -94,13 +94,13 @@ void z_xtensa_fatal_error(unsigned int reason, const z_arch_esf_t *esf) */ unsigned int key = arch_irq_lock(); - z_xtensa_dump_stack(esf); + xtensa_dump_stack(esf); coredump(reason, esf, IS_ENABLED(CONFIG_MULTITHREADING) ? k_current_get() : NULL); #if defined(CONFIG_XTENSA_ENABLE_BACKTRACE) #if XCHAL_HAVE_WINDOWED - z_xtensa_backtrace_print(100, (int *)esf); + xtensa_backtrace_print(100, (int *)esf); #endif #endif arch_irq_unlock(key); diff --git a/arch/xtensa/core/irq_manage.c b/arch/xtensa/core/irq_manage.c index cb3d9914583..576eb6e62bb 100644 --- a/arch/xtensa/core/irq_manage.c +++ b/arch/xtensa/core/irq_manage.c @@ -10,6 +10,8 @@ #include +#include + #include LOG_MODULE_DECLARE(os, CONFIG_KERNEL_LOG_LEVEL); @@ -72,7 +74,7 @@ void z_irq_spurious(const void *arg) __asm__ volatile("rsr.intenable %0" : "=r"(ie)); LOG_ERR(" ** Spurious INTERRUPT(s) %p, INTENABLE = %p", (void *)irqs, (void *)ie); - z_xtensa_fatal_error(K_ERR_SPURIOUS_IRQ, NULL); + xtensa_fatal_error(K_ERR_SPURIOUS_IRQ, NULL); } int xtensa_irq_is_enabled(unsigned int irq) diff --git a/arch/xtensa/core/ptables.c b/arch/xtensa/core/ptables.c index a5de406ffd6..4788584d64d 100644 --- a/arch/xtensa/core/ptables.c +++ b/arch/xtensa/core/ptables.c @@ -60,7 +60,7 @@ static uint32_t l1_page_table[CONFIG_XTENSA_MMU_NUM_L1_TABLES][XTENSA_L1_PAGE_TA /* * That is an alias for the page tables set used by the kernel. */ -uint32_t *z_xtensa_kernel_ptables = (uint32_t *)l1_page_table[0]; +uint32_t *xtensa_kernel_ptables = (uint32_t *)l1_page_table[0]; /* * Each table in the level 2 maps a 4Mb memory range. It consists of 1024 entries each one @@ -170,7 +170,7 @@ static inline uint32_t *thread_page_tables_get(const struct k_thread *thread) } #endif - return z_xtensa_kernel_ptables; + return xtensa_kernel_ptables; } /** @@ -231,7 +231,7 @@ static void map_memory_range(const uint32_t start, const uint32_t end, uint32_t l2_pos = XTENSA_MMU_L2_POS(page); uint32_t l1_pos = XTENSA_MMU_L1_POS(page); - if (is_pte_illegal(z_xtensa_kernel_ptables[l1_pos])) { + if (is_pte_illegal(xtensa_kernel_ptables[l1_pos])) { table = alloc_l2_table(); __ASSERT(table != NULL, "There is no l2 page table available to " @@ -239,12 +239,12 @@ static void map_memory_range(const uint32_t start, const uint32_t end, init_page_table(table, XTENSA_L2_PAGE_TABLE_ENTRIES); - z_xtensa_kernel_ptables[l1_pos] = + xtensa_kernel_ptables[l1_pos] = XTENSA_MMU_PTE((uint32_t)table, XTENSA_MMU_KERNEL_RING, XTENSA_MMU_PAGE_TABLE_ATTR); } - table = (uint32_t *)(z_xtensa_kernel_ptables[l1_pos] & XTENSA_MMU_PTE_PPN_MASK); + table = (uint32_t *)(xtensa_kernel_ptables[l1_pos] & XTENSA_MMU_PTE_PPN_MASK); table[l2_pos] = pte; } } @@ -270,7 +270,7 @@ static void xtensa_init_page_tables(void) { volatile uint8_t entry; - init_page_table(z_xtensa_kernel_ptables, XTENSA_L1_PAGE_TABLE_ENTRIES); + init_page_table(xtensa_kernel_ptables, XTENSA_L1_PAGE_TABLE_ENTRIES); atomic_set_bit(l1_page_table_track, 0); for (entry = 0; entry < ARRAY_SIZE(mmu_zephyr_ranges); entry++) { @@ -342,7 +342,7 @@ void xtensa_mmu_init(void) xtensa_init_page_tables(); } - xtensa_init_paging(z_xtensa_kernel_ptables); + xtensa_init_paging(xtensa_kernel_ptables); arch_xtensa_mmu_post_init(_current_cpu->id == 0); } @@ -437,12 +437,12 @@ static inline void __arch_mem_map(void *va, uintptr_t pa, uint32_t xtensa_flags, flags = xtensa_flags; } - ret = l2_page_table_map(z_xtensa_kernel_ptables, (void *)vaddr, paddr, + ret = l2_page_table_map(xtensa_kernel_ptables, (void *)vaddr, paddr, flags, is_user); __ASSERT(ret, "Virtual address (%p) already mapped", va); if (IS_ENABLED(CONFIG_XTENSA_MMU_DOUBLE_MAP) && ret) { - ret = l2_page_table_map(z_xtensa_kernel_ptables, (void *)vaddr_uc, paddr_uc, + ret = l2_page_table_map(xtensa_kernel_ptables, (void *)vaddr_uc, paddr_uc, flags_uc, is_user); __ASSERT(ret, "Virtual address (%p) already mapped", vaddr_uc); } @@ -599,10 +599,10 @@ static inline void __arch_mem_unmap(void *va) vaddr = va; } - is_exec = l2_page_table_unmap(z_xtensa_kernel_ptables, (void *)vaddr); + is_exec = l2_page_table_unmap(xtensa_kernel_ptables, (void *)vaddr); if (IS_ENABLED(CONFIG_XTENSA_MMU_DOUBLE_MAP)) { - (void)l2_page_table_unmap(z_xtensa_kernel_ptables, (void *)vaddr_uc); + (void)l2_page_table_unmap(xtensa_kernel_ptables, (void *)vaddr_uc); } #ifdef CONFIG_USERSPACE @@ -803,7 +803,7 @@ int arch_mem_domain_init(struct k_mem_domain *domain) __ASSERT(asid_count < (XTENSA_MMU_SHARED_ASID), "Reached maximum of ASID available"); key = k_spin_lock(&xtensa_mmu_lock); - ptables = dup_table(z_xtensa_kernel_ptables); + ptables = dup_table(xtensa_kernel_ptables); if (ptables == NULL) { ret = -ENOMEM; @@ -1088,7 +1088,7 @@ int arch_buffer_validate(void *addr, size_t size, int write) return ret; } -void z_xtensa_swap_update_page_tables(struct k_thread *incoming) +void xtensa_swap_update_page_tables(struct k_thread *incoming) { uint32_t *ptables = incoming->arch.ptables; struct arch_mem_domain *domain = diff --git a/arch/xtensa/core/thread.c b/arch/xtensa/core/thread.c index 53a4126d6ce..4ba0150f705 100644 --- a/arch/xtensa/core/thread.c +++ b/arch/xtensa/core/thread.c @@ -10,6 +10,7 @@ #include #include +#include #include LOG_MODULE_DECLARE(os, CONFIG_KERNEL_LOG_LEVEL); @@ -40,8 +41,8 @@ static void *init_stack(struct k_thread *thread, int *stack_top, void *ret; _xtensa_irq_stack_frame_a11_t *frame; #ifdef CONFIG_USERSPACE - struct z_xtensa_thread_stack_header *header = - (struct z_xtensa_thread_stack_header *)thread->stack_obj; + struct xtensa_thread_stack_header *header = + (struct xtensa_thread_stack_header *)thread->stack_obj; thread->arch.psp = header->privilege_stack + sizeof(header->privilege_stack); @@ -152,8 +153,8 @@ FUNC_NORETURN void arch_user_mode_enter(k_thread_entry_t user_entry, current->stack_info.size - current->stack_info.delta); - z_xtensa_userspace_enter(user_entry, p1, p2, p3, - stack_end, current->stack_info.start); + xtensa_userspace_enter(user_entry, p1, p2, p3, + stack_end, current->stack_info.start); CODE_UNREACHABLE; } diff --git a/arch/xtensa/core/userspace.S b/arch/xtensa/core/userspace.S index eff55dec46b..f385d7223ea 100644 --- a/arch/xtensa/core/userspace.S +++ b/arch/xtensa/core/userspace.S @@ -16,10 +16,10 @@ * a2 a6, a3, a4, a5, a8, a9 * **/ -.pushsection .text.z_xtensa_do_syscall, "ax" -.global z_xtensa_do_syscall +.pushsection .text.xtensa_do_syscall, "ax" +.global xtensa_do_syscall .align 4 -z_xtensa_do_syscall: +xtensa_do_syscall: rsr a0, ZSR_CPU l32i a0, a0, ___cpu_t_current_OFFSET l32i a0, a0, _thread_offset_to_psp @@ -199,17 +199,17 @@ _bad_syscall: .popsection -/* FUNC_NORETURN void z_xtensa_userspace_enter(k_thread_entry_t user_entry, +/* FUNC_NORETURN void xtensa_userspace_enter(k_thread_entry_t user_entry, * void *p1, void *p2, void *p3, * uint32_t stack_end, * uint32_t stack_start) * * A one-way trip to userspace. */ -.global z_xtensa_userspace_enter -.type z_xtensa_userspace_enter, @function +.global xtensa_userspace_enter +.type xtensa_userspace_enter, @function .align 4 -z_xtensa_userspace_enter: +xtensa_userspace_enter: /* Call entry to set a bit in the windowstart and * do the rotation, but we are going to set our own * stack. @@ -240,7 +240,7 @@ z_xtensa_userspace_enter: call4 xtensa_user_stack_perms l32i a6, a1, 24 - call4 z_xtensa_swap_update_page_tables + call4 xtensa_swap_update_page_tables #ifdef CONFIG_THREAD_LOCAL_STORAGE rur.threadptr a3 @@ -302,12 +302,12 @@ arch_user_string_nlen: /* This code might page fault */ strlen_loop: -.global z_xtensa_user_string_nlen_fault_start -z_xtensa_user_string_nlen_fault_start: +.global xtensa_user_string_nlen_fault_start +xtensa_user_string_nlen_fault_start: l8ui a6, a2, 0 /* Current char */ -.global z_xtensa_user_string_nlen_fault_end -z_xtensa_user_string_nlen_fault_end: +.global xtensa_user_string_nlen_fault_end +xtensa_user_string_nlen_fault_end: beqz a6, strlen_done addi a5, a5, 1 addi a2, a2, 1 @@ -322,6 +322,6 @@ strlen_done: movi a5, 0x0 s32i a5, a4, 0 -.global z_xtensa_user_string_nlen_fixup -z_xtensa_user_string_nlen_fixup: +.global xtensa_user_string_nlen_fixup +xtensa_user_string_nlen_fixup: retw diff --git a/arch/xtensa/core/xtensa_asm2.c b/arch/xtensa/core/xtensa_asm2.c index 88f1acaa734..fdcd219dfef 100644 --- a/arch/xtensa/core/xtensa_asm2.c +++ b/arch/xtensa/core/xtensa_asm2.c @@ -25,14 +25,14 @@ extern char xtensa_arch_except_epc[]; extern char xtensa_arch_kernel_oops_epc[]; #ifdef CONFIG_USERSPACE -Z_EXC_DECLARE(z_xtensa_user_string_nlen); +Z_EXC_DECLARE(xtensa_user_string_nlen); static const struct z_exc_handle exceptions[] = { - Z_EXC_HANDLE(z_xtensa_user_string_nlen) + Z_EXC_HANDLE(xtensa_user_string_nlen) }; #endif /* CONFIG_USERSPACE */ -void z_xtensa_dump_stack(const z_arch_esf_t *stack) +void xtensa_dump_stack(const z_arch_esf_t *stack) { _xtensa_irq_stack_frame_raw_t *frame = (void *)stack; _xtensa_irq_bsa_t *bsa = frame->ptr_to_bsa; @@ -115,7 +115,7 @@ static void print_fatal_exception(void *print_stack, int cause, LOG_ERR(" ** FATAL EXCEPTION%s", (is_dblexc ? " (DOUBLE)" : "")); LOG_ERR(" ** CPU %d EXCCAUSE %d (%s)", arch_curr_cpu()->id, cause, - z_xtensa_exccause(cause)); + xtensa_exccause(cause)); LOG_ERR(" ** PC %p VADDR %p", pc, (void *)vaddr); if (is_dblexc) { @@ -244,7 +244,7 @@ void *xtensa_excint1_c(int *interrupted_stack) /* Just report it to the console for now */ LOG_ERR(" ** SYSCALL PS %p PC %p", (void *)bsa->ps, (void *)bsa->pc); - z_xtensa_dump_stack(interrupted_stack); + xtensa_dump_stack(interrupted_stack); /* Xtensa exceptions don't automatically advance PC, * have to skip the SYSCALL instruction manually or @@ -279,7 +279,7 @@ void *xtensa_excint1_c(int *interrupted_stack) /* We need to distinguish between an ill in xtensa_arch_except, * e.g for k_panic, and any other ill. For exceptions caused by * xtensa_arch_except calls, we also need to pass the reason_p - * to z_xtensa_fatal_error. Since the ARCH_EXCEPT frame is in the + * to xtensa_fatal_error. Since the ARCH_EXCEPT frame is in the * BSA, the first arg reason_p is stored at the A2 offset. * We assign EXCCAUSE the unused, reserved code 63; this may be * problematic if the app or new boards also decide to repurpose @@ -316,8 +316,7 @@ void *xtensa_excint1_c(int *interrupted_stack) * as these are software errors. Should clean this * up. */ - z_xtensa_fatal_error(reason, - (void *)print_stack); + xtensa_fatal_error(reason, (void *)print_stack); break; } @@ -341,7 +340,7 @@ void *xtensa_excint1_c(int *interrupted_stack) /* We are going to manipulate _current_cpu->nested manually. * Since the error is fatal, for recoverable errors, code * execution must not return back to the current thread as - * it is being terminated (via above z_xtensa_fatal_error()). + * it is being terminated (via above xtensa_fatal_error()). * So we need to prevent more interrupts coming in which * will affect the nested value as we are going outside of * normal interrupt handling procedure. diff --git a/arch/xtensa/core/xtensa_asm2_util.S b/arch/xtensa/core/xtensa_asm2_util.S index 32fe783b207..5dabb39ea3a 100644 --- a/arch/xtensa/core/xtensa_asm2_util.S +++ b/arch/xtensa/core/xtensa_asm2_util.S @@ -277,7 +277,7 @@ noflush: /* Switch page tables */ rsr a6, ZSR_CPU l32i a6, a6, ___cpu_t_current_OFFSET - call4 z_xtensa_swap_update_page_tables + call4 xtensa_swap_update_page_tables l32i a2, a3, 0 l32i a2, a2, 0 @@ -407,7 +407,7 @@ _handle_tlb_miss_user: #ifdef CONFIG_USERSPACE _syscall: rsr a0, ZSR_A0SAVE - j z_xtensa_do_syscall + j xtensa_do_syscall #endif /* CONFIG_USERSPACE */ #endif /* CONFIG_XTENSA_MMU */ .popsection diff --git a/arch/xtensa/core/xtensa_backtrace.c b/arch/xtensa/core/xtensa_backtrace.c index e0abe09049b..5871a10c48f 100644 --- a/arch/xtensa/core/xtensa_backtrace.c +++ b/arch/xtensa/core/xtensa_backtrace.c @@ -16,7 +16,7 @@ #endif static int mask, cause; -static inline uint32_t z_xtensa_cpu_process_stack_pc(uint32_t pc) +static inline uint32_t xtensa_cpu_process_stack_pc(uint32_t pc) { if (pc & 0x80000000) { /* Top two bits of a0 (return address) specify window increment. @@ -34,7 +34,7 @@ static inline uint32_t z_xtensa_cpu_process_stack_pc(uint32_t pc) return pc - 3; } -static inline bool z_xtensa_stack_ptr_is_sane(uint32_t sp) +static inline bool xtensa_stack_ptr_is_sane(uint32_t sp) { #if defined(CONFIG_SOC_SERIES_ESP32) return esp_stack_ptr_is_sane(sp); @@ -43,11 +43,11 @@ static inline bool z_xtensa_stack_ptr_is_sane(uint32_t sp) #elif defined(CONFIG_SOC_XTENSA_DC233C) return xtensa_dc233c_stack_ptr_is_sane(sp); #else -#warning "z_xtensa_stack_ptr_is_sane is not defined for this platform" +#warning "xtensa_stack_ptr_is_sane is not defined for this platform" #endif } -static inline bool z_xtensa_ptr_executable(const void *p) +static inline bool xtensa_ptr_executable(const void *p) { #if defined(CONFIG_SOC_SERIES_ESP32) return esp_ptr_executable(p); @@ -56,11 +56,11 @@ static inline bool z_xtensa_ptr_executable(const void *p) #elif defined(CONFIG_SOC_XTENSA_DC233C) return xtensa_dc233c_ptr_executable(p); #else -#warning "z_xtensa_ptr_executable is not defined for this platform" +#warning "xtensa_ptr_executable is not defined for this platform" #endif } -bool z_xtensa_backtrace_get_next_frame(struct z_xtensa_backtrace_frame_t *frame) +bool xtensa_backtrace_get_next_frame(struct xtensa_backtrace_frame_t *frame) { /* Use frame(i-1)'s BS area located below frame(i)'s * sp to get frame(i-1)'s sp and frame(i-2)'s pc @@ -79,12 +79,12 @@ bool z_xtensa_backtrace_get_next_frame(struct z_xtensa_backtrace_frame_t *frame) /* Return true if both sp and pc of frame(i-1) are sane, * false otherwise */ - return (z_xtensa_stack_ptr_is_sane(frame->sp) && - z_xtensa_ptr_executable((void *) - z_xtensa_cpu_process_stack_pc(frame->pc))); + return (xtensa_stack_ptr_is_sane(frame->sp) && + xtensa_ptr_executable((void *) + xtensa_cpu_process_stack_pc(frame->pc))); } -int z_xtensa_backtrace_print(int depth, int *interrupted_stack) +int xtensa_backtrace_print(int depth, int *interrupted_stack) { /* Check arguments */ if (depth <= 0) { @@ -92,9 +92,9 @@ int z_xtensa_backtrace_print(int depth, int *interrupted_stack) } /* Initialize stk_frame with first frame of stack */ - struct z_xtensa_backtrace_frame_t stk_frame; + struct xtensa_backtrace_frame_t stk_frame; - z_xtensa_backtrace_get_start(&(stk_frame.pc), &(stk_frame.sp), + xtensa_backtrace_get_start(&(stk_frame.pc), &(stk_frame.sp), &(stk_frame.next_pc), interrupted_stack); __asm__ volatile("l32i a4, a3, 0"); __asm__ volatile("l32i a4, a4, 4"); @@ -104,22 +104,22 @@ int z_xtensa_backtrace_print(int depth, int *interrupted_stack) } printk("\r\n\r\nBacktrace:"); printk("0x%08x:0x%08x ", - z_xtensa_cpu_process_stack_pc(stk_frame.pc), + xtensa_cpu_process_stack_pc(stk_frame.pc), stk_frame.sp); /* Check if first frame is valid */ - bool corrupted = !(z_xtensa_stack_ptr_is_sane(stk_frame.sp) && - (z_xtensa_ptr_executable((void *) - z_xtensa_cpu_process_stack_pc(stk_frame.pc)) || + bool corrupted = !(xtensa_stack_ptr_is_sane(stk_frame.sp) && + (xtensa_ptr_executable((void *) + xtensa_cpu_process_stack_pc(stk_frame.pc)) || /* Ignore the first corrupted PC in case of InstrFetchProhibited */ cause == EXCCAUSE_INSTR_PROHIBITED)); while (depth-- > 0 && stk_frame.next_pc != 0 && !corrupted) { /* Get previous stack frame */ - if (!z_xtensa_backtrace_get_next_frame(&stk_frame)) { + if (!xtensa_backtrace_get_next_frame(&stk_frame)) { corrupted = true; } - printk("0x%08x:0x%08x ", z_xtensa_cpu_process_stack_pc(stk_frame.pc), stk_frame.sp); + printk("0x%08x:0x%08x ", xtensa_cpu_process_stack_pc(stk_frame.pc), stk_frame.sp); } /* Print backtrace termination marker */ diff --git a/arch/xtensa/include/kernel_arch_func.h b/arch/xtensa/include/kernel_arch_func.h index 21354339b07..f303a8a0c3a 100644 --- a/arch/xtensa/include/kernel_arch_func.h +++ b/arch/xtensa/include/kernel_arch_func.h @@ -20,8 +20,6 @@ extern "C" { #endif -extern void z_xtensa_fatal_error(unsigned int reason, const z_arch_esf_t *esf); - K_KERNEL_STACK_ARRAY_DECLARE(z_interrupt_stacks, CONFIG_MP_MAX_NUM_CPUS, CONFIG_ISR_STACK_SIZE); @@ -188,13 +186,6 @@ static inline bool arch_is_in_isr(void) return arch_curr_cpu()->nested != 0U; } -#ifdef CONFIG_USERSPACE -extern void z_xtensa_userspace_enter(k_thread_entry_t user_entry, - void *p1, void *p2, void *p3, - uintptr_t stack_end, - uintptr_t stack_start); -#endif /* CONFIG_USERSPACE */ - #ifdef __cplusplus } #endif diff --git a/arch/xtensa/include/xtensa_asm2_s.h b/arch/xtensa/include/xtensa_asm2_s.h index 5cbb1d8247c..1791b85a8cd 100644 --- a/arch/xtensa/include/xtensa_asm2_s.h +++ b/arch/xtensa/include/xtensa_asm2_s.h @@ -539,7 +539,7 @@ _do_call_\@: rsr a6, ZSR_CPU l32i a6, a6, ___cpu_t_current_OFFSET - call4 z_xtensa_swap_update_page_tables + call4 xtensa_swap_update_page_tables l32i a1, a1, 0 l32i a0, a1, ___xtensa_irq_bsa_t_a0_OFFSET addi a1, a1, ___xtensa_irq_bsa_t_SIZEOF diff --git a/arch/xtensa/include/xtensa_backtrace.h b/arch/xtensa/include/xtensa_backtrace.h index 2963836a4c6..069bdcb41ca 100644 --- a/arch/xtensa/include/xtensa_backtrace.h +++ b/arch/xtensa/include/xtensa_backtrace.h @@ -16,12 +16,17 @@ extern "C" { #include #include -/* +/** + * @ingroup xtensa_internal_apis + * @{ + */ + +/** * @brief Structure used for backtracing * * This structure stores the backtrace information of a particular stack frame * (i.e. the PC and SP). This structure is used iteratively with the - * z_xtensa_cpu_get_next_backtrace_frame() function to traverse each frame + * xtensa_cpu_get_next_backtrace_frame() function to traverse each frame * within a single stack. The next_pc represents the PC of the current * frame's caller, thus a next_pc of 0 indicates that the current frame * is the last frame on the stack. @@ -29,7 +34,7 @@ extern "C" { * @note Call esp_backtrace_get_start() to obtain initialization values for * this structure */ -struct z_xtensa_backtrace_frame_t { +struct xtensa_backtrace_frame_t { uint32_t pc; /* PC of the current frame */ uint32_t sp; /* SP of the current frame */ uint32_t next_pc; /* PC of the current frame's caller */ @@ -52,13 +57,13 @@ struct z_xtensa_backtrace_frame_t { * @param[out] next_pc PC of the first frame's caller * @param[in] interrupted_stack Pointer to interrupted stack */ -void z_xtensa_backtrace_get_start(uint32_t *pc, +void xtensa_backtrace_get_start(uint32_t *pc, uint32_t *sp, uint32_t *next_pc, int *interrupted_stack); /** - * Get the next frame on a stack for backtracing + * @brief Get the next frame on a stack for backtracing * * Given a stack frame(i), this function will obtain the next * stack frame(i-1) on the same call stack (i.e. the caller of frame(i)). @@ -77,7 +82,7 @@ void z_xtensa_backtrace_get_start(uint32_t *pc, * - True if the SP and PC of the next frame(i-1) are sane * - False otherwise */ -bool z_xtensa_backtrace_get_next_frame(struct z_xtensa_backtrace_frame_t *frame); +bool xtensa_backtrace_get_next_frame(struct xtensa_backtrace_frame_t *frame); /** * @brief Print the backtrace of the current stack @@ -89,7 +94,11 @@ bool z_xtensa_backtrace_get_next_frame(struct z_xtensa_backtrace_frame_t *frame) * - 0 Backtrace successfully printed to completion or to depth limit * - -1 Backtrace is corrupted */ -int z_xtensa_backtrace_print(int depth, int *interrupted_stack); +int xtensa_backtrace_print(int depth, int *interrupted_stack); + +/** + * @} + */ #endif #ifdef __cplusplus diff --git a/arch/xtensa/include/xtensa_internal.h b/arch/xtensa/include/xtensa_internal.h index 04d9129266a..b97c109a994 100644 --- a/arch/xtensa/include/xtensa_internal.h +++ b/arch/xtensa/include/xtensa_internal.h @@ -8,7 +8,55 @@ #ifndef ZEPHYR_ARCH_XTENSA_INCLUDE_XTENSA_INTERNAL_H_ #define ZEPHYR_ARCH_XTENSA_INCLUDE_XTENSA_INTERNAL_H_ -void z_xtensa_dump_stack(const z_arch_esf_t *stack); -char *z_xtensa_exccause(unsigned int cause_code); +#include + +#include +#include + +/** + * @ingroup xtensa_internal_apis + * @{ + */ + +/** + * @brief Dump and print out the stack frame content. + * + * This mainly prints out the registers stashed in the stack frame. + * + * @param stack Pointer to stack frame. + */ +void xtensa_dump_stack(const z_arch_esf_t *stack); + +/** + * @brief Get string description from an exception code. + * + * @param cause_code Exception code. + * + * @return String description. + */ +char *xtensa_exccause(unsigned int cause_code); + +/** + * @brief Called upon a fatal error. + * + * @param reason The reason for the fatal error + * @param esf Exception context, with details and partial or full register + * state when the error occurred. May in some cases be NULL. + */ +void xtensa_fatal_error(unsigned int reason, const z_arch_esf_t *esf); + +/** + * @brief Perform a one-way transition from supervisor to user mode. + * + * @see arch_user_mode_enter + */ +void xtensa_userspace_enter(k_thread_entry_t user_entry, + void *p1, void *p2, void *p3, + uintptr_t stack_end, + uintptr_t stack_start); + +/** + * @} + */ #endif /* ZEPHYR_ARCH_XTENSA_INCLUDE_XTENSA_INTERNAL_H_ */ diff --git a/include/zephyr/arch/xtensa/thread_stack.h b/include/zephyr/arch/xtensa/thread_stack.h index eaa160ccf1f..b862b7a8c1e 100644 --- a/include/zephyr/arch/xtensa/thread_stack.h +++ b/include/zephyr/arch/xtensa/thread_stack.h @@ -18,11 +18,11 @@ #if CONFIG_USERSPACE -#define Z_XTENSA_STACK_BASE_ALIGN CONFIG_MMU_PAGE_SIZE -#define Z_XTENSA_STACK_SIZE_ALIGN CONFIG_MMU_PAGE_SIZE +#define XTENSA_STACK_BASE_ALIGN CONFIG_MMU_PAGE_SIZE +#define XTENSA_STACK_SIZE_ALIGN CONFIG_MMU_PAGE_SIZE #else -#define Z_XTENSA_STACK_BASE_ALIGN ARCH_STACK_PTR_ALIGN -#define Z_XTENSA_STACK_SIZE_ALIGN ARCH_STACK_PTR_ALIGN +#define XTENSA_STACK_BASE_ALIGN ARCH_STACK_PTR_ALIGN +#define XTENSA_STACK_SIZE_ALIGN ARCH_STACK_PTR_ALIGN #endif /* @@ -46,17 +46,17 @@ /* thread stack */ #ifdef CONFIG_XTENSA_MMU -struct z_xtensa_thread_stack_header { +struct xtensa_thread_stack_header { char privilege_stack[CONFIG_MMU_PAGE_SIZE]; -} __packed __aligned(Z_XTENSA_STACK_BASE_ALIGN); +} __packed __aligned(XTENSA_STACK_BASE_ALIGN); #define ARCH_THREAD_STACK_RESERVED \ - sizeof(struct z_xtensa_thread_stack_header) + sizeof(struct xtensa_thread_stack_header) #endif /* CONFIG_XTENSA_MMU */ -#define ARCH_THREAD_STACK_OBJ_ALIGN(size) Z_XTENSA_STACK_BASE_ALIGN +#define ARCH_THREAD_STACK_OBJ_ALIGN(size) XTENSA_STACK_BASE_ALIGN #define ARCH_THREAD_STACK_SIZE_ADJUST(size) \ - ROUND_UP((size), Z_XTENSA_STACK_SIZE_ALIGN) + ROUND_UP((size), XTENSA_STACK_SIZE_ALIGN) /* kernel stack */ #define ARCH_KERNEL_STACK_RESERVED 0 diff --git a/scripts/coredump/gdbstubs/arch/xtensa.py b/scripts/coredump/gdbstubs/arch/xtensa.py index fbe572ac16b..c8829408ee2 100644 --- a/scripts/coredump/gdbstubs/arch/xtensa.py +++ b/scripts/coredump/gdbstubs/arch/xtensa.py @@ -76,7 +76,7 @@ def get_gdb_reg_definition(soc, toolchain): class ExceptionCodes(Enum): - # Matches arch/xtensa/core/fatal.c->z_xtensa_exccause + # Matches arch/xtensa/core/fatal.c->xtensa_exccause ILLEGAL_INSTRUCTION = 0 # Syscall not fatal INSTR_FETCH_ERROR = 2 diff --git a/soc/xtensa/dc233c/include/xtensa-dc233c.ld b/soc/xtensa/dc233c/include/xtensa-dc233c.ld index 54701b37ee7..b77effc032b 100644 --- a/soc/xtensa/dc233c/include/xtensa-dc233c.ld +++ b/soc/xtensa/dc233c/include/xtensa-dc233c.ld @@ -323,8 +323,8 @@ SECTIONS *libarch__xtensa__core.a:debug_helpers_asm.S.obj(.iram1.literal .iram1) /* Userspace related stuff */ - LIB_OBJ_FUNC_IN_SECT(libarch__xtensa__core.a,userspace.S.obj,z_xtensa_do_syscall) - LIB_OBJ_FUNC_IN_SECT(libarch__xtensa__core.a,ptables.c.obj,z_xtensa_swap_update_page_tables) + LIB_OBJ_FUNC_IN_SECT(libarch__xtensa__core.a,userspace.S.obj,xtensa_do_syscall) + LIB_OBJ_FUNC_IN_SECT(libarch__xtensa__core.a,ptables.c.obj,xtensa_swap_update_page_tables) /* Below are to speed up execution by avoiding TLB misses * on frequently used functions. From b2f20d65b3a2cd5aaf1ee9263e6f9a97c47d420a Mon Sep 17 00:00:00 2001 From: Daniel Leung Date: Fri, 8 Dec 2023 12:33:14 -0800 Subject: [PATCH 1166/3723] xtensa: remove z_arch_get_next_switch_handle Fold z_arch_get_next_switch_handle() into return_to(). This is not exactly an arch interface, and is simple enough to be moved into return_to(). Signed-off-by: Daniel Leung --- arch/xtensa/core/xtensa_asm2.c | 12 ++---------- 1 file changed, 2 insertions(+), 10 deletions(-) diff --git a/arch/xtensa/core/xtensa_asm2.c b/arch/xtensa/core/xtensa_asm2.c index fdcd219dfef..3334af67b7b 100644 --- a/arch/xtensa/core/xtensa_asm2.c +++ b/arch/xtensa/core/xtensa_asm2.c @@ -141,22 +141,14 @@ static ALWAYS_INLINE void usage_stop(void) #endif } -#ifdef CONFIG_MULTITHREADING -void *z_arch_get_next_switch_handle(struct k_thread *interrupted) +static inline void *return_to(void *interrupted) { +#ifdef CONFIG_MULTITHREADING return _current_cpu->nested <= 1 ? z_get_next_switch_handle(interrupted) : interrupted; -} #else -void *z_arch_get_next_switch_handle(struct k_thread *interrupted) -{ return interrupted; -} #endif /* CONFIG_MULTITHREADING */ - -static inline void *return_to(void *interrupted) -{ - return z_arch_get_next_switch_handle(interrupted); } /* The wrapper code lives here instead of in the python script that From 0636e52effcc2a0e466d10844f21f23179b59100 Mon Sep 17 00:00:00 2001 From: Daniel Leung Date: Fri, 8 Dec 2023 13:42:59 -0800 Subject: [PATCH 1167/3723] xtensa: rename xtensa_asm2.c to vector_handlers.c Rename xtensa_asm2.c to have a more meaningful name to actually reflect the content of the file. This file is mostly about handling interrupts and exceptions (via the predefined vectors in Xtensa core). Signed-off-by: Daniel Leung --- arch/xtensa/core/CMakeLists.txt | 2 +- arch/xtensa/core/{xtensa_asm2.c => vector_handlers.c} | 0 2 files changed, 1 insertion(+), 1 deletion(-) rename arch/xtensa/core/{xtensa_asm2.c => vector_handlers.c} (100%) diff --git a/arch/xtensa/core/CMakeLists.txt b/arch/xtensa/core/CMakeLists.txt index ed430f2d0c4..f1f82dc3834 100644 --- a/arch/xtensa/core/CMakeLists.txt +++ b/arch/xtensa/core/CMakeLists.txt @@ -9,9 +9,9 @@ zephyr_library_sources( fatal.c window_vectors.S xtensa_asm2_util.S - xtensa_asm2.c irq_manage.c thread.c + vector_handlers.c ) zephyr_library_sources_ifdef(CONFIG_XTENSA_USE_CORE_CRT1 crt1.S) diff --git a/arch/xtensa/core/xtensa_asm2.c b/arch/xtensa/core/vector_handlers.c similarity index 100% rename from arch/xtensa/core/xtensa_asm2.c rename to arch/xtensa/core/vector_handlers.c From 7c3853537eb000318bb7f4cb75ec14e19da0b5fb Mon Sep 17 00:00:00 2001 From: Alexis LECOQ Date: Wed, 6 Dec 2023 16:40:48 +0100 Subject: [PATCH 1168/3723] dts: boards: stm32h562: Adding USART11 This commit is enabling the USART11 for STM32H562/563 boards. Signed-off-by: Alexis LECOQ --- dts/arm/st/h5/stm32h562.dtsi | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/dts/arm/st/h5/stm32h562.dtsi b/dts/arm/st/h5/stm32h562.dtsi index f7cd14f7213..6d99b0d67e2 100644 --- a/dts/arm/st/h5/stm32h562.dtsi +++ b/dts/arm/st/h5/stm32h562.dtsi @@ -90,6 +90,15 @@ status = "disabled"; }; + usart11: serial@40006c00 { + compatible = "st,stm32-usart", "st,stm32-uart"; + reg = <0x40006c00 0x400>; + clocks = <&rcc STM32_CLOCK_BUS_APB1 0x08000000>; + resets = <&rctl STM32_RESET(APB1L, 27U)>; + interrupts = <87 0>; + status = "disabled"; + }; + uart12: serial@40008400 { compatible = "st,stm32-uart"; reg = <0x40008400 0x400>; From d3d46a6d80ea075c7ebf44028d98fb5bdd196dc6 Mon Sep 17 00:00:00 2001 From: Mariusz Skamra Date: Wed, 8 Nov 2023 13:28:06 +0100 Subject: [PATCH 1169/3723] Bluetooth: has: Fix control point error return code This fixes the return error code for Preset Write operation that shall be returned when preset is not writable (or disabled via Kconfig like in this case). As per HAS_v1.0; 3.2.2.3 Write Preset Name operation "If the Writable bit in the Properties field of the preset record which is identified by the Index parameter is set to 0b0, then the server shall return an ATT_ERROR_RSP PDU to the ATT_WRITE_REQ PDU with the Error Code parameter set to Write Name Not Allowed." Signed-off-by: Mariusz Skamra --- subsys/bluetooth/audio/has.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/subsys/bluetooth/audio/has.c b/subsys/bluetooth/audio/has.c index 72db5946d02..b018e034bb7 100644 --- a/subsys/bluetooth/audio/has.c +++ b/subsys/bluetooth/audio/has.c @@ -1396,6 +1396,8 @@ static uint8_t handle_control_point_op(struct bt_conn *conn, struct net_buf_simp case BT_HAS_OP_WRITE_PRESET_NAME: if (IS_ENABLED(CONFIG_BT_HAS_PRESET_NAME_DYNAMIC)) { return handle_write_preset_name(conn, buf); + } else { + return BT_HAS_ERR_WRITE_NAME_NOT_ALLOWED; } break; case BT_HAS_OP_SET_ACTIVE_PRESET: From f9b5dc20f7b3355c6c080e60ca49954cb787e3f2 Mon Sep 17 00:00:00 2001 From: Jukka Rissanen Date: Mon, 11 Dec 2023 15:50:12 +0200 Subject: [PATCH 1170/3723] drivers: net: loopback: Do not change the original pkt When we are sending a network pkt, do not tweak the original packet but the cloned one. The original behavior is ok too, but logically we should adjust the cloned packet only that is being received by the stack. This also means that we avoid one extra copy to tmp variable when sending the packet. Signed-off-by: Jukka Rissanen --- drivers/net/loopback.c | 35 +++++++++++++++-------------------- 1 file changed, 15 insertions(+), 20 deletions(-) diff --git a/drivers/net/loopback.c b/drivers/net/loopback.c index d8ae5ca1b05..2695875ae27 100644 --- a/drivers/net/loopback.c +++ b/drivers/net/loopback.c @@ -110,26 +110,6 @@ static int loopback_send(const struct device *dev, struct net_pkt *pkt) return -ENODATA; } - /* We need to swap the IP addresses because otherwise - * the packet will be dropped. - */ - - if (net_pkt_family(pkt) == AF_INET6) { - struct in6_addr addr; - - net_ipv6_addr_copy_raw((uint8_t *)&addr, NET_IPV6_HDR(pkt)->src); - net_ipv6_addr_copy_raw(NET_IPV6_HDR(pkt)->src, - NET_IPV6_HDR(pkt)->dst); - net_ipv6_addr_copy_raw(NET_IPV6_HDR(pkt)->dst, (uint8_t *)&addr); - } else { - struct in_addr addr; - - net_ipv4_addr_copy_raw((uint8_t *)&addr, NET_IPV4_HDR(pkt)->src); - net_ipv4_addr_copy_raw(NET_IPV4_HDR(pkt)->src, - NET_IPV4_HDR(pkt)->dst); - net_ipv4_addr_copy_raw(NET_IPV4_HDR(pkt)->dst, (uint8_t *)&addr); - } - /* We should simulate normal driver meaning that if the packet is * properly sent (which is always in this driver), then the packet * must be dropped. This is very much needed for TCP packets where @@ -141,6 +121,21 @@ static int loopback_send(const struct device *dev, struct net_pkt *pkt) goto out; } + /* We need to swap the IP addresses because otherwise + * the packet will be dropped. + */ + if (net_pkt_family(pkt) == AF_INET6) { + net_ipv6_addr_copy_raw(NET_IPV6_HDR(cloned)->src, + NET_IPV6_HDR(pkt)->dst); + net_ipv6_addr_copy_raw(NET_IPV6_HDR(cloned)->dst, + NET_IPV6_HDR(pkt)->src); + } else { + net_ipv4_addr_copy_raw(NET_IPV4_HDR(cloned)->src, + NET_IPV4_HDR(pkt)->dst); + net_ipv4_addr_copy_raw(NET_IPV4_HDR(cloned)->dst, + NET_IPV4_HDR(pkt)->src); + } + res = net_recv_data(net_pkt_iface(cloned), cloned); if (res < 0) { LOG_ERR("Data receive failed."); From 72620baefe9d78857ca31554a9035b53664d5f03 Mon Sep 17 00:00:00 2001 From: Armando Visconti Date: Mon, 11 Dec 2023 16:59:44 +0100 Subject: [PATCH 1171/3723] tests: drivers: build_all: add die_temp test case Add test case for all drivers that are supporting the die temperature feature, and fix right away all the yet undiscovered issues. Signed-off-by: Armando Visconti --- drivers/sensor/iis2iclx/iis2iclx.c | 3 +- drivers/sensor/ism330dhcx/ism330dhcx.c | 6 +- .../sensor/lsm6dsv16x/lsm6dsv16x_trigger.c | 57 +------------------ .../build_all/sensor/sensors_die_temp.conf | 8 +++ tests/drivers/build_all/sensor/testcase.yaml | 9 +-- 5 files changed, 20 insertions(+), 63 deletions(-) create mode 100644 tests/drivers/build_all/sensor/sensors_die_temp.conf diff --git a/drivers/sensor/iis2iclx/iis2iclx.c b/drivers/sensor/iis2iclx/iis2iclx.c index 8395f38c6ba..e45203da003 100644 --- a/drivers/sensor/iis2iclx/iis2iclx.c +++ b/drivers/sensor/iis2iclx/iis2iclx.c @@ -214,9 +214,10 @@ static int iis2iclx_sample_fetch_accel(const struct device *dev) static int iis2iclx_sample_fetch_temp(const struct device *dev) { struct iis2iclx_data *data = dev->data; + const struct iis2iclx_config *cfg = dev->config; int16_t buf; - if (iis2iclx_temperature_raw_get(&data->ctx, &buf) < 0) { + if (iis2iclx_temperature_raw_get((stmdev_ctx_t *)&cfg->ctx, &buf) < 0) { LOG_ERR("Failed to read sample"); return -EIO; } diff --git a/drivers/sensor/ism330dhcx/ism330dhcx.c b/drivers/sensor/ism330dhcx/ism330dhcx.c index 3dfa7a64137..97d0aaa5f44 100644 --- a/drivers/sensor/ism330dhcx/ism330dhcx.c +++ b/drivers/sensor/ism330dhcx/ism330dhcx.c @@ -473,9 +473,11 @@ static int ism330dhcx_gyro_channel_get(const struct device *dev, enum sensor_cha } #if defined(CONFIG_ISM330DHCX_ENABLE_TEMP) -static void ism330dhcx_gyro_channel_get_temp(struct sensor_value *val, - struct ism330dhcx_data *data) +static void ism330dhcx_gyro_channel_get_temp(const struct device *dev, + struct sensor_value *val) { + struct ism330dhcx_data *data = dev->data; + /* val = temp_sample / 256 + 25 */ val->val1 = data->temp_sample / 256 + 25; val->val2 = (data->temp_sample % 256) * (1000000 / 256); diff --git a/drivers/sensor/lsm6dsv16x/lsm6dsv16x_trigger.c b/drivers/sensor/lsm6dsv16x/lsm6dsv16x_trigger.c index 2911ee55cb7..52bd7d6c0dd 100644 --- a/drivers/sensor/lsm6dsv16x/lsm6dsv16x_trigger.c +++ b/drivers/sensor/lsm6dsv16x/lsm6dsv16x_trigger.c @@ -19,41 +19,6 @@ LOG_MODULE_DECLARE(LSM6DSV16X, CONFIG_SENSOR_LOG_LEVEL); -#if defined(CONFIG_LSM6DSV16X_ENABLE_TEMP) -/** - * lsm6dsv16x_enable_t_int - TEMP enable selected int pin to generate interrupt - */ -static int lsm6dsv16x_enable_t_int(const struct device *dev, int enable) -{ - const struct lsm6dsv16x_config *cfg = dev->config; - stmdev_ctx_t *ctx = (stmdev_ctx_t *)&cfg->ctx; - lsm6dsv16x_pin_int_route_t val; - int ret; - - if (enable) { - int16_t buf; - - /* dummy read: re-trigger interrupt */ - lsm6dsv16x_temperature_raw_get(ctx, &buf); - } - - /* set interrupt (TEMP DRDY interrupt is only on INT2) */ - if (cfg->drdy_pin == 1) { - return -EIO; - } - - ret = lsm6dsv16x_pin_int2_route_get(ctx, &val); - if (ret < 0) { - LOG_ERR("pint_int2_route_get error"); - return ret; - } - - val.drdy_temp = 1; - - return lsm6dsv16x_pin_int2_route_set(ctx, &val); -} -#endif - /** * lsm6dsv16x_enable_xl_int - XL enable selected int pin to generate interrupt */ @@ -178,17 +143,6 @@ int lsm6dsv16x_trigger_set(const struct device *dev, return lsm6dsv16x_enable_g_int(dev, LSM6DSV16X_DIS_BIT); } } -#if defined(CONFIG_LSM6DSV16X_ENABLE_TEMP) - else if (trig->chan == SENSOR_CHAN_DIE_TEMP) { - lsm6dsv16x->handler_drdy_temp = handler; - lsm6dsv16x->trig_drdy_temp = trig; - if (handler) { - return lsm6dsv16x_enable_t_int(dev, LSM6DSV16X_EN_BIT); - } else { - return lsm6dsv16x_enable_t_int(dev, LSM6DSV16X_DIS_BIT); - } - } -#endif return -ENOTSUP; } @@ -210,11 +164,7 @@ static void lsm6dsv16x_handle_interrupt(const struct device *dev) return; } - if ((status.drdy_xl == 0) && (status.drdy_gy == 0) -#if defined(CONFIG_LSM6DSV16X_ENABLE_TEMP) - && (status.drdy_temp == 0) -#endif - ) { + if ((status.drdy_xl == 0) && (status.drdy_gy == 0)) { break; } @@ -226,11 +176,6 @@ static void lsm6dsv16x_handle_interrupt(const struct device *dev) lsm6dsv16x->handler_drdy_gyr(dev, lsm6dsv16x->trig_drdy_gyr); } -#if defined(CONFIG_LSM6DSV16X_ENABLE_TEMP) - if ((status.drdy_temp) && (lsm6dsv16x->handler_drdy_temp != NULL)) { - lsm6dsv16x->handler_drdy_temp(dev, lsm6dsv16x->trig_drdy_temp); - } -#endif } gpio_pin_interrupt_configure_dt(lsm6dsv16x->drdy_gpio, diff --git a/tests/drivers/build_all/sensor/sensors_die_temp.conf b/tests/drivers/build_all/sensor/sensors_die_temp.conf new file mode 100644 index 00000000000..1d629e9b94f --- /dev/null +++ b/tests/drivers/build_all/sensor/sensors_die_temp.conf @@ -0,0 +1,8 @@ +CONFIG_ISM330DHCX_ENABLE_TEMP=y +CONFIG_IIS2ICLX_ENABLE_TEMP=y +CONFIG_LSM6DS0_ENABLE_TEMP=y +CONFIG_LSM6DSV16X_ENABLE_TEMP=y +CONFIG_LSM6DSO_ENABLE_TEMP=y +CONFIG_LIS2DS12_ENABLE_TEMP=y +CONFIG_LSM6DSO16IS_ENABLE_TEMP=y +CONFIG_LSM6DSL_ENABLE_TEMP=y diff --git a/tests/drivers/build_all/sensor/testcase.yaml b/tests/drivers/build_all/sensor/testcase.yaml index 2bf581e58da..bece435e252 100644 --- a/tests/drivers/build_all/sensor/testcase.yaml +++ b/tests/drivers/build_all/sensor/testcase.yaml @@ -10,17 +10,18 @@ common: build_only: true tests: sensors.build.sensorhub: - extra_args: OVERLAY_CONFIG=sensors_shub.conf + extra_args: OVERLAY_CONFIG=sensors_shub.conf;sensors_die_temp.conf sensors.build.trigger.own: - extra_args: OVERLAY_CONFIG=sensors_trigger_own.conf + extra_args: OVERLAY_CONFIG=sensors_trigger_own.conf;sensors_die_temp.conf sensors.build.trigger.global: - extra_args: OVERLAY_CONFIG=sensors_trigger_global.conf + extra_args: OVERLAY_CONFIG=sensors_trigger_global.conf;sensors_die_temp.conf sensors.build.trigger.none: - extra_args: OVERLAY_CONFIG=sensors_trigger_none.conf + extra_args: OVERLAY_CONFIG=sensors_trigger_none.conf;sensors_die_temp.conf sensors.build.no_default: extra_args: OVERLAY_CONFIG=sensors_no_default.conf sensors.build: tags: sensors + extra_args: OVERLAY_CONFIG=sensors_die_temp.conf sensors.build.pm: extra_configs: - CONFIG_PM=y From 547a75d4d05b09a925179d3f4fa477facde609bd Mon Sep 17 00:00:00 2001 From: Jason Kridner Date: Mon, 11 Dec 2023 13:38:05 -0500 Subject: [PATCH 1172/3723] Revert "boards: arm: Fix sensor shell sample for beagleconnect_freedom board" This reverts commit 3769938e785b09cff9ebb604a371100d1bfcf257. Now that gpio_i2c_switch is upstream, this hack should be removed. This had the unintended effect of disabling the on-board sensors. The issue was that the board was merged before this driver was upstream, resulting in the issue this commit "fixed". This revert also does not move the bus driver under the controller used by the driver as the sensor bus I2C driver is not an I2C peripheral. See: * https://github.com/zephyrproject-rtos/zephyr/pull/64881 * https://github.com/zephyrproject-rtos/zephyr/pull/64693 * https://github.com/zephyrproject-rtos/zephyr/pull/65031 Signed-off-by: Jason Kridner --- .../arm/beagle_bcf/beagleconnect_freedom.dts | 24 +++++++++---------- 1 file changed, 12 insertions(+), 12 deletions(-) diff --git a/boards/arm/beagle_bcf/beagleconnect_freedom.dts b/boards/arm/beagle_bcf/beagleconnect_freedom.dts index 7fd8341e89b..9f8c84df956 100644 --- a/boards/arm/beagle_bcf/beagleconnect_freedom.dts +++ b/boards/arm/beagle_bcf/beagleconnect_freedom.dts @@ -64,6 +64,18 @@ #size-cells = <0>; controller = <&i2c0>; gpios = <&gpio0 14 GPIO_ACTIVE_HIGH>; + + light: opt3001-light@44 { + status = "okay"; + compatible = "ti,opt3001"; + reg = <0x44>; + }; + + humidity: hdc2010-humidity@41 { + status = "okay"; + compatible = "ti,hdc2010"; + reg = <0x41>; + }; }; }; @@ -126,18 +138,6 @@ compatible = "beagle,usbbridge"; reg = <0x4>; }; - - light: opt3001-light@44 { - status = "okay"; - compatible = "ti,opt3001"; - reg = <0x44>; - }; - - humidity: hdc2010-humidity@41 { - status = "okay"; - compatible = "ti,hdc2010"; - reg = <0x41>; - }; }; &spi0 { From e268a6ce7dd15f45798c036f49c3201a3ea03772 Mon Sep 17 00:00:00 2001 From: Jeremy Bettis Date: Mon, 4 Dec 2023 23:39:32 +0000 Subject: [PATCH 1173/3723] gpio: Add lock around registers and data Added a spinlock to accesses of registers and struct gpio_ite_data, except for gpio_ite_isr() function. Bug #66401 Signed-off-by: Jeremy Bettis --- drivers/gpio/gpio_ite_it8xxx2_v2.c | 49 ++++++++++++++++++++++++++---- 1 file changed, 43 insertions(+), 6 deletions(-) diff --git a/drivers/gpio/gpio_ite_it8xxx2_v2.c b/drivers/gpio/gpio_ite_it8xxx2_v2.c index 23fd2178179..71a7ee37b50 100644 --- a/drivers/gpio/gpio_ite_it8xxx2_v2.c +++ b/drivers/gpio/gpio_ite_it8xxx2_v2.c @@ -18,9 +18,11 @@ #include #include #include +#include #include #include #include + LOG_MODULE_REGISTER(gpio_it8xxx2, LOG_LEVEL_ERR); /* @@ -57,6 +59,7 @@ struct gpio_ite_data { struct gpio_driver_data common; sys_slist_t callbacks; uint8_t volt_default_set; + struct k_spinlock lock; }; /** @@ -73,6 +76,7 @@ static int gpio_ite_configure(const struct device *dev, volatile uint8_t *reg_gpcr = (uint8_t *)gpio_config->reg_gpcr + pin; struct gpio_ite_data *data = dev->data; uint8_t mask = BIT(pin); + int rc = 0; /* Don't support "open source" mode */ if (((flags & GPIO_SINGLE_ENDED) != 0) && @@ -80,6 +84,7 @@ static int gpio_ite_configure(const struct device *dev, return -ENOTSUP; } + k_spinlock_key_t key = k_spin_lock(&data->lock); if (flags == GPIO_DISCONNECTED) { *reg_gpcr = GPCR_PORT_PIN_MODE_TRISTATE; /* @@ -91,13 +96,15 @@ static int gpio_ite_configure(const struct device *dev, *reg_gpcr = GPCR_PORT_PIN_MODE_INPUT; LOG_ERR("Cannot config the node-gpio@%x, pin=%d as tri-state", (uint32_t)reg_gpdr, pin); - return -ENOTSUP; + rc = -ENOTSUP; + goto unlock_and_return; } /* * The following configuration isn't necessary because the pin * was configured as disconnected. */ - return 0; + rc = 0; + goto unlock_and_return; } /* @@ -131,7 +138,8 @@ static int gpio_ite_configure(const struct device *dev, *reg_p18scr &= ~mask; data->volt_default_set |= mask; } else { - return -EINVAL; + rc = -EINVAL; + goto unlock_and_return; } } @@ -166,7 +174,9 @@ static int gpio_ite_configure(const struct device *dev, GPCR_PORT_PIN_MODE_PULLDOWN); } - return 0; +unlock_and_return: + k_spin_unlock(&data->lock, key); + return rc; } #ifdef CONFIG_GPIO_GET_CONFIG @@ -183,6 +193,7 @@ static int gpio_ite_get_config(const struct device *dev, uint8_t mask = BIT(pin); gpio_flags_t flags = 0; + k_spinlock_key_t key = k_spin_lock(&data->lock); /* push-pull or open-drain */ if (*reg_gpotr & mask) { flags |= GPIO_OPEN_DRAIN; @@ -227,6 +238,7 @@ static int gpio_ite_get_config(const struct device *dev, } *out_flags = flags; + k_spin_unlock(&data->lock, key); return 0; } @@ -250,9 +262,13 @@ static int gpio_ite_port_set_masked_raw(const struct device *dev, { const struct gpio_ite_cfg *gpio_config = dev->config; volatile uint8_t *reg_gpdr = (uint8_t *)gpio_config->reg_gpdr; + uint8_t masked_value = value & mask; + struct gpio_ite_data *data = dev->data; + k_spinlock_key_t key = k_spin_lock(&data->lock); uint8_t out = *reg_gpdr; - *reg_gpdr = ((out & ~mask) | (value & mask)); + *reg_gpdr = ((out & ~mask) | masked_value); + k_spin_unlock(&data->lock, key); return 0; } @@ -262,9 +278,12 @@ static int gpio_ite_port_set_bits_raw(const struct device *dev, { const struct gpio_ite_cfg *gpio_config = dev->config; volatile uint8_t *reg_gpdr = (uint8_t *)gpio_config->reg_gpdr; + struct gpio_ite_data *data = dev->data; + k_spinlock_key_t key = k_spin_lock(&data->lock); /* Set raw bits of GPIO data register */ *reg_gpdr |= pins; + k_spin_unlock(&data->lock, key); return 0; } @@ -274,9 +293,12 @@ static int gpio_ite_port_clear_bits_raw(const struct device *dev, { const struct gpio_ite_cfg *gpio_config = dev->config; volatile uint8_t *reg_gpdr = (uint8_t *)gpio_config->reg_gpdr; + struct gpio_ite_data *data = dev->data; + k_spinlock_key_t key = k_spin_lock(&data->lock); /* Clear raw bits of GPIO data register */ *reg_gpdr &= ~pins; + k_spin_unlock(&data->lock, key); return 0; } @@ -286,9 +308,12 @@ static int gpio_ite_port_toggle_bits(const struct device *dev, { const struct gpio_ite_cfg *gpio_config = dev->config; volatile uint8_t *reg_gpdr = (uint8_t *)gpio_config->reg_gpdr; + struct gpio_ite_data *data = dev->data; + k_spinlock_key_t key = k_spin_lock(&data->lock); /* Toggle raw bits of GPIO data register */ *reg_gpdr ^= pins; + k_spin_unlock(&data->lock, key); return 0; } @@ -299,7 +324,11 @@ static int gpio_ite_manage_callback(const struct device *dev, { struct gpio_ite_data *data = dev->data; - return gpio_manage_callback(&data->callbacks, callback, set); + k_spinlock_key_t key = k_spin_lock(&data->lock); + int rc = gpio_manage_callback(&data->callbacks, callback, set); + + k_spin_unlock(&data->lock, key); + return rc; } static void gpio_ite_isr(const void *arg) @@ -318,8 +347,12 @@ static void gpio_ite_isr(const void *arg) volatile uint8_t *reg_wuesr = reg_base + 1; uint8_t wuc_mask = gpio_config->wuc_mask[pin]; + /* Should be safe even without spinlock. */ /* Clear the WUC status register. */ *reg_wuesr = wuc_mask; + /* The callbacks are user code, and therefore should + * not hold the lock. + */ gpio_fire_callbacks(&data->callbacks, dev, BIT(pin)); break; @@ -334,6 +367,7 @@ static int gpio_ite_pin_interrupt_configure(const struct device *dev, { const struct gpio_ite_cfg *gpio_config = dev->config; uint8_t gpio_irq = gpio_config->gpio_irq[pin]; + struct gpio_ite_data *data = dev->data; #ifdef CONFIG_GPIO_ENABLE_DISABLE_INTERRUPT if (mode == GPIO_INT_MODE_DISABLED || mode == GPIO_INT_MODE_DISABLE_ONLY) { @@ -366,6 +400,8 @@ static int gpio_ite_pin_interrupt_configure(const struct device *dev, volatile uint8_t *reg_wubemr = reg_base + 3; uint8_t wuc_mask = gpio_config->wuc_mask[pin]; + k_spinlock_key_t key = k_spin_lock(&data->lock); + /* Set both edges interrupt. */ if ((trig & GPIO_INT_TRIG_BOTH) == GPIO_INT_TRIG_BOTH) { *reg_wubemr |= wuc_mask; @@ -383,6 +419,7 @@ static int gpio_ite_pin_interrupt_configure(const struct device *dev, * modifying edge mode selection register (WUBEMR and WUEMR). */ *reg_wuesr = wuc_mask; + k_spin_unlock(&data->lock, key); } /* Enable GPIO interrupt */ From 6b00b537aa56aadabbd191e7bbbedd848b9423e7 Mon Sep 17 00:00:00 2001 From: Robert Lubos Date: Mon, 11 Dec 2023 16:49:55 +0100 Subject: [PATCH 1174/3723] net: tcp: Fix deadlock with tcp_conn_close() While improving thread safety of the TCP stack I've introduced a possible deadlock scenario, when calling tcp_conn_close() in tcp_in(). This function shall not be called with connection mutex locked, as it calls registered recv callback internally, which could lead to deadlock between TCP/socket mutexes. This commit moves the tcp_conn_close() back where it was originally called. I've verified that the thread safety is still solid with the test apps used originally. Signed-off-by: Robert Lubos --- subsys/net/ip/tcp.c | 14 ++++++++------ 1 file changed, 8 insertions(+), 6 deletions(-) diff --git a/subsys/net/ip/tcp.c b/subsys/net/ip/tcp.c index 50972a9211b..7efdddc2cc6 100644 --- a/subsys/net/ip/tcp.c +++ b/subsys/net/ip/tcp.c @@ -3392,12 +3392,7 @@ static enum net_verdict tcp_in(struct tcp *conn, struct net_pkt *pkt) goto next_state; } - /* Make sure we close the connection only once by checking connection - * state. - */ - if (do_close && conn->state != TCP_UNUSED && conn->state != TCP_CLOSED) { - tcp_conn_close(conn, close_status); - } else if (conn->context) { + if (conn->context) { /* If the conn->context is not set, then the connection was * already closed. */ @@ -3423,6 +3418,13 @@ static enum net_verdict tcp_in(struct tcp *conn, struct net_pkt *pkt) } } + /* Make sure we close the connection only once by checking connection + * state. + */ + if (do_close && conn->state != TCP_UNUSED && conn->state != TCP_CLOSED) { + tcp_conn_close(conn, close_status); + } + return verdict; } From 8cb4f09a2872b062cad76c14efdd2e9ac8570787 Mon Sep 17 00:00:00 2001 From: Robert Lubos Date: Mon, 11 Dec 2023 16:54:54 +0100 Subject: [PATCH 1175/3723] net: tcp: Remove pointless recv callback calls Calling the registered receive callback when releasing TCP context doesn't make sense, as at that point the application should've already closed the associated socket (that's one of the conditions for the context to be released). Therefore, remove the pointless receive callback call, while keeping the loop to unref any leftover data packets (although again, I don' think there should be any packets left at that point, as they're all consumed in tcp_in()). Signed-off-by: Robert Lubos --- subsys/net/ip/tcp.c | 12 ++++-------- 1 file changed, 4 insertions(+), 8 deletions(-) diff --git a/subsys/net/ip/tcp.c b/subsys/net/ip/tcp.c index 7efdddc2cc6..23fec86262a 100644 --- a/subsys/net/ip/tcp.c +++ b/subsys/net/ip/tcp.c @@ -714,15 +714,11 @@ static void tcp_conn_release(struct k_work *work) k_mutex_lock(&tcp_lock, K_FOREVER); - /* If there is any pending data, pass that to application */ + /* Application is no longer there, unref any remaining packets on the + * fifo (although there shouldn't be any at this point.) + */ while ((pkt = k_fifo_get(&conn->recv_data, K_NO_WAIT)) != NULL) { - if (net_context_packet_received( - (struct net_conn *)conn->context->conn_handler, - pkt, NULL, NULL, conn->recv_user_data) == - NET_DROP) { - /* Application is no longer there, unref the pkt */ - tcp_pkt_unref(pkt); - } + tcp_pkt_unref(pkt); } k_mutex_lock(&conn->lock, K_FOREVER); From 431da79dfa564b7f716f4b57bd377f16a6e7c70d Mon Sep 17 00:00:00 2001 From: Fabiola Kwasowiec Date: Thu, 7 Dec 2023 16:29:10 +0100 Subject: [PATCH 1176/3723] hda: separation of l1 settings to new function Separating two new functions force and allow l1 to have the current state with separated functions in the ipc file so that SOF can call these functions via IPC DMI_FORCE_L1_EXIT. Change related to the addition of a new parameter to force DMI L1 exit on IPC request. Signed-off-by: Fabiola Kwasowiec --- drivers/dma/dma_intel_adsp_hda.c | 8 ++------ .../intel_adsp/common/include/intel_adsp_hda.h | 15 +++++++++++++++ 2 files changed, 17 insertions(+), 6 deletions(-) diff --git a/drivers/dma/dma_intel_adsp_hda.c b/drivers/dma/dma_intel_adsp_hda.c index 2dd0bea6ed6..7a131db2216 100644 --- a/drivers/dma/dma_intel_adsp_hda.c +++ b/drivers/dma/dma_intel_adsp_hda.c @@ -176,9 +176,7 @@ int intel_adsp_hda_dma_host_reload(const struct device *dev, uint32_t channel, __ASSERT(channel < cfg->dma_channels, "Channel does not exist"); #if CONFIG_DMA_INTEL_ADSP_HDA_TIMING_L1_EXIT -#if CONFIG_SOC_SERIES_INTEL_ACE - ACE_DfPMCCH.svcfg |= ADSP_FORCE_DECOUPLED_HDMA_L1_EXIT_BIT; -#endif + intel_adsp_force_dmi_l0_state(); switch (cfg->direction) { case HOST_TO_MEMORY: ; /* Only statements can be labeled in C, a declaration is not valid */ @@ -458,9 +456,7 @@ void intel_adsp_hda_dma_isr(void) } if (clear_l1_exit) { -#if CONFIG_SOC_SERIES_INTEL_ACE - ACE_DfPMCCH.svcfg &= ~(ADSP_FORCE_DECOUPLED_HDMA_L1_EXIT_BIT); -#endif + intel_adsp_allow_dmi_l1_state(); } #endif } diff --git a/soc/xtensa/intel_adsp/common/include/intel_adsp_hda.h b/soc/xtensa/intel_adsp/common/include/intel_adsp_hda.h index 2b403eb17a4..9a123a71b15 100644 --- a/soc/xtensa/intel_adsp/common/include/intel_adsp_hda.h +++ b/soc/xtensa/intel_adsp/common/include/intel_adsp_hda.h @@ -10,6 +10,7 @@ #include #include #include +#include /** * @brief HDA stream functionality for Intel ADSP @@ -441,6 +442,20 @@ static inline void intel_adsp_hda_disable_buffer_interrupt(uint32_t base, uint32 *DGCS(base, regblock_size, sid) &= ~DGCS_BSCIE; } +static inline void intel_adsp_force_dmi_l0_state(void) +{ +#ifdef CONFIG_SOC_SERIES_INTEL_ACE + ACE_DfPMCCH.svcfg |= ADSP_FORCE_DECOUPLED_HDMA_L1_EXIT_BIT; +#endif +} + +static inline void intel_adsp_allow_dmi_l1_state(void) +{ +#ifdef CONFIG_SOC_SERIES_INTEL_ACE + ACE_DfPMCCH.svcfg &= ~(ADSP_FORCE_DECOUPLED_HDMA_L1_EXIT_BIT); +#endif +} + /** * @brief Clear BSC interrupt * From c758f1cc147da100d346d5f7db26293fca1bcd46 Mon Sep 17 00:00:00 2001 From: Marc Desvaux Date: Mon, 6 Nov 2023 09:25:47 +0100 Subject: [PATCH 1177/3723] drivers: usb: device: usb_dc_stm32 issue USB drivers Isochronous endpoint issue with USB drivers on STM32G491 we setup an isochronous endpoint and are having an issue where every other frame sends the desired data sandwiched between garbage data. For isochronous the parameter ep_kind into the fonction : HAL_PCDEx_PMAConfig(PCD_HandleTypeDef *hpcd, uint16_t ep_addr, uint16_t ep_kind, uint32_t pmaadress) must be PCD_DBL_BUF. The parameter pmaadress (EP address in The PMA) is like that: EP address in The PMA: In case of single buffer endpoint this parameter is 16-bit value providing the address in PMA allocated to endpoint. In case of double buffer endpoint this parameter is a 32-bit value providing the endpoint buffer 0 address in the LSB part of 32-bit value and endpoint buffer 1 address in the MSB part of 32-bit value. Signed-off-by: Marc Desvaux --- drivers/usb/device/usb_dc_stm32.c | 35 ++++++++++++++++++++++++------- 1 file changed, 27 insertions(+), 8 deletions(-) diff --git a/drivers/usb/device/usb_dc_stm32.c b/drivers/usb/device/usb_dc_stm32.c index de0a8bc2a27..fe2c0b65f5d 100644 --- a/drivers/usb/device/usb_dc_stm32.c +++ b/drivers/usb/device/usb_dc_stm32.c @@ -639,20 +639,39 @@ int usb_dc_ep_configure(const struct usb_dc_ep_cfg_data * const ep_cfg) LOG_DBG("ep 0x%02x, previous ep_mps %u, ep_mps %u, ep_type %u", ep_cfg->ep_addr, ep_state->ep_mps, ep_cfg->ep_mps, ep_cfg->ep_type); - #if defined(USB) || defined(USB_DRD_FS) if (ep_cfg->ep_mps > ep_state->ep_pma_buf_len) { - if (USB_RAM_SIZE <= - (usb_dc_stm32_state.pma_offset + ep_cfg->ep_mps)) { + if (ep_cfg->ep_type == USB_DC_EP_ISOCHRONOUS) { + if (USB_RAM_SIZE <= + (usb_dc_stm32_state.pma_offset + ep_cfg->ep_mps*2)) { + return -EINVAL; + } + } else if (USB_RAM_SIZE <= + (usb_dc_stm32_state.pma_offset + ep_cfg->ep_mps)) { return -EINVAL; } - HAL_PCDEx_PMAConfig(&usb_dc_stm32_state.pcd, ep, PCD_SNG_BUF, - usb_dc_stm32_state.pma_offset); - ep_state->ep_pma_buf_len = ep_cfg->ep_mps; - usb_dc_stm32_state.pma_offset += ep_cfg->ep_mps; + + if (ep_cfg->ep_type == USB_DC_EP_ISOCHRONOUS) { + HAL_PCDEx_PMAConfig(&usb_dc_stm32_state.pcd, ep, PCD_DBL_BUF, + usb_dc_stm32_state.pma_offset + + ((usb_dc_stm32_state.pma_offset + ep_cfg->ep_mps) << 16)); + ep_state->ep_pma_buf_len = ep_cfg->ep_mps*2; + usb_dc_stm32_state.pma_offset += ep_cfg->ep_mps*2; + } else { + HAL_PCDEx_PMAConfig(&usb_dc_stm32_state.pcd, ep, PCD_SNG_BUF, + usb_dc_stm32_state.pma_offset); + ep_state->ep_pma_buf_len = ep_cfg->ep_mps; + usb_dc_stm32_state.pma_offset += ep_cfg->ep_mps; + } } -#endif + if (ep_cfg->ep_type == USB_DC_EP_ISOCHRONOUS) { + ep_state->ep_mps = ep_cfg->ep_mps*2; + } else { + ep_state->ep_mps = ep_cfg->ep_mps; + } +#else ep_state->ep_mps = ep_cfg->ep_mps; +#endif switch (ep_cfg->ep_type) { case USB_DC_EP_CONTROL: From fbfd36e81e2aa2dcd9699faf69645c1f60374aac Mon Sep 17 00:00:00 2001 From: Kevin ORourke Date: Fri, 24 Nov 2023 12:16:11 +0100 Subject: [PATCH 1178/3723] drivers: clock_control: stm32: Add HSE CSS support Add support for enabling the clock security system, which can detect failures of the HSE clock. Includes tests for nucleo_h743zi and nucleo_g474re. Signed-off-by: Kevin ORourke --- drivers/clock_control/Kconfig.stm32 | 2 ++ drivers/clock_control/clock_stm32_ll_common.c | 15 +++++++++++++++ drivers/clock_control/clock_stm32_ll_h7.c | 15 +++++++++++++++ dts/bindings/clock/st,stm32-hse-clock.yaml | 16 ++++++++++++++++ .../drivers/clock_control/stm32_clock_control.h | 13 +++++++++++++ .../stm32_common_core/boards/hse_css.overlay | 14 ++++++++++++++ .../src/test_stm32_clock_configuration.c | 13 +++++++++++++ .../stm32_common_core/testcase.yaml | 4 ++++ .../stm32h7_core/boards/hse_css.overlay | 14 ++++++++++++++ .../src/test_stm32_clock_configuration.c | 13 +++++++++++++ .../stm32h7_core/testcase.yaml | 6 ++++++ 11 files changed, 125 insertions(+) create mode 100644 tests/drivers/clock_control/stm32_clock_configuration/stm32_common_core/boards/hse_css.overlay create mode 100644 tests/drivers/clock_control/stm32_clock_configuration/stm32h7_core/boards/hse_css.overlay diff --git a/drivers/clock_control/Kconfig.stm32 b/drivers/clock_control/Kconfig.stm32 index 8d7890d1fdf..cccbe5e2e74 100644 --- a/drivers/clock_control/Kconfig.stm32 +++ b/drivers/clock_control/Kconfig.stm32 @@ -10,6 +10,8 @@ menuconfig CLOCK_CONTROL_STM32_CUBE select USE_STM32_LL_UTILS select USE_STM32_LL_RCC if (SOC_SERIES_STM32MP1X || SOC_SERIES_STM32H7X || \ SOC_SERIES_STM32F4X || SOC_SERIES_STM32F7X) + select RUNTIME_NMI if ($(dt_nodelabel_enabled,clk_hse) && \ + $(dt_nodelabel_has_prop,clk_hse,css-enabled)) help Enable driver for Reset & Clock Control subsystem found in STM32 family of MCUs diff --git a/drivers/clock_control/clock_stm32_ll_common.c b/drivers/clock_control/clock_stm32_ll_common.c index ba5ba2e4673..d3adbe62535 100644 --- a/drivers/clock_control/clock_stm32_ll_common.c +++ b/drivers/clock_control/clock_stm32_ll_common.c @@ -567,6 +567,11 @@ static void set_up_fixed_clock_sources(void) while (LL_RCC_HSE_IsReady() != 1) { /* Wait for HSE ready */ } + /* Check if we need to enable HSE clock security system or not */ +#if STM32_HSE_CSS + z_arm_nmi_set_handler(HAL_RCC_NMI_IRQHandler); + LL_RCC_HSE_EnableCSS(); +#endif /* STM32_HSE_CSS */ } if (IS_ENABLED(STM32_HSI_ENABLED)) { @@ -817,6 +822,16 @@ int stm32_clock_control_init(const struct device *dev) return 0; } +#if defined(STM32_HSE_CSS) +void __weak stm32_hse_css_callback(void) {} + +/* Called by the HAL in response to an HSE CSS interrupt */ +void HAL_RCC_CSSCallback(void) +{ + stm32_hse_css_callback(); +} +#endif + /** * @brief RCC device, note that priority is intentionally set to 1 so * that the device init runs just after SOC init diff --git a/drivers/clock_control/clock_stm32_ll_h7.c b/drivers/clock_control/clock_stm32_ll_h7.c index dc9127d277d..23856ff7e2d 100644 --- a/drivers/clock_control/clock_stm32_ll_h7.c +++ b/drivers/clock_control/clock_stm32_ll_h7.c @@ -586,6 +586,11 @@ static void set_up_fixed_clock_sources(void) LL_RCC_HSE_Enable(); while (LL_RCC_HSE_IsReady() != 1) { } + /* Check if we need to enable HSE clock security system or not */ +#if STM32_HSE_CSS + z_arm_nmi_set_handler(HAL_RCC_NMI_IRQHandler); + LL_RCC_HSE_EnableCSS(); +#endif /* STM32_HSE_CSS */ } if (IS_ENABLED(STM32_HSI_ENABLED)) { @@ -930,6 +935,16 @@ int stm32_clock_control_init(const struct device *dev) } #endif /* CONFIG_CPU_CORTEX_M7 */ +#if defined(STM32_HSE_CSS) +void __weak stm32_hse_css_callback(void) {} + +/* Called by the HAL in response to an HSE CSS interrupt */ +void HAL_RCC_CSSCallback(void) +{ + stm32_hse_css_callback(); +} +#endif + /** * @brief RCC device, note that priority is intentionally set to 1 so * that the device init runs just after SOC init diff --git a/dts/bindings/clock/st,stm32-hse-clock.yaml b/dts/bindings/clock/st,stm32-hse-clock.yaml index 833a393595d..45cfa050c50 100644 --- a/dts/bindings/clock/st,stm32-hse-clock.yaml +++ b/dts/bindings/clock/st,stm32-hse-clock.yaml @@ -13,3 +13,19 @@ properties: description: | HSE crystal oscillator bypass Set to the property to by-pass the oscillator with an external clock. + + css-enabled: + type: boolean + description: | + HSE clock security system enabled + Set the property to enable the clock security system (CSS) for the HSE clock. + + If a failure is detected on the HSE clock, the HSE oscillator is automatically disabled, + a clock failure event is sent to timers, and a non-maskable interrupt is generated to + inform the software about the failure, allowing the MCU to perform rescue operations. + See the MCU reference manual for details. + + The interaction of CSS and low-power modes is unclear from the documentation. + For at least some devices Zephyr will reconfigure the clocks on resuming from low-power + modes; this will include re-enabling CSS. However it is important that you verify + this for your own hardware. diff --git a/include/zephyr/drivers/clock_control/stm32_clock_control.h b/include/zephyr/drivers/clock_control/stm32_clock_control.h index f18c351c0d5..062fae034e3 100644 --- a/include/zephyr/drivers/clock_control/stm32_clock_control.h +++ b/include/zephyr/drivers/clock_control/stm32_clock_control.h @@ -369,6 +369,7 @@ #define STM32_HSE_ENABLED 1 #define STM32_HSE_BYPASS DT_PROP(DT_NODELABEL(clk_hse), hse_bypass) #define STM32_HSE_FREQ DT_PROP(DT_NODELABEL(clk_hse), clock_frequency) +#define STM32_HSE_CSS DT_PROP(DT_NODELABEL(clk_hse), css_enabled) #elif DT_NODE_HAS_COMPAT_STATUS(DT_NODELABEL(clk_hse), st_stm32wl_hse_clock, okay) #define STM32_HSE_ENABLED 1 #define STM32_HSE_TCXO DT_PROP(DT_NODELABEL(clk_hse), hse_tcxo) @@ -460,4 +461,16 @@ struct stm32_pclken { #define STM32_CLOCK_VAL_GET(clock) \ (((clock) >> STM32_CLOCK_VAL_SHIFT) & STM32_CLOCK_VAL_MASK) +#if defined(STM32_HSE_CSS) +/** + * @brief Called if the HSE clock security system detects a clock fault. + * + * The function is called in interrupt context. + * + * The default (weakly-linked) implementation does nothing and should be + * overridden. + */ +void stm32_hse_css_callback(void); +#endif + #endif /* ZEPHYR_INCLUDE_DRIVERS_CLOCK_CONTROL_STM32_CLOCK_CONTROL_H_ */ diff --git a/tests/drivers/clock_control/stm32_clock_configuration/stm32_common_core/boards/hse_css.overlay b/tests/drivers/clock_control/stm32_clock_configuration/stm32_common_core/boards/hse_css.overlay new file mode 100644 index 00000000000..e1da83b1fcc --- /dev/null +++ b/tests/drivers/clock_control/stm32_clock_configuration/stm32_common_core/boards/hse_css.overlay @@ -0,0 +1,14 @@ +/* + * Copyright (c) 2023 Ferroamp AB (publ) + * + * SPDX-License-Identifier: Apache-2.0 + */ + +/* + * Warning: This overlay assumes the HSE clock has already been enabled, + * for example by hse_24.overlay. + */ + +&clk_hse { + css-enabled; +}; diff --git a/tests/drivers/clock_control/stm32_clock_configuration/stm32_common_core/src/test_stm32_clock_configuration.c b/tests/drivers/clock_control/stm32_clock_configuration/stm32_common_core/src/test_stm32_clock_configuration.c index 9b4591e0613..46571164776 100644 --- a/tests/drivers/clock_control/stm32_clock_configuration/stm32_common_core/src/test_stm32_clock_configuration.c +++ b/tests/drivers/clock_control/stm32_clock_configuration/stm32_common_core/src/test_stm32_clock_configuration.c @@ -105,4 +105,17 @@ ZTEST(stm32_sysclck_config, test_pll_src) #endif } + +#if STM32_HSE_ENABLED +ZTEST(stm32_sysclck_config, test_hse_css) +{ + /* there is no function to read CSS status, so read directly from the register */ +#if STM32_HSE_CSS + zassert_true(READ_BIT(RCC->CR, RCC_CR_CSSON), "HSE CSS is not enabled"); +#else + zassert_false(READ_BIT(RCC->CR, RCC_CR_CSSON), "HSE CSS unexpectedly enabled"); +#endif /* STM32_HSE_CSS */ + +} +#endif /* STM32_HSE_ENABLED */ ZTEST_SUITE(stm32_sysclck_config, NULL, NULL, NULL, NULL, NULL); diff --git a/tests/drivers/clock_control/stm32_clock_configuration/stm32_common_core/testcase.yaml b/tests/drivers/clock_control/stm32_clock_configuration/stm32_common_core/testcase.yaml index 563108bfe91..dbc0f6722ea 100644 --- a/tests/drivers/clock_control/stm32_clock_configuration/stm32_common_core/testcase.yaml +++ b/tests/drivers/clock_control/stm32_clock_configuration/stm32_common_core/testcase.yaml @@ -114,6 +114,10 @@ tests: drivers.clock.stm32_clock_configuration.common_core.g4.sysclksrc_hse_24: extra_args: DTC_OVERLAY_FILE="boards/clear_clocks.overlay;boards/hse_24.overlay" platform_allow: nucleo_g474re + drivers.clock.stm32_clock_configuration.common_core.g4.sysclksrc_hse_24.css: + extra_args: + DTC_OVERLAY_FILE="boards/clear_clocks.overlay;boards/hse_24.overlay;boards/hse_css.overlay" + platform_allow: nucleo_g474re drivers.clock.stm32_clock_configuration.common_core.l0_l1.sysclksrc_hse_8: extra_args: DTC_OVERLAY_FILE="boards/clear_clocks.overlay;boards/clear_msi.overlay;boards/hse_8.overlay" diff --git a/tests/drivers/clock_control/stm32_clock_configuration/stm32h7_core/boards/hse_css.overlay b/tests/drivers/clock_control/stm32_clock_configuration/stm32h7_core/boards/hse_css.overlay new file mode 100644 index 00000000000..3fb213cbc4a --- /dev/null +++ b/tests/drivers/clock_control/stm32_clock_configuration/stm32h7_core/boards/hse_css.overlay @@ -0,0 +1,14 @@ +/* + * Copyright (c) 2023 Ferroamp AB (publ) + * + * SPDX-License-Identifier: Apache-2.0 + */ + +/* + * Warning: This overlay assumes the HSE clock has already been enabled, + * for example by hse_8.overlay. + */ + +&clk_hse { + css-enabled; +}; diff --git a/tests/drivers/clock_control/stm32_clock_configuration/stm32h7_core/src/test_stm32_clock_configuration.c b/tests/drivers/clock_control/stm32_clock_configuration/stm32h7_core/src/test_stm32_clock_configuration.c index 596edb90280..360fa4877ca 100644 --- a/tests/drivers/clock_control/stm32_clock_configuration/stm32h7_core/src/test_stm32_clock_configuration.c +++ b/tests/drivers/clock_control/stm32_clock_configuration/stm32h7_core/src/test_stm32_clock_configuration.c @@ -76,4 +76,17 @@ ZTEST(stm32_syclck_config, test_pll_src) #endif } + +#if STM32_HSE_ENABLED +ZTEST(stm32_syclck_config, test_hse_css) +{ + /* there is no function to read CSS status, so read directly from the register */ +#if STM32_HSE_CSS + zassert_true(READ_BIT(RCC->CR, RCC_CR_CSSHSEON), "HSE CSS is not enabled"); +#else + zassert_false(READ_BIT(RCC->CR, RCC_CR_CSSHSEON), "HSE CSS unexpectedly enabled"); +#endif /* STM32_HSE_CSS */ + +} +#endif /* STM32_HSE_ENABLED */ ZTEST_SUITE(stm32_syclck_config, NULL, NULL, NULL, NULL, NULL); diff --git a/tests/drivers/clock_control/stm32_clock_configuration/stm32h7_core/testcase.yaml b/tests/drivers/clock_control/stm32_clock_configuration/stm32h7_core/testcase.yaml index f134f811906..8b868d3618a 100644 --- a/tests/drivers/clock_control/stm32_clock_configuration/stm32h7_core/testcase.yaml +++ b/tests/drivers/clock_control/stm32_clock_configuration/stm32h7_core/testcase.yaml @@ -28,6 +28,12 @@ tests: platform_allow: nucleo_h743zi integration_platforms: - nucleo_h743zi + drivers.clock.stm32_clock_configuration.h7_core.sysclksrc_hse_8_css: + extra_args: + DTC_OVERLAY_FILE="boards/clear_clocks.overlay;boards/hse_8.overlay;boards/hse_css.overlay" + platform_allow: nucleo_h743zi + integration_platforms: + - nucleo_h743zi drivers.clock.stm32_clock_configuration.h7_core.sysclksrc_pll_csi_96: extra_args: DTC_OVERLAY_FILE="boards/clear_clocks.overlay;boards/pll_csi_96.overlay" platform_allow: nucleo_h743zi From 13df15845e9b80e53d68ec71959ad0a05c40f916 Mon Sep 17 00:00:00 2001 From: Marc Herbert Date: Fri, 1 Dec 2023 00:23:22 +0000 Subject: [PATCH 1179/3723] cmake: drop ERROR_QUIET in python.cmake ERROR_QUIET should be used only when the command is actually expected to fail, otherwise discarding stderr can be extremely time-consuming. See recent example of time lost in commit 40c2e08e8211 ("xcc/cmake: don't discard stderr; don't (ever!) use ERROR_QUIET") If some Python interpreter cannot even evaluate `sys.version_info[:2]`, then we definitely don't want to hide what its stderr says about that. Fixes commit 94de3e9f60dc ("cmake: FindPython3: Adjust python3 program search") Signed-off-by: Marc Herbert --- cmake/modules/python.cmake | 1 - 1 file changed, 1 deletion(-) diff --git a/cmake/modules/python.cmake b/cmake/modules/python.cmake index 78a29959b8b..6fc765f8f58 100644 --- a/cmake/modules/python.cmake +++ b/cmake/modules/python.cmake @@ -31,7 +31,6 @@ if(NOT Python3_EXECUTABLE) "import sys; sys.stdout.write('.'.join([str(x) for x in sys.version_info[:2]]))" RESULT_VARIABLE result OUTPUT_VARIABLE version - ERROR_QUIET OUTPUT_STRIP_TRAILING_WHITESPACE) if(version VERSION_LESS PYTHON_MINIMUM_REQUIRED) From 7afeb62e209258ddf6d0765bf387a757c3b087c8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?J=C4=99drzej=20Ciupis?= Date: Tue, 21 Nov 2023 14:49:42 +0100 Subject: [PATCH 1180/3723] drivers: ieee802154: support Key Identifier Mode > 1 MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit IEEE 802.15.4-2020 defines four possible values for Key Identifier Mode field of the Auxiliary Security Header. The current ieee802154 driver API only supports two of them: b00 and b01. This commit adds support for the two remaining Key Identifier Mode values. It's done by replacing a field that can only hold Key Index into a field that can holds a pointer to the entire Key Identifier field. See IEEE 802.15.4-2020, sections 9.4.2.3 and 9.4.4 for further reference. Signed-off-by: Jędrzej Ciupis --- drivers/ieee802154/ieee802154_nrf5.c | 26 +++++++------------------- include/zephyr/net/ieee802154_radio.h | 7 ++++++- modules/openthread/platform/radio.c | 27 ++++++++++++++++++--------- 3 files changed, 31 insertions(+), 29 deletions(-) diff --git a/drivers/ieee802154/ieee802154_nrf5.c b/drivers/ieee802154/ieee802154_nrf5.c index dd32f633364..df01f530abf 100644 --- a/drivers/ieee802154/ieee802154_nrf5.c +++ b/drivers/ieee802154/ieee802154_nrf5.c @@ -781,25 +781,17 @@ static void nrf5_iface_init(struct net_if *iface) #if defined(CONFIG_NRF_802154_ENCRYPTION) static void nrf5_config_mac_keys(struct ieee802154_key *mac_keys) { - static nrf_802154_key_id_t stored_key_ids[NRF_802154_SECURITY_KEY_STORAGE_SIZE]; - static uint8_t stored_ids[NRF_802154_SECURITY_KEY_STORAGE_SIZE]; - uint8_t i; + nrf_802154_security_key_remove_all(); - for (i = 0; i < NRF_802154_SECURITY_KEY_STORAGE_SIZE && stored_key_ids[i].p_key_id; i++) { - nrf_802154_security_key_remove(&stored_key_ids[i]); - stored_key_ids[i].p_key_id = NULL; - } - - i = 0; - for (struct ieee802154_key *keys = mac_keys; keys->key_value - && i < NRF_802154_SECURITY_KEY_STORAGE_SIZE; keys++, i++) { + for (uint8_t i = 0; mac_keys->key_value + && i < NRF_802154_SECURITY_KEY_STORAGE_SIZE; mac_keys++, i++) { nrf_802154_key_t key = { - .value.p_cleartext_key = keys->key_value, - .id.mode = keys->key_id_mode, - .id.p_key_id = &(keys->key_index), + .value.p_cleartext_key = mac_keys->key_value, + .id.mode = mac_keys->key_id_mode, + .id.p_key_id = mac_keys->key_id, .type = NRF_802154_KEY_CLEARTEXT, .frame_counter = 0, - .use_global_frame_counter = !(keys->frame_counter_per_key), + .use_global_frame_counter = !(mac_keys->frame_counter_per_key), }; __ASSERT_EVAL((void)nrf_802154_security_key_store(&key), @@ -807,10 +799,6 @@ static void nrf5_config_mac_keys(struct ieee802154_key *mac_keys) err == NRF_802154_SECURITY_ERROR_NONE || err == NRF_802154_SECURITY_ERROR_ALREADY_PRESENT, "Storing key failed, err: %d", err); - - stored_ids[i] = *key.id.p_key_id; - stored_key_ids[i].mode = key.id.mode; - stored_key_ids[i].p_key_id = &stored_ids[i]; }; } #endif /* CONFIG_NRF_802154_ENCRYPTION */ diff --git a/include/zephyr/net/ieee802154_radio.h b/include/zephyr/net/ieee802154_radio.h index 59608fac391..de0cf89da4c 100644 --- a/include/zephyr/net/ieee802154_radio.h +++ b/include/zephyr/net/ieee802154_radio.h @@ -592,11 +592,16 @@ struct ieee802154_filter { * IEEE802154_CONFIG_MAC_KEYS. */ struct ieee802154_key { + /** Key material */ uint8_t *key_value; + /** Initial value of frame counter associated with the key, see section 9.4.3 */ uint32_t key_frame_counter; + /** Indicates if per-key frame counter should be used, see section 9.4.3 */ bool frame_counter_per_key; + /** Key Identifier Mode, see section 9.4.2.3, Table 9-7 */ uint8_t key_id_mode; - uint8_t key_index; + /** Key Identifier, see section 9.4.4 */ + uint8_t *key_id; }; /** IEEE 802.15.4 Transmission mode. */ diff --git a/modules/openthread/platform/radio.c b/modules/openthread/platform/radio.c index 62b26ae1076..631d00bdca6 100644 --- a/modules/openthread/platform/radio.c +++ b/modules/openthread/platform/radio.c @@ -1192,20 +1192,14 @@ void otPlatRadioSetMacKey(otInstance *aInstance, uint8_t aKeyIdMode, uint8_t aKe struct ieee802154_key keys[] = { { .key_id_mode = key_id_mode, - .key_index = aKeyId == 1 ? 0x80 : aKeyId - 1, - .key_value = (uint8_t *)aPrevKey->mKeyMaterial.mKey.m8, .frame_counter_per_key = false, }, { .key_id_mode = key_id_mode, - .key_index = aKeyId, - .key_value = (uint8_t *)aCurrKey->mKeyMaterial.mKey.m8, .frame_counter_per_key = false, }, { .key_id_mode = key_id_mode, - .key_index = aKeyId == 0x80 ? 1 : aKeyId + 1, - .key_value = (uint8_t *)aNextKey->mKeyMaterial.mKey.m8, .frame_counter_per_key = false, }, { @@ -1219,9 +1213,24 @@ void otPlatRadioSetMacKey(otInstance *aInstance, uint8_t aKeyIdMode, uint8_t aKe }, }; - /* aKeyId in range: (1, 0x80) means valid keys - * aKeyId == 0 is used only to clear keys for stack reset in RCP - */ + if (key_id_mode == 1) { + /* aKeyId in range: (1, 0x80) means valid keys */ + uint8_t prev_key_id = aKeyId == 1 ? 0x80 : aKeyId - 1; + uint8_t next_key_id = aKeyId == 0x80 ? 1 : aKeyId + 1; + + keys[0].key_id = &prev_key_id; + keys[0].key_value = (uint8_t *)aPrevKey->mKeyMaterial.mKey.m8; + + keys[1].key_id = &aKeyId; + keys[1].key_value = (uint8_t *)aCurrKey->mKeyMaterial.mKey.m8; + + keys[2].key_id = &next_key_id; + keys[2].key_value = (uint8_t *)aNextKey->mKeyMaterial.mKey.m8; + } else { + /* aKeyId == 0 is used only to clear keys for stack reset in RCP */ + __ASSERT_NO_MSG((key_id_mode == 0) && (aKeyId == 0)); + } + struct ieee802154_config config = { .mac_keys = aKeyId == 0 ? clear_keys : keys, }; From 00f7c0e445d43b3e460aea6b7894f833dd469e2e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?J=C4=99drzej=20Ciupis?= Date: Mon, 4 Dec 2023 10:19:11 +0100 Subject: [PATCH 1181/3723] modules: hal_nordic: nrf_802154: remove magic number MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This commit replaces a magic number in the definition of serialization ring buffer length with a macro provided by the 802.15.4 driver. Signed-off-by: Jędrzej Ciupis --- .../serialization/platform/nrf_802154_spinel_backend_ipc.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/modules/hal_nordic/nrf_802154/serialization/platform/nrf_802154_spinel_backend_ipc.c b/modules/hal_nordic/nrf_802154/serialization/platform/nrf_802154_spinel_backend_ipc.c index 8a9cd8739b2..b2629eef67b 100644 --- a/modules/hal_nordic/nrf_802154/serialization/platform/nrf_802154_spinel_backend_ipc.c +++ b/modules/hal_nordic/nrf_802154/serialization/platform/nrf_802154_spinel_backend_ipc.c @@ -9,6 +9,7 @@ #include #include +#include "nrf_802154.h" #include "nrf_802154_spinel_backend_callouts.h" #include "nrf_802154_serialization_error.h" #include "../../spinel_base/spinel.h" @@ -74,7 +75,7 @@ nrf_802154_ser_err_t nrf_802154_backend_init(void) #define SEND_THREAD_STACK_SIZE 1024 /* Make the ring buffer long enough to hold all notifications that the driver can produce */ -#define RING_BUFFER_LEN (CONFIG_NRF_802154_RX_BUFFERS + 10) +#define RING_BUFFER_LEN (NRF_802154_MAX_PENDING_NOTIFICATIONS + 1) static K_SEM_DEFINE(send_sem, 0, RING_BUFFER_LEN); K_THREAD_STACK_DEFINE(send_thread_stack, SEND_THREAD_STACK_SIZE); From 25d44a828d404422099dfa4d8875438dacf1f38c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Anders=20Storr=C3=B8?= Date: Tue, 12 Dec 2023 13:14:18 +0100 Subject: [PATCH 1182/3723] Bluetooth: Mesh: Rename prov_dev->provisionee MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Renames "prov device" references and options to "provisionee" to align implementation with Mesh Protocol specification v1.1, section 5.4. Signed-off-by: Anders Storrø --- doc/connectivity/bluetooth/api/mesh/shell.rst | 4 +- doc/releases/migration-guide-3.6.rst | 20 ++++-- samples/bluetooth/mesh_provisioner/prj.conf | 2 +- subsys/bluetooth/Kconfig.logging | 2 +- subsys/bluetooth/mesh/CMakeLists.txt | 2 +- subsys/bluetooth/mesh/Kconfig | 15 +++- .../mesh/{prov_device.c => provisionee.c} | 8 +-- subsys/bluetooth/mesh/provisioner.c | 72 +++++++++---------- subsys/bluetooth/mesh/shell/shell.c | 8 +-- tests/bsim/bluetooth/mesh/prj.conf | 2 +- tests/bsim/bluetooth/mesh/prj_mesh1d1.conf | 2 +- 11 files changed, 76 insertions(+), 61 deletions(-) rename subsys/bluetooth/mesh/{prov_device.c => provisionee.c} (99%) diff --git a/doc/connectivity/bluetooth/api/mesh/shell.rst b/doc/connectivity/bluetooth/api/mesh/shell.rst index 9d5829fe380..3d925f29a3e 100644 --- a/doc/connectivity/bluetooth/api/mesh/shell.rst +++ b/doc/connectivity/bluetooth/api/mesh/shell.rst @@ -282,7 +282,7 @@ Provisioning ============ To allow a device to broadcast connectable unprovisioned beacons, the -:kconfig:option:`CONFIG_BT_MESH_PROV_DEVICE` configuration option must be enabled, along with the +:kconfig:option:`CONFIG_BT_MESH_PROVISIONEE` configuration option must be enabled, along with the :kconfig:option:`CONFIG_BT_MESH_PB_GATT` option. ``mesh prov pb-gatt `` @@ -295,7 +295,7 @@ To allow a device to broadcast connectable unprovisioned beacons, the * ``Val``: Enable or disable provisioning with GATT To allow a device to broadcast unprovisioned beacons, the -:kconfig:option:`CONFIG_BT_MESH_PROV_DEVICE` configuration option must be enabled, along with the +:kconfig:option:`CONFIG_BT_MESH_PROVISIONEE` configuration option must be enabled, along with the :kconfig:option:`CONFIG_BT_MESH_PB_ADV` option. ``mesh prov pb-adv `` diff --git a/doc/releases/migration-guide-3.6.rst b/doc/releases/migration-guide-3.6.rst index c72c71b00b9..429ece62724 100644 --- a/doc/releases/migration-guide-3.6.rst +++ b/doc/releases/migration-guide-3.6.rst @@ -195,19 +195,25 @@ Bluetooth cleared on :c:func:`bt_enable`. Callbacks can now be registered before the initial call to :c:func:`bt_enable`, and should no longer be re-registered after a :c:func:`bt_disable` :c:func:`bt_enable` cycle. (:github:`63693`) -* The Bluetooth Mesh ``model`` declaration has been changed to add prefix ``const``. - The ``model->user_data``, ``model->elem_idx`` and ``model->mod_idx`` field has been changed to - the new runtime structure, replaced by ``model->rt->user_data``, ``model->rt->elem_idx`` and - ``model->rt->mod_idx`` separately. (:github:`65152`) -* The Bluetooth Mesh ``element`` declaration has been changed to add prefix ``const``. - The ``elem->addr`` field has been changed to the new runtime structure, replaced by - ``elem->rt->addr``. (:github:`65388`) * The Bluetooth UUID has been modified to rodata in ``BT_UUID_DECLARE_16``, ``BT_UUID_DECLARE_32` and ``BT_UUID_DECLARE_128`` as the return value has been changed to `const`. Any pointer to a UUID must be prefixed with `const`, otherwise there will be a compilation warning. For example change ``struct bt_uuid *uuid = BT_UUID_DECLARE_16(xx)`` to ``const struct bt_uuid *uuid = BT_UUID_DECLARE_16(xx)``. (:github:`66136`) +* Mesh + + * The Bluetooth Mesh ``model`` declaration has been changed to add prefix ``const``. + The ``model->user_data``, ``model->elem_idx`` and ``model->mod_idx`` field has been changed to + the new runtime structure, replaced by ``model->rt->user_data``, ``model->rt->elem_idx`` and + ``model->rt->mod_idx`` separately. (:github:`65152`) + * The Bluetooth Mesh ``element`` declaration has been changed to add prefix ``const``. + The ``elem->addr`` field has been changed to the new runtime structure, replaced by + ``elem->rt->addr``. (:github:`65388`) + * Deprecated :kconfig:option:`CONFIG_BT_MESH_PROV_DEVICE`. This option is + replaced by new option :kconfig:option:`CONFIG_BT_MESH_PROVISIONEE` to + be aligned with Mesh Protocol Specification v1.1, section 5.4. (:github:`64252`) + LoRaWAN ======= diff --git a/samples/bluetooth/mesh_provisioner/prj.conf b/samples/bluetooth/mesh_provisioner/prj.conf index bfc6d5a1241..341dd49ed2e 100644 --- a/samples/bluetooth/mesh_provisioner/prj.conf +++ b/samples/bluetooth/mesh_provisioner/prj.conf @@ -33,7 +33,7 @@ CONFIG_BT_MESH_RELAY=y CONFIG_BT_MESH_RELAY_RETRANSMIT_COUNT=3 CONFIG_BT_MESH_PROVISIONER=y -CONFIG_BT_MESH_PROV_DEVICE=n +CONFIG_BT_MESH_PROVISIONEE=n CONFIG_BT_MESH_CDB=y CONFIG_BT_MESH_CDB_NODE_COUNT=16 CONFIG_BT_MESH_CDB_SUBNET_COUNT=3 diff --git a/subsys/bluetooth/Kconfig.logging b/subsys/bluetooth/Kconfig.logging index 0da05c687fd..5a7032723fc 100644 --- a/subsys/bluetooth/Kconfig.logging +++ b/subsys/bluetooth/Kconfig.logging @@ -1012,7 +1012,7 @@ legacy-debug-sym = BT_MESH_DEBUG_PROVISIONER module-str = "Provisioner" source "subsys/bluetooth/common/Kconfig.template.log_config_bt" -module = BT_MESH_PROV_DEVICE +module = BT_MESH_PROVISIONEE legacy-debug-sym = BT_MESH_DEBUG_PROV_DEVICE module-str = "Provisioning device" source "subsys/bluetooth/common/Kconfig.template.log_config_bt" diff --git a/subsys/bluetooth/mesh/CMakeLists.txt b/subsys/bluetooth/mesh/CMakeLists.txt index 3fd2e7c3bfc..fe4444b28ab 100644 --- a/subsys/bluetooth/mesh/CMakeLists.txt +++ b/subsys/bluetooth/mesh/CMakeLists.txt @@ -40,7 +40,7 @@ zephyr_library_sources_ifdef(CONFIG_BT_MESH_FRIEND friend.c) zephyr_library_sources_ifdef(CONFIG_BT_MESH_PROV prov.c) -zephyr_library_sources_ifdef(CONFIG_BT_MESH_PROV_DEVICE prov_device.c) +zephyr_library_sources_ifdef(CONFIG_BT_MESH_PROVISIONEE provisionee.c) zephyr_library_sources_ifdef(CONFIG_BT_MESH_PROVISIONER provisioner.c) diff --git a/subsys/bluetooth/mesh/Kconfig b/subsys/bluetooth/mesh/Kconfig index bd453f8f91c..807cb4d1058 100644 --- a/subsys/bluetooth/mesh/Kconfig +++ b/subsys/bluetooth/mesh/Kconfig @@ -240,7 +240,7 @@ config BT_MESH_PB_GATT select BT_MESH_GATT_SERVER select BT_MESH_PROV select BT_MESH_PB_GATT_COMMON - select BT_MESH_PROV_DEVICE + select BT_MESH_PROVISIONEE help Enable this option to allow the device to be provisioned over GATT. @@ -268,7 +268,16 @@ config BT_MESH_PB_GATT_CLIENT endif # BT_CONN config BT_MESH_PROV_DEVICE - bool "Provisioning device role support" + bool "[DEPRECATED] Provisioning device role support" + select DEPRECATED + select BT_MESH_PROVISIONEE + help + Enable this option to allow the device to be provisioned into a mesh network. + The option is marked as deprecated and will be replaced by BT_MESH_PROVISIONEE + option. + +config BT_MESH_PROVISIONEE + bool "Provisionee role support" depends on BT_MESH_PB_ADV || BT_MESH_PB_GATT default y help @@ -276,7 +285,7 @@ config BT_MESH_PROV_DEVICE config BT_MESH_PROV_OOB_PUBLIC_KEY bool "OOB Public key support" - depends on BT_MESH_PROV_DEVICE + depends on BT_MESH_PROVISIONEE help Enable this option if public key is to be exchanged via Out of Band (OOB) technology. diff --git a/subsys/bluetooth/mesh/prov_device.c b/subsys/bluetooth/mesh/provisionee.c similarity index 99% rename from subsys/bluetooth/mesh/prov_device.c rename to subsys/bluetooth/mesh/provisionee.c index 6ca65c2ec63..dcecb5838f0 100644 --- a/subsys/bluetooth/mesh/prov_device.c +++ b/subsys/bluetooth/mesh/provisionee.c @@ -32,9 +32,9 @@ #include "settings.h" #include "rpr.h" -#define LOG_LEVEL CONFIG_BT_MESH_PROV_DEVICE_LOG_LEVEL +#define LOG_LEVEL CONFIG_BT_MESH_PROVISIONEE_LOG_LEVEL #include -LOG_MODULE_REGISTER(bt_mesh_prov_device); +LOG_MODULE_REGISTER(bt_mesh_provisionee); static void reprovision_fail(void); @@ -696,8 +696,8 @@ int bt_mesh_prov_enable(bt_mesh_prov_bearer_t bearers) return -EALREADY; } -#if defined(CONFIG_BT_MESH_PROV_DEVICE_LOG_LEVEL) - if (CONFIG_BT_MESH_PROV_DEVICE_LOG_LEVEL > 2) { +#if defined(CONFIG_BT_MESH_PROVISIONEE_LOG_LEVEL) + if (CONFIG_BT_MESH_PROVISIONEE_LOG_LEVEL > 2) { struct bt_uuid_128 uuid = { .uuid = { BT_UUID_TYPE_128 } }; sys_memcpy_swap(uuid.val, bt_mesh_prov->uuid, 16); diff --git a/subsys/bluetooth/mesh/provisioner.c b/subsys/bluetooth/mesh/provisioner.c index ba02723e830..08b3f8bb8f1 100644 --- a/subsys/bluetooth/mesh/provisioner.c +++ b/subsys/bluetooth/mesh/provisioner.c @@ -46,7 +46,7 @@ static struct { uint8_t attention_duration; uint8_t uuid[16]; uint8_t new_dev_key[16]; -} prov_device; +} provisionee; static void send_pub_key(void); static void prov_dh_key_gen(void); @@ -54,8 +54,8 @@ static void prov_dh_key_gen(void); static int reset_state(void) { if (!atomic_test_bit(bt_mesh_prov_link.flags, REPROVISION) && - prov_device.node != NULL) { - bt_mesh_cdb_node_del(prov_device.node, false); + provisionee.node != NULL) { + bt_mesh_cdb_node_del(provisionee.node, false); } return bt_mesh_prov_reset_state(); @@ -86,9 +86,9 @@ static void send_invite(void) LOG_DBG(""); bt_mesh_prov_buf_init(&inv, PROV_INVITE); - net_buf_simple_add_u8(&inv, prov_device.attention_duration); + net_buf_simple_add_u8(&inv, provisionee.attention_duration); - memcpy(bt_mesh_prov_link.conf_inputs.invite, &prov_device.attention_duration, + memcpy(bt_mesh_prov_link.conf_inputs.invite, &provisionee.attention_duration, PDU_LEN_INVITE); if (bt_mesh_prov_send(&inv, NULL)) { @@ -246,8 +246,8 @@ static void prov_capabilities(const uint8_t *data) LOG_DBG("Input OOB Size: %u", caps.input_size); LOG_DBG("Input OOB Action: 0x%04x", caps.input_actions); - prov_device.elem_count = caps.elem_count; - if (prov_device.elem_count == 0) { + provisionee.elem_count = caps.elem_count; + if (provisionee.elem_count == 0) { LOG_ERR("Invalid number of elements"); prov_fail(PROV_ERR_NVAL_FMT); return; @@ -271,7 +271,7 @@ static void prov_capabilities(const uint8_t *data) if (atomic_test_bit(bt_mesh_prov_link.flags, REPROVISION)) { if (!bt_mesh_prov_link.addr) { bt_mesh_prov_link.addr = bt_mesh_cdb_free_addr_get( - prov_device.elem_count); + provisionee.elem_count); if (!bt_mesh_prov_link.addr) { LOG_ERR("Failed allocating address for node"); prov_fail(PROV_ERR_ADDR); @@ -279,19 +279,19 @@ static void prov_capabilities(const uint8_t *data) } } } else { - prov_device.node = - bt_mesh_cdb_node_alloc(prov_device.uuid, + provisionee.node = + bt_mesh_cdb_node_alloc(provisionee.uuid, bt_mesh_prov_link.addr, - prov_device.elem_count, - prov_device.net_idx); - if (prov_device.node == NULL) { + provisionee.elem_count, + provisionee.net_idx); + if (provisionee.node == NULL) { LOG_ERR("Failed allocating node 0x%04x", bt_mesh_prov_link.addr); prov_fail(PROV_ERR_RESOURCES); return; } /* Address might change in the alloc call */ - bt_mesh_prov_link.addr = prov_device.node->addr; + bt_mesh_prov_link.addr = provisionee.node->addr; } memcpy(bt_mesh_prov_link.conf_inputs.capabilities, data, PDU_LEN_CAPABILITIES); @@ -517,16 +517,16 @@ static void send_prov_data(void) LOG_DBG("Nonce: %s", bt_hex(nonce, 13)); err = bt_mesh_dev_key(bt_mesh_prov_link.dhkey, - bt_mesh_prov_link.prov_salt, prov_device.new_dev_key); + bt_mesh_prov_link.prov_salt, provisionee.new_dev_key); if (err) { LOG_ERR("Unable to generate device key"); prov_fail(PROV_ERR_UNEXP_ERR); goto session_key_destructor; } - sub = bt_mesh_cdb_subnet_get(prov_device.node->net_idx); + sub = bt_mesh_cdb_subnet_get(provisionee.node->net_idx); if (sub == NULL) { - LOG_ERR("No subnet with net_idx %u", prov_device.node->net_idx); + LOG_ERR("No subnet with net_idx %u", provisionee.node->net_idx); prov_fail(PROV_ERR_UNEXP_ERR); goto session_key_destructor; } @@ -540,14 +540,14 @@ static void send_prov_data(void) bt_mesh_prov_buf_init(&pdu, PROV_DATA); net_buf_simple_add_mem(&pdu, net_key, sizeof(net_key)); - net_buf_simple_add_be16(&pdu, prov_device.node->net_idx); + net_buf_simple_add_be16(&pdu, provisionee.node->net_idx); net_buf_simple_add_u8(&pdu, bt_mesh_cdb_subnet_flags(sub)); net_buf_simple_add_be32(&pdu, bt_mesh_cdb.iv_index); net_buf_simple_add_be16(&pdu, bt_mesh_prov_link.addr); net_buf_simple_add(&pdu, 8); /* For MIC */ LOG_DBG("net_idx %u, iv_index 0x%08x, addr 0x%04x", - prov_device.node->net_idx, bt_mesh.iv_index, + provisionee.node->net_idx, bt_mesh.iv_index, bt_mesh_prov_link.addr); err = bt_mesh_prov_encrypt(&session_key, nonce, &pdu.data[1], @@ -571,10 +571,10 @@ static void send_prov_data(void) static void prov_complete(const uint8_t *data) { - struct bt_mesh_cdb_node *node = prov_device.node; + struct bt_mesh_cdb_node *node = provisionee.node; LOG_DBG("key %s, net_idx %u, num_elem %u, addr 0x%04x", - bt_hex(&prov_device.new_dev_key, 16), node->net_idx, + bt_hex(&provisionee.new_dev_key, 16), node->net_idx, node->num_elem, node->addr); bt_mesh_prov_link.expect = PROV_NO_PDU; @@ -586,15 +586,15 @@ static void prov_complete(const uint8_t *data) static void prov_node_add(void) { LOG_DBG(""); - struct bt_mesh_cdb_node *node = prov_device.node; + struct bt_mesh_cdb_node *node = provisionee.node; int err; if (atomic_test_bit(bt_mesh_prov_link.flags, REPROVISION)) { bt_mesh_cdb_node_update(node, bt_mesh_prov_link.addr, - prov_device.elem_count); + provisionee.elem_count); } - err = bt_mesh_cdb_node_key_import(node, prov_device.new_dev_key); + err = bt_mesh_cdb_node_key_import(node, provisionee.new_dev_key); if (err) { LOG_ERR("Failed to import node device key"); return; @@ -604,7 +604,7 @@ static void prov_node_add(void) bt_mesh_cdb_node_store(node); } - prov_device.node = NULL; + provisionee.node = NULL; if (bt_mesh_prov->node_added) { bt_mesh_prov->node_added(node->net_idx, node->uuid, node->addr, @@ -807,7 +807,7 @@ static int link_open(const uint8_t *uuid, const struct prov_bearer *bearer, } if (uuid) { - memcpy(prov_device.uuid, uuid, 16); + memcpy(provisionee.uuid, uuid, 16); struct bt_uuid_128 uuid_repr = { .uuid = { BT_UUID_TYPE_128 } }; @@ -823,8 +823,8 @@ static int link_open(const uint8_t *uuid, const struct prov_bearer *bearer, bt_mesh_prov_link.addr = addr; bt_mesh_prov_link.bearer = bearer; bt_mesh_prov_link.role = &role_provisioner; - prov_device.net_idx = net_idx; - prov_device.attention_duration = attention_duration; + provisionee.net_idx = net_idx; + provisionee.attention_duration = attention_duration; err = bt_mesh_prov_link.bearer->link_open( uuid, timeout, bt_mesh_prov_bearer_cb_get(), bearer_cb_data); @@ -877,15 +877,15 @@ static int reprovision_local_client_server(uint16_t addr) } LOG_DBG("net_idx %u iv_index 0x%08x, addr 0x%04x", - prov_device.node->net_idx, bt_mesh_cdb.iv_index, addr); + provisionee.node->net_idx, bt_mesh_cdb.iv_index, addr); atomic_set_bit(bt_mesh_prov_link.flags, REPROVISION); atomic_set_bit(bt_mesh_prov_link.flags, PROVISIONER); bt_mesh_prov_link.addr = addr; bt_mesh_prov_link.bearer = &pb_remote_cli; bt_mesh_prov_link.role = &role_provisioner; - prov_device.net_idx = prov_device.node->net_idx; - prov_device.attention_duration = 0; + provisionee.net_idx = provisionee.node->net_idx; + provisionee.attention_duration = 0; if (IS_ENABLED(CONFIG_BT_MESH_PROV_OOB_PUBLIC_KEY) && bt_mesh_prov->public_key_be && bt_mesh_prov->private_key_be) { @@ -908,13 +908,13 @@ static int reprovision_local_client_server(uint16_t addr) LOG_DBG("DHkey: %s", bt_hex(bt_mesh_prov_link.dhkey, DH_KEY_SIZE)); err = bt_mesh_dev_key(bt_mesh_prov_link.dhkey, - bt_mesh_prov_link.prov_salt, prov_device.new_dev_key); + bt_mesh_prov_link.prov_salt, provisionee.new_dev_key); if (err) { LOG_ERR("Unable to generate device key"); return err; } - bt_mesh_dev_key_cand(prov_device.new_dev_key); + bt_mesh_dev_key_cand(provisionee.new_dev_key); /* Mark the link that was never opened as closed. */ atomic_set_bit(bt_mesh_prov_link.flags, COMPLETE); bt_mesh_reprovision(addr); @@ -943,8 +943,8 @@ int bt_mesh_pb_remote_open_node(struct bt_mesh_rpr_cli *cli, ctx.refresh = BT_MESH_RPR_NODE_REFRESH_DEVKEY; } - prov_device.node = bt_mesh_cdb_node_get(srv->addr); - if (!prov_device.node) { + provisionee.node = bt_mesh_cdb_node_get(srv->addr); + if (!provisionee.node) { LOG_ERR("No CDB node for 0x%04x", srv->addr); return -ENOENT; } @@ -954,7 +954,7 @@ int bt_mesh_pb_remote_open_node(struct bt_mesh_rpr_cli *cli, return reprovision_local_client_server(addr); } - return link_open(NULL, &pb_remote_cli, prov_device.node->net_idx, addr, + return link_open(NULL, &pb_remote_cli, provisionee.node->net_idx, addr, 0, &ctx, 0); } #endif diff --git a/subsys/bluetooth/mesh/shell/shell.c b/subsys/bluetooth/mesh/shell/shell.c index bb9892eb355..9a0e5ece5e3 100644 --- a/subsys/bluetooth/mesh/shell/shell.c +++ b/subsys/bluetooth/mesh/shell/shell.c @@ -771,7 +771,7 @@ static int cmd_provision_gatt(const struct shell *sh, size_t argc, } #endif /* CONFIG_BT_MESH_PB_GATT_CLIENT */ -#if defined(CONFIG_BT_MESH_PROV_DEVICE) +#if defined(CONFIG_BT_MESH_PROVISIONEE) static int cmd_pb(bt_mesh_prov_bearer_t bearer, const struct shell *sh, size_t argc, char *argv[]) { @@ -822,7 +822,7 @@ static int cmd_pb_gatt(const struct shell *sh, size_t argc, char *argv[]) return cmd_pb(BT_MESH_PROV_GATT, sh, argc, argv); } #endif /* CONFIG_BT_MESH_PB_GATT */ -#endif /* CONFIG_BT_MESH_PROV_DEVICE */ +#endif /* CONFIG_BT_MESH_PROVISIONEE */ #if defined(CONFIG_BT_MESH_PROVISIONER) static int cmd_remote_pub_key_set(const struct shell *sh, size_t argc, char *argv[]) @@ -1681,14 +1681,14 @@ SHELL_STATIC_SUBCMD_SET_CREATE( SHELL_CMD_ARG(comp-change, NULL, NULL, cmd_comp_change, 1, 0), /* Provisioning operations */ -#if defined(CONFIG_BT_MESH_PROV_DEVICE) +#if defined(CONFIG_BT_MESH_PROVISIONEE) #if defined(CONFIG_BT_MESH_PB_GATT) SHELL_CMD_ARG(pb-gatt, NULL, "", cmd_pb_gatt, 2, 0), #endif #if defined(CONFIG_BT_MESH_PB_ADV) SHELL_CMD_ARG(pb-adv, NULL, "", cmd_pb_adv, 2, 0), #endif -#endif /* CONFIG_BT_MESH_PROV_DEVICE */ +#endif /* CONFIG_BT_MESH_PROVISIONEE */ #if defined(CONFIG_BT_MESH_PROVISIONER) SHELL_CMD(auth-method, &auth_cmds, "Authentication methods", bt_mesh_shell_mdl_cmds_help), diff --git a/tests/bsim/bluetooth/mesh/prj.conf b/tests/bsim/bluetooth/mesh/prj.conf index a45bef89775..e9c719de6d7 100644 --- a/tests/bsim/bluetooth/mesh/prj.conf +++ b/tests/bsim/bluetooth/mesh/prj.conf @@ -37,7 +37,7 @@ CONFIG_BT_MESH_LABEL_COUNT=3 CONFIG_BT_MESH_IV_UPDATE_TEST=y CONFIG_BT_MESH_PB_ADV=y CONFIG_BT_MESH_PROVISIONER=y -CONFIG_BT_MESH_PROV_DEVICE=y +CONFIG_BT_MESH_PROVISIONEE=y CONFIG_BT_MESH_CDB=y CONFIG_BT_MESH_CDB_NODE_COUNT=4 CONFIG_BT_MESH_PROV_OOB_PUBLIC_KEY=y diff --git a/tests/bsim/bluetooth/mesh/prj_mesh1d1.conf b/tests/bsim/bluetooth/mesh/prj_mesh1d1.conf index 11059c03da4..fd0c953226b 100644 --- a/tests/bsim/bluetooth/mesh/prj_mesh1d1.conf +++ b/tests/bsim/bluetooth/mesh/prj_mesh1d1.conf @@ -39,7 +39,7 @@ CONFIG_BT_MESH_LABEL_COUNT=3 CONFIG_BT_MESH_IV_UPDATE_TEST=y CONFIG_BT_MESH_PB_ADV=y CONFIG_BT_MESH_PROVISIONER=y -CONFIG_BT_MESH_PROV_DEVICE=y +CONFIG_BT_MESH_PROVISIONEE=y CONFIG_BT_MESH_CDB=y CONFIG_BT_MESH_CDB_NODE_COUNT=4 CONFIG_BT_MESH_PROV_OOB_PUBLIC_KEY=y From a54a52b0854032b1d296ec16456971b2c8e78859 Mon Sep 17 00:00:00 2001 From: Evan Perry Grove Date: Fri, 8 Dec 2023 14:51:37 -0600 Subject: [PATCH 1183/3723] dts: arm: Add support for STM32F722 SoC The STM32F722 is similar to the STM32F723, but lacks the latter's more advanced USB PHY. Otherwise, they are virtually identical. Signed-off-by: Evan Perry Grove --- dts/arm/st/f7/stm32f722.dtsi | 53 +++++++++++++++++++ dts/arm/st/f7/stm32f722Xe.dtsi | 18 +++++++ dts/arm/st/f7/stm32f723.dtsi | 41 +------------- .../stm32f7/Kconfig.defconfig.stm32f722xx | 15 ++++++ soc/arm/st_stm32/stm32f7/Kconfig.soc | 4 ++ 5 files changed, 91 insertions(+), 40 deletions(-) create mode 100644 dts/arm/st/f7/stm32f722.dtsi create mode 100644 dts/arm/st/f7/stm32f722Xe.dtsi create mode 100644 soc/arm/st_stm32/stm32f7/Kconfig.defconfig.stm32f722xx diff --git a/dts/arm/st/f7/stm32f722.dtsi b/dts/arm/st/f7/stm32f722.dtsi new file mode 100644 index 00000000000..172f1d8e32b --- /dev/null +++ b/dts/arm/st/f7/stm32f722.dtsi @@ -0,0 +1,53 @@ +/* + * Copyright (c) 2023 Evan Perry Grove + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include + +/ { + /* 16KB ITCM @ 0x0, 64KB DTCM @ 0x20000000, + * 176KB SRAM1 @ 0x20010000, 16KB SRAM2 @ 0x2003C00 + */ + + sram0: memory@20010000 { + compatible = "mmio-sram"; + reg = <0x20010000 DT_SIZE_K(192)>; + }; + + dtcm: memory@20000000 { + compatible = "zephyr,memory-region", "arm,dtcm"; + reg = <0x20000000 DT_SIZE_K(64)>; + zephyr,memory-region = "DTCM"; + }; + + itcm: memory@0 { + compatible = "zephyr,memory-region", "arm,itcm"; + reg = <0x00000000 DT_SIZE_K(16)>; + zephyr,memory-region = "ITCM"; + }; + + soc { + compatible = "st,stm32f722", "st,stm32f7", "simple-bus"; + + sdmmc2: sdmmc@40011c00 { + compatible = "st,stm32-sdmmc"; + reg = <0x40011c00 0x400>; + clocks = <&rcc STM32_CLOCK_BUS_APB2 0x00000080>, + <&rcc STM32_SRC_PLL_Q SDMMC2_SEL(0)>; + resets = <&rctl STM32_RESET(APB2, 7U)>; + interrupts = <103 0>; + status = "disabled"; + }; + }; + + die_temp: dietemp { + ts-cal1-addr = <0x1FF07A2C>; + ts-cal2-addr = <0x1FF07A2E>; + }; + + vref: vref { + vrefint-cal-addr = <0x1FF07A2A>; + }; +}; diff --git a/dts/arm/st/f7/stm32f722Xe.dtsi b/dts/arm/st/f7/stm32f722Xe.dtsi new file mode 100644 index 00000000000..79491e4008b --- /dev/null +++ b/dts/arm/st/f7/stm32f722Xe.dtsi @@ -0,0 +1,18 @@ +/* + * Copyright (c) 2023 Evan Perry Grove + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include +#include + +/ { + soc { + flash-controller@40023c00 { + flash0: flash@8000000 { + reg = <0x08000000 DT_SIZE_K(512)>; + }; + }; + }; +}; diff --git a/dts/arm/st/f7/stm32f723.dtsi b/dts/arm/st/f7/stm32f723.dtsi index 2b2031d89b5..f8b5448a788 100644 --- a/dts/arm/st/f7/stm32f723.dtsi +++ b/dts/arm/st/f7/stm32f723.dtsi @@ -4,28 +4,9 @@ * SPDX-License-Identifier: Apache-2.0 */ -#include +#include / { - /* 64KB DTCM @ 0x20000000, 176KB SRAM1 @ 0x20010000, 16KB SRAM2 @ 0x2003C00 */ - - sram0: memory@20010000 { - compatible = "mmio-sram"; - reg = <0x20010000 DT_SIZE_K(192)>; - }; - - dtcm: memory@20000000 { - compatible = "zephyr,memory-region", "arm,dtcm"; - reg = <0x20000000 DT_SIZE_K(64)>; - zephyr,memory-region = "DTCM"; - }; - - itcm: memory@0 { - compatible = "zephyr,memory-region", "arm,itcm"; - reg = <0x00000000 DT_SIZE_K(16)>; - zephyr,memory-region = "ITCM"; - }; - soc { compatible = "st,stm32f723", "st,stm32f7", "simple-bus"; @@ -39,26 +20,6 @@ phys = <&usbphyc>; maximum-speed = "high-speed"; }; - - sdmmc2: sdmmc@40011c00 { - compatible = "st,stm32-sdmmc"; - reg = <0x40011c00 0x400>; - clocks = <&rcc STM32_CLOCK_BUS_APB2 0x00000080>, - <&rcc STM32_SRC_PLL_Q SDMMC2_SEL(0)>; - resets = <&rctl STM32_RESET(APB2, 7U)>; - interrupts = <103 0>; - status = "disabled"; - }; - }; - - vref: vref { - compatible = "st,stm32-vref"; - vrefint-cal-addr = <0x1FF07A2A>; - }; - - die_temp: dietemp { - ts-cal1-addr = <0x1FF07A2C>; - ts-cal2-addr = <0x1FF07A2E>; }; }; diff --git a/soc/arm/st_stm32/stm32f7/Kconfig.defconfig.stm32f722xx b/soc/arm/st_stm32/stm32f7/Kconfig.defconfig.stm32f722xx new file mode 100644 index 00000000000..5b85551f939 --- /dev/null +++ b/soc/arm/st_stm32/stm32f7/Kconfig.defconfig.stm32f722xx @@ -0,0 +1,15 @@ +# ST STM32F722XE Configuration options +# +# Copyright (c) 2023 Evan Perry Grove +# +# SPDX-License-Identifier: Apache-2.0 + +if SOC_STM32F722XX + +config SOC + default "stm32f722xx" + +config NUM_IRQS + default 104 + +endif # SOC_STM32F722XX diff --git a/soc/arm/st_stm32/stm32f7/Kconfig.soc b/soc/arm/st_stm32/stm32f7/Kconfig.soc index 727ed908813..c83a9962a60 100644 --- a/soc/arm/st_stm32/stm32f7/Kconfig.soc +++ b/soc/arm/st_stm32/stm32f7/Kconfig.soc @@ -3,12 +3,16 @@ # Copyright (c) 2018 Yurii Hamann # Copyright (c) 2022, Rtone. # Copyright (c) 2023, Rahul Arasikere. +# Copyright (c) 2023 Evan Perry Grove # SPDX-License-Identifier: Apache-2.0 choice prompt "STM32F7x MCU Selection" depends on SOC_SERIES_STM32F7X +config SOC_STM32F722XX + bool "STM32F722XX" + config SOC_STM32F723XX bool "STM32F723XX" From f93ea05895e4df293f8c015d54e7b0ed87bf9d82 Mon Sep 17 00:00:00 2001 From: Evan Perry Grove Date: Fri, 8 Dec 2023 14:52:04 -0600 Subject: [PATCH 1184/3723] boards: arm: Add support for ST NUCLEO F722ZE Introduce support for ST Nucleo F722ZE, an evaluation board based on the STM32F722ZET6U microcontroller. Signed-off-by: Evan Perry Grove --- boards/arm/nucleo_f722ze/Kconfig.board | 8 + boards/arm/nucleo_f722ze/Kconfig.defconfig | 15 ++ .../nucleo_f722ze/arduino_r3_connector.dtsi | 41 +++ boards/arm/nucleo_f722ze/board.cmake | 6 + .../nucleo_f722ze/doc/img/nucleo_f722ze.jpg | Bin 0 -> 95323 bytes boards/arm/nucleo_f722ze/doc/index.rst | 243 +++++++++++++++++ boards/arm/nucleo_f722ze/nucleo_f722ze.dts | 251 ++++++++++++++++++ boards/arm/nucleo_f722ze/nucleo_f722ze.yaml | 25 ++ .../arm/nucleo_f722ze/nucleo_f722ze_defconfig | 26 ++ boards/arm/nucleo_f722ze/support/openocd.cfg | 12 + 10 files changed, 627 insertions(+) create mode 100644 boards/arm/nucleo_f722ze/Kconfig.board create mode 100644 boards/arm/nucleo_f722ze/Kconfig.defconfig create mode 100644 boards/arm/nucleo_f722ze/arduino_r3_connector.dtsi create mode 100644 boards/arm/nucleo_f722ze/board.cmake create mode 100644 boards/arm/nucleo_f722ze/doc/img/nucleo_f722ze.jpg create mode 100644 boards/arm/nucleo_f722ze/doc/index.rst create mode 100644 boards/arm/nucleo_f722ze/nucleo_f722ze.dts create mode 100644 boards/arm/nucleo_f722ze/nucleo_f722ze.yaml create mode 100644 boards/arm/nucleo_f722ze/nucleo_f722ze_defconfig create mode 100644 boards/arm/nucleo_f722ze/support/openocd.cfg diff --git a/boards/arm/nucleo_f722ze/Kconfig.board b/boards/arm/nucleo_f722ze/Kconfig.board new file mode 100644 index 00000000000..f15e218e161 --- /dev/null +++ b/boards/arm/nucleo_f722ze/Kconfig.board @@ -0,0 +1,8 @@ +# STM32F722ZE Nucleo board configuration + +# Copyright (c) 2023 Evan Perry Grove +# SPDX-License-Identifier: Apache-2.0 + +config BOARD_NUCLEO_F722ZE + bool "Nucleo F722ZE Development Board" + depends on SOC_STM32F722XX diff --git a/boards/arm/nucleo_f722ze/Kconfig.defconfig b/boards/arm/nucleo_f722ze/Kconfig.defconfig new file mode 100644 index 00000000000..1dfff0c9d44 --- /dev/null +++ b/boards/arm/nucleo_f722ze/Kconfig.defconfig @@ -0,0 +1,15 @@ +# STM32F722ZE Nucleo board configuration +# +# Copyright (c) 2023 Evan Perry Grove +# SPDX-License-Identifier: Apache-2.0 + +if BOARD_NUCLEO_F722ZE + +config BOARD + default "nucleo_f722ze" + +config SPI_STM32_INTERRUPT + default y + depends on SPI + +endif # BOARD_NUCLEO_F722ZE diff --git a/boards/arm/nucleo_f722ze/arduino_r3_connector.dtsi b/boards/arm/nucleo_f722ze/arduino_r3_connector.dtsi new file mode 100644 index 00000000000..9072fa91476 --- /dev/null +++ b/boards/arm/nucleo_f722ze/arduino_r3_connector.dtsi @@ -0,0 +1,41 @@ +/* + * Copyright (c) 2021, Tom Owen + * Copyright (c) 2023 Evan Perry Grove + * + * SPDX-License-Identifier: Apache-2.0 + */ + +/ { + arduino_header: connector { + compatible = "arduino-header-r3"; + #gpio-cells = <2>; + gpio-map-mask = <0xffffffff 0xffffffc0>; + gpio-map-pass-thru = <0 0x3f>; + gpio-map = <0 0 &gpioa 3 0>, /* A0 */ + <1 0 &gpioc 0 0>, /* A1 */ + <2 0 &gpioc 3 0>, /* A2 */ + <3 0 &gpiof 3 0>, /* A3 */ + <4 0 &gpiof 5 0>, /* A4 */ + <5 0 &gpiof 10 0>, /* A5 */ + <6 0 &gpiog 9 0>, /* D0 */ + <7 0 &gpiog 14 0>, /* D1 */ + <8 0 &gpiof 15 0>, /* D2 */ + <9 0 &gpioe 13 0>, /* D3 */ + <10 0 &gpiof 14 0>, /* D4 */ + <11 0 &gpioe 11 0>, /* D5 */ + <12 0 &gpioe 9 0>, /* D6 */ + <13 0 &gpiof 13 0>, /* D7 */ + <14 0 &gpiof 12 0>, /* D8 */ + <15 0 &gpiod 15 0>, /* D9 */ + <16 0 &gpiod 14 0>, /* D10 */ + <17 0 &gpioa 7 0>, /* D11 */ + <18 0 &gpioa 6 0>, /* D12 */ + <19 0 &gpioa 5 0>, /* D13 */ + <20 0 &gpiob 9 0>, /* D14 */ + <21 0 &gpiob 8 0>; /* D15 */ + }; +}; + +arduino_i2c: &i2c1 {}; +arduino_spi: &spi1 {}; +arduino_serial: &usart6 {}; diff --git a/boards/arm/nucleo_f722ze/board.cmake b/boards/arm/nucleo_f722ze/board.cmake new file mode 100644 index 00000000000..6335e34584a --- /dev/null +++ b/boards/arm/nucleo_f722ze/board.cmake @@ -0,0 +1,6 @@ +# SPDX-License-Identifier: Apache-2.0 + +board_runner_args(jlink "--device=STM32F722ZE" "--speed=4000") + +include(${ZEPHYR_BASE}/boards/common/openocd.board.cmake) +include(${ZEPHYR_BASE}/boards/common/jlink.board.cmake) diff --git a/boards/arm/nucleo_f722ze/doc/img/nucleo_f722ze.jpg b/boards/arm/nucleo_f722ze/doc/img/nucleo_f722ze.jpg new file mode 100644 index 0000000000000000000000000000000000000000..0778ea20cfd21e1f4f225c0eb14943260d781190 GIT binary patch literal 95323 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 N0~-a#YU{G+|Jg6G#J&Ik literal 0 HcmV?d00001 diff --git a/boards/arm/nucleo_f722ze/doc/index.rst b/boards/arm/nucleo_f722ze/doc/index.rst new file mode 100644 index 00000000000..f0c40595f3a --- /dev/null +++ b/boards/arm/nucleo_f722ze/doc/index.rst @@ -0,0 +1,243 @@ +.. _nucleo_f722ze_board: + +ST Nucleo F722ZE +################ + +Overview +******** + +The Nucleo F722ZE board features an ARM Cortex-M7 based STM32F722ZE MCU. + +Key Features: + +- STM32 microcontroller in LQFP144 package +- USB full-speed/high-speed device +- 3 user LEDs +- 1 user button and 1 reset button +- 32.768 kHz crystal oscillator +- Board connectors: + - USB Micro-AB + - SWD + - ST Zio connector (Arduino Uno R3 compatible) + - ST Morpho connector +- On-board ST-LINK debugger/programmer +- Flexible power supply options, including ST-LINK VBUS and external sources. + +.. image:: img/nucleo_f722ze.jpg + :width: 800px + :align: center + :alt: Nucleo F722ZE + +Hardware +******** + +Nucleo F722ZE provides the following hardware components: + +- STM32F722ZET6 microcontroller in LQFP144 package +- ARM |reg| Cortex |reg|-M4 with FPU +- Adaptive Real-Time Accelerator (ART Accelerator) +- 216MHz max CPU frequency +- 512 KB flash +- 256 KB RAM +- I2C (3) +- USART/UART (4) +- SPI (5) +- I2S (3) +- SAI (2) +- USB OTG Full-speed (1) +- USB OTG Full-speed/high-speed (1) +- SDMMC (2) +- CAN (1) +- Dual mode Quad-SPI +- Random number generator (RNG) +- 3x 12-bit ADC, up to 2.4 MSPS with 24 channels or 7.2 MSPS in triple-interleaved mode +- 2x 12-bit DAC +- 16-channel DMA controller +- 16-bit timers (13) with PWM, pulse counter, and quadrature features +- 32-bit timers (2) with PWM, pulse counter, and quadrature features +- CRC +- 96-bit unique ID +- Die temperature + +Supported Features +================== + ++---------------+------------+-------------------------------+ +| Interface | Controller | Driver/Component | ++===============+============+===============================+ +| NVIC | on-chip | arch/arm | ++---------------+------------+-------------------------------+ +| MPU | on-chip | arch/arm | ++---------------+------------+-------------------------------+ +| ADC | on-chip | adc | ++---------------+------------+-------------------------------+ +| CAN | on-chip | can | ++---------------+------------+-------------------------------+ +| USART/UART | on-chip | console, serial | ++---------------+------------+-------------------------------+ +| TIMER | on-chip | counter, pwm, timer | ++---------------+------------+-------------------------------+ +| DAC | on-chip | dac | ++---------------+------------+-------------------------------+ +| DMA | on-chip | dma | ++---------------+------------+-------------------------------+ +| GPIO | on-chip | gpio | ++---------------+------------+-------------------------------+ +| HWINFO | on-chip | hwinfo | ++---------------+------------+-------------------------------+ +| I2C | on-chip | i2c | ++---------------+------------+-------------------------------+ +| EXTI | on-chip | interrupt_controller | ++---------------+------------+-------------------------------+ +| BACKUP_SRAM | on-chip | memory | ++---------------+------------+-------------------------------+ +| QUADSPI | on-chip | memory | ++---------------+------------+-------------------------------+ +| PINMUX | on-chip | pinctrl | ++---------------+------------+-------------------------------+ +| RCC | on-chip | reset | ++---------------+------------+-------------------------------+ +| RTC | on-chip | rtc | ++---------------+------------+-------------------------------+ +| DIE_TEMP | on-chip | sensor | ++---------------+------------+-------------------------------+ +| VREF | on-chip | sensor | ++---------------+------------+-------------------------------+ +| VBAT | on-chip | sensor | ++---------------+------------+-------------------------------+ +| SPI | on-chip | spi | ++---------------+------------+-------------------------------+ +| USBOTG_HS | on-chip | usb | ++---------------+------------+-------------------------------+ +| USBOTG_FS | on-chip | usb | ++---------------+------------+-------------------------------+ +| IWDG | on-chip | watchdog | ++---------------+------------+-------------------------------+ +| WWDG | on-chip | watchdog | ++---------------+------------+-------------------------------+ + +Connections and IOs +=================== + +- SDMMC1: Pins marked as "SDMMC" on the ST Zio connector. + - D0: PC8 (CN8 pin 2) + - D1: PC9 (CN8 pin 4) + - D2: PC10 (CN8 pin 6) + - D3: PC11 (CN8 pin 8) + - CK: PC12 (CN8 pin 10) + - CMD: PD2 (CN8 pin 12) +- ADC1: + - IN3: PA3 (CN9 pin 1, Arduino A0) + - IN10: PC0 (CN9 pin 3, Arduino A1) +- DAC1: + - OUT1: PA4 (CN7 pin 17) +- I2C2: Pins marked as "I2C" on the ST Zio connector. + - SCL: PF1 (CN9 pin 19) + - SDA: PF0 (CN9 pin 21) +- CAN1: Pins marked as "CAN" on the ST Zio connector. + - RX: PD0 (CN9 pin 25) + - TX: PD1 (CN9 pin 27) +- USART2: Pins marked as "USART" on the ST Zio connector. + - RX: PD6 (CN9 pin 4) + - TX: PD5 (CN9 pin 6) + - RTS: PD4 (CN9 pin 8) + - CTS: PD3 (CN9 pin 10) +- PWM1: Uses TIMER1. + - PE13 (CN10 pin 10, Arduino D3) + - PE11 (CN10 pin 6, Arduino D5) +- USART3: Connected to ST-Link virtual COM port. + - TX: PD8 + - RX: PD9 +- USART6: Arduino UART port. + - RX: PG9 (CN10 pin 16, Arduino D0) + - TX: PG14 (CN10 pin 14, Arduino D1) +- USBOTG_FS: Connected to USB Micro-AB connector (CN13) + - DM: PA11 + - DP: PA12 + - ID: PA10 +- QUADSPI: Pins marked as "QSPI" on the ST Zio connector. + - CS: PB6 (CN10 pin 13) + - CLK: PB2 (CN10 pin 15) + - IO3: PD13 (CN10 pin 19) + - IO1: PD12 (CN10 pin 21) + - IO0: PD11 (CN10 pin 23) + - IO2: PE2 (CN10 pin 25) + +System Clock +------------ + +By default, the system clock is driven by the external clock supplied by +the ST-LINK interface. Nucleo F722ZE system clock can be driven by internal +or external sources. + +Serial Port +----------- + +Zephyr console is assigned to UART3 (ST-Link Virtual COM Port) by default, +using 115200 8N1. + +Programming and Debugging +************************* + +The ``nucleo_f722ze`` can be flashed and debugged in the typical manner. +The Nucleo F722ZE board includes an ST-LINK V2-1 debugger, which can be used +with the OpenOCD version provided with the Zephyr SDK. Refer to +:ref:`build_an_application` and :ref:`application_run` for detailed +instructions. + +Flashing +======== + +Build the :ref:`hello_world` application and flash it using the on-board +ST-LINK interface: + +.. zephyr-app-commands:: + :zephyr-app: samples/hello_world + :board: nucleo_f722ze + :goals: build flash + +Debugging +========= + +.. zephyr-app-commands:: + :zephyr-app: samples/hello_world + :board: nucleo_f722ze + :maybe-skip-config: + :goals: debug + +J-Link OB Firmware +------------------ + +Like many other STM32 evaluation boards, the Nucleo F722ZE's on-board ST-LINK +debug interface may be flashed with `SEGGER J-Link OB firmware`_. This +firmware turns the ST-LINK into a J-Link probe. If the on-board debugger has +been re-flashed with J-Link OB firmware, simply append ``--runner jlink`` to +all flashing/debugging commands. + +References +********** + +More information about the STM32F722ZE: + +- `STM32F722ZE on www.st.com`_ +- `STM32F722ZE Reference Manual (RM0431)`_ (PDF) + +More information about Nucleo F722ZE: + +- `Nucleo F722ZE on www.st.com`_ +- `STM32 Nucleo-144 User Manual (UM1974)`_ (PDF) + +.. _SEGGER J-Link OB firmware: + https://www.segger.com/products/debug-probes/j-link/models/other-j-links/st-link-on-board/ + +.. _STM32F722ZE on www.st.com: + https://www.st.com/en/microcontrollers-microprocessors/stm32f722ze.html + +.. _STM32F722ZE Reference Manual (RM0431): + https://www.st.com/resource/en/reference_manual/rm0431-stm32f72xxx-and-stm32f73xxx-advanced-armbased-32bit-mcus-stmicroelectronics.pdf + +.. _Nucleo F722ZE on www.st.com: + https://www.st.com/en/evaluation-tools/nucleo-f722ze.html + +.. _STM32 Nucleo-144 User Manual (UM1974): + https://www.st.com/resource/en/user_manual/um1974-stm32-nucleo144-boards-mb1137-stmicroelectronics.pdf diff --git a/boards/arm/nucleo_f722ze/nucleo_f722ze.dts b/boards/arm/nucleo_f722ze/nucleo_f722ze.dts new file mode 100644 index 00000000000..e3a2e65ad3b --- /dev/null +++ b/boards/arm/nucleo_f722ze/nucleo_f722ze.dts @@ -0,0 +1,251 @@ +/* + * Copyright (c) 2023 Evan Perry Grove + * + * SPDX-License-Identifier: Apache-2.0 + */ + +/dts-v1/; +#include +#include +#include "arduino_r3_connector.dtsi" +#include + +/ { + model = "STMicroelectronics STM32F722ZE-NUCLEO board"; + compatible = "st,stm32f722ze-nucleo"; + + chosen { + zephyr,console = &usart3; + zephyr,shell-uart = &usart3; + zephyr,sram = &sram0; + zephyr,flash = &flash0; + zephyr,dtcm = &dtcm; + zephyr,canbus = &can1; + }; + + leds { + compatible = "gpio-leds"; + green_led: led_1 { + gpios = <&gpiob 0 GPIO_ACTIVE_HIGH>; + label = "User LD1"; + }; + blue_led: led_2 { + gpios = <&gpiob 7 GPIO_ACTIVE_HIGH>; + label = "User LD2"; + }; + red_led: led_3 { + gpios = <&gpiob 14 GPIO_ACTIVE_HIGH>; + label = "User LD3"; + }; + }; + + gpio_keys { + compatible = "gpio-keys"; + user_button: button { + label = "User"; + gpios = <&gpioc 13 GPIO_ACTIVE_HIGH>; + zephyr,code = ; + }; + }; + + aliases { + led0 = &green_led; + led1 = &blue_led; + led2 = &red_led; + sw0 = &user_button; + watchdog0 = &iwdg; + die-temp0 = &die_temp; + volt-sensor0 = &vref; + }; +}; + +&clk_hse { + clock-frequency = ; + status = "okay"; +}; + +&clk_hsi { + status = "disabled"; +}; + +&pll { + div-m = <4>; + mul-n = <216>; + div-p = <2>; + div-q = <9>; + clocks = <&clk_hse>; + status = "okay"; +}; + +&rcc { + clocks = <&pll>; + clock-frequency = ; + ahb-prescaler = <1>; + apb1-prescaler = <4>; + apb2-prescaler = <2>; +}; + +&sdmmc1 { + status = "okay"; + pinctrl-0 = <&sdmmc1_d0_pc8 &sdmmc1_d1_pc9 &sdmmc1_d2_pc10 + &sdmmc1_d3_pc11 &sdmmc1_ck_pc12 &sdmmc1_cmd_pd2>; + pinctrl-names = "default"; + cd-gpios = <&gpioi 15 GPIO_ACTIVE_LOW>; +}; + +&adc1 { + pinctrl-0 = <&adc1_in3_pa3 &adc1_in10_pc0>; + pinctrl-names = "default"; + st,adc-clock-source = ; + st,adc-prescaler = <2>; + status = "okay"; +}; + +&dac1 { + pinctrl-0 = <&dac_out1_pa4>; + pinctrl-names = "default"; + status = "okay"; +}; + +&i2c2 { + pinctrl-0 = <&i2c2_scl_pf1 &i2c2_sda_pf0>; + pinctrl-names = "default"; + status = "okay"; + clock-frequency = ; +}; + +&can1 { + pinctrl-0 = <&can1_rx_pd0 &can1_tx_pd1>; + pinctrl-names = "default"; + bus-speed = <125000>; + status = "okay"; +}; + +&usart2 { + pinctrl-0 = <&usart2_tx_pd5 &usart2_rx_pd6 &usart2_rts_pd4 &usart2_cts_pd3>; + pinctrl-names = "default"; + current-speed = <115200>; + status = "okay"; +}; + +&usart3 { + pinctrl-0 = <&usart3_tx_pd8 &usart3_rx_pd9>; + pinctrl-names = "default"; + current-speed = <115200>; + status = "okay"; +}; + +&i2c1 { + pinctrl-0 = <&i2c1_scl_pb8 &i2c1_sda_pb9>; + pinctrl-names = "default"; + status = "okay"; +}; + +&spi1 { + pinctrl-0 = <&spi1_sck_pa5 &spi1_miso_pa6 &spi1_mosi_pa7>; + pinctrl-names = "default"; + cs-gpios = <&gpiod 14 (GPIO_ACTIVE_LOW | GPIO_PULL_UP)>; + status = "okay"; +}; + +&timers1 { + status = "okay"; + + pwm1: pwm { + status = "okay"; + pinctrl-0 = <&tim1_ch2_pe11 &tim1_ch3_pe13>; + pinctrl-names = "default"; + }; +}; + +&usart6 { + pinctrl-0 = <&usart6_tx_pg14 &usart6_rx_pg9>; + pinctrl-names = "default"; + current-speed = <115200>; + status = "okay"; +}; + +zephyr_udc0: &usbotg_fs { + pinctrl-0 = <&usb_otg_fs_dm_pa11 &usb_otg_fs_dp_pa12 &usb_otg_fs_id_pa10>; + pinctrl-names = "default"; + status = "okay"; +}; + +&rtc { + clocks = <&rcc STM32_CLOCK_BUS_APB1 0x10000000>, + <&rcc STM32_SRC_LSI RTC_SEL(2)>; + status = "okay"; +}; + +&die_temp { + status = "okay"; +}; + +&dma2 { + status = "okay"; +}; + +&iwdg { + status = "okay"; +}; + +&vref { + status = "okay"; +}; + +&rng { + status = "okay"; +}; + +&backup_sram { + status = "okay"; +}; + +&quadspi { + pinctrl-names = "default"; + pinctrl-0 = <&quadspi_clk_pb2 &quadspi_bk1_ncs_pb6 + &quadspi_bk1_io0_pd11 &quadspi_bk1_io1_pd12 + &quadspi_bk1_io2_pe2 &quadspi_bk1_io3_pd13>; + flash-id = <1>; + status = "okay"; +}; + +&flash0 { + + partitions { + compatible = "fixed-partitions"; + #address-cells = <1>; + #size-cells = <1>; + + /* sectors 0-3 */ + boot_partition: partition@0 { + label = "mcuboot"; + reg = <0x00000000 DT_SIZE_K(64)>; + read-only; + }; + + /* sector 4 */ + storage_partition: partition@10000 { + label = "storage"; + reg = <0x00010000 DT_SIZE_K(64)>; + }; + + /* sector 5 */ + slot0_partition: partition@20000 { + label = "image-0"; + reg = <0x00020000 DT_SIZE_K(128)>; + }; + + /* sector 6 */ + slot1_partition: partition@40000 { + label = "image-1"; + reg = <0x00040000 DT_SIZE_K(128)>; + }; + + /* sector 7 */ + scratch_partition: partition@60000 { + label = "image-scratch"; + reg = <0x00060000 DT_SIZE_K(128)>; + }; + }; +}; diff --git a/boards/arm/nucleo_f722ze/nucleo_f722ze.yaml b/boards/arm/nucleo_f722ze/nucleo_f722ze.yaml new file mode 100644 index 00000000000..94cdcb73914 --- /dev/null +++ b/boards/arm/nucleo_f722ze/nucleo_f722ze.yaml @@ -0,0 +1,25 @@ +identifier: nucleo_f722ze +name: ST Nucleo F722ZE +type: mcu +arch: arm +toolchain: + - zephyr + - gnuarmemb + - xtools +supported: + - adc + - arduino_gpio + - arduino_i2c + - arduino_spi + - backup_sram + - can + - counter + - dac + - gpio + - i2c + - quadspi + - spi + - usb_device +ram: 256 +flash: 512 +vendor: st diff --git a/boards/arm/nucleo_f722ze/nucleo_f722ze_defconfig b/boards/arm/nucleo_f722ze/nucleo_f722ze_defconfig new file mode 100644 index 00000000000..345694efd80 --- /dev/null +++ b/boards/arm/nucleo_f722ze/nucleo_f722ze_defconfig @@ -0,0 +1,26 @@ +# SPDX-License-Identifier: Apache-2.0 + +CONFIG_SOC_SERIES_STM32F7X=y +CONFIG_SOC_STM32F722XX=y + +# Enable MPU +CONFIG_ARM_MPU=y + +# Enable HW stack protection +CONFIG_HW_STACK_PROTECTION=y + +# Enable UART +CONFIG_SERIAL=y + +# Enable console (use UART by default) +CONFIG_CONSOLE=y +CONFIG_UART_CONSOLE=y + +# Enable GPIO +CONFIG_GPIO=y + +# Enable clocks +CONFIG_CLOCK_CONTROL=y + +# Enable pinctrl +CONFIG_PINCTRL=y diff --git a/boards/arm/nucleo_f722ze/support/openocd.cfg b/boards/arm/nucleo_f722ze/support/openocd.cfg new file mode 100644 index 00000000000..599f7e84012 --- /dev/null +++ b/boards/arm/nucleo_f722ze/support/openocd.cfg @@ -0,0 +1,12 @@ +source [find board/st_nucleo_f7.cfg] + +$_TARGETNAME configure -event gdb-attach { + echo "Debugger attaching: halting execution" + reset halt + gdb_breakpoint_override hard +} + +$_TARGETNAME configure -event gdb-detach { + echo "Debugger detaching: resuming execution" + resume +} From 6df457624984fb0cd0d2490819ca78f373a09626 Mon Sep 17 00:00:00 2001 From: Evan Perry Grove Date: Fri, 8 Dec 2023 14:52:37 -0600 Subject: [PATCH 1185/3723] tests: drivers: Add nucleo_f722ze board support Add overlays for the adc_api and counter_basic_api tests. Support Nucleo F722ZE in the dac_api test. Signed-off-by: Evan Perry Grove --- .../adc/adc_api/boards/nucleo_f722ze.overlay | 32 +++++++ .../boards/nucleo_f722ze.overlay | 93 +++++++++++++++++++ tests/drivers/dac/dac_api/src/test_dac.c | 1 + 3 files changed, 126 insertions(+) create mode 100644 tests/drivers/adc/adc_api/boards/nucleo_f722ze.overlay create mode 100644 tests/drivers/counter/counter_basic_api/boards/nucleo_f722ze.overlay diff --git a/tests/drivers/adc/adc_api/boards/nucleo_f722ze.overlay b/tests/drivers/adc/adc_api/boards/nucleo_f722ze.overlay new file mode 100644 index 00000000000..fba6adc0de1 --- /dev/null +++ b/tests/drivers/adc/adc_api/boards/nucleo_f722ze.overlay @@ -0,0 +1,32 @@ +/* + * SPDX-License-Identifier: Apache-2.0 + * + * Copyright (c) 2023 Evan Perry Grove + */ + +/ { + zephyr,user { + io-channels = <&adc1 3>, <&adc1 10>; + }; +}; + +&adc1 { + #address-cells = <1>; + #size-cells = <0>; + + channel@3 { + reg = <3>; + zephyr,gain = "ADC_GAIN_1"; + zephyr,reference = "ADC_REF_INTERNAL"; + zephyr,acquisition-time = ; + zephyr,resolution = <12>; + }; + + channel@a { + reg = <10>; + zephyr,gain = "ADC_GAIN_1"; + zephyr,reference = "ADC_REF_INTERNAL"; + zephyr,acquisition-time = ; + zephyr,resolution = <12>; + }; +}; diff --git a/tests/drivers/counter/counter_basic_api/boards/nucleo_f722ze.overlay b/tests/drivers/counter/counter_basic_api/boards/nucleo_f722ze.overlay new file mode 100644 index 00000000000..ac8e74baaf1 --- /dev/null +++ b/tests/drivers/counter/counter_basic_api/boards/nucleo_f722ze.overlay @@ -0,0 +1,93 @@ +/* + * SPDX-License-Identifier: Apache-2.0 + * + * Copyright (c) 2023 Evan Perry Grove + */ + +&clk_lsi { + status = "okay"; +}; + +&timers2 { + st,prescaler = <79>; + counter { + status = "okay"; + }; +}; + +&timers3 { + st,prescaler = <79>; + counter { + status = "okay"; + }; +}; + +&timers4 { + st,prescaler = <79>; + counter { + status = "okay"; + }; +}; + +&timers5 { + st,prescaler = <79>; + counter { + status = "okay"; + }; +}; + +&timers6 { + st,prescaler = <79>; + counter { + status = "okay"; + }; +}; + +&timers7 { + st,prescaler = <79>; + counter { + status = "okay"; + }; +}; + +&timers9 { + st,prescaler = <79>; + counter { + status = "okay"; + }; +}; + +&timers10 { + st,prescaler = <79>; + counter { + status = "okay"; + }; +}; + +&timers11 { + st,prescaler = <79>; + counter { + status = "okay"; + }; +}; + +&timers12 { + st,prescaler = <79>; + counter { + status = "okay"; + }; +}; + +&timers13 { + st,prescaler = <79>; + counter { + status = "okay"; + }; +}; + +&timers14 { + st,prescaler = <79>; + counter { + status = "okay"; + }; +}; diff --git a/tests/drivers/dac/dac_api/src/test_dac.c b/tests/drivers/dac/dac_api/src/test_dac.c index 9c45ea041f6..53ffb2ac0e9 100644 --- a/tests/drivers/dac/dac_api/src/test_dac.c +++ b/tests/drivers/dac/dac_api/src/test_dac.c @@ -15,6 +15,7 @@ defined(CONFIG_BOARD_NUCLEO_F429ZI) || \ defined(CONFIG_BOARD_NUCLEO_F746ZG) || \ defined(CONFIG_BOARD_NUCLEO_F767ZI) || \ + defined(CONFIG_BOARD_NUCLEO_F722ZE) || \ defined(CONFIG_BOARD_NUCLEO_G071RB) || \ defined(CONFIG_BOARD_NUCLEO_G431RB) || \ defined(CONFIG_BOARD_NUCLEO_G474RE) || \ From 9f3d9f75942f595964447ec685701e808eef1ab3 Mon Sep 17 00:00:00 2001 From: Georgij Cernysiov Date: Mon, 11 Dec 2023 14:16:33 +0100 Subject: [PATCH 1186/3723] drivers: spi: stm32: disable cs when spi is done Deassert CS after SPI is done. Signed-off-by: Georgij Cernysiov Co-authored-by: Daniel Gaston Ochoa --- drivers/spi/spi_ll_stm32.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/drivers/spi/spi_ll_stm32.c b/drivers/spi/spi_ll_stm32.c index c5df1e249cd..76e9b923c87 100644 --- a/drivers/spi/spi_ll_stm32.c +++ b/drivers/spi/spi_ll_stm32.c @@ -471,7 +471,6 @@ static void spi_stm32_complete(const struct device *dev, int status) ll_func_disable_int_errors(spi); #endif - spi_stm32_cs_control(dev, false); #if DT_HAS_COMPAT_STATUS_OKAY(st_stm32_spi_fifo) /* Flush RX buffer */ @@ -484,7 +483,10 @@ static void spi_stm32_complete(const struct device *dev, int status) while (ll_func_spi_is_busy(spi)) { /* NOP */ } + + spi_stm32_cs_control(dev, false); } + /* BSY flag is cleared when MODF flag is raised */ if (LL_SPI_IsActiveFlag_MODF(spi)) { LL_SPI_ClearFlag_MODF(spi); From 88874022906b3b35d96cca8888dece1a647011bb Mon Sep 17 00:00:00 2001 From: Luca Burelli Date: Wed, 13 Dec 2023 09:16:24 +0100 Subject: [PATCH 1187/3723] llext: fix: use proper global #define for cache flush The arch_* functions are architecture-specific and may not be defined in all targets. Use the global alias defined in the Cache API instead. Fixes #66382. Signed-off-by: Luca Burelli --- subsys/llext/llext.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/subsys/llext/llext.c b/subsys/llext/llext.c index d71dfca3a77..84cbc4d583d 100644 --- a/subsys/llext/llext.c +++ b/subsys/llext/llext.c @@ -781,7 +781,7 @@ static int llext_link(struct llext_loader *ldr, struct llext *ext, bool do_local /* Make sure changes to ext sections are flushed to RAM */ for (i = 0; i < LLEXT_MEM_COUNT; ++i) { if (ext->mem[i]) { - arch_dcache_flush_range(ext->mem[i], ext->mem_size[i]); + sys_cache_data_flush_range(ext->mem[i], ext->mem_size[i]); } } #endif From 2c7ea1dde529ad6d4a65e2271802fe7ccfd6a090 Mon Sep 17 00:00:00 2001 From: Luca Burelli Date: Wed, 13 Dec 2023 09:18:33 +0100 Subject: [PATCH 1188/3723] llext: autoselect CACHE_MANAGEMENT on supported targets Targets that have a data cache must enable CACHE_MANAGEMENT to allow the llext API to flush it when loading an extension. This patch forces the flag to be enabled when the target has a data cache. Signed-off-by: Luca Burelli --- subsys/llext/Kconfig | 1 + 1 file changed, 1 insertion(+) diff --git a/subsys/llext/Kconfig b/subsys/llext/Kconfig index b1210b8f2e8..59a4129a1ad 100644 --- a/subsys/llext/Kconfig +++ b/subsys/llext/Kconfig @@ -3,6 +3,7 @@ menuconfig LLEXT bool "Linkable loadable extensions" + select CACHE_MANAGEMENT if DCACHE help Enable the linkable loadable extension subsystem From 52686a83080402a086f38d2fa01c3da4663f4fc8 Mon Sep 17 00:00:00 2001 From: Johann Fischer Date: Sat, 18 Nov 2023 12:15:49 +0100 Subject: [PATCH 1189/3723] usb: device_next: simplify way to set/change triple code Usually we want set all values of code triple Base Class, SubClass, and Protocol at once. Merge existing functions to set code, subcode, protocol into just one helper to set code triple. Signed-off-by: Johann Fischer --- include/zephyr/usb/usbd.h | 35 +++++------------- subsys/usb/device_next/usbd_device.c | 53 +++++----------------------- subsys/usb/device_next/usbd_shell.c | 53 ++++++---------------------- 3 files changed, 27 insertions(+), 114 deletions(-) diff --git a/include/zephyr/usb/usbd.h b/include/zephyr/usb/usbd.h index 5048bdd78ee..716ee9821f4 100644 --- a/include/zephyr/usb/usbd.h +++ b/include/zephyr/usb/usbd.h @@ -701,37 +701,18 @@ int usbd_device_set_pid(struct usbd_contex *const uds_ctx, const uint16_t pid); /** - * @brief Set USB device descriptor value bDeviceClass + * @brief Set USB device descriptor code triple Base Class, SubClass, and Protocol * - * @param[in] uds_ctx Pointer to USB device support context - * @param[in] value bDeviceClass value - * - * @return 0 on success, other values on fail. - */ -int usbd_device_set_class(struct usbd_contex *const uds_ctx, - const uint8_t value); - -/** - * @brief Set USB device descriptor value bDeviceSubClass - * - * @param[in] uds_ctx Pointer to USB device support context - * @param[in] value bDeviceSubClass value - * - * @return 0 on success, other values on fail. - */ -int usbd_device_set_subclass(struct usbd_contex *const uds_ctx, - const uint8_t value); - -/** - * @brief Set USB device descriptor value bDeviceProtocol - * - * @param[in] uds_ctx Pointer to USB device support context - * @param[in] value bDeviceProtocol value + * @param[in] uds_ctx Pointer to USB device support context + * @param[in] class bDeviceClass value + * @param[in] subclass bDeviceSubClass value + * @param[in] protocol bDeviceProtocol value * * @return 0 on success, other values on fail. */ -int usbd_device_set_proto(struct usbd_contex *const uds_ctx, - const uint8_t value); +int usbd_device_set_code_triple(struct usbd_contex *const uds_ctx, + const uint8_t class, const uint8_t subclass, + const uint8_t protocol); /** * @brief Setup USB device configuration attribute Remote Wakeup diff --git a/subsys/usb/device_next/usbd_device.c b/subsys/usb/device_next/usbd_device.c index c836c271ed3..8046ea12013 100644 --- a/subsys/usb/device_next/usbd_device.c +++ b/subsys/usb/device_next/usbd_device.c @@ -80,8 +80,9 @@ int usbd_device_set_pid(struct usbd_contex *const uds_ctx, return ret; } -int usbd_device_set_class(struct usbd_contex *const uds_ctx, - const uint8_t value) +int usbd_device_set_code_triple(struct usbd_contex *const uds_ctx, + const uint8_t class, const uint8_t subclass, + const uint8_t protocol) { struct usb_device_descriptor *desc = uds_ctx->desc; int ret = 0; @@ -90,52 +91,14 @@ int usbd_device_set_class(struct usbd_contex *const uds_ctx, if (usbd_is_enabled(uds_ctx)) { ret = -EALREADY; - goto set_class_exit; + goto set_code_triple_exit; } - desc->bDeviceClass = value; + desc->bDeviceClass = class; + desc->bDeviceSubClass = subclass; + desc->bDeviceProtocol = protocol; -set_class_exit: - usbd_device_unlock(uds_ctx); - return ret; -} - -int usbd_device_set_subclass(struct usbd_contex *const uds_ctx, - const uint8_t value) -{ - struct usb_device_descriptor *desc = uds_ctx->desc; - int ret = 0; - - usbd_device_lock(uds_ctx); - - if (usbd_is_enabled(uds_ctx)) { - ret = -EALREADY; - goto set_subclass_exit; - } - - desc->bDeviceSubClass = value; - -set_subclass_exit: - usbd_device_unlock(uds_ctx); - return ret; -} - -int usbd_device_set_proto(struct usbd_contex *const uds_ctx, - const uint8_t value) -{ - struct usb_device_descriptor *desc = uds_ctx->desc; - int ret = 0; - - usbd_device_lock(uds_ctx); - - if (usbd_is_enabled(uds_ctx)) { - ret = -EALREADY; - goto set_proto_exit; - } - - desc->bDeviceProtocol = value; - -set_proto_exit: +set_code_triple_exit: usbd_device_unlock(uds_ctx); return ret; } diff --git a/subsys/usb/device_next/usbd_shell.c b/subsys/usb/device_next/usbd_shell.c index ee07a60b30f..22c903bb858 100644 --- a/subsys/usb/device_next/usbd_shell.c +++ b/subsys/usb/device_next/usbd_shell.c @@ -280,46 +280,19 @@ static int cmd_device_vid(const struct shell *sh, size_t argc, return ret; } -static int cmd_device_class(const struct shell *sh, size_t argc, - char *argv[]) -{ - uint8_t value; - int ret; - - value = strtol(argv[1], NULL, 16); - ret = usbd_device_set_class(my_uds_ctx, value); - if (ret) { - shell_error(sh, "dev: failed to set device class to %x", value); - } - - return ret; -} - -static int cmd_device_subclass(const struct shell *sh, size_t argc, - char *argv[]) -{ - uint8_t value; - int ret; - - value = strtol(argv[1], NULL, 16); - ret = usbd_device_set_subclass(my_uds_ctx, value); - if (ret) { - shell_error(sh, "dev: failed to set device subclass to %x", value); - } - - return ret; -} - -static int cmd_device_proto(const struct shell *sh, size_t argc, - char *argv[]) +static int cmd_device_code_triple(const struct shell *sh, size_t argc, + char *argv[]) { - uint8_t value; + uint8_t class, subclass, protocol; int ret; - value = strtol(argv[1], NULL, 16); - ret = usbd_device_set_proto(my_uds_ctx, value); + class = strtol(argv[1], NULL, 16); + subclass = strtol(argv[2], NULL, 16); + protocol = strtol(argv[3], NULL, 16); + ret = usbd_device_set_code_triple(my_uds_ctx, class, subclass, protocol); if (ret) { - shell_error(sh, "dev: failed to set device proto to %x", value); + shell_error(sh, "dev: failed to set device code triple to %x %x %x", + class, subclass, protocol); } return ret; @@ -467,12 +440,8 @@ SHELL_STATIC_SUBCMD_SET_CREATE(device_cmds, cmd_device_pid, 2, 0), SHELL_CMD_ARG(vid, NULL, "", cmd_device_vid, 2, 0), - SHELL_CMD_ARG(class, NULL, "", - cmd_device_class, 2, 0), - SHELL_CMD_ARG(subclass, NULL, "", - cmd_device_subclass, 2, 0), - SHELL_CMD_ARG(proto, NULL, "", - cmd_device_proto, 2, 0), + SHELL_CMD_ARG(triple, NULL, " ", + cmd_device_code_triple, 4, 0), SHELL_SUBCMD_SET_END ); From b00a998cf19d0853100aa311fedd7120d76cf37a Mon Sep 17 00:00:00 2001 From: Johann Fischer Date: Fri, 17 Nov 2023 16:05:37 +0100 Subject: [PATCH 1190/3723] samples: usb: add common USB device instantiation and initialization There is common code for the new USB device support in the samples to instantiate USB device, descriptors, configuration and initialize USB device. Add common code that can be used for the simple usecase with a single USB device and single configuration. Signed-off-by: Johann Fischer --- samples/subsys/usb/common/Kconfig.sample_usbd | 48 +++++++++ samples/subsys/usb/common/common.cmake | 9 ++ samples/subsys/usb/common/sample_usbd.h | 32 ++++++ samples/subsys/usb/common/sample_usbd_init.c | 102 ++++++++++++++++++ 4 files changed, 191 insertions(+) create mode 100644 samples/subsys/usb/common/Kconfig.sample_usbd create mode 100644 samples/subsys/usb/common/common.cmake create mode 100644 samples/subsys/usb/common/sample_usbd.h create mode 100644 samples/subsys/usb/common/sample_usbd_init.c diff --git a/samples/subsys/usb/common/Kconfig.sample_usbd b/samples/subsys/usb/common/Kconfig.sample_usbd new file mode 100644 index 00000000000..1d330c2ad08 --- /dev/null +++ b/samples/subsys/usb/common/Kconfig.sample_usbd @@ -0,0 +1,48 @@ +# Copyright (c) 2023 Nordic Semiconductor ASA +# SPDX-License-Identifier: Apache-2.0 + +# This file contains Kconfig options and defaults for configuring USB devices +# using the new experimental USB device support. The scope of these options is +# limited to USB samples in project tree, you cannot use them in your own +# application. + +menu "USB sample options" + depends on USB_DEVICE_STACK_NEXT + +config SAMPLE_USBD_MANUFACTURER + string "USB device sample manufacturer string" + default "Zephyr Project" + help + USB device sample manufacturer string. + +config SAMPLE_USBD_PRODUCT + string "USB device sample product string" + default "USBD sample" + help + USB device sample product stringa. + +config SAMPLE_USBD_PID + hex "USB device sample Product ID" + default 0x0001 + help + USB device sample Product ID. + +config SAMPLE_USBD_SELF_POWERED + bool "USB device sample Self-powered attribute" + default y + help + Set the Self-powered attribute in the sample configuration. + +config SAMPLE_USBD_REMOTE_WAKEUP + bool "USB device sample Remote Wakeup attribute" + help + Set the Remote Wakeup attribute in the sample configuration. + +config SAMPLE_USBD_MAX_POWER + int "USB device sample bMaxPower value" + default 125 + range 0 250 + help + bMaxPower value in the sample configuration in 2 mA units. + +endmenu diff --git a/samples/subsys/usb/common/common.cmake b/samples/subsys/usb/common/common.cmake new file mode 100644 index 00000000000..08d90a86612 --- /dev/null +++ b/samples/subsys/usb/common/common.cmake @@ -0,0 +1,9 @@ +# Copyright (c) 2023 Nordic Semiconductor ASA +# SPDX-License-Identifier: Apache-2.0 + +set(SAMPLE_USBD_DIR ${ZEPHYR_BASE}/samples/subsys/usb/common) + +target_include_directories(app PRIVATE ${SAMPLE_USBD_DIR}) +target_sources_ifdef(CONFIG_USB_DEVICE_STACK_NEXT app PRIVATE + ${SAMPLE_USBD_DIR}/sample_usbd_init.c +) diff --git a/samples/subsys/usb/common/sample_usbd.h b/samples/subsys/usb/common/sample_usbd.h new file mode 100644 index 00000000000..95880f02b0a --- /dev/null +++ b/samples/subsys/usb/common/sample_usbd.h @@ -0,0 +1,32 @@ +/* + * Copyright (c) 2023 Nordic Semiconductor ASA. + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#ifndef ZEPHYR_SAMPLES_SUBSYS_USB_COMMON_SAMPLE_USBD_H +#define ZEPHYR_SAMPLES_SUBSYS_USB_COMMON_SAMPLE_USBD_H + +#include +#include + +/* + * The scope of this header is limited to use in USB samples together with the + * new experimental USB device stack, you should not use it in your own + * application. However, you can use the code as a template. + */ + +/* + * This function uses Kconfig.sample_usbd options to configure and initialize a + * USB device. It configures sample's device context, default string descriptors, + * USB device configuration, registers any available class instances, and + * finally initializes USB device. It is limited to a single device with a + * single configuration instantiated in sample_usbd_init.c, which should be + * enough for a simple USB device sample. + * + * It returns the configured and initialized USB device context on success, + * otherwise it returns NULL. + */ +struct usbd_contex *sample_usbd_init_device(void); + +#endif /* ZEPHYR_SAMPLES_SUBSYS_USB_COMMON_SAMPLE_USBD_H */ diff --git a/samples/subsys/usb/common/sample_usbd_init.c b/samples/subsys/usb/common/sample_usbd_init.c new file mode 100644 index 00000000000..ce4d5ce7fc9 --- /dev/null +++ b/samples/subsys/usb/common/sample_usbd_init.c @@ -0,0 +1,102 @@ +/* + * Copyright (c) 2023 Nordic Semiconductor ASA + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include + +#include +#include +#include + +#include +LOG_MODULE_REGISTER(usbd_sample_config); + +#define ZEPHYR_PROJECT_USB_VID 0x2fe3 + +USBD_DEVICE_DEFINE(sample_usbd, + DEVICE_DT_GET(DT_NODELABEL(zephyr_udc0)), + ZEPHYR_PROJECT_USB_VID, CONFIG_SAMPLE_USBD_PID); + +USBD_DESC_LANG_DEFINE(sample_lang); +USBD_DESC_MANUFACTURER_DEFINE(sample_mfr, CONFIG_SAMPLE_USBD_MANUFACTURER); +USBD_DESC_PRODUCT_DEFINE(sample_product, CONFIG_SAMPLE_USBD_PRODUCT); +USBD_DESC_SERIAL_NUMBER_DEFINE(sample_sn, "0123456789ABCDEF"); + +static const uint8_t attributes = (IS_ENABLED(CONFIG_SAMPLE_USBD_SELF_POWERED) ? + USB_SCD_SELF_POWERED : 0) | + (IS_ENABLED(CONFIG_SAMPLE_USBD_REMOTE_WAKEUP) ? + USB_SCD_REMOTE_WAKEUP : 0); + +USBD_CONFIGURATION_DEFINE(sample_config, + attributes, + CONFIG_SAMPLE_USBD_MAX_POWER); + +struct usbd_contex *sample_usbd_init_device(void) +{ + int err; + + err = usbd_add_descriptor(&sample_usbd, &sample_lang); + if (err) { + LOG_ERR("Failed to initialize language descriptor (%d)", err); + return NULL; + } + + err = usbd_add_descriptor(&sample_usbd, &sample_mfr); + if (err) { + LOG_ERR("Failed to initialize manufacturer descriptor (%d)", err); + return NULL; + } + + err = usbd_add_descriptor(&sample_usbd, &sample_product); + if (err) { + LOG_ERR("Failed to initialize product descriptor (%d)", err); + return NULL; + } + + err = usbd_add_descriptor(&sample_usbd, &sample_sn); + if (err) { + LOG_ERR("Failed to initialize SN descriptor (%d)", err); + return NULL; + } + + err = usbd_add_configuration(&sample_usbd, &sample_config); + if (err) { + LOG_ERR("Failed to add configuration (%d)", err); + return NULL; + } + + STRUCT_SECTION_FOREACH(usbd_class_node, node) { + /* Pull everything that is enabled in our configuration. */ + err = usbd_register_class(&sample_usbd, node->name, 1); + if (err) { + LOG_ERR("Failed to register %s (%d)", node->name, err); + return NULL; + } + + LOG_DBG("Register %s", node->name); + } + + /* Always use class code information from Interface Descriptors */ + if (IS_ENABLED(CONFIG_USBD_CDC_ACM_CLASS) || + IS_ENABLED(CONFIG_USBD_CDC_ECM_CLASS)) { + /* + * Class with multiple interfaces have an Interface + * Association Descriptor available, use an appropriate triple + * to indicate it. + */ + usbd_device_set_code_triple(&sample_usbd, + USB_BCC_MISCELLANEOUS, 0x02, 0x01); + } else { + usbd_device_set_code_triple(&sample_usbd, 0, 0, 0); + } + + err = usbd_init(&sample_usbd); + if (err) { + LOG_ERR("Failed to initialize device support"); + return NULL; + } + + return &sample_usbd; +} From 9566419300ba698a17815392d624fb989b078396 Mon Sep 17 00:00:00 2001 From: Johann Fischer Date: Fri, 17 Nov 2023 17:34:18 +0100 Subject: [PATCH 1191/3723] samples: usb: use common sample USBD initialization Use the common USBD sample initialization helper where new USB device support has already been added. Signed-off-by: Johann Fischer --- samples/subsys/usb/cdc_acm/CMakeLists.txt | 1 + samples/subsys/usb/cdc_acm/Kconfig | 9 +++ samples/subsys/usb/cdc_acm/src/main.c | 61 +++--------------- samples/subsys/usb/cdc_acm/usbd_next_prj.conf | 3 + samples/subsys/usb/console/CMakeLists.txt | 1 + samples/subsys/usb/console/Kconfig | 9 +++ samples/subsys/usb/console/src/main.c | 53 +++------------- samples/subsys/usb/console/usbd_next_prj.conf | 3 + samples/subsys/usb/mass/CMakeLists.txt | 1 + samples/subsys/usb/mass/Kconfig | 9 +++ samples/subsys/usb/mass/src/main.c | 62 +++---------------- samples/subsys/usb/mass/usbd_next_prj.conf | 2 + 12 files changed, 61 insertions(+), 153 deletions(-) create mode 100644 samples/subsys/usb/cdc_acm/Kconfig create mode 100644 samples/subsys/usb/console/Kconfig diff --git a/samples/subsys/usb/cdc_acm/CMakeLists.txt b/samples/subsys/usb/cdc_acm/CMakeLists.txt index 0cba7b39068..c97b4990766 100644 --- a/samples/subsys/usb/cdc_acm/CMakeLists.txt +++ b/samples/subsys/usb/cdc_acm/CMakeLists.txt @@ -4,5 +4,6 @@ cmake_minimum_required(VERSION 3.20.0) find_package(Zephyr REQUIRED HINTS $ENV{ZEPHYR_BASE}) project(cdc_acm) +include(${ZEPHYR_BASE}/samples/subsys/usb/common/common.cmake) FILE(GLOB app_sources src/*.c) target_sources(app PRIVATE ${app_sources}) diff --git a/samples/subsys/usb/cdc_acm/Kconfig b/samples/subsys/usb/cdc_acm/Kconfig new file mode 100644 index 00000000000..96c54558948 --- /dev/null +++ b/samples/subsys/usb/cdc_acm/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/usb/cdc_acm/src/main.c b/samples/subsys/usb/cdc_acm/src/main.c index 6847ed8d11e..1fa40ace366 100644 --- a/samples/subsys/usb/cdc_acm/src/main.c +++ b/samples/subsys/usb/cdc_acm/src/main.c @@ -12,6 +12,8 @@ * to the serial port. */ +#include + #include #include #include @@ -32,66 +34,19 @@ struct ring_buf ringbuf; static bool rx_throttled; #if defined(CONFIG_USB_DEVICE_STACK_NEXT) -USBD_CONFIGURATION_DEFINE(config_1, - USB_SCD_SELF_POWERED, - 200); - -USBD_DESC_LANG_DEFINE(sample_lang); -USBD_DESC_MANUFACTURER_DEFINE(sample_mfr, "ZEPHYR"); -USBD_DESC_PRODUCT_DEFINE(sample_product, "Zephyr USBD CDC ACM"); -USBD_DESC_SERIAL_NUMBER_DEFINE(sample_sn, "0123456789ABCDEF"); - -USBD_DEVICE_DEFINE(sample_usbd, - DEVICE_DT_GET(DT_NODELABEL(zephyr_udc0)), - 0x2fe3, 0x0001); +static struct usbd_contex *sample_usbd; static int enable_usb_device_next(void) { int err; - err = usbd_add_descriptor(&sample_usbd, &sample_lang); - if (err) { - LOG_ERR("Failed to initialize language descriptor (%d)", err); - return err; - } - - err = usbd_add_descriptor(&sample_usbd, &sample_mfr); - if (err) { - LOG_ERR("Failed to initialize manufacturer descriptor (%d)", err); - return err; - } - - err = usbd_add_descriptor(&sample_usbd, &sample_product); - if (err) { - LOG_ERR("Failed to initialize product descriptor (%d)", err); - return err; - } - - err = usbd_add_descriptor(&sample_usbd, &sample_sn); - if (err) { - LOG_ERR("Failed to initialize SN descriptor (%d)", err); - return err; - } - - err = usbd_add_configuration(&sample_usbd, &config_1); - if (err) { - LOG_ERR("Failed to add configuration (%d)", err); - return err; - } - - err = usbd_register_class(&sample_usbd, "cdc_acm_0", 1); - if (err) { - LOG_ERR("Failed to register CDC ACM class (%d)", err); - return err; - } - - err = usbd_init(&sample_usbd); - if (err) { - LOG_ERR("Failed to initialize device support"); - return err; + sample_usbd = sample_usbd_init_device(); + if (sample_usbd == NULL) { + LOG_ERR("Failed to initialize USB device"); + return -ENODEV; } - err = usbd_enable(&sample_usbd); + err = usbd_enable(sample_usbd); if (err) { LOG_ERR("Failed to enable device support"); return err; diff --git a/samples/subsys/usb/cdc_acm/usbd_next_prj.conf b/samples/subsys/usb/cdc_acm/usbd_next_prj.conf index 36076b593ad..c5147519f87 100644 --- a/samples/subsys/usb/cdc_acm/usbd_next_prj.conf +++ b/samples/subsys/usb/cdc_acm/usbd_next_prj.conf @@ -8,3 +8,6 @@ CONFIG_USBD_CDC_ACM_CLASS=y CONFIG_LOG=y CONFIG_USBD_LOG_LEVEL_WRN=y CONFIG_UDC_DRIVER_LOG_LEVEL_WRN=y + +CONFIG_SAMPLE_USBD_PID=0x0001 +CONFIG_SAMPLE_USBD_PRODUCT="USBD CDC ACM sample" diff --git a/samples/subsys/usb/console/CMakeLists.txt b/samples/subsys/usb/console/CMakeLists.txt index cf1601304ab..8ef0ebe2e70 100644 --- a/samples/subsys/usb/console/CMakeLists.txt +++ b/samples/subsys/usb/console/CMakeLists.txt @@ -4,5 +4,6 @@ cmake_minimum_required(VERSION 3.20.0) find_package(Zephyr REQUIRED HINTS $ENV{ZEPHYR_BASE}) project(console) +include(${ZEPHYR_BASE}/samples/subsys/usb/common/common.cmake) FILE(GLOB app_sources src/*.c) target_sources(app PRIVATE ${app_sources}) diff --git a/samples/subsys/usb/console/Kconfig b/samples/subsys/usb/console/Kconfig new file mode 100644 index 00000000000..96c54558948 --- /dev/null +++ b/samples/subsys/usb/console/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/usb/console/src/main.c b/samples/subsys/usb/console/src/main.c index d0cd78b60dc..6c39cac89a6 100644 --- a/samples/subsys/usb/console/src/main.c +++ b/samples/subsys/usb/console/src/main.c @@ -4,6 +4,8 @@ * SPDX-License-Identifier: Apache-2.0 */ +#include + #include #include #include @@ -14,59 +16,18 @@ BUILD_ASSERT(DT_NODE_HAS_COMPAT(DT_CHOSEN(zephyr_console), zephyr_cdc_acm_uart), "Console device is not ACM CDC UART device"); #if defined(CONFIG_USB_DEVICE_STACK_NEXT) -USBD_CONFIGURATION_DEFINE(config_1, - USB_SCD_SELF_POWERED, - 200); - -USBD_DESC_LANG_DEFINE(sample_lang); -USBD_DESC_MANUFACTURER_DEFINE(sample_mfr, "ZEPHYR"); -USBD_DESC_PRODUCT_DEFINE(sample_product, "Zephyr USBD ACM console"); -USBD_DESC_SERIAL_NUMBER_DEFINE(sample_sn, "0123456789ABCDEF"); - -USBD_DEVICE_DEFINE(sample_usbd, - DEVICE_DT_GET(DT_NODELABEL(zephyr_udc0)), - 0x2fe3, 0x0001); +static struct usbd_contex *sample_usbd; static int enable_usb_device_next(void) { int err; - err = usbd_add_descriptor(&sample_usbd, &sample_lang); - if (err) { - return err; - } - - err = usbd_add_descriptor(&sample_usbd, &sample_mfr); - if (err) { - return err; - } - - err = usbd_add_descriptor(&sample_usbd, &sample_product); - if (err) { - return err; - } - - err = usbd_add_descriptor(&sample_usbd, &sample_sn); - if (err) { - return err; - } - - err = usbd_add_configuration(&sample_usbd, &config_1); - if (err) { - return err; - } - - err = usbd_register_class(&sample_usbd, "cdc_acm_0", 1); - if (err) { - return err; - } - - err = usbd_init(&sample_usbd); - if (err) { - return err; + sample_usbd = sample_usbd_init_device(); + if (sample_usbd == NULL) { + return -ENODEV; } - err = usbd_enable(&sample_usbd); + err = usbd_enable(sample_usbd); if (err) { return err; } diff --git a/samples/subsys/usb/console/usbd_next_prj.conf b/samples/subsys/usb/console/usbd_next_prj.conf index 36076b593ad..841bffbf012 100644 --- a/samples/subsys/usb/console/usbd_next_prj.conf +++ b/samples/subsys/usb/console/usbd_next_prj.conf @@ -8,3 +8,6 @@ CONFIG_USBD_CDC_ACM_CLASS=y CONFIG_LOG=y CONFIG_USBD_LOG_LEVEL_WRN=y CONFIG_UDC_DRIVER_LOG_LEVEL_WRN=y + +CONFIG_SAMPLE_USBD_PID=0x0004 +CONFIG_SAMPLE_USBD_PRODUCT="USBD console sample" diff --git a/samples/subsys/usb/mass/CMakeLists.txt b/samples/subsys/usb/mass/CMakeLists.txt index ef71596104d..c0475b031f3 100644 --- a/samples/subsys/usb/mass/CMakeLists.txt +++ b/samples/subsys/usb/mass/CMakeLists.txt @@ -10,6 +10,7 @@ if((NOT CONFIG_DISK_DRIVER_FLASH) AND message( FATAL_ERROR "No disk access settings detected." ) endif() +include(${ZEPHYR_BASE}/samples/subsys/usb/common/common.cmake) FILE(GLOB app_sources src/*.c) target_sources(app PRIVATE ${app_sources}) diff --git a/samples/subsys/usb/mass/Kconfig b/samples/subsys/usb/mass/Kconfig index e031a4545db..69cf30f5186 100644 --- a/samples/subsys/usb/mass/Kconfig +++ b/samples/subsys/usb/mass/Kconfig @@ -1,6 +1,8 @@ # Copyright (c) 2019-2020 Nordic Semiconductor ASA # SPDX-License-Identifier: Apache-2.0 +menu "MSC sample options" + config APP_WIPE_STORAGE bool "Option to clear the flash area before mounting" help @@ -65,4 +67,11 @@ endif # NORDIC_QSPI_NOR endif # DISK_DRIVER_FLASH +endmenu + +# 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/usb/mass/src/main.c b/samples/subsys/usb/mass/src/main.c index 0d8d6ba982a..760612279cf 100644 --- a/samples/subsys/usb/mass/src/main.c +++ b/samples/subsys/usb/mass/src/main.c @@ -5,6 +5,8 @@ * SPDX-License-Identifier: Apache-2.0 */ +#include + #include #include #include @@ -34,19 +36,7 @@ FS_LITTLEFS_DECLARE_DEFAULT_CONFIG(storage); static struct fs_mount_t fs_mnt; #if defined(CONFIG_USB_DEVICE_STACK_NEXT) -USBD_CONFIGURATION_DEFINE(config_1, - USB_SCD_SELF_POWERED, - 200); - -USBD_DESC_LANG_DEFINE(sample_lang); -USBD_DESC_MANUFACTURER_DEFINE(sample_mfr, "ZEPHYR"); -USBD_DESC_PRODUCT_DEFINE(sample_product, "Zephyr USBD MSC"); -USBD_DESC_SERIAL_NUMBER_DEFINE(sample_sn, "0123456789ABCDEF"); - - -USBD_DEVICE_DEFINE(sample_usbd, - DEVICE_DT_GET(DT_NODELABEL(zephyr_udc0)), - 0x2fe3, 0x0008); +static struct usbd_contex *sample_usbd; #if CONFIG_DISK_DRIVER_RAM USBD_DEFINE_MSC_LUN(RAM, "Zephyr", "RAMDisk", "0.00"); @@ -64,49 +54,13 @@ static int enable_usb_device_next(void) { int err; - err = usbd_add_descriptor(&sample_usbd, &sample_lang); - if (err) { - LOG_ERR("Failed to initialize language descriptor (%d)", err); - return err; - } - - err = usbd_add_descriptor(&sample_usbd, &sample_mfr); - if (err) { - LOG_ERR("Failed to initialize manufacturer descriptor (%d)", err); - return err; - } - - err = usbd_add_descriptor(&sample_usbd, &sample_product); - if (err) { - LOG_ERR("Failed to initialize product descriptor (%d)", err); - return err; - } - - err = usbd_add_descriptor(&sample_usbd, &sample_sn); - if (err) { - LOG_ERR("Failed to initialize SN descriptor (%d)", err); - return err; - } - - err = usbd_add_configuration(&sample_usbd, &config_1); - if (err) { - LOG_ERR("Failed to add configuration (%d)", err); - return err; - } - - err = usbd_register_class(&sample_usbd, "msc_0", 1); - if (err) { - LOG_ERR("Failed to register MSC class (%d)", err); - return err; - } - - err = usbd_init(&sample_usbd); - if (err) { - LOG_ERR("Failed to initialize device support"); - return err; + sample_usbd = sample_usbd_init_device(); + if (sample_usbd == NULL) { + LOG_ERR("Failed to initialize USB device"); + return -ENODEV; } - err = usbd_enable(&sample_usbd); + err = usbd_enable(sample_usbd); if (err) { LOG_ERR("Failed to enable device support"); return err; diff --git a/samples/subsys/usb/mass/usbd_next_prj.conf b/samples/subsys/usb/mass/usbd_next_prj.conf index cdf37f75ada..1f7345d25fd 100644 --- a/samples/subsys/usb/mass/usbd_next_prj.conf +++ b/samples/subsys/usb/mass/usbd_next_prj.conf @@ -10,4 +10,6 @@ CONFIG_LOG=y CONFIG_USBD_LOG_LEVEL_WRN=y CONFIG_UDC_DRIVER_LOG_LEVEL_WRN=y +CONFIG_SAMPLE_USBD_PID=0x0008 +CONFIG_SAMPLE_USBD_PRODUCT="USBD MSC sample" CONFIG_MAIN_STACK_SIZE=1536 From 6621e780c9c22952d2eb1b1f543ec1a2f51a4045 Mon Sep 17 00:00:00 2001 From: Florian La Roche Date: Tue, 12 Dec 2023 21:59:32 +0100 Subject: [PATCH 1192/3723] lib: libc: minimal: proper cast to "(char *)" from "(const char *)" The string "" is of type '(const char *)', so add a cast over to '(char *)' to clean up source code. Signed-off-by: Florian La Roche --- lib/libc/minimal/source/string/strerror.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/libc/minimal/source/string/strerror.c b/lib/libc/minimal/source/string/strerror.c index 624e8922b7f..77dfd8b477a 100644 --- a/lib/libc/minimal/source/string/strerror.c +++ b/lib/libc/minimal/source/string/strerror.c @@ -28,7 +28,7 @@ char *strerror(int errnum) return (char *)sys_errlist[errnum]; } - return ""; + return (char *) ""; } /* From fdcfec03286aef7011723b17f7d0ea1ecd5fdc62 Mon Sep 17 00:00:00 2001 From: Florian La Roche Date: Tue, 12 Dec 2023 18:37:52 +0100 Subject: [PATCH 1193/3723] drivers: entropy: entropy_esp32.c: remove not necessary cast This cast already has the correct type on both sides, so it can be removed. Signed-off-by: Florian La Roche --- drivers/entropy/entropy_esp32.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/entropy/entropy_esp32.c b/drivers/entropy/entropy_esp32.c index 359c67dda77..4a15f640ce9 100644 --- a/drivers/entropy/entropy_esp32.c +++ b/drivers/entropy/entropy_esp32.c @@ -44,7 +44,7 @@ static int entropy_esp32_get_entropy(const struct device *dev, uint8_t *buf, uint16_t len) { assert(buf != NULL); - uint8_t *buf_bytes = (uint8_t *)buf; + uint8_t *buf_bytes = buf; while (len > 0) { uint32_t word = entropy_esp32_get_u32(); From 2457a942edb4aadbe605660e7f0366bfee1529c6 Mon Sep 17 00:00:00 2001 From: Adam Wojasinski Date: Wed, 13 Dec 2023 08:52:48 +0100 Subject: [PATCH 1194/3723] boards: arm: nrf5340dk_nrf5340: Add SPI to supported peripherals The target has board configuration for spi_flash sample but bacause of the lack of SPI mentioned in supported peripherals Twister is filtering out the target for sample.drivers.spi.flash test. Signed-off-by: Adam Wojasinski --- boards/arm/nrf5340dk_nrf5340/nrf5340dk_nrf5340_cpuapp.yaml | 1 + boards/arm/nrf5340dk_nrf5340/nrf5340dk_nrf5340_cpuapp_ns.yaml | 1 + 2 files changed, 2 insertions(+) diff --git a/boards/arm/nrf5340dk_nrf5340/nrf5340dk_nrf5340_cpuapp.yaml b/boards/arm/nrf5340dk_nrf5340/nrf5340dk_nrf5340_cpuapp.yaml index 545a41e9cd6..6ed15a5d7ef 100644 --- a/boards/arm/nrf5340dk_nrf5340/nrf5340dk_nrf5340_cpuapp.yaml +++ b/boards/arm/nrf5340dk_nrf5340/nrf5340dk_nrf5340_cpuapp.yaml @@ -18,4 +18,5 @@ supported: - usb_device - netif:openthread - gpio + - spi vendor: nordic diff --git a/boards/arm/nrf5340dk_nrf5340/nrf5340dk_nrf5340_cpuapp_ns.yaml b/boards/arm/nrf5340dk_nrf5340/nrf5340dk_nrf5340_cpuapp_ns.yaml index 9519f50f3e9..90abc04b119 100644 --- a/boards/arm/nrf5340dk_nrf5340/nrf5340dk_nrf5340_cpuapp_ns.yaml +++ b/boards/arm/nrf5340dk_nrf5340/nrf5340dk_nrf5340_cpuapp_ns.yaml @@ -16,4 +16,5 @@ supported: - usb_device - netif:openthread - gpio + - spi vendor: nordic From 9bc2815c59a0c51ea27c7b859573a533f2ffc5fa Mon Sep 17 00:00:00 2001 From: Jukka Rissanen Date: Wed, 13 Dec 2023 11:05:23 +0200 Subject: [PATCH 1195/3723] net: buf: Define only one pool initializer macro Use the IF_ENABLED() macro to define the net_buf pool initializer macro only once. This way the initializer is only defined in one place. Signed-off-by: Jukka Rissanen --- include/zephyr/net/buf.h | 21 +++++---------------- 1 file changed, 5 insertions(+), 16 deletions(-) diff --git a/include/zephyr/net/buf.h b/include/zephyr/net/buf.h index f7378fc3962..948517428f5 100644 --- a/include/zephyr/net/buf.h +++ b/include/zephyr/net/buf.h @@ -1006,21 +1006,10 @@ struct net_buf_pool { }; /** @cond INTERNAL_HIDDEN */ -#if defined(CONFIG_NET_BUF_POOL_USAGE) -#define NET_BUF_POOL_INITIALIZER(_pool, _alloc, _bufs, _count, _ud_size, _destroy) \ - { \ - .free = Z_LIFO_INITIALIZER(_pool.free), \ - .lock = { }, \ - .buf_count = _count, \ - .uninit_count = _count, \ - .user_data_size = _ud_size, \ - .avail_count = ATOMIC_INIT(_count), \ - .name = STRINGIFY(_pool), \ - .destroy = _destroy, \ - .alloc = _alloc, \ - .__bufs = (struct net_buf *)_bufs, \ - } -#else +#define NET_BUF_POOL_USAGE_INIT(_pool, _count) \ + IF_ENABLED(CONFIG_NET_BUF_POOL_USAGE, (.avail_count = ATOMIC_INIT(_count),)) \ + IF_ENABLED(CONFIG_NET_BUF_POOL_USAGE, (.name = STRINGIFY(_pool),)) + #define NET_BUF_POOL_INITIALIZER(_pool, _alloc, _bufs, _count, _ud_size, _destroy) \ { \ .free = Z_LIFO_INITIALIZER(_pool.free), \ @@ -1028,11 +1017,11 @@ struct net_buf_pool { .buf_count = _count, \ .uninit_count = _count, \ .user_data_size = _ud_size, \ + NET_BUF_POOL_USAGE_INIT(_pool, _count) \ .destroy = _destroy, \ .alloc = _alloc, \ .__bufs = (struct net_buf *)_bufs, \ } -#endif /* CONFIG_NET_BUF_POOL_USAGE */ #define _NET_BUF_ARRAY_DEFINE(_name, _count, _ud_size) \ struct _net_buf_##_name { uint8_t b[sizeof(struct net_buf)]; \ From f4974ca82a57b92de697b7131e5a85f21c5abc97 Mon Sep 17 00:00:00 2001 From: Jukka Rissanen Date: Wed, 13 Dec 2023 11:28:11 +0200 Subject: [PATCH 1196/3723] net: if: Cleanup network interface init macros Avoid using #ifdefs when declaring macros twice. This way there is only one macro that does the initialization. Signed-off-by: Jukka Rissanen --- include/zephyr/net/net_if.h | 17 +++++------------ 1 file changed, 5 insertions(+), 12 deletions(-) diff --git a/include/zephyr/net/net_if.h b/include/zephyr/net/net_if.h index 3438709136f..2078dd261fd 100644 --- a/include/zephyr/net/net_if.h +++ b/include/zephyr/net/net_if.h @@ -2799,21 +2799,14 @@ struct net_if_api { void (*init)(struct net_if *iface); }; -#if defined(CONFIG_NET_IP) -#define NET_IF_IP_INIT .ip = {}, -#else -#define NET_IF_IP_INIT -#endif - -#if defined(CONFIG_NET_DHCPV4) && defined(CONFIG_NET_NATIVE_IPV4) -#define NET_IF_DHCPV4_INIT .dhcpv4.state = NET_DHCPV4_DISABLED, -#else -#define NET_IF_DHCPV4_INIT -#endif +#define NET_IF_DHCPV4_INIT \ + IF_ENABLED(UTIL_AND(IS_ENABLED(CONFIG_NET_DHCPV4), \ + IS_ENABLED(CONFIG_NET_NATIVE_IPV4)), \ + (.dhcpv4.state = NET_DHCPV4_DISABLED,)) #define NET_IF_CONFIG_INIT \ .config = { \ - NET_IF_IP_INIT \ + IF_ENABLED(CONFIG_NET_IP, (.ip = {},)) \ NET_IF_DHCPV4_INIT \ } From 37c18ddcb18792e00dcdd788a1664557a795e3ba Mon Sep 17 00:00:00 2001 From: Jukka Rissanen Date: Wed, 13 Dec 2023 11:31:35 +0200 Subject: [PATCH 1197/3723] net: if: Init also dhcpv6 when interface is init Do dhcpv6 state initialization same way as how dhcpv4 is done when initializing network interface structure. Signed-off-by: Jukka Rissanen --- include/zephyr/net/net_if.h | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/include/zephyr/net/net_if.h b/include/zephyr/net/net_if.h index 2078dd261fd..22a3e14fa14 100644 --- a/include/zephyr/net/net_if.h +++ b/include/zephyr/net/net_if.h @@ -2804,10 +2804,16 @@ struct net_if_api { IS_ENABLED(CONFIG_NET_NATIVE_IPV4)), \ (.dhcpv4.state = NET_DHCPV4_DISABLED,)) +#define NET_IF_DHCPV6_INIT \ + IF_ENABLED(UTIL_AND(IS_ENABLED(CONFIG_NET_DHCPV6), \ + IS_ENABLED(CONFIG_NET_NATIVE_IPV6)), \ + (.dhcpv6.state = NET_DHCPV6_DISABLED,)) + #define NET_IF_CONFIG_INIT \ .config = { \ IF_ENABLED(CONFIG_NET_IP, (.ip = {},)) \ NET_IF_DHCPV4_INIT \ + NET_IF_DHCPV6_INIT \ } #define NET_IF_GET_NAME(dev_id, sfx) __net_if_##dev_id##_##sfx From 477a4a5d34042f49830fc8aff94ffc16a98cce10 Mon Sep 17 00:00:00 2001 From: Jukka Rissanen Date: Wed, 13 Dec 2023 15:46:45 +0200 Subject: [PATCH 1198/3723] net: shell: Rename the common.h to be more unique As the common.h is only meant to be used by the network shell files, rename it to be more descriptive in order to avoid possible conflicts with any other common.h file. Signed-off-by: Jukka Rissanen --- subsys/net/lib/shell/allocs.c | 2 +- subsys/net/lib/shell/arp.c | 2 +- subsys/net/lib/shell/capture.c | 2 +- subsys/net/lib/shell/conn.c | 2 +- subsys/net/lib/shell/dns.c | 2 +- subsys/net/lib/shell/events.c | 2 +- subsys/net/lib/shell/gptp.c | 2 +- subsys/net/lib/shell/iface.c | 2 +- subsys/net/lib/shell/ipv4.c | 2 +- subsys/net/lib/shell/ipv6.c | 2 +- subsys/net/lib/shell/mem.c | 2 +- subsys/net/lib/shell/nbr.c | 2 +- subsys/net/lib/shell/net_shell.c | 2 +- subsys/net/lib/shell/{common.h => net_shell_private.h} | 0 subsys/net/lib/shell/ping.c | 2 +- subsys/net/lib/shell/pkt.c | 2 +- subsys/net/lib/shell/ppp.c | 2 +- subsys/net/lib/shell/resume.c | 2 +- subsys/net/lib/shell/route.c | 2 +- subsys/net/lib/shell/sockets.c | 2 +- subsys/net/lib/shell/stats.c | 2 +- subsys/net/lib/shell/suspend.c | 2 +- subsys/net/lib/shell/tcp.c | 2 +- subsys/net/lib/shell/udp.c | 2 +- subsys/net/lib/shell/virtual.c | 2 +- subsys/net/lib/shell/vlan.c | 2 +- subsys/net/lib/shell/websocket.c | 2 +- 27 files changed, 26 insertions(+), 26 deletions(-) rename subsys/net/lib/shell/{common.h => net_shell_private.h} (100%) diff --git a/subsys/net/lib/shell/allocs.c b/subsys/net/lib/shell/allocs.c index 1c6e7288003..a2669590520 100644 --- a/subsys/net/lib/shell/allocs.c +++ b/subsys/net/lib/shell/allocs.c @@ -8,7 +8,7 @@ #include LOG_MODULE_DECLARE(net_shell); -#include "common.h" +#include "net_shell_private.h" #if defined(CONFIG_NET_DEBUG_NET_PKT_ALLOC) static void allocs_cb(struct net_pkt *pkt, diff --git a/subsys/net/lib/shell/arp.c b/subsys/net/lib/shell/arp.c index fb1582411e9..58889f27d5c 100644 --- a/subsys/net/lib/shell/arp.c +++ b/subsys/net/lib/shell/arp.c @@ -8,7 +8,7 @@ #include LOG_MODULE_DECLARE(net_shell); -#include "common.h" +#include "net_shell_private.h" #if defined(CONFIG_NET_ARP) #include "ethernet/arp.h" diff --git a/subsys/net/lib/shell/capture.c b/subsys/net/lib/shell/capture.c index f05531562ae..0c7347f8774 100644 --- a/subsys/net/lib/shell/capture.c +++ b/subsys/net/lib/shell/capture.c @@ -10,7 +10,7 @@ LOG_MODULE_DECLARE(net_shell); #include -#include "common.h" +#include "net_shell_private.h" #include diff --git a/subsys/net/lib/shell/conn.c b/subsys/net/lib/shell/conn.c index 36831809eb8..24b528537bd 100644 --- a/subsys/net/lib/shell/conn.c +++ b/subsys/net/lib/shell/conn.c @@ -8,7 +8,7 @@ #include LOG_MODULE_DECLARE(net_shell); -#include "common.h" +#include "net_shell_private.h" #if defined(CONFIG_NET_TCP) #include "tcp_internal.h" diff --git a/subsys/net/lib/shell/dns.c b/subsys/net/lib/shell/dns.c index 24a52f5e8a2..54c768cecd1 100644 --- a/subsys/net/lib/shell/dns.c +++ b/subsys/net/lib/shell/dns.c @@ -10,7 +10,7 @@ LOG_MODULE_DECLARE(net_shell); #include -#include "common.h" +#include "net_shell_private.h" #if defined(CONFIG_DNS_RESOLVER) static void dns_result_cb(enum dns_resolve_status status, diff --git a/subsys/net/lib/shell/events.c b/subsys/net/lib/shell/events.c index f263e517850..88b3644e029 100644 --- a/subsys/net/lib/shell/events.c +++ b/subsys/net/lib/shell/events.c @@ -14,7 +14,7 @@ LOG_MODULE_DECLARE(net_shell); #include #include -#include "common.h" +#include "net_shell_private.h" #if defined(CONFIG_NET_MGMT_EVENT_MONITOR) #define EVENT_MON_STACK_SIZE 1024 diff --git a/subsys/net/lib/shell/gptp.c b/subsys/net/lib/shell/gptp.c index a156637e3af..0de653e26cd 100644 --- a/subsys/net/lib/shell/gptp.c +++ b/subsys/net/lib/shell/gptp.c @@ -19,7 +19,7 @@ LOG_MODULE_DECLARE(net_shell); #include "ethernet/gptp/gptp_private.h" #endif -#include "common.h" +#include "net_shell_private.h" #if defined(CONFIG_NET_GPTP) static const char *selected_role_str(int port); diff --git a/subsys/net/lib/shell/iface.c b/subsys/net/lib/shell/iface.c index 89983bd4839..53d4e99bd21 100644 --- a/subsys/net/lib/shell/iface.c +++ b/subsys/net/lib/shell/iface.c @@ -18,7 +18,7 @@ LOG_MODULE_DECLARE(net_shell); #include #endif -#include "common.h" +#include "net_shell_private.h" #if defined(CONFIG_NET_L2_ETHERNET) && defined(CONFIG_NET_NATIVE) struct ethernet_capabilities { diff --git a/subsys/net/lib/shell/ipv4.c b/subsys/net/lib/shell/ipv4.c index 752b1cda046..f0bb845b46d 100644 --- a/subsys/net/lib/shell/ipv4.c +++ b/subsys/net/lib/shell/ipv4.c @@ -10,7 +10,7 @@ LOG_MODULE_DECLARE(net_shell); #include -#include "common.h" +#include "net_shell_private.h" #include "../ip/ipv4.h" #if defined(CONFIG_NET_NATIVE_IPV4) diff --git a/subsys/net/lib/shell/ipv6.c b/subsys/net/lib/shell/ipv6.c index f81b8dcae23..04efda65d0f 100644 --- a/subsys/net/lib/shell/ipv6.c +++ b/subsys/net/lib/shell/ipv6.c @@ -8,7 +8,7 @@ #include LOG_MODULE_DECLARE(net_shell); -#include "common.h" +#include "net_shell_private.h" #include "../ip/ipv6.h" #if defined(CONFIG_NET_IPV6_FRAGMENT) diff --git a/subsys/net/lib/shell/mem.c b/subsys/net/lib/shell/mem.c index cf58cda6bd6..47058f92767 100644 --- a/subsys/net/lib/shell/mem.c +++ b/subsys/net/lib/shell/mem.c @@ -8,7 +8,7 @@ #include LOG_MODULE_DECLARE(net_shell); -#include "common.h" +#include "net_shell_private.h" struct ctx_info { int pos; diff --git a/subsys/net/lib/shell/nbr.c b/subsys/net/lib/shell/nbr.c index fd420b818ae..63b62406702 100644 --- a/subsys/net/lib/shell/nbr.c +++ b/subsys/net/lib/shell/nbr.c @@ -8,7 +8,7 @@ #include LOG_MODULE_DECLARE(net_shell); -#include "common.h" +#include "net_shell_private.h" static int cmd_net_nbr_rm(const struct shell *sh, size_t argc, char *argv[]) { diff --git a/subsys/net/lib/shell/net_shell.c b/subsys/net/lib/shell/net_shell.c index 19bab12e029..9f932cb1bc4 100644 --- a/subsys/net/lib/shell/net_shell.c +++ b/subsys/net/lib/shell/net_shell.c @@ -20,7 +20,7 @@ LOG_MODULE_REGISTER(net_shell, LOG_LEVEL_DBG); #include -#include "common.h" +#include "net_shell_private.h" #include "net_shell.h" int get_iface_idx(const struct shell *sh, char *index_str) diff --git a/subsys/net/lib/shell/common.h b/subsys/net/lib/shell/net_shell_private.h similarity index 100% rename from subsys/net/lib/shell/common.h rename to subsys/net/lib/shell/net_shell_private.h diff --git a/subsys/net/lib/shell/ping.c b/subsys/net/lib/shell/ping.c index b31f6f686fd..0af4dc41246 100644 --- a/subsys/net/lib/shell/ping.c +++ b/subsys/net/lib/shell/ping.c @@ -13,7 +13,7 @@ LOG_MODULE_DECLARE(net_shell); #include #include -#include "common.h" +#include "net_shell_private.h" #include "../ip/icmpv6.h" #include "../ip/icmpv4.h" diff --git a/subsys/net/lib/shell/pkt.c b/subsys/net/lib/shell/pkt.c index 09d7ae6738a..3306b05d1a7 100644 --- a/subsys/net/lib/shell/pkt.c +++ b/subsys/net/lib/shell/pkt.c @@ -8,7 +8,7 @@ #include LOG_MODULE_DECLARE(net_shell); -#include "common.h" +#include "net_shell_private.h" static bool is_pkt_part_of_slab(const struct k_mem_slab *slab, const char *ptr) { diff --git a/subsys/net/lib/shell/ppp.c b/subsys/net/lib/shell/ppp.c index 9b5f8355d47..f63c6ca3324 100644 --- a/subsys/net/lib/shell/ppp.c +++ b/subsys/net/lib/shell/ppp.c @@ -10,7 +10,7 @@ LOG_MODULE_DECLARE(net_shell); #include -#include "common.h" +#include "net_shell_private.h" #if defined(CONFIG_NET_L2_PPP) #include diff --git a/subsys/net/lib/shell/resume.c b/subsys/net/lib/shell/resume.c index 585d421efab..dcd3fbf309d 100644 --- a/subsys/net/lib/shell/resume.c +++ b/subsys/net/lib/shell/resume.c @@ -9,7 +9,7 @@ #include LOG_MODULE_DECLARE(net_shell); -#include "common.h" +#include "net_shell_private.h" static int cmd_net_resume(const struct shell *sh, size_t argc, char *argv[]) { diff --git a/subsys/net/lib/shell/route.c b/subsys/net/lib/shell/route.c index d48c442ed41..035b56f6dfc 100644 --- a/subsys/net/lib/shell/route.c +++ b/subsys/net/lib/shell/route.c @@ -8,7 +8,7 @@ #include LOG_MODULE_DECLARE(net_shell); -#include "common.h" +#include "net_shell_private.h" #include "../ip/route.h" diff --git a/subsys/net/lib/shell/sockets.c b/subsys/net/lib/shell/sockets.c index 792e34efc21..8be67fc5faf 100644 --- a/subsys/net/lib/shell/sockets.c +++ b/subsys/net/lib/shell/sockets.c @@ -7,7 +7,7 @@ #include LOG_MODULE_DECLARE(net_shell); -#include "common.h" +#include "net_shell_private.h" #include #if defined(CONFIG_NET_SOCKETS_OBJ_CORE) diff --git a/subsys/net/lib/shell/stats.c b/subsys/net/lib/shell/stats.c index 455f5d7decd..666a98e35d7 100644 --- a/subsys/net/lib/shell/stats.c +++ b/subsys/net/lib/shell/stats.c @@ -10,7 +10,7 @@ LOG_MODULE_DECLARE(net_shell); #include -#include "common.h" +#include "net_shell_private.h" #include "../ip/net_stats.h" diff --git a/subsys/net/lib/shell/suspend.c b/subsys/net/lib/shell/suspend.c index 326eb602077..cfa01375cac 100644 --- a/subsys/net/lib/shell/suspend.c +++ b/subsys/net/lib/shell/suspend.c @@ -9,7 +9,7 @@ #include LOG_MODULE_DECLARE(net_shell); -#include "common.h" +#include "net_shell_private.h" static int cmd_net_suspend(const struct shell *sh, size_t argc, char *argv[]) { diff --git a/subsys/net/lib/shell/tcp.c b/subsys/net/lib/shell/tcp.c index f90e16b3b66..e2839af36ba 100644 --- a/subsys/net/lib/shell/tcp.c +++ b/subsys/net/lib/shell/tcp.c @@ -10,7 +10,7 @@ LOG_MODULE_DECLARE(net_shell); #include -#include "common.h" +#include "net_shell_private.h" #if defined(CONFIG_NET_TCP) && defined(CONFIG_NET_NATIVE_TCP) static struct net_context *tcp_ctx; diff --git a/subsys/net/lib/shell/udp.c b/subsys/net/lib/shell/udp.c index 9eaf3254514..7bccbf93ba3 100644 --- a/subsys/net/lib/shell/udp.c +++ b/subsys/net/lib/shell/udp.c @@ -10,7 +10,7 @@ LOG_MODULE_DECLARE(net_shell); #include -#include "common.h" +#include "net_shell_private.h" #if defined(CONFIG_NET_UDP) && defined(CONFIG_NET_NATIVE_UDP) static struct net_context *udp_ctx; diff --git a/subsys/net/lib/shell/virtual.c b/subsys/net/lib/shell/virtual.c index 19c9b1c1b0e..4eaabaa9916 100644 --- a/subsys/net/lib/shell/virtual.c +++ b/subsys/net/lib/shell/virtual.c @@ -12,7 +12,7 @@ LOG_MODULE_DECLARE(net_shell); #include #endif -#include "common.h" +#include "net_shell_private.h" #if defined(CONFIG_NET_L2_VIRTUAL) static void virtual_iface_cb(struct net_if *iface, void *user_data) diff --git a/subsys/net/lib/shell/vlan.c b/subsys/net/lib/shell/vlan.c index 0a980caa11f..ea7103ef1c9 100644 --- a/subsys/net/lib/shell/vlan.c +++ b/subsys/net/lib/shell/vlan.c @@ -15,7 +15,7 @@ LOG_MODULE_DECLARE(net_shell); #include -#include "common.h" +#include "net_shell_private.h" #if defined(CONFIG_NET_VLAN) static void iface_vlan_del_cb(struct net_if *iface, void *user_data) diff --git a/subsys/net/lib/shell/websocket.c b/subsys/net/lib/shell/websocket.c index f3e77187627..56e705199e3 100644 --- a/subsys/net/lib/shell/websocket.c +++ b/subsys/net/lib/shell/websocket.c @@ -12,7 +12,7 @@ LOG_MODULE_DECLARE(net_shell); #include #endif -#include "common.h" +#include "net_shell_private.h" #include "websocket/websocket_internal.h" From 64462657c96c3ca39106385707b84e11d23369d9 Mon Sep 17 00:00:00 2001 From: Simon Hein Date: Wed, 13 Dec 2023 15:11:15 +0100 Subject: [PATCH 1199/3723] doc: irq: fix function link fix not correct shown function link for irq_connect_dynamic. Signed-off-by: Simon Hein --- doc/kernel/services/interrupts.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/doc/kernel/services/interrupts.rst b/doc/kernel/services/interrupts.rst index 849e614a562..7f19829c3b7 100644 --- a/doc/kernel/services/interrupts.rst +++ b/doc/kernel/services/interrupts.rst @@ -399,7 +399,7 @@ being invoked each time interrupt 24 is triggered. If :kconfig:option:`CONFIG_SHARED_IRQ_MAX_NUM_CLIENTS` is set to a value lower than 2 (current number of clients), a build error will be generated. -If dynamic interrupts are enabled, c:func:`irq_connect_dynamic` will allow sharing interrupts +If dynamic interrupts are enabled, :c:func:`irq_connect_dynamic` will allow sharing interrupts during runtime. Exceeding the configured maximum number of allowed clients will result in a failed assertion. From 6cb588820f8e9b3bc466b8a85f3bc56a1e2e50e1 Mon Sep 17 00:00:00 2001 From: Anas Nashif Date: Fri, 17 Nov 2023 18:43:30 -0500 Subject: [PATCH 1200/3723] lib: os: move heap to own folder consolidate all heap related files and implementation into one folder. Signed-off-by: Anas Nashif --- lib/CMakeLists.txt | 1 + lib/Kconfig | 2 ++ lib/heap/CMakeLists.txt | 11 +++++++++++ lib/{os/Kconfig.heap => heap/Kconfig} | 0 lib/{os => heap}/heap-validate.c | 0 lib/{os => heap}/heap.c | 0 lib/{os => heap}/heap.h | 0 lib/{os => heap}/heap_listener.c | 0 lib/{os => heap}/multi_heap.c | 0 lib/{os => heap}/shared_multi_heap.c | 0 lib/os/CMakeLists.txt | 7 ------- lib/os/Kconfig | 9 --------- 12 files changed, 14 insertions(+), 16 deletions(-) create mode 100644 lib/heap/CMakeLists.txt rename lib/{os/Kconfig.heap => heap/Kconfig} (100%) rename lib/{os => heap}/heap-validate.c (100%) rename lib/{os => heap}/heap.c (100%) rename lib/{os => heap}/heap.h (100%) rename lib/{os => heap}/heap_listener.c (100%) rename lib/{os => heap}/multi_heap.c (100%) rename lib/{os => heap}/shared_multi_heap.c (100%) diff --git a/lib/CMakeLists.txt b/lib/CMakeLists.txt index 6fe18f63992..ceba13bc2af 100644 --- a/lib/CMakeLists.txt +++ b/lib/CMakeLists.txt @@ -10,6 +10,7 @@ add_subdirectory(posix) endif() add_subdirectory_ifdef(CONFIG_CPP cpp) add_subdirectory(hash) +add_subdirectory(heap) add_subdirectory(os) add_subdirectory_ifdef(CONFIG_SMF smf) add_subdirectory_ifdef(CONFIG_OPENAMP open-amp) diff --git a/lib/Kconfig b/lib/Kconfig index 97ee3f6002d..9b6eb56d275 100644 --- a/lib/Kconfig +++ b/lib/Kconfig @@ -11,6 +11,8 @@ menu "Additional libraries" source "lib/hash/Kconfig" +source "lib/heap/Kconfig" + source "lib/os/Kconfig" source "lib/posix/Kconfig" diff --git a/lib/heap/CMakeLists.txt b/lib/heap/CMakeLists.txt new file mode 100644 index 00000000000..bc5f30b4841 --- /dev/null +++ b/lib/heap/CMakeLists.txt @@ -0,0 +1,11 @@ +# SPDX-License-Identifier: Apache-2.0 + +zephyr_sources( + heap.c + heap-validate.c + multi_heap.c + ) + +zephyr_sources_ifdef(CONFIG_SHARED_MULTI_HEAP shared_multi_heap.c) + +zephyr_sources_ifdef(CONFIG_HEAP_LISTENER heap_listener.c) diff --git a/lib/os/Kconfig.heap b/lib/heap/Kconfig similarity index 100% rename from lib/os/Kconfig.heap rename to lib/heap/Kconfig diff --git a/lib/os/heap-validate.c b/lib/heap/heap-validate.c similarity index 100% rename from lib/os/heap-validate.c rename to lib/heap/heap-validate.c diff --git a/lib/os/heap.c b/lib/heap/heap.c similarity index 100% rename from lib/os/heap.c rename to lib/heap/heap.c diff --git a/lib/os/heap.h b/lib/heap/heap.h similarity index 100% rename from lib/os/heap.h rename to lib/heap/heap.h diff --git a/lib/os/heap_listener.c b/lib/heap/heap_listener.c similarity index 100% rename from lib/os/heap_listener.c rename to lib/heap/heap_listener.c diff --git a/lib/os/multi_heap.c b/lib/heap/multi_heap.c similarity index 100% rename from lib/os/multi_heap.c rename to lib/heap/multi_heap.c diff --git a/lib/os/shared_multi_heap.c b/lib/heap/shared_multi_heap.c similarity index 100% rename from lib/os/shared_multi_heap.c rename to lib/heap/shared_multi_heap.c diff --git a/lib/os/CMakeLists.txt b/lib/os/CMakeLists.txt index 4f082716c48..4f403c2a289 100644 --- a/lib/os/CMakeLists.txt +++ b/lib/os/CMakeLists.txt @@ -15,10 +15,7 @@ zephyr_sources( sem.c thread_entry.c timeutil.c - heap.c - heap-validate.c bitarray.c - multi_heap.c ) zephyr_sources_ifdef(CONFIG_FDTABLE fdtable.c) @@ -50,10 +47,6 @@ zephyr_sources_ifdef(CONFIG_SCHED_DEADLINE p4wq.c) zephyr_sources_ifdef(CONFIG_REBOOT reboot.c) -zephyr_sources_ifdef(CONFIG_SHARED_MULTI_HEAP shared_multi_heap.c) - -zephyr_sources_ifdef(CONFIG_HEAP_LISTENER heap_listener.c) - zephyr_sources_ifdef(CONFIG_UTF8 utf8.c) zephyr_sources_ifdef(CONFIG_SYS_MEM_BLOCKS mem_blocks.c) diff --git a/lib/os/Kconfig b/lib/os/Kconfig index e6b25ade5a5..8b41f92f5b2 100644 --- a/lib/os/Kconfig +++ b/lib/os/Kconfig @@ -119,14 +119,6 @@ config SPSC_PBUF_UTILIZATION endif # SPSC_PBUF -config SHARED_MULTI_HEAP - bool "Shared multi-heap manager" - help - Enable support for a shared multi-heap manager that uses the - multi-heap allocator to manage a set of reserved memory regions with - different capabilities / attributes (cacheable, non-cacheable, - etc...) defined in the DT. - config WINSTREAM bool "Lockless shared memory window byte stream" help @@ -177,6 +169,5 @@ config UTF8 rsource "Kconfig.cbprintf" -rsource "Kconfig.heap" endmenu From 4cd9c116924b8fcafbbcc375c268677ecee9bcab Mon Sep 17 00:00:00 2001 From: Anas Nashif Date: Fri, 17 Nov 2023 18:58:55 -0500 Subject: [PATCH 1201/3723] lib: heap: split heap-validate.c Split heap-validate.c into smaller chunks. We have been adding all kind of new APIs under this file and building it unconditionally whether those APIs are needed/used or not. Many of those APIs have nothing to do with the validation part. Signed-off-by: Anas Nashif --- lib/heap/CMakeLists.txt | 2 + lib/heap/heap-info.c | 76 +++++++++++++ lib/heap/heap-stress.c | 153 ++++++++++++++++++++++++++ lib/heap/heap-validate.c | 228 +-------------------------------------- lib/heap/heap.h | 17 +++ 5 files changed, 249 insertions(+), 227 deletions(-) create mode 100644 lib/heap/heap-info.c create mode 100644 lib/heap/heap-stress.c diff --git a/lib/heap/CMakeLists.txt b/lib/heap/CMakeLists.txt index bc5f30b4841..fa297fbdca6 100644 --- a/lib/heap/CMakeLists.txt +++ b/lib/heap/CMakeLists.txt @@ -3,6 +3,8 @@ zephyr_sources( heap.c heap-validate.c + heap-stress.c + heap-info.c multi_heap.c ) diff --git a/lib/heap/heap-info.c b/lib/heap/heap-info.c new file mode 100644 index 00000000000..15d383f41e3 --- /dev/null +++ b/lib/heap/heap-info.c @@ -0,0 +1,76 @@ +/* + * Copyright (c) 2019 Intel Corporation + * + * SPDX-License-Identifier: Apache-2.0 + */ +#include +#include +#include +#include "heap.h" + +/* + * Print heap info for debugging / analysis purpose + */ +void heap_print_info(struct z_heap *h, bool dump_chunks) +{ + int i, nb_buckets = bucket_idx(h, h->end_chunk) + 1; + size_t free_bytes, allocated_bytes, total, overhead; + + printk("Heap at %p contains %d units in %d buckets\n\n", + chunk_buf(h), h->end_chunk, nb_buckets); + + printk(" bucket# min units total largest largest\n" + " threshold chunks (units) (bytes)\n" + " -----------------------------------------------------------\n"); + for (i = 0; i < nb_buckets; i++) { + chunkid_t first = h->buckets[i].next; + chunksz_t largest = 0; + int count = 0; + + if (first) { + chunkid_t curr = first; + + do { + count++; + largest = MAX(largest, chunk_size(h, curr)); + curr = next_free_chunk(h, curr); + } while (curr != first); + } + if (count) { + printk("%9d %12d %12d %12d %12zd\n", + i, (1 << i) - 1 + min_chunk_size(h), count, + largest, chunksz_to_bytes(h, largest)); + } + } + + if (dump_chunks) { + printk("\nChunk dump:\n"); + for (chunkid_t c = 0; ; c = right_chunk(h, c)) { + printk("chunk %4d: [%c] size=%-4d left=%-4d right=%d\n", + c, + chunk_used(h, c) ? '*' + : solo_free_header(h, c) ? '.' + : '-', + chunk_size(h, c), + left_chunk(h, c), + right_chunk(h, c)); + if (c == h->end_chunk) { + break; + } + } + } + + get_alloc_info(h, &allocated_bytes, &free_bytes); + /* The end marker chunk has a header. It is part of the overhead. */ + total = h->end_chunk * CHUNK_UNIT + chunk_header_bytes(h); + overhead = total - free_bytes - allocated_bytes; + printk("\n%zd free bytes, %zd allocated bytes, overhead = %zd bytes (%zd.%zd%%)\n", + free_bytes, allocated_bytes, overhead, + (1000 * overhead + total/2) / total / 10, + (1000 * overhead + total/2) / total % 10); +} + +void sys_heap_print_info(struct sys_heap *heap, bool dump_chunks) +{ + heap_print_info(heap->heap, dump_chunks); +} diff --git a/lib/heap/heap-stress.c b/lib/heap/heap-stress.c new file mode 100644 index 00000000000..443ffc9e7eb --- /dev/null +++ b/lib/heap/heap-stress.c @@ -0,0 +1,153 @@ +/* + * Copyright (c) 2019 Intel Corporation + * + * SPDX-License-Identifier: Apache-2.0 + */ +#include +#include +#include +#include "heap.h" + +struct z_heap_stress_rec { + void *(*alloc_fn)(void *arg, size_t bytes); + void (*free_fn)(void *arg, void *p); + void *arg; + size_t total_bytes; + struct z_heap_stress_block *blocks; + size_t nblocks; + size_t blocks_alloced; + size_t bytes_alloced; + uint32_t target_percent; +}; + +struct z_heap_stress_block { + void *ptr; + size_t sz; +}; + +/* Very simple LCRNG (from https://nuclear.llnl.gov/CNP/rng/rngman/node4.html) + * + * Here to guarantee cross-platform test repeatability. + */ +static uint32_t rand32(void) +{ + static uint64_t state = 123456789; /* seed */ + + state = state * 2862933555777941757UL + 3037000493UL; + + return (uint32_t)(state >> 32); +} + +static bool rand_alloc_choice(struct z_heap_stress_rec *sr) +{ + /* Edge cases: no blocks allocated, and no space for a new one */ + if (sr->blocks_alloced == 0) { + return true; + } else if (sr->blocks_alloced >= sr->nblocks) { + return false; + } else { + + /* The way this works is to scale the chance of choosing to + * allocate vs. free such that it's even odds when the heap is + * at the target percent, with linear tapering on the low + * slope (i.e. we choose to always allocate with an empty + * heap, allocate 50% of the time when the heap is exactly at + * the target, and always free when above the target). In + * practice, the operations aren't quite symmetric (you can + * always free, but your allocation might fail), and the units + * aren't matched (we're doing math based on bytes allocated + * and ignoring the overhead) but this is close enough. And + * yes, the math here is coarse (in units of percent), but + * that's good enough and fits well inside 32 bit quantities. + * (Note precision issue when heap size is above 40MB + * though!). + */ + __ASSERT(sr->total_bytes < 0xffffffffU / 100, "too big for u32!"); + uint32_t full_pct = (100 * sr->bytes_alloced) / sr->total_bytes; + uint32_t target = sr->target_percent ? sr->target_percent : 1; + uint32_t free_chance = 0xffffffffU; + + if (full_pct < sr->target_percent) { + free_chance = full_pct * (0x80000000U / target); + } + + return rand32() > free_chance; + } +} + +/* Chooses a size of block to allocate, logarithmically favoring + * smaller blocks (i.e. blocks twice as large are half as frequent + */ +static size_t rand_alloc_size(struct z_heap_stress_rec *sr) +{ + ARG_UNUSED(sr); + + /* Min scale of 4 means that the half of the requests in the + * smallest size have an average size of 8 + */ + int scale = 4 + __builtin_clz(rand32()); + + return rand32() & BIT_MASK(scale); +} + +/* Returns the index of a randomly chosen block to free */ +static size_t rand_free_choice(struct z_heap_stress_rec *sr) +{ + return rand32() % sr->blocks_alloced; +} + +/* General purpose heap stress test. Takes function pointers to allow + * for testing multiple heap APIs with the same rig. The alloc and + * free functions are passed back the argument as a context pointer. + * The "log" function is for readable user output. The total_bytes + * argument should reflect the size of the heap being tested. The + * scratch array is used to store temporary state and should be sized + * about half as large as the heap itself. Returns true on success. + */ +void sys_heap_stress(void *(*alloc_fn)(void *arg, size_t bytes), + void (*free_fn)(void *arg, void *p), + void *arg, size_t total_bytes, + uint32_t op_count, + void *scratch_mem, size_t scratch_bytes, + int target_percent, + struct z_heap_stress_result *result) +{ + struct z_heap_stress_rec sr = { + .alloc_fn = alloc_fn, + .free_fn = free_fn, + .arg = arg, + .total_bytes = total_bytes, + .blocks = scratch_mem, + .nblocks = scratch_bytes / sizeof(struct z_heap_stress_block), + .target_percent = target_percent, + }; + + *result = (struct z_heap_stress_result) {0}; + + for (uint32_t i = 0; i < op_count; i++) { + if (rand_alloc_choice(&sr)) { + size_t sz = rand_alloc_size(&sr); + void *p = sr.alloc_fn(sr.arg, sz); + + result->total_allocs++; + if (p != NULL) { + result->successful_allocs++; + sr.blocks[sr.blocks_alloced].ptr = p; + sr.blocks[sr.blocks_alloced].sz = sz; + sr.blocks_alloced++; + sr.bytes_alloced += sz; + } + } else { + int b = rand_free_choice(&sr); + void *p = sr.blocks[b].ptr; + size_t sz = sr.blocks[b].sz; + + result->total_frees++; + sr.blocks[b] = sr.blocks[sr.blocks_alloced - 1]; + sr.blocks_alloced--; + sr.bytes_alloced -= sz; + sr.free_fn(sr.arg, p); + } + result->accumulated_in_use_bytes += sr.bytes_alloced; + } +} diff --git a/lib/heap/heap-validate.c b/lib/heap/heap-validate.c index 18aafe71804..3d52a0d15c4 100644 --- a/lib/heap/heap-validate.c +++ b/lib/heap/heap-validate.c @@ -68,23 +68,6 @@ static inline void check_nexts(struct z_heap *h, int bidx) } } -static void get_alloc_info(struct z_heap *h, size_t *alloc_bytes, - size_t *free_bytes) -{ - chunkid_t c; - - *alloc_bytes = 0; - *free_bytes = 0; - - for (c = right_chunk(h, 0); c < h->end_chunk; c = right_chunk(h, c)) { - if (chunk_used(h, c)) { - *alloc_bytes += chunksz_to_bytes(h, chunk_size(h, c)); - } else if (!solo_free_header(h, c)) { - *free_bytes += chunksz_to_bytes(h, chunk_size(h, c)); - } - } -} - bool sys_heap_validate(struct sys_heap *heap) { struct z_heap *h = heap->heap; @@ -157,6 +140,7 @@ bool sys_heap_validate(struct sys_heap *heap) * USED. */ chunkid_t prev_chunk = 0; + for (c = right_chunk(h, 0); c < h->end_chunk; c = right_chunk(h, c)) { if (!chunk_used(h, c) && !solo_free_header(h, c)) { return false; @@ -201,216 +185,6 @@ bool sys_heap_validate(struct sys_heap *heap) return true; } -struct z_heap_stress_rec { - void *(*alloc_fn)(void *arg, size_t bytes); - void (*free_fn)(void *arg, void *p); - void *arg; - size_t total_bytes; - struct z_heap_stress_block *blocks; - size_t nblocks; - size_t blocks_alloced; - size_t bytes_alloced; - uint32_t target_percent; -}; - -struct z_heap_stress_block { - void *ptr; - size_t sz; -}; - -/* Very simple LCRNG (from https://nuclear.llnl.gov/CNP/rng/rngman/node4.html) - * - * Here to guarantee cross-platform test repeatability. - */ -static uint32_t rand32(void) -{ - static uint64_t state = 123456789; /* seed */ - - state = state * 2862933555777941757UL + 3037000493UL; - - return (uint32_t)(state >> 32); -} - -static bool rand_alloc_choice(struct z_heap_stress_rec *sr) -{ - /* Edge cases: no blocks allocated, and no space for a new one */ - if (sr->blocks_alloced == 0) { - return true; - } else if (sr->blocks_alloced >= sr->nblocks) { - return false; - } else { - - /* The way this works is to scale the chance of choosing to - * allocate vs. free such that it's even odds when the heap is - * at the target percent, with linear tapering on the low - * slope (i.e. we choose to always allocate with an empty - * heap, allocate 50% of the time when the heap is exactly at - * the target, and always free when above the target). In - * practice, the operations aren't quite symmetric (you can - * always free, but your allocation might fail), and the units - * aren't matched (we're doing math based on bytes allocated - * and ignoring the overhead) but this is close enough. And - * yes, the math here is coarse (in units of percent), but - * that's good enough and fits well inside 32 bit quantities. - * (Note precision issue when heap size is above 40MB - * though!). - */ - __ASSERT(sr->total_bytes < 0xffffffffU / 100, "too big for u32!"); - uint32_t full_pct = (100 * sr->bytes_alloced) / sr->total_bytes; - uint32_t target = sr->target_percent ? sr->target_percent : 1; - uint32_t free_chance = 0xffffffffU; - - if (full_pct < sr->target_percent) { - free_chance = full_pct * (0x80000000U / target); - } - - return rand32() > free_chance; - } -} - -/* Chooses a size of block to allocate, logarithmically favoring - * smaller blocks (i.e. blocks twice as large are half as frequent - */ -static size_t rand_alloc_size(struct z_heap_stress_rec *sr) -{ - ARG_UNUSED(sr); - - /* Min scale of 4 means that the half of the requests in the - * smallest size have an average size of 8 - */ - int scale = 4 + __builtin_clz(rand32()); - - return rand32() & BIT_MASK(scale); -} - -/* Returns the index of a randomly chosen block to free */ -static size_t rand_free_choice(struct z_heap_stress_rec *sr) -{ - return rand32() % sr->blocks_alloced; -} - -/* General purpose heap stress test. Takes function pointers to allow - * for testing multiple heap APIs with the same rig. The alloc and - * free functions are passed back the argument as a context pointer. - * The "log" function is for readable user output. The total_bytes - * argument should reflect the size of the heap being tested. The - * scratch array is used to store temporary state and should be sized - * about half as large as the heap itself. Returns true on success. - */ -void sys_heap_stress(void *(*alloc_fn)(void *arg, size_t bytes), - void (*free_fn)(void *arg, void *p), - void *arg, size_t total_bytes, - uint32_t op_count, - void *scratch_mem, size_t scratch_bytes, - int target_percent, - struct z_heap_stress_result *result) -{ - struct z_heap_stress_rec sr = { - .alloc_fn = alloc_fn, - .free_fn = free_fn, - .arg = arg, - .total_bytes = total_bytes, - .blocks = scratch_mem, - .nblocks = scratch_bytes / sizeof(struct z_heap_stress_block), - .target_percent = target_percent, - }; - - *result = (struct z_heap_stress_result) {0}; - - for (uint32_t i = 0; i < op_count; i++) { - if (rand_alloc_choice(&sr)) { - size_t sz = rand_alloc_size(&sr); - void *p = sr.alloc_fn(sr.arg, sz); - - result->total_allocs++; - if (p != NULL) { - result->successful_allocs++; - sr.blocks[sr.blocks_alloced].ptr = p; - sr.blocks[sr.blocks_alloced].sz = sz; - sr.blocks_alloced++; - sr.bytes_alloced += sz; - } - } else { - int b = rand_free_choice(&sr); - void *p = sr.blocks[b].ptr; - size_t sz = sr.blocks[b].sz; - - result->total_frees++; - sr.blocks[b] = sr.blocks[sr.blocks_alloced - 1]; - sr.blocks_alloced--; - sr.bytes_alloced -= sz; - sr.free_fn(sr.arg, p); - } - result->accumulated_in_use_bytes += sr.bytes_alloced; - } -} - -/* - * Print heap info for debugging / analysis purpose - */ -void heap_print_info(struct z_heap *h, bool dump_chunks) -{ - int i, nb_buckets = bucket_idx(h, h->end_chunk) + 1; - size_t free_bytes, allocated_bytes, total, overhead; - - printk("Heap at %p contains %d units in %d buckets\n\n", - chunk_buf(h), h->end_chunk, nb_buckets); - - printk(" bucket# min units total largest largest\n" - " threshold chunks (units) (bytes)\n" - " -----------------------------------------------------------\n"); - for (i = 0; i < nb_buckets; i++) { - chunkid_t first = h->buckets[i].next; - chunksz_t largest = 0; - int count = 0; - - if (first) { - chunkid_t curr = first; - do { - count++; - largest = MAX(largest, chunk_size(h, curr)); - curr = next_free_chunk(h, curr); - } while (curr != first); - } - if (count) { - printk("%9d %12d %12d %12d %12zd\n", - i, (1 << i) - 1 + min_chunk_size(h), count, - largest, chunksz_to_bytes(h, largest)); - } - } - - if (dump_chunks) { - printk("\nChunk dump:\n"); - for (chunkid_t c = 0; ; c = right_chunk(h, c)) { - printk("chunk %4d: [%c] size=%-4d left=%-4d right=%d\n", - c, - chunk_used(h, c) ? '*' - : solo_free_header(h, c) ? '.' - : '-', - chunk_size(h, c), - left_chunk(h, c), - right_chunk(h, c)); - if (c == h->end_chunk) { - break; - } - } - } - - get_alloc_info(h, &allocated_bytes, &free_bytes); - /* The end marker chunk has a header. It is part of the overhead. */ - total = h->end_chunk * CHUNK_UNIT + chunk_header_bytes(h); - overhead = total - free_bytes - allocated_bytes; - printk("\n%zd free bytes, %zd allocated bytes, overhead = %zd bytes (%zd.%zd%%)\n", - free_bytes, allocated_bytes, overhead, - (1000 * overhead + total/2) / total / 10, - (1000 * overhead + total/2) / total % 10); -} - -void sys_heap_print_info(struct sys_heap *heap, bool dump_chunks) -{ - heap_print_info(heap->heap, dump_chunks); -} - #ifdef CONFIG_SYS_HEAP_RUNTIME_STATS int sys_heap_runtime_stats_get(struct sys_heap *heap, diff --git a/lib/heap/heap.h b/lib/heap/heap.h index a29f4adfbd6..9e0354b0b21 100644 --- a/lib/heap/heap.h +++ b/lib/heap/heap.h @@ -262,6 +262,23 @@ static inline bool size_too_big(struct z_heap *h, size_t bytes) return (bytes / CHUNK_UNIT) >= h->end_chunk; } +static inline void get_alloc_info(struct z_heap *h, size_t *alloc_bytes, + size_t *free_bytes) +{ + chunkid_t c; + + *alloc_bytes = 0; + *free_bytes = 0; + + for (c = right_chunk(h, 0); c < h->end_chunk; c = right_chunk(h, c)) { + if (chunk_used(h, c)) { + *alloc_bytes += chunksz_to_bytes(h, chunk_size(h, c)); + } else if (!solo_free_header(h, c)) { + *free_bytes += chunksz_to_bytes(h, chunk_size(h, c)); + } + } +} + /* For debugging */ void heap_print_info(struct z_heap *h, bool dump_chunks); From d6d716b32a519f74e9605605a0287696677d848f Mon Sep 17 00:00:00 2001 From: Anas Nashif Date: Fri, 17 Nov 2023 19:08:11 -0500 Subject: [PATCH 1202/3723] lib: heap: build heap utilities only on demand Build the heap features only when needed and based on Kconfigs being set. Signed-off-by: Anas Nashif --- lib/heap/CMakeLists.txt | 4 ++-- lib/heap/Kconfig | 5 +++++ tests/lib/heap/prj.conf | 1 + 3 files changed, 8 insertions(+), 2 deletions(-) diff --git a/lib/heap/CMakeLists.txt b/lib/heap/CMakeLists.txt index fa297fbdca6..fc684cb98cd 100644 --- a/lib/heap/CMakeLists.txt +++ b/lib/heap/CMakeLists.txt @@ -2,12 +2,12 @@ zephyr_sources( heap.c - heap-validate.c - heap-stress.c heap-info.c multi_heap.c ) +zephyr_sources_ifdef(CONFIG_SYS_HEAP_VALIDATE heap-validate.c) +zephyr_sources_ifdef(CONFIG_SYS_HEAP_STRESS heap-stress.c) zephyr_sources_ifdef(CONFIG_SHARED_MULTI_HEAP shared_multi_heap.c) zephyr_sources_ifdef(CONFIG_HEAP_LISTENER heap_listener.c) diff --git a/lib/heap/Kconfig b/lib/heap/Kconfig index b913d6100dc..2dda1d197e2 100644 --- a/lib/heap/Kconfig +++ b/lib/heap/Kconfig @@ -13,6 +13,11 @@ config SYS_HEAP_VALIDATE environments that require sensitive detection of memory corruption. +config SYS_HEAP_STRESS + bool "General purpose heap stress test" + help + Stresses the heap. + config SYS_HEAP_ALLOC_LOOPS int "Number of tries in the inner heap allocation loop" default 3 diff --git a/tests/lib/heap/prj.conf b/tests/lib/heap/prj.conf index 036a06f8b0a..756fb274b5b 100644 --- a/tests/lib/heap/prj.conf +++ b/tests/lib/heap/prj.conf @@ -2,3 +2,4 @@ CONFIG_ZTEST=y CONFIG_SYS_HEAP_VALIDATE=y CONFIG_SYS_HEAP_RUNTIME_STATS=y CONFIG_SYS_HEAP_LISTENER=y +CONFIG_SYS_HEAP_STRESS=y From b9f2ac027087a8db6e8ba8ca735ad4736abb668b Mon Sep 17 00:00:00 2001 From: Anas Nashif Date: Fri, 17 Nov 2023 19:14:58 -0500 Subject: [PATCH 1203/3723] lib: heap: make heap_print_info static This should be declated static as it is being only called in this file. Signed-off-by: Anas Nashif --- lib/heap/heap-info.c | 2 +- lib/heap/heap.h | 3 --- 2 files changed, 1 insertion(+), 4 deletions(-) diff --git a/lib/heap/heap-info.c b/lib/heap/heap-info.c index 15d383f41e3..80640da2fd4 100644 --- a/lib/heap/heap-info.c +++ b/lib/heap/heap-info.c @@ -11,7 +11,7 @@ /* * Print heap info for debugging / analysis purpose */ -void heap_print_info(struct z_heap *h, bool dump_chunks) +static void heap_print_info(struct z_heap *h, bool dump_chunks) { int i, nb_buckets = bucket_idx(h, h->end_chunk) + 1; size_t free_bytes, allocated_bytes, total, overhead; diff --git a/lib/heap/heap.h b/lib/heap/heap.h index 9e0354b0b21..df11f18b9e0 100644 --- a/lib/heap/heap.h +++ b/lib/heap/heap.h @@ -279,7 +279,4 @@ static inline void get_alloc_info(struct z_heap *h, size_t *alloc_bytes, } } -/* For debugging */ -void heap_print_info(struct z_heap *h, bool dump_chunks); - #endif /* ZEPHYR_INCLUDE_LIB_OS_HEAP_H_ */ From dd2dcbed540f6368fd2ddab9325ff8bc8ed169aa Mon Sep 17 00:00:00 2001 From: Anas Nashif Date: Fri, 17 Nov 2023 19:24:10 -0500 Subject: [PATCH 1204/3723] tests: move mheap_api_concept into tests/lib/multi_heap Move multi-heap tests out of kernel folder along side all other heap related tests. Signed-off-by: Anas Nashif --- .../mem_heap/mheap_api_concept => lib/multi_heap}/CMakeLists.txt | 0 .../mem_heap/mheap_api_concept => lib/multi_heap}/prj.conf | 0 .../mem_heap/mheap_api_concept => lib/multi_heap}/src/main.c | 0 .../mheap_api_concept => lib/multi_heap}/src/test_mheap.h | 0 .../mheap_api_concept => lib/multi_heap}/src/test_mheap_api.c | 0 .../mheap_api_concept => lib/multi_heap}/src/test_mheap_concept.c | 0 .../mem_heap/mheap_api_concept => lib/multi_heap}/testcase.yaml | 0 7 files changed, 0 insertions(+), 0 deletions(-) rename tests/{kernel/mem_heap/mheap_api_concept => lib/multi_heap}/CMakeLists.txt (100%) rename tests/{kernel/mem_heap/mheap_api_concept => lib/multi_heap}/prj.conf (100%) rename tests/{kernel/mem_heap/mheap_api_concept => lib/multi_heap}/src/main.c (100%) rename tests/{kernel/mem_heap/mheap_api_concept => lib/multi_heap}/src/test_mheap.h (100%) rename tests/{kernel/mem_heap/mheap_api_concept => lib/multi_heap}/src/test_mheap_api.c (100%) rename tests/{kernel/mem_heap/mheap_api_concept => lib/multi_heap}/src/test_mheap_concept.c (100%) rename tests/{kernel/mem_heap/mheap_api_concept => lib/multi_heap}/testcase.yaml (100%) diff --git a/tests/kernel/mem_heap/mheap_api_concept/CMakeLists.txt b/tests/lib/multi_heap/CMakeLists.txt similarity index 100% rename from tests/kernel/mem_heap/mheap_api_concept/CMakeLists.txt rename to tests/lib/multi_heap/CMakeLists.txt diff --git a/tests/kernel/mem_heap/mheap_api_concept/prj.conf b/tests/lib/multi_heap/prj.conf similarity index 100% rename from tests/kernel/mem_heap/mheap_api_concept/prj.conf rename to tests/lib/multi_heap/prj.conf diff --git a/tests/kernel/mem_heap/mheap_api_concept/src/main.c b/tests/lib/multi_heap/src/main.c similarity index 100% rename from tests/kernel/mem_heap/mheap_api_concept/src/main.c rename to tests/lib/multi_heap/src/main.c diff --git a/tests/kernel/mem_heap/mheap_api_concept/src/test_mheap.h b/tests/lib/multi_heap/src/test_mheap.h similarity index 100% rename from tests/kernel/mem_heap/mheap_api_concept/src/test_mheap.h rename to tests/lib/multi_heap/src/test_mheap.h diff --git a/tests/kernel/mem_heap/mheap_api_concept/src/test_mheap_api.c b/tests/lib/multi_heap/src/test_mheap_api.c similarity index 100% rename from tests/kernel/mem_heap/mheap_api_concept/src/test_mheap_api.c rename to tests/lib/multi_heap/src/test_mheap_api.c diff --git a/tests/kernel/mem_heap/mheap_api_concept/src/test_mheap_concept.c b/tests/lib/multi_heap/src/test_mheap_concept.c similarity index 100% rename from tests/kernel/mem_heap/mheap_api_concept/src/test_mheap_concept.c rename to tests/lib/multi_heap/src/test_mheap_concept.c diff --git a/tests/kernel/mem_heap/mheap_api_concept/testcase.yaml b/tests/lib/multi_heap/testcase.yaml similarity index 100% rename from tests/kernel/mem_heap/mheap_api_concept/testcase.yaml rename to tests/lib/multi_heap/testcase.yaml From 44381f957a8eba8cdd513da8c4eee9031a0d7edb Mon Sep 17 00:00:00 2001 From: Anas Nashif Date: Fri, 17 Nov 2023 19:27:19 -0500 Subject: [PATCH 1205/3723] tests: multi_heap: adapt test identifiers Change identifier to match with other heap related tests. Signed-off-by: Anas Nashif --- tests/lib/multi_heap/testcase.yaml | 10 ++++------ 1 file changed, 4 insertions(+), 6 deletions(-) diff --git a/tests/lib/multi_heap/testcase.yaml b/tests/lib/multi_heap/testcase.yaml index 380c9a0726f..7780e09193a 100644 --- a/tests/lib/multi_heap/testcase.yaml +++ b/tests/lib/multi_heap/testcase.yaml @@ -1,14 +1,12 @@ tests: - kernel.memory_heap: + libraries.multi_heap: tags: - - kernel - - memory_heap + - multi_heap extra_configs: - CONFIG_IRQ_OFFLOAD=y - kernel.memory_heap.no_mt: + libraries.multi_heap.no_mt: tags: - - kernel - - memory_heap + - multi_heap platform_allow: - qemu_cortex_m3 - qemu_cortex_m0 From 11365fc4f8c0280894d1293c75a1f0e246c21fcf Mon Sep 17 00:00:00 2001 From: Anas Nashif Date: Fri, 17 Nov 2023 19:30:30 -0500 Subject: [PATCH 1206/3723] tests: move shared_multi_heap to tests/lib Move shared_multi_heap test under lib alongside all other heap tests. Signed-off-by: Anas Nashif --- tests/{kernel/mem_heap => lib}/shared_multi_heap/CMakeLists.txt | 0 .../mem_heap => lib}/shared_multi_heap/boards/mps2_an521.overlay | 0 .../shared_multi_heap/boards/qemu_cortex_a53.conf | 0 .../shared_multi_heap/boards/qemu_cortex_a53.overlay | 0 .../shared_multi_heap/linker_arm64_shared_pool.ld | 0 tests/{kernel/mem_heap => lib}/shared_multi_heap/prj.conf | 0 tests/{kernel/mem_heap => lib}/shared_multi_heap/src/main.c | 0 tests/{kernel/mem_heap => lib}/shared_multi_heap/testcase.yaml | 0 tests/subsys/mem_mgmt/mem_attr_heap/prj.conf | 1 + 9 files changed, 1 insertion(+) rename tests/{kernel/mem_heap => lib}/shared_multi_heap/CMakeLists.txt (100%) rename tests/{kernel/mem_heap => lib}/shared_multi_heap/boards/mps2_an521.overlay (100%) rename tests/{kernel/mem_heap => lib}/shared_multi_heap/boards/qemu_cortex_a53.conf (100%) rename tests/{kernel/mem_heap => lib}/shared_multi_heap/boards/qemu_cortex_a53.overlay (100%) rename tests/{kernel/mem_heap => lib}/shared_multi_heap/linker_arm64_shared_pool.ld (100%) rename tests/{kernel/mem_heap => lib}/shared_multi_heap/prj.conf (100%) rename tests/{kernel/mem_heap => lib}/shared_multi_heap/src/main.c (100%) rename tests/{kernel/mem_heap => lib}/shared_multi_heap/testcase.yaml (100%) diff --git a/tests/kernel/mem_heap/shared_multi_heap/CMakeLists.txt b/tests/lib/shared_multi_heap/CMakeLists.txt similarity index 100% rename from tests/kernel/mem_heap/shared_multi_heap/CMakeLists.txt rename to tests/lib/shared_multi_heap/CMakeLists.txt diff --git a/tests/kernel/mem_heap/shared_multi_heap/boards/mps2_an521.overlay b/tests/lib/shared_multi_heap/boards/mps2_an521.overlay similarity index 100% rename from tests/kernel/mem_heap/shared_multi_heap/boards/mps2_an521.overlay rename to tests/lib/shared_multi_heap/boards/mps2_an521.overlay diff --git a/tests/kernel/mem_heap/shared_multi_heap/boards/qemu_cortex_a53.conf b/tests/lib/shared_multi_heap/boards/qemu_cortex_a53.conf similarity index 100% rename from tests/kernel/mem_heap/shared_multi_heap/boards/qemu_cortex_a53.conf rename to tests/lib/shared_multi_heap/boards/qemu_cortex_a53.conf diff --git a/tests/kernel/mem_heap/shared_multi_heap/boards/qemu_cortex_a53.overlay b/tests/lib/shared_multi_heap/boards/qemu_cortex_a53.overlay similarity index 100% rename from tests/kernel/mem_heap/shared_multi_heap/boards/qemu_cortex_a53.overlay rename to tests/lib/shared_multi_heap/boards/qemu_cortex_a53.overlay diff --git a/tests/kernel/mem_heap/shared_multi_heap/linker_arm64_shared_pool.ld b/tests/lib/shared_multi_heap/linker_arm64_shared_pool.ld similarity index 100% rename from tests/kernel/mem_heap/shared_multi_heap/linker_arm64_shared_pool.ld rename to tests/lib/shared_multi_heap/linker_arm64_shared_pool.ld diff --git a/tests/kernel/mem_heap/shared_multi_heap/prj.conf b/tests/lib/shared_multi_heap/prj.conf similarity index 100% rename from tests/kernel/mem_heap/shared_multi_heap/prj.conf rename to tests/lib/shared_multi_heap/prj.conf diff --git a/tests/kernel/mem_heap/shared_multi_heap/src/main.c b/tests/lib/shared_multi_heap/src/main.c similarity index 100% rename from tests/kernel/mem_heap/shared_multi_heap/src/main.c rename to tests/lib/shared_multi_heap/src/main.c diff --git a/tests/kernel/mem_heap/shared_multi_heap/testcase.yaml b/tests/lib/shared_multi_heap/testcase.yaml similarity index 100% rename from tests/kernel/mem_heap/shared_multi_heap/testcase.yaml rename to tests/lib/shared_multi_heap/testcase.yaml diff --git a/tests/subsys/mem_mgmt/mem_attr_heap/prj.conf b/tests/subsys/mem_mgmt/mem_attr_heap/prj.conf index 64c26116108..0110280e258 100644 --- a/tests/subsys/mem_mgmt/mem_attr_heap/prj.conf +++ b/tests/subsys/mem_mgmt/mem_attr_heap/prj.conf @@ -4,3 +4,4 @@ CONFIG_ZTEST=y CONFIG_MEM_ATTR=y CONFIG_MEM_ATTR_HEAP=y +CONFIG_SHARED_MULTI_HEAP=y From 2e24e9da9e0075f55e3316791ea692a608ea3645 Mon Sep 17 00:00:00 2001 From: Anas Nashif Date: Fri, 17 Nov 2023 19:31:22 -0500 Subject: [PATCH 1207/3723] tests: shared_multi_heap: fix identifier Adapt identifier and be consistent with other heap tests. Signed-off-by: Anas Nashif --- tests/lib/shared_multi_heap/testcase.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/lib/shared_multi_heap/testcase.yaml b/tests/lib/shared_multi_heap/testcase.yaml index d839512b86e..5580716785d 100644 --- a/tests/lib/shared_multi_heap/testcase.yaml +++ b/tests/lib/shared_multi_heap/testcase.yaml @@ -2,7 +2,7 @@ # SPDX-License-Identifier: Apache-2.0 tests: - kernel.shared_multi_heap: + libraries.shared_multi_heap: platform_allow: - qemu_cortex_a53 - mps2_an521 From 00680bd23ac5bdd0b737f2d3d89b4abe3f140872 Mon Sep 17 00:00:00 2001 From: Anas Nashif Date: Fri, 17 Nov 2023 19:33:17 -0500 Subject: [PATCH 1208/3723] lib: heap: rename with files and use _ be consistent with other files in the same folder. Signed-off-by: Anas Nashif --- lib/heap/CMakeLists.txt | 6 +++--- lib/heap/{heap-info.c => heap_info.c} | 0 lib/heap/{heap-stress.c => heap_stress.c} | 0 lib/heap/{heap-validate.c => heap_validate.c} | 0 4 files changed, 3 insertions(+), 3 deletions(-) rename lib/heap/{heap-info.c => heap_info.c} (100%) rename lib/heap/{heap-stress.c => heap_stress.c} (100%) rename lib/heap/{heap-validate.c => heap_validate.c} (100%) diff --git a/lib/heap/CMakeLists.txt b/lib/heap/CMakeLists.txt index fc684cb98cd..58fc62fa82b 100644 --- a/lib/heap/CMakeLists.txt +++ b/lib/heap/CMakeLists.txt @@ -2,12 +2,12 @@ zephyr_sources( heap.c - heap-info.c + heap_info.c multi_heap.c ) -zephyr_sources_ifdef(CONFIG_SYS_HEAP_VALIDATE heap-validate.c) -zephyr_sources_ifdef(CONFIG_SYS_HEAP_STRESS heap-stress.c) +zephyr_sources_ifdef(CONFIG_SYS_HEAP_VALIDATE heap_validate.c) +zephyr_sources_ifdef(CONFIG_SYS_HEAP_STRESS heap_stress.c) zephyr_sources_ifdef(CONFIG_SHARED_MULTI_HEAP shared_multi_heap.c) zephyr_sources_ifdef(CONFIG_HEAP_LISTENER heap_listener.c) diff --git a/lib/heap/heap-info.c b/lib/heap/heap_info.c similarity index 100% rename from lib/heap/heap-info.c rename to lib/heap/heap_info.c diff --git a/lib/heap/heap-stress.c b/lib/heap/heap_stress.c similarity index 100% rename from lib/heap/heap-stress.c rename to lib/heap/heap_stress.c diff --git a/lib/heap/heap-validate.c b/lib/heap/heap_validate.c similarity index 100% rename from lib/heap/heap-validate.c rename to lib/heap/heap_validate.c From d398e9631bfbfee5e2dc1b42c426ef98b928ea7e Mon Sep 17 00:00:00 2001 From: Anas Nashif Date: Fri, 17 Nov 2023 19:42:42 -0500 Subject: [PATCH 1209/3723] lib: heap: build heap_info conditionally Only build when needed and adapt existing users to pull this in when needed. Signed-off-by: Anas Nashif --- lib/heap/CMakeLists.txt | 2 +- lib/heap/Kconfig | 12 ++++++++++++ modules/lvgl/Kconfig.memory | 1 + 3 files changed, 14 insertions(+), 1 deletion(-) diff --git a/lib/heap/CMakeLists.txt b/lib/heap/CMakeLists.txt index 58fc62fa82b..0224a864dcb 100644 --- a/lib/heap/CMakeLists.txt +++ b/lib/heap/CMakeLists.txt @@ -2,10 +2,10 @@ zephyr_sources( heap.c - heap_info.c multi_heap.c ) +zephyr_sources_ifdef(CONFIG_SYS_HEAP_INFO heap_info.c) zephyr_sources_ifdef(CONFIG_SYS_HEAP_VALIDATE heap_validate.c) zephyr_sources_ifdef(CONFIG_SYS_HEAP_STRESS heap_stress.c) zephyr_sources_ifdef(CONFIG_SHARED_MULTI_HEAP shared_multi_heap.c) diff --git a/lib/heap/Kconfig b/lib/heap/Kconfig index 2dda1d197e2..8a79bea77d9 100644 --- a/lib/heap/Kconfig +++ b/lib/heap/Kconfig @@ -13,11 +13,23 @@ config SYS_HEAP_VALIDATE environments that require sensitive detection of memory corruption. + Use for testing and validation only. + config SYS_HEAP_STRESS bool "General purpose heap stress test" help Stresses the heap. + Use for testing and validation only. + +config SYS_HEAP_INFO + bool "Heap internal structure information" + help + Enables support for printing heap internal structure + information to the console. + + Use for debugging only. + config SYS_HEAP_ALLOC_LOOPS int "Number of tries in the inner heap allocation loop" default 3 diff --git a/modules/lvgl/Kconfig.memory b/modules/lvgl/Kconfig.memory index fc59eccb2e3..6cb1b197d9d 100644 --- a/modules/lvgl/Kconfig.memory +++ b/modules/lvgl/Kconfig.memory @@ -26,6 +26,7 @@ choice LV_Z_MEMORY_POOL config LV_Z_MEM_POOL_SYS_HEAP bool "User space lvgl pool" + select SYS_HEAP_INFO help Use a dedicated memory pool from a private sys heap. From 740d0c3b50616d20bd5ffaa2072b5c502b507900 Mon Sep 17 00:00:00 2001 From: Anas Nashif Date: Fri, 17 Nov 2023 19:52:48 -0500 Subject: [PATCH 1210/3723] lib: heap: make multi-heap feature configurable Make multi-heap configurable via Kconfig and adapt existing tests. Signed-off-by: Anas Nashif --- lib/heap/CMakeLists.txt | 3 +-- lib/heap/Kconfig | 12 ++++++++++++ tests/lib/multi_heap/prj.conf | 1 + 3 files changed, 14 insertions(+), 2 deletions(-) diff --git a/lib/heap/CMakeLists.txt b/lib/heap/CMakeLists.txt index 0224a864dcb..06508170b23 100644 --- a/lib/heap/CMakeLists.txt +++ b/lib/heap/CMakeLists.txt @@ -2,12 +2,11 @@ zephyr_sources( heap.c - multi_heap.c ) zephyr_sources_ifdef(CONFIG_SYS_HEAP_INFO heap_info.c) zephyr_sources_ifdef(CONFIG_SYS_HEAP_VALIDATE heap_validate.c) zephyr_sources_ifdef(CONFIG_SYS_HEAP_STRESS heap_stress.c) zephyr_sources_ifdef(CONFIG_SHARED_MULTI_HEAP shared_multi_heap.c) - +zephyr_sources_ifdef(CONFIG_MULTI_HEAP multi_heap.c) zephyr_sources_ifdef(CONFIG_HEAP_LISTENER heap_listener.c) diff --git a/lib/heap/Kconfig b/lib/heap/Kconfig index 8a79bea77d9..4f08bccf7c4 100644 --- a/lib/heap/Kconfig +++ b/lib/heap/Kconfig @@ -112,8 +112,20 @@ config SYS_HEAP_AUTO endchoice +config MULTI_HEAP + bool "Multi-heap manager" + help + Allows multiple sys_heap regions to be unified under a single + allocation API. Sometimes apps need the ability to share multiple + discontiguous regions in a single "heap", or + to have memory of different "types" be allocated heuristically based + on usage (e.g. cacheability, latency, power...). This allows a + user-specified function to select the underlying memory to use for + each application. + config SHARED_MULTI_HEAP bool "Shared multi-heap manager" + select MULTI_HEAP help Enable support for a shared multi-heap manager that uses the multi-heap allocator to manage a set of reserved memory regions with diff --git a/tests/lib/multi_heap/prj.conf b/tests/lib/multi_heap/prj.conf index 9491650b184..6952ca2acfc 100644 --- a/tests/lib/multi_heap/prj.conf +++ b/tests/lib/multi_heap/prj.conf @@ -1,2 +1,3 @@ CONFIG_ZTEST=y CONFIG_HEAP_MEM_POOL_SIZE=256 +CONFIG_MULTI_HEAP=y From d4c881da04bd501acac4f6c877de3db1f671e728 Mon Sep 17 00:00:00 2001 From: Anas Nashif Date: Sat, 18 Nov 2023 04:24:45 -0500 Subject: [PATCH 1211/3723] lib: mem_block: move to own folder Move mem_block into own folder and seperate from lib/os and heap configuration. Signed-off-by: Anas Nashif --- lib/CMakeLists.txt | 1 + lib/Kconfig | 2 ++ lib/heap/Kconfig | 47 ------------------------- lib/mem_blocks/CMakeLists.txt | 3 ++ lib/mem_blocks/Kconfig | 54 +++++++++++++++++++++++++++++ lib/{os => mem_blocks}/mem_blocks.c | 0 lib/os/CMakeLists.txt | 2 -- lib/os/Kconfig | 1 - 8 files changed, 60 insertions(+), 50 deletions(-) create mode 100644 lib/mem_blocks/CMakeLists.txt create mode 100644 lib/mem_blocks/Kconfig rename lib/{os => mem_blocks}/mem_blocks.c (100%) diff --git a/lib/CMakeLists.txt b/lib/CMakeLists.txt index ceba13bc2af..75387fdbb9a 100644 --- a/lib/CMakeLists.txt +++ b/lib/CMakeLists.txt @@ -11,6 +11,7 @@ endif() add_subdirectory_ifdef(CONFIG_CPP cpp) add_subdirectory(hash) add_subdirectory(heap) +add_subdirectory(mem_blocks) add_subdirectory(os) add_subdirectory_ifdef(CONFIG_SMF smf) add_subdirectory_ifdef(CONFIG_OPENAMP open-amp) diff --git a/lib/Kconfig b/lib/Kconfig index 9b6eb56d275..1b95bde76b1 100644 --- a/lib/Kconfig +++ b/lib/Kconfig @@ -13,6 +13,8 @@ source "lib/hash/Kconfig" source "lib/heap/Kconfig" +source "lib/mem_blocks/Kconfig" + source "lib/os/Kconfig" source "lib/posix/Kconfig" diff --git a/lib/heap/Kconfig b/lib/heap/Kconfig index 4f08bccf7c4..7f01b280b3b 100644 --- a/lib/heap/Kconfig +++ b/lib/heap/Kconfig @@ -132,51 +132,4 @@ config SHARED_MULTI_HEAP different capabilities / attributes (cacheable, non-cacheable, etc...) defined in the DT. -config SYS_MEM_BLOCKS - bool "(Yet Another) Memory Blocks Allocator" - help - This enables support for memory block allocator where: - () All memory blocks have a single fixed size. - () Multiple blocks can be allocated or freed at the same time. - () A group of blocks allocated together may not be contiguous. - This is useful for operations such as scatter-gather DMA - transfers. - () Bookkeeping of allocated blocks is done outside of - the associated buffer (unlike memory slab). This allows - the buffer to reside in memory regions where these can be - powered down to conserve energy. - -config SYS_MEM_BLOCKS_LISTENER - bool "Memory Blocks Allocator event notifications" - depends on SYS_MEM_BLOCKS - select HEAP_LISTENER - help - This allows application to listen for memory blocks allocator - events, such as memory allocation and de-allocation. - -config SYS_MEM_BLOCKS_RUNTIME_STATS - bool "Memory blocks runtime statistics" - depends on SYS_MEM_BLOCKS - help - This option enables the tracking and reporting of the memory - blocks statistics related to the current and maximum number - of allocations in a given memory block. - -config OBJ_CORE_SYS_MEM_BLOCKS - bool "Kernel object for memory blocks" - depends on SYS_MEM_BLOCKS && OBJ_CORE - default y if SYS_MEM_BLOCKS && OBJ_CORE - help - This option allows object cores to be integrated into memory block - objects. - -config OBJ_CORE_STATS_SYS_MEM_BLOCKS - bool "Object core statistics for memory blocks" - depends on SYS_MEM_BLOCKS && OBJ_CORE_STATS - default y if SYS_MEM_BLOCKS && OBJ_CORE_STATS - select SYS_MEM_BLOCKS_RUNTIME_STATS - help - This option integrates the object core statistics framework into - the memory blocks. - endmenu diff --git a/lib/mem_blocks/CMakeLists.txt b/lib/mem_blocks/CMakeLists.txt new file mode 100644 index 00000000000..9bf33924172 --- /dev/null +++ b/lib/mem_blocks/CMakeLists.txt @@ -0,0 +1,3 @@ +# SPDX-License-Identifier: Apache-2.0 + +zephyr_sources_ifdef(CONFIG_SYS_MEM_BLOCKS mem_blocks.c) diff --git a/lib/mem_blocks/Kconfig b/lib/mem_blocks/Kconfig new file mode 100644 index 00000000000..ea04f8be97b --- /dev/null +++ b/lib/mem_blocks/Kconfig @@ -0,0 +1,54 @@ +# Copyright (c) 2021,2023 Intel Corporation +# +# SPDX-License-Identifier: Apache-2.0 + +menu "Memory Blocks" + +config SYS_MEM_BLOCKS + bool "(Yet Another) Memory Blocks Allocator" + help + This enables support for memory block allocator where: + () All memory blocks have a single fixed size. + () Multiple blocks can be allocated or freed at the same time. + () A group of blocks allocated together may not be contiguous. + This is useful for operations such as scatter-gather DMA + transfers. + () Bookkeeping of allocated blocks is done outside of + the associated buffer (unlike memory slab). This allows + the buffer to reside in memory regions where these can be + powered down to conserve energy. + +config SYS_MEM_BLOCKS_LISTENER + bool "Memory Blocks Allocator event notifications" + depends on SYS_MEM_BLOCKS + select HEAP_LISTENER + help + This allows application to listen for memory blocks allocator + events, such as memory allocation and de-allocation. + +config SYS_MEM_BLOCKS_RUNTIME_STATS + bool "Memory blocks runtime statistics" + depends on SYS_MEM_BLOCKS + help + This option enables the tracking and reporting of the memory + blocks statistics related to the current and maximum number + of allocations in a given memory block. + +config OBJ_CORE_SYS_MEM_BLOCKS + bool "Kernel object for memory blocks" + depends on SYS_MEM_BLOCKS && OBJ_CORE + default y if SYS_MEM_BLOCKS && OBJ_CORE + help + This option allows object cores to be integrated into memory block + objects. + +config OBJ_CORE_STATS_SYS_MEM_BLOCKS + bool "Object core statistics for memory blocks" + depends on SYS_MEM_BLOCKS && OBJ_CORE_STATS + default y if SYS_MEM_BLOCKS && OBJ_CORE_STATS + select SYS_MEM_BLOCKS_RUNTIME_STATS + help + This option integrates the object core statistics framework into + the memory blocks. + +endmenu diff --git a/lib/os/mem_blocks.c b/lib/mem_blocks/mem_blocks.c similarity index 100% rename from lib/os/mem_blocks.c rename to lib/mem_blocks/mem_blocks.c diff --git a/lib/os/CMakeLists.txt b/lib/os/CMakeLists.txt index 4f403c2a289..47d4501ca0b 100644 --- a/lib/os/CMakeLists.txt +++ b/lib/os/CMakeLists.txt @@ -49,8 +49,6 @@ zephyr_sources_ifdef(CONFIG_REBOOT reboot.c) zephyr_sources_ifdef(CONFIG_UTF8 utf8.c) -zephyr_sources_ifdef(CONFIG_SYS_MEM_BLOCKS mem_blocks.c) - zephyr_sources_ifdef(CONFIG_WINSTREAM winstream.c) zephyr_sources_ifdef(CONFIG_POWEROFF poweroff.c) diff --git a/lib/os/Kconfig b/lib/os/Kconfig index 8b41f92f5b2..2f67b2da4dc 100644 --- a/lib/os/Kconfig +++ b/lib/os/Kconfig @@ -169,5 +169,4 @@ config UTF8 rsource "Kconfig.cbprintf" - endmenu From 246ec224e2866721cc4ac6f807ac0768701c9c2d Mon Sep 17 00:00:00 2001 From: Anas Nashif Date: Fri, 24 Nov 2023 07:40:06 -0500 Subject: [PATCH 1212/3723] lib: heap: move heap stats to own file heap stats are split out from heap_validate.c into own file. Signed-off-by: Anas Nashif --- lib/heap/CMakeLists.txt | 1 + lib/heap/heap_stats.c | 34 ++++++++++++++++++++++++++++++++++ lib/heap/heap_validate.c | 29 ----------------------------- 3 files changed, 35 insertions(+), 29 deletions(-) create mode 100644 lib/heap/heap_stats.c diff --git a/lib/heap/CMakeLists.txt b/lib/heap/CMakeLists.txt index 06508170b23..f3853fc5b7d 100644 --- a/lib/heap/CMakeLists.txt +++ b/lib/heap/CMakeLists.txt @@ -4,6 +4,7 @@ zephyr_sources( heap.c ) +zephyr_sources_ifdef(CONFIG_SYS_HEAP_RUNTIME_STATS heap_stats.c) zephyr_sources_ifdef(CONFIG_SYS_HEAP_INFO heap_info.c) zephyr_sources_ifdef(CONFIG_SYS_HEAP_VALIDATE heap_validate.c) zephyr_sources_ifdef(CONFIG_SYS_HEAP_STRESS heap_stress.c) diff --git a/lib/heap/heap_stats.c b/lib/heap/heap_stats.c new file mode 100644 index 00000000000..e9c28b96d2f --- /dev/null +++ b/lib/heap/heap_stats.c @@ -0,0 +1,34 @@ +/* + * Copyright (c) 2019,2023 Intel Corporation + * + * SPDX-License-Identifier: Apache-2.0 + */ +#include +#include +#include +#include "heap.h" + +int sys_heap_runtime_stats_get(struct sys_heap *heap, + struct sys_memory_stats *stats) +{ + if ((heap == NULL) || (stats == NULL)) { + return -EINVAL; + } + + stats->free_bytes = heap->heap->free_bytes; + stats->allocated_bytes = heap->heap->allocated_bytes; + stats->max_allocated_bytes = heap->heap->max_allocated_bytes; + + return 0; +} + +int sys_heap_runtime_stats_reset_max(struct sys_heap *heap) +{ + if (heap == NULL) { + return -EINVAL; + } + + heap->heap->max_allocated_bytes = heap->heap->allocated_bytes; + + return 0; +} diff --git a/lib/heap/heap_validate.c b/lib/heap/heap_validate.c index 3d52a0d15c4..af63c8cdd8c 100644 --- a/lib/heap/heap_validate.c +++ b/lib/heap/heap_validate.c @@ -184,32 +184,3 @@ bool sys_heap_validate(struct sys_heap *heap) } return true; } - -#ifdef CONFIG_SYS_HEAP_RUNTIME_STATS - -int sys_heap_runtime_stats_get(struct sys_heap *heap, - struct sys_memory_stats *stats) -{ - if ((heap == NULL) || (stats == NULL)) { - return -EINVAL; - } - - stats->free_bytes = heap->heap->free_bytes; - stats->allocated_bytes = heap->heap->allocated_bytes; - stats->max_allocated_bytes = heap->heap->max_allocated_bytes; - - return 0; -} - -int sys_heap_runtime_stats_reset_max(struct sys_heap *heap) -{ - if (heap == NULL) { - return -EINVAL; - } - - heap->heap->max_allocated_bytes = heap->heap->allocated_bytes; - - return 0; -} - -#endif From 5ff4f46d9e8ba8f0f13efef470640b6370c0f7d2 Mon Sep 17 00:00:00 2001 From: Maureen Helm Date: Tue, 14 Nov 2023 17:38:25 -0600 Subject: [PATCH 1213/3723] tests: drivers: dma: Refactor tests to use data relocation Eliminates dma tests' dependency on CONFIG_NOCACHE_MEMORY=y for configuring dma data linker sections. This allows optionally relocating dma source and destination data to sram or other custom linker section on boards that don't support dma access to flash. Signed-off-by: Maureen Helm --- .../dma/chan_blen_transfer/CMakeLists.txt | 2 ++ tests/drivers/dma/chan_blen_transfer/Kconfig | 6 +++--- .../chan_blen_transfer/boards/nucleo_h743zi.conf | 3 ++- .../dma/chan_blen_transfer/src/test_dma.c | 16 ++-------------- tests/drivers/dma/loop_transfer/CMakeLists.txt | 2 ++ tests/drivers/dma/loop_transfer/Kconfig | 6 +++--- .../dma/loop_transfer/boards/nucleo_h743zi.conf | 3 ++- .../dma/loop_transfer/src/test_dma_loop.c | 12 ++---------- 8 files changed, 18 insertions(+), 32 deletions(-) diff --git a/tests/drivers/dma/chan_blen_transfer/CMakeLists.txt b/tests/drivers/dma/chan_blen_transfer/CMakeLists.txt index e1bba7f3f65..7683c4ebce2 100644 --- a/tests/drivers/dma/chan_blen_transfer/CMakeLists.txt +++ b/tests/drivers/dma/chan_blen_transfer/CMakeLists.txt @@ -6,3 +6,5 @@ project(chan_blen_transfer) FILE(GLOB app_sources src/*.c) target_sources(app PRIVATE ${app_sources}) + +zephyr_code_relocate(FILES src/test_dma.c LOCATION ${CONFIG_DMA_LOOP_TRANSFER_RELOCATE_SECTION}_RODATA_BSS) diff --git a/tests/drivers/dma/chan_blen_transfer/Kconfig b/tests/drivers/dma/chan_blen_transfer/Kconfig index 748f380b71e..8be4efa636a 100644 --- a/tests/drivers/dma/chan_blen_transfer/Kconfig +++ b/tests/drivers/dma/chan_blen_transfer/Kconfig @@ -13,10 +13,10 @@ config DMA_TRANSFER_CHANNEL_NR_1 int "second DMA channel to use" default 1 -config DMA_LOOP_TRANSFER_SRAM_SECTION +config DMA_LOOP_TRANSFER_RELOCATE_SECTION string "the section to place the memory buffers." - depends on NOCACHE_MEMORY - default ".nocache" + depends on CODE_DATA_RELOCATION + default "RAM" config DMA_LOOP_TRANSFER_NUMBER_OF_DMAS int "Number of DMAs to test" diff --git a/tests/drivers/dma/chan_blen_transfer/boards/nucleo_h743zi.conf b/tests/drivers/dma/chan_blen_transfer/boards/nucleo_h743zi.conf index 9baa0e8a2fc..05e4ba8623e 100644 --- a/tests/drivers/dma/chan_blen_transfer/boards/nucleo_h743zi.conf +++ b/tests/drivers/dma/chan_blen_transfer/boards/nucleo_h743zi.conf @@ -5,7 +5,8 @@ CONFIG_DMA_LOOP_TRANSFER_NUMBER_OF_DMAS=2 # Required by BDMA which only has access to # a NOCACHE SRAM4 section. All other DMAs also # has access to this section. -CONFIG_DMA_LOOP_TRANSFER_SRAM_SECTION="SRAM4.dma" +CONFIG_CODE_DATA_RELOCATION=y +CONFIG_DMA_LOOP_TRANSFER_RELOCATE_SECTION="SRAM4" # Required for SRAM4 to be non-cachable CONFIG_NOCACHE_MEMORY=y diff --git a/tests/drivers/dma/chan_blen_transfer/src/test_dma.c b/tests/drivers/dma/chan_blen_transfer/src/test_dma.c index 312e7666aec..a546715f37f 100644 --- a/tests/drivers/dma/chan_blen_transfer/src/test_dma.c +++ b/tests/drivers/dma/chan_blen_transfer/src/test_dma.c @@ -22,16 +22,8 @@ #define RX_BUFF_SIZE (48) -#ifdef CONFIG_NOCACHE_MEMORY -static __aligned(32) char tx_data[RX_BUFF_SIZE] __used - __attribute__((__section__(CONFIG_DMA_LOOP_TRANSFER_SRAM_SECTION))); -static const char TX_DATA[] = "It is harder to be kind than to be wise........"; -static __aligned(32) char rx_data[RX_BUFF_SIZE] __used - __attribute__((__section__(CONFIG_DMA_LOOP_TRANSFER_SRAM_SECTION".dma"))); -#else -static const char tx_data[] = "It is harder to be kind than to be wise........"; -static char rx_data[RX_BUFF_SIZE] = { 0 }; -#endif +static __aligned(32) const char tx_data[] = "It is harder to be kind than to be wise........"; +static __aligned(32) char rx_data[RX_BUFF_SIZE] = { 0 }; static void test_done(const struct device *dma_dev, void *arg, uint32_t id, int status) @@ -53,10 +45,6 @@ static int test_task(const struct device *dma, uint32_t chan_id, uint32_t blen) return TC_FAIL; } -#ifdef CONFIG_NOCACHE_MEMORY - memcpy(tx_data, TX_DATA, sizeof(TX_DATA)); -#endif - dma_cfg.channel_direction = MEMORY_TO_MEMORY; dma_cfg.source_data_size = 1U; dma_cfg.dest_data_size = 1U; diff --git a/tests/drivers/dma/loop_transfer/CMakeLists.txt b/tests/drivers/dma/loop_transfer/CMakeLists.txt index 028e0e5d60b..2cbc79c80f4 100644 --- a/tests/drivers/dma/loop_transfer/CMakeLists.txt +++ b/tests/drivers/dma/loop_transfer/CMakeLists.txt @@ -6,3 +6,5 @@ project(loop_transfer) FILE(GLOB app_sources src/*.c) target_sources(app PRIVATE ${app_sources}) + +zephyr_code_relocate(FILES src/test_dma_loop.c LOCATION ${CONFIG_DMA_LOOP_TRANSFER_RELOCATE_SECTION}_RODATA_BSS) diff --git a/tests/drivers/dma/loop_transfer/Kconfig b/tests/drivers/dma/loop_transfer/Kconfig index 9f6ca2a8e5d..e06d84296b2 100644 --- a/tests/drivers/dma/loop_transfer/Kconfig +++ b/tests/drivers/dma/loop_transfer/Kconfig @@ -9,10 +9,10 @@ config DMA_LOOP_TRANSFER_CHANNEL_NR int "DMA channel to use" default 0 -config DMA_LOOP_TRANSFER_SRAM_SECTION +config DMA_LOOP_TRANSFER_RELOCATE_SECTION string "the section to place the memory buffers." - depends on NOCACHE_MEMORY - default ".nocache" + depends on CODE_DATA_RELOCATION + default "RAM" config DMA_LOOP_TRANSFER_NUMBER_OF_DMAS int "Number of DMAs to test" diff --git a/tests/drivers/dma/loop_transfer/boards/nucleo_h743zi.conf b/tests/drivers/dma/loop_transfer/boards/nucleo_h743zi.conf index 6d04df24ec1..a179977c116 100644 --- a/tests/drivers/dma/loop_transfer/boards/nucleo_h743zi.conf +++ b/tests/drivers/dma/loop_transfer/boards/nucleo_h743zi.conf @@ -4,7 +4,8 @@ CONFIG_DMA_LOOP_TRANSFER_NUMBER_OF_DMAS=2 # Required by BDMA which only has access to # a NOCACHE SRAM4 section. All other DMAs also # has access to this section. -CONFIG_DMA_LOOP_TRANSFER_SRAM_SECTION="SRAM4.dma" +CONFIG_CODE_DATA_RELOCATION=y +CONFIG_DMA_LOOP_TRANSFER_RELOCATE_SECTION="SRAM4" # Required for SRAM4 to be non-cachable CONFIG_NOCACHE_MEMORY=y diff --git a/tests/drivers/dma/loop_transfer/src/test_dma_loop.c b/tests/drivers/dma/loop_transfer/src/test_dma_loop.c index e282a508777..da964eb24b1 100644 --- a/tests/drivers/dma/loop_transfer/src/test_dma_loop.c +++ b/tests/drivers/dma/loop_transfer/src/test_dma_loop.c @@ -33,16 +33,8 @@ #define TRANSFER_LOOPS (4) -#if CONFIG_NOCACHE_MEMORY -static __aligned(32) uint8_t tx_data[CONFIG_DMA_LOOP_TRANSFER_SIZE] __used - __attribute__((__section__(CONFIG_DMA_LOOP_TRANSFER_SRAM_SECTION))); -static __aligned(32) uint8_t rx_data[TRANSFER_LOOPS][CONFIG_DMA_LOOP_TRANSFER_SIZE] __used - __attribute__((__section__(CONFIG_DMA_LOOP_TRANSFER_SRAM_SECTION".dma"))); -#else -/* this src memory shall be in RAM to support usingas a DMA source pointer.*/ -static uint8_t tx_data[CONFIG_DMA_LOOP_TRANSFER_SIZE]; -static __aligned(16) uint8_t rx_data[TRANSFER_LOOPS][CONFIG_DMA_LOOP_TRANSFER_SIZE] = { { 0 } }; -#endif +static __aligned(32) uint8_t tx_data[CONFIG_DMA_LOOP_TRANSFER_SIZE]; +static __aligned(32) uint8_t rx_data[TRANSFER_LOOPS][CONFIG_DMA_LOOP_TRANSFER_SIZE] = { { 0 } }; volatile uint32_t transfer_count; volatile uint32_t done; From b7949766e661faed50a69a7b8cc952e7a2471284 Mon Sep 17 00:00:00 2001 From: Adam Wojasinski Date: Fri, 17 Nov 2023 12:29:42 +0100 Subject: [PATCH 1214/3723] drivers: timer: nrf_rtc_timer: Change HAL to HALY in RTC timer driver NRFX has introduced HALY software layer which is a superset of HAL and aggregates some hardware registers manipulations in a single function calls. Quote from nrfx changelog: "HALY is an extension of the HAL layer that aggregates basic hardware use cases within single functions. Now it is used instead of HAL in the corresponding drivers." This commit zephyr's driver to be aligned with the approach used in nrfx, where drivers has been switched to use HALY instead of HAL. Signed-off-by: Adam Wojasinski --- drivers/timer/nrf_rtc_timer.c | 49 ++++++++++++++++------------------- 1 file changed, 23 insertions(+), 26 deletions(-) diff --git a/drivers/timer/nrf_rtc_timer.c b/drivers/timer/nrf_rtc_timer.c index 9241c5b7a10..e0584a3c8b3 100644 --- a/drivers/timer/nrf_rtc_timer.c +++ b/drivers/timer/nrf_rtc_timer.c @@ -14,7 +14,7 @@ #include #include #include -#include +#include #include #define RTC_PRETICK (IS_ENABLED(CONFIG_SOC_NRF53_RTC_PRETICK) && \ @@ -72,32 +72,32 @@ static uint32_t counter_sub(uint32_t a, uint32_t b) static void set_comparator(int32_t chan, uint32_t cyc) { - nrf_rtc_cc_set(RTC, chan, cyc & COUNTER_MAX); + nrfy_rtc_cc_set(RTC, chan, cyc & COUNTER_MAX); } static bool event_check(int32_t chan) { - return nrf_rtc_event_check(RTC, NRF_RTC_CHANNEL_EVENT_ADDR(chan)); + return nrfy_rtc_event_check(RTC, NRF_RTC_CHANNEL_EVENT_ADDR(chan)); } static void event_clear(int32_t chan) { - nrf_rtc_event_clear(RTC, NRF_RTC_CHANNEL_EVENT_ADDR(chan)); + nrfy_rtc_event_clear(RTC, NRF_RTC_CHANNEL_EVENT_ADDR(chan)); } static void event_enable(int32_t chan) { - nrf_rtc_event_enable(RTC, NRF_RTC_CHANNEL_INT_MASK(chan)); + nrfy_rtc_event_enable(RTC, NRF_RTC_CHANNEL_INT_MASK(chan)); } static void event_disable(int32_t chan) { - nrf_rtc_event_disable(RTC, NRF_RTC_CHANNEL_INT_MASK(chan)); + nrfy_rtc_event_disable(RTC, NRF_RTC_CHANNEL_INT_MASK(chan)); } static uint32_t counter(void) { - return nrf_rtc_counter_get(RTC); + return nrfy_rtc_counter_get(RTC); } static uint32_t absolute_time_to_cc(uint64_t absolute_time) @@ -132,7 +132,7 @@ static void full_int_unlock(uint32_t mcu_critical_state) uint32_t z_nrf_rtc_timer_compare_evt_address_get(int32_t chan) { __ASSERT_NO_MSG(chan >= 0 && chan < CHAN_COUNT); - return nrf_rtc_event_address_get(RTC, nrf_rtc_compare_event_get(chan)); + return nrfy_rtc_event_address_get(RTC, nrfy_rtc_compare_event_get(chan)); } uint32_t z_nrf_rtc_timer_capture_task_address_get(int32_t chan) @@ -143,9 +143,7 @@ uint32_t z_nrf_rtc_timer_capture_task_address_get(int32_t chan) return 0; } - nrf_rtc_task_t task = offsetof(NRF_RTC_Type, TASKS_CAPTURE[chan]); - - return nrf_rtc_task_address_get(RTC, task); + return nrfy_rtc_task_address_get(RTC, nrfy_rtc_capture_task_get(chan)); #else ARG_UNUSED(chan); return 0; @@ -156,7 +154,7 @@ static bool compare_int_lock(int32_t chan) { atomic_val_t prev = atomic_and(&int_mask, ~BIT(chan)); - nrf_rtc_int_disable(RTC, NRF_RTC_CHANNEL_INT_MASK(chan)); + nrfy_rtc_int_disable(RTC, NRF_RTC_CHANNEL_INT_MASK(chan)); barrier_dmem_fence_full(); barrier_isync_fence_full(); @@ -176,7 +174,7 @@ static void compare_int_unlock(int32_t chan, bool key) { if (key) { atomic_or(&int_mask, BIT(chan)); - nrf_rtc_int_enable(RTC, NRF_RTC_CHANNEL_INT_MASK(chan)); + nrfy_rtc_int_enable(RTC, NRF_RTC_CHANNEL_INT_MASK(chan)); if (atomic_get(&force_isr_mask) & BIT(chan)) { NVIC_SetPendingIRQ(RTC_IRQn); } @@ -194,7 +192,7 @@ uint32_t z_nrf_rtc_timer_compare_read(int32_t chan) { __ASSERT_NO_MSG(chan >= 0 && chan < CHAN_COUNT); - return nrf_rtc_cc_get(RTC, chan); + return nrfy_rtc_cc_get(RTC, chan); } uint64_t z_nrf_rtc_timer_get_ticks(k_timeout_t t) @@ -494,7 +492,7 @@ static void sys_clock_timeout_handler(int32_t chan, static bool channel_processing_check_and_clear(int32_t chan) { - if (nrf_rtc_int_enable_check(RTC, NRF_RTC_CHANNEL_INT_MASK(chan))) { + if (nrfy_rtc_int_enable_check(RTC, NRF_RTC_CHANNEL_INT_MASK(chan))) { /* The processing of channel can be caused by CC match * or be forced. */ @@ -568,9 +566,8 @@ void rtc_nrf_isr(const void *arg) rtc_pretick_rtc1_isr_hook(); } - if (nrf_rtc_int_enable_check(RTC, NRF_RTC_INT_OVERFLOW_MASK) && - nrf_rtc_event_check(RTC, NRF_RTC_EVENT_OVERFLOW)) { - nrf_rtc_event_clear(RTC, NRF_RTC_EVENT_OVERFLOW); + if (nrfy_rtc_int_enable_check(RTC, NRF_RTC_INT_OVERFLOW_MASK) && + nrfy_rtc_events_process(RTC, NRF_RTC_INT_OVERFLOW_MASK)) { overflow_cnt++; } @@ -623,7 +620,7 @@ int z_nrf_rtc_timer_trigger_overflow(void) goto bail; } - nrf_rtc_task_trigger(RTC, NRF_RTC_TASK_TRIGGER_OVERFLOW); + nrfy_rtc_task_trigger(RTC, NRF_RTC_TASK_TRIGGER_OVERFLOW); k_busy_wait(80); uint64_t now = z_nrf_rtc_timer_read(); @@ -713,10 +710,10 @@ static void int_event_disable_rtc(void) NRF_RTC_INT_COMPARE3_MASK; /* Reset interrupt enabling to expected reset values */ - nrf_rtc_int_disable(RTC, mask); + nrfy_rtc_int_disable(RTC, mask); /* Reset event routing enabling to expected reset values */ - nrf_rtc_event_disable(RTC, mask); + nrfy_rtc_event_disable(RTC, mask); } void sys_clock_disable(void) @@ -739,13 +736,13 @@ static int sys_clock_driver_init(void) int_event_disable_rtc(); /* TODO: replace with counter driver to access RTC */ - nrf_rtc_prescaler_set(RTC, 0); + nrfy_rtc_prescaler_set(RTC, 0); for (int32_t chan = 0; chan < CHAN_COUNT; chan++) { cc_data[chan].target_time = TARGET_TIME_INVALID; - nrf_rtc_int_enable(RTC, NRF_RTC_CHANNEL_INT_MASK(chan)); + nrfy_rtc_int_enable(RTC, NRF_RTC_CHANNEL_INT_MASK(chan)); } - nrf_rtc_int_enable(RTC, NRF_RTC_INT_OVERFLOW_MASK); + nrfy_rtc_int_enable(RTC, NRF_RTC_INT_OVERFLOW_MASK); NVIC_ClearPendingIRQ(RTC_IRQn); @@ -753,8 +750,8 @@ static int sys_clock_driver_init(void) rtc_nrf_isr, 0, 0); irq_enable(RTC_IRQn); - nrf_rtc_task_trigger(RTC, NRF_RTC_TASK_CLEAR); - nrf_rtc_task_trigger(RTC, NRF_RTC_TASK_START); + nrfy_rtc_task_trigger(RTC, NRF_RTC_TASK_CLEAR); + nrfy_rtc_task_trigger(RTC, NRF_RTC_TASK_START); int_mask = BIT_MASK(CHAN_COUNT); if (CONFIG_NRF_RTC_TIMER_USER_CHAN_COUNT) { From 861ccddb9265ca7261e0dafd7bda8addfe8825bf Mon Sep 17 00:00:00 2001 From: Adam Wojasinski Date: Fri, 17 Nov 2023 12:35:40 +0100 Subject: [PATCH 1215/3723] drivers: counter: counter_nrfx_rtc: Change HAL to HALY in RTC counter NRFX has introduced HALY software layer which is a superset of HAL and aggregates some hardware registers manipulations in a single function calls. Quote from nrfx changelog: "HALY is an extension of the HAL layer that aggregates basic hardware use cases within single functions. Now it is used instead of HAL in the corresponding drivers." This commit zephyr's driver to be aligned with the approach used in nrfx, where drivers has been switched to use HALY instead of HAL. Signed-off-by: Adam Wojasinski --- drivers/counter/counter_nrfx_rtc.c | 94 +++++++++++++++--------------- 1 file changed, 47 insertions(+), 47 deletions(-) diff --git a/drivers/counter/counter_nrfx_rtc.c b/drivers/counter/counter_nrfx_rtc.c index af35564a158..398921f2bd6 100644 --- a/drivers/counter/counter_nrfx_rtc.c +++ b/drivers/counter/counter_nrfx_rtc.c @@ -9,6 +9,7 @@ #include #include #endif +#include #include #ifdef DPPI_PRESENT #include @@ -77,7 +78,7 @@ static int start(const struct device *dev) { const struct counter_nrfx_config *config = dev->config; - nrf_rtc_task_trigger(config->rtc, NRF_RTC_TASK_START); + nrfy_rtc_task_trigger(config->rtc, NRF_RTC_TASK_START); return 0; } @@ -86,7 +87,7 @@ static int stop(const struct device *dev) { const struct counter_nrfx_config *config = dev->config; - nrf_rtc_task_trigger(config->rtc, NRF_RTC_TASK_STOP); + nrfy_rtc_task_trigger(config->rtc, NRF_RTC_TASK_STOP); return 0; } @@ -95,7 +96,7 @@ static uint32_t read(const struct device *dev) { const struct counter_nrfx_config *config = dev->config; - return nrf_rtc_counter_get(config->rtc); + return nrfy_rtc_counter_get(config->rtc); } static int get_value(const struct device *dev, uint32_t *ticks) @@ -157,7 +158,7 @@ static void set_cc_int_pending(const struct device *dev, uint8_t chan) struct counter_nrfx_data *data = dev->data; atomic_or(&data->ipend_adj, BIT(chan)); - NRFX_IRQ_PENDING_SET(NRFX_IRQ_NUMBER_GET(config->rtc)); + NRFY_IRQ_PENDING_SET(NRFX_IRQ_NUMBER_GET(config->rtc)); } /** @brief Handle case when CC value equals COUNTER+1. @@ -180,12 +181,12 @@ static void handle_next_tick_case(const struct device *dev, uint8_t chan, struct counter_nrfx_data *data = dev->data; val = ticks_add(dev, val, 1, data->top); - nrf_rtc_cc_set(config->rtc, chan, val); + nrfy_rtc_cc_set(config->rtc, chan, val); atomic_or(&data->ipend_adj, CC_ADJ_MASK(chan)); - if (nrf_rtc_counter_get(config->rtc) != now) { + if (nrfy_rtc_counter_get(config->rtc) != now) { set_cc_int_pending(dev, chan); } else { - nrf_rtc_int_enable(config->rtc, NRF_RTC_CHANNEL_INT_MASK(chan)); + nrfy_rtc_int_enable(config->rtc, NRF_RTC_CHANNEL_INT_MASK(chan)); } } @@ -240,8 +241,8 @@ static int set_cc(const struct device *dev, uint8_t chan, uint32_t val, "Expected that CC interrupt is disabled."); evt = NRF_RTC_CHANNEL_EVENT_ADDR(chan); - top = data->top; - now = nrf_rtc_counter_get(rtc); + top = data->top; + now = nrfy_rtc_counter_get(rtc); /* First take care of a risk of an event coming from CC being set to * next tick. Reconfigure CC to future (now tick is the furthest @@ -249,17 +250,17 @@ static int set_cc(const struct device *dev, uint8_t chan, uint32_t val, * (half of 32k tick) and clean potential event. After that time there * is no risk of unwanted event. */ - prev_val = nrf_rtc_cc_get(rtc, chan); - nrf_rtc_event_clear(rtc, evt); - nrf_rtc_cc_set(rtc, chan, now); - nrf_rtc_event_enable(rtc, int_mask); + prev_val = nrfy_rtc_cc_get(rtc, chan); + nrfy_rtc_event_clear(rtc, evt); + nrfy_rtc_cc_set(rtc, chan, now); + nrfy_rtc_event_enable(rtc, int_mask); if (ticks_sub(dev, prev_val, now, top) == 1) { NRFX_DELAY_US(15); - nrf_rtc_event_clear(rtc, evt); + nrfy_rtc_event_clear(rtc, evt); } - now = nrf_rtc_counter_get(rtc); + now = nrfy_rtc_counter_get(rtc); if (absolute) { val = skip_zero_on_custom_top(val, top); @@ -289,8 +290,8 @@ static int set_cc(const struct device *dev, uint8_t chan, uint32_t val, */ handle_next_tick_case(dev, chan, now, val); } else { - nrf_rtc_cc_set(rtc, chan, val); - now = nrf_rtc_counter_get(rtc); + nrfy_rtc_cc_set(rtc, chan, val); + now = nrfy_rtc_counter_get(rtc); /* decrement value to detect also case when val == read(dev). * Otherwise, condition would need to include comparing diff @@ -318,7 +319,7 @@ static int set_cc(const struct device *dev, uint8_t chan, uint32_t val, */ handle_next_tick_case(dev, chan, now, val); } else { - nrf_rtc_int_enable(rtc, int_mask); + nrfy_rtc_int_enable(rtc, int_mask); } } @@ -353,9 +354,8 @@ static void disable(const struct device *dev, uint8_t chan) NRF_RTC_Type *rtc = config->rtc; nrf_rtc_event_t evt = NRF_RTC_CHANNEL_EVENT_ADDR(chan); - nrf_rtc_int_disable(rtc, NRF_RTC_CHANNEL_INT_MASK(chan)); - nrf_rtc_event_disable(rtc, NRF_RTC_CHANNEL_INT_MASK(chan)); - nrf_rtc_event_clear(rtc, evt); + nrfy_rtc_event_int_disable(rtc, NRF_RTC_CHANNEL_INT_MASK(chan)); + nrfy_rtc_event_clear(rtc, evt); config->ch_data[chan].callback = NULL; } @@ -379,7 +379,7 @@ static int ppi_setup(const struct device *dev, uint8_t chan) return 0; } - nrf_rtc_event_enable(rtc, NRF_RTC_CHANNEL_INT_MASK(chan)); + nrfy_rtc_event_enable(rtc, NRF_RTC_CHANNEL_INT_MASK(chan)); #ifdef DPPI_PRESENT result = nrfx_dppi_channel_alloc(&data->ppi_ch); if (result != NRFX_SUCCESS) { @@ -387,15 +387,15 @@ static int ppi_setup(const struct device *dev, uint8_t chan) return -ENODEV; } - nrf_rtc_subscribe_set(rtc, NRF_RTC_TASK_CLEAR, data->ppi_ch); - nrf_rtc_publish_set(rtc, evt, data->ppi_ch); + nrfy_rtc_subscribe_set(rtc, NRF_RTC_TASK_CLEAR, data->ppi_ch); + nrfy_rtc_publish_set(rtc, evt, data->ppi_ch); (void)nrfx_dppi_channel_enable(data->ppi_ch); #else /* DPPI_PRESENT */ uint32_t evt_addr; uint32_t task_addr; - evt_addr = nrf_rtc_event_address_get(rtc, evt); - task_addr = nrf_rtc_task_address_get(rtc, NRF_RTC_TASK_CLEAR); + evt_addr = nrfy_rtc_event_address_get(rtc, evt); + task_addr = nrfy_rtc_task_address_get(rtc, NRF_RTC_TASK_CLEAR); result = nrfx_ppi_channel_alloc(&data->ppi_ch); if (result != NRFX_SUCCESS) { @@ -420,13 +420,13 @@ static void ppi_free(const struct device *dev, uint8_t chan) if (!nrfx_config->use_ppi) { return; } - nrf_rtc_event_disable(rtc, NRF_RTC_CHANNEL_INT_MASK(chan)); + nrfy_rtc_event_disable(rtc, NRF_RTC_CHANNEL_INT_MASK(chan)); #ifdef DPPI_PRESENT nrf_rtc_event_t evt = NRF_RTC_CHANNEL_EVENT_ADDR(chan); (void)nrfx_dppi_channel_disable(ppi_ch); - nrf_rtc_subscribe_clear(rtc, NRF_RTC_TASK_CLEAR); - nrf_rtc_publish_clear(rtc, evt); + nrfy_rtc_subscribe_clear(rtc, NRF_RTC_TASK_CLEAR); + nrfy_rtc_publish_clear(rtc, evt); (void)nrfx_dppi_channel_free(ppi_ch); #else /* DPPI_PRESENT */ (void)nrfx_ppi_channel_disable(ppi_ch); @@ -457,16 +457,16 @@ static int set_fixed_top_value(const struct device *dev, return -EINVAL; } - nrf_rtc_int_disable(rtc, NRF_RTC_INT_OVERFLOW_MASK); + nrfy_rtc_int_disable(rtc, NRF_RTC_INT_OVERFLOW_MASK); data->top_cb = cfg->callback; data->top_user_data = cfg->user_data; if (!(cfg->flags & COUNTER_TOP_CFG_DONT_RESET)) { - nrf_rtc_task_trigger(rtc, NRF_RTC_TASK_CLEAR); + nrfy_rtc_task_trigger(rtc, NRF_RTC_TASK_CLEAR); } if (cfg->callback) { - nrf_rtc_int_enable(rtc, NRF_RTC_INT_OVERFLOW_MASK); + nrfy_rtc_int_enable(rtc, NRF_RTC_INT_OVERFLOW_MASK); } return 0; @@ -494,7 +494,7 @@ static int set_top_value(const struct device *dev, } } - nrf_rtc_int_disable(rtc, NRF_RTC_CHANNEL_INT_MASK(top_ch)); + nrfy_rtc_int_disable(rtc, NRF_RTC_CHANNEL_INT_MASK(top_ch)); if (IS_PPI_WRAP(dev)) { if ((dev_data->top == NRF_RTC_COUNTER_MAX) && @@ -509,19 +509,19 @@ static int set_top_value(const struct device *dev, dev_data->top_cb = cfg->callback; dev_data->top_user_data = cfg->user_data; dev_data->top = cfg->ticks; - nrf_rtc_cc_set(rtc, top_ch, cfg->ticks); + nrfy_rtc_cc_set(rtc, top_ch, cfg->ticks); if (!(cfg->flags & COUNTER_TOP_CFG_DONT_RESET)) { - nrf_rtc_task_trigger(rtc, NRF_RTC_TASK_CLEAR); + nrfy_rtc_task_trigger(rtc, NRF_RTC_TASK_CLEAR); } else if (read(dev) >= cfg->ticks) { err = -ETIME; if (cfg->flags & COUNTER_TOP_CFG_RESET_WHEN_LATE) { - nrf_rtc_task_trigger(rtc, NRF_RTC_TASK_CLEAR); + nrfy_rtc_task_trigger(rtc, NRF_RTC_TASK_CLEAR); } } if (cfg->callback || sw_wrap_required(dev)) { - nrf_rtc_int_enable(rtc, NRF_RTC_CHANNEL_INT_MASK(top_ch)); + nrfy_rtc_int_enable(rtc, NRF_RTC_CHANNEL_INT_MASK(top_ch)); } return err; @@ -546,9 +546,9 @@ static int init_rtc(const struct device *dev, uint32_t prescaler) z_nrf_clock_control_lf_on(CLOCK_CONTROL_NRF_LF_START_NOWAIT); #endif - nrf_rtc_prescaler_set(rtc, prescaler); + nrfy_rtc_prescaler_set(rtc, prescaler); - NRFX_IRQ_ENABLE(NRFX_IRQ_NUMBER_GET(rtc)); + NRFY_IRQ_ENABLE(NRFX_IRQ_NUMBER_GET(rtc)); data->top = NRF_RTC_COUNTER_MAX; err = set_top_value(dev, &top_cfg); @@ -593,14 +593,14 @@ static void top_irq_handle(const struct device *dev) NRF_RTC_EVENT_OVERFLOW : NRF_RTC_CHANNEL_EVENT_ADDR(counter_get_num_of_channels(dev)); - if (nrf_rtc_event_check(rtc, top_evt)) { - nrf_rtc_event_clear(rtc, top_evt); + uint32_t event_mask = nrfy_rtc_events_process(rtc, NRFY_EVENT_TO_INT_BITMASK(top_evt)); + if (event_mask & NRFY_EVENT_TO_INT_BITMASK(top_evt)) { /* Perform manual clear if custom top value is used and PPI * clearing is not used. */ if (!IS_FIXED_TOP(dev) && !IS_PPI_WRAP(dev)) { - nrf_rtc_task_trigger(rtc, NRF_RTC_TASK_CLEAR); + nrfy_rtc_task_trigger(rtc, NRF_RTC_TASK_CLEAR); } if (cb) { @@ -617,24 +617,24 @@ static void alarm_irq_handle(const struct device *dev, uint32_t chan) NRF_RTC_Type *rtc = config->rtc; nrf_rtc_event_t evt = NRF_RTC_CHANNEL_EVENT_ADDR(chan); uint32_t int_mask = NRF_RTC_CHANNEL_INT_MASK(chan); - bool hw_irq_pending = nrf_rtc_event_check(rtc, evt) && - nrf_rtc_int_enable_check(rtc, int_mask); + + bool hw_irq_pending = nrfy_rtc_events_process(rtc, NRFY_EVENT_TO_INT_BITMASK(evt)) & + nrfy_rtc_int_enable_check(rtc, NRFY_EVENT_TO_INT_BITMASK(evt)); bool sw_irq_pending = data->ipend_adj & BIT(chan); if (hw_irq_pending || sw_irq_pending) { struct counter_nrfx_ch_data *chdata; counter_alarm_callback_t cb; - nrf_rtc_event_clear(rtc, evt); atomic_and(&data->ipend_adj, ~BIT(chan)); - nrf_rtc_int_disable(rtc, int_mask); + nrfy_rtc_int_disable(rtc, int_mask); chdata = &config->ch_data[chan]; cb = chdata->callback; chdata->callback = NULL; if (cb) { - uint32_t cc = nrf_rtc_cc_get(rtc, chan); + uint32_t cc = nrfy_rtc_cc_get(rtc, chan); if (data->ipend_adj & CC_ADJ_MASK(chan)) { cc = ticks_sub(dev, cc, 1, data->top); From 4e14f732163c41fe858882e54adddf05cc250634 Mon Sep 17 00:00:00 2001 From: Mahesh Mahadevan Date: Mon, 2 Oct 2023 23:31:51 +0100 Subject: [PATCH 1216/3723] drivers: dma_lpc: Process complete_callback flag Add code to recognize the complete_callback flag and issue the callback accordingly. Signed-off-by: Mahesh Mahadevan --- drivers/dma/dma_mcux_lpc.c | 37 +++++++++++++++++++++++++++---------- 1 file changed, 27 insertions(+), 10 deletions(-) diff --git a/drivers/dma/dma_mcux_lpc.c b/drivers/dma/dma_mcux_lpc.c index 0a34efb9dca..0c1d50401c8 100644 --- a/drivers/dma/dma_mcux_lpc.c +++ b/drivers/dma/dma_mcux_lpc.c @@ -115,7 +115,8 @@ static void dma_mcux_lpc_irq_handler(const struct device *dev) static int dma_mcux_lpc_queue_descriptors(struct channel_data *data, struct dma_block_config *block, uint8_t src_inc, - uint8_t dest_inc) + uint8_t dest_inc, + bool callback_en) { uint32_t xfer_config = 0U; dma_descriptor_t *next_descriptor = NULL; @@ -191,7 +192,8 @@ static int dma_mcux_lpc_queue_descriptors(struct channel_data *data, if (local_block.block_size > max_xfer_bytes) { enable_interrupt = 0; } else { - enable_interrupt = 1; + /* Enable or disable interrupt based on user configuration */ + enable_interrupt = callback_en; } /* Reload if we have more descriptors */ @@ -241,8 +243,10 @@ static int dma_mcux_lpc_queue_descriptors(struct channel_data *data, /* Leave curr pointer unchanged so we start queuing new data from * this descriptor */ - /* Enable interrupt and reload for the descriptor */ - xfer_config = DMA_CHANNEL_XFER(1UL, 0UL, 1U, 0U, + /* Enable or disable interrupt based on user request. + * Reload for the descriptor. + */ + xfer_config = DMA_CHANNEL_XFER(1UL, 0UL, callback_en, 0U, width, src_inc, dest_inc, @@ -286,6 +290,7 @@ static int dma_mcux_lpc_configure(const struct device *dev, uint32_t channel, uint8_t width; uint32_t max_xfer_bytes; uint8_t reload = 0; + bool complete_callback; if (NULL == dev || NULL == config) { return -EINVAL; @@ -473,6 +478,8 @@ static int dma_mcux_lpc_configure(const struct device *dev, uint32_t channel, k_spin_unlock(&configuring_otrigs, otrigs_key); + complete_callback = config->complete_callback_en; + /* Check if we need to queue DMA descriptors */ if ((block_config->block_size > max_xfer_bytes) || (block_config->next_block != NULL)) { @@ -489,9 +496,8 @@ static int dma_mcux_lpc_configure(const struct device *dev, uint32_t channel, dst_inc, max_xfer_bytes); } else { - /* Enable interrupt and reload for the descriptor - */ - xfer_config = DMA_CHANNEL_XFER(1UL, 0UL, 1UL, 0UL, + /* Enable interrupt if user requested and reload for the descriptor */ + xfer_config = DMA_CHANNEL_XFER(1UL, 0UL, complete_callback, 0UL, width, src_inc, dst_inc, @@ -539,7 +545,13 @@ static int dma_mcux_lpc_configure(const struct device *dev, uint32_t channel, local_block.next_block = block_config->next_block; local_block.source_reload_en = reload; - if (dma_mcux_lpc_queue_descriptors(data, &local_block, src_inc, dst_inc)) { + if (block_config->next_block == NULL) { + /* This is the last block, enable callback. */ + complete_callback = true; + } + + if (dma_mcux_lpc_queue_descriptors(data, &local_block, + src_inc, dst_inc, complete_callback)) { return -ENOMEM; } } @@ -555,7 +567,12 @@ static int dma_mcux_lpc_configure(const struct device *dev, uint32_t channel, assert(block_config->dest_address == ROUND_UP(block_config->dest_address, width)); - if (dma_mcux_lpc_queue_descriptors(data, block_config, src_inc, dst_inc)) { + if (block_config->next_block == NULL) { + /* This is the last block. Enable callback if not enabled. */ + complete_callback = true; + } + if (dma_mcux_lpc_queue_descriptors(data, block_config, + src_inc, dst_inc, complete_callback)) { return -ENOMEM; } @@ -686,7 +703,7 @@ static int dma_mcux_lpc_reload(const struct device *dev, uint32_t channel, local_block.dest_address = dst; local_block.block_size = size; local_block.source_reload_en = 1; - dma_mcux_lpc_queue_descriptors(data, &local_block, src_inc, dst_inc); + dma_mcux_lpc_queue_descriptors(data, &local_block, src_inc, dst_inc, true); } return 0; From 0dbbc3cc77a9127af0d29134edb192e24258c7a8 Mon Sep 17 00:00:00 2001 From: Mahesh Mahadevan Date: Mon, 2 Oct 2023 23:41:37 +0100 Subject: [PATCH 1217/3723] drivers: spi: Set the complete_callback flag The MCUX LPC driver now recognizes the complete_callback flag. We need to set this flag so we receive a callback after every block. Signed-off-by: Mahesh Mahadevan --- drivers/spi/spi_mcux_flexcomm.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/drivers/spi/spi_mcux_flexcomm.c b/drivers/spi/spi_mcux_flexcomm.c index 32b5638d49d..cb20fcea6e3 100644 --- a/drivers/spi/spi_mcux_flexcomm.c +++ b/drivers/spi/spi_mcux_flexcomm.c @@ -830,10 +830,11 @@ static void spi_mcux_config_func_##id(const struct device *dev) \ .dma_dev = DEVICE_DT_GET(DT_INST_DMAS_CTLR_BY_NAME(id, tx)), \ .channel = \ DT_INST_DMAS_CELL_BY_NAME(id, tx, channel), \ - .dma_cfg = { \ + .dma_cfg = { \ .channel_direction = MEMORY_TO_PERIPHERAL, \ .dma_callback = spi_mcux_dma_callback, \ - .block_count = 2, \ + .complete_callback_en = true, \ + .block_count = 2, \ } \ }, \ .dma_rx = { \ From 7d12d654db8e7b1b37594246a35e1020f1b2dac6 Mon Sep 17 00:00:00 2001 From: Mahesh Mahadevan Date: Mon, 2 Oct 2023 23:45:43 +0100 Subject: [PATCH 1218/3723] drivers: i2s: Set DMA complete_callback flag The MCUX LPC DMA driver now recognizes the compelete_callback flag. Set this flag so we receive an interrupt after completion of every block. Signed-off-by: Mahesh Mahadevan --- drivers/i2s/i2s_mcux_flexcomm.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/i2s/i2s_mcux_flexcomm.c b/drivers/i2s/i2s_mcux_flexcomm.c index 4155bd24b62..24fb0873a82 100644 --- a/drivers/i2s/i2s_mcux_flexcomm.c +++ b/drivers/i2s/i2s_mcux_flexcomm.c @@ -930,6 +930,7 @@ static int i2s_mcux_init(const struct device *dev) .dma_cfg = { \ .channel_direction = PERIPHERAL_TO_MEMORY, \ .dma_callback = i2s_mcux_dma_rx_callback, \ + .complete_callback_en = true, \ .block_count = NUM_RX_DMA_BLOCKS, \ } \ } From 3535732580561269a4151e68ef3ef60d88622248 Mon Sep 17 00:00:00 2001 From: Mahesh Mahadevan Date: Thu, 7 Dec 2023 14:18:34 +0000 Subject: [PATCH 1219/3723] drivers: dma: Return DMA_STATUS_BLOCK or DMA_STATUS_COMPLETE Use intA and intB fields of the DMA descriptor to decide when the interrupt is per block versus when the transfer is complete. This allows us to return the correct flag to the user. Signed-off-by: Mahesh Mahadevan --- drivers/dma/dma_mcux_lpc.c | 38 ++++++++++++++++++++++++++++---------- 1 file changed, 28 insertions(+), 10 deletions(-) diff --git a/drivers/dma/dma_mcux_lpc.c b/drivers/dma/dma_mcux_lpc.c index 0c1d50401c8..ce0632a4045 100644 --- a/drivers/dma/dma_mcux_lpc.c +++ b/drivers/dma/dma_mcux_lpc.c @@ -83,12 +83,12 @@ static void nxp_lpc_dma_callback(dma_handle_t *handle, void *param, struct channel_data *data = (struct channel_data *)param; uint32_t channel = handle->channel; - if (transferDone) { - ret = DMA_STATUS_COMPLETE; - } - if (intmode == kDMA_IntError) { DMA_AbortTransfer(handle); + } else if (intmode == kDMA_IntA) { + ret = DMA_STATUS_BLOCK; + } else { + ret = DMA_STATUS_COMPLETE; } data->busy = DMA_ChannelIsBusy(data->dma_handle.base, channel); @@ -123,9 +123,13 @@ static int dma_mcux_lpc_queue_descriptors(struct channel_data *data, uint32_t width = data->width; uint32_t max_xfer_bytes = NXP_LPC_DMA_MAX_XFER * width; bool setup_extra_descriptor = false; - uint8_t enable_interrupt; + /* intA is used to indicate transfer of a block */ + uint8_t enable_a_interrupt; + /* intB is used to indicate complete transfer of the list of blocks */ + uint8_t enable_b_interrupt; uint8_t reload; struct dma_block_config local_block; + bool last_block = false; memcpy(&local_block, block, sizeof(struct dma_block_config)); @@ -149,6 +153,7 @@ static int dma_mcux_lpc_queue_descriptors(struct channel_data *data, } else { /* Check if this is the last block to transfer */ if (local_block.next_block == NULL) { + last_block = true; /* Last descriptor, check if we should setup a * circular chain */ @@ -190,10 +195,20 @@ static int dma_mcux_lpc_queue_descriptors(struct channel_data *data, /* Fire an interrupt after the whole block has been transferred */ if (local_block.block_size > max_xfer_bytes) { - enable_interrupt = 0; + enable_a_interrupt = 0; + enable_b_interrupt = 0; } else { - /* Enable or disable interrupt based on user configuration */ - enable_interrupt = callback_en; + /* Use intB when this is the end of the block list and transfer */ + if (last_block) { + enable_a_interrupt = 0; + enable_b_interrupt = 1; + } else { + /* Use intA when we need an interrupt per block + * Enable or disable intA based on user configuration + */ + enable_a_interrupt = callback_en; + enable_b_interrupt = 0; + } } /* Reload if we have more descriptors */ @@ -204,7 +219,8 @@ static int dma_mcux_lpc_queue_descriptors(struct channel_data *data, } /* Enable interrupt and reload for the descriptor */ - xfer_config = DMA_CHANNEL_XFER(reload, 0UL, enable_interrupt, 0U, + xfer_config = DMA_CHANNEL_XFER(reload, 0UL, enable_a_interrupt, + enable_b_interrupt, width, src_inc, dest_inc, @@ -496,7 +512,9 @@ static int dma_mcux_lpc_configure(const struct device *dev, uint32_t channel, dst_inc, max_xfer_bytes); } else { - /* Enable interrupt if user requested and reload for the descriptor */ + /* Enable INTA interrupt if user requested DMA for each block. + * Reload for the descriptor. + */ xfer_config = DMA_CHANNEL_XFER(1UL, 0UL, complete_callback, 0UL, width, src_inc, From 858007dc93c78e81af228323fb96618d7aac5cd1 Mon Sep 17 00:00:00 2001 From: Armando Visconti Date: Wed, 13 Dec 2023 10:07:34 +0100 Subject: [PATCH 1220/3723] drivers/sensor: add Kconfig.trigger_template Add Kconfig.trigger_template to allow an extensive re-use of trigger configuration inside all sensor drivers. This template must be included as in the following example: module = LSM6DSO thread_priority = 10 thread_stack_size = 1024 source "drivers/sensor/Kconfig.trigger_template" Signed-off-by: Armando Visconti --- drivers/sensor/Kconfig.trigger_template | 44 +++++++++++++++++++++++++ 1 file changed, 44 insertions(+) create mode 100644 drivers/sensor/Kconfig.trigger_template diff --git a/drivers/sensor/Kconfig.trigger_template b/drivers/sensor/Kconfig.trigger_template new file mode 100644 index 00000000000..7cb98e10e9e --- /dev/null +++ b/drivers/sensor/Kconfig.trigger_template @@ -0,0 +1,44 @@ +# Common Kconfig template for all sensors +# Copyright (c) 2023 STMicroelectronics +# SPDX-License-Identifier: Apache-2.0 + +choice "$(module)_TRIGGER_MODE" + prompt "Trigger mode" + help + Specify the type of triggering to be used by the sensor module. + +config $(module)_TRIGGER_NONE + bool "No trigger" + +config $(module)_TRIGGER_GLOBAL_THREAD + bool "Use global thread" + depends on GPIO + select $(module)_TRIGGER + +config $(module)_TRIGGER_OWN_THREAD + bool "Use own thread" + depends on GPIO + select $(module)_TRIGGER + +endchoice + +config $(module)_TRIGGER + bool + +if $(module)_TRIGGER + +config $(module)_THREAD_PRIORITY + int "Thread priority" + depends on $(module)_TRIGGER_OWN_THREAD + default $(thread_priority) + help + Priority of thread used by the driver to handle interrupts. + +config $(module)_THREAD_STACK_SIZE + int "Thread stack size" + depends on $(module)_TRIGGER_OWN_THREAD + default $(thread_stack_size) + help + Stack size of thread used by the driver to handle interrupts. + +endif # $(module)_TRIGGER From 1badec4bfda81707ed406bef82fedfa0250a59f0 Mon Sep 17 00:00:00 2001 From: Armando Visconti Date: Wed, 15 Nov 2023 16:18:34 +0100 Subject: [PATCH 1221/3723] drivers/sensor: add support to LIS2DU12 accelerometer The LIS2DU12 is a linear 3-axis accelerometer with advanced digital functions whose MEMS and ASIC have been expressly designed to build an outstanding ultralow-power architecture in which the anti-aliasing filter operates with a current consumption among the lowest in the market. This driver is based on stmemsc HAL i/f v2.3 https://www.st.com/en/datasheet/lis2du12.pdf Signed-off-by: Armando Visconti --- drivers/sensor/CMakeLists.txt | 1 + drivers/sensor/Kconfig | 1 + drivers/sensor/lis2du12/CMakeLists.txt | 12 + drivers/sensor/lis2du12/Kconfig | 24 + drivers/sensor/lis2du12/lis2du12.c | 471 ++++++++++++++++++ drivers/sensor/lis2du12/lis2du12.h | 98 ++++ drivers/sensor/lis2du12/lis2du12_trigger.c | 215 ++++++++ dts/bindings/sensor/st,lis2du12-common.yaml | 97 ++++ dts/bindings/sensor/st,lis2du12-i2c.yaml | 10 + dts/bindings/sensor/st,lis2du12-spi.yaml | 10 + include/zephyr/dt-bindings/sensor/lis2du12.h | 31 ++ modules/Kconfig.st | 3 + tests/drivers/build_all/sensor/app.overlay | 3 +- tests/drivers/build_all/sensor/i2c.dtsi | 10 + .../sensor/sensors_trigger_global.conf | 1 + .../sensor/sensors_trigger_none.conf | 1 + .../build_all/sensor/sensors_trigger_own.conf | 1 + tests/drivers/build_all/sensor/spi.dtsi | 9 + 18 files changed, 997 insertions(+), 1 deletion(-) create mode 100644 drivers/sensor/lis2du12/CMakeLists.txt create mode 100644 drivers/sensor/lis2du12/Kconfig create mode 100644 drivers/sensor/lis2du12/lis2du12.c create mode 100644 drivers/sensor/lis2du12/lis2du12.h create mode 100644 drivers/sensor/lis2du12/lis2du12_trigger.c create mode 100644 dts/bindings/sensor/st,lis2du12-common.yaml create mode 100644 dts/bindings/sensor/st,lis2du12-i2c.yaml create mode 100644 dts/bindings/sensor/st,lis2du12-spi.yaml create mode 100644 include/zephyr/dt-bindings/sensor/lis2du12.h diff --git a/drivers/sensor/CMakeLists.txt b/drivers/sensor/CMakeLists.txt index afa200a06ab..b470865ee31 100644 --- a/drivers/sensor/CMakeLists.txt +++ b/drivers/sensor/CMakeLists.txt @@ -68,6 +68,7 @@ add_subdirectory_ifdef(CONFIG_ISM330DHCX ism330dhcx) add_subdirectory_ifdef(CONFIG_ITDS wsen_itds) add_subdirectory_ifdef(CONFIG_LIS2DH lis2dh) add_subdirectory_ifdef(CONFIG_LIS2DS12 lis2ds12) +add_subdirectory_ifdef(CONFIG_LIS2DU12 lis2du12) add_subdirectory_ifdef(CONFIG_LIS2DW12 lis2dw12) add_subdirectory_ifdef(CONFIG_LIS2MDL lis2mdl) add_subdirectory_ifdef(CONFIG_LIS3MDL lis3mdl) diff --git a/drivers/sensor/Kconfig b/drivers/sensor/Kconfig index 7e454740973..79bc70fada8 100644 --- a/drivers/sensor/Kconfig +++ b/drivers/sensor/Kconfig @@ -140,6 +140,7 @@ source "drivers/sensor/ite_tach_it8xxx2/Kconfig" source "drivers/sensor/ite_vcmp_it8xxx2/Kconfig" source "drivers/sensor/lis2dh/Kconfig" source "drivers/sensor/lis2ds12/Kconfig" +source "drivers/sensor/lis2du12/Kconfig" source "drivers/sensor/lis2dw12/Kconfig" source "drivers/sensor/lis2mdl/Kconfig" source "drivers/sensor/lis3mdl/Kconfig" diff --git a/drivers/sensor/lis2du12/CMakeLists.txt b/drivers/sensor/lis2du12/CMakeLists.txt new file mode 100644 index 00000000000..378cc8f7f0d --- /dev/null +++ b/drivers/sensor/lis2du12/CMakeLists.txt @@ -0,0 +1,12 @@ +# ST Microelectronics LIS2DU12 3-axis accelerometer sensor driver +# +# Copyright (c) 2023 STMicroelectronics +# +# SPDX-License-Identifier: Apache-2.0 +# +zephyr_library() + +zephyr_library_sources(lis2du12.c) +zephyr_library_sources_ifdef(CONFIG_LIS2DU12_TRIGGER lis2du12_trigger.c) + +zephyr_library_include_directories(../stmemsc) diff --git a/drivers/sensor/lis2du12/Kconfig b/drivers/sensor/lis2du12/Kconfig new file mode 100644 index 00000000000..24802d5fa6f --- /dev/null +++ b/drivers/sensor/lis2du12/Kconfig @@ -0,0 +1,24 @@ +# ST Microelectronics LIS2DU12 3-axis accelerometer sensor driver + +# Copyright (c) 2023 STMicroelectronics +# SPDX-License-Identifier: Apache-2.0 + +menuconfig LIS2DU12 + bool "LIS2DU12 I2C/SPI smartxl Chip" + default y + depends on DT_HAS_ST_LIS2DU12_ENABLED + select I2C if $(dt_compat_on_bus,$(DT_COMPAT_ST_LIS2DU12),i2c) + select SPI if $(dt_compat_on_bus,$(DT_COMPAT_ST_LIS2DU12),spi) + select HAS_STMEMSC + select USE_STDC_LIS2DU12 + help + Enable driver for LIS2DU12 smartxl sensor. + +if LIS2DU12 + +module = LIS2DU12 +thread_priority = 10 +thread_stack_size = 1024 +source "drivers/sensor/Kconfig.trigger_template" + +endif # LIS2DU12 diff --git a/drivers/sensor/lis2du12/lis2du12.c b/drivers/sensor/lis2du12/lis2du12.c new file mode 100644 index 00000000000..bd5d8b2faf0 --- /dev/null +++ b/drivers/sensor/lis2du12/lis2du12.c @@ -0,0 +1,471 @@ +/* ST Microelectronics LIS2DU12 3-axis accelerometer sensor driver + * + * Copyright (c) 2023 STMicroelectronics + * + * SPDX-License-Identifier: Apache-2.0 + * + * Datasheet: + * https://www.st.com/resource/en/datasheet/lis2du12.pdf + */ + +#define DT_DRV_COMPAT st_lis2du12 + +#include +#include +#include +#include +#include +#include +#include +#include + +#include "lis2du12.h" + +LOG_MODULE_REGISTER(LIS2DU12, CONFIG_SENSOR_LOG_LEVEL); + +static const float lis2du12_odr_map[14] = { + 0.0f, 1.6f, 3.0f, 6.0f, 6.0f, 12.5f, 25.0f, + 50.0f, 100.0f, 200.0f, 400.0f, 800.0f, 0.0f, 0.0f}; + +static int lis2du12_freq_to_odr_val(const struct device *dev, uint16_t freq) +{ + size_t i; + + for (i = 0; i < ARRAY_SIZE(lis2du12_odr_map); i++) { + if (freq <= lis2du12_odr_map[i]) { + return i; + } + } + + return -EINVAL; +} + +static const uint16_t lis2du12_accel_fs_map[] = {2, 4, 8, 16}; + +static int lis2du12_accel_range_to_fs_val(int32_t range) +{ + size_t i; + + for (i = 0; i < ARRAY_SIZE(lis2du12_accel_fs_map); i++) { + if (range == lis2du12_accel_fs_map[i]) { + return i; + } + } + + return -EINVAL; +} + +static inline int lis2du12_reboot(const struct device *dev) +{ + const struct lis2du12_config *cfg = dev->config; + stmdev_ctx_t *ctx = (stmdev_ctx_t *)&cfg->ctx; + lis2du12_status_t status; + uint8_t tries = 10; + + if (lis2du12_init_set(ctx, LIS2DU12_RESET) < 0) { + return -EIO; + } + + do { + if (!--tries) { + LOG_ERR("sw reset timed out"); + return -ETIMEDOUT; + } + k_usleep(50); + + if (lis2du12_status_get(ctx, &status) < 0) { + return -EIO; + } + } while (status.sw_reset != 0); + + if (lis2du12_init_set(ctx, LIS2DU12_DRV_RDY) < 0) { + return -EIO; + } + + return 0; +} + +static int lis2du12_accel_set_fs_raw(const struct device *dev, uint8_t fs) +{ + const struct lis2du12_config *cfg = dev->config; + stmdev_ctx_t *ctx = (stmdev_ctx_t *)&cfg->ctx; + struct lis2du12_data *data = dev->data; + lis2du12_md_t mode; + + if (lis2du12_mode_get(ctx, &mode) < 0) { + return -EIO; + } + + mode.fs = fs; + if (lis2du12_mode_set(ctx, &mode) < 0) { + return -EIO; + } + + data->accel_fs = fs; + + return 0; +} + +static int lis2du12_accel_set_odr_raw(const struct device *dev, uint8_t odr) +{ + const struct lis2du12_config *cfg = dev->config; + stmdev_ctx_t *ctx = (stmdev_ctx_t *)&cfg->ctx; + struct lis2du12_data *data = dev->data; + lis2du12_md_t mode; + + if (lis2du12_mode_get(ctx, &mode) < 0) { + return -EIO; + } + + mode.odr = odr; + if (lis2du12_mode_set(ctx, &mode) < 0) { + return -EIO; + } + + data->accel_freq = odr; + + return 0; +} + +static int lis2du12_accel_odr_set(const struct device *dev, uint16_t freq) +{ + int odr; + + odr = lis2du12_freq_to_odr_val(dev, freq); + if (odr < 0) { + return odr; + } + + if (lis2du12_accel_set_odr_raw(dev, odr) < 0) { + LOG_ERR("failed to set accelerometer sampling rate"); + return -EIO; + } + + return 0; +} + +static int lis2du12_accel_range_set(const struct device *dev, int32_t range) +{ + int fs; + struct lis2du12_data *data = dev->data; + + fs = lis2du12_accel_range_to_fs_val(range); + if (fs < 0) { + return fs; + } + + if (lis2du12_accel_set_fs_raw(dev, fs) < 0) { + LOG_ERR("failed to set accelerometer full-scale"); + return -EIO; + } + + data->acc_gain = lis2du12_accel_fs_map[fs] * GAIN_UNIT_XL / 2; + return 0; +} + +static int lis2du12_accel_config(const struct device *dev, + enum sensor_channel chan, + enum sensor_attribute attr, + const struct sensor_value *val) +{ + switch (attr) { + case SENSOR_ATTR_FULL_SCALE: + return lis2du12_accel_range_set(dev, sensor_ms2_to_g(val)); + case SENSOR_ATTR_SAMPLING_FREQUENCY: + return lis2du12_accel_odr_set(dev, val->val1); + default: + LOG_WRN("Accel attribute %d not supported.", attr); + return -ENOTSUP; + } + + return 0; +} + +static int lis2du12_attr_set(const struct device *dev, + enum sensor_channel chan, + enum sensor_attribute attr, + const struct sensor_value *val) +{ + switch (chan) { + case SENSOR_CHAN_ACCEL_XYZ: + return lis2du12_accel_config(dev, chan, attr, val); + default: + LOG_WRN("attribute %d not supported on this channel.", chan); + return -ENOTSUP; + } + + return 0; +} + +static int lis2du12_sample_fetch_accel(const struct device *dev) +{ + const struct lis2du12_config *cfg = dev->config; + stmdev_ctx_t *ctx = (stmdev_ctx_t *)&cfg->ctx; + struct lis2du12_data *data = dev->data; + lis2du12_data_t xl_data; + lis2du12_md_t md; + + md.fs = cfg->accel_range; + if (lis2du12_data_get(ctx, &md, &xl_data) < 0) { + LOG_ERR("Failed to read sample"); + return -EIO; + } + + data->acc[0] = xl_data.xl.raw[0]; + data->acc[1] = xl_data.xl.raw[1]; + data->acc[2] = xl_data.xl.raw[2]; + + return 0; +} + +static int lis2du12_sample_fetch(const struct device *dev, + enum sensor_channel chan) +{ + switch (chan) { + case SENSOR_CHAN_ACCEL_XYZ: + lis2du12_sample_fetch_accel(dev); + break; + case SENSOR_CHAN_ALL: + lis2du12_sample_fetch_accel(dev); + break; + default: + return -ENOTSUP; + } + + return 0; +} + +static inline void lis2du12_accel_convert(struct sensor_value *val, int raw_val, + uint32_t sensitivity) +{ + int64_t dval; + + /* Sensitivity is exposed in ug/LSB */ + /* Convert to m/s^2 */ + dval = (int64_t)(raw_val) * sensitivity * SENSOR_G_DOUBLE; + val->val1 = (int32_t)(dval / 1000000); + val->val2 = (int32_t)(dval % 1000000); + +} + +static inline int lis2du12_accel_get_channel(enum sensor_channel chan, + struct sensor_value *val, + struct lis2du12_data *data, + uint32_t sensitivity) +{ + uint8_t i; + + switch (chan) { + case SENSOR_CHAN_ACCEL_X: + lis2du12_accel_convert(val, data->acc[0], sensitivity); + break; + case SENSOR_CHAN_ACCEL_Y: + lis2du12_accel_convert(val, data->acc[1], sensitivity); + break; + case SENSOR_CHAN_ACCEL_Z: + lis2du12_accel_convert(val, data->acc[2], sensitivity); + break; + case SENSOR_CHAN_ACCEL_XYZ: + for (i = 0; i < 3; i++) { + lis2du12_accel_convert(val++, data->acc[i], sensitivity); + } + break; + default: + return -ENOTSUP; + } + + return 0; +} + +static int lis2du12_accel_channel_get(enum sensor_channel chan, + struct sensor_value *val, + struct lis2du12_data *data) +{ + return lis2du12_accel_get_channel(chan, val, data, data->acc_gain); +} + +static int lis2du12_channel_get(const struct device *dev, + enum sensor_channel chan, + struct sensor_value *val) +{ + struct lis2du12_data *data = dev->data; + + switch (chan) { + case SENSOR_CHAN_ACCEL_X: + case SENSOR_CHAN_ACCEL_Y: + case SENSOR_CHAN_ACCEL_Z: + case SENSOR_CHAN_ACCEL_XYZ: + lis2du12_accel_channel_get(chan, val, data); + break; + default: + return -ENOTSUP; + } + + return 0; +} + +static const struct sensor_driver_api lis2du12_driver_api = { + .attr_set = lis2du12_attr_set, +#if CONFIG_LIS2DU12_TRIGGER + .trigger_set = lis2du12_trigger_set, +#endif + .sample_fetch = lis2du12_sample_fetch, + .channel_get = lis2du12_channel_get, +}; + +static int lis2du12_init_chip(const struct device *dev) +{ + const struct lis2du12_config *cfg = dev->config; + stmdev_ctx_t *ctx = (stmdev_ctx_t *)&cfg->ctx; + struct lis2du12_data *lis2du12 = dev->data; + lis2du12_id_t chip_id; + uint8_t odr, fs; + + if (lis2du12_id_get(ctx, &chip_id) < 0) { + LOG_ERR("Failed reading chip id"); + return -EIO; + } + + LOG_INF("chip id 0x%x", chip_id.whoami); + + if (chip_id.whoami != LIS2DU12_ID) { + LOG_ERR("Invalid chip id 0x%x", chip_id.whoami); + return -EIO; + } + + /* reboot device */ + if (lis2du12_reboot(dev) < 0) { + return -EIO; + } + + /* set FS from DT */ + fs = cfg->accel_range; + LOG_DBG("accel range is %d", fs); + if (lis2du12_accel_set_fs_raw(dev, fs) < 0) { + LOG_ERR("failed to set accelerometer range %d", fs); + return -EIO; + } + lis2du12->acc_gain = lis2du12_accel_fs_map[fs] * GAIN_UNIT_XL / 2; + + /* set odr from DT (the only way to go in high performance) */ + odr = cfg->accel_odr; + LOG_DBG("accel odr is %d", odr); + if (lis2du12_accel_set_odr_raw(dev, odr) < 0) { + LOG_ERR("failed to set accelerometer odr %d", odr); + return -EIO; + } + + return 0; +} + +static int lis2du12_init(const struct device *dev) +{ +#ifdef CONFIG_LIS2DU12_TRIGGER + const struct lis2du12_config *cfg = dev->config; +#endif + struct lis2du12_data *data = dev->data; + + LOG_INF("Initialize device %s", dev->name); + data->dev = dev; + + if (lis2du12_init_chip(dev) < 0) { + LOG_ERR("failed to initialize chip"); + return -EIO; + } + +#ifdef CONFIG_LIS2DU12_TRIGGER + if (cfg->trig_enabled) { + if (lis2du12_init_interrupt(dev) < 0) { + LOG_ERR("Failed to initialize interrupt."); + return -EIO; + } + } +#endif + + return 0; +} + +/* + * Device creation macro, shared by LIS2DU12_DEFINE_SPI() and + * LIS2DU12_DEFINE_I2C(). + */ + +#define LIS2DU12_DEVICE_INIT(inst) \ + SENSOR_DEVICE_DT_INST_DEFINE(inst, \ + lis2du12_init, \ + NULL, \ + &lis2du12_data_##inst, \ + &lis2du12_config_##inst, \ + POST_KERNEL, \ + CONFIG_SENSOR_INIT_PRIORITY, \ + &lis2du12_driver_api); + +/* + * Instantiation macros used when a device is on a SPI bus. + */ + +#ifdef CONFIG_LIS2DU12_TRIGGER +#define LIS2DU12_CFG_IRQ(inst) \ + .trig_enabled = true, \ + .int1_gpio = GPIO_DT_SPEC_INST_GET_OR(inst, int1_gpios, { 0 }), \ + .int2_gpio = GPIO_DT_SPEC_INST_GET_OR(inst, int2_gpios, { 0 }), \ + .drdy_pulsed = DT_INST_PROP(inst, drdy_pulsed), \ + .drdy_pin = DT_INST_PROP(inst, drdy_pin) +#else +#define LIS2DU12_CFG_IRQ(inst) +#endif /* CONFIG_LIS2DU12_TRIGGER */ + +#define LIS2DU12_SPI_OP (SPI_WORD_SET(8) | \ + SPI_OP_MODE_MASTER | \ + SPI_MODE_CPOL | \ + SPI_MODE_CPHA) \ + +#define LIS2DU12_CONFIG_COMMON(inst) \ + .accel_odr = DT_INST_PROP(inst, accel_odr), \ + .accel_range = DT_INST_PROP(inst, accel_range), \ + IF_ENABLED(UTIL_OR(DT_INST_NODE_HAS_PROP(inst, int1_gpios), \ + DT_INST_NODE_HAS_PROP(inst, int2_gpios)), \ + (LIS2DU12_CFG_IRQ(inst))) + +/* + * Instantiation macros used when a device is on a SPI bus. + */ + +#define LIS2DU12_CONFIG_SPI(inst) \ + { \ + STMEMSC_CTX_SPI(&lis2du12_config_##inst.stmemsc_cfg), \ + .stmemsc_cfg = { \ + .spi = SPI_DT_SPEC_INST_GET(inst, \ + LIS2DU12_SPI_OP, \ + 0), \ + }, \ + LIS2DU12_CONFIG_COMMON(inst) \ + } + +/* + * Instantiation macros used when a device is on an I2C bus. + */ + +#define LIS2DU12_CONFIG_I2C(inst) \ + { \ + STMEMSC_CTX_I2C(&lis2du12_config_##inst.stmemsc_cfg), \ + .stmemsc_cfg = { \ + .i2c = I2C_DT_SPEC_INST_GET(inst), \ + }, \ + LIS2DU12_CONFIG_COMMON(inst) \ + } + +/* + * Main instantiation macro. Use of COND_CODE_1() selects the right + * bus-specific macro at preprocessor time. + */ + +#define LIS2DU12_DEFINE(inst) \ + static struct lis2du12_data lis2du12_data_##inst; \ + static const struct lis2du12_config lis2du12_config_##inst = \ + COND_CODE_1(DT_INST_ON_BUS(inst, spi), \ + (LIS2DU12_CONFIG_SPI(inst)), \ + (LIS2DU12_CONFIG_I2C(inst))); \ + LIS2DU12_DEVICE_INIT(inst) + +DT_INST_FOREACH_STATUS_OKAY(LIS2DU12_DEFINE) diff --git a/drivers/sensor/lis2du12/lis2du12.h b/drivers/sensor/lis2du12/lis2du12.h new file mode 100644 index 00000000000..f05d0511b7b --- /dev/null +++ b/drivers/sensor/lis2du12/lis2du12.h @@ -0,0 +1,98 @@ +/* ST Microelectronics LIS2DU12 3-axis accelerometer sensor driver + * + * Copyright (c) 2023 STMicroelectronics + * + * SPDX-License-Identifier: Apache-2.0 + * + * Datasheet: + * https://www.st.com/resource/en/datasheet/lis2du12.pdf + */ + +#ifndef ZEPHYR_DRIVERS_SENSOR_LIS2DU12_LIS2DU12_H_ +#define ZEPHYR_DRIVERS_SENSOR_LIS2DU12_LIS2DU12_H_ + +#include +#include +#include +#include +#include +#include "lis2du12_reg.h" + +#if DT_ANY_INST_ON_BUS_STATUS_OKAY(spi) +#include +#endif /* DT_ANY_INST_ON_BUS_STATUS_OKAY(spi) */ + +#if DT_ANY_INST_ON_BUS_STATUS_OKAY(i2c) +#include +#endif /* DT_ANY_INST_ON_BUS_STATUS_OKAY(i2c) */ + +#define LIS2DU12_EN_BIT 0x01 +#define LIS2DU12_DIS_BIT 0x00 + +/* Accel sensor sensitivity grain is 61 ug/LSB */ +#define GAIN_UNIT_XL (61LL) + +#define SENSOR_G_DOUBLE (SENSOR_G / 1000000.0) + +struct lis2du12_config { + stmdev_ctx_t ctx; + union { +#if DT_ANY_INST_ON_BUS_STATUS_OKAY(i2c) + const struct i2c_dt_spec i2c; +#endif +#if DT_ANY_INST_ON_BUS_STATUS_OKAY(spi) + const struct spi_dt_spec spi; +#endif + } stmemsc_cfg; + uint8_t accel_pm; + uint8_t accel_odr; + uint8_t accel_range; + uint8_t drdy_pulsed; +#ifdef CONFIG_LIS2DU12_TRIGGER + const struct gpio_dt_spec int1_gpio; + const struct gpio_dt_spec int2_gpio; + uint8_t drdy_pin; + bool trig_enabled; +#endif /* CONFIG_LIS2DU12_TRIGGER */ +}; + +union samples { + uint8_t raw[6]; + struct { + int16_t axis[3]; + }; +} __aligned(2); + +struct lis2du12_data { + const struct device *dev; + int16_t acc[3]; + uint32_t acc_gain; + uint16_t accel_freq; + uint8_t accel_fs; + +#ifdef CONFIG_LIS2DU12_TRIGGER + struct gpio_dt_spec *drdy_gpio; + + struct gpio_callback gpio_cb; + sensor_trigger_handler_t handler_drdy_acc; + const struct sensor_trigger *trig_drdy_acc; + +#if defined(CONFIG_LIS2DU12_TRIGGER_OWN_THREAD) + K_KERNEL_STACK_MEMBER(thread_stack, CONFIG_LIS2DU12_THREAD_STACK_SIZE); + struct k_thread thread; + struct k_sem gpio_sem; +#elif defined(CONFIG_LIS2DU12_TRIGGER_GLOBAL_THREAD) + struct k_work work; +#endif +#endif /* CONFIG_LIS2DU12_TRIGGER */ +}; + +#ifdef CONFIG_LIS2DU12_TRIGGER +int lis2du12_trigger_set(const struct device *dev, + const struct sensor_trigger *trig, + sensor_trigger_handler_t handler); + +int lis2du12_init_interrupt(const struct device *dev); +#endif + +#endif /* ZEPHYR_DRIVERS_SENSOR_LIS2DU12_LIS2DU12_H_ */ diff --git a/drivers/sensor/lis2du12/lis2du12_trigger.c b/drivers/sensor/lis2du12/lis2du12_trigger.c new file mode 100644 index 00000000000..d2edbad3e2b --- /dev/null +++ b/drivers/sensor/lis2du12/lis2du12_trigger.c @@ -0,0 +1,215 @@ +/* ST Microelectronics LIS2DU12 3-axis accelerometer sensor driver + * + * Copyright (c) 2023 STMicroelectronics + * + * SPDX-License-Identifier: Apache-2.0 + * + * Datasheet: + * https://www.st.com/resource/en/datasheet/lis2du12.pdf + */ + +#define DT_DRV_COMPAT st_lis2du12 + +#include +#include +#include +#include + +#include "lis2du12.h" + +LOG_MODULE_DECLARE(LIS2DU12, CONFIG_SENSOR_LOG_LEVEL); + +/** + * lis2du12_enable_xl_int - XL enable selected int pin to generate interrupt + */ +static int lis2du12_enable_xl_int(const struct device *dev, int enable) +{ + const struct lis2du12_config *cfg = dev->config; + stmdev_ctx_t *ctx = (stmdev_ctx_t *)&cfg->ctx; + int ret; + + if (enable) { + lis2du12_md_t md; + lis2du12_data_t xl_data; + + /* dummy read: re-trigger interrupt */ + md.fs = cfg->accel_range; + lis2du12_data_get(ctx, &md, &xl_data); + } + + /* set interrupt */ + if (cfg->drdy_pin == 1) { + lis2du12_pin_int_route_t val; + + ret = lis2du12_pin_int1_route_get(ctx, &val); + if (ret < 0) { + LOG_ERR("pint_int1_route_get error"); + return ret; + } + + val.drdy_xl = 1; + + ret = lis2du12_pin_int1_route_set(ctx, &val); + } else { + lis2du12_pin_int_route_t val; + + ret = lis2du12_pin_int2_route_get(ctx, &val); + if (ret < 0) { + LOG_ERR("pint_int2_route_get error"); + return ret; + } + + val.drdy_xl = 1; + + ret = lis2du12_pin_int2_route_set(ctx, &val); + } + + return ret; +} + +/** + * lis2du12_trigger_set - link external trigger to event data ready + */ +int lis2du12_trigger_set(const struct device *dev, + const struct sensor_trigger *trig, + sensor_trigger_handler_t handler) +{ + const struct lis2du12_config *cfg = dev->config; + struct lis2du12_data *lis2du12 = dev->data; + + if (!cfg->trig_enabled) { + LOG_ERR("trigger_set op not supported"); + return -ENOTSUP; + } + + switch (trig->chan) { + case SENSOR_CHAN_ACCEL_XYZ: + lis2du12->handler_drdy_acc = handler; + lis2du12->trig_drdy_acc = trig; + if (handler) { + return lis2du12_enable_xl_int(dev, LIS2DU12_EN_BIT); + } + + return lis2du12_enable_xl_int(dev, LIS2DU12_DIS_BIT); + + default: + return -ENOTSUP; + } + +} + +/** + * lis2du12_handle_interrupt - handle the drdy event + * read data and call handler if registered any + */ +static void lis2du12_handle_interrupt(const struct device *dev) +{ + struct lis2du12_data *lis2du12 = dev->data; + const struct lis2du12_config *cfg = dev->config; + stmdev_ctx_t *ctx = (stmdev_ctx_t *)&cfg->ctx; + lis2du12_status_t status; + + while (1) { + if (lis2du12_status_get(ctx, &status) < 0) { + LOG_ERR("failed reading status reg"); + return; + } + + if (status.drdy_xl == 0) { + break; + } + + if ((status.drdy_xl) && (lis2du12->handler_drdy_acc != NULL)) { + lis2du12->handler_drdy_acc(dev, lis2du12->trig_drdy_acc); + } + } + + gpio_pin_interrupt_configure_dt(lis2du12->drdy_gpio, + GPIO_INT_EDGE_TO_ACTIVE); +} + +static void lis2du12_gpio_callback(const struct device *dev, + struct gpio_callback *cb, uint32_t pins) +{ + struct lis2du12_data *lis2du12 = + CONTAINER_OF(cb, struct lis2du12_data, gpio_cb); + + ARG_UNUSED(pins); + + gpio_pin_interrupt_configure_dt(lis2du12->drdy_gpio, GPIO_INT_DISABLE); + +#if defined(CONFIG_LIS2DU12_TRIGGER_OWN_THREAD) + k_sem_give(&lis2du12->gpio_sem); +#elif defined(CONFIG_LIS2DU12_TRIGGER_GLOBAL_THREAD) + k_work_submit(&lis2du12->work); +#endif /* CONFIG_LIS2DU12_TRIGGER_OWN_THREAD */ +} + +#ifdef CONFIG_LIS2DU12_TRIGGER_OWN_THREAD +static void lis2du12_thread(struct lis2du12_data *lis2du12) +{ + while (1) { + k_sem_take(&lis2du12->gpio_sem, K_FOREVER); + lis2du12_handle_interrupt(lis2du12->dev); + } +} +#endif /* CONFIG_LIS2DU12_TRIGGER_OWN_THREAD */ + +#ifdef CONFIG_LIS2DU12_TRIGGER_GLOBAL_THREAD +static void lis2du12_work_cb(struct k_work *work) +{ + struct lis2du12_data *lis2du12 = + CONTAINER_OF(work, struct lis2du12_data, work); + + lis2du12_handle_interrupt(lis2du12->dev); +} +#endif /* CONFIG_LIS2DU12_TRIGGER_GLOBAL_THREAD */ + +int lis2du12_init_interrupt(const struct device *dev) +{ + struct lis2du12_data *lis2du12 = dev->data; + const struct lis2du12_config *cfg = dev->config; + int ret; + + lis2du12->drdy_gpio = (cfg->drdy_pin == 1) ? + (struct gpio_dt_spec *)&cfg->int1_gpio : + (struct gpio_dt_spec *)&cfg->int2_gpio; + + /* setup data ready gpio interrupt (INT1 or INT2) */ + if (!gpio_is_ready_dt(lis2du12->drdy_gpio)) { + LOG_ERR("Cannot get pointer to drdy_gpio device (%p)", + lis2du12->drdy_gpio); + return -EINVAL; + } + +#if defined(CONFIG_LIS2DU12_TRIGGER_OWN_THREAD) + k_sem_init(&lis2du12->gpio_sem, 0, K_SEM_MAX_LIMIT); + + k_thread_create(&lis2du12->thread, lis2du12->thread_stack, + CONFIG_LIS2DU12_THREAD_STACK_SIZE, + (k_thread_entry_t)lis2du12_thread, lis2du12, + NULL, NULL, K_PRIO_COOP(CONFIG_LIS2DU12_THREAD_PRIORITY), + 0, K_NO_WAIT); + k_thread_name_set(&lis2du12->thread, dev->name); +#elif defined(CONFIG_LIS2DU12_TRIGGER_GLOBAL_THREAD) + lis2du12->work.handler = lis2du12_work_cb; +#endif /* CONFIG_LIS2DU12_TRIGGER_OWN_THREAD */ + + ret = gpio_pin_configure_dt(lis2du12->drdy_gpio, GPIO_INPUT); + if (ret < 0) { + LOG_ERR("Could not configure gpio: %d", ret); + return ret; + } + + gpio_init_callback(&lis2du12->gpio_cb, + lis2du12_gpio_callback, + BIT(lis2du12->drdy_gpio->pin)); + + if (gpio_add_callback(lis2du12->drdy_gpio->port, &lis2du12->gpio_cb) < 0) { + LOG_ERR("Could not set gpio callback"); + return -EIO; + } + + return gpio_pin_interrupt_configure_dt(lis2du12->drdy_gpio, + GPIO_INT_EDGE_TO_ACTIVE); +} diff --git a/dts/bindings/sensor/st,lis2du12-common.yaml b/dts/bindings/sensor/st,lis2du12-common.yaml new file mode 100644 index 00000000000..d9ca38d9e32 --- /dev/null +++ b/dts/bindings/sensor/st,lis2du12-common.yaml @@ -0,0 +1,97 @@ +# Copyright (c) 2023 STMicroelectronics +# SPDX-License-Identifier: Apache-2.0 + +description: | + When setting the accel-range, accel-odr, properties in a .dts or .dtsi + file you may include lis2du12.h and use the macros defined there. + + Example: + #include + + lis2du12: lis2du12@0 { + ... + + accel-range = ; + accel-odr = ; + }; + +include: sensor-device.yaml + +properties: + int1-gpios: + type: phandle-array + description: | + INT1 pin + + This pin defaults to active high when produced by the sensor. + The property value should ensure the flags properly describe + the signal that is presented to the driver. + + int2-gpios: + type: phandle-array + description: | + INT2 pin + + This pin defaults to active high when produced by the sensor. + The property value should ensure the flags properly describe + the signal that is presented to the driver. + + drdy-pin: + type: int + default: 1 + description: | + Select DRDY pin number (1 or 2). + + 1 = drdy is generated from INT1 + 2 = drdy is generated from INT2 + + This number represents which of the two interrupt pins + (INT1 or INT2) the drdy line is attached to. This property is not + mandatory and if not present it defaults to 1 which is the + configuration at power-up. + enum: [1, 2] + + accel-range: + type: int + default: 0 + description: | + Range in g. Default is power-up configuration. + + 0 # LIS2DU12_DT_FS_2G (0.061 mg/LSB) + 1 # LIS2DU12_DT_FS_4G (0.122 mg/LSB) + 2 # LIS2DU12_DT_FS_8G (0.244 mg/LSB) + 3 # LIS2DU12_DT_FS_16G (0.488 mg/LSB) + + enum: [0, 1, 2, 3] + + accel-odr: + type: int + default: 0x0 + description: | + Specify the default accelerometer output data rate expressed in samples per second (Hz). + The values are taken in accordance to lis2du12_md_t enumerative in hal/st + module. Please note that this values will also enable/disable High performance mode. + Default is power-up configuration. + + 0x00 # LIS2DU12_DT_ODR_OFF + 0x01 # 1Hz6 (ultra low power) + 0x02 # 3Hz (ultra low power) + 0x03 # 25Hz (ultra low power) + 0x04 # 6Hz (low power) + 0x05 # 12Hz5 (low power) + 0x06 # 25Hz (low power) + 0x07 # 50Hz (low power) + 0x08 # 100Hz (low power) + 0x09 # 200Hz (low power) + 0x0a # 400Hz (low power) + 0x0b # 800Hz (low power) + 0x0e # Single-shot high latency by INT2 + 0x0f # Single-shot high latency by IF + + enum: [0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b, 0x0e, 0x0f] + + drdy-pulsed: + type: boolean + description: | + Selects the pulsed mode for data-ready interrupt when enabled, + and the latched mode when disabled. diff --git a/dts/bindings/sensor/st,lis2du12-i2c.yaml b/dts/bindings/sensor/st,lis2du12-i2c.yaml new file mode 100644 index 00000000000..ad09f2601c3 --- /dev/null +++ b/dts/bindings/sensor/st,lis2du12-i2c.yaml @@ -0,0 +1,10 @@ +# Copyright (c) 2023 STMicroelectronics +# SPDX-License-Identifier: Apache-2.0 + +description: | + STMicroelectronics LIS2DU12 3-axis ultra-low power accelerometer sensor + accessed through I2C bus + +compatible: "st,lis2du12" + +include: ["i2c-device.yaml", "st,lis2du12-common.yaml"] diff --git a/dts/bindings/sensor/st,lis2du12-spi.yaml b/dts/bindings/sensor/st,lis2du12-spi.yaml new file mode 100644 index 00000000000..0fad5696827 --- /dev/null +++ b/dts/bindings/sensor/st,lis2du12-spi.yaml @@ -0,0 +1,10 @@ +# Copyright (c) 2023 STMicroelectronics +# SPDX-License-Identifier: Apache-2.0 + +description: | + STMicroelectronics LIS2DU12 3-axis ultra-low power accelerometer sensor + accessed through SPI bus + +compatible: "st,lis2du12" + +include: ["spi-device.yaml", "st,lis2du12-common.yaml"] diff --git a/include/zephyr/dt-bindings/sensor/lis2du12.h b/include/zephyr/dt-bindings/sensor/lis2du12.h new file mode 100644 index 00000000000..99e4c520e3f --- /dev/null +++ b/include/zephyr/dt-bindings/sensor/lis2du12.h @@ -0,0 +1,31 @@ +/* + * Copyright (c) 2023 STMicroelectronics + * + * SPDX-License-Identifier: Apache-2.0 + */ +#ifndef ZEPHYR_INCLUDE_DT_BINDINGS_ST_LIS2DU12_H_ +#define ZEPHYR_INCLUDE_DT_BINDINGS_ST_LIS2DU12_H_ + +/* Accel range */ +#define LIS2DU12_DT_FS_2G 0 +#define LIS2DU12_DT_FS_4G 1 +#define LIS2DU12_DT_FS_8G 2 +#define LIS2DU12_DT_FS_16G 3 + +/* Accel rates */ +#define LIS2DU12_DT_ODR_OFF 0x00 /* Power-Down */ +#define LIS2DU12_DT_ODR_AT_1Hz6_ULP 0x01 /* 1Hz6 (ultra low power) */ +#define LIS2DU12_DT_ODR_AT_3Hz_ULP 0x02 /* 3Hz (ultra low power) */ +#define LIS2DU12_DT_ODR_AT_6Hz_ULP 0x03 /* 6Hz (ultra low power) */ +#define LIS2DU12_DT_ODR_AT_6Hz 0x04 /* 6Hz (normal) */ +#define LIS2DU12_DT_ODR_AT_12Hz 0x05 /* 12Hz5 (normal) */ +#define LIS2DU12_DT_ODR_AT_25Hz 0x06 /* 25Hz (normal) */ +#define LIS2DU12_DT_ODR_AT_50Hz 0x07 /* 50Hz (normal) */ +#define LIS2DU12_DT_ODR_AT_100Hz 0x08 /* 100Hz (normal) */ +#define LIS2DU12_DT_ODR_AT_200Hz 0x09 /* 200Hz (normal) */ +#define LIS2DU12_DT_ODR_AT_400Hz 0x0a /* 400Hz (normal) */ +#define LIS2DU12_DT_ODR_AT_800Hz 0x0b /* 800Hz (normal) */ +#define LIS2DU12_DT_ODR_TRIG_PIN 0x0e /* Single-shot high latency by INT2 */ +#define LIS2DU12_DT_ODR_TRIG_SW 0x0f /* Single-shot high latency by IF */ + +#endif /* ZEPHYR_INCLUDE_DT_BINDINGS_ST_LIS2DU12_H_ */ diff --git a/modules/Kconfig.st b/modules/Kconfig.st index 371f1063349..d853b742512 100644 --- a/modules/Kconfig.st +++ b/modules/Kconfig.st @@ -88,6 +88,9 @@ config USE_STDC_LIS2DS12 config USE_STDC_LIS2DTW12 bool +config USE_STDC_LIS2DU12 + bool + config USE_STDC_LIS2DW12 bool diff --git a/tests/drivers/build_all/sensor/app.overlay b/tests/drivers/build_all/sensor/app.overlay index 9f7c604bf30..c836a2b5fa8 100644 --- a/tests/drivers/build_all/sensor/app.overlay +++ b/tests/drivers/build_all/sensor/app.overlay @@ -122,7 +122,8 @@ <&test_gpio 0 0>, <&test_gpio 0 0>, /* 0x25 */ <&test_gpio 0 0>, /* 0x26 */ - <&test_gpio 0 0>; /* 0x27 */ + <&test_gpio 0 0>, /* 0x27 */ + <&test_gpio 0 0>; /* 0x28 */ #include "spi.dtsi" }; diff --git a/tests/drivers/build_all/sensor/i2c.dtsi b/tests/drivers/build_all/sensor/i2c.dtsi index 23abb1a47a4..9387a24cc85 100644 --- a/tests/drivers/build_all/sensor/i2c.dtsi +++ b/tests/drivers/build_all/sensor/i2c.dtsi @@ -17,6 +17,7 @@ #include #include #include +#include /**************************************** * PLEASE KEEP REG ADDRESSES SEQUENTIAL * @@ -869,3 +870,12 @@ test_i2c_lps28dfw: lps28dfw@7b { avg = ; fs = ; }; + +test_i2c_lis2du12: lis2du12@7c { + compatible = "st,lis2du12"; + reg = <0x7c>; + int1-gpios = <&test_gpio 0 0>; + int2-gpios = <&test_gpio 0 0>; + accel-range = ; + accel-odr = ; +}; diff --git a/tests/drivers/build_all/sensor/sensors_trigger_global.conf b/tests/drivers/build_all/sensor/sensors_trigger_global.conf index 197f61bd74d..2dc30736420 100644 --- a/tests/drivers/build_all/sensor/sensors_trigger_global.conf +++ b/tests/drivers/build_all/sensor/sensors_trigger_global.conf @@ -33,6 +33,7 @@ CONFIG_ISL29035_TRIGGER_GLOBAL_THREAD=y CONFIG_ISM330DHCX_TRIGGER_GLOBAL_THREAD=y CONFIG_LIS2DH_TRIGGER_GLOBAL_THREAD=y CONFIG_LIS2DS12_TRIGGER_GLOBAL_THREAD=y +CONFIG_LIS2DU12_TRIGGER_GLOBAL_THREAD=y CONFIG_LIS2DW12_TRIGGER_GLOBAL_THREAD=y CONFIG_LIS2MDL_TRIGGER_GLOBAL_THREAD=y CONFIG_LIS3MDL_TRIGGER_GLOBAL_THREAD=y diff --git a/tests/drivers/build_all/sensor/sensors_trigger_none.conf b/tests/drivers/build_all/sensor/sensors_trigger_none.conf index cd9dfac3915..3012c09845b 100644 --- a/tests/drivers/build_all/sensor/sensors_trigger_none.conf +++ b/tests/drivers/build_all/sensor/sensors_trigger_none.conf @@ -33,6 +33,7 @@ CONFIG_ISL29035_TRIGGER_NONE=y CONFIG_ISM330DHCX_TRIGGER_NONE=y CONFIG_LIS2DH_TRIGGER_NONE=y CONFIG_LIS2DS12_TRIGGER_NONE=y +CONFIG_LIS2DU12_TRIGGER_NONE=y CONFIG_LIS2DW12_TRIGGER_NONE=y CONFIG_LIS2MDL_TRIGGER_NONE=y CONFIG_LIS3MDL_TRIGGER_NONE=y diff --git a/tests/drivers/build_all/sensor/sensors_trigger_own.conf b/tests/drivers/build_all/sensor/sensors_trigger_own.conf index 05ed9500fe3..79ee1f82eae 100644 --- a/tests/drivers/build_all/sensor/sensors_trigger_own.conf +++ b/tests/drivers/build_all/sensor/sensors_trigger_own.conf @@ -31,6 +31,7 @@ CONFIG_ISL29035_TRIGGER_OWN_THREAD=y CONFIG_ISM330DHCX_TRIGGER_OWN_THREAD=y CONFIG_LIS2DH_TRIGGER_OWN_THREAD=y CONFIG_LIS2DS12_TRIGGER_OWN_THREAD=y +CONFIG_LIS2DU12_TRIGGER_OWN_THREAD=y CONFIG_LIS2DW12_TRIGGER_OWN_THREAD=y CONFIG_LIS2MDL_TRIGGER_OWN_THREAD=y CONFIG_LIS3MDL_TRIGGER_OWN_THREAD=y diff --git a/tests/drivers/build_all/sensor/spi.dtsi b/tests/drivers/build_all/sensor/spi.dtsi index cd7bf1b66ec..120b990fccd 100644 --- a/tests/drivers/build_all/sensor/spi.dtsi +++ b/tests/drivers/build_all/sensor/spi.dtsi @@ -312,3 +312,12 @@ test_spi_lps22df: lps22df@27 { drdy-gpios = <&test_gpio 0 0>; status = "okay"; }; + +test_spi_lis2du12: lis2du12@28 { + compatible = "st,lis2du12"; + reg = <0x28>; + spi-max-frequency = <0>; + int1-gpios = <&test_gpio 0 0>; + int2-gpios = <&test_gpio 0 0>; + status = "okay"; +}; From 23110dcfae62087b03a120131efd975dda84e2f6 Mon Sep 17 00:00:00 2001 From: Armando Visconti Date: Fri, 24 Nov 2023 11:33:09 +0100 Subject: [PATCH 1222/3723] boards: arm: sensortile_box_pro: extend with lis2du12 Extend sensortile_box_pro with lis2du12 accelerometer. Signed-off-by: Armando Visconti --- .../arm/sensortile_box_pro/sensortile_box_pro.dts | 14 ++++++++++++-- 1 file changed, 12 insertions(+), 2 deletions(-) diff --git a/boards/arm/sensortile_box_pro/sensortile_box_pro.dts b/boards/arm/sensortile_box_pro/sensortile_box_pro.dts index dc3f7ba9c64..a9090366709 100644 --- a/boards/arm/sensortile_box_pro/sensortile_box_pro.dts +++ b/boards/arm/sensortile_box_pro/sensortile_box_pro.dts @@ -169,17 +169,27 @@ stm32_lp_tick_source: &lptim1 { pinctrl-names = "default"; status = "okay"; - cs-gpios = <&gpioi 5 GPIO_ACTIVE_LOW>; + cs-gpios = <&gpioi 5 GPIO_ACTIVE_LOW>, <&gpioi 7 GPIO_ACTIVE_LOW>; lsm6dsv16x: lsm6dsv16x@0 { compatible = "st,lsm6dsv16x"; - spi-max-frequency = ; /* 10 MHz */ + spi-max-frequency = ; reg = <0>; int1-gpios = <&gpioa 4 GPIO_ACTIVE_HIGH>; int2-gpios = <&gpiod 11 GPIO_ACTIVE_HIGH>; drdy-pin = <2>; }; + + lis2du12: lis2du12@1 { + compatible = "st,lis2du12"; + spi-max-frequency = ; + reg = <1>; + int1-gpios = <&gpiof 2 GPIO_ACTIVE_HIGH>; + int2-gpios = <&gpiof 15 GPIO_ACTIVE_HIGH>; + + drdy-pin = <2>; + }; }; &timers4 { From 3fe0ffb9dcf16f424405f678bdc3d7df9cda36cb Mon Sep 17 00:00:00 2001 From: Armando Visconti Date: Fri, 24 Nov 2023 11:34:59 +0100 Subject: [PATCH 1223/3723] sample: board: sensortile_box_pro: extend with lis2du12 accelerometer Extend sensor sample reading also lis2du12 accelerometer data. Signed-off-by: Armando Visconti --- .../sensors-on-board/README.rst | 5 ++ .../sensors-on-board/prj.conf | 1 + .../sensors-on-board/src/main.c | 58 +++++++++++++++++++ 3 files changed, 64 insertions(+) diff --git a/samples/boards/sensortile_box_pro/sensors-on-board/README.rst b/samples/boards/sensortile_box_pro/sensors-on-board/README.rst index f65294f2aa8..ce0034e2d86 100644 --- a/samples/boards/sensortile_box_pro/sensors-on-board/README.rst +++ b/samples/boards/sensortile_box_pro/sensors-on-board/README.rst @@ -15,6 +15,7 @@ sensors: - HTS221: ambient temperature and relative humidity - LPS22DF: ambient temperature and atmospheric pressure - LSM6DSV16X: 6-Axis acceleration and angular velocity +- LIS2DU12: 3-Axis acceleration Requirements ************ @@ -67,7 +68,11 @@ The sample code outputs sensors data on the SensorTile.box Pro console. LPS22DF: Pressure:99.694 kpa LSM6DSV16X: Accel (m.s-2): x: -0.158, y: 0.158, z: 9.811 LSM6DSV16X: GYro (dps): x: 0.003, y: 0.000, z: -0.005 + LIS2DU12: Accel (m.s-2): x: -0.756, y: -0.249, z: -9.629 + 1:: lps22df trig 199 1:: lsm6dsv16x acc trig 836 1:: lsm6dsv16x gyr trig 836 + 1:: lis2mdl trig 402 + 1:: lis2du12 trig 1589 diff --git a/samples/boards/sensortile_box_pro/sensors-on-board/prj.conf b/samples/boards/sensortile_box_pro/sensors-on-board/prj.conf index a618f6ebece..97e6a2d17f2 100644 --- a/samples/boards/sensortile_box_pro/sensors-on-board/prj.conf +++ b/samples/boards/sensortile_box_pro/sensors-on-board/prj.conf @@ -11,5 +11,6 @@ CONFIG_HTS221_TRIGGER_NONE=y CONFIG_LPS2XDF_TRIGGER_OWN_THREAD=y CONFIG_LSM6DSV16X_TRIGGER_OWN_THREAD=y CONFIG_LIS2MDL_TRIGGER_OWN_THREAD=y +CONFIG_LIS2DU12_TRIGGER_OWN_THREAD=y CONFIG_CBPRINTF_FP_SUPPORT=y diff --git a/samples/boards/sensortile_box_pro/sensors-on-board/src/main.c b/samples/boards/sensortile_box_pro/sensors-on-board/src/main.c index 80c44f7ff0c..cc27fc2c125 100644 --- a/samples/boards/sensortile_box_pro/sensors-on-board/src/main.c +++ b/samples/boards/sensortile_box_pro/sensors-on-board/src/main.c @@ -64,6 +64,17 @@ static void lis2mdl_trigger_handler(const struct device *dev, } #endif +#ifdef CONFIG_LIS2DU12_TRIGGER +static int lis2du12_trig_cnt; + +static void lis2du12_trigger_handler(const struct device *dev, + const struct sensor_trigger *trig) +{ + sensor_sample_fetch_chan(dev, SENSOR_CHAN_ALL); + lis2du12_trig_cnt++; +} +#endif + static void lps22df_config(const struct device *lps22df) { struct sensor_value odr_attr; @@ -167,6 +178,29 @@ static void lis2mdl_config(const struct device *lis2mdl) #endif } +static void lis2du12_config(const struct device *lis2du12) +{ + struct sensor_value odr_attr; + + /* set LIS2DU12 sampling frequency to 400 Hz */ + odr_attr.val1 = 400; + odr_attr.val2 = 0; + + if (sensor_attr_set(lis2du12, SENSOR_CHAN_ACCEL_XYZ, + SENSOR_ATTR_SAMPLING_FREQUENCY, &odr_attr) < 0) { + printk("Cannot set sampling frequency for LIS2DU12\n"); + return; + } + +#ifdef CONFIG_LIS2DU12_TRIGGER + struct sensor_trigger trig; + + trig.type = SENSOR_TRIG_DATA_READY; + trig.chan = SENSOR_CHAN_ACCEL_XYZ; + sensor_trigger_set(lis2du12, &trig, lis2du12_trigger_handler); +#endif +} + static int led_pattern_out(void) { const struct gpio_dt_spec led0_gpio = GPIO_DT_SPEC_GET(DT_ALIAS(led0), gpios); @@ -236,6 +270,7 @@ int main(void) const struct device *const lps22df = DEVICE_DT_GET_ONE(st_lps22df); const struct device *const lsm6dsv16x = DEVICE_DT_GET_ONE(st_lsm6dsv16x); const struct device *const lis2mdl = DEVICE_DT_GET_ONE(st_lis2mdl); + const struct device *const lis2du12 = DEVICE_DT_GET_ONE(st_lis2du12); if (!device_is_ready(hts221)) { printk("%s: device not ready.\n", hts221->name); @@ -253,7 +288,12 @@ int main(void) printk("%s: device not ready.\n", lis2mdl->name); return 0; } + if (!device_is_ready(lis2du12)) { + printk("%s: device not ready.\n", lis2du12->name); + return 0; + } + lis2du12_config(lis2du12); lis2mdl_config(lis2mdl); lps22df_config(lps22df); lsm6dsv16x_config(lsm6dsv16x); @@ -264,6 +304,7 @@ int main(void) struct sensor_value lsm6dsv16x_accel[3], lsm6dsv16x_gyro[3]; struct sensor_value lis2mdl_magn[3]; struct sensor_value lis2mdl_temp; + struct sensor_value lis2du12_accel[3]; /* handle HTS221 sensor */ if (sensor_sample_fetch(hts221) < 0) { @@ -292,6 +333,13 @@ int main(void) } #endif +#ifndef CONFIG_LIS2DU12_TRIGGER + if (sensor_sample_fetch(lis2du12) < 0) { + printf("LIS2DU12 xl Sensor sample update error\n"); + return 0; + } +#endif + sensor_channel_get(hts221, SENSOR_CHAN_HUMIDITY, &hts221_hum); sensor_channel_get(hts221, SENSOR_CHAN_AMBIENT_TEMP, &hts221_temp); sensor_channel_get(lps22df, SENSOR_CHAN_AMBIENT_TEMP, &lps22df_temp); @@ -300,6 +348,7 @@ int main(void) sensor_channel_get(lsm6dsv16x, SENSOR_CHAN_GYRO_XYZ, lsm6dsv16x_gyro); sensor_channel_get(lis2mdl, SENSOR_CHAN_MAGN_XYZ, lis2mdl_magn); sensor_channel_get(lis2mdl, SENSOR_CHAN_DIE_TEMP, &lis2mdl_temp); + sensor_channel_get(lis2du12, SENSOR_CHAN_ACCEL_XYZ, lis2du12_accel); /* Display sensor data */ @@ -343,6 +392,11 @@ int main(void) printf("LIS2MDL: Temperature: %.1f C\n", sensor_value_to_double(&lis2mdl_temp)); + printf("LIS2DU12: Accel (m.s-2): x: %.3f, y: %.3f, z: %.3f\n", + sensor_value_to_double(&lis2du12_accel[0]), + sensor_value_to_double(&lis2du12_accel[1]), + sensor_value_to_double(&lis2du12_accel[2])); + #ifdef CONFIG_LPS2XDF_TRIGGER printk("%d:: lps22df trig %d\n", cnt, lps22df_trig_cnt); #endif @@ -356,6 +410,10 @@ int main(void) printk("%d:: lis2mdl trig %d\n", cnt, lis2mdl_trig_cnt); #endif +#ifdef CONFIG_LIS2DU12_TRIGGER + printk("%d:: lis2du12 trig %d\n", cnt, lis2du12_trig_cnt); +#endif + k_sleep(K_MSEC(2000)); } } From 263846dd67262335b899c9c62fec05b824ff3d6d Mon Sep 17 00:00:00 2001 From: Andrej Butok Date: Thu, 7 Dec 2023 14:53:11 +0100 Subject: [PATCH 1224/3723] boards: mimxrt1040_evk: add boot and slot partitions Add boot and slot partitions for mimxrt1040_evk. Enable MCUBoot support for it. Signed-off-by: Andrej Butok --- boards/arm/mimxrt1040_evk/mimxrt1040_evk.dts | 25 +++++++++++++++++++- 1 file changed, 24 insertions(+), 1 deletion(-) diff --git a/boards/arm/mimxrt1040_evk/mimxrt1040_evk.dts b/boards/arm/mimxrt1040_evk/mimxrt1040_evk.dts index 6e9a9c4c2bb..5beae5ffc40 100644 --- a/boards/arm/mimxrt1040_evk/mimxrt1040_evk.dts +++ b/boards/arm/mimxrt1040_evk/mimxrt1040_evk.dts @@ -21,12 +21,14 @@ }; chosen { - zephyr,flash = &w25q64jvssiq; zephyr,sram = &sdram0; zephyr,itcm = &itcm; zephyr,dtcm = &dtcm; zephyr,console = &lpuart1; zephyr,shell-uart = &lpuart1; + zephyr,flash = &w25q64jvssiq; + zephyr,flash-controller = &w25q64jvssiq; + zephyr,code-partition = &slot0_partition; }; sdram0: memory@80000000 { @@ -95,6 +97,27 @@ jedec-id = [ef 40 17]; erase-block-size = <4096>; write-block-size = <1>; + partitions { + compatible = "fixed-partitions"; + #address-cells = <1>; + #size-cells = <1>; + boot_partition: partition@0 { + label = "mcuboot"; + reg = <0x00000000 DT_SIZE_K(64)>; + }; + slot0_partition: partition@10000 { + label = "image-0"; + reg = <0x00010000 DT_SIZE_M(3)>; + }; + slot1_partition: partition@310000 { + label = "image-1"; + reg = <0x00310000 DT_SIZE_M(3)>; + }; + storage_partition: partition@610000 { + label = "storage"; + reg = <0x00610000 DT_SIZE_K(1984)>; + }; + }; }; }; From e913ccc75354537627e6735892aaa20ba268ffe9 Mon Sep 17 00:00:00 2001 From: Declan Snyder Date: Mon, 11 Dec 2023 10:57:10 -0600 Subject: [PATCH 1225/3723] net: Add Kconfig for net buf alignment Add a NET_BUF_ALIGNMENT kconfig to make net buffer alignment configurable. Signed-off-by: Declan Snyder --- include/zephyr/net/buf.h | 4 ++++ subsys/net/Kconfig | 10 ++++++++++ 2 files changed, 14 insertions(+) diff --git a/include/zephyr/net/buf.h b/include/zephyr/net/buf.h index 948517428f5..94b0b9a7533 100644 --- a/include/zephyr/net/buf.h +++ b/include/zephyr/net/buf.h @@ -28,7 +28,11 @@ extern "C" { */ /* Alignment needed for various parts of the buffer definition */ +#if CONFIG_NET_BUF_ALIGNMENT == 0 #define __net_buf_align __aligned(sizeof(void *)) +#else +#define __net_buf_align __aligned(CONFIG_NET_BUF_ALIGNMENT) +#endif /** * @brief Define a net_buf_simple stack variable. diff --git a/subsys/net/Kconfig b/subsys/net/Kconfig index fad47cfe881..57706cd2f5d 100644 --- a/subsys/net/Kconfig +++ b/subsys/net/Kconfig @@ -51,6 +51,16 @@ config NET_BUF_POOL_USAGE * total size of the pool is calculated * pool name is stored and can be shown in debugging prints +config NET_BUF_ALIGNMENT + int "Network buffer alignment restriction" + default 0 + help + Alignment restriction for network buffers. This is useful for + some hardware IP with DMA that requires the buffers to be aligned + to a certain byte boundary, or dealing with cache line restrictions. + Default value of 0 means the alignment will be the size of a void pointer, + any other value will force the alignment of a net buffer in bytes. + endif # NET_BUF config NETWORKING From 1011acd4d7f94a02115c9de1deed3c2293d4ae31 Mon Sep 17 00:00:00 2001 From: Declan Snyder Date: Thu, 7 Dec 2023 00:00:55 -0600 Subject: [PATCH 1226/3723] drivers: nxp_enet: Improve code readability Improve code readability of this driver by simplifying and reworking some of the source code, formatting and comments. This commit is not meant to cause any functional difference. Signed-off-by: Declan Snyder --- drivers/ethernet/eth_nxp_enet.c | 332 +++++++----------- .../zephyr/drivers/ethernet/eth_nxp_enet.h | 4 + 2 files changed, 123 insertions(+), 213 deletions(-) diff --git a/drivers/ethernet/eth_nxp_enet.c b/drivers/ethernet/eth_nxp_enet.c index 293143fd1a1..e85edf46b82 100644 --- a/drivers/ethernet/eth_nxp_enet.c +++ b/drivers/ethernet/eth_nxp_enet.c @@ -89,7 +89,7 @@ struct nxp_enet_mac_data { struct k_mutex rx_frame_buf_mutex; #ifdef CONFIG_PTP_CLOCK_NXP_ENET struct k_sem ptp_ts_sem; - struct k_mutex *ptp_mutex; + struct k_mutex *ptp_mutex; /* created in PTP driver */ #endif /* TODO: FIXME. This Ethernet frame sized buffer is used for * interfacing with MCUX. How it works is that hardware uses @@ -118,23 +118,11 @@ struct nxp_enet_mac_data { static inline struct net_if *get_iface(struct nxp_enet_mac_data *data, uint16_t vlan_tag) { -#if defined(CONFIG_NET_VLAN) - struct net_if *iface; - - iface = net_eth_get_vlan_iface(data->iface, vlan_tag); - if (!iface) { - return data->iface; - } + struct net_if *iface = net_eth_get_vlan_iface(data->iface, vlan_tag); - return iface; -#else - ARG_UNUSED(vlan_tag); - - return data->iface; -#endif + return iface ? iface : data->iface; } -#if defined(CONFIG_NET_NATIVE_IPV4) || defined(CONFIG_NET_NATIVE_IPV6) static void net_if_mcast_cb(struct net_if *iface, const struct net_addr *addr, bool is_joined) @@ -157,105 +145,85 @@ static void net_if_mcast_cb(struct net_if *iface, ENET_LeaveMulticastGroup(config->base, mac_addr.addr); } } -#endif /* CONFIG_NET_NATIVE_IPV4 || CONFIG_NET_NATIVE_IPV6 */ - -/* - ***************** - * PTP Functions * - ***************** - */ #if defined(CONFIG_PTP_CLOCK_NXP_ENET) static bool eth_get_ptp_data(struct net_if *iface, struct net_pkt *pkt) { - int eth_hlen; + struct net_eth_vlan_hdr *hdr_vlan = (struct net_eth_vlan_hdr *)NET_ETH_HDR(pkt); + struct ethernet_context *eth_ctx = net_if_l2_data(iface); + bool pkt_is_ptp; -#if defined(CONFIG_NET_VLAN) - struct net_eth_vlan_hdr *hdr_vlan; - struct ethernet_context *eth_ctx; - bool vlan_enabled = false; - - eth_ctx = net_if_l2_data(iface); if (net_eth_is_vlan_enabled(eth_ctx, iface)) { - hdr_vlan = (struct net_eth_vlan_hdr *)NET_ETH_HDR(pkt); - vlan_enabled = true; - - if (ntohs(hdr_vlan->type) != NET_ETH_PTYPE_PTP) { - return false; - } - - eth_hlen = sizeof(struct net_eth_vlan_hdr); - } else -#endif /* CONFIG_NET_VLAN */ - { - if (ntohs(NET_ETH_HDR(pkt)->type) != NET_ETH_PTYPE_PTP) { - return false; - } - - eth_hlen = sizeof(struct net_eth_hdr); + pkt_is_ptp = ntohs(hdr_vlan->type) == NET_ETH_PTYPE_PTP; + } else { + pkt_is_ptp = ntohs(NET_ETH_HDR(pkt)->type) == NET_ETH_PTYPE_PTP; } - net_pkt_set_priority(pkt, NET_PRIORITY_CA); + if (pkt_is_ptp) { + net_pkt_set_priority(pkt, NET_PRIORITY_CA); + } - return true; + return pkt_is_ptp; } -#if defined(CONFIG_NET_L2_PTP) static inline void ts_register_tx_event(const struct device *dev, enet_frame_info_t *frameinfo) { struct nxp_enet_mac_data *data = dev->data; - struct net_pkt *pkt; + struct net_pkt *pkt = frameinfo->context; - pkt = frameinfo->context; if (pkt && atomic_get(&pkt->atomic_ref) > 0) { - if (eth_get_ptp_data(net_pkt_iface(pkt), pkt)) { - if (frameinfo->isTsAvail) { - k_mutex_lock(data->ptp_mutex, K_FOREVER); - - pkt->timestamp.nanosecond = - frameinfo->timeStamp.nanosecond; - pkt->timestamp.second = - frameinfo->timeStamp.second; - - net_if_add_tx_timestamp(pkt); - k_sem_give(&data->ptp_ts_sem); - k_mutex_unlock(data->ptp_mutex); - } - } + if (eth_get_ptp_data(net_pkt_iface(pkt), pkt) && frameinfo->isTsAvail) { + k_mutex_lock(data->ptp_mutex, K_FOREVER); + + pkt->timestamp.nanosecond = frameinfo->timeStamp.nanosecond; + pkt->timestamp.second = frameinfo->timeStamp.second; + + net_if_add_tx_timestamp(pkt); + k_sem_give(&data->ptp_ts_sem); + k_mutex_unlock(data->ptp_mutex); + } net_pkt_unref(pkt); } } -#endif /* CONFIG_NET_L2_PTP */ +static inline void eth_wait_for_ptp_ts(const struct device *dev, struct net_pkt *pkt) +{ + struct nxp_enet_mac_data *data = dev->data; + + net_pkt_ref(pkt); + k_sem_take(&data->ptp_ts_sem, K_FOREVER); +} +#else +#define eth_get_ptp_data(...) false +#define ts_register_tx_event(...) +#define eth_wait_for_ptp_ts(...) +#endif /* CONFIG_PTP_CLOCK_NXP_ENET */ + +#ifdef CONFIG_PTP_CLOCK static const struct device *eth_nxp_enet_get_ptp_clock(const struct device *dev) { const struct nxp_enet_mac_config *config = dev->config; return config->ptp_clock; } - -#endif /* CONFIG_PTP_CLOCK_NXP_ENET */ +#endif /* CONFIG_PTP_CLOCK */ /* - ************************************** - * L2 Networking Driver API Functions * - ************************************** + ********************************* + * Ethernet driver API Functions * + ********************************* */ - static int eth_nxp_enet_tx(const struct device *dev, struct net_pkt *pkt) { const struct nxp_enet_mac_config *config = dev->config; struct nxp_enet_mac_data *data = dev->data; uint16_t total_len = net_pkt_get_len(pkt); - status_t status; - -#if defined(CONFIG_PTP_CLOCK_NXP_ENET) - bool timestamped_frame; -#endif + bool frame_is_timestamped; + status_t ret; /* Wait for a TX buffer descriptor to be available */ k_sem_take(&data->tx_buf_sem, K_FOREVER); @@ -264,49 +232,32 @@ static int eth_nxp_enet_tx(const struct device *dev, struct net_pkt *pkt) k_mutex_lock(&data->tx_frame_buf_mutex, K_FOREVER); /* Read network packet from upper layer into frame buffer */ - if (net_pkt_read(pkt, data->tx_frame_buf, total_len)) { + ret = net_pkt_read(pkt, data->tx_frame_buf, total_len); + if (ret) { k_sem_give(&data->tx_buf_sem); - k_mutex_unlock(&data->tx_frame_buf_mutex); - return -EIO; + goto exit; } -#if defined(CONFIG_PTP_CLOCK_NXP_ENET) - timestamped_frame = eth_get_ptp_data(net_pkt_iface(pkt), pkt); - if (timestamped_frame) { - status = ENET_SendFrame(config->base, &data->enet_handle, - data->tx_frame_buf, total_len, RING_ID, true, pkt); - if (!status) { - net_pkt_ref(pkt); - /* - * Network stack will modify the packet upon return, - * so wait for the packet to be timestamped, - * which will occur within the TX ISR, before - * returning - */ - k_sem_take(&data->ptp_ts_sem, K_FOREVER); - } + frame_is_timestamped = eth_get_ptp_data(net_pkt_iface(pkt), pkt); - } else -#endif - { - /* Send frame to ring buffer for transmit */ - status = ENET_SendFrame(config->base, &data->enet_handle, - data->tx_frame_buf, total_len, - RING_ID, false, NULL); + ret = ENET_SendFrame(config->base, &data->enet_handle, data->tx_frame_buf, + total_len, RING_ID, frame_is_timestamped, pkt); + if (ret == kStatus_Success) { + goto exit; } - if (status) { - LOG_ERR("ENET_SendFrame error: %d", (int)status); - k_mutex_unlock(&data->tx_frame_buf_mutex); - ENET_ReclaimTxDescriptor(config->base, - &data->enet_handle, RING_ID); - return -1; + if (frame_is_timestamped) { + eth_wait_for_ptp_ts(dev, pkt); + } else { + LOG_ERR("ENET_SendFrame error: %d", ret); + ENET_ReclaimTxDescriptor(config->base, &data->enet_handle, RING_ID); } +exit: /* Leave critical section for TX frame buffer access */ k_mutex_unlock(&data->tx_frame_buf_mutex); - return 0; + return ret; } static void eth_nxp_enet_iface_init(struct net_if *iface) @@ -314,11 +265,9 @@ static void eth_nxp_enet_iface_init(struct net_if *iface) const struct device *dev = net_if_get_device(iface); struct nxp_enet_mac_data *data = dev->data; const struct nxp_enet_mac_config *config = dev->config; -#if defined(CONFIG_NET_NATIVE_IPV4) || defined(CONFIG_NET_NATIVE_IPV6) static struct net_if_mcast_monitor mon; net_if_mcast_mon_register(&mon, iface, net_if_mcast_cb); -#endif /* CONFIG_NET_NATIVE_IPV4 || CONFIG_NET_NATIVE_IPV6 */ net_if_set_link_addr(iface, data->mac_addr, sizeof(data->mac_addr), @@ -335,6 +284,7 @@ static void eth_nxp_enet_iface_init(struct net_if *iface) #if defined(CONFIG_NET_DSA) dsa_register_master_tx(iface, ð_nxp_enet_tx); #endif + ethernet_init(iface); net_eth_carrier_off(data->iface); @@ -405,10 +355,6 @@ static int eth_nxp_enet_rx(const struct device *dev) status_t status; uint32_t ts; -#if defined(CONFIG_PTP_CLOCK_NXP_ENET) - enet_ptp_time_t ptp_time_data; -#endif - status = ENET_GetRxFrameSize(&data->enet_handle, (uint32_t *)&frame_length, RING_ID); if (status == kStatus_ENET_RxFrameEmpty) { @@ -424,7 +370,7 @@ static int eth_nxp_enet_rx(const struct device *dev) } if (frame_length > NET_ETH_MAX_FRAME_SIZE) { - LOG_ERR("frame too large (%d)", frame_length); + LOG_ERR("Frame too large (%d)", frame_length); goto flush; } @@ -435,76 +381,56 @@ static int eth_nxp_enet_rx(const struct device *dev) goto flush; } - /* in case multiply thread access - * we need to protect it with mutex. - */ k_mutex_lock(&data->rx_frame_buf_mutex, K_FOREVER); - status = ENET_ReadFrame(config->base, &data->enet_handle, data->rx_frame_buf, frame_length, RING_ID, &ts); + k_mutex_unlock(&data->rx_frame_buf_mutex); + if (status) { LOG_ERR("ENET_ReadFrame failed: %d", (int)status); - net_pkt_unref(pkt); - - k_mutex_unlock(&data->rx_frame_buf_mutex); goto error; } if (net_pkt_write(pkt, data->rx_frame_buf, frame_length)) { - LOG_ERR("Unable to write frame into the pkt"); - net_pkt_unref(pkt); - k_mutex_unlock(&data->rx_frame_buf_mutex); + LOG_ERR("Unable to write frame into the packet"); goto error; } - k_mutex_unlock(&data->rx_frame_buf_mutex); - -#if defined(CONFIG_NET_VLAN) - { - struct net_eth_hdr *hdr = NET_ETH_HDR(pkt); - - if (ntohs(hdr->type) == NET_ETH_PTYPE_VLAN) { - struct net_eth_vlan_hdr *hdr_vlan = - (struct net_eth_vlan_hdr *)NET_ETH_HDR(pkt); + if (IS_ENABLED(CONFIG_NET_VLAN) && ntohs(NET_ETH_HDR(pkt)->type) == NET_ETH_PTYPE_VLAN) { + struct net_eth_vlan_hdr *hdr_vlan = (struct net_eth_vlan_hdr *)NET_ETH_HDR(pkt); - net_pkt_set_vlan_tci(pkt, ntohs(hdr_vlan->vlan.tci)); - vlan_tag = net_pkt_vlan_tag(pkt); + net_pkt_set_vlan_tci(pkt, ntohs(hdr_vlan->vlan.tci)); + vlan_tag = net_pkt_vlan_tag(pkt); #if CONFIG_NET_TC_RX_COUNT > 1 - { - enum net_priority prio; + enum net_priority prio = net_vlan2priority(net_pkt_vlan_priority(pkt)); - prio = net_vlan2priority( - net_pkt_vlan_priority(pkt)); - net_pkt_set_priority(pkt, prio); - } + net_pkt_set_priority(pkt, prio); #endif /* CONFIG_NET_TC_RX_COUNT > 1 */ - } } -#endif /* CONFIG_NET_VLAN */ - /* - * Use MAC timestamp - */ #if defined(CONFIG_PTP_CLOCK_NXP_ENET) k_mutex_lock(data->ptp_mutex, K_FOREVER); + + /* Invalid value by default. */ + pkt->timestamp.nanosecond = UINT32_MAX; + pkt->timestamp.second = UINT64_MAX; + + /* Timestamp the packet using PTP clock */ if (eth_get_ptp_data(get_iface(data, vlan_tag), pkt)) { - ENET_Ptp1588GetTimer(config->base, &data->enet_handle, - &ptp_time_data); + struct net_ptp_time ptp_time; + + ptp_clock_nxp_enet_get(config->ptp_clock, &ptp_time); + /* If latest timestamp reloads after getting from Rx BD, - * then second - 1 to make sure the actual Rx timestamp is - * accurate + * then second - 1 to make sure the actual Rx timestamp is accurate */ - if (ptp_time_data.nanosecond < ts) { - ptp_time_data.second--; + if (ptp_time.nanosecond < ts) { + ptp_time.second--; } pkt->timestamp.nanosecond = ts; - pkt->timestamp.second = ptp_time_data.second; - } else { - /* Invalid value. */ - pkt->timestamp.nanosecond = UINT32_MAX; - pkt->timestamp.second = UINT64_MAX; + pkt->timestamp.second = ptp_time.second; } k_mutex_unlock(data->ptp_mutex); #endif /* CONFIG_PTP_CLOCK_NXP_ENET */ @@ -514,7 +440,6 @@ static int eth_nxp_enet_rx(const struct device *dev) iface = dsa_net_recv(iface, &pkt); #endif if (net_recv_data(iface, pkt) < 0) { - net_pkt_unref(pkt); goto error; } @@ -528,6 +453,7 @@ static int eth_nxp_enet_rx(const struct device *dev) 0, RING_ID, NULL); __ASSERT_NO_MSG(status == kStatus_Success); error: + net_pkt_unref(pkt); eth_stats_update_errors_rx(get_iface(data, vlan_tag)); return -EIO; } @@ -558,7 +484,7 @@ static void eth_nxp_enet_rx_thread(void *arg1, void *unused1, void *unused2) static int nxp_enet_phy_reset_and_configure(const struct device *phy) { - int ret = 0; + int ret; /* Reset the PHY */ ret = phy_write(phy, MII_BMCR, MII_BMCR_RESET); @@ -570,15 +496,8 @@ static int nxp_enet_phy_reset_and_configure(const struct device *phy) k_busy_wait(500000); /* Configure the PHY */ - ret = phy_configure_link(phy, LINK_HALF_10BASE_T | - LINK_FULL_10BASE_T | - LINK_HALF_100BASE_T | - LINK_FULL_100BASE_T); - if (ret) { - return ret; - } - - return ret; + return phy_configure_link(phy, LINK_HALF_10BASE_T | LINK_FULL_10BASE_T | + LINK_HALF_100BASE_T | LINK_FULL_100BASE_T); } static void nxp_enet_phy_cb(const struct device *phy, @@ -627,20 +546,14 @@ static int nxp_enet_phy_init(const struct device *dev) **************************** */ -void nxp_enet_driver_cb(const struct device *dev, - enum nxp_enet_driver dev_type, - enum nxp_enet_callback_reason event, - void *data) +void nxp_enet_driver_cb(const struct device *dev, enum nxp_enet_driver dev_type, + enum nxp_enet_callback_reason event, void *data) { if (dev_type == NXP_ENET_MDIO) { nxp_enet_mdio_callback(dev, event, data); - } - -#ifdef CONFIG_PTP_CLOCK_NXP_ENET - if (dev_type == NXP_ENET_PTP_CLOCK) { + } else if (dev_type == NXP_ENET_PTP_CLOCK) { nxp_enet_ptp_clock_callback(dev, event, data); } -#endif } static void eth_callback(ENET_Type *base, enet_handle_t *handle, @@ -658,9 +571,7 @@ static void eth_callback(ENET_Type *base, enet_handle_t *handle, k_sem_give(&data->rx_thread_sem); break; case kENET_TxEvent: -#if defined(CONFIG_PTP_CLOCK_NXP_ENET) && defined(CONFIG_NET_L2_PTP) ts_register_tx_event(dev, frameinfo); -#endif /* Free the TX buffer. */ k_sem_give(&data->tx_buf_sem); break; @@ -681,6 +592,12 @@ static void eth_callback(ENET_Type *base, enet_handle_t *handle, } } +#if FSL_FEATURE_ENET_QUEUE > 1 +#define ENET_IRQ_HANDLER_ARGS(base, handle) base, handle, 0 +#else +#define ENET_IRQ_HANDLER_ARGS(base, handle) base, handle +#endif /* FSL_FEATURE_ENET_QUEUE > 1 */ + static void eth_nxp_enet_isr(const struct device *dev) { const struct nxp_enet_mac_config *config = dev->config; @@ -690,22 +607,13 @@ static void eth_nxp_enet_isr(const struct device *dev) uint32_t eir = ENET_GetInterruptStatus(config->base); if (eir & (kENET_RxBufferInterrupt | kENET_RxFrameInterrupt)) { -#if FSL_FEATURE_ENET_QUEUE > 1 - /* Only use ring 0 in this driver */ - ENET_ReceiveIRQHandler(config->base, &data->enet_handle, 0); -#else - ENET_ReceiveIRQHandler(config->base, &data->enet_handle); -#endif - ENET_DisableInterrupts(config->base, kENET_RxFrameInterrupt | - kENET_RxBufferInterrupt); + ENET_ReceiveIRQHandler(ENET_IRQ_HANDLER_ARGS(config->base, &data->enet_handle)); + ENET_DisableInterrupts(config->base, + kENET_RxFrameInterrupt | kENET_RxBufferInterrupt); } if (eir & kENET_TxFrameInterrupt) { -#if FSL_FEATURE_ENET_QUEUE > 1 - ENET_TransmitIRQHandler(config->base, &data->enet_handle, 0); -#else - ENET_TransmitIRQHandler(config->base, &data->enet_handle); -#endif + ENET_TransmitIRQHandler(ENET_IRQ_HANDLER_ARGS(config->base, &data->enet_handle)); } if (eir & kENET_TxBufferInterrupt) { @@ -714,14 +622,12 @@ static void eth_nxp_enet_isr(const struct device *dev) } if (eir & ENET_EIR_MII_MASK) { - /* Callback to MDIO driver for relevant interrupt */ nxp_enet_driver_cb(config->mdio, NXP_ENET_MDIO, NXP_ENET_INTERRUPT, NULL); } irq_unlock(irq_lock_key); } - /* ****************** * Initialization * @@ -781,12 +687,12 @@ static int eth_nxp_enet_init(const struct device *dev) enet_config.macSpecialConfig |= kENET_ControlVLANTagEnable; } -#if defined(CONFIG_ETH_NXP_ENET_HW_ACCELERATION) - enet_config.txAccelerConfig |= - kENET_TxAccelIpCheckEnabled | kENET_TxAccelProtoCheckEnabled; - enet_config.rxAccelerConfig |= - kENET_RxAccelIpCheckEnabled | kENET_RxAccelProtoCheckEnabled; -#endif + if (IS_ENABLED(CONFIG_ETH_NXP_ENET_HW_ACCELERATION)) { + enet_config.txAccelerConfig |= + kENET_TxAccelIpCheckEnabled | kENET_TxAccelProtoCheckEnabled; + enet_config.rxAccelerConfig |= + kENET_RxAccelIpCheckEnabled | kENET_RxAccelProtoCheckEnabled; + } enet_config.interrupt |= kENET_RxFrameInterrupt; enet_config.interrupt |= kENET_TxFrameInterrupt; @@ -833,16 +739,19 @@ static int eth_nxp_enet_init(const struct device *dev) return 0; } +#ifdef CONFIG_NET_DSA +#define NXP_ENET_SEND_FUNC dsa_tx +#else +#define NXP_ENET_SEND_FUNC eth_nxp_enet_tx +#endif /* CONFIG_NET_DSA */ + static const struct ethernet_api api_funcs = { .iface_api.init = eth_nxp_enet_iface_init, -#if defined(CONFIG_PTP_CLOCK_NXP_ENET) - .get_ptp_clock = eth_nxp_enet_get_ptp_clock, -#endif .get_capabilities = eth_nxp_enet_get_capabilities, .set_config = eth_nxp_enet_set_config, - .send = eth_nxp_enet_tx, -#if defined(CONFIG_NET_DSA) - .send = dsa_tx, + .send = NXP_ENET_SEND_FUNC, +#if defined(CONFIG_PTP_CLOCK) + .get_ptp_clock = eth_nxp_enet_get_ptp_clock, #endif }; @@ -926,7 +835,6 @@ static const struct ethernet_api api_funcs = { #if DT_NODE_HAS_STATUS(DT_CHOSEN(zephyr_dtcm), okay) && \ CONFIG_ETH_NXP_ENET_USE_DTCM_FOR_DMA_BUFFER -/* Use DTCM for hardware DMA buffers */ #define _nxp_enet_dma_desc_section __dtcm_bss_section #define _nxp_enet_dma_buffer_section __dtcm_noinit_section #define _nxp_enet_driver_buffer_section __dtcm_noinit_section @@ -940,9 +848,9 @@ static const struct ethernet_api api_funcs = { #define _nxp_enet_driver_buffer_section #endif - /* Use ENET_FRAME_MAX_VLANFRAMELEN for VLAN frame size - * Use ENET_FRAME_MAX_FRAMELEN for Ethernet frame size - */ +/* Use ENET_FRAME_MAX_VLANFRAMELEN for VLAN frame size + * Use ENET_FRAME_MAX_FRAMELEN for Ethernet frame size + */ #if defined(CONFIG_NET_VLAN) #if !defined(ENET_FRAME_MAX_VLANFRAMELEN) #define ENET_FRAME_MAX_VLANFRAMELEN (ENET_FRAME_MAX_FRAMELEN + 4) @@ -1051,11 +959,9 @@ static const struct ethernet_api api_funcs = { DT_INST_FOREACH_STATUS_OKAY(NXP_ENET_MAC_INIT) - /* * ENET module-level management */ - #undef DT_DRV_COMPAT #define DT_DRV_COMPAT nxp_enet diff --git a/include/zephyr/drivers/ethernet/eth_nxp_enet.h b/include/zephyr/drivers/ethernet/eth_nxp_enet.h index 5fc5564b328..767acbea09e 100644 --- a/include/zephyr/drivers/ethernet/eth_nxp_enet.h +++ b/include/zephyr/drivers/ethernet/eth_nxp_enet.h @@ -44,9 +44,13 @@ extern void nxp_enet_mdio_callback(const struct device *mdio_dev, enum nxp_enet_callback_reason event, void *data); +#ifdef CONFIG_PTP_CLOCK_NXP_ENET extern void nxp_enet_ptp_clock_callback(const struct device *dev, enum nxp_enet_callback_reason event, void *data); +#else +#define nxp_enet_ptp_clock_callback(...) +#endif /* * Internal implementation, inter-driver communication function From 28445d62c6018aef587813bc6ee237e2dc353321 Mon Sep 17 00:00:00 2001 From: Anas Nashif Date: Tue, 12 Dec 2023 02:29:57 +0000 Subject: [PATCH 1227/3723] soc: intel_adsp: share adsp_imr_layout.h across SoC generations This header is shared across all ace intel_adsp platforms, so move it to a common place. Signed-off-by: Anas Nashif --- .../{intel_ace15_mtpm => }/adsp_imr_layout.h | 0 .../include/intel_ace20_lnl/adsp_imr_layout.h | 38 ------------------- 2 files changed, 38 deletions(-) rename soc/xtensa/intel_adsp/ace/include/{intel_ace15_mtpm => }/adsp_imr_layout.h (100%) delete mode 100644 soc/xtensa/intel_adsp/ace/include/intel_ace20_lnl/adsp_imr_layout.h diff --git a/soc/xtensa/intel_adsp/ace/include/intel_ace15_mtpm/adsp_imr_layout.h b/soc/xtensa/intel_adsp/ace/include/adsp_imr_layout.h similarity index 100% rename from soc/xtensa/intel_adsp/ace/include/intel_ace15_mtpm/adsp_imr_layout.h rename to soc/xtensa/intel_adsp/ace/include/adsp_imr_layout.h diff --git a/soc/xtensa/intel_adsp/ace/include/intel_ace20_lnl/adsp_imr_layout.h b/soc/xtensa/intel_adsp/ace/include/intel_ace20_lnl/adsp_imr_layout.h deleted file mode 100644 index 6e953991a81..00000000000 --- a/soc/xtensa/intel_adsp/ace/include/intel_ace20_lnl/adsp_imr_layout.h +++ /dev/null @@ -1,38 +0,0 @@ -/* Copyright (c) 2022 Intel Corporation - * SPDX-License-Identifier: Apache-2.0 - */ -#ifndef ZEPHYR_SOC_INTEL_ADSP_ACE_IMR_LAYOUT_H_ -#define ZEPHYR_SOC_INTEL_ADSP_ACE_IMR_LAYOUT_H_ - -/* These structs and macros are from from the ROM code header - * on cAVS platforms, please keep them immutable - */ - -/* - * A magic that tells ROM to jump to imr_restore_vector instead of normal boot - */ -#define ADSP_IMR_MAGIC_VALUE 0x02468ACE -#define IMR_LAYOUT_OFFSET 0x20000 -#define IMR_LAYOUT_ADDRESS (L3_MEM_BASE_ADDR + IMR_LAYOUT_OFFSET) - -struct imr_header { - uint32_t adsp_imr_magic; - uint32_t structure_version; - uint32_t structure_size; - uint32_t imr_state; - uint32_t imr_size; - void *imr_restore_vector; - void *imr_auth_api_vector; - uint8_t *imr_ram_storage; -}; - -struct imr_state { - struct imr_header header; - uint8_t reserved[0x1000 - sizeof(struct imr_header)]; -}; - -struct imr_layout { - struct imr_state imr_state; -}; - -#endif /* ZEPHYR_SOC_INTEL_ADSP_ACE_IMR_LAYOUT_H_ */ From cc4ffb2a54bd136095100c899f1b875fd1ce6f9d Mon Sep 17 00:00:00 2001 From: Andrej Butok Date: Tue, 12 Dec 2023 12:50:10 +0100 Subject: [PATCH 1228/3723] kernel: cmake: fix k_sleep compilation error for single thread Fix k_sleep compilation error: [build] ... syscalls/kernel.h:135: undefined reference to `z_impl_k_sleep' for single thread applications (CONFIG_MULTITHREADING = n). The shed.c contains source code which must be present also in single thread applications. Signed-off-by: Andrej Butok --- kernel/CMakeLists.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/kernel/CMakeLists.txt b/kernel/CMakeLists.txt index bec410968cc..5e55b05be61 100644 --- a/kernel/CMakeLists.txt +++ b/kernel/CMakeLists.txt @@ -59,6 +59,7 @@ list(APPEND kernel_files mem_slab.c thread.c version.c + sched.c ) if(CONFIG_MULTITHREADING) @@ -72,7 +73,6 @@ list(APPEND kernel_files stack.c system_work_q.c work.c - sched.c condvar.c ) From 7da776809506bcb7fb825a7f79c492de8dbbe8ff Mon Sep 17 00:00:00 2001 From: Anas Nashif Date: Tue, 12 Dec 2023 07:46:13 -0500 Subject: [PATCH 1229/3723] cmake: remove deprecated XCC_USE_CLANG This was deprecated in 3.0, so remove it now and remove all docs related to it. Signed-off-by: Anas Nashif --- cmake/modules/FindDeprecated.cmake | 20 -------------------- cmake/modules/FindHostTools.cmake | 2 +- doc/develop/toolchains/cadence_xcc.rst | 4 ---- 3 files changed, 1 insertion(+), 25 deletions(-) diff --git a/cmake/modules/FindDeprecated.cmake b/cmake/modules/FindDeprecated.cmake index f80d3419861..875f243b034 100644 --- a/cmake/modules/FindDeprecated.cmake +++ b/cmake/modules/FindDeprecated.cmake @@ -37,26 +37,6 @@ if("${Deprecated_FIND_COMPONENTS}" STREQUAL "") message(WARNING "find_package(Deprecated) missing required COMPONENTS keyword") endif() -if("XCC_USE_CLANG" IN_LIST Deprecated_FIND_COMPONENTS) - list(REMOVE_ITEM Deprecated_FIND_COMPONENTS XCC_USE_CLANG) - # This code was deprecated after Zephyr v3.0.0 - # Keep XCC_USE_CLANG behaviour for a while. - if(NOT DEFINED ZEPHYR_TOOLCHAIN_VARIANT) - set(ZEPHYR_TOOLCHAIN_VARIANT $ENV{ZEPHYR_TOOLCHAIN_VARIANT}) - endif() - - if ("${ZEPHYR_TOOLCHAIN_VARIANT}" STREQUAL "xcc" - AND "$ENV{XCC_USE_CLANG}" STREQUAL "1") - set(ZEPHYR_TOOLCHAIN_VARIANT xt-clang CACHE STRING "Zephyr toolchain variant" FORCE) - message(DEPRECATION "XCC_USE_CLANG is deprecated. Please set ZEPHYR_TOOLCHAIN_VARIANT to 'xt-clang'") - endif() - - if("${ZEPHYR_TOOLCHAIN_VARIANT}" STREQUAL "xcc-clang") - set(ZEPHYR_TOOLCHAIN_VARIANT xt-clang CACHE STRING "Zephyr toolchain variant" FORCE) - message(DEPRECATION "ZEPHYR_TOOLCHAIN_VARIANT 'xcc-clang' is deprecated. Please set ZEPHYR_TOOLCHAIN_VARIANT to 'xt-clang'") - endif() -endif() - if("CROSS_COMPILE" IN_LIST Deprecated_FIND_COMPONENTS) list(REMOVE_ITEM Deprecated_FIND_COMPONENTS CROSS_COMPILE) # This code was deprecated after Zephyr v3.1.0 diff --git a/cmake/modules/FindHostTools.cmake b/cmake/modules/FindHostTools.cmake index 82225b49e56..b2d5257642d 100644 --- a/cmake/modules/FindHostTools.cmake +++ b/cmake/modules/FindHostTools.cmake @@ -48,7 +48,7 @@ if(HostTools_FOUND) return() endif() -find_package(Deprecated COMPONENTS XCC_USE_CLANG CROSS_COMPILE) +find_package(Deprecated COMPONENTS CROSS_COMPILE) find_package(Zephyr-sdk 0.16) diff --git a/doc/develop/toolchains/cadence_xcc.rst b/doc/develop/toolchains/cadence_xcc.rst index 5778c542068..f1de7ed1e53 100644 --- a/doc/develop/toolchains/cadence_xcc.rst +++ b/doc/develop/toolchains/cadence_xcc.rst @@ -68,7 +68,3 @@ Cadence Tensilica Xtensa C/C++ Compiler (XCC) # Linux export XCC_NO_G_FLAG=1 - - * Also note that setting :envvar:`XCC_USE_CLANG` to ``1`` and - :envvar:`ZEPHYR_TOOLCHAIN_VARIANT` to ``xcc`` is deprecated. - Set :envvar:`ZEPHYR_TOOLCHAIN_VARIANT` to ``xt-clang`` instead. From 733b81d2c79fe17ca993ce9875f6790f7b756459 Mon Sep 17 00:00:00 2001 From: Alessio Lei Date: Tue, 12 Dec 2023 14:28:20 +0100 Subject: [PATCH 1230/3723] drivers: modem: remove dependency of modem_socket Fixed Kconfig to remove dependency between modem_socket and modem_context, the two do not depend on each other and should be possible to use independently Signed-off-by: Alessio Lei --- drivers/modem/Kconfig | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/modem/Kconfig b/drivers/modem/Kconfig index c233d5db821..02e3557918f 100644 --- a/drivers/modem/Kconfig +++ b/drivers/modem/Kconfig @@ -142,6 +142,8 @@ config MODEM_CMD_HANDLER_MAX_PARAM_COUNT of the match_buf (match_buf_len) field as it needs to be large enough to hold a single line of data (ending with /r). +endif # MODEM_CONTEXT + config MODEM_SOCKET bool "Generic modem socket support layer" help @@ -165,8 +167,6 @@ config MODEM_SOCKET_PACKET_COUNT these values are organized into "packets". This setting limits the maximum number of packet sizes the socket can keep track of. -endif # MODEM_CONTEXT - config MODEM_SHELL bool "Modem shell utilities" select SHELL From 1cb80d328239f82cb22c0b1904ca655718471a95 Mon Sep 17 00:00:00 2001 From: Mariusz Skamra Date: Fri, 4 Aug 2023 13:34:52 +0200 Subject: [PATCH 1231/3723] Bluetooth: audio: has_client: Use CONTAINER_OF to get client instance This starts using CONTAINER_OF macro instead of inst_by_conn function wherever possible. It's better approach as the client instance is a container for parameters passed to the callbacks. Signed-off-by: Mariusz Skamra --- subsys/bluetooth/audio/has_client.c | 66 +++++++---------------------- 1 file changed, 15 insertions(+), 51 deletions(-) diff --git a/subsys/bluetooth/audio/has_client.c b/subsys/bluetooth/audio/has_client.c index 77f40d48bd5..c5bd983ce9a 100644 --- a/subsys/bluetooth/audio/has_client.c +++ b/subsys/bluetooth/audio/has_client.c @@ -223,9 +223,9 @@ static uint8_t control_point_notify_cb(struct bt_conn *conn, struct bt_gatt_subscribe_params *params, const void *data, uint16_t len) { + struct has_inst *inst = CONTAINER_OF(params, struct has_inst, control_point_subscription); const struct bt_has_cp_hdr *hdr; struct net_buf_simple buf; - struct has_inst *inst; LOG_DBG("conn %p params %p data %p len %u", (void *)conn, params, data, len); @@ -239,12 +239,6 @@ static uint8_t control_point_notify_cb(struct bt_conn *conn, return BT_GATT_ITER_STOP; } - inst = inst_by_conn(conn); - if (!inst) { - /* Ignore notification from unknown instance */ - return BT_GATT_ITER_STOP; - } - if (len < sizeof(*hdr)) { /* Ignore malformed notification */ return BT_GATT_ITER_CONTINUE; } @@ -309,9 +303,7 @@ static int cp_write(struct has_inst *inst, struct net_buf_simple *buf, bt_gatt_w static void read_presets_req_cb(struct bt_conn *conn, uint8_t err, struct bt_gatt_write_params *params) { - struct has_inst *inst = inst_by_conn(conn); - - __ASSERT(inst, "no instance for conn %p", (void *)conn); + struct has_inst *inst = CONTAINER_OF(params, struct has_inst, params.write); LOG_DBG("conn %p err 0x%02x param %p", (void *)conn, err, params); @@ -344,9 +336,7 @@ static int read_presets_req(struct has_inst *inst, uint8_t start_index, uint8_t static void set_active_preset_cb(struct bt_conn *conn, uint8_t err, struct bt_gatt_write_params *params) { - struct has_inst *inst = inst_by_conn(conn); - - __ASSERT(inst, "no instance for conn %p", (void *)conn); + struct has_inst *inst = CONTAINER_OF(params, struct has_inst, params.write); LOG_DBG("conn %p err 0x%02x param %p", (void *)conn, err, params); @@ -406,7 +396,7 @@ static uint8_t active_preset_notify_cb(struct bt_conn *conn, struct bt_gatt_subscribe_params *params, const void *data, uint16_t len) { - struct has_inst *inst; + struct has_inst *inst = CONTAINER_OF(params, struct has_inst, active_index_subscription); uint8_t prev; LOG_DBG("conn %p params %p data %p len %u", (void *)conn, params, data, len); @@ -423,12 +413,6 @@ static uint8_t active_preset_notify_cb(struct bt_conn *conn, return BT_GATT_ITER_STOP; } - inst = inst_by_conn(conn); - if (!inst) { - /* Ignore notification from unknown instance */ - return BT_GATT_ITER_STOP; - } - if (len == 0) { /* Ignore empty notification */ return BT_GATT_ITER_CONTINUE; @@ -453,9 +437,7 @@ static uint8_t active_preset_notify_cb(struct bt_conn *conn, static void active_index_subscribe_cb(struct bt_conn *conn, uint8_t att_err, struct bt_gatt_subscribe_params *params) { - struct has_inst *inst = inst_by_conn(conn); - - __ASSERT(inst, "no instance for conn %p", (void *)conn); + struct has_inst *inst = CONTAINER_OF(params, struct has_inst, active_index_subscription); LOG_DBG("conn %p att_err 0x%02x params %p", (void *)inst->conn, att_err, params); @@ -489,11 +471,9 @@ static uint8_t active_index_read_cb(struct bt_conn *conn, uint8_t att_err, struct bt_gatt_read_params *params, const void *data, uint16_t len) { - struct has_inst *inst = inst_by_conn(conn); + struct has_inst *inst = CONTAINER_OF(params, struct has_inst, params.read); int err = att_err; - __ASSERT(inst, "no instance for conn %p", (void *)conn); - LOG_DBG("conn %p att_err 0x%02x params %p data %p len %u", (void *)conn, att_err, params, data, len); @@ -538,13 +518,11 @@ static int active_index_read(struct has_inst *inst) } static void control_point_subscribe_cb(struct bt_conn *conn, uint8_t att_err, - struct bt_gatt_subscribe_params *subscribe) + struct bt_gatt_subscribe_params *params) { - struct has_inst *inst = inst_by_conn(conn); + struct has_inst *inst = CONTAINER_OF(params, struct has_inst, control_point_subscription); int err = att_err; - __ASSERT(inst, "no instance for conn %p", (void *)conn); - LOG_DBG("conn %p att_err 0x%02x", (void *)inst->conn, att_err); if (att_err != BT_ATT_ERR_SUCCESS) { @@ -591,13 +569,11 @@ static int control_point_subscribe(struct has_inst *inst, uint16_t value_handle, static uint8_t control_point_discover_cb(struct bt_conn *conn, const struct bt_gatt_attr *attr, struct bt_gatt_discover_params *params) { - struct has_inst *inst = inst_by_conn(conn); + struct has_inst *inst = CONTAINER_OF(params, struct has_inst, params.discover); const struct bt_gatt_chrc *chrc; int err; - __ASSERT(inst, "no instance for conn %p", (void *)conn); - - LOG_DBG("conn %p attr %p params %p", (void *)inst->conn, attr, params); + LOG_DBG("conn %p attr %p params %p", (void *)conn, attr, params); if (!attr) { LOG_INF("Control Point not found"); @@ -651,11 +627,9 @@ static void features_update(struct has_inst *inst, const void *data, uint16_t le static uint8_t features_read_cb(struct bt_conn *conn, uint8_t att_err, struct bt_gatt_read_params *params, const void *data, uint16_t len) { - struct has_inst *inst = inst_by_conn(conn); + struct has_inst *inst = CONTAINER_OF(params, struct has_inst, params.read); int err = att_err; - __ASSERT(inst, "no instance for conn %p", (void *)conn); - LOG_DBG("conn %p att_err 0x%02x params %p data %p len %u", (void *)conn, att_err, params, data, len); @@ -705,12 +679,10 @@ static int features_read(struct has_inst *inst, uint16_t value_handle) static void features_subscribe_cb(struct bt_conn *conn, uint8_t att_err, struct bt_gatt_subscribe_params *params) { - struct has_inst *inst = inst_by_conn(conn); + struct has_inst *inst = CONTAINER_OF(params, struct has_inst, features_subscription); int err = att_err; - __ASSERT(inst, "no instance for conn %p", (void *)conn); - - LOG_DBG("conn %p att_err 0x%02x params %p", (void *)inst->conn, att_err, params); + LOG_DBG("conn %p att_err 0x%02x params %p", (void *)conn, att_err, params); if (att_err != BT_ATT_ERR_SUCCESS) { goto fail; @@ -734,7 +706,7 @@ static void features_subscribe_cb(struct bt_conn *conn, uint8_t att_err, static uint8_t features_notify_cb(struct bt_conn *conn, struct bt_gatt_subscribe_params *params, const void *data, uint16_t len) { - struct has_inst *inst; + struct has_inst *inst = CONTAINER_OF(params, struct has_inst, features_subscription); LOG_DBG("conn %p params %p data %p len %u", (void *)conn, params, data, len); @@ -750,12 +722,6 @@ static uint8_t features_notify_cb(struct bt_conn *conn, struct bt_gatt_subscribe return BT_GATT_ITER_STOP; } - inst = inst_by_conn(conn); - if (!inst) { - /* Ignore notification from unknown instance */ - return BT_GATT_ITER_STOP; - } - if (len == 0) { /* Ignore empty notification */ return BT_GATT_ITER_CONTINUE; @@ -785,12 +751,10 @@ static int features_subscribe(struct has_inst *inst, uint16_t value_handle) static uint8_t features_discover_cb(struct bt_conn *conn, const struct bt_gatt_attr *attr, struct bt_gatt_discover_params *params) { - struct has_inst *inst = inst_by_conn(conn); + struct has_inst *inst = CONTAINER_OF(params, struct has_inst, params.discover); const struct bt_gatt_chrc *chrc; int err; - __ASSERT(inst, "no instance for conn %p", (void *)conn); - LOG_DBG("conn %p attr %p params %p", (void *)conn, attr, params); if (!attr) { From 044e2d6bff83d298286e6753a9e2ad60d16ec320 Mon Sep 17 00:00:00 2001 From: Anas Nashif Date: Mon, 11 Dec 2023 13:32:43 -0500 Subject: [PATCH 1232/3723] arch: make CONFIG_EXCEPTION_DEBUG cross arch config Define CONFIG_EXCEPTION_DEBUG globally and remove architecture specific definition of config. Signed-off-by: Anas Nashif --- arch/Kconfig | 10 ++++++++++ arch/arc/Kconfig | 9 --------- arch/arc/core/fatal.c | 6 +++--- arch/arc/core/fault.c | 6 +++--- arch/arm64/core/Kconfig | 9 --------- arch/x86/Kconfig | 10 ---------- boards/arc/nsim/nsim_em11d_defconfig | 1 - boards/arc/nsim/nsim_em7d_v22_defconfig | 1 - boards/arc/nsim/nsim_em_defconfig | 1 - boards/arc/nsim/nsim_hs3x_hostlink_defconfig | 1 - boards/arc/nsim/nsim_hs5x_defconfig | 1 - boards/arc/nsim/nsim_hs5x_smp_12cores_defconfig | 1 - boards/arc/nsim/nsim_hs5x_smp_defconfig | 1 - boards/arc/nsim/nsim_hs6x_defconfig | 1 - boards/arc/nsim/nsim_hs6x_smp_12cores_defconfig | 1 - boards/arc/nsim/nsim_hs6x_smp_defconfig | 1 - boards/arc/nsim/nsim_hs_defconfig | 1 - boards/arc/nsim/nsim_hs_flash_xip_defconfig | 1 - boards/arc/nsim/nsim_hs_mpuv6_defconfig | 1 - boards/arc/nsim/nsim_hs_smp_defconfig | 1 - boards/arc/nsim/nsim_hs_sram_defconfig | 1 - boards/arc/nsim/nsim_sem_defconfig | 1 - boards/arc/nsim/nsim_sem_mpu_stack_guard_defconfig | 1 - boards/arc/nsim/nsim_vpx5_defconfig | 1 - .../arc_secure_services/nsim_sem_normal_defconfig | 1 - tests/arch/x86/pagetables/prj.conf | 1 - 26 files changed, 16 insertions(+), 54 deletions(-) diff --git a/arch/Kconfig b/arch/Kconfig index bc99f789014..8130d3fa6a8 100644 --- a/arch/Kconfig +++ b/arch/Kconfig @@ -514,6 +514,16 @@ config IRQ_OFFLOAD_NESTED synchronous nested interrupt on the current CPU. Not all hardware is capable. +config EXCEPTION_DEBUG + bool "Unhandled exception debugging" + default y + depends on PRINTK || LOG + help + Install handlers for various CPU exception/trap vectors to + make debugging them easier, at a small expense in code size. + This prints out the specific exception vector and any associated + error codes. + config EXTRA_EXCEPTION_INFO bool "Collect extra exception info" depends on ARCH_HAS_EXTRA_EXCEPTION_INFO diff --git a/arch/arc/Kconfig b/arch/arc/Kconfig index ce23b12aa1d..b9e59adc498 100644 --- a/arch/arc/Kconfig +++ b/arch/arc/Kconfig @@ -376,15 +376,6 @@ config ARC_EXCEPTION_STACK_SIZE endmenu -config ARC_EXCEPTION_DEBUG - bool "Unhandled exception debugging information" - default n - depends on PRINTK || LOG - help - Print human-readable information about exception vectors, cause codes, - and parameters, at a cost of code/data size for the human-readable - strings. - config ARC_EARLY_SOC_INIT bool "Make early stage SoC-specific initialization" help diff --git a/arch/arc/core/fatal.c b/arch/arc/core/fatal.c index 22205a0834d..346a04062c1 100644 --- a/arch/arc/core/fatal.c +++ b/arch/arc/core/fatal.c @@ -21,7 +21,7 @@ LOG_MODULE_DECLARE(os, CONFIG_KERNEL_LOG_LEVEL); -#ifdef CONFIG_ARC_EXCEPTION_DEBUG +#ifdef CONFIG_EXCEPTION_DEBUG static void dump_arc_esf(const z_arch_esf_t *esf) { LOG_ERR(" r0: 0x%" PRIxPTR " r1: 0x%" PRIxPTR " r2: 0x%" PRIxPTR " r3: 0x%" PRIxPTR "", @@ -42,11 +42,11 @@ static void dump_arc_esf(const z_arch_esf_t *esf) void z_arc_fatal_error(unsigned int reason, const z_arch_esf_t *esf) { -#ifdef CONFIG_ARC_EXCEPTION_DEBUG +#ifdef CONFIG_EXCEPTION_DEBUG if (esf != NULL) { dump_arc_esf(esf); } -#endif /* CONFIG_ARC_EXCEPTION_DEBUG */ +#endif /* CONFIG_EXCEPTION_DEBUG */ z_fatal_error(reason, esf); } diff --git a/arch/arc/core/fault.c b/arch/arc/core/fault.c index 9e0ddaf7ed9..caa12326b9d 100644 --- a/arch/arc/core/fault.c +++ b/arch/arc/core/fault.c @@ -104,7 +104,7 @@ static bool z_check_thread_stack_fail(const uint32_t fault_addr, uint32_t sp) } #endif -#ifdef CONFIG_ARC_EXCEPTION_DEBUG +#ifdef CONFIG_EXCEPTION_DEBUG /* For EV_ProtV, the numbering/semantics of the parameter are consistent across * several codes, although not all combination will be reported. * @@ -335,7 +335,7 @@ static void dump_exception_info(uint32_t vector, uint32_t cause, uint32_t parame break; } } -#endif /* CONFIG_ARC_EXCEPTION_DEBUG */ +#endif /* CONFIG_EXCEPTION_DEBUG */ /* * @brief Fault handler @@ -387,7 +387,7 @@ void _Fault(z_arch_esf_t *esf, uint32_t old_sp) LOG_ERR("***** Exception vector: 0x%x, cause code: 0x%x, parameter 0x%x", vector, cause, parameter); LOG_ERR("Address 0x%x", exc_addr); -#ifdef CONFIG_ARC_EXCEPTION_DEBUG +#ifdef CONFIG_EXCEPTION_DEBUG dump_exception_info(vector, cause, parameter); #endif diff --git a/arch/arm64/core/Kconfig b/arch/arm64/core/Kconfig index fd74a526416..8f09d49a04c 100644 --- a/arch/arm64/core/Kconfig +++ b/arch/arm64/core/Kconfig @@ -253,15 +253,6 @@ config ARM_MMU help Memory Management Unit support. -config EXCEPTION_DEBUG - bool "Unhandled exception debugging information" - default y - depends on LOG - help - Print human-readable information about exception vectors, cause codes, - and parameters, at a cost of code/data size for the human-readable - strings. - config XIP select AARCH64_IMAGE_HEADER diff --git a/arch/x86/Kconfig b/arch/x86/Kconfig index 13030d26a1d..ae7fdef2f77 100644 --- a/arch/x86/Kconfig +++ b/arch/x86/Kconfig @@ -292,16 +292,6 @@ config MULTIBOOT_MEMMAP endif # MULTIBOOT -config EXCEPTION_DEBUG - bool "Unhandled exception debugging" - default y - depends on LOG - help - Install handlers for various CPU exception/trap vectors to - make debugging them easier, at a small expense in code size. - This prints out the specific exception vector and any associated - error codes. - config X86_VERY_EARLY_CONSOLE bool "Support very early boot printk" depends on PRINTK diff --git a/boards/arc/nsim/nsim_em11d_defconfig b/boards/arc/nsim/nsim_em11d_defconfig index 49b4b4be58d..494ff760838 100644 --- a/boards/arc/nsim/nsim_em11d_defconfig +++ b/boards/arc/nsim/nsim_em11d_defconfig @@ -12,5 +12,4 @@ CONFIG_ARC_MPU_ENABLE=y CONFIG_CONSOLE=y CONFIG_UART_CONSOLE=y CONFIG_SERIAL=y -CONFIG_ARC_EXCEPTION_DEBUG=y CONFIG_ARC_USE_UNALIGNED_MEM_ACCESS=y diff --git a/boards/arc/nsim/nsim_em7d_v22_defconfig b/boards/arc/nsim/nsim_em7d_v22_defconfig index 6f44addd50b..0a6d7ad5e4c 100644 --- a/boards/arc/nsim/nsim_em7d_v22_defconfig +++ b/boards/arc/nsim/nsim_em7d_v22_defconfig @@ -12,5 +12,4 @@ CONFIG_ARC_MPU_ENABLE=y CONFIG_CONSOLE=y CONFIG_UART_CONSOLE=y CONFIG_SERIAL=y -CONFIG_ARC_EXCEPTION_DEBUG=y CONFIG_ARC_USE_UNALIGNED_MEM_ACCESS=y diff --git a/boards/arc/nsim/nsim_em_defconfig b/boards/arc/nsim/nsim_em_defconfig index f55dce20517..263c5b27af5 100644 --- a/boards/arc/nsim/nsim_em_defconfig +++ b/boards/arc/nsim/nsim_em_defconfig @@ -12,5 +12,4 @@ CONFIG_ARC_MPU_ENABLE=y CONFIG_CONSOLE=y CONFIG_UART_CONSOLE=y CONFIG_SERIAL=y -CONFIG_ARC_EXCEPTION_DEBUG=y CONFIG_ARC_USE_UNALIGNED_MEM_ACCESS=y diff --git a/boards/arc/nsim/nsim_hs3x_hostlink_defconfig b/boards/arc/nsim/nsim_hs3x_hostlink_defconfig index 92ca6763a59..eddd5076c65 100644 --- a/boards/arc/nsim/nsim_hs3x_hostlink_defconfig +++ b/boards/arc/nsim/nsim_hs3x_hostlink_defconfig @@ -11,5 +11,4 @@ CONFIG_ARCV2_TIMER=y CONFIG_CONSOLE=y CONFIG_UART_CONSOLE=y CONFIG_SERIAL=y -CONFIG_ARC_EXCEPTION_DEBUG=y CONFIG_ARC_MPU_ENABLE=y diff --git a/boards/arc/nsim/nsim_hs5x_defconfig b/boards/arc/nsim/nsim_hs5x_defconfig index f87e1dfdcba..03c5f678869 100644 --- a/boards/arc/nsim/nsim_hs5x_defconfig +++ b/boards/arc/nsim/nsim_hs5x_defconfig @@ -12,4 +12,3 @@ CONFIG_ARCV2_TIMER=y CONFIG_CONSOLE=y CONFIG_UART_CONSOLE=y CONFIG_SERIAL=y -CONFIG_ARC_EXCEPTION_DEBUG=y diff --git a/boards/arc/nsim/nsim_hs5x_smp_12cores_defconfig b/boards/arc/nsim/nsim_hs5x_smp_12cores_defconfig index 1d146abff7f..c27e5d81ede 100644 --- a/boards/arc/nsim/nsim_hs5x_smp_12cores_defconfig +++ b/boards/arc/nsim/nsim_hs5x_smp_12cores_defconfig @@ -12,7 +12,6 @@ CONFIG_ARCV2_TIMER=y CONFIG_CONSOLE=y CONFIG_UART_CONSOLE=y CONFIG_SERIAL=y -CONFIG_ARC_EXCEPTION_DEBUG=y CONFIG_SMP=y CONFIG_MP_MAX_NUM_CPUS=12 CONFIG_TICKET_SPINLOCKS=y diff --git a/boards/arc/nsim/nsim_hs5x_smp_defconfig b/boards/arc/nsim/nsim_hs5x_smp_defconfig index c801fe9430e..ac6baba1858 100644 --- a/boards/arc/nsim/nsim_hs5x_smp_defconfig +++ b/boards/arc/nsim/nsim_hs5x_smp_defconfig @@ -12,7 +12,6 @@ CONFIG_ARCV2_TIMER=y CONFIG_CONSOLE=y CONFIG_UART_CONSOLE=y CONFIG_SERIAL=y -CONFIG_ARC_EXCEPTION_DEBUG=y CONFIG_SMP=y CONFIG_MP_MAX_NUM_CPUS=2 CONFIG_TICKET_SPINLOCKS=y diff --git a/boards/arc/nsim/nsim_hs6x_defconfig b/boards/arc/nsim/nsim_hs6x_defconfig index 4db6e16b61e..dfb41bf2215 100644 --- a/boards/arc/nsim/nsim_hs6x_defconfig +++ b/boards/arc/nsim/nsim_hs6x_defconfig @@ -12,4 +12,3 @@ CONFIG_ARCV2_TIMER=y CONFIG_CONSOLE=y CONFIG_UART_CONSOLE=y CONFIG_SERIAL=y -CONFIG_ARC_EXCEPTION_DEBUG=y diff --git a/boards/arc/nsim/nsim_hs6x_smp_12cores_defconfig b/boards/arc/nsim/nsim_hs6x_smp_12cores_defconfig index 86793a594c7..2e14a87ed40 100644 --- a/boards/arc/nsim/nsim_hs6x_smp_12cores_defconfig +++ b/boards/arc/nsim/nsim_hs6x_smp_12cores_defconfig @@ -12,7 +12,6 @@ CONFIG_ARCV2_TIMER=y CONFIG_CONSOLE=y CONFIG_UART_CONSOLE=y CONFIG_SERIAL=y -CONFIG_ARC_EXCEPTION_DEBUG=y CONFIG_SMP=y CONFIG_MP_MAX_NUM_CPUS=12 CONFIG_TICKET_SPINLOCKS=y diff --git a/boards/arc/nsim/nsim_hs6x_smp_defconfig b/boards/arc/nsim/nsim_hs6x_smp_defconfig index 43085894396..c34a380d1d0 100644 --- a/boards/arc/nsim/nsim_hs6x_smp_defconfig +++ b/boards/arc/nsim/nsim_hs6x_smp_defconfig @@ -12,7 +12,6 @@ CONFIG_ARCV2_TIMER=y CONFIG_CONSOLE=y CONFIG_UART_CONSOLE=y CONFIG_SERIAL=y -CONFIG_ARC_EXCEPTION_DEBUG=y CONFIG_SMP=y CONFIG_MP_MAX_NUM_CPUS=2 CONFIG_TICKET_SPINLOCKS=y diff --git a/boards/arc/nsim/nsim_hs_defconfig b/boards/arc/nsim/nsim_hs_defconfig index 92ca6763a59..eddd5076c65 100644 --- a/boards/arc/nsim/nsim_hs_defconfig +++ b/boards/arc/nsim/nsim_hs_defconfig @@ -11,5 +11,4 @@ CONFIG_ARCV2_TIMER=y CONFIG_CONSOLE=y CONFIG_UART_CONSOLE=y CONFIG_SERIAL=y -CONFIG_ARC_EXCEPTION_DEBUG=y CONFIG_ARC_MPU_ENABLE=y diff --git a/boards/arc/nsim/nsim_hs_flash_xip_defconfig b/boards/arc/nsim/nsim_hs_flash_xip_defconfig index bc6104c8a12..e4124a3ed69 100644 --- a/boards/arc/nsim/nsim_hs_flash_xip_defconfig +++ b/boards/arc/nsim/nsim_hs_flash_xip_defconfig @@ -11,6 +11,5 @@ CONFIG_ARCV2_TIMER=y CONFIG_CONSOLE=y CONFIG_UART_CONSOLE=y CONFIG_SERIAL=y -CONFIG_ARC_EXCEPTION_DEBUG=y CONFIG_HARVARD=n CONFIG_ARC_MPU_ENABLE=y diff --git a/boards/arc/nsim/nsim_hs_mpuv6_defconfig b/boards/arc/nsim/nsim_hs_mpuv6_defconfig index 33b9af526d6..4f57122f208 100644 --- a/boards/arc/nsim/nsim_hs_mpuv6_defconfig +++ b/boards/arc/nsim/nsim_hs_mpuv6_defconfig @@ -12,4 +12,3 @@ CONFIG_ARC_MPU_ENABLE=y CONFIG_CONSOLE=y CONFIG_UART_CONSOLE=y CONFIG_SERIAL=y -CONFIG_ARC_EXCEPTION_DEBUG=y diff --git a/boards/arc/nsim/nsim_hs_smp_defconfig b/boards/arc/nsim/nsim_hs_smp_defconfig index b07bc87ed41..1b0d663da8d 100644 --- a/boards/arc/nsim/nsim_hs_smp_defconfig +++ b/boards/arc/nsim/nsim_hs_smp_defconfig @@ -11,7 +11,6 @@ CONFIG_ARCV2_TIMER=y CONFIG_CONSOLE=y CONFIG_UART_CONSOLE=y CONFIG_SERIAL=y -CONFIG_ARC_EXCEPTION_DEBUG=y CONFIG_SMP=y CONFIG_MP_MAX_NUM_CPUS=2 CONFIG_TICKET_SPINLOCKS=y diff --git a/boards/arc/nsim/nsim_hs_sram_defconfig b/boards/arc/nsim/nsim_hs_sram_defconfig index 9b60f760e62..8c4032b2054 100644 --- a/boards/arc/nsim/nsim_hs_sram_defconfig +++ b/boards/arc/nsim/nsim_hs_sram_defconfig @@ -11,6 +11,5 @@ CONFIG_ARCV2_TIMER=y CONFIG_CONSOLE=y CONFIG_UART_CONSOLE=y CONFIG_SERIAL=y -CONFIG_ARC_EXCEPTION_DEBUG=y CONFIG_HARVARD=n CONFIG_ARC_MPU_ENABLE=y diff --git a/boards/arc/nsim/nsim_sem_defconfig b/boards/arc/nsim/nsim_sem_defconfig index 2ec15d063f5..c6be9e45d58 100644 --- a/boards/arc/nsim/nsim_sem_defconfig +++ b/boards/arc/nsim/nsim_sem_defconfig @@ -12,5 +12,4 @@ CONFIG_ARC_MPU_ENABLE=y CONFIG_CONSOLE=y CONFIG_UART_CONSOLE=y CONFIG_SERIAL=y -CONFIG_ARC_EXCEPTION_DEBUG=y CONFIG_TRUSTED_EXECUTION_SECURE=y diff --git a/boards/arc/nsim/nsim_sem_mpu_stack_guard_defconfig b/boards/arc/nsim/nsim_sem_mpu_stack_guard_defconfig index 56e4a729daf..4f846b18d61 100644 --- a/boards/arc/nsim/nsim_sem_mpu_stack_guard_defconfig +++ b/boards/arc/nsim/nsim_sem_mpu_stack_guard_defconfig @@ -13,5 +13,4 @@ CONFIG_ARC_MPU_ENABLE=y CONFIG_CONSOLE=y CONFIG_UART_CONSOLE=y CONFIG_SERIAL=y -CONFIG_ARC_EXCEPTION_DEBUG=y CONFIG_TRUSTED_EXECUTION_SECURE=y diff --git a/boards/arc/nsim/nsim_vpx5_defconfig b/boards/arc/nsim/nsim_vpx5_defconfig index 4107bf940ee..83fdaa12a7d 100644 --- a/boards/arc/nsim/nsim_vpx5_defconfig +++ b/boards/arc/nsim/nsim_vpx5_defconfig @@ -11,4 +11,3 @@ CONFIG_ARCV2_TIMER=y CONFIG_CONSOLE=y CONFIG_UART_CONSOLE=y CONFIG_SERIAL=y -CONFIG_ARC_EXCEPTION_DEBUG=y diff --git a/samples/boards/arc_secure_services/nsim_sem_normal_defconfig b/samples/boards/arc_secure_services/nsim_sem_normal_defconfig index 98b3d6edca0..91b9775a7dd 100644 --- a/samples/boards/arc_secure_services/nsim_sem_normal_defconfig +++ b/samples/boards/arc_secure_services/nsim_sem_normal_defconfig @@ -10,5 +10,4 @@ CONFIG_ARCV2_TIMER=y CONFIG_CONSOLE=y CONFIG_UART_CONSOLE=y CONFIG_SERIAL=y -CONFIG_ARC_EXCEPTION_DEBUG=y CONFIG_TRUSTED_EXECUTION_NONSECURE=y diff --git a/tests/arch/x86/pagetables/prj.conf b/tests/arch/x86/pagetables/prj.conf index 1c2858b3e00..4377016135f 100644 --- a/tests/arch/x86/pagetables/prj.conf +++ b/tests/arch/x86/pagetables/prj.conf @@ -1,5 +1,4 @@ CONFIG_ZTEST=y CONFIG_TEST_HW_STACK_PROTECTION=n CONFIG_TEST_USERSPACE=y -CONFIG_EXCEPTION_DEBUG=y CONFIG_APPLICATION_DEFINED_SYSCALL=y From a7e8391e31ca8cadcfe929f4f1c5514701f96c08 Mon Sep 17 00:00:00 2001 From: Anas Nashif Date: Tue, 12 Dec 2023 07:33:47 -0500 Subject: [PATCH 1233/3723] debug: coredump: handle xtensa coredump like everyone else There should not be any special handling for coredump with xtensa. Signed-off-by: Anas Nashif --- arch/xtensa/core/fatal.c | 2 -- kernel/fatal.c | 4 ---- 2 files changed, 6 deletions(-) diff --git a/arch/xtensa/core/fatal.c b/arch/xtensa/core/fatal.c index 4e0f7d41ecd..425c3e79af5 100644 --- a/arch/xtensa/core/fatal.c +++ b/arch/xtensa/core/fatal.c @@ -9,7 +9,6 @@ #include #include #include -#include #include #include @@ -96,7 +95,6 @@ void xtensa_fatal_error(unsigned int reason, const z_arch_esf_t *esf) xtensa_dump_stack(esf); - coredump(reason, esf, IS_ENABLED(CONFIG_MULTITHREADING) ? k_current_get() : NULL); #if defined(CONFIG_XTENSA_ENABLE_BACKTRACE) #if XCHAL_HAVE_WINDOWED diff --git a/kernel/fatal.c b/kernel/fatal.c index 7a3733cbfef..688c9030a1b 100644 --- a/kernel/fatal.c +++ b/kernel/fatal.c @@ -13,9 +13,7 @@ #include #include #include -#ifndef CONFIG_XTENSA #include -#endif LOG_MODULE_DECLARE(os, CONFIG_KERNEL_LOG_LEVEL); @@ -115,9 +113,7 @@ void z_fatal_error(unsigned int reason, const z_arch_esf_t *esf) LOG_ERR("Current thread: %p (%s)", thread, thread_name_get(thread)); -#ifndef CONFIG_XTENSA coredump(reason, esf, thread); -#endif k_sys_fatal_error_handler(reason, esf); From e25f31ab78df07720a22ab47ac4d006eb8419b79 Mon Sep 17 00:00:00 2001 From: Anas Nashif Date: Tue, 12 Dec 2023 09:57:11 -0500 Subject: [PATCH 1234/3723] arch: guard more code with CONFIG_EXCEPTION_DEBUG It should be possible to disable exception debug, which is enabled by default to reduce image size. Add missing guards now that the option is cross architecture. Signed-off-by: Anas Nashif --- arch/arm/core/fatal.c | 5 ++++- arch/mips/core/fatal.c | 3 ++- arch/nios2/core/fatal.c | 2 ++ arch/riscv/core/fatal.c | 3 ++- arch/sparc/core/fatal.c | 6 +++++- arch/xtensa/core/fatal.c | 2 ++ 6 files changed, 17 insertions(+), 4 deletions(-) diff --git a/arch/arm/core/fatal.c b/arch/arm/core/fatal.c index c053bb53e4a..c5adebf8ee7 100644 --- a/arch/arm/core/fatal.c +++ b/arch/arm/core/fatal.c @@ -17,6 +17,7 @@ #include LOG_MODULE_DECLARE(os, CONFIG_KERNEL_LOG_LEVEL); +#ifdef CONFIG_EXCEPTION_DEBUG static void esf_dump(const z_arch_esf_t *esf) { LOG_ERR("r0/a1: 0x%08x r1/a2: 0x%08x r2/a3: 0x%08x", @@ -63,13 +64,15 @@ static void esf_dump(const z_arch_esf_t *esf) LOG_ERR("Faulting instruction address (r15/pc): 0x%08x", esf->basic.pc); } +#endif /* CONFIG_EXCEPTION_DEBUG */ void z_arm_fatal_error(unsigned int reason, const z_arch_esf_t *esf) { - +#ifdef CONFIG_EXCEPTION_DEBUG if (esf != NULL) { esf_dump(esf); } +#endif /* CONFIG_EXCEPTION_DEBUG */ z_fatal_error(reason, esf); } diff --git a/arch/mips/core/fatal.c b/arch/mips/core/fatal.c index 48234680a6a..5a8c183213a 100644 --- a/arch/mips/core/fatal.c +++ b/arch/mips/core/fatal.c @@ -12,6 +12,7 @@ LOG_MODULE_DECLARE(os, CONFIG_KERNEL_LOG_LEVEL); FUNC_NORETURN void z_mips_fatal_error(unsigned int reason, const z_arch_esf_t *esf) { +#ifdef CONFIG_EXCEPTION_DEBUG if (esf != NULL) { printk("$ 0 : (ze) %08lx(at) %08lx(v0) %08lx(v1)\n", esf->at, esf->v0, esf->v1); @@ -33,7 +34,7 @@ FUNC_NORETURN void z_mips_fatal_error(unsigned int reason, printk("Cause : %08lx\n", esf->cause); printk("BadVA : %08lx\n", esf->badvaddr); } - +#endif /* CONFIG_EXCEPTION_DEBUG */ z_fatal_error(reason, esf); CODE_UNREACHABLE; } diff --git a/arch/nios2/core/fatal.c b/arch/nios2/core/fatal.c index 9ccb4f3fd92..ac64b5bc309 100644 --- a/arch/nios2/core/fatal.c +++ b/arch/nios2/core/fatal.c @@ -14,6 +14,7 @@ LOG_MODULE_DECLARE(os, CONFIG_KERNEL_LOG_LEVEL); FUNC_NORETURN void z_nios2_fatal_error(unsigned int reason, const z_arch_esf_t *esf) { +#if CONFIG_EXCEPTION_DEBUG if (esf != NULL) { /* Subtract 4 from EA since we added 4 earlier so that the * faulting instruction isn't retried. @@ -33,6 +34,7 @@ FUNC_NORETURN void z_nios2_fatal_error(unsigned int reason, esf->r13, esf->r14, esf->r15, esf->ra); LOG_ERR("estatus: %08x", esf->estatus); } +#endif /* CONFIG_EXCEPTION_DEBUG */ z_fatal_error(reason, esf); CODE_UNREACHABLE; diff --git a/arch/riscv/core/fatal.c b/arch/riscv/core/fatal.c index 171497ff0ca..0cbcf27d5fd 100644 --- a/arch/riscv/core/fatal.c +++ b/arch/riscv/core/fatal.c @@ -31,6 +31,7 @@ static const struct z_exc_handle exceptions[] = { FUNC_NORETURN void z_riscv_fatal_error(unsigned int reason, const z_arch_esf_t *esf) { +#ifdef CONFIG_EXCEPTION_DEBUG if (esf != NULL) { LOG_ERR(" a0: " PR_REG " t0: " PR_REG, esf->a0, esf->t0); LOG_ERR(" a1: " PR_REG " t1: " PR_REG, esf->a1, esf->t1); @@ -54,7 +55,7 @@ FUNC_NORETURN void z_riscv_fatal_error(unsigned int reason, LOG_ERR("mstatus: " PR_REG, esf->mstatus); LOG_ERR(""); } - +#endif /* CONFIG_EXCEPTION_DEBUG */ z_fatal_error(reason, esf); CODE_UNREACHABLE; } diff --git a/arch/sparc/core/fatal.c b/arch/sparc/core/fatal.c index ef92fa69f91..55100606b92 100644 --- a/arch/sparc/core/fatal.c +++ b/arch/sparc/core/fatal.c @@ -93,7 +93,7 @@ struct savearea { uint32_t in[8]; }; - +#if CONFIG_EXCEPTION_DEBUG /* * Exception trap type (tt) values according to The SPARC V8 * manual, Table 7-1. @@ -202,10 +202,12 @@ static void print_all(const z_arch_esf_t *esf) print_backtrace(esf); LOG_ERR(""); } +#endif /* CONFIG_EXCEPTION_DEBUG */ FUNC_NORETURN void z_sparc_fatal_error(unsigned int reason, const z_arch_esf_t *esf) { +#if CONFIG_EXCEPTION_DEBUG if (esf != NULL) { if (IS_ENABLED(CONFIG_EXTRA_EXCEPTION_INFO)) { print_all(esf); @@ -213,6 +215,8 @@ FUNC_NORETURN void z_sparc_fatal_error(unsigned int reason, print_special_registers(esf); } } +#endif /* CONFIG_EXCEPTION_DEBUG */ + z_fatal_error(reason, esf); CODE_UNREACHABLE; } diff --git a/arch/xtensa/core/fatal.c b/arch/xtensa/core/fatal.c index 425c3e79af5..faf6c38a33f 100644 --- a/arch/xtensa/core/fatal.c +++ b/arch/xtensa/core/fatal.c @@ -86,6 +86,7 @@ char *xtensa_exccause(unsigned int cause_code) void xtensa_fatal_error(unsigned int reason, const z_arch_esf_t *esf) { +#ifdef CONFIG_EXCEPTION_DEBUG if (esf) { /* Don't want to get elbowed by xtensa_switch * in between printing registers and dumping them; @@ -103,6 +104,7 @@ void xtensa_fatal_error(unsigned int reason, const z_arch_esf_t *esf) #endif arch_irq_unlock(key); } +#endif /* CONFIG_EXCEPTION_DEBUG */ z_fatal_error(reason, esf); } From dddc5687a9af8b181a9b7e9114779479da566b5d Mon Sep 17 00:00:00 2001 From: Anas Nashif Date: Tue, 12 Dec 2023 10:12:53 -0500 Subject: [PATCH 1235/3723] arch: mips: use LOG_ERR to print exceptions Change exception code to use LOG_ERR and align with all other architectures when CONFIG_EXCEPTION_DEBUG is enabled. Signed-off-by: Anas Nashif --- arch/mips/core/fatal.c | 23 +++++++++++------------ 1 file changed, 11 insertions(+), 12 deletions(-) diff --git a/arch/mips/core/fatal.c b/arch/mips/core/fatal.c index 5a8c183213a..16011241666 100644 --- a/arch/mips/core/fatal.c +++ b/arch/mips/core/fatal.c @@ -5,7 +5,6 @@ */ #include -#include #include LOG_MODULE_DECLARE(os, CONFIG_KERNEL_LOG_LEVEL); @@ -14,25 +13,25 @@ FUNC_NORETURN void z_mips_fatal_error(unsigned int reason, { #ifdef CONFIG_EXCEPTION_DEBUG if (esf != NULL) { - printk("$ 0 : (ze) %08lx(at) %08lx(v0) %08lx(v1)\n", + LOG_ERR("$ 0 : (ze) %08lx(at) %08lx(v0) %08lx(v1)\n", esf->at, esf->v0, esf->v1); - printk("$ 4 : %08lx(a0) %08lx(a1) %08lx(a2) %08lx(a3)\n", + LOG_ERR("$ 4 : %08lx(a0) %08lx(a1) %08lx(a2) %08lx(a3)\n", esf->a0, esf->a1, esf->a2, esf->a3); - printk("$ 8 : %08lx(t0) %08lx(t1) %08lx(t2) %08lx(t3)\n", + LOG_ERR("$ 8 : %08lx(t0) %08lx(t1) %08lx(t2) %08lx(t3)\n", esf->t0, esf->t1, esf->t2, esf->t3); - printk("$12 : %08lx(t4) %08lx(t5) %08lx(t6) %08lx(t7)\n", + LOG_ERR("$12 : %08lx(t4) %08lx(t5) %08lx(t6) %08lx(t7)\n", esf->t4, esf->t5, esf->t6, esf->t7); - printk("...\n"); - printk("$24 : %08lx(t8) %08lx(t9)\n", + LOG_ERR("...\n"); + LOG_ERR("$24 : %08lx(t8) %08lx(t9)\n", esf->t8, esf->t9); - printk("$28 : %08lx(gp) (sp) (s8) %08lx(ra)\n", + LOG_ERR("$28 : %08lx(gp) (sp) (s8) %08lx(ra)\n", esf->gp, esf->ra); - printk("EPC : %08lx\n", esf->epc); + LOG_ERR("EPC : %08lx\n", esf->epc); - printk("Status: %08lx\n", esf->status); - printk("Cause : %08lx\n", esf->cause); - printk("BadVA : %08lx\n", esf->badvaddr); + LOG_ERR("Status: %08lx\n", esf->status); + LOG_ERR("Cause : %08lx\n", esf->cause); + LOG_ERR("BadVA : %08lx\n", esf->badvaddr); } #endif /* CONFIG_EXCEPTION_DEBUG */ z_fatal_error(reason, esf); From 21561e4e032a98beecc64fb897a2359789933ba9 Mon Sep 17 00:00:00 2001 From: Anas Nashif Date: Tue, 12 Dec 2023 12:19:06 -0500 Subject: [PATCH 1236/3723] tests: coredump: no need for special xtensa entry We use the same code flow now on all architectures, so no need for a special entry for xtensa. Signed-off-by: Anas Nashif --- tests/subsys/debug/coredump/testcase.yaml | 24 ----------------------- 1 file changed, 24 deletions(-) diff --git a/tests/subsys/debug/coredump/testcase.yaml b/tests/subsys/debug/coredump/testcase.yaml index 150c07600a1..5b7dde692b1 100644 --- a/tests/subsys/debug/coredump/testcase.yaml +++ b/tests/subsys/debug/coredump/testcase.yaml @@ -7,7 +7,6 @@ tests: platform_exclude: acrn_ehl_crb arch_exclude: - posix - - xtensa integration_platforms: - qemu_x86 harness: console @@ -23,26 +22,3 @@ tests: - "E: #CD:4([dD])([0-9a-fA-F]+)" - "E: #CD:END#" - "k_sys_fatal_error_handler" - - debug.coredump.logging_backend_xtensa: - tags: coredump - ignore_faults: true - ignore_qemu_crash: true - filter: CONFIG_ARCH_SUPPORTS_COREDUMP - arch_allow: - - xtensa - integration_platforms: - - qemu_xtensa - harness: console - harness_config: - type: multi_line - regex: - - "Coredump: (.*)" - - "E: #CD:BEGIN#" - - "E: #CD:5([aA])45([0-9a-fA-F]+)" - - "E: #CD:41([0-9a-fA-F]+)" - - "E: #CD:4([dD])([0-9a-fA-F]+)" - - "E: #CD:4([dD])([0-9a-fA-F]+)" - - "E: #CD:END#" - - ">>> ZEPHYR FATAL ERROR " - - "k_sys_fatal_error_handler" From 4dc0bd1800b7f549adb5033861edd6a813d14f31 Mon Sep 17 00:00:00 2001 From: Marc Desvaux Date: Tue, 12 Dec 2023 16:35:56 +0100 Subject: [PATCH 1237/3723] drivers: ethernet: remove sections.ld for SOC_SERIES_STM32H5X remove section(".eth_stm32_desc") and section(".eth_stm32_desc") for SOC_SERIES_STM32H5X Signed-off-by: Marc Desvaux --- drivers/ethernet/eth_stm32_hal.c | 2 +- soc/arm/st_stm32/stm32h5/CMakeLists.txt | 1 - soc/arm/st_stm32/stm32h5/sections.ld | 19 ------------------- 3 files changed, 1 insertion(+), 21 deletions(-) delete mode 100644 soc/arm/st_stm32/stm32h5/sections.ld diff --git a/drivers/ethernet/eth_stm32_hal.c b/drivers/ethernet/eth_stm32_hal.c index 40760171e9d..1808b59f23b 100644 --- a/drivers/ethernet/eth_stm32_hal.c +++ b/drivers/ethernet/eth_stm32_hal.c @@ -84,7 +84,7 @@ LOG_MODULE_REGISTER(LOG_MODULE_NAME); DT_NODE_HAS_STATUS(DT_CHOSEN(zephyr_dtcm), okay) #define __eth_stm32_desc __dtcm_noinit_section #define __eth_stm32_buf __dtcm_noinit_section -#elif defined(CONFIG_SOC_SERIES_STM32H7X) || defined(CONFIG_SOC_SERIES_STM32H5X) +#elif defined(CONFIG_SOC_SERIES_STM32H7X) #define __eth_stm32_desc __attribute__((section(".eth_stm32_desc"))) #define __eth_stm32_buf __attribute__((section(".eth_stm32_buf"))) #elif defined(CONFIG_NOCACHE_MEMORY) diff --git a/soc/arm/st_stm32/stm32h5/CMakeLists.txt b/soc/arm/st_stm32/stm32h5/CMakeLists.txt index c8d32ef22aa..e02052e3946 100644 --- a/soc/arm/st_stm32/stm32h5/CMakeLists.txt +++ b/soc/arm/st_stm32/stm32h5/CMakeLists.txt @@ -4,6 +4,5 @@ zephyr_include_directories(${ZEPHYR_BASE}/drivers) zephyr_sources( soc.c ) -zephyr_linker_sources(SECTIONS sections.ld) set(SOC_LINKER_SCRIPT ${ZEPHYR_BASE}/include/zephyr/arch/arm/cortex_m/scripts/linker.ld CACHE INTERNAL "") diff --git a/soc/arm/st_stm32/stm32h5/sections.ld b/soc/arm/st_stm32/stm32h5/sections.ld deleted file mode 100644 index ead1bcd811b..00000000000 --- a/soc/arm/st_stm32/stm32h5/sections.ld +++ /dev/null @@ -1,19 +0,0 @@ -/* - * Copyright (c) 2020 Mario Jaun - * - * SPDX-License-Identifier: Apache-2.0 - */ - -#if DT_NODE_HAS_STATUS(DT_NODELABEL(mac), okay) - -SECTION_DATA_PROLOGUE(eth_stm32,(NOLOAD),) -{ -#if DT_NODE_HAS_STATUS(DT_NODELABEL(sram3), okay) - . = ABSOLUTE(DT_REG_ADDR(DT_NODELABEL(sram3))); - *(.eth_stm32_desc) - . = ABSOLUTE(DT_REG_ADDR(DT_NODELABEL(sram3))) + 256; - *(.eth_stm32_buf) - . = ABSOLUTE(DT_REG_ADDR(DT_NODELABEL(sram3))) + 16K; -} GROUP_DATA_LINK_IN(LINKER_DT_NODE_REGION_NAME(DT_NODELABEL(sram3)), LINKER_DT_NODE_REGION_NAME(DT_NODELABEL(sram3))) -#endif -#endif From 3091ddc4fee7ead733cffc2e1565f45e680b74ff Mon Sep 17 00:00:00 2001 From: Daniel DeGrasse Date: Tue, 12 Dec 2023 10:28:26 -0600 Subject: [PATCH 1238/3723] net: lib: lwm2m: use correct format specifier for LOG_ERR Use correct format specifier for LOG_ERR in lwm2m_obj_device.c. The previously used format specifier of %u was correct for 32 bit systems but would produce a build warning for 64 bit systems. Fixes #66441 Signed-off-by: Daniel DeGrasse --- subsys/net/lib/lwm2m/lwm2m_obj_device.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/subsys/net/lib/lwm2m/lwm2m_obj_device.c b/subsys/net/lib/lwm2m/lwm2m_obj_device.c index 9416b3cf92c..f5399fefc1e 100644 --- a/subsys/net/lib/lwm2m/lwm2m_obj_device.c +++ b/subsys/net/lib/lwm2m/lwm2m_obj_device.c @@ -261,7 +261,7 @@ static int lwm2m_obj_device_settings_set(const char *name, size_t len, if (settings_name_steq(name, ERROR_LIST_KEY, &next) && !next) { if (len > sizeof(error_code_list)) { - LOG_ERR("Error code list too large: %u", len); + LOG_ERR("Error code list too large: %zu", len); return -EINVAL; } From 04c990305535de12641330321f3d390544e7fef3 Mon Sep 17 00:00:00 2001 From: Christopher Friedt Date: Mon, 11 Dec 2023 23:05:28 -0500 Subject: [PATCH 1239/3723] posix: pthread_once: simplify and reduce size of pthread_once_t Since pthread_once() is both the initializer and executor of pthread_once_t, it can have maximally two states. Since the implementation in Zephyr previously aimed to maximize libc compatibility, we opted to use the definition of pthread_once_t from newlib, which is a structure with two ints. It does not make sense to use 64 bits to manage 2 possible states. The control for that should effectively be a bool. We maintain compatibility with newlib by asserting (at build time), that newlib's pthread_once_t is larger than Zephyr's new struct pthread_once (which just contains a bool). This allows us to delete the non-standard pthread_key.h header file (finally). Reuse the pthread_pool_lock in order to synchronize the related init function (so that it is only called maximally once from any thread). The spinlock is only used to test the state and the init function is not called with the spinlock held. The alternative was to use an atomic inside of struct pthread_once. But again, that could be up to 64-bits with Zephyr's atomics implementation. Ideally we would use C11 generics or something to support atomics on 8, 16, 32, and 64-bit primitives. Lastly, also update declarations for C11 threads as they mostly mirror our pthread implementation. This needed to be done as a single commit in order to ensure continuity of build. Signed-off-by: Christopher Friedt --- include/zephyr/posix/posix_types.h | 13 ++++++++ include/zephyr/posix/pthread.h | 7 +---- include/zephyr/posix/pthread_key.h | 36 ---------------------- lib/libc/common/include/machine/_threads.h | 8 ++--- lib/posix/key.c | 1 - lib/posix/pthread.c | 21 ++++++++----- tests/posix/common/src/pthread.c | 2 +- 7 files changed, 30 insertions(+), 58 deletions(-) delete mode 100644 include/zephyr/posix/pthread_key.h diff --git a/include/zephyr/posix/posix_types.h b/include/zephyr/posix/posix_types.h index 73a7485f000..25009dc88bc 100644 --- a/include/zephyr/posix/posix_types.h +++ b/include/zephyr/posix/posix_types.h @@ -101,6 +101,19 @@ typedef struct pthread_rwlock_obj { k_tid_t wr_owner; } pthread_rwlock_t; +struct pthread_once { + bool flag; +}; + +#if defined(CONFIG_MINIMAL_LIBC) || defined(CONFIG_PICOLIBC) || defined(CONFIG_ARMCLANG_STD_LIBC) \ + || defined(CONFIG_ARCMWDT_LIBC) +typedef uint32_t pthread_key_t; +typedef struct pthread_once pthread_once_t; +#endif + +/* Newlib typedefs pthread_once_t as a struct with two ints */ +BUILD_ASSERT(sizeof(pthread_once_t) >= sizeof(struct pthread_once)); + #ifdef __cplusplus } #endif diff --git a/include/zephyr/posix/pthread.h b/include/zephyr/posix/pthread.h index 7d7536ef0db..ccb1c71a4bd 100644 --- a/include/zephyr/posix/pthread.h +++ b/include/zephyr/posix/pthread.h @@ -7,8 +7,6 @@ #ifndef ZEPHYR_INCLUDE_POSIX_PTHREAD_H_ #define ZEPHYR_INCLUDE_POSIX_PTHREAD_H_ -#include "pthread_key.h" - #include #include @@ -37,10 +35,7 @@ extern "C" { #define PTHREAD_CANCEL_ASYNCHRONOUS 1 /* Passed to pthread_once */ -#define PTHREAD_ONCE_INIT \ - { \ - 1, 0 \ - } +#define PTHREAD_ONCE_INIT {0} /* The minimum allowable stack size */ #define PTHREAD_STACK_MIN Z_KERNEL_STACK_SIZE_ADJUST(0) diff --git a/include/zephyr/posix/pthread_key.h b/include/zephyr/posix/pthread_key.h deleted file mode 100644 index 6b89c8f9818..00000000000 --- a/include/zephyr/posix/pthread_key.h +++ /dev/null @@ -1,36 +0,0 @@ -/* - * Copyright (c) 2018 Intel Corporation - * - * SPDX-License-Identifier: Apache-2.0 - */ - -#ifndef ZEPHYR_INCLUDE_POSIX_PTHREAD_KEY_H_ -#define ZEPHYR_INCLUDE_POSIX_PTHREAD_KEY_H_ - -#include - -#ifdef __cplusplus -extern "C" { -#endif - -#if defined(CONFIG_MINIMAL_LIBC) || defined(CONFIG_PICOLIBC) || defined(CONFIG_ARMCLANG_STD_LIBC) \ - || defined(CONFIG_ARCMWDT_LIBC) - -#ifdef CONFIG_PTHREAD_IPC - -typedef struct { - int is_initialized; - int init_executed; -} pthread_once_t; -#endif - -/* pthread_key */ -typedef uint32_t pthread_key_t; - -#endif /* CONFIG_PTHREAD_IPC */ - -#ifdef __cplusplus -} -#endif - -#endif /* ZEPHYR_INCLUDE_POSIX_PTHREAD_KEY_H_*/ diff --git a/lib/libc/common/include/machine/_threads.h b/lib/libc/common/include/machine/_threads.h index 578536ca5c6..cebce717c73 100644 --- a/lib/libc/common/include/machine/_threads.h +++ b/lib/libc/common/include/machine/_threads.h @@ -11,18 +11,14 @@ extern "C" { #endif -#define ONCE_FLAG_INIT \ - { \ - 1, 0 \ - } +#define ONCE_FLAG_INIT {0} typedef int cnd_t; typedef int mtx_t; typedef int thrd_t; typedef int tss_t; typedef struct { - int is_initialized; - int init_executed; + char flag; } once_flag; #ifdef __cplusplus diff --git a/lib/posix/key.c b/lib/posix/key.c index 9c32c95f043..df9062362ed 100644 --- a/lib/posix/key.c +++ b/lib/posix/key.c @@ -9,7 +9,6 @@ #include #include #include -#include #include #include diff --git a/lib/posix/pthread.c b/lib/posix/pthread.c index f8c62a233f1..e809b539c6a 100644 --- a/lib/posix/pthread.c +++ b/lib/posix/pthread.c @@ -58,7 +58,6 @@ static sys_dlist_t done_q = SYS_DLIST_STATIC_INIT(&done_q); static struct posix_thread posix_thread_pool[CONFIG_MAX_PTHREAD_COUNT]; static struct k_spinlock pthread_pool_lock; static int pthread_concurrency; -static K_MUTEX_DEFINE(pthread_once_lock); static const struct pthread_attr init_pthread_attrs = { .priority = 0, @@ -707,17 +706,23 @@ int pthread_getschedparam(pthread_t pthread, int *policy, struct sched_param *pa int pthread_once(pthread_once_t *once, void (*init_func)(void)) { __unused int ret; + bool run_init_func = false; + struct pthread_once *const _once = (struct pthread_once *)once; - ret = k_mutex_lock(&pthread_once_lock, K_FOREVER); - __ASSERT_NO_MSG(ret == 0); + if (init_func == NULL) { + return EINVAL; + } - if (once->is_initialized != 0 && once->init_executed == 0) { - init_func(); - once->init_executed = 1; + K_SPINLOCK(&pthread_pool_lock) { + if (!_once->flag) { + run_init_func = true; + _once->flag = true; + } } - ret = k_mutex_unlock(&pthread_once_lock); - __ASSERT_NO_MSG(ret == 0); + if (run_init_func) { + init_func(); + } return 0; } diff --git a/tests/posix/common/src/pthread.c b/tests/posix/common/src/pthread.c index 974e13d2ac2..3ff1092df27 100644 --- a/tests/posix/common/src/pthread.c +++ b/tests/posix/common/src/pthread.c @@ -473,7 +473,7 @@ ZTEST(posix_apis, test_pthread_errors_errno) "cancel NULL error"); zassert_equal(pthread_join(PTHREAD_INVALID, NULL), ESRCH, "join with NULL has error"); - zassert_false(pthread_once(&key, NULL), + zassert_equal(pthread_once(&key, NULL), EINVAL, "pthread dynamic package initialization error"); zassert_equal(pthread_getschedparam(PTHREAD_INVALID, &policy, ¶m), ESRCH, "get schedparam with NULL error"); From 5a3b9799aa7599e3a2eae51c40149c47472998c1 Mon Sep 17 00:00:00 2001 From: Piotr Golyzniak Date: Wed, 22 Nov 2023 19:57:10 +0100 Subject: [PATCH 1240/3723] doc: test: improve pytest documentation Improve documentation about pytest integration with Twister. Add examples of usage, improve description of available options and introduce automatic doc generation of two plugin classes (DeviceAdapter and Shell) basing on their docstrings from source code. Signed-off-by: Piotr Golyzniak --- doc/conf.py | 3 + doc/develop/test/pytest.rst | 233 +++++++++++++++--- doc/develop/test/twister.rst | 32 ++- doc/requirements.txt | 3 + .../twister_harness/device/device_adapter.py | 20 +- .../src/twister_harness/helpers/shell.py | 2 +- tests/boot/with_mcumgr/README.rst | 2 +- 7 files changed, 241 insertions(+), 54 deletions(-) diff --git a/doc/conf.py b/doc/conf.py index a6f6a1af3b4..c0ce3c07235 100644 --- a/doc/conf.py +++ b/doc/conf.py @@ -25,6 +25,9 @@ # for autodoc directives on runners.xyz. sys.path.insert(0, str(ZEPHYR_BASE / "scripts" / "west_commands")) +# Add the directory which contains the pytest-twister-pytest +sys.path.insert(0, str(ZEPHYR_BASE / "scripts" / "pylib" / "pytest-twister-harness" / "src")) + import redirects try: diff --git a/doc/develop/test/pytest.rst b/doc/develop/test/pytest.rst index f6ba54fa52e..8edcc67f0ae 100644 --- a/doc/develop/test/pytest.rst +++ b/doc/develop/test/pytest.rst @@ -1,4 +1,4 @@ -.. integration-with-pytest: +.. _integration_with_pytest: Integration with pytest test framework ###################################### @@ -46,43 +46,71 @@ sets the test result accordingly. How to create a pytest test *************************** -An example of a pytest test is given at :zephyr_file:`samples/subsys/testsuite/pytest/shell/pytest/test_shell.py`. -Twister calls pytest for each configuration from the .yaml file which uses ``harness: pytest``. -By default, it points to ``pytest`` directory, located next to a directory with binary sources. -A keyword ``pytest_root`` placed under ``harness_config`` section can be used to point to other -files, directories or subtests. +An example folder containing a pytest test, application source code and Twister configuration .yaml +file can look like the following: + +.. code-block:: none + + test_foo/ + ├─── pytest/ + │ └─── test_foo.py + ├─── src/ + │ └─── main.c + ├─── CMakeList.txt + ├─── prj.conf + └─── testcase.yaml + +An example of a pytest test is given at +:zephyr_file:`samples/subsys/testsuite/pytest/shell/pytest/test_shell.py`. Using the configuration +provided in the ``testcase.yaml`` file, Twister builds the application from ``src`` and then, if the +.yaml file contains a ``harness: pytest`` entry, it calls pytest in a separate subprocess. A sample +configuration file may look like this: + +.. code-block:: yaml + + tests: + some.foo.test: + harness: pytest + tags: foo + +By default, pytest tries to look for tests in a ``pytest`` directory located next to a directory +with binary sources. A keyword ``pytest_root`` placed under ``harness_config`` section in .yaml file +can be used to point to other files, directories or subtests (more info :ref:`here `). Pytest scans the given locations looking for tests, following its default -`discovery rules `_ -One can also pass some extra arguments to the pytest from yaml file using ``pytest_args`` keyword -under ``harness_config``, e.g.: ``pytest_args: [‘-k=test_method’, ‘--log-level=DEBUG’]``. -There is also an option to pass ``--pytest-args`` through Twister command line parameters. -This can be particularly useful when one wants to select a specific testcase from a test suite. -For instance, one can use a command: +`discovery rules `_. + +Passing extra arguments +======================= -.. code-block:: console +There are two ways for passing extra arguments to the called pytest subprocess: - $ ./scripts/twister --platform native_sim -T samples/subsys/testsuite/pytest/shell \ - -s samples/subsys/testsuite/pytest/shell/sample.pytest.shell \ - --pytest-args='-k test_shell_print_version' +#. From .yaml file, using ``pytest_args`` placed under ``harness_config`` section - more info + :ref:`here `. +#. Through Twister command line interface as ``--pytest-args`` argument. This can be particularly + useful when one wants to select a specific testcase from a test suite. For instance, one can use + a command: + .. code-block:: console -Note that ``--pytest-args`` can be passed multiple times to pass several arguments to the pytest. + $ ./scripts/twister --platform native_sim -T samples/subsys/testsuite/pytest/shell \ + -s samples/subsys/testsuite/pytest/shell/sample.pytest.shell \ + --pytest-args='-k test_shell_print_version' -Helpers & fixtures -================== + +Fixtures +******** dut ---- +=== -Give access to a DeviceAdapter type object, that represents Device Under Test. -This fixture is the core of pytest harness plugin. It is required to launch -DUT (initialize logging, flash device, connect serial etc). -This fixture yields a device prepared according to the requested type -(``native``, ``qemu``, ``hardware``, etc.). All types of devices share the same API. -This allows for writing tests which are device-type-agnostic. -Scope of this fixture is determined by the ``pytest_dut_scope`` -keyword placed under ``harness_config`` section. +Give access to a `DeviceAdapter`_ type object, that represents Device Under Test. This fixture is +the core of pytest harness plugin. It is required to launch DUT (initialize logging, flash device, +connect serial etc). This fixture yields a device prepared according to the requested type +(``native``, ``qemu``, ``hardware``, etc.). All types of devices share the same API. This allows for +writing tests which are device-type-agnostic. Scope of this fixture is determined by the +``pytest_dut_scope`` keyword placed under ``harness_config`` section (more info +:ref:`here `). .. code-block:: python @@ -93,13 +121,14 @@ keyword placed under ``harness_config`` section. dut.readlines_until('Hello world') shell ------ +===== -Provide an object with methods used to interact with shell application. -It calls ``wait_for_promt`` method, to not start scenario until DUT is ready. -Note that it uses ``dut`` fixture, so ``dut`` can be skipped when ``shell`` is used. -Scope of this fixture is determined by the ``pytest_dut_scope`` -keyword placed under ``harness_config`` section. +Provide a `Shell `_ class object with methods used to interact with shell application. +It calls ``wait_for_promt`` method, to not start scenario until DUT is ready. The shell fixture +calls ``dut`` fixture, hence has access to all its methods. The ``shell`` fixture adds methods +optimized for interactions with a shell. It can be used instead of ``dut`` for tests. Scope of this +fixture is determined by the ``pytest_dut_scope`` keyword placed under ``harness_config`` section +(more info :ref:`here `). .. code-block:: python @@ -109,16 +138,16 @@ keyword placed under ``harness_config`` section. shell.exec_command('help') mcumgr ------- +====== -Sample fixture to wrap ``mcumgr`` command-line tool used to manage remote devices. -More information about MCUmgr can be found here :ref:`mcu_mgr`. +Sample fixture to wrap ``mcumgr`` command-line tool used to manage remote devices. More information +about MCUmgr can be found here :ref:`mcu_mgr`. .. note:: This fixture requires the ``mcumgr`` available in the system PATH -Only selected functionality of MCUmgr is wrapped by this fixture. -For example, here is a test with a fixture ``mcumgr`` +Only selected functionality of MCUmgr is wrapped by this fixture. For example, here is a test with +a fixture ``mcumgr`` .. code-block:: python @@ -137,6 +166,132 @@ For example, here is a test with a fixture ``mcumgr`` mcumgr.reset_device() # continue test scenario, check version etc. +Classes +******* + +DeviceAdapter +============= + +.. autoclass:: twister_harness.DeviceAdapter + + .. automethod:: launch + + .. automethod:: connect + + .. automethod:: readline + + .. automethod:: readlines + + .. automethod:: readlines_until + + .. automethod:: write + + .. automethod:: disconnect + + .. automethod:: close + +.. _shell_class: + +Shell +===== + +.. autoclass:: twister_harness.Shell + + .. automethod:: exec_command + + .. automethod:: wait_for_prompt + + +Examples of pytest tests in the Zephyr project +********************************************** + +* Shell demo - :zephyr_file:`samples/subsys/testsuite/pytest/shell` +* MCUmgr tests - :zephyr_file:`tests/boot/with_mcumgr` +* LwM2M tests - :zephyr_file:`tests/net/lib/lwm2m/interop` +* GDB stub tests - :zephyr_file:`tests/subsys/debug/gdbstub` + + +FAQ +*** + +How to flash/run application only once per pytest session? +========================================================== + + ``dut`` is a fixture responsible for flashing/running application. By default, its scope is set + as ``function``. This can be changed by adding to .yaml file ``pytest_dut_scope`` keyword placed + under ``harness_config`` section: + + .. code-block:: yaml + + harness: pytest + harness_config: + pytest_dut_scope: session + + More info can be found :ref:`here `. + +How to run only one particular test from a python file? +======================================================= + + This can be achieved in several ways. In .yaml file it can be added using a ``pytest_root`` entry + placed under ``harness_config`` with list of tests which should be run: + + .. code-block:: yaml + + harness: pytest + harness_config: + pytest_root: + - "pytest/test_shell.py::test_shell_print_help" + + Particular tests can be also chosen by pytest ``-k`` option (more info about pytest keyword + filter can be found + `here `_ + ). It can be applied by adding ``-k`` filter in ``pytest_args`` in .yaml file: + + .. code-block:: yaml + + harness: pytest + harness_config: + pytest_args: + - "-k test_shell_print_help" + + or by adding it to Twister command overriding parameters from the .yaml file: + + .. code-block:: console + + $ ./scripts/twister ... --pytest-args='-k test_shell_print_help' + +How to get information about used device type in test? +====================================================== + + This can be taken from ``dut`` fixture (which represents `DeviceAdapter`_ object): + + .. code-block:: python + + device_type: str = dut.device_config.type + if device_type == 'hardware': + ... + elif device_type == 'native': + ... + +How to rerun locally pytest tests without rebuilding application by Twister? +============================================================================ + + This can be achieved by running Twister once again with ``--test-only`` argument added to Twister + command. Another way is running Twister with highest verbosity level (``-vv``) and then + copy-pasting from logs command dedicated for spawning pytest (log started by ``Running pytest + command: ...``). + +Is this possible to run pytest tests in parallel? +================================================= + + Basically ``pytest-harness-plugin`` wasn't written with intention of running pytest tests in + parallel. Especially those one dedicated for hardware. There was assumption that parallelization + of tests is made by Twister, and it is responsible for managing available sources (jobs and + hardwares). If anyone is interested in doing this for some reasons (for example via + `pytest-xdist plugin `_) they do so at their own + risk. + + Limitations *********** diff --git a/doc/develop/test/twister.rst b/doc/develop/test/twister.rst index 4677244725b..0866653a636 100644 --- a/doc/develop/test/twister.rst +++ b/doc/develop/test/twister.rst @@ -514,14 +514,36 @@ harness_config: Only one fixture can be defined per testcase and the fixture name has to be unique across all tests in the test suite. +.. _pytest_root: + pytest_root: (default pytest) - Specify a list of pytest directories, files or subtests that need to be executed - when test case begin to running, default pytest directory is pytest. - After pytest finished, twister will check if this case pass or fail according - to the pytest report. + Specify a list of pytest directories, files or subtests that need to be + executed when a test case begins to run. The default pytest directory is + ``pytest``. After the pytest run is finished, Twister will check if + the test case passed or failed according to the pytest report. + As an example, a list of valid pytest roots is presented below: + + .. code-block:: yaml + + harness_config: + pytest_root: + - "pytest/test_shell_help.py" + - "../shell/pytest/test_shell.py" + - "/tmp/test_shell.py" + - "~/tmp/test_shell.py" + - "$ZEPHYR_BASE/samples/subsys/testsuite/pytest/shell/pytest/test_shell.py" + - "pytest/test_shell_help.py::test_shell2_sample" # select pytest subtest + - "pytest/test_shell_help.py::test_shell2_sample[param_a]" # select pytest parametrized subtest + +.. _pytest_args: pytest_args: (default empty) - Specify a list of additional arguments to pass to ``pytest``. + Specify a list of additional arguments to pass to ``pytest`` e.g.: + ``pytest_args: [‘-k=test_method’, ‘--log-level=DEBUG’]``. Note that + ``--pytest-args`` can be passed multiple times to pass several arguments + to the pytest. + +.. _pytest_dut_scope: pytest_dut_scope: (default function) The scope for which ``dut`` and ``shell`` pytest fixtures are shared. diff --git a/doc/requirements.txt b/doc/requirements.txt index 45bb461e518..e7747b5f13f 100644 --- a/doc/requirements.txt +++ b/doc/requirements.txt @@ -13,3 +13,6 @@ sphinx-togglebutton # YAML validation. Used by zephyr_module. PyYAML>=5.1 pykwalify + +# Used by pytest-twister-harness plugin +pytest diff --git a/scripts/pylib/pytest-twister-harness/src/twister_harness/device/device_adapter.py b/scripts/pylib/pytest-twister-harness/src/twister_harness/device/device_adapter.py index 59be6c52af9..ce8492c78b7 100644 --- a/scripts/pylib/pytest-twister-harness/src/twister_harness/device/device_adapter.py +++ b/scripts/pylib/pytest-twister-harness/src/twister_harness/device/device_adapter.py @@ -25,7 +25,11 @@ class DeviceAdapter(abc.ABC): - """Class defines an interface for all devices.""" + """ + This class defines a common interface for all device types (hardware, + simulator, QEMU) used in tests to gathering device output and send data to + it. + """ def __init__(self, device_config: DeviceConfig) -> None: """ @@ -54,8 +58,8 @@ def env(self) -> dict[str, str]: def launch(self) -> None: """ Start by closing previously running application (no effect if not - needed). Then, flash and run test application. Finally, start a reader - thread capturing an output from a device. + needed). Then, flash and run test application. Finally, start an + internal reader thread capturing an output from a device. """ self.close() self._clear_internal_resources() @@ -100,7 +104,7 @@ def disconnect(self) -> None: def readline(self, timeout: float | None = None, print_output: bool = True) -> str: """ Read line from device output. If timeout is not provided, then use - base_timeout + base_timeout. """ timeout = timeout or self.base_timeout if self.is_device_connected() or not self._device_read_queue.empty(): @@ -125,13 +129,13 @@ def readlines_until( until following conditions: 1. If regex is provided - read until regex regex is found in read - line (or until timeout) + line (or until timeout). 2. If num_of_lines is provided - read until number of read lines is - equal to num_of_lines (or until timeout) + equal to num_of_lines (or until timeout). 3. If none of above is provided - return immediately lines collected so - far in internal queue + far in internal buffer. - If timeout is not provided, then use base_timeout + If timeout is not provided, then use base_timeout. """ timeout = timeout or self.base_timeout if regex: diff --git a/scripts/pylib/pytest-twister-harness/src/twister_harness/helpers/shell.py b/scripts/pylib/pytest-twister-harness/src/twister_harness/helpers/shell.py index f6eb8074451..64f1cac63f4 100644 --- a/scripts/pylib/pytest-twister-harness/src/twister_harness/helpers/shell.py +++ b/scripts/pylib/pytest-twister-harness/src/twister_harness/helpers/shell.py @@ -55,7 +55,7 @@ def exec_command(self, command: str, timeout: float | None = None, print_output: Send shell command to a device and return response. Passed command is extended by double enter sings - first one to execute this command on a device, second one to receive next prompt what is a signal that - execution was finished. + execution was finished. Method returns printout of the executed command. """ timeout = timeout or self.base_timeout command_ext = f'{command}\n\n' diff --git a/tests/boot/with_mcumgr/README.rst b/tests/boot/with_mcumgr/README.rst index 5f0ef82d30a..f3281f57c5c 100644 --- a/tests/boot/with_mcumgr/README.rst +++ b/tests/boot/with_mcumgr/README.rst @@ -3,7 +3,7 @@ Upgrade testing with MCUmgr This application is based on :ref:`smp_svr_sample`. It is built using **sysbuild**. Tests are automated with pytest, a new harness of Twister -(more information can be found here :ref:`integration-with-pytest`) +(more information can be found :ref:`here `) .. note:: Pytest uses the MCUmgr fixture which requires the ``mcumgr`` available From 5ae567499b03ee5614226d29fcc542cb9e83849d Mon Sep 17 00:00:00 2001 From: Piotr Golyzniak Date: Fri, 1 Dec 2023 19:24:46 +0100 Subject: [PATCH 1241/3723] samples: pytest: add README Add README.rst file with description of sample which shows how to use pytest and Twister together. Signed-off-by: Piotr Golyzniak --- doc/develop/test/pytest.rst | 2 +- .../subsys/testsuite/pytest/shell/README.rst | 79 +++++++++++++++++++ samples/subsys/testsuite/testsuite.rst | 10 +++ 3 files changed, 90 insertions(+), 1 deletion(-) create mode 100644 samples/subsys/testsuite/pytest/shell/README.rst create mode 100644 samples/subsys/testsuite/testsuite.rst diff --git a/doc/develop/test/pytest.rst b/doc/develop/test/pytest.rst index 8edcc67f0ae..ac3980105d9 100644 --- a/doc/develop/test/pytest.rst +++ b/doc/develop/test/pytest.rst @@ -205,7 +205,7 @@ Shell Examples of pytest tests in the Zephyr project ********************************************** -* Shell demo - :zephyr_file:`samples/subsys/testsuite/pytest/shell` +* :zephyr:code-sample:`pytest_shell` * MCUmgr tests - :zephyr_file:`tests/boot/with_mcumgr` * LwM2M tests - :zephyr_file:`tests/net/lib/lwm2m/interop` * GDB stub tests - :zephyr_file:`tests/subsys/debug/gdbstub` diff --git a/samples/subsys/testsuite/pytest/shell/README.rst b/samples/subsys/testsuite/pytest/shell/README.rst new file mode 100644 index 00000000000..4fb4eea11fc --- /dev/null +++ b/samples/subsys/testsuite/pytest/shell/README.rst @@ -0,0 +1,79 @@ +.. zephyr:code-sample:: pytest_shell + :name: Pytest shell application testing + + Execute pytest tests against the Zephyr shell. + +Overview +******** + +The sample project illustrates usage of pytest framework integrated with +Twister test runner. + +A simple application provides basic Zephyr shell interface. Twister builds it +and then calls pytest in subprocess which runs tests from +``pytest/test_shell.py`` file. The first test verifies valid response for +``help`` command, second one verifies if application is able to return +information about used kernel version. Both tests use ``shell`` fixture, which +is defined in ``pytest-twister-harness`` plugin. More information about plugin +can be found :ref:`here `. + +Requirements +************ + +Board (hardware, ``native_sim`` or ``QEMU``) with UART console. + +Building and Running +******************** + +Build and run sample by Twister: + +.. code-block:: console + + $ ./scripts/twister -vv --platform native_sim -T samples/subsys/testsuite/pytest/shell + + +Sample Output +============= + +.. code-block:: console + + ... + samples/subsys/testsuite/pytest/shell/pytest/test_shell.py::test_shell_print_help + INFO: send "help" command + DEBUG: #: uart:~$ help + DEBUG: #: Please press the button to see all available commands. + DEBUG: #: You can also use the button to prompt or auto-complete all commands or its subcommands. + DEBUG: #: You can try to call commands with <-h> or <--help> parameter for more information. + DEBUG: #: Shell supports following meta-keys: + DEBUG: #: Ctrl + (a key from: abcdefklnpuw) + DEBUG: #: Alt + (a key from: bf) + DEBUG: #: Please refer to shell documentation for more details. + DEBUG: #: Available commands: + DEBUG: #: clear :Clear screen. + DEBUG: #: device :Device commands + DEBUG: #: devmem :Read/write physical memory + DEBUG: #: Usage: + DEBUG: #: Read memory at address with optional width: + DEBUG: #: devmem address [width] + DEBUG: #: Write memory at address with mandatory width and value: + DEBUG: #: devmem address + DEBUG: #: help :Prints the help message. + DEBUG: #: history :Command history. + DEBUG: #: kernel :Kernel commands + DEBUG: #: rem :Ignore lines beginning with 'rem ' + DEBUG: #: resize :Console gets terminal screen size or assumes default in case the + DEBUG: #: readout fails. It must be executed after each terminal width change + DEBUG: #: to ensure correct text display. + DEBUG: #: retval :Print return value of most recent command + DEBUG: #: shell :Useful, not Unix-like shell commands. + DEBUG: #: uart:~$ + INFO: response is valid + PASSED + samples/subsys/testsuite/pytest/shell/pytest/test_shell.py::test_shell_print_version + INFO: send "kernel version" command + DEBUG: #: uart:~$ kernel version + DEBUG: #: Zephyr version 3.5.99 + DEBUG: #: uart:~$ + INFO: response is valid + PASSED + ... diff --git a/samples/subsys/testsuite/testsuite.rst b/samples/subsys/testsuite/testsuite.rst new file mode 100644 index 00000000000..7c84784e9a6 --- /dev/null +++ b/samples/subsys/testsuite/testsuite.rst @@ -0,0 +1,10 @@ +.. _testsuite-samples: + +Testsuite samples +################# + +.. toctree:: + :maxdepth: 1 + :glob: + + **/README From ae75a8f73a583967354987be682d9c88c1cad6f5 Mon Sep 17 00:00:00 2001 From: Adam Wojasinski Date: Fri, 22 Oct 2021 16:40:18 +0200 Subject: [PATCH 1242/3723] drivers: spi: spi_nrfx_spim: Add support for RX buffer from RAM region This patch adds support for RX buffer placed by a linker in memory region defined in SPIM devicetree node. The buffer is placed in memory region defined as devicetree node. The memory region node's reference is then stored in `memory-regions` property of SPIM node. Added build time assertion to check if `CONFIG_SPI_NRFX_RAM_BUFFER_SIZE` Kconfig symbol has value greater than 0 when given SPIM node has `memory-region` property. Signed-off-by: Adam Wojasinski --- drivers/spi/spi_nrfx_spim.c | 45 +++++++++++++++++++++++++++++-------- 1 file changed, 36 insertions(+), 9 deletions(-) diff --git a/drivers/spi/spi_nrfx_spim.c b/drivers/spi/spi_nrfx_spim.c index 8122af39a6b..1338bd0a4dc 100644 --- a/drivers/spi/spi_nrfx_spim.c +++ b/drivers/spi/spi_nrfx_spim.c @@ -42,8 +42,9 @@ struct spi_nrfx_data { size_t chunk_len; bool busy; bool initialized; -#if SPI_BUFFER_IN_RAM - uint8_t *buffer; +#ifdef SPI_BUFFER_IN_RAM + uint8_t *tx_buffer; + uint8_t *rx_buffer; #endif #ifdef CONFIG_SOC_NRF52832_ALLOW_SPIM_DESPITE_PAN_58 bool anomaly_58_workaround_active; @@ -312,27 +313,40 @@ static void transfer_next_chunk(const struct device *dev) nrfx_spim_xfer_desc_t xfer; nrfx_err_t result; const uint8_t *tx_buf = ctx->tx_buf; + uint8_t *rx_buf = ctx->rx_buf; if (chunk_len > dev_config->max_chunk_len) { chunk_len = dev_config->max_chunk_len; } -#if (CONFIG_SPI_NRFX_RAM_BUFFER_SIZE > 0) +#ifdef SPI_BUFFER_IN_RAM if (spi_context_tx_buf_on(ctx) && !nrf_dma_accessible_check(&dev_config->spim.p_reg, tx_buf)) { + if (chunk_len > CONFIG_SPI_NRFX_RAM_BUFFER_SIZE) { chunk_len = CONFIG_SPI_NRFX_RAM_BUFFER_SIZE; } - memcpy(dev_data->buffer, tx_buf, chunk_len); - tx_buf = dev_data->buffer; + memcpy(dev_data->tx_buffer, tx_buf, chunk_len); + tx_buf = dev_data->tx_buffer; + } + + if (spi_context_rx_buf_on(ctx) && + !nrf_dma_accessible_check(&dev_config->spim.p_reg, rx_buf)) { + + if (chunk_len > CONFIG_SPI_NRFX_RAM_BUFFER_SIZE) { + chunk_len = CONFIG_SPI_NRFX_RAM_BUFFER_SIZE; + } + + rx_buf = dev_data->rx_buffer; } #endif + dev_data->chunk_len = chunk_len; xfer.p_tx_buffer = tx_buf; xfer.tx_length = spi_context_tx_buf_on(ctx) ? chunk_len : 0; - xfer.p_rx_buffer = ctx->rx_buf; + xfer.p_rx_buffer = rx_buf; xfer.rx_length = spi_context_rx_buf_on(ctx) ? chunk_len : 0; #ifdef CONFIG_SOC_NRF52832_ALLOW_SPIM_DESPITE_PAN_58 @@ -376,6 +390,15 @@ static void event_handler(const nrfx_spim_evt_t *p_event, void *p_context) #ifdef CONFIG_SOC_NRF52832_ALLOW_SPIM_DESPITE_PAN_58 anomaly_58_workaround_clear(dev_data); +#endif +#ifdef SPI_BUFFER_IN_RAM + if (spi_context_rx_buf_on(&dev_data->ctx) && + p_event->xfer_desc.p_rx_buffer != NULL && + p_event->xfer_desc.p_rx_buffer != dev_data->ctx.rx_buf) { + (void)memcpy(dev_data->ctx.rx_buf, + dev_data->rx_buffer, + dev_data->chunk_len); + } #endif spi_context_update_tx(&dev_data->ctx, 1, dev_data->chunk_len); spi_context_update_rx(&dev_data->ctx, 1, dev_data->chunk_len); @@ -603,7 +626,10 @@ static int spi_nrfx_init(const struct device *dev) nrfx_isr, nrfx_spim_##idx##_irq_handler, 0); \ } \ IF_ENABLED(SPI_BUFFER_IN_RAM, \ - (static uint8_t spim_##idx##_buffer \ + (static uint8_t spim_##idx##_tx_buffer \ + [CONFIG_SPI_NRFX_RAM_BUFFER_SIZE] \ + SPIM_MEMORY_SECTION(idx); \ + static uint8_t spim_##idx##_rx_buffer \ [CONFIG_SPI_NRFX_RAM_BUFFER_SIZE] \ SPIM_MEMORY_SECTION(idx);)) \ static struct spi_nrfx_data spi_##idx##_data = { \ @@ -611,7 +637,8 @@ static int spi_nrfx_init(const struct device *dev) SPI_CONTEXT_INIT_SYNC(spi_##idx##_data, ctx), \ SPI_CONTEXT_CS_GPIOS_INITIALIZE(SPIM(idx), ctx) \ IF_ENABLED(SPI_BUFFER_IN_RAM, \ - (.buffer = spim_##idx##_buffer,)) \ + (.tx_buffer = spim_##idx##_tx_buffer, \ + .rx_buffer = spim_##idx##_rx_buffer,)) \ .dev = DEVICE_DT_GET(SPIM(idx)), \ .busy = false, \ }; \ @@ -639,7 +666,7 @@ static int spi_nrfx_init(const struct device *dev) .wake_pin = NRF_DT_GPIOS_TO_PSEL_OR(SPIM(idx), wake_gpios, \ WAKE_PIN_NOT_USED), \ }; \ - BUILD_ASSERT(!DT_NODE_HAS_PROP(SPIM(idx), wake_gpios) || \ + BUILD_ASSERT(!SPIM_HAS_PROP(idx, wake_gpios) || \ !(DT_GPIO_FLAGS(SPIM(idx), wake_gpios) & GPIO_ACTIVE_LOW),\ "WAKE line must be configured as active high"); \ PM_DEVICE_DT_DEFINE(SPIM(idx), spim_nrfx_pm_action); \ From c88b492842b3021efeb42dd181406c9b30c07c44 Mon Sep 17 00:00:00 2001 From: Adam Wojasinski Date: Thu, 16 Nov 2023 12:22:08 +0100 Subject: [PATCH 1243/3723] drivers: spi: nrfx: Update doc for RAM_BUFFER_SIZE Kconfig symbol Update documentation for SPI_NRFX_RAM_BUFFER_SIZE Kconfig symbol to reflect new usage of it. Now the symbol specifies size of RX buffer. The change introducing support for RX buffer placed by a linker in memory region defined in SPIM devicetree node is in a parent commit of that one. Signed-off-by: Adam Wojasinski --- drivers/spi/Kconfig.nrfx | 22 ++++++++++++++-------- 1 file changed, 14 insertions(+), 8 deletions(-) diff --git a/drivers/spi/Kconfig.nrfx b/drivers/spi/Kconfig.nrfx index 611bad822b2..0ee1c03065b 100644 --- a/drivers/spi/Kconfig.nrfx +++ b/drivers/spi/Kconfig.nrfx @@ -75,14 +75,20 @@ config SPI_NRFX_RAM_BUFFER_SIZE default 8 depends on SPI_NRFX_SPIM help - SPIM peripherals cannot transmit data directly from flash. Therefore, - a buffer in RAM needs to be provided for each instance of SPI driver - using SPIM peripheral, so that the driver can copy there a chunk of - data from flash and transmit it. - The size is specified in bytes. A size of 0 means that this feature - should be disabled, and the application must then take care of not - supplying buffers located in flash to the driver, otherwise such - transfers will fail. + Because of using EasyDMA, SPIM peripherals cannot use transmit and + receive buffers from all memory locations. They are restricted to + buffers located in certain RAM memories only. Therefore, each SPIM + driver instance needs to use an intermediate local RAM buffer, + to transfer data in chunks not exceeding the size of that buffer, + and to copy those chunks between the local buffer and the one + specified in the transfer request if the latter is not accessible + by EasyDMA. + + This option specifies the size in bytes of such local RAM buffers + for both TX and RX paths. A size of 0 means that this feature should + be disabled and the driver user must take care of not making transfer + requests with buffers not accessible by EasyDMA since such transfers + will fail. config SPI_NRFX_WAKE_TIMEOUT_US int "Maximum time to wait for SPI slave to wake up" From c6b6f7451000680e7c814f6291a525e41b81d06b Mon Sep 17 00:00:00 2001 From: Jukka Rissanen Date: Mon, 4 Dec 2023 17:49:31 +0200 Subject: [PATCH 1244/3723] net: socket: Group various defines together for documentation Groupped various defines in socket.h together based on their usage. This groupping is only for documentation. Fixes #66081 Signed-off-by: Jukka Rissanen --- include/zephyr/net/socket.h | 77 +++++++++++++++++++++++++++++++------ 1 file changed, 66 insertions(+), 11 deletions(-) diff --git a/include/zephyr/net/socket.h b/include/zephyr/net/socket.h index 7be9faa68f1..05af3248bdd 100644 --- a/include/zephyr/net/socket.h +++ b/include/zephyr/net/socket.h @@ -41,6 +41,10 @@ struct zsock_pollfd { short revents; }; +/** + * @name Options for poll() + * @{ + */ /* ZSOCK_POLL* values are compatible with Linux */ /** zsock_poll: Poll for readability */ #define ZSOCK_POLLIN 1 @@ -54,7 +58,12 @@ struct zsock_pollfd { #define ZSOCK_POLLHUP 0x10 /** zsock_poll: Invalid socket (output value only) */ #define ZSOCK_POLLNVAL 0x20 +/** @} */ +/** + * @name Options for sending and receiving data + * @{ + */ /** zsock_recv: Read data without removing it from socket input queue */ #define ZSOCK_MSG_PEEK 0x02 /** zsock_recvmsg: Control data buffer too small. @@ -68,7 +77,12 @@ struct zsock_pollfd { #define ZSOCK_MSG_DONTWAIT 0x40 /** zsock_recv: block until the full amount of data can be returned */ #define ZSOCK_MSG_WAITALL 0x100 +/** @} */ +/** + * @name Options for shutdown() function + * @{ + */ /* Well-known values, e.g. from Linux man 2 shutdown: * "The constants SHUT_RD, SHUT_WR, SHUT_RDWR have the value 0, 1, 2, * respectively". Some software uses numeric values. @@ -79,6 +93,7 @@ struct zsock_pollfd { #define ZSOCK_SHUT_WR 1 /** zsock_shutdown: Shut down for both reading and writing */ #define ZSOCK_SHUT_RDWR 2 +/** @} */ /** Protocol level for TLS. * Here, the same socket protocol level for TLS as in Linux was used. @@ -670,6 +685,10 @@ __syscall int z_zsock_getaddrinfo_internal(const char *host, /* Flags for getaddrinfo() hints. */ +/** + * @name Flags for getaddrinfo() hints + * @{ + */ /** Address for bind() (vs for connect()) */ #define AI_PASSIVE 0x1 /** Fill in ai_canonname */ @@ -684,6 +703,7 @@ __syscall int z_zsock_getaddrinfo_internal(const char *host, #define AI_ADDRCONFIG 0x20 /** Assume service (port) is numeric */ #define AI_NUMERICSERV 0x400 +/** @} */ /** * @brief Resolve a domain name to one or more network addresses @@ -729,6 +749,10 @@ void zsock_freeaddrinfo(struct zsock_addrinfo *ai); */ const char *zsock_gai_strerror(int errcode); +/** + * @name Flags for getnameinfo() + * @{ + */ /** zsock_getnameinfo(): Resolve to numeric address. */ #define NI_NUMERICHOST 1 /** zsock_getnameinfo(): Resolve to numeric port number. */ @@ -746,6 +770,7 @@ const char *zsock_gai_strerror(int errcode); #ifndef NI_MAXHOST #define NI_MAXHOST 64 #endif +/** @} */ /** * @brief Resolve a network address to a domain name or ASCII address @@ -1020,6 +1045,10 @@ static inline char *inet_ntop(sa_family_t family, const void *src, char *dst, #define EAI_FAMILY DNS_EAI_FAMILY #endif /* defined(CONFIG_NET_SOCKETS_POSIX_NAMES) */ +/** + * @name Network interface name description + * @{ + */ #if defined(CONFIG_NET_INTERFACE_NAME) #define IFNAMSIZ CONFIG_NET_INTERFACE_NAME_LEN #else @@ -1030,7 +1059,12 @@ static inline char *inet_ntop(sa_family_t family, const void *src, char *dst, struct ifreq { char ifr_name[IFNAMSIZ]; /* Interface name */ }; +/** @} */ +/** + * @name Socket level options + * @{ + */ /** sockopt: Socket-level option */ #define SOL_SOCKET 1 @@ -1058,6 +1092,8 @@ struct ifreq { #define SO_KEEPALIVE 9 /** sockopt: Place out-of-band data into receive stream (ignored, for compatibility) */ #define SO_OOBINLINE 10 +/** sockopt: Socket priority */ +#define SO_PRIORITY 12 /** sockopt: Socket lingers on close (ignored, for compatibility) */ #define SO_LINGER 13 /** sockopt: Allow multiple sockets to reuse a single port */ @@ -1090,8 +1126,20 @@ struct ifreq { /** sockopt: Domain used with SOCKET (ignored, for compatibility) */ #define SO_DOMAIN 39 +/** sockopt: Enable SOCKS5 for Socket */ +#define SO_SOCKS5 60 + +/** sockopt: Socket TX time (when the data should be sent) */ +#define SO_TXTIME 61 +#define SCM_TXTIME SO_TXTIME + /** End Socket options for SOL_SOCKET level */ +/** @} */ +/** + * @name TCP level options + * @{ + */ /* Socket options for IPPROTO_TCP level */ /** sockopt: Disable TCP buffering (ignored, for compatibility) */ #define TCP_NODELAY 1 @@ -1102,6 +1150,12 @@ struct ifreq { /** Number of keepalives before dropping connection */ #define TCP_KEEPCNT 4 +/** @} */ + +/** + * @name IPv4 level options + * @{ + */ /* Socket options for IPPROTO_IP level */ /** sockopt: Set or receive the Type-Of-Service value for an outgoing packet. */ #define IP_TOS 1 @@ -1134,6 +1188,12 @@ struct ip_mreqn { int imr_ifindex; /* interface index */ }; +/** @} */ + +/** + * @name IPv6 level options + * @{ + */ /* Socket options for IPPROTO_IPV6 level */ /** sockopt: Set the unicast hop limit for the socket. */ #define IPV6_UNICAST_HOPS 16 @@ -1171,20 +1231,15 @@ struct in6_pktinfo { /** sockopt: Set or receive the traffic class value for an outgoing packet. */ #define IPV6_TCLASS 67 +/** @} */ -/** sockopt: Socket priority */ -#define SO_PRIORITY 12 - -/** sockopt: Socket TX time (when the data should be sent) */ -#define SO_TXTIME 61 -#define SCM_TXTIME SO_TXTIME - -/* Socket options for SOCKS5 proxy */ -/** sockopt: Enable SOCKS5 for Socket */ -#define SO_SOCKS5 60 - +/** + * @name Backlog size for listen() + * @{ + */ /** listen: The maximum backlog queue length (ignored, for compatibility) */ #define SOMAXCONN 128 +/** @} */ /** @cond INTERNAL_HIDDEN */ /** From bbd029a087328bd87e517acf45f040ee35b7c32c Mon Sep 17 00:00:00 2001 From: Jukka Rissanen Date: Mon, 4 Dec 2023 17:51:04 +0200 Subject: [PATCH 1245/3723] net: socket: TLS doc group was missing defines Couple of TLS defines were not in correct documentation group. Add also missing doxygen comments for TLS defines. Signed-off-by: Jukka Rissanen --- include/zephyr/net/socket.h | 52 ++++++++++++++++++++++--------------- 1 file changed, 31 insertions(+), 21 deletions(-) diff --git a/include/zephyr/net/socket.h b/include/zephyr/net/socket.h index 05af3248bdd..b40feeb5bbf 100644 --- a/include/zephyr/net/socket.h +++ b/include/zephyr/net/socket.h @@ -95,15 +95,19 @@ struct zsock_pollfd { #define ZSOCK_SHUT_RDWR 2 /** @} */ -/** Protocol level for TLS. - * Here, the same socket protocol level for TLS as in Linux was used. - */ -#define SOL_TLS 282 - /** * @defgroup secure_sockets_options Socket options for TLS * @{ */ +/** + * @name Socket options for TLS + * @{ + */ + +/** Protocol level for TLS. + * Here, the same socket protocol level for TLS as in Linux was used. + */ +#define SOL_TLS 282 /** Socket option to select TLS credentials to use. It accepts and returns an * array of sec_tag_t that indicate which TLS credentials should be used with @@ -152,11 +156,16 @@ struct zsock_pollfd { * the TLS handshake. */ #define TLS_ALPN_LIST 7 -/** Socket option to set DTLS handshake timeout. The timeout starts at min, +/** Socket option to set DTLS min handshake timeout. The timeout starts at min, * and upon retransmission the timeout is doubled util max is reached. * Min and max arguments are separate options. The time unit is ms. */ #define TLS_DTLS_HANDSHAKE_TIMEOUT_MIN 8 + +/** Socket option to set DTLS max handshake timeout. The timeout starts at min, + * and upon retransmission the timeout is doubled util max is reached. + * Min and max arguments are separate options. The time unit is ms. + */ #define TLS_DTLS_HANDSHAKE_TIMEOUT_MAX 9 /** Socket option for preventing certificates from being copied to the mbedTLS @@ -218,35 +227,36 @@ struct zsock_pollfd { * connection ID, otherwise will contain the length of the CID value. */ #define TLS_DTLS_PEER_CID_VALUE 17 -/** @} */ -/* Valid values for TLS_PEER_VERIFY option */ +/* Valid values for @ref TLS_PEER_VERIFY option */ #define TLS_PEER_VERIFY_NONE 0 /**< Peer verification disabled. */ #define TLS_PEER_VERIFY_OPTIONAL 1 /**< Peer verification optional. */ #define TLS_PEER_VERIFY_REQUIRED 2 /**< Peer verification required. */ -/* Valid values for TLS_DTLS_ROLE option */ +/* Valid values for @ref TLS_DTLS_ROLE option */ #define TLS_DTLS_ROLE_CLIENT 0 /**< Client role in a DTLS session. */ #define TLS_DTLS_ROLE_SERVER 1 /**< Server role in a DTLS session. */ -/* Valid values for TLS_CERT_NOCOPY option */ +/* Valid values for @ref TLS_CERT_NOCOPY option */ #define TLS_CERT_NOCOPY_NONE 0 /**< Cert duplicated in heap */ #define TLS_CERT_NOCOPY_OPTIONAL 1 /**< Cert not copied in heap if DER */ -/* Valid values for TLS_SESSION_CACHE option */ +/* Valid values for @ref TLS_SESSION_CACHE option */ #define TLS_SESSION_CACHE_DISABLED 0 /**< Disable TLS session caching. */ #define TLS_SESSION_CACHE_ENABLED 1 /**< Enable TLS session caching. */ -/* Valid values for TLS_DTLS_CID option */ -#define TLS_DTLS_CID_DISABLED 0 -#define TLS_DTLS_CID_SUPPORTED 1 -#define TLS_DTLS_CID_ENABLED 2 - -/* Valid values for TLS_DTLS_CID_STATUS option */ -#define TLS_DTLS_CID_STATUS_DISABLED 0 -#define TLS_DTLS_CID_STATUS_DOWNLINK 1 -#define TLS_DTLS_CID_STATUS_UPLINK 2 -#define TLS_DTLS_CID_STATUS_BIDIRECTIONAL 3 +/* Valid values for @ref TLS_DTLS_CID (Connection ID) option */ +#define TLS_DTLS_CID_DISABLED 0 /**< CID is disabled */ +#define TLS_DTLS_CID_SUPPORTED 1 /**< CID is supported */ +#define TLS_DTLS_CID_ENABLED 2 /**< CID is enabled */ + +/* Valid values for @ref TLS_DTLS_CID_STATUS option */ +#define TLS_DTLS_CID_STATUS_DISABLED 0 /**< CID is disabled */ +#define TLS_DTLS_CID_STATUS_DOWNLINK 1 /**< CID is in use by us */ +#define TLS_DTLS_CID_STATUS_UPLINK 2 /**< CID is in use by peer */ +#define TLS_DTLS_CID_STATUS_BIDIRECTIONAL 3 /**< CID is in use by us and peer */ +/** @} */ /* for @name */ +/** @} */ /* for @defgroup */ struct zsock_addrinfo { struct zsock_addrinfo *ai_next; From 124f874bed4032f997a715a7d947b737ed3c861b Mon Sep 17 00:00:00 2001 From: Jukka Rissanen Date: Tue, 5 Dec 2023 10:06:34 +0200 Subject: [PATCH 1246/3723] net: socket: Update socket option documentation Remove redundant information from socket option documentation. Signed-off-by: Jukka Rissanen --- include/zephyr/net/socket.h | 87 +++++++++++++++++++------------------ 1 file changed, 44 insertions(+), 43 deletions(-) diff --git a/include/zephyr/net/socket.h b/include/zephyr/net/socket.h index b40feeb5bbf..41585d588df 100644 --- a/include/zephyr/net/socket.h +++ b/include/zephyr/net/socket.h @@ -1059,6 +1059,7 @@ static inline char *inet_ntop(sa_family_t family, const void *src, char *dst, * @name Network interface name description * @{ */ +/** Network interface name length */ #if defined(CONFIG_NET_INTERFACE_NAME) #define IFNAMSIZ CONFIG_NET_INTERFACE_NAME_LEN #else @@ -1072,86 +1073,86 @@ struct ifreq { /** @} */ /** - * @name Socket level options + * @name Socket level options (SOL_SOCKET) * @{ */ -/** sockopt: Socket-level option */ +/** Socket-level option */ #define SOL_SOCKET 1 /* Socket options for SOL_SOCKET level */ -/** sockopt: Recording debugging information (ignored, for compatibility) */ +/** Recording debugging information (ignored, for compatibility) */ #define SO_DEBUG 1 -/** sockopt: address reuse */ +/** address reuse */ #define SO_REUSEADDR 2 -/** sockopt: Type of the socket */ +/** Type of the socket */ #define SO_TYPE 3 -/** sockopt: Async error (ignored, for compatibility) */ +/** Async error (ignored, for compatibility) */ #define SO_ERROR 4 -/** sockopt: Bypass normal routing and send directly to host (ignored, for compatibility) */ +/** Bypass normal routing and send directly to host (ignored, for compatibility) */ #define SO_DONTROUTE 5 -/** sockopt: Transmission of broadcast messages is supported (ignored, for compatibility) */ +/** Transmission of broadcast messages is supported (ignored, for compatibility) */ #define SO_BROADCAST 6 -/** sockopt: Size of socket send buffer */ +/** Size of socket send buffer */ #define SO_SNDBUF 7 -/** sockopt: Size of socket recv buffer */ +/** Size of socket recv buffer */ #define SO_RCVBUF 8 /** Enable sending keep-alive messages on connections */ #define SO_KEEPALIVE 9 -/** sockopt: Place out-of-band data into receive stream (ignored, for compatibility) */ +/** Place out-of-band data into receive stream (ignored, for compatibility) */ #define SO_OOBINLINE 10 -/** sockopt: Socket priority */ +/** Socket priority */ #define SO_PRIORITY 12 -/** sockopt: Socket lingers on close (ignored, for compatibility) */ +/** Socket lingers on close (ignored, for compatibility) */ #define SO_LINGER 13 -/** sockopt: Allow multiple sockets to reuse a single port */ +/** Allow multiple sockets to reuse a single port */ #define SO_REUSEPORT 15 -/** sockopt: Receive low watermark (ignored, for compatibility) */ +/** Receive low watermark (ignored, for compatibility) */ #define SO_RCVLOWAT 18 -/** sockopt: Send low watermark (ignored, for compatibility) */ +/** Send low watermark (ignored, for compatibility) */ #define SO_SNDLOWAT 19 /** - * sockopt: Receive timeout + * Receive timeout * Applies to receive functions like recv(), but not to connect() */ #define SO_RCVTIMEO 20 -/** sockopt: Send timeout */ +/** Send timeout */ #define SO_SNDTIMEO 21 -/** sockopt: Bind a socket to an interface */ +/** Bind a socket to an interface */ #define SO_BINDTODEVICE 25 -/** sockopt: Socket accepts incoming connections (ignored, for compatibility) */ +/** Socket accepts incoming connections (ignored, for compatibility) */ #define SO_ACCEPTCONN 30 -/** sockopt: Timestamp TX packets */ +/** Timestamp TX packets */ #define SO_TIMESTAMPING 37 -/** sockopt: Protocol used with the socket */ +/** Protocol used with the socket */ #define SO_PROTOCOL 38 -/** sockopt: Domain used with SOCKET (ignored, for compatibility) */ +/** Domain used with SOCKET (ignored, for compatibility) */ #define SO_DOMAIN 39 -/** sockopt: Enable SOCKS5 for Socket */ +/** Enable SOCKS5 for Socket */ #define SO_SOCKS5 60 -/** sockopt: Socket TX time (when the data should be sent) */ +/** Socket TX time (when the data should be sent) */ #define SO_TXTIME 61 +/** Socket TX time (same as SO_TXTIME) */ #define SCM_TXTIME SO_TXTIME -/** End Socket options for SOL_SOCKET level */ /** @} */ /** - * @name TCP level options + * @name TCP level options (IPPROTO_TCP) * @{ */ /* Socket options for IPPROTO_TCP level */ -/** sockopt: Disable TCP buffering (ignored, for compatibility) */ +/** Disable TCP buffering (ignored, for compatibility) */ #define TCP_NODELAY 1 /** Start keepalives after this period (seconds) */ #define TCP_KEEPIDLE 2 @@ -1163,17 +1164,17 @@ struct ifreq { /** @} */ /** - * @name IPv4 level options + * @name IPv4 level options (IPPROTO_IP) * @{ */ /* Socket options for IPPROTO_IP level */ -/** sockopt: Set or receive the Type-Of-Service value for an outgoing packet. */ +/** Set or receive the Type-Of-Service value for an outgoing packet. */ #define IP_TOS 1 -/** sockopt: Set or receive the Time-To-Live value for an outgoing packet. */ +/** Set or receive the Time-To-Live value for an outgoing packet. */ #define IP_TTL 2 -/** sockopt: Pass an IP_PKTINFO ancillary message that contains a +/** Pass an IP_PKTINFO ancillary message that contains a * pktinfo structure that supplies some information about the * incoming packet. */ @@ -1185,11 +1186,11 @@ struct in_pktinfo { struct in_addr ipi_addr; /* Header Destination address */ }; -/** sockopt: Set IPv4 multicast TTL value. */ +/** Set IPv4 multicast TTL value. */ #define IP_MULTICAST_TTL 33 -/** sockopt: Join IPv4 multicast group. */ +/** Join IPv4 multicast group. */ #define IP_ADD_MEMBERSHIP 35 -/** sockopt: Leave IPv4 multicast group. */ +/** Leave IPv4 multicast group. */ #define IP_DROP_MEMBERSHIP 36 struct ip_mreqn { @@ -1201,20 +1202,20 @@ struct ip_mreqn { /** @} */ /** - * @name IPv6 level options + * @name IPv6 level options (IPPROTO_IPV6) * @{ */ /* Socket options for IPPROTO_IPV6 level */ -/** sockopt: Set the unicast hop limit for the socket. */ +/** Set the unicast hop limit for the socket. */ #define IPV6_UNICAST_HOPS 16 -/** sockopt: Set the multicast hop limit for the socket. */ +/** Set the multicast hop limit for the socket. */ #define IPV6_MULTICAST_HOPS 18 -/** sockopt: Join IPv6 multicast group. */ +/** Join IPv6 multicast group. */ #define IPV6_ADD_MEMBERSHIP 20 -/** sockopt: Leave IPv6 multicast group. */ +/** Leave IPv6 multicast group. */ #define IPV6_DROP_MEMBERSHIP 21 struct ipv6_mreq { @@ -1225,10 +1226,10 @@ struct ipv6_mreq { int ipv6mr_ifindex; }; -/** sockopt: Don't support IPv4 access */ +/** Don't support IPv4 access */ #define IPV6_V6ONLY 26 -/** sockopt: Pass an IPV6_RECVPKTINFO ancillary message that contains a +/** Pass an IPV6_RECVPKTINFO ancillary message that contains a * in6_pktinfo structure that supplies some information about the * incoming packet. See RFC 3542. */ @@ -1239,7 +1240,7 @@ struct in6_pktinfo { unsigned int ipi6_ifindex; /* send/recv interface index */ }; -/** sockopt: Set or receive the traffic class value for an outgoing packet. */ +/** Set or receive the traffic class value for an outgoing packet. */ #define IPV6_TCLASS 67 /** @} */ From 43c1b8917f32c0d4a2765ea515c7696acc95217a Mon Sep 17 00:00:00 2001 From: Jukka Rissanen Date: Tue, 5 Dec 2023 10:41:24 +0200 Subject: [PATCH 1247/3723] net: socket: Add missing doxygen documentation Add doxygen comments to those APIs where they were missing and were relevant. Signed-off-by: Jukka Rissanen --- include/zephyr/net/socket.h | 86 +++++++++++++++++++++++++++---------- 1 file changed, 64 insertions(+), 22 deletions(-) diff --git a/include/zephyr/net/socket.h b/include/zephyr/net/socket.h index 41585d588df..ca57f9f397e 100644 --- a/include/zephyr/net/socket.h +++ b/include/zephyr/net/socket.h @@ -35,10 +35,15 @@ extern "C" { #endif +/** + * @brief Definition of the monitored socket/file descriptor. + * + * An array of these descriptors is passed as an argument to poll(). + */ struct zsock_pollfd { - int fd; - short events; - short revents; + int fd; /**< Socket descriptor */ + short events; /**< Requested events */ + short revents; /**< Returned events */ }; /** @@ -258,18 +263,26 @@ struct zsock_pollfd { /** @} */ /* for @name */ /** @} */ /* for @defgroup */ +/** + * @brief Definition used when querying address information. + * + * A linked list of these descriptors is returned by getaddrinfo(). The struct + * is also passed as hints when calling the getaddrinfo() function. + */ struct zsock_addrinfo { - struct zsock_addrinfo *ai_next; - int ai_flags; - int ai_family; - int ai_socktype; - int ai_protocol; - socklen_t ai_addrlen; - struct sockaddr *ai_addr; - char *ai_canonname; + struct zsock_addrinfo *ai_next; /**< Pointer to next address entry */ + int ai_flags; /**< Additional options */ + int ai_family; /**< Address family of the returned addresses */ + int ai_socktype; /**< Socket type, for example SOCK_STREAM or SOCK_DGRAM */ + int ai_protocol; /**< Protocol for addresses, 0 means any protocol */ + socklen_t ai_addrlen; /**< Length of the socket address */ + struct sockaddr *ai_addr; /**< Pointer to the address */ + char *ai_canonname; /**< Optional official name of the host */ +/** @cond INTERNAL_HIDDEN */ struct sockaddr _ai_addr; char _ai_canonname[DNS_MAX_NAME_SIZE + 1]; +/** @endcond */ }; /** @@ -800,6 +813,12 @@ int zsock_getnameinfo(const struct sockaddr *addr, socklen_t addrlen, #if defined(CONFIG_NET_SOCKETS_POSIX_NAMES) +/** + * @name Socket APIs available if CONFIG_NET_SOCKETS_POSIX_NAMES is enabled + * @{ + */ + +/** POSIX wrapper for @ref zsock_pollfd */ #define pollfd zsock_pollfd /** POSIX wrapper for @ref zsock_socket */ @@ -863,6 +882,7 @@ static inline ssize_t recv(int sock, void *buf, size_t max_len, int flags) return zsock_recv(sock, buf, max_len, flags); } +/** @cond INTERNAL_HIDDEN */ /* * Need this wrapper because newer GCC versions got too smart and "typecheck" * even macros, so '#define fcntl zsock_fcntl' leads to error. @@ -879,7 +899,9 @@ static inline int zsock_fcntl_wrapper(int sock, int cmd, ...) } #define fcntl zsock_fcntl_wrapper +/** @endcond */ +/** POSIX wrapper for @ref zsock_ioctl */ static inline int ioctl(int sock, unsigned long request, ...) { int ret; @@ -983,6 +1005,7 @@ static inline int getnameinfo(const struct sockaddr *addr, socklen_t addrlen, serv, servlen, flags); } +/** POSIX wrapper for @ref zsock_addrinfo */ #define addrinfo zsock_addrinfo /** POSIX wrapper for @ref zsock_gethostname */ @@ -1053,6 +1076,7 @@ static inline char *inet_ntop(sa_family_t family, const void *src, char *dst, #define EAI_SOCKTYPE DNS_EAI_SOCKTYPE /** POSIX wrapper for @ref DNS_EAI_FAMILY */ #define EAI_FAMILY DNS_EAI_FAMILY +/** @} */ #endif /* defined(CONFIG_NET_SOCKETS_POSIX_NAMES) */ /** @@ -1068,7 +1092,7 @@ static inline char *inet_ntop(sa_family_t family, const void *src, char *dst, /** Interface description structure */ struct ifreq { - char ifr_name[IFNAMSIZ]; /* Interface name */ + char ifr_name[IFNAMSIZ]; /**< Network interface name */ }; /** @} */ @@ -1180,10 +1204,16 @@ struct ifreq { */ #define IP_PKTINFO 8 +/** + * @brief Incoming IPv4 packet information. + * + * Used as ancillary data when calling recvmsg() and IP_PKTINFO socket + * option is set. + */ struct in_pktinfo { - unsigned int ipi_ifindex; /* Interface index */ - struct in_addr ipi_spec_dst; /* Local address */ - struct in_addr ipi_addr; /* Header Destination address */ + unsigned int ipi_ifindex; /**< Network interface index */ + struct in_addr ipi_spec_dst; /**< Local address */ + struct in_addr ipi_addr; /**< Header Destination address */ }; /** Set IPv4 multicast TTL value. */ @@ -1193,10 +1223,13 @@ struct in_pktinfo { /** Leave IPv4 multicast group. */ #define IP_DROP_MEMBERSHIP 36 +/** + * @brief Struct used when joining or leaving a IPv4 multicast group. + */ struct ip_mreqn { - struct in_addr imr_multiaddr; /* IP multicast group address */ - struct in_addr imr_address; /* IP address of local interface */ - int imr_ifindex; /* interface index */ + struct in_addr imr_multiaddr; /**< IP multicast group address */ + struct in_addr imr_address; /**< IP address of local interface */ + int imr_ifindex; /**< Network interface index */ }; /** @} */ @@ -1218,11 +1251,14 @@ struct ip_mreqn { /** Leave IPv6 multicast group. */ #define IPV6_DROP_MEMBERSHIP 21 +/** + * @brief Struct used when joining or leaving a IPv6 multicast group. + */ struct ipv6_mreq { - /* IPv6 multicast address of group */ + /** IPv6 multicast address of group */ struct in6_addr ipv6mr_multiaddr; - /* Interface index of the local IPv6 address */ + /** Network interface index of the local IPv6 address */ int ipv6mr_ifindex; }; @@ -1235,9 +1271,15 @@ struct ipv6_mreq { */ #define IPV6_RECVPKTINFO 49 +/** + * @brief Incoming IPv6 packet information. + * + * Used as ancillary data when calling recvmsg() and IPV6_RECVPKTINFO socket + * option is set. + */ struct in6_pktinfo { - struct in6_addr ipi6_addr; /* src/dst IPv6 address */ - unsigned int ipi6_ifindex; /* send/recv interface index */ + struct in6_addr ipi6_addr; /**< Destination IPv6 address */ + unsigned int ipi6_ifindex; /**< Receive interface index */ }; /** Set or receive the traffic class value for an outgoing packet. */ From af0336ed19228e1350fcc7fe7de4321ffd0ac830 Mon Sep 17 00:00:00 2001 From: Jukka Rissanen Date: Tue, 5 Dec 2023 10:48:00 +0200 Subject: [PATCH 1248/3723] net: socket: Remove "ignored" comment from supported symbols Some socket symbols were marked as "ignored" even when they are in fact supported. Signed-off-by: Jukka Rissanen --- include/zephyr/net/socket.h | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/include/zephyr/net/socket.h b/include/zephyr/net/socket.h index ca57f9f397e..a61b8604973 100644 --- a/include/zephyr/net/socket.h +++ b/include/zephyr/net/socket.h @@ -53,7 +53,7 @@ struct zsock_pollfd { /* ZSOCK_POLL* values are compatible with Linux */ /** zsock_poll: Poll for readability */ #define ZSOCK_POLLIN 1 -/** zsock_poll: Compatibility value, ignored */ +/** zsock_poll: Poll for exceptional condition */ #define ZSOCK_POLLPRI 2 /** zsock_poll: Poll for writability */ #define ZSOCK_POLLOUT 4 @@ -1111,7 +1111,7 @@ struct ifreq { #define SO_REUSEADDR 2 /** Type of the socket */ #define SO_TYPE 3 -/** Async error (ignored, for compatibility) */ +/** Async error */ #define SO_ERROR 4 /** Bypass normal routing and send directly to host (ignored, for compatibility) */ #define SO_DONTROUTE 5 @@ -1290,7 +1290,7 @@ struct in6_pktinfo { * @name Backlog size for listen() * @{ */ -/** listen: The maximum backlog queue length (ignored, for compatibility) */ +/** listen: The maximum backlog queue length */ #define SOMAXCONN 128 /** @} */ From e7039bc37fff43f272e0e6b6e47c796944728788 Mon Sep 17 00:00:00 2001 From: Zoltan Havas Date: Mon, 11 Sep 2023 15:03:15 +0200 Subject: [PATCH 1249/3723] zephyr: Kconfig: SOC_GECKO_CUSTOM_RADIO_PHY option for RAIL for proprietary Currently on zephyr, RAIL library is used only by Bluetooth applications, with this update, it will be able to be used for sample applications for custom radio phys. All files were copied from Silicon Labs GSDK v4.2.4. Signed-off-by: Zoltan Havas --- soc/arm/silabs_exx32/Kconfig | 9 +++++++++ west.yml | 2 +- 2 files changed, 10 insertions(+), 1 deletion(-) diff --git a/soc/arm/silabs_exx32/Kconfig b/soc/arm/silabs_exx32/Kconfig index d0bbf68c885..60bda813903 100644 --- a/soc/arm/silabs_exx32/Kconfig +++ b/soc/arm/silabs_exx32/Kconfig @@ -340,4 +340,13 @@ config SOC_GECKO_USE_RAIL 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_EXX32 diff --git a/west.yml b/west.yml index 261740c1d26..2208fa9ad80 100644 --- a/west.yml +++ b/west.yml @@ -219,7 +219,7 @@ manifest: groups: - hal - name: hal_silabs - revision: d191d981c4eb20c0c7445a4061fcdbcfa686113a + revision: 72a67203f0b37dc2c12bfae5ddf05c991c0ab0a4 path: modules/hal/silabs groups: - hal From d8ec9118b48232aecb285f31dea651f5847d32d2 Mon Sep 17 00:00:00 2001 From: Jukka Rissanen Date: Tue, 21 Nov 2023 10:29:05 +0200 Subject: [PATCH 1250/3723] net: if: Interface stays down if device is not ready It is pointless to take net interface up if the underlaying device is not ready. Set also the interface status properly in this case. Fixes #65423 Signed-off-by: Jukka Rissanen --- subsys/net/ip/net_if.c | 26 ++++++++++++++++++++++++++ 1 file changed, 26 insertions(+) diff --git a/subsys/net/ip/net_if.c b/subsys/net/ip/net_if.c index 551adb50c91..bb6099b9781 100644 --- a/subsys/net/ip/net_if.c +++ b/subsys/net/ip/net_if.c @@ -4388,6 +4388,11 @@ static void update_operational_state(struct net_if *iface) goto exit; } + if (!device_is_ready(net_if_get_device(iface))) { + new_state = NET_IF_OPER_LOWERLAYERDOWN; + goto exit; + } + if (!net_if_is_carrier_ok(iface)) { #if defined(CONFIG_NET_L2_VIRTUAL) if (net_if_l2(iface) == &NET_L2_GET_NAME(VIRTUAL)) { @@ -4462,6 +4467,27 @@ int net_if_up(struct net_if *iface) /* If the L2 does not support enable just set the flag */ if (!net_if_l2(iface) || !net_if_l2(iface)->enable) { goto done; + } else { + /* If the L2 does not implement enable(), then the network + * device driver cannot implement start(), in which case + * we can do simple check here and not try to bring interface + * up as the device is not ready. + * + * If the network device driver does implement start(), then + * it could bring the interface up when the enable() is called + * few lines below. + */ + const struct device *dev; + + dev = net_if_get_device(iface); + NET_ASSERT(dev); + + /* If the device is not ready it is pointless trying to take it up. */ + if (!device_is_ready(dev)) { + NET_DBG("Device %s (%p) is not ready", dev->name, dev); + status = -ENXIO; + goto out; + } } /* Notify L2 to enable the interface */ From 67d21c8b1db131e46ceb505e7e36f30bff2afe08 Mon Sep 17 00:00:00 2001 From: Jukka Rissanen Date: Tue, 21 Nov 2023 10:31:48 +0200 Subject: [PATCH 1251/3723] tests: net: if: Add test to check device readiness Add tests that check if device is ready or not, and then verify the functionality of net_if_up() in that case. Signed-off-by: Jukka Rissanen --- tests/net/iface/src/main.c | 52 ++++++++++++++++++++++++++++++++++++-- 1 file changed, 50 insertions(+), 2 deletions(-) diff --git a/tests/net/iface/src/main.c b/tests/net/iface/src/main.c index b33845608d6..37567af9a81 100644 --- a/tests/net/iface/src/main.c +++ b/tests/net/iface/src/main.c @@ -66,6 +66,7 @@ static struct net_if *iface4; static bool test_failed; static bool test_started; static struct k_sem wait_data; +static bool device_ok; #define WAIT_TIME 250 @@ -103,6 +104,15 @@ static void net_iface_init(struct net_if *iface) NET_LINK_ETHERNET); } +static int dev_init(const struct device *dev) +{ + if (device_ok == false) { + return -EAGAIN; + } + + return 0; +} + static int sender_iface(const struct device *dev, struct net_pkt *pkt) { if (!pkt->buffer) { @@ -144,7 +154,7 @@ static struct dummy_api net_iface_api = { NET_DEVICE_INIT_INSTANCE(net_iface1_test, "iface1", iface1, - NULL, + dev_init, NULL, &net_iface1_data, NULL, @@ -314,7 +324,9 @@ static void *iface_setup(void) { struct net_if_mcast_addr *maddr; struct net_if_addr *ifaddr; - int idx; + const struct device *dev; + bool status; + int idx, ret; /* The semaphore is there to wait the data to be received. */ k_sem_init(&wait_data, 0, UINT_MAX); @@ -342,6 +354,42 @@ static void *iface_setup(void) zassert_not_null(iface2, "Interface 2"); zassert_not_null(iface3, "Interface 3"); + /* Make sure that the first interface device is not ready */ + dev = net_if_get_device(iface1); + zassert_not_null(dev, "Device is not set!"); + + status = device_is_ready(dev); + zassert_equal(status, false, "Device %s (%p) is ready!", + dev->name, dev); + + /* Trying to take the interface up will fail */ + ret = net_if_up(iface1); + zassert_equal(ret, -ENXIO, "Interface 1 is up (%d)", ret); + + /* Try to set dormant state */ + net_if_dormant_on(iface1); + + /* Operational state should be "oper down" */ + zassert_equal(iface1->if_dev->oper_state, NET_IF_OPER_DOWN, + "Invalid operational state (%d)", + iface1->if_dev->oper_state); + + /* Mark the device ready and take the interface up */ + dev->state->init_res = 0; + device_ok = true; + + ret = net_if_up(iface1); + zassert_equal(ret, 0, "Interface 1 is not up (%d)", ret); + + zassert_equal(iface1->if_dev->oper_state, NET_IF_OPER_DORMANT, + "Invalid operational state (%d)", + iface1->if_dev->oper_state); + + net_if_dormant_off(iface1); + zassert_equal(iface1->if_dev->oper_state, NET_IF_OPER_UP, + "Invalid operational state (%d)", + iface1->if_dev->oper_state); + ifaddr = net_if_ipv6_addr_add(iface1, &my_addr1, NET_ADDR_MANUAL, 0); if (!ifaddr) { From b6aea97dc726d0d6e6e8d2b42e681762470fbd70 Mon Sep 17 00:00:00 2001 From: Jukka Rissanen Date: Wed, 13 Dec 2023 14:53:19 +0200 Subject: [PATCH 1252/3723] net: l2: dummy: Add start/stop API functions The dummy L2 layer does not implement any L2 functionality but it does not mean that it should not implement start/stop functions that are called when the related network interface is brought up or taken down. Signed-off-by: Jukka Rissanen --- include/zephyr/net/dummy.h | 6 ++++++ subsys/net/l2/dummy/dummy.c | 24 +++++++++++++++++++++++- 2 files changed, 29 insertions(+), 1 deletion(-) diff --git a/include/zephyr/net/dummy.h b/include/zephyr/net/dummy.h index d291f93d508..0be84c80191 100644 --- a/include/zephyr/net/dummy.h +++ b/include/zephyr/net/dummy.h @@ -31,6 +31,12 @@ struct dummy_api { /** Send a network packet */ int (*send)(const struct device *dev, struct net_pkt *pkt); + + /** Start the device. Called when the bound network interface is brought up. */ + int (*start)(const struct device *dev); + + /** Stop the device. Called when the bound network interface is taken down. */ + int (*stop)(const struct device *dev); }; /* Make sure that the network interface API is properly setup inside diff --git a/subsys/net/l2/dummy/dummy.c b/subsys/net/l2/dummy/dummy.c index f1ce5800b9a..0aec98c36c0 100644 --- a/subsys/net/l2/dummy/dummy.c +++ b/subsys/net/l2/dummy/dummy.c @@ -45,9 +45,31 @@ static inline int dummy_send(struct net_if *iface, struct net_pkt *pkt) return ret; } +static inline int dummy_enable(struct net_if *iface, bool state) +{ + int ret = 0; + const struct dummy_api *api = net_if_get_device(iface)->api; + + if (!api) { + return -ENOENT; + } + + if (!state) { + if (api->stop) { + ret = api->stop(net_if_get_device(iface)); + } + } else { + if (api->start) { + ret = api->start(net_if_get_device(iface)); + } + } + + return ret; +} + static enum net_l2_flags dummy_flags(struct net_if *iface) { return NET_L2_MULTICAST; } -NET_L2_INIT(DUMMY_L2, dummy_recv, dummy_send, NULL, dummy_flags); +NET_L2_INIT(DUMMY_L2, dummy_recv, dummy_send, dummy_enable, dummy_flags); From 28d5d23a232b69b213112e723e0a6392cbd5a47e Mon Sep 17 00:00:00 2001 From: Fabiola Kwasowiec Date: Thu, 14 Dec 2023 10:08:01 +0100 Subject: [PATCH 1253/3723] intel_adsp: lnl: add missing definition for lnl Definition of ADSP_FORCE_DECOUPLED_HDMA_L1_EXIT_BIT, which is used in the intel_adsp_force_dmi_l0_state function, is missing. Signed-off-by: Fabiola Kwasowiec --- soc/xtensa/intel_adsp/ace/include/intel_ace20_lnl/adsp_shim.h | 2 ++ 1 file changed, 2 insertions(+) diff --git a/soc/xtensa/intel_adsp/ace/include/intel_ace20_lnl/adsp_shim.h b/soc/xtensa/intel_adsp/ace/include/intel_ace20_lnl/adsp_shim.h index 363feb14fa0..f7661317062 100644 --- a/soc/xtensa/intel_adsp/ace/include/intel_ace20_lnl/adsp_shim.h +++ b/soc/xtensa/intel_adsp/ace/include/intel_ace20_lnl/adsp_shim.h @@ -170,4 +170,6 @@ struct ace_dfpmccu { #define GENO_MDIVOSEL BIT(1) #define GENO_DIOPTOSEL BIT(2) +#define ADSP_FORCE_DECOUPLED_HDMA_L1_EXIT_BIT BIT(1) + #endif /* ZEPHYR_SOC_INTEL_ADSP_SHIM_H_ */ From bf2bdcf6f79cf9711b1fdee3f2d91a5e61603f29 Mon Sep 17 00:00:00 2001 From: Arnaud Pouliquen Date: Thu, 14 Dec 2023 10:59:52 +0100 Subject: [PATCH 1254/3723] ipc_service: open-amp: Fix libmetal shared memory registration When using multiple instances of IPC static vring, each instance should register its shared memory with a unique name. Instead of a predefined default name, the name of the ipc instance is reused for the metal device name. Signed-off-by: Arnaud Pouliquen --- subsys/ipc/ipc_service/backends/ipc_rpmsg_static_vrings.c | 1 + subsys/ipc/ipc_service/lib/ipc_static_vrings.c | 7 ++++--- 2 files changed, 5 insertions(+), 3 deletions(-) diff --git a/subsys/ipc/ipc_service/backends/ipc_rpmsg_static_vrings.c b/subsys/ipc/ipc_service/backends/ipc_rpmsg_static_vrings.c index dcbff7b360c..20e29604fa5 100644 --- a/subsys/ipc/ipc_service/backends/ipc_rpmsg_static_vrings.c +++ b/subsys/ipc/ipc_service/backends/ipc_rpmsg_static_vrings.c @@ -555,6 +555,7 @@ static int open(const struct device *instance) data->vr.notify_cb = virtio_notify_cb; data->vr.priv = (void *) conf; + data->vr.shm_device.name = instance->name; err = ipc_static_vrings_init(&data->vr, conf->role); if (err != 0) { diff --git a/subsys/ipc/ipc_service/lib/ipc_static_vrings.c b/subsys/ipc/ipc_service/lib/ipc_static_vrings.c index be6c365a023..e23c5deafd5 100644 --- a/subsys/ipc/ipc_service/lib/ipc_static_vrings.c +++ b/subsys/ipc/ipc_service/lib/ipc_static_vrings.c @@ -7,7 +7,7 @@ #include #include -#define SHM_DEVICE_NAME "sram0.shm" +#define SHM_DEVICE_DEFAULT_NAME "sram0.shm" #define RPMSG_VQ_0 (0) /* TX virtqueue queue index */ #define RPMSG_VQ_1 (1) /* RX virtqueue queue index */ @@ -88,7 +88,7 @@ static int libmetal_setup(struct ipc_static_vrings *vr) return err; } - err = metal_device_open("generic", SHM_DEVICE_NAME, &device); + err = metal_device_open("generic", vr->shm_device.name, &device); if (err != 0) { return err; } @@ -166,7 +166,8 @@ int ipc_static_vrings_init(struct ipc_static_vrings *vr, unsigned int role) return -EINVAL; } - vr->shm_device.name = SHM_DEVICE_NAME; + if (!vr->shm_device.name) + vr->shm_device.name = SHM_DEVICE_DEFAULT_NAME; vr->shm_device.num_regions = 1; vr->shm_physmap[0] = vr->shm_addr; From bfb4794c367bc47444a63203bb9ea0882502ab11 Mon Sep 17 00:00:00 2001 From: Jamie McCrae Date: Thu, 14 Dec 2023 13:24:48 +0000 Subject: [PATCH 1255/3723] retention: Increase read size variables to 16-bit Increases 2 variables to be 16-bits instead of 8-bits to allow for target read sizes, this would only be an issue if someone changed the default retention block size from the default value of 16 to a value over 256 Signed-off-by: Jamie McCrae --- subsys/retention/retention.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/subsys/retention/retention.c b/subsys/retention/retention.c index c95df2e2c78..a61f8df6b4d 100644 --- a/subsys/retention/retention.c +++ b/subsys/retention/retention.c @@ -96,7 +96,7 @@ static int retention_checksum(const struct device *dev, uint32_t *output) *output = 0; while (pos < end) { - uint8_t read_size = MIN((end - pos), sizeof(buffer)); + uint16_t read_size = MIN((end - pos), sizeof(buffer)); rc = retained_mem_read(config->parent, pos, buffer, read_size); @@ -188,7 +188,7 @@ int retention_is_valid(const struct device *dev) off_t pos = 0; while (pos < config->prefix_len) { - uint8_t read_size = MIN((config->prefix_len - pos), sizeof(buffer)); + uint16_t read_size = MIN((config->prefix_len - pos), sizeof(buffer)); rc = retained_mem_read(config->parent, (config->offset + pos), buffer, read_size); From 4b1f2da9f77f98aaf66759645ff7f40d984bc7f9 Mon Sep 17 00:00:00 2001 From: Jamie McCrae Date: Thu, 14 Dec 2023 13:29:06 +0000 Subject: [PATCH 1256/3723] doc: release: 3.6: Add note on increase retention variable size Adds a note that the buffer variable size has increased Signed-off-by: Jamie McCrae --- doc/releases/release-notes-3.6.rst | 3 +++ 1 file changed, 3 insertions(+) diff --git a/doc/releases/release-notes-3.6.rst b/doc/releases/release-notes-3.6.rst index ca442cad3e0..b1985f66e33 100644 --- a/doc/releases/release-notes-3.6.rst +++ b/doc/releases/release-notes-3.6.rst @@ -316,6 +316,9 @@ Libraries / Subsystems * Retention + * Fixed issue whereby :kconfig:option:`CONFIG_RETENTION_BUFFER_SIZE` values over 256 would cause + an infinite loop due to use of 8-bit variables. + * Binary descriptors * POSIX API From 93869605ebc94be28767d83d3a1d69bfa6dc696a Mon Sep 17 00:00:00 2001 From: Weifeng Li Date: Thu, 30 Nov 2023 10:10:23 +1300 Subject: [PATCH 1257/3723] drivers: flash: flash_stm32l5x: fix the STM32U5X flash bank issue STM32U5X has 128k/256k/512k/1M/2M dual bank Flash. The address of the 2 bank are continuous, so it's no need a "Dummy page" in "stm32_flash_layout", which cause wrong slot1 section (for secondary image), and the BANK2_OFFSET is not right either, which cause "flash_stm32_valid_range" return a failure. To fix the issue, just set CONFIG_FLASH_SIZE to STM32_SERIES_MAX_FLASH Tested on NUCLEO-U545RE with mcuboot. Signed-off-by: Weifeng Li --- drivers/flash/flash_stm32l5x.c | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) diff --git a/drivers/flash/flash_stm32l5x.c b/drivers/flash/flash_stm32l5x.c index 8ece9b22492..5e4c096dcea 100644 --- a/drivers/flash/flash_stm32l5x.c +++ b/drivers/flash/flash_stm32l5x.c @@ -26,8 +26,10 @@ LOG_MODULE_REGISTER(LOG_DOMAIN); #elif defined(CONFIG_SOC_SERIES_STM32L5X) #define STM32_SERIES_MAX_FLASH 512 #elif defined(CONFIG_SOC_SERIES_STM32U5X) -/* at this time stm32u5 mcus have 1MB (stm32u575) or 2MB (stm32u585) */ -#define STM32_SERIES_MAX_FLASH 2048 +/* It is used to handle the 2 banks discontinuity case, the discontinuity is not happen on STM32U5, + * so define it to flash size to avoid the unexptected check. + */ +#define STM32_SERIES_MAX_FLASH (CONFIG_FLASH_SIZE) #endif #define PAGES_PER_BANK ((FLASH_SIZE / FLASH_PAGE_SIZE) / 2) @@ -397,7 +399,7 @@ void flash_stm32_page_layout(const struct device *dev, if (stm32_flash_has_2_banks(dev) && (CONFIG_FLASH_SIZE < STM32_SERIES_MAX_FLASH)) { /* - * For stm32l552xx with 256 kB flash or stm32u57x with 1MB flash + * For stm32l552xx with 256 kB flash * which have space between banks 1 and 2. */ @@ -417,8 +419,8 @@ void flash_stm32_page_layout(const struct device *dev, stm32_flash_layout_size = ARRAY_SIZE(stm32_flash_layout); } else { /* - * For stm32l562xx & stm32l552xx with 512 flash or stm32u58x - * with 2MB flash which has no space between banks 1 and 2. + * For stm32l562xx & stm32l552xx with 512 flash or stm32u5x, + * which has no space between banks 1 and 2. */ if (stm32_flash_has_2_banks(dev)) { From 4d861629894fbef721e4884cc2aa75cdf6190ac2 Mon Sep 17 00:00:00 2001 From: Luca Burelli Date: Fri, 1 Dec 2023 19:04:49 +0100 Subject: [PATCH 1258/3723] llext: merge llext_mem and llext_section enums The only difference in the two enums are some entries related to relocation sections. However, these entries are not used in the code, so they can be safely removed, along with the mapping function. Use LLEXT_MEM_* to avoid confusion with low-level "section" names. Signed-off-by: Luca Burelli --- arch/xtensa/core/elf.c | 3 +- include/zephyr/llext/llext.h | 7 +- include/zephyr/llext/loader.h | 27 +------- subsys/llext/llext.c | 116 +++++++++++----------------------- 4 files changed, 44 insertions(+), 109 deletions(-) diff --git a/arch/xtensa/core/elf.c b/arch/xtensa/core/elf.c index 959f374888c..976be9f794a 100644 --- a/arch/xtensa/core/elf.c +++ b/arch/xtensa/core/elf.c @@ -6,6 +6,7 @@ #include #include +#include #include LOG_MODULE_DECLARE(llext); @@ -39,6 +40,6 @@ void arch_elf_relocate_local(struct llext_loader *ldr, struct llext *ext, /* Relocate a local symbol: Xtensa specific */ *(elf_word *)(text + got_offset) = (elf_word)(text + ptr_offset - - ldr->sects[LLEXT_SECT_TEXT].sh_addr); + ldr->sects[LLEXT_MEM_TEXT].sh_addr); } } diff --git a/include/zephyr/llext/llext.h b/include/zephyr/llext/llext.h index 951b13b8acd..832aba25cac 100644 --- a/include/zephyr/llext/llext.h +++ b/include/zephyr/llext/llext.h @@ -10,7 +10,6 @@ #include #include #include -#include #include #include @@ -26,7 +25,7 @@ extern "C" { */ /** - * @brief Enum of memory regions for lookup tables + * @brief List of ELF regions that are stored or referenced in the llext */ enum llext_mem { LLEXT_MEM_TEXT, @@ -41,6 +40,8 @@ enum llext_mem { LLEXT_MEM_COUNT, }; +struct llext_loader; + /** * @brief Linkable loadable extension */ @@ -55,7 +56,7 @@ struct llext { /** Lookup table of llext memory regions */ void *mem[LLEXT_MEM_COUNT]; - /** Memory allocated on heap */ + /** Is the memory for this section allocated on heap? */ bool mem_on_heap[LLEXT_MEM_COUNT]; /** Size of each stored section */ diff --git a/include/zephyr/llext/loader.h b/include/zephyr/llext/loader.h index bef29524471..7eb49d611be 100644 --- a/include/zephyr/llext/loader.h +++ b/include/zephyr/llext/loader.h @@ -21,30 +21,7 @@ extern "C" { * @{ */ -/** - * @brief Enum of sections for lookup tables - */ -enum llext_section { - LLEXT_SECT_TEXT, - LLEXT_SECT_DATA, - LLEXT_SECT_RODATA, - LLEXT_SECT_BSS, - - LLEXT_SECT_REL_TEXT, - LLEXT_SECT_REL_DATA, - LLEXT_SECT_REL_RODATA, - LLEXT_SECT_REL_BSS, - - LLEXT_SECT_EXPORT, - - LLEXT_SECT_SYMTAB, - LLEXT_SECT_STRTAB, - LLEXT_SECT_SHSTRTAB, - - LLEXT_SECT_COUNT, -}; - -enum llext_mem; +#include /** * @brief Linkable loadable extension loader context @@ -93,7 +70,7 @@ struct llext_loader { /** @cond ignore */ elf_ehdr_t hdr; - elf_shdr_t sects[LLEXT_SECT_COUNT]; + elf_shdr_t sects[LLEXT_MEM_COUNT]; enum llext_mem *sect_map; uint32_t sect_cnt; /** @endcond */ diff --git a/subsys/llext/llext.c b/subsys/llext/llext.c index 84cbc4d583d..bcd5ccda843 100644 --- a/subsys/llext/llext.c +++ b/subsys/llext/llext.c @@ -42,7 +42,7 @@ ssize_t llext_find_section(struct llext_loader *ldr, const char *search_name) } const char *name = llext_peek(ldr, - ldr->sects[LLEXT_SECT_SHSTRTAB].sh_offset + + ldr->sects[LLEXT_MEM_SHSTRTAB].sh_offset + shdr->sh_name); if (!strcmp(name, search_name)) { @@ -131,9 +131,9 @@ static int llext_find_tables(struct llext_loader *ldr) size_t pos; elf_shdr_t shdr; - ldr->sects[LLEXT_SECT_SHSTRTAB] = - ldr->sects[LLEXT_SECT_STRTAB] = - ldr->sects[LLEXT_SECT_SYMTAB] = (elf_shdr_t){0}; + ldr->sects[LLEXT_MEM_SHSTRTAB] = + ldr->sects[LLEXT_MEM_STRTAB] = + ldr->sects[LLEXT_MEM_SYMTAB] = (elf_shdr_t){0}; /* Find symbol and string tables */ for (i = 0, sect_cnt = 0, pos = ldr->hdr.e_shoff; @@ -164,18 +164,18 @@ static int llext_find_tables(struct llext_loader *ldr) case SHT_SYMTAB: case SHT_DYNSYM: LOG_DBG("symtab at %d", i); - ldr->sects[LLEXT_SECT_SYMTAB] = shdr; + ldr->sects[LLEXT_MEM_SYMTAB] = shdr; ldr->sect_map[i] = LLEXT_MEM_SYMTAB; sect_cnt++; break; case SHT_STRTAB: if (ldr->hdr.e_shstrndx == i) { LOG_DBG("shstrtab at %d", i); - ldr->sects[LLEXT_SECT_SHSTRTAB] = shdr; + ldr->sects[LLEXT_MEM_SHSTRTAB] = shdr; ldr->sect_map[i] = LLEXT_MEM_SHSTRTAB; } else { LOG_DBG("strtab at %d", i); - ldr->sects[LLEXT_SECT_STRTAB] = shdr; + ldr->sects[LLEXT_MEM_STRTAB] = shdr; ldr->sect_map[i] = LLEXT_MEM_STRTAB; } sect_cnt++; @@ -185,9 +185,9 @@ static int llext_find_tables(struct llext_loader *ldr) } } - if (!ldr->sects[LLEXT_SECT_SHSTRTAB].sh_type || - !ldr->sects[LLEXT_SECT_STRTAB].sh_type || - !ldr->sects[LLEXT_SECT_SYMTAB].sh_type) { + if (!ldr->sects[LLEXT_MEM_SHSTRTAB].sh_type || + !ldr->sects[LLEXT_MEM_STRTAB].sh_type || + !ldr->sects[LLEXT_MEM_SYMTAB].sh_type) { LOG_ERR("Some sections are missing or present multiple times!"); return -ENOENT; } @@ -228,86 +228,43 @@ static int llext_map_sections(struct llext_loader *ldr, struct llext *ext) LOG_DBG("section %d name %s", i, name); - enum llext_section sect_idx; enum llext_mem mem_idx; if (strcmp(name, ".text") == 0) { - sect_idx = LLEXT_SECT_TEXT; mem_idx = LLEXT_MEM_TEXT; } else if (strcmp(name, ".data") == 0) { - sect_idx = LLEXT_SECT_DATA; mem_idx = LLEXT_MEM_DATA; } else if (strcmp(name, ".rodata") == 0) { - sect_idx = LLEXT_SECT_RODATA; mem_idx = LLEXT_MEM_RODATA; } else if (strcmp(name, ".bss") == 0) { - sect_idx = LLEXT_SECT_BSS; mem_idx = LLEXT_MEM_BSS; } else if (strcmp(name, ".exported_sym") == 0) { - sect_idx = LLEXT_SECT_EXPORT; mem_idx = LLEXT_MEM_EXPORT; } else { LOG_DBG("Not copied section %s", name); continue; } - ldr->sects[sect_idx] = shdr; + ldr->sects[mem_idx] = shdr; ldr->sect_map[i] = mem_idx; } return 0; } -static enum llext_section llext_sect_from_mem(enum llext_mem m) -{ - enum llext_section s; - - switch (m) { - case LLEXT_MEM_BSS: - s = LLEXT_SECT_BSS; - break; - case LLEXT_MEM_DATA: - s = LLEXT_SECT_DATA; - break; - case LLEXT_MEM_RODATA: - s = LLEXT_SECT_RODATA; - break; - case LLEXT_MEM_EXPORT: - s = LLEXT_SECT_EXPORT; - break; - case LLEXT_MEM_TEXT: - s = LLEXT_SECT_TEXT; - break; - case LLEXT_MEM_SYMTAB: - s = LLEXT_SECT_SYMTAB; - break; - case LLEXT_MEM_STRTAB: - s = LLEXT_SECT_STRTAB; - break; - case LLEXT_MEM_SHSTRTAB: - s = LLEXT_SECT_SHSTRTAB; - break; - default: - CODE_UNREACHABLE; - } - - return s; -} - static int llext_copy_section(struct llext_loader *ldr, struct llext *ext, enum llext_mem mem_idx) { - enum llext_section sect_idx = llext_sect_from_mem(mem_idx); int ret; - if (!ldr->sects[sect_idx].sh_size) { + if (!ldr->sects[mem_idx].sh_size) { return 0; } - ext->mem_size[mem_idx] = ldr->sects[sect_idx].sh_size; + ext->mem_size[mem_idx] = ldr->sects[mem_idx].sh_size; - if (ldr->sects[sect_idx].sh_type != SHT_NOBITS && + if (ldr->sects[mem_idx].sh_type != SHT_NOBITS && IS_ENABLED(CONFIG_LLEXT_STORAGE_WRITABLE)) { - ext->mem[mem_idx] = llext_peek(ldr, ldr->sects[sect_idx].sh_offset); + ext->mem[mem_idx] = llext_peek(ldr, ldr->sects[mem_idx].sh_offset); if (ext->mem[mem_idx]) { ext->mem_on_heap[mem_idx] = false; return 0; @@ -315,22 +272,22 @@ static int llext_copy_section(struct llext_loader *ldr, struct llext *ext, } ext->mem[mem_idx] = k_heap_aligned_alloc(&llext_heap, sizeof(uintptr_t), - ldr->sects[sect_idx].sh_size, + ldr->sects[mem_idx].sh_size, K_NO_WAIT); if (!ext->mem[mem_idx]) { return -ENOMEM; } - ext->alloc_size += ldr->sects[sect_idx].sh_size; + ext->alloc_size += ldr->sects[mem_idx].sh_size; - if (ldr->sects[sect_idx].sh_type == SHT_NOBITS) { - memset(ext->mem[mem_idx], 0, ldr->sects[sect_idx].sh_size); + if (ldr->sects[mem_idx].sh_type == SHT_NOBITS) { + memset(ext->mem[mem_idx], 0, ldr->sects[mem_idx].sh_size); } else { - ret = llext_seek(ldr, ldr->sects[sect_idx].sh_offset); + ret = llext_seek(ldr, ldr->sects[mem_idx].sh_offset); if (ret != 0) { goto err; } - ret = llext_read(ldr, ext->mem[mem_idx], ldr->sects[sect_idx].sh_size); + ret = llext_read(ldr, ext->mem[mem_idx], ldr->sects[mem_idx].sh_size); if (ret != 0) { goto err; } @@ -376,8 +333,8 @@ static int llext_copy_sections(struct llext_loader *ldr, struct llext *ext) static int llext_count_export_syms(struct llext_loader *ldr, struct llext *ext) { - size_t ent_size = ldr->sects[LLEXT_SECT_SYMTAB].sh_entsize; - size_t syms_size = ldr->sects[LLEXT_SECT_SYMTAB].sh_size; + size_t ent_size = ldr->sects[LLEXT_MEM_SYMTAB].sh_entsize; + size_t syms_size = ldr->sects[LLEXT_MEM_SYMTAB].sh_size; int sym_cnt = syms_size / sizeof(elf_sym_t); const char *name; elf_sym_t sym; @@ -386,7 +343,7 @@ static int llext_count_export_syms(struct llext_loader *ldr, struct llext *ext) LOG_DBG("symbol count %u", sym_cnt); - for (i = 0, pos = ldr->sects[LLEXT_SECT_SYMTAB].sh_offset; + for (i = 0, pos = ldr->sects[LLEXT_MEM_SYMTAB].sh_offset; i < sym_cnt; i++, pos += ent_size) { if (!i) { @@ -440,7 +397,7 @@ static int llext_allocate_symtab(struct llext_loader *ldr, struct llext *ext) static int llext_export_symbols(struct llext_loader *ldr, struct llext *ext) { - elf_shdr_t *shdr = ldr->sects + LLEXT_SECT_EXPORT; + elf_shdr_t *shdr = ldr->sects + LLEXT_MEM_EXPORT; struct llext_symbol *sym; unsigned int i; @@ -471,15 +428,15 @@ static int llext_export_symbols(struct llext_loader *ldr, struct llext *ext) static int llext_copy_symbols(struct llext_loader *ldr, struct llext *ext) { - size_t ent_size = ldr->sects[LLEXT_SECT_SYMTAB].sh_entsize; - size_t syms_size = ldr->sects[LLEXT_SECT_SYMTAB].sh_size; + size_t ent_size = ldr->sects[LLEXT_MEM_SYMTAB].sh_entsize; + size_t syms_size = ldr->sects[LLEXT_MEM_SYMTAB].sh_size; int sym_cnt = syms_size / sizeof(elf_sym_t); struct llext_symtable *sym_tab = &ext->sym_tab; elf_sym_t sym; int i, j, ret; size_t pos; - for (i = 0, pos = ldr->sects[LLEXT_SECT_SYMTAB].sh_offset, j = 0; + for (i = 0, pos = ldr->sects[LLEXT_MEM_SYMTAB].sh_offset, j = 0; i < sym_cnt; i++, pos += ent_size) { if (!i) { @@ -502,17 +459,16 @@ static int llext_copy_symbols(struct llext_loader *ldr, struct llext *ext) unsigned int sect = sym.st_shndx; if (stt == STT_FUNC && stb == STB_GLOBAL && sect != SHN_UNDEF) { - enum llext_mem mem = ldr->sect_map[sect]; - enum llext_section sect_idx = llext_sect_from_mem(mem); + enum llext_mem mem_idx = ldr->sect_map[sect]; const char *name = llext_string(ldr, ext, LLEXT_MEM_STRTAB, sym.st_name); __ASSERT(j <= sym_tab->sym_cnt, "Miscalculated symbol number %u\n", j); sym_tab->syms[j].name = name; - sym_tab->syms[j].addr = (void *)((uintptr_t)ext->mem[mem] + + sym_tab->syms[j].addr = (void *)((uintptr_t)ext->mem[mem_idx] + sym.st_value - (ldr->hdr.e_type == ET_REL ? 0 : - ldr->sects[sect_idx].sh_addr)); + ldr->sects[mem_idx].sh_addr)); LOG_DBG("function symbol %d name %s addr %p", j, name, sym_tab->syms[j].addr); j++; @@ -530,7 +486,7 @@ static size_t llext_file_offset(struct llext_loader *ldr, size_t offset) { unsigned int i; - for (i = 0; i < LLEXT_SECT_COUNT; i++) + for (i = 0; i < LLEXT_MEM_COUNT; i++) if (ldr->sects[i].sh_addr <= offset && ldr->sects[i].sh_addr + ldr->sects[i].sh_size > offset) return offset - ldr->sects[i].sh_addr + ldr->sects[i].sh_offset; @@ -557,7 +513,7 @@ static void llext_link_plt(struct llext_loader *ldr, struct llext *ext, (void *)llext_string(ldr, ext, LLEXT_MEM_SHSTRTAB, shdr->sh_name), shdr->sh_type, shdr->sh_entsize, sh_cnt, (void *)text); - const elf_shdr_t *sym_shdr = ldr->sects + LLEXT_SECT_SYMTAB; + const elf_shdr_t *sym_shdr = ldr->sects + LLEXT_MEM_SYMTAB; unsigned int sym_cnt = sym_shdr->sh_size / sym_shdr->sh_entsize; for (unsigned int i = 0; i < sh_cnt; i++) { @@ -608,7 +564,7 @@ static void llext_link_plt(struct llext_loader *ldr, struct llext *ext, * has been built. */ size_t got_offset = llext_file_offset(ldr, rela.r_offset) - - ldr->sects[LLEXT_SECT_TEXT].sh_offset; + ldr->sects[LLEXT_MEM_TEXT].sh_offset; const void *link_addr; @@ -639,7 +595,7 @@ static void llext_link_plt(struct llext_loader *ldr, struct llext *ext, LOG_DBG("symbol %s offset %#x r-offset %#x .text offset %#x stb %u", name, got_offset, - rela.r_offset, ldr->sects[LLEXT_SECT_TEXT].sh_offset, stb); + rela.r_offset, ldr->sects[LLEXT_MEM_TEXT].sh_offset, stb); } } @@ -716,7 +672,7 @@ static int llext_link(struct llext_loader *ldr, struct llext *ext, bool do_local } /* get corresponding symbol */ - ret = llext_seek(ldr, ldr->sects[LLEXT_SECT_SYMTAB].sh_offset + ret = llext_seek(ldr, ldr->sects[LLEXT_MEM_SYMTAB].sh_offset + ELF_R_SYM(rel.r_info) * sizeof(elf_sym_t)); if (ret != 0) { return ret; From 87f2486e1c3e22b8c1da5582d280448662e047de Mon Sep 17 00:00:00 2001 From: Dawid Niedzwiecki Date: Mon, 11 Dec 2023 10:47:21 +0100 Subject: [PATCH 1259/3723] entropy: stm32: enable rng module if needed Move enabling/disabling the RNG module to acquire/release functions. It causes enabling the RNG module for the get_entropy_isr function. It fixes hanging in the get_entropy_isr function. Signed-off-by: Dawid Niedzwiecki --- drivers/entropy/entropy_stm32.c | 22 +++++++++++++--------- 1 file changed, 13 insertions(+), 9 deletions(-) diff --git a/drivers/entropy/entropy_stm32.c b/drivers/entropy/entropy_stm32.c index 75537680bfb..14bcf36a4d2 100644 --- a/drivers/entropy/entropy_stm32.c +++ b/drivers/entropy/entropy_stm32.c @@ -103,8 +103,9 @@ static struct entropy_stm32_rng_dev_data entropy_stm32_rng_data = { .rng = (RNG_TypeDef *)DT_INST_REG_ADDR(0), }; -static int entropy_stm32_suspend(const struct device *dev) +static int entropy_stm32_suspend(void) { + const struct device *dev = DEVICE_DT_GET(DT_DRV_INST(0)); struct entropy_stm32_rng_dev_data *dev_data = dev->data; const struct entropy_stm32_rng_dev_cfg *dev_cfg = dev->config; RNG_TypeDef *rng = dev_data->rng; @@ -133,8 +134,9 @@ static int entropy_stm32_suspend(const struct device *dev) return res; } -static int entropy_stm32_resume(const struct device *dev) +static int entropy_stm32_resume(void) { + const struct device *dev = DEVICE_DT_GET(DT_DRV_INST(0)); struct entropy_stm32_rng_dev_data *dev_data = dev->data; const struct entropy_stm32_rng_dev_cfg *dev_cfg = dev->config; RNG_TypeDef *rng = dev_data->rng; @@ -201,6 +203,7 @@ static void configure_rng(void) static void acquire_rng(void) { + entropy_stm32_resume(); #if defined(CONFIG_SOC_SERIES_STM32WBX) || defined(CONFIG_STM32H7_DUAL_CORE) /* Lock the RNG to prevent concurrent access */ z_stm32_hsem_lock(CFG_HW_RNG_SEMID, HSEM_LOCK_WAIT_FOREVER); @@ -211,6 +214,7 @@ static void acquire_rng(void) static void release_rng(void) { + entropy_stm32_suspend(); #if defined(CONFIG_SOC_SERIES_STM32WBX) || defined(CONFIG_STM32H7_DUAL_CORE) z_stm32_hsem_unlock(CFG_HW_RNG_SEMID); #endif /* CONFIG_SOC_SERIES_STM32WBX || CONFIG_STM32H7_DUAL_CORE */ @@ -382,7 +386,6 @@ static int start_pool_filling(bool wait) { unsigned int key; bool already_filling; - const struct device *dev = DEVICE_DT_GET(DT_DRV_INST(0)); key = irq_lock(); #if defined(CONFIG_SOC_SERIES_STM32WBX) || defined(CONFIG_STM32H7_DUAL_CORE) @@ -409,7 +412,6 @@ static int start_pool_filling(bool wait) */ pm_policy_state_lock_get(PM_STATE_SUSPEND_TO_IDLE, PM_ALL_SUBSTATES); - entropy_stm32_resume(dev); acquire_rng(); irq_enable(IRQN); @@ -520,7 +522,6 @@ static void rng_pool_init(struct rng_pool *rngp, uint16_t size, static void stm32_rng_isr(const void *arg) { int byte, ret; - const struct device *dev = DEVICE_DT_GET(DT_DRV_INST(0)); ARG_UNUSED(arg); @@ -538,7 +539,6 @@ static void stm32_rng_isr(const void *arg) if (ret < 0) { irq_disable(IRQN); release_rng(); - entropy_stm32_suspend(dev); pm_policy_state_lock_put(PM_STATE_SUSPEND_TO_IDLE, PM_ALL_SUBSTATES); entropy_stm32_rng_data.filling_pools = false; } @@ -602,7 +602,11 @@ static int entropy_stm32_rng_get_entropy_isr(const struct device *dev, irq_disable(IRQN); irq_unlock(key); - rng_already_acquired = z_stm32_hsem_is_owned(CFG_HW_RNG_SEMID); + /* Do not release if IRQ is enabled. RNG will be released in ISR + * when the pools are full. + */ + rng_already_acquired = z_stm32_hsem_is_owned(CFG_HW_RNG_SEMID) || + irq_enabled; acquire_rng(); cnt = generate_from_isr(buf, len); @@ -689,12 +693,12 @@ static int entropy_stm32_rng_pm_action(const struct device *dev, switch (action) { case PM_DEVICE_ACTION_SUSPEND: - res = entropy_stm32_suspend(dev); + res = entropy_stm32_suspend(); break; case PM_DEVICE_ACTION_RESUME: /* Resume RNG only if it was suspended during filling pool */ if (entropy_stm32_rng_data.filling_pools) { - res = entropy_stm32_resume(dev); + res = entropy_stm32_resume(); } break; default: From b0753d9c107c563dfb50a06ab9939823234e6ad3 Mon Sep 17 00:00:00 2001 From: Dawid Niedzwiecki Date: Thu, 14 Dec 2023 08:55:57 +0100 Subject: [PATCH 1260/3723] entropy: stm32: enable interrupt when RNG is resumed Enable the RNG module interrupt every time it is resumed. It is done to make sure the interrupt is always enabled. The CR register may not persist when the device clock is disabled on some chips. Signed-off-by: Dawid Niedzwiecki --- drivers/entropy/entropy_stm32.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/entropy/entropy_stm32.c b/drivers/entropy/entropy_stm32.c index 14bcf36a4d2..bb3ba116345 100644 --- a/drivers/entropy/entropy_stm32.c +++ b/drivers/entropy/entropy_stm32.c @@ -145,6 +145,7 @@ static int entropy_stm32_resume(void) res = clock_control_on(dev_data->clock, (clock_control_subsys_t)&dev_cfg->pclken[0]); LL_RNG_Enable(rng); + LL_RNG_EnableIT(rng); return res; } From 0b8b67e3469506a6792f18d02b155299e846ebbb Mon Sep 17 00:00:00 2001 From: Mariusz Skamra Date: Mon, 6 Nov 2023 10:42:05 +0100 Subject: [PATCH 1261/3723] tests: bsim: has: Clean up the #ifdef Use if(IS_ENABLED(...)) {...} instead. Signed-off-by: Mariusz Skamra --- tests/bsim/bluetooth/audio/src/has_client_test.c | 10 +++++----- tests/bsim/bluetooth/audio/src/has_test.c | 14 +++++--------- 2 files changed, 10 insertions(+), 14 deletions(-) diff --git a/tests/bsim/bluetooth/audio/src/has_client_test.c b/tests/bsim/bluetooth/audio/src/has_client_test.c index 27ad787fef1..cc8055d1414 100644 --- a/tests/bsim/bluetooth/audio/src/has_client_test.c +++ b/tests/bsim/bluetooth/audio/src/has_client_test.c @@ -19,7 +19,6 @@ extern const uint8_t test_preset_index_3; extern const uint8_t test_preset_index_5; extern const enum bt_has_properties test_preset_properties; -#ifdef CONFIG_BT_HAS_CLIENT CREATE_FLAG(g_service_discovered); CREATE_FLAG(g_preset_switched); CREATE_FLAG(g_preset_1_found); @@ -246,7 +245,6 @@ static void test_main(void) PASS("HAS main PASS\n"); } -#endif /* CONFIG_BT_HAS_CLIENT */ #define FEATURES_SUB_NTF BIT(0) #define ACTIVE_INDEX_SUB_NTF BIT(1) @@ -670,14 +668,12 @@ static void test_gatt_client(void) } static const struct bst_test_instance test_has[] = { -#ifdef CONFIG_BT_HAS_CLIENT { .test_id = "has_client", .test_post_init_f = test_init, .test_tick_f = test_tick, .test_main_f = test_main, }, -#endif /* CONFIG_BT_HAS_CLIENT */ { .test_id = "has_client_offline_behavior", .test_descr = "Test receiving notifications after reconnection", @@ -690,5 +686,9 @@ static const struct bst_test_instance test_has[] = { struct bst_test_list *test_has_client_install(struct bst_test_list *tests) { - return bst_add_tests(tests, test_has); + if (IS_ENABLED(CONFIG_BT_HAS_CLIENT)) { + return bst_add_tests(tests, test_has); + } else { + return tests; + } } diff --git a/tests/bsim/bluetooth/audio/src/has_test.c b/tests/bsim/bluetooth/audio/src/has_test.c index f2b5bdeade9..8e95e464757 100644 --- a/tests/bsim/bluetooth/audio/src/has_test.c +++ b/tests/bsim/bluetooth/audio/src/has_test.c @@ -4,7 +4,6 @@ * SPDX-License-Identifier: Apache-2.0 */ -#ifdef CONFIG_BT_HAS #include #include @@ -163,12 +162,9 @@ static const struct bst_test_instance test_has[] = { struct bst_test_list *test_has_install(struct bst_test_list *tests) { - return bst_add_tests(tests, test_has); -} -#else -struct bst_test_list *test_has_install(struct bst_test_list *tests) -{ - return tests; + if (IS_ENABLED(CONFIG_BT_HAS)) { + return bst_add_tests(tests, test_has); + } else { + return tests; + } } - -#endif /* CONFIG_BT_HAS */ From daa7a99b8c4c4b7865ff38a1f846abce4e09d6bf Mon Sep 17 00:00:00 2001 From: Mariusz Skamra Date: Tue, 7 Nov 2023 12:44:11 +0100 Subject: [PATCH 1262/3723] tests: bsim: has: Change printk to LOG Replace combination of printk() to LOG_DBG() to fix the order of the test execution logs. The printk() is printed immediately, while logs are buffered, thus the messages from test are printed out before the stack logs. Signed-off-by: Mariusz Skamra --- .../bluetooth/audio/src/has_client_test.c | 91 ++++++++++--------- tests/bsim/bluetooth/audio/src/has_test.c | 9 +- 2 files changed, 53 insertions(+), 47 deletions(-) diff --git a/tests/bsim/bluetooth/audio/src/has_client_test.c b/tests/bsim/bluetooth/audio/src/has_client_test.c index cc8055d1414..a56808af997 100644 --- a/tests/bsim/bluetooth/audio/src/has_client_test.c +++ b/tests/bsim/bluetooth/audio/src/has_client_test.c @@ -10,6 +10,9 @@ #include "common.h" +#include +LOG_MODULE_REGISTER(has_client_test, LOG_LEVEL_DBG); + extern enum bst_result_t bst_result; extern const char *test_preset_name_1; @@ -36,7 +39,7 @@ static void discover_cb(struct bt_conn *conn, int err, struct bt_has *has, return; } - printk("HAS discovered type %d caps %d\n", type, caps); + LOG_DBG("HAS discovered type %d caps %d", type, caps); g_has = has; SET_FLAG(g_service_discovered); @@ -48,7 +51,7 @@ static void preset_switch_cb(struct bt_has *has, int err, uint8_t index) return; } - printk("Active preset index %d\n", index); + LOG_DBG("Active preset index %d", index); SET_FLAG(g_preset_switched); g_active_index = index; @@ -112,7 +115,7 @@ static bool test_preset_switch(uint8_t index) err = bt_has_client_preset_set(g_has, index, false); if (err < 0) { - printk("%s (err %d)\n", __func__, err); + LOG_DBG("%s (err %d)", __func__, err); return false; } @@ -129,7 +132,7 @@ static bool test_preset_next(uint8_t active_index_expected) err = bt_has_client_preset_next(g_has, false); if (err < 0) { - printk("%s (err %d)\n", __func__, err); + LOG_DBG("%s (err %d)", __func__, err); return false; } @@ -146,7 +149,7 @@ static bool test_preset_prev(uint8_t active_index_expected) err = bt_has_client_preset_prev(g_has, false); if (err < 0) { - printk("%s (err %d)\n", __func__, err); + LOG_DBG("%s (err %d)", __func__, err); return false; } @@ -165,7 +168,7 @@ static void test_main(void) return; } - printk("Bluetooth initialized\n"); + LOG_DBG("Bluetooth initialized"); err = bt_has_client_cb_register(&has_cb); if (err < 0) { @@ -181,7 +184,7 @@ static void test_main(void) return; } - printk("Scanning successfully started\n"); + LOG_DBG("Scanning successfully started"); WAIT_FOR_FLAG(flag_connected); @@ -292,29 +295,29 @@ static void preset_availability_changed(uint8_t index, bool available) static uint8_t notify_handler(struct bt_conn *conn, struct bt_gatt_subscribe_params *params, const void *data, uint16_t length) { - printk("conn %p params %p data %p length %u\n", (void *)conn, params, data, length); + LOG_DBG("conn %p params %p data %p length %u", (void *)conn, params, data, length); if (params == &features_sub) { if (data == NULL) { - printk("features_sub [UNSUBSCRIBED]\n"); + LOG_DBG("features_sub [UNSUBSCRIBED]"); return BT_GATT_ITER_STOP; } - printk("Received features_sub notification\n"); + LOG_DBG("Received features_sub notification"); notify_received_mask |= FEATURES_SUB_NTF; } else if (params == &active_preset_index_sub) { if (data == NULL) { - printk("active_preset_index_sub_sub [UNSUBSCRIBED]\n"); + LOG_DBG("active_preset_index_sub_sub [UNSUBSCRIBED]"); return BT_GATT_ITER_STOP; } - printk("Received active_preset_index_sub_sub notification\n"); + LOG_DBG("Received active_preset_index_sub_sub notification"); notify_received_mask |= ACTIVE_INDEX_SUB_NTF; } else if (params == &control_point_sub) { const struct bt_has_cp_hdr *hdr; if (data == NULL) { - printk("control_point_sub [UNSUBSCRIBED]\n"); + LOG_DBG("control_point_sub [UNSUBSCRIBED]"); return BT_GATT_ITER_STOP; } @@ -347,8 +350,8 @@ static uint8_t notify_handler(struct bt_conn *conn, struct bt_gatt_subscribe_par gu = (const void *)pc->additional_params; - printk("Received generic update index 0x%02x props 0x%02x\n", - gu->index, gu->properties); + LOG_DBG("Received generic update index 0x%02x props 0x%02x", + gu->index, gu->properties); is_available = (gu->properties & BT_HAS_PROP_AVAILABLE) != 0; @@ -356,7 +359,7 @@ static uint8_t notify_handler(struct bt_conn *conn, struct bt_gatt_subscribe_par break; } default: - printk("Unexpected Change ID 0x%02x", pc->change_id); + LOG_DBG("Unexpected Change ID 0x%02x", pc->change_id); return BT_GATT_ITER_STOP; } @@ -364,12 +367,12 @@ static uint8_t notify_handler(struct bt_conn *conn, struct bt_gatt_subscribe_par notify_received_mask |= PRESET_CHANGED_SUB_NTF; } } else { - printk("Unexpected opcode 0x%02x", hdr->opcode); + LOG_DBG("Unexpected opcode 0x%02x", hdr->opcode); return BT_GATT_ITER_STOP; } } - printk("pacs_instance.notify_received_mask is %d\n", notify_received_mask); + LOG_DBG("pacs_instance.notify_received_mask is %d", notify_received_mask); if (notify_received_mask == SUB_NTF_ALL) { SET_FLAG(flag_all_notifications_received); @@ -385,7 +388,7 @@ static void subscribe_cb(struct bt_conn *conn, uint8_t err, struct bt_gatt_subsc return; } - printk("[SUBSCRIBED]\n"); + LOG_DBG("[SUBSCRIBED]"); if (params == &features_sub) { SET_FLAG(flag_features_discovered); @@ -410,13 +413,13 @@ static uint8_t discover_features_cb(struct bt_conn *conn, const struct bt_gatt_a int err; if (!attr) { - printk("Discover complete\n"); + LOG_DBG("Discover complete"); (void)memset(params, 0, sizeof(*params)); return BT_GATT_ITER_STOP; } if (!bt_uuid_cmp(params->uuid, BT_UUID_HAS_HEARING_AID_FEATURES)) { - printk("HAS Hearing Aid Features handle at %d\n", attr->handle); + LOG_DBG("HAS Hearing Aid Features handle at %d", attr->handle); memcpy(&uuid, BT_UUID_GATT_CCC, sizeof(uuid)); discover_params.uuid = &uuid.uuid; discover_params.start_handle = attr->handle + 2; @@ -426,10 +429,10 @@ static uint8_t discover_features_cb(struct bt_conn *conn, const struct bt_gatt_a err = bt_gatt_discover(conn, &discover_params); if (err) { - printk("Discover failed (err %d)\n", err); + LOG_DBG("Discover failed (err %d)", err); } } else if (!bt_uuid_cmp(params->uuid, BT_UUID_GATT_CCC)) { - printk("CCC handle at %d\n", attr->handle); + LOG_DBG("CCC handle at %d", attr->handle); subscribe_params = &features_sub; subscribe_params->notify = notify_handler; subscribe_params->value = BT_GATT_CCC_NOTIFY; @@ -438,10 +441,10 @@ static uint8_t discover_features_cb(struct bt_conn *conn, const struct bt_gatt_a err = bt_gatt_subscribe(conn, subscribe_params); if (err && err != -EALREADY) { - printk("Subscribe failed (err %d)\n", err); + LOG_DBG("Subscribe failed (err %d)", err); } } else { - printk("Unknown handle at %d\n", attr->handle); + LOG_DBG("Unknown handle at %d", attr->handle); return BT_GATT_ITER_CONTINUE; } @@ -452,7 +455,7 @@ static void discover_and_subscribe_features(void) { int err = 0; - printk("%s\n", __func__); + LOG_DBG("%s", __func__); memcpy(&uuid, BT_UUID_HAS_HEARING_AID_FEATURES, sizeof(uuid)); discover_params.uuid = &uuid.uuid; @@ -476,13 +479,13 @@ static uint8_t discover_active_preset_index_cb(struct bt_conn *conn, int err; if (!attr) { - printk("Discover complete\n"); + LOG_DBG("Discover complete"); (void)memset(params, 0, sizeof(*params)); return BT_GATT_ITER_STOP; } if (!bt_uuid_cmp(params->uuid, BT_UUID_HAS_ACTIVE_PRESET_INDEX)) { - printk("HAS Hearing Aid Features handle at %d\n", attr->handle); + LOG_DBG("HAS Hearing Aid Features handle at %d", attr->handle); memcpy(&uuid, BT_UUID_GATT_CCC, sizeof(uuid)); discover_params.uuid = &uuid.uuid; discover_params.start_handle = attr->handle + 2; @@ -492,10 +495,10 @@ static uint8_t discover_active_preset_index_cb(struct bt_conn *conn, err = bt_gatt_discover(conn, &discover_params); if (err) { - printk("Discover failed (err %d)\n", err); + LOG_DBG("Discover failed (err %d)", err); } } else if (!bt_uuid_cmp(params->uuid, BT_UUID_GATT_CCC)) { - printk("CCC handle at %d\n", attr->handle); + LOG_DBG("CCC handle at %d", attr->handle); subscribe_params = &active_preset_index_sub; subscribe_params->notify = notify_handler; subscribe_params->value = BT_GATT_CCC_NOTIFY; @@ -504,10 +507,10 @@ static uint8_t discover_active_preset_index_cb(struct bt_conn *conn, err = bt_gatt_subscribe(conn, subscribe_params); if (err && err != -EALREADY) { - printk("Subscribe failed (err %d)\n", err); + LOG_DBG("Subscribe failed (err %d)", err); } } else { - printk("Unknown handle at %d\n", attr->handle); + LOG_DBG("Unknown handle at %d", attr->handle); return BT_GATT_ITER_CONTINUE; } @@ -518,7 +521,7 @@ static void discover_and_subscribe_active_preset_index(void) { int err = 0; - printk("%s\n", __func__); + LOG_DBG("%s", __func__); memcpy(&uuid, BT_UUID_HAS_ACTIVE_PRESET_INDEX, sizeof(uuid)); discover_params.uuid = &uuid.uuid; @@ -541,13 +544,13 @@ static uint8_t discover_control_point_cb(struct bt_conn *conn, const struct bt_g int err; if (!attr) { - printk("Discover complete\n"); + LOG_DBG("Discover complete"); (void)memset(params, 0, sizeof(*params)); return BT_GATT_ITER_STOP; } if (!bt_uuid_cmp(params->uuid, BT_UUID_HAS_PRESET_CONTROL_POINT)) { - printk("HAS Control Point handle at %d\n", attr->handle); + LOG_DBG("HAS Control Point handle at %d", attr->handle); memcpy(&uuid, BT_UUID_GATT_CCC, sizeof(uuid)); discover_params.uuid = &uuid.uuid; discover_params.start_handle = attr->handle + 2; @@ -557,10 +560,10 @@ static uint8_t discover_control_point_cb(struct bt_conn *conn, const struct bt_g err = bt_gatt_discover(conn, &discover_params); if (err) { - printk("Discover failed (err %d)\n", err); + LOG_DBG("Discover failed (err %d)", err); } } else if (!bt_uuid_cmp(params->uuid, BT_UUID_GATT_CCC)) { - printk("CCC handle at %d\n", attr->handle); + LOG_DBG("CCC handle at %d", attr->handle); subscribe_params = &control_point_sub; subscribe_params->notify = notify_handler; subscribe_params->value = BT_GATT_CCC_INDICATE; @@ -569,10 +572,10 @@ static uint8_t discover_control_point_cb(struct bt_conn *conn, const struct bt_g err = bt_gatt_subscribe(conn, subscribe_params); if (err && err != -EALREADY) { - printk("Subscribe failed (err %d)\n", err); + LOG_DBG("Subscribe failed (err %d)", err); } } else { - printk("Unknown handle at %d\n", attr->handle); + LOG_DBG("Unknown handle at %d", attr->handle); return BT_GATT_ITER_CONTINUE; } @@ -583,7 +586,7 @@ static void discover_and_subscribe_control_point(void) { int err = 0; - printk("%s\n", __func__); + LOG_DBG("%s", __func__); memcpy(&uuid, BT_UUID_HAS_PRESET_CONTROL_POINT, sizeof(uuid)); discover_params.uuid = &uuid.uuid; @@ -609,7 +612,7 @@ static void test_gatt_client(void) return; } - printk("Bluetooth initialized\n"); + LOG_DBG("Bluetooth initialized"); bt_le_scan_cb_register(&common_scan_cb); @@ -619,13 +622,13 @@ static void test_gatt_client(void) return; } - printk("Scanning successfully started\n"); + LOG_DBG("Scanning successfully started"); WAIT_FOR_FLAG(flag_connected); err = bt_conn_set_security(default_conn, BT_SECURITY_L2); if (err) { - FAIL("Failed to set security level %d (err %d)\n", BT_SECURITY_L2, err); + FAIL("Failed to set security level %d (err %d)", BT_SECURITY_L2, err); return; } @@ -652,7 +655,7 @@ static void test_gatt_client(void) return; } - printk("Scanning successfully started\n"); + LOG_DBG("Scanning successfully started"); WAIT_FOR_FLAG(flag_connected); diff --git a/tests/bsim/bluetooth/audio/src/has_test.c b/tests/bsim/bluetooth/audio/src/has_test.c index 8e95e464757..1f5c7f62897 100644 --- a/tests/bsim/bluetooth/audio/src/has_test.c +++ b/tests/bsim/bluetooth/audio/src/has_test.c @@ -9,6 +9,9 @@ #include "common.h" +#include +LOG_MODULE_REGISTER(has_test, LOG_LEVEL_DBG); + extern enum bst_result_t bst_result; const uint8_t test_preset_index_1 = 0x01; @@ -41,7 +44,7 @@ static void test_common(void) return; } - printk("Bluetooth initialized\n"); + LOG_DBG("Bluetooth initialized"); err = bt_le_adv_start(BT_LE_ADV_CONN_NAME, ad, AD_SIZE, NULL, 0); if (err) { @@ -49,7 +52,7 @@ static void test_common(void) return; } - printk("Advertising successfully started\n"); + LOG_DBG("Advertising successfully started"); has_param.type = BT_HAS_HEARING_AID_TYPE_BINAURAL; has_param.preset_sync_support = true; @@ -90,7 +93,7 @@ static void test_common(void) return; } - printk("Presets registered\n"); + LOG_DBG("Presets registered"); PASS("HAS passed\n"); } From 438e8a4cb0355c2f1e0b930aa72c061796268098 Mon Sep 17 00:00:00 2001 From: Flavio Ceolin Date: Tue, 12 Dec 2023 15:20:40 -0800 Subject: [PATCH 1263/3723] samples: syscall_perf: Remove unused build option This sample does not define any syscall. It does need to set CONFIG_APPLICATION_DEFINE_SYSCALL. Signed-off-by: Flavio Ceolin --- samples/userspace/syscall_perf/prj.conf | 1 - 1 file changed, 1 deletion(-) diff --git a/samples/userspace/syscall_perf/prj.conf b/samples/userspace/syscall_perf/prj.conf index c16c800cc93..08f8fc9aaf7 100644 --- a/samples/userspace/syscall_perf/prj.conf +++ b/samples/userspace/syscall_perf/prj.conf @@ -1,5 +1,4 @@ CONFIG_USERSPACE=y -CONFIG_APPLICATION_DEFINED_SYSCALL=y CONFIG_ASSERT=y CONFIG_LOG=y CONFIG_LOG_MODE_MINIMAL=y From dca352bfa3077cadeb6c3c3f2ff3100082c9e4b6 Mon Sep 17 00:00:00 2001 From: Flavio Ceolin Date: Tue, 12 Dec 2023 15:21:42 -0800 Subject: [PATCH 1264/3723] tests: arm64_high_addresses: Remove unused build option This test does not define any syscall. It does not need to set CONFIG_APPLICATION_DEFINE_SYSCALL. Signed-off-by: Flavio Ceolin --- tests/arch/arm64/arm64_high_addresses/prj.conf | 1 - 1 file changed, 1 deletion(-) diff --git a/tests/arch/arm64/arm64_high_addresses/prj.conf b/tests/arch/arm64/arm64_high_addresses/prj.conf index cc08fb4b743..dc5dc080f49 100644 --- a/tests/arch/arm64/arm64_high_addresses/prj.conf +++ b/tests/arch/arm64/arm64_high_addresses/prj.conf @@ -1,5 +1,4 @@ CONFIG_TEST_USERSPACE=y -CONFIG_APPLICATION_DEFINED_SYSCALL=y CONFIG_ASSERT=y CONFIG_LOG=y CONFIG_LOG_MODE_MINIMAL=y From b16110587c76cebd644c01f9e45218412281e140 Mon Sep 17 00:00:00 2001 From: Flavio Ceolin Date: Tue, 12 Dec 2023 22:05:09 -0800 Subject: [PATCH 1265/3723] pm: device_runtime: Avoid unnecessary work Similar to what is done in pm_device_runtime_get, we don't need to wait the device be suspended if the work is still in the work queue. In this case we just cancel the work and update the device state to active. Signed-off-by: Flavio Ceolin --- subsys/pm/device_runtime.c | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/subsys/pm/device_runtime.c b/subsys/pm/device_runtime.c index fb1d3286c54..b3546b6608f 100644 --- a/subsys/pm/device_runtime.c +++ b/subsys/pm/device_runtime.c @@ -347,8 +347,14 @@ int pm_device_runtime_disable(const struct device *dev) goto unlock; } - /* wait until possible async suspend is completed */ if (!k_is_pre_kernel()) { + if ((pm->state == PM_DEVICE_STATE_SUSPENDING) && + ((k_work_cancel_delayable(&pm->work) & K_WORK_RUNNING) == 0)) { + pm->state = PM_DEVICE_STATE_ACTIVE; + goto clear_bit; + } + + /* wait until possible async suspend is completed */ while (pm->state == PM_DEVICE_STATE_SUSPENDING) { k_sem_give(&pm->lock); @@ -368,6 +374,7 @@ int pm_device_runtime_disable(const struct device *dev) pm->state = PM_DEVICE_STATE_ACTIVE; } +clear_bit: atomic_clear_bit(&pm->flags, PM_DEVICE_FLAG_RUNTIME_ENABLED); unlock: From 29b19bcf8bc8f97069be00a9012c4cf1b7dbfb8b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Benjamin=20Cab=C3=A9?= Date: Tue, 5 Dec 2023 15:17:47 +0100 Subject: [PATCH 1266/3723] doc: sphinx: Tweak page scroll behavior to maximize real estate MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This picks up custom javscript from Godot documentation and uses CSS rules we already had in place (only they were not used) to tweak the page scroll behavior. As folks scroll down the page, the Zephyr logo in the top right corner gradually disappears, leaving more room for the navigation menu. Also, when scrolling in the navigation pane, the UI there is slightly adapted to make it more clear that the search box is "fixed", plus, when one reaches the bottom of the navigation tree and continues scrolling, the "main" page scrolls down. Signed-off-by: Benjamin Cabé --- doc/_static/js/custom.js | 122 +++++++++++++++++++++++++++++++++++++++ doc/conf.py | 1 + 2 files changed, 123 insertions(+) create mode 100644 doc/_static/js/custom.js diff --git a/doc/_static/js/custom.js b/doc/_static/js/custom.js new file mode 100644 index 00000000000..52f254b38c7 --- /dev/null +++ b/doc/_static/js/custom.js @@ -0,0 +1,122 @@ +/** + * Copyright (c) 2020-2023, The Godot community + * Copyright (c) 2023, Benjamin Cabé + * SPDX-License-Identifier: CC-BY-3.0 + */ + + +// Handle page scroll and adjust sidebar accordingly. + +// Each page has two scrolls: the main scroll, which is moving the content of the page; +// and the sidebar scroll, which is moving the navigation in the sidebar. +// We want the logo to gradually disappear as the main content is scrolled, giving +// more room to the navigation on the left. This means adjusting the height +// available to the navigation on the fly. +const registerOnScrollEvent = (function(){ + // Configuration. + + // The number of pixels the user must scroll by before the logo is completely hidden. + const scrollTopPixels = 156; + // The target margin to be applied to the navigation bar when the logo is hidden. + const menuTopMargin = 54; + // The max-height offset when the logo is completely visible. + const menuHeightOffset_default = 210; + // The max-height offset when the logo is completely hidden. + const menuHeightOffset_fixed = 63; + // The distance between the two max-height offset values above; used for intermediate values. + const menuHeightOffset_diff = (menuHeightOffset_default - menuHeightOffset_fixed); + + // Media query handler. + return function(mediaQuery) { + // We only apply this logic to the "desktop" resolution (defined by a media query at the bottom). + // This handler is executed when the result of the query evaluation changes, which means that + // the page has moved between "desktop" and "mobile" states. + + // When entering the "desktop" state, we register scroll events and adjust elements on the page. + // When entering the "mobile" state, we clean up any registered events and restore elements on the page + // to their initial state. + + const $window = $(window); + const $sidebar = $('.wy-side-scroll'); + const $search = $sidebar.children('.wy-side-nav-search'); + const $menu = $sidebar.children('.wy-menu-vertical'); + + if (mediaQuery.matches) { + // Entering the "desktop" state. + + // The main scroll event handler. + // Executed as the page is scrolled and once immediately as the page enters this state. + const handleMainScroll = (currentScroll) => { + if (currentScroll >= scrollTopPixels) { + // After the page is scrolled below the threshold, we fix everything in place. + $search.css('margin-top', `-${scrollTopPixels}px`); + $menu.css('margin-top', `${menuTopMargin}px`); + $menu.css('max-height', `calc(100% - ${menuHeightOffset_fixed}px)`); + } + else { + // Between the top of the page and the threshold we calculate intermediate values + // to guarantee a smooth transition. + $search.css('margin-top', `-${currentScroll}px`); + $menu.css('margin-top', `${menuTopMargin + (scrollTopPixels - currentScroll)}px`); + + if (currentScroll > 0) { + const scrolledPercent = (scrollTopPixels - currentScroll) / scrollTopPixels; + const offsetValue = menuHeightOffset_fixed + menuHeightOffset_diff * scrolledPercent; + $menu.css('max-height', `calc(100% - ${offsetValue}px)`); + } else { + $menu.css('max-height', `calc(100% - ${menuHeightOffset_default}px)`); + } + } + }; + + // The sidebar scroll event handler. + // Executed as the sidebar is scrolled as well as after the main scroll. This is needed + // because the main scroll can affect the scrollable area of the sidebar. + const handleSidebarScroll = () => { + const menuElement = $menu.get(0); + const menuScrollTop = $menu.scrollTop(); + const menuScrollBottom = menuElement.scrollHeight - (menuScrollTop + menuElement.offsetHeight); + + // As the navigation is scrolled we add a shadow to the top bar hanging over it. + if (menuScrollTop > 0) { + $search.addClass('fixed-and-scrolled'); + } else { + $search.removeClass('fixed-and-scrolled'); + } + }; + + $search.addClass('fixed'); + + $window.scroll(function() { + handleMainScroll(window.scrollY); + handleSidebarScroll(); + }); + + $menu.scroll(function() { + handleSidebarScroll(); + }); + + handleMainScroll(window.scrollY); + handleSidebarScroll(); + } else { + // Entering the "mobile" state. + + $window.unbind('scroll'); + $menu.unbind('scroll'); + + $search.removeClass('fixed'); + + $search.css('margin-top', `0px`); + $menu.css('margin-top', `0px`); + $menu.css('max-height', 'initial'); + } + }; + })(); + + $(document).ready(() => { + // Initialize handlers for page scrolling and our custom sidebar. + const mediaQuery = window.matchMedia('only screen and (min-width: 769px)'); + + registerOnScrollEvent(mediaQuery); + mediaQuery.addListener(registerOnScrollEvent); + }); diff --git a/doc/conf.py b/doc/conf.py index c0ce3c07235..35afc15af16 100644 --- a/doc/conf.py +++ b/doc/conf.py @@ -339,4 +339,5 @@ def setup(app): # theme customizations app.add_css_file("css/custom.css") + app.add_js_file("js/custom.js") app.add_js_file("js/dark-mode-toggle.min.mjs", type="module") From 7d2b3302eb9b71c5f66b8a71b0fbb5080e132587 Mon Sep 17 00:00:00 2001 From: Anas Nashif Date: Mon, 11 Dec 2023 15:29:45 -0500 Subject: [PATCH 1267/3723] twister: support lcov > 2.0 Support lcov > 2.0 tool which has strict error checking and some new configuration options deprecating syntax used in 1.4 versions. Fixes #62202 Signed-off-by: Anas Nashif --- scripts/pylib/twister/twisterlib/coverage.py | 74 +++++++++++++++----- 1 file changed, 56 insertions(+), 18 deletions(-) diff --git a/scripts/pylib/twister/twisterlib/coverage.py b/scripts/pylib/twister/twisterlib/coverage.py index c1c9065d9ad..bb5f5a9dbca 100644 --- a/scripts/pylib/twister/twisterlib/coverage.py +++ b/scripts/pylib/twister/twisterlib/coverage.py @@ -138,6 +138,20 @@ def __init__(self): super().__init__() self.ignores = [] self.output_formats = "lcov,html" + self.version = self.get_version() + + def get_version(self): + try: + result = subprocess.run(['lcov', '--version'], + stdout=subprocess.PIPE, + stderr=subprocess.PIPE, + text=True, check=True) + version_output = result.stdout.strip().replace('lcov: LCOV version ', '') + return version_output + except subprocess.CalledProcessError as e: + logger.error(f"Unsable to determine lcov version: {e}") + + return "" def add_ignore_file(self, pattern): self.ignores.append('*' + pattern + '*') @@ -145,51 +159,75 @@ def add_ignore_file(self, pattern): def add_ignore_directory(self, pattern): self.ignores.append('*/' + pattern + '/*') + @staticmethod + def run_command(cmd, coveragelog): + cmd_str = " ".join(cmd) + logger.debug(f"Running {cmd_str}...") + return subprocess.call(cmd, stdout=coveragelog) + def _generate(self, outdir, coveragelog): coveragefile = os.path.join(outdir, "coverage.info") ztestfile = os.path.join(outdir, "ztest.info") + if self.version.startswith("2"): + branch_coverage = "branch_coverage=1" + ignore_errors = [ + "--ignore-errors", "inconsistent,inconsistent", + "--ignore-errors", "negative,negative", + "--ignore-errors", "unused,unused", + "--ignore-errors", "empty,empty", + "--ignore-errors", "mismatch,mismatch" + ] + else: + branch_coverage = "lcov_branch_coverage=1" + ignore_errors = [] + cmd = ["lcov", "--gcov-tool", str(self.gcov_tool), "--capture", "--directory", outdir, - "--rc", "lcov_branch_coverage=1", + "--rc", branch_coverage, "--output-file", coveragefile] - cmd_str = " ".join(cmd) - logger.debug(f"Running {cmd_str}...") - subprocess.call(cmd, stdout=coveragelog) + cmd = cmd + ignore_errors + self.run_command(cmd, coveragelog) # We want to remove tests/* and tests/ztest/test/* but save tests/ztest - subprocess.call(["lcov", "--gcov-tool", self.gcov_tool, "--extract", + cmd = ["lcov", "--gcov-tool", self.gcov_tool, "--extract", coveragefile, os.path.join(self.base_dir, "tests", "ztest", "*"), "--output-file", ztestfile, - "--rc", "lcov_branch_coverage=1"], stdout=coveragelog) + "--rc", branch_coverage] + + cmd = cmd + ignore_errors + self.run_command(cmd, coveragelog) if os.path.exists(ztestfile) and os.path.getsize(ztestfile) > 0: - subprocess.call(["lcov", "--gcov-tool", self.gcov_tool, "--remove", + cmd = ["lcov", "--gcov-tool", self.gcov_tool, "--remove", ztestfile, os.path.join(self.base_dir, "tests/ztest/test/*"), "--output-file", ztestfile, - "--rc", "lcov_branch_coverage=1"], - stdout=coveragelog) + "--rc", branch_coverage] + cmd = cmd + ignore_errors + self.run_command(cmd, coveragelog) + files = [coveragefile, ztestfile] else: files = [coveragefile] for i in self.ignores: - subprocess.call( - ["lcov", "--gcov-tool", self.gcov_tool, "--remove", - coveragefile, i, "--output-file", - coveragefile, "--rc", "lcov_branch_coverage=1"], - stdout=coveragelog) + cmd = ["lcov", "--gcov-tool", self.gcov_tool, "--remove", + coveragefile, i, + "--output-file", coveragefile, + "--rc", branch_coverage] + cmd = cmd + ignore_errors + self.run_command(cmd, coveragelog) if 'html' not in self.output_formats.split(','): return 0 # The --ignore-errors source option is added to avoid it exiting due to # samples/application_development/external_lib/ - return subprocess.call(["genhtml", "--legend", "--branch-coverage", - "--ignore-errors", "source", + cmd = ["genhtml", "--legend", "--branch-coverage", "-output-directory", - os.path.join(outdir, "coverage")] + files, - stdout=coveragelog) + os.path.join(outdir, "coverage")] + files + cmd = cmd + ignore_errors + return self.run_command(cmd, coveragelog) class Gcovr(CoverageTool): From 1453e26b2109bb4a4a40ad0d19733959ed046403 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Benjamin=20Cab=C3=A9?= Date: Fri, 27 Oct 2023 16:43:10 +0200 Subject: [PATCH 1268/3723] doc: update doxygen awesome to v2.3.1 MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Update to a more recent version of Doyxgen Awesome for better compatibilty with recent versions of Doxygen. Signed-off-by: Benjamin Cabé --- .../doxygen-awesome-darkmode-toggle.js | 54 +- ...n-awesome-sidebar-only-darkmode-toggle.css | 3 +- doc/_doxygen/doxygen-awesome-sidebar-only.css | 12 +- doc/_doxygen/doxygen-awesome.css | 1583 ++++++++++++++--- doc/_doxygen/footer.html | 14 - doc/_doxygen/header.html | 3 + 6 files changed, 1436 insertions(+), 233 deletions(-) diff --git a/doc/_doxygen/doxygen-awesome-darkmode-toggle.js b/doc/_doxygen/doxygen-awesome-darkmode-toggle.js index ae72bf7ec6e..4b4d92d4923 100644 --- a/doc/_doxygen/doxygen-awesome-darkmode-toggle.js +++ b/doc/_doxygen/doxygen-awesome-darkmode-toggle.js @@ -5,7 +5,7 @@ https://github.com/jothepro/doxygen-awesome-css MIT License -Copyright (c) 2021 jothepro +Copyright (c) 2021 - 2023 jothepro Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal @@ -28,19 +28,25 @@ SOFTWARE. */ class DoxygenAwesomeDarkModeToggle extends HTMLElement { + // SVG icons from https://fonts.google.com/icons + // Licensed under the Apache 2.0 license: + // https://www.apache.org/licenses/LICENSE-2.0.html + static lightModeIcon = `` + static darkModeIcon = `` + static title = "Toggle Light/Dark Mode" + static prefersLightModeInDarkModeKey = "prefers-light-mode-in-dark-mode" static prefersDarkModeInLightModeKey = "prefers-dark-mode-in-light-mode" static _staticConstructor = function() { - DoxygenAwesomeDarkModeToggle.darkModeEnabled = DoxygenAwesomeDarkModeToggle.userPreference - DoxygenAwesomeDarkModeToggle.enableDarkMode(DoxygenAwesomeDarkModeToggle.darkModeEnabled) + DoxygenAwesomeDarkModeToggle.enableDarkMode(DoxygenAwesomeDarkModeToggle.userPreference) // Update the color scheme when the browsers preference changes // without user interaction on the website. window.matchMedia('(prefers-color-scheme: dark)').addEventListener('change', event => { DoxygenAwesomeDarkModeToggle.onSystemPreferenceChanged() }) // Update the color scheme when the tab is made visible again. - // It is possible that the appearance was changed in another tab + // It is possible that the appearance was changed in another tab // while this tab was in the background. document.addEventListener("visibilitychange", visibilityState => { if (document.visibilityState === 'visible') { @@ -49,6 +55,32 @@ class DoxygenAwesomeDarkModeToggle extends HTMLElement { }); }() + static init() { + $(function() { + $(document).ready(function() { + const toggleButton = document.createElement('doxygen-awesome-dark-mode-toggle') + toggleButton.title = DoxygenAwesomeDarkModeToggle.title + toggleButton.updateIcon() + + window.matchMedia('(prefers-color-scheme: dark)').addEventListener('change', event => { + toggleButton.updateIcon() + }) + document.addEventListener("visibilitychange", visibilityState => { + if (document.visibilityState === 'visible') { + toggleButton.updateIcon() + } + }); + + $(document).ready(function(){ + document.getElementById("MSearchBox").parentNode.appendChild(toggleButton) + }) + $(window).resize(function(){ + document.getElementById("MSearchBox").parentNode.appendChild(toggleButton) + }) + }) + }) + } + constructor() { super(); this.onclick=this.toggleDarkMode @@ -65,7 +97,7 @@ class DoxygenAwesomeDarkModeToggle extends HTMLElement { * @returns `true` for dark-mode, `false` for light-mode user preference */ static get userPreference() { - return (!DoxygenAwesomeDarkModeToggle.systemPreference && localStorage.getItem(DoxygenAwesomeDarkModeToggle.prefersDarkModeInLightModeKey)) || + return (!DoxygenAwesomeDarkModeToggle.systemPreference && localStorage.getItem(DoxygenAwesomeDarkModeToggle.prefersDarkModeInLightModeKey)) || (DoxygenAwesomeDarkModeToggle.systemPreference && !localStorage.getItem(DoxygenAwesomeDarkModeToggle.prefersLightModeInDarkModeKey)) } @@ -88,11 +120,12 @@ class DoxygenAwesomeDarkModeToggle extends HTMLElement { } static enableDarkMode(enable) { - let head = document.getElementsByTagName('head')[0] if(enable) { + DoxygenAwesomeDarkModeToggle.darkModeEnabled = true document.documentElement.classList.add("dark-mode") document.documentElement.classList.remove("light-mode") } else { + DoxygenAwesomeDarkModeToggle.darkModeEnabled = false document.documentElement.classList.remove("dark-mode") document.documentElement.classList.add("light-mode") } @@ -109,6 +142,15 @@ class DoxygenAwesomeDarkModeToggle extends HTMLElement { toggleDarkMode() { DoxygenAwesomeDarkModeToggle.userPreference = !DoxygenAwesomeDarkModeToggle.userPreference + this.updateIcon() + } + + updateIcon() { + if(DoxygenAwesomeDarkModeToggle.darkModeEnabled) { + this.innerHTML = DoxygenAwesomeDarkModeToggle.darkModeIcon + } else { + this.innerHTML = DoxygenAwesomeDarkModeToggle.lightModeIcon + } } } diff --git a/doc/_doxygen/doxygen-awesome-sidebar-only-darkmode-toggle.css b/doc/_doxygen/doxygen-awesome-sidebar-only-darkmode-toggle.css index b988b6f05ed..7114a030435 100644 --- a/doc/_doxygen/doxygen-awesome-sidebar-only-darkmode-toggle.css +++ b/doc/_doxygen/doxygen-awesome-sidebar-only-darkmode-toggle.css @@ -1,4 +1,3 @@ - /** Doxygen Awesome @@ -6,7 +5,7 @@ https://github.com/jothepro/doxygen-awesome-css MIT License -Copyright (c) 2021 jothepro +Copyright (c) 2021 - 2023 jothepro Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal diff --git a/doc/_doxygen/doxygen-awesome-sidebar-only.css b/doc/_doxygen/doxygen-awesome-sidebar-only.css index 526761db69a..853f6d6926e 100644 --- a/doc/_doxygen/doxygen-awesome-sidebar-only.css +++ b/doc/_doxygen/doxygen-awesome-sidebar-only.css @@ -5,7 +5,7 @@ https://github.com/jothepro/doxygen-awesome-css MIT License -Copyright (c) 2021 jothepro +Copyright (c) 2021 - 2023 jothepro Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal @@ -31,10 +31,16 @@ html { /* side nav width. MUST be = `TREEVIEW_WIDTH`. * Make sure it is wide enough to contain the page title (logo + title + version) */ - --side-nav-fixed-width: 340px; + --side-nav-fixed-width: 335px; --menu-display: none; --top-height: 120px; + --toc-sticky-top: -25px; + --toc-max-height: calc(100vh - 2 * var(--spacing-medium) - 25px); +} + +#projectname { + white-space: nowrap; } @@ -64,6 +70,7 @@ html { height: var(--top-height); margin-bottom: calc(0px - var(--top-height)); max-width: var(--side-nav-fixed-width); + overflow: hidden; background: var(--side-nav-background); } #main-nav { @@ -74,6 +81,7 @@ html { .ui-resizable-handle { cursor: default; width: 1px !important; + background: var(--separator-color); box-shadow: 0 calc(-2 * var(--top-height)) 0 0 var(--separator-color); } diff --git a/doc/_doxygen/doxygen-awesome.css b/doc/_doxygen/doxygen-awesome.css index 8414dcbf651..05ecbfe94c1 100644 --- a/doc/_doxygen/doxygen-awesome.css +++ b/doc/_doxygen/doxygen-awesome.css @@ -5,7 +5,7 @@ https://github.com/jothepro/doxygen-awesome-css MIT License -Copyright (c) 2021 jothepro +Copyright (c) 2021 - 2023 jothepro Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal @@ -30,15 +30,13 @@ SOFTWARE. html { /* primary theme color. This will affect the entire websites color scheme: links, arrows, labels, ... */ --primary-color: #1779c4; - --primary-dark-color: #00559f; - --primary-light-color: #7aabd6; - --primary-lighter-color: #cae1f1; - --primary-lightest-color: #e9f1f8; + --primary-dark-color: #335c80; + --primary-light-color: #70b1e9; /* page base colors */ - --page-background-color: white; - --page-foreground-color: #2c3e50; - --page-secondary-foreground-color: #67727e; + --page-background-color: #ffffff; + --page-foreground-color: #2f4153; + --page-secondary-foreground-color: #6f7e8e; /* color for all separators on the website: hr, borders, ... */ --separator-color: #dedede; @@ -53,49 +51,57 @@ html { --spacing-medium: 10px; --spacing-large: 16px; - /* default box shadow used for raising an element above the normal content. Used in dropdowns, Searchresult, ... */ - --box-shadow: 0 2px 10px 0 rgba(0,0,0,.1); + /* default box shadow used for raising an element above the normal content. Used in dropdowns, search result, ... */ + --box-shadow: 0 2px 8px 0 rgba(0,0,0,.075); - --odd-color: rgba(0,0,0,.03); + --odd-color: rgba(0,0,0,.028); /* font-families. will affect all text on the website * font-family: the normal font for text, headlines, menus * font-family-monospace: used for preformatted text in memtitle, code, fragments */ --font-family: -apple-system,BlinkMacSystemFont,Segoe UI,Roboto,Oxygen,Ubuntu,Cantarell,Fira Sans,Droid Sans,Helvetica Neue,sans-serif; - --font-family-monospace: source-code-pro,Menlo,Monaco,Consolas,Courier New,monospace; + --font-family-monospace: ui-monospace,SFMono-Regular,SF Mono,Menlo,Consolas,Liberation Mono,monospace; /* font sizes */ --page-font-size: 15.6px; --navigation-font-size: 14.4px; - --code-font-size: 14.4px; /* affects code, fragment */ + --toc-font-size: 13.4px; + --code-font-size: 14px; /* affects code, fragment */ --title-font-size: 22px; /* content text properties. These only affect the page content, not the navigation or any other ui elements */ --content-line-height: 27px; /* The content is centered and constraint in it's width. To make the content fill the whole page, set the variable to auto.*/ - --content-maxwidth: 1000px; + --content-maxwidth: 1050px; + --table-line-height: 24px; + --toc-sticky-top: var(--spacing-medium); + --toc-width: 200px; + --toc-max-height: calc(100vh - 2 * var(--spacing-medium) - 85px); /* colors for various content boxes: @warning, @note, @deprecated @bug */ - --warning-color: #fca49b; - --warning-color-dark: #b61825; - --warning-color-darker: #75070f; - --note-color: rgba(255,229,100,.3); - --note-color-dark: #c39900; - --note-color-darker: #8d7400; - --deprecated-color: rgb(214, 216, 224); + --warning-color: #faf3d8; + --warning-color-dark: #f3a600; + --warning-color-darker: #5f4204; + --note-color: #e4f3ff; + --note-color-dark: #1879C4; + --note-color-darker: #274a5c; + --todo-color: #e4dafd; + --todo-color-dark: #5b2bdd; + --todo-color-darker: #2a0d72; + --deprecated-color: #ecf0f3; --deprecated-color-dark: #5b6269; --deprecated-color-darker: #43454a; - --bug-color: rgb(246, 208, 178); - --bug-color-dark: #a53a00; - --bug-color-darker: #5b1d00; - --invariant-color: #b7f8d0; - --invariant-color-dark: #00ba44; - --invariant-color-darker: #008622; + --bug-color: #f8d1cc; + --bug-color-dark: #b61825; + --bug-color-darker: #75070f; + --invariant-color: #d8f1e3; + --invariant-color-dark: #44b86f; + --invariant-color-darker: #265532; /* blockquote colors */ - --blockquote-background: #f5f5f5; - --blockquote-foreground: #727272; + --blockquote-background: #f8f9fa; + --blockquote-foreground: #636568; /* table colors */ --tablehead-background: #f1f1f1; @@ -124,24 +130,25 @@ html { * on smaller screens the searchbar will always fill the entire screen width) */ --searchbar-height: 33px; --searchbar-width: 210px; + --searchbar-border-radius: var(--searchbar-height); /* code block colors */ --code-background: #f5f5f5; --code-foreground: var(--page-foreground-color); /* fragment colors */ - --fragment-background: #282c34; - --fragment-foreground: #ffffff; - --fragment-keyword: #cc99cd; - --fragment-keywordtype: #ab99cd; - --fragment-keywordflow: #e08000; - --fragment-token: #7ec699; - --fragment-comment: #999999; - --fragment-link: #98c0e3; - --fragment-preprocessor: #65cabe; - --fragment-linenumber-color: #cccccc; - --fragment-linenumber-background: #35393c; - --fragment-linenumber-border: #1f1f1f; + --fragment-background: #F8F9FA; + --fragment-foreground: #37474F; + --fragment-keyword: #bb6bb2; + --fragment-keywordtype: #8258b3; + --fragment-keywordflow: #d67c3b; + --fragment-token: #438a59; + --fragment-comment: #969696; + --fragment-link: #5383d6; + --fragment-preprocessor: #46aaa5; + --fragment-linenumber-color: #797979; + --fragment-linenumber-background: #f4f4f5; + --fragment-linenumber-border: #e3e5e7; --fragment-lineheight: 20px; /* sidebar navigation (treeview) colors */ @@ -150,16 +157,27 @@ html { --side-nav-arrow-opacity: 0; --side-nav-arrow-hover-opacity: 0.9; - /* height of an item in any tree / collapsable table */ + --toc-background: var(--side-nav-background); + --toc-foreground: var(--side-nav-foreground); + + /* height of an item in any tree / collapsible table */ --tree-item-height: 30px; - --darkmode-toggle-button-icon: '☀️' + --memname-font-size: var(--code-font-size); + --memtitle-font-size: 18px; + + --webkit-scrollbar-size: 7px; + --webkit-scrollbar-padding: 4px; + --webkit-scrollbar-color: var(--separator-color); + + --animation-duration: .12s } @media screen and (max-width: 767px) { html { --page-font-size: 16px; --navigation-font-size: 16px; + --toc-font-size: 15px; --code-font-size: 15px; /* affects code, fragment */ --title-font-size: 22px; } @@ -170,44 +188,59 @@ html { color-scheme: dark; --primary-color: #1982d2; - --primary-dark-color: #5ca8e2; + --primary-dark-color: #86a9c4; --primary-light-color: #4779ac; - --primary-lighter-color: #191e21; - --primary-lightest-color: #191a1c; - --box-shadow: 0 2px 10px 0 rgba(0,0,0,.35); + --box-shadow: 0 2px 8px 0 rgba(0,0,0,.35); - --odd-color: rgba(0,0,0,.1); + --odd-color: rgba(100,100,100,.06); --menu-selected-background: rgba(0,0,0,.4); --page-background-color: #1C1D1F; --page-foreground-color: #d2dbde; --page-secondary-foreground-color: #859399; - --separator-color: #000000; + --separator-color: #38393b; --side-nav-background: #252628; --code-background: #2a2c2f; --tablehead-background: #2a2c2f; - --blockquote-background: #1f2022; - --blockquote-foreground: #77848a; - - --warning-color: #b61825; - --warning-color-dark: #510a02; - --warning-color-darker: #f5b1aa; - --note-color: rgb(255, 183, 0); - --note-color-dark: #9f7300; - --note-color-darker: #645b39; - --deprecated-color: rgb(88, 90, 96); - --deprecated-color-dark: #262e37; - --deprecated-color-darker: #a0a5b0; - --bug-color: rgb(248, 113, 0); - --bug-color-dark: #812a00; - --bug-color-darker: #ffd3be; - - --darkmode-toggle-button-icon: '🌛'; + --blockquote-background: #222325; + --blockquote-foreground: #7e8c92; + + --warning-color: #3b2e04; + --warning-color-dark: #f1b602; + --warning-color-darker: #ceb670; + --note-color: #163750; + --note-color-dark: #1982D2; + --note-color-darker: #dcf0fa; + --todo-color: #2a2536; + --todo-color-dark: #7661b3; + --todo-color-darker: #ae9ed6; + --deprecated-color: #2e323b; + --deprecated-color-dark: #738396; + --deprecated-color-darker: #abb0bd; + --bug-color: #2e1917; + --bug-color-dark: #ad2617; + --bug-color-darker: #f5b1aa; + --invariant-color: #303a35; + --invariant-color-dark: #76ce96; + --invariant-color-darker: #cceed5; + + --fragment-background: #282c34; + --fragment-foreground: #dbe4eb; + --fragment-keyword: #cc99cd; + --fragment-keywordtype: #ab99cd; + --fragment-keywordflow: #e08000; + --fragment-token: #7ec699; + --fragment-comment: #999999; + --fragment-link: #98c0e3; + --fragment-preprocessor: #65cabe; + --fragment-linenumber-color: #cccccc; + --fragment-linenumber-background: #35393c; + --fragment-linenumber-border: #1f1f1f; } } @@ -216,44 +249,59 @@ html.dark-mode { color-scheme: dark; --primary-color: #1982d2; - --primary-dark-color: #5ca8e2; + --primary-dark-color: #86a9c4; --primary-light-color: #4779ac; - --primary-lighter-color: #191e21; - --primary-lightest-color: #191a1c; - --box-shadow: 0 2px 10px 0 rgba(0,0,0,.35); + --box-shadow: 0 2px 8px 0 rgba(0,0,0,.30); - --odd-color: rgba(0,0,0,.1); + --odd-color: rgba(100,100,100,.06); --menu-selected-background: rgba(0,0,0,.4); --page-background-color: #1C1D1F; --page-foreground-color: #d2dbde; --page-secondary-foreground-color: #859399; - --separator-color: #000000; + --separator-color: #38393b; --side-nav-background: #252628; --code-background: #2a2c2f; --tablehead-background: #2a2c2f; - --blockquote-background: #1f2022; - --blockquote-foreground: #77848a; + --blockquote-background: #222325; + --blockquote-foreground: #7e8c92; + + --warning-color: #3b2e04; + --warning-color-dark: #f1b602; + --warning-color-darker: #ceb670; + --note-color: #163750; + --note-color-dark: #1982D2; + --note-color-darker: #dcf0fa; + --todo-color: #2a2536; + --todo-color-dark: #7661b3; + --todo-color-darker: #ae9ed6; + --deprecated-color: #2e323b; + --deprecated-color-dark: #738396; + --deprecated-color-darker: #abb0bd; + --bug-color: #2e1917; + --bug-color-dark: #ad2617; + --bug-color-darker: #f5b1aa; + --invariant-color: #303a35; + --invariant-color-dark: #76ce96; + --invariant-color-darker: #cceed5; - --warning-color: #b61825; - --warning-color-dark: #510a02; - --warning-color-darker: #f5b1aa; - --note-color: rgb(255, 183, 0); - --note-color-dark: #9f7300; - --note-color-darker: #645b39; - --deprecated-color: rgb(88, 90, 96); - --deprecated-color-dark: #262e37; - --deprecated-color-darker: #a0a5b0; - --bug-color: rgb(248, 113, 0); - --bug-color-dark: #812a00; - --bug-color-darker: #ffd3be; - - --darkmode-toggle-button-icon: '🌛'; + --fragment-background: #282c34; + --fragment-foreground: #dbe4eb; + --fragment-keyword: #cc99cd; + --fragment-keywordtype: #ab99cd; + --fragment-keywordflow: #e08000; + --fragment-token: #7ec699; + --fragment-comment: #999999; + --fragment-link: #98c0e3; + --fragment-preprocessor: #65cabe; + --fragment-linenumber-color: #cccccc; + --fragment-linenumber-background: #35393c; + --fragment-linenumber-border: #1f1f1f; } body { @@ -262,25 +310,37 @@ body { font-size: var(--page-font-size); } -body, table, div, p, dl, #nav-tree .label, .title, .sm-dox a, .sm-dox a:hover, .sm-dox a:focus, #projectname, .SelectItem, #MSearchField, .navpath li.navelem a, .navpath li.navelem a:hover { +body, table, div, p, dl, #nav-tree .label, .title, +.sm-dox a, .sm-dox a:hover, .sm-dox a:focus, #projectname, +.SelectItem, #MSearchField, .navpath li.navelem a, +.navpath li.navelem a:hover, p.reference, p.definition { font-family: var(--font-family); } h1, h2, h3, h4, h5 { - margin-top: .9em; + margin-top: 1em; font-weight: 600; line-height: initial; } -p, div, table, dl { +p, div, table, dl, p.reference, p.definition { font-size: var(--page-font-size); } +p.reference, p.definition { + color: var(--page-secondary-foreground-color); +} + a:link, a:visited, a:hover, a:focus, a:active { color: var(--primary-color) !important; font-weight: 500; } +a.anchor { + scroll-margin-top: var(--spacing-large); + display: block; +} + /* Title and top navigation */ @@ -356,10 +416,23 @@ a:link, a:visited, a:hover, a:focus, a:active { margin-bottom: -1px; } +.main-menu-btn-icon, .main-menu-btn-icon:before, .main-menu-btn-icon:after { + background: var(--page-secondary-foreground-color); +} + @media screen and (max-width: 767px) { .sm-dox a span.sub-arrow { background: var(--code-background); } + + #main-menu a.has-submenu span.sub-arrow { + color: var(--page-secondary-foreground-color); + border-radius: var(--border-radius-medium); + } + + #main-menu a.has-submenu:hover span.sub-arrow { + color: var(--page-foreground-color); + } } @media screen and (min-width: 768px) { @@ -434,6 +507,7 @@ a:link, a:visited, a:hover, a:focus, a:active { color: var(--header-foreground) !important; font-weight: normal; font-size: var(--navigation-font-size); + border-radius: var(--border-radius-small) !important; } .sm-dox a:focus { @@ -470,7 +544,7 @@ a:link, a:visited, a:hover, a:focus, a:active { #MSearchBox { height: var(--searchbar-height); background: var(--searchbar-background); - border-radius: var(--searchbar-height); + border-radius: var(--searchbar-border-radius); border: 1px solid var(--separator-color); overflow: hidden; width: var(--searchbar-width); @@ -480,8 +554,27 @@ a:link, a:visited, a:hover, a:focus, a:active { margin-top: 0; } -.left #MSearchSelect { +/* until Doxygen 1.9.4 */ +.left img#MSearchSelect { + left: 0; + user-select: none; + padding-left: 8px; +} + +/* Doxygen 1.9.5 */ +.left span#MSearchSelect { left: 0; + user-select: none; + margin-left: 8px; + padding: 0; +} + +.left #MSearchSelect[src$=".png"] { + padding-left: 0 +} + +.SelectionMark { + user-select: none; } .tabs .left #MSearchSelect { @@ -536,12 +629,9 @@ a:link, a:visited, a:hover, a:focus, a:active { top: calc(calc(var(--searchbar-height) / 2) - 11px); } -.left #MSearchSelect { - padding-left: 8px; -} - #MSearchBox span.left, #MSearchBox span.right { background: none; + background-image: none; } #MSearchBox span.right { @@ -595,11 +685,22 @@ html.dark-mode iframe#MSearchResults { filter: invert() hue-rotate(180deg); } +#MSearchResults .SRPage { + background-color: transparent; +} + +#MSearchResults .SRPage .SREntry { + font-size: 10pt; + padding: var(--spacing-small) var(--spacing-medium); +} + #MSearchSelectWindow { border: 1px solid var(--separator-color); border-radius: var(--border-radius-medium); box-shadow: var(--box-shadow); background: var(--page-background-color); + padding-top: var(--spacing-small); + padding-bottom: var(--spacing-small); } #MSearchSelectWindow a.SelectItem { @@ -649,6 +750,7 @@ html.dark-mode iframe#MSearchResults { overflow: auto; transform: translate(0, 20px); animation: ease-out 280ms slideInSearchResultsMobile; + width: auto !important; } /* @@ -676,6 +778,8 @@ html.dark-mode iframe#MSearchResults { #side-nav { padding: 0 !important; background: var(--side-nav-background); + min-width: 8px; + max-width: 50vw; } @media screen and (max-width: 767px) { @@ -685,13 +789,12 @@ html.dark-mode iframe#MSearchResults { #doc-content { margin-left: 0 !important; - height: auto !important; - padding-bottom: calc(2 * var(--spacing-large)); } } #nav-tree { background: transparent; + margin-right: 1px; } #nav-tree .label { @@ -704,17 +807,31 @@ html.dark-mode iframe#MSearchResults { } #nav-sync { - top: 12px !important; + bottom: 12px; right: 12px; + top: auto !important; + user-select: none; } #nav-tree .selected { text-shadow: none; background-image: none; background-color: transparent; - box-shadow: inset 4px 0 0 0 var(--primary-color); + position: relative; +} + +#nav-tree .selected::after { + content: ""; + position: absolute; + top: 1px; + bottom: 1px; + left: 0; + width: 4px; + border-radius: 0 var(--border-radius-small) var(--border-radius-small) 0; + background: var(--primary-color); } + #nav-tree a { color: var(--side-nav-foreground) !important; font-weight: normal; @@ -750,8 +867,9 @@ html.dark-mode iframe#MSearchResults { } .ui-resizable-e { - background: var(--separator-color); - width: 1px; + width: 4px; + background: transparent; + box-shadow: inset -1px 0 0 0 var(--separator-color); } /* @@ -764,6 +882,21 @@ div.header { background-image: none; } +@media screen and (min-width: 1000px) { + #doc-content > div > div.contents, + .PageDoc > div.contents { + display: flex; + flex-direction: row-reverse; + flex-wrap: nowrap; + align-items: flex-start; + } + + div.contents .textblock { + min-width: 200px; + flex-grow: 1; + } +} + div.contents, div.header .title, div.header .summary { max-width: var(--content-maxwidth); } @@ -783,7 +916,7 @@ div.headertitle { div.header .title { font-weight: 600; - font-size: 210%; + font-size: 225%; padding: var(--spacing-medium) var(--spacing-large); word-break: break-word; } @@ -799,14 +932,6 @@ td.memSeparator { border-color: var(--separator-color); } -.mdescLeft, .mdescRight, .memItemLeft, .memItemRight, .memTemplItemLeft, .memTemplItemRight, .memTemplParams { - background: var(--code-background); -} - -.mdescRight { - color: var(--page-secondary-foreground-color); -} - span.mlabel { background: var(--primary-color); border: none; @@ -834,34 +959,82 @@ div.contents div.dyncontent { @media (prefers-color-scheme: dark) { html:not(.light-mode) div.contents div.dyncontent img, html:not(.light-mode) div.contents center img, - html:not(.light-mode) div.contents table img, + html:not(.light-mode) div.contents > table img, html:not(.light-mode) div.contents div.dyncontent iframe, html:not(.light-mode) div.contents center iframe, - html:not(.light-mode) div.contents table iframe { - filter: hue-rotate(180deg) invert(); + html:not(.light-mode) div.contents table iframe, + html:not(.light-mode) div.contents .dotgraph iframe { + filter: brightness(89%) hue-rotate(180deg) invert(); } } html.dark-mode div.contents div.dyncontent img, html.dark-mode div.contents center img, -html.dark-mode div.contents table img, +html.dark-mode div.contents > table img, html.dark-mode div.contents div.dyncontent iframe, html.dark-mode div.contents center iframe, -html.dark-mode div.contents table iframe { - filter: hue-rotate(180deg) invert(); +html.dark-mode div.contents table iframe, +html.dark-mode div.contents .dotgraph iframe + { + filter: brightness(89%) hue-rotate(180deg) invert(); } h2.groupheader { - border-bottom: 1px solid var(--separator-color); + border-bottom: 0px; color: var(--page-foreground-color); + box-shadow: + 100px 0 var(--page-background-color), + -100px 0 var(--page-background-color), + 100px 0.75px var(--separator-color), + -100px 0.75px var(--separator-color), + 500px 0 var(--page-background-color), + -500px 0 var(--page-background-color), + 500px 0.75px var(--separator-color), + -500px 0.75px var(--separator-color), + 900px 0 var(--page-background-color), + -900px 0 var(--page-background-color), + 900px 0.75px var(--separator-color), + -900px 0.75px var(--separator-color), + 1400px 0 var(--page-background-color), + -1400px 0 var(--page-background-color), + 1400px 0.75px var(--separator-color), + -1400px 0.75px var(--separator-color), + 1900px 0 var(--page-background-color), + -1900px 0 var(--page-background-color), + 1900px 0.75px var(--separator-color), + -1900px 0.75px var(--separator-color); } blockquote { - padding: var(--spacing-small) var(--spacing-medium); + margin: 0 var(--spacing-medium) 0 var(--spacing-medium); + padding: var(--spacing-small) var(--spacing-large); background: var(--blockquote-background); color: var(--blockquote-foreground); - border-left: 2px solid var(--blockquote-foreground); - margin: 0; + border-left: 0; + overflow: visible; + border-radius: var(--border-radius-medium); + overflow: visible; + position: relative; +} + +blockquote::before, blockquote::after { + font-weight: bold; + font-family: serif; + font-size: 360%; + opacity: .15; + position: absolute; +} + +blockquote::before { + content: "“"; + left: -10px; + top: 4px; +} + +blockquote::after { + content: "”"; + right: -8px; + bottom: -25px; } blockquote p { @@ -872,62 +1045,156 @@ blockquote p { color: var(--primary-dark-color); } -.glow { - text-shadow: 0 0 15px var(--primary-light-color) !important; +.paramname > code { + border: 0; +} + +table.params .paramname { + font-weight: 600; + font-family: var(--font-family-monospace); + font-size: var(--code-font-size); + padding-right: var(--spacing-small); + line-height: var(--table-line-height); +} + +h1.glow, h2.glow, h3.glow, h4.glow, h5.glow, h6.glow { + text-shadow: 0 0 15px var(--primary-light-color); } .alphachar a { color: var(--page-foreground-color); } +.dotgraph { + max-width: 100%; + overflow-x: scroll; +} + +.dotgraph .caption { + position: sticky; + left: 0; +} + +/* Wrap Graphviz graphs with the `interactive_dotgraph` class if `INTERACTIVE_SVG = YES` */ +.interactive_dotgraph .dotgraph iframe { + max-width: 100%; +} + /* Table of Contents */ -div.toc { - background-color: var(--side-nav-background); - border: 1px solid var(--separator-color); - border-radius: var(--border-radius-medium); - box-shadow: var(--box-shadow); +div.contents .toc { + max-height: var(--toc-max-height); + min-width: var(--toc-width); + border: 0; + border-left: 1px solid var(--separator-color); + border-radius: 0; + background-color: transparent; + box-shadow: none; + position: sticky; + top: var(--toc-sticky-top); padding: 0 var(--spacing-large); - margin: 0 0 var(--spacing-medium) var(--spacing-medium); + margin: var(--spacing-small) 0 var(--spacing-large) var(--spacing-large); } div.toc h3 { - color: var(--side-nav-foreground); + color: var(--toc-foreground); font-size: var(--navigation-font-size); - margin: var(--spacing-large) 0; + margin: var(--spacing-large) 0 var(--spacing-medium) 0; } div.toc li { - font-size: var(--navigation-font-size); padding: 0; background: none; + line-height: var(--toc-font-size); + margin: var(--toc-font-size) 0 0 0; } -div.toc li:before { - content: '↓'; - font-weight: 800; - font-family: var(--font-family); - margin-right: var(--spacing-small); - color: var(--side-nav-foreground); - opacity: .4; +div.toc li::before { + display: none; } -div.toc ul li.level1 { - margin: 0; +div.toc ul { + margin-top: 0 } -div.toc ul li.level2, div.toc ul li.level3 { - margin-top: 0; +div.toc li a { + font-size: var(--toc-font-size); + color: var(--page-foreground-color) !important; + text-decoration: none; +} + +div.toc li a:hover, div.toc li a.active { + color: var(--primary-color) !important; +} + +div.toc li a.aboveActive { + color: var(--page-secondary-foreground-color) !important; } -@media screen and (max-width: 767px) { - div.toc { +@media screen and (max-width: 999px) { + div.contents .toc { + max-height: 45vh; float: none; width: auto; margin: 0 0 var(--spacing-medium) 0; + position: relative; + top: 0; + position: relative; + border: 1px solid var(--separator-color); + border-radius: var(--border-radius-medium); + background-color: var(--toc-background); + box-shadow: var(--box-shadow); + } + + div.contents .toc.interactive { + max-height: calc(var(--navigation-font-size) + 2 * var(--spacing-large)); + overflow: hidden; + } + + div.contents .toc > h3 { + -webkit-tap-highlight-color: transparent; + cursor: pointer; + position: sticky; + top: 0; + background-color: var(--toc-background); + margin: 0; + padding: var(--spacing-large) 0; + display: block; + } + + div.contents .toc.interactive > h3::before { + content: ""; + width: 0; + height: 0; + border-left: 4px solid transparent; + border-right: 4px solid transparent; + border-top: 5px solid var(--primary-color); + display: inline-block; + margin-right: var(--spacing-small); + margin-bottom: calc(var(--navigation-font-size) / 4); + transform: rotate(-90deg); + transition: transform var(--animation-duration) ease-out; + } + + div.contents .toc.interactive.open > h3::before { + transform: rotate(0deg); + } + + div.contents .toc.interactive.open { + max-height: 45vh; + overflow: auto; + transition: max-height 0.2s ease-in-out; + } + + div.contents .toc a, div.contents .toc a.active { + color: var(--primary-color) !important; + } + + div.contents .toc a:hover { + text-decoration: underline; } } @@ -937,7 +1204,7 @@ div.toc ul li.level2, div.toc ul li.level3 { code, div.fragment, pre.fragment { border-radius: var(--border-radius-small); - border: none; + border: 1px solid var(--separator-color); overflow: hidden; } @@ -946,12 +1213,11 @@ code { background: var(--code-background); color: var(--code-foreground); padding: 2px 6px; - word-break: break-word; } div.fragment, pre.fragment { margin: var(--spacing-medium) 0; - padding: 14px 16px; + padding: calc(var(--spacing-large) - (var(--spacing-large) / 6)) var(--spacing-large); background: var(--fragment-background); color: var(--fragment-foreground); overflow-x: auto; @@ -961,24 +1227,49 @@ div.fragment, pre.fragment { div.fragment, pre.fragment { border-top-right-radius: 0; border-bottom-right-radius: 0; + border-right: 0; } - .contents > div.fragment, .textblock > div.fragment, .textblock > pre.fragment { + .contents > div.fragment, + .textblock > div.fragment, + .textblock > pre.fragment, + .textblock > .tabbed > ul > li > div.fragment, + .textblock > .tabbed > ul > li > pre.fragment, + .contents > .doxygen-awesome-fragment-wrapper > div.fragment, + .textblock > .doxygen-awesome-fragment-wrapper > div.fragment, + .textblock > .doxygen-awesome-fragment-wrapper > pre.fragment, + .textblock > .tabbed > ul > li > .doxygen-awesome-fragment-wrapper > div.fragment, + .textblock > .tabbed > ul > li > .doxygen-awesome-fragment-wrapper > pre.fragment { margin: var(--spacing-medium) calc(0px - var(--spacing-large)); border-radius: 0; + border-left: 0; } - .textblock li > .fragment { + .textblock li > .fragment, + .textblock li > .doxygen-awesome-fragment-wrapper > .fragment { margin: var(--spacing-medium) calc(0px - var(--spacing-large)); } - .memdoc li > .fragment { + .memdoc li > .fragment, + .memdoc li > .doxygen-awesome-fragment-wrapper > .fragment { margin: var(--spacing-medium) calc(0px - var(--spacing-medium)); } - .memdoc > div.fragment, .memdoc > pre.fragment, dl dd > div.fragment, dl dd pre.fragment { + .textblock ul, .memdoc ul { + overflow: initial; + } + + .memdoc > div.fragment, + .memdoc > pre.fragment, + dl dd > div.fragment, + dl dd pre.fragment, + .memdoc > .doxygen-awesome-fragment-wrapper > div.fragment, + .memdoc > .doxygen-awesome-fragment-wrapper > pre.fragment, + dl dd > .doxygen-awesome-fragment-wrapper > div.fragment, + dl dd .doxygen-awesome-fragment-wrapper > pre.fragment { margin: var(--spacing-medium) calc(0px - var(--spacing-medium)); border-radius: 0; + border-left: 0; } } @@ -1038,15 +1329,29 @@ div.fragment span.lineno a { color: var(--fragment-link) !important; } -div.fragment .line:first-child .lineno { +div.fragment > .line:first-child .lineno { box-shadow: -999999px 0px 0 999999px var(--fragment-linenumber-background), -999998px 0px 0 999999px var(--fragment-linenumber-border); + background-color: var(--fragment-linenumber-background) !important; +} + +div.line { + border-radius: var(--border-radius-small); +} + +div.line.glow { + background-color: var(--primary-light-color); + box-shadow: none; } /* dl warning, attention, note, deprecated, bug, ... */ -dl.warning, dl.attention, dl.note, dl.deprecated, dl.bug, dl.invariant, dl.pre { +dl.bug dt a, dl.deprecated dt a, dl.todo dt a { + font-weight: bold !important; +} + +dl.warning, dl.attention, dl.note, dl.deprecated, dl.bug, dl.invariant, dl.pre, dl.post, dl.todo, dl.remark { padding: var(--spacing-medium); margin: var(--spacing-medium) 0; color: var(--page-background-color); @@ -1069,16 +1374,30 @@ dl.warning dt, dl.attention dt { color: var(--warning-color-dark); } -dl.note { +dl.note, dl.remark { background: var(--note-color); border-left: 8px solid var(--note-color-dark); color: var(--note-color-darker); } -dl.note dt { +dl.note dt, dl.remark dt { color: var(--note-color-dark); } +dl.todo { + background: var(--todo-color); + border-left: 8px solid var(--todo-color-dark); + color: var(--todo-color-darker); +} + +dl.todo dt a { + color: var(--todo-color-dark) !important; +} + +dl.bug dt a { + color: var(--todo-color-dark) !important; +} + dl.bug { background: var(--bug-color); border-left: 8px solid var(--bug-color-dark); @@ -1099,16 +1418,20 @@ dl.deprecated dt a { color: var(--deprecated-color-dark) !important; } -dl.section dd, dl.bug dd, dl.deprecated dd { +dl.section dd, dl.bug dd, dl.deprecated dd, dl.todo dd { margin-inline-start: 0px; } -dl.invariant, dl.pre { +dl.invariant, dl.pre, dl.post { background: var(--invariant-color); border-left: 8px solid var(--invariant-color-dark); color: var(--invariant-color-darker); } +dl.invariant dt, dl.pre dt, dl.post dt { + color: var(--invariant-color-dark); +} + /* memitem */ @@ -1126,32 +1449,63 @@ div.memdoc { h2.memtitle, div.memitem { border: 1px solid var(--separator-color); + box-shadow: var(--box-shadow); +} + +h2.memtitle { + box-shadow: 0px var(--spacing-medium) 0 -1px var(--fragment-background), var(--box-shadow); +} + +div.memitem { + transition: none; } div.memproto, h2.memtitle { - background: var(--code-background); - text-shadow: none; + background: var(--fragment-background); } h2.memtitle { font-weight: 500; - font-family: monospace, fixed; + font-size: var(--memtitle-font-size); + font-family: var(--font-family-monospace); border-bottom: none; border-top-left-radius: var(--border-radius-medium); border-top-right-radius: var(--border-radius-medium); word-break: break-all; + position: relative; } -a:target + h2.memtitle, a:target + h2.memtitle + div.memitem { - border-color: var(--primary-light-color); +h2.memtitle:after { + content: ""; + display: block; + background: var(--fragment-background); + height: var(--spacing-medium); + bottom: calc(0px - var(--spacing-medium)); + left: 0; + right: -14px; + position: absolute; + border-top-right-radius: var(--border-radius-medium); +} + +h2.memtitle > span.permalink { + font-size: inherit; +} + +h2.memtitle > span.permalink > a { + text-decoration: none; + padding-left: 3px; + margin-right: -4px; + user-select: none; + display: inline-block; + margin-top: -6px; } -a:target + h2.memtitle { - box-shadow: -3px -3px 3px 0 var(--primary-lightest-color), 3px -3px 3px 0 var(--primary-lightest-color); +h2.memtitle > span.permalink > a:hover { + color: var(--primary-dark-color) !important; } -a:target + h2.memtitle + div.memitem { - box-shadow: 0 0 10px 0 var(--primary-lighter-color); +a:target + h2.memtitle, a:target + h2.memtitle + div.memitem { + border-color: var(--primary-light-color); } div.memitem { @@ -1180,8 +1534,18 @@ div.memtitle { } div.memproto table.memname { - font-family: monospace, fixed; + font-family: var(--font-family-monospace); color: var(--page-foreground-color); + font-size: var(--memname-font-size); + text-shadow: none; +} + +div.memproto div.memtemplate { + font-family: var(--font-family-monospace); + color: var(--primary-dark-color); + font-size: var(--memname-font-size); + margin-left: 2px; + text-shadow: none; } table.mlabels, table.mlabels > tbody { @@ -1192,6 +1556,12 @@ td.mlabels-left { width: auto; } +td.mlabels-right { + margin-top: 3px; + position: sticky; + left: 0; +} + table.mlabels > tbody > tr:first-child { display: flex; justify-content: space-between; @@ -1241,56 +1611,361 @@ dl.reflist dd { Table */ -table.markdownTable, table.fieldtable { - width: 100%; - border: 1px solid var(--separator-color); +.contents table:not(.memberdecls):not(.mlabels):not(.fieldtable):not(.memname), +.contents table:not(.memberdecls):not(.mlabels):not(.fieldtable):not(.memname) tbody { + display: inline-block; + max-width: 100%; +} + +.contents > table:not(.memberdecls):not(.mlabels):not(.fieldtable):not(.memname):not(.classindex) { + margin-left: calc(0px - var(--spacing-large)); + margin-right: calc(0px - var(--spacing-large)); + max-width: calc(100% + 2 * var(--spacing-large)); +} + +table.fieldtable, +table.markdownTable tbody, +table.doxtable tbody { + border: none; margin: var(--spacing-medium) 0; + box-shadow: 0 0 0 1px var(--separator-color); + border-radius: var(--border-radius-small); +} + +table.markdownTable, table.doxtable, table.fieldtable { + padding: 1px; +} + +table.doxtable caption { + display: block; } table.fieldtable { - box-shadow: none; - border-radius: var(--border-radius-small); + border-collapse: collapse; + width: 100%; } -th.markdownTableHeadLeft, th.markdownTableHeadRight, th.markdownTableHeadCenter, th.markdownTableHeadNone { +th.markdownTableHeadLeft, +th.markdownTableHeadRight, +th.markdownTableHeadCenter, +th.markdownTableHeadNone, +table.doxtable th { background: var(--tablehead-background); color: var(--tablehead-foreground); font-weight: 600; font-size: var(--page-font-size); } -table.markdownTable td, table.markdownTable th, table.fieldtable dt { +th.markdownTableHeadLeft:first-child, +th.markdownTableHeadRight:first-child, +th.markdownTableHeadCenter:first-child, +th.markdownTableHeadNone:first-child, +table.doxtable tr th:first-child { + border-top-left-radius: var(--border-radius-small); +} + +th.markdownTableHeadLeft:last-child, +th.markdownTableHeadRight:last-child, +th.markdownTableHeadCenter:last-child, +th.markdownTableHeadNone:last-child, +table.doxtable tr th:last-child { + border-top-right-radius: var(--border-radius-small); +} + +table.markdownTable td, +table.markdownTable th, +table.fieldtable td, +table.fieldtable th, +table.doxtable td, +table.doxtable th { border: 1px solid var(--separator-color); padding: var(--spacing-small) var(--spacing-medium); } +table.markdownTable td:last-child, +table.markdownTable th:last-child, +table.fieldtable td:last-child, +table.fieldtable th:last-child, +table.doxtable td:last-child, +table.doxtable th:last-child { + border-right: none; +} + +table.markdownTable td:first-child, +table.markdownTable th:first-child, +table.fieldtable td:first-child, +table.fieldtable th:first-child, +table.doxtable td:first-child, +table.doxtable th:first-child { + border-left: none; +} + +table.markdownTable tr:first-child td, +table.markdownTable tr:first-child th, +table.fieldtable tr:first-child td, +table.fieldtable tr:first-child th, +table.doxtable tr:first-child td, +table.doxtable tr:first-child th { + border-top: none; +} + +table.markdownTable tr:last-child td, +table.markdownTable tr:last-child th, +table.fieldtable tr:last-child td, +table.fieldtable tr:last-child th, +table.doxtable tr:last-child td, +table.doxtable tr:last-child th { + border-bottom: none; +} + +table.markdownTable tr, table.doxtable tr { + border-bottom: 1px solid var(--separator-color); +} + +table.markdownTable tr:last-child, table.doxtable tr:last-child { + border-bottom: none; +} + +.full_width_table table:not(.memberdecls):not(.mlabels):not(.fieldtable):not(.memname) { + display: block; +} + +.full_width_table table:not(.memberdecls):not(.mlabels):not(.fieldtable):not(.memname) tbody { + display: table; + width: 100%; +} + table.fieldtable th { font-size: var(--page-font-size); font-weight: 600; background-image: none; background-color: var(--tablehead-background); color: var(--tablehead-foreground); - border-bottom: 1px solid var(--separator-color); } -.fieldtable td.fieldtype, .fieldtable td.fieldname { +table.fieldtable td.fieldtype, .fieldtable td.fieldname, .fieldtable td.fielddoc, .fieldtable th { border-bottom: 1px solid var(--separator-color); border-right: 1px solid var(--separator-color); } -.fieldtable td.fielddoc { - border-bottom: 1px solid var(--separator-color); +table.fieldtable tr:last-child td:first-child { + border-bottom-left-radius: var(--border-radius-small); } -.memberdecls td.glow, .fieldtable tr.glow { - background-color: var(--primary-light-color); - box-shadow: 0 0 15px var(--primary-lighter-color); +table.fieldtable tr:last-child td:last-child { + border-bottom-right-radius: var(--border-radius-small); +} + +.memberdecls td.glow, .fieldtable tr.glow { + background-color: var(--primary-light-color); + box-shadow: none; } table.memberdecls { display: block; - overflow-x: auto; - overflow-y: hidden; + -webkit-tap-highlight-color: transparent; +} + +table.memberdecls tr[class^='memitem'] { + font-family: var(--font-family-monospace); + font-size: var(--code-font-size); +} + +table.memberdecls tr[class^='memitem'] .memTemplParams { + font-family: var(--font-family-monospace); + font-size: var(--code-font-size); + color: var(--primary-dark-color); + white-space: normal; +} + +table.memberdecls .memItemLeft, +table.memberdecls .memItemRight, +table.memberdecls .memTemplItemLeft, +table.memberdecls .memTemplItemRight, +table.memberdecls .memTemplParams { + transition: none; + padding-top: var(--spacing-small); + padding-bottom: var(--spacing-small); + border-top: 1px solid var(--separator-color); + border-bottom: 1px solid var(--separator-color); + background-color: var(--fragment-background); +} + +table.memberdecls .memTemplItemLeft, +table.memberdecls .memTemplItemRight { + padding-top: 2px; +} + +table.memberdecls .memTemplParams { + border-bottom: 0; + border-left: 1px solid var(--separator-color); + border-right: 1px solid var(--separator-color); + border-radius: var(--border-radius-small) var(--border-radius-small) 0 0; + padding-bottom: var(--spacing-small); +} + +table.memberdecls .memTemplItemLeft { + border-radius: 0 0 0 var(--border-radius-small); + border-left: 1px solid var(--separator-color); + border-top: 0; +} + +table.memberdecls .memTemplItemRight { + border-radius: 0 0 var(--border-radius-small) 0; + border-right: 1px solid var(--separator-color); + padding-left: 0; + border-top: 0; +} + +table.memberdecls .memItemLeft { + border-radius: var(--border-radius-small) 0 0 var(--border-radius-small); + border-left: 1px solid var(--separator-color); + padding-left: var(--spacing-medium); + padding-right: 0; +} + +table.memberdecls .memItemRight { + border-radius: 0 var(--border-radius-small) var(--border-radius-small) 0; + border-right: 1px solid var(--separator-color); + padding-right: var(--spacing-medium); + padding-left: 0; + +} + +table.memberdecls .mdescLeft, table.memberdecls .mdescRight { + background: none; + color: var(--page-foreground-color); + padding: var(--spacing-small) 0; +} + +table.memberdecls .memItemLeft, +table.memberdecls .memTemplItemLeft { + padding-right: var(--spacing-medium); +} + +table.memberdecls .memSeparator { + background: var(--page-background-color); + height: var(--spacing-large); + border: 0; + transition: none; +} + +table.memberdecls .groupheader { + margin-bottom: var(--spacing-large); +} + +table.memberdecls .inherit_header td { + padding: 0 0 var(--spacing-medium) 0; + text-indent: -12px; + color: var(--page-secondary-foreground-color); +} + +table.memberdecls img[src="closed.png"], +table.memberdecls img[src="open.png"], +div.dynheader img[src="open.png"], +div.dynheader img[src="closed.png"] { + width: 0; + height: 0; + border-left: 4px solid transparent; + border-right: 4px solid transparent; + border-top: 5px solid var(--primary-color); + margin-top: 8px; + display: block; + float: left; + margin-left: -10px; + transition: transform var(--animation-duration) ease-out; +} + +table.memberdecls img { + margin-right: 10px; +} + +table.memberdecls img[src="closed.png"], +div.dynheader img[src="closed.png"] { + transform: rotate(-90deg); + +} + +.compoundTemplParams { + font-family: var(--font-family-monospace); + color: var(--primary-dark-color); + font-size: var(--code-font-size); +} + +@media screen and (max-width: 767px) { + + table.memberdecls .memItemLeft, + table.memberdecls .memItemRight, + table.memberdecls .mdescLeft, + table.memberdecls .mdescRight, + table.memberdecls .memTemplItemLeft, + table.memberdecls .memTemplItemRight, + table.memberdecls .memTemplParams { + display: block; + text-align: left; + padding-left: var(--spacing-large); + margin: 0 calc(0px - var(--spacing-large)) 0 calc(0px - var(--spacing-large)); + border-right: none; + border-left: none; + border-radius: 0; + white-space: normal; + } + + table.memberdecls .memItemLeft, + table.memberdecls .mdescLeft, + table.memberdecls .memTemplItemLeft { + border-bottom: 0; + padding-bottom: 0; + } + + table.memberdecls .memTemplItemLeft { + padding-top: 0; + } + + table.memberdecls .mdescLeft { + margin-bottom: calc(0px - var(--page-font-size)); + } + + table.memberdecls .memItemRight, + table.memberdecls .mdescRight, + table.memberdecls .memTemplItemRight { + border-top: 0; + padding-top: 0; + padding-right: var(--spacing-large); + overflow-x: auto; + } + + table.memberdecls tr[class^='memitem']:not(.inherit) { + display: block; + width: calc(100vw - 2 * var(--spacing-large)); + } + + table.memberdecls .mdescRight { + color: var(--page-foreground-color); + } + + table.memberdecls tr.inherit { + visibility: hidden; + } + + table.memberdecls tr[style="display: table-row;"] { + display: block !important; + visibility: visible; + width: calc(100vw - 2 * var(--spacing-large)); + animation: fade .5s; + } + + @keyframes fade { + 0% { + opacity: 0; + max-height: 0; + } + + 100% { + opacity: 1; + max-height: 200px; + } + } } @@ -1301,15 +1976,33 @@ table.memberdecls { hr { margin-top: var(--spacing-large); margin-bottom: var(--spacing-large); - border-top:1px solid var(--separator-color); + height: 1px; + background-color: var(--separator-color); + border: 0; } .contents hr { - box-shadow: var(--content-maxwidth) 0 0 0 var(--separator-color), calc(0px - var(--content-maxwidth)) 0 0 0 var(--separator-color); + box-shadow: 100px 0 0 var(--separator-color), + -100px 0 0 var(--separator-color), + 500px 0 0 var(--separator-color), + -500px 0 0 var(--separator-color), + 1500px 0 0 var(--separator-color), + -1500px 0 0 var(--separator-color), + 2000px 0 0 var(--separator-color), + -2000px 0 0 var(--separator-color); } -.contents img { +.contents img, .contents .center, .contents center, .contents div.image object { max-width: 100%; + overflow: auto; +} + +@media screen and (max-width: 767px) { + .contents .dyncontent > .center, .contents > center { + margin-left: calc(0px - var(--spacing-large)); + margin-right: calc(0px - var(--spacing-large)); + max-width: calc(100% + 2 * var(--spacing-large)); + } } /* @@ -1325,18 +2018,42 @@ table.directory { font-family: var(--font-family); font-size: var(--page-font-size); font-weight: normal; + width: 100%; } -.directory td.entry { - padding: var(--spacing-small); - display: flex; - align-items: center; +table.directory td.entry, table.directory td.desc { + padding: calc(var(--spacing-small) / 2) var(--spacing-small); + line-height: var(--table-line-height); +} + +table.directory tr.even td:last-child { + border-radius: 0 var(--border-radius-small) var(--border-radius-small) 0; +} + +table.directory tr.even td:first-child { + border-radius: var(--border-radius-small) 0 0 var(--border-radius-small); +} + +table.directory tr.even:last-child td:last-child { + border-radius: 0 var(--border-radius-small) 0 0; +} + +table.directory tr.even:last-child td:first-child { + border-radius: var(--border-radius-small) 0 0 0; +} + +table.directory td.desc { + min-width: 250px; } -.directory tr.even { +table.directory tr.even { background-color: var(--odd-color); } +table.directory tr.odd { + background-color: transparent; +} + .icona { width: auto; height: auto; @@ -1345,14 +2062,20 @@ table.directory { .icon { background: var(--primary-color); - width: 18px; - height: 18px; - line-height: 18px; + border-radius: var(--border-radius-small); + font-size: var(--page-font-size); + padding: calc(var(--page-font-size) / 5); + line-height: var(--page-font-size); + transform: scale(0.8); + height: auto; + width: var(--page-font-size); + user-select: none; } .iconfopen, .icondoc, .iconfclosed { background-position: center; margin-bottom: 0; + height: var(--table-line-height); } .icondoc { @@ -1361,8 +2084,8 @@ table.directory { @media screen and (max-width: 767px) { div.directory { - margin-left: calc(0px - var(--spacing-medium)); - margin-right: calc(0px - var(--spacing-medium)); + margin-left: calc(0px - var(--spacing-large)); + margin-right: calc(0px - var(--spacing-large)); } } @@ -1385,10 +2108,35 @@ html.dark-mode .iconfopen, html.dark-mode .iconfclosed { border-radius: var(--border-radius-small); } -@media screen and (max-width: 767px) { - .classindex { - margin: 0 calc(0px - var(--spacing-small)); - } +.classindex dl.even { + background-color: transparent; +} + +/* + Class Index Doxygen 1.8 +*/ + +table.classindex { + margin-left: 0; + margin-right: 0; + width: 100%; +} + +table.classindex table div.ah { + background-image: none; + background-color: initial; + border-color: var(--separator-color); + color: var(--page-foreground-color); + box-shadow: var(--box-shadow); + border-radius: var(--border-radius-large); + padding: var(--spacing-small); +} + +div.qindex { + background-color: var(--odd-color); + border-radius: var(--border-radius-small); + border: 1px solid var(--separator-color); + padding: var(--spacing-small) 0; } /* @@ -1396,7 +2144,6 @@ html.dark-mode .iconfopen, html.dark-mode .iconfclosed { */ #nav-path { - margin-bottom: -1px; width: 100%; } @@ -1406,6 +2153,8 @@ html.dark-mode .iconfopen, html.dark-mode .iconfclosed { border: none; border-top: 1px solid var(--separator-color); border-bottom: 1px solid var(--separator-color); + border-bottom: 0; + box-shadow: 0 0.75px 0 var(--separator-color); font-size: var(--navigation-font-size); } @@ -1418,6 +2167,7 @@ img.footer { } address.footer { + color: var(--page-secondary-foreground-color); margin-bottom: var(--spacing-large); } @@ -1457,7 +2207,7 @@ li.navelem:first-child:before { border-bottom-color: transparent; border-right-color: transparent; border-top-color: transparent; - transform: scaleY(4.2); + transform: translateY(-1px) scaleY(4.2); z-index: 10; margin-left: 6px; } @@ -1468,7 +2218,7 @@ li.navelem:first-child:before { border-bottom-color: transparent; border-right-color: transparent; border-top-color: transparent; - transform: scaleY(3.2); + transform: translateY(-1px) scaleY(3.2); margin-right: var(--spacing-small); } @@ -1476,6 +2226,106 @@ li.navelem:first-child:before { color: var(--primary-color); } +/* + Scrollbars for Webkit +*/ + +#nav-tree::-webkit-scrollbar, +div.fragment::-webkit-scrollbar, +pre.fragment::-webkit-scrollbar, +div.memproto::-webkit-scrollbar, +.contents center::-webkit-scrollbar, +.contents .center::-webkit-scrollbar, +.contents table:not(.memberdecls):not(.mlabels):not(.fieldtable):not(.memname) tbody::-webkit-scrollbar, +div.contents .toc::-webkit-scrollbar, +.contents .dotgraph::-webkit-scrollbar, +.contents .tabs-overview-container::-webkit-scrollbar { + background: transparent; + width: calc(var(--webkit-scrollbar-size) + var(--webkit-scrollbar-padding) + var(--webkit-scrollbar-padding)); + height: calc(var(--webkit-scrollbar-size) + var(--webkit-scrollbar-padding) + var(--webkit-scrollbar-padding)); +} + +#nav-tree::-webkit-scrollbar-thumb, +div.fragment::-webkit-scrollbar-thumb, +pre.fragment::-webkit-scrollbar-thumb, +div.memproto::-webkit-scrollbar-thumb, +.contents center::-webkit-scrollbar-thumb, +.contents .center::-webkit-scrollbar-thumb, +.contents table:not(.memberdecls):not(.mlabels):not(.fieldtable):not(.memname) tbody::-webkit-scrollbar-thumb, +div.contents .toc::-webkit-scrollbar-thumb, +.contents .dotgraph::-webkit-scrollbar-thumb, +.contents .tabs-overview-container::-webkit-scrollbar-thumb { + background-color: transparent; + border: var(--webkit-scrollbar-padding) solid transparent; + border-radius: calc(var(--webkit-scrollbar-padding) + var(--webkit-scrollbar-padding)); + background-clip: padding-box; +} + +#nav-tree:hover::-webkit-scrollbar-thumb, +div.fragment:hover::-webkit-scrollbar-thumb, +pre.fragment:hover::-webkit-scrollbar-thumb, +div.memproto:hover::-webkit-scrollbar-thumb, +.contents center:hover::-webkit-scrollbar-thumb, +.contents .center:hover::-webkit-scrollbar-thumb, +.contents table:not(.memberdecls):not(.mlabels):not(.fieldtable):not(.memname) tbody:hover::-webkit-scrollbar-thumb, +div.contents .toc:hover::-webkit-scrollbar-thumb, +.contents .dotgraph:hover::-webkit-scrollbar-thumb, +.contents .tabs-overview-container:hover::-webkit-scrollbar-thumb { + background-color: var(--webkit-scrollbar-color); +} + +#nav-tree::-webkit-scrollbar-track, +div.fragment::-webkit-scrollbar-track, +pre.fragment::-webkit-scrollbar-track, +div.memproto::-webkit-scrollbar-track, +.contents center::-webkit-scrollbar-track, +.contents .center::-webkit-scrollbar-track, +.contents table:not(.memberdecls):not(.mlabels):not(.fieldtable):not(.memname) tbody::-webkit-scrollbar-track, +div.contents .toc::-webkit-scrollbar-track, +.contents .dotgraph::-webkit-scrollbar-track, +.contents .tabs-overview-container::-webkit-scrollbar-track { + background: transparent; +} + +#nav-tree::-webkit-scrollbar-corner { + background-color: var(--side-nav-background); +} + +#nav-tree, +div.fragment, +pre.fragment, +div.memproto, +.contents center, +.contents .center, +.contents table:not(.memberdecls):not(.mlabels):not(.fieldtable):not(.memname) tbody, +div.contents .toc { + overflow-x: auto; + overflow-x: overlay; +} + +#nav-tree { + overflow-x: auto; + overflow-y: auto; + overflow-y: overlay; +} + +/* + Scrollbars for Firefox +*/ + +#nav-tree, +div.fragment, +pre.fragment, +div.memproto, +.contents center, +.contents .center, +.contents table:not(.memberdecls):not(.mlabels):not(.fieldtable):not(.memname) tbody, +div.contents .toc, +.contents .dotgraph, +.contents .tabs-overview-container { + scrollbar-width: thin; +} + /* Optional Dark mode toggle button */ @@ -1488,17 +2338,332 @@ doxygen-awesome-dark-mode-toggle { height: var(--searchbar-height); background: none; border: none; - font-size: 23px; - border-radius: var(--border-radius-medium); + border-radius: var(--searchbar-height); vertical-align: middle; text-align: center; line-height: var(--searchbar-height); + font-size: 22px; + display: flex; + align-items: center; + justify-content: center; + user-select: none; + cursor: pointer; +} + +doxygen-awesome-dark-mode-toggle > svg { + transition: transform var(--animation-duration) ease-in-out; +} + +doxygen-awesome-dark-mode-toggle:active > svg { + transform: scale(.5); } doxygen-awesome-dark-mode-toggle:hover { + background-color: rgba(0,0,0,.03); +} + +html.dark-mode doxygen-awesome-dark-mode-toggle:hover { + background-color: rgba(0,0,0,.18); +} + +/* + Optional fragment copy button +*/ +.doxygen-awesome-fragment-wrapper { + position: relative; +} + +doxygen-awesome-fragment-copy-button { + opacity: 0; + background: var(--fragment-background); + width: 28px; + height: 28px; + position: absolute; + right: calc(var(--spacing-large) - (var(--spacing-large) / 2.5)); + top: calc(var(--spacing-large) - (var(--spacing-large) / 2.5)); + border: 1px solid var(--fragment-foreground); + cursor: pointer; + border-radius: var(--border-radius-small); + display: flex; + justify-content: center; + align-items: center; +} + +.doxygen-awesome-fragment-wrapper:hover doxygen-awesome-fragment-copy-button, doxygen-awesome-fragment-copy-button.success { + opacity: .28; +} + +doxygen-awesome-fragment-copy-button:hover, doxygen-awesome-fragment-copy-button.success { + opacity: 1 !important; +} + +doxygen-awesome-fragment-copy-button:active:not([class~=success]) svg { + transform: scale(.91); +} + +doxygen-awesome-fragment-copy-button svg { + fill: var(--fragment-foreground); + width: 18px; + height: 18px; +} + +doxygen-awesome-fragment-copy-button.success svg { + fill: rgb(14, 168, 14); +} + +doxygen-awesome-fragment-copy-button.success { + border-color: rgb(14, 168, 14); +} + +@media screen and (max-width: 767px) { + .textblock > .doxygen-awesome-fragment-wrapper > doxygen-awesome-fragment-copy-button, + .textblock li > .doxygen-awesome-fragment-wrapper > doxygen-awesome-fragment-copy-button, + .memdoc li > .doxygen-awesome-fragment-wrapper > doxygen-awesome-fragment-copy-button, + .memdoc > .doxygen-awesome-fragment-wrapper > doxygen-awesome-fragment-copy-button, + dl dd > .doxygen-awesome-fragment-wrapper > doxygen-awesome-fragment-copy-button { + right: 0; + } +} + +/* + Optional paragraph link button +*/ + +a.anchorlink { + font-size: 90%; + margin-left: var(--spacing-small); + color: var(--page-foreground-color) !important; + text-decoration: none; + opacity: .15; + display: none; + transition: opacity var(--animation-duration) ease-in-out, color var(--animation-duration) ease-in-out; +} + +a.anchorlink svg { + fill: var(--page-foreground-color); +} + +h3 a.anchorlink svg, h4 a.anchorlink svg { + margin-bottom: -3px; + margin-top: -4px; +} + +a.anchorlink:hover { + opacity: .45; +} + +h2:hover a.anchorlink, h1:hover a.anchorlink, h3:hover a.anchorlink, h4:hover a.anchorlink { + display: inline-block; +} + +/* + Optional tab feature +*/ + +.tabbed ul { + padding-inline-start: 0px; + margin: 0; + padding: var(--spacing-small) 0; +} + +.tabbed li { + display: none; +} + +.tabbed li.selected { + display: block; +} + +.tabs-overview-container { + overflow-x: auto; + display: block; + overflow-y: visible; +} + +.tabs-overview { + border-bottom: 1px solid var(--separator-color); + display: flex; + flex-direction: row; +} + +@media screen and (max-width: 767px) { + .tabs-overview-container { + margin: 0 calc(0px - var(--spacing-large)); + } + .tabs-overview { + padding: 0 var(--spacing-large) + } +} + +.tabs-overview button.tab-button { + color: var(--page-foreground-color); + margin: 0; + border: none; + background: transparent; + padding: calc(var(--spacing-large) / 2) 0; + display: inline-block; + font-size: var(--page-font-size); + cursor: pointer; + box-shadow: 0 1px 0 0 var(--separator-color); + position: relative; + + -webkit-tap-highlight-color: transparent; +} + +.tabs-overview button.tab-button .tab-title::before { + display: block; + content: attr(title); + font-weight: 600; + height: 0; + overflow: hidden; + visibility: hidden; +} + +.tabs-overview button.tab-button .tab-title { + float: left; + white-space: nowrap; + font-weight: normal; + padding: calc(var(--spacing-large) / 2) var(--spacing-large); + border-radius: var(--border-radius-medium); + transition: background-color var(--animation-duration) ease-in-out, font-weight var(--animation-duration) ease-in-out; +} + +.tabs-overview button.tab-button:not(:last-child) .tab-title { + box-shadow: 8px 0 0 -7px var(--separator-color); +} + +.tabs-overview button.tab-button:hover .tab-title { background: var(--separator-color); + box-shadow: none; +} + +.tabs-overview button.tab-button.active .tab-title { + font-weight: 600; +} + +.tabs-overview button.tab-button::after { + content: ''; + display: block; + position: absolute; + left: 0; + bottom: 0; + right: 0; + height: 0; + width: 0%; + margin: 0 auto; + border-radius: var(--border-radius-small) var(--border-radius-small) 0 0; + background-color: var(--primary-color); + transition: width var(--animation-duration) ease-in-out, height var(--animation-duration) ease-in-out; +} + +.tabs-overview button.tab-button.active::after { + width: 100%; + box-sizing: border-box; + height: 3px; +} + + +/* + Navigation Buttons +*/ + +.section_buttons:not(:empty) { + margin-top: calc(var(--spacing-large) * 3); +} + +.section_buttons table.markdownTable { + display: block; + width: 100%; +} + +.section_buttons table.markdownTable tbody { + display: table !important; + width: 100%; + box-shadow: none; + border-spacing: 10px; +} + +.section_buttons table.markdownTable td { + padding: 0; } -doxygen-awesome-dark-mode-toggle:after { - content: var(--darkmode-toggle-button-icon) +.section_buttons table.markdownTable th { + display: none; +} + +.section_buttons table.markdownTable tr.markdownTableHead { + border: none; +} + +.section_buttons tr th, .section_buttons tr td { + background: none; + border: none; + padding: var(--spacing-large) 0 var(--spacing-small); +} + +.section_buttons a { + display: inline-block; + border: 1px solid var(--separator-color); + border-radius: var(--border-radius-medium); + color: var(--page-secondary-foreground-color) !important; + text-decoration: none; + transition: color var(--animation-duration) ease-in-out, background-color var(--animation-duration) ease-in-out; +} + +.section_buttons a:hover { + color: var(--page-foreground-color) !important; + background-color: var(--odd-color); +} + +.section_buttons tr td.markdownTableBodyLeft a { + padding: var(--spacing-medium) var(--spacing-large) var(--spacing-medium) calc(var(--spacing-large) / 2); +} + +.section_buttons tr td.markdownTableBodyRight a { + padding: var(--spacing-medium) calc(var(--spacing-large) / 2) var(--spacing-medium) var(--spacing-large); +} + +.section_buttons tr td.markdownTableBodyLeft a::before, +.section_buttons tr td.markdownTableBodyRight a::after { + color: var(--page-secondary-foreground-color) !important; + display: inline-block; + transition: color .08s ease-in-out, transform .09s ease-in-out; +} + +.section_buttons tr td.markdownTableBodyLeft a::before { + content: '〈'; + padding-right: var(--spacing-large); +} + + +.section_buttons tr td.markdownTableBodyRight a::after { + content: '〉'; + padding-left: var(--spacing-large); +} + + +.section_buttons tr td.markdownTableBodyLeft a:hover::before { + color: var(--page-foreground-color) !important; + transform: translateX(-3px); +} + +.section_buttons tr td.markdownTableBodyRight a:hover::after { + color: var(--page-foreground-color) !important; + transform: translateX(3px); +} + +@media screen and (max-width: 450px) { + .section_buttons a { + width: 100%; + box-sizing: border-box; + } + + .section_buttons tr td:nth-of-type(1).markdownTableBodyLeft a { + border-radius: var(--border-radius-medium) 0 0 var(--border-radius-medium); + border-right: none; + } + + .section_buttons tr td:nth-of-type(2).markdownTableBodyRight a { + border-radius: 0 var(--border-radius-medium) var(--border-radius-medium) 0; + } } diff --git a/doc/_doxygen/footer.html b/doc/_doxygen/footer.html index 9d24d69b7be..efa3357e594 100644 --- a/doc/_doxygen/footer.html +++ b/doc/_doxygen/footer.html @@ -13,19 +13,5 @@ $generatedby doxygen $doxygenversion
- diff --git a/doc/_doxygen/header.html b/doc/_doxygen/header.html index 4422349d766..06be6c6529d 100644 --- a/doc/_doxygen/header.html +++ b/doc/_doxygen/header.html @@ -13,6 +13,9 @@ + $treeview $search $mathjax From 66fbf35435b1f70a750e1ee754ae0e241b52ab3c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Benjamin=20Cab=C3=A9?= Date: Tue, 7 Nov 2023 12:40:15 +0100 Subject: [PATCH 1269/3723] doc: remove readthedocs-sphinx-search CSS rules MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The "Sphinx search extension" CSS rules are not needed as we are not using this extension since we are not hosting on readthedocs.io. Signed-off-by: Benjamin Cabé --- doc/_static/css/custom.css | 99 -------------------------------------- 1 file changed, 99 deletions(-) diff --git a/doc/_static/css/custom.css b/doc/_static/css/custom.css index 72756780b8e..7b1f513aa5b 100644 --- a/doc/_static/css/custom.css +++ b/doc/_static/css/custom.css @@ -163,105 +163,6 @@ a.icon-home:visited { color: var(--navbar-level-1-color); } -/* Sphinx Search extension */ -/* .wy-body-for-nav is used for higher rule specificity */ - -/* Search popup body */ -.wy-body-for-nav .search__outer { - background-color: var(--content-background-color); - border: 2px solid var(--content-background-color); -} -.wy-body-for-nav .search__cross svg { - fill: var(--body-color); -} - -.wy-body-for-nav .search__outer::-webkit-scrollbar-track { - border-radius: 10px; - background-color: var(--content-background-color); -} -.wy-body-for-nav .search__outer::-webkit-scrollbar { - width: 7px; - height: 7px; - background-color: var(--content-background-color); -} -.wy-body-for-nav .search__outer::-webkit-scrollbar-thumb { - border-radius: 10px; - background-color: var(--hr-color); -} - -/* Search input */ -.wy-body-for-nav .search__outer__input { - background-color: var(--search-input-background-color); - background-image: none; - border-radius: 50px; - border: 2px solid transparent; - color: var(--body-color); - height: 36px; - padding: 6px 12px; -} -.wy-body-for-nav .search__outer__input:focus { - border-color: var(--input-focus-border-color); -} -.wy-body-for-nav .search__outer .bar:after, -.wy-body-for-nav .search__outer .bar:before { - display: none; -} - -/* Search results item */ -.wy-body-for-nav .search__result__single { - border-bottom-color: var(--hr-color); -} -/* Search item title */ -.wy-body-for-nav .search__result__title { - color: var(--link-color); - border-bottom: none; - font-size: 120%; - font-weight: 400; -} - -/* Search item section */ -.wy-body-for-nav .outer_div_page_results:hover, -.wy-body-for-nav .search__result__box .active { - background-color: var(--search-active-color); -} -.wy-body-for-nav .search__result__subheading{ - color: var(--body-color); - font-size: 100%; - font-weight: 400; -} -.wy-body-for-nav .search__result__content { - color: var(--footer-color); -} - -/* Search item matching substring */ -.wy-body-for-nav .search__outer .search__result__title span, -.wy-body-for-nav .search__outer .search__result__content span { - color: var(--search-match-color); - border-bottom: 1px solid var(--search-match-color); - background-color: var(--search-match-background-color); - padding: 0 2px; -} -.wy-body-for-nav .search__result__subheading span { - border-bottom-color: var(--body-color); -} - -/* Search empty results */ -/* The original styles are inlined, see https://github.com/readthedocs/readthedocs-sphinx-search/issues/48 */ -.wy-body-for-nav .search__result__box { - color: var(--body-color) !important; -} - -/* Search footer & credits */ -.wy-body-for-nav .rtd__search__credits { - background-color: var(--search-credits-background-color); - border-color: var(--search-credits-background-color); - color: var(--search-credits-color); - padding: 4px 8px; -} -.wy-body-for-nav .rtd__search__credits a { - color: var(--search-credits-link-color); -} - /* Main sections */ .wy-nav-content-wrap { From fc0a9c5655b0ea19e50546330cf4c1163b034826 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Benjamin=20Cab=C3=A9?= Date: Tue, 7 Nov 2023 10:56:12 +0100 Subject: [PATCH 1270/3723] doc: exclude some HTML DIVs from search engine "snippets" MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Some portions of the documentation do not make sense when shown as "snippets" in search engines' results. Use "data-nosnippet" attribute to instruct search engines (Google for sure, hopefully others in the future) to exclude them. Signed-off-by: Benjamin Cabé --- doc/_templates/footer.html | 2 +- doc/_templates/layout.html | 32 +++++++++++++++++--------------- 2 files changed, 18 insertions(+), 16 deletions(-) diff --git a/doc/_templates/footer.html b/doc/_templates/footer.html index 54ba724acb3..757bb27529d 100644 --- a/doc/_templates/footer.html +++ b/doc/_templates/footer.html @@ -13,7 +13,7 @@

{%- set git_last_updated, sha1 = pagename | git_info | default((None, None), true) %} {%- if git_last_updated %} -
+

Help us keep our technical documentation accurate and up-to-date!

diff --git a/doc/_templates/layout.html b/doc/_templates/layout.html index 205b2488555..6d58c015548 100644 --- a/doc/_templates/layout.html +++ b/doc/_templates/layout.html @@ -1,12 +1,12 @@ {% extends "!layout.html" %} {% block document %} {% if is_release %} -
+
The latest development version of this page may be more current than this released {{ version }} version.
{% else %} -
+
This is the documentation for the latest (main) development branch of Zephyr. If you are looking for the documentation of previous releases, use the drop-down menu on the left and select the desired version. @@ -15,20 +15,22 @@ {{ super() }} {% endblock %} {% block menu %} - {% include "zversions.html" %} - {{ super() }} - {% if reference_links %} -
-

Reference

-
    - {% for title, url in reference_links.items() %} -
  • - {{ title }} -
  • - {% endfor %} -
+
+ {% include "zversions.html" %} + {{ super() }} + {% if reference_links %} +
+

Reference

+
    + {% for title, url in reference_links.items() %} +
  • + {{ title }} +
  • + {% endfor %} +
+
+ {% endif %}
- {% endif %} {% endblock %} {% block extrahead %} From 7688f4859c31bd7a8a97de7bb0432a2b1633ca1a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Benjamin=20Cab=C3=A9?= Date: Tue, 4 Jul 2023 17:20:09 +0200 Subject: [PATCH 1271/3723] doc: Add Google Programmable Search Engine MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Add Google Programmable Search engine to the documentation, while leaving it possible to easily revert to the built-in Sphinx search engine. As the styling of the search results is apparently not thought to be easy to tweak, the gcs.css stylesheet might require further improvements. Fixes #55173. Signed-off-by: Benjamin Cabé --- doc/_static/css/gcs.css | 101 +++++++++++++++++++++++++++++++++++++ doc/_templates/search.html | 28 ++++++++++ doc/conf.py | 6 ++- 3 files changed, 134 insertions(+), 1 deletion(-) create mode 100644 doc/_static/css/gcs.css create mode 100644 doc/_templates/search.html diff --git a/doc/_static/css/gcs.css b/doc/_static/css/gcs.css new file mode 100644 index 00000000000..16501108852 --- /dev/null +++ b/doc/_static/css/gcs.css @@ -0,0 +1,101 @@ +/** + * Copyright (c) 2023, Benjamin Cabé . + * SPDX-License-Identifier: Apache-2.0 + * + * Custom stylesheet for Google Programmable Search Engine results. + */ + +.gs-webResult .gs-snippet, +.gs-fileFormatType, +.gs-spelling, +.gsc-refinementHeader, +.gsc-result-info, +.gsc-orderby-label { + color: var(--body-color) !important; +} + +.gsc-control-cse { + width: 100%; + padding: 0 !important; + font-family: inherit !important; + font-size: inherit !important; + background-color: inherit !important; + border: none !important; + font-size: inherit !important; +} + +.gsc-completion-container { + font-family: inherit !important; +} + +.gs-result .gs-title, .gs-result .gs-title * { + color: var(--link-color) !important; + background-color: var(--content-background-color) !important; +} + +.gs-result .gs-title:visited, .gs-result .gs-title:visited * { + color: var(--link-color-visited) !important; +} + +.gsc-results .gsc-cursor-box .gsc-cursor-page, +.gsc-results .gsc-cursor-box .gsc-cursor-current-page { + background-color: var(--content-background-color) !important; + color: var(--link-color) !important; +} + +.gs-result .gs-image, .gs-result .gs-promotion-image { + border: none !important; + padding-right: .5em; +} + +.gsc-table-result { + font-family: inherit !important; + padding-top: .5em !important; + font-size: inherit !important; +} + +.gsc-tabHeader.gsc-tabhActive, .gsc-refinementHeader.gsc-refinementhActive, +.gsc-tabHeader.gsc-tabhInactive, .gsc-refinementHeader.gsc-refinementhInactive { + background-color: inherit !important; +} + +.gs-no-results-result .gs-snippet, .gs-error-result .gs-snippet { + color: var(--admonition-attention-title-color) !important; + background-color: var(--admonition-attention-title-background-color) !important; +} + +.gsc-webResult .gsc-result { + background-color: inherit !important; + margin: 0; + padding: .5em 0; + border: none !important; + border-bottom: 1px solid var(--hr-color) !important; +} + +.gs-webResult div.gs-per-result-labels { + margin-top: 1.3em; + margin-bottom: 0.3em; + font-size:0.8em; +} + +.gs-webResult div.gs-per-result-labels span { + display: none; +} + +.gs-webResult div.gs-per-result-labels a.gs-label { + text-decoration: none !important; + cursor: pointer; + padding: 0.4em 0.6em; + margin-left: .5em; + color: var(--admonition-tip-title-color) !important; + background-color: var(--admonition-tip-title-background-color) !important; + border-radius: 50px; +} + +.gcsc-find-more-on-google { + color: var(--link-color) !important; +} + +.gcsc-find-more-on-google-magnifier { + fill: var(--link-color) !important; +} diff --git a/doc/_templates/search.html b/doc/_templates/search.html new file mode 100644 index 00000000000..ee9343cce08 --- /dev/null +++ b/doc/_templates/search.html @@ -0,0 +1,28 @@ +{%- extends "!search.html" %} +{%- block scripts %} + {% if google_searchengine_id %} + {{ super.super() }} + + {% else %} + {{ super() }} + {% endif %} +{%- endblock %} + +{% block footer %} + {% if google_searchengine_id %} + {{ super.super() }} + {% else %} + {{ super() }} + {% endif %} +{% endblock %} + +{% block body %} + {% if google_searchengine_id %} +

{{ _('Search Results') }}

+ +
+ {% else %} + {{ super() }} + {% endif %} +{% endblock %} diff --git a/doc/conf.py b/doc/conf.py index 35afc15af16..a01f51f6872 100644 --- a/doc/conf.py +++ b/doc/conf.py @@ -176,7 +176,11 @@ "Kconfig Options": f"{reference_prefix}/kconfig.html", "Devicetree Bindings": f"{reference_prefix}/build/dts/api/bindings.html", "West Projects": f"{reference_prefix}/develop/manifest/index.html", - } + }, + # Set google_searchengine_id to your Search Engine ID to replace built-in search + # engine with Google's Programmable Search Engine. + # See https://programmablesearchengine.google.com/ for details. + "google_searchengine_id": "746031aa0d56d4912", } # -- Options for LaTeX output --------------------------------------------- From 7e253ff937ac8501c9cad2187eb2a19ef98c73d8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Benjamin=20Cab=C3=A9?= Date: Tue, 7 Nov 2023 11:32:08 +0100 Subject: [PATCH 1272/3723] doc: Make search engine configurable MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Add UI to select preferred search engine when Google Programmable Search is enabled. The user's preference is saved using local storage. This also makes the search input field of type "search" for better UX (in particular on mobile). Signed-off-by: Benjamin Cabé --- doc/_static/css/custom.css | 67 +++++++++++++++++- doc/_templates/gsearch.html | 17 +++++ doc/_templates/search.html | 28 -------- doc/_templates/searchbox.html | 130 ++++++++++++++++++++++++++++++++++ doc/conf.py | 3 + 5 files changed, 214 insertions(+), 31 deletions(-) create mode 100644 doc/_templates/gsearch.html delete mode 100644 doc/_templates/search.html create mode 100644 doc/_templates/searchbox.html diff --git a/doc/_static/css/custom.css b/doc/_static/css/custom.css index 7b1f513aa5b..a374fda4d37 100644 --- a/doc/_static/css/custom.css +++ b/doc/_static/css/custom.css @@ -552,7 +552,10 @@ kbd, .kbd, background-color: var(--navbar-background-color-active); } -.wy-side-nav-search input[type="text"] { +.wy-side-nav-search input[type=search] { + width: 100%; + border-radius: 50px; + padding: 6px 12px; background-color: var(--input-background-color); color: var(--body-color); /* Avoid reflowing when toggling the focus state */ @@ -563,11 +566,11 @@ kbd, .kbd, font-size: 14px; } -.wy-side-nav-search input[type="text"]:focus { +.wy-side-nav-search input[type="search"]:focus { border: 2px solid var(--input-focus-border-color); } -.wy-side-nav-search input[type="text"]::placeholder { +.wy-side-nav-search input[type="search"]::placeholder { color: var(--body-color); opacity: 0.55; } @@ -889,3 +892,61 @@ dark-mode-toggle::part(toggleLabel){ font-size: 3rem; color: white; } + +/* Custom search box, including search engine selection */ + +.search-container { + position: relative; +} + +#search-se-settings-icon { + position: absolute; + color: var(--body-color); + right: 10px; + top: 50%; + transform: translateY(-50%); + cursor: pointer; + opacity: 0.8; +} + +#search-se-menu { + display: none; + position: absolute; + font-size: 11px; + background-color: var(--input-background-color); + color: var(--body-color); + right: 0px; + top: 36px; + border: solid 1px var(--body-color); + border-radius: 10px; + z-index: 1000; +} + +#search-se-menu ul { + list-style: none; + margin: 0; + padding: 2px; +} + +#search-se-menu ul li { + padding: 8px 12px; + cursor: pointer; + display: flex; + justify-content: space-between; + align-items: center; + gap: 1em; +} + +#search-se-menu [role="menuitemradio"]:focus { + background-color: var(--navbar-current-background-color-hover); + color: var(--navbar-level-1-color); + border-radius: 10px; +} + +#search-se-menu ul li .fa-check { + display: none; + } + + #search-se-menu ul li.selected .fa-check { + display: inline; + } diff --git a/doc/_templates/gsearch.html b/doc/_templates/gsearch.html new file mode 100644 index 00000000000..1953466355b --- /dev/null +++ b/doc/_templates/gsearch.html @@ -0,0 +1,17 @@ +{%- extends "!search.html" %} + +{%- block scripts %} + {{ super.super() }} + +{%- endblock %} + +{% block footer %} + {{ super.super() }} +{% endblock %} + +{% block body %} +

{{ _('Search Results') }}

+ +
+{% endblock %} diff --git a/doc/_templates/search.html b/doc/_templates/search.html deleted file mode 100644 index ee9343cce08..00000000000 --- a/doc/_templates/search.html +++ /dev/null @@ -1,28 +0,0 @@ -{%- extends "!search.html" %} -{%- block scripts %} - {% if google_searchengine_id %} - {{ super.super() }} - - {% else %} - {{ super() }} - {% endif %} -{%- endblock %} - -{% block footer %} - {% if google_searchengine_id %} - {{ super.super() }} - {% else %} - {{ super() }} - {% endif %} -{% endblock %} - -{% block body %} - {% if google_searchengine_id %} -

{{ _('Search Results') }}

- -
- {% else %} - {{ super() }} - {% endif %} -{% endblock %} diff --git a/doc/_templates/searchbox.html b/doc/_templates/searchbox.html new file mode 100644 index 00000000000..4779a49c03b --- /dev/null +++ b/doc/_templates/searchbox.html @@ -0,0 +1,130 @@ +{# + Override the default searchbox from RTD theme to provide the ability to select a search method + (ex. built-in search, Google Custom Search, ...) +#} +{%- if ('singlehtml' not in builder) %} + +{%- if google_searchengine_id is defined %} + +{%- endif %} +{%- endif %} \ No newline at end of file diff --git a/doc/conf.py b/doc/conf.py index a01f51f6872..af4b11fd0bb 100644 --- a/doc/conf.py +++ b/doc/conf.py @@ -153,6 +153,9 @@ html_show_sourcelink = False html_show_sphinx = False html_search_scorer = str(ZEPHYR_BASE / "doc" / "_static" / "js" / "scorer.js") +html_additional_pages = { + "gsearch": "gsearch.html" +} is_release = tags.has("release") # pylint: disable=undefined-variable reference_prefix = "" From b22bb172f28c7fb388d7703e43b5e24d2308a84f Mon Sep 17 00:00:00 2001 From: Patryk Koscik Date: Mon, 25 Sep 2023 14:12:35 +0200 Subject: [PATCH 1273/3723] samples: blinky: add verbose printf output Add console output to the sample, with the LED status upon a GPIO toggle. Signed-off-by: Patryk Koscik --- samples/basic/blinky/README.rst | 5 +++-- samples/basic/blinky/src/main.c | 5 +++++ 2 files changed, 8 insertions(+), 2 deletions(-) diff --git a/samples/basic/blinky/README.rst b/samples/basic/blinky/README.rst index 893d00b5103..ec23fe5403f 100644 --- a/samples/basic/blinky/README.rst +++ b/samples/basic/blinky/README.rst @@ -40,8 +40,9 @@ Build and flash Blinky as follows, changing ``reel_board`` for your board: :goals: build flash :compact: -After flashing, the LED starts to blink. If a runtime error occurs, the sample -exits without printing to the console. +After flashing, the LED starts to blink and messages with the current LED state +are printed on the console. If a runtime error occurs, the sample exits without +printing to the console. Build errors ************ diff --git a/samples/basic/blinky/src/main.c b/samples/basic/blinky/src/main.c index fb86da1abdc..4cab4969d94 100644 --- a/samples/basic/blinky/src/main.c +++ b/samples/basic/blinky/src/main.c @@ -4,6 +4,7 @@ * SPDX-License-Identifier: Apache-2.0 */ +#include #include #include @@ -22,6 +23,7 @@ static const struct gpio_dt_spec led = GPIO_DT_SPEC_GET(LED0_NODE, gpios); int main(void) { int ret; + bool led_state = true; if (!gpio_is_ready_dt(&led)) { return 0; @@ -37,6 +39,9 @@ int main(void) if (ret < 0) { return 0; } + + led_state = !led_state; + printf("LED state: %s\n", led_state ? "ON" : "OFF"); k_msleep(SLEEP_TIME_MS); } return 0; From f473bd9be1a1c4815bce1c69970a9427afe8a88c Mon Sep 17 00:00:00 2001 From: Lukasz Mrugala Date: Mon, 20 Nov 2023 15:36:23 +0100 Subject: [PATCH 1274/3723] twister: testplan: Platform key checking rationalisation in apply_filters Fixes #65477 Platform key checking seemed to be erroneous; now the variable names, comments and code seem in line with each other. Signed-off-by: Lukasz Mrugala --- scripts/pylib/twister/twisterlib/testplan.py | 34 +++++++++++--------- 1 file changed, 18 insertions(+), 16 deletions(-) diff --git a/scripts/pylib/twister/twisterlib/testplan.py b/scripts/pylib/twister/twisterlib/testplan.py index 32586b7a27b..e25e05e49a1 100755 --- a/scripts/pylib/twister/twisterlib/testplan.py +++ b/scripts/pylib/twister/twisterlib/testplan.py @@ -858,30 +858,32 @@ def apply_filters(self, **kwargs): # will match against to determine if it should be scheduled to run. A key containing a # field name that the platform does not have will filter the platform. # - # A simple example is keying on arch and simulation to run a test once per unique (arch, simulation) platform. + # A simple example is keying on arch and simulation + # to run a test once per unique (arch, simulation) platform. if not ignore_platform_key and hasattr(ts, 'platform_key') and len(ts.platform_key) > 0: - # form a key by sorting the key fields first, then fetching the key fields from plat if they exist - # if a field does not exist the test is still scheduled on that platform as its undeterminable. key_fields = sorted(set(ts.platform_key)) - key = [getattr(plat, key_field) for key_field in key_fields] - has_all_fields = True - for key_field in key_fields: - if key_field is None or key_field == 'na': - has_all_fields = False - if has_all_fields: - test_key = copy.deepcopy(key) - test_key.append(ts.name) - test_key = tuple(test_key) - keyed_test = keyed_tests.get(test_key) + keys = [getattr(plat, key_field) for key_field in key_fields] + for key in keys: + if key is None or key == 'na': + instance.add_filter( + f"Excluded platform missing key fields demanded by test {key_fields}", + Filters.PLATFORM + ) + break + else: + test_keys = copy.deepcopy(keys) + test_keys.append(ts.name) + test_keys = tuple(test_keys) + keyed_test = keyed_tests.get(test_keys) if keyed_test is not None: plat_key = {key_field: getattr(keyed_test['plat'], key_field) for key_field in key_fields} instance.add_filter(f"Already covered for key {tuple(key)} by platform {keyed_test['plat'].name} having key {plat_key}", Filters.PLATFORM_KEY) else: # do not add a platform to keyed tests if previously filtered if not instance.filters: - keyed_tests[test_key] = {'plat': plat, 'ts': ts} - else: - instance.add_filter(f"Excluded platform missing key fields demanded by test {key_fields}", Filters.PLATFORM) + keyed_tests[test_keys] = {'plat': plat, 'ts': ts} + else: + instance.add_filter(f"Excluded platform missing key fields demanded by test {key_fields}", Filters.PLATFORM) # if nothing stopped us until now, it means this configuration # needs to be added. From c7e3ccd51ad4adf191603cece22acb012b4fc673 Mon Sep 17 00:00:00 2001 From: Kai Vehmanen Date: Tue, 28 Nov 2023 18:28:05 +0200 Subject: [PATCH 1275/3723] drivers: dma: intel_adsp_gpdma: fix issue with stop and PM refcounts The DMA interface allows start and stop to be called multiple times and driver should ensure nothing bad happens if the calls are not balanced. Fix an issue where after a start-stop sequence the DMA would be powered down, and then a subsequent stop would result in a crash as driver accesses registers of a powered down hardware block. Fix the issue by handling stop without actually reading the hw registers to check channel status. Link: https://github.com/thesofproject/sof/issues/8503 Signed-off-by: Kai Vehmanen --- drivers/dma/dma_dw_common.c | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/drivers/dma/dma_dw_common.c b/drivers/dma/dma_dw_common.c index 0a5040980b2..22de9a7d9ef 100644 --- a/drivers/dma/dma_dw_common.c +++ b/drivers/dma/dma_dw_common.c @@ -12,6 +12,7 @@ #include #include #include +#include #include #include #include "dma_dw_common.h" @@ -546,6 +547,7 @@ int dw_dma_stop(const struct device *dev, uint32_t channel) const struct dw_dma_dev_cfg *const dev_cfg = dev->config; struct dw_dma_dev_data *dev_data = dev->data; struct dw_dma_chan_data *chan_data = &dev_data->chan[channel]; + enum pm_device_state pm_state; int ret = 0; if (channel >= DW_CHAN_COUNT) { @@ -553,7 +555,17 @@ int dw_dma_stop(const struct device *dev, uint32_t channel) goto out; } + /* + * skip if device is not active. if we get an error for state_get, + * do not skip but check actual hardware state and stop if + * needed + */ + ret = pm_device_state_get(dev, &pm_state); + if (!ret && pm_state != PM_DEVICE_STATE_ACTIVE) + goto out; + if (!dw_dma_is_enabled(dev, channel) && chan_data->state != DW_DMA_SUSPENDED) { + ret = 0; goto out; } From c0b103bfb1db249cf2f2f03e38c4434fcade56c9 Mon Sep 17 00:00:00 2001 From: Fabio Baltieri Date: Fri, 8 Dec 2023 01:05:44 +0000 Subject: [PATCH 1276/3723] input: ft5336: add suspend and resume support Add power management support to ft5336. The chip can go to hibernate and reduce power consumption to a minimum, the only way to wake it up though is by pulsing the reset or wake signal. Only reset is implemented in the driver right now so only allow this functionality if the reset pin is defined. Signed-off-by: Fabio Baltieri --- drivers/input/input_ft5336.c | 90 +++++++++++++++++++++++++++++++----- 1 file changed, 78 insertions(+), 12 deletions(-) diff --git a/drivers/input/input_ft5336.c b/drivers/input/input_ft5336.c index 1dd705d80f6..fea0aa26c11 100644 --- a/drivers/input/input_ft5336.c +++ b/drivers/input/input_ft5336.c @@ -11,6 +11,8 @@ #include #include #include +#include +#include #include LOG_MODULE_REGISTER(ft5336, CONFIG_INPUT_LOG_LEVEL); @@ -18,6 +20,7 @@ LOG_MODULE_REGISTER(ft5336, CONFIG_INPUT_LOG_LEVEL); /* FT5336 used registers */ #define REG_TD_STATUS 0x02U #define REG_P1_XH 0x03U +#define REG_G_PMODE 0xA5U /* REG_TD_STATUS: Touch points. */ #define TOUCH_POINTS_POS 0U @@ -35,6 +38,9 @@ LOG_MODULE_REGISTER(ft5336, CONFIG_INPUT_LOG_LEVEL); /* REG_Pn_XH: Position */ #define POSITION_H_MSK 0x0FU +/* REG_G_PMODE: Power Consume Mode */ +#define PMOD_HIBERNATE 0x03U + /** FT5336 configuration (DT). */ struct ft5336_config { /** I2C bus. */ @@ -173,7 +179,6 @@ static int ft5336_init(const struct device *dev) } #ifdef CONFIG_INPUT_FT5336_INTERRUPT - if (!gpio_is_ready_dt(&config->int_gpio)) { LOG_ERR("Interrupt GPIO controller device not ready"); return -ENODEV; @@ -204,19 +209,80 @@ static int ft5336_init(const struct device *dev) k_timer_start(&data->timer, K_MSEC(CONFIG_INPUT_FT5336_PERIOD), K_MSEC(CONFIG_INPUT_FT5336_PERIOD)); #endif + + r = pm_device_runtime_enable(dev); + if (r < 0 && r != -ENOTSUP) { + LOG_ERR("Failed to enable runtime power management"); + return r; + } + return 0; } -#define FT5336_INIT(index) \ - static const struct ft5336_config ft5336_config_##index = { \ - .bus = I2C_DT_SPEC_INST_GET(index), \ - .reset_gpio = GPIO_DT_SPEC_INST_GET_OR(index, reset_gpios, {0}), \ - IF_ENABLED(CONFIG_INPUT_FT5336_INTERRUPT, \ - (.int_gpio = GPIO_DT_SPEC_INST_GET(index, int_gpios),)) \ - }; \ - static struct ft5336_data ft5336_data_##index; \ - DEVICE_DT_INST_DEFINE(index, ft5336_init, NULL, \ - &ft5336_data_##index, &ft5336_config_##index, \ - POST_KERNEL, CONFIG_INPUT_INIT_PRIORITY, NULL); +#ifdef CONFIG_PM_DEVICE +static int ft5336_pm_action(const struct device *dev, + enum pm_device_action action) +{ + const struct ft5336_config *config = dev->config; +#ifndef CONFIG_INPUT_FT5336_INTERRUPT + struct ft5336_data *data = dev->data; +#endif + int ret; + + if (config->reset_gpio.port == NULL) { + return -ENOTSUP; + } + + switch (action) { + case PM_DEVICE_ACTION_SUSPEND: + ret = i2c_reg_write_byte_dt(&config->bus, + REG_G_PMODE, PMOD_HIBERNATE); + if (ret < 0) { + return ret; + } + +#ifndef CONFIG_INPUT_FT5336_INTERRUPT + k_timer_stop(&data->timer); +#endif + break; + case PM_DEVICE_ACTION_RESUME: + ret = gpio_pin_set_dt(&config->reset_gpio, 1); + if (ret < 0) { + return ret; + } + + k_sleep(K_MSEC(5)); + + ret = gpio_pin_set_dt(&config->reset_gpio, 0); + if (ret < 0) { + return ret; + } + +#ifndef CONFIG_INPUT_FT5336_INTERRUPT + k_timer_start(&data->timer, + K_MSEC(CONFIG_INPUT_FT5336_PERIOD), + K_MSEC(CONFIG_INPUT_FT5336_PERIOD)); +#endif + break; + default: + return -ENOTSUP; + } + + return 0; +} +#endif + +#define FT5336_INIT(index) \ + PM_DEVICE_DT_INST_DEFINE(n, ft5336_pm_action); \ + static const struct ft5336_config ft5336_config_##index = { \ + .bus = I2C_DT_SPEC_INST_GET(index), \ + .reset_gpio = GPIO_DT_SPEC_INST_GET_OR(index, reset_gpios, {0}), \ + IF_ENABLED(CONFIG_INPUT_FT5336_INTERRUPT, \ + (.int_gpio = GPIO_DT_SPEC_INST_GET(index, int_gpios),)) \ + }; \ + static struct ft5336_data ft5336_data_##index; \ + DEVICE_DT_INST_DEFINE(index, ft5336_init, PM_DEVICE_DT_INST_GET(n), \ + &ft5336_data_##index, &ft5336_config_##index, \ + POST_KERNEL, CONFIG_INPUT_INIT_PRIORITY, NULL); DT_INST_FOREACH_STATUS_OKAY(FT5336_INIT) From 044299a7c433993f366cb97b353ef9f29058acf6 Mon Sep 17 00:00:00 2001 From: Sateesh Kotapati Date: Thu, 23 Nov 2023 12:42:27 +0530 Subject: [PATCH 1277/3723] gecko: EFR32BG22 Device files updated | Update to GSDK 4.3.2 Update the EFR32BG22 device files inside gecko/Device/SiliconLabs/EFR32BG22 from gecko_sdk to align the codebase of hal_silabs with gecko_sdk 4.3.2 Signed-off-by: Sateesh Kotapati --- west.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/west.yml b/west.yml index 2208fa9ad80..7f90fbf59e8 100644 --- a/west.yml +++ b/west.yml @@ -219,7 +219,7 @@ manifest: groups: - hal - name: hal_silabs - revision: 72a67203f0b37dc2c12bfae5ddf05c991c0ab0a4 + revision: 7a6ba7ce989c3c466b4cb450e44858a3bb0a949a path: modules/hal/silabs groups: - hal From a7a6b5654acc11f41e31d13e4c3dbb2eb77a1856 Mon Sep 17 00:00:00 2001 From: Adam Wojasinski Date: Thu, 14 Dec 2023 11:50:59 +0100 Subject: [PATCH 1278/3723] modules: hal_nordic: Add possibility to specify own source of the nrfx Introduce possibility to override `NRFX_DIR` sybol from hal_nordic's CMakeLists.txt file that specifies source dir for the nrfx drivers. Signed-off-by: Adam Wojasinski --- modules/hal_nordic/nrfx/CMakeLists.txt | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/modules/hal_nordic/nrfx/CMakeLists.txt b/modules/hal_nordic/nrfx/CMakeLists.txt index 69afbcc9c51..b395bc65a88 100644 --- a/modules/hal_nordic/nrfx/CMakeLists.txt +++ b/modules/hal_nordic/nrfx/CMakeLists.txt @@ -3,7 +3,12 @@ zephyr_library() -set(NRFX_DIR ${ZEPHYR_CURRENT_MODULE_DIR}/nrfx CACHE PATH "nrfx Directory") +# The nrfx source directory can be override through the definition of the NRFX_DIR symbol +# during the invocation of the build system +if(NOT DEFINED NRFX_DIR) + set(NRFX_DIR ${ZEPHYR_CURRENT_MODULE_DIR}/nrfx CACHE PATH "nrfx Directory") +endif() + set(INC_DIR ${NRFX_DIR}/drivers/include) set(SRC_DIR ${NRFX_DIR}/drivers/src) set(MDK_DIR ${NRFX_DIR}/mdk) From dc9ad42ffb47c4775a49443e5a53d4a70714ab4b Mon Sep 17 00:00:00 2001 From: Rubin Gerritsen Date: Wed, 13 Dec 2023 09:25:28 +0100 Subject: [PATCH 1279/3723] Bluetooth: Clarify when the sent callback is issued The timing of the sent callback shouldn't be used to determine when something is sent on air. The callback is issued after the controller has raised the HCI event "Number Of Completed Packets". The timing of this event is dependent on the implementation. Signed-off-by: Rubin Gerritsen --- include/zephyr/bluetooth/audio/bap.h | 6 ++++-- include/zephyr/bluetooth/iso.h | 6 ++++-- include/zephyr/bluetooth/l2cap.h | 6 ++++-- 3 files changed, 12 insertions(+), 6 deletions(-) diff --git a/include/zephyr/bluetooth/audio/bap.h b/include/zephyr/bluetooth/audio/bap.h index f2c231dcd81..588c44d5efe 100644 --- a/include/zephyr/bluetooth/audio/bap.h +++ b/include/zephyr/bluetooth/audio/bap.h @@ -569,8 +569,10 @@ struct bt_bap_stream_ops { /** * @brief Stream audio HCI sent callback * - * If this callback is provided it will be called whenever a SDU has been completely sent, - * or otherwise flushed due to transmission issues. + * This callback will be called once the controller marks the SDU + * as completed. When the controller does so is implementation + * dependent. It could be after the SDU is enqueued for transmission, + * or after it is sent on air or flushed. * * This callback is only used if the ISO data path is HCI. * diff --git a/include/zephyr/bluetooth/iso.h b/include/zephyr/bluetooth/iso.h index 68ceec3ac3d..e280951eda7 100644 --- a/include/zephyr/bluetooth/iso.h +++ b/include/zephyr/bluetooth/iso.h @@ -663,8 +663,10 @@ struct bt_iso_chan_ops { /** @brief Channel sent callback * - * If this callback is provided it will be called whenever a SDU has - * been completely sent. + * This callback will be called once the controller marks the SDU + * as completed. When the controller does so is implementation + * dependent. It could be after the SDU is enqueued for transmission, + * or after it is sent on air or flushed. * * @param chan The channel which has sent data. */ diff --git a/include/zephyr/bluetooth/l2cap.h b/include/zephyr/bluetooth/l2cap.h index 34d1f2dc2ab..d9241e7af21 100644 --- a/include/zephyr/bluetooth/l2cap.h +++ b/include/zephyr/bluetooth/l2cap.h @@ -346,8 +346,10 @@ struct bt_l2cap_chan_ops { /** @brief Channel sent callback * - * If this callback is provided it will be called whenever a SDU has - * been completely sent. + * This callback will be called once the controller marks the SDU + * as completed. When the controller does so is implementation + * dependent. It could be after the SDU is enqueued for transmission, + * or after it is sent on air. * * @param chan The channel which has sent data. */ From d09d3d82ef0a6861b7632dac7cb0519da17919a1 Mon Sep 17 00:00:00 2001 From: Juha Ylinen Date: Tue, 12 Dec 2023 15:27:29 +0200 Subject: [PATCH 1280/3723] net: lib: coap: Change coap_pending_init() Replace function parameter 'retries' with pointer to structure holding coap transmission parameters. This allows setting the retransmission parameters individually for each pending request. Add coap transmission parameters to coap_pending structure. Update migration guide and release notes. Signed-off-by: Juha Ylinen --- doc/releases/migration-guide-3.6.rst | 6 ++++ doc/releases/release-notes-3.6.rst | 5 +++ include/zephyr/net/coap.h | 30 ++++++++-------- include/zephyr/net/coap_client.h | 5 ++- subsys/net/lib/coap/coap.c | 23 +++++++----- subsys/net/lib/coap/coap_client.c | 19 ++++------ subsys/net/lib/coap/coap_server.c | 7 ++-- subsys/net/lib/lwm2m/lwm2m_message_handling.c | 6 ++-- tests/net/lib/coap/src/main.c | 2 +- tests/net/lib/coap_client/src/main.c | 35 ++++++++++++------- 10 files changed, 81 insertions(+), 57 deletions(-) diff --git a/doc/releases/migration-guide-3.6.rst b/doc/releases/migration-guide-3.6.rst index 429ece62724..9f1ccaa4073 100644 --- a/doc/releases/migration-guide-3.6.rst +++ b/doc/releases/migration-guide-3.6.rst @@ -236,6 +236,12 @@ Networking subsystem. The ``CONFIG_COAP_OBSERVER_EVENTS`` configuration option has been removed. (:github:`65936`) +* The CoAP public API function :c:func:`coap_pending_init` has changed. The parameter + ``retries`` is replaced with a pointer to :c:struct:`coap_transmission_parameters`. This allows to + specify retransmission parameters of the confirmable message. It is safe to pass a NULL pointer to + use default values. + (:github:`66482`) + * The IGMP multicast library now supports IGMPv3. This results in a minor change to the existing api. The :c:func:`net_ipv4_igmp_join` now takes an additional argument of the type ``const struct igmp_param *param``. This allows IGMPv3 to exclude/include certain groups of diff --git a/doc/releases/release-notes-3.6.rst b/doc/releases/release-notes-3.6.rst index b1985f66e33..265f994c600 100644 --- a/doc/releases/release-notes-3.6.rst +++ b/doc/releases/release-notes-3.6.rst @@ -225,6 +225,11 @@ Networking * Emit observer/service network events using the Network Event subsystem. + * Added new API functions: + + * :c:func:`coap_get_transmission_parameters` + * :c:func:`coap_set_transmission_parameters` + * Connection Manager: * DHCP: diff --git a/include/zephyr/net/coap.h b/include/zephyr/net/coap.h index e4374f41e34..e303d5c8ad3 100644 --- a/include/zephyr/net/coap.h +++ b/include/zephyr/net/coap.h @@ -309,6 +309,18 @@ typedef int (*coap_reply_t)(const struct coap_packet *response, struct coap_reply *reply, const struct sockaddr *from); +/** + * @brief CoAP transmission parameters. + */ +struct coap_transmission_parameters { + /** Initial ACK timeout. Value is used as a base value to retry pending CoAP packets. */ + uint32_t ack_timeout; + /** Set CoAP retry backoff factor. A value of 200 means a factor of 2.0. */ + uint16_t coap_backoff_percent; + /** Maximum number of retransmissions. */ + uint8_t max_retransmission; +}; + /** * @brief Represents a request awaiting for an acknowledgment (ACK). */ @@ -320,6 +332,7 @@ struct coap_pending { uint8_t *data; /**< User allocated buffer */ uint16_t len; /**< Length of the CoAP packet */ uint8_t retries; /**< Number of times the request has been sent */ + struct coap_transmission_parameters params; /**< Transmission parameters */ }; /** @@ -989,14 +1002,15 @@ void coap_reply_init(struct coap_reply *reply, * confirmation message, initialized with data from @a request * @param request Message waiting for confirmation * @param addr Address to send the retransmission - * @param retries Maximum number of retransmissions of the message. + * @param params Pointer to the CoAP transmission parameters struct, + * or NULL to use default values * * @return 0 in case of success or negative in case of error. */ int coap_pending_init(struct coap_pending *pending, const struct coap_packet *request, const struct sockaddr *addr, - uint8_t retries); + const struct coap_transmission_parameters *params); /** * @brief Returns the next available pending struct, that can be used @@ -1134,18 +1148,6 @@ int coap_resource_notify(struct coap_resource *resource); */ bool coap_request_is_observe(const struct coap_packet *request); -/** - * @brief CoAP transmission parameters. - */ -struct coap_transmission_parameters { - /** Initial AKC timeout. Value is used as a base value to retry pending CoAP packets. */ - uint32_t ack_timeout; - /** Set CoAP retry backoff factor. A value of 200 means a factor of 2.0. */ - uint16_t coap_backoff_percent; - /** Maximum number of retransmissions. */ - uint8_t max_retransmission; -}; - /** * @brief Get currently active CoAP transmission parameters. * diff --git a/include/zephyr/net/coap_client.h b/include/zephyr/net/coap_client.h index c3de1abee27..e48048d5c26 100644 --- a/include/zephyr/net/coap_client.h +++ b/include/zephyr/net/coap_client.h @@ -83,7 +83,6 @@ struct coap_client_internal_request { uint32_t offset; uint32_t last_id; uint8_t request_tkl; - uint8_t retry_count; bool request_ongoing; struct coap_block_context recv_blk_ctx; struct coap_block_context send_blk_ctx; @@ -131,12 +130,12 @@ int coap_client_init(struct coap_client *client, const char *info); * @param sock Open socket file descriptor. * @param addr the destination address of the request, NULL if socket is already connected. * @param req CoAP request structure - * @param retries How many times to retry or -1 to use default. + * @param params Pointer to transmission parameters structure or NULL to use default values. * @return zero when operation started successfully or negative error code otherwise. */ int coap_client_req(struct coap_client *client, int sock, const struct sockaddr *addr, - struct coap_client_request *req, int retries); + struct coap_client_request *req, struct coap_transmission_parameters *params); /** * @} diff --git a/subsys/net/lib/coap/coap.c b/subsys/net/lib/coap/coap.c index c21e14e5ded..bfb643a8e8c 100644 --- a/subsys/net/lib/coap/coap.c +++ b/subsys/net/lib/coap/coap.c @@ -1553,7 +1553,7 @@ size_t coap_next_block(const struct coap_packet *cpkt, int coap_pending_init(struct coap_pending *pending, const struct coap_packet *request, const struct sockaddr *addr, - uint8_t retries) + const struct coap_transmission_parameters *params) { memset(pending, 0, sizeof(*pending)); @@ -1561,10 +1561,16 @@ int coap_pending_init(struct coap_pending *pending, memcpy(&pending->addr, addr, sizeof(*addr)); + if (params) { + pending->params = *params; + } else { + pending->params = coap_transmission_params; + } + pending->data = request->data; pending->len = request->offset; pending->t0 = k_uptime_get(); - pending->retries = retries; + pending->retries = pending->params.max_retransmission; return 0; } @@ -1676,12 +1682,12 @@ struct coap_pending *coap_pending_next_to_expire( return found; } -static uint32_t init_ack_timeout(void) +static uint32_t init_ack_timeout(const struct coap_transmission_parameters *params) { #if defined(CONFIG_COAP_RANDOMIZE_ACK_TIMEOUT) - const uint32_t max_ack = coap_transmission_params.ack_timeout * + const uint32_t max_ack = params->ack_timeout * CONFIG_COAP_ACK_RANDOM_PERCENT / 100; - const uint32_t min_ack = coap_transmission_params.ack_timeout; + const uint32_t min_ack = params->ack_timeout; /* Randomly generated initial ACK timeout * ACK_TIMEOUT < INIT_ACK_TIMEOUT < ACK_TIMEOUT * ACK_RANDOM_FACTOR @@ -1689,7 +1695,7 @@ static uint32_t init_ack_timeout(void) */ return min_ack + (sys_rand32_get() % (max_ack - min_ack)); #else - return coap_transmission_params.ack_timeout; + return params->ack_timeout; #endif /* defined(CONFIG_COAP_RANDOMIZE_ACK_TIMEOUT) */ } @@ -1697,8 +1703,7 @@ bool coap_pending_cycle(struct coap_pending *pending) { if (pending->timeout == 0) { /* Initial transmission. */ - pending->timeout = init_ack_timeout(); - + pending->timeout = init_ack_timeout(&pending->params); return true; } @@ -1707,7 +1712,7 @@ bool coap_pending_cycle(struct coap_pending *pending) } pending->t0 += pending->timeout; - pending->timeout = pending->timeout * coap_transmission_params.coap_backoff_percent / 100; + pending->timeout = pending->timeout * pending->params.coap_backoff_percent / 100; pending->retries--; return true; diff --git a/subsys/net/lib/coap/coap_client.c b/subsys/net/lib/coap/coap_client.c index a947b15ae8e..4bdf387a242 100644 --- a/subsys/net/lib/coap/coap_client.c +++ b/subsys/net/lib/coap/coap_client.c @@ -16,7 +16,6 @@ LOG_MODULE_DECLARE(net_coap, CONFIG_COAP_LOG_LEVEL); #define COAP_VERSION 1 #define COAP_SEPARATE_TIMEOUT 6000 #define COAP_PERIODIC_TIMEOUT 500 -#define DEFAULT_RETRY_AMOUNT 5 #define BLOCK1_OPTION_SIZE 4 #define PAYLOAD_MARKER_SIZE 1 @@ -60,7 +59,6 @@ static void reset_internal_request(struct coap_client_internal_request *request) { request->offset = 0; request->last_id = 0; - request->retry_count = 0; reset_block_contexts(request); } @@ -277,7 +275,7 @@ static int coap_client_init_request(struct coap_client *client, } int coap_client_req(struct coap_client *client, int sock, const struct sockaddr *addr, - struct coap_client_request *req, int retries) + struct coap_client_request *req, struct coap_transmission_parameters *params) { int ret; @@ -352,14 +350,8 @@ int coap_client_req(struct coap_client *client, int sock, const struct sockaddr /* only TYPE_CON messages need pending tracking */ if (coap_header_get_type(&internal_req->request) == COAP_TYPE_CON) { - if (retries == -1) { - internal_req->retry_count = DEFAULT_RETRY_AMOUNT; - } else { - internal_req->retry_count = retries; - } - ret = coap_pending_init(&internal_req->pending, &internal_req->request, - &client->address, internal_req->retry_count); + &client->address, params); if (ret < 0) { LOG_ERR("Failed to initialize pending struct"); @@ -692,9 +684,11 @@ static int handle_response(struct coap_client *client, const struct coap_packet } if (coap_header_get_type(&internal_req->request) == COAP_TYPE_CON) { + struct coap_transmission_parameters params = + internal_req->pending.params; ret = coap_pending_init(&internal_req->pending, &internal_req->request, &client->address, - internal_req->retry_count); + ¶ms); if (ret < 0) { LOG_ERR("Error creating pending"); k_mutex_unlock(&client->send_mutex); @@ -793,8 +787,9 @@ static int handle_response(struct coap_client *client, const struct coap_packet goto fail; } + struct coap_transmission_parameters params = internal_req->pending.params; ret = coap_pending_init(&internal_req->pending, &internal_req->request, - &client->address, internal_req->retry_count); + &client->address, ¶ms); if (ret < 0) { LOG_ERR("Error creating pending"); k_mutex_unlock(&client->send_mutex); diff --git a/subsys/net/lib/coap/coap_server.c b/subsys/net/lib/coap/coap_server.c index ce312968ea7..66e5dcbc32c 100644 --- a/subsys/net/lib/coap/coap_server.c +++ b/subsys/net/lib/coap/coap_server.c @@ -542,6 +542,8 @@ int coap_service_send(const struct coap_service *service, const struct coap_pack * try to send. */ if (coap_header_get_type(cpkt) == COAP_TYPE_CON) { + struct coap_transmission_parameters params; + struct coap_pending *pending = coap_pending_next_unused(service->data->pending, MAX_PENDINGS); @@ -550,8 +552,9 @@ int coap_service_send(const struct coap_service *service, const struct coap_pack goto send; } - ret = coap_pending_init(pending, cpkt, addr, - CONFIG_COAP_SERVICE_PENDING_RETRANSMITS); + params = coap_get_transmission_parameters(); + params.max_retransmission = CONFIG_COAP_SERVICE_PENDING_RETRANSMITS; + ret = coap_pending_init(pending, cpkt, addr, ¶ms); if (ret < 0) { LOG_WRN("Failed to init pending message for %s (%d)", service->name, ret); goto send; diff --git a/subsys/net/lib/lwm2m/lwm2m_message_handling.c b/subsys/net/lib/lwm2m/lwm2m_message_handling.c index 02c62cee67c..677879304f8 100644 --- a/subsys/net/lib/lwm2m/lwm2m_message_handling.c +++ b/subsys/net/lib/lwm2m/lwm2m_message_handling.c @@ -654,8 +654,7 @@ int lwm2m_init_message(struct lwm2m_message *msg) goto cleanup; } - r = coap_pending_init(msg->pending, &msg->cpkt, &msg->ctx->remote_addr, - CONFIG_COAP_MAX_RETRANSMIT); + r = coap_pending_init(msg->pending, &msg->cpkt, &msg->ctx->remote_addr, NULL); if (r < 0) { LOG_ERR("Unable to initialize a pending " "retransmission (err:%d).", @@ -2594,8 +2593,7 @@ static int lwm2m_response_promote_to_con(struct lwm2m_message *msg) return -ENOMEM; } - ret = coap_pending_init(msg->pending, &msg->cpkt, &msg->ctx->remote_addr, - CONFIG_COAP_MAX_RETRANSMIT); + ret = coap_pending_init(msg->pending, &msg->cpkt, &msg->ctx->remote_addr, NULL); if (ret < 0) { LOG_ERR("Unable to initialize a pending " "retransmission (err:%d).", diff --git a/tests/net/lib/coap/src/main.c b/tests/net/lib/coap/src/main.c index c9d0456d332..52b6cf0fd2a 100644 --- a/tests/net/lib/coap/src/main.c +++ b/tests/net/lib/coap/src/main.c @@ -779,7 +779,7 @@ ZTEST(coap, test_retransmit_second_round) zassert_not_null(pending, "No free pending"); r = coap_pending_init(pending, &cpkt, (struct sockaddr *) &dummy_addr, - CONFIG_COAP_MAX_RETRANSMIT); + NULL); zassert_equal(r, 0, "Could not initialize packet"); /* We "send" the packet the first time here */ diff --git a/tests/net/lib/coap_client/src/main.c b/tests/net/lib/coap_client/src/main.c index e1240c5e2ed..7d99c738950 100644 --- a/tests/net/lib/coap_client/src/main.c +++ b/tests/net/lib/coap_client/src/main.c @@ -378,7 +378,7 @@ ZTEST(coap_client, test_get_request) k_sleep(K_MSEC(1)); LOG_INF("Send request"); - ret = coap_client_req(&client, 0, &address, &client_request, -1); + ret = coap_client_req(&client, 0, &address, &client_request, NULL); zassert_true(ret >= 0, "Sending request failed, %d", ret); set_socket_events(ZSOCK_POLLIN); @@ -409,7 +409,7 @@ ZTEST(coap_client, test_resend_request) k_sleep(K_MSEC(1)); LOG_INF("Send request"); - ret = coap_client_req(&client, 0, &address, &client_request, -1); + ret = coap_client_req(&client, 0, &address, &client_request, NULL); zassert_true(ret >= 0, "Sending request failed, %d", ret); k_sleep(K_MSEC(300)); set_socket_events(ZSOCK_POLLIN); @@ -441,7 +441,7 @@ ZTEST(coap_client, test_echo_option) k_sleep(K_MSEC(1)); LOG_INF("Send request"); - ret = coap_client_req(&client, 0, &address, &client_request, -1); + ret = coap_client_req(&client, 0, &address, &client_request, NULL); zassert_true(ret >= 0, "Sending request failed, %d", ret); set_socket_events(ZSOCK_POLLIN); @@ -472,7 +472,7 @@ ZTEST(coap_client, test_echo_option_next_req) k_sleep(K_MSEC(1)); LOG_INF("Send request"); - ret = coap_client_req(&client, 0, &address, &client_request, -1); + ret = coap_client_req(&client, 0, &address, &client_request, NULL); zassert_true(ret >= 0, "Sending request failed, %d", ret); set_socket_events(ZSOCK_POLLIN); @@ -487,7 +487,7 @@ ZTEST(coap_client, test_echo_option_next_req) client_request.len = strlen(payload); LOG_INF("Send next request"); - ret = coap_client_req(&client, 0, &address, &client_request, -1); + ret = coap_client_req(&client, 0, &address, &client_request, NULL); zassert_true(ret >= 0, "Sending request failed, %d", ret); set_socket_events(ZSOCK_POLLIN); @@ -516,7 +516,7 @@ ZTEST(coap_client, test_get_no_path) k_sleep(K_MSEC(1)); LOG_INF("Send request"); - ret = coap_client_req(&client, 0, &address, &client_request, -1); + ret = coap_client_req(&client, 0, &address, &client_request, NULL); zassert_equal(ret, -EINVAL, "Get request without path"); } @@ -541,7 +541,7 @@ ZTEST(coap_client, test_send_large_data) k_sleep(K_MSEC(1)); LOG_INF("Send request"); - ret = coap_client_req(&client, 0, &address, &client_request, -1); + ret = coap_client_req(&client, 0, &address, &client_request, NULL); zassert_true(ret >= 0, "Sending request failed, %d", ret); set_socket_events(ZSOCK_POLLIN); @@ -563,6 +563,11 @@ ZTEST(coap_client, test_no_response) .payload = NULL, .len = 0 }; + struct coap_transmission_parameters params = { + .ack_timeout = 200, + .coap_backoff_percent = 200, + .max_retransmission = 0 + }; client_request.payload = short_payload; client_request.len = strlen(short_payload); @@ -571,7 +576,7 @@ ZTEST(coap_client, test_no_response) LOG_INF("Send request"); clear_socket_events(); - ret = coap_client_req(&client, 0, &address, &client_request, 0); + ret = coap_client_req(&client, 0, &address, &client_request, ¶ms); zassert_true(ret >= 0, "Sending request failed, %d", ret); k_sleep(K_MSEC(300)); @@ -601,7 +606,7 @@ ZTEST(coap_client, test_separate_response) k_sleep(K_MSEC(1)); LOG_INF("Send request"); - ret = coap_client_req(&client, 0, &address, &client_request, -1); + ret = coap_client_req(&client, 0, &address, &client_request, NULL); zassert_true(ret >= 0, "Sending request failed, %d", ret); set_socket_events(ZSOCK_POLLIN); @@ -632,10 +637,10 @@ ZTEST(coap_client, test_multiple_requests) set_socket_events(ZSOCK_POLLIN); LOG_INF("Send request"); - ret = coap_client_req(&client, 0, &address, &client_request, -1); + ret = coap_client_req(&client, 0, &address, &client_request, NULL); zassert_true(ret >= 0, "Sending request failed, %d", ret); - ret = coap_client_req(&client, 0, &address, &client_request, -1); + ret = coap_client_req(&client, 0, &address, &client_request, NULL); zassert_true(ret >= 0, "Sending request failed, %d", ret); k_sleep(K_MSEC(5)); @@ -660,6 +665,11 @@ ZTEST(coap_client, test_unmatching_tokens) .payload = NULL, .len = 0 }; + struct coap_transmission_parameters params = { + .ack_timeout = 200, + .coap_backoff_percent = 200, + .max_retransmission = 0 + }; client_request.payload = short_payload; client_request.len = strlen(short_payload); @@ -667,7 +677,7 @@ ZTEST(coap_client, test_unmatching_tokens) z_impl_zsock_recvfrom_fake.custom_fake = z_impl_zsock_recvfrom_custom_fake_unmatching; LOG_INF("Send request"); - ret = coap_client_req(&client, 0, &address, &client_request, 0); + ret = coap_client_req(&client, 0, &address, &client_request, ¶ms); zassert_true(ret >= 0, "Sending request failed, %d", ret); set_socket_events(ZSOCK_POLLIN); @@ -675,4 +685,5 @@ ZTEST(coap_client, test_unmatching_tokens) k_sleep(K_MSEC(1)); clear_socket_events(); k_sleep(K_MSEC(500)); + zassert_equal(last_response_code, -ETIMEDOUT, "Unexpected response"); } From f9fa2ae77ccf71c5443e756338d2234ea89ecbc2 Mon Sep 17 00:00:00 2001 From: Juha Ylinen Date: Wed, 13 Dec 2023 15:13:18 +0200 Subject: [PATCH 1281/3723] tests: net: coap: Add test case for transmission parameters Add new test case. Signed-off-by: Juha Ylinen --- tests/net/lib/coap/src/main.c | 53 +++++++++++++++++++++++++++++++++++ 1 file changed, 53 insertions(+) diff --git a/tests/net/lib/coap/src/main.c b/tests/net/lib/coap/src/main.c index 52b6cf0fd2a..d1903dea10c 100644 --- a/tests/net/lib/coap/src/main.c +++ b/tests/net/lib/coap/src/main.c @@ -1718,4 +1718,57 @@ ZTEST(coap, test_coap_packet_set_path) COAP_OPTION_URI_PATH); } +ZTEST(coap, test_transmission_parameters) +{ + struct coap_packet cpkt; + struct coap_pending *pending; + struct coap_transmission_parameters params; + uint8_t *data = data_buf[0]; + int r; + uint16_t id; + + params = coap_get_transmission_parameters(); + zassert_equal(params.ack_timeout, CONFIG_COAP_INIT_ACK_TIMEOUT_MS, "Wrong ACK timeout"); + zassert_equal(params.coap_backoff_percent, CONFIG_COAP_BACKOFF_PERCENT, + "Wrong backoff percent"); + zassert_equal(params.max_retransmission, CONFIG_COAP_MAX_RETRANSMIT, + "Wrong max retransmission value"); + + params.ack_timeout = 1000; + params.coap_backoff_percent = 150; + params.max_retransmission = 2; + + coap_set_transmission_parameters(¶ms); + + id = coap_next_id(); + + r = coap_packet_init(&cpkt, data, COAP_BUF_SIZE, COAP_VERSION_1, + COAP_TYPE_CON, 0, coap_next_token(), + COAP_METHOD_GET, id); + zassert_equal(r, 0, "Could not initialize packet"); + + pending = coap_pending_next_unused(pendings, NUM_PENDINGS); + zassert_not_null(pending, "No free pending"); + + params.ack_timeout = 3000; + params.coap_backoff_percent = 250; + params.max_retransmission = 3; + + r = coap_pending_init(pending, &cpkt, (struct sockaddr *) &dummy_addr, + ¶ms); + zassert_equal(r, 0, "Could not initialize packet"); + + zassert_equal(pending->params.ack_timeout, 3000, "Wrong ACK timeout"); + zassert_equal(pending->params.coap_backoff_percent, 250, "Wrong backoff percent"); + zassert_equal(pending->params.max_retransmission, 3, "Wrong max retransmission value"); + + r = coap_pending_init(pending, &cpkt, (struct sockaddr *) &dummy_addr, + NULL); + zassert_equal(r, 0, "Could not initialize packet"); + + zassert_equal(pending->params.ack_timeout, 1000, "Wrong ACK timeout"); + zassert_equal(pending->params.coap_backoff_percent, 150, "Wrong backoff percent"); + zassert_equal(pending->params.max_retransmission, 2, "Wrong max retransmission value"); +} + ZTEST_SUITE(coap, NULL, NULL, NULL, NULL, NULL); From d2745d6dbac0486aac74e3258c6a8d2b0bc520fc Mon Sep 17 00:00:00 2001 From: Mariusz Skamra Date: Wed, 13 Dec 2023 12:56:52 +0100 Subject: [PATCH 1282/3723] tests: Bluetooth: shell: Fix connection reference leak This fixes regression introduced in recently. Redundant connection reference is taken twice in connected() callback. The redunant reference was then not returned, and as a result we had a leak. Signed-off-by: Mariusz Skamra --- subsys/bluetooth/shell/bt.c | 2 -- 1 file changed, 2 deletions(-) diff --git a/subsys/bluetooth/shell/bt.c b/subsys/bluetooth/shell/bt.c index 79647ead4ef..da8c5abec5a 100644 --- a/subsys/bluetooth/shell/bt.c +++ b/subsys/bluetooth/shell/bt.c @@ -694,8 +694,6 @@ static void connected(struct bt_conn *conn, uint8_t err) } } - default_conn = bt_conn_ref(conn); - done: /* clear connection reference for sec mode 3 pairing */ if (pairing_conn) { From 6e6311ebfb808599278923e0e947fa449831b74b Mon Sep 17 00:00:00 2001 From: Mariusz Skamra Date: Wed, 13 Dec 2023 13:02:21 +0100 Subject: [PATCH 1283/3723] tests: Bluetooth: shell: Use BT_LE_CONN_PARAM_DEFAULT for connection This basically reverts changes made by 9c8ec58bebed7478901551c2538c642ea3f2660e. Signed-off-by: Mariusz Skamra --- subsys/bluetooth/shell/bt.c | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/subsys/bluetooth/shell/bt.c b/subsys/bluetooth/shell/bt.c index da8c5abec5a..1d4c61a84f7 100644 --- a/subsys/bluetooth/shell/bt.c +++ b/subsys/bluetooth/shell/bt.c @@ -2843,10 +2843,8 @@ static int cmd_connect_le(const struct shell *sh, size_t argc, char *argv[]) BT_GAP_SCAN_FAST_INTERVAL, BT_GAP_SCAN_FAST_INTERVAL); - err = bt_conn_le_create( - &addr, create_params, - BT_LE_CONN_PARAM(BT_GAP_INIT_CONN_INT_MIN, BT_GAP_INIT_CONN_INT_MIN, 0, 400), - &conn); + err = bt_conn_le_create(&addr, create_params, BT_LE_CONN_PARAM_DEFAULT, + &conn); if (err) { shell_error(sh, "Connection failed (%d)", err); return -ENOEXEC; From c9404e0174e95a22eabddcd1b1d697c3a1744b43 Mon Sep 17 00:00:00 2001 From: Daniel DeGrasse Date: Wed, 13 Dec 2023 14:27:01 -0600 Subject: [PATCH 1284/3723] drivers: usb: usb_dc_kinetis: fix k_heap_alloc wait duration Change k_heap_alloc wait duration to K_NO_WAIT in kinetis USB driver, since the usb_dc_ep_configure function may be called from an ISR context, where only K_NO_WAIT would be allowed as a duration for this function. Fixes #66507 Signed-off-by: Daniel DeGrasse --- drivers/usb/device/usb_dc_kinetis.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/usb/device/usb_dc_kinetis.c b/drivers/usb/device/usb_dc_kinetis.c index 903b1a9dc33..36734580e6c 100644 --- a/drivers/usb/device/usb_dc_kinetis.c +++ b/drivers/usb/device/usb_dc_kinetis.c @@ -354,7 +354,7 @@ int usb_dc_ep_configure(const struct usb_dc_ep_cfg_data * const cfg) (void)memset(&bdt[idx_even], 0, sizeof(struct buf_descriptor)); (void)memset(&bdt[idx_odd], 0, sizeof(struct buf_descriptor)); - block->data = k_heap_alloc(&ep_buf_pool, cfg->ep_mps * 2U, K_MSEC(10)); + block->data = k_heap_alloc(&ep_buf_pool, cfg->ep_mps * 2U, K_NO_WAIT); if (block->data != NULL) { (void)memset(block->data, 0, cfg->ep_mps * 2U); } else { From 6b1a3207dd5d82c25751acce3b851a07590ce35f Mon Sep 17 00:00:00 2001 From: Peter Mitsis Date: Wed, 13 Dec 2023 15:40:35 -0500 Subject: [PATCH 1285/3723] tests: Fix bias adjustment in latency_measure Updates the non-blocking semaphore and mutex benchmark sub-tests in the latency_measure benchmark to remove the timestamp bias adjustment. As the timestamps are not sampled during each iteration of those sub-tests, there is no need to correct for any bias from the sampling. Signed-off-by: Peter Mitsis --- tests/benchmarks/latency_measure/src/mutex_lock_unlock.c | 2 -- tests/benchmarks/latency_measure/src/sema_test_signal_release.c | 2 -- 2 files changed, 4 deletions(-) diff --git a/tests/benchmarks/latency_measure/src/mutex_lock_unlock.c b/tests/benchmarks/latency_measure/src/mutex_lock_unlock.c index 5ab52b43dcd..2f78f45d386 100644 --- a/tests/benchmarks/latency_measure/src/mutex_lock_unlock.c +++ b/tests/benchmarks/latency_measure/src/mutex_lock_unlock.c @@ -91,7 +91,6 @@ int mutex_lock_unlock(uint32_t num_iterations, uint32_t options) k_thread_start(&start_thread); cycles = timestamp.cycles; - cycles -= timestamp_overhead_adjustment(options, options); k_sem_give(&pause_sem); snprintf(description, sizeof(description), @@ -101,7 +100,6 @@ int mutex_lock_unlock(uint32_t num_iterations, uint32_t options) false, ""); cycles = timestamp.cycles; - cycles -= timestamp_overhead_adjustment(options, options); snprintf(description, sizeof(description), "Unlock a mutex from %s thread", diff --git a/tests/benchmarks/latency_measure/src/sema_test_signal_release.c b/tests/benchmarks/latency_measure/src/sema_test_signal_release.c index e5ea2b72992..7610200332c 100644 --- a/tests/benchmarks/latency_measure/src/sema_test_signal_release.c +++ b/tests/benchmarks/latency_measure/src/sema_test_signal_release.c @@ -253,7 +253,6 @@ int sema_test_signal(uint32_t num_iterations, uint32_t options) /* 5. Retrieve the number of cycles spent giving the semaphore */ cycles = timestamp.cycles; - cycles -= timestamp_overhead_adjustment(options, options); snprintf(description, sizeof(description), "Give a semaphore (no waiters) from %s thread", @@ -273,7 +272,6 @@ int sema_test_signal(uint32_t num_iterations, uint32_t options) /* 9. Retrieve the number of cycles spent taking the semaphore */ cycles = timestamp.cycles; - cycles -= timestamp_overhead_adjustment(options, options); snprintf(description, sizeof(description), "Take a semaphore (no blocking) from %s thread", From 37e1a116ef0b7fcb43d50de161f4b8cc89a4be71 Mon Sep 17 00:00:00 2001 From: Fredrik Danebjer Date: Thu, 14 Dec 2023 09:00:00 +0100 Subject: [PATCH 1286/3723] bluetooth: shell: Fix stream_start_sine for single stream Fixed the stream_start_sine function when omitting the all argument. The verification of the sine checked reversed return value, and was placed in incorrect order. Signed-off-by: Fredrik Danebjer --- subsys/bluetooth/audio/shell/bap.c | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/subsys/bluetooth/audio/shell/bap.c b/subsys/bluetooth/audio/shell/bap.c index 70368226487..7ad179969cf 100644 --- a/subsys/bluetooth/audio/shell/bap.c +++ b/subsys/bluetooth/audio/shell/bap.c @@ -2697,11 +2697,6 @@ static int cmd_start_sine(const struct shell *sh, size_t argc, char *argv[]) shell_print(sh, "Started transmitting on broadcast stream %p", bap_stream); } } else { - if (stream_start_sine_verify(default_stream)) { - shell_error(sh, "Invalid stream %p", default_stream); - return -ENOEXEC; - } - err = init_lc3(default_stream); if (err != 0) { shell_error(sh, "Failed to init LC3 %d", err); @@ -2709,6 +2704,11 @@ static int cmd_start_sine(const struct shell *sh, size_t argc, char *argv[]) return -ENOEXEC; } + if (!stream_start_sine_verify(default_stream)) { + shell_error(sh, "Invalid stream %p", default_stream); + return -ENOEXEC; + } + err = stream_start_sine(default_stream); if (err != 0) { shell_error(sh, "Failed to start TX for stream %p: %d", default_stream, From 0c095898fbdfb8a2787fa6fea8048802eb455240 Mon Sep 17 00:00:00 2001 From: Robert Lubos Date: Thu, 14 Dec 2023 10:14:09 +0100 Subject: [PATCH 1287/3723] net: shell: Prevent deadlock with net arp command In case one of the networking shell backends is enabled, net arp command could potentially trigger a deadlock, as it locks the ARP mutex before TCP connection mutex, while TCP stack could do this in reverse order (for instance when sending ACK or retransmission). Mitigate this, by forcing a separate TX thread in such case, so that ARP mutex is no longer accessed with TCP mutex locked. Signed-off-by: Robert Lubos --- subsys/net/ip/Kconfig | 16 +++++++++++++--- 1 file changed, 13 insertions(+), 3 deletions(-) diff --git a/subsys/net/ip/Kconfig b/subsys/net/ip/Kconfig index 705ffdcae1c..a479561e132 100644 --- a/subsys/net/ip/Kconfig +++ b/subsys/net/ip/Kconfig @@ -184,13 +184,23 @@ config NET_SHELL_DYN_CMD_COMPLETION length) by default. Other dynamic completion commands in net-shell require also some smaller amount of memory. +config NET_SHELL_REQUIRE_TX_THREAD + bool + depends on NET_SHELL && (SHELL_BACKEND_TELNET || SHELL_BACKEND_MQTT) + default y if NET_ARP + help + Hidden symbol indicating that network shell requires separate TX + thread due to possible deadlocks during shell/net stack operations. + config NET_TC_TX_COUNT int "How many Tx traffic classes to have for each network device" - default 1 if USERSPACE || USB_DEVICE_NETWORK + default 1 if USERSPACE || USB_DEVICE_NETWORK || \ + NET_SHELL_REQUIRE_TX_THREAD default 0 - range 1 NET_TC_NUM_PRIORITIES if NET_TC_NUM_PRIORITIES<=8 && USERSPACE + range 1 NET_TC_NUM_PRIORITIES if NET_TC_NUM_PRIORITIES<=8 && \ + (USERSPACE || NET_SHELL_REQUIRE_TX_THREAD) range 0 NET_TC_NUM_PRIORITIES if NET_TC_NUM_PRIORITIES<=8 - range 1 8 if USERSPACE + range 1 8 if USERSPACE || NET_SHELL_REQUIRE_TX_THREAD range 0 8 help Define how many Tx traffic classes (queues) the system should have From a48a594f13a286f926450c4dc8be2f635dc16563 Mon Sep 17 00:00:00 2001 From: Jamie McCrae Date: Sun, 10 Dec 2023 13:10:13 +0000 Subject: [PATCH 1288/3723] mgmt: mcumgr: callback: Add op to receive callback Adds the operation supplied by the client to the MCUmgr command received callback Signed-off-by: Jamie McCrae --- include/zephyr/mgmt/mcumgr/mgmt/callbacks.h | 3 +++ subsys/mgmt/mcumgr/smp/src/smp.c | 2 +- 2 files changed, 4 insertions(+), 1 deletion(-) diff --git a/include/zephyr/mgmt/mcumgr/mgmt/callbacks.h b/include/zephyr/mgmt/mcumgr/mgmt/callbacks.h index 43ee5ed6f95..7678a70fdf9 100644 --- a/include/zephyr/mgmt/mcumgr/mgmt/callbacks.h +++ b/include/zephyr/mgmt/mcumgr/mgmt/callbacks.h @@ -251,6 +251,9 @@ struct mgmt_evt_op_cmd_arg { uint8_t id; union { + /** #mcumgr_op_t used in #MGMT_EVT_OP_CMD_RECV */ + uint8_t op; + /** #mcumgr_err_t, used in #MGMT_EVT_OP_CMD_DONE */ int err; diff --git a/subsys/mgmt/mcumgr/smp/src/smp.c b/subsys/mgmt/mcumgr/smp/src/smp.c index a0004f6aa68..7aff480e091 100644 --- a/subsys/mgmt/mcumgr/smp/src/smp.c +++ b/subsys/mgmt/mcumgr/smp/src/smp.c @@ -213,7 +213,7 @@ static int smp_handle_single_payload(struct smp_streamer *cbuf, const struct smp #if defined(CONFIG_MCUMGR_SMP_COMMAND_STATUS_HOOKS) cmd_recv.group = req_hdr->nh_group; cmd_recv.id = req_hdr->nh_id; - cmd_recv.err = MGMT_ERR_EOK; + cmd_recv.op = req_hdr->nh_op; /* Send request to application to check if handler should run or not. */ status = mgmt_callback_notify(MGMT_EVT_OP_CMD_RECV, &cmd_recv, sizeof(cmd_recv), From cf5781a1481b39b849cb7c03f31cb13e6f9f372b Mon Sep 17 00:00:00 2001 From: Vudang Thaihai Date: Fri, 15 Dec 2023 11:24:21 +0000 Subject: [PATCH 1289/3723] drivers: gpio: gpio_pca953x: Adding input latch and interrupt mask The gpio_pca953x gpio driver doesn't have the input latch and interrupt mask configuration which causes a lack of accessing and using those features on an gpio expander device. Fix it by adding input latch and interrupt mask configurations in this driver. Signed-off-by: Vudang Thaihai --- drivers/gpio/gpio_pca953x.c | 14 ++++++++++++++ dts/bindings/gpio/ti,tca9538.yaml | 14 ++++++++++++++ 2 files changed, 28 insertions(+) diff --git a/drivers/gpio/gpio_pca953x.c b/drivers/gpio/gpio_pca953x.c index 7b5db11826e..5bdb5ba8fd9 100644 --- a/drivers/gpio/gpio_pca953x.c +++ b/drivers/gpio/gpio_pca953x.c @@ -27,6 +27,8 @@ LOG_MODULE_REGISTER(pca953x, CONFIG_GPIO_LOG_LEVEL); #define PCA953X_INPUT_PORT 0x00 #define PCA953X_OUTPUT_PORT 0x01 #define PCA953X_CONFIGURATION 0x03 +#define REG_INPUT_LATCH_PORT0 0x42 +#define REG_INT_MASK_PORT0 0x45 /* Number of pins supported by the device */ #define NUM_PINS 8 @@ -67,6 +69,8 @@ struct pca953x_config { struct i2c_dt_spec i2c; const struct gpio_dt_spec gpio_int; bool interrupt_enabled; + int interrupt_mask; + int input_latch; }; /** @@ -439,6 +443,14 @@ static int gpio_pca953x_init(const struct device *dev) rc = gpio_add_callback(cfg->gpio_int.port, &drv_data->gpio_cb); + + /* This may not present on all variants of device */ + if (cfg->input_latch > -1) { + i2c_reg_write_byte_dt(&cfg->i2c, REG_INPUT_LATCH_PORT0, cfg->input_latch); + } + if (cfg->interrupt_mask > -1) { + i2c_reg_write_byte_dt(&cfg->i2c, REG_INT_MASK_PORT0, cfg->interrupt_mask); + } } out: if (rc) { @@ -468,6 +480,8 @@ static const struct gpio_driver_api api_table = { }, \ .interrupt_enabled = DT_INST_NODE_HAS_PROP(n, nint_gpios), \ .gpio_int = GPIO_DT_SPEC_INST_GET_OR(n, nint_gpios, {0}), \ + .interrupt_mask = DT_INST_PROP_OR(n, interrupt_mask, -1), \ + .input_latch = DT_INST_PROP_OR(n, input_latch, -1), \ }; \ \ static struct pca953x_drv_data pca953x_drvdata_##n = { \ diff --git a/dts/bindings/gpio/ti,tca9538.yaml b/dts/bindings/gpio/ti,tca9538.yaml index 6cb235995ab..9200a9a1606 100644 --- a/dts/bindings/gpio/ti,tca9538.yaml +++ b/dts/bindings/gpio/ti,tca9538.yaml @@ -24,6 +24,20 @@ properties: Connection for the NINT signal. This signal is active-low when produced by tca9538 GPIO node. + input-latch: + type: int + description: | + Input latch register bit is 0 by default and the input pin state + is not latched. When input latch register bit is 1 and the input + pin state is latched. + + interrupt-mask: + type: int + description: | + Interrupt mask register is set to logic 1 by default without + enabling interrupts. Setting corresponding mask bits to logic + 0 to enable the interrupts. + gpio-cells: - pin - flags From f684e299b94cb7a579e8d12f3edb638c609f01f8 Mon Sep 17 00:00:00 2001 From: Gustavo Silva Date: Sun, 5 Nov 2023 17:46:59 -0300 Subject: [PATCH 1290/3723] drivers: stm32: use IF_ENABLED() macro in config structs Use the IF_ENABLED() macro to increase readability in some of the STM32 drivers. Fixes #62962 Signed-off-by: Gustavo Silva --- drivers/dma/dma_stm32.c | 20 ++++---------------- drivers/i2c/i2c_ll_stm32.c | 33 +++++++++------------------------ drivers/spi/spi_ll_stm32.c | 12 +++--------- 3 files changed, 16 insertions(+), 49 deletions(-) diff --git a/drivers/dma/dma_stm32.c b/drivers/dma/dma_stm32.c index 64c3b21f5ae..2e7e37a7cfb 100644 --- a/drivers/dma/dma_stm32.c +++ b/drivers/dma/dma_stm32.c @@ -688,20 +688,6 @@ static const struct dma_driver_api dma_funcs = { .get_status = dma_stm32_get_status, }; -#ifdef CONFIG_DMAMUX_STM32 -#define DMA_STM32_OFFSET_INIT(index) \ - .offset = DT_INST_PROP(index, dma_offset), -#else -#define DMA_STM32_OFFSET_INIT(index) -#endif /* CONFIG_DMAMUX_STM32 */ - -#ifdef CONFIG_DMA_STM32_V1 -#define DMA_STM32_MEM2MEM_INIT(index) \ - .support_m2m = DT_INST_PROP(index, st_mem2mem), -#else -#define DMA_STM32_MEM2MEM_INIT(index) -#endif /* CONFIG_DMA_STM32_V1 */ \ - #define DMA_STM32_INIT_DEV(index) \ static struct dma_stm32_stream \ dma_stm32_streams_##index[DMA_STM32_##index##_STREAM_COUNT]; \ @@ -711,10 +697,12 @@ const struct dma_stm32_config dma_stm32_config_##index = { \ .enr = DT_INST_CLOCKS_CELL(index, bits) }, \ .config_irq = dma_stm32_config_irq_##index, \ .base = DT_INST_REG_ADDR(index), \ - DMA_STM32_MEM2MEM_INIT(index) \ + IF_ENABLED(CONFIG_DMA_STM32_V1, \ + (.support_m2m = DT_INST_PROP(index, st_mem2mem),)) \ .max_streams = DMA_STM32_##index##_STREAM_COUNT, \ .streams = dma_stm32_streams_##index, \ - DMA_STM32_OFFSET_INIT(index) \ + IF_ENABLED(CONFIG_DMAMUX_STM32, \ + (.offset = DT_INST_PROP(index, dma_offset),)) \ }; \ \ static struct dma_stm32_data dma_stm32_data_##index = { \ diff --git a/drivers/i2c/i2c_ll_stm32.c b/drivers/i2c/i2c_ll_stm32.c index 616c89b3dcb..f834aa658f7 100644 --- a/drivers/i2c/i2c_ll_stm32.c +++ b/drivers/i2c/i2c_ll_stm32.c @@ -557,30 +557,12 @@ static void i2c_stm32_irq_config_func_##index(const struct device *dev) \ #endif /* CONFIG_I2C_STM32_INTERRUPT */ -#if CONFIG_I2C_STM32_BUS_RECOVERY -#define I2C_STM32_SCL_INIT(n) .scl = GPIO_DT_SPEC_INST_GET_OR(n, scl_gpios, {0}), -#define I2C_STM32_SDA_INIT(n) .sda = GPIO_DT_SPEC_INST_GET_OR(n, sda_gpios, {0}), -#else -#define I2C_STM32_SCL_INIT(n) -#define I2C_STM32_SDA_INIT(n) -#endif /* CONFIG_I2C_STM32_BUS_RECOVERY */ - -#if DT_HAS_COMPAT_STATUS_OKAY(st_stm32_i2c_v2) -#define DEFINE_TIMINGS(index) \ - static const uint32_t i2c_timings_##index[] = \ - DT_INST_PROP_OR(index, timings, {}); -#define USE_TIMINGS(index) \ - .timings = (const struct i2c_config_timing *) i2c_timings_##index, \ - .n_timings = ARRAY_SIZE(i2c_timings_##index), -#else /* V2 */ -#define DEFINE_TIMINGS(index) -#define USE_TIMINGS(index) -#endif /* V2 */ - #define STM32_I2C_INIT(index) \ STM32_I2C_IRQ_HANDLER_DECL(index); \ \ -DEFINE_TIMINGS(index) \ +IF_ENABLED(DT_HAS_COMPAT_STATUS_OKAY(st_stm32_i2c_v2), \ + (static const uint32_t i2c_timings_##index[] = \ + DT_INST_PROP_OR(index, timings, {});)) \ \ PINCTRL_DT_INST_DEFINE(index); \ \ @@ -594,9 +576,12 @@ static const struct i2c_stm32_config i2c_stm32_cfg_##index = { \ STM32_I2C_IRQ_HANDLER_FUNCTION(index) \ .bitrate = DT_INST_PROP(index, clock_frequency), \ .pcfg = PINCTRL_DT_INST_DEV_CONFIG_GET(index), \ - I2C_STM32_SCL_INIT(index) \ - I2C_STM32_SDA_INIT(index) \ - USE_TIMINGS(index) \ + IF_ENABLED(CONFIG_I2C_STM32_BUS_RECOVERY, \ + (.scl = GPIO_DT_SPEC_INST_GET_OR(index, scl_gpios, {0}),\ + .sda = GPIO_DT_SPEC_INST_GET_OR(index, sda_gpios, {0}),))\ + IF_ENABLED(DT_HAS_COMPAT_STATUS_OKAY(st_stm32_i2c_v2), \ + (.timings = (const struct i2c_config_timing *) i2c_timings_##index,\ + .n_timings = ARRAY_SIZE(i2c_timings_##index),)) \ }; \ \ static struct i2c_stm32_data i2c_stm32_dev_data_##index; \ diff --git a/drivers/spi/spi_ll_stm32.c b/drivers/spi/spi_ll_stm32.c index 76e9b923c87..fcb27cdbe31 100644 --- a/drivers/spi/spi_ll_stm32.c +++ b/drivers/spi/spi_ll_stm32.c @@ -1173,14 +1173,6 @@ static void spi_stm32_irq_config_func_##id(const struct device *dev) \ #define SPI_DMA_STATUS_SEM(id) #endif -#if DT_HAS_COMPAT_STATUS_OKAY(st_stm32_spi_subghz) -#define STM32_SPI_USE_SUBGHZSPI_NSS_CONFIG(id) \ - .use_subghzspi_nss = DT_INST_PROP_OR( \ - id, use_subghzspi_nss, false), -#else -#define STM32_SPI_USE_SUBGHZSPI_NSS_CONFIG(id) -#endif - #define STM32_SPI_INIT(id) \ @@ -1197,7 +1189,9 @@ static const struct spi_stm32_config spi_stm32_cfg_##id = { \ .pclk_len = DT_INST_NUM_CLOCKS(id), \ .pcfg = PINCTRL_DT_INST_DEV_CONFIG_GET(id), \ STM32_SPI_IRQ_HANDLER_FUNC(id) \ - STM32_SPI_USE_SUBGHZSPI_NSS_CONFIG(id) \ + IF_ENABLED(DT_HAS_COMPAT_STATUS_OKAY(st_stm32_spi_subghz), \ + (.use_subghzspi_nss = \ + DT_INST_PROP_OR(id, use_subghzspi_nss, false),))\ }; \ \ static struct spi_stm32_data spi_stm32_dev_data_##id = { \ From 2f4cf25c393248ba24b53e6d914416d1414c08bd Mon Sep 17 00:00:00 2001 From: Bartosz Bilas Date: Sun, 3 Dec 2023 17:47:57 +0100 Subject: [PATCH 1291/3723] dts: bindings: ethernet: esp32: remove default phy conn type That's already harcoded in the driver so there is no need to do that in the bindings. Signed-off-by: Bartosz Bilas --- dts/bindings/ethernet/espressif,esp32-eth.yaml | 3 --- 1 file changed, 3 deletions(-) diff --git a/dts/bindings/ethernet/espressif,esp32-eth.yaml b/dts/bindings/ethernet/espressif,esp32-eth.yaml index ea973265ab2..df063fd57a8 100644 --- a/dts/bindings/ethernet/espressif,esp32-eth.yaml +++ b/dts/bindings/ethernet/espressif,esp32-eth.yaml @@ -12,9 +12,6 @@ properties: phy-handle: required: true - phy-connection-type: - default: "rmii" - ref-clk-output-gpios: type: phandle-array description: | From d77c706f9481725ab0c04dd29eae37af283f8e5f Mon Sep 17 00:00:00 2001 From: Mahesh Mahadevan Date: Mon, 11 Dec 2023 11:20:35 -0600 Subject: [PATCH 1292/3723] drivers: dma_lpc: Suppport dest_scatter and source_gather Process dest_scatter_interval and source_gather_interval configurations and accordingly set the source and destination increment values. Signed-off-by: Mahesh Mahadevan --- drivers/dma/dma_mcux_lpc.c | 91 +++++++++++++++++++++++++++----------- 1 file changed, 65 insertions(+), 26 deletions(-) diff --git a/drivers/dma/dma_mcux_lpc.c b/drivers/dma/dma_mcux_lpc.c index ce0632a4045..f8d9ab81e08 100644 --- a/drivers/dma/dma_mcux_lpc.c +++ b/drivers/dma/dma_mcux_lpc.c @@ -41,6 +41,8 @@ struct channel_data { void *user_data; dma_callback_t dma_callback; enum dma_channel_direction dir; + uint8_t src_inc; + uint8_t dst_inc; dma_descriptor_t *curr_descriptor; uint8_t num_of_descriptors; bool descriptors_queued; @@ -283,6 +285,8 @@ static void dma_mcux_lpc_clear_channel_data(struct channel_data *data) { data->dma_callback = NULL; data->dir = 0; + data->src_inc = 0; + data->dst_inc = 0; data->descriptors_queued = false; data->num_of_descriptors = 0; data->curr_descriptor = NULL; @@ -301,7 +305,7 @@ static int dma_mcux_lpc_configure(const struct device *dev, uint32_t channel, struct dma_block_config *block_config; uint32_t virtual_channel; uint8_t otrig_index; - uint8_t src_inc, dst_inc; + uint8_t src_inc = 1, dst_inc = 1; bool is_periph = true; uint8_t width; uint32_t max_xfer_bytes; @@ -322,6 +326,15 @@ static int dma_mcux_lpc_configure(const struct device *dev, uint32_t channel, */ assert(config->dest_data_size == config->source_data_size); width = config->dest_data_size; + + /* If skip is set on both source and destination + * then skip by the same amount on both sides + */ + if (block_config->source_gather_en && block_config->dest_scatter_en) { + assert(block_config->source_gather_interval == + block_config->dest_scatter_interval); + } + max_xfer_bytes = NXP_LPC_DMA_MAX_XFER * width; /* @@ -361,16 +374,53 @@ static int dma_mcux_lpc_configure(const struct device *dev, uint32_t channel, switch (config->channel_direction) { case MEMORY_TO_MEMORY: is_periph = false; - src_inc = 1; - dst_inc = 1; + if (block_config->source_gather_en) { + src_inc = block_config->source_gather_interval / width; + /* The current controller only supports incrementing the + * source and destination up to 4 time transfer width + */ + if ((src_inc > 4) || (src_inc == 3)) { + return -EINVAL; + } + } + + if (block_config->dest_scatter_en) { + dst_inc = block_config->dest_scatter_interval / width; + /* The current controller only supports incrementing the + * source and destination up to 4 time transfer width + */ + if ((dst_inc > 4) || (dst_inc == 3)) { + return -EINVAL; + } + } break; case MEMORY_TO_PERIPHERAL: - src_inc = 1; + /* Set the source increment value */ + if (block_config->source_gather_en) { + src_inc = block_config->source_gather_interval / width; + /* The current controller only supports incrementing the + * source and destination up to 4 time transfer width + */ + if ((src_inc > 4) || (src_inc == 3)) { + return -EINVAL; + } + } + dst_inc = 0; break; case PERIPHERAL_TO_MEMORY: src_inc = 0; - dst_inc = 1; + + /* Set the destination increment value */ + if (block_config->dest_scatter_en) { + dst_inc = block_config->dest_scatter_interval / width; + /* The current controller only supports incrementing the + * source and destination up to 4 time transfer width + */ + if ((dst_inc > 4) || (dst_inc == 3)) { + return -EINVAL; + } + } break; default: LOG_ERR("not support transfer direction"); @@ -409,6 +459,9 @@ static int dma_mcux_lpc_configure(const struct device *dev, uint32_t channel, dma_mcux_lpc_clear_channel_data(data); data->dir = config->channel_direction; + /* Save the increment values for the reload function */ + data->src_inc = src_inc; + data->dst_inc = dst_inc; if (data->busy) { DMA_AbortTransfer(p_handle); @@ -677,26 +730,11 @@ static int dma_mcux_lpc_reload(const struct device *dev, uint32_t channel, struct dma_mcux_lpc_dma_data *dev_data = dev->data; int8_t virtual_channel = dev_data->channel_index[channel]; struct channel_data *data = DEV_CHANNEL_DATA(dev, virtual_channel); - uint8_t src_inc, dst_inc; uint32_t xfer_config = 0U; - switch (data->dir) { - case MEMORY_TO_MEMORY: - src_inc = 1; - dst_inc = 1; - break; - case MEMORY_TO_PERIPHERAL: - src_inc = 1; - dst_inc = 0; - break; - case PERIPHERAL_TO_MEMORY: - src_inc = 0; - dst_inc = 1; - break; - default: - LOG_ERR("not support transfer direction"); - return -EINVAL; - } + /* DMA controller requires that the address be aligned to transfer size */ + assert(src == ROUND_UP(src, data->width)); + assert(dst == ROUND_UP(dst, data->width)); if (!data->descriptors_queued) { dma_handle_t *p_handle; @@ -706,8 +744,8 @@ static int dma_mcux_lpc_reload(const struct device *dev, uint32_t channel, /* Only one buffer, enable interrupt */ xfer_config = DMA_CHANNEL_XFER(0UL, 0UL, 1UL, 0UL, data->width, - src_inc, - dst_inc, + data->src_inc, + data->dst_inc, size); DMA_SubmitChannelTransferParameter(p_handle, xfer_config, @@ -721,7 +759,8 @@ static int dma_mcux_lpc_reload(const struct device *dev, uint32_t channel, local_block.dest_address = dst; local_block.block_size = size; local_block.source_reload_en = 1; - dma_mcux_lpc_queue_descriptors(data, &local_block, src_inc, dst_inc, true); + dma_mcux_lpc_queue_descriptors(data, &local_block, + data->src_inc, data->dst_inc, true); } return 0; From cb13e21eaee2be73c626d30f3ef19d9d8c8afdf8 Mon Sep 17 00:00:00 2001 From: Joakim Andersson Date: Wed, 13 Dec 2023 14:39:05 +0100 Subject: [PATCH 1293/3723] tests: net: socket: tcp: Fix build for nrf5340dk_nrf5340_cpuapp_ns Fix build for nrf5340dk_nrf5340_cpuapp_ns. Test takes up almost all of the flash, leaving no room for the image to be signed. Disable the bootloader to free up flash-usage. Fixes: #66469 Signed-off-by: Joakim Andersson --- tests/net/socket/tcp/prj.conf | 3 +++ 1 file changed, 3 insertions(+) diff --git a/tests/net/socket/tcp/prj.conf b/tests/net/socket/tcp/prj.conf index 77f483a0486..846cfa90749 100644 --- a/tests/net/socket/tcp/prj.conf +++ b/tests/net/socket/tcp/prj.conf @@ -57,3 +57,6 @@ CONFIG_NET_CONTEXT_SNDBUF=y # Because of userspace and recvmsg() we need some extra heap in order to # copy the iovec in the recvmsg tests. CONFIG_HEAP_MEM_POOL_SIZE=512 + +# If using TF-M, disable the BL2 bootloader to save flash-space for the test. +CONFIG_TFM_BL2=n From c2dae16a6a2ea9044cb47a9feed03ec0fa57c5b1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Benjamin=20Cab=C3=A9?= Date: Fri, 15 Dec 2023 08:41:15 +0000 Subject: [PATCH 1294/3723] doc: remove explicit libpython3.8-dev from Ubuntu deps MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Having libpython3.8-dev explicitly mentioned causes issues if "python3-dev" pulls a Python version that's not 3.8. What's more, python3-dev already pulls the correct "versionless" libpython3-dev anyway. Fixes #66461 Signed-off-by: Benjamin Cabé --- doc/develop/getting_started/installation_linux.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/doc/develop/getting_started/installation_linux.rst b/doc/develop/getting_started/installation_linux.rst index 1d96ec1060f..afe8fbfecf4 100644 --- a/doc/develop/getting_started/installation_linux.rst +++ b/doc/develop/getting_started/installation_linux.rst @@ -78,7 +78,7 @@ need one. sudo apt-get install --no-install-recommends git cmake ninja-build gperf \ ccache dfu-util device-tree-compiler wget \ - python3-dev python3-pip python3-setuptools python3-tk python3-wheel xz-utils file libpython3.8-dev \ + python3-dev python3-pip python3-setuptools python3-tk python3-wheel xz-utils file \ make gcc gcc-multilib g++-multilib libsdl2-dev libmagic1 .. group-tab:: Fedora From d76934daeb43a7f0200847f299e720b68beef084 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tomasz=20Mo=C5=84?= Date: Wed, 22 Nov 2023 08:45:28 +0100 Subject: [PATCH 1295/3723] dt-bindings: usb: initial USB Audio Class 2 support MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit USB Audio Class 2 (UAC2) includes a method to describe audio device topology to host using a set of class specific descriptors. The audio device description includes complete sample clock topology and audio processing organization. Zephyr specific bindings are supposed to allow user to create reasonably simple audio device description using devicetree syntax. The bindings currently include only the absolute minimum set required for headset example. Bindings for other entities (Clock Selector, Clock Multiplier, Mixer Unit, Selector Unit, Feature Unit, Sample Rate Converter, variuos Effect Units, various Processing Units, Extension Unit) can be added later together with the actual USB class implementation. The main idea is that user does create one zephyr,uac2 compatible node for every USB Audio 2 class instance. Note that in majority of cases just one USB Audio 2 class is necessary because the number of streaming interfaces is virtually unlimited (USB Audio 2 class can have up to 255 entities). The zephyr,uac2 node includes child nodes with compatibles set to desired entity or audiostreaming interface. The parent-child relationship is necessary to allow grouping entities to correct audio class instance. Signed-off-by: Tomasz Moń --- .../usb/uac2/zephyr,uac2-audio-streaming.yaml | 80 ++++++++++++ .../usb/uac2/zephyr,uac2-channel-cluster.yaml | 117 ++++++++++++++++++ .../usb/uac2/zephyr,uac2-clock-source.yaml | 52 ++++++++ .../usb/uac2/zephyr,uac2-input-terminal.yaml | 62 ++++++++++ .../usb/uac2/zephyr,uac2-output-terminal.yaml | 60 +++++++++ dts/bindings/usb/uac2/zephyr,uac2.yaml | 39 ++++++ include/zephyr/dt-bindings/usb/audio.h | 112 +++++++++++++++++ 7 files changed, 522 insertions(+) create mode 100644 dts/bindings/usb/uac2/zephyr,uac2-audio-streaming.yaml create mode 100644 dts/bindings/usb/uac2/zephyr,uac2-channel-cluster.yaml create mode 100644 dts/bindings/usb/uac2/zephyr,uac2-clock-source.yaml create mode 100644 dts/bindings/usb/uac2/zephyr,uac2-input-terminal.yaml create mode 100644 dts/bindings/usb/uac2/zephyr,uac2-output-terminal.yaml create mode 100644 dts/bindings/usb/uac2/zephyr,uac2.yaml create mode 100644 include/zephyr/dt-bindings/usb/audio.h diff --git a/dts/bindings/usb/uac2/zephyr,uac2-audio-streaming.yaml b/dts/bindings/usb/uac2/zephyr,uac2-audio-streaming.yaml new file mode 100644 index 00000000000..6e661d1c73d --- /dev/null +++ b/dts/bindings/usb/uac2/zephyr,uac2-audio-streaming.yaml @@ -0,0 +1,80 @@ +# Copyright (c) 2023 Nordic Semiconductor ASA +# SPDX-License-Identifier: Apache-2.0 + +description: USB Audio Class 2 Audio Streaming interface + +compatible: "zephyr,uac2-audio-streaming" + +properties: + linked-terminal: + type: phandle + required: true + description: | + Input or Output Terminal to which this interface is connected. + + active-alternate-setting-control: + type: string + description: Active Alternate Setting Control capabilities + enum: + - "read-only" + + valid-alternate-settings-control: + type: string + description: Valid Alternate Settings Control capabilities + enum: + - "read-only" + + external-interface: + type: boolean + description: | + Enable if audio stream is not transmitted over USB (Type IV Audio Stream). + + implicit-feedback: + type: boolean + description: | + Enable implicit feedback on asynchronous endpoint. For IN endpoints this + sets endpoint behaviour type to implicit feedback data endpoint. For OUT + endpoints setting this property removes explicit feedback endpoint. + + pitch-control: + type: string + description: Pitch Control capabilities + enum: + - "read-only" + - "host-programmable" + + data-overrun-control: + type: string + description: Data Overrun capabilities + enum: + - "read-only" + + data-underrun-control: + type: string + description: Data Underrun capabilities + enum: + - "read-only" + + lock-delay: + type: int + description: | + Time it takes this endpoint to reliably lock its internal clock recovery + circuitry. Units depend on the lock-delay-units field. Relevant only if + linked-terminal's clock is sof-synchronized. + + lock-delay-units: + type: string + description: Units for lock-delay parameter. + enum: + - "milliseconds" + - "decoded-pcm-samples" + + subslot-size: + type: int + description: | + Number of bytes occupied by one audio subslot. Can be 1, 2, 3 or 4. + + bit-resolution: + type: int + description: | + Number of effectively used bits in audio subslot. diff --git a/dts/bindings/usb/uac2/zephyr,uac2-channel-cluster.yaml b/dts/bindings/usb/uac2/zephyr,uac2-channel-cluster.yaml new file mode 100644 index 00000000000..e71b2990a29 --- /dev/null +++ b/dts/bindings/usb/uac2/zephyr,uac2-channel-cluster.yaml @@ -0,0 +1,117 @@ +# Copyright (c) 2023 Nordic Semiconductor ASA +# SPDX-License-Identifier: Apache-2.0 + +description: USB Audio Class 2 Audio Channel Cluster + +properties: + front-left: + type: boolean + description: Front Left channel present in the cluster + + front-right: + type: boolean + description: Front Right channel present in the cluster + + front-center: + type: boolean + description: Front Center channel present in the cluster + + low-frequency-effects: + type: boolean + description: Low Frequency Effects channel present in the cluster + + back-left: + type: boolean + description: Back Left channel present in the cluster + + back-right: + type: boolean + description: Back Right channel present in the cluster + + front-left-of-center: + type: boolean + description: Front Left of Center channel present in the cluster + + front-right-of-center: + type: boolean + description: Front Right of Center channel present in the cluster + + back-center: + type: boolean + description: Back Center channel present in the cluster + + side-left: + type: boolean + description: Side Left channel present in the cluster + + side-right: + type: boolean + description: Side Right channel present in the cluster + + top-center: + type: boolean + description: Top Center channel present in the cluster + + top-front-left: + type: boolean + description: Top Front Left channel present in the cluster + + top-front-center: + type: boolean + description: Top Front Center channel present in the cluster + + top-front-right: + type: boolean + description: Top Front Right channel present in the cluster + + top-back-left: + type: boolean + description: Top Back Left channel present in the cluster + + top-back-center: + type: boolean + description: Top Back Center channel present in the cluster + + top-back-right: + type: boolean + description: Top Back Right channel present in the cluster + + top-front-left-of-center: + type: boolean + description: Top Front Left of Center channel present in the cluster + + top-front-right-of-center: + type: boolean + description: Top Front Right of Center channel present in the cluster + + left-low-frequency-effects: + type: boolean + description: Left Low Frequency Effects channel present in the cluster + + right-low-frequency-effects: + type: boolean + description: Right Low Frequency Effects channel present in the cluster + + top-side-left: + type: boolean + description: Top Side Left channel present in the cluster + + top-side-right: + type: boolean + description: Top Side Right channel present in the cluster + + bottom-center: + type: boolean + description: Bottom Center channel present in the cluster + + back-left-of-center: + type: boolean + description: Back Left of Center channel present in the cluster + + back-right-of-center: + type: boolean + description: Back Right of Center channel present in the cluster + + raw-data: + type: boolean + description: Raw Data, mutually exclusive with all other spatial locations diff --git a/dts/bindings/usb/uac2/zephyr,uac2-clock-source.yaml b/dts/bindings/usb/uac2/zephyr,uac2-clock-source.yaml new file mode 100644 index 00000000000..3a2412b1427 --- /dev/null +++ b/dts/bindings/usb/uac2/zephyr,uac2-clock-source.yaml @@ -0,0 +1,52 @@ +# Copyright (c) 2023 Nordic Semiconductor ASA +# SPDX-License-Identifier: Apache-2.0 + +description: USB Audio Class 2 Clock Source entity + +compatible: "zephyr,uac2-clock-source" + +properties: + clock-type: + type: string + required: true + description: | + Clock Type indicating whether the Clock Source represents an external + clock or an internal clock with either fixed frequency, variable + frequency, or programmable frequency. + enum: + - "external" + - "internal-fixed" + - "internal-variable" + - "internal-programmable" + + sof-synchronized: + type: boolean + description: | + True if clock is synchronized to USB Start of Frame. False if clock is + free running. External clock must be free running. + + frequency-control: + type: string + description: Clock Frequency Control capabilities + enum: + - "read-only" + - "host-programmable" + + validity-control: + type: string + description: Clock Validity Control capabilities + enum: + - "read-only" + + assoc-terminal: + type: phandle + description: | + Input or Output Terminal associated with this Clock Source. Set if clock + is derived from USB OUT data endpoint (point the handle to respective + Input Terminal) or from input signal on S/PDIF connector. + + sampling-frequencies: + type: array + required: true + description: | + Sampling Frequencies, in Hz, this Clock Source Entity can generate. diff --git a/dts/bindings/usb/uac2/zephyr,uac2-input-terminal.yaml b/dts/bindings/usb/uac2/zephyr,uac2-input-terminal.yaml new file mode 100644 index 00000000000..0c638566c61 --- /dev/null +++ b/dts/bindings/usb/uac2/zephyr,uac2-input-terminal.yaml @@ -0,0 +1,62 @@ +# Copyright (c) 2023 Nordic Semiconductor ASA +# SPDX-License-Identifier: Apache-2.0 + +description: USB Audio Class 2 Input Terminal entity + +compatible: "zephyr,uac2-input-terminal" + +include: zephyr,uac2-channel-cluster.yaml + +properties: + terminal-type: + type: int + required: true + description: | + Terminal Type constant specified in USB Audio Terminal Types + + assoc-terminal: + type: phandle + description: | + Associated terminal for bi-directional terminal types. + + clock-source: + type: phandle + required: true + description: | + Connected clock entity + + copy-protect-control: + type: string + description: Copy Protect Control capabilities + enum: + - "read-only" + + connector-control: + type: string + description: Connector Control capabilities + enum: + - "read-only" + + overload-control: + type: string + description: Overload Control capabilities + enum: + - "read-only" + + cluster-control: + type: string + description: Cluster Control capabilities + enum: + - "read-only" + + underflow-control: + type: string + description: Underflow Control capabilities + enum: + - "read-only" + + overflow-control: + type: string + description: Overflow Control capabilities + enum: + - "read-only" diff --git a/dts/bindings/usb/uac2/zephyr,uac2-output-terminal.yaml b/dts/bindings/usb/uac2/zephyr,uac2-output-terminal.yaml new file mode 100644 index 00000000000..c1ce1d842f3 --- /dev/null +++ b/dts/bindings/usb/uac2/zephyr,uac2-output-terminal.yaml @@ -0,0 +1,60 @@ +# Copyright (c) 2023 Nordic Semiconductor ASA +# SPDX-License-Identifier: Apache-2.0 + +description: USB Audio Class 2 Output Terminal entity + +compatible: "zephyr,uac2-output-terminal" + +properties: + terminal-type: + type: int + required: true + description: | + Terminal Type constant specified in USB Audio Terminal Types + + assoc-terminal: + type: phandle + description: | + Associated terminal, e.g. for bidirectional terminal types. + + data-source: + type: phandle + required: true + description: | + Unit or Terminal this terminal receives data from + + clock-source: + type: phandle + required: true + description: | + Connected clock entity + + copy-protect-control: + type: string + description: Copy Protect Control capabilities + enum: + - "host-programmable" + + connector-control: + type: string + description: Connector Control capabilities + enum: + - "read-only" + + overload-control: + type: string + description: Overload Control capabilities + enum: + - "read-only" + + underflow-control: + type: string + description: Underflow Control capabilities + enum: + - "read-only" + + overflow-control: + type: string + description: Overflow Control capabilities + enum: + - "read-only" diff --git a/dts/bindings/usb/uac2/zephyr,uac2.yaml b/dts/bindings/usb/uac2/zephyr,uac2.yaml new file mode 100644 index 00000000000..0f0aaf5b55f --- /dev/null +++ b/dts/bindings/usb/uac2/zephyr,uac2.yaml @@ -0,0 +1,39 @@ +# Copyright (c) 2023 Nordic Semiconductor ASA +# SPDX-License-Identifier: Apache-2.0 + +description: USB Audio Class 2 instance + +compatible: "zephyr,uac2" + +# Child nodes of "zephyr,uac2" compatibles are supposed to be Audio Control +# entities, i.e. clock sources, input terminals, output terminals, etc. +# After all Audio Control entities, the Audio Streaming interface compatibles +# should follow (as child nodes of "zephyr,uac2"). +# +# The only reason for putting Audio Streaming interfaces at the end is because +# Audio Control entities derive their unique ID from child index (+ 1). For most +# cases the order shouldn't really matter, but if there happen to be maximum +# possible number of entities (255) then the Audio Streaming would inadvertedly +# "consume" one of the available IDs. + +properties: + audio-function: + type: int + required: true + description: | + Constant, indicating the primary use of this audio function, as intended + by the manufacturer. Use Audio Function category codes define from + dt-bindings/usb/audio.h. + + interrupt-endpoint: + type: boolean + description: | + Enable to support an optional interrupt endpoint to inform the Host about + dynamic changes that occur on the different addressable entities. + + latency-control: + type: string + description: Latency Control capabilities + enum: + - "read-only" + - "host-programmable" diff --git a/include/zephyr/dt-bindings/usb/audio.h b/include/zephyr/dt-bindings/usb/audio.h new file mode 100644 index 00000000000..4bc8c591457 --- /dev/null +++ b/include/zephyr/dt-bindings/usb/audio.h @@ -0,0 +1,112 @@ +/* + * Copyright (c) 2023 Nordic Semiconductor ASA + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#ifndef ZEPHYR_INCLUDE_DT_BINDINGS_USB_AUDIO_H +#define ZEPHYR_INCLUDE_DT_BINDINGS_USB_AUDIO_H + +/* USB Device Class Definition for Audio Devices Release 2.0 May 31, 2006 + * A.7 Audio Function Category Codes + */ +#define AUDIO_FUNCTION_SUBCLASS_UNDEFINED 0x00 +#define AUDIO_FUNCTION_DESKTOP_SPEAKER 0x01 +#define AUDIO_FUNCTION_HOME_THEATER 0x02 +#define AUDIO_FUNCTION_MICROPHONE 0x03 +#define AUDIO_FUNCTION_HEADSET 0x04 +#define AUDIO_FUNCTION_TELEPHONE 0x05 +#define AUDIO_FUNCTION_CONVERTER 0x06 +#define AUDIO_FUNCTION_VOICE_SOUND_RECORDER 0x07 +#define AUDIO_FUNCTION_IO_BOX 0x08 +#define AUDIO_FUNCTION_MUSICAL_INSTRUMENT 0x09 +#define AUDIO_FUNCTION_PRO_AUDIO 0x0A +#define AUDIO_FUNCTION_AUDIO_VIDEO 0x0B +#define AUDIO_FUNCTION_CONTROL_PANEL 0x0C +#define AUDIO_FUNCTION_OTHER 0xFF + + +/* USB Device Class Definition for Terminal Types + * Both "Universal Serial Bus Device Class Definition for Terminal Types" + * Release 2.0 May 31, 2006 and Release 3.0 September 22, 2016 contain exactly + * the same terminal types and values. + */ + +/* 2.1 USB Terminal Types */ +#define USB_TERMINAL_UNDEFINED 0x0100 +#define USB_TERMINAL_STREAMING 0x0101 +#define USB_TERMINAL_VENDOR_SPECIFIC 0x01FF + +/* 2.2 Input Terminal Types */ +#define INPUT_TERMINAL_UNDEFINED 0x0200 +#define INPUT_TERMINAL_MICROPHONE 0x0201 +#define INPUT_TERMINAL_DESKTOP_MICROPHONE 0x0202 +#define INPUT_TERMINAL_PERSONAL_MICROPHONE 0x0203 +#define INPUT_TERMINAL_OMNI_DIRECTIONAL_MICROPHONE 0x0204 +#define INPUT_TERMINAL_MICROPHONE_ARRAY 0x0205 +#define INPUT_TERMINAL_PROCESSING_MICROPHONE_ARRAY 0x0206 + +/* 2.3 Output Terminal Types */ +#define OUTPUT_TERMINAL_UNDEFINED 0x0300 +#define OUTPUT_TERMINAL_SPEAKER 0x0301 +#define OUTPUT_TERMINAL_HEADPHONES 0x0302 +#define OUTPUT_TERMINAL_HEAD_MOUNTED_DISPLAY_AUDIO 0x0303 +#define OUTPUT_TERMINAL_DESKTOP_SPEAKER 0x0304 +#define OUTPUT_TERMINAL_ROOM_SPEAKER 0x0305 +#define OUTPUT_TERMINAL_COMMUNICATION_SPEAKER 0x0306 +#define OUTPUT_TERMINAL_LOW_FREQUENCY_EFFECTS_SPEAKER 0x0307 + +/* 2.4 Bi-directional Terminal Types */ +#define BIDIRECTIONAL_TERMINAL_UNDEFINED 0x0400 +#define BIDIRECTIONAL_TERMINAL_HANDSET 0x0401 +#define BIDIRECTIONAL_TERMINAL_HEADSET 0x0402 +#define BIDIRECTIONAL_TERMINAL_SPEAKERPHONE_NO_ECHO_REDUCTION 0x0403 +#define BIDIRECTIONAL_TERMINAL_ECHO_SUPPRESSING_SPEAKERPHONE 0x0404 +#define BIDIRECTIONAL_TERMINAL_ECHO_CANCELLING_SPEAKERPHONE 0x0405 + +/* 2.5 Telephony Terminal Types */ +#define TELEPHONY_TERMINAL_UNDEFINED 0x0500 +#define TELEPHONY_TERMINAL_PHONE_LINE 0x0501 +#define TELEPHONY_TERMINAL_TELEPHONE 0x0502 +#define TELEPHONY_TERMINAL_DOWN_LINE_PHONE 0x0503 + +/* 2.6 External Terminal Types */ +#define EXTERNAL_TERMINAL_UNDEFINED 0x0600 +#define EXTERNAL_TERMINAL_ANALOG_CONNECTOR 0x0601 +#define EXTERNAL_TERMINAL_DIGITAL_AUDIO_INTERFACE 0x0602 +#define EXTERNAL_TERMINAL_LINE_CONNECTOR 0x0603 +#define EXTERNAL_TERMINAL_LEGACY_AUDIO_CONNECTOR 0x0604 +#define EXTERNAL_TERMINAL_SPDIF_INTERFACE 0x0605 +#define EXTERNAL_TERMINAL_1394_DA_STREAM 0x0606 +#define EXTERNAL_TERMINAL_1394_DV_STREAM_SOUNDTRACK 0x0607 +#define EXTERNAL_TERMINAL_ADAT_LIGHTPIPE 0x0608 +#define EXTERNAL_TERMINAL_TDIF 0x0609 +#define EXTERNAL_TERMINAL_MADI 0x060A + +/* 2.7 Embedded Function Terminal Types */ +#define EMBEDDED_TERMINAL_UNDEFINED 0x0700 +#define EMBEDDED_TERMINAL_LEVEL_CALIBRATION_NOISE_SOURCE 0x0701 +#define EMBEDDED_TERMINAL_EQUALIZATION_NOISE 0x0702 +#define EMBEDDED_TERMINAL_CD_PLAYER 0x0703 +#define EMBEDDED_TERMINAL_DAT 0x0704 +#define EMBEDDED_TERMINAL_DCC 0x0705 +#define EMBEDDED_TERMINAL_COMPRESSED_AUDIO_PLAYER 0x0706 +#define EMBEDDED_TERMINAL_ANALOG_TAPE 0x0707 +#define EMBEDDED_TERMINAL_PHONOGRAPH 0x0708 +#define EMBEDDED_TERMINAL_VCR_AUDIO 0x0709 +#define EMBEDDED_TERMINAL_VIDEO_DISC_AUDIO 0x070A +#define EMBEDDED_TERMINAL_DVD_AUDIO 0x070B +#define EMBEDDED_TERMINAL_TV_TUNER_AUDIO 0x070C +#define EMBEDDED_TERMINAL_SATELLITE_RECEIVER_AUDIO 0x070D +#define EMBEDDED_TERMINAL_CABLE_TUNER_AUDIO 0x070E +#define EMBEDDED_TERMINAL_DSS_AUDIO 0x070F +#define EMBEDDED_TERMINAL_RADIO_RECEIVER 0x0710 +#define EMBEDDED_TERMINAL_RADIO_TRANSMITTER 0x0711 +#define EMBEDDED_TERMINAL_MULTI_TRACK_RECORDER 0x0712 +#define EMBEDDED_TERMINAL_SYNTHESIZER 0x0713 +#define EMBEDDED_TERMINAL_PIANO 0x0714 +#define EMBEDDED_TERMINAL_GUITAR 0x0715 +#define EMBEDDED_TERMINAL_DRUMS_RHYTHM 0x0716 +#define EMBEDDED_TERMINAL_OTHER_MUSICAL_INSTRUMENT 0x0717 + +#endif /* ZEPHYR_INCLUDE_DT_BINDINGS_USB_AUDIO_H */ From 4f1b5b11b27fe27fca6fdee8b97e86011022775d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tomasz=20Mo=C5=84?= Date: Thu, 30 Nov 2023 13:29:11 +0100 Subject: [PATCH 1296/3723] usb: device_next: uac2: devicetree descriptor macros MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Initial set of macros to generate class specific descriptors based on devicetree nodes. Descriptors are generated as uint8_t array initializer list because there is variable number of entities in between standard USB interface and endpoint descriptors. Because the descriptors are automatically generated there is no real point in trying to generate corresponding C structures (especially that some entity descriptors have variably sized fields in the middle of descriptor, e.g. Clock Selector). Signed-off-by: Tomasz Moń --- .../usb/device_next/class/usbd_uac2_macros.h | 398 ++++++++++++++++++ 1 file changed, 398 insertions(+) create mode 100644 subsys/usb/device_next/class/usbd_uac2_macros.h diff --git a/subsys/usb/device_next/class/usbd_uac2_macros.h b/subsys/usb/device_next/class/usbd_uac2_macros.h new file mode 100644 index 00000000000..ec4ecd1008e --- /dev/null +++ b/subsys/usb/device_next/class/usbd_uac2_macros.h @@ -0,0 +1,398 @@ +/* + * Copyright (c) 2023 Nordic Semiconductor ASA + * + * SPDX-License-Identifier: Apache-2.0 + */ + +/* The macros in this file are not public, applications should not use them. + * The macros are used to translate devicetree zephyr,uac2 compatible nodes + * into uint8_t array initializer. The output should be treated as a binary blob + * for the USB host to use (and parse). + */ + +#include + +#ifndef ZEPHYR_INCLUDE_USBD_UAC2_MACROS_H_ +#define ZEPHYR_INCLUDE_USBD_UAC2_MACROS_H_ + +#define ARRAY_BIT(idx, value) (value##ull << idx) + +#define U16_LE(value) ((value) & 0xFF), (((value) & 0xFF00) >> 8) +#define U32_LE(value) \ + ((value) & 0xFF), \ + (((value) & 0xFF00) >> 8), \ + (((value) & 0xFF0000) >> 16), \ + (((value) & 0xFF000000) >> 24) + +#define ARRAY_ELEMENT_LESS_THAN_NEXT(node, prop, idx) \ + COND_CODE_1(IS_EQ(idx, UTIL_DEC(DT_PROP_LEN(node, prop))), \ + (1 /* nothing to compare the last element against */), \ + ((DT_PROP_BY_IDX(node, prop, idx) < \ + DT_PROP_BY_IDX(node, prop, UTIL_INC(idx))))) +#define IS_ARRAY_SORTED(node, prop) \ + DT_FOREACH_PROP_ELEM_SEP(node, prop, ARRAY_ELEMENT_LESS_THAN_NEXT, (&&)) + +/* A.8 Audio Class-Specific Descriptor Types */ +#define CS_UNDEFINED 0x20 +#define CS_DEVICE 0x21 +#define CS_CONFIGURATION 0x22 +#define CS_STRING 0x23 +#define CS_INTERFACE 0x24 +#define CS_ENDPOINT 0x25 + +/* A.9 Audio Class-Specific AC Interface Descriptor Subtypes */ +#define AC_DESCRIPTOR_UNDEFINED 0x00 +#define AC_DESCRIPTOR_HEADER 0x01 +#define AC_DESCRIPTOR_INPUT_TERMINAL 0x02 +#define AC_DESCRIPTOR_OUTPUT_TERMINAL 0x03 +#define AC_DESCRIPTOR_MIXER_UNIT 0x04 +#define AC_DESCRIPTOR_SELECTOR_UNIT 0x05 +#define AC_DESCRIPTOR_FEATURE_UNIT 0x06 +#define AC_DESCRIPTOR_EFFECT_UNIT 0x07 +#define AC_DESCRIPTOR_PROCESSING_UNIT 0x08 +#define AC_DESCRIPTOR_EXTENSION_UNIT 0x09 +#define AC_DESCRIPTOR_CLOCK_SOURCE 0x0A +#define AC_DESCRIPTOR_CLOCK_SELECTOR 0x0B +#define AC_DESCRIPTOR_CLOCK_MULTIPLIER 0x0C +#define AC_DESCRIPTOR_SAMPLE_RATE_CONVERTER 0x0D + +/* A.10 Audio Class-Specific AS Interface Descriptor Subtypes */ +#define AS_DESCRIPTOR_UNDEFINED 0x00 +#define AS_DESCRIPTOR_GENERAL 0x01 +#define AS_DESCRIPTOR_FORMAT_TYPE 0x02 +#define AS_DESCRIPTOR_ENCODER 0x03 +#define AS_DESCRIPTOR_DECODER 0x04 + +/* Universal Serial Bus Device Class Definition for Audio Data Formats + * Release 2.0, May 31, 2006. A.1 Format Type Codes + * Values are in decimal to facilitate use with IS_EQ() macro. + */ +#define FORMAT_TYPE_UNDEFINED 0 +#define FORMAT_TYPE_I 1 +#define FORMAT_TYPE_II 2 +#define FORMAT_TYPE_III 3 +#define FORMAT_TYPE_IV 4 +#define EXT_FORMAT_TYPE_I 129 +#define EXT_FORMAT_TYPE_II 130 +#define EXT_FORMAT_TYPE_III 131 + +/* Automatically assign Entity IDs based on entities order in devicetree */ +#define ENTITY_ID(e) UTIL_INC(DT_NODE_CHILD_IDX(e)) + +/* Connected Entity ID or 0 if property is not defined. Rely on devicetree + * "required: true" to fail compilation if mandatory handle (e.g. clock source) + * is absent. + */ +#define CONNECTED_ENTITY_ID(entity, phandle) \ + COND_CODE_1(DT_NODE_HAS_PROP(entity, phandle), \ + (ENTITY_ID(DT_PHANDLE_BY_IDX(entity, phandle, 0))), (0)) + +#define ID_IF_TERMINAL_ASSOCIATES_WITH_TARGET(entity, target_id) \ + IF_ENABLED(UTIL_AND(IS_EQ( \ + CONNECTED_ENTITY_ID(entity, assoc_terminal), target_id), \ + UTIL_OR( \ + DT_NODE_HAS_COMPAT(entity, zephyr_uac2_input_terminal), \ + DT_NODE_HAS_COMPAT(entity, zephyr_uac2_output_terminal) \ + )), (ENTITY_ID(entity))) + +/* Find ID of terminal entity associated with given terminal entity. This macro + * evaluates to "+ 0" if there isn't any terminal entity associated. If there + * are terminal entities associated with given terminal, then the macro evalues + * to "IDs + 0" where IDs are the terminal entities ID separated by spaces. + * + * If there is exactly one ID then compiler will compute correct value. + * If there is more than one associated entity, then it will fail at build time + * (as it should) because the caller expects single integer. + */ +#define FIND_ASSOCIATED_TERMINAL(entity) \ + DT_FOREACH_CHILD_VARGS(DT_PARENT(entity), \ + ID_IF_TERMINAL_ASSOCIATES_WITH_TARGET, ENTITY_ID(entity)) + 0 + +/* If entity has assoc_terminal property, return the entity ID of associated + * terminal. Otherwise, search if any other terminal entity points to us and + * use its ID. If search yields no results then this evaluates to "+ 0" which + * matches the value USB Audio Class expects in bAssocTerminal if no association + * exists. + * + * This is a workaround for lack of cyclic dependencies support in devicetree. + */ +#define ASSOCIATED_TERMINAL_ID(entity) \ + COND_CODE_1(DT_NODE_HAS_PROP(entity, assoc_terminal), \ + (CONNECTED_ENTITY_ID(entity, assoc_terminal)), \ + (FIND_ASSOCIATED_TERMINAL(entity))) + + +#define CLOCK_SOURCE_ATTRIBUTES(entity) \ + (DT_ENUM_IDX(entity, clock_type)) | \ + (DT_PROP(entity, sof_synchronized) << 2) + +/* Control properties are optional enums in devicetree that can either be + * "read-only" or "host-programmable". If the property is missing, then it means + * that control is not present. Convert the control property into actual values + * used by USB Audio Class, i.e. 0b00 when control is not present, 0b01 when + * control is present but read-only and 0b11 when control can be programmed by + * host. Value 0b10 is not allowed by the specification. + */ +#define CONTROL_BITS(entity, control_name, bitshift) \ + COND_CODE_1(DT_NODE_HAS_PROP(entity, control_name), \ + (COND_CODE_0(DT_ENUM_IDX(entity, control_name), \ + ((0x1 << bitshift)) /* read-only */, \ + ((0x3 << bitshift)) /* host-programmable */)), \ + ((0x0 << bitshift)) /* control not present */) + +#define CLOCK_SOURCE_CONTROLS(entity) \ + CONTROL_BITS(entity, frequency_control, 0) | \ + CONTROL_BITS(entity, validity_control, 2) + +#define INPUT_TERMINAL_CONTROLS(entity) \ + CONTROL_BITS(entity, copy_protect_control, 0) | \ + CONTROL_BITS(entity, connector_control, 2) | \ + CONTROL_BITS(entity, overload_control, 4) | \ + CONTROL_BITS(entity, cluster_control, 6) | \ + CONTROL_BITS(entity, underflow_control, 8) | \ + CONTROL_BITS(entity, overflow_control, 10) + +#define OUTPUT_TERMINAL_CONTROLS(entity) \ + CONTROL_BITS(entity, copy_protect_control, 0) | \ + CONTROL_BITS(entity, connector_control, 2) | \ + CONTROL_BITS(entity, overload_control, 4) | \ + CONTROL_BITS(entity, underflow_control, 6) | \ + CONTROL_BITS(entity, overflow_control, 8) + +/* 4.1 Audio Channel Cluster Descriptor */ +#define SPATIAL_LOCATIONS_ARRAY(cluster) \ + DT_PROP(cluster, front_left), \ + DT_PROP(cluster, front_right), \ + DT_PROP(cluster, front_center), \ + DT_PROP(cluster, low_frequency_effects), \ + DT_PROP(cluster, back_left), \ + DT_PROP(cluster, back_right), \ + DT_PROP(cluster, front_left_of_center), \ + DT_PROP(cluster, front_right_of_center), \ + DT_PROP(cluster, back_center), \ + DT_PROP(cluster, side_left), \ + DT_PROP(cluster, side_right), \ + DT_PROP(cluster, top_center), \ + DT_PROP(cluster, top_front_left), \ + DT_PROP(cluster, top_front_center), \ + DT_PROP(cluster, top_front_right), \ + DT_PROP(cluster, top_back_left), \ + DT_PROP(cluster, top_back_center), \ + DT_PROP(cluster, top_back_right), \ + DT_PROP(cluster, top_front_left_of_center), \ + DT_PROP(cluster, top_front_right_of_center), \ + DT_PROP(cluster, left_low_frequency_effects), \ + DT_PROP(cluster, right_low_frequency_effects), \ + DT_PROP(cluster, top_side_left), \ + DT_PROP(cluster, top_side_right), \ + DT_PROP(cluster, bottom_center), \ + DT_PROP(cluster, back_left_of_center), \ + DT_PROP(cluster, back_right_of_center), \ + 0, 0, 0, 0, /* D27..D30: Reserved */ \ + DT_PROP(cluster, raw_data) + +#define SPATIAL_LOCATIONS_U32(entity) \ + (FOR_EACH_IDX(ARRAY_BIT, (|), SPATIAL_LOCATIONS_ARRAY(entity))) +#define NUM_SPATIAL_LOCATIONS(entity) \ + (FOR_EACH(IDENTITY, (+), SPATIAL_LOCATIONS_ARRAY(entity))) +#define SPATIAL_LOCATIONS(entity) U32_LE(SPATIAL_LOCATIONS_U32(entity)) + + +/* 4.7.2.1 Clock Source Descriptor */ +#define CLOCK_SOURCE_DESCRIPTOR(entity) \ + 0x08, /* bLength */ \ + CS_INTERFACE, /* bDescriptorType */ \ + AC_DESCRIPTOR_CLOCK_SOURCE, /* bDescriptorSubtype */\ + ENTITY_ID(entity), /* bClockID */ \ + CLOCK_SOURCE_ATTRIBUTES(entity), /* bmAttributes */ \ + CLOCK_SOURCE_CONTROLS(entity), /* bmControls */ \ + CONNECTED_ENTITY_ID(entity, assoc_terminal), /* bAssocTerminal */ \ + 0x00, /* iClockSource */ + +/* 4.7.2.4 Input Terminal Descriptor */ +#define INPUT_TERMINAL_DESCRIPTOR(entity) \ + 0x11, /* bLength */ \ + CS_INTERFACE, /* bDescriptorType */ \ + AC_DESCRIPTOR_INPUT_TERMINAL, /* bDescriptorSubtype */\ + ENTITY_ID(entity), /* bTerminalID */ \ + U16_LE(DT_PROP(entity, terminal_type)), /* wTerminalType */ \ + ASSOCIATED_TERMINAL_ID(entity), /* bAssocTerminal */ \ + CONNECTED_ENTITY_ID(entity, clock_source), /* bCSourceID */ \ + NUM_SPATIAL_LOCATIONS(entity), /* bNrChannels */ \ + SPATIAL_LOCATIONS(entity), /* bmChannelConfig */ \ + 0x00, /* iChannelNames */ \ + U16_LE(INPUT_TERMINAL_CONTROLS(entity)), /* bmControls */ \ + 0x00, /* iTerminal */ + +/* 4.7.2.5 Output Terminal Descriptor */ +#define OUTPUT_TERMINAL_DESCRIPTOR(entity) \ + 0x0C, /* bLength */ \ + CS_INTERFACE, /* bDescriptorType */ \ + AC_DESCRIPTOR_OUTPUT_TERMINAL, /* bDescriptorSubtype */\ + ENTITY_ID(entity), /* bTerminalID */ \ + U16_LE(DT_PROP(entity, terminal_type)), /* wTerminalType */ \ + ASSOCIATED_TERMINAL_ID(entity), /* bAssocTerminal */ \ + CONNECTED_ENTITY_ID(entity, data_source), /* bSourceID */ \ + CONNECTED_ENTITY_ID(entity, clock_source), /* bCSourceID */ \ + U16_LE(OUTPUT_TERMINAL_CONTROLS(entity)), /* bmControls */ \ + 0x00, /* iTerminal */ + +#define ENTITY_HEADER(entity) \ + IF_ENABLED(DT_NODE_HAS_COMPAT(entity, zephyr_uac2_clock_source), ( \ + CLOCK_SOURCE_DESCRIPTOR(entity) \ + )) \ + IF_ENABLED(DT_NODE_HAS_COMPAT(entity, zephyr_uac2_input_terminal), ( \ + INPUT_TERMINAL_DESCRIPTOR(entity) \ + )) \ + IF_ENABLED(DT_NODE_HAS_COMPAT(entity, zephyr_uac2_output_terminal), ( \ + OUTPUT_TERMINAL_DESCRIPTOR(entity) \ + )) + +#define ENTITY_HEADERS(node) DT_FOREACH_CHILD(node, ENTITY_HEADER) +#define ENTITY_HEADERS_LENGTH(node) sizeof((uint8_t []){ENTITY_HEADERS(node)}) + +#define AUDIO_STREAMING_CONTROLS(node) \ + CONTROL_BITS(entity, active_alternate_setting_control, 0) | \ + CONTROL_BITS(entity, valid_alternate_settings_control, 2) + +/* TODO: Support other format types. Currently the PCM format (0x00000001) is + * hardcoded and format type is either I or IV depending on whether the + * interface has isochronous endpoint or not. + */ +#define AUDIO_STREAMING_FORMAT_TYPE(node) \ + COND_CODE_0(DT_PROP(node, external_interface), \ + (FORMAT_TYPE_I), (FORMAT_TYPE_IV)) +#define AUDIO_STREAMING_FORMATS(node) U32_LE(0x00000001) + +/* If AudioStreaming is linked to input terminal, obtain the channel cluster + * configuration from the linked terminal. Otherwise (it has to be connected + * to output terminal) obtain the channel cluster configuration from data source + * entity. + */ +#define AUDIO_STREAMING_CHANNEL_CLUSTER(node) \ + IF_ENABLED(DT_NODE_HAS_COMPAT(DT_PROP(node, linked_terminal), \ + zephyr_uac2_input_terminal), ( \ + DT_PROP(node, linked_terminal) \ + )) \ + IF_ENABLED(DT_NODE_HAS_COMPAT(DT_PROP(node, linked_terminal), \ + zephyr_uac2_output_terminal), ( \ + DT_PROP(DT_PROP(node, linked_terminal), data_source) \ + )) + +#define AUDIO_STREAMING_NUM_SPATIAL_LOCATIONS(node) \ + NUM_SPATIAL_LOCATIONS(AUDIO_STREAMING_CHANNEL_CLUSTER(node)) +#define AUDIO_STREAMING_SPATIAL_LOCATIONS(node) \ + SPATIAL_LOCATIONS(AUDIO_STREAMING_CHANNEL_CLUSTER(node)) + +/* 4.9.2 Class-Specific AS Interface Descriptor */ +#define AUDIO_STREAMING_GENERAL_DESCRIPTOR(node) \ + 0x10, /* bLength */ \ + CS_INTERFACE, /* bDescriptorType */ \ + AS_DESCRIPTOR_GENERAL, /* bDescriptorSubtype */\ + CONNECTED_ENTITY_ID(node, linked_terminal), /* bTerminalLink */ \ + AUDIO_STREAMING_CONTROLS(node), /* bmControls*/ \ + AUDIO_STREAMING_FORMAT_TYPE(node), /* bFormatType */ \ + AUDIO_STREAMING_FORMATS(node), /* bmFormats */ \ + AUDIO_STREAMING_NUM_SPATIAL_LOCATIONS(node), /* bNrChannels */ \ + AUDIO_STREAMING_SPATIAL_LOCATIONS(node), /* bmChannelConfig */ \ + 0x00, /* iChannelNames */ + +/* Universal Serial Bus Device Class Definition for Audio Data Formats + * Release 2.0, May 31, 2006. 2.3.1.6 Type I Format Type Descriptor + */ +#define AUDIO_STREAMING_FORMAT_I_TYPE_DESCRIPTOR(node) \ + 0x06, /* bLength */ \ + CS_INTERFACE, /* bDescriptorType */ \ + AS_DESCRIPTOR_FORMAT_TYPE, /* bDescriptorSubtype */\ + FORMAT_TYPE_I, /* bFormatType */ \ + DT_PROP(node, subslot_size), /* bSubslotSize */ \ + DT_PROP(node, bit_resolution), /* bBitResolution */ + +/* Universal Serial Bus Device Class Definition for Audio Data Formats + * Release 2.0, May 31, 2006. 2.3.4.1 Type IV Format Type Descriptor + */ +#define AUDIO_STREAMING_FORMAT_IV_TYPE_DESCRIPTOR(node) \ + 0x04, /* bLength */ \ + CS_INTERFACE, /* bDescriptorType */ \ + AS_DESCRIPTOR_FORMAT_TYPE, /* bDescriptorSubtype */\ + FORMAT_TYPE_IV, /* bFormatType */ + +/* 4.9.3 Class-Specific AS Format Type Descriptor */ +#define AUDIO_STREAMING_FORMAT_TYPE_DESCRIPTOR(node) \ + IF_ENABLED(IS_EQ(AUDIO_STREAMING_FORMAT_TYPE(node), FORMAT_TYPE_I), ( \ + AUDIO_STREAMING_FORMAT_I_TYPE_DESCRIPTOR(node))) \ + IF_ENABLED(IS_EQ(AUDIO_STREAMING_FORMAT_TYPE(node), FORMAT_TYPE_IV), ( \ + AUDIO_STREAMING_FORMAT_IV_TYPE_DESCRIPTOR(node))) + +#define AUDIO_STREAMING_INTERFACE_DESCRIPTORS(node) \ + AUDIO_STREAMING_GENERAL_DESCRIPTOR(node) \ + AUDIO_STREAMING_FORMAT_TYPE_DESCRIPTOR(node) + +/* 4.7.2 Class-Specific AC Interface Descriptor */ +#define AC_INTERFACE_HEADER_DESCRIPTOR(node) \ + 0x09, /* bLength */ \ + CS_INTERFACE, /* bDescriptorType */ \ + AC_DESCRIPTOR_HEADER, /* bDescriptorSubtype */\ + U16_LE(0x0200), /* bcdADC */ \ + DT_PROP(node, audio_function), /* bCategory */ \ + U16_LE(9 + ENTITY_HEADERS_LENGTH(node)), /* wTotalLength */ \ + 0x00, /* bmControls */ \ + +#define VALIDATE_INPUT_TERMINAL_ASSOCIATION(entity) \ + UTIL_OR(UTIL_NOT(DT_NODE_HAS_PROP(entity, assoc_terminal)), \ + DT_NODE_HAS_COMPAT(DT_PROP(entity, assoc_terminal), \ + zephyr_uac2_output_terminal)) + +#define VALIDATE_OUTPUT_TERMINAL_ASSOCIATION(entity) \ + UTIL_OR(UTIL_NOT(DT_NODE_HAS_PROP(entity, assoc_terminal)), \ + DT_NODE_HAS_COMPAT(DT_PROP(entity, assoc_terminal), \ + zephyr_uac2_input_terminal)) + +#define NEEDS_SUBSLOT_SIZE_AND_BIT_RESOLUTION(node) UTIL_OR( \ + UTIL_OR(IS_EQ(AUDIO_STREAMING_FORMAT_TYPE(node), FORMAT_TYPE_I), \ + IS_EQ(AUDIO_STREAMING_FORMAT_TYPE(node), FORMAT_TYPE_III)), \ + UTIL_OR(IS_EQ(AUDIO_STREAMING_FORMAT_TYPE(node), EXT_FORMAT_TYPE_I), \ + IS_EQ(AUDIO_STREAMING_FORMAT_TYPE(node), EXT_FORMAT_TYPE_III))) + +#define VALIDATE_SUBSLOT_SIZE(node) \ + (DT_PROP(node, subslot_size) >= 1 && DT_PROP(node, subslot_size) <= 4) + +#define VALIDATE_BIT_RESOLUTION(node) \ + (DT_PROP(node, bit_resolution) <= (DT_PROP(node, subslot_size) * 8)) + +#define VALIDATE_LINKED_TERMINAL(node) \ + UTIL_OR(DT_NODE_HAS_COMPAT(DT_PROP(node, linked_terminal), \ + zephyr_uac2_input_terminal), \ + DT_NODE_HAS_COMPAT(DT_PROP(node, linked_terminal), \ + zephyr_uac2_output_terminal)) + +#define VALIDATE_NODE(node) \ + IF_ENABLED(DT_NODE_HAS_COMPAT(node, zephyr_uac2_clock_source), ( \ + BUILD_ASSERT(DT_PROP_LEN(node, sampling_frequencies), \ + "Sampling frequencies array must not be empty"); \ + BUILD_ASSERT(IS_ARRAY_SORTED(node, sampling_frequencies), \ + "Sampling frequencies array must be sorted ascending"); \ + )) \ + IF_ENABLED(DT_NODE_HAS_COMPAT(node, zephyr_uac2_input_terminal), ( \ + BUILD_ASSERT(!((SPATIAL_LOCATIONS_U32(node) & BIT(31))) || \ + SPATIAL_LOCATIONS_U32(node) == BIT(31), \ + "Raw Data set alongside other spatial locations"); \ + BUILD_ASSERT(VALIDATE_INPUT_TERMINAL_ASSOCIATION(node), \ + "Terminals associations must be Input<->Output"); \ + )) \ + IF_ENABLED(DT_NODE_HAS_COMPAT(node, zephyr_uac2_output_terminal), ( \ + BUILD_ASSERT(VALIDATE_OUTPUT_TERMINAL_ASSOCIATION(node), \ + "Terminals associations must be Input<->Output"); \ + )) \ + IF_ENABLED(DT_NODE_HAS_COMPAT(node, zephyr_uac2_audio_streaming), ( \ + BUILD_ASSERT(VALIDATE_LINKED_TERMINAL(node), \ + "Linked Terminal must be Input or Output Terminal"); \ + BUILD_ASSERT(!NEEDS_SUBSLOT_SIZE_AND_BIT_RESOLUTION(node) || \ + VALIDATE_SUBSLOT_SIZE(node), \ + "Subslot Size can only be 1, 2, 3 or 4"); \ + BUILD_ASSERT(!NEEDS_SUBSLOT_SIZE_AND_BIT_RESOLUTION(node) || \ + VALIDATE_BIT_RESOLUTION(node), \ + "Bit Resolution must fit inside Subslot Size"); \ + )) + +#endif /* ZEPHYR_INCLUDE_USBD_UAC2_MACROS_H_ */ From a825147d0cf0f45df70a3f6f7532db1182b74222 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tomasz=20Mo=C5=84?= Date: Thu, 30 Nov 2023 12:51:55 +0100 Subject: [PATCH 1297/3723] tests: usb: uac2: test descriptor macros MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Compare devicetree generated class specific descriptors for headset example against reference hex values. Signed-off-by: Tomasz Moń --- tests/subsys/usb/uac2/CMakeLists.txt | 12 ++ tests/subsys/usb/uac2/app.overlay | 74 ++++++++++++ tests/subsys/usb/uac2/prj.conf | 1 + tests/subsys/usb/uac2/src/uac2_desc.c | 159 ++++++++++++++++++++++++++ tests/subsys/usb/uac2/testcase.yaml | 9 ++ 5 files changed, 255 insertions(+) create mode 100644 tests/subsys/usb/uac2/CMakeLists.txt create mode 100644 tests/subsys/usb/uac2/app.overlay create mode 100644 tests/subsys/usb/uac2/prj.conf create mode 100644 tests/subsys/usb/uac2/src/uac2_desc.c create mode 100644 tests/subsys/usb/uac2/testcase.yaml diff --git a/tests/subsys/usb/uac2/CMakeLists.txt b/tests/subsys/usb/uac2/CMakeLists.txt new file mode 100644 index 00000000000..18471c2037a --- /dev/null +++ b/tests/subsys/usb/uac2/CMakeLists.txt @@ -0,0 +1,12 @@ +# SPDX-License-Identifier: Apache-2.0 + +cmake_minimum_required(VERSION 3.20.0) +find_package(Zephyr REQUIRED HINTS $ENV{ZEPHYR_BASE}) +project(uac2) + +zephyr_library_include_directories( + ${ZEPHYR_BASE}/subsys/usb/device_next/class + ) + +FILE(GLOB app_sources src/*.c) +target_sources(app PRIVATE ${app_sources}) diff --git a/tests/subsys/usb/uac2/app.overlay b/tests/subsys/usb/uac2/app.overlay new file mode 100644 index 00000000000..3cafb19a00e --- /dev/null +++ b/tests/subsys/usb/uac2/app.overlay @@ -0,0 +1,74 @@ +/* + * Copyright (c) 2023 Nordic Semiconductor ASA + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include + +/ { + uac2_headset: usb_audio2 { + compatible = "zephyr,uac2"; + status = "okay"; + audio-function = ; + + uac_aclk: aclk { + compatible = "zephyr,uac2-clock-source"; + clock-type = "internal-programmable"; + frequency-control = "host-programmable"; + sampling-frequencies = <48000>; + }; + + out_terminal: out_terminal { + compatible = "zephyr,uac2-input-terminal"; + clock-source = <&uac_aclk>; + terminal-type = ; + front-left; + front-right; + }; + + headphones_output: headphones { + compatible = "zephyr,uac2-output-terminal"; + data-source = <&out_terminal>; + clock-source = <&uac_aclk>; + terminal-type = ; + assoc-terminal = <&mic_input>; + }; + + mic_input: microphone { + compatible = "zephyr,uac2-input-terminal"; + clock-source = <&uac_aclk>; + terminal-type = ; + /* Circular reference, macros will figure it out and + * provide correct associated terminal ID because the + * terminals associations are always 1-to-1. + * + * assoc-terminal = <&headphones_output>; + */ + front-left; + }; + + in_terminal: in_terminal { + compatible = "zephyr,uac2-output-terminal"; + data-source = <&mic_input>; + clock-source = <&uac_aclk>; + terminal-type = ; + }; + + as_iso_out: out_interface { + compatible = "zephyr,uac2-audio-streaming"; + linked-terminal = <&out_terminal>; + implicit-feedback; + subslot-size = <2>; + bit-resolution = <16>; + }; + + as_iso_in: in_interface { + compatible = "zephyr,uac2-audio-streaming"; + linked-terminal = <&in_terminal>; + implicit-feedback; + subslot-size = <2>; + bit-resolution = <16>; + }; + }; +}; diff --git a/tests/subsys/usb/uac2/prj.conf b/tests/subsys/usb/uac2/prj.conf new file mode 100644 index 00000000000..9467c292689 --- /dev/null +++ b/tests/subsys/usb/uac2/prj.conf @@ -0,0 +1 @@ +CONFIG_ZTEST=y diff --git a/tests/subsys/usb/uac2/src/uac2_desc.c b/tests/subsys/usb/uac2/src/uac2_desc.c new file mode 100644 index 00000000000..d1645e0ad3b --- /dev/null +++ b/tests/subsys/usb/uac2/src/uac2_desc.c @@ -0,0 +1,159 @@ +/* + * Copyright (c) 2023 Nordic Semiconductor ASA + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include + +#include + +static const uint8_t reference_ac_descriptors[] = { + /* 4.7.2 Class-Specific AC Interface Descriptor */ + 0x09, /* bLength = 9 */ + 0x24, /* bDescriptorType = CS_INTERFACE */ + 0x01, /* bDescriptorSubtype = HEADER */ + 0x00, 0x02, /* bcdADC = 02.00 */ + 0x04, /* bCategory = HEADSET */ + 0x4b, 0x00, /* wTotalLength = 0x4b = 75 */ + 0x00, /* bmControls = Latency Control not present */ + /* 4.7.2.1 Clock Source Descriptor */ + 0x08, /* bLength = 8 */ + 0x24, /* bDescriptorType = CS_INTERFACE */ + 0x0a, /* bDescriptorSubtype = CLOCK_SOURCE */ + 0x01, /* bClockID = 1 */ + 0x03, /* bmAttributes = Internal programmable */ + 0x03, /* bmControls = frequency host programmable */ + 0x00, /* bAssocTerminal = 0 (not associated) */ + 0x00, /* iClockSource = 0 (no string descriptor) */ + /* 4.7.2.4 Input Terminal Descriptor */ + 0x11, /* bLength = 17 */ + 0x24, /* bDescriptorType = CS_INTERFACE */ + 0x02, /* bDescriptorSubtype = INPUT_TERMINAL */ + 0x02, /* bTerminalID = 2 */ + 0x01, 0x01, /* wTerminalType = 0x0101 (USB streaming) */ + 0x00, /* bAssocTerminal = 0 (not associated) */ + 0x01, /* bCSourceID = 1 (main clock) */ + 0x02, /* bNrChannels = 2 */ + 0x03, 0x00, 0x00, 0x00, /* bmChannelConfig = Front Left, Front Right */ + 0x00, /* iChannelNames = 0 (all pre-defined) */ + 0x00, 0x00, /* bmControls = none present */ + 0x00, /* iTerminal = 0 (no string descriptor) */ + /* 4.7.2.5 Output Terminal Descriptor */ + 0x0c, /* bLength = 12 */ + 0x24, /* bDescriptorType = CS_INTERFACE */ + 0x03, /* bDescriptorSubtype = OUTPUT_TERMINAL */ + 0x03, /* bTerminalID = 3 */ + 0x02, 0x04, /* wTerminalType = 0x0402 (Headset) */ + 0x04, /* bAssocTerminal = 4 (headset input) */ + 0x02, /* bSourceID = 2 (streaming input) */ + 0x01, /* bCSourceID = 1 (main clock) */ + 0x00, 0x00, /* bmControls = none present */ + 0x00, /* iTerminal = 0 (no string descriptor) */ + /* 4.7.2.4 Input Terminal Descriptor */ + 0x11, /* bLength = 17 */ + 0x24, /* bDescriptorType = CS_INTERFACE */ + 0x02, /* bDescriptorSubtype = INPUT_TERMINAL */ + 0x04, /* bTerminalID = 4 */ + 0x02, 0x04, /* wTerminalType = 0x0402 (Headset) */ + 0x03, /* bAssocTerminal = 3 (headset output) */ + 0x01, /* bCSourceID = 1 (main clock) */ + 0x01, /* bNrChannels = 1 */ + 0x01, 0x00, 0x00, 0x00, /* bmChannelConfig = Front Left */ + 0x00, /* iChannelNames = 0 (all pre-defined) */ + 0x00, 0x00, /* bmControls = none present */ + 0x00, /* iTerminal = 0 (no string descriptor) */ + /* 4.7.2.5 Output Terminal Descriptor */ + 0x0c, /* bLength = 12 */ + 0x24, /* bDescriptorType = CS_INTERFACE */ + 0x03, /* bDescriptorSubtype = OUTPUT_TERMINAL */ + 0x05, /* bTerminalID = 5 */ + 0x01, 0x01, /* wTerminalType = 0x0101 (USB streaming) */ + 0x00, /* bAssocTerminal = 0 (not associated) */ + 0x04, /* bSourceID = 4 (headset input) */ + 0x01, /* bCSourceID = 1 (main clock) */ + 0x00, 0x00, /* bmControls = none present */ + 0x00, /* iTerminal = 0 (no string descriptor) */ +}; + +/* USB IN = Audio device streaming output */ +static const uint8_t reference_as_in_descriptors[] = { + /* 4.9.2 Class-Specific AS Interface Descriptor */ + 0x10, /* bLength = 16 */ + 0x24, /* bDescriptorType = CS_INTERFACE */ + 0x01, /* bDescriptorSubtype = AS_GENERAL */ + 0x05, /* bTerminalLink = 5 (USB streaming output) */ + 0x00, /* bmControls = non present */ + 0x01, /* bFormatType = 1 */ + 0x01, 0x00, 0x00, 0x00, /* bmFormats = PCM */ + 0x01, /* bNrChannels = 1 */ + 0x01, 0x00, 0x00, 0x00, /* bmChannelConfig = Front Left */ + 0x00, /* iChannelNames = 0 (all pre-defined) */ + /* Universal Serial Bus Device Class Definition for Audio Data Formats + * Release 2.0, May 31, 2006. 2.3.1.6 Type I Format Type Descriptor + */ + 0x06, /* bLength = 6 */ + 0x24, /* bDescriptorType = CS_INTERFACE */ + 0x02, /* bDescriptorSubtype = FORMAT_TYPE */ + 0x01, /* bFormatType = 1 */ + 0x02, /* bSubslotSize = 2 */ + 0x10, /* bBitResolution = 16 */ +}; + +/* USB OUT = Audio device streaming input */ +static const uint8_t reference_as_out_descriptors[] = { + /* 4.9.2 Class-Specific AS Interface Descriptor */ + 0x10, /* bLength = 16 */ + 0x24, /* bDescriptorType = CS_INTERFACE */ + 0x01, /* bDescriptorSubtype = AS_GENERAL */ + 0x02, /* bTerminalLink = 2 (USB streaming input) */ + 0x00, /* bmControls = non present */ + 0x01, /* bFormatType = 1 */ + 0x01, 0x00, 0x00, 0x00, /* bmFormats = PCM */ + 0x02, /* bNrChannels = 2 */ + 0x03, 0x00, 0x00, 0x00, /* bmChannelConfig = Front Left, Front Right */ + 0x00, /* iChannelNames = 0 (all pre-defined) */ + /* Universal Serial Bus Device Class Definition for Audio Data Formats + * Release 2.0, May 31, 2006. 2.3.1.6 Type I Format Type Descriptor + */ + 0x06, /* bLength = 6 */ + 0x24, /* bDescriptorType = CS_INTERFACE */ + 0x02, /* bDescriptorSubtype = FORMAT_TYPE */ + 0x01, /* bFormatType = 1 */ + 0x02, /* bSubslotSize = 2 */ + 0x10, /* bBitResolution = 16 */ +}; + +DT_FOREACH_CHILD(DT_NODELABEL(uac2_headset), VALIDATE_NODE) + +static const uint8_t generated_ac_descriptors[] = { + AC_INTERFACE_HEADER_DESCRIPTOR(DT_NODELABEL(uac2_headset)) + ENTITY_HEADERS(DT_NODELABEL(uac2_headset)) +}; + +static const uint8_t generated_as_in_descriptors[] = { + AUDIO_STREAMING_INTERFACE_DESCRIPTORS(DT_NODELABEL(as_iso_in)) +}; + +static const uint8_t generated_as_out_descriptors[] = { + AUDIO_STREAMING_INTERFACE_DESCRIPTORS(DT_NODELABEL(as_iso_out)) +}; + +ZTEST(uac2_desc, test_audiocontrol_descriptors) +{ + zassert_mem_equal(reference_ac_descriptors, generated_ac_descriptors, + ARRAY_SIZE(reference_ac_descriptors)); +} + +ZTEST(uac2_desc, test_audiostreaming_descriptors) +{ + zassert_mem_equal(reference_as_in_descriptors, + generated_as_in_descriptors, + ARRAY_SIZE(reference_as_in_descriptors)); + + zassert_mem_equal(reference_as_out_descriptors, + generated_as_out_descriptors, + ARRAY_SIZE(reference_as_out_descriptors)); +} + +ZTEST_SUITE(uac2_desc, NULL, NULL, NULL, NULL, NULL); diff --git a/tests/subsys/usb/uac2/testcase.yaml b/tests/subsys/usb/uac2/testcase.yaml new file mode 100644 index 00000000000..11a8657220a --- /dev/null +++ b/tests/subsys/usb/uac2/testcase.yaml @@ -0,0 +1,9 @@ +tests: + usb.uac2: + depends_on: usb_device + tags: usb + platform_allow: + - native_sim + - qemu_cortex_m3 + integration_platforms: + - native_sim From 3e7368829b0dc642cce4e17475d3c96629d5ce86 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tomasz=20Mo=C5=84?= Date: Tue, 5 Dec 2023 13:44:57 +0100 Subject: [PATCH 1298/3723] usb: device_next: uac2: interface descriptor macros MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Add macros to initialize full set of descriptors required for USB Audio Class 2 instance. Descriptors start with Interface Association Descriptor that binds together the AudioControl interface and all AudioStreaming interfaces. AudioStreaming interfaces have alternate setting 0 without any endpoints and alternate setting 1 with isochronous endpoint with max packet size calculated on maximum sample frequency, number of channels, subslot size and clock synchronization (asynchronous endpoints require +1 sample). Signed-off-by: Tomasz Moń --- .../usb/device_next/class/usbd_uac2_macros.h | 308 ++++++++++++++++++ tests/subsys/usb/uac2/src/uac2_desc.c | 159 +++++++++ 2 files changed, 467 insertions(+) diff --git a/subsys/usb/device_next/class/usbd_uac2_macros.h b/subsys/usb/device_next/class/usbd_uac2_macros.h index ec4ecd1008e..3160dd13433 100644 --- a/subsys/usb/device_next/class/usbd_uac2_macros.h +++ b/subsys/usb/device_next/class/usbd_uac2_macros.h @@ -11,6 +11,7 @@ */ #include +#include #ifndef ZEPHYR_INCLUDE_USBD_UAC2_MACROS_H_ #define ZEPHYR_INCLUDE_USBD_UAC2_MACROS_H_ @@ -32,6 +33,33 @@ #define IS_ARRAY_SORTED(node, prop) \ DT_FOREACH_PROP_ELEM_SEP(node, prop, ARRAY_ELEMENT_LESS_THAN_NEXT, (&&)) +#define FIRST_INTERFACE_NUMBER 0x00 +#define FIRST_IN_EP_ADDR 0x81 +#define FIRST_OUT_EP_ADDR 0x01 + +/* A.1 Audio Function Class Code */ +#define AUDIO_FUNCTION AUDIO + +/* A.2 Audio Function Subclass Codes */ +#define FUNCTION_SUBCLASS_UNDEFINED 0x00 + +/* A.3 Audio Function Protocol Codes */ +#define FUNCTION_PROTOCOL_UNDEFINED 0x00 +#define AF_VERSION_02_00 IP_VERSION_02_00 + +/* A.4 Audio Interface Class Code */ +#define AUDIO 0x01 + +/* A.5 Audio Interface Subclass Codes */ +#define INTERFACE_SUBCLASS_UNDEFINED 0x00 +#define AUDIOCONTROL 0x01 +#define AUDIOSTREAMING 0x02 +#define MIDISTREAMING 0x03 + +/* A.6 Audio Interface Protocol Codes */ +#define INTERFACE_PROTOCOL_UNDEFINED 0x00 +#define IP_VERSION_02_00 0x20 + /* A.8 Audio Class-Specific Descriptor Types */ #define CS_UNDEFINED 0x20 #define CS_DEVICE 0x21 @@ -63,6 +91,10 @@ #define AS_DESCRIPTOR_ENCODER 0x03 #define AS_DESCRIPTOR_DECODER 0x04 +/* A.13 Audio Class-Specific Endpoint Descriptor Subtypes */ +#define DESCRIPTOR_UNDEFINED 0x00 +#define EP_GENERAL 0x01 + /* Universal Serial Bus Device Class Definition for Audio Data Formats * Release 2.0, May 31, 2006. A.1 Format Type Codes * Values are in decimal to facilitate use with IS_EQ() macro. @@ -159,6 +191,11 @@ CONTROL_BITS(entity, underflow_control, 6) | \ CONTROL_BITS(entity, overflow_control, 8) +#define AUDIO_STREAMING_DATA_ENDPOINT_CONTROLS(node) \ + CONTROL_BITS(node, pitch_control, 0) | \ + CONTROL_BITS(node, data_overrun_control, 2) | \ + CONTROL_BITS(node, data_underrun_control, 4) + /* 4.1 Audio Channel Cluster Descriptor */ #define SPATIAL_LOCATIONS_ARRAY(cluster) \ DT_PROP(cluster, front_left), \ @@ -338,6 +375,274 @@ U16_LE(9 + ENTITY_HEADERS_LENGTH(node)), /* wTotalLength */ \ 0x00, /* bmControls */ \ +#define IS_AUDIOSTREAMING_INTERFACE(node) \ + DT_NODE_HAS_COMPAT(node, zephyr_uac2_audio_streaming) + +#define UAC2_NUM_INTERFACES(node) \ + 1 /* AudioControl interface */ + \ + DT_FOREACH_CHILD_SEP(node, IS_AUDIOSTREAMING_INTERFACE, (+)) + +/* 4.6 Interface Association Descriptor */ +#define UAC2_INTERFACE_ASSOCIATION_DESCRIPTOR(node) \ + 0x08, /* bLength */ \ + USB_DESC_INTERFACE_ASSOC, /* bDescriptorType */ \ + FIRST_INTERFACE_NUMBER, /* bFirstInterface */ \ + UAC2_NUM_INTERFACES(node), /* bInterfaceCount */ \ + AUDIO_FUNCTION, /* bFunctionClass */ \ + FUNCTION_SUBCLASS_UNDEFINED, /* bFunctionSubclass */ \ + AF_VERSION_02_00, /* bFunctionProtocol */ \ + 0x00, /* iFunction */ + +/* 4.7.1 Standard AC Interface Descriptor */ +#define AC_INTERFACE_DESCRIPTOR(node) \ + 0x09, /* bLength */ \ + USB_DESC_INTERFACE, /* bDescriptorType */ \ + FIRST_INTERFACE_NUMBER, /* bInterfaceNumber */ \ + 0x00, /* bAlternateSetting */ \ + DT_PROP(node, interrupt_endpoint), /* bNumEndpoints */ \ + AUDIO, /* bInterfaceClass */ \ + AUDIOCONTROL, /* bInterfaceSubClass */\ + IP_VERSION_02_00, /* bInterfaceProtocol */\ + 0x00, /* iInterface */ + +/* 4.8.2.1 Standard AC Interrupt Endpoint Descriptor */ +#define AC_ENDPOINT_DESCRIPTOR(node) \ + 0x07, /* bLength */ \ + USB_DESC_ENDPOINT, /* bDescriptorType */ \ + FIRST_IN_EP_ADDR, /* bEndpointAddress */ \ + USB_EP_TYPE_INTERRUPT, /* bmAttributes */ \ + 0x06, /* wMaxPacketSize */ \ + 0x01, /* bInterval */ \ + +#define FIND_AUDIOSTREAMING(node, fn, ...) \ + IF_ENABLED(DT_NODE_HAS_COMPAT(node, zephyr_uac2_audio_streaming), ( \ + fn(node, __VA_ARGS__))) + +#define FOR_EACH_AUDIOSTREAMING_INTERFACE(node, fn, ...) \ + DT_FOREACH_CHILD_VARGS(node, FIND_AUDIOSTREAMING, fn, __VA_ARGS__) + +#define COUNT_AS_INTERFACES_BEFORE_IDX(node, idx) \ + + 1 * (DT_NODE_CHILD_IDX(node) < idx) + +#define AS_INTERFACE_NUMBER(node) \ + FIRST_INTERFACE_NUMBER + 1 /* AudioControl interface */ + \ + FOR_EACH_AUDIOSTREAMING_INTERFACE(DT_PARENT(node), \ + COUNT_AS_INTERFACES_BEFORE_IDX, DT_NODE_CHILD_IDX(node)) + +#define AS_HAS_ISOCHRONOUS_DATA_ENDPOINT(node) \ + UTIL_NOT(DT_PROP(node, external_interface)) + +#define AS_IS_USB_ISO_IN(node) \ + UTIL_AND(AS_HAS_ISOCHRONOUS_DATA_ENDPOINT(node), \ + DT_NODE_HAS_COMPAT(DT_PROP(node, linked_terminal), \ + zephyr_uac2_output_terminal)) + +#define AS_IS_USB_ISO_OUT(node) \ + UTIL_AND(AS_HAS_ISOCHRONOUS_DATA_ENDPOINT(node), \ + DT_NODE_HAS_COMPAT(DT_PROP(node, linked_terminal), \ + zephyr_uac2_input_terminal)) + +#define CLK_IS_SOF_SYNCHRONIZED(entity) \ + IF_ENABLED(DT_NODE_HAS_COMPAT(entity, zephyr_uac2_clock_source), ( \ + DT_PROP(entity, sof_synchronized) \ + )) + +/* Sampling frequencies are sorted (asserted at compile time), so just grab + * last sampling frequency. + */ +#define CLK_MAX_FREQUENCY(entity) \ + IF_ENABLED(DT_NODE_HAS_COMPAT(entity, zephyr_uac2_clock_source), ( \ + DT_PROP_BY_IDX(entity, sampling_frequencies, \ + UTIL_DEC(DT_PROP_LEN(entity, sampling_frequencies))) \ + )) + +#define AS_CLK_SOURCE(node) \ + DT_PROP(DT_PROP(node, linked_terminal), clock_source) + +#define AS_CLK_MAX_FREQUENCY(node) \ + CLK_MAX_FREQUENCY(AS_CLK_SOURCE(node)) + +#define AS_IS_SOF_SYNCHRONIZED(node) \ + CLK_IS_SOF_SYNCHRONIZED(AS_CLK_SOURCE(node)) + +#define AS_HAS_EXPLICIT_FEEDBACK_ENDPOINT(node) \ + UTIL_AND(UTIL_AND(AS_HAS_ISOCHRONOUS_DATA_ENDPOINT(node), \ + UTIL_NOT(DT_PROP(node, implicit_feedback))), \ + UTIL_AND(UTIL_NOT(AS_IS_SOF_SYNCHRONIZED(node)), \ + AS_IS_USB_ISO_OUT(node))) + +#define AS_INTERFACE_NUM_ENDPOINTS(node) \ + (AS_HAS_ISOCHRONOUS_DATA_ENDPOINT(node) + \ + AS_HAS_EXPLICIT_FEEDBACK_ENDPOINT(node)) + +/* 4.9.1 Standard AS Interface Descriptor */ +#define AS_INTERFACE_DESCRIPTOR(node, alternate, numendpoints) \ + 0x09, /* bLength */ \ + USB_DESC_INTERFACE, /* bDescriptorType */ \ + AS_INTERFACE_NUMBER(node), /* bInterfaceNumber */ \ + alternate, /* bAlternateSetting */ \ + numendpoints, /* bNumEndpoints */ \ + AUDIO, /* bInterfaceClass */ \ + AUDIOSTREAMING, /* bInterfaceSubClass */\ + IP_VERSION_02_00, /* bInterfaceProtocol */\ + 0x00, /* iInterface */ + +#define COUNT_AS_OUT_ENDPOINTS_BEFORE_IDX(node, idx) \ + + AS_IS_USB_ISO_OUT(node) * (DT_NODE_CHILD_IDX(node) < idx) + +#define COUNT_AS_IN_ENDPOINTS_BEFORE_IDX(node, idx) \ + + (AS_IS_USB_ISO_IN(node) + AS_HAS_EXPLICIT_FEEDBACK_ENDPOINT(node)) \ + * (DT_NODE_CHILD_IDX(node) < idx) + +/* FIXME: Ensure that the explicit feedback endpoints assignments match + * numbering requirements from Universal Serial Bus Specification Revision 2.0 + * 9.6.6 Endpoint. This FIXME is not limited to the macros here but also to + * actual USB stack endpoint fixup (so the fixup does not break the numbering). + * + * This FIXME does not affect nRF52 and nRF53 when implicit feedback is used + * because the endpoints after fixup will be 0x08 and 0x88 because there are + * only two isochronous endpoints on these devices (one IN, one OUT). + */ +#define AS_NEXT_OUT_EP_ADDR(node) \ + FIRST_OUT_EP_ADDR + \ + FOR_EACH_AUDIOSTREAMING_INTERFACE(DT_PARENT(node), \ + COUNT_AS_OUT_ENDPOINTS_BEFORE_IDX, DT_NODE_CHILD_IDX(node)) + +#define AS_NEXT_IN_EP_ADDR(node) \ + FIRST_IN_EP_ADDR + DT_PROP(DT_PARENT(node), interrupt_endpoint) + \ + FOR_EACH_AUDIOSTREAMING_INTERFACE(DT_PARENT(node), \ + COUNT_AS_IN_ENDPOINTS_BEFORE_IDX, DT_NODE_CHILD_IDX(node)) + +#define AS_DATA_EP_ADDR(node) \ + COND_CODE_1(AS_IS_USB_ISO_OUT(node), \ + (AS_NEXT_OUT_EP_ADDR(node)), \ + (AS_NEXT_IN_EP_ADDR(node))) + +#define AS_BYTES_PER_SAMPLE(node) \ + DT_PROP(node, subslot_size) + +/* Asynchronous endpoints needs space for 1 extra sample */ +#define AS_SAMPLES_PER_PACKET(node) \ + ((ROUND_UP(AS_CLK_MAX_FREQUENCY(node), 1000) / 1000) + \ + UTIL_NOT(AS_IS_SOF_SYNCHRONIZED(node))) + +#define AS_DATA_EP_SYNC_TYPE(node) \ + COND_CODE_1(AS_IS_SOF_SYNCHRONIZED(node), (0x3 << 2), (0x1 << 2)) + +#define AS_DATA_EP_USAGE_TYPE(node) \ + COND_CODE_1(UTIL_AND(DT_PROP(node, implicit_feedback), \ + UTIL_NOT(AS_IS_USB_ISO_OUT(node))), (0x2 << 4), (0x0 << 4)) + +#define AS_DATA_EP_ATTR(node) \ + USB_EP_TYPE_ISO | AS_DATA_EP_SYNC_TYPE(node) | \ + AS_DATA_EP_USAGE_TYPE(node) + +#define AS_DATA_EP_MAX_PACKET_SIZE(node) \ + AUDIO_STREAMING_NUM_SPATIAL_LOCATIONS(node) * \ + AS_BYTES_PER_SAMPLE(node) * AS_SAMPLES_PER_PACKET(node) + +/* 4.10.1.1 Standard AS Isochronous Audio Data Endpoint Descriptor */ +#define STANDARD_AS_ISOCHRONOUS_DATA_ENDPOINT_DESCRIPTOR(node) \ + 0x07, /* bLength */ \ + USB_DESC_ENDPOINT, /* bDescriptorType */ \ + AS_DATA_EP_ADDR(node), /* bEndpointAddress */ \ + AS_DATA_EP_ATTR(node), /* bmAttributes */ \ + U16_LE(AS_DATA_EP_MAX_PACKET_SIZE(node)), /* wMaxPacketSize */ \ + 0x01, /* bInterval */ + +#define LOCK_DELAY_UNITS(node) \ + COND_CODE_1(DT_NODE_HAS_PROP(node, lock_delay_units), \ + (1 + DT_ENUM_IDX(node, lock_delay_units)), \ + (0 /* Undefined */)) + +/* 4.10.1.2 Class-Specific AS Isochronous Audio Data Endpoint Descriptor */ +#define CLASS_SPECIFIC_AS_ISOCHRONOUS_DATA_ENDPOINT_DESCRIPTOR(node) \ + 0x08, /* bLength */ \ + CS_ENDPOINT, /* bDescriptorType */ \ + EP_GENERAL, /* bDescriptorSubtype */\ + 0x00, /* bmAttributes */ \ + AUDIO_STREAMING_DATA_ENDPOINT_CONTROLS(node), /* bmControls */ \ + LOCK_DELAY_UNITS(node), /* bLockDelayUnits */ \ + U16_LE(DT_PROP_OR(node, lock_delay, 0)), /* wLockDelay */ + +#define AS_ISOCHRONOUS_DATA_ENDPOINT_DESCRIPTORS(node) \ + STANDARD_AS_ISOCHRONOUS_DATA_ENDPOINT_DESCRIPTOR(node) \ + CLASS_SPECIFIC_AS_ISOCHRONOUS_DATA_ENDPOINT_DESCRIPTOR(node) + +#define AS_EXPLICIT_FEEDBACK_ENDPOINT_DESCRIPTOR(node) \ + 0x07, /* bLength */ \ + USB_DESC_ENDPOINT, /* bDescriptorType */ \ + AS_NEXT_IN_EP_ADDR(node), /* bEndpointAddress */ \ + 0x11, /* bmAttributes */ \ + U16_LE(0x03), /* FIXME: 4 on High-Speed*/ /* wMaxPacketSize */ \ + 0x01, /* TODO: adjust to P 5.12.4.2 Feedback */ /* bInterval */ + +#define AS_DESCRIPTORS(node) \ + AS_INTERFACE_DESCRIPTOR(node, 0, 0) \ + IF_ENABLED(AS_HAS_ISOCHRONOUS_DATA_ENDPOINT(node), ( \ + AS_INTERFACE_DESCRIPTOR(node, 1, \ + AS_INTERFACE_NUM_ENDPOINTS(node)))) \ + AUDIO_STREAMING_INTERFACE_DESCRIPTORS(node) \ + IF_ENABLED(AS_HAS_ISOCHRONOUS_DATA_ENDPOINT(node), ( \ + AS_ISOCHRONOUS_DATA_ENDPOINT_DESCRIPTORS(node) \ + IF_ENABLED(AS_HAS_EXPLICIT_FEEDBACK_ENDPOINT(node), ( \ + AS_EXPLICIT_FEEDBACK_ENDPOINT_DESCRIPTOR(node))) \ + )) + +#define AS_DESCRIPTORS_IF_AUDIOSTREAMING(node) \ + IF_ENABLED(DT_NODE_HAS_COMPAT(node, zephyr_uac2_audio_streaming), ( \ + AS_DESCRIPTORS(node))) + +#define UAC2_AUDIO_CONTROL_DESCRIPTORS(node) \ + AC_INTERFACE_DESCRIPTOR(node) \ + AC_INTERFACE_HEADER_DESCRIPTOR(node) \ + ENTITY_HEADERS(node) \ + IF_ENABLED(DT_PROP(node, interrupt_endpoint), ( \ + AC_ENDPOINT_DESCRIPTOR(node))) + +#define UAC2_DESCRIPTORS(node) \ + UAC2_INTERFACE_ASSOCIATION_DESCRIPTOR(node) \ + UAC2_AUDIO_CONTROL_DESCRIPTORS(node) \ + DT_FOREACH_CHILD(node, AS_DESCRIPTORS_IF_AUDIOSTREAMING) + + +/* Helper macros to determine endpoint offset within complete UAC2 blob */ +#define COUNT_AS_DESCRIPTORS_BYTES_UP_TO_IDX(node, idx) \ + (sizeof((uint8_t []){AS_DESCRIPTORS_IF_AUDIOSTREAMING(node)}) * \ + (DT_NODE_CHILD_IDX(node) <= idx)) + +#define UAC2_DESCRIPTOR_AS_DESC_END_OFFSET(node) \ + (sizeof((uint8_t []){ \ + UAC2_INTERFACE_ASSOCIATION_DESCRIPTOR(DT_PARENT(node)) \ + UAC2_AUDIO_CONTROL_DESCRIPTORS(DT_PARENT(node)) \ + })) + DT_FOREACH_CHILD_SEP_VARGS(DT_PARENT(node), \ + COUNT_AS_DESCRIPTORS_BYTES_UP_TO_IDX, (+), \ + DT_NODE_CHILD_IDX(node)) + +#define AS_ISOCHRONOUS_DATA_ENDPOINT_DESCRIPTORS_SIZE(node) \ + (sizeof((uint8_t []) {AS_ISOCHRONOUS_DATA_ENDPOINT_DESCRIPTORS(node)})) + +#define AS_EXPLICIT_FEEDBACK_ENDPOINT_DESCRIPTOR_SIZE(node) \ + COND_CODE_1(AS_HAS_EXPLICIT_FEEDBACK_ENDPOINT(node), \ + (sizeof((uint8_t []) { \ + AS_EXPLICIT_FEEDBACK_ENDPOINT_DESCRIPTOR(node) \ + })), (0)) + +/* Return offset inside UAC2_DESCRIPTORS(DT_PARENT(node)) poiting to data + * endpoint address belonging to given AudioStreaming interface node. + * + * It is programmer error to call this macro with node other than AudioStreaming + * or when AS_HAS_ISOCHRONOUS_DATA_ENDPOINT(node) is 0. + */ +#define UAC2_DESCRIPTOR_AS_DATA_EP_OFFSET(node) \ + UAC2_DESCRIPTOR_AS_DESC_END_OFFSET(node) \ + - AS_EXPLICIT_FEEDBACK_ENDPOINT_DESCRIPTOR_SIZE(node) \ + - AS_ISOCHRONOUS_DATA_ENDPOINT_DESCRIPTORS_SIZE(node) \ + + offsetof(struct usb_ep_descriptor, bEndpointAddress) + +/* Helper macros to validate USB Audio Class 2 devicetree entries. + * Macros above do rely on the assumptions checked below. + */ #define VALIDATE_INPUT_TERMINAL_ASSOCIATION(entity) \ UTIL_OR(UTIL_NOT(DT_NODE_HAS_PROP(entity, assoc_terminal)), \ DT_NODE_HAS_COMPAT(DT_PROP(entity, assoc_terminal), \ @@ -393,6 +698,9 @@ BUILD_ASSERT(!NEEDS_SUBSLOT_SIZE_AND_BIT_RESOLUTION(node) || \ VALIDATE_BIT_RESOLUTION(node), \ "Bit Resolution must fit inside Subslot Size"); \ + BUILD_ASSERT(!DT_PROP(node, implicit_feedback) || \ + !AS_IS_SOF_SYNCHRONIZED(node), \ + "Implicit feedback on SOF synchronized clock"); \ )) #endif /* ZEPHYR_INCLUDE_USBD_UAC2_MACROS_H_ */ diff --git a/tests/subsys/usb/uac2/src/uac2_desc.c b/tests/subsys/usb/uac2/src/uac2_desc.c index d1645e0ad3b..9e22bc079ce 100644 --- a/tests/subsys/usb/uac2/src/uac2_desc.c +++ b/tests/subsys/usb/uac2/src/uac2_desc.c @@ -5,6 +5,7 @@ */ #include +#include #include @@ -124,6 +125,18 @@ static const uint8_t reference_as_out_descriptors[] = { 0x10, /* bBitResolution = 16 */ }; +static const uint8_t reference_as_ep_descriptor[] = { + /* 4.10.1.2 Class-Specific AS Isochronous Audio Data Endpoint Descriptor + */ + 0x08, /* bLength = 8 */ + 0x25, /* bDescriptorType = CS_ENDPOINT */ + 0x01, /* bDescriptorSubtype = EP_GENERAL */ + 0x00, /* bmAttributes = MaxPacketsOnly not set */ + 0x00, /* bmControls = non present */ + 0x00, /* bLockDelayUnits = 0 (Undefined) */ + 0x00, 0x00, /* wLockDelay = 0 */ +}; + DT_FOREACH_CHILD(DT_NODELABEL(uac2_headset), VALIDATE_NODE) static const uint8_t generated_ac_descriptors[] = { @@ -139,6 +152,10 @@ static const uint8_t generated_as_out_descriptors[] = { AUDIO_STREAMING_INTERFACE_DESCRIPTORS(DT_NODELABEL(as_iso_out)) }; +static const uint8_t generated_uac2_descriptors[] = { + UAC2_DESCRIPTORS(DT_NODELABEL(uac2_headset)) +}; + ZTEST(uac2_desc, test_audiocontrol_descriptors) { zassert_mem_equal(reference_ac_descriptors, generated_ac_descriptors, @@ -156,4 +173,146 @@ ZTEST(uac2_desc, test_audiostreaming_descriptors) ARRAY_SIZE(reference_as_out_descriptors)); } +ZTEST(uac2_desc, test_uac2_descriptors) +{ + const uint8_t *ptr = generated_uac2_descriptors; + const struct usb_association_descriptor *iad; + const struct usb_if_descriptor *iface; + const struct usb_ep_descriptor *ep; + + /* Headset has 3 interfaces: 1 AudioControl and 2 AudioStreaming */ + iad = (const struct usb_association_descriptor *)ptr; + zassert_equal(iad->bLength, sizeof(struct usb_association_descriptor)); + zassert_equal(iad->bDescriptorType, USB_DESC_INTERFACE_ASSOC); + zassert_equal(iad->bFirstInterface, FIRST_INTERFACE_NUMBER); + zassert_equal(iad->bInterfaceCount, 3); + zassert_equal(iad->bFunctionClass, AUDIO_FUNCTION); + zassert_equal(iad->bFunctionSubClass, FUNCTION_SUBCLASS_UNDEFINED); + zassert_equal(iad->bFunctionProtocol, AF_VERSION_02_00); + zassert_equal(iad->iFunction, 0); + ptr += sizeof(struct usb_association_descriptor); + + /* AudioControl interface goes first */ + iface = (const struct usb_if_descriptor *)ptr; + zassert_equal(iface->bLength, sizeof(struct usb_if_descriptor)); + zassert_equal(iface->bDescriptorType, USB_DESC_INTERFACE); + zassert_equal(iface->bInterfaceNumber, FIRST_INTERFACE_NUMBER); + zassert_equal(iface->bAlternateSetting, 0); + zassert_equal(iface->bNumEndpoints, 0); + zassert_equal(iface->bInterfaceClass, AUDIO); + zassert_equal(iface->bInterfaceSubClass, AUDIOCONTROL); + zassert_equal(iface->bInterfaceProtocol, IP_VERSION_02_00); + zassert_equal(iface->iInterface, 0); + ptr += sizeof(struct usb_if_descriptor); + + /* AudioControl class-specific descriptors */ + zassert_mem_equal(reference_ac_descriptors, ptr, + ARRAY_SIZE(reference_ac_descriptors)); + ptr += ARRAY_SIZE(reference_ac_descriptors); + + /* AudioStreaming OUT interface Alt 0 without endpoints */ + iface = (const struct usb_if_descriptor *)ptr; + zassert_equal(iface->bLength, sizeof(struct usb_if_descriptor)); + zassert_equal(iface->bDescriptorType, USB_DESC_INTERFACE); + zassert_equal(iface->bInterfaceNumber, FIRST_INTERFACE_NUMBER + 1); + zassert_equal(iface->bAlternateSetting, 0); + zassert_equal(iface->bNumEndpoints, 0); + zassert_equal(iface->bInterfaceClass, AUDIO); + zassert_equal(iface->bInterfaceSubClass, AUDIOSTREAMING); + zassert_equal(iface->bInterfaceProtocol, IP_VERSION_02_00); + zassert_equal(iface->iInterface, 0); + ptr += sizeof(struct usb_if_descriptor); + + /* AudioStreaming OUT interface Alt 1 with endpoint */ + iface = (const struct usb_if_descriptor *)ptr; + zassert_equal(iface->bLength, sizeof(struct usb_if_descriptor)); + zassert_equal(iface->bDescriptorType, USB_DESC_INTERFACE); + zassert_equal(iface->bInterfaceNumber, FIRST_INTERFACE_NUMBER + 1); + zassert_equal(iface->bAlternateSetting, 1); + zassert_equal(iface->bNumEndpoints, 1); + zassert_equal(iface->bInterfaceClass, AUDIO); + zassert_equal(iface->bInterfaceSubClass, AUDIOSTREAMING); + zassert_equal(iface->bInterfaceProtocol, IP_VERSION_02_00); + zassert_equal(iface->iInterface, 0); + ptr += sizeof(struct usb_if_descriptor); + + /* AudioStreaming OUT class-specific descriptors */ + zassert_mem_equal(reference_as_out_descriptors, ptr, + ARRAY_SIZE(reference_as_out_descriptors)); + ptr += ARRAY_SIZE(reference_as_out_descriptors); + + /* Isochronous OUT endpoint descriptor */ + ep = (const struct usb_ep_descriptor *)ptr; + zassert_equal(ep->bLength, sizeof(struct usb_ep_descriptor)); + zassert_equal(ep->bDescriptorType, USB_DESC_ENDPOINT); + zassert_equal(ep->bEndpointAddress, FIRST_OUT_EP_ADDR); + zassert_equal(&ep->bEndpointAddress - generated_uac2_descriptors, + UAC2_DESCRIPTOR_AS_DATA_EP_OFFSET(DT_NODELABEL(as_iso_out))); + zassert_equal(ep->Attributes.transfer, USB_EP_TYPE_ISO); + zassert_equal(ep->Attributes.synch, 1 /* Asynchronous */); + zassert_equal(ep->Attributes.usage, 0 /* Data Endpoint */); + zassert_equal(sys_le16_to_cpu(ep->wMaxPacketSize), 196); + zassert_equal(ep->bInterval, 1); + ptr += sizeof(struct usb_ep_descriptor); + + /* AudioStreaming OUT endpoint descriptor */ + zassert_mem_equal(reference_as_ep_descriptor, ptr, + ARRAY_SIZE(reference_as_ep_descriptor)); + ptr += ARRAY_SIZE(reference_as_ep_descriptor); + + /* AudioStreaming IN interface Alt 0 without endpoints */ + iface = (const struct usb_if_descriptor *)ptr; + zassert_equal(iface->bLength, sizeof(struct usb_if_descriptor)); + zassert_equal(iface->bDescriptorType, USB_DESC_INTERFACE); + zassert_equal(iface->bInterfaceNumber, FIRST_INTERFACE_NUMBER + 2); + zassert_equal(iface->bAlternateSetting, 0); + zassert_equal(iface->bNumEndpoints, 0); + zassert_equal(iface->bInterfaceClass, AUDIO); + zassert_equal(iface->bInterfaceSubClass, AUDIOSTREAMING); + zassert_equal(iface->bInterfaceProtocol, IP_VERSION_02_00); + zassert_equal(iface->iInterface, 0); + ptr += sizeof(struct usb_if_descriptor); + + /* AudioStreaming IN interface Alt 1 with endpoint */ + iface = (const struct usb_if_descriptor *)ptr; + zassert_equal(iface->bLength, sizeof(struct usb_if_descriptor)); + zassert_equal(iface->bDescriptorType, USB_DESC_INTERFACE); + zassert_equal(iface->bInterfaceNumber, FIRST_INTERFACE_NUMBER + 2); + zassert_equal(iface->bAlternateSetting, 1); + zassert_equal(iface->bNumEndpoints, 1); + zassert_equal(iface->bInterfaceClass, AUDIO); + zassert_equal(iface->bInterfaceSubClass, AUDIOSTREAMING); + zassert_equal(iface->bInterfaceProtocol, IP_VERSION_02_00); + zassert_equal(iface->iInterface, 0); + ptr += sizeof(struct usb_if_descriptor); + + /* AudioStreaming IN class-specific descriptors */ + zassert_mem_equal(reference_as_in_descriptors, ptr, + ARRAY_SIZE(reference_as_in_descriptors)); + ptr += ARRAY_SIZE(reference_as_in_descriptors); + + /* Isochronous IN endpoint descriptor */ + ep = (const struct usb_ep_descriptor *)ptr; + zassert_equal(ep->bLength, sizeof(struct usb_ep_descriptor)); + zassert_equal(ep->bDescriptorType, USB_DESC_ENDPOINT); + zassert_equal(ep->bEndpointAddress, FIRST_IN_EP_ADDR); + zassert_equal(&ep->bEndpointAddress - generated_uac2_descriptors, + UAC2_DESCRIPTOR_AS_DATA_EP_OFFSET(DT_NODELABEL(as_iso_in))); + zassert_equal(ep->Attributes.transfer, USB_EP_TYPE_ISO); + zassert_equal(ep->Attributes.synch, 1 /* Asynchronous */); + zassert_equal(ep->Attributes.usage, 2 /* Implicit Feedback Data */); + zassert_equal(sys_le16_to_cpu(ep->wMaxPacketSize), 98); + zassert_equal(ep->bInterval, 1); + ptr += sizeof(struct usb_ep_descriptor); + + /* AudioStreaming IN endpoint descriptor */ + zassert_mem_equal(reference_as_ep_descriptor, ptr, + ARRAY_SIZE(reference_as_ep_descriptor)); + ptr += ARRAY_SIZE(reference_as_ep_descriptor); + + /* Confirm there are is no trailing data */ + zassert_equal(ptr - generated_uac2_descriptors, + ARRAY_SIZE(generated_uac2_descriptors)); +} + ZTEST_SUITE(uac2_desc, NULL, NULL, NULL, NULL, NULL); From 15640611cfe1e3375ca6dd75bb1574dbd218561f Mon Sep 17 00:00:00 2001 From: Fang Huang Date: Fri, 8 Dec 2023 13:21:19 +0800 Subject: [PATCH 1299/3723] scripts: logging/dictionary/sys-t: remove escape between CDATA This removes escape from generate XML_CATALOG_EACH string, because the string between CDATA tag need to be treated as normal text. Signed-off-by: Fang Huang --- scripts/logging/dictionary/dictionary_parser/mipi_syst.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/scripts/logging/dictionary/dictionary_parser/mipi_syst.py b/scripts/logging/dictionary/dictionary_parser/mipi_syst.py index 467e74400c1..046a120d2fc 100644 --- a/scripts/logging/dictionary/dictionary_parser/mipi_syst.py +++ b/scripts/logging/dictionary/dictionary_parser/mipi_syst.py @@ -1,6 +1,6 @@ #!/usr/bin/env python3 # -# Copyright (c) 2022 Intel Corporation +# Copyright (c) 2022 - 2023 Intel Corporation # # SPDX-License-Identifier: Apache-2.0 @@ -106,7 +106,7 @@ def __gen_syst_catalog(database): fmt = XML_CATALOG32_EACH for addr, one_str in database.get_string_mappings().items(): - xml += fmt.format(addr, escape(one_str)) + xml += fmt.format(addr, one_str) if database.is_tgt_64bit(): xml += XML_CATALOG64_FOOTER From 9616b3b182e4404884d2e9bac5ff6f3ccb8dad9e Mon Sep 17 00:00:00 2001 From: Emil Gydesen Date: Fri, 8 Dec 2023 11:21:25 +0100 Subject: [PATCH 1300/3723] Bluetooth: MPL: Use set_track_position more excessively The set_track_position handles both correct clamping of the position, as well as the notification, so use that instead of setting the value and sending notifications manually. Also adds a new function, set_relative_track_position, to help set relative positions. Signed-off-by: Emil Gydesen --- subsys/bluetooth/audio/mpl.c | 170 +++++++++++++---------------------- 1 file changed, 60 insertions(+), 110 deletions(-) diff --git a/subsys/bluetooth/audio/mpl.c b/subsys/bluetooth/audio/mpl.c index 1b9d89e7a99..1ea859fe791 100644 --- a/subsys/bluetooth/audio/mpl.c +++ b/subsys/bluetooth/audio/mpl.c @@ -1,11 +1,13 @@ /* Media player skeleton implementation */ /* - * Copyright (c) 2019 - 2021 Nordic Semiconductor ASA + * Copyright (c) 2019 - 2023 Nordic Semiconductor ASA * * SPDX-License-Identifier: Apache-2.0 */ +#include + #include #include @@ -291,6 +293,9 @@ static struct obj_t obj = { .content = NET_BUF_SIMPLE(CONFIG_BT_MPL_MAX_OBJ_SIZE) }; +static void set_track_position(int32_t position); +static void set_relative_track_position(int32_t rel_pos); + /* Set up content buffer for the icon object */ static int setup_icon_object(void) { @@ -1296,8 +1301,7 @@ void do_full_prev_group(struct mpl_mediaplayer *pl) do_track_change_notifications(pl); /* If no track change, still reset track position, if needed */ } else if (pl->track_pos != 0) { - pl->track_pos = 0; - media_proxy_pl_track_position_cb(pl->track_pos); + set_track_position(0); } } @@ -1319,8 +1323,7 @@ void do_full_next_group(struct mpl_mediaplayer *pl) do_track_change_notifications(pl); /* If no track change, still reset track position, if needed */ } else if (pl->track_pos != 0) { - pl->track_pos = 0; - media_proxy_pl_track_position_cb(pl->track_pos); + set_track_position(0); } } @@ -1342,8 +1345,7 @@ void do_full_first_group(struct mpl_mediaplayer *pl) do_track_change_notifications(pl); /* If no track change, still reset track position, if needed */ } else if (pl->track_pos != 0) { - pl->track_pos = 0; - media_proxy_pl_track_position_cb(pl->track_pos); + set_track_position(0); } } @@ -1365,8 +1367,7 @@ void do_full_last_group(struct mpl_mediaplayer *pl) do_track_change_notifications(pl); /* If no track change, still reset track position, if needed */ } else if (pl->track_pos != 0) { - pl->track_pos = 0; - media_proxy_pl_track_position_cb(pl->track_pos); + set_track_position(0); } } @@ -1388,8 +1389,7 @@ void do_full_goto_group(struct mpl_mediaplayer *pl, int32_t groupnum) do_track_change_notifications(pl); /* If no track change, still reset track position, if needed */ } else if (pl->track_pos != 0) { - pl->track_pos = 0; - media_proxy_pl_track_position_cb(pl->track_pos); + set_track_position(0); } } @@ -1426,8 +1426,7 @@ void inactive_state_command_handler(const struct mpl_cmd *command, /* For previous track, the position is reset to 0 */ /* even if we stay at the same track (goto start of */ /* track) */ - media_player.track_pos = 0; - media_proxy_pl_track_position_cb(media_player.track_pos); + set_track_position(0); } media_player.state = MEDIA_PROXY_STATE_PAUSED; media_proxy_pl_media_state_cb(media_player.state); @@ -1464,8 +1463,7 @@ void inactive_state_command_handler(const struct mpl_cmd *command, } else { /* For first track, the position is reset to 0 even */ /* if we stay at the same track (goto start of track) */ - media_player.track_pos = 0; - media_proxy_pl_track_position_cb(media_player.track_pos); + set_track_position(0); } media_player.state = MEDIA_PROXY_STATE_PAUSED; media_proxy_pl_media_state_cb(media_player.state); @@ -1479,8 +1477,7 @@ void inactive_state_command_handler(const struct mpl_cmd *command, } else { /* For last track, the position is reset to 0 even */ /* if we stay at the same track (goto start of track) */ - media_player.track_pos = 0; - media_proxy_pl_track_position_cb(media_player.track_pos); + set_track_position(0); } media_player.state = MEDIA_PROXY_STATE_PAUSED; media_proxy_pl_media_state_cb(media_player.state); @@ -1496,8 +1493,7 @@ void inactive_state_command_handler(const struct mpl_cmd *command, /* For goto track, the position is reset to 0 */ /* even if we stay at the same track (goto */ /* start of track) */ - media_player.track_pos = 0; - media_proxy_pl_track_position_cb(media_player.track_pos); + set_track_position(0); } media_player.state = MEDIA_PROXY_STATE_PAUSED; media_proxy_pl_media_state_cb(media_player.state); @@ -1594,29 +1590,19 @@ void playing_state_command_handler(const struct mpl_cmd *command, media_proxy_pl_command_cb(ntf); break; case MEDIA_PROXY_OP_STOP: - media_player.track_pos = 0; + set_track_position(0); media_player.state = MEDIA_PROXY_STATE_PAUSED; media_proxy_pl_media_state_cb(media_player.state); - media_proxy_pl_track_position_cb(media_player.track_pos); ntf->result_code = MEDIA_PROXY_CMD_SUCCESS; media_proxy_pl_command_cb(ntf); break; case MEDIA_PROXY_OP_MOVE_RELATIVE: if (command->use_param) { - /* Keep within track - i.e. in the range 0 - duration */ - if (command->param > - media_player.group->track->duration - media_player.track_pos) { - media_player.track_pos = media_player.group->track->duration; - } else if (command->param < -media_player.track_pos) { - media_player.track_pos = 0; - } else { - media_player.track_pos += command->param; - } + set_relative_track_position(command->param); ntf->result_code = MEDIA_PROXY_CMD_SUCCESS; } else { ntf->result_code = MEDIA_PROXY_CMD_CANNOT_BE_COMPLETED; } - media_proxy_pl_track_position_cb(media_player.track_pos); media_proxy_pl_command_cb(ntf); break; case MEDIA_PROXY_OP_PREV_SEGMENT: @@ -1626,29 +1612,25 @@ void playing_state_command_handler(const struct mpl_cmd *command, media_player.group->track->segment->pos) { do_prev_segment(&media_player); } - media_player.track_pos = media_player.group->track->segment->pos; - media_proxy_pl_track_position_cb(media_player.track_pos); + set_track_position(media_player.group->track->segment->pos); ntf->result_code = MEDIA_PROXY_CMD_SUCCESS; media_proxy_pl_command_cb(ntf); break; case MEDIA_PROXY_OP_NEXT_SEGMENT: do_next_segment(&media_player); - media_player.track_pos = media_player.group->track->segment->pos; - media_proxy_pl_track_position_cb(media_player.track_pos); + set_track_position(media_player.group->track->segment->pos); ntf->result_code = MEDIA_PROXY_CMD_SUCCESS; media_proxy_pl_command_cb(ntf); break; case MEDIA_PROXY_OP_FIRST_SEGMENT: do_first_segment(&media_player); - media_player.track_pos = media_player.group->track->segment->pos; - media_proxy_pl_track_position_cb(media_player.track_pos); + set_track_position(media_player.group->track->segment->pos); ntf->result_code = MEDIA_PROXY_CMD_SUCCESS; media_proxy_pl_command_cb(ntf); break; case MEDIA_PROXY_OP_LAST_SEGMENT: do_last_segment(&media_player); - media_player.track_pos = media_player.group->track->segment->pos; - media_proxy_pl_track_position_cb(media_player.track_pos); + set_track_position(media_player.group->track->segment->pos); ntf->result_code = MEDIA_PROXY_CMD_SUCCESS; media_proxy_pl_command_cb(ntf); break; @@ -1656,8 +1638,7 @@ void playing_state_command_handler(const struct mpl_cmd *command, if (command->use_param) { if (command->param != 0) { do_goto_segment(&media_player, command->param); - media_player.track_pos = media_player.group->track->segment->pos; - media_proxy_pl_track_position_cb(media_player.track_pos); + set_track_position(media_player.group->track->segment->pos); } /* If the argument to "goto segment" is zero, */ /* the segment shall stay the same, and the */ @@ -1676,8 +1657,7 @@ void playing_state_command_handler(const struct mpl_cmd *command, /* For previous track, the position is reset to 0 */ /* even if we stay at the same track (goto start of */ /* track) */ - media_player.track_pos = 0; - media_proxy_pl_track_position_cb(media_player.track_pos); + set_track_position(0); } ntf->result_code = MEDIA_PROXY_CMD_SUCCESS; media_proxy_pl_command_cb(ntf); @@ -1706,8 +1686,7 @@ void playing_state_command_handler(const struct mpl_cmd *command, } else { /* For first track, the position is reset to 0 even */ /* if we stay at the same track (goto start of track) */ - media_player.track_pos = 0; - media_proxy_pl_track_position_cb(media_player.track_pos); + set_track_position(0); } ntf->result_code = MEDIA_PROXY_CMD_SUCCESS; media_proxy_pl_command_cb(ntf); @@ -1719,8 +1698,7 @@ void playing_state_command_handler(const struct mpl_cmd *command, } else { /* For last track, the position is reset to 0 even */ /* if we stay at the same track (goto start of track) */ - media_player.track_pos = 0; - media_proxy_pl_track_position_cb(media_player.track_pos); + set_track_position(0); } ntf->result_code = MEDIA_PROXY_CMD_SUCCESS; media_proxy_pl_command_cb(ntf); @@ -1734,8 +1712,7 @@ void playing_state_command_handler(const struct mpl_cmd *command, /* For goto track, the position is reset to 0 */ /* even if we stay at the same track (goto */ /* start of track) */ - media_player.track_pos = 0; - media_proxy_pl_track_position_cb(media_player.track_pos); + set_track_position(0); } ntf->result_code = MEDIA_PROXY_CMD_SUCCESS; } else { @@ -1820,29 +1797,19 @@ void paused_state_command_handler(const struct mpl_cmd *command, media_proxy_pl_command_cb(ntf); break; case MEDIA_PROXY_OP_STOP: - media_player.track_pos = 0; + set_track_position(0); media_player.state = MEDIA_PROXY_STATE_PAUSED; media_proxy_pl_media_state_cb(media_player.state); - media_proxy_pl_track_position_cb(media_player.track_pos); ntf->result_code = MEDIA_PROXY_CMD_SUCCESS; media_proxy_pl_command_cb(ntf); break; case MEDIA_PROXY_OP_MOVE_RELATIVE: if (command->use_param) { - /* Keep within track - i.e. in the range 0 - duration */ - if (command->param > - media_player.group->track->duration - media_player.track_pos) { - media_player.track_pos = media_player.group->track->duration; - } else if (command->param < -media_player.track_pos) { - media_player.track_pos = 0; - } else { - media_player.track_pos += command->param; - } + set_relative_track_position(command->param); ntf->result_code = MEDIA_PROXY_CMD_SUCCESS; } else { ntf->result_code = MEDIA_PROXY_CMD_CANNOT_BE_COMPLETED; } - media_proxy_pl_track_position_cb(media_player.track_pos); media_proxy_pl_command_cb(ntf); break; case MEDIA_PROXY_OP_PREV_SEGMENT: @@ -1854,8 +1821,7 @@ void paused_state_command_handler(const struct mpl_cmd *command, do_prev_segment(&media_player); } - media_player.track_pos = media_player.group->track->segment->pos; - media_proxy_pl_track_position_cb(media_player.track_pos); + set_track_position(media_player.group->track->segment->pos); ntf->result_code = MEDIA_PROXY_CMD_SUCCESS; } else { ntf->result_code = MEDIA_PROXY_CMD_CANNOT_BE_COMPLETED; @@ -1866,8 +1832,7 @@ void paused_state_command_handler(const struct mpl_cmd *command, case MEDIA_PROXY_OP_NEXT_SEGMENT: if (media_player.group->track->segment != NULL) { do_next_segment(&media_player); - media_player.track_pos = media_player.group->track->segment->pos; - media_proxy_pl_track_position_cb(media_player.track_pos); + set_track_position(media_player.group->track->segment->pos); ntf->result_code = MEDIA_PROXY_CMD_SUCCESS; } else { ntf->result_code = MEDIA_PROXY_CMD_CANNOT_BE_COMPLETED; @@ -1878,8 +1843,7 @@ void paused_state_command_handler(const struct mpl_cmd *command, case MEDIA_PROXY_OP_FIRST_SEGMENT: if (media_player.group->track->segment != NULL) { do_first_segment(&media_player); - media_player.track_pos = media_player.group->track->segment->pos; - media_proxy_pl_track_position_cb(media_player.track_pos); + set_track_position(media_player.group->track->segment->pos); ntf->result_code = MEDIA_PROXY_CMD_SUCCESS; } else { ntf->result_code = MEDIA_PROXY_CMD_CANNOT_BE_COMPLETED; @@ -1890,8 +1854,7 @@ void paused_state_command_handler(const struct mpl_cmd *command, case MEDIA_PROXY_OP_LAST_SEGMENT: if (media_player.group->track->segment != NULL) { do_last_segment(&media_player); - media_player.track_pos = media_player.group->track->segment->pos; - media_proxy_pl_track_position_cb(media_player.track_pos); + set_track_position(media_player.group->track->segment->pos); ntf->result_code = MEDIA_PROXY_CMD_SUCCESS; } else { ntf->result_code = MEDIA_PROXY_CMD_CANNOT_BE_COMPLETED; @@ -1903,8 +1866,7 @@ void paused_state_command_handler(const struct mpl_cmd *command, if (command->use_param && media_player.group->track->segment != NULL) { if (command->param != 0) { do_goto_segment(&media_player, command->param); - media_player.track_pos = media_player.group->track->segment->pos; - media_proxy_pl_track_position_cb(media_player.track_pos); + set_track_position(media_player.group->track->segment->pos); } /* If the argument to "goto segment" is zero, */ /* the segment shall stay the same, and the */ @@ -1923,8 +1885,7 @@ void paused_state_command_handler(const struct mpl_cmd *command, /* For previous track, the position is reset to 0 */ /* even if we stay at the same track (goto start of */ /* track) */ - media_player.track_pos = 0; - media_proxy_pl_track_position_cb(media_player.track_pos); + set_track_position(0); } ntf->result_code = MEDIA_PROXY_CMD_SUCCESS; media_proxy_pl_command_cb(ntf); @@ -1953,8 +1914,7 @@ void paused_state_command_handler(const struct mpl_cmd *command, } else { /* For first track, the position is reset to 0 even */ /* if we stay at the same track (goto start of track) */ - media_player.track_pos = 0; - media_proxy_pl_track_position_cb(media_player.track_pos); + set_track_position(0); } ntf->result_code = MEDIA_PROXY_CMD_SUCCESS; media_proxy_pl_command_cb(ntf); @@ -1966,8 +1926,7 @@ void paused_state_command_handler(const struct mpl_cmd *command, } else { /* For last track, the position is reset to 0 even */ /* if we stay at the same track (goto start of track) */ - media_player.track_pos = 0; - media_proxy_pl_track_position_cb(media_player.track_pos); + set_track_position(0); } ntf->result_code = MEDIA_PROXY_CMD_SUCCESS; media_proxy_pl_command_cb(ntf); @@ -1981,8 +1940,7 @@ void paused_state_command_handler(const struct mpl_cmd *command, /* For goto track, the position is reset to 0 */ /* even if we stay at the same track (goto */ /* start of track) */ - media_player.track_pos = 0; - media_proxy_pl_track_position_cb(media_player.track_pos); + set_track_position(0); } ntf->result_code = MEDIA_PROXY_CMD_SUCCESS; } else { @@ -2081,30 +2039,20 @@ void seeking_state_command_handler(const struct mpl_cmd *command, break; case MEDIA_PROXY_OP_STOP: media_player.seeking_speed_factor = MEDIA_PROXY_SEEKING_SPEED_FACTOR_ZERO; - media_player.track_pos = 0; + set_track_position(0); media_player.state = MEDIA_PROXY_STATE_PAUSED; media_proxy_pl_media_state_cb(media_player.state); media_proxy_pl_seeking_speed_cb(media_player.seeking_speed_factor); - media_proxy_pl_track_position_cb(media_player.track_pos); ntf->result_code = MEDIA_PROXY_CMD_SUCCESS; media_proxy_pl_command_cb(ntf); break; case MEDIA_PROXY_OP_MOVE_RELATIVE: if (command->use_param) { - /* Keep within track - i.e. in the range 0 - duration */ - if (command->param > - media_player.group->track->duration - media_player.track_pos) { - media_player.track_pos = media_player.group->track->duration; - } else if (command->param < -media_player.track_pos) { - media_player.track_pos = 0; - } else { - media_player.track_pos += command->param; - } + set_relative_track_position(command->param); ntf->result_code = MEDIA_PROXY_CMD_SUCCESS; } else { ntf->result_code = MEDIA_PROXY_CMD_CANNOT_BE_COMPLETED; } - media_proxy_pl_track_position_cb(media_player.track_pos); media_proxy_pl_command_cb(ntf); break; case MEDIA_PROXY_OP_PREV_SEGMENT: @@ -2114,29 +2062,25 @@ void seeking_state_command_handler(const struct mpl_cmd *command, media_player.group->track->segment->pos) { do_prev_segment(&media_player); } - media_player.track_pos = media_player.group->track->segment->pos; - media_proxy_pl_track_position_cb(media_player.track_pos); + set_track_position(media_player.group->track->segment->pos); ntf->result_code = MEDIA_PROXY_CMD_SUCCESS; media_proxy_pl_command_cb(ntf); break; case MEDIA_PROXY_OP_NEXT_SEGMENT: do_next_segment(&media_player); - media_player.track_pos = media_player.group->track->segment->pos; - media_proxy_pl_track_position_cb(media_player.track_pos); + set_track_position(media_player.group->track->segment->pos); ntf->result_code = MEDIA_PROXY_CMD_SUCCESS; media_proxy_pl_command_cb(ntf); break; case MEDIA_PROXY_OP_FIRST_SEGMENT: do_first_segment(&media_player); - media_player.track_pos = media_player.group->track->segment->pos; - media_proxy_pl_track_position_cb(media_player.track_pos); + set_track_position(media_player.group->track->segment->pos); ntf->result_code = MEDIA_PROXY_CMD_SUCCESS; media_proxy_pl_command_cb(ntf); break; case MEDIA_PROXY_OP_LAST_SEGMENT: do_last_segment(&media_player); - media_player.track_pos = media_player.group->track->segment->pos; - media_proxy_pl_track_position_cb(media_player.track_pos); + set_track_position(media_player.group->track->segment->pos); ntf->result_code = MEDIA_PROXY_CMD_SUCCESS; media_proxy_pl_command_cb(ntf); break; @@ -2144,8 +2088,7 @@ void seeking_state_command_handler(const struct mpl_cmd *command, if (command->use_param) { if (command->param != 0) { do_goto_segment(&media_player, command->param); - media_player.track_pos = media_player.group->track->segment->pos; - media_proxy_pl_track_position_cb(media_player.track_pos); + set_track_position(media_player.group->track->segment->pos); } /* If the argument to "goto segment" is zero, */ /* the segment shall stay the same, and the */ @@ -2164,8 +2107,7 @@ void seeking_state_command_handler(const struct mpl_cmd *command, /* For previous track, the position is reset to 0 */ /* even if we stay at the same track (goto start of */ /* track) */ - media_player.track_pos = 0; - media_proxy_pl_track_position_cb(media_player.track_pos); + set_track_position(0); } media_player.seeking_speed_factor = MEDIA_PROXY_SEEKING_SPEED_FACTOR_ZERO; media_player.state = MEDIA_PROXY_STATE_PAUSED; @@ -2200,8 +2142,7 @@ void seeking_state_command_handler(const struct mpl_cmd *command, } else { /* For first track, the position is reset to 0 even */ /* if we stay at the same track (goto start of track) */ - media_player.track_pos = 0; - media_proxy_pl_track_position_cb(media_player.track_pos); + set_track_position(0); } media_player.seeking_speed_factor = MEDIA_PROXY_SEEKING_SPEED_FACTOR_ZERO; media_player.state = MEDIA_PROXY_STATE_PAUSED; @@ -2216,8 +2157,7 @@ void seeking_state_command_handler(const struct mpl_cmd *command, } else { /* For last track, the position is reset to 0 even */ /* if we stay at the same track (goto start of track) */ - media_player.track_pos = 0; - media_proxy_pl_track_position_cb(media_player.track_pos); + set_track_position(0); } media_player.seeking_speed_factor = MEDIA_PROXY_SEEKING_SPEED_FACTOR_ZERO; media_player.state = MEDIA_PROXY_STATE_PAUSED; @@ -2234,8 +2174,7 @@ void seeking_state_command_handler(const struct mpl_cmd *command, /* For goto track, the position is reset to 0 */ /* even if we stay at the same track (goto */ /* start of track) */ - media_player.track_pos = 0; - media_proxy_pl_track_position_cb(media_player.track_pos); + set_track_position(0); } media_player.seeking_speed_factor = MEDIA_PROXY_SEEKING_SPEED_FACTOR_ZERO; media_player.state = MEDIA_PROXY_STATE_PAUSED; @@ -2409,7 +2348,7 @@ int32_t get_track_position(void) return media_player.track_pos; } -void set_track_position(int32_t position) +static void set_track_position(int32_t position) { int32_t old_pos = media_player.track_pos; int32_t new_pos; @@ -2442,6 +2381,17 @@ void set_track_position(int32_t position) } } +static void set_relative_track_position(int32_t rel_pos) +{ + int64_t pos; + + pos = media_player.track_pos + rel_pos; + /* Clamp to allowed values */ + pos = CLAMP(pos, 0, media_player.group->track->duration); + + set_track_position((int32_t)pos); +} + int8_t get_playback_speed(void) { return media_player.playback_speed_param; From f138f7dd3ec67399139e6ef36c3d2d9960a9bc53 Mon Sep 17 00:00:00 2001 From: Emil Gydesen Date: Fri, 8 Dec 2023 13:30:06 +0100 Subject: [PATCH 1301/3723] Bluetooth: MPL: Add mpl_set_state Add the static function, mpl_set_state, to help set the playing state of the media player. Signed-off-by: Emil Gydesen --- subsys/bluetooth/audio/mpl.c | 117 ++++++++++++++++------------------- 1 file changed, 53 insertions(+), 64 deletions(-) diff --git a/subsys/bluetooth/audio/mpl.c b/subsys/bluetooth/audio/mpl.c index 1ea859fe791..2426f371617 100644 --- a/subsys/bluetooth/audio/mpl.c +++ b/subsys/bluetooth/audio/mpl.c @@ -1393,6 +1393,22 @@ void do_full_goto_group(struct mpl_mediaplayer *pl, int32_t groupnum) } } +static void mpl_set_state(uint8_t state) +{ + switch (state) { + case MEDIA_PROXY_STATE_INACTIVE: + case MEDIA_PROXY_STATE_PLAYING: + case MEDIA_PROXY_STATE_PAUSED: + case MEDIA_PROXY_STATE_SEEKING: + break; + default: + __ASSERT(false, "Invalid state: %u", state); + } + + media_player.state = state; + media_proxy_pl_media_state_cb(media_player.state); +} + /* Command handlers (state machines) */ void inactive_state_command_handler(const struct mpl_cmd *command, struct mpl_cmd_ntf *ntf) @@ -1428,8 +1444,8 @@ void inactive_state_command_handler(const struct mpl_cmd *command, /* track) */ set_track_position(0); } - media_player.state = MEDIA_PROXY_STATE_PAUSED; - media_proxy_pl_media_state_cb(media_player.state); + + mpl_set_state(MEDIA_PROXY_STATE_PAUSED); ntf->result_code = MEDIA_PROXY_CMD_SUCCESS; media_proxy_pl_command_cb(ntf); break; @@ -1449,10 +1465,10 @@ void inactive_state_command_handler(const struct mpl_cmd *command, media_player.track_pos = 0; do_track_change_notifications(&media_player); } + /* For next track, the position is kept if the track */ /* does not change */ - media_player.state = MEDIA_PROXY_STATE_PAUSED; - media_proxy_pl_media_state_cb(media_player.state); + mpl_set_state(MEDIA_PROXY_STATE_PAUSED); ntf->result_code = MEDIA_PROXY_CMD_SUCCESS; media_proxy_pl_command_cb(ntf); break; @@ -1465,8 +1481,8 @@ void inactive_state_command_handler(const struct mpl_cmd *command, /* if we stay at the same track (goto start of track) */ set_track_position(0); } - media_player.state = MEDIA_PROXY_STATE_PAUSED; - media_proxy_pl_media_state_cb(media_player.state); + + mpl_set_state(MEDIA_PROXY_STATE_PAUSED); ntf->result_code = MEDIA_PROXY_CMD_SUCCESS; media_proxy_pl_command_cb(ntf); break; @@ -1479,8 +1495,8 @@ void inactive_state_command_handler(const struct mpl_cmd *command, /* if we stay at the same track (goto start of track) */ set_track_position(0); } - media_player.state = MEDIA_PROXY_STATE_PAUSED; - media_proxy_pl_media_state_cb(media_player.state); + + mpl_set_state(MEDIA_PROXY_STATE_PAUSED); ntf->result_code = MEDIA_PROXY_CMD_SUCCESS; media_proxy_pl_command_cb(ntf); break; @@ -1495,8 +1511,8 @@ void inactive_state_command_handler(const struct mpl_cmd *command, /* start of track) */ set_track_position(0); } - media_player.state = MEDIA_PROXY_STATE_PAUSED; - media_proxy_pl_media_state_cb(media_player.state); + + mpl_set_state(MEDIA_PROXY_STATE_PAUSED); ntf->result_code = MEDIA_PROXY_CMD_SUCCESS; } else { ntf->result_code = MEDIA_PROXY_CMD_CANNOT_BE_COMPLETED; @@ -1505,37 +1521,32 @@ void inactive_state_command_handler(const struct mpl_cmd *command, break; case MEDIA_PROXY_OP_PREV_GROUP: do_full_prev_group(&media_player); - media_player.state = MEDIA_PROXY_STATE_PAUSED; - media_proxy_pl_media_state_cb(media_player.state); + mpl_set_state(MEDIA_PROXY_STATE_PAUSED); ntf->result_code = MEDIA_PROXY_CMD_SUCCESS; media_proxy_pl_command_cb(ntf); break; case MEDIA_PROXY_OP_NEXT_GROUP: do_full_next_group(&media_player); - media_player.state = MEDIA_PROXY_STATE_PAUSED; - media_proxy_pl_media_state_cb(media_player.state); + mpl_set_state(MEDIA_PROXY_STATE_PAUSED); ntf->result_code = MEDIA_PROXY_CMD_SUCCESS; media_proxy_pl_command_cb(ntf); break; case MEDIA_PROXY_OP_FIRST_GROUP: do_full_first_group(&media_player); - media_player.state = MEDIA_PROXY_STATE_PAUSED; - media_proxy_pl_media_state_cb(media_player.state); + mpl_set_state(MEDIA_PROXY_STATE_PAUSED); ntf->result_code = MEDIA_PROXY_CMD_SUCCESS; media_proxy_pl_command_cb(ntf); break; case MEDIA_PROXY_OP_LAST_GROUP: do_full_last_group(&media_player); - media_player.state = MEDIA_PROXY_STATE_PAUSED; - media_proxy_pl_media_state_cb(media_player.state); + mpl_set_state(MEDIA_PROXY_STATE_PAUSED); ntf->result_code = MEDIA_PROXY_CMD_SUCCESS; media_proxy_pl_command_cb(ntf); break; case MEDIA_PROXY_OP_GOTO_GROUP: if (command->use_param) { do_full_goto_group(&media_player, command->param); - media_player.state = MEDIA_PROXY_STATE_PAUSED; - media_proxy_pl_media_state_cb(media_player.state); + mpl_set_state(MEDIA_PROXY_STATE_PAUSED); ntf->result_code = MEDIA_PROXY_CMD_SUCCESS; } else { ntf->result_code = MEDIA_PROXY_CMD_CANNOT_BE_COMPLETED; @@ -1566,16 +1577,14 @@ void playing_state_command_handler(const struct mpl_cmd *command, media_proxy_pl_command_cb(ntf); break; case MEDIA_PROXY_OP_PAUSE: - media_player.state = MEDIA_PROXY_STATE_PAUSED; - media_proxy_pl_media_state_cb(media_player.state); + mpl_set_state(MEDIA_PROXY_STATE_PAUSED); ntf->result_code = MEDIA_PROXY_CMD_SUCCESS; media_proxy_pl_command_cb(ntf); break; case MEDIA_PROXY_OP_FAST_REWIND: /* We're in playing state, seeking speed must have been zero */ media_player.seeking_speed_factor = -MPL_SEEKING_SPEED_FACTOR_STEP; - media_player.state = MEDIA_PROXY_STATE_SEEKING; - media_proxy_pl_media_state_cb(media_player.state); + mpl_set_state(MEDIA_PROXY_STATE_SEEKING); media_proxy_pl_seeking_speed_cb(media_player.seeking_speed_factor); ntf->result_code = MEDIA_PROXY_CMD_SUCCESS; media_proxy_pl_command_cb(ntf); @@ -1583,16 +1592,14 @@ void playing_state_command_handler(const struct mpl_cmd *command, case MEDIA_PROXY_OP_FAST_FORWARD: /* We're in playing state, seeking speed must have been zero */ media_player.seeking_speed_factor = MPL_SEEKING_SPEED_FACTOR_STEP; - media_player.state = MEDIA_PROXY_STATE_SEEKING; - media_proxy_pl_media_state_cb(media_player.state); + mpl_set_state(MEDIA_PROXY_STATE_SEEKING); media_proxy_pl_seeking_speed_cb(media_player.seeking_speed_factor); ntf->result_code = MEDIA_PROXY_CMD_SUCCESS; media_proxy_pl_command_cb(ntf); break; case MEDIA_PROXY_OP_STOP: set_track_position(0); - media_player.state = MEDIA_PROXY_STATE_PAUSED; - media_proxy_pl_media_state_cb(media_player.state); + mpl_set_state(MEDIA_PROXY_STATE_PAUSED); ntf->result_code = MEDIA_PROXY_CMD_SUCCESS; media_proxy_pl_command_cb(ntf); break; @@ -1768,8 +1775,7 @@ void paused_state_command_handler(const struct mpl_cmd *command, } switch (command->opcode) { case MEDIA_PROXY_OP_PLAY: - media_player.state = MEDIA_PROXY_STATE_PLAYING; - media_proxy_pl_media_state_cb(media_player.state); + mpl_set_state(MEDIA_PROXY_STATE_PLAYING); ntf->result_code = MEDIA_PROXY_CMD_SUCCESS; media_proxy_pl_command_cb(ntf); break; @@ -1781,8 +1787,7 @@ void paused_state_command_handler(const struct mpl_cmd *command, case MEDIA_PROXY_OP_FAST_REWIND: /* We're in paused state, seeking speed must have been zero */ media_player.seeking_speed_factor = -MPL_SEEKING_SPEED_FACTOR_STEP; - media_player.state = MEDIA_PROXY_STATE_SEEKING; - media_proxy_pl_media_state_cb(media_player.state); + mpl_set_state(MEDIA_PROXY_STATE_SEEKING); media_proxy_pl_seeking_speed_cb(media_player.seeking_speed_factor); ntf->result_code = MEDIA_PROXY_CMD_SUCCESS; media_proxy_pl_command_cb(ntf); @@ -1790,16 +1795,14 @@ void paused_state_command_handler(const struct mpl_cmd *command, case MEDIA_PROXY_OP_FAST_FORWARD: /* We're in paused state, seeking speed must have been zero */ media_player.seeking_speed_factor = MPL_SEEKING_SPEED_FACTOR_STEP; - media_player.state = MEDIA_PROXY_STATE_SEEKING; - media_proxy_pl_media_state_cb(media_player.state); + mpl_set_state(MEDIA_PROXY_STATE_SEEKING); media_proxy_pl_seeking_speed_cb(media_player.seeking_speed_factor); ntf->result_code = MEDIA_PROXY_CMD_SUCCESS; media_proxy_pl_command_cb(ntf); break; case MEDIA_PROXY_OP_STOP: set_track_position(0); - media_player.state = MEDIA_PROXY_STATE_PAUSED; - media_proxy_pl_media_state_cb(media_player.state); + mpl_set_state(MEDIA_PROXY_STATE_PAUSED); ntf->result_code = MEDIA_PROXY_CMD_SUCCESS; media_proxy_pl_command_cb(ntf); break; @@ -1997,8 +2000,7 @@ void seeking_state_command_handler(const struct mpl_cmd *command, switch (command->opcode) { case MEDIA_PROXY_OP_PLAY: media_player.seeking_speed_factor = MEDIA_PROXY_SEEKING_SPEED_FACTOR_ZERO; - media_player.state = MEDIA_PROXY_STATE_PLAYING; - media_proxy_pl_media_state_cb(media_player.state); + mpl_set_state(MEDIA_PROXY_STATE_PLAYING); media_proxy_pl_seeking_speed_cb(media_player.seeking_speed_factor); ntf->result_code = MEDIA_PROXY_CMD_SUCCESS; media_proxy_pl_command_cb(ntf); @@ -2006,8 +2008,7 @@ void seeking_state_command_handler(const struct mpl_cmd *command, case MEDIA_PROXY_OP_PAUSE: media_player.seeking_speed_factor = MEDIA_PROXY_SEEKING_SPEED_FACTOR_ZERO; /* TODO: Set track and track position */ - media_player.state = MEDIA_PROXY_STATE_PAUSED; - media_proxy_pl_media_state_cb(media_player.state); + mpl_set_state(MEDIA_PROXY_STATE_PAUSED); media_proxy_pl_seeking_speed_cb(media_player.seeking_speed_factor); ntf->result_code = MEDIA_PROXY_CMD_SUCCESS; media_proxy_pl_command_cb(ntf); @@ -2040,8 +2041,7 @@ void seeking_state_command_handler(const struct mpl_cmd *command, case MEDIA_PROXY_OP_STOP: media_player.seeking_speed_factor = MEDIA_PROXY_SEEKING_SPEED_FACTOR_ZERO; set_track_position(0); - media_player.state = MEDIA_PROXY_STATE_PAUSED; - media_proxy_pl_media_state_cb(media_player.state); + mpl_set_state(MEDIA_PROXY_STATE_PAUSED); media_proxy_pl_seeking_speed_cb(media_player.seeking_speed_factor); ntf->result_code = MEDIA_PROXY_CMD_SUCCESS; media_proxy_pl_command_cb(ntf); @@ -2110,8 +2110,7 @@ void seeking_state_command_handler(const struct mpl_cmd *command, set_track_position(0); } media_player.seeking_speed_factor = MEDIA_PROXY_SEEKING_SPEED_FACTOR_ZERO; - media_player.state = MEDIA_PROXY_STATE_PAUSED; - media_proxy_pl_media_state_cb(media_player.state); + mpl_set_state(MEDIA_PROXY_STATE_PAUSED); ntf->result_code = MEDIA_PROXY_CMD_SUCCESS; media_proxy_pl_command_cb(ntf); break; @@ -2130,8 +2129,7 @@ void seeking_state_command_handler(const struct mpl_cmd *command, /* For next track, the position is kept if the track */ /* does not change */ media_player.seeking_speed_factor = MEDIA_PROXY_SEEKING_SPEED_FACTOR_ZERO; - media_player.state = MEDIA_PROXY_STATE_PAUSED; - media_proxy_pl_media_state_cb(media_player.state); + mpl_set_state(MEDIA_PROXY_STATE_PAUSED); ntf->result_code = MEDIA_PROXY_CMD_SUCCESS; media_proxy_pl_command_cb(ntf); break; @@ -2145,8 +2143,7 @@ void seeking_state_command_handler(const struct mpl_cmd *command, set_track_position(0); } media_player.seeking_speed_factor = MEDIA_PROXY_SEEKING_SPEED_FACTOR_ZERO; - media_player.state = MEDIA_PROXY_STATE_PAUSED; - media_proxy_pl_media_state_cb(media_player.state); + mpl_set_state(MEDIA_PROXY_STATE_PAUSED); ntf->result_code = MEDIA_PROXY_CMD_SUCCESS; media_proxy_pl_command_cb(ntf); break; @@ -2160,8 +2157,7 @@ void seeking_state_command_handler(const struct mpl_cmd *command, set_track_position(0); } media_player.seeking_speed_factor = MEDIA_PROXY_SEEKING_SPEED_FACTOR_ZERO; - media_player.state = MEDIA_PROXY_STATE_PAUSED; - media_proxy_pl_media_state_cb(media_player.state); + mpl_set_state(MEDIA_PROXY_STATE_PAUSED); ntf->result_code = MEDIA_PROXY_CMD_SUCCESS; media_proxy_pl_command_cb(ntf); break; @@ -2177,8 +2173,7 @@ void seeking_state_command_handler(const struct mpl_cmd *command, set_track_position(0); } media_player.seeking_speed_factor = MEDIA_PROXY_SEEKING_SPEED_FACTOR_ZERO; - media_player.state = MEDIA_PROXY_STATE_PAUSED; - media_proxy_pl_media_state_cb(media_player.state); + mpl_set_state(MEDIA_PROXY_STATE_PAUSED); ntf->result_code = MEDIA_PROXY_CMD_SUCCESS; } else { ntf->result_code = MEDIA_PROXY_CMD_CANNOT_BE_COMPLETED; @@ -2187,37 +2182,32 @@ void seeking_state_command_handler(const struct mpl_cmd *command, break; case MEDIA_PROXY_OP_PREV_GROUP: do_full_prev_group(&media_player); - media_player.state = MEDIA_PROXY_STATE_PAUSED; - media_proxy_pl_media_state_cb(media_player.state); + mpl_set_state(MEDIA_PROXY_STATE_PAUSED); ntf->result_code = MEDIA_PROXY_CMD_SUCCESS; media_proxy_pl_command_cb(ntf); break; case MEDIA_PROXY_OP_NEXT_GROUP: do_full_next_group(&media_player); - media_player.state = MEDIA_PROXY_STATE_PAUSED; - media_proxy_pl_media_state_cb(media_player.state); + mpl_set_state(MEDIA_PROXY_STATE_PAUSED); ntf->result_code = MEDIA_PROXY_CMD_SUCCESS; media_proxy_pl_command_cb(ntf); break; case MEDIA_PROXY_OP_FIRST_GROUP: do_full_first_group(&media_player); - media_player.state = MEDIA_PROXY_STATE_PAUSED; - media_proxy_pl_media_state_cb(media_player.state); + mpl_set_state(MEDIA_PROXY_STATE_PAUSED); ntf->result_code = MEDIA_PROXY_CMD_SUCCESS; media_proxy_pl_command_cb(ntf); break; case MEDIA_PROXY_OP_LAST_GROUP: do_full_last_group(&media_player); - media_player.state = MEDIA_PROXY_STATE_PAUSED; - media_proxy_pl_media_state_cb(media_player.state); + mpl_set_state(MEDIA_PROXY_STATE_PAUSED); ntf->result_code = MEDIA_PROXY_CMD_SUCCESS; media_proxy_pl_command_cb(ntf); break; case MEDIA_PROXY_OP_GOTO_GROUP: if (command->use_param) { do_full_goto_group(&media_player, command->param); - media_player.state = MEDIA_PROXY_STATE_PAUSED; - media_proxy_pl_media_state_cb(media_player.state); + mpl_set_state(MEDIA_PROXY_STATE_PAUSED); ntf->result_code = MEDIA_PROXY_CMD_SUCCESS; } else { ntf->result_code = MEDIA_PROXY_CMD_CANNOT_BE_COMPLETED; @@ -2852,8 +2842,7 @@ void mpl_test_unset_parent_group(void) void mpl_test_media_state_set(uint8_t state) { - media_player.state = state; - media_proxy_pl_media_state_cb(media_player.state); + mpl_set_state(state); } void mpl_test_player_name_changed_cb(void) From 984e4213c1885b8c05d7a832ffc761ecf784b7c7 Mon Sep 17 00:00:00 2001 From: Emil Gydesen Date: Fri, 8 Dec 2023 14:21:53 +0100 Subject: [PATCH 1302/3723] Bluetooth: MPL: Simplify track and group changes Simplify track and group changes by moving the notifications into the functions that changes the states. This removes some code duplication, and makes the code easier to read, as well, as ensuring that notifications are always sent. Signed-off-by: Emil Gydesen --- subsys/bluetooth/audio/mpl.c | 460 +++++++++-------------------------- 1 file changed, 118 insertions(+), 342 deletions(-) diff --git a/subsys/bluetooth/audio/mpl.c b/subsys/bluetooth/audio/mpl.c index 2426f371617..d4b26b5d125 100644 --- a/subsys/bluetooth/audio/mpl.c +++ b/subsys/bluetooth/audio/mpl.c @@ -295,6 +295,8 @@ static struct obj_t obj = { static void set_track_position(int32_t position); static void set_relative_track_position(int32_t rel_pos); +static void do_track_change_notifications(struct mpl_mediaplayer *pl); +static void do_group_change_notifications(struct mpl_mediaplayer *pl); /* Set up content buffer for the icon object */ static int setup_icon_object(void) @@ -925,7 +927,7 @@ void do_last_segment(struct mpl_mediaplayer *pl) LOG_DBG("Segment name after: %s", pl->group->track->segment->name); } -void do_goto_segment(struct mpl_mediaplayer *pl, int32_t segnum) +static void do_goto_segment(struct mpl_mediaplayer *pl, int32_t segnum) { int32_t k; @@ -962,47 +964,48 @@ void do_goto_segment(struct mpl_mediaplayer *pl, int32_t segnum) } LOG_DBG("Segment name after: %s", pl->group->track->segment->name); + + set_track_position(pl->group->track->segment->pos); } -static bool do_prev_track(struct mpl_mediaplayer *pl) +static void do_prev_track(struct mpl_mediaplayer *pl) { - bool track_changed = false; - #ifdef CONFIG_BT_MPL_OBJECTS LOG_DBG_OBJ_ID("Track ID before: ", pl->group->track->id); #endif /* CONFIG_BT_MPL_OBJECTS */ if (pl->group->track->prev != NULL) { pl->group->track = pl->group->track->prev; - track_changed = true; + pl->track_pos = 0; + do_track_change_notifications(pl); + } else { + /* For previous track, the position is reset to 0 */ + /* even if we stay at the same track (goto start of */ + /* track) */ + set_track_position(0); } #ifdef CONFIG_BT_MPL_OBJECTS LOG_DBG_OBJ_ID("Track ID after: ", pl->group->track->id); #endif /* CONFIG_BT_MPL_OBJECTS */ - - return track_changed; } /* Change to next track according to the current track's next track */ -static bool do_next_track_normal_order(struct mpl_mediaplayer *pl) +static void do_next_track_normal_order(struct mpl_mediaplayer *pl) { - bool track_changed = false; - #ifdef CONFIG_BT_MPL_OBJECTS LOG_DBG_OBJ_ID("Track ID before: ", pl->group->track->id); #endif /* CONFIG_BT_MPL_OBJECTS */ if (pl->group->track->next != NULL) { pl->group->track = pl->group->track->next; - track_changed = true; + pl->track_pos = 0; + do_track_change_notifications(pl); } #ifdef CONFIG_BT_MPL_OBJECTS LOG_DBG_OBJ_ID("Track ID after: ", pl->group->track->id); #endif /* CONFIG_BT_MPL_OBJECTS */ - - return track_changed; } /* Change to next track when the next track has been explicitly set @@ -1012,13 +1015,11 @@ static bool do_next_track_normal_order(struct mpl_mediaplayer *pl) * * Returns true if the _group_ has been changed, otherwise false */ -static bool do_next_track_next_track_set(struct mpl_mediaplayer *pl) +static void do_next_track_next_track_set(struct mpl_mediaplayer *pl) { - bool group_changed = false; - if (pl->next.group != pl->group) { pl->group = pl->next.group; - group_changed = true; + do_group_change_notifications(pl); } pl->group->track = pl->next.track; @@ -1026,22 +1027,36 @@ static bool do_next_track_next_track_set(struct mpl_mediaplayer *pl) pl->next.track = NULL; pl->next.group = NULL; pl->next_track_set = false; - - return group_changed; + pl->track_pos = 0; + do_track_change_notifications(pl); } -static bool do_first_track(struct mpl_mediaplayer *pl) +static void do_next_track(struct mpl_mediaplayer *pl) { - bool track_changed = false; + if (pl->next_track_set) { + LOG_DBG("Next track set"); + do_next_track_next_track_set(pl); + } else { + do_next_track_normal_order(pl); + } +} +static void do_first_track(struct mpl_mediaplayer *pl) +{ #ifdef CONFIG_BT_MPL_OBJECTS LOG_DBG_OBJ_ID("Track ID before: ", pl->group->track->id); #endif /* CONFIG_BT_MPL_OBJECTS */ if (pl->group->track->prev != NULL) { pl->group->track = pl->group->track->prev; - track_changed = true; + media_player.track_pos = 0; + do_track_change_notifications(&media_player); + } else { + /* For first track, the position is reset to 0 even */ + /* if we stay at the same track (goto start of track) */ + set_track_position(0); } + while (pl->group->track->prev != NULL) { pl->group->track = pl->group->track->prev; } @@ -1049,22 +1064,25 @@ static bool do_first_track(struct mpl_mediaplayer *pl) #ifdef CONFIG_BT_MPL_OBJECTS LOG_DBG_OBJ_ID("Track ID after: ", pl->group->track->id); #endif /* CONFIG_BT_MPL_OBJECTS */ - - return track_changed; } -static bool do_last_track(struct mpl_mediaplayer *pl) +static void do_last_track(struct mpl_mediaplayer *pl) { - bool track_changed = false; - #ifdef CONFIG_BT_MPL_OBJECTS LOG_DBG_OBJ_ID("Track ID before: ", pl->group->track->id); #endif /* CONFIG_BT_MPL_OBJECTS */ if (pl->group->track->next != NULL) { pl->group->track = pl->group->track->next; - track_changed = true; + media_player.track_pos = 0; + do_track_change_notifications(&media_player); + } else { + + /* For last track, the position is reset to 0 even */ + /* if we stay at the same track (goto start of track) */ + set_track_position(0); } + while (pl->group->track->next != NULL) { pl->group->track = pl->group->track->next; } @@ -1072,11 +1090,9 @@ static bool do_last_track(struct mpl_mediaplayer *pl) #ifdef CONFIG_BT_MPL_OBJECTS LOG_DBG_OBJ_ID("Track ID after: ", pl->group->track->id); #endif /* CONFIG_BT_MPL_OBJECTS */ - - return track_changed; } -static bool do_goto_track(struct mpl_mediaplayer *pl, int32_t tracknum) +static void do_goto_track(struct mpl_mediaplayer *pl, int32_t tracknum) { int32_t count = 0; int32_t k; @@ -1121,33 +1137,35 @@ static bool do_goto_track(struct mpl_mediaplayer *pl, int32_t tracknum) /* The track has changed if we have moved more in one direction */ /* than in the other */ - return (count != 0); + if (count != 0) { + media_player.track_pos = 0; + do_track_change_notifications(&media_player); + } else { + /* For goto track, the position is reset to 0 */ + /* even if we stay at the same track (goto */ + /* start of track) */ + set_track_position(0); + } } - -static bool do_prev_group(struct mpl_mediaplayer *pl) +static void do_prev_group(struct mpl_mediaplayer *pl) { - bool group_changed = false; - #ifdef CONFIG_BT_MPL_OBJECTS LOG_DBG_OBJ_ID("Group ID before: ", pl->group->id); #endif /* CONFIG_BT_MPL_OBJECTS */ if (pl->group->prev != NULL) { pl->group = pl->group->prev; - group_changed = true; + do_group_change_notifications(pl); } #ifdef CONFIG_BT_MPL_OBJECTS LOG_DBG_OBJ_ID("Group ID after: ", pl->group->id); #endif /* CONFIG_BT_MPL_OBJECTS */ - - return group_changed; } -static bool do_next_group(struct mpl_mediaplayer *pl) +static void do_next_group(struct mpl_mediaplayer *pl) { - bool group_changed = false; #ifdef CONFIG_BT_MPL_OBJECTS LOG_DBG_OBJ_ID("Group ID before: ", pl->group->id); @@ -1155,28 +1173,25 @@ static bool do_next_group(struct mpl_mediaplayer *pl) if (pl->group->next != NULL) { pl->group = pl->group->next; - group_changed = true; + do_group_change_notifications(pl); } #ifdef CONFIG_BT_MPL_OBJECTS LOG_DBG_OBJ_ID("Group ID after: ", pl->group->id); #endif /* CONFIG_BT_MPL_OBJECTS */ - - return group_changed; } -static bool do_first_group(struct mpl_mediaplayer *pl) +static void do_first_group(struct mpl_mediaplayer *pl) { - bool group_changed = false; - #ifdef CONFIG_BT_MPL_OBJECTS LOG_DBG_OBJ_ID("Group ID before: ", pl->group->id); #endif /* CONFIG_BT_MPL_OBJECTS */ if (pl->group->prev != NULL) { pl->group = pl->group->prev; - group_changed = true; + do_group_change_notifications(pl); } + while (pl->group->prev != NULL) { pl->group = pl->group->prev; } @@ -1184,22 +1199,19 @@ static bool do_first_group(struct mpl_mediaplayer *pl) #ifdef CONFIG_BT_MPL_OBJECTS LOG_DBG_OBJ_ID("Group ID after: ", pl->group->id); #endif /* CONFIG_BT_MPL_OBJECTS */ - - return group_changed; } -static bool do_last_group(struct mpl_mediaplayer *pl) +static void do_last_group(struct mpl_mediaplayer *pl) { - bool group_changed = false; - #ifdef CONFIG_BT_MPL_OBJECTS LOG_DBG_OBJ_ID("Group ID before: ", pl->group->id); #endif /* CONFIG_BT_MPL_OBJECTS */ if (pl->group->next != NULL) { pl->group = pl->group->next; - group_changed = true; + do_group_change_notifications(pl); } + while (pl->group->next != NULL) { pl->group = pl->group->next; } @@ -1207,11 +1219,9 @@ static bool do_last_group(struct mpl_mediaplayer *pl) #ifdef CONFIG_BT_MPL_OBJECTS LOG_DBG_OBJ_ID("Group ID after: ", pl->group->id); #endif /* CONFIG_BT_MPL_OBJECTS */ - - return group_changed; } -static bool do_goto_group(struct mpl_mediaplayer *pl, int32_t groupnum) +static void do_goto_group(struct mpl_mediaplayer *pl, int32_t groupnum) { int32_t count = 0; int32_t k; @@ -1256,10 +1266,12 @@ static bool do_goto_group(struct mpl_mediaplayer *pl, int32_t groupnum) /* The group has changed if we have moved more in one direction */ /* than in the other */ - return (count != 0); + if (count != 0) { + do_group_change_notifications(pl); + } } -void do_track_change_notifications(struct mpl_mediaplayer *pl) +static void do_track_change_notifications(struct mpl_mediaplayer *pl) { media_proxy_pl_track_changed_cb(); media_proxy_pl_track_title_cb(pl->group->track->title); @@ -1276,121 +1288,56 @@ void do_track_change_notifications(struct mpl_mediaplayer *pl) #endif /* CONFIG_BT_MPL_OBJECTS */ } -void do_group_change_notifications(struct mpl_mediaplayer *pl) +static void do_group_change_notifications(struct mpl_mediaplayer *pl) { #ifdef CONFIG_BT_MPL_OBJECTS media_proxy_pl_current_group_id_cb(pl->group->id); #endif /* CONFIG_BT_MPL_OBJECTS */ } -void do_full_prev_group(struct mpl_mediaplayer *pl) +static void do_full_prev_group(struct mpl_mediaplayer *pl) { /* Change the group (if not already on first group) */ - if (do_prev_group(pl)) { - do_group_change_notifications(pl); - /* If group change, also go to first track in group. */ - /* Notify the track info in all cases - it is a track */ - /* change for the player even if the group was set to */ - /* this track already. */ - (void) do_first_track(pl); - pl->track_pos = 0; - do_track_change_notifications(pl); - /* If no group change, still switch to first track, if needed */ - } else if (do_first_track(pl)) { - pl->track_pos = 0; - do_track_change_notifications(pl); - /* If no track change, still reset track position, if needed */ - } else if (pl->track_pos != 0) { - set_track_position(0); - } + do_prev_group(pl); + + /* Whether there is a group change or not, we always go to the first track */ + do_first_track(pl); } -void do_full_next_group(struct mpl_mediaplayer *pl) +static void do_full_next_group(struct mpl_mediaplayer *pl) { /* Change the group (if not already on last group) */ - if (do_next_group(pl)) { - do_group_change_notifications(pl); - /* If group change, also go to first track in group. */ - /* Notify the track info in all cases - it is a track */ - /* change for the player even if the group was set to */ - /* this track already. */ - (void) do_first_track(pl); - pl->track_pos = 0; - do_track_change_notifications(pl); - /* If no group change, still switch to first track, if needed */ - } else if (do_first_track(pl)) { - pl->track_pos = 0; - do_track_change_notifications(pl); - /* If no track change, still reset track position, if needed */ - } else if (pl->track_pos != 0) { - set_track_position(0); - } + do_next_group(pl); + + /* Whether there is a group change or not, we always go to the first track */ + do_first_track(pl); } -void do_full_first_group(struct mpl_mediaplayer *pl) +static void do_full_first_group(struct mpl_mediaplayer *pl) { /* Change the group (if not already on first group) */ - if (do_first_group(pl)) { - do_group_change_notifications(pl); - /* If group change, also go to first track in group. */ - /* Notify the track info in all cases - it is a track */ - /* change for the player even if the group was set to */ - /* this track already. */ - (void) do_first_track(pl); - pl->track_pos = 0; - do_track_change_notifications(pl); - /* If no group change, still switch to first track, if needed */ - } else if (do_first_track(pl)) { - pl->track_pos = 0; - do_track_change_notifications(pl); - /* If no track change, still reset track position, if needed */ - } else if (pl->track_pos != 0) { - set_track_position(0); - } + do_first_group(pl); + + /* Whether there is a group change or not, we always go to the first track */ + do_first_track(pl); } -void do_full_last_group(struct mpl_mediaplayer *pl) +static void do_full_last_group(struct mpl_mediaplayer *pl) { /* Change the group (if not already on last group) */ - if (do_last_group(pl)) { - do_group_change_notifications(pl); - /* If group change, also go to first track in group. */ - /* Notify the track info in all cases - it is a track */ - /* change for the player even if the group was set to */ - /* this track already. */ - (void) do_first_track(pl); - pl->track_pos = 0; - do_track_change_notifications(pl); - /* If no group change, still switch to first track, if needed */ - } else if (do_first_track(pl)) { - pl->track_pos = 0; - do_track_change_notifications(pl); - /* If no track change, still reset track position, if needed */ - } else if (pl->track_pos != 0) { - set_track_position(0); - } + do_last_group(pl); + + /* Whether there is a group change or not, we always go to the first track */ + do_first_track(pl); } -void do_full_goto_group(struct mpl_mediaplayer *pl, int32_t groupnum) +static void do_full_goto_group(struct mpl_mediaplayer *pl, int32_t groupnum) { /* Change the group (if not already on given group) */ - if (do_goto_group(pl, groupnum)) { - do_group_change_notifications(pl); - /* If group change, also go to first track in group. */ - /* Notify the track info in all cases - it is a track */ - /* change for the player even if the group was set to */ - /* this track already. */ - (void) do_first_track(pl); - pl->track_pos = 0; - do_track_change_notifications(pl); - /* If no group change, still switch to first track, if needed */ - } else if (do_first_track(pl)) { - pl->track_pos = 0; - do_track_change_notifications(pl); - /* If no track change, still reset track position, if needed */ - } else if (pl->track_pos != 0) { - set_track_position(0); - } + do_goto_group(pl, groupnum); + + /* Whether there is a group change or not, we always go to the first track */ + do_first_track(pl); } static void mpl_set_state(uint8_t state) @@ -1435,16 +1382,7 @@ void inactive_state_command_handler(const struct mpl_cmd *command, media_proxy_pl_command_cb(ntf); break; case MEDIA_PROXY_OP_PREV_TRACK: - if (do_prev_track(&media_player)) { - media_player.track_pos = 0; - do_track_change_notifications(&media_player); - } else { - /* For previous track, the position is reset to 0 */ - /* even if we stay at the same track (goto start of */ - /* track) */ - set_track_position(0); - } - + do_prev_track(&media_player); mpl_set_state(MEDIA_PROXY_STATE_PAUSED); ntf->result_code = MEDIA_PROXY_CMD_SUCCESS; media_proxy_pl_command_cb(ntf); @@ -1454,17 +1392,7 @@ void inactive_state_command_handler(const struct mpl_cmd *command, * The case where the next track has been set explicitly breaks somewhat * with the "next" order hardcoded into the group and track structure */ - if (media_player.next_track_set) { - LOG_DBG("Next track set"); - if (do_next_track_next_track_set(&media_player)) { - do_group_change_notifications(&media_player); - } - media_player.track_pos = 0; - do_track_change_notifications(&media_player); - } else if (do_next_track_normal_order(&media_player)) { - media_player.track_pos = 0; - do_track_change_notifications(&media_player); - } + do_next_track(&media_player); /* For next track, the position is kept if the track */ /* does not change */ @@ -1473,45 +1401,20 @@ void inactive_state_command_handler(const struct mpl_cmd *command, media_proxy_pl_command_cb(ntf); break; case MEDIA_PROXY_OP_FIRST_TRACK: - if (do_first_track(&media_player)) { - media_player.track_pos = 0; - do_track_change_notifications(&media_player); - } else { - /* For first track, the position is reset to 0 even */ - /* if we stay at the same track (goto start of track) */ - set_track_position(0); - } - + do_first_track(&media_player); mpl_set_state(MEDIA_PROXY_STATE_PAUSED); ntf->result_code = MEDIA_PROXY_CMD_SUCCESS; media_proxy_pl_command_cb(ntf); break; case MEDIA_PROXY_OP_LAST_TRACK: - if (do_last_track(&media_player)) { - media_player.track_pos = 0; - do_track_change_notifications(&media_player); - } else { - /* For last track, the position is reset to 0 even */ - /* if we stay at the same track (goto start of track) */ - set_track_position(0); - } - + do_last_track(&media_player); mpl_set_state(MEDIA_PROXY_STATE_PAUSED); ntf->result_code = MEDIA_PROXY_CMD_SUCCESS; media_proxy_pl_command_cb(ntf); break; case MEDIA_PROXY_OP_GOTO_TRACK: if (command->use_param) { - if (do_goto_track(&media_player, command->param)) { - media_player.track_pos = 0; - do_track_change_notifications(&media_player); - } else { - /* For goto track, the position is reset to 0 */ - /* even if we stay at the same track (goto */ - /* start of track) */ - set_track_position(0); - } - + do_goto_track(&media_player, command->param); mpl_set_state(MEDIA_PROXY_STATE_PAUSED); ntf->result_code = MEDIA_PROXY_CMD_SUCCESS; } else { @@ -1645,7 +1548,6 @@ void playing_state_command_handler(const struct mpl_cmd *command, if (command->use_param) { if (command->param != 0) { do_goto_segment(&media_player, command->param); - set_track_position(media_player.group->track->segment->pos); } /* If the argument to "goto segment" is zero, */ /* the segment shall stay the same, and the */ @@ -1657,70 +1559,30 @@ void playing_state_command_handler(const struct mpl_cmd *command, media_proxy_pl_command_cb(ntf); break; case MEDIA_PROXY_OP_PREV_TRACK: - if (do_prev_track(&media_player)) { - media_player.track_pos = 0; - do_track_change_notifications(&media_player); - } else { - /* For previous track, the position is reset to 0 */ - /* even if we stay at the same track (goto start of */ - /* track) */ - set_track_position(0); - } + do_prev_track(&media_player); ntf->result_code = MEDIA_PROXY_CMD_SUCCESS; media_proxy_pl_command_cb(ntf); break; case MEDIA_PROXY_OP_NEXT_TRACK: - if (media_player.next_track_set) { - LOG_DBG("Next track set"); - if (do_next_track_next_track_set(&media_player)) { - do_group_change_notifications(&media_player); - } - media_player.track_pos = 0; - do_track_change_notifications(&media_player); - } else if (do_next_track_normal_order(&media_player)) { - media_player.track_pos = 0; - do_track_change_notifications(&media_player); - } + do_next_track(&media_player); /* For next track, the position is kept if the track */ /* does not change */ ntf->result_code = MEDIA_PROXY_CMD_SUCCESS; media_proxy_pl_command_cb(ntf); break; case MEDIA_PROXY_OP_FIRST_TRACK: - if (do_first_track(&media_player)) { - media_player.track_pos = 0; - do_track_change_notifications(&media_player); - } else { - /* For first track, the position is reset to 0 even */ - /* if we stay at the same track (goto start of track) */ - set_track_position(0); - } + do_first_track(&media_player); ntf->result_code = MEDIA_PROXY_CMD_SUCCESS; media_proxy_pl_command_cb(ntf); break; case MEDIA_PROXY_OP_LAST_TRACK: - if (do_last_track(&media_player)) { - media_player.track_pos = 0; - do_track_change_notifications(&media_player); - } else { - /* For last track, the position is reset to 0 even */ - /* if we stay at the same track (goto start of track) */ - set_track_position(0); - } + do_last_track(&media_player); ntf->result_code = MEDIA_PROXY_CMD_SUCCESS; media_proxy_pl_command_cb(ntf); break; case MEDIA_PROXY_OP_GOTO_TRACK: if (command->use_param) { - if (do_goto_track(&media_player, command->param)) { - media_player.track_pos = 0; - do_track_change_notifications(&media_player); - } else { - /* For goto track, the position is reset to 0 */ - /* even if we stay at the same track (goto */ - /* start of track) */ - set_track_position(0); - } + do_goto_track(&media_player, command->param); ntf->result_code = MEDIA_PROXY_CMD_SUCCESS; } else { ntf->result_code = MEDIA_PROXY_CMD_CANNOT_BE_COMPLETED; @@ -1869,7 +1731,6 @@ void paused_state_command_handler(const struct mpl_cmd *command, if (command->use_param && media_player.group->track->segment != NULL) { if (command->param != 0) { do_goto_segment(&media_player, command->param); - set_track_position(media_player.group->track->segment->pos); } /* If the argument to "goto segment" is zero, */ /* the segment shall stay the same, and the */ @@ -1881,70 +1742,30 @@ void paused_state_command_handler(const struct mpl_cmd *command, media_proxy_pl_command_cb(ntf); break; case MEDIA_PROXY_OP_PREV_TRACK: - if (do_prev_track(&media_player)) { - media_player.track_pos = 0; - do_track_change_notifications(&media_player); - } else { - /* For previous track, the position is reset to 0 */ - /* even if we stay at the same track (goto start of */ - /* track) */ - set_track_position(0); - } + do_prev_track(&media_player); ntf->result_code = MEDIA_PROXY_CMD_SUCCESS; media_proxy_pl_command_cb(ntf); break; case MEDIA_PROXY_OP_NEXT_TRACK: - if (media_player.next_track_set) { - LOG_DBG("Next track set"); - if (do_next_track_next_track_set(&media_player)) { - do_group_change_notifications(&media_player); - } - media_player.track_pos = 0; - do_track_change_notifications(&media_player); - } else if (do_next_track_normal_order(&media_player)) { - media_player.track_pos = 0; - do_track_change_notifications(&media_player); - } + do_next_track(&media_player); /* For next track, the position is kept if the track */ /* does not change */ ntf->result_code = MEDIA_PROXY_CMD_SUCCESS; media_proxy_pl_command_cb(ntf); break; case MEDIA_PROXY_OP_FIRST_TRACK: - if (do_first_track(&media_player)) { - media_player.track_pos = 0; - do_track_change_notifications(&media_player); - } else { - /* For first track, the position is reset to 0 even */ - /* if we stay at the same track (goto start of track) */ - set_track_position(0); - } + do_first_track(&media_player); ntf->result_code = MEDIA_PROXY_CMD_SUCCESS; media_proxy_pl_command_cb(ntf); break; case MEDIA_PROXY_OP_LAST_TRACK: - if (do_last_track(&media_player)) { - media_player.track_pos = 0; - do_track_change_notifications(&media_player); - } else { - /* For last track, the position is reset to 0 even */ - /* if we stay at the same track (goto start of track) */ - set_track_position(0); - } + do_last_track(&media_player); ntf->result_code = MEDIA_PROXY_CMD_SUCCESS; media_proxy_pl_command_cb(ntf); break; case MEDIA_PROXY_OP_GOTO_TRACK: if (command->use_param) { - if (do_goto_track(&media_player, command->param)) { - media_player.track_pos = 0; - do_track_change_notifications(&media_player); - } else { - /* For goto track, the position is reset to 0 */ - /* even if we stay at the same track (goto */ - /* start of track) */ - set_track_position(0); - } + do_goto_track(&media_player, command->param); ntf->result_code = MEDIA_PROXY_CMD_SUCCESS; } else { ntf->result_code = MEDIA_PROXY_CMD_CANNOT_BE_COMPLETED; @@ -2088,7 +1909,6 @@ void seeking_state_command_handler(const struct mpl_cmd *command, if (command->use_param) { if (command->param != 0) { do_goto_segment(&media_player, command->param); - set_track_position(media_player.group->track->segment->pos); } /* If the argument to "goto segment" is zero, */ /* the segment shall stay the same, and the */ @@ -2100,32 +1920,14 @@ void seeking_state_command_handler(const struct mpl_cmd *command, media_proxy_pl_command_cb(ntf); break; case MEDIA_PROXY_OP_PREV_TRACK: - if (do_prev_track(&media_player)) { - media_player.track_pos = 0; - do_track_change_notifications(&media_player); - } else { - /* For previous track, the position is reset to 0 */ - /* even if we stay at the same track (goto start of */ - /* track) */ - set_track_position(0); - } + do_prev_track(&media_player); media_player.seeking_speed_factor = MEDIA_PROXY_SEEKING_SPEED_FACTOR_ZERO; mpl_set_state(MEDIA_PROXY_STATE_PAUSED); ntf->result_code = MEDIA_PROXY_CMD_SUCCESS; media_proxy_pl_command_cb(ntf); break; case MEDIA_PROXY_OP_NEXT_TRACK: - if (media_player.next_track_set) { - LOG_DBG("Next track set"); - if (do_next_track_next_track_set(&media_player)) { - do_group_change_notifications(&media_player); - } - media_player.track_pos = 0; - do_track_change_notifications(&media_player); - } else if (do_next_track_normal_order(&media_player)) { - media_player.track_pos = 0; - do_track_change_notifications(&media_player); - } + do_next_track(&media_player); /* For next track, the position is kept if the track */ /* does not change */ media_player.seeking_speed_factor = MEDIA_PROXY_SEEKING_SPEED_FACTOR_ZERO; @@ -2134,28 +1936,14 @@ void seeking_state_command_handler(const struct mpl_cmd *command, media_proxy_pl_command_cb(ntf); break; case MEDIA_PROXY_OP_FIRST_TRACK: - if (do_first_track(&media_player)) { - media_player.track_pos = 0; - do_track_change_notifications(&media_player); - } else { - /* For first track, the position is reset to 0 even */ - /* if we stay at the same track (goto start of track) */ - set_track_position(0); - } + do_first_track(&media_player); media_player.seeking_speed_factor = MEDIA_PROXY_SEEKING_SPEED_FACTOR_ZERO; mpl_set_state(MEDIA_PROXY_STATE_PAUSED); ntf->result_code = MEDIA_PROXY_CMD_SUCCESS; media_proxy_pl_command_cb(ntf); break; case MEDIA_PROXY_OP_LAST_TRACK: - if (do_last_track(&media_player)) { - media_player.track_pos = 0; - do_track_change_notifications(&media_player); - } else { - /* For last track, the position is reset to 0 even */ - /* if we stay at the same track (goto start of track) */ - set_track_position(0); - } + do_last_track(&media_player); media_player.seeking_speed_factor = MEDIA_PROXY_SEEKING_SPEED_FACTOR_ZERO; mpl_set_state(MEDIA_PROXY_STATE_PAUSED); ntf->result_code = MEDIA_PROXY_CMD_SUCCESS; @@ -2163,15 +1951,7 @@ void seeking_state_command_handler(const struct mpl_cmd *command, break; case MEDIA_PROXY_OP_GOTO_TRACK: if (command->use_param) { - if (do_goto_track(&media_player, command->param)) { - media_player.track_pos = 0; - do_track_change_notifications(&media_player); - } else { - /* For goto track, the position is reset to 0 */ - /* even if we stay at the same track (goto */ - /* start of track) */ - set_track_position(0); - } + do_goto_track(&media_player, command->param); media_player.seeking_speed_factor = MEDIA_PROXY_SEEKING_SPEED_FACTOR_ZERO; mpl_set_state(MEDIA_PROXY_STATE_PAUSED); ntf->result_code = MEDIA_PROXY_CMD_SUCCESS; @@ -2490,7 +2270,6 @@ uint64_t get_current_group_id(void) void set_current_group_id(uint64_t id) { struct mpl_group *group; - bool track_change; LOG_DBG_OBJ_ID("Group ID to set: ", id); @@ -2502,10 +2281,7 @@ void set_current_group_id(uint64_t id) do_group_change_notifications(&media_player); /* And change to first track in group */ - track_change = do_first_track(&media_player); - if (track_change) { - do_track_change_notifications(&media_player); - } + do_first_track(&media_player); } return; } From a8fbab6b1a52a9f6e1c9786e3e45baf5ff671f87 Mon Sep 17 00:00:00 2001 From: Emil Gydesen Date: Fri, 8 Dec 2023 14:29:59 +0100 Subject: [PATCH 1303/3723] Bluetooth: MPL: Simplify control point ops Simplify how control point operations are handled, and reduce code duplication. Signed-off-by: Emil Gydesen --- subsys/bluetooth/audio/mpl.c | 248 +++++++++-------------------------- 1 file changed, 60 insertions(+), 188 deletions(-) diff --git a/subsys/bluetooth/audio/mpl.c b/subsys/bluetooth/audio/mpl.c index d4b26b5d125..745b34d703a 100644 --- a/subsys/bluetooth/audio/mpl.c +++ b/subsys/bluetooth/audio/mpl.c @@ -1357,9 +1357,10 @@ static void mpl_set_state(uint8_t state) } /* Command handlers (state machines) */ -void inactive_state_command_handler(const struct mpl_cmd *command, - struct mpl_cmd_ntf *ntf) +static uint8_t inactive_state_command_handler(const struct mpl_cmd *command) { + uint8_t result_code = MEDIA_PROXY_CMD_SUCCESS; + LOG_DBG("Command opcode: %d", command->opcode); if (IS_ENABLED(CONFIG_BT_MPL_LOG_LEVEL_DBG)) { if (command->use_param) { @@ -1378,14 +1379,11 @@ void inactive_state_command_handler(const struct mpl_cmd *command, case MEDIA_PROXY_OP_FIRST_SEGMENT: case MEDIA_PROXY_OP_LAST_SEGMENT: case MEDIA_PROXY_OP_GOTO_SEGMENT: - ntf->result_code = MEDIA_PROXY_CMD_PLAYER_INACTIVE; - media_proxy_pl_command_cb(ntf); + result_code = MEDIA_PROXY_CMD_PLAYER_INACTIVE; break; case MEDIA_PROXY_OP_PREV_TRACK: do_prev_track(&media_player); mpl_set_state(MEDIA_PROXY_STATE_PAUSED); - ntf->result_code = MEDIA_PROXY_CMD_SUCCESS; - media_proxy_pl_command_cb(ntf); break; case MEDIA_PROXY_OP_NEXT_TRACK: /* TODO: @@ -1397,123 +1395,98 @@ void inactive_state_command_handler(const struct mpl_cmd *command, /* For next track, the position is kept if the track */ /* does not change */ mpl_set_state(MEDIA_PROXY_STATE_PAUSED); - ntf->result_code = MEDIA_PROXY_CMD_SUCCESS; - media_proxy_pl_command_cb(ntf); break; case MEDIA_PROXY_OP_FIRST_TRACK: do_first_track(&media_player); mpl_set_state(MEDIA_PROXY_STATE_PAUSED); - ntf->result_code = MEDIA_PROXY_CMD_SUCCESS; - media_proxy_pl_command_cb(ntf); break; case MEDIA_PROXY_OP_LAST_TRACK: do_last_track(&media_player); mpl_set_state(MEDIA_PROXY_STATE_PAUSED); - ntf->result_code = MEDIA_PROXY_CMD_SUCCESS; - media_proxy_pl_command_cb(ntf); break; case MEDIA_PROXY_OP_GOTO_TRACK: if (command->use_param) { do_goto_track(&media_player, command->param); mpl_set_state(MEDIA_PROXY_STATE_PAUSED); - ntf->result_code = MEDIA_PROXY_CMD_SUCCESS; } else { - ntf->result_code = MEDIA_PROXY_CMD_CANNOT_BE_COMPLETED; + result_code = MEDIA_PROXY_CMD_CANNOT_BE_COMPLETED; } - media_proxy_pl_command_cb(ntf); break; case MEDIA_PROXY_OP_PREV_GROUP: do_full_prev_group(&media_player); mpl_set_state(MEDIA_PROXY_STATE_PAUSED); - ntf->result_code = MEDIA_PROXY_CMD_SUCCESS; - media_proxy_pl_command_cb(ntf); break; case MEDIA_PROXY_OP_NEXT_GROUP: do_full_next_group(&media_player); mpl_set_state(MEDIA_PROXY_STATE_PAUSED); - ntf->result_code = MEDIA_PROXY_CMD_SUCCESS; - media_proxy_pl_command_cb(ntf); break; case MEDIA_PROXY_OP_FIRST_GROUP: do_full_first_group(&media_player); mpl_set_state(MEDIA_PROXY_STATE_PAUSED); - ntf->result_code = MEDIA_PROXY_CMD_SUCCESS; - media_proxy_pl_command_cb(ntf); break; case MEDIA_PROXY_OP_LAST_GROUP: do_full_last_group(&media_player); mpl_set_state(MEDIA_PROXY_STATE_PAUSED); - ntf->result_code = MEDIA_PROXY_CMD_SUCCESS; - media_proxy_pl_command_cb(ntf); break; case MEDIA_PROXY_OP_GOTO_GROUP: if (command->use_param) { do_full_goto_group(&media_player, command->param); mpl_set_state(MEDIA_PROXY_STATE_PAUSED); - ntf->result_code = MEDIA_PROXY_CMD_SUCCESS; } else { - ntf->result_code = MEDIA_PROXY_CMD_CANNOT_BE_COMPLETED; + result_code = MEDIA_PROXY_CMD_CANNOT_BE_COMPLETED; } - media_proxy_pl_command_cb(ntf); + break; default: LOG_DBG("Invalid command: %d", command->opcode); - ntf->result_code = MEDIA_PROXY_CMD_NOT_SUPPORTED; - media_proxy_pl_command_cb(ntf); + result_code = MEDIA_PROXY_CMD_NOT_SUPPORTED; break; } + + return result_code; } -void playing_state_command_handler(const struct mpl_cmd *command, - struct mpl_cmd_ntf *ntf) +static uint8_t playing_state_command_handler(const struct mpl_cmd *command) { + uint8_t result_code = MEDIA_PROXY_CMD_SUCCESS; + LOG_DBG("Command opcode: %d", command->opcode); if (IS_ENABLED(CONFIG_BT_MPL_LOG_LEVEL_DBG)) { if (command->use_param) { LOG_DBG("Command parameter: %d", command->param); } } + switch (command->opcode) { case MEDIA_PROXY_OP_PLAY: /* Continue playing - i.e. do nothing */ - ntf->result_code = MEDIA_PROXY_CMD_SUCCESS; - media_proxy_pl_command_cb(ntf); break; case MEDIA_PROXY_OP_PAUSE: mpl_set_state(MEDIA_PROXY_STATE_PAUSED); - ntf->result_code = MEDIA_PROXY_CMD_SUCCESS; - media_proxy_pl_command_cb(ntf); break; case MEDIA_PROXY_OP_FAST_REWIND: /* We're in playing state, seeking speed must have been zero */ media_player.seeking_speed_factor = -MPL_SEEKING_SPEED_FACTOR_STEP; mpl_set_state(MEDIA_PROXY_STATE_SEEKING); media_proxy_pl_seeking_speed_cb(media_player.seeking_speed_factor); - ntf->result_code = MEDIA_PROXY_CMD_SUCCESS; - media_proxy_pl_command_cb(ntf); break; case MEDIA_PROXY_OP_FAST_FORWARD: /* We're in playing state, seeking speed must have been zero */ media_player.seeking_speed_factor = MPL_SEEKING_SPEED_FACTOR_STEP; mpl_set_state(MEDIA_PROXY_STATE_SEEKING); media_proxy_pl_seeking_speed_cb(media_player.seeking_speed_factor); - ntf->result_code = MEDIA_PROXY_CMD_SUCCESS; - media_proxy_pl_command_cb(ntf); break; case MEDIA_PROXY_OP_STOP: set_track_position(0); mpl_set_state(MEDIA_PROXY_STATE_PAUSED); - ntf->result_code = MEDIA_PROXY_CMD_SUCCESS; - media_proxy_pl_command_cb(ntf); break; case MEDIA_PROXY_OP_MOVE_RELATIVE: if (command->use_param) { set_relative_track_position(command->param); - ntf->result_code = MEDIA_PROXY_CMD_SUCCESS; } else { - ntf->result_code = MEDIA_PROXY_CMD_CANNOT_BE_COMPLETED; + result_code = MEDIA_PROXY_CMD_CANNOT_BE_COMPLETED; } - media_proxy_pl_command_cb(ntf); + break; case MEDIA_PROXY_OP_PREV_SEGMENT: /* Switch to previous segment if we are less than */ @@ -1523,26 +1496,18 @@ void playing_state_command_handler(const struct mpl_cmd *command, do_prev_segment(&media_player); } set_track_position(media_player.group->track->segment->pos); - ntf->result_code = MEDIA_PROXY_CMD_SUCCESS; - media_proxy_pl_command_cb(ntf); break; case MEDIA_PROXY_OP_NEXT_SEGMENT: do_next_segment(&media_player); set_track_position(media_player.group->track->segment->pos); - ntf->result_code = MEDIA_PROXY_CMD_SUCCESS; - media_proxy_pl_command_cb(ntf); break; case MEDIA_PROXY_OP_FIRST_SEGMENT: do_first_segment(&media_player); set_track_position(media_player.group->track->segment->pos); - ntf->result_code = MEDIA_PROXY_CMD_SUCCESS; - media_proxy_pl_command_cb(ntf); break; case MEDIA_PROXY_OP_LAST_SEGMENT: do_last_segment(&media_player); set_track_position(media_player.group->track->segment->pos); - ntf->result_code = MEDIA_PROXY_CMD_SUCCESS; - media_proxy_pl_command_cb(ntf); break; case MEDIA_PROXY_OP_GOTO_SEGMENT: if (command->use_param) { @@ -1552,130 +1517,100 @@ void playing_state_command_handler(const struct mpl_cmd *command, /* If the argument to "goto segment" is zero, */ /* the segment shall stay the same, and the */ /* track position shall not change. */ - ntf->result_code = MEDIA_PROXY_CMD_SUCCESS; } else { - ntf->result_code = MEDIA_PROXY_CMD_CANNOT_BE_COMPLETED; + result_code = MEDIA_PROXY_CMD_CANNOT_BE_COMPLETED; } - media_proxy_pl_command_cb(ntf); + break; case MEDIA_PROXY_OP_PREV_TRACK: do_prev_track(&media_player); - ntf->result_code = MEDIA_PROXY_CMD_SUCCESS; - media_proxy_pl_command_cb(ntf); break; case MEDIA_PROXY_OP_NEXT_TRACK: do_next_track(&media_player); - /* For next track, the position is kept if the track */ - /* does not change */ - ntf->result_code = MEDIA_PROXY_CMD_SUCCESS; - media_proxy_pl_command_cb(ntf); break; case MEDIA_PROXY_OP_FIRST_TRACK: do_first_track(&media_player); - ntf->result_code = MEDIA_PROXY_CMD_SUCCESS; - media_proxy_pl_command_cb(ntf); break; case MEDIA_PROXY_OP_LAST_TRACK: do_last_track(&media_player); - ntf->result_code = MEDIA_PROXY_CMD_SUCCESS; - media_proxy_pl_command_cb(ntf); break; case MEDIA_PROXY_OP_GOTO_TRACK: if (command->use_param) { do_goto_track(&media_player, command->param); - ntf->result_code = MEDIA_PROXY_CMD_SUCCESS; } else { - ntf->result_code = MEDIA_PROXY_CMD_CANNOT_BE_COMPLETED; + result_code = MEDIA_PROXY_CMD_CANNOT_BE_COMPLETED; } - media_proxy_pl_command_cb(ntf); + break; case MEDIA_PROXY_OP_PREV_GROUP: do_full_prev_group(&media_player); - ntf->result_code = MEDIA_PROXY_CMD_SUCCESS; - media_proxy_pl_command_cb(ntf); break; case MEDIA_PROXY_OP_NEXT_GROUP: do_full_next_group(&media_player); - ntf->result_code = MEDIA_PROXY_CMD_SUCCESS; - media_proxy_pl_command_cb(ntf); break; case MEDIA_PROXY_OP_FIRST_GROUP: do_full_first_group(&media_player); - ntf->result_code = MEDIA_PROXY_CMD_SUCCESS; - media_proxy_pl_command_cb(ntf); break; case MEDIA_PROXY_OP_LAST_GROUP: do_full_last_group(&media_player); - ntf->result_code = MEDIA_PROXY_CMD_SUCCESS; - media_proxy_pl_command_cb(ntf); break; case MEDIA_PROXY_OP_GOTO_GROUP: if (command->use_param) { do_full_goto_group(&media_player, command->param); - ntf->result_code = MEDIA_PROXY_CMD_SUCCESS; } else { - ntf->result_code = MEDIA_PROXY_CMD_CANNOT_BE_COMPLETED; + result_code = MEDIA_PROXY_CMD_CANNOT_BE_COMPLETED; } - media_proxy_pl_command_cb(ntf); break; default: LOG_DBG("Invalid command: %d", command->opcode); - ntf->result_code = MEDIA_PROXY_CMD_NOT_SUPPORTED; - media_proxy_pl_command_cb(ntf); + result_code = MEDIA_PROXY_CMD_NOT_SUPPORTED; break; } + + return result_code; } -void paused_state_command_handler(const struct mpl_cmd *command, - struct mpl_cmd_ntf *ntf) +static uint8_t paused_state_command_handler(const struct mpl_cmd *command) { + uint8_t result_code = MEDIA_PROXY_CMD_SUCCESS; + LOG_DBG("Command opcode: %d", command->opcode); if (IS_ENABLED(CONFIG_BT_MPL_LOG_LEVEL_DBG)) { if (command->use_param) { LOG_DBG("Command parameter: %d", command->param); } } + switch (command->opcode) { case MEDIA_PROXY_OP_PLAY: mpl_set_state(MEDIA_PROXY_STATE_PLAYING); - ntf->result_code = MEDIA_PROXY_CMD_SUCCESS; - media_proxy_pl_command_cb(ntf); break; case MEDIA_PROXY_OP_PAUSE: /* No change */ - ntf->result_code = MEDIA_PROXY_CMD_SUCCESS; - media_proxy_pl_command_cb(ntf); break; case MEDIA_PROXY_OP_FAST_REWIND: /* We're in paused state, seeking speed must have been zero */ media_player.seeking_speed_factor = -MPL_SEEKING_SPEED_FACTOR_STEP; mpl_set_state(MEDIA_PROXY_STATE_SEEKING); media_proxy_pl_seeking_speed_cb(media_player.seeking_speed_factor); - ntf->result_code = MEDIA_PROXY_CMD_SUCCESS; - media_proxy_pl_command_cb(ntf); break; case MEDIA_PROXY_OP_FAST_FORWARD: /* We're in paused state, seeking speed must have been zero */ media_player.seeking_speed_factor = MPL_SEEKING_SPEED_FACTOR_STEP; mpl_set_state(MEDIA_PROXY_STATE_SEEKING); media_proxy_pl_seeking_speed_cb(media_player.seeking_speed_factor); - ntf->result_code = MEDIA_PROXY_CMD_SUCCESS; - media_proxy_pl_command_cb(ntf); break; case MEDIA_PROXY_OP_STOP: set_track_position(0); mpl_set_state(MEDIA_PROXY_STATE_PAUSED); - ntf->result_code = MEDIA_PROXY_CMD_SUCCESS; - media_proxy_pl_command_cb(ntf); break; case MEDIA_PROXY_OP_MOVE_RELATIVE: if (command->use_param) { set_relative_track_position(command->param); - ntf->result_code = MEDIA_PROXY_CMD_SUCCESS; } else { - ntf->result_code = MEDIA_PROXY_CMD_CANNOT_BE_COMPLETED; + result_code = MEDIA_PROXY_CMD_CANNOT_BE_COMPLETED; } - media_proxy_pl_command_cb(ntf); + break; case MEDIA_PROXY_OP_PREV_SEGMENT: /* Switch to previous segment if we are less than 5 seconds */ @@ -1687,45 +1622,37 @@ void paused_state_command_handler(const struct mpl_cmd *command, } set_track_position(media_player.group->track->segment->pos); - ntf->result_code = MEDIA_PROXY_CMD_SUCCESS; } else { - ntf->result_code = MEDIA_PROXY_CMD_CANNOT_BE_COMPLETED; + result_code = MEDIA_PROXY_CMD_CANNOT_BE_COMPLETED; } - media_proxy_pl_command_cb(ntf); break; case MEDIA_PROXY_OP_NEXT_SEGMENT: if (media_player.group->track->segment != NULL) { do_next_segment(&media_player); set_track_position(media_player.group->track->segment->pos); - ntf->result_code = MEDIA_PROXY_CMD_SUCCESS; } else { - ntf->result_code = MEDIA_PROXY_CMD_CANNOT_BE_COMPLETED; + result_code = MEDIA_PROXY_CMD_CANNOT_BE_COMPLETED; } - media_proxy_pl_command_cb(ntf); break; case MEDIA_PROXY_OP_FIRST_SEGMENT: if (media_player.group->track->segment != NULL) { do_first_segment(&media_player); set_track_position(media_player.group->track->segment->pos); - ntf->result_code = MEDIA_PROXY_CMD_SUCCESS; } else { - ntf->result_code = MEDIA_PROXY_CMD_CANNOT_BE_COMPLETED; + result_code = MEDIA_PROXY_CMD_CANNOT_BE_COMPLETED; } - media_proxy_pl_command_cb(ntf); break; case MEDIA_PROXY_OP_LAST_SEGMENT: if (media_player.group->track->segment != NULL) { do_last_segment(&media_player); set_track_position(media_player.group->track->segment->pos); - ntf->result_code = MEDIA_PROXY_CMD_SUCCESS; } else { - ntf->result_code = MEDIA_PROXY_CMD_CANNOT_BE_COMPLETED; + result_code = MEDIA_PROXY_CMD_CANNOT_BE_COMPLETED; } - media_proxy_pl_command_cb(ntf); break; case MEDIA_PROXY_OP_GOTO_SEGMENT: if (command->use_param && media_player.group->track->segment != NULL) { @@ -1735,104 +1662,84 @@ void paused_state_command_handler(const struct mpl_cmd *command, /* If the argument to "goto segment" is zero, */ /* the segment shall stay the same, and the */ /* track position shall not change. */ - ntf->result_code = MEDIA_PROXY_CMD_SUCCESS; } else { - ntf->result_code = MEDIA_PROXY_CMD_CANNOT_BE_COMPLETED; + result_code = MEDIA_PROXY_CMD_CANNOT_BE_COMPLETED; } - media_proxy_pl_command_cb(ntf); + break; case MEDIA_PROXY_OP_PREV_TRACK: do_prev_track(&media_player); - ntf->result_code = MEDIA_PROXY_CMD_SUCCESS; - media_proxy_pl_command_cb(ntf); break; case MEDIA_PROXY_OP_NEXT_TRACK: do_next_track(&media_player); /* For next track, the position is kept if the track */ /* does not change */ - ntf->result_code = MEDIA_PROXY_CMD_SUCCESS; - media_proxy_pl_command_cb(ntf); break; case MEDIA_PROXY_OP_FIRST_TRACK: do_first_track(&media_player); - ntf->result_code = MEDIA_PROXY_CMD_SUCCESS; - media_proxy_pl_command_cb(ntf); break; case MEDIA_PROXY_OP_LAST_TRACK: do_last_track(&media_player); - ntf->result_code = MEDIA_PROXY_CMD_SUCCESS; - media_proxy_pl_command_cb(ntf); break; case MEDIA_PROXY_OP_GOTO_TRACK: if (command->use_param) { do_goto_track(&media_player, command->param); - ntf->result_code = MEDIA_PROXY_CMD_SUCCESS; } else { - ntf->result_code = MEDIA_PROXY_CMD_CANNOT_BE_COMPLETED; + result_code = MEDIA_PROXY_CMD_CANNOT_BE_COMPLETED; } - media_proxy_pl_command_cb(ntf); + break; case MEDIA_PROXY_OP_PREV_GROUP: do_full_prev_group(&media_player); - ntf->result_code = MEDIA_PROXY_CMD_SUCCESS; - media_proxy_pl_command_cb(ntf); break; case MEDIA_PROXY_OP_NEXT_GROUP: do_full_next_group(&media_player); - ntf->result_code = MEDIA_PROXY_CMD_SUCCESS; - media_proxy_pl_command_cb(ntf); break; case MEDIA_PROXY_OP_FIRST_GROUP: do_full_first_group(&media_player); - ntf->result_code = MEDIA_PROXY_CMD_SUCCESS; - media_proxy_pl_command_cb(ntf); break; case MEDIA_PROXY_OP_LAST_GROUP: do_full_last_group(&media_player); - ntf->result_code = MEDIA_PROXY_CMD_SUCCESS; - media_proxy_pl_command_cb(ntf); break; case MEDIA_PROXY_OP_GOTO_GROUP: if (command->use_param) { do_full_goto_group(&media_player, command->param); - ntf->result_code = MEDIA_PROXY_CMD_SUCCESS; } else { - ntf->result_code = MEDIA_PROXY_CMD_CANNOT_BE_COMPLETED; + result_code = MEDIA_PROXY_CMD_CANNOT_BE_COMPLETED; } - media_proxy_pl_command_cb(ntf); + break; default: LOG_DBG("Invalid command: %d", command->opcode); - ntf->result_code = MEDIA_PROXY_CMD_NOT_SUPPORTED; - media_proxy_pl_command_cb(ntf); + result_code = MEDIA_PROXY_CMD_NOT_SUPPORTED; break; } + + return result_code; } -void seeking_state_command_handler(const struct mpl_cmd *command, - struct mpl_cmd_ntf *ntf) +static uint8_t seeking_state_command_handler(const struct mpl_cmd *command) { + uint8_t result_code = MEDIA_PROXY_CMD_SUCCESS; + LOG_DBG("Command opcode: %d", command->opcode); if (IS_ENABLED(CONFIG_BT_MPL_LOG_LEVEL_DBG)) { if (command->use_param) { LOG_DBG("Command parameter: %d", command->param); } } + switch (command->opcode) { case MEDIA_PROXY_OP_PLAY: media_player.seeking_speed_factor = MEDIA_PROXY_SEEKING_SPEED_FACTOR_ZERO; mpl_set_state(MEDIA_PROXY_STATE_PLAYING); media_proxy_pl_seeking_speed_cb(media_player.seeking_speed_factor); - ntf->result_code = MEDIA_PROXY_CMD_SUCCESS; - media_proxy_pl_command_cb(ntf); break; case MEDIA_PROXY_OP_PAUSE: media_player.seeking_speed_factor = MEDIA_PROXY_SEEKING_SPEED_FACTOR_ZERO; /* TODO: Set track and track position */ mpl_set_state(MEDIA_PROXY_STATE_PAUSED); media_proxy_pl_seeking_speed_cb(media_player.seeking_speed_factor); - ntf->result_code = MEDIA_PROXY_CMD_SUCCESS; - media_proxy_pl_command_cb(ntf); break; case MEDIA_PROXY_OP_FAST_REWIND: /* TODO: Here, and for FAST_FORWARD */ @@ -1846,8 +1753,6 @@ void seeking_state_command_handler(const struct mpl_cmd *command, media_player.seeking_speed_factor -= MPL_SEEKING_SPEED_FACTOR_STEP; media_proxy_pl_seeking_speed_cb(media_player.seeking_speed_factor); } - ntf->result_code = MEDIA_PROXY_CMD_SUCCESS; - media_proxy_pl_command_cb(ntf); break; case MEDIA_PROXY_OP_FAST_FORWARD: /* Highest value allowed by spec is 64, notify on change only */ @@ -1856,25 +1761,20 @@ void seeking_state_command_handler(const struct mpl_cmd *command, media_player.seeking_speed_factor += MPL_SEEKING_SPEED_FACTOR_STEP; media_proxy_pl_seeking_speed_cb(media_player.seeking_speed_factor); } - ntf->result_code = MEDIA_PROXY_CMD_SUCCESS; - media_proxy_pl_command_cb(ntf); break; case MEDIA_PROXY_OP_STOP: media_player.seeking_speed_factor = MEDIA_PROXY_SEEKING_SPEED_FACTOR_ZERO; set_track_position(0); mpl_set_state(MEDIA_PROXY_STATE_PAUSED); media_proxy_pl_seeking_speed_cb(media_player.seeking_speed_factor); - ntf->result_code = MEDIA_PROXY_CMD_SUCCESS; - media_proxy_pl_command_cb(ntf); break; case MEDIA_PROXY_OP_MOVE_RELATIVE: if (command->use_param) { set_relative_track_position(command->param); - ntf->result_code = MEDIA_PROXY_CMD_SUCCESS; } else { - ntf->result_code = MEDIA_PROXY_CMD_CANNOT_BE_COMPLETED; + result_code = MEDIA_PROXY_CMD_CANNOT_BE_COMPLETED; } - media_proxy_pl_command_cb(ntf); + break; case MEDIA_PROXY_OP_PREV_SEGMENT: /* Switch to previous segment if we are less than 5 seconds */ @@ -1884,26 +1784,18 @@ void seeking_state_command_handler(const struct mpl_cmd *command, do_prev_segment(&media_player); } set_track_position(media_player.group->track->segment->pos); - ntf->result_code = MEDIA_PROXY_CMD_SUCCESS; - media_proxy_pl_command_cb(ntf); break; case MEDIA_PROXY_OP_NEXT_SEGMENT: do_next_segment(&media_player); set_track_position(media_player.group->track->segment->pos); - ntf->result_code = MEDIA_PROXY_CMD_SUCCESS; - media_proxy_pl_command_cb(ntf); break; case MEDIA_PROXY_OP_FIRST_SEGMENT: do_first_segment(&media_player); set_track_position(media_player.group->track->segment->pos); - ntf->result_code = MEDIA_PROXY_CMD_SUCCESS; - media_proxy_pl_command_cb(ntf); break; case MEDIA_PROXY_OP_LAST_SEGMENT: do_last_segment(&media_player); set_track_position(media_player.group->track->segment->pos); - ntf->result_code = MEDIA_PROXY_CMD_SUCCESS; - media_proxy_pl_command_cb(ntf); break; case MEDIA_PROXY_OP_GOTO_SEGMENT: if (command->use_param) { @@ -1913,18 +1805,14 @@ void seeking_state_command_handler(const struct mpl_cmd *command, /* If the argument to "goto segment" is zero, */ /* the segment shall stay the same, and the */ /* track position shall not change. */ - ntf->result_code = MEDIA_PROXY_CMD_SUCCESS; } else { - ntf->result_code = MEDIA_PROXY_CMD_CANNOT_BE_COMPLETED; + result_code = MEDIA_PROXY_CMD_CANNOT_BE_COMPLETED; } - media_proxy_pl_command_cb(ntf); break; case MEDIA_PROXY_OP_PREV_TRACK: do_prev_track(&media_player); media_player.seeking_speed_factor = MEDIA_PROXY_SEEKING_SPEED_FACTOR_ZERO; mpl_set_state(MEDIA_PROXY_STATE_PAUSED); - ntf->result_code = MEDIA_PROXY_CMD_SUCCESS; - media_proxy_pl_command_cb(ntf); break; case MEDIA_PROXY_OP_NEXT_TRACK: do_next_track(&media_player); @@ -1932,82 +1820,64 @@ void seeking_state_command_handler(const struct mpl_cmd *command, /* does not change */ media_player.seeking_speed_factor = MEDIA_PROXY_SEEKING_SPEED_FACTOR_ZERO; mpl_set_state(MEDIA_PROXY_STATE_PAUSED); - ntf->result_code = MEDIA_PROXY_CMD_SUCCESS; - media_proxy_pl_command_cb(ntf); break; case MEDIA_PROXY_OP_FIRST_TRACK: do_first_track(&media_player); media_player.seeking_speed_factor = MEDIA_PROXY_SEEKING_SPEED_FACTOR_ZERO; mpl_set_state(MEDIA_PROXY_STATE_PAUSED); - ntf->result_code = MEDIA_PROXY_CMD_SUCCESS; - media_proxy_pl_command_cb(ntf); break; case MEDIA_PROXY_OP_LAST_TRACK: do_last_track(&media_player); media_player.seeking_speed_factor = MEDIA_PROXY_SEEKING_SPEED_FACTOR_ZERO; mpl_set_state(MEDIA_PROXY_STATE_PAUSED); - ntf->result_code = MEDIA_PROXY_CMD_SUCCESS; - media_proxy_pl_command_cb(ntf); break; case MEDIA_PROXY_OP_GOTO_TRACK: if (command->use_param) { do_goto_track(&media_player, command->param); media_player.seeking_speed_factor = MEDIA_PROXY_SEEKING_SPEED_FACTOR_ZERO; mpl_set_state(MEDIA_PROXY_STATE_PAUSED); - ntf->result_code = MEDIA_PROXY_CMD_SUCCESS; } else { - ntf->result_code = MEDIA_PROXY_CMD_CANNOT_BE_COMPLETED; + result_code = MEDIA_PROXY_CMD_CANNOT_BE_COMPLETED; } - media_proxy_pl_command_cb(ntf); break; case MEDIA_PROXY_OP_PREV_GROUP: do_full_prev_group(&media_player); mpl_set_state(MEDIA_PROXY_STATE_PAUSED); - ntf->result_code = MEDIA_PROXY_CMD_SUCCESS; - media_proxy_pl_command_cb(ntf); break; case MEDIA_PROXY_OP_NEXT_GROUP: do_full_next_group(&media_player); mpl_set_state(MEDIA_PROXY_STATE_PAUSED); - ntf->result_code = MEDIA_PROXY_CMD_SUCCESS; - media_proxy_pl_command_cb(ntf); break; case MEDIA_PROXY_OP_FIRST_GROUP: do_full_first_group(&media_player); mpl_set_state(MEDIA_PROXY_STATE_PAUSED); - ntf->result_code = MEDIA_PROXY_CMD_SUCCESS; - media_proxy_pl_command_cb(ntf); break; case MEDIA_PROXY_OP_LAST_GROUP: do_full_last_group(&media_player); mpl_set_state(MEDIA_PROXY_STATE_PAUSED); - ntf->result_code = MEDIA_PROXY_CMD_SUCCESS; - media_proxy_pl_command_cb(ntf); break; case MEDIA_PROXY_OP_GOTO_GROUP: if (command->use_param) { do_full_goto_group(&media_player, command->param); mpl_set_state(MEDIA_PROXY_STATE_PAUSED); - ntf->result_code = MEDIA_PROXY_CMD_SUCCESS; } else { - ntf->result_code = MEDIA_PROXY_CMD_CANNOT_BE_COMPLETED; + result_code = MEDIA_PROXY_CMD_CANNOT_BE_COMPLETED; } - media_proxy_pl_command_cb(ntf); break; default: LOG_DBG("Invalid command: %d", command->opcode); - ntf->result_code = MEDIA_PROXY_CMD_NOT_SUPPORTED; - media_proxy_pl_command_cb(ntf); + result_code = MEDIA_PROXY_CMD_NOT_SUPPORTED; break; } + + return result_code; } -void (*command_handlers[MEDIA_PROXY_STATE_LAST])(const struct mpl_cmd *command, - struct mpl_cmd_ntf *ntf) = { +static uint8_t (*command_handlers[MEDIA_PROXY_STATE_LAST])(const struct mpl_cmd *command) = { inactive_state_command_handler, playing_state_command_handler, paused_state_command_handler, - seeking_state_command_handler + seeking_state_command_handler, }; #ifdef CONFIG_BT_MPL_OBJECTS @@ -2327,7 +2197,9 @@ void send_command(const struct mpl_cmd *command) if (media_player.state < MEDIA_PROXY_STATE_LAST) { ntf.requested_opcode = command->opcode; - command_handlers[media_player.state](command, &ntf); + ntf.result_code = command_handlers[media_player.state](command); + + media_proxy_pl_command_cb(&ntf); } else { LOG_DBG("INVALID STATE"); } From 62ab25e3f539a97c106a253676910be41568ab59 Mon Sep 17 00:00:00 2001 From: Emil Gydesen Date: Fri, 8 Dec 2023 14:41:55 +0100 Subject: [PATCH 1304/3723] Bluetooth: MPL: Make internal functions static Several internal functions were not static. Signed-off-by: Emil Gydesen --- subsys/bluetooth/audio/mpl.c | 70 ++++++++++++++++++------------------ 1 file changed, 35 insertions(+), 35 deletions(-) diff --git a/subsys/bluetooth/audio/mpl.c b/subsys/bluetooth/audio/mpl.c index 745b34d703a..8a8840a3b44 100644 --- a/subsys/bluetooth/audio/mpl.c +++ b/subsys/bluetooth/audio/mpl.c @@ -246,6 +246,11 @@ static struct mpl_mediaplayer media_player = { .next_track_set = false }; +static void set_track_position(int32_t position); +static void set_relative_track_position(int32_t rel_pos); +static void do_track_change_notifications(struct mpl_mediaplayer *pl); +static void do_group_change_notifications(struct mpl_mediaplayer *pl); + #ifdef CONFIG_BT_MPL_OBJECTS /* The types of objects we keep in the Object Transfer Service */ @@ -293,11 +298,6 @@ static struct obj_t obj = { .content = NET_BUF_SIMPLE(CONFIG_BT_MPL_MAX_OBJ_SIZE) }; -static void set_track_position(int32_t position); -static void set_relative_track_position(int32_t rel_pos); -static void do_track_change_notifications(struct mpl_mediaplayer *pl); -static void do_group_change_notifications(struct mpl_mediaplayer *pl); - /* Set up content buffer for the icon object */ static int setup_icon_object(void) { @@ -883,7 +883,7 @@ static struct bt_ots_cb ots_cbs = { /* and do_prev_group() with a generic do_prev() command that can be used at */ /* all levels. Similarly for do_next, do_prev, and so on. */ -void do_prev_segment(struct mpl_mediaplayer *pl) +static void do_prev_segment(struct mpl_mediaplayer *pl) { LOG_DBG("Segment name before: %s", pl->group->track->segment->name); @@ -894,7 +894,7 @@ void do_prev_segment(struct mpl_mediaplayer *pl) LOG_DBG("Segment name after: %s", pl->group->track->segment->name); } -void do_next_segment(struct mpl_mediaplayer *pl) +static void do_next_segment(struct mpl_mediaplayer *pl) { LOG_DBG("Segment name before: %s", pl->group->track->segment->name); @@ -905,7 +905,7 @@ void do_next_segment(struct mpl_mediaplayer *pl) LOG_DBG("Segment name after: %s", pl->group->track->segment->name); } -void do_first_segment(struct mpl_mediaplayer *pl) +static void do_first_segment(struct mpl_mediaplayer *pl) { LOG_DBG("Segment name before: %s", pl->group->track->segment->name); @@ -916,7 +916,7 @@ void do_first_segment(struct mpl_mediaplayer *pl) LOG_DBG("Segment name after: %s", pl->group->track->segment->name); } -void do_last_segment(struct mpl_mediaplayer *pl) +static void do_last_segment(struct mpl_mediaplayer *pl) { LOG_DBG("Segment name before: %s", pl->group->track->segment->name); @@ -1956,34 +1956,34 @@ static bool find_group_by_id(const struct mpl_mediaplayer *pl, uint64_t id, } #endif /* CONFIG_BT_MPL_OBJECTS */ -const char *get_player_name(void) +static const char *get_player_name(void) { return media_player.name; } #ifdef CONFIG_BT_MPL_OBJECTS -uint64_t get_icon_id(void) +static uint64_t get_icon_id(void) { return media_player.icon_id; } #endif /* CONFIG_BT_MPL_OBJECTS */ -const char *get_icon_url(void) +static const char *get_icon_url(void) { return media_player.icon_url; } -const char *get_track_title(void) +static const char *get_track_title(void) { return media_player.group->track->title; } -int32_t get_track_duration(void) +static int32_t get_track_duration(void) { return media_player.group->track->duration; } -int32_t get_track_position(void) +static int32_t get_track_position(void) { return media_player.track_pos; } @@ -2032,12 +2032,12 @@ static void set_relative_track_position(int32_t rel_pos) set_track_position((int32_t)pos); } -int8_t get_playback_speed(void) +static int8_t get_playback_speed(void) { return media_player.playback_speed_param; } -void set_playback_speed(int8_t speed) +static void set_playback_speed(int8_t speed) { /* Set new speed parameter and notify, if different from current */ if (speed != media_player.playback_speed_param) { @@ -2046,23 +2046,23 @@ void set_playback_speed(int8_t speed) } } -int8_t get_seeking_speed(void) +static int8_t get_seeking_speed(void) { return media_player.seeking_speed_factor; } #ifdef CONFIG_BT_MPL_OBJECTS -uint64_t get_track_segments_id(void) +static uint64_t get_track_segments_id(void) { return media_player.group->track->segments_id; } -uint64_t get_current_track_id(void) +static uint64_t get_current_track_id(void) { return media_player.group->track->id; } -void set_current_track_id(uint64_t id) +static void set_current_track_id(uint64_t id) { struct mpl_group *group; struct mpl_track *track; @@ -2092,7 +2092,7 @@ void set_current_track_id(uint64_t id) */ } -uint64_t get_next_track_id(void) +static uint64_t get_next_track_id(void) { /* If the next track has been set explicitly */ if (media_player.next_track_set) { @@ -2108,7 +2108,7 @@ uint64_t get_next_track_id(void) return MPL_NO_TRACK_ID; } -void set_next_track_id(uint64_t id) +static void set_next_track_id(uint64_t id) { struct mpl_group *group; struct mpl_track *track; @@ -2127,17 +2127,17 @@ void set_next_track_id(uint64_t id) LOG_DBG("Track not found"); } -uint64_t get_parent_group_id(void) +static uint64_t get_parent_group_id(void) { return media_player.group->parent->id; } -uint64_t get_current_group_id(void) +static uint64_t get_current_group_id(void) { return media_player.group->id; } -void set_current_group_id(uint64_t id) +static void set_current_group_id(uint64_t id) { struct mpl_group *group; @@ -2160,12 +2160,12 @@ void set_current_group_id(uint64_t id) } #endif /* CONFIG_BT_MPL_OBJECTS */ -uint8_t get_playing_order(void) +static uint8_t get_playing_order(void) { return media_player.playing_order; } -void set_playing_order(uint8_t order) +static void set_playing_order(uint8_t order) { if (order != media_player.playing_order) { if (BIT(order - 1) & media_player.playing_orders_supported) { @@ -2175,17 +2175,17 @@ void set_playing_order(uint8_t order) } } -uint16_t get_playing_orders_supported(void) +static uint16_t get_playing_orders_supported(void) { return media_player.playing_orders_supported; } -uint8_t get_media_state(void) +static uint8_t get_media_state(void) { return media_player.state; } -void send_command(const struct mpl_cmd *command) +static void send_command(const struct mpl_cmd *command) { struct mpl_cmd_ntf ntf; @@ -2205,7 +2205,7 @@ void send_command(const struct mpl_cmd *command) } } -uint32_t get_commands_supported(void) +static uint32_t get_commands_supported(void) { return media_player.opcodes_supported; } @@ -2264,7 +2264,7 @@ static void parse_search(const struct mpl_search *search) media_proxy_pl_search_results_id_cb(media_player.search_results_id); } -void send_search(const struct mpl_search *search) +static void send_search(const struct mpl_search *search) { if (search->len > SEARCH_LEN_MAX) { LOG_WRN("Search too long: %d", search->len); @@ -2275,13 +2275,13 @@ void send_search(const struct mpl_search *search) parse_search(search); } -uint64_t get_search_results_id(void) +static uint64_t get_search_results_id(void) { return media_player.search_results_id; } #endif /* CONFIG_BT_MPL_OBJECTS */ -uint8_t get_content_ctrl_id(void) +static uint8_t get_content_ctrl_id(void) { return media_player.content_ctrl_id; } From a40a8a5f4950fb5844b5d785d115557cb637bcec Mon Sep 17 00:00:00 2001 From: Richard Wheatley Date: Mon, 11 Dec 2023 09:24:22 -0600 Subject: [PATCH 1305/3723] boards: arm: apollo4p_evb add connector to apollo4p_evb Generic Connector for the apollo4p_evb Ran tests/drivers/gpio/gpio_basic_api Ambiq does not support DUAL Edged Interrupts. Added Connector Usages as defined by the Ambiq BSP. Signed-off-by: Richard Wheatley --- .../apollo4p_evb/apollo4p_evb-pinctrl.dtsi | 1 + .../apollo4p_evb/apollo4p_evb_connector.dtsi | 121 ++++++++++++++++++ drivers/gpio/gpio_ambiq.c | 4 + dts/bindings/gpio/ambiq-header.yaml | 59 +++++++++ .../boards/apollo4p_evb.overlay | 13 ++ 5 files changed, 198 insertions(+) create mode 100644 boards/arm/apollo4p_evb/apollo4p_evb_connector.dtsi create mode 100644 dts/bindings/gpio/ambiq-header.yaml create mode 100644 tests/drivers/gpio/gpio_basic_api/boards/apollo4p_evb.overlay diff --git a/boards/arm/apollo4p_evb/apollo4p_evb-pinctrl.dtsi b/boards/arm/apollo4p_evb/apollo4p_evb-pinctrl.dtsi index abc9f9c9c54..941c6271e22 100644 --- a/boards/arm/apollo4p_evb/apollo4p_evb-pinctrl.dtsi +++ b/boards/arm/apollo4p_evb/apollo4p_evb-pinctrl.dtsi @@ -5,6 +5,7 @@ */ #include +#include "apollo4p_evb_connector.dtsi" &pinctrl { uart0_default: uart0_default { diff --git a/boards/arm/apollo4p_evb/apollo4p_evb_connector.dtsi b/boards/arm/apollo4p_evb/apollo4p_evb_connector.dtsi new file mode 100644 index 00000000000..b3cafd9587e --- /dev/null +++ b/boards/arm/apollo4p_evb/apollo4p_evb_connector.dtsi @@ -0,0 +1,121 @@ +/* + * Copyright (c) 2023 Antmicro + * + * SPDX-License-Identifier: Apache-2.0 + */ + +/ { + ambiq_header: connector { + compatible = "ambiq-header"; + #gpio-cells = <2>; + gpio-map-mask = <0xffffffff 0xffffff80>; + gpio-map-pass-thru = <0 0x7f>; + gpio-map = <0 0 &gpio0_31 0 0>, /* IOS_SPI_SCK, IOS_I2C_SCL, MSPI2_CE0 */ + <1 0 &gpio0_31 1 0>, /* IOS_SPI_MOSI, IOS_I2C_SDA, MSPI0_CE0 */ + <2 0 &gpio0_31 2 0>, /* IOS_SPI_MISO */ + <3 0 &gpio0_31 3 0>, /* IOS_CE */ + <4 0 &gpio0_31 4 0>, /* IOS_INT */ + <5 0 &gpio0_31 5 0>, /* IOM0_SPI_SCK, IOM0_I2C_SCL */ + <6 0 &gpio0_31 6 0>, /* IOM0_SPI_MOSI, IOM0_I2C_SDA */ + <7 0 &gpio0_31 7 0>, /* See am_hal_pins.h file for further info */ + <8 0 &gpio0_31 8 0>, /* IOM1_SPI_SCK, IOM1_I2C_SCL */ + <9 0 &gpio0_31 9 0>, /* IOM1_SPI_MOSI, IOM1_I2C_SDA */ + <10 0 &gpio0_31 10 0>, /* IOM1_SPI_MISO */ + <11 0 &gpio0_31 11 0>, /* UART2_RX, IOM1_CS, I2S0_CLK */ + <12 0 &gpio0_31 12 0>, /* ADCSE7, UART1_TX, I2S0_DATA, I2S0_SDOUT */ + <13 0 &gpio0_31 13 0>, /* ADCSE6, UART2_TX, I2S0_WS */ + <14 0 &gpio0_31 14 0>, /* ADCSE5, UART1_RX, I2S0_SDIN */ + <15 0 &gpio0_31 15 0>, /* ADCSE4 */ + <16 0 &gpio0_31 16 0>, /* ADCSE3, I2S1_CLK */ + <17 0 &gpio0_31 17 0>, /* ADCSE2, UART3_RTS, I2S1_DATA */ + <18 0 &gpio0_31 18 0>, /* BUTTON0, ADCSE1, I2S1_WS */ + <19 0 &gpio0_31 19 0>, /* BUTTON1, ADCSE0, UART3_CTS, I2S1_SDIN */ + <20 0 &gpio0_31 19 0>, /* SWDCK */ + <21 0 &gpio0_31 19 0>, /* SWDIO */ + <22 0 &gpio0_31 22 0>, /* IOM7_SPI_SCK, IOM7_I2C_SCL */ + <23 0 &gpio0_31 23 0>, /* IOM7_SPI_MOSI, IOM7_I2C_SDA */ + <24 0 &gpio0_31 24 0>, /* IOM7_SPI_MISO */ + <25 0 &gpio0_31 25 0>, /* IOM2_SPI_SCK, IOM2_I2C_SCL */ + <26 0 &gpio0_31 26 0>, /* IOM2_SPI_MOSI, IOM2_I2C_SDA */ + <27 0 &gpio0_31 27 0>, /* IOM2_SPI_MISO */ + <28 0 &gpio0_31 28 0>, /* ITM_SWO */ + <29 0 &gpio0_31 29 0>, /* See am_hal_pins.h file for further info */ + <30 0 &gpio0_31 30 0>, /* LED1, IOM6_CS */ + <31 0 &gpio0_31 31 0>, /* IOM3_SPI_SCK, IOM3_I2C_SCL */ + <32 0 &gpio32_63 0 0>, /* IOM3_SPI_MOSI, IOM3_I2C_SDA */ + <33 0 &gpio32_63 1 0>, /* IOM3_SPI_MISO */ + <34 0 &gpio32_63 2 0>, /* IOM4_SPI_SCK, IOM4_I2C_SCL */ + <35 0 &gpio32_63 3 0>, /* IOM4_SPI_MOSI, IOM4_I2C_SDA */ + <36 0 &gpio32_63 4 0>, /* IOM4_SPI_MISO */ + <37 0 &gpio32_63 5 0>, /* IOM2_CS, MSPI1_D0, X16SPI_D8 */ + <38 0 &gpio32_63 6 0>, /* MSPI1_D1, X16SPI_D9 */ + <39 0 &gpio32_63 7 0>, /* MSPI1_D2, X16SPI_D10 */ + <40 0 &gpio32_63 8 0>, /* MSPI1_D3, X16SPI_D11 */ + <41 0 &gpio32_63 9 0>, /* MSPI1_D4, X16SPI_D12 */ + <42 0 &gpio32_63 10 0>, /* MSPI1_D5, X16SPI_D13 */ + <43 0 &gpio32_63 11 0>, /* MSPI1_D6, X16SPI_D14 */ + <44 0 &gpio32_63 12 0>, /* MSPI1_D7, X16SPI_D15 */ + <45 0 &gpio32_63 13 0>, /* MSPI1_SCK, X16SPI_DQS1DM1 */ + <46 0 &gpio32_63 14 0>, /* MSPI1_DQSDM */ + <47 0 &gpio32_63 15 0>, /* COM_UART_RX, IOM5_SPI_SCK, IOM5_I2C_SCL */ + <48 0 &gpio32_63 16 0>, /* IOM5_SPI_MOSI, IOM5_I2C_SDA */ + <49 0 &gpio32_63 17 0>, /* UART1_RTS, IOM5_SPI_MISO */ + <50 0 &gpio32_63 18 0>, /* UART2_RTS, ETM_TRACECLK, PDM0_CLK */ + <51 0 &gpio32_63 19 0>, /* UART1_CTS, EMT_TRACE0, PDM0_DATA */ + <52 0 &gpio32_63 20 0>, /* UART2_CTS, MSPI0_CE1, ETM_TRACE1, PDM1_CLK */ + <53 0 &gpio32_63 21 0>, /* ETM_TRACE2, PDM1_DATA */ + <54 0 &gpio32_63 22 0>, /* ETM_TRACE3, PDM2_CLK */ + <55 0 &gpio32_63 23 0>, /* ETM_TRACECTL, PDM2_DATA */ + <56 0 &gpio32_63 24 0>, /* PDM3_CLK */ + <57 0 &gpio32_63 25 0>, /* PDM3_DATA */ + <58 0 &gpio32_63 26 0>, /* COM_UART_RTS, UART0_RTS */ + <59 0 &gpio32_63 27 0>, /* COM_UART_CTS, UART0_CTS */ + <60 0 &gpio32_63 28 0>, /* COM_UART_TX, UART0_TX, IOM5_CS */ + <61 0 &gpio32_63 29 0>, /* UART3_TX, IOM6_SPI_SCK, IOM6_I2C_SCL */ + <62 0 &gpio32_63 30 0>, /* IOM6_SPI_MOSI, IOM6_I2C_SDA */ + <63 0 &gpio32_63 31 0>, /* UART3_RX, IOM6_SPI_MISO */ + <64 0 &gpio64_95 0 0>, /* MSPI0_D0, X16SPI_D0 */ + <65 0 &gpio64_95 1 0>, /* MSPI0_D1, X16SPI_D1 */ + <66 0 &gpio64_95 2 0>, /* MSPI0_D2, X16SPI_D2 */ + <67 0 &gpio64_95 3 0>, /* MSPI0_D3, X16SPI_D3 */ + <68 0 &gpio64_95 4 0>, /* MSPI0_D4, X16SPI_D4 */ + <69 0 &gpio64_95 5 0>, /* MSPI0_D5, X16SPI_D5 */ + <70 0 &gpio64_95 6 0>, /* MSPI0_D6, X16SPI_D6 */ + <71 0 &gpio64_95 7 0>, /* MSPI0_D7, X16SPI_D7 */ + <72 0 &gpio64_95 8 0>, /* IOM0_CS, MSPI0_SCK, X16SPI_SCK */ + <73 0 &gpio64_95 9 0>, /* MSPI0_DQSDM, X16SPI_DQSDM */ + <74 0 &gpio64_95 10 0>, /* MSPI2_D0 */ + <75 0 &gpio64_95 11 0>, /* MSPI2_D1 */ + <76 0 &gpio64_95 12 0>, /* MSPI2_D2 */ + <77 0 &gpio64_95 13 0>, /* MSPI2_D3 */ + <78 0 &gpio64_95 14 0>, /* MSPI2_D4 */ + <79 0 &gpio64_95 15 0>, /* IOM4_CS, MSPI2_D5, SDIF_DAT4 */ + <80 0 &gpio64_95 16 0>, /* MSPI2_D6, SDIF_DAT5 */ + <81 0 &gpio64_95 17 0>, /* MSPI2_D7, SDIF_DAT6 */ + <82 0 &gpio64_95 18 0>, /* MSPI2_D8, SDIF_DAT7 */ + <83 0 &gpio64_95 19 0>, /* MSPI2_DQSDM, SDIF_CMD */ + <84 0 &gpio64_95 20 0>, /* SDIF_DAT0 */ + <85 0 &gpio64_95 21 0>, /* IOM3_CS, SDIF_DAT1 */ + <86 0 &gpio64_95 22 0>, /* MSPI2_CE1, SDIF_DAT2 */ + <87 0 &gpio64_95 23 0>, /* SDIF_DAT3 */ + <88 0 &gpio64_95 24 0>, /* IOM7_CS, SDIF_CLKOUT */ + <89 0 &gpio64_95 25 0>, /* MSPI1_CE0, X16SPI_CE0, X16SPI_CE1 */ + <90 0 &gpio64_95 26 0>, /* LED0 */ + <91 0 &gpio64_95 27 0>, /* MSPI1_CE1, */ + <92 0 &gpio64_95 28 0>, /* See am_hal_pins.h file for further info */ + <93 0 &gpio64_95 29 0>, /* See am_hal_pins.h file for further info */ + <94 0 &gpio64_95 30 0>, /* See am_hal_pins.h file for further info */ + <95 0 &gpio64_95 31 0>, /* See am_hal_pins.h file for further info */ + <96 0 &gpio96_127 0 0>, /* See am_hal_pins.h file for further info */ + <97 0 &gpio96_127 1 0>, /* See am_hal_pins.h file for further info */ + <98 0 &gpio96_127 2 0>, /* See am_hal_pins.h file for further info */ + <99 0 &gpio96_127 3 0>, /* See am_hal_pins.h file for further info */ + <100 0 &gpio96_127 4 0>, /* See am_hal_pins.h file for further info */ + <101 0 &gpio96_127 5 0>, /* VDDUSB0P9_SWITCH */ + <102 0 &gpio96_127 6 0>, /* See am_hal_pins.h file for further info */ + <103 0 &gpio96_127 7 0>, /* VDDUSB33_SWITCH */ + <104 0 &gpio96_127 8 0>; /* VDD18_SWITCH */ + }; +}; + +ambiq_spi: &iom1 {}; diff --git a/drivers/gpio/gpio_ambiq.c b/drivers/gpio/gpio_ambiq.c index 7a1bb5e0fb0..b036094e683 100644 --- a/drivers/gpio/gpio_ambiq.c +++ b/drivers/gpio/gpio_ambiq.c @@ -274,6 +274,10 @@ static int ambiq_gpio_pin_interrupt_configure(const struct device *dev, gpio_pin pincfg.GP.cfg_b.eIntDir = AM_HAL_GPIO_PIN_INTDIR_LO2HI; break; case GPIO_INT_TRIG_BOTH: + /* + * GPIO_INT_TRIG_BOTH is not supported on Ambiq Apollo4 Plus Platform + * ERR008: GPIO: Dual-edge interrupts are not vectoring + */ return -ENOTSUP; } ret = am_hal_gpio_pinconfig(gpio_pin, pincfg); diff --git a/dts/bindings/gpio/ambiq-header.yaml b/dts/bindings/gpio/ambiq-header.yaml new file mode 100644 index 00000000000..b082bc0ae58 --- /dev/null +++ b/dts/bindings/gpio/ambiq-header.yaml @@ -0,0 +1,59 @@ +# Copyright (c) 2023 Antmicro +# SPDX-License-Identifier: Apache-2.0 + +description: | + GPIO pins exposed on Ambiq Apollo4p EVB headers + + The Ambiq Apollo4p EVB layout provides 5x16 and 1x20 pin headers. + + The binding provides a nexus mapping for these pins as depicted below. + + J7 J12 + + VDD_MCU - VDD_MCU - GPIO22 22 GND - + VDD_EXT - VDD_EXT - GPIO23 23 GPIO24 24 + nRST - GND - VDD_MCU - GND - + VDD_EXT - VDD_EXT - GND - GPIO64 64 + VDD_5V - VDD_5V - GPIO61 61 GPIO65 65 + GND - GND - GPIO63 63 GPIO66 66 + GND - GPIO100 100 GPIO62 62 GPIO67 67 + VDDH2 - GPIO97 97 GPIO47 47 GPIO68 68 + GPIO49 49 GPIO69 69 + J9 GPIO48 48 GPIO70 70 + + GPIO19 19 GPIO96 96 J11 + GPIO18 18 GPIO95 95 + GPIO17 17 GPIO98 98 GPIO53 53 GPIO71 71 + GPIO16 16 GPIO99 99 GPIO52 52 GPIO72 72 + GPIO15 15 GPIO102 102 GPIO91 91 GPIO73 73 + GPIO14 14 GPIO34 34 GPIO90 90 GPIO93 93 + GPIO13 13 GPIO35 35 GPIO11 11 GPIO92 92 + GPIO12 12 GPIO36 36 GPIO10 10 GPIO33 33 + GPIO8 8 GPIO32 32 + GPIO9 9 GPIO31 31 + + J10 + + GPIO28 28 GPIO60 60 + GPIO30 30 GPIO59 59 + GPIO94 94 GPIO58 58 + GPIO55 55 GPIO7 7 + GPIO0 0 GPIO54 54 + GPIO51 51 GPIO1 1 + GPIO2 2 GPIO50 50 + GPIO3 3 GPIO4 4 + + Voltage Header + + VDD_EXT - VDD_5V - + GND - GND - + BIAS - BIAS - + GND - AUDA - + GND - GND - + D1P - DON - + D1N - DOP - + GND - GND - + +compatible: "ambiq-header" + +include: [gpio-nexus.yaml, base.yaml] diff --git a/tests/drivers/gpio/gpio_basic_api/boards/apollo4p_evb.overlay b/tests/drivers/gpio/gpio_basic_api/boards/apollo4p_evb.overlay new file mode 100644 index 00000000000..d0cb20f1012 --- /dev/null +++ b/tests/drivers/gpio/gpio_basic_api/boards/apollo4p_evb.overlay @@ -0,0 +1,13 @@ +/* + * Copyright (c) 2023 Antmicro + * + * SPDX-License-Identifier: Apache-2.0 + */ + +/ { + resources { + compatible = "test-gpio-basic-api"; + out-gpios = <&ambiq_header 12 0>; + in-gpios = <&ambiq_header 13 0>; + }; +}; From ac78b97820056ca072a534ae3e7c05d942a94cca Mon Sep 17 00:00:00 2001 From: Jordan Yates Date: Sun, 10 Dec 2023 16:04:57 +1000 Subject: [PATCH 1306/3723] scripts: ci: guideline_check: support other repos Support running this check against other repositories. Signed-off-by: Jordan Yates --- scripts/ci/guideline_check.py | 21 +++++++++++++-------- 1 file changed, 13 insertions(+), 8 deletions(-) diff --git a/scripts/ci/guideline_check.py b/scripts/ci/guideline_check.py index 0d4266eb3a3..57c878f651f 100755 --- a/scripts/ci/guideline_check.py +++ b/scripts/ci/guideline_check.py @@ -11,13 +11,6 @@ if "ZEPHYR_BASE" not in os.environ: exit("$ZEPHYR_BASE environment variable undefined.") -repository_path = os.environ['ZEPHYR_BASE'] - -sh_special_args = { - '_tty_out': False, - '_cwd': repository_path -} - coccinelle_scripts = ["/scripts/coccinelle/reserved_names.cocci", "/scripts/coccinelle/same_identifier.cocci", #"/scripts/coccinelle/identifier_length.cocci", @@ -38,7 +31,9 @@ def parse_coccinelle(contents: str, violations: dict): def parse_args(): parser = argparse.ArgumentParser( - description="Check if change requires full twister", allow_abbrev=False) + description="Check commits against Cocccinelle rules", allow_abbrev=False) + parser.add_argument('-r', "--repository", required=False, + help="Path to repository") parser.add_argument('-c', '--commits', default=None, help="Commit range in the form: a..b") parser.add_argument("-o", "--output", required=False, @@ -51,6 +46,16 @@ def main(): if not args.commits: exit("missing commit range") + if args.repository is None: + repository_path = os.environ['ZEPHYR_BASE'] + else: + repository_path = args.repository + + sh_special_args = { + '_tty_out': False, + '_cwd': repository_path + } + # pylint does not like the 'sh' library # pylint: disable=too-many-function-args,unexpected-keyword-arg commit = sh.git("diff", args.commits, **sh_special_args) From f0495d4d472f5852906318bdf93582af07b3c12d Mon Sep 17 00:00:00 2001 From: Conor Paxton Date: Mon, 4 Dec 2023 23:59:00 +0000 Subject: [PATCH 1307/3723] boards: riscv: introduce support for Beagleboard BeagleV-Fire The BeagleV-Fire is a SBC powered by Microchip's PolarFire SoC MPFS025T. Signed-off-by: Conor Paxton --- boards/riscv/beaglev_fire/Kconfig.board | 9 ++ boards/riscv/beaglev_fire/Kconfig.defconfig | 6 ++ boards/riscv/beaglev_fire/beaglev_fire.dts | 33 +++++++ boards/riscv/beaglev_fire/beaglev_fire.yaml | 12 +++ .../riscv/beaglev_fire/beaglev_fire_defconfig | 18 ++++ .../BeagleV-Fire-Front-Annotated-768x432.webp | Bin 0 -> 42568 bytes .../beaglev_fire/doc/img/board-booting.png | Bin 0 -> 16583 bytes boards/riscv/beaglev_fire/doc/index.rst | 85 ++++++++++++++++++ 8 files changed, 163 insertions(+) create mode 100644 boards/riscv/beaglev_fire/Kconfig.board create mode 100644 boards/riscv/beaglev_fire/Kconfig.defconfig create mode 100644 boards/riscv/beaglev_fire/beaglev_fire.dts create mode 100644 boards/riscv/beaglev_fire/beaglev_fire.yaml create mode 100644 boards/riscv/beaglev_fire/beaglev_fire_defconfig create mode 100644 boards/riscv/beaglev_fire/doc/img/BeagleV-Fire-Front-Annotated-768x432.webp create mode 100644 boards/riscv/beaglev_fire/doc/img/board-booting.png create mode 100644 boards/riscv/beaglev_fire/doc/index.rst diff --git a/boards/riscv/beaglev_fire/Kconfig.board b/boards/riscv/beaglev_fire/Kconfig.board new file mode 100644 index 00000000000..1984bb05c09 --- /dev/null +++ b/boards/riscv/beaglev_fire/Kconfig.board @@ -0,0 +1,9 @@ +# Copyright (c) 2023 Microchip Technology Inc +# SPDX-License-Identifier: Apache-2.0 + +config BOARD_BEAGLEV_FIRE + bool "Beagleboard BeagleV-Fire" + depends on SOC_MPFS + select 64BIT + select SCHED_IPI_SUPPORTED + select CPU_HAS_FPU_DOUBLE_PRECISION diff --git a/boards/riscv/beaglev_fire/Kconfig.defconfig b/boards/riscv/beaglev_fire/Kconfig.defconfig new file mode 100644 index 00000000000..df89660bcb6 --- /dev/null +++ b/boards/riscv/beaglev_fire/Kconfig.defconfig @@ -0,0 +1,6 @@ +# Copyright (c) 2023 Microchip Technology Inc +# SPDX-License-Identifier: Apache-2.0 + +config BOARD + default "beaglev_fire" + depends on BOARD_BEAGLEV_FIRE diff --git a/boards/riscv/beaglev_fire/beaglev_fire.dts b/boards/riscv/beaglev_fire/beaglev_fire.dts new file mode 100644 index 00000000000..df956f5c8f2 --- /dev/null +++ b/boards/riscv/beaglev_fire/beaglev_fire.dts @@ -0,0 +1,33 @@ +/* + * Copyright (c) 2023 Microchip Technology Inc + * + * SPDX-License-Identifier: Apache-2.0 + */ + +/dts-v1/; +#include +#include +#include + +/ { + model = "BeagleV-Fire"; + compatible = "beagle,beaglev-fire", "microchip,mpfs"; + aliases { + }; + + chosen { + zephyr,console = &uart0; + zephyr,shell-uart = &uart0; + zephyr,sram = &sram1; + }; +}; + +&uart0 { + status = "okay"; + current-speed = <115200>; + clock-frequency = <150000000>; +}; + +&gpio2 { + status = "okay"; +}; diff --git a/boards/riscv/beaglev_fire/beaglev_fire.yaml b/boards/riscv/beaglev_fire/beaglev_fire.yaml new file mode 100644 index 00000000000..64d34b454f8 --- /dev/null +++ b/boards/riscv/beaglev_fire/beaglev_fire.yaml @@ -0,0 +1,12 @@ +identifier: beaglev_fire +name: Beagleboard BeagleV-Fire +type: mcu +arch: riscv64 +toolchain: + - zephyr +ram: 3840 +testing: + ignore_tags: + - net + - bluetooth +vendor: beagle diff --git a/boards/riscv/beaglev_fire/beaglev_fire_defconfig b/boards/riscv/beaglev_fire/beaglev_fire_defconfig new file mode 100644 index 00000000000..a60ed8c1691 --- /dev/null +++ b/boards/riscv/beaglev_fire/beaglev_fire_defconfig @@ -0,0 +1,18 @@ +# Copyright (c) 2023 Microchip Technology Inc +# SPDX-License-Identifier: Apache-2.0 + +CONFIG_SOC_SERIES_RISCV64_MIV=y +CONFIG_SOC_MPFS=y +CONFIG_MPFS_HAL=n +CONFIG_BASE64=y +CONFIG_INCLUDE_RESET_VECTOR=y +CONFIG_BOARD_BEAGLEV_FIRE=y +CONFIG_CONSOLE=y +CONFIG_SERIAL=y +CONFIG_UART_CONSOLE=y +CONFIG_RISCV_SOC_INTERRUPT_INIT=y +CONFIG_RISCV_HAS_PLIC=y +CONFIG_XIP=n +CONFIG_INIT_STACKS=y +CONFIG_SYS_CLOCK_TICKS_PER_SEC=1000 +CONFIG_FPU=n diff --git a/boards/riscv/beaglev_fire/doc/img/BeagleV-Fire-Front-Annotated-768x432.webp b/boards/riscv/beaglev_fire/doc/img/BeagleV-Fire-Front-Annotated-768x432.webp new file mode 100644 index 0000000000000000000000000000000000000000..a4ba6b0d98e9e985397ab938b9c56f50fd3111f9 GIT binary patch literal 42568 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 @7=|-LM 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⋙=X0LB2ORQzinB28xAnvHAh*hpb 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 literal 0 HcmV?d00001 diff --git a/boards/riscv/beaglev_fire/doc/index.rst b/boards/riscv/beaglev_fire/doc/index.rst new file mode 100644 index 00000000000..88808145c9b --- /dev/null +++ b/boards/riscv/beaglev_fire/doc/index.rst @@ -0,0 +1,85 @@ +.. _beaglev_fire: + +BeagleV®-Fire +############# + +Overview +******** + +BeagleV®-Fire is a revolutionary single-board computer (SBC) powered by the Microchip’s +PolarFire® MPFS025T 5x core RISC-V System on Chip (SoC) with FPGA fabric. BeagleV®-Fire opens up new +horizons for developers, tinkerers, and the open-source community to explore the vast potential of +RISC-V architecture and FPGA technology. It has the same P8 & P9 cape header pins as BeagleBone +Black allowing you to stack your favorite BeagleBone cape on top to expand it’s capability. +Built around the powerful and energy-efficient RISC-V instruction set architecture (ISA) along with +its versatile FPGA fabric, BeagleV®-Fire SBC offers unparalleled opportunities for developers, +hobbyists, and researchers to explore and experiment with RISC-V technology. + +.. image:: img/BeagleV-Fire-Front-Annotated-768x432.webp + :align: center + :alt: beaglev_fire + +Building +======== + +Applications for the ``beaglev_fire`` board configuration can be built as usual: + +.. zephyr-app-commands:: + :zephyr-app: samples/hello_world + :board: beaglev_fire + :goals: build + +Debugging +========= + +In order to upload the application to the device, you'll need OpenOCD and GDB +with RISC-V support. +You can get them as a part of SoftConsole SDK. +Download and installation instructions can be found on +`Microchip's SoftConsole website +`_. + +You will also require a Debugger such as Microchip's FlashPro5/6. + +Connect to BeagleV-Fire UART debug port using a 3.3v USB to UART bridge. +Now you can run ``tio `` in a terminal window to access the UART debug port connection. Once you +are connected properly you can press the Reset button which will show you a progress bar like: + +.. image:: img/board-booting.png + :align: center + :alt: beaglev_fire + +Once you see that progress bar on your screen you can start pressing any button (0-9/a-z) which +will interrupt the Hart Software Services from booting its payload. + +With the necessary tools installed, you can connect to the board using OpenOCD. +from a different terminal, run: + +.. code-block:: bash + + /openocd/bin/openocd --file \ + /openocd/share/openocd/scripts/board/microsemi-riscv.cfg + + +Leave it running, and in a different terminal, use GDB to upload the binary to +the board. You can use the RISC-V GDB from the Zephyr SDK. +launch GDB: + +.. code-block:: bash + + /riscv64-zephyr-elf/bin/riscv64-zephyr-elf-gdb + + + +Here is the GDB terminal command to connect to the device +and load the binary: + +.. code-block:: bash + + set arch riscv:rv64 + set mem inaccessible-by-default off + file + target extended-remote localhost:3333 + load + break main + continue From 9c22c82604763021004606d2e54a3ee81715c9b2 Mon Sep 17 00:00:00 2001 From: Ryan McClelland Date: Tue, 28 Nov 2023 01:09:00 -0800 Subject: [PATCH 1308/3723] drivers: i3c: cdns: handle controller aborts Some targets do not give EoD at the end of a register read. They will auto increment their address pointer on to the next address, but that may not be of interest to the application where the buffer size will only be set to the size of only that register. If the target, does not give an EoD, then the Controller will give an Abort... but this should not be treated as an error in this case. There is still however a case where an abort Error shall still be considered as an error. Athough the driver does not support it yet, threshold interrupts are to be used if the length of the buffer exceeds the size of the fifo. There could be the case where the cpu can not get around fast enough to pop out data out of the rx fifo and it will fill up. The controller will just give an abort as it can not take any more data. Signed-off-by: Ryan McClelland --- drivers/i3c/i3c_cdns.c | 27 ++++++++++++++++++++++++++- 1 file changed, 26 insertions(+), 1 deletion(-) diff --git a/drivers/i3c/i3c_cdns.c b/drivers/i3c/i3c_cdns.c index 27f6b1af8da..2d07f807f8e 100644 --- a/drivers/i3c/i3c_cdns.c +++ b/drivers/i3c/i3c_cdns.c @@ -1284,6 +1284,10 @@ static void cdns_i3c_complete_transfer(const struct device *dev) uint32_t rx = 0; int ret = 0; struct cdns_i3c_cmd *cmd; + bool was_full; + + /* Used only to determine in the case of a controller abort */ + was_full = cdns_i3c_rx_fifo_full(config); /* Disable further interrupts */ sys_write32(MST_INT_CMDD_EMP, config->base + MST_IDR); @@ -1324,12 +1328,33 @@ static void cdns_i3c_complete_transfer(const struct device *dev) case CMDR_NO_ERROR: break; + case CMDR_MST_ABORT: + /* + * A controller abort is forced if the RX FIFO fills up + * There is also the case where the fifo can be full as + * the len of the packet is the same length of the fifo + * Check that the requested len is greater than the total + * transferred to confirm that is not case. Otherwise the + * abort was caused by the buffer length being meet and + * the target did not give an End of Data (EoD) in the T + * bit. Do not treat that condition as an error because + * some targets will just auto-increment the read address + * way beyond the buffer not giving an EoD. + */ + if ((was_full) && (data->xfer.cmds[i].len > *data->xfer.cmds[i].num_xfer)) { + ret = -ENOSPC; + } else { + LOG_DBG("%s: Controller Abort due to buffer length excedded with " + "no EoD from target", + dev->name); + } + break; + case CMDR_DDR_PREAMBLE_ERROR: case CMDR_DDR_PARITY_ERROR: case CMDR_M0_ERROR: case CMDR_M1_ERROR: case CMDR_M2_ERROR: - case CMDR_MST_ABORT: case CMDR_NACK_RESP: case CMDR_DDR_DROPPED: ret = -EIO; From b4768d5d4241f55b7ecf2362dd260197780cc8d7 Mon Sep 17 00:00:00 2001 From: Ryan McClelland Date: Wed, 13 Dec 2023 10:45:10 -0800 Subject: [PATCH 1309/3723] drivers: i3c: cdns: run clang-format Run the clang-formatter. This just changes white-space on defines. Signed-off-by: Ryan McClelland --- drivers/i3c/i3c_cdns.c | 408 ++++++++++++++++++++--------------------- 1 file changed, 204 insertions(+), 204 deletions(-) diff --git a/drivers/i3c/i3c_cdns.c b/drivers/i3c/i3c_cdns.c index 2d07f807f8e..ef361523e4e 100644 --- a/drivers/i3c/i3c_cdns.c +++ b/drivers/i3c/i3c_cdns.c @@ -14,154 +14,154 @@ #include #include -#define DEV_ID 0x0 +#define DEV_ID 0x0 #define DEV_ID_I3C_MASTER 0x5034 -#define CONF_STATUS0 0x4 +#define CONF_STATUS0 0x4 #define CONF_STATUS0_CMDR_DEPTH(x) (4 << (((x)&GENMASK(31, 29)) >> 29)) -#define CONF_STATUS0_ECC_CHK BIT(28) -#define CONF_STATUS0_INTEG_CHK BIT(27) +#define CONF_STATUS0_ECC_CHK BIT(28) +#define CONF_STATUS0_INTEG_CHK BIT(27) #define CONF_STATUS0_CSR_DAP_CHK BIT(26) #define CONF_STATUS0_TRANS_TOUT_CHK BIT(25) #define CONF_STATUS0_PROT_FAULTS_CHK BIT(24) -#define CONF_STATUS0_GPO_NUM(x) (((x)&GENMASK(23, 16)) >> 16) -#define CONF_STATUS0_GPI_NUM(x) (((x)&GENMASK(15, 8)) >> 8) +#define CONF_STATUS0_GPO_NUM(x) (((x)&GENMASK(23, 16)) >> 16) +#define CONF_STATUS0_GPI_NUM(x) (((x)&GENMASK(15, 8)) >> 8) #define CONF_STATUS0_IBIR_DEPTH(x) (4 << (((x)&GENMASK(7, 6)) >> 7)) #define CONF_STATUS0_SUPPORTS_DDR BIT(5) -#define CONF_STATUS0_SEC_MASTER BIT(4) +#define CONF_STATUS0_SEC_MASTER BIT(4) #define CONF_STATUS0_DEVS_NUM(x) ((x)&GENMASK(3, 0)) -#define CONF_STATUS1 0x8 -#define CONF_STATUS1_IBI_HW_RES(x) ((((x)&GENMASK(31, 28)) >> 28) + 1) -#define CONF_STATUS1_CMD_DEPTH(x) (4 << (((x)&GENMASK(27, 26)) >> 26)) +#define CONF_STATUS1 0x8 +#define CONF_STATUS1_IBI_HW_RES(x) ((((x)&GENMASK(31, 28)) >> 28) + 1) +#define CONF_STATUS1_CMD_DEPTH(x) (4 << (((x)&GENMASK(27, 26)) >> 26)) #define CONF_STATUS1_SLVDDR_RX_DEPTH(x) (8 << (((x)&GENMASK(25, 21)) >> 21)) #define CONF_STATUS1_SLVDDR_TX_DEPTH(x) (8 << (((x)&GENMASK(20, 16)) >> 16)) -#define CONF_STATUS1_IBI_DEPTH(x) (2 << (((x)&GENMASK(12, 10)) >> 10)) -#define CONF_STATUS1_RX_DEPTH(x) (8 << (((x)&GENMASK(9, 5)) >> 5)) -#define CONF_STATUS1_TX_DEPTH(x) (8 << ((x)&GENMASK(4, 0))) - -#define REV_ID 0xc -#define REV_ID_VID(id) (((id)&GENMASK(31, 20)) >> 20) -#define REV_ID_PID(id) (((id)&GENMASK(19, 8)) >> 8) -#define REV_ID_REV(id) ((id)&GENMASK(7, 0)) +#define CONF_STATUS1_IBI_DEPTH(x) (2 << (((x)&GENMASK(12, 10)) >> 10)) +#define CONF_STATUS1_RX_DEPTH(x) (8 << (((x)&GENMASK(9, 5)) >> 5)) +#define CONF_STATUS1_TX_DEPTH(x) (8 << ((x)&GENMASK(4, 0))) + +#define REV_ID 0xc +#define REV_ID_VID(id) (((id)&GENMASK(31, 20)) >> 20) +#define REV_ID_PID(id) (((id)&GENMASK(19, 8)) >> 8) +#define REV_ID_REV(id) ((id)&GENMASK(7, 0)) #define REV_ID_VERSION(m, n) ((m << 5) | (n)) #define REV_ID_REV_MAJOR(id) (((id)&GENMASK(7, 5)) >> 5) #define REV_ID_REV_MINOR(id) ((id)&GENMASK(4, 0)) -#define CTRL 0x10 -#define CTRL_DEV_EN BIT(31) -#define CTRL_HALT_EN BIT(30) -#define CTRL_MCS BIT(29) -#define CTRL_MCS_EN BIT(28) -#define CTRL_I3C_11_SUPP BIT(26) -#define CTRL_THD_DELAY(x) (((x) << 24) & GENMASK(25, 24)) -#define CTRL_HJ_DISEC BIT(8) -#define CTRL_MST_ACK BIT(7) -#define CTRL_HJ_ACK BIT(6) -#define CTRL_HJ_INIT BIT(5) -#define CTRL_MST_INIT BIT(4) -#define CTRL_AHDR_OPT BIT(3) -#define CTRL_PURE_BUS_MODE 0 +#define CTRL 0x10 +#define CTRL_DEV_EN BIT(31) +#define CTRL_HALT_EN BIT(30) +#define CTRL_MCS BIT(29) +#define CTRL_MCS_EN BIT(28) +#define CTRL_I3C_11_SUPP BIT(26) +#define CTRL_THD_DELAY(x) (((x) << 24) & GENMASK(25, 24)) +#define CTRL_HJ_DISEC BIT(8) +#define CTRL_MST_ACK BIT(7) +#define CTRL_HJ_ACK BIT(6) +#define CTRL_HJ_INIT BIT(5) +#define CTRL_MST_INIT BIT(4) +#define CTRL_AHDR_OPT BIT(3) +#define CTRL_PURE_BUS_MODE 0 #define CTRL_MIXED_FAST_BUS_MODE 2 #define CTRL_MIXED_SLOW_BUS_MODE 3 -#define CTRL_BUS_MODE_MASK GENMASK(1, 0) -#define THD_DELAY_MAX 3 +#define CTRL_BUS_MODE_MASK GENMASK(1, 0) +#define THD_DELAY_MAX 3 -#define PRESCL_CTRL0 0x14 +#define PRESCL_CTRL0 0x14 #define PRESCL_CTRL0_I2C(x) ((x) << 16) #define PRESCL_CTRL0_I3C(x) (x) #define PRESCL_CTRL0_MAX GENMASK(9, 0) -#define PRESCL_CTRL1 0x18 +#define PRESCL_CTRL1 0x18 #define PRESCL_CTRL1_PP_LOW_MASK GENMASK(15, 8) -#define PRESCL_CTRL1_PP_LOW(x) ((x) << 8) +#define PRESCL_CTRL1_PP_LOW(x) ((x) << 8) #define PRESCL_CTRL1_OD_LOW_MASK GENMASK(7, 0) -#define PRESCL_CTRL1_OD_LOW(x) (x) - -#define MST_IER 0x20 -#define MST_IDR 0x24 -#define MST_IMR 0x28 -#define MST_ICR 0x2c -#define MST_ISR 0x30 -#define MST_INT_HALTED BIT(18) -#define MST_INT_MR_DONE BIT(17) +#define PRESCL_CTRL1_OD_LOW(x) (x) + +#define MST_IER 0x20 +#define MST_IDR 0x24 +#define MST_IMR 0x28 +#define MST_ICR 0x2c +#define MST_ISR 0x30 +#define MST_INT_HALTED BIT(18) +#define MST_INT_MR_DONE BIT(17) #define MST_INT_IMM_COMP BIT(16) -#define MST_INT_TX_THR BIT(15) -#define MST_INT_TX_OVF BIT(14) +#define MST_INT_TX_THR BIT(15) +#define MST_INT_TX_OVF BIT(14) #define MST_INT_IBID_THR BIT(12) #define MST_INT_IBID_UNF BIT(11) #define MST_INT_IBIR_THR BIT(10) #define MST_INT_IBIR_UNF BIT(9) #define MST_INT_IBIR_OVF BIT(8) -#define MST_INT_RX_THR BIT(7) -#define MST_INT_RX_UNF BIT(6) +#define MST_INT_RX_THR BIT(7) +#define MST_INT_RX_UNF BIT(6) #define MST_INT_CMDD_EMP BIT(5) #define MST_INT_CMDD_THR BIT(4) #define MST_INT_CMDD_OVF BIT(3) #define MST_INT_CMDR_THR BIT(2) #define MST_INT_CMDR_UNF BIT(1) #define MST_INT_CMDR_OVF BIT(0) -#define MST_INT_MASK GENMASK(18, 0) +#define MST_INT_MASK GENMASK(18, 0) -#define MST_STATUS0 0x34 -#define MST_STATUS0_IDLE BIT(18) -#define MST_STATUS0_HALTED BIT(17) +#define MST_STATUS0 0x34 +#define MST_STATUS0_IDLE BIT(18) +#define MST_STATUS0_HALTED BIT(17) #define MST_STATUS0_MASTER_MODE BIT(16) -#define MST_STATUS0_TX_FULL BIT(13) -#define MST_STATUS0_IBID_FULL BIT(12) -#define MST_STATUS0_IBIR_FULL BIT(11) -#define MST_STATUS0_RX_FULL BIT(10) -#define MST_STATUS0_CMDD_FULL BIT(9) -#define MST_STATUS0_CMDR_FULL BIT(8) -#define MST_STATUS0_TX_EMP BIT(5) -#define MST_STATUS0_IBID_EMP BIT(4) -#define MST_STATUS0_IBIR_EMP BIT(3) -#define MST_STATUS0_RX_EMP BIT(2) -#define MST_STATUS0_CMDD_EMP BIT(1) -#define MST_STATUS0_CMDR_EMP BIT(0) - -#define CMDR 0x38 -#define CMDR_NO_ERROR 0 +#define MST_STATUS0_TX_FULL BIT(13) +#define MST_STATUS0_IBID_FULL BIT(12) +#define MST_STATUS0_IBIR_FULL BIT(11) +#define MST_STATUS0_RX_FULL BIT(10) +#define MST_STATUS0_CMDD_FULL BIT(9) +#define MST_STATUS0_CMDR_FULL BIT(8) +#define MST_STATUS0_TX_EMP BIT(5) +#define MST_STATUS0_IBID_EMP BIT(4) +#define MST_STATUS0_IBIR_EMP BIT(3) +#define MST_STATUS0_RX_EMP BIT(2) +#define MST_STATUS0_CMDD_EMP BIT(1) +#define MST_STATUS0_CMDR_EMP BIT(0) + +#define CMDR 0x38 +#define CMDR_NO_ERROR 0 #define CMDR_DDR_PREAMBLE_ERROR 1 -#define CMDR_DDR_PARITY_ERROR 2 -#define CMDR_DDR_RX_FIFO_OVF 3 -#define CMDR_DDR_TX_FIFO_UNF 4 -#define CMDR_M0_ERROR 5 -#define CMDR_M1_ERROR 6 -#define CMDR_M2_ERROR 7 -#define CMDR_MST_ABORT 8 -#define CMDR_NACK_RESP 9 -#define CMDR_INVALID_DA 10 -#define CMDR_DDR_DROPPED 11 -#define CMDR_ERROR(x) (((x)&GENMASK(27, 24)) >> 24) -#define CMDR_XFER_BYTES(x) (((x)&GENMASK(19, 8)) >> 8) -#define CMDR_CMDID_HJACK_DISEC 0xfe +#define CMDR_DDR_PARITY_ERROR 2 +#define CMDR_DDR_RX_FIFO_OVF 3 +#define CMDR_DDR_TX_FIFO_UNF 4 +#define CMDR_M0_ERROR 5 +#define CMDR_M1_ERROR 6 +#define CMDR_M2_ERROR 7 +#define CMDR_MST_ABORT 8 +#define CMDR_NACK_RESP 9 +#define CMDR_INVALID_DA 10 +#define CMDR_DDR_DROPPED 11 +#define CMDR_ERROR(x) (((x)&GENMASK(27, 24)) >> 24) +#define CMDR_XFER_BYTES(x) (((x)&GENMASK(19, 8)) >> 8) +#define CMDR_CMDID_HJACK_DISEC 0xfe #define CMDR_CMDID_HJACK_ENTDAA 0xff -#define CMDR_CMDID(x) ((x)&GENMASK(7, 0)) +#define CMDR_CMDID(x) ((x)&GENMASK(7, 0)) -#define IBIR 0x3c -#define IBIR_ACKED BIT(12) -#define IBIR_SLVID(x) (((x)&GENMASK(11, 8)) >> 8) -#define IBIR_SLVID_INV 0xF -#define IBIR_ERROR BIT(7) +#define IBIR 0x3c +#define IBIR_ACKED BIT(12) +#define IBIR_SLVID(x) (((x)&GENMASK(11, 8)) >> 8) +#define IBIR_SLVID_INV 0xF +#define IBIR_ERROR BIT(7) #define IBIR_XFER_BYTES(x) (((x)&GENMASK(6, 2)) >> 2) -#define IBIR_TYPE_IBI 0 -#define IBIR_TYPE_HJ 1 -#define IBIR_TYPE_MR 2 -#define IBIR_TYPE(x) ((x)&GENMASK(1, 0)) - -#define SLV_IER 0x40 -#define SLV_IDR 0x44 -#define SLV_IMR 0x48 -#define SLV_ICR 0x4c -#define SLV_ISR 0x50 -#define SLV_INT_DEFSLVS BIT(21) -#define SLV_INT_TM BIT(20) -#define SLV_INT_ERROR BIT(19) +#define IBIR_TYPE_IBI 0 +#define IBIR_TYPE_HJ 1 +#define IBIR_TYPE_MR 2 +#define IBIR_TYPE(x) ((x)&GENMASK(1, 0)) + +#define SLV_IER 0x40 +#define SLV_IDR 0x44 +#define SLV_IMR 0x48 +#define SLV_ICR 0x4c +#define SLV_ISR 0x50 +#define SLV_INT_DEFSLVS BIT(21) +#define SLV_INT_TM BIT(20) +#define SLV_INT_ERROR BIT(19) #define SLV_INT_EVENT_UP BIT(18) -#define SLV_INT_HJ_DONE BIT(17) -#define SLV_INT_MR_DONE BIT(16) -#define SLV_INT_DA_UPD BIT(15) +#define SLV_INT_HJ_DONE BIT(17) +#define SLV_INT_MR_DONE BIT(16) +#define SLV_INT_DA_UPD BIT(15) #define SLV_INT_SDR_FAIL BIT(14) #define SLV_INT_DDR_FAIL BIT(13) #define SLV_INT_M_RD_ABORT BIT(12) @@ -177,73 +177,73 @@ #define SLV_INT_DDR_WR_COMP BIT(2) #define SLV_INT_SDR_RD_COMP BIT(1) #define SLV_INT_SDR_WR_COMP BIT(0) -#define SLV_INT_MASK GENMASK(20, 0) +#define SLV_INT_MASK GENMASK(20, 0) -#define SLV_STATUS0 0x54 -#define SLV_STATUS0_REG_ADDR(s) (((s)&GENMASK(23, 16)) >> 16) +#define SLV_STATUS0 0x54 +#define SLV_STATUS0_REG_ADDR(s) (((s)&GENMASK(23, 16)) >> 16) #define SLV_STATUS0_XFRD_BYTES(s) ((s)&GENMASK(15, 0)) -#define SLV_STATUS1 0x58 -#define SLV_STATUS1_AS(s) (((s)&GENMASK(21, 20)) >> 20) -#define SLV_STATUS1_VEN_TM BIT(19) -#define SLV_STATUS1_HJ_DIS BIT(18) -#define SLV_STATUS1_MR_DIS BIT(17) -#define SLV_STATUS1_PROT_ERR BIT(16) -#define SLV_STATUS1_DA(s) (((s)&GENMASK(15, 9)) >> 9) -#define SLV_STATUS1_HAS_DA BIT(8) -#define SLV_STATUS1_DDR_RX_FULL BIT(7) -#define SLV_STATUS1_DDR_TX_FULL BIT(6) +#define SLV_STATUS1 0x58 +#define SLV_STATUS1_AS(s) (((s)&GENMASK(21, 20)) >> 20) +#define SLV_STATUS1_VEN_TM BIT(19) +#define SLV_STATUS1_HJ_DIS BIT(18) +#define SLV_STATUS1_MR_DIS BIT(17) +#define SLV_STATUS1_PROT_ERR BIT(16) +#define SLV_STATUS1_DA(s) (((s)&GENMASK(15, 9)) >> 9) +#define SLV_STATUS1_HAS_DA BIT(8) +#define SLV_STATUS1_DDR_RX_FULL BIT(7) +#define SLV_STATUS1_DDR_TX_FULL BIT(6) #define SLV_STATUS1_DDR_RX_EMPTY BIT(5) #define SLV_STATUS1_DDR_TX_EMPTY BIT(4) -#define SLV_STATUS1_SDR_RX_FULL BIT(3) -#define SLV_STATUS1_SDR_TX_FULL BIT(2) +#define SLV_STATUS1_SDR_RX_FULL BIT(3) +#define SLV_STATUS1_SDR_TX_FULL BIT(2) #define SLV_STATUS1_SDR_RX_EMPTY BIT(1) #define SLV_STATUS1_SDR_TX_EMPTY BIT(0) -#define CMD0_FIFO 0x60 -#define CMD0_FIFO_IS_DDR BIT(31) -#define CMD0_FIFO_IS_CCC BIT(30) -#define CMD0_FIFO_BCH BIT(29) +#define CMD0_FIFO 0x60 +#define CMD0_FIFO_IS_DDR BIT(31) +#define CMD0_FIFO_IS_CCC BIT(30) +#define CMD0_FIFO_BCH BIT(29) #define XMIT_BURST_STATIC_SUBADDR 0 -#define XMIT_SINGLE_INC_SUBADDR 1 +#define XMIT_SINGLE_INC_SUBADDR 1 #define XMIT_SINGLE_STATIC_SUBADDR 2 #define XMIT_BURST_WITHOUT_SUBADDR 3 #define CMD0_FIFO_PRIV_XMIT_MODE(m) ((m) << 27) -#define CMD0_FIFO_SBCA BIT(26) -#define CMD0_FIFO_RSBC BIT(25) -#define CMD0_FIFO_IS_10B BIT(24) -#define CMD0_FIFO_PL_LEN(l) ((l) << 12) -#define CMD0_FIFO_PL_LEN_MAX 4095 -#define CMD0_FIFO_DEV_ADDR(a) ((a) << 1) -#define CMD0_FIFO_RNW BIT(0) - -#define CMD1_FIFO 0x64 +#define CMD0_FIFO_SBCA BIT(26) +#define CMD0_FIFO_RSBC BIT(25) +#define CMD0_FIFO_IS_10B BIT(24) +#define CMD0_FIFO_PL_LEN(l) ((l) << 12) +#define CMD0_FIFO_PL_LEN_MAX 4095 +#define CMD0_FIFO_DEV_ADDR(a) ((a) << 1) +#define CMD0_FIFO_RNW BIT(0) + +#define CMD1_FIFO 0x64 #define CMD1_FIFO_CMDID(id) ((id) << 24) #define CMD1_FIFO_CSRADDR(a) (a) #define CMD1_FIFO_CCC(id) (id) #define TX_FIFO 0x68 -#define IMD_CMD0 0x70 +#define IMD_CMD0 0x70 #define IMD_CMD0_PL_LEN(l) ((l) << 12) #define IMD_CMD0_DEV_ADDR(a) ((a) << 1) -#define IMD_CMD0_RNW BIT(0) +#define IMD_CMD0_RNW BIT(0) -#define IMD_CMD1 0x74 +#define IMD_CMD1 0x74 #define IMD_CMD1_CCC(id) (id) -#define IMD_DATA 0x78 -#define RX_FIFO 0x80 -#define IBI_DATA_FIFO 0x84 +#define IMD_DATA 0x78 +#define RX_FIFO 0x80 +#define IBI_DATA_FIFO 0x84 #define SLV_DDR_TX_FIFO 0x88 #define SLV_DDR_RX_FIFO 0x8c #define CMD_IBI_THR_CTRL 0x90 -#define IBIR_THR(t) ((t) << 24) -#define CMDR_THR(t) ((t) << 16) -#define CMDR_THR_MASK (GENMASK(20, 16)) -#define IBI_THR(t) ((t) << 8) -#define CMD_THR(t) (t) +#define IBIR_THR(t) ((t) << 24) +#define CMDR_THR(t) ((t) << 16) +#define CMDR_THR_MASK (GENMASK(20, 16)) +#define IBI_THR(t) ((t) << 8) +#define CMD_THR(t) (t) #define TX_RX_THR_CTRL 0x94 #define RX_THR(t) ((t) << 16) @@ -255,91 +255,91 @@ #define SLV_DDR_RX_THR(t) ((t) << 16) #define SLV_DDR_TX_THR(t) (t) -#define FLUSH_CTRL 0x9c -#define FLUSH_IBI_RESP BIT(23) -#define FLUSH_CMD_RESP BIT(22) +#define FLUSH_CTRL 0x9c +#define FLUSH_IBI_RESP BIT(23) +#define FLUSH_CMD_RESP BIT(22) #define FLUSH_SLV_DDR_RX_FIFO BIT(22) #define FLUSH_SLV_DDR_TX_FIFO BIT(21) -#define FLUSH_IMM_FIFO BIT(20) -#define FLUSH_IBI_FIFO BIT(19) -#define FLUSH_RX_FIFO BIT(18) -#define FLUSH_TX_FIFO BIT(17) -#define FLUSH_CMD_FIFO BIT(16) +#define FLUSH_IMM_FIFO BIT(20) +#define FLUSH_IBI_FIFO BIT(19) +#define FLUSH_RX_FIFO BIT(18) +#define FLUSH_TX_FIFO BIT(17) +#define FLUSH_CMD_FIFO BIT(16) -#define TTO_PRESCL_CTRL0 0xb0 +#define TTO_PRESCL_CTRL0 0xb0 #define TTO_PRESCL_CTRL0_PRESCL_I2C(x) ((x) << 16) #define TTO_PRESCL_CTRL0_PRESCL_I3C(x) (x) -#define TTO_PRESCL_CTRL1 0xb4 +#define TTO_PRESCL_CTRL1 0xb4 #define TTO_PRESCL_CTRL1_DIVB(x) ((x) << 16) #define TTO_PRESCL_CTRL1_DIVA(x) (x) #define TTO_PRESCL_CTRL1_PP_LOW(x) ((x) << 8) #define TTO_PRESCL_CTRL1_OD_LOW(x) (x) -#define DEVS_CTRL 0xb8 -#define DEVS_CTRL_DEV_CLR_SHIFT 16 -#define DEVS_CTRL_DEV_CLR_ALL GENMASK(31, 16) -#define DEVS_CTRL_DEV_CLR(dev) BIT(16 + (dev)) +#define DEVS_CTRL 0xb8 +#define DEVS_CTRL_DEV_CLR_SHIFT 16 +#define DEVS_CTRL_DEV_CLR_ALL GENMASK(31, 16) +#define DEVS_CTRL_DEV_CLR(dev) BIT(16 + (dev)) #define DEVS_CTRL_DEV_ACTIVE(dev) BIT(dev) #define DEVS_CTRL_DEVS_ACTIVE_MASK GENMASK(15, 0) -#define MAX_DEVS 16 +#define MAX_DEVS 16 -#define DEV_ID_RR0(d) (0xc0 + ((d)*0x10)) -#define DEV_ID_RR0_LVR_EXT_ADDR BIT(11) -#define DEV_ID_RR0_HDR_CAP BIT(10) -#define DEV_ID_RR0_IS_I3C BIT(9) +#define DEV_ID_RR0(d) (0xc0 + ((d)*0x10)) +#define DEV_ID_RR0_LVR_EXT_ADDR BIT(11) +#define DEV_ID_RR0_HDR_CAP BIT(10) +#define DEV_ID_RR0_IS_I3C BIT(9) #define DEV_ID_RR0_DEV_ADDR_MASK (GENMASK(6, 0) | GENMASK(15, 13)) #define DEV_ID_RR0_SET_DEV_ADDR(a) (((a)&GENMASK(6, 0)) | (((a)&GENMASK(9, 7)) << 6)) #define DEV_ID_RR0_GET_DEV_ADDR(x) ((((x) >> 1) & GENMASK(6, 0)) | (((x) >> 6) & GENMASK(9, 7))) -#define DEV_ID_RR1(d) (0xc4 + ((d)*0x10)) +#define DEV_ID_RR1(d) (0xc4 + ((d)*0x10)) #define DEV_ID_RR1_PID_MSB(pid) (pid) -#define DEV_ID_RR2(d) (0xc8 + ((d)*0x10)) +#define DEV_ID_RR2(d) (0xc8 + ((d)*0x10)) #define DEV_ID_RR2_PID_LSB(pid) ((pid) << 16) -#define DEV_ID_RR2_BCR(bcr) ((bcr) << 8) -#define DEV_ID_RR2_DCR(dcr) (dcr) -#define DEV_ID_RR2_LVR(lvr) (lvr) +#define DEV_ID_RR2_BCR(bcr) ((bcr) << 8) +#define DEV_ID_RR2_DCR(dcr) (dcr) +#define DEV_ID_RR2_LVR(lvr) (lvr) -#define SIR_MAP(x) (0x180 + ((x)*4)) -#define SIR_MAP_DEV_REG(d) SIR_MAP((d) / 2) +#define SIR_MAP(x) (0x180 + ((x)*4)) +#define SIR_MAP_DEV_REG(d) SIR_MAP((d) / 2) #define SIR_MAP_DEV_SHIFT(d, fs) ((fs) + (((d) % 2) ? 16 : 0)) #define SIR_MAP_DEV_CONF_MASK(d) (GENMASK(15, 0) << (((d) % 2) ? 16 : 0)) -#define SIR_MAP_DEV_CONF(d, c) ((c) << (((d) % 2) ? 16 : 0)) -#define DEV_ROLE_SLAVE 0 -#define DEV_ROLE_MASTER 1 -#define SIR_MAP_DEV_ROLE(role) ((role) << 14) -#define SIR_MAP_DEV_SLOW BIT(13) -#define SIR_MAP_DEV_PL(l) ((l) << 8) -#define SIR_MAP_PL_MAX GENMASK(4, 0) -#define SIR_MAP_DEV_DA(a) ((a) << 1) -#define SIR_MAP_DEV_ACK BIT(0) - -#define GPIR_WORD(x) (0x200 + ((x)*4)) +#define SIR_MAP_DEV_CONF(d, c) ((c) << (((d) % 2) ? 16 : 0)) +#define DEV_ROLE_SLAVE 0 +#define DEV_ROLE_MASTER 1 +#define SIR_MAP_DEV_ROLE(role) ((role) << 14) +#define SIR_MAP_DEV_SLOW BIT(13) +#define SIR_MAP_DEV_PL(l) ((l) << 8) +#define SIR_MAP_PL_MAX GENMASK(4, 0) +#define SIR_MAP_DEV_DA(a) ((a) << 1) +#define SIR_MAP_DEV_ACK BIT(0) + +#define GPIR_WORD(x) (0x200 + ((x)*4)) #define GPI_REG(val, id) (((val) >> (((id) % 4) * 8)) & GENMASK(7, 0)) -#define GPOR_WORD(x) (0x220 + ((x)*4)) +#define GPOR_WORD(x) (0x220 + ((x)*4)) #define GPO_REG(val, id) (((val) >> (((id) % 4) * 8)) & GENMASK(7, 0)) -#define ASF_INT_STATUS 0x300 +#define ASF_INT_STATUS 0x300 #define ASF_INT_RAW_STATUS 0x304 -#define ASF_INT_MASK 0x308 -#define ASF_INT_TEST 0x30c +#define ASF_INT_MASK 0x308 +#define ASF_INT_TEST 0x30c #define ASF_INT_FATAL_SELECT 0x310 #define ASF_INTEGRITY_ERR BIT(6) #define ASF_PROTOCOL_ERR BIT(5) #define ASF_TRANS_TIMEOUT_ERR BIT(4) -#define ASF_CSR_ERR BIT(3) -#define ASF_DAP_ERR BIT(2) +#define ASF_CSR_ERR BIT(3) +#define ASF_DAP_ERR BIT(2) #define ASF_SRAM_UNCORR_ERR BIT(1) #define ASF_SRAM_CORR_ERR BIT(0) -#define ASF_SRAM_CORR_FAULT_STATUS 0x320 -#define ASF_SRAM_UNCORR_FAULT_STATUS 0x324 +#define ASF_SRAM_CORR_FAULT_STATUS 0x320 +#define ASF_SRAM_UNCORR_FAULT_STATUS 0x324 #define ASF_SRAM_CORR_FAULT_INSTANCE(x) ((x) >> 24) -#define ASF_SRAM_CORR_FAULT_ADDR(x) ((x)&GENMASK(23, 0)) +#define ASF_SRAM_CORR_FAULT_ADDR(x) ((x)&GENMASK(23, 0)) -#define ASF_SRAM_FAULT_STATS 0x328 +#define ASF_SRAM_FAULT_STATS 0x328 #define ASF_SRAM_FAULT_UNCORR_STATS(x) ((x) >> 16) #define ASF_SRAM_FAULT_CORR_STATS(x) ((x)&GENMASK(15, 0)) @@ -354,14 +354,14 @@ #define ASF_TRANS_TOUT_FAULT_SCL_HIGH BIT(1) #define ASF_TRANS_TOUT_FAULT_FSCL_HIGH BIT(0) -#define ASF_PROTO_FAULT_MASK 0x340 -#define ASF_PROTO_FAULT_STATUS 0x344 +#define ASF_PROTO_FAULT_MASK 0x340 +#define ASF_PROTO_FAULT_STATUS 0x344 #define ASF_PROTO_FAULT_SLVSDR_RD_ABORT BIT(31) -#define ASF_PROTO_FAULT_SLVDDR_FAIL BIT(30) -#define ASF_PROTO_FAULT_S(x) BIT(16 + (x)) +#define ASF_PROTO_FAULT_SLVDDR_FAIL BIT(30) +#define ASF_PROTO_FAULT_S(x) BIT(16 + (x)) #define ASF_PROTO_FAULT_MSTSDR_RD_ABORT BIT(15) -#define ASF_PROTO_FAULT_MSTDDR_FAIL BIT(14) -#define ASF_PROTO_FAULT_M(x) BIT(x) +#define ASF_PROTO_FAULT_MSTDDR_FAIL BIT(14) +#define ASF_PROTO_FAULT_M(x) BIT(x) /******************************************************************************* * Local Constants Definition @@ -371,13 +371,13 @@ #define I3C_CONTROLLER_ADDR 0x08 /* Maximum i3c devices that the IP can be built with */ -#define I3C_MAX_DEVS 11 -#define I3C_MAX_MSGS 10 -#define I3C_SIR_DEFAULT_DA 0x7F -#define I3C_MAX_IDLE_CANCEL_WAIT_RETRIES 50 -#define I3C_PRESCL_REG_SCALE (4) -#define I2C_PRESCL_REG_SCALE (5) -#define I3C_WAIT_FOR_IDLE_STATE_US 100 +#define I3C_MAX_DEVS 11 +#define I3C_MAX_MSGS 10 +#define I3C_SIR_DEFAULT_DA 0x7F +#define I3C_MAX_IDLE_CANCEL_WAIT_RETRIES 50 +#define I3C_PRESCL_REG_SCALE (4) +#define I2C_PRESCL_REG_SCALE (5) +#define I3C_WAIT_FOR_IDLE_STATE_US 100 #define I3C_IDLE_TIMEOUT_CYC \ (I3C_WAIT_FOR_IDLE_STATE_US * (sys_clock_hw_cycles_per_sec() / USEC_PER_SEC)) From b3e8b1f12bd18be6e7ed3197b34a83bd85433cdc Mon Sep 17 00:00:00 2001 From: Ryan McClelland Date: Thu, 13 Jul 2023 23:37:04 -0700 Subject: [PATCH 1310/3723] manifest: wurthelektronik: update revision for double promotion fix Update wurtheletronik, this is needed for the double promotion fix Signed-off-by: Ryan McClelland --- west.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/west.yml b/west.yml index 7f90fbf59e8..6e5b4d2af25 100644 --- a/west.yml +++ b/west.yml @@ -244,7 +244,7 @@ manifest: groups: - hal - name: hal_wurthelektronik - revision: 24ca9873c3d608fad1fea0431836bc8f144c132e + revision: e5bcb2eac1bb9639ce13b4dafc78eb254e014342 path: modules/hal/wurthelektronik groups: - hal From 6bb610581e990ae5235b30672578893440172e26 Mon Sep 17 00:00:00 2001 From: Ryan McClelland Date: Wed, 19 Jul 2023 12:26:26 -0700 Subject: [PATCH 1311/3723] manifest: hal_openisa: update revision for double promotion fix Update hal_openisa, this is needed for the double promotion fix Signed-off-by: Ryan McClelland --- west.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/west.yml b/west.yml index 6e5b4d2af25..9740133cea0 100644 --- a/west.yml +++ b/west.yml @@ -198,7 +198,7 @@ manifest: groups: - hal - name: hal_openisa - revision: d1e61c0c654d8ca9e73d27fca3a7eb3b7881cb6a + revision: eabd530a64d71de91d907bad257cd61aacf607bc path: modules/hal/openisa groups: - hal From 039e5ef1b8134a672ffa5b8d3e3264b53e354422 Mon Sep 17 00:00:00 2001 From: Marc Herbert Date: Fri, 8 Dec 2023 00:34:21 +0000 Subject: [PATCH 1312/3723] intel_adsp: remove rimage sign() from `west flash` `west sign` has been invoked by `west build` (through CMake) since commit fad2da39aaaf, almost one year ago. During that time, this new workflow has been refined and successfully used by at least two vendors, multiple CIs across both SOF and Zephyr and many developers. At the time, the ability to sign from `west flash` was preserved for backwards compatibility. This means rimage parameters can come from many different places at once and that rimage can be invoked twice during a single `west flash` invocation! Now that Zephyr 3.5 has been released, we need to reduce the number of rimage use cases and the corresponding validation complexity and maintenance workload to simplify and accelerate new features like splitting rimage configuration files (#65411) Signed-off-by: Marc Herbert --- boards/common/intel_adsp.board.cmake | 5 -- .../xtensa/intel_adsp_ace15_mtpm/board.cmake | 2 +- boards/xtensa/intel_adsp_cavs25/board.cmake | 2 +- .../doc/intel_adsp_generic.rst | 10 ++- scripts/west_commands/runners/intel_adsp.py | 66 ++++--------------- 5 files changed, 17 insertions(+), 68 deletions(-) delete mode 100644 boards/common/intel_adsp.board.cmake diff --git a/boards/common/intel_adsp.board.cmake b/boards/common/intel_adsp.board.cmake deleted file mode 100644 index 813ece3fb99..00000000000 --- a/boards/common/intel_adsp.board.cmake +++ /dev/null @@ -1,5 +0,0 @@ -# SPDX-License-Identifier: Apache-2.0 - -board_runner_args(intel_adsp "--default-key=${RIMAGE_SIGN_KEY}") - -board_finalize_runner_args(intel_adsp) diff --git a/boards/xtensa/intel_adsp_ace15_mtpm/board.cmake b/boards/xtensa/intel_adsp_ace15_mtpm/board.cmake index 63777239a1d..e9778da4d84 100644 --- a/boards/xtensa/intel_adsp_ace15_mtpm/board.cmake +++ b/boards/xtensa/intel_adsp_ace15_mtpm/board.cmake @@ -6,4 +6,4 @@ board_set_rimage_target(mtl) set(RIMAGE_SIGN_KEY "otc_private_key_3k.pem" CACHE STRING "default in ace15_mtpm/board.cmake") -include(${ZEPHYR_BASE}/boards/common/intel_adsp.board.cmake) +board_finalize_runner_args(intel_adsp) diff --git a/boards/xtensa/intel_adsp_cavs25/board.cmake b/boards/xtensa/intel_adsp_cavs25/board.cmake index 8d7f36e07bd..1bdb2698c12 100644 --- a/boards/xtensa/intel_adsp_cavs25/board.cmake +++ b/boards/xtensa/intel_adsp_cavs25/board.cmake @@ -17,4 +17,4 @@ if(CONFIG_BOARD_INTEL_ADSP_CAVS25_TGPH) board_set_rimage_target(tgl-h) endif() -include(${ZEPHYR_BASE}/boards/common/intel_adsp.board.cmake) +board_finalize_runner_args(intel_adsp) diff --git a/boards/xtensa/intel_adsp_cavs25/doc/intel_adsp_generic.rst b/boards/xtensa/intel_adsp_cavs25/doc/intel_adsp_generic.rst index fe97ed6466a..6b0a4526fe4 100644 --- a/boards/xtensa/intel_adsp_cavs25/doc/intel_adsp_generic.rst +++ b/boards/xtensa/intel_adsp_cavs25/doc/intel_adsp_generic.rst @@ -143,12 +143,10 @@ undocumented rimage precedence rules it's best to use only one way at a time. ``boards/my/board/board.cmake``, see example in ``soc/xtensa/intel_adsp/common/CMakeLists.txt`` -For backwards compatibility reasons, you can also pass rimage parameters like -the path to the tool binary as arguments to -``west flash`` if the flash target exists for your board. To see a list -of all arguments to the Intel ADSP runner, run the following after you have -built the binary. There are multiple arguments related to signing, including a -key argument. +Starting with Zephyr 3.6.0, ``west flash`` does not invoke ``west sign`` +anymore and you cannot pass rimage parameters to ``west flash`` anymore. To +see an up-to-date list of all arguments to the Intel ADSP runner, run the +following after you have built the binary: .. code-block:: console diff --git a/scripts/west_commands/runners/intel_adsp.py b/scripts/west_commands/runners/intel_adsp.py index 18b1462ef05..f7587331dc3 100644 --- a/scripts/west_commands/runners/intel_adsp.py +++ b/scripts/west_commands/runners/intel_adsp.py @@ -4,6 +4,7 @@ '''Runner for flashing with the Intel ADSP boards.''' +import argparse import os import sys import re @@ -14,11 +15,12 @@ from zephyr_ext_common import ZEPHYR_BASE DEFAULT_CAVSTOOL='soc/xtensa/intel_adsp/tools/cavstool_client.py' -DEFAULT_SOF_MOD_DIR=os.path.join(ZEPHYR_BASE, '../modules/audio/sof') -DEFAULT_RIMAGE_TOOL=shutil.which('rimage') -DEFAULT_CONFIG_DIR=os.path.join(DEFAULT_SOF_MOD_DIR, 'tools/rimage/config') -DEFAULT_KEY_DIR=os.path.join(DEFAULT_SOF_MOD_DIR, 'keys') +class SignParamError(argparse.Action): + 'User-friendly feedback when trying to sign with west flash' + def __call__(self, parser, namespace, values, option_string=None): + parser.error(f'Cannot use "west flash {option_string} ..." any more. ' + + '"west sign" is now called from CMake, see "west sign -h"') class IntelAdspBinaryRunner(ZephyrBinaryRunner): '''Runner front-end for the intel ADSP boards.''' @@ -26,32 +28,19 @@ class IntelAdspBinaryRunner(ZephyrBinaryRunner): def __init__(self, cfg, remote_host, - rimage_tool, - config_dir, - default_key, - key, pty, tool_opt, - do_sign, ): super().__init__(cfg) self.remote_host = remote_host - self.rimage_tool = rimage_tool - self.config_dir = config_dir self.bin_fw = os.path.join(cfg.build_dir, 'zephyr', 'zephyr.ri') self.cavstool = os.path.join(ZEPHYR_BASE, DEFAULT_CAVSTOOL) self.platform = os.path.basename(cfg.board_dir) self.pty = pty - if key: - self.key = key - else: - self.key = os.path.join(DEFAULT_KEY_DIR, default_key) - self.tool_opt_args = tool_opt - self.do_sign = do_sign @classmethod def name(cls): @@ -65,18 +54,14 @@ def capabilities(cls): def do_add_parser(cls, parser): parser.add_argument('--remote-host', help='hostname of the remote targeting ADSP board') - parser.add_argument('--rimage-tool', default=DEFAULT_RIMAGE_TOOL, - help='path to the rimage tool') - parser.add_argument('--config-dir', default=DEFAULT_CONFIG_DIR, - help='path to the toml config file') - parser.add_argument('--default-key', - help='the default basename of the key store in board.cmake') - parser.add_argument('--key', - help='specify where the signing key is') parser.add_argument('--pty', nargs='?', const="remote-host", type=str, help=''''Capture the output of cavstool.py running on --remote-host \ and stream it remotely to west's standard output.''') + for old_sign_param in [ '--rimage-tool', '--config-dir', '--default-key', '--key']: + parser.add_argument(old_sign_param, action=SignParamError, + help='do not use, "west sign" is now called from CMake, see "west sign -h"') + @classmethod def tool_opt_help(cls) -> str: return """Additional options for run/request service tool, @@ -84,35 +69,15 @@ def tool_opt_help(cls) -> str: @classmethod def do_create(cls, cfg, args): - # We now have `west flash` -> `west build` -> `west sign` so - # `west flash` -> `west sign` is not needed anymore; it's also - # slower because not concurrent. However, for backwards - # compatibility keep signing here if some explicit rimage - # --option was passed. Some of these options may differ from the - # current `west sign` configuration; we take "precedence" by - # running last. - do_sign = ( - args.rimage_tool != DEFAULT_RIMAGE_TOOL or - args.config_dir != DEFAULT_CONFIG_DIR or - args.key is not None - ) return IntelAdspBinaryRunner(cfg, remote_host=args.remote_host, - rimage_tool=args.rimage_tool, - config_dir=args.config_dir, - default_key=args.default_key, - key=args.key, pty=args.pty, tool_opt=args.tool_opt, - do_sign=do_sign, ) def do_run(self, command, **kwargs): self.logger.info('Starting Intel ADSP runner') - if self.do_sign: - self.sign(**kwargs) - if re.search("intel_adsp", self.platform): self.require(self.cavstool) self.flash(**kwargs) @@ -120,17 +85,8 @@ def do_run(self, command, **kwargs): self.logger.error("No suitable platform for running") sys.exit(1) - def sign(self, **kwargs): - path_opt = ['-p', f'{self.rimage_tool}'] if self.rimage_tool else [] - sign_cmd = ( - ['west', 'sign', '-d', f'{self.cfg.build_dir}', '-t', 'rimage'] - + path_opt + ['-D', f'{self.config_dir}', '--', '-k', f'{self.key}'] - ) - self.logger.info(" ".join(sign_cmd)) - self.check_call(sign_cmd) - def flash(self, **kwargs): - # Generate a hash string for appending to the sending ri file + 'Generate a hash string for appending to the sending ri file' hash_object = hashlib.md5(self.bin_fw.encode()) random_str = f"{random.getrandbits(64)}".encode() hash_object.update(random_str) From dbc4b2ed4ed574a00bfda4cd63f8cdd18d069bc1 Mon Sep 17 00:00:00 2001 From: Marc Herbert Date: Mon, 11 Dec 2023 05:44:10 +0000 Subject: [PATCH 1313/3723] west: sign.py: extract new method RimageSigner.rimage_config_dir() Zero functional change, preparation for the .toml modularization. RimageSigner.sign() is also way too long and too complex and this helps. Signed-off-by: Marc Herbert --- scripts/west_commands/sign.py | 36 ++++++++++++++++++++--------------- 1 file changed, 21 insertions(+), 15 deletions(-) diff --git a/scripts/west_commands/sign.py b/scripts/west_commands/sign.py index 0ad4c678398..bae2c5674e0 100644 --- a/scripts/west_commands/sign.py +++ b/scripts/west_commands/sign.py @@ -420,11 +420,26 @@ def edt_flash_params(flash): class RimageSigner(Signer): + def rimage_config_dir(self): + 'Returns the rimage/config/ directory with the highest precedence' + args = self.command.args + if args.tool_data: + conf_dir = pathlib.Path(args.tool_data) + elif self.cmake_cache.get('RIMAGE_CONFIG_PATH'): + conf_dir = pathlib.Path(self.cmake_cache['RIMAGE_CONFIG_PATH']) + else: + conf_dir = self.sof_src_dir / 'tools' / 'rimage' / 'config' + self.command.dbg(f'rimage config directory={conf_dir}') + return conf_dir + def sign(self, command, build_dir, build_conf, formats): + self.command = command args = command.args b = pathlib.Path(build_dir) + self.build_dir = b cache = CMakeCache.from_build_dir(build_dir) + self.cmake_cache = cache # Warning: RIMAGE_TARGET in Zephyr is a duplicate of # CONFIG_RIMAGE_SIGNING_SCHEMA in SOF. @@ -481,8 +496,6 @@ def sign(self, command, build_dir, build_conf, formats): #### -c sof/rimage/config/signing_schema.toml #### - cmake_toml = target + '.toml' - if not args.quiet: log.inf('Signing with tool {}'.format(tool_path)) @@ -492,19 +505,8 @@ def sign(self, command, build_dir, build_conf, formats): except ValueError: # sof is the manifest sof_src_dir = pathlib.Path(manifest.manifest_path()).parent - if '-c' in args.tool_args: - # Precedence to the arguments passed after '--': west sign ... -- -c ... - if args.tool_data: - log.wrn('--tool-data ' + args.tool_data + ' ignored, overridden by: -- -c ... ') - conf_dir = None - elif args.tool_data: - conf_dir = pathlib.Path(args.tool_data) - elif cache.get('RIMAGE_CONFIG_PATH'): - conf_dir = pathlib.Path(cache['RIMAGE_CONFIG_PATH']) - else: - conf_dir = sof_src_dir / 'tools' / 'rimage' / 'config' + self.sof_src_dir = sof_src_dir - conf_path_cmd = ['-c', str(conf_dir / cmake_toml)] if conf_dir else [] log.inf('Signing for SOC target ' + target) @@ -545,8 +547,12 @@ def sign(self, command, build_dir, build_conf, formats): cmake_default_key = cache.get('RIMAGE_SIGN_KEY', 'key placeholder from sign.py') extra_ri_args += [ '-k', str(sof_src_dir / 'keys' / cmake_default_key) ] + if args.tool_data and '-c' in args.tool_args: + log.wrn('--tool-data ' + args.tool_data + ' ignored! Overridden by: -- -c ... ') + if '-c' not in sign_config_extra_args + args.tool_args: - extra_ri_args += conf_path_cmd + conf_dir = self.rimage_config_dir() + extra_ri_args += ['-c', str(conf_dir / (target + '.toml'))] # Warning: while not officially supported (yet?), the rimage --option that is last # on the command line currently wins in case of duplicate options. So pay From c13cf99f2a90f08ad335bbc5add49bd97b1d9269 Mon Sep 17 00:00:00 2001 From: Marc Herbert Date: Mon, 11 Dec 2023 00:56:08 +0000 Subject: [PATCH 1314/3723] west: sign.py: recommend separator -- tool_args always In the following command, the first argument `for_rimage` is passed to `rimage` whereas `--for west` goes to west. ``` west sign for_rimage --for west ``` This is somehow valid but we really don't want anyone to do that. Signed-off-by: Marc Herbert --- scripts/west_commands/sign.py | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/scripts/west_commands/sign.py b/scripts/west_commands/sign.py index bae2c5674e0..cd29dd589cf 100644 --- a/scripts/west_commands/sign.py +++ b/scripts/west_commands/sign.py @@ -34,9 +34,11 @@ west sign -t your_tool -- ARGS_FOR_YOUR_TOOL -The "ARGS_FOR_YOUR_TOOL" value can be any additional -arguments you want to pass to the tool, such as the location of a -signing key etc. +The "ARGS_FOR_YOUR_TOOL" value can be any additional arguments you want to +pass to the tool, such as the location of a signing key etc. Depending on +which sort of ARGS_FOR_YOUR_TOOLS you use, the `--` separator/sentinel may +not always be required. To avoid ambiguity and having to find and +understand POSIX 12.2 Guideline 10, always use `--`. See tool-specific help below for details.''' From a65b8d40fbf4d7aa1e5cc1f2f6bd85a4a0706238 Mon Sep 17 00:00:00 2001 From: Marc Herbert Date: Mon, 11 Dec 2023 01:26:58 +0000 Subject: [PATCH 1315/3723] west: sign.py: always log the rimage command rimage is very verbose by default and has no -q(uiet) option, so saving one line out of more than 100 lines is pointless. RimageSigner.sign() was already very complex and suffering from combinatorial explosion of parameters. With .toml pre-processing (#65411) it's getting worse, so we really need all build logs to show the complete rimage command. Signed-off-by: Marc Herbert --- scripts/west_commands/sign.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/scripts/west_commands/sign.py b/scripts/west_commands/sign.py index cd29dd589cf..4e5e459eff5 100644 --- a/scripts/west_commands/sign.py +++ b/scripts/west_commands/sign.py @@ -535,7 +535,8 @@ def sign(self, command, build_dir, build_conf, formats): sign_base = [tool_path] - # Sub-command arg '-q' takes precedence over west '-v' + # Align rimage verbosity. + # Sub-command arg 'west sign -q' takes precedence over west '-v' if not args.quiet and args.verbose: sign_base += ['-v'] * args.verbose @@ -562,8 +563,7 @@ def sign(self, command, build_dir, build_conf, formats): sign_base += (['-o', out_bin] + sign_config_extra_args + extra_ri_args + args.tool_args + components) - if not args.quiet: - log.inf(quote_sh_list(sign_base)) + command.inf(quote_sh_list(sign_base)) subprocess.check_call(sign_base) if no_manifest: From 15336045aff85e2027748de89ab5a662492eff83 Mon Sep 17 00:00:00 2001 From: Marc Herbert Date: Tue, 12 Dec 2023 06:18:44 +0000 Subject: [PATCH 1316/3723] west: sign.py: generate platf.toml from platf.toml.h with cc -E Allow using the C pre-processor to generate a `rimage/config/platform.toml` file from a "source" `rimage/config/platform.toml.h` file. This is optional and fully backwards compatible. To use, do not use `-c` and point west sign at a configuration directory instead or let it use the default `rimage/config/` directory and change the files there. Signed-off-by: Marc Herbert --- scripts/west_commands/sign.py | 26 +++++++++++++++++++++++++- 1 file changed, 25 insertions(+), 1 deletion(-) diff --git a/scripts/west_commands/sign.py b/scripts/west_commands/sign.py index 4e5e459eff5..8d961004adb 100644 --- a/scripts/west_commands/sign.py +++ b/scripts/west_commands/sign.py @@ -434,6 +434,18 @@ def rimage_config_dir(self): self.command.dbg(f'rimage config directory={conf_dir}') return conf_dir + def preprocess_toml(self, config_dir, toml_basename, subdir): + 'Runs the C pre-processor on config_dir/toml_basename.h' + + compiler_path = self.cmake_cache.get("CMAKE_C_COMPILER") + preproc_cmd = [compiler_path, '-P', '-E', str(config_dir / (toml_basename + '.h'))] + preproc_cmd += ['-I', str(self.sof_src_dir / 'src')] + preproc_cmd += ['-imacros', + str(pathlib.Path('zephyr') / 'include' / 'generated' / 'autoconf.h')] + preproc_cmd += ['-o', str(subdir / toml_basename)] + self.command.inf(quote_sh_list(preproc_cmd)) + subprocess.run(preproc_cmd, check=True, cwd=self.build_dir) + def sign(self, command, build_dir, build_conf, formats): self.command = command args = command.args @@ -555,7 +567,19 @@ def sign(self, command, build_dir, build_conf, formats): if '-c' not in sign_config_extra_args + args.tool_args: conf_dir = self.rimage_config_dir() - extra_ri_args += ['-c', str(conf_dir / (target + '.toml'))] + toml_basename = target + '.toml' + if ((conf_dir / toml_basename).exists() and + (conf_dir / (toml_basename + '.h')).exists()): + command.die(f"Cannot have both {toml_basename + '.h'} and {toml_basename} in {conf_dir}") + + if (conf_dir / (toml_basename + '.h')).exists(): + toml_subdir = pathlib.Path('zephyr') / 'misc' / 'generated' + self.preprocess_toml(conf_dir, toml_basename, toml_subdir) + toml_dir = b / toml_subdir + else: + toml_dir = conf_dir + + extra_ri_args += ['-c', str(toml_dir / toml_basename)] # Warning: while not officially supported (yet?), the rimage --option that is last # on the command line currently wins in case of duplicate options. So pay From e70a1a0c4835c230776fa28a386a09c5f70c169d Mon Sep 17 00:00:00 2001 From: Abderrahmane Jarmouni Date: Tue, 12 Dec 2023 15:29:22 +0100 Subject: [PATCH 1317/3723] board: arm: stm32f429i_disc1: flashing Add the possibility to flash stm32f429i_disc1 board using STM32CubeProgrammer & patch the OpenOCD cfg. Signed-off-by: Abderrahmane Jarmouni --- boards/arm/stm32f429i_disc1/board.cmake | 2 ++ boards/arm/stm32f429i_disc1/doc/index.rst | 11 +++++++++++ boards/arm/stm32f429i_disc1/support/openocd.cfg | 9 ++++++++- 3 files changed, 21 insertions(+), 1 deletion(-) diff --git a/boards/arm/stm32f429i_disc1/board.cmake b/boards/arm/stm32f429i_disc1/board.cmake index 7e8103a64b0..402b28d32c0 100644 --- a/boards/arm/stm32f429i_disc1/board.cmake +++ b/boards/arm/stm32f429i_disc1/board.cmake @@ -1,6 +1,8 @@ # SPDX-License-Identifier: Apache-2.0 +board_runner_args(stm32cubeprogrammer "--erase" "--port=swd" "--reset-mode=hw") board_runner_args(jlink "--device=STM32F429ZI" "--speed=4000") include(${ZEPHYR_BASE}/boards/common/openocd.board.cmake) +include(${ZEPHYR_BASE}/boards/common/stm32cubeprogrammer.board.cmake) include(${ZEPHYR_BASE}/boards/common/jlink.board.cmake) diff --git a/boards/arm/stm32f429i_disc1/doc/index.rst b/boards/arm/stm32f429i_disc1/doc/index.rst index 1a8defe5340..b2787dc7d98 100644 --- a/boards/arm/stm32f429i_disc1/doc/index.rst +++ b/boards/arm/stm32f429i_disc1/doc/index.rst @@ -161,6 +161,14 @@ This interface is supported by the openocd version included in Zephyr SDK. Flashing an application to STM32F429I-DISC1 ------------------------------------------- +The board is configured to be flashed using west OpenOCD runner. +Alternatively, you can use `STM32CubeProgrammer`_ (after installing it) using the ``--runner`` +(or ``-r``) option: + +.. code-block:: console + + $ west flash --runner stm32cubeprogrammer + First, connect the STM32F429I-DISC1 Discovery kit to your host computer using the USB port to prepare it for flashing. Then build and flash your application. @@ -206,3 +214,6 @@ You can debug an application in the usual way. Here is an example for the .. _STM32F429 Reference Manual: https://www.st.com/content/ccc/resource/technical/document/reference_manual/3d/6d/5a/66/b4/99/40/d4/DM00031020.pdf/files/DM00031020.pdf/jcr:content/translations/en.DM00031020.pdf + +.. _STM32CubeProgrammer: + https://www.st.com/en/development-tools/stm32cubeprog.html diff --git a/boards/arm/stm32f429i_disc1/support/openocd.cfg b/boards/arm/stm32f429i_disc1/support/openocd.cfg index d1426b667d5..98fed0614df 100644 --- a/boards/arm/stm32f429i_disc1/support/openocd.cfg +++ b/boards/arm/stm32f429i_disc1/support/openocd.cfg @@ -1,4 +1,11 @@ -source [find board/st_nucleo_f4.cfg] +source [find interface/stlink-dap.cfg] + +transport select "dapdirect_swd" + +set CHIPNAME STM32F429ZITx +set BOARDNAME STM32F429I-DISC1 + +source [find target/stm32f4x.cfg] $_TARGETNAME configure -event gdb-attach { echo "Debugger attaching: halting execution" From 8977784afee870e107f639ace7a4b5cd57cfaeb6 Mon Sep 17 00:00:00 2001 From: Flavio Ceolin Date: Tue, 12 Dec 2023 10:20:45 -0800 Subject: [PATCH 1318/3723] settings: shell: Fix possible buffer overflow Checks the size of the given string before copying it to internal buffer. Signed-off-by: Flavio Ceolin --- subsys/settings/src/settings_shell.c | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/subsys/settings/src/settings_shell.c b/subsys/settings/src/settings_shell.c index e8132eeeb49..bef6b23c2b5 100644 --- a/subsys/settings/src/settings_shell.c +++ b/subsys/settings/src/settings_shell.c @@ -182,6 +182,11 @@ static int cmd_write(const struct shell *shell_ptr, size_t argc, char *argv[]) break; case SETTINGS_VALUE_STRING: buffer_len = strlen(argv[argc - 1]) + 1; + if (buffer_len > sizeof(buffer)) { + shell_error(shell_ptr, "%s is bigger than shell's buffer", argv[argc - 1]); + return -EINVAL; + } + memcpy(buffer, argv[argc - 1], buffer_len); break; } From ed040f187375cea20b5cceab2a3697a5e305980b Mon Sep 17 00:00:00 2001 From: Sigurd Hellesvik Date: Wed, 6 Dec 2023 10:20:34 +0100 Subject: [PATCH 1319/3723] cmake: Show executable for memory report Firstly, COMMENT does not work for ninja. Therefore, change COMMENT to echo. With the addition of sysbuild, several memory reports can be printed for one build. Because of this, it is useful to know which executable each memory report is printed for, so adding full path to elf file. Signed-off-by: Sigurd Hellesvik --- CMakeLists.txt | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 3b0af4e34a3..be0dafe0fc1 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -1885,12 +1885,11 @@ endif() add_custom_command( TARGET ${logical_target_for_zephyr_elf} POST_BUILD + COMMAND ${CMAKE_COMMAND} -E echo "Generating files from ${PROJECT_BINARY_DIR}/${KERNEL_ELF_NAME} for board: ${BOARD}" ${post_build_commands} BYPRODUCTS ${post_build_byproducts} - COMMENT "Generating files from ${KERNEL_ELF_NAME} for board: ${BOARD}" COMMAND_EXPAND_LISTS - # NB: COMMENT only works for some CMake-Generators ) # To populate with hex files to merge, do the following: From 47ec4359b9ee87318471692c143d9c5dba4a3355 Mon Sep 17 00:00:00 2001 From: Simon Hein Date: Thu, 14 Dec 2023 10:44:52 +0100 Subject: [PATCH 1320/3723] doc: Clean up wrong c function links Resolve wrong documentation c function links for irq: z_shared_isr, rtio: rtio_cqe_get_mempool_buffer and sensor: sensor_read Signed-off-by: Simon Hein --- doc/kernel/services/interrupts.rst | 2 +- doc/services/rtio/index.rst | 2 +- include/zephyr/drivers/sensor.h | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/doc/kernel/services/interrupts.rst b/doc/kernel/services/interrupts.rst index 7f19829c3b7..a388bc13a0f 100644 --- a/doc/kernel/services/interrupts.rst +++ b/doc/kernel/services/interrupts.rst @@ -554,7 +554,7 @@ This is an array of struct z_shared_isr_table_entry: }; This table keeps track of the registered clients for each of the interrupt -lines. Whenever an interrupt line becomes shared, c:func:`z_shared_isr` will +lines. Whenever an interrupt line becomes shared, :c:func:`z_shared_isr` will replace the currently registered ISR in _sw_isr_table. This special ISR will iterate through the list of registered clients and invoke the ISRs. diff --git a/doc/services/rtio/index.rst b/doc/services/rtio/index.rst index 88c5f29a075..df6e75d7702 100644 --- a/doc/services/rtio/index.rst +++ b/doc/services/rtio/index.rst @@ -178,7 +178,7 @@ by calling :c:func:`rtio_sqe_rx_buf` like so: } Finally, the consumer will be able to access the allocated buffer via -c:func:`rtio_cqe_get_mempool_buffer`. +:c:func:`rtio_cqe_get_mempool_buffer`. .. code-block:: C diff --git a/include/zephyr/drivers/sensor.h b/include/zephyr/drivers/sensor.h index e652c3a2040..9a719948672 100644 --- a/include/zephyr/drivers/sensor.h +++ b/include/zephyr/drivers/sensor.h @@ -418,7 +418,7 @@ typedef int (*sensor_channel_get_t)(const struct device *dev, * @brief Decodes a single raw data buffer * * Data buffers are provided on the @ref rtio context that's supplied to - * c:func:`sensor_read`. + * @ref sensor_read. */ struct sensor_decoder_api { /** From a05a47573a11ba8a78dadc5d3229659f24ddd32f Mon Sep 17 00:00:00 2001 From: Jonathan Rico Date: Wed, 29 Nov 2023 15:17:17 +0100 Subject: [PATCH 1321/3723] Bluetooth: ATT: Internalize ATT PDU TX pool Why? - metadata is easier to manage as an array + index - less error-prone -> less memory-management bugs - we can. because of the previous refactor - PDU allocations are more predictable - ATT buffer size can be optimized by app - isolates ATT from the rest of the ACL users - decouples ATT PDU size from e.g. SMP w/ LESC Drawbacks: - higher memory usage - kconfig change The higher memory use is only temporary, as this will be followed-up with more refactors that should bring it back down. Signed-off-by: Jonathan Rico Co-authored-by: Aleksander Wasaznik --- doc/releases/migration-guide-3.6.rst | 3 + include/zephyr/bluetooth/gatt.h | 16 +-- samples/bluetooth/tmap_bmr/prj.conf | 2 +- samples/bluetooth/tmap_peripheral/prj.conf | 2 +- subsys/bluetooth/audio/tbs_client.c | 2 +- subsys/bluetooth/host/Kconfig.gatt | 9 ++ subsys/bluetooth/host/att.c | 121 ++++++------------- tests/bluetooth/shell/audio.conf | 2 +- tests/bluetooth/tester/overlay-le-audio.conf | 2 +- tests/bsim/bluetooth/audio/prj.conf | 2 +- 10 files changed, 66 insertions(+), 95 deletions(-) diff --git a/doc/releases/migration-guide-3.6.rst b/doc/releases/migration-guide-3.6.rst index 9f1ccaa4073..5e8ae8e3a0a 100644 --- a/doc/releases/migration-guide-3.6.rst +++ b/doc/releases/migration-guide-3.6.rst @@ -185,6 +185,9 @@ Bootloader Bluetooth ========= +* ATT now has its own TX buffer pool. + If extra ATT buffers were configured using :kconfig:option:`CONFIG_BT_L2CAP_TX_BUF_COUNT`, + they now instead should be configured through :kconfig:option:`CONFIG_BT_ATT_TX_COUNT`. * The HCI implementation for both the Host and the Controller sides has been renamed for the IPC transport. The ``CONFIG_BT_RPMSG`` Kconfig option is now :kconfig:option:`CONFIG_BT_HCI_IPC`, and the ``zephyr,bt-hci-rpmsg-ipc`` diff --git a/include/zephyr/bluetooth/gatt.h b/include/zephyr/bluetooth/gatt.h index 15d3536a4f6..b5c355fad21 100644 --- a/include/zephyr/bluetooth/gatt.h +++ b/include/zephyr/bluetooth/gatt.h @@ -1336,7 +1336,7 @@ struct bt_gatt_exchange_params { * @retval -ENOMEM ATT request queue is full and blocking would cause deadlock. * Allow a pending request to resolve before retrying, or call this function * outside the BT RX thread to get blocking behavior. Queue size is controlled - * by @kconfig{CONFIG_BT_L2CAP_TX_BUF_COUNT}. + * by @kconfig{CONFIG_BT_ATT_TX_COUNT}. * * @retval -EALREADY The MTU exchange procedure has been already performed. */ @@ -1502,7 +1502,7 @@ struct bt_gatt_discover_params { * @retval -ENOMEM ATT request queue is full and blocking would cause deadlock. * Allow a pending request to resolve before retrying, or call this function * outside the BT RX thread to get blocking behavior. Queue size is controlled - * by @kconfig{CONFIG_BT_L2CAP_TX_BUF_COUNT}. + * by @kconfig{CONFIG_BT_ATT_TX_COUNT}. */ int bt_gatt_discover(struct bt_conn *conn, struct bt_gatt_discover_params *params); @@ -1617,7 +1617,7 @@ struct bt_gatt_read_params { * @retval -ENOMEM ATT request queue is full and blocking would cause deadlock. * Allow a pending request to resolve before retrying, or call this function * outside the BT RX thread to get blocking behavior. Queue size is controlled - * by @kconfig{CONFIG_BT_L2CAP_TX_BUF_COUNT}. + * by @kconfig{CONFIG_BT_ATT_TX_COUNT}. */ int bt_gatt_read(struct bt_conn *conn, struct bt_gatt_read_params *params); @@ -1670,7 +1670,7 @@ struct bt_gatt_write_params { * @retval -ENOMEM ATT request queue is full and blocking would cause deadlock. * Allow a pending request to resolve before retrying, or call this function * outside Bluetooth event context to get blocking behavior. Queue size is - * controlled by @kconfig{CONFIG_BT_L2CAP_TX_BUF_COUNT}. + * controlled by @kconfig{CONFIG_BT_ATT_TX_COUNT}. */ int bt_gatt_write(struct bt_conn *conn, struct bt_gatt_write_params *params); @@ -1707,7 +1707,7 @@ int bt_gatt_write(struct bt_conn *conn, struct bt_gatt_write_params *params); * @retval -ENOMEM ATT request queue is full and blocking would cause deadlock. * Allow a pending request to resolve before retrying, or call this function * outside the BT RX thread to get blocking behavior. Queue size is controlled - * by @kconfig{CONFIG_BT_L2CAP_TX_BUF_COUNT}. + * by @kconfig{CONFIG_BT_ATT_TX_COUNT}. */ int bt_gatt_write_without_response_cb(struct bt_conn *conn, uint16_t handle, const void *data, uint16_t length, @@ -1733,7 +1733,7 @@ int bt_gatt_write_without_response_cb(struct bt_conn *conn, uint16_t handle, * @retval -ENOMEM ATT request queue is full and blocking would cause deadlock. * Allow a pending request to resolve before retrying, or call this function * outside the BT RX thread to get blocking behavior. Queue size is controlled - * by @kconfig{CONFIG_BT_L2CAP_TX_BUF_COUNT}. + * by @kconfig{CONFIG_BT_ATT_TX_COUNT}. */ static inline int bt_gatt_write_without_response(struct bt_conn *conn, uint16_t handle, const void *data, @@ -1895,7 +1895,7 @@ struct bt_gatt_subscribe_params { * @retval -ENOMEM ATT request queue is full and blocking would cause deadlock. * Allow a pending request to resolve before retrying, or call this function * outside the BT RX thread to get blocking behavior. Queue size is controlled - * by @kconfig{CONFIG_BT_L2CAP_TX_BUF_COUNT}. + * by @kconfig{CONFIG_BT_ATT_TX_COUNT}. */ int bt_gatt_subscribe(struct bt_conn *conn, struct bt_gatt_subscribe_params *params); @@ -1941,7 +1941,7 @@ int bt_gatt_resubscribe(uint8_t id, const bt_addr_le_t *peer, * @retval -ENOMEM ATT request queue is full and blocking would cause deadlock. * Allow a pending request to resolve before retrying, or call this function * outside the BT RX thread to get blocking behavior. Queue size is controlled - * by @kconfig{CONFIG_BT_L2CAP_TX_BUF_COUNT}. + * by @kconfig{CONFIG_BT_ATT_TX_COUNT}. */ int bt_gatt_unsubscribe(struct bt_conn *conn, struct bt_gatt_subscribe_params *params); diff --git a/samples/bluetooth/tmap_bmr/prj.conf b/samples/bluetooth/tmap_bmr/prj.conf index 3a0fd96f598..7c3ea5b0372 100644 --- a/samples/bluetooth/tmap_bmr/prj.conf +++ b/samples/bluetooth/tmap_bmr/prj.conf @@ -8,7 +8,7 @@ CONFIG_UTF8=y CONFIG_BT_SMP=y CONFIG_BT_KEYS_OVERWRITE_OLDEST=y -CONFIG_BT_L2CAP_TX_BUF_COUNT=20 +CONFIG_BT_ATT_TX_COUNT=20 # TMAP support CONFIG_BT_TMAP=y diff --git a/samples/bluetooth/tmap_peripheral/prj.conf b/samples/bluetooth/tmap_peripheral/prj.conf index 6b7d7d390a8..79725aaba2b 100644 --- a/samples/bluetooth/tmap_peripheral/prj.conf +++ b/samples/bluetooth/tmap_peripheral/prj.conf @@ -7,7 +7,7 @@ CONFIG_UTF8=y CONFIG_BT_SMP=y CONFIG_BT_KEYS_OVERWRITE_OLDEST=y -CONFIG_BT_L2CAP_TX_BUF_COUNT=20 +CONFIG_BT_ATT_TX_COUNT=20 # TMAP support CONFIG_BT_TMAP=y diff --git a/subsys/bluetooth/audio/tbs_client.c b/subsys/bluetooth/audio/tbs_client.c index 527b7c73459..181f951b918 100644 --- a/subsys/bluetooth/audio/tbs_client.c +++ b/subsys/bluetooth/audio/tbs_client.c @@ -41,7 +41,7 @@ LOG_MODULE_REGISTER(bt_tbs_client, CONFIG_BT_TBS_CLIENT_LOG_LEVEL); IS_ENABLED(CONFIG_BT_TBS_CLIENT_CALL_FRIENDLY_NAME) + \ IS_ENABLED(CONFIG_BT_TBS_CLIENT_INCOMING_CALL)) -BUILD_ASSERT(CONFIG_BT_L2CAP_TX_BUF_COUNT >= TBS_CLIENT_BUF_COUNT, "Too few L2CAP buffers"); +BUILD_ASSERT(CONFIG_BT_ATT_TX_COUNT >= TBS_CLIENT_BUF_COUNT, "Too few ATT buffers"); #include "common/bt_str.h" diff --git a/subsys/bluetooth/host/Kconfig.gatt b/subsys/bluetooth/host/Kconfig.gatt index 53b482a0a38..066cc56df58 100644 --- a/subsys/bluetooth/host/Kconfig.gatt +++ b/subsys/bluetooth/host/Kconfig.gatt @@ -5,6 +5,15 @@ menu "ATT and GATT Options" +config BT_ATT_TX_COUNT + int "Number of ATT buffers" + default BT_BUF_ACL_TX_COUNT + default 3 + range 1 255 + help + These buffers are only used for sending anything over ATT. + Requests, responses, indications, confirmations, notifications. + config BT_ATT_PREPARE_COUNT int "Number of ATT prepare write buffers" default 0 diff --git a/subsys/bluetooth/host/att.c b/subsys/bluetooth/host/att.c index 62cce595ec6..f2dc679f9af 100644 --- a/subsys/bluetooth/host/att.c +++ b/subsys/bluetooth/host/att.c @@ -69,7 +69,7 @@ NET_BUF_POOL_DEFINE(prep_pool, CONFIG_BT_ATT_PREPARE_COUNT, BT_ATT_BUF_SIZE, #endif /* CONFIG_BT_ATT_PREPARE_COUNT */ K_MEM_SLAB_DEFINE(req_slab, sizeof(struct bt_att_req), - CONFIG_BT_L2CAP_TX_BUF_COUNT, __alignof__(struct bt_att_req)); + CONFIG_BT_ATT_TX_COUNT, __alignof__(struct bt_att_req)); enum { ATT_CONNECTED, @@ -176,30 +176,20 @@ static struct bt_att_req cancel; */ static k_tid_t att_handle_rsp_thread; -#define bt_att_tx_meta_data(buf) (((struct bt_att_tx_meta *)net_buf_user_data(buf))->data) +static struct bt_att_tx_meta_data tx_meta_data_storage[CONFIG_BT_ATT_TX_COUNT]; -static struct bt_att_tx_meta_data tx_meta_data_storage[CONFIG_BT_CONN_TX_MAX]; -K_FIFO_DEFINE(free_att_tx_meta_data); +NET_BUF_POOL_DEFINE(att_pool, CONFIG_BT_ATT_TX_COUNT, + BT_L2CAP_SDU_BUF_SIZE(BT_ATT_BUF_SIZE), + CONFIG_BT_CONN_TX_USER_DATA_SIZE, NULL); -static struct bt_att_tx_meta_data *tx_meta_data_alloc(k_timeout_t timeout) +struct bt_att_tx_meta_data *bt_att_get_tx_meta_data(const struct net_buf *buf) { - /* The meta data always get freed in the system workqueue, - * so if we're in the same workqueue but there are no immediate - * contexts available, there's no chance we'll get one by waiting. - */ - if (k_current_get() == &k_sys_work_q.thread) { - return k_fifo_get(&free_att_tx_meta_data, K_NO_WAIT); - } - - return k_fifo_get(&free_att_tx_meta_data, timeout); -} + __ASSERT_NO_MSG(net_buf_pool_get(buf->pool_id) == &att_pool); -static inline void tx_meta_data_free(struct bt_att_tx_meta_data *data) -{ - __ASSERT_NO_MSG(data); - - (void)memset(data, 0, sizeof(*data)); - k_fifo_put(&free_att_tx_meta_data, data); + /* Metadata lifetime is implicitly tied to the buffer lifetime. + * Treat it as part of the buffer itself. + */ + return &tx_meta_data_storage[net_buf_id((struct net_buf *)buf)]; } static int bt_att_chan_send(struct bt_att_chan *chan, struct net_buf *buf); @@ -266,7 +256,7 @@ static int chan_send(struct bt_att_chan *chan, struct net_buf *buf) struct bt_att_hdr *hdr; struct net_buf_simple_state state; int err; - struct bt_att_tx_meta_data *data = bt_att_tx_meta_data(buf); + struct bt_att_tx_meta_data *data = bt_att_get_tx_meta_data(buf); struct bt_att_chan *prev_chan = data->att_chan; hdr = (void *)buf->data; @@ -325,7 +315,6 @@ static int chan_send(struct bt_att_chan *chan, struct net_buf *buf) err = bt_smp_sign(chan->att->conn, buf); if (err) { LOG_ERR("Error signing data"); - tx_meta_data_free(bt_att_tx_meta_data(buf)); net_buf_unref(buf); return err; } @@ -370,12 +359,14 @@ static struct net_buf *get_first_buf_matching_chan(struct k_fifo *fifo, struct b struct k_fifo skipped; struct net_buf *buf; struct net_buf *ret = NULL; + struct bt_att_tx_meta_data *meta; k_fifo_init(&skipped); while ((buf = net_buf_get(fifo, K_NO_WAIT))) { + meta = bt_att_get_tx_meta_data(buf); if (!ret && - att_chan_matches_chan_opt(chan, bt_att_tx_meta_data(buf)->chan_opt)) { + att_chan_matches_chan_opt(chan, meta->chan_opt)) { ret = buf; } else { net_buf_put(&skipped, buf); @@ -400,10 +391,11 @@ static struct bt_att_req *get_first_req_matching_chan(sys_slist_t *reqs, struct { if (IS_ENABLED(CONFIG_BT_EATT)) { sys_snode_t *curr, *prev = NULL; + struct bt_att_tx_meta_data *meta = NULL; SYS_SLIST_FOR_EACH_NODE(reqs, curr) { - if (att_chan_matches_chan_opt( - chan, bt_att_tx_meta_data(ATT_REQ(curr)->buf)->chan_opt)) { + meta = bt_att_get_tx_meta_data(ATT_REQ(curr)->buf); + if (att_chan_matches_chan_opt(chan, meta->chan_opt)) { break; } @@ -546,7 +538,6 @@ static void chan_cfm_sent(struct bt_conn *conn, struct bt_att_tx_meta_data *user LOG_DBG("chan %p", chan); - tx_meta_data_free(data); } static void chan_rsp_sent(struct bt_conn *conn, struct bt_att_tx_meta_data *user_data) @@ -556,7 +547,6 @@ static void chan_rsp_sent(struct bt_conn *conn, struct bt_att_tx_meta_data *user LOG_DBG("chan %p", chan); - tx_meta_data_free(data); } static void chan_req_sent(struct bt_conn *conn, struct bt_att_tx_meta_data *user_data) @@ -571,7 +561,6 @@ static void chan_req_sent(struct bt_conn *conn, struct bt_att_tx_meta_data *user k_work_reschedule(&chan->timeout_work, BT_ATT_TIMEOUT); } - tx_meta_data_free(user_data); } static void chan_tx_complete(struct bt_conn *conn, struct bt_att_tx_meta_data *user_data) @@ -584,7 +573,6 @@ static void chan_tx_complete(struct bt_conn *conn, struct bt_att_tx_meta_data *u LOG_DBG("TX Complete chan %p CID 0x%04X", chan, chan->chan.tx.cid); - tx_meta_data_free(data); if (func) { for (uint16_t i = 0; i < attr_count; i++) { @@ -593,11 +581,6 @@ static void chan_tx_complete(struct bt_conn *conn, struct bt_att_tx_meta_data *u } } -static void chan_unknown(struct bt_conn *conn, struct bt_att_tx_meta_data *user_data) -{ - tx_meta_data_free(user_data); -} - static bt_att_tx_cb_t chan_cb(const struct net_buf *buf) { const att_type_t op_type = att_op_get_type(buf->data[0]); @@ -615,9 +598,8 @@ static bt_att_tx_cb_t chan_cb(const struct net_buf *buf) return chan_tx_complete; default: __ASSERT(false, "Unknown op type 0x%02X", op_type); + return NULL; } - - return chan_unknown; } static void att_cfm_sent(struct bt_conn *conn, void *user_data, int err) @@ -661,8 +643,6 @@ static void att_unknown(struct bt_conn *conn, void *user_data, int err) if (!err) { att_sent(conn, user_data); } - - chan_unknown(conn, user_data); } static bt_conn_tx_cb_t att_cb(const struct net_buf *buf) @@ -682,9 +662,11 @@ static bt_conn_tx_cb_t att_cb(const struct net_buf *buf) return att_tx_complete; default: __ASSERT(false, "Unknown op type 0x%02X", op_type); + /* This only ever runs if asserts are disabled. + * In any case, all bets are off. + */ + return att_unknown; } - - return att_unknown; } static struct net_buf *bt_att_chan_create_pdu(struct bt_att_chan *chan, uint8_t op, size_t len) @@ -710,25 +692,24 @@ static struct net_buf *bt_att_chan_create_pdu(struct bt_att_chan *chan, uint8_t timeout = K_FOREVER; } - buf = bt_l2cap_create_pdu_timeout(NULL, 0, timeout); + /* This will reserve headspace for lower layers */ + buf = bt_l2cap_create_pdu_timeout(&att_pool, 0, timeout); if (!buf) { LOG_ERR("Unable to allocate buffer for op 0x%02x", op); return NULL; } - data = tx_meta_data_alloc(timeout); - if (!data) { - LOG_WRN("Unable to allocate ATT TX meta"); - net_buf_unref(buf); - return NULL; - } + data = bt_att_get_tx_meta_data(buf); + /* If we got a buf from `att_pool`, then the metadata slot at its index + * is officially ours to use. + */ + memset(data, 0, sizeof(*data)); if (IS_ENABLED(CONFIG_BT_EATT)) { net_buf_reserve(buf, BT_L2CAP_SDU_BUF_SIZE(0)); } data->att_chan = chan; - bt_att_tx_meta_data(buf) = data; hdr = net_buf_add(buf, sizeof(*hdr)); hdr->code = op; @@ -742,7 +723,7 @@ static int bt_att_chan_send(struct bt_att_chan *chan, struct net_buf *buf) ((struct bt_att_hdr *)buf->data)->code); if (IS_ENABLED(CONFIG_BT_EATT) && - !att_chan_matches_chan_opt(chan, bt_att_tx_meta_data(buf)->chan_opt)) { + !att_chan_matches_chan_opt(chan, bt_att_get_tx_meta_data(buf)->chan_opt)) { return -EINVAL; } @@ -1095,7 +1076,6 @@ static uint8_t att_find_info_rsp(struct bt_att_chan *chan, uint16_t start_handle bt_gatt_foreach_attr(start_handle, end_handle, find_info_cb, &data); if (!data.rsp) { - tx_meta_data_free(bt_att_tx_meta_data(data.buf)); net_buf_unref(data.buf); /* Respond since handle is set */ send_err_rsp(chan, BT_ATT_OP_FIND_INFO_REQ, start_handle, @@ -1258,7 +1238,6 @@ static uint8_t att_find_type_rsp(struct bt_att_chan *chan, uint16_t start_handle /* If error has not been cleared, no service has been found */ if (data.err) { - tx_meta_data_free(bt_att_tx_meta_data(data.buf)); net_buf_unref(data.buf); /* Respond since handle is set */ send_err_rsp(chan, BT_ATT_OP_FIND_TYPE_REQ, start_handle, @@ -1489,7 +1468,6 @@ static uint8_t att_read_type_rsp(struct bt_att_chan *chan, struct bt_uuid *uuid, bt_gatt_foreach_attr(start_handle, end_handle, read_type_cb, &data); if (data.err) { - tx_meta_data_free(bt_att_tx_meta_data(data.buf)); net_buf_unref(data.buf); /* Response here since handle is set */ send_err_rsp(chan, BT_ATT_OP_READ_TYPE_REQ, start_handle, @@ -1611,7 +1589,6 @@ static uint8_t att_read_rsp(struct bt_att_chan *chan, uint8_t op, uint8_t rsp, /* In case of error discard data and respond with an error */ if (data.err) { - tx_meta_data_free(bt_att_tx_meta_data(data.buf)); net_buf_unref(data.buf); /* Respond here since handle is set */ send_err_rsp(chan, op, handle, data.err); @@ -1695,7 +1672,6 @@ static uint8_t att_read_mult_req(struct bt_att_chan *chan, struct net_buf *buf) /* Stop reading in case of error */ if (data.err) { - tx_meta_data_free(bt_att_tx_meta_data(data.buf)); net_buf_unref(data.buf); /* Respond here since handle is set */ send_err_rsp(chan, BT_ATT_OP_READ_MULT_REQ, handle, @@ -1790,7 +1766,6 @@ static uint8_t att_read_mult_vl_req(struct bt_att_chan *chan, struct net_buf *bu /* Stop reading in case of error */ if (data.err) { - tx_meta_data_free(bt_att_tx_meta_data(data.buf)); net_buf_unref(data.buf); /* Respond here since handle is set */ send_err_rsp(chan, BT_ATT_OP_READ_MULT_VL_REQ, handle, @@ -1907,7 +1882,6 @@ static uint8_t att_read_group_rsp(struct bt_att_chan *chan, struct bt_uuid *uuid bt_gatt_foreach_attr(start_handle, end_handle, read_group_cb, &data); if (!data.rsp->len) { - tx_meta_data_free(bt_att_tx_meta_data(data.buf)); net_buf_unref(data.buf); /* Respond here since handle is set */ send_err_rsp(chan, BT_ATT_OP_READ_GROUP_REQ, start_handle, @@ -2057,7 +2031,6 @@ static uint8_t att_write_rsp(struct bt_att_chan *chan, uint8_t req, uint8_t rsp, if (data.err) { /* In case of error discard data and respond with an error */ if (rsp) { - tx_meta_data_free(bt_att_tx_meta_data(data.buf)); net_buf_unref(data.buf); /* Respond here since handle is set */ send_err_rsp(chan, req, handle, data.err); @@ -2988,7 +2961,6 @@ static void att_reset(struct bt_att *att) #if CONFIG_BT_ATT_PREPARE_COUNT > 0 /* Discard queued buffers */ while ((buf = net_buf_slist_get(&att->prep_queue))) { - tx_meta_data_free(bt_att_tx_meta_data(buf)); net_buf_unref(buf); } #endif /* CONFIG_BT_ATT_PREPARE_COUNT > 0 */ @@ -3000,7 +2972,6 @@ static void att_reset(struct bt_att *att) #endif /* CONFIG_BT_EATT */ while ((buf = net_buf_get(&att->tx_queue, K_NO_WAIT))) { - tx_meta_data_free(bt_att_tx_meta_data(buf)); net_buf_unref(buf); } @@ -3036,7 +3007,6 @@ static void att_chan_detach(struct bt_att_chan *chan) /* Release pending buffers */ while ((buf = net_buf_get(&chan->tx_queue, K_NO_WAIT))) { - tx_meta_data_free(bt_att_tx_meta_data(buf)); net_buf_unref(buf); } @@ -3155,13 +3125,11 @@ static uint8_t att_req_retry(struct bt_att_chan *att_chan) } if (req->encode(buf, req->len, req->user_data)) { - tx_meta_data_free(bt_att_tx_meta_data(buf)); net_buf_unref(buf); return BT_ATT_ERR_UNLIKELY; } if (chan_send(att_chan, buf)) { - tx_meta_data_free(bt_att_tx_meta_data(buf)); net_buf_unref(buf); return BT_ATT_ERR_UNLIKELY; } @@ -3257,13 +3225,9 @@ static void bt_att_released(struct bt_l2cap_chan *ch) { struct bt_att_chan *chan = ATT_CHAN(ch); - /* Traverse the ATT bearer's TX queue and free the metadata. */ + /* Empty the ATT bearer's TX queue */ while (!sys_slist_is_empty(&chan->tx_cb_queue)) { - sys_snode_t *tx_meta_data_node = sys_slist_get(&chan->tx_cb_queue); - struct bt_att_tx_meta_data *tx_meta_data = CONTAINER_OF( - tx_meta_data_node, struct bt_att_tx_meta_data, tx_cb_queue_node); - - tx_meta_data_free(tx_meta_data); + (void)sys_slist_get(&chan->tx_cb_queue); } LOG_DBG("chan %p", chan); @@ -3754,11 +3718,6 @@ static void bt_eatt_init(void) void bt_att_init(void) { - k_fifo_init(&free_att_tx_meta_data); - for (size_t i = 0; i < ARRAY_SIZE(tx_meta_data_storage); i++) { - k_fifo_put(&free_att_tx_meta_data, &tx_meta_data_storage[i]); - } - bt_gatt_init(); if (IS_ENABLED(CONFIG_BT_EATT)) { @@ -3839,7 +3798,6 @@ void bt_att_req_free(struct bt_att_req *req) LOG_DBG("req %p", req); if (req->buf) { - tx_meta_data_free(bt_att_tx_meta_data(req->buf)); net_buf_unref(req->buf); req->buf = NULL; } @@ -3856,7 +3814,6 @@ int bt_att_send(struct bt_conn *conn, struct net_buf *buf) att = att_get(conn); if (!att) { - tx_meta_data_free(bt_att_tx_meta_data(buf)); net_buf_unref(buf); return -ENOTCONN; } @@ -3996,7 +3953,7 @@ bool bt_att_out_of_sync_sent_on_fixed(struct bt_conn *conn) void bt_att_set_tx_meta_data(struct net_buf *buf, bt_gatt_complete_func_t func, void *user_data, enum bt_att_chan_opt chan_opt) { - struct bt_att_tx_meta_data *data = bt_att_tx_meta_data(buf); + struct bt_att_tx_meta_data *data = bt_att_get_tx_meta_data(buf); data->func = func; data->user_data = user_data; @@ -4006,7 +3963,7 @@ void bt_att_set_tx_meta_data(struct net_buf *buf, bt_gatt_complete_func_t func, void bt_att_increment_tx_meta_data_attr_count(struct net_buf *buf, uint16_t attr_count) { - struct bt_att_tx_meta_data *data = bt_att_tx_meta_data(buf); + struct bt_att_tx_meta_data *data = bt_att_get_tx_meta_data(buf); data->attr_count += attr_count; } @@ -4014,9 +3971,11 @@ void bt_att_increment_tx_meta_data_attr_count(struct net_buf *buf, uint16_t attr bool bt_att_tx_meta_data_match(const struct net_buf *buf, bt_gatt_complete_func_t func, const void *user_data, enum bt_att_chan_opt chan_opt) { - return ((bt_att_tx_meta_data(buf)->func == func) && - (bt_att_tx_meta_data(buf)->user_data == user_data) && - (bt_att_tx_meta_data(buf)->chan_opt == chan_opt)); + const struct bt_att_tx_meta_data *meta = bt_att_get_tx_meta_data(buf); + + return ((meta->func == func) && + (meta->user_data == user_data) && + (meta->chan_opt == chan_opt)); } bool bt_att_chan_opt_valid(struct bt_conn *conn, enum bt_att_chan_opt chan_opt) diff --git a/tests/bluetooth/shell/audio.conf b/tests/bluetooth/shell/audio.conf index 902fe3e833e..0458bcb82b1 100644 --- a/tests/bluetooth/shell/audio.conf +++ b/tests/bluetooth/shell/audio.conf @@ -20,7 +20,7 @@ CONFIG_BT_SHELL=y CONFIG_BT_DEVICE_NAME="audio test shell" CONFIG_BT_DEVICE_NAME_DYNAMIC=y # TBS Client may require up to 12 buffers -CONFIG_BT_L2CAP_TX_BUF_COUNT=12 +CONFIG_BT_ATT_TX_COUNT=12 CONFIG_BT_ID_MAX=2 CONFIG_BT_FILTER_ACCEPT_LIST=y CONFIG_BT_REMOTE_INFO=y diff --git a/tests/bluetooth/tester/overlay-le-audio.conf b/tests/bluetooth/tester/overlay-le-audio.conf index 1501365dd76..3536a2712da 100644 --- a/tests/bluetooth/tester/overlay-le-audio.conf +++ b/tests/bluetooth/tester/overlay-le-audio.conf @@ -94,7 +94,7 @@ CONFIG_BT_HAS_PRESET_NAME_DYNAMIC=y CONFIG_BT_CSIP_SET_MEMBER=y # CCP -CONFIG_BT_L2CAP_TX_BUF_COUNT=12 +CONFIG_BT_ATT_TX_COUNT=12 CONFIG_BT_TBS_CLIENT_GTBS=y CONFIG_BT_TBS_CLIENT_TBS=n diff --git a/tests/bsim/bluetooth/audio/prj.conf b/tests/bsim/bluetooth/audio/prj.conf index 01e70dafdce..9a822ede63a 100644 --- a/tests/bsim/bluetooth/audio/prj.conf +++ b/tests/bsim/bluetooth/audio/prj.conf @@ -7,7 +7,7 @@ CONFIG_BT_CENTRAL=y CONFIG_BT_PERIPHERAL=y CONFIG_BT_DEVICE_NAME="bsim_test_audio" # TBS Client may require up to 12 buffers -CONFIG_BT_L2CAP_TX_BUF_COUNT=12 +CONFIG_BT_ATT_TX_COUNT=12 CONFIG_BT_ATT_PREPARE_COUNT=5 CONFIG_BT_MAX_CONN=3 CONFIG_BT_MAX_PAIRED=3 From b83b9bede3bdc787615073a99463e6a00932318d Mon Sep 17 00:00:00 2001 From: Jonathan Rico Date: Wed, 29 Nov 2023 13:38:24 +0100 Subject: [PATCH 1322/3723] Bluetooth: ATT: call-back on buffer destroy This is just as arbitrary as what was before, but simpler. Before this change, the callback were invoked upon receiving the num complete packets event. This did not necessarily work with all spec-compliant controllers. Now the callback is invoked as soon as the lower layer destroys the buffer. ATT shouldn't care whether L2CAP sends it over RFC1149 or something else after that point. Signed-off-by: Jonathan Rico Co-authored-by: Aleksander Wasaznik --- .../src/gatt_write_common.c | 5 + subsys/bluetooth/host/att.c | 238 +++++++----------- subsys/bluetooth/host/att_internal.h | 2 - 3 files changed, 96 insertions(+), 149 deletions(-) diff --git a/samples/bluetooth/central_gatt_write/src/gatt_write_common.c b/samples/bluetooth/central_gatt_write/src/gatt_write_common.c index 58c8c58f50f..7deecd11219 100644 --- a/samples/bluetooth/central_gatt_write/src/gatt_write_common.c +++ b/samples/bluetooth/central_gatt_write/src/gatt_write_common.c @@ -27,6 +27,11 @@ static void write_cmd_cb(struct bt_conn *conn, void *user_data) delta = k_cycle_get_32() - cycle_stamp; delta = k_cyc_to_ns_floor64(delta); + if (delta == 0) { + /* Skip division by zero */ + return; + } + /* if last data rx-ed was greater than 1 second in the past, * reset the metrics. */ diff --git a/subsys/bluetooth/host/att.c b/subsys/bluetooth/host/att.c index f2dc679f9af..50e5f7d42dc 100644 --- a/subsys/bluetooth/host/att.c +++ b/subsys/bluetooth/host/att.c @@ -86,10 +86,10 @@ typedef void (*bt_att_tx_cb_t)(struct bt_conn *conn, struct bt_att_tx_meta_data *user_data); struct bt_att_tx_meta_data { - sys_snode_t tx_cb_queue_node; - bt_att_tx_cb_t chan_cb; - struct bt_att_chan *att_chan; + int err; + uint8_t opcode; uint16_t attr_count; + struct bt_att_chan *att_chan; bt_gatt_complete_func_t func; void *user_data; enum bt_att_chan_opt chan_opt; @@ -105,7 +105,6 @@ struct bt_att_chan { struct bt_att *att; struct bt_l2cap_le_chan chan; ATOMIC_DEFINE(flags, ATT_NUM_FLAGS); - sys_slist_t tx_cb_queue; struct bt_att_req *req; struct k_fifo tx_queue; struct k_work_delayable timeout_work; @@ -178,9 +177,44 @@ static k_tid_t att_handle_rsp_thread; static struct bt_att_tx_meta_data tx_meta_data_storage[CONFIG_BT_ATT_TX_COUNT]; +struct bt_att_tx_meta_data *bt_att_get_tx_meta_data(const struct net_buf *buf); +static void att_on_sent_cb(struct bt_att_tx_meta_data *meta); + +static void att_tx_destroy(struct net_buf *buf) +{ + struct bt_att_tx_meta_data *p_meta = bt_att_get_tx_meta_data(buf); + struct bt_att_tx_meta_data meta; + + LOG_DBG("%p", buf); + + /* Destroy the buffer first, as the callback may attempt to allocate a + * new one for another operation. + */ + meta = *p_meta; + + /* Clear the meta storage. This might help catch illegal + * "use-after-free"s. An initial memset is not necessary, as the + * metadata storage array is `static`. + */ + memset(p_meta, 0x00, sizeof(*p_meta)); + + /* After this point, p_meta doesn't belong to us. + * The user data will be memset to 0 on allocation. + */ + net_buf_destroy(buf); + + /* ATT opcode 0 is invalid. If we get here, that means the buffer got + * destroyed before it was ready to be sent. Hopefully nobody sets the + * opcode and then destroys the buffer without sending it. :'( + */ + if (meta.opcode != 0) { + att_on_sent_cb(&meta); + } +} + NET_BUF_POOL_DEFINE(att_pool, CONFIG_BT_ATT_TX_COUNT, BT_L2CAP_SDU_BUF_SIZE(BT_ATT_BUF_SIZE), - CONFIG_BT_CONN_TX_USER_DATA_SIZE, NULL); + CONFIG_BT_CONN_TX_USER_DATA_SIZE, att_tx_destroy); struct bt_att_tx_meta_data *bt_att_get_tx_meta_data(const struct net_buf *buf) { @@ -193,8 +227,6 @@ struct bt_att_tx_meta_data *bt_att_get_tx_meta_data(const struct net_buf *buf) } static int bt_att_chan_send(struct bt_att_chan *chan, struct net_buf *buf); -static bt_att_tx_cb_t chan_cb(const struct net_buf *buf); -static bt_conn_tx_cb_t att_cb(const struct net_buf *buf); static void att_chan_mtu_updated(struct bt_att_chan *updated_chan); static void bt_att_disconnected(struct bt_l2cap_chan *chan); @@ -204,10 +236,11 @@ struct net_buf *bt_att_create_rsp_pdu(struct bt_att_chan *chan, static void bt_att_sent(struct bt_l2cap_chan *ch); -void att_sent(struct bt_conn *conn, void *user_data) +static void att_sent(void *user_data) { struct bt_att_tx_meta_data *data = user_data; struct bt_att_chan *att_chan = data->att_chan; + struct bt_conn *conn = att_chan->att->conn; struct bt_l2cap_chan *chan = &att_chan->chan.chan; __ASSERT_NO_MSG(!bt_att_is_enhanced(att_chan)); @@ -223,27 +256,6 @@ void att_sent(struct bt_conn *conn, void *user_data) bt_att_sent(chan); } -static int att_chan_send_cb(struct bt_att_chan *att_chan, - struct net_buf *buf, - bt_att_tx_cb_t cb, - struct bt_att_tx_meta_data *data) -{ - int err; - - data->chan_cb = chan_cb(buf); - sys_slist_append(&att_chan->tx_cb_queue, &data->tx_cb_queue_node); - - err = bt_l2cap_chan_send(&att_chan->chan.chan, buf); - if (err < 0) { - LOG_WRN("Failed to send ATT PDU: %d", err); - - sys_slist_find_and_remove(&att_chan->tx_cb_queue, - &data->tx_cb_queue_node); - } - - return err; -} - /* In case of success the ownership of the buffer is transferred to the stack * which takes care of releasing it when it completes transmitting to the * controller. @@ -276,6 +288,10 @@ static int chan_send(struct bt_att_chan *chan, struct net_buf *buf) return -ENOTSUP; } + __ASSERT_NO_MSG(buf->len >= sizeof(struct bt_att_hdr)); + data->opcode = buf->data[0]; + data->err = 0; + if (IS_ENABLED(CONFIG_BT_EATT) && bt_att_is_enhanced(chan)) { /* Check if sent is pending already, if it does it cannot be * modified so the operation will need to be queued. @@ -301,11 +317,20 @@ static int chan_send(struct bt_att_chan *chan, struct net_buf *buf) /* bt_l2cap_chan_send does actually return the number of bytes * that could be sent immediately. */ - err = att_chan_send_cb(chan, buf, chan_cb(buf), data); + err = bt_l2cap_chan_send(&chan->chan.chan, buf); if (err < 0) { data->att_chan = prev_chan; atomic_clear_bit(chan->flags, ATT_PENDING_SENT); + data->err = err; + return err; + } else { + /* On success, the almighty scheduler might already have + * run the destroy cb on the buffer. In that case, buf + * and its metadata are dangling pointers. + */ + buf = NULL; + data = NULL; } return 0; @@ -324,8 +349,7 @@ static int chan_send(struct bt_att_chan *chan, struct net_buf *buf) data->att_chan = chan; - err = bt_l2cap_send_cb(chan->att->conn, BT_L2CAP_CID_ATT, - buf, att_cb(buf), data); + err = bt_l2cap_send(chan->att->conn, BT_L2CAP_CID_ATT, buf); if (err) { if (err == -ENOBUFS) { LOG_ERR("Ran out of TX buffers or contexts."); @@ -333,6 +357,7 @@ static int chan_send(struct bt_att_chan *chan, struct net_buf *buf) /* In case of an error has occurred restore the buffer state */ net_buf_simple_restore(&buf->b, &state); data->att_chan = prev_chan; + data->err = err; } return err; @@ -478,24 +503,9 @@ static int chan_req_send(struct bt_att_chan *chan, struct bt_att_req *req) static void bt_att_sent(struct bt_l2cap_chan *ch) { struct bt_att_chan *chan = ATT_CHAN(ch); - sys_snode_t *tx_meta_data_node = sys_slist_get(&chan->tx_cb_queue); struct bt_att *att = chan->att; int err; - /* EATT channels should always set metadata and a callback */ - __ASSERT_NO_MSG(!tx_meta_data_node == !bt_att_is_enhanced(chan)); - - if (tx_meta_data_node) { - struct bt_att_tx_meta_data *tx_meta_data = CONTAINER_OF( - tx_meta_data_node, struct bt_att_tx_meta_data, tx_cb_queue_node); - - if (tx_meta_data->chan_cb) { - tx_meta_data->chan_cb(ch->conn, tx_meta_data); - } - } else { - LOG_DBG("No tx meta data node"); - } - LOG_DBG("chan %p", chan); atomic_clear_bit(chan->flags, ATT_PENDING_SENT); @@ -531,48 +541,41 @@ static void bt_att_sent(struct bt_l2cap_chan *ch) (void)process_queue(chan, &att->tx_queue); } -static void chan_cfm_sent(struct bt_conn *conn, struct bt_att_tx_meta_data *user_data) -{ - struct bt_att_tx_meta_data *data = user_data; - struct bt_att_chan *chan = data->att_chan; - - LOG_DBG("chan %p", chan); - -} - -static void chan_rsp_sent(struct bt_conn *conn, struct bt_att_tx_meta_data *user_data) -{ - struct bt_att_tx_meta_data *data = user_data; - struct bt_att_chan *chan = data->att_chan; - - LOG_DBG("chan %p", chan); - -} - -static void chan_req_sent(struct bt_conn *conn, struct bt_att_tx_meta_data *user_data) +static void chan_rebegin_att_timeout(struct bt_att_tx_meta_data *user_data) { struct bt_att_tx_meta_data *data = user_data; struct bt_att_chan *chan = data->att_chan; LOG_DBG("chan %p chan->req %p", chan, chan->req); - /* Start timeout work */ + if (!atomic_test_bit(chan->flags, ATT_CONNECTED)) { + LOG_ERR("ATT channel not connected"); + return; + } + + /* Start timeout work. Only if we are sure that the request is really + * in-flight. + */ if (chan->req) { k_work_reschedule(&chan->timeout_work, BT_ATT_TIMEOUT); } - } -static void chan_tx_complete(struct bt_conn *conn, struct bt_att_tx_meta_data *user_data) +static void chan_req_notif_sent(struct bt_att_tx_meta_data *user_data) { struct bt_att_tx_meta_data *data = user_data; struct bt_att_chan *chan = data->att_chan; + struct bt_conn *conn = chan->att->conn; bt_gatt_complete_func_t func = data->func; uint16_t attr_count = data->attr_count; void *ud = data->user_data; - LOG_DBG("TX Complete chan %p CID 0x%04X", chan, chan->chan.tx.cid); + LOG_DBG("chan %p CID 0x%04X", chan, chan->chan.tx.cid); + if (!atomic_test_bit(chan->flags, ATT_CONNECTED)) { + LOG_ERR("ATT channel not connected"); + return; + } if (func) { for (uint16_t i = 0; i < attr_count; i++) { @@ -581,91 +584,39 @@ static void chan_tx_complete(struct bt_conn *conn, struct bt_att_tx_meta_data *u } } -static bt_att_tx_cb_t chan_cb(const struct net_buf *buf) +static void att_on_sent_cb(struct bt_att_tx_meta_data *meta) { - const att_type_t op_type = att_op_get_type(buf->data[0]); + const att_type_t op_type = att_op_get_type(meta->opcode); - switch (op_type) { - case ATT_RESPONSE: - return chan_rsp_sent; - case ATT_CONFIRMATION: - return chan_cfm_sent; - case ATT_REQUEST: - case ATT_INDICATION: - return chan_req_sent; - case ATT_COMMAND: - case ATT_NOTIFICATION: - return chan_tx_complete; - default: - __ASSERT(false, "Unknown op type 0x%02X", op_type); - return NULL; - } -} - -static void att_cfm_sent(struct bt_conn *conn, void *user_data, int err) -{ - if (!err) { - att_sent(conn, user_data); - } - - chan_cfm_sent(conn, user_data); -} - -static void att_rsp_sent(struct bt_conn *conn, void *user_data, int err) -{ - if (!err) { - att_sent(conn, user_data); - } + LOG_DBG("opcode 0x%x", meta->opcode); - chan_rsp_sent(conn, user_data); -} - -static void att_req_sent(struct bt_conn *conn, void *user_data, int err) -{ - if (!err) { - att_sent(conn, user_data); - } - - chan_req_sent(conn, user_data); -} - -static void att_tx_complete(struct bt_conn *conn, void *user_data, int err) -{ - if (!err) { - att_sent(conn, user_data); + if (meta->err) { + LOG_ERR("Got err %d, not calling ATT cb", meta->err); + return; } - chan_tx_complete(conn, user_data); -} - -static void att_unknown(struct bt_conn *conn, void *user_data, int err) -{ - if (!err) { - att_sent(conn, user_data); + if (!bt_att_is_enhanced(meta->att_chan)) { + /* For EATT, L2CAP will call it after the SDU is fully sent. */ + LOG_DBG("UATT bearer, calling att_sent"); + att_sent(meta); } -} - -static bt_conn_tx_cb_t att_cb(const struct net_buf *buf) -{ - const att_type_t op_type = att_op_get_type(buf->data[0]); switch (op_type) { case ATT_RESPONSE: - return att_rsp_sent; + return; case ATT_CONFIRMATION: - return att_cfm_sent; + return; case ATT_REQUEST: case ATT_INDICATION: - return att_req_sent; + chan_rebegin_att_timeout(meta); + return; case ATT_COMMAND: case ATT_NOTIFICATION: - return att_tx_complete; + chan_req_notif_sent(meta); + return; default: __ASSERT(false, "Unknown op type 0x%02X", op_type); - /* This only ever runs if asserts are disabled. - * In any case, all bets are off. - */ - return att_unknown; + return; } } @@ -699,11 +650,10 @@ static struct net_buf *bt_att_chan_create_pdu(struct bt_att_chan *chan, uint8_t return NULL; } - data = bt_att_get_tx_meta_data(buf); /* If we got a buf from `att_pool`, then the metadata slot at its index * is officially ours to use. */ - memset(data, 0, sizeof(*data)); + data = bt_att_get_tx_meta_data(buf); if (IS_ENABLED(CONFIG_BT_EATT)) { net_buf_reserve(buf, BT_L2CAP_SDU_BUF_SIZE(0)); @@ -3225,11 +3175,6 @@ static void bt_att_released(struct bt_l2cap_chan *ch) { struct bt_att_chan *chan = ATT_CHAN(ch); - /* Empty the ATT bearer's TX queue */ - while (!sys_slist_is_empty(&chan->tx_cb_queue)) { - (void)sys_slist_get(&chan->tx_cb_queue); - } - LOG_DBG("chan %p", chan); k_mem_slab_free(&chan_slab, (void *)chan); @@ -3283,7 +3228,6 @@ static struct bt_att_chan *att_chan_new(struct bt_att *att, atomic_val_t flags) (void)memset(chan, 0, sizeof(*chan)); chan->chan.chan.ops = &ops; - sys_slist_init(&chan->tx_cb_queue); k_fifo_init(&chan->tx_queue); atomic_set(chan->flags, flags); chan->att = att; diff --git a/subsys/bluetooth/host/att_internal.h b/subsys/bluetooth/host/att_internal.h index de8f49276ad..a2b9895b46f 100644 --- a/subsys/bluetooth/host/att_internal.h +++ b/subsys/bluetooth/host/att_internal.h @@ -291,8 +291,6 @@ struct bt_att_req { void *user_data; }; -void att_sent(struct bt_conn *conn, void *user_data); - void bt_att_init(void); uint16_t bt_att_get_mtu(struct bt_conn *conn); struct net_buf *bt_att_create_pdu(struct bt_conn *conn, uint8_t op, From 4b2bf5abccab6aefd6afe70f91000e21767b81a8 Mon Sep 17 00:00:00 2001 From: Peter Mitsis Date: Fri, 8 Dec 2023 14:29:08 -0500 Subject: [PATCH 1323/3723] kernel: Apply const to k_pipe_put() parameter The pointer parameter 'data' in the function 'k_pipe_put()' ought to use the const modifier as the contents of the buffer to which it points never change. Internally, that const modifier is dropped as both 'k_pipe_get()' and 'k_pipe_put()' share common code for copying data; however 'k_pipe_put()' never takes a path that modifies those contents. Signed-off-by: Peter Mitsis --- include/zephyr/kernel.h | 2 +- kernel/pipes.c | 20 ++++++++++---------- 2 files changed, 11 insertions(+), 11 deletions(-) diff --git a/include/zephyr/kernel.h b/include/zephyr/kernel.h index c7840420b9c..7b9a00f1abd 100644 --- a/include/zephyr/kernel.h +++ b/include/zephyr/kernel.h @@ -4968,7 +4968,7 @@ __syscall int k_pipe_alloc_init(struct k_pipe *pipe, size_t size); * @retval -EAGAIN Waiting period timed out; between zero and @a min_xfer * minus one data bytes were written. */ -__syscall int k_pipe_put(struct k_pipe *pipe, void *data, +__syscall int k_pipe_put(struct k_pipe *pipe, const void *data, size_t bytes_to_write, size_t *bytes_written, size_t min_xfer, k_timeout_t timeout); diff --git a/kernel/pipes.c b/kernel/pipes.c index 3fa1c72036d..355377c2a79 100644 --- a/kernel/pipes.c +++ b/kernel/pipes.c @@ -377,9 +377,9 @@ static size_t pipe_write(struct k_pipe *pipe, sys_dlist_t *src_list, return num_bytes_written; } -int z_impl_k_pipe_put(struct k_pipe *pipe, void *data, size_t bytes_to_write, - size_t *bytes_written, size_t min_xfer, - k_timeout_t timeout) +int z_impl_k_pipe_put(struct k_pipe *pipe, const void *data, + size_t bytes_to_write, size_t *bytes_written, + size_t min_xfer, k_timeout_t timeout) { struct _pipe_desc pipe_desc[2]; struct _pipe_desc isr_desc; @@ -445,7 +445,7 @@ int z_impl_k_pipe_put(struct k_pipe *pipe, void *data, size_t bytes_to_write, src_desc = k_is_in_isr() ? &isr_desc : &_current->pipe_desc; - src_desc->buffer = data; + src_desc->buffer = (unsigned char *)data; src_desc->bytes_to_xfer = bytes_to_write; src_desc->thread = _current; sys_dlist_append(&src_list, &src_desc->node); @@ -513,17 +513,17 @@ int z_impl_k_pipe_put(struct k_pipe *pipe, void *data, size_t bytes_to_write, } #ifdef CONFIG_USERSPACE -int z_vrfy_k_pipe_put(struct k_pipe *pipe, void *data, size_t bytes_to_write, - size_t *bytes_written, size_t min_xfer, - k_timeout_t timeout) +int z_vrfy_k_pipe_put(struct k_pipe *pipe, const void *data, + size_t bytes_to_write, size_t *bytes_written, + size_t min_xfer, k_timeout_t timeout) { K_OOPS(K_SYSCALL_OBJ(pipe, K_OBJ_PIPE)); K_OOPS(K_SYSCALL_MEMORY_WRITE(bytes_written, sizeof(*bytes_written))); K_OOPS(K_SYSCALL_MEMORY_READ((void *)data, bytes_to_write)); - return z_impl_k_pipe_put((struct k_pipe *)pipe, (void *)data, - bytes_to_write, bytes_written, min_xfer, - timeout); + return z_impl_k_pipe_put((struct k_pipe *)pipe, data, + bytes_to_write, bytes_written, min_xfer, + timeout); } #include #endif From 94829f444c42a316bf3eee97451c726ae421b38d Mon Sep 17 00:00:00 2001 From: Peter Mitsis Date: Fri, 8 Dec 2023 15:30:21 -0500 Subject: [PATCH 1324/3723] tests: Initialize array in pipe test As the pointer to the data buffer passed to k_pipe_put() is now a 'const', that buffer must be initialized before calling k_pipe_put() to avoid a compiler warning. Signed-off-by: Peter Mitsis --- tests/kernel/pipe/pipe_api/src/test_pipe_contexts.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/tests/kernel/pipe/pipe_api/src/test_pipe_contexts.c b/tests/kernel/pipe/pipe_api/src/test_pipe_contexts.c index 3c7a119bf41..376bf65a97e 100644 --- a/tests/kernel/pipe/pipe_api/src/test_pipe_contexts.c +++ b/tests/kernel/pipe/pipe_api/src/test_pipe_contexts.c @@ -353,6 +353,8 @@ ZTEST(pipe_api, test_half_pipe_put_get) size_t rd_byte = 0; int ret; + memset(rx_data, 0, sizeof(rx_data)); + /* TESTPOINT: min_xfer > bytes_to_read */ ret = k_pipe_put(&kpipe, &rx_data[0], 1, &rd_byte, 24, K_NO_WAIT); zassert_true(ret == -EINVAL); From ee977dee47ecb21286df678643cfc2c0f453648f Mon Sep 17 00:00:00 2001 From: Peter Mitsis Date: Thu, 14 Dec 2023 10:18:39 -0500 Subject: [PATCH 1325/3723] kernel: Remove obsolete _mailbox field Removes the _mailbox from the k_mbox_msg structure. This field is not used and only existed for legacy API support while Zephyr was transitioning from the split microkernel/nanokernel to the current unified kernel design. Signed-off-by: Peter Mitsis --- include/zephyr/kernel.h | 2 -- 1 file changed, 2 deletions(-) diff --git a/include/zephyr/kernel.h b/include/zephyr/kernel.h index 7b9a00f1abd..ee47caed199 100644 --- a/include/zephyr/kernel.h +++ b/include/zephyr/kernel.h @@ -4685,8 +4685,6 @@ static inline uint32_t z_impl_k_msgq_num_used_get(struct k_msgq *msgq) * */ struct k_mbox_msg { - /** internal use only - needed for legacy API support */ - uint32_t _mailbox; /** size of message (in bytes) */ size_t size; /** application-defined information value */ From cc5cef817969117743440677f7a2a617d247f21a Mon Sep 17 00:00:00 2001 From: Fabio Baltieri Date: Fri, 15 Dec 2023 18:20:50 +0000 Subject: [PATCH 1326/3723] input: gpio_keys: add power management support Add power management support to the gpio keys driver. When in suspend, disable all the button gpios and interrupts. Signed-off-by: Fabio Baltieri --- drivers/input/input_gpio_keys.c | 62 +++++++++++++++++++++++++++++++-- 1 file changed, 59 insertions(+), 3 deletions(-) diff --git a/drivers/input/input_gpio_keys.c b/drivers/input/input_gpio_keys.c index aca17d466cb..e9df3cb907d 100644 --- a/drivers/input/input_gpio_keys.c +++ b/drivers/input/input_gpio_keys.c @@ -11,6 +11,8 @@ #include #include #include +#include +#include LOG_MODULE_REGISTER(gpio_keys, CONFIG_INPUT_LOG_LEVEL); @@ -138,8 +140,56 @@ static int gpio_keys_init(const struct device *dev) } } + ret = pm_device_runtime_enable(dev); + if (ret < 0) { + LOG_ERR("Failed to enable runtime power management"); + return ret; + } + + return 0; +} + +#ifdef CONFIG_PM_DEVICE +static int gpio_keys_pm_action(const struct device *dev, + enum pm_device_action action) +{ + const struct gpio_keys_config *cfg = dev->config; + gpio_flags_t gpio_flags; + gpio_flags_t int_flags; + int ret; + + switch (action) { + case PM_DEVICE_ACTION_SUSPEND: + gpio_flags = GPIO_DISCONNECTED; + int_flags = GPIO_INT_DISABLE; + break; + case PM_DEVICE_ACTION_RESUME: + gpio_flags = GPIO_INPUT; + int_flags = GPIO_INT_EDGE_BOTH; + break; + default: + return -ENOTSUP; + } + + for (int i = 0; i < cfg->num_keys; i++) { + const struct gpio_dt_spec *gpio = &cfg->pin_cfg[i].spec; + + ret = gpio_pin_configure_dt(gpio, gpio_flags); + if (ret != 0) { + LOG_ERR("Pin %d configuration failed: %d", i, ret); + return ret; + } + + ret = gpio_pin_interrupt_configure_dt(gpio, int_flags); + if (ret < 0) { + LOG_ERR("interrupt configuration failed: %d", ret); + return ret; + } + } + return 0; } +#endif #define GPIO_KEYS_CFG_CHECK(node_id) \ BUILD_ASSERT(DT_NODE_HAS_PROP(node_id, zephyr_code), \ @@ -153,17 +203,23 @@ static int gpio_keys_init(const struct device *dev) #define GPIO_KEYS_INIT(i) \ DT_INST_FOREACH_CHILD_STATUS_OKAY(i, GPIO_KEYS_CFG_CHECK); \ + \ static const struct gpio_keys_pin_config gpio_keys_pin_config_##i[] = { \ DT_INST_FOREACH_CHILD_STATUS_OKAY_SEP(i, GPIO_KEYS_CFG_DEF, (,))}; \ + \ static const struct gpio_keys_config gpio_keys_config_##i = { \ .debounce_interval_ms = DT_INST_PROP(i, debounce_interval_ms), \ .num_keys = ARRAY_SIZE(gpio_keys_pin_config_##i), \ .pin_cfg = gpio_keys_pin_config_##i, \ }; \ + \ static struct gpio_keys_pin_data \ gpio_keys_pin_data_##i[ARRAY_SIZE(gpio_keys_pin_config_##i)]; \ - DEVICE_DT_INST_DEFINE(i, &gpio_keys_init, NULL, gpio_keys_pin_data_##i, \ - &gpio_keys_config_##i, POST_KERNEL, CONFIG_INPUT_INIT_PRIORITY, \ - NULL); + \ + PM_DEVICE_DT_INST_DEFINE(n, gpio_keys_pm_action); \ + \ + DEVICE_DT_INST_DEFINE(i, &gpio_keys_init, PM_DEVICE_DT_INST_GET(n), \ + gpio_keys_pin_data_##i, &gpio_keys_config_##i, \ + POST_KERNEL, CONFIG_INPUT_INIT_PRIORITY, NULL); DT_INST_FOREACH_STATUS_OKAY(GPIO_KEYS_INIT) From 38d5c0a8ac27d90f8c797c6aeb3f8c399fdc3d48 Mon Sep 17 00:00:00 2001 From: Fabio Baltieri Date: Fri, 15 Dec 2023 15:17:46 +0000 Subject: [PATCH 1327/3723] input: kbd_matrix: make the thread priority configurable Add a config entry for the keyboard matrix thread priority. This changes the current default, but that was pretty much an arbitrary numbe anyay and the exact one should be picked the application so it should be alright to do so. Signed-off-by: Fabio Baltieri --- drivers/input/Kconfig.kbd_matrix | 7 +++++++ drivers/input/input_kbd_matrix.c | 2 +- 2 files changed, 8 insertions(+), 1 deletion(-) diff --git a/drivers/input/Kconfig.kbd_matrix b/drivers/input/Kconfig.kbd_matrix index e75402c7346..2ff139acde0 100644 --- a/drivers/input/Kconfig.kbd_matrix +++ b/drivers/input/Kconfig.kbd_matrix @@ -14,6 +14,13 @@ config INPUT_KBD_MATRIX_THREAD_STACK_SIZE help Size of the stack used for the keyboard matrix thread. + +config INPUT_KBD_MATRIX_THREAD_PRIORITY + int "Priority for the keyboard matrix thread" + default 0 + help + Priority level of the keyboard matrix thread. + config INPUT_KBD_MATRIX_16_BIT_ROW bool "16 bit row size support" help diff --git a/drivers/input/input_kbd_matrix.c b/drivers/input/input_kbd_matrix.c index ee830beac28..078ccf8cefa 100644 --- a/drivers/input/input_kbd_matrix.c +++ b/drivers/input/input_kbd_matrix.c @@ -310,7 +310,7 @@ int input_kbd_matrix_common_init(const struct device *dev) k_thread_create(&data->thread, data->thread_stack, CONFIG_INPUT_KBD_MATRIX_THREAD_STACK_SIZE, input_kbd_matrix_polling_thread, (void *)dev, NULL, NULL, - K_PRIO_COOP(4), 0, K_NO_WAIT); + CONFIG_INPUT_KBD_MATRIX_THREAD_PRIORITY, 0, K_NO_WAIT); k_thread_name_set(&data->thread, dev->name); From 51c54b1eaed28bc2e32df70bfad58c5ad47dc339 Mon Sep 17 00:00:00 2001 From: Joakim Andersson Date: Fri, 15 Dec 2023 12:13:54 +0100 Subject: [PATCH 1328/3723] MAINTAINERS: Remove joerchan Remove joerchan, put SebastianBoe instead. Signed-off-by: Joakim Andersson --- MAINTAINERS.yml | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/MAINTAINERS.yml b/MAINTAINERS.yml index c14008e8e8f..21603d8b785 100644 --- a/MAINTAINERS.yml +++ b/MAINTAINERS.yml @@ -3005,7 +3005,7 @@ TF-M Integration: maintainers: - d3zd3z collaborators: - - joerchan + - SebastianBoe files: - samples/tfm_integration/ - modules/trusted-firmware-m/ @@ -3757,7 +3757,6 @@ West: maintainers: - d3zd3z collaborators: - - joerchan - SebastianBoe files: - modules/trusted-firmware-m/ @@ -3769,7 +3768,6 @@ West: maintainers: - d3zd3z collaborators: - - joerchan - SebastianBoe files: [] labels: @@ -3792,7 +3790,6 @@ West: maintainers: - d3zd3z collaborators: - - joerchan - SebastianBoe files: [] labels: From d84598256c060d44b355592775c4e15257a5a9eb Mon Sep 17 00:00:00 2001 From: Peter Mitsis Date: Thu, 14 Dec 2023 13:59:12 -0500 Subject: [PATCH 1329/3723] tests: disable timeslicing on latency_measure Updates the latency_measure benchmark so that its default configuration does not enable timeslicing. As it is still valuable to know what kind of performance overhead is incurred by enabling timeslicing, new test configurations have been added. Signed-off-by: Peter Mitsis --- tests/benchmarks/latency_measure/prj.conf | 3 ++ .../benchmarks/latency_measure/prj_user.conf | 3 ++ .../benchmarks/latency_measure/testcase.yaml | 38 +++++++++++++++++++ 3 files changed, 44 insertions(+) diff --git a/tests/benchmarks/latency_measure/prj.conf b/tests/benchmarks/latency_measure/prj.conf index d1bc5fbaa17..a1ca84e4dc1 100644 --- a/tests/benchmarks/latency_measure/prj.conf +++ b/tests/benchmarks/latency_measure/prj.conf @@ -24,3 +24,6 @@ CONFIG_TIMING_FUNCTIONS=y CONFIG_HEAP_MEM_POOL_SIZE=2048 CONFIG_APPLICATION_DEFINED_SYSCALL=y + +# Disable time slicing +CONFIG_TIMESLICING=n diff --git a/tests/benchmarks/latency_measure/prj_user.conf b/tests/benchmarks/latency_measure/prj_user.conf index 92ca89a3bea..62ce8cafb52 100644 --- a/tests/benchmarks/latency_measure/prj_user.conf +++ b/tests/benchmarks/latency_measure/prj_user.conf @@ -25,3 +25,6 @@ CONFIG_TIMING_FUNCTIONS=y CONFIG_HEAP_MEM_POOL_SIZE=2048 CONFIG_APPLICATION_DEFINED_SYSCALL=y CONFIG_USERSPACE=y + +# Disable time slicing +CONFIG_TIMESLICING=n diff --git a/tests/benchmarks/latency_measure/testcase.yaml b/tests/benchmarks/latency_measure/testcase.yaml index e63fc9e5b30..272eeb8748b 100644 --- a/tests/benchmarks/latency_measure/testcase.yaml +++ b/tests/benchmarks/latency_measure/testcase.yaml @@ -95,3 +95,41 @@ tests: regex: "(?P.*):(?P.*) cycles ,(?P.*) ns" regex: - "PROJECT EXECUTION SUCCESSFUL" + + # Obtain the various kernel benchmark results with time slicing enabled + benchmark.kernel.latency.timeslicing: + # FIXME: no DWT and no RTC_TIMER for qemu_cortex_m0 + platform_exclude: + - qemu_cortex_m0 + - m2gl025_miv + filter: CONFIG_PRINTK and not CONFIG_SOC_FAMILY_STM32 + harness: console + integration_platforms: + - qemu_x86 + - qemu_arc_em + extra_configs: + - CONFIG_TIMESLICING=y + harness_config: + type: one_line + record: + regex: "(?P.*):(?P.*) cycles ,(?P.*) ns" + regex: + - "PROJECT EXECUTION SUCCESSFUL" + + # Obtain the various userspace benchmark results with timeslicing enabled + benchmark.user.latency.timeslicing: + filter: CONFIG_ARCH_HAS_USERSPACE + timeout: 300 + extra_args: CONF_FILE=prj_user.conf + harness: console + integration_platforms: + - qemu_x86 + - qemu_cortex_a53 + extra_configs: + - CONFIG_TIMESLICING=y + harness_config: + type: one_line + record: + regex: "(?P.*):(?P.*) cycles ,(?P.*) ns" + regex: + - "PROJECT EXECUTION SUCCESSFUL" From 4e37071f575bba1704a2811a5569adf155a38b2e Mon Sep 17 00:00:00 2001 From: Peter Mitsis Date: Thu, 14 Dec 2023 14:29:43 -0500 Subject: [PATCH 1330/3723] tests: disable timeslicing on app_kernel Updates the app_kernel benchmark so that its default configuration does not enable timeslicing. As it is still valuable to know what kind of performance overhead is incurred by enabling timeslicing, new test configurations have been added. Signed-off-by: Peter Mitsis --- tests/benchmarks/app_kernel/prj.conf | 3 +++ tests/benchmarks/app_kernel/prj_user.conf | 3 +++ tests/benchmarks/app_kernel/testcase.yaml | 14 ++++++++++++++ 3 files changed, 20 insertions(+) diff --git a/tests/benchmarks/app_kernel/prj.conf b/tests/benchmarks/app_kernel/prj.conf index a01e0835a81..57cd1f1544e 100644 --- a/tests/benchmarks/app_kernel/prj.conf +++ b/tests/benchmarks/app_kernel/prj.conf @@ -21,3 +21,6 @@ CONFIG_PIPES=y CONFIG_APPLICATION_DEFINED_SYSCALL=y CONFIG_TIMING_FUNCTIONS=y + +# Disable time slicing +CONFIG_TIMESLICING=n diff --git a/tests/benchmarks/app_kernel/prj_user.conf b/tests/benchmarks/app_kernel/prj_user.conf index b0438e6b34c..e890dbf3c8e 100644 --- a/tests/benchmarks/app_kernel/prj_user.conf +++ b/tests/benchmarks/app_kernel/prj_user.conf @@ -22,3 +22,6 @@ CONFIG_PIPES=y CONFIG_APPLICATION_DEFINED_SYSCALL=y CONFIG_TIMING_FUNCTIONS=y CONFIG_USERSPACE=y + +# Disable time slicing +CONFIG_TIMESLICING=n diff --git a/tests/benchmarks/app_kernel/testcase.yaml b/tests/benchmarks/app_kernel/testcase.yaml index 07a3720993a..2b07dedad66 100644 --- a/tests/benchmarks/app_kernel/testcase.yaml +++ b/tests/benchmarks/app_kernel/testcase.yaml @@ -32,3 +32,17 @@ tests: extra_configs: - CONFIG_OBJ_CORE=y - CONFIG_OBJ_CORE_STATS=y + benchmark.kernel.application.timeslicing: + integration_platforms: + - mps2_an385 + - qemu_x86 + extra_configs: + - CONFIG_TIMESLICING=y + benchmark.kernel.application.user.timeslicing: + extra_args: CONF_FILE=prj_user.conf + filter: CONFIG_ARCH_HAS_USERSPACE + integration_platforms: + - mps2_an385 + - qemu_x86 + extra_configs: + - CONFIG_TIMESLICING=y From 9736cc7f29668542a85b5c775b368a6a30c7f8c0 Mon Sep 17 00:00:00 2001 From: Chaitanya Tata Date: Thu, 14 Dec 2023 21:13:44 +0530 Subject: [PATCH 1331/3723] wifi: shell: Fix AP argument checks and help AP enable takes the same parameters as connect, so, update the help and also fix the optional parameter count when security is involved. Signed-off-by: Chaitanya Tata --- subsys/net/l2/wifi/wifi_shell.c | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) diff --git a/subsys/net/l2/wifi/wifi_shell.c b/subsys/net/l2/wifi/wifi_shell.c index c5b8f60d933..e243a9de4e4 100644 --- a/subsys/net/l2/wifi/wifi_shell.c +++ b/subsys/net/l2/wifi/wifi_shell.c @@ -1602,9 +1602,16 @@ SHELL_STATIC_SUBCMD_SET_CREATE(wifi_cmd_ap, "Disable Access Point mode", cmd_wifi_ap_disable, 1, 0), - SHELL_CMD_ARG(enable, NULL, " [channel] [PSK]", + SHELL_CMD_ARG(enable, NULL, + "\"\"\n" + "[channel number: 0 means all]\n" + "[PSK: valid only for secure SSIDs]\n" + "[Security type: valid only for secure SSIDs]\n" + "0:None, 1:WPA2-PSK, 2:WPA2-PSK-256, 3:SAE, 4:WAPI, 5:EAP, 6:WEP, 7: WPA-PSK\n" + "[MFP (optional: needs security type to be specified)]\n" + ": 0:Disable, 1:Optional, 2:Required", cmd_wifi_ap_enable, - 2, 1), + 2, 4), SHELL_SUBCMD_SET_END ); From eaba47445a4e9cd1bee7d6adb9b9c62f159f3088 Mon Sep 17 00:00:00 2001 From: Chaitanya Tata Date: Thu, 14 Dec 2023 21:17:07 +0530 Subject: [PATCH 1332/3723] wifi: shell: Display RSSI only for station mode RSSI makes sense only for modes that have a single peer, so, add a station mode check. Signed-off-by: Chaitanya Tata --- subsys/net/l2/wifi/wifi_shell.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/subsys/net/l2/wifi/wifi_shell.c b/subsys/net/l2/wifi/wifi_shell.c index e243a9de4e4..f1a98105204 100644 --- a/subsys/net/l2/wifi/wifi_shell.c +++ b/subsys/net/l2/wifi/wifi_shell.c @@ -660,7 +660,9 @@ static int cmd_wifi_status(const struct shell *sh, size_t argc, char *argv[]) wifi_security_txt(status.security)); shell_fprintf(sh, SHELL_NORMAL, "MFP: %s\n", wifi_mfp_txt(status.mfp)); - shell_fprintf(sh, SHELL_NORMAL, "RSSI: %d\n", status.rssi); + if (status.iface_mode == WIFI_MODE_INFRA) { + shell_fprintf(sh, SHELL_NORMAL, "RSSI: %d\n", status.rssi); + } shell_fprintf(sh, SHELL_NORMAL, "Beacon Interval: %d\n", status.beacon_interval); shell_fprintf(sh, SHELL_NORMAL, "DTIM: %d\n", status.dtim_period); shell_fprintf(sh, SHELL_NORMAL, "TWT: %s\n", From 4807ada01ee98d52ad7aa5b36166529b683fc09b Mon Sep 17 00:00:00 2001 From: Pieter De Gendt Date: Thu, 14 Dec 2023 15:53:28 +0100 Subject: [PATCH 1333/3723] net: lib: coap: Use coap_transmission_parameters in coap_server Update coap_service_send and coap_resource_send to take an optional pointer argument to the newly introduced coap_transmission_parameters. Signed-off-by: Pieter De Gendt --- .../networking/api/coap_server.rst | 4 ++-- include/zephyr/net/coap_service.h | 8 ++++++-- samples/net/sockets/coap_server/src/core.c | 2 +- samples/net/sockets/coap_server/src/large.c | 6 +++--- .../sockets/coap_server/src/location_query.c | 2 +- samples/net/sockets/coap_server/src/observer.c | 2 +- samples/net/sockets/coap_server/src/query.c | 2 +- samples/net/sockets/coap_server/src/separate.c | 4 ++-- samples/net/sockets/coap_server/src/test.c | 8 ++++---- subsys/net/lib/coap/Kconfig | 6 ------ subsys/net/lib/coap/coap_server.c | 18 ++++++++---------- 11 files changed, 29 insertions(+), 33 deletions(-) diff --git a/doc/connectivity/networking/api/coap_server.rst b/doc/connectivity/networking/api/coap_server.rst index f80bf42ada7..ac330c8d01e 100644 --- a/doc/connectivity/networking/api/coap_server.rst +++ b/doc/connectivity/networking/api/coap_server.rst @@ -97,7 +97,7 @@ The following is an example of a CoAP resource registered with our service: coap_packet_append_payload(&response, (uint8_t *)msg, sizeof(msg)); /* Send to response back to the client */ - return coap_resource_send(resource, &response, addr, addr_len); + return coap_resource_send(resource, &response, addr, addr_len, NULL); } static int my_put(struct coap_resource *resource, struct coap_packet *request, @@ -178,7 +178,7 @@ of CoAP services. An example using a temperature sensor can look like: coap_packet_append_payload_marker(&response); coap_packet_append_payload(&response, (uint8_t *)payload, strlen(payload)); - return coap_resource_send(resource, &response, addr, addr_len); + return coap_resource_send(resource, &response, addr, addr_len, NULL); } static int temp_get(struct coap_resource *resource, struct coap_packet *request, diff --git a/include/zephyr/net/coap_service.h b/include/zephyr/net/coap_service.h index 6f038ce61e1..b894fecf519 100644 --- a/include/zephyr/net/coap_service.h +++ b/include/zephyr/net/coap_service.h @@ -235,10 +235,12 @@ int coap_service_is_running(const struct coap_service *service); * @param cpkt CoAP Packet to send * @param addr Peer address * @param addr_len Peer address length + * @param params Pointer to transmission parameters structure or NULL to use default values. * @return 0 in case of success or negative in case of error. */ int coap_service_send(const struct coap_service *service, const struct coap_packet *cpkt, - const struct sockaddr *addr, socklen_t addr_len); + const struct sockaddr *addr, socklen_t addr_len, + const struct coap_transmission_parameters *params); /** * @brief Send a CoAP message from the provided @p resource . @@ -249,10 +251,12 @@ int coap_service_send(const struct coap_service *service, const struct coap_pack * @param cpkt CoAP Packet to send * @param addr Peer address * @param addr_len Peer address length + * @param params Pointer to transmission parameters structure or NULL to use default values. * @return 0 in case of success or negative in case of error. */ int coap_resource_send(const struct coap_resource *resource, const struct coap_packet *cpkt, - const struct sockaddr *addr, socklen_t addr_len); + const struct sockaddr *addr, socklen_t addr_len, + const struct coap_transmission_parameters *params); /** * @brief Parse a CoAP observe request for the provided @p resource . diff --git a/samples/net/sockets/coap_server/src/core.c b/samples/net/sockets/coap_server/src/core.c index 276ab0d5de1..00f4adb4d34 100644 --- a/samples/net/sockets/coap_server/src/core.c +++ b/samples/net/sockets/coap_server/src/core.c @@ -45,7 +45,7 @@ static int core_get(struct coap_resource *resource, return r; } - r = coap_resource_send(resource, &response, addr, addr_len); + r = coap_resource_send(resource, &response, addr, addr_len, NULL); return r; } diff --git a/samples/net/sockets/coap_server/src/large.c b/samples/net/sockets/coap_server/src/large.c index 28a3eebe099..8656a5b53b1 100644 --- a/samples/net/sockets/coap_server/src/large.c +++ b/samples/net/sockets/coap_server/src/large.c @@ -87,7 +87,7 @@ static int large_get(struct coap_resource *resource, memset(&ctx, 0, sizeof(ctx)); } - r = coap_resource_send(resource, &response, addr, addr_len); + r = coap_resource_send(resource, &response, addr, addr_len, NULL); return r; } @@ -167,7 +167,7 @@ static int large_update_put(struct coap_resource *resource, return r; } - r = coap_resource_send(resource, &response, addr, addr_len); + r = coap_resource_send(resource, &response, addr, addr_len, NULL); return r; } @@ -239,7 +239,7 @@ static int large_create_post(struct coap_resource *resource, return r; } - r = coap_resource_send(resource, &response, addr, addr_len); + r = coap_resource_send(resource, &response, addr, addr_len, NULL); return r; } diff --git a/samples/net/sockets/coap_server/src/location_query.c b/samples/net/sockets/coap_server/src/location_query.c index b13079bc456..bce4eb67b86 100644 --- a/samples/net/sockets/coap_server/src/location_query.c +++ b/samples/net/sockets/coap_server/src/location_query.c @@ -59,7 +59,7 @@ static int location_query_post(struct coap_resource *resource, } } - r = coap_resource_send(resource, &response, addr, addr_len); + r = coap_resource_send(resource, &response, addr, addr_len, NULL); return r; } diff --git a/samples/net/sockets/coap_server/src/observer.c b/samples/net/sockets/coap_server/src/observer.c index 6d39536e232..8a14d316c61 100644 --- a/samples/net/sockets/coap_server/src/observer.c +++ b/samples/net/sockets/coap_server/src/observer.c @@ -80,7 +80,7 @@ static int send_notification_packet(struct coap_resource *resource, k_work_reschedule(&obs_work, K_SECONDS(5)); - r = coap_resource_send(resource, &response, addr, addr_len); + r = coap_resource_send(resource, &response, addr, addr_len, NULL); return r; } diff --git a/samples/net/sockets/coap_server/src/query.c b/samples/net/sockets/coap_server/src/query.c index 10479b1e6f1..95272189d9c 100644 --- a/samples/net/sockets/coap_server/src/query.c +++ b/samples/net/sockets/coap_server/src/query.c @@ -89,7 +89,7 @@ static int query_get(struct coap_resource *resource, return r; } - r = coap_resource_send(resource, &response, addr, addr_len); + r = coap_resource_send(resource, &response, addr, addr_len, NULL); return r; } diff --git a/samples/net/sockets/coap_server/src/separate.c b/samples/net/sockets/coap_server/src/separate.c index c3f6f6c256e..68bba0bb473 100644 --- a/samples/net/sockets/coap_server/src/separate.c +++ b/samples/net/sockets/coap_server/src/separate.c @@ -43,7 +43,7 @@ static int separate_get(struct coap_resource *resource, return r; } - r = coap_resource_send(resource, &response, addr, addr_len); + r = coap_resource_send(resource, &response, addr, addr_len, NULL); if (r < 0) { return r; } @@ -86,7 +86,7 @@ static int separate_get(struct coap_resource *resource, return r; } - r = coap_resource_send(resource, &response, addr, addr_len); + r = coap_resource_send(resource, &response, addr, addr_len, NULL); return r; } diff --git a/samples/net/sockets/coap_server/src/test.c b/samples/net/sockets/coap_server/src/test.c index aa496a125b1..52885b31a5d 100644 --- a/samples/net/sockets/coap_server/src/test.c +++ b/samples/net/sockets/coap_server/src/test.c @@ -73,7 +73,7 @@ static int piggyback_get(struct coap_resource *resource, return r; } - r = coap_resource_send(resource, &response, addr, addr_len); + r = coap_resource_send(resource, &response, addr, addr_len, NULL); return r; } @@ -113,7 +113,7 @@ static int test_del(struct coap_resource *resource, return r; } - r = coap_resource_send(resource, &response, addr, addr_len); + r = coap_resource_send(resource, &response, addr, addr_len, NULL); return r; } @@ -160,7 +160,7 @@ static int test_put(struct coap_resource *resource, return r; } - r = coap_resource_send(resource, &response, addr, addr_len); + r = coap_resource_send(resource, &response, addr, addr_len, NULL); return r; } @@ -221,7 +221,7 @@ static int test_post(struct coap_resource *resource, } } - r = coap_resource_send(resource, &response, addr, addr_len); + r = coap_resource_send(resource, &response, addr, addr_len, NULL); return r; } diff --git a/subsys/net/lib/coap/Kconfig b/subsys/net/lib/coap/Kconfig index f4d002d0c5d..63396bb0518 100644 --- a/subsys/net/lib/coap/Kconfig +++ b/subsys/net/lib/coap/Kconfig @@ -202,12 +202,6 @@ config COAP_SERVICE_PENDING_MESSAGES help Maximum number of pending CoAP messages to retransmit per active service. -config COAP_SERVICE_PENDING_RETRANSMITS - int "CoAP retransmit count" - default 2 - help - Maximum number of retries to send a pending message. - config COAP_SERVICE_OBSERVERS int "CoAP service observers" default 3 diff --git a/subsys/net/lib/coap/coap_server.c b/subsys/net/lib/coap/coap_server.c index 66e5dcbc32c..28d5b8de47f 100644 --- a/subsys/net/lib/coap/coap_server.c +++ b/subsys/net/lib/coap/coap_server.c @@ -215,7 +215,7 @@ static int coap_server_process(int sock_fd) goto unlock; } - ret = coap_service_send(service, &response, &client_addr, client_addr_len); + ret = coap_service_send(service, &response, &client_addr, client_addr_len, NULL); } else { ret = coap_handle_request_len(&request, service->res_begin, COAP_SERVICE_RESOURCE_COUNT(service), @@ -246,7 +246,7 @@ static int coap_server_process(int sock_fd) goto unlock; } - ret = coap_service_send(service, &ack, &client_addr, client_addr_len); + ret = coap_service_send(service, &ack, &client_addr, client_addr_len, NULL); } } @@ -521,7 +521,8 @@ int coap_service_is_running(const struct coap_service *service) } int coap_service_send(const struct coap_service *service, const struct coap_packet *cpkt, - const struct sockaddr *addr, socklen_t addr_len) + const struct sockaddr *addr, socklen_t addr_len, + const struct coap_transmission_parameters *params) { int ret; @@ -542,8 +543,6 @@ int coap_service_send(const struct coap_service *service, const struct coap_pack * try to send. */ if (coap_header_get_type(cpkt) == COAP_TYPE_CON) { - struct coap_transmission_parameters params; - struct coap_pending *pending = coap_pending_next_unused(service->data->pending, MAX_PENDINGS); @@ -552,9 +551,7 @@ int coap_service_send(const struct coap_service *service, const struct coap_pack goto send; } - params = coap_get_transmission_parameters(); - params.max_retransmission = CONFIG_COAP_SERVICE_PENDING_RETRANSMITS; - ret = coap_pending_init(pending, cpkt, addr, ¶ms); + ret = coap_pending_init(pending, cpkt, addr, params); if (ret < 0) { LOG_WRN("Failed to init pending message for %s (%d)", service->name, ret); goto send; @@ -589,12 +586,13 @@ int coap_service_send(const struct coap_service *service, const struct coap_pack } int coap_resource_send(const struct coap_resource *resource, const struct coap_packet *cpkt, - const struct sockaddr *addr, socklen_t addr_len) + const struct sockaddr *addr, socklen_t addr_len, + const struct coap_transmission_parameters *params) { /* Find owning service */ COAP_SERVICE_FOREACH(svc) { if (COAP_SERVICE_HAS_RESOURCE(svc, resource)) { - return coap_service_send(svc, cpkt, addr, addr_len); + return coap_service_send(svc, cpkt, addr, addr_len, params); } } From dee2fe27f658e715427215d477f298558f6b1381 Mon Sep 17 00:00:00 2001 From: Pieter De Gendt Date: Thu, 14 Dec 2023 16:06:55 +0100 Subject: [PATCH 1334/3723] doc: migration-guide: 3.6: Add CoAP service send functions update. Add an entry to indicate the changes to the coap_service_send and coap_resource_send API functions. Signed-off-by: Pieter De Gendt --- doc/releases/migration-guide-3.6.rst | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/doc/releases/migration-guide-3.6.rst b/doc/releases/migration-guide-3.6.rst index 5e8ae8e3a0a..b2bf8ed6837 100644 --- a/doc/releases/migration-guide-3.6.rst +++ b/doc/releases/migration-guide-3.6.rst @@ -245,6 +245,10 @@ Networking use default values. (:github:`66482`) +* The CoAP public API functions :c:func:`coap_service_send` and :c:func:`coap_resource_send` have + changed. An additional parameter pointer to :c:struct:`coap_transmission_parameters` has been + added. It is safe to pass a NULL pointer to use default values. (:github:`66540`) + * The IGMP multicast library now supports IGMPv3. This results in a minor change to the existing api. The :c:func:`net_ipv4_igmp_join` now takes an additional argument of the type ``const struct igmp_param *param``. This allows IGMPv3 to exclude/include certain groups of From 25cb4683d2b6289bd500fc40f00337a6b5e8bd2f Mon Sep 17 00:00:00 2001 From: Andrej Butok Date: Thu, 14 Dec 2023 13:51:23 +0100 Subject: [PATCH 1335/3723] test: mcuboot: enable test on rt1010/1015/1040 and k22f/82f platforms Enable mcuboot test for mimxrt1010/1015/1040 and frdm_k22f/82f boards Signed-off-by: Andrej Butok --- tests/boot/test_mcuboot/testcase.yaml | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/tests/boot/test_mcuboot/testcase.yaml b/tests/boot/test_mcuboot/testcase.yaml index c5622139386..0fff9fa97d3 100644 --- a/tests/boot/test_mcuboot/testcase.yaml +++ b/tests/boot/test_mcuboot/testcase.yaml @@ -13,9 +13,14 @@ tests: bootloader.mcuboot: tags: mcuboot platform_allow: + - frdm_k22f - frdm_k64f + - frdm_k82f + - mimxrt1010_evk + - mimxrt1015_evk - mimxrt1020_evk - mimxrt1024_evk + - mimxrt1040_evk - mimxrt1050_evk - mimxrt1060_evk - mimxrt1064_evk From b7e3ae25212fecb992ceb5e6668c6445dce31b09 Mon Sep 17 00:00:00 2001 From: Robert Lubos Date: Thu, 14 Dec 2023 12:49:47 +0100 Subject: [PATCH 1336/3723] net: ipv6_mld: Silently drop MLDv1 queries Zephyr does not support MLDv1 (which has a shorter header than MLDv2), and this resulted in log errors being printed on header access if MLDv1 queries were received. Since receiving such packet is not really an error, just drop it silently. Signed-off-by: Robert Lubos --- subsys/net/ip/ipv6_mld.c | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/subsys/net/ip/ipv6_mld.c b/subsys/net/ip/ipv6_mld.c index e9eb82984f2..a7c3971e8ef 100644 --- a/subsys/net/ip/ipv6_mld.c +++ b/subsys/net/ip/ipv6_mld.c @@ -321,6 +321,13 @@ static int handle_mld_query(struct net_icmp_ctx *ctx, uint16_t length = net_pkt_get_len(pkt); struct net_icmpv6_mld_query *mld_query; uint16_t pkt_len; + int ret = -EIO; + + if (net_pkt_remaining_data(pkt) < sizeof(struct net_icmpv6_mld_query)) { + /* MLDv1 query, drop. */ + ret = 0; + goto drop; + } mld_query = (struct net_icmpv6_mld_query *) net_pkt_get_data(pkt, &mld_access); @@ -361,7 +368,7 @@ static int handle_mld_query(struct net_icmp_ctx *ctx, drop: net_stats_update_ipv6_mld_drop(net_pkt_iface(pkt)); - return -EIO; + return ret; } void net_ipv6_mld_init(void) From ad4544fd0f1e08f27e2de8d7211e257f0905f6fa Mon Sep 17 00:00:00 2001 From: Alberto Escolar Piedras Date: Thu, 14 Dec 2023 11:11:23 +0100 Subject: [PATCH 1337/3723] native_sim docs: Miscellaneous fixes * Add a subsection linking to the emulators section. * Added more internal links * Fixed EPROM simulator/emulator mix, and added link to simulator * For the RTC peripheral, mention there is no driver for it yet. Signed-off-by: Alberto Escolar Piedras --- boards/posix/native_sim/doc/index.rst | 51 ++++++++++++++++++++------- 1 file changed, 38 insertions(+), 13 deletions(-) diff --git a/boards/posix/native_sim/doc/index.rst b/boards/posix/native_sim/doc/index.rst index b92d0bf911a..ae858b1d05f 100644 --- a/boards/posix/native_sim/doc/index.rst +++ b/boards/posix/native_sim/doc/index.rst @@ -351,6 +351,10 @@ The following peripherals are currently provided with this board: execution speed of native_sim and the host load, it may return a value considerably ahead of the simulated time. + Note this device does not yet have an :ref:`RTC API compatible driver `. + +.. _nsim_per_entr: + **Entropy device** An entropy device based on the host :c:func:`random` API. This device will generate the same sequence of random numbers if initialized @@ -359,6 +363,8 @@ The following peripherals are currently provided with this board: :samp:`--seed={}` where the value specified is a 32-bit integer such as 97229 (decimal), 0x17BCD (hex), or 0275715 (octal). +.. _nsim_per_ethe: + **Ethernet driver** A simple TAP based ethernet driver is provided. The driver expects that the **zeth** network interface already exists in the host system. The **zeth** @@ -373,6 +379,7 @@ The following peripherals are currently provided with this board: .. _net-tools: https://github.com/zephyrproject-rtos/net-tools +.. _nsim_bt_host_cont: **Bluetooth controller** It's possible to use the host's Bluetooth adapter as a Bluetooth @@ -393,11 +400,15 @@ The following peripherals are currently provided with this board: a virtual Bluetooth controller that does not depend on the Linux Bluetooth stack and its HCI interface. +.. _nsim_per_usb: + **USB controller** It's possible to use the Virtual USB controller working over USB/IP protocol. More information can be found in :ref:`Testing USB over USP/IP in native_sim `. +.. _nsim_per_disp_sdl: + **Display driver** A display driver is provided that creates a window on the host machine to render display content. @@ -420,6 +431,8 @@ The following peripherals are currently provided with this board: .. _SDL2: https://www.libsdl.org/download-2.0.php +.. _nsim_per_flash_simu: + **Flash driver** A flash driver is provided that accesses all flash data through a binary file on the host file system. The behavior of the flash device can be configured @@ -530,6 +543,8 @@ Apart from its own peripherals, the native_sim board also has some dedicated backends for some of Zephyr's subsystems. These backends are designed to ease development by integrating more seamlessly with the host operating system: +.. _nsim_back_console: + **Console backend**: A console backend which by default is configured to redirect any :c:func:`printk` write to the native host application's @@ -539,6 +554,8 @@ development by integrating more seamlessly with the host operating system: Otherwise :kconfig:option:`CONFIG_UART_CONSOLE` will be set to select the UART as console backend. +.. _nsim_back_logger: + **Logger backend**: A backend which prints all logger output to the process ``stdout``. It supports timestamping, which can be enabled with @@ -555,11 +572,18 @@ development by integrating more seamlessly with the host operating system: In this later case, by default, the logger is set to output to the `PTTY UART`_. +.. _nsim_back_trace: + **Tracing**: A backend/"bottom" for Zephyr's CTF tracing subsystem which writes the tracing data to a file in the host filesystem. More information can be found in :ref:`Common Tracing Format ` +Emulators +********* + +All :ref:`available HW emulators ` can be used with native_sim. + .. _native_fuse_flash: Host based flash access @@ -614,24 +638,25 @@ host libC (:kconfig:option:`CONFIG_EXTERNAL_LIBC`): :header: Driver class, driver name, driver kconfig, libC choices adc, ADC emul, :kconfig:option:`CONFIG_ADC_EMUL`, all - bluetooth, userchan, :kconfig:option:`CONFIG_BT_USERCHAN`, host libC + bluetooth, :ref:`userchan `, :kconfig:option:`CONFIG_BT_USERCHAN`, host libC can, can native Linux, :kconfig:option:`CONFIG_CAN_NATIVE_LINUX`, all - console backend, POSIX arch console, :kconfig:option:`CONFIG_POSIX_ARCH_CONSOLE`, all - display, display SDL, :kconfig:option:`CONFIG_SDL_DISPLAY`, all - entropy, native posix entropy, :kconfig:option:`CONFIG_FAKE_ENTROPY_NATIVE_POSIX`, all - eprom, eprom emulator, :kconfig:option:`CONFIG_EEPROM_EMULATOR`, host libC - ethernet, eth native_posix, :kconfig:option:`CONFIG_ETH_NATIVE_POSIX`, all - flash, flash simulator, :kconfig:option:`CONFIG_FLASH_SIMULATOR`, all - flash, host based flash access, :kconfig:option:`CONFIG_FUSE_FS_ACCESS`, host libC + console backend, :ref:`POSIX arch console `, :kconfig:option:`CONFIG_POSIX_ARCH_CONSOLE`, all + display, :ref:`display SDL `, :kconfig:option:`CONFIG_SDL_DISPLAY`, all + entropy, :ref:`native posix entropy `, :kconfig:option:`CONFIG_FAKE_ENTROPY_NATIVE_POSIX`, all + eeprom, eeprom simulator, :kconfig:option:`CONFIG_EEPROM_SIMULATOR`, host libC + eeprom, eeprom emulator, :kconfig:option:`CONFIG_EEPROM_EMULATOR`, all + ethernet, :ref:`eth native_posix `, :kconfig:option:`CONFIG_ETH_NATIVE_POSIX`, all + flash, :ref:`flash simulator `, :kconfig:option:`CONFIG_FLASH_SIMULATOR`, all + flash, :ref:`host based flash access `, :kconfig:option:`CONFIG_FUSE_FS_ACCESS`, host libC gpio, GPIO emulator, :kconfig:option:`CONFIG_GPIO_EMUL`, all gpio, SDL GPIO emulator, :kconfig:option:`CONFIG_GPIO_EMUL_SDL`, all i2c, I2C emulator, :kconfig:option:`CONFIG_I2C_EMUL`, all input, input SDL touch, :kconfig:option:`CONFIG_INPUT_SDL_TOUCH`, all - log backend, native backend, :kconfig:option:`CONFIG_LOG_BACKEND_NATIVE_POSIX`, all + log backend, :ref:`native backend `, :kconfig:option:`CONFIG_LOG_BACKEND_NATIVE_POSIX`, all rtc, RTC emul, :kconfig:option:`CONFIG_RTC_EMUL`, all - serial, uart native posix/PTTY, :kconfig:option:`CONFIG_UART_NATIVE_POSIX`, all - serial, uart native TTY, :kconfig:option:`CONFIG_UART_NATIVE_TTY`, all + serial, :ref:`uart native posix/PTTY `, :kconfig:option:`CONFIG_UART_NATIVE_POSIX`, all + serial, :ref:`uart native TTY `, :kconfig:option:`CONFIG_UART_NATIVE_TTY`, all spi, SPI emul, :kconfig:option:`CONFIG_SPI_EMUL`, all system tick, native_posix timer, :kconfig:option:`CONFIG_NATIVE_POSIX_TIMER`, all - tracing, Posix tracing backend, :kconfig:option:`CONFIG_TRACING_BACKEND_POSIX`, all - usb, USB native posix, :kconfig:option:`CONFIG_USB_NATIVE_POSIX`, host libC + tracing, :ref:`Posix tracing backend `, :kconfig:option:`CONFIG_TRACING_BACKEND_POSIX`, all + usb, :ref:`USB native posix `, :kconfig:option:`CONFIG_USB_NATIVE_POSIX`, host libC From 9b78b4e894209d02330421a136273639f4dd54ca Mon Sep 17 00:00:00 2001 From: Tomi Fontanilles Date: Thu, 14 Dec 2023 11:43:04 +0200 Subject: [PATCH 1338/3723] drivers: net: ppp: various fixes - Disable UART when the PPP interface is brought down. This prevents an error when it is next brought up. - Change the level of certain logs to be less concerning and less verbose. - Fix warnings regarding the passed parameter types of %p conversions. Signed-off-by: Tomi Fontanilles --- drivers/net/ppp.c | 13 ++++++++----- 1 file changed, 8 insertions(+), 5 deletions(-) diff --git a/drivers/net/ppp.c b/drivers/net/ppp.c index ecfdb7c3af1..1d9bb9fd96a 100644 --- a/drivers/net/ppp.c +++ b/drivers/net/ppp.c @@ -121,7 +121,7 @@ static void uart_callback(const struct device *dev, switch (evt->type) { case UART_TX_DONE: - LOG_DBG("UART_TX_DONE: sent %d bytes", evt->data.tx.len); + LOG_DBG("UART_TX_DONE: sent %zu bytes", evt->data.tx.len); k_sem_give(&uarte_tx_finished); break; @@ -171,7 +171,7 @@ static void uart_callback(const struct device *dev, case UART_RX_BUF_REQUEST: { - LOG_DBG("UART_RX_BUF_REQUEST: buf %p", next_buf); + LOG_DBG("UART_RX_BUF_REQUEST: buf %p", (void *)next_buf); if (next_buf) { err = uart_rx_buf_rsp(dev, next_buf, sizeof(context->buf)); @@ -185,7 +185,7 @@ static void uart_callback(const struct device *dev, case UART_RX_BUF_RELEASED: next_buf = evt->data.rx_buf.buf; - LOG_DBG("UART_RX_BUF_RELEASED: buf %p", next_buf); + LOG_DBG("UART_RX_BUF_RELEASED: buf %p", (void *)next_buf); break; case UART_RX_DISABLED: @@ -243,7 +243,7 @@ static void uart_recovery(struct k_work *work) if (ret) { LOG_ERR("ppp_async_uart_rx_enable() failed, err %d", ret); } else { - LOG_WRN("UART RX recovered"); + LOG_DBG("UART RX recovered."); } uart_recovery_pending = false; } else { @@ -1027,7 +1027,7 @@ static int ppp_start(const struct device *dev) /* dts chosen zephyr,ppp-uart case */ context->dev = DEVICE_DT_GET(DT_CHOSEN(zephyr_ppp_uart)); #endif - LOG_INF("Initializing PPP to use %s", context->dev->name); + LOG_DBG("Initializing PPP to use %s", context->dev->name); if (!device_is_ready(context->dev)) { LOG_ERR("Device %s is not ready", context->dev->name); @@ -1056,6 +1056,9 @@ static int ppp_stop(const struct device *dev) struct ppp_driver_context *context = dev->data; net_if_carrier_off(context->iface); +#if defined(CONFIG_NET_PPP_ASYNC_UART) + uart_rx_disable(context->dev); +#endif context->modem_init_done = false; return 0; } From 490a02fda7b614a58fc8226715b3e9337d584fb1 Mon Sep 17 00:00:00 2001 From: Tomi Fontanilles Date: Thu, 14 Dec 2023 11:58:55 +0200 Subject: [PATCH 1339/3723] drivers: net: ppp: improve CONFIG_NET_PPP_ASYNC_UART_TX_TIMEOUT Its default value (100 ms) resulted in PDUs big enough to never make it through on a slow enough UART (e.g. ~1152-byte PDUs on a UART@115200). The UART TXs were silently aborted. A no-timeout value is now allowed and made the default. Additional warnings are logged when it is likely that a UART TX was aborted due to a too low timeout for the used baud rate. Signed-off-by: Tomi Fontanilles --- drivers/net/Kconfig | 13 +++++-------- drivers/net/ppp.c | 28 +++++++++++++++++++++++++--- 2 files changed, 30 insertions(+), 11 deletions(-) diff --git a/drivers/net/Kconfig b/drivers/net/Kconfig index f6e0faa334a..c83f0f42a08 100644 --- a/drivers/net/Kconfig +++ b/drivers/net/Kconfig @@ -94,11 +94,12 @@ config PPP_NET_IF_NO_AUTO_START if NET_PPP_ASYNC_UART config NET_PPP_ASYNC_UART_TX_BUF_LEN - int "Buffer length from where the write to async UART is done" + int "Length of the UART TX buffer to which data is written." default 2048 - help - This options sets the size of the UART TX buffer where data - is being written from to UART. + +config NET_PPP_ASYNC_UART_TX_TIMEOUT + int "The timeout for UART transfers in milliseconds, or 0 for no timeout." + default 0 config NET_PPP_ASYNC_UART_RX_RECOVERY_TIMEOUT int "UART RX recovery timeout in milliseconds" @@ -111,10 +112,6 @@ config NET_PPP_ASYNC_UART_RX_ENABLE_TIMEOUT int "A timeout for uart_rx_enable() in milliseconds" default 100 -config NET_PPP_ASYNC_UART_TX_TIMEOUT - int "A timeout for uart_tx() in milliseconds" - default 100 - endif # NET_PPP_ASYNC_UART module = NET_PPP diff --git a/drivers/net/ppp.c b/drivers/net/ppp.c index 1d9bb9fd96a..70fbe9631a5 100644 --- a/drivers/net/ppp.c +++ b/drivers/net/ppp.c @@ -126,9 +126,29 @@ static void uart_callback(const struct device *dev, break; case UART_TX_ABORTED: - LOG_DBG("Tx aborted"); + { k_sem_give(&uarte_tx_finished); + if (CONFIG_NET_PPP_ASYNC_UART_TX_TIMEOUT == 0) { + LOG_WRN("UART TX aborted."); + break; + } + struct uart_config uart_conf; + + err = uart_config_get(dev, &uart_conf); + if (err) { + LOG_ERR("uart_config_get() err: %d", err); + } else if (uart_conf.baudrate / 10 * CONFIG_NET_PPP_ASYNC_UART_TX_TIMEOUT + / MSEC_PER_SEC > evt->data.tx.len * 2) { + /* The abort likely did not happen because of missing bandwidth. */ + LOG_DBG("UART_TX_ABORTED"); + } else { + LOG_WRN("UART TX aborted: Only %zu bytes were sent. You may want" + " to change either CONFIG_NET_PPP_ASYNC_UART_TX_TIMEOUT" + " (%d ms) or the UART baud rate (%u).", evt->data.tx.len, + CONFIG_NET_PPP_ASYNC_UART_TX_TIMEOUT, uart_conf.baudrate); + } break; + } case UART_RX_RDY: len = evt->data.rx.len; @@ -368,11 +388,13 @@ static int ppp_send_flush(struct ppp_driver_context *ppp, int off) } else if (IS_ENABLED(CONFIG_NET_PPP_ASYNC_UART)) { #if defined(CONFIG_NET_PPP_ASYNC_UART) int ret; + const int32_t timeout = CONFIG_NET_PPP_ASYNC_UART_TX_TIMEOUT + ? CONFIG_NET_PPP_ASYNC_UART_TX_TIMEOUT * USEC_PER_MSEC + : SYS_FOREVER_US; k_sem_take(&uarte_tx_finished, K_FOREVER); - ret = uart_tx(ppp->dev, buf, off, - CONFIG_NET_PPP_ASYNC_UART_TX_TIMEOUT * USEC_PER_MSEC); + ret = uart_tx(ppp->dev, buf, off, timeout); if (ret) { LOG_ERR("uart_tx() failed, err %d", ret); k_sem_give(&uarte_tx_finished); From 640a493c1d5c1e87a4bd61057e9610815ab7aecc Mon Sep 17 00:00:00 2001 From: HaiLong Yang Date: Thu, 14 Dec 2023 11:03:40 +0800 Subject: [PATCH 1340/3723] drivers: adc: stm32 adc support h7 dual core lines For STM32H7 dual core lines, M4 can not access to linear calib addr ADC_LINEAR_CALIB_REG_1_ADDR. Signed-off-by: HaiLong Yang --- drivers/adc/adc_stm32.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/drivers/adc/adc_stm32.c b/drivers/adc/adc_stm32.c index 7c97958c8f2..f456c78acb6 100644 --- a/drivers/adc/adc_stm32.c +++ b/drivers/adc/adc_stm32.c @@ -567,7 +567,8 @@ static int adc_stm32_calibrate(const struct device *dev) adc_stm32_calibration_start(dev); #endif /* DT_HAS_COMPAT_STATUS_OKAY(st_stm32f1_adc) */ -#ifdef CONFIG_SOC_SERIES_STM32H7X +#if defined(CONFIG_SOC_SERIES_STM32H7X) && \ + defined(CONFIG_CPU_CORTEX_M7) /* * To ensure linearity the factory calibration values * should be loaded on initialization. From fe70e50d412cd470b301ccfda9ff07835f17219b Mon Sep 17 00:00:00 2001 From: Pavel Vasilyev Date: Mon, 11 Dec 2023 23:29:36 +0100 Subject: [PATCH 1341/3723] Bluetooth: Mesh: Added support for randomly delaying publications The section 3.7.3.1 of the mesh specification recommends to delay a message publication in certain cases: - at power-up or upon state change for a time between 20 to 500 ms - for periodic publications for a time between 20 to 50 ms This change implements this recommendation by adding the `CONFIG_BT_MESH_DELAYABLE_PUBLICATION` Kconfig option which enables the randomization code and by adding the `bt_mesh_model_pub.delayable` bit field which allows each model decide whether the publications should be delayed for this model or not. Signed-off-by: Pavel Vasilyev --- .../bluetooth/api/mesh/access.rst | 15 ++ include/zephyr/bluetooth/mesh/access.h | 2 + subsys/bluetooth/mesh/Kconfig | 9 + subsys/bluetooth/mesh/access.c | 91 ++++++++- tests/bsim/bluetooth/mesh/src/test_access.c | 176 ++++++++++++++++-- .../access/access_period_delayable.sh | 17 ++ .../access/access_transmit_delayable.sh | 17 ++ 7 files changed, 311 insertions(+), 16 deletions(-) create mode 100755 tests/bsim/bluetooth/mesh/tests_scripts/access/access_period_delayable.sh create mode 100755 tests/bsim/bluetooth/mesh/tests_scripts/access/access_transmit_delayable.sh diff --git a/doc/connectivity/bluetooth/api/mesh/access.rst b/doc/connectivity/bluetooth/api/mesh/access.rst index 7030a3c14b2..cb02028b697 100644 --- a/doc/connectivity/bluetooth/api/mesh/access.rst +++ b/doc/connectivity/bluetooth/api/mesh/access.rst @@ -255,6 +255,21 @@ message, it will send messages with delay close to expiration to free memory. When the mesh stack is suspended or reset, messages not yet sent are removed and the :c:member:`bt_mesh_send_cb.start` callback is raised with an error code. +Delayable publications +====================== + +The delayable publication functionality implements the specification recommendations for message +publication delays in the following cases: + +* Between 20 to 500 milliseconds when the Bluetooth Mesh stack starts or when the publication is + triggered by the :c:func:`bt_mesh_model_publish` function +* Between 20 to 50 milliseconds for periodically published messages + +This feature is optional and enabled with the :kconfig:option:`CONFIG_BT_MESH_DELAYABLE_PUBLICATION` +Kconfig option. When enabled, each model can enable or disable the delayable publication by setting +the :c:member:`bt_mesh_model_pub.delayable` bit field to ``1`` or ``0`` correspondingly. This bit +field can be changed at any time. + API reference ************* diff --git a/include/zephyr/bluetooth/mesh/access.h b/include/zephyr/bluetooth/mesh/access.h index d57f30f8f05..a236ede525d 100644 --- a/include/zephyr/bluetooth/mesh/access.h +++ b/include/zephyr/bluetooth/mesh/access.h @@ -713,6 +713,8 @@ struct bt_mesh_model_pub { uint8_t period_div:4, /**< Divisor for the Period. */ count:4; /**< Transmissions left. */ + uint8_t delayable:1; /**< Use random delay for publishing. */ + uint32_t period_start; /**< Start of the current period. */ /** @brief Publication buffer, containing the publication message. diff --git a/subsys/bluetooth/mesh/Kconfig b/subsys/bluetooth/mesh/Kconfig index 807cb4d1058..3ac9954d4de 100644 --- a/subsys/bluetooth/mesh/Kconfig +++ b/subsys/bluetooth/mesh/Kconfig @@ -672,6 +672,15 @@ config BT_MESH_ACCESS_DELAYABLE_MSG_CHUNK_COUNT endif # BT_MESH_ACCESS_DELAYABLE_MSG +config BT_MESH_DELAYABLE_PUBLICATION + bool "Delayable publication" + default y + help + When enabled, the periodic publications are randomly delayed by 20 to 50ms. Publications + triggered at the start of the stack or by the bt_mesh_model_publish() call are delayed by + 20 to 500ms. This option reduces the probability of collisions when multiple nodes publish + at the same time. + endmenu # Access layer menu "Models" diff --git a/subsys/bluetooth/mesh/access.c b/subsys/bluetooth/mesh/access.c index 4cffe064329..c3ef6a40554 100644 --- a/subsys/bluetooth/mesh/access.c +++ b/subsys/bluetooth/mesh/access.c @@ -33,6 +33,11 @@ #include LOG_MODULE_REGISTER(bt_mesh_access); +/* 20 - 50ms */ +#define RANDOM_DELAY_SHORT 30 +/* 20 - 500ms */ +#define RANDOM_DELAY_LONG 480 + /* Model publication information for persistent storage. */ struct mod_pub_val { struct { @@ -761,8 +766,16 @@ static int32_t next_period(const struct bt_mesh_model *mod) if (period && elapsed >= period) { LOG_WRN("Retransmission interval is too short"); - /* Return smallest positive number since 0 means disabled */ - return 1; + + if (!!pub->delayable) { + LOG_WRN("Publication period is too short for" + " retransmissions"); + } + + /* Keep retransmitting the message with the interval sacrificing the + * next publication period start. + */ + return BT_MESH_PUB_TRANSMIT_INT(mod->pub->retransmit); } } @@ -775,6 +788,11 @@ static int32_t next_period(const struct bt_mesh_model *mod) if (elapsed >= period) { LOG_WRN("Publication sending took longer than the period"); + + if (!!pub->delayable) { + LOG_WRN("Publication period is too short to be delayable"); + } + /* Return smallest positive number since 0 means disabled */ return 1; } @@ -855,6 +873,39 @@ static int pub_period_start(struct bt_mesh_model_pub *pub) return 0; } +static uint16_t pub_delay_get(int random_delay_window) +{ + if (!IS_ENABLED(CONFIG_BT_MESH_DELAYABLE_PUBLICATION)) { + return 0; + } + + uint16_t num = 0; + + (void)bt_rand(&num, sizeof(num)); + + return 20 + (num % random_delay_window); +} + +static int pub_delay_schedule(struct bt_mesh_model_pub *pub, int delay) +{ + uint16_t random; + int err; + + if (!IS_ENABLED(CONFIG_BT_MESH_DELAYABLE_PUBLICATION)) { + return -ENOTSUP; + } + + random = pub_delay_get(delay); + err = k_work_reschedule(&pub->timer, K_MSEC(random)); + if (err < 0) { + LOG_ERR("Unable to delay publication (err %d)", err); + return err; + } + + LOG_DBG("Publication delayed by %dms", random); + return 0; +} + static void mod_publish(struct k_work *work) { struct k_work_delayable *dwork = k_work_delayable_from_work(work); @@ -890,6 +941,13 @@ static void mod_publish(struct k_work *work) if (err) { return; } + + /* Delay the first publication in a period. */ + if (!!pub->delayable && !pub_delay_schedule(pub, RANDOM_DELAY_SHORT)) { + /* Increment count as it would do BT_MESH_PUB_MSG_TOTAL */ + pub->count++; + return; + } } err = publish_transmit(pub->mod); @@ -1564,6 +1622,18 @@ int bt_mesh_model_publish(const struct bt_mesh_model *model) LOG_DBG("Publish Retransmit Count %u Interval %ums", pub->count, BT_MESH_PUB_TRANSMIT_INT(pub->retransmit)); + /* Delay the publication for longer time when the publication is triggered manually (section + * 3.7.3.1): + * + * When the publication of a message is the result of a power-up, a state transition + * progress update, or completion of a state transition, multiple nodes may be reporting the + * state change at the same time. To reduce the probability of a message collision, these + * messages should be sent with a random delay between 20 and 500 milliseconds. + */ + if (!!pub->delayable && !pub_delay_schedule(pub, RANDOM_DELAY_LONG)) { + return 0; + } + k_work_reschedule(&pub->timer, K_NO_WAIT); return 0; @@ -2568,8 +2638,21 @@ static void commit_mod(const struct bt_mesh_model *mod, const struct bt_mesh_ele int32_t ms = bt_mesh_model_pub_period_get(mod); if (ms > 0) { - LOG_DBG("Starting publish timer (period %u ms)", ms); - k_work_schedule(&mod->pub->timer, K_MSEC(ms)); + /* Delay the first publication after power-up for longer time (section + * 3.7.3.1): + * + * When the publication of a message is the result of a power-up, a state + * transition progress update, or completion of a state transition, multiple + * nodes may be reporting the state change at the same time. To reduce the + * probability of a message collision, these messages should be sent with a + * random delay between 20 and 500 milliseconds. + */ + uint16_t random; + + random = !!mod->pub->delayable ? pub_delay_get(RANDOM_DELAY_LONG) : 0; + + LOG_DBG("Starting publish timer (period %u ms, delay %u ms)", ms, random); + k_work_schedule(&mod->pub->timer, K_MSEC(ms + random)); } } diff --git a/tests/bsim/bluetooth/mesh/src/test_access.c b/tests/bsim/bluetooth/mesh/src/test_access.c index b8b10fd7634..5cb7d2e28e1 100644 --- a/tests/bsim/bluetooth/mesh/src/test_access.c +++ b/tests/bsim/bluetooth/mesh/src/test_access.c @@ -60,6 +60,7 @@ static const struct { uint8_t div; int32_t period_ms; } test_period[] = { + { BT_MESH_PUB_PERIOD_100MS(1), 0, 100 }, { BT_MESH_PUB_PERIOD_100MS(5), 0, 500 }, { BT_MESH_PUB_PERIOD_SEC(2), 0, 2000 }, { BT_MESH_PUB_PERIOD_10SEC(1), 0, 10000 }, @@ -522,6 +523,91 @@ static void msgf_publish(void) bt_mesh_model_publish(model); } +static void pub_delayable_check(int32_t interval, uint8_t count) +{ + int64_t timestamp = k_uptime_get(); + int err; + + for (size_t j = 0; j < count; j++) { + /* Every new publication will release semaphore in the update handler and the time + * between two consecutive publications will be measured. + */ + err = k_sem_take(&publish_sem, K_SECONDS(20)); + if (err) { + FAIL("Send timed out"); + } + + int32_t time_delta = k_uptime_delta(×tamp); + int32_t pub_delta = time_delta - interval; + + LOG_DBG("Send time: %d delta: %d pub_delta: %d", (int32_t)timestamp, time_delta, + pub_delta); + + if (j == 0) { + /* The first delta will be between the messages published manually and next + * publication (or retransmission). So the time difference should not be + * longer than 500 - 20 + 10 (margin): + * + * |---|-------|--------|-------|----> + * M1 20ms tx(M1) 500ms + * update() + */ + ASSERT_IN_RANGE(pub_delta, 0, 510); + } else { + /* Time difference between the consequtive update callback calls should be + * within a small margin like without random delay as the callbacks should + * be called at the regular interval or immediately (if it passed the next + * period time). + */ + ASSERT_IN_RANGE(pub_delta, 0, 10); + } + } +} + +static void recv_delayable_check(int32_t interval, uint8_t count) +{ + int64_t timestamp; + int err; + + /* The measurement starts by the first received message. */ + err = k_sem_take(&publish_sem, K_SECONDS(20)); + if (err) { + FAIL("Recv timed out"); + } + + timestamp = k_uptime_get(); + + for (size_t j = 0; j < count; j++) { + /* Every new received message will release semaphore in the message handler and + * the time between two consecutive publications will be measured. + */ + err = k_sem_take(&publish_sem, K_SECONDS(20)); + if (err) { + FAIL("Recv timed out"); + } + + int32_t time_delta = k_uptime_delta(×tamp); + /* First message can be delayed up to 500ms, others for up to 50ms. */ + int32_t upper_delay = j == 0 ? 500 : 50; + + /* + * Lower boundary: tx2 - tx1 + interval + * |---|-------|---------------|-------|-----> + * M1 tx1(50ms/500ms) M2 tx2(20ms) + * + * Upper boundary: tx2 - tx1 + interval + * |---|-------|--------|-----------|-----> + * M1 tx1(20ms) M2 tx2(50ms/500ms) + */ + int32_t lower_boundary = 20 - upper_delay + interval; + int32_t upper_boundary = upper_delay - 20 + interval; + + LOG_DBG("Recv time: %d delta: %d boundaries: %d/%d", (int32_t)timestamp, time_delta, + lower_boundary, upper_boundary); + ASSERT_IN_RANGE(time_delta, lower_boundary, upper_boundary + RX_JITTER_MAX); + } +} + static void pub_jitter_check(int32_t interval, uint8_t count) { int64_t timestamp = k_uptime_get(); @@ -578,8 +664,8 @@ static void recv_jitter_check(int32_t interval, uint8_t count) jitter = MAX(pub_delta, jitter); - LOG_DBG("Recv time: %d delta: %d jitter: %d", (int32_t)timestamp, time_delta, - jitter); + LOG_DBG("Recv time: %d delta: %d jitter: %d, j: %d", (int32_t)timestamp, time_delta, + jitter, j); } LOG_INF("Recv jitter: %d", jitter); @@ -589,17 +675,19 @@ static void recv_jitter_check(int32_t interval, uint8_t count) /* Test publish period states by publishing a message and checking interval between update handler * calls. */ -static void test_tx_period(void) +static void tx_period(bool delayable) { const struct bt_mesh_model *model = &models[2]; - bt_mesh_test_cfg_set(NULL, 60); + bt_mesh_test_cfg_set(NULL, 70); bt_mesh_device_setup(&prov, &local_comp); provision(UNICAST_ADDR1); common_configure(UNICAST_ADDR1); k_sem_init(&publish_sem, 0, 1); + model->pub->delayable = delayable; + for (size_t i = 0; i < ARRAY_SIZE(test_period); i++) { pub_param_set(test_period[i].period, 0); @@ -611,7 +699,11 @@ static void test_tx_period(void) /* Start publishing messages and measure jitter. */ msgf_publish(); publish_allow = true; - pub_jitter_check(test_period[i].period_ms, PUB_PERIOD_COUNT); + if (delayable) { + pub_delayable_check(test_period[i].period_ms, PUB_PERIOD_COUNT); + } else { + pub_jitter_check(test_period[i].period_ms, PUB_PERIOD_COUNT); + } /* Disable periodic publication before the next test iteration. */ publish_allow = false; @@ -626,9 +718,9 @@ static void test_tx_period(void) /* Receive a periodically published message and check publication period by measuring interval * between message handler calls. */ -static void test_rx_period(void) +static void rx_period(bool delayable) { - bt_mesh_test_cfg_set(NULL, 60); + bt_mesh_test_cfg_set(NULL, 70); bt_mesh_device_setup(&prov, &local_comp); provision(UNICAST_ADDR2); common_configure(UNICAST_ADDR2); @@ -636,16 +728,40 @@ static void test_rx_period(void) k_sem_init(&publish_sem, 0, 1); for (size_t i = 0; i < ARRAY_SIZE(test_period); i++) { - recv_jitter_check(test_period[i].period_ms, PUB_PERIOD_COUNT); + if (delayable) { + recv_delayable_check(test_period[i].period_ms, PUB_PERIOD_COUNT); + } else { + recv_jitter_check(test_period[i].period_ms, PUB_PERIOD_COUNT); + } } PASS(); } +static void test_tx_period(void) +{ + tx_period(false); +} + +static void test_rx_period(void) +{ + rx_period(false); +} + +static void test_tx_period_delayable(void) +{ + tx_period(true); +} + +static void test_rx_period_delayable(void) +{ + rx_period(true); +} + /* Test publish retransmit interval and count states by publishing a message and checking interval * between update handler calls. */ -static void test_tx_transmit(void) +static void tx_transmit(bool delayable) { const struct bt_mesh_model *model = &models[2]; uint8_t status; @@ -672,6 +788,7 @@ static void test_tx_transmit(void) publish_allow = true; model->pub->retr_update = true; + model->pub->delayable = delayable; for (size_t i = 0; i < ARRAY_SIZE(test_transmit); i++) { pub_param_set(0, test_transmit[i]); @@ -683,7 +800,11 @@ static void test_tx_transmit(void) /* Start publishing messages and measure jitter. */ msgf_publish(); - pub_jitter_check(interval, count); + if (delayable) { + pub_delayable_check(interval, count); + } else { + pub_jitter_check(interval, count); + } /* Let the receiver hit the first semaphore. */ k_sleep(K_SECONDS(1)); @@ -695,7 +816,7 @@ static void test_tx_transmit(void) /* Receive a published message and check retransmission interval by measuring interval between * message handler calls. */ -static void test_rx_transmit(void) +static void rx_transmit(bool delayable) { bt_mesh_test_cfg_set(NULL, 60); bt_mesh_device_setup(&prov, &local_comp); @@ -708,12 +829,36 @@ static void test_rx_transmit(void) int32_t interval = BT_MESH_PUB_TRANSMIT_INT(test_transmit[i]); int count = BT_MESH_PUB_TRANSMIT_COUNT(test_transmit[i]); - recv_jitter_check(interval, count); + if (delayable) { + recv_delayable_check(interval, count); + } else { + recv_jitter_check(interval, count); + } } PASS(); } +static void test_tx_transmit(void) +{ + tx_transmit(false); +} + +static void test_rx_transmit(void) +{ + rx_transmit(false); +} + +static void test_tx_transmit_delayable(void) +{ + tx_transmit(true); +} + +static void test_rx_transmit_delayable(void) +{ + rx_transmit(true); +} + /* Cancel one of messages to be published and check that the next one is published when next period * starts. */ @@ -841,6 +986,13 @@ static const struct bst_test_instance test_access[] = { TEST_CASE(tx, cancel, "Access: Cancel a message during publication"), TEST_CASE(rx, cancel, "Access: Receive published messages except cancelled"), + TEST_CASE(tx, period_delayable, "Access: Test delayable periodic publication"), + TEST_CASE(rx, period_delayable, "Access: Receive delayable periodic publication"), + + TEST_CASE(tx, transmit_delayable, "Access: Test delayable publication with retransmission"), + TEST_CASE(rx, transmit_delayable, "Access: Receive delayable publication with" + " retransmissions"), + BSTEST_END_MARKER }; diff --git a/tests/bsim/bluetooth/mesh/tests_scripts/access/access_period_delayable.sh b/tests/bsim/bluetooth/mesh/tests_scripts/access/access_period_delayable.sh new file mode 100755 index 00000000000..5ecd4a061de --- /dev/null +++ b/tests/bsim/bluetooth/mesh/tests_scripts/access/access_period_delayable.sh @@ -0,0 +1,17 @@ +#!/usr/bin/env bash +# Copyright 2023 Nordic Semiconductor +# SPDX-License-Identifier: Apache-2.0 + +source $(dirname "${BASH_SOURCE[0]}")/../../_mesh_test.sh + +RunTest mesh_access_pub_period_delayable_retr \ + access_tx_period_delayable access_rx_period_delayable + +conf=prj_mesh1d1_conf +RunTest mesh_access_pub_period_delayable_retr_1d1 \ + access_tx_period_delayable access_rx_period_delayable + +conf=prj_mesh1d1_conf +overlay=overlay_psa_conf +RunTest mesh_access_pub_period_delayable_retr_psa \ + access_tx_period_delayable access_rx_period_delayable diff --git a/tests/bsim/bluetooth/mesh/tests_scripts/access/access_transmit_delayable.sh b/tests/bsim/bluetooth/mesh/tests_scripts/access/access_transmit_delayable.sh new file mode 100755 index 00000000000..1622ac49f06 --- /dev/null +++ b/tests/bsim/bluetooth/mesh/tests_scripts/access/access_transmit_delayable.sh @@ -0,0 +1,17 @@ +#!/usr/bin/env bash +# Copyright 2023 Nordic Semiconductor +# SPDX-License-Identifier: Apache-2.0 + +source $(dirname "${BASH_SOURCE[0]}")/../../_mesh_test.sh + +RunTest mesh_access_pub_transmit_delayable_retr \ + access_tx_transmit_delayable access_rx_transmit_delayable + +conf=prj_mesh1d1_conf +RunTest mesh_access_pub_transmit_delayable_retr_1d1 \ + access_tx_transmit_delayable access_rx_transmit_delayable + +conf=prj_mesh1d1_conf +overlay=overlay_psa_conf +RunTest mesh_access_pub_transmit_delayable_retr_psa \ + access_tx_period_delayable access_rx_period_delayable From 6c67ab3a637ea44bf815faffbe6fe083d5508aa3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Anders=20Storr=C3=B8?= Date: Wed, 6 Dec 2023 13:59:39 +0100 Subject: [PATCH 1342/3723] Bluetooth: Mesh: Refactor proxy adv MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Refactors proxy advertising implementation to allow fair sharing of advertising resources between all subnets. In the new implementation, each subnet is agnostic to any other subnet that might have active proxy advertisement work. When proxy advertisement is triggered, the implementation will first check how many subnets that has active work. If there are more than one active subnet, a maximum timeslot will be calculated to ensure that all active subnets get access to the medium. The implementation will then poll the next eligible subnet for a proxy advertising request. If the duration of this request exceeds the maximum timeslot, the duration for the next advertisement will be set to the maximum value. If a proxy advertisement for a subnet is interrupted by other advertising activity, the implementation will now ensure that the interrupted proxy adv continues from the point where it was interrupted so that the subnet gets to utilize the entire allocated timeslot. This PR also alters the priv_proxy_net_id_multi Bsim test to align with the refactored proxy advertising scheme. Signed-off-by: Anders Storrø --- subsys/bluetooth/mesh/proxy_srv.c | 332 +++++++++++--------- tests/bsim/bluetooth/mesh/src/test_beacon.c | 10 +- 2 files changed, 190 insertions(+), 152 deletions(-) diff --git a/subsys/bluetooth/mesh/proxy_srv.c b/subsys/bluetooth/mesh/proxy_srv.c index 45e29915325..9cad9e2fe04 100644 --- a/subsys/bluetooth/mesh/proxy_srv.c +++ b/subsys/bluetooth/mesh/proxy_srv.c @@ -625,7 +625,7 @@ static int net_id_adv(struct bt_mesh_subnet *sub, int32_t duration) return 0; } -static bool advertise_subnet(struct bt_mesh_subnet *sub) +static bool is_sub_proxy_active(struct bt_mesh_subnet *sub) { if (sub->net_idx == BT_MESH_KEY_UNUSED) { return false; @@ -633,44 +633,18 @@ static bool advertise_subnet(struct bt_mesh_subnet *sub) return (sub->node_id == BT_MESH_NODE_IDENTITY_RUNNING || #if defined(CONFIG_BT_MESH_OD_PRIV_PROXY_SRV) - sub->solicited || + (bt_mesh_od_priv_proxy_get() > 0 && sub->solicited) || #endif bt_mesh_gatt_proxy_get() == BT_MESH_GATT_PROXY_ENABLED || bt_mesh_priv_gatt_proxy_get() == BT_MESH_GATT_PROXY_ENABLED); } -static struct bt_mesh_subnet *next_sub(void) +static bool active_proxy_sub_cnt_cb(struct bt_mesh_subnet *sub, void *cb_data) { - struct bt_mesh_subnet *sub = NULL; + int *cnt = cb_data; - if (!beacon_sub) { - beacon_sub = bt_mesh_subnet_next(NULL); - if (!beacon_sub) { - /* No valid subnets */ - return NULL; - } - } - - sub = beacon_sub; - do { - if (advertise_subnet(sub)) { - beacon_sub = sub; - return sub; - } - - sub = bt_mesh_subnet_next(sub); - } while (sub != beacon_sub); - - /* No subnets to advertise on */ - return NULL; -} - -static bool sub_count_cb(struct bt_mesh_subnet *sub, void *cb_data) -{ - int *count = cb_data; - - if (advertise_subnet(sub)) { - (*count)++; + if (is_sub_proxy_active(sub)) { + (*cnt)++; } /* Don't stop until we've visited all subnets. @@ -679,155 +653,225 @@ static bool sub_count_cb(struct bt_mesh_subnet *sub, void *cb_data) return false; } -static int sub_count(void) +static int active_proxy_sub_cnt_get(void) { - int count = 0; + int cnt = 0; - (void)bt_mesh_subnet_find(sub_count_cb, &count); + (void)bt_mesh_subnet_find(active_proxy_sub_cnt_cb, &cnt); - return count; + return cnt; } -#if defined(CONFIG_BT_MESH_OD_PRIV_PROXY_SRV) -static void gatt_proxy_solicited(struct bt_mesh_subnet *sub) +static void proxy_adv_timeout_eval(struct bt_mesh_subnet *sub) { - int64_t now = k_uptime_get(); - int64_t timeout = 0; - int32_t remaining; - - if (sub->priv_net_id_sent > 0) { - timeout = sub->priv_net_id_sent + - MSEC_PER_SEC * (int64_t) bt_mesh_od_priv_proxy_get(); - remaining = MIN(timeout - now, INT32_MAX); - } else { - remaining = MSEC_PER_SEC * bt_mesh_od_priv_proxy_get(); + int32_t time_passed; + + if (sub->node_id == BT_MESH_NODE_IDENTITY_RUNNING) { + time_passed = k_uptime_get_32() - sub->node_id_start; + if (time_passed > (NODE_ID_TIMEOUT - MSEC_PER_SEC)) { + bt_mesh_proxy_identity_stop(sub); + LOG_DBG("Node ID stopped for subnet %d after %dms", sub->net_idx, + time_passed); + } } - if ((timeout > 0 && now > timeout) || (remaining / MSEC_PER_SEC < 1)) { - LOG_DBG("Advertising Private Network ID timed out " - "after solicitation"); - sub->priv_net_id_sent = 0; - sub->solicited = false; - } else { - LOG_DBG("Advertising Private Network ID for %ds" - "(%d remaining)", - bt_mesh_od_priv_proxy_get(), - remaining / MSEC_PER_SEC); - priv_net_id_adv(sub, remaining); - - if (!sub->priv_net_id_sent) { - sub->priv_net_id_sent = now; +#if defined(CONFIG_BT_MESH_OD_PRIV_PROXY_SRV) + if (bt_mesh_od_priv_proxy_get() > 0 && sub->solicited && sub->priv_net_id_sent) { + time_passed = k_uptime_get_32() - sub->priv_net_id_sent; + if (time_passed > ((MSEC_PER_SEC * bt_mesh_od_priv_proxy_get()) - MSEC_PER_SEC)) { + sub->priv_net_id_sent = 0; + sub->solicited = false; + LOG_DBG("Private Network ID stopped for subnet %d after %dms on " + "solicitation", + sub->net_idx, time_passed); } } +#endif } + +enum proxy_adv_evt { + NET_ID, + PRIV_NET_ID, + NODE_ID, + PRIV_NODE_ID, + OD_PRIV_NET_ID, +}; + +struct proxy_adv_request { + int32_t duration; + enum proxy_adv_evt evt; +}; + +static bool proxy_adv_request_get(struct bt_mesh_subnet *sub, struct proxy_adv_request *request) +{ + if (!sub) { + return false; + } + + if (sub->net_idx == BT_MESH_KEY_UNUSED) { + return false; + } + +#if defined(CONFIG_BT_MESH_OD_PRIV_PROXY_SRV) + if (bt_mesh_od_priv_proxy_get() > 0 && sub->solicited) { + int32_t timeout = MSEC_PER_SEC * (int32_t)bt_mesh_od_priv_proxy_get(); + + request->evt = OD_PRIV_NET_ID; + request->duration = !sub->priv_net_id_sent + ? timeout + : timeout - (k_uptime_get_32() - sub->priv_net_id_sent); + return true; + } #endif -static int gatt_proxy_advertise(struct bt_mesh_subnet *sub) + if (sub->node_id == BT_MESH_NODE_IDENTITY_RUNNING) { + request->duration = NODE_ID_TIMEOUT - (k_uptime_get_32() - sub->node_id_start); + request->evt = +#if defined(CONFIG_BT_MESH_PRIV_BEACONS) + sub->priv_beacon_ctx.node_id ? PRIV_NODE_ID : +#endif + NODE_ID; + + return true; + } + + if (bt_mesh_priv_gatt_proxy_get() == BT_MESH_FEATURE_ENABLED) { + request->evt = PRIV_NET_ID; + request->duration = PROXY_RANDOM_UPDATE_INTERVAL; + return true; + } + + if (bt_mesh_gatt_proxy_get() == BT_MESH_FEATURE_ENABLED) { + request->evt = NET_ID; + request->duration = SYS_FOREVER_MS; + return true; + } + + return false; +} + +static struct bt_mesh_subnet *adv_sub_get_next(struct bt_mesh_subnet *sub_start, + struct proxy_adv_request *request) { - int32_t remaining = SYS_FOREVER_MS; - int subnet_count; - int err = -EBUSY; - bool planned = false; + struct bt_mesh_subnet *sub_temp = sub_start; + + do { + if (proxy_adv_request_get(sub_temp, request)) { + return sub_temp; + } + + sub_temp = bt_mesh_subnet_next(sub_temp); + } while (sub_temp != sub_start); + + return NULL; +} + +static struct { + int32_t start; + struct bt_mesh_subnet *sub; + struct proxy_adv_request request; +} sub_adv; + +static int gatt_proxy_advertise(void) +{ + int err; + + int32_t max_adv_duration; + int cnt; + struct bt_mesh_subnet *sub; + struct proxy_adv_request request; LOG_DBG(""); + /* Close proxy activity that has timed out on all subnets */ + bt_mesh_subnet_foreach(proxy_adv_timeout_eval); + if (!bt_mesh_proxy_has_avail_conn()) { LOG_DBG("Connectable advertising deferred (max connections)"); return -ENOMEM; } - sub = beacon_sub ? beacon_sub : bt_mesh_subnet_next(beacon_sub); - if (!sub) { - LOG_WRN("No subnets to advertise on"); + cnt = active_proxy_sub_cnt_get(); + if (!cnt) { + LOG_DBG("No subnets to advertise proxy on"); return -ENOENT; - } - - subnet_count = sub_count(); - LOG_DBG("sub_count %u", subnet_count); - if (subnet_count > 1) { - int32_t max_timeout; + } else if (cnt > 1) { + /** There is more than one subnet that requires proxy adv, + * and the adv resources must be shared. + */ /* We use NODE_ID_TIMEOUT as a starting point since it may * be less than 60 seconds. Divide this period into at least - * 6 slices, but make sure that a slice is at least one + * 6 slices, but make sure that a slice is more than one * second long (to avoid excessive rotation). */ - max_timeout = NODE_ID_TIMEOUT / MAX(subnet_count, 6); - max_timeout = MAX(max_timeout, 1 * MSEC_PER_SEC); - - if (remaining > max_timeout || remaining == SYS_FOREVER_MS) { - remaining = max_timeout; + max_adv_duration = NODE_ID_TIMEOUT / MAX(cnt, 6); + max_adv_duration = MAX(max_adv_duration, MSEC_PER_SEC + 20); + + /* Check if the previous subnet finished its allocated timeslot */ + if ((sub_adv.request.duration != SYS_FOREVER_MS) && + proxy_adv_request_get(sub_adv.sub, &request) && + (sub_adv.request.evt == request.evt)) { + int32_t time_passed = k_uptime_get_32() - sub_adv.start; + + if (time_passed < sub_adv.request.duration && + ((sub_adv.request.duration - time_passed) >= MSEC_PER_SEC)) { + sub = sub_adv.sub; + request.duration = sub_adv.request.duration - time_passed; + goto end; + } } } - for (int i = 0; i < subnet_count; i++) { - - if (sub->node_id == BT_MESH_NODE_IDENTITY_RUNNING) { - uint32_t active = k_uptime_get_32() - sub->node_id_start; - bool priv_node_id = false; - - if (active < NODE_ID_TIMEOUT) { - remaining = MIN(remaining, NODE_ID_TIMEOUT - active); - LOG_DBG("Node ID active for %u ms, %d ms remaining", - active, remaining); -#if defined(CONFIG_BT_MESH_PRIV_BEACONS) - priv_node_id = sub->priv_beacon_ctx.node_id; -#endif - if (priv_node_id) { - err = priv_node_id_adv(sub, remaining); - } else { - err = node_id_adv(sub, remaining); - } - planned = true; - } else { - bt_mesh_proxy_identity_stop(sub); - LOG_DBG("Node ID stopped"); - } - } + sub = adv_sub_get_next(bt_mesh_subnet_next(sub_adv.sub), &request); + if (!sub) { + LOG_ERR("Could not find subnet to advertise"); + return -ENOENT; + } +end: + if (cnt > 1) { + request.duration = (request.duration == SYS_FOREVER_MS) + ? max_adv_duration + : MIN(request.duration, max_adv_duration); + } - /* MshPRTv1.1: section 7.2.2.2.1: - * "A node that does not support the Proxy feature or - * has the GATT Proxy state disabled shall not advertise with Network ID." - */ - if (sub->node_id == BT_MESH_NODE_IDENTITY_STOPPED) { - if (IS_ENABLED(CONFIG_BT_MESH_PRIV_BEACONS) && - (bt_mesh_priv_gatt_proxy_get() == BT_MESH_GATT_PROXY_ENABLED)) { - /* MshPRTv1.1: 7.2.2.2.4: The Random - * field should be updated every 10 minutes. Limit advertising to - * 10 minutes to ensure regeneration of a new random value at least - * that often. - */ - if (remaining == SYS_FOREVER_MS || - remaining > PROXY_RANDOM_UPDATE_INTERVAL) { - remaining = PROXY_RANDOM_UPDATE_INTERVAL; - } - - err = priv_net_id_adv(sub, remaining); - planned = true; - } else if (bt_mesh_gatt_proxy_get() == BT_MESH_FEATURE_ENABLED) { - err = net_id_adv(sub, remaining); - planned = true; - } + /* Save current state for next iteration */ + sub_adv.start = k_uptime_get_32(); + sub_adv.sub = sub; + sub_adv.request = request; + switch (request.evt) { + case NET_ID: + err = net_id_adv(sub, request.duration); + break; #if defined(CONFIG_BT_MESH_OD_PRIV_PROXY_SRV) - else if (bt_mesh_od_priv_proxy_get() > 0 && - sub->solicited) { - gatt_proxy_solicited(sub); - } -#endif - } - - beacon_sub = bt_mesh_subnet_next(sub); - - if (planned) { - LOG_DBG("Advertising %d ms for net_idx 0x%04x", remaining, sub->net_idx); - return err; + case OD_PRIV_NET_ID: + if (!sub->priv_net_id_sent) { + sub->priv_net_id_sent = k_uptime_get(); } + /* Fall through */ +#endif + case PRIV_NET_ID: + err = priv_net_id_adv(sub, request.duration); + break; + case NODE_ID: + err = node_id_adv(sub, request.duration); + break; + case PRIV_NODE_ID: + err = priv_node_id_adv(sub, request.duration); + break; + default: + LOG_ERR("Unexpected proxy adv evt: %d", request.evt); + return -ENODEV; + } - sub = beacon_sub; + if (err) { + LOG_ERR("Advertising proxy failed (err: %d)", err); + return err; } - return 0; + LOG_DBG("Advertising %d ms for net_idx 0x%04x", request.duration, sub->net_idx); + return err; } static void subnet_evt(struct bt_mesh_subnet *sub, enum bt_mesh_key_evt evt) @@ -1152,7 +1196,7 @@ int bt_mesh_proxy_adv_start(void) return -ENOTSUP; } - return gatt_proxy_advertise(next_sub()); + return gatt_proxy_advertise(); } BT_CONN_CB_DEFINE(conn_callbacks) = { diff --git a/tests/bsim/bluetooth/mesh/src/test_beacon.c b/tests/bsim/bluetooth/mesh/src/test_beacon.c index 038c705f2cb..f9230a397a9 100644 --- a/tests/bsim/bluetooth/mesh/src/test_beacon.c +++ b/tests/bsim/bluetooth/mesh/src/test_beacon.c @@ -1763,12 +1763,6 @@ static void test_tx_priv_multi_net_id(void) { tx_priv_common_init(PP_MULT_NET_ID_WAIT_TIME); - /* TODO: This should be removed as soon as - * SNB/proxy service advertising issue has - * been resolved. - */ - bt_mesh_beacon_set(false); - /* Add second network */ ASSERT_OK_MSG(bt_mesh_subnet_add(TEST_NET_IDX2, test_net_key_secondary), "Failed to add second subnet"); @@ -1819,8 +1813,8 @@ static void test_rx_priv_multi_net_id(void) /* Verify last Net ID adv result */ ASSERT_IN_RANGE(k_uptime_get() - net_ctx[old_idx].start, - MAX_TIMEOUT - 1000, MAX_TIMEOUT); - ASSERT_IN_RANGE(net_ctx[old_idx].recv_cnt, 9, 10); + MAX_TIMEOUT - 1000, MAX_TIMEOUT + 1000); + ASSERT_IN_RANGE(net_ctx[old_idx].recv_cnt, 9, 12); net_ctx[old_idx].recv_cnt = 0; old_idx = i; From f70929a8f12214de7dc7e1fe52a8d696bfc7f55f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Anders=20Storr=C3=B8?= Date: Wed, 6 Dec 2023 13:59:39 +0100 Subject: [PATCH 1343/3723] tests: Bluetooth: Mesh: Add proxy adv coex test. MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Adds test that verifies correct Proxy advertisement behavior for a device where the Proxy adv requirements changes over time, both for single and multiple subnets. Signed-off-by: Anders Storrø --- subsys/bluetooth/mesh/proxy_srv.c | 11 +- tests/bsim/bluetooth/mesh/overlay_gatt.conf | 1 + tests/bsim/bluetooth/mesh/src/test_beacon.c | 366 ++++++++++++++++-- .../proxy_adv_multi_subnet_coex.sh | 54 +++ 4 files changed, 397 insertions(+), 35 deletions(-) create mode 100755 tests/bsim/bluetooth/mesh/tests_scripts/priv_beacon/proxy_adv_multi_subnet_coex.sh diff --git a/subsys/bluetooth/mesh/proxy_srv.c b/subsys/bluetooth/mesh/proxy_srv.c index 9cad9e2fe04..25a44abfded 100644 --- a/subsys/bluetooth/mesh/proxy_srv.c +++ b/subsys/bluetooth/mesh/proxy_srv.c @@ -712,6 +712,13 @@ static bool proxy_adv_request_get(struct bt_mesh_subnet *sub, struct proxy_adv_r return false; } + /** The priority for proxy adv is first solicitation, then Node Identity, + * and lastly Network ID. Network ID is prioritized last since, in many + * cases, another device can fulfill the same demand. Solicitation is + * prioritized first since legacy devices are dependent on this to + * connect to the network. + */ + #if defined(CONFIG_BT_MESH_OD_PRIV_PROXY_SRV) if (bt_mesh_od_priv_proxy_get() > 0 && sub->solicited) { int32_t timeout = MSEC_PER_SEC * (int32_t)bt_mesh_od_priv_proxy_get(); @@ -753,7 +760,7 @@ static bool proxy_adv_request_get(struct bt_mesh_subnet *sub, struct proxy_adv_r static struct bt_mesh_subnet *adv_sub_get_next(struct bt_mesh_subnet *sub_start, struct proxy_adv_request *request) { - struct bt_mesh_subnet *sub_temp = sub_start; + struct bt_mesh_subnet *sub_temp = bt_mesh_subnet_next(sub_start); do { if (proxy_adv_request_get(sub_temp, request)) { @@ -823,7 +830,7 @@ static int gatt_proxy_advertise(void) } } - sub = adv_sub_get_next(bt_mesh_subnet_next(sub_adv.sub), &request); + sub = adv_sub_get_next(sub_adv.sub, &request); if (!sub) { LOG_ERR("Could not find subnet to advertise"); return -ENOENT; diff --git a/tests/bsim/bluetooth/mesh/overlay_gatt.conf b/tests/bsim/bluetooth/mesh/overlay_gatt.conf index f94a26d623f..7660313b700 100644 --- a/tests/bsim/bluetooth/mesh/overlay_gatt.conf +++ b/tests/bsim/bluetooth/mesh/overlay_gatt.conf @@ -6,3 +6,4 @@ CONFIG_BT_MESH_LOW_POWER=n CONFIG_BT_MESH_FRIEND=n CONFIG_BT_CENTRAL=y CONFIG_BT_MESH_PROXY_CLIENT=y +CONFIG_BT_MESH_PROXY_SOLICITATION=y diff --git a/tests/bsim/bluetooth/mesh/src/test_beacon.c b/tests/bsim/bluetooth/mesh/src/test_beacon.c index f9230a397a9..e5f7d515da7 100644 --- a/tests/bsim/bluetooth/mesh/src/test_beacon.c +++ b/tests/bsim/bluetooth/mesh/src/test_beacon.c @@ -31,7 +31,7 @@ LOG_MODULE_REGISTER(LOG_MODULE_NAME, LOG_LEVEL_INF); #define BEACON_TYPE_PRIVATE 0x02 #endif -static uint8_t test_net_key_secondary[16] = { 0xca, 0x11, 0xab, 0x1e }; +static uint8_t test_net_key_2[16] = { 0xca, 0x11, 0xab, 0x1e }; static struct { uint8_t primary[16]; uint8_t secondary[16]; @@ -334,6 +334,7 @@ static struct { uint8_t random[13]; uint64_t pp_hash; uint64_t pp_random; + uint64_t net_id; bt_addr_le_t adv_addr; #endif bool (*process_cb)(const uint8_t *net_id, void *ctx); @@ -625,7 +626,7 @@ static void test_tx_kr_old_key(void) * the new Net Key. The node shall set Key Refresh phase to 2. The beacon interval shall * be increased. */ - beacon_create(&buf, test_net_key_secondary, 0x03, 0x0001); + beacon_create(&buf, test_net_key_2, 0x03, 0x0001); send_beacon(&buf); ASSERT_FALSE(wait_for_beacon(beacon_scan_cb, BEACON_INTERVAL + 1, NULL, NULL)); ASSERT_TRUE(wait_for_beacon(beacon_scan_cb, BEACON_INTERVAL + 1, NULL, NULL)); @@ -645,7 +646,7 @@ static void test_tx_kr_old_key(void) /* Try the same with the new Net Key. Now the node shall change Key Refresh phase to 0. The * beacon interval shall be increased. */ - beacon_create(&buf, test_net_key_secondary, 0x02, 0x0001); + beacon_create(&buf, test_net_key_2, 0x02, 0x0001); send_beacon(&buf); ASSERT_FALSE(wait_for_beacon(beacon_scan_cb, BEACON_INTERVAL + 1, NULL, NULL)); ASSERT_TRUE(wait_for_beacon(beacon_scan_cb, BEACON_INTERVAL + 1, NULL, NULL)); @@ -665,7 +666,7 @@ static void test_tx_kr_old_key(void) /* Do the same, but secure beacon with the new Net Key. Now the node shall change IV Update * flag to 0. The beacon interval shall be increased. */ - beacon_create(&buf, test_net_key_secondary, 0x00, 0x0001); + beacon_create(&buf, test_net_key_2, 0x00, 0x0001); send_beacon(&buf); ASSERT_FALSE(wait_for_beacon(beacon_scan_cb, BEACON_INTERVAL + 1, NULL, NULL)); ASSERT_TRUE(wait_for_beacon(beacon_scan_cb, BEACON_INTERVAL + 1, NULL, NULL)); @@ -686,7 +687,7 @@ static void test_rx_kr_old_key(void) bt_mesh_test_setup(); bt_mesh_iv_update_test(true); - err = bt_mesh_cfg_cli_net_key_update(0, cfg->addr, 0, test_net_key_secondary, &status); + err = bt_mesh_cfg_cli_net_key_update(0, cfg->addr, 0, test_net_key_2, &status); if (err || status) { FAIL("Net Key update failed (err %d, status %u)", err, status); } @@ -1541,60 +1542,73 @@ static void test_tx_priv_beacon_cache(void) #if IS_ENABLED(CONFIG_BT_MESH_GATT_PROXY) +static uint8_t test_net_key_3[16] = {0x12, 0x54, 0xab, 0x1e}; + +#define UNTIL_UPTIME(time) (k_uptime_get() > (time) ? K_NO_WAIT : K_MSEC((time) - k_uptime_get())) +#define BEACON_TYPE_NET_ID 0 +#define BEACON_TYPE_NODE_ID 1 #define BEACON_TYPE_PRIVATE_NET_ID 2 #define BEACON_TYPE_PRIVATE_NODE_ID 3 #define BEACON_TYPE_PRIVATE_LEN 28 #define TEST_NET_IDX1 0 #define TEST_NET_IDX2 1 +#define TEST_NET_IDX3 2 #define MAX_TIMEOUT ((CONFIG_BT_MESH_NODE_ID_TIMEOUT * 1000) / 6) #define PP_NET_ID_WAIT_TIME 610 /*seconds*/ #define PP_NODE_ID_WAIT_TIME 80 /*seconds*/ #define PP_MULT_NET_ID_WAIT_TIME 50 /*seconds*/ +#define PROXY_ADV_MULTI_SUBNET_COEX_WAIT_TIME 151 /*seconds*/ -struct pp_netkey_ctx { +struct netkey_ctx { uint8_t *net_key; uint8_t net_id[8]; + uint8_t net_idx; struct bt_mesh_key id_key; }; -static struct pp_netkey_ctx pp_net0 = {.net_key = (uint8_t *)test_net_key}; -static struct pp_netkey_ctx pp_net1 = {.net_key = (uint8_t *)test_net_key_secondary}; +static struct netkey_ctx pp_net0 = {.net_key = (uint8_t *)test_net_key, .net_idx = 0}; +static struct netkey_ctx pp_net1 = {.net_key = (uint8_t *)test_net_key_2, .net_idx = 1}; +static struct netkey_ctx pp_net2 = {.net_key = (uint8_t *)test_net_key_3, .net_idx = 2}; struct priv_test_ctx { uint8_t beacon_type; uint16_t *node_id_addr; }; -static void pp_netkey_ctx_init(struct pp_netkey_ctx *net) +static void pp_netkey_ctx_init(struct netkey_ctx *net) { ASSERT_OK_MSG(bt_mesh_identity_key(net->net_key, &net->id_key), "Failed to generate ID key"); ASSERT_OK_MSG(bt_mesh_k3(net->net_key, net->net_id), "Failed to generate Net ID"); } -static bool pp_type_check(uint16_t expected_beacon, uint8_t adv_type, struct net_buf_simple *buf) +static uint8_t proxy_adv_type_get(uint8_t adv_type, struct net_buf_simple *buf) { - if (adv_type != BT_GAP_ADV_TYPE_ADV_IND || buf->len != BEACON_TYPE_PRIVATE_LEN) { - return false; + uint8_t type; + uint8_t len = buf->len; + + if (adv_type != BT_GAP_ADV_TYPE_ADV_IND || len < 12) { + return 0xFF; } - /* Remove Header */ (void)net_buf_simple_pull_mem(buf, 11); - - uint8_t beacon_type = net_buf_simple_pull_u8(buf); - - if (beacon_type != expected_beacon) { - return false; + type = net_buf_simple_pull_u8(buf); + /* BEACON_TYPE_NET_ID is 20 bytes long, while the three other accepted types are 28 bytes*/ + if (len != ((type == BEACON_TYPE_NET_ID) ? 20 : 28)) { + return 0xFF; } - return true; + return type; } -static uint64_t pp_hash_calc(struct pp_netkey_ctx *net, uint64_t random, uint16_t *addr) +static uint64_t proxy_adv_hash_calc(struct netkey_ctx *net, uint64_t random, uint16_t *addr, + bool is_priv) { uint64_t hash; - uint8_t tmp[16] = {0, 0, 0, 0, 0, 3}; + uint8_t tmp[16] = {0}; + + tmp[5] = is_priv ? 3 : 0; if (addr) { memcpy(&tmp[6], &random, 8); @@ -1616,7 +1630,7 @@ static bool pp_beacon_check(const uint8_t *net_id, void *ctx) struct priv_test_ctx *test_ctx = (struct priv_test_ctx *)ctx; ASSERT_EQUAL(beacon.pp_hash, - pp_hash_calc(&pp_net0, beacon.pp_random, test_ctx->node_id_addr)); + proxy_adv_hash_calc(&pp_net0, beacon.pp_random, test_ctx->node_id_addr, true)); if (memcmp(beacon.adv_addr.a.val, last_beacon_adv_addr.a.val, BT_ADDR_SIZE) == 0) { return false; @@ -1632,15 +1646,58 @@ static void priv_scan_cb(const bt_addr_le_t *addr, int8_t rssi, uint8_t adv_type { struct priv_test_ctx *ctx = (struct priv_test_ctx *)beacon.user_ctx; - if (!pp_type_check(ctx->beacon_type, adv_type, buf)) { + if (proxy_adv_type_get(adv_type, buf) != ctx->beacon_type) { /* Wrong message type */ return; } bt_addr_le_copy(&beacon.adv_addr, addr); - beacon.pp_hash = net_buf_simple_pull_le64(buf); - beacon.pp_random = net_buf_simple_pull_le64(buf); + if (ctx->beacon_type == BEACON_TYPE_NET_ID) { + beacon.net_id = net_buf_simple_pull_le64(buf); + } else { + beacon.pp_hash = net_buf_simple_pull_le64(buf); + beacon.pp_random = net_buf_simple_pull_le64(buf); + } + + if (!beacon.process_cb || beacon.process_cb(NULL, beacon.user_ctx)) { + k_sem_give(&observer_sem); + } +} + +struct proxy_adv_beacon { + uint8_t evt_type; + uint8_t net_idx; + int64_t rx_timestamp; + union { + uint64_t net_id; + struct { + uint64_t hash; + uint64_t random; + } enc; + } ctx; +}; + +static void proxy_adv_scan_all_cb(const bt_addr_le_t *addr, int8_t rssi, uint8_t adv_type, + struct net_buf_simple *buf) +{ + struct proxy_adv_beacon *beac = (struct proxy_adv_beacon *)beacon.user_ctx; + + beac->evt_type = proxy_adv_type_get(adv_type, buf); + if (beac->evt_type == 0xFF) { + /* Not a related beacon type */ + return; + } + + bt_addr_le_copy(&beacon.adv_addr, addr); + beac->rx_timestamp = k_uptime_get(); + + if (beac->evt_type == BEACON_TYPE_NET_ID) { + beac->ctx.net_id = net_buf_simple_pull_le64(buf); + } else { + beac->ctx.enc.hash = net_buf_simple_pull_le64(buf); + beac->ctx.enc.random = net_buf_simple_pull_le64(buf); + } if (!beacon.process_cb || beacon.process_cb(NULL, beacon.user_ctx)) { k_sem_give(&observer_sem); @@ -1656,11 +1713,11 @@ static void rx_priv_common_init(uint16_t wait) ASSERT_OK_MSG(bt_enable(NULL), "Bluetooth init failed"); } -static void tx_priv_common_init(uint16_t wait) +static void tx_proxy_adv_common_init(uint16_t wait, const struct bt_mesh_test_cfg *cfg) { bt_mesh_test_cfg_set(NULL, wait); bt_mesh_device_setup(&prov, &prb_comp); - provision(&tx_cfg); + provision(cfg); /* Disable GATT proxy */ ASSERT_OK_MSG(bt_mesh_gatt_proxy_set(BT_MESH_GATT_PROXY_DISABLED), @@ -1669,7 +1726,7 @@ static void tx_priv_common_init(uint16_t wait) static void test_tx_priv_net_id(void) { - tx_priv_common_init(PP_NET_ID_WAIT_TIME); + tx_proxy_adv_common_init(PP_NET_ID_WAIT_TIME, &tx_cfg); /* Enable private GATT proxy */ ASSERT_OK_MSG(bt_mesh_priv_gatt_proxy_set(BT_MESH_GATT_PROXY_ENABLED), @@ -1708,7 +1765,7 @@ static void test_tx_priv_node_id(void) { enum bt_mesh_feat_state state; - tx_priv_common_init(PP_NODE_ID_WAIT_TIME); + tx_proxy_adv_common_init(PP_NODE_ID_WAIT_TIME, &tx_cfg); /* Start first node advertisement */ ASSERT_OK_MSG(bt_mesh_subnet_priv_node_id_set(TEST_NET_IDX1, BT_MESH_NODE_IDENTITY_RUNNING), @@ -1761,10 +1818,10 @@ static void test_rx_priv_node_id(void) static void test_tx_priv_multi_net_id(void) { - tx_priv_common_init(PP_MULT_NET_ID_WAIT_TIME); + tx_proxy_adv_common_init(PP_MULT_NET_ID_WAIT_TIME, &tx_cfg); /* Add second network */ - ASSERT_OK_MSG(bt_mesh_subnet_add(TEST_NET_IDX2, test_net_key_secondary), + ASSERT_OK_MSG(bt_mesh_subnet_add(TEST_NET_IDX2, test_net_key_2), "Failed to add second subnet"); /* Enable private GATT proxy */ @@ -1774,6 +1831,246 @@ static void test_tx_priv_multi_net_id(void) PASS(); } +static void proxy_adv_subnet_find(struct proxy_adv_beacon *beac, struct netkey_ctx **nets, + uint8_t net_cnt) +{ + for (size_t i = 0; i < net_cnt; i++) { + + switch (beac->evt_type) { + case BEACON_TYPE_NET_ID: + if (!memcmp(nets[i]->net_id, &beac->ctx.net_id, 8)) { + beac->net_idx = nets[i]->net_idx; + return; + } + break; + case BEACON_TYPE_NODE_ID: + if (beac->ctx.enc.hash == + proxy_adv_hash_calc(nets[i], beac->ctx.enc.random, + (uint16_t *)&tx_cfg.addr, false)) { + beac->net_idx = nets[i]->net_idx; + return; + } + break; + case BEACON_TYPE_PRIVATE_NET_ID: + if (beac->ctx.enc.hash == + proxy_adv_hash_calc(nets[i], beac->ctx.enc.random, + NULL, true)) { + beac->net_idx = nets[i]->net_idx; + return; + } + break; + case BEACON_TYPE_PRIVATE_NODE_ID: + if (beac->ctx.enc.hash == + proxy_adv_hash_calc(nets[i], beac->ctx.enc.random, + (uint16_t *)&tx_cfg.addr, true)) { + beac->net_idx = nets[i]->net_idx; + return; + } + break; + + default: + FAIL("Unexpected beacon type"); + break; + } + } + + FAIL("Could not find matching subnet for incoming proxy adv beacon"); +} + +static const char *const proxy_adv_str[] = {"Net_ID", "Node_ID", "Priv_Net_ID", "Priv_Node_ID"}; +struct expected_proxy_adv_evt { + uint8_t evt_type; + uint8_t net_idx; + uint16_t evt_cnt; + struct { + int64_t after; + int64_t before; + } time; +}; + +static void proxy_adv_register_evt(struct proxy_adv_beacon *beac, + struct expected_proxy_adv_evt *exp_evts, uint8_t cnt) +{ + for (int i = 0; i < cnt; i++) { + if ((exp_evts[i].evt_cnt) && (beac->evt_type == exp_evts[i].evt_type) && + (beac->net_idx == exp_evts[i].net_idx) && + (beac->rx_timestamp >= exp_evts[i].time.after) && + (beac->rx_timestamp <= exp_evts[i].time.before)) { + exp_evts[i].evt_cnt--; + } + } +} + +static void proxy_adv_confirm_evt(struct expected_proxy_adv_evt *exp_evts, uint8_t cnt) +{ + bool missing_evts = false; + + for (int i = 0; i < cnt; i++) { + if (exp_evts[i].evt_cnt) { + LOG_ERR("Missing %d expected %s events in period %llums-%llums", + exp_evts[i].evt_cnt, proxy_adv_str[exp_evts[i].evt_type], + exp_evts[i].time.after, exp_evts[i].time.before); + missing_evts = true; + } + } + + if (missing_evts) { + FAIL("Test failed due to missing events"); + } +} + +static void proxy_adv_scan_all(struct netkey_ctx **nets, uint16_t net_cnt, + struct expected_proxy_adv_evt *exp_evt, uint16_t exp_evt_cnt, + int64_t timeout) +{ + struct proxy_adv_beacon beac; + + while (k_uptime_get() < timeout) { + + ASSERT_TRUE(wait_for_beacon(proxy_adv_scan_all_cb, 2, NULL, &beac)); + proxy_adv_subnet_find(&beac, nets, net_cnt); + proxy_adv_register_evt(&beac, exp_evt, exp_evt_cnt); + + /** We want to monitor an even distribution of adv events. + * To ensure this, we wait a little less than the minimum + * proxy adv period (1 second) before scanning for the next + * evt. + */ + k_sleep(K_MSEC(990)); + } + + proxy_adv_confirm_evt(exp_evt, exp_evt_cnt); +} + +#define PROXY_ADV_MULTI_CHECKPOINT_1 20000 +#define PROXY_ADV_MULTI_CHECKPOINT_2 50000 +#define PROXY_ADV_MULTI_CHECKPOINT_3 110000 +#define PROXY_ADV_MULTI_CHECKPOINT_4 130000 +#define PROXY_ADV_MULTI_CHECKPOINT_END 150000 + +static void test_tx_proxy_adv_multi_subnet_coex(void) +{ + tx_proxy_adv_common_init(PROXY_ADV_MULTI_SUBNET_COEX_WAIT_TIME, &tx_cfg); + + /* Enable GATT proxy */ + ASSERT_OK_MSG(bt_mesh_gatt_proxy_set(BT_MESH_GATT_PROXY_ENABLED), + "Failed to Enable gatt proxy"); + + k_sleep(UNTIL_UPTIME(PROXY_ADV_MULTI_CHECKPOINT_1)); + /* Add second and third network */ + ASSERT_OK_MSG(bt_mesh_subnet_add(TEST_NET_IDX2, test_net_key_2), + "Failed to add second subnet"); + ASSERT_OK_MSG(bt_mesh_subnet_add(TEST_NET_IDX3, test_net_key_3), + "Failed to add third subnet"); + + k_sleep(UNTIL_UPTIME(PROXY_ADV_MULTI_CHECKPOINT_2)); + /* Start Node Identity on second network */ + bt_mesh_proxy_identity_start(bt_mesh_subnet_get(TEST_NET_IDX2), false); + + k_sleep(UNTIL_UPTIME(PROXY_ADV_MULTI_CHECKPOINT_3)); + /* Prepare for solicitation */ + ASSERT_OK_MSG(bt_mesh_gatt_proxy_set(BT_MESH_GATT_PROXY_DISABLED), + "Failed to Enable gatt proxy"); + ASSERT_OK_MSG(bt_mesh_od_priv_proxy_set(20), "Failed to set OD priv proxy state"); + + k_sleep(UNTIL_UPTIME(PROXY_ADV_MULTI_CHECKPOINT_4)); + /* Re-enable GATT proxy and remove second and third network */ + ASSERT_OK_MSG(bt_mesh_gatt_proxy_set(BT_MESH_GATT_PROXY_ENABLED), + "Failed to Enable gatt proxy"); + ASSERT_OK_MSG(bt_mesh_subnet_del(TEST_NET_IDX2), "Failed to delete subnet"); + ASSERT_OK_MSG(bt_mesh_subnet_del(TEST_NET_IDX3), "Failed to delete subnet"); + + PASS(); +} + +static const struct bt_mesh_test_cfg solicit_trigger_cfg = { + .addr = 0x0003, + .dev_key = { 0x03 }, +}; + +static void test_tx_proxy_adv_solicit_trigger(void) +{ + tx_proxy_adv_common_init(PROXY_ADV_MULTI_SUBNET_COEX_WAIT_TIME, &solicit_trigger_cfg); + ASSERT_OK_MSG(bt_mesh_subnet_add(TEST_NET_IDX2, test_net_key_2), + "Failed to add second subnet"); + + k_sleep(UNTIL_UPTIME(PROXY_ADV_MULTI_CHECKPOINT_3)); + + /* Solicit first and second network */ + ASSERT_OK_MSG(bt_mesh_proxy_solicit(TEST_NET_IDX1), + "Failed to start solicitation"); + ASSERT_OK_MSG(bt_mesh_proxy_solicit(TEST_NET_IDX2), + "Failed to start solicitation"); + + PASS(); +} + +static void test_rx_proxy_adv_multi_subnet_coex(void) +{ + rx_priv_common_init(PROXY_ADV_MULTI_SUBNET_COEX_WAIT_TIME); + pp_netkey_ctx_init(&pp_net1); + pp_netkey_ctx_init(&pp_net2); + + struct netkey_ctx *nets[] = {&pp_net0, &pp_net1, &pp_net2}; + struct expected_proxy_adv_evt exp_evt[] = { + /** A single subnet is active on the device with GATT Proxy + * enabled. Verify that the single subnet has exclusive + * access to the adv medium. + */ + {.evt_type = BEACON_TYPE_NET_ID, .net_idx = 0, .evt_cnt = 19, + .time = {.after = 0, .before = PROXY_ADV_MULTI_CHECKPOINT_1}}, + + /** Two additional subnets are added to the device. + * Check that the subnets are sharing the adv medium, + * advertising NET_ID beacons. + */ + {.evt_type = BEACON_TYPE_NET_ID, .net_idx = 0, .evt_cnt = 8, + .time = {.after = PROXY_ADV_MULTI_CHECKPOINT_1, + .before = PROXY_ADV_MULTI_CHECKPOINT_2}}, + {.evt_type = BEACON_TYPE_NET_ID, .net_idx = 1, .evt_cnt = 8, + .time = {.after = PROXY_ADV_MULTI_CHECKPOINT_1, + .before = PROXY_ADV_MULTI_CHECKPOINT_2}}, + {.evt_type = BEACON_TYPE_NET_ID, .net_idx = 2, .evt_cnt = 8, + .time = {.after = PROXY_ADV_MULTI_CHECKPOINT_1, + .before = PROXY_ADV_MULTI_CHECKPOINT_2}}, + + /** The second subnet enables Node Identity. Check that NODE_ID + * is advertised by this subnet, and that the two others + * continues to advertise NET_ID. + */ + {.evt_type = BEACON_TYPE_NET_ID, .net_idx = 0, .evt_cnt = 17, + .time = {.after = PROXY_ADV_MULTI_CHECKPOINT_2, + .before = PROXY_ADV_MULTI_CHECKPOINT_3}}, + {.evt_type = BEACON_TYPE_NODE_ID, .net_idx = 1, .evt_cnt = 17, + .time = {.after = PROXY_ADV_MULTI_CHECKPOINT_2, + .before = PROXY_ADV_MULTI_CHECKPOINT_3}}, + {.evt_type = BEACON_TYPE_NET_ID, .net_idx = 2, .evt_cnt = 17, + .time = {.after = PROXY_ADV_MULTI_CHECKPOINT_2, + .before = PROXY_ADV_MULTI_CHECKPOINT_3}}, + + /** The first and second subnet gets solicited. Check that + * PRIVATE_NET_ID is advertised by these subnet, + */ + {.evt_type = BEACON_TYPE_PRIVATE_NET_ID, .net_idx = 0, .evt_cnt = 9, + .time = {.after = PROXY_ADV_MULTI_CHECKPOINT_3, + .before = PROXY_ADV_MULTI_CHECKPOINT_4}}, + {.evt_type = BEACON_TYPE_PRIVATE_NET_ID, .net_idx = 1, .evt_cnt = 9, + .time = {.after = PROXY_ADV_MULTI_CHECKPOINT_3, + .before = PROXY_ADV_MULTI_CHECKPOINT_4}}, + + /** Second and third subnet are disabled. Verify that the single + * subnet has exclusive access to the adv medium. + */ + {.evt_type = BEACON_TYPE_NET_ID, .net_idx = 0, .evt_cnt = 19, + .time = {.after = PROXY_ADV_MULTI_CHECKPOINT_4, + .before = PROXY_ADV_MULTI_CHECKPOINT_END}}, + }; + + proxy_adv_scan_all(nets, ARRAY_SIZE(nets), exp_evt, ARRAY_SIZE(exp_evt), + PROXY_ADV_MULTI_CHECKPOINT_END); + PASS(); +} + static void test_rx_priv_multi_net_id(void) { rx_priv_common_init(PP_MULT_NET_ID_WAIT_TIME); @@ -1787,7 +2084,7 @@ static void test_rx_priv_multi_net_id(void) uint16_t itr = 4; static uint8_t old_idx = 0xff; static struct { - struct pp_netkey_ctx *net; + struct netkey_ctx *net; uint16_t recv_cnt; int64_t start; } net_ctx[2] = { @@ -1802,7 +2099,7 @@ static void test_rx_priv_multi_net_id(void) for (size_t i = 0; i < ARRAY_SIZE(net_ctx); i++) { if (beacon.pp_hash == - pp_hash_calc(net_ctx[i].net, beacon.pp_random, NULL)) { + proxy_adv_hash_calc(net_ctx[i].net, beacon.pp_random, NULL, true)) { if (old_idx == 0xff) { /* Received first Net ID advertisment */ old_idx = i; @@ -1931,6 +2228,8 @@ static const struct bst_test_instance test_beacon[] = { TEST_CASE(tx, priv_node_id, "Private Proxy: advertise Node ID"), TEST_CASE(tx, priv_multi_net_id, "Private Proxy: advertise multiple Net ID"), TEST_CASE(tx, priv_gatt_proxy, "Private Proxy: Send Private Beacons over GATT"), + TEST_CASE(tx, proxy_adv_multi_subnet_coex, "Proxy Adv: Multi subnet coex proxy adv"), + TEST_CASE(tx, proxy_adv_solicit_trigger, "Proxy Adv: Trigger Solicitation"), #endif #endif @@ -1951,6 +2250,7 @@ static const struct bst_test_instance test_beacon[] = { TEST_CASE(rx, priv_node_id, "Private Proxy: scan for Node ID"), TEST_CASE(rx, priv_multi_net_id, "Private Proxy: scan for multiple Net ID"), TEST_CASE(rx, priv_gatt_proxy, "Private Proxy: Receive Private Beacons over GATT"), + TEST_CASE(rx, proxy_adv_multi_subnet_coex, "Proxy Adv: Multi subnet coex proxy adv"), #endif #endif BSTEST_END_MARKER diff --git a/tests/bsim/bluetooth/mesh/tests_scripts/priv_beacon/proxy_adv_multi_subnet_coex.sh b/tests/bsim/bluetooth/mesh/tests_scripts/priv_beacon/proxy_adv_multi_subnet_coex.sh new file mode 100755 index 00000000000..aa96ee325d8 --- /dev/null +++ b/tests/bsim/bluetooth/mesh/tests_scripts/priv_beacon/proxy_adv_multi_subnet_coex.sh @@ -0,0 +1,54 @@ +#!/usr/bin/env bash +# Copyright 2023 Nordic Semiconductor +# SPDX-License-Identifier: Apache-2.0 + +source $(dirname "${BASH_SOURCE[0]}")/../../_mesh_test.sh + +# Test Proxy advertisement Coex + +# This test verifies correct Proxy advertisement behavior for a device +# where the Proxy adv requirements changes over time, both for single +# and multiple subnets. The TX device is the DUT in this instance, while +# the RX device scans and verifies that the correct proxy adv messages of +# the different subnets is sent within the expected time delta. + +# Note 1: The maximum allowed timeslot for a subnet to advertise proxy +# in this scenario is 10 seconds when there is more than one subnet that +# has active proxy adv work. This is reflected in the scanning criteria +# on the RX device. + +# Note 2: The expected message received count for each event is based on +# what would be a reasonable/acceptable to receive within a given time +# window. The Mesh Protocol specification does not specify exactly the +# timing for Proxy ADV messages. + +# Test procedure: +# 1. (0-20 seconds) A single subnet is active on the TX device with GATT +# Proxy enabled. RX device verifies that the single subnet has exclusive +# access to the adv medium. +# 2. (20-50 seconds) Two additional subnets are added to the TX device. RX +# device checks that the subnets are sharing the adv medium, advertising +# NET_ID beacons. +# 3. (50-110 seconds) The second subnet enables Node Identity. RX device +# checks that NODE_ID is advertised by this subnet, and that the two +# others continues to advertise NET_ID. +# 4. (110-130 seconds) The first and second subnet gets solicited. RX device +# checks that PRIVATE_NET_ID is advertised by these subnets. +# 5. (130-150 seconds) The second and third subnet are disabled on the TX +# device. RX device verifies that the single subnet has exclusive access +# to the adv medium again. + + +conf=prj_mesh1d1_conf +overlay=overlay_gatt_conf +RunTest proxy_adv_multi_subnet_coex \ + beacon_tx_proxy_adv_multi_subnet_coex \ + beacon_rx_proxy_adv_multi_subnet_coex \ + beacon_tx_proxy_adv_solicit_trigger + +conf=prj_mesh1d1_conf +overlay=overlay_gatt_conf_overlay_psa_conf +RunTest proxy_adv_multi_subnet_coex \ + beacon_tx_proxy_adv_multi_subnet_coex \ + beacon_rx_proxy_adv_multi_subnet_coex \ + beacon_tx_proxy_adv_solicit_trigger From 6cb1ff6560f5b8e271b1ecbfc8f7f9b02d0ba14a Mon Sep 17 00:00:00 2001 From: Mahesh Mahadevan Date: Thu, 7 Dec 2023 18:50:12 +0000 Subject: [PATCH 1344/3723] pm: Move settting timeout to after suspending devices pm_suspend_devices() could return an error. Set timeout using sys_clock_set_timeout() to after this error is handled so that we have the accurate power state when calling the timeout function. This is useful in cases where we wish to compensate the system timer for certain power modes. Signed-off-by: Mahesh Mahadevan --- subsys/pm/pm.c | 23 ++++++++++++----------- 1 file changed, 12 insertions(+), 11 deletions(-) diff --git a/subsys/pm/pm.c b/subsys/pm/pm.c index cfeadaa4447..07c197e246f 100644 --- a/subsys/pm/pm.c +++ b/subsys/pm/pm.c @@ -197,17 +197,6 @@ bool pm_system_suspend(int32_t ticks) return false; } - if (ticks != K_TICKS_FOREVER) { - /* - * We need to set the timer to interrupt a little bit early to - * accommodate the time required by the CPU to fully wake up. - */ - sys_clock_set_timeout(ticks - - k_us_to_ticks_ceil32( - z_cpus_pm_state[id].exit_latency_us), - true); - } - #if defined(CONFIG_PM_DEVICE) && !defined(CONFIG_PM_DEVICE_RUNTIME_EXCLUSIVE) if (atomic_sub(&_cpus_active, 1) == 1) { if (z_cpus_pm_state[id].state != PM_STATE_RUNTIME_IDLE) { @@ -222,6 +211,18 @@ bool pm_system_suspend(int32_t ticks) } } #endif + + if (ticks != K_TICKS_FOREVER) { + /* + * We need to set the timer to interrupt a little bit early to + * accommodate the time required by the CPU to fully wake up. + */ + sys_clock_set_timeout(ticks - + k_us_to_ticks_ceil32( + z_cpus_pm_state[id].exit_latency_us), + true); + } + /* * This function runs with interruptions locked but it is * expected the SoC to unlock them in From 4dc7c89f40a40ace3c231c966d3d5159d980340d Mon Sep 17 00:00:00 2001 From: Tom Chang Date: Fri, 8 Dec 2023 17:25:35 +0800 Subject: [PATCH 1345/3723] drivers: espi: npcx: introduce espi taf driver This CL implements espi taf read/write/erase function for NPCX. Signed-off-by: Tom Chang --- drivers/espi/CMakeLists.txt | 1 + drivers/espi/Kconfig.npcx | 30 ++ drivers/espi/espi_npcx.c | 93 +++- drivers/espi/espi_taf_npcx.c | 466 ++++++++++++++++++ dts/arm/nuvoton/npcx/npcx4.dtsi | 11 + dts/arm/nuvoton/npcx/npcx7.dtsi | 5 + dts/arm/nuvoton/npcx/npcx9.dtsi | 5 + dts/bindings/espi/nuvoton,npcx-espi-taf.yaml | 60 +++ dts/bindings/espi/nuvoton,npcx-espi.yaml | 10 + include/zephyr/drivers/espi_saf.h | 32 ++ soc/arm/nuvoton_npcx/common/reg/reg_access.h | 8 + soc/arm/nuvoton_npcx/common/reg/reg_def.h | 62 ++- soc/arm/nuvoton_npcx/common/registers.c | 2 +- soc/arm/nuvoton_npcx/common/soc_espi_taf.h | 151 ++++++ .../npcx4/Kconfig.defconfig.series | 4 + soc/arm/nuvoton_npcx/npcx4/soc.h | 1 + 16 files changed, 928 insertions(+), 13 deletions(-) create mode 100644 drivers/espi/espi_taf_npcx.c create mode 100644 dts/bindings/espi/nuvoton,npcx-espi-taf.yaml create mode 100644 soc/arm/nuvoton_npcx/common/soc_espi_taf.h diff --git a/drivers/espi/CMakeLists.txt b/drivers/espi/CMakeLists.txt index 77455ebda01..5379d00ea21 100644 --- a/drivers/espi/CMakeLists.txt +++ b/drivers/espi/CMakeLists.txt @@ -7,6 +7,7 @@ zephyr_library() zephyr_library_sources_ifdef(CONFIG_ESPI_XEC espi_mchp_xec.c) zephyr_library_sources_ifdef(CONFIG_ESPI_NPCX espi_npcx.c) zephyr_library_sources_ifdef(CONFIG_ESPI_NPCX host_subs_npcx.c) +zephyr_library_sources_ifdef(CONFIG_ESPI_TAF_NPCX espi_taf_npcx.c) zephyr_library_sources_ifdef(CONFIG_USERSPACE espi_handlers.c) zephyr_library_sources_ifdef(CONFIG_ESPI_EMUL espi_emul.c) zephyr_library_sources_ifdef(CONFIG_ESPI_SAF_XEC espi_saf_mchp_xec.c) diff --git a/drivers/espi/Kconfig.npcx b/drivers/espi/Kconfig.npcx index 69a7087fce7..3f1d511caa1 100644 --- a/drivers/espi/Kconfig.npcx +++ b/drivers/espi/Kconfig.npcx @@ -58,6 +58,36 @@ config ESPI_NPCX_PERIPHERAL_DEBUG_PORT_80_RING_BUF_SIZE The size of the ring buffer in byte used by the Port80 ISR to store Postcodes from Host. +config ESPI_TAF_NPCX + bool "Nuvoton NPCX embedded controller (EC) ESPI TAF driver" + depends on SOC_SERIES_NPCX4 + help + This option enables the Intel Enhanced Serial Peripheral Interface + Target Attached Flash (eSPI TAF) for NPCX4 family of processors. + +choice ESPI_TAF_ACCESS_MODE_CHOICE + prompt "eSPI TAF Read Access Mode" + default ESPI_TAF_AUTO_MODE + +config ESPI_TAF_AUTO_MODE + bool "eSPI TAF Automatic Mode" + help + This is the setting to use auto mode for eSPI TAF read. + +config ESPI_TAF_MANUAL_MODE + bool "eSPI TAF Manual Mode" + help + This is the setting to use manual mode for eSPI TAF read. + +endchoice + +config ESPI_TAF_PR_NUM + int "Sets of protection region settings" + default 16 + help + This size is display how many group of slave attached flash protection + region. + # The default value 'y' for the existing options if ESPI_NPCX is selected. if ESPI_NPCX diff --git a/drivers/espi/espi_npcx.c b/drivers/espi/espi_npcx.c index d6177dee388..6a8a83a13c3 100644 --- a/drivers/espi/espi_npcx.c +++ b/drivers/espi/espi_npcx.c @@ -7,6 +7,7 @@ #define DT_DRV_COMPAT nuvoton_npcx_espi #include +#include #include #include #include @@ -74,8 +75,8 @@ struct espi_npcx_data { ((hdr & 0xf0000) >> 8)) /* Flash channel maximum payload size */ -#define NPCX_ESPI_FLASH_MAX_RX_PAYLOAD 64 -#define NPCX_ESPI_FLASH_MAX_TX_PAYLOAD 16 +#define NPCX_ESPI_FLASH_MAX_RX_PAYLOAD DT_INST_PROP(0, rx_plsize) +#define NPCX_ESPI_FLASH_MAX_TX_PAYLOAD DT_INST_PROP(0, tx_plsize) /* eSPI cycle type field for OOB and FLASH channels */ #define ESPI_FLASH_READ_CYCLE_TYPE 0x00 @@ -275,6 +276,19 @@ static void espi_bus_cfg_update_isr(const struct device *dev) NPCX_ESPI_HOST_CH_EN(NPCX_ESPI_CH_VW))) { espi_vw_send_bootload_done(dev); } + +#if (defined(CONFIG_ESPI_FLASH_CHANNEL) && defined(CONFIG_ESPI_SAF)) + /* If CONFIG_ESPI_SAF is set, set to auto or manual mode accroding + * to configuration. + */ + if (IS_BIT_SET(inst->ESPICFG, NPCX_ESPICFG_FLCHANMODE)) { +#if defined(CONFIG_ESPI_TAF_AUTO_MODE) + inst->FLASHCTL |= BIT(NPCX_FLASHCTL_SAF_AUTO_READ); +#else + inst->FLASHCTL &= ~BIT(NPCX_FLASHCTL_SAF_AUTO_READ); +#endif + } +#endif } #if defined(CONFIG_ESPI_OOB_CHANNEL) @@ -288,12 +302,82 @@ static void espi_bus_oob_rx_isr(const struct device *dev) #endif #if defined(CONFIG_ESPI_FLASH_CHANNEL) +#if defined(CONFIG_ESPI_SAF) +static struct espi_taf_pckt taf_pckt; + +static uint32_t espi_taf_parse(const struct device *dev) +{ + struct espi_reg *const inst = HAL_INSTANCE(dev); + struct npcx_taf_head taf_head; + uint32_t taf_addr; + uint8_t i, roundsize; + + /* Get type, length and tag from RX buffer */ + memcpy(&taf_head, (void *)&inst->FLASHRXBUF[0], sizeof(taf_head)); + taf_pckt.type = taf_head.type; + taf_pckt.len = (((uint16_t)taf_head.tag_hlen & 0xF) << 8) | taf_head.llen; + taf_pckt.tag = taf_head.tag_hlen >> 4; + + if ((taf_pckt.len == 0) && ((taf_pckt.type & 0xF) == NPCX_ESPI_TAF_REQ_READ)) { + taf_pckt.len = KB(4); + } + + /* Get address from RX buffer */ + taf_addr = inst->FLASHRXBUF[1]; + taf_pckt.addr = sys_cpu_to_be32(taf_addr); + + /* Get written data if eSPI TAF write */ + if ((taf_pckt.type & 0xF) == NPCX_ESPI_TAF_REQ_WRITE) { + roundsize = DIV_ROUND_UP(taf_pckt.len, sizeof(uint32_t)); + for (i = 0; i < roundsize; i++) { + taf_pckt.src[i] = inst->FLASHRXBUF[2 + i]; + } + } + + return (uint32_t)&taf_pckt; +} +#endif /* CONFIG_ESPI_SAF */ + static void espi_bus_flash_rx_isr(const struct device *dev) { + struct espi_reg *const inst = HAL_INSTANCE(dev); struct espi_npcx_data *const data = dev->data; - LOG_DBG("%s", __func__); - k_sem_give(&data->flash_rx_lock); + /* Controller Attached Flash Access */ + if ((inst->ESPICFG & BIT(NPCX_ESPICFG_FLCHANMODE)) == 0) { + k_sem_give(&data->flash_rx_lock); + } else { /* Target Attached Flash Access */ +#if defined(CONFIG_ESPI_SAF) + struct espi_event evt = { + .evt_type = ESPI_BUS_SAF_NOTIFICATION, + .evt_details = ESPI_CHANNEL_FLASH, + .evt_data = espi_taf_parse(dev), + }; + espi_send_callbacks(&data->callbacks, dev, evt); +#else + LOG_WRN("ESPI TAF not supported"); +#endif + } +} + +static void espi_bus_completion_sent_isr(const struct device *dev) +{ + struct espi_reg *const inst = HAL_INSTANCE(dev); + + /* check that ESPISTS.FLNACS is clear. */ + if (IS_BIT_SET(inst->ESPISTS, NPCX_ESPISTS_FLNACS)) { + LOG_ERR("ESPISTS_FLNACS not clear\r\n"); + } + + /* flash operation is done, Make sure the TAFS transmit buffer is empty */ + if (IS_BIT_SET(inst->FLASHCTL, NPCX_FLASHCTL_FLASH_TX_AVAIL)) { + LOG_ERR("FLASH_TX_AVAIL not clear\r\n"); + } + + /* In auto mode, release FLASH_NP_FREE here to get next SAF request.*/ + if (IS_BIT_SET(inst->FLASHCTL, NPCX_FLASHCTL_SAF_AUTO_READ)) { + inst->FLASHCTL |= BIT(NPCX_FLASHCTL_FLASH_NP_FREE); + } } #endif @@ -307,6 +391,7 @@ const struct espi_bus_isr espi_bus_isr_tbl[] = { #endif #if defined(CONFIG_ESPI_FLASH_CHANNEL) NPCX_ESPI_BUS_INT_ITEM(FLASHRX, espi_bus_flash_rx_isr), + NPCX_ESPI_BUS_INT_ITEM(FLNACS, espi_bus_completion_sent_isr), #endif }; diff --git a/drivers/espi/espi_taf_npcx.c b/drivers/espi/espi_taf_npcx.c new file mode 100644 index 00000000000..722b26730e8 --- /dev/null +++ b/drivers/espi/espi_taf_npcx.c @@ -0,0 +1,466 @@ +/* + * Copyright (c) 2023 Nuvoton Technology Corporation. + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#define DT_DRV_COMPAT nuvoton_npcx_espi_taf + +#include +#include +#include +#include +#include +#include + +LOG_MODULE_REGISTER(espi_taf, CONFIG_ESPI_LOG_LEVEL); + +static const struct device *const spi_dev = DEVICE_DT_GET(DT_ALIAS(taf_flash)); + +struct espi_taf_npcx_config { + uintptr_t base; + uintptr_t mapped_addr; + uintptr_t rx_plsz; + enum NPCX_ESPI_TAF_ERASE_BLOCK_SIZE erase_sz; + enum NPCX_ESPI_TAF_MAX_READ_REQ max_rd_sz; +}; + +struct espi_taf_npcx_data { + sys_slist_t callbacks; +}; + +#define HAL_INSTANCE(dev) \ + ((struct espi_reg *)((const struct espi_taf_npcx_config *) \ + (dev)->config)->base) + +#define FLBASE_ADDR ( \ + GET_FIELD(inst->FLASHBASE, NPCX_FLASHBASE_FLBASE_ADDR) \ + << GET_FIELD_POS(NPCX_FLASHBASE_FLBASE_ADDR)) + +#define PRTR_BADDR(i) ( \ + GET_FIELD(inst->FLASH_PRTR_BADDR[i], NPCX_FLASH_PRTR_BADDR) \ + << GET_FIELD_POS(NPCX_FLASH_PRTR_BADDR)) + +#define PRTR_HADDR(i) ( \ + GET_FIELD(inst->FLASH_PRTR_HADDR[i], NPCX_FLASH_PRTR_HADDR) \ + << GET_FIELD_POS(NPCX_FLASH_PRTR_HADDR)) | 0xFFF; + +/* Check access region of read request is protected or not */ +static bool espi_taf_check_read_protect(const struct device *dev, uint32_t addr, uint32_t len, + uint8_t tag) +{ + struct espi_reg *const inst = HAL_INSTANCE(dev); + uint32_t flash_addr = addr; + uint8_t i; + uint16_t override_rd; + uint32_t base, high; + bool rdpr; + + flash_addr += FLBASE_ADDR; + + for (i = 0; i < CONFIG_ESPI_TAF_PR_NUM; i++) { + base = PRTR_BADDR(i); + high = PRTR_HADDR(i); + + rdpr = IS_BIT_SET(inst->FLASH_PRTR_BADDR[i], NPCX_FRGN_RPR); + override_rd = GET_FIELD(inst->FLASH_RGN_TAG_OVR[i], NPCX_FLASH_TAG_OVR_RPR); + + if (rdpr && !IS_BIT_SET(override_rd, tag) && + (base <= flash_addr + len - 1 && flash_addr <= high)) { + return true; + } + } + + return false; +} + +/* Check access region of write request is protected or not */ +static bool espi_taf_check_write_protect(const struct device *dev, uint32_t addr, + uint32_t len, uint8_t tag) +{ + struct espi_reg *const inst = HAL_INSTANCE(dev); + uint32_t flash_addr = addr; + uint8_t i; + uint16_t override_wr; + uint32_t base, high; + bool wrpr; + + flash_addr += FLBASE_ADDR; + + for (i = 0; i < CONFIG_ESPI_TAF_PR_NUM; i++) { + base = PRTR_BADDR(i); + high = PRTR_HADDR(i); + + wrpr = IS_BIT_SET(inst->FLASH_PRTR_BADDR[i], NPCX_FRGN_WPR); + override_wr = GET_FIELD(inst->FLASH_RGN_TAG_OVR[i], NPCX_FLASH_TAG_OVR_WPR); + + if (wrpr && !IS_BIT_SET(override_wr, tag) && + (base <= flash_addr + len - 1 && flash_addr <= high)) { + return true; + } + } + + return false; +} + +static int espi_taf_npcx_configure(const struct device *dev, const struct espi_saf_cfg *cfg) +{ + struct espi_reg *const inst = HAL_INSTANCE(dev); + +#if defined(CONFIG_ESPI_TAF_AUTO_MODE) + inst->FLASHCTL |= BIT(NPCX_FLASHCTL_SAF_AUTO_READ); +#else + inst->FLASHCTL &= ~BIT(NPCX_FLASHCTL_SAF_AUTO_READ); +#endif + return 0; +} + +static int espi_taf_npcx_set_pr(const struct device *dev, const struct espi_saf_protection *pr) +{ + struct espi_reg *const inst = HAL_INSTANCE(dev); + const struct espi_saf_pr *preg = pr->pregions; + size_t n = pr->nregions; + uint8_t regnum; + uint16_t bitmask, offset; + uint32_t rw_pr, override_rw; + + if ((dev == NULL) || (pr == NULL)) { + return -EINVAL; + } + + if (pr->nregions >= CONFIG_ESPI_TAF_PR_NUM) { + return -EINVAL; + } + + while (n--) { + regnum = preg->pr_num; + + if (regnum >= CONFIG_ESPI_TAF_PR_NUM) { + return -EINVAL; + } + + rw_pr = preg->master_bm_we << NPCX_FRGN_WPR; + rw_pr = rw_pr | (preg->master_bm_rd << NPCX_FRGN_RPR); + + if (preg->flags) { + bitmask = BIT_MASK(GET_FIELD_SZ(NPCX_FLASH_PRTR_BADDR)); + offset = GET_FIELD_POS(NPCX_FLASH_PRTR_BADDR); + inst->FLASH_PRTR_BADDR[regnum] = ((preg->start & bitmask) << offset) + | rw_pr; + bitmask = BIT_MASK(GET_FIELD_SZ(NPCX_FLASH_PRTR_HADDR)); + offset = GET_FIELD_POS(NPCX_FLASH_PRTR_HADDR); + inst->FLASH_PRTR_HADDR[regnum] = (preg->end & bitmask) << offset; + } + + override_rw = (preg->override_r << 16) | preg->override_w; + inst->FLASH_RGN_TAG_OVR[regnum] = override_rw; + preg++; + } + + return 0; +} + +static int espi_taf_npcx_activate(const struct device *dev) +{ + struct espi_reg *const inst = HAL_INSTANCE(dev); + + inst->FLASHCTL &= ~BIT(NPCX_FLASHCTL_AUTO_RD_DIS_CTL); + inst->FLASHCTL &= ~BIT(NPCX_FLASHCTL_BLK_FLASH_NP_FREE); + + return 0; +} + +static bool espi_taf_npcx_channel_ready(const struct device *dev) +{ + struct espi_reg *const inst = HAL_INSTANCE(dev); + + if (!IS_BIT_SET(inst->ESPICFG, NPCX_ESPICFG_FLCHANMODE)) { + return false; + } + return true; +} + +/* This routine set FLASH_C_AVAIL for standard request */ +static void taf_set_flash_c_avail(const struct device *dev) +{ + struct espi_reg *const inst = HAL_INSTANCE(dev); + uint32_t tmp = inst->FLASHCTL; + + /* + * Clear FLASHCTL_FLASH_NP_FREE to avoid host puts a flash + * standard request command at here. + */ + tmp &= NPCX_FLASHCTL_ACCESS_MASK; + + /* Set FLASHCTL_FLASH_TX_AVAIL */ + tmp |= BIT(NPCX_FLASHCTL_FLASH_TX_AVAIL); + inst->FLASHCTL = tmp; +} + +/* This routine release FLASH_NP_FREE for standard request */ +static void taf_release_flash_np_free(const struct device *dev) +{ + struct espi_reg *const inst = HAL_INSTANCE(dev); + uint32_t tmp = inst->FLASHCTL; + + /* + * Clear FLASHCTL_FLASH_TX_AVAIL to avoid host puts a + * GET_FLASH_C command at here. + */ + tmp &= NPCX_FLASHCTL_ACCESS_MASK; + + /* Release FLASH_NP_FREE */ + tmp |= BIT(NPCX_FLASHCTL_FLASH_NP_FREE); + inst->FLASHCTL = tmp; +} + +static int taf_npcx_completion_handler(const struct device *dev, uint32_t *buffer) +{ + uint16_t size = DIV_ROUND_UP((uint8_t)(buffer[0]) + 1, sizeof(uint32_t)); + struct espi_reg *const inst = HAL_INSTANCE(dev); + struct npcx_taf_head *head = (struct npcx_taf_head *)buffer; + uint8_t i; + + /* Check the Flash Access TX Queue is empty by polling + * FLASH_TX_AVAIL. + */ + if (WAIT_FOR(IS_BIT_SET(inst->FLASHCTL, NPCX_FLASHCTL_FLASH_TX_AVAIL), + NPCX_FLASH_CHK_TIMEOUT, NULL)) { + LOG_ERR("Check TX Queue Is Empty Timeout"); + return -EBUSY; + } + + /* Check ESPISTS.FLNACS is clear (no slave completion is detected) */ + if (WAIT_FOR(IS_BIT_SET(inst->ESPISTS, NPCX_ESPISTS_FLNACS), + NPCX_FLASH_CHK_TIMEOUT, NULL)) { + LOG_ERR("Check Slave Completion Timeout"); + return -EBUSY; + } + + /* Write packet to FLASHTXBUF */ + for (i = 0; i < size; i++) { + inst->FLASHTXBUF[i] = buffer[i]; + } + + /* Set the FLASHCTL.FLASH_TX_AVAIL bit to 1 to enqueue the packet */ + taf_set_flash_c_avail(dev); + + /* Release FLASH_NP_FREE here to ready get next TAF request */ + if ((head->type != CYC_SCS_CMP_WITH_DATA_FIRST) && + (head->type != CYC_SCS_CMP_WITH_DATA_MIDDLE)) { + taf_release_flash_np_free(dev); + } + + return 0; +} + +static int espi_taf_npcx_flash_read(const struct device *dev, struct espi_saf_packet *pckt) +{ + struct espi_reg *const inst = HAL_INSTANCE(dev); + struct espi_taf_npcx_config *config = ((struct espi_taf_npcx_config *)(dev)->config); + struct espi_taf_npcx_pckt *taf_data_ptr = (struct espi_taf_npcx_pckt *)pckt->buf; + uint8_t *data_ptr = (uint8_t *)taf_data_ptr->data; + uint8_t cycle_type = CYC_SCS_CMP_WITH_DATA_ONLY; + uint32_t total_len = pckt->len; + uint32_t len = total_len; + uint32_t addr = pckt->flash_addr; + uint8_t flash_req_size = GET_FIELD(inst->FLASHCFG, NPCX_FLASHCFG_FLASHREQSIZE); + uint8_t target_max_size = GET_FIELD(inst->FLASHCFG, NPCX_FLASHCFG_FLREQSUP); + uint16_t max_read_req = 32 << flash_req_size; + struct npcx_taf_head taf_head; + int rc; + + if (flash_req_size > target_max_size) { + LOG_DBG("Exceeded the maximum supported length"); + if (target_max_size == 0) { + target_max_size = 1; + } + max_read_req = 32 << target_max_size; + } + + if (total_len > max_read_req) { + LOG_ERR("Exceeded the limitation of read length"); + return -EINVAL; + } + + if (espi_taf_check_read_protect(dev, addr, len, taf_data_ptr->tag)) { + LOG_ERR("Access protect region"); + return -EINVAL; + } + + if (total_len <= config->rx_plsz) { + cycle_type = CYC_SCS_CMP_WITH_DATA_ONLY; + len = total_len; + } else { + cycle_type = CYC_SCS_CMP_WITH_DATA_FIRST; + len = config->rx_plsz; + } + + do { + data_ptr = (uint8_t *)taf_data_ptr->data; + + taf_head.pkt_len = len + NPCX_TAF_CMP_HEADER_LEN; + taf_head.type = cycle_type; + taf_head.tag_hlen = (taf_data_ptr->tag << 4) | ((len & 0xF00) >> 8); + taf_head.llen = len & 0xFF; + memcpy(data_ptr, &taf_head, sizeof(taf_head)); + + rc = flash_read(spi_dev, addr, data_ptr + 4, len); + if (rc) { + LOG_ERR("flash read fail 0x%x", rc); + return -EIO; + } + + rc = taf_npcx_completion_handler(dev, (uint32_t *)taf_data_ptr->data); + if (rc) { + LOG_ERR("espi taf completion handler fail"); + return rc; + } + + total_len -= len; + addr += len; + + if (total_len <= config->rx_plsz) { + cycle_type = CYC_SCS_CMP_WITH_DATA_LAST; + len = total_len; + } else { + cycle_type = CYC_SCS_CMP_WITH_DATA_MIDDLE; + } + } while (total_len); + + return 0; +} + +static int espi_taf_npcx_flash_write(const struct device *dev, struct espi_saf_packet *pckt) +{ + struct espi_taf_npcx_pckt *taf_data_ptr = (struct espi_taf_npcx_pckt *)pckt->buf; + uint8_t *data_ptr = (uint8_t *)(taf_data_ptr->data); + struct npcx_taf_head taf_head; + int rc; + + if (espi_taf_check_write_protect(dev, pckt->flash_addr, + pckt->len, taf_data_ptr->tag)) { + LOG_ERR("Access protection region"); + return -EINVAL; + } + + rc = flash_write(spi_dev, pckt->flash_addr, data_ptr, pckt->len); + if (rc) { + LOG_ERR("flash write fail 0x%x", rc); + return -EIO; + } + + taf_head.pkt_len = NPCX_TAF_CMP_HEADER_LEN; + taf_head.type = CYC_SCS_CMP_WITHOUT_DATA; + taf_head.tag_hlen = (taf_data_ptr->tag << 4); + taf_head.llen = 0x0; + memcpy(data_ptr, &taf_head, sizeof(taf_head)); + + rc = taf_npcx_completion_handler(dev, (uint32_t *)taf_data_ptr->data); + if (rc) { + LOG_ERR("espi taf completion handler fail"); + return rc; + } + + return 0; +} + +static int espi_taf_npcx_flash_erase(const struct device *dev, struct espi_saf_packet *pckt) +{ + struct espi_taf_npcx_pckt *taf_data_ptr = (struct espi_taf_npcx_pckt *)pckt->buf; + uint8_t *data_ptr = (uint8_t *)taf_data_ptr->data; + uint32_t addr = pckt->flash_addr; + uint32_t len = pckt->len; + struct npcx_taf_head taf_head; + int rc; + + if (espi_taf_check_write_protect(dev, addr, len, taf_data_ptr->tag)) { + LOG_ERR("Access protection region"); + return -EINVAL; + } + + rc = flash_erase(spi_dev, addr, len); + if (rc) { + LOG_ERR("flash erase fail"); + return -EIO; + } + + taf_head.pkt_len = NPCX_TAF_CMP_HEADER_LEN; + taf_head.type = CYC_SCS_CMP_WITHOUT_DATA; + taf_head.tag_hlen = (taf_data_ptr->tag << 4); + taf_head.llen = 0x0; + memcpy(data_ptr, &taf_head, sizeof(taf_head)); + + rc = taf_npcx_completion_handler(dev, (uint32_t *)taf_data_ptr->data); + if (rc) { + LOG_ERR("espi taf completion handler fail"); + return rc; + } + + return 0; +} + +static int espi_taf_npcx_flash_unsuccess(const struct device *dev, struct espi_saf_packet *pckt) +{ + struct espi_taf_npcx_pckt *taf_data_ptr + = (struct espi_taf_npcx_pckt *)pckt->buf; + uint8_t *data_ptr = (uint8_t *)taf_data_ptr->data; + struct npcx_taf_head taf_head; + int rc; + + taf_head.pkt_len = NPCX_TAF_CMP_HEADER_LEN; + taf_head.type = CYC_UNSCS_CMP_WITHOUT_DATA_ONLY; + taf_head.tag_hlen = (taf_data_ptr->tag << 4); + taf_head.llen = 0x0; + memcpy(data_ptr, &taf_head, sizeof(taf_head)); + + rc = taf_npcx_completion_handler(dev, (uint32_t *)taf_data_ptr->data); + if (rc) { + LOG_ERR("espi taf completion handler fail"); + return rc; + } + + return 0; +} + +static int espi_taf_npcx_init(const struct device *dev) +{ + struct espi_reg *const inst = HAL_INSTANCE(dev); + struct espi_taf_npcx_config *config = ((struct espi_taf_npcx_config *)(dev)->config); + + SET_FIELD(inst->FLASHCFG, NPCX_FLASHCFG_FLCAPA, + NPCX_FLASH_SHARING_CAP_SUPP_TAF_AND_CAF); + SET_FIELD(inst->FLASHCFG, NPCX_FLASHCFG_TRGFLEBLKSIZE, + BIT(config->erase_sz)); + SET_FIELD(inst->FLASHCFG, NPCX_FLASHCFG_FLREQSUP, + config->max_rd_sz); + inst->FLASHBASE = config->mapped_addr; + + return 0; +} + +static const struct espi_saf_driver_api espi_taf_npcx_driver_api = { + .config = espi_taf_npcx_configure, + .set_protection_regions = espi_taf_npcx_set_pr, + .activate = espi_taf_npcx_activate, + .get_channel_status = espi_taf_npcx_channel_ready, + .flash_read = espi_taf_npcx_flash_read, + .flash_write = espi_taf_npcx_flash_write, + .flash_erase = espi_taf_npcx_flash_erase, + .flash_unsuccess = espi_taf_npcx_flash_unsuccess, +}; + +static struct espi_taf_npcx_data npcx_espi_taf_data; + +static const struct espi_taf_npcx_config espi_taf_npcx_config = { + .base = DT_INST_REG_ADDR(0), + .mapped_addr = DT_INST_PROP(0, mapped_addr), + .rx_plsz = DT_PROP(DT_INST_PARENT(0), rx_plsize), + .erase_sz = DT_INST_STRING_TOKEN(0, erase_sz), + .max_rd_sz = DT_INST_STRING_TOKEN(0, max_read_sz), +}; + +DEVICE_DT_INST_DEFINE(0, &espi_taf_npcx_init, NULL, + &npcx_espi_taf_data, &espi_taf_npcx_config, + PRE_KERNEL_2, CONFIG_ESPI_INIT_PRIORITY, + &espi_taf_npcx_driver_api); diff --git a/dts/arm/nuvoton/npcx/npcx4.dtsi b/dts/arm/nuvoton/npcx/npcx4.dtsi index e18bd89f103..5cc63cb658e 100644 --- a/dts/arm/nuvoton/npcx/npcx4.dtsi +++ b/dts/arm/nuvoton/npcx/npcx4.dtsi @@ -306,6 +306,17 @@ buffer-tx-size = <128>; shi-cs-wui =<&wui_io53>; }; + + espi0: espi@4000a000 { + rx-plsize = <64>; + tx-plsize = <64>; + + espi_taf: espitaf@4000a000 { + compatible = "nuvoton,npcx-espi-taf"; + reg = <0x4000a000 0x2000>; + status = "disabled"; + }; + }; }; soc-if { diff --git a/dts/arm/nuvoton/npcx/npcx7.dtsi b/dts/arm/nuvoton/npcx/npcx7.dtsi index 29be4fcc1f3..be003127596 100644 --- a/dts/arm/nuvoton/npcx/npcx7.dtsi +++ b/dts/arm/nuvoton/npcx/npcx7.dtsi @@ -255,6 +255,11 @@ buffer-tx-size = <128>; shi-cs-wui =<&wui_io53>; }; + + espi0: espi@4000a000 { + rx-plsize = <64>; + tx-plsize = <16>; + }; }; soc-id { diff --git a/dts/arm/nuvoton/npcx/npcx9.dtsi b/dts/arm/nuvoton/npcx/npcx9.dtsi index f4716d7947e..e3004ab879d 100644 --- a/dts/arm/nuvoton/npcx/npcx9.dtsi +++ b/dts/arm/nuvoton/npcx/npcx9.dtsi @@ -283,6 +283,11 @@ buffer-tx-size = <128>; shi-cs-wui =<&wui_io53>; }; + + espi0: espi@4000a000 { + rx-plsize = <64>; + tx-plsize = <16>; + }; }; soc-id { diff --git a/dts/bindings/espi/nuvoton,npcx-espi-taf.yaml b/dts/bindings/espi/nuvoton,npcx-espi-taf.yaml new file mode 100644 index 00000000000..115f8e5e4a4 --- /dev/null +++ b/dts/bindings/espi/nuvoton,npcx-espi-taf.yaml @@ -0,0 +1,60 @@ +# Copyright (c) 2023 Nuvoton Technology Corporation. +# SPDX-License-Identifier: Apache-2.0 + +description: | + The target flash devices accessed by Nuvoton eSPI TAF controller. + + Representation: + + espi_taf: espitaf@4000a000 { + compatible = "nuvoton,npcx-espi-taf"; + reg = <0x4000a000 0x2000>; + + mapped-addr = <0x68000000>; + max-read-sz = "NPCX_ESPI_TAF_MAX_READ_REQ_64B"; + erase-sz = "NPCX_ESPI_TAF_ERASE_BLOCK_SIZE_4KB"; + + #address-cells = <1>; + #size-cells = <1>; + status = "okay"; + }; + +compatible: "nuvoton,npcx-espi-taf" + +include: [espi-controller.yaml, pinctrl-device.yaml] + +properties: + mapped-addr: + type: int + description: | + Mapped memory address of direct read access for flash. + required: true + + erase-sz: + type: string + required: true + description: | + Erase block size of target flash. The default was 4KB Erase Block Size. + All Intel platforms require support for at least 4 KB Erase Block Size. + default: "NPCX_ESPI_TAF_ERASE_BLOCK_SIZE_4KB" + enum: + - "NPCX_ESPI_TAF_ERASE_BLOCK_SIZE_4KB" + - "NPCX_ESPI_TAF_ERASE_BLOCK_SIZE_32KB" + - "NPCX_ESPI_TAF_ERASE_BLOCK_SIZE_64KB" + - "NPCX_ESPI_TAF_ERASE_BLOCK_SIZE_128KB" + + max-read-sz: + type: string + required: true + description: | + Maximum read request size of flash access channel. The default was 64 bytes. + This value is recommended in datasheet. + default: "NPCX_ESPI_TAF_MAX_READ_REQ_64B" + enum: + - "NPCX_ESPI_TAF_MAX_READ_REQ_64B" + - "NPCX_ESPI_TAF_MAX_READ_REQ_128B" + - "NPCX_ESPI_TAF_MAX_READ_REQ_256B" + - "NPCX_ESPI_TAF_MAX_READ_REQ_512B" + - "NPCX_ESPI_TAF_MAX_READ_REQ_1024B" + - "NPCX_ESPI_TAF_MAX_READ_REQ_2048B" + - "NPCX_ESPI_TAF_MAX_READ_REQ_4096B" diff --git a/dts/bindings/espi/nuvoton,npcx-espi.yaml b/dts/bindings/espi/nuvoton,npcx-espi.yaml index ebce305a3af..e53c3acb94b 100644 --- a/dts/bindings/espi/nuvoton,npcx-espi.yaml +++ b/dts/bindings/espi/nuvoton,npcx-espi.yaml @@ -30,3 +30,13 @@ properties: For example the WUI mapping on NPCX7 would be espi-rst-wui = <&wui_cr_sin1>; + + rx-plsize: + type: int + required: true + description: The maximum receive channel payload size. + + tx-plsize: + type: int + required: true + description: The maximum transmit channel payload size. diff --git a/include/zephyr/drivers/espi_saf.h b/include/zephyr/drivers/espi_saf.h index 9c6f47d1590..31fc23c0808 100644 --- a/include/zephyr/drivers/espi_saf.h +++ b/include/zephyr/drivers/espi_saf.h @@ -145,6 +145,8 @@ typedef int (*espi_saf_api_flash_write)(const struct device *dev, struct espi_saf_packet *pckt); typedef int (*espi_saf_api_flash_erase)(const struct device *dev, struct espi_saf_packet *pckt); +typedef int (*espi_saf_api_flash_unsuccess)(const struct device *dev, + struct espi_saf_packet *pckt); /* Callbacks and traffic intercept */ typedef int (*espi_saf_api_manage_callback)(const struct device *dev, struct espi_callback *callback, @@ -158,6 +160,7 @@ __subsystem struct espi_saf_driver_api { espi_saf_api_flash_read flash_read; espi_saf_api_flash_write flash_write; espi_saf_api_flash_erase flash_erase; + espi_saf_api_flash_unsuccess flash_unsuccess; espi_saf_api_manage_callback manage_callback; }; @@ -383,6 +386,35 @@ static inline int z_impl_espi_saf_flash_erase(const struct device *dev, return api->flash_erase(dev, pckt); } +/** + * @brief Response unsuccessful completion for slave attached flash. + * + * This routines provides an interface to response that transaction is + * invalid and return unsuccessful completion from target to controller. + * + * @param dev Pointer to the device structure for the driver instance. + * @param pckt Address of the representation of flash transaction. + * + * @retval -ENOTSUP eSPI flash logical channel transactions not supported. + * @retval -EBUSY eSPI flash channel is not ready or disabled by master. + * @retval -EIO General input / output error, failed request to master. + */ +__syscall int espi_saf_flash_unsuccess(const struct device *dev, + struct espi_saf_packet *pckt); + +static inline int z_impl_espi_saf_flash_unsuccess(const struct device *dev, + struct espi_saf_packet *pckt) +{ + const struct espi_saf_driver_api *api = + (const struct espi_saf_driver_api *)dev->api; + + if (!api->flash_unsuccess) { + return -ENOTSUP; + } + + return api->flash_unsuccess(dev, pckt); +} + /** * Callback model * diff --git a/soc/arm/nuvoton_npcx/common/reg/reg_access.h b/soc/arm/nuvoton_npcx/common/reg/reg_access.h index 4f302f51461..ae1d6a61694 100644 --- a/soc/arm/nuvoton_npcx/common/reg/reg_access.h +++ b/soc/arm/nuvoton_npcx/common/reg/reg_access.h @@ -27,4 +27,12 @@ ((reg) = ((reg) & (~(((1 << (f_size))-1) << (f_pos)))) \ | ((value) << (f_pos))) +#define GET_FIELD_POS(field) \ + _GET_FIELD_POS_(FIELD_POS(field)) +#define _GET_FIELD_POS_(f_ops) f_ops + +#define GET_FIELD_SZ(field) \ + _GET_FIELD_SZ_(FIELD_SIZE(field)) +#define _GET_FIELD_SZ_(f_ops) f_ops + #endif /* _NUVOTON_NPCX_REG_ACCESS_H */ diff --git a/soc/arm/nuvoton_npcx/common/reg/reg_def.h b/soc/arm/nuvoton_npcx/common/reg/reg_def.h index d6b081533df..76cab3a6624 100644 --- a/soc/arm/nuvoton_npcx/common/reg/reg_def.h +++ b/soc/arm/nuvoton_npcx/common/reg/reg_def.h @@ -625,14 +625,35 @@ struct espi_reg { volatile uint32_t reserved8[11]; /* 0x3FC: OOB Channel Control used in 'direct' mode */ volatile uint32_t OOBCTL_DIRECT; - /* 0x400 - 443: Flash Receive Buffer 0-16 */ - volatile uint32_t FLASHRXBUF[17]; - volatile uint32_t reserved9[15]; - /* 0x480 - 497: Flash Transmit Buffer 0-5 */ - volatile uint32_t FLASHTXBUF[6]; - volatile uint32_t reserved10[25]; + /* 0x400 - 443: Flash Receive Buffer 0-17 */ + volatile uint32_t FLASHRXBUF[18]; + volatile uint32_t reserved9[14]; + /* 0x480 - 497: Flash Transmit Buffer 0-16 */ + volatile uint32_t FLASHTXBUF[17]; + volatile uint32_t reserved10[14]; /* 0x4FC: Flash Channel Control used in 'direct' mode */ volatile uint32_t FLASHCTL_DIRECT; + volatile uint32_t reserved12[64]; + /* 0x600 - 63F */ + volatile uint32_t FLASH_PRTR_BADDR[16]; + /* 0x640 - 67F */ + volatile uint32_t FLASH_PRTR_HADDR[16]; + /* 0x680 - 6BF */ + volatile uint32_t FLASH_RGN_TAG_OVR[16]; + volatile uint32_t reserved13[80]; + /* 0x800 */ + volatile uint32_t FLASH_RPMC_CFG_1; + /* 0x804 */ + volatile uint32_t FLASH_RPMC_CFG_2; + /* 0x808 */ + volatile uint32_t RMAP_FLASH_OFFS; + /* 0x80C */ + volatile uint32_t RMAP_DST_BASE; + /* 0x810 */ + volatile uint32_t RMAP_WIN_SIZE; + /* 0x814 */ + volatile uint32_t FLASHBASE; + volatile uint32_t reserved14[58]; }; /* eSPI register fields */ @@ -648,6 +669,7 @@ struct espi_reg { #define NPCX_ESPICFG_HCHANS_FIELD FIELD(4, 4) #define NPCX_ESPICFG_IOMODE_FIELD FIELD(8, 2) #define NPCX_ESPICFG_MAXFREQ_FIELD FIELD(10, 3) +#define NPCX_ESPICFG_FLCHANMODE 16 #define NPCX_ESPICFG_PCCHN_SUPP 24 #define NPCX_ESPICFG_VWCHN_SUPP 25 #define NPCX_ESPICFG_OOBCHN_SUPP 26 @@ -657,7 +679,7 @@ struct espi_reg { #define NPCX_ESPIIE_BERRIE 2 #define NPCX_ESPIIE_OOBRXIE 3 #define NPCX_ESPIIE_FLASHRXIE 4 -#define NPCX_ESPIIE_SFLASHRDIE 5 +#define NPCX_ESPIIE_FLNACSIE 5 #define NPCX_ESPIIE_PERACCIE 6 #define NPCX_ESPIIE_DFRDIE 7 #define NPCX_ESPIIE_VWUPDIE 8 @@ -675,6 +697,7 @@ struct espi_reg { #define NPCX_ESPIWE_BERRWE 2 #define NPCX_ESPIWE_OOBRXWE 3 #define NPCX_ESPIWE_FLASHRXWE 4 +#define NPCX_ESPIWE_FLNACSWE 5 #define NPCX_ESPIWE_PERACCWE 6 #define NPCX_ESPIWE_DFRDWE 7 #define NPCX_ESPIWE_VWUPDWE 8 @@ -686,6 +709,7 @@ struct espi_reg { #define NPCX_ESPISTS_BERR 2 #define NPCX_ESPISTS_OOBRX 3 #define NPCX_ESPISTS_FLASHRX 4 +#define NPCX_ESPISTS_FLNACS 5 #define NPCX_ESPISTS_PERACC 6 #define NPCX_ESPISTS_DFRD 7 #define NPCX_ESPISTS_VWUPD 8 @@ -700,6 +724,14 @@ struct espi_reg { #define NPCX_ESPISTS_BMBURSTERR 22 #define NPCX_ESPISTS_BMBURSTDONE 23 #define NPCX_ESPISTS_ESPIRST_LVL 24 +#define NPCX_VWSWIRQ_IRQ_NUM FIELD(0, 7) +#define NPCX_VWSWIRQ_IRQ_LVL 7 +#define NPCX_VWSWIRQ_INDEX FIELD(8, 7) +#define NPCX_VWSWIRQ_INDEX_EN 15 +#define NPCX_VWSWIRQ_DIRTY 16 +#define NPCX_VWSWIRQ_ENPLTRST 17 +#define NPCX_VWSWIRQ_ENCDRST 19 +#define NPCX_VWSWIRQ_EDGE_IRQ 28 #define NPCX_VWEVMS_WIRE FIELD(0, 4) #define NPCX_VWEVMS_VALID FIELD(4, 4) #define NPCX_VWEVMS_IE 18 @@ -716,6 +748,9 @@ struct espi_reg { #define NPCX_FLASHCFG_FLASHBLERSSIZE FIELD(7, 3) #define NPCX_FLASHCFG_FLASHPLSIZE FIELD(10, 3) #define NPCX_FLASHCFG_FLASHREQSIZE FIELD(13, 3) +#define NPCX_FLASHCFG_FLCAPA FIELD(24, 2) +#define NPCX_FLASHCFG_TRGFLEBLKSIZE FIELD(16, 8) +#define NPCX_FLASHCFG_FLREQSUP FIELD(0, 3) #define NPCX_FLASHCTL_FLASH_NP_FREE 0 #define NPCX_FLASHCTL_FLASH_TX_AVAIL 1 #define NPCX_FLASHCTL_STRPHDR 2 @@ -725,10 +760,21 @@ struct espi_reg { #define NPCX_FLASHCTL_CRCEN 14 #define NPCX_FLASHCTL_CHKSUMSEL 15 #define NPCX_FLASHCTL_AMTEN 16 - +#define NPCX_FLASHCTL_SAF_AUTO_READ 18 +#define NPCX_FLASHCTL_AUTO_RD_DIS_CTL 19 +#define NPCX_FLASHCTL_BLK_FLASH_NP_FREE 20 +#define NPCX_FLASHBASE_FLBASE_ADDR FIELD(12, 15) +#define NPCX_FLASH_PRTR_BADDR FIELD(12, 15) +#define NPCX_FRGN_WPR 29 +#define SAF_PROT_LCK 31 +#define NPCX_FRGN_RPR 30 +#define NPCX_FLASH_PRTR_HADDR FIELD(12, 15) +#define NPCX_FLASH_TAG_OVR_RPR FIELD(16, 16) +#define NPCX_FLASH_TAG_OVR_WPR FIELD(0, 16) #define NPCX_ONLY_ESPI_REG1_UNLOCK_REG2 0x55 #define NPCX_ONLY_ESPI_REG1_LOCK_REG2 0 #define NPCX_ONLY_ESPI_REG2_TRANS_END_CONFIG 4 + /* * Mobile System Wake-Up Control (MSWC) device registers */ diff --git a/soc/arm/nuvoton_npcx/common/registers.c b/soc/arm/nuvoton_npcx/common/registers.c index 0405bee3567..d2e64d290ca 100644 --- a/soc/arm/nuvoton_npcx/common/registers.c +++ b/soc/arm/nuvoton_npcx/common/registers.c @@ -62,7 +62,7 @@ NPCX_REG_OFFSET_CHECK(twd_reg, TWMWD, 0x00e); NPCX_REG_OFFSET_CHECK(twd_reg, WDCP, 0x010); /* ESPI register structure check */ -NPCX_REG_SIZE_CHECK(espi_reg, 0x500); +NPCX_REG_SIZE_CHECK(espi_reg, 0x900); NPCX_REG_OFFSET_CHECK(espi_reg, FLASHCFG, 0x034); NPCX_REG_OFFSET_CHECK(espi_reg, NPCX_ONLY_ESPI_REG1, 0x0f0); NPCX_REG_OFFSET_CHECK(espi_reg, VWEVMS, 0x140); diff --git a/soc/arm/nuvoton_npcx/common/soc_espi_taf.h b/soc/arm/nuvoton_npcx/common/soc_espi_taf.h new file mode 100644 index 00000000000..a8755e080f7 --- /dev/null +++ b/soc/arm/nuvoton_npcx/common/soc_espi_taf.h @@ -0,0 +1,151 @@ +/* + * Copyright (c) 2023 Nuvoton Technology Corporation. + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#ifndef _NUVOTON_NPCX_SOC_ESPI_TAF_H_ +#define _NUVOTON_NPCX_SOC_ESPI_TAF_H_ + +#include + +#ifdef __cplusplus +extern "C" { +#endif + +/* Transmit buffer for eSPI TAF transaction on NPCX */ +/* +-------------+--------------+--------------+---------------+ */ +/* | Byte 3 | Byte 2 | Byte 1 | Byte 0 | */ +/* +-------------+--------------+--------------+---------------+ */ +/* | Length | Tag |Length | Type | PKT_LEN | */ +/* | [7:0] | |[11:8] | | | */ +/* +-------------+--------------+--------------+---------------+ */ +/* | Data 3 | Data 2 | Data 1 | Data 0 | */ +/* +-------------+--------------+--------------+---------------+ */ +/* | Data 7 | Data 6 | Data 5 | Data 4 | */ +/* +-------------+--------------+--------------+---------------+ */ +/* | ... | ... | ... | ... | */ +/* +-------------+--------------+--------------+---------------+ */ +/* | Data 63 | Data 62 | Data 61 | Data 60 | */ +/* +-------------+--------------+--------------+---------------+ */ +/* PKT_LEN holds the sum of header (Type, Tag and Length) length */ +/* and data length */ + +/* + * NPCX_TAF_CMP_HEADER_LEN is the preamble length of Type, Length + * and Tag (i.e. byte 1~byte 3) for flash access completion packet + * on NPCX + */ +#define NPCX_TAF_CMP_HEADER_LEN 3 + +/* Successful Completion Without Data */ +#define CYC_SCS_CMP_WITHOUT_DATA 0x06 +/* Successful middle Completion With Data */ +#define CYC_SCS_CMP_WITH_DATA_MIDDLE 0x09 +/* Successful first Completion With Data */ +#define CYC_SCS_CMP_WITH_DATA_FIRST 0x0B +/* Successful last Completion With Data */ +#define CYC_SCS_CMP_WITH_DATA_LAST 0x0D +/* Successful only Completion With Data */ +#define CYC_SCS_CMP_WITH_DATA_ONLY 0x0F +/* Unsuccessful Completion Without Data */ +#define CYC_UNSCS_CMP_WITHOUT_DATA 0x08 +/* Unsuccessful Last Completion Without Data */ +#define CYC_UNSCS_CMP_WITHOUT_DATA_LAST 0x0C +/* Unsuccessful Only Completion Without Data */ +#define CYC_UNSCS_CMP_WITHOUT_DATA_ONLY 0x0E + +/* Timeout for checking transmit buffer available and no completion was sent */ +#define NPCX_FLASH_CHK_TIMEOUT 10000 + +/* Clear RSTBUFHEADS, FLASH_ACC_TX_AVAIL, and FLASH_ACC_NP_FREE */ +#define NPCX_FLASHCTL_ACCESS_MASK (~(BIT(NPCX_FLASHCTL_RSTBUFHEADS) | \ + BIT(NPCX_FLASHCTL_FLASH_NP_FREE) | \ + BIT(NPCX_FLASHCTL_FLASH_TX_AVAIL))) + +/* Flash Sharing Capability Support */ +#define NPCX_FLASH_SHARING_CAP_SUPP_CAF 0 +#define NPCX_FLASH_SHARING_CAP_SUPP_TAF 2 +#define NPCX_FLASH_SHARING_CAP_SUPP_TAF_AND_CAF 3 + +enum NPCX_ESPI_TAF_REQ { + NPCX_ESPI_TAF_REQ_READ, + NPCX_ESPI_TAF_REQ_WRITE, + NPCX_ESPI_TAF_REQ_ERASE, + NPCX_ESPI_TAF_REQ_RPMC_OP1, + NPCX_ESPI_TAF_REQ_RPMC_OP2, + NPCX_ESPI_TAF_REQ_UNKNOWN, +}; + +/* NPCX_ESPI_TAF_ERASE_BLOCK_SIZE_4KB is default */ +enum NPCX_ESPI_TAF_ERASE_BLOCK_SIZE { + NPCX_ESPI_TAF_ERASE_BLOCK_SIZE_1KB, + NPCX_ESPI_TAF_ERASE_BLOCK_SIZE_2KB, + NPCX_ESPI_TAF_ERASE_BLOCK_SIZE_4KB, + NPCX_ESPI_TAF_ERASE_BLOCK_SIZE_8KB, + NPCX_ESPI_TAF_ERASE_BLOCK_SIZE_16KB, + NPCX_ESPI_TAF_ERASE_BLOCK_SIZE_32KB, + NPCX_ESPI_TAF_ERASE_BLOCK_SIZE_64KB, + NPCX_ESPI_TAF_ERASE_BLOCK_SIZE_128KB, +}; + +/* NPCX_ESPI_TAF_MAX_READ_REQ_64B is default */ +enum NPCX_ESPI_TAF_MAX_READ_REQ { + NPCX_ESPI_TAF_MAX_READ_REQ_64B = 1, + NPCX_ESPI_TAF_MAX_READ_REQ_128B, + NPCX_ESPI_TAF_MAX_READ_REQ_256B, + NPCX_ESPI_TAF_MAX_READ_REQ_512B, + NPCX_ESPI_TAF_MAX_READ_REQ_1024B, + NPCX_ESPI_TAF_MAX_READ_REQ_2048B, + NPCX_ESPI_TAF_MAX_READ_REQ_4096B, +}; + +/* + * The configurations of SPI flash are set in FIU module. + * Thus, eSPI TAF driver of NPCX does not need additional hardware configuarations. + * Therefore, define an empty structure here to comply with espi_saf.h + */ +struct espi_saf_hw_cfg { +}; + +struct espi_saf_pr { + uint32_t start; + uint32_t end; + uint16_t override_r; + uint16_t override_w; + uint8_t master_bm_we; + uint8_t master_bm_rd; + uint8_t pr_num; + uint8_t flags; +}; + +struct espi_saf_protection { + size_t nregions; + const struct espi_saf_pr *pregions; +}; + +struct espi_taf_npcx_pckt { + uint8_t tag; + uint8_t *data; +}; + +struct espi_taf_pckt { + uint8_t type; + uint8_t tag; + uint32_t addr; + uint16_t len; + uint32_t src[16]; +}; + +struct npcx_taf_head { + uint8_t pkt_len; + uint8_t type; + uint8_t tag_hlen; + uint8_t llen; +}; + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/soc/arm/nuvoton_npcx/npcx4/Kconfig.defconfig.series b/soc/arm/nuvoton_npcx/npcx4/Kconfig.defconfig.series index 377575b1d9f..1b692cf7621 100644 --- a/soc/arm/nuvoton_npcx/npcx4/Kconfig.defconfig.series +++ b/soc/arm/nuvoton_npcx/npcx4/Kconfig.defconfig.series @@ -14,6 +14,10 @@ config NUM_IRQS config CORTEX_M_SYSTICK default !NPCX_ITIM_TIMER +config ESPI_TAF_NPCX + default y + depends on ESPI_SAF + source "soc/arm/nuvoton_npcx/npcx4/Kconfig.defconfig.npcx4*" endif # SOC_SERIES_NPCX4 diff --git a/soc/arm/nuvoton_npcx/npcx4/soc.h b/soc/arm/nuvoton_npcx/npcx4/soc.h index 9c780ca034a..4ada738102c 100644 --- a/soc/arm/nuvoton_npcx/npcx4/soc.h +++ b/soc/arm/nuvoton_npcx/npcx4/soc.h @@ -53,6 +53,7 @@ #include #include #include +#include #include #include From 26577a18b080628e5a6e91e882424267ba357755 Mon Sep 17 00:00:00 2001 From: Ian Morris Date: Fri, 8 Dec 2023 16:49:41 -0800 Subject: [PATCH 1346/3723] dt-bindings: pinctrl: renesas: fix r7fa4m1 pin config numbering Pin configuration value generated by RA_PINCFG_xxx macro is incorrect if pin number is greater than 9 due to a mistake in the pin numbering. Signed-off-by: Ian Morris --- .../pinctrl/renesas/pinctrl-r7fa4m1xxxxxx.h | 192 +++++++++--------- 1 file changed, 96 insertions(+), 96 deletions(-) diff --git a/include/zephyr/dt-bindings/pinctrl/renesas/pinctrl-r7fa4m1xxxxxx.h b/include/zephyr/dt-bindings/pinctrl/renesas/pinctrl-r7fa4m1xxxxxx.h index dfe21b00183..e5466757653 100644 --- a/include/zephyr/dt-bindings/pinctrl/renesas/pinctrl-r7fa4m1xxxxxx.h +++ b/include/zephyr/dt-bindings/pinctrl/renesas/pinctrl-r7fa4m1xxxxxx.h @@ -28,21 +28,21 @@ #define P007_AMP3O RA_PINCFG_100(0, 7, 0x02, RA_PINCFG_FUNC | RA_PINCFG_ANALOG) #define P007_AN013 RA_PINCFG_100(0, 7, 0x01, RA_PINCFG_ANALOG) #define P008_AN014 RA_PINCFG_100(0, 8, 0x01, RA_PINCFG_ANALOG) -#define P010_AMP2M RA_PINCFG__40(0, 0, 0x02, RA_PINCFG_FUNC | RA_PINCFG_ANALOG) -#define P010_AN005 RA_PINCFG__40(0, 0, 0x01, RA_PINCFG_ANALOG) -#define P010_TS30 RA_PINCFG__40(0, 0, 0x0C, RA_PINCFG_FUNC) -#define P010_VREFH0 RA_PINCFG__40(0, 0, 0x03, RA_PINCFG_FUNC | RA_PINCFG_ANALOG) -#define P011_AN006 RA_PINCFG__40(0, 1, 0x01, RA_PINCFG_ANALOG) -#define P011_TS31 RA_PINCFG__40(0, 1, 0x0C, RA_PINCFG_FUNC) -#define P011_VREFL0 RA_PINCFG__40(0, 1, 0x03, RA_PINCFG_FUNC | RA_PINCFG_ANALOG) -#define P012_AN007 RA_PINCFG__40(0, 2, 0x01, RA_PINCFG_ANALOG) -#define P012_VREFH RA_PINCFG__40(0, 2, 0x03, RA_PINCFG_FUNC | RA_PINCFG_ANALOG) -#define P013_AN008 RA_PINCFG__40(0, 3, 0x01, RA_PINCFG_ANALOG) -#define P013_VREFL RA_PINCFG__40(0, 3, 0x03, RA_PINCFG_FUNC | RA_PINCFG_ANALOG) -#define P014_AN009 RA_PINCFG__40(0, 4, 0x01, RA_PINCFG_ANALOG) -#define P014_DA0 RA_PINCFG__40(0, 4, 0x02, RA_PINCFG_FUNC | RA_PINCFG_ANALOG) -#define P015_AN010 RA_PINCFG__40(0, 5, 0x01, RA_PINCFG_ANALOG) -#define P015_TS28 RA_PINCFG__40(0, 5, 0x0C, RA_PINCFG_FUNC) +#define P010_AMP2M RA_PINCFG__40(0, 10, 0x02, RA_PINCFG_FUNC | RA_PINCFG_ANALOG) +#define P010_AN005 RA_PINCFG__40(0, 10, 0x01, RA_PINCFG_ANALOG) +#define P010_TS30 RA_PINCFG__40(0, 10, 0x0C, RA_PINCFG_FUNC) +#define P010_VREFH0 RA_PINCFG__40(0, 10, 0x03, RA_PINCFG_FUNC | RA_PINCFG_ANALOG) +#define P011_AN006 RA_PINCFG__40(0, 11, 0x01, RA_PINCFG_ANALOG) +#define P011_TS31 RA_PINCFG__40(0, 11, 0x0C, RA_PINCFG_FUNC) +#define P011_VREFL0 RA_PINCFG__40(0, 11, 0x03, RA_PINCFG_FUNC | RA_PINCFG_ANALOG) +#define P012_AN007 RA_PINCFG__40(0, 12, 0x01, RA_PINCFG_ANALOG) +#define P012_VREFH RA_PINCFG__40(0, 12, 0x03, RA_PINCFG_FUNC | RA_PINCFG_ANALOG) +#define P013_AN008 RA_PINCFG__40(0, 13, 0x01, RA_PINCFG_ANALOG) +#define P013_VREFL RA_PINCFG__40(0, 13, 0x03, RA_PINCFG_FUNC | RA_PINCFG_ANALOG) +#define P014_AN009 RA_PINCFG__40(0, 14, 0x01, RA_PINCFG_ANALOG) +#define P014_DA0 RA_PINCFG__40(0, 14, 0x02, RA_PINCFG_FUNC | RA_PINCFG_ANALOG) +#define P015_AN010 RA_PINCFG__40(0, 15, 0x01, RA_PINCFG_ANALOG) +#define P015_TS28 RA_PINCFG__40(0, 15, 0x0C, RA_PINCFG_FUNC) #define P100_AGTIO0 RA_PINCFG__40(1, 0, 0x01, RA_PINCFG_FUNC) #define P100_AN022 RA_PINCFG__40(1, 0, 0x01, RA_PINCFG_ANALOG) #define P100_CMPIN0 RA_PINCFG__40(1, 0, 0x02, RA_PINCFG_FUNC | RA_PINCFG_ANALOG) @@ -132,45 +132,45 @@ #define P109_SEG23 RA_PINCFG__40(1, 9, 0x0D, RA_PINCFG_FUNC) #define P109_TS10 RA_PINCFG__40(1, 9, 0x0C, RA_PINCFG_FUNC) #define P109_TXD9 RA_PINCFG__40(1, 9, 0x05, RA_PINCFG_FUNC) -#define P110_CRX0 RA_PINCFG__40(1, 0, 0x10, RA_PINCFG_FUNC) -#define P110_CTS2_RTS2 RA_PINCFG__40(1, 0, 0x04, RA_PINCFG_FUNC) -#define P110_GTIOC1B RA_PINCFG__40(1, 0, 0x03, RA_PINCFG_FUNC) -#define P110_GTOVLO RA_PINCFG__40(1, 0, 0x02, RA_PINCFG_FUNC) -#define P110_MISO9 RA_PINCFG__40(1, 0, 0x05, RA_PINCFG_FUNC) -#define P110_MISOB RA_PINCFG__40(1, 0, 0x06, RA_PINCFG_FUNC) -#define P110_RXD9 RA_PINCFG__40(1, 0, 0x05, RA_PINCFG_FUNC) -#define P110_SCL9 RA_PINCFG__40(1, 0, 0x05, RA_PINCFG_FUNC) -#define P110_SEG24 RA_PINCFG__40(1, 0, 0x0D, RA_PINCFG_FUNC) -#define P110_SS2 RA_PINCFG__40(1, 0, 0x04, RA_PINCFG_FUNC) -#define P110_VCOUT RA_PINCFG__40(1, 0, 0x09, RA_PINCFG_FUNC) -#define P111_CAPH RA_PINCFG__40(1, 1, 0x0D, RA_PINCFG_FUNC) -#define P111_GTIOC3A RA_PINCFG__40(1, 1, 0x03, RA_PINCFG_FUNC) -#define P111_RSPCKB RA_PINCFG__40(1, 1, 0x06, RA_PINCFG_FUNC) -#define P111_SCK2 RA_PINCFG__40(1, 1, 0x04, RA_PINCFG_FUNC) -#define P111_SCK9 RA_PINCFG__40(1, 1, 0x05, RA_PINCFG_FUNC) -#define P111_TS12 RA_PINCFG__40(1, 1, 0x0C, RA_PINCFG_FUNC) -#define P112_CAPL RA_PINCFG__40(1, 2, 0x0D, RA_PINCFG_FUNC) -#define P112_GTIOC3B RA_PINCFG__40(1, 2, 0x03, RA_PINCFG_FUNC) -#define P112_MOSI2 RA_PINCFG__40(1, 2, 0x04, RA_PINCFG_FUNC) -#define P112_SCK1 RA_PINCFG__40(1, 2, 0x05, RA_PINCFG_FUNC) -#define P112_SDA2 RA_PINCFG__40(1, 2, 0x04, RA_PINCFG_FUNC) -#define P112_SSIBCK0 RA_PINCFG__40(1, 2, 0x12, RA_PINCFG_FUNC) -#define P112_SSLB0 RA_PINCFG__40(1, 2, 0x06, RA_PINCFG_FUNC) -#define P112_TSCAP RA_PINCFG__40(1, 2, 0x0C, RA_PINCFG_FUNC) -#define P112_TXD2 RA_PINCFG__40(1, 2, 0x04, RA_PINCFG_FUNC) -#define P113_GTIOC2A RA_PINCFG__64(1, 3, 0x03, RA_PINCFG_FUNC) -#define P113_SEG00COM4 RA_PINCFG__64(1, 3, 0x0D, RA_PINCFG_FUNC) -#define P113_SSIFS0 RA_PINCFG__64(1, 3, 0x12, RA_PINCFG_FUNC) -#define P113_SSILRCK0 RA_PINCFG__64(1, 3, 0x12, RA_PINCFG_FUNC) -#define P113_TS27 RA_PINCFG__64(1, 3, 0x0C, RA_PINCFG_FUNC) -#define P114_GTIOC2B RA_PINCFG_100(1, 4, 0x03, RA_PINCFG_FUNC) -#define P114_SEG25 RA_PINCFG_100(1, 4, 0x0D, RA_PINCFG_FUNC) -#define P114_SSIRXD0 RA_PINCFG_100(1, 4, 0x12, RA_PINCFG_FUNC) -#define P114_TS29 RA_PINCFG_100(1, 4, 0x0C, RA_PINCFG_FUNC) -#define P115_GTIOC4A RA_PINCFG_100(1, 5, 0x03, RA_PINCFG_FUNC) -#define P115_SEG26 RA_PINCFG_100(1, 5, 0x0D, RA_PINCFG_FUNC) -#define P115_SSITXD0 RA_PINCFG_100(1, 5, 0x12, RA_PINCFG_FUNC) -#define P115_TS35 RA_PINCFG_100(1, 5, 0x0C, RA_PINCFG_FUNC) +#define P110_CRX0 RA_PINCFG__40(1, 10, 0x10, RA_PINCFG_FUNC) +#define P110_CTS2_RTS2 RA_PINCFG__40(1, 10, 0x04, RA_PINCFG_FUNC) +#define P110_GTIOC1B RA_PINCFG__40(1, 10, 0x03, RA_PINCFG_FUNC) +#define P110_GTOVLO RA_PINCFG__40(1, 10, 0x02, RA_PINCFG_FUNC) +#define P110_MISO9 RA_PINCFG__40(1, 10, 0x05, RA_PINCFG_FUNC) +#define P110_MISOB RA_PINCFG__40(1, 10, 0x06, RA_PINCFG_FUNC) +#define P110_RXD9 RA_PINCFG__40(1, 10, 0x05, RA_PINCFG_FUNC) +#define P110_SCL9 RA_PINCFG__40(1, 10, 0x05, RA_PINCFG_FUNC) +#define P110_SEG24 RA_PINCFG__40(1, 10, 0x0D, RA_PINCFG_FUNC) +#define P110_SS2 RA_PINCFG__40(1, 10, 0x04, RA_PINCFG_FUNC) +#define P110_VCOUT RA_PINCFG__40(1, 10, 0x09, RA_PINCFG_FUNC) +#define P111_CAPH RA_PINCFG__40(1, 11, 0x0D, RA_PINCFG_FUNC) +#define P111_GTIOC3A RA_PINCFG__40(1, 11, 0x03, RA_PINCFG_FUNC) +#define P111_RSPCKB RA_PINCFG__40(1, 11, 0x06, RA_PINCFG_FUNC) +#define P111_SCK2 RA_PINCFG__40(1, 11, 0x04, RA_PINCFG_FUNC) +#define P111_SCK9 RA_PINCFG__40(1, 11, 0x05, RA_PINCFG_FUNC) +#define P111_TS12 RA_PINCFG__40(1, 11, 0x0C, RA_PINCFG_FUNC) +#define P112_CAPL RA_PINCFG__40(1, 12, 0x0D, RA_PINCFG_FUNC) +#define P112_GTIOC3B RA_PINCFG__40(1, 12, 0x03, RA_PINCFG_FUNC) +#define P112_MOSI2 RA_PINCFG__40(1, 12, 0x04, RA_PINCFG_FUNC) +#define P112_SCK1 RA_PINCFG__40(1, 12, 0x05, RA_PINCFG_FUNC) +#define P112_SDA2 RA_PINCFG__40(1, 12, 0x04, RA_PINCFG_FUNC) +#define P112_SSIBCK0 RA_PINCFG__40(1, 12, 0x12, RA_PINCFG_FUNC) +#define P112_SSLB0 RA_PINCFG__40(1, 12, 0x06, RA_PINCFG_FUNC) +#define P112_TSCAP RA_PINCFG__40(1, 12, 0x0C, RA_PINCFG_FUNC) +#define P112_TXD2 RA_PINCFG__40(1, 12, 0x04, RA_PINCFG_FUNC) +#define P113_GTIOC2A RA_PINCFG__64(1, 13, 0x03, RA_PINCFG_FUNC) +#define P113_SEG00COM4 RA_PINCFG__64(1, 13, 0x0D, RA_PINCFG_FUNC) +#define P113_SSIFS0 RA_PINCFG__64(1, 13, 0x12, RA_PINCFG_FUNC) +#define P113_SSILRCK0 RA_PINCFG__64(1, 13, 0x12, RA_PINCFG_FUNC) +#define P113_TS27 RA_PINCFG__64(1, 13, 0x0C, RA_PINCFG_FUNC) +#define P114_GTIOC2B RA_PINCFG_100(1, 14, 0x03, RA_PINCFG_FUNC) +#define P114_SEG25 RA_PINCFG_100(1, 14, 0x0D, RA_PINCFG_FUNC) +#define P114_SSIRXD0 RA_PINCFG_100(1, 14, 0x12, RA_PINCFG_FUNC) +#define P114_TS29 RA_PINCFG_100(1, 14, 0x0C, RA_PINCFG_FUNC) +#define P115_GTIOC4A RA_PINCFG_100(1, 15, 0x03, RA_PINCFG_FUNC) +#define P115_SEG26 RA_PINCFG_100(1, 15, 0x0D, RA_PINCFG_FUNC) +#define P115_SSITXD0 RA_PINCFG_100(1, 15, 0x12, RA_PINCFG_FUNC) +#define P115_TS35 RA_PINCFG_100(1, 15, 0x0C, RA_PINCFG_FUNC) #define P202_GTIOC5B RA_PINCFG_100(2, 2, 0x03, RA_PINCFG_FUNC) #define P202_MISO9 RA_PINCFG_100(2, 2, 0x05, RA_PINCFG_FUNC) #define P202_MISOB RA_PINCFG_100(2, 2, 0x06, RA_PINCFG_FUNC) @@ -221,17 +221,17 @@ #define P206_SSLB1 RA_PINCFG__48(2, 6, 0x06, RA_PINCFG_FUNC) #define P206_TS01 RA_PINCFG__48(2, 6, 0x0C, RA_PINCFG_FUNC) #define P206_USB_VBUSEN RA_PINCFG__48(2, 6, 0x13, RA_PINCFG_FUNC) -#define P212_AGTEE1 RA_PINCFG__40(2, 2, 0x01, RA_PINCFG_FUNC) -#define P212_GTETRGB RA_PINCFG__40(2, 2, 0x02, RA_PINCFG_FUNC) -#define P212_GTIOC0B RA_PINCFG__40(2, 2, 0x03, RA_PINCFG_FUNC) -#define P212_MISO1 RA_PINCFG__40(2, 2, 0x05, RA_PINCFG_FUNC) -#define P212_RXD1 RA_PINCFG__40(2, 2, 0x05, RA_PINCFG_FUNC) -#define P212_SCL1 RA_PINCFG__40(2, 2, 0x05, RA_PINCFG_FUNC) -#define P213_GTETRGA RA_PINCFG__40(2, 3, 0x02, RA_PINCFG_FUNC) -#define P213_GTIOC0A RA_PINCFG__40(2, 3, 0x03, RA_PINCFG_FUNC) -#define P213_MOSI1 RA_PINCFG__40(2, 3, 0x05, RA_PINCFG_FUNC) -#define P213_SDA1 RA_PINCFG__40(2, 3, 0x05, RA_PINCFG_FUNC) -#define P213_TXD1 RA_PINCFG__40(2, 3, 0x05, RA_PINCFG_FUNC) +#define P212_AGTEE1 RA_PINCFG__40(2, 12, 0x01, RA_PINCFG_FUNC) +#define P212_GTETRGB RA_PINCFG__40(2, 12, 0x02, RA_PINCFG_FUNC) +#define P212_GTIOC0B RA_PINCFG__40(2, 12, 0x03, RA_PINCFG_FUNC) +#define P212_MISO1 RA_PINCFG__40(2, 12, 0x05, RA_PINCFG_FUNC) +#define P212_RXD1 RA_PINCFG__40(2, 12, 0x05, RA_PINCFG_FUNC) +#define P212_SCL1 RA_PINCFG__40(2, 12, 0x05, RA_PINCFG_FUNC) +#define P213_GTETRGA RA_PINCFG__40(2, 13, 0x02, RA_PINCFG_FUNC) +#define P213_GTIOC0A RA_PINCFG__40(2, 13, 0x03, RA_PINCFG_FUNC) +#define P213_MOSI1 RA_PINCFG__40(2, 13, 0x05, RA_PINCFG_FUNC) +#define P213_SDA1 RA_PINCFG__40(2, 13, 0x05, RA_PINCFG_FUNC) +#define P213_TXD1 RA_PINCFG__40(2, 13, 0x05, RA_PINCFG_FUNC) #define P300_GTIOC0A RA_PINCFG__40(3, 0, 0x03, RA_PINCFG_FUNC) #define P300_GTOUUP RA_PINCFG__40(3, 0, 0x02, RA_PINCFG_FUNC) #define P300_SSLB1 RA_PINCFG__40(3, 0, 0x06, RA_PINCFG_FUNC) @@ -340,33 +340,33 @@ #define P409_TS05 RA_PINCFG__48(4, 9, 0x0C, RA_PINCFG_FUNC) #define P409_TXD9 RA_PINCFG__48(4, 9, 0x05, RA_PINCFG_FUNC) #define P409_USB_EXICEN RA_PINCFG__48(4, 9, 0x13, RA_PINCFG_FUNC) -#define P410_AGTOB1 RA_PINCFG__64(4, 0, 0x01, RA_PINCFG_FUNC) -#define P410_GTIOC6B RA_PINCFG__64(4, 0, 0x04, RA_PINCFG_FUNC) -#define P410_GTOVLO RA_PINCFG__64(4, 0, 0x03, RA_PINCFG_FUNC) -#define P410_MISO0 RA_PINCFG__64(4, 0, 0x04, RA_PINCFG_FUNC) -#define P410_MISOA RA_PINCFG__64(4, 0, 0x06, RA_PINCFG_FUNC) -#define P410_RXD0 RA_PINCFG__64(4, 0, 0x04, RA_PINCFG_FUNC) -#define P410_SCL0 RA_PINCFG__64(4, 0, 0x04, RA_PINCFG_FUNC) -#define P410_SEG08 RA_PINCFG__64(4, 0, 0x0D, RA_PINCFG_FUNC) -#define P410_TS06 RA_PINCFG__64(4, 0, 0x0C, RA_PINCFG_FUNC) -#define P411_AGTOA1 RA_PINCFG__64(4, 1, 0x01, RA_PINCFG_FUNC) -#define P411_GTIOC6A RA_PINCFG__64(4, 1, 0x04, RA_PINCFG_FUNC) -#define P411_GTOVUP RA_PINCFG__64(4, 1, 0x03, RA_PINCFG_FUNC) -#define P411_MOSI0 RA_PINCFG__64(4, 1, 0x04, RA_PINCFG_FUNC) -#define P411_MOSIA RA_PINCFG__64(4, 1, 0x06, RA_PINCFG_FUNC) -#define P411_SDA0 RA_PINCFG__64(4, 1, 0x04, RA_PINCFG_FUNC) -#define P411_SEG07 RA_PINCFG__64(4, 1, 0x0D, RA_PINCFG_FUNC) -#define P411_TS07 RA_PINCFG__64(4, 1, 0x0C, RA_PINCFG_FUNC) -#define P411_TXD0 RA_PINCFG__64(4, 1, 0x04, RA_PINCFG_FUNC) -#define P412_RSPCKA RA_PINCFG_100(4, 2, 0x06, RA_PINCFG_FUNC) -#define P412_SCK0 RA_PINCFG_100(4, 2, 0x04, RA_PINCFG_FUNC) -#define P413_CTS0_RTS0 RA_PINCFG_100(4, 3, 0x04, RA_PINCFG_FUNC) -#define P413_SS0 RA_PINCFG_100(4, 3, 0x04, RA_PINCFG_FUNC) -#define P413_SSLA0 RA_PINCFG_100(4, 3, 0x06, RA_PINCFG_FUNC) -#define P414_GTIOC0B RA_PINCFG_100(4, 4, 0x04, RA_PINCFG_FUNC) -#define P414_SSLA1 RA_PINCFG_100(4, 4, 0x06, RA_PINCFG_FUNC) -#define P415_GTIOC0A RA_PINCFG_100(4, 5, 0x04, RA_PINCFG_FUNC) -#define P415_SSLA2 RA_PINCFG_100(4, 5, 0x06, RA_PINCFG_FUNC) +#define P410_AGTOB1 RA_PINCFG__64(4, 10, 0x01, RA_PINCFG_FUNC) +#define P410_GTIOC6B RA_PINCFG__64(4, 10, 0x04, RA_PINCFG_FUNC) +#define P410_GTOVLO RA_PINCFG__64(4, 10, 0x03, RA_PINCFG_FUNC) +#define P410_MISO0 RA_PINCFG__64(4, 10, 0x04, RA_PINCFG_FUNC) +#define P410_MISOA RA_PINCFG__64(4, 10, 0x06, RA_PINCFG_FUNC) +#define P410_RXD0 RA_PINCFG__64(4, 10, 0x04, RA_PINCFG_FUNC) +#define P410_SCL0 RA_PINCFG__64(4, 10, 0x04, RA_PINCFG_FUNC) +#define P410_SEG08 RA_PINCFG__64(4, 10, 0x0D, RA_PINCFG_FUNC) +#define P410_TS06 RA_PINCFG__64(4, 10, 0x0C, RA_PINCFG_FUNC) +#define P411_AGTOA1 RA_PINCFG__64(4, 11, 0x01, RA_PINCFG_FUNC) +#define P411_GTIOC6A RA_PINCFG__64(4, 11, 0x04, RA_PINCFG_FUNC) +#define P411_GTOVUP RA_PINCFG__64(4, 11, 0x03, RA_PINCFG_FUNC) +#define P411_MOSI0 RA_PINCFG__64(4, 11, 0x04, RA_PINCFG_FUNC) +#define P411_MOSIA RA_PINCFG__64(4, 11, 0x06, RA_PINCFG_FUNC) +#define P411_SDA0 RA_PINCFG__64(4, 11, 0x04, RA_PINCFG_FUNC) +#define P411_SEG07 RA_PINCFG__64(4, 11, 0x0D, RA_PINCFG_FUNC) +#define P411_TS07 RA_PINCFG__64(4, 11, 0x0C, RA_PINCFG_FUNC) +#define P411_TXD0 RA_PINCFG__64(4, 11, 0x04, RA_PINCFG_FUNC) +#define P412_RSPCKA RA_PINCFG_100(4, 12, 0x06, RA_PINCFG_FUNC) +#define P412_SCK0 RA_PINCFG_100(4, 12, 0x04, RA_PINCFG_FUNC) +#define P413_CTS0_RTS0 RA_PINCFG_100(4, 13, 0x04, RA_PINCFG_FUNC) +#define P413_SS0 RA_PINCFG_100(4, 13, 0x04, RA_PINCFG_FUNC) +#define P413_SSLA0 RA_PINCFG_100(4, 13, 0x06, RA_PINCFG_FUNC) +#define P414_GTIOC0B RA_PINCFG_100(4, 14, 0x04, RA_PINCFG_FUNC) +#define P414_SSLA1 RA_PINCFG_100(4, 14, 0x06, RA_PINCFG_FUNC) +#define P415_GTIOC0A RA_PINCFG_100(4, 15, 0x04, RA_PINCFG_FUNC) +#define P415_SSLA2 RA_PINCFG_100(4, 15, 0x06, RA_PINCFG_FUNC) #define P500_AGTOA0 RA_PINCFG__48(5, 0, 0x01, RA_PINCFG_FUNC) #define P500_AN016 RA_PINCFG__48(5, 0, 0x01, RA_PINCFG_ANALOG) #define P500_CMPREF1 RA_PINCFG__48(5, 0, 0x02, RA_PINCFG_FUNC | RA_PINCFG_ANALOG) @@ -424,14 +424,14 @@ #define P608_SEG27 RA_PINCFG_100(6, 8, 0x0D, RA_PINCFG_FUNC) #define P609_GTIOC5A RA_PINCFG_100(6, 9, 0x01, RA_PINCFG_FUNC) #define P609_SEG28 RA_PINCFG_100(6, 9, 0x0D, RA_PINCFG_FUNC) -#define P610_GTIOC5B RA_PINCFG_100(6, 0, 0x01, RA_PINCFG_FUNC) -#define P610_SEG29 RA_PINCFG_100(6, 0, 0x0D, RA_PINCFG_FUNC) +#define P610_GTIOC5B RA_PINCFG_100(6, 10, 0x01, RA_PINCFG_FUNC) +#define P610_SEG29 RA_PINCFG_100(6, 10, 0x0D, RA_PINCFG_FUNC) #define P708_MISO1 RA_PINCFG_100(7, 8, 0x05, RA_PINCFG_FUNC) #define P708_RXD1 RA_PINCFG_100(7, 8, 0x05, RA_PINCFG_FUNC) #define P708_SCL1 RA_PINCFG_100(7, 8, 0x05, RA_PINCFG_FUNC) #define P708_SSLA3 RA_PINCFG_100(7, 8, 0x06, RA_PINCFG_FUNC) #define P808_SEG21 RA_PINCFG_100(8, 8, 0x0D, RA_PINCFG_FUNC) #define P809_SEG22 RA_PINCFG_100(8, 9, 0x0D, RA_PINCFG_FUNC) -#define P914_USB_DP RA_PINCFG__40(9, 4, 0x00, RA_PINCFG_GPIO) -#define P915_USB_DM RA_PINCFG__40(9, 5, 0x00, RA_PINCFG_GPIO) +#define P914_USB_DP RA_PINCFG__40(9, 14, 0x00, RA_PINCFG_GPIO) +#define P915_USB_DM RA_PINCFG__40(9, 15, 0x00, RA_PINCFG_GPIO) #endif From 5781b6a05f04fb3786f76fd59ce304b5b5edda9a Mon Sep 17 00:00:00 2001 From: Daniel Gaston Ochoa Date: Sat, 16 Dec 2023 11:45:17 +0000 Subject: [PATCH 1347/3723] Revert "drivers: spi: stm32h7: Use FIFO" This reverts commit bffa0c6bddbc91d39f4b01baa34e3d0595760d50. This FIFO implementation causes a regression by which the SPI peripheral generates several spurious SCK cyles after the last data has been sent. Signed-off-by: Daniel Gaston Ochoa --- drivers/spi/spi_ll_stm32.c | 50 +++++++------------------------------- 1 file changed, 9 insertions(+), 41 deletions(-) diff --git a/drivers/spi/spi_ll_stm32.c b/drivers/spi/spi_ll_stm32.c index fcb27cdbe31..027a9f8da23 100644 --- a/drivers/spi/spi_ll_stm32.c +++ b/drivers/spi/spi_ll_stm32.c @@ -273,7 +273,7 @@ static int spi_dma_move_buffers(const struct device *dev, size_t len) #define SPI_STM32_TX_NOP 0x00 static void spi_stm32_send_next_frame(SPI_TypeDef *spi, - struct spi_stm32_data *data) + struct spi_stm32_data *data) { const uint8_t frame_size = SPI_WORD_SIZE_GET(data->ctx.config->operation); uint32_t tx_frame = SPI_STM32_TX_NOP; @@ -338,52 +338,20 @@ static int spi_stm32_get_err(SPI_TypeDef *spi) return 0; } -static bool spi_stm32_can_use_fifo(void) -{ -#if DT_HAS_COMPAT_STATUS_OKAY(st_stm32h7_spi) - return true; -#else - /* - * TODO Test the FIFO usage in other FIFO-enabled STM32 SPI devices. - */ - return false; -#endif /* DT_HAS_COMPAT_STATUS_OKAY(st_stm32h7_spi) */ -} - -static void spi_stm32_shift_fifo(SPI_TypeDef *spi, struct spi_stm32_data *data) -{ - while (ll_func_rx_is_not_empty(spi)) { - spi_stm32_read_next_frame(spi, data); - } - - while (ll_func_tx_is_not_full(spi) && spi_stm32_transfer_ongoing(data)) { - spi_stm32_send_next_frame(spi, data); - - if (ll_func_rx_is_not_empty(spi)) { - /* Break as soon as a frame is ready to read to avoid overruns */ - break; - } - } -} - /* Shift a SPI frame as master. */ static void spi_stm32_shift_m(SPI_TypeDef *spi, struct spi_stm32_data *data) { - if (spi_stm32_can_use_fifo()) { - spi_stm32_shift_fifo(spi, data); - } else { - while (!ll_func_tx_is_not_full(spi)) { - /* NOP */ - } + while (!ll_func_tx_is_not_full(spi)) { + /* NOP */ + } - spi_stm32_send_next_frame(spi, data); + spi_stm32_send_next_frame(spi, data); - while (!ll_func_rx_is_not_empty(spi)) { - /* NOP */ - } - - spi_stm32_read_next_frame(spi, data); + while (!ll_func_rx_is_not_empty(spi)) { + /* NOP */ } + + spi_stm32_read_next_frame(spi, data); } /* Shift a SPI frame as slave. */ From 9e8c00f28c1c94c46bbd3c20d23b52fdf78a122e Mon Sep 17 00:00:00 2001 From: Adrien Bruant Date: Mon, 9 Oct 2023 10:42:19 +0200 Subject: [PATCH 1348/3723] drivers: stm32-rtc: return -ENODATA when RTC is uninitialized rtc_get_time() on STM32 does not implement the -ENODATA return code. This prevents testing the initialisation status of the RTC. Fixed by reading INITS flag and adding a error path in rtc_stm32_get_time(). Signed-off-by: Adrien Bruant --- drivers/rtc/rtc_ll_stm32.c | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/drivers/rtc/rtc_ll_stm32.c b/drivers/rtc/rtc_ll_stm32.c index 8714439ef47..ca0f9dc24e1 100644 --- a/drivers/rtc/rtc_ll_stm32.c +++ b/drivers/rtc/rtc_ll_stm32.c @@ -259,6 +259,15 @@ static int rtc_stm32_get_time(const struct device *dev, struct rtc_time *timeptr return err; } + if (!LL_RTC_IsActiveFlag_INITS(RTC)) { + /* INITS flag is set when the calendar has been initialiazed. This flag is + * reset only on backup domain reset, so it can be read after a system + * reset to check if the calendar has been initialized. + */ + k_mutex_unlock(&data->lock); + return -ENODATA; + } + do { /* read date, time and subseconds and relaunch if a day increment occurred * while doing so as it will result in an erroneous result otherwise From 60682555120376bf083bd16bff1cce576c352ddc Mon Sep 17 00:00:00 2001 From: Marek Vedral Date: Thu, 27 Apr 2023 12:39:06 +0200 Subject: [PATCH 1349/3723] drivers/timer/arm_arch_timer: Fix cycles overflow with GDB stub If GDBSTUB is enabled and the kernel runs in tickless mode, the timer must not convert the delta cycles to a 32-bit data type (cycle_diff_t in this case). The delta_ticks variable would overflow and the next timeout would be set before the current timestamp, thus generating an interrupt right after leaving the handler. As a result, the system would receive tens of thousands of interrupts per second and would not boot. Cc: Michal Sojka Signed-off-by: Marek Vedral --- drivers/timer/arm_arch_timer.c | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/drivers/timer/arm_arch_timer.c b/drivers/timer/arm_arch_timer.c index a9a762d9afa..718fecea582 100644 --- a/drivers/timer/arm_arch_timer.c +++ b/drivers/timer/arm_arch_timer.c @@ -20,6 +20,14 @@ static uint32_t cyc_per_tick; / CONFIG_SYS_CLOCK_TICKS_PER_SEC) #endif +#if defined(CONFIG_GDBSTUB) +/* When interactively debugging, the cycle diff can overflow 32-bit variable */ +#define TO_CYCLE_DIFF(x) (x) +#else +/* Convert to 32-bit for fast division */ +#define TO_CYCLE_DIFF(x) ((cycle_diff_t)(x)) +#endif + /* the unsigned long cast limits divisors to native CPU register width */ #define cycle_diff_t unsigned long @@ -58,7 +66,7 @@ static void arm_arch_timer_compare_isr(const void *arg) uint64_t curr_cycle = arm_arch_timer_count(); uint64_t delta_cycles = curr_cycle - last_cycle; - uint32_t delta_ticks = (cycle_diff_t)delta_cycles / CYC_PER_TICK; + uint32_t delta_ticks = TO_CYCLE_DIFF(delta_cycles) / CYC_PER_TICK; last_cycle += (cycle_diff_t)delta_ticks * CYC_PER_TICK; last_tick += delta_ticks; From 0d304b9223c486f274e0a7c3e20992b103ff0471 Mon Sep 17 00:00:00 2001 From: Marek Vedral Date: Wed, 7 Jun 2023 17:05:21 +0200 Subject: [PATCH 1350/3723] samples: debug: Add support for qemu_cortex_a9 in GDB stub sample This commit adds a devicetree overlay file and an extra condition in the CMakeLists.txt file to allow remote debugging for the qemu_cortex_a9 board. Signed-off-by: Marek Vedral --- tests/subsys/debug/gdbstub/boards/qemu_cortex_a9.overlay | 7 +++++++ 1 file changed, 7 insertions(+) create mode 100644 tests/subsys/debug/gdbstub/boards/qemu_cortex_a9.overlay diff --git a/tests/subsys/debug/gdbstub/boards/qemu_cortex_a9.overlay b/tests/subsys/debug/gdbstub/boards/qemu_cortex_a9.overlay new file mode 100644 index 00000000000..e6c560fae72 --- /dev/null +++ b/tests/subsys/debug/gdbstub/boards/qemu_cortex_a9.overlay @@ -0,0 +1,7 @@ +/* SPDX-License-Identifier: Apache-2.0 */ + +/ { + chosen { + zephyr,gdbstub-uart = &uart1; + }; +}; From 93a42871156e09942983d215c8d2b7f2628a5f4c Mon Sep 17 00:00:00 2001 From: Marek Vedral Date: Sat, 8 Apr 2023 20:06:23 +0200 Subject: [PATCH 1351/3723] arm: debug: Add GDB stub for aarch32 This commit adds implementation of GDB stub for 32-bit ARM. It has been tested only on the Zynq-7000 SoC and I would like to get any feedback from others. The stub still has these issues: - To implement single stepping, it uses instruction address mismatch breakpoint, as recommended in ARMv7 reference. The breakpoint control register is configured (the state control fields) for the "PL0, Supervisor and System modes only" option. Otherwise the breakpoint would also halt the processor in abort mode, in which the stub loop runs. Zephyr kernel runs in the system mode. This works well until the kernel enables interrupts, as interrupt handlers typically run in Supervisor mode. Single stepping therefore sometimes "catches" a handler instead of the next application instruction. I have not tried User mode, because Cortex-A SoCs do not appear to have the ARCH_HAS_USERSPACE flag. Cc: Michal Sojka Signed-off-by: Marek Vedral --- arch/arm/core/CMakeLists.txt | 1 + arch/arm/core/Kconfig | 9 ++ arch/arm/core/cortex_a_r/fault.c | 28 ++++ arch/arm/core/gdbstub.c | 225 ++++++++++++++++++++++++++++++ arch/arm/core/mmu/arm_mmu.c | 7 + include/zephyr/arch/arm/arch.h | 3 + include/zephyr/arch/arm/gdbstub.h | 71 ++++++++++ 7 files changed, 344 insertions(+) create mode 100644 arch/arm/core/gdbstub.c create mode 100644 include/zephyr/arch/arm/gdbstub.h diff --git a/arch/arm/core/CMakeLists.txt b/arch/arm/core/CMakeLists.txt index 1b4fa58eae5..41e3dc485ff 100644 --- a/arch/arm/core/CMakeLists.txt +++ b/arch/arm/core/CMakeLists.txt @@ -14,6 +14,7 @@ zephyr_library_sources_ifdef(CONFIG_THREAD_LOCAL_STORAGE tls.c) zephyr_library_sources_ifdef(CONFIG_USERSPACE userspace.S) zephyr_library_sources_ifdef(CONFIG_ARM_ZIMAGE_HEADER header.S) zephyr_library_sources_ifdef(CONFIG_LLEXT elf.c) +zephyr_library_sources_ifdef(CONFIG_GDBSTUB gdbstub.c) add_subdirectory_ifdef(CONFIG_CPU_CORTEX_M cortex_m) add_subdirectory_ifdef(CONFIG_CPU_CORTEX_M_HAS_CMSE cortex_m/cmse) diff --git a/arch/arm/core/Kconfig b/arch/arm/core/Kconfig index dd322bff626..e446eb25c1d 100644 --- a/arch/arm/core/Kconfig +++ b/arch/arm/core/Kconfig @@ -58,9 +58,18 @@ config CPU_AARCH32_CORTEX_A select ARCH_HAS_EXTRA_EXCEPTION_INFO if !USE_SWITCH select ARCH_HAS_NOCACHE_MEMORY_SUPPORT select USE_SWITCH_SUPPORTED + # GDBSTUB has not yet been tested on Cortex M or R SoCs + select ARCH_HAS_GDBSTUB + # GDB on ARM needs the etxra registers + select EXTRA_EXCEPTION_INFO if GDBSTUB help This option signifies the use of a CPU of the Cortex-A family. +config GDBSTUB_BUF_SZ + # GDB for ARM expects up to 18 4-byte plus 8 12-byte + # registers - 336 HEX letters + default 350 if GDBSTUB + config ISA_THUMB2 bool help diff --git a/arch/arm/core/cortex_a_r/fault.c b/arch/arm/core/cortex_a_r/fault.c index 4b1624cd54b..a39efeb96e0 100644 --- a/arch/arm/core/cortex_a_r/fault.c +++ b/arch/arm/core/cortex_a_r/fault.c @@ -10,6 +10,11 @@ #include #include #include +#if defined(CONFIG_GDBSTUB) +#include +#include +#endif + LOG_MODULE_DECLARE(os, CONFIG_KERNEL_LOG_LEVEL); #define FAULT_DUMP_VERBOSE (CONFIG_FAULT_DUMP == 2) @@ -213,6 +218,12 @@ bool z_arm_fault_undef_instruction(z_arch_esf_t *esf) z_arm_fpu_caller_save(&esf->fpu); #endif +#if defined(CONFIG_GDBSTUB) + z_gdb_entry(esf, GDB_EXCEPTION_INVALID_INSTRUCTION); + /* Might not be fatal if GDB stub placed it in the code. */ + return false; +#endif + /* Print fault information */ LOG_ERR("***** UNDEFINED INSTRUCTION ABORT *****"); @@ -247,6 +258,17 @@ bool z_arm_fault_prefetch(z_arch_esf_t *esf) /* Read Instruction Fault Address Register (IFAR) */ uint32_t ifar = __get_IFAR(); +#if defined(CONFIG_GDBSTUB) + /* The BKPT instruction could have caused a software breakpoint */ + if (fs == IFSR_DEBUG_EVENT) { + /* Debug event, call the gdbstub handler */ + z_gdb_entry(esf, GDB_EXCEPTION_BREAKPOINT); + } else { + /* Fatal */ + z_gdb_entry(esf, GDB_EXCEPTION_MEMORY_FAULT); + } + return false; +#endif /* Print fault information*/ LOG_ERR("***** PREFETCH ABORT *****"); if (FAULT_DUMP_VERBOSE) { @@ -314,6 +336,12 @@ bool z_arm_fault_data(z_arch_esf_t *esf) /* Read Data Fault Address Register (DFAR) */ uint32_t dfar = __get_DFAR(); +#if defined(CONFIG_GDBSTUB) + z_gdb_entry(esf, GDB_EXCEPTION_MEMORY_FAULT); + /* return false - non-fatal error */ + return false; +#endif + #if defined(CONFIG_USERSPACE) if ((fs == COND_CODE_1(CONFIG_AARCH32_ARMV8_R, (FSR_FS_TRANSLATION_FAULT), diff --git a/arch/arm/core/gdbstub.c b/arch/arm/core/gdbstub.c new file mode 100644 index 00000000000..5386cfa619f --- /dev/null +++ b/arch/arm/core/gdbstub.c @@ -0,0 +1,225 @@ +/* + * Copyright (c) 2023 Marek Vedral + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include +#include +#include +#include + +/* Position of each register in the packet - n-th register in the ctx.registers array needs to be + * the packet_pos[n]-th byte of the g (read all registers) packet. See struct arm_register_names in + * GDB file gdb/arm-tdep.c, which defines these positions. + */ +static const int packet_pos[] = {0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 41}; + +/* Required struct */ +static struct gdb_ctx ctx; + +/* Return true if BKPT instruction caused the current entry */ +static int is_bkpt(unsigned int exc_cause) +{ + int ret = 0; + + if (exc_cause == GDB_EXCEPTION_BREAKPOINT) { + /* Get the instruction */ + unsigned int instr = sys_read32(ctx.registers[PC]); + /* Try to check the instruction encoding */ + int ist = ((ctx.registers[SPSR] & BIT(SPSR_J)) >> (SPSR_J - 1)) | + ((ctx.registers[SPSR] & BIT(SPSR_T)) >> SPSR_T); + + if (ist == SPSR_ISETSTATE_ARM) { + /* ARM instruction set state */ + ret = ((instr & 0xFF00000) == 0x1200000) && ((instr & 0xF0) == 0x70); + } else if (ist != SPSR_ISETSTATE_JAZELLE) { + /* Thumb or ThumbEE encoding */ + ret = ((instr & 0xFF00) == 0xBE00); + } + } + return ret; +} + +/* Wrapper function to save and restore execution c */ +void z_gdb_entry(z_arch_esf_t *esf, unsigned int exc_cause) +{ + /* Disable the hardware breakpoint in case it was set */ + __asm__ volatile("mcr p14, 0, %0, c0, c0, 5" ::"r"(0x0) :); + + ctx.exception = exc_cause; + /* save the registers */ + ctx.registers[R0] = esf->basic.r0; + ctx.registers[R1] = esf->basic.r1; + ctx.registers[R2] = esf->basic.r2; + ctx.registers[R3] = esf->basic.r3; + /* The EXTRA_EXCEPTION_INFO kernel option ensures these regs are set */ + ctx.registers[R4] = esf->extra_info.callee->v1; + ctx.registers[R5] = esf->extra_info.callee->v2; + ctx.registers[R6] = esf->extra_info.callee->v3; + ctx.registers[R7] = esf->extra_info.callee->v4; + ctx.registers[R8] = esf->extra_info.callee->v5; + ctx.registers[R9] = esf->extra_info.callee->v6; + ctx.registers[R10] = esf->extra_info.callee->v7; + ctx.registers[R11] = esf->extra_info.callee->v8; + ctx.registers[R13] = esf->extra_info.callee->psp; + + ctx.registers[R12] = esf->basic.r12; + ctx.registers[LR] = esf->basic.lr; + ctx.registers[PC] = esf->basic.pc; + ctx.registers[SPSR] = esf->basic.xpsr; + + /* True if entering after a BKPT instruction */ + const int bkpt_entry = is_bkpt(exc_cause); + + z_gdb_main_loop(&ctx); + + /* The registers part of EXTRA_EXCEPTION_INFO are read-only - the excpetion return code + * does not restore them, thus we don't need to do so here + */ + esf->basic.r0 = ctx.registers[R0]; + esf->basic.r1 = ctx.registers[R1]; + esf->basic.r2 = ctx.registers[R2]; + esf->basic.r3 = ctx.registers[R3]; + esf->basic.r12 = ctx.registers[R12]; + esf->basic.lr = ctx.registers[LR]; + esf->basic.pc = ctx.registers[PC]; + esf->basic.xpsr = ctx.registers[SPSR]; + /* TODO: restore regs from extra exc. info */ + + if (bkpt_entry) { + /* Apply this offset, so that the process won't be affected by the + * BKPT instruction + */ + esf->basic.pc += 0x4; + } + esf->basic.xpsr = ctx.registers[SPSR]; +} + +void arch_gdb_init(void) +{ + uint32_t reg_val; + /* Enable the monitor debug mode */ + __asm__ volatile("mrc p14, 0, %0, c0, c2, 2" : "=r"(reg_val)::); + reg_val |= DBGDSCR_MONITOR_MODE_EN; + __asm__ volatile("mcr p14, 0, %0, c0, c2, 2" ::"r"(reg_val) :); + + /* Generate the Prefetch abort exception */ + __asm__ volatile("BKPT"); +} + +void arch_gdb_continue(void) +{ + /* No need to do anything, return to the code. */ +} + +void arch_gdb_step(void) +{ + /* Set the hardware breakpoint */ + uint32_t reg_val = ctx.registers[PC]; + /* set BVR (Breakpoint value register) to PC, make sure it is word aligned */ + reg_val &= ~(0x3); + __asm__ volatile("mcr p14, 0, %0, c0, c0, 4" ::"r"(reg_val) :); + + reg_val = 0; + /* Address mismatch */ + reg_val |= (DBGDBCR_MEANING_ADDR_MISMATCH & DBGDBCR_MEANING_MASK) << DBGDBCR_MEANING_SHIFT; + /* Match any other instruction */ + reg_val |= (0xF & DBGDBCR_BYTE_ADDR_MASK) << DBGDBCR_BYTE_ADDR_SHIFT; + /* Breakpoint enable */ + reg_val |= DBGDBCR_BRK_EN_MASK; + __asm__ volatile("mcr p14, 0, %0, c0, c0, 5" ::"r"(reg_val) :); +} + +size_t arch_gdb_reg_readall(struct gdb_ctx *c, uint8_t *buf, size_t buflen) +{ + int ret = 0; + /* All other registers are not supported */ + memset(buf, 'x', buflen); + for (int i = 0; i < GDB_NUM_REGS; i++) { + /* offset inside the packet */ + int pos = packet_pos[i] * 8; + int r = bin2hex((const uint8_t *)(c->registers + i), 4, buf + pos, buflen - pos); + /* remove the newline character placed by the bin2hex function */ + buf[pos + 8] = 'x'; + if (r == 0) { + ret = 0; + break; + } + ret += r; + } + + if (ret) { + /* Since we don't support some floating point registers, set the packet size + * manually + */ + ret = GDB_READALL_PACKET_SIZE; + } + return ret; +} + +size_t arch_gdb_reg_writeall(struct gdb_ctx *c, uint8_t *hex, size_t hexlen) +{ + int ret = 0; + + for (unsigned int i = 0; i < hexlen; i += 8) { + if (hex[i] != 'x') { + /* check if the stub supports this register */ + for (unsigned int j = 0; j < GDB_NUM_REGS; j++) { + if (packet_pos[j] != i) { + continue; + } + int r = hex2bin(hex + i * 8, 8, (uint8_t *)(c->registers + j), 4); + + if (r == 0) { + return 0; + } + ret += r; + } + } + } + return ret; +} + +size_t arch_gdb_reg_readone(struct gdb_ctx *c, uint8_t *buf, size_t buflen, uint32_t regno) +{ + /* Reading four bytes (could be any return value except 0, which would indicate an error) */ + int ret = 4; + /* Fill the buffer with 'x' in case the stub does not support the required register */ + memset(buf, 'x', 8); + if (regno == SPSR_REG_IDX) { + /* The SPSR register is at the end, we have to check separately */ + ret = bin2hex((uint8_t *)(c->registers + GDB_NUM_REGS - 1), 4, buf, buflen); + } else { + /* Check which of our registers corresponds to regnum */ + for (int i = 0; i < GDB_NUM_REGS; i++) { + if (packet_pos[i] == regno) { + ret = bin2hex((uint8_t *)(c->registers + i), 4, buf, buflen); + break; + } + } + } + return ret; +} + +size_t arch_gdb_reg_writeone(struct gdb_ctx *c, uint8_t *hex, size_t hexlen, uint32_t regno) +{ + int ret = 0; + /* Set the value of a register */ + if (hexlen != 8) { + return ret; + } + + if (regno < (GDB_NUM_REGS - 1)) { + /* Again, check the corresponding register index */ + for (int i = 0; i < GDB_NUM_REGS; i++) { + if (packet_pos[i] == regno) { + ret = hex2bin(hex, hexlen, (uint8_t *)(c->registers + i), 4); + break; + } + } + } else if (regno == SPSR_REG_IDX) { + ret = hex2bin(hex, hexlen, (uint8_t *)(c->registers + GDB_NUM_REGS - 1), 4); + } + return ret; +} diff --git a/arch/arm/core/mmu/arm_mmu.c b/arch/arm/core/mmu/arm_mmu.c index 77c79fdfc3d..f37b4354d46 100644 --- a/arch/arm/core/mmu/arm_mmu.c +++ b/arch/arm/core/mmu/arm_mmu.c @@ -81,7 +81,14 @@ static const struct arm_mmu_flat_range mmu_zephyr_ranges[] = { .start = (uint32_t)__text_region_start, .end = (uint32_t)__text_region_end, .attrs = MT_NORMAL | MATTR_SHARED | + /* The code needs to have write permission in order for + * software breakpoints (which modify instructions) to work + */ +#if defined(CONFIG_GDBSTUB) + MPERM_R | MPERM_X | MPERM_W | +#else MPERM_R | MPERM_X | +#endif MATTR_CACHE_OUTER_WB_nWA | MATTR_CACHE_INNER_WB_nWA | MATTR_MAY_MAP_L1_SECTION}, diff --git a/include/zephyr/arch/arm/arch.h b/include/zephyr/arch/arm/arch.h index d3a64e9ef8b..804e1d23dbd 100644 --- a/include/zephyr/arch/arm/arch.h +++ b/include/zephyr/arch/arm/arch.h @@ -32,6 +32,9 @@ #include #include #include +#if defined(CONFIG_GDBSTUB) +#include +#endif #ifdef CONFIG_CPU_CORTEX_M #include diff --git a/include/zephyr/arch/arm/gdbstub.h b/include/zephyr/arch/arm/gdbstub.h new file mode 100644 index 00000000000..e8e606d7def --- /dev/null +++ b/include/zephyr/arch/arm/gdbstub.h @@ -0,0 +1,71 @@ +/* + * Copyright (c) 2023 Marek Vedral + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#ifndef ZEPHYR_INCLUDE_ARCH_ARM_AARCH32_GDBSTUB_H_ +#define ZEPHYR_INCLUDE_ARCH_ARM_AARCH32_GDBSTUB_H_ + +#include + +#ifndef _ASMLANGUAGE + +#define DBGDSCR_MONITOR_MODE_EN 0x8000 + +#define SPSR_ISETSTATE_ARM 0x0 +#define SPSR_ISETSTATE_JAZELLE 0x2 +#define SPSR_J 24 +#define SPSR_T 5 + +/* Debug Breakpoint Control Register constants */ +#define DBGDBCR_MEANING_MASK 0x7 +#define DBGDBCR_MEANING_SHIFT 20 +#define DBGDBCR_MEANING_ADDR_MISMATCH 0x4 +#define DBGDBCR_BYTE_ADDR_MASK 0xF +#define DBGDBCR_BYTE_ADDR_SHIFT 5 +#define DBGDBCR_BRK_EN_MASK 0x1 + +/* Regno of the SPSR */ +#define SPSR_REG_IDX 25 +/* Minimal size of the packet - SPSR is the last, 42-nd byte, see packet_pos array */ +#define GDB_READALL_PACKET_SIZE (42 * 8) + +#define IFSR_DEBUG_EVENT 0x2 + +enum AARCH32_GDB_REG { + R0 = 0, + R1, + R2, + R3, + /* READONLY registers (R4 - R13) except R12 */ + R4, + R5, + R6, + R7, + R8, + R9, + R10, + R11, + R12, + /* Stack pointer - READONLY */ + R13, + LR, + PC, + /* Saved program status register */ + SPSR, + GDB_NUM_REGS +}; + +/* required structure */ +struct gdb_ctx { + /* cause of the exception */ + unsigned int exception; + unsigned int registers[GDB_NUM_REGS]; +}; + +void z_gdb_entry(z_arch_esf_t *esf, unsigned int exc_cause); + +#endif + +#endif From ef124718aa651ae8fc674ed46c2d82b3c9d3ae0a Mon Sep 17 00:00:00 2001 From: Johann Fischer Date: Wed, 6 Sep 2023 09:17:44 +0200 Subject: [PATCH 1352/3723] drivers: usb: add common DWC2 register header This header is based on drivers/usb/device/usb_dw_registers.h and describes registers of the DWC2 controllers IP and is intended for use in both device controller drivers and a host controller driver. The difference to usb_dw_registers.h is that this header does not confuse offsets with bit positions, contains all the definitions required for device mode, has register and bit field names identical to the databook and no annoying underscores. Signed-off-by: Johann Fischer --- drivers/usb/common/usb_dwc2_hw.h | 626 +++++++++++++++++++++++++++++++ 1 file changed, 626 insertions(+) create mode 100644 drivers/usb/common/usb_dwc2_hw.h diff --git a/drivers/usb/common/usb_dwc2_hw.h b/drivers/usb/common/usb_dwc2_hw.h new file mode 100644 index 00000000000..edcab56b50f --- /dev/null +++ b/drivers/usb/common/usb_dwc2_hw.h @@ -0,0 +1,626 @@ +/* + * Copyright (c) 2016 Intel Corporation + * Copyright (c) 2023 Nordic Semiconductor ASA + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#ifndef ZEPHYR_DRIVERS_USB_COMMON_USB_DWC2_HW +#define ZEPHYR_DRIVERS_USB_COMMON_USB_DWC2_HW + +#include + +#ifdef __cplusplus +extern "C" { +#endif + +/* This file describes register set for the DesignWare USB 2.0 controller IP */ + +/* IN endpoint register block */ +struct usb_dwc2_in_ep { + volatile uint32_t diepctl; + uint32_t reserved; + volatile uint32_t diepint; + uint32_t reserved1; + volatile uint32_t dieptsiz; + volatile uint32_t diepdma; + volatile uint32_t dtxfsts; + volatile uint32_t diepdmab; +}; + +/* OUT endpoint register block */ +struct usb_dwc2_out_ep { + volatile uint32_t doepctl; + uint32_t reserved; + volatile uint32_t doepint; + uint32_t reserved1; + volatile uint32_t doeptsiz; + volatile uint32_t doepdma; + uint32_t reserved2; + volatile uint32_t doepdmab; +}; + +/* DWC2 register map + * TODO: This should probably be split into global, host, and device register + * blocks + */ +struct usb_dwc2_reg { + volatile uint32_t gotgctl; + volatile uint32_t gotgint; + volatile uint32_t gahbcfg; + volatile uint32_t gusbcfg; + volatile uint32_t grstctl; + volatile uint32_t gintsts; + volatile uint32_t gintmsk; + volatile uint32_t grxstsr; + volatile uint32_t grxstsp; + volatile uint32_t grxfsiz; + volatile uint32_t gnptxfsiz; + volatile uint32_t gnptxsts; + volatile uint32_t gi2cctl; + volatile uint32_t gpvndctl; + volatile uint32_t ggpio; + volatile uint32_t guid; + volatile uint32_t gsnpsid; + volatile uint32_t ghwcfg1; + volatile uint32_t ghwcfg2; + volatile uint32_t ghwcfg3; + volatile uint32_t ghwcfg4; + volatile uint32_t glpmcfg; + volatile uint32_t gpwrdn; + volatile uint32_t gdfifocfg; + volatile uint32_t gadpctl; + volatile uint32_t grefclk; + volatile uint32_t gintmsk2; + volatile uint32_t gintsts2; + volatile uint32_t reserved1[36]; + volatile uint32_t hptxfsiz; + union { + volatile uint32_t dptxfsiz[15]; + volatile uint32_t dieptxf[15]; + }; + volatile uint32_t reserved2[176]; + /* Host mode register 0x0400 .. 0x0670 */ + uint32_t reserved3[256]; + /* Device mode register 0x0800 .. 0x0D00 */ + volatile uint32_t dcfg; + volatile uint32_t dctl; + volatile uint32_t dsts; + uint32_t reserved4; + volatile uint32_t diepmsk; + volatile uint32_t doepmsk; + volatile uint32_t daint; + volatile uint32_t daintmsk; + volatile uint32_t dtknqr1; + volatile uint32_t dtknqr2; + volatile uint32_t dvbusdis; + volatile uint32_t dvbuspulse; + union { + volatile uint32_t dtknqr3; + volatile uint32_t dthrctl; + }; + union { + volatile uint32_t dtknqr4; + volatile uint32_t diepempmsk; + }; + volatile uint32_t deachint; + volatile uint32_t deachintmsk; + volatile uint32_t diepeachmsk[16]; + volatile uint32_t doepeachmsk[16]; + volatile uint32_t reserved5[16]; + struct usb_dwc2_in_ep in_ep[16]; + struct usb_dwc2_out_ep out_ep[16]; +}; + +/* + * With the maximum number of supported endpoints, register map + * of the controller must be equal to 0x0D00. + */ +BUILD_ASSERT(sizeof(struct usb_dwc2_reg) == 0x0D00); + +/* + * GET_FIELD/SET_FIELD macros below are intended to be used to define functions + * to get/set a bitfield of a register from/into a value. They should not be + * used to get/set a bitfield consisting of only one bit. + */ +#define USB_DWC2_GET_FIELD_DEFINE(name, reg_name_and_field) \ + static inline uint32_t usb_dwc2_get_##name(const uint32_t value) \ + { \ + return (value & USB_DWC2_##reg_name_and_field##_MASK) >> \ + USB_DWC2_##reg_name_and_field##_POS; \ + } + +#define USB_DWC2_SET_FIELD_DEFINE(name, reg_name_and_field) \ + static inline uint32_t usb_dwc2_set_##name(const uint32_t value) \ + { \ + return (value << USB_DWC2_##reg_name_and_field##_POS) & \ + USB_DWC2_##reg_name_and_field##_MASK; \ + } + +#define USB_DWC2_GET_FIELD_AND_IDX_DEFINE(name, reg_name_and_field) \ + static inline uint32_t usb_dwc2_get_##name(const uint32_t value, \ + const uint32_t idx) \ + { \ + return (value & USB_DWC2_##reg_name_and_field##_MASK(idx)) >> \ + USB_DWC2_##reg_name_and_field##_POS(idx); \ + } + +/* AHB configuration register */ +#define USB_DWC2_GAHBCFG 0x0008UL +#define USB_DWC2_GAHBCFG_DMAEN_POS 5UL +#define USB_DWC2_GAHBCFG_DMAEN BIT(USB_DWC2_GAHBCFG_DMAEN_POS) +#define USB_DWC2_GAHBCFG_GLBINTRMASK_POS 0UL +#define USB_DWC2_GAHBCFG_GLBINTRMASK BIT(USB_DWC2_GAHBCFG_GLBINTRMASK_POS) + +/* USB configuration register */ +#define USB_DWC2_GUSBCFG 0x000CUL +#define USB_DWC2_GUSBCFG_FORCEDEVMODE_POS 30UL +#define USB_DWC2_GUSBCFG_FORCEDEVMODE BIT(USB_DWC2_GUSBCFG_FORCEDEVMODE_POS) +#define USB_DWC2_GUSBCFG_FORCEHSTMODE_POS 29UL +#define USB_DWC2_GUSBCFG_FORCEHSTMODE BIT(USB_DWC2_GUSBCFG_FORCEHSTMODE_POS) +#define USB_DWC2_GUSBCFG_PHYSEL_POS 6UL +#define USB_DWC2_GUSBCFG_PHYSEL_USB11 BIT(USB_DWC2_GUSBCFG_PHYSEL_POS) +#define USB_DWC2_GUSBCFG_PHYSEL_USB20 0UL +#define USB_DWC2_GUSBCFG_ULPI_UTMI_SEL_POS 4UL +#define USB_DWC2_GUSBCFG_ULPI_UTMI_SEL_ULPI BIT(USB_DWC2_GUSBCFG_ULPI_UTMI_SEL_POS) +#define USB_DWC2_GUSBCFG_ULPI_UTMI_SEL_UTMI 0UL +#define USB_DWC2_GUSBCFG_PHYIF_POS 3UL +#define USB_DWC2_GUSBCFG_PHYIF_16_BIT BIT(USB_DWC2_GUSBCFG_PHYIF_POS) +#define USB_DWC2_GUSBCFG_PHYIF_8_BIT 0UL + +/* Reset register */ +#define USB_DWC2_GRSTCTL 0x0010UL +#define USB_DWC2_GRSTCTL_AHBIDLE_POS 31UL +#define USB_DWC2_GRSTCTL_AHBIDLE BIT(USB_DWC2_GRSTCTL_AHBIDLE_POS) +#define USB_DWC2_GRSTCTL_CSFTRSTDONE_POS 29UL +#define USB_DWC2_GRSTCTL_CSFTRSTDONE BIT(USB_DWC2_GRSTCTL_CSFTRSTDONE_POS) +#define USB_DWC2_GRSTCTL_TXFNUM_POS 6UL +#define USB_DWC2_GRSTCTL_TXFNUM_MASK (0x1FUL << USB_DWC2_GRSTCTL_TXFNUM_POS) +#define USB_DWC2_GRSTCTL_TXFFLSH_POS 5UL +#define USB_DWC2_GRSTCTL_TXFFLSH BIT(USB_DWC2_GRSTCTL_TXFFLSH_POS) +#define USB_DWC2_GRSTCTL_RXFFLSH_POS 4UL +#define USB_DWC2_GRSTCTL_RXFFLSH BIT(USB_DWC2_GRSTCTL_RXFFLSH_POS) +#define USB_DWC2_GRSTCTL_CSFTRST_POS 0UL +#define USB_DWC2_GRSTCTL_CSFTRST BIT(USB_DWC2_GRSTCTL_CSFTRST_POS) + +USB_DWC2_SET_FIELD_DEFINE(grstctl_txfnum, GRSTCTL_TXFNUM) + +/* Core interrupt registers */ +#define USB_DWC2_GINTSTS 0x0014UL +#define USB_DWC2_GINTMSK 0x0018UL +#define USB_DWC2_GINTSTS_WKUPINT_POS 31UL +#define USB_DWC2_GINTSTS_WKUPINT BIT(USB_DWC2_GINTSTS_WKUPINT_POS) +#define USB_DWC2_GINTSTS_OEPINT_POS 19UL +#define USB_DWC2_GINTSTS_OEPINT BIT(USB_DWC2_GINTSTS_OEPINT_POS) +#define USB_DWC2_GINTSTS_IEPINT_POS 18UL +#define USB_DWC2_GINTSTS_IEPINT BIT(USB_DWC2_GINTSTS_IEPINT_POS) +#define USB_DWC2_GINTSTS_ENUMDONE_POS 13UL +#define USB_DWC2_GINTSTS_ENUMDONE BIT(USB_DWC2_GINTSTS_ENUMDONE_POS) +#define USB_DWC2_GINTSTS_USBRST_POS 12UL +#define USB_DWC2_GINTSTS_USBRST BIT(USB_DWC2_GINTSTS_USBRST_POS) +#define USB_DWC2_GINTSTS_USBSUSP_POS 11UL +#define USB_DWC2_GINTSTS_USBSUSP BIT(USB_DWC2_GINTSTS_USBSUSP_POS) +#define USB_DWC2_GINTSTS_RXFLVL_POS 4UL +#define USB_DWC2_GINTSTS_RXFLVL BIT(USB_DWC2_GINTSTS_RXFLVL_POS) +#define USB_DWC2_GINTSTS_OTGINT_POS 2UL +#define USB_DWC2_GINTSTS_OTGINT BIT(USB_DWC2_GINTSTS_OTGINT_POS) + +/* Status read and pop registers */ +#define USB_DWC2_GRXSTSR 0x001CUL +#define USB_DWC2_GRXSTSP 0x0020UL +#define USB_DWC2_GRXSTSR_PKTSTS_POS 17UL +#define USB_DWC2_GRXSTSR_PKTSTS_MASK (0xFUL << USB_DWC2_GRXSTSR_PKTSTS_POS) +#define USB_DWC2_GRXSTSR_PKTSTS_OUT_DATA 2 +#define USB_DWC2_GRXSTSR_PKTSTS_OUT_DATA_DONE 3 +#define USB_DWC2_GRXSTSR_PKTSTS_SETUP_DONE 4 +#define USB_DWC2_GRXSTSR_PKTSTS_SETUP 6 +#define USB_DWC2_GRXSTSR_BCNT_POS 4UL +#define USB_DWC2_GRXSTSR_BCNT_MASK (0x000007FFUL << USB_DWC2_GRXSTSR_BCNT_POS) +#define USB_DWC2_GRXSTSR_EPNUM_POS 0UL +#define USB_DWC2_GRXSTSR_EPNUM_MASK 0x0000000FUL +#define USB_DWC2_GRXSTSR_CHNUM_POS 0UL +#define USB_DWC2_GRXSTSR_CHNUM_MASK 0x0000000FUL + +USB_DWC2_GET_FIELD_DEFINE(grxstsp_pktsts, GRXSTSR_PKTSTS) +USB_DWC2_GET_FIELD_DEFINE(grxstsp_bcnt, GRXSTSR_BCNT) +USB_DWC2_GET_FIELD_DEFINE(grxstsp_epnum, GRXSTSR_EPNUM) + +/* Receive FIFO size register (device mode) */ +#define USB_DWC2_GRXFSIZ 0x0024UL +#define USB_DWC2_GRXFSIZ_RXFDEP_POS 0UL +#define USB_DWC2_GRXFSIZ_RXFDEP_MASK (0xFFFFUL << USB_DWC2_GRXFSIZ_RXFDEP_POS) + +USB_DWC2_GET_FIELD_DEFINE(grxfsiz, GRXFSIZ_RXFDEP) +USB_DWC2_SET_FIELD_DEFINE(grxfsiz, GRXFSIZ_RXFDEP) + +/* Non-periodic transmit FIFO size register (device mode) */ +#define USB_DWC2_GNPTXFSIZ 0x0028UL +#define USB_DWC2_GNPTXFSIZ_NPTXFDEP_POS 16UL +#define USB_DWC2_GNPTXFSIZ_NPTXFDEP_MASK (0xFFFFUL << USB_DWC2_GNPTXFSIZ_NPTXFDEP_POS) +#define USB_DWC2_GNPTXFSIZ_NPTXFSTADDR_POS 0UL +#define USB_DWC2_GNPTXFSIZ_NPTXFSTADDR_MASK (0xFFFFUL << USB_DWC2_GNPTXFSIZ_NPTXFSTADDR_POS) + +USB_DWC2_GET_FIELD_DEFINE(gnptxfsiz_nptxfdep, GNPTXFSIZ_NPTXFDEP) +USB_DWC2_GET_FIELD_DEFINE(gnptxfsiz_nptxfstaddr, GNPTXFSIZ_NPTXFSTADDR) +USB_DWC2_SET_FIELD_DEFINE(gnptxfsiz_nptxfdep, GNPTXFSIZ_NPTXFDEP) +USB_DWC2_SET_FIELD_DEFINE(gnptxfsiz_nptxfstaddr, GNPTXFSIZ_NPTXFSTADDR) + +/* Application (vendor) general purpose registers */ +#define USB_DWC2_GGPIO 0x0038UL +#define USB_DWC2_GGPIO_STM32_VBDEN_POS 21UL +#define USB_DWC2_GGPIO_STM32_VBDEN BIT(USB_DWC2_GGPIO_STM32_VBDEN_POS) +#define USB_DWC2_GGPIO_STM32_PWRDWN_POS 16UL +#define USB_DWC2_GGPIO_STM32_PWRDWN BIT(USB_DWC2_GGPIO_STM32_PWRDWN_POS) + +/* GHWCFG1 register */ +#define USB_DWC2_GHWCFG1 0x0044UL +#define USB_DWC2_GHWCFG1_EPDIR_POS(i) (i * 2) +#define USB_DWC2_GHWCFG1_EPDIR_MASK(i) (0x3UL << USB_DWC2_GHWCFG1_EPDIR_POS(i)) +#define USB_DWC2_GHWCFG1_EPDIR_OUT 2 +#define USB_DWC2_GHWCFG1_EPDIR_IN 1 +#define USB_DWC2_GHWCFG1_EPDIR_BDIR 0 + +USB_DWC2_GET_FIELD_AND_IDX_DEFINE(ghwcfg1_epdir, GHWCFG1_EPDIR) + +/* GHWCFG2 register */ +#define USB_DWC2_GHWCFG2 0x0048UL +#define USB_DWC2_GHWCFG2_DYNFIFOSIZING_POS 19UL +#define USB_DWC2_GHWCFG2_DYNFIFOSIZING BIT(USB_DWC2_GHWCFG2_DYNFIFOSIZING_POS) +#define USB_DWC2_GHWCFG2_NUMDEVEPS_POS 10UL +#define USB_DWC2_GHWCFG2_NUMDEVEPS_MASK (0xFUL << USB_DWC2_GHWCFG2_NUMDEVEPS_POS) +#define USB_DWC2_GHWCFG2_FSPHYTYPE_POS 8UL +#define USB_DWC2_GHWCFG2_FSPHYTYPE_MASK (0x3UL << USB_DWC2_GHWCFG2_FSPHYTYPE_POS) +#define USB_DWC2_GHWCFG2_FSPHYTYPE_FSPLUSULPI 3 +#define USB_DWC2_GHWCFG2_FSPHYTYPE_FSPLUSUTMI 2 +#define USB_DWC2_GHWCFG2_FSPHYTYPE_FS 1 +#define USB_DWC2_GHWCFG2_FSPHYTYPE_NO_FS 0 +#define USB_DWC2_GHWCFG2_HSPHYTYPE_POS 6UL +#define USB_DWC2_GHWCFG2_HSPHYTYPE_MASK (0x3UL << USB_DWC2_GHWCFG2_HSPHYTYPE_POS) +#define USB_DWC2_GHWCFG2_HSPHYTYPE_UTMIPLUSULPI 3 +#define USB_DWC2_GHWCFG2_HSPHYTYPE_ULPI 2 +#define USB_DWC2_GHWCFG2_HSPHYTYPE_UTMIPLUS 1 +#define USB_DWC2_GHWCFG2_HSPHYTYPE_NO_HS 0 +#define USB_DWC2_GHWCFG2_OTGARCH_POS 3UL +#define USB_DWC2_GHWCFG2_OTGARCH_MASK (0x3UL << USB_DWC2_GHWCFG2_OTGARCH_POS) +#define USB_DWC2_GHWCFG2_OTGARCH_INTERNALDMA 2 +#define USB_DWC2_GHWCFG2_OTGARCH_EXTERNALDMA 1 +#define USB_DWC2_GHWCFG2_OTGARCH_SLAVEMODE 0 +#define USB_DWC2_GHWCFG2_OTGMODE_POS 0UL +#define USB_DWC2_GHWCFG2_OTGMODE_MASK (0x7UL << USB_DWC2_GHWCFG2_OTGMODE_POS) +#define USB_DWC2_GHWCFG2_OTGMODE_NONOTGH 6 +#define USB_DWC2_GHWCFG2_OTGMODE_SRPCAPH 5 +#define USB_DWC2_GHWCFG2_OTGMODE_NONOTGD 4 +#define USB_DWC2_GHWCFG2_OTGMODE_SRPCAPD 3 +#define USB_DWC2_GHWCFG2_OTGMODE_NHNPNSRP 2 +#define USB_DWC2_GHWCFG2_OTGMODE_SRPOTG 1 +#define USB_DWC2_GHWCFG2_OTGMODE_HNPSRP 0 + +USB_DWC2_GET_FIELD_DEFINE(ghwcfg2_numdeveps, GHWCFG2_NUMDEVEPS) +USB_DWC2_GET_FIELD_DEFINE(ghwcfg2_fsphytype, GHWCFG2_FSPHYTYPE) +USB_DWC2_GET_FIELD_DEFINE(ghwcfg2_hsphytype, GHWCFG2_HSPHYTYPE) +USB_DWC2_GET_FIELD_DEFINE(ghwcfg2_otgarch, GHWCFG2_OTGARCH) +USB_DWC2_GET_FIELD_DEFINE(ghwcfg2_otgmode, GHWCFG2_OTGMODE) + +/* GHWCFG3 register */ +#define USB_DWC2_GHWCFG3 0x004CUL +#define USB_DWC2_GHWCFG3_DFIFODEPTH_POS 16UL +#define USB_DWC2_GHWCFG3_DFIFODEPTH_MASK (0xFFFFUL << USB_DWC2_GHWCFG3_DFIFODEPTH_POS) +#define USB_DWC2_GHWCFG3_LPMMODE_POS 15UL +#define USB_DWC2_GHWCFG3_LPMMODE BIT(USB_DWC2_GHWCFG3_LPMMODE_POS) +#define USB_DWC2_GHWCFG3_OPTFEATURE_POS 10UL +#define USB_DWC2_GHWCFG3_OPTFEATURE BIT(USB_DWC2_GHWCFG3_OPTFEATURE_POS) +#define USB_DWC2_GHWCFG3_VNDCTLSUPT_POS 9UL +#define USB_DWC2_GHWCFG3_VNDCTLSUPT BIT(USB_DWC2_GHWCFG3_VNDCTLSUPT_POS) +#define USB_DWC2_GHWCFG3_OTGEN_POS 7UL +#define USB_DWC2_GHWCFG3_OTGEN BIT(USB_DWC2_GHWCFG3_OTGEN_POS) +#define USB_DWC2_GHWCFG3_PKTSIZEWIDTH_POS 4UL +#define USB_DWC2_GHWCFG3_PKTSIZEWIDTH_MASK (0x7UL << USB_DWC2_GHWCFG3_PKTSIZEWIDTH_POS) +#define USB_DWC2_GHWCFG3_PKTSIZEWIDTH_BITS10 6U +#define USB_DWC2_GHWCFG3_PKTSIZEWIDTH_BITS9 5U +#define USB_DWC2_GHWCFG3_PKTSIZEWIDTH_BITS8 4U +#define USB_DWC2_GHWCFG3_PKTSIZEWIDTH_BITS7 3U +#define USB_DWC2_GHWCFG3_PKTSIZEWIDTH_BITS6 2U +#define USB_DWC2_GHWCFG3_PKTSIZEWIDTH_BITS5 1U +#define USB_DWC2_GHWCFG3_PKTSIZEWIDTH_BITS4 0U +#define USB_DWC2_GHWCFG3_XFERSIZEWIDTH_POS 0UL +#define USB_DWC2_GHWCFG3_XFERSIZEWIDTH_MASK (0xFUL << USB_DWC2_GHWCFG3_XFERSIZEWIDTH_POS) +#define USB_DWC2_GHWCFG3_XFERSIZEWIDTH_WIDTH19 8U +#define USB_DWC2_GHWCFG3_XFERSIZEWIDTH_WIDTH18 7U +#define USB_DWC2_GHWCFG3_XFERSIZEWIDTH_WIDTH17 6U +#define USB_DWC2_GHWCFG3_XFERSIZEWIDTH_WIDTH16 5U +#define USB_DWC2_GHWCFG3_XFERSIZEWIDTH_WIDTH15 4U +#define USB_DWC2_GHWCFG3_XFERSIZEWIDTH_WIDTH14 3U +#define USB_DWC2_GHWCFG3_XFERSIZEWIDTH_WIDTH13 2U +#define USB_DWC2_GHWCFG3_XFERSIZEWIDTH_WIDTH12 1U +#define USB_DWC2_GHWCFG3_XFERSIZEWIDTH_WIDTH11 0U + +#define GHWCFG3_PKTCOUNT(pktsizewidth) BIT_MASK(pktsizewidth + 4) +#define GHWCFG3_XFERSIZE(xfersizewidth) BIT_MASK(xfersizewidth + 11) + +USB_DWC2_GET_FIELD_DEFINE(ghwcfg3_dfifodepth, GHWCFG3_DFIFODEPTH) +USB_DWC2_GET_FIELD_DEFINE(ghwcfg3_pktsizewidth, GHWCFG3_PKTSIZEWIDTH) +USB_DWC2_GET_FIELD_DEFINE(ghwcfg3_xfersizewidth, GHWCFG3_XFERSIZEWIDTH) + +/* GHWCFG4 register */ +#define USB_DWC2_GHWCFG4 0x0050UL +#define USB_DWC2_GHWCFG4_INEPS_POS 26UL +#define USB_DWC2_GHWCFG4_INEPS_MASK (0xFUL << USB_DWC2_GHWCFG4_INEPS_POS) +#define USB_DWC2_GHWCFG4_DEDFIFOMODE_POS 25UL +#define USB_DWC2_GHWCFG4_DEDFIFOMODE BIT(USB_DWC2_GHWCFG4_DEDFIFOMODE_POS) +#define USB_DWC2_GHWCFG4_NUMCTLEPS_POS 16UL +#define USB_DWC2_GHWCFG4_NUMCTLEPS_MASK (0xFUL << USB_DWC2_GHWCFG4_NUMCTLEPS_POS) +#define USB_DWC2_GHWCFG4_PHYDATAWIDTH_POS 14UL +#define USB_DWC2_GHWCFG4_PHYDATAWIDTH_MASK (0x3UL << USB_DWC2_GHWCFG4_PHYDATAWIDTH_POS) +#define USB_DWC2_GHWCFG4_NUMDEVPERIOEPS_POS 0UL +#define USB_DWC2_GHWCFG4_NUMDEVPERIOEPS_MASK (0xFUL << USB_DWC2_GHWCFG4_NUMDEVPERIOEPS_POS) + +USB_DWC2_GET_FIELD_DEFINE(ghwcfg4_ineps, GHWCFG4_INEPS) +USB_DWC2_GET_FIELD_DEFINE(ghwcfg4_numctleps, GHWCFG4_NUMCTLEPS) +USB_DWC2_GET_FIELD_DEFINE(ghwcfg4_phydatawidth, GHWCFG4_PHYDATAWIDTH) +USB_DWC2_GET_FIELD_DEFINE(ghwcfg4_numdevperioeps, GHWCFG4_NUMDEVPERIOEPS) + +/* Device IN endpoint transmit FIFO size register */ +#define USB_DWC2_DIEPTXF1 0x0104UL +#define USB_DWC2_DIEPTXF_INEPNTXFDEP_POS 16UL +#define USB_DWC2_DIEPTXF_INEPNTXFDEP_MASK (0xFFFFUL << USB_DWC2_DIEPTXF_INEPNTXFDEP_POS) +#define USB_DWC2_DIEPTXF_INEPNTXFSTADDR_POS 0UL +#define USB_DWC2_DIEPTXF_INEPNTXFSTADDR_MASK (0xFFFFUL << USB_DWC2_DIEPTXF_INEPNTXFSTADDR_POS) + +USB_DWC2_GET_FIELD_DEFINE(dieptxf_inepntxfdep, DIEPTXF_INEPNTXFDEP) +USB_DWC2_GET_FIELD_DEFINE(dieptxf_inepntxfstaddr, DIEPTXF_INEPNTXFSTADDR) +USB_DWC2_SET_FIELD_DEFINE(dieptxf_inepntxfdep, DIEPTXF_INEPNTXFDEP) +USB_DWC2_SET_FIELD_DEFINE(dieptxf_inepntxfstaddr, DIEPTXF_INEPNTXFSTADDR) + +/* Device configuration registers */ +#define USB_DWC2_DCFG 0x0800UL +#define USB_DWC2_DCFG_DEVADDR_POS 4UL +#define USB_DWC2_DCFG_DEVADDR_MASK (0x7FUL << USB_DWC2_DCFG_DEVADDR_POS) +#define USB_DWC2_DCFG_DEVSPD_POS 0UL +#define USB_DWC2_DCFG_DEVSPD_MASK (0x03UL << USB_DWC2_DCFG_DEVSPD_POS) +#define USB_DWC2_DCFG_DEVSPD_USBHS20 0 +#define USB_DWC2_DCFG_DEVSPD_USBFS20 1 +#define USB_DWC2_DCFG_DEVSPD_USBLS116 2 +#define USB_DWC2_DCFG_DEVSPD_USBFS1148 3 + +USB_DWC2_SET_FIELD_DEFINE(dcfg_devaddr, DCFG_DEVADDR) +USB_DWC2_GET_FIELD_DEFINE(dcfg_devspd, DCFG_DEVSPD) + +/* Device control register */ +#define USB_DWC2_DCTL 0x0804UL +#define USB_DWC2_DCTL_SERVINT_POS 19UL +#define USB_DWC2_DCTL_SERVINT BIT(USB_DWC2_DCTL_SERVINT_POS) +#define USB_DWC2_DCTL_DEEPSLEEPBESLREJECT_POS 18UL +#define USB_DWC2_DCTL_DEEPSLEEPBESLREJECT BIT(USB_DWC2_DCTL_DEEPSLEEPBESLREJECT_POS) +#define USB_DWC2_DCTL_NAKONBBLE_POS 16UL +#define USB_DWC2_DCTL_NAKONBBLE BIT(USB_DWC2_DCTL_NAKONBBLE_POS) +#define USB_DWC2_DCTL_IGNRFRMNUM_POS 15UL +#define USB_DWC2_DCTL_IGNRFRMNUM BIT(USB_DWC2_DCTL_IGNRFRMNUM_POS) +#define USB_DWC2_DCTL_PWRONPRGDONE_POS 11UL +#define USB_DWC2_DCTL_PWRONPRGDONE BIT(USB_DWC2_DCTL_PWRONPRGDONE_POS) +#define USB_DWC2_DCTL_CGOUTNAK_POS 10UL +#define USB_DWC2_DCTL_CGOUTNAK BIT(USB_DWC2_DCTL_CGOUTNAK_POS) +#define USB_DWC2_DCTL_SGOUTNAK_POS 9UL +#define USB_DWC2_DCTL_SGOUTNAK BIT(USB_DWC2_DCTL_SGOUTNAK_POS) +#define USB_DWC2_DCTL_CGNPINNAK_POS 8UL +#define USB_DWC2_DCTL_CGNPINNAK BIT(USB_DWC2_DCTL_CGNPINNAK_POS) +#define USB_DWC2_DCTL_SGNPINNAK_POS 7UL +#define USB_DWC2_DCTL_SGNPINNAK BIT(USB_DWC2_DCTL_SGNPINNAK_POS) +#define USB_DWC2_DCTL_TSTCTL_POS 4UL +#define USB_DWC2_DCTL_TSTCTL_MASK (0x7UL << USB_DWC2_DCTL_TSTCTL_POS) +#define USB_DWC2_DCTL_TSTCTL_TESTFE 5UL +#define USB_DWC2_DCTL_TSTCTL_TESTPM 4UL +#define USB_DWC2_DCTL_TSTCTL_TESTSN 3UL +#define USB_DWC2_DCTL_TSTCTL_TESTK 2UL +#define USB_DWC2_DCTL_TSTCTL_TESTJ 1UL +#define USB_DWC2_DCTL_TSTCTL_DISABLED 0UL +#define USB_DWC2_DCTL_GOUTNAKSTS_POS 3UL +#define USB_DWC2_DCTL_GOUTNAKSTS BIT(USB_DWC2_DCTL_GOUTNAKSTS_POS) +#define USB_DWC2_DCTL_GNPINNAKSTS_POS 2UL +#define USB_DWC2_DCTL_GNPINNAKSTS BIT(USB_DWC2_DCTL_GNPINNAKSTS_POS) +#define USB_DWC2_DCTL_SFTDISCON_POS 1UL +#define USB_DWC2_DCTL_SFTDISCON BIT(USB_DWC2_DCTL_SFTDISCON_POS) +#define USB_DWC2_DCTL_RMTWKUPSIG_POS 0UL +#define USB_DWC2_DCTL_RMTWKUPSIG BIT(USB_DWC2_DCTL_RMTWKUPSIG_POS) + +USB_DWC2_GET_FIELD_DEFINE(dctl_tstctl, DCTL_TSTCTL) +USB_DWC2_SET_FIELD_DEFINE(dctl_tstctl, DCTL_TSTCTL) + +/* Device status register */ +#define USB_DWC2_DSTS 0x0808UL +#define USB_DWC2_DSTS_ENUMSPD_POS 1UL +#define USB_DWC2_DSTS_ENUMSPD_MASK (0x3UL << USB_DWC2_DSTS_ENUMSPD_POS) +#define USB_DWC2_DSTS_ENUMSPD_HS3060 0 +#define USB_DWC2_DSTS_ENUMSPD_FS3060 1 +#define USB_DWC2_DSTS_ENUMSPD_LS6 2 +#define USB_DWC2_DSTS_ENUMSPD_FS48 3 + +USB_DWC2_GET_FIELD_DEFINE(dsts_enumspd, DSTS_ENUMSPD) + +/* Device all endpoints interrupt registers */ +#define USB_DWC2_DAINT 0x0818UL +#define USB_DWC2_DAINTMSK 0x081CUL +#define USB_DWC2_DAINT_OUTEPINT(ep_num) BIT(16UL + ep_num) +#define USB_DWC2_DAINT_INEPINT(ep_num) BIT(ep_num) + +/* + * Device IN/OUT endpoint control register + * IN endpoint offsets 0x0900 + (0x20 * n), n = 0 .. x, + * OUT endpoint offsets 0x0B00 + (0x20 * n), n = 0 .. x, + * + */ +#define USB_DWC2_DIEPCTL0 0x0900UL +#define USB_DWC2_DOEPCTL0 0x0B00UL +#define USB_DWC2_DEPCTL_EPENA_POS 31UL +#define USB_DWC2_DEPCTL_EPENA BIT(USB_DWC2_DEPCTL_EPENA_POS) +#define USB_DWC2_DEPCTL_EPDIS_POS 30UL +#define USB_DWC2_DEPCTL_EPDIS BIT(USB_DWC2_DEPCTL_EPDIS_POS) +#define USB_DWC2_DEPCTL_SETD0PID_POS 28UL +#define USB_DWC2_DEPCTL_SETD0PID BIT(USB_DWC2_DEPCTL_SETD0PID_POS) +#define USB_DWC2_DEPCTL_SNAK_POS 27UL +#define USB_DWC2_DEPCTL_SNAK BIT(USB_DWC2_DEPCTL_SNAK_POS) +#define USB_DWC2_DEPCTL_CNAK_POS 26UL +#define USB_DWC2_DEPCTL_CNAK BIT(USB_DWC2_DEPCTL_CNAK_POS) +#define USB_DWC2_DEPCTL_TXFNUM_POS 22UL +#define USB_DWC2_DEPCTL_TXFNUM_MASK (0xFUL << USB_DWC2_DEPCTL_TXFNUM_POS) +#define USB_DWC2_DEPCTL_STALL_POS 21UL +#define USB_DWC2_DEPCTL_STALL BIT(USB_DWC2_DEPCTL_STALL_POS) +#define USB_DWC2_DEPCTL_EPTYPE_POS 18UL +#define USB_DWC2_DEPCTL_EPTYPE_MASK (0x3UL << USB_DWC2_DEPCTL_EPTYPE_POS) +#define USB_DWC2_DEPCTL_EPTYPE_INTERRUPT 3 +#define USB_DWC2_DEPCTL_EPTYPE_BULK 2 +#define USB_DWC2_DEPCTL_EPTYPE_ISO 1 +#define USB_DWC2_DEPCTL_EPTYPE_CONTROL 0 +#define USB_DWC2_DEPCTL_USBACTEP_POS 15UL +#define USB_DWC2_DEPCTL_USBACTEP BIT(USB_DWC2_DEPCTL_USBACTEP_POS) +#define USB_DWC2_DEPCTL0_MPS_POS 0UL +#define USB_DWC2_DEPCTL0_MPS_MASK (0x3UL << USB_DWC2_DEPCTL0_MPS_POS) +#define USB_DWC2_DEPCTL0_MPS_8 3 +#define USB_DWC2_DEPCTL0_MPS_16 2 +#define USB_DWC2_DEPCTL0_MPS_32 1 +#define USB_DWC2_DEPCTL0_MPS_64 0 +#define USB_DWC2_DEPCTL_MPS_POS 0UL +#define USB_DWC2_DEPCTL_MPS_MASK (0x7FF << USB_DWC2_DEPCTL_MPS_POS) + +USB_DWC2_GET_FIELD_DEFINE(depctl_txfnum, DEPCTL_TXFNUM) +USB_DWC2_SET_FIELD_DEFINE(depctl_txfnum, DEPCTL_TXFNUM) +USB_DWC2_GET_FIELD_DEFINE(depctl_eptype, DEPCTL_EPTYPE) +USB_DWC2_SET_FIELD_DEFINE(depctl_eptype, DEPCTL_EPTYPE) +USB_DWC2_GET_FIELD_DEFINE(depctl0_mps, DEPCTL0_MPS) +USB_DWC2_SET_FIELD_DEFINE(depctl0_mps, DEPCTL0_MPS) +USB_DWC2_GET_FIELD_DEFINE(depctl_mps, DEPCTL_MPS) +USB_DWC2_SET_FIELD_DEFINE(depctl_mps, DEPCTL_MPS) + +/* + * Device IN endpoint interrupt register + * offsets 0x0908 + (0x20 * n), n = 0 .. x + */ +#define USB_DWC2_DIEPINT0 0x0908UL +#define USB_DWC2_DIEPINT_NYETINTRPT_POS 14UL +#define USB_DWC2_DIEPINT_NYETINTRPT BIT(USB_DWC2_DIEPINT_NYETINTRPT_POS) +#define USB_DWC2_DIEPINT_NAKINTRPT_POS 13UL +#define USB_DWC2_DIEPINT_NAKINTRPT BIT(USB_DWC2_DIEPINT_NAKINTRPT_POS) +#define USB_DWC2_DIEPINT_BBLEERR_POS 12UL +#define USB_DWC2_DIEPINT_BBLEERR BIT(USB_DWC2_DIEPINT_BBLEERR_POS) +#define USB_DWC2_DIEPINT_PKTDRPSTS_POS 11UL +#define USB_DWC2_DIEPINT_PKTDRPSTS BIT(USB_DWC2_DIEPINT_PKTDRPSTS_POS) +#define USB_DWC2_DIEPINT_BNAINTR_POS 9UL +#define USB_DWC2_DIEPINT_BNAINTR BIT(USB_DWC2_DIEPINT_BNAINTR_POS) +#define USB_DWC2_DIEPINT_TXFIFOUNDRN_POS 8UL +#define USB_DWC2_DIEPINT_TXFIFOUNDRN BIT(USB_DWC2_DIEPINT_TXFIFOUNDRN_POS) +#define USB_DWC2_DIEPINT_TXFEMP_POS 7UL +#define USB_DWC2_DIEPINT_TXFEMP BIT(USB_DWC2_DIEPINT_TXFEMP_POS) +#define USB_DWC2_DIEPINT_INEPNAKEFF_POS 6UL +#define USB_DWC2_DIEPINT_INEPNAKEFF BIT(USB_DWC2_DIEPINT_INEPNAKEFF_POS) +#define USB_DWC2_DIEPINT_INTKNEPMIS_POS 5UL +#define USB_DWC2_DIEPINT_INTKNEPMIS BIT(USB_DWC2_DIEPINT_INTKNEPMIS_POS) +#define USB_DWC2_DIEPINT_INTKNTXFEMP_POS 4UL +#define USB_DWC2_DIEPINT_INTKNTXFEMP BIT(USB_DWC2_DIEPINT_INTKNTXFEMP_POS) +#define USB_DWC2_DIEPINT_TIMEOUT_POS 3UL +#define USB_DWC2_DIEPINT_TIMEOUT BIT(USB_DWC2_DIEPINT_TIMEOUT_POS) +#define USB_DWC2_DIEPINT_AHBERR_POS 2UL +#define USB_DWC2_DIEPINT_AHBERR BIT(USB_DWC2_DIEPINT_AHBERR_POS) +#define USB_DWC2_DIEPINT_EPDISBLD_POS 1UL +#define USB_DWC2_DIEPINT_EPDISBLD BIT(USB_DWC2_DIEPINT_EPDISBLD_POS) +#define USB_DWC2_DIEPINT_XFERCOMPL_POS 0UL +#define USB_DWC2_DIEPINT_XFERCOMPL BIT(USB_DWC2_DIEPINT_XFERCOMPL_POS) + +/* + * Device OUT endpoint interrupt register + * offsets 0x0B08 + (0x20 * n), n = 0 .. x + */ +#define USB_DWC2_DOEPINT0 0x0B08UL +#define USB_DWC2_DOEPINT_STUPPKTRCVD_POS 15UL +#define USB_DWC2_DOEPINT_STUPPKTRCVD BIT(USB_DWC2_DOEPINT_STUPPKTRCVD_POS) +#define USB_DWC2_DOEPINT_NYETINTRPT_POS 14UL +#define USB_DWC2_DOEPINT_NYETINTRPT BIT(USB_DWC2_DOEPINT_NYETINTRPT_POS) +#define USB_DWC2_DOEPINT_NAKINTRPT_POS 13UL +#define USB_DWC2_DOEPINT_NAKINTRPT BIT(USB_DWC2_DOEPINT_NAKINTRPT_POS) +#define USB_DWC2_DOEPINT_BBLEERR_POS 12UL +#define USB_DWC2_DOEPINT_BBLEERR BIT(USB_DWC2_DOEPINT_BBLEERR_POS) +#define USB_DWC2_DOEPINT_PKTDRPSTS_POS 11UL +#define USB_DWC2_DOEPINT_PKTDRPSTS BIT(USB_DWC2_DOEPINT_PKTDRPSTS_POS) +#define USB_DWC2_DOEPINT_BNAINTR_POS 9UL +#define USB_DWC2_DOEPINT_BNAINTR BIT(USB_DWC2_DOEPINT_BNAINTR_POS) +#define USB_DWC2_DOEPINT_OUTPKTERR_POS 8UL +#define USB_DWC2_DOEPINT_OUTPKTERR BIT(USB_DWC2_DOEPINT_OUTPKTERR_POS) +#define USB_DWC2_DOEPINT_BACK2BACKSETUP_POS 6UL +#define USB_DWC2_DOEPINT_BACK2BACKSETUP BIT(USB_DWC2_DOEPINT_BACK2BACKSETUP_POS) +#define USB_DWC2_DOEPINT_STSPHSERCVD_POS 5UL +#define USB_DWC2_DOEPINT_STSPHSERCVD BIT(USB_DWC2_DOEPINT_STSPHSERCVD_POS) +#define USB_DWC2_DOEPINT_OUTTKNEPDIS_POS 4UL +#define USB_DWC2_DOEPINT_OUTTKNEPDIS BIT(USB_DWC2_DOEPINT_OUTTKNEPDIS_POS) +#define USB_DWC2_DOEPINT_SETUP_POS 3UL +#define USB_DWC2_DOEPINT_SETUP BIT(USB_DWC2_DOEPINT_SETUP_POS) +#define USB_DWC2_DOEPINT_AHBERR_POS 2UL +#define USB_DWC2_DOEPINT_AHBERR BIT(USB_DWC2_DOEPINT_AHBERR_POS) +#define USB_DWC2_DOEPINT_EPDISBLD_POS 1UL +#define USB_DWC2_DOEPINT_EPDISBLD BIT(USB_DWC2_DOEPINT_EPDISBLD_POS) +#define USB_DWC2_DOEPINT_XFERCOMPL_POS 0UL +#define USB_DWC2_DOEPINT_XFERCOMPL BIT(USB_DWC2_DOEPINT_XFERCOMPL_POS) + +/* + * Device IN/OUT control endpoint transfer size register + */ +#define USB_DWC2_DIEPTSIZ0 0x0910UL +#define USB_DWC2_DOEPTSIZ0 0x0B10UL +#define USB_DWC2_DOEPTSIZ0_SUPCNT_POS 29UL +#define USB_DWC2_DOEPTSIZ0_SUPCNT_MASK (0x3UL << USB_DWC2_DOEPTSIZ0_SUPCNT_POS) +#define USB_DWC2_DOEPTSIZ0_PKTCNT_POS 19UL +#define USB_DWC2_DOEPTSIZ0_PKTCNT_MASK (0x1UL << USB_DWC2_DOEPTSIZ0_PKTCNT_POS) +#define USB_DWC2_DIEPTSIZ0_PKTCNT_POS 19UL +#define USB_DWC2_DIEPTSIZ0_PKTCNT_MASK (0x3UL << USB_DWC2_DIEPTSIZ0_PKTCNT_POS) +#define USB_DWC2_DEPTSIZ0_XFERSIZE_POS 0UL +#define USB_DWC2_DEPTSIZ0_XFERSIZE_MASK 0x7FUL + +USB_DWC2_GET_FIELD_DEFINE(doeptsiz0_supcnt, DOEPTSIZ0_SUPCNT) +USB_DWC2_GET_FIELD_DEFINE(doeptsiz0_pktcnt, DOEPTSIZ0_PKTCNT) +USB_DWC2_GET_FIELD_DEFINE(doeptsiz0_xfersize, DEPTSIZ0_XFERSIZE) +USB_DWC2_GET_FIELD_DEFINE(dieptsiz0_pktcnt, DIEPTSIZ0_PKTCNT) +USB_DWC2_GET_FIELD_DEFINE(dieptsiz0_xfersize, DEPTSIZ0_XFERSIZE) + +/* + * Device IN/OUT endpoint transfer size register + * IN at offsets 0x0910 + (0x20 * n), n = 1 .. x, + * OUT at offsets 0x0B10 + (0x20 * n), n = 1 .. x + */ +#define USB_DWC2_DEPTSIZN_PKTCNT_POS 19UL +#define USB_DWC2_DEPTSIZN_PKTCNT_MASK (0x3FFUL << USB_DWC2_DEPTSIZN_PKTCNT_POS) +#define USB_DWC2_DEPTSIZN_XFERSIZE_POS 0UL +#define USB_DWC2_DEPTSIZN_XFERSIZE_MASK 0x7FFFFUL + +USB_DWC2_GET_FIELD_DEFINE(deptsizn_pktcnt, DEPTSIZN_PKTCNT) +USB_DWC2_GET_FIELD_DEFINE(deptsizn_xfersize, DEPTSIZN_XFERSIZE) + +/* + * Device IN/OUT endpoint transfer size register + * IN at offsets 0x0910 + (0x20 * n), n = 0 .. x, + * OUT at offsets 0x0B10 + (0x20 * n), n = 0 .. x + * + * Note: Legacy definitions for the usb_dc_dw.c driver only. + */ +#define USB_DWC2_DEPTSIZ_PKT_CNT_POS 19UL +#define USB_DWC2_DIEPTSIZ0_PKT_CNT_MASK (0x3 << 19) +#define USB_DWC2_DIEPTSIZn_PKT_CNT_MASK (0x3FF << 19) +#define USB_DWC2_DOEPTSIZn_PKT_CNT_MASK (0x3FF << 19) +#define USB_DWC2_DOEPTSIZ0_PKT_CNT_MASK (0x1 << 19) +#define USB_DWC2_DOEPTSIZ_SUP_CNT_POS 29UL +#define USB_DWC2_DOEPTSIZ_SUP_CNT_MASK (0x3 << 29) +#define USB_DWC2_DEPTSIZ_XFER_SIZE_POS 0UL +#define USB_DWC2_DEPTSIZ0_XFER_SIZE_MASK 0x7F +#define USB_DWC2_DEPTSIZn_XFER_SIZE_MASK 0x7FFFF + +/* + * Device IN endpoint transmit FIFO status register, + * offsets 0x0918 + (0x20 * n), n = 0 .. x + */ +#define USB_DWC2_DTXFSTS0 0x0918UL +#define USB_DWC2_DTXFSTS_INEPTXFSPCAVAIL_POS 0UL +#define USB_DWC2_DTXFSTS_INEPTXFSPCAVAIL_MASK 0xFFFFUL + +USB_DWC2_GET_FIELD_DEFINE(dtxfsts_ineptxfspcavail, DTXFSTS_INEPTXFSPCAVAIL) + +#ifdef __cplusplus +} +#endif + +#endif /* ZEPHYR_DRIVERS_USB_COMMON_USB_DWC2_HW */ From ffbe257c765f2dabd9705cb3f9f0221bf9baa4b9 Mon Sep 17 00:00:00 2001 From: Johann Fischer Date: Tue, 7 Nov 2023 09:32:18 +0100 Subject: [PATCH 1353/3723] drivers: usb: use common usb_dwc2_hw.h header Use new common header and remove usb_dw_registers.h. No functional changes, only renaming of registers and field identifiers. Signed-off-by: Johann Fischer --- drivers/usb/device/CMakeLists.txt | 1 + drivers/usb/device/usb_dc_dw.c | 344 +++++++++++++------------- drivers/usb/device/usb_dc_dw_stm32.h | 6 +- drivers/usb/device/usb_dw_registers.h | 268 -------------------- 4 files changed, 176 insertions(+), 443 deletions(-) delete mode 100644 drivers/usb/device/usb_dw_registers.h diff --git a/drivers/usb/device/CMakeLists.txt b/drivers/usb/device/CMakeLists.txt index 534195e4a07..a66e5091f1a 100644 --- a/drivers/usb/device/CMakeLists.txt +++ b/drivers/usb/device/CMakeLists.txt @@ -3,6 +3,7 @@ if(CONFIG_USB_DEVICE_DRIVER) zephyr_library() +zephyr_library_include_directories(${ZEPHYR_BASE}/drivers/usb/common/) zephyr_library_sources_ifdef(CONFIG_USB_DW usb_dc_dw.c) zephyr_library_sources_ifdef(CONFIG_USB_DC_RPI_PICO usb_dc_rpi_pico.c) diff --git a/drivers/usb/device/usb_dc_dw.c b/drivers/usb/device/usb_dc_dw.c index 252e4f6d639..b2f6a8f0e3c 100644 --- a/drivers/usb/device/usb_dc_dw.c +++ b/drivers/usb/device/usb_dc_dw.c @@ -25,7 +25,7 @@ #include #include -#include "usb_dw_registers.h" +#include #include "usb_dc_dw_stm32.h" #include @@ -64,11 +64,11 @@ enum usb_dw_out_ep_idx { (*(uint32_t *)(POINTER_TO_UINT(base) + 0x1000 * (idx + 1))) struct usb_dw_config { - struct usb_dw_reg *const base; + struct usb_dwc2_reg *const base; struct pinctrl_dev_config *const pcfg; void (*irq_enable_func)(const struct device *dev); int (*clk_enable_func)(void); - int (*pwr_on_func)(struct usb_dw_reg *const base); + int (*pwr_on_func)(struct usb_dwc2_reg *const base); }; /* @@ -166,7 +166,7 @@ static int usb_dw_init_pinctrl(const struct usb_dw_config *const config) } \ \ static const struct usb_dw_config usb_dw_cfg_##n = { \ - .base = (struct usb_dw_reg *)DT_INST_REG_ADDR(n), \ + .base = (struct usb_dwc2_reg *)DT_INST_REG_ADDR(n), \ .pcfg = USB_DW_PINCTRL_DT_INST_DEV_CONFIG_GET(n), \ .irq_enable_func = usb_dw_irq_enable_func_##n, \ .clk_enable_func = USB_DW_GET_COMPAT_CLK_QUIRK_0(n), \ @@ -182,7 +182,7 @@ USB_DW_DEVICE_DEFINE(0) static void usb_dw_reg_dump(void) { - struct usb_dw_reg *const base = usb_dw_cfg.base; + struct usb_dwc2_reg *const base = usb_dw_cfg.base; uint8_t i; LOG_DBG("USB registers: GOTGCTL : 0x%x GOTGINT : 0x%x GAHBCFG : " @@ -200,16 +200,16 @@ static void usb_dw_reg_dump(void) for (i = 0U; i < USB_DW_OUT_EP_NUM; i++) { LOG_DBG("\n EP %d registers: DIEPCTL : 0x%x DIEPINT : " - "0x%x", i, base->in_ep_reg[i].diepctl, - base->in_ep_reg[i].diepint); + "0x%x", i, base->in_ep[i].diepctl, + base->in_ep[i].diepint); LOG_DBG(" DIEPTSIZ: 0x%x DIEPDMA : 0x%x DOEPCTL : " - "0x%x", base->in_ep_reg[i].dieptsiz, - base->in_ep_reg[i].diepdma, - base->out_ep_reg[i].doepctl); + "0x%x", base->in_ep[i].dieptsiz, + base->in_ep[i].diepdma, + base->out_ep[i].doepctl); LOG_DBG(" DOEPINT : 0x%x DOEPTSIZ: 0x%x DOEPDMA : " - "0x%x", base->out_ep_reg[i].doepint, - base->out_ep_reg[i].doeptsiz, - base->out_ep_reg[i].doepdma); + "0x%x", base->out_ep[i].doepint, + base->out_ep[i].doeptsiz, + base->out_ep[i].doepdma); } } @@ -250,11 +250,11 @@ static inline void usb_dw_udelay(uint32_t us) static int usb_dw_reset(void) { - struct usb_dw_reg *const base = usb_dw_cfg.base; + struct usb_dwc2_reg *const base = usb_dw_cfg.base; uint32_t cnt = 0U; /* Wait for AHB master idle state. */ - while (!(base->grstctl & USB_DW_GRSTCTL_AHB_IDLE)) { + while (!(base->grstctl & USB_DWC2_GRSTCTL_AHBIDLE)) { usb_dw_udelay(1); if (++cnt > USB_DW_CORE_RST_TIMEOUT_US) { @@ -266,7 +266,7 @@ static int usb_dw_reset(void) /* Core Soft Reset */ cnt = 0U; - base->grstctl |= USB_DW_GRSTCTL_C_SFT_RST; + base->grstctl |= USB_DWC2_GRSTCTL_CSFTRST; do { if (++cnt > USB_DW_CORE_RST_TIMEOUT_US) { @@ -275,7 +275,7 @@ static int usb_dw_reset(void) return -EIO; } usb_dw_udelay(1); - } while (base->grstctl & USB_DW_GRSTCTL_C_SFT_RST); + } while (base->grstctl & USB_DWC2_GRSTCTL_CSFTRST); /* Wait for 3 PHY Clocks */ usb_dw_udelay(100); @@ -285,14 +285,14 @@ static int usb_dw_reset(void) static int usb_dw_num_dev_eps(void) { - struct usb_dw_reg *const base = usb_dw_cfg.base; + struct usb_dwc2_reg *const base = usb_dw_cfg.base; return (base->ghwcfg2 >> 10) & 0xf; } static void usb_dw_flush_tx_fifo(int ep) { - struct usb_dw_reg *const base = usb_dw_cfg.base; + struct usb_dwc2_reg *const base = usb_dw_cfg.base; int fnum = usb_dw_ctrl.in_ep_ctrl[ep].fifo_num; base->grstctl = (fnum << 6) | (1<<5); @@ -302,20 +302,20 @@ static void usb_dw_flush_tx_fifo(int ep) static int usb_dw_tx_fifo_avail(int ep) { - struct usb_dw_reg *const base = usb_dw_cfg.base; + struct usb_dwc2_reg *const base = usb_dw_cfg.base; - return base->in_ep_reg[ep].dtxfsts & USB_DW_DTXFSTS_TXF_SPC_AVAIL_MASK; + return base->in_ep[ep].dtxfsts & USB_DWC2_DTXFSTS_INEPTXFSPCAVAIL_MASK; } /* Choose a FIFO number for an IN endpoint */ static int usb_dw_set_fifo(uint8_t ep) { - struct usb_dw_reg *const base = usb_dw_cfg.base; + struct usb_dwc2_reg *const base = usb_dw_cfg.base; int ep_idx = USB_EP_GET_IDX(ep); - volatile uint32_t *reg = &base->in_ep_reg[ep_idx].diepctl; + volatile uint32_t *reg = &base->in_ep[ep_idx].diepctl; uint32_t val; int fifo = 0; - int ded_fifo = !!(base->ghwcfg4 & USB_DW_GHWCFG4_DEDFIFOMODE); + int ded_fifo = !!(base->ghwcfg4 & USB_DWC2_GHWCFG4_DEDFIFOMODE); if (!ded_fifo) { /* No support for shared-FIFO mode yet, existing @@ -340,9 +340,9 @@ static int usb_dw_set_fifo(uint8_t ep) return -EINVAL; } - reg = &base->in_ep_reg[ep_idx].diepctl; - val = *reg & ~USB_DW_DEPCTL_TXFNUM_MASK; - val |= fifo << USB_DW_DEPCTL_TXFNUM_OFFSET; + reg = &base->in_ep[ep_idx].diepctl; + val = *reg & ~USB_DWC2_DEPCTL_TXFNUM_MASK; + val |= fifo << USB_DWC2_DEPCTL_TXFNUM_POS; *reg = val; } @@ -359,40 +359,40 @@ static int usb_dw_set_fifo(uint8_t ep) static int usb_dw_ep_set(uint8_t ep, uint32_t ep_mps, enum usb_dc_ep_transfer_type ep_type) { - struct usb_dw_reg *const base = usb_dw_cfg.base; + struct usb_dwc2_reg *const base = usb_dw_cfg.base; volatile uint32_t *p_depctl; uint8_t ep_idx = USB_EP_GET_IDX(ep); LOG_DBG("%s ep %x, mps %d, type %d", __func__, ep, ep_mps, ep_type); if (USB_EP_DIR_IS_OUT(ep)) { - p_depctl = &base->out_ep_reg[ep_idx].doepctl; + p_depctl = &base->out_ep[ep_idx].doepctl; usb_dw_ctrl.out_ep_ctrl[ep_idx].mps = ep_mps; } else { - p_depctl = &base->in_ep_reg[ep_idx].diepctl; + p_depctl = &base->in_ep[ep_idx].diepctl; usb_dw_ctrl.in_ep_ctrl[ep_idx].mps = ep_mps; } if (!ep_idx) { /* Set max packet size for EP0 */ - *p_depctl &= ~USB_DW_DEPCTL0_MSP_MASK; + *p_depctl &= ~USB_DWC2_DEPCTL0_MPS_MASK; switch (ep_mps) { case 8: - *p_depctl |= USB_DW_DEPCTL0_MSP_8 << - USB_DW_DEPCTL_MSP_OFFSET; + *p_depctl |= USB_DWC2_DEPCTL0_MPS_8 << + USB_DWC2_DEPCTL_MPS_POS; break; case 16: - *p_depctl |= USB_DW_DEPCTL0_MSP_16 << - USB_DW_DEPCTL_MSP_OFFSET; + *p_depctl |= USB_DWC2_DEPCTL0_MPS_16 << + USB_DWC2_DEPCTL_MPS_POS; break; case 32: - *p_depctl |= USB_DW_DEPCTL0_MSP_32 << - USB_DW_DEPCTL_MSP_OFFSET; + *p_depctl |= USB_DWC2_DEPCTL0_MPS_32 << + USB_DWC2_DEPCTL_MPS_POS; break; case 64: - *p_depctl |= USB_DW_DEPCTL0_MSP_64 << - USB_DW_DEPCTL_MSP_OFFSET; + *p_depctl |= USB_DWC2_DEPCTL0_MPS_64 << + USB_DWC2_DEPCTL_MPS_POS; break; default: return -EINVAL; @@ -400,36 +400,36 @@ static int usb_dw_ep_set(uint8_t ep, /* No need to set EP0 type */ } else { /* Set max packet size for EP */ - if (ep_mps > (USB_DW_DEPCTLn_MSP_MASK >> - USB_DW_DEPCTL_MSP_OFFSET)) { + if (ep_mps > (USB_DWC2_DEPCTL_MPS_MASK >> + USB_DWC2_DEPCTL_MPS_POS)) { return -EINVAL; } - *p_depctl &= ~USB_DW_DEPCTLn_MSP_MASK; - *p_depctl |= ep_mps << USB_DW_DEPCTL_MSP_OFFSET; + *p_depctl &= ~USB_DWC2_DEPCTL_MPS_MASK; + *p_depctl |= ep_mps << USB_DWC2_DEPCTL_MPS_POS; /* Set endpoint type */ - *p_depctl &= ~USB_DW_DEPCTL_EP_TYPE_MASK; + *p_depctl &= ~USB_DWC2_DEPCTL_EPTYPE_MASK; switch (ep_type) { case USB_DC_EP_CONTROL: - *p_depctl |= USB_DW_DEPCTL_EP_TYPE_CONTROL << - USB_DW_DEPCTL_EP_TYPE_OFFSET; + *p_depctl |= USB_DWC2_DEPCTL_EPTYPE_CONTROL << + USB_DWC2_DEPCTL_EPTYPE_POS; break; case USB_DC_EP_BULK: - *p_depctl |= USB_DW_DEPCTL_EP_TYPE_BULK << - USB_DW_DEPCTL_EP_TYPE_OFFSET; + *p_depctl |= USB_DWC2_DEPCTL_EPTYPE_BULK << + USB_DWC2_DEPCTL_EPTYPE_POS; break; case USB_DC_EP_INTERRUPT: - *p_depctl |= USB_DW_DEPCTL_EP_TYPE_INTERRUPT << - USB_DW_DEPCTL_EP_TYPE_OFFSET; + *p_depctl |= USB_DWC2_DEPCTL_EPTYPE_INTERRUPT << + USB_DWC2_DEPCTL_EPTYPE_POS; break; default: return -EINVAL; } /* sets the Endpoint Data PID to DATA0 */ - *p_depctl |= USB_DW_DEPCTL_SETDOPID; + *p_depctl |= USB_DWC2_DEPCTL_SETD0PID; } if (USB_EP_DIR_IS_IN(ep)) { @@ -445,7 +445,7 @@ static int usb_dw_ep_set(uint8_t ep, static void usb_dw_prep_rx(const uint8_t ep, uint8_t setup) { - struct usb_dw_reg *const base = usb_dw_cfg.base; + struct usb_dwc2_reg *const base = usb_dw_cfg.base; enum usb_dw_out_ep_idx ep_idx = USB_EP_GET_IDX(ep); uint32_t ep_mps = usb_dw_ctrl.out_ep_ctrl[ep_idx].mps; @@ -453,16 +453,16 @@ static void usb_dw_prep_rx(const uint8_t ep, uint8_t setup) * each time a packet is received */ - base->out_ep_reg[ep_idx].doeptsiz = - (USB_DW_SUP_CNT << USB_DW_DOEPTSIZ_SUP_CNT_OFFSET) | - (1 << USB_DW_DEPTSIZ_PKT_CNT_OFFSET) | ep_mps; + base->out_ep[ep_idx].doeptsiz = + (USB_DW_SUP_CNT << USB_DWC2_DOEPTSIZ_SUP_CNT_POS) | + (1 << USB_DWC2_DEPTSIZ_PKT_CNT_POS) | ep_mps; /* Clear NAK and enable ep */ if (!setup) { - base->out_ep_reg[ep_idx].doepctl |= USB_DW_DEPCTL_CNAK; + base->out_ep[ep_idx].doepctl |= USB_DWC2_DEPCTL_CNAK; } - base->out_ep_reg[ep_idx].doepctl |= USB_DW_DEPCTL_EP_ENA; + base->out_ep[ep_idx].doepctl |= USB_DWC2_DEPCTL_EPENA; LOG_DBG("USB OUT EP%d armed", ep_idx); } @@ -470,7 +470,7 @@ static void usb_dw_prep_rx(const uint8_t ep, uint8_t setup) static int usb_dw_tx(uint8_t ep, const uint8_t *const data, uint32_t data_len) { - struct usb_dw_reg *const base = usb_dw_cfg.base; + struct usb_dwc2_reg *const base = usb_dw_cfg.base; enum usb_dw_in_ep_idx ep_idx = USB_EP_GET_IDX(ep); uint32_t max_xfer_size, max_pkt_cnt, pkt_cnt, avail_space; uint32_t ep_mps = usb_dw_ctrl.in_ep_ctrl[ep_idx].mps; @@ -492,7 +492,7 @@ static int usb_dw_tx(uint8_t ep, const uint8_t *const data, avail_space *= 4U; if (!avail_space) { LOG_ERR("USB IN EP%d no space available, DTXFSTS %x", ep_idx, - base->in_ep_reg[ep_idx].dtxfsts); + base->in_ep[ep_idx].dtxfsts); irq_unlock(key); return -EAGAIN; } @@ -510,18 +510,18 @@ static int usb_dw_tx(uint8_t ep, const uint8_t *const data, /* Get max packet size and packet count for ep */ if (ep_idx == USB_DW_IN_EP_0) { max_pkt_cnt = - USB_DW_DIEPTSIZ0_PKT_CNT_MASK >> - USB_DW_DEPTSIZ_PKT_CNT_OFFSET; + USB_DWC2_DIEPTSIZ0_PKT_CNT_MASK >> + USB_DWC2_DEPTSIZ_PKT_CNT_POS; max_xfer_size = - USB_DW_DEPTSIZ0_XFER_SIZE_MASK >> - USB_DW_DEPTSIZ_XFER_SIZE_OFFSET; + USB_DWC2_DEPTSIZ0_XFER_SIZE_MASK >> + USB_DWC2_DEPTSIZ_XFER_SIZE_POS; } else { max_pkt_cnt = - USB_DW_DIEPTSIZn_PKT_CNT_MASK >> - USB_DW_DEPTSIZ_PKT_CNT_OFFSET; + USB_DWC2_DIEPTSIZn_PKT_CNT_MASK >> + USB_DWC2_DEPTSIZ_PKT_CNT_POS; max_xfer_size = - USB_DW_DEPTSIZn_XFER_SIZE_MASK >> - USB_DW_DEPTSIZ_XFER_SIZE_OFFSET; + USB_DWC2_DEPTSIZn_XFER_SIZE_MASK >> + USB_DWC2_DEPTSIZ_XFER_SIZE_POS; } /* Check if transfer len is too big */ @@ -551,12 +551,12 @@ static int usb_dw_tx(uint8_t ep, const uint8_t *const data, } /* Set number of packets and transfer size */ - base->in_ep_reg[ep_idx].dieptsiz = - (pkt_cnt << USB_DW_DEPTSIZ_PKT_CNT_OFFSET) | data_len; + base->in_ep[ep_idx].dieptsiz = + (pkt_cnt << USB_DWC2_DEPTSIZ_PKT_CNT_POS) | data_len; /* Clear NAK and enable ep */ - base->in_ep_reg[ep_idx].diepctl |= (USB_DW_DEPCTL_EP_ENA | - USB_DW_DEPCTL_CNAK); + base->in_ep[ep_idx].diepctl |= (USB_DWC2_DEPCTL_EPENA | + USB_DWC2_DEPCTL_CNAK); /* * Write data to FIFO, make sure that we are protected against @@ -592,7 +592,7 @@ static int usb_dw_tx(uint8_t ep, const uint8_t *const data, static int usb_dw_init(void) { - struct usb_dw_reg *const base = usb_dw_cfg.base; + struct usb_dwc2_reg *const base = usb_dw_cfg.base; uint8_t ep; int ret; @@ -605,36 +605,36 @@ static int usb_dw_init(void) * Force device mode as we do no support other roles or role changes. * Wait 25ms for the change to take effect. */ - base->gusbcfg |= USB_DW_GUSBCFG_FORCEDEVMODE; + base->gusbcfg |= USB_DWC2_GUSBCFG_FORCEDEVMODE; k_msleep(25); #ifdef CONFIG_USB_DW_USB_2_0 /* set the PHY interface to be 16-bit UTMI */ - base->gusbcfg = (base->gusbcfg & ~USB_DW_GUSBCFG_PHY_IF_MASK) | - USB_DW_GUSBCFG_PHY_IF_16_BIT; + base->gusbcfg = (base->gusbcfg & ~USB_DWC2_GUSBCFG_PHYIF_16_BIT) | + USB_DWC2_GUSBCFG_PHYIF_16_BIT; /* Set USB2.0 High Speed */ - base->dcfg |= USB_DW_DCFG_DEV_SPD_USB2_HS; + base->dcfg |= USB_DWC2_DCFG_DEVSPD_USBHS20; #else /* Set device speed to Full Speed */ - base->dcfg |= USB_DW_DCFG_DEV_SPD_FS; + base->dcfg |= USB_DWC2_DCFG_DEVSPD_USBFS1148; #endif /* Set NAK for all OUT EPs */ for (ep = 0U; ep < USB_DW_OUT_EP_NUM; ep++) { - base->out_ep_reg[ep].doepctl = USB_DW_DEPCTL_SNAK; + base->out_ep[ep].doepctl = USB_DWC2_DEPCTL_SNAK; } /* Enable global interrupts */ - base->gintmsk = USB_DW_GINTSTS_OEP_INT | - USB_DW_GINTSTS_IEP_INT | - USB_DW_GINTSTS_ENUM_DONE | - USB_DW_GINTSTS_USB_RST | - USB_DW_GINTSTS_WK_UP_INT | - USB_DW_GINTSTS_USB_SUSP; + base->gintmsk = USB_DWC2_GINTSTS_OEPINT | + USB_DWC2_GINTSTS_IEPINT | + USB_DWC2_GINTSTS_ENUMDONE | + USB_DWC2_GINTSTS_USBRST | + USB_DWC2_GINTSTS_WKUPINT | + USB_DWC2_GINTSTS_USBSUSP; /* Enable global interrupt */ - base->gahbcfg |= USB_DW_GAHBCFG_GLB_INTR_MASK; + base->gahbcfg |= USB_DWC2_GAHBCFG_GLBINTRMASK; /* Call vendor-specific function to enable peripheral */ if (usb_dw_cfg.pwr_on_func != NULL) { @@ -645,7 +645,7 @@ static int usb_dw_init(void) } /* Disable soft disconnect */ - base->dctl &= ~USB_DW_DCTL_SFT_DISCON; + base->dctl &= ~USB_DWC2_DCTL_SFTDISCON; usb_dw_reg_dump(); @@ -654,7 +654,7 @@ static int usb_dw_init(void) static void usb_dw_handle_reset(void) { - struct usb_dw_reg *const base = usb_dw_cfg.base; + struct usb_dwc2_reg *const base = usb_dw_cfg.base; LOG_DBG("USB RESET event"); @@ -664,24 +664,24 @@ static void usb_dw_handle_reset(void) } /* Clear device address during reset. */ - base->dcfg &= ~USB_DW_DCFG_DEV_ADDR_MASK; + base->dcfg &= ~USB_DWC2_DCFG_DEVADDR_MASK; /* enable global EP interrupts */ base->doepmsk = 0U; - base->gintmsk |= USB_DW_GINTSTS_RX_FLVL; - base->diepmsk |= USB_DW_DIEPINT_XFER_COMPL; + base->gintmsk |= USB_DWC2_GINTSTS_RXFLVL; + base->diepmsk |= USB_DWC2_DIEPINT_XFERCOMPL; } static void usb_dw_handle_enum_done(void) { - struct usb_dw_reg *const base = usb_dw_cfg.base; + struct usb_dwc2_reg *const base = usb_dw_cfg.base; uint32_t speed; - speed = (base->dsts & ~USB_DW_DSTS_ENUM_SPD_MASK) >> - USB_DW_DSTS_ENUM_SPD_OFFSET; + speed = (base->dsts & ~USB_DWC2_DSTS_ENUMSPD_MASK) >> + USB_DWC2_DSTS_ENUMSPD_POS; LOG_DBG("USB ENUM DONE event, %s speed detected", - speed == USB_DW_DSTS_ENUM_LS ? "Low" : "Full"); + speed == USB_DWC2_DSTS_ENUMSPD_LS6 ? "Low" : "Full"); /* Inform upper layers */ if (usb_dw_ctrl.status_cb) { @@ -692,7 +692,7 @@ static void usb_dw_handle_enum_done(void) /* USB ISR handler */ static inline void usb_dw_int_rx_flvl_handler(void) { - struct usb_dw_reg *const base = usb_dw_cfg.base; + struct usb_dwc2_reg *const base = usb_dw_cfg.base; uint32_t grxstsp = base->grxstsp; uint32_t status, xfer_size; uint8_t ep_idx; @@ -700,11 +700,11 @@ static inline void usb_dw_int_rx_flvl_handler(void) /* Packet in RX FIFO */ - ep_idx = grxstsp & USB_DW_GRXSTSR_EP_NUM_MASK; - status = (grxstsp & USB_DW_GRXSTSR_PKT_STS_MASK) >> - USB_DW_GRXSTSR_PKT_STS_OFFSET; - xfer_size = (grxstsp & USB_DW_GRXSTSR_PKT_CNT_MASK) >> - USB_DW_GRXSTSR_PKT_CNT_OFFSET; + ep_idx = grxstsp & USB_DWC2_GRXSTSR_EPNUM_MASK; + status = (grxstsp & USB_DWC2_GRXSTSR_PKTSTS_MASK) >> + USB_DWC2_GRXSTSR_PKTSTS_POS; + xfer_size = (grxstsp & USB_DWC2_GRXSTSR_BCNT_MASK) >> + USB_DWC2_GRXSTSR_BCNT_POS; LOG_DBG("USB OUT EP%u: RX_FLVL status %u, size %u", ep_idx, status, xfer_size); @@ -713,7 +713,7 @@ static inline void usb_dw_int_rx_flvl_handler(void) ep_cb = usb_dw_ctrl.out_ep_ctrl[ep_idx].cb; switch (status) { - case USB_DW_GRXSTSR_PKT_STS_SETUP: + case USB_DWC2_GRXSTSR_PKTSTS_SETUP: /* Call the registered callback if any */ if (ep_cb) { ep_cb(USB_EP_GET_ADDR(ep_idx, USB_EP_DIR_OUT), @@ -721,15 +721,15 @@ static inline void usb_dw_int_rx_flvl_handler(void) } break; - case USB_DW_GRXSTSR_PKT_STS_OUT_DATA: + case USB_DWC2_GRXSTSR_PKTSTS_OUT_DATA: if (ep_cb) { ep_cb(USB_EP_GET_ADDR(ep_idx, USB_EP_DIR_OUT), USB_DC_EP_DATA_OUT); } break; - case USB_DW_GRXSTSR_PKT_STS_OUT_DATA_DONE: - case USB_DW_GRXSTSR_PKT_STS_SETUP_DONE: + case USB_DWC2_GRXSTSR_PKTSTS_OUT_DATA_DONE: + case USB_DWC2_GRXSTSR_PKTSTS_SETUP_DONE: break; default: break; @@ -738,26 +738,26 @@ static inline void usb_dw_int_rx_flvl_handler(void) static inline void usb_dw_int_iep_handler(void) { - struct usb_dw_reg *const base = usb_dw_cfg.base; + struct usb_dwc2_reg *const base = usb_dw_cfg.base; uint32_t ep_int_status; uint8_t ep_idx; usb_dc_ep_callback ep_cb; for (ep_idx = 0U; ep_idx < USB_DW_IN_EP_NUM; ep_idx++) { - if (base->daint & USB_DW_DAINT_IN_EP_INT(ep_idx)) { + if (base->daint & USB_DWC2_DAINT_INEPINT(ep_idx)) { /* Read IN EP interrupt status */ - ep_int_status = base->in_ep_reg[ep_idx].diepint & + ep_int_status = base->in_ep[ep_idx].diepint & base->diepmsk; /* Clear IN EP interrupts */ - base->in_ep_reg[ep_idx].diepint = ep_int_status; + base->in_ep[ep_idx].diepint = ep_int_status; LOG_DBG("USB IN EP%u interrupt status: 0x%x", ep_idx, ep_int_status); ep_cb = usb_dw_ctrl.in_ep_ctrl[ep_idx].cb; if (ep_cb && - (ep_int_status & USB_DW_DIEPINT_XFER_COMPL)) { + (ep_int_status & USB_DWC2_DIEPINT_XFERCOMPL)) { /* Call the registered callback */ ep_cb(USB_EP_GET_ADDR(ep_idx, USB_EP_DIR_IN), @@ -767,23 +767,23 @@ static inline void usb_dw_int_iep_handler(void) } /* Clear interrupt. */ - base->gintsts = USB_DW_GINTSTS_IEP_INT; + base->gintsts = USB_DWC2_GINTSTS_IEPINT; } static inline void usb_dw_int_oep_handler(void) { - struct usb_dw_reg *const base = usb_dw_cfg.base; + struct usb_dwc2_reg *const base = usb_dw_cfg.base; uint32_t ep_int_status; uint8_t ep_idx; for (ep_idx = 0U; ep_idx < USB_DW_OUT_EP_NUM; ep_idx++) { - if (base->daint & USB_DW_DAINT_OUT_EP_INT(ep_idx)) { + if (base->daint & USB_DWC2_DAINT_OUTEPINT(ep_idx)) { /* Read OUT EP interrupt status */ - ep_int_status = base->out_ep_reg[ep_idx].doepint & + ep_int_status = base->out_ep[ep_idx].doepint & base->doepmsk; /* Clear OUT EP interrupts */ - base->out_ep_reg[ep_idx].doepint = ep_int_status; + base->out_ep[ep_idx].doepint = ep_int_status; LOG_DBG("USB OUT EP%u interrupt status: 0x%x\n", ep_idx, ep_int_status); @@ -791,12 +791,12 @@ static inline void usb_dw_int_oep_handler(void) } /* Clear interrupt. */ - base->gintsts = USB_DW_GINTSTS_OEP_INT; + base->gintsts = USB_DWC2_GINTSTS_OEPINT; } static void usb_dw_isr_handler(const void *unused) { - struct usb_dw_reg *const base = usb_dw_cfg.base; + struct usb_dwc2_reg *const base = usb_dw_cfg.base; uint32_t int_status; ARG_UNUSED(unused); @@ -806,51 +806,51 @@ static void usb_dw_isr_handler(const void *unused) LOG_DBG("USB GINTSTS 0x%x", int_status); - if (int_status & USB_DW_GINTSTS_USB_RST) { + if (int_status & USB_DWC2_GINTSTS_USBRST) { /* Clear interrupt. */ - base->gintsts = USB_DW_GINTSTS_USB_RST; + base->gintsts = USB_DWC2_GINTSTS_USBRST; /* Reset detected */ usb_dw_handle_reset(); } - if (int_status & USB_DW_GINTSTS_ENUM_DONE) { + if (int_status & USB_DWC2_GINTSTS_ENUMDONE) { /* Clear interrupt. */ - base->gintsts = USB_DW_GINTSTS_ENUM_DONE; + base->gintsts = USB_DWC2_GINTSTS_ENUMDONE; /* Enumeration done detected */ usb_dw_handle_enum_done(); } - if (int_status & USB_DW_GINTSTS_USB_SUSP) { + if (int_status & USB_DWC2_GINTSTS_USBSUSP) { /* Clear interrupt. */ - base->gintsts = USB_DW_GINTSTS_USB_SUSP; + base->gintsts = USB_DWC2_GINTSTS_USBSUSP; if (usb_dw_ctrl.status_cb) { usb_dw_ctrl.status_cb(USB_DC_SUSPEND, NULL); } } - if (int_status & USB_DW_GINTSTS_WK_UP_INT) { + if (int_status & USB_DWC2_GINTSTS_WKUPINT) { /* Clear interrupt. */ - base->gintsts = USB_DW_GINTSTS_WK_UP_INT; + base->gintsts = USB_DWC2_GINTSTS_WKUPINT; if (usb_dw_ctrl.status_cb) { usb_dw_ctrl.status_cb(USB_DC_RESUME, NULL); } } - if (int_status & USB_DW_GINTSTS_RX_FLVL) { + if (int_status & USB_DWC2_GINTSTS_RXFLVL) { /* Packet in RX FIFO */ usb_dw_int_rx_flvl_handler(); } - if (int_status & USB_DW_GINTSTS_IEP_INT) { + if (int_status & USB_DWC2_GINTSTS_IEPINT) { /* IN EP interrupt */ usb_dw_int_iep_handler(); } - if (int_status & USB_DW_GINTSTS_OEP_INT) { + if (int_status & USB_DWC2_GINTSTS_OEPINT) { /* No OUT interrupt expected in FIFO mode, * just clear interrupt */ @@ -894,7 +894,7 @@ int usb_dc_attach(void) int usb_dc_detach(void) { - struct usb_dw_reg *const base = usb_dw_cfg.base; + struct usb_dwc2_reg *const base = usb_dw_cfg.base; if (!usb_dw_ctrl.attached) { return 0; @@ -903,7 +903,7 @@ int usb_dc_detach(void) irq_disable(DT_INST_IRQN(0)); /* Enable soft disconnect */ - base->dctl |= USB_DW_DCTL_SFT_DISCON; + base->dctl |= USB_DWC2_DCTL_SFTDISCON; usb_dw_ctrl.attached = 0U; @@ -924,14 +924,14 @@ int usb_dc_reset(void) int usb_dc_set_address(const uint8_t addr) { - struct usb_dw_reg *const base = usb_dw_cfg.base; + struct usb_dwc2_reg *const base = usb_dw_cfg.base; - if (addr > (USB_DW_DCFG_DEV_ADDR_MASK >> USB_DW_DCFG_DEV_ADDR_OFFSET)) { + if (addr > (USB_DWC2_DCFG_DEVADDR_MASK >> USB_DWC2_DCFG_DEVADDR_POS)) { return -EINVAL; } - base->dcfg &= ~USB_DW_DCFG_DEV_ADDR_MASK; - base->dcfg |= addr << USB_DW_DCFG_DEV_ADDR_OFFSET; + base->dcfg &= ~USB_DWC2_DCFG_DEVADDR_MASK; + base->dcfg |= addr << USB_DWC2_DCFG_DEVADDR_POS; return 0; } @@ -988,7 +988,7 @@ int usb_dc_ep_configure(const struct usb_dc_ep_cfg_data * const ep_cfg) int usb_dc_ep_set_stall(const uint8_t ep) { - struct usb_dw_reg *const base = usb_dw_cfg.base; + struct usb_dwc2_reg *const base = usb_dw_cfg.base; uint8_t ep_idx = USB_EP_GET_IDX(ep); if (!usb_dw_ctrl.attached || !usb_dw_ep_is_valid(ep)) { @@ -997,9 +997,9 @@ int usb_dc_ep_set_stall(const uint8_t ep) } if (USB_EP_DIR_IS_OUT(ep)) { - base->out_ep_reg[ep_idx].doepctl |= USB_DW_DEPCTL_STALL; + base->out_ep[ep_idx].doepctl |= USB_DWC2_DEPCTL_STALL; } else { - base->in_ep_reg[ep_idx].diepctl |= USB_DW_DEPCTL_STALL; + base->in_ep[ep_idx].diepctl |= USB_DWC2_DEPCTL_STALL; } return 0; @@ -1007,7 +1007,7 @@ int usb_dc_ep_set_stall(const uint8_t ep) int usb_dc_ep_clear_stall(const uint8_t ep) { - struct usb_dw_reg *const base = usb_dw_cfg.base; + struct usb_dwc2_reg *const base = usb_dw_cfg.base; uint8_t ep_idx = USB_EP_GET_IDX(ep); if (!usb_dw_ctrl.attached || !usb_dw_ep_is_valid(ep)) { @@ -1021,9 +1021,9 @@ int usb_dc_ep_clear_stall(const uint8_t ep) } if (USB_EP_DIR_IS_OUT(ep)) { - base->out_ep_reg[ep_idx].doepctl &= ~USB_DW_DEPCTL_STALL; + base->out_ep[ep_idx].doepctl &= ~USB_DWC2_DEPCTL_STALL; } else { - base->in_ep_reg[ep_idx].diepctl &= ~USB_DW_DEPCTL_STALL; + base->in_ep[ep_idx].diepctl &= ~USB_DWC2_DEPCTL_STALL; } return 0; @@ -1031,7 +1031,7 @@ int usb_dc_ep_clear_stall(const uint8_t ep) int usb_dc_ep_halt(const uint8_t ep) { - struct usb_dw_reg *const base = usb_dw_cfg.base; + struct usb_dwc2_reg *const base = usb_dw_cfg.base; uint8_t ep_idx = USB_EP_GET_IDX(ep); volatile uint32_t *p_depctl; @@ -1045,16 +1045,16 @@ int usb_dc_ep_halt(const uint8_t ep) usb_dc_ep_set_stall(ep); } else { if (USB_EP_DIR_IS_OUT(ep)) { - p_depctl = &base->out_ep_reg[ep_idx].doepctl; + p_depctl = &base->out_ep[ep_idx].doepctl; } else { - p_depctl = &base->in_ep_reg[ep_idx].diepctl; + p_depctl = &base->in_ep[ep_idx].diepctl; } /* Set STALL and disable endpoint if enabled */ - if (*p_depctl & USB_DW_DEPCTL_EP_ENA) { - *p_depctl |= USB_DW_DEPCTL_EP_DIS | USB_DW_DEPCTL_STALL; + if (*p_depctl & USB_DWC2_DEPCTL_EPENA) { + *p_depctl |= USB_DWC2_DEPCTL_EPDIS | USB_DWC2_DEPCTL_STALL; } else { - *p_depctl |= USB_DW_DEPCTL_STALL; + *p_depctl |= USB_DWC2_DEPCTL_STALL; } } @@ -1063,7 +1063,7 @@ int usb_dc_ep_halt(const uint8_t ep) int usb_dc_ep_is_stalled(const uint8_t ep, uint8_t *const stalled) { - struct usb_dw_reg *const base = usb_dw_cfg.base; + struct usb_dwc2_reg *const base = usb_dw_cfg.base; uint8_t ep_idx = USB_EP_GET_IDX(ep); if (!usb_dw_ctrl.attached || !usb_dw_ep_is_valid(ep)) { @@ -1077,11 +1077,11 @@ int usb_dc_ep_is_stalled(const uint8_t ep, uint8_t *const stalled) *stalled = 0U; if (USB_EP_DIR_IS_OUT(ep)) { - if (base->out_ep_reg[ep_idx].doepctl & USB_DW_DEPCTL_STALL) { + if (base->out_ep[ep_idx].doepctl & USB_DWC2_DEPCTL_STALL) { *stalled = 1U; } } else { - if (base->in_ep_reg[ep_idx].diepctl & USB_DW_DEPCTL_STALL) { + if (base->in_ep[ep_idx].diepctl & USB_DWC2_DEPCTL_STALL) { *stalled = 1U; } } @@ -1091,7 +1091,7 @@ int usb_dc_ep_is_stalled(const uint8_t ep, uint8_t *const stalled) int usb_dc_ep_enable(const uint8_t ep) { - struct usb_dw_reg *const base = usb_dw_cfg.base; + struct usb_dwc2_reg *const base = usb_dw_cfg.base; uint8_t ep_idx = USB_EP_GET_IDX(ep); if (!usb_dw_ctrl.attached || !usb_dw_ep_is_valid(ep)) { @@ -1101,17 +1101,17 @@ int usb_dc_ep_enable(const uint8_t ep) /* enable EP interrupts */ if (USB_EP_DIR_IS_OUT(ep)) { - base->daintmsk |= USB_DW_DAINT_OUT_EP_INT(ep_idx); + base->daintmsk |= USB_DWC2_DAINT_OUTEPINT(ep_idx); } else { - base->daintmsk |= USB_DW_DAINT_IN_EP_INT(ep_idx); + base->daintmsk |= USB_DWC2_DAINT_INEPINT(ep_idx); } /* Activate Ep */ if (USB_EP_DIR_IS_OUT(ep)) { - base->out_ep_reg[ep_idx].doepctl |= USB_DW_DEPCTL_USB_ACT_EP; + base->out_ep[ep_idx].doepctl |= USB_DWC2_DEPCTL_USBACTEP; usb_dw_ctrl.out_ep_ctrl[ep_idx].ep_ena = 1U; } else { - base->in_ep_reg[ep_idx].diepctl |= USB_DW_DEPCTL_USB_ACT_EP; + base->in_ep[ep_idx].diepctl |= USB_DWC2_DEPCTL_USBACTEP; usb_dw_ctrl.in_ep_ctrl[ep_idx].ep_ena = 1U; } @@ -1126,7 +1126,7 @@ int usb_dc_ep_enable(const uint8_t ep) int usb_dc_ep_disable(const uint8_t ep) { - struct usb_dw_reg *const base = usb_dw_cfg.base; + struct usb_dwc2_reg *const base = usb_dw_cfg.base; uint8_t ep_idx = USB_EP_GET_IDX(ep); if (!usb_dw_ctrl.attached || !usb_dw_ep_is_valid(ep)) { @@ -1136,26 +1136,26 @@ int usb_dc_ep_disable(const uint8_t ep) /* Disable EP interrupts */ if (USB_EP_DIR_IS_OUT(ep)) { - base->daintmsk &= ~USB_DW_DAINT_OUT_EP_INT(ep_idx); - base->doepmsk &= ~USB_DW_DOEPINT_SET_UP; + base->daintmsk &= ~USB_DWC2_DAINT_OUTEPINT(ep_idx); + base->doepmsk &= ~USB_DWC2_DOEPINT_SETUP; } else { - base->daintmsk &= ~USB_DW_DAINT_IN_EP_INT(ep_idx); - base->diepmsk &= ~USB_DW_DIEPINT_XFER_COMPL; - base->gintmsk &= ~USB_DW_GINTSTS_RX_FLVL; + base->daintmsk &= ~USB_DWC2_DAINT_INEPINT(ep_idx); + base->diepmsk &= ~USB_DWC2_DIEPINT_XFERCOMPL; + base->gintmsk &= ~USB_DWC2_GINTSTS_RXFLVL; } /* De-activate, disable and set NAK for Ep */ if (USB_EP_DIR_IS_OUT(ep)) { - base->out_ep_reg[ep_idx].doepctl &= - ~(USB_DW_DEPCTL_USB_ACT_EP | - USB_DW_DEPCTL_EP_ENA | - USB_DW_DEPCTL_SNAK); + base->out_ep[ep_idx].doepctl &= + ~(USB_DWC2_DEPCTL_USBACTEP | + USB_DWC2_DEPCTL_EPENA | + USB_DWC2_DEPCTL_SNAK); usb_dw_ctrl.out_ep_ctrl[ep_idx].ep_ena = 0U; } else { - base->in_ep_reg[ep_idx].diepctl &= - ~(USB_DW_DEPCTL_USB_ACT_EP | - USB_DW_DEPCTL_EP_ENA | - USB_DW_DEPCTL_SNAK); + base->in_ep[ep_idx].diepctl &= + ~(USB_DWC2_DEPCTL_USBACTEP | + USB_DWC2_DEPCTL_EPENA | + USB_DWC2_DEPCTL_SNAK); usb_dw_ctrl.in_ep_ctrl[ep_idx].ep_ena = 0U; } @@ -1164,7 +1164,7 @@ int usb_dc_ep_disable(const uint8_t ep) int usb_dc_ep_flush(const uint8_t ep) { - struct usb_dw_reg *const base = usb_dw_cfg.base; + struct usb_dwc2_reg *const base = usb_dw_cfg.base; uint8_t ep_idx = USB_EP_GET_IDX(ep); uint32_t cnt; @@ -1179,8 +1179,8 @@ int usb_dc_ep_flush(const uint8_t ep) } /* Each endpoint has dedicated Tx FIFO */ - base->grstctl |= ep_idx << USB_DW_GRSTCTL_TX_FNUM_OFFSET; - base->grstctl |= USB_DW_GRSTCTL_TX_FFLSH; + base->grstctl |= ep_idx << USB_DWC2_GRSTCTL_TXFNUM_POS; + base->grstctl |= USB_DWC2_GRSTCTL_TXFFLSH; cnt = 0U; @@ -1190,7 +1190,7 @@ int usb_dc_ep_flush(const uint8_t ep) return -EIO; } usb_dw_udelay(1); - } while (base->grstctl & USB_DW_GRSTCTL_TX_FFLSH); + } while (base->grstctl & USB_DWC2_GRSTCTL_TXFFLSH); return 0; } @@ -1230,7 +1230,7 @@ int usb_dc_ep_write(const uint8_t ep, const uint8_t *const data, int usb_dc_ep_read_wait(uint8_t ep, uint8_t *data, uint32_t max_data_len, uint32_t *read_bytes) { - struct usb_dw_reg *const base = usb_dw_cfg.base; + struct usb_dwc2_reg *const base = usb_dw_cfg.base; uint8_t ep_idx = USB_EP_GET_IDX(ep); uint32_t i, j, data_len, bytes_to_copy; diff --git a/drivers/usb/device/usb_dc_dw_stm32.h b/drivers/usb/device/usb_dc_dw_stm32.h index 282ae41ab99..e2cd5208459 100644 --- a/drivers/usb/device/usb_dc_dw_stm32.h +++ b/drivers/usb/device/usb_dc_dw_stm32.h @@ -11,7 +11,7 @@ #include #include -#include "usb_dw_registers.h" +#include struct usb_dw_stm32_clk { const struct device *const dev; @@ -52,9 +52,9 @@ static inline int clk_enable_st_stm32f4_fsotg(const struct usb_dw_stm32_clk *con return clock_control_on(clk->dev, (void *)&clk->pclken[0]); } -static inline int pwr_on_st_stm32f4_fsotg(struct usb_dw_reg *const base) +static inline int pwr_on_st_stm32f4_fsotg(struct usb_dwc2_reg *const base) { - base->ggpio |= USB_DW_GGPIO_STM32_PWRDWN | USB_DW_GGPIO_STM32_VBDEN; + base->ggpio |= USB_DWC2_GGPIO_STM32_PWRDWN | USB_DWC2_GGPIO_STM32_VBDEN; return 0; } diff --git a/drivers/usb/device/usb_dw_registers.h b/drivers/usb/device/usb_dw_registers.h deleted file mode 100644 index 83e67c157ce..00000000000 --- a/drivers/usb/device/usb_dw_registers.h +++ /dev/null @@ -1,268 +0,0 @@ -/* - * Copyright (c) 2016 Intel Corporation - * Copyright (c) 2023 Nordic Semiconductor ASA - * - * SPDX-License-Identifier: Apache-2.0 - */ - -#ifndef ZEPHYR_DRIVERS_USB_DEVICE_USB_DW_REGISTERS_H_ -#define ZEPHYR_DRIVERS_USB_DEVICE_USB_DW_REGISTERS_H_ - -#include - -#ifdef __cplusplus -extern "C" { -#endif - -/* - * This file describes register set for the DesignWare USB 2.0 controller IP, - * other known names are OTG_FS, OTG_HS. - */ - -/* USB IN EP Register block type */ -struct usb_dw_in_ep_reg { - volatile uint32_t diepctl; - uint32_t reserved; - volatile uint32_t diepint; - uint32_t reserved1; - volatile uint32_t dieptsiz; - volatile uint32_t diepdma; - volatile uint32_t dtxfsts; - uint32_t reserved2; -}; - -/* USB OUT EP Register block type */ -struct usb_dw_out_ep_reg { - volatile uint32_t doepctl; - uint32_t reserved; - volatile uint32_t doepint; - uint32_t reserved1; - volatile uint32_t doeptsiz; - volatile uint32_t doepdma; - uint32_t reserved2; - uint32_t reserved3; -}; - -/* USB Register block type */ -struct usb_dw_reg { - volatile uint32_t gotgctl; - volatile uint32_t gotgint; - volatile uint32_t gahbcfg; - volatile uint32_t gusbcfg; - volatile uint32_t grstctl; - volatile uint32_t gintsts; - volatile uint32_t gintmsk; - volatile uint32_t grxstsr; - volatile uint32_t grxstsp; - volatile uint32_t grxfsiz; - volatile uint32_t gnptxfsiz; - uint32_t reserved[3]; - volatile uint32_t ggpio; - volatile uint32_t guid; - volatile uint32_t gsnpsid; - volatile uint32_t ghwcfg1; - volatile uint32_t ghwcfg2; - volatile uint32_t ghwcfg3; - volatile uint32_t ghwcfg4; - volatile uint32_t gdfifocfg; - uint32_t reserved1[43]; - volatile uint32_t dieptxf1; - volatile uint32_t dieptxf2; - volatile uint32_t dieptxf3; - volatile uint32_t dieptxf4; - volatile uint32_t dieptxf5; - /* Host mode register 0x0400 .. 0x0670 */ - uint32_t reserved2[442]; - /* Device mode register 0x0800 .. 0x0D00 */ - volatile uint32_t dcfg; - volatile uint32_t dctl; - volatile uint32_t dsts; - uint32_t reserved3; - volatile uint32_t diepmsk; - volatile uint32_t doepmsk; - volatile uint32_t daint; - volatile uint32_t daintmsk; - uint32_t reserved4[2]; - volatile uint32_t dvbusdis; - volatile uint32_t dvbuspulse; - volatile uint32_t dthrctl; - volatile uint32_t diepempmsk; - uint32_t reserved5[50]; - struct usb_dw_in_ep_reg in_ep_reg[16]; - struct usb_dw_out_ep_reg out_ep_reg[16]; -}; - -/* - * With the maximum number of supported endpoints, register set - * of the controller can occupy the region up to 0x0D00. - */ -BUILD_ASSERT(sizeof(struct usb_dw_reg) <= 0x0D00); - -/* AHB configuration register, offset: 0x0008 */ -#define USB_DW_GAHBCFG_DMA_EN BIT(5) -#define USB_DW_GAHBCFG_GLB_INTR_MASK BIT(0) - -/* USB configuration register, offset: 0x000C */ -#define USB_DW_GUSBCFG_FORCEDEVMODE BIT(30) -#define USB_DW_GUSBCFG_FORCEHSTMODE BIT(29) -#define USB_DW_GUSBCFG_PHY_IF_MASK BIT(3) -#define USB_DW_GUSBCFG_PHY_IF_8_BIT 0 -#define USB_DW_GUSBCFG_PHY_IF_16_BIT BIT(3) - -/* Reset register, offset: 0x0010 */ -#define USB_DW_GRSTCTL_AHB_IDLE BIT(31) -#define USB_DW_GRSTCTL_TX_FNUM_OFFSET 6 -#define USB_DW_GRSTCTL_TX_FFLSH BIT(5) -#define USB_DW_GRSTCTL_C_SFT_RST BIT(0) - -/* Core interrupt register, offset: 0x0014 */ -#define USB_DW_GINTSTS_WK_UP_INT BIT(31) -#define USB_DW_GINTSTS_OEP_INT BIT(19) -#define USB_DW_GINTSTS_IEP_INT BIT(18) -#define USB_DW_GINTSTS_ENUM_DONE BIT(13) -#define USB_DW_GINTSTS_USB_RST BIT(12) -#define USB_DW_GINTSTS_USB_SUSP BIT(11) -#define USB_DW_GINTSTS_RX_FLVL BIT(4) -#define USB_DW_GINTSTS_OTG_INT BIT(2) - -/* Status read and pop registers (device mode), offset: 0x001C 0x0020 */ -#define USB_DW_GRXSTSR_PKT_STS_MASK (0xF << 17) -#define USB_DW_GRXSTSR_PKT_STS_OFFSET 17 -#define USB_DW_GRXSTSR_PKT_STS_OUT_DATA 2 -#define USB_DW_GRXSTSR_PKT_STS_OUT_DATA_DONE 3 -#define USB_DW_GRXSTSR_PKT_STS_SETUP_DONE 4 -#define USB_DW_GRXSTSR_PKT_STS_SETUP 6 -#define USB_DW_GRXSTSR_PKT_CNT_MASK (0x7FF << 4) -#define USB_DW_GRXSTSR_PKT_CNT_OFFSET 4 -#define USB_DW_GRXSTSR_EP_NUM_MASK (0xF << 0) - -/* Application (vendor) general purpose registers, offset: 0x0038 */ -#define USB_DW_GGPIO_STM32_VBDEN BIT(21) -#define USB_DW_GGPIO_STM32_PWRDWN BIT(16) - -/* GHWCFG1 register, offset: 0x0044 */ -#define USB_DW_GHWCFG1_EPDIR_MASK(i) (0x3 << (i * 2)) -#define USB_DW_GHWCFG1_EPDIR_SHIFT(i) (i * 2) -#define USB_DW_GHWCFG1_OUTENDPT 2 -#define USB_DW_GHWCFG1_INENDPT 1 -#define USB_DW_GHWCFG1_BDIR 0 - -/* GHWCFG2 register, offset: 0x0048 */ -#define USB_DW_GHWCFG2_NUMDEVEPS_MASK (0xF << 10) -#define USB_DW_GHWCFG2_NUMDEVEPS_SHIFT 10 -#define USB_DW_GHWCFG2_FSPHYTYPE_MASK (0x3 << 8) -#define USB_DW_GHWCFG2_FSPHYTYPE_SHIFT 8 -#define USB_DW_GHWCFG2_FSPHYTYPE_FSPLUSULPI 3 -#define USB_DW_GHWCFG2_FSPHYTYPE_FSPLUSUTMI 2 -#define USB_DW_GHWCFG2_FSPHYTYPE_FS 1 -#define USB_DW_GHWCFG2_FSPHYTYPE_NO_FS 0 -#define USB_DW_GHWCFG2_HSPHYTYPE_MASK (0x3 << 6) -#define USB_DW_GHWCFG2_HSPHYTYPE_SHIFT 6 -#define USB_DW_GHWCFG2_HSPHYTYPE_UTMIPLUSULPI 3 -#define USB_DW_GHWCFG2_HSPHYTYPE_ULPI 2 -#define USB_DW_GHWCFG2_HSPHYTYPE_UTMIPLUS 1 -#define USB_DW_GHWCFG2_HSPHYTYPE_NO_HS 0 - -/* GHWCFG3 register, offset: 0x004C */ -#define USB_DW_GHWCFG3_DFIFODEPTH_MASK (0xFFFFU << 16) -#define USB_DW_GHWCFG3_DFIFODEPTH_SHIFT 16 - -/* GHWCFG4 register, offset: 0x0050 */ -#define USB_DW_GHWCFG4_INEPS_MASK (0xF << 26) -#define USB_DW_GHWCFG4_INEPS_SHIFT 26 -#define USB_DW_GHWCFG4_DEDFIFOMODE BIT(25) - -/* Device configuration registers, offset: 0x0800 */ -#define USB_DW_DCFG_DEV_ADDR_MASK (0x7F << 4) -#define USB_DW_DCFG_DEV_ADDR_OFFSET 4 -#define USB_DW_DCFG_DEV_SPD_USB2_HS 0 -#define USB_DW_DCFG_DEV_SPD_USB2_FS 1 -#define USB_DW_DCFG_DEV_SPD_LS 2 -#define USB_DW_DCFG_DEV_SPD_FS 3 - -/* Device control register, offset 0x0804 */ -#define USB_DW_DCTL_SFT_DISCON BIT(1) - -/* Device status register, offset 0x0808 */ -#define USB_DW_DSTS_ENUM_SPD_MASK (0x3 << 1) -#define USB_DW_DSTS_ENUM_SPD_OFFSET 1 -#define USB_DW_DSTS_ENUM_LS 2 -#define USB_DW_DSTS_ENUM_FS 3 - -/* Device all endpoints interrupt register, offset 0x0818 */ -#define USB_DW_DAINT_OUT_EP_INT(ep) (0x10000 << (ep)) -#define USB_DW_DAINT_IN_EP_INT(ep) (1 << (ep)) - -/* - * Device IN/OUT endpoint control register - * IN endpoint offsets 0x0900 + (0x20 * n), n = 0 .. x, - * offset 0x0900 and 0x0B00 are hardcoded to control type. - * - * REVISE: Better own definitions for DIEPTCTL0, DOEPTCTL0... - */ -#define USB_DW_DEPCTL_EP_ENA BIT(31) -#define USB_DW_DEPCTL_EP_DIS BIT(30) -#define USB_DW_DEPCTL_SETDOPID BIT(28) -#define USB_DW_DEPCTL_SNAK BIT(27) -#define USB_DW_DEPCTL_CNAK BIT(26) -#define USB_DW_DEPCTL_STALL BIT(21) -#define USB_DW_DEPCTL_TXFNUM_OFFSET 22 -#define USB_DW_DEPCTL_TXFNUM_MASK (0xF << 22) -#define USB_DW_DEPCTL_EP_TYPE_MASK (0x3 << 18) -#define USB_DW_DEPCTL_EP_TYPE_OFFSET 18 -#define USB_DW_DEPCTL_EP_TYPE_INTERRUPT 3 -#define USB_DW_DEPCTL_EP_TYPE_BULK 2 -#define USB_DW_DEPCTL_EP_TYPE_ISO 1 -#define USB_DW_DEPCTL_EP_TYPE_CONTROL 0 -#define USB_DW_DEPCTL_USB_ACT_EP BIT(15) -#define USB_DW_DEPCTL0_MSP_MASK 0x3 -#define USB_DW_DEPCTL0_MSP_8 3 -#define USB_DW_DEPCTL0_MSP_16 2 -#define USB_DW_DEPCTL0_MSP_32 1 -#define USB_DW_DEPCTL0_MSP_64 0 -#define USB_DW_DEPCTLn_MSP_MASK 0x3FF -#define USB_DW_DEPCTL_MSP_OFFSET 0 - -/* - * Device IN endpoint interrupt register - * offsets 0x0908 + (0x20 * n), n = 0 .. x - */ -#define USB_DW_DIEPINT_TX_FEMP BIT(7) -#define USB_DW_DIEPINT_XFER_COMPL BIT(0) - -/* - * Device OUT endpoint interrupt register - * offsets 0x0B08 + (0x20 * n), n = 0 .. x - */ -#define USB_DW_DOEPINT_SET_UP BIT(3) -#define USB_DW_DOEPINT_XFER_COMPL BIT(0) - -/* - * Device IN/OUT endpoint transfer size register - * IN at offsets 0x0910 + (0x20 * n), n = 0 .. x, - * OUT at offsets 0x0B10 + (0x20 * n), n = 0 .. x - * - * REVISE: Better own definitions for DIEPTSIZ0, DOEPTSIZ0... - */ -#define USB_DW_DEPTSIZ_PKT_CNT_OFFSET 19 -#define USB_DW_DIEPTSIZ0_PKT_CNT_MASK (0x3 << 19) -#define USB_DW_DIEPTSIZn_PKT_CNT_MASK (0x3FF << 19) -#define USB_DW_DOEPTSIZn_PKT_CNT_MASK (0x3FF << 19) -#define USB_DW_DOEPTSIZ0_PKT_CNT_MASK (0x1 << 19) -#define USB_DW_DOEPTSIZ_SUP_CNT_OFFSET 29 -#define USB_DW_DOEPTSIZ_SUP_CNT_MASK (0x3 << 29) -#define USB_DW_DEPTSIZ_XFER_SIZE_OFFSET 0 -#define USB_DW_DEPTSIZ0_XFER_SIZE_MASK 0x7F -#define USB_DW_DEPTSIZn_XFER_SIZE_MASK 0x7FFFF - -/* - * Device IN endpoint transmit FIFO status register, - * offsets 0x0918 + (0x20 * n), n = 0 .. x - */ -#define USB_DW_DTXFSTS_TXF_SPC_AVAIL_MASK 0xFFFF - -#ifdef __cplusplus -} -#endif - -#endif /* ZEPHYR_DRIVERS_USB_DEVICE_USB_DW_REGISTERS_H_ */ From cc2fdf2053cff2193588154fa6f9036e783bcefe Mon Sep 17 00:00:00 2001 From: Johann Fischer Date: Thu, 7 Sep 2023 13:40:13 +0200 Subject: [PATCH 1354/3723] drivers: udc: add initial support for DWC2 controller The driver currently supports only dedicated FIFO mode (with dynfifosizing if enabled). Control, bulk and interrupt transfers are supported, isochronous transfers are not yet supported. The driver accesses controller registers using sys_io.h, but for debugging purposes one can get a register map from the driver's config, similar to the usb_dc_dw.c driver. Initial support also has vendor quirks for the STM32F4 SoC family. Tested on NUCLEO-F413HG. Signed-off-by: Johann Fischer --- drivers/usb/udc/CMakeLists.txt | 3 + drivers/usb/udc/Kconfig | 1 + drivers/usb/udc/Kconfig.dwc2 | 30 + drivers/usb/udc/udc_dwc2.c | 1775 ++++++++++++++++++++++ drivers/usb/udc/udc_dwc2.h | 40 + drivers/usb/udc/udc_dwc2_vendor_quirks.h | 101 ++ 6 files changed, 1950 insertions(+) create mode 100644 drivers/usb/udc/Kconfig.dwc2 create mode 100644 drivers/usb/udc/udc_dwc2.c create mode 100644 drivers/usb/udc/udc_dwc2.h create mode 100644 drivers/usb/udc/udc_dwc2_vendor_quirks.h diff --git a/drivers/usb/udc/CMakeLists.txt b/drivers/usb/udc/CMakeLists.txt index f4f729cb181..ebca5f64277 100644 --- a/drivers/usb/udc/CMakeLists.txt +++ b/drivers/usb/udc/CMakeLists.txt @@ -4,6 +4,9 @@ zephyr_library() zephyr_library_sources(udc_common.c) +zephyr_library_include_directories(${ZEPHYR_BASE}/drivers/usb/common/) + +zephyr_library_sources_ifdef(CONFIG_UDC_DWC2 udc_dwc2.c) zephyr_library_sources_ifdef(CONFIG_UDC_NRF udc_nrf.c) zephyr_library_sources_ifdef(CONFIG_UDC_KINETIS udc_kinetis.c) zephyr_library_sources_ifdef(CONFIG_UDC_SKELETON udc_skeleton.c) diff --git a/drivers/usb/udc/Kconfig b/drivers/usb/udc/Kconfig index ef1e01d82d2..5b19a3385ad 100644 --- a/drivers/usb/udc/Kconfig +++ b/drivers/usb/udc/Kconfig @@ -47,6 +47,7 @@ module = UDC_DRIVER module-str = usb drv source "subsys/logging/Kconfig.template.log_config" +source "drivers/usb/udc/Kconfig.dwc2" source "drivers/usb/udc/Kconfig.nrf" source "drivers/usb/udc/Kconfig.kinetis" source "drivers/usb/udc/Kconfig.skeleton" diff --git a/drivers/usb/udc/Kconfig.dwc2 b/drivers/usb/udc/Kconfig.dwc2 new file mode 100644 index 00000000000..e7f7e782325 --- /dev/null +++ b/drivers/usb/udc/Kconfig.dwc2 @@ -0,0 +1,30 @@ +# Copyright (c) 2023 Nordic Semiconductor ASA +# SPDX-License-Identifier: Apache-2.0 + +config UDC_DWC2 + bool "DWC2 USB device controller driver" + default y + depends on DT_HAS_SNPS_DWC2_ENABLED + help + DWC2 USB device controller driver. + +config UDC_DWC2_STACK_SIZE + int "UDC DWC2 driver internal thread stack size" + depends on UDC_DWC2 + default 512 + help + DWC2 driver internal thread stack size. + +config UDC_DWC2_THREAD_PRIORITY + int "UDC DWC2 driver thread priority" + depends on UDC_DWC2 + default 8 + help + DWC2 driver thread priority. + +config UDC_DWC2_MAX_QMESSAGES + int "UDC DWC2 maximum number of ISR event messages" + range 4 64 + default 8 + help + DWC2 maximum number of ISR event messages. diff --git a/drivers/usb/udc/udc_dwc2.c b/drivers/usb/udc/udc_dwc2.c new file mode 100644 index 00000000000..c38e03157b6 --- /dev/null +++ b/drivers/usb/udc/udc_dwc2.c @@ -0,0 +1,1775 @@ +/* + * Copyright (c) 2023 Nordic Semiconductor ASA + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include "udc_common.h" +#include "udc_dwc2.h" +#include "udc_dwc2_vendor_quirks.h" + +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include + +#include +LOG_MODULE_REGISTER(udc_dwc2, CONFIG_UDC_DRIVER_LOG_LEVEL); + +enum dwc2_drv_event_type { + /* Trigger next transfer, must not be used for control OUT */ + DWC2_DRV_EVT_XFER, + /* Setup packet received */ + DWC2_DRV_EVT_SETUP, + /* OUT transaction for specific endpoint is finished */ + DWC2_DRV_EVT_DOUT, + /* IN transaction for specific endpoint is finished */ + DWC2_DRV_EVT_DIN, +}; + +struct dwc2_drv_event { + const struct device *dev; + enum dwc2_drv_event_type type; + uint32_t bcnt; + uint8_t ep; +}; + +K_MSGQ_DEFINE(drv_msgq, sizeof(struct dwc2_drv_event), + CONFIG_UDC_DWC2_MAX_QMESSAGES, sizeof(void *)); + + +/* Minimum RX FIFO size in 32-bit words considering the largest used OUT packet + * of 512 bytes. The value must be adjusted according to the number of OUT + * endpoints. + */ +#define UDC_DWC2_GRXFSIZ_DEFAULT (15U + 512U/4U) + +/* TX FIFO0 depth in 32-bit words (used by control IN endpoint) */ +#define UDC_DWC2_FIFO0_DEPTH 16U + +/* Number of endpoints supported by the driver. + * This must be equal to or greater than the number supported by the hardware. + * (FIXME) + */ +#define UDC_DWC2_DRV_EP_NUM 8 + +/* Get Data FIFO access register */ +#define UDC_DWC2_EP_FIFO(base, idx) ((mem_addr_t)base + 0x1000 * (idx + 1)) + +/* Driver private data per instance */ +struct udc_dwc2_data { + struct k_thread thread_data; + uint32_t ghwcfg1; + uint32_t enumspd; + uint32_t txf_set; + uint32_t grxfsiz; + uint32_t dfifodepth; + uint32_t max_xfersize; + uint32_t max_pktcnt; + uint32_t tx_len[16]; + unsigned int dynfifosizing : 1; + /* Number of endpoints in addition to control endpoint */ + uint8_t numdeveps; + /* Number of IN endpoints including control endpoint */ + uint8_t ineps; + /* Number of OUT endpoints including control endpoint */ + uint8_t outeps; + uint8_t setup[8]; +}; + +#if defined(CONFIG_PINCTRL) +#include + +static int dwc2_init_pinctrl(const struct device *dev) +{ + const struct udc_dwc2_config *const config = dev->config; + const struct pinctrl_dev_config *const pcfg = config->pcfg; + int ret = 0; + + if (pcfg == NULL) { + LOG_INF("Skip pinctrl configuration"); + return 0; + } + + ret = pinctrl_apply_state(pcfg, PINCTRL_STATE_DEFAULT); + if (ret) { + LOG_ERR("Failed to apply default pinctrl state (%d)", ret); + } + + LOG_DBG("Apply pinctrl"); + + return ret; +} +#else +static int dwc2_init_pinctrl(const struct device *dev) +{ + ARG_UNUSED(dev); + + return 0; +} +#endif + +static inline struct usb_dwc2_reg *dwc2_get_base(const struct device *dev) +{ + const struct udc_dwc2_config *const config = dev->config; + + return config->base; +} + +/* Get DOEPCTLn or DIEPCTLn register address */ +static mem_addr_t dwc2_get_dxepctl_reg(const struct device *dev, const uint8_t ep) +{ + struct usb_dwc2_reg *const base = dwc2_get_base(dev); + uint8_t ep_idx = USB_EP_GET_IDX(ep); + + if (USB_EP_DIR_IS_OUT(ep)) { + return (mem_addr_t)&base->out_ep[ep_idx].doepctl; + } else { + return (mem_addr_t)&base->in_ep[ep_idx].diepctl; + } +} + +/* Get available FIFO space in bytes */ +static uint32_t dwc2_ftx_avail(const struct device *dev, const uint32_t idx) +{ + struct usb_dwc2_reg *const base = dwc2_get_base(dev); + mem_addr_t reg = (mem_addr_t)&base->in_ep[idx].dtxfsts; + uint32_t dtxfsts; + + dtxfsts = sys_read32(reg); + + return usb_dwc2_get_dtxfsts_ineptxfspcavail(dtxfsts) * 4; +} + +static uint32_t dwc2_get_iept_pktctn(const struct device *dev, const uint32_t idx) +{ + struct udc_dwc2_data *const priv = udc_get_private(dev); + + if (idx == 0) { + return usb_dwc2_get_dieptsiz0_pktcnt(UINT32_MAX); + } else { + return priv->max_pktcnt; + } +} + +static uint32_t dwc2_get_iept_xfersize(const struct device *dev, const uint32_t idx) +{ + struct udc_dwc2_data *const priv = udc_get_private(dev); + + if (idx == 0) { + return usb_dwc2_get_dieptsiz0_xfersize(UINT32_MAX); + } else { + return priv->max_xfersize; + } +} + +static void dwc2_flush_rx_fifo(const struct device *dev) +{ + struct usb_dwc2_reg *const base = dwc2_get_base(dev); + mem_addr_t grstctl_reg = (mem_addr_t)&base->grstctl; + + sys_write32(USB_DWC2_GRSTCTL_RXFFLSH, grstctl_reg); + while (sys_read32(grstctl_reg) & USB_DWC2_GRSTCTL_RXFFLSH) { + } +} + +static void dwc2_flush_tx_fifo(const struct device *dev, const uint8_t idx) +{ + struct usb_dwc2_reg *const base = dwc2_get_base(dev); + mem_addr_t grstctl_reg = (mem_addr_t)&base->grstctl; + /* TODO: use dwc2_get_dxepctl_reg() */ + mem_addr_t diepctl_reg = (mem_addr_t)&base->in_ep[idx].diepctl; + uint32_t grstctl; + uint32_t fnum; + + fnum = usb_dwc2_get_depctl_txfnum(sys_read32(diepctl_reg)); + grstctl = usb_dwc2_set_grstctl_txfnum(fnum) | USB_DWC2_GRSTCTL_TXFFLSH; + + sys_write32(grstctl, grstctl_reg); + while (sys_read32(grstctl_reg) & USB_DWC2_GRSTCTL_TXFFLSH) { + } +} + +/* Return TX FIFOi depth in 32-bit words (i = f_idx + 1) */ +static uint32_t dwc2_get_txfdep(const struct device *dev, const uint32_t f_idx) +{ + struct usb_dwc2_reg *const base = dwc2_get_base(dev); + uint32_t dieptxf; + + dieptxf = sys_read32((mem_addr_t)&base->dieptxf[f_idx]); + + return usb_dwc2_get_dieptxf_inepntxfdep(dieptxf); +} + +/* Return TX FIFOi address (i = f_idx + 1) */ +static uint32_t dwc2_get_txfaddr(const struct device *dev, const uint32_t f_idx) +{ + struct usb_dwc2_reg *const base = dwc2_get_base(dev); + uint32_t dieptxf; + + dieptxf = sys_read32((mem_addr_t)&base->dieptxf[f_idx]); + + return usb_dwc2_get_dieptxf_inepntxfstaddr(dieptxf); +} + +/* Set TX FIFOi address and depth (i = f_idx + 1) */ +static void dwc2_set_txf(const struct device *dev, const uint32_t f_idx, + const uint32_t dep, const uint32_t addr) +{ + struct usb_dwc2_reg *const base = dwc2_get_base(dev); + uint32_t dieptxf; + + dieptxf = usb_dwc2_set_dieptxf_inepntxfdep(dep) | + usb_dwc2_set_dieptxf_inepntxfstaddr(addr); + + sys_write32(dieptxf, (mem_addr_t)&base->dieptxf[f_idx]); +} + +/* Enable/disable endpoint interrupt */ +static void dwc2_set_epint(const struct device *dev, + struct udc_ep_config *const cfg, const bool enabled) +{ + struct usb_dwc2_reg *const base = dwc2_get_base(dev); + mem_addr_t reg = (mem_addr_t)&base->daintmsk; + uint8_t ep_idx = USB_EP_GET_IDX(cfg->addr); + uint32_t epmsk; + + if (USB_EP_DIR_IS_IN(cfg->addr)) { + epmsk = USB_DWC2_DAINT_INEPINT(ep_idx); + } else { + epmsk = USB_DWC2_DAINT_OUTEPINT(ep_idx); + } + + if (enabled) { + sys_set_bits(reg, epmsk); + } else { + sys_clear_bits(reg, epmsk); + } +} + +/* Can be called from ISR context */ +static int dwc2_tx_fifo_write(const struct device *dev, + struct udc_ep_config *const cfg, struct net_buf *const buf) +{ + struct usb_dwc2_reg *const base = dwc2_get_base(dev); + struct udc_dwc2_data *const priv = udc_get_private(dev); + uint8_t ep_idx = USB_EP_GET_IDX(cfg->addr); + + mem_addr_t dieptsiz_reg = (mem_addr_t)&base->in_ep[ep_idx].dieptsiz; + /* TODO: use dwc2_get_dxepctl_reg() */ + mem_addr_t diepctl_reg = (mem_addr_t)&base->in_ep[ep_idx].diepctl; + + uint32_t max_xfersize, max_pktcnt, pktcnt, spcavail; + const size_t d = sizeof(uint32_t); + unsigned int key; + uint32_t len; + + spcavail = dwc2_ftx_avail(dev, ep_idx); + /* Round down to multiple of endpoint MPS */ + spcavail -= spcavail % cfg->mps; + /* + * Here, the available space should be equal to the FIFO space + * assigned/configured for that endpoint because we do not schedule another + * transfer until the previous one has not finished. For simplicity, + * we only check that the available space is not less than the endpoint + * MPS. + */ + if (spcavail < cfg->mps) { + LOG_ERR("ep 0x%02x FIFO space is too low, %u (%u)", + cfg->addr, spcavail, dwc2_ftx_avail(dev, ep_idx)); + return -EAGAIN; + } + + len = MIN(buf->len, spcavail); + + if (len != 0U) { + max_pktcnt = dwc2_get_iept_pktctn(dev, ep_idx); + max_xfersize = dwc2_get_iept_xfersize(dev, ep_idx); + + if (len > max_xfersize) { + /* + * Avoid short packets if the transfer size cannot be + * handled in one set. + */ + len = ROUND_DOWN(max_xfersize, cfg->mps); + } + + /* + * Determine the number of packets for the current transfer; + * if the pktcnt is too large, truncate the actual transfer length. + */ + pktcnt = DIV_ROUND_UP(len, cfg->mps); + if (pktcnt > max_pktcnt) { + pktcnt = max_pktcnt; + len = pktcnt * cfg->mps; + } + } else { + /* ZLP */ + pktcnt = 1U; + } + + LOG_DBG("Prepare ep 0x%02x xfer len %u pktcnt %u spcavail %u", + cfg->addr, len, pktcnt, spcavail); + priv->tx_len[ep_idx] = len; + + /* Lock and write to endpoint FIFO */ + key = irq_lock(); + + /* Set number of packets and transfer size */ + sys_write32((pktcnt << USB_DWC2_DEPTSIZN_PKTCNT_POS) | len, dieptsiz_reg); + + /* Clear NAK and set endpoint enable */ + sys_set_bits(diepctl_reg, USB_DWC2_DEPCTL_EPENA | USB_DWC2_DEPCTL_CNAK); + + /* FIFO access is always in 32-bit words */ + + for (uint32_t i = 0UL; i < len; i += d) { + uint32_t val = buf->data[i]; + + if (i + 1 < len) { + val |= ((uint32_t)buf->data[i + 1UL]) << 8; + } + if (i + 2 < len) { + val |= ((uint32_t)buf->data[i + 2UL]) << 16; + } + if (i + 3 < len) { + val |= ((uint32_t)buf->data[i + 3UL]) << 24; + } + + sys_write32(val, UDC_DWC2_EP_FIFO(base, ep_idx)); + } + + irq_unlock(key); + + return 0; +} + +static inline int dwc2_read_fifo(const struct device *dev, const uint8_t ep, + struct net_buf *const buf, const size_t size) +{ + struct usb_dwc2_reg *const base = dwc2_get_base(dev); + size_t len = MIN(size, net_buf_tailroom(buf)); + const size_t d = sizeof(uint32_t); + + /* FIFO access is always in 32-bit words */ + + for (uint32_t n = 0; n < (len / d); n++) { + net_buf_add_le32(buf, sys_read32(UDC_DWC2_EP_FIFO(base, ep))); + } + + if (len % d) { + uint8_t r[4]; + + /* Get the remaining */ + sys_put_le32(sys_read32(UDC_DWC2_EP_FIFO(base, ep)), r); + for (uint32_t i = 0U; i < (len % d); i++) { + net_buf_add_u8(buf, r[i]); + } + } + + if (unlikely(size > len)) { + for (uint32_t n = 0; n < DIV_ROUND_UP(size - len, d); n++) { + (void)sys_read32(UDC_DWC2_EP_FIFO(base, ep)); + } + } + + return 0; +} + +/* Can be called from ISR and we call it only when there is a buffer in the queue */ +static void dwc2_prep_rx(const struct device *dev, + struct udc_ep_config *const cfg, const bool ncnak) +{ + struct usb_dwc2_reg *const base = dwc2_get_base(dev); + uint8_t ep_idx = USB_EP_GET_IDX(cfg->addr); + mem_addr_t doeptsiz_reg = (mem_addr_t)&base->out_ep[ep_idx].doeptsiz; + mem_addr_t doepctl_reg = dwc2_get_dxepctl_reg(dev, ep_idx); + uint32_t doeptsiz; + + doeptsiz = (1 << USB_DWC2_DOEPTSIZ0_PKTCNT_POS) | cfg->mps; + if (cfg->addr == USB_CONTROL_EP_OUT) { + doeptsiz |= (1 << USB_DWC2_DOEPTSIZ0_SUPCNT_POS); + } + + sys_write32(doeptsiz, doeptsiz_reg); + + if (ncnak) { + sys_set_bits(doepctl_reg, USB_DWC2_DEPCTL_EPENA); + } else { + sys_set_bits(doepctl_reg, USB_DWC2_DEPCTL_EPENA | USB_DWC2_DEPCTL_CNAK); + } + + LOG_INF("Prepare RX 0x%02x doeptsiz 0x%x", cfg->addr, doeptsiz); +} + +static void dwc2_handle_xfer_next(const struct device *dev, + struct udc_ep_config *const cfg) +{ + struct net_buf *buf; + + buf = udc_buf_peek(dev, cfg->addr); + if (buf == NULL) { + return; + } + + if (USB_EP_DIR_IS_OUT(cfg->addr)) { + dwc2_prep_rx(dev, cfg, 0); + } else { + if (dwc2_tx_fifo_write(dev, cfg, buf)) { + LOG_ERR("Failed to start write to TX FIFO, ep 0x%02x", + cfg->addr); + } + } + + udc_ep_set_busy(dev, cfg->addr, true); +} + +static int dwc2_ctrl_feed_dout(const struct device *dev, const size_t length) +{ + struct net_buf *buf; + + buf = udc_ctrl_alloc(dev, USB_CONTROL_EP_OUT, length); + if (buf == NULL) { + return -ENOMEM; + } + + udc_buf_put(udc_get_ep_cfg(dev, USB_CONTROL_EP_OUT), buf); + dwc2_prep_rx(dev, udc_get_ep_cfg(dev, USB_CONTROL_EP_OUT), 0); + LOG_DBG("feed buf %p", buf); + + return 0; +} + +static int dwc2_handle_evt_setup(const struct device *dev) +{ + struct udc_dwc2_data *const priv = udc_get_private(dev); + struct net_buf *buf; + int err; + + buf = udc_buf_get(dev, USB_CONTROL_EP_OUT); + if (buf == NULL) { + LOG_ERR("No buffer queued for control ep"); + return -ENODATA; + } + + net_buf_add_mem(buf, priv->setup, sizeof(priv->setup)); + udc_ep_buf_set_setup(buf); + LOG_HEXDUMP_DBG(buf->data, buf->len, "setup"); + + /* Update to next stage of control transfer */ + udc_ctrl_update_stage(dev, buf); + + /* We always allocate and feed buffer large enough for a setup packet. */ + + if (udc_ctrl_stage_is_data_out(dev)) { + /* Allocate and feed buffer for data OUT stage */ + LOG_DBG("s:%p|feed for -out-", buf); + + err = dwc2_ctrl_feed_dout(dev, udc_data_stage_length(buf)); + if (err == -ENOMEM) { + err = udc_submit_ep_event(dev, buf, err); + } + } else if (udc_ctrl_stage_is_data_in(dev)) { + LOG_DBG("s:%p|feed for -in-status", buf); + + err = dwc2_ctrl_feed_dout(dev, 8); + if (err == -ENOMEM) { + err = udc_submit_ep_event(dev, buf, err); + } + + err = udc_ctrl_submit_s_in_status(dev); + } else { + LOG_DBG("s:%p|feed >setup", buf); + + err = dwc2_ctrl_feed_dout(dev, 8); + if (err == -ENOMEM) { + err = udc_submit_ep_event(dev, buf, err); + } + + err = udc_ctrl_submit_s_status(dev); + } + + return err; +} + +static inline int dwc2_handle_evt_dout(const struct device *dev, + struct udc_ep_config *const cfg) +{ + struct net_buf *buf; + int err = 0; + + buf = udc_buf_get(dev, cfg->addr); + if (buf == NULL) { + LOG_ERR("No buffer queued for control ep"); + return -ENODATA; + } + + udc_ep_set_busy(dev, cfg->addr, false); + + if (cfg->addr == USB_CONTROL_EP_OUT) { + if (udc_ctrl_stage_is_status_out(dev)) { + /* s-in-status finished */ + LOG_DBG("dout:%p| status, feed >s", buf); + + /* Feed a buffer for the next setup packet */ + err = dwc2_ctrl_feed_dout(dev, 8); + if (err == -ENOMEM) { + err = udc_submit_ep_event(dev, buf, err); + } + + /* Status stage finished, notify upper layer */ + udc_ctrl_submit_status(dev, buf); + } else { + /* + * For all other cases we feed with a buffer + * large enough for setup packet. + */ + LOG_DBG("dout:%p| data, feed >s", buf); + + err = dwc2_ctrl_feed_dout(dev, 8); + if (err == -ENOMEM) { + err = udc_submit_ep_event(dev, buf, err); + } + } + + /* Update to next stage of control transfer */ + udc_ctrl_update_stage(dev, buf); + + if (udc_ctrl_stage_is_status_in(dev)) { + err = udc_ctrl_submit_s_out_status(dev, buf); + } + } else { + err = udc_submit_ep_event(dev, buf, 0); + } + + return err; +} + +static int dwc2_handle_evt_din(const struct device *dev, + struct udc_ep_config *const cfg) +{ + struct net_buf *buf; + + buf = udc_buf_peek(dev, cfg->addr); + if (buf == NULL) { + LOG_ERR("No buffer for ep 0x%02x", cfg->addr); + udc_submit_event(dev, UDC_EVT_ERROR, -ENOBUFS); + return -ENOBUFS; + } + + if (buf->len) { + /* Looks like we failed to continue in ISR, retry */ + return dwc2_tx_fifo_write(dev, cfg, buf); + } + + if (cfg->addr == USB_CONTROL_EP_IN && udc_ep_buf_has_zlp(buf)) { + udc_ep_buf_clear_zlp(buf); + return dwc2_tx_fifo_write(dev, cfg, buf); + } + + buf = udc_buf_get(dev, cfg->addr); + udc_ep_set_busy(dev, cfg->addr, false); + + if (cfg->addr == USB_CONTROL_EP_IN) { + if (udc_ctrl_stage_is_status_in(dev) || + udc_ctrl_stage_is_no_data(dev)) { + /* Status stage finished, notify upper layer */ + udc_ctrl_submit_status(dev, buf); + } + + /* Update to next stage of control transfer */ + udc_ctrl_update_stage(dev, buf); + + if (udc_ctrl_stage_is_status_out(dev)) { + /* + * IN transfer finished, release buffer, + * control OUT buffer should be already fed. + */ + net_buf_unref(buf); + } + + return 0; + } + + return udc_submit_ep_event(dev, buf, 0); +} + +static ALWAYS_INLINE void dwc2_thread_handler(void *const arg) +{ + const struct device *dev = (const struct device *)arg; + struct udc_ep_config *ep_cfg; + struct dwc2_drv_event evt; + + /* This is the bottom-half of the ISR handler and the place where + * a new transfer can be fed. + */ + k_msgq_get(&drv_msgq, &evt, K_FOREVER); + ep_cfg = udc_get_ep_cfg(dev, evt.ep); + + switch (evt.type) { + case DWC2_DRV_EVT_XFER: + LOG_DBG("New transfer in the queue"); + break; + case DWC2_DRV_EVT_SETUP: + LOG_DBG("SETUP event"); + dwc2_handle_evt_setup(dev); + break; + case DWC2_DRV_EVT_DOUT: + LOG_DBG("DOUT event ep 0x%02x", ep_cfg->addr); + dwc2_handle_evt_dout(dev, ep_cfg); + break; + case DWC2_DRV_EVT_DIN: + LOG_DBG("DIN event"); + dwc2_handle_evt_din(dev, ep_cfg); + break; + } + + if (ep_cfg->addr != USB_CONTROL_EP_OUT && !udc_ep_is_busy(dev, ep_cfg->addr)) { + dwc2_handle_xfer_next(dev, ep_cfg); + } else { + LOG_DBG("ep 0x%02x busy", ep_cfg->addr); + } +} + +static void dwc2_on_bus_reset(const struct device *dev) +{ + struct usb_dwc2_reg *const base = dwc2_get_base(dev); + struct udc_dwc2_data *const priv = udc_get_private(dev); + + /* Set the NAK bit for all OUT endpoints */ + for (uint8_t i = 0U; i < priv->numdeveps; i++) { + uint32_t epdir = usb_dwc2_get_ghwcfg1_epdir(priv->ghwcfg1, i); + mem_addr_t doepctl_reg; + + LOG_DBG("ep 0x%02x EPDIR %u", i, epdir); + if (epdir == USB_DWC2_GHWCFG1_EPDIR_OUT || + epdir == USB_DWC2_GHWCFG1_EPDIR_BDIR) { + doepctl_reg = dwc2_get_dxepctl_reg(dev, i); + sys_write32(USB_DWC2_DEPCTL_SNAK, doepctl_reg); + } + } + + sys_write32(0UL, (mem_addr_t)&base->doepmsk); + sys_set_bits((mem_addr_t)&base->gintmsk, USB_DWC2_GINTSTS_RXFLVL); + sys_set_bits((mem_addr_t)&base->diepmsk, USB_DWC2_DIEPINT_XFERCOMPL); + + /* Clear device address during reset. */ + sys_clear_bits((mem_addr_t)&base->dcfg, USB_DWC2_DCFG_DEVADDR_MASK); +} + +static void dwc2_handle_enumdone(const struct device *dev) +{ + struct usb_dwc2_reg *const base = dwc2_get_base(dev); + struct udc_dwc2_data *const priv = udc_get_private(dev); + uint32_t dsts; + + dsts = sys_read32((mem_addr_t)&base->dsts); + priv->enumspd = usb_dwc2_get_dsts_enumspd(dsts); +} + +static inline int dwc2_read_fifo_setup(const struct device *dev) +{ + struct usb_dwc2_reg *const base = dwc2_get_base(dev); + struct udc_dwc2_data *const priv = udc_get_private(dev); + + /* FIFO access is always in 32-bit words */ + + /* + * We store the setup packet temporarily in the driver's private data + * because there is always a race risk after the status stage OUT + * packet from the host and the new setup packet. This is fine in + * bottom-half processing because the events arrive in a queue and + * there will be a next net_buf for the setup packet. + */ + sys_put_le32(sys_read32(UDC_DWC2_EP_FIFO(base, 0)), priv->setup); + sys_put_le32(sys_read32(UDC_DWC2_EP_FIFO(base, 0)), &priv->setup[4]); + + return 0; +} + +static inline void dwc2_handle_rxflvl(const struct device *dev) +{ + struct usb_dwc2_reg *const base = dwc2_get_base(dev); + struct udc_ep_config *ep_cfg; + struct dwc2_drv_event evt; + struct net_buf *buf; + uint32_t grxstsp; + uint32_t pktsts; + + grxstsp = sys_read32((mem_addr_t)&base->grxstsp); + evt.ep = usb_dwc2_get_grxstsp_epnum(grxstsp); + evt.bcnt = usb_dwc2_get_grxstsp_bcnt(grxstsp); + pktsts = usb_dwc2_get_grxstsp_pktsts(grxstsp); + + LOG_DBG("ep 0x%02x: pktsts %u, bcnt %u", evt.ep, pktsts, evt.bcnt); + + switch (pktsts) { + case USB_DWC2_GRXSTSR_PKTSTS_SETUP: + evt.type = DWC2_DRV_EVT_SETUP; + + __ASSERT(evt.bcnt == 8, "Incorrect setup packet length"); + dwc2_read_fifo_setup(dev); + + k_msgq_put(&drv_msgq, &evt, K_NO_WAIT); + break; + case USB_DWC2_GRXSTSR_PKTSTS_OUT_DATA: + evt.type = DWC2_DRV_EVT_DOUT; + ep_cfg = udc_get_ep_cfg(dev, evt.ep); + + buf = udc_buf_peek(dev, ep_cfg->addr); + if (buf == NULL) { + LOG_ERR("No buffer for ep 0x%02x", ep_cfg->addr); + udc_submit_event(dev, UDC_EVT_ERROR, -ENOBUFS); + break; + } + + dwc2_read_fifo(dev, USB_CONTROL_EP_OUT, buf, evt.bcnt); + + if (net_buf_tailroom(buf) && evt.bcnt == ep_cfg->mps) { + dwc2_prep_rx(dev, ep_cfg, 0); + } else { + k_msgq_put(&drv_msgq, &evt, K_NO_WAIT); + } + + break; + case USB_DWC2_GRXSTSR_PKTSTS_OUT_DATA_DONE: + case USB_DWC2_GRXSTSR_PKTSTS_SETUP_DONE: + LOG_DBG("RX pktsts DONE"); + break; + default: + break; + } +} + +static inline void dwc2_handle_xfercompl(const struct device *dev, + const uint8_t ep_idx) +{ + struct udc_dwc2_data *const priv = udc_get_private(dev); + struct udc_ep_config *ep_cfg; + struct dwc2_drv_event evt; + struct net_buf *buf; + + ep_cfg = udc_get_ep_cfg(dev, ep_idx | USB_EP_DIR_IN); + buf = udc_buf_peek(dev, ep_cfg->addr); + if (buf == NULL) { + udc_submit_event(dev, UDC_EVT_ERROR, -ENOBUFS); + return; + } + + net_buf_pull(buf, priv->tx_len[ep_idx]); + if (buf->len && dwc2_tx_fifo_write(dev, ep_cfg, buf) == 0) { + return; + } + + evt.dev = dev; + evt.ep = ep_cfg->addr; + evt.type = DWC2_DRV_EVT_DIN; + k_msgq_put(&drv_msgq, &evt, K_NO_WAIT); +} + +static inline void dwc2_handle_iepint(const struct device *dev) +{ + struct usb_dwc2_reg *const base = dwc2_get_base(dev); + const uint8_t n_max = 16; + uint32_t diepmsk; + uint32_t daint; + + diepmsk = sys_read32((mem_addr_t)&base->diepmsk); + daint = sys_read32((mem_addr_t)&base->daint); + + for (uint8_t n = 0U; n < n_max; n++) { + mem_addr_t diepint_reg = (mem_addr_t)&base->in_ep[n].diepint; + uint32_t diepint; + uint32_t status; + + if (daint & USB_DWC2_DAINT_INEPINT(n)) { + /* Read and clear interrupt status */ + diepint = sys_read32(diepint_reg); + status = diepint & diepmsk; + sys_write32(status, diepint_reg); + + LOG_DBG("ep 0x%02x interrupt status: 0x%x", + n | USB_EP_DIR_IN, status); + + if (status & USB_DWC2_DIEPINT_XFERCOMPL) { + dwc2_handle_xfercompl(dev, n); + } + + } + } + + /* Clear IEPINT interrupt */ + sys_write32(USB_DWC2_GINTSTS_IEPINT, (mem_addr_t)&base->gintsts); +} + +static inline void dwc2_handle_oepint(const struct device *dev) +{ + struct usb_dwc2_reg *const base = dwc2_get_base(dev); + const uint8_t n_max = 16; + uint32_t doepmsk; + uint32_t daint; + + doepmsk = sys_read32((mem_addr_t)&base->doepmsk); + daint = sys_read32((mem_addr_t)&base->daint); + + /* No OUT interrupt expected in FIFO mode, just clear interrupt */ + for (uint8_t n = 0U; n < n_max; n++) { + mem_addr_t doepint_reg = (mem_addr_t)&base->out_ep[n].doepint; + uint32_t doepint; + uint32_t status; + + if (daint & USB_DWC2_DAINT_OUTEPINT(n)) { + /* Read and clear interrupt status */ + doepint = sys_read32(doepint_reg); + status = doepint & doepmsk; + sys_write32(status, doepint_reg); + + LOG_DBG("ep 0x%02x interrupt status: 0x%x", n, status); + } + } + + /* Clear OEPINT interrupt */ + sys_write32(USB_DWC2_GINTSTS_OEPINT, (mem_addr_t)&base->gintsts); +} + +static void udc_dwc2_isr_handler(const struct device *dev) +{ + const struct udc_dwc2_config *const config = dev->config; + struct usb_dwc2_reg *const base = config->base; + mem_addr_t gintsts_reg = (mem_addr_t)&base->gintsts; + uint32_t int_status; + uint32_t gintmsk; + + gintmsk = sys_read32((mem_addr_t)&base->gintmsk); + + /* Read and handle interrupt status register */ + while ((int_status = sys_read32(gintsts_reg) & gintmsk)) { + + LOG_DBG("GINTSTS 0x%x", int_status); + + if (int_status & USB_DWC2_GINTSTS_USBRST) { + /* Clear and handle USB Reset interrupt. */ + sys_write32(USB_DWC2_GINTSTS_USBRST, gintsts_reg); + dwc2_on_bus_reset(dev); + LOG_DBG("USB Reset interrupt"); + udc_submit_event(dev, UDC_EVT_RESET, 0); + } + + if (int_status & USB_DWC2_GINTSTS_ENUMDONE) { + /* Clear and handle Enumeration Done interrupt. */ + sys_write32(USB_DWC2_GINTSTS_ENUMDONE, gintsts_reg); + dwc2_handle_enumdone(dev); + } + + if (int_status & USB_DWC2_GINTSTS_USBSUSP) { + /* Clear USB Suspend interrupt. */ + sys_write32(USB_DWC2_GINTSTS_USBSUSP, gintsts_reg); + udc_set_suspended(dev, true); + udc_submit_event(dev, UDC_EVT_SUSPEND, 0); + } + + if (int_status & USB_DWC2_GINTSTS_WKUPINT) { + /* Clear Resume/Remote Wakeup Detected interrupt. */ + sys_write32(USB_DWC2_GINTSTS_WKUPINT, gintsts_reg); + udc_set_suspended(dev, false); + udc_submit_event(dev, UDC_EVT_RESUME, 0); + } + + if (int_status & USB_DWC2_GINTSTS_RXFLVL) { + /* Handle RxFIFO Non-Empty interrupt */ + dwc2_handle_rxflvl(dev); + } + + if (int_status & USB_DWC2_GINTSTS_IEPINT) { + /* Handle IN Endpoints interrupt */ + dwc2_handle_iepint(dev); + } + + if (int_status & USB_DWC2_GINTSTS_OEPINT) { + /* Handle OUT Endpoints interrupt */ + dwc2_handle_oepint(dev); + } + } + + if (config->quirks != NULL && config->quirks->irq_clear != NULL) { + config->quirks->irq_clear(dev); + } +} + +static int udc_dwc2_ep_enqueue(const struct device *dev, + struct udc_ep_config *const cfg, + struct net_buf *const buf) +{ + struct dwc2_drv_event evt = { + .ep = cfg->addr, + .type = DWC2_DRV_EVT_XFER, + }; + + LOG_DBG("%p enqueue %x %p", dev, cfg->addr, buf); + udc_buf_put(cfg, buf); + + if (!cfg->stat.halted) { + k_msgq_put(&drv_msgq, &evt, K_NO_WAIT); + } + + return 0; +} + +static int udc_dwc2_ep_dequeue(const struct device *dev, + struct udc_ep_config *const cfg) +{ + unsigned int lock_key; + struct net_buf *buf; + + lock_key = irq_lock(); + + if (USB_EP_DIR_IS_IN(cfg->addr)) { + dwc2_flush_tx_fifo(dev, USB_EP_GET_IDX(cfg->addr)); + } + + buf = udc_buf_get_all(dev, cfg->addr); + if (buf) { + udc_submit_ep_event(dev, buf, -ECONNABORTED); + } + + irq_unlock(lock_key); + LOG_DBG("dequeue ep 0x%02x", cfg->addr); + + return 0; +} + +static void dwc2_unset_unused_fifo(const struct device *dev) +{ + struct udc_dwc2_data *const priv = udc_get_private(dev); + struct udc_ep_config *tmp; + + for (uint8_t i = priv->ineps; i > 0; i--) { + tmp = udc_get_ep_cfg(dev, i | USB_EP_DIR_IN); + + if (tmp->stat.enabled && (priv->txf_set & BIT(i))) { + return; + } + + if (!tmp->stat.enabled && (priv->txf_set & BIT(i))) { + priv->txf_set &= ~BIT(i); + } + } +} + +/* + * In dedicated FIFO mode there are i (i = 1 ... ineps - 1) FIFO size registers, + * e.g. DIEPTXF1, DIEPTXF2, ... DIEPTXF4. When dynfifosizing is enabled, + * the size register is mutable. The offset of DIEPTXF1 registers is 0. + */ +static int dwc2_set_dedicated_fifo(const struct device *dev, + struct udc_ep_config *const cfg, + uint32_t *const diepctl) +{ + struct udc_dwc2_data *const priv = udc_get_private(dev); + uint8_t ep_idx = USB_EP_GET_IDX(cfg->addr); + uint32_t txfaddr; + uint32_t txfdep; + uint32_t tmp; + + /* Keep everything but FIFO number */ + tmp = *diepctl & ~USB_DWC2_DEPCTL_TXFNUM_MASK; + + if (priv->dynfifosizing) { + if (priv->txf_set & ~BIT_MASK(ep_idx)) { + dwc2_unset_unused_fifo(dev); + } + + if (priv->txf_set & ~BIT_MASK(ep_idx)) { + LOG_WRN("Some of the FIFOs higher than %u are set, %lx", + ep_idx, priv->txf_set & ~BIT_MASK(ep_idx)); + return -EIO; + } + + if ((ep_idx - 1) != 0U) { + txfaddr = dwc2_get_txfdep(dev, ep_idx - 2) + + dwc2_get_txfaddr(dev, ep_idx - 2); + } else { + txfaddr = UDC_DWC2_FIFO0_DEPTH + priv->grxfsiz; + } + + /* Set FIFO depth (32-bit words) and address */ + txfdep = cfg->mps / 4U; + dwc2_set_txf(dev, ep_idx - 1, txfdep, txfaddr); + } else { + txfdep = dwc2_get_txfdep(dev, ep_idx - 1); + txfaddr = dwc2_get_txfaddr(dev, ep_idx - 1); + + if (cfg->mps < txfdep * 4U) { + return -ENOMEM; + } + + LOG_DBG("Reuse FIFO%u addr 0x%08x depth %u", ep_idx, txfaddr, txfdep); + } + + /* Assign FIFO to the IN endpoint */ + *diepctl = tmp | usb_dwc2_set_depctl_txfnum(ep_idx); + priv->txf_set |= BIT(ep_idx); + dwc2_flush_tx_fifo(dev, ep_idx); + + LOG_INF("Set FIFO%u (ep 0x%02x) addr 0x%04x depth %u size %u", + ep_idx, cfg->addr, txfaddr, txfdep, dwc2_ftx_avail(dev, ep_idx)); + + return 0; +} + +static int dwc2_ep_control_enable(const struct device *dev, + struct udc_ep_config *const cfg) +{ + struct usb_dwc2_reg *const base = dwc2_get_base(dev); + struct udc_dwc2_data *const priv = udc_get_private(dev); + mem_addr_t dxepctl0_reg; + uint32_t dxepctl0; + + dxepctl0_reg = dwc2_get_dxepctl_reg(dev, cfg->addr); + dxepctl0 = sys_read32(dxepctl0_reg); + + dxepctl0 &= ~USB_DWC2_DEPCTL0_MPS_MASK; + switch (cfg->mps) { + case 8: + dxepctl0 |= USB_DWC2_DEPCTL0_MPS_8 << USB_DWC2_DEPCTL_MPS_POS; + break; + case 16: + dxepctl0 |= USB_DWC2_DEPCTL0_MPS_16 << USB_DWC2_DEPCTL_MPS_POS; + break; + case 32: + dxepctl0 |= USB_DWC2_DEPCTL0_MPS_32 << USB_DWC2_DEPCTL_MPS_POS; + break; + case 64: + dxepctl0 |= USB_DWC2_DEPCTL0_MPS_64 << USB_DWC2_DEPCTL_MPS_POS; + break; + default: + return -EINVAL; + } + + dxepctl0 |= USB_DWC2_DEPCTL_USBACTEP; + + /* + * The following applies to the Control IN endpoint only. + * + * Set endpoint 0 TxFIFO depth when dynfifosizing is enabled. + * Note that only dedicated mode is supported at this time. + */ + if (cfg->addr == USB_CONTROL_EP_IN && priv->dynfifosizing) { + uint32_t gnptxfsiz; + + gnptxfsiz = usb_dwc2_set_gnptxfsiz_nptxfdep(UDC_DWC2_FIFO0_DEPTH) | + usb_dwc2_set_gnptxfsiz_nptxfstaddr(priv->grxfsiz); + + sys_write32(gnptxfsiz, (mem_addr_t)&base->gnptxfsiz); + } + + if (cfg->addr == USB_CONTROL_EP_OUT) { + int ret; + + dwc2_flush_rx_fifo(dev); + ret = dwc2_ctrl_feed_dout(dev, 8); + if (ret) { + return ret; + } + } else { + dwc2_flush_tx_fifo(dev, 0); + } + + sys_write32(dxepctl0, dxepctl0_reg); + dwc2_set_epint(dev, cfg, true); + + return 0; +} + +static int udc_dwc2_ep_enable(const struct device *dev, + struct udc_ep_config *const cfg) +{ + struct usb_dwc2_reg *const base = dwc2_get_base(dev); + struct udc_dwc2_data *const priv = udc_get_private(dev); + uint8_t ep_idx = USB_EP_GET_IDX(cfg->addr); + mem_addr_t dxepctl_reg; + uint32_t dxepctl; + + LOG_DBG("Enable ep 0x%02x", cfg->addr); + + if (ep_idx == 0U) { + return dwc2_ep_control_enable(dev, cfg); + } + + if (USB_EP_DIR_IS_OUT(cfg->addr)) { + /* TODO: use dwc2_get_dxepctl_reg() */ + dxepctl_reg = (mem_addr_t)&base->out_ep[ep_idx].doepctl; + } else { + if (priv->ineps > 0U && ep_idx > (priv->ineps - 1U)) { + LOG_ERR("No resources available for ep 0x%02x", cfg->addr); + return -EINVAL; + } + + dxepctl_reg = (mem_addr_t)&base->in_ep[ep_idx].diepctl; + } + + if (cfg->mps > usb_dwc2_get_depctl_mps(UINT16_MAX)) { + return -EINVAL; + } + + dxepctl = sys_read32(dxepctl_reg); + /* Set max packet size */ + dxepctl &= ~USB_DWC2_DEPCTL_MPS_MASK; + dxepctl |= cfg->mps << USB_DWC2_DEPCTL_MPS_POS; + + /* Set endpoint type */ + dxepctl &= ~USB_DWC2_DEPCTL_EPTYPE_MASK; + + switch (cfg->attributes & USB_EP_TRANSFER_TYPE_MASK) { + case USB_EP_TYPE_BULK: + dxepctl |= USB_DWC2_DEPCTL_EPTYPE_BULK << + USB_DWC2_DEPCTL_EPTYPE_POS; + dxepctl |= USB_DWC2_DEPCTL_SETD0PID; + break; + case USB_EP_TYPE_INTERRUPT: + dxepctl |= USB_DWC2_DEPCTL_EPTYPE_INTERRUPT << + USB_DWC2_DEPCTL_EPTYPE_POS; + dxepctl |= USB_DWC2_DEPCTL_SETD0PID; + break; + case USB_EP_TYPE_ISO: + dxepctl |= USB_DWC2_DEPCTL_EPTYPE_ISO << + USB_DWC2_DEPCTL_EPTYPE_POS; + break; + default: + return -EINVAL; + } + + if (USB_EP_DIR_IS_IN(cfg->addr) && cfg->mps != 0U) { + int ret = dwc2_set_dedicated_fifo(dev, cfg, &dxepctl); + + if (ret) { + return ret; + } + } + + dxepctl |= USB_DWC2_DEPCTL_USBACTEP; + + /* Enable endpoint interrupts */ + dwc2_set_epint(dev, cfg, true); + sys_write32(dxepctl, dxepctl_reg); + + for (uint8_t i = 1U; i < priv->ineps; i++) { + LOG_DBG("DIEPTXF%u %08x DIEPCTL%u %08x", + i, sys_read32((mem_addr_t)base->dieptxf[i - 1U]), i, dxepctl); + } + + return 0; +} + +static int dwc2_unset_dedicated_fifo(const struct device *dev, + struct udc_ep_config *const cfg, + uint32_t *const diepctl) +{ + struct udc_dwc2_data *const priv = udc_get_private(dev); + uint8_t ep_idx = USB_EP_GET_IDX(cfg->addr); + + /* Clear FIFO number field */ + *diepctl &= ~USB_DWC2_DEPCTL_TXFNUM_MASK; + + if (priv->dynfifosizing) { + if (priv->txf_set & ~BIT_MASK(ep_idx)) { + LOG_WRN("Some of the FIFOs higher than %u are set, %lx", + ep_idx, priv->txf_set & ~BIT_MASK(ep_idx)); + return 0; + } + + dwc2_set_txf(dev, ep_idx - 1, 0, 0); + } + + priv->txf_set &= ~BIT(ep_idx); + + return 0; +} + +static int udc_dwc2_ep_disable(const struct device *dev, + struct udc_ep_config *const cfg) +{ + uint8_t ep_idx = USB_EP_GET_IDX(cfg->addr); + mem_addr_t dxepctl_reg; + uint32_t dxepctl; + + dxepctl_reg = dwc2_get_dxepctl_reg(dev, cfg->addr); + dxepctl = sys_read32(dxepctl_reg); + + if (dxepctl & USB_DWC2_DEPCTL_USBACTEP) { + LOG_DBG("Disable ep 0x%02x DxEPCTL%u %x", + cfg->addr, ep_idx, dxepctl); + dxepctl |= USB_DWC2_DEPCTL_EPDIS | USB_DWC2_DEPCTL_SNAK; + } else { + LOG_WRN("ep 0x%02x is not active DxEPCTL%u %x", + cfg->addr, ep_idx, dxepctl); + } + + if (USB_EP_DIR_IS_IN(cfg->addr) && cfg->mps != 0U && ep_idx != 0U) { + dwc2_unset_dedicated_fifo(dev, cfg, &dxepctl); + } + + sys_write32(dxepctl, dxepctl_reg); + dwc2_set_epint(dev, cfg, false); + + return 0; +} + +static int udc_dwc2_ep_set_halt(const struct device *dev, + struct udc_ep_config *const cfg) +{ + uint8_t ep_idx = USB_EP_GET_IDX(cfg->addr); + + sys_set_bits(dwc2_get_dxepctl_reg(dev, cfg->addr), USB_DWC2_DEPCTL_STALL); + + LOG_DBG("Set halt ep 0x%02x", cfg->addr); + if (ep_idx != 0) { + cfg->stat.halted = true; + } + + return 0; +} + +static int udc_dwc2_ep_clear_halt(const struct device *dev, + struct udc_ep_config *const cfg) +{ + sys_clear_bits(dwc2_get_dxepctl_reg(dev, cfg->addr), USB_DWC2_DEPCTL_STALL); + + LOG_DBG("Clear halt ep 0x%02x", cfg->addr); + cfg->stat.halted = false; + + return 0; +} + +static int udc_dwc2_set_address(const struct device *dev, const uint8_t addr) +{ + struct usb_dwc2_reg *const base = dwc2_get_base(dev); + mem_addr_t dcfg_reg = (mem_addr_t)&base->dcfg; + + if (addr > (USB_DWC2_DCFG_DEVADDR_MASK >> USB_DWC2_DCFG_DEVADDR_POS)) { + return -EINVAL; + } + + sys_clear_bits(dcfg_reg, USB_DWC2_DCFG_DEVADDR_MASK); + sys_set_bits(dcfg_reg, usb_dwc2_set_dcfg_devaddr(addr)); + LOG_DBG("Set new address %u for %p", addr, dev); + + return 0; +} + +static int udc_dwc2_test_mode(const struct device *dev, + const uint8_t mode, const bool dryrun) +{ + struct usb_dwc2_reg *const base = dwc2_get_base(dev); + mem_addr_t dctl_reg = (mem_addr_t)&base->dctl; + uint32_t tstctl; + + if (mode == 0U || mode > USB_DWC2_DCTL_TSTCTL_TESTFE) { + return -EINVAL; + } + + tstctl = usb_dwc2_get_dctl_tstctl(sys_read32(dctl_reg)); + if (tstctl != USB_DWC2_DCTL_TSTCTL_DISABLED) { + return -EALREADY; + } + + if (dryrun) { + LOG_DBG("Test Mode %u supported", mode); + return 0; + } + + sys_set_bits(dctl_reg, usb_dwc2_set_dctl_tstctl(mode)); + LOG_DBG("Enable Test Mode %u", mode); + + return 0; +} + +static int udc_dwc2_host_wakeup(const struct device *dev) +{ + LOG_DBG("Remote wakeup from %p", dev); + + return -ENOTSUP; +} + +/* Return actual USB device speed */ +static enum udc_bus_speed udc_dwc2_device_speed(const struct device *dev) +{ + struct udc_dwc2_data *const priv = udc_get_private(dev); + + switch (priv->enumspd) { + case USB_DWC2_DSTS_ENUMSPD_HS3060: + return UDC_BUS_SPEED_HS; + case USB_DWC2_DSTS_ENUMSPD_LS6: + __ASSERT(false, "Low speed mode not supported"); + __fallthrough; + case USB_DWC2_DSTS_ENUMSPD_FS48: + __fallthrough; + case USB_DWC2_DSTS_ENUMSPD_FS3060: + __fallthrough; + default: + return UDC_BUS_SPEED_FS; + } +} + +static int udc_dwc2_enable(const struct device *dev) +{ + struct usb_dwc2_reg *const base = dwc2_get_base(dev); + mem_addr_t dctl_reg = (mem_addr_t)&base->dctl; + + /* Disable soft disconnect */ + sys_clear_bits(dctl_reg, USB_DWC2_DCTL_SFTDISCON); + LOG_DBG("Enable device %p", base); + + return 0; +} + +static int udc_dwc2_disable(const struct device *dev) +{ + struct usb_dwc2_reg *const base = dwc2_get_base(dev); + mem_addr_t dctl_reg = (mem_addr_t)&base->dctl; + + /* Enable soft disconnect */ + sys_set_bits(dctl_reg, USB_DWC2_DCTL_SFTDISCON); + LOG_DBG("Disable device %p", dev); + + return 0; +} + +static int dwc2_core_soft_reset(const struct device *dev) +{ + struct usb_dwc2_reg *const base = dwc2_get_base(dev); + mem_addr_t grstctl_reg = (mem_addr_t)&base->grstctl; + const unsigned int csr_timeout_us = 10000UL; + uint32_t cnt = 0UL; + + /* Check AHB master idle state */ + while (!(sys_read32(grstctl_reg) & USB_DWC2_GRSTCTL_AHBIDLE)) { + k_busy_wait(1); + + if (++cnt > csr_timeout_us) { + LOG_ERR("Wait for AHB idle timeout, GRSTCTL 0x%08x", + sys_read32(grstctl_reg)); + return -EIO; + } + } + + /* Apply Core Soft Reset */ + sys_write32(USB_DWC2_GRSTCTL_CSFTRST, grstctl_reg); + + cnt = 0UL; + do { + if (++cnt > csr_timeout_us) { + LOG_ERR("Wait for CSR done timeout, GRSTCTL 0x%08x", + sys_read32(grstctl_reg)); + return -EIO; + } + + k_busy_wait(1); + } while (sys_read32(grstctl_reg) & USB_DWC2_GRSTCTL_CSFTRST && + !(sys_read32(grstctl_reg) & USB_DWC2_GRSTCTL_CSFTRSTDONE)); + + sys_clear_bits(grstctl_reg, USB_DWC2_GRSTCTL_CSFTRST | USB_DWC2_GRSTCTL_CSFTRSTDONE); + + return 0; +} + +static int udc_dwc2_init(const struct device *dev) +{ + const struct udc_dwc2_config *const config = dev->config; + struct udc_dwc2_data *const priv = udc_get_private(dev); + struct usb_dwc2_reg *const base = config->base; + mem_addr_t gusbcfg_reg = (mem_addr_t)&base->gusbcfg; + mem_addr_t dcfg_reg = (mem_addr_t)&base->dcfg; + uint32_t gusbcfg; + uint32_t ghwcfg2; + uint32_t ghwcfg3; + uint32_t ghwcfg4; + int ret; + + if (config->quirks != NULL && config->quirks->clk_enable != NULL) { + LOG_DBG("Enable vendor clock"); + ret = config->quirks->clk_enable(dev); + if (ret) { + return ret; + } + } + + ret = dwc2_init_pinctrl(dev); + if (ret) { + return ret; + } + + ret = dwc2_core_soft_reset(dev); + if (ret) { + return ret; + } + + priv->ghwcfg1 = sys_read32((mem_addr_t)&base->ghwcfg1); + ghwcfg2 = sys_read32((mem_addr_t)&base->ghwcfg2); + ghwcfg3 = sys_read32((mem_addr_t)&base->ghwcfg3); + ghwcfg4 = sys_read32((mem_addr_t)&base->ghwcfg4); + + if (!(ghwcfg4 & USB_DWC2_GHWCFG4_DEDFIFOMODE)) { + LOG_ERR("Only dedicated TX FIFO mode is supported"); + return -ENOTSUP; + } + + /* + * Force device mode as we do no support role changes. + * Wait 25ms for the change to take effect. + */ + gusbcfg = USB_DWC2_GUSBCFG_FORCEDEVMODE; + sys_write32(gusbcfg, gusbcfg_reg); + k_msleep(25); + + if (ghwcfg2 & USB_DWC2_GHWCFG2_DYNFIFOSIZING) { + LOG_DBG("Dynamic FIFO Sizing is enabled"); + priv->dynfifosizing = true; + } + + /* Get the number or endpoints and IN endpoints we can use later */ + priv->numdeveps = usb_dwc2_get_ghwcfg2_numdeveps(ghwcfg2); + priv->ineps = usb_dwc2_get_ghwcfg4_ineps(ghwcfg4); + LOG_DBG("Number of endpoints (NUMDEVEPS) %u", priv->numdeveps); + LOG_DBG("Number of IN endpoints (INEPS) %u", priv->ineps); + + LOG_DBG("Number of periodic IN endpoints (NUMDEVPERIOEPS) %u", + usb_dwc2_get_ghwcfg4_numdevperioeps(ghwcfg4)); + LOG_DBG("Number of additional control endpoints (NUMCTLEPS) %u", + usb_dwc2_get_ghwcfg4_numctleps(ghwcfg4)); + + LOG_DBG("OTG architecture (OTGARCH) %u, mode (OTGMODE) %u", + usb_dwc2_get_ghwcfg2_otgarch(ghwcfg2), + usb_dwc2_get_ghwcfg2_otgmode(ghwcfg2)); + + priv->dfifodepth = usb_dwc2_get_ghwcfg3_dfifodepth(ghwcfg3); + LOG_DBG("DFIFO depth (DFIFODEPTH) %u bytes", priv->dfifodepth * 4); + + priv->max_pktcnt = GHWCFG3_PKTCOUNT(usb_dwc2_get_ghwcfg3_pktsizewidth(ghwcfg3)); + priv->max_xfersize = GHWCFG3_XFERSIZE(usb_dwc2_get_ghwcfg3_xfersizewidth(ghwcfg3)); + LOG_DBG("Max packet count %u, Max transfer size %u", + priv->max_pktcnt, priv->max_xfersize); + + LOG_DBG("Vendor Control interface support enabled: %s", + (ghwcfg3 & USB_DWC2_GHWCFG3_VNDCTLSUPT) ? "true" : "false"); + + LOG_DBG("PHY interface type: FSPHYTYPE %u, HSPHYTYPE %u, DATAWIDTH %u", + usb_dwc2_get_ghwcfg2_fsphytype(ghwcfg2), + usb_dwc2_get_ghwcfg2_hsphytype(ghwcfg2), + usb_dwc2_get_ghwcfg4_phydatawidth(ghwcfg4)); + + LOG_DBG("LPM mode is %s", + (ghwcfg3 & USB_DWC2_GHWCFG3_LPMMODE) ? "enabled" : "disabled"); + + /* Configure PHY and device speed */ + switch (usb_dwc2_get_ghwcfg2_hsphytype(ghwcfg2)) { + case USB_DWC2_GHWCFG2_HSPHYTYPE_UTMIPLUSULPI: + __fallthrough; + case USB_DWC2_GHWCFG2_HSPHYTYPE_ULPI: + gusbcfg |= USB_DWC2_GUSBCFG_PHYSEL_USB20 | + USB_DWC2_GUSBCFG_ULPI_UTMI_SEL_ULPI; + sys_set_bits(dcfg_reg, USB_DWC2_DCFG_DEVSPD_USBHS20); + break; + case USB_DWC2_GHWCFG2_HSPHYTYPE_UTMIPLUS: + gusbcfg |= USB_DWC2_GUSBCFG_PHYSEL_USB20 | + USB_DWC2_GUSBCFG_ULPI_UTMI_SEL_UTMI; + sys_set_bits(dcfg_reg, USB_DWC2_DCFG_DEVSPD_USBHS20); + break; + case USB_DWC2_GHWCFG2_HSPHYTYPE_NO_HS: + __fallthrough; + default: + if (usb_dwc2_get_ghwcfg2_fsphytype(ghwcfg2) != + USB_DWC2_GHWCFG2_FSPHYTYPE_NO_FS) { + gusbcfg |= USB_DWC2_GUSBCFG_PHYSEL_USB11; + } + + sys_set_bits(dcfg_reg, USB_DWC2_DCFG_DEVSPD_USBFS1148); + } + + if (usb_dwc2_get_ghwcfg4_phydatawidth(ghwcfg4)) { + gusbcfg |= USB_DWC2_GUSBCFG_PHYIF_16_BIT; + } + + /* Update PHY configuration */ + sys_set_bits(gusbcfg_reg, gusbcfg); + + priv->outeps = 0U; + for (uint8_t i = 0U; i < priv->numdeveps; i++) { + uint32_t epdir = usb_dwc2_get_ghwcfg1_epdir(priv->ghwcfg1, i); + + if (epdir == USB_DWC2_GHWCFG1_EPDIR_OUT || + epdir == USB_DWC2_GHWCFG1_EPDIR_BDIR) { + mem_addr_t doepctl_reg = dwc2_get_dxepctl_reg(dev, i); + + sys_write32(USB_DWC2_DEPCTL_SNAK, doepctl_reg); + priv->outeps++; + } + } + + LOG_DBG("Number of OUT endpoints %u", priv->outeps); + + if (priv->dynfifosizing) { + priv->grxfsiz = UDC_DWC2_GRXFSIZ_DEFAULT + priv->outeps * 2U; + sys_write32(usb_dwc2_set_grxfsiz(priv->grxfsiz), (mem_addr_t)&base->grxfsiz); + } + + LOG_DBG("RX FIFO size %u bytes", priv->grxfsiz * 4); + for (uint8_t i = 1U; i < priv->ineps; i++) { + LOG_DBG("TX FIFO%u depth %u addr %u", + i, dwc2_get_txfdep(dev, i), dwc2_get_txfaddr(dev, i)); + } + + if (udc_ep_enable_internal(dev, USB_CONTROL_EP_OUT, + USB_EP_TYPE_CONTROL, 64, 0)) { + LOG_ERR("Failed to enable control endpoint"); + return -EIO; + } + + if (udc_ep_enable_internal(dev, USB_CONTROL_EP_IN, + USB_EP_TYPE_CONTROL, 64, 0)) { + LOG_ERR("Failed to enable control endpoint"); + return -EIO; + } + + /* Unmask interrupts */ + sys_write32(USB_DWC2_GINTSTS_OEPINT | USB_DWC2_GINTSTS_IEPINT | + USB_DWC2_GINTSTS_ENUMDONE | USB_DWC2_GINTSTS_USBRST | + USB_DWC2_GINTSTS_WKUPINT | USB_DWC2_GINTSTS_USBSUSP, + (mem_addr_t)&base->gintmsk); + + + /* Call vendor-specific function to enable peripheral */ + if (config->quirks != NULL && config->quirks->pwr_on != NULL) { + LOG_DBG("Enable vendor power"); + ret = config->quirks->pwr_on(dev); + if (ret) { + return ret; + } + } + + /* Enable global interrupt */ + sys_set_bits((mem_addr_t)&base->gahbcfg, USB_DWC2_GAHBCFG_GLBINTRMASK); + config->irq_enable_func(dev); + + return 0; +} + +static int udc_dwc2_shutdown(const struct device *dev) +{ + const struct udc_dwc2_config *const config = dev->config; + struct usb_dwc2_reg *const base = config->base; + + config->irq_disable_func(dev); + sys_clear_bits((mem_addr_t)&base->gahbcfg, USB_DWC2_GAHBCFG_GLBINTRMASK); + + if (udc_ep_disable_internal(dev, USB_CONTROL_EP_OUT)) { + LOG_DBG("Failed to disable control endpoint"); + return -EIO; + } + + if (udc_ep_disable_internal(dev, USB_CONTROL_EP_IN)) { + LOG_DBG("Failed to disable control endpoint"); + return -EIO; + } + + return 0; +} + +static int dwc2_driver_preinit(const struct device *dev) +{ + const struct udc_dwc2_config *config = dev->config; + struct udc_data *data = dev->data; + uint16_t mps = 1023; + int err; + + k_mutex_init(&data->mutex); + + data->caps.rwup = true; + data->caps.addr_before_status = true; + data->caps.mps0 = UDC_MPS0_64; + if (config->speed_idx == 2) { + data->caps.hs = true; + mps = 1024; + } + + for (int i = 0; i < config->num_of_eps; i++) { + config->ep_cfg_out[i].caps.out = 1; + if (i == 0) { + config->ep_cfg_out[i].caps.control = 1; + config->ep_cfg_out[i].caps.mps = 64; + } else { + config->ep_cfg_out[i].caps.bulk = 1; + config->ep_cfg_out[i].caps.interrupt = 1; + config->ep_cfg_out[i].caps.iso = 1; + config->ep_cfg_out[i].caps.mps = mps; + } + + config->ep_cfg_out[i].addr = USB_EP_DIR_OUT | i; + err = udc_register_ep(dev, &config->ep_cfg_out[i]); + if (err != 0) { + LOG_ERR("Failed to register endpoint"); + return err; + } + } + + for (int i = 0; i < config->num_of_eps; i++) { + config->ep_cfg_in[i].caps.in = 1; + if (i == 0) { + config->ep_cfg_in[i].caps.control = 1; + config->ep_cfg_in[i].caps.mps = 64; + } else { + config->ep_cfg_in[i].caps.bulk = 1; + config->ep_cfg_in[i].caps.interrupt = 1; + config->ep_cfg_in[i].caps.iso = 1; + config->ep_cfg_in[i].caps.mps = mps; + } + + config->ep_cfg_in[i].addr = USB_EP_DIR_IN | i; + err = udc_register_ep(dev, &config->ep_cfg_in[i]); + if (err != 0) { + LOG_ERR("Failed to register endpoint"); + return err; + } + } + + config->make_thread(dev); + + return 0; +} + +static int udc_dwc2_lock(const struct device *dev) +{ + return udc_lock_internal(dev, K_FOREVER); +} + +static int udc_dwc2_unlock(const struct device *dev) +{ + return udc_unlock_internal(dev); +} + +static const struct udc_api udc_dwc2_api = { + .lock = udc_dwc2_lock, + .unlock = udc_dwc2_unlock, + .device_speed = udc_dwc2_device_speed, + .init = udc_dwc2_init, + .enable = udc_dwc2_enable, + .disable = udc_dwc2_disable, + .shutdown = udc_dwc2_shutdown, + .set_address = udc_dwc2_set_address, + .test_mode = udc_dwc2_test_mode, + .host_wakeup = udc_dwc2_host_wakeup, + .ep_enable = udc_dwc2_ep_enable, + .ep_disable = udc_dwc2_ep_disable, + .ep_set_halt = udc_dwc2_ep_set_halt, + .ep_clear_halt = udc_dwc2_ep_clear_halt, + .ep_enqueue = udc_dwc2_ep_enqueue, + .ep_dequeue = udc_dwc2_ep_dequeue, +}; + +#define DT_DRV_COMPAT snps_dwc2 + +#define UDC_DWC2_VENDOR_QUIRK_GET(n) \ + COND_CODE_1(DT_NODE_VENDOR_HAS_IDX(DT_DRV_INST(n), 1), \ + (&dwc2_vendor_quirks_##n), \ + (NULL)) + +#define UDC_DWC2_DT_INST_REG_ADDR(n) \ + COND_CODE_1(DT_NUM_REGS(DT_DRV_INST(n)), (DT_INST_REG_ADDR(n)), \ + (DT_INST_REG_ADDR_BY_NAME(n, core))) + +#define UDC_DWC2_PINCTRL_DT_INST_DEFINE(n) \ + COND_CODE_1(DT_INST_PINCTRL_HAS_NAME(n, default), \ + (PINCTRL_DT_INST_DEFINE(n)), ()) + +#define UDC_DWC2_PINCTRL_DT_INST_DEV_CONFIG_GET(n) \ + COND_CODE_1(DT_INST_PINCTRL_HAS_NAME(n, default), \ + ((void *)PINCTRL_DT_INST_DEV_CONFIG_GET(n)), (NULL)) + +#define UDC_DWC2_IRQ_FLAGS_TYPE0(n) 0 +#define UDC_DWC2_IRQ_FLAGS_TYPE1(n) DT_INST_IRQ(n, type) +#define DW_IRQ_FLAGS(n) \ + _CONCAT(UDC_DWC2_IRQ_FLAGS_TYPE, DT_INST_IRQ_HAS_CELL(n, type))(n) + +/* + * A UDC driver should always be implemented as a multi-instance + * driver, even if your platform does not require it. + */ +#define UDC_DWC2_DEVICE_DEFINE(n) \ + UDC_DWC2_PINCTRL_DT_INST_DEFINE(n); \ + \ + K_THREAD_STACK_DEFINE(udc_dwc2_stack_##n, CONFIG_UDC_DWC2_STACK_SIZE); \ + \ + static void udc_dwc2_thread_##n(void *dev, void *arg1, void *arg2) \ + { \ + while (true) { \ + dwc2_thread_handler(dev); \ + } \ + } \ + \ + static void udc_dwc2_make_thread_##n(const struct device *dev) \ + { \ + struct udc_dwc2_data *priv = udc_get_private(dev); \ + \ + k_thread_create(&priv->thread_data, \ + udc_dwc2_stack_##n, \ + K_THREAD_STACK_SIZEOF(udc_dwc2_stack_##n), \ + udc_dwc2_thread_##n, \ + (void *)dev, NULL, NULL, \ + K_PRIO_COOP(CONFIG_UDC_DWC2_THREAD_PRIORITY), \ + K_ESSENTIAL, \ + K_NO_WAIT); \ + k_thread_name_set(&priv->thread_data, dev->name); \ + } \ + \ + static void udc_dwc2_irq_enable_func_##n(const struct device *dev) \ + { \ + IRQ_CONNECT(DT_INST_IRQN(n), \ + DT_INST_IRQ(n, priority), \ + udc_dwc2_isr_handler, \ + DEVICE_DT_INST_GET(n), \ + DW_IRQ_FLAGS(n)); \ + \ + irq_enable(DT_INST_IRQN(n)); \ + } \ + \ + static void udc_dwc2_irq_disable_func_##n(const struct device *dev) \ + { \ + irq_disable(DT_INST_IRQN(n)); \ + } \ + \ + static struct udc_ep_config ep_cfg_out[UDC_DWC2_DRV_EP_NUM]; \ + static struct udc_ep_config ep_cfg_in[UDC_DWC2_DRV_EP_NUM]; \ + \ + static const struct udc_dwc2_config udc_dwc2_config_##n = { \ + .num_of_eps = UDC_DWC2_DRV_EP_NUM, \ + .ep_cfg_in = ep_cfg_out, \ + .ep_cfg_out = ep_cfg_in, \ + .make_thread = udc_dwc2_make_thread_##n, \ + .base = (struct usb_dwc2_reg *)UDC_DWC2_DT_INST_REG_ADDR(n), \ + .pcfg = UDC_DWC2_PINCTRL_DT_INST_DEV_CONFIG_GET(n), \ + .irq_enable_func = udc_dwc2_irq_enable_func_##n, \ + .irq_disable_func = udc_dwc2_irq_disable_func_##n, \ + .quirks = UDC_DWC2_VENDOR_QUIRK_GET(n), \ + }; \ + \ + static struct udc_dwc2_data udc_priv_##n = { \ + }; \ + \ + static struct udc_data udc_data_##n = { \ + .mutex = Z_MUTEX_INITIALIZER(udc_data_##n.mutex), \ + .priv = &udc_priv_##n, \ + }; \ + \ + DEVICE_DT_INST_DEFINE(n, dwc2_driver_preinit, NULL, \ + &udc_data_##n, &udc_dwc2_config_##n, \ + POST_KERNEL, CONFIG_KERNEL_INIT_PRIORITY_DEVICE, \ + &udc_dwc2_api); + +DT_INST_FOREACH_STATUS_OKAY(UDC_DWC2_DEVICE_DEFINE) diff --git a/drivers/usb/udc/udc_dwc2.h b/drivers/usb/udc/udc_dwc2.h new file mode 100644 index 00000000000..11d8178c135 --- /dev/null +++ b/drivers/usb/udc/udc_dwc2.h @@ -0,0 +1,40 @@ +/* + * Copyright (c) 2023 Nordic Semiconductor ASA + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#ifndef ZEPHYR_DRIVERS_USB_UDC_DWC2_H +#define ZEPHYR_DRIVERS_USB_UDC_DWC2_H + +#include +#include +#include +#include + +/* Vendor quirks per driver instance */ +struct dwc2_vendor_quirks { + int (*clk_enable)(const struct device *dev); + int (*clk_disable)(const struct device *dev); + int (*pwr_on)(const struct device *dev); + int (*pwr_off)(const struct device *dev); + int (*irq_clear)(const struct device *dev); +}; + +/* Driver configuration per instance */ +struct udc_dwc2_config { + size_t num_of_eps; + struct udc_ep_config *ep_cfg_in; + struct udc_ep_config *ep_cfg_out; + int speed_idx; + struct usb_dwc2_reg *const base; + /* Pointer to pin control configuration or NULL */ + struct pinctrl_dev_config *const pcfg; + /* Pointer to vendor quirks or NULL */ + struct dwc2_vendor_quirks *const quirks; + void (*make_thread)(const struct device *dev); + void (*irq_enable_func)(const struct device *dev); + void (*irq_disable_func)(const struct device *dev); +}; + +#endif /* ZEPHYR_DRIVERS_USB_UDC_DWC2_H */ diff --git a/drivers/usb/udc/udc_dwc2_vendor_quirks.h b/drivers/usb/udc/udc_dwc2_vendor_quirks.h new file mode 100644 index 00000000000..104cb5cb847 --- /dev/null +++ b/drivers/usb/udc/udc_dwc2_vendor_quirks.h @@ -0,0 +1,101 @@ +/* + * Copyright (c) 2023 Nordic Semiconductor ASA + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#ifndef ZEPHYR_DRIVERS_USB_UDC_DWC2_VENDOR_QUIRKS_H +#define ZEPHYR_DRIVERS_USB_UDC_DWC2_VENDOR_QUIRKS_H + +#include "udc_dwc2.h" + +#include +#include +#include +#include + +#include + +#if DT_HAS_COMPAT_STATUS_OKAY(st_stm32f4_fsotg) + +struct usb_dw_stm32_clk { + const struct device *const dev; + const struct stm32_pclken *const pclken; + size_t pclken_len; +}; + +#define DT_DRV_COMPAT snps_dwc2 + +static inline int clk_enable_stm32f4_fsotg(const struct usb_dw_stm32_clk *const clk) +{ + int ret; + + if (!device_is_ready(clk->dev)) { + return -ENODEV; + } + + if (clk->pclken_len > 1) { + uint32_t clk_rate; + + ret = clock_control_configure(clk->dev, + (void *)&clk->pclken[1], + NULL); + if (ret) { + return ret; + } + + ret = clock_control_get_rate(clk->dev, + (void *)&clk->pclken[1], + &clk_rate); + if (ret) { + return ret; + } + + if (clk_rate != MHZ(48)) { + return -ENOTSUP; + } + } + + return clock_control_on(clk->dev, (void *)&clk->pclken[0]); +} + +static inline int pwr_on_stm32f4_fsotg(const struct device *dev) +{ + const struct udc_dwc2_config *const config = dev->config; + mem_addr_t ggpio_reg = (mem_addr_t)&config->base->ggpio; + + sys_set_bits(ggpio_reg, USB_DWC2_GGPIO_STM32_PWRDWN | USB_DWC2_GGPIO_STM32_VBDEN); + + return 0; +} + +#define QUIRK_STM32F4_FSOTG_DEFINE(n) \ + static const struct stm32_pclken pclken_##n[] = STM32_DT_INST_CLOCKS(n);\ + \ + static const struct usb_dw_stm32_clk stm32f4_clk_##n = { \ + .dev = DEVICE_DT_GET(STM32_CLOCK_CONTROL_NODE), \ + .pclken = pclken_##n, \ + .pclken_len = DT_INST_NUM_CLOCKS(n), \ + }; \ + \ + static int clk_enable_stm32f4_fsotg_##n(const struct device *dev) \ + { \ + return clk_enable_stm32f4_fsotg(&stm32f4_clk_##n); \ + } \ + \ + struct dwc2_vendor_quirks dwc2_vendor_quirks_##n = { \ + .clk_enable = clk_enable_stm32f4_fsotg_##n, \ + .pwr_on = pwr_on_stm32f4_fsotg, \ + .irq_clear = NULL, \ + }; + + +DT_INST_FOREACH_STATUS_OKAY(QUIRK_STM32F4_FSOTG_DEFINE) + +#undef DT_DRV_COMPAT + +#endif /*DT_HAS_COMPAT_STATUS_OKAY(st_stm32f4_fsotg) */ + +/* Add next vendor quirks definition above this line */ + +#endif /* ZEPHYR_DRIVERS_USB_UDC_DWC2_VENDOR_QUIRKS_H */ From ad25668313221f81a0f26d4140dc62964934d24c Mon Sep 17 00:00:00 2001 From: Johann Fischer Date: Thu, 14 Sep 2023 23:28:32 +0200 Subject: [PATCH 1355/3723] samples: usb shell: add DT overlay to support snps,dwc2 on nucleo_f413zh Add DT overlay to be able to support and test UDC DWC2 driver (snps,dwc2) on nucleo_f413zh board. This disables STM32 shim driver described and configured on the SoC and board level. Obviously,it should work with other STM32F4 boards as well and we could have a mechanism to apply it generically using snippets. Signed-off-by: Johann Fischer --- .../usb/shell/nucleo_f413zh_dwc2.overlay | 26 +++++++++++++++++++ 1 file changed, 26 insertions(+) create mode 100644 samples/subsys/usb/shell/nucleo_f413zh_dwc2.overlay diff --git a/samples/subsys/usb/shell/nucleo_f413zh_dwc2.overlay b/samples/subsys/usb/shell/nucleo_f413zh_dwc2.overlay new file mode 100644 index 00000000000..ff51b08078e --- /dev/null +++ b/samples/subsys/usb/shell/nucleo_f413zh_dwc2.overlay @@ -0,0 +1,26 @@ +/* + * Copyright (c) 2023 Nordic Semiconductor ASA + * + * SPDX-License-Identifier: Apache-2.0 + */ + +/delete-node/ &zephyr_udc0; + +/ { + soc { + dwc2_fsotg0: usb@50000000 { + compatible = "st,stm32f4-fsotg", "snps,dwc2"; + reg = <0x50000000 0x40000>; + interrupts = <67 0>; + interrupt-names = "fsotg"; + clocks = <&rcc STM32_CLOCK_BUS_AHB2 0x00000080>, + <&rcc STM32_SRC_PLL_Q NO_SEL>; + }; + }; +}; + +zephyr_udc0: &dwc2_fsotg0 { + pinctrl-0 = <&usb_otg_fs_dm_pa11 &usb_otg_fs_dp_pa12>; + pinctrl-names = "default"; + status = "okay"; +}; From 987eb10fafd5201e277287bf961ab5ed16fedc18 Mon Sep 17 00:00:00 2001 From: Daniel Mangum Date: Sat, 16 Dec 2023 10:34:49 -0500 Subject: [PATCH 1356/3723] soc: posix: fix kconfig description Fixes a small typo in kconfig description for the posix port. Signed-off-by: Daniel Mangum --- soc/posix/inf_clock/Kconfig | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/soc/posix/inf_clock/Kconfig b/soc/posix/inf_clock/Kconfig index 9e5f5ccc89f..27a5d511ec5 100644 --- a/soc/posix/inf_clock/Kconfig +++ b/soc/posix/inf_clock/Kconfig @@ -35,7 +35,7 @@ config NATIVE_SIMULATOR_EXTRA_IMAGE_PATHS help This option can be used to provide the native simulator with other MCUs/Cores images which have been produced by either other Zephyr builds or different OS builds. - So you can, for ex., use this application build produce one core image, and at the same time + So you can, for ex., use this application build to produce one core image, and at the same time have it produce the final link with the native simulator runner and the other MCU images. config NATIVE_SIMULATOR_AUTOSTART_MCU From 9804c60a4e52bfa960abc0ee4b347c96e9c7e862 Mon Sep 17 00:00:00 2001 From: Ryan McClelland Date: Sun, 10 Dec 2023 12:32:26 -0800 Subject: [PATCH 1357/3723] tests: lib: c_lib: fix double promotion error Fix double promotion warnings Signed-off-by: Ryan McClelland --- tests/lib/c_lib/common/src/test_sqrt.c | 53 +++++++++++--------------- 1 file changed, 22 insertions(+), 31 deletions(-) diff --git a/tests/lib/c_lib/common/src/test_sqrt.c b/tests/lib/c_lib/common/src/test_sqrt.c index cd06e33e7d3..3c465b8f0eb 100644 --- a/tests/lib/c_lib/common/src/test_sqrt.c +++ b/tests/lib/c_lib/common/src/test_sqrt.c @@ -16,16 +16,8 @@ #define NAN (__builtin_nansf("")) #endif -#ifndef NANF -#define NANF (__builtin_nans("")) -#endif - -#ifndef INF -#define INF (__builtin_inf()) -#endif - -#ifndef INFF -#define INFF (__builtin_inff()) +#ifndef INFINITY +#define INFINITY (__builtin_inff()) #endif static float test_floats[] = { @@ -91,14 +83,13 @@ static int isnanf(float x) #endif /* small errors are expected, computed as percentage error */ -#define MAX_FLOAT_ERROR_PERCENT (3.5e-5) +#define MAX_FLOAT_ERROR_PERCENT (3.5e-5f) #define MAX_DOUBLE_ERROR_PERCENT (4.5e-14) ZTEST(libc_common, test_sqrtf) { int i; -float exponent, resf, square, root_squared; -double error; +float exponent, resf, square, root_squared, error; uint32_t max_error; int32_t ierror; int32_t *p_square = (int32_t *)□ @@ -107,16 +98,16 @@ int32_t *p_root_squared = (int32_t *)&root_squared; max_error = 0; - /* test the special cases of 0.0, NAN, -NAN, INF, -INF, and -10.0 */ + /* test the special cases of 0.0, NAN, -NAN, INFINITY, -INFINITY, and -10.0 */ zassert_true(sqrtf(0.0f) == 0.0f, "sqrtf(0.0)"); - zassert_true(isnanf(sqrtf(NANF)), "sqrt(nan)"); + zassert_true(isnanf(sqrtf(NAN)), "sqrt(nan)"); #ifdef issignallingf - zassert_true(issignallingf(sqrtf(NANF)), "ssignalingf(sqrtf(nan))"); + zassert_true(issignallingf(sqrtf(NAN)), "ssignalingf(sqrtf(nan))"); /* printf("issignallingf();\n"); */ #endif - zassert_true(isnanf(sqrtf(-NANF)), "isnanf(sqrtf(-nan))"); - zassert_true(isinff(sqrtf(INFF)), "isinff(sqrt(inf))"); - zassert_true(isnanf(sqrtf(-INFF)), "isnanf(sqrt(-inf))"); + zassert_true(isnanf(sqrtf(-NAN)), "isnanf(sqrtf(-nan))"); + zassert_true(isinff(sqrtf(INFINITY)), "isinff(sqrt(inf))"); + zassert_true(isnanf(sqrtf(-INFINITY)), "isnanf(sqrt(-inf))"); zassert_true(isnanf(sqrtf(-10.0f)), "isnanf(sqrt(-10.0))"); for (exponent = 1.0e-10f; exponent < 1.0e10f; exponent *= 10.0f) { @@ -124,12 +115,12 @@ int32_t *p_root_squared = (int32_t *)&root_squared; square = test_floats[i] * exponent; resf = sqrtf(square); root_squared = resf * resf; - zassert_true((resf > 0.0f) && (resf < INFF), + zassert_true((resf > 0.0f) && (resf < INFINITY), "sqrtf out of range"); - if ((resf > 0.0f) && (resf < INFF)) { + if ((resf > 0.0f) && (resf < INFINITY)) { error = (square - root_squared) / square * 100; - if (error < 0.0) { + if (error < 0.0f) { error = -error; } /* square and root_squared should be almost identical @@ -143,7 +134,7 @@ int32_t *p_root_squared = (int32_t *)&root_squared; } } else { /* negative, +NaN, -NaN, inf or -inf */ - error = 0.0; + error = 0.0f; } zassert_true(error < MAX_FLOAT_ERROR_PERCENT, "max sqrtf error exceeded"); @@ -166,16 +157,16 @@ int64_t *p_root_squared = (int64_t *)&root_squared; max_error = 0; - /* test the special cases of 0.0, NAN, -NAN, INF, -INF, and -10.0 */ + /* test the special cases of 0.0, NAN, -NAN, INFINITY, -INFINITY, and -10.0 */ zassert_true(sqrt(0.0) == 0.0, "sqrt(0.0)"); - zassert_true(isnan(sqrt(NAN)), "sqrt(nan)"); + zassert_true(isnan(sqrt((double)NAN)), "sqrt(nan)"); #ifdef issignalling - zassert_true(issignalling(sqrt(NAN)), "ssignaling(sqrt(nan))"); + zassert_true(issignalling(sqrt((double)NAN)), "ssignaling(sqrt(nan))"); /* printf("issignalling();\n"); */ #endif - zassert_true(isnan(sqrt(-NAN)), "isnan(sqrt(-nan))"); - zassert_true(isinf(sqrt(INF)), "isinf(sqrt(inf))"); - zassert_true(isnan(sqrt(-INF)), "isnan(sqrt(-inf))"); + zassert_true(isnan(sqrt((double)-NAN)), "isnan(sqrt(-nan))"); + zassert_true(isinf(sqrt((double)INFINITY)), "isinf(sqrt(inf))"); + zassert_true(isnan(sqrt((double)-INFINITY)), "isnan(sqrt(-inf))"); zassert_true(isnan(sqrt(-10.0)), "isnan(sqrt(-10.0))"); for (exponent = 1.0e-10; exponent < 1.0e10; exponent *= 10.0) { @@ -183,9 +174,9 @@ int64_t *p_root_squared = (int64_t *)&root_squared; square = test_doubles[i] * exponent; resd = sqrt(square); root_squared = resd * resd; - zassert_true((resd > 0.0) && (resd < INF), + zassert_true((resd > 0.0) && (resd < (double)INFINITY), "sqrt out of range"); - if ((resd > 0.0) && (resd < INF)) { + if ((resd > 0.0) && (resd < (double)INFINITY)) { error = (square - root_squared) / square * 100; if (error < 0.0) { From 2b83e91a433d8fa0bd528b9eb7c71741ec9a2081 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ruben=20V=C3=B6ll?= Date: Fri, 15 Dec 2023 19:25:49 +0100 Subject: [PATCH 1358/3723] mgmt: fs_mgmt: clear lock before return MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Not clearing that lock lead to the fs_mgmt commands being useless, after the mgmt callback returned `MGMT_CB_ERROR_RC` once, since the lock is now occupied and never cleared. Fixes #66581 Signed-off-by: Ruben Völl --- subsys/mgmt/mcumgr/grp/fs_mgmt/src/fs_mgmt.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/subsys/mgmt/mcumgr/grp/fs_mgmt/src/fs_mgmt.c b/subsys/mgmt/mcumgr/grp/fs_mgmt/src/fs_mgmt.c index 3458c3d6f8b..7cb31627d35 100644 --- a/subsys/mgmt/mcumgr/grp/fs_mgmt/src/fs_mgmt.c +++ b/subsys/mgmt/mcumgr/grp/fs_mgmt/src/fs_mgmt.c @@ -255,6 +255,7 @@ static int fs_mgmt_file_download(struct smp_streamer *ctxt) if (status != MGMT_CB_OK) { if (status == MGMT_CB_ERROR_RC) { + k_sem_give(&fs_mgmt_ctxt.lock_sem); return err_rc; } @@ -404,6 +405,7 @@ static int fs_mgmt_file_upload(struct smp_streamer *ctxt) if (status != MGMT_CB_OK) { if (status == MGMT_CB_ERROR_RC) { + k_sem_give(&fs_mgmt_ctxt.lock_sem); return err_rc; } From f9313b1745eb9fedfe045b4b8c8bfeca43455196 Mon Sep 17 00:00:00 2001 From: Fabio Baltieri Date: Sun, 10 Dec 2023 18:30:50 +0000 Subject: [PATCH 1359/3723] input: add a linux-evdev device Add a device driver to read events from a Linux evdev device node and inject them back as Zephyr input events. Signed-off-by: Fabio Baltieri --- boards/posix/native_sim/doc/index.rst | 18 +++ drivers/input/CMakeLists.txt | 13 ++ drivers/input/Kconfig | 1 + drivers/input/Kconfig.evdev | 28 +++++ drivers/input/linux_evdev.c | 115 ++++++++++++++++++ drivers/input/linux_evdev_bottom.c | 53 ++++++++ drivers/input/linux_evdev_bottom.h | 17 +++ .../input/zephyr,native-linux-evdev.yaml | 23 ++++ tests/drivers/build_all/input/app.overlay | 4 + 9 files changed, 272 insertions(+) create mode 100644 drivers/input/Kconfig.evdev create mode 100644 drivers/input/linux_evdev.c create mode 100644 drivers/input/linux_evdev_bottom.c create mode 100644 drivers/input/linux_evdev_bottom.h create mode 100644 dts/bindings/input/zephyr,native-linux-evdev.yaml diff --git a/boards/posix/native_sim/doc/index.rst b/boards/posix/native_sim/doc/index.rst index ae858b1d05f..be419705643 100644 --- a/boards/posix/native_sim/doc/index.rst +++ b/boards/posix/native_sim/doc/index.rst @@ -449,6 +449,23 @@ The following peripherals are currently provided with this board: The flash content can be accessed from the host system, as explained in the `Host based flash access`_ section. +**Input events** + A driver is provided to read input events from a Linux evdev input device and + inject them back into the Zephyr input subsystem. + + The driver is automatically enabled when :kconfig:option:`CONFIG_INPUT` is + enabled and the devicetree contains a node such as: + + .. code-block:: dts + + evdev { + compatible = "zephyr,native-linux-evdev"; + }; + + The application then has to be run with a command line option to specify + which evdev device node has to be used, for example + ``zephyr.exe --evdev=/dev/input/event0``. + .. _native_ptty_uart: PTTY UART @@ -652,6 +669,7 @@ host libC (:kconfig:option:`CONFIG_EXTERNAL_LIBC`): gpio, SDL GPIO emulator, :kconfig:option:`CONFIG_GPIO_EMUL_SDL`, all i2c, I2C emulator, :kconfig:option:`CONFIG_I2C_EMUL`, all input, input SDL touch, :kconfig:option:`CONFIG_INPUT_SDL_TOUCH`, all + input, Linux evdev, :kconfig:option:`CONFIG_NATIVE_LINUX_EVDEV`, all log backend, :ref:`native backend `, :kconfig:option:`CONFIG_LOG_BACKEND_NATIVE_POSIX`, all rtc, RTC emul, :kconfig:option:`CONFIG_RTC_EMUL`, all serial, :ref:`uart native posix/PTTY `, :kconfig:option:`CONFIG_UART_NATIVE_POSIX`, all diff --git a/drivers/input/CMakeLists.txt b/drivers/input/CMakeLists.txt index 04f4878a240..012bb08b283 100644 --- a/drivers/input/CMakeLists.txt +++ b/drivers/input/CMakeLists.txt @@ -27,3 +27,16 @@ if (CONFIG_INPUT_SDL_TOUCH) target_sources(native_simulator INTERFACE input_sdl_touch_bottom.c) endif() endif() + +if(CONFIG_NATIVE_LINUX_EVDEV) + if(${CMAKE_HOST_SYSTEM_NAME} STREQUAL Linux) + zephyr_library_sources(linux_evdev.c) + if (CONFIG_NATIVE_APPLICATION) + zephyr_library_sources(linux_evdev_bottom.c) + else() + target_sources(native_simulator INTERFACE linux_evdev_bottom.c) + endif() + else() + message(FATAL_ERROR "CONFIG_NATIVE_LINUX_EVDEV only available on Linux") + endif() +endif() diff --git a/drivers/input/Kconfig b/drivers/input/Kconfig index 003f43adc58..8aa5471e571 100644 --- a/drivers/input/Kconfig +++ b/drivers/input/Kconfig @@ -9,6 +9,7 @@ menu "Input drivers" source "drivers/input/Kconfig.cap1203" source "drivers/input/Kconfig.cst816s" source "drivers/input/Kconfig.esp32" +source "drivers/input/Kconfig.evdev" source "drivers/input/Kconfig.ft5336" source "drivers/input/Kconfig.gpio_kbd_matrix" source "drivers/input/Kconfig.gpio_keys" diff --git a/drivers/input/Kconfig.evdev b/drivers/input/Kconfig.evdev new file mode 100644 index 00000000000..ed2ac16d812 --- /dev/null +++ b/drivers/input/Kconfig.evdev @@ -0,0 +1,28 @@ +# Copyright 2023 Google LLC +# SPDX-License-Identifier: Apache-2.0 + +config NATIVE_LINUX_EVDEV + bool "Native Linux evdev based input device" + default y + depends on DT_HAS_ZEPHYR_NATIVE_LINUX_EVDEV_ENABLED + depends on ARCH_POSIX + help + Enable reading input from a Linux evdev device, requires specifying + an evdev device path in the --evdev command line argument. + +if NATIVE_LINUX_EVDEV + +config NATIVE_LINUX_EVDEV_THREAD_PRIORITY + int "Priority for the Linux evdev thread" + default 0 + help + Priority level of the internal thread handling Linux input events. + +config NATIVE_LINUX_THREAD_SLEEP_MS + int "Sleep period for the Linux evdev thread" + default 10 + help + How long to sleep between checking for new events in the Linux input + events thread. + +endif diff --git a/drivers/input/linux_evdev.c b/drivers/input/linux_evdev.c new file mode 100644 index 00000000000..20ba7419b1d --- /dev/null +++ b/drivers/input/linux_evdev.c @@ -0,0 +1,115 @@ +/* + * Copyright 2023 Google LLC + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#define DT_DRV_COMPAT zephyr_native_linux_evdev + +#include +#include +#include +#include +#include +#include +#include +#include + +#include "linux_evdev_bottom.h" + +LOG_MODULE_REGISTER(linux_evdev, CONFIG_INPUT_LOG_LEVEL); + +static int linux_evdev_fd = -1; +static const char *linux_evdev_path; +static struct k_thread linux_evdev_thread; +static K_KERNEL_STACK_DEFINE(linux_evdev_thread_stack, + CONFIG_ARCH_POSIX_RECOMMENDED_STACK_SIZE); + +static void linux_evdev_options(void) +{ + static struct args_struct_t linux_evdev_options[] = { + { + .is_mandatory = true, + .option = "evdev", + .name = "path", + .type = 's', + .dest = (void *)&linux_evdev_path, + .descript = "Path of the evdev device to use", + }, + ARG_TABLE_ENDMARKER, + }; + + native_add_command_line_opts(linux_evdev_options); +} + +static void linux_evdev_check_arg(void) +{ + if (linux_evdev_path == NULL) { + posix_print_error_and_exit( + "Error: evdev device missing.\n" + "Please specify an evdev device with the --evdev " + "argument when using CONFIG_NATIVE_LINUX_EVDEV=y\n"); + } +} + +static void linux_evdev_cleanup(void) +{ + if (linux_evdev_fd >= 0) { + nsi_host_close(linux_evdev_fd); + } +} + +NATIVE_TASK(linux_evdev_options, PRE_BOOT_1, 10); +NATIVE_TASK(linux_evdev_check_arg, PRE_BOOT_2, 10); +NATIVE_TASK(linux_evdev_cleanup, ON_EXIT, 10); + +static void linux_evdev_thread_fn(void *p1, void *p2, void *p3) +{ + const struct device *dev = p1; + uint16_t type; + uint16_t code; + int32_t value; + int ret; + + while (true) { + ret = linux_evdev_read(linux_evdev_fd, &type, &code, &value); + if (ret == NATIVE_LINUX_EVDEV_NO_DATA) { + /* Let other threads run. */ + k_sleep(K_MSEC(CONFIG_NATIVE_LINUX_THREAD_SLEEP_MS)); + continue; + } else if (ret < 0) { + return; + } + + LOG_DBG("evdev event: type=%d code=%d val=%d", type, code, value); + + if (type == 0) { /* EV_SYN */ + input_report(dev, 0, 0, 0, true, K_FOREVER); + } else if (type == INPUT_EV_KEY && value == 2) { + /* nothing, ignore key repeats */ + } else { + input_report(dev, type, code, value, false, K_FOREVER); + } + } +} + +static int linux_evdev_init(const struct device *dev) +{ + linux_evdev_fd = linux_evdev_open(linux_evdev_path); + + k_thread_create(&linux_evdev_thread, linux_evdev_thread_stack, + CONFIG_ARCH_POSIX_RECOMMENDED_STACK_SIZE, + linux_evdev_thread_fn, (void *)dev, NULL, NULL, + CONFIG_NATIVE_LINUX_EVDEV_THREAD_PRIORITY, 0, K_NO_WAIT); + + k_thread_name_set(&linux_evdev_thread, dev->name); + + return 0; +} + +BUILD_ASSERT(DT_NUM_INST_STATUS_OKAY(DT_DRV_COMPAT) == 1, + "Only one zephyr,native-linux-evdev compatible node is supported"); + +DEVICE_DT_INST_DEFINE(0, linux_evdev_init, NULL, + NULL, NULL, + POST_KERNEL, CONFIG_INPUT_INIT_PRIORITY, NULL); diff --git a/drivers/input/linux_evdev_bottom.c b/drivers/input/linux_evdev_bottom.c new file mode 100644 index 00000000000..be65ace084a --- /dev/null +++ b/drivers/input/linux_evdev_bottom.c @@ -0,0 +1,53 @@ +/* + * Copyright 2023 Google LLC + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include +#include +#include +#include +#include +#include + +#include "linux_evdev_bottom.h" + +int linux_evdev_read(int fd, uint16_t *type, uint16_t *code, int32_t *value) +{ + struct input_event ev; + int ret; + + ret = read(fd, &ev, sizeof(ev)); + if (ret < 0) { + if (errno == EAGAIN || errno == EINTR) { + return NATIVE_LINUX_EVDEV_NO_DATA; + } + nsi_print_warning("Read error: %s", strerror(errno)); + return -EIO; + } else if (ret < sizeof(ev)) { + nsi_print_warning("Unexpected read size: %d, expecting %d", + ret, sizeof(ev)); + return -EIO; + } + + *type = ev.type; + *code = ev.code; + *value = ev.value; + + return 0; +} + +int linux_evdev_open(const char *path) +{ + int fd; + + fd = open(path, O_RDONLY | O_NONBLOCK); + if (fd < 0) { + nsi_print_error_and_exit( + "Failed to open the evdev device %s: %s\n", + path, strerror(errno)); + } + + return fd; +} diff --git a/drivers/input/linux_evdev_bottom.h b/drivers/input/linux_evdev_bottom.h new file mode 100644 index 00000000000..153fa4ef6c2 --- /dev/null +++ b/drivers/input/linux_evdev_bottom.h @@ -0,0 +1,17 @@ +/* + * Copyright 2023 Google LLC + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#ifndef ZEPHYR_DRIVERS_INPUT_LINUX_EVDEV_BOTTOM_H_ +#define ZEPHYR_DRIVERS_INPUT_LINUX_EVDEV_BOTTOM_H_ + +#include + +#define NATIVE_LINUX_EVDEV_NO_DATA INT32_MIN + +int linux_evdev_read(int fd, uint16_t *type, uint16_t *code, int32_t *value); +int linux_evdev_open(const char *path); + +#endif /* ZEPHYR_DRIVERS_INPUT_LINUX_EVDEV_BOTTOM_H_ */ diff --git a/dts/bindings/input/zephyr,native-linux-evdev.yaml b/dts/bindings/input/zephyr,native-linux-evdev.yaml new file mode 100644 index 00000000000..cd3fa219810 --- /dev/null +++ b/dts/bindings/input/zephyr,native-linux-evdev.yaml @@ -0,0 +1,23 @@ +# Copyright 2023 Google LLC +# SPDX-License-Identifier: Apache-2.0 + +description: | + Linux evdev based input device + + Allows using a Linux evdev device to read input events and report them back + as Zephyr input events. + + Example configuration: + + evdev { + compatible = "zephyr,native-linux-evdev"; + }; + + Then run the binary specifying the evdev device with the --evdev flag, for + example: + + ./build/zephyr/zephyr.exe --evdev=/dev/input/event0 + +compatible: "zephyr,native-linux-evdev" + +include: base.yaml diff --git a/tests/drivers/build_all/input/app.overlay b/tests/drivers/build_all/input/app.overlay index eaaaa01bb39..0a005414667 100644 --- a/tests/drivers/build_all/input/app.overlay +++ b/tests/drivers/build_all/input/app.overlay @@ -26,6 +26,10 @@ }; }; + evdev { + compatible = "zephyr,native-linux-evdev"; + }; + kbd-matrix-0 { compatible = "gpio-kbd-matrix"; row-gpios = <&test_gpio 0 (GPIO_PULL_UP | GPIO_ACTIVE_LOW)>, From 7ed7a8c272b0681b1a48e2e8fc80cf59c9295949 Mon Sep 17 00:00:00 2001 From: Ryan Woodward Date: Tue, 12 Dec 2023 10:24:34 -0700 Subject: [PATCH 1360/3723] mgmt/osdp: Update ReadMe.rst Updated Link to the LibOSDP Library Respository in the ReadMe for mgmt/osdp Signed-off-by: Ryan Woodward --- samples/subsys/mgmt/osdp/README.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/samples/subsys/mgmt/osdp/README.rst b/samples/subsys/mgmt/osdp/README.rst index 7656d1cd8ab..ac65db5ee57 100644 --- a/samples/subsys/mgmt/osdp/README.rst +++ b/samples/subsys/mgmt/osdp/README.rst @@ -12,7 +12,7 @@ OSDP describes the communication protocol for interfacing one or more Peripheral Devices (PD) to a Control Panel (CP) over a two-wire RS-485 multi-drop serial communication channel. Nevertheless, this protocol can be used to transfer secure data over any stream based physical channel. Read more about `OSDP here -`_.. +`_.. Although OSDP is steered towards the Access and Security industries, it can be used as a general communication protocol for devices in a secure way without From 9d3a3e96e11ca24b9603ba44f576ef8dc5263d5e Mon Sep 17 00:00:00 2001 From: Andrei Emeltchenko Date: Wed, 13 Dec 2023 13:30:18 +0200 Subject: [PATCH 1361/3723] kernel: threads: Do not use string compare instead of bit ops Remove converting bit to string and comparing the string instead of ready helpers. The "Check if thread is in use" seems to check only that parameters state_buf and sizeof(state_buf) not zero. Signed-off-by: Andrei Emeltchenko --- kernel/dynamic.c | 11 +++-------- 1 file changed, 3 insertions(+), 8 deletions(-) diff --git a/kernel/dynamic.c b/kernel/dynamic.c index d30dba8ac02..df94aaaaefa 100644 --- a/kernel/dynamic.c +++ b/kernel/dynamic.c @@ -7,6 +7,7 @@ #include "kernel_internal.h" #include +#include #include #include #include @@ -120,20 +121,14 @@ static void dyn_cb(const struct k_thread *thread, void *user_data) int z_impl_k_thread_stack_free(k_thread_stack_t *stack) { - char state_buf[16] = {0}; struct dyn_cb_data data = {.stack = stack}; /* Get a possible tid associated with stack */ k_thread_foreach(dyn_cb, &data); if (data.tid != NULL) { - /* Check if thread is in use */ - if (k_thread_state_str(data.tid, state_buf, sizeof(state_buf)) != state_buf) { - LOG_ERR("tid %p is invalid!", data.tid); - return -EINVAL; - } - - if (!(strcmp("dummy", state_buf) == 0) || (strcmp("dead", state_buf) == 0)) { + if (!(z_is_thread_state_set(data.tid, _THREAD_DUMMY) || + z_is_thread_state_set(data.tid, _THREAD_DEAD))) { LOG_ERR("tid %p is in use!", data.tid); return -EBUSY; } From dab6f665ca77509bc667eb985e0ae1fff48865e2 Mon Sep 17 00:00:00 2001 From: Daniel Leung Date: Fri, 15 Dec 2023 14:52:10 -0800 Subject: [PATCH 1362/3723] xtensa: fix build errors with cache functions () arch_icache_line_size_get() needs to be inlined or else compiler would complain that it is not being used. () arch_icache_flush_all() returns -ENOTSUP not as there is no xthal_icache_all_writeback() in HAL. () Fix typo vid -> void in arch_icache_disable(). Signed-off-by: Daniel Leung --- include/zephyr/arch/xtensa/cache.h | 9 +++------ 1 file changed, 3 insertions(+), 6 deletions(-) diff --git a/include/zephyr/arch/xtensa/cache.h b/include/zephyr/arch/xtensa/cache.h index 4f472b3667c..8a190d0d371 100644 --- a/include/zephyr/arch/xtensa/cache.h +++ b/include/zephyr/arch/xtensa/cache.h @@ -121,17 +121,14 @@ static ALWAYS_INLINE void arch_dcache_disable(void) #if defined(CONFIG_ICACHE) -static size_t arch_icache_line_size_get(void) +static ALWAYS_INLINE size_t arch_icache_line_size_get(void) { return -ENOTSUP; } static ALWAYS_INLINE int arch_icache_flush_all(void) { -#if XCHAL_ICACHE_SIZE - xthal_icache_all_writeback(); -#endif - return 0; + return -ENOTSUP; } static ALWAYS_INLINE int arch_icache_invd_all(void) @@ -170,7 +167,7 @@ static ALWAYS_INLINE void arch_icache_enable(void) /* nothing */ } -static ALWAYS_INLINE vid arch_icache_disable(void) +static ALWAYS_INLINE void arch_icache_disable(void) { /* nothing */ } From 48349351a96a982b8bf4bb81b8c84a6cad5fadd9 Mon Sep 17 00:00:00 2001 From: Daniel Leung Date: Fri, 15 Dec 2023 15:09:41 -0800 Subject: [PATCH 1363/3723] tests: kernel/cache: skip i-cache range tests if Xtensa MMU With MMU enabled on Xtensa, user_buffer is not marked as executable. Invalidating the i-cache by region will cause an instruction fetch prohibited exception. So skip all i-cache tests, instead of just the range ones to avoid confusions of only running the test partially. Signed-off-by: Daniel Leung --- tests/kernel/cache/src/test_cache_api.c | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/tests/kernel/cache/src/test_cache_api.c b/tests/kernel/cache/src/test_cache_api.c index 7c3fa1bbb19..000a4634b3b 100644 --- a/tests/kernel/cache/src/test_cache_api.c +++ b/tests/kernel/cache/src/test_cache_api.c @@ -15,6 +15,16 @@ ZTEST(cache_api, test_instr_cache_api) { int ret; +#ifdef CONFIG_XTENSA_MMU + /* With MMU enabled, user_buffer is not marked as executable. + * Invalidating the i-cache by region will cause an instruction + * fetch prohibited exception. So skip all i-cache tests, + * instead of just the range ones to avoid confusions of + * only running the test partially. + */ + ztest_test_skip(); +#endif + ret = sys_cache_instr_flush_all(); zassert_true((ret == 0) || (ret == -ENOTSUP)); From d59e7be1ec73376a0aeec635fd88eda9fe2d5e3b Mon Sep 17 00:00:00 2001 From: Daniel Leung Date: Fri, 15 Dec 2023 15:10:46 -0800 Subject: [PATCH 1364/3723] soc: xtensa/dc233c: turn on i-cache and d-cache The DC233C core has support for both i-cache and d-cache. So mark it as such so we can test caching of Xtensa in QEMU. Signed-off-by: Daniel Leung --- soc/xtensa/dc233c/Kconfig.soc | 2 ++ 1 file changed, 2 insertions(+) diff --git a/soc/xtensa/dc233c/Kconfig.soc b/soc/xtensa/dc233c/Kconfig.soc index 617eaa13849..aac2fb89fbb 100644 --- a/soc/xtensa/dc233c/Kconfig.soc +++ b/soc/xtensa/dc233c/Kconfig.soc @@ -7,6 +7,8 @@ config SOC_XTENSA_DC233C select XTENSA select XTENSA_HAL select ARCH_HAS_THREAD_LOCAL_STORAGE + select CPU_HAS_DCACHE + select CPU_HAS_ICACHE select CPU_HAS_MMU select ARCH_HAS_RESERVED_PAGE_FRAMES if XTENSA_MMU select ARCH_HAS_USERSPACE if XTENSA_MMU From b6d8d2715c31e971316cb1009460001e68df305f Mon Sep 17 00:00:00 2001 From: Przemyslaw Bida Date: Fri, 15 Dec 2023 21:30:27 +0100 Subject: [PATCH 1365/3723] net: openthread: Add cmake makro to openthread cmake lists. This commit introduces `kconfig_to_ot_option` to simply fye the way of adding openthread related kconfigs. Signed-off-by: Przemyslaw Bida --- modules/openthread/CMakeLists.txt | 571 +++++------------------------- 1 file changed, 90 insertions(+), 481 deletions(-) diff --git a/modules/openthread/CMakeLists.txt b/modules/openthread/CMakeLists.txt index 150039863d9..6691084eebd 100644 --- a/modules/openthread/CMakeLists.txt +++ b/modules/openthread/CMakeLists.txt @@ -3,6 +3,14 @@ if(CONFIG_OPENTHREAD_SOURCES) set(CMAKE_TRY_COMPILE_TARGET_TYPE STATIC_LIBRARY) +macro(kconfig_to_ot_option kconfig_option ot_config description) + if(${kconfig_option}) + set(${ot_config} ON CACHE BOOL "${description}" FORCE) + else() + set(${ot_config} OFF CACHE BOOL "${description}" FORCE) + endif() +endmacro() + # OpenThread options set(OT_BUILD_EXECUTABLES OFF CACHE BOOL "Disable OpenThread samples") set(OT_BUILTIN_MBEDTLS_MANAGEMENT OFF CACHE BOOL "Use Zephyr's mbedTLS heap") @@ -28,494 +36,95 @@ elseif(CONFIG_OPENTHREAD_MTD) set(OT_MTD ON CACHE BOOL "Enable MTD" FORCE) endif() -if(CONFIG_OPENTHREAD_ANYCAST_LOCATOR) - set(OT_ANYCAST_LOCATOR ON CACHE BOOL "Enable anycast locator" FORCE) -else() - set(OT_ANYCAST_LOCATOR OFF CACHE BOOL "Enable anycast locator" FORCE) -endif() - -if(CONFIG_ASSERT) - set(OT_ASSERT ON CACHE BOOL "Enable assert function OT_ASSERT()" FORCE) -else() - set(OT_ASSERT OFF CACHE BOOL "Enable assert function OT_ASSERT()" FORCE) -endif() - -if(CONFIG_OPENTHREAD_BACKBONE_ROUTER) - set(OT_BACKBONE_ROUTER ON CACHE BOOL "Enable backbone router functionality" FORCE) -else() - set(OT_BACKBONE_ROUTER OFF CACHE BOOL "Enable backbone router functionality" FORCE) -endif() - -if(CONFIG_OPENTHREAD_BACKBONE_ROUTER_DUA_NDPROXYING) - set(OT_BACKBONE_ROUTER_DUA_NDPROXYING ON CACHE BOOL "Enable BBR DUA ND Proxy support" FORCE) -else() - set(OT_BACKBONE_ROUTER_DUA_NDPROXYING OFF CACHE BOOL "Enable BBR DUA ND Proxy support" FORCE) -endif() - -if(CONFIG_OPENTHREAD_BACKBONE_ROUTER_MULTICAST_ROUTING) - set(OT_BACKBONE_ROUTER_MULTICAST_ROUTING ON CACHE BOOL "Enable BBR MR support" FORCE) -else() - set(OT_BACKBONE_ROUTER_MULTICAST_ROUTING OFF CACHE BOOL "Enable BBR MR support" FORCE) -endif() - -if(CONFIG_OPENTHREAD_BLE_TCAT) - set(OT_BLE_TCAT ON CACHE BOOL "Enable BLE TCAT support" FORCE) -else() - set(OT_BLE_TCAT OFF CACHE BOOL "Enable BLE TCAT support" FORCE) -endif() - -if(CONFIG_OPENTHREAD_BORDER_AGENT) - set(OT_BORDER_AGENT ON CACHE BOOL "Enable Border Agent" FORCE) -else() - set(OT_BORDER_AGENT OFF CACHE BOOL "Enable Border Agent" FORCE) -endif() - -if(CONFIG_OPENTHREAD_BORDER_ROUTER) - set(OT_BORDER_ROUTER ON CACHE BOOL "Enable Border Router" FORCE) -else() - set(OT_BORDER_ROUTER OFF CACHE BOOL "Enable Border Router" FORCE) -endif() - -if(CONFIG_OPENTHREAD_BORDER_ROUTING) - set(OT_BORDER_ROUTING ON CACHE BOOL "Enable Border routing" FORCE) -else() - set(OT_BORDER_ROUTING OFF CACHE BOOL "Enable Border routing" FORCE) -endif() - -if(CONFIG_OPENTHREAD_BORDER_ROUTING_COUNTERS) - set(OT_BORDER_ROUTING_COUNTERS ON CACHE BOOL "Enable Border routing counters" FORCE) -else() - set(OT_BORDER_ROUTING_COUNTERS OFF CACHE BOOL "Enable Border routing counters" FORCE) -endif() - -if(CONFIG_OPENTHREAD_BORDER_ROUTING_DHCP6_PD) - set(OT_BORDER_ROUTING_DHCP6_PD ON CACHE BOOL "DHCPv6-PD support in border routing" FORCE) -else() - set(OT_BORDER_ROUTING_DHCP6_PD OFF CACHE BOOL "DHCPv6-PD support in border routing" FORCE) -endif() - -if(CONFIG_OPENTHREAD_CHANNEL_MANAGER) - set(OT_CHANNEL_MANAGER ON CACHE BOOL "Enable channel manager support" FORCE) -else() - set(OT_CHANNEL_MANAGER OFF CACHE BOOL "Enable channel manager support" FORCE) -endif() - -if(CONFIG_OPENTHREAD_CHANNEL_MONITOR) - set(OT_CHANNEL_MONITOR ON CACHE BOOL "Enable channel monitor support" FORCE) -else() - set(OT_CHANNEL_MONITOR OFF CACHE BOOL "Enable channel monitor support" FORCE) -endif() - -if(CONFIG_OPENTHREAD_COAP) - set(OT_COAP ON CACHE BOOL "Enable CoAP API" FORCE) -else() - set(OT_COAP OFF CACHE BOOL "Enable CoAP API" FORCE) -endif() - -if(CONFIG_OPENTHREAD_COAP_BLOCK) - set(OT_COAP_BLOCK ON CACHE BOOL "Enable CoAP Block-wise option support" FORCE) -else() - set(OT_COAP_BLOCK OFF CACHE BOOL "Enable CoAP Block-wise option support" FORCE) -endif() - -if(CONFIG_OPENTHREAD_COAP_OBSERVE) - set(OT_COAP_OBSERVE ON CACHE BOOL "Enable CoAP Observe option support" FORCE) -else() - set(OT_COAP_OBSERVE OFF CACHE BOOL "Enable CoAP Observe option support" FORCE) -endif() - -if(CONFIG_OPENTHREAD_COAPS) - set(OT_COAPS ON CACHE BOOL "Enable secure CoAP API support" FORCE) -else() - set(OT_COAPS OFF CACHE BOOL "Enable secure CoAP API support" FORCE) -endif() - -if(CONFIG_OPENTHREAD_COMMISSIONER) - set(OT_COMMISSIONER ON CACHE BOOL "Enable Commissioner" FORCE) -else() - set(OT_COMMISSIONER OFF CACHE BOOL "Enable Commissioner" FORCE) -endif() - -if(CONFIG_OPENTHREAD_CSL_AUTO_SYNC) - set(OT_CSL_AUTO_SYNC ON CACHE BOOL "Enable csl autosync" FORCE) -else() - set(OT_CSL_AUTO_SYNC OFF CACHE BOOL "Enable csl autosync" FORCE) -endif() - -if(CONFIG_OPENTHREAD_CSL_DEBUG) - set(OT_CSL_DEBUG ON CACHE BOOL "Enable CSL debug" FORCE) -else() - set(OT_CSL_DEBUG OFF CACHE BOOL "Enable CSL debug" FORCE) -endif() - -if(CONFIG_OPENTHREAD_CSL_RECEIVER) - set(OT_CSL_RECEIVER ON CACHE BOOL "Enable CSL receiver feature for Thread 1.2" FORCE) -else() - set(OT_CSL_RECEIVER OFF CACHE BOOL "Enable CSL receiver feature for Thread 1.2" FORCE) -endif() +kconfig_to_ot_option(CONFIG_OPENTHREAD_ANYCAST_LOCATOR OT_ANYCAST_LOCATOR "Enable anycast locator") +kconfig_to_ot_option(CONFIG_ASSERT OT_ASSERT "Enable assert function OT_ASSERT()") +kconfig_to_ot_option(CONFIG_OPENTHREAD_BACKBONE_ROUTER OT_BACKBONE_ROUTER "Enable backbone router functionality") +kconfig_to_ot_option(CONFIG_OPENTHREAD_BACKBONE_ROUTER_DUA_NDPROXYING OT_BACKBONE_ROUTER_DUA_NDPROXYING "Enable BBR DUA ND Proxy support") +kconfig_to_ot_option(CONFIG_OPENTHREAD_BACKBONE_ROUTER_MULTICAST_ROUTING OT_BACKBONE_ROUTER_MULTICAST_ROUTING "Enable BBR MR support") +kconfig_to_ot_option(CONFIG_OPENTHREAD_BLE_TCAT OT_BLE_TCAT "Enable BLE TCAT support") +kconfig_to_ot_option(CONFIG_OPENTHREAD_BORDER_AGENT OT_BORDER_AGENT "Enable Border Agent") +kconfig_to_ot_option(CONFIG_OPENTHREAD_BORDER_ROUTER OT_BORDER_ROUTER "Enable Border Router") +kconfig_to_ot_option(CONFIG_OPENTHREAD_BORDER_ROUTING OT_BORDER_ROUTING "Enable Border routing") +kconfig_to_ot_option(CONFIG_OPENTHREAD_BORDER_ROUTING_COUNTERS OT_BORDER_ROUTING_COUNTERS "Enable Border routing counters") +kconfig_to_ot_option(CONFIG_OPENTHREAD_BORDER_ROUTING_DHCP6_PD OT_BORDER_ROUTING_DHCP6_PD "DHCPv6-PD support in border routing") +kconfig_to_ot_option(CONFIG_OPENTHREAD_CHANNEL_MANAGER OT_CHANNEL_MANAGER "Enable channel manager support") +kconfig_to_ot_option(CONFIG_OPENTHREAD_CHANNEL_MONITOR OT_CHANNEL_MONITOR "Enable channel monitor support") +kconfig_to_ot_option(CONFIG_OPENTHREAD_COAP OT_COAP "Enable CoAP API") +kconfig_to_ot_option(CONFIG_OPENTHREAD_COAP_BLOCK OT_COAP_BLOCK "Enable CoAP Block-wise option support") +kconfig_to_ot_option(CONFIG_OPENTHREAD_COAP_OBSERVE OT_COAP_OBSERVE "Enable CoAP Observe option support") +kconfig_to_ot_option(CONFIG_OPENTHREAD_COAPS OT_COAPS "Enable secure CoAP API support") +kconfig_to_ot_option(CONFIG_OPENTHREAD_COMMISSIONER OT_COMMISSIONER "Enable Commissioner") +kconfig_to_ot_option(CONFIG_OPENTHREAD_CSL_AUTO_SYNC OT_CSL_AUTO_SYNC "Enable csl autosync") +kconfig_to_ot_option(CONFIG_OPENTHREAD_CSL_DEBUG OT_CSL_DEBUG "Enable CSL debug") +kconfig_to_ot_option(CONFIG_OPENTHREAD_CSL_RECEIVER OT_CSL_RECEIVER "Enable CSL receiver feature for Thread 1.2") +kconfig_to_ot_option(CONFIG_OPENTHREAD_CSL_RECEIVER_LOCAL_TIME_SYNC OT_CSL_RECEIVER_LOCAL_TIME_SYNC "Use local time for CSL sync") +kconfig_to_ot_option(CONFIG_OPENTHREAD_DATASET_UPDATER OT_DATASET_UPDATER "Enable Dataset updater") +kconfig_to_ot_option(CONFIG_OPENTHREAD_DEVICE_PROP_LEADER_WEIGHT OT_DEVICE_PROP_LEADER_WEIGHT "Enable device props for leader weight") +kconfig_to_ot_option(CONFIG_OPENTHREAD_DHCP6_CLIENT OT_DHCP6_CLIENT "Enable DHCPv6 Client") +kconfig_to_ot_option(CONFIG_OPENTHREAD_DHCP6_SERVER OT_DHCP6_SERVER "Enable DHCPv6 Server") +kconfig_to_ot_option(CONFIG_OPENTHREAD_DIAG OT_DIAGNOSTIC "Enable Diagnostics support") +kconfig_to_ot_option(CONFIG_OPENTHREAD_DNS_CLIENT OT_DNS_CLIENT "Enable DNS client support") +kconfig_to_ot_option(CONFIG_OPENTHREAD_DNS_CLIENT_OVER_TCP OT_DNS_CLIENT_OVER_TCP "Enable dns query over tcp") +kconfig_to_ot_option(CONFIG_OPENTHREAD_DNS_DSO OT_DNS_DSO "Enable DNS Stateful Operations (DSO) support") +kconfig_to_ot_option(CONFIG_OPENTHREAD_DNS_UPSTREAM_QUERY OT_DNS_UPSTREAM_QUERY "Enable forwarding DNS queries to upstream") +kconfig_to_ot_option(CONFIG_OPENTHREAD_DNSSD_SERVER OT_DNSSD_SERVER "Enable DNS-SD server support") +kconfig_to_ot_option(CONFIG_OPENTHREAD_DUA OT_DUA "Enable Domain Unicast Address feature for Thread 1.2") +kconfig_to_ot_option(CONFIG_OPENTHREAD_ECDSA OT_ECDSA "Enable ECDSA support") +kconfig_to_ot_option(CONFIG_OPENTHREAD_ENABLE_SERVICE OT_SERVICE "Enable Service entries in Thread Network Data") +kconfig_to_ot_option(CONFIG_OPENTHREAD_EXTERNAL_HEAP OT_EXTERNAL_HEAP "Enable external heap support") +kconfig_to_ot_option(CONFIG_OPENTHREAD_FIREWALL OT_FIREWALL "Enable firewall") +kconfig_to_ot_option(CONFIG_OPENTHREAD_FULL_LOGS OT_FULL_LOGS "Enable full logs") +kconfig_to_ot_option(CONFIG_OPENTHREAD_HISTORY_TRACKER OT_HISTORY_TRACKER "Enable history tracker support.") +kconfig_to_ot_option(CONFIG_OPENTHREAD_IP6_FRAGM OT_IP6_FRAGM "Enable IPv6 fragmentation support") +kconfig_to_ot_option(CONFIG_OPENTHREAD_JAM_DETECTION OT_JAM_DETECTION "Enable Jam Detection") +kconfig_to_ot_option(CONFIG_OPENTHREAD_JOINER OT_JOINER "Enable Joiner") +kconfig_to_ot_option(CONFIG_OPENTHREAD_LEGACY OT_LEGACY "Enable legacy network support") +kconfig_to_ot_option(CONFIG_OPENTHREAD_LINK_METRICS_INITIATOR OT_LINK_METRICS_INITIATOR "Enable Link Metrics initiator for Thread 1.2") +kconfig_to_ot_option(CONFIG_OPENTHREAD_LINK_METRICS_MANAGER OT_LINK_METRICS_MANAGER "Enable Link Metrics manager for Thread 1.2") +kconfig_to_ot_option(CONFIG_OPENTHREAD_LINK_METRICS_SUBJECT OT_LINK_METRICS_SUBJECT "Enable Link Metrics subject for Thread 1.2") +kconfig_to_ot_option(CONFIG_OPENTHREAD_LOG_LEVEL_DYNAMIC OT_LOG_LEVEL_DYNAMIC "Enable dynamic log level control") +kconfig_to_ot_option(CONFIG_OPENTHREAD_MAC_FILTER OT_MAC_FILTER "Enable MAC filter support") +kconfig_to_ot_option(CONFIG_OPENTHREAD_MESH_DIAG OT_MESH_DIAG "Enable Mesh Diagnostics") +kconfig_to_ot_option(CONFIG_OPENTHREAD_MESSAGE_USE_HEAP OT_MESSAGE_USE_HEAP "Enable heap allocator for message buffers") +kconfig_to_ot_option(CONFIG_OPENTHREAD_MLE_LONG_ROUTES OT_MLE_LONG_ROUTES "Enable MLE long routes support (Experimental)") +kconfig_to_ot_option(CONFIG_OPENTHREAD_MLR OT_MLR "Enable Multicast Listener Registration feature for Thread 1.2") +kconfig_to_ot_option(CONFIG_OPENTHREAD_MULTIPAN_RCP OT_MULTIPAN_RCP "Enable Multi-PAN RCP") +kconfig_to_ot_option(CONFIG_OPENTHREAD_MULTIPLE_INSTANCE OT_MULTIPLE_INSTANCE "Enable multiple instances") +kconfig_to_ot_option(CONFIG_OPENTHREAD_NAT64_BORDER_ROUTING OT_NAT64_BORDER_ROUTING "Enable border routing NAT64 support") +kconfig_to_ot_option(CONFIG_OPENTHREAD_NAT64_TRANSLATOR OT_NAT64_TRANSLATOR "Enable NAT64 translator") +kconfig_to_ot_option(CONFIG_OPENTHREAD_NEIGHBOR_DISCOVERY_AGENT OT_NEIGHBOR_DISCOVERY_AGENT "Enable neighbor discovery agent support") +kconfig_to_ot_option(CONFIG_OPENTHREAD_NETDIAG_CLIENT OT_NETDIAG_CLIENT "Enable TMF network diagnostics on clients") +kconfig_to_ot_option(CONFIG_OPENTHREAD_NETDATA_PUBLISHER OT_NETDATA_PUBLISHER "Enable Thread Network Data publisher") +kconfig_to_ot_option(CONFIG_OPENTHREAD_OPERATIONAL_DATASET_AUTO_INIT OT_OPERATIONAL_DATASET_AUTO_INIT "Enable operational dataset auto init") +kconfig_to_ot_option(CONFIG_OPENTHREAD_OTNS OT_OTNS "Enable OTNS support") +kconfig_to_ot_option(CONFIG_OPENTHREAD_PING_SENDER OT_PING_SENDER "Enable ping sender support") +kconfig_to_ot_option(CONFIG_OPENTHREAD_PLATFORM_KEY_REF OT_PLATFORM_KEY_REF "Enable platform key reference support") +kconfig_to_ot_option(CONFIG_OPENTHREAD_PLATFORM_NETIF OT_PLATFORM_NETIF "Enable platform netif support") +kconfig_to_ot_option(CONFIG_OPENTHREAD_PLATFORM_UDP OT_PLATFORM_UDP "Enable platform UDP support") +kconfig_to_ot_option(CONFIG_OPENTHREAD_RADIO_LINK_IEEE_802_15_4_ENABLE OT_15_4 "Enable 802.15.4 radio") +kconfig_to_ot_option(CONFIG_OPENTHREAD_RAW OT_LINK_RAW "Enable Link Raw") +kconfig_to_ot_option(CONFIG_OPENTHREAD_REFERENCE_DEVICE OT_REFERENCE_DEVICE "Enable Thread Certification Reference Device") +kconfig_to_ot_option(CONFIG_OPENTHREAD_SETTINGS_RAM OT_SETTINGS_RAM "Enable volatile-only storage of settings") +kconfig_to_ot_option(CONFIG_OPENTHREAD_SLAAC OT_SLAAC "Enable SLAAC") +kconfig_to_ot_option(CONFIG_OPENTHREAD_SNTP_CLIENT OT_SNTP_CLIENT "Enable SNTP Client support") +kconfig_to_ot_option(CONFIG_OPENTHREAD_SRP_CLIENT OT_SRP_CLIENT "Enable SRP Client support") +kconfig_to_ot_option(CONFIG_OPENTHREAD_SRP_SERVER OT_SRP_SERVER "Enable SRP Server support") +kconfig_to_ot_option(CONFIG_OPENTHREAD_TCP_ENABLE OT_TCP "Enable TCP support") +kconfig_to_ot_option(CONFIG_OPENTHREAD_TIME_SYNC OT_TIME_SYNC "Enable the time synchronization service feature") +kconfig_to_ot_option(CONFIG_OPENTHREAD_TREL OT_TREL "Enable TREL radio link for Thread over Infrastructure feature") +kconfig_to_ot_option(CONFIG_OPENTHREAD_TX_BEACON_PAYLOAD OT_TX_BEACON_PAYLOAD "Enable tx beacon payload support") +kconfig_to_ot_option(CONFIG_OPENTHREAD_TX_QUEUE_STATISTICS OT_TX_QUEUE_STATS "Enable tx queue statistics") +kconfig_to_ot_option(CONFIG_OPENTHREAD_UDP_FORWARD OT_UDP_FORWARD "Enable UDP forward feature") +kconfig_to_ot_option(CONFIG_OPENTHREAD_UPTIME OT_UPTIME "Enable support for tracking OpenThread instance's uptime") -if(CONFIG_OPENTHREAD_CSL_RECEIVER_LOCAL_TIME_SYNC) - set(OT_CSL_RECEIVER_LOCAL_TIME_SYNC ON CACHE BOOL "Use local time for CSL sync" FORCE) -else() - set(OT_CSL_RECEIVER_LOCAL_TIME_SYNC OFF CACHE BOOL "Use local time for CSL sync" FORCE) -endif() - -if(CONFIG_OPENTHREAD_DATASET_UPDATER) - set(OT_DATASET_UPDATER ON CACHE BOOL "Enable Dataset updater" FORCE) -else() - set(OT_DATASET_UPDATER OFF CACHE BOOL "Enable Dataset updater" FORCE) -endif() - -if(CONFIG_OPENTHREAD_DEVICE_PROP_LEADER_WEIGHT) - set(OT_DEVICE_PROP_LEADER_WEIGHT ON CACHE BOOL "Enable device props for leader weight" FORCE) -else() - set(OT_DEVICE_PROP_LEADER_WEIGHT OFF CACHE BOOL "Enable device props for leader weight" FORCE) -endif() - -if(CONFIG_OPENTHREAD_DHCP6_CLIENT) - set(OT_DHCP6_CLIENT ON CACHE BOOL "Enable DHCPv6 Client" FORCE) -else() - set(OT_DHCP6_CLIENT OFF CACHE BOOL "Enable DHCPv6 Client" FORCE) -endif() - -if(CONFIG_OPENTHREAD_DHCP6_SERVER) - set(OT_DHCP6_SERVER ON CACHE BOOL "Enable DHCPv6 Server" FORCE) -else() - set(OT_DHCP6_SERVER OFF CACHE BOOL "Enable DHCPv6 Server" FORCE) -endif() - -if(CONFIG_OPENTHREAD_DIAG) - set(OT_DIAGNOSTIC ON CACHE BOOL "Enable Diagnostics support" FORCE) -else() - set(OT_DIAGNOSTIC OFF CACHE BOOL "Enable Diagnostics support" FORCE) -endif() - -if(CONFIG_OPENTHREAD_DNS_CLIENT) - set(OT_DNS_CLIENT ON CACHE BOOL "Enable DNS client support" FORCE) -else() - set(OT_DNS_CLIENT OFF CACHE BOOL "Enable DNS client support" FORCE) -endif() - -if(CONFIG_OPENTHREAD_DNS_CLIENT_OVER_TCP) - set(OT_DNS_CLIENT_OVER_TCP ON CACHE BOOL "Enable dns query over tcp" FORCE) -else() - set(OT_DNS_CLIENT_OVER_TCP OFF CACHE BOOL "Enable dns query over tcp" FORCE) -endif() - -if(CONFIG_OPENTHREAD_DNS_DSO) - set(OT_DNS_DSO ON CACHE BOOL "Enable DNS Stateful Operations (DSO) support" FORCE) -else() - set(OT_DNS_DSO OFF CACHE BOOL "Enable DNS Stateful Operations (DSO) support" FORCE) -endif() - -if(CONFIG_OPENTHREAD_DNS_UPSTREAM_QUERY) - set(OT_DNS_UPSTREAM_QUERY ON CACHE BOOL "Enable forwarding DNS queries to upstream" FORCE) -else() - set(OT_DNS_UPSTREAM_QUERY OFF CACHE BOOL "Enable forwarding DNS queries to upstream" FORCE) -endif() - -if(CONFIG_OPENTHREAD_DNSSD_SERVER) - set(OT_DNSSD_SERVER ON CACHE BOOL "Enable DNS-SD server support" FORCE) -else() - set(OT_DNSSD_SERVER OFF CACHE BOOL "Enable DNS-SD server support" FORCE) -endif() - -if(CONFIG_OPENTHREAD_DUA) - set(OT_DUA ON CACHE BOOL "Enable Domain Unicast Address feature for Thread 1.2" FORCE) -else() - set(OT_DUA OFF CACHE BOOL "Enable Domain Unicast Address feature for Thread 1.2" FORCE) -endif() - -if(CONFIG_OPENTHREAD_ECDSA) - set(OT_ECDSA ON CACHE BOOL "Enable ECDSA support" FORCE) -else() - set(OT_ECDSA OFF CACHE BOOL "Enable ECDSA support" FORCE) -endif() - -if(CONFIG_OPENTHREAD_ENABLE_SERVICE) - set(OT_SERVICE ON CACHE BOOL "Enable Service entries in Thread Network Data" FORCE) -else() - set(OT_SERVICE OFF CACHE BOOL "Enable Service entries in Thread Network Data" FORCE) -endif() - -if(CONFIG_OPENTHREAD_EXTERNAL_HEAP) - set(OT_EXTERNAL_HEAP ON CACHE BOOL "Enable external heap support" FORCE) -else() - set(OT_EXTERNAL_HEAP OFF CACHE BOOL "Enable external heap support" FORCE) -endif() - -if(CONFIG_OPENTHREAD_FIREWALL) - set(OT_FIREWALL ON CACHE BOOL "Enable firewall" FORCE) -else() - set(OT_FIREWALL OFF CACHE BOOL "Enable firewall" FORCE) -endif() - -if(CONFIG_OPENTHREAD_FULL_LOGS) - set(OT_FULL_LOGS ON CACHE BOOL "Enable full logs" FORCE) -else() - set(OT_FULL_LOGS OFF CACHE BOOL "Enable full logs" FORCE) -endif() - -if(CONFIG_OPENTHREAD_HISTORY_TRACKER) - set(OT_HISTORY_TRACKER ON CACHE BOOL "Enable history tracker support." FORCE) -else() - set(OT_HISTORY_TRACKER OFF CACHE BOOL "Enable history tracker support." FORCE) -endif() - -if(CONFIG_OPENTHREAD_IP6_FRAGM) - set(OT_IP6_FRAGM ON CACHE BOOL "Enable IPv6 fragmentation support" FORCE) -else() - set(OT_IP6_FRAGM OFF CACHE BOOL "Enable IPv6 fragmentation support" FORCE) -endif() - -if(CONFIG_OPENTHREAD_JAM_DETECTION) - set(OT_JAM_DETECTION ON CACHE BOOL "Enable Jam Detection" FORCE) -else() - set(OT_JAM_DETECTION OFF CACHE BOOL "Enable Jam Detection" FORCE) -endif() - -if(CONFIG_OPENTHREAD_JOINER) - set(OT_JOINER ON CACHE BOOL "Enable Joiner" FORCE) -else() - set(OT_JOINER OFF CACHE BOOL "Enable Joiner" FORCE) -endif() - -if(CONFIG_OPENTHREAD_LEGACY) - set(OT_LEGACY ON CACHE BOOL "Enable legacy network support" FORCE) -else() - set(OT_LEGACY OFF CACHE BOOL "Enable legacy network support" FORCE) -endif() - -if(CONFIG_OPENTHREAD_LINK_METRICS_INITIATOR) - set(OT_LINK_METRICS_INITIATOR ON CACHE BOOL "Enable Link Metrics initiator for Thread 1.2" FORCE) -else() - set(OT_LINK_METRICS_INITIATOR OFF CACHE BOOL "Enable Link Metrics initiator for Thread 1.2" FORCE) -endif() - -if(CONFIG_OPENTHREAD_LINK_METRICS_MANAGER) - set(OT_LINK_METRICS_MANAGER ON CACHE BOOL "Enable Link Metrics manager for Thread 1.2" FORCE) -else() - set(OT_LINK_METRICS_MANAGER OFF CACHE BOOL "Enable Link Metrics manager for Thread 1.2" FORCE) -endif() - -if(CONFIG_OPENTHREAD_LINK_METRICS_SUBJECT) - set(OT_LINK_METRICS_SUBJECT ON CACHE BOOL "Enable Link Metrics subject for Thread 1.2" FORCE) -else() - set(OT_LINK_METRICS_SUBJECT OFF CACHE BOOL "Enable Link Metrics subject for Thread 1.2" FORCE) -endif() - -if(CONFIG_OPENTHREAD_LOG_LEVEL_DYNAMIC) - set(OT_LOG_LEVEL_DYNAMIC ON CACHE BOOL "Enable dynamic log level control" FORCE) -else() - set(OT_LOG_LEVEL_DYNAMIC OFF CACHE BOOL "Enable dynamic log level control" FORCE) -endif() - -if(CONFIG_OPENTHREAD_MAC_FILTER) - set(OT_MAC_FILTER ON CACHE BOOL "Enable MAC filter support" FORCE) -else() - set(OT_MAC_FILTER OFF CACHE BOOL "Enable MAC filter support" FORCE) -endif() - -if(CONFIG_OPENTHREAD_MESH_DIAG) - set(OT_MESH_DIAG ON CACHE BOOL "Enable Mesh Diagnostics" FORCE) -else() - set(OT_MESH_DIAG OFF CACHE BOOL "Enable Mesh Diagnostics" FORCE) -endif() - -if(CONFIG_OPENTHREAD_MESSAGE_USE_HEAP) - set(OT_MESSAGE_USE_HEAP ON CACHE BOOL "Enable heap allocator for message buffers" FORCE) -else() - set(OT_MESSAGE_USE_HEAP OFF CACHE BOOL "Enable heap allocator for message buffers" FORCE) -endif() - -if(CONFIG_OPENTHREAD_MLE_LONG_ROUTES) - set(OT_MLE_LONG_ROUTES ON CACHE BOOL "Enable MLE long routes support (Experimental)" FORCE) -else() - set(OT_MLE_LONG_ROUTES OFF CACHE BOOL "Enable MLE long routes support (Experimental)" FORCE) -endif() - -if(CONFIG_OPENTHREAD_MLR) - set(OT_MLR ON CACHE BOOL "Enable Multicast Listener Registration feature for Thread 1.2" FORCE) -else() - set(OT_MLR OFF CACHE BOOL "Enable Multicast Listener Registration feature for Thread 1.2" FORCE) -endif() - -if(CONFIG_OPENTHREAD_MULTIPAN_RCP) - set(OT_MULTIPAN_RCP ON CACHE BOOL "Enable Multi-PAN RCP" FORCE) -else() - set(OT_MULTIPAN_RCP OFF CACHE BOOL "Enable Multi-PAN RCP" FORCE) -endif() - -if(CONFIG_OPENTHREAD_MULTIPLE_INSTANCE) - set(OT_MULTIPLE_INSTANCE ON CACHE BOOL "Enable multiple instances" FORCE) -else() - set(OT_MULTIPLE_INSTANCE OFF CACHE BOOL "Enable multiple instances" FORCE) -endif() - -if(CONFIG_OPENTHREAD_NAT64_BORDER_ROUTING) - set(OT_NAT64_BORDER_ROUTING ON CACHE BOOL "Enable border routing NAT64 support" FORCE) -else() - set(OT_NAT64_BORDER_ROUTING OFF CACHE BOOL "Enable border routing NAT64 support" FORCE) -endif() - -if(CONFIG_OPENTHREAD_NAT64_TRANSLATOR) - set(OT_NAT64_TRANSLATOR ON CACHE BOOL "Enable NAT64 translator" FORCE) -else() - set(OT_NAT64_TRANSLATOR OFF CACHE BOOL "Enable NAT64 translator" FORCE) -endif() - -if(CONFIG_OPENTHREAD_NEIGHBOR_DISCOVERY_AGENT) - set(OT_NEIGHBOR_DISCOVERY_AGENT ON CACHE BOOL "Enable neighbor discovery agent support" FORCE) -else() - set(OT_NEIGHBOR_DISCOVERY_AGENT OFF CACHE BOOL "Enable neighbor discovery agent support" FORCE) -endif() - -if(CONFIG_OPENTHREAD_NETDIAG_CLIENT) - set(OT_NETDIAG_CLIENT ON CACHE BOOL "Enable TMF network diagnostics on clients" FORCE) -else() - set(OT_NETDIAG_CLIENT OFF CACHE BOOL "Enable TMF network diagnostics on clients" FORCE) -endif() - -if(CONFIG_OPENTHREAD_NETDATA_PUBLISHER) - set(OT_NETDATA_PUBLISHER ON CACHE BOOL "Enable Thread Network Data publisher" FORCE) -else() - set(OT_NETDATA_PUBLISHER OFF CACHE BOOL "Enable Thread Network Data publisher" FORCE) -endif() - -if(CONFIG_OPENTHREAD_OPERATIONAL_DATASET_AUTO_INIT) - set(OT_OPERATIONAL_DATASET_AUTO_INIT ON CACHE BOOL "Enable operational dataset auto init" FORCE) -else() - set(OT_OPERATIONAL_DATASET_AUTO_INIT OFF CACHE BOOL "Enable operational dataset auto init" FORCE) -endif() - -if(CONFIG_OPENTHREAD_OTNS) - set(OT_OTNS ON CACHE BOOL "Enable OTNS support" FORCE) -else() - set(OT_OTNS OFF CACHE BOOL "Enable OTNS support" FORCE) -endif() - -if(CONFIG_OPENTHREAD_PING_SENDER) - set(OT_PING_SENDER ON CACHE BOOL "Enable ping sender support" FORCE) -else() - set(OT_PING_SENDER OFF CACHE BOOL "Enable ping sender support" FORCE) -endif() - -if(OPENTHREAD_PLATFORM_KEY_REF) - set(OT_PLATFORM_KEY_REF ON CACHE BOOL "Enable platform key reference support" FORCE) -else() - set(OT_PLATFORM_KEY_REF OFF CACHE BOOL "Enable platform key reference support" FORCE) -endif() - -if(CONFIG_OPENTHREAD_PLATFORM_NETIF) - set(OT_PLATFORM_NETIF ON CACHE BOOL "Enable platform netif support" FORCE) -else() - set(OT_PLATFORM_NETIF OFF CACHE BOOL "Enable platform netif support" FORCE) -endif() - -if(CONFIG_OPENTHREAD_PLATFORM_UDP) - set(OT_PLATFORM_UDP ON CACHE BOOL "Enable platform UDP support" FORCE) -else() - set(OT_PLATFORM_UDP OFF CACHE BOOL "Enable platform UDP support" FORCE) +if(CONFIG_OPENTHREAD_COPROCESSOR_VENDOR_HOOK_SOURCE) + set(OT_NCP_VENDOR_HOOK_SOURCE ${CONFIG_OPENTHREAD_COPROCESSOR_VENDOR_HOOK_SOURCE} CACHE STRING "NCP vendor hook source file name" FORCE) endif() if(CONFIG_OPENTHREAD_POWER_SUPPLY) set(OT_POWER_SUPPLY ${CONFIG_OPENTHREAD_POWER_SUPPLY} CACHE STRING "Power supply configuration" FORCE) endif() -if(CONFIG_OPENTHREAD_RADIO_LINK_IEEE_802_15_4_ENABLE) - set(OT_15_4 ON CACHE BOOL "Enable 802.15.4 radio" FORCE) -else() - set(OT_15_4 OFF CACHE BOOL "Enable 802.15.4 radio" FORCE) -endif() - -if(CONFIG_OPENTHREAD_RAW) - set(OT_LINK_RAW ON CACHE BOOL "Enable Link Raw" FORCE) -else() - set(OT_LINK_RAW OFF CACHE BOOL "Enable Link Raw" FORCE) -endif() - -if(CONFIG_OPENTHREAD_REFERENCE_DEVICE) - set(OT_REFERENCE_DEVICE ON CACHE BOOL "Enable Thread Certification Reference Device" FORCE) -else() - set(OT_REFERENCE_DEVICE OFF CACHE BOOL "Enable Thread Certification Reference Device" FORCE) -endif() - -if(CONFIG_OPENTHREAD_SETTINGS_RAM) - set(OT_SETTINGS_RAM ON CACHE BOOL "Enable volatile-only storage of settings" FORCE) -else() - set(OT_SETTINGS_RAM OFF CACHE BOOL "Enable volatile-only storage of settings" FORCE) -endif() - -if(CONFIG_OPENTHREAD_SLAAC) - set(OT_SLAAC ON CACHE BOOL "Enable SLAAC" FORCE) -else() - set(OT_SLAAC OFF CACHE BOOL "Enable SLAAC" FORCE) -endif() - -if(CONFIG_OPENTHREAD_SNTP_CLIENT) - set(OT_SNTP_CLIENT ON CACHE BOOL "Enable SNTP Client support" FORCE) -else() - set(OT_SNTP_CLIENT OFF CACHE BOOL "Enable SNTP Client support" FORCE) -endif() - -if(CONFIG_OPENTHREAD_SRP_CLIENT) - set(OT_SRP_CLIENT ON CACHE BOOL "Enable SRP Client support" FORCE) -else() - set(OT_SRP_CLIENT OFF CACHE BOOL "Enable SRP Client support" FORCE) -endif() - -if(CONFIG_OPENTHREAD_SRP_SERVER) - set(OT_SRP_SERVER ON CACHE BOOL "Enable SRP Server support" FORCE) -else() - set(OT_SRP_SERVER OFF CACHE BOOL "Enable SRP Server support" FORCE) -endif() - -if(CONFIG_OPENTHREAD_TCP_ENABLE) - set(OT_TCP ON CACHE BOOL "Enable TCP support" FORCE) -else() - set(OT_TCP OFF CACHE BOOL "Enable TCP support" FORCE) -endif() - -if(CONFIG_OPENTHREAD_TIME_SYNC) - set(OT_TIME_SYNC ON CACHE BOOL "Enable the time synchronization service feature" FORCE) -else() - set(OT_TIME_SYNC OFF CACHE BOOL "Enable the time synchronization service feature" FORCE) -endif() - -if(CONFIG_OPENTHREAD_TREL) - set(OT_TREL ON CACHE BOOL "Enable TREL radio link for Thread over Infrastructure feature" FORCE) -else() - set(OT_TREL OFF CACHE BOOL "Enable TREL radio link for Thread over Infrastructure feature" FORCE) -endif() - -if(CONFIG_OPENTHREAD_TX_BEACON_PAYLOAD) - set(OT_TX_BEACON_PAYLOAD ON CACHE BOOL "Enable tx beacon payload support" FORCE) -else() - set(OT_TX_BEACON_PAYLOAD OFF CACHE BOOL "Enable tx beacon payload support" FORCE) -endif() - -if(CONFIG_OPENTHREAD_TX_QUEUE_STATISTICS) - set(OT_TX_QUEUE_STATS ON CACHE BOOL "Enable tx queue statistics" FORCE) -else() - set(OT_TX_QUEUE_STATS OFF CACHE BOOL "Enable tx queue statistics" FORCE) -endif() - -if(CONFIG_OPENTHREAD_UDP_FORWARD) - set(OT_UDP_FORWARD ON CACHE BOOL "Enable UDP forward feature" FORCE) -else() - set(OT_UDP_FORWARD OFF CACHE BOOL "Enable UDP forward feature" FORCE) -endif() - -if(CONFIG_OPENTHREAD_UPTIME) - set(OT_UPTIME ON CACHE BOOL "Enable support for tracking OpenThread instance's uptime" FORCE) -else() - set(OT_UPTIME OFF CACHE BOOL "Enable support for tracking OpenThread instance's uptime" FORCE) -endif() - -if(CONFIG_OPENTHREAD_COPROCESSOR_VENDOR_HOOK_SOURCE) - set(OT_NCP_VENDOR_HOOK_SOURCE ${CONFIG_OPENTHREAD_COPROCESSOR_VENDOR_HOOK_SOURCE} CACHE STRING "NCP vendor hook source file name" FORCE) -endif() - set(BUILD_TESTING OFF CACHE BOOL "Disable openthread cmake testing targets" FORCE) # Zephyr logging options From ffbd0397dd3ea120eb7495a813193c40c1bc1365 Mon Sep 17 00:00:00 2001 From: Fabio Baltieri Date: Fri, 15 Dec 2023 16:18:31 +0000 Subject: [PATCH 1366/3723] input: gpio_kbd_matrix: use edge-to-active interrupt Change the interrupt setup from both edge to edge to active. Edge to active is all was needed anyway and it makes this compatible with gpio controller that only support single edge interrupt. Signed-off-by: Fabio Baltieri --- drivers/input/input_gpio_kbd_matrix.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/input/input_gpio_kbd_matrix.c b/drivers/input/input_gpio_kbd_matrix.c index b869616a14f..4c82e132f07 100644 --- a/drivers/input/input_gpio_kbd_matrix.c +++ b/drivers/input/input_gpio_kbd_matrix.c @@ -132,7 +132,6 @@ static void gpio_kbd_matrix_set_detect_mode(const struct device *dev, bool enabl { const struct gpio_kbd_matrix_config *cfg = dev->config; const struct input_kbd_matrix_common_config *common = &cfg->common; - gpio_flags_t flags = enabled ? GPIO_INT_EDGE_BOTH : GPIO_INT_DISABLE; int ret; if (cfg->idle_poll_dwork != NULL) { @@ -149,6 +148,7 @@ static void gpio_kbd_matrix_set_detect_mode(const struct device *dev, bool enabl for (int i = 0; i < common->row_size; i++) { const struct gpio_dt_spec *gpio = &cfg->row_gpio[i]; + gpio_flags_t flags = enabled ? GPIO_INT_EDGE_TO_ACTIVE : GPIO_INT_DISABLE; ret = gpio_pin_interrupt_configure_dt(gpio, flags); if (ret != 0) { From ecce23532270a0b5bb6e64f97503b1b3cf00b26a Mon Sep 17 00:00:00 2001 From: Fabio Baltieri Date: Fri, 15 Dec 2023 16:19:57 +0000 Subject: [PATCH 1367/3723] input: kbd_matrix: fix possible race condition Fix a possible race condition in the keyboard matrix library where a key would get pressed between the last read and reenabling the (edge sensitive) interrupt and the even would be lost. The window for this to happen is very narrow and had to artificially add a sleep to reproduce it. Signed-off-by: Fabio Baltieri --- drivers/input/input_kbd_matrix.c | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/drivers/input/input_kbd_matrix.c b/drivers/input/input_kbd_matrix.c index 078ccf8cefa..39bebf5c496 100644 --- a/drivers/input/input_kbd_matrix.c +++ b/drivers/input/input_kbd_matrix.c @@ -291,6 +291,13 @@ static void input_kbd_matrix_polling_thread(void *arg1, void *unused2, void *unu input_kbd_matrix_drive_column(dev, INPUT_KBD_MATRIX_COLUMN_DRIVE_ALL); api->set_detect_mode(dev, true); + /* Check the rows again after enabling the interrupt to catch + * any potential press since the last read. + */ + if (api->read_row(dev) != 0) { + input_kbd_matrix_poll_start(dev); + } + k_sem_take(&data->poll_lock, K_FOREVER); LOG_DBG("scan start"); From d385150bb07585f9cde5623a40a834102cc17084 Mon Sep 17 00:00:00 2001 From: Aaron Ye Date: Wed, 13 Dec 2023 12:18:57 +0800 Subject: [PATCH 1368/3723] drivers: bluetooth: Add Ambiq HCI driver for Apollo4 Blue Plus. This commits create the dts binding for Ambiq BT HCI instance. And create the SPI based common HCI driver for Ambiq Apollox Blue SoC and the extended soc driver for HCI. Signed-off-by: Aaron Ye --- drivers/bluetooth/hci/CMakeLists.txt | 1 + drivers/bluetooth/hci/Kconfig | 23 +- drivers/bluetooth/hci/apollox_blue.c | 366 ++++++++++++++++++ drivers/bluetooth/hci/apollox_blue.h | 105 +++++ drivers/bluetooth/hci/hci_ambiq.c | 387 +++++++++++++++++++ dts/bindings/bluetooth/ambiq,bt-hci-spi.yaml | 32 ++ subsys/bluetooth/host/Kconfig | 1 + 7 files changed, 914 insertions(+), 1 deletion(-) create mode 100644 drivers/bluetooth/hci/apollox_blue.c create mode 100644 drivers/bluetooth/hci/apollox_blue.h create mode 100644 drivers/bluetooth/hci/hci_ambiq.c create mode 100644 dts/bindings/bluetooth/ambiq,bt-hci-spi.yaml diff --git a/drivers/bluetooth/hci/CMakeLists.txt b/drivers/bluetooth/hci/CMakeLists.txt index 6aaf5205b0d..b5d30d2b880 100644 --- a/drivers/bluetooth/hci/CMakeLists.txt +++ b/drivers/bluetooth/hci/CMakeLists.txt @@ -25,3 +25,4 @@ zephyr_library_sources_ifdef(CONFIG_BT_USERCHAN userchan.c) zephyr_library_sources_ifdef(CONFIG_BT_SILABS_HCI slz_hci.c) zephyr_library_sources_ifdef(CONFIG_BT_PSOC6_BLESS hci_psoc6_bless.c) zephyr_library_sources_ifdef(CONFIG_SOC_NRF5340_CPUAPP nrf53_support.c) +zephyr_library_sources_ifdef(CONFIG_BT_AMBIQ_HCI hci_ambiq.c apollox_blue.c) diff --git a/drivers/bluetooth/hci/Kconfig b/drivers/bluetooth/hci/Kconfig index b1901d504a8..fe204d564fb 100644 --- a/drivers/bluetooth/hci/Kconfig +++ b/drivers/bluetooth/hci/Kconfig @@ -110,6 +110,16 @@ config BT_NO_DRIVER This is intended for unit tests where no internal driver should be selected. +config BT_AMBIQ_HCI + bool "AMBIQ BT HCI driver" + select SPI + select GPIO + select CLOCK_CONTROL + select BT_HCI_SETUP + help + Supports Ambiq Bluetooth SoC using SPI as the communication protocol. + HCI packets are sent and received as single Byte transfers. + endchoice if BT_SPI @@ -127,6 +137,17 @@ config BT_BLUENRG_ACI endif # BT_SPI +if BT_AMBIQ_HCI + +config BT_HCI_INIT_PRIORITY + int "BT HCI init priority" + default 75 + help + The priority of BT HCI driver initialization needs to be lower than + the SPI, GPIO, clock controller drivers initialization priorities. + +endif # BT_AMBIQ_HCI + config BT_STM32_IPM_RX_STACK_SIZE int "STM32 IPM stack size for RX thread" depends on BT_STM32_IPM @@ -193,7 +214,7 @@ config BT_DRV_TX_STACK_SIZE config BT_DRV_RX_STACK_SIZE int - default 640 if BT_SPI + default 640 if (BT_SPI || BT_AMBIQ_HCI) default BT_RX_STACK_SIZE if (BT_H4 || BT_HCI_RAW_H4) default BT_STM32_IPM_RX_STACK_SIZE if BT_STM32_IPM default 256 diff --git a/drivers/bluetooth/hci/apollox_blue.c b/drivers/bluetooth/hci/apollox_blue.c new file mode 100644 index 00000000000..eff8d8fbd81 --- /dev/null +++ b/drivers/bluetooth/hci/apollox_blue.c @@ -0,0 +1,366 @@ +/* + * Copyright (c) 2023 Ambiq Micro Inc. + * + * SPDX-License-Identifier: Apache-2.0 + */ + +/** + * @brief Ambiq Apollox Blue SoC extended driver for SPI based HCI. + */ + +#define DT_DRV_COMPAT ambiq_bt_hci_spi + +#include +#include +#include +#include +#include +#include +#include + +#define LOG_LEVEL CONFIG_BT_HCI_DRIVER_LOG_LEVEL +#include +LOG_MODULE_REGISTER(bt_apollox_driver); + +#include +#include + +#include "apollox_blue.h" +#include "am_devices_cooper.h" + +#define HCI_SPI_NODE DT_COMPAT_GET_ANY_STATUS_OKAY(ambiq_bt_hci_spi) +#define SPI_DEV_NODE DT_BUS(HCI_SPI_NODE) +#define CLK_32M_NODE DT_NODELABEL(xo32m) +#define CLK_32K_NODE DT_NODELABEL(xo32k) + +/* Command/response for SPI operation */ +#define SPI_WRITE 0x80 +#define SPI_READ 0x04 +#define READY_BYTE0 0x68 +#define READY_BYTE1 0xA8 + +/* Maximum attempts of SPI write */ +#define SPI_WRITE_TIMEOUT 200 + +#define SPI_MAX_RX_MSG_LEN 258 + +static const struct gpio_dt_spec irq_gpio = GPIO_DT_SPEC_GET(HCI_SPI_NODE, irq_gpios); +static const struct gpio_dt_spec rst_gpio = GPIO_DT_SPEC_GET(HCI_SPI_NODE, reset_gpios); +static const struct gpio_dt_spec cs_gpio = GPIO_DT_SPEC_GET(SPI_DEV_NODE, cs_gpios); +static const struct gpio_dt_spec clkreq_gpio = GPIO_DT_SPEC_GET(HCI_SPI_NODE, clkreq_gpios); + +static struct gpio_callback irq_gpio_cb; +static struct gpio_callback clkreq_gpio_cb; + +static const struct device *clk32m_dev = DEVICE_DT_GET(CLK_32M_NODE); +static const struct device *clk32k_dev = DEVICE_DT_GET(CLK_32K_NODE); + +extern void bt_packet_irq_isr(const struct device *unused1, struct gpio_callback *unused2, + uint32_t unused3); + +static bool irq_pin_state(void) +{ + int pin_state; + + pin_state = gpio_pin_get_dt(&irq_gpio); + LOG_DBG("IRQ Pin: %d", pin_state); + return pin_state > 0; +} + +static bool clkreq_pin_state(void) +{ + int pin_state; + + pin_state = gpio_pin_get_dt(&clkreq_gpio); + LOG_DBG("CLKREQ Pin: %d", pin_state); + return pin_state > 0; +} + +static void bt_clkreq_isr(const struct device *unused1, struct gpio_callback *unused2, + uint32_t unused3) +{ + if (clkreq_pin_state()) { + /* Enable XO32MHz */ + clock_control_on(clk32m_dev, + (clock_control_subsys_t)CLOCK_CONTROL_AMBIQ_TYPE_HFXTAL_BLE); + gpio_pin_interrupt_configure_dt(&clkreq_gpio, GPIO_INT_EDGE_FALLING); + } else { + /* Disable XO32MHz */ + clock_control_off(clk32m_dev, + (clock_control_subsys_t)CLOCK_CONTROL_AMBIQ_TYPE_HFXTAL_BLE); + gpio_pin_interrupt_configure_dt(&clkreq_gpio, GPIO_INT_EDGE_RISING); + } +} + +static void bt_apollo_controller_ready_wait(void) +{ + /* The CS pin is used to wake up the controller as well. If the controller is not ready + * to receive the SPI packet, need to inactivate the CS at first and reconfigure the pin + * to CS function again before next sending attempt. + */ + gpio_pin_configure_dt(&cs_gpio, GPIO_OUTPUT_INACTIVE); + k_busy_wait(200); + PINCTRL_DT_DEFINE(SPI_DEV_NODE); + pinctrl_apply_state(PINCTRL_DT_DEV_CONFIG_GET(SPI_DEV_NODE), PINCTRL_STATE_DEFAULT); + k_busy_wait(2000); +} + +static void bt_apollo_controller_reset(void) +{ + /* Reset the controller*/ + gpio_pin_set_dt(&rst_gpio, 1); + + /* Take controller out of reset */ + k_sleep(K_MSEC(10)); + gpio_pin_set_dt(&rst_gpio, 0); + + /* Give the controller some time to boot */ + k_sleep(K_MSEC(500)); +} + +int bt_apollo_spi_send(uint8_t *data, uint16_t len, bt_spi_transceive_fun transceive) +{ + int ret; + uint8_t command[1] = {SPI_WRITE}; + uint8_t response[2] = {0, 0}; + uint16_t fail_count = 0; + + do { + /* Check if the controller is ready to receive the HCI packets. */ + ret = transceive(command, 1, response, 2); + if ((response[0] != READY_BYTE0) || (response[1] != READY_BYTE1) || ret) { + bt_apollo_controller_ready_wait(); + } else { + /* Transmit the message */ + ret = transceive(data, len, NULL, 0); + if (ret) { + LOG_ERR("SPI write error %d", ret); + } + break; + } + } while (fail_count++ < SPI_WRITE_TIMEOUT); + + return ret; +} + +int bt_apollo_spi_rcv(uint8_t *data, uint16_t *len, bt_spi_transceive_fun transceive) +{ + int ret; + uint8_t command[1] = {SPI_READ}; + uint8_t response[2] = {0, 0}; + uint16_t read_size = 0; + + do { + /* Skip if the IRQ pin is not in high state */ + if (!irq_pin_state()) { + ret = -1; + break; + } + + /* Check the available packet bytes */ + ret = transceive(command, 1, response, 2); + if (ret) { + break; + } + + /* Check if the read size is acceptable */ + read_size = (uint16_t)(response[0] | response[1] << 8); + if ((read_size == 0) || (read_size > SPI_MAX_RX_MSG_LEN)) { + ret = -1; + break; + } + + *len = read_size; + + /* Read the HCI data from controller */ + ret = transceive(NULL, 0, data, read_size); + + if (ret) { + LOG_ERR("SPI read error %d", ret); + break; + } + } while (0); + + return ret; +} + +bool bt_apollo_vnd_rcv_ongoing(uint8_t *data, uint16_t len) +{ + /* The vendor specific handshake command/response is incompatible with + * standard Bluetooth HCI format, need to handle the received packets + * specifically. + */ + if (am_devices_cooper_get_initialize_state() != AM_DEVICES_COOPER_STATE_INITIALIZED) { + am_devices_cooper_handshake_recv(data, len); + return true; + } else { + return false; + } +} + +int bt_hci_transport_setup(const struct device *dev) +{ + ARG_UNUSED(dev); + + int ret; + + /* Configure the XO32MHz and XO32kHz clocks.*/ + clock_control_configure(clk32k_dev, NULL, NULL); + clock_control_configure(clk32m_dev, NULL, NULL); + + /* Enable XO32kHz for Controller */ + clock_control_on(clk32k_dev, (clock_control_subsys_t)CLOCK_CONTROL_AMBIQ_TYPE_LFXTAL); + + /* Enable XO32MHz for Controller */ + clock_control_on(clk32m_dev, (clock_control_subsys_t)CLOCK_CONTROL_AMBIQ_TYPE_HFXTAL_BLE); + + /* Configure RST pin and hold BLE in Reset */ + ret = gpio_pin_configure_dt(&rst_gpio, GPIO_OUTPUT_ACTIVE); + if (ret) { + return ret; + } + + /* Configure IRQ pin and register the callback */ + ret = gpio_pin_configure_dt(&irq_gpio, GPIO_INPUT); + if (ret) { + return ret; + } + + gpio_init_callback(&irq_gpio_cb, bt_packet_irq_isr, BIT(irq_gpio.pin)); + ret = gpio_add_callback(irq_gpio.port, &irq_gpio_cb); + if (ret) { + return ret; + } + + /* Configure CLKREQ pin and register the callback */ + ret = gpio_pin_configure_dt(&clkreq_gpio, GPIO_INPUT); + if (ret) { + return ret; + } + + gpio_init_callback(&clkreq_gpio_cb, bt_clkreq_isr, BIT(clkreq_gpio.pin)); + ret = gpio_add_callback(clkreq_gpio.port, &clkreq_gpio_cb); + if (ret) { + return ret; + } + + /* Configure the interrupt edge for CLKREQ pin */ + gpio_pin_interrupt_configure_dt(&clkreq_gpio, GPIO_INT_EDGE_RISING); + + /* Take controller out of reset */ + k_sleep(K_MSEC(10)); + gpio_pin_set_dt(&rst_gpio, 0); + + /* Give the controller some time to boot */ + k_sleep(K_MSEC(500)); + + /* Configure the interrupt edge for IRQ pin */ + gpio_pin_interrupt_configure_dt(&irq_gpio, GPIO_INT_EDGE_RISING); + + return 0; +} + +int bt_apollo_controller_init(spi_transmit_fun transmit) +{ + int ret; + am_devices_cooper_callback_t cb = { + .write = transmit, + .reset = bt_apollo_controller_reset, + }; + + /* Initialize the BLE controller */ + ret = am_devices_cooper_init(&cb); + if (ret == AM_DEVICES_COOPER_STATUS_SUCCESS) { + am_devices_cooper_set_initialize_state(AM_DEVICES_COOPER_STATE_INITIALIZED); + LOG_INF("BT controller initialized"); + } else { + am_devices_cooper_set_initialize_state(AM_DEVICES_COOPER_STATE_INITIALIZE_FAIL); + LOG_ERR("BT controller initialization fail"); + } + + return ret; +} + +static int bt_apollo_set_nvds(void) +{ + int ret; + struct net_buf *buf; + +#if defined(CONFIG_BT_HCI_RAW) + struct bt_hci_cmd_hdr hdr; + + hdr.opcode = sys_cpu_to_le16(HCI_VSC_UPDATE_NVDS_CFG_CMD_OPCODE); + hdr.param_len = HCI_VSC_UPDATE_NVDS_CFG_CMD_LENGTH; + buf = bt_buf_get_tx(BT_BUF_CMD, K_NO_WAIT, &hdr, sizeof(hdr)); + if (!buf) { + return -ENOBUFS; + } + + net_buf_add_mem(buf, &am_devices_cooper_nvds[0], HCI_VSC_UPDATE_NVDS_CFG_CMD_LENGTH); + ret = bt_send(buf); + + if (!ret) { + /* Give some time to make NVDS take effect in BLE controller */ + k_sleep(K_MSEC(5)); + + /* Need to send reset command to make the NVDS take effect */ + hdr.opcode = sys_cpu_to_le16(BT_HCI_OP_RESET); + hdr.param_len = 0; + buf = bt_buf_get_tx(BT_BUF_CMD, K_NO_WAIT, &hdr, sizeof(hdr)); + if (!buf) { + return -ENOBUFS; + } + + ret = bt_send(buf); + } +#else + uint8_t *p; + + buf = bt_hci_cmd_create(HCI_VSC_UPDATE_NVDS_CFG_CMD_OPCODE, + HCI_VSC_UPDATE_NVDS_CFG_CMD_LENGTH); + if (!buf) { + return -ENOBUFS; + } + + p = net_buf_add(buf, HCI_VSC_UPDATE_NVDS_CFG_CMD_LENGTH); + memcpy(p, &am_devices_cooper_nvds[0], HCI_VSC_UPDATE_NVDS_CFG_CMD_LENGTH); + ret = bt_hci_cmd_send_sync(HCI_VSC_UPDATE_NVDS_CFG_CMD_OPCODE, buf, NULL); + + if (!ret) { + /* Give some time to make NVDS take effect in BLE controller */ + k_sleep(K_MSEC(5)); + } +#endif /* defined(CONFIG_BT_HCI_RAW) */ + + return ret; +} + +int bt_apollo_vnd_setup(void) +{ + int ret; + + /* Set the NVDS parameters to BLE controller */ + ret = bt_apollo_set_nvds(); + + return ret; +} + +int bt_apollo_dev_init(void) +{ + if (!gpio_is_ready_dt(&irq_gpio)) { + LOG_ERR("IRQ GPIO device not ready"); + return -ENODEV; + } + + if (!gpio_is_ready_dt(&rst_gpio)) { + LOG_ERR("Reset GPIO device not ready"); + return -ENODEV; + } + + if (!gpio_is_ready_dt(&clkreq_gpio)) { + LOG_ERR("CLKREQ GPIO device not ready"); + return -ENODEV; + } + + return 0; +} diff --git a/drivers/bluetooth/hci/apollox_blue.h b/drivers/bluetooth/hci/apollox_blue.h new file mode 100644 index 00000000000..a05238657e5 --- /dev/null +++ b/drivers/bluetooth/hci/apollox_blue.h @@ -0,0 +1,105 @@ +/* + * Copyright (c) 2023 Ambiq Micro Inc. + * + * SPDX-License-Identifier: Apache-2.0 + */ + +/** + * @brief Header file of Ambiq Apollox Blue SoC extended driver + * for SPI based HCI. + */ +#ifndef ZEPHYR_DRIVERS_BLUETOOTH_HCI_APOLLOX_BLUE_H_ +#define ZEPHYR_DRIVERS_BLUETOOTH_HCI_APOLLOX_BLUE_H_ + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * @typedef bt_spi_transceive_fun + * @brief SPI transceive function for Bluetooth packet. + * + * @param tx Pointer of transmission packet. + * @param tx_len Length of transmission packet. + * @param rx Pointer of reception packet. + * @param rx_len Length of reception packet. + * + * @return 0 on success or negative error number on failure. + */ +typedef int (*bt_spi_transceive_fun)(void *tx, uint32_t tx_len, void *rx, uint32_t rx_len); + +/** + * @typedef spi_transmit_fun + * @brief Define the SPI transmission function. + * + * @param data Pointer of transmission packet. + * @param len Length of transmission packet. + * + * @return 0 on success or negative error number on failure. + */ +typedef int (*spi_transmit_fun)(uint8_t *data, uint16_t len); + +/** + * @brief Initialize the required devices for HCI driver. + * + * The devices mainly include the required gpio (e.g. reset-gpios, + * irq-gpios). + * + * @return 0 on success or negative error number on failure. + */ +int bt_apollo_dev_init(void); + +/** + * @brief Send the packets to BLE controller from host via SPI. + * + * @param data Pointer of transmission packet. + * @param len Length of transmission packet. + * @param transceive SPI transceive function for Bluetooth packet. + * + * @return 0 on success or negative error number on failure. + */ +int bt_apollo_spi_send(uint8_t *data, uint16_t len, bt_spi_transceive_fun transceive); + +/** + * @brief Receive the packets sent from BLE controller to host via SPI. + * + * @param data Pointer of reception packet. + * @param len Pointer of reception packet length. + * @param transceive SPI transceive function for Bluetooth packet. + * + * @return 0 on success or negative error number on failure. + */ +int bt_apollo_spi_rcv(uint8_t *data, uint16_t *len, bt_spi_transceive_fun transceive); + +/** + * @brief Initialize the BLE controller. + * + * This step may do the necessary handshaking with the controller before + * @param transmit SPI transmit function + * + * @return 0 on success or negative error number on failure. + */ +int bt_apollo_controller_init(spi_transmit_fun transmit); + +/** + * @brief Vendor specific setup before general HCI command sequence for + * Bluetooth application. + * + * @return 0 on success or negative error number on failure. + */ +int bt_apollo_vnd_setup(void); + +/** + * @brief Check if vendor specific receiving handling is ongoing. + * + * @param data Pointer of received packet. + * + * @return true indicates if vendor specific receiving handling is ongoing. + */ +bool bt_apollo_vnd_rcv_ongoing(uint8_t *data, uint16_t len); + +#ifdef __cplusplus +} +#endif + +#endif /* ZEPHYR_DRIVERS_BLUETOOTH_HCI_APOLLOX_BLUE_H_ */ diff --git a/drivers/bluetooth/hci/hci_ambiq.c b/drivers/bluetooth/hci/hci_ambiq.c new file mode 100644 index 00000000000..387bc5611f1 --- /dev/null +++ b/drivers/bluetooth/hci/hci_ambiq.c @@ -0,0 +1,387 @@ +/* + * Copyright (c) 2023 Ambiq Micro Inc. + * + * SPDX-License-Identifier: Apache-2.0 + */ + +/** + * @brief Ambiq SPI based Bluetooth HCI driver. + */ + +#define DT_DRV_COMPAT ambiq_bt_hci_spi + +#include +#include +#include +#include +#include + +#define LOG_LEVEL CONFIG_BT_HCI_DRIVER_LOG_LEVEL +#include +LOG_MODULE_REGISTER(bt_hci_driver); + +#include "apollox_blue.h" + +#define HCI_SPI_NODE DT_COMPAT_GET_ANY_STATUS_OKAY(ambiq_bt_hci_spi) +#define SPI_DEV_NODE DT_BUS(HCI_SPI_NODE) + +#define HCI_CMD 0x01 +#define HCI_ACL 0x02 +#define HCI_SCO 0x03 +#define HCI_EVT 0x04 + +/* Offset of special item */ +#define PACKET_TYPE 0 +#define PACKET_TYPE_SIZE 1 +#define EVT_HEADER_TYPE 0 +#define EVT_HEADER_EVENT 1 +#define EVT_HEADER_SIZE 2 +#define EVT_VENDOR_CODE_LSB 3 +#define EVT_VENDOR_CODE_MSB 4 +#define CMD_OGF 1 +#define CMD_OCF 2 + +#define EVT_OK 0 +#define EVT_DISCARD 1 +#define EVT_NOP 2 + +/* Max SPI buffer length for transceive operations. + * The maximum TX packet number is 512 bytes data + 12 bytes header. + * The maximum RX packet number is 255 bytes data + 3 header. + */ +#define SPI_MAX_TX_MSG_LEN 524 +#define SPI_MAX_RX_MSG_LEN 258 + +static uint8_t g_hciRxMsg[SPI_MAX_RX_MSG_LEN]; +static const struct device *spi_dev = DEVICE_DT_GET(SPI_DEV_NODE); +static struct spi_config spi_cfg = { + .operation = SPI_OP_MODE_MASTER | SPI_TRANSFER_MSB | SPI_MODE_CPOL | SPI_MODE_CPHA | + SPI_WORD_SET(8), +}; +static K_KERNEL_STACK_DEFINE(spi_rx_stack, CONFIG_BT_DRV_RX_STACK_SIZE); +static struct k_thread spi_rx_thread_data; + +static struct spi_buf spi_tx_buf; +static struct spi_buf spi_rx_buf; +static const struct spi_buf_set spi_tx = {.buffers = &spi_tx_buf, .count = 1}; +static const struct spi_buf_set spi_rx = {.buffers = &spi_rx_buf, .count = 1}; + +static K_SEM_DEFINE(sem_irq, 0, 1); +static K_SEM_DEFINE(sem_spi_available, 1, 1); + +void bt_packet_irq_isr(const struct device *unused1, struct gpio_callback *unused2, + uint32_t unused3) +{ + k_sem_give(&sem_irq); +} + +static inline int bt_spi_transceive(void *tx, uint32_t tx_len, void *rx, uint32_t rx_len) +{ + spi_tx_buf.buf = tx; + spi_tx_buf.len = (size_t)tx_len; + spi_rx_buf.buf = rx; + spi_rx_buf.len = (size_t)rx_len; + return spi_transceive(spi_dev, &spi_cfg, &spi_tx, &spi_rx); +} + +static int spi_send_packet(uint8_t *data, uint16_t len) +{ + int ret; + + /* Wait for SPI bus to be available */ + k_sem_take(&sem_spi_available, K_FOREVER); + + /* Send the SPI packet to controller */ + ret = bt_apollo_spi_send(data, len, bt_spi_transceive); + + /* Free the SPI bus */ + k_sem_give(&sem_spi_available); + + return ret; +} + +static int spi_receive_packet(uint8_t *data, uint16_t *len) +{ + int ret; + + /* Wait for SPI bus to be available */ + k_sem_take(&sem_spi_available, K_FOREVER); + + /* Receive the SPI packet from controller */ + ret = bt_apollo_spi_rcv(data, len, bt_spi_transceive); + + /* Free the SPI bus */ + k_sem_give(&sem_spi_available); + + return ret; +} + +static int hci_event_filter(const uint8_t *evt_data) +{ + uint8_t evt_type = evt_data[0]; + + switch (evt_type) { + case BT_HCI_EVT_LE_META_EVENT: { + uint8_t subevt_type = evt_data[sizeof(struct bt_hci_evt_hdr)]; + + switch (subevt_type) { + case BT_HCI_EVT_LE_ADVERTISING_REPORT: + return EVT_DISCARD; + default: + return EVT_OK; + } + } + case BT_HCI_EVT_CMD_COMPLETE: { + uint16_t opcode = (uint16_t)(evt_data[3] + (evt_data[4] << 8)); + + switch (opcode) { + case BT_OP_NOP: + return EVT_NOP; + default: + return EVT_OK; + } + } + default: + return EVT_OK; + } +} + +static struct net_buf *bt_hci_evt_recv(uint8_t *data, size_t len) +{ + int evt_filter; + bool discardable = false; + struct bt_hci_evt_hdr hdr = {0}; + struct net_buf *buf; + size_t buf_tailroom; + + if (len < sizeof(hdr)) { + LOG_ERR("Not enough data for event header"); + return NULL; + } + + evt_filter = hci_event_filter(data); + if (evt_filter == EVT_NOP) { + /* The controller sends NOP event when wakes up based on + * hardware specific requirement, do not post this event to + * host stack. + */ + return NULL; + } else if (evt_filter == EVT_DISCARD) { + discardable = true; + } + + memcpy((void *)&hdr, data, sizeof(hdr)); + data += sizeof(hdr); + len -= sizeof(hdr); + + if (len != hdr.len) { + LOG_ERR("Event payload length is not correct"); + return NULL; + } + + buf = bt_buf_get_evt(hdr.evt, discardable, K_NO_WAIT); + if (!buf) { + if (discardable) { + LOG_DBG("Discardable buffer pool full, ignoring event"); + } else { + LOG_ERR("No available event buffers!"); + } + return buf; + } + + net_buf_add_mem(buf, &hdr, sizeof(hdr)); + + buf_tailroom = net_buf_tailroom(buf); + if (buf_tailroom < len) { + LOG_ERR("Not enough space in buffer %zu/%zu", len, buf_tailroom); + net_buf_unref(buf); + return NULL; + } + + net_buf_add_mem(buf, data, len); + + return buf; +} + +static struct net_buf *bt_hci_acl_recv(uint8_t *data, size_t len) +{ + struct bt_hci_acl_hdr hdr = {0}; + struct net_buf *buf; + size_t buf_tailroom; + + if (len < sizeof(hdr)) { + LOG_ERR("Not enough data for ACL header"); + return NULL; + } + + buf = bt_buf_get_rx(BT_BUF_ACL_IN, K_NO_WAIT); + if (buf) { + memcpy((void *)&hdr, data, sizeof(hdr)); + data += sizeof(hdr); + len -= sizeof(hdr); + } else { + LOG_ERR("No available ACL buffers!"); + return NULL; + } + + if (len != sys_le16_to_cpu(hdr.len)) { + LOG_ERR("ACL payload length is not correct"); + net_buf_unref(buf); + return NULL; + } + + net_buf_add_mem(buf, &hdr, sizeof(hdr)); + buf_tailroom = net_buf_tailroom(buf); + if (buf_tailroom < len) { + LOG_ERR("Not enough space in buffer %zu/%zu", len, buf_tailroom); + net_buf_unref(buf); + return NULL; + } + + net_buf_add_mem(buf, data, len); + + return buf; +} + +static void bt_spi_rx_thread(void *p1, void *p2, void *p3) +{ + ARG_UNUSED(p1); + ARG_UNUSED(p2); + ARG_UNUSED(p3); + + struct net_buf *buf; + int ret; + uint16_t len = 0; + + while (true) { + /* Wait for controller interrupt */ + k_sem_take(&sem_irq, K_FOREVER); + + do { + /* Recevive the HCI packet via SPI */ + ret = spi_receive_packet(&g_hciRxMsg[0], &len); + if (ret) { + break; + } + + /* Check if needs to handle the vendor specific events which are + * incompatible with the standard Bluetooth HCI format. + */ + if (bt_apollo_vnd_rcv_ongoing(&g_hciRxMsg[0], len)) { + break; + } + + switch (g_hciRxMsg[PACKET_TYPE]) { + case HCI_EVT: + buf = bt_hci_evt_recv(&g_hciRxMsg[PACKET_TYPE + PACKET_TYPE_SIZE], + (len - PACKET_TYPE_SIZE)); + break; + case HCI_ACL: + buf = bt_hci_acl_recv(&g_hciRxMsg[PACKET_TYPE + PACKET_TYPE_SIZE], + (len - PACKET_TYPE_SIZE)); + break; + default: + buf = NULL; + LOG_WRN("Unknown BT buf type %d", g_hciRxMsg[PACKET_TYPE]); + break; + } + + /* Post the RX message to host stack to process */ + if (buf) { + bt_recv(buf); + } + } while (0); + } +} + +static int bt_hci_send(struct net_buf *buf) +{ + int ret = 0; + + /* Buffer needs an additional byte for type */ + if (buf->len >= SPI_MAX_TX_MSG_LEN) { + LOG_ERR("Message too long"); + return -EINVAL; + } + + switch (bt_buf_get_type(buf)) { + case BT_BUF_ACL_OUT: + net_buf_push_u8(buf, HCI_ACL); + break; + case BT_BUF_CMD: + net_buf_push_u8(buf, HCI_CMD); + break; + default: + LOG_ERR("Unsupported type"); + net_buf_unref(buf); + return -EINVAL; + } + + /* Send the SPI packet */ + ret = spi_send_packet(buf->data, buf->len); + + net_buf_unref(buf); + + return ret; +} + +static int bt_hci_open(void) +{ + int ret; + + ret = bt_hci_transport_setup(spi_dev); + if (ret) { + return ret; + } + + /* Start RX thread */ + k_thread_create(&spi_rx_thread_data, spi_rx_stack, K_KERNEL_STACK_SIZEOF(spi_rx_stack), + (k_thread_entry_t)bt_spi_rx_thread, NULL, NULL, NULL, + K_PRIO_COOP(CONFIG_BT_DRIVER_RX_HIGH_PRIO), 0, K_NO_WAIT); + + ret = bt_apollo_controller_init(spi_send_packet); + + return ret; +} + +static int bt_spi_setup(const struct bt_hci_setup_params *params) +{ + ARG_UNUSED(params); + + int ret; + + ret = bt_apollo_vnd_setup(); + + return ret; +} + +static const struct bt_hci_driver drv = { + .name = "ambiq hci", + .bus = BT_HCI_DRIVER_BUS_SPI, + .open = bt_hci_open, + .send = bt_hci_send, + .setup = bt_spi_setup, +}; + +static int bt_hci_init(void) +{ + int ret; + + if (!device_is_ready(spi_dev)) { + LOG_ERR("SPI device not ready"); + return -ENODEV; + } + + ret = bt_apollo_dev_init(); + if (ret) { + return ret; + } + + bt_hci_driver_register(&drv); + + LOG_DBG("BT HCI initialized"); + + return 0; +} + +SYS_INIT(bt_hci_init, POST_KERNEL, CONFIG_BT_HCI_INIT_PRIORITY); diff --git a/dts/bindings/bluetooth/ambiq,bt-hci-spi.yaml b/dts/bindings/bluetooth/ambiq,bt-hci-spi.yaml new file mode 100644 index 00000000000..c939f27841f --- /dev/null +++ b/dts/bindings/bluetooth/ambiq,bt-hci-spi.yaml @@ -0,0 +1,32 @@ +# Copyright (c) 2023, Ambiq Micro Inc. +# SPDX-License-Identifier: Apache-2.0 + +description: | + Bluetooth module that uses Ambiq's Bluetooth Host Controller Interface SPI + driver (e.g. Apollo4 Blue Plus). + +compatible: "ambiq,bt-hci-spi" + +properties: + reg: + type: array + required: true + + irq-gpios: + type: phandle-array + description: | + This irq gpio is used to indicate there is packet ready to send to host + from controller. + + reset-gpios: + type: phandle-array + description: | + This reset gpio is used to reset the Bluetooth controller. + + clkreq-gpios: + type: phandle-array + description: | + This clkreq gpio is used to send the XO32MHz clock request to host from + from controller. The host needs to enable XO32MHz when receiveing low to + high edge interrupt and disable XO32MHz when receiveing high to low edge + interrupt. diff --git a/subsys/bluetooth/host/Kconfig b/subsys/bluetooth/host/Kconfig index c5c73be39a2..94378128baa 100644 --- a/subsys/bluetooth/host/Kconfig +++ b/subsys/bluetooth/host/Kconfig @@ -82,6 +82,7 @@ config BT_HCI_RESERVE default 1 if BT_USERCHAN default 1 if BT_ESP32 default 0 if BT_B91 + default 1 if BT_AMBIQ_HCI # Even if no driver is selected the following default is still # needed e.g. for unit tests. default 0 From a95cbfb0dd8f914dbdcb2f462af2f66a0b9f17ae Mon Sep 17 00:00:00 2001 From: Aaron Ye Date: Wed, 6 Dec 2023 23:04:02 +0800 Subject: [PATCH 1369/3723] boards: arm: apollo4p_blue_kxr_evb: Enable BT HCI. The BT HCI uses internal IOM4 (SPI4) for communication bus. Set the default configuration for BT based on the controller supported capability and HCI driver dependency. Signed-off-by: Aaron Ye --- .../apollo4p_blue_kxr_evb/Kconfig.defconfig | 31 +++++++++++++++++++ .../apollo4p_blue_kxr_evb.dts | 17 ++++++++++ 2 files changed, 48 insertions(+) diff --git a/boards/arm/apollo4p_blue_kxr_evb/Kconfig.defconfig b/boards/arm/apollo4p_blue_kxr_evb/Kconfig.defconfig index f14c801d3b3..1edc7b5581b 100644 --- a/boards/arm/apollo4p_blue_kxr_evb/Kconfig.defconfig +++ b/boards/arm/apollo4p_blue_kxr_evb/Kconfig.defconfig @@ -5,3 +5,34 @@ config BOARD default "apollo4p_blue_kxr_evb" depends on BOARD_APOLLO4P_BLUE_KXR_EVB + +if BT + +config MAIN_STACK_SIZE + default 2048 + +choice BT_HCI_BUS_TYPE + default BT_AMBIQ_HCI +endchoice + +config BT_BUF_ACL_TX_COUNT + default 14 + +config BT_BUF_CMD_TX_SIZE + default 255 + +config BT_BUF_EVT_RX_SIZE + default 255 + +config BT_BUF_ACL_TX_SIZE + default 251 + +config BT_BUF_ACL_RX_SIZE + default 251 + +# L2CAP SDU/PDU TX MTU +# BT_L2CAP_RX_MTU = CONFIG_BT_BUF_ACL_RX_SIZE - BT_L2CAP_HDR_SIZE +config BT_L2CAP_TX_MTU + default 247 + +endif # BT diff --git a/boards/arm/apollo4p_blue_kxr_evb/apollo4p_blue_kxr_evb.dts b/boards/arm/apollo4p_blue_kxr_evb/apollo4p_blue_kxr_evb.dts index 4f698df2b78..e14a8bd3372 100644 --- a/boards/arm/apollo4p_blue_kxr_evb/apollo4p_blue_kxr_evb.dts +++ b/boards/arm/apollo4p_blue_kxr_evb/apollo4p_blue_kxr_evb.dts @@ -86,6 +86,23 @@ status = "okay"; }; +&iom4 { + compatible = "ambiq,spi"; + pinctrl-0 = <&spi4_default>; + pinctrl-names = "default"; + cs-gpios = <&gpio32_63 22 (GPIO_ACTIVE_LOW | GPIO_PULL_UP)>; + clock-frequency = ; + status = "okay"; + + bt-hci@0 { + compatible = "ambiq,bt-hci-spi"; + reg = <0>; + irq-gpios = <&gpio32_63 21 GPIO_ACTIVE_HIGH>; + reset-gpios = <&gpio32_63 23 GPIO_ACTIVE_LOW>; + clkreq-gpios = <&gpio32_63 20 GPIO_ACTIVE_HIGH>; + }; +}; + &mspi0 { pinctrl-0 = <&mspi0_default>; pinctrl-names = "default"; From 9a642caebbc7c516f3b6f07fa74b35c981e85fef Mon Sep 17 00:00:00 2001 From: Aaron Ye Date: Wed, 13 Dec 2023 20:41:57 +0800 Subject: [PATCH 1370/3723] west.yml: hal_ambiq: Add Bluetooth support. Imported the original Cooper (Apollo4x BLE controller) device files from AmbiqSuite SDK 4.4.0 and adapts them to support the new implemented HCI driver for Apollo4 Blue Plus. Signed-off-by: Aaron Ye --- west.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/west.yml b/west.yml index 9740133cea0..4cfffb58c91 100644 --- a/west.yml +++ b/west.yml @@ -142,7 +142,7 @@ manifest: groups: - hal - name: hal_ambiq - revision: 0c5ea5749245c8ff6ce7aefbf0aa9981943c2857 + revision: 323048f916faa84cebcf6dfd73e606d8cf64107a path: modules/hal/ambiq groups: - hal From eb006b992fc42f9304d32d042f47b5428a86a091 Mon Sep 17 00:00:00 2001 From: Murlidhar Roy Date: Tue, 17 Oct 2023 14:41:17 +0800 Subject: [PATCH 1371/3723] drivers: sdhc: add cdns sdhc/combophy driver files Add SDHC driver files with new SD framework changes SDHC driver includes combophy configurations. Added mmc binding yaml file Signed-off-by: Murlidhar Roy --- drivers/sdhc/CMakeLists.txt | 1 + drivers/sdhc/Kconfig | 1 + drivers/sdhc/Kconfig.sdhc_cdns | 26 + drivers/sdhc/sdhc_cdns.c | 301 ++++++++++ drivers/sdhc/sdhc_cdns/sdhc_cdns.c | 301 ++++++++++ drivers/sdhc/sdhc_cdns/sdhc_cdns_ll.c | 791 ++++++++++++++++++++++++++ drivers/sdhc/sdhc_cdns/sdhc_cdns_ll.h | 489 ++++++++++++++++ drivers/sdhc/sdhc_cdns_ll.c | 791 ++++++++++++++++++++++++++ drivers/sdhc/sdhc_cdns_ll.h | 489 ++++++++++++++++ dts/bindings/sdhc/cdns,sdhc.yaml | 20 + 10 files changed, 3210 insertions(+) create mode 100644 drivers/sdhc/Kconfig.sdhc_cdns create mode 100644 drivers/sdhc/sdhc_cdns.c create mode 100644 drivers/sdhc/sdhc_cdns/sdhc_cdns.c create mode 100644 drivers/sdhc/sdhc_cdns/sdhc_cdns_ll.c create mode 100644 drivers/sdhc/sdhc_cdns/sdhc_cdns_ll.h create mode 100644 drivers/sdhc/sdhc_cdns_ll.c create mode 100644 drivers/sdhc/sdhc_cdns_ll.h create mode 100644 dts/bindings/sdhc/cdns,sdhc.yaml diff --git a/drivers/sdhc/CMakeLists.txt b/drivers/sdhc/CMakeLists.txt index 431867fb2b8..2675589bfc9 100644 --- a/drivers/sdhc/CMakeLists.txt +++ b/drivers/sdhc/CMakeLists.txt @@ -9,4 +9,5 @@ zephyr_library_sources_ifdef(CONFIG_MCUX_SDIF mcux_sdif.c) zephyr_library_sources_ifdef(CONFIG_SAM_HSMCI sam_hsmci.c) zephyr_library_sources_ifdef(CONFIG_INTEL_EMMC_HOST intel_emmc_host.c) zephyr_library_sources_ifdef(CONFIG_SDHC_INFINEON_CAT1 ifx_cat1_sdio.c) +zephyr_library_sources_ifdef(CONFIG_CDNS_SDHC sdhc_cdns_ll.c sdhc_cdns.c) endif() diff --git a/drivers/sdhc/Kconfig b/drivers/sdhc/Kconfig index 7e75e03a024..13b63cfcc9c 100644 --- a/drivers/sdhc/Kconfig +++ b/drivers/sdhc/Kconfig @@ -14,6 +14,7 @@ source "drivers/sdhc/Kconfig.spi" source "drivers/sdhc/Kconfig.mcux_sdif" source "drivers/sdhc/Kconfig.sam_hsmci" source "drivers/sdhc/Kconfig.intel" +source "drivers/sdhc/Kconfig.sdhc_cdns" config SDHC_INIT_PRIORITY int "SDHC driver init priority" diff --git a/drivers/sdhc/Kconfig.sdhc_cdns b/drivers/sdhc/Kconfig.sdhc_cdns new file mode 100644 index 00000000000..3558763fbf4 --- /dev/null +++ b/drivers/sdhc/Kconfig.sdhc_cdns @@ -0,0 +1,26 @@ +# Copyright (c) 2023 Intel Corporation +# SPDX-License-Identifier: Apache-2.0 + +config CDNS_SDHC + bool "CDNS SDHC" + default y + depends on DT_HAS_CDNS_SDHC_ENABLED + select SDHC_SUPPORTS_NATIVE_MODE + help + Enable Cadence SDMMC Host Controller. + +if CDNS_SDHC + +# Cadence SDHC DMA needs 64 bit aligned buffers +config SDHC_BUFFER_ALIGNMENT + default 8 + +config CDNS_DESC_COUNT + int "Allocate number of descriptors" + default 8 + help + SD host controllers require DMA preparation for read and write operation. + Creates static descriptors which can be used by ADMA. Devices should + configure this flag if they require to transfer more than 8*64Kb of data. + +endif # CDNS_SDHC diff --git a/drivers/sdhc/sdhc_cdns.c b/drivers/sdhc/sdhc_cdns.c new file mode 100644 index 00000000000..a2a071d8760 --- /dev/null +++ b/drivers/sdhc/sdhc_cdns.c @@ -0,0 +1,301 @@ +/* + * Copyright (C) 2023 Intel Corporation + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#define DT_DRV_COMPAT cdns_sdhc + +#include +#include +#include +#include + +#include "sdhc_cdns_ll.h" + +#define SDHC_CDNS_DESC_SIZE (1<<20) +#define COMBOPHY_ADDR_MASK 0x0000FFFFU + +#define DEV_CFG(_dev) ((const struct sdhc_cdns_config *)(_dev)->config) +#define DEV_DATA(_dev) ((struct sdhc_cdns_data *const)(_dev)->data) + +LOG_MODULE_REGISTER(sdhc_cdns, CONFIG_SDHC_LOG_LEVEL); + +/* SDMMC operations FPs are the element of structure*/ +static const struct sdhc_cdns_ops *cdns_sdmmc_ops; + +struct sdhc_cdns_config { + DEVICE_MMIO_NAMED_ROM(reg_base); + DEVICE_MMIO_NAMED_ROM(combo_phy); + /* Clock rate for host */ + uint32_t clk_rate; + /* power delay prop for host */ + uint32_t power_delay_ms; + /* run time device structure */ + const struct device *cdns_clk_dev; + /* type to identify a clock controller sub-system */ + clock_control_subsys_t clkid; + /* Reset controller device configuration. */ + const struct reset_dt_spec reset_sdmmc; + const struct reset_dt_spec reset_sdmmcocp; + const struct reset_dt_spec reset_softphy; +}; + +struct sdhc_cdns_data { + DEVICE_MMIO_NAMED_RAM(reg_base); + DEVICE_MMIO_NAMED_RAM(combo_phy); + /* Host controller parameters */ + struct sdhc_cdns_params params; + /* sdmmc device informartaion for host */ + struct sdmmc_device_info info; + /* Input/Output configuration */ + struct sdhc_io host_io; +}; + +static int sdhc_cdns_request(const struct device *dev, + struct sdhc_command *cmd, + struct sdhc_data *data) +{ + int ret = 0; + struct sdmmc_cmd cdns_sdmmc_cmd; + + if (cmd == NULL) { + LOG_ERR("Wrong CMD parameter"); + return -EINVAL; + } + + /* Initialization of command structure */ + cdns_sdmmc_cmd.cmd_idx = cmd->opcode; + cdns_sdmmc_cmd.cmd_arg = cmd->arg; + cdns_sdmmc_cmd.resp_type = (cmd->response_type & SDHC_NATIVE_RESPONSE_MASK); + + /* Sending command as per the data or non data */ + if (data) { + ret = cdns_sdmmc_ops->prepare(data->block_addr, (uintptr_t)data->data, + data); + if (ret != 0) { + LOG_ERR("DMA Prepare failed"); + return -EINVAL; + } + } + + ret = cdns_sdmmc_ops->send_cmd(&cdns_sdmmc_cmd, data); + + if (ret == 0) { + if (cmd->opcode == SD_READ_SINGLE_BLOCK || cmd->opcode == SD_APP_SEND_SCR || + cmd->opcode == SD_READ_MULTIPLE_BLOCK) { + + if (data == NULL) { + LOG_ERR("Invalid data parameter"); + return -ENODATA; + } + ret = cdns_sdmmc_ops->cache_invd(data->block_addr, (uintptr_t)data->data, + data->block_size); + if (ret != 0) { + return ret; + } + } + } + /* copying all responses as per response type */ + for (int i = 0; i < 4; i++) { + cmd->response[i] = cdns_sdmmc_cmd.resp_data[i]; + } + return ret; +} + +static int sdhc_cdns_get_card_present(const struct device *dev) +{ + return cdns_sdmmc_ops->card_present(); +} + +static int sdhc_cdns_card_busy(const struct device *dev) +{ + return cdns_sdmmc_ops->busy(); +} + +static int sdhc_cdns_get_host_props(const struct device *dev, + struct sdhc_host_props *props) +{ + const struct sdhc_cdns_config *sdhc_config = DEV_CFG(dev); + + memset(props, 0, sizeof(struct sdhc_host_props)); + props->f_min = SDMMC_CLOCK_400KHZ; + /* + * default max speed is 25MHZ, as per SCR register + * it will switch accordingly + */ + props->f_max = SD_CLOCK_25MHZ; + props->power_delay = sdhc_config->power_delay_ms; + props->host_caps.vol_330_support = true; + props->is_spi = false; + return 0; +} + +static int sdhc_cdns_reset(const struct device *dev) +{ + return cdns_sdmmc_ops->reset(); +} + +static int sdhc_cdns_init(const struct device *dev) +{ + struct sdhc_cdns_data *const data = DEV_DATA(dev); + const struct sdhc_cdns_config *sdhc_config = DEV_CFG(dev); + int ret; + + /* SDHC reg base */ + DEVICE_MMIO_NAMED_MAP(dev, reg_base, K_MEM_CACHE_NONE); + /* ComboPhy reg base */ + DEVICE_MMIO_NAMED_MAP(dev, combo_phy, K_MEM_CACHE_NONE); + + /* clock setting */ + if (sdhc_config->clk_rate == 0U) { + if (!device_is_ready(sdhc_config->cdns_clk_dev)) { + LOG_ERR("Clock controller device is not ready"); + return -EINVAL; + } + + ret = clock_control_get_rate(sdhc_config->cdns_clk_dev, + sdhc_config->clkid, &data->params.clk_rate); + + if (ret != 0) { + return ret; + } + } else { + data->params.clk_rate = sdhc_config->clk_rate; + } + + /* Setting regbase */ + data->params.reg_base = DEVICE_MMIO_NAMED_GET(dev, reg_base); + data->params.reg_phy = DEVICE_MMIO_NAMED_GET(dev, combo_phy); + data->params.combophy = (DEVICE_MMIO_NAMED_ROM_PTR((dev), + combo_phy)->phys_addr); + data->params.combophy = (data->params.combophy & COMBOPHY_ADDR_MASK); + + /* resetting the lines */ + if (sdhc_config->reset_sdmmc.dev != NULL) { + if (!device_is_ready(sdhc_config->reset_sdmmc.dev) || + !device_is_ready(sdhc_config->reset_sdmmcocp.dev) || + !device_is_ready(sdhc_config->reset_softphy.dev)) { + LOG_ERR("Reset device not found"); + return -ENODEV; + } + + ret = reset_line_toggle(sdhc_config->reset_softphy.dev, + sdhc_config->reset_softphy.id); + if (ret != 0) { + LOG_ERR("Softphy Reset failed"); + return ret; + } + + ret = reset_line_toggle(sdhc_config->reset_sdmmc.dev, + sdhc_config->reset_sdmmc.id); + if (ret != 0) { + LOG_ERR("sdmmc Reset failed"); + return ret; + } + + ret = reset_line_toggle(sdhc_config->reset_sdmmcocp.dev, + sdhc_config->reset_sdmmcocp.id); + if (ret != 0) { + LOG_ERR("sdmmcocp Reset failed"); + return ret; + } + } + + /* Init function to call lower layer file */ + sdhc_cdns_sdmmc_init(&data->params, &data->info, &cdns_sdmmc_ops); + + ret = sdhc_cdns_reset(dev); + if (ret != 0U) { + LOG_ERR("Card reset failed"); + return ret; + } + + /* Init operation called for register initialisation */ + ret = cdns_sdmmc_ops->init(); + if (ret != 0U) { + LOG_ERR("Card initialization failed"); + return ret; + } + + return 0; +} + +static int sdhc_cdns_set_io(const struct device *dev, struct sdhc_io *ios) +{ + struct sdhc_cdns_data *data = dev->data; + struct sdhc_io *host_io = &data->host_io; + + if (host_io->bus_width != ios->bus_width || host_io->clock != + ios->clock) { + host_io->bus_width = ios->bus_width; + host_io->clock = ios->clock; + return cdns_sdmmc_ops->set_ios(ios->clock, ios->bus_width); + } + return 0; +} + +static struct sdhc_driver_api sdhc_cdns_api = { + .request = sdhc_cdns_request, + .set_io = sdhc_cdns_set_io, + .get_host_props = sdhc_cdns_get_host_props, + .get_card_present = sdhc_cdns_get_card_present, + .reset = sdhc_cdns_reset, + .card_busy = sdhc_cdns_card_busy, +}; + +#define SDHC_CDNS_CLOCK_RATE_INIT(inst) \ + COND_CODE_1(DT_INST_NODE_HAS_PROP(inst, clock_frequency), \ + ( \ + .clk_rate = DT_INST_PROP(inst, clock_frequency), \ + .cdns_clk_dev = NULL, \ + .clkid = (clock_control_subsys_t)0, \ + ), \ + ( \ + .clk_rate = 0, \ + .cdns_clk_dev = DEVICE_DT_GET(DT_INST_CLOCKS_CTLR(inst)), \ + .clkid = (clock_control_subsys_t)DT_INST_CLOCKS_CELL(inst, clkid), \ + ) \ + ) + +#define SDHC_CDNS_RESET_SPEC_INIT(inst) \ + .reset_sdmmc = RESET_DT_SPEC_INST_GET_BY_IDX(inst, 0), \ + .reset_sdmmcocp = RESET_DT_SPEC_INST_GET_BY_IDX(inst, 1),\ + .reset_softphy = RESET_DT_SPEC_INST_GET_BY_IDX(inst, 2), + +#define SDHC_CDNS_INIT(inst) \ + static struct sdhc_cdns_desc cdns_desc \ + [CONFIG_CDNS_DESC_COUNT]; \ + \ + static const struct sdhc_cdns_config sdhc_cdns_config_##inst = {\ + DEVICE_MMIO_NAMED_ROM_INIT_BY_NAME( \ + reg_base, DT_DRV_INST(inst)), \ + DEVICE_MMIO_NAMED_ROM_INIT_BY_NAME( \ + combo_phy, DT_DRV_INST(inst)), \ + SDHC_CDNS_CLOCK_RATE_INIT(inst) \ + IF_ENABLED(DT_INST_NODE_HAS_PROP(inst, resets), \ + (SDHC_CDNS_RESET_SPEC_INIT(inst))) \ + .power_delay_ms = DT_INST_PROP(inst, power_delay_ms), \ + }; \ + static struct sdhc_cdns_data sdhc_cdns_data_##inst = { \ + .params = { \ + .bus_width = SDHC_BUS_WIDTH1BIT, \ + .desc_base = (uintptr_t) &cdns_desc, \ + .desc_size = SDHC_CDNS_DESC_SIZE, \ + .flags = 0, \ + }, \ + .info = { \ + .cdn_sdmmc_dev_type = SD_DS, \ + .ocr_voltage = OCR_3_3_3_4 | OCR_3_2_3_3, \ + }, \ + }; \ + DEVICE_DT_INST_DEFINE(inst, \ + &sdhc_cdns_init, \ + NULL, \ + &sdhc_cdns_data_##inst, \ + &sdhc_cdns_config_##inst, \ + POST_KERNEL, \ + CONFIG_SDHC_INIT_PRIORITY, \ + &sdhc_cdns_api); + +DT_INST_FOREACH_STATUS_OKAY(SDHC_CDNS_INIT) diff --git a/drivers/sdhc/sdhc_cdns/sdhc_cdns.c b/drivers/sdhc/sdhc_cdns/sdhc_cdns.c new file mode 100644 index 00000000000..a2a071d8760 --- /dev/null +++ b/drivers/sdhc/sdhc_cdns/sdhc_cdns.c @@ -0,0 +1,301 @@ +/* + * Copyright (C) 2023 Intel Corporation + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#define DT_DRV_COMPAT cdns_sdhc + +#include +#include +#include +#include + +#include "sdhc_cdns_ll.h" + +#define SDHC_CDNS_DESC_SIZE (1<<20) +#define COMBOPHY_ADDR_MASK 0x0000FFFFU + +#define DEV_CFG(_dev) ((const struct sdhc_cdns_config *)(_dev)->config) +#define DEV_DATA(_dev) ((struct sdhc_cdns_data *const)(_dev)->data) + +LOG_MODULE_REGISTER(sdhc_cdns, CONFIG_SDHC_LOG_LEVEL); + +/* SDMMC operations FPs are the element of structure*/ +static const struct sdhc_cdns_ops *cdns_sdmmc_ops; + +struct sdhc_cdns_config { + DEVICE_MMIO_NAMED_ROM(reg_base); + DEVICE_MMIO_NAMED_ROM(combo_phy); + /* Clock rate for host */ + uint32_t clk_rate; + /* power delay prop for host */ + uint32_t power_delay_ms; + /* run time device structure */ + const struct device *cdns_clk_dev; + /* type to identify a clock controller sub-system */ + clock_control_subsys_t clkid; + /* Reset controller device configuration. */ + const struct reset_dt_spec reset_sdmmc; + const struct reset_dt_spec reset_sdmmcocp; + const struct reset_dt_spec reset_softphy; +}; + +struct sdhc_cdns_data { + DEVICE_MMIO_NAMED_RAM(reg_base); + DEVICE_MMIO_NAMED_RAM(combo_phy); + /* Host controller parameters */ + struct sdhc_cdns_params params; + /* sdmmc device informartaion for host */ + struct sdmmc_device_info info; + /* Input/Output configuration */ + struct sdhc_io host_io; +}; + +static int sdhc_cdns_request(const struct device *dev, + struct sdhc_command *cmd, + struct sdhc_data *data) +{ + int ret = 0; + struct sdmmc_cmd cdns_sdmmc_cmd; + + if (cmd == NULL) { + LOG_ERR("Wrong CMD parameter"); + return -EINVAL; + } + + /* Initialization of command structure */ + cdns_sdmmc_cmd.cmd_idx = cmd->opcode; + cdns_sdmmc_cmd.cmd_arg = cmd->arg; + cdns_sdmmc_cmd.resp_type = (cmd->response_type & SDHC_NATIVE_RESPONSE_MASK); + + /* Sending command as per the data or non data */ + if (data) { + ret = cdns_sdmmc_ops->prepare(data->block_addr, (uintptr_t)data->data, + data); + if (ret != 0) { + LOG_ERR("DMA Prepare failed"); + return -EINVAL; + } + } + + ret = cdns_sdmmc_ops->send_cmd(&cdns_sdmmc_cmd, data); + + if (ret == 0) { + if (cmd->opcode == SD_READ_SINGLE_BLOCK || cmd->opcode == SD_APP_SEND_SCR || + cmd->opcode == SD_READ_MULTIPLE_BLOCK) { + + if (data == NULL) { + LOG_ERR("Invalid data parameter"); + return -ENODATA; + } + ret = cdns_sdmmc_ops->cache_invd(data->block_addr, (uintptr_t)data->data, + data->block_size); + if (ret != 0) { + return ret; + } + } + } + /* copying all responses as per response type */ + for (int i = 0; i < 4; i++) { + cmd->response[i] = cdns_sdmmc_cmd.resp_data[i]; + } + return ret; +} + +static int sdhc_cdns_get_card_present(const struct device *dev) +{ + return cdns_sdmmc_ops->card_present(); +} + +static int sdhc_cdns_card_busy(const struct device *dev) +{ + return cdns_sdmmc_ops->busy(); +} + +static int sdhc_cdns_get_host_props(const struct device *dev, + struct sdhc_host_props *props) +{ + const struct sdhc_cdns_config *sdhc_config = DEV_CFG(dev); + + memset(props, 0, sizeof(struct sdhc_host_props)); + props->f_min = SDMMC_CLOCK_400KHZ; + /* + * default max speed is 25MHZ, as per SCR register + * it will switch accordingly + */ + props->f_max = SD_CLOCK_25MHZ; + props->power_delay = sdhc_config->power_delay_ms; + props->host_caps.vol_330_support = true; + props->is_spi = false; + return 0; +} + +static int sdhc_cdns_reset(const struct device *dev) +{ + return cdns_sdmmc_ops->reset(); +} + +static int sdhc_cdns_init(const struct device *dev) +{ + struct sdhc_cdns_data *const data = DEV_DATA(dev); + const struct sdhc_cdns_config *sdhc_config = DEV_CFG(dev); + int ret; + + /* SDHC reg base */ + DEVICE_MMIO_NAMED_MAP(dev, reg_base, K_MEM_CACHE_NONE); + /* ComboPhy reg base */ + DEVICE_MMIO_NAMED_MAP(dev, combo_phy, K_MEM_CACHE_NONE); + + /* clock setting */ + if (sdhc_config->clk_rate == 0U) { + if (!device_is_ready(sdhc_config->cdns_clk_dev)) { + LOG_ERR("Clock controller device is not ready"); + return -EINVAL; + } + + ret = clock_control_get_rate(sdhc_config->cdns_clk_dev, + sdhc_config->clkid, &data->params.clk_rate); + + if (ret != 0) { + return ret; + } + } else { + data->params.clk_rate = sdhc_config->clk_rate; + } + + /* Setting regbase */ + data->params.reg_base = DEVICE_MMIO_NAMED_GET(dev, reg_base); + data->params.reg_phy = DEVICE_MMIO_NAMED_GET(dev, combo_phy); + data->params.combophy = (DEVICE_MMIO_NAMED_ROM_PTR((dev), + combo_phy)->phys_addr); + data->params.combophy = (data->params.combophy & COMBOPHY_ADDR_MASK); + + /* resetting the lines */ + if (sdhc_config->reset_sdmmc.dev != NULL) { + if (!device_is_ready(sdhc_config->reset_sdmmc.dev) || + !device_is_ready(sdhc_config->reset_sdmmcocp.dev) || + !device_is_ready(sdhc_config->reset_softphy.dev)) { + LOG_ERR("Reset device not found"); + return -ENODEV; + } + + ret = reset_line_toggle(sdhc_config->reset_softphy.dev, + sdhc_config->reset_softphy.id); + if (ret != 0) { + LOG_ERR("Softphy Reset failed"); + return ret; + } + + ret = reset_line_toggle(sdhc_config->reset_sdmmc.dev, + sdhc_config->reset_sdmmc.id); + if (ret != 0) { + LOG_ERR("sdmmc Reset failed"); + return ret; + } + + ret = reset_line_toggle(sdhc_config->reset_sdmmcocp.dev, + sdhc_config->reset_sdmmcocp.id); + if (ret != 0) { + LOG_ERR("sdmmcocp Reset failed"); + return ret; + } + } + + /* Init function to call lower layer file */ + sdhc_cdns_sdmmc_init(&data->params, &data->info, &cdns_sdmmc_ops); + + ret = sdhc_cdns_reset(dev); + if (ret != 0U) { + LOG_ERR("Card reset failed"); + return ret; + } + + /* Init operation called for register initialisation */ + ret = cdns_sdmmc_ops->init(); + if (ret != 0U) { + LOG_ERR("Card initialization failed"); + return ret; + } + + return 0; +} + +static int sdhc_cdns_set_io(const struct device *dev, struct sdhc_io *ios) +{ + struct sdhc_cdns_data *data = dev->data; + struct sdhc_io *host_io = &data->host_io; + + if (host_io->bus_width != ios->bus_width || host_io->clock != + ios->clock) { + host_io->bus_width = ios->bus_width; + host_io->clock = ios->clock; + return cdns_sdmmc_ops->set_ios(ios->clock, ios->bus_width); + } + return 0; +} + +static struct sdhc_driver_api sdhc_cdns_api = { + .request = sdhc_cdns_request, + .set_io = sdhc_cdns_set_io, + .get_host_props = sdhc_cdns_get_host_props, + .get_card_present = sdhc_cdns_get_card_present, + .reset = sdhc_cdns_reset, + .card_busy = sdhc_cdns_card_busy, +}; + +#define SDHC_CDNS_CLOCK_RATE_INIT(inst) \ + COND_CODE_1(DT_INST_NODE_HAS_PROP(inst, clock_frequency), \ + ( \ + .clk_rate = DT_INST_PROP(inst, clock_frequency), \ + .cdns_clk_dev = NULL, \ + .clkid = (clock_control_subsys_t)0, \ + ), \ + ( \ + .clk_rate = 0, \ + .cdns_clk_dev = DEVICE_DT_GET(DT_INST_CLOCKS_CTLR(inst)), \ + .clkid = (clock_control_subsys_t)DT_INST_CLOCKS_CELL(inst, clkid), \ + ) \ + ) + +#define SDHC_CDNS_RESET_SPEC_INIT(inst) \ + .reset_sdmmc = RESET_DT_SPEC_INST_GET_BY_IDX(inst, 0), \ + .reset_sdmmcocp = RESET_DT_SPEC_INST_GET_BY_IDX(inst, 1),\ + .reset_softphy = RESET_DT_SPEC_INST_GET_BY_IDX(inst, 2), + +#define SDHC_CDNS_INIT(inst) \ + static struct sdhc_cdns_desc cdns_desc \ + [CONFIG_CDNS_DESC_COUNT]; \ + \ + static const struct sdhc_cdns_config sdhc_cdns_config_##inst = {\ + DEVICE_MMIO_NAMED_ROM_INIT_BY_NAME( \ + reg_base, DT_DRV_INST(inst)), \ + DEVICE_MMIO_NAMED_ROM_INIT_BY_NAME( \ + combo_phy, DT_DRV_INST(inst)), \ + SDHC_CDNS_CLOCK_RATE_INIT(inst) \ + IF_ENABLED(DT_INST_NODE_HAS_PROP(inst, resets), \ + (SDHC_CDNS_RESET_SPEC_INIT(inst))) \ + .power_delay_ms = DT_INST_PROP(inst, power_delay_ms), \ + }; \ + static struct sdhc_cdns_data sdhc_cdns_data_##inst = { \ + .params = { \ + .bus_width = SDHC_BUS_WIDTH1BIT, \ + .desc_base = (uintptr_t) &cdns_desc, \ + .desc_size = SDHC_CDNS_DESC_SIZE, \ + .flags = 0, \ + }, \ + .info = { \ + .cdn_sdmmc_dev_type = SD_DS, \ + .ocr_voltage = OCR_3_3_3_4 | OCR_3_2_3_3, \ + }, \ + }; \ + DEVICE_DT_INST_DEFINE(inst, \ + &sdhc_cdns_init, \ + NULL, \ + &sdhc_cdns_data_##inst, \ + &sdhc_cdns_config_##inst, \ + POST_KERNEL, \ + CONFIG_SDHC_INIT_PRIORITY, \ + &sdhc_cdns_api); + +DT_INST_FOREACH_STATUS_OKAY(SDHC_CDNS_INIT) diff --git a/drivers/sdhc/sdhc_cdns/sdhc_cdns_ll.c b/drivers/sdhc/sdhc_cdns/sdhc_cdns_ll.c new file mode 100644 index 00000000000..3d8e3f97e4a --- /dev/null +++ b/drivers/sdhc/sdhc_cdns/sdhc_cdns_ll.c @@ -0,0 +1,791 @@ +/* + * Copyright (C) 2023 Intel Corporation + * SPDX-License-Identifier: Apache-2.0 + */ + +#include +#include "sdhc_cdns_ll.h" +#include + +LOG_MODULE_REGISTER(sdhc_cdns_ll, CONFIG_SDHC_LOG_LEVEL); + +/* card busy and present */ +#define CARD_BUSY 1 +#define CARD_NOT_BUSY 0 +#define CARD_PRESENT 1 + +/* SRS12 error mask */ +#define CDNS_SRS12_ERR_MASK 0xFFFF8000U +#define CDNS_CSD_BYTE_MASK 0x000000FFU + +/* General define */ +#define SDHC_REG_MASK 0xFFFFFFFFU +#define SD_HOST_BLOCK_SIZE 0x200 + +#define SDMMC_DMA_MAX_BUFFER_SIZE (64 * 1024) +#define CDNSMMC_ADDRESS_MASK (CONFIG_SDHC_BUFFER_ALIGNMENT - 1) + +#define SRS10_VAL_READ (ADMA2_32 | HS_EN | DT_WIDTH) +#define SRS10_VAL_SW (ADMA2_32 | DT_WIDTH) +#define SRS11_VAL_GEN (READ_CLK | CDNS_SRS11_ICE | CDNS_SRS11_ICS | CDNS_SRS11_SDCE) +#define SRS11_VAL_CID (CDNS_SRS11_ICE | CDNS_SRS11_ICS | CDNS_SRS11_SDCE) +#define SRS15_VAL_GEN (CDNS_SRS15_BIT_AD_64 | CDNS_SRS15_HV4E | CDNS_SRS15_V18SE) +#define SRS15_VAL_RD_WR (SRS15_VAL_GEN | CDNS_SRS15_SDR104 | CDNS_SRS15_PVE) +#define SRS15_VAL_CID (CDNS_SRS15_HV4E | CDNS_SRS15_V18SE) + +#define CARD_REG_TIME_DELAY_US 100000 +#define WAIT_ICS_TIME_DELAY_US 5000 +#define RESET_SRS14 0x00000000 + +static struct sdhc_cdns_params cdns_params; +static struct sdhc_cdns_combo_phy sdhc_cdns_combo_phy_reg_info; +static struct sdhc_cdns_sdmmc sdhc_cdns_sdmmc_reg_info; + +/* Function to write general phy registers */ +static int sdhc_cdns_write_phy_reg(uint32_t phy_reg_addr, uint32_t phy_reg_addr_value, + uint32_t phy_reg_data, uint32_t phy_reg_data_value) +{ + uint32_t data = 0; + + /* Set PHY register address, write HRS04*/ + sys_write32(phy_reg_addr_value, phy_reg_addr); + + /* Set PHY register data, write HRS05 */ + sys_write32(phy_reg_data_value, phy_reg_data); + data = sys_read32(phy_reg_data); + + if (data != phy_reg_data_value) { + LOG_ERR("PHY_REG_DATA is not set properly"); + return -ENXIO; + } + + return 0; +} + +int sdhc_cdns_wait_ics(uint16_t timeout, uint32_t cdn_srs_res) +{ + /* Wait status command response ready */ + if (!WAIT_FOR(((sys_read32(cdn_srs_res) & CDNS_SRS11_ICS) + == CDNS_SRS11_ICS), timeout, k_msleep(1))) { + LOG_ERR("Timed out waiting for ICS response"); + return -ETIMEDOUT; + } + + return 0; +} + +static int sdhc_cdns_busy(void) +{ + unsigned int data; + + data = sys_read32(cdns_params.reg_base + SDHC_CDNS_SRS09); + return (data & CDNS_SRS09_STAT_DAT_BUSY) ? CARD_BUSY : CARD_NOT_BUSY; +} + +static int sdhc_cdns_card_present(void) +{ + uint32_t timeout = CARD_REG_TIME_DELAY_US; + + if (!WAIT_FOR((((sys_read32(cdns_params.reg_base + SDHC_CDNS_SRS09)) + & CDNS_SRS09_CI) == CDNS_SRS09_CI), + timeout, k_msleep(1))) { + LOG_ERR("Card detection timeout"); + return -ETIMEDOUT; + } + + return CARD_PRESENT; +} + +static int sdhc_cdns_vol_reset(void) +{ + /* Reset embedded card */ + sys_write32((7 << CDNS_SRS10_BVS) | (0 << CDNS_SRS10_BP), + (cdns_params.reg_base + SDHC_CDNS_SRS10)); + + /* + * Turn on supply voltage + * CDNS_SRS10_BVS = 7, CDNS_SRS10_BP = 1, BP2 only in UHS2 mode + */ + sys_write32((7 << CDNS_SRS10_BVS) | (1 << CDNS_SRS10_BP), + (cdns_params.reg_base + SDHC_CDNS_SRS10)); + + return 0; +} + +/* + * Values are taken from IP documents and calc_setting.py script + * with input value- mode sd_ds, + * sdmclk 5000, + * sdclk 10000, + * iocell_input_delay 2500, + * iocell_output_delay 2500 and + * delay_element 24 + */ +void cdns_sdhc_set_sdmmc_params(struct sdhc_cdns_combo_phy *sdhc_cdns_combo_phy_reg, + struct sdhc_cdns_sdmmc *sdhc_cdns_sdmmc_reg) +{ + /* Values are taken by the reference of cadence IP documents */ + sdhc_cdns_combo_phy_reg->cp_clk_wr_delay = 0; + sdhc_cdns_combo_phy_reg->cp_clk_wrdqs_delay = 0; + sdhc_cdns_combo_phy_reg->cp_data_select_oe_end = 1; + sdhc_cdns_combo_phy_reg->cp_dll_bypass_mode = 1; + sdhc_cdns_combo_phy_reg->cp_dll_locked_mode = 3; + sdhc_cdns_combo_phy_reg->cp_dll_start_point = 4; + sdhc_cdns_combo_phy_reg->cp_gate_cfg_always_on = 1; + sdhc_cdns_combo_phy_reg->cp_io_mask_always_on = 0; + sdhc_cdns_combo_phy_reg->cp_io_mask_end = 2; + sdhc_cdns_combo_phy_reg->cp_io_mask_start = 0; + sdhc_cdns_combo_phy_reg->cp_rd_del_sel = 52; + sdhc_cdns_combo_phy_reg->cp_read_dqs_cmd_delay = 0; + sdhc_cdns_combo_phy_reg->cp_read_dqs_delay = 0; + sdhc_cdns_combo_phy_reg->cp_sw_half_cycle_shift = 0; + sdhc_cdns_combo_phy_reg->cp_sync_method = 1; + sdhc_cdns_combo_phy_reg->cp_underrun_suppress = 1; + sdhc_cdns_combo_phy_reg->cp_use_ext_lpbk_dqs = 1; + sdhc_cdns_combo_phy_reg->cp_use_lpbk_dqs = 1; + sdhc_cdns_combo_phy_reg->cp_use_phony_dqs = 1; + sdhc_cdns_combo_phy_reg->cp_use_phony_dqs_cmd = 1; + + sdhc_cdns_sdmmc_reg->sdhc_extended_rd_mode = 1; + sdhc_cdns_sdmmc_reg->sdhc_extended_wr_mode = 1; + sdhc_cdns_sdmmc_reg->sdhc_hcsdclkadj = 6; + sdhc_cdns_sdmmc_reg->sdhc_idelay_val = 1; + sdhc_cdns_sdmmc_reg->sdhc_rdcmd_en = 1; + sdhc_cdns_sdmmc_reg->sdhc_rddata_en = 1; + sdhc_cdns_sdmmc_reg->sdhc_rw_compensate = 10; + sdhc_cdns_sdmmc_reg->sdhc_sdcfsh = 0; + sdhc_cdns_sdmmc_reg->sdhc_sdcfsl = 1; + sdhc_cdns_sdmmc_reg->sdhc_wrcmd0_dly = 1; + sdhc_cdns_sdmmc_reg->sdhc_wrcmd0_sdclk_dly = 0; + sdhc_cdns_sdmmc_reg->sdhc_wrcmd1_dly = 0; + sdhc_cdns_sdmmc_reg->sdhc_wrcmd1_sdclk_dly = 0; + sdhc_cdns_sdmmc_reg->sdhc_wrdata0_dly = 1; + sdhc_cdns_sdmmc_reg->sdhc_wrdata0_sdclk_dly = 0; + sdhc_cdns_sdmmc_reg->sdhc_wrdata1_dly = 0; + sdhc_cdns_sdmmc_reg->sdhc_wrdata1_sdclk_dly = 0; +} + +/* Phy register programing for phy init */ +static int sdhc_cdns_program_phy_reg(struct sdhc_cdns_combo_phy *sdhc_cdns_combo_phy_reg, + struct sdhc_cdns_sdmmc *sdhc_cdns_sdmmc_reg) +{ + uint32_t value = 0; + int ret = 0; + + /* + * program PHY_DQS_TIMING_REG + * This register controls the DQS related timing + */ + value = (CP_USE_EXT_LPBK_DQS(sdhc_cdns_combo_phy_reg->cp_use_ext_lpbk_dqs)) + | (CP_USE_LPBK_DQS(sdhc_cdns_combo_phy_reg->cp_use_lpbk_dqs)) + | (CP_USE_PHONY_DQS(sdhc_cdns_combo_phy_reg->cp_use_phony_dqs)) + | (CP_USE_PHONY_DQS_CMD(sdhc_cdns_combo_phy_reg->cp_use_phony_dqs_cmd)); + ret = sdhc_cdns_write_phy_reg(cdns_params.reg_base + SDHC_CDNS_HRS04, + cdns_params.combophy + PHY_DQS_TIMING_REG, cdns_params.reg_base + + SDHC_CDNS_HRS05, value); + if (ret != 0U) { + LOG_ERR("Error in PHY_DQS_TIMING_REG programming"); + return ret; + } + + /* + * program PHY_GATE_LPBK_CTRL_REG + * This register controls the gate and loopback control related timing. + */ + value = (CP_SYNC_METHOD(sdhc_cdns_combo_phy_reg->cp_sync_method)) + | (CP_SW_HALF_CYCLE_SHIFT(sdhc_cdns_combo_phy_reg->cp_sw_half_cycle_shift)) + | (CP_RD_DEL_SEL(sdhc_cdns_combo_phy_reg->cp_rd_del_sel)) + | (CP_UNDERRUN_SUPPRESS(sdhc_cdns_combo_phy_reg->cp_underrun_suppress)) + | (CP_GATE_CFG_ALWAYS_ON(sdhc_cdns_combo_phy_reg->cp_gate_cfg_always_on)); + ret = sdhc_cdns_write_phy_reg(cdns_params.reg_base + SDHC_CDNS_HRS04, + cdns_params.combophy + PHY_GATE_LPBK_CTRL_REG, cdns_params.reg_base + + SDHC_CDNS_HRS05, value); + if (ret != 0U) { + LOG_ERR("Error in PHY_GATE_LPBK_CTRL_REG programming"); + return -ret; + } + + /* + * program PHY_DLL_MASTER_CTRL_REG + * This register holds the control for the Master DLL logic. + */ + value = (CP_DLL_BYPASS_MODE(sdhc_cdns_combo_phy_reg->cp_dll_bypass_mode)) + | (CP_DLL_START_POINT(sdhc_cdns_combo_phy_reg->cp_dll_start_point)); + ret = sdhc_cdns_write_phy_reg(cdns_params.reg_base + SDHC_CDNS_HRS04, + cdns_params.combophy + PHY_DLL_MASTER_CTRL_REG, cdns_params.reg_base + + SDHC_CDNS_HRS05, value); + if (ret != 0U) { + LOG_ERR("Error in PHY_DLL_MASTER_CTRL_REG programming"); + return ret; + } + + /* + * program PHY_DLL_SLAVE_CTRL_REG + * This register holds the control for the slave DLL logic. + */ + value = (CP_READ_DQS_CMD_DELAY(sdhc_cdns_combo_phy_reg->cp_read_dqs_cmd_delay)) + | (CP_CLK_WRDQS_DELAY(sdhc_cdns_combo_phy_reg->cp_clk_wrdqs_delay)) + | (CP_CLK_WR_DELAY(sdhc_cdns_combo_phy_reg->cp_clk_wr_delay)) + | (CP_READ_DQS_DELAY(sdhc_cdns_combo_phy_reg->cp_read_dqs_delay)); + ret = sdhc_cdns_write_phy_reg(cdns_params.reg_base + SDHC_CDNS_HRS04, + cdns_params.combophy + PHY_DLL_SLAVE_CTRL_REG, cdns_params.reg_base + + SDHC_CDNS_HRS05, value); + if (ret != 0U) { + LOG_ERR("Error in PHY_DLL_SLAVE_CTRL_REG programming"); + return ret; + } + + /* + * program PHY_CTRL_REG + * This register handles the global control settings for the PHY. + */ + sys_write32(cdns_params.combophy + PHY_CTRL_REG, cdns_params.reg_base + + SDHC_CDNS_HRS04); + value = sys_read32(cdns_params.reg_base + SDHC_CDNS_HRS05); + + /* phony_dqs_timing=0 */ + value &= ~(CP_PHONY_DQS_TIMING_MASK << CP_PHONY_DQS_TIMING_SHIFT); + sys_write32(value, cdns_params.reg_base + SDHC_CDNS_HRS05); + + /* switch off DLL_RESET */ + do { + value = sys_read32(cdns_params.reg_base + SDHC_CDNS_HRS09); + value |= CDNS_HRS09_PHY_SW_RESET; + sys_write32(value, cdns_params.reg_base + SDHC_CDNS_HRS09); + value = sys_read32(cdns_params.reg_base + SDHC_CDNS_HRS09); + /* polling PHY_INIT_COMPLETE */ + } while ((value & CDNS_HRS09_PHY_INIT_COMP) != CDNS_HRS09_PHY_INIT_COMP); + + /* + * program PHY_DQ_TIMING_REG + * This register controls the DQ related timing. + */ + sdhc_cdns_combo_phy_reg->cp_io_mask_end = 0U; + value = (CP_IO_MASK_ALWAYS_ON(sdhc_cdns_combo_phy_reg->cp_io_mask_always_on)) + | (CP_IO_MASK_END(sdhc_cdns_combo_phy_reg->cp_io_mask_end)) + | (CP_IO_MASK_START(sdhc_cdns_combo_phy_reg->cp_io_mask_start)) + | (CP_DATA_SELECT_OE_END(sdhc_cdns_combo_phy_reg->cp_data_select_oe_end)); + + ret = sdhc_cdns_write_phy_reg(cdns_params.reg_base + SDHC_CDNS_HRS04, + cdns_params.combophy + PHY_DQ_TIMING_REG, cdns_params.reg_base + + SDHC_CDNS_HRS05, value); + if (ret != 0U) { + LOG_ERR("Error in PHY_DQ_TIMING_REG programming"); + return ret; + } + return 0; +} + +static int sdhc_cdns_cache_invd(int lba, uintptr_t buf, size_t size) +{ + int ret = 0; + + ret = arch_dcache_invd_range((void *)buf, size); + if (ret != 0) { + LOG_ERR("%s: error in invalidate dcache with ret %d", __func__, ret); + return ret; + } + + return 0; +} + +/* DMA preparation for the read and write operation */ +static int sdhc_cdns_prepare(uint32_t dma_start_addr, uintptr_t dma_buff, + struct sdhc_data *data) +{ + struct sdhc_cdns_desc *desc; + uint32_t desc_cnt, i; + uintptr_t base; + uint64_t desc_base; + uint32_t size = data->blocks * data->block_size; + + __ASSERT_NO_MSG(((dma_buff & CDNSMMC_ADDRESS_MASK) == 0) && + (cdns_params.desc_size > 0) && + ((cdns_params.desc_size & MMC_BLOCK_MASK) == 0)); + + arch_dcache_flush_range((void *)dma_buff, size); + + desc_cnt = (size + (SDMMC_DMA_MAX_BUFFER_SIZE) - 1) / + (SDMMC_DMA_MAX_BUFFER_SIZE); + __ASSERT_NO_MSG(desc_cnt * sizeof(struct sdhc_cdns_desc) < + cdns_params.desc_size); + + if (desc_cnt > CONFIG_CDNS_DESC_COUNT) { + LOG_ERR("Requested data transfer length %u greater than configured length %u", + size, (CONFIG_CDNS_DESC_COUNT * SDMMC_DMA_MAX_BUFFER_SIZE)); + return -EINVAL; + } + + /* + * Creating descriptor as per the desc_count and linked list of + * descriptor for contiguous desc alignment + */ + base = cdns_params.reg_base; + desc = (struct sdhc_cdns_desc *)cdns_params.desc_base; + desc_base = (uint64_t)desc; + i = 0; + + while ((i+1) < desc_cnt) { + desc->attr = ADMA_DESC_ATTR_VALID | ADMA_DESC_TRANSFER_DATA; + desc->reserved = 0; + desc->len = MAX_64KB_PAGE; + desc->addr_lo = (dma_buff & 0xffffffff) + (SDMMC_DMA_MAX_BUFFER_SIZE * i); + desc->addr_hi = (dma_buff >> 32) & 0xffffffff; + size -= SDMMC_DMA_MAX_BUFFER_SIZE; + desc++; + i++; + } + + desc->attr = ADMA_DESC_ATTR_VALID | ADMA_DESC_TRANSFER_DATA | + ADMA_DESC_ATTR_END; + desc->reserved = 0; + desc->len = size; + desc->addr_lo = (dma_buff & 0xffffffff) + (SDMMC_DMA_MAX_BUFFER_SIZE * i); + desc->addr_hi = (dma_buff >> 32) & 0xffffffff; + + sys_write32((uint32_t)desc_base, cdns_params.reg_base + SDHC_CDNS_SRS22); + sys_write32((uint32_t)(desc_base >> 32), cdns_params.reg_base + SDHC_CDNS_SRS23); + arch_dcache_flush_range((void *)cdns_params.desc_base, + desc_cnt * sizeof(struct sdhc_cdns_desc)); + + sys_write32((data->block_size << CDNS_SRS01_BLK_SIZE | + data->blocks << CDNS_SRS01_BLK_COUNT_CT | CDNS_SRS01_SDMA_BUF), + cdns_params.reg_base + SDHC_CDNS_SRS01); + + return 0; +} + +static int sdhc_cdns_host_set_clk(int clk) +{ + uint32_t sdclkfsval = 0; + uint32_t dtcvval = 0xe; + int ret = 0; + + sdclkfsval = (cdns_params.clk_rate / 2000) / clk; + sys_write32(0, cdns_params.reg_base + SDHC_CDNS_SRS11); + sys_write32(((dtcvval << CDNS_SRS11_DTCV) | (sdclkfsval << CDNS_SRS11_SDCLKFS) | + (1 << CDNS_SRS11_ICE)), cdns_params.reg_base + SDHC_CDNS_SRS11); + + ret = sdhc_cdns_wait_ics(WAIT_ICS_TIME_DELAY_US, cdns_params.reg_base + SDHC_CDNS_SRS11); + if (ret != 0) { + return ret; + } + + /* Enable DLL reset */ + sys_clear_bit(cdns_params.reg_base + SDHC_CDNS_HRS09, 0); + /* Set extended_wr_mode */ + sys_write32(((sys_read32(cdns_params.reg_base + SDHC_CDNS_HRS09) + & 0xFFFFFFF7) | (1 << CDNS_HRS09_EXT_WR_MODE)), (cdns_params.reg_base + + SDHC_CDNS_HRS09)); + /* Release DLL reset */ + sys_set_bit(cdns_params.reg_base + SDHC_CDNS_HRS09, 1); + sys_set_bits(cdns_params.reg_base + SDHC_CDNS_HRS09, (3 << CDNS_HRS09_RDCMD_EN)); + + sys_write32(((dtcvval << CDNS_SRS11_DTCV) | (sdclkfsval << CDNS_SRS11_SDCLKFS) + | (1 << CDNS_SRS11_ICE) | (1 << CDNS_SRS11_SDCE)), + cdns_params.reg_base + SDHC_CDNS_SRS11); + + sys_write32(0xFFFFFFFF, cdns_params.reg_base + SDHC_CDNS_SRS13); + + return 0; +} + +static int sdhc_cdns_set_ios(unsigned int clk, unsigned int width) +{ + int ret = 0; + + switch (width) { + case SDHC_BUS_WIDTH1BIT: + sys_clear_bit(cdns_params.reg_base + SDHC_CDNS_SRS10, WIDTH_BIT1); + break; + case SDHC_BUS_WIDTH4BIT: + sys_set_bit(cdns_params.reg_base + SDHC_CDNS_SRS10, WIDTH_BIT4); + break; + case SDHC_BUS_WIDTH8BIT: + sys_set_bit(cdns_params.reg_base + SDHC_CDNS_SRS10, WIDTH_BIT8); + break; + default: + __ASSERT_NO_MSG(0); + break; + } + + /* Perform clock configuration when SD clock is not gated */ + if (clk != 0) { + ret = sdhc_cdns_host_set_clk(clk); + if (ret != 0) { + LOG_ERR("%s: Clock configuration failed", __func__); + return ret; + } + } + + return 0; +} + +/* Programming HRS register for initialisation */ +static int sdhc_cdns_init_hrs_io(struct sdhc_cdns_combo_phy *sdhc_cdns_combo_phy_reg, + struct sdhc_cdns_sdmmc *sdhc_cdns_sdmmc_reg) +{ + uint32_t value = 0; + int ret = 0; + + /* + * program HRS09, register 42 + * PHY Control and Status Register + */ + value = (CDNS_HRS09_RDDATA_EN(sdhc_cdns_sdmmc_reg->sdhc_rddata_en)) + | (CDNS_HRS09_RDCMD(sdhc_cdns_sdmmc_reg->sdhc_rdcmd_en)) + | (CDNS_HRS09_EXTENDED_WR(sdhc_cdns_sdmmc_reg->sdhc_extended_wr_mode)) + | (CDNS_HRS09_EXT_RD_MODE(sdhc_cdns_sdmmc_reg->sdhc_extended_rd_mode)); + sys_write32(value, cdns_params.reg_base + SDHC_CDNS_HRS09); + + /* + * program HRS10, register 43 + * Host Controller SDCLK start point adjustment + */ + value = (SDHC_HRS10_HCSDCLKADJ(sdhc_cdns_sdmmc_reg->sdhc_hcsdclkadj)); + sys_write32(value, cdns_params.reg_base + SDHC_CDNS_HRS10); + + /* + * program HRS16, register 48 + * CMD/DAT output delay + */ + value = (CDNS_HRS16_WRDATA1_SDCLK_DLY(sdhc_cdns_sdmmc_reg->sdhc_wrdata1_sdclk_dly)) + | (CDNS_HRS16_WRDATA0_SDCLK_DLY(sdhc_cdns_sdmmc_reg->sdhc_wrdata0_sdclk_dly)) + | (CDNS_HRS16_WRCMD1_SDCLK_DLY(sdhc_cdns_sdmmc_reg->sdhc_wrcmd1_sdclk_dly)) + | (CDNS_HRS16_WRCMD0_SDCLK_DLY(sdhc_cdns_sdmmc_reg->sdhc_wrcmd0_sdclk_dly)) + | (CDNS_HRS16_WRDATA1_DLY(sdhc_cdns_sdmmc_reg->sdhc_wrdata1_dly)) + | (CDNS_HRS16_WRDATA0_DLY(sdhc_cdns_sdmmc_reg->sdhc_wrdata0_dly)) + | (CDNS_HRS16_WRCMD1_DLY(sdhc_cdns_sdmmc_reg->sdhc_wrcmd1_dly)) + | (CDNS_HRS16_WRCMD0_DLY(sdhc_cdns_sdmmc_reg->sdhc_wrcmd0_dly)); + sys_write32(value, cdns_params.reg_base + SDHC_CDNS_HRS16); + + /* + * program HRS07, register 40 + * IO Delay Information Register + */ + value = (CDNS_HRS07_RW_COMPENSATE(sdhc_cdns_sdmmc_reg->sdhc_rw_compensate)) + | (CDNS_HRS07_IDELAY_VAL(sdhc_cdns_sdmmc_reg->sdhc_idelay_val)); + sys_write32(value, cdns_params.reg_base + SDHC_CDNS_HRS07); + + return ret; +} + +static int sdhc_cdns_set_clk(struct sdhc_cdns_params *cdn_sdmmc_dev_type_params) +{ + uint32_t dtcvval, sdclkfsval; + int ret = 0; + + dtcvval = DTC_VAL; + sdclkfsval = 0; + + /* Condition for Default speed mode and SDR12 and SDR_BC */ + if ((cdn_sdmmc_dev_type_params->cdn_sdmmc_dev_type == SD_DS) || + (cdn_sdmmc_dev_type_params->cdn_sdmmc_dev_type == SD_UHS_SDR12) || + (cdn_sdmmc_dev_type_params->cdn_sdmmc_dev_type == EMMC_SDR_BC)) { + sdclkfsval = 4; + } else if ((cdn_sdmmc_dev_type_params->cdn_sdmmc_dev_type == SD_HS) || + (cdn_sdmmc_dev_type_params->cdn_sdmmc_dev_type == SD_UHS_SDR25) || + (cdn_sdmmc_dev_type_params->cdn_sdmmc_dev_type == SD_UHS_DDR50) || + (cdn_sdmmc_dev_type_params->cdn_sdmmc_dev_type == EMMC_SDR)) { + sdclkfsval = 2; + } else if ((cdn_sdmmc_dev_type_params->cdn_sdmmc_dev_type == SD_UHS_SDR50) || + (cdn_sdmmc_dev_type_params->cdn_sdmmc_dev_type == EMMC_DDR) || + (cdn_sdmmc_dev_type_params->cdn_sdmmc_dev_type == EMMC_HS400) || + (cdn_sdmmc_dev_type_params->cdn_sdmmc_dev_type == EMMC_HS400ES)) { + sdclkfsval = 1; + } else if ((cdn_sdmmc_dev_type_params->cdn_sdmmc_dev_type == SD_UHS_SDR104) || + (cdn_sdmmc_dev_type_params->cdn_sdmmc_dev_type == EMMC_HS200)) { + sdclkfsval = 0; + } + + /* Disabling SD clock enable */ + sys_write32(0, cdns_params.reg_base + SDHC_CDNS_SRS11); + sys_write32((dtcvval << CDNS_SRS11_DTCV) | + (sdclkfsval << CDNS_SRS11_SDCLKFS) | (1 << CDNS_SRS11_ICE), + cdns_params.reg_base + SDHC_CDNS_SRS11); + ret = sdhc_cdns_wait_ics(WAIT_ICS_TIME_DELAY_US, cdns_params.reg_base + SDHC_CDNS_SRS11); + if (ret != 0) { + return ret; + } + + /* Enable DLL reset */ + sys_clear_bit(cdns_params.reg_base + SDHC_CDNS_HRS09, 0); + /* Set extended_wr_mode */ + sys_write32(((sys_read32(cdns_params.reg_base + SDHC_CDNS_HRS09) & + 0xFFFFFFF7) | (1 << CDNS_HRS09_EXT_WR_MODE)), (cdns_params.reg_base + + SDHC_CDNS_HRS09)); + /* Release DLL reset */ + sys_set_bit(cdns_params.reg_base + SDHC_CDNS_HRS09, 1); + sys_set_bits(cdns_params.reg_base + SDHC_CDNS_HRS09, (3 << CDNS_HRS09_RDCMD_EN)); + + sys_write32((dtcvval << CDNS_SRS11_DTCV) | (sdclkfsval << CDNS_SRS11_SDCLKFS) | + (1 << CDNS_SRS11_ICE) | (1 << CDNS_SRS11_SDCE), cdns_params.reg_base + + SDHC_CDNS_SRS11); + + sys_write32(0xFFFFFFFF, cdns_params.reg_base + SDHC_CDNS_SRS13); + return 0; +} + +static int sdhc_cdns_reset(void) +{ + int32_t timeout; + + sys_clear_bits(cdns_params.reg_base + SDHC_CDNS_SRS11, 0xFFFF); + + /* Software reset */ + sys_set_bit(cdns_params.reg_base + SDHC_CDNS_HRS00, CDNS_HRS00_SWR); + + /* Wait status command response ready */ + timeout = CARD_REG_TIME_DELAY_US; + if (!WAIT_FOR(((sys_read32(cdns_params.reg_base + SDHC_CDNS_HRS00) & + CDNS_HRS00_SWR) == 0), timeout, k_msleep(1))) { + LOG_ERR("Software reset is not completed...timedout"); + return -ETIMEDOUT; + } + + /* Step 1, switch on DLL_RESET */ + sys_clear_bit(cdns_params.reg_base + SDHC_CDNS_HRS09, CDNS_HRS09_PHY_SW_RESET); + + return 0; +} + +static int sdhc_cdns_init(void) +{ + int ret = 0; + + ret = sdhc_cdns_program_phy_reg(&sdhc_cdns_combo_phy_reg_info, &sdhc_cdns_sdmmc_reg_info); + if (ret != 0U) { + LOG_ERR("SoftPhy register configuration failed"); + return ret; + } + + ret = sdhc_cdns_init_hrs_io(&sdhc_cdns_combo_phy_reg_info, &sdhc_cdns_sdmmc_reg_info); + if (ret != 0U) { + LOG_ERR("Configuration for HRS IO reg failed"); + return ret; + } + + ret = sdhc_cdns_card_present(); + if (ret != CARD_PRESENT) { + LOG_ERR("SD card does not detect"); + return -ETIMEDOUT; + } + + ret = sdhc_cdns_vol_reset(); + if (ret != 0U) { + LOG_ERR("SD/MMC card reset failed"); + return ret; + } + + ret = sdhc_cdns_set_clk(&cdns_params); + if (ret != 0U) { + LOG_ERR("Host controller set clk failed"); + return ret; + } + + return 0; +} + +static int sdhc_cdns_send_cmd(struct sdmmc_cmd *cmd, struct sdhc_data *data) +{ + uint32_t op = 0; + uint32_t value; + uintptr_t base; + int32_t timeout; + uint32_t cmd_indx; + uint32_t status_check = 0; + + __ASSERT(cmd, "Assert %s function call", __func__); + base = cdns_params.reg_base; + cmd_indx = (cmd->cmd_idx) << CDNS_SRS03_COM_IDX; + + if (data) { + switch (cmd->cmd_idx) { + case SD_SWITCH: + op = CDNS_SRS03_DATA_PRSNT; + sys_set_bits(cdns_params.reg_base + SDHC_CDNS_SRS10, SRS10_VAL_SW); + sys_set_bits(cdns_params.reg_base + SDHC_CDNS_SRS11, SRS11_VAL_GEN); + sys_set_bits(cdns_params.reg_base + SDHC_CDNS_SRS15, SRS15_VAL_GEN); + break; + + case SD_WRITE_SINGLE_BLOCK: + case SD_READ_SINGLE_BLOCK: + op = CDNS_SRS03_DATA_PRSNT; + sys_set_bits(cdns_params.reg_base + SDHC_CDNS_SRS10, SRS10_VAL_READ); + sys_set_bits(cdns_params.reg_base + SDHC_CDNS_SRS11, SRS11_VAL_GEN); + sys_set_bits(cdns_params.reg_base + SDHC_CDNS_SRS15, SRS15_VAL_RD_WR); + sys_write32(CDNS_SRS00_SAAR, cdns_params.reg_base + SDHC_CDNS_SRS00); + break; + + case SD_WRITE_MULTIPLE_BLOCK: + case SD_READ_MULTIPLE_BLOCK: + op = CDNS_SRS03_DATA_PRSNT | AUTO_CMD23 | CDNS_SRS03_MULTI_BLK_READ; + sys_set_bits(cdns_params.reg_base + SDHC_CDNS_SRS10, SRS10_VAL_READ); + sys_set_bits(cdns_params.reg_base + SDHC_CDNS_SRS11, SRS11_VAL_GEN); + sys_set_bits(cdns_params.reg_base + SDHC_CDNS_SRS15, SRS15_VAL_RD_WR); + sys_write32(CDNS_SRS00_SAAR, cdns_params.reg_base + SDHC_CDNS_SRS00); + break; + + case SD_APP_SEND_SCR: + op = CDNS_SRS03_DATA_PRSNT; + sys_set_bits(cdns_params.reg_base + SDHC_CDNS_SRS10, ADMA2_32); + sys_set_bits(cdns_params.reg_base + SDHC_CDNS_SRS11, SRS11_VAL_GEN); + sys_set_bits(cdns_params.reg_base + SDHC_CDNS_SRS15, SRS15_VAL_GEN); + break; + + default: + op = 0; + break; + } + } else { + switch (cmd->cmd_idx) { + case SD_GO_IDLE_STATE: + sys_set_bits(cdns_params.reg_base + SDHC_CDNS_SRS11, SRS11_VAL_CID); + sys_set_bits(cdns_params.reg_base + SDHC_CDNS_SRS15, CDNS_SRS15_HV4E); + break; + + case SD_ALL_SEND_CID: + sys_set_bits(cdns_params.reg_base + SDHC_CDNS_SRS11, SRS11_VAL_CID); + sys_set_bits(cdns_params.reg_base + SDHC_CDNS_SRS15, SRS15_VAL_CID); + break; + + case SD_SEND_IF_COND: + op = CDNS_SRS03_CMD_IDX_CHK_EN; + sys_set_bits(cdns_params.reg_base + SDHC_CDNS_SRS11, SRS11_VAL_GEN); + sys_set_bits(cdns_params.reg_base + SDHC_CDNS_SRS15, CDNS_SRS15_HV4E); + break; + + case SD_STOP_TRANSMISSION: + op = CMD_STOP_ABORT_CMD; + break; + + case SD_SEND_STATUS: + break; + + case SD_SELECT_CARD: + op = CDNS_SRS03_MULTI_BLK_READ; + break; + + default: + op = 0; + break; + } + } + + switch (cmd->resp_type) { + case SD_RSP_TYPE_NONE: + op |= (CDNS_SRS03_CMD_READ | CDNS_SRS03_MULTI_BLK_READ | + CDNS_SRS03_DMA_EN | CDNS_SRS03_BLK_CNT_EN); + break; + + case SD_RSP_TYPE_R2: + op |= (CDNS_SRS03_CMD_READ | CDNS_SRS03_MULTI_BLK_READ | + CDNS_SRS03_DMA_EN | CDNS_SRS03_BLK_CNT_EN | + RES_TYPE_SEL_136 | CDNS_SRS03_RESP_CRC); + break; + + case SD_RSP_TYPE_R3: + op |= (CDNS_SRS03_CMD_READ | CDNS_SRS03_MULTI_BLK_READ | + CDNS_SRS03_DMA_EN | CDNS_SRS03_BLK_CNT_EN | RES_TYPE_SEL_48); + break; + + case SD_RSP_TYPE_R1: + if ((cmd->cmd_idx == SD_WRITE_SINGLE_BLOCK) || (cmd->cmd_idx + == SD_WRITE_MULTIPLE_BLOCK)) { + op |= (CDNS_SRS03_DMA_EN | CDNS_SRS03_BLK_CNT_EN | RES_TYPE_SEL_48 + | CDNS_SRS03_RESP_CRC | CDNS_SRS03_CMD_IDX_CHK_EN); + } else { + op |= (CDNS_SRS03_DMA_EN | CDNS_SRS03_BLK_CNT_EN | CDNS_SRS03_CMD_READ + | RES_TYPE_SEL_48 | CDNS_SRS03_RESP_CRC | CDNS_SRS03_CMD_IDX_CHK_EN); + } + break; + + default: + op |= (CDNS_SRS03_DMA_EN | CDNS_SRS03_BLK_CNT_EN | CDNS_SRS03_CMD_READ | + CDNS_SRS03_MULTI_BLK_READ | RES_TYPE_SEL_48 | CDNS_SRS03_RESP_CRC | + CDNS_SRS03_CMD_IDX_CHK_EN); + break; + } + + timeout = CARD_REG_TIME_DELAY_US; + if (!WAIT_FOR((sdhc_cdns_busy() == 0), timeout, k_msleep(1))) { + k_panic(); + } + + sys_write32(~0, cdns_params.reg_base + SDHC_CDNS_SRS12); + + sys_write32(cmd->cmd_arg, cdns_params.reg_base + SDHC_CDNS_SRS02); + sys_write32(RESET_SRS14, cdns_params.reg_base + SDHC_CDNS_SRS14); + sys_write32(op | cmd_indx, cdns_params.reg_base + SDHC_CDNS_SRS03); + + timeout = CARD_REG_TIME_DELAY_US; + if (!WAIT_FOR(((((sys_read32(cdns_params.reg_base + SDHC_CDNS_SRS12)) & + CDNS_SRS03_CMD_DONE) == 1) | (((sys_read32(cdns_params.reg_base + + SDHC_CDNS_SRS12)) & ERROR_INT) == ERROR_INT)), timeout, k_busy_wait(1))) { + LOG_ERR("Response timeout SRS12"); + return -ETIMEDOUT; + } + + value = sys_read32(cdns_params.reg_base + SDHC_CDNS_SRS12); + status_check = value & CDNS_SRS12_ERR_MASK; + if (status_check != 0U) { + LOG_ERR("SD host controller send command failed, SRS12 = %X", status_check); + return -EIO; + } + + if ((op & RES_TYPE_SEL_48) || (op & RES_TYPE_SEL_136)) { + cmd->resp_data[0] = sys_read32(cdns_params.reg_base + SDHC_CDNS_SRS04); + if (op & RES_TYPE_SEL_136) { + cmd->resp_data[1] = sys_read32(cdns_params.reg_base + SDHC_CDNS_SRS05); + cmd->resp_data[2] = sys_read32(cdns_params.reg_base + SDHC_CDNS_SRS06); + cmd->resp_data[3] = sys_read32(cdns_params.reg_base + SDHC_CDNS_SRS07); + + /* 136-bit: RTS=01b, Response field R[127:8] - RESP3[23:0], + * RESP2[31:0], RESP1[31:0], RESP0[31:0] + * Subsystem expects 128 bits response but cadence SDHC sends + * 120 bits response from R[127:8]. Bits manupulation to address + * the correct responses for the 136 bit response type. + */ + cmd->resp_data[3] = ((cmd->resp_data[3] << 8) | ((cmd->resp_data[2] >> 24) + & CDNS_CSD_BYTE_MASK)); + cmd->resp_data[2] = ((cmd->resp_data[2] << 8) | ((cmd->resp_data[1] >> 24) + & CDNS_CSD_BYTE_MASK)); + cmd->resp_data[1] = ((cmd->resp_data[1] << 8) | ((cmd->resp_data[0] >> 24) + & CDNS_CSD_BYTE_MASK)); + cmd->resp_data[0] = (cmd->resp_data[0] << 8); + } + } + + return 0; +} + +static const struct sdhc_cdns_ops cdns_sdmmc_ops = { + .init = sdhc_cdns_init, + .send_cmd = sdhc_cdns_send_cmd, + .card_present = sdhc_cdns_card_present, + .set_ios = sdhc_cdns_set_ios, + .prepare = sdhc_cdns_prepare, + .cache_invd = sdhc_cdns_cache_invd, + .busy = sdhc_cdns_busy, + .reset = sdhc_cdns_reset, +}; + +void sdhc_cdns_sdmmc_init(struct sdhc_cdns_params *params, struct sdmmc_device_info *info, + const struct sdhc_cdns_ops **cb_sdmmc_ops) +{ + __ASSERT_NO_MSG((params != NULL) && + ((params->reg_base & MMC_BLOCK_MASK) == 0) && + ((params->desc_size & MMC_BLOCK_MASK) == 0) && + ((params->reg_phy & MMC_BLOCK_MASK) == 0) && + (params->desc_size > 0) && + (params->clk_rate > 0) && + ((params->bus_width == MMC_BUS_WIDTH_1) || + (params->bus_width == MMC_BUS_WIDTH_4) || + (params->bus_width == MMC_BUS_WIDTH_8))); + + memcpy(&cdns_params, params, sizeof(struct sdhc_cdns_params)); + cdns_params.cdn_sdmmc_dev_type = info->cdn_sdmmc_dev_type; + *cb_sdmmc_ops = &cdns_sdmmc_ops; + + cdns_sdhc_set_sdmmc_params(&sdhc_cdns_combo_phy_reg_info, &sdhc_cdns_sdmmc_reg_info); +} diff --git a/drivers/sdhc/sdhc_cdns/sdhc_cdns_ll.h b/drivers/sdhc/sdhc_cdns/sdhc_cdns_ll.h new file mode 100644 index 00000000000..c07e446dad0 --- /dev/null +++ b/drivers/sdhc/sdhc_cdns/sdhc_cdns_ll.h @@ -0,0 +1,489 @@ +/* + * Copyright (C) 2023 Intel Corporation + * SPDX-License-Identifier: Apache-2.0 + */ + +#include +#include + +/* HRS09 */ +#define CDNS_HRS09_PHY_SW_RESET BIT(0) +#define CDNS_HRS09_PHY_INIT_COMP BIT(1) +#define CDNS_HRS09_EXT_RD_MODE(x) ((x) << 2) +#define CDNS_HRS09_EXT_WR_MODE 3 +#define CDNS_HRS09_EXTENDED_WR(x) ((x) << 3) +#define CDNS_HRS09_RDCMD_EN 15 +#define CDNS_HRS09_RDCMD(x) ((x) << 15) +#define CDNS_HRS09_RDDATA_EN(x) ((x) << 16) + +/* HRS00 */ +#define CDNS_HRS00_SWR BIT(0) + +/* CMD_DATA_OUTPUT */ +#define SDHC_CDNS_HRS16 0x40 + +/* SRS09 */ +#define CDNS_SRS09_STAT_DAT_BUSY BIT(2) +#define CDNS_SRS09_CI BIT(16) + +/* SRS10 */ +#define CDNS_SRS10_DTW 1 +#define CDNS_SRS10_EDTW 5 +#define CDNS_SRS10_BP 8 +#define CDNS_SRS10_BVS 9 + +/* data bus width */ +#define WIDTH_BIT1 CDNS_SRS10_DTW +#define WIDTH_BIT4 CDNS_SRS10_DTW +#define WIDTH_BIT8 CDNS_SRS10_EDTW + +/* SRS11 */ +#define CDNS_SRS11_ICE BIT(0) +#define CDNS_SRS11_ICS BIT(1) +#define CDNS_SRS11_SDCE BIT(2) +#define CDNS_SRS11_USDCLKFS 6 +#define CDNS_SRS11_SDCLKFS 8 +#define CDNS_SRS11_DTCV 16 +#define CDNS_SRS11_SRFA BIT(24) +#define CDNS_SRS11_SRCMD BIT(25) +#define CDNS_SRS11_SRDAT BIT(26) + +/* + * This value determines the interval by which DAT line timeouts are detected + * The interval can be computed as below: + * • 1111b - Reserved + * • 1110b - t_sdmclk*2(27+2) + * • 1101b - t_sdmclk*2(26+2) + */ +#define READ_CLK (0xa << 16) +#define WRITE_CLK (0xe << 16) +#define DTC_VAL 0xE + +/* SRS12 */ +#define CDNS_SRS12_CC 0U +#define CDNS_SRS12_TC 1 +#define CDNS_SRS12_EINT 15 + +/* SRS01 */ +#define CDNS_SRS01_BLK_SIZE 0U +#define CDNS_SRS01_SDMA_BUF 7 << 12 +#define CDNS_SRS01_BLK_COUNT_CT 16 + +/* SRS15 Registers */ +#define CDNS_SRS15_SDR12 0U +#define CDNS_SRS15_SDR25 BIT(16) +#define CDNS_SRS15_SDR50 (2 << 16) +#define CDNS_SRS15_SDR104 (3 << 16) +#define CDNS_SRS15_DDR50 (4 << 16) +/* V18SE is 0 for DS and HS, 1 for UHS-I */ +#define CDNS_SRS15_V18SE BIT(19) +#define CDNS_SRS15_CMD23_EN BIT(27) +/* HC4E is 0 means version 3.0 and 1 means v 4.0 */ +#define CDNS_SRS15_HV4E BIT(28) +#define CDNS_SRS15_BIT_AD_32 0U +#define CDNS_SRS15_BIT_AD_64 BIT(29) +#define CDNS_SRS15_PVE BIT(31) + +/* Combo PHY */ +#define PHY_DQ_TIMING_REG 0x0 +#define PHY_DQS_TIMING_REG 0x04 +#define PHY_GATE_LPBK_CTRL_REG 0x08 +#define PHY_DLL_MASTER_CTRL_REG 0x0C +#define PHY_DLL_SLAVE_CTRL_REG 0x10 +#define PHY_CTRL_REG 0x80 + +#define PERIPHERAL_SDMMC_MASK 0x60 +#define PERIPHERAL_SDMMC_OFFSET 6 +#define DFI_INTF_MASK 0x1 + +/* PHY_DQS_TIMING_REG */ +#define CP_USE_EXT_LPBK_DQS(x) (x << 22) +#define CP_USE_LPBK_DQS(x) (x << 21) +#define CP_USE_PHONY_DQS(x) (x << 20) +#define CP_USE_PHONY_DQS_CMD(x) (x << 19) + +/* PHY_GATE_LPBK_CTRL_REG */ +#define CP_SYNC_METHOD(x) ((x) << 31) +#define CP_SW_HALF_CYCLE_SHIFT(x) ((x) << 28) +#define CP_RD_DEL_SEL(x) ((x) << 19) +#define CP_UNDERRUN_SUPPRESS(x) ((x) << 18) +#define CP_GATE_CFG_ALWAYS_ON(x) ((x) << 6) + +/* PHY_DLL_MASTER_CTRL_REG */ +#define CP_DLL_BYPASS_MODE(x) ((x) << 23) +#define CP_DLL_START_POINT(x) ((x) << 0) + +/* PHY_DLL_SLAVE_CTRL_REG */ +#define CP_READ_DQS_CMD_DELAY(x) ((x) << 24) +#define CP_CLK_WRDQS_DELAY(x) ((x) << 16) +#define CP_CLK_WR_DELAY(x) ((x) << 8) +#define CP_READ_DQS_DELAY(x) (x) + +/* PHY_DQ_TIMING_REG */ +#define CP_IO_MASK_ALWAYS_ON(x) ((x) << 31) +#define CP_IO_MASK_END(x) ((x) << 27) +#define CP_IO_MASK_START(x) ((x) << 24) +#define CP_DATA_SELECT_OE_END(x) (x) + +/* SW RESET REG */ +#define SDHC_CDNS_HRS00 (0x00) +#define CDNS_HRS00_SWR BIT(0) + +/* PHY access port */ +#define SDHC_CDNS_HRS04 0x10 +#define CDNS_HRS04_ADDR GENMASK(5, 0) + +/* PHY data access port */ +#define SDHC_CDNS_HRS05 0x14 + +/* eMMC control registers */ +#define SDHC_CDNS_HRS06 0x18 + +/* PHY_CTRL_REG */ +#define CP_PHONY_DQS_TIMING_MASK 0x3F +#define CP_PHONY_DQS_TIMING_SHIFT 4 + +/* SRS */ +#define SDHC_CDNS_SRS00 0x200 +#define SDHC_CDNS_SRS01 0x204 +#define SDHC_CDNS_SRS02 0x208 +#define SDHC_CDNS_SRS03 0x20c +#define SDHC_CDNS_SRS04 0x210 +#define SDHC_CDNS_SRS05 0x214 +#define SDHC_CDNS_SRS06 0x218 +#define SDHC_CDNS_SRS07 0x21C +#define SDHC_CDNS_SRS08 0x220 +#define SDHC_CDNS_SRS09 0x224 +#define SDHC_CDNS_SRS10 0x228 +#define SDHC_CDNS_SRS11 0x22C +#define SDHC_CDNS_SRS12 0x230 +#define SDHC_CDNS_SRS13 0x234 +#define SDHC_CDNS_SRS14 0x238 +#define SDHC_CDNS_SRS15 0x23c +#define SDHC_CDNS_SRS21 0x254 +#define SDHC_CDNS_SRS22 0x258 +#define SDHC_CDNS_SRS23 0x25c + +/* SRS00 */ +#define CDNS_SRS00_SAAR 1 + +/* SRS03 */ +#define CDNS_SRS03_CMD_START BIT(31) +#define CDNS_SRS03_CMD_USE_HOLD_REG BIT(29) +#define CDNS_SRS03_CMD_UPDATE_CLK_ONLY BIT(21) +#define CDNS_SRS03_CMD_SEND_INIT BIT(15) +/* Command type */ +#define CDNS_SRS03_CMD_TYPE BIT(22) +#define CMD_STOP_ABORT_CMD (3 << 22) +#define CMD_RESUME_CMD (2 << 22) +#define CMD_SUSPEND_CMD BIT(22) +#define CDNS_SRS03_DATA_PRSNT BIT(21) +#define CDNS_SRS03_CMD_IDX_CHK_EN BIT(20) +#define CDNS_SRS03_CMD_READ BIT(4) +#define CDNS_SRS03_MULTI_BLK_READ BIT(5) +#define CDNS_SRS03_RESP_ERR BIT(7) +#define CDNS_SRS03_RESP_CRC BIT(19) +#define CDNS_SRS03_CMD_DONE BIT(0) +/* Response type select */ +#define CDNS_SRS03_RES_TYPE_SEL BIT(16) +#define RES_TYPE_SEL_48 (2 << 16) +#define RES_TYPE_SEL_136 (1 << 16) +#define RES_TYPE_SEL_48_B (3 << 16) +#define RES_TYPE_SEL_NO (0 << 16) +/* Auto CMD Enable */ +#define CDNS_SRS03_AUTO_CMD_EN BIT(2) +#define AUTO_CMD23 (2 << 2) +#define AUTO_CMD12 BIT(2) +#define AUTO_CMD_AUTO (3 << 2) +#define CDNS_SRS03_COM_IDX 24 +#define ERROR_INT BIT(15) +#define CDNS_SRS03_DMA_EN BIT(0) +#define CDNS_SRS03_BLK_CNT_EN BIT(1) + +/* HRS07 */ +#define SDHC_CDNS_HRS07 0x1c +#define CDNS_HRS07_IDELAY_VAL(x) (x) +#define CDNS_HRS07_RW_COMPENSATE(x) ((x) << 16) + +/* PHY reset port */ +#define SDHC_CDNS_HRS09 0x24 + +/* HRS10 */ +/* PHY reset port */ +#define SDHC_CDNS_HRS10 0x28 + +/* HCSDCLKADJ DATA; DDR Mode */ +#define SDHC_HRS10_HCSDCLKADJ(x) ((x) << 16) + +/* HRS16 */ +#define CDNS_HRS16_WRCMD0_DLY(x) (x) +#define CDNS_HRS16_WRCMD1_DLY(x) ((x) << 4) +#define CDNS_HRS16_WRDATA0_DLY(x) ((x) << 8) +#define CDNS_HRS16_WRDATA1_DLY(x) ((x) << 12) +#define CDNS_HRS16_WRCMD0_SDCLK_DLY(x) ((x) << 16) +#define CDNS_HRS16_WRCMD1_SDCLK_DLY(x) ((x) << 20) +#define CDNS_HRS16_WRDATA0_SDCLK_DLY(x) ((x) << 24) +#define CDNS_HRS16_WRDATA1_SDCLK_DLY(x) ((x) << 28) + +/* Shared Macros */ +#define SDMMC_CDN(_reg) (SDMMC_CDN_REG_BASE + \ + (SDMMC_CDN_##_reg)) + +/* MMC Peripheral Definition */ +#define MMC_BLOCK_SIZE 512U +#define MMC_BLOCK_MASK (MMC_BLOCK_SIZE - 1) +#define MMC_BOOT_CLK_RATE (400 * 1000) + +#define OCR_POWERUP BIT(31) +#define OCR_HCS BIT(30) + +#define OCR_3_5_3_6 BIT(23) +#define OCR_3_4_3_5 BIT(22) +#define OCR_3_3_3_4 BIT(21) +#define OCR_3_2_3_3 BIT(20) +#define OCR_3_1_3_2 BIT(19) +#define OCR_3_0_3_1 BIT(18) +#define OCR_2_9_3_0 BIT(17) +#define OCR_2_8_2_9 BIT(16) +#define OCR_2_7_2_8 BIT(15) +#define OCR_VDD_MIN_2V7 GENMASK(23, 15) +#define OCR_VDD_MIN_2V0 GENMASK(14, 8) +#define OCR_VDD_MIN_1V7 BIT(7) + +#define MMC_RSP_48 BIT(0) +#define MMC_RSP_136 BIT(1) /* 136 bit response */ +#define MMC_RSP_CRC BIT(2) /* expect valid crc */ +#define MMC_RSP_CMD_IDX BIT(3) /* response contains cmd idx */ +#define MMC_RSP_BUSY BIT(4) /* device may be busy */ + +/* JEDEC 4.51 chapter 6.12 */ +#define MMC_RESPONSE_R1 (MMC_RSP_48 | MMC_RSP_CMD_IDX | MMC_RSP_CRC) +#define MMC_RESPONSE_R1B (MMC_RESPONSE_R1 | MMC_RSP_BUSY) +#define MMC_RESPONSE_R2 (MMC_RSP_48 | MMC_RSP_136 | MMC_RSP_CRC) +#define MMC_RESPONSE_R3 (MMC_RSP_48) +#define MMC_RESPONSE_R4 (MMC_RSP_48) +#define MMC_RESPONSE_R5 (MMC_RSP_48 | MMC_RSP_CRC | MMC_RSP_CMD_IDX) +#define MMC_RESPONSE_R6 (MMC_RSP_CRC | MMC_RSP_CMD_IDX) +#define MMC_RESPONSE_R7 (MMC_RSP_48 | MMC_RSP_CRC) +#define MMC_RESPONSE_NONE 0 + +/* Value randomly chosen for eMMC RCA, it should be > 1 */ +#define MMC_FIX_RCA 6 +#define RCA_SHIFT_OFFSET 16 + +#define CMD_EXTCSD_PARTITION_CONFIG 179 +#define CMD_EXTCSD_BUS_WIDTH 183 +#define CMD_EXTCSD_HS_TIMING 185 +#define CMD_EXTCSD_SEC_CNT 212 + +#define PART_CFG_BOOT_PARTITION1_ENABLE BIT(3) +#define PART_CFG_PARTITION1_ACCESS 1 + +/* Values in EXT CSD register */ +#define MMC_BUS_WIDTH_1 0 +#define MMC_BUS_WIDTH_4 1 +#define MMC_BUS_WIDTH_8 2 +#define MMC_BUS_WIDTH_DDR_4 5 +#define MMC_BUS_WIDTH_DDR_8 6 +#define MMC_BOOT_MODE_BACKWARD 0 +#define MMC_BOOT_MODE_HS_TIMING BIT(3) +#define MMC_BOOT_MODE_DDR (2 << 3) + +#define EXTCSD_SET_CMD 0 +#define EXTCSD_SET_BITS BIT(24) +#define EXTCSD_CLR_BITS (2 << 24) +#define EXTCSD_WRITE_BYTES (3 << 24) +#define EXTCSD_CMD(x) (((x) & 0xff) << 16) +#define EXTCSD_VALUE(x) (((x) & 0xff) << 8) +#define EXTCSD_CMD_SET_NORMAL 1 + +#define CSD_TRAN_SPEED_UNIT_MASK GENMASK(2, 0) +#define CSD_TRAN_SPEED_MULT_MASK GENMASK(6, 3) +#define CSD_TRAN_SPEED_MULT_SHIFT 3 + +#define STATUS_CURRENT_STATE(x) (((x) & 0xf) << 9) +#define STATUS_READY_FOR_DATA BIT(8) +#define STATUS_SWITCH_ERROR BIT(7) +#define MMC_GET_STATE(x) (((x) >> 9) & 0xf) +#define MMC_STATE_IDLE 0 +#define MMC_STATE_READY 1 +#define MMC_STATE_IDENT 2 +#define MMC_STATE_STBY 3 +#define MMC_STATE_TRAN 4 +#define MMC_STATE_DATA 5 +#define MMC_STATE_RCV 6 +#define MMC_STATE_PRG 7 +#define MMC_STATE_DIS 8 +#define MMC_STATE_BTST 9 +#define MMC_STATE_SLP 10 + +#define MMC_FLAG_CMD23 1 + +#define CMD8_CHECK_PATTERN 0xAA +#define VHS_2_7_3_6_V BIT(8) + +#define SD_SCR_BUS_WIDTH_1 BIT(8) +#define SD_SCR_BUS_WIDTH_4 BIT(10) + +/* ADMA table component */ +#define ADMA_DESC_ATTR_VALID BIT(0) +#define ADMA_DESC_ATTR_END BIT(1) +#define ADMA_DESC_ATTR_INT BIT(2) +#define ADMA_DESC_ATTR_ACT1 BIT(4) +#define ADMA_DESC_ATTR_ACT2 BIT(5) +#define ADMA_DESC_TRANSFER_DATA ADMA_DESC_ATTR_ACT2 + +/* SRS10 Register */ +#define LEDC BIT(0) +#define DT_WIDTH BIT(1) +#define HS_EN BIT(2) +/* Conf depends on SRS15.HV4E */ +#define SDMA 0 +#define ADMA2_32 (2 << 3) +#define ADMA2_64 (3 << 3) +/* here 0 defines the 64 Kb size */ +#define MAX_64KB_PAGE 0 + +struct sdmmc_cmd { + unsigned int cmd_idx; + unsigned int cmd_arg; + unsigned int resp_type; + unsigned int resp_data[4]; +}; + +struct sdhc_cdns_ops { + /* init function for card */ + int (*init)(void); + /* busy check function for card */ + int (*busy)(void); + /* card_present function check for card */ + int (*card_present)(void); + /* reset the card */ + int (*reset)(void); + /* send command and respective argument */ + int (*send_cmd)(struct sdmmc_cmd *cmd, struct sdhc_data *data); + /* io set up for card */ + int (*set_ios)(unsigned int clk, unsigned int width); + /* prepare dma descriptors */ + int (*prepare)(uint32_t lba, uintptr_t buf, struct sdhc_data *data); + /* cache invd api */ + int (*cache_invd)(int lba, uintptr_t buf, size_t size); +}; + +/* Combo Phy reg */ +struct sdhc_cdns_combo_phy { + uint32_t cp_clk_wr_delay; + uint32_t cp_clk_wrdqs_delay; + uint32_t cp_data_select_oe_end; + uint32_t cp_dll_bypass_mode; + uint32_t cp_dll_locked_mode; + uint32_t cp_dll_start_point; + uint32_t cp_gate_cfg_always_on; + uint32_t cp_io_mask_always_on; + uint32_t cp_io_mask_end; + uint32_t cp_io_mask_start; + uint32_t cp_rd_del_sel; + uint32_t cp_read_dqs_cmd_delay; + uint32_t cp_read_dqs_delay; + uint32_t cp_sw_half_cycle_shift; + uint32_t cp_sync_method; + uint32_t cp_underrun_suppress; + uint32_t cp_use_ext_lpbk_dqs; + uint32_t cp_use_lpbk_dqs; + uint32_t cp_use_phony_dqs; + uint32_t cp_use_phony_dqs_cmd; +}; + +/* sdmmc reg */ +struct sdhc_cdns_sdmmc { + uint32_t sdhc_extended_rd_mode; + uint32_t sdhc_extended_wr_mode; + uint32_t sdhc_hcsdclkadj; + uint32_t sdhc_idelay_val; + uint32_t sdhc_rdcmd_en; + uint32_t sdhc_rddata_en; + uint32_t sdhc_rw_compensate; + uint32_t sdhc_sdcfsh; + uint32_t sdhc_sdcfsl; + uint32_t sdhc_wrcmd0_dly; + uint32_t sdhc_wrcmd0_sdclk_dly; + uint32_t sdhc_wrcmd1_dly; + uint32_t sdhc_wrcmd1_sdclk_dly; + uint32_t sdhc_wrdata0_dly; + uint32_t sdhc_wrdata0_sdclk_dly; + uint32_t sdhc_wrdata1_dly; + uint32_t sdhc_wrdata1_sdclk_dly; +}; + +enum sdmmc_device_mode { + /* Identification */ + SD_DS_ID, + /* Default speed */ + SD_DS, + /* High speed */ + SD_HS, + /* Ultra high speed SDR12 */ + SD_UHS_SDR12, + /* Ultra high speed SDR25 */ + SD_UHS_SDR25, + /* Ultra high speed SDR`50 */ + SD_UHS_SDR50, + /* Ultra high speed SDR104 */ + SD_UHS_SDR104, + /* Ultra high speed DDR50 */ + SD_UHS_DDR50, + /* SDR backward compatible */ + EMMC_SDR_BC, + /* SDR */ + EMMC_SDR, + /* DDR */ + EMMC_DDR, + /* High speed 200Mhz in SDR */ + EMMC_HS200, + /* High speed 200Mhz in DDR */ + EMMC_HS400, + /* High speed 200Mhz in SDR with enhanced strobe */ + EMMC_HS400ES, +}; + +struct sdhc_cdns_params { + uintptr_t reg_base; + uintptr_t reg_phy; + uintptr_t desc_base; + size_t desc_size; + int clk_rate; + int bus_width; + unsigned int flags; + enum sdmmc_device_mode cdn_sdmmc_dev_type; + uint32_t combophy; +}; + +struct sdmmc_device_info { + /* Size of device in bytes */ + unsigned long long device_size; + /* Block size in bytes */ + unsigned int block_size; + /* Max bus freq in Hz */ + unsigned int max_bus_freq; + /* OCR voltage */ + unsigned int ocr_voltage; + /* Type of MMC */ + enum sdmmc_device_mode cdn_sdmmc_dev_type; +}; + +/*descriptor structure with 8 byte alignment*/ +struct sdhc_cdns_desc { + /* 8 bit attribute */ + uint8_t attr; + /* reserved bits in desc */ + uint8_t reserved; + /* page length for the descriptor */ + uint16_t len; + /* lower 32 bits for buffer (64 bit addressing) */ + uint32_t addr_lo; + /* higher 32 bits for buffer (64 bit addressing) */ + uint32_t addr_hi; +} __aligned(8); + +void sdhc_cdns_sdmmc_init(struct sdhc_cdns_params *params, struct sdmmc_device_info *info, + const struct sdhc_cdns_ops **cb_sdmmc_ops); diff --git a/drivers/sdhc/sdhc_cdns_ll.c b/drivers/sdhc/sdhc_cdns_ll.c new file mode 100644 index 00000000000..3d8e3f97e4a --- /dev/null +++ b/drivers/sdhc/sdhc_cdns_ll.c @@ -0,0 +1,791 @@ +/* + * Copyright (C) 2023 Intel Corporation + * SPDX-License-Identifier: Apache-2.0 + */ + +#include +#include "sdhc_cdns_ll.h" +#include + +LOG_MODULE_REGISTER(sdhc_cdns_ll, CONFIG_SDHC_LOG_LEVEL); + +/* card busy and present */ +#define CARD_BUSY 1 +#define CARD_NOT_BUSY 0 +#define CARD_PRESENT 1 + +/* SRS12 error mask */ +#define CDNS_SRS12_ERR_MASK 0xFFFF8000U +#define CDNS_CSD_BYTE_MASK 0x000000FFU + +/* General define */ +#define SDHC_REG_MASK 0xFFFFFFFFU +#define SD_HOST_BLOCK_SIZE 0x200 + +#define SDMMC_DMA_MAX_BUFFER_SIZE (64 * 1024) +#define CDNSMMC_ADDRESS_MASK (CONFIG_SDHC_BUFFER_ALIGNMENT - 1) + +#define SRS10_VAL_READ (ADMA2_32 | HS_EN | DT_WIDTH) +#define SRS10_VAL_SW (ADMA2_32 | DT_WIDTH) +#define SRS11_VAL_GEN (READ_CLK | CDNS_SRS11_ICE | CDNS_SRS11_ICS | CDNS_SRS11_SDCE) +#define SRS11_VAL_CID (CDNS_SRS11_ICE | CDNS_SRS11_ICS | CDNS_SRS11_SDCE) +#define SRS15_VAL_GEN (CDNS_SRS15_BIT_AD_64 | CDNS_SRS15_HV4E | CDNS_SRS15_V18SE) +#define SRS15_VAL_RD_WR (SRS15_VAL_GEN | CDNS_SRS15_SDR104 | CDNS_SRS15_PVE) +#define SRS15_VAL_CID (CDNS_SRS15_HV4E | CDNS_SRS15_V18SE) + +#define CARD_REG_TIME_DELAY_US 100000 +#define WAIT_ICS_TIME_DELAY_US 5000 +#define RESET_SRS14 0x00000000 + +static struct sdhc_cdns_params cdns_params; +static struct sdhc_cdns_combo_phy sdhc_cdns_combo_phy_reg_info; +static struct sdhc_cdns_sdmmc sdhc_cdns_sdmmc_reg_info; + +/* Function to write general phy registers */ +static int sdhc_cdns_write_phy_reg(uint32_t phy_reg_addr, uint32_t phy_reg_addr_value, + uint32_t phy_reg_data, uint32_t phy_reg_data_value) +{ + uint32_t data = 0; + + /* Set PHY register address, write HRS04*/ + sys_write32(phy_reg_addr_value, phy_reg_addr); + + /* Set PHY register data, write HRS05 */ + sys_write32(phy_reg_data_value, phy_reg_data); + data = sys_read32(phy_reg_data); + + if (data != phy_reg_data_value) { + LOG_ERR("PHY_REG_DATA is not set properly"); + return -ENXIO; + } + + return 0; +} + +int sdhc_cdns_wait_ics(uint16_t timeout, uint32_t cdn_srs_res) +{ + /* Wait status command response ready */ + if (!WAIT_FOR(((sys_read32(cdn_srs_res) & CDNS_SRS11_ICS) + == CDNS_SRS11_ICS), timeout, k_msleep(1))) { + LOG_ERR("Timed out waiting for ICS response"); + return -ETIMEDOUT; + } + + return 0; +} + +static int sdhc_cdns_busy(void) +{ + unsigned int data; + + data = sys_read32(cdns_params.reg_base + SDHC_CDNS_SRS09); + return (data & CDNS_SRS09_STAT_DAT_BUSY) ? CARD_BUSY : CARD_NOT_BUSY; +} + +static int sdhc_cdns_card_present(void) +{ + uint32_t timeout = CARD_REG_TIME_DELAY_US; + + if (!WAIT_FOR((((sys_read32(cdns_params.reg_base + SDHC_CDNS_SRS09)) + & CDNS_SRS09_CI) == CDNS_SRS09_CI), + timeout, k_msleep(1))) { + LOG_ERR("Card detection timeout"); + return -ETIMEDOUT; + } + + return CARD_PRESENT; +} + +static int sdhc_cdns_vol_reset(void) +{ + /* Reset embedded card */ + sys_write32((7 << CDNS_SRS10_BVS) | (0 << CDNS_SRS10_BP), + (cdns_params.reg_base + SDHC_CDNS_SRS10)); + + /* + * Turn on supply voltage + * CDNS_SRS10_BVS = 7, CDNS_SRS10_BP = 1, BP2 only in UHS2 mode + */ + sys_write32((7 << CDNS_SRS10_BVS) | (1 << CDNS_SRS10_BP), + (cdns_params.reg_base + SDHC_CDNS_SRS10)); + + return 0; +} + +/* + * Values are taken from IP documents and calc_setting.py script + * with input value- mode sd_ds, + * sdmclk 5000, + * sdclk 10000, + * iocell_input_delay 2500, + * iocell_output_delay 2500 and + * delay_element 24 + */ +void cdns_sdhc_set_sdmmc_params(struct sdhc_cdns_combo_phy *sdhc_cdns_combo_phy_reg, + struct sdhc_cdns_sdmmc *sdhc_cdns_sdmmc_reg) +{ + /* Values are taken by the reference of cadence IP documents */ + sdhc_cdns_combo_phy_reg->cp_clk_wr_delay = 0; + sdhc_cdns_combo_phy_reg->cp_clk_wrdqs_delay = 0; + sdhc_cdns_combo_phy_reg->cp_data_select_oe_end = 1; + sdhc_cdns_combo_phy_reg->cp_dll_bypass_mode = 1; + sdhc_cdns_combo_phy_reg->cp_dll_locked_mode = 3; + sdhc_cdns_combo_phy_reg->cp_dll_start_point = 4; + sdhc_cdns_combo_phy_reg->cp_gate_cfg_always_on = 1; + sdhc_cdns_combo_phy_reg->cp_io_mask_always_on = 0; + sdhc_cdns_combo_phy_reg->cp_io_mask_end = 2; + sdhc_cdns_combo_phy_reg->cp_io_mask_start = 0; + sdhc_cdns_combo_phy_reg->cp_rd_del_sel = 52; + sdhc_cdns_combo_phy_reg->cp_read_dqs_cmd_delay = 0; + sdhc_cdns_combo_phy_reg->cp_read_dqs_delay = 0; + sdhc_cdns_combo_phy_reg->cp_sw_half_cycle_shift = 0; + sdhc_cdns_combo_phy_reg->cp_sync_method = 1; + sdhc_cdns_combo_phy_reg->cp_underrun_suppress = 1; + sdhc_cdns_combo_phy_reg->cp_use_ext_lpbk_dqs = 1; + sdhc_cdns_combo_phy_reg->cp_use_lpbk_dqs = 1; + sdhc_cdns_combo_phy_reg->cp_use_phony_dqs = 1; + sdhc_cdns_combo_phy_reg->cp_use_phony_dqs_cmd = 1; + + sdhc_cdns_sdmmc_reg->sdhc_extended_rd_mode = 1; + sdhc_cdns_sdmmc_reg->sdhc_extended_wr_mode = 1; + sdhc_cdns_sdmmc_reg->sdhc_hcsdclkadj = 6; + sdhc_cdns_sdmmc_reg->sdhc_idelay_val = 1; + sdhc_cdns_sdmmc_reg->sdhc_rdcmd_en = 1; + sdhc_cdns_sdmmc_reg->sdhc_rddata_en = 1; + sdhc_cdns_sdmmc_reg->sdhc_rw_compensate = 10; + sdhc_cdns_sdmmc_reg->sdhc_sdcfsh = 0; + sdhc_cdns_sdmmc_reg->sdhc_sdcfsl = 1; + sdhc_cdns_sdmmc_reg->sdhc_wrcmd0_dly = 1; + sdhc_cdns_sdmmc_reg->sdhc_wrcmd0_sdclk_dly = 0; + sdhc_cdns_sdmmc_reg->sdhc_wrcmd1_dly = 0; + sdhc_cdns_sdmmc_reg->sdhc_wrcmd1_sdclk_dly = 0; + sdhc_cdns_sdmmc_reg->sdhc_wrdata0_dly = 1; + sdhc_cdns_sdmmc_reg->sdhc_wrdata0_sdclk_dly = 0; + sdhc_cdns_sdmmc_reg->sdhc_wrdata1_dly = 0; + sdhc_cdns_sdmmc_reg->sdhc_wrdata1_sdclk_dly = 0; +} + +/* Phy register programing for phy init */ +static int sdhc_cdns_program_phy_reg(struct sdhc_cdns_combo_phy *sdhc_cdns_combo_phy_reg, + struct sdhc_cdns_sdmmc *sdhc_cdns_sdmmc_reg) +{ + uint32_t value = 0; + int ret = 0; + + /* + * program PHY_DQS_TIMING_REG + * This register controls the DQS related timing + */ + value = (CP_USE_EXT_LPBK_DQS(sdhc_cdns_combo_phy_reg->cp_use_ext_lpbk_dqs)) + | (CP_USE_LPBK_DQS(sdhc_cdns_combo_phy_reg->cp_use_lpbk_dqs)) + | (CP_USE_PHONY_DQS(sdhc_cdns_combo_phy_reg->cp_use_phony_dqs)) + | (CP_USE_PHONY_DQS_CMD(sdhc_cdns_combo_phy_reg->cp_use_phony_dqs_cmd)); + ret = sdhc_cdns_write_phy_reg(cdns_params.reg_base + SDHC_CDNS_HRS04, + cdns_params.combophy + PHY_DQS_TIMING_REG, cdns_params.reg_base + + SDHC_CDNS_HRS05, value); + if (ret != 0U) { + LOG_ERR("Error in PHY_DQS_TIMING_REG programming"); + return ret; + } + + /* + * program PHY_GATE_LPBK_CTRL_REG + * This register controls the gate and loopback control related timing. + */ + value = (CP_SYNC_METHOD(sdhc_cdns_combo_phy_reg->cp_sync_method)) + | (CP_SW_HALF_CYCLE_SHIFT(sdhc_cdns_combo_phy_reg->cp_sw_half_cycle_shift)) + | (CP_RD_DEL_SEL(sdhc_cdns_combo_phy_reg->cp_rd_del_sel)) + | (CP_UNDERRUN_SUPPRESS(sdhc_cdns_combo_phy_reg->cp_underrun_suppress)) + | (CP_GATE_CFG_ALWAYS_ON(sdhc_cdns_combo_phy_reg->cp_gate_cfg_always_on)); + ret = sdhc_cdns_write_phy_reg(cdns_params.reg_base + SDHC_CDNS_HRS04, + cdns_params.combophy + PHY_GATE_LPBK_CTRL_REG, cdns_params.reg_base + + SDHC_CDNS_HRS05, value); + if (ret != 0U) { + LOG_ERR("Error in PHY_GATE_LPBK_CTRL_REG programming"); + return -ret; + } + + /* + * program PHY_DLL_MASTER_CTRL_REG + * This register holds the control for the Master DLL logic. + */ + value = (CP_DLL_BYPASS_MODE(sdhc_cdns_combo_phy_reg->cp_dll_bypass_mode)) + | (CP_DLL_START_POINT(sdhc_cdns_combo_phy_reg->cp_dll_start_point)); + ret = sdhc_cdns_write_phy_reg(cdns_params.reg_base + SDHC_CDNS_HRS04, + cdns_params.combophy + PHY_DLL_MASTER_CTRL_REG, cdns_params.reg_base + + SDHC_CDNS_HRS05, value); + if (ret != 0U) { + LOG_ERR("Error in PHY_DLL_MASTER_CTRL_REG programming"); + return ret; + } + + /* + * program PHY_DLL_SLAVE_CTRL_REG + * This register holds the control for the slave DLL logic. + */ + value = (CP_READ_DQS_CMD_DELAY(sdhc_cdns_combo_phy_reg->cp_read_dqs_cmd_delay)) + | (CP_CLK_WRDQS_DELAY(sdhc_cdns_combo_phy_reg->cp_clk_wrdqs_delay)) + | (CP_CLK_WR_DELAY(sdhc_cdns_combo_phy_reg->cp_clk_wr_delay)) + | (CP_READ_DQS_DELAY(sdhc_cdns_combo_phy_reg->cp_read_dqs_delay)); + ret = sdhc_cdns_write_phy_reg(cdns_params.reg_base + SDHC_CDNS_HRS04, + cdns_params.combophy + PHY_DLL_SLAVE_CTRL_REG, cdns_params.reg_base + + SDHC_CDNS_HRS05, value); + if (ret != 0U) { + LOG_ERR("Error in PHY_DLL_SLAVE_CTRL_REG programming"); + return ret; + } + + /* + * program PHY_CTRL_REG + * This register handles the global control settings for the PHY. + */ + sys_write32(cdns_params.combophy + PHY_CTRL_REG, cdns_params.reg_base + + SDHC_CDNS_HRS04); + value = sys_read32(cdns_params.reg_base + SDHC_CDNS_HRS05); + + /* phony_dqs_timing=0 */ + value &= ~(CP_PHONY_DQS_TIMING_MASK << CP_PHONY_DQS_TIMING_SHIFT); + sys_write32(value, cdns_params.reg_base + SDHC_CDNS_HRS05); + + /* switch off DLL_RESET */ + do { + value = sys_read32(cdns_params.reg_base + SDHC_CDNS_HRS09); + value |= CDNS_HRS09_PHY_SW_RESET; + sys_write32(value, cdns_params.reg_base + SDHC_CDNS_HRS09); + value = sys_read32(cdns_params.reg_base + SDHC_CDNS_HRS09); + /* polling PHY_INIT_COMPLETE */ + } while ((value & CDNS_HRS09_PHY_INIT_COMP) != CDNS_HRS09_PHY_INIT_COMP); + + /* + * program PHY_DQ_TIMING_REG + * This register controls the DQ related timing. + */ + sdhc_cdns_combo_phy_reg->cp_io_mask_end = 0U; + value = (CP_IO_MASK_ALWAYS_ON(sdhc_cdns_combo_phy_reg->cp_io_mask_always_on)) + | (CP_IO_MASK_END(sdhc_cdns_combo_phy_reg->cp_io_mask_end)) + | (CP_IO_MASK_START(sdhc_cdns_combo_phy_reg->cp_io_mask_start)) + | (CP_DATA_SELECT_OE_END(sdhc_cdns_combo_phy_reg->cp_data_select_oe_end)); + + ret = sdhc_cdns_write_phy_reg(cdns_params.reg_base + SDHC_CDNS_HRS04, + cdns_params.combophy + PHY_DQ_TIMING_REG, cdns_params.reg_base + + SDHC_CDNS_HRS05, value); + if (ret != 0U) { + LOG_ERR("Error in PHY_DQ_TIMING_REG programming"); + return ret; + } + return 0; +} + +static int sdhc_cdns_cache_invd(int lba, uintptr_t buf, size_t size) +{ + int ret = 0; + + ret = arch_dcache_invd_range((void *)buf, size); + if (ret != 0) { + LOG_ERR("%s: error in invalidate dcache with ret %d", __func__, ret); + return ret; + } + + return 0; +} + +/* DMA preparation for the read and write operation */ +static int sdhc_cdns_prepare(uint32_t dma_start_addr, uintptr_t dma_buff, + struct sdhc_data *data) +{ + struct sdhc_cdns_desc *desc; + uint32_t desc_cnt, i; + uintptr_t base; + uint64_t desc_base; + uint32_t size = data->blocks * data->block_size; + + __ASSERT_NO_MSG(((dma_buff & CDNSMMC_ADDRESS_MASK) == 0) && + (cdns_params.desc_size > 0) && + ((cdns_params.desc_size & MMC_BLOCK_MASK) == 0)); + + arch_dcache_flush_range((void *)dma_buff, size); + + desc_cnt = (size + (SDMMC_DMA_MAX_BUFFER_SIZE) - 1) / + (SDMMC_DMA_MAX_BUFFER_SIZE); + __ASSERT_NO_MSG(desc_cnt * sizeof(struct sdhc_cdns_desc) < + cdns_params.desc_size); + + if (desc_cnt > CONFIG_CDNS_DESC_COUNT) { + LOG_ERR("Requested data transfer length %u greater than configured length %u", + size, (CONFIG_CDNS_DESC_COUNT * SDMMC_DMA_MAX_BUFFER_SIZE)); + return -EINVAL; + } + + /* + * Creating descriptor as per the desc_count and linked list of + * descriptor for contiguous desc alignment + */ + base = cdns_params.reg_base; + desc = (struct sdhc_cdns_desc *)cdns_params.desc_base; + desc_base = (uint64_t)desc; + i = 0; + + while ((i+1) < desc_cnt) { + desc->attr = ADMA_DESC_ATTR_VALID | ADMA_DESC_TRANSFER_DATA; + desc->reserved = 0; + desc->len = MAX_64KB_PAGE; + desc->addr_lo = (dma_buff & 0xffffffff) + (SDMMC_DMA_MAX_BUFFER_SIZE * i); + desc->addr_hi = (dma_buff >> 32) & 0xffffffff; + size -= SDMMC_DMA_MAX_BUFFER_SIZE; + desc++; + i++; + } + + desc->attr = ADMA_DESC_ATTR_VALID | ADMA_DESC_TRANSFER_DATA | + ADMA_DESC_ATTR_END; + desc->reserved = 0; + desc->len = size; + desc->addr_lo = (dma_buff & 0xffffffff) + (SDMMC_DMA_MAX_BUFFER_SIZE * i); + desc->addr_hi = (dma_buff >> 32) & 0xffffffff; + + sys_write32((uint32_t)desc_base, cdns_params.reg_base + SDHC_CDNS_SRS22); + sys_write32((uint32_t)(desc_base >> 32), cdns_params.reg_base + SDHC_CDNS_SRS23); + arch_dcache_flush_range((void *)cdns_params.desc_base, + desc_cnt * sizeof(struct sdhc_cdns_desc)); + + sys_write32((data->block_size << CDNS_SRS01_BLK_SIZE | + data->blocks << CDNS_SRS01_BLK_COUNT_CT | CDNS_SRS01_SDMA_BUF), + cdns_params.reg_base + SDHC_CDNS_SRS01); + + return 0; +} + +static int sdhc_cdns_host_set_clk(int clk) +{ + uint32_t sdclkfsval = 0; + uint32_t dtcvval = 0xe; + int ret = 0; + + sdclkfsval = (cdns_params.clk_rate / 2000) / clk; + sys_write32(0, cdns_params.reg_base + SDHC_CDNS_SRS11); + sys_write32(((dtcvval << CDNS_SRS11_DTCV) | (sdclkfsval << CDNS_SRS11_SDCLKFS) | + (1 << CDNS_SRS11_ICE)), cdns_params.reg_base + SDHC_CDNS_SRS11); + + ret = sdhc_cdns_wait_ics(WAIT_ICS_TIME_DELAY_US, cdns_params.reg_base + SDHC_CDNS_SRS11); + if (ret != 0) { + return ret; + } + + /* Enable DLL reset */ + sys_clear_bit(cdns_params.reg_base + SDHC_CDNS_HRS09, 0); + /* Set extended_wr_mode */ + sys_write32(((sys_read32(cdns_params.reg_base + SDHC_CDNS_HRS09) + & 0xFFFFFFF7) | (1 << CDNS_HRS09_EXT_WR_MODE)), (cdns_params.reg_base + + SDHC_CDNS_HRS09)); + /* Release DLL reset */ + sys_set_bit(cdns_params.reg_base + SDHC_CDNS_HRS09, 1); + sys_set_bits(cdns_params.reg_base + SDHC_CDNS_HRS09, (3 << CDNS_HRS09_RDCMD_EN)); + + sys_write32(((dtcvval << CDNS_SRS11_DTCV) | (sdclkfsval << CDNS_SRS11_SDCLKFS) + | (1 << CDNS_SRS11_ICE) | (1 << CDNS_SRS11_SDCE)), + cdns_params.reg_base + SDHC_CDNS_SRS11); + + sys_write32(0xFFFFFFFF, cdns_params.reg_base + SDHC_CDNS_SRS13); + + return 0; +} + +static int sdhc_cdns_set_ios(unsigned int clk, unsigned int width) +{ + int ret = 0; + + switch (width) { + case SDHC_BUS_WIDTH1BIT: + sys_clear_bit(cdns_params.reg_base + SDHC_CDNS_SRS10, WIDTH_BIT1); + break; + case SDHC_BUS_WIDTH4BIT: + sys_set_bit(cdns_params.reg_base + SDHC_CDNS_SRS10, WIDTH_BIT4); + break; + case SDHC_BUS_WIDTH8BIT: + sys_set_bit(cdns_params.reg_base + SDHC_CDNS_SRS10, WIDTH_BIT8); + break; + default: + __ASSERT_NO_MSG(0); + break; + } + + /* Perform clock configuration when SD clock is not gated */ + if (clk != 0) { + ret = sdhc_cdns_host_set_clk(clk); + if (ret != 0) { + LOG_ERR("%s: Clock configuration failed", __func__); + return ret; + } + } + + return 0; +} + +/* Programming HRS register for initialisation */ +static int sdhc_cdns_init_hrs_io(struct sdhc_cdns_combo_phy *sdhc_cdns_combo_phy_reg, + struct sdhc_cdns_sdmmc *sdhc_cdns_sdmmc_reg) +{ + uint32_t value = 0; + int ret = 0; + + /* + * program HRS09, register 42 + * PHY Control and Status Register + */ + value = (CDNS_HRS09_RDDATA_EN(sdhc_cdns_sdmmc_reg->sdhc_rddata_en)) + | (CDNS_HRS09_RDCMD(sdhc_cdns_sdmmc_reg->sdhc_rdcmd_en)) + | (CDNS_HRS09_EXTENDED_WR(sdhc_cdns_sdmmc_reg->sdhc_extended_wr_mode)) + | (CDNS_HRS09_EXT_RD_MODE(sdhc_cdns_sdmmc_reg->sdhc_extended_rd_mode)); + sys_write32(value, cdns_params.reg_base + SDHC_CDNS_HRS09); + + /* + * program HRS10, register 43 + * Host Controller SDCLK start point adjustment + */ + value = (SDHC_HRS10_HCSDCLKADJ(sdhc_cdns_sdmmc_reg->sdhc_hcsdclkadj)); + sys_write32(value, cdns_params.reg_base + SDHC_CDNS_HRS10); + + /* + * program HRS16, register 48 + * CMD/DAT output delay + */ + value = (CDNS_HRS16_WRDATA1_SDCLK_DLY(sdhc_cdns_sdmmc_reg->sdhc_wrdata1_sdclk_dly)) + | (CDNS_HRS16_WRDATA0_SDCLK_DLY(sdhc_cdns_sdmmc_reg->sdhc_wrdata0_sdclk_dly)) + | (CDNS_HRS16_WRCMD1_SDCLK_DLY(sdhc_cdns_sdmmc_reg->sdhc_wrcmd1_sdclk_dly)) + | (CDNS_HRS16_WRCMD0_SDCLK_DLY(sdhc_cdns_sdmmc_reg->sdhc_wrcmd0_sdclk_dly)) + | (CDNS_HRS16_WRDATA1_DLY(sdhc_cdns_sdmmc_reg->sdhc_wrdata1_dly)) + | (CDNS_HRS16_WRDATA0_DLY(sdhc_cdns_sdmmc_reg->sdhc_wrdata0_dly)) + | (CDNS_HRS16_WRCMD1_DLY(sdhc_cdns_sdmmc_reg->sdhc_wrcmd1_dly)) + | (CDNS_HRS16_WRCMD0_DLY(sdhc_cdns_sdmmc_reg->sdhc_wrcmd0_dly)); + sys_write32(value, cdns_params.reg_base + SDHC_CDNS_HRS16); + + /* + * program HRS07, register 40 + * IO Delay Information Register + */ + value = (CDNS_HRS07_RW_COMPENSATE(sdhc_cdns_sdmmc_reg->sdhc_rw_compensate)) + | (CDNS_HRS07_IDELAY_VAL(sdhc_cdns_sdmmc_reg->sdhc_idelay_val)); + sys_write32(value, cdns_params.reg_base + SDHC_CDNS_HRS07); + + return ret; +} + +static int sdhc_cdns_set_clk(struct sdhc_cdns_params *cdn_sdmmc_dev_type_params) +{ + uint32_t dtcvval, sdclkfsval; + int ret = 0; + + dtcvval = DTC_VAL; + sdclkfsval = 0; + + /* Condition for Default speed mode and SDR12 and SDR_BC */ + if ((cdn_sdmmc_dev_type_params->cdn_sdmmc_dev_type == SD_DS) || + (cdn_sdmmc_dev_type_params->cdn_sdmmc_dev_type == SD_UHS_SDR12) || + (cdn_sdmmc_dev_type_params->cdn_sdmmc_dev_type == EMMC_SDR_BC)) { + sdclkfsval = 4; + } else if ((cdn_sdmmc_dev_type_params->cdn_sdmmc_dev_type == SD_HS) || + (cdn_sdmmc_dev_type_params->cdn_sdmmc_dev_type == SD_UHS_SDR25) || + (cdn_sdmmc_dev_type_params->cdn_sdmmc_dev_type == SD_UHS_DDR50) || + (cdn_sdmmc_dev_type_params->cdn_sdmmc_dev_type == EMMC_SDR)) { + sdclkfsval = 2; + } else if ((cdn_sdmmc_dev_type_params->cdn_sdmmc_dev_type == SD_UHS_SDR50) || + (cdn_sdmmc_dev_type_params->cdn_sdmmc_dev_type == EMMC_DDR) || + (cdn_sdmmc_dev_type_params->cdn_sdmmc_dev_type == EMMC_HS400) || + (cdn_sdmmc_dev_type_params->cdn_sdmmc_dev_type == EMMC_HS400ES)) { + sdclkfsval = 1; + } else if ((cdn_sdmmc_dev_type_params->cdn_sdmmc_dev_type == SD_UHS_SDR104) || + (cdn_sdmmc_dev_type_params->cdn_sdmmc_dev_type == EMMC_HS200)) { + sdclkfsval = 0; + } + + /* Disabling SD clock enable */ + sys_write32(0, cdns_params.reg_base + SDHC_CDNS_SRS11); + sys_write32((dtcvval << CDNS_SRS11_DTCV) | + (sdclkfsval << CDNS_SRS11_SDCLKFS) | (1 << CDNS_SRS11_ICE), + cdns_params.reg_base + SDHC_CDNS_SRS11); + ret = sdhc_cdns_wait_ics(WAIT_ICS_TIME_DELAY_US, cdns_params.reg_base + SDHC_CDNS_SRS11); + if (ret != 0) { + return ret; + } + + /* Enable DLL reset */ + sys_clear_bit(cdns_params.reg_base + SDHC_CDNS_HRS09, 0); + /* Set extended_wr_mode */ + sys_write32(((sys_read32(cdns_params.reg_base + SDHC_CDNS_HRS09) & + 0xFFFFFFF7) | (1 << CDNS_HRS09_EXT_WR_MODE)), (cdns_params.reg_base + + SDHC_CDNS_HRS09)); + /* Release DLL reset */ + sys_set_bit(cdns_params.reg_base + SDHC_CDNS_HRS09, 1); + sys_set_bits(cdns_params.reg_base + SDHC_CDNS_HRS09, (3 << CDNS_HRS09_RDCMD_EN)); + + sys_write32((dtcvval << CDNS_SRS11_DTCV) | (sdclkfsval << CDNS_SRS11_SDCLKFS) | + (1 << CDNS_SRS11_ICE) | (1 << CDNS_SRS11_SDCE), cdns_params.reg_base + + SDHC_CDNS_SRS11); + + sys_write32(0xFFFFFFFF, cdns_params.reg_base + SDHC_CDNS_SRS13); + return 0; +} + +static int sdhc_cdns_reset(void) +{ + int32_t timeout; + + sys_clear_bits(cdns_params.reg_base + SDHC_CDNS_SRS11, 0xFFFF); + + /* Software reset */ + sys_set_bit(cdns_params.reg_base + SDHC_CDNS_HRS00, CDNS_HRS00_SWR); + + /* Wait status command response ready */ + timeout = CARD_REG_TIME_DELAY_US; + if (!WAIT_FOR(((sys_read32(cdns_params.reg_base + SDHC_CDNS_HRS00) & + CDNS_HRS00_SWR) == 0), timeout, k_msleep(1))) { + LOG_ERR("Software reset is not completed...timedout"); + return -ETIMEDOUT; + } + + /* Step 1, switch on DLL_RESET */ + sys_clear_bit(cdns_params.reg_base + SDHC_CDNS_HRS09, CDNS_HRS09_PHY_SW_RESET); + + return 0; +} + +static int sdhc_cdns_init(void) +{ + int ret = 0; + + ret = sdhc_cdns_program_phy_reg(&sdhc_cdns_combo_phy_reg_info, &sdhc_cdns_sdmmc_reg_info); + if (ret != 0U) { + LOG_ERR("SoftPhy register configuration failed"); + return ret; + } + + ret = sdhc_cdns_init_hrs_io(&sdhc_cdns_combo_phy_reg_info, &sdhc_cdns_sdmmc_reg_info); + if (ret != 0U) { + LOG_ERR("Configuration for HRS IO reg failed"); + return ret; + } + + ret = sdhc_cdns_card_present(); + if (ret != CARD_PRESENT) { + LOG_ERR("SD card does not detect"); + return -ETIMEDOUT; + } + + ret = sdhc_cdns_vol_reset(); + if (ret != 0U) { + LOG_ERR("SD/MMC card reset failed"); + return ret; + } + + ret = sdhc_cdns_set_clk(&cdns_params); + if (ret != 0U) { + LOG_ERR("Host controller set clk failed"); + return ret; + } + + return 0; +} + +static int sdhc_cdns_send_cmd(struct sdmmc_cmd *cmd, struct sdhc_data *data) +{ + uint32_t op = 0; + uint32_t value; + uintptr_t base; + int32_t timeout; + uint32_t cmd_indx; + uint32_t status_check = 0; + + __ASSERT(cmd, "Assert %s function call", __func__); + base = cdns_params.reg_base; + cmd_indx = (cmd->cmd_idx) << CDNS_SRS03_COM_IDX; + + if (data) { + switch (cmd->cmd_idx) { + case SD_SWITCH: + op = CDNS_SRS03_DATA_PRSNT; + sys_set_bits(cdns_params.reg_base + SDHC_CDNS_SRS10, SRS10_VAL_SW); + sys_set_bits(cdns_params.reg_base + SDHC_CDNS_SRS11, SRS11_VAL_GEN); + sys_set_bits(cdns_params.reg_base + SDHC_CDNS_SRS15, SRS15_VAL_GEN); + break; + + case SD_WRITE_SINGLE_BLOCK: + case SD_READ_SINGLE_BLOCK: + op = CDNS_SRS03_DATA_PRSNT; + sys_set_bits(cdns_params.reg_base + SDHC_CDNS_SRS10, SRS10_VAL_READ); + sys_set_bits(cdns_params.reg_base + SDHC_CDNS_SRS11, SRS11_VAL_GEN); + sys_set_bits(cdns_params.reg_base + SDHC_CDNS_SRS15, SRS15_VAL_RD_WR); + sys_write32(CDNS_SRS00_SAAR, cdns_params.reg_base + SDHC_CDNS_SRS00); + break; + + case SD_WRITE_MULTIPLE_BLOCK: + case SD_READ_MULTIPLE_BLOCK: + op = CDNS_SRS03_DATA_PRSNT | AUTO_CMD23 | CDNS_SRS03_MULTI_BLK_READ; + sys_set_bits(cdns_params.reg_base + SDHC_CDNS_SRS10, SRS10_VAL_READ); + sys_set_bits(cdns_params.reg_base + SDHC_CDNS_SRS11, SRS11_VAL_GEN); + sys_set_bits(cdns_params.reg_base + SDHC_CDNS_SRS15, SRS15_VAL_RD_WR); + sys_write32(CDNS_SRS00_SAAR, cdns_params.reg_base + SDHC_CDNS_SRS00); + break; + + case SD_APP_SEND_SCR: + op = CDNS_SRS03_DATA_PRSNT; + sys_set_bits(cdns_params.reg_base + SDHC_CDNS_SRS10, ADMA2_32); + sys_set_bits(cdns_params.reg_base + SDHC_CDNS_SRS11, SRS11_VAL_GEN); + sys_set_bits(cdns_params.reg_base + SDHC_CDNS_SRS15, SRS15_VAL_GEN); + break; + + default: + op = 0; + break; + } + } else { + switch (cmd->cmd_idx) { + case SD_GO_IDLE_STATE: + sys_set_bits(cdns_params.reg_base + SDHC_CDNS_SRS11, SRS11_VAL_CID); + sys_set_bits(cdns_params.reg_base + SDHC_CDNS_SRS15, CDNS_SRS15_HV4E); + break; + + case SD_ALL_SEND_CID: + sys_set_bits(cdns_params.reg_base + SDHC_CDNS_SRS11, SRS11_VAL_CID); + sys_set_bits(cdns_params.reg_base + SDHC_CDNS_SRS15, SRS15_VAL_CID); + break; + + case SD_SEND_IF_COND: + op = CDNS_SRS03_CMD_IDX_CHK_EN; + sys_set_bits(cdns_params.reg_base + SDHC_CDNS_SRS11, SRS11_VAL_GEN); + sys_set_bits(cdns_params.reg_base + SDHC_CDNS_SRS15, CDNS_SRS15_HV4E); + break; + + case SD_STOP_TRANSMISSION: + op = CMD_STOP_ABORT_CMD; + break; + + case SD_SEND_STATUS: + break; + + case SD_SELECT_CARD: + op = CDNS_SRS03_MULTI_BLK_READ; + break; + + default: + op = 0; + break; + } + } + + switch (cmd->resp_type) { + case SD_RSP_TYPE_NONE: + op |= (CDNS_SRS03_CMD_READ | CDNS_SRS03_MULTI_BLK_READ | + CDNS_SRS03_DMA_EN | CDNS_SRS03_BLK_CNT_EN); + break; + + case SD_RSP_TYPE_R2: + op |= (CDNS_SRS03_CMD_READ | CDNS_SRS03_MULTI_BLK_READ | + CDNS_SRS03_DMA_EN | CDNS_SRS03_BLK_CNT_EN | + RES_TYPE_SEL_136 | CDNS_SRS03_RESP_CRC); + break; + + case SD_RSP_TYPE_R3: + op |= (CDNS_SRS03_CMD_READ | CDNS_SRS03_MULTI_BLK_READ | + CDNS_SRS03_DMA_EN | CDNS_SRS03_BLK_CNT_EN | RES_TYPE_SEL_48); + break; + + case SD_RSP_TYPE_R1: + if ((cmd->cmd_idx == SD_WRITE_SINGLE_BLOCK) || (cmd->cmd_idx + == SD_WRITE_MULTIPLE_BLOCK)) { + op |= (CDNS_SRS03_DMA_EN | CDNS_SRS03_BLK_CNT_EN | RES_TYPE_SEL_48 + | CDNS_SRS03_RESP_CRC | CDNS_SRS03_CMD_IDX_CHK_EN); + } else { + op |= (CDNS_SRS03_DMA_EN | CDNS_SRS03_BLK_CNT_EN | CDNS_SRS03_CMD_READ + | RES_TYPE_SEL_48 | CDNS_SRS03_RESP_CRC | CDNS_SRS03_CMD_IDX_CHK_EN); + } + break; + + default: + op |= (CDNS_SRS03_DMA_EN | CDNS_SRS03_BLK_CNT_EN | CDNS_SRS03_CMD_READ | + CDNS_SRS03_MULTI_BLK_READ | RES_TYPE_SEL_48 | CDNS_SRS03_RESP_CRC | + CDNS_SRS03_CMD_IDX_CHK_EN); + break; + } + + timeout = CARD_REG_TIME_DELAY_US; + if (!WAIT_FOR((sdhc_cdns_busy() == 0), timeout, k_msleep(1))) { + k_panic(); + } + + sys_write32(~0, cdns_params.reg_base + SDHC_CDNS_SRS12); + + sys_write32(cmd->cmd_arg, cdns_params.reg_base + SDHC_CDNS_SRS02); + sys_write32(RESET_SRS14, cdns_params.reg_base + SDHC_CDNS_SRS14); + sys_write32(op | cmd_indx, cdns_params.reg_base + SDHC_CDNS_SRS03); + + timeout = CARD_REG_TIME_DELAY_US; + if (!WAIT_FOR(((((sys_read32(cdns_params.reg_base + SDHC_CDNS_SRS12)) & + CDNS_SRS03_CMD_DONE) == 1) | (((sys_read32(cdns_params.reg_base + + SDHC_CDNS_SRS12)) & ERROR_INT) == ERROR_INT)), timeout, k_busy_wait(1))) { + LOG_ERR("Response timeout SRS12"); + return -ETIMEDOUT; + } + + value = sys_read32(cdns_params.reg_base + SDHC_CDNS_SRS12); + status_check = value & CDNS_SRS12_ERR_MASK; + if (status_check != 0U) { + LOG_ERR("SD host controller send command failed, SRS12 = %X", status_check); + return -EIO; + } + + if ((op & RES_TYPE_SEL_48) || (op & RES_TYPE_SEL_136)) { + cmd->resp_data[0] = sys_read32(cdns_params.reg_base + SDHC_CDNS_SRS04); + if (op & RES_TYPE_SEL_136) { + cmd->resp_data[1] = sys_read32(cdns_params.reg_base + SDHC_CDNS_SRS05); + cmd->resp_data[2] = sys_read32(cdns_params.reg_base + SDHC_CDNS_SRS06); + cmd->resp_data[3] = sys_read32(cdns_params.reg_base + SDHC_CDNS_SRS07); + + /* 136-bit: RTS=01b, Response field R[127:8] - RESP3[23:0], + * RESP2[31:0], RESP1[31:0], RESP0[31:0] + * Subsystem expects 128 bits response but cadence SDHC sends + * 120 bits response from R[127:8]. Bits manupulation to address + * the correct responses for the 136 bit response type. + */ + cmd->resp_data[3] = ((cmd->resp_data[3] << 8) | ((cmd->resp_data[2] >> 24) + & CDNS_CSD_BYTE_MASK)); + cmd->resp_data[2] = ((cmd->resp_data[2] << 8) | ((cmd->resp_data[1] >> 24) + & CDNS_CSD_BYTE_MASK)); + cmd->resp_data[1] = ((cmd->resp_data[1] << 8) | ((cmd->resp_data[0] >> 24) + & CDNS_CSD_BYTE_MASK)); + cmd->resp_data[0] = (cmd->resp_data[0] << 8); + } + } + + return 0; +} + +static const struct sdhc_cdns_ops cdns_sdmmc_ops = { + .init = sdhc_cdns_init, + .send_cmd = sdhc_cdns_send_cmd, + .card_present = sdhc_cdns_card_present, + .set_ios = sdhc_cdns_set_ios, + .prepare = sdhc_cdns_prepare, + .cache_invd = sdhc_cdns_cache_invd, + .busy = sdhc_cdns_busy, + .reset = sdhc_cdns_reset, +}; + +void sdhc_cdns_sdmmc_init(struct sdhc_cdns_params *params, struct sdmmc_device_info *info, + const struct sdhc_cdns_ops **cb_sdmmc_ops) +{ + __ASSERT_NO_MSG((params != NULL) && + ((params->reg_base & MMC_BLOCK_MASK) == 0) && + ((params->desc_size & MMC_BLOCK_MASK) == 0) && + ((params->reg_phy & MMC_BLOCK_MASK) == 0) && + (params->desc_size > 0) && + (params->clk_rate > 0) && + ((params->bus_width == MMC_BUS_WIDTH_1) || + (params->bus_width == MMC_BUS_WIDTH_4) || + (params->bus_width == MMC_BUS_WIDTH_8))); + + memcpy(&cdns_params, params, sizeof(struct sdhc_cdns_params)); + cdns_params.cdn_sdmmc_dev_type = info->cdn_sdmmc_dev_type; + *cb_sdmmc_ops = &cdns_sdmmc_ops; + + cdns_sdhc_set_sdmmc_params(&sdhc_cdns_combo_phy_reg_info, &sdhc_cdns_sdmmc_reg_info); +} diff --git a/drivers/sdhc/sdhc_cdns_ll.h b/drivers/sdhc/sdhc_cdns_ll.h new file mode 100644 index 00000000000..c07e446dad0 --- /dev/null +++ b/drivers/sdhc/sdhc_cdns_ll.h @@ -0,0 +1,489 @@ +/* + * Copyright (C) 2023 Intel Corporation + * SPDX-License-Identifier: Apache-2.0 + */ + +#include +#include + +/* HRS09 */ +#define CDNS_HRS09_PHY_SW_RESET BIT(0) +#define CDNS_HRS09_PHY_INIT_COMP BIT(1) +#define CDNS_HRS09_EXT_RD_MODE(x) ((x) << 2) +#define CDNS_HRS09_EXT_WR_MODE 3 +#define CDNS_HRS09_EXTENDED_WR(x) ((x) << 3) +#define CDNS_HRS09_RDCMD_EN 15 +#define CDNS_HRS09_RDCMD(x) ((x) << 15) +#define CDNS_HRS09_RDDATA_EN(x) ((x) << 16) + +/* HRS00 */ +#define CDNS_HRS00_SWR BIT(0) + +/* CMD_DATA_OUTPUT */ +#define SDHC_CDNS_HRS16 0x40 + +/* SRS09 */ +#define CDNS_SRS09_STAT_DAT_BUSY BIT(2) +#define CDNS_SRS09_CI BIT(16) + +/* SRS10 */ +#define CDNS_SRS10_DTW 1 +#define CDNS_SRS10_EDTW 5 +#define CDNS_SRS10_BP 8 +#define CDNS_SRS10_BVS 9 + +/* data bus width */ +#define WIDTH_BIT1 CDNS_SRS10_DTW +#define WIDTH_BIT4 CDNS_SRS10_DTW +#define WIDTH_BIT8 CDNS_SRS10_EDTW + +/* SRS11 */ +#define CDNS_SRS11_ICE BIT(0) +#define CDNS_SRS11_ICS BIT(1) +#define CDNS_SRS11_SDCE BIT(2) +#define CDNS_SRS11_USDCLKFS 6 +#define CDNS_SRS11_SDCLKFS 8 +#define CDNS_SRS11_DTCV 16 +#define CDNS_SRS11_SRFA BIT(24) +#define CDNS_SRS11_SRCMD BIT(25) +#define CDNS_SRS11_SRDAT BIT(26) + +/* + * This value determines the interval by which DAT line timeouts are detected + * The interval can be computed as below: + * • 1111b - Reserved + * • 1110b - t_sdmclk*2(27+2) + * • 1101b - t_sdmclk*2(26+2) + */ +#define READ_CLK (0xa << 16) +#define WRITE_CLK (0xe << 16) +#define DTC_VAL 0xE + +/* SRS12 */ +#define CDNS_SRS12_CC 0U +#define CDNS_SRS12_TC 1 +#define CDNS_SRS12_EINT 15 + +/* SRS01 */ +#define CDNS_SRS01_BLK_SIZE 0U +#define CDNS_SRS01_SDMA_BUF 7 << 12 +#define CDNS_SRS01_BLK_COUNT_CT 16 + +/* SRS15 Registers */ +#define CDNS_SRS15_SDR12 0U +#define CDNS_SRS15_SDR25 BIT(16) +#define CDNS_SRS15_SDR50 (2 << 16) +#define CDNS_SRS15_SDR104 (3 << 16) +#define CDNS_SRS15_DDR50 (4 << 16) +/* V18SE is 0 for DS and HS, 1 for UHS-I */ +#define CDNS_SRS15_V18SE BIT(19) +#define CDNS_SRS15_CMD23_EN BIT(27) +/* HC4E is 0 means version 3.0 and 1 means v 4.0 */ +#define CDNS_SRS15_HV4E BIT(28) +#define CDNS_SRS15_BIT_AD_32 0U +#define CDNS_SRS15_BIT_AD_64 BIT(29) +#define CDNS_SRS15_PVE BIT(31) + +/* Combo PHY */ +#define PHY_DQ_TIMING_REG 0x0 +#define PHY_DQS_TIMING_REG 0x04 +#define PHY_GATE_LPBK_CTRL_REG 0x08 +#define PHY_DLL_MASTER_CTRL_REG 0x0C +#define PHY_DLL_SLAVE_CTRL_REG 0x10 +#define PHY_CTRL_REG 0x80 + +#define PERIPHERAL_SDMMC_MASK 0x60 +#define PERIPHERAL_SDMMC_OFFSET 6 +#define DFI_INTF_MASK 0x1 + +/* PHY_DQS_TIMING_REG */ +#define CP_USE_EXT_LPBK_DQS(x) (x << 22) +#define CP_USE_LPBK_DQS(x) (x << 21) +#define CP_USE_PHONY_DQS(x) (x << 20) +#define CP_USE_PHONY_DQS_CMD(x) (x << 19) + +/* PHY_GATE_LPBK_CTRL_REG */ +#define CP_SYNC_METHOD(x) ((x) << 31) +#define CP_SW_HALF_CYCLE_SHIFT(x) ((x) << 28) +#define CP_RD_DEL_SEL(x) ((x) << 19) +#define CP_UNDERRUN_SUPPRESS(x) ((x) << 18) +#define CP_GATE_CFG_ALWAYS_ON(x) ((x) << 6) + +/* PHY_DLL_MASTER_CTRL_REG */ +#define CP_DLL_BYPASS_MODE(x) ((x) << 23) +#define CP_DLL_START_POINT(x) ((x) << 0) + +/* PHY_DLL_SLAVE_CTRL_REG */ +#define CP_READ_DQS_CMD_DELAY(x) ((x) << 24) +#define CP_CLK_WRDQS_DELAY(x) ((x) << 16) +#define CP_CLK_WR_DELAY(x) ((x) << 8) +#define CP_READ_DQS_DELAY(x) (x) + +/* PHY_DQ_TIMING_REG */ +#define CP_IO_MASK_ALWAYS_ON(x) ((x) << 31) +#define CP_IO_MASK_END(x) ((x) << 27) +#define CP_IO_MASK_START(x) ((x) << 24) +#define CP_DATA_SELECT_OE_END(x) (x) + +/* SW RESET REG */ +#define SDHC_CDNS_HRS00 (0x00) +#define CDNS_HRS00_SWR BIT(0) + +/* PHY access port */ +#define SDHC_CDNS_HRS04 0x10 +#define CDNS_HRS04_ADDR GENMASK(5, 0) + +/* PHY data access port */ +#define SDHC_CDNS_HRS05 0x14 + +/* eMMC control registers */ +#define SDHC_CDNS_HRS06 0x18 + +/* PHY_CTRL_REG */ +#define CP_PHONY_DQS_TIMING_MASK 0x3F +#define CP_PHONY_DQS_TIMING_SHIFT 4 + +/* SRS */ +#define SDHC_CDNS_SRS00 0x200 +#define SDHC_CDNS_SRS01 0x204 +#define SDHC_CDNS_SRS02 0x208 +#define SDHC_CDNS_SRS03 0x20c +#define SDHC_CDNS_SRS04 0x210 +#define SDHC_CDNS_SRS05 0x214 +#define SDHC_CDNS_SRS06 0x218 +#define SDHC_CDNS_SRS07 0x21C +#define SDHC_CDNS_SRS08 0x220 +#define SDHC_CDNS_SRS09 0x224 +#define SDHC_CDNS_SRS10 0x228 +#define SDHC_CDNS_SRS11 0x22C +#define SDHC_CDNS_SRS12 0x230 +#define SDHC_CDNS_SRS13 0x234 +#define SDHC_CDNS_SRS14 0x238 +#define SDHC_CDNS_SRS15 0x23c +#define SDHC_CDNS_SRS21 0x254 +#define SDHC_CDNS_SRS22 0x258 +#define SDHC_CDNS_SRS23 0x25c + +/* SRS00 */ +#define CDNS_SRS00_SAAR 1 + +/* SRS03 */ +#define CDNS_SRS03_CMD_START BIT(31) +#define CDNS_SRS03_CMD_USE_HOLD_REG BIT(29) +#define CDNS_SRS03_CMD_UPDATE_CLK_ONLY BIT(21) +#define CDNS_SRS03_CMD_SEND_INIT BIT(15) +/* Command type */ +#define CDNS_SRS03_CMD_TYPE BIT(22) +#define CMD_STOP_ABORT_CMD (3 << 22) +#define CMD_RESUME_CMD (2 << 22) +#define CMD_SUSPEND_CMD BIT(22) +#define CDNS_SRS03_DATA_PRSNT BIT(21) +#define CDNS_SRS03_CMD_IDX_CHK_EN BIT(20) +#define CDNS_SRS03_CMD_READ BIT(4) +#define CDNS_SRS03_MULTI_BLK_READ BIT(5) +#define CDNS_SRS03_RESP_ERR BIT(7) +#define CDNS_SRS03_RESP_CRC BIT(19) +#define CDNS_SRS03_CMD_DONE BIT(0) +/* Response type select */ +#define CDNS_SRS03_RES_TYPE_SEL BIT(16) +#define RES_TYPE_SEL_48 (2 << 16) +#define RES_TYPE_SEL_136 (1 << 16) +#define RES_TYPE_SEL_48_B (3 << 16) +#define RES_TYPE_SEL_NO (0 << 16) +/* Auto CMD Enable */ +#define CDNS_SRS03_AUTO_CMD_EN BIT(2) +#define AUTO_CMD23 (2 << 2) +#define AUTO_CMD12 BIT(2) +#define AUTO_CMD_AUTO (3 << 2) +#define CDNS_SRS03_COM_IDX 24 +#define ERROR_INT BIT(15) +#define CDNS_SRS03_DMA_EN BIT(0) +#define CDNS_SRS03_BLK_CNT_EN BIT(1) + +/* HRS07 */ +#define SDHC_CDNS_HRS07 0x1c +#define CDNS_HRS07_IDELAY_VAL(x) (x) +#define CDNS_HRS07_RW_COMPENSATE(x) ((x) << 16) + +/* PHY reset port */ +#define SDHC_CDNS_HRS09 0x24 + +/* HRS10 */ +/* PHY reset port */ +#define SDHC_CDNS_HRS10 0x28 + +/* HCSDCLKADJ DATA; DDR Mode */ +#define SDHC_HRS10_HCSDCLKADJ(x) ((x) << 16) + +/* HRS16 */ +#define CDNS_HRS16_WRCMD0_DLY(x) (x) +#define CDNS_HRS16_WRCMD1_DLY(x) ((x) << 4) +#define CDNS_HRS16_WRDATA0_DLY(x) ((x) << 8) +#define CDNS_HRS16_WRDATA1_DLY(x) ((x) << 12) +#define CDNS_HRS16_WRCMD0_SDCLK_DLY(x) ((x) << 16) +#define CDNS_HRS16_WRCMD1_SDCLK_DLY(x) ((x) << 20) +#define CDNS_HRS16_WRDATA0_SDCLK_DLY(x) ((x) << 24) +#define CDNS_HRS16_WRDATA1_SDCLK_DLY(x) ((x) << 28) + +/* Shared Macros */ +#define SDMMC_CDN(_reg) (SDMMC_CDN_REG_BASE + \ + (SDMMC_CDN_##_reg)) + +/* MMC Peripheral Definition */ +#define MMC_BLOCK_SIZE 512U +#define MMC_BLOCK_MASK (MMC_BLOCK_SIZE - 1) +#define MMC_BOOT_CLK_RATE (400 * 1000) + +#define OCR_POWERUP BIT(31) +#define OCR_HCS BIT(30) + +#define OCR_3_5_3_6 BIT(23) +#define OCR_3_4_3_5 BIT(22) +#define OCR_3_3_3_4 BIT(21) +#define OCR_3_2_3_3 BIT(20) +#define OCR_3_1_3_2 BIT(19) +#define OCR_3_0_3_1 BIT(18) +#define OCR_2_9_3_0 BIT(17) +#define OCR_2_8_2_9 BIT(16) +#define OCR_2_7_2_8 BIT(15) +#define OCR_VDD_MIN_2V7 GENMASK(23, 15) +#define OCR_VDD_MIN_2V0 GENMASK(14, 8) +#define OCR_VDD_MIN_1V7 BIT(7) + +#define MMC_RSP_48 BIT(0) +#define MMC_RSP_136 BIT(1) /* 136 bit response */ +#define MMC_RSP_CRC BIT(2) /* expect valid crc */ +#define MMC_RSP_CMD_IDX BIT(3) /* response contains cmd idx */ +#define MMC_RSP_BUSY BIT(4) /* device may be busy */ + +/* JEDEC 4.51 chapter 6.12 */ +#define MMC_RESPONSE_R1 (MMC_RSP_48 | MMC_RSP_CMD_IDX | MMC_RSP_CRC) +#define MMC_RESPONSE_R1B (MMC_RESPONSE_R1 | MMC_RSP_BUSY) +#define MMC_RESPONSE_R2 (MMC_RSP_48 | MMC_RSP_136 | MMC_RSP_CRC) +#define MMC_RESPONSE_R3 (MMC_RSP_48) +#define MMC_RESPONSE_R4 (MMC_RSP_48) +#define MMC_RESPONSE_R5 (MMC_RSP_48 | MMC_RSP_CRC | MMC_RSP_CMD_IDX) +#define MMC_RESPONSE_R6 (MMC_RSP_CRC | MMC_RSP_CMD_IDX) +#define MMC_RESPONSE_R7 (MMC_RSP_48 | MMC_RSP_CRC) +#define MMC_RESPONSE_NONE 0 + +/* Value randomly chosen for eMMC RCA, it should be > 1 */ +#define MMC_FIX_RCA 6 +#define RCA_SHIFT_OFFSET 16 + +#define CMD_EXTCSD_PARTITION_CONFIG 179 +#define CMD_EXTCSD_BUS_WIDTH 183 +#define CMD_EXTCSD_HS_TIMING 185 +#define CMD_EXTCSD_SEC_CNT 212 + +#define PART_CFG_BOOT_PARTITION1_ENABLE BIT(3) +#define PART_CFG_PARTITION1_ACCESS 1 + +/* Values in EXT CSD register */ +#define MMC_BUS_WIDTH_1 0 +#define MMC_BUS_WIDTH_4 1 +#define MMC_BUS_WIDTH_8 2 +#define MMC_BUS_WIDTH_DDR_4 5 +#define MMC_BUS_WIDTH_DDR_8 6 +#define MMC_BOOT_MODE_BACKWARD 0 +#define MMC_BOOT_MODE_HS_TIMING BIT(3) +#define MMC_BOOT_MODE_DDR (2 << 3) + +#define EXTCSD_SET_CMD 0 +#define EXTCSD_SET_BITS BIT(24) +#define EXTCSD_CLR_BITS (2 << 24) +#define EXTCSD_WRITE_BYTES (3 << 24) +#define EXTCSD_CMD(x) (((x) & 0xff) << 16) +#define EXTCSD_VALUE(x) (((x) & 0xff) << 8) +#define EXTCSD_CMD_SET_NORMAL 1 + +#define CSD_TRAN_SPEED_UNIT_MASK GENMASK(2, 0) +#define CSD_TRAN_SPEED_MULT_MASK GENMASK(6, 3) +#define CSD_TRAN_SPEED_MULT_SHIFT 3 + +#define STATUS_CURRENT_STATE(x) (((x) & 0xf) << 9) +#define STATUS_READY_FOR_DATA BIT(8) +#define STATUS_SWITCH_ERROR BIT(7) +#define MMC_GET_STATE(x) (((x) >> 9) & 0xf) +#define MMC_STATE_IDLE 0 +#define MMC_STATE_READY 1 +#define MMC_STATE_IDENT 2 +#define MMC_STATE_STBY 3 +#define MMC_STATE_TRAN 4 +#define MMC_STATE_DATA 5 +#define MMC_STATE_RCV 6 +#define MMC_STATE_PRG 7 +#define MMC_STATE_DIS 8 +#define MMC_STATE_BTST 9 +#define MMC_STATE_SLP 10 + +#define MMC_FLAG_CMD23 1 + +#define CMD8_CHECK_PATTERN 0xAA +#define VHS_2_7_3_6_V BIT(8) + +#define SD_SCR_BUS_WIDTH_1 BIT(8) +#define SD_SCR_BUS_WIDTH_4 BIT(10) + +/* ADMA table component */ +#define ADMA_DESC_ATTR_VALID BIT(0) +#define ADMA_DESC_ATTR_END BIT(1) +#define ADMA_DESC_ATTR_INT BIT(2) +#define ADMA_DESC_ATTR_ACT1 BIT(4) +#define ADMA_DESC_ATTR_ACT2 BIT(5) +#define ADMA_DESC_TRANSFER_DATA ADMA_DESC_ATTR_ACT2 + +/* SRS10 Register */ +#define LEDC BIT(0) +#define DT_WIDTH BIT(1) +#define HS_EN BIT(2) +/* Conf depends on SRS15.HV4E */ +#define SDMA 0 +#define ADMA2_32 (2 << 3) +#define ADMA2_64 (3 << 3) +/* here 0 defines the 64 Kb size */ +#define MAX_64KB_PAGE 0 + +struct sdmmc_cmd { + unsigned int cmd_idx; + unsigned int cmd_arg; + unsigned int resp_type; + unsigned int resp_data[4]; +}; + +struct sdhc_cdns_ops { + /* init function for card */ + int (*init)(void); + /* busy check function for card */ + int (*busy)(void); + /* card_present function check for card */ + int (*card_present)(void); + /* reset the card */ + int (*reset)(void); + /* send command and respective argument */ + int (*send_cmd)(struct sdmmc_cmd *cmd, struct sdhc_data *data); + /* io set up for card */ + int (*set_ios)(unsigned int clk, unsigned int width); + /* prepare dma descriptors */ + int (*prepare)(uint32_t lba, uintptr_t buf, struct sdhc_data *data); + /* cache invd api */ + int (*cache_invd)(int lba, uintptr_t buf, size_t size); +}; + +/* Combo Phy reg */ +struct sdhc_cdns_combo_phy { + uint32_t cp_clk_wr_delay; + uint32_t cp_clk_wrdqs_delay; + uint32_t cp_data_select_oe_end; + uint32_t cp_dll_bypass_mode; + uint32_t cp_dll_locked_mode; + uint32_t cp_dll_start_point; + uint32_t cp_gate_cfg_always_on; + uint32_t cp_io_mask_always_on; + uint32_t cp_io_mask_end; + uint32_t cp_io_mask_start; + uint32_t cp_rd_del_sel; + uint32_t cp_read_dqs_cmd_delay; + uint32_t cp_read_dqs_delay; + uint32_t cp_sw_half_cycle_shift; + uint32_t cp_sync_method; + uint32_t cp_underrun_suppress; + uint32_t cp_use_ext_lpbk_dqs; + uint32_t cp_use_lpbk_dqs; + uint32_t cp_use_phony_dqs; + uint32_t cp_use_phony_dqs_cmd; +}; + +/* sdmmc reg */ +struct sdhc_cdns_sdmmc { + uint32_t sdhc_extended_rd_mode; + uint32_t sdhc_extended_wr_mode; + uint32_t sdhc_hcsdclkadj; + uint32_t sdhc_idelay_val; + uint32_t sdhc_rdcmd_en; + uint32_t sdhc_rddata_en; + uint32_t sdhc_rw_compensate; + uint32_t sdhc_sdcfsh; + uint32_t sdhc_sdcfsl; + uint32_t sdhc_wrcmd0_dly; + uint32_t sdhc_wrcmd0_sdclk_dly; + uint32_t sdhc_wrcmd1_dly; + uint32_t sdhc_wrcmd1_sdclk_dly; + uint32_t sdhc_wrdata0_dly; + uint32_t sdhc_wrdata0_sdclk_dly; + uint32_t sdhc_wrdata1_dly; + uint32_t sdhc_wrdata1_sdclk_dly; +}; + +enum sdmmc_device_mode { + /* Identification */ + SD_DS_ID, + /* Default speed */ + SD_DS, + /* High speed */ + SD_HS, + /* Ultra high speed SDR12 */ + SD_UHS_SDR12, + /* Ultra high speed SDR25 */ + SD_UHS_SDR25, + /* Ultra high speed SDR`50 */ + SD_UHS_SDR50, + /* Ultra high speed SDR104 */ + SD_UHS_SDR104, + /* Ultra high speed DDR50 */ + SD_UHS_DDR50, + /* SDR backward compatible */ + EMMC_SDR_BC, + /* SDR */ + EMMC_SDR, + /* DDR */ + EMMC_DDR, + /* High speed 200Mhz in SDR */ + EMMC_HS200, + /* High speed 200Mhz in DDR */ + EMMC_HS400, + /* High speed 200Mhz in SDR with enhanced strobe */ + EMMC_HS400ES, +}; + +struct sdhc_cdns_params { + uintptr_t reg_base; + uintptr_t reg_phy; + uintptr_t desc_base; + size_t desc_size; + int clk_rate; + int bus_width; + unsigned int flags; + enum sdmmc_device_mode cdn_sdmmc_dev_type; + uint32_t combophy; +}; + +struct sdmmc_device_info { + /* Size of device in bytes */ + unsigned long long device_size; + /* Block size in bytes */ + unsigned int block_size; + /* Max bus freq in Hz */ + unsigned int max_bus_freq; + /* OCR voltage */ + unsigned int ocr_voltage; + /* Type of MMC */ + enum sdmmc_device_mode cdn_sdmmc_dev_type; +}; + +/*descriptor structure with 8 byte alignment*/ +struct sdhc_cdns_desc { + /* 8 bit attribute */ + uint8_t attr; + /* reserved bits in desc */ + uint8_t reserved; + /* page length for the descriptor */ + uint16_t len; + /* lower 32 bits for buffer (64 bit addressing) */ + uint32_t addr_lo; + /* higher 32 bits for buffer (64 bit addressing) */ + uint32_t addr_hi; +} __aligned(8); + +void sdhc_cdns_sdmmc_init(struct sdhc_cdns_params *params, struct sdmmc_device_info *info, + const struct sdhc_cdns_ops **cb_sdmmc_ops); diff --git a/dts/bindings/sdhc/cdns,sdhc.yaml b/dts/bindings/sdhc/cdns,sdhc.yaml new file mode 100644 index 00000000000..536b9c4bd58 --- /dev/null +++ b/dts/bindings/sdhc/cdns,sdhc.yaml @@ -0,0 +1,20 @@ +# Copyright (c) 2023 Intel Corporation +# SPDX-License-Identifier: Apache-2.0 + +description: Cadence SDHC Controller node + +compatible: "cdns,sdhc" + +include: [sdhc.yaml, reset-device.yaml] + +properties: + clock-frequency: + type: int + description: clock-frequency for SDHC + reg: + required: true + description: register space + power_delay_ms: + type: int + required: true + description: delay required to switch on the SDHC From d16a80d2e8060eba85b1314b088860c0c6aacaf0 Mon Sep 17 00:00:00 2001 From: Murlidhar Roy Date: Tue, 17 Oct 2023 14:45:10 +0800 Subject: [PATCH 1372/3723] dts: arm64: intel: add dts node for sdhc in agilex5 adds dts support for cdns sdhc driver bringup on agilex5 Signed-off-by: Murlidhar Roy --- dts/arm64/intel/intel_socfpga_agilex5.dtsi | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/dts/arm64/intel/intel_socfpga_agilex5.dtsi b/dts/arm64/intel/intel_socfpga_agilex5.dtsi index 6a177c1047b..f4566e2f17e 100644 --- a/dts/arm64/intel/intel_socfpga_agilex5.dtsi +++ b/dts/arm64/intel/intel_socfpga_agilex5.dtsi @@ -117,6 +117,19 @@ status = "okay"; }; + sdmmc: sdmmc@10808000 { + compatible = "cdns,sdhc"; + reg = <0x10808000 0x1000>, + <0x10B92000 0x1000>; + reg-names = "reg_base", "combo_phy"; + clock-frequency = <200000000>; + power_delay_ms = <1000>; + resets = <&reset RSTMGR_SDMMC_RSTLINE>, + <&reset RSTMGR_SDMMCECC_RSTLINE>, + <&reset RSTMGR_SOFTPHY_RSTLINE>; + status = "disabled"; + }; + timer0: timer@10C03000 { compatible = "snps,dw-timers"; interrupt-parent = <&gic>; From bc8e09d4ec770d7d2cecb4ccc957ee38d36d952d Mon Sep 17 00:00:00 2001 From: Murlidhar Roy Date: Tue, 17 Oct 2023 14:49:26 +0800 Subject: [PATCH 1373/3723] boards: arm64: intel: intel_socfpga_agilex5_socdk: Enable sdmmc Enable SDMMC and add MMC child node Signed-off-by: Murlidhar Roy --- .../intel_socfpga_agilex5_socdk.dts | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/boards/arm64/intel_socfpga_agilex5_socdk/intel_socfpga_agilex5_socdk.dts b/boards/arm64/intel_socfpga_agilex5_socdk/intel_socfpga_agilex5_socdk.dts index 4bc1e1ce9f2..701401f569b 100644 --- a/boards/arm64/intel_socfpga_agilex5_socdk/intel_socfpga_agilex5_socdk.dts +++ b/boards/arm64/intel_socfpga_agilex5_socdk/intel_socfpga_agilex5_socdk.dts @@ -21,6 +21,15 @@ }; }; +&sdmmc { + status = "okay"; + mmc { + /*SD Disk Access */ + compatible = "zephyr,sdmmc-disk"; + status = "okay"; + }; +}; + &uart0 { status = "okay"; current-speed = <115200>; From 3426eab29c5d8e9adf575bcbcd437c0653cd1f82 Mon Sep 17 00:00:00 2001 From: Murlidhar Roy Date: Tue, 17 Oct 2023 17:02:50 +0800 Subject: [PATCH 1374/3723] samples: subsys: shell: shell_module: adding support for shell app adding support for shell application for agilex5 platform Signed-off-by: Murlidhar Roy --- .../boards/intel_socfpga_agilex5_socdk.conf | 16 ++++++++++++++++ .../boards/intel_socfpga_agilex5_socdk.overlay | 4 ++++ 2 files changed, 20 insertions(+) diff --git a/samples/subsys/shell/shell_module/boards/intel_socfpga_agilex5_socdk.conf b/samples/subsys/shell/shell_module/boards/intel_socfpga_agilex5_socdk.conf index 489e3f9fe16..b96ff81fe83 100644 --- a/samples/subsys/shell/shell_module/boards/intel_socfpga_agilex5_socdk.conf +++ b/samples/subsys/shell/shell_module/boards/intel_socfpga_agilex5_socdk.conf @@ -27,3 +27,19 @@ CONFIG_ARM_SIP_SVC_SUBSYS_SINGLY_OPEN=y #SiP SVC Service Shell CONFIG_ARM_SIP_SVC_SUBSYS_SHELL=y + +# Enable File System Shell +CONFIG_FILE_SYSTEM_SHELL=y + +# Enable Disk access +CONFIG_DISK_ACCESS=y + +# File System Setting +CONFIG_FILE_SYSTEM=y +CONFIG_FAT_FILESYSTEM_ELM=y + +# Enable SDMMC +CONFIG_DISK_DRIVER_SDMMC=y + +# Enable SDHC +CONFIG_SDHC=y diff --git a/samples/subsys/shell/shell_module/boards/intel_socfpga_agilex5_socdk.overlay b/samples/subsys/shell/shell_module/boards/intel_socfpga_agilex5_socdk.overlay index a35c307aeca..c7de2dd4529 100644 --- a/samples/subsys/shell/shell_module/boards/intel_socfpga_agilex5_socdk.overlay +++ b/samples/subsys/shell/shell_module/boards/intel_socfpga_agilex5_socdk.overlay @@ -31,3 +31,7 @@ status = "okay"; zephyr,num-clients = <2>; }; + +&sdmmc { + status = "okay"; +}; From 1ddb931fa8706307018434ff14c14838394d9e8d Mon Sep 17 00:00:00 2001 From: Murlidhar Roy Date: Tue, 17 Oct 2023 17:05:18 +0800 Subject: [PATCH 1375/3723] samples: subsys: fs: fs_sample: adding support for fat_fs app adding support for fat_fs application agilex5 platform Signed-off-by: Murlidhar Roy --- .../fs_sample/boards/intel_socfpga_agilex5_socdk.overlay | 9 +++++++++ 1 file changed, 9 insertions(+) create mode 100644 samples/subsys/fs/fs_sample/boards/intel_socfpga_agilex5_socdk.overlay diff --git a/samples/subsys/fs/fs_sample/boards/intel_socfpga_agilex5_socdk.overlay b/samples/subsys/fs/fs_sample/boards/intel_socfpga_agilex5_socdk.overlay new file mode 100644 index 00000000000..22d18f5879c --- /dev/null +++ b/samples/subsys/fs/fs_sample/boards/intel_socfpga_agilex5_socdk.overlay @@ -0,0 +1,9 @@ +/* + * Copyright (C) 2023 Intel Corporation + * + * SPDX-License-Identifier: Apache-2.0 + */ + +&sdmmc { + status = "okay"; +}; From d11c65db0739fadb2b5e07ea433b11f271363ce8 Mon Sep 17 00:00:00 2001 From: Murlidhar Roy Date: Tue, 17 Oct 2023 17:10:12 +0800 Subject: [PATCH 1376/3723] CODEOWNERS: Update codeowners for SDHC Cadence Updated codeowners for SDHC Cadence Driver files. Signed-off-by: Murlidhar Roy --- CODEOWNERS | 2 ++ 1 file changed, 2 insertions(+) diff --git a/CODEOWNERS b/CODEOWNERS index 6b8919a6a84..8c2b478fb4a 100644 --- a/CODEOWNERS +++ b/CODEOWNERS @@ -363,6 +363,8 @@ /drivers/spi/spi_rv32m1_lpspi* @karstenkoenig /drivers/spi/*esp32* @sylvioalves /drivers/spi/*pl022* @soburi +/drivers/sdhc/ @danieldegrasse +/drivers/sdhc/sdhc_cdns* @roymurlidhar /drivers/timer/*arm_arch* @carlocaione /drivers/timer/*cortex_m_systick* @anangl /drivers/timer/*altera_avalon* @nashif From 67099d2bbade01106383e444964f5a7879f6f9fe Mon Sep 17 00:00:00 2001 From: Bryan Zhu Date: Thu, 7 Dec 2023 22:43:28 +0800 Subject: [PATCH 1377/3723] timer: ambiq_stimer: fixing disabling tickless not working issue In init function, start timer with period CYC_PER_TICK if tickless is not enabled, This change is for fixing the issue that disabling CONFIG_TICKLESS_KERNEL the OS tick is not work issue, this causes the OS not starting scheduling correctly. Signed-off-by: Bryan Zhu --- drivers/timer/ambiq_stimer.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/drivers/timer/ambiq_stimer.c b/drivers/timer/ambiq_stimer.c index 5db803fb12d..bcef78dd1ac 100644 --- a/drivers/timer/ambiq_stimer.c +++ b/drivers/timer/ambiq_stimer.c @@ -142,7 +142,10 @@ static int stimer_init(void) irq_enable(TIMER_IRQ); am_hal_stimer_int_enable(AM_HAL_STIMER_INT_COMPAREA); - + /* Start timer with period CYC_PER_TICK if tickless is not enabled */ + if (!IS_ENABLED(CONFIG_TICKLESS_KERNEL)) { + am_hal_stimer_compare_delta_set(0, CYC_PER_TICK); + } return 0; } From 6152e64aa0b89d9fd3b988e33884669a86bf1c66 Mon Sep 17 00:00:00 2001 From: Chaitanya Tata Date: Mon, 18 Dec 2023 17:42:43 +0530 Subject: [PATCH 1378/3723] wifi: shell: Fix arg count for regulatory domain Regulatory domain supports both get and set, so, fix the argument counts. Signed-off-by: Chaitanya Tata --- subsys/net/l2/wifi/wifi_shell.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/subsys/net/l2/wifi/wifi_shell.c b/subsys/net/l2/wifi/wifi_shell.c index f1a98105204..3aa674e73b7 100644 --- a/subsys/net/l2/wifi/wifi_shell.c +++ b/subsys/net/l2/wifi/wifi_shell.c @@ -1688,7 +1688,7 @@ SHELL_STATIC_SUBCMD_SET_CREATE(wifi_commands, "[-f]: Force to use this regulatory hint over any other regulatory hints\n" "Note: This may cause regulatory compliance issues, use it at your own risk.", cmd_wifi_reg_domain, - 2, 1), + 1, 1), SHELL_CMD_ARG(mode, NULL, "mode operational setting\n" "This command may be used to set the Wi-Fi device into a specific mode of operation\n" "parameters:" From e51a877a90d479e2b2d23b0e20d2c9721b3e0c57 Mon Sep 17 00:00:00 2001 From: Fabio Baltieri Date: Fri, 15 Dec 2023 20:15:14 +0000 Subject: [PATCH 1379/3723] bluetooth: shell: match cmd_conn_phy_update conditions The condition for channel-map are CONFIG_BT_CENTRAL || CONFIG_BT_BROADCASTER, change the corresponding handler ifdef so that it's included in the build if CONFIG_BT_BROADCASTER is enabled but CONFIG_BT_CENTRAL is not. Signed-off-by: Fabio Baltieri --- subsys/bluetooth/shell/bt.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/subsys/bluetooth/shell/bt.c b/subsys/bluetooth/shell/bt.c index 1d4c61a84f7..ca3c7c3c0ea 100644 --- a/subsys/bluetooth/shell/bt.c +++ b/subsys/bluetooth/shell/bt.c @@ -3244,7 +3244,7 @@ static int cmd_conn_phy_update(const struct shell *sh, size_t argc, } #endif -#if defined(CONFIG_BT_CENTRAL) +#if defined(CONFIG_BT_CENTRAL) || defined(CONFIG_BT_BROADCASTER) static int cmd_chan_map(const struct shell *sh, size_t argc, char *argv[]) { uint8_t chan_map[5] = {}; From 54d7793e82a15c5dc574a100b82056d862199604 Mon Sep 17 00:00:00 2001 From: Erwan Gouriou Date: Mon, 12 Sep 2022 16:56:03 +0200 Subject: [PATCH 1380/3723] drivers: bluethooth: stm32wba: Add HCI driver for STM32WBA Add HCI Driver for STM32WBA devices. Based on B91 HCI driver. Signed-off-by: Erwan Gouriou --- drivers/bluetooth/hci/CMakeLists.txt | 1 + drivers/bluetooth/hci/Kconfig | 6 + drivers/bluetooth/hci/hci_stm32wba.c | 382 +++++++++++++++++++++++++++ subsys/bluetooth/Kconfig | 2 +- subsys/bluetooth/host/Kconfig | 1 + 5 files changed, 391 insertions(+), 1 deletion(-) create mode 100644 drivers/bluetooth/hci/hci_stm32wba.c diff --git a/drivers/bluetooth/hci/CMakeLists.txt b/drivers/bluetooth/hci/CMakeLists.txt index b5d30d2b880..e20706c494f 100644 --- a/drivers/bluetooth/hci/CMakeLists.txt +++ b/drivers/bluetooth/hci/CMakeLists.txt @@ -21,6 +21,7 @@ zephyr_library_sources_ifdef(CONFIG_BT_H5 h5.c) zephyr_library_sources_ifdef(CONFIG_BT_HCI_IPC ipc.c) zephyr_library_sources_ifdef(CONFIG_BT_SPI spi.c) zephyr_library_sources_ifdef(CONFIG_BT_STM32_IPM ipm_stm32wb.c) +zephyr_library_sources_ifdef(CONFIG_BT_STM32WBA hci_stm32wba.c) zephyr_library_sources_ifdef(CONFIG_BT_USERCHAN userchan.c) zephyr_library_sources_ifdef(CONFIG_BT_SILABS_HCI slz_hci.c) zephyr_library_sources_ifdef(CONFIG_BT_PSOC6_BLESS hci_psoc6_bless.c) diff --git a/drivers/bluetooth/hci/Kconfig b/drivers/bluetooth/hci/Kconfig index fe204d564fb..ad1d9da2df2 100644 --- a/drivers/bluetooth/hci/Kconfig +++ b/drivers/bluetooth/hci/Kconfig @@ -62,6 +62,12 @@ config BT_STM32_IPM help TODO +config BT_STM32WBA + bool "STM32WBA HCI driver" + select HAS_STM32LIB + help + ST STM32WBA HCI Bluetooth interface + config BT_SILABS_HCI bool "Silicon Labs Bluetooth interface" depends on SOC_SERIES_EFR32BG22 || SOC_SERIES_EFR32MG24 || SOC_SERIES_EFR32BG27 diff --git a/drivers/bluetooth/hci/hci_stm32wba.c b/drivers/bluetooth/hci/hci_stm32wba.c new file mode 100644 index 00000000000..357c3a8dac4 --- /dev/null +++ b/drivers/bluetooth/hci/hci_stm32wba.c @@ -0,0 +1,382 @@ +/* hci_stm32wba.c - HCI driver for stm32wba */ + +/* + * Copyright (c) 2022, Telink Semiconductor (Shanghai) Co., Ltd. + * Copyright (c) 2023 STMicroelectronics + * + * SPDX-License-Identifier: Apache-2.0 + */ + + +#include +#include +#include +#include +#include +#include +#include + +#include + +#include "blestack.h" +#include "app_conf.h" +#include "ll_sys.h" +/* TODO: Enable Flash Manager once available */ +/* #include "flash_driver.h" */ + +#define LOG_LEVEL CONFIG_BT_HCI_DRIVER_LOG_LEVEL +#include +LOG_MODULE_REGISTER(hci_wba); + +static K_SEM_DEFINE(hci_sem, 1, 1); + +#define HCI_CMD 0x01 +#define HCI_ACL 0x02 +#define HCI_SCO 0x03 +#define HCI_EVT 0x04 +#define HCI_ISO 0x05 + +#define BLE_CTRLR_STACK_BUFFER_SIZE 300 + +#define MBLOCK_COUNT (BLE_MBLOCKS_CALC(PREP_WRITE_LIST_SIZE, \ + CFG_BLE_ATT_MTU_MAX, \ + CFG_BLE_NUM_LINK) \ + + CFG_BLE_MBLOCK_COUNT_MARGIN) + +#define BLE_DYN_ALLOC_SIZE \ + (BLE_TOTAL_BUFFER_SIZE(CFG_BLE_NUM_LINK, MBLOCK_COUNT)) + +#define DIVC(x, y) (((x)+(y)-1)/(y)) + +static uint32_t buffer[DIVC(BLE_DYN_ALLOC_SIZE, 4)]; + +extern uint8_t ll_state_busy; + +static bool is_hci_event_discardable(const uint8_t *evt_data) +{ + uint8_t evt_type = evt_data[0]; + + switch (evt_type) { +#if defined(CONFIG_BT_BREDR) + case BT_HCI_EVT_INQUIRY_RESULT_WITH_RSSI: + case BT_HCI_EVT_EXTENDED_INQUIRY_RESULT: + return true; +#endif + case BT_HCI_EVT_LE_META_EVENT: { + uint8_t subevt_type = evt_data[sizeof(struct bt_hci_evt_hdr)]; + + switch (subevt_type) { + case BT_HCI_EVT_LE_ADVERTISING_REPORT: + return true; + default: + return false; + } + } + default: + return false; + } +} + +static struct net_buf *treat_evt(const uint8_t *data, size_t len) +{ + bool discardable; + struct bt_hci_evt_hdr hdr; + struct net_buf *buf; + size_t buf_tailroom; + + if (len < sizeof(hdr)) { + LOG_ERR("Not enough data for event header"); + return NULL; + } + + discardable = is_hci_event_discardable(data); + + memcpy((void *)&hdr, data, sizeof(hdr)); + data += sizeof(hdr); + len -= sizeof(hdr); + + if (len != hdr.len) { + LOG_ERR("Event payload length is not correct.\n"); + LOG_ERR("len: %d, hdr.len: %d\n", len, hdr.len); + return NULL; + } + LOG_DBG("len %u", hdr.len); + + buf = bt_buf_get_evt(hdr.evt, discardable, discardable ? K_NO_WAIT : K_SECONDS(3)); + if (!buf) { + if (discardable) { + LOG_DBG("Discardable buffer pool full, ignoring event"); + } else { + LOG_ERR("No available event buffers!"); + + } + __ASSERT_NO_MSG(buf); + return buf; + } + + net_buf_add_mem(buf, &hdr, sizeof(hdr)); + + buf_tailroom = net_buf_tailroom(buf); + if (buf_tailroom < len) { + LOG_ERR("Not enough space in buffer %zu/%zu", len, buf_tailroom); + net_buf_unref(buf); + return NULL; + } + + net_buf_add_mem(buf, data, len); + + return buf; +} + +static struct net_buf *treat_acl(const uint8_t *data, size_t len, + const uint8_t *ext_data, size_t ext_len) +{ + struct bt_hci_acl_hdr hdr; + struct net_buf *buf; + size_t buf_tailroom; + + if (len < sizeof(hdr)) { + LOG_ERR("Not enough data for ACL header"); + return NULL; + } + + buf = bt_buf_get_rx(BT_BUF_ACL_IN, K_NO_WAIT); + if (buf) { + memcpy((void *)&hdr, data, sizeof(hdr)); + data += sizeof(hdr); + len -= sizeof(hdr); + } else { + LOG_ERR("No available ACL buffers!"); + return NULL; + } + + if (ext_len != sys_le16_to_cpu(hdr.len)) { + LOG_ERR("ACL payload length is not correct"); + net_buf_unref(buf); + return NULL; + } + + net_buf_add_mem(buf, &hdr, sizeof(hdr)); + buf_tailroom = net_buf_tailroom(buf); + if (buf_tailroom < len) { + LOG_ERR("Not enough space in buffer %zu/%zu", len, buf_tailroom); + net_buf_unref(buf); + return NULL; + } + + LOG_DBG("ext_len %u", ext_len); + net_buf_add_mem(buf, ext_data, ext_len); + + return buf; +} + +static struct net_buf *treat_iso(const uint8_t *data, size_t len, + const uint8_t *ext_data, size_t ext_len) +{ + struct bt_hci_iso_hdr hdr; + struct net_buf *buf; + size_t buf_tailroom; + + if (len < sizeof(hdr)) { + LOG_ERR("Not enough data for ISO header"); + return NULL; + } + + buf = bt_buf_get_rx(BT_BUF_ISO_IN, K_NO_WAIT); + if (buf) { + memcpy((void *)&hdr, data, sizeof(hdr)); + data += sizeof(hdr); + len -= sizeof(hdr); + } else { + LOG_ERR("No available ISO buffers!"); + return NULL; + } + + if (ext_len != bt_iso_hdr_len(sys_le16_to_cpu(hdr.len))) { + LOG_ERR("ISO payload length is not correct"); + net_buf_unref(buf); + return NULL; + } + + net_buf_add_mem(buf, &hdr, sizeof(hdr)); + buf_tailroom = net_buf_tailroom(buf); + if (buf_tailroom < len) { + LOG_ERR("Not enough space in buffer %zu/%zu", len, buf_tailroom); + net_buf_unref(buf); + return NULL; + } + + LOG_DBG("ext_len %zu", ext_len); + net_buf_add_mem(buf, ext_data, ext_len); + + return buf; +} + +static int receive_data(const uint8_t *data, size_t len, + const uint8_t *ext_data, size_t ext_len) +{ + uint8_t pkt_indicator; + struct net_buf *buf; + int err = 0; + + LOG_HEXDUMP_DBG(data, len, "host packet data:"); + LOG_HEXDUMP_DBG(ext_data, ext_len, "host packet ext_data:"); + + pkt_indicator = *data++; + len -= sizeof(pkt_indicator); + + switch (pkt_indicator) { + case HCI_EVT: + buf = treat_evt(data, len); + break; + case HCI_ACL: + buf = treat_acl(data, len + 1, ext_data, ext_len); + break; + case HCI_ISO: + case HCI_SCO: + buf = treat_iso(data, len + 1, ext_data, ext_len); + break; + default: + buf = NULL; + LOG_ERR("Unknown HCI type %u", pkt_indicator); + } + + if (buf) { + bt_recv(buf); + } else { + err = -ENOMEM; + ll_state_busy = 1; + } + + return err; +} + +uint8_t BLECB_Indication(const uint8_t *data, uint16_t length, + const uint8_t *ext_data, uint16_t ext_length) +{ + int ret = 0; + int err; + + LOG_DBG("length: %d", length); + if (ext_length != 0) { + LOG_DBG("ext_length: %d", ext_length); + } + + k_sem_take(&hci_sem, K_FOREVER); + + err = receive_data(data, (size_t)length - 1, + ext_data, (size_t)ext_length); + + k_sem_give(&hci_sem); + + HostStack_Process(); + + if (err) { + ret = 1; + } + + return ret; +} + +static int bt_hci_stm32wba_send(struct net_buf *buf) +{ + uint16_t event_length; + uint8_t pkt_indicator; + uint8_t tx_buffer[BLE_CTRLR_STACK_BUFFER_SIZE]; + + k_sem_take(&hci_sem, K_FOREVER); + + LOG_DBG("buf %p type %u len %u", buf, bt_buf_get_type(buf), buf->len); + + switch (bt_buf_get_type(buf)) { + case BT_BUF_ACL_OUT: + pkt_indicator = HCI_ACL; + break; + case BT_BUF_CMD: + pkt_indicator = HCI_CMD; + break; + case BT_BUF_ISO_OUT: + pkt_indicator = HCI_ISO; + break; + default: + LOG_ERR("Unknown type %u", bt_buf_get_type(buf)); + k_sem_give(&hci_sem); + return -EIO; + } + net_buf_push_u8(buf, pkt_indicator); + + memcpy(&tx_buffer, buf->data, buf->len); + + event_length = BleStack_Request(tx_buffer); + LOG_DBG("event_length: %u", event_length); + + if (event_length) { + receive_data((uint8_t *)&tx_buffer, (size_t)event_length, NULL, 0); + } + + k_sem_give(&hci_sem); + + net_buf_unref(buf); + + return 0; +} + +static int bt_ble_ctlr_init(void) +{ + BleStack_init_t init_params_p = {0}; + + init_params_p.numAttrRecord = CFG_BLE_NUM_GATT_ATTRIBUTES; + init_params_p.numAttrServ = CFG_BLE_NUM_GATT_SERVICES; + init_params_p.attrValueArrSize = CFG_BLE_ATT_VALUE_ARRAY_SIZE; + init_params_p.prWriteListSize = CFG_BLE_ATTR_PREPARE_WRITE_VALUE_SIZE; + init_params_p.attMtu = CFG_BLE_ATT_MTU_MAX; + init_params_p.max_coc_nbr = CFG_BLE_COC_NBR_MAX; + init_params_p.max_coc_mps = CFG_BLE_COC_MPS_MAX; + init_params_p.max_coc_initiator_nbr = CFG_BLE_COC_INITIATOR_NBR_MAX; + init_params_p.numOfLinks = CFG_BLE_NUM_LINK; + init_params_p.mblockCount = CFG_BLE_MBLOCK_COUNT; + init_params_p.bleStartRamAddress = (uint8_t *)buffer; + init_params_p.total_buffer_size = BLE_DYN_ALLOC_SIZE; + init_params_p.bleStartRamAddress_GATT = NULL; + init_params_p.total_buffer_size_GATT = 0; + init_params_p.options = CFG_BLE_OPTIONS; + init_params_p.debug = 0U; + + if (BleStack_Init(&init_params_p) != BLE_STATUS_SUCCESS) { + return -EIO; + } + + return 0; +} + +static int bt_hci_stm32wba_open(void) +{ + int ret = 0; + + link_layer_register_isr(); + + ll_sys_config_params(); + + ret = bt_ble_ctlr_init(); + + /* TODO. Enable Flash manager once available */ + /* FD_SetStatus(FD_FLASHACCESS_RFTS_BYPASS, LL_FLASH_DISABLE); */ + + return ret; +} + +static const struct bt_hci_driver drv = { + .name = "BT IPM", + .bus = BT_HCI_DRIVER_BUS_IPM, + .open = bt_hci_stm32wba_open, + .send = bt_hci_stm32wba_send, +}; + +static int bt_stm32wba_hci_init(void) +{ + bt_hci_driver_register(&drv); + + return 0; +} + +SYS_INIT(bt_stm32wba_hci_init, POST_KERNEL, CONFIG_KERNEL_INIT_PRIORITY_DEVICE); diff --git a/subsys/bluetooth/Kconfig b/subsys/bluetooth/Kconfig index 912846e4cda..c8f71afb207 100644 --- a/subsys/bluetooth/Kconfig +++ b/subsys/bluetooth/Kconfig @@ -128,7 +128,7 @@ if BT_CONN config BT_HCI_ACL_FLOW_CONTROL bool "Controller to Host ACL flow control support" # Enable if building a Host-only build - default y if !BT_CTLR && !BT_STM32_IPM && !BT_ESP32 + default y if !BT_CTLR && !BT_STM32_IPM && !BT_ESP32 && !BT_STM32WBA # Enable if building a Controller-only build default y if BT_HCI_RAW select POLL diff --git a/subsys/bluetooth/host/Kconfig b/subsys/bluetooth/host/Kconfig index 94378128baa..d17aa7d1b0e 100644 --- a/subsys/bluetooth/host/Kconfig +++ b/subsys/bluetooth/host/Kconfig @@ -79,6 +79,7 @@ config BT_HCI_RESERVE default 1 if BT_HCI_IPC default 1 if BT_SPI default 1 if BT_STM32_IPM + default 1 if BT_STM32WBA default 1 if BT_USERCHAN default 1 if BT_ESP32 default 0 if BT_B91 From 6ed002ddae64043778e4cca9f05f12c4f4dff455 Mon Sep 17 00:00:00 2001 From: Erwan Gouriou Date: Mon, 4 Dec 2023 15:28:09 +0100 Subject: [PATCH 1381/3723] modules: Kconfig.stm32: Add Kconfig symbol for RAMCFG RAMCFG will be required for STM32WBA BLE support. Signed-off-by: Erwan Gouriou --- modules/Kconfig.stm32 | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/modules/Kconfig.stm32 b/modules/Kconfig.stm32 index ad598f63006..57749a8ec6b 100644 --- a/modules/Kconfig.stm32 +++ b/modules/Kconfig.stm32 @@ -447,6 +447,11 @@ config USE_STM32_HAL_RAMECC help Enable STM32Cube RAM ECC monitoring (RAMECC) HAL module driver +config USE_STM32_HAL_RAMCFG + bool + help + Enable STM32Cube RAM config (RAMCFG) HAL module driver + config USE_STM32_HAL_RNG bool help From 6f6410061de69bf419e2ad3a55d9fcb429ca8b07 Mon Sep 17 00:00:00 2001 From: Erwan Gouriou Date: Mon, 4 Dec 2023 15:44:58 +0100 Subject: [PATCH 1382/3723] soc: stm32wba: Implement BLE controller lib APIs over Zephyr In order to enable BLE support on STM32WBA, following APIs are implemented: - HostStack_: BLE Controller scheduling - ll_sys_: Link layer API required for scheduling - UTIL_TIMER_: BLE Controller timer utility - LINKLAYER_PLAT_: BLE controller utilities Signed-off-by: Erwan Gouriou --- soc/arm/st_stm32/stm32wba/CMakeLists.txt | 10 + .../stm32wba/Kconfig.defconfig.series | 26 ++ soc/arm/st_stm32/stm32wba/hci_if/bleplat.c | 100 ++++++ .../st_stm32/stm32wba/hci_if/host_stack_if.c | 82 +++++ .../st_stm32/stm32wba/hci_if/linklayer_plat.c | 304 ++++++++++++++++++ .../stm32wba/hci_if/linklayer_plat_local.h | 13 + soc/arm/st_stm32/stm32wba/hci_if/ll_sys_if.c | 47 +++ .../st_stm32/stm32wba/hci_if/stm32_timer.c | 59 ++++ 8 files changed, 641 insertions(+) create mode 100644 soc/arm/st_stm32/stm32wba/hci_if/bleplat.c create mode 100644 soc/arm/st_stm32/stm32wba/hci_if/host_stack_if.c create mode 100644 soc/arm/st_stm32/stm32wba/hci_if/linklayer_plat.c create mode 100644 soc/arm/st_stm32/stm32wba/hci_if/linklayer_plat_local.h create mode 100644 soc/arm/st_stm32/stm32wba/hci_if/ll_sys_if.c create mode 100644 soc/arm/st_stm32/stm32wba/hci_if/stm32_timer.c diff --git a/soc/arm/st_stm32/stm32wba/CMakeLists.txt b/soc/arm/st_stm32/stm32wba/CMakeLists.txt index 0fd5073770d..d26c143f8f6 100644 --- a/soc/arm/st_stm32/stm32wba/CMakeLists.txt +++ b/soc/arm/st_stm32/stm32wba/CMakeLists.txt @@ -9,4 +9,14 @@ zephyr_sources_ifdef(CONFIG_PM power.c ) +if(CONFIG_BT_STM32WBA) + zephyr_include_directories(hci_if) + + zephyr_sources(hci_if/linklayer_plat.c) + zephyr_sources(hci_if/bleplat.c) + zephyr_sources(hci_if/host_stack_if.c) + zephyr_sources(hci_if/ll_sys_if.c) + zephyr_sources(hci_if/stm32_timer.c) +endif() + set(SOC_LINKER_SCRIPT ${ZEPHYR_BASE}/include/zephyr/arch/arm/cortex_m/scripts/linker.ld CACHE INTERNAL "") diff --git a/soc/arm/st_stm32/stm32wba/Kconfig.defconfig.series b/soc/arm/st_stm32/stm32wba/Kconfig.defconfig.series index e6d57729a09..a1099228e5f 100644 --- a/soc/arm/st_stm32/stm32wba/Kconfig.defconfig.series +++ b/soc/arm/st_stm32/stm32wba/Kconfig.defconfig.series @@ -13,4 +13,30 @@ config SOC_SERIES config STM32_LPTIM_TIMER default y if PM +choice BT_HCI_BUS_TYPE + default BT_STM32WBA + depends on BT +endchoice + +config BT_STM32WBA + select DYNAMIC_INTERRUPTS + select DYNAMIC_DIRECT_INTERRUPTS + select ENTROPY_GENERATOR + select USE_STM32_HAL_RAMCFG + +if BT_STM32WBA + +choice LIBC_IMPLEMENTATION + default NEWLIB_LIBC +endchoice + +choice LINKER_ORPHAN_CONFIGURATION + default LINKER_ORPHAN_SECTION_PLACE +endchoice + +config ENTROPY_STM32_CLK_CHECK + default n + +endif + endif # SOC_SERIES_STM32WBAX diff --git a/soc/arm/st_stm32/stm32wba/hci_if/bleplat.c b/soc/arm/st_stm32/stm32wba/hci_if/bleplat.c new file mode 100644 index 00000000000..7c1ed1aa962 --- /dev/null +++ b/soc/arm/st_stm32/stm32wba/hci_if/bleplat.c @@ -0,0 +1,100 @@ +/* + * Copyright (c) 2023 STMicroelectronics + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include +#include +#include + +#include "bleplat.h" +#include "bpka.h" +#include "linklayer_plat.h" + +#define LOG_LEVEL CONFIG_SOC_LOG_LEVEL +LOG_MODULE_REGISTER(ble_plat); + +RAMCFG_HandleTypeDef hramcfg_SRAM1; +const struct device *rng_dev; + +void BLEPLAT_Init(void) +{ + BPKA_Reset(); + + rng_dev = DEVICE_DT_GET(DT_CHOSEN(zephyr_entropy)); + if (!device_is_ready(rng_dev)) { + LOG_ERR("error: random device not ready"); + } +} + +void BLEPLAT_RngGet(uint8_t n, uint32_t *val) +{ + LINKLAYER_PLAT_GetRNG((uint8_t *)val, 4 * n); +} + +int BLEPLAT_PkaStartP256Key(const uint32_t *local_private_key) +{ + return BPKA_StartP256Key(local_private_key); +} + +void BLEPLAT_PkaReadP256Key(uint32_t *local_public_key) +{ + BPKA_ReadP256Key(local_public_key); +} + +int BLEPLAT_PkaStartDhKey(const uint32_t *local_private_key, + const uint32_t *remote_public_key) +{ + return BPKA_StartDhKey(local_private_key, remote_public_key); +} + +int BLEPLAT_PkaReadDhKey(uint32_t *dh_key) +{ + return BPKA_ReadDhKey(dh_key); +} + +void BPKACB_Complete(void) +{ + BLEPLATCB_PkaComplete(); +} + +void MX_RAMCFG_Init(void) +{ + /* Initialize RAMCFG SRAM1 */ + hramcfg_SRAM1.Instance = RAMCFG_SRAM1; + if (HAL_RAMCFG_Init(&hramcfg_SRAM1) != HAL_OK) { + LOG_ERR("Could not init RAMCFG"); + } +} + +void *ble_memcpy(void *dst, const void *src, uint8_t n) +{ + memcpy(dst, src, (size_t)n); + + return dst; +} + +void *ble_memset(void *dst, uint8_t c, uint16_t n) +{ + memset((void *)dst, (int)c, (size_t)n); + + return dst; +} + +int8_t ble_memcmp(const void *a, const void *b, uint16_t n) +{ + return (int8_t)memcmp(a, b, (size_t)n); +} + +void Error_Handler(void) +{ + LOG_ERR(""); +} + +/* BLE ctlr should not disable HSI on its own */ +void SCM_HSI_CLK_OFF(void) {} + +/* BLE ctlr should not alter RNG clocks */ +void HW_RNG_DisableClock(uint8_t) {} +void HW_RNG_EnableClock(uint8_t) {} diff --git a/soc/arm/st_stm32/stm32wba/hci_if/host_stack_if.c b/soc/arm/st_stm32/stm32wba/hci_if/host_stack_if.c new file mode 100644 index 00000000000..6cc224cc60a --- /dev/null +++ b/soc/arm/st_stm32/stm32wba/hci_if/host_stack_if.c @@ -0,0 +1,82 @@ +/* + * Copyright (c) 2023 STMicroelectronics + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include +#include + +#include "app_conf.h" +#include "blestack.h" +#include "bpka.h" +#include "ll_intf.h" + +K_MUTEX_DEFINE(ble_ctlr_stack_mutex); +struct k_work_q ble_ctlr_work_q, ll_work_q; +struct k_work ble_ctlr_stack_work, bpka_work; + +uint8_t ll_state_busy; + +#define BLE_CTLR_TASK_STACK_SIZE (256 * 7) +#define LL_TASK_STACK_SIZE (256 * 7) +#define BLE_CTLR_TASK_PRIO (14) +#define LL_TASK_PRIO (14) + +K_THREAD_STACK_DEFINE(ble_ctlr_work_area, BLE_CTLR_TASK_STACK_SIZE); +K_THREAD_STACK_DEFINE(ll_work_area, LL_TASK_STACK_SIZE); + +void HostStack_Process(void) +{ + k_work_submit_to_queue(&ble_ctlr_work_q, &ble_ctlr_stack_work); +} + +static void ble_ctlr_stack_handler(struct k_work *work) +{ + uint8_t running = 0x0; + change_state_options_t options; + + k_mutex_lock(&ble_ctlr_stack_mutex, K_FOREVER); + running = BleStack_Process(); + k_mutex_unlock(&ble_ctlr_stack_mutex); + + if (ll_state_busy == 1) { + options.combined_value = 0x0F; + ll_intf_chng_evnt_hndlr_state(options); + ll_state_busy = 0; + } + + if (running == BLE_SLEEPMODE_RUNNING) { + HostStack_Process(); + } +} + +void BPKACB_Process(void) +{ + k_work_submit_to_queue(&ble_ctlr_work_q, &bpka_work); +} + +static void bpka_work_handler(struct k_work *work) +{ + BPKA_BG_Process(); +} + +static int stm32wba_ble_ctlr_init(void) +{ + k_work_queue_init(&ble_ctlr_work_q); + k_work_queue_start(&ble_ctlr_work_q, ble_ctlr_work_area, + K_THREAD_STACK_SIZEOF(ble_ctlr_work_area), + BLE_CTLR_TASK_PRIO, NULL); + + k_work_queue_init(&ll_work_q); + k_work_queue_start(&ll_work_q, ll_work_area, + K_THREAD_STACK_SIZEOF(ll_work_area), + LL_TASK_PRIO, NULL); + + k_work_init(&ble_ctlr_stack_work, &ble_ctlr_stack_handler); + k_work_init(&bpka_work, &bpka_work_handler); + + return 0; +} + +SYS_INIT(stm32wba_ble_ctlr_init, POST_KERNEL, CONFIG_KERNEL_INIT_PRIORITY_DEFAULT); diff --git a/soc/arm/st_stm32/stm32wba/hci_if/linklayer_plat.c b/soc/arm/st_stm32/stm32wba/hci_if/linklayer_plat.c new file mode 100644 index 00000000000..1e890949147 --- /dev/null +++ b/soc/arm/st_stm32/stm32wba/hci_if/linklayer_plat.c @@ -0,0 +1,304 @@ +/* + * Copyright (c) 2023 STMicroelectronics + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include +#include +#include +#include +#include +#include +#include + +#include + +#include + +#include "scm.h" + +#define LOG_LEVEL CONFIG_SOC_LOG_LEVEL +LOG_MODULE_REGISTER(linklayer_plat); + +#define RADIO_INTR_PRIO_HIGH_Z (RADIO_INTR_PRIO_HIGH + _IRQ_PRIO_OFFSET) +#define RADIO_INTR_PRIO_LOW_Z (RADIO_INTR_PRIO_LOW + _IRQ_PRIO_OFFSET) + +/* 2.4GHz RADIO ISR callbacks */ +typedef void (*radio_isr_cb_t) (void); + +radio_isr_cb_t radio_callback; +radio_isr_cb_t low_isr_callback; + +extern const struct device *rng_dev; + +/* Radio critical sections */ +volatile int32_t prio_high_isr_counter; +volatile int32_t prio_low_isr_counter; +volatile int32_t prio_sys_isr_counter; +volatile int32_t irq_counter; +volatile uint32_t local_basepri_value; + +/* Radio SW low ISR global variable */ +volatile uint8_t radio_sw_low_isr_is_running_high_prio; + +void LINKLAYER_PLAT_ClockInit(void) +{ + LL_PWR_EnableBkUpAccess(); + + /* Select LSE as Sleep CLK */ + __HAL_RCC_RADIOSLPTIM_CONFIG(RCC_RADIOSTCLKSOURCE_LSE); + + LL_PWR_DisableBkUpAccess(); + + /* Enable AHB5ENR peripheral clock (bus CLK) */ + __HAL_RCC_RADIO_CLK_ENABLE(); +} + +void LINKLAYER_PLAT_DelayUs(uint32_t delay) +{ + k_busy_wait(delay); +} + +void LINKLAYER_PLAT_WaitHclkRdy(void) +{ + while (HAL_RCCEx_GetRadioBusClockReadiness() != RCC_RADIO_BUS_CLOCK_READY) { + } +} + +void LINKLAYER_PLAT_AclkCtrl(uint8_t enable) +{ + LOG_DBG("enable: %d", enable); + if (enable) { + /* Enable RADIO baseband clock (active CLK) */ + HAL_RCCEx_EnableRadioBBClock(); + + /* Polling on HSE32 activation */ + while (LL_RCC_HSE_IsReady() == 0) { + } + } else { + /* Disable RADIO baseband clock (active CLK) */ + HAL_RCCEx_DisableRadioBBClock(); + } +} + +void LINKLAYER_PLAT_GetRNG(uint8_t *ptr_rnd, uint32_t len) +{ + int ret; + + /* Read 32-bit random values from HW driver */ + ret = entropy_get_entropy_isr(rng_dev, (char *)ptr_rnd, len, 0); + if (ret < 0) { + LOG_ERR("Error: entropy_get_entropy failed: %d", ret); + } + LOG_DBG("n %d, val: %p", len, (void *)ptr_rnd); +} + +void LINKLAYER_PLAT_SetupRadioIT(void (*intr_cb)()) +{ + radio_callback = intr_cb; +} + +void LINKLAYER_PLAT_SetupSwLowIT(void (*intr_cb)()) +{ + low_isr_callback = intr_cb; +} + +void radio_high_prio_isr(void) +{ + radio_callback(); + + HAL_RCCEx_DisableRequestUponRadioWakeUpEvent(); + + __ISB(); + + ISR_DIRECT_PM(); +} + +void radio_low_prio_isr(void) +{ + irq_disable((IRQn_Type)RADIO_SW_LOW_INTR_NUM); + + low_isr_callback(); + + /* Check if nested SW radio low interrupt has been requested*/ + if (radio_sw_low_isr_is_running_high_prio != 0) { + NVIC_SetPriority((IRQn_Type) RADIO_SW_LOW_INTR_NUM, RADIO_INTR_PRIO_LOW); + radio_sw_low_isr_is_running_high_prio = 0; + } + + /* Re-enable SW radio low interrupt */ + irq_enable((IRQn_Type)RADIO_SW_LOW_INTR_NUM); + + ISR_DIRECT_PM(); +} + + +void link_layer_register_isr(void) +{ + ARM_IRQ_DIRECT_DYNAMIC_CONNECT(RADIO_INTR_NUM, 0, 0, reschedule); + + /* Ensure the IRQ is disabled before enabling it at run time */ + irq_disable((IRQn_Type)RADIO_INTR_NUM); + + irq_connect_dynamic((IRQn_Type)RADIO_INTR_NUM, RADIO_INTR_PRIO_HIGH_Z, + (void (*)(const void *))radio_high_prio_isr, NULL, 0); + + irq_enable((IRQn_Type)RADIO_INTR_NUM); + + ARM_IRQ_DIRECT_DYNAMIC_CONNECT(RADIO_SW_LOW_INTR_NUM, 0, 0, reschedule); + + /* Ensure the IRQ is disabled before enabling it at run time */ + irq_disable((IRQn_Type)RADIO_SW_LOW_INTR_NUM); + + irq_connect_dynamic((IRQn_Type)RADIO_SW_LOW_INTR_NUM, RADIO_SW_LOW_INTR_PRIO, + (void (*)(const void *))radio_low_prio_isr, NULL, 0); + + irq_enable((IRQn_Type)RADIO_SW_LOW_INTR_NUM); +} + + +void LINKLAYER_PLAT_TriggerSwLowIT(uint8_t priority) +{ + uint8_t low_isr_priority = RADIO_INTR_PRIO_LOW_Z; + + LOG_DBG("Priotity: %d", priority); + + /* Check if a SW low interrupt as already been raised. + * Nested call far radio low isr are not supported + **/ + + if (NVIC_GetActive(RADIO_SW_LOW_INTR_NUM) == 0) { + /* No nested SW low ISR, default behavior */ + + if (priority == 0) { + low_isr_priority = RADIO_SW_LOW_INTR_PRIO; + } + + NVIC_SetPriority((IRQn_Type)RADIO_SW_LOW_INTR_NUM, low_isr_priority); + } else { + /* Nested call detected */ + /* No change for SW radio low interrupt priority for the moment */ + + if (priority != 0) { + /* At the end of current SW radio low ISR, this pending SW + * low interrupt will run with RADIO_INTR_PRIO_LOW_Z priority + **/ + radio_sw_low_isr_is_running_high_prio = 1; + } + } + + NVIC_SetPendingIRQ((IRQn_Type)RADIO_SW_LOW_INTR_NUM); +} + +void LINKLAYER_PLAT_EnableIRQ(void) +{ + irq_counter = MAX(0, irq_counter - 1); + + if (irq_counter == 0) { + __enable_irq(); + } +} + +void LINKLAYER_PLAT_DisableIRQ(void) +{ + __disable_irq(); + + irq_counter++; +} + +void LINKLAYER_PLAT_Assert(uint8_t condition) +{ + __ASSERT_NO_MSG(condition); +} + +void LINKLAYER_PLAT_EnableSpecificIRQ(uint8_t isr_type) +{ + + LOG_DBG("isr_type: %d", isr_type); + + if ((isr_type & LL_HIGH_ISR_ONLY) != 0) { + prio_high_isr_counter--; + if (prio_high_isr_counter == 0) { + irq_enable(RADIO_INTR_NUM); + } + } + + if ((isr_type & LL_LOW_ISR_ONLY) != 0) { + prio_low_isr_counter--; + if (prio_low_isr_counter == 0) { + irq_enable(RADIO_SW_LOW_INTR_NUM); + } + } + + if ((isr_type & SYS_LOW_ISR) != 0) { + prio_sys_isr_counter--; + if (prio_sys_isr_counter == 0) { + __set_BASEPRI(local_basepri_value); + } + } +} + +void LINKLAYER_PLAT_DisableSpecificIRQ(uint8_t isr_type) +{ + + LOG_DBG("isr_type: %d", isr_type); + + if ((isr_type & LL_HIGH_ISR_ONLY) != 0) { + prio_high_isr_counter++; + if (prio_high_isr_counter == 1) { + irq_disable(RADIO_INTR_NUM); + } + } + + if ((isr_type & LL_LOW_ISR_ONLY) != 0) { + prio_low_isr_counter++; + if (prio_low_isr_counter == 1) { + irq_disable(RADIO_SW_LOW_INTR_NUM); + } + } + + if ((isr_type & SYS_LOW_ISR) != 0) { + prio_sys_isr_counter++; + if (prio_sys_isr_counter == 1) { + local_basepri_value = __get_BASEPRI(); + __set_BASEPRI_MAX(RADIO_INTR_PRIO_LOW_Z << 4); + } + } +} + +void LINKLAYER_PLAT_EnableRadioIT(void) +{ + irq_enable((IRQn_Type)RADIO_INTR_NUM); +} + +void LINKLAYER_PLAT_DisableRadioIT(void) +{ + irq_disable((IRQn_Type)RADIO_INTR_NUM); +} + +void LINKLAYER_PLAT_StartRadioEvt(void) +{ + __HAL_RCC_RADIO_CLK_SLEEP_ENABLE(); + + NVIC_SetPriority(RADIO_INTR_NUM, RADIO_INTR_PRIO_HIGH_Z); + + scm_notifyradiostate(SCM_RADIO_ACTIVE); +} + +void LINKLAYER_PLAT_StopRadioEvt(void) +{ + __HAL_RCC_RADIO_CLK_SLEEP_DISABLE(); + + NVIC_SetPriority(RADIO_INTR_NUM, RADIO_INTR_PRIO_LOW_Z); + + scm_notifyradiostate(SCM_RADIO_NOT_ACTIVE); +} + +void LINKLAYER_PLAT_RequestTemperature(void) {} + +void LINKLAYER_PLAT_SCHLDR_TIMING_UPDATE_NOT(Evnt_timing_t *p_evnt_timing) {} + +void LINKLAYER_PLAT_EnableOSContextSwitch(void) {} + +void LINKLAYER_PLAT_DisableOSContextSwitch(void) {} diff --git a/soc/arm/st_stm32/stm32wba/hci_if/linklayer_plat_local.h b/soc/arm/st_stm32/stm32wba/hci_if/linklayer_plat_local.h new file mode 100644 index 00000000000..1cf621b89de --- /dev/null +++ b/soc/arm/st_stm32/stm32wba/hci_if/linklayer_plat_local.h @@ -0,0 +1,13 @@ +/* + * Copyright (c) 2023 STMicroelectronics + * + * SPDX-License-Identifier: Apache-2.0 + */ + + +#ifndef _STM32WBA_LINK_LAYER_PLAT_LOCAL_H_ +#define _STM32WBA_LINK_LAYER_PLAT_LOCAL_H_ + +void link_layer_register_isr(void); + +#endif /* _STM32WBA_LINK_LAYER_PLAT_LOCAL_H_ */ diff --git a/soc/arm/st_stm32/stm32wba/hci_if/ll_sys_if.c b/soc/arm/st_stm32/stm32wba/hci_if/ll_sys_if.c new file mode 100644 index 00000000000..8607cbbafd8 --- /dev/null +++ b/soc/arm/st_stm32/stm32wba/hci_if/ll_sys_if.c @@ -0,0 +1,47 @@ +/* + * Copyright (c) 2023 STMicroelectronics + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include + +#include +#define LOG_LEVEL CONFIG_SOC_LOG_LEVEL +LOG_MODULE_REGISTER(ll_sys_if); + +#include "ll_intf.h" +#include "ll_sys.h" +#include "linklayer_plat.h" +#include "app_conf.h" + +extern struct k_mutex ble_ctlr_stack_mutex; +extern struct k_work_q ll_work_q; +struct k_work ll_sys_work; + +void ll_sys_schedule_bg_process(void) +{ + k_work_submit_to_queue(&ll_work_q, &ll_sys_work); +} + +void ll_sys_schedule_bg_process_isr(void) +{ + k_work_submit_to_queue(&ll_work_q, &ll_sys_work); +} + +static void ll_sys_bg_process_handler(struct k_work *work) +{ + k_mutex_lock(&ble_ctlr_stack_mutex, K_FOREVER); + ll_sys_bg_process(); + k_mutex_unlock(&ble_ctlr_stack_mutex); +} + +void ll_sys_bg_process_init(void) +{ + k_work_init(&ll_sys_work, &ll_sys_bg_process_handler); +} + +void ll_sys_config_params(void) +{ + ll_intf_config_ll_ctx_params(USE_RADIO_LOW_ISR, NEXT_EVENT_SCHEDULING_FROM_ISR); +} diff --git a/soc/arm/st_stm32/stm32wba/hci_if/stm32_timer.c b/soc/arm/st_stm32/stm32wba/hci_if/stm32_timer.c new file mode 100644 index 00000000000..45c3f1b3782 --- /dev/null +++ b/soc/arm/st_stm32/stm32wba/hci_if/stm32_timer.c @@ -0,0 +1,59 @@ +/* + * Copyright (c) 2023 STMicroelectronics + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include +#include + +#include "stm32_timer.h" + +#define TICKS_PER_MS (CONFIG_SYS_CLOCK_TICKS_PER_SEC / MSEC_PER_SEC) + +static struct k_timer timer; + +UTIL_TIMER_Status_t UTIL_TIMER_Create(UTIL_TIMER_Object_t *timer_object, + uint32_t period, UTIL_TIMER_Mode_t mode, + void (*callback)(void *), void *argument) +{ + if (timer_object == NULL) { + return UTIL_TIMER_INVALID_PARAM; + } + + timer_object->ReloadValue = period * TICKS_PER_MS; + timer_object->Mode = mode; + timer_object->Callback = callback; + timer_object->argument = argument; + timer_object->IsRunning = false; + timer_object->IsReloadStopped = false; + timer_object->Next = NULL; + + return UTIL_TIMER_OK; +} + +UTIL_TIMER_Status_t UTIL_TIMER_Start(UTIL_TIMER_Object_t *timer_object) +{ + if (timer_object == NULL) { + return UTIL_TIMER_INVALID_PARAM; + } + + k_timer_user_data_set(&timer, timer_object); + k_timer_start(&timer, K_TICKS(timer_object->ReloadValue), + K_TICKS(timer_object->ReloadValue)); + timer_object->IsRunning = true; + + return UTIL_TIMER_OK; +} + +UTIL_TIMER_Status_t UTIL_TIMER_Stop(UTIL_TIMER_Object_t *timer_object) +{ + if (timer_object == NULL) { + return UTIL_TIMER_INVALID_PARAM; + } + + k_timer_stop(&timer); + timer_object->IsRunning = false; + + return UTIL_TIMER_OK; +} From 2c88daab3b63c553ddde7dd04f59d28c29cf866d Mon Sep 17 00:00:00 2001 From: Erwan Gouriou Date: Wed, 22 Mar 2023 17:53:50 +0100 Subject: [PATCH 1383/3723] dts: stm32wba: Define SRAM6 as RAM_NOCACHE SRAM6 is used by RF and should be defined as RAM_NOCACHE to allow unaligned access reads. "IO" might be a better match but is not available on this arch. Signed-off-by: Erwan Gouriou --- dts/arm/st/wba/stm32wba.dtsi | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/dts/arm/st/wba/stm32wba.dtsi b/dts/arm/st/wba/stm32wba.dtsi index d9d718a9898..5c047a6926b 100644 --- a/dts/arm/st/wba/stm32wba.dtsi +++ b/dts/arm/st/wba/stm32wba.dtsi @@ -6,6 +6,7 @@ #include +#include #include #include #include @@ -61,6 +62,15 @@ compatible = "mmio-sram"; }; + /* Defining this memory solves unaligned memory access issue */ + sram6: memory@48028000 { + compatible = "zephyr,memory-region", "mmio-sram"; + reg = <0x48028000 DT_SIZE_K(16)>; + device_type = "memory"; + zephyr,memory-region = "SRAM6"; + zephyr,memory-attr = <( DT_MEM_ARM(ATTR_MPU_RAM_NOCACHE) )>; + }; + clocks { clk_hse: clk-hse { #clock-cells = <0>; From 79e55c2a04e65c75de30c73fc0f30b87fcdce035 Mon Sep 17 00:00:00 2001 From: Erwan Gouriou Date: Thu, 23 Mar 2023 09:05:25 +0100 Subject: [PATCH 1384/3723] dts: wba: configure HSI16 as RNG clk source We might have to do this differently: Configure rng default clock in .dtsi Set board specific config in .dts Signed-off-by: Erwan Gouriou --- dts/arm/st/wba/stm32wba.dtsi | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/dts/arm/st/wba/stm32wba.dtsi b/dts/arm/st/wba/stm32wba.dtsi index 5c047a6926b..6946f23f64e 100644 --- a/dts/arm/st/wba/stm32wba.dtsi +++ b/dts/arm/st/wba/stm32wba.dtsi @@ -443,7 +443,7 @@ reg = <0x520c0800 0x400>; interrupts = <59 0>; clocks = <&rcc STM32_CLOCK_BUS_AHB2 0x00040000>, - <&rcc STM32_SRC_PLL1_Q RNG_SEL(3)>; + <&rcc STM32_SRC_HSI16 RNG_SEL(2)>; nist-config = <0xf00d>; health-test-config = <0xaac7>; status = "disabled"; From aa8c9322dff15b99866427d4a704161c66758e46 Mon Sep 17 00:00:00 2001 From: Erwan Gouriou Date: Tue, 5 Dec 2023 16:45:44 +0100 Subject: [PATCH 1385/3723] boards: nucleo_wba55cg: Update clock configuration to be BLE compatible To be compatible with BLE operation and BLE Controler configuration, update board clock configuration to work using a fixed core clock at 16MHz. Signed-off-by: Erwan Gouriou --- boards/arm/nucleo_wba55cg/nucleo_wba55cg.dts | 18 ++++++++---------- 1 file changed, 8 insertions(+), 10 deletions(-) diff --git a/boards/arm/nucleo_wba55cg/nucleo_wba55cg.dts b/boards/arm/nucleo_wba55cg/nucleo_wba55cg.dts index 86d755cba50..b0510c624ad 100644 --- a/boards/arm/nucleo_wba55cg/nucleo_wba55cg.dts +++ b/boards/arm/nucleo_wba55cg/nucleo_wba55cg.dts @@ -58,24 +58,20 @@ &clk_hse { status = "okay"; + hse-div2; }; -&pll1 { - div-m = <8>; - mul-n = <48>; - div-q = <2>; - div-r = <2>; - clocks = <&clk_hse>; +&clk_hsi { status = "okay"; }; &rcc { - clocks = <&pll1>; - clock-frequency = ; + clocks = <&clk_hse>; + clock-frequency = ; ahb-prescaler = <1>; - ahb5-prescaler = <4>; + ahb5-prescaler = <2>; apb1-prescaler = <1>; - apb2-prescaler = <1>; + apb2-prescaler = <2>; apb7-prescaler = <1>; }; @@ -91,6 +87,8 @@ }; &usart1 { + clocks = <&rcc STM32_CLOCK_BUS_APB2 0x00004000>, + <&rcc STM32_SRC_HSI16 USART1_SEL(2)>; pinctrl-0 = <&usart1_tx_pb12 &usart1_rx_pa8>; pinctrl-names = "default"; current-speed = <115200>; From 44af61b865d859e2e68f88d73ece1d5b63e2a383 Mon Sep 17 00:00:00 2001 From: Erwan Gouriou Date: Tue, 5 Dec 2023 17:50:18 +0100 Subject: [PATCH 1386/3723] west.yml: Point to hal_stm32 version compatible with STM32WBA BLE Update west manifest to point to hal_stm32 PR containing changes which allow to build a zephyr bluetooth application on STM32WBA. Prior building such application, user should run 'west blobs fetch stm32' to install binary blobs providing the BLE controller support. Signed-off-by: Erwan Gouriou --- west.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/west.yml b/west.yml index 4cfffb58c91..0347bb086f6 100644 --- a/west.yml +++ b/west.yml @@ -229,7 +229,7 @@ manifest: groups: - hal - name: hal_stm32 - revision: 39903791f413a944b3ec926276557757ea47a691 + revision: d183c9c9f56dfed04da0b8e150424177ab9ce51e path: modules/hal/stm32 groups: - hal From dadd16996ad28fba4d4bf01b55909878606e6f6e Mon Sep 17 00:00:00 2001 From: Arnaud Pouliquen Date: Tue, 21 Nov 2023 15:30:01 +0100 Subject: [PATCH 1387/3723] west.yml: Update libmetal and open-amp for v2023.10 release Update to the last relase of open-amp library The libmetal is updated to a more recent commit to integrate 2 zephyr commits on top of the v2023.10 release. Signed-off-by: Arnaud Pouliquen --- west.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/west.yml b/west.yml index 0347bb086f6..d3b7591f372 100644 --- a/west.yml +++ b/west.yml @@ -258,7 +258,7 @@ manifest: path: modules/lib/hostap revision: 7adaff26baa48e26a32c576125e0a749a5239b12 - name: libmetal - revision: 03140d7f4bd9ba474ebfbb6256e84a9089248e67 + revision: cebd92d15c9759a9d49d508869081def927af4f0 path: modules/hal/libmetal groups: - hal @@ -298,7 +298,7 @@ manifest: revision: 9b985ea6bc237b6ae06f48eb228f2ac7f6e3b96b path: modules/bsim_hw_models/nrf_hw_models - name: open-amp - revision: 214f9fc1539f8e5937c0474cb6ee29b6dcb2d4b8 + revision: da78aea63159771956fe0c9263f2e6985b66e9d5 path: modules/lib/open-amp - name: openthread revision: 4ed44bc7d58d9a98c6cca13a50d38129045ab3df From 56570cc8c164b524f3eded011c153fe49441974b Mon Sep 17 00:00:00 2001 From: Yong Cong Sin Date: Wed, 6 Dec 2023 13:14:18 +0800 Subject: [PATCH 1388/3723] scripts: build: gen_isr_tables: fix calculation of THIRD_LVL_INTERRUPTS The calculation of `THIRD_LVL_INTERRUPTS` bitmask in the `update_masks()` function is wrong, the number of bits to shift should be the sum of the first two levels. Signed-off-by: Yong Cong Sin --- scripts/build/gen_isr_tables.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/scripts/build/gen_isr_tables.py b/scripts/build/gen_isr_tables.py index cd329f85551..314b56604ec 100755 --- a/scripts/build/gen_isr_tables.py +++ b/scripts/build/gen_isr_tables.py @@ -287,7 +287,7 @@ def update_masks(): FIRST_LVL_INTERRUPTS = bit_mask(INTERRUPT_BITS[0]) SECND_LVL_INTERRUPTS = bit_mask(INTERRUPT_BITS[1]) << INTERRUPT_BITS[0] - THIRD_LVL_INTERRUPTS = bit_mask(INTERRUPT_BITS[2]) << INTERRUPT_BITS[0] + INTERRUPT_BITS[2] + THIRD_LVL_INTERRUPTS = bit_mask(INTERRUPT_BITS[2]) << INTERRUPT_BITS[0] + INTERRUPT_BITS[1] def main(): parse_args() From b4db285c1fde9dcd287c1f0b084b7c6eaa691bfe Mon Sep 17 00:00:00 2001 From: Yong Cong Sin Date: Wed, 6 Dec 2023 13:17:55 +0800 Subject: [PATCH 1389/3723] scripts: build: gen_isr_tables: change naming of bitmask variables Rename the bitmask variables from `*_LVL_INTERRUPTS` to `INTERRUPT_LVL_BITMASK[]` array to be consistent with `INTERRUPT_BITS`, making it easier to loop over the bitmasks. Signed-off-by: Yong Cong Sin --- scripts/build/gen_isr_tables.py | 20 +++++++------------- 1 file changed, 7 insertions(+), 13 deletions(-) diff --git a/scripts/build/gen_isr_tables.py b/scripts/build/gen_isr_tables.py index 314b56604ec..ea14b0ebf52 100755 --- a/scripts/build/gen_isr_tables.py +++ b/scripts/build/gen_isr_tables.py @@ -23,9 +23,7 @@ # into 1 line which then goes into the 1st level) # 0x00FF0000 - represents the 3rd level (i.e. the interrupts funnel # into 1 line which then goes into the 2nd level) -FIRST_LVL_INTERRUPTS = 0x000000FF -SECND_LVL_INTERRUPTS = 0x0000FF00 -THIRD_LVL_INTERRUPTS = 0x00FF0000 +INTERRUPT_LVL_BITMASK = [0x000000FF, 0x0000FF00, 0x00FF0000] INTERRUPT_BITS = [8, 8, 8] @@ -278,16 +276,12 @@ def bit_mask(bits): return mask def update_masks(): - global FIRST_LVL_INTERRUPTS - global SECND_LVL_INTERRUPTS - global THIRD_LVL_INTERRUPTS - if sum(INTERRUPT_BITS) > 32: raise ValueError("Too many interrupt bits") - FIRST_LVL_INTERRUPTS = bit_mask(INTERRUPT_BITS[0]) - SECND_LVL_INTERRUPTS = bit_mask(INTERRUPT_BITS[1]) << INTERRUPT_BITS[0] - THIRD_LVL_INTERRUPTS = bit_mask(INTERRUPT_BITS[2]) << INTERRUPT_BITS[0] + INTERRUPT_BITS[1] + INTERRUPT_LVL_BITMASK[0] = bit_mask(INTERRUPT_BITS[0]) + INTERRUPT_LVL_BITMASK[1] = bit_mask(INTERRUPT_BITS[1]) << INTERRUPT_BITS[0] + INTERRUPT_LVL_BITMASK[2] = bit_mask(INTERRUPT_BITS[2]) << INTERRUPT_BITS[0] + INTERRUPT_BITS[1] def main(): parse_args() @@ -377,9 +371,9 @@ def main(): else: # Figure out third level interrupt position debug('IRQ = ' + hex(irq)) - irq3 = (irq & THIRD_LVL_INTERRUPTS) >> INTERRUPT_BITS[0] + INTERRUPT_BITS[1] - irq2 = (irq & SECND_LVL_INTERRUPTS) >> INTERRUPT_BITS[0] - irq1 = irq & FIRST_LVL_INTERRUPTS + irq3 = (irq & INTERRUPT_LVL_BITMASK[2]) >> INTERRUPT_BITS[0] + INTERRUPT_BITS[1] + irq2 = (irq & INTERRUPT_LVL_BITMASK[1]) >> INTERRUPT_BITS[0] + irq1 = irq & INTERRUPT_LVL_BITMASK[0] if irq3: irq_parent = irq2 From 0884a33ee3da3c20e6416039e0ec71927020f06a Mon Sep 17 00:00:00 2001 From: Yong Cong Sin Date: Wed, 6 Dec 2023 13:21:33 +0800 Subject: [PATCH 1390/3723] scripts: build: gen_isr_tables: add some debug prints Add some debug prints for the interrupts bits and bitmasks in each level. Signed-off-by: Yong Cong Sin --- scripts/build/gen_isr_tables.py | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/scripts/build/gen_isr_tables.py b/scripts/build/gen_isr_tables.py index ea14b0ebf52..13c9d79b0b3 100755 --- a/scripts/build/gen_isr_tables.py +++ b/scripts/build/gen_isr_tables.py @@ -283,6 +283,12 @@ def update_masks(): INTERRUPT_LVL_BITMASK[1] = bit_mask(INTERRUPT_BITS[1]) << INTERRUPT_BITS[0] INTERRUPT_LVL_BITMASK[2] = bit_mask(INTERRUPT_BITS[2]) << INTERRUPT_BITS[0] + INTERRUPT_BITS[1] + debug("Level Bits Bitmask") + debug("----------------------------") + for i in range(3): + bitmask_str = "0x" + format(INTERRUPT_LVL_BITMASK[i], '08X') + debug(f"{i + 1:>5} {INTERRUPT_BITS[i]:>7} {bitmask_str:>14}") + def main(): parse_args() From 170531eb2d46c7447ea088c3576b5b28ec34e752 Mon Sep 17 00:00:00 2001 From: Yong Cong Sin Date: Mon, 11 Dec 2023 15:14:23 +0800 Subject: [PATCH 1391/3723] tests: kernel: gen_isr_table: rework multi_level_bit_masks tests Reworked and combined the multi-level interrupt bit masks tests to work on any configuration of bits in every level. Updated the bits configuration in the testcase to use non-symetric numbers so that shifting a level with the wrong number of bits will certainly cause the test to fail. Signed-off-by: Yong Cong Sin --- tests/kernel/gen_isr_table/src/main.c | 179 ++++++++++++----------- tests/kernel/gen_isr_table/testcase.yaml | 10 +- 2 files changed, 98 insertions(+), 91 deletions(-) diff --git a/tests/kernel/gen_isr_table/src/main.c b/tests/kernel/gen_isr_table/src/main.c index c58b866a92e..6a6938c8e32 100644 --- a/tests/kernel/gen_isr_table/src/main.c +++ b/tests/kernel/gen_isr_table/src/main.c @@ -383,96 +383,103 @@ static void *gen_isr_table_setup(void) } #ifdef CONFIG_MULTI_LEVEL_INTERRUPTS -ZTEST(gen_isr_table, test_multi_level_bit_masks_sec) +static void test_multi_level_bit_masks_fn(uint32_t irq1, uint32_t irq2, uint32_t irq3) { -#if CONFIG_1ST_LEVEL_INTERRUPT_BITS < 10 && CONFIG_2ND_LEVEL_INTERRUPT_BITS < 10 - ztest_test_skip(); -#endif - /* 0x400 is an l2 interrupt */ - unsigned int irq = 0x400; - unsigned int level = 0; - unsigned int ret_irq = 0; - - level = irq_get_level(irq); - - zassert_equal(2, level); - - /* 0x40 is l1 interrupt since it is less than 10 bits */ - irq = 0x40; - level = irq_get_level(irq); - zassert_equal(1, level); - - /* this is an l2 interrupt since it is more than 10 bits */ - irq = 0x800; - ret_irq = irq_from_level_2(irq); - zassert_equal(1, ret_irq); - - /* convert l1 interrupt to l2 */ - irq = 0x1; - ret_irq = irq_to_level_2(irq); - zassert_equal(0x800, ret_irq); - - /* get the parent of this l2 interrupt */ - irq = 0x401; - ret_irq = irq_parent_level_2(irq); - zassert_equal(1, ret_irq); + const uint32_t l2_shift = CONFIG_1ST_LEVEL_INTERRUPT_BITS; + const uint32_t l3_shift = CONFIG_1ST_LEVEL_INTERRUPT_BITS + CONFIG_2ND_LEVEL_INTERRUPT_BITS; + const uint32_t hwirq1 = irq1; + const uint32_t hwirq2 = irq2 - 1; + const uint32_t hwirq3 = irq3 - 1; + const bool has_l3 = irq3 > 0; + const bool has_l2 = irq2 > 0; + const uint32_t level = has_l3 ? 3 : has_l2 ? 2 : 1; + const uint32_t irqn = (irq3 << l3_shift) | (irq2 << l2_shift) | irq1; + + zassert_equal(level, irq_get_level(irqn)); + + if (has_l2) { + zassert_equal(hwirq2, irq_from_level_2(irqn)); + zassert_equal((hwirq2 + 1) << l2_shift, irq_to_level_2(hwirq2)); + zassert_equal(hwirq1, irq_parent_level_2(irqn)); + } + + if (has_l3) { + zassert_equal(hwirq3, irq_from_level_3(irqn)); + zassert_equal((hwirq3 + 1) << l3_shift, irq_to_level_3(hwirq3)); + zassert_equal(hwirq2 + 1, irq_parent_level_3(irqn)); + } } -#endif -#ifdef CONFIG_3RD_LEVEL_INTERRUPTS -ZTEST(gen_isr_table, test_multi_level_bit_masks_thr) +ZTEST(gen_isr_table, test_multi_level_bit_masks_l1) { -#if CONFIG_2ND_LEVEL_INTERRUPT_BITS < 10 && CONFIG_3RD_LEVEL_INTERRUPT_BITS < 9 - ztest_test_skip(); -# endif - /* 0x400 is an l2 interrupt */ - unsigned int irq = 0x400; - unsigned int level = 0; - unsigned int ret_irq = 0; - - - /* note the first part of this test is the same as the above - * test this is to ensure the values are true after enabling l3 interrupts - */ - level = irq_get_level(irq); - - zassert_equal(2, level); - - /* this irq is within 10 bits so it is a l1 interrupt */ - irq = 0x40; - level = irq_get_level(irq); - zassert_equal(1, level); - - /* this irq is in the second 10 bits so it is a l2 interrupt */ - irq = 0x800; - ret_irq = irq_from_level_2(irq); - zassert_equal(1, ret_irq); - - /* convert a l1 interrupt to an l2 0x1 is less than 10 bits so it is l1 */ - irq = 0x1; - ret_irq = irq_to_level_2(irq); - zassert_equal(0x800, ret_irq); - - /* get the parent of an l2 interrupt 0x401 is an l2 interrupt with parent 1 */ - irq = 0x401; - ret_irq = irq_parent_level_2(irq); - zassert_equal(1, ret_irq); - - /* get the irq from level 3 this value is an l3 interrupt */ - irq = 0x200000; - ret_irq = irq_from_level_3(irq); - zassert_equal(1, ret_irq); - - /* convert the zero interrupt to l3 */ - irq = 0x0; - ret_irq = irq_to_level_3(irq); - zassert_equal(0x100000, ret_irq); - - /* parent of the l3 interrupt */ - irq = 0x101000; - ret_irq = irq_parent_level_3(irq); - zassert_equal(0x4, ret_irq); + uint32_t irq1; + + /* First IRQ of level 1 */ + irq1 = 0; + test_multi_level_bit_masks_fn(irq1, 0, 0); + + /* Somewhere in-between */ + irq1 = BIT_MASK(CONFIG_1ST_LEVEL_INTERRUPT_BITS) >> 1; + test_multi_level_bit_masks_fn(irq1, 0, 0); + + /* Last IRQ of level 1 */ + irq1 = BIT_MASK(CONFIG_1ST_LEVEL_INTERRUPT_BITS); + test_multi_level_bit_masks_fn(irq1, 0, 0); } -#endif + +ZTEST(gen_isr_table, test_multi_level_bit_masks_l2) +{ + if (!IS_ENABLED(CONFIG_2ND_LEVEL_INTERRUPTS)) { + ztest_test_skip(); + } + + uint32_t irq1, irq2; + + /* First IRQ of level 2 */ + irq1 = 0; + /* First irq of level 2 and onwards is 1, as 0 means that the irq is not present */ + irq2 = 1; + test_multi_level_bit_masks_fn(irq1, irq2, 0); + + /* Somewhere in-between */ + irq1 = BIT_MASK(CONFIG_1ST_LEVEL_INTERRUPT_BITS) >> 1; + irq2 = BIT_MASK(CONFIG_2ND_LEVEL_INTERRUPT_BITS) >> 1; + test_multi_level_bit_masks_fn(irq1, irq2, 0); + + /* Last IRQ of level 2 */ + irq1 = BIT_MASK(CONFIG_1ST_LEVEL_INTERRUPT_BITS); + irq2 = BIT_MASK(CONFIG_2ND_LEVEL_INTERRUPT_BITS); + test_multi_level_bit_masks_fn(irq1, irq2, 0); +} + +ZTEST(gen_isr_table, test_multi_level_bit_masks_l3) +{ + if (!IS_ENABLED(CONFIG_3RD_LEVEL_INTERRUPTS)) { + ztest_test_skip(); + } + + uint32_t irq1, irq2, irq3; + + /* First IRQ of level 3 */ + irq1 = 0; + /* First irq of level 2 and onwards is 1, as 0 means that the irq is not present */ + irq2 = 1; + irq3 = 1; + test_multi_level_bit_masks_fn(irq1, irq2, irq3); + + /* Somewhere in-between */ + irq1 = BIT_MASK(CONFIG_1ST_LEVEL_INTERRUPT_BITS) >> 1; + irq2 = BIT_MASK(CONFIG_2ND_LEVEL_INTERRUPT_BITS) >> 1; + irq3 = BIT_MASK(CONFIG_3RD_LEVEL_INTERRUPT_BITS) >> 1; + test_multi_level_bit_masks_fn(irq1, irq2, irq3); + + /* Last IRQ of level 3 */ + irq1 = BIT_MASK(CONFIG_1ST_LEVEL_INTERRUPT_BITS); + irq2 = BIT_MASK(CONFIG_2ND_LEVEL_INTERRUPT_BITS); + irq3 = BIT_MASK(CONFIG_3RD_LEVEL_INTERRUPT_BITS); + test_multi_level_bit_masks_fn(irq1, irq2, irq3); +} + +#endif /* CONFIG_MULTI_LEVEL_INTERRUPTS */ ZTEST_SUITE(gen_isr_table, NULL, gen_isr_table_setup, NULL, NULL, NULL); diff --git a/tests/kernel/gen_isr_table/testcase.yaml b/tests/kernel/gen_isr_table/testcase.yaml index cd8c95e2584..29c4316dafa 100644 --- a/tests/kernel/gen_isr_table/testcase.yaml +++ b/tests/kernel/gen_isr_table/testcase.yaml @@ -68,8 +68,8 @@ tests: platform_allow: qemu_riscv32 filter: CONFIG_SOC_FAMILY_RISCV_PRIVILEGED extra_configs: - - CONFIG_1ST_LEVEL_INTERRUPT_BITS=10 - - CONFIG_2ND_LEVEL_INTERRUPT_BITS=10 + - CONFIG_1ST_LEVEL_INTERRUPT_BITS=7 + - CONFIG_2ND_LEVEL_INTERRUPT_BITS=9 arch.interrupt.gen_isr_table.bit_shift_3rd_level: platform_allow: qemu_riscv32 filter: CONFIG_SOC_FAMILY_RISCV_PRIVILEGED @@ -77,6 +77,6 @@ tests: - CONFIG_MULTI_LEVEL_INTERRUPTS=y - CONFIG_2ND_LEVEL_INTERRUPTS=y - CONFIG_3RD_LEVEL_INTERRUPTS=y - - CONFIG_1ST_LEVEL_INTERRUPT_BITS=10 - - CONFIG_2ND_LEVEL_INTERRUPT_BITS=10 - - CONFIG_3RD_LEVEL_INTERRUPT_BITS=9 + - CONFIG_1ST_LEVEL_INTERRUPT_BITS=8 + - CONFIG_2ND_LEVEL_INTERRUPT_BITS=11 + - CONFIG_3RD_LEVEL_INTERRUPT_BITS=13 From 52b8858e829453b6cbad15232b25129681bf562a Mon Sep 17 00:00:00 2001 From: Anas Nashif Date: Mon, 18 Dec 2023 12:41:31 -0500 Subject: [PATCH 1392/3723] ci: upload merged coverage file as artifact Upload merged coverage file as artifact for verification and inspection. Signed-off-by: Anas Nashif --- .github/workflows/codecov.yaml | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/.github/workflows/codecov.yaml b/.github/workflows/codecov.yaml index 0ea3641d1e7..9e841025993 100644 --- a/.github/workflows/codecov.yaml +++ b/.github/workflows/codecov.yaml @@ -165,6 +165,13 @@ jobs: cd ./coverage/reports lcov ${{ steps.get-coverage-files.outputs.mergefiles }} -o merged.info --rc lcov_branch_coverage=1 + - name: Upload Merged Coverage Results + if: always() + uses: actions/upload-artifact@v3 + with: + name: Merged Coverage Data + path: merged.info + - name: Upload coverage to Codecov if: always() uses: codecov/codecov-action@v3 From 2876dcabbf0153b3076238247c8c647240d40329 Mon Sep 17 00:00:00 2001 From: Manuel Loew Date: Tue, 5 Dec 2023 16:15:01 +0100 Subject: [PATCH 1393/3723] boards: Corrects RAM size of CY8CPROTO-062-4343W PSoC6 eval board. This PR corrects the RAM size specification of the Infineon CY8CPROTO-062-4343W PSoC6 eval board. Fixes #60876 Signed-off-by: Manuel Loew --- boards/arm/cy8cproto_062_4343w/cy8cproto_062_4343w.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/boards/arm/cy8cproto_062_4343w/cy8cproto_062_4343w.yaml b/boards/arm/cy8cproto_062_4343w/cy8cproto_062_4343w.yaml index b6d56577209..8300a160c5a 100644 --- a/boards/arm/cy8cproto_062_4343w/cy8cproto_062_4343w.yaml +++ b/boards/arm/cy8cproto_062_4343w/cy8cproto_062_4343w.yaml @@ -7,7 +7,7 @@ identifier: cy8cproto_062_4343w name: CY8CPROTO-062-4343W PSoC 6 Wi-Fi BT Prototyping Kit type: mcu arch: arm -ram: 288 +ram: 1024 flash: 2048 toolchain: - zephyr From cda5e58aa5e5a8cab81c42a5a3b8cd87c8021771 Mon Sep 17 00:00:00 2001 From: Emil Gydesen Date: Mon, 6 Nov 2023 13:19:00 +0100 Subject: [PATCH 1394/3723] Bluetooth: CAP: Commander discovery support Implement the CAP Commander discovery function. Adds support for it in the shell. This includes initial babblesim and unit testing as well. Signed-off-by: Emil Gydesen --- doc/connectivity/bluetooth/api/shell/cap.rst | 37 +++ include/zephyr/bluetooth/audio/cap.h | 56 ++++- subsys/bluetooth/audio/cap_commander.c | 54 ++++- subsys/bluetooth/audio/cap_common.c | 17 +- subsys/bluetooth/audio/ccid_internal.h | 1 - subsys/bluetooth/audio/shell/CMakeLists.txt | 4 + subsys/bluetooth/audio/shell/cap_commander.c | 79 +++++++ .../audio/cap_commander/CMakeLists.txt | 18 ++ tests/bluetooth/audio/cap_commander/prj.conf | 18 ++ .../bluetooth/audio/cap_commander/src/main.c | 166 ++++++++++++++ .../audio/cap_commander/testcase.yaml | 7 + .../audio/cap_commander/uut/CMakeLists.txt | 21 ++ .../bluetooth/audio/cap_commander/uut/csip.c | 62 +++++ tests/bluetooth/audio/mocks/CMakeLists.txt | 1 + .../audio/mocks/include/cap_commander.h | 21 ++ .../bluetooth/audio/mocks/src/cap_commander.c | 28 +++ tests/bluetooth/audio/mocks/src/gatt.c | 60 +++++ tests/bluetooth/shell/testcase.yaml | 6 + tests/bsim/bluetooth/audio/prj.conf | 1 + .../bluetooth/audio/src/cap_acceptor_test.c | 15 ++ .../bluetooth/audio/src/cap_commander_test.c | 216 ++++++++++++++++++ tests/bsim/bluetooth/audio/src/common.c | 5 + tests/bsim/bluetooth/audio/src/common.h | 1 + tests/bsim/bluetooth/audio/src/main.c | 2 + .../test_scripts/cap_capture_and_render.sh | 33 +++ 25 files changed, 917 insertions(+), 12 deletions(-) create mode 100644 subsys/bluetooth/audio/shell/cap_commander.c create mode 100644 tests/bluetooth/audio/cap_commander/CMakeLists.txt create mode 100644 tests/bluetooth/audio/cap_commander/prj.conf create mode 100644 tests/bluetooth/audio/cap_commander/src/main.c create mode 100644 tests/bluetooth/audio/cap_commander/testcase.yaml create mode 100644 tests/bluetooth/audio/cap_commander/uut/CMakeLists.txt create mode 100644 tests/bluetooth/audio/cap_commander/uut/csip.c create mode 100644 tests/bluetooth/audio/mocks/include/cap_commander.h create mode 100644 tests/bluetooth/audio/mocks/src/cap_commander.c create mode 100644 tests/bsim/bluetooth/audio/src/cap_commander_test.c create mode 100755 tests/bsim/bluetooth/audio/test_scripts/cap_capture_and_render.sh diff --git a/doc/connectivity/bluetooth/api/shell/cap.rst b/doc/connectivity/bluetooth/api/shell/cap.rst index 5ab57a8d320..13c8d665421 100644 --- a/doc/connectivity/bluetooth/api/shell/cap.rst +++ b/doc/connectivity/bluetooth/api/shell/cap.rst @@ -137,3 +137,40 @@ used. uart:~$ cap_initiator unicast-stop Unicast stopped for group 0x81e41c0 completed + +CAP Commander +************* + +The Commander will typically be a either co-located with a CAP Initiator or be on a separate +resource-rich mobile device, such as a phone or smartwatch. The Commander can +discover CAP Acceptors's CAS and optional CSIS services. The CSIS service can be read to provide +information about other CAP Acceptors in the same Coordinated Set. The Commander can provide +information about broadcast sources to CAP Acceptors or coordinate capture and rendering information +such as mute or volume states. + +Using the CAP Commander +======================= + +When the Bluetooth stack has been initialized (:code:`bt init`), the Commander can discover CAS and +the optionally included CSIS instance by calling (:code:`cap_commander discover`). + +.. code-block:: console + + cap_commander --help + cap_commander - Bluetooth CAP commander shell commands + Subcommands: + discover :Discover CAS + +Before being able to perform any stream operation, the device must also perform the +:code:`bap discover` operation to discover the ASEs and PAC records. The :code:`bap init` +command also needs to be called. + +When connected +-------------- + +Discovering CAS and CSIS on a device: + +.. code-block:: console + + uart:~$ cap_commander discover + discovery completed with CSIS diff --git a/include/zephyr/bluetooth/audio/cap.h b/include/zephyr/bluetooth/audio/cap.h index 06b148ce461..19aa1e4092b 100644 --- a/include/zephyr/bluetooth/audio/cap.h +++ b/include/zephyr/bluetooth/audio/cap.h @@ -131,7 +131,10 @@ struct bt_cap_initiator_cb { * * @param conn Connection to a remote server. * - * @return 0 on success or negative error value on failure. + * @retval 0 Success + * @retval -EINVAL @p conn is NULL + * @retval -ENOTCONN @p conn is not connected + * @retval -ENOMEM Could not allocated memory for the request */ int bt_cap_initiator_unicast_discover(struct bt_conn *conn); @@ -250,7 +253,7 @@ struct bt_cap_unicast_audio_update_param { }; /** - * @brief Register Common Audio Profile callbacks + * @brief Register Common Audio Profile Initiator callbacks * * @param cb The callback structure. Shall remain static. * @@ -636,6 +639,45 @@ struct bt_cap_broadcast_to_unicast_param { int bt_cap_initiator_broadcast_to_unicast(const struct bt_cap_broadcast_to_unicast_param *param, struct bt_bap_unicast_group **unicast_group); +/** Callback structure for CAP procedures */ +struct bt_cap_commander_cb { + /** + * @brief Callback for bt_cap_initiator_unicast_discover(). + * + * @param conn The connection pointer supplied to + * bt_cap_initiator_unicast_discover(). + * @param err 0 if Common Audio Service was found else -ENODATA. + * @param csis_inst The Coordinated Set Identification Service if + * Common Audio Service was found and includes a + * Coordinated Set Identification Service. + * NULL on error or if remote device does not include + * Coordinated Set Identification Service. + */ + void (*discovery_complete)(struct bt_conn *conn, int err, + const struct bt_csip_set_coordinator_csis_inst *csis_inst); +}; + +/** + * @brief Register Common Audio Profile Commander callbacks + * + * @param cb The callback structure. Shall remain static. + * + * @retval 0 Success + * @retval -EINVAL @p cb is NULL + * @retval -EALREADY Callbacks are already registered + */ +int bt_cap_commander_register_cb(const struct bt_cap_commander_cb *cb); + +/** + * @brief Unregister Common Audio Profile Commander callbacks + * + * @param cb The callback structure that was previously registered. + * + * @retval 0 Success + * @retval -EINVAL @p cb is NULL or @p cb was not registered + */ +int bt_cap_commander_unregister_cb(const struct bt_cap_commander_cb *cb); + /** * @brief Discovers audio support on a remote device. * @@ -644,13 +686,17 @@ int bt_cap_initiator_broadcast_to_unicast(const struct bt_cap_broadcast_to_unica * * @note @kconfig{CONFIG_BT_CAP_COMMANDER} must be enabled for this function. If * @kconfig{CONFIG_BT_CAP_INITIATOR} is also enabled, it does not matter if - * bt_cap_commander_unicast_discover() or bt_cap_initiator_unicast_discover() is used. + * bt_cap_commander_discover() or bt_cap_initiator_unicast_discover() is used. * * @param conn Connection to a remote server. * - * @return 0 on success or negative error value on failure. + * @retval 0 Success + * @retval -EINVAL @p conn is NULL + * @retval -ENOTCONN @p conn is not connected + * @retval -ENOMEM Could not allocated memory for the request + * @retval -EBUSY Already doing discovery for @p conn */ -int bt_cap_commander_unicast_discover(struct bt_conn *conn); +int bt_cap_commander_discover(struct bt_conn *conn); struct bt_cap_commander_broadcast_reception_start_member_param { /** Coordinated or ad-hoc set member. */ diff --git a/subsys/bluetooth/audio/cap_commander.c b/subsys/bluetooth/audio/cap_commander.c index ffe8cd0f89a..611cf1fcacf 100644 --- a/subsys/bluetooth/audio/cap_commander.c +++ b/subsys/bluetooth/audio/cap_commander.c @@ -20,9 +20,59 @@ LOG_MODULE_REGISTER(bt_cap_commander, CONFIG_BT_CAP_COMMANDER_LOG_LEVEL); #include "common/bt_str.h" -int bt_cap_commander_unicast_discover(struct bt_conn *conn) +static const struct bt_cap_commander_cb *cap_cb; + +int bt_cap_commander_register_cb(const struct bt_cap_commander_cb *cb) { - return -ENOSYS; + CHECKIF(cb == NULL) { + LOG_DBG("cb is NULL"); + return -EINVAL; + } + + CHECKIF(cap_cb != NULL) { + LOG_DBG("callbacks already registered"); + return -EALREADY; + } + + cap_cb = cb; + + return 0; +} + +int bt_cap_commander_unregister_cb(const struct bt_cap_commander_cb *cb) +{ + CHECKIF(cb == NULL) { + LOG_DBG("cb is NULL"); + return -EINVAL; + } + + CHECKIF(cap_cb != cb) { + LOG_DBG("cb is not registered"); + return -EINVAL; + } + + cap_cb = NULL; + + return 0; +} + +static void +cap_commander_discover_complete(struct bt_conn *conn, int err, + const struct bt_csip_set_coordinator_csis_inst *csis_inst) +{ + if (cap_cb && cap_cb->discovery_complete) { + cap_cb->discovery_complete(conn, err, csis_inst); + } +} + +int bt_cap_commander_discover(struct bt_conn *conn) +{ + CHECKIF(conn == NULL) { + LOG_DBG("NULL conn"); + return -EINVAL; + } + + return bt_cap_common_discover(conn, cap_commander_discover_complete); } int bt_cap_commander_broadcast_reception_start( diff --git a/subsys/bluetooth/audio/cap_common.c b/subsys/bluetooth/audio/cap_common.c index c0862f3e98b..b341dcfc0d8 100644 --- a/subsys/bluetooth/audio/cap_common.c +++ b/subsys/bluetooth/audio/cap_common.c @@ -240,7 +240,6 @@ static uint8_t bt_cap_common_discover_included_cb(struct bt_conn *conn, client->csis_start_handle = included_service->start_handle; client->csis_inst = bt_csip_set_coordinator_csis_inst_by_handle( conn, client->csis_start_handle); - if (client->csis_inst == NULL) { static struct bt_csip_set_coordinator_cb csis_client_cb = { .discover = csis_client_discover_cb, @@ -325,10 +324,20 @@ int bt_cap_common_discover(struct bt_conn *conn, bt_cap_common_discover_func_t f param->start_handle = BT_ATT_FIRST_ATTRIBUTE_HANDLE; param->end_handle = BT_ATT_LAST_ATTRIBUTE_HANDLE; + discover_cb_func = func; + err = bt_gatt_discover(conn, param); - if (err == 0) { - discover_cb_func = func; + if (err != 0) { + discover_cb_func = NULL; + + /* Report expected possible errors */ + if (err == -ENOTCONN || err == -ENOMEM) { + return err; + } + + LOG_DBG("Unexpected err %d from bt_gatt_discover", err); + return -ENOEXEC; } - return err; + return 0; } diff --git a/subsys/bluetooth/audio/ccid_internal.h b/subsys/bluetooth/audio/ccid_internal.h index 87cca3d7098..bf48877529d 100644 --- a/subsys/bluetooth/audio/ccid_internal.h +++ b/subsys/bluetooth/audio/ccid_internal.h @@ -10,7 +10,6 @@ #ifndef ZEPHYR_INCLUDE_BLUETOOTH_CCID_H_ #define ZEPHYR_INCLUDE_BLUETOOTH_CCID_H_ -#include #include /** diff --git a/subsys/bluetooth/audio/shell/CMakeLists.txt b/subsys/bluetooth/audio/shell/CMakeLists.txt index 11775acc8ab..18cb1df9933 100644 --- a/subsys/bluetooth/audio/shell/CMakeLists.txt +++ b/subsys/bluetooth/audio/shell/CMakeLists.txt @@ -59,6 +59,10 @@ zephyr_library_sources_ifdef( CONFIG_BT_CAP_INITIATOR cap_initiator.c ) +zephyr_library_sources_ifdef( + CONFIG_BT_CAP_COMMANDER + cap_commander.c + ) zephyr_library_sources_ifdef( CONFIG_BT_HAS_CLIENT has_client.c diff --git a/subsys/bluetooth/audio/shell/cap_commander.c b/subsys/bluetooth/audio/shell/cap_commander.c new file mode 100644 index 00000000000..0545197341f --- /dev/null +++ b/subsys/bluetooth/audio/shell/cap_commander.c @@ -0,0 +1,79 @@ +/** + * @file + * @brief Shell APIs for Bluetooth CAP commander + * + * Copyright (c) 2023 Nordic Semiconductor ASA + * + * SPDX-License-Identifier: Apache-2.0 + */ +#include + +#include +#include +#include +#include + +#include "shell/bt.h" +#include "audio.h" + +static void cap_discover_cb(struct bt_conn *conn, int err, + const struct bt_csip_set_coordinator_csis_inst *csis_inst) +{ + if (err != 0) { + shell_error(ctx_shell, "discover failed (%d)", err); + return; + } + + shell_print(ctx_shell, "discovery completed%s", csis_inst == NULL ? "" : " with CSIS"); +} + +static struct bt_cap_commander_cb cbs = { + .discovery_complete = cap_discover_cb, +}; + +static int cmd_cap_commander_discover(const struct shell *sh, size_t argc, char *argv[]) +{ + static bool cbs_registered; + int err; + + if (default_conn == NULL) { + shell_error(sh, "Not connected"); + return -ENOEXEC; + } + + if (ctx_shell == NULL) { + ctx_shell = sh; + } + + if (!cbs_registered) { + bt_cap_commander_register_cb(&cbs); + cbs_registered = true; + } + + err = bt_cap_commander_discover(default_conn); + if (err != 0) { + shell_error(sh, "Fail: %d", err); + } + + return err; +} + +static int cmd_cap_commander(const struct shell *sh, size_t argc, char **argv) +{ + if (argc > 1) { + shell_error(sh, "%s unknown parameter: %s", argv[0], argv[1]); + } else { + shell_error(sh, "%s Missing subcommand", argv[0]); + } + + return -ENOEXEC; +} + +SHELL_STATIC_SUBCMD_SET_CREATE( + cap_commander_cmds, + SHELL_CMD_ARG(discover, NULL, "Discover CAS", cmd_cap_commander_discover, 1, 0), + SHELL_SUBCMD_SET_END +); + +SHELL_CMD_ARG_REGISTER(cap_commander, &cap_commander_cmds, "Bluetooth CAP commander shell commands", + cmd_cap_commander, 1, 1); diff --git a/tests/bluetooth/audio/cap_commander/CMakeLists.txt b/tests/bluetooth/audio/cap_commander/CMakeLists.txt new file mode 100644 index 00000000000..17f6ad2f4b2 --- /dev/null +++ b/tests/bluetooth/audio/cap_commander/CMakeLists.txt @@ -0,0 +1,18 @@ +# SPDX-License-Identifier: Apache-2.0 + +cmake_minimum_required(VERSION 3.20.0) + +project(bluetooth_ascs) +find_package(Zephyr COMPONENTS unittest HINTS $ENV{ZEPHYR_BASE}) + +add_subdirectory(${ZEPHYR_BASE}/tests/bluetooth/audio/cap_commander/uut uut) + +target_link_libraries(testbinary PRIVATE uut) + +target_include_directories(testbinary PRIVATE include) + +target_sources(testbinary + PRIVATE + ${ZEPHYR_BASE}/subsys/bluetooth/host/uuid.c + src/main.c +) diff --git a/tests/bluetooth/audio/cap_commander/prj.conf b/tests/bluetooth/audio/cap_commander/prj.conf new file mode 100644 index 00000000000..e4e2edeb05a --- /dev/null +++ b/tests/bluetooth/audio/cap_commander/prj.conf @@ -0,0 +1,18 @@ +CONFIG_ZTEST=y + +CONFIG_BT=y +CONFIG_BT_CENTRAL=y +CONFIG_BT_AUDIO=y + +# Requirements for CAP commander +CONFIG_BT_VCP_VOL_CTLR=y +CONFIG_BT_CSIP_SET_COORDINATOR=y + +CONFIG_BT_CAP_COMMANDER=y + +CONFIG_LOG=y +CONFIG_BT_CAP_COMMANDER_LOG_LEVEL_DBG=y + +CONFIG_ASSERT=y +CONFIG_ASSERT_LEVEL=2 +CONFIG_ASSERT_VERBOSE=y diff --git a/tests/bluetooth/audio/cap_commander/src/main.c b/tests/bluetooth/audio/cap_commander/src/main.c new file mode 100644 index 00000000000..b095eead8e5 --- /dev/null +++ b/tests/bluetooth/audio/cap_commander/src/main.c @@ -0,0 +1,166 @@ +/* main.c - Application main entry point */ + +/* + * Copyright (c) 2023 Nordic Semiconductor ASA + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include + +#include +#include + +#include "bluetooth.h" +#include "cap_commander.h" +#include "conn.h" +#include "expects_util.h" + +DEFINE_FFF_GLOBALS; + +static void mock_init_rule_before(const struct ztest_unit_test *test, void *fixture) +{ + mock_cap_commander_init(); +} + +static void mock_destroy_rule_after(const struct ztest_unit_test *test, void *fixture) +{ + mock_cap_commander_cleanup(); +} + +ZTEST_RULE(mock_rule, mock_init_rule_before, mock_destroy_rule_after); + +struct cap_commander_test_suite_fixture { + struct bt_conn conn; +}; + +static void test_conn_init(struct bt_conn *conn) +{ + conn->index = 0; + conn->info.type = BT_CONN_TYPE_LE; + conn->info.role = BT_CONN_ROLE_PERIPHERAL; + conn->info.state = BT_CONN_STATE_CONNECTED; + conn->info.security.level = BT_SECURITY_L2; + conn->info.security.enc_key_size = BT_ENC_KEY_SIZE_MAX; + conn->info.security.flags = BT_SECURITY_FLAG_OOB | BT_SECURITY_FLAG_SC; +} + +static void cap_commander_test_suite_fixture_init(struct cap_commander_test_suite_fixture *fixture) +{ + test_conn_init(&fixture->conn); +} + +static void *cap_commander_test_suite_setup(void) +{ + struct cap_commander_test_suite_fixture *fixture; + + fixture = malloc(sizeof(*fixture)); + zassert_not_null(fixture); + + return fixture; +} + +static void cap_commander_test_suite_before(void *f) +{ + memset(f, 0, sizeof(struct cap_commander_test_suite_fixture)); + cap_commander_test_suite_fixture_init(f); +} + +static void cap_commander_test_suite_after(void *f) +{ + bt_cap_commander_unregister_cb(&mock_cap_commander_cb); +} + +static void cap_commander_test_suite_teardown(void *f) +{ + free(f); +} + +ZTEST_SUITE(cap_commander_test_suite, NULL, cap_commander_test_suite_setup, + cap_commander_test_suite_before, cap_commander_test_suite_after, + cap_commander_test_suite_teardown); + +ZTEST_F(cap_commander_test_suite, test_commander_register_cb) +{ + int err; + + err = bt_cap_commander_register_cb(&mock_cap_commander_cb); + zassert_equal(0, err, "Unexpected return value %d", err); +} + +ZTEST_F(cap_commander_test_suite, test_commander_register_cb_inval_param_null) +{ + int err; + + err = bt_cap_commander_register_cb(NULL); + zassert_equal(-EINVAL, err, "Unexpected return value %d", err); +} + +ZTEST_F(cap_commander_test_suite, test_commander_register_cb_inval_double_register) +{ + int err; + + err = bt_cap_commander_register_cb(&mock_cap_commander_cb); + zassert_equal(0, err, "Unexpected return value %d", err); + + err = bt_cap_commander_register_cb(&mock_cap_commander_cb); + zassert_equal(-EALREADY, err, "Unexpected return value %d", err); +} + +ZTEST_F(cap_commander_test_suite, test_commander_unregister_cb) +{ + int err; + + err = bt_cap_commander_register_cb(&mock_cap_commander_cb); + zassert_equal(0, err, "Unexpected return value %d", err); + + err = bt_cap_commander_unregister_cb(&mock_cap_commander_cb); + zassert_equal(0, err, "Unexpected return value %d", err); +} + +ZTEST_F(cap_commander_test_suite, test_commander_unregister_cb_inval_param_null) +{ + int err; + + err = bt_cap_commander_unregister_cb(NULL); + zassert_equal(-EINVAL, err, "Unexpected return value %d", err); +} + +ZTEST_F(cap_commander_test_suite, test_commander_unregister_cb_inval_double_unregister) +{ + int err; + + err = bt_cap_commander_register_cb(&mock_cap_commander_cb); + zassert_equal(0, err, "Unexpected return value %d", err); + + err = bt_cap_commander_unregister_cb(&mock_cap_commander_cb); + zassert_equal(0, err, "Unexpected return value %d", err); + + err = bt_cap_commander_unregister_cb(&mock_cap_commander_cb); + zassert_equal(-EINVAL, err, "Unexpected return value %d", err); +} + +ZTEST_F(cap_commander_test_suite, test_commander_discover) +{ + int err; + + err = bt_cap_commander_register_cb(&mock_cap_commander_cb); + zassert_equal(0, err, "Unexpected return value %d", err); + + err = bt_cap_commander_discover(&fixture->conn); + zassert_equal(0, err, "Unexpected return value %d", err); + + zexpect_call_count("bt_cap_commander_cb.discovery_complete", 1, + mock_cap_commander_discovery_complete_cb_fake.call_count); +} + +ZTEST_F(cap_commander_test_suite, test_commander_discover_inval_param_null) +{ + int err; + + err = bt_cap_commander_register_cb(&mock_cap_commander_cb); + zassert_equal(0, err, "Unexpected return value %d", err); + + err = bt_cap_commander_discover(NULL); + zassert_equal(-EINVAL, err, "Unexpected return value %d", err); +} diff --git a/tests/bluetooth/audio/cap_commander/testcase.yaml b/tests/bluetooth/audio/cap_commander/testcase.yaml new file mode 100644 index 00000000000..e37b5c0d22a --- /dev/null +++ b/tests/bluetooth/audio/cap_commander/testcase.yaml @@ -0,0 +1,7 @@ +common: + tags: + - bluetooth + - bluetooth_audio +tests: + bluetooth.audio.cap_commander.test_default: + type: unit diff --git a/tests/bluetooth/audio/cap_commander/uut/CMakeLists.txt b/tests/bluetooth/audio/cap_commander/uut/CMakeLists.txt new file mode 100644 index 00000000000..8dc2539f682 --- /dev/null +++ b/tests/bluetooth/audio/cap_commander/uut/CMakeLists.txt @@ -0,0 +1,21 @@ +# +# Copyright (c) 2023 Nordic Semiconductor ASA +# +# SPDX-License-Identifier: Apache-2.0 +# +# CMakeLists.txt file for creating of uut library. +# + +add_library(uut STATIC + ${ZEPHYR_BASE}/subsys/bluetooth/audio/cap_commander.c + ${ZEPHYR_BASE}/subsys/bluetooth/audio/cap_common.c + ${ZEPHYR_BASE}/subsys/logging/log_minimal.c + ${ZEPHYR_BASE}/subsys/net/buf_simple.c + csip.c +) + +add_subdirectory(${ZEPHYR_BASE}/tests/bluetooth/audio/mocks mocks) + +target_link_libraries(uut PUBLIC test_interface mocks) + +target_compile_options(uut PRIVATE -std=c11 -include ztest.h) diff --git a/tests/bluetooth/audio/cap_commander/uut/csip.c b/tests/bluetooth/audio/cap_commander/uut/csip.c new file mode 100644 index 00000000000..348b1ac9146 --- /dev/null +++ b/tests/bluetooth/audio/cap_commander/uut/csip.c @@ -0,0 +1,62 @@ +/* csip.c - CAP Commander specific CSIP mocks */ + +/* + * Copyright (c) 2023 Nordic Semiconductor ASA + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include + +static struct bt_csip_set_coordinator_cb *csip_cb; + +struct bt_csip_set_coordinator_svc_inst { + struct bt_conn *conn; + struct bt_csip_set_coordinator_set_info *set_info; +} svc_inst; + +static struct bt_csip_set_coordinator_set_member member = { + .insts = { + { + .info = { + .set_size = 2, + .rank = 1, + .lockable = false, + }, + .svc_inst = &svc_inst, + }, + }, +}; + +struct bt_csip_set_coordinator_csis_inst * +bt_csip_set_coordinator_csis_inst_by_handle(struct bt_conn *conn, uint16_t start_handle) +{ + return &member.insts[0]; +} + +int bt_csip_set_coordinator_register_cb(struct bt_csip_set_coordinator_cb *cb) +{ + csip_cb = cb; + + return 0; +} + +int bt_csip_set_coordinator_discover(struct bt_conn *conn) +{ + if (csip_cb != NULL) { + svc_inst.conn = conn; + svc_inst.set_info = &member.insts[0].info; + csip_cb->discover(conn, &member, 0, 1); + } + + return 0; +} + +void mock_bt_csip_init(void) +{ + csip_cb = NULL; +} + +void mock_bt_csip_cleanup(void) +{ +} diff --git a/tests/bluetooth/audio/mocks/CMakeLists.txt b/tests/bluetooth/audio/mocks/CMakeLists.txt index 270a9b75f19..5b86b22eebb 100644 --- a/tests/bluetooth/audio/mocks/CMakeLists.txt +++ b/tests/bluetooth/audio/mocks/CMakeLists.txt @@ -10,6 +10,7 @@ add_library(mocks STATIC src/bap_stream.c src/bap_unicast_client.c src/bap_unicast_server.c + src/cap_commander.c src/conn.c src/crypto.c src/fatal.c diff --git a/tests/bluetooth/audio/mocks/include/cap_commander.h b/tests/bluetooth/audio/mocks/include/cap_commander.h new file mode 100644 index 00000000000..0fd47ea8d51 --- /dev/null +++ b/tests/bluetooth/audio/mocks/include/cap_commander.h @@ -0,0 +1,21 @@ +/* + * Copyright (c) 2023 Nordic Semiconductor ASA + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#ifndef MOCKS_CAP_COMMANDER_H_ +#define MOCKS_CAP_COMMANDER_H_ + +#include +#include + +extern struct bt_cap_commander_cb mock_cap_commander_cb; + +void mock_cap_commander_init(void); +void mock_cap_commander_cleanup(void); + +DECLARE_FAKE_VOID_FUNC(mock_cap_commander_discovery_complete_cb, struct bt_conn *, int, + const struct bt_csip_set_coordinator_csis_inst *); + +#endif /* MOCKS_CAP_COMMANDER_H_ */ diff --git a/tests/bluetooth/audio/mocks/src/cap_commander.c b/tests/bluetooth/audio/mocks/src/cap_commander.c new file mode 100644 index 00000000000..c55b72e1a5d --- /dev/null +++ b/tests/bluetooth/audio/mocks/src/cap_commander.c @@ -0,0 +1,28 @@ +/* + * Copyright (c) 2023 Nordic Semiconductor ASA + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include + +#include "cap_commander.h" + +/* List of fakes used by this unit tester */ +#define FFF_FAKES_LIST(FAKE) FAKE(mock_cap_commander_discovery_complete_cb) + +struct bt_cap_commander_cb mock_cap_commander_cb; + +DEFINE_FAKE_VOID_FUNC(mock_cap_commander_discovery_complete_cb, struct bt_conn *, int, + const struct bt_csip_set_coordinator_csis_inst *); + +void mock_cap_commander_init(void) +{ + FFF_FAKES_LIST(RESET_FAKE); + + mock_cap_commander_cb.discovery_complete = mock_cap_commander_discovery_complete_cb; +} + +void mock_cap_commander_cleanup(void) +{ +} diff --git a/tests/bluetooth/audio/mocks/src/gatt.c b/tests/bluetooth/audio/mocks/src/gatt.c index 29ab2ee2b0d..3a9db441cb5 100644 --- a/tests/bluetooth/audio/mocks/src/gatt.c +++ b/tests/bluetooth/audio/mocks/src/gatt.c @@ -7,9 +7,12 @@ #include #include #include +#include +#include #include #include "gatt.h" +#include "conn.h" #define LOG_LEVEL CONFIG_BT_GATT_LOG_LEVEL #include @@ -283,6 +286,63 @@ ssize_t bt_gatt_attr_read(struct bt_conn *conn, const struct bt_gatt_attr *attr, return len; } +int bt_gatt_discover(struct bt_conn *conn, struct bt_gatt_discover_params *params) +{ + zassert_not_null(conn, "'%s()' was called with incorrect '%s' value", __func__, "conn"); + zassert_not_null(params, "'%s()' was called with incorrect '%s' value", __func__, "params"); + zassert_not_null(params->func, "'%s()' was called with incorrect '%s' value", __func__, + "params->func"); + zassert_between_inclusive( + params->start_handle, BT_ATT_FIRST_ATTRIBUTE_HANDLE, BT_ATT_LAST_ATTRIBUTE_HANDLE, + "'%s()' was called with incorrect '%s' value", __func__, "params->start_handle"); + zassert_between_inclusive( + params->end_handle, BT_ATT_FIRST_ATTRIBUTE_HANDLE, BT_ATT_LAST_ATTRIBUTE_HANDLE, + "'%s()' was called with incorrect '%s' value", __func__, "params->end_handle"); + zassert_true(params->start_handle <= params->end_handle, + "'%s()' was called with incorrect '%s' value", __func__, "params->end_handle"); + + struct bt_gatt_service_val value; + struct bt_uuid_16 uuid; + struct bt_gatt_attr attr; + uint16_t start_handle; + uint16_t end_handle; + + if (conn->info.state != BT_CONN_STATE_CONNECTED) { + return -ENOTCONN; + } + + switch (params->type) { + case BT_GATT_DISCOVER_PRIMARY: + case BT_GATT_DISCOVER_SECONDARY: + case BT_GATT_DISCOVER_STD_CHAR_DESC: + case BT_GATT_DISCOVER_INCLUDE: + case BT_GATT_DISCOVER_CHARACTERISTIC: + case BT_GATT_DISCOVER_DESCRIPTOR: + case BT_GATT_DISCOVER_ATTRIBUTE: + break; + default: + LOG_ERR("Invalid discovery type: %u", params->type); + return -EINVAL; + } + + uuid.uuid.type = BT_UUID_TYPE_16; + uuid.val = params->type; + start_handle = params->start_handle; + end_handle = params->end_handle; + value.end_handle = end_handle; + value.uuid = params->uuid; + + attr = (struct bt_gatt_attr){ + .uuid = &uuid.uuid, + .user_data = &value, + .handle = start_handle, + }; + + params->func(conn, &attr, params); + + return 0; +} + uint16_t bt_gatt_get_mtu(struct bt_conn *conn) { return 64; diff --git a/tests/bluetooth/shell/testcase.yaml b/tests/bluetooth/shell/testcase.yaml index 0ea96cc1b05..a20abfbdda8 100644 --- a/tests/bluetooth/shell/testcase.yaml +++ b/tests/bluetooth/shell/testcase.yaml @@ -309,3 +309,9 @@ tests: platform_allow: native_posix extra_configs: - CONFIG_BT_GMAP=n + bluetooth.audio_shell.no_cap_commander: + extra_args: CONF_FILE="audio.conf" + build_only: true + platform_allow: native_posix + extra_configs: + - CONFIG_BT_CAP_COMMANDER=n diff --git a/tests/bsim/bluetooth/audio/prj.conf b/tests/bsim/bluetooth/audio/prj.conf index 9a822ede63a..06114766881 100644 --- a/tests/bsim/bluetooth/audio/prj.conf +++ b/tests/bsim/bluetooth/audio/prj.conf @@ -124,6 +124,7 @@ CONFIG_BT_HAS_FEATURES_NOTIFIABLE=y # Common Audio Profile CONFIG_BT_CAP_ACCEPTOR=y CONFIG_BT_CAP_ACCEPTOR_SET_MEMBER=y +CONFIG_BT_CAP_COMMANDER=y CONFIG_BT_CAP_INITIATOR=y # Telephony and Media Audio Profile diff --git a/tests/bsim/bluetooth/audio/src/cap_acceptor_test.c b/tests/bsim/bluetooth/audio/src/cap_acceptor_test.c index 92ba6677c76..56bb02cb6d2 100644 --- a/tests/bsim/bluetooth/audio/src/cap_acceptor_test.c +++ b/tests/bsim/bluetooth/audio/src/cap_acceptor_test.c @@ -758,6 +758,15 @@ static void test_cap_acceptor_broadcast(void) PASS("CAP acceptor broadcast passed\n"); } +static void test_cap_acceptor_capture_and_render(void) +{ + init(); + + WAIT_FOR_FLAG(flag_connected); + + PASS("CAP acceptor unicast passed\n"); +} + static const struct bst_test_instance test_cap_acceptor[] = { { .test_id = "cap_acceptor_unicast", @@ -777,6 +786,12 @@ static const struct bst_test_instance test_cap_acceptor[] = { .test_tick_f = test_tick, .test_main_f = test_cap_acceptor_broadcast, }, + { + .test_id = "cap_acceptor_capture_and_render", + .test_post_init_f = test_init, + .test_tick_f = test_tick, + .test_main_f = test_cap_acceptor_capture_and_render, + }, BSTEST_END_MARKER, }; diff --git a/tests/bsim/bluetooth/audio/src/cap_commander_test.c b/tests/bsim/bluetooth/audio/src/cap_commander_test.c new file mode 100644 index 00000000000..794ffe5d7dd --- /dev/null +++ b/tests/bsim/bluetooth/audio/src/cap_commander_test.c @@ -0,0 +1,216 @@ +/* + * Copyright (c) 2023 Nordic Semiconductor ASA + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#if defined(CONFIG_BT_CAP_COMMANDER) + +#include +#include +#include +#include +#include +#include +#include "common.h" +#include "bap_common.h" + +extern enum bst_result_t bst_result; + +static struct bt_conn *connected_conns[CONFIG_BT_MAX_CONN]; +static volatile size_t connected_conn_cnt; + +CREATE_FLAG(flag_discovered); +CREATE_FLAG(flag_mtu_exchanged); + +static void cap_discovery_complete_cb(struct bt_conn *conn, int err, + const struct bt_csip_set_coordinator_csis_inst *csis_inst) +{ + if (err != 0) { + FAIL("Failed to discover CAS: %d", err); + + return; + } + + if (IS_ENABLED(CONFIG_BT_CAP_ACCEPTOR_SET_MEMBER)) { + if (csis_inst == NULL) { + FAIL("Failed to discover CAS CSIS"); + + return; + } + + printk("Found CAS with CSIS %p\n", csis_inst); + } else { + printk("Found CAS\n"); + } + + SET_FLAG(flag_discovered); +} + +static struct bt_cap_commander_cb cap_cb = { + .discovery_complete = cap_discovery_complete_cb, +}; + +static void att_mtu_updated(struct bt_conn *conn, uint16_t tx, uint16_t rx) +{ + printk("MTU exchanged\n"); + SET_FLAG(flag_mtu_exchanged); +} + +static struct bt_gatt_cb gatt_callbacks = { + .att_mtu_updated = att_mtu_updated, +}; + +static void init(void) +{ + int err; + + err = bt_enable(NULL); + if (err != 0) { + FAIL("Bluetooth enable failed (err %d)\n", err); + return; + } + + bt_gatt_cb_register(&gatt_callbacks); + + err = bt_cap_commander_register_cb(&cap_cb); + if (err != 0) { + FAIL("Failed to register CAP callbacks (err %d)\n", err); + return; + } +} + +static void cap_device_found(const bt_addr_le_t *addr, int8_t rssi, uint8_t type, + struct net_buf_simple *ad) +{ + char addr_str[BT_ADDR_LE_STR_LEN]; + struct bt_conn *conn; + int err; + + /* We're only interested in connectable events */ + if (type != BT_HCI_ADV_IND && type != BT_HCI_ADV_DIRECT_IND) { + return; + } + + conn = bt_conn_lookup_addr_le(BT_ID_DEFAULT, addr); + if (conn != NULL) { + /* Already connected to this device */ + bt_conn_unref(conn); + return; + } + + bt_addr_le_to_str(addr, addr_str, sizeof(addr_str)); + printk("Device found: %s (RSSI %d)\n", addr_str, rssi); + + /* connect only to devices in close proximity */ + if (rssi < -70) { + FAIL("RSSI too low"); + return; + } + + printk("Stopping scan\n"); + if (bt_le_scan_stop()) { + FAIL("Could not stop scan"); + return; + } + + err = bt_conn_le_create( + addr, BT_CONN_LE_CREATE_CONN, + BT_LE_CONN_PARAM(BT_GAP_INIT_CONN_INT_MIN, BT_GAP_INIT_CONN_INT_MIN, 0, 400), + &connected_conns[connected_conn_cnt]); + if (err) { + FAIL("Could not connect to peer: %d", err); + } +} + +static void scan_and_connect(void) +{ + int err; + + UNSET_FLAG(flag_connected); + + err = bt_le_scan_start(BT_LE_SCAN_PASSIVE, cap_device_found); + if (err != 0) { + FAIL("Scanning failed to start (err %d)\n", err); + return; + } + + printk("Scanning successfully started\n"); + WAIT_FOR_FLAG(flag_connected); + connected_conn_cnt++; +} + +static void disconnect_acl(struct bt_conn *conn) +{ + int err; + + err = bt_conn_disconnect(conn, BT_HCI_ERR_REMOTE_USER_TERM_CONN); + if (err != 0) { + FAIL("Failed to disconnect (err %d)\n", err); + return; + } +} + +static void discover_cas(struct bt_conn *conn) +{ + int err; + + UNSET_FLAG(flag_discovered); + + err = bt_cap_commander_discover(conn); + if (err != 0) { + printk("Failed to discover CAS: %d\n", err); + return; + } + + WAIT_FOR_FLAG(flag_discovered); +} + +static void test_main_cap_commander_capture_and_render(void) +{ + init(); + + /* Connect to and do discovery on all CAP acceptors */ + for (size_t i = 0U; i < get_dev_cnt() - 1; i++) { + scan_and_connect(); + + WAIT_FOR_FLAG(flag_mtu_exchanged); + + /* TODO: We should use CSIP to find set members */ + discover_cas(default_conn); + } + + /* TODO: Do CAP Commander stuff */ + + /* Disconnect all CAP acceptors */ + for (size_t i = 0U; i < connected_conn_cnt; i++) { + disconnect_acl(connected_conns[i]); + } + connected_conn_cnt = 0U; + + PASS("CAP commander capture and rendering passed\n"); +} + +static const struct bst_test_instance test_cap_commander[] = { + { + .test_id = "cap_commander_capture_and_render", + .test_post_init_f = test_init, + .test_tick_f = test_tick, + .test_main_f = test_main_cap_commander_capture_and_render, + }, + BSTEST_END_MARKER, +}; + +struct bst_test_list *test_cap_commander_install(struct bst_test_list *tests) +{ + return bst_add_tests(tests, test_cap_commander); +} + +#else /* !CONFIG_BT_CAP_COMMANDER */ + +struct bst_test_list *test_cap_commander_install(struct bst_test_list *tests) +{ + return tests; +} + +#endif /* CONFIG_BT_CAP_COMMANDER */ diff --git a/tests/bsim/bluetooth/audio/src/common.c b/tests/bsim/bluetooth/audio/src/common.c index 1c74b2ae20a..b22d269bcdb 100644 --- a/tests/bsim/bluetooth/audio/src/common.c +++ b/tests/bsim/bluetooth/audio/src/common.c @@ -167,6 +167,11 @@ static void register_more_cmd_args(void) } NATIVE_TASK(register_more_cmd_args, PRE_BOOT_1, 100); +uint16_t get_dev_cnt(void) +{ + return (uint16_t)dev_cnt; +} + /** * @brief Get the channel id based on remote device ID * diff --git a/tests/bsim/bluetooth/audio/src/common.h b/tests/bsim/bluetooth/audio/src/common.h index 5df925412a3..0fb3aac451d 100644 --- a/tests/bsim/bluetooth/audio/src/common.h +++ b/tests/bsim/bluetooth/audio/src/common.h @@ -98,6 +98,7 @@ extern volatile bt_security_t security_level; void disconnected(struct bt_conn *conn, uint8_t reason); void test_tick(bs_time_t HW_device_time); void test_init(void); +uint16_t get_dev_cnt(void); void backchannel_sync_send(uint dev); void backchannel_sync_send_all(void); void backchannel_sync_wait(uint dev); diff --git a/tests/bsim/bluetooth/audio/src/main.c b/tests/bsim/bluetooth/audio/src/main.c index 2213014b251..284f29ca88f 100644 --- a/tests/bsim/bluetooth/audio/src/main.c +++ b/tests/bsim/bluetooth/audio/src/main.c @@ -25,6 +25,7 @@ extern struct bst_test_list *test_scan_delegator_install(struct bst_test_list *t extern struct bst_test_list *test_bap_broadcast_assistant_install(struct bst_test_list *tests); extern struct bst_test_list *test_bass_broadcaster_install(struct bst_test_list *tests); extern struct bst_test_list *test_cap_acceptor_install(struct bst_test_list *tests); +extern struct bst_test_list *test_cap_commander_install(struct bst_test_list *tests); extern struct bst_test_list *test_cap_initiator_broadcast_install(struct bst_test_list *tests); extern struct bst_test_list *test_cap_initiator_unicast_install(struct bst_test_list *tests); extern struct bst_test_list *test_has_install(struct bst_test_list *tests); @@ -59,6 +60,7 @@ bst_test_install_t test_installers[] = { test_scan_delegator_install, test_bap_broadcast_assistant_install, test_bass_broadcaster_install, + test_cap_commander_install, test_cap_acceptor_install, test_cap_initiator_broadcast_install, test_cap_initiator_unicast_install, diff --git a/tests/bsim/bluetooth/audio/test_scripts/cap_capture_and_render.sh b/tests/bsim/bluetooth/audio/test_scripts/cap_capture_and_render.sh new file mode 100755 index 00000000000..e80df63b7ce --- /dev/null +++ b/tests/bsim/bluetooth/audio/test_scripts/cap_capture_and_render.sh @@ -0,0 +1,33 @@ +#!/usr/bin/env bash +# +# Copyright (c) 2023 Nordic Semiconductor ASA +# +# SPDX-License-Identifier: Apache-2.0 + +SIMULATION_ID="cap_capture_and_render" +VERBOSITY_LEVEL=2 +EXECUTE_TIMEOUT=20 + +source ${ZEPHYR_BASE}/tests/bsim/sh_common.source + +cd ${BSIM_OUT_PATH}/bin + +printf "\n\n======== Running CAP commander capture and rendering test =========\n\n" + +Execute ./bs_${BOARD}_tests_bsim_bluetooth_audio_prj_conf \ + -v=${VERBOSITY_LEVEL} -s=${SIMULATION_ID} -d=0 -testid=cap_commander_capture_and_render \ + -rs=46 -D=3 + +Execute ./bs_${BOARD}_tests_bsim_bluetooth_audio_prj_conf \ + -v=${VERBOSITY_LEVEL} -s=${SIMULATION_ID} -d=1 -testid=cap_acceptor_capture_and_render \ + -rs=23 -D=3 + +Execute ./bs_${BOARD}_tests_bsim_bluetooth_audio_prj_conf \ + -v=${VERBOSITY_LEVEL} -s=${SIMULATION_ID} -d=2 -testid=cap_acceptor_capture_and_render \ + -rs=69 -D=3 + +# Simulation time should be larger than the WAIT_TIME in common.h +Execute ./bs_2G4_phy_v1 -v=${VERBOSITY_LEVEL} -s=${SIMULATION_ID} \ + -D=3 -sim_length=60e6 $@ + +wait_for_background_jobs From 7688e5efb1cb3a4a92a233b6d9371f9d92fc22c0 Mon Sep 17 00:00:00 2001 From: Declan Snyder Date: Mon, 11 Dec 2023 14:49:16 -0600 Subject: [PATCH 1395/3723] dts: mdio-controller: Add MDC frequency property Add a property to the mdio controller binding to describe the MDC frequency generated by the controller. Signed-off-by: Declan Snyder --- dts/bindings/mdio/mdio-controller.yaml | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/dts/bindings/mdio/mdio-controller.yaml b/dts/bindings/mdio/mdio-controller.yaml index 9259bbf3afa..ad83e032787 100644 --- a/dts/bindings/mdio/mdio-controller.yaml +++ b/dts/bindings/mdio/mdio-controller.yaml @@ -22,3 +22,12 @@ properties: When present, the SMA suppresses the 32-bit preamble and transmits MDIO frames with only 1 preamble bit. By default, the MDIO frame always has 32 bits of preamble as defined in the IEEE 802.3 specs. + + clock-frequency: + type: int + default: 2500000 + description: | + Some MDIO controllers have the ability to configure the MDC frequency. + If present, this property may be used to specify the MDC frequency based + on what the PHYs connected to the mdio bus can support. Default of 2.5MHz + is the standard and should supported by all PHYs. From 410990825aa7f894c9cd49d98a3e095c6327927b Mon Sep 17 00:00:00 2001 From: Declan Snyder Date: Mon, 11 Dec 2023 14:50:34 -0600 Subject: [PATCH 1396/3723] drivers: mdio_nxp_enet: Support MDC freq prop If the DT node for mdio of nxp enet has a mdc freq specified, use this when configuring the module. Signed-off-by: Declan Snyder --- drivers/mdio/mdio_nxp_enet.c | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/drivers/mdio/mdio_nxp_enet.c b/drivers/mdio/mdio_nxp_enet.c index cc704f2271a..1a5c54145b4 100644 --- a/drivers/mdio/mdio_nxp_enet.c +++ b/drivers/mdio/mdio_nxp_enet.c @@ -16,14 +16,12 @@ #include #include -/* Target MDC frequency 2.5 MHz */ -#define NXP_ENET_MDIO_MDC_FREQ 2500000U - struct nxp_enet_mdio_config { ENET_Type *base; const struct pinctrl_dev_config *pincfg; const struct device *clock_dev; clock_control_subsys_t clock_subsys; + uint32_t mdc_freq; uint16_t timeout; bool disable_preamble; }; @@ -218,8 +216,8 @@ static void nxp_enet_mdio_post_module_reset_init(const struct device *dev) /* Set up MSCR register */ (void) clock_control_get_rate(config->clock_dev, config->clock_subsys, &enet_module_clock_rate); - uint32_t mii_speed = (enet_module_clock_rate + 2 * NXP_ENET_MDIO_MDC_FREQ - 1) / - (2 * NXP_ENET_MDIO_MDC_FREQ) - 1; + uint32_t mii_speed = (enet_module_clock_rate + 2 * config->mdc_freq - 1) / + (2 * config->mdc_freq) - 1; uint32_t holdtime = (10 + NSEC_PER_SEC / enet_module_clock_rate - 1) / (NSEC_PER_SEC / enet_module_clock_rate) - 1; uint32_t mscr = ENET_MSCR_MII_SPEED(mii_speed) | ENET_MSCR_HOLDTIME(holdtime) | @@ -286,6 +284,7 @@ static int nxp_enet_mdio_init(const struct device *dev) .clock_subsys = (void *) DT_CLOCKS_CELL_BY_IDX( \ DT_INST_PARENT(inst), 0, name), \ .disable_preamble = DT_INST_PROP(inst, suppress_preamble), \ + .mdc_freq = DT_INST_PROP(inst, clock_frequency), \ }; \ \ static struct nxp_enet_mdio_data nxp_enet_mdio_data_##inst; \ From 096e95898b18cce731c1bdec3077ccf368d126ac Mon Sep 17 00:00:00 2001 From: Michal Smola Date: Wed, 13 Dec 2023 11:35:19 +0100 Subject: [PATCH 1397/3723] twister: fix hardware map hardware detection NXP boards with CMSID-DAP are not detected by twister --generate-hardware-map, because serial device name 'mbed' is compared with upper case 'MBED' in a list of supported manufacturers. Fix it by making the comparison case-insensitive. Tested using mimxrt1020_evk. Fixes #63765 Signed-off-by: Michal Smola --- scripts/pylib/twister/twisterlib/hardwaremap.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/scripts/pylib/twister/twisterlib/hardwaremap.py b/scripts/pylib/twister/twisterlib/hardwaremap.py index 5e90b7c84c6..438f5cf5d4a 100644 --- a/scripts/pylib/twister/twisterlib/hardwaremap.py +++ b/scripts/pylib/twister/twisterlib/hardwaremap.py @@ -287,7 +287,7 @@ def readlink(link): serial_devices = list_ports.comports() logger.info("Scanning connected hardware...") for d in serial_devices: - if d.manufacturer in self.manufacturer: + if d.manufacturer.casefold() in [m.casefold() for m in self.manufacturer]: # TI XDS110 can have multiple serial devices for a single board # assume endpoint 0 is the serial, skip all others From 8df987935b653b1b490c6d3369b46949bf900a78 Mon Sep 17 00:00:00 2001 From: Emil Gydesen Date: Fri, 15 Dec 2023 13:31:38 +0100 Subject: [PATCH 1398/3723] Bluetooth: MPL: Add track position notifications during seeking When seeking the media player should notify clients about the track position change. Signed-off-by: Emil Gydesen --- subsys/bluetooth/audio/mpl.c | 28 +++++++++++++++++++++++ subsys/bluetooth/audio/mpl_internal.h | 2 ++ tests/bsim/bluetooth/audio/src/mcc_test.c | 20 ++++++++++++++++ 3 files changed, 50 insertions(+) diff --git a/subsys/bluetooth/audio/mpl.c b/subsys/bluetooth/audio/mpl.c index 8a8840a3b44..e97357508e8 100644 --- a/subsys/bluetooth/audio/mpl.c +++ b/subsys/bluetooth/audio/mpl.c @@ -8,7 +8,9 @@ #include +#include #include +#include #include #include @@ -26,6 +28,9 @@ LOG_MODULE_REGISTER(bt_mpl, CONFIG_BT_MPL_LOG_LEVEL); #define TRACK_STATUS_INVALID 0x00 #define TRACK_STATUS_VALID 0x01 +#define TRACK_POS_WORK_DELAY_MS 1000 +#define TRACK_POS_WORK_DELAY K_MSEC(TRACK_POS_WORK_DELAY_MS) + #define PLAYBACK_SPEED_PARAM_DEFAULT MEDIA_PROXY_PLAYBACK_SPEED_UNITY /* Temporary hardcoded setup for groups, tracks and segments */ @@ -1346,7 +1351,10 @@ static void mpl_set_state(uint8_t state) case MEDIA_PROXY_STATE_INACTIVE: case MEDIA_PROXY_STATE_PLAYING: case MEDIA_PROXY_STATE_PAUSED: + (void)k_work_cancel_delayable(&media_player.pos_work); + break; case MEDIA_PROXY_STATE_SEEKING: + (void)k_work_schedule(&media_player.pos_work, TRACK_POS_WORK_DELAY); break; default: __ASSERT(false, "Invalid state: %u", state); @@ -2286,6 +2294,24 @@ static uint8_t get_content_ctrl_id(void) return media_player.content_ctrl_id; } +static void pos_work_cb(struct k_work *work) +{ + if (media_player.state == MEDIA_PROXY_STATE_SEEKING) { + const int32_t pos_diff_cs = + TRACK_POS_WORK_DELAY_MS / 10; /* position is in centiseconds*/ + + /* When seeking, apply the seeking speed factor */ + set_relative_track_position(pos_diff_cs * media_player.seeking_speed_factor); + + if (media_player.track_pos == media_player.group->track->duration) { + /* Go to next track */ + do_next_track(&media_player); + } + + (void)k_work_schedule(&media_player.pos_work, TRACK_POS_WORK_DELAY); + } +} + int media_proxy_pl_init(void) { static bool initialized; @@ -2387,6 +2413,8 @@ int media_proxy_pl_init(void) return ret; } + k_work_init_delayable(&media_player.pos_work, pos_work_cb); + initialized = true; return 0; } diff --git a/subsys/bluetooth/audio/mpl_internal.h b/subsys/bluetooth/audio/mpl_internal.h index b66b83abed4..c8a553da216 100644 --- a/subsys/bluetooth/audio/mpl_internal.h +++ b/subsys/bluetooth/audio/mpl_internal.h @@ -89,6 +89,8 @@ struct mpl_mediaplayer { struct mpl_track *track; /* The track explicitly set as next track */ struct mpl_group *group; /* The group of the set track */ } next; + + struct k_work_delayable pos_work; }; diff --git a/tests/bsim/bluetooth/audio/src/mcc_test.c b/tests/bsim/bluetooth/audio/src/mcc_test.c index 9e8cd95806b..3be3d5beaf9 100644 --- a/tests/bsim/bluetooth/audio/src/mcc_test.c +++ b/tests/bsim/bluetooth/audio/src/mcc_test.c @@ -784,11 +784,14 @@ static void test_cp_pause(void) static void test_cp_fast_rewind(void) { + const int32_t tmp_pos = g_pos; struct mpl_cmd cmd; cmd.opcode = BT_MCS_OPC_FAST_REWIND; cmd.use_param = false; + UNSET_FLAG(track_position_read); + test_send_cmd_wait_flags(&cmd); if (g_command_result != BT_MCS_OPC_NTF_SUCCESS) { @@ -799,15 +802,25 @@ static void test_cp_fast_rewind(void) if (test_verify_media_state_wait_flags(BT_MCS_MEDIA_STATE_SEEKING)) { printk("FAST REWIND command succeeded\n"); } + + /* Wait for the track position to change during rewinding */ + WAIT_FOR_FLAG(track_position_read); + if (tmp_pos <= g_pos) { + FAIL("Position did not change during rewinding"); + return; + } } static void test_cp_fast_forward(void) { + const int32_t tmp_pos = g_pos; struct mpl_cmd cmd; cmd.opcode = BT_MCS_OPC_FAST_FORWARD; cmd.use_param = false; + UNSET_FLAG(track_position_read); + test_send_cmd_wait_flags(&cmd); if (g_command_result != BT_MCS_OPC_NTF_SUCCESS) { @@ -818,6 +831,13 @@ static void test_cp_fast_forward(void) if (test_verify_media_state_wait_flags(BT_MCS_MEDIA_STATE_SEEKING)) { printk("FAST FORWARD command succeeded\n"); } + + /* Wait for the track position to change during forwarding */ + WAIT_FOR_FLAG(track_position_read); + if (tmp_pos >= g_pos) { + FAIL("Position did not change during forwarding"); + return; + } } static void test_cp_stop(void) From d2e864f17b91116685ccd6805004ec8c7e1f9516 Mon Sep 17 00:00:00 2001 From: Lukasz Majewski Date: Fri, 8 Dec 2023 10:29:09 +0100 Subject: [PATCH 1399/3723] drivers: ethernet: lan865x: Don't wait on semaphore if no memory for pkt With the current approach, the driver prevents from TX transmission when waiting on timeout (standard 100ms) for available memory to be able to allocate memory for RX packet. It is safe to just protect the part of reading chunks. In that way pending TX transmission can be performed. Signed-off-by: Lukasz Majewski --- drivers/ethernet/eth_lan865x.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/drivers/ethernet/eth_lan865x.c b/drivers/ethernet/eth_lan865x.c index f8dd9327d44..476ac1caa56 100644 --- a/drivers/ethernet/eth_lan865x.c +++ b/drivers/ethernet/eth_lan865x.c @@ -395,14 +395,13 @@ static void lan865x_read_chunks(const struct device *dev) struct net_pkt *pkt; int ret; - k_sem_take(&ctx->tx_rx_sem, K_FOREVER); pkt = net_pkt_rx_alloc(K_MSEC(cfg->timeout)); if (!pkt) { - k_sem_give(&ctx->tx_rx_sem); LOG_ERR("OA RX: Could not allocate packet!"); return; } + k_sem_take(&ctx->tx_rx_sem, K_FOREVER); ret = oa_tc6_read_chunks(tc6, pkt); if (ret < 0) { eth_stats_update_errors_rx(ctx->iface); From 4903ec74789816cc839dd0687bd57e3789307661 Mon Sep 17 00:00:00 2001 From: Lukasz Majewski Date: Fri, 8 Dec 2023 10:36:39 +0100 Subject: [PATCH 1400/3723] drivers: ethernet: tc6: Check footer parity before updating struct oa_tc6 The parity of the received footer from data transfer (also including the NORX) shall be checked before members of struct tc6 are updated. This prevents from updating the driver's crucial metadata (i.e. struct oa_tc6) with malformed values and informs the upper layers of the driver that error has been detected. Signed-off-by: Lukasz Majewski --- drivers/ethernet/oa_tc6.c | 12 +++++++++--- 1 file changed, 9 insertions(+), 3 deletions(-) diff --git a/drivers/ethernet/oa_tc6.c b/drivers/ethernet/oa_tc6.c index 942de4bfb1e..2b1e017f007 100644 --- a/drivers/ethernet/oa_tc6.c +++ b/drivers/ethernet/oa_tc6.c @@ -254,12 +254,19 @@ int oa_tc6_check_status(struct oa_tc6 *tc6) return 0; } -static void oa_tc6_update_status(struct oa_tc6 *tc6, uint32_t ftr) +static int oa_tc6_update_status(struct oa_tc6 *tc6, uint32_t ftr) { + if (oa_tc6_get_parity(ftr)) { + LOG_DBG("OA Status Update: Footer parity error!"); + return -EIO; + } + tc6->exst = FIELD_GET(OA_DATA_FTR_EXST, ftr); tc6->sync = FIELD_GET(OA_DATA_FTR_SYNC, ftr); tc6->rca = FIELD_GET(OA_DATA_FTR_RCA, ftr); tc6->txc = FIELD_GET(OA_DATA_FTR_TXC, ftr); + + return 0; } int oa_tc6_chunk_spi_transfer(struct oa_tc6 *tc6, uint8_t *buf_rx, uint8_t *buf_tx, @@ -295,9 +302,8 @@ int oa_tc6_chunk_spi_transfer(struct oa_tc6 *tc6, uint8_t *buf_rx, uint8_t *buf_ return ret; } *ftr = sys_be32_to_cpu(*ftr); - oa_tc6_update_status(tc6, *ftr); - return 0; + return oa_tc6_update_status(tc6, *ftr); } int oa_tc6_read_status(struct oa_tc6 *tc6, uint32_t *ftr) From f426ad16e17d8fa4153b384d20598d0061d90a4c Mon Sep 17 00:00:00 2001 From: Lukasz Majewski Date: Fri, 8 Dec 2023 10:41:28 +0100 Subject: [PATCH 1401/3723] drivers: ethernet: Update ETH_LAN865X_TIMEOUT Kconfig description The description is a bit misleading as the packet is not even read in the mentioned case by the OA TC6 Zephyr driver. When the timeout occurs the data (packet) received by LAN865x may be: - Read latter if still in the RX buffer of LAN865x or - Is (probably) dropped by LAN8651 itself as the RX buffer gets overrun Signed-off-by: Lukasz Majewski --- drivers/ethernet/Kconfig.lan865x | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/ethernet/Kconfig.lan865x b/drivers/ethernet/Kconfig.lan865x index d96e5ea68e1..42138aa1ed4 100644 --- a/drivers/ethernet/Kconfig.lan865x +++ b/drivers/ethernet/Kconfig.lan865x @@ -46,6 +46,6 @@ config ETH_LAN865X_TIMEOUT help Given timeout in milliseconds. Maximum amount of time that the driver will wait from the IP stack to get - a memory buffer before the Ethernet frame is dropped. + a memory buffer. endif # ETH_LAN865X From eccc64fc49c43e29c89ff1c6b36baa168c359770 Mon Sep 17 00:00:00 2001 From: Lukasz Majewski Date: Tue, 12 Dec 2023 11:17:30 +0100 Subject: [PATCH 1402/3723] drivers: ethernet: lan865x: Trigger IRQ routine when rca>0 read from TX ftr MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This code fixes following issue: The TX data chunk (with NORX set) is send to chip (via SPI) and at the same time a frame is received (by the LAN8651 chip), there will be no IRQ (the CS is still asserted), just the footer will indicate this with the rca > 0. Afterwards, new frames are received by LAN865x, but as the previous footer already is larger than zero there is no IRQ generated. To be more specific (from [1], chapter 7.7): ----->8------- RCA – Receive Chunks Available Asserted: The MAC-PHY detects CSn deasserted and the previous data footer had no receive data chunks available (RCA = 0). The IRQn pin will be asserted when receive data chunks become available for reading while CSn is deasserted. Deasserted: On reception of the first data header following CSn being asserted ------8<------ Doc: [1] - "OPEN Alliance 10BASE-T1x MAC-PHY Serial Interface" OPEN_Alliance_10BASET1x_MAC-PHY_Serial_Interface_V1.1.pdf Signed-off-by: Lukasz Majewski --- drivers/ethernet/eth_lan865x.c | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/drivers/ethernet/eth_lan865x.c b/drivers/ethernet/eth_lan865x.c index 476ac1caa56..5a588914b30 100644 --- a/drivers/ethernet/eth_lan865x.c +++ b/drivers/ethernet/eth_lan865x.c @@ -547,6 +547,12 @@ static int lan865x_port_send(const struct device *dev, struct net_pkt *pkt) k_sem_take(&ctx->tx_rx_sem, K_FOREVER); ret = oa_tc6_send_chunks(tc6, pkt); + + /* Check if rca > 0 during half-duplex TX transmission */ + if (tc6->rca > 0) { + k_sem_give(&ctx->int_sem); + } + k_sem_give(&ctx->tx_rx_sem); if (ret < 0) { LOG_ERR("TX transmission error, %d", ret); From 276ae6c5732aafe3306e5bde872257cf2e787f14 Mon Sep 17 00:00:00 2001 From: Pieter De Gendt Date: Mon, 18 Dec 2023 11:59:37 +0100 Subject: [PATCH 1403/3723] mcumgr: transport: smp_udp: Start socket on interface UP The implementation waited for a NET_EVENT_L4_CONNECTED event to be emitted. However we can start the receiving thread in case the interface is up. This allows for IPv6 Link Local addresses to be used with mcumgr. Signed-off-by: Pieter De Gendt --- subsys/mgmt/mcumgr/transport/src/smp_udp.c | 34 +++++++++++++--------- 1 file changed, 20 insertions(+), 14 deletions(-) diff --git a/subsys/mgmt/mcumgr/transport/src/smp_udp.c b/subsys/mgmt/mcumgr/transport/src/smp_udp.c index f103ba91249..c66bae5c9b1 100644 --- a/subsys/mgmt/mcumgr/transport/src/smp_udp.c +++ b/subsys/mgmt/mcumgr/transport/src/smp_udp.c @@ -266,27 +266,34 @@ static void smp_udp_receive_thread(void *p1, void *p2, void *p3) } } -static void smp_udp_net_event_handler(struct net_mgmt_event_callback *cb, uint32_t mgmt_event, - struct net_if *iface) +static void smp_udp_open_iface(struct net_if *iface, void *user_data) { - ARG_UNUSED(cb); - ARG_UNUSED(iface); + ARG_UNUSED(user_data); - if (mgmt_event == NET_EVENT_L4_CONNECTED) { - LOG_INF("Network connected"); + if (net_if_is_up(iface)) { #ifdef CONFIG_MCUMGR_TRANSPORT_UDP_IPV4 - if (IS_THREAD_RUNNING(smp_udp_configs.ipv4.thread)) { + if (net_if_flag_is_set(iface, NET_IF_IPV4) && + IS_THREAD_RUNNING(smp_udp_configs.ipv4.thread)) { k_sem_give(&smp_udp_configs.ipv4.network_ready_sem); } #endif #ifdef CONFIG_MCUMGR_TRANSPORT_UDP_IPV6 - if (IS_THREAD_RUNNING(smp_udp_configs.ipv6.thread)) { + if (net_if_flag_is_set(iface, NET_IF_IPV6) && + IS_THREAD_RUNNING(smp_udp_configs.ipv6.thread)) { k_sem_give(&smp_udp_configs.ipv6.network_ready_sem); } #endif - } else if (mgmt_event == NET_EVENT_L4_DISCONNECTED) { - LOG_INF("Network disconnected"); + } +} + +static void smp_udp_net_event_handler(struct net_mgmt_event_callback *cb, uint32_t mgmt_event, + struct net_if *iface) +{ + ARG_UNUSED(cb); + + if (mgmt_event == NET_EVENT_IF_UP) { + smp_udp_open_iface(iface, NULL); } } @@ -326,8 +333,8 @@ int smp_udp_open(void) #endif if (started) { - /* One or more threads were started, send interface notifications */ - conn_mgr_mon_resend_status(); + /* One or more threads were started, check existing interfaces */ + net_if_foreach(smp_udp_open_iface, NULL); } return 0; @@ -413,8 +420,7 @@ static void smp_udp_start(void) } #endif - net_mgmt_init_event_callback(&smp_udp_mgmt_cb, smp_udp_net_event_handler, - (NET_EVENT_L4_CONNECTED | NET_EVENT_L4_DISCONNECTED)); + net_mgmt_init_event_callback(&smp_udp_mgmt_cb, smp_udp_net_event_handler, NET_EVENT_IF_UP); net_mgmt_add_event_callback(&smp_udp_mgmt_cb); #ifdef CONFIG_MCUMGR_TRANSPORT_UDP_AUTOMATIC_INIT From abcfd0cbd876246c3094d9418fa48f62c9db6902 Mon Sep 17 00:00:00 2001 From: Andrej Butok Date: Mon, 18 Dec 2023 15:42:02 +0100 Subject: [PATCH 1404/3723] soc: lpc55xxx: Fix TFM TFM is using flash, so sys. clock must be decreased. Fixes #65957 Signed-off-by: Andrej Butok --- soc/arm/nxp_lpc/lpc55xxx/Kconfig.soc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/soc/arm/nxp_lpc/lpc55xxx/Kconfig.soc b/soc/arm/nxp_lpc/lpc55xxx/Kconfig.soc index a80374f2d81..c8c3cae3c49 100644 --- a/soc/arm/nxp_lpc/lpc55xxx/Kconfig.soc +++ b/soc/arm/nxp_lpc/lpc55xxx/Kconfig.soc @@ -124,7 +124,7 @@ config INIT_PLL0 config INIT_PLL1 bool "Initialize PLL1" default "y" - depends on !(SOC_LPC55S06 || FLASH) + depends on !(SOC_LPC55S06 || FLASH || BUILD_WITH_TFM) help In the LPC55XXX Family, this is currently being used to set the core clock value at it's highest frequency which clocks at 150MHz. From fcc572e0409acb21973ae3154c90fa73e02c5248 Mon Sep 17 00:00:00 2001 From: Anisetti Avinash Krishna Date: Mon, 18 Dec 2023 20:51:23 +0530 Subject: [PATCH 1405/3723] drivers: dma: intel_lpss: Fix channel count condition Fixes channel count comparison by using connect const. Signed-off-by: Anisetti Avinash Krishna --- drivers/dma/dma_intel_lpss.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/dma/dma_intel_lpss.c b/drivers/dma/dma_intel_lpss.c index 7d0fec20045..346b78ff334 100644 --- a/drivers/dma/dma_intel_lpss.c +++ b/drivers/dma/dma_intel_lpss.c @@ -76,7 +76,7 @@ int dma_intel_lpss_reload(const struct device *dev, uint32_t channel, struct dw_dma_chan_data *chan_data; uint32_t ctrl_hi = 0; - if (channel >= DW_MAX_CHAN) { + if (channel >= DW_CHAN_COUNT) { return -EINVAL; } From eb2cd314075bb3b28581c72bb777eee7ec5fd4bc Mon Sep 17 00:00:00 2001 From: Anisetti Avinash Krishna Date: Mon, 18 Dec 2023 21:45:34 +0530 Subject: [PATCH 1406/3723] drivers: sdhc: intel_emmc_host: Fix return value Fixes uninitialized variable return by returning zero at the end of function. Signed-off-by: Anisetti Avinash Krishna --- drivers/sdhc/intel_emmc_host.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/sdhc/intel_emmc_host.c b/drivers/sdhc/intel_emmc_host.c index ec5c7934be1..6286965f156 100644 --- a/drivers/sdhc/intel_emmc_host.c +++ b/drivers/sdhc/intel_emmc_host.c @@ -1087,7 +1087,7 @@ static int emmc_set_io(const struct device *dev, struct sdhc_io *ios) host_io->timing = ios->timing; } - return ret; + return 0; } static int emmc_get_card_present(const struct device *dev) From 4c3eda827a40ac5455ae55a3c71635767b60c453 Mon Sep 17 00:00:00 2001 From: Andrei Emeltchenko Date: Thu, 7 Dec 2023 11:50:42 +0200 Subject: [PATCH 1407/3723] acpi: Add acpi_dmar_foreach helpers Add function walking though all DMAR subtables, at the moment only first subtable is taking into account, which causes bugs for some boards. Signed-off-by: Andrei Emeltchenko --- include/zephyr/acpi/acpi.h | 8 ++++++++ lib/acpi/acpi.c | 31 +++++++++++++++++++++++++++++++ 2 files changed, 39 insertions(+) diff --git a/include/zephyr/acpi/acpi.h b/include/zephyr/acpi/acpi.h index 589cd7d6c4d..4d8829fba67 100644 --- a/include/zephyr/acpi/acpi.h +++ b/include/zephyr/acpi/acpi.h @@ -173,6 +173,14 @@ int acpi_dmar_entry_get(enum AcpiDmarType type, ACPI_SUBTABLE_HEADER **tables); int acpi_drhd_get(enum AcpiDmarScopeType scope, ACPI_DMAR_DEVICE_SCOPE *dev_scope, union acpi_dmar_id *dmar_id, int *num_inst, int max_inst); +typedef void (*dmar_foreach_subtable_func_t)(ACPI_DMAR_HEADER *subtable, void *arg); +typedef void (*dmar_foreach_devscope_func_t)(ACPI_DMAR_DEVICE_SCOPE *devscope, void *arg); + +void acpi_dmar_foreach_subtable(ACPI_TABLE_DMAR *dmar, dmar_foreach_subtable_func_t func, + void *arg); +void acpi_dmar_foreach_devscope(ACPI_DMAR_HARDWARE_UNIT *hu, + dmar_foreach_devscope_func_t func, void *arg); + /** * @brief Retrieve the 'n'th enabled local apic info. * diff --git a/lib/acpi/acpi.c b/lib/acpi/acpi.c index 7d84b4e5d29..b54adf15259 100644 --- a/lib/acpi/acpi.c +++ b/lib/acpi/acpi.c @@ -651,6 +651,37 @@ int acpi_dmar_entry_get(enum AcpiDmarType type, ACPI_SUBTABLE_HEADER **tables) return -ENODEV; } +void acpi_dmar_foreach_subtable(ACPI_TABLE_DMAR *dmar, + dmar_foreach_subtable_func_t func, void *arg) +{ + uint16_t length = dmar->Header.Length; + uintptr_t offset = sizeof(ACPI_TABLE_DMAR); + + while (offset < length) { + ACPI_DMAR_HEADER *subtable = ACPI_ADD_PTR(ACPI_DMAR_HEADER, dmar, offset); + + func(subtable, arg); + + offset += subtable->Length; + } +} + +void acpi_dmar_foreach_devscope(ACPI_DMAR_HARDWARE_UNIT *hu, + dmar_foreach_devscope_func_t func, void *arg) +{ + uint16_t length = hu->Header.Length; + uintptr_t offset = sizeof(ACPI_DMAR_HARDWARE_UNIT); + + while (offset < length) { + ACPI_DMAR_DEVICE_SCOPE *devscope = ACPI_ADD_PTR(ACPI_DMAR_DEVICE_SCOPE, + hu, offset); + + func(devscope, arg); + + offset += devscope->Length; + } +} + int acpi_drhd_get(enum AcpiDmarScopeType scope, ACPI_DMAR_DEVICE_SCOPE *dev_scope, union acpi_dmar_id *dmar_id, int *num_inst, int max_inst) { From 8924feb960181e1c4687601cdbf748087cb9d3db Mon Sep 17 00:00:00 2001 From: Andrei Emeltchenko Date: Thu, 7 Dec 2023 13:51:44 +0200 Subject: [PATCH 1408/3723] tests: Refactor ACPI info sample Take into account multiple DMAR HARDWARE_UNIT tables. Signed-off-by: Andrei Emeltchenko --- tests/arch/x86/info/src/acpi.c | 65 ++++++++++++++++------------------ 1 file changed, 31 insertions(+), 34 deletions(-) diff --git a/tests/arch/x86/info/src/acpi.c b/tests/arch/x86/info/src/acpi.c index a9f6eb4638b..56adc9b87e8 100644 --- a/tests/arch/x86/info/src/acpi.c +++ b/tests/arch/x86/info/src/acpi.c @@ -6,10 +6,6 @@ #include #include -static const uint32_t dmar_scope[] = {ACPI_DMAR_SCOPE_TYPE_ENDPOINT, ACPI_DMAR_SCOPE_TYPE_BRIDGE, - ACPI_DMAR_SCOPE_TYPE_IOAPIC, ACPI_DMAR_SCOPE_TYPE_HPET, - ACPI_DMAR_SCOPE_TYPE_NAMESPACE}; - static const char *get_dmar_scope_type(int type) { switch (type) { @@ -28,25 +24,34 @@ static const char *get_dmar_scope_type(int type) } } -static void vtd_dev_scope_info(struct acpi_dmar_device_scope *dev_scope, - union acpi_dmar_id *dmar_id, int num_inst) +static void dmar_devsope_handler(ACPI_DMAR_DEVICE_SCOPE *devscope, void *arg) { - int i = 0; + ARG_UNUSED(arg); + + printk("\t\t\t. Scope type %s\n", get_dmar_scope_type(devscope->EntryType)); + printk("\t\t\t. Enumeration ID %u\n", devscope->EnumerationId); - printk("\t\t\t. Enumeration ID %u\n", dev_scope->EnumerationId); + if (devscope->EntryType < ACPI_DMAR_SCOPE_TYPE_RESERVED) { + ACPI_DMAR_PCI_PATH *devpath; + int num_path = (devscope->Length - 6u) / 2u; + int i = 0; - for (; num_inst > 0; num_inst--, i++) { - printk("\t\t\t. BDF 0x%x:0x%x:0x%x\n", - dmar_id[i].bits.bus, dmar_id[i].bits.device, - dmar_id[i].bits.function); + devpath = ACPI_ADD_PTR(ACPI_DMAR_PCI_PATH, devscope, + sizeof(ACPI_DMAR_DEVICE_SCOPE)); + + while (num_path--) { + printk("\t\t\t. PCI Path %02x:%02x.%02x\n", devscope->Bus, + devpath[i].Device, devpath[i].Function); + } } } -static void vtd_drhd_info(struct acpi_dmar_hardware_unit *drhd) +static void vtd_drhd_info(ACPI_DMAR_HEADER *subtable) { - struct acpi_dmar_device_scope dev_scope; - union acpi_dmar_id dmar_id[4]; - int num_inst, i; + struct acpi_dmar_hardware_unit *drhd = (void *)subtable; + static int unit; + + printk("\t\t[ Hardware Unit Definition %d ]\n", unit++); if (drhd->Flags & ACPI_DRHD_FLAG_INCLUDE_PCI_ALL) { printk("\t\t- Includes all PCI devices"); @@ -60,25 +65,24 @@ static void vtd_drhd_info(struct acpi_dmar_hardware_unit *drhd) printk("\t\t- Base Address 0x%llx\n", drhd->Address); printk("\t\t- Device Scopes:\n"); - for (i = 0; i < ARRAY_SIZE(dmar_scope); i++) { - if (acpi_drhd_get(dmar_scope[i], &dev_scope, dmar_id, &num_inst, 4u)) { - printk("\t\tNo DRHD type: %s\n", - get_dmar_scope_type(dmar_scope[i])); - continue; - } - printk("\t\tDRHD type %s\n", get_dmar_scope_type(dmar_scope[i])); + acpi_dmar_foreach_devscope(drhd, dmar_devsope_handler, NULL); +} + +static void dmar_subtable_handler(ACPI_DMAR_HEADER *subtable, void *arg) +{ + ARG_UNUSED(arg); - vtd_dev_scope_info(&dev_scope, dmar_id, num_inst); + if (subtable->Type != ACPI_DMAR_TYPE_HARDWARE_UNIT) { + return; } - printk("\n"); + vtd_drhd_info(subtable); } static void vtd_info(void) { struct acpi_table_dmar *dmar; - struct acpi_dmar_hardware_unit *drhd; dmar = acpi_table_get("DMAR", 0); if (dmar == NULL) { @@ -96,15 +100,8 @@ static void vtd_info(void) } if (dmar->Flags & ACPI_DMAR_FLAG_INTR_REMAP) { - printk("\t-> Interrupt remapping supported\n"); - - if (acpi_dmar_entry_get(ACPI_DMAR_TYPE_HARDWARE_UNIT, - (struct acpi_subtable_header **)&drhd)) { - printk("\tError in retrieving DHRD!!\n"); - return; - } - vtd_drhd_info(drhd); + acpi_dmar_foreach_subtable(dmar, dmar_subtable_handler, NULL); } else { printk("\t-> Interrupt remapping not supported\n"); } From 2a49611ab014c128992d12c85f42e7f3c1e96f3d Mon Sep 17 00:00:00 2001 From: Andrei Emeltchenko Date: Thu, 7 Dec 2023 13:54:06 +0200 Subject: [PATCH 1409/3723] boards: alder_lake: Enable VTD Enable VTD for Alder Lake board. Signed-off-by: Andrei Emeltchenko --- dts/x86/intel/alder_lake.dtsi | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/dts/x86/intel/alder_lake.dtsi b/dts/x86/intel/alder_lake.dtsi index 610c9f4ba72..3bc21994ffe 100644 --- a/dts/x86/intel/alder_lake.dtsi +++ b/dts/x86/intel/alder_lake.dtsi @@ -258,6 +258,12 @@ compatible = "simple-bus"; ranges; + vtd: vtd@fed91000 { + compatible = "intel,vt-d"; + reg = <0xfed91000 0x1000>; + status = "okay"; + }; + uart0_legacy: uart@3f8 { compatible = "ns16550"; reg = <0x000003f8 0x100>; From 28ac21330da001fd9f0fe05fb50be96b02559bdb Mon Sep 17 00:00:00 2001 From: Andrei Emeltchenko Date: Tue, 12 Dec 2023 13:38:46 +0200 Subject: [PATCH 1410/3723] lib: acpi: Implement acpi_dmar_ioapic_get() Implement get IOAPIC id from DMAR table. Signed-off-by: Andrei Emeltchenko --- include/zephyr/acpi/acpi.h | 8 ++++++ lib/acpi/acpi.c | 52 ++++++++++++++++++++++++++++++++++++++ 2 files changed, 60 insertions(+) diff --git a/include/zephyr/acpi/acpi.h b/include/zephyr/acpi/acpi.h index 4d8829fba67..b74f4f10a15 100644 --- a/include/zephyr/acpi/acpi.h +++ b/include/zephyr/acpi/acpi.h @@ -181,6 +181,14 @@ void acpi_dmar_foreach_subtable(ACPI_TABLE_DMAR *dmar, dmar_foreach_subtable_fun void acpi_dmar_foreach_devscope(ACPI_DMAR_HARDWARE_UNIT *hu, dmar_foreach_devscope_func_t func, void *arg); +/** + * @brief Retrieve IOAPIC id + * + * @param ioapic_id IOAPIC id + * @return return 0 on success or error code + */ +int acpi_dmar_ioapic_get(uint16_t *ioapic_id); + /** * @brief Retrieve the 'n'th enabled local apic info. * diff --git a/lib/acpi/acpi.c b/lib/acpi/acpi.c index b54adf15259..70f792d9b5c 100644 --- a/lib/acpi/acpi.c +++ b/lib/acpi/acpi.c @@ -682,6 +682,58 @@ void acpi_dmar_foreach_devscope(ACPI_DMAR_HARDWARE_UNIT *hu, } } +static void devscope_handler(ACPI_DMAR_DEVICE_SCOPE *devscope, void *arg) +{ + ACPI_DMAR_PCI_PATH *dev_path; + union acpi_dmar_id pci_path; + + ARG_UNUSED(arg); /* may be unused */ + + if (devscope->EntryType == ACPI_DMAR_SCOPE_TYPE_IOAPIC) { + uint16_t *ioapic_id = arg; + + dev_path = ACPI_ADD_PTR(ACPI_DMAR_PCI_PATH, devscope, + sizeof(ACPI_DMAR_DEVICE_SCOPE)); + + /* Get first entry */ + pci_path.bits.bus = devscope->Bus; + pci_path.bits.device = dev_path->Device; + pci_path.bits.function = dev_path->Function; + + *ioapic_id = pci_path.raw; + } +} + +static void subtable_handler(ACPI_DMAR_HEADER *subtable, void *arg) +{ + ARG_UNUSED(arg); /* may be unused */ + + if (subtable->Type == ACPI_DMAR_TYPE_HARDWARE_UNIT) { + ACPI_DMAR_HARDWARE_UNIT *hu; + + hu = CONTAINER_OF(subtable, ACPI_DMAR_HARDWARE_UNIT, Header); + acpi_dmar_foreach_devscope(hu, devscope_handler, arg); + } +} + +int acpi_dmar_ioapic_get(uint16_t *ioapic_id) +{ + ACPI_TABLE_DMAR *dmar = acpi_table_get("DMAR", 0); + uint16_t found_ioapic = USHRT_MAX; + + if (dmar == NULL) { + return -ENODEV; + } + + acpi_dmar_foreach_subtable(dmar, subtable_handler, &found_ioapic); + if (found_ioapic != USHRT_MAX) { + *ioapic_id = found_ioapic; + return 0; + } + + return -ENOENT; +} + int acpi_drhd_get(enum AcpiDmarScopeType scope, ACPI_DMAR_DEVICE_SCOPE *dev_scope, union acpi_dmar_id *dmar_id, int *num_inst, int max_inst) { From c78bff954e57f40545dd3feda5827166bac86e22 Mon Sep 17 00:00:00 2001 From: Andrei Emeltchenko Date: Fri, 8 Dec 2023 15:15:14 +0200 Subject: [PATCH 1411/3723] drivers: intc_ioapic: Fix get ioapic_id Information about IOAPIC can be located not in the first DMAR Hardware Unit Definition subtable. Iterate them all. Signed-off-by: Andrei Emeltchenko --- drivers/interrupt_controller/intc_ioapic.c | 12 +----------- 1 file changed, 1 insertion(+), 11 deletions(-) diff --git a/drivers/interrupt_controller/intc_ioapic.c b/drivers/interrupt_controller/intc_ioapic.c index 65615f269a3..0748ddccf76 100644 --- a/drivers/interrupt_controller/intc_ioapic.c +++ b/drivers/interrupt_controller/intc_ioapic.c @@ -127,9 +127,6 @@ static uint16_t ioapic_id; static bool get_vtd(void) { - union acpi_dmar_id dmar_id; - int inst_cnt; - if (!device_is_ready(vtd)) { return false; } @@ -138,14 +135,7 @@ static bool get_vtd(void) return true; } - /* Assume only one PCH in system (say client platform). */ - if (!acpi_drhd_get(ACPI_DMAR_SCOPE_TYPE_IOAPIC, NULL, &dmar_id, &inst_cnt, 1u)) { - return false; - } - - ioapic_id = dmar_id.raw; - - return true; + return acpi_dmar_ioapic_get(&ioapic_id) == 0; } #endif /* CONFIG_INTEL_VTD_ICTL && !INTEL_VTD_ICTL_XAPIC_PASSTHROUGH */ From abbbc43be842450f772c15e4aff8466d3d86ba74 Mon Sep 17 00:00:00 2001 From: Andrei Emeltchenko Date: Fri, 15 Dec 2023 16:13:18 +0200 Subject: [PATCH 1412/3723] tests: acpi: Rename acpi to integration test Rename test to integration and allow to include unit tests for ACPI. Signed-off-by: Andrei Emeltchenko --- tests/lib/acpi/{ => integration}/CMakeLists.txt | 0 tests/lib/acpi/{ => integration}/prj.conf | 0 tests/lib/acpi/{ => integration}/src/main.c | 0 tests/lib/acpi/{ => integration}/testcase.yaml | 0 4 files changed, 0 insertions(+), 0 deletions(-) rename tests/lib/acpi/{ => integration}/CMakeLists.txt (100%) rename tests/lib/acpi/{ => integration}/prj.conf (100%) rename tests/lib/acpi/{ => integration}/src/main.c (100%) rename tests/lib/acpi/{ => integration}/testcase.yaml (100%) diff --git a/tests/lib/acpi/CMakeLists.txt b/tests/lib/acpi/integration/CMakeLists.txt similarity index 100% rename from tests/lib/acpi/CMakeLists.txt rename to tests/lib/acpi/integration/CMakeLists.txt diff --git a/tests/lib/acpi/prj.conf b/tests/lib/acpi/integration/prj.conf similarity index 100% rename from tests/lib/acpi/prj.conf rename to tests/lib/acpi/integration/prj.conf diff --git a/tests/lib/acpi/src/main.c b/tests/lib/acpi/integration/src/main.c similarity index 100% rename from tests/lib/acpi/src/main.c rename to tests/lib/acpi/integration/src/main.c diff --git a/tests/lib/acpi/testcase.yaml b/tests/lib/acpi/integration/testcase.yaml similarity index 100% rename from tests/lib/acpi/testcase.yaml rename to tests/lib/acpi/integration/testcase.yaml From 24b58ecc51957d8c9ad838a449b57ad64157de52 Mon Sep 17 00:00:00 2001 From: Andrei Emeltchenko Date: Fri, 15 Dec 2023 16:20:54 +0200 Subject: [PATCH 1413/3723] lib: acpi: Add ASSERT() for wrong length Add ASSERT() for length. Signed-off-by: Andrei Emeltchenko --- lib/acpi/acpi.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/lib/acpi/acpi.c b/lib/acpi/acpi.c index 70f792d9b5c..d9ae1819511 100644 --- a/lib/acpi/acpi.c +++ b/lib/acpi/acpi.c @@ -660,6 +660,8 @@ void acpi_dmar_foreach_subtable(ACPI_TABLE_DMAR *dmar, while (offset < length) { ACPI_DMAR_HEADER *subtable = ACPI_ADD_PTR(ACPI_DMAR_HEADER, dmar, offset); + __ASSERT_NO_MSG(subtable->Length > sizeof(*subtable)); + func(subtable, arg); offset += subtable->Length; @@ -676,6 +678,8 @@ void acpi_dmar_foreach_devscope(ACPI_DMAR_HARDWARE_UNIT *hu, ACPI_DMAR_DEVICE_SCOPE *devscope = ACPI_ADD_PTR(ACPI_DMAR_DEVICE_SCOPE, hu, offset); + __ASSERT_NO_MSG(devscope->Length > sizeof(*devscope)); + func(devscope, arg); offset += devscope->Length; From 751f871b20f0ae37aee744347c11994e352e39ac Mon Sep 17 00:00:00 2001 From: Andrei Emeltchenko Date: Fri, 15 Dec 2023 16:47:31 +0200 Subject: [PATCH 1414/3723] tests: acpi: Add unit test for ACPI table parsing Initial unit test for ACPI table parsing. Signed-off-by: Andrei Emeltchenko --- tests/lib/acpi/unit/CMakeLists.txt | 24 +++++ tests/lib/acpi/unit/prj.conf | 2 + tests/lib/acpi/unit/src/assert.c | 38 ++++++++ tests/lib/acpi/unit/src/assert.h | 19 ++++ tests/lib/acpi/unit/src/main.c | 101 +++++++++++++++++++++ tests/lib/acpi/unit/src/mock.c | 141 +++++++++++++++++++++++++++++ tests/lib/acpi/unit/src/mock.h | 19 ++++ tests/lib/acpi/unit/testcase.yaml | 4 + 8 files changed, 348 insertions(+) create mode 100644 tests/lib/acpi/unit/CMakeLists.txt create mode 100644 tests/lib/acpi/unit/prj.conf create mode 100644 tests/lib/acpi/unit/src/assert.c create mode 100644 tests/lib/acpi/unit/src/assert.h create mode 100644 tests/lib/acpi/unit/src/main.c create mode 100644 tests/lib/acpi/unit/src/mock.c create mode 100644 tests/lib/acpi/unit/src/mock.h create mode 100644 tests/lib/acpi/unit/testcase.yaml diff --git a/tests/lib/acpi/unit/CMakeLists.txt b/tests/lib/acpi/unit/CMakeLists.txt new file mode 100644 index 00000000000..c62ee890a5e --- /dev/null +++ b/tests/lib/acpi/unit/CMakeLists.txt @@ -0,0 +1,24 @@ +# SPDX-License-Identifier: Apache-2.0 + +cmake_minimum_required(VERSION 3.20.0) + +project(lib_acpi) +find_package(Zephyr COMPONENTS unittest REQUIRED HINTS $ENV{ZEPHYR_BASE}) + +# Assert library +add_library(mock_assert STATIC src/assert.c) +target_link_libraries(mock_assert PRIVATE test_interface) +target_compile_options(test_interface INTERFACE -include ztest.h) + +target_include_directories(testbinary PRIVATE + ${ZEPHYR_BASE}/../modules/lib + ${ZEPHYR_BASE}/../modules/lib/acpica/source/include + ${ZEPHYR_BASE}/../modules/lib/acpica/source/tools/acpiexec + ) + +target_sources(testbinary PRIVATE + src/main.c + src/mock.c + ) + +target_link_libraries(testbinary PRIVATE mock_assert) diff --git a/tests/lib/acpi/unit/prj.conf b/tests/lib/acpi/unit/prj.conf new file mode 100644 index 00000000000..c8046e1e12d --- /dev/null +++ b/tests/lib/acpi/unit/prj.conf @@ -0,0 +1,2 @@ +CONFIG_ZTEST=y +CONFIG_ASSERT=y diff --git a/tests/lib/acpi/unit/src/assert.c b/tests/lib/acpi/unit/src/assert.c new file mode 100644 index 00000000000..7006b195f85 --- /dev/null +++ b/tests/lib/acpi/unit/src/assert.c @@ -0,0 +1,38 @@ +/* + * Copyright (c) 2022 Nordic Semiconductor ASA + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include "assert.h" + +DEFINE_FAKE_VALUE_FUNC(bool, mock_check_if_assert_expected); + +void assert_print(const char *fmt, ...) +{ + va_list ap; + + va_start(ap, fmt); + vprintk(fmt, ap); + va_end(ap); +} + +void assert_post_action(const char *file, unsigned int line) +{ + /* ztest_test_pass()/ztest_test_fail() are used to stop the execution + * If this is an unexpected assert (i.e. not following expect_assert()) + * calling mock_check_if_assert_expected() will return 'false' as + * a default return value + */ + if (mock_check_if_assert_expected() == true) { + printk("Assertion expected as part of a test case.\n"); + /* Mark the test as passed and stop execution: + * Needed in the passing scenario to prevent undefined behavior after hitting the + * assert. In real builds (non-UT), the system will be halted by the assert. + */ + ztest_test_pass(); + } else { + /* Mark the test as failed and stop execution */ + ztest_test_fail(); + } +} diff --git a/tests/lib/acpi/unit/src/assert.h b/tests/lib/acpi/unit/src/assert.h new file mode 100644 index 00000000000..fb0f93d8980 --- /dev/null +++ b/tests/lib/acpi/unit/src/assert.h @@ -0,0 +1,19 @@ +/* + * Copyright (c) 2022 Nordic Semiconductor ASA + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include +#include +#include + +#include + +/* List of fakes used by this unit tester */ +#define ASSERT_FFF_FAKES_LIST(FAKE) \ + FAKE(mock_check_if_assert_expected) \ + +DECLARE_FAKE_VALUE_FUNC(bool, mock_check_if_assert_expected); + +#define expect_assert() (mock_check_if_assert_expected_fake.return_val = 1) diff --git a/tests/lib/acpi/unit/src/main.c b/tests/lib/acpi/unit/src/main.c new file mode 100644 index 00000000000..b3a5c7f9d37 --- /dev/null +++ b/tests/lib/acpi/unit/src/main.c @@ -0,0 +1,101 @@ +/* + * Copyright (c) 2023 Intel Corporation + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include +#include +#include + +#include "mock.h" + +#define CONFIG_ACPI_DEV_MAX 1 +#define _AcpiModuleName "" + +#include +#include +#include "assert.h" + +#include +DEFINE_FFF_GLOBALS; + +struct DMAR { + ACPI_TABLE_DMAR header; + + /* Hardware Unit 0 */ + struct { + ACPI_DMAR_HARDWARE_UNIT header; + + ACPI_DMAR_DEVICE_SCOPE unit0_ds0; + ACPI_DMAR_PCI_PATH unit0_ds0_path0; + + ACPI_DMAR_DEVICE_SCOPE unit0_ds1; + ACPI_DMAR_PCI_PATH unit0_ds1_path0; + } unit0; + + /* Hardware Unit 1 */ + struct { + ACPI_DMAR_HARDWARE_UNIT header; + + ACPI_DMAR_DEVICE_SCOPE unit1_ds0; + ACPI_DMAR_PCI_PATH unit1_ds0_path0; + + ACPI_DMAR_DEVICE_SCOPE unit1_ds1; + ACPI_DMAR_PCI_PATH unit1_ds1_path0; + } unit1; +}; + +static struct DMAR dmar0 = { + .header.Header.Length = sizeof(struct DMAR), + + .unit0.header.Header.Length = sizeof(dmar0.unit0), + .unit1.header.Header.Length = sizeof(dmar0.unit1), +}; + +static void dmar_initialize(struct DMAR *dmar) +{ + dmar->unit0.header.Header.Length = sizeof(dmar->unit0); + dmar->unit1.header.Header.Length = sizeof(dmar->unit1); +} + +static void dmar_clear(struct DMAR *dmar) +{ + dmar->unit0.header.Header.Length = 0; + dmar->unit1.header.Header.Length = 0; +} + +ZTEST(lib_acpi, test_nop) +{ +} + +static void count_subtables(ACPI_DMAR_HEADER *subtable, void *arg) +{ + uint8_t *count = arg; + + (*count)++; +} + +ZTEST(lib_acpi, test_dmar_foreach) +{ + uint8_t count = 0; + + dmar_initialize(&dmar0); + + acpi_dmar_foreach_subtable((void *)&dmar0, count_subtables, &count); + zassert_equal(count, 2); + + TC_PRINT("Counted %u hardware units\n", count); +} + +ZTEST(lib_acpi, test_dmar_foreach_invalid_unit_size) +{ + uint8_t count = 0; + + dmar_clear(&dmar0); + expect_assert(); + + acpi_dmar_foreach_subtable((void *)&dmar0, count_subtables, &count); +} + +ZTEST_SUITE(lib_acpi, NULL, NULL, NULL, NULL, NULL); diff --git a/tests/lib/acpi/unit/src/mock.c b/tests/lib/acpi/unit/src/mock.c new file mode 100644 index 00000000000..948eba85c4d --- /dev/null +++ b/tests/lib/acpi/unit/src/mock.c @@ -0,0 +1,141 @@ +/* + * Copyright (c) 2023 Intel Corporation + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include + +#include "mock.h" +#include + +#include +#include +#include +#include +#include + +void ACPI_INTERNAL_VAR_XFACE AcpiInfo(const char *Format, ...) +{ +} + +ACPI_STATUS AcpiInstallNotifyHandler(ACPI_HANDLE Device, + UINT32 HandlerType, + ACPI_NOTIFY_HANDLER Handler, + void *Context) +{ + return AE_OK; +} + +void ACPI_INTERNAL_VAR_XFACE AcpiException(const char *ModuleName, + UINT32 LineNumber, + ACPI_STATUS Status, + const char *Format, + ...) +{ +} + +ACPI_STATUS ACPI_INIT_FUNCTION AcpiInitializeSubsystem(void) +{ + return AE_OK; +} + +ACPI_STATUS ACPI_INIT_FUNCTION AcpiInitializeTables(ACPI_TABLE_DESC *InitialTableArray, + UINT32 InitialTableCount, + BOOLEAN AllowResize) +{ + return AE_OK; +} + +ACPI_STATUS ACPI_INIT_FUNCTION AcpiEnableSubsystem(UINT32 Flags) +{ + return AE_OK; +} + +ACPI_STATUS ACPI_INIT_FUNCTION AcpiInitializeObjects(UINT32 Flags) +{ + return AE_OK; +} + +ACPI_STATUS ACPI_INIT_FUNCTION AcpiLoadTables(void) +{ + return AE_OK; +} + +ACPI_STATUS AcpiNsInternalizeName(const char *ExternalName, + char **ConvertedName) +{ + return AE_OK; +} + +ACPI_STATUS AcpiNsLookup(ACPI_GENERIC_STATE *ScopeInfo, + char *Pathname, + ACPI_OBJECT_TYPE Type, + ACPI_INTERPRETER_MODE InterpreterMode, + UINT32 Flags, + ACPI_WALK_STATE *WalkState, + ACPI_NAMESPACE_NODE **ReturnNode) +{ + return AE_OK; +} + +void AcpiOsFree(void *Mem) +{ +} + +ACPI_STATUS AcpiGetHandle(ACPI_HANDLE Parent, + const char *Pathname, + ACPI_HANDLE *RetHandle) +{ + return AE_OK; +} + +ACPI_STATUS AcpiEvaluateObject(ACPI_HANDLE Handle, + ACPI_STRING Pathname, + ACPI_OBJECT_LIST *ExternalParams, + ACPI_BUFFER *ReturnBuffer) +{ + return AE_OK; +} + +ACPI_STATUS AcpiGetObjectInfo(ACPI_HANDLE Handle, + ACPI_DEVICE_INFO **ReturnBuffer) +{ + return AE_OK; +} + +char *AcpiNsGetNormalizedPathname(ACPI_NAMESPACE_NODE *Node, + BOOLEAN NoTrailing) +{ + return NULL; +} + +ACPI_STATUS AcpiGetCurrentResources(ACPI_HANDLE DeviceHandle, + ACPI_BUFFER *RetBuffer) +{ + return AE_OK; +} + +ACPI_STATUS AcpiWalkNamespace(ACPI_OBJECT_TYPE Type, + ACPI_HANDLE StartObject, + UINT32 MaxDepth, + ACPI_WALK_CALLBACK DescendingCallback, + ACPI_WALK_CALLBACK AscendingCallback, + void *Context, + void **ReturnValue) +{ + return AE_OK; +} + +ACPI_STATUS AcpiGetPossibleResources(ACPI_HANDLE DeviceHandle, + ACPI_BUFFER *RetBuffer) +{ + return AE_OK; +} + +ACPI_STATUS AcpiGetTable(char *Signature, + UINT32 Instance, + ACPI_TABLE_HEADER **OutTable) +{ + return AE_OK; +} diff --git a/tests/lib/acpi/unit/src/mock.h b/tests/lib/acpi/unit/src/mock.h new file mode 100644 index 00000000000..d8c8df4da0b --- /dev/null +++ b/tests/lib/acpi/unit/src/mock.h @@ -0,0 +1,19 @@ +/* + * Copyright (c) 2023 Intel Corporation + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include + +/* Exclude PCIE header */ +#define ZEPHYR_INCLUDE_DRIVERS_PCIE_PCIE_H_ + +/* Exclude Logging macrobatic */ +#define ZEPHYR_INCLUDE_LOGGING_LOG_H_ +#define LOG_MODULE_REGISTER(...) +#define LOG_DBG(...) +#define LOG_ERR(...) +#define LOG_WRN(...) + +typedef uint32_t pcie_bdf_t; diff --git a/tests/lib/acpi/unit/testcase.yaml b/tests/lib/acpi/unit/testcase.yaml new file mode 100644 index 00000000000..039c1711f5a --- /dev/null +++ b/tests/lib/acpi/unit/testcase.yaml @@ -0,0 +1,4 @@ +tests: + lib.acpi: + tags: acpi + type: unit From 0223fe897f9d78ad541a7a9cc6a53f0147fccf3a Mon Sep 17 00:00:00 2001 From: Andrei Emeltchenko Date: Mon, 18 Dec 2023 11:41:44 +0200 Subject: [PATCH 1415/3723] tests: lib: acpi: Convert to FFF Convert fake functions to FFF. Signed-off-by: Andrei Emeltchenko --- tests/lib/acpi/unit/src/mock.c | 174 ++++++++++----------------------- 1 file changed, 50 insertions(+), 124 deletions(-) diff --git a/tests/lib/acpi/unit/src/mock.c b/tests/lib/acpi/unit/src/mock.c index 948eba85c4d..687c5f26a21 100644 --- a/tests/lib/acpi/unit/src/mock.c +++ b/tests/lib/acpi/unit/src/mock.c @@ -15,127 +15,53 @@ #include #include -void ACPI_INTERNAL_VAR_XFACE AcpiInfo(const char *Format, ...) -{ -} - -ACPI_STATUS AcpiInstallNotifyHandler(ACPI_HANDLE Device, - UINT32 HandlerType, - ACPI_NOTIFY_HANDLER Handler, - void *Context) -{ - return AE_OK; -} - -void ACPI_INTERNAL_VAR_XFACE AcpiException(const char *ModuleName, - UINT32 LineNumber, - ACPI_STATUS Status, - const char *Format, - ...) -{ -} - -ACPI_STATUS ACPI_INIT_FUNCTION AcpiInitializeSubsystem(void) -{ - return AE_OK; -} - -ACPI_STATUS ACPI_INIT_FUNCTION AcpiInitializeTables(ACPI_TABLE_DESC *InitialTableArray, - UINT32 InitialTableCount, - BOOLEAN AllowResize) -{ - return AE_OK; -} - -ACPI_STATUS ACPI_INIT_FUNCTION AcpiEnableSubsystem(UINT32 Flags) -{ - return AE_OK; -} - -ACPI_STATUS ACPI_INIT_FUNCTION AcpiInitializeObjects(UINT32 Flags) -{ - return AE_OK; -} - -ACPI_STATUS ACPI_INIT_FUNCTION AcpiLoadTables(void) -{ - return AE_OK; -} - -ACPI_STATUS AcpiNsInternalizeName(const char *ExternalName, - char **ConvertedName) -{ - return AE_OK; -} - -ACPI_STATUS AcpiNsLookup(ACPI_GENERIC_STATE *ScopeInfo, - char *Pathname, - ACPI_OBJECT_TYPE Type, - ACPI_INTERPRETER_MODE InterpreterMode, - UINT32 Flags, - ACPI_WALK_STATE *WalkState, - ACPI_NAMESPACE_NODE **ReturnNode) -{ - return AE_OK; -} - -void AcpiOsFree(void *Mem) -{ -} - -ACPI_STATUS AcpiGetHandle(ACPI_HANDLE Parent, - const char *Pathname, - ACPI_HANDLE *RetHandle) -{ - return AE_OK; -} - -ACPI_STATUS AcpiEvaluateObject(ACPI_HANDLE Handle, - ACPI_STRING Pathname, - ACPI_OBJECT_LIST *ExternalParams, - ACPI_BUFFER *ReturnBuffer) -{ - return AE_OK; -} - -ACPI_STATUS AcpiGetObjectInfo(ACPI_HANDLE Handle, - ACPI_DEVICE_INFO **ReturnBuffer) -{ - return AE_OK; -} - -char *AcpiNsGetNormalizedPathname(ACPI_NAMESPACE_NODE *Node, - BOOLEAN NoTrailing) -{ - return NULL; -} - -ACPI_STATUS AcpiGetCurrentResources(ACPI_HANDLE DeviceHandle, - ACPI_BUFFER *RetBuffer) -{ - return AE_OK; -} - -ACPI_STATUS AcpiWalkNamespace(ACPI_OBJECT_TYPE Type, - ACPI_HANDLE StartObject, - UINT32 MaxDepth, - ACPI_WALK_CALLBACK DescendingCallback, - ACPI_WALK_CALLBACK AscendingCallback, - void *Context, - void **ReturnValue) -{ - return AE_OK; -} - -ACPI_STATUS AcpiGetPossibleResources(ACPI_HANDLE DeviceHandle, - ACPI_BUFFER *RetBuffer) -{ - return AE_OK; -} - -ACPI_STATUS AcpiGetTable(char *Signature, - UINT32 Instance, - ACPI_TABLE_HEADER **OutTable) -{ - return AE_OK; -} +#include + +FAKE_VOID_FUNC_VARARG(AcpiInfo, const char *, ...); + +FAKE_VALUE_FUNC(ACPI_STATUS, AcpiInstallNotifyHandler, ACPI_HANDLE, + UINT32, ACPI_NOTIFY_HANDLER, void *); + +FAKE_VOID_FUNC_VARARG(AcpiException, const char *, UINT32, ACPI_STATUS, + const char *, ...); + +FAKE_VALUE_FUNC(ACPI_STATUS, AcpiInitializeSubsystem); + + +FAKE_VALUE_FUNC(ACPI_STATUS, AcpiInitializeTables, ACPI_TABLE_DESC *, UINT32, + BOOLEAN); +FAKE_VALUE_FUNC(ACPI_STATUS, AcpiEnableSubsystem, UINT32); + +FAKE_VALUE_FUNC(ACPI_STATUS, AcpiInitializeObjects, UINT32); + +FAKE_VALUE_FUNC(ACPI_STATUS, AcpiLoadTables); + +FAKE_VALUE_FUNC(ACPI_STATUS, AcpiNsInternalizeName, const char *, char **); + +FAKE_VALUE_FUNC(ACPI_STATUS, AcpiNsLookup, ACPI_GENERIC_STATE *, char *, + ACPI_OBJECT_TYPE, ACPI_INTERPRETER_MODE, UINT32, + ACPI_WALK_STATE *, struct acpi_namespace_node **); + +FAKE_VOID_FUNC(AcpiOsFree, void *); + +FAKE_VALUE_FUNC(ACPI_STATUS, AcpiGetHandle, ACPI_HANDLE, const char *, + ACPI_HANDLE *); + +FAKE_VALUE_FUNC(ACPI_STATUS, AcpiEvaluateObject, ACPI_HANDLE, ACPI_STRING, + ACPI_OBJECT_LIST *, ACPI_BUFFER *); + +FAKE_VALUE_FUNC(ACPI_STATUS, AcpiGetObjectInfo, ACPI_HANDLE, + struct acpi_device_info **); + +FAKE_VALUE_FUNC(char *, AcpiNsGetNormalizedPathname, ACPI_NAMESPACE_NODE *, + BOOLEAN); + +FAKE_VALUE_FUNC(ACPI_STATUS, AcpiGetCurrentResources, ACPI_HANDLE, ACPI_BUFFER *); + +FAKE_VALUE_FUNC(ACPI_STATUS, AcpiWalkNamespace, ACPI_OBJECT_TYPE, ACPI_HANDLE, + UINT32, ACPI_WALK_CALLBACK, ACPI_WALK_CALLBACK, void *, void **); + +FAKE_VALUE_FUNC(ACPI_STATUS, AcpiGetPossibleResources, ACPI_HANDLE, ACPI_BUFFER *); + +FAKE_VALUE_FUNC(ACPI_STATUS, AcpiGetTable, char *, UINT32, + struct acpi_table_header **); From 0442fe3bbf49df802c22a4e5d835c35c06183012 Mon Sep 17 00:00:00 2001 From: Fabio Baltieri Date: Fri, 15 Dec 2023 17:27:49 +0000 Subject: [PATCH 1416/3723] input: npcx_kbd: clear pending interrupts before reenabling detection The driver right now re-enters polling mode a couple times after the matrix has been detected as stable as the key interrupt is still pending and fires again once detection is reenabled. Clear pending WUI interrupts before reenabling key press detection to avoid that. Signed-off-by: Fabio Baltieri --- drivers/input/input_npcx_kbd.c | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/drivers/input/input_npcx_kbd.c b/drivers/input/input_npcx_kbd.c index cd0850e33f7..ba6dc398d1a 100644 --- a/drivers/input/input_npcx_kbd.c +++ b/drivers/input/input_npcx_kbd.c @@ -57,8 +57,13 @@ static void npcx_kbd_ksi_isr(const struct device *dev, struct npcx_wui *wui) static void npcx_kbd_set_detect_mode(const struct device *dev, bool enabled) { const struct npcx_kbd_config *const config = dev->config; + const struct input_kbd_matrix_common_config *common = &config->common; if (enabled) { + for (int i = 0; i < common->row_size; i++) { + npcx_miwu_irq_get_and_clear_pending(&config->wui_maps[i]); + } + irq_enable(config->irq); } else { irq_disable(config->irq); From 5b9a0e54569c8f128315de7c997f86d24ae178ee Mon Sep 17 00:00:00 2001 From: Manuel Aebischer Date: Mon, 11 Dec 2023 20:37:24 +0100 Subject: [PATCH 1417/3723] drivers: usb_dc_rpi_pico: handling of data toggle after endpoint setup The previous behaviour led to an issue where we already expected data1 on the first transfer instead of data0. The DesignWare USB DC actually implements the same behaviour. Also, the next_pid flag has to be reset on setting up the endpoint. Fixes #66283. Signed-off-by: Manuel Aebischer --- drivers/usb/device/usb_dc_rpi_pico.c | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/drivers/usb/device/usb_dc_rpi_pico.c b/drivers/usb/device/usb_dc_rpi_pico.c index bcc5e93151b..c13d564b72d 100644 --- a/drivers/usb/device/usb_dc_rpi_pico.c +++ b/drivers/usb/device/usb_dc_rpi_pico.c @@ -637,9 +637,9 @@ int usb_dc_ep_enable(const uint8_t ep) LOG_DBG("ep 0x%02x (id: %d) -> type %d", ep, USB_EP_GET_IDX(ep), ep_state->type); - /* clear buffer state (EP0 starts with PID=1 for setup phase) */ - - *ep_state->buf_ctl = (USB_EP_GET_IDX(ep) == 0 ? USB_BUF_CTRL_DATA1_PID : 0); + /* clear buffer state */ + *ep_state->buf_ctl = USB_BUF_CTRL_DATA0_PID; + ep_state->next_pid = 0; /* EP0 doesn't have an ep_ctl */ if (ep_state->ep_ctl) { @@ -652,7 +652,9 @@ int usb_dc_ep_enable(const uint8_t ep) *ep_state->ep_ctl = val; } - if (USB_EP_DIR_IS_OUT(ep) && ep != USB_CONTROL_EP_OUT) { + if (USB_EP_DIR_IS_OUT(ep) && ep != USB_CONTROL_EP_OUT && + ep_state->cb != usb_transfer_ep_callback) { + /* Start reading now, except for transfer managed eps */ return usb_dc_ep_start_read(ep, DATA_BUFFER_SIZE); } From a3acc425a9cf635221f712e64a848fc27809241f Mon Sep 17 00:00:00 2001 From: Piotr Kosycarz Date: Mon, 18 Dec 2023 13:35:40 +0100 Subject: [PATCH 1418/3723] scripts: twister: coverage: deal with multiple function definitions Keep definitions instead of abort report creation. Signed-off-by: Piotr Kosycarz --- scripts/pylib/twister/twisterlib/coverage.py | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/scripts/pylib/twister/twisterlib/coverage.py b/scripts/pylib/twister/twisterlib/coverage.py index bb5f5a9dbca..5b32d2f85c8 100644 --- a/scripts/pylib/twister/twisterlib/coverage.py +++ b/scripts/pylib/twister/twisterlib/coverage.py @@ -258,12 +258,16 @@ def _generate(self, outdir, coveragelog): excludes = Gcovr._interleave_list("-e", self.ignores) + # Different ifdef-ed implementations of the same function should not be + # in conflict treated by GCOVR as separate objects for coverage statistics. + mode_options = ["--merge-mode-functions=separate"] + # We want to remove tests/* and tests/ztest/test/* but save tests/ztest cmd = ["gcovr", "-r", self.base_dir, "--gcov-ignore-parse-errors=negative_hits.warn_once_per_file", "--gcov-executable", str(self.gcov_tool), "-e", "tests/*"] - cmd += excludes + ["--json", "-o", coveragefile, outdir] + cmd += excludes + mode_options + ["--json", "-o", coveragefile, outdir] cmd_str = " ".join(cmd) logger.debug(f"Running {cmd_str}...") subprocess.call(cmd, stdout=coveragelog) @@ -271,7 +275,7 @@ def _generate(self, outdir, coveragelog): subprocess.call(["gcovr", "-r", self.base_dir, "--gcov-executable", self.gcov_tool, "-f", "tests/ztest", "-e", "tests/ztest/test/*", "--json", "-o", ztestfile, - outdir], stdout=coveragelog) + outdir] + mode_options, stdout=coveragelog) if os.path.exists(ztestfile) and os.path.getsize(ztestfile) > 0: files = [coveragefile, ztestfile] @@ -294,7 +298,7 @@ def _generate(self, outdir, coveragelog): } gcovr_options = self._flatten_list([report_options[r] for r in self.output_formats.split(',')]) - return subprocess.call(["gcovr", "-r", self.base_dir] + gcovr_options + tracefiles, + return subprocess.call(["gcovr", "-r", self.base_dir] + mode_options + gcovr_options + tracefiles, stdout=coveragelog) From 2bd0c8c5523e904de6813c774149c2e61807210e Mon Sep 17 00:00:00 2001 From: Yong Cong Sin Date: Wed, 13 Dec 2023 15:06:07 +0800 Subject: [PATCH 1419/3723] twister: change schema of `platform_type` to follow `type` The `platform_type` was created to filter `type` so they should have the same schema. Signed-off-by: Yong Cong Sin --- scripts/schemas/twister/testsuite-schema.yaml | 1 + 1 file changed, 1 insertion(+) diff --git a/scripts/schemas/twister/testsuite-schema.yaml b/scripts/schemas/twister/testsuite-schema.yaml index 387a9b884c9..cdf05ac699e 100644 --- a/scripts/schemas/twister/testsuite-schema.yaml +++ b/scripts/schemas/twister/testsuite-schema.yaml @@ -145,6 +145,7 @@ mapping: required: false sequence: - type: str + enum: ["mcu", "qemu", "sim", "unit", "native"] "platform_key": required: false type: seq From 1b16d3d3ec24528e57ca058e5a2bcd2ad3ccd209 Mon Sep 17 00:00:00 2001 From: Yong Cong Sin Date: Tue, 12 Dec 2023 15:19:47 +0800 Subject: [PATCH 1420/3723] twister: fix a minor typo Should be 'related' instead of 'realted'. Signed-off-by: Yong Cong Sin --- scripts/pylib/twister/twisterlib/testplan.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/scripts/pylib/twister/twisterlib/testplan.py b/scripts/pylib/twister/twisterlib/testplan.py index e25e05e49a1..3202d5d483a 100755 --- a/scripts/pylib/twister/twisterlib/testplan.py +++ b/scripts/pylib/twister/twisterlib/testplan.py @@ -58,7 +58,7 @@ class Filters: TESTSUITE = 'testsuite filter' # filters in the testplan yaml definition TESTPLAN = 'testplan filter' - # filters realted to platform definition + # filters related to platform definition PLATFORM = 'Platform related filter' # in case a test suite was quarantined. QUARANTINE = 'Quarantine filter' From 9d314ff86d7e7d2f57a4f326308b57f197bdc7d4 Mon Sep 17 00:00:00 2001 From: Yong Cong Sin Date: Tue, 12 Dec 2023 15:40:49 +0800 Subject: [PATCH 1421/3723] twister: implement `simulation_exclude` filter This gives us the flexibility to exclude certain platforms' simulator that's known to fail from running in Twister, but allows real hardware to be tested. Signed-off-by: Yong Cong Sin --- .../pylib/twister/twisterlib/config_parser.py | 1 + .../pylib/twister/twisterlib/testinstance.py | 3 +- scripts/schemas/twister/testsuite-schema.yaml | 36 +++++++++++++++++++ scripts/twister | 3 ++ 4 files changed, 42 insertions(+), 1 deletion(-) diff --git a/scripts/pylib/twister/twisterlib/config_parser.py b/scripts/pylib/twister/twisterlib/config_parser.py index 53732876247..843fce51a7c 100644 --- a/scripts/pylib/twister/twisterlib/config_parser.py +++ b/scripts/pylib/twister/twisterlib/config_parser.py @@ -70,6 +70,7 @@ class TwisterConfigParser: "platform_exclude": {"type": "set"}, "platform_allow": {"type": "set"}, "platform_key": {"type": "list", "default": []}, + "simulation_exclude": {"type": "list", "default": []}, "toolchain_exclude": {"type": "set"}, "toolchain_allow": {"type": "set"}, "filter": {"type": "str"}, diff --git a/scripts/pylib/twister/twisterlib/testinstance.py b/scripts/pylib/twister/twisterlib/testinstance.py index 24ab66ae030..3b307e41cf2 100644 --- a/scripts/pylib/twister/twisterlib/testinstance.py +++ b/scripts/pylib/twister/twisterlib/testinstance.py @@ -219,7 +219,8 @@ def check_runnable(self, enable_slow=False, filter='buildable', fixtures=[], har target_ready = bool(self.testsuite.type == "unit" or \ self.platform.type == "native" or \ - self.platform.simulation in SUPPORTED_SIMS or \ + (self.platform.simulation in SUPPORTED_SIMS and \ + self.platform.simulation not in self.testsuite.simulation_exclude) or \ filter == 'runnable') # check if test is runnable in pytest diff --git a/scripts/schemas/twister/testsuite-schema.yaml b/scripts/schemas/twister/testsuite-schema.yaml index cdf05ac699e..31aacc76edf 100644 --- a/scripts/schemas/twister/testsuite-schema.yaml +++ b/scripts/schemas/twister/testsuite-schema.yaml @@ -157,6 +157,24 @@ mapping: required: false sequence: - type: str + "simulation_exclude": + type: seq + required: false + sequence: + - type: str + enum: + [ + "qemu", + "simics", + "xt-sim", + "renode", + "nsim", + "mdb-nsim", + "tsim", + "armfvp", + "native", + "custom", + ] "tags": type: any required: false @@ -356,6 +374,24 @@ mapping: matching: "all" sequence: - type: str + "simulation_exclude": + type: seq + required: false + sequence: + - type: str + enum: + [ + "qemu", + "simics", + "xt-sim", + "renode", + "nsim", + "mdb-nsim", + "tsim", + "armfvp", + "native", + "custom", + ] "tags": type: any required: false diff --git a/scripts/twister b/scripts/twister index c66b81d84e1..aa075beb7a1 100755 --- a/scripts/twister +++ b/scripts/twister @@ -90,6 +90,9 @@ pairs: platform_exclude: Set of platforms that this test case should not run on. + simulation_exclude: + Set of simulators that this test case should not run on. + extra_sections: When computing sizes, twister will report errors if it finds extra, unexpected sections in the Zephyr binary unless they are named From a1042c407964cd9710f544b8ba9a61c15a7de2fb Mon Sep 17 00:00:00 2001 From: Yong Cong Sin Date: Tue, 12 Dec 2023 15:43:30 +0800 Subject: [PATCH 1422/3723] tests: kernel: timer_behavior: exclude renode instead of boards We just need to exclude renode simulation and not the physical boards, let's do just that. Signed-off-by: Yong Cong Sin --- tests/kernel/timer/timer_behavior/testcase.yaml | 13 ++----------- 1 file changed, 2 insertions(+), 11 deletions(-) diff --git a/tests/kernel/timer/timer_behavior/testcase.yaml b/tests/kernel/timer/timer_behavior/testcase.yaml index 96a8eb937d4..11ac75e5597 100644 --- a/tests/kernel/timer/timer_behavior/testcase.yaml +++ b/tests/kernel/timer/timer_behavior/testcase.yaml @@ -6,17 +6,8 @@ tests: min_ram: 16 platform_type: - mcu - # Really want to exclude renode not the physical boards, but no good - # way of doing so at the moment. - platform_exclude: - - hifive1 - - tflite-micro - - it8xxx2_evb - - m2gl025_miv - - mpfs_icicle - - hifive_unleashed - - mps2_an385 - - mps2_an521_ns + simulation_exclude: + - renode kernel.timer.timer_behavior_external: filter: dt_compat_enabled("test-kernel-timer-behavior-external") harness: pytest From 947c9dc1b4f79d19b957261fed977a5144717db7 Mon Sep 17 00:00:00 2001 From: Dmitrii Golovanov Date: Fri, 15 Dec 2023 16:01:32 +0100 Subject: [PATCH 1423/3723] twister: coverage: Fix LCOV full path prefixes In some cases genhtml incorrectly built reports from LCOV coverage data using full path for some of the source files and relative paths for other files. This fix adds `--prefix` parameter to shorten paths explicitly relative to the ZEPHYR_BASE directory. Signed-off-by: Dmitrii Golovanov --- scripts/pylib/twister/twisterlib/coverage.py | 1 + 1 file changed, 1 insertion(+) diff --git a/scripts/pylib/twister/twisterlib/coverage.py b/scripts/pylib/twister/twisterlib/coverage.py index 5b32d2f85c8..91265a2665a 100644 --- a/scripts/pylib/twister/twisterlib/coverage.py +++ b/scripts/pylib/twister/twisterlib/coverage.py @@ -224,6 +224,7 @@ def _generate(self, outdir, coveragelog): # The --ignore-errors source option is added to avoid it exiting due to # samples/application_development/external_lib/ cmd = ["genhtml", "--legend", "--branch-coverage", + "--prefix", self.base_dir, "-output-directory", os.path.join(outdir, "coverage")] + files cmd = cmd + ignore_errors From 04601aedad63e51af7ab5377cb5295429c7b5e0a Mon Sep 17 00:00:00 2001 From: Nikolay Agishev Date: Wed, 13 Dec 2023 15:50:44 +0300 Subject: [PATCH 1424/3723] ARCMWDT: Add headers for POSIX compatibility Add ENODATA errno code, wich is not presented in ARCMWDT headers Add PATH_MAX define Signed-off-by: Nikolay Agishev --- lib/libc/arcmwdt/include/errno.h | 38 +++++++++++++++++++++++++++++++ lib/libc/arcmwdt/include/limits.h | 22 ++++++++++++++++++ 2 files changed, 60 insertions(+) create mode 100644 lib/libc/arcmwdt/include/errno.h create mode 100644 lib/libc/arcmwdt/include/limits.h diff --git a/lib/libc/arcmwdt/include/errno.h b/lib/libc/arcmwdt/include/errno.h new file mode 100644 index 00000000000..c69da58b167 --- /dev/null +++ b/lib/libc/arcmwdt/include/errno.h @@ -0,0 +1,38 @@ +/* + * Copyright (c) 1984-1999, 2012 Wind River Systems, Inc. + * Copyright (c) 2023 Synopsys + * + * SPDX-License-Identifier: Apache-2.0 + */ + +/** + * @file + * @brief System error numbers + */ + +#ifndef LIB_LIBC_ARCMWDT_INCLUDE_ERRNO_H_ +#define LIB_LIBC_ARCMWDT_INCLUDE_ERRNO_H_ + +#include_next + +#ifdef __cplusplus +extern "C" { +#endif + +/* MWDT supports range of error codes (ref. $(METAWARE_ROOT)/arc/lib/src/inc/errno.h) + * Add unsupported only + */ +#ifndef ENODATA +#define ENODATA 86 +#endif + +/** + * @} + */ + +#ifdef __cplusplus +} +#endif + + +#endif /* LIB_LIBC_ARCMWDT_INCLUDE_ERRNO_H_ */ diff --git a/lib/libc/arcmwdt/include/limits.h b/lib/libc/arcmwdt/include/limits.h new file mode 100644 index 00000000000..822e66f24d2 --- /dev/null +++ b/lib/libc/arcmwdt/include/limits.h @@ -0,0 +1,22 @@ +/* + * Copyright (c) 2023 Synopsys + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#ifndef LIB_LIBC_ARCMWDT_INCLUDE_LIMITS_H_ +#define LIB_LIBC_ARCMWDT_INCLUDE_LIMITS_H_ + +#include_next + +#ifdef __cplusplus +extern "C" { +#endif + +#define PATH_MAX 256 + +#ifdef __cplusplus +} +#endif + +#endif /* LIB_LIBC_ARCMWDT_INCLUDE_LIMITS_H_ */ From fbe95e4a733fa737120cd29a01b5ca6e88139acb Mon Sep 17 00:00:00 2001 From: Dmitrii Golovanov Date: Fri, 15 Dec 2023 17:45:10 +0100 Subject: [PATCH 1425/3723] tests: unit: Fix Power-of-Two test build issue Fix linker error for the PoT test build with code coverage. Signed-off-by: Dmitrii Golovanov --- tests/unit/pot/prj.conf | 2 ++ 1 file changed, 2 insertions(+) diff --git a/tests/unit/pot/prj.conf b/tests/unit/pot/prj.conf index 3aff91ca987..910bd8dc806 100644 --- a/tests/unit/pot/prj.conf +++ b/tests/unit/pot/prj.conf @@ -2,3 +2,5 @@ # SPDX-License-Identifier: Apache-2.0 CONFIG_ZTEST=y + +CONFIG_CPP=y From 8d51a1dac570bd3b54702a158a10030afff4d293 Mon Sep 17 00:00:00 2001 From: Aleksandr Khromykh Date: Fri, 15 Dec 2023 10:30:37 +0100 Subject: [PATCH 1426/3723] tests: Bluetooth: Mesh: relax beacon test time conditions Some beacon tests have strict time conditions and depend on randomization interval that doesn't guarantee test pass. This change fixes strict conditions. Signed-off-by: Aleksandr Khromykh --- tests/bsim/bluetooth/mesh/src/test_beacon.c | 30 +++++++++++++++++---- 1 file changed, 25 insertions(+), 5 deletions(-) diff --git a/tests/bsim/bluetooth/mesh/src/test_beacon.c b/tests/bsim/bluetooth/mesh/src/test_beacon.c index e5f7d515da7..a4a238f0be1 100644 --- a/tests/bsim/bluetooth/mesh/src/test_beacon.c +++ b/tests/bsim/bluetooth/mesh/src/test_beacon.c @@ -812,6 +812,11 @@ static void test_tx_multiple_netkeys(void) ASSERT_EQUAL(0x00, beacon.flags); ASSERT_EQUAL(0x0000, beacon.iv_index); + /* Wait for end of sending all beacons from the rx node before sending beacon back + * to prevent beacon collision. + */ + k_sleep(K_MSEC(500)); + /* Do the same, but secure beacon with the new Net Key. The node shall set Key * Refresh phase to 2. */ @@ -824,6 +829,11 @@ static void test_tx_multiple_netkeys(void) ASSERT_EQUAL(0x01, beacon.flags); ASSERT_EQUAL(0x0000, beacon.iv_index); + /* Wait for end of sending all beacons from the rx node before sending beacon back + * to prevent beacon collision. + */ + k_sleep(K_MSEC(500)); + /* Send beacon with Key Refresh flag set to 0, but secured with the old Net Key. * The beacon shall be rejected. The beacon interval shall not be changed. */ @@ -836,6 +846,11 @@ static void test_tx_multiple_netkeys(void) ASSERT_EQUAL(0x01, beacon.flags); ASSERT_EQUAL(0x0000, beacon.iv_index); + /* Wait for end of sending all beacons from the rx node before sending beacon back + * to prevent beacon collision. + */ + k_sleep(K_MSEC(500)); + /* Do the same with the new Net Key. Now the node shall change Key Refresh phase * to 0. The beacon interval shall be increased. */ @@ -847,6 +862,11 @@ static void test_tx_multiple_netkeys(void) beacon_confirm_by_subnet, net_id_secondary)); ASSERT_EQUAL(0x00, beacon.flags); ASSERT_EQUAL(0x0000, beacon.iv_index); + + /* Wait for end of sending all beacons from the rx node before sending beacon back + * to prevent beacon collision. + */ + k_sleep(K_MSEC(500)); } /* Create a valid beacon secured with unknown Net Key. The node shall ignore the beacon and @@ -1746,7 +1766,7 @@ static void test_rx_priv_net_id(void) /* Scan for first net ID */ ASSERT_TRUE( - wait_for_beacon(priv_scan_cb, 1, pp_beacon_check, &ctx)); + wait_for_beacon(priv_scan_cb, 5, pp_beacon_check, &ctx)); uint64_t last_pp_random = beacon.pp_random; @@ -1755,7 +1775,7 @@ static void test_rx_priv_net_id(void) */ k_sleep(K_SECONDS(600)); ASSERT_TRUE( - wait_for_beacon(priv_scan_cb, 1, pp_beacon_check, &ctx)); + wait_for_beacon(priv_scan_cb, 5, pp_beacon_check, &ctx)); ASSERT_FALSE(beacon.pp_random == last_pp_random); PASS(); @@ -1800,7 +1820,7 @@ static void test_rx_priv_node_id(void) /* Scan for first node ID */ ASSERT_TRUE( - wait_for_beacon(priv_scan_cb, 1, pp_beacon_check, &ctx)); + wait_for_beacon(priv_scan_cb, 5, pp_beacon_check, &ctx)); uint64_t last_pp_random = beacon.pp_random; @@ -1810,7 +1830,7 @@ static void test_rx_priv_node_id(void) k_sleep(K_SECONDS(65)); ASSERT_TRUE( - wait_for_beacon(priv_scan_cb, 1, pp_beacon_check, &ctx)); + wait_for_beacon(priv_scan_cb, 5, pp_beacon_check, &ctx)); ASSERT_FALSE(beacon.pp_random == last_pp_random); PASS(); @@ -2095,7 +2115,7 @@ static void test_rx_priv_multi_net_id(void) while (itr) { /* Scan for net ID from both networks */ - ASSERT_TRUE(wait_for_beacon(priv_scan_cb, 2, NULL, &ctx)); + ASSERT_TRUE(wait_for_beacon(priv_scan_cb, 5, NULL, &ctx)); for (size_t i = 0; i < ARRAY_SIZE(net_ctx); i++) { if (beacon.pp_hash == From ac4cfe9880f45e871a98e2a62c3b1bd804b3860f Mon Sep 17 00:00:00 2001 From: Aleksandr Khromykh Date: Fri, 15 Dec 2023 10:33:41 +0100 Subject: [PATCH 1427/3723] Bluetooth: Mesh: remove 20ms tx delay in adv bearer The recommendation to have 20ms is fair for two consecutive messages over a single bearer. When mesh sends two messages it can be interpreted as two bearers working in parallel. No need to keep an artificial 20ms delay for that. Delay was removed and all related bsim tests were fixed. Signed-off-by: Aleksandr Khromykh --- subsys/bluetooth/mesh/adv_ext.c | 54 ++++++------------- tests/bsim/bluetooth/mesh/overlay_pst.conf | 2 + .../bluetooth/mesh/src/test_persistence.c | 6 +++ .../bsim/bluetooth/mesh/src/test_provision.c | 10 ++++ 4 files changed, 34 insertions(+), 38 deletions(-) diff --git a/subsys/bluetooth/mesh/adv_ext.c b/subsys/bluetooth/mesh/adv_ext.c index d3bc8a3af82..48d83e8b05a 100644 --- a/subsys/bluetooth/mesh/adv_ext.c +++ b/subsys/bluetooth/mesh/adv_ext.c @@ -60,8 +60,8 @@ struct bt_mesh_ext_adv { ATOMIC_DEFINE(flags, ADV_FLAGS_NUM); struct bt_le_ext_adv *instance; struct bt_mesh_adv *adv; - uint64_t timestamp; - struct k_work_delayable work; + uint32_t timestamp; + struct k_work work; struct bt_le_adv_param adv_param; }; @@ -85,7 +85,7 @@ static struct bt_mesh_ext_adv advs[] = { #endif /* CONFIG_BT_MESH_PB_ADV */ BT_MESH_ADV_TAG_BIT_LOCAL ), - .work = Z_WORK_DELAYABLE_INITIALIZER(send_pending_adv), + .work = Z_WORK_INITIALIZER(send_pending_adv), }, #if CONFIG_BT_MESH_RELAY_ADV_SETS [1 ... CONFIG_BT_MESH_RELAY_ADV_SETS] = { @@ -97,19 +97,19 @@ static struct bt_mesh_ext_adv advs[] = { BT_MESH_ADV_TAG_BIT_PROV | #endif /* CONFIG_BT_MESH_PB_ADV_USE_RELAY_SETS */ 0), - .work = Z_WORK_DELAYABLE_INITIALIZER(send_pending_adv), + .work = Z_WORK_INITIALIZER(send_pending_adv), }, #endif /* CONFIG_BT_MESH_RELAY_ADV_SETS */ #if defined(CONFIG_BT_MESH_ADV_EXT_FRIEND_SEPARATE) { .tags = BT_MESH_ADV_TAG_BIT_FRIEND, - .work = Z_WORK_DELAYABLE_INITIALIZER(send_pending_adv), + .work = Z_WORK_INITIALIZER(send_pending_adv), }, #endif /* CONFIG_BT_MESH_ADV_EXT_FRIEND_SEPARATE */ #if defined(CONFIG_BT_MESH_ADV_EXT_GATT_SEPARATE) { .tags = BT_MESH_ADV_TAG_BIT_PROXY, - .work = Z_WORK_DELAYABLE_INITIALIZER(send_pending_adv), + .work = Z_WORK_INITIALIZER(send_pending_adv), }, #endif /* CONFIG_BT_MESH_ADV_EXT_GATT_SEPARATE */ }; @@ -172,7 +172,7 @@ static int adv_start(struct bt_mesh_ext_adv *ext_adv, return err; } - ext_adv->timestamp = k_uptime_get(); + ext_adv->timestamp = k_uptime_get_32(); err = bt_le_ext_adv_start(ext_adv->instance, start); if (err) { @@ -246,18 +246,13 @@ static void send_pending_adv(struct k_work *work) struct bt_mesh_adv *adv; int err; - ext_adv = CONTAINER_OF(work, struct bt_mesh_ext_adv, work.work); + ext_adv = CONTAINER_OF(work, struct bt_mesh_ext_adv, work); if (atomic_test_and_clear_bit(ext_adv->flags, ADV_FLAG_SENT)) { - /* Calling k_uptime_delta on a timestamp moves it to the current time. - * This is essential here, as schedule_send() uses the end of the event - * as a reference to avoid sending the next advertisement too soon. - */ - int64_t duration = k_uptime_delta(&ext_adv->timestamp); - - LOG_DBG("Advertising stopped after %u ms for %s", (uint32_t)duration, - ext_adv->adv ? adv_tag_to_str[ext_adv->adv->ctx.tag] : - adv_tag_to_str[BT_MESH_ADV_TAG_PROXY]); + LOG_DBG("Advertising stopped after %u ms for %s", + k_uptime_get_32() - ext_adv->timestamp, + ext_adv->adv ? adv_tag_to_str[ext_adv->adv->ctx.tag] + : adv_tag_to_str[BT_MESH_ADV_TAG_PROXY]); atomic_clear_bit(ext_adv->flags, ADV_FLAG_ACTIVE); atomic_clear_bit(ext_adv->flags, ADV_FLAG_PROXY); @@ -315,11 +310,6 @@ static void send_pending_adv(struct k_work *work) static bool schedule_send(struct bt_mesh_ext_adv *ext_adv) { - uint64_t timestamp; - int64_t delta; - - timestamp = ext_adv->timestamp; - if (atomic_test_and_clear_bit(ext_adv->flags, ADV_FLAG_PROXY)) { atomic_clear_bit(ext_adv->flags, ADV_FLAG_PROXY_START); (void)bt_le_ext_adv_stop(ext_adv->instance); @@ -335,19 +325,7 @@ static bool schedule_send(struct bt_mesh_ext_adv *ext_adv) } atomic_clear_bit(ext_adv->flags, ADV_FLAG_SCHEDULE_PENDING); - - if ((IS_ENABLED(CONFIG_BT_MESH_ADV_EXT_FRIEND_SEPARATE) && - ext_adv->tags & BT_MESH_ADV_TAG_BIT_FRIEND) || - (CONFIG_BT_MESH_RELAY_ADV_SETS > 0 && ext_adv->tags & BT_MESH_ADV_TAG_BIT_RELAY)) { - k_work_reschedule(&ext_adv->work, K_NO_WAIT); - } else { - /* The controller will send the next advertisement immediately. - * Introduce a delay here to avoid sending the next mesh packet closer - * to the previous packet than what's permitted by the specification. - */ - delta = k_uptime_delta(×tamp); - k_work_reschedule(&ext_adv->work, K_MSEC(ADV_INT_FAST_MS - delta)); - } + k_work_submit(&ext_adv->work); return true; } @@ -413,7 +391,7 @@ void bt_mesh_adv_terminate(struct bt_mesh_adv *adv) atomic_set_bit(ext_adv->flags, ADV_FLAG_SENT); - k_work_submit(&ext_adv->work.work); + k_work_submit(&ext_adv->work); return; } @@ -462,7 +440,7 @@ static void adv_sent(struct bt_le_ext_adv *instance, atomic_set_bit(ext_adv->flags, ADV_FLAG_SENT); - k_work_submit(&ext_adv->work.work); + k_work_submit(&ext_adv->work); } #if defined(CONFIG_BT_MESH_GATT_SERVER) @@ -511,7 +489,7 @@ int bt_mesh_adv_disable(void) struct k_work_sync sync; for (int i = 0; i < ARRAY_SIZE(advs); i++) { - k_work_flush_delayable(&advs[i].work, &sync); + k_work_flush(&advs[i].work, &sync); err = bt_le_ext_adv_stop(advs[i].instance); if (err) { diff --git a/tests/bsim/bluetooth/mesh/overlay_pst.conf b/tests/bsim/bluetooth/mesh/overlay_pst.conf index 6a56ec8065b..6730b9ee233 100644 --- a/tests/bsim/bluetooth/mesh/overlay_pst.conf +++ b/tests/bsim/bluetooth/mesh/overlay_pst.conf @@ -19,4 +19,6 @@ CONFIG_BT_MESH_SEQ_STORE_RATE=1 CONFIG_BT_MESH_RPL_STORE_TIMEOUT=1 CONFIG_BT_MESH_STORE_TIMEOUT=1 CONFIG_BT_MESH_TX_SEG_RETRANS_COUNT=1 +CONFIG_BT_MESH_TX_SEG_RETRANS_TIMEOUT_UNICAST=200 +CONFIG_BT_MESH_SEG_ACK_BASE_TIMEOUT=400 CONFIG_BT_MESH_COMP_PST_BUF_SIZE=600 diff --git a/tests/bsim/bluetooth/mesh/src/test_persistence.c b/tests/bsim/bluetooth/mesh/src/test_persistence.c index 4bf1f9faa93..ec7d838d26a 100644 --- a/tests/bsim/bluetooth/mesh/src/test_persistence.c +++ b/tests/bsim/bluetooth/mesh/src/test_persistence.c @@ -455,6 +455,12 @@ static void provisioner_setup(void) FAIL("Failed to add test_netkey (err: %d, status: %d)", err, status); } + err = bt_mesh_cfg_cli_net_transmit_set(test_netkey_idx, TEST_PROV_ADDR, + BT_MESH_TRANSMIT(3, 50), &status); + if (err || status != BT_MESH_TRANSMIT(3, 50)) { + FAIL("Net transmit set failed (err %d, transmit %x)", err, status); + } + provisioner_ready = true; } diff --git a/tests/bsim/bluetooth/mesh/src/test_provision.c b/tests/bsim/bluetooth/mesh/src/test_provision.c index 9a83f874e11..3f566947efa 100644 --- a/tests/bsim/bluetooth/mesh/src/test_provision.c +++ b/tests/bsim/bluetooth/mesh/src/test_provision.c @@ -1211,6 +1211,7 @@ static void test_provisioner_pb_remote_client_nppi_robustness(void) uint16_t pb_remote_server_addr; uint8_t status; struct bt_mesh_cdb_node *node; + int err; provisioner_pb_remote_client_setup(); @@ -1224,6 +1225,15 @@ static void test_provisioner_pb_remote_client_nppi_robustness(void) .ttl = 3, }; + /* Set Network Transmit Count state on the remote client greater than on the remote server + * to increase probability of reception responses. + */ + err = bt_mesh_cfg_cli_net_transmit_set(0, current_dev_addr, BT_MESH_TRANSMIT(3, 50), + &status); + if (err || status != BT_MESH_TRANSMIT(3, 50)) { + FAIL("Net transmit set failed (err %d, transmit %x)", err, status); + } + ASSERT_OK(provision_remote(&srv, 2, &srv.addr)); /* Check device key by adding appkey. */ From f82c2f9b1448d8393645a8689f042e5c79bc5520 Mon Sep 17 00:00:00 2001 From: Jordan Yates Date: Fri, 1 Dec 2023 16:45:12 +1000 Subject: [PATCH 1428/3723] doc: _extensions: support `build-dir-fmt` option Support `zephyr-app-commands` being provided with a `build-dir-fmt`, option, which assumes that `west config build.dir-fmt` has been run previously. Signed-off-by: Jordan Yates --- doc/_extensions/zephyr/application.py | 26 ++++++++++++++++++++++++-- 1 file changed, 24 insertions(+), 2 deletions(-) diff --git a/doc/_extensions/zephyr/application.py b/doc/_extensions/zephyr/application.py index 969e3290a59..5e012b43aa2 100644 --- a/doc/_extensions/zephyr/application.py +++ b/doc/_extensions/zephyr/application.py @@ -75,6 +75,10 @@ class ZephyrAppCommandsDirective(Directive): mostly useful for distinguishing builds for one application within a single page. + \:build-dir-fmt: + if set, assume that "west config build.dir-fmt" has been set to this + path. Exclusive with 'build-dir' and depends on 'tool=west'. + \:goals: a whitespace-separated list of what to do with the app (in 'build', 'flash', 'debug', 'debugserver', 'run'). Commands to accomplish @@ -113,6 +117,7 @@ class ZephyrAppCommandsDirective(Directive): 'gen-args': directives.unchanged, 'build-args': directives.unchanged, 'build-dir': directives.unchanged, + 'build-dir-fmt': directives.unchanged, 'goals': directives.unchanged_required, 'maybe-skip-config': directives.flag, 'compact': directives.flag, @@ -143,6 +148,7 @@ def run(self): gen_args = self.options.get('gen-args', None) build_args = self.options.get('build-args', None) build_dir_append = self.options.get('build-dir', '').strip('/') + build_dir_fmt = self.options.get('build-dir-fmt', None) goals = self.options.get('goals').split() skip_config = 'maybe-skip-config' in self.options compact = 'compact' in self.options @@ -156,6 +162,12 @@ def run(self): if app and zephyr_app: raise self.error('Both app and zephyr-app options were given.') + if build_dir_append != '' and build_dir_fmt: + raise self.error('Both build-dir and build-dir-fmt options were given.') + + if build_dir_fmt and tool != 'west': + raise self.error('build-dir-fmt is only supported for the west build tool.') + if generator not in self.GENERATORS: raise self.error('Unknown generator {}; choose from: {}'.format( generator, self.GENERATORS)) @@ -195,6 +207,7 @@ def run(self): 'gen_args': gen_args, 'build_args': build_args, 'build_dir': build_dir, + 'build_dir_fmt': build_dir_fmt, 'goals': goals, 'compact': compact, 'skip_config': skip_config, @@ -248,6 +261,7 @@ def _generate_west(self, **kwargs): goals = kwargs['goals'] cd_into = kwargs['cd_into'] build_dir = kwargs['build_dir'] + build_dir_fmt = kwargs['build_dir_fmt'] compact = kwargs['compact'] west_args = kwargs['west_args'] flash_args = kwargs['flash_args'] @@ -261,7 +275,15 @@ def _generate_west(self, **kwargs): # ignore zephyr_app since west needs to run within # the installation. Instead rely on relative path. src = ' {}'.format(app) if app and not cd_into else '' - dst = ' -d {}'.format(build_dir) if build_dir != 'build' else '' + + if build_dir_fmt is None: + dst = ' -d {}'.format(build_dir) if build_dir != 'build' else '' + build_dst = dst + else: + app_name = app.split('/')[-1] + build_dir_formatted = build_dir_fmt.format(app=app_name, board=board, source_dir=app) + dst = ' -d {}'.format(build_dir_formatted) + build_dst = '' if in_tree and not compact: content.append(in_tree) @@ -280,7 +302,7 @@ def _generate_west(self, **kwargs): # # For now, this keeps the resulting commands working. content.append('west build -b {}{}{}{}{}'. - format(board, west_args, dst, src, cmake_args)) + format(board, west_args, build_dst, src, cmake_args)) # If we're signing, we want to do that next, so that flashing # etc. commands can use the signed file which must be created From 60a9f33f37ae4c5517d084045589543aad63e38c Mon Sep 17 00:00:00 2001 From: Jordan Yates Date: Thu, 16 Nov 2023 17:13:23 +1000 Subject: [PATCH 1429/3723] drivers: flash: spi_nor: boot into DPD Boot into the deep power down state when `SPI_NOR_IDLE_IN_DPD` is not enabled. DPD is the correct hardware state for the `SUSPENDED` software state. Without this change, it takes a cycle of `SUSPENDED->ACTIVE->SUSPENDED` to get to the low power state. Signed-off-by: Jordan Yates --- drivers/flash/spi_nor.c | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/drivers/flash/spi_nor.c b/drivers/flash/spi_nor.c index ea23d11eb95..1658fce1039 100644 --- a/drivers/flash/spi_nor.c +++ b/drivers/flash/spi_nor.c @@ -1359,6 +1359,16 @@ static int spi_nor_pm_control(const struct device *dev, enum pm_device_action ac case PM_DEVICE_ACTION_TURN_ON: /* Coming out of power off */ rc = spi_nor_configure(dev); +#ifndef CONFIG_SPI_NOR_IDLE_IN_DPD + if (rc == 0) { + /* Move to DPD, the correct device state + * for PM_DEVICE_STATE_SUSPENDED + */ + acquire_device(dev); + rc = enter_dpd(dev); + release_device(dev); + } +#endif /* CONFIG_SPI_NOR_IDLE_IN_DPD */ break; case PM_DEVICE_ACTION_TURN_OFF: break; From a5e5c1d00aa19138e7c88430e5e95a8dacdeada2 Mon Sep 17 00:00:00 2001 From: Lucas Denefle Date: Tue, 19 Dec 2023 15:20:01 +0000 Subject: [PATCH 1430/3723] drivers: cellular: add ldenefle to copyright Add Lucas Denefle to copyright of the cellular API. Signed-off-by: Lucas Denefle --- include/zephyr/drivers/cellular.h | 1 + 1 file changed, 1 insertion(+) diff --git a/include/zephyr/drivers/cellular.h b/include/zephyr/drivers/cellular.h index 83135967123..445cd83857c 100644 --- a/include/zephyr/drivers/cellular.h +++ b/include/zephyr/drivers/cellular.h @@ -1,5 +1,6 @@ /* * Copyright (c) 2023 Bjarki Arge Andreasen + * Copyright (c) 2023 Lucas Denefle * * SPDX-License-Identifier: Apache-2.0 */ From 98336b28110c47fdb6567e5541cc39a9969cf7f3 Mon Sep 17 00:00:00 2001 From: Mario Paja Date: Tue, 19 Dec 2023 12:16:49 +0100 Subject: [PATCH 1431/3723] Revert "net: gptp: Fix announce message len" This reverts commit 6b644dff676e56e1402e72db8efe121c1d6b5b43. Reason: breaks Peer-to-Peer gPTP connection. A better solution should be found to handle the optional TLV on the announce message (chapter 10.5.1 IEEE 802.1AS-2011) Signed-off-by: Mario Paja --- subsys/net/l2/ethernet/gptp/gptp_messages.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/subsys/net/l2/ethernet/gptp/gptp_messages.h b/subsys/net/l2/ethernet/gptp/gptp_messages.h index 38c4f60349c..35c5fea2798 100644 --- a/subsys/net/l2/ethernet/gptp/gptp_messages.h +++ b/subsys/net/l2/ethernet/gptp/gptp_messages.h @@ -68,7 +68,7 @@ extern "C" { #define GPTP_ANNOUNCE_LEN(pkt) \ (sizeof(struct gptp_hdr) + sizeof(struct gptp_announce) \ + ntohs(GPTP_ANNOUNCE(pkt)->tlv.len) \ - - sizeof(struct gptp_path_trace_tlv)) + - sizeof(struct gptp_path_trace_tlv) + 4) #define GPTP_CHECK_LEN(pkt, len) \ ((GPTP_PACKET_LEN(pkt) != len) && (GPTP_VALID_LEN(pkt, len))) From 6e678e3baee0c57fcf9a96e47b79f8b9a9e6eeaf Mon Sep 17 00:00:00 2001 From: Francois Ramu Date: Thu, 7 Dec 2023 12:35:49 +0100 Subject: [PATCH 1432/3723] drivers: usb stm32H5 and stm32U5 have an independent power supply The stm32H5 mcu has an independent USB supply to be enabled at init with LL_PWR_EnableVDDUSB function like the stm32U5 serie. Both series have PWR_USBSCR_USB33SV bit in their USBSCR POWER reg. and other series all have PWR_CR2_USV bit in their CR2 POWER reg. Signed-off-by: Francois Ramu --- drivers/usb/device/usb_dc_stm32.c | 11 +++++++---- drivers/usb/udc/udc_stm32.c | 9 ++++++--- 2 files changed, 13 insertions(+), 7 deletions(-) diff --git a/drivers/usb/device/usb_dc_stm32.c b/drivers/usb/device/usb_dc_stm32.c index fe2c0b65f5d..d1434d3ab4b 100644 --- a/drivers/usb/device/usb_dc_stm32.c +++ b/drivers/usb/device/usb_dc_stm32.c @@ -217,10 +217,13 @@ static int usb_dc_stm32_clock_enable(void) return -ENODEV; } -#ifdef CONFIG_SOC_SERIES_STM32U5X - /* VDDUSB independent USB supply (PWR clock is on) */ +#ifdef PWR_USBSCR_USB33SV + /* + * VDDUSB independent USB supply (PWR clock is on) + * with LL_PWR_EnableVDDUSB function (higher case) + */ LL_PWR_EnableVDDUSB(); -#endif /* CONFIG_SOC_SERIES_STM32U5X */ +#endif /* PWR_USBSCR_USB33SV */ if (DT_INST_NUM_CLOCKS(0) > 1) { if (clock_control_configure(clk, (clock_control_subsys_t)&pclken[1], @@ -508,7 +511,7 @@ int usb_dc_attach(void) /* * Required for at least STM32L4 devices as they electrically - * isolate USB features from VDDUSB. It must be enabled before + * isolate USB features from VddUSB. It must be enabled before * USB can function. Refer to section 5.1.3 in DM00083560 or * DM00310109. */ diff --git a/drivers/usb/udc/udc_stm32.c b/drivers/usb/udc/udc_stm32.c index 88070329cc3..bfa3ee8e0f7 100644 --- a/drivers/usb/udc/udc_stm32.c +++ b/drivers/usb/udc/udc_stm32.c @@ -914,10 +914,13 @@ static int priv_clock_enable(void) return -ENODEV; } -#ifdef CONFIG_SOC_SERIES_STM32U5X - /* VDDUSB independent USB supply (PWR clock is on) */ +#if defined(PWR_USBSCR_USB33SV) + /* + * VDDUSB independent USB supply (PWR clock is on) + * with LL_PWR_EnableVDDUSB function (higher case) + */ LL_PWR_EnableVDDUSB(); -#endif /* CONFIG_SOC_SERIES_STM32U5X */ +#endif /* PWR_USBSCR_USB33SV */ #if defined(CONFIG_SOC_SERIES_STM32H7X) LL_PWR_EnableUSBVoltageDetector(); From 3fbf12487c6c01c488210bc56b0f342f07098df9 Mon Sep 17 00:00:00 2001 From: Johan Hedberg Date: Wed, 29 Nov 2023 11:22:39 +0200 Subject: [PATCH 1433/3723] kernel: Introduce a way to specify minimum system heap size There are several subsystems and boards which require a relatively large system heap (used by k_malloc()) to function properly. This became even more notable with the recent introduction of the ACPICA library, which causes ACPI-using boards to require a system heap of up to several megabytes in size. Until now, subsystems and boards have tried to solve this by having Kconfig overlays which modify the default value of HEAP_MEM_POOL_SIZE. This works ok, except when applications start explicitly setting values in their prj.conf files: $ git grep CONFIG_HEAP_MEM_POOL_SIZE= tests samples|wc -l 157 The vast majority of values set by current sample or test applications is much too small for subsystems like ACPI, which results in the application not being able to run on such boards. To solve this situation, we introduce support for subsystems to specify their own custom system heap size requirement. Subsystems do this by defining Kconfig options with the prefix HEAP_MEM_POOL_ADD_SIZE_. The final value of the system heap is the sum of the custom minimum requirements, or the value existing HEAP_MEM_POOL_SIZE option, whichever is greater. We also introduce a new HEAP_MEM_POOL_IGNORE_MIN Kconfig option which applications can use to force a lower value than what subsystems have specficied, however this behavior is disabled by default. Whenever the minimum is greater than the requested value a CMake warning will be issued in the build output. This patch ends up modifying several places outside of kernel code, since the presence of the system heap is no longer detected using a non-zero CONFIG_HEAP_MEM_POOL_SIZE value, rather it's now detected using a new K_HEAP_MEM_POOL_SIZE value that's evaluated at build. Signed-off-by: Johan Hedberg --- arch/xtensa/core/ptables.c | 2 +- doc/kernel/memory_management/heap.rst | 12 +++++++ include/zephyr/kernel.h | 4 +-- kernel/CMakeLists.txt | 32 ++++++++++++++++++- kernel/Kconfig | 20 ++++++++++-- kernel/include/kswap.h | 2 +- kernel/mempool.c | 4 +-- .../mcumgr/grp/img_mgmt/src/zephyr_img_mgmt.c | 4 +-- subsys/net/buf.c | 4 +-- subsys/net/lib/lwm2m/lwm2m_shell.c | 2 +- subsys/portability/cmsis_rtos_v2/mempool.c | 2 +- subsys/portability/cmsis_rtos_v2/msgq.c | 4 +-- subsys/shell/modules/kernel_service.c | 6 ++-- subsys/zbus/zbus.c | 2 +- 14 files changed, 79 insertions(+), 21 deletions(-) diff --git a/arch/xtensa/core/ptables.c b/arch/xtensa/core/ptables.c index 4788584d64d..b6d81e21db1 100644 --- a/arch/xtensa/core/ptables.c +++ b/arch/xtensa/core/ptables.c @@ -133,7 +133,7 @@ static const struct xtensa_mmu_range mmu_zephyr_ranges[] = { #endif .name = "data", }, -#if CONFIG_HEAP_MEM_POOL_SIZE > 0 +#if K_HEAP_MEM_POOL_SIZE > 0 /* System heap memory */ { .start = (uint32_t)_heap_start, diff --git a/doc/kernel/memory_management/heap.rst b/doc/kernel/memory_management/heap.rst index 70d719c7396..7dd332464d2 100644 --- a/doc/kernel/memory_management/heap.rst +++ b/doc/kernel/memory_management/heap.rst @@ -165,6 +165,18 @@ the kernel not to define the heap memory pool object. The maximum size is limite by the amount of available memory in the system. The project build will fail in the link stage if the size specified can not be supported. +In addition, each subsystem (board, driver, library, etc) can set a custom +requirement by defining a Kconfig option with the prefix +``HEAP_MEM_POOL_ADD_SIZE_`` (this value is in bytes). If multiple subsystems +specify custom values, the sum of these will be used as the minimum requirement. +If the application tries to set a value that's less than the minimum value, this +will be ignored and the minimum value will be used instead. + +To force a smaller than minimum value to be used, the application may enable the +:kconfig:option:`CONFIG_HEAP_MEM_POOL_IGNORE_MIN` option. This can be useful +when optimizing the heap size and the minimum requirement can be more accurately +determined for a speficic application. + Allocating Memory ================= diff --git a/include/zephyr/kernel.h b/include/zephyr/kernel.h index ee47caed199..adf121f72ee 100644 --- a/include/zephyr/kernel.h +++ b/include/zephyr/kernel.h @@ -420,7 +420,7 @@ __syscall int k_thread_stack_space_get(const struct k_thread *thread, size_t *unused_ptr); #endif -#if (CONFIG_HEAP_MEM_POOL_SIZE > 0) +#if (K_HEAP_MEM_POOL_SIZE > 0) /** * @brief Assign the system heap as a thread's resource pool * @@ -434,7 +434,7 @@ __syscall int k_thread_stack_space_get(const struct k_thread *thread, * */ void k_thread_system_pool_assign(struct k_thread *thread); -#endif /* (CONFIG_HEAP_MEM_POOL_SIZE > 0) */ +#endif /* (K_HEAP_MEM_POOL_SIZE > 0) */ /** * @brief Sleep until a thread exits diff --git a/kernel/CMakeLists.txt b/kernel/CMakeLists.txt index 5e55b05be61..cd9f39c9558 100644 --- a/kernel/CMakeLists.txt +++ b/kernel/CMakeLists.txt @@ -117,8 +117,38 @@ target_sources_ifdef(CONFIG_OBJ_CORE kernel PRIVATE obj_core.c) if(${CONFIG_KERNEL_MEM_POOL}) target_sources(kernel PRIVATE mempool.c) -endif() + if(CONFIG_HEAP_MEM_POOL_IGNORE_MIN) + set(final_heap_size ${CONFIG_HEAP_MEM_POOL_SIZE}) + else() + # Import all custom HEAP_MEM_POOL size requirements + import_kconfig(CONFIG_HEAP_MEM_POOL_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_HEAP_MEM_POOL_SIZE LESS "${add_size_sum}") + # Only warn if default value 0 has been modified + if(NOT CONFIG_HEAP_MEM_POOL_SIZE EQUAL 0) + message(WARNING " + CONFIG_HEAP_MEM_POOL_SIZE is less than requested minimum: + ${CONFIG_HEAP_MEM_POOL_SIZE} < ${add_size_sum} + Setting the system heap size to ${add_size_sum}") + endif() + + set(final_heap_size ${add_size_sum}) + else() + # CONFIG_HEAP_MEM_POOL_SIZE was greater than the sum of the requirements + set(final_heap_size ${CONFIG_HEAP_MEM_POOL_SIZE}) + endif() + + endif() + + zephyr_compile_definitions(K_HEAP_MEM_POOL_SIZE=${final_heap_size}) +endif() # The last 2 files inside the target_sources_ifdef should be # userspace_handler.c and userspace.c. If not the linker would complain. diff --git a/kernel/Kconfig b/kernel/Kconfig index bd157d8bcc7..3b916aba062 100644 --- a/kernel/Kconfig +++ b/kernel/Kconfig @@ -840,8 +840,24 @@ config HEAP_MEM_POOL_SIZE help This option specifies the size of the heap memory pool used when dynamically allocating memory using k_malloc(). The maximum size of - the memory pool is only limited to available memory. A size of zero - means that no heap memory pool is defined. + the memory pool is only limited to available memory. If subsystems + specify HEAP_MEM_POOL_ADD_SIZE_* options, these will be added together + and the sum will be compared to the HEAP_MEM_POOL_SIZE value. + If the sum is greater than the HEAP_MEM_POOL_SIZE option (even if this + has the default 0 value), then the actual heap size will be rounded up + to the sum of the individual requirements (unless the + HEAP_MEM_POOL_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 system heap will be + available. + +config HEAP_MEM_POOL_IGNORE_MIN + bool "Ignore the minimum heap memory pool requirement" + help + This option can be set to force setting a smaller heap memory pool + size than what's specified by enabled subsystems. This can be useful + when optimizing memory usage and a more precise minimum heap size + is known for a given application. endif # KERNEL_MEM_POOL diff --git a/kernel/include/kswap.h b/kernel/include/kswap.h index fa1e538b8e8..01a72744b00 100644 --- a/kernel/include/kswap.h +++ b/kernel/include/kswap.h @@ -250,7 +250,7 @@ static inline void z_dummy_thread_init(struct k_thread *dummy_thread) #ifdef CONFIG_USERSPACE dummy_thread->mem_domain_info.mem_domain = &k_mem_domain_default; #endif -#if (CONFIG_HEAP_MEM_POOL_SIZE > 0) +#if (K_HEAP_MEM_POOL_SIZE > 0) k_thread_system_pool_assign(dummy_thread); #else dummy_thread->resource_pool = NULL; diff --git a/kernel/mempool.c b/kernel/mempool.c index 3cbfa201222..b3943b52728 100644 --- a/kernel/mempool.c +++ b/kernel/mempool.c @@ -56,9 +56,9 @@ void k_free(void *ptr) } } -#if (CONFIG_HEAP_MEM_POOL_SIZE > 0) +#if (K_HEAP_MEM_POOL_SIZE > 0) -K_HEAP_DEFINE(_system_heap, CONFIG_HEAP_MEM_POOL_SIZE); +K_HEAP_DEFINE(_system_heap, K_HEAP_MEM_POOL_SIZE); #define _SYSTEM_HEAP (&_system_heap) void *k_aligned_alloc(size_t align, size_t size) diff --git a/subsys/mgmt/mcumgr/grp/img_mgmt/src/zephyr_img_mgmt.c b/subsys/mgmt/mcumgr/grp/img_mgmt/src/zephyr_img_mgmt.c index 0af1f19ba88..303f112709a 100644 --- a/subsys/mgmt/mcumgr/grp/img_mgmt/src/zephyr_img_mgmt.c +++ b/subsys/mgmt/mcumgr/grp/img_mgmt/src/zephyr_img_mgmt.c @@ -371,12 +371,12 @@ int img_mgmt_read(int slot, unsigned int offset, void *dst, unsigned int num_byt int img_mgmt_write_image_data(unsigned int offset, const void *data, unsigned int num_bytes, bool last) { - /* Even if CONFIG_HEAP_MEM_POOL_SIZE will be able to match size of the structure, + /* Even if K_HEAP_MEM_POOL_SIZE will be able to match size of the structure, * keep in mind that when application will put the heap under pressure, obtaining * of a flash image context may not be possible, so plan bigger heap size or * make sure to limit application pressure on heap when DFU is expected. */ - BUILD_ASSERT(CONFIG_HEAP_MEM_POOL_SIZE >= (sizeof(struct flash_img_context)), + BUILD_ASSERT(K_HEAP_MEM_POOL_SIZE >= (sizeof(struct flash_img_context)), "Not enough heap mem for flash_img_context."); int rc = IMG_MGMT_ERR_OK; diff --git a/subsys/net/buf.c b/subsys/net/buf.c index 09f937da59d..4862a65f226 100644 --- a/subsys/net/buf.c +++ b/subsys/net/buf.c @@ -166,7 +166,7 @@ const struct net_buf_data_cb net_buf_fixed_cb = { .unref = fixed_data_unref, }; -#if (CONFIG_HEAP_MEM_POOL_SIZE > 0) +#if (K_HEAP_MEM_POOL_SIZE > 0) static uint8_t *heap_data_alloc(struct net_buf *buf, size_t *size, k_timeout_t timeout) @@ -205,7 +205,7 @@ const struct net_buf_data_alloc net_buf_heap_alloc = { .cb = &net_buf_heap_cb, }; -#endif /* CONFIG_HEAP_MEM_POOL_SIZE > 0 */ +#endif /* K_HEAP_MEM_POOL_SIZE > 0 */ static uint8_t *data_alloc(struct net_buf *buf, size_t *size, k_timeout_t timeout) { diff --git a/subsys/net/lib/lwm2m/lwm2m_shell.c b/subsys/net/lib/lwm2m/lwm2m_shell.c index a4cedf8cd62..5dc891178ff 100644 --- a/subsys/net/lib/lwm2m/lwm2m_shell.c +++ b/subsys/net/lib/lwm2m/lwm2m_shell.c @@ -565,7 +565,7 @@ static int cmd_unlock(const struct shell *sh, size_t argc, char **argv) static int cmd_cache(const struct shell *sh, size_t argc, char **argv) { -#if (CONFIG_HEAP_MEM_POOL_SIZE > 0) +#if (K_HEAP_MEM_POOL_SIZE > 0) int rc; int elems; struct lwm2m_time_series_elem *cache; diff --git a/subsys/portability/cmsis_rtos_v2/mempool.c b/subsys/portability/cmsis_rtos_v2/mempool.c index 183d3ac789a..a5a08919753 100644 --- a/subsys/portability/cmsis_rtos_v2/mempool.c +++ b/subsys/portability/cmsis_rtos_v2/mempool.c @@ -30,7 +30,7 @@ osMemoryPoolId_t osMemoryPoolNew(uint32_t block_count, uint32_t block_size, { struct cv2_mslab *mslab; - BUILD_ASSERT(CONFIG_HEAP_MEM_POOL_SIZE >= + BUILD_ASSERT(K_HEAP_MEM_POOL_SIZE >= CONFIG_CMSIS_V2_MEM_SLAB_MAX_DYNAMIC_SIZE, "heap must be configured to be at least the max dynamic size"); diff --git a/subsys/portability/cmsis_rtos_v2/msgq.c b/subsys/portability/cmsis_rtos_v2/msgq.c index d23a5569031..af8c910c189 100644 --- a/subsys/portability/cmsis_rtos_v2/msgq.c +++ b/subsys/portability/cmsis_rtos_v2/msgq.c @@ -28,7 +28,7 @@ osMessageQueueId_t osMessageQueueNew(uint32_t msg_count, uint32_t msg_size, { struct cv2_msgq *msgq; - BUILD_ASSERT(CONFIG_HEAP_MEM_POOL_SIZE >= + BUILD_ASSERT(K_HEAP_MEM_POOL_SIZE >= CONFIG_CMSIS_V2_MSGQ_MAX_DYNAMIC_SIZE, "heap must be configured to be at least the max dynamic size"); @@ -55,7 +55,7 @@ osMessageQueueId_t osMessageQueueNew(uint32_t msg_count, uint32_t msg_size, CONFIG_CMSIS_V2_MSGQ_MAX_DYNAMIC_SIZE, "message queue size exceeds dynamic maximum"); -#if (CONFIG_HEAP_MEM_POOL_SIZE > 0) +#if (K_HEAP_MEM_POOL_SIZE > 0) msgq->pool = k_calloc(msg_count, msg_size); if (msgq->pool == NULL) { k_mem_slab_free(&cv2_msgq_slab, (void *)msgq); diff --git a/subsys/shell/modules/kernel_service.c b/subsys/shell/modules/kernel_service.c index 58a3a454dc5..8c82322729a 100644 --- a/subsys/shell/modules/kernel_service.c +++ b/subsys/shell/modules/kernel_service.c @@ -16,7 +16,7 @@ #include #include #include -#if defined(CONFIG_SYS_HEAP_RUNTIME_STATS) && (CONFIG_HEAP_MEM_POOL_SIZE > 0) +#if defined(CONFIG_SYS_HEAP_RUNTIME_STATS) && (K_HEAP_MEM_POOL_SIZE > 0) #include #endif #if defined(CONFIG_LOG_RUNTIME_FILTERING) @@ -276,7 +276,7 @@ static int cmd_kernel_stacks(const struct shell *sh, } #endif -#if defined(CONFIG_SYS_HEAP_RUNTIME_STATS) && (CONFIG_HEAP_MEM_POOL_SIZE > 0) +#if defined(CONFIG_SYS_HEAP_RUNTIME_STATS) && (K_HEAP_MEM_POOL_SIZE > 0) extern struct sys_heap _system_heap; static int cmd_kernel_heap(const struct shell *sh, @@ -400,7 +400,7 @@ SHELL_STATIC_SUBCMD_SET_CREATE(sub_kernel, SHELL_CMD(stacks, NULL, "List threads stack usage.", cmd_kernel_stacks), SHELL_CMD(threads, NULL, "List kernel threads.", cmd_kernel_threads), #endif -#if defined(CONFIG_SYS_HEAP_RUNTIME_STATS) && (CONFIG_HEAP_MEM_POOL_SIZE > 0) +#if defined(CONFIG_SYS_HEAP_RUNTIME_STATS) && (K_HEAP_MEM_POOL_SIZE > 0) SHELL_CMD(heap, NULL, "System heap usage statistics.", cmd_kernel_heap), #endif SHELL_CMD_ARG(uptime, NULL, "Kernel uptime. Can be called with the -p or --pretty options", diff --git a/subsys/zbus/zbus.c b/subsys/zbus/zbus.c index 440d4c09315..959ef59aa8e 100644 --- a/subsys/zbus/zbus.c +++ b/subsys/zbus/zbus.c @@ -18,7 +18,7 @@ LOG_MODULE_REGISTER(zbus, CONFIG_ZBUS_LOG_LEVEL); NET_BUF_POOL_HEAP_DEFINE(_zbus_msg_subscribers_pool, CONFIG_ZBUS_MSG_SUBSCRIBER_NET_BUF_POOL_SIZE, sizeof(struct zbus_channel *), NULL); -BUILD_ASSERT(CONFIG_HEAP_MEM_POOL_SIZE > 0, "MSG_SUBSCRIBER feature requires heap memory pool."); +BUILD_ASSERT(K_HEAP_MEM_POOL_SIZE > 0, "MSG_SUBSCRIBER feature requires heap memory pool."); static inline struct net_buf *_zbus_create_net_buf(struct net_buf_pool *pool, size_t size, k_timeout_t timeout) From 35854391c85c0d435e92b8d399e9e27e03be5d53 Mon Sep 17 00:00:00 2001 From: Johan Hedberg Date: Tue, 12 Dec 2023 13:34:49 +0200 Subject: [PATCH 1434/3723] scripts: compliance: Add HEAP_MEM_POOL_ADD_SIZE_ to undef whitelist The HEAP_MEM_POOL_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: Johan Hedberg --- 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 a331fa1c7b9..94e6b99f4ec 100755 --- a/scripts/ci/check_compliance.py +++ b/scripts/ci/check_compliance.py @@ -664,6 +664,7 @@ def check_no_undef_outside_kconfig(self, kconf): "FOO_LOG_LEVEL", "FOO_SETTING_1", "FOO_SETTING_2", + "HEAP_MEM_POOL_ADD_SIZE_", # Used as an option matching prefix "LSM6DSO_INT_PIN", "LIBGCC_RTLIB", "LLVM_USE_LD", # Both LLVM_USE_* are in cmake/toolchain/llvm/Kconfig From 0594d29f4e009a714661f2ea6a84342bc6c24563 Mon Sep 17 00:00:00 2001 From: Johan Hedberg Date: Wed, 29 Nov 2023 11:43:25 +0200 Subject: [PATCH 1435/3723] lib: acpi: Introduce HEAP_MEM_POOL_ADD_SIZE_ACPI option All x86 boards have so far set a custom heap memory pool size because of their dependency on ACPI. It makes more sense to introduce a new ACPI-specific option, utilizing the recently added HEAP_MEM_POOL_ADD_SIZE_ Kconfig option prefix, and adjust the default value as necessary for each board. Signed-off-by: Johan Hedberg --- boards/x86/acrn/Kconfig.defconfig | 6 +++--- boards/x86/intel_adl/Kconfig.defconfig | 2 +- boards/x86/intel_ehl/Kconfig.defconfig | 6 +++--- boards/x86/intel_rpl/Kconfig.defconfig | 2 +- boards/x86/qemu_x86/Kconfig.defconfig | 8 -------- boards/x86/up_squared/Kconfig.defconfig | 4 ---- lib/acpi/Kconfig | 4 ++++ 7 files changed, 12 insertions(+), 20 deletions(-) diff --git a/boards/x86/acrn/Kconfig.defconfig b/boards/x86/acrn/Kconfig.defconfig index 0216875583c..a1a8936e38b 100644 --- a/boards/x86/acrn/Kconfig.defconfig +++ b/boards/x86/acrn/Kconfig.defconfig @@ -10,8 +10,8 @@ config BOARD config MP_MAX_NUM_CPUS default 2 -config HEAP_MEM_POOL_SIZE - default 32768 if ACPI - depends on KERNEL_MEM_POOL +config HEAP_MEM_POOL_ADD_SIZE_ACPI + default 32768 + depends on ACPI endif diff --git a/boards/x86/intel_adl/Kconfig.defconfig b/boards/x86/intel_adl/Kconfig.defconfig index cc9e3882ec4..597f6c566f4 100644 --- a/boards/x86/intel_adl/Kconfig.defconfig +++ b/boards/x86/intel_adl/Kconfig.defconfig @@ -33,7 +33,7 @@ config ACPI default y if ACPI -config HEAP_MEM_POOL_SIZE +config HEAP_MEM_POOL_ADD_SIZE_ACPI default 64000000 config MAIN_STACK_SIZE default 320000 diff --git a/boards/x86/intel_ehl/Kconfig.defconfig b/boards/x86/intel_ehl/Kconfig.defconfig index 7d6667a6cec..f3a5519ee9b 100644 --- a/boards/x86/intel_ehl/Kconfig.defconfig +++ b/boards/x86/intel_ehl/Kconfig.defconfig @@ -23,9 +23,9 @@ config ACPI_PRT_BUS_NAME depends on ACPI default "_SB.PC00" -config HEAP_MEM_POOL_SIZE - default 2097152 if ACPI - depends on KERNEL_MEM_POOL +config HEAP_MEM_POOL_ADD_SIZE_ACPI + default 2097152 + depends on ACPI # TSC on this board is 1.9 GHz, HPET and APIC are 19.2 MHz config SYS_CLOCK_HW_CYCLES_PER_SEC diff --git a/boards/x86/intel_rpl/Kconfig.defconfig b/boards/x86/intel_rpl/Kconfig.defconfig index ea93b03e039..10ae8ff2682 100644 --- a/boards/x86/intel_rpl/Kconfig.defconfig +++ b/boards/x86/intel_rpl/Kconfig.defconfig @@ -31,7 +31,7 @@ config ACPI default y if ACPI -config HEAP_MEM_POOL_SIZE +config HEAP_MEM_POOL_ADD_SIZE_ACPI default 64000000 config MAIN_STACK_SIZE default 320000 diff --git a/boards/x86/qemu_x86/Kconfig.defconfig b/boards/x86/qemu_x86/Kconfig.defconfig index 84f66e32004..1e2b7af0a4d 100644 --- a/boards/x86/qemu_x86/Kconfig.defconfig +++ b/boards/x86/qemu_x86/Kconfig.defconfig @@ -24,10 +24,6 @@ config FLASH_SIMULATOR config KERNEL_VM_SIZE default 0x10000000 if ACPI -config HEAP_MEM_POOL_SIZE - default 1048576 if ACPI - depends on KERNEL_MEM_POOL - config MULTIBOOT default y @@ -53,10 +49,6 @@ config BOARD config KERNEL_VM_SIZE default 0x10000000 if ACPI -config HEAP_MEM_POOL_SIZE - default 1048576 if ACPI - depends on KERNEL_MEM_POOL - endif # BOARD_QEMU_X86_64 if BOARD_QEMU_X86_LAKEMONT diff --git a/boards/x86/up_squared/Kconfig.defconfig b/boards/x86/up_squared/Kconfig.defconfig index 33cf546edfc..e8eecbcc508 100644 --- a/boards/x86/up_squared/Kconfig.defconfig +++ b/boards/x86/up_squared/Kconfig.defconfig @@ -8,10 +8,6 @@ config BOARD config MP_MAX_NUM_CPUS default 2 if BOARD_UP_SQUARED -config HEAP_MEM_POOL_SIZE - default 1048576 if ACPI - depends on KERNEL_MEM_POOL - config BUILD_OUTPUT_STRIPPED default y diff --git a/lib/acpi/Kconfig b/lib/acpi/Kconfig index 42b35725c70..5431a1c7e28 100644 --- a/lib/acpi/Kconfig +++ b/lib/acpi/Kconfig @@ -30,6 +30,10 @@ config ACPI_MAX_PRT_ENTRY endif # PCIE_PRT +# Default minimum system heap required by ACPI +config HEAP_MEM_POOL_ADD_SIZE_ACPI + def_int 1048576 # 1MB + config ACPI_SHELL bool "ACPI command Shell" depends on SHELL From 9bc1a2fca2e35826c822ca667452b6e2bac26de9 Mon Sep 17 00:00:00 2001 From: Johan Hedberg Date: Wed, 29 Nov 2023 11:37:58 +0200 Subject: [PATCH 1436/3723] boards: arm: Use HEAP_MEM_POOL_ADD_SIZE KConfig options Kconfig options with a HEAP_MEM_POOL_ADD_SIZE_ prefix should be used to set the minimum required system heap size. This helps prevent applications from creating a non-working image by trying to set a too small value. Signed-off-by: Johan Hedberg --- boards/arm/bl5340_dvk/Kconfig.defconfig | 3 ++- boards/arm/cy8cproto_062_4343w/Kconfig.defconfig | 3 ++- boards/arm/mimxrt595_evk/Kconfig.defconfig | 5 +++-- boards/arm/nrf5340_audio_dk_nrf5340/Kconfig.defconfig | 3 ++- boards/arm/nrf5340dk_nrf5340/Kconfig.defconfig | 3 ++- boards/arm/pan1783_pan1783a_evb/Kconfig.defconfig | 3 ++- boards/arm/raytac_mdbt53_db_40_nrf5340/Kconfig.defconfig | 3 ++- boards/arm/raytac_mdbt53v_db_40_nrf5340/Kconfig.defconfig | 3 ++- boards/arm/thingy53_nrf5340/Kconfig.defconfig | 3 ++- 9 files changed, 19 insertions(+), 10 deletions(-) diff --git a/boards/arm/bl5340_dvk/Kconfig.defconfig b/boards/arm/bl5340_dvk/Kconfig.defconfig index 798f331efc3..d87d6d75f37 100644 --- a/boards/arm/bl5340_dvk/Kconfig.defconfig +++ b/boards/arm/bl5340_dvk/Kconfig.defconfig @@ -78,7 +78,8 @@ choice BT_HCI_BUS_TYPE default BT_HCI_IPC if BT endchoice -config HEAP_MEM_POOL_SIZE +config HEAP_MEM_POOL_ADD_SIZE_BOARD + int default 4096 if BT_HCI_IPC config BT_HCI_VS diff --git a/boards/arm/cy8cproto_062_4343w/Kconfig.defconfig b/boards/arm/cy8cproto_062_4343w/Kconfig.defconfig index ba117ace665..0ed2d372835 100644 --- a/boards/arm/cy8cproto_062_4343w/Kconfig.defconfig +++ b/boards/arm/cy8cproto_062_4343w/Kconfig.defconfig @@ -49,7 +49,8 @@ endchoice endif # BT # Heap Pool Size -config HEAP_MEM_POOL_SIZE +config HEAP_MEM_POOL_ADD_SIZE_BOARD + int default 15000 if WIFI default 4096 diff --git a/boards/arm/mimxrt595_evk/Kconfig.defconfig b/boards/arm/mimxrt595_evk/Kconfig.defconfig index 3a4580a3603..96779115e14 100644 --- a/boards/arm/mimxrt595_evk/Kconfig.defconfig +++ b/boards/arm/mimxrt595_evk/Kconfig.defconfig @@ -23,8 +23,9 @@ if DMA_MCUX_LPC # Memory from the heap pool is used to allocate DMA descriptors for # channels that use multiple blocks for a DMA transfer. -# Adjust HEAP_MEM_POOL_SIZE in case you need more memory. -config HEAP_MEM_POOL_SIZE +# Adjust HEAP_MEM_POOL_MIN_SIZE in case you need more memory. +config HEAP_MEM_POOL_ADD_SIZE_BOARD + int default 4096 endif # DMA_MCUX_LPC diff --git a/boards/arm/nrf5340_audio_dk_nrf5340/Kconfig.defconfig b/boards/arm/nrf5340_audio_dk_nrf5340/Kconfig.defconfig index eaa56252095..685ebc49b63 100644 --- a/boards/arm/nrf5340_audio_dk_nrf5340/Kconfig.defconfig +++ b/boards/arm/nrf5340_audio_dk_nrf5340/Kconfig.defconfig @@ -73,7 +73,8 @@ choice BT_HCI_BUS_TYPE default BT_HCI_IPC if BT endchoice -config HEAP_MEM_POOL_SIZE +config HEAP_MEM_POOL_ADD_SIZE_BOARD + int default 4096 if BT_HCI_IPC endif # BOARD_NRF5340_AUDIO_DK_NRF5340_CPUAPP || BOARD_NRF5340_AUDIO_DK_NRF5340_CPUAPP_NS diff --git a/boards/arm/nrf5340dk_nrf5340/Kconfig.defconfig b/boards/arm/nrf5340dk_nrf5340/Kconfig.defconfig index 9006846dccb..84f19365cc5 100644 --- a/boards/arm/nrf5340dk_nrf5340/Kconfig.defconfig +++ b/boards/arm/nrf5340dk_nrf5340/Kconfig.defconfig @@ -70,7 +70,8 @@ choice BT_HCI_BUS_TYPE default BT_HCI_IPC if BT endchoice -config HEAP_MEM_POOL_SIZE +config HEAP_MEM_POOL_ADD_SIZE_BOARD + int default 4096 if BT_HCI_IPC endif # BOARD_NRF5340DK_NRF5340_CPUAPP || BOARD_NRF5340DK_NRF5340_CPUAPP_NS diff --git a/boards/arm/pan1783_pan1783a_evb/Kconfig.defconfig b/boards/arm/pan1783_pan1783a_evb/Kconfig.defconfig index a8e70837d3a..34daddb0ea7 100644 --- a/boards/arm/pan1783_pan1783a_evb/Kconfig.defconfig +++ b/boards/arm/pan1783_pan1783a_evb/Kconfig.defconfig @@ -18,7 +18,8 @@ choice BT_HCI_BUS_TYPE default BT_HCI_IPC if BT endchoice -config HEAP_MEM_POOL_SIZE +config HEAP_MEM_POOL_ADD_SIZE_BOARD + int default 4096 if BT_HCI_IPC endif # BOARD_PAN1783_EVB_CPUAPP || BOARD_PAN1783A_EVB_CPUAPP diff --git a/boards/arm/raytac_mdbt53_db_40_nrf5340/Kconfig.defconfig b/boards/arm/raytac_mdbt53_db_40_nrf5340/Kconfig.defconfig index f179e667d6b..fb5a6b85630 100644 --- a/boards/arm/raytac_mdbt53_db_40_nrf5340/Kconfig.defconfig +++ b/boards/arm/raytac_mdbt53_db_40_nrf5340/Kconfig.defconfig @@ -73,7 +73,8 @@ choice BT_HCI_BUS_TYPE default BT_HCI_IPC if BT endchoice -config HEAP_MEM_POOL_SIZE +config HEAP_MEM_POOL_ADD_SIZE_BOARD + int default 4096 if BT_HCI_IPC endif # BOARD_RAYTAC_MDBT53_DB_40_NRF5340_CPUAPP || BOARD_RAYTAC_MDBT53_DB_40_NRF5340_CPUAPP_NS diff --git a/boards/arm/raytac_mdbt53v_db_40_nrf5340/Kconfig.defconfig b/boards/arm/raytac_mdbt53v_db_40_nrf5340/Kconfig.defconfig index 10f4373b352..fd3e5210d28 100644 --- a/boards/arm/raytac_mdbt53v_db_40_nrf5340/Kconfig.defconfig +++ b/boards/arm/raytac_mdbt53v_db_40_nrf5340/Kconfig.defconfig @@ -73,7 +73,8 @@ choice BT_HCI_BUS_TYPE default BT_HCI_IPC if BT endchoice -config HEAP_MEM_POOL_SIZE +config HEAP_MEM_POOL_ADD_SIZE_BOARD + int default 4096 if BT_HCI_IPC endif # BOARD_RAYTAC_MDBT53V_DB_40_NRF5340_CPUAPP || BOARD_RAYTAC_MDBT53V_DB_40_NRF5340_CPUAPP_NS diff --git a/boards/arm/thingy53_nrf5340/Kconfig.defconfig b/boards/arm/thingy53_nrf5340/Kconfig.defconfig index 708d9a05d51..12f1e5bbdc9 100644 --- a/boards/arm/thingy53_nrf5340/Kconfig.defconfig +++ b/boards/arm/thingy53_nrf5340/Kconfig.defconfig @@ -62,7 +62,8 @@ choice BT_HCI_BUS_TYPE default BT_HCI_IPC if BT endchoice -config HEAP_MEM_POOL_SIZE +config HEAP_MEM_POOL_ADD_SIZE_BOARD + int default 4096 if BT_HCI_IPC config BT_HAS_HCI_VS From 2b83dd72d8985d0c81a8476cf2ed99177f916d6e Mon Sep 17 00:00:00 2001 From: Johan Hedberg Date: Wed, 29 Nov 2023 11:40:38 +0200 Subject: [PATCH 1437/3723] boards: arm64: Use HEAP_MEM_POOL_ADD_SIZE KConfig options Kconfig options with a HEAP_MEM_POOL_ADD_SIZE_ prefix should be used to set the minimum required system heap size. This helps prevent applications from creating a non-working image by trying to set a too small value. Signed-off-by: Johan Hedberg --- boards/arm64/fvp_base_revc_2xaemv8a/Kconfig | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/boards/arm64/fvp_base_revc_2xaemv8a/Kconfig b/boards/arm64/fvp_base_revc_2xaemv8a/Kconfig index 8059b39fe90..c8271b2ff0e 100644 --- a/boards/arm64/fvp_base_revc_2xaemv8a/Kconfig +++ b/boards/arm64/fvp_base_revc_2xaemv8a/Kconfig @@ -14,5 +14,6 @@ # This doesn't necessarily include the Interrupt Translation Table, which are # 256bytes aligned tables, for reference a 32 ITEs table needs 256bytes. # With 11x64K HEAP, up to 116 ITT tables of 32 ITEs can be allocated. -config HEAP_MEM_POOL_SIZE +config HEAP_MEM_POOL_ADD_SIZE_BOARD + int default 720896 if GIC_V3_ITS From 1fb4cbbb4808097aa9cca426090f9784398b40c4 Mon Sep 17 00:00:00 2001 From: Johan Hedberg Date: Wed, 29 Nov 2023 11:41:23 +0200 Subject: [PATCH 1438/3723] boards: posix: Use HEAP_MEM_POOL_ADD_SIZE KConfig options Kconfig options with a HEAP_MEM_POOL_ADD_SIZE_ prefix should be used to set the minimum required system heap size. This helps prevent applications from creating a non-working image by trying to set a too small value. Signed-off-by: Johan Hedberg --- boards/posix/nrf_bsim/Kconfig.defconfig | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/boards/posix/nrf_bsim/Kconfig.defconfig b/boards/posix/nrf_bsim/Kconfig.defconfig index 6993048248c..e762a3c6c85 100644 --- a/boards/posix/nrf_bsim/Kconfig.defconfig +++ b/boards/posix/nrf_bsim/Kconfig.defconfig @@ -44,7 +44,8 @@ config BT_CTLR default y if BOARD_NRF52_BSIM || BOARD_NRF5340BSIM_NRF5340_CPUNET depends on BT -config HEAP_MEM_POOL_SIZE +config HEAP_MEM_POOL_ADD_SIZE_BOARD + int default 4096 if BT_HCI_IPC default 4096 if NRF_802154_SER_HOST && BOARD_NRF5340BSIM_NRF5340_CPUAPP default 4096 if NRF_802154_SER_RADIO && BOARD_NRF5340BSIM_NRF5340_CPUNET From 1afc0a16c5670834604ff4f2b70b2c1511b5c230 Mon Sep 17 00:00:00 2001 From: Johan Hedberg Date: Wed, 29 Nov 2023 11:42:25 +0200 Subject: [PATCH 1439/3723] boards: riscv: Use HEAP_MEM_POOL_ADD_SIZE KConfig options Kconfig options with a HEAP_MEM_POOL_ADD_SIZE_ prefix should be used to set the minimum required system heap size. This helps prevent applications from creating a non-working image by trying to set a too small value. Signed-off-by: Johan Hedberg --- boards/riscv/esp32c3_devkitm/Kconfig.defconfig | 3 ++- boards/riscv/esp32c3_luatos_core/Kconfig.defconfig | 3 ++- boards/riscv/icev_wireless/Kconfig.defconfig | 3 ++- boards/riscv/stamp_c3/Kconfig.defconfig | 3 ++- boards/riscv/xiao_esp32c3/Kconfig.defconfig | 3 ++- 5 files changed, 10 insertions(+), 5 deletions(-) diff --git a/boards/riscv/esp32c3_devkitm/Kconfig.defconfig b/boards/riscv/esp32c3_devkitm/Kconfig.defconfig index 3686c1e8ad3..50f3d6b382c 100644 --- a/boards/riscv/esp32c3_devkitm/Kconfig.defconfig +++ b/boards/riscv/esp32c3_devkitm/Kconfig.defconfig @@ -7,7 +7,8 @@ config BOARD default "esp32c3_devkitm" depends on BOARD_ESP32C3_DEVKITM -config HEAP_MEM_POOL_SIZE +config HEAP_MEM_POOL_ADD_SIZE_BOARD + int default 98304 if WIFI default 40960 if BT default 4096 diff --git a/boards/riscv/esp32c3_luatos_core/Kconfig.defconfig b/boards/riscv/esp32c3_luatos_core/Kconfig.defconfig index 1a1ee456a3d..d132f546144 100644 --- a/boards/riscv/esp32c3_luatos_core/Kconfig.defconfig +++ b/boards/riscv/esp32c3_luatos_core/Kconfig.defconfig @@ -7,7 +7,8 @@ config BOARD default "esp32c3_luatos_core" depends on BOARD_ESP32C3_LUATOS_CORE || BOARD_ESP32C3_LUATOS_CORE_USB -config HEAP_MEM_POOL_SIZE +config HEAP_MEM_POOL_ADD_SIZE_BOARD + int default 98304 if WIFI default 40960 if BT default 4096 diff --git a/boards/riscv/icev_wireless/Kconfig.defconfig b/boards/riscv/icev_wireless/Kconfig.defconfig index 84ce9486559..1eca2f02e6d 100644 --- a/boards/riscv/icev_wireless/Kconfig.defconfig +++ b/boards/riscv/icev_wireless/Kconfig.defconfig @@ -5,7 +5,8 @@ config BOARD default "icev_wireless" depends on BOARD_ICEV_WIRELESS -config HEAP_MEM_POOL_SIZE +config HEAP_MEM_POOL_ADD_SIZE_BOARD + int default 98304 if WIFI default 40960 if BT default 4096 diff --git a/boards/riscv/stamp_c3/Kconfig.defconfig b/boards/riscv/stamp_c3/Kconfig.defconfig index cbd96af9cd0..6ad89229799 100644 --- a/boards/riscv/stamp_c3/Kconfig.defconfig +++ b/boards/riscv/stamp_c3/Kconfig.defconfig @@ -7,7 +7,8 @@ config BOARD default "stamp_c3" depends on BOARD_STAMP_C3 -config HEAP_MEM_POOL_SIZE +config HEAP_MEM_POOL_ADD_SIZE_BOARD + int default 98304 if WIFI default 40960 if BT default 4096 diff --git a/boards/riscv/xiao_esp32c3/Kconfig.defconfig b/boards/riscv/xiao_esp32c3/Kconfig.defconfig index e67ddbcc42e..52c7a95c46c 100644 --- a/boards/riscv/xiao_esp32c3/Kconfig.defconfig +++ b/boards/riscv/xiao_esp32c3/Kconfig.defconfig @@ -5,7 +5,8 @@ config BOARD default "xiao_esp32c3" depends on BOARD_XIAO_ESP32C3 -config HEAP_MEM_POOL_SIZE +config HEAP_MEM_POOL_ADD_SIZE_BOARD + int default 98304 if WIFI default 40960 if BT default 4096 From c6c1d462a0ac541cf6b08de3223d37ec0e0072e7 Mon Sep 17 00:00:00 2001 From: Johan Hedberg Date: Wed, 29 Nov 2023 11:44:25 +0200 Subject: [PATCH 1440/3723] boards: xtensa: Use HEAP_MEM_POOL_ADD_SIZE KConfig options Kconfig options with a HEAP_MEM_POOL_ADD_SIZE_ prefix should be used to set the minimum required system heap size. This helps prevent applications from creating a non-working image by trying to set a too small value. Signed-off-by: Johan Hedberg --- boards/xtensa/esp32_devkitc_wroom/Kconfig.defconfig | 3 ++- boards/xtensa/esp32_devkitc_wrover/Kconfig.defconfig | 3 ++- boards/xtensa/esp32_ethernet_kit/Kconfig.defconfig | 3 ++- boards/xtensa/esp32_net/Kconfig.defconfig | 3 ++- boards/xtensa/esp32s2_franzininho/Kconfig.defconfig | 3 ++- boards/xtensa/esp32s2_lolin_mini/Kconfig.defconfig | 3 ++- boards/xtensa/esp32s2_saola/Kconfig.defconfig | 3 ++- boards/xtensa/esp32s3_devkitm/Kconfig.defconfig | 7 ++++--- boards/xtensa/esp32s3_luatos_core/Kconfig.defconfig | 3 ++- boards/xtensa/esp_wrover_kit/Kconfig.defconfig | 3 ++- boards/xtensa/heltec_wifi_lora32_v2/Kconfig.defconfig | 3 ++- .../xtensa/heltec_wireless_stick_lite_v3/Kconfig.defconfig | 3 ++- boards/xtensa/m5stack_atoms3/Kconfig.defconfig | 3 ++- boards/xtensa/m5stack_core2/Kconfig.defconfig | 3 ++- boards/xtensa/m5stickc_plus/Kconfig.defconfig | 3 ++- boards/xtensa/odroid_go/Kconfig.defconfig | 3 ++- boards/xtensa/olimex_esp32_evb/Kconfig.defconfig | 3 ++- boards/xtensa/xiao_esp32s3/Kconfig.defconfig | 3 ++- boards/xtensa/yd_esp32/Kconfig.defconfig | 3 ++- 19 files changed, 40 insertions(+), 21 deletions(-) diff --git a/boards/xtensa/esp32_devkitc_wroom/Kconfig.defconfig b/boards/xtensa/esp32_devkitc_wroom/Kconfig.defconfig index cf2cb4403a1..a168ca5f31d 100644 --- a/boards/xtensa/esp32_devkitc_wroom/Kconfig.defconfig +++ b/boards/xtensa/esp32_devkitc_wroom/Kconfig.defconfig @@ -10,7 +10,8 @@ config BOARD config ENTROPY_GENERATOR default y -config HEAP_MEM_POOL_SIZE +config HEAP_MEM_POOL_ADD_SIZE_BOARD + int default 98304 if WIFI default 40960 if BT default 4096 diff --git a/boards/xtensa/esp32_devkitc_wrover/Kconfig.defconfig b/boards/xtensa/esp32_devkitc_wrover/Kconfig.defconfig index 8b977af6943..9e07262b1d4 100644 --- a/boards/xtensa/esp32_devkitc_wrover/Kconfig.defconfig +++ b/boards/xtensa/esp32_devkitc_wrover/Kconfig.defconfig @@ -8,7 +8,8 @@ config BOARD config ENTROPY_GENERATOR default y -config HEAP_MEM_POOL_SIZE +config HEAP_MEM_POOL_ADD_SIZE_BOARD + int default 98304 if WIFI default 40960 if BT default 4096 diff --git a/boards/xtensa/esp32_ethernet_kit/Kconfig.defconfig b/boards/xtensa/esp32_ethernet_kit/Kconfig.defconfig index aed4adc50a8..78dd56efa0f 100644 --- a/boards/xtensa/esp32_ethernet_kit/Kconfig.defconfig +++ b/boards/xtensa/esp32_ethernet_kit/Kconfig.defconfig @@ -17,7 +17,8 @@ endchoice config ENTROPY_GENERATOR default y -config HEAP_MEM_POOL_SIZE +config HEAP_MEM_POOL_ADD_SIZE_BOARD + int default 98304 if WIFI default 40960 if BT default 4096 diff --git a/boards/xtensa/esp32_net/Kconfig.defconfig b/boards/xtensa/esp32_net/Kconfig.defconfig index 928a4c06de9..7770e94a0ae 100644 --- a/boards/xtensa/esp32_net/Kconfig.defconfig +++ b/boards/xtensa/esp32_net/Kconfig.defconfig @@ -10,7 +10,8 @@ config BOARD config ENTROPY_GENERATOR default y -config HEAP_MEM_POOL_SIZE +config HEAP_MEM_POOL_ADD_SIZE_BOARD + int default 98304 if WIFI default 40960 if BT default 4096 diff --git a/boards/xtensa/esp32s2_franzininho/Kconfig.defconfig b/boards/xtensa/esp32s2_franzininho/Kconfig.defconfig index 94937f824dc..d8bd4c6916f 100644 --- a/boards/xtensa/esp32s2_franzininho/Kconfig.defconfig +++ b/boards/xtensa/esp32s2_franzininho/Kconfig.defconfig @@ -10,6 +10,7 @@ config BOARD config ENTROPY_GENERATOR default y -config HEAP_MEM_POOL_SIZE +config HEAP_MEM_POOL_ADD_SIZE_BOARD + int default 98304 if WIFI default 4096 diff --git a/boards/xtensa/esp32s2_lolin_mini/Kconfig.defconfig b/boards/xtensa/esp32s2_lolin_mini/Kconfig.defconfig index 7724f8c90a1..709b0d5b53b 100644 --- a/boards/xtensa/esp32s2_lolin_mini/Kconfig.defconfig +++ b/boards/xtensa/esp32s2_lolin_mini/Kconfig.defconfig @@ -10,6 +10,7 @@ config BOARD config ENTROPY_GENERATOR default y -config HEAP_MEM_POOL_SIZE +config HEAP_MEM_POOL_ADD_SIZE_BOARD + int default 32768 if WIFI default 4096 diff --git a/boards/xtensa/esp32s2_saola/Kconfig.defconfig b/boards/xtensa/esp32s2_saola/Kconfig.defconfig index 077b2bde4ac..8b160c02935 100644 --- a/boards/xtensa/esp32s2_saola/Kconfig.defconfig +++ b/boards/xtensa/esp32s2_saola/Kconfig.defconfig @@ -10,6 +10,7 @@ config BOARD config ENTROPY_GENERATOR default y -config HEAP_MEM_POOL_SIZE +config HEAP_MEM_POOL_ADD_SIZE_BOARD + int default 32768 if WIFI default 4096 diff --git a/boards/xtensa/esp32s3_devkitm/Kconfig.defconfig b/boards/xtensa/esp32s3_devkitm/Kconfig.defconfig index cb102b4ee64..87c980194e2 100644 --- a/boards/xtensa/esp32s3_devkitm/Kconfig.defconfig +++ b/boards/xtensa/esp32s3_devkitm/Kconfig.defconfig @@ -8,7 +8,8 @@ if BOARD_ESP32S3_DEVKITM config BOARD default "esp32s3_devkitm" -config HEAP_MEM_POOL_SIZE +config HEAP_MEM_POOL_ADD_SIZE_BOARD + int default 98304 if WIFI default 40960 if BT default 4096 @@ -24,8 +25,8 @@ if BOARD_ESP32S3_DEVKITM_APPCPU config BOARD default "esp32s3_devkitm_appcpu" -config HEAP_MEM_POOL_SIZE - default 4096 +config HEAP_MEM_POOL_ADD_SIZE_BOARD + def_int 4096 config KERNEL_BIN_NAME default "esp32_net_firmware" diff --git a/boards/xtensa/esp32s3_luatos_core/Kconfig.defconfig b/boards/xtensa/esp32s3_luatos_core/Kconfig.defconfig index 88744adac06..e5b99a7818a 100644 --- a/boards/xtensa/esp32s3_luatos_core/Kconfig.defconfig +++ b/boards/xtensa/esp32s3_luatos_core/Kconfig.defconfig @@ -10,7 +10,8 @@ config BOARD config ENTROPY_GENERATOR default y -config HEAP_MEM_POOL_SIZE +config HEAP_MEM_POOL_ADD_SIZE_BOARD + int default 98304 if WIFI default 40960 if BT default 4096 diff --git a/boards/xtensa/esp_wrover_kit/Kconfig.defconfig b/boards/xtensa/esp_wrover_kit/Kconfig.defconfig index 65efe16093d..02ef06aba61 100644 --- a/boards/xtensa/esp_wrover_kit/Kconfig.defconfig +++ b/boards/xtensa/esp_wrover_kit/Kconfig.defconfig @@ -7,7 +7,8 @@ config BOARD default "esp_wrover_kit" depends on BOARD_ESP_WROVER_KIT -config HEAP_MEM_POOL_SIZE +config HEAP_MEM_POOL_ADD_SIZE_BOARD + int default 98304 if WIFI default 40960 if BT default 4096 diff --git a/boards/xtensa/heltec_wifi_lora32_v2/Kconfig.defconfig b/boards/xtensa/heltec_wifi_lora32_v2/Kconfig.defconfig index d8e0ba31dba..79349187103 100644 --- a/boards/xtensa/heltec_wifi_lora32_v2/Kconfig.defconfig +++ b/boards/xtensa/heltec_wifi_lora32_v2/Kconfig.defconfig @@ -10,7 +10,8 @@ config BOARD config ENTROPY_GENERATOR default y -config HEAP_MEM_POOL_SIZE +config HEAP_MEM_POOL_ADD_SIZE_BOARD + int default 98304 if WIFI default 40960 if BT default 4096 diff --git a/boards/xtensa/heltec_wireless_stick_lite_v3/Kconfig.defconfig b/boards/xtensa/heltec_wireless_stick_lite_v3/Kconfig.defconfig index ce6459f509e..d5cdd956f81 100644 --- a/boards/xtensa/heltec_wireless_stick_lite_v3/Kconfig.defconfig +++ b/boards/xtensa/heltec_wireless_stick_lite_v3/Kconfig.defconfig @@ -11,7 +11,8 @@ config BOARD config ENTROPY_GENERATOR default y -config HEAP_MEM_POOL_SIZE +config HEAP_MEM_POOL_ADD_SIZE_BOARD + int default 98304 if WIFI default 40960 if BT default 4096 diff --git a/boards/xtensa/m5stack_atoms3/Kconfig.defconfig b/boards/xtensa/m5stack_atoms3/Kconfig.defconfig index b9bd2641458..2ae18530839 100644 --- a/boards/xtensa/m5stack_atoms3/Kconfig.defconfig +++ b/boards/xtensa/m5stack_atoms3/Kconfig.defconfig @@ -11,7 +11,8 @@ config BOARD config ENTROPY_GENERATOR default y -config HEAP_MEM_POOL_SIZE +config HEAP_MEM_POOL_ADD_SIZE_BOARD + int default 98304 if WIFI default 65536 if BT default 4096 diff --git a/boards/xtensa/m5stack_core2/Kconfig.defconfig b/boards/xtensa/m5stack_core2/Kconfig.defconfig index 08fc712b0d3..388bc5c027c 100644 --- a/boards/xtensa/m5stack_core2/Kconfig.defconfig +++ b/boards/xtensa/m5stack_core2/Kconfig.defconfig @@ -12,7 +12,8 @@ config BOARD config ENTROPY_GENERATOR default y -config HEAP_MEM_POOL_SIZE +config HEAP_MEM_POOL_ADD_SIZE_BOARD + int default 98304 if WIFI default 65536 if BT default 4096 diff --git a/boards/xtensa/m5stickc_plus/Kconfig.defconfig b/boards/xtensa/m5stickc_plus/Kconfig.defconfig index 2fdc31f4008..20bb58c5872 100644 --- a/boards/xtensa/m5stickc_plus/Kconfig.defconfig +++ b/boards/xtensa/m5stickc_plus/Kconfig.defconfig @@ -10,7 +10,8 @@ config BOARD config ENTROPY_GENERATOR default y -config HEAP_MEM_POOL_SIZE +config HEAP_MEM_POOL_ADD_SIZE_BOARD + int default 98304 if WIFI default 40960 if BT default 4096 diff --git a/boards/xtensa/odroid_go/Kconfig.defconfig b/boards/xtensa/odroid_go/Kconfig.defconfig index 7193624673e..049138994e5 100644 --- a/boards/xtensa/odroid_go/Kconfig.defconfig +++ b/boards/xtensa/odroid_go/Kconfig.defconfig @@ -16,7 +16,8 @@ config SPI config ENTROPY_GENERATOR default y -config HEAP_MEM_POOL_SIZE +config HEAP_MEM_POOL_ADD_SIZE_BOARD + int default 98304 if WIFI default 40960 if BT default 4096 diff --git a/boards/xtensa/olimex_esp32_evb/Kconfig.defconfig b/boards/xtensa/olimex_esp32_evb/Kconfig.defconfig index 8e788f6a393..34808e57c67 100644 --- a/boards/xtensa/olimex_esp32_evb/Kconfig.defconfig +++ b/boards/xtensa/olimex_esp32_evb/Kconfig.defconfig @@ -11,7 +11,8 @@ config BOARD config ENTROPY_GENERATOR default y -config HEAP_MEM_POOL_SIZE +config HEAP_MEM_POOL_ADD_SIZE_BOARD + int default 98304 if WIFI default 40960 if BT default 4096 diff --git a/boards/xtensa/xiao_esp32s3/Kconfig.defconfig b/boards/xtensa/xiao_esp32s3/Kconfig.defconfig index 4a1b168cf54..123fff98e82 100644 --- a/boards/xtensa/xiao_esp32s3/Kconfig.defconfig +++ b/boards/xtensa/xiao_esp32s3/Kconfig.defconfig @@ -8,7 +8,8 @@ config BOARD config ENTROPY_GENERATOR default y -config HEAP_MEM_POOL_SIZE +config HEAP_MEM_POOL_ADD_SIZE_BOARD + int default 98304 if WIFI default 40960 if BT default 4096 diff --git a/boards/xtensa/yd_esp32/Kconfig.defconfig b/boards/xtensa/yd_esp32/Kconfig.defconfig index ebb60766eb9..7a2b83553f4 100644 --- a/boards/xtensa/yd_esp32/Kconfig.defconfig +++ b/boards/xtensa/yd_esp32/Kconfig.defconfig @@ -10,7 +10,8 @@ config BOARD config ENTROPY_GENERATOR default y -config HEAP_MEM_POOL_SIZE +config HEAP_MEM_POOL_ADD_SIZE_BOARD + int default 98304 if WIFI default 40960 if BT default 4096 From 95b1d586b9ef859eec4c345225a6aae569f887fc Mon Sep 17 00:00:00 2001 From: Johan Hedberg Date: Wed, 29 Nov 2023 11:45:22 +0200 Subject: [PATCH 1441/3723] soc: arm: Use HEAP_MEM_POOL_ADD_SIZE KConfig options Kconfig options with a HEAP_MEM_POOL_ADD_SIZE_ prefix should be used to set the minimum required system heap size. This helps prevent applications from creating a non-working image by trying to set a too small value. Signed-off-by: Johan Hedberg --- soc/arm/atmel_sam0/common/Kconfig.defconfig.series | 4 ++-- .../nordic_nrf/nrf53/Kconfig.defconfig.nrf5340_CPUAPP_QKAA | 5 +++-- .../nordic_nrf/nrf53/Kconfig.defconfig.nrf5340_CPUNET_QKAA | 5 +++-- 3 files changed, 8 insertions(+), 6 deletions(-) diff --git a/soc/arm/atmel_sam0/common/Kconfig.defconfig.series b/soc/arm/atmel_sam0/common/Kconfig.defconfig.series index ef6e1e0ff83..8d9068424fd 100644 --- a/soc/arm/atmel_sam0/common/Kconfig.defconfig.series +++ b/soc/arm/atmel_sam0/common/Kconfig.defconfig.series @@ -10,8 +10,8 @@ config HWINFO_SAM0 if USB_DEVICE_DRIVER -config HEAP_MEM_POOL_SIZE - default 1024 +config HEAP_MEM_POOL_ADD_SIZE_SOC + def_int 1024 endif # USB_DEVICE_DRIVER diff --git a/soc/arm/nordic_nrf/nrf53/Kconfig.defconfig.nrf5340_CPUAPP_QKAA b/soc/arm/nordic_nrf/nrf53/Kconfig.defconfig.nrf5340_CPUAPP_QKAA index 0c0f9f05926..f0f7f5a7d84 100644 --- a/soc/arm/nordic_nrf/nrf53/Kconfig.defconfig.nrf5340_CPUAPP_QKAA +++ b/soc/arm/nordic_nrf/nrf53/Kconfig.defconfig.nrf5340_CPUAPP_QKAA @@ -14,8 +14,9 @@ config NUM_IRQS config IEEE802154_NRF5 default IEEE802154 -config HEAP_MEM_POOL_SIZE - default 4096 if NRF_802154_SER_HOST +config HEAP_MEM_POOL_ADD_SIZE_SOC + def_int 4096 + depends on NRF_802154_SER_HOST if IPC_SERVICE_BACKEND_RPMSG diff --git a/soc/arm/nordic_nrf/nrf53/Kconfig.defconfig.nrf5340_CPUNET_QKAA b/soc/arm/nordic_nrf/nrf53/Kconfig.defconfig.nrf5340_CPUNET_QKAA index 88d53a3a0f7..0c60adc04f3 100644 --- a/soc/arm/nordic_nrf/nrf53/Kconfig.defconfig.nrf5340_CPUNET_QKAA +++ b/soc/arm/nordic_nrf/nrf53/Kconfig.defconfig.nrf5340_CPUNET_QKAA @@ -15,8 +15,9 @@ config IEEE802154_NRF5 default y depends on IEEE802154 -config HEAP_MEM_POOL_SIZE - default 4096 if NRF_802154_SER_RADIO +config HEAP_MEM_POOL_ADD_SIZE_SOC + def_int 4096 + depends on NRF_802154_SER_RADIO config LOG_DOMAIN_NAME default "net" From ec23622b07cdd16e38a98f17ca92a2a41a7087df Mon Sep 17 00:00:00 2001 From: Johan Hedberg Date: Wed, 29 Nov 2023 11:46:27 +0200 Subject: [PATCH 1442/3723] soc: xtensa: Use HEAP_MEM_POOL_ADD_SIZE KConfig options Kconfig options with a HEAP_MEM_POOL_ADD_SIZE_ prefix should be used to set the minimum required system heap size. This helps prevent applications from creating a non-working image by trying to set a too small value. Signed-off-by: Johan Hedberg --- soc/xtensa/espressif_esp32/esp32s2/Kconfig.defconfig.series | 4 ++-- soc/xtensa/espressif_esp32/esp32s3/Kconfig.defconfig.series | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/soc/xtensa/espressif_esp32/esp32s2/Kconfig.defconfig.series b/soc/xtensa/espressif_esp32/esp32s2/Kconfig.defconfig.series index c1618783ae5..f3abfd5f017 100644 --- a/soc/xtensa/espressif_esp32/esp32s2/Kconfig.defconfig.series +++ b/soc/xtensa/espressif_esp32/esp32s2/Kconfig.defconfig.series @@ -18,8 +18,8 @@ config MP_MAX_NUM_CPUS config ISR_STACK_SIZE default 2048 -config HEAP_MEM_POOL_SIZE - default 32768 +config HEAP_MEM_POOL_ADD_SIZE_SOC + def_int 32768 config ESPTOOLPY_FLASHFREQ_80M default y diff --git a/soc/xtensa/espressif_esp32/esp32s3/Kconfig.defconfig.series b/soc/xtensa/espressif_esp32/esp32s3/Kconfig.defconfig.series index 31f7bdbff50..99de5f6661d 100644 --- a/soc/xtensa/espressif_esp32/esp32s3/Kconfig.defconfig.series +++ b/soc/xtensa/espressif_esp32/esp32s3/Kconfig.defconfig.series @@ -6,8 +6,8 @@ if SOC_SERIES_ESP32S3 config SOC_SERIES default "esp32s3" -config HEAP_MEM_POOL_SIZE - default 32768 +config HEAP_MEM_POOL_ADD_SIZE_SOC + def_int 32768 config MINIMAL_LIBC_OPTIMIZE_STRING_FOR_SIZE default n From 7bb16c779b537c01409e80f3364c928a04aa5577 Mon Sep 17 00:00:00 2001 From: Johan Hedberg Date: Fri, 8 Dec 2023 12:16:32 +0200 Subject: [PATCH 1443/3723] posix: mqueue: Remove custom default for HEAP_MEM_POOL_SIZE Use the new HEAP_MEM_POOL_ADD_SIZE_ prefix to construct a minimum requirement for posix message queue usage. This way we can remove the "special case" default values from the HEAP_MEM_POOL_SIZE Kconfig definition. Signed-off-by: Johan Hedberg --- kernel/Kconfig | 3 +-- lib/posix/Kconfig.mqueue | 3 +++ 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/kernel/Kconfig b/kernel/Kconfig index 3b916aba062..a01f40551e1 100644 --- a/kernel/Kconfig +++ b/kernel/Kconfig @@ -835,8 +835,7 @@ if KERNEL_MEM_POOL config HEAP_MEM_POOL_SIZE int "Heap memory pool size (in bytes)" - default 0 if !POSIX_MQUEUE - default 1024 if POSIX_MQUEUE + default 0 help This option specifies the size of the heap memory pool used when dynamically allocating memory using k_malloc(). The maximum size of diff --git a/lib/posix/Kconfig.mqueue b/lib/posix/Kconfig.mqueue index 58e04d21faf..7c49aee6c21 100644 --- a/lib/posix/Kconfig.mqueue +++ b/lib/posix/Kconfig.mqueue @@ -30,4 +30,7 @@ config MQUEUE_NAMELEN_MAX help Mention length of message queue name in number of characters. +config HEAP_MEM_POOL_ADD_SIZE_MQUEUE + def_int 1024 + endif From 3bd364d3925b7464dd7aac9b1c5843148c6d2740 Mon Sep 17 00:00:00 2001 From: Johan Hedberg Date: Fri, 8 Dec 2023 15:13:26 +0200 Subject: [PATCH 1444/3723] manifest: Update espressif revision to support system heap changes This is needed so that module uses K_HEAP_MEM_POOL_SIZE for determining the availablility of the k_malloc family of functions. Signed-off-by: Johan Hedberg --- west.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/west.yml b/west.yml index d3b7591f372..495158a55d5 100644 --- a/west.yml +++ b/west.yml @@ -152,7 +152,7 @@ manifest: groups: - hal - name: hal_espressif - revision: eb7e415dc115e57afe96f552493b19d49dfc8c0e + revision: b6d2ea66a0047204ffc5ec8725ec45a671ab397b path: modules/hal/espressif west-commands: west/west-commands.yml groups: From 12b5adf3e87999eb7a74882799bd42f132a9b3f1 Mon Sep 17 00:00:00 2001 From: Johan Hedberg Date: Fri, 8 Dec 2023 15:45:53 +0200 Subject: [PATCH 1445/3723] manifest: Update libmetal revision to support system heap changes This is needed so that module uses K_HEAP_MEM_POOL_SIZE for determining the availablility of the k_malloc family of functions. Signed-off-by: Johan Hedberg --- west.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/west.yml b/west.yml index 495158a55d5..e6a68c8934e 100644 --- a/west.yml +++ b/west.yml @@ -258,7 +258,7 @@ manifest: path: modules/lib/hostap revision: 7adaff26baa48e26a32c576125e0a749a5239b12 - name: libmetal - revision: cebd92d15c9759a9d49d508869081def927af4f0 + revision: 243eed541b9c211a2ce8841c788e62ddce84425e path: modules/hal/libmetal groups: - hal From d8cc04f59649d25c05f71813a80d766c117af27b Mon Sep 17 00:00:00 2001 From: Johan Hedberg Date: Tue, 12 Dec 2023 21:00:44 +0200 Subject: [PATCH 1446/3723] doc: migration-guide-3.6: Add a note about system heap size changes Add a note about the new K_MEM_POOL_HEAP_SIZE define and the mechanism for specifying custom system heap size requirements. Signed-off-by: Johan Hedberg --- doc/releases/migration-guide-3.6.rst | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/doc/releases/migration-guide-3.6.rst b/doc/releases/migration-guide-3.6.rst index b2bf8ed6837..434bc9368c5 100644 --- a/doc/releases/migration-guide-3.6.rst +++ b/doc/releases/migration-guide-3.6.rst @@ -29,6 +29,15 @@ Build System Kernel ====== +* The system heap size and its availability is now determined by a ``K_HEAP_MEM_POOL_SIZE`` + define instead of the :kconfig:option:`CONFIG_HEAP_MEM_POOL_SIZE` Kconfig option. Subsystems + can specify their own custom system heap size requirements by specifying Kconfig options with + the prefix ``CONFIG_HEAP_MEM_POOL_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_HEAP_MEM_POOL_IGNORE_MIN` option has been introduced (which defaults + being disabled). + C Library ========= From 9aba4e8f3dc25da244685b5b5fcce48bf97cb6d8 Mon Sep 17 00:00:00 2001 From: Robert Lubos Date: Thu, 9 Nov 2023 14:58:09 +0100 Subject: [PATCH 1447/3723] net: sockets: tls: Read the actual error on interrupted wait In case a waiting TLS socket reports an error in the underlying poll call, try to read the actual error from the socket, instead of blindly returning -EIO in all cases. Signed-off-by: Robert Lubos --- subsys/net/lib/sockets/sockets_tls.c | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/subsys/net/lib/sockets/sockets_tls.c b/subsys/net/lib/sockets/sockets_tls.c index c83d2c18b80..ba490d325a9 100644 --- a/subsys/net/lib/sockets/sockets_tls.c +++ b/subsys/net/lib/sockets/sockets_tls.c @@ -741,6 +741,14 @@ static int wait(int sock, int timeout, int event) } if (fds.revents & ZSOCK_POLLERR) { + int optval; + socklen_t optlen = sizeof(optval); + + if (zsock_getsockopt(fds.fd, SOL_SOCKET, SO_ERROR, + &optval, &optlen) == 0) { + return -optval; + } + return -EIO; } } From 833d565c36125c1140a22375f2f3193b78370a27 Mon Sep 17 00:00:00 2001 From: Robert Lubos Date: Wed, 8 Nov 2023 15:14:23 +0100 Subject: [PATCH 1448/3723] tests: net: socket: tls: Remove unnecessary delay from test cases SO_TYPE and SO_PROTOCOL test cases does not really establish connection, so teardown delay at the end is not needed. Signed-off-by: Robert Lubos --- tests/net/socket/tls/src/main.c | 2 -- 1 file changed, 2 deletions(-) diff --git a/tests/net/socket/tls/src/main.c b/tests/net/socket/tls/src/main.c index 0a4dab9f1f0..6a42062d2f7 100644 --- a/tests/net/socket/tls/src/main.c +++ b/tests/net/socket/tls/src/main.c @@ -179,7 +179,6 @@ ZTEST(net_socket_tls, test_so_type) test_close(sock1); test_close(sock2); - k_sleep(TCP_TEARDOWN_TIMEOUT); } ZTEST(net_socket_tls, test_so_protocol) @@ -207,7 +206,6 @@ ZTEST(net_socket_tls, test_so_protocol) test_close(sock1); test_close(sock2); - k_sleep(TCP_TEARDOWN_TIMEOUT); } struct test_msg_waitall_data { From be4400e80db90abd3f0288c64b82f7cfed44d006 Mon Sep 17 00:00:00 2001 From: Robert Lubos Date: Wed, 8 Nov 2023 15:58:16 +0100 Subject: [PATCH 1449/3723] tests: net: socket: tls: Add helper for TLS connection establishment Move the code responsible for TLS connection establishment to a helper function, as it'll be needed as well in other test cases. Signed-off-by: Robert Lubos --- tests/net/socket/tls/prj.conf | 3 ++ tests/net/socket/tls/src/main.c | 84 ++++++++++++++++++--------------- 2 files changed, 50 insertions(+), 37 deletions(-) diff --git a/tests/net/socket/tls/prj.conf b/tests/net/socket/tls/prj.conf index d67e0a2d5f8..59391863cc5 100644 --- a/tests/net/socket/tls/prj.conf +++ b/tests/net/socket/tls/prj.conf @@ -19,6 +19,9 @@ CONFIG_NET_SOCKETS_TLS_MAX_CONTEXTS=4 CONFIG_NET_CONTEXT_RCVTIMEO=y CONFIG_POSIX_MAX_FDS=20 +# Keep time wait delay short for the test +CONFIG_NET_TCP_TIME_WAIT_DELAY=10 + # Network driver config CONFIG_NET_DRIVERS=y CONFIG_NET_LOOPBACK=y diff --git a/tests/net/socket/tls/src/main.c b/tests/net/socket/tls/src/main.c index 6a42062d2f7..31a29923146 100644 --- a/tests/net/socket/tls/src/main.c +++ b/tests/net/socket/tls/src/main.c @@ -26,7 +26,7 @@ LOG_MODULE_REGISTER(net_test, CONFIG_NET_SOCKETS_LOG_LEVEL); #define MAX_CONNS 5 -#define TCP_TEARDOWN_TIMEOUT K_SECONDS(1) +#define TCP_TEARDOWN_TIMEOUT K_MSEC(CONFIG_NET_TCP_TIME_WAIT_DELAY) static const unsigned char psk[] = { 0x01, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, @@ -230,6 +230,46 @@ static void test_msg_waitall_tx_work_handler(struct k_work *work) } } +static void test_prepare_tls_connection(sa_family_t family, int *c_sock, + int *s_sock, int *new_sock) +{ + struct sockaddr c_saddr; + struct sockaddr s_saddr; + socklen_t exp_addrlen = family == AF_INET6 ? + sizeof(struct sockaddr_in6) : + sizeof(struct sockaddr_in); + struct sockaddr addr; + socklen_t addrlen = sizeof(addr); + + if (family == AF_INET6) { + prepare_sock_tls_v6(MY_IPV6_ADDR, ANY_PORT, c_sock, + (struct sockaddr_in6 *)&c_saddr, + IPPROTO_TLS_1_2); + prepare_sock_tls_v6(MY_IPV6_ADDR, ANY_PORT, s_sock, + (struct sockaddr_in6 *)&s_saddr, + IPPROTO_TLS_1_2); + } else { + prepare_sock_tls_v4(MY_IPV4_ADDR, ANY_PORT, c_sock, + (struct sockaddr_in *)&c_saddr, + IPPROTO_TLS_1_2); + prepare_sock_tls_v4(MY_IPV4_ADDR, ANY_PORT, s_sock, + (struct sockaddr_in *)&s_saddr, + IPPROTO_TLS_1_2); + } + + test_config_psk(*s_sock, *c_sock); + + test_bind(*s_sock, &s_saddr, exp_addrlen); + test_listen(*s_sock); + + spawn_client_connect_thread(*c_sock, &s_saddr); + + test_accept(*s_sock, new_sock, &addr, &addrlen); + zassert_equal(addrlen, exp_addrlen, "Wrong addrlen"); + + k_thread_join(&client_connect_thread, K_FOREVER); +} + ZTEST(net_socket_tls, test_v4_msg_waitall) { struct test_msg_waitall_data test_data = { @@ -238,10 +278,6 @@ ZTEST(net_socket_tls, test_v4_msg_waitall) int c_sock; int s_sock; int new_sock; - struct sockaddr_in c_saddr; - struct sockaddr_in s_saddr; - struct sockaddr addr; - socklen_t addrlen = sizeof(addr); int ret; uint8_t rx_buf[sizeof(TEST_STR_SMALL) - 1] = { 0 }; struct timeval timeo_optval = { @@ -249,20 +285,7 @@ ZTEST(net_socket_tls, test_v4_msg_waitall) .tv_usec = 500000, }; - prepare_sock_tls_v4(MY_IPV4_ADDR, ANY_PORT, &c_sock, &c_saddr, IPPROTO_TLS_1_2); - prepare_sock_tls_v4(MY_IPV4_ADDR, ANY_PORT, &s_sock, &s_saddr, IPPROTO_TLS_1_2); - - test_config_psk(s_sock, c_sock); - - test_bind(s_sock, (struct sockaddr *)&s_saddr, sizeof(s_saddr)); - test_listen(s_sock); - - spawn_client_connect_thread(c_sock, (struct sockaddr *)&s_saddr); - - test_accept(s_sock, &new_sock, &addr, &addrlen); - zassert_equal(addrlen, sizeof(struct sockaddr_in), "Wrong addrlen"); - - k_thread_join(&client_connect_thread, K_FOREVER); + test_prepare_tls_connection(AF_INET, &c_sock, &s_sock, &new_sock); /* Regular MSG_WAITALL - make sure recv returns only after * requested amount is received. @@ -304,6 +327,8 @@ ZTEST(net_socket_tls, test_v4_msg_waitall) test_close(new_sock); test_close(s_sock); test_close(c_sock); + + k_sleep(TCP_TEARDOWN_TIMEOUT); } ZTEST(net_socket_tls, test_v6_msg_waitall) @@ -314,10 +339,6 @@ ZTEST(net_socket_tls, test_v6_msg_waitall) int c_sock; int s_sock; int new_sock; - struct sockaddr_in6 c_saddr; - struct sockaddr_in6 s_saddr; - struct sockaddr addr; - socklen_t addrlen = sizeof(addr); int ret; uint8_t rx_buf[sizeof(TEST_STR_SMALL) - 1] = { 0 }; struct timeval timeo_optval = { @@ -325,20 +346,7 @@ ZTEST(net_socket_tls, test_v6_msg_waitall) .tv_usec = 500000, }; - prepare_sock_tls_v6(MY_IPV6_ADDR, ANY_PORT, &c_sock, &c_saddr, IPPROTO_TLS_1_2); - prepare_sock_tls_v6(MY_IPV6_ADDR, ANY_PORT, &s_sock, &s_saddr, IPPROTO_TLS_1_2); - - test_config_psk(s_sock, c_sock); - - test_bind(s_sock, (struct sockaddr *)&s_saddr, sizeof(s_saddr)); - test_listen(s_sock); - - spawn_client_connect_thread(c_sock, (struct sockaddr *)&s_saddr); - - test_accept(s_sock, &new_sock, &addr, &addrlen); - zassert_equal(addrlen, sizeof(struct sockaddr_in6), "Wrong addrlen"); - - k_thread_join(&client_connect_thread, K_FOREVER); + test_prepare_tls_connection(AF_INET6, &c_sock, &s_sock, &new_sock); /* Regular MSG_WAITALL - make sure recv returns only after * requested amount is received. @@ -380,6 +388,8 @@ ZTEST(net_socket_tls, test_v6_msg_waitall) test_close(new_sock); test_close(s_sock); test_close(c_sock); + + k_sleep(TCP_TEARDOWN_TIMEOUT); } struct test_msg_trunc_data { From a416553dba7cac1fc9c3a70827eba4a5bd34952d Mon Sep 17 00:00:00 2001 From: Robert Lubos Date: Wed, 8 Nov 2023 16:52:18 +0100 Subject: [PATCH 1450/3723] tests: net: socket: tls: Add more tests covering socket behaviors A first batch of tests for TLS sockets, covering expected socket behaviors: * Verify that blocking/non-blocking tx/rx work as expected * Verify that timeouts on tx/rx are calculated properly * Verify proper behaviors when interacting with a socket from different threads (close/shutodown/send). Signed-off-by: Robert Lubos --- tests/net/socket/tls/prj.conf | 7 +- tests/net/socket/tls/src/main.c | 805 ++++++++++++++++++++++++++++++-- 2 files changed, 766 insertions(+), 46 deletions(-) diff --git a/tests/net/socket/tls/prj.conf b/tests/net/socket/tls/prj.conf index 59391863cc5..6a49c5094e6 100644 --- a/tests/net/socket/tls/prj.conf +++ b/tests/net/socket/tls/prj.conf @@ -17,18 +17,21 @@ CONFIG_NET_SOCKETS_SOCKOPT_TLS=y CONFIG_NET_SOCKETS_ENABLE_DTLS=y CONFIG_NET_SOCKETS_TLS_MAX_CONTEXTS=4 CONFIG_NET_CONTEXT_RCVTIMEO=y +CONFIG_NET_CONTEXT_SNDTIMEO=y +CONFIG_NET_CONTEXT_RCVBUF=y CONFIG_POSIX_MAX_FDS=20 -# Keep time wait delay short for the test +# Keep timings short for the test CONFIG_NET_TCP_TIME_WAIT_DELAY=10 +CONFIG_NET_SOCKETS_CONNECT_TIMEOUT=100 # Network driver config CONFIG_NET_DRIVERS=y CONFIG_NET_LOOPBACK=y +CONFIG_NET_LOOPBACK_SIMULATE_PACKET_DROP=y CONFIG_TEST_RANDOM_GENERATOR=y CONFIG_MAIN_STACK_SIZE=2048 -CONFIG_SYSTEM_WORKQUEUE_STACK_SIZE=3072 CONFIG_TEST_USERSPACE=y # The test requires lot of bufs diff --git a/tests/net/socket/tls/src/main.c b/tests/net/socket/tls/src/main.c index 31a29923146..7467f33b059 100644 --- a/tests/net/socket/tls/src/main.c +++ b/tests/net/socket/tls/src/main.c @@ -9,6 +9,7 @@ LOG_MODULE_REGISTER(net_test, CONFIG_NET_SOCKETS_LOG_LEVEL); #include #include +#include #include #include @@ -28,6 +29,24 @@ LOG_MODULE_REGISTER(net_test, CONFIG_NET_SOCKETS_LOG_LEVEL); #define TCP_TEARDOWN_TIMEOUT K_MSEC(CONFIG_NET_TCP_TIME_WAIT_DELAY) +#define TLS_TEST_WORK_QUEUE_STACK_SIZE 3072 + +K_THREAD_STACK_DEFINE(tls_test_work_queue_stack, TLS_TEST_WORK_QUEUE_STACK_SIZE); +static struct k_work_q tls_test_work_queue; + +static void test_work_reschedule(struct k_work_delayable *dwork, + k_timeout_t delay) +{ + k_work_reschedule_for_queue(&tls_test_work_queue, dwork, delay); +} + +static void test_work_wait(struct k_work_delayable *dwork) +{ + struct k_work_sync sync; + + k_work_cancel_delayable_sync(dwork, &sync); +} + static const unsigned char psk[] = { 0x01, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f @@ -63,6 +82,11 @@ static void test_config_psk(int s_sock, int c_sock) } } +static void test_fcntl(int sock, int cmd, int val) +{ + zassert_equal(fcntl(sock, cmd, val), 0, "fcntl failed"); +} + static void test_bind(int sock, struct sockaddr *addr, socklen_t addrlen) { zassert_equal(bind(sock, addr, addrlen), @@ -122,6 +146,13 @@ static void test_accept(int sock, int *new_sock, struct sockaddr *addr, zassert_true(*new_sock >= 0, "accept failed"); } +static void test_shutdown(int sock, int how) +{ + zassert_equal(shutdown(sock, how), + 0, + "shutdown failed"); +} + static void test_close(int sock) { zassert_equal(close(sock), @@ -129,31 +160,23 @@ static void test_close(int sock) "close failed"); } -#define CLIENT_CONNECT_STACK_SIZE 2048 - -/* Helper thread for the connect operation - need to handle client/server in - * parallell due to handshake. - */ -struct k_thread client_connect_thread; -K_THREAD_STACK_DEFINE(client_connect_stack, CLIENT_CONNECT_STACK_SIZE); - -static void client_connect_entry(void *p1, void *p2, void *p3) +static void test_eof(int sock) { - int sock = POINTER_TO_INT(p1); - struct sockaddr *addr = p2; + char rx_buf[1]; + ssize_t recved; - test_connect(sock, addr, addr->sa_family == AF_INET ? - sizeof(struct sockaddr_in) : sizeof(struct sockaddr_in6)); -} + /* Test that EOF properly detected. */ + recved = recv(sock, rx_buf, sizeof(rx_buf), 0); + zassert_equal(recved, 0, ""); -static void spawn_client_connect_thread(int sock, struct sockaddr *addr) -{ - k_thread_create(&client_connect_thread, client_connect_stack, - K_THREAD_STACK_SIZEOF(client_connect_stack), - client_connect_entry, INT_TO_POINTER(sock), addr, NULL, - K_LOWEST_APPLICATION_THREAD_PRIO, 0, K_NO_WAIT); + /* Calling again should be OK. */ + recved = recv(sock, rx_buf, sizeof(rx_buf), 0); + zassert_equal(recved, 0, ""); - k_thread_start(&client_connect_thread); + /* Calling when TCP connection is fully torn down should be still OK. */ + k_sleep(TCP_TEARDOWN_TIMEOUT); + recved = recv(sock, rx_buf, sizeof(rx_buf), 0); + zassert_equal(recved, 0, ""); } ZTEST(net_socket_tls, test_so_type) @@ -226,10 +249,26 @@ static void test_msg_waitall_tx_work_handler(struct k_work *work) test_send(test_data->sock, test_data->data + test_data->offset, 1, 0); test_data->offset++; test_data->retries--; - k_work_reschedule(&test_data->tx_work, K_MSEC(10)); + test_work_reschedule(&test_data->tx_work, K_MSEC(10)); } } +struct connect_data { + struct k_work_delayable work; + int sock; + struct sockaddr *addr; +}; + +static void client_connect_work_handler(struct k_work *work) +{ + struct k_work_delayable *dwork = k_work_delayable_from_work(work); + struct connect_data *data = + CONTAINER_OF(dwork, struct connect_data, work); + + test_connect(data->sock, data->addr, data->addr->sa_family == AF_INET ? + sizeof(struct sockaddr_in) : sizeof(struct sockaddr_in6)); +} + static void test_prepare_tls_connection(sa_family_t family, int *c_sock, int *s_sock, int *new_sock) { @@ -240,6 +279,7 @@ static void test_prepare_tls_connection(sa_family_t family, int *c_sock, sizeof(struct sockaddr_in); struct sockaddr addr; socklen_t addrlen = sizeof(addr); + struct connect_data test_data; if (family == AF_INET6) { prepare_sock_tls_v6(MY_IPV6_ADDR, ANY_PORT, c_sock, @@ -262,12 +302,18 @@ static void test_prepare_tls_connection(sa_family_t family, int *c_sock, test_bind(*s_sock, &s_saddr, exp_addrlen); test_listen(*s_sock); - spawn_client_connect_thread(*c_sock, &s_saddr); + /* Helper work for the connect operation - need to handle client/server + * in parallel due to handshake. + */ + test_data.sock = *c_sock; + test_data.addr = &s_saddr; + k_work_init_delayable(&test_data.work, client_connect_work_handler); + test_work_reschedule(&test_data.work, K_NO_WAIT); test_accept(*s_sock, new_sock, &addr, &addrlen); zassert_equal(addrlen, exp_addrlen, "Wrong addrlen"); - k_thread_join(&client_connect_thread, K_FOREVER); + test_work_wait(&test_data.work); } ZTEST(net_socket_tls, test_v4_msg_waitall) @@ -295,13 +341,13 @@ ZTEST(net_socket_tls, test_v4_msg_waitall) test_data.sock = c_sock; k_work_init_delayable(&test_data.tx_work, test_msg_waitall_tx_work_handler); - k_work_reschedule(&test_data.tx_work, K_MSEC(10)); + test_work_reschedule(&test_data.tx_work, K_MSEC(10)); ret = recv(new_sock, rx_buf, sizeof(rx_buf), MSG_WAITALL); zassert_equal(ret, sizeof(rx_buf), "Invalid length received"); zassert_mem_equal(rx_buf, TEST_STR_SMALL, sizeof(rx_buf), "Invalid data received"); - k_work_cancel_delayable(&test_data.tx_work); + test_work_wait(&test_data.tx_work); /* MSG_WAITALL + SO_RCVTIMEO - make sure recv returns the amount of data * received so far @@ -316,13 +362,13 @@ ZTEST(net_socket_tls, test_v4_msg_waitall) test_data.sock = c_sock; k_work_init_delayable(&test_data.tx_work, test_msg_waitall_tx_work_handler); - k_work_reschedule(&test_data.tx_work, K_MSEC(10)); + test_work_reschedule(&test_data.tx_work, K_MSEC(10)); ret = recv(new_sock, rx_buf, sizeof(rx_buf) - 1, MSG_WAITALL); zassert_equal(ret, sizeof(rx_buf) - 1, "Invalid length received"); zassert_mem_equal(rx_buf, TEST_STR_SMALL, sizeof(rx_buf) - 1, "Invalid data received"); - k_work_cancel_delayable(&test_data.tx_work); + test_work_wait(&test_data.tx_work); test_close(new_sock); test_close(s_sock); @@ -356,13 +402,13 @@ ZTEST(net_socket_tls, test_v6_msg_waitall) test_data.sock = c_sock; k_work_init_delayable(&test_data.tx_work, test_msg_waitall_tx_work_handler); - k_work_reschedule(&test_data.tx_work, K_MSEC(10)); + test_work_reschedule(&test_data.tx_work, K_MSEC(10)); ret = recv(new_sock, rx_buf, sizeof(rx_buf), MSG_WAITALL); zassert_equal(ret, sizeof(rx_buf), "Invalid length received"); zassert_mem_equal(rx_buf, TEST_STR_SMALL, sizeof(rx_buf), "Invalid data received"); - k_work_cancel_delayable(&test_data.tx_work); + test_work_wait(&test_data.tx_work); /* MSG_WAITALL + SO_RCVTIMEO - make sure recv returns the amount of data * received so far @@ -377,13 +423,13 @@ ZTEST(net_socket_tls, test_v6_msg_waitall) test_data.sock = c_sock; k_work_init_delayable(&test_data.tx_work, test_msg_waitall_tx_work_handler); - k_work_reschedule(&test_data.tx_work, K_MSEC(10)); + test_work_reschedule(&test_data.tx_work, K_MSEC(10)); ret = recv(new_sock, rx_buf, sizeof(rx_buf) - 1, MSG_WAITALL); zassert_equal(ret, sizeof(rx_buf) - 1, "Invalid length received"); zassert_mem_equal(rx_buf, TEST_STR_SMALL, sizeof(rx_buf) - 1, "Invalid data received"); - k_work_cancel_delayable(&test_data.tx_work); + test_work_wait(&test_data.tx_work); test_close(new_sock); test_close(s_sock); @@ -392,18 +438,18 @@ ZTEST(net_socket_tls, test_v6_msg_waitall) k_sleep(TCP_TEARDOWN_TIMEOUT); } -struct test_msg_trunc_data { +struct send_data { struct k_work_delayable tx_work; int sock; const uint8_t *data; size_t datalen; }; -static void test_msg_trunc_tx_work_handler(struct k_work *work) +static void send_work_handler(struct k_work *work) { struct k_work_delayable *dwork = k_work_delayable_from_work(work); - struct test_msg_trunc_data *test_data = - CONTAINER_OF(dwork, struct test_msg_trunc_data, tx_work); + struct send_data *test_data = + CONTAINER_OF(dwork, struct send_data, tx_work); test_send(test_data->sock, test_data->data, test_data->datalen, 0); } @@ -415,7 +461,7 @@ void test_msg_trunc(int sock_c, int sock_s, struct sockaddr *addr_c, int rv; uint8_t rx_buf[sizeof(TEST_STR_SMALL) - 1]; int role = TLS_DTLS_ROLE_SERVER; - struct test_msg_trunc_data test_data = { + struct send_data test_data = { .data = TEST_STR_SMALL, .datalen = sizeof(TEST_STR_SMALL) - 1 }; @@ -437,9 +483,8 @@ void test_msg_trunc(int sock_c, int sock_s, struct sockaddr *addr_c, /* MSG_TRUNC */ test_data.sock = sock_c; - k_work_init_delayable(&test_data.tx_work, - test_msg_trunc_tx_work_handler); - k_work_reschedule(&test_data.tx_work, K_MSEC(10)); + k_work_init_delayable(&test_data.tx_work, send_work_handler); + test_work_reschedule(&test_data.tx_work, K_MSEC(10)); memset(rx_buf, 0, sizeof(rx_buf)); rv = recv(sock_s, rx_buf, 2, ZSOCK_MSG_TRUNC); @@ -458,6 +503,8 @@ void test_msg_trunc(int sock_c, int sock_s, struct sockaddr *addr_c, zassert_equal(rv, 0, "close failed"); rv = close(sock_s); zassert_equal(rv, 0, "close failed"); + + test_work_wait(&test_data.tx_work); } ZTEST(net_socket_tls, test_v4_msg_trunc) @@ -547,25 +594,29 @@ static void test_dtls_sendmsg(int sock_c, int sock_s, struct sockaddr *addr_c, msg.msg_iov = &iov[1]; msg.msg_iovlen = 1, - k_work_reschedule(&test_data.tx_work, K_MSEC(10)); + test_work_reschedule(&test_data.tx_work, K_MSEC(10)); memset(rx_buf, 0, sizeof(rx_buf)); rv = recv(sock_s, rx_buf, sizeof(rx_buf), 0); zassert_equal(rv, sizeof(TEST_STR_SMALL) - 1, "recv failed"); zassert_mem_equal(rx_buf, TEST_STR_SMALL, sizeof(TEST_STR_SMALL) - 1, "invalid rx data"); + test_work_wait(&test_data.tx_work); + /* sendmsg() with single non-empty fragment */ msg.msg_iov = iov; msg.msg_iovlen = ARRAY_SIZE(iov); - k_work_reschedule(&test_data.tx_work, K_MSEC(10)); + test_work_reschedule(&test_data.tx_work, K_MSEC(10)); memset(rx_buf, 0, sizeof(rx_buf)); rv = recv(sock_s, rx_buf, sizeof(rx_buf), 0); zassert_equal(rv, sizeof(TEST_STR_SMALL) - 1, "recv failed"); zassert_mem_equal(rx_buf, TEST_STR_SMALL, sizeof(TEST_STR_SMALL) - 1, "invalid rx data"); + test_work_wait(&test_data.tx_work); + /* sendmsg() with multiple non-empty fragments */ iov[0].iov_base = TEST_STR_SMALL; @@ -643,7 +694,7 @@ ZTEST(net_socket_tls, test_close_while_accept) /* Schedule close() from workqueue */ k_work_init_delayable(&close_work_data.work, close_work); close_work_data.fd = s_sock; - k_work_schedule(&close_work_data.work, K_MSEC(10)); + test_work_reschedule(&close_work_data.work, K_MSEC(10)); /* Start blocking accept(), which should be unblocked by close() from * another thread and return an error. @@ -651,6 +702,672 @@ ZTEST(net_socket_tls, test_close_while_accept) new_sock = accept(s_sock, &addr, &addrlen); zassert_equal(new_sock, -1, "accept did not return error"); zassert_equal(errno, EINTR, "Unexpected errno value: %d", errno); + + test_work_wait(&close_work_data.work); +} + +ZTEST(net_socket_tls, test_close_while_recv) +{ + int c_sock, s_sock, new_sock, ret; + struct close_data close_work_data; + uint8_t rx_buf; + + test_prepare_tls_connection(AF_INET6, &c_sock, &s_sock, &new_sock); + + /* Schedule close() from workqueue */ + k_work_init_delayable(&close_work_data.work, close_work); + close_work_data.fd = new_sock; + test_work_reschedule(&close_work_data.work, K_MSEC(10)); + + ret = recv(new_sock, &rx_buf, sizeof(rx_buf), 0); + zassert_equal(ret, -1, "recv did not return error"); + zassert_equal(errno, EINTR, "Unexpected errno value: %d", errno); + + test_close(s_sock); + test_close(c_sock); + + test_work_wait(&close_work_data.work); + k_sleep(TCP_TEARDOWN_TIMEOUT); +} + +ZTEST(net_socket_tls, test_connect_timeout) +{ + struct sockaddr_in6 c_saddr; + struct sockaddr_in6 s_saddr; + int c_sock; + int ret; + + prepare_sock_tls_v6(MY_IPV6_ADDR, ANY_PORT, &c_sock, &c_saddr, + IPPROTO_TLS_1_2); + test_config_psk(-1, c_sock); + + s_saddr.sin6_family = AF_INET6; + s_saddr.sin6_port = htons(SERVER_PORT); + ret = zsock_inet_pton(AF_INET6, MY_IPV6_ADDR, &s_saddr.sin6_addr); + zassert_equal(ret, 1, "inet_pton failed"); + + loopback_set_packet_drop_ratio(1.0f); + + zassert_equal(connect(c_sock, (struct sockaddr *)&s_saddr, + sizeof(s_saddr)), + -1, "connect succeed"); + zassert_equal(errno, ETIMEDOUT, + "connect should be timed out, got %d", errno); + + test_close(c_sock); + + loopback_set_packet_drop_ratio(0.0f); + k_sleep(TCP_TEARDOWN_TIMEOUT); +} + +ZTEST(net_socket_tls, test_connect_closed_port) +{ + struct sockaddr_in6 c_saddr; + struct sockaddr_in6 s_saddr; + int c_sock; + int ret; + + prepare_sock_tls_v6(MY_IPV6_ADDR, ANY_PORT, &c_sock, &c_saddr, + IPPROTO_TLS_1_2); + test_config_psk(-1, c_sock); + + s_saddr.sin6_family = AF_INET6; + s_saddr.sin6_port = htons(SERVER_PORT); + ret = zsock_inet_pton(AF_INET6, MY_IPV6_ADDR, &s_saddr.sin6_addr); + zassert_equal(ret, 1, "inet_pton failed"); + + zassert_equal(connect(c_sock, (struct sockaddr *)&s_saddr, + sizeof(s_saddr)), + -1, "connect succeed"); + zassert_equal(errno, ETIMEDOUT, + "connect should fail, got %d", errno); + + test_close(c_sock); + k_sleep(TCP_TEARDOWN_TIMEOUT); +} + +struct fake_tcp_server_data { + struct k_work_delayable work; + int sock; + bool reply; +}; + +static void fake_tcp_server_work(struct k_work *work) +{ + struct k_work_delayable *dwork = k_work_delayable_from_work(work); + struct fake_tcp_server_data *data = + CONTAINER_OF(dwork, struct fake_tcp_server_data, work); + int new_sock; + + test_accept(data->sock, &new_sock, NULL, 0); + + if (!data->reply) { + goto out; + } + + while (true) { + int ret; + char rx_buf[32]; + + ret = recv(new_sock, rx_buf, sizeof(rx_buf), 0); + if (ret <= 0) { + break; + } + + (void)send(new_sock, TEST_STR_SMALL, sizeof(TEST_STR_SMALL), 0); + } + +out: + test_close(new_sock); +} + +static void test_prepare_fake_tcp_server(struct fake_tcp_server_data *s_data, + sa_family_t family, int *s_sock, + struct sockaddr *s_saddr, bool reply) +{ + socklen_t exp_addrlen = family == AF_INET6 ? + sizeof(struct sockaddr_in6) : + sizeof(struct sockaddr_in); + + if (family == AF_INET6) { + prepare_sock_tcp_v6(MY_IPV6_ADDR, SERVER_PORT, s_sock, + (struct sockaddr_in6 *)s_saddr); + } else { + prepare_sock_tcp_v4(MY_IPV4_ADDR, SERVER_PORT, s_sock, + (struct sockaddr_in *)s_saddr); + } + + test_bind(*s_sock, s_saddr, exp_addrlen); + test_listen(*s_sock); + + s_data->sock = *s_sock; + s_data->reply = reply; + k_work_init_delayable(&s_data->work, fake_tcp_server_work); + test_work_reschedule(&s_data->work, K_NO_WAIT); +} + +ZTEST(net_socket_tls, test_connect_invalid_handshake_data) +{ + struct fake_tcp_server_data server_data; + struct sockaddr_in6 c_saddr; + struct sockaddr_in6 s_saddr; + int c_sock, s_sock; + + prepare_sock_tls_v6(MY_IPV6_ADDR, ANY_PORT, &c_sock, &c_saddr, + IPPROTO_TLS_1_2); + test_config_psk(-1, c_sock); + test_prepare_fake_tcp_server(&server_data, AF_INET6, &s_sock, + (struct sockaddr *)&s_saddr, true); + + zassert_equal(connect(c_sock, (struct sockaddr *)&s_saddr, + sizeof(s_saddr)), + -1, "connect succeed"); + zassert_equal(errno, ECONNABORTED, + "connect should fail, got %d", errno); + + test_close(c_sock); + test_close(s_sock); + + test_work_wait(&server_data.work); + k_sleep(TCP_TEARDOWN_TIMEOUT); +} + +ZTEST(net_socket_tls, test_connect_no_handshake_data) +{ + struct fake_tcp_server_data server_data; + struct sockaddr_in6 c_saddr; + struct sockaddr s_saddr; + int c_sock, s_sock; + + prepare_sock_tls_v6(MY_IPV6_ADDR, ANY_PORT, &c_sock, &c_saddr, + IPPROTO_TLS_1_2); + test_config_psk(-1, c_sock); + test_prepare_fake_tcp_server(&server_data, AF_INET6, &s_sock, + (struct sockaddr *)&s_saddr, false); + + zassert_equal(connect(c_sock, (struct sockaddr *)&s_saddr, + sizeof(s_saddr)), + -1, "connect succeed"); + zassert_equal(errno, ECONNABORTED, + "connect should fail, got %d", errno); + + test_close(c_sock); + test_close(s_sock); + + test_work_wait(&server_data.work); + k_sleep(TCP_TEARDOWN_TIMEOUT); +} + +ZTEST(net_socket_tls, test_accept_non_block) +{ + int s_sock, new_sock; + uint32_t timestamp; + struct sockaddr_in6 s_saddr; + + prepare_sock_tls_v6(MY_IPV6_ADDR, SERVER_PORT, &s_sock, &s_saddr, + IPPROTO_TLS_1_2); + + test_config_psk(s_sock, -1); + test_fcntl(s_sock, F_SETFL, O_NONBLOCK); + test_bind(s_sock, (struct sockaddr *)&s_saddr, sizeof(s_saddr)); + test_listen(s_sock); + + timestamp = k_uptime_get_32(); + new_sock = accept(s_sock, NULL, NULL); + zassert_true(k_uptime_get_32() - timestamp <= 100, ""); + zassert_equal(new_sock, -1, "accept did not return error"); + zassert_equal(errno, EAGAIN, "Unexpected errno value: %d", errno); + + test_close(s_sock); +} + +ZTEST(net_socket_tls, test_accept_invalid_handshake_data) +{ + int s_sock, c_sock, new_sock; + struct sockaddr_in6 s_saddr; + struct sockaddr_in6 c_saddr; + + prepare_sock_tls_v6(MY_IPV6_ADDR, ANY_PORT, &s_sock, &s_saddr, + IPPROTO_TLS_1_2); + prepare_sock_tcp_v6(MY_IPV6_ADDR, ANY_PORT, &c_sock, &c_saddr); + + test_config_psk(s_sock, -1); + test_bind(s_sock, (struct sockaddr *)&s_saddr, sizeof(s_saddr)); + test_listen(s_sock); + + /* Connect at TCP level and send some unexpected data. */ + test_connect(c_sock, (struct sockaddr *)&s_saddr, sizeof(s_saddr)); + test_send(c_sock, TEST_STR_SMALL, sizeof(TEST_STR_SMALL), 0); + + new_sock = accept(s_sock, NULL, NULL); + zassert_equal(new_sock, -1, "accept did not return error"); + zassert_equal(errno, ECONNABORTED, "Unexpected errno value: %d", errno); + + test_close(s_sock); + test_close(c_sock); +} + +ZTEST(net_socket_tls, test_recv_non_block) +{ + int c_sock, s_sock, new_sock, ret; + uint8_t rx_buf[sizeof(TEST_STR_SMALL) - 1] = { 0 }; + + test_prepare_tls_connection(AF_INET6, &c_sock, &s_sock, &new_sock); + + /* Verify ZSOCK_MSG_DONTWAIT flag first */ + ret = recv(new_sock, rx_buf, sizeof(rx_buf), ZSOCK_MSG_DONTWAIT); + zassert_equal(ret, -1, "recv()) should've failed"); + zassert_equal(errno, EAGAIN, "Unexpected errno value: %d", errno); + + /* Verify fcntl and O_NONBLOCK */ + test_fcntl(new_sock, F_SETFL, O_NONBLOCK); + ret = recv(new_sock, rx_buf, sizeof(rx_buf), 0); + zassert_equal(ret, -1, "recv() should've failed"); + zassert_equal(errno, EAGAIN, "Unexpected errno value: %d", errno); + + ret = send(c_sock, TEST_STR_SMALL, strlen(TEST_STR_SMALL), 0); + zassert_equal(ret, strlen(TEST_STR_SMALL), "send() failed"); + + /* Let the data got through. */ + k_sleep(K_MSEC(10)); + + /* Should get data now */ + ret = recv(new_sock, rx_buf, sizeof(rx_buf), 0); + zassert_equal(ret, strlen(TEST_STR_SMALL), "recv() failed"); + zassert_mem_equal(rx_buf, TEST_STR_SMALL, ret, "Invalid data received"); + + /* And EAGAIN on consecutive read */ + ret = recv(new_sock, rx_buf, sizeof(rx_buf), 0); + zassert_equal(ret, -1, "recv() should've failed"); + zassert_equal(errno, EAGAIN, "Unexpected errno value: %d", errno); + + test_close(c_sock); + test_close(new_sock); + test_close(s_sock); + + k_sleep(TCP_TEARDOWN_TIMEOUT); +} + +ZTEST(net_socket_tls, test_recv_block) +{ + int c_sock, s_sock, new_sock, ret; + uint8_t rx_buf[sizeof(TEST_STR_SMALL) - 1] = { 0 }; + struct send_data test_data = { + .data = TEST_STR_SMALL, + .datalen = sizeof(TEST_STR_SMALL) - 1 + }; + + test_prepare_tls_connection(AF_INET6, &c_sock, &s_sock, &new_sock); + + test_data.sock = c_sock; + k_work_init_delayable(&test_data.tx_work, send_work_handler); + test_work_reschedule(&test_data.tx_work, K_MSEC(10)); + + /* recv() shall block until send work sends the data. */ + ret = recv(new_sock, rx_buf, sizeof(rx_buf), 0); + zassert_equal(ret, sizeof(TEST_STR_SMALL) - 1, "recv() failed"); + zassert_mem_equal(rx_buf, TEST_STR_SMALL, ret, "Invalid data received"); + + test_close(c_sock); + test_close(new_sock); + test_close(s_sock); + + k_sleep(TCP_TEARDOWN_TIMEOUT); +} + +#define TLS_RECORD_OVERHEAD 81 + +ZTEST(net_socket_tls, test_send_non_block) +{ + int c_sock, s_sock, new_sock, ret; + uint8_t rx_buf[sizeof(TEST_STR_SMALL) - 1] = { 0 }; + int buf_optval = TLS_RECORD_OVERHEAD + sizeof(TEST_STR_SMALL) - 1; + + test_prepare_tls_connection(AF_INET6, &c_sock, &s_sock, &new_sock); + + /* Simulate window full scenario with SO_RCVBUF option. */ + ret = setsockopt(new_sock, SOL_SOCKET, SO_RCVBUF, &buf_optval, + sizeof(buf_optval)); + zassert_equal(ret, 0, "setsockopt failed (%d)", errno); + + /* Fill out the window */ + ret = send(c_sock, TEST_STR_SMALL, strlen(TEST_STR_SMALL), 0); + zassert_equal(ret, strlen(TEST_STR_SMALL), "send() failed"); + + /* Wait for ACK (empty window, min. 100 ms due to silly window + * protection). + */ + k_sleep(K_MSEC(150)); + + /* Verify ZSOCK_MSG_DONTWAIT flag first */ + ret = send(c_sock, TEST_STR_SMALL, strlen(TEST_STR_SMALL), + ZSOCK_MSG_DONTWAIT); + zassert_equal(ret, -1, "send() should've failed"); + zassert_equal(errno, EAGAIN, "Unexpected errno value: %d", errno); + + /* Verify fcntl and O_NONBLOCK */ + test_fcntl(c_sock, F_SETFL, O_NONBLOCK); + ret = send(c_sock, TEST_STR_SMALL, strlen(TEST_STR_SMALL), 0); + zassert_equal(ret, -1, "send() should've failed"); + zassert_equal(errno, EAGAIN, "Unexpected errno value: %d", errno); + + ret = recv(new_sock, rx_buf, sizeof(rx_buf), 0); + zassert_equal(ret, strlen(TEST_STR_SMALL), "recv() failed"); + zassert_mem_equal(rx_buf, TEST_STR_SMALL, ret, "Invalid data received"); + + /* Wait for the window to update. */ + k_sleep(K_MSEC(10)); + + /* Should succeed now. */ + ret = send(c_sock, TEST_STR_SMALL, strlen(TEST_STR_SMALL), 0); + zassert_equal(ret, strlen(TEST_STR_SMALL), "send() failed"); + + /* Flush the data */ + ret = recv(new_sock, rx_buf, sizeof(rx_buf), 0); + zassert_equal(ret, strlen(TEST_STR_SMALL), "recv() failed"); + zassert_mem_equal(rx_buf, TEST_STR_SMALL, ret, "Invalid data received"); + + /* And make sure there's no more data left. */ + ret = recv(new_sock, rx_buf, sizeof(rx_buf), ZSOCK_MSG_DONTWAIT); + zassert_equal(ret, -1, "recv() should've failed"); + zassert_equal(errno, EAGAIN, "Unexpected errno value: %d", errno); + + test_close(c_sock); + test_close(new_sock); + test_close(s_sock); + + k_sleep(TCP_TEARDOWN_TIMEOUT); +} + +struct recv_data { + struct k_work_delayable work; + int sock; + const uint8_t *data; + size_t datalen; +}; + +static void recv_work_handler(struct k_work *work) +{ + struct k_work_delayable *dwork = k_work_delayable_from_work(work); + struct recv_data *test_data = CONTAINER_OF(dwork, struct recv_data, work); + char rx_buf[30] = { 0 }; + size_t off = 0; + int ret; + + while (off < test_data->datalen) { + size_t recvlen = MIN(sizeof(rx_buf), test_data->datalen - off); + + ret = recv(test_data->sock, rx_buf, recvlen, 0); + zassert_true(ret > 0, "recv() error"); + zassert_mem_equal(rx_buf, test_data->data + off, ret, + "unexpected data"); + + off += ret; + zassert_true(off <= test_data->datalen, + "received more than expected"); + } +} + +ZTEST(net_socket_tls, test_send_block) +{ + int c_sock, s_sock, new_sock, ret; + int buf_optval = TLS_RECORD_OVERHEAD + sizeof(TEST_STR_SMALL) - 1; + uint8_t rx_buf[sizeof(TEST_STR_SMALL) - 1] = { 0 }; + struct recv_data test_data = { + .data = TEST_STR_SMALL, + .datalen = sizeof(TEST_STR_SMALL) - 1 + }; + + test_prepare_tls_connection(AF_INET6, &c_sock, &s_sock, &new_sock); + + /* Simulate window full scenario with SO_RCVBUF option. */ + ret = setsockopt(new_sock, SOL_SOCKET, SO_RCVBUF, &buf_optval, + sizeof(buf_optval)); + zassert_equal(ret, 0, "setsockopt failed (%d)", errno); + + /* Fill out the window */ + ret = send(c_sock, TEST_STR_SMALL, strlen(TEST_STR_SMALL), 0); + zassert_equal(ret, strlen(TEST_STR_SMALL), "send() failed"); + + /* Wait for ACK (empty window, min. 100 ms due to silly window + * protection). + */ + k_sleep(K_MSEC(150)); + + test_data.sock = new_sock; + k_work_init_delayable(&test_data.work, recv_work_handler); + test_work_reschedule(&test_data.work, K_MSEC(10)); + + /* Should block and succeed. */ + ret = send(c_sock, TEST_STR_SMALL, strlen(TEST_STR_SMALL), 0); + zassert_equal(ret, strlen(TEST_STR_SMALL), "send() failed"); + + /* Flush the data */ + ret = recv(new_sock, rx_buf, sizeof(rx_buf), 0); + zassert_equal(ret, strlen(TEST_STR_SMALL), "recv() failed"); + zassert_mem_equal(rx_buf, TEST_STR_SMALL, ret, "Invalid data received"); + + /* And make sure there's no more data left. */ + ret = recv(new_sock, rx_buf, sizeof(rx_buf), ZSOCK_MSG_DONTWAIT); + zassert_equal(ret, -1, "recv() should've failed"); + zassert_equal(errno, EAGAIN, "Unexpected errno value: %d", errno); + + test_close(c_sock); + test_close(new_sock); + test_close(s_sock); + + k_sleep(TCP_TEARDOWN_TIMEOUT); +} + +ZTEST(net_socket_tls, test_so_rcvtimeo) +{ + uint8_t rx_buf[sizeof(TEST_STR_SMALL) - 1]; + uint32_t start_time, time_diff; + struct timeval optval = { + .tv_sec = 0, + .tv_usec = 500000, + }; + struct send_data test_data = { + .data = TEST_STR_SMALL, + .datalen = sizeof(TEST_STR_SMALL) - 1 + }; + int c_sock, s_sock, new_sock, ret; + + test_prepare_tls_connection(AF_INET6, &c_sock, &s_sock, &new_sock); + + ret = setsockopt(c_sock, SOL_SOCKET, SO_RCVTIMEO, &optval, + sizeof(optval)); + zassert_equal(ret, 0, "setsockopt failed (%d)", errno); + + start_time = k_uptime_get_32(); + ret = recv(c_sock, rx_buf, sizeof(rx_buf), 0); + time_diff = k_uptime_get_32() - start_time; + + zassert_equal(ret, -1, "recv() should've failed"); + zassert_equal(errno, EAGAIN, "Unexpected errno value: %d", errno); + zassert_true(time_diff >= 500, "Expected timeout after 500ms but " + "was %dms", time_diff); + + test_data.sock = c_sock; + k_work_init_delayable(&test_data.tx_work, send_work_handler); + test_work_reschedule(&test_data.tx_work, K_MSEC(10)); + + /* recv() shall return as soon as it gets data, regardless of timeout. */ + ret = recv(new_sock, rx_buf, sizeof(rx_buf), 0); + zassert_equal(ret, sizeof(TEST_STR_SMALL) - 1, "recv() failed"); + zassert_mem_equal(rx_buf, TEST_STR_SMALL, ret, "Invalid data received"); + + test_close(c_sock); + test_close(new_sock); + test_close(s_sock); + + k_sleep(TCP_TEARDOWN_TIMEOUT); +} + +ZTEST(net_socket_tls, test_so_sndtimeo) +{ + int buf_optval = TLS_RECORD_OVERHEAD + sizeof(TEST_STR_SMALL) - 1; + uint32_t start_time, time_diff; + struct timeval timeo_optval = { + .tv_sec = 0, + .tv_usec = 500000, + }; + struct recv_data test_data = { + .data = TEST_STR_SMALL, + .datalen = sizeof(TEST_STR_SMALL) - 1 + }; + int c_sock, s_sock, new_sock, ret; + + test_prepare_tls_connection(AF_INET6, &c_sock, &s_sock, &new_sock); + + ret = setsockopt(c_sock, SOL_SOCKET, SO_SNDTIMEO, &timeo_optval, + sizeof(timeo_optval)); + zassert_equal(ret, 0, "setsockopt failed (%d)", errno); + + /* Simulate window full scenario with SO_RCVBUF option. */ + ret = setsockopt(new_sock, SOL_SOCKET, SO_RCVBUF, &buf_optval, + sizeof(buf_optval)); + zassert_equal(ret, 0, "setsockopt failed (%d)", errno); + + ret = send(c_sock, TEST_STR_SMALL, sizeof(TEST_STR_SMALL) - 1, 0); + zassert_equal(ret, sizeof(TEST_STR_SMALL) - 1, "send() failed"); + + /* Wait for ACK (empty window). */ + k_msleep(150); + + /* Client should not be able to send now and time out after SO_SNDTIMEO */ + start_time = k_uptime_get_32(); + ret = send(c_sock, TEST_STR_SMALL, sizeof(TEST_STR_SMALL) - 1, 0); + time_diff = k_uptime_get_32() - start_time; + + zassert_equal(ret, -1, "send() should've failed"); + zassert_equal(errno, EAGAIN, "Unexpected errno value: %d", errno); + zassert_true(time_diff >= 500, "Expected timeout after 500ms but " + "was %dms", time_diff); + + test_data.sock = new_sock; + k_work_init_delayable(&test_data.work, recv_work_handler); + test_work_reschedule(&test_data.work, K_MSEC(10)); + + /* Should block and succeed. */ + ret = send(c_sock, TEST_STR_SMALL, strlen(TEST_STR_SMALL), 0); + zassert_equal(ret, strlen(TEST_STR_SMALL), "send() failed"); + + test_close(c_sock); + test_close(new_sock); + test_close(s_sock); + + k_sleep(TCP_TEARDOWN_TIMEOUT); +} + +ZTEST(net_socket_tls, test_shutdown_rd_synchronous) +{ + int c_sock, s_sock, new_sock; + + test_prepare_tls_connection(AF_INET6, &c_sock, &s_sock, &new_sock); + + /* Shutdown reception */ + test_shutdown(c_sock, ZSOCK_SHUT_RD); + + /* EOF should be notified by recv() */ + test_eof(c_sock); + + test_close(new_sock); + test_close(s_sock); + test_close(c_sock); + + k_sleep(TCP_TEARDOWN_TIMEOUT); +} + +struct shutdown_data { + struct k_work_delayable work; + int sock; + int how; +}; + +static void shutdown_work(struct k_work *work) +{ + struct k_work_delayable *dwork = k_work_delayable_from_work(work); + struct shutdown_data *data = CONTAINER_OF(dwork, struct shutdown_data, + work); + + shutdown(data->sock, data->how); +} + +ZTEST(net_socket_tls, test_shutdown_rd_while_recv) +{ + int c_sock, s_sock, new_sock; + struct shutdown_data test_data = { + .how = ZSOCK_SHUT_RD, + }; + + test_prepare_tls_connection(AF_INET6, &c_sock, &s_sock, &new_sock); + + /* Schedule reception shutdown from workqueue */ + k_work_init_delayable(&test_data.work, shutdown_work); + test_data.sock = c_sock; + test_work_reschedule(&test_data.work, K_MSEC(10)); + + /* EOF should be notified by recv() */ + test_eof(c_sock); + + test_close(new_sock); + test_close(s_sock); + test_close(c_sock); + + k_sleep(TCP_TEARDOWN_TIMEOUT); +} + +ZTEST(net_socket_tls, test_send_while_recv) +{ + uint8_t rx_buf[sizeof(TEST_STR_SMALL) - 1]; + struct send_data test_data_c = { + .data = TEST_STR_SMALL, + .datalen = sizeof(TEST_STR_SMALL) - 1 + }; + struct send_data test_data_s = { + .data = TEST_STR_SMALL, + .datalen = sizeof(TEST_STR_SMALL) - 1 + }; + int c_sock, s_sock, new_sock, ret; + + test_prepare_tls_connection(AF_INET6, &c_sock, &s_sock, &new_sock); + + test_data_c.sock = c_sock; + k_work_init_delayable(&test_data_c.tx_work, send_work_handler); + test_work_reschedule(&test_data_c.tx_work, K_MSEC(10)); + + test_data_s.sock = new_sock; + k_work_init_delayable(&test_data_s.tx_work, send_work_handler); + test_work_reschedule(&test_data_s.tx_work, K_MSEC(20)); + + /* recv() shall block until the second work is executed. The second work + * will execute only if the first one won't block. + */ + ret = recv(c_sock, rx_buf, sizeof(rx_buf), 0); + zassert_equal(ret, sizeof(TEST_STR_SMALL) - 1, "recv() failed"); + zassert_mem_equal(rx_buf, TEST_STR_SMALL, ret, "Invalid data received"); + + /* Check if the server sock got its data. */ + ret = recv(new_sock, rx_buf, sizeof(rx_buf), 0); + zassert_equal(ret, sizeof(TEST_STR_SMALL) - 1, "recv() failed"); + zassert_mem_equal(rx_buf, TEST_STR_SMALL, ret, "Invalid data received"); + + test_close(c_sock); + test_close(new_sock); + test_close(s_sock); + + k_sleep(TCP_TEARDOWN_TIMEOUT); +} + +static void *tls_tests_setup(void) +{ + k_work_queue_init(&tls_test_work_queue); + k_work_queue_start(&tls_test_work_queue, tls_test_work_queue_stack, + K_THREAD_STACK_SIZEOF(tls_test_work_queue_stack), + K_LOWEST_APPLICATION_THREAD_PRIO, NULL); + + return NULL; } -ZTEST_SUITE(net_socket_tls, NULL, NULL, NULL, NULL, NULL); +ZTEST_SUITE(net_socket_tls, NULL, tls_tests_setup, NULL, NULL, NULL); From 0bc8de8444b27aa542879e8b975252b14485804a Mon Sep 17 00:00:00 2001 From: Robert Lubos Date: Wed, 13 Dec 2023 14:12:35 +0100 Subject: [PATCH 1451/3723] tests: net: socket: tls: Disable vmu_rt1170 platform Due to unresolved bug (see #61129 for details) building TLS tests fails on vmu_rt1170 platform. Therefore disable this platform for this test suite. Signed-off-by: Robert Lubos --- tests/net/socket/tls/testcase.yaml | 1 + 1 file changed, 1 insertion(+) diff --git a/tests/net/socket/tls/testcase.yaml b/tests/net/socket/tls/testcase.yaml index fd9d615335d..e10c883312f 100644 --- a/tests/net/socket/tls/testcase.yaml +++ b/tests/net/socket/tls/testcase.yaml @@ -9,6 +9,7 @@ common: filter: CONFIG_FULL_LIBC_SUPPORTED integration_platforms: - qemu_x86 + platform_exclude: vmu_rt1170 # See #61129 tests: net.socket.tls: extra_configs: From ea1cafbee705b4846b094df5862dc8d359c1f9f5 Mon Sep 17 00:00:00 2001 From: Andrei-Edward Popa Date: Sat, 18 Mar 2023 22:59:40 +0200 Subject: [PATCH 1452/3723] drivers: clock_control: Added clock driver for Raspberry Pi Pico Added clock driver for Raspberry Pi Pico platform Signed-off-by: Andrei-Edward Popa Signed-off-by: TOKITA Hiroshi --- .../arm/adafruit_kb2040/adafruit_kb2040.dts | 6 - .../adafruit_kb2040/adafruit_kb2040_defconfig | 3 + boards/arm/rpi_pico/rpi_pico-common.dtsi | 6 - boards/arm/rpi_pico/rpi_pico_defconfig | 1 + boards/arm/rpi_pico/rpi_pico_w_defconfig | 1 + .../sparkfun_pro_micro_rp2040.dts | 6 - .../sparkfun_pro_micro_rp2040_defconfig | 3 + drivers/clock_control/CMakeLists.txt | 1 + drivers/clock_control/Kconfig | 2 + drivers/clock_control/Kconfig.rpi_pico | 19 + .../clock_control/clock_control_rpi_pico.c | 876 ++++++++++++++++++ dts/arm/rpi_pico/rp2040.dtsi | 204 +++- .../raspberrypi,pico-clock-controller.yaml | 18 + .../clock/raspberrypi,pico-clock.yaml | 18 + dts/bindings/clock/raspberrypi,pico-pll.yaml | 31 + dts/bindings/clock/raspberrypi,pico-rosc.yaml | 38 + .../zephyr/dt-bindings/clock/rpi_pico_clock.h | 44 + .../pinctrl/rpi-pico-rp2040-pinctrl.h | 7 + .../sensor/bme280/rpi_pico_spi_pio.overlay | 2 +- soc/arm/rpi_pico/rp2/soc.c | 20 - 20 files changed, 1243 insertions(+), 63 deletions(-) create mode 100644 drivers/clock_control/Kconfig.rpi_pico create mode 100644 drivers/clock_control/clock_control_rpi_pico.c create mode 100644 dts/bindings/clock/raspberrypi,pico-clock-controller.yaml create mode 100644 dts/bindings/clock/raspberrypi,pico-clock.yaml create mode 100644 dts/bindings/clock/raspberrypi,pico-pll.yaml create mode 100644 dts/bindings/clock/raspberrypi,pico-rosc.yaml create mode 100644 include/zephyr/dt-bindings/clock/rpi_pico_clock.h diff --git a/boards/arm/adafruit_kb2040/adafruit_kb2040.dts b/boards/arm/adafruit_kb2040/adafruit_kb2040.dts index 2d9c815f578..227bb53e8d6 100644 --- a/boards/arm/adafruit_kb2040/adafruit_kb2040.dts +++ b/boards/arm/adafruit_kb2040/adafruit_kb2040.dts @@ -25,12 +25,6 @@ aliases { watchdog0 = &wdt0; }; - - xtal_clk: xtal-clk { - compatible = "fixed-clock"; - clock-frequency = <12000000>; - #clock-cells = <0>; - }; }; &flash0 { diff --git a/boards/arm/adafruit_kb2040/adafruit_kb2040_defconfig b/boards/arm/adafruit_kb2040/adafruit_kb2040_defconfig index 735148fbce2..6ce0691032d 100644 --- a/boards/arm/adafruit_kb2040/adafruit_kb2040_defconfig +++ b/boards/arm/adafruit_kb2040/adafruit_kb2040_defconfig @@ -17,6 +17,9 @@ CONFIG_UART_CONSOLE=y # Enable reset by default CONFIG_RESET=y +# Enable clock control by default +CONFIG_CLOCK_CONTROL=y + # Code partition needed to target the correct flash range CONFIG_USE_DT_CODE_PARTITION=y diff --git a/boards/arm/rpi_pico/rpi_pico-common.dtsi b/boards/arm/rpi_pico/rpi_pico-common.dtsi index 680d2032449..aee3e144368 100644 --- a/boards/arm/rpi_pico/rpi_pico-common.dtsi +++ b/boards/arm/rpi_pico/rpi_pico-common.dtsi @@ -23,12 +23,6 @@ zephyr,code-partition = &code_partition; }; - xtal_clk: xtal-clk { - compatible = "fixed-clock"; - clock-frequency = <12000000>; - #clock-cells = <0>; - }; - aliases { watchdog0 = &wdt0; }; diff --git a/boards/arm/rpi_pico/rpi_pico_defconfig b/boards/arm/rpi_pico/rpi_pico_defconfig index 2a276892119..111edceb147 100644 --- a/boards/arm/rpi_pico/rpi_pico_defconfig +++ b/boards/arm/rpi_pico/rpi_pico_defconfig @@ -11,3 +11,4 @@ CONFIG_BUILD_OUTPUT_UF2=y CONFIG_BUILD_OUTPUT_HEX=y CONFIG_UART_INTERRUPT_DRIVEN=y CONFIG_RESET=y +CONFIG_CLOCK_CONTROL=y diff --git a/boards/arm/rpi_pico/rpi_pico_w_defconfig b/boards/arm/rpi_pico/rpi_pico_w_defconfig index a0355614197..9b3868541d1 100644 --- a/boards/arm/rpi_pico/rpi_pico_w_defconfig +++ b/boards/arm/rpi_pico/rpi_pico_w_defconfig @@ -11,3 +11,4 @@ CONFIG_BUILD_OUTPUT_UF2=y CONFIG_BUILD_OUTPUT_HEX=y CONFIG_UART_INTERRUPT_DRIVEN=y CONFIG_RESET=y +CONFIG_CLOCK_CONTROL=y diff --git a/boards/arm/sparkfun_pro_micro_rp2040/sparkfun_pro_micro_rp2040.dts b/boards/arm/sparkfun_pro_micro_rp2040/sparkfun_pro_micro_rp2040.dts index 1bd5e226e2a..50b92f603f7 100644 --- a/boards/arm/sparkfun_pro_micro_rp2040/sparkfun_pro_micro_rp2040.dts +++ b/boards/arm/sparkfun_pro_micro_rp2040/sparkfun_pro_micro_rp2040.dts @@ -23,12 +23,6 @@ aliases { watchdog0 = &wdt0; }; - - xtal_clk: xtal-clk { - compatible = "fixed-clock"; - clock-frequency = <12000000>; - #clock-cells = <0>; - }; }; &flash0 { diff --git a/boards/arm/sparkfun_pro_micro_rp2040/sparkfun_pro_micro_rp2040_defconfig b/boards/arm/sparkfun_pro_micro_rp2040/sparkfun_pro_micro_rp2040_defconfig index 4ec1c6cad43..36aba349204 100644 --- a/boards/arm/sparkfun_pro_micro_rp2040/sparkfun_pro_micro_rp2040_defconfig +++ b/boards/arm/sparkfun_pro_micro_rp2040/sparkfun_pro_micro_rp2040_defconfig @@ -15,6 +15,9 @@ CONFIG_UART_INTERRUPT_DRIVEN=y CONFIG_CONSOLE=y CONFIG_UART_CONSOLE=y +# Enable clock control by default +CONFIG_CLOCK_CONTROL=y + # Code partition needed to target the correct flash range CONFIG_USE_DT_CODE_PARTITION=y diff --git a/drivers/clock_control/CMakeLists.txt b/drivers/clock_control/CMakeLists.txt index 219aac76b97..14f6c603000 100644 --- a/drivers/clock_control/CMakeLists.txt +++ b/drivers/clock_control/CMakeLists.txt @@ -29,6 +29,7 @@ zephyr_library_sources_ifdef(CONFIG_CLOCK_CONTROL_NXP_S32 clock_cont zephyr_library_sources_ifdef(CONFIG_CLOCK_CONTROL_RA clock_control_ra.c) zephyr_library_sources_ifdef(CONFIG_CLOCK_CONTROL_AMBIQ clock_control_ambiq.c) zephyr_library_sources_ifdef(CONFIG_CLOCK_CONTROL_PWM clock_control_pwm.c) +zephyr_library_sources_ifdef(CONFIG_CLOCK_CONTROL_RPI_PICO clock_control_rpi_pico.c) if(CONFIG_CLOCK_CONTROL_STM32_CUBE) diff --git a/drivers/clock_control/Kconfig b/drivers/clock_control/Kconfig index 37cbb2e2895..9f7412cd9f2 100644 --- a/drivers/clock_control/Kconfig +++ b/drivers/clock_control/Kconfig @@ -86,4 +86,6 @@ source "drivers/clock_control/Kconfig.ambiq" source "drivers/clock_control/Kconfig.pwm" +source "drivers/clock_control/Kconfig.rpi_pico" + endif # CLOCK_CONTROL diff --git a/drivers/clock_control/Kconfig.rpi_pico b/drivers/clock_control/Kconfig.rpi_pico new file mode 100644 index 00000000000..3c7c87121fd --- /dev/null +++ b/drivers/clock_control/Kconfig.rpi_pico @@ -0,0 +1,19 @@ +# Raspberry Pi Pico Clock Controller Driver configuration options + +# Copyright (c) 2022 Andrei-Edward Popa +# SPDX-License-Identifier: Apache-2.0 + +config CLOCK_CONTROL_RPI_PICO + bool "Raspberry Pi Pico Clock Controller Driver" + default y + depends on DT_HAS_RASPBERRYPI_PICO_CLOCK_CONTROLLER_ENABLED + +if CLOCK_CONTROL_RPI_PICO + +config RPI_PICO_ROSC_USE_MEASURED_FREQ + bool "Use measured frequency for ring oscillator" + help + Instead of the dts value, use the value measured by + the frequency counter as the rosc frequency. + +endif # CLOCK_CONTROL_RPI_PICO diff --git a/drivers/clock_control/clock_control_rpi_pico.c b/drivers/clock_control/clock_control_rpi_pico.c new file mode 100644 index 00000000000..0313ee2d71d --- /dev/null +++ b/drivers/clock_control/clock_control_rpi_pico.c @@ -0,0 +1,876 @@ +/* + * Copyright (c) 2022 Andrei-Edward Popa + * Copyright (c) 2023 TOKITA Hiroshi + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#define DT_DRV_COMPAT raspberrypi_pico_clock_controller + +#include +#include +#include + +#include +#include +#include +#include +#include +#include + +/* Undefine to prevent conflicts with header definitions */ +#undef pll_sys +#undef pll_usb + +#define CTRL_SRC_LSB CLOCKS_CLK_REF_CTRL_SRC_LSB +#define CTRL_SRC_BITS CLOCKS_CLK_REF_CTRL_SRC_BITS +#define CTRL_AUXSRC_LSB CLOCKS_CLK_GPOUT0_CTRL_AUXSRC_LSB +#define CTRL_AUXSRC_BITS CLOCKS_CLK_GPOUT0_CTRL_AUXSRC_BITS +#define CTRL_ENABLE_BITS CLOCKS_CLK_GPOUT0_CTRL_ENABLE_BITS +#define DIV_FRAC_BITS CLOCKS_CLK_GPOUT0_DIV_FRAC_BITS +#define DIV_INT_BITS CLOCKS_CLK_GPOUT0_DIV_INT_BITS +#define DIV_INT_LSB CLOCKS_CLK_GPOUT0_DIV_INT_LSB + +#define PLL_VCO_FREQ_MIN 750000000 +#define PLL_VCO_FREQ_MAX 1600000000 +#define PLL_FB_DIV_MIN 16 +#define PLL_FB_DIV_MAX 320 +#define PLL_POST_DIV_MIN 1 +#define PLL_POST_DIV_MAX 7 + +#define ROSC_PHASE_PASSWD_VALUE_PASS _u(0xAA) + +#define STAGE_DS(n) \ + (COND_CODE_1( \ + DT_PROP_HAS_IDX(DT_INST_CLOCKS_CTLR_BY_NAME(0, rosc), stage_drive_strength, n), \ + (DT_PROP_BY_IDX(DT_INST_CLOCKS_CTLR_BY_NAME(0, rosc), stage_drive_strength, n) & \ + ROSC_FREQA_DS0_BITS), \ + (0)) \ + << (n * 3)) + +#define CLK_SRC_IS(clk, src) \ + DT_SAME_NODE(DT_CLOCKS_CTLR_BY_IDX(DT_INST_CLOCKS_CTLR_BY_NAME(0, clk), 0), \ + DT_INST_CLOCKS_CTLR_BY_NAME(0, src)) + +#define REF_DIV(pll) DT_PROP(DT_INST_CLOCKS_CTLR_BY_NAME(0, pll), clock_div) +#define FB_DIV(pll) DT_PROP(DT_INST_CLOCKS_CTLR_BY_NAME(0, pll), fb_div) +#define POST_DIV1(pll) DT_PROP(DT_INST_CLOCKS_CTLR_BY_NAME(0, pll), post_div1) +#define POST_DIV2(pll) DT_PROP(DT_INST_CLOCKS_CTLR_BY_NAME(0, pll), post_div2) +#define VCO_FREQ(pll) ((CLOCK_FREQ_xosc / REF_DIV(pll)) * FB_DIV(pll)) + +/* + * Using the 'clock-names[0]' for expanding macro to frequency value. + * The 'clock-names[0]' is set same as label value that given to the node itself. + * Use it for traverse clock tree to find root of clock source. + */ +#define CLOCK_FREQ(clk) _CONCAT(CLOCK_FREQ_, clk) +#define SRC_CLOCK(clk) DT_STRING_TOKEN_BY_IDX(DT_INST_CLOCKS_CTLR_BY_NAME(0, clk), \ + clock_names, 0) +#define SRC_CLOCK_FREQ(clk) _CONCAT(CLOCK_FREQ_, SRC_CLOCK(clk)) + +#define PLL_FREQ(pll) \ + (DT_PROP(DT_CLOCKS_CTLR_BY_IDX(DT_INST_CLOCKS_CTLR_BY_NAME(0, pll), 0), clock_frequency) / \ + REF_DIV(pll) * FB_DIV(pll) / POST_DIV1(pll) / POST_DIV2(pll)) + +#define CLOCK_FREQ_clk_gpout0 DT_PROP(DT_INST_CLOCKS_CTLR_BY_NAME(0, clk_gpout0), clock_frequency) +#define CLOCK_FREQ_clk_gpout1 DT_PROP(DT_INST_CLOCKS_CTLR_BY_NAME(0, clk_gpout1), clock_frequency) +#define CLOCK_FREQ_clk_gpout2 DT_PROP(DT_INST_CLOCKS_CTLR_BY_NAME(0, clk_gpout2), clock_frequency) +#define CLOCK_FREQ_clk_gpout3 DT_PROP(DT_INST_CLOCKS_CTLR_BY_NAME(0, clk_gpout3), clock_frequency) +#define CLOCK_FREQ_clk_ref DT_PROP(DT_INST_CLOCKS_CTLR_BY_NAME(0, clk_ref), clock_frequency) +#define CLOCK_FREQ_clk_sys DT_PROP(DT_INST_CLOCKS_CTLR_BY_NAME(0, clk_sys), clock_frequency) +#define CLOCK_FREQ_clk_usb DT_PROP(DT_INST_CLOCKS_CTLR_BY_NAME(0, clk_usb), clock_frequency) +#define CLOCK_FREQ_clk_adc DT_PROP(DT_INST_CLOCKS_CTLR_BY_NAME(0, clk_adc), clock_frequency) +#define CLOCK_FREQ_clk_rtc DT_PROP(DT_INST_CLOCKS_CTLR_BY_NAME(0, clk_rtc), clock_frequency) +#define CLOCK_FREQ_clk_peri DT_PROP(DT_INST_CLOCKS_CTLR_BY_NAME(0, clk_peri), clock_frequency) +#define CLOCK_FREQ_xosc DT_PROP(DT_INST_CLOCKS_CTLR_BY_NAME(0, xosc), clock_frequency) +#define CLOCK_FREQ_rosc DT_PROP(DT_INST_CLOCKS_CTLR_BY_NAME(0, rosc), clock_frequency) +#define CLOCK_FREQ_rosc_ph DT_PROP(DT_INST_CLOCKS_CTLR_BY_NAME(0, rosc), clock_frequency) +#define CLOCK_FREQ_gpin0 DT_PROP(DT_INST_CLOCKS_CTLR_BY_NAME(0, gpin0), clock_frequency) +#define CLOCK_FREQ_gpin1 DT_PROP(DT_INST_CLOCKS_CTLR_BY_NAME(0, gpin1), clock_frequency) +#define CLOCK_FREQ_pll_sys PLL_FREQ(pll_sys) +#define CLOCK_FREQ_pll_usb PLL_FREQ(pll_usb) + +#define CLOCK_AUX_SOURCE(clk) _CONCAT(_CONCAT(AUXSTEM_, clk), _CONCAT(AUXSRC_, SRC_CLOCK(clk))) + +#define AUXSRC_xosc XOSC_CLKSRC +#define AUXSRC_rosc ROSC_CLKSRC +#define AUXSRC_rosc_ph ROSC_CLKSRC_PH +#define AUXSRC_pll_sys CLKSRC_PLL_SYS +#define AUXSRC_pll_usb CLKSRC_PLL_USB +#define AUXSRC_clk_ref CLK_REF +#define AUXSRC_clk_sys CLK_SYS +#define AUXSRC_clk_usb CLK_USB +#define AUXSRC_clk_adc CLK_ADC +#define AUXSRC_clk_rtc CLK_RTC +#define AUXSRC_clk_gpin0 CLKSRC_GPIN0 +#define AUXSRC_clk_gpin1 CLKSRC_GPIN1 + +#define AUXSTEM_clk_gpout0 CLOCKS_CLK_GPOUT0_CTRL_AUXSRC_VALUE_ +#define AUXSTEM_clk_gpout1 CLOCKS_CLK_GPOUT1_CTRL_AUXSRC_VALUE_ +#define AUXSTEM_clk_gpout2 CLOCKS_CLK_GPOUT2_CTRL_AUXSRC_VALUE_ +#define AUXSTEM_clk_gpout3 CLOCKS_CLK_GPOUT3_CTRL_AUXSRC_VALUE_ +#define AUXSTEM_clk_ref CLOCKS_CLK_REF_CTRL_AUXSRC_VALUE_ +#define AUXSTEM_clk_sys CLOCKS_CLK_SYS_CTRL_AUXSRC_VALUE_ +#define AUXSTEM_clk_usb CLOCKS_CLK_USB_CTRL_AUXSRC_VALUE_ +#define AUXSTEM_clk_adc CLOCKS_CLK_ADC_CTRL_AUXSRC_VALUE_ +#define AUXSTEM_clk_rtc CLOCKS_CLK_RTC_CTRL_AUXSRC_VALUE_ +#define AUXSTEM_clk_peri CLOCKS_CLK_PERI_CTRL_AUXSRC_VALUE_ + +#define TUPLE_ENTRY(n, p, i) \ + { \ + _CONCAT(RPI_PICO_CLKID_, DT_INST_STRING_UPPER_TOKEN_BY_IDX(0, clock_names, i)), \ + COND_CODE_1( \ + DT_PROP_HAS_IDX(DT_CLOCKS_CTLR_BY_IDX(DT_NODELABEL(clocks), i), \ + clocks, 0), \ + (_CONCAT(RPI_PICO_CLKID_, \ + DT_STRING_UPPER_TOKEN_BY_IDX( \ + DT_CLOCKS_CTLR_BY_IDX(DT_NODELABEL(clocks), i), \ + clock_names, 0))), \ + (-1)) \ + } + +enum rpi_pico_clkid { + rpi_pico_clkid_none = -1, + rpi_pico_clkid_clk_gpout0 = RPI_PICO_CLKID_CLK_GPOUT0, + rpi_pico_clkid_clk_gpout1 = RPI_PICO_CLKID_CLK_GPOUT1, + rpi_pico_clkid_clk_gpout2 = RPI_PICO_CLKID_CLK_GPOUT2, + rpi_pico_clkid_clk_gpout3 = RPI_PICO_CLKID_CLK_GPOUT3, + rpi_pico_clkid_clk_ref = RPI_PICO_CLKID_CLK_REF, + rpi_pico_clkid_clk_sys = RPI_PICO_CLKID_CLK_SYS, + rpi_pico_clkid_clk_peri = RPI_PICO_CLKID_CLK_PERI, + rpi_pico_clkid_clk_usb = RPI_PICO_CLKID_CLK_USB, + rpi_pico_clkid_clk_adc = RPI_PICO_CLKID_CLK_ADC, + rpi_pico_clkid_clk_rtc = RPI_PICO_CLKID_CLK_RTC, + rpi_pico_clkid_pll_sys = RPI_PICO_CLKID_PLL_SYS, + rpi_pico_clkid_pll_usb = RPI_PICO_CLKID_PLL_USB, + rpi_pico_clkid_xosc = RPI_PICO_CLKID_XOSC, + rpi_pico_clkid_rosc = RPI_PICO_CLKID_ROSC, + rpi_pico_clkid_rosc_ph = RPI_PICO_CLKID_ROSC_PH, + rpi_pico_clkid_gpin0 = RPI_PICO_CLKID_GPIN0, + rpi_pico_clkid_gpin1 = RPI_PICO_CLKID_GPIN1, + END_OF_RPI_PICO_CLKID, +}; + +struct rpi_pico_clkid_tuple { + enum rpi_pico_clkid clk; + enum rpi_pico_clkid parent; +}; + +struct rpi_pico_clk_config { + uint32_t source; + uint32_t aux_source; + uint32_t rate; + uint32_t source_rate; +}; + +struct rpi_pico_pll_config { + uint32_t ref_div; + uint32_t fb_div; + uint32_t post_div1; + uint32_t post_div2; +}; + +struct rpi_pico_rosc_config { + uint32_t phase; + uint32_t range; + uint32_t div; + uint32_t code; +}; + +struct rpi_pico_gpin_config { + uint32_t frequency; +}; + +struct clock_control_rpi_pico_config { + clocks_hw_t *const clocks_regs; + xosc_hw_t *const xosc_regs; + pll_hw_t *const pll_sys_regs; + pll_hw_t *const pll_usb_regs; + rosc_hw_t *const rosc_regs; + const struct pinctrl_dev_config *pcfg; + struct rpi_pico_pll_config plls_data[RPI_PICO_PLL_COUNT]; + struct rpi_pico_clk_config clocks_data[RPI_PICO_CLOCK_COUNT]; + struct rpi_pico_rosc_config rosc_data; + struct rpi_pico_gpin_config gpin_data[RPI_PICO_GPIN_COUNT]; +}; + +struct clock_control_rpi_pico_data { + uint32_t rosc_freq; + uint32_t rosc_ph_freq; +}; + +uint64_t rpi_pico_frequency_count(const struct device *dev, clock_control_subsys_t sys) +{ + const struct clock_control_rpi_pico_config *config = dev->config; + enum rpi_pico_clkid clkid = (enum rpi_pico_clkid)sys; + fc_hw_t *fc0 = &config->clocks_regs->fc0; + uint32_t fc0_id; + + switch (clkid) { + case rpi_pico_clkid_clk_ref: + fc0_id = CLOCKS_FC0_SRC_VALUE_CLK_REF; + break; + case rpi_pico_clkid_clk_sys: + fc0_id = CLOCKS_FC0_SRC_VALUE_CLK_SYS; + break; + case rpi_pico_clkid_clk_peri: + fc0_id = CLOCKS_FC0_SRC_VALUE_CLK_PERI; + break; + case rpi_pico_clkid_clk_usb: + fc0_id = CLOCKS_FC0_SRC_VALUE_CLK_USB; + break; + case rpi_pico_clkid_clk_adc: + fc0_id = CLOCKS_FC0_SRC_VALUE_CLK_ADC; + break; + case rpi_pico_clkid_clk_rtc: + fc0_id = CLOCKS_FC0_SRC_VALUE_CLK_RTC; + break; + case rpi_pico_clkid_pll_sys: + fc0_id = CLOCKS_FC0_SRC_VALUE_PLL_SYS_CLKSRC_PRIMARY; + break; + case rpi_pico_clkid_pll_usb: + fc0_id = CLOCKS_FC0_SRC_VALUE_PLL_USB_CLKSRC_PRIMARY; + break; + case rpi_pico_clkid_xosc: + fc0_id = CLOCKS_FC0_SRC_VALUE_XOSC_CLKSRC; + break; + case rpi_pico_clkid_rosc: + fc0_id = CLOCKS_FC0_SRC_VALUE_ROSC_CLKSRC; + break; + case rpi_pico_clkid_rosc_ph: + fc0_id = CLOCKS_FC0_SRC_VALUE_ROSC_CLKSRC_PH; + break; + case rpi_pico_clkid_gpin0: + fc0_id = CLOCKS_FC0_SRC_VALUE_CLKSRC_GPIN0; + break; + case rpi_pico_clkid_gpin1: + fc0_id = CLOCKS_FC0_SRC_VALUE_CLKSRC_GPIN0; + break; + default: + return -1; + } + + (void)frequency_count_khz(fc0_id); + + return ((fc0->result >> CLOCKS_FC0_RESULT_KHZ_LSB) * 1000) + + ((fc0->result & CLOCKS_FC0_RESULT_FRAC_BITS) * 1000 / CLOCKS_FC0_RESULT_FRAC_BITS); +} + +static int rpi_pico_rosc_write(const struct device *dev, io_rw_32 *addr, uint32_t value) +{ + hw_clear_bits(&rosc_hw->status, ROSC_STATUS_BADWRITE_BITS); + + if (rosc_hw->status & ROSC_STATUS_BADWRITE_BITS) { + return -EINVAL; + } + + *addr = value; + + if (rosc_hw->status & ROSC_STATUS_BADWRITE_BITS) { + return -EINVAL; + } + + return 0; +} + +/** + * Get source clock id of this clock + * + * @param dev pointer to clock device + * @param id id of this clock + * @return parent clock id + */ +static enum rpi_pico_clkid rpi_pico_get_clock_src(const struct device *dev, enum rpi_pico_clkid id) +{ + const struct clock_control_rpi_pico_config *config = dev->config; + enum rpi_pico_clkid srcid = rpi_pico_clkid_none; + + if (id == rpi_pico_clkid_clk_gpout0 || id == rpi_pico_clkid_clk_gpout1 || + id == rpi_pico_clkid_clk_gpout2 || id == rpi_pico_clkid_clk_gpout3) { + const static enum rpi_pico_clkid table[] = { + rpi_pico_clkid_pll_sys, + rpi_pico_clkid_gpin0, + rpi_pico_clkid_gpin1, + rpi_pico_clkid_pll_usb, + rpi_pico_clkid_rosc_ph, + rpi_pico_clkid_xosc, + rpi_pico_clkid_clk_sys, + rpi_pico_clkid_clk_usb, + rpi_pico_clkid_clk_adc, + rpi_pico_clkid_clk_rtc, + rpi_pico_clkid_clk_ref, + }; + + clock_hw_t *clock_hw = &config->clocks_regs->clk[id]; + uint32_t aux = ((clock_hw->ctrl & CTRL_AUXSRC_BITS) >> CTRL_AUXSRC_LSB); + + srcid = table[aux]; + } else if (id == rpi_pico_clkid_clk_ref) { + const static enum rpi_pico_clkid table[] = { + rpi_pico_clkid_pll_usb, + rpi_pico_clkid_gpin0, + rpi_pico_clkid_gpin1, + }; + + clock_hw_t *clock_hw = &clocks_hw->clk[id]; + uint32_t aux = ((clock_hw->ctrl & CTRL_AUXSRC_BITS) >> CTRL_AUXSRC_LSB); + uint32_t src = ((clock_hw->ctrl >> CTRL_SRC_LSB) & CTRL_SRC_BITS); + + if (src == CLOCKS_CLK_REF_CTRL_SRC_VALUE_ROSC_CLKSRC_PH) { + srcid = rpi_pico_clkid_rosc_ph; + } else if (src == CLOCKS_CLK_REF_CTRL_SRC_VALUE_XOSC_CLKSRC) { + srcid = rpi_pico_clkid_xosc; + } else { + srcid = table[aux]; + } + } else if (id == rpi_pico_clkid_clk_sys) { + const static enum rpi_pico_clkid table[] = { + rpi_pico_clkid_pll_sys, + rpi_pico_clkid_pll_usb, + rpi_pico_clkid_rosc, + rpi_pico_clkid_xosc, + rpi_pico_clkid_gpin0, + rpi_pico_clkid_gpin1, + }; + + clock_hw_t *clock_hw = &clocks_hw->clk[id]; + uint32_t aux = ((clock_hw->ctrl & CTRL_AUXSRC_BITS) >> CTRL_AUXSRC_LSB); + uint32_t src = ((clock_hw->ctrl >> CTRL_SRC_LSB) & CTRL_SRC_BITS); + + if (src == CLOCKS_CLK_SYS_CTRL_SRC_VALUE_CLK_REF) { + srcid = rpi_pico_clkid_clk_ref; + } else { + srcid = table[aux]; + } + } else if (id == rpi_pico_clkid_clk_peri) { + const static enum rpi_pico_clkid table[] = { + rpi_pico_clkid_clk_sys, + rpi_pico_clkid_pll_sys, + rpi_pico_clkid_pll_usb, + rpi_pico_clkid_rosc_ph, + rpi_pico_clkid_xosc, + rpi_pico_clkid_gpin0, + rpi_pico_clkid_gpin1, + }; + + clock_hw_t *clock_hw = &clocks_hw->clk[id]; + uint32_t aux = ((clock_hw->ctrl & CTRL_AUXSRC_BITS) >> CTRL_AUXSRC_LSB); + + srcid = table[aux]; + } else if (id == rpi_pico_clkid_clk_usb || id == rpi_pico_clkid_clk_adc || + id == rpi_pico_clkid_clk_rtc) { + const static enum rpi_pico_clkid table[] = { + rpi_pico_clkid_pll_usb, + rpi_pico_clkid_pll_sys, + rpi_pico_clkid_rosc_ph, + rpi_pico_clkid_xosc, + rpi_pico_clkid_gpin0, + rpi_pico_clkid_gpin1, + }; + + clock_hw_t *clock_hw = &clocks_hw->clk[id]; + uint32_t aux = ((clock_hw->ctrl & CTRL_AUXSRC_BITS) >> CTRL_AUXSRC_LSB); + + srcid = table[aux]; + } else if (id == rpi_pico_clkid_pll_sys || id == rpi_pico_clkid_pll_usb) { + srcid = rpi_pico_clkid_xosc; + } + + return srcid; +} + +/** + * Query clock is enabled or not + * + * @param dev pointer to clock device + * @param id id of clock + * @return true if the clock enabled, otherwith false + */ +static bool rpi_pico_is_clock_enabled(const struct device *dev, enum rpi_pico_clkid id) +{ + const struct clock_control_rpi_pico_config *config = dev->config; + + if (id == rpi_pico_clkid_clk_sys || id == rpi_pico_clkid_clk_ref) { + return true; + } else if (id == rpi_pico_clkid_clk_usb || + id == rpi_pico_clkid_clk_peri || + id == rpi_pico_clkid_clk_adc || + id == rpi_pico_clkid_clk_rtc || + id == rpi_pico_clkid_clk_gpout0 || + id == rpi_pico_clkid_clk_gpout1 || + id == rpi_pico_clkid_clk_gpout2 || + id == rpi_pico_clkid_clk_gpout3) { + clock_hw_t *clock_hw = &config->clocks_regs->clk[id]; + + if (clock_hw->ctrl & CTRL_ENABLE_BITS) { + return true; + } + } else if (id == rpi_pico_clkid_pll_sys || id == rpi_pico_clkid_pll_usb) { + pll_hw_t *pll = (id == rpi_pico_clkid_pll_sys) ? config->pll_sys_regs + : config->pll_usb_regs; + + if (!(pll->pwr & (PLL_PWR_VCOPD_BITS | PLL_PWR_POSTDIVPD_BITS | PLL_PWR_PD_BITS))) { + return true; + } + } else if (id == rpi_pico_clkid_xosc) { + if (config->xosc_regs->status & XOSC_STATUS_ENABLED_BITS) { + return true; + } + } else if (id == rpi_pico_clkid_rosc || id == rpi_pico_clkid_rosc_ph) { + return true; + } + + return false; +} + +/** + * Calculate clock frequency with traversing clock tree. + * + * @param dev pointer to clock device + * @param id id of clock + * @return frequency value or 0 if disabled + */ +static float rpi_pico_calc_clock_freq(const struct device *dev, enum rpi_pico_clkid id) +{ + const struct clock_control_rpi_pico_config *config = dev->config; + struct clock_control_rpi_pico_data *data = dev->data; + float freq = 0.f; + + if (!rpi_pico_is_clock_enabled(dev, id)) { + return freq; + } + + if (id == rpi_pico_clkid_clk_sys || + id == rpi_pico_clkid_clk_usb || + id == rpi_pico_clkid_clk_adc || + id == rpi_pico_clkid_clk_rtc || + id == rpi_pico_clkid_clk_ref || + id == rpi_pico_clkid_clk_gpout0 || + id == rpi_pico_clkid_clk_gpout1 || + id == rpi_pico_clkid_clk_gpout2 || + id == rpi_pico_clkid_clk_gpout3) { + clock_hw_t *clock_hw = &config->clocks_regs->clk[id]; + + freq = rpi_pico_calc_clock_freq(dev, rpi_pico_get_clock_src(dev, id)) / + (((clock_hw->div & DIV_INT_BITS) >> DIV_INT_LSB) + + ((clock_hw->div & DIV_FRAC_BITS) / (float)DIV_FRAC_BITS)); + } else if (id == rpi_pico_clkid_clk_peri) { + freq = rpi_pico_calc_clock_freq(dev, rpi_pico_get_clock_src(dev, id)); + } else if (id == rpi_pico_clkid_pll_sys || id == rpi_pico_clkid_pll_usb) { + pll_hw_t *pll = (id == rpi_pico_clkid_pll_sys) ? config->pll_sys_regs + : config->pll_usb_regs; + freq = rpi_pico_calc_clock_freq(dev, rpi_pico_get_clock_src(dev, id)) * + (pll->fbdiv_int) / (pll->cs & PLL_CS_REFDIV_BITS) / + ((pll->prim & PLL_PRIM_POSTDIV1_BITS) >> PLL_PRIM_POSTDIV1_LSB) / + ((pll->prim & PLL_PRIM_POSTDIV2_BITS) >> PLL_PRIM_POSTDIV2_LSB); + } else if (id == rpi_pico_clkid_xosc) { + freq = CLOCK_FREQ_xosc; + } else if (id == rpi_pico_clkid_rosc) { + freq = data->rosc_freq; + } else if (id == rpi_pico_clkid_rosc_ph) { + freq = data->rosc_ph_freq; + } + + return freq; +} + +static int rpi_pico_is_valid_clock_index(enum rpi_pico_clkid index) +{ + if (index >= END_OF_RPI_PICO_CLKID) { + return -EINVAL; + } + + return 0; +} + +static int clock_control_rpi_pico_on(const struct device *dev, clock_control_subsys_t sys) +{ + const struct clock_control_rpi_pico_config *config = dev->config; + enum rpi_pico_clkid clkid = (enum rpi_pico_clkid)sys; + clocks_hw_t *clocks_regs = config->clocks_regs; + + if (rpi_pico_is_valid_clock_index(clkid) < 0) { + return -EINVAL; + } + + hw_set_bits(&clocks_regs->clk[clkid].ctrl, CTRL_ENABLE_BITS); + + return 0; +} + +static int clock_control_rpi_pico_off(const struct device *dev, clock_control_subsys_t sys) +{ + const struct clock_control_rpi_pico_config *config = dev->config; + enum rpi_pico_clkid clkid = (enum rpi_pico_clkid)sys; + clocks_hw_t *clocks_regs = config->clocks_regs; + + if (rpi_pico_is_valid_clock_index(clkid) < 0) { + return -EINVAL; + } + + hw_clear_bits(&clocks_regs->clk[clkid].ctrl, CTRL_ENABLE_BITS); + + return 0; +} + +static enum clock_control_status clock_control_rpi_pico_get_status(const struct device *dev, + clock_control_subsys_t sys) +{ + enum rpi_pico_clkid clkid = (enum rpi_pico_clkid)sys; + + if (rpi_pico_is_valid_clock_index(clkid) < 0) { + return -EINVAL; + } + + if (rpi_pico_is_clock_enabled(dev, clkid)) { + return CLOCK_CONTROL_STATUS_ON; + } + + return CLOCK_CONTROL_STATUS_OFF; +} + +static int clock_control_rpi_pico_get_rate(const struct device *dev, clock_control_subsys_t sys, + uint32_t *rate) +{ + struct clock_control_rpi_pico_data *data = dev->data; + enum rpi_pico_clkid clkid = (enum rpi_pico_clkid)sys; + + if (rpi_pico_is_valid_clock_index(clkid) < 0) { + return -EINVAL; + } + + if (IS_ENABLED(CONFIG_RPI_PICO_ROSC_USE_MEASURED_FREQ)) { + if (clkid == rpi_pico_clkid_rosc) { + data->rosc_freq = rpi_pico_frequency_count(dev, sys); + } else if (clkid == rpi_pico_clkid_rosc_ph) { + data->rosc_ph_freq = rpi_pico_frequency_count(dev, sys); + } + } + + *rate = (int)rpi_pico_calc_clock_freq(dev, clkid); + + return 0; +} + +void rpi_pico_clkid_tuple_swap(struct rpi_pico_clkid_tuple *lhs, struct rpi_pico_clkid_tuple *rhs) +{ + struct rpi_pico_clkid_tuple tmp = *lhs; + *lhs = *rhs; + *rhs = tmp; +} + +void rpi_pico_clkid_tuple_reorder_by_dependencies(struct rpi_pico_clkid_tuple *tuples, size_t len) +{ + uint32_t sorted_idx = 0; + uint32_t checked_idx = 0; + uint32_t target = -1; + + while (sorted_idx < len) { + for (uint32_t i = sorted_idx; i < len; i++) { + if (tuples[i].parent == target) { + rpi_pico_clkid_tuple_swap(&tuples[sorted_idx], &tuples[i]); + sorted_idx++; + } + } + target = tuples[checked_idx++].clk; + } +} + +static int clock_control_rpi_pico_init(const struct device *dev) +{ + const struct clock_control_rpi_pico_config *config = dev->config; + struct clock_control_rpi_pico_data *data = dev->data; + clocks_hw_t *clocks_regs = config->clocks_regs; + rosc_hw_t *rosc_regs = config->rosc_regs; + pll_hw_t *plls[] = {config->pll_sys_regs, config->pll_usb_regs}; + struct rpi_pico_clkid_tuple tuples[] = { + DT_INST_FOREACH_PROP_ELEM_SEP(0, clock_names, TUPLE_ENTRY, (,))}; + uint32_t rosc_div; + int ret; + + /* Reset all function before clock configuring */ + reset_block(~(RESETS_RESET_IO_QSPI_BITS | RESETS_RESET_PADS_QSPI_BITS | + RESETS_RESET_PLL_USB_BITS | RESETS_RESET_USBCTRL_BITS | + RESETS_RESET_PLL_USB_BITS | RESETS_RESET_SYSCFG_BITS | + RESETS_RESET_PLL_SYS_BITS)); + + unreset_block_wait(RESETS_RESET_BITS & + ~(RESETS_RESET_ADC_BITS | RESETS_RESET_RTC_BITS | + RESETS_RESET_SPI0_BITS | RESETS_RESET_SPI1_BITS | + RESETS_RESET_UART0_BITS | RESETS_RESET_UART1_BITS | + RESETS_RESET_USBCTRL_BITS | RESETS_RESET_PWM_BITS)); + + /* Start tick in watchdog */ + watchdog_hw->tick = ((CLOCK_FREQ_xosc/1000000) | WATCHDOG_TICK_ENABLE_BITS); + + clocks_regs->resus.ctrl = 0; + + /* Configure xosc */ + xosc_init(); + + /* Before we touch PLLs, switch sys and ref cleanly away from their aux sources. */ + clocks_hw->clk[RPI_PICO_CLKID_CLK_SYS].ctrl &= ~CTRL_SRC_BITS; + while (clocks_hw->clk[RPI_PICO_CLKID_CLK_SYS].selected != 0x1) { + ; + } + clocks_hw->clk[RPI_PICO_CLKID_CLK_REF].ctrl &= ~CTRL_SRC_BITS; + while (clocks_hw->clk[RPI_PICO_CLKID_CLK_REF].selected != 0x1) { + ; + } + + /* Configure pll */ + for (uint32_t i = 0; i < RPI_PICO_PLL_COUNT; i++) { + pll_init(plls[i], config->plls_data[i].ref_div, + CLOCK_FREQ_xosc * config->plls_data[i].fb_div, + config->plls_data[i].post_div1, config->plls_data[i].post_div2); + } + + /* Configure clocks */ + rpi_pico_clkid_tuple_reorder_by_dependencies(tuples, ARRAY_SIZE(tuples)); + for (uint32_t i = 0; i < ARRAY_SIZE(tuples); i++) { + if (tuples[i].clk < 0 || tuples[i].clk >= RPI_PICO_CLOCK_COUNT) { + continue; + } + + if (!(clock_configure(tuples[i].clk, config->clocks_data[tuples[i].clk].source, + config->clocks_data[tuples[i].clk].aux_source, + config->clocks_data[tuples[i].clk].source_rate, + config->clocks_data[tuples[i].clk].rate))) { + return -EINVAL; + } + } + + hw_clear_bits(&clocks_regs->clk[rpi_pico_clkid_clk_gpout0].ctrl, CTRL_ENABLE_BITS); + hw_clear_bits(&clocks_regs->clk[rpi_pico_clkid_clk_gpout1].ctrl, CTRL_ENABLE_BITS); + hw_clear_bits(&clocks_regs->clk[rpi_pico_clkid_clk_gpout2].ctrl, CTRL_ENABLE_BITS); + hw_clear_bits(&clocks_regs->clk[rpi_pico_clkid_clk_gpout3].ctrl, CTRL_ENABLE_BITS); + + /* Configure rosc */ + ret = rpi_pico_rosc_write(dev, &rosc_regs->phase, + (ROSC_PHASE_PASSWD_VALUE_PASS << ROSC_PHASE_PASSWD_LSB) | + config->rosc_data.phase); + if (ret < 0) { + return ret; + } + + ret = rpi_pico_rosc_write(dev, &rosc_regs->ctrl, + (ROSC_CTRL_ENABLE_VALUE_ENABLE << ROSC_CTRL_ENABLE_LSB) | + config->rosc_data.range); + if (ret < 0) { + return ret; + } + + if (config->rosc_data.div <= 0) { + rosc_div = ROSC_DIV_VALUE_PASS + 1; + } else if (config->rosc_data.div > 31) { + rosc_div = ROSC_DIV_VALUE_PASS; + } else { + rosc_div = ROSC_DIV_VALUE_PASS + config->rosc_data.div; + } + + ret = rpi_pico_rosc_write(dev, &rosc_regs->div, rosc_div); + if (ret < 0) { + return ret; + } + + ret = rpi_pico_rosc_write(dev, &rosc_regs->freqa, + (ROSC_FREQA_PASSWD_VALUE_PASS << ROSC_FREQA_PASSWD_LSB) | + (config->rosc_data.code & UINT16_MAX)); + if (ret < 0) { + return ret; + } + + ret = rpi_pico_rosc_write(dev, &rosc_regs->freqb, + (ROSC_FREQA_PASSWD_VALUE_PASS << ROSC_FREQA_PASSWD_LSB) | + (config->rosc_data.code >> 16)); + if (ret < 0) { + return ret; + } + + unreset_block_wait(RESETS_RESET_BITS); + + if (IS_ENABLED(CONFIG_RPI_PICO_ROSC_USE_MEASURED_FREQ)) { + data->rosc_freq = + rpi_pico_frequency_count(dev, (clock_control_subsys_t)rpi_pico_clkid_rosc); + data->rosc_ph_freq = rpi_pico_frequency_count( + dev, (clock_control_subsys_t)rpi_pico_clkid_rosc_ph); + } + + return 0; +} + +static const struct clock_control_driver_api clock_control_rpi_pico_api = { + .on = clock_control_rpi_pico_on, + .off = clock_control_rpi_pico_off, + .get_rate = clock_control_rpi_pico_get_rate, + .get_status = clock_control_rpi_pico_get_status, +}; + +BUILD_ASSERT((VCO_FREQ(pll_sys) >= PLL_VCO_FREQ_MIN) && (VCO_FREQ(pll_sys) <= PLL_VCO_FREQ_MAX) && + (VCO_FREQ(pll_sys) >= (CLOCK_FREQ_xosc / REF_DIV(pll_sys) * 16)), + "pll_sys: vco_freq is out of range"); +BUILD_ASSERT((FB_DIV(pll_sys) >= PLL_FB_DIV_MIN) && (FB_DIV(pll_sys) <= PLL_FB_DIV_MAX), + "pll_sys: fb-div is out of range"); +BUILD_ASSERT((POST_DIV1(pll_sys) >= PLL_POST_DIV_MIN) && (POST_DIV1(pll_sys) <= PLL_POST_DIV_MAX), + "pll_sys: post-div1 is out of range"); +BUILD_ASSERT((POST_DIV2(pll_sys) >= PLL_POST_DIV_MIN) && (POST_DIV2(pll_sys) <= PLL_POST_DIV_MAX), + "pll_sys: post-div2 is out of range"); + +BUILD_ASSERT((VCO_FREQ(pll_usb) >= PLL_VCO_FREQ_MIN) && (VCO_FREQ(pll_usb) <= PLL_VCO_FREQ_MAX) && + (VCO_FREQ(pll_usb) >= (CLOCK_FREQ_xosc / REF_DIV(pll_usb) * 16)), + "pll_usb: vco_freq is out of range"); +BUILD_ASSERT((FB_DIV(pll_usb) >= PLL_FB_DIV_MIN) && (FB_DIV(pll_usb) <= PLL_FB_DIV_MAX), + "pll_usb: fb-div is out of range"); +BUILD_ASSERT((POST_DIV1(pll_usb) >= PLL_POST_DIV_MIN) && (POST_DIV1(pll_usb) <= PLL_POST_DIV_MAX), + "pll_usb: post-div is out of range"); +BUILD_ASSERT((POST_DIV2(pll_usb) >= PLL_POST_DIV_MIN) && (POST_DIV2(pll_usb) <= PLL_POST_DIV_MAX), + "pll_usb: post-div is out of range"); + +BUILD_ASSERT(SRC_CLOCK_FREQ(clk_ref) >= CLOCK_FREQ_clk_ref, + "clk_ref: clock divider is out of range"); +BUILD_ASSERT(SRC_CLOCK_FREQ(clk_sys) >= CLOCK_FREQ_clk_sys, + "clk_sys: clock divider is out of range"); +BUILD_ASSERT(SRC_CLOCK_FREQ(clk_usb) >= CLOCK_FREQ_clk_usb, + "clk_usb: clock divider is out of range"); +BUILD_ASSERT(SRC_CLOCK_FREQ(clk_adc) >= CLOCK_FREQ_clk_adc, + "clk_adc: clock divider is out of range"); +BUILD_ASSERT(SRC_CLOCK_FREQ(clk_rtc) >= CLOCK_FREQ_clk_rtc, + "clk_rtc: clock divider is out of range"); +BUILD_ASSERT(SRC_CLOCK_FREQ(clk_peri) >= CLOCK_FREQ_clk_peri, + "clk_peri: clock divider is out of range"); + +BUILD_ASSERT(CLOCK_FREQ(rosc_ph) == CLOCK_FREQ(rosc), "rosc_ph: frequency must be equal to rosc"); + +static const struct clock_control_rpi_pico_config clock_control_rpi_pico_config = { + .clocks_regs = (clocks_hw_t *)DT_INST_REG_ADDR_BY_NAME(0, clocks), + .xosc_regs = (xosc_hw_t *)DT_INST_REG_ADDR_BY_NAME(0, xosc), + .pll_sys_regs = (pll_hw_t *)DT_INST_REG_ADDR_BY_NAME(0, pll_sys), + .pll_usb_regs = (pll_hw_t *)DT_INST_REG_ADDR_BY_NAME(0, pll_usb), + .rosc_regs = (rosc_hw_t *)DT_INST_REG_ADDR_BY_NAME(0, rosc), + .clocks_data = { + [RPI_PICO_CLKID_CLK_GPOUT0] = { + .source = 0, + .aux_source = CLOCK_AUX_SOURCE(clk_gpout0), + .source_rate = SRC_CLOCK_FREQ(clk_gpout0), + .rate = CLOCK_FREQ(clk_gpout0), + }, + [RPI_PICO_CLKID_CLK_GPOUT1] = { + .source = 0, + .aux_source = CLOCK_AUX_SOURCE(clk_gpout1), + .source_rate = SRC_CLOCK_FREQ(clk_gpout1), + .rate = CLOCK_FREQ(clk_gpout1), + }, + [RPI_PICO_CLKID_CLK_GPOUT2] = { + .source = 0, + .aux_source = CLOCK_AUX_SOURCE(clk_gpout2), + .source_rate = SRC_CLOCK_FREQ(clk_gpout2), + .rate = CLOCK_FREQ(clk_gpout2), + }, + [RPI_PICO_CLKID_CLK_GPOUT3] = { + .source = 0, + .aux_source = CLOCK_AUX_SOURCE(clk_gpout3), + .source_rate = SRC_CLOCK_FREQ(clk_gpout3), + .rate = CLOCK_FREQ(clk_gpout3), + }, + [RPI_PICO_CLKID_CLK_REF] = { +#if CLK_SRC_IS(clk_ref, rosc_ph) + .source = CLOCKS_CLK_REF_CTRL_SRC_VALUE_ROSC_CLKSRC_PH, + .aux_source = 0, +#elif CLK_SRC_IS(clk_ref, xosc) + .source = CLOCKS_CLK_REF_CTRL_SRC_VALUE_XOSC_CLKSRC, + .aux_source = 0, +#else + .source = CLOCKS_CLK_REF_CTRL_SRC_VALUE_CLKSRC_CLK_REF_AUX, +#endif + .source_rate = SRC_CLOCK_FREQ(clk_ref), + .rate = CLOCK_FREQ(clk_ref), + }, + [RPI_PICO_CLKID_CLK_SYS] = { +#if CLK_SRC_IS(clk_sys, clk_ref) + .source = CLOCKS_CLK_SYS_CTRL_SRC_VALUE_CLK_REF, + .aux_source = 0, +#else + .source = CLOCKS_CLK_SYS_CTRL_SRC_VALUE_CLKSRC_CLK_SYS_AUX, + .aux_source = CLOCK_AUX_SOURCE(clk_sys), +#endif + .source_rate = SRC_CLOCK_FREQ(clk_sys), + .rate = CLOCK_FREQ(clk_sys), + }, + [RPI_PICO_CLKID_CLK_PERI] = { + .source = 0, + .aux_source = CLOCK_AUX_SOURCE(clk_peri), + .source_rate = SRC_CLOCK_FREQ(clk_peri), + .rate = CLOCK_FREQ(clk_peri), + }, + [RPI_PICO_CLKID_CLK_USB] = { + .source = 0, + .aux_source = CLOCK_AUX_SOURCE(clk_usb), + .source_rate = SRC_CLOCK_FREQ(clk_usb), + .rate = CLOCK_FREQ(clk_usb), + }, + [RPI_PICO_CLKID_CLK_ADC] = { + .source = 0, + .aux_source = CLOCK_AUX_SOURCE(clk_adc), + .source_rate = SRC_CLOCK_FREQ(clk_adc), + .rate = CLOCK_FREQ(clk_adc), + }, + [RPI_PICO_CLKID_CLK_RTC] = { + .source = 0, + .aux_source = CLOCK_AUX_SOURCE(clk_rtc), + .source_rate = SRC_CLOCK_FREQ(clk_rtc), + .rate = CLOCK_FREQ(clk_rtc), + }, + }, + .plls_data = { + [RPI_PICO_PLL_SYS] = { + .ref_div = DT_PROP(DT_INST_CLOCKS_CTLR_BY_NAME(0, pll_sys), clock_div), + .fb_div = DT_PROP(DT_INST_CLOCKS_CTLR_BY_NAME(0, pll_sys), fb_div), + .post_div1 = DT_PROP(DT_INST_CLOCKS_CTLR_BY_NAME(0, pll_sys), post_div1), + .post_div2 = DT_PROP(DT_INST_CLOCKS_CTLR_BY_NAME(0, pll_sys), post_div2), + }, + [RPI_PICO_PLL_USB] = { + .ref_div = DT_PROP(DT_INST_CLOCKS_CTLR_BY_NAME(0, pll_usb), clock_div), + .fb_div = DT_PROP(DT_INST_CLOCKS_CTLR_BY_NAME(0, pll_usb), fb_div), + .post_div1 = DT_PROP(DT_INST_CLOCKS_CTLR_BY_NAME(0, pll_usb), post_div1), + .post_div2 = DT_PROP(DT_INST_CLOCKS_CTLR_BY_NAME(0, pll_usb), post_div2), + }, + }, + .rosc_data = { + .phase = (COND_CODE_1(DT_NODE_HAS_PROP(DT_INST_CLOCKS_CTLR_BY_NAME(0, rosc), + phase_flip), + (ROSC_PHASE_FLIP_BITS), (0x0)) | + COND_CODE_1(DT_NODE_HAS_PROP(DT_INST_CLOCKS_CTLR_BY_NAME(0, rosc), + phase), + ((DT_PROP(DT_INST_CLOCKS_CTLR_BY_NAME(0, rosc), phase) & + ROSC_PHASE_SHIFT_BITS) | ROSC_PHASE_ENABLE_BITS), (0x0))), + .div = DT_PROP(DT_INST_CLOCKS_CTLR_BY_NAME(0, rosc), clock_div), + .range = DT_PROP(DT_INST_CLOCKS_CTLR_BY_NAME(0, rosc), range), + .code = (STAGE_DS(0) | STAGE_DS(1) | STAGE_DS(2) | STAGE_DS(3) | + STAGE_DS(4) | STAGE_DS(5) | STAGE_DS(6) | STAGE_DS(7)), + }, + .gpin_data = { + [RPI_PICO_GPIN_0] = { + COND_CODE_1(DT_NODE_HAS_PROP(DT_INST_CLOCKS_CTLR_BY_NAME(0, gpin0), + clock_frequency), + (.frequency = DT_PROP(DT_INST_CLOCKS_CTLR_BY_NAME(0, gpin0), + clock_frequency),), + (.frequency = 0,)) + }, + [RPI_PICO_GPIN_1] = { + COND_CODE_1(DT_NODE_HAS_PROP(DT_INST_CLOCKS_CTLR_BY_NAME(0, gpin1), + clock_frequency), + (.frequency = DT_PROP(DT_INST_CLOCKS_CTLR_BY_NAME(0, gpin1), + clock_frequency),), + (.frequency = 0,)) + }, + }, +}; + +static struct clock_control_rpi_pico_data clock_control_rpi_pico_data = { + .rosc_freq = CLOCK_FREQ(rosc), + .rosc_ph_freq = CLOCK_FREQ(rosc_ph), +}; + +DEVICE_DT_INST_DEFINE(0, &clock_control_rpi_pico_init, NULL, &clock_control_rpi_pico_data, + &clock_control_rpi_pico_config, PRE_KERNEL_1, + CONFIG_CLOCK_CONTROL_INIT_PRIORITY, &clock_control_rpi_pico_api); diff --git a/dts/arm/rpi_pico/rp2040.dtsi b/dts/arm/rpi_pico/rp2040.dtsi index 34a09a24dc9..72c71bfcfdc 100644 --- a/dts/arm/rpi_pico/rp2040.dtsi +++ b/dts/arm/rpi_pico/rp2040.dtsi @@ -7,6 +7,7 @@ #include #include #include +#include #include #include #include @@ -33,6 +34,149 @@ }; }; + clocks { + clk_gpout0: clk-gpout0 { + compatible = "raspberrypi,pico-clock"; + clocks = <&pll_sys>; + clock-names = "pll_sys"; + clock-frequency = <125000000>; + #clock-cells = <0>; + #address-cells = <0>; + }; + + clk_gpout1: clk-gpout1 { + compatible = "raspberrypi,pico-clock"; + clocks = <&pll_sys>; + clock-names = "pll_sys"; + clock-frequency = <125000000>; + #clock-cells = <0>; + }; + + clk_gpout2: clk-gpout2 { + compatible = "raspberrypi,pico-clock"; + clocks = <&pll_sys>; + clock-names = "pll_sys"; + clock-frequency = <125000000>; + #clock-cells = <0>; + }; + + clk_gpout3: clk-gpout3 { + compatible = "raspberrypi,pico-clock"; + clocks = <&pll_sys>; + clock-names = "pll_sys"; + clock-frequency = <125000000>; + #clock-cells = <0>; + }; + + clk_ref: clk-ref { + compatible = "raspberrypi,pico-clock"; + clocks = <&xosc>; + clock-names = "xosc"; + clock-frequency = <12000000>; + #clock-cells = <0>; + }; + + clk_sys: clk-sys { + compatible = "raspberrypi,pico-clock"; + clocks = <&pll_sys>; + clock-names = "pll_sys"; + clock-frequency = <125000000>; + #clock-cells = <0>; + }; + + clk_usb: clk-usb { + compatible = "raspberrypi,pico-clock"; + clocks = <&pll_usb>; + clock-names = "pll_usb"; + clock-frequency = <48000000>; + #clock-cells = <0>; + }; + + clk_adc: clk-adc { + compatible = "raspberrypi,pico-clock"; + clocks = <&pll_usb>; + clock-names = "pll_usb"; + clock-frequency = <48000000>; + #clock-cells = <0>; + }; + + clk_rtc: clk-rtc { + compatible = "raspberrypi,pico-clock"; + clocks = <&pll_usb>; + clock-names = "pll_usb"; + clock-frequency = <46875>; + #clock-cells = <0>; + }; + + clk_peri: clk-peri { + compatible = "raspberrypi,pico-clock"; + clocks = <&clk_sys>; + clock-names = "clk_sys"; + clock-frequency = <125000000>; + #clock-cells = <0>; + }; + + pll_sys: pll-sys { + compatible = "raspberrypi,pico-pll"; + clocks = <&xosc>; + clock-names = "xosc"; + clock-div= <1>; + fb-div= <125>; + post-div1 = <6>; + post-div2 = <2>; + #clock-cells = <0>; + }; + + pll_usb: pll-usb { + compatible = "raspberrypi,pico-pll"; + clocks = <&xosc>; + clock-names = "xosc"; + clock-div= <1>; + fb-div = <100>; + post-div1 = <5>; + post-div2 = <5>; + #clock-cells = <0>; + }; + + rosc: rosc { + compatible = "raspberrypi,pico-rosc"; + clock-frequency = <6500000>; + range = ; + stage-drive-strength = <0>, <0>, <0>, <0>, <0>, <0>, <0>, <0>; + clock-div = <16>; + phase = <0>; + #clock-cells = <0>; + }; + + rosc_ph: rosc-ph { + compatible = "raspberrypi,pico-clock"; + clock-frequency = <6500000>; + clocks = <&rosc>; + clock-names = "rosc"; + #clock-cells = <0>; + }; + + xosc: xosc { + compatible = "raspberrypi,pico-clock"; + clock-frequency = <12000000>; + #clock-cells = <0>; + }; + + gpin0: gpin0 { + compatible = "raspberrypi,pico-clock"; + status = "disabled"; + clock-frequency = <0>; + #clock-cells = <0>; + }; + + gpin1: gpin1 { + compatible = "raspberrypi,pico-clock"; + status = "disabled"; + clock-frequency = <0>; + #clock-cells = <0>; + }; + }; + soc { compatible = "raspberrypi,rp2040", "simple-bus"; @@ -55,18 +199,6 @@ }; }; - peripheral_clk: peripheral-clk { - compatible = "fixed-clock"; - clock-frequency = <125000000>; - #clock-cells = <0>; - }; - - system_clk: system-clk { - compatible = "fixed-clock"; - clock-frequency = <125000000>; - #clock-cells = <0>; - }; - reset: reset-controller@4000c000 { compatible = "raspberrypi,pico-reset"; reg = <0x4000c000 DT_SIZE_K(4)>; @@ -75,6 +207,28 @@ #reset-cells = <1>; }; + clocks: clock-controller@40008000 { + compatible = "raspberrypi,pico-clock-controller"; + reg = <0x40008000 DT_SIZE_K(4) + 0x40024000 DT_SIZE_K(4) + 0x40028000 DT_SIZE_K(4) + 0x4002c000 DT_SIZE_K(4) + 0x40060000 DT_SIZE_K(4)>; + reg-names = "clocks", "xosc", "pll_sys", "pll_usb", "rosc"; + #clock-cells = <1>; + status = "okay"; + clocks = <&clk_gpout0>, <&clk_gpout1>, <&clk_gpout2>, <&clk_gpout3>, + <&clk_ref>, <&clk_sys>, <&clk_peri>, + <&clk_usb>, <&clk_adc>, <&clk_rtc>, + <&pll_sys>, <&pll_usb>, <&xosc>, <&rosc>, <&rosc_ph>, + <&gpin0>, <&gpin1>; + clock-names = "clk_gpout0", "clk_gpout1", "clk_gpout2", "clk_gpout3", + "clk_ref", "clk_sys", "clk_peri", + "clk_usb", "clk_adc", "clk_rtc", + "pll_sys", "pll_usb", "xosc", "rosc", "rosc_ph", + "gpin0", "gpin1"; + }; + gpio0: gpio@40014000 { compatible = "raspberrypi,pico-gpio"; reg = <0x40014000 DT_SIZE_K(4)>; @@ -88,7 +242,7 @@ uart0: uart@40034000 { compatible = "raspberrypi,pico-uart"; reg = <0x40034000 DT_SIZE_K(4)>; - clocks = <&peripheral_clk>; + clocks = <&clocks RPI_PICO_CLKID_CLK_PERI>; resets = <&reset RPI_PICO_RESETS_RESET_UART0>; interrupts = <20 RPI_PICO_DEFAULT_IRQ_PRIORITY>; interrupt-names = "uart0"; @@ -98,7 +252,7 @@ uart1: uart@40038000 { compatible = "raspberrypi,pico-uart"; reg = <0x40038000 DT_SIZE_K(4)>; - clocks = <&peripheral_clk>; + clocks = <&clocks RPI_PICO_CLKID_CLK_PERI>; resets = <&reset RPI_PICO_RESETS_RESET_UART1>; interrupts = <21 RPI_PICO_DEFAULT_IRQ_PRIORITY>; interrupt-names = "uart1"; @@ -110,7 +264,7 @@ #address-cells = <1>; #size-cells = <0>; reg = <0x4003c000 DT_SIZE_K(4)>; - clocks = <&peripheral_clk>; + clocks = <&clocks RPI_PICO_CLKID_CLK_PERI>; resets = <&reset RPI_PICO_RESETS_RESET_SPI0>; interrupts = <18 RPI_PICO_DEFAULT_IRQ_PRIORITY>; interrupt-names = "spi0"; @@ -123,7 +277,7 @@ #size-cells = <0>; reg = <0x40040000 DT_SIZE_K(4)>; resets = <&reset RPI_PICO_RESETS_RESET_SPI1>; - clocks = <&peripheral_clk>; + clocks = <&clocks RPI_PICO_CLKID_CLK_PERI>; interrupts = <19 RPI_PICO_DEFAULT_IRQ_PRIORITY>; interrupt-names = "spi1"; status = "disabled"; @@ -133,6 +287,7 @@ compatible = "raspberrypi,pico-adc"; reg = <0x4004c000 DT_SIZE_K(4)>; resets = <&reset RPI_PICO_RESETS_RESET_ADC>; + clocks = <&clocks RPI_PICO_CLKID_CLK_ADC>; interrupts = <22 RPI_PICO_DEFAULT_IRQ_PRIORITY>; interrupt-names = "adc0"; status = "disabled"; @@ -145,7 +300,7 @@ #size-cells = <0>; reg = <0x40044000 DT_SIZE_K(4)>; resets = <&reset RPI_PICO_RESETS_RESET_I2C0>; - clocks = <&system_clk>; + clocks = <&clocks RPI_PICO_CLKID_CLK_SYS>; interrupts = <23 RPI_PICO_DEFAULT_IRQ_PRIORITY>; interrupt-names = "i2c0"; status = "disabled"; @@ -157,7 +312,7 @@ #size-cells = <0>; reg = <0x40048000 DT_SIZE_K(4)>; resets = <&reset RPI_PICO_RESETS_RESET_I2C0>; - clocks = <&system_clk>; + clocks = <&clocks RPI_PICO_CLKID_CLK_SYS>; interrupts = <24 RPI_PICO_DEFAULT_IRQ_PRIORITY>; interrupt-names = "i2c1"; status = "disabled"; @@ -166,7 +321,7 @@ wdt0: watchdog@40058000 { compatible = "raspberrypi,pico-watchdog"; reg = <0x40058000 DT_SIZE_K(4)>; - clocks = <&xtal_clk>; + clocks = <&clocks RPI_PICO_CLKID_CLK_REF>; status = "disabled"; }; @@ -174,6 +329,7 @@ compatible = "raspberrypi,pico-usbd"; reg = <0x50100000 0x10000>; resets = <&reset RPI_PICO_RESETS_RESET_USBCTRL>; + clocks = <&clocks RPI_PICO_CLKID_CLK_USB>; interrupts = <5 RPI_PICO_DEFAULT_IRQ_PRIORITY>; interrupt-names = "usbctrl"; num-bidir-endpoints = <16>; @@ -184,7 +340,7 @@ compatible = "raspberrypi,pico-pwm"; reg = <0x40050000 DT_SIZE_K(4)>; resets = <&reset RPI_PICO_RESETS_RESET_PWM>; - clocks = <&system_clk>; + clocks = <&clocks RPI_PICO_CLKID_CLK_SYS>; interrupts = <4 RPI_PICO_DEFAULT_IRQ_PRIORITY>; interrupt-names = "PWM_IRQ_WRAP"; status = "disabled"; @@ -195,7 +351,7 @@ compatible = "raspberrypi,pico-timer"; reg = <0x40054000 DT_SIZE_K(4)>; resets = <&reset RPI_PICO_RESETS_RESET_TIMER>; - clocks = <&xtal_clk>; + clocks = <&clocks RPI_PICO_CLKID_CLK_REF>; interrupts = <0 RPI_PICO_DEFAULT_IRQ_PRIORITY>, <1 RPI_PICO_DEFAULT_IRQ_PRIORITY>, <2 RPI_PICO_DEFAULT_IRQ_PRIORITY>, @@ -211,7 +367,7 @@ compatible = "raspberrypi,pico-dma"; reg = <0x50000000 DT_SIZE_K(64)>; resets = <&reset RPI_PICO_RESETS_RESET_DMA>; - clocks = <&system_clk>; + clocks = <&clocks RPI_PICO_CLKID_CLK_SYS>; interrupts = <11 RPI_PICO_DEFAULT_IRQ_PRIORITY>, <12 RPI_PICO_DEFAULT_IRQ_PRIORITY>; interrupt-names = "dma0", "dma1"; @@ -231,7 +387,7 @@ pio0: pio@50200000 { compatible = "raspberrypi,pico-pio"; reg = <0x50200000 DT_SIZE_K(4)>; - clocks = <&system_clk>; + clocks = <&clocks RPI_PICO_CLKID_CLK_SYS>; resets = <&reset RPI_PICO_RESETS_RESET_PIO0>; status = "disabled"; }; @@ -239,7 +395,7 @@ pio1: pio@50300000 { compatible = "raspberrypi,pico-pio"; reg = <0x50300000 DT_SIZE_K(4)>; - clocks = <&system_clk>; + clocks = <&clocks RPI_PICO_CLKID_CLK_SYS>; resets = <&reset RPI_PICO_RESETS_RESET_PIO1>; status = "disabled"; }; diff --git a/dts/bindings/clock/raspberrypi,pico-clock-controller.yaml b/dts/bindings/clock/raspberrypi,pico-clock-controller.yaml new file mode 100644 index 00000000000..cf740654949 --- /dev/null +++ b/dts/bindings/clock/raspberrypi,pico-clock-controller.yaml @@ -0,0 +1,18 @@ +# Copyright (c) 2022 Andrei-Edward Popa +# SPDX-License-Identifier: Apache-2.0 + +description: Raspberry Pi Pico clock controller node + +compatible: "raspberrypi,pico-clock-controller" + +include: [base.yaml, clock-controller.yaml] + +properties: + reg: + required: true + + "#clock-cells": + const: 1 + +clock-cells: + - clk-id diff --git a/dts/bindings/clock/raspberrypi,pico-clock.yaml b/dts/bindings/clock/raspberrypi,pico-clock.yaml new file mode 100644 index 00000000000..c787f3c7e81 --- /dev/null +++ b/dts/bindings/clock/raspberrypi,pico-clock.yaml @@ -0,0 +1,18 @@ +# Copyright (c) 2023 TOKITA Hiroshi +# SPDX-License-Identifier: Apache-2.0 + +description: | + The representation of Raspberry Pi Pico's clock + +compatible: "raspberrypi,pico-clock" + +include: fixed-clock.yaml + +properties: + clocks: + type: phandle-array + description: Clock gate information + + clock-names: + type: string-array + description: name of each clock diff --git a/dts/bindings/clock/raspberrypi,pico-pll.yaml b/dts/bindings/clock/raspberrypi,pico-pll.yaml new file mode 100644 index 00000000000..d3859802c7d --- /dev/null +++ b/dts/bindings/clock/raspberrypi,pico-pll.yaml @@ -0,0 +1,31 @@ +# Copyright (c) 2023 TOKITA Hiroshi +# SPDX-License-Identifier: Apache-2.0 + +description: | + The representation of Raspberry Pi Pico's PLL. + +compatible: "raspberrypi,pico-pll" + +include: [base.yaml, fixed-factor-clock.yaml] + +properties: + fb-div: + type: int + required: true + description: | + The feedback divider value. + The valid range is 16 to 320. + + post-div1: + type: int + required: true + description: | + The post clock divider. + The valid range is 1 to 49. + + post-div2: + type: int + required: true + description: | + The post clock divider. + The valid range is 1 to 49. diff --git a/dts/bindings/clock/raspberrypi,pico-rosc.yaml b/dts/bindings/clock/raspberrypi,pico-rosc.yaml new file mode 100644 index 00000000000..189ba12c0f5 --- /dev/null +++ b/dts/bindings/clock/raspberrypi,pico-rosc.yaml @@ -0,0 +1,38 @@ +# Copyright (c) 2023 TOKITA Hiroshi +# SPDX-License-Identifier: Apache-2.0 + +description: | + The representation of Raspberry Pi Pico ring oscillator. + +compatible: "raspberrypi,pico-rosc" + +include: [fixed-clock.yaml, fixed-factor-clock.yaml] + +properties: + range: + type: int + required: true + description: | + Specify the number of ring oscillator stages to use. + - LOW: 8 (default) + - MEDIUM: 6 + - HIGH: 4 + - TOOHIGH: 2 + + stage-drive-strength: + type: array + required: true + description: | + Specifies the drive strength of the eight stages of the ring oscillator. + The valid range of each value is between 0 and 7. + + phase-flip: + type: boolean + description: | + Flipping phase-shifter output. + + phase: + type: int + description: | + The phase-shift vlaue. + The valid range is 0 to 3 diff --git a/include/zephyr/dt-bindings/clock/rpi_pico_clock.h b/include/zephyr/dt-bindings/clock/rpi_pico_clock.h new file mode 100644 index 00000000000..07522be6632 --- /dev/null +++ b/include/zephyr/dt-bindings/clock/rpi_pico_clock.h @@ -0,0 +1,44 @@ +/* + * Copyright (c) 2022 Andrei-Edward Popa + * + * SPDX-License-Identifier: Apache-2.0 + */ +#ifndef ZEPHYR_INCLUDE_DT_BINDINGS_CLOCK_RPI_PICO_CLOCK_H_ +#define ZEPHYR_INCLUDE_DT_BINDINGS_CLOCK_RPI_PICO_CLOCK_H_ + +#define RPI_PICO_PLL_SYS 0 +#define RPI_PICO_PLL_USB 1 +#define RPI_PICO_PLL_COUNT 2 + +#define RPI_PICO_GPIN_0 0 +#define RPI_PICO_GPIN_1 1 +#define RPI_PICO_GPIN_COUNT 2 + +#define RPI_PICO_CLKID_CLK_GPOUT0 0 +#define RPI_PICO_CLKID_CLK_GPOUT1 1 +#define RPI_PICO_CLKID_CLK_GPOUT2 2 +#define RPI_PICO_CLKID_CLK_GPOUT3 3 +#define RPI_PICO_CLKID_CLK_REF 4 +#define RPI_PICO_CLKID_CLK_SYS 5 +#define RPI_PICO_CLKID_CLK_PERI 6 +#define RPI_PICO_CLKID_CLK_USB 7 +#define RPI_PICO_CLKID_CLK_ADC 8 +#define RPI_PICO_CLKID_CLK_RTC 9 + +#define RPI_PICO_CLKID_PLL_SYS 10 +#define RPI_PICO_CLKID_PLL_USB 11 +#define RPI_PICO_CLKID_XOSC 12 +#define RPI_PICO_CLKID_ROSC 13 +#define RPI_PICO_CLKID_ROSC_PH 14 +#define RPI_PICO_CLKID_GPIN0 15 +#define RPI_PICO_CLKID_GPIN1 16 + +#define RPI_PICO_ROSC_RANGE_RESET 0xAA0 +#define RPI_PICO_ROSC_RANGE_LOW 0xFA4 +#define RPI_PICO_ROSC_RANGE_MEDIUM 0xFA5 +#define RPI_PICO_ROSC_RANGE_HIGH 0xFA7 +#define RPI_PICO_ROSC_RANGE_TOOHIGH 0xFA6 + +#define RPI_PICO_CLOCK_COUNT 10 + +#endif /* ZEPHYR_INCLUDE_DT_BINDINGS_CLOCK_RPI_PICO_CLOCK_H_ */ diff --git a/include/zephyr/dt-bindings/pinctrl/rpi-pico-rp2040-pinctrl.h b/include/zephyr/dt-bindings/pinctrl/rpi-pico-rp2040-pinctrl.h index 4249fd24a3a..c7870a21082 100644 --- a/include/zephyr/dt-bindings/pinctrl/rpi-pico-rp2040-pinctrl.h +++ b/include/zephyr/dt-bindings/pinctrl/rpi-pico-rp2040-pinctrl.h @@ -219,4 +219,11 @@ #define PIO1_P28 RP2040_PINMUX(28, RP2_PINCTRL_GPIO_FUNC_PIO1) #define PIO1_P29 RP2040_PINMUX(29, RP2_PINCTRL_GPIO_FUNC_PIO1) +#define GPIN0_P20 RP2040_PINMUX(20, RP2_PINCTRL_GPIO_FUNC_GPCK) +#define GPIN1_P22 RP2040_PINMUX(22, RP2_PINCTRL_GPIO_FUNC_GPCK) +#define GPOUT0_P21 RP2040_PINMUX(21, RP2_PINCTRL_GPIO_FUNC_GPCK) +#define GPOUT1_P23 RP2040_PINMUX(23, RP2_PINCTRL_GPIO_FUNC_GPCK) +#define GPOUT2_P24 RP2040_PINMUX(24, RP2_PINCTRL_GPIO_FUNC_GPCK) +#define GPOUT3_P25 RP2040_PINMUX(25, RP2_PINCTRL_GPIO_FUNC_GPCK) + #endif /* __RP2040_PINCTRL_H__ */ diff --git a/samples/sensor/bme280/rpi_pico_spi_pio.overlay b/samples/sensor/bme280/rpi_pico_spi_pio.overlay index 473cfae2a0b..a555e93213c 100644 --- a/samples/sensor/bme280/rpi_pico_spi_pio.overlay +++ b/samples/sensor/bme280/rpi_pico_spi_pio.overlay @@ -22,7 +22,7 @@ status = "okay"; #address-cells = <1>; #size-cells = <0>; - clocks = < &system_clk >; + clocks = <&clocks RPI_PICO_CLKID_CLK_SYS>; miso-gpios = <&gpio0 12 0>; cs-gpios = <&gpio0 13 GPIO_ACTIVE_LOW>; clk-gpios = <&gpio0 14 GPIO_ACTIVE_HIGH>; diff --git a/soc/arm/rpi_pico/rp2/soc.c b/soc/arm/rpi_pico/rp2/soc.c index d953436f77e..012f5431283 100644 --- a/soc/arm/rpi_pico/rp2/soc.c +++ b/soc/arm/rpi_pico/rp2/soc.c @@ -26,24 +26,6 @@ LOG_MODULE_REGISTER(soc, CONFIG_SOC_LOG_LEVEL); -static int rp2040_init(void) -{ - reset_block(~(RESETS_RESET_IO_QSPI_BITS | RESETS_RESET_PADS_QSPI_BITS | - RESETS_RESET_PLL_USB_BITS | RESETS_RESET_PLL_SYS_BITS)); - - unreset_block_wait(RESETS_RESET_BITS & - ~(RESETS_RESET_ADC_BITS | RESETS_RESET_RTC_BITS | - RESETS_RESET_SPI0_BITS | RESETS_RESET_SPI1_BITS | - RESETS_RESET_UART0_BITS | RESETS_RESET_UART1_BITS | - RESETS_RESET_USBCTRL_BITS | RESETS_RESET_PWM_BITS)); - - clocks_init(); - - unreset_block_wait(RESETS_RESET_BITS); - - return 0; -} - /* * Some pico-sdk drivers call panic on fatal error. * This alternative implementation of panic handles the panic @@ -57,5 +39,3 @@ void __attribute__((noreturn)) panic(const char *fmt, ...) vprintf(fmt, args); k_fatal_halt(K_ERR_CPU_EXCEPTION); } - -SYS_INIT(rp2040_init, PRE_KERNEL_1, 0); From 99a9b995d38c45bc41c75aecb69de6b419803c0b Mon Sep 17 00:00:00 2001 From: TOKITA Hiroshi Date: Sat, 9 Sep 2023 09:06:30 +0900 Subject: [PATCH 1453/3723] drivers: clock_control: rpi_pico: Configure GPOUT/GPIN pins Configure GPOUT/GPIN pin for external clock in/out via GPIO. Signed-off-by: TOKITA Hiroshi --- boards/arm/adafruit_kb2040/adafruit_kb2040-pinctrl.dtsi | 3 +++ boards/arm/adafruit_kb2040/adafruit_kb2040.dts | 5 +++++ boards/arm/rpi_pico/rpi_pico-common.dtsi | 5 +++++ boards/arm/rpi_pico/rpi_pico-pinctrl.dtsi | 3 +++ .../sparkfun_pro_micro_rp2040-pinctrl.dtsi | 3 +++ .../sparkfun_pro_micro_rp2040.dts | 4 ++++ drivers/clock_control/clock_control_rpi_pico.c | 9 +++++++++ .../clock/raspberrypi,pico-clock-controller.yaml | 2 +- 8 files changed, 33 insertions(+), 1 deletion(-) diff --git a/boards/arm/adafruit_kb2040/adafruit_kb2040-pinctrl.dtsi b/boards/arm/adafruit_kb2040/adafruit_kb2040-pinctrl.dtsi index 5ae00a45cde..cf4eeaf6b95 100644 --- a/boards/arm/adafruit_kb2040/adafruit_kb2040-pinctrl.dtsi +++ b/boards/arm/adafruit_kb2040/adafruit_kb2040-pinctrl.dtsi @@ -47,4 +47,7 @@ input-enable; }; }; + + clocks_default: clocks_default { + }; }; diff --git a/boards/arm/adafruit_kb2040/adafruit_kb2040.dts b/boards/arm/adafruit_kb2040/adafruit_kb2040.dts index 227bb53e8d6..1abbb70e988 100644 --- a/boards/arm/adafruit_kb2040/adafruit_kb2040.dts +++ b/boards/arm/adafruit_kb2040/adafruit_kb2040.dts @@ -54,6 +54,11 @@ }; }; +&clocks { + pinctrl-0 = <&clocks_default>; + pinctrl-names = "default"; +}; + &uart0 { current-speed = <115200>; status = "okay"; diff --git a/boards/arm/rpi_pico/rpi_pico-common.dtsi b/boards/arm/rpi_pico/rpi_pico-common.dtsi index aee3e144368..95a27d3a009 100644 --- a/boards/arm/rpi_pico/rpi_pico-common.dtsi +++ b/boards/arm/rpi_pico/rpi_pico-common.dtsi @@ -88,6 +88,11 @@ }; }; +&clocks { + pinctrl-0 = <&clocks_default>; + pinctrl-names = "default"; +}; + &uart0 { current-speed = <115200>; status = "okay"; diff --git a/boards/arm/rpi_pico/rpi_pico-pinctrl.dtsi b/boards/arm/rpi_pico/rpi_pico-pinctrl.dtsi index 747b0d04e40..761354420c6 100644 --- a/boards/arm/rpi_pico/rpi_pico-pinctrl.dtsi +++ b/boards/arm/rpi_pico/rpi_pico-pinctrl.dtsi @@ -54,4 +54,7 @@ input-enable; }; }; + + clocks_default: clocks_default { + }; }; diff --git a/boards/arm/sparkfun_pro_micro_rp2040/sparkfun_pro_micro_rp2040-pinctrl.dtsi b/boards/arm/sparkfun_pro_micro_rp2040/sparkfun_pro_micro_rp2040-pinctrl.dtsi index 64f3ab61e5f..3bca8b4f384 100644 --- a/boards/arm/sparkfun_pro_micro_rp2040/sparkfun_pro_micro_rp2040-pinctrl.dtsi +++ b/boards/arm/sparkfun_pro_micro_rp2040/sparkfun_pro_micro_rp2040-pinctrl.dtsi @@ -46,4 +46,7 @@ input-enable; }; }; + + clocks_default: clocks_default { + }; }; diff --git a/boards/arm/sparkfun_pro_micro_rp2040/sparkfun_pro_micro_rp2040.dts b/boards/arm/sparkfun_pro_micro_rp2040/sparkfun_pro_micro_rp2040.dts index 50b92f603f7..1d92bcf1cba 100644 --- a/boards/arm/sparkfun_pro_micro_rp2040/sparkfun_pro_micro_rp2040.dts +++ b/boards/arm/sparkfun_pro_micro_rp2040/sparkfun_pro_micro_rp2040.dts @@ -56,6 +56,10 @@ }; }; +&clocks { + pinctrl-0 = <&clocks_default>; + pinctrl-names = "default"; +}; &uart0 { current-speed = <115200>; diff --git a/drivers/clock_control/clock_control_rpi_pico.c b/drivers/clock_control/clock_control_rpi_pico.c index 0313ee2d71d..4deec67423b 100644 --- a/drivers/clock_control/clock_control_rpi_pico.c +++ b/drivers/clock_control/clock_control_rpi_pico.c @@ -8,6 +8,7 @@ #define DT_DRV_COMPAT raspberrypi_pico_clock_controller #include +#include #include #include @@ -696,6 +697,11 @@ static int clock_control_rpi_pico_init(const struct device *dev) dev, (clock_control_subsys_t)rpi_pico_clkid_rosc_ph); } + ret = pinctrl_apply_state(config->pcfg, PINCTRL_STATE_DEFAULT); + if (ret < 0) { + return ret; + } + return 0; } @@ -741,12 +747,15 @@ BUILD_ASSERT(SRC_CLOCK_FREQ(clk_peri) >= CLOCK_FREQ_clk_peri, BUILD_ASSERT(CLOCK_FREQ(rosc_ph) == CLOCK_FREQ(rosc), "rosc_ph: frequency must be equal to rosc"); +PINCTRL_DT_INST_DEFINE(0); + static const struct clock_control_rpi_pico_config clock_control_rpi_pico_config = { .clocks_regs = (clocks_hw_t *)DT_INST_REG_ADDR_BY_NAME(0, clocks), .xosc_regs = (xosc_hw_t *)DT_INST_REG_ADDR_BY_NAME(0, xosc), .pll_sys_regs = (pll_hw_t *)DT_INST_REG_ADDR_BY_NAME(0, pll_sys), .pll_usb_regs = (pll_hw_t *)DT_INST_REG_ADDR_BY_NAME(0, pll_usb), .rosc_regs = (rosc_hw_t *)DT_INST_REG_ADDR_BY_NAME(0, rosc), + .pcfg = PINCTRL_DT_INST_DEV_CONFIG_GET(0), .clocks_data = { [RPI_PICO_CLKID_CLK_GPOUT0] = { .source = 0, diff --git a/dts/bindings/clock/raspberrypi,pico-clock-controller.yaml b/dts/bindings/clock/raspberrypi,pico-clock-controller.yaml index cf740654949..a4f8557e8ca 100644 --- a/dts/bindings/clock/raspberrypi,pico-clock-controller.yaml +++ b/dts/bindings/clock/raspberrypi,pico-clock-controller.yaml @@ -5,7 +5,7 @@ description: Raspberry Pi Pico clock controller node compatible: "raspberrypi,pico-clock-controller" -include: [base.yaml, clock-controller.yaml] +include: [base.yaml, clock-controller.yaml, pinctrl-device.yaml] properties: reg: From 5f927cfc3b371c3e6a7537cd7479a91c6cb9b9d5 Mon Sep 17 00:00:00 2001 From: Andrei-Edward Popa Date: Thu, 8 Dec 2022 16:36:46 +0200 Subject: [PATCH 1454/3723] drivers: watchdog: Changed how to get xtal frequency for Raspberry Pi Pico Changed how to get xtal frequency for Raspberry Pi Pico Signed-off-by: Andrei-Edward Popa Signed-off-by: TOKITA Hiroshi --- drivers/watchdog/wdt_rpi_pico.c | 23 +++++++++++++++++++---- 1 file changed, 19 insertions(+), 4 deletions(-) diff --git a/drivers/watchdog/wdt_rpi_pico.c b/drivers/watchdog/wdt_rpi_pico.c index 83285ba659e..7d3f2a5fc60 100644 --- a/drivers/watchdog/wdt_rpi_pico.c +++ b/drivers/watchdog/wdt_rpi_pico.c @@ -8,6 +8,7 @@ #include #include +#include #include #include @@ -19,7 +20,7 @@ LOG_MODULE_REGISTER(wdt_rpi_pico, CONFIG_WDT_LOG_LEVEL); #define RPI_PICO_WDT_TIME_MULTIPLICATION_FACTOR 2 /* Watchdog requires a 1MHz clock source, divided from the crystal oscillator */ -#define RPI_PICO_XTAL_FREQ_WDT_TICK_DIVISOR 1000000 +#define RPI_PICO_CLK_REF_FREQ_WDT_TICK_DIVISOR 1000000 struct wdt_rpi_pico_data { uint8_t reset_type; @@ -28,13 +29,16 @@ struct wdt_rpi_pico_data { }; struct wdt_rpi_pico_config { - uint32_t xtal_frequency; + const struct device *clk_dev; + clock_control_subsys_t clk_id; }; static int wdt_rpi_pico_setup(const struct device *dev, uint8_t options) { const struct wdt_rpi_pico_config *config = dev->config; struct wdt_rpi_pico_data *data = dev->data; + uint32_t ref_clk; + int err; if ((options & WDT_OPT_PAUSE_IN_SLEEP) == 1) { return -ENOTSUP; @@ -75,7 +79,17 @@ static int wdt_rpi_pico_setup(const struct device *dev, uint8_t options) data->enabled = true; - watchdog_hw->tick = (config->xtal_frequency / RPI_PICO_XTAL_FREQ_WDT_TICK_DIVISOR) | + err = clock_control_on(config->clk_dev, config->clk_id); + if (err < 0) { + return err; + } + + err = clock_control_get_rate(config->clk_dev, config->clk_id, &ref_clk); + if (err < 0) { + return err; + } + + watchdog_hw->tick = (ref_clk / RPI_PICO_CLK_REF_FREQ_WDT_TICK_DIVISOR) | WATCHDOG_TICK_ENABLE_BITS; return 0; @@ -157,7 +171,8 @@ static const struct wdt_driver_api wdt_rpi_pico_driver_api = { #define WDT_RPI_PICO_WDT_DEVICE(idx) \ static const struct wdt_rpi_pico_config wdt_##idx##_config = { \ - .xtal_frequency = DT_INST_PROP_BY_PHANDLE(idx, clocks, clock_frequency) \ + .clk_dev = DEVICE_DT_GET(DT_INST_CLOCKS_CTLR(idx)), \ + .clk_id = (clock_control_subsys_t)DT_INST_PHA_BY_IDX(idx, clocks, 0, clk_id), \ }; \ static struct wdt_rpi_pico_data wdt_##idx##_data = { \ .reset_type = WDT_FLAG_RESET_SOC, \ From 0f41a2da1c552010516df04c5b79e958e63a4e0e Mon Sep 17 00:00:00 2001 From: Andrei-Edward Popa Date: Sat, 18 Mar 2023 23:01:11 +0200 Subject: [PATCH 1455/3723] drivers: serial: Removed all function calls from Raspberry Pi Pico SDK Removed all function calls from Raspberry Pi Pico SDK Added functions for setting uart baudrate and format Signed-off-by: Andrei-Edward Popa Signed-off-by: TOKITA Hiroshi --- drivers/serial/uart_rpi_pico.c | 196 ++++++++++++++++++++------------- 1 file changed, 122 insertions(+), 74 deletions(-) diff --git a/drivers/serial/uart_rpi_pico.c b/drivers/serial/uart_rpi_pico.c index 9eb820d6224..a423c94cc9c 100644 --- a/drivers/serial/uart_rpi_pico.c +++ b/drivers/serial/uart_rpi_pico.c @@ -5,11 +5,11 @@ * SPDX-License-Identifier: Apache-2.0 */ -#include -#include +#include #include +#include +#include #include -#include /* pico-sdk includes */ #include @@ -17,10 +17,11 @@ #define DT_DRV_COMPAT raspberrypi_pico_uart struct uart_rpi_config { - uart_inst_t *const uart_dev; uart_hw_t *const uart_regs; const struct pinctrl_dev_config *pcfg; const struct reset_dt_spec reset; + const struct device *clk_dev; + clock_control_subsys_t clk_id; #ifdef CONFIG_UART_INTERRUPT_DRIVEN uart_irq_config_func_t irq_config_func; #endif /* CONFIG_UART_INTERRUPT_DRIVEN */ @@ -59,13 +60,51 @@ static void uart_rpi_poll_out(const struct device *dev, unsigned char c) uart_hw->dr = c; } +static int uart_rpi_set_baudrate(const struct device *dev, uint32_t input_baudrate, + uint32_t *output_baudrate) +{ + const struct uart_rpi_config *cfg = dev->config; + uart_hw_t * const uart_hw = cfg->uart_regs; + uint32_t baudrate_frac; + uint32_t baudrate_int; + uint32_t baudrate_div; + uint32_t pclk; + int ret; + + if (input_baudrate == 0) { + return -EINVAL; + } + + ret = clock_control_get_rate(cfg->clk_dev, cfg->clk_id, &pclk); + if (ret < 0 || pclk == 0) { + return -EINVAL; + } + + baudrate_div = (8 * pclk / input_baudrate); + baudrate_int = baudrate_div >> 7; + baudrate_frac = (baudrate_int == 0) || (baudrate_int >= UINT16_MAX) ? 0 : + ((baudrate_div & 0x7f) + 1) / 2; + baudrate_int = (baudrate_int == 0) ? 1 : + (baudrate_int >= UINT16_MAX) ? UINT16_MAX : baudrate_int; + + uart_hw->ibrd = baudrate_int; + uart_hw->fbrd = baudrate_frac; + + uart_hw->lcr_h |= 0; + + *output_baudrate = (4 * pclk) / (64 * baudrate_int + baudrate_frac); + + return 0; +} + static int uart_rpi_set_format(const struct device *dev, const struct uart_config *cfg) { const struct uart_rpi_config *config = dev->config; - uart_inst_t * const uart_inst = config->uart_dev; - uart_parity_t parity = 0; - uint data_bits = 0; - uint stop_bits = 0; + uart_hw_t * const uart_hw = config->uart_regs; + uint32_t data_bits; + uint32_t stop_bits; + uint32_t lcr_value; + uint32_t lcr_mask; switch (cfg->data_bits) { case UART_CFG_DATA_BITS_5: @@ -95,30 +134,25 @@ static int uart_rpi_set_format(const struct device *dev, const struct uart_confi return -EINVAL; } - switch (cfg->parity) { - case UART_CFG_PARITY_NONE: - parity = UART_PARITY_NONE; - break; - case UART_CFG_PARITY_EVEN: - parity = UART_PARITY_EVEN; - break; - case UART_CFG_PARITY_ODD: - parity = UART_PARITY_ODD; - break; - default: - return -EINVAL; - } + lcr_mask = UART_UARTLCR_H_WLEN_BITS | UART_UARTLCR_H_STP2_BITS | + UART_UARTLCR_H_PEN_BITS | UART_UARTLCR_H_EPS_BITS; + + lcr_value = ((data_bits - 5) << UART_UARTLCR_H_WLEN_LSB) | + ((stop_bits - 1) << UART_UARTLCR_H_STP2_LSB) | + (!!(cfg->parity != UART_CFG_PARITY_NONE) << UART_UARTLCR_H_PEN_LSB) | + (!!(cfg->parity == UART_CFG_PARITY_EVEN) << UART_UARTLCR_H_EPS_LSB); + + uart_hw->lcr_h = (uart_hw->lcr_h & ~lcr_mask) | (lcr_value & lcr_mask); - uart_set_format(uart_inst, data_bits, stop_bits, parity); return 0; } static int uart_rpi_init(const struct device *dev) { const struct uart_rpi_config *config = dev->config; - uart_inst_t * const uart_inst = config->uart_dev; uart_hw_t * const uart_hw = config->uart_regs; struct uart_rpi_data * const data = dev->data; + uint32_t baudrate; int ret; ret = pinctrl_apply_state(config->pcfg, PINCTRL_STATE_DEFAULT); @@ -126,20 +160,32 @@ static int uart_rpi_init(const struct device *dev) return ret; } - /* - * uart_init() may be replaced by register based API once rpi-pico platform - * has a clock controller driver - */ - data->uart_config.baudrate = uart_init(uart_inst, data->uart_config.baudrate); + ret = clock_control_on(config->clk_dev, config->clk_id); + if (ret < 0) { + return ret; + } - /* Check if baudrate adjustment returned by 'uart_init' function is a positive value */ - if (data->uart_config.baudrate == 0) { - return -EINVAL; + ret = reset_line_toggle(config->reset.dev, config->reset.id); + if (ret < 0) { + return ret; } + + ret = uart_rpi_set_baudrate(dev, data->uart_config.baudrate, &baudrate); + if (ret < 0) { + return ret; + } + + uart_rpi_set_format(dev, &data->uart_config); + + uart_hw->cr = UART_UARTCR_UARTEN_BITS | UART_UARTCR_TXE_BITS | UART_UARTCR_RXE_BITS; + uart_hw->lcr_h |= UART_UARTLCR_H_FEN_BITS; + + uart_hw->dmacr = UART_UARTDMACR_TXDMAE_BITS | UART_UARTDMACR_RXDMAE_BITS; + /* * initialize uart_config with hardware reset values * https://datasheets.raspberrypi.com/rp2040/rp2040-datasheet.pdf#tab-registerlist_uart page:431 - * data bits set default to 8 instaed of hardware reset 5 to increase compatibility. + * data bits set default to 8 instead of hardware reset 5 to increase compatibility. */ data->uart_config.data_bits = UART_CFG_DATA_BITS_8; data->uart_config.parity = UART_CFG_PARITY_NONE; @@ -149,7 +195,7 @@ static int uart_rpi_init(const struct device *dev) uart_hw->dr = 0U; if (data->uart_config.flow_ctrl == UART_CFG_FLOW_CTRL_RTS_CTS) { - uart_set_hw_flow(uart_inst, true, true); + uart_set_hw_flow((uart_inst_t *)uart_hw, true, true); } #ifdef CONFIG_UART_INTERRUPT_DRIVEN @@ -163,24 +209,25 @@ static int uart_rpi_config_get(const struct device *dev, struct uart_config *cfg { struct uart_rpi_data *data = dev->data; - memcpy(cfg, &data->uart_config, sizeof(struct uart_config)); + *cfg = data->uart_config; + return 0; } static int uart_rpi_configure(const struct device *dev, const struct uart_config *cfg) { - const struct uart_rpi_config *config = dev->config; - uart_inst_t * const uart_inst = config->uart_dev; struct uart_rpi_data *data = dev->data; - uint baudrate = 0; + uint32_t baudrate = 0; + int ret; - baudrate = uart_set_baudrate(uart_inst, cfg->baudrate); - if (baudrate == 0) { - return -EINVAL; + ret = uart_rpi_set_baudrate(dev, cfg->baudrate, &baudrate); + if (ret < 0) { + return ret; } - if (uart_rpi_set_format(dev, cfg) != 0) { - return -EINVAL; + ret = uart_rpi_set_format(dev, cfg); + if (ret < 0) { + return ret; } data->uart_config = *cfg; @@ -389,37 +436,38 @@ static const struct uart_driver_api uart_rpi_driver_api = { #define RPI_UART_IRQ_CONFIG_INIT(idx) #endif /* CONFIG_UART_INTERRUPT_DRIVEN*/ -#define RPI_UART_INIT(idx) \ - PINCTRL_DT_INST_DEFINE(idx); \ - \ - static void uart##idx##_rpi_irq_config_func(const struct device *port) \ - { \ - IRQ_CONNECT(DT_INST_IRQN(idx), \ - DT_INST_IRQ(idx, priority), \ - uart_rpi_isr, \ - DEVICE_DT_INST_GET(idx), 0); \ - irq_enable(DT_INST_IRQN(idx)); \ - } \ - \ - static const struct uart_rpi_config uart##idx##_rpi_config = { \ - .uart_dev = (uart_inst_t *const)DT_INST_REG_ADDR(idx), \ - .uart_regs = (uart_hw_t *const)DT_INST_REG_ADDR(idx), \ - .pcfg = PINCTRL_DT_INST_DEV_CONFIG_GET(idx), \ - .reset = RESET_DT_SPEC_INST_GET(idx), \ - RPI_UART_IRQ_CONFIG_INIT(idx), \ - }; \ - \ - static struct uart_rpi_data uart##idx##_rpi_data = { \ - .uart_config.baudrate = DT_INST_PROP(idx, current_speed), \ - .uart_config.flow_ctrl = DT_INST_PROP(idx, hw_flow_control) \ - ? UART_CFG_FLOW_CTRL_RTS_CTS \ - : UART_CFG_FLOW_CTRL_NONE, \ - }; \ - \ - DEVICE_DT_INST_DEFINE(idx, &uart_rpi_init, \ - NULL, &uart##idx##_rpi_data, \ - &uart##idx##_rpi_config, PRE_KERNEL_1, \ - CONFIG_SERIAL_INIT_PRIORITY, \ - &uart_rpi_driver_api); \ +#define RPI_UART_INIT(idx) \ + PINCTRL_DT_INST_DEFINE(idx); \ + \ + static void uart##idx##_rpi_irq_config_func(const struct device *port) \ + { \ + IRQ_CONNECT(DT_INST_IRQN(idx), \ + DT_INST_IRQ(idx, priority), \ + uart_rpi_isr, \ + DEVICE_DT_INST_GET(idx), 0); \ + irq_enable(DT_INST_IRQN(idx)); \ + } \ + \ + static const struct uart_rpi_config uart##idx##_rpi_config = { \ + .uart_regs = (uart_hw_t *const)DT_INST_REG_ADDR(idx), \ + .pcfg = PINCTRL_DT_INST_DEV_CONFIG_GET(idx), \ + .reset = RESET_DT_SPEC_INST_GET(idx), \ + .clk_dev = DEVICE_DT_GET(DT_INST_CLOCKS_CTLR(idx)), \ + .clk_id = (clock_control_subsys_t)DT_INST_PHA_BY_IDX(idx, clocks, 0, clk_id), \ + RPI_UART_IRQ_CONFIG_INIT(idx), \ + }; \ + \ + static struct uart_rpi_data uart##idx##_rpi_data = { \ + .uart_config.baudrate = DT_INST_PROP(idx, current_speed), \ + .uart_config.flow_ctrl = DT_INST_PROP(idx, hw_flow_control) \ + ? UART_CFG_FLOW_CTRL_RTS_CTS \ + : UART_CFG_FLOW_CTRL_NONE, \ + }; \ + \ + DEVICE_DT_INST_DEFINE(idx, &uart_rpi_init, \ + NULL, &uart##idx##_rpi_data, \ + &uart##idx##_rpi_config, PRE_KERNEL_1, \ + CONFIG_SERIAL_INIT_PRIORITY, \ + &uart_rpi_driver_api); DT_INST_FOREACH_STATUS_OKAY(RPI_UART_INIT) From c4488660425bb6cd7d3d5d3bd3eeeea4cfd175fa Mon Sep 17 00:00:00 2001 From: Andrei-Edward Popa Date: Sat, 18 Mar 2023 23:00:14 +0200 Subject: [PATCH 1456/3723] drivers: spi: Changed how to get clock frequency for PL022 Changed how to get clock frequency for PL022 Signed-off-by: Andrei-Edward Popa Signed-off-by: TOKITA Hiroshi --- drivers/spi/spi_pl022.c | 47 +++++++++++++++++++++++++++++++++++------ 1 file changed, 40 insertions(+), 7 deletions(-) diff --git a/drivers/spi/spi_pl022.c b/drivers/spi/spi_pl022.c index 29f92d3050c..985cc2ab348 100644 --- a/drivers/spi/spi_pl022.c +++ b/drivers/spi/spi_pl022.c @@ -8,6 +8,7 @@ #include #include +#include #include #include #include @@ -266,13 +267,17 @@ struct spi_pl022_dma_data { /* * Max frequency */ -#define MAX_FREQ_CONTROLLER_MODE(cfg) (cfg->pclk / 2) -#define MAX_FREQ_PERIPHERAL_MODE(cfg) (cfg->pclk / 12) +#define MAX_FREQ_CONTROLLER_MODE(pclk) ((pclk) / 2) +#define MAX_FREQ_PERIPHERAL_MODE(pclk) ((pclk) / 12) struct spi_pl022_cfg { const uint32_t reg; const uint32_t pclk; const bool dma_enabled; +#if IS_ENABLED(CONFIG_CLOCK_CONTROL) + const struct device *clk_dev; + const clock_control_subsys_t clk_id; +#endif #if defined(CONFIG_PINCTRL) const struct pinctrl_dev_config *pincfg; #endif @@ -336,15 +341,25 @@ static int spi_pl022_configure(const struct device *dev, const uint16_t op = spicfg->operation; uint32_t prescale; uint32_t postdiv; + uint32_t pclk = 0; uint32_t cr0; uint32_t cr1; + int ret; if (spi_context_configured(&data->ctx, spicfg)) { return 0; } - if (spicfg->frequency > MAX_FREQ_CONTROLLER_MODE(cfg)) { - LOG_ERR("Frequency is up to %u in controller mode.", MAX_FREQ_CONTROLLER_MODE(cfg)); +#if IS_ENABLED(CONFIG_CLOCK_CONTROL) + ret = clock_control_get_rate(cfg->clk_dev, cfg->clk_id, &pclk); + if (ret < 0 || pclk == 0) { + return -EINVAL; + } +#endif + + if (spicfg->frequency > MAX_FREQ_CONTROLLER_MODE(pclk)) { + LOG_ERR("Frequency is up to %u in controller mode.", + MAX_FREQ_CONTROLLER_MODE(pclk)); return -ENOTSUP; } @@ -373,8 +388,8 @@ static int spi_pl022_configure(const struct device *dev, /* configure registers */ - prescale = spi_pl022_calc_prescale(cfg->pclk, spicfg->frequency); - postdiv = spi_pl022_calc_postdiv(cfg->pclk, spicfg->frequency, prescale); + prescale = spi_pl022_calc_prescale(pclk, spicfg->frequency); + postdiv = spi_pl022_calc_postdiv(pclk, spicfg->frequency, prescale); cr0 = 0; cr0 |= (postdiv << SSP_CR0_SCR_LSB); @@ -887,6 +902,16 @@ static int spi_pl022_init(const struct device *dev) struct spi_pl022_data *data = dev->data; int ret; +#if IS_ENABLED(CONFIG_CLOCK_CONTROL) + if (cfg->clk_dev) { + ret = clock_control_on(cfg->clk_dev, cfg->clk_id); + if (ret < 0) { + LOG_ERR("Failed to enable the clock"); + return ret; + } + } +#endif + #if defined(CONFIG_PINCTRL) ret = pinctrl_apply_state(cfg->pincfg, PINCTRL_STATE_DEFAULT); if (ret < 0) { @@ -952,6 +977,11 @@ static int spi_pl022_init(const struct device *dev) #define DMAS_ENABLED(idx) (DT_INST_DMAS_HAS_NAME(idx, tx) && DT_INST_DMAS_HAS_NAME(idx, rx)) +#define CLOCK_ID_DECL(idx) \ + IF_ENABLED(DT_INST_NODE_HAS_PROP(0, clocks), \ + (static const clock_control_subsys_t pl022_clk_id##idx = \ + (clock_control_subsys_t)DT_INST_PHA_BY_IDX(idx, clocks, 0, clk_id);)) \ + #define SPI_PL022_INIT(idx) \ IF_ENABLED(CONFIG_PINCTRL, (PINCTRL_DT_INST_DEFINE(idx);)) \ IF_ENABLED(CONFIG_SPI_PL022_INTERRUPT, \ @@ -961,13 +991,16 @@ static int spi_pl022_init(const struct device *dev) spi_pl022_isr, DEVICE_DT_INST_GET(idx), 0); \ irq_enable(DT_INST_IRQN(idx)); \ })) \ + IF_ENABLED(CONFIG_CLOCK_CONTROL, (CLOCK_ID_DECL(idx))) \ static struct spi_pl022_data spi_pl022_data_##idx = { \ SPI_CONTEXT_INIT_LOCK(spi_pl022_data_##idx, ctx), \ SPI_CONTEXT_INIT_SYNC(spi_pl022_data_##idx, ctx), \ SPI_CONTEXT_CS_GPIOS_INITIALIZE(DT_DRV_INST(idx), ctx)}; \ static struct spi_pl022_cfg spi_pl022_cfg_##idx = { \ .reg = DT_INST_REG_ADDR(idx), \ - .pclk = DT_INST_PROP_BY_PHANDLE(idx, clocks, clock_frequency), \ + IF_ENABLED(CONFIG_CLOCK_CONTROL, (IF_ENABLED(DT_INST_NODE_HAS_PROP(0, clocks), \ + (.clk_dev = DEVICE_DT_GET(DT_INST_CLOCKS_CTLR(idx)), \ + .clk_id = pl022_clk_id##idx,)))) \ IF_ENABLED(CONFIG_PINCTRL, (.pincfg = PINCTRL_DT_INST_DEV_CONFIG_GET(idx),)) \ IF_ENABLED(CONFIG_SPI_PL022_DMA, (.dma = DMAS_DECL(idx),)) COND_CODE_1( \ CONFIG_SPI_PL022_DMA, (.dma_enabled = DMAS_ENABLED(idx),), \ From 57641875c382d76cbef0f88ba9942af6a6492352 Mon Sep 17 00:00:00 2001 From: TOKITA Hiroshi Date: Fri, 8 Sep 2023 22:03:46 +0900 Subject: [PATCH 1457/3723] drivers: spi: pl022: Reset device on initializing Reset the device on initializing via reset controller. Signed-off-by: TOKITA Hiroshi --- drivers/spi/spi_pl022.c | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/drivers/spi/spi_pl022.c b/drivers/spi/spi_pl022.c index 985cc2ab348..2565ce66957 100644 --- a/drivers/spi/spi_pl022.c +++ b/drivers/spi/spi_pl022.c @@ -9,6 +9,7 @@ #include #include #include +#include #include #include #include @@ -278,6 +279,9 @@ struct spi_pl022_cfg { const struct device *clk_dev; const clock_control_subsys_t clk_id; #endif +#if IS_ENABLED(CONFIG_RESET) + const struct reset_dt_spec reset; +#endif #if defined(CONFIG_PINCTRL) const struct pinctrl_dev_config *pincfg; #endif @@ -912,6 +916,15 @@ static int spi_pl022_init(const struct device *dev) } #endif +#if IS_ENABLED(CONFIG_RESET) + if (cfg->reset.dev) { + ret = reset_line_toggle_dt(&cfg->reset); + if (ret < 0) { + return ret; + } + } +#endif + #if defined(CONFIG_PINCTRL) ret = pinctrl_apply_state(cfg->pincfg, PINCTRL_STATE_DEFAULT); if (ret < 0) { @@ -1001,6 +1014,8 @@ static int spi_pl022_init(const struct device *dev) IF_ENABLED(CONFIG_CLOCK_CONTROL, (IF_ENABLED(DT_INST_NODE_HAS_PROP(0, clocks), \ (.clk_dev = DEVICE_DT_GET(DT_INST_CLOCKS_CTLR(idx)), \ .clk_id = pl022_clk_id##idx,)))) \ + IF_ENABLED(CONFIG_RESET, (IF_ENABLED(DT_INST_NODE_HAS_PROP(0, resets), \ + (.reset = RESET_DT_SPEC_INST_GET(idx),)))) \ IF_ENABLED(CONFIG_PINCTRL, (.pincfg = PINCTRL_DT_INST_DEV_CONFIG_GET(idx),)) \ IF_ENABLED(CONFIG_SPI_PL022_DMA, (.dma = DMAS_DECL(idx),)) COND_CODE_1( \ CONFIG_SPI_PL022_DMA, (.dma_enabled = DMAS_ENABLED(idx),), \ From e905483bd0dc6bfa518705591b6d3b92b9b10938 Mon Sep 17 00:00:00 2001 From: TOKITA Hiroshi Date: Fri, 1 Sep 2023 08:11:26 +0900 Subject: [PATCH 1458/3723] driver: pwm: rpi_pico: Change to use clock controller Since clock_control has been introduced, use it to obtain the frequency. Signed-off-by: TOKITA Hiroshi --- drivers/pwm/pwm_rpi_pico.c | 21 ++++++++++++++++++--- 1 file changed, 18 insertions(+), 3 deletions(-) diff --git a/drivers/pwm/pwm_rpi_pico.c b/drivers/pwm/pwm_rpi_pico.c index 4b23cc558f1..8477752f2a5 100644 --- a/drivers/pwm/pwm_rpi_pico.c +++ b/drivers/pwm/pwm_rpi_pico.c @@ -6,6 +6,7 @@ #define DT_DRV_COMPAT raspberrypi_pico_pwm #include +#include #include #include #include @@ -33,6 +34,8 @@ struct pwm_rpi_config { struct pwm_rpi_slice_config slice_configs[NUM_PWM_SLICES]; const struct pinctrl_dev_config *pcfg; const struct reset_dt_spec reset; + const struct device *clk_dev; + const clock_control_subsys_t clk_id; }; static float pwm_rpi_get_clkdiv(const struct device *dev, int slice) @@ -56,19 +59,24 @@ static inline uint32_t pwm_rpi_channel_to_pico_channel(uint32_t channel) static int pwm_rpi_get_cycles_per_sec(const struct device *dev, uint32_t ch, uint64_t *cycles) { - float f_clock_in; + const struct pwm_rpi_config *cfg = dev->config; int slice = pwm_rpi_channel_to_slice(ch); + uint32_t pclk; + int ret; if (ch >= PWM_RPI_NUM_CHANNELS) { return -EINVAL; } - f_clock_in = (float)sys_clock_hw_cycles_per_sec(); + ret = clock_control_get_rate(cfg->clk_dev, cfg->clk_id, &pclk); + if (ret < 0 || pclk == 0) { + return -EINVAL; + } /* No need to check for divide by 0 since the minimum value of * pwm_rpi_get_clkdiv is 1 */ - *cycles = (uint64_t)(f_clock_in / pwm_rpi_get_clkdiv(dev, slice)); + *cycles = (uint64_t)((float)pclk / pwm_rpi_get_clkdiv(dev, slice)); return 0; } @@ -136,6 +144,11 @@ static int pwm_rpi_init(const struct device *dev) return err; } + err = clock_control_on(cfg->clk_dev, cfg->clk_id); + if (err < 0) { + return err; + } + for (slice_idx = 0; slice_idx < NUM_PWM_SLICES; slice_idx++) { slice_cfg = pwm_get_default_config(); pwm_config_set_clkdiv_mode(&slice_cfg, PWM_DIV_FREE_RUNNING); @@ -174,6 +187,8 @@ static int pwm_rpi_init(const struct device *dev) PWM_INST_RPI_SLICE_DIVIDER(idx, 7), \ }, \ .reset = RESET_DT_SPEC_INST_GET(idx), \ + .clk_dev = DEVICE_DT_GET(DT_INST_CLOCKS_CTLR(idx)), \ + .clk_id = (clock_control_subsys_t)DT_INST_PHA_BY_IDX(idx, clocks, 0, clk_id), \ }; \ \ DEVICE_DT_INST_DEFINE(idx, pwm_rpi_init, NULL, NULL, &pwm_rpi_config_##idx, POST_KERNEL, \ From 6ad894eb995669bfb4e0b4db2a5e4fad379bc7ca Mon Sep 17 00:00:00 2001 From: TOKITA Hiroshi Date: Sun, 1 Oct 2023 03:40:39 +0900 Subject: [PATCH 1459/3723] drivers: pwm: rpi_pico: Reset device on init Resetting PWM device via reset controller on initializing. Signed-off-by: TOKITA Hiroshi --- drivers/pwm/pwm_rpi_pico.c | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/drivers/pwm/pwm_rpi_pico.c b/drivers/pwm/pwm_rpi_pico.c index 8477752f2a5..b36a468fe37 100644 --- a/drivers/pwm/pwm_rpi_pico.c +++ b/drivers/pwm/pwm_rpi_pico.c @@ -149,6 +149,11 @@ static int pwm_rpi_init(const struct device *dev) return err; } + err = reset_line_toggle_dt(&cfg->reset); + if (err < 0) { + return err; + } + for (slice_idx = 0; slice_idx < NUM_PWM_SLICES; slice_idx++) { slice_cfg = pwm_get_default_config(); pwm_config_set_clkdiv_mode(&slice_cfg, PWM_DIV_FREE_RUNNING); From 90976db5a3e789c689bab1dd6aad657b61145bb6 Mon Sep 17 00:00:00 2001 From: TOKITA Hiroshi Date: Fri, 8 Sep 2023 01:57:24 +0900 Subject: [PATCH 1460/3723] drivers: adc: rpi_pico: Turn on clock and reset device on init Turning on clock via clock controller and resetting ADC device via reset controller on initializing. Signed-off-by: TOKITA Hiroshi --- drivers/adc/adc_rpi_pico.c | 71 ++++++++++++++++++++++++-------------- 1 file changed, 46 insertions(+), 25 deletions(-) diff --git a/drivers/adc/adc_rpi_pico.c b/drivers/adc/adc_rpi_pico.c index ec13b0d7b6d..76c3a52a15b 100644 --- a/drivers/adc/adc_rpi_pico.c +++ b/drivers/adc/adc_rpi_pico.c @@ -8,7 +8,9 @@ #define DT_DRV_COMPAT raspberrypi_pico_adc #include +#include #include +#include #include #include @@ -36,6 +38,12 @@ struct adc_rpi_config { const struct pinctrl_dev_config *pcfg; /** function pointer to irq setup */ void (*irq_configure)(void); + /** Pointer to clock controller device */ + const struct device *clk_dev; + /** Clock id of ADC clock */ + clock_control_subsys_t clk_id; + /** Reset controller config */ + const struct reset_dt_spec reset; }; /** @@ -299,6 +307,16 @@ static int adc_rpi_init(const struct device *dev) return ret; } + ret = clock_control_on(config->clk_dev, config->clk_id); + if (ret < 0) { + return ret; + } + + ret = reset_line_toggle_dt(&config->reset); + if (ret < 0) { + return ret; + } + config->irq_configure(); /* @@ -332,31 +350,34 @@ static int adc_rpi_init(const struct device *dev) #define IRQ_CONFIGURE_DEFINE(idx) .irq_configure = adc_rpi_configure_func_##idx -#define ADC_RPI_INIT(idx) \ - IRQ_CONFIGURE_FUNC(idx) \ - PINCTRL_DT_INST_DEFINE(idx); \ - static struct adc_driver_api adc_rpi_api_##idx = { \ - .channel_setup = adc_rpi_channel_setup, \ - .read = adc_rpi_read, \ - .ref_internal = DT_INST_PROP(idx, vref_mv), \ - IF_ENABLED(CONFIG_ADC_ASYNC, (.read_async = adc_rpi_read_async,)) \ - }; \ - static const struct adc_rpi_config adc_rpi_config_##idx = { \ - .num_channels = ADC_RPI_CHANNEL_NUM, \ - .pcfg = PINCTRL_DT_INST_DEV_CONFIG_GET(idx), \ - IRQ_CONFIGURE_DEFINE(idx), \ - }; \ - static struct adc_rpi_data adc_rpi_data_##idx = { \ - ADC_CONTEXT_INIT_TIMER(adc_rpi_data_##idx, ctx), \ - ADC_CONTEXT_INIT_LOCK(adc_rpi_data_##idx, ctx), \ - ADC_CONTEXT_INIT_SYNC(adc_rpi_data_##idx, ctx), \ - .dev = DEVICE_DT_INST_GET(idx), \ - }; \ - \ - DEVICE_DT_INST_DEFINE(idx, adc_rpi_init, NULL, \ - &adc_rpi_data_##idx, \ - &adc_rpi_config_##idx, POST_KERNEL, \ - CONFIG_ADC_INIT_PRIORITY, \ +#define ADC_RPI_INIT(idx) \ + IRQ_CONFIGURE_FUNC(idx) \ + PINCTRL_DT_INST_DEFINE(idx); \ + static struct adc_driver_api adc_rpi_api_##idx = { \ + .channel_setup = adc_rpi_channel_setup, \ + .read = adc_rpi_read, \ + .ref_internal = DT_INST_PROP(idx, vref_mv), \ + IF_ENABLED(CONFIG_ADC_ASYNC, (.read_async = adc_rpi_read_async,)) \ + }; \ + static const struct adc_rpi_config adc_rpi_config_##idx = { \ + .num_channels = ADC_RPI_CHANNEL_NUM, \ + .pcfg = PINCTRL_DT_INST_DEV_CONFIG_GET(idx), \ + .clk_dev = DEVICE_DT_GET(DT_INST_CLOCKS_CTLR(idx)), \ + .clk_id = (clock_control_subsys_t)DT_INST_PHA_BY_IDX(idx, clocks, 0, clk_id), \ + .reset = RESET_DT_SPEC_INST_GET(idx), \ + IRQ_CONFIGURE_DEFINE(idx), \ + }; \ + static struct adc_rpi_data adc_rpi_data_##idx = { \ + ADC_CONTEXT_INIT_TIMER(adc_rpi_data_##idx, ctx), \ + ADC_CONTEXT_INIT_LOCK(adc_rpi_data_##idx, ctx), \ + ADC_CONTEXT_INIT_SYNC(adc_rpi_data_##idx, ctx), \ + .dev = DEVICE_DT_INST_GET(idx), \ + }; \ + \ + DEVICE_DT_INST_DEFINE(idx, adc_rpi_init, NULL, \ + &adc_rpi_data_##idx, \ + &adc_rpi_config_##idx, POST_KERNEL, \ + CONFIG_ADC_INIT_PRIORITY, \ &adc_rpi_api_##idx) DT_INST_FOREACH_STATUS_OKAY(ADC_RPI_INIT); From 4e36854148fc42855e39218edc7ef9726af70b91 Mon Sep 17 00:00:00 2001 From: TOKITA Hiroshi Date: Fri, 8 Sep 2023 02:56:36 +0900 Subject: [PATCH 1461/3723] drivers: misc: pio_rpi_pico: Turn on clock and reset device on init Turning on clock via clock controller and resetting PIO device via reset controller on initializing. Signed-off-by: TOKITA Hiroshi --- drivers/misc/pio_rpi_pico/pio_rpi_pico.c | 36 ++++++++++++++++++------ 1 file changed, 28 insertions(+), 8 deletions(-) diff --git a/drivers/misc/pio_rpi_pico/pio_rpi_pico.c b/drivers/misc/pio_rpi_pico/pio_rpi_pico.c index 03a03e824c2..5182cdf32b0 100644 --- a/drivers/misc/pio_rpi_pico/pio_rpi_pico.c +++ b/drivers/misc/pio_rpi_pico/pio_rpi_pico.c @@ -6,13 +6,18 @@ */ #include +#include #include #include +#include #define DT_DRV_COMPAT raspberrypi_pico_pio struct pio_rpi_pico_config { PIO pio; + const struct device *clk_dev; + clock_control_subsys_t clk_id; + const struct reset_dt_spec reset; }; int pio_rpi_pico_allocate_sm(const struct device *dev, size_t *sm) @@ -38,16 +43,31 @@ PIO pio_rpi_pico_get_pio(const struct device *dev) static int pio_rpi_pico_init(const struct device *dev) { + const struct pio_rpi_pico_config *config = dev->config; + int ret; + + ret = clock_control_on(config->clk_dev, config->clk_id); + if (ret < 0) { + return ret; + } + + ret = reset_line_toggle_dt(&config->reset); + if (ret < 0) { + return ret; + } + return 0; } -#define RPI_PICO_PIO_INIT(idx) \ - static const struct pio_rpi_pico_config pio_rpi_pico_config_##idx = { \ - .pio = (PIO)DT_INST_REG_ADDR(idx), \ - }; \ - \ - DEVICE_DT_INST_DEFINE(idx, &pio_rpi_pico_init, NULL, NULL, \ - &pio_rpi_pico_config_##idx, PRE_KERNEL_2, \ - CONFIG_KERNEL_INIT_PRIORITY_DEFAULT, NULL); +#define RPI_PICO_PIO_INIT(idx) \ + static const struct pio_rpi_pico_config pio_rpi_pico_config_##idx = { \ + .pio = (PIO)DT_INST_REG_ADDR(idx), \ + .clk_dev = DEVICE_DT_GET(DT_INST_CLOCKS_CTLR(idx)), \ + .clk_id = (clock_control_subsys_t)DT_INST_PHA_BY_IDX(0, clocks, 0, clk_id), \ + .reset = RESET_DT_SPEC_INST_GET(idx), \ + }; \ + \ + DEVICE_DT_INST_DEFINE(idx, &pio_rpi_pico_init, NULL, NULL, &pio_rpi_pico_config_##idx, \ + PRE_KERNEL_2, CONFIG_KERNEL_INIT_PRIORITY_DEFAULT, NULL); DT_INST_FOREACH_STATUS_OKAY(RPI_PICO_PIO_INIT) From 8891f734ecd319fd3246008e0de52611582b2aa5 Mon Sep 17 00:00:00 2001 From: TOKITA Hiroshi Date: Fri, 8 Sep 2023 02:35:59 +0900 Subject: [PATCH 1462/3723] drivers: usb: rpi_pico: Turn on clock on initializing Turning on clock via clock controller on initializing. Signed-off-by: TOKITA Hiroshi --- drivers/usb/device/usb_dc_rpi_pico.c | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/drivers/usb/device/usb_dc_rpi_pico.c b/drivers/usb/device/usb_dc_rpi_pico.c index c13d564b72d..e3599c00bfe 100644 --- a/drivers/usb/device/usb_dc_rpi_pico.c +++ b/drivers/usb/device/usb_dc_rpi_pico.c @@ -17,6 +17,7 @@ #include #include #include +#include LOG_MODULE_REGISTER(udc_rpi, CONFIG_USB_DRIVER_LOG_LEVEL); @@ -26,6 +27,8 @@ LOG_MODULE_REGISTER(udc_rpi, CONFIG_USB_DRIVER_LOG_LEVEL); #define USB_IRQ DT_INST_IRQ_BY_NAME(0, usbctrl, irq) #define USB_IRQ_PRI DT_INST_IRQ_BY_NAME(0, usbctrl, priority) #define USB_NUM_BIDIR_ENDPOINTS DT_INST_PROP(0, num_bidir_endpoints) +#define CLK_DRV DEVICE_DT_GET(DT_INST_CLOCKS_CTLR(0)) +#define CLK_ID (clock_control_subsys_t)DT_INST_PHA_BY_IDX(0, clocks, 0, clk_id) #define DATA_BUFFER_SIZE 64U @@ -987,6 +990,7 @@ static void udc_rpi_thread_main(void *arg1, void *unused1, void *unused2) static int usb_rpi_init(void) { + int ret; k_thread_create(&thread, thread_stack, USBD_THREAD_STACK_SIZE, @@ -994,6 +998,11 @@ static int usb_rpi_init(void) K_PRIO_COOP(2), 0, K_NO_WAIT); k_thread_name_set(&thread, "usb_rpi"); + ret = clock_control_on(CLK_DRV, CLK_ID); + if (ret < 0) { + return ret; + } + IRQ_CONNECT(USB_IRQ, USB_IRQ_PRI, udc_rpi_isr, 0, 0); irq_enable(USB_IRQ); From a34210d669a1617854a4f1257ef2e1fbba81ff77 Mon Sep 17 00:00:00 2001 From: TOKITA Hiroshi Date: Thu, 14 Sep 2023 07:44:39 +0900 Subject: [PATCH 1463/3723] drivers: counter: rpi_pico: Turn on clock and reset device on init Turning on clock via clock controller and resetting PIO device via reset controller on initializing. Signed-off-by: TOKITA Hiroshi --- drivers/counter/counter_rpi_pico_timer.c | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+) diff --git a/drivers/counter/counter_rpi_pico_timer.c b/drivers/counter/counter_rpi_pico_timer.c index 40a5aadd491..c2140d58777 100644 --- a/drivers/counter/counter_rpi_pico_timer.c +++ b/drivers/counter/counter_rpi_pico_timer.c @@ -7,6 +7,8 @@ #include #include +#include +#include #include #include #include @@ -32,6 +34,9 @@ struct counter_rpi_pico_timer_config { struct counter_config_info info; timer_hw_t *timer; void (*irq_config)(); + const struct device *clk_dev; + clock_control_subsys_t clk_id; + const struct reset_dt_spec reset; }; static int counter_rpi_pico_timer_start(const struct device *dev) @@ -166,6 +171,17 @@ static void counter_rpi_pico_irq_handle(uint32_t ch, void *arg) static int counter_rpi_pico_timer_init(const struct device *dev) { const struct counter_rpi_pico_timer_config *config = dev->config; + int ret; + + ret = clock_control_on(config->clk_dev, config->clk_id); + if (ret < 0) { + return ret; + } + + ret = reset_line_toggle_dt(&config->reset); + if (ret < 0) { + return ret; + } config->irq_config(); @@ -214,6 +230,9 @@ static const struct counter_driver_api counter_rpi_pico_driver_api = { .flags = COUNTER_CONFIG_INFO_COUNT_UP, \ .channels = ARRAY_SIZE(ch_data##inst), \ }, \ + .clk_dev = DEVICE_DT_GET(DT_INST_CLOCKS_CTLR(inst)), \ + .clk_id = (clock_control_subsys_t)DT_INST_PHA_BY_IDX(inst, clocks, 0, clk_id), \ + .reset = RESET_DT_SPEC_INST_GET(inst), \ }; \ DEVICE_DT_INST_DEFINE(inst, counter_rpi_pico_timer_init, NULL, &counter_##inst##_data, \ &counter_##inst##_config, PRE_KERNEL_1, \ From 00d1ceceddd2594f44ad33eb41dddcb0d088936f Mon Sep 17 00:00:00 2001 From: TOKITA Hiroshi Date: Sun, 1 Oct 2023 01:26:37 +0900 Subject: [PATCH 1464/3723] driver: spi: spi_rpi_pico_pio: Change to use clock controller Since clock_control has been introduced, use it to obtain the frequency. Signed-off-by: TOKITA Hiroshi --- drivers/spi/spi_rpi_pico_pio.c | 39 +++++++++++++++++++++++----------- 1 file changed, 27 insertions(+), 12 deletions(-) diff --git a/drivers/spi/spi_rpi_pico_pio.c b/drivers/spi/spi_rpi_pico_pio.c index 579c97e5cdd..db348f2d5aa 100644 --- a/drivers/spi/spi_rpi_pico_pio.c +++ b/drivers/spi/spi_rpi_pico_pio.c @@ -12,6 +12,7 @@ LOG_MODULE_REGISTER(spi_pico_pio); #include #include +#include #include #include #include "spi_context.h" @@ -30,7 +31,8 @@ struct spi_pico_pio_config { struct gpio_dt_spec clk_gpio; struct gpio_dt_spec mosi_gpio; struct gpio_dt_spec miso_gpio; - const uint32_t clock_freq; + const struct device *clk_dev; + clock_control_subsys_t clk_id; }; struct spi_pico_pio_data { @@ -57,20 +59,19 @@ RPI_PICO_PIO_DEFINE_PROGRAM(spi_cpol_1_cpha_1, 0, 2, /* .wrap */ ); -static float spi_pico_pio_clock_divisor(const struct spi_pico_pio_config *dev_cfg, - uint32_t spi_frequency) +static float spi_pico_pio_clock_divisor(const uint32_t clock_freq, uint32_t spi_frequency) { - return (float)dev_cfg->clock_freq / (float)(PIO_CYCLES * spi_frequency); + return (float)clock_freq / (float)(PIO_CYCLES * spi_frequency); } -static uint32_t spi_pico_pio_maximum_clock_frequency(const struct spi_pico_pio_config *dev_cfg) +static uint32_t spi_pico_pio_maximum_clock_frequency(const uint32_t clock_freq) { - return dev_cfg->clock_freq / PIO_CYCLES; + return clock_freq / PIO_CYCLES; } -static uint32_t spi_pico_pio_minimum_clock_frequency(const struct spi_pico_pio_config *dev_cfg) +static uint32_t spi_pico_pio_minimum_clock_frequency(const uint32_t clock_freq) { - return dev_cfg->clock_freq / (PIO_CYCLES * 65536); + return clock_freq / (PIO_CYCLES * 65536); } static inline bool spi_pico_pio_transfer_ongoing(struct spi_pico_pio_data *data) @@ -109,10 +110,23 @@ static int spi_pico_pio_configure(const struct spi_pico_pio_config *dev_cfg, uint32_t cpol = 0; uint32_t cpha = 0; uint32_t bits; + uint32_t clock_freq; float clock_div; const pio_program_t *program; int rc; + rc = clock_control_on(dev_cfg->clk_dev, dev_cfg->clk_id); + if (rc < 0) { + LOG_ERR("Failed to enable the clock"); + return rc; + } + + rc = clock_control_get_rate(dev_cfg->clk_dev, dev_cfg->clk_id, &clock_freq); + if (rc < 0) { + LOG_ERR("Failed to get clock frequency"); + return rc; + } + if (spi_context_configured(&data->spi_ctx, spi_cfg)) { return 0; } @@ -143,13 +157,13 @@ static int spi_pico_pio_configure(const struct spi_pico_pio_config *dev_cfg, data->dfs = DIV_ROUND_UP(bits, 8); - if ((spi_cfg->frequency < spi_pico_pio_minimum_clock_frequency(dev_cfg)) || - (spi_cfg->frequency > spi_pico_pio_maximum_clock_frequency(dev_cfg))) { + if ((spi_cfg->frequency < spi_pico_pio_minimum_clock_frequency(clock_freq)) || + (spi_cfg->frequency > spi_pico_pio_maximum_clock_frequency(clock_freq))) { LOG_ERR("clock-frequency out of range"); return -EINVAL; } - clock_div = spi_pico_pio_clock_divisor(dev_cfg, spi_cfg->frequency); + clock_div = spi_pico_pio_clock_divisor(clock_freq, spi_cfg->frequency); /* Half-duplex mode has not been implemented */ if (spi_cfg->operation & SPI_HALF_DUPLEX) { @@ -352,7 +366,8 @@ int spi_pico_pio_init(const struct device *dev) .clk_gpio = GPIO_DT_SPEC_INST_GET(inst, clk_gpios), \ .mosi_gpio = GPIO_DT_SPEC_INST_GET_OR(inst, mosi_gpios, {0}), \ .miso_gpio = GPIO_DT_SPEC_INST_GET_OR(inst, miso_gpios, {0}), \ - .clock_freq = DT_INST_PROP_BY_PHANDLE(inst, clocks, clock_frequency), \ + .clk_dev = DEVICE_DT_GET(DT_INST_CLOCKS_CTLR(inst)), \ + .clk_id = (clock_control_subsys_t)DT_INST_PHA_BY_IDX(inst, clocks, 0, clk_id), \ }; \ static struct spi_pico_pio_data spi_pico_pio_data_##inst = { \ SPI_CONTEXT_INIT_LOCK(spi_pico_pio_data_##inst, spi_ctx), \ From cca5e3c0a46ad28bf8301c30999becb0157c02ac Mon Sep 17 00:00:00 2001 From: TOKITA Hiroshi Date: Sun, 1 Oct 2023 03:29:28 +0900 Subject: [PATCH 1465/3723] boards: arm: rpi_pico: Added clock support in documentation Added clock in supported hardware features Signed-off-by: Andrei-Edward Popa Signed-off-by: TOKITA Hiroshi --- boards/arm/rpi_pico/doc/index.rst | 3 +++ boards/arm/rpi_pico/rpi_pico.yaml | 1 + boards/arm/rpi_pico/rpi_pico_w.yaml | 1 + 3 files changed, 5 insertions(+) diff --git a/boards/arm/rpi_pico/doc/index.rst b/boards/arm/rpi_pico/doc/index.rst index c94698f14fe..f535d85506a 100644 --- a/boards/arm/rpi_pico/doc/index.rst +++ b/boards/arm/rpi_pico/doc/index.rst @@ -89,6 +89,9 @@ hardware features: * - Flash - :kconfig:option:`CONFIG_FLASH` - :dtcompatible:`raspberrypi,pico-flash` + * - Clock controller + - :kconfig:option:`CONFIG_CLOCK_CONTROL` + - :dtcompatible:`raspberrypi,pico-clock-controller` * - UART (PIO) - :kconfig:option:`CONFIG_SERIAL` - :dtcompatible:`raspberrypi,pico-uart-pio` diff --git a/boards/arm/rpi_pico/rpi_pico.yaml b/boards/arm/rpi_pico/rpi_pico.yaml index 485cfde0db5..ada56d84480 100644 --- a/boards/arm/rpi_pico/rpi_pico.yaml +++ b/boards/arm/rpi_pico/rpi_pico.yaml @@ -20,3 +20,4 @@ supported: - flash - dma - counter + - clock diff --git a/boards/arm/rpi_pico/rpi_pico_w.yaml b/boards/arm/rpi_pico/rpi_pico_w.yaml index 32bf9ef078f..12d5b473249 100644 --- a/boards/arm/rpi_pico/rpi_pico_w.yaml +++ b/boards/arm/rpi_pico/rpi_pico_w.yaml @@ -20,3 +20,4 @@ supported: - flash - dma - pio + - clock From 2c3943355d0da7e0434c736a26f15128958c0038 Mon Sep 17 00:00:00 2001 From: TOKITA Hiroshi Date: Fri, 1 Sep 2023 08:37:44 +0900 Subject: [PATCH 1466/3723] boards: arm: adafruit_kb2040: Added clock support in docs Added clock in supported hardware features Signed-off-by: TOKITA Hiroshi --- boards/arm/adafruit_kb2040/adafruit_kb2040.yaml | 1 + boards/arm/adafruit_kb2040/doc/index.rst | 3 +++ 2 files changed, 4 insertions(+) diff --git a/boards/arm/adafruit_kb2040/adafruit_kb2040.yaml b/boards/arm/adafruit_kb2040/adafruit_kb2040.yaml index 51dd75d58d9..0d386d6f0d6 100644 --- a/boards/arm/adafruit_kb2040/adafruit_kb2040.yaml +++ b/boards/arm/adafruit_kb2040/adafruit_kb2040.yaml @@ -19,3 +19,4 @@ supported: - pwm - flash - dma + - clock diff --git a/boards/arm/adafruit_kb2040/doc/index.rst b/boards/arm/adafruit_kb2040/doc/index.rst index 98c2bacf9e3..09d5bfb0960 100644 --- a/boards/arm/adafruit_kb2040/doc/index.rst +++ b/boards/arm/adafruit_kb2040/doc/index.rst @@ -79,6 +79,9 @@ hardware features: * - Flash - :kconfig:option:`CONFIG_FLASH` - :dtcompatible:`raspberrypi,pico-flash` + * - Clock controller + - :kconfig:option:`CONFIG_CLOCK_CONTROL` + - :dtcompatible:`raspberrypi,pico-clock-controller` * - UART (PIO) - :kconfig:option:`CONFIG_SERIAL` - :dtcompatible:`raspberrypi,pico-uart-pio` From aad251ecb51584de17938a20aeed0b2215dbd864 Mon Sep 17 00:00:00 2001 From: TOKITA Hiroshi Date: Fri, 1 Sep 2023 08:37:56 +0900 Subject: [PATCH 1467/3723] boards: arm: sparkfun_pro_micro_rp2040: Added clock support in docs Added clock in supported hardware features Signed-off-by: TOKITA Hiroshi --- boards/arm/sparkfun_pro_micro_rp2040/doc/index.rst | 3 +++ .../sparkfun_pro_micro_rp2040/sparkfun_pro_micro_rp2040.yaml | 1 + 2 files changed, 4 insertions(+) diff --git a/boards/arm/sparkfun_pro_micro_rp2040/doc/index.rst b/boards/arm/sparkfun_pro_micro_rp2040/doc/index.rst index 1999d64def7..3fa4fe40b71 100644 --- a/boards/arm/sparkfun_pro_micro_rp2040/doc/index.rst +++ b/boards/arm/sparkfun_pro_micro_rp2040/doc/index.rst @@ -79,6 +79,9 @@ hardware features: * - Flash - :kconfig:option:`CONFIG_FLASH` - :dtcompatible:`raspberrypi,pico-flash` + * - Clock controller + - :kconfig:option:`CONFIG_CLOCK_CONTROL` + - :dtcompatible:`raspberrypi,pico-clock-controller` * - UART (PIO) - :kconfig:option:`CONFIG_SERIAL` - :dtcompatible:`raspberrypi,pico-uart-pio` diff --git a/boards/arm/sparkfun_pro_micro_rp2040/sparkfun_pro_micro_rp2040.yaml b/boards/arm/sparkfun_pro_micro_rp2040/sparkfun_pro_micro_rp2040.yaml index d5993798ff4..978515c0eec 100644 --- a/boards/arm/sparkfun_pro_micro_rp2040/sparkfun_pro_micro_rp2040.yaml +++ b/boards/arm/sparkfun_pro_micro_rp2040/sparkfun_pro_micro_rp2040.yaml @@ -19,3 +19,4 @@ supported: - pwm - flash - dma + - clock From 7d5f3d0b9af2b49b5ee9e10d584f16800838f900 Mon Sep 17 00:00:00 2001 From: TOKITA Hiroshi Date: Sat, 30 Sep 2023 15:18:57 +0900 Subject: [PATCH 1468/3723] boards: arm: rpi_pico_w: Added counter support in docs Added counter in supported hardware features. It forgot in the commit when introducing the counter driver. Signed-off-by: TOKITA Hiroshi --- boards/arm/rpi_pico/rpi_pico_w.yaml | 1 + 1 file changed, 1 insertion(+) diff --git a/boards/arm/rpi_pico/rpi_pico_w.yaml b/boards/arm/rpi_pico/rpi_pico_w.yaml index 12d5b473249..d0acab19cc6 100644 --- a/boards/arm/rpi_pico/rpi_pico_w.yaml +++ b/boards/arm/rpi_pico/rpi_pico_w.yaml @@ -20,4 +20,5 @@ supported: - flash - dma - pio + - counter - clock From 3b28890d7c391b70d72a66c803198d7abb8e3b0e Mon Sep 17 00:00:00 2001 From: TOKITA Hiroshi Date: Sat, 30 Sep 2023 15:18:47 +0900 Subject: [PATCH 1469/3723] boards: arm: adafruit_kb2040: Added counter support in docs Added counter in supported hardware features. It forgot in the commit when introducing the counter driver. Signed-off-by: TOKITA Hiroshi --- boards/arm/adafruit_kb2040/adafruit_kb2040.yaml | 1 + 1 file changed, 1 insertion(+) diff --git a/boards/arm/adafruit_kb2040/adafruit_kb2040.yaml b/boards/arm/adafruit_kb2040/adafruit_kb2040.yaml index 0d386d6f0d6..40511a77633 100644 --- a/boards/arm/adafruit_kb2040/adafruit_kb2040.yaml +++ b/boards/arm/adafruit_kb2040/adafruit_kb2040.yaml @@ -19,4 +19,5 @@ supported: - pwm - flash - dma + - counter - clock From bd44338dd32db88931a9accc84b487500b1c05ca Mon Sep 17 00:00:00 2001 From: TOKITA Hiroshi Date: Sat, 30 Sep 2023 15:18:37 +0900 Subject: [PATCH 1470/3723] boards: arm: sparkfun_pro_micro_rp2040: Added counter support in docs Added counter in supported hardware features. It forgot in the commit when introducing the counter driver. Signed-off-by: TOKITA Hiroshi --- .../arm/sparkfun_pro_micro_rp2040/sparkfun_pro_micro_rp2040.yaml | 1 + 1 file changed, 1 insertion(+) diff --git a/boards/arm/sparkfun_pro_micro_rp2040/sparkfun_pro_micro_rp2040.yaml b/boards/arm/sparkfun_pro_micro_rp2040/sparkfun_pro_micro_rp2040.yaml index 978515c0eec..a2a8932d78f 100644 --- a/boards/arm/sparkfun_pro_micro_rp2040/sparkfun_pro_micro_rp2040.yaml +++ b/boards/arm/sparkfun_pro_micro_rp2040/sparkfun_pro_micro_rp2040.yaml @@ -19,4 +19,5 @@ supported: - pwm - flash - dma + - counter - clock From 2b24a5c90c9c3cab31160fc503ffc0efa89ea407 Mon Sep 17 00:00:00 2001 From: TOKITA Hiroshi Date: Fri, 1 Sep 2023 08:08:33 +0900 Subject: [PATCH 1471/3723] modules: hal_rpi_pico: Remove unused drivers Remove drivers that not been referenced. Signed-off-by: TOKITA Hiroshi --- modules/hal_rpi_pico/CMakeLists.txt | 2 -- 1 file changed, 2 deletions(-) diff --git a/modules/hal_rpi_pico/CMakeLists.txt b/modules/hal_rpi_pico/CMakeLists.txt index 3281528d73f..6474b18055e 100644 --- a/modules/hal_rpi_pico/CMakeLists.txt +++ b/modules/hal_rpi_pico/CMakeLists.txt @@ -82,8 +82,6 @@ if(CONFIG_HAS_RPI_PICO) zephyr_include_directories_ifdef(CONFIG_PICOSDK_USE_GPIO ${rp2_common_dir}/hardware_gpio/include) - zephyr_library_sources_ifdef(CONFIG_PICOSDK_USE_UART - ${rp2_common_dir}/hardware_uart/uart.c) zephyr_include_directories_ifdef(CONFIG_PICOSDK_USE_UART ${rp2_common_dir}/hardware_uart/include) From f4eb77f76bfbf8d322dcb7558b659c14083eeef5 Mon Sep 17 00:00:00 2001 From: Laurentiu Mihalcea Date: Wed, 15 Nov 2023 14:27:19 +0200 Subject: [PATCH 1472/3723] manifest: Bump up hal_nxp revision Bump up hal_nxp revision to contain the latest SAI-related changes from NXP HAL side. Signed-off-by: Laurentiu Mihalcea --- west.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/west.yml b/west.yml index e6a68c8934e..cd02b7125f9 100644 --- a/west.yml +++ b/west.yml @@ -193,7 +193,7 @@ manifest: groups: - hal - name: hal_nxp - revision: 2a294b540c09b36f7cddece44d25628bfde5970e + revision: ed3efff426ce56230be189d99ce985ceafece4a4 path: modules/hal/nxp groups: - hal From 897897970b140e39f3ba74639008fd450c62f6e0 Mon Sep 17 00:00:00 2001 From: Laurentiu Mihalcea Date: Tue, 14 Nov 2023 16:27:26 +0200 Subject: [PATCH 1473/3723] include: dai.h: Add definitions for parsing dai_config's format field This commit introduces some macros and enums which can be used to parse struct dai_config's format field. This is required by the SAI driver since it uses dai_config's format field to select the protocol, clock configuration and clock inversion. This is added to the dai.h header to avoid having to define these macros/enums in each of the DAI drivers. Signed-off-by: Laurentiu Mihalcea --- include/zephyr/drivers/dai.h | 55 ++++++++++++++++++++++++++++++++++++ 1 file changed, 55 insertions(+) diff --git a/include/zephyr/drivers/dai.h b/include/zephyr/drivers/dai.h index 8e5fbcf553e..e0969292fbb 100644 --- a/include/zephyr/drivers/dai.h +++ b/include/zephyr/drivers/dai.h @@ -33,6 +33,61 @@ extern "C" { #endif +/** Used to extract the clock configuration from the format attribute of struct dai_config */ +#define DAI_FORMAT_CLOCK_PROVIDER_MASK 0xf000 +/** Used to extract the protocol from the format attribute of struct dai_config */ +#define DAI_FORMAT_PROTOCOL_MASK 0x000f +/** Used to extract the clock inversion from the format attribute of struct dai_config */ +#define DAI_FORMAT_CLOCK_INVERSION_MASK 0x0f00 + +/** @brief DAI clock configurations + * + * This is used to describe all of the possible + * clock-related configurations w.r.t the DAI + * and the codec. + */ +enum dai_clock_provider { + /**< codec BLCK provider, codec FSYNC provider */ + DAI_CBP_CFP = (0 << 12), + /**< codec BCLK consumer, codec FSYNC provider */ + DAI_CBC_CFP = (2 << 12), + /**< codec BCLK provider, codec FSYNC consumer */ + DAI_CBP_CFC = (3 << 12), + /**< codec BCLK consumer, codec FSYNC consumer */ + DAI_CBC_CFC = (4 << 12), +}; + +/** @brief DAI protocol + * + * The communication between the DAI and the CODEC + * may use different protocols depending on the scenario. + */ +enum dai_protocol { + DAI_PROTO_I2S = 1, /**< I2S */ + DAI_PROTO_RIGHT_J, /**< Right Justified */ + DAI_PROTO_LEFT_J, /**< Left Justified */ + DAI_PROTO_DSP_A, /**< TDM, FSYNC asserted 1 BCLK early */ + DAI_PROTO_DSP_B, /**< TDM, FSYNC asserted at the same time as MSB */ + DAI_PROTO_PDM, /**< Pulse Density Modulation */ +}; + +/** @brief DAI clock inversion + * + * Some applications may require a different + * clock polarity (FSYNC/BCLK) compared to + * the default one chosen based on the protocol. + */ +enum dai_clock_inversion { + /**< no BCLK inversion, no FSYNC inversion */ + DAI_INVERSION_NB_NF = 0, + /**< no BCLK inversion, FSYNC inversion */ + DAI_INVERSION_NB_IF = (2 << 8), + /**< BCLK inversion, no FSYNC inversion */ + DAI_INVERSION_IB_NF = (3 << 8), + /**< BCLK inversion, FSYNC inversion */ + DAI_INVERSION_IB_IF = (4 << 8), +}; + /** @brief Types of DAI * * The type of the DAI. This ID type is used to configure bespoke DAI HW From fe64d840ccb4f597562765d0293857d94633ae75 Mon Sep 17 00:00:00 2001 From: Laurentiu Mihalcea Date: Tue, 3 Oct 2023 14:11:53 +0300 Subject: [PATCH 1474/3723] drivers: dai: Add driver for NXP's SAI This commit introduces a new DAI driver used for NXP'S SAI IP. Signed-off-by: Laurentiu Mihalcea --- drivers/dai/CMakeLists.txt | 1 + drivers/dai/Kconfig | 1 + drivers/dai/nxp/sai/CMakeLists.txt | 5 + drivers/dai/nxp/sai/Kconfig.sai | 30 ++ drivers/dai/nxp/sai/sai.c | 758 +++++++++++++++++++++++++++++ drivers/dai/nxp/sai/sai.h | 511 +++++++++++++++++++ dts/bindings/dai/nxp,dai-sai.yaml | 60 +++ 7 files changed, 1366 insertions(+) create mode 100644 drivers/dai/nxp/sai/CMakeLists.txt create mode 100644 drivers/dai/nxp/sai/Kconfig.sai create mode 100644 drivers/dai/nxp/sai/sai.c create mode 100644 drivers/dai/nxp/sai/sai.h create mode 100644 dts/bindings/dai/nxp,dai-sai.yaml diff --git a/drivers/dai/CMakeLists.txt b/drivers/dai/CMakeLists.txt index 90b5d8b931c..b6bd04939d5 100644 --- a/drivers/dai/CMakeLists.txt +++ b/drivers/dai/CMakeLists.txt @@ -4,3 +4,4 @@ add_subdirectory_ifdef(CONFIG_DAI_INTEL_SSP intel/ssp) add_subdirectory_ifdef(CONFIG_DAI_INTEL_ALH intel/alh) add_subdirectory_ifdef(CONFIG_DAI_INTEL_DMIC intel/dmic) add_subdirectory_ifdef(CONFIG_DAI_INTEL_HDA intel/hda) +add_subdirectory_ifdef(CONFIG_DAI_NXP_SAI nxp/sai) diff --git a/drivers/dai/Kconfig b/drivers/dai/Kconfig index 770b528da6a..da882a99fa0 100644 --- a/drivers/dai/Kconfig +++ b/drivers/dai/Kconfig @@ -29,5 +29,6 @@ source "drivers/dai/intel/ssp/Kconfig.ssp" source "drivers/dai/intel/alh/Kconfig.alh" source "drivers/dai/intel/dmic/Kconfig.dmic" source "drivers/dai/intel/hda/Kconfig.hda" +source "drivers/dai/nxp/sai/Kconfig.sai" endif # DAI diff --git a/drivers/dai/nxp/sai/CMakeLists.txt b/drivers/dai/nxp/sai/CMakeLists.txt new file mode 100644 index 00000000000..755261307a6 --- /dev/null +++ b/drivers/dai/nxp/sai/CMakeLists.txt @@ -0,0 +1,5 @@ +# Copyright 2023 NXP +# SPDX-License-Identifier: Apache-2.0 + +zephyr_library() +zephyr_library_sources(sai.c) diff --git a/drivers/dai/nxp/sai/Kconfig.sai b/drivers/dai/nxp/sai/Kconfig.sai new file mode 100644 index 00000000000..e123c955f6b --- /dev/null +++ b/drivers/dai/nxp/sai/Kconfig.sai @@ -0,0 +1,30 @@ +# Copyright 2023 NXP +# SPDX-License-Identifier: Apache-2.0 + +config DAI_NXP_SAI + bool "NXP Synchronous Audio Interface (SAI) driver" + default y + depends on DT_HAS_NXP_DAI_SAI_ENABLED + help + Select this to enable NXP SAI driver. + +if DAI_NXP_SAI + +config SAI_HAS_MCLK_CONFIG_OPTION + bool "Set if SAI has MCLK configuration options" + default n + help + Select this if the SAI IP allows configuration + of the master clock. Master clock configuration + refers to enabling/disabling the master clock, + setting the signal as input or output or dividing + the master clock output. + +config SAI_FIFO_WORD_SIZE + int "Size (in bytes) of a FIFO word" + default 4 + help + Use this to set the size (in bytes) of a SAI + FIFO word. + +endif # DAI_NXP_SAI diff --git a/drivers/dai/nxp/sai/sai.c b/drivers/dai/nxp/sai/sai.c new file mode 100644 index 00000000000..000c754f8b6 --- /dev/null +++ b/drivers/dai/nxp/sai/sai.c @@ -0,0 +1,758 @@ +/* + * Copyright 2023 NXP + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include +#include +#include + +#include "sai.h" + +/* used for binding the driver */ +#define DT_DRV_COMPAT nxp_dai_sai + +#define SAI_TX_RX_HW_DISABLE_TIMEOUT 50 + +/* TODO list: + * + * 1) No busy waiting should be performed in any of the operations. + * In the case of STOP(), the operation should be split into TRIGGER_STOP + * and TRIGGER_POST_STOP. (SOF) + * + * 2) The SAI ISR should stop the SAI whenever a FIFO error interrupt + * is raised. + * + * 3) Transmitter/receiver may remain enabled after sai_tx_rx_disable(). + * Fix this. + */ + +#ifdef CONFIG_SAI_HAS_MCLK_CONFIG_OPTION +/* note: i.MX8 boards don't seem to support the MICS field in the MCR + * register. As such, the MCLK source field of sai_master_clock_t is + * useless. I'm assuming the source is selected through xCR2's MSEL. + * + * TODO: for now, this function will set MCR's MSEL to the same value + * as xCR2's MSEL or, rather, to the same MCLK as the one used for + * generating BCLK. Is there a need to support different MCLKs in + * xCR2 and MCR? + */ +static int sai_mclk_config(const struct device *dev, + sai_bclk_source_t bclk_source, + const struct sai_bespoke_config *bespoke) +{ + const struct sai_config *cfg; + struct sai_data *data; + sai_master_clock_t mclk_config; + uint32_t msel, mclk_rate; + int ret; + + cfg = dev->config; + data = dev->data; + + mclk_config.mclkOutputEnable = cfg->mclk_is_output; + + ret = get_msel(bclk_source, &msel); + if (ret < 0) { + LOG_ERR("invalid MCLK source %d for MSEL", bclk_source); + return ret; + } + + /* get MCLK's rate */ + ret = get_mclk_rate(&cfg->clk_data, bclk_source, &mclk_rate); + if (ret < 0) { + LOG_ERR("failed to query MCLK's rate"); + return ret; + } + + LOG_DBG("source MCLK is %u", mclk_rate); + + LOG_DBG("target MCLK is %u", bespoke->mclk_rate); + + /* source MCLK rate */ + mclk_config.mclkSourceClkHz = mclk_rate; + + /* target MCLK rate */ + mclk_config.mclkHz = bespoke->mclk_rate; + + /* commit configuration */ + SAI_SetMasterClockConfig(UINT_TO_I2S(data->regmap), &mclk_config); + + set_msel(data->regmap, msel); + + return 0; +} +#endif /* CONFIG_SAI_HAS_MCLK_CONFIG_OPTION */ + +void sai_isr(const void *parameter) +{ + const struct device *dev; + struct sai_data *data; + + dev = parameter; + data = dev->data; + + /* check for TX FIFO error */ + if (SAI_TX_RX_STATUS_IS_SET(DAI_DIR_TX, data->regmap, kSAI_FIFOErrorFlag)) { + LOG_ERR("FIFO underrun detected"); + /* TODO: this will crash the program and should be addressed as + * mentioned in TODO list's 2). + */ + z_irq_spurious(NULL); + } + + /* check for RX FIFO error */ + if (SAI_TX_RX_STATUS_IS_SET(DAI_DIR_RX, data->regmap, kSAI_FIFOErrorFlag)) { + LOG_ERR("FIFO overrun detected"); + /* TODO: this will crash the program and should be addressed as + * mentioned in TODO list's 2). + */ + z_irq_spurious(NULL); + } +} + +static int sai_config_get(const struct device *dev, + struct dai_config *cfg, + enum dai_dir dir) +{ + struct sai_data *data = dev->data; + + /* dump content of the DAI configuration */ + memcpy(cfg, &data->cfg, sizeof(*cfg)); + + return 0; +} + +static const struct dai_properties + *sai_get_properties(const struct device *dev, enum dai_dir dir, int stream_id) +{ + const struct sai_config *cfg = dev->config; + + switch (dir) { + case DAI_DIR_RX: + return cfg->rx_props; + case DAI_DIR_TX: + return cfg->tx_props; + default: + LOG_ERR("invalid direction: %d", dir); + return NULL; + } + + CODE_UNREACHABLE; +} + +static int sai_config_set(const struct device *dev, + const struct dai_config *cfg, + const void *bespoke_data) +{ + const struct sai_bespoke_config *bespoke; + sai_transceiver_t *rx_config, *tx_config; + struct sai_data *data; + const struct sai_config *sai_cfg; + int ret; + + if (cfg->type != DAI_IMX_SAI) { + LOG_ERR("wrong DAI type: %d", cfg->type); + return -EINVAL; + } + + bespoke = bespoke_data; + data = dev->data; + sai_cfg = dev->config; + rx_config = &data->rx_config; + tx_config = &data->tx_config; + + /* since this function configures the transmitter AND the receiver, that + * means both of them need to be stopped. As such, doing the state + * transition here will also result in a state check. + */ + ret = sai_update_state(DAI_DIR_TX, data, DAI_STATE_READY); + if (ret < 0) { + LOG_ERR("failed to update TX state. Reason: %d", ret); + return ret; + } + + ret = sai_update_state(DAI_DIR_RX, data, DAI_STATE_READY); + if (ret < 0) { + LOG_ERR("failed to update RX state. Reason: %d", ret); + return ret; + } + + /* condition: BCLK = FSYNC * TDM_SLOT_WIDTH * TDM_SLOTS */ + if (bespoke->bclk_rate != + (bespoke->fsync_rate * bespoke->tdm_slot_width * bespoke->tdm_slots)) { + LOG_ERR("bad BCLK value: %d", bespoke->bclk_rate); + return -EINVAL; + } + + /* TODO: this should be removed if we're to support sw channels != hw channels */ + if (count_leading_zeros(~bespoke->tx_slots) != bespoke->tdm_slots || + count_leading_zeros(~bespoke->rx_slots) != bespoke->tdm_slots) { + LOG_ERR("number of TX/RX slots doesn't match number of TDM slots"); + return -EINVAL; + } + + /* get default configurations */ + get_bclk_default_config(&tx_config->bitClock); + get_fsync_default_config(&tx_config->frameSync); + get_serial_default_config(&tx_config->serialData); + get_fifo_default_config(&tx_config->fifo); + + /* note1: this may be obvious but enabling multiple SAI + * channels (or data lines) may lead to FIFO starvation/ + * overflow if data is not written/read from the respective + * TDR/RDR registers. + * + * note2: the SAI data line should be enabled based on + * the direction (TX/RX) we're enabling. Enabling the + * data line for the opposite direction will lead to FIFO + * overrun/underrun when working with a SYNC direction. + * + * note3: the TX/RX data line shall be enabled/disabled + * via the sai_trigger_() suite to avoid scenarios in + * which one configures both direction but only starts + * the SYNC direction which would lead to a FIFO underrun. + */ + tx_config->channelMask = 0x0; + + /* TODO: for now, only MCLK1 is supported */ + tx_config->bitClock.bclkSource = kSAI_BclkSourceMclkOption1; + + /* FSYNC is asserted for tdm_slot_width BCLKs */ + tx_config->frameSync.frameSyncWidth = bespoke->tdm_slot_width; + + /* serial data common configuration */ + tx_config->serialData.dataWord0Length = bespoke->tdm_slot_width; + tx_config->serialData.dataWordNLength = bespoke->tdm_slot_width; + tx_config->serialData.dataFirstBitShifted = bespoke->tdm_slot_width; + tx_config->serialData.dataWordNum = bespoke->tdm_slots; + + /* clock provider configuration */ + switch (cfg->format & DAI_FORMAT_CLOCK_PROVIDER_MASK) { + case DAI_CBP_CFP: + tx_config->masterSlave = kSAI_Slave; + break; + case DAI_CBC_CFC: + tx_config->masterSlave = kSAI_Master; + break; + case DAI_CBC_CFP: + case DAI_CBP_CFC: + LOG_ERR("unsupported provider configuration: %d", + cfg->format & DAI_FORMAT_CLOCK_PROVIDER_MASK); + return -ENOTSUP; + default: + LOG_ERR("invalid provider configuration: %d", + cfg->format & DAI_FORMAT_CLOCK_PROVIDER_MASK); + return -EINVAL; + } + + LOG_DBG("SAI is in %d mode", tx_config->masterSlave); + + /* protocol configuration */ + switch (cfg->format & DAI_FORMAT_PROTOCOL_MASK) { + case DAI_PROTO_I2S: + /* BCLK is active LOW */ + tx_config->bitClock.bclkPolarity = kSAI_PolarityActiveLow; + /* FSYNC is active LOW */ + tx_config->frameSync.frameSyncPolarity = kSAI_PolarityActiveLow; + break; + case DAI_PROTO_DSP_A: + /* FSYNC is asserted for a single BCLK */ + tx_config->frameSync.frameSyncWidth = 1; + /* BCLK is active LOW */ + tx_config->bitClock.bclkPolarity = kSAI_PolarityActiveLow; + break; + default: + LOG_ERR("unsupported DAI protocol: %d", + cfg->format & DAI_FORMAT_PROTOCOL_MASK); + return -EINVAL; + } + + LOG_DBG("SAI uses protocol: %d", + cfg->format & DAI_FORMAT_PROTOCOL_MASK); + + /* clock inversion configuration */ + switch (cfg->format & DAI_FORMAT_CLOCK_INVERSION_MASK) { + case DAI_INVERSION_IB_IF: + SAI_INVERT_POLARITY(tx_config->bitClock.bclkPolarity); + SAI_INVERT_POLARITY(tx_config->frameSync.frameSyncPolarity); + break; + case DAI_INVERSION_IB_NF: + SAI_INVERT_POLARITY(tx_config->bitClock.bclkPolarity); + break; + case DAI_INVERSION_NB_IF: + SAI_INVERT_POLARITY(tx_config->frameSync.frameSyncPolarity); + break; + case DAI_INVERSION_NB_NF: + /* nothing to do here */ + break; + default: + LOG_ERR("invalid clock inversion configuration: %d", + cfg->format & DAI_FORMAT_CLOCK_INVERSION_MASK); + return -EINVAL; + } + + LOG_DBG("FSYNC polarity: %d", tx_config->frameSync.frameSyncPolarity); + LOG_DBG("BCLK polarity: %d", tx_config->bitClock.bclkPolarity); + + /* duplicate TX configuration */ + memcpy(rx_config, tx_config, sizeof(sai_transceiver_t)); + + tx_config->serialData.dataMaskedWord = ~bespoke->tx_slots; + rx_config->serialData.dataMaskedWord = ~bespoke->rx_slots; + + tx_config->fifo.fifoWatermark = sai_cfg->tx_fifo_watermark - 1; + rx_config->fifo.fifoWatermark = sai_cfg->rx_fifo_watermark - 1; + + LOG_DBG("RX watermark: %d", sai_cfg->rx_fifo_watermark); + LOG_DBG("TX watermark: %d", sai_cfg->tx_fifo_watermark); + + /* TODO: for now, the only supported operation mode is RX sync with TX. + * Is there a need to support other modes? + */ + tx_config->syncMode = kSAI_ModeAsync; + rx_config->syncMode = kSAI_ModeSync; + + /* commit configuration */ + SAI_RxSetConfig(UINT_TO_I2S(data->regmap), rx_config); + SAI_TxSetConfig(UINT_TO_I2S(data->regmap), tx_config); + + /* a few notes here: + * 1) TX and RX operate in the same mode: master or slave. + * 2) Setting BCLK's rate needs to be performed explicitly + * since SetConfig() doesn't do it for us. + * 3) Setting BCLK's rate has to be performed after the + * SetConfig() call as that resets the SAI registers. + */ + if (tx_config->masterSlave == kSAI_Master) { + SAI_TxSetBitClockRate(UINT_TO_I2S(data->regmap), bespoke->mclk_rate, + bespoke->fsync_rate, bespoke->tdm_slot_width, + bespoke->tdm_slots); + + SAI_RxSetBitClockRate(UINT_TO_I2S(data->regmap), bespoke->mclk_rate, + bespoke->fsync_rate, bespoke->tdm_slot_width, + bespoke->tdm_slots); + } + +#ifdef CONFIG_SAI_HAS_MCLK_CONFIG_OPTION + ret = sai_mclk_config(dev, tx_config->bitClock.bclkSource, bespoke); + if (ret < 0) { + LOG_ERR("failed to set MCLK configuration"); + return ret; + } +#endif /* CONFIG_SAI_HAS_MCLK_CONFIG_OPTION */ + + /* this is needed so that rates different from FSYNC_RATE + * will not be allowed. + * + * this is because the hardware is configured to match + * the topology rates so attempting to play a file using + * a different rate from the one configured in the hardware + * doesn't work properly. + * + * if != 0, SOF will raise an error if the PCM rate is + * different than the hardware rate (a.k.a this one). + */ + data->cfg.rate = bespoke->fsync_rate; + /* SOF note: we don't support a variable number of channels + * at the moment so leaving the number of channels as 0 is + * unnecessary and leads to issues (e.g: the mixer buffers + * use this value to set the number of channels so having + * a 0 as this value leads to mixer buffers having 0 channels, + * which, in turn, leads to the DAI ending up with 0 channels, + * thus resulting in an error) + */ + data->cfg.channels = bespoke->tdm_slots; + + sai_dump_register_data(data->regmap); + + return 0; +} + +/* SOF note: please be very careful with this function as it does + * busy waiting and may mess up your timing in time critial applications + * (especially with timer domain). If this becomes unusable, the busy + * waiting should be removed altogether and the HW state check should + * be performed in sai_trigger_start() or in sai_config_set(). + * + * TODO: seems like the transmitter still remains active (even if 1ms + * has passed after doing a sai_trigger_stop()!). Most likely this is + * because sai_trigger_stop() immediately stops the data line w/o + * checking the HW state of the transmitter/receiver. As such, to get + * rid of the busy waiting, the STOP operation may have to be split into + * 2 operations: TRIG_STOP and TRIG_POST_STOP. + */ +static int sai_tx_rx_disable(struct sai_data *data, enum dai_dir dir) +{ + bool ret; + + /* sai_disable() should never be called from ISR context + * as it does some busy waiting. + */ + if (k_is_in_isr()) { + LOG_ERR("sai_disable() should never be called from ISR context"); + return -EINVAL; + } + + if ((dir == DAI_DIR_TX && !data->rx_enabled) || dir == DAI_DIR_RX) { + /* VERY IMPORTANT: DO NOT use SAI_TxEnable/SAI_RxEnable + * here as they do not disable the ASYNC direction. + * Since the software logic assures that the ASYNC direction + * is not disabled before the SYNC direction, we can force + * the disablement of the given direction. + */ + sai_tx_rx_force_disable(dir, data->regmap); + + /* please note the difference between the transmitter/receiver's + * hardware states and their software states. The software + * states can be obtained by reading data->tx/rx_enabled, while + * the hardware states can be obtained by reading TCSR/RCSR. The + * hadrware state can actually differ from the software state. + * Here, we're interested in reading the hardware state which + * indicates if the transmitter/receiver was actually disabled + * or not. + */ + ret = WAIT_FOR(!SAI_TX_RX_IS_HW_ENABLED(dir, data->regmap), + SAI_TX_RX_HW_DISABLE_TIMEOUT, k_busy_wait(1)); + if (!ret) { + LOG_ERR("timed out while waiting for dir %d disable", dir); + return -ETIMEDOUT; + } + } + + /* if TX wasn't explicitly enabled (via sai_trigger_start(TX)) + * then that means it was enabled by a sai_trigger_start(RX). As + * such, data->tx_enabled will be false. + */ + if (dir == DAI_DIR_RX && !data->tx_enabled) { + sai_tx_rx_force_disable(DAI_DIR_TX, data->regmap); + + ret = WAIT_FOR(!SAI_TX_RX_IS_HW_ENABLED(DAI_DIR_TX, data->regmap), + SAI_TX_RX_HW_DISABLE_TIMEOUT, k_busy_wait(1)); + if (!ret) { + LOG_ERR("timed out while waiting for dir TX disable"); + return -ETIMEDOUT; + } + } + + return 0; +} + +static int sai_trigger_pause(const struct device *dev, + enum dai_dir dir) +{ + struct sai_data *data; + int ret; + + data = dev->data; + + if (dir != DAI_DIR_RX && dir != DAI_DIR_TX) { + LOG_ERR("invalid direction: %d", dir); + return -EINVAL; + } + + /* attempt to change state */ + ret = sai_update_state(dir, data, DAI_STATE_PAUSED); + if (ret < 0) { + LOG_ERR("failed to transition to PAUSED from %d. Reason: %d", + sai_get_state(dir, data), ret); + return ret; + } + + LOG_DBG("pause on direction %d", dir); + + ret = sai_tx_rx_disable(data, dir); + if (ret < 0) { + return ret; + } + + /* update the software state of TX/RX */ + sai_tx_rx_sw_enable_disable(dir, data, false); + + return 0; +} + +static int sai_trigger_stop(const struct device *dev, + enum dai_dir dir) +{ + struct sai_data *data; + int ret; + uint32_t old_state; + + data = dev->data; + old_state = sai_get_state(dir, data); + + if (dir != DAI_DIR_RX && dir != DAI_DIR_TX) { + LOG_ERR("invalid direction: %d", dir); + return -EINVAL; + } + + /* attempt to change state */ + ret = sai_update_state(dir, data, DAI_STATE_STOPPING); + if (ret < 0) { + LOG_ERR("failed to transition to STOPPING from %d. Reason: %d", + sai_get_state(dir, data), ret); + return ret; + } + + LOG_DBG("stop on direction %d", dir); + + if (old_state == DAI_STATE_PAUSED) { + /* if SAI was previously paused then all that's + * left to do is disable the DMA requests and + * the data line. + */ + goto out_dline_disable; + } + + ret = sai_tx_rx_disable(data, dir); + if (ret < 0) { + return ret; + } + + /* update the software state of TX/RX */ + sai_tx_rx_sw_enable_disable(dir, data, false); + +out_dline_disable: + /* disable TX/RX data line */ + sai_tx_rx_set_dline_mask(dir, data->regmap, 0x0); + + /* disable DMA requests */ + SAI_TX_RX_DMA_ENABLE_DISABLE(dir, data->regmap, false); + + /* disable error interrupt */ + SAI_TX_RX_ENABLE_DISABLE_IRQ(dir, data->regmap, + kSAI_FIFOErrorInterruptEnable, false); + + return 0; +} + +static int sai_trigger_start(const struct device *dev, + enum dai_dir dir) +{ + struct sai_data *data; + uint32_t old_state; + int ret; + + data = dev->data; + old_state = sai_get_state(dir, data); + + /* TX and RX should be triggered independently */ + if (dir != DAI_DIR_RX && dir != DAI_DIR_TX) { + LOG_ERR("invalid direction: %d", dir); + return -EINVAL; + } + + /* attempt to change state */ + ret = sai_update_state(dir, data, DAI_STATE_RUNNING); + if (ret < 0) { + LOG_ERR("failed to transition to RUNNING from %d. Reason: %d", + sai_get_state(dir, data), ret); + return ret; + } + + if (old_state == DAI_STATE_PAUSED) { + /* if the SAI has been paused then there's no + * point in issuing a software reset. As such, + * skip this part and go directly to the TX/RX + * enablement. + */ + goto out_enable_tx_rx; + } + + LOG_DBG("start on direction %d", dir); + + if (dir == DAI_DIR_RX) { + /* this is fine because TX is async so it won't be + * affected by an RX software reset. + */ + SAI_TX_RX_SW_RESET(dir, data->regmap); + + /* do a TX software reset only if not already enabled */ + if (!data->tx_enabled) { + SAI_TX_RX_SW_RESET(DAI_DIR_TX, data->regmap); + } + } else { + /* a software reset should be issued for TX + * only if RX was not already enabled. + */ + if (!data->rx_enabled) { + SAI_TX_RX_SW_RESET(dir, data->regmap); + } + } + + /* enable error interrupt */ + SAI_TX_RX_ENABLE_DISABLE_IRQ(dir, data->regmap, + kSAI_FIFOErrorInterruptEnable, true); + + /* TODO: is there a need to write some words to the FIFO to avoid starvation? */ + + /* TODO: for now, only DMA mode is supported */ + SAI_TX_RX_DMA_ENABLE_DISABLE(dir, data->regmap, true); + + /* enable TX/RX data line. This translates to TX_DLINE0/RX_DLINE0 + * being enabled. + * + * TODO: for now we only support 1 data line per direction. + */ + sai_tx_rx_set_dline_mask(dir, data->regmap, 0x1); + +out_enable_tx_rx: + /* this will also enable the async side */ + SAI_TX_RX_ENABLE_DISABLE(dir, data->regmap, true); + + /* update the software state of TX/RX */ + sai_tx_rx_sw_enable_disable(dir, data, true); + + return 0; +} + +static int sai_trigger(const struct device *dev, + enum dai_dir dir, + enum dai_trigger_cmd cmd) +{ + switch (cmd) { + case DAI_TRIGGER_START: + return sai_trigger_start(dev, dir); + case DAI_TRIGGER_PAUSE: + return sai_trigger_pause(dev, dir); + case DAI_TRIGGER_STOP: + return sai_trigger_stop(dev, dir); + case DAI_TRIGGER_PRE_START: + case DAI_TRIGGER_COPY: + /* COPY and PRE_START don't require the SAI + * driver to do anything at the moment so + * mark them as successful via a NULL return + * + * note: although the rest of the unhandled + * trigger commands may be valid, return + * an error code for them as they aren't + * implemented ATM (since they're not + * mandatory for the SAI driver to work). + */ + return 0; + default: + LOG_ERR("invalid trigger command: %d", cmd); + return -EINVAL; + } + + CODE_UNREACHABLE; +} + +static int sai_probe(const struct device *dev) +{ + /* nothing to be done here but sadly mandatory to implement */ + return 0; +} + +static int sai_remove(const struct device *dev) +{ + /* nothing to be done here but sadly mandatory to implement */ + return 0; +} + +static const struct dai_driver_api sai_api = { + .config_set = sai_config_set, + .config_get = sai_config_get, + .trigger = sai_trigger, + .get_properties = sai_get_properties, + .probe = sai_probe, + .remove = sai_remove, +}; + +static int sai_init(const struct device *dev) +{ + const struct sai_config *cfg; + struct sai_data *data; + int i, ret; + + cfg = dev->config; + data = dev->data; + + device_map(&data->regmap, cfg->regmap_phys, cfg->regmap_size, K_MEM_CACHE_NONE); + + /* enable clocks if any */ + for (i = 0; i < cfg->clk_data.clock_num; i++) { + ret = clock_control_on(cfg->clk_data.dev, + UINT_TO_POINTER(cfg->clk_data.clocks[i])); + if (ret < 0) { + return ret; + } + + LOG_DBG("clock %s has been ungated", cfg->clk_data.clock_names[i]); + } + + /* set TX/RX default states */ + data->tx_state = DAI_STATE_NOT_READY; + data->rx_state = DAI_STATE_NOT_READY; + + /* register ISR and enable IRQ */ + cfg->irq_config(); + + return 0; +} + +#define SAI_INIT(inst) \ + \ +BUILD_ASSERT(SAI_FIFO_DEPTH(inst) > 0 && \ + SAI_FIFO_DEPTH(inst) <= _SAI_FIFO_DEPTH(inst), \ + "invalid FIFO depth"); \ + \ +BUILD_ASSERT(SAI_RX_FIFO_WATERMARK(inst) > 0 && \ + SAI_RX_FIFO_WATERMARK(inst) <= _SAI_FIFO_DEPTH(inst), \ + "invalid RX FIFO watermark"); \ + \ +BUILD_ASSERT(SAI_TX_FIFO_WATERMARK(inst) > 0 && \ + SAI_TX_FIFO_WATERMARK(inst) <= _SAI_FIFO_DEPTH(inst), \ + "invalid TX FIFO watermark"); \ + \ +BUILD_ASSERT(IS_ENABLED(CONFIG_SAI_HAS_MCLK_CONFIG_OPTION) || \ + !DT_INST_PROP(inst, mclk_is_output), \ + "SAI doesn't support MCLK config but mclk_is_output is specified");\ + \ +static const struct dai_properties sai_tx_props_##inst = { \ + .fifo_address = SAI_TX_FIFO_BASE(inst), \ + .fifo_depth = SAI_FIFO_DEPTH(inst) * CONFIG_SAI_FIFO_WORD_SIZE, \ + .dma_hs_id = SAI_TX_DMA_MUX(inst), \ +}; \ + \ +static const struct dai_properties sai_rx_props_##inst = { \ + .fifo_address = SAI_RX_FIFO_BASE(inst), \ + .fifo_depth = SAI_FIFO_DEPTH(inst) * CONFIG_SAI_FIFO_WORD_SIZE, \ + .dma_hs_id = SAI_RX_DMA_MUX(inst), \ +}; \ + \ +void irq_config_##inst(void) \ +{ \ + IRQ_CONNECT(DT_INST_IRQN(inst), \ + 0, \ + sai_isr, \ + DEVICE_DT_INST_GET(inst), \ + 0); \ + irq_enable(DT_INST_IRQN(inst)); \ +} \ + \ +static struct sai_config sai_config_##inst = { \ + .regmap_phys = DT_INST_REG_ADDR(inst), \ + .regmap_size = DT_INST_REG_SIZE(inst), \ + .clk_data = SAI_CLOCK_DATA_DECLARE(inst), \ + .rx_fifo_watermark = SAI_RX_FIFO_WATERMARK(inst), \ + .tx_fifo_watermark = SAI_TX_FIFO_WATERMARK(inst), \ + .mclk_is_output = DT_INST_PROP_OR(inst, mclk_is_output, false), \ + .tx_props = &sai_tx_props_##inst, \ + .rx_props = &sai_rx_props_##inst, \ + .irq_config = irq_config_##inst, \ +}; \ + \ +static struct sai_data sai_data_##inst = { \ + .cfg.type = DAI_IMX_SAI, \ + .cfg.dai_index = DT_INST_PROP_OR(inst, dai_index, 0), \ +}; \ + \ +DEVICE_DT_INST_DEFINE(inst, &sai_init, NULL, \ + &sai_data_##inst, &sai_config_##inst, \ + POST_KERNEL, CONFIG_DAI_INIT_PRIORITY, \ + &sai_api); \ + +DT_INST_FOREACH_STATUS_OKAY(SAI_INIT); diff --git a/drivers/dai/nxp/sai/sai.h b/drivers/dai/nxp/sai/sai.h new file mode 100644 index 00000000000..33200d5a8fe --- /dev/null +++ b/drivers/dai/nxp/sai/sai.h @@ -0,0 +1,511 @@ +/* Copyright 2023 NXP + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#ifndef ZEPHYR_DRIVERS_DAI_NXP_SAI_H_ +#define ZEPHYR_DRIVERS_DAI_NXP_SAI_H_ + +#include +#include +#include + +LOG_MODULE_REGISTER(nxp_dai_sai); + +#ifdef CONFIG_SAI_HAS_MCLK_CONFIG_OPTION +#define SAI_MCLK_MCR_MSEL_SHIFT 24 +#define SAI_MCLK_MCR_MSEL_MASK GENMASK(24, 25) +#endif /* CONFIG_SAI_HAS_MCLK_CONFIG_OPTION */ +/* workaround the fact that device_map() doesn't exist for SoCs with no MMU */ +#ifndef DEVICE_MMIO_IS_IN_RAM +#define device_map(virt, phys, size, flags) *(virt) = (phys) +#endif /* DEVICE_MMIO_IS_IN_RAM */ + +/* used to convert an uint to I2S_Type * */ +#define UINT_TO_I2S(x) ((I2S_Type *)(uintptr_t)(x)) + +/* macros used for parsing DTS data */ + +/* used instead of IDENTITY because LISTIFY expects the used macro function + * to also take a variable number of arguments. + */ +#define IDENTITY_VARGS(V, ...) IDENTITY(V) + +/* used to generate the list of clock indexes */ +#define _SAI_CLOCK_INDEX_ARRAY(inst)\ + LISTIFY(DT_INST_PROP_LEN_OR(inst, clocks, 0), IDENTITY_VARGS, (,)) + +/* used to retrieve a clock's ID using its index generated via _SAI_CLOCK_INDEX_ARRAY */ +#define _SAI_GET_CLOCK_ID(clock_idx, inst)\ + DT_INST_CLOCKS_CELL_BY_IDX(inst, clock_idx, name) + +/* used to retrieve a clock's name using its index generated via _SAI_CLOCK_INDEX_ARRAY */ +#define _SAI_GET_CLOCK_NAME(clock_idx, inst)\ + DT_INST_PROP_BY_IDX(inst, clock_names, clock_idx) + +/* used to convert the clocks property into an array of clock IDs */ +#define _SAI_CLOCK_ID_ARRAY(inst)\ + FOR_EACH_FIXED_ARG(_SAI_GET_CLOCK_ID, (,), inst, _SAI_CLOCK_INDEX_ARRAY(inst)) + +/* used to convert the clock-names property into an array of clock names */ +#define _SAI_CLOCK_NAME_ARRAY(inst)\ + FOR_EACH_FIXED_ARG(_SAI_GET_CLOCK_NAME, (,), inst, _SAI_CLOCK_INDEX_ARRAY(inst)) + +/* used to convert a clocks property into an array of clock IDs. If the property + * is not specified then this macro will return {}. + */ +#define _SAI_GET_CLOCK_ARRAY(inst)\ + COND_CODE_1(DT_NODE_HAS_PROP(DT_INST(inst, nxp_dai_sai), clocks),\ + ({ _SAI_CLOCK_ID_ARRAY(inst) }),\ + ({ })) + +/* used to retrieve a const struct device *dev pointing to the clock controller. + * It is assumed that all SAI clocks come from a single clock provider. + * This macro returns a NULL if the clocks property doesn't exist. + */ +#define _SAI_GET_CLOCK_CONTROLLER(inst)\ + COND_CODE_1(DT_NODE_HAS_PROP(DT_INST(inst, nxp_dai_sai), clocks),\ + (DEVICE_DT_GET(DT_INST_CLOCKS_CTLR(inst))),\ + (NULL)) + +/* used to convert a clock-names property into an array of clock names. If the + * property is not specified then this macro will return {}. + */ +#define _SAI_GET_CLOCK_NAMES(inst)\ + COND_CODE_1(DT_NODE_HAS_PROP(DT_INST(inst, nxp_dai_sai), clocks),\ + ({ _SAI_CLOCK_NAME_ARRAY(inst) }),\ + ({ })) + +/* used to declare a struct clock_data */ +#define SAI_CLOCK_DATA_DECLARE(inst) \ +{ \ + .clocks = (uint32_t [])_SAI_GET_CLOCK_ARRAY(inst), \ + .clock_num = DT_INST_PROP_LEN_OR(inst, clocks, 0), \ + .dev = _SAI_GET_CLOCK_CONTROLLER(inst), \ + .clock_names = (const char *[])_SAI_GET_CLOCK_NAMES(inst), \ +} + +/* used to parse the tx-fifo-watermark property. If said property is not + * specified then this macro will return half of the number of words in the + * FIFO. + */ +#define SAI_TX_FIFO_WATERMARK(inst)\ + DT_INST_PROP_OR(inst, tx_fifo_watermark,\ + FSL_FEATURE_SAI_FIFO_COUNTn(UINT_TO_I2S(DT_INST_REG_ADDR(inst))) / 2) + +/* used to parse the rx-fifo-watermark property. If said property is not + * specified then this macro will return half of the number of words in the + * FIFO. + */ +#define SAI_RX_FIFO_WATERMARK(inst)\ + DT_INST_PROP_OR(inst, rx_fifo_watermark,\ + FSL_FEATURE_SAI_FIFO_COUNTn(UINT_TO_I2S(DT_INST_REG_ADDR(inst))) / 2) + +/* used to retrieve TFR0's address based on SAI's physical address */ +#define SAI_TX_FIFO_BASE(inst)\ + FSL_FEATURE_SAI_TX_FIFO_BASEn(UINT_TO_I2S(DT_INST_REG_ADDR(inst)), 0) + +/* used to retrieve RFR0's address based on SAI's physical address */ +#define SAI_RX_FIFO_BASE(inst)\ + FSL_FEATURE_SAI_RX_FIFO_BASEn(UINT_TO_I2S(DT_INST_REG_ADDR(inst)), 0) + +/* internal macro used to retrieve the default TX/RX FIFO's size (in FIFO words) */ +#define _SAI_FIFO_DEPTH(inst)\ + FSL_FEATURE_SAI_FIFO_COUNTn(UINT_TO_I2S(DT_INST_REG_ADDR(inst))) + +/* used to retrieve the TX/RX FIFO's size (in FIFO words) */ +#define SAI_FIFO_DEPTH(inst)\ + DT_INST_PROP_OR(inst, fifo_depth, _SAI_FIFO_DEPTH(inst)) + +/* used to retrieve the DMA MUX for transmitter */ +#define SAI_TX_DMA_MUX(inst)\ + FSL_FEATURE_SAI_TX_DMA_MUXn(UINT_TO_I2S(DT_INST_REG_ADDR(inst))) + +/* used to retrieve the DMA MUX for receiver */ +#define SAI_RX_DMA_MUX(inst)\ + FSL_FEATURE_SAI_RX_DMA_MUXn(UINT_TO_I2S(DT_INST_REG_ADDR(inst))) + +/* utility macros */ + +/* invert a clock's polarity. This works because a clock's polarity is expressed + * as a 0 or as a 1. + */ +#define SAI_INVERT_POLARITY(polarity) (polarity) = !(polarity) + +/* used to issue a software reset of the transmitter/receiver */ +#define SAI_TX_RX_SW_RESET(dir, regmap)\ + ((dir) == DAI_DIR_RX ? SAI_RxSoftwareReset(UINT_TO_I2S(regmap), kSAI_ResetTypeSoftware) :\ + SAI_TxSoftwareReset(UINT_TO_I2S(regmap), kSAI_ResetTypeSoftware)) + +/* used to enable/disable the transmitter/receiver. + * When enabling the SYNC component, the ASYNC component will also be enabled. + * Attempting to disable the SYNC component will fail unless the SYNC bit is + * cleared. It is recommended to use sai_tx_rx_force_disable() instead of this + * macro when disabling transmitter/receiver. + */ +#define SAI_TX_RX_ENABLE_DISABLE(dir, regmap, enable)\ + ((dir) == DAI_DIR_RX ? SAI_RxEnable(UINT_TO_I2S(regmap), enable) :\ + SAI_TxEnable(UINT_TO_I2S(regmap), enable)) + +/* used to enable/disable the DMA requests for transmitter/receiver */ +#define SAI_TX_RX_DMA_ENABLE_DISABLE(dir, regmap, enable)\ + ((dir) == DAI_DIR_RX ? SAI_RxEnableDMA(UINT_TO_I2S(regmap),\ + kSAI_FIFORequestDMAEnable, enable) :\ + SAI_TxEnableDMA(UINT_TO_I2S(regmap), kSAI_FIFORequestDMAEnable, enable)) + +/* used to check if the hardware transmitter/receiver is enabled */ +#define SAI_TX_RX_IS_HW_ENABLED(dir, regmap)\ + ((dir) == DAI_DIR_RX ? (UINT_TO_I2S(regmap)->RCSR & I2S_RCSR_RE_MASK) : \ + (UINT_TO_I2S(regmap)->TCSR & I2S_TCSR_TE_MASK)) + +/* used to enable various transmitter/receiver interrupts */ +#define _SAI_TX_RX_ENABLE_IRQ(dir, regmap, which)\ + ((dir) == DAI_DIR_RX ? SAI_RxEnableInterrupts(UINT_TO_I2S(regmap), which) : \ + SAI_TxEnableInterrupts(UINT_TO_I2S(regmap), which)) + +/* used to disable various transmitter/receiver interrupts */ +#define _SAI_TX_RX_DISABLE_IRQ(dir, regmap, which)\ + ((dir) == DAI_DIR_RX ? SAI_RxDisableInterrupts(UINT_TO_I2S(regmap), which) : \ + SAI_TxDisableInterrupts(UINT_TO_I2S(regmap), which)) + +/* used to enable/disable various transmitter/receiver interrupts */ +#define SAI_TX_RX_ENABLE_DISABLE_IRQ(dir, regmap, which, enable)\ + ((enable == true) ? _SAI_TX_RX_ENABLE_IRQ(dir, regmap, which) :\ + _SAI_TX_RX_DISABLE_IRQ(dir, regmap, which)) + +/* used to check if a status flag is set */ +#define SAI_TX_RX_STATUS_IS_SET(dir, regmap, which)\ + ((dir) == DAI_DIR_RX ? ((UINT_TO_I2S(regmap))->RCSR & (which)) : \ + ((UINT_TO_I2S(regmap))->TCSR & (which))) + +struct sai_clock_data { + uint32_t *clocks; + uint32_t clock_num; + /* assumption: all clocks belong to the same producer */ + const struct device *dev; + const char **clock_names; +}; + +struct sai_data { + mm_reg_t regmap; + sai_transceiver_t rx_config; + sai_transceiver_t tx_config; + bool tx_enabled; + bool rx_enabled; + enum dai_state tx_state; + enum dai_state rx_state; + struct dai_config cfg; +}; + +struct sai_config { + uint32_t regmap_phys; + uint32_t regmap_size; + struct sai_clock_data clk_data; + bool mclk_is_output; + /* if the tx/rx-fifo-watermark properties are not specified, it's going + * to be assumed that the watermark should be set to half of the FIFO + * size. + */ + uint32_t rx_fifo_watermark; + uint32_t tx_fifo_watermark; + const struct dai_properties *tx_props; + const struct dai_properties *rx_props; + uint32_t dai_index; + void (*irq_config)(void); +}; + +/* this needs to perfectly match SOF's struct sof_ipc_dai_sai_params */ +struct sai_bespoke_config { + uint32_t reserved0; + + uint16_t reserved1; + uint16_t mclk_id; + uint32_t mclk_direction; + + /* CLOCK-related data */ + uint32_t mclk_rate; + uint32_t fsync_rate; + uint32_t bclk_rate; + + /* TDM-related data */ + uint32_t tdm_slots; + uint32_t rx_slots; + uint32_t tx_slots; + uint16_t tdm_slot_width; + uint16_t reserved2; +}; + +#ifdef CONFIG_SAI_HAS_MCLK_CONFIG_OPTION +static int get_msel(sai_bclk_source_t bclk_source, uint32_t *msel) +{ + switch (bclk_source) { + case kSAI_BclkSourceMclkOption1: + *msel = 0; + break; + case kSAI_BclkSourceMclkOption2: + *msel = (0x2 << SAI_MCLK_MCR_MSEL_SHIFT); + break; + case kSAI_BclkSourceMclkOption3: + *msel = (0x3 << SAI_MCLK_MCR_MSEL_SHIFT); + break; + default: + return -EINVAL; + } + + return 0; +} + +static void set_msel(uint32_t regmap, int msel) +{ + UINT_TO_I2S(regmap)->MCR &= ~SAI_MCLK_MCR_MSEL_MASK; + UINT_TO_I2S(regmap)->MCR |= msel; +} + +static int clk_lookup_by_name(const struct sai_clock_data *clk_data, char *name) +{ + int i; + + for (i = 0; i < clk_data->clock_num; i++) { + if (!strcmp(name, clk_data->clock_names[i])) { + return i; + } + } + + return -EINVAL; +} + +static int get_mclk_rate(const struct sai_clock_data *clk_data, + sai_bclk_source_t bclk_source, + uint32_t *rate) +{ + int clk_idx; + char *clk_name; + + switch (bclk_source) { + case kSAI_BclkSourceMclkOption1: + clk_name = "mclk1"; + break; + case kSAI_BclkSourceMclkOption2: + clk_name = "mclk2"; + break; + case kSAI_BclkSourceMclkOption3: + clk_name = "mclk3"; + break; + default: + LOG_ERR("invalid bitclock source: %d", bclk_source); + return -EINVAL; + } + + clk_idx = clk_lookup_by_name(clk_data, clk_name); + if (clk_idx < 0) { + LOG_ERR("failed to get clock index for %s", clk_name); + return clk_idx; + } + + return clock_control_get_rate(clk_data->dev, + UINT_TO_POINTER(clk_data->clocks[clk_idx]), + rate); +} +#endif /* CONFIG_SAI_HAS_MCLK_CONFIG_OPTION */ + +static inline void get_bclk_default_config(sai_bit_clock_t *cfg) +{ + memset(cfg, 0, sizeof(sai_bit_clock_t)); + + /* by default, BCLK has the following properties: + * + * 1) BCLK is active HIGH. + * 2) BCLK uses MCLK1 source. (only applicable to master mode) + * 3) No source swap. + * 4) No input delay. + */ + cfg->bclkPolarity = kSAI_PolarityActiveHigh; + cfg->bclkSource = kSAI_BclkSourceMclkOption1; +} + +static inline void get_fsync_default_config(sai_frame_sync_t *cfg) +{ + memset(cfg, 0, sizeof(sai_frame_sync_t)); + + /* by default, FSYNC has the following properties: + * + * 1) FSYNC is asserted one bit early with respect to the next + * frame. + * 2) FSYNC is active HIGH. + */ + cfg->frameSyncEarly = true; + cfg->frameSyncPolarity = kSAI_PolarityActiveHigh; +} + +static inline void get_serial_default_config(sai_serial_data_t *cfg) +{ + memset(cfg, 0, sizeof(sai_serial_data_t)); + + /* by default, the serial configuration has the following quirks: + * + * 1) Data pin is not tri-stated. + * 2) MSB is first. + */ + /* note: this is equivalent to checking if the SAI has xCR4's CHMOD bit */ +#if FSL_FEATURE_SAI_HAS_CHANNEL_MODE + cfg->dataMode = kSAI_DataPinStateOutputZero; +#endif /* FSL_FEATURE_SAI_HAS_CHANNEL_MODE */ + cfg->dataOrder = kSAI_DataMSB; +} + +static inline void get_fifo_default_config(sai_fifo_t *cfg) +{ + memset(cfg, 0, sizeof(sai_fifo_t)); +} + +static inline uint32_t sai_get_state(enum dai_dir dir, + struct sai_data *data) +{ + if (dir == DAI_DIR_RX) { + return data->rx_state; + } else { + return data->tx_state; + } +} + +static int sai_update_state(enum dai_dir dir, + struct sai_data *data, + enum dai_state new_state) +{ + enum dai_state old_state = sai_get_state(dir, data); + + LOG_DBG("attempting to transition from %d to %d", old_state, new_state); + + /* check if transition is possible */ + switch (new_state) { + case DAI_STATE_NOT_READY: + /* this shouldn't be possible */ + return -EPERM; + case DAI_STATE_READY: + if (old_state != DAI_STATE_NOT_READY && + old_state != DAI_STATE_READY && + old_state != DAI_STATE_STOPPING) { + return -EPERM; + } + break; + case DAI_STATE_RUNNING: + if (old_state != DAI_STATE_PAUSED && + old_state != DAI_STATE_STOPPING && + old_state != DAI_STATE_READY) { + return -EPERM; + } + break; + case DAI_STATE_PAUSED: + if (old_state != DAI_STATE_RUNNING) { + return -EPERM; + } + break; + case DAI_STATE_STOPPING: + if (old_state != DAI_STATE_READY && + old_state != DAI_STATE_RUNNING && + old_state != DAI_STATE_PAUSED) { + return -EPERM; + } + break; + case DAI_STATE_ERROR: + case DAI_STATE_PRE_RUNNING: + /* these states are not used so transitioning to them + * is considered invalid. + */ + default: + return -EINVAL; + } + + if (dir == DAI_DIR_RX) { + data->rx_state = new_state; + } else { + data->tx_state = new_state; + } + + return 0; +} + +static inline void sai_tx_rx_force_disable(enum dai_dir dir, + uint32_t regmap) +{ + I2S_Type *base = UINT_TO_I2S(regmap); + + if (dir == DAI_DIR_RX) { + base->RCSR = ((base->RCSR & 0xFFE3FFFFU) & (~I2S_RCSR_RE_MASK)); + } else { + base->TCSR = ((base->TCSR & 0xFFE3FFFFU) & (~I2S_TCSR_TE_MASK)); + } +} + +static inline void sai_tx_rx_sw_enable_disable(enum dai_dir dir, + struct sai_data *data, + bool enable) +{ + if (dir == DAI_DIR_RX) { + data->rx_enabled = enable; + } else { + data->tx_enabled = enable; + } +} + +static inline int count_leading_zeros(uint32_t word) +{ + int num = 0; + + while (word) { + if (!(word & 0x1)) { + num++; + } else { + break; + } + + word = word >> 1; + } + + return num; +} + +static inline void sai_tx_rx_set_dline_mask(enum dai_dir dir, uint32_t regmap, uint32_t mask) +{ + I2S_Type *base = UINT_TO_I2S(regmap); + + if (dir == DAI_DIR_RX) { + base->RCR3 &= ~I2S_RCR3_RCE_MASK; + base->RCR3 |= I2S_RCR3_RCE(mask); + } else { + base->TCR3 &= ~I2S_TCR3_TCE_MASK; + base->TCR3 |= I2S_TCR3_TCE(mask); + } +} + +static inline void sai_dump_register_data(uint32_t regmap) +{ + I2S_Type *base = UINT_TO_I2S(regmap); + + LOG_DBG("TCSR: 0x%x", base->TCSR); + LOG_DBG("RCSR: 0x%x", base->RCSR); + + LOG_DBG("TCR1: 0x%x", base->TCR1); + LOG_DBG("RCR1: 0x%x", base->RCR1); + + LOG_DBG("TCR2: 0x%x", base->TCR2); + LOG_DBG("RCR2: 0x%x", base->RCR2); + + LOG_DBG("TCR3: 0x%x", base->TCR3); + LOG_DBG("RCR3: 0x%x", base->RCR3); + + LOG_DBG("TCR4: 0x%x", base->TCR4); + LOG_DBG("RCR4: 0x%x", base->RCR4); + + LOG_DBG("TCR5: 0x%x", base->TCR5); + LOG_DBG("RCR5: 0x%x", base->RCR5); + + LOG_DBG("TMR: 0x%x", base->TMR); + LOG_DBG("RMR: 0x%x", base->RMR); + +#ifdef CONFIG_SAI_HAS_MCLK_CONFIG_OPTION + LOG_DBG("MCR: 0x%x", base->MCR); +#endif /* CONFIG_SAI_HAS_MCLK_CONFIG_OPTION */ +} + +#endif /* ZEPHYR_DRIVERS_DAI_NXP_SAI_H_ */ diff --git a/dts/bindings/dai/nxp,dai-sai.yaml b/dts/bindings/dai/nxp,dai-sai.yaml new file mode 100644 index 00000000000..901382f90bb --- /dev/null +++ b/dts/bindings/dai/nxp,dai-sai.yaml @@ -0,0 +1,60 @@ +# Copyright 2023 NXP +# SPDX-License-Identifier: Apache-2.0 + +description: NXP Synchronous Audio Interface (SAI) node + +compatible: "nxp,dai-sai" + +include: base.yaml + +properties: + reg: + required: true + mclk-is-output: + type: boolean + description: | + Use this property to set the SAI MCLK as output or as input. + By default, if this property is not specified, MCLK will be + set as input. Setting the MCLK as output for SAIs which don't + support MCLK configuration will result in a BUILD_ASSERT() + failure. + rx-fifo-watermark: + type: int + description: | + Use this property to specify the watermark value for the TX + FIFO. This value needs to be in FIFO words (NOT BYTES). This + value needs to be in the following interval: (0, DEFAULT_FIFO_DEPTH], + otherwise a BUILD_ASSERT() failure will be raised. + tx-fifo-watermark: + type: int + description: | + Use this property to specify the watermark value for the RX + FIFO. This value needs to be in FIFO words (NOT BYTES). This + value needs to be in the following interval: (0, DEFAULT_FIFO_DEPTH], + otherwise a BUILD_ASSERT() failure will be raised. + interrupts: + required: true + fifo-depth: + type: int + description: | + Use this property to set the FIFO depth that will be reported + to other applications calling dai_get_properties(). This value + should be in the following interval: (0, DEFAULT_FIFO_DEPTH], + otherwise a BUILD_ASSERT() failure will be raised. + By DEFAULT_FIFO_DEPTH we mean the actual (hardware) value of + the FIFO depth. This is needed because some applications (e.g: SOF) + use this value to compute the DMA burst size, in which case + DEFAULT_FIFO_DEPTH cannot be used. Generally, reporting a false + FIFO depth should be avoided. Please note that the sanity check + for tx/rx-fifo-watermark uses DEFAULT_FIFO_DEPTH instead of this + value so use with caution. If unsure, it's better to simply not + use this property, in which case the reported value will be + DEFAULT_FIFO_DEPTH. + dai-index: + type: int + description: | + Use this property to specify the index of the DAI. At the + moment, this is only used by SOF to fetch the "struct device" + associated with the DAI whose index Linux passes to SOF + through an IPC. If this property is not specified, the DAI + index will be considered 0. From 52deadd420d671f71e778f67f5e9809ebe8778f0 Mon Sep 17 00:00:00 2001 From: Laurentiu Mihalcea Date: Tue, 3 Oct 2023 14:17:57 +0300 Subject: [PATCH 1475/3723] clock_control: imx_ccm: Add support for i.MX93's SAI clocks This commit introduces support for querying i.MX93's SAI clocks. Signed-off-by: Laurentiu Mihalcea --- .../clock_control_mcux_ccm_rev2.c | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) diff --git a/drivers/clock_control/clock_control_mcux_ccm_rev2.c b/drivers/clock_control/clock_control_mcux_ccm_rev2.c index f7ef8b80b59..8edb33e3798 100644 --- a/drivers/clock_control/clock_control_mcux_ccm_rev2.c +++ b/drivers/clock_control/clock_control_mcux_ccm_rev2.c @@ -115,6 +115,24 @@ static int mcux_ccm_get_subsys_rate(const struct device *dev, break; #endif +#if defined(CONFIG_SOC_MIMX93_A55) && defined(CONFIG_DAI_NXP_SAI) + case IMX_CCM_SAI1_CLK: + case IMX_CCM_SAI2_CLK: + case IMX_CCM_SAI3_CLK: + clock_root = kCLOCK_Root_Sai1 + instance; + uint32_t mux = CLOCK_GetRootClockMux(clock_root); + uint32_t divider = CLOCK_GetRootClockDiv(clock_root); + + /* assumption: SAI's SRC is AUDIO_PLL */ + if (mux != 1) { + return -EINVAL; + } + + /* assumption: AUDIO_PLL's frequency is 393216000 Hz */ + *rate = 393216000 / divider; + + return 0; +#endif default: return -EINVAL; } From e23ae3b678f70f2dcc53846a403f3ea6b6d5ae39 Mon Sep 17 00:00:00 2001 From: Ren Chen Date: Tue, 3 Oct 2023 15:21:29 +0800 Subject: [PATCH 1476/3723] drivers: usb: usb_dc_it82xx2: refactor usb driver with macros Refactor the code using macros to enhance readability. Signed-off-by: Ren Chen --- drivers/usb/device/usb_dc_it82xx2.c | 148 ++++++++------------- soc/riscv/riscv-ite/common/chip_chipregs.h | 3 +- 2 files changed, 54 insertions(+), 97 deletions(-) diff --git a/drivers/usb/device/usb_dc_it82xx2.c b/drivers/usb/device/usb_dc_it82xx2.c index b5307252325..758591ce007 100644 --- a/drivers/usb/device/usb_dc_it82xx2.c +++ b/drivers/usb/device/usb_dc_it82xx2.c @@ -20,11 +20,12 @@ #include LOG_MODULE_REGISTER(usb_dc_it82xx2, CONFIG_USB_DRIVER_LOG_LEVEL); +#define IT8XXX2_IS_EXTEND_ENDPOINT(n) (USB_EP_GET_IDX(n) >= 4) + /* USB Device Controller Registers Bits & Constants */ #define IT8XXX2_USB_IRQ DT_INST_IRQ_BY_IDX(0, 0, irq) #define IT8XXX2_WU90_IRQ DT_INST_IRQ_BY_IDX(0, 1, irq) -#define MAX_NUM_ENDPOINTS 16 #define FIFO_NUM 3 #define SETUP_DATA_CNT 8 #define DC_ADDR_NULL 0x00 @@ -45,10 +46,6 @@ LOG_MODULE_REGISTER(usb_dc_it82xx2, CONFIG_USB_DRIVER_LOG_LEVEL); #define READY_BITS 0x0F #define COMPLETED_TRANS 0xF0 -/* EP Definitions */ -#define EP_VALID_MASK 0x0F -#define EP_INVALID_MASK ~(USB_EP_DIR_MASK | EP_VALID_MASK) - /* Bit [1:0] represents the TRANSACTION_TYPE as follows: */ enum it82xx2_transaction_types { DC_SETUP_TRANS, @@ -102,7 +99,7 @@ enum it82xx2_transaction_types { #define EP_DIRECTION BIT(5) enum it82xx2_ep_status { - EP_INIT, + EP_INIT = 0, EP_CHECK, EP_CONFIG, EP_CONFIG_IN, @@ -433,7 +430,7 @@ static int it82xx2_usb_extend_ep_ctrl(uint8_t ep_idx, uint8_t reg_idx, mask; bool flag; - if (ep_idx < EP4) { + if (!IT8XXX2_IS_EXTEND_ENDPOINT(ep_idx)) { return -EINVAL; } @@ -554,7 +551,7 @@ static int it82xx2_setup_done(uint8_t ep_ctrl, uint8_t idx) udata0.last_token = udata0.now_token; udata0.now_token = IN_TOKEN; udata0.st_state = STATUS_ST; - udata0.ep_data[idx].cb_in(idx | 0x80, USB_DC_EP_DATA_IN); + udata0.ep_data[idx].cb_in(idx | USB_EP_DIR_IN, USB_DC_EP_DATA_IN); } udata0.last_token = udata0.now_token; @@ -620,7 +617,7 @@ static int it82xx2_in_done(uint8_t ep_ctrl, uint8_t idx) } else { ep_regs[idx].ep_ctrl |= EP_OUTDATA_SEQ; } - udata0.ep_data[idx].cb_in(idx | 0x80, USB_DC_EP_DATA_IN); + udata0.ep_data[idx].cb_in(idx | USB_EP_DIR_IN, USB_DC_EP_DATA_IN); /* set ready bit for status out */ LOG_DBG("Remaining Bytes: %d, Stage: %d", @@ -693,7 +690,7 @@ static void it82xx2_ep_in_out_config(uint8_t idx) uint8_t ep_trans = (epn_ext_ctrl[idx].epn_ext_ctrl2 >> 4) & READY_BITS; if (udata0.ep_data[ep_trans].ep_status == EP_CONFIG_IN) { - if (ep_trans < 4) { + if (!IT8XXX2_IS_EXTEND_ENDPOINT(ep_trans)) { if (!!(ep_regs[idx].ep_ctrl & EP_OUTDATA_SEQ)) { ep_regs[idx].ep_ctrl &= ~EP_OUTDATA_SEQ; } else { @@ -705,7 +702,7 @@ static void it82xx2_ep_in_out_config(uint8_t idx) } if (udata0.ep_data[ep_trans].cb_in) { - udata0.ep_data[ep_trans].cb_in(ep_trans | 0x80, + udata0.ep_data[ep_trans].cb_in(ep_trans | USB_EP_DIR_IN, USB_DC_EP_DATA_IN); } @@ -729,7 +726,7 @@ static void it82xx2_usb_dc_trans_done(void) int ret; - for (uint8_t idx = 0 ; idx < EP4 ; idx++) { + for (uint8_t idx = 0; idx < 4; idx++) { uint8_t ep_ctrl = ep_regs[idx].ep_ctrl; /* check ready bit ,will be 0 when trans done */ @@ -934,14 +931,12 @@ int usb_dc_reset(void) struct it82xx2_usb_ep_regs *ep_regs = usb_regs->usb_ep_regs; struct it82xx2_usb_ep_fifo_regs *ff_regs = usb_regs->fifo_regs; - int idx; - LOG_DBG("USB Device Reset"); ff_regs[EP0].ep_rx_fifo_ctrl = FIFO_FORCE_EMPTY; ff_regs[EP0].ep_tx_fifo_ctrl = FIFO_FORCE_EMPTY; - for (idx = 1 ; idx < EP4 ; idx++) { + for (uint8_t idx = 1; idx < 4; idx++) { if (udata0.ep_data[idx].ep_status > EP_CHECK) { ff_regs[idx].ep_rx_fifo_ctrl = FIFO_FORCE_EMPTY; ff_regs[idx].ep_tx_fifo_ctrl = FIFO_FORCE_EMPTY; @@ -974,12 +969,8 @@ void usb_dc_set_status_callback(const usb_dc_status_callback cb) int usb_dc_ep_check_cap(const struct usb_dc_ep_cfg_data * const cfg) { - uint8_t ep_idx = cfg->ep_addr & EP_VALID_MASK; - bool in = !!((cfg->ep_addr) & USB_EP_DIR_MASK); - - if ((cfg->ep_addr & EP_INVALID_MASK) != 0) { - return -EINVAL; - } + uint8_t ep_idx = USB_EP_GET_IDX(cfg->ep_addr); + bool in = USB_EP_DIR_IS_IN(cfg->ep_addr); if ((cfg->ep_type == USB_DC_EP_CONTROL) && ep_idx > EP0) { LOG_ERR("Invalid Endpoint Configuration"); @@ -1001,7 +992,7 @@ int usb_dc_ep_check_cap(const struct usb_dc_ep_cfg_data * const cfg) return -EINVAL; } - if (udata0.ep_data[ep_idx].ep_status > 0) { + if (udata0.ep_data[ep_idx].ep_status > EP_INIT) { LOG_WRN("EP%d have been used", ep_idx); return -EINVAL; } @@ -1024,15 +1015,10 @@ int usb_dc_ep_configure(const struct usb_dc_ep_cfg_data *const cfg) volatile uint8_t *ep_fifo_ctrl = usb_regs->fifo_regs[EP_EXT_REGS_BX].fifo_ctrl.ep_fifo_ctrl; - uint8_t ep_idx = (cfg->ep_addr) & EP_VALID_MASK; + uint8_t ep_idx = USB_EP_GET_IDX(cfg->ep_addr); uint8_t reg_idx = it82xx2_get_ep_fifo_ctrl_reg_idx(ep_idx); uint8_t reg_val = it82xx2_get_ep_fifo_ctrl_reg_val(ep_idx); - bool in = !!((cfg->ep_addr) & USB_EP_DIR_MASK); - - if ((cfg->ep_addr & EP_INVALID_MASK) != 0) { - LOG_DBG("Invalid Address"); - return -EINVAL; - } + bool in = USB_EP_DIR_IS_IN(cfg->ep_addr); if (!udata0.attached || ep_idx >= MAX_NUM_ENDPOINTS) { LOG_DBG("Not attached / Invalid Endpoint: 0x%X", cfg->ep_addr); @@ -1054,7 +1040,7 @@ int usb_dc_ep_configure(const struct usb_dc_ep_cfg_data *const cfg) return 0; } - if (ep_idx < EP4) { + if (!IT8XXX2_IS_EXTEND_ENDPOINT(ep_idx)) { (in) ? (ep_regs[ep_idx].ep_ctrl |= EP_DIRECTION) : (ep_regs[ep_idx].ep_ctrl &= ~EP_DIRECTION); @@ -1081,7 +1067,7 @@ int usb_dc_ep_configure(const struct usb_dc_ep_cfg_data *const cfg) return -EINVAL; case USB_DC_EP_ISOCHRONOUS: - if (ep_idx < EP4) { + if (!IT8XXX2_IS_EXTEND_ENDPOINT(ep_idx)) { ep_regs[ep_idx].ep_ctrl |= EP_ISO_ENABLE; } else { it82xx2_usb_extend_ep_ctrl(ep_idx, EXT_EP_ISO_ENABLE); @@ -1092,7 +1078,7 @@ int usb_dc_ep_configure(const struct usb_dc_ep_cfg_data *const cfg) case USB_DC_EP_BULK: case USB_DC_EP_INTERRUPT: default: - if (ep_idx < EP4) { + if (!IT8XXX2_IS_EXTEND_ENDPOINT(ep_idx)) { ep_regs[ep_idx].ep_ctrl &= ~EP_ISO_ENABLE; } else { it82xx2_usb_extend_ep_ctrl(ep_idx, EXT_EP_ISO_DISABLE); @@ -1110,11 +1096,7 @@ int usb_dc_ep_configure(const struct usb_dc_ep_cfg_data *const cfg) int usb_dc_ep_set_callback(const uint8_t ep, const usb_dc_ep_callback cb) { - uint8_t ep_idx = ep & EP_VALID_MASK; - - if ((ep & EP_INVALID_MASK) != 0) { - return -EINVAL; - } + uint8_t ep_idx = USB_EP_GET_IDX(ep); if (!udata0.attached || ep_idx >= MAX_NUM_ENDPOINTS) { LOG_ERR("(%d)Not attached / Invalid endpoint: EP 0x%x", @@ -1129,9 +1111,11 @@ int usb_dc_ep_set_callback(const uint8_t ep, const usb_dc_ep_callback cb) LOG_DBG("EP%d set callback: %d", ep_idx, !!(ep & USB_EP_DIR_IN)); - (ep & USB_EP_DIR_IN) ? - (udata0.ep_data[ep_idx].cb_in = cb) : - (udata0.ep_data[ep_idx].cb_out = cb); + if (USB_EP_DIR_IS_IN(ep)) { + udata0.ep_data[ep_idx].cb_in = cb; + } else { + udata0.ep_data[ep_idx].cb_out = cb; + } return 0; } @@ -1142,19 +1126,14 @@ int usb_dc_ep_enable(const uint8_t ep) (struct usb_it82xx2_regs *)it82xx2_get_usb_regs(); struct it82xx2_usb_ep_regs *ep_regs = usb_regs->usb_ep_regs; - uint8_t ep_idx = ep & EP_VALID_MASK; - - if ((ep & EP_INVALID_MASK) != 0) { - LOG_DBG("Bit[6:4] has something invalid"); - return -EINVAL; - } + uint8_t ep_idx = USB_EP_GET_IDX(ep); if (!udata0.attached || ep_idx >= MAX_NUM_ENDPOINTS) { LOG_ERR("Not attached / Invalid endpoint: EP 0x%x", ep_idx); return -EINVAL; } - if (ep_idx < EP4) { + if (!IT8XXX2_IS_EXTEND_ENDPOINT(ep_idx)) { LOG_DBG("ep_idx < 4"); ep_regs[ep_idx].ep_ctrl |= ENDPOINT_EN; LOG_DBG("EP%d Enabled %02x", ep_idx, ep_regs[ep_idx].ep_ctrl); @@ -1172,18 +1151,14 @@ int usb_dc_ep_disable(uint8_t ep) (struct usb_it82xx2_regs *)it82xx2_get_usb_regs(); struct it82xx2_usb_ep_regs *ep_regs = usb_regs->usb_ep_regs; - uint8_t ep_idx = ep & EP_VALID_MASK; - - if ((ep & EP_INVALID_MASK) != 0) { - return -EINVAL; - } + uint8_t ep_idx = USB_EP_GET_IDX(ep); if (!udata0.attached || ep_idx >= MAX_NUM_ENDPOINTS) { LOG_ERR("Not attached / Invalid endpoint: EP 0x%x", ep_idx); return -EINVAL; } - if (ep_idx < EP4) { + if (!IT8XXX2_IS_EXTEND_ENDPOINT(ep_idx)) { ep_regs[ep_idx].ep_ctrl &= ~ENDPOINT_EN; } else { it82xx2_usb_extend_ep_ctrl(ep_idx, EXT_EP_DISABLE); @@ -1199,14 +1174,14 @@ int usb_dc_ep_set_stall(const uint8_t ep) (struct usb_it82xx2_regs *)it82xx2_get_usb_regs(); struct it82xx2_usb_ep_regs *ep_regs = usb_regs->usb_ep_regs; - uint8_t ep_idx = ep & EP_VALID_MASK; + uint8_t ep_idx = USB_EP_GET_IDX(ep); struct gctrl_it8xxx2_regs *const gctrl_regs = GCTRL_IT8XXX2_REGS_BASE; - if (((ep & EP_INVALID_MASK) != 0) || (ep_idx >= MAX_NUM_ENDPOINTS)) { + if (ep_idx >= MAX_NUM_ENDPOINTS) { return -EINVAL; } - if (ep_idx < EP4) { + if (!IT8XXX2_IS_EXTEND_ENDPOINT(ep_idx)) { ep_regs[ep_idx].ep_ctrl |= EP_SEND_STALL; } else { it82xx2_usb_extend_ep_ctrl(ep_idx, EXT_EP_SEND_STALL); @@ -1243,11 +1218,7 @@ int usb_dc_ep_clear_stall(const uint8_t ep) (struct usb_it82xx2_regs *)it82xx2_get_usb_regs(); struct it82xx2_usb_ep_regs *ep_regs = usb_regs->usb_ep_regs; - uint8_t ep_idx = ep & EP_VALID_MASK; - - if ((ep & EP_INVALID_MASK) != 0) { - return -EINVAL; - } + uint8_t ep_idx = USB_EP_GET_IDX(ep); if (ep_idx >= MAX_NUM_ENDPOINTS) { return -EINVAL; @@ -1265,14 +1236,13 @@ int usb_dc_ep_is_stalled(const uint8_t ep, uint8_t *stalled) (struct usb_it82xx2_regs *)it82xx2_get_usb_regs(); struct it82xx2_usb_ep_regs *ep_regs = usb_regs->usb_ep_regs; - uint8_t ep_idx = ep & EP_VALID_MASK; + uint8_t ep_idx = USB_EP_GET_IDX(ep); - if ((!stalled) || ((ep & EP_INVALID_MASK) != 0) || - (ep_idx >= MAX_NUM_ENDPOINTS)) { + if ((!stalled) || (ep_idx >= MAX_NUM_ENDPOINTS)) { return -EINVAL; } - if (ep_idx < EP4) { + if (!IT8XXX2_IS_EXTEND_ENDPOINT(ep_idx)) { *stalled = (0 != (ep_regs[ep_idx].ep_ctrl & EP_SEND_STALL)); } else { @@ -1294,10 +1264,9 @@ int usb_dc_ep_flush(uint8_t ep) (struct usb_it82xx2_regs *)it82xx2_get_usb_regs(); struct it82xx2_usb_ep_fifo_regs *ff_regs = usb_regs->fifo_regs; - uint8_t ep_idx = ep & EP_VALID_MASK; - bool in = !!(ep & USB_EP_DIR_MASK); + uint8_t ep_idx = USB_EP_GET_IDX(ep); - if (((ep & EP_INVALID_MASK) != 0) || (ep_idx >= MAX_NUM_ENDPOINTS)) { + if (ep_idx >= MAX_NUM_ENDPOINTS) { return -EINVAL; } @@ -1305,8 +1274,11 @@ int usb_dc_ep_flush(uint8_t ep) ep_idx = ep_fifo_res[ep_idx % FIFO_NUM]; } - in ? (ff_regs[ep_idx].ep_tx_fifo_ctrl = FIFO_FORCE_EMPTY) : - (ff_regs[ep_idx].ep_rx_fifo_ctrl = FIFO_FORCE_EMPTY); + if (USB_EP_DIR_IS_IN(ep)) { + ff_regs[ep_idx].ep_tx_fifo_ctrl = FIFO_FORCE_EMPTY; + } else { + ff_regs[ep_idx].ep_rx_fifo_ctrl = FIFO_FORCE_EMPTY; + } return 0; } @@ -1321,16 +1293,13 @@ int usb_dc_ep_write(uint8_t ep, const uint8_t *buf, volatile uint8_t *ep_fifo_ctrl = usb_regs->fifo_regs[EP_EXT_REGS_BX].fifo_ctrl.ep_fifo_ctrl; - uint8_t ep_idx = ep & EP_VALID_MASK; + uint8_t ep_idx = USB_EP_GET_IDX(ep); uint8_t reg_idx = it82xx2_get_ep_fifo_ctrl_reg_idx(ep_idx); uint8_t reg_val = it82xx2_get_ep_fifo_ctrl_reg_val(ep_idx); uint8_t ep_fifo = (ep_idx > EP0) ? (ep_fifo_res[ep_idx % FIFO_NUM]) : 0; uint32_t idx; - if ((ep & EP_INVALID_MASK) != 0) - return -EINVAL; - /* status IN */ if ((ep_idx == EP0) && (data_len == 0) && (udata0.now_token == SETUP_TOKEN)) { @@ -1381,7 +1350,7 @@ int usb_dc_ep_write(uint8_t ep, const uint8_t *buf, LOG_DBG("Write %d Packets to TX FIFO(%d)", data_len, ep_idx); } - if (ep_idx > FIFO_NUM) { + if (IT8XXX2_IS_EXTEND_ENDPOINT(ep_idx)) { it82xx2_usb_extend_ep_ctrl(ep_idx, EXT_EP_READY); } @@ -1405,11 +1374,11 @@ int usb_dc_ep_read(uint8_t ep, uint8_t *buf, uint32_t max_data_len, struct it82xx2_usb_ep_regs *ep_regs = usb_regs->usb_ep_regs; struct it82xx2_usb_ep_fifo_regs *ff_regs = usb_regs->fifo_regs; - uint8_t ep_idx = ep & EP_VALID_MASK; + uint8_t ep_idx = USB_EP_GET_IDX(ep); uint8_t ep_fifo = 0; uint16_t rx_fifo_len; - if ((ep & EP_INVALID_MASK) != 0) { + if (ep_idx >= MAX_NUM_ENDPOINTS) { return -EINVAL; } @@ -1539,20 +1508,16 @@ int usb_dc_ep_read_wait(uint8_t ep, uint8_t *buf, uint32_t max_data_len, struct it82xx2_usb_ep_regs *ep_regs = usb_regs->usb_ep_regs; struct it82xx2_usb_ep_fifo_regs *ff_regs = usb_regs->fifo_regs; - uint8_t ep_idx = ep & EP_VALID_MASK; + uint8_t ep_idx = USB_EP_GET_IDX(ep); uint8_t ep_fifo = 0; uint16_t rx_fifo_len; - if ((ep & EP_INVALID_MASK) != 0) { - return -EINVAL; - } - if (ep_idx >= MAX_NUM_ENDPOINTS) { LOG_ERR("(%d): Wrong Endpoint Index/Address", __LINE__); return -EINVAL; } - /* Check if OUT ep */ - if (!!(ep & USB_EP_DIR_MASK)) { + + if (USB_EP_DIR_IS_IN(ep)) { LOG_ERR("Wrong Endpoint Direction"); return -EINVAL; } @@ -1592,20 +1557,15 @@ int usb_dc_ep_read_continue(uint8_t ep) (struct usb_it82xx2_regs *)it82xx2_get_usb_regs(); struct it82xx2_usb_ep_regs *ep_regs = usb_regs->usb_ep_regs; - uint8_t ep_idx = ep & EP_VALID_MASK; + uint8_t ep_idx = USB_EP_GET_IDX(ep); uint8_t ep_fifo = 2; - if ((ep & EP_INVALID_MASK) != 0) { - return -EINVAL; - } - if (ep_idx >= MAX_NUM_ENDPOINTS) { LOG_ERR("(%d): Wrong Endpoint Index/Address", __LINE__); return -EINVAL; } - /* Check if OUT ep */ - if (!!(ep & USB_EP_DIR_MASK)) { + if (USB_EP_DIR_IS_IN(ep)) { LOG_ERR("Wrong Endpoint Direction"); return -EINVAL; } @@ -1624,11 +1584,7 @@ int usb_dc_ep_read_continue(uint8_t ep) int usb_dc_ep_mps(const uint8_t ep) { - uint8_t ep_idx = ep & EP_VALID_MASK; - - if ((ep & EP_INVALID_MASK) != 0) { - return -EINVAL; - } + uint8_t ep_idx = USB_EP_GET_IDX(ep); if (ep_idx >= MAX_NUM_ENDPOINTS) { LOG_ERR("(%d): Wrong Endpoint Index/Address", __LINE__); diff --git a/soc/riscv/riscv-ite/common/chip_chipregs.h b/soc/riscv/riscv-ite/common/chip_chipregs.h index b1009e3eee5..c0ea599568f 100644 --- a/soc/riscv/riscv-ite/common/chip_chipregs.h +++ b/soc/riscv/riscv-ite/common/chip_chipregs.h @@ -477,7 +477,8 @@ enum usb_dc_endpoints { EP12, EP13, EP14, - EP15 + EP15, + MAX_NUM_ENDPOINTS }; struct it82xx2_usb_ep_regs { From 13788d46496c5a60ee645e232537d2769282f96f Mon Sep 17 00:00:00 2001 From: Ren Chen Date: Tue, 3 Oct 2023 17:00:35 +0800 Subject: [PATCH 1477/3723] drivers: usb: usb_dc_it82xx2: correct the FIFO control There are two registers that control the selection of one FIFO as data buffer for 15 endpoints (ep1-ep15). Both registers should be configured before sending and receiving data. Additionally, there was an issue with the corresponding FIFO index setting in the 'usb_dc_ep_read_continue' function, which has been addressed in this commit. Signed-off-by: Ren Chen --- drivers/usb/device/usb_dc_it82xx2.c | 128 +++++++++++----------------- 1 file changed, 52 insertions(+), 76 deletions(-) diff --git a/drivers/usb/device/usb_dc_it82xx2.c b/drivers/usb/device/usb_dc_it82xx2.c index 758591ce007..298f3340cb8 100644 --- a/drivers/usb/device/usb_dc_it82xx2.c +++ b/drivers/usb/device/usb_dc_it82xx2.c @@ -43,7 +43,6 @@ LOG_MODULE_REGISTER(usb_dc_it82xx2, CONFIG_USB_DRIVER_LOG_LEVEL); #define RX_LINE_RESET 0x00 /* EPN Extend Control 2 Register Mask Definition */ -#define READY_BITS 0x0F #define COMPLETED_TRANS 0xF0 /* Bit [1:0] represents the TRANSACTION_TYPE as follows: */ @@ -302,35 +301,40 @@ static void it8xxx2_usb_dc_wuc_init(const struct device *dev) IRQ_CONNECT(IT8XXX2_WU90_IRQ, 0, it82xx2_wu90_isr, 0, 0); } -/* Function it82xx2_get_ep_fifo_ctrl_reg_idx(uint8_t ep_idx): - * - * Calculate the register offset index which determines the corresponding - * EP FIFO Ctrl Registers which is defined as ep_fifo_ctrl[reg_idx] here - * - * The ep_fifo_res[ep_idx % FIFO_NUM] represents the EP mapping because when - * (ep_idx % FIFO_NUM) is 3, it actually means the EP0. - */ -static uint8_t it82xx2_get_ep_fifo_ctrl_reg_idx(uint8_t ep_idx) +static int it82xx2_usb_fifo_ctrl(uint8_t ep) { + struct usb_it82xx2_regs *const usb_regs = (struct usb_it82xx2_regs *)it82xx2_get_usb_regs(); + volatile uint8_t *ep_fifo_ctrl = usb_regs->fifo_regs[EP_EXT_REGS_BX].fifo_ctrl.ep_fifo_ctrl; + uint8_t ep_idx = USB_EP_GET_IDX(ep); + uint8_t fifon_ctrl = (ep_fifo_res[ep_idx % FIFO_NUM] - 1) * 2; + int ret = 0; - uint8_t reg_idx = (ep_idx < EP8) ? - ((ep_fifo_res[ep_idx % FIFO_NUM] - 1) * 2) : - ((ep_fifo_res[ep_idx % FIFO_NUM] - 1) * 2 + 1); - - return reg_idx; -} + if (ep_idx == 0) { + LOG_ERR("Invalid endpoint 0x%x", ep); + return -EINVAL; + } -/* Function it82xx2_get_ep_fifo_ctrl_reg_val(uint8_t ep_idx): - * - * Calculate the register value written to the ep_fifo_ctrl which is defined as - * ep_fifo_ctrl[reg_idx] here for selecting the corresponding control bit. - */ -static uint8_t it82xx2_get_ep_fifo_ctrl_reg_val(uint8_t ep_idx) -{ - uint8_t reg_val = (ep_idx < EP8) ? - (1 << ep_idx) : (1 << (ep_idx - EP8)); + if (USB_EP_DIR_IS_IN(ep) && udata0.ep_data[ep_idx].ep_status == EP_CONFIG_IN) { + if (ep_idx < 8) { + ep_fifo_ctrl[fifon_ctrl] = BIT(ep_idx); + ep_fifo_ctrl[fifon_ctrl + 1] = 0x0; + } else { + ep_fifo_ctrl[fifon_ctrl] = 0x0; + ep_fifo_ctrl[fifon_ctrl + 1] = BIT(ep_idx - 8); + } + } else if (USB_EP_DIR_IS_OUT(ep) && + udata0.ep_data[ep_idx].ep_status == EP_CONFIG_OUT) { + if (ep_idx < 8) { + ep_fifo_ctrl[fifon_ctrl] |= BIT(ep_idx); + } else { + ep_fifo_ctrl[fifon_ctrl + 1] |= BIT(ep_idx - 8); + } + } else { + LOG_ERR("Failed to set fifo control register for ep 0x%x", ep); + ret = -EINVAL; + } - return reg_val; + return ret; } /* @@ -687,31 +691,28 @@ static void it82xx2_ep_in_out_config(uint8_t idx) struct epn_ext_ctrl_regs *epn_ext_ctrl = usb_regs->fifo_regs[EP_EXT_REGS_DX].ext_0_3.epn_ext_ctrl; - uint8_t ep_trans = (epn_ext_ctrl[idx].epn_ext_ctrl2 >> 4) & READY_BITS; + uint8_t ep_idx = (epn_ext_ctrl[idx].epn_ext_ctrl2 & COMPLETED_TRANS) >> 4; - if (udata0.ep_data[ep_trans].ep_status == EP_CONFIG_IN) { - if (!IT8XXX2_IS_EXTEND_ENDPOINT(ep_trans)) { + if (udata0.ep_data[ep_idx].ep_status == EP_CONFIG_IN) { + if (!IT8XXX2_IS_EXTEND_ENDPOINT(ep_idx)) { if (!!(ep_regs[idx].ep_ctrl & EP_OUTDATA_SEQ)) { ep_regs[idx].ep_ctrl &= ~EP_OUTDATA_SEQ; } else { ep_regs[idx].ep_ctrl |= EP_OUTDATA_SEQ; } } else { - it82xx2_usb_extend_ep_ctrl(ep_trans, - EXT_EP_DATA_SEQ_INV); + it82xx2_usb_extend_ep_ctrl(ep_idx, EXT_EP_DATA_SEQ_INV); } - if (udata0.ep_data[ep_trans].cb_in) { - udata0.ep_data[ep_trans].cb_in(ep_trans | USB_EP_DIR_IN, - USB_DC_EP_DATA_IN); + if (udata0.ep_data[ep_idx].cb_in) { + udata0.ep_data[ep_idx].cb_in(ep_idx | USB_EP_DIR_IN, USB_DC_EP_DATA_IN); } k_sem_give(&udata0.ep_sem[idx - 1]); } else { - if (udata0.ep_data[ep_trans].cb_out) { - udata0.ep_data[ep_trans].cb_out(ep_trans, - USB_DC_EP_DATA_OUT); + if (udata0.ep_data[ep_idx].cb_out) { + udata0.ep_data[ep_idx].cb_out(ep_idx, USB_DC_EP_DATA_OUT); } } } @@ -1012,12 +1013,8 @@ int usb_dc_ep_configure(const struct usb_dc_ep_cfg_data *const cfg) struct usb_it82xx2_regs *const usb_regs = (struct usb_it82xx2_regs *)it82xx2_get_usb_regs(); struct it82xx2_usb_ep_regs *ep_regs = usb_regs->usb_ep_regs; - volatile uint8_t *ep_fifo_ctrl = - usb_regs->fifo_regs[EP_EXT_REGS_BX].fifo_ctrl.ep_fifo_ctrl; uint8_t ep_idx = USB_EP_GET_IDX(cfg->ep_addr); - uint8_t reg_idx = it82xx2_get_ep_fifo_ctrl_reg_idx(ep_idx); - uint8_t reg_val = it82xx2_get_ep_fifo_ctrl_reg_val(ep_idx); bool in = USB_EP_DIR_IS_IN(cfg->ep_addr); if (!udata0.attached || ep_idx >= MAX_NUM_ENDPOINTS) { @@ -1059,7 +1056,9 @@ int usb_dc_ep_configure(const struct usb_dc_ep_cfg_data *const cfg) (in) ? (udata0.ep_data[ep_idx].ep_status = EP_CONFIG_IN) : (udata0.ep_data[ep_idx].ep_status = EP_CONFIG_OUT); - ep_fifo_ctrl[reg_idx] |= reg_val; + if (!in) { + it82xx2_usb_fifo_ctrl(cfg->ep_addr); + } switch (cfg->ep_type) { @@ -1265,19 +1264,16 @@ int usb_dc_ep_flush(uint8_t ep) struct it82xx2_usb_ep_fifo_regs *ff_regs = usb_regs->fifo_regs; uint8_t ep_idx = USB_EP_GET_IDX(ep); + uint8_t ep_fifo = (ep_idx > 0) ? (ep_fifo_res[ep_idx % FIFO_NUM]) : 0; if (ep_idx >= MAX_NUM_ENDPOINTS) { return -EINVAL; } - if (ep_idx > FIFO_NUM) { - ep_idx = ep_fifo_res[ep_idx % FIFO_NUM]; - } - if (USB_EP_DIR_IS_IN(ep)) { - ff_regs[ep_idx].ep_tx_fifo_ctrl = FIFO_FORCE_EMPTY; + ff_regs[ep_fifo].ep_tx_fifo_ctrl = FIFO_FORCE_EMPTY; } else { - ff_regs[ep_idx].ep_rx_fifo_ctrl = FIFO_FORCE_EMPTY; + ff_regs[ep_fifo].ep_rx_fifo_ctrl = FIFO_FORCE_EMPTY; } return 0; @@ -1290,14 +1286,9 @@ int usb_dc_ep_write(uint8_t ep, const uint8_t *buf, (struct usb_it82xx2_regs *)it82xx2_get_usb_regs(); struct it82xx2_usb_ep_regs *ep_regs = usb_regs->usb_ep_regs; struct it82xx2_usb_ep_fifo_regs *ff_regs = usb_regs->fifo_regs; - volatile uint8_t *ep_fifo_ctrl = - usb_regs->fifo_regs[EP_EXT_REGS_BX].fifo_ctrl.ep_fifo_ctrl; uint8_t ep_idx = USB_EP_GET_IDX(ep); - uint8_t reg_idx = it82xx2_get_ep_fifo_ctrl_reg_idx(ep_idx); - uint8_t reg_val = it82xx2_get_ep_fifo_ctrl_reg_val(ep_idx); - uint8_t ep_fifo = (ep_idx > EP0) ? - (ep_fifo_res[ep_idx % FIFO_NUM]) : 0; + uint8_t ep_fifo = (ep_idx > 0) ? (ep_fifo_res[ep_idx % FIFO_NUM]) : 0; uint32_t idx; /* status IN */ @@ -1321,11 +1312,8 @@ int usb_dc_ep_write(uint8_t ep, const uint8_t *buf, /* select FIFO */ if (ep_idx > EP0) { - k_sem_take(&udata0.ep_sem[ep_fifo-1], K_FOREVER); - - /* select FIFO */ - ep_fifo_ctrl[reg_idx] |= reg_val; + it82xx2_usb_fifo_ctrl(ep); } if (data_len > udata0.ep_data[ep_idx].mps) { @@ -1375,15 +1363,15 @@ int usb_dc_ep_read(uint8_t ep, uint8_t *buf, uint32_t max_data_len, struct it82xx2_usb_ep_fifo_regs *ff_regs = usb_regs->fifo_regs; uint8_t ep_idx = USB_EP_GET_IDX(ep); - uint8_t ep_fifo = 0; + uint8_t ep_fifo = (ep_idx > 0) ? (ep_fifo_res[ep_idx % FIFO_NUM]) : 0; uint16_t rx_fifo_len; if (ep_idx >= MAX_NUM_ENDPOINTS) { return -EINVAL; } - if (ep_regs[ep_idx].ep_status & EP_STATUS_ERROR) { - LOG_WRN("EP Error Flag: 0x%02x", ep_regs[ep_idx].ep_status); + if (ep_regs[ep_fifo].ep_status & EP_STATUS_ERROR) { + LOG_WRN("fifo_%d error status: 0x%02x", ep_fifo, ep_regs[ep_fifo].ep_status); } if (max_data_len == 0) { @@ -1398,10 +1386,6 @@ int usb_dc_ep_read(uint8_t ep, uint8_t *buf, uint32_t max_data_len, return 0; } - if (ep_idx > EP0) { - ep_fifo = ep_fifo_res[ep_idx % FIFO_NUM]; - } - rx_fifo_len = (uint16_t)ff_regs[ep_fifo].ep_rx_fifo_dcnt_lsb + (((uint16_t)ff_regs[ep_fifo].ep_rx_fifo_dcnt_msb) << 8); @@ -1509,7 +1493,7 @@ int usb_dc_ep_read_wait(uint8_t ep, uint8_t *buf, uint32_t max_data_len, struct it82xx2_usb_ep_fifo_regs *ff_regs = usb_regs->fifo_regs; uint8_t ep_idx = USB_EP_GET_IDX(ep); - uint8_t ep_fifo = 0; + uint8_t ep_fifo = (ep_idx > 0) ? (ep_fifo_res[ep_idx % FIFO_NUM]) : 0; uint16_t rx_fifo_len; if (ep_idx >= MAX_NUM_ENDPOINTS) { @@ -1522,12 +1506,8 @@ int usb_dc_ep_read_wait(uint8_t ep, uint8_t *buf, uint32_t max_data_len, return -EINVAL; } - if (ep_idx > EP0) { - ep_fifo = ep_fifo_res[ep_idx % FIFO_NUM]; - } - if (ep_regs[ep_fifo].ep_status & EP_STATUS_ERROR) { - LOG_WRN("EP error flag(%02x)", ep_regs[ep_fifo].ep_status); + LOG_WRN("fifo_%d error status(%02x)", ep_fifo, ep_regs[ep_fifo].ep_status); } rx_fifo_len = (uint16_t)ff_regs[ep_fifo].ep_rx_fifo_dcnt_lsb + @@ -1558,7 +1538,7 @@ int usb_dc_ep_read_continue(uint8_t ep) struct it82xx2_usb_ep_regs *ep_regs = usb_regs->usb_ep_regs; uint8_t ep_idx = USB_EP_GET_IDX(ep); - uint8_t ep_fifo = 2; + uint8_t ep_fifo = (ep_idx > 0) ? (ep_fifo_res[ep_idx % FIFO_NUM]) : 0; if (ep_idx >= MAX_NUM_ENDPOINTS) { LOG_ERR("(%d): Wrong Endpoint Index/Address", __LINE__); @@ -1570,10 +1550,6 @@ int usb_dc_ep_read_continue(uint8_t ep) return -EINVAL; } - if (ep_idx > EP0) { - ep_fifo = ep_fifo_res[ep_idx % FIFO_NUM]; - } - it82xx2_usb_extend_ep_ctrl(ep_idx, EXT_EP_READY); ep_regs[ep_fifo].ep_ctrl |= ENDPOINT_RDY; udata0.ep_ready[ep_fifo - 1] = true; From 1c48b77ffa3a78583676928d3947730aa5c6170f Mon Sep 17 00:00:00 2001 From: Ren Chen Date: Wed, 4 Oct 2023 09:18:54 +0800 Subject: [PATCH 1478/3723] drivers: usb: usb_dc_it82xx2: remove unused code and debug msg This change remove unused code and debug messages. Signed-off-by: Ren Chen --- drivers/usb/device/usb_dc_it82xx2.c | 45 ++++++++--------------------- 1 file changed, 12 insertions(+), 33 deletions(-) diff --git a/drivers/usb/device/usb_dc_it82xx2.c b/drivers/usb/device/usb_dc_it82xx2.c index 298f3340cb8..9aaf5b6fb49 100644 --- a/drivers/usb/device/usb_dc_it82xx2.c +++ b/drivers/usb/device/usb_dc_it82xx2.c @@ -471,20 +471,18 @@ static int it82xx2_usb_extend_ep_ctrl(uint8_t ep_idx, return 0; } -static int it82xx2_usb_dc_ip_init(uint8_t p_action) +static int it82xx2_usb_dc_ip_init(void) { struct usb_it82xx2_regs *const usb_regs = (struct usb_it82xx2_regs *)it82xx2_get_usb_regs(); - if (p_action == 0) { - /* Reset Device Controller */ - usb_regs->host_device_control = RESET_CORE; - k_msleep(1); - usb_regs->port0_misc_control &= ~(PULL_DOWN_EN); - usb_regs->port1_misc_control &= ~(PULL_DOWN_EN); - /* clear reset bit */ - usb_regs->host_device_control = 0; - } + /* Reset Device Controller */ + usb_regs->host_device_control = RESET_CORE; + k_msleep(1); + usb_regs->port0_misc_control &= ~(PULL_DOWN_EN); + usb_regs->port1_misc_control &= ~(PULL_DOWN_EN); + /* clear reset bit */ + usb_regs->host_device_control = 0; usb_regs->dc_interrupt_status = DC_TRANS_DONE | DC_RESET_EVENT | DC_SOF_RECEIVED; @@ -508,7 +506,7 @@ static int it82xx2_usb_dc_attach_init(void) gctrl_regs->GCTRL_MCCR &= ~(IT8XXX2_GCTRL_MCCR_USB_EN); gctrl_regs->gctrl_pmer2 |= IT8XXX2_GCTRL_PMER2_USB_PAD_EN; - return it82xx2_usb_dc_ip_init(0); + return it82xx2_usb_dc_ip_init(); } /* Check the condition that SETUP_TOKEN following OUT_TOKEN and return it */ @@ -568,8 +566,6 @@ static int it82xx2_setup_done(uint8_t ep_ctrl, uint8_t idx) /* Set ready bit to no-data control in */ if (udata0.no_data_ctrl) { ep_regs[EP0].ep_ctrl |= ENDPOINT_RDY; - LOG_DBG("(%d): Set Ready Bit for no-data control", __LINE__); - udata0.no_data_ctrl = false; } @@ -629,7 +625,6 @@ static int it82xx2_in_done(uint8_t ep_ctrl, uint8_t idx) if (udata0.st_state == DIN_ST && udata0.ep_data[EP0].remaining == 0) { ep_regs[EP0].ep_ctrl |= ENDPOINT_RDY; - LOG_DBG("Set EP%d Ready (%d)", idx, __LINE__); } return 0; @@ -661,7 +656,7 @@ static int it82xx2_out_done(uint8_t idx) /* SETUP_TOKEN follow OUT_TOKEN */ if (it82xx2_check_setup_following_out()) { - LOG_WRN("[%s] OUT => SETUP", __func__); + LOG_DBG("[%s] OUT => SETUP", __func__); udata0.last_token = udata0.now_token; udata0.now_token = SETUP_TOKEN; udata0.st_state = SETUP_ST; @@ -671,7 +666,6 @@ static int it82xx2_out_done(uint8_t idx) /* NOTE: set ready bit to no-data control in */ if (udata0.no_data_ctrl) { ep_regs[EP0].ep_ctrl |= ENDPOINT_RDY; - LOG_DBG("Set Ready Bit for no-data control"); udata0.no_data_ctrl = false; } } @@ -790,13 +784,7 @@ static void it82xx2_usb_dc_isr(void) RX_LINE_RESET) { usb_dc_reset(); usb_regs->dc_interrupt_status = DC_RESET_EVENT; - - if (udata0.usb_status_cb) { - (*(udata0.usb_status_cb))(USB_DC_RESET, NULL); - } - return; - } else { usb_regs->dc_interrupt_status = DC_RESET_EVENT; } @@ -1133,14 +1121,13 @@ int usb_dc_ep_enable(const uint8_t ep) } if (!IT8XXX2_IS_EXTEND_ENDPOINT(ep_idx)) { - LOG_DBG("ep_idx < 4"); ep_regs[ep_idx].ep_ctrl |= ENDPOINT_EN; - LOG_DBG("EP%d Enabled %02x", ep_idx, ep_regs[ep_idx].ep_ctrl); } else { - LOG_DBG("ep_idx >= 4"); it82xx2_usb_extend_ep_ctrl(ep_idx, EXT_EP_ENABLE); } + LOG_DBG("Endpoint 0x%02x is enabled", ep); + return 0; } @@ -1380,7 +1367,6 @@ int usb_dc_ep_read(uint8_t ep, uint8_t *buf, uint32_t max_data_len, if (ep_idx > EP0) { ep_regs[ep_idx].ep_ctrl |= ENDPOINT_RDY; - LOG_DBG("Set EP%d Ready(%d)", ep_idx, __LINE__); } return 0; @@ -1453,7 +1439,6 @@ int usb_dc_ep_read(uint8_t ep, uint8_t *buf, uint32_t max_data_len, if (ep_fifo > EP0) { ep_regs[ep_fifo].ep_ctrl |= ENDPOINT_RDY; it82xx2_usb_extend_ep_ctrl(ep_idx, EXT_EP_READY); - LOG_DBG("(%d): Set EP%d Ready", __LINE__, ep_idx); udata0.ep_ready[ep_fifo - 1] = true; } else if (udata0.now_token == SETUP_TOKEN) { @@ -1466,8 +1451,6 @@ int usb_dc_ep_read(uint8_t ep, uint8_t *buf, uint32_t max_data_len, /* set status IN after data OUT */ ep_regs[EP0].ep_ctrl |= ENDPOINT_RDY | EP_OUTDATA_SEQ; - LOG_DBG("Set EP%d Ready(%d)", - ep_idx, __LINE__); } else { /* no_data_ctrl status */ @@ -1524,10 +1507,6 @@ int usb_dc_ep_read_wait(uint8_t ep, uint8_t *buf, uint32_t max_data_len, LOG_DBG("Read %d packets", *read_bytes); - if (ep_idx > EP0) { - LOG_DBG("RX buf[0]: 0x%02X", buf[0]); - } - return 0; } From d6cc083c2c48733f0fc7142ea7cfb83977ffc09f Mon Sep 17 00:00:00 2001 From: Ren Chen Date: Wed, 4 Oct 2023 10:00:06 +0800 Subject: [PATCH 1479/3723] drivers: usb: usb_dc_it82xx2: usb driver cleanup Cleans up the it82xx2 usb driver. Signed-off-by: Ren Chen --- drivers/usb/device/usb_dc_it82xx2.c | 99 ++++++++++------------------- 1 file changed, 33 insertions(+), 66 deletions(-) diff --git a/drivers/usb/device/usb_dc_it82xx2.c b/drivers/usb/device/usb_dc_it82xx2.c index 9aaf5b6fb49..117247c19c8 100644 --- a/drivers/usb/device/usb_dc_it82xx2.c +++ b/drivers/usb/device/usb_dc_it82xx2.c @@ -861,7 +861,7 @@ int usb_dc_attach(void) return ret; } - for (int idx = 0 ; idx < MAX_NUM_ENDPOINTS ; idx++) { + for (uint8_t idx = 0; idx < MAX_NUM_ENDPOINTS; idx++) { udata0.ep_data[idx].ep_status = EP_INIT; } @@ -1063,7 +1063,9 @@ int usb_dc_ep_configure(const struct usb_dc_ep_cfg_data *const cfg) break; case USB_DC_EP_BULK: + __fallthrough; case USB_DC_EP_INTERRUPT: + __fallthrough; default: if (!IT8XXX2_IS_EXTEND_ENDPOINT(ep_idx)) { ep_regs[ep_idx].ep_ctrl &= ~EP_ISO_ENABLE; @@ -1276,36 +1278,29 @@ int usb_dc_ep_write(uint8_t ep, const uint8_t *buf, uint8_t ep_idx = USB_EP_GET_IDX(ep); uint8_t ep_fifo = (ep_idx > 0) ? (ep_fifo_res[ep_idx % FIFO_NUM]) : 0; - uint32_t idx; - - /* status IN */ - if ((ep_idx == EP0) && (data_len == 0) && - (udata0.now_token == SETUP_TOKEN)) { - return 0; - } if (ep_idx >= MAX_NUM_ENDPOINTS) { return -EINVAL; } - /* clear fifo before write*/ if (ep_idx == EP0) { + if ((udata0.now_token == SETUP_TOKEN) && (data_len == 0)) { + return 0; + } + /* clear fifo before write*/ ff_regs[ep_idx].ep_tx_fifo_ctrl = FIFO_FORCE_EMPTY; - } - if ((ep_idx == EP0) && (udata0.st_state == SETUP_ST)) { - udata0.st_state = DIN_ST; - } - - /* select FIFO */ - if (ep_idx > EP0) { + if (udata0.st_state == SETUP_ST) { + udata0.st_state = DIN_ST; + } + } else { k_sem_take(&udata0.ep_sem[ep_fifo-1], K_FOREVER); it82xx2_usb_fifo_ctrl(ep); } if (data_len > udata0.ep_data[ep_idx].mps) { - for (idx = 0 ; idx < udata0.ep_data[ep_idx].mps ; idx++) { + for (uint32_t idx = 0; idx < udata0.ep_data[ep_idx].mps; idx++) { ff_regs[ep_fifo].ep_tx_fifo_data = buf[idx]; } @@ -1316,7 +1311,7 @@ int usb_dc_ep_write(uint8_t ep, const uint8_t *buf, LOG_DBG("data_len: %d, Write Max Packets to TX FIFO(%d)", data_len, ep_idx); } else { - for (idx = 0 ; idx < data_len ; idx++) { + for (uint32_t idx = 0; idx < data_len; idx++) { ff_regs[ep_fifo].ep_tx_fifo_data = buf[idx]; } @@ -1365,7 +1360,7 @@ int usb_dc_ep_read(uint8_t ep, uint8_t *buf, uint32_t max_data_len, *read_bytes = 0; - if (ep_idx > EP0) { + if (ep_idx > 0) { ep_regs[ep_idx].ep_ctrl |= ENDPOINT_RDY; } @@ -1376,47 +1371,28 @@ int usb_dc_ep_read(uint8_t ep, uint8_t *buf, uint32_t max_data_len, (((uint16_t)ff_regs[ep_fifo].ep_rx_fifo_dcnt_msb) << 8); if (ep_idx == 0) { - /* if ep0 check trans_type in OUT_TOKEN to - * prevent wrong read_bytes cause memory error - */ - if (udata0.st_state == STATUS_ST && - (ep_regs[EP0].ep_transtype_sts & DC_ALL_TRANS) == 0) { - + /* Prevent wrong read_bytes cause memory error + * if EP0 is in OUT status stage + */ + if (udata0.st_state == STATUS_ST) { *read_bytes = 0; return 0; - - } else if (udata0.st_state == STATUS_ST) { - /* status out but rx_fifo_len not zero */ - if (rx_fifo_len != 0) { - LOG_ERR("Status OUT length not 0 (%d)", - rx_fifo_len); + } else if (udata0.now_token == SETUP_TOKEN) { + if (rx_fifo_len == 0) { + LOG_ERR("Setup length 0, reset to 8"); + rx_fifo_len = 8; + } + if (rx_fifo_len != 8) { + LOG_ERR("Setup length: %d", rx_fifo_len); + ff_regs[0].ep_rx_fifo_ctrl = FIFO_FORCE_EMPTY; + return -EIO; } - /* rx_fifo_len = 0; */ - *read_bytes = 0; - - return 0; - } else if (rx_fifo_len == 0 && - udata0.now_token == SETUP_TOKEN) { - /* RX fifo error workaround */ - - /* wrong length(like 7), - * may read wrong packet so clear fifo then return -1 - */ - LOG_ERR("Setup length 0, reset to 8"); - rx_fifo_len = 8; - } else if (rx_fifo_len != 8 && - udata0.now_token == SETUP_TOKEN) { - LOG_ERR("Setup length: %d", rx_fifo_len); - /* clear rx fifo */ - ff_regs[EP0].ep_rx_fifo_ctrl = FIFO_FORCE_EMPTY; - - return -EIO; } } if (rx_fifo_len > max_data_len) { *read_bytes = max_data_len; - for (int idx = 0 ; idx < max_data_len ; idx++) { + for (uint32_t idx = 0; idx < max_data_len; idx++) { buf[idx] = ff_regs[ep_fifo].ep_rx_fifo_data; } @@ -1425,7 +1401,7 @@ int usb_dc_ep_read(uint8_t ep, uint8_t *buf, uint32_t max_data_len, *read_bytes = rx_fifo_len; - for (int idx = 0 ; idx < rx_fifo_len ; idx++) { + for (uint32_t idx = 0; idx < rx_fifo_len; idx++) { buf[idx] = ff_regs[ep_fifo].ep_rx_fifo_data; } @@ -1441,27 +1417,18 @@ int usb_dc_ep_read(uint8_t ep, uint8_t *buf, uint32_t max_data_len, it82xx2_usb_extend_ep_ctrl(ep_idx, EXT_EP_READY); udata0.ep_ready[ep_fifo - 1] = true; } else if (udata0.now_token == SETUP_TOKEN) { - if (!(buf[0] & USB_EP_DIR_MASK)) { - /* Host to device transfer check */ + /* request type: host-to-device transfer direction */ + ff_regs[0].ep_tx_fifo_ctrl = FIFO_FORCE_EMPTY; if (buf[6] != 0 || buf[7] != 0) { - /* clear tx fifo */ - ff_regs[EP0].ep_tx_fifo_ctrl = - FIFO_FORCE_EMPTY; /* set status IN after data OUT */ - ep_regs[EP0].ep_ctrl |= - ENDPOINT_RDY | EP_OUTDATA_SEQ; + ep_regs[0].ep_ctrl |= ENDPOINT_RDY | EP_OUTDATA_SEQ; } else { /* no_data_ctrl status */ - - /* clear tx fifo */ - ff_regs[EP0].ep_tx_fifo_ctrl = - FIFO_FORCE_EMPTY; udata0.no_data_ctrl = true; } } } - } return 0; @@ -1501,7 +1468,7 @@ int usb_dc_ep_read_wait(uint8_t ep, uint8_t *buf, uint32_t max_data_len, *read_bytes = (rx_fifo_len > max_data_len) ? max_data_len : rx_fifo_len; - for (int idx = 0 ; idx < *read_bytes ; idx++) { + for (uint32_t idx = 0; idx < *read_bytes; idx++) { buf[idx] = ff_regs[ep_fifo].ep_rx_fifo_data; } From 5846412167984457b681e5aac14f6cd5b8e05504 Mon Sep 17 00:00:00 2001 From: Ren Chen Date: Wed, 4 Oct 2023 12:57:09 +0800 Subject: [PATCH 1480/3723] drivers: usb: usb_dc_it82xx2: correct the extend endpoint control There are some issues with the extended endpoint settings. The incorrect setting leads to the chip being unable to respond with NAK when the host polls the extended endpoint for data transfers. Additionally, the controls for the extended endpoint's ISO and PID data sequence are also incorrect. This commit addresses these issues to properly support extended endpoint transactions. Signed-off-by: Ren Chen --- drivers/usb/device/usb_dc_it82xx2.c | 44 +++++++++++++++++++++-------- 1 file changed, 33 insertions(+), 11 deletions(-) diff --git a/drivers/usb/device/usb_dc_it82xx2.c b/drivers/usb/device/usb_dc_it82xx2.c index 117247c19c8..f2195b71e42 100644 --- a/drivers/usb/device/usb_dc_it82xx2.c +++ b/drivers/usb/device/usb_dc_it82xx2.c @@ -211,7 +211,7 @@ static const uint8_t ep_fifo_res[3] = {3, 1, 2}; /* Mapping the enum it82xx2_extend_ep_ctrl code to their corresponding bit in * the EP45/67/89/1011/1213/1415 Extended Control Registers. */ -static const uint8_t ext_ctrl_tbl[7] = { +static const uint8_t ext_ctrl_tbl[8] = { EPN0_ISO_ENABLE, EPN0_ISO_ENABLE, EPN0_SEND_STALL, @@ -219,6 +219,7 @@ static const uint8_t ext_ctrl_tbl[7] = { EPN0_SEND_STALL, EPN0_OUTDATA_SEQ, EPN0_OUTDATA_SEQ, + EPN0_OUTDATA_SEQ, }; /* Indexing of the following control codes: @@ -363,9 +364,8 @@ static void it82xx2_epn0n1_ext_ctrl_cfg_seq_inv(uint8_t reg_idx, volatile uint8_t *epn0n1_ext_ctrl = usb_regs->fifo_regs[EP_EXT_REGS_9X].ext_4_15.epn0n1_ext_ctrl; - bool check = (set_clr) ? - (epn0n1_ext_ctrl[reg_idx] & EPN0_OUTDATA_SEQ) : - (epn0n1_ext_ctrl[reg_idx] & EPN1_OUTDATA_SEQ); + bool check = (set_clr) ? (epn0n1_ext_ctrl[reg_idx] & EPN1_OUTDATA_SEQ) + : (epn0n1_ext_ctrl[reg_idx] & EPN0_OUTDATA_SEQ); (check) ? (epn0n1_ext_ctrl[reg_idx] &= ~(bit_mask)) : (epn0n1_ext_ctrl[reg_idx] |= bit_mask); @@ -441,7 +441,11 @@ static int it82xx2_usb_extend_ep_ctrl(uint8_t ep_idx, if ((ctrl >= EXT_EP_DIR_IN) && (ctrl < EXT_EP_READY)) { /* From EXT_EP_DIR_IN to EXT_EP_DISABLE */ reg_idx = ep_fifo_res[ep_idx % FIFO_NUM]; - mask = 1 << (ext_ep_bit_shift[ep_idx - 4] * 2 + 1); + if (ctrl == EXT_EP_DIR_IN || ctrl == EXT_EP_DIR_OUT) { + mask = BIT(ext_ep_bit_shift[ep_idx - 4] * 2 + 1); + } else { + mask = BIT(ext_ep_bit_shift[ep_idx - 4] * 2); + } flag = epn_ext_ctrl_tbl[ctrl - EXT_EP_DIR_IN]; it82xx2_epn_ext_ctrl_cfg1(reg_idx, mask, flag); @@ -451,13 +455,28 @@ static int it82xx2_usb_extend_ep_ctrl(uint8_t ep_idx, flag = !!(ep_idx & 1); mask = flag ? (ext_ctrl_tbl[ctrl] << 4) : (ext_ctrl_tbl[ctrl]); - if (ctrl == EXT_EP_CHECK_STALL) { + switch (ctrl) { + case EXT_EP_CHECK_STALL: return it82xx2_epn01n1_check_stall(reg_idx, mask); - } else if (ctrl == EXT_EP_DATA_SEQ_INV) { - it82xx2_epn0n1_ext_ctrl_cfg_seq_inv( - reg_idx, mask, flag); - } else { - it82xx2_epn0n1_ext_ctrl_cfg(reg_idx, mask, flag); + case EXT_EP_DATA_SEQ_INV: + it82xx2_epn0n1_ext_ctrl_cfg_seq_inv(reg_idx, mask, flag); + break; + case EXT_EP_ISO_DISABLE: + __fallthrough; + case EXT_EP_CLEAR_STALL: + __fallthrough; + case EXT_EP_DATA_SEQ_0: + it82xx2_epn0n1_ext_ctrl_cfg(reg_idx, mask, false); + break; + case EXT_EP_ISO_ENABLE: + __fallthrough; + case EXT_EP_SEND_STALL: + __fallthrough; + case EXT_EP_DATA_SEQ_1: + it82xx2_epn0n1_ext_ctrl_cfg(reg_idx, mask, true); + break; + default: + break; } } else if (ctrl == EXT_EP_READY) { reg_idx = (ep_idx - 4) >> 1; @@ -1125,6 +1144,9 @@ int usb_dc_ep_enable(const uint8_t ep) if (!IT8XXX2_IS_EXTEND_ENDPOINT(ep_idx)) { ep_regs[ep_idx].ep_ctrl |= ENDPOINT_EN; } else { + uint8_t ep_fifo = ep_fifo_res[ep_idx % FIFO_NUM]; + + ep_regs[ep_fifo].ep_ctrl |= ENDPOINT_EN; it82xx2_usb_extend_ep_ctrl(ep_idx, EXT_EP_ENABLE); } From 40fa61213e71764527b469151da2c647f6a681b7 Mon Sep 17 00:00:00 2001 From: Ren Chen Date: Mon, 2 Oct 2023 11:55:49 +0800 Subject: [PATCH 1481/3723] drivers: usb: usb_dc_it81xx2: refactor transaction complete isr function This commit refactor transaction complete callback function. Signed-off-by: Ren Chen --- drivers/usb/device/usb_dc_it82xx2.c | 315 ++++++++++++---------------- 1 file changed, 138 insertions(+), 177 deletions(-) diff --git a/drivers/usb/device/usb_dc_it82xx2.c b/drivers/usb/device/usb_dc_it82xx2.c index f2195b71e42..0ab1e4ace3b 100644 --- a/drivers/usb/device/usb_dc_it82xx2.c +++ b/drivers/usb/device/usb_dc_it82xx2.c @@ -189,10 +189,10 @@ struct usb_it82xx2_data { bool suspended; usb_dc_status_callback usb_status_cb; - /* Check the EP interrupt status for (ep > 0) */ - bool ep_ready[3]; + /* FIFO_1/2/3 ready status */ + bool fifo_ready[3]; - struct k_sem ep_sem[3]; + struct k_sem fifo_sem[3]; struct k_sem suspended_sem; struct k_work_delayable check_suspended_work; }; @@ -541,191 +541,181 @@ static bool it82xx2_check_setup_following_out(void) ff_regs[EP0].ep_rx_fifo_dcnt_lsb == SETUP_DATA_CNT)); } -static int it82xx2_setup_done(uint8_t ep_ctrl, uint8_t idx) +static inline void it82xx2_handler_setup(uint8_t fifo_idx, uint8_t ep_ctrl) { struct usb_it82xx2_regs *const usb_regs = (struct usb_it82xx2_regs *)it82xx2_get_usb_regs(); struct it82xx2_usb_ep_regs *ep_regs = usb_regs->usb_ep_regs; struct it82xx2_usb_ep_fifo_regs *ff_regs = usb_regs->fifo_regs; + uint8_t ep_idx = fifo_idx; - LOG_DBG("SETUP(%d)", idx); - /* wrong trans*/ + /* wrong trans */ if (ep_ctrl & EP_SEND_STALL) { - ep_regs[idx].ep_ctrl &= ~EP_SEND_STALL; + ep_regs[fifo_idx].ep_ctrl &= ~EP_SEND_STALL; udata0.st_state = STALL_SEND; - ff_regs[idx].ep_rx_fifo_ctrl = FIFO_FORCE_EMPTY; + ff_regs[fifo_idx].ep_rx_fifo_ctrl = FIFO_FORCE_EMPTY; LOG_DBG("Clear Stall Bit & RX FIFO"); - return -EINVAL; + return; } - /* handle status interrupt */ - /* status out */ + if (udata0.st_state == DIN_ST) { - LOG_DBG("Status OUT"); + /* setup -> in(data) -> out(status) */ udata0.last_token = udata0.now_token; udata0.now_token = OUT_TOKEN; udata0.st_state = STATUS_ST; - udata0.ep_data[idx].cb_out(idx, USB_DC_EP_DATA_OUT); + udata0.ep_data[ep_idx].cb_out(ep_idx | USB_EP_DIR_OUT, USB_DC_EP_DATA_OUT); } else if (udata0.st_state == DOUT_ST || udata0.st_state == SETUP_ST) { - /* Status IN*/ - LOG_DBG("Status IN"); + /* setup -> out(data) -> in(status) + * or + * setup -> in(status) + */ udata0.last_token = udata0.now_token; udata0.now_token = IN_TOKEN; udata0.st_state = STATUS_ST; - udata0.ep_data[idx].cb_in(idx | USB_EP_DIR_IN, USB_DC_EP_DATA_IN); + udata0.ep_data[ep_idx].cb_in(ep_idx | USB_EP_DIR_IN, USB_DC_EP_DATA_IN); } udata0.last_token = udata0.now_token; udata0.now_token = SETUP_TOKEN; udata0.st_state = SETUP_ST; - ep_regs[idx].ep_ctrl |= EP_OUTDATA_SEQ; - udata0.ep_data[idx].cb_out(USB_EP_DIR_OUT, USB_DC_EP_SETUP); + ep_regs[fifo_idx].ep_ctrl |= EP_OUTDATA_SEQ; + udata0.ep_data[ep_idx].cb_out(ep_idx | USB_EP_DIR_OUT, USB_DC_EP_SETUP); /* Set ready bit to no-data control in */ if (udata0.no_data_ctrl) { - ep_regs[EP0].ep_ctrl |= ENDPOINT_RDY; + ep_regs[fifo_idx].ep_ctrl |= ENDPOINT_RDY; udata0.no_data_ctrl = false; } - - return 0; } -static int it82xx2_in_done(uint8_t ep_ctrl, uint8_t idx) +static inline void it82xx2_handler_in(uint8_t fifo_idx, uint8_t ep_ctrl) { struct usb_it82xx2_regs *const usb_regs = (struct usb_it82xx2_regs *)it82xx2_get_usb_regs(); struct it82xx2_usb_ep_regs *ep_regs = usb_regs->usb_ep_regs; + volatile struct epn_ext_ctrl_regs *epn_ext_ctrl = + usb_regs->fifo_regs[EP_EXT_REGS_DX].ext_0_3.epn_ext_ctrl; + uint8_t ep_idx; - /* stall send check */ - if (ep_ctrl & EP_SEND_STALL) { - ep_regs[EP0].ep_ctrl &= ~EP_SEND_STALL; - udata0.st_state = STALL_SEND; - LOG_DBG("Clear Stall Bit"); - return -EINVAL; - } + if (fifo_idx != 0) { + if (!udata0.fifo_ready[fifo_idx - 1]) { + return; + } - if (udata0.st_state >= STATUS_ST) { - return -EINVAL; - } + ep_idx = (epn_ext_ctrl[fifo_idx].epn_ext_ctrl2 & COMPLETED_TRANS) >> 4; + if (ep_idx == 0 || udata0.ep_data[ep_idx].ep_status != EP_CONFIG_IN) { + return; + } + udata0.fifo_ready[fifo_idx - 1] = false; + } else { + ep_idx = 0; + if (ep_ctrl & EP_SEND_STALL) { + ep_regs[0].ep_ctrl &= ~EP_SEND_STALL; + udata0.st_state = STALL_SEND; + LOG_DBG("Clear Stall Bit"); + return; + } - LOG_DBG("IN(%d)(%d)", idx, !!(ep_regs[idx].ep_ctrl & EP_OUTDATA_SEQ)); + if (udata0.st_state >= STATUS_ST) { + return; + } - udata0.last_token = udata0.now_token; - udata0.now_token = IN_TOKEN; + udata0.last_token = udata0.now_token; + udata0.now_token = IN_TOKEN; - if (udata0.addr != DC_ADDR_NULL && - udata0.addr != usb_regs->dc_address) { - usb_regs->dc_address = udata0.addr; - LOG_DBG("Address Is Set Successfully"); - } + if (udata0.addr != DC_ADDR_NULL && udata0.addr != usb_regs->dc_address) { + usb_regs->dc_address = udata0.addr; + LOG_DBG("Address Is Set Successfully"); + } - /* set setup stage */ - if (udata0.st_state == DOUT_ST) { - udata0.st_state = STATUS_ST; - /* no data status in */ - } else if (udata0.ep_data[EP0].remaining == 0 && - udata0.st_state == SETUP_ST) { - udata0.st_state = STATUS_ST; - } else { - udata0.st_state = DIN_ST; + if (udata0.st_state == DOUT_ST) { + /* setup -> out(data) -> in(status) */ + udata0.st_state = STATUS_ST; + } else if (udata0.ep_data[0].remaining == 0 && udata0.st_state == SETUP_ST) { + /* setup -> in(status) */ + udata0.st_state = STATUS_ST; + } else { + /* setup -> in(data) */ + udata0.st_state = DIN_ST; + } } - if (!!(ep_regs[idx].ep_ctrl & EP_OUTDATA_SEQ)) { - ep_regs[idx].ep_ctrl &= ~EP_OUTDATA_SEQ; + if (!!(ep_regs[fifo_idx].ep_ctrl & EP_OUTDATA_SEQ)) { + ep_regs[fifo_idx].ep_ctrl &= ~EP_OUTDATA_SEQ; } else { - ep_regs[idx].ep_ctrl |= EP_OUTDATA_SEQ; - } - udata0.ep_data[idx].cb_in(idx | USB_EP_DIR_IN, USB_DC_EP_DATA_IN); - - /* set ready bit for status out */ - LOG_DBG("Remaining Bytes: %d, Stage: %d", - udata0.ep_data[EP0].remaining, udata0.st_state); - - if (udata0.st_state == DIN_ST && udata0.ep_data[EP0].remaining == 0) { - ep_regs[EP0].ep_ctrl |= ENDPOINT_RDY; + ep_regs[fifo_idx].ep_ctrl |= EP_OUTDATA_SEQ; } - return 0; -} - -static int it82xx2_out_done(uint8_t idx) -{ - struct usb_it82xx2_regs *const usb_regs = - (struct usb_it82xx2_regs *)it82xx2_get_usb_regs(); - struct it82xx2_usb_ep_regs *ep_regs = usb_regs->usb_ep_regs; - - /* ep0 wrong enter check */ - if (udata0.st_state >= STATUS_ST) { - return -EINVAL; + if (udata0.ep_data[ep_idx].cb_in) { + udata0.ep_data[ep_idx].cb_in(ep_idx | USB_EP_DIR_IN, USB_DC_EP_DATA_IN); } - LOG_DBG("OUT(%d)", idx); - - udata0.last_token = udata0.now_token; - udata0.now_token = OUT_TOKEN; - - if (udata0.st_state == SETUP_ST) { - udata0.st_state = DOUT_ST; + if (fifo_idx != 0) { + k_sem_give(&udata0.fifo_sem[fifo_idx - 1]); } else { - udata0.st_state = STATUS_ST; - } - - udata0.ep_data[idx].cb_out(idx, USB_DC_EP_DATA_OUT); - - /* SETUP_TOKEN follow OUT_TOKEN */ - if (it82xx2_check_setup_following_out()) { - LOG_DBG("[%s] OUT => SETUP", __func__); - udata0.last_token = udata0.now_token; - udata0.now_token = SETUP_TOKEN; - udata0.st_state = SETUP_ST; - ep_regs[EP0].ep_ctrl |= EP_OUTDATA_SEQ; - udata0.ep_data[EP0].cb_out(USB_EP_DIR_OUT, USB_DC_EP_SETUP); - - /* NOTE: set ready bit to no-data control in */ - if (udata0.no_data_ctrl) { - ep_regs[EP0].ep_ctrl |= ENDPOINT_RDY; - udata0.no_data_ctrl = false; + if (udata0.st_state == DIN_ST && udata0.ep_data[ep_idx].remaining == 0) { + ep_regs[fifo_idx].ep_ctrl |= ENDPOINT_RDY; } } - - return 0; } -/* Functions it82xx2_ep_in_out_config(): - * Dealing with the ep_ctrl configurations in this subroutine when it's - * invoked in the it82xx2_usb_dc_trans_done(). - */ -static void it82xx2_ep_in_out_config(uint8_t idx) +static inline void it82xx2_handler_out(uint8_t fifo_idx) { struct usb_it82xx2_regs *const usb_regs = (struct usb_it82xx2_regs *)it82xx2_get_usb_regs(); struct it82xx2_usb_ep_regs *ep_regs = usb_regs->usb_ep_regs; - struct epn_ext_ctrl_regs *epn_ext_ctrl = + volatile struct epn_ext_ctrl_regs *epn_ext_ctrl = usb_regs->fifo_regs[EP_EXT_REGS_DX].ext_0_3.epn_ext_ctrl; + uint8_t ep_idx; - uint8_t ep_idx = (epn_ext_ctrl[idx].epn_ext_ctrl2 & COMPLETED_TRANS) >> 4; + if (fifo_idx != 0) { + if (!udata0.fifo_ready[fifo_idx - 1]) { + return; + } - if (udata0.ep_data[ep_idx].ep_status == EP_CONFIG_IN) { - if (!IT8XXX2_IS_EXTEND_ENDPOINT(ep_idx)) { - if (!!(ep_regs[idx].ep_ctrl & EP_OUTDATA_SEQ)) { - ep_regs[idx].ep_ctrl &= ~EP_OUTDATA_SEQ; - } else { - ep_regs[idx].ep_ctrl |= EP_OUTDATA_SEQ; - } - } else { - it82xx2_usb_extend_ep_ctrl(ep_idx, EXT_EP_DATA_SEQ_INV); + ep_idx = (epn_ext_ctrl[fifo_idx].epn_ext_ctrl2 & COMPLETED_TRANS) >> 4; + if (ep_idx == 0 || udata0.ep_data[ep_idx].ep_status != EP_CONFIG_OUT) { + return; } + udata0.fifo_ready[fifo_idx - 1] = false; + } else { + ep_idx = 0; + /* ep0 wrong enter check */ + if (udata0.st_state >= STATUS_ST) { + return; + } + + udata0.last_token = udata0.now_token; + udata0.now_token = OUT_TOKEN; - if (udata0.ep_data[ep_idx].cb_in) { - udata0.ep_data[ep_idx].cb_in(ep_idx | USB_EP_DIR_IN, USB_DC_EP_DATA_IN); + if (udata0.st_state == SETUP_ST) { + /* setup -> out(data) */ + udata0.st_state = DOUT_ST; + } else { + /* setup -> in(data) -> out(status) */ + udata0.st_state = STATUS_ST; } + } - k_sem_give(&udata0.ep_sem[idx - 1]); + if (udata0.ep_data[ep_idx].cb_out) { + udata0.ep_data[ep_idx].cb_out(ep_idx, USB_DC_EP_DATA_OUT); + } - } else { - if (udata0.ep_data[ep_idx].cb_out) { - udata0.ep_data[ep_idx].cb_out(ep_idx, USB_DC_EP_DATA_OUT); + if (fifo_idx == 0) { + /* SETUP_TOKEN follow OUT_TOKEN */ + if (it82xx2_check_setup_following_out()) { + udata0.last_token = udata0.now_token; + udata0.now_token = SETUP_TOKEN; + udata0.st_state = SETUP_ST; + ep_regs[fifo_idx].ep_ctrl |= EP_OUTDATA_SEQ; + udata0.ep_data[ep_idx].cb_out(ep_idx | USB_EP_DIR_OUT, USB_DC_EP_SETUP); + + if (udata0.no_data_ctrl) { + ep_regs[fifo_idx].ep_ctrl |= ENDPOINT_RDY; + udata0.no_data_ctrl = false; + } } } } @@ -735,55 +725,26 @@ static void it82xx2_usb_dc_trans_done(void) struct usb_it82xx2_regs *const usb_regs = (struct usb_it82xx2_regs *)it82xx2_get_usb_regs(); struct it82xx2_usb_ep_regs *ep_regs = usb_regs->usb_ep_regs; - struct epn_ext_ctrl_regs *epn_ext_ctrl = - usb_regs->fifo_regs[EP_EXT_REGS_DX].ext_0_3.epn_ext_ctrl; - - int ret; - for (uint8_t idx = 0; idx < 4; idx++) { - uint8_t ep_ctrl = ep_regs[idx].ep_ctrl; + for (uint8_t fifo_idx = 0; fifo_idx < 4; fifo_idx++) { + uint8_t ep_ctrl = ep_regs[fifo_idx].ep_ctrl; /* check ready bit ,will be 0 when trans done */ if ((ep_ctrl & ENDPOINT_EN) && !(ep_ctrl & ENDPOINT_RDY)) { - if (idx == EP0) { - uint8_t ep_trans_type = ep_regs[idx].ep_transtype_sts & - DC_ALL_TRANS; - - /* set up*/ - if (ep_trans_type == DC_SETUP_TRANS) { - ret = it82xx2_setup_done(ep_ctrl, idx); - - if (ret != 0) { - continue; - } - } else if (ep_trans_type == DC_IN_TRANS) { - /* in */ - ret = it82xx2_in_done(ep_ctrl, idx); - - if (ret != 0) { - continue; - } - } else if (ep_trans_type == DC_OUTDATA_TRANS) { - /* out */ - ret = it82xx2_out_done(idx); - - if (ret != 0) { - continue; - } - } - } else { - /* prevent wrong entry */ - if (!udata0.ep_ready[idx - 1]) { - continue; + switch (ep_regs[fifo_idx].ep_transtype_sts & DC_ALL_TRANS) { + case DC_SETUP_TRANS: + if (fifo_idx == 0) { + it82xx2_handler_setup(fifo_idx, ep_ctrl); } - - if ((epn_ext_ctrl[idx].epn_ext_ctrl2 & - COMPLETED_TRANS) == 0) { - continue; - } - - udata0.ep_ready[idx - 1] = false; - it82xx2_ep_in_out_config(idx); + break; + case DC_IN_TRANS: + it82xx2_handler_in(fifo_idx, ep_ctrl); + break; + case DC_OUTDATA_TRANS: + it82xx2_handler_out(fifo_idx); + break; + default: + break; } } } @@ -886,14 +847,14 @@ int usb_dc_attach(void) udata0.attached = 1U; - /* init ep ready status */ - udata0.ep_ready[0] = false; - udata0.ep_ready[1] = false; - udata0.ep_ready[2] = false; + /* init fifo ready status */ + udata0.fifo_ready[0] = false; + udata0.fifo_ready[1] = false; + udata0.fifo_ready[2] = false; - k_sem_init(&udata0.ep_sem[0], 1, 1); - k_sem_init(&udata0.ep_sem[1], 1, 1); - k_sem_init(&udata0.ep_sem[2], 1, 1); + k_sem_init(&udata0.fifo_sem[0], 1, 1); + k_sem_init(&udata0.fifo_sem[1], 1, 1); + k_sem_init(&udata0.fifo_sem[2], 1, 1); k_sem_init(&udata0.suspended_sem, 0, 1); k_work_init_delayable(&udata0.check_suspended_work, suspended_check_handler); @@ -1316,7 +1277,7 @@ int usb_dc_ep_write(uint8_t ep, const uint8_t *buf, udata0.st_state = DIN_ST; } } else { - k_sem_take(&udata0.ep_sem[ep_fifo-1], K_FOREVER); + k_sem_take(&udata0.fifo_sem[ep_fifo - 1], K_FOREVER); it82xx2_usb_fifo_ctrl(ep); } @@ -1349,7 +1310,7 @@ int usb_dc_ep_write(uint8_t ep, const uint8_t *buf, ep_regs[ep_fifo].ep_ctrl |= ENDPOINT_RDY; if (ep_fifo > EP0) { - udata0.ep_ready[ep_fifo - 1] = true; + udata0.fifo_ready[ep_fifo - 1] = true; } LOG_DBG("Set EP%d Ready(%d)", ep_idx, __LINE__); @@ -1437,7 +1398,7 @@ int usb_dc_ep_read(uint8_t ep, uint8_t *buf, uint32_t max_data_len, if (ep_fifo > EP0) { ep_regs[ep_fifo].ep_ctrl |= ENDPOINT_RDY; it82xx2_usb_extend_ep_ctrl(ep_idx, EXT_EP_READY); - udata0.ep_ready[ep_fifo - 1] = true; + udata0.fifo_ready[ep_fifo - 1] = true; } else if (udata0.now_token == SETUP_TOKEN) { if (!(buf[0] & USB_EP_DIR_MASK)) { /* request type: host-to-device transfer direction */ @@ -1520,7 +1481,7 @@ int usb_dc_ep_read_continue(uint8_t ep) it82xx2_usb_extend_ep_ctrl(ep_idx, EXT_EP_READY); ep_regs[ep_fifo].ep_ctrl |= ENDPOINT_RDY; - udata0.ep_ready[ep_fifo - 1] = true; + udata0.fifo_ready[ep_fifo - 1] = true; LOG_DBG("EP(%d) Read Continue", ep_idx); return 0; } From 5762d022dc440e28a9df471d0752f77e76be83a0 Mon Sep 17 00:00:00 2001 From: Ren Chen Date: Mon, 2 Oct 2023 13:13:51 +0800 Subject: [PATCH 1482/3723] drivers: usb: usb_dc_it82xx2: optimize the basic/extend endpoints control This commit refactors the basic and extended endpoint control functions to enhance readability. Signed-off-by: Ren Chen --- drivers/usb/device/usb_dc_it82xx2.c | 507 +++++++++------------ soc/riscv/riscv-ite/common/chip_chipregs.h | 47 +- 2 files changed, 269 insertions(+), 285 deletions(-) diff --git a/drivers/usb/device/usb_dc_it82xx2.c b/drivers/usb/device/usb_dc_it82xx2.c index 0ab1e4ace3b..5020c1c39ed 100644 --- a/drivers/usb/device/usb_dc_it82xx2.c +++ b/drivers/usb/device/usb_dc_it82xx2.c @@ -65,12 +65,6 @@ enum it82xx2_transaction_types { /* Bit definitions of the register Port0/Port1 MISC Control: 0XE4/0xE8 */ #define PULL_DOWN_EN BIT(4) -/* Bit definitions of the register EPN0N1_EXTEND_CONTROL_REG: 0X98 ~ 0X9D */ -#define EPN1_OUTDATA_SEQ BIT(4) -#define EPN0_ISO_ENABLE BIT(2) -#define EPN0_SEND_STALL BIT(1) -#define EPN0_OUTDATA_SEQ BIT(0) - /* ENDPOINT[3..0]_STATUS_REG */ #define DC_STALL_SENT BIT(5) @@ -92,10 +86,7 @@ enum it82xx2_transaction_types { /* ENDPOINT[3..0]_CONTROL_REG */ #define ENDPOINT_EN BIT(0) #define ENDPOINT_RDY BIT(1) -#define EP_OUTDATA_SEQ BIT(2) #define EP_SEND_STALL BIT(3) -#define EP_ISO_ENABLE BIT(4) -#define EP_DIRECTION BIT(5) enum it82xx2_ep_status { EP_INIT = 0, @@ -120,23 +111,15 @@ enum it82xx2_setup_stage { STALL_SEND, }; -enum it82xx2_extend_ep_ctrl { - /* EPN0N1_EXTEND_CONTROL_REG */ - EXT_EP_ISO_DISABLE, - EXT_EP_ISO_ENABLE, - EXT_EP_SEND_STALL, - EXT_EP_CLEAR_STALL, - EXT_EP_CHECK_STALL, - EXT_EP_DATA_SEQ_1, - EXT_EP_DATA_SEQ_0, - EXT_EP_DATA_SEQ_INV, - /* EPN_EXTEND_CONTROL1_REG */ - EXT_EP_DIR_IN, - EXT_EP_DIR_OUT, - EXT_EP_ENABLE, - EXT_EP_DISABLE, - /* EPN_EXTEND_CONTROL2_REG */ - EXT_EP_READY, +enum it82xx2_ep_ctrl { + EP_IN_DIRECTION_SET, + EP_STALL_SEND, + EP_STALL_CHECK, + EP_IOS_ENABLE, + EP_ENABLE, + EP_DATA_SEQ_1, + EP_DATA_SEQ_TOGGLE, + EP_READY_ENABLE, }; struct usb_it8xxx2_wuc { @@ -197,36 +180,11 @@ struct usb_it82xx2_data { struct k_work_delayable check_suspended_work; }; -/* Mapped to the bit definitions in the EPN_EXTEND_CONTROL1 Register - * (D6h to DDh) for configuring the FIFO direction and for enabling/disabling - * the endpoints. - */ -static uint8_t ext_ep_bit_shift[12] = {0, 0, 0, 1, 1, 1, 2, 2, 2, 3, 3, 3}; - /* The ep_fifo_res[ep_idx % FIFO_NUM] where the FIFO_NUM is 3 represents the * EP mapping because when (ep_idx % FIFO_NUM) is 3, it actually means the EP0. */ static const uint8_t ep_fifo_res[3] = {3, 1, 2}; -/* Mapping the enum it82xx2_extend_ep_ctrl code to their corresponding bit in - * the EP45/67/89/1011/1213/1415 Extended Control Registers. - */ -static const uint8_t ext_ctrl_tbl[8] = { - EPN0_ISO_ENABLE, - EPN0_ISO_ENABLE, - EPN0_SEND_STALL, - EPN0_SEND_STALL, - EPN0_SEND_STALL, - EPN0_OUTDATA_SEQ, - EPN0_OUTDATA_SEQ, - EPN0_OUTDATA_SEQ, -}; - -/* Indexing of the following control codes: - * EXT_EP_DIR_IN, EXT_EP_DIR_OUT, EXT_EP_ENABLE, EXT_EP_DISABLE - */ -static const uint8_t epn_ext_ctrl_tbl[4] = {1, 0, 1, 0}; - static struct usb_it82xx2_data udata0; static struct usb_it82xx2_regs *it82xx2_get_usb_regs(void) @@ -338,158 +296,196 @@ static int it82xx2_usb_fifo_ctrl(uint8_t ep) return ret; } -/* - * Functions it82xx2_epn0n1_ext_ctrl_cfg() and epn0n1_ext_ctrl_cfg_seq_inv() - * provide the entrance of configuring the EPN0N1 Extended Ctrl Registers. - * - * The variable set_clr determines if we set/clear the corresponding bit. - */ -static void it82xx2_epn0n1_ext_ctrl_cfg(uint8_t reg_idx, uint8_t bit_mask, - bool set_clr) +static volatile void *it82xx2_get_ext_ctrl(int ep_idx, enum it82xx2_ep_ctrl ctrl) { + uint8_t idx; struct usb_it82xx2_regs *const usb_regs = (struct usb_it82xx2_regs *)it82xx2_get_usb_regs(); - volatile uint8_t *epn0n1_ext_ctrl = + union epn0n1_extend_ctrl_reg *epn0n1_ext_ctrl = usb_regs->fifo_regs[EP_EXT_REGS_9X].ext_4_15.epn0n1_ext_ctrl; + struct epn_ext_ctrl_regs *ext_ctrl = + usb_regs->fifo_regs[EP_EXT_REGS_DX].ext_0_3.epn_ext_ctrl; + + if ((ctrl == EP_IN_DIRECTION_SET) || (ctrl == EP_ENABLE)) { + idx = ((ep_idx - 4) % 3) + 1; + return &ext_ctrl[idx].epn_ext_ctrl1; + } - (set_clr) ? (epn0n1_ext_ctrl[reg_idx] |= bit_mask) : - (epn0n1_ext_ctrl[reg_idx] &= ~(bit_mask)); + idx = (ep_idx - 4) / 2; + return &epn0n1_ext_ctrl[idx]; } -static void it82xx2_epn0n1_ext_ctrl_cfg_seq_inv(uint8_t reg_idx, - uint8_t bit_mask, bool set_clr) +static int it82xx2_usb_extend_ep_ctrl(uint8_t ep, enum it82xx2_ep_ctrl ctrl, bool enable) { - struct usb_it82xx2_regs *const usb_regs = - (struct usb_it82xx2_regs *)it82xx2_get_usb_regs(); - volatile uint8_t *epn0n1_ext_ctrl = - usb_regs->fifo_regs[EP_EXT_REGS_9X].ext_4_15.epn0n1_ext_ctrl; - - bool check = (set_clr) ? (epn0n1_ext_ctrl[reg_idx] & EPN1_OUTDATA_SEQ) - : (epn0n1_ext_ctrl[reg_idx] & EPN0_OUTDATA_SEQ); + struct usb_it82xx2_regs *const usb_regs = (struct usb_it82xx2_regs *)it82xx2_get_usb_regs(); + struct epn_ext_ctrl_regs *ext_ctrl = + usb_regs->fifo_regs[EP_EXT_REGS_DX].ext_0_3.epn_ext_ctrl; + union epn_extend_ctrl1_reg *epn_ext_ctrl1 = NULL; + union epn0n1_extend_ctrl_reg *epn0n1_ext_ctrl = NULL; + uint8_t ep_idx = USB_EP_GET_IDX(ep); - (check) ? (epn0n1_ext_ctrl[reg_idx] &= ~(bit_mask)) : - (epn0n1_ext_ctrl[reg_idx] |= bit_mask); -} + if (!IT8XXX2_IS_EXTEND_ENDPOINT(ep_idx)) { + return -EINVAL; + } -/* Return the status of STALL bit in the EPN0N1 Extend Control Registers */ -static bool it82xx2_epn01n1_check_stall(uint8_t reg_idx, uint8_t bit_mask) -{ - struct usb_it82xx2_regs *const usb_regs = - (struct usb_it82xx2_regs *)it82xx2_get_usb_regs(); - volatile uint8_t *epn0n1_ext_ctrl = - usb_regs->fifo_regs[EP_EXT_REGS_9X].ext_4_15.epn0n1_ext_ctrl; + if ((ctrl == EP_IN_DIRECTION_SET) || (ctrl == EP_ENABLE)) { + epn_ext_ctrl1 = (union epn_extend_ctrl1_reg *)it82xx2_get_ext_ctrl(ep_idx, ctrl); + } else { + epn0n1_ext_ctrl = + (union epn0n1_extend_ctrl_reg *)it82xx2_get_ext_ctrl(ep_idx, ctrl); + } - return !!(epn0n1_ext_ctrl[reg_idx] & bit_mask); -} + switch (ctrl) { + case EP_STALL_SEND: + if (ep_idx % 2) { + epn0n1_ext_ctrl->fields.epn1_send_stall_bit = enable; + } else { + epn0n1_ext_ctrl->fields.epn0_send_stall_bit = enable; + } + break; + case EP_STALL_CHECK: + if (ep_idx % 2) { + return epn0n1_ext_ctrl->fields.epn1_send_stall_bit; + } else { + return epn0n1_ext_ctrl->fields.epn0_send_stall_bit; + } + break; + case EP_IOS_ENABLE: + if (ep_idx % 2) { + epn0n1_ext_ctrl->fields.epn1_iso_enable_bit = enable; + } else { + epn0n1_ext_ctrl->fields.epn0_iso_enable_bit = enable; + } + break; + case EP_DATA_SEQ_1: + if (ep_idx % 2) { + epn0n1_ext_ctrl->fields.epn1_outdata_sequence_bit = enable; + } else { + epn0n1_ext_ctrl->fields.epn0_outdata_sequence_bit = enable; + } + break; + case EP_DATA_SEQ_TOGGLE: + if (!enable) { + break; + } + if (ep_idx % 2) { + if (epn0n1_ext_ctrl->fields.epn1_outdata_sequence_bit) { + epn0n1_ext_ctrl->fields.epn1_outdata_sequence_bit = 0; + } else { + epn0n1_ext_ctrl->fields.epn1_outdata_sequence_bit = 1; + } + } else { + if (epn0n1_ext_ctrl->fields.epn0_outdata_sequence_bit) { + epn0n1_ext_ctrl->fields.epn0_outdata_sequence_bit = 0; + } else { + epn0n1_ext_ctrl->fields.epn0_outdata_sequence_bit = 1; + } + } + break; + case EP_IN_DIRECTION_SET: + if (((ep_idx - 4) / 3 == 0)) { + epn_ext_ctrl1->fields.epn0_direction_bit = enable; + } else if (((ep_idx - 4) / 3 == 1)) { + epn_ext_ctrl1->fields.epn3_direction_bit = enable; + } else if (((ep_idx - 4) / 3 == 2)) { + epn_ext_ctrl1->fields.epn6_direction_bit = enable; + } else if (((ep_idx - 4) / 3 == 3)) { + epn_ext_ctrl1->fields.epn9_direction_bit = enable; + } else { + LOG_ERR("Invalid endpoint 0x%x for control type 0x%x", ep, ctrl); + return -EINVAL; + } + break; + case EP_ENABLE: + if (((ep_idx - 4) / 3 == 0)) { + epn_ext_ctrl1->fields.epn0_enable_bit = enable; + } else if (((ep_idx - 4) / 3 == 1)) { + epn_ext_ctrl1->fields.epn3_enable_bit = enable; + } else if (((ep_idx - 4) / 3 == 2)) { + epn_ext_ctrl1->fields.epn6_enable_bit = enable; + } else if (((ep_idx - 4) / 3 == 3)) { + epn_ext_ctrl1->fields.epn9_enable_bit = enable; + } else { + LOG_ERR("Invalid endpoint 0x%x for control type 0x%x", ep, ctrl); + return -EINVAL; + } + break; + case EP_READY_ENABLE: + int idx = ((ep_idx - 4) % 3) + 1; -/* Configuring the EPN Extended Ctrl Registers. */ -static void it82xx2_epn_ext_ctrl_cfg1(uint8_t reg_idx, uint8_t bit_mask, - bool set_clr) -{ - struct usb_it82xx2_regs *const usb_regs = - (struct usb_it82xx2_regs *)it82xx2_get_usb_regs(); - struct epn_ext_ctrl_regs *epn_ext_ctrl = - usb_regs->fifo_regs[EP_EXT_REGS_DX].ext_0_3.epn_ext_ctrl; + (enable) ? (ext_ctrl[idx].epn_ext_ctrl2 |= BIT((ep_idx - 4) / 3)) + : (ext_ctrl[idx].epn_ext_ctrl2 &= ~BIT((ep_idx - 4) / 3)); + break; + default: + LOG_ERR("Unknown control type 0x%x", ctrl); + return -EINVAL; + } - (set_clr) ? (epn_ext_ctrl[reg_idx].epn_ext_ctrl1 |= bit_mask) : - (epn_ext_ctrl[reg_idx].epn_ext_ctrl1 &= ~(bit_mask)); + return 0; } -static void it82xx2_epn_ext_ctrl_cfg2(uint8_t reg_idx, uint8_t bit_mask, - bool set_clr) +static int it82xx2_usb_ep_ctrl(uint8_t ep, enum it82xx2_ep_ctrl ctrl, bool enable) { struct usb_it82xx2_regs *const usb_regs = (struct usb_it82xx2_regs *)it82xx2_get_usb_regs(); - struct epn_ext_ctrl_regs *epn_ext_ctrl = - usb_regs->fifo_regs[EP_EXT_REGS_DX].ext_0_3.epn_ext_ctrl; - - (set_clr) ? (epn_ext_ctrl[reg_idx].epn_ext_ctrl2 |= bit_mask) : - (epn_ext_ctrl[reg_idx].epn_ext_ctrl2 &= ~(bit_mask)); -} - -/* From 98h to 9Dh, the EP45/67/89/1011/1213/1415 Extended Control Registers - * are defined, and their bits definitions are as follows: - * - * Bit Description - * 7 Reserved - * 6 EPPOINT5_ISO_ENABLE - * 5 EPPOINT5_SEND_STALL - * 4 EPPOINT5_OUT_DATA_SEQUENCE - * 3 Reserved - * 2 EPPOINT4_ISO_ENABLE - * 1 EPPOINT4_SEND_STALL - * 0 EPPOINT4_OUT_DATA_SEQUENCE - * - * Apparently, we can tell that the EP4 and EP5 share the same register, and - * the EP6 and EP7 share the same one, and the other EPs are defined in the - * same way. - * - * In the function it82xx2_usb_extend_ep_ctrl() we will obtain the mask/flag - * according to the bits definitions mentioned above. As for the control code, - * please refer to the definition of enum it82xx2_extend_ep_ctrl. - */ -static int it82xx2_usb_extend_ep_ctrl(uint8_t ep_idx, - enum it82xx2_extend_ep_ctrl ctrl) -{ - uint8_t reg_idx, mask; - bool flag; + struct it82xx2_usb_ep_regs *ep_regs = usb_regs->usb_ep_regs; + uint8_t ep_idx = USB_EP_GET_IDX(ep); - if (!IT8XXX2_IS_EXTEND_ENDPOINT(ep_idx)) { + if (IT8XXX2_IS_EXTEND_ENDPOINT(ep_idx)) { return -EINVAL; } - if ((ctrl >= EXT_EP_DIR_IN) && (ctrl < EXT_EP_READY)) { - /* From EXT_EP_DIR_IN to EXT_EP_DISABLE */ - reg_idx = ep_fifo_res[ep_idx % FIFO_NUM]; - if (ctrl == EXT_EP_DIR_IN || ctrl == EXT_EP_DIR_OUT) { - mask = BIT(ext_ep_bit_shift[ep_idx - 4] * 2 + 1); - } else { - mask = BIT(ext_ep_bit_shift[ep_idx - 4] * 2); - } - flag = epn_ext_ctrl_tbl[ctrl - EXT_EP_DIR_IN]; - it82xx2_epn_ext_ctrl_cfg1(reg_idx, mask, flag); - - } else if ((ctrl >= EXT_EP_ISO_DISABLE) && (ctrl < EXT_EP_DIR_IN)) { - /* From EXT_EP_ISO_DISABLE to EXT_EP_DATA_SEQ_0 */ - reg_idx = (ep_idx - 4) >> 1; - flag = !!(ep_idx & 1); - mask = flag ? (ext_ctrl_tbl[ctrl] << 4) : (ext_ctrl_tbl[ctrl]); - - switch (ctrl) { - case EXT_EP_CHECK_STALL: - return it82xx2_epn01n1_check_stall(reg_idx, mask); - case EXT_EP_DATA_SEQ_INV: - it82xx2_epn0n1_ext_ctrl_cfg_seq_inv(reg_idx, mask, flag); - break; - case EXT_EP_ISO_DISABLE: - __fallthrough; - case EXT_EP_CLEAR_STALL: - __fallthrough; - case EXT_EP_DATA_SEQ_0: - it82xx2_epn0n1_ext_ctrl_cfg(reg_idx, mask, false); - break; - case EXT_EP_ISO_ENABLE: - __fallthrough; - case EXT_EP_SEND_STALL: - __fallthrough; - case EXT_EP_DATA_SEQ_1: - it82xx2_epn0n1_ext_ctrl_cfg(reg_idx, mask, true); - break; - default: + switch (ctrl) { + case EP_IN_DIRECTION_SET: + ep_regs[ep_idx].ep_ctrl.fields.direction_bit = enable; + break; + case EP_STALL_SEND: + ep_regs[ep_idx].ep_ctrl.fields.send_stall_bit = enable; + break; + case EP_STALL_CHECK: + return ep_regs[ep_idx].ep_ctrl.fields.send_stall_bit; + case EP_IOS_ENABLE: + ep_regs[ep_idx].ep_ctrl.fields.iso_enable_bit = enable; + break; + case EP_ENABLE: + ep_regs[ep_idx].ep_ctrl.fields.enable_bit = enable; + break; + case EP_READY_ENABLE: + ep_regs[ep_idx].ep_ctrl.fields.ready_bit = enable; + break; + case EP_DATA_SEQ_1: + ep_regs[ep_idx].ep_ctrl.fields.outdata_sequence_bit = enable; + break; + case EP_DATA_SEQ_TOGGLE: + if (!enable) { break; } - } else if (ctrl == EXT_EP_READY) { - reg_idx = (ep_idx - 4) >> 1; - mask = 1 << (ext_ep_bit_shift[ep_idx - 4]); - it82xx2_epn_ext_ctrl_cfg2(reg_idx, mask, true); - } else { - LOG_ERR("Invalid Control Code of Endpoint"); + if (ep_regs[ep_idx].ep_ctrl.fields.outdata_sequence_bit) { + ep_regs[ep_idx].ep_ctrl.fields.outdata_sequence_bit = 0; + } else { + ep_regs[ep_idx].ep_ctrl.fields.outdata_sequence_bit = 1; + } + break; + default: + LOG_ERR("Unknown control type 0x%x", ctrl); return -EINVAL; } - return 0; } +static int it82xx2_usb_set_ep_ctrl(uint8_t ep, enum it82xx2_ep_ctrl ctrl, bool enable) +{ + uint8_t ep_idx = USB_EP_GET_IDX(ep); + int ret = 0; + + if (IT8XXX2_IS_EXTEND_ENDPOINT(ep_idx)) { + ret = it82xx2_usb_extend_ep_ctrl(ep, ctrl, enable); + } else { + ret = it82xx2_usb_ep_ctrl(ep, ctrl, enable); + } + return ret; +} + static int it82xx2_usb_dc_ip_init(void) { struct usb_it82xx2_regs *const usb_regs = @@ -551,7 +547,7 @@ static inline void it82xx2_handler_setup(uint8_t fifo_idx, uint8_t ep_ctrl) /* wrong trans */ if (ep_ctrl & EP_SEND_STALL) { - ep_regs[fifo_idx].ep_ctrl &= ~EP_SEND_STALL; + ep_regs[fifo_idx].ep_ctrl.fields.send_stall_bit = 0; udata0.st_state = STALL_SEND; ff_regs[fifo_idx].ep_rx_fifo_ctrl = FIFO_FORCE_EMPTY; LOG_DBG("Clear Stall Bit & RX FIFO"); @@ -580,12 +576,12 @@ static inline void it82xx2_handler_setup(uint8_t fifo_idx, uint8_t ep_ctrl) udata0.now_token = SETUP_TOKEN; udata0.st_state = SETUP_ST; - ep_regs[fifo_idx].ep_ctrl |= EP_OUTDATA_SEQ; + ep_regs[fifo_idx].ep_ctrl.fields.outdata_sequence_bit = 1; udata0.ep_data[ep_idx].cb_out(ep_idx | USB_EP_DIR_OUT, USB_DC_EP_SETUP); /* Set ready bit to no-data control in */ if (udata0.no_data_ctrl) { - ep_regs[fifo_idx].ep_ctrl |= ENDPOINT_RDY; + ep_regs[fifo_idx].ep_ctrl.fields.ready_bit = 1; udata0.no_data_ctrl = false; } } @@ -612,7 +608,7 @@ static inline void it82xx2_handler_in(uint8_t fifo_idx, uint8_t ep_ctrl) } else { ep_idx = 0; if (ep_ctrl & EP_SEND_STALL) { - ep_regs[0].ep_ctrl &= ~EP_SEND_STALL; + ep_regs[fifo_idx].ep_ctrl.fields.send_stall_bit = 0; udata0.st_state = STALL_SEND; LOG_DBG("Clear Stall Bit"); return; @@ -625,7 +621,8 @@ static inline void it82xx2_handler_in(uint8_t fifo_idx, uint8_t ep_ctrl) udata0.last_token = udata0.now_token; udata0.now_token = IN_TOKEN; - if (udata0.addr != DC_ADDR_NULL && udata0.addr != usb_regs->dc_address) { + if (udata0.addr != DC_ADDR_NULL && + udata0.addr != usb_regs->dc_address) { usb_regs->dc_address = udata0.addr; LOG_DBG("Address Is Set Successfully"); } @@ -633,7 +630,9 @@ static inline void it82xx2_handler_in(uint8_t fifo_idx, uint8_t ep_ctrl) if (udata0.st_state == DOUT_ST) { /* setup -> out(data) -> in(status) */ udata0.st_state = STATUS_ST; - } else if (udata0.ep_data[0].remaining == 0 && udata0.st_state == SETUP_ST) { + + } else if (udata0.ep_data[ep_idx].remaining == 0 && + udata0.st_state == SETUP_ST) { /* setup -> in(status) */ udata0.st_state = STATUS_ST; } else { @@ -642,11 +641,7 @@ static inline void it82xx2_handler_in(uint8_t fifo_idx, uint8_t ep_ctrl) } } - if (!!(ep_regs[fifo_idx].ep_ctrl & EP_OUTDATA_SEQ)) { - ep_regs[fifo_idx].ep_ctrl &= ~EP_OUTDATA_SEQ; - } else { - ep_regs[fifo_idx].ep_ctrl |= EP_OUTDATA_SEQ; - } + it82xx2_usb_set_ep_ctrl(ep_idx, EP_DATA_SEQ_TOGGLE, true); if (udata0.ep_data[ep_idx].cb_in) { udata0.ep_data[ep_idx].cb_in(ep_idx | USB_EP_DIR_IN, USB_DC_EP_DATA_IN); @@ -656,7 +651,7 @@ static inline void it82xx2_handler_in(uint8_t fifo_idx, uint8_t ep_ctrl) k_sem_give(&udata0.fifo_sem[fifo_idx - 1]); } else { if (udata0.st_state == DIN_ST && udata0.ep_data[ep_idx].remaining == 0) { - ep_regs[fifo_idx].ep_ctrl |= ENDPOINT_RDY; + ep_regs[fifo_idx].ep_ctrl.fields.ready_bit = 1; } } } @@ -709,11 +704,11 @@ static inline void it82xx2_handler_out(uint8_t fifo_idx) udata0.last_token = udata0.now_token; udata0.now_token = SETUP_TOKEN; udata0.st_state = SETUP_ST; - ep_regs[fifo_idx].ep_ctrl |= EP_OUTDATA_SEQ; + ep_regs[fifo_idx].ep_ctrl.fields.outdata_sequence_bit = 1; udata0.ep_data[ep_idx].cb_out(ep_idx | USB_EP_DIR_OUT, USB_DC_EP_SETUP); if (udata0.no_data_ctrl) { - ep_regs[fifo_idx].ep_ctrl |= ENDPOINT_RDY; + ep_regs[fifo_idx].ep_ctrl.fields.ready_bit = 1; udata0.no_data_ctrl = false; } } @@ -727,7 +722,7 @@ static void it82xx2_usb_dc_trans_done(void) struct it82xx2_usb_ep_regs *ep_regs = usb_regs->usb_ep_regs; for (uint8_t fifo_idx = 0; fifo_idx < 4; fifo_idx++) { - uint8_t ep_ctrl = ep_regs[fifo_idx].ep_ctrl; + uint8_t ep_ctrl = ep_regs[fifo_idx].ep_ctrl.value; /* check ready bit ,will be 0 when trans done */ if ((ep_ctrl & ENDPOINT_EN) && !(ep_ctrl & ENDPOINT_RDY)) { @@ -912,7 +907,7 @@ int usb_dc_reset(void) } } - ep_regs[EP0].ep_ctrl = ENDPOINT_EN; + ep_regs[0].ep_ctrl.value = ENDPOINT_EN; usb_regs->dc_address = DC_ADDR_NULL; udata0.addr = DC_ADDR_NULL; usb_regs->dc_interrupt_status = DC_NAK_SENT_INT | DC_SOF_RECEIVED; @@ -978,10 +973,6 @@ int usb_dc_ep_check_cap(const struct usb_dc_ep_cfg_data * const cfg) int usb_dc_ep_configure(const struct usb_dc_ep_cfg_data *const cfg) { - struct usb_it82xx2_regs *const usb_regs = - (struct usb_it82xx2_regs *)it82xx2_get_usb_regs(); - struct it82xx2_usb_ep_regs *ep_regs = usb_regs->usb_ep_regs; - uint8_t ep_idx = USB_EP_GET_IDX(cfg->ep_addr); bool in = USB_EP_DIR_IS_IN(cfg->ep_addr); @@ -1005,56 +996,31 @@ int usb_dc_ep_configure(const struct usb_dc_ep_cfg_data *const cfg) return 0; } - if (!IT8XXX2_IS_EXTEND_ENDPOINT(ep_idx)) { - (in) ? (ep_regs[ep_idx].ep_ctrl |= EP_DIRECTION) : - (ep_regs[ep_idx].ep_ctrl &= ~EP_DIRECTION); + it82xx2_usb_set_ep_ctrl(ep_idx, EP_IN_DIRECTION_SET, in); - } else { - - (in) ? (it82xx2_usb_extend_ep_ctrl(ep_idx, EXT_EP_DIR_IN)) : - (it82xx2_usb_extend_ep_ctrl(ep_idx, EXT_EP_DIR_OUT)); - - if (in) { - it82xx2_usb_extend_ep_ctrl(ep_idx, EXT_EP_DATA_SEQ_0); + if (in) { + if (IT8XXX2_IS_EXTEND_ENDPOINT(ep_idx)) { + it82xx2_usb_extend_ep_ctrl(ep_idx, EP_DATA_SEQ_1, false); } - - LOG_DBG("ep_status %d", udata0.ep_data[ep_idx].ep_status); - } - - (in) ? (udata0.ep_data[ep_idx].ep_status = EP_CONFIG_IN) : - (udata0.ep_data[ep_idx].ep_status = EP_CONFIG_OUT); - - if (!in) { + udata0.ep_data[ep_idx].ep_status = EP_CONFIG_IN; + } else { + udata0.ep_data[ep_idx].ep_status = EP_CONFIG_OUT; it82xx2_usb_fifo_ctrl(cfg->ep_addr); } switch (cfg->ep_type) { - case USB_DC_EP_CONTROL: return -EINVAL; - case USB_DC_EP_ISOCHRONOUS: - if (!IT8XXX2_IS_EXTEND_ENDPOINT(ep_idx)) { - ep_regs[ep_idx].ep_ctrl |= EP_ISO_ENABLE; - } else { - it82xx2_usb_extend_ep_ctrl(ep_idx, EXT_EP_ISO_ENABLE); - } - + it82xx2_usb_set_ep_ctrl(ep_idx, EP_IOS_ENABLE, true); break; - case USB_DC_EP_BULK: __fallthrough; case USB_DC_EP_INTERRUPT: __fallthrough; default: - if (!IT8XXX2_IS_EXTEND_ENDPOINT(ep_idx)) { - ep_regs[ep_idx].ep_ctrl &= ~EP_ISO_ENABLE; - } else { - it82xx2_usb_extend_ep_ctrl(ep_idx, EXT_EP_ISO_DISABLE); - } - + it82xx2_usb_set_ep_ctrl(ep_idx, EP_IOS_ENABLE, false); break; - } udata0.ep_data[ep_idx].ep_type = cfg->ep_type; @@ -1091,24 +1057,23 @@ int usb_dc_ep_set_callback(const uint8_t ep, const usb_dc_ep_callback cb) int usb_dc_ep_enable(const uint8_t ep) { - struct usb_it82xx2_regs *const usb_regs = - (struct usb_it82xx2_regs *)it82xx2_get_usb_regs(); - struct it82xx2_usb_ep_regs *ep_regs = usb_regs->usb_ep_regs; - uint8_t ep_idx = USB_EP_GET_IDX(ep); + int ret = 0; if (!udata0.attached || ep_idx >= MAX_NUM_ENDPOINTS) { LOG_ERR("Not attached / Invalid endpoint: EP 0x%x", ep_idx); return -EINVAL; } - if (!IT8XXX2_IS_EXTEND_ENDPOINT(ep_idx)) { - ep_regs[ep_idx].ep_ctrl |= ENDPOINT_EN; - } else { + if (IT8XXX2_IS_EXTEND_ENDPOINT(ep_idx)) { uint8_t ep_fifo = ep_fifo_res[ep_idx % FIFO_NUM]; - ep_regs[ep_fifo].ep_ctrl |= ENDPOINT_EN; - it82xx2_usb_extend_ep_ctrl(ep_idx, EXT_EP_ENABLE); + it82xx2_usb_set_ep_ctrl(ep_fifo, EP_ENABLE, true); + } + + ret = it82xx2_usb_set_ep_ctrl(ep_idx, EP_ENABLE, true); + if (ret < 0) { + return ret; } LOG_DBG("Endpoint 0x%02x is enabled", ep); @@ -1118,10 +1083,6 @@ int usb_dc_ep_enable(const uint8_t ep) int usb_dc_ep_disable(uint8_t ep) { - struct usb_it82xx2_regs *const usb_regs = - (struct usb_it82xx2_regs *)it82xx2_get_usb_regs(); - struct it82xx2_usb_ep_regs *ep_regs = usb_regs->usb_ep_regs; - uint8_t ep_idx = USB_EP_GET_IDX(ep); if (!udata0.attached || ep_idx >= MAX_NUM_ENDPOINTS) { @@ -1129,13 +1090,7 @@ int usb_dc_ep_disable(uint8_t ep) return -EINVAL; } - if (!IT8XXX2_IS_EXTEND_ENDPOINT(ep_idx)) { - ep_regs[ep_idx].ep_ctrl &= ~ENDPOINT_EN; - } else { - it82xx2_usb_extend_ep_ctrl(ep_idx, EXT_EP_DISABLE); - } - - return 0; + return it82xx2_usb_set_ep_ctrl(ep_idx, EP_ENABLE, false); } @@ -1152,32 +1107,29 @@ int usb_dc_ep_set_stall(const uint8_t ep) return -EINVAL; } - if (!IT8XXX2_IS_EXTEND_ENDPOINT(ep_idx)) { - ep_regs[ep_idx].ep_ctrl |= EP_SEND_STALL; - } else { - it82xx2_usb_extend_ep_ctrl(ep_idx, EXT_EP_SEND_STALL); - } + it82xx2_usb_set_ep_ctrl(ep_idx, EP_STALL_SEND, true); - if (ep_idx == EP0) { - ep_regs[EP0].ep_ctrl |= ENDPOINT_RDY; + if (ep_idx == 0) { uint32_t idx = 0; + + ep_regs[ep_idx].ep_ctrl.fields.ready_bit = 1; /* polling if stall send for 3ms */ while (idx < 198 && - !(ep_regs[EP0].ep_status & DC_STALL_SENT)) { + !(ep_regs[ep_idx].ep_status & DC_STALL_SENT)) { /* wait 15.15us */ gctrl_regs->GCTRL_WNCKR = 0; idx++; } if (idx < 198) { - ep_regs[EP0].ep_ctrl &= ~EP_SEND_STALL; + ep_regs[ep_idx].ep_ctrl.fields.send_stall_bit = 0; } udata0.no_data_ctrl = false; udata0.st_state = STALL_SEND; } - LOG_DBG("EP(%d) ctrl: 0x%02x", ep_idx, ep_regs[ep_idx].ep_ctrl); + LOG_DBG("EP(%d) ctrl: 0x%02x", ep_idx, ep_regs[ep_idx].ep_ctrl.value); LOG_DBG("EP(%d) Set Stall", ep_idx); return 0; @@ -1185,17 +1137,13 @@ int usb_dc_ep_set_stall(const uint8_t ep) int usb_dc_ep_clear_stall(const uint8_t ep) { - struct usb_it82xx2_regs *const usb_regs = - (struct usb_it82xx2_regs *)it82xx2_get_usb_regs(); - struct it82xx2_usb_ep_regs *ep_regs = usb_regs->usb_ep_regs; - uint8_t ep_idx = USB_EP_GET_IDX(ep); if (ep_idx >= MAX_NUM_ENDPOINTS) { return -EINVAL; } - ep_regs[ep_idx].ep_ctrl &= ~EP_SEND_STALL; + it82xx2_usb_set_ep_ctrl(ep_idx, EP_STALL_SEND, false); LOG_DBG("EP(%d) clear stall", ep_idx); return 0; @@ -1203,23 +1151,13 @@ int usb_dc_ep_clear_stall(const uint8_t ep) int usb_dc_ep_is_stalled(const uint8_t ep, uint8_t *stalled) { - struct usb_it82xx2_regs *const usb_regs = - (struct usb_it82xx2_regs *)it82xx2_get_usb_regs(); - struct it82xx2_usb_ep_regs *ep_regs = usb_regs->usb_ep_regs; - uint8_t ep_idx = USB_EP_GET_IDX(ep); if ((!stalled) || (ep_idx >= MAX_NUM_ENDPOINTS)) { return -EINVAL; } - if (!IT8XXX2_IS_EXTEND_ENDPOINT(ep_idx)) { - *stalled = - (0 != (ep_regs[ep_idx].ep_ctrl & EP_SEND_STALL)); - } else { - *stalled = it82xx2_usb_extend_ep_ctrl(ep_idx, - EXT_EP_CHECK_STALL); - } + *stalled = it82xx2_usb_set_ep_ctrl(ep_idx, EP_STALL_CHECK, true); return 0; } @@ -1304,10 +1242,10 @@ int usb_dc_ep_write(uint8_t ep, const uint8_t *buf, } if (IT8XXX2_IS_EXTEND_ENDPOINT(ep_idx)) { - it82xx2_usb_extend_ep_ctrl(ep_idx, EXT_EP_READY); + it82xx2_usb_extend_ep_ctrl(ep_idx, EP_READY_ENABLE, true); } - ep_regs[ep_fifo].ep_ctrl |= ENDPOINT_RDY; + ep_regs[ep_fifo].ep_ctrl.fields.ready_bit = 1; if (ep_fifo > EP0) { udata0.fifo_ready[ep_fifo - 1] = true; @@ -1344,7 +1282,7 @@ int usb_dc_ep_read(uint8_t ep, uint8_t *buf, uint32_t max_data_len, *read_bytes = 0; if (ep_idx > 0) { - ep_regs[ep_idx].ep_ctrl |= ENDPOINT_RDY; + ep_regs[ep_idx].ep_ctrl.fields.ready_bit = 1; } return 0; @@ -1396,8 +1334,10 @@ int usb_dc_ep_read(uint8_t ep, uint8_t *buf, uint32_t max_data_len, } if (ep_fifo > EP0) { - ep_regs[ep_fifo].ep_ctrl |= ENDPOINT_RDY; - it82xx2_usb_extend_ep_ctrl(ep_idx, EXT_EP_READY); + ep_regs[ep_fifo].ep_ctrl.fields.ready_bit = 1; + if (IT8XXX2_IS_EXTEND_ENDPOINT(ep_idx)) { + it82xx2_usb_extend_ep_ctrl(ep_idx, EP_READY_ENABLE, true); + } udata0.fifo_ready[ep_fifo - 1] = true; } else if (udata0.now_token == SETUP_TOKEN) { if (!(buf[0] & USB_EP_DIR_MASK)) { @@ -1405,7 +1345,8 @@ int usb_dc_ep_read(uint8_t ep, uint8_t *buf, uint32_t max_data_len, ff_regs[0].ep_tx_fifo_ctrl = FIFO_FORCE_EMPTY; if (buf[6] != 0 || buf[7] != 0) { /* set status IN after data OUT */ - ep_regs[0].ep_ctrl |= ENDPOINT_RDY | EP_OUTDATA_SEQ; + ep_regs[0].ep_ctrl.fields.outdata_sequence_bit = 1; + ep_regs[0].ep_ctrl.fields.ready_bit = 1; } else { /* no_data_ctrl status */ udata0.no_data_ctrl = true; @@ -1479,8 +1420,10 @@ int usb_dc_ep_read_continue(uint8_t ep) return -EINVAL; } - it82xx2_usb_extend_ep_ctrl(ep_idx, EXT_EP_READY); - ep_regs[ep_fifo].ep_ctrl |= ENDPOINT_RDY; + if (IT8XXX2_IS_EXTEND_ENDPOINT(ep_idx)) { + it82xx2_usb_extend_ep_ctrl(ep_idx, EP_READY_ENABLE, true); + } + ep_regs[ep_fifo].ep_ctrl.fields.ready_bit = 1; udata0.fifo_ready[ep_fifo - 1] = true; LOG_DBG("EP(%d) Read Continue", ep_idx); return 0; diff --git a/soc/riscv/riscv-ite/common/chip_chipregs.h b/soc/riscv/riscv-ite/common/chip_chipregs.h index c0ea599568f..14130648435 100644 --- a/soc/riscv/riscv-ite/common/chip_chipregs.h +++ b/soc/riscv/riscv-ite/common/chip_chipregs.h @@ -481,8 +481,21 @@ enum usb_dc_endpoints { MAX_NUM_ENDPOINTS }; +union ep_ctrl_reg { + volatile uint8_t value; + struct { + volatile uint8_t enable_bit: 1; + volatile uint8_t ready_bit: 1; + volatile uint8_t outdata_sequence_bit: 1; + volatile uint8_t send_stall_bit: 1; + volatile uint8_t iso_enable_bit: 1; + volatile uint8_t direction_bit: 1; + volatile uint8_t reserved: 2; + } __packed fields; +} __packed; + struct it82xx2_usb_ep_regs { - volatile uint8_t ep_ctrl; + union ep_ctrl_reg ep_ctrl; volatile uint8_t ep_status; volatile uint8_t ep_transtype_sts; volatile uint8_t ep_nak_transtype_sts; @@ -531,6 +544,20 @@ struct ep_ext_regs_7x { * the EP6 and EP7 share the same one, and the rest EPs are defined in the * same way. */ +union epn0n1_extend_ctrl_reg { + volatile uint8_t value; + struct { + volatile uint8_t epn0_outdata_sequence_bit: 1; + volatile uint8_t epn0_send_stall_bit: 1; + volatile uint8_t epn0_iso_enable_bit: 1; + volatile uint8_t reserved0: 1; + volatile uint8_t epn1_outdata_sequence_bit: 1; + volatile uint8_t epn1_send_stall_bit: 1; + volatile uint8_t epn1_iso_enable_bit: 1; + volatile uint8_t reserved1: 1; + } __packed fields; +} __packed; + struct ep_ext_regs_9x { /* 0x95 Reserved */ volatile uint8_t ep_ext_ctrl_95; @@ -539,7 +566,7 @@ struct ep_ext_regs_9x { /* 0x97 Reserved */ volatile uint8_t ep_ext_ctrl_97; /* 0x98 ~ 0x9D EP45/67/89/1011/1213/1415 Extended Control Registers */ - volatile uint8_t epn0n1_ext_ctrl[6]; + union epn0n1_extend_ctrl_reg epn0n1_ext_ctrl[6]; /* 0x9E Reserved */ volatile uint8_t ep_ext_ctrl_9e; /* 0x9F Reserved */ @@ -602,9 +629,23 @@ struct ep_ext_regs_bx { * We classify them into 4 groups which each of them contains Control 1 and 2 * according to the EP number as follows: */ +union epn_extend_ctrl1_reg { + volatile uint8_t value; + struct { + volatile uint8_t epn0_enable_bit: 1; + volatile uint8_t epn0_direction_bit: 1; + volatile uint8_t epn3_enable_bit: 1; + volatile uint8_t epn3_direction_bit: 1; + volatile uint8_t epn6_enable_bit: 1; + volatile uint8_t epn6_direction_bit: 1; + volatile uint8_t epn9_enable_bit: 1; + volatile uint8_t epn9_direction_bit: 1; + } __packed fields; +} __packed; + struct epn_ext_ctrl_regs { /* 0xD6/0xD8/0xDA/0xDC EPN Extended Control1 Register */ - volatile uint8_t epn_ext_ctrl1; + union epn_extend_ctrl1_reg epn_ext_ctrl1; /* 0xD7/0xD9/0xDB/0xDD EPB Extended Control2 Register */ volatile uint8_t epn_ext_ctrl2; }; From 7d373c7c28c20c10009e93c96481a5dcf41be3ea Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Anders=20Storr=C3=B8?= Date: Wed, 20 Dec 2023 11:02:59 +0100 Subject: [PATCH 1483/3723] Bluetooth: Mesh: Fix broken proxy adv test MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Relaxes test requirements for proxy_adv_multi_subnet_coex to resolve failing test on CI. Signed-off-by: Anders Storrø --- tests/bsim/bluetooth/mesh/src/test_beacon.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/bsim/bluetooth/mesh/src/test_beacon.c b/tests/bsim/bluetooth/mesh/src/test_beacon.c index a4a238f0be1..938b5dc141a 100644 --- a/tests/bsim/bluetooth/mesh/src/test_beacon.c +++ b/tests/bsim/bluetooth/mesh/src/test_beacon.c @@ -2081,7 +2081,7 @@ static void test_rx_proxy_adv_multi_subnet_coex(void) /** Second and third subnet are disabled. Verify that the single * subnet has exclusive access to the adv medium. */ - {.evt_type = BEACON_TYPE_NET_ID, .net_idx = 0, .evt_cnt = 19, + {.evt_type = BEACON_TYPE_NET_ID, .net_idx = 0, .evt_cnt = 18, .time = {.after = PROXY_ADV_MULTI_CHECKPOINT_4, .before = PROXY_ADV_MULTI_CHECKPOINT_END}}, }; From b17b496ec731a0a6812479abe3a2de4f09401732 Mon Sep 17 00:00:00 2001 From: Erwan Gouriou Date: Tue, 19 Dec 2023 09:04:35 +0100 Subject: [PATCH 1484/3723] boards: nucleo_wba52cg: Enable HSI16 clock By default rng source is using HSI16 clock. It has to be enabled on as part of board support. Signed-off-by: Erwan Gouriou --- boards/arm/nucleo_wba52cg/nucleo_wba52cg.dts | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/boards/arm/nucleo_wba52cg/nucleo_wba52cg.dts b/boards/arm/nucleo_wba52cg/nucleo_wba52cg.dts index 755454fcff3..67bc009bd8a 100644 --- a/boards/arm/nucleo_wba52cg/nucleo_wba52cg.dts +++ b/boards/arm/nucleo_wba52cg/nucleo_wba52cg.dts @@ -59,6 +59,10 @@ status = "okay"; }; +&clk_hsi { + status = "okay"; +}; + &pll1 { div-m = <8>; mul-n = <48>; From 12c51f8937e78d18edddb3d9604cbf2e7750a3f7 Mon Sep 17 00:00:00 2001 From: William Leara Date: Tue, 19 Dec 2023 16:30:00 -0600 Subject: [PATCH 1485/3723] style: fix misspelling in "precededs" Should be "precedes". Signed-off-by: William Leara --- arch/arc/core/fault.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/arch/arc/core/fault.c b/arch/arc/core/fault.c index caa12326b9d..8034f5673d4 100644 --- a/arch/arc/core/fault.c +++ b/arch/arc/core/fault.c @@ -69,7 +69,7 @@ static bool z_check_thread_stack_fail(const uint32_t fault_addr, uint32_t sp) * "guard" installed in this case, instead what's * happening is that the stack pointer is crashing * into the privilege mode stack buffer which - * immediately precededs it. + * immediately precedes it. */ guard_end = thread->stack_info.start; guard_start = (uint32_t)thread->stack_obj; From a4356da48427cdcb16ad7ed592cb4e0e4a60d5e8 Mon Sep 17 00:00:00 2001 From: Anas Nashif Date: Fri, 15 Dec 2023 06:33:12 -0500 Subject: [PATCH 1486/3723] ci: version_mgr: minor cleanups - store downloaded version file in a temporary file. - list weekly builds Signed-off-by: Anas Nashif --- scripts/ci/version_mgr.py | 20 +++++++++++++------- 1 file changed, 13 insertions(+), 7 deletions(-) diff --git a/scripts/ci/version_mgr.py b/scripts/ci/version_mgr.py index 3957595d351..b800f36b42b 100755 --- a/scripts/ci/version_mgr.py +++ b/scripts/ci/version_mgr.py @@ -1,5 +1,5 @@ #!/usr/bin/env python3 -# Copyright (c) 2020 Intel Corp. +# Copyright (c) 2020-2023 Intel Corp. # SPDX-License-Identifier: Apache-2.0 """ @@ -16,6 +16,7 @@ import argparse import urllib.request import os +import tempfile from git import Git from datetime import datetime @@ -34,6 +35,8 @@ def parse_args(): help="Get latest published version") parser.add_argument('-w', '--weekly', action="store_true", help="Mark as weekly") + parser.add_argument('-W', '--list-weekly', action="store_true", + help="List weekly commits") parser.add_argument('-v', '--verbose', action="store_true", help="Verbose output") return parser.parse_args() @@ -41,12 +44,12 @@ def parse_args(): def get_versions(): data = None + fo = tempfile.NamedTemporaryFile() if not os.path.exists('versions.json'): url = 'https://testing.zephyrproject.org/daily_tests/versions.json' - urllib.request.urlretrieve(url, 'versions.json') - with open("versions.json", "r") as fp: + urllib.request.urlretrieve(url, fo.name) + with open(fo.name, "r") as fp: data = json.load(fp) - return data def handle_compat(item): @@ -60,11 +63,13 @@ def handle_compat(item): return item_compat -def show_versions(): +def show_versions(weekly=False): data = get_versions() for item in data: item_compat = handle_compat(item) is_weekly = item_compat.get('weekly', False) + if weekly and not is_weekly: + continue wstr = "" datestr = "" if args.verbose: @@ -79,6 +84,7 @@ def show_versions(): print(f"{item_compat['version']}") + def show_latest(): data = get_versions() latest = data[-1] @@ -134,8 +140,8 @@ def main(): args = parse_args() if args.update: update(args.update, args.weekly) - elif args.list: - show_versions() + elif args.list or args.list_weekly: + show_versions(weekly=args.list_weekly) elif args.latest: show_latest() else: From 01568b573a93bf55ecd7da62ce1cab08746c9392 Mon Sep 17 00:00:00 2001 From: Seppo Takalo Date: Mon, 18 Dec 2023 13:37:33 +0200 Subject: [PATCH 1487/3723] net: coap: Add API to count number of pending requests Add coap_pendings_count() that return number of waiting requests on the pendings array. Signed-off-by: Seppo Takalo --- include/zephyr/net/coap.h | 9 +++++++++ subsys/net/lib/coap/coap.c | 13 +++++++++++++ 2 files changed, 22 insertions(+) diff --git a/include/zephyr/net/coap.h b/include/zephyr/net/coap.h index e303d5c8ad3..cd57c560bee 100644 --- a/include/zephyr/net/coap.h +++ b/include/zephyr/net/coap.h @@ -1112,6 +1112,15 @@ void coap_pending_clear(struct coap_pending *pending); */ void coap_pendings_clear(struct coap_pending *pendings, size_t len); +/** + * @brief Count number of pending requests. + * + * @param len Number of elements in array. + * @param pendings Array of pending requests. + * @return count of elements where timeout is not zero. + */ +size_t coap_pendings_count(struct coap_pending *pendings, size_t len); + /** * @brief Cancels awaiting for this reply, so it becomes available * again. User responsibility to free the memory associated with data. diff --git a/subsys/net/lib/coap/coap.c b/subsys/net/lib/coap/coap.c index bfb643a8e8c..d22ee29bea7 100644 --- a/subsys/net/lib/coap/coap.c +++ b/subsys/net/lib/coap/coap.c @@ -1734,6 +1734,19 @@ void coap_pendings_clear(struct coap_pending *pendings, size_t len) } } +size_t coap_pendings_count(struct coap_pending *pendings, size_t len) +{ + struct coap_pending *p = pendings; + size_t c = 0; + + for (size_t i = 0; i < len && p; i++, p++) { + if (p->timeout) { + c++; + } + } + return c; +} + /* Reordering according to RFC7641 section 3.4 but without timestamp comparison */ static inline bool is_newer(int v1, int v2) { From 0d650ffd2626e522a64d08525f62fdac75298c2c Mon Sep 17 00:00:00 2001 From: Seppo Takalo Date: Mon, 18 Dec 2023 13:43:03 +0200 Subject: [PATCH 1488/3723] net: lwm2m: Update TX timestamp on zsock_send() In slow networks, like Nb-IOT, when using queue mode, there might be significant delay between the time we put the packet into a transmission queue and the time we actually start transmitting. This might cause QUEUE_RX_OFF state to be triggered earlier than expected. Remedy the issue by updating the timestamp on the moment where packet is accepted by zsock_send(). Signed-off-by: Seppo Takalo --- subsys/net/lib/lwm2m/lwm2m_engine.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/subsys/net/lib/lwm2m/lwm2m_engine.c b/subsys/net/lib/lwm2m/lwm2m_engine.c index 959d07419d3..85a428eeb5d 100644 --- a/subsys/net/lib/lwm2m/lwm2m_engine.c +++ b/subsys/net/lib/lwm2m/lwm2m_engine.c @@ -684,6 +684,8 @@ static int socket_send_message(struct lwm2m_ctx *client_ctx) if (rc < 0) { LOG_ERR("Failed to send packet, err %d", errno); rc = -errno; + } else { + engine_update_tx_time(); } if (msg->type != COAP_TYPE_CON) { From 6161fbdf21fe5f567b5828c54f84c5e3405fca71 Mon Sep 17 00:00:00 2001 From: Seppo Takalo Date: Thu, 9 Nov 2023 11:59:09 +0200 Subject: [PATCH 1489/3723] net: lwm2m: Transmission state indications Allow engine to give hints about ongoing CoAP transmissions. This information can be used to control various power saving modes for network interfaces. For example cellular networks might support release assist indicator. Signed-off-by: Seppo Takalo --- include/zephyr/net/lwm2m.h | 24 +++++++ samples/net/lwm2m_client/overlay-queue.conf | 2 + samples/net/lwm2m_client/src/lwm2m-client.c | 20 ++++++ subsys/net/lib/lwm2m/lwm2m_engine.c | 35 +++++++++- tests/net/lib/lwm2m/lwm2m_engine/src/main.c | 72 +++++++++++++++++++- tests/net/lib/lwm2m/lwm2m_engine/src/stubs.c | 2 + tests/net/lib/lwm2m/lwm2m_engine/src/stubs.h | 4 ++ 7 files changed, 155 insertions(+), 4 deletions(-) diff --git a/include/zephyr/net/lwm2m.h b/include/zephyr/net/lwm2m.h index 51324f63153..3fca8bffae3 100644 --- a/include/zephyr/net/lwm2m.h +++ b/include/zephyr/net/lwm2m.h @@ -134,6 +134,22 @@ typedef void (*lwm2m_ctx_event_cb_t)(struct lwm2m_ctx *ctx, enum lwm2m_rd_client_event event); +/** + * @brief Different traffic states of the LwM2M socket. + * + * This information can be used to give hints for the network interface + * that can decide what kind of power management should be used. + * + * These hints are given from CoAP layer messages, so usage of DTLS might affect the + * actual number of expected datagrams. + */ +enum lwm2m_socket_states { + LWM2M_SOCKET_STATE_ONGOING, /**< Ongoing traffic is expected. */ + LWM2M_SOCKET_STATE_ONE_RESPONSE, /**< One response is expected for the next message. */ + LWM2M_SOCKET_STATE_LAST, /**< Next message is the last one. */ + LWM2M_SOCKET_STATE_NO_DATA, /**< No more data is expected. */ +}; + /** * @brief LwM2M context structure to maintain information for a single * LwM2M connection. @@ -249,6 +265,14 @@ struct lwm2m_ctx { * copied into the actual resource buffer. */ uint8_t validate_buf[CONFIG_LWM2M_ENGINE_VALIDATION_BUFFER_SIZE]; + + /** + * Callback to indicate transmission states. + * Client application may request LwM2M engine to indicate hints about + * transmission states and use that information to control various power + * saving modes. + */ + void (*set_socket_state)(int fd, enum lwm2m_socket_states state); }; /** diff --git a/samples/net/lwm2m_client/overlay-queue.conf b/samples/net/lwm2m_client/overlay-queue.conf index 1adc9eda5ec..946c0fbab67 100644 --- a/samples/net/lwm2m_client/overlay-queue.conf +++ b/samples/net/lwm2m_client/overlay-queue.conf @@ -1,5 +1,7 @@ CONFIG_LWM2M_QUEUE_MODE_ENABLED=y CONFIG_LWM2M_QUEUE_MODE_UPTIME=20 +CONFIG_LWM2M_RD_CLIENT_STOP_POLLING_AT_IDLE=y + # Default lifetime is 1 day CONFIG_LWM2M_ENGINE_DEFAULT_LIFETIME=86400 # Send update once an hour diff --git a/samples/net/lwm2m_client/src/lwm2m-client.c b/samples/net/lwm2m_client/src/lwm2m-client.c index c610f1ad8dd..2e9792e51ea 100644 --- a/samples/net/lwm2m_client/src/lwm2m-client.c +++ b/samples/net/lwm2m_client/src/lwm2m-client.c @@ -253,6 +253,25 @@ static void rd_client_event(struct lwm2m_ctx *client, } } +static void socket_state(int fd, enum lwm2m_socket_states state) +{ + (void) fd; + switch (state) { + case LWM2M_SOCKET_STATE_ONGOING: + LOG_DBG("LWM2M_SOCKET_STATE_ONGOING"); + break; + case LWM2M_SOCKET_STATE_ONE_RESPONSE: + LOG_DBG("LWM2M_SOCKET_STATE_ONE_RESPONSE"); + break; + case LWM2M_SOCKET_STATE_LAST: + LOG_DBG("LWM2M_SOCKET_STATE_LAST"); + break; + case LWM2M_SOCKET_STATE_NO_DATA: + LOG_DBG("LWM2M_SOCKET_STATE_NO_DATA"); + break; + } +} + static void observe_cb(enum lwm2m_observe_event event, struct lwm2m_obj_path *path, void *user_data) { @@ -367,6 +386,7 @@ int main(void) #if defined(CONFIG_LWM2M_DTLS_SUPPORT) client_ctx.tls_tag = CONFIG_LWM2M_APP_TLS_TAG; #endif + client_ctx.set_socket_state = socket_state; /* client_ctx.sec_obj_inst is 0 as a starting point */ lwm2m_rd_client_start(&client_ctx, endpoint, flags, rd_client_event, observe_cb); diff --git a/subsys/net/lib/lwm2m/lwm2m_engine.c b/subsys/net/lib/lwm2m/lwm2m_engine.c index 85a428eeb5d..d5a289a111f 100644 --- a/subsys/net/lib/lwm2m/lwm2m_engine.c +++ b/subsys/net/lib/lwm2m/lwm2m_engine.c @@ -197,6 +197,11 @@ int lwm2m_socket_suspend(struct lwm2m_ctx *client_ctx) lwm2m_close_socket(client_ctx); /* store back the socket handle */ client_ctx->sock_fd = socket_temp_id; + + if (client_ctx->set_socket_state) { + client_ctx->set_socket_state(client_ctx->sock_fd, + LWM2M_SOCKET_STATE_NO_DATA); + } } return ret; @@ -659,10 +664,10 @@ static int socket_recv_message(struct lwm2m_ctx *client_ctx) return 0; } -static int socket_send_message(struct lwm2m_ctx *client_ctx) +static int socket_send_message(struct lwm2m_ctx *ctx) { int rc; - sys_snode_t *msg_node = sys_slist_get(&client_ctx->pending_sends); + sys_snode_t *msg_node = sys_slist_get(&ctx->pending_sends); struct lwm2m_message *msg; if (!msg_node) { @@ -679,6 +684,32 @@ static int socket_send_message(struct lwm2m_ctx *client_ctx) coap_pending_cycle(msg->pending); } + if (ctx->set_socket_state) { +#if defined(CONFIG_LWM2M_QUEUE_MODE_ENABLED) + bool empty = sys_slist_is_empty(&ctx->pending_sends) && + sys_slist_is_empty(&ctx->queued_messages); +#else + bool empty = sys_slist_is_empty(&ctx->pending_sends); +#endif + if (coap_pendings_count(ctx->pendings, ARRAY_SIZE(ctx->pendings)) > 1) { + empty = false; + } + + if (!empty) { + ctx->set_socket_state(ctx->sock_fd, LWM2M_SOCKET_STATE_ONGOING); + } else { + switch (msg->type) { + case COAP_TYPE_CON: + ctx->set_socket_state(ctx->sock_fd, + LWM2M_SOCKET_STATE_ONE_RESPONSE); + break; + default: + ctx->set_socket_state(ctx->sock_fd, LWM2M_SOCKET_STATE_LAST); + break; + } + } + } + rc = zsock_send(msg->ctx->sock_fd, msg->cpkt.data, msg->cpkt.offset, 0); if (rc < 0) { diff --git a/tests/net/lib/lwm2m/lwm2m_engine/src/main.c b/tests/net/lib/lwm2m/lwm2m_engine/src/main.c index ed26380eccd..5d80f5d1049 100644 --- a/tests/net/lib/lwm2m/lwm2m_engine/src/main.c +++ b/tests/net/lib/lwm2m/lwm2m_engine/src/main.c @@ -13,10 +13,11 @@ #include "lwm2m_rd_client.h" #include "stubs.h" -#if defined(CONFIG_NATIVE_POSIX_SLOWDOWN_TO_REAL_TIME) +#if defined(CONFIG_NATIVE_SIM_SLOWDOWN_TO_REAL_TIME) #include "timer_model.h" #endif +#define LOG_LEVEL LOG_LEVEL_DBG LOG_MODULE_REGISTER(lwm2m_engine_test); DEFINE_FFF_GLOBALS; @@ -67,7 +68,7 @@ static void test_service(struct k_work *work) static void setup(void *data) { -#if defined(CONFIG_NATIVE_POSIX_SLOWDOWN_TO_REAL_TIME) +#if defined(CONFIG_NATIVE_SIM_SLOWDOWN_TO_REAL_TIME) /* It is enough that some slow-down is happening on sleeps, it does not have to be * real time */ @@ -467,3 +468,70 @@ ZTEST(lwm2m_engine, test_security) zassert_equal(tls_credential_add_fake.arg1_history[2], TLS_CREDENTIAL_CA_CERTIFICATE); zassert_equal(lwm2m_engine_stop(&ctx), 0); } + +static enum lwm2m_socket_states last_state; + +static void socket_state(int fd, enum lwm2m_socket_states state) +{ + (void) fd; + last_state = state; +} + +ZTEST(lwm2m_engine, test_socket_state) +{ + int ret; + struct lwm2m_ctx ctx = { + .remote_addr.sa_family = AF_INET, + .sock_fd = -1, + .set_socket_state = socket_state, + }; + struct lwm2m_message msg1 = { + .ctx = &ctx, + .type = COAP_TYPE_CON, + }; + struct lwm2m_message msg2 = msg1; + struct lwm2m_message ack = { + .ctx = &ctx, + .type = COAP_TYPE_ACK, + }; + + sys_slist_init(&ctx.pending_sends); + ret = lwm2m_engine_start(&ctx); + zassert_equal(ret, 0); + + /* One confimable in queue, should cause ONE_RESPONSE status */ + coap_pendings_count_fake.return_val = 1; + sys_slist_append(&ctx.pending_sends, &msg1.node); + set_socket_events(ZSOCK_POLLOUT); + k_sleep(K_MSEC(100)); + zassert_equal(last_state, LWM2M_SOCKET_STATE_ONE_RESPONSE); + + /* More than one messages in queue, not empty, should cause ONGOING */ + coap_pendings_count_fake.return_val = 2; + sys_slist_append(&ctx.pending_sends, &msg1.node); + sys_slist_append(&ctx.pending_sends, &msg2.node); + set_socket_events(ZSOCK_POLLOUT); + k_sleep(K_MSEC(100)); + zassert_equal(last_state, LWM2M_SOCKET_STATE_ONGOING); + + /* Last out, while waiting for ACK to both, should still cause ONGOING */ + coap_pendings_count_fake.return_val = 2; + set_socket_events(ZSOCK_POLLOUT); + k_sleep(K_MSEC(100)); + zassert_equal(last_state, LWM2M_SOCKET_STATE_ONGOING); + + /* Only one Ack transmiting, nothing expected back -> LAST */ + coap_pendings_count_fake.return_val = 0; + sys_slist_append(&ctx.pending_sends, &ack.node); + set_socket_events(ZSOCK_POLLOUT); + k_sleep(K_MSEC(100)); + zassert_equal(last_state, LWM2M_SOCKET_STATE_LAST); + + /* Socket suspended (as in QUEUE_RX_OFF), should cause NO_DATA */ + ret = lwm2m_socket_suspend(&ctx); + zassert_equal(ret, 0); + zassert_equal(last_state, LWM2M_SOCKET_STATE_NO_DATA); + + ret = lwm2m_engine_stop(&ctx); + zassert_equal(ret, 0); +} diff --git a/tests/net/lib/lwm2m/lwm2m_engine/src/stubs.c b/tests/net/lib/lwm2m/lwm2m_engine/src/stubs.c index 5db155f1e29..0958d75a54a 100644 --- a/tests/net/lib/lwm2m/lwm2m_engine/src/stubs.c +++ b/tests/net/lib/lwm2m/lwm2m_engine/src/stubs.c @@ -19,6 +19,7 @@ DEFINE_FAKE_VALUE_FUNC(int, lwm2m_send_message_async, struct lwm2m_message *); DEFINE_FAKE_VOID_FUNC(lwm2m_registry_lock); DEFINE_FAKE_VOID_FUNC(lwm2m_registry_unlock); DEFINE_FAKE_VALUE_FUNC(bool, coap_pending_cycle, struct coap_pending *); +DEFINE_FAKE_VALUE_FUNC(size_t, coap_pendings_count, struct coap_pending *, size_t); DEFINE_FAKE_VALUE_FUNC(int, generate_notify_message, struct lwm2m_ctx *, struct observe_node *, void *); DEFINE_FAKE_VALUE_FUNC(int64_t, engine_observe_shedule_next_event, struct observe_node *, uint16_t, @@ -41,6 +42,7 @@ DEFINE_FAKE_VALUE_FUNC(int, lwm2m_delete_obj_inst, uint16_t, uint16_t); DEFINE_FAKE_VOID_FUNC(lwm2m_clear_block_contexts); DEFINE_FAKE_VALUE_FUNC(int, lwm2m_security_mode, struct lwm2m_ctx *); DEFINE_FAKE_VALUE_FUNC(int, z_impl_zsock_setsockopt, int, int, int, const void *, socklen_t); +DEFINE_FAKE_VOID_FUNC(engine_update_tx_time); static sys_slist_t obs_obj_path_list = SYS_SLIST_STATIC_INIT(&obs_obj_path_list); sys_slist_t *lwm2m_obs_obj_path_list(void) diff --git a/tests/net/lib/lwm2m/lwm2m_engine/src/stubs.h b/tests/net/lib/lwm2m/lwm2m_engine/src/stubs.h index 7b8ca481f85..67c4cde883d 100644 --- a/tests/net/lib/lwm2m/lwm2m_engine/src/stubs.h +++ b/tests/net/lib/lwm2m/lwm2m_engine/src/stubs.h @@ -28,6 +28,7 @@ DECLARE_FAKE_VALUE_FUNC(int, lwm2m_rd_client_resume); DECLARE_FAKE_VALUE_FUNC(struct lwm2m_message *, find_msg, struct coap_pending *, struct coap_reply *); DECLARE_FAKE_VOID_FUNC(coap_pending_clear, struct coap_pending *); +DECLARE_FAKE_VALUE_FUNC(size_t, coap_pendings_count, struct coap_pending *, size_t); DECLARE_FAKE_VOID_FUNC(lwm2m_reset_message, struct lwm2m_message *, bool); DECLARE_FAKE_VALUE_FUNC(int, lwm2m_send_message_async, struct lwm2m_message *); DECLARE_FAKE_VOID_FUNC(lwm2m_registry_lock); @@ -56,6 +57,7 @@ DECLARE_FAKE_VOID_FUNC(lwm2m_clear_block_contexts); DECLARE_FAKE_VALUE_FUNC(int, z_impl_zsock_connect, int, const struct sockaddr *, socklen_t); DECLARE_FAKE_VALUE_FUNC(int, lwm2m_security_mode, struct lwm2m_ctx *); DECLARE_FAKE_VALUE_FUNC(int, z_impl_zsock_setsockopt, int, int, int, const void *, socklen_t); +DECLARE_FAKE_VOID_FUNC(engine_update_tx_time); #define DO_FOREACH_FAKE(FUNC) \ do { \ @@ -63,6 +65,7 @@ DECLARE_FAKE_VALUE_FUNC(int, z_impl_zsock_setsockopt, int, int, int, const void FUNC(lwm2m_rd_client_resume) \ FUNC(find_msg) \ FUNC(coap_pending_clear) \ + FUNC(coap_pendings_count) \ FUNC(lwm2m_reset_message) \ FUNC(lwm2m_send_message_async) \ FUNC(lwm2m_registry_lock) \ @@ -85,6 +88,7 @@ DECLARE_FAKE_VALUE_FUNC(int, z_impl_zsock_setsockopt, int, int, int, const void FUNC(z_impl_zsock_connect) \ FUNC(lwm2m_security_mode) \ FUNC(z_impl_zsock_setsockopt) \ + FUNC(engine_update_tx_time) \ } while (0) #endif /* STUBS_H */ From a6fda002549f0be5fe928d7a6762abd0f262984e Mon Sep 17 00:00:00 2001 From: Anisetti Avinash Krishna Date: Mon, 18 Dec 2023 21:24:02 +0530 Subject: [PATCH 1490/3723] drivers: spi: pw: Fix SPI Receive FIFO set Fixes SPI Receive FIFO register set operation. Signed-off-by: Anisetti Avinash Krishna --- drivers/spi/spi_pw.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/spi/spi_pw.c b/drivers/spi/spi_pw.c index e6f4061c6e2..fa100f054e0 100644 --- a/drivers/spi/spi_pw.c +++ b/drivers/spi/spi_pw.c @@ -208,8 +208,8 @@ static void spi_pw_rx_thld_set(const struct device *dev, /* Rx threshold */ reg_data = spi_pw_reg_read(dev, PW_SPI_REG_SIRF); - reg_data = (uint32_t) ~(PW_SPI_WM_MASK); - reg_data = PW_SPI_SIRF_WM_DFLT; + reg_data &= (uint32_t) ~(PW_SPI_WM_MASK); + reg_data |= PW_SPI_SIRF_WM_DFLT; if (spi->ctx.rx_len && spi->ctx.rx_len < spi->fifo_depth) { reg_data = spi->ctx.rx_len - 1; } From d053b8bf3bc743d42b8b8e4d9119b3e4bb35341b Mon Sep 17 00:00:00 2001 From: Carles Cufi Date: Tue, 19 Dec 2023 16:35:16 +0100 Subject: [PATCH 1491/3723] doc: Rename stable API change to breaking change It is often confusing for users and developers alike to see the sentence "stable API change" in a label or in the release notes. Stable APIs can change in at least two ways (retaining compatibility or not), and so it is preferrable to use a term that clearly describes the change as incompatible, by using the common term "breaking". Signed-off-by: Carles Cufi --- doc/develop/api/api_lifecycle.rst | 23 +++++++++++------------ doc/project/dev_env_and_tools.rst | 8 ++++---- 2 files changed, 15 insertions(+), 16 deletions(-) diff --git a/doc/develop/api/api_lifecycle.rst b/doc/develop/api/api_lifecycle.rst index 8f1f689c12c..b34832655c8 100644 --- a/doc/develop/api/api_lifecycle.rst +++ b/doc/develop/api/api_lifecycle.rst @@ -94,23 +94,23 @@ In order to declare an API ``stable``, the following steps need to be followed: `Zephyr Architecture meeting`_ where, barring any objections, the Pull Request will be merged -.. _stable_api_changes: +.. _breaking_api_changes: -Introducing incompatible changes +Introducing breaking API changes ================================ -A stable API, as described above strives to remain backwards-compatible through +A stable API, as described above, strives to remain backwards-compatible through its life-cycle. There are however cases where fulfilling this objective prevents -technical progress or is simply unfeasible without unreasonable burden on the +technical progress, or is simply unfeasible without unreasonable burden on the maintenance of the API and its implementation(s). -An incompatible change is defined as one that forces users to modify their +A breaking API change is defined as one that forces users to modify their existing code in order to maintain the current behavior of their application. The need for recompilation of applications (without changing the application -itself) is not considered an incompatible change. +itself) is not considered a breaking API change. In order to restrict and control the introduction of a change that breaks the -promise of backwards compatibility the following steps must be followed whenever +promise of backwards compatibility, the following steps must be followed whenever such a change is considered necessary in order to accept it in the project: #. An :ref:`RFC issue ` must be opened on GitHub with the following @@ -118,7 +118,7 @@ such a change is considered necessary in order to accept it in the project: .. code-block:: none - Title: RFC: API Change: + Title: RFC: Breaking API Change: Contents: - Problem Description: - Background information on why the change is required - Proposed Change (detailed): @@ -133,7 +133,7 @@ such a change is considered necessary in order to accept it in the project: Instead of a written description of the changes, the RFC issue may link to a Pull Request containing those changes in code form. -#. The RFC issue must be labeled with the GitHub ``Stable API Change`` label +#. The RFC issue must be labeled with the GitHub ``Breaking API Change`` label #. The RFC issue must be submitted for discussion in the next `Zephyr Architecture meeting`_ #. An email must be sent to the ``devel`` mailing list with a subject identical @@ -164,7 +164,7 @@ The Pull Request must include the following: the corresponding maintainers - An entry in the "API Changes" section of the release notes for the next upcoming release -- The labels ``API``, ``Stable API Change`` and ``Release Notes``, as well as +- The labels ``API``, ``Breaking API Change`` and ``Release Notes``, as well as any others that are applicable Once the steps above have been completed, the outcome of the proposal will @@ -177,8 +177,7 @@ If the Pull Request is merged then an email must be sent to the ``devel`` and .. note:: - Incompatible changes will be announced in the "API Changes" section of the - release notes. + Breaking API changes will be listed and described in the migration guide. Deprecated *********** diff --git a/doc/project/dev_env_and_tools.rst b/doc/project/dev_env_and_tools.rst index 8269e891d43..3d7e5fd4bbd 100644 --- a/doc/project/dev_env_and_tools.rst +++ b/doc/project/dev_env_and_tools.rst @@ -111,7 +111,7 @@ TSC and Working Groups Changes that introduce new features or functionality or change the way the overall system works need to be reviewed by the TSC or the responsible Working -Group. For example for :ref:`stable API changes `, the +Group. For example for :ref:`breaking API changes `, the proposal needs to be presented in the Architecture meeting so that the relevant stakeholders are made aware of the change. @@ -383,10 +383,10 @@ following `TSC meeting`_ if time permits. .. _`TSC meeting`: https://github.com/zephyrproject-rtos/zephyr/wiki/Zephyr-Committee-and-Working-Group-Meetings#technical-steering-committee-tsc -* *Stable API Change* +* *Breaking API Change* -The issue or PR describes a change to a stable API. See additional information -in :ref:`stable_api_changes`. +The issue or PR describes a breaking change to a stable API. See additional information +in :ref:`breaking_api_changes`. * *Bug* From d1f3f863f1453e016d95ff53421a46f03edd1af0 Mon Sep 17 00:00:00 2001 From: Yong Cong Sin Date: Wed, 20 Dec 2023 13:57:35 +0800 Subject: [PATCH 1492/3723] soc/xtensa/intel_adsp: fix interrupts typo Hex should be `0x` instead of `0X` Signed-off-by: Yong Cong Sin --- dts/xtensa/intel/intel_adsp_cavs18.dtsi | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/dts/xtensa/intel/intel_adsp_cavs18.dtsi b/dts/xtensa/intel/intel_adsp_cavs18.dtsi index 4ba04636a47..def86567e75 100644 --- a/dts/xtensa/intel/intel_adsp_cavs18.dtsi +++ b/dts/xtensa/intel/intel_adsp_cavs18.dtsi @@ -140,7 +140,7 @@ reg = <0x78820 0x10>; interrupt-controller; #interrupt-cells = <3>; - interrupts = <0XD 0 0>; + interrupts = <0xD 0 0>; interrupt-parent = <&core_intc>; }; From 2f2ee91947d22c09bccd502e65a8fac132073e2c Mon Sep 17 00:00:00 2001 From: Sylvio Alves Date: Wed, 3 May 2023 09:09:41 -0300 Subject: [PATCH 1493/3723] pinctrl: esp32: move files from hal_espressif to main ESP32 family pinctrl files are currently placed in hal_espressif. Move to main branch as part of pinctrl dt-bindings. Signed-off-by: Sylvio Alves --- .../pinctrl/espressif,esp32-pinctrl.yaml | 2 +- .../dt-bindings/pinctrl/esp32-pinctrl.h | 11363 ++++++++++++++ .../dt-bindings/pinctrl/esp32c3-pinctrl.h | 2224 +++ .../dt-bindings/pinctrl/esp32s2-pinctrl.h | 7587 +++++++++ .../dt-bindings/pinctrl/esp32s3-pinctrl.h | 12661 ++++++++++++++++ west.yml | 2 +- 6 files changed, 33837 insertions(+), 2 deletions(-) create mode 100644 include/zephyr/dt-bindings/pinctrl/esp32-pinctrl.h create mode 100644 include/zephyr/dt-bindings/pinctrl/esp32c3-pinctrl.h create mode 100644 include/zephyr/dt-bindings/pinctrl/esp32s2-pinctrl.h create mode 100644 include/zephyr/dt-bindings/pinctrl/esp32s3-pinctrl.h diff --git a/dts/bindings/pinctrl/espressif,esp32-pinctrl.yaml b/dts/bindings/pinctrl/espressif,esp32-pinctrl.yaml index 79cd24910cf..c55372094ae 100644 --- a/dts/bindings/pinctrl/espressif,esp32-pinctrl.yaml +++ b/dts/bindings/pinctrl/espressif,esp32-pinctrl.yaml @@ -65,7 +65,7 @@ description: | target SoC in the following URL - https://github.com/zephyrproject-rtos/hal_espressif/tree/zephyr/include/dt-bindings/pinctrl + https://github.com/zephyrproject-rtos/zephyr/tree/main/include/zephyr/dt-bindings/pinctrl The ESP-WROVER-KIT board is based on the ESP32 SoC, in that case, we search diff --git a/include/zephyr/dt-bindings/pinctrl/esp32-pinctrl.h b/include/zephyr/dt-bindings/pinctrl/esp32-pinctrl.h new file mode 100644 index 00000000000..b961c27facf --- /dev/null +++ b/include/zephyr/dt-bindings/pinctrl/esp32-pinctrl.h @@ -0,0 +1,11363 @@ +/* + * Copyright (c) 2022 Espressif Systems (Shanghai) Co., Ltd. + * + * SPDX-License-Identifier: Apache-2.0 + * + * NOTE: Autogenerated file using esp_genpinctrl.py + */ + +#ifndef INC_DT_BINDS_PINCTRL_ESP32_PINCTRL_HAL_H_ +#define INC_DT_BINDS_PINCTRL_ESP32_PINCTRL_HAL_H_ + +/* DAC_CH1 */ +#define DAC_CH1_GPIO25 \ + ESP32_PINMUX(25, ESP_NOSIG, ESP_DAC1_OUT) + +/* DAC_CH2 */ +#define DAC_CH2_GPIO26 \ + ESP32_PINMUX(26, ESP_NOSIG, ESP_DAC2_OUT) + +/* I2C0_SCL */ +#define I2C0_SCL_GPIO0 \ + ESP32_PINMUX(0, ESP_I2CEXT0_SCL_IN, ESP_I2CEXT0_SCL_OUT) + +#define I2C0_SCL_GPIO1 \ + ESP32_PINMUX(1, ESP_I2CEXT0_SCL_IN, ESP_I2CEXT0_SCL_OUT) + +#define I2C0_SCL_GPIO2 \ + ESP32_PINMUX(2, ESP_I2CEXT0_SCL_IN, ESP_I2CEXT0_SCL_OUT) + +#define I2C0_SCL_GPIO3 \ + ESP32_PINMUX(3, ESP_I2CEXT0_SCL_IN, ESP_I2CEXT0_SCL_OUT) + +#define I2C0_SCL_GPIO4 \ + ESP32_PINMUX(4, ESP_I2CEXT0_SCL_IN, ESP_I2CEXT0_SCL_OUT) + +#define I2C0_SCL_GPIO5 \ + ESP32_PINMUX(5, ESP_I2CEXT0_SCL_IN, ESP_I2CEXT0_SCL_OUT) + +#define I2C0_SCL_GPIO6 \ + ESP32_PINMUX(6, ESP_I2CEXT0_SCL_IN, ESP_I2CEXT0_SCL_OUT) + +#define I2C0_SCL_GPIO7 \ + ESP32_PINMUX(7, ESP_I2CEXT0_SCL_IN, ESP_I2CEXT0_SCL_OUT) + +#define I2C0_SCL_GPIO8 \ + ESP32_PINMUX(8, ESP_I2CEXT0_SCL_IN, ESP_I2CEXT0_SCL_OUT) + +#define I2C0_SCL_GPIO9 \ + ESP32_PINMUX(9, ESP_I2CEXT0_SCL_IN, ESP_I2CEXT0_SCL_OUT) + +#define I2C0_SCL_GPIO10 \ + ESP32_PINMUX(10, ESP_I2CEXT0_SCL_IN, ESP_I2CEXT0_SCL_OUT) + +#define I2C0_SCL_GPIO11 \ + ESP32_PINMUX(11, ESP_I2CEXT0_SCL_IN, ESP_I2CEXT0_SCL_OUT) + +#define I2C0_SCL_GPIO12 \ + ESP32_PINMUX(12, ESP_I2CEXT0_SCL_IN, ESP_I2CEXT0_SCL_OUT) + +#define I2C0_SCL_GPIO13 \ + ESP32_PINMUX(13, ESP_I2CEXT0_SCL_IN, ESP_I2CEXT0_SCL_OUT) + +#define I2C0_SCL_GPIO14 \ + ESP32_PINMUX(14, ESP_I2CEXT0_SCL_IN, ESP_I2CEXT0_SCL_OUT) + +#define I2C0_SCL_GPIO15 \ + ESP32_PINMUX(15, ESP_I2CEXT0_SCL_IN, ESP_I2CEXT0_SCL_OUT) + +#define I2C0_SCL_GPIO16 \ + ESP32_PINMUX(16, ESP_I2CEXT0_SCL_IN, ESP_I2CEXT0_SCL_OUT) + +#define I2C0_SCL_GPIO17 \ + ESP32_PINMUX(17, ESP_I2CEXT0_SCL_IN, ESP_I2CEXT0_SCL_OUT) + +#define I2C0_SCL_GPIO18 \ + ESP32_PINMUX(18, ESP_I2CEXT0_SCL_IN, ESP_I2CEXT0_SCL_OUT) + +#define I2C0_SCL_GPIO19 \ + ESP32_PINMUX(19, ESP_I2CEXT0_SCL_IN, ESP_I2CEXT0_SCL_OUT) + +#define I2C0_SCL_GPIO20 \ + ESP32_PINMUX(20, ESP_I2CEXT0_SCL_IN, ESP_I2CEXT0_SCL_OUT) + +#define I2C0_SCL_GPIO21 \ + ESP32_PINMUX(21, ESP_I2CEXT0_SCL_IN, ESP_I2CEXT0_SCL_OUT) + +#define I2C0_SCL_GPIO22 \ + ESP32_PINMUX(22, ESP_I2CEXT0_SCL_IN, ESP_I2CEXT0_SCL_OUT) + +#define I2C0_SCL_GPIO23 \ + ESP32_PINMUX(23, ESP_I2CEXT0_SCL_IN, ESP_I2CEXT0_SCL_OUT) + +#define I2C0_SCL_GPIO25 \ + ESP32_PINMUX(25, ESP_I2CEXT0_SCL_IN, ESP_I2CEXT0_SCL_OUT) + +#define I2C0_SCL_GPIO26 \ + ESP32_PINMUX(26, ESP_I2CEXT0_SCL_IN, ESP_I2CEXT0_SCL_OUT) + +#define I2C0_SCL_GPIO27 \ + ESP32_PINMUX(27, ESP_I2CEXT0_SCL_IN, ESP_I2CEXT0_SCL_OUT) + +#define I2C0_SCL_GPIO32 \ + ESP32_PINMUX(32, ESP_I2CEXT0_SCL_IN, ESP_I2CEXT0_SCL_OUT) + +#define I2C0_SCL_GPIO33 \ + ESP32_PINMUX(33, ESP_I2CEXT0_SCL_IN, ESP_I2CEXT0_SCL_OUT) + +/* I2C0_SDA */ +#define I2C0_SDA_GPIO0 \ + ESP32_PINMUX(0, ESP_I2CEXT0_SDA_IN, ESP_I2CEXT0_SDA_OUT) + +#define I2C0_SDA_GPIO1 \ + ESP32_PINMUX(1, ESP_I2CEXT0_SDA_IN, ESP_I2CEXT0_SDA_OUT) + +#define I2C0_SDA_GPIO2 \ + ESP32_PINMUX(2, ESP_I2CEXT0_SDA_IN, ESP_I2CEXT0_SDA_OUT) + +#define I2C0_SDA_GPIO3 \ + ESP32_PINMUX(3, ESP_I2CEXT0_SDA_IN, ESP_I2CEXT0_SDA_OUT) + +#define I2C0_SDA_GPIO4 \ + ESP32_PINMUX(4, ESP_I2CEXT0_SDA_IN, ESP_I2CEXT0_SDA_OUT) + +#define I2C0_SDA_GPIO5 \ + ESP32_PINMUX(5, ESP_I2CEXT0_SDA_IN, ESP_I2CEXT0_SDA_OUT) + +#define I2C0_SDA_GPIO6 \ + ESP32_PINMUX(6, ESP_I2CEXT0_SDA_IN, ESP_I2CEXT0_SDA_OUT) + +#define I2C0_SDA_GPIO7 \ + ESP32_PINMUX(7, ESP_I2CEXT0_SDA_IN, ESP_I2CEXT0_SDA_OUT) + +#define I2C0_SDA_GPIO8 \ + ESP32_PINMUX(8, ESP_I2CEXT0_SDA_IN, ESP_I2CEXT0_SDA_OUT) + +#define I2C0_SDA_GPIO9 \ + ESP32_PINMUX(9, ESP_I2CEXT0_SDA_IN, ESP_I2CEXT0_SDA_OUT) + +#define I2C0_SDA_GPIO10 \ + ESP32_PINMUX(10, ESP_I2CEXT0_SDA_IN, ESP_I2CEXT0_SDA_OUT) + +#define I2C0_SDA_GPIO11 \ + ESP32_PINMUX(11, ESP_I2CEXT0_SDA_IN, ESP_I2CEXT0_SDA_OUT) + +#define I2C0_SDA_GPIO12 \ + ESP32_PINMUX(12, ESP_I2CEXT0_SDA_IN, ESP_I2CEXT0_SDA_OUT) + +#define I2C0_SDA_GPIO13 \ + ESP32_PINMUX(13, ESP_I2CEXT0_SDA_IN, ESP_I2CEXT0_SDA_OUT) + +#define I2C0_SDA_GPIO14 \ + ESP32_PINMUX(14, ESP_I2CEXT0_SDA_IN, ESP_I2CEXT0_SDA_OUT) + +#define I2C0_SDA_GPIO15 \ + ESP32_PINMUX(15, ESP_I2CEXT0_SDA_IN, ESP_I2CEXT0_SDA_OUT) + +#define I2C0_SDA_GPIO16 \ + ESP32_PINMUX(16, ESP_I2CEXT0_SDA_IN, ESP_I2CEXT0_SDA_OUT) + +#define I2C0_SDA_GPIO17 \ + ESP32_PINMUX(17, ESP_I2CEXT0_SDA_IN, ESP_I2CEXT0_SDA_OUT) + +#define I2C0_SDA_GPIO18 \ + ESP32_PINMUX(18, ESP_I2CEXT0_SDA_IN, ESP_I2CEXT0_SDA_OUT) + +#define I2C0_SDA_GPIO19 \ + ESP32_PINMUX(19, ESP_I2CEXT0_SDA_IN, ESP_I2CEXT0_SDA_OUT) + +#define I2C0_SDA_GPIO20 \ + ESP32_PINMUX(20, ESP_I2CEXT0_SDA_IN, ESP_I2CEXT0_SDA_OUT) + +#define I2C0_SDA_GPIO21 \ + ESP32_PINMUX(21, ESP_I2CEXT0_SDA_IN, ESP_I2CEXT0_SDA_OUT) + +#define I2C0_SDA_GPIO22 \ + ESP32_PINMUX(22, ESP_I2CEXT0_SDA_IN, ESP_I2CEXT0_SDA_OUT) + +#define I2C0_SDA_GPIO23 \ + ESP32_PINMUX(23, ESP_I2CEXT0_SDA_IN, ESP_I2CEXT0_SDA_OUT) + +#define I2C0_SDA_GPIO25 \ + ESP32_PINMUX(25, ESP_I2CEXT0_SDA_IN, ESP_I2CEXT0_SDA_OUT) + +#define I2C0_SDA_GPIO26 \ + ESP32_PINMUX(26, ESP_I2CEXT0_SDA_IN, ESP_I2CEXT0_SDA_OUT) + +#define I2C0_SDA_GPIO27 \ + ESP32_PINMUX(27, ESP_I2CEXT0_SDA_IN, ESP_I2CEXT0_SDA_OUT) + +#define I2C0_SDA_GPIO32 \ + ESP32_PINMUX(32, ESP_I2CEXT0_SDA_IN, ESP_I2CEXT0_SDA_OUT) + +#define I2C0_SDA_GPIO33 \ + ESP32_PINMUX(33, ESP_I2CEXT0_SDA_IN, ESP_I2CEXT0_SDA_OUT) + +/* I2C1_SCL */ +#define I2C1_SCL_GPIO0 \ + ESP32_PINMUX(0, ESP_I2CEXT1_SCL_IN, ESP_I2CEXT1_SCL_OUT) + +#define I2C1_SCL_GPIO1 \ + ESP32_PINMUX(1, ESP_I2CEXT1_SCL_IN, ESP_I2CEXT1_SCL_OUT) + +#define I2C1_SCL_GPIO2 \ + ESP32_PINMUX(2, ESP_I2CEXT1_SCL_IN, ESP_I2CEXT1_SCL_OUT) + +#define I2C1_SCL_GPIO3 \ + ESP32_PINMUX(3, ESP_I2CEXT1_SCL_IN, ESP_I2CEXT1_SCL_OUT) + +#define I2C1_SCL_GPIO4 \ + ESP32_PINMUX(4, ESP_I2CEXT1_SCL_IN, ESP_I2CEXT1_SCL_OUT) + +#define I2C1_SCL_GPIO5 \ + ESP32_PINMUX(5, ESP_I2CEXT1_SCL_IN, ESP_I2CEXT1_SCL_OUT) + +#define I2C1_SCL_GPIO6 \ + ESP32_PINMUX(6, ESP_I2CEXT1_SCL_IN, ESP_I2CEXT1_SCL_OUT) + +#define I2C1_SCL_GPIO7 \ + ESP32_PINMUX(7, ESP_I2CEXT1_SCL_IN, ESP_I2CEXT1_SCL_OUT) + +#define I2C1_SCL_GPIO8 \ + ESP32_PINMUX(8, ESP_I2CEXT1_SCL_IN, ESP_I2CEXT1_SCL_OUT) + +#define I2C1_SCL_GPIO9 \ + ESP32_PINMUX(9, ESP_I2CEXT1_SCL_IN, ESP_I2CEXT1_SCL_OUT) + +#define I2C1_SCL_GPIO10 \ + ESP32_PINMUX(10, ESP_I2CEXT1_SCL_IN, ESP_I2CEXT1_SCL_OUT) + +#define I2C1_SCL_GPIO11 \ + ESP32_PINMUX(11, ESP_I2CEXT1_SCL_IN, ESP_I2CEXT1_SCL_OUT) + +#define I2C1_SCL_GPIO12 \ + ESP32_PINMUX(12, ESP_I2CEXT1_SCL_IN, ESP_I2CEXT1_SCL_OUT) + +#define I2C1_SCL_GPIO13 \ + ESP32_PINMUX(13, ESP_I2CEXT1_SCL_IN, ESP_I2CEXT1_SCL_OUT) + +#define I2C1_SCL_GPIO14 \ + ESP32_PINMUX(14, ESP_I2CEXT1_SCL_IN, ESP_I2CEXT1_SCL_OUT) + +#define I2C1_SCL_GPIO15 \ + ESP32_PINMUX(15, ESP_I2CEXT1_SCL_IN, ESP_I2CEXT1_SCL_OUT) + +#define I2C1_SCL_GPIO16 \ + ESP32_PINMUX(16, ESP_I2CEXT1_SCL_IN, ESP_I2CEXT1_SCL_OUT) + +#define I2C1_SCL_GPIO17 \ + ESP32_PINMUX(17, ESP_I2CEXT1_SCL_IN, ESP_I2CEXT1_SCL_OUT) + +#define I2C1_SCL_GPIO18 \ + ESP32_PINMUX(18, ESP_I2CEXT1_SCL_IN, ESP_I2CEXT1_SCL_OUT) + +#define I2C1_SCL_GPIO19 \ + ESP32_PINMUX(19, ESP_I2CEXT1_SCL_IN, ESP_I2CEXT1_SCL_OUT) + +#define I2C1_SCL_GPIO20 \ + ESP32_PINMUX(20, ESP_I2CEXT1_SCL_IN, ESP_I2CEXT1_SCL_OUT) + +#define I2C1_SCL_GPIO21 \ + ESP32_PINMUX(21, ESP_I2CEXT1_SCL_IN, ESP_I2CEXT1_SCL_OUT) + +#define I2C1_SCL_GPIO22 \ + ESP32_PINMUX(22, ESP_I2CEXT1_SCL_IN, ESP_I2CEXT1_SCL_OUT) + +#define I2C1_SCL_GPIO23 \ + ESP32_PINMUX(23, ESP_I2CEXT1_SCL_IN, ESP_I2CEXT1_SCL_OUT) + +#define I2C1_SCL_GPIO25 \ + ESP32_PINMUX(25, ESP_I2CEXT1_SCL_IN, ESP_I2CEXT1_SCL_OUT) + +#define I2C1_SCL_GPIO26 \ + ESP32_PINMUX(26, ESP_I2CEXT1_SCL_IN, ESP_I2CEXT1_SCL_OUT) + +#define I2C1_SCL_GPIO27 \ + ESP32_PINMUX(27, ESP_I2CEXT1_SCL_IN, ESP_I2CEXT1_SCL_OUT) + +#define I2C1_SCL_GPIO32 \ + ESP32_PINMUX(32, ESP_I2CEXT1_SCL_IN, ESP_I2CEXT1_SCL_OUT) + +#define I2C1_SCL_GPIO33 \ + ESP32_PINMUX(33, ESP_I2CEXT1_SCL_IN, ESP_I2CEXT1_SCL_OUT) + +/* I2C1_SDA */ +#define I2C1_SDA_GPIO0 \ + ESP32_PINMUX(0, ESP_I2CEXT1_SDA_IN, ESP_I2CEXT1_SDA_OUT) + +#define I2C1_SDA_GPIO1 \ + ESP32_PINMUX(1, ESP_I2CEXT1_SDA_IN, ESP_I2CEXT1_SDA_OUT) + +#define I2C1_SDA_GPIO2 \ + ESP32_PINMUX(2, ESP_I2CEXT1_SDA_IN, ESP_I2CEXT1_SDA_OUT) + +#define I2C1_SDA_GPIO3 \ + ESP32_PINMUX(3, ESP_I2CEXT1_SDA_IN, ESP_I2CEXT1_SDA_OUT) + +#define I2C1_SDA_GPIO4 \ + ESP32_PINMUX(4, ESP_I2CEXT1_SDA_IN, ESP_I2CEXT1_SDA_OUT) + +#define I2C1_SDA_GPIO5 \ + ESP32_PINMUX(5, ESP_I2CEXT1_SDA_IN, ESP_I2CEXT1_SDA_OUT) + +#define I2C1_SDA_GPIO6 \ + ESP32_PINMUX(6, ESP_I2CEXT1_SDA_IN, ESP_I2CEXT1_SDA_OUT) + +#define I2C1_SDA_GPIO7 \ + ESP32_PINMUX(7, ESP_I2CEXT1_SDA_IN, ESP_I2CEXT1_SDA_OUT) + +#define I2C1_SDA_GPIO8 \ + ESP32_PINMUX(8, ESP_I2CEXT1_SDA_IN, ESP_I2CEXT1_SDA_OUT) + +#define I2C1_SDA_GPIO9 \ + ESP32_PINMUX(9, ESP_I2CEXT1_SDA_IN, ESP_I2CEXT1_SDA_OUT) + +#define I2C1_SDA_GPIO10 \ + ESP32_PINMUX(10, ESP_I2CEXT1_SDA_IN, ESP_I2CEXT1_SDA_OUT) + +#define I2C1_SDA_GPIO11 \ + ESP32_PINMUX(11, ESP_I2CEXT1_SDA_IN, ESP_I2CEXT1_SDA_OUT) + +#define I2C1_SDA_GPIO12 \ + ESP32_PINMUX(12, ESP_I2CEXT1_SDA_IN, ESP_I2CEXT1_SDA_OUT) + +#define I2C1_SDA_GPIO13 \ + ESP32_PINMUX(13, ESP_I2CEXT1_SDA_IN, ESP_I2CEXT1_SDA_OUT) + +#define I2C1_SDA_GPIO14 \ + ESP32_PINMUX(14, ESP_I2CEXT1_SDA_IN, ESP_I2CEXT1_SDA_OUT) + +#define I2C1_SDA_GPIO15 \ + ESP32_PINMUX(15, ESP_I2CEXT1_SDA_IN, ESP_I2CEXT1_SDA_OUT) + +#define I2C1_SDA_GPIO16 \ + ESP32_PINMUX(16, ESP_I2CEXT1_SDA_IN, ESP_I2CEXT1_SDA_OUT) + +#define I2C1_SDA_GPIO17 \ + ESP32_PINMUX(17, ESP_I2CEXT1_SDA_IN, ESP_I2CEXT1_SDA_OUT) + +#define I2C1_SDA_GPIO18 \ + ESP32_PINMUX(18, ESP_I2CEXT1_SDA_IN, ESP_I2CEXT1_SDA_OUT) + +#define I2C1_SDA_GPIO19 \ + ESP32_PINMUX(19, ESP_I2CEXT1_SDA_IN, ESP_I2CEXT1_SDA_OUT) + +#define I2C1_SDA_GPIO20 \ + ESP32_PINMUX(20, ESP_I2CEXT1_SDA_IN, ESP_I2CEXT1_SDA_OUT) + +#define I2C1_SDA_GPIO21 \ + ESP32_PINMUX(21, ESP_I2CEXT1_SDA_IN, ESP_I2CEXT1_SDA_OUT) + +#define I2C1_SDA_GPIO22 \ + ESP32_PINMUX(22, ESP_I2CEXT1_SDA_IN, ESP_I2CEXT1_SDA_OUT) + +#define I2C1_SDA_GPIO23 \ + ESP32_PINMUX(23, ESP_I2CEXT1_SDA_IN, ESP_I2CEXT1_SDA_OUT) + +#define I2C1_SDA_GPIO25 \ + ESP32_PINMUX(25, ESP_I2CEXT1_SDA_IN, ESP_I2CEXT1_SDA_OUT) + +#define I2C1_SDA_GPIO26 \ + ESP32_PINMUX(26, ESP_I2CEXT1_SDA_IN, ESP_I2CEXT1_SDA_OUT) + +#define I2C1_SDA_GPIO27 \ + ESP32_PINMUX(27, ESP_I2CEXT1_SDA_IN, ESP_I2CEXT1_SDA_OUT) + +#define I2C1_SDA_GPIO32 \ + ESP32_PINMUX(32, ESP_I2CEXT1_SDA_IN, ESP_I2CEXT1_SDA_OUT) + +#define I2C1_SDA_GPIO33 \ + ESP32_PINMUX(33, ESP_I2CEXT1_SDA_IN, ESP_I2CEXT1_SDA_OUT) + +/* LEDC_CH0 */ +#define LEDC_CH0_GPIO0 \ + ESP32_PINMUX(0, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT0) + +#define LEDC_CH0_GPIO1 \ + ESP32_PINMUX(1, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT0) + +#define LEDC_CH0_GPIO2 \ + ESP32_PINMUX(2, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT0) + +#define LEDC_CH0_GPIO3 \ + ESP32_PINMUX(3, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT0) + +#define LEDC_CH0_GPIO4 \ + ESP32_PINMUX(4, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT0) + +#define LEDC_CH0_GPIO5 \ + ESP32_PINMUX(5, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT0) + +#define LEDC_CH0_GPIO6 \ + ESP32_PINMUX(6, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT0) + +#define LEDC_CH0_GPIO7 \ + ESP32_PINMUX(7, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT0) + +#define LEDC_CH0_GPIO8 \ + ESP32_PINMUX(8, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT0) + +#define LEDC_CH0_GPIO9 \ + ESP32_PINMUX(9, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT0) + +#define LEDC_CH0_GPIO10 \ + ESP32_PINMUX(10, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT0) + +#define LEDC_CH0_GPIO11 \ + ESP32_PINMUX(11, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT0) + +#define LEDC_CH0_GPIO12 \ + ESP32_PINMUX(12, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT0) + +#define LEDC_CH0_GPIO13 \ + ESP32_PINMUX(13, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT0) + +#define LEDC_CH0_GPIO14 \ + ESP32_PINMUX(14, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT0) + +#define LEDC_CH0_GPIO15 \ + ESP32_PINMUX(15, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT0) + +#define LEDC_CH0_GPIO16 \ + ESP32_PINMUX(16, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT0) + +#define LEDC_CH0_GPIO17 \ + ESP32_PINMUX(17, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT0) + +#define LEDC_CH0_GPIO18 \ + ESP32_PINMUX(18, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT0) + +#define LEDC_CH0_GPIO19 \ + ESP32_PINMUX(19, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT0) + +#define LEDC_CH0_GPIO20 \ + ESP32_PINMUX(20, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT0) + +#define LEDC_CH0_GPIO21 \ + ESP32_PINMUX(21, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT0) + +#define LEDC_CH0_GPIO22 \ + ESP32_PINMUX(22, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT0) + +#define LEDC_CH0_GPIO23 \ + ESP32_PINMUX(23, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT0) + +#define LEDC_CH0_GPIO25 \ + ESP32_PINMUX(25, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT0) + +#define LEDC_CH0_GPIO26 \ + ESP32_PINMUX(26, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT0) + +#define LEDC_CH0_GPIO27 \ + ESP32_PINMUX(27, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT0) + +#define LEDC_CH0_GPIO32 \ + ESP32_PINMUX(32, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT0) + +#define LEDC_CH0_GPIO33 \ + ESP32_PINMUX(33, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT0) + +/* LEDC_CH1 */ +#define LEDC_CH1_GPIO0 \ + ESP32_PINMUX(0, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT1) + +#define LEDC_CH1_GPIO1 \ + ESP32_PINMUX(1, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT1) + +#define LEDC_CH1_GPIO2 \ + ESP32_PINMUX(2, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT1) + +#define LEDC_CH1_GPIO3 \ + ESP32_PINMUX(3, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT1) + +#define LEDC_CH1_GPIO4 \ + ESP32_PINMUX(4, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT1) + +#define LEDC_CH1_GPIO5 \ + ESP32_PINMUX(5, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT1) + +#define LEDC_CH1_GPIO6 \ + ESP32_PINMUX(6, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT1) + +#define LEDC_CH1_GPIO7 \ + ESP32_PINMUX(7, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT1) + +#define LEDC_CH1_GPIO8 \ + ESP32_PINMUX(8, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT1) + +#define LEDC_CH1_GPIO9 \ + ESP32_PINMUX(9, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT1) + +#define LEDC_CH1_GPIO10 \ + ESP32_PINMUX(10, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT1) + +#define LEDC_CH1_GPIO11 \ + ESP32_PINMUX(11, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT1) + +#define LEDC_CH1_GPIO12 \ + ESP32_PINMUX(12, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT1) + +#define LEDC_CH1_GPIO13 \ + ESP32_PINMUX(13, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT1) + +#define LEDC_CH1_GPIO14 \ + ESP32_PINMUX(14, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT1) + +#define LEDC_CH1_GPIO15 \ + ESP32_PINMUX(15, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT1) + +#define LEDC_CH1_GPIO16 \ + ESP32_PINMUX(16, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT1) + +#define LEDC_CH1_GPIO17 \ + ESP32_PINMUX(17, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT1) + +#define LEDC_CH1_GPIO18 \ + ESP32_PINMUX(18, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT1) + +#define LEDC_CH1_GPIO19 \ + ESP32_PINMUX(19, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT1) + +#define LEDC_CH1_GPIO20 \ + ESP32_PINMUX(20, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT1) + +#define LEDC_CH1_GPIO21 \ + ESP32_PINMUX(21, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT1) + +#define LEDC_CH1_GPIO22 \ + ESP32_PINMUX(22, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT1) + +#define LEDC_CH1_GPIO23 \ + ESP32_PINMUX(23, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT1) + +#define LEDC_CH1_GPIO25 \ + ESP32_PINMUX(25, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT1) + +#define LEDC_CH1_GPIO26 \ + ESP32_PINMUX(26, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT1) + +#define LEDC_CH1_GPIO27 \ + ESP32_PINMUX(27, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT1) + +#define LEDC_CH1_GPIO32 \ + ESP32_PINMUX(32, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT1) + +#define LEDC_CH1_GPIO33 \ + ESP32_PINMUX(33, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT1) + +/* LEDC_CH10 */ +#define LEDC_CH10_GPIO0 \ + ESP32_PINMUX(0, ESP_NOSIG, ESP_LEDC_HS_SIG_OUT2) + +#define LEDC_CH10_GPIO1 \ + ESP32_PINMUX(1, ESP_NOSIG, ESP_LEDC_HS_SIG_OUT2) + +#define LEDC_CH10_GPIO2 \ + ESP32_PINMUX(2, ESP_NOSIG, ESP_LEDC_HS_SIG_OUT2) + +#define LEDC_CH10_GPIO3 \ + ESP32_PINMUX(3, ESP_NOSIG, ESP_LEDC_HS_SIG_OUT2) + +#define LEDC_CH10_GPIO4 \ + ESP32_PINMUX(4, ESP_NOSIG, ESP_LEDC_HS_SIG_OUT2) + +#define LEDC_CH10_GPIO5 \ + ESP32_PINMUX(5, ESP_NOSIG, ESP_LEDC_HS_SIG_OUT2) + +#define LEDC_CH10_GPIO6 \ + ESP32_PINMUX(6, ESP_NOSIG, ESP_LEDC_HS_SIG_OUT2) + +#define LEDC_CH10_GPIO7 \ + ESP32_PINMUX(7, ESP_NOSIG, ESP_LEDC_HS_SIG_OUT2) + +#define LEDC_CH10_GPIO8 \ + ESP32_PINMUX(8, ESP_NOSIG, ESP_LEDC_HS_SIG_OUT2) + +#define LEDC_CH10_GPIO9 \ + ESP32_PINMUX(9, ESP_NOSIG, ESP_LEDC_HS_SIG_OUT2) + +#define LEDC_CH10_GPIO10 \ + ESP32_PINMUX(10, ESP_NOSIG, ESP_LEDC_HS_SIG_OUT2) + +#define LEDC_CH10_GPIO11 \ + ESP32_PINMUX(11, ESP_NOSIG, ESP_LEDC_HS_SIG_OUT2) + +#define LEDC_CH10_GPIO12 \ + ESP32_PINMUX(12, ESP_NOSIG, ESP_LEDC_HS_SIG_OUT2) + +#define LEDC_CH10_GPIO13 \ + ESP32_PINMUX(13, ESP_NOSIG, ESP_LEDC_HS_SIG_OUT2) + +#define LEDC_CH10_GPIO14 \ + ESP32_PINMUX(14, ESP_NOSIG, ESP_LEDC_HS_SIG_OUT2) + +#define LEDC_CH10_GPIO15 \ + ESP32_PINMUX(15, ESP_NOSIG, ESP_LEDC_HS_SIG_OUT2) + +#define LEDC_CH10_GPIO16 \ + ESP32_PINMUX(16, ESP_NOSIG, ESP_LEDC_HS_SIG_OUT2) + +#define LEDC_CH10_GPIO17 \ + ESP32_PINMUX(17, ESP_NOSIG, ESP_LEDC_HS_SIG_OUT2) + +#define LEDC_CH10_GPIO18 \ + ESP32_PINMUX(18, ESP_NOSIG, ESP_LEDC_HS_SIG_OUT2) + +#define LEDC_CH10_GPIO19 \ + ESP32_PINMUX(19, ESP_NOSIG, ESP_LEDC_HS_SIG_OUT2) + +#define LEDC_CH10_GPIO20 \ + ESP32_PINMUX(20, ESP_NOSIG, ESP_LEDC_HS_SIG_OUT2) + +#define LEDC_CH10_GPIO21 \ + ESP32_PINMUX(21, ESP_NOSIG, ESP_LEDC_HS_SIG_OUT2) + +#define LEDC_CH10_GPIO22 \ + ESP32_PINMUX(22, ESP_NOSIG, ESP_LEDC_HS_SIG_OUT2) + +#define LEDC_CH10_GPIO23 \ + ESP32_PINMUX(23, ESP_NOSIG, ESP_LEDC_HS_SIG_OUT2) + +#define LEDC_CH10_GPIO25 \ + ESP32_PINMUX(25, ESP_NOSIG, ESP_LEDC_HS_SIG_OUT2) + +#define LEDC_CH10_GPIO26 \ + ESP32_PINMUX(26, ESP_NOSIG, ESP_LEDC_HS_SIG_OUT2) + +#define LEDC_CH10_GPIO27 \ + ESP32_PINMUX(27, ESP_NOSIG, ESP_LEDC_HS_SIG_OUT2) + +#define LEDC_CH10_GPIO32 \ + ESP32_PINMUX(32, ESP_NOSIG, ESP_LEDC_HS_SIG_OUT2) + +#define LEDC_CH10_GPIO33 \ + ESP32_PINMUX(33, ESP_NOSIG, ESP_LEDC_HS_SIG_OUT2) + +/* LEDC_CH11 */ +#define LEDC_CH11_GPIO0 \ + ESP32_PINMUX(0, ESP_NOSIG, ESP_LEDC_HS_SIG_OUT3) + +#define LEDC_CH11_GPIO1 \ + ESP32_PINMUX(1, ESP_NOSIG, ESP_LEDC_HS_SIG_OUT3) + +#define LEDC_CH11_GPIO2 \ + ESP32_PINMUX(2, ESP_NOSIG, ESP_LEDC_HS_SIG_OUT3) + +#define LEDC_CH11_GPIO3 \ + ESP32_PINMUX(3, ESP_NOSIG, ESP_LEDC_HS_SIG_OUT3) + +#define LEDC_CH11_GPIO4 \ + ESP32_PINMUX(4, ESP_NOSIG, ESP_LEDC_HS_SIG_OUT3) + +#define LEDC_CH11_GPIO5 \ + ESP32_PINMUX(5, ESP_NOSIG, ESP_LEDC_HS_SIG_OUT3) + +#define LEDC_CH11_GPIO6 \ + ESP32_PINMUX(6, ESP_NOSIG, ESP_LEDC_HS_SIG_OUT3) + +#define LEDC_CH11_GPIO7 \ + ESP32_PINMUX(7, ESP_NOSIG, ESP_LEDC_HS_SIG_OUT3) + +#define LEDC_CH11_GPIO8 \ + ESP32_PINMUX(8, ESP_NOSIG, ESP_LEDC_HS_SIG_OUT3) + +#define LEDC_CH11_GPIO9 \ + ESP32_PINMUX(9, ESP_NOSIG, ESP_LEDC_HS_SIG_OUT3) + +#define LEDC_CH11_GPIO10 \ + ESP32_PINMUX(10, ESP_NOSIG, ESP_LEDC_HS_SIG_OUT3) + +#define LEDC_CH11_GPIO11 \ + ESP32_PINMUX(11, ESP_NOSIG, ESP_LEDC_HS_SIG_OUT3) + +#define LEDC_CH11_GPIO12 \ + ESP32_PINMUX(12, ESP_NOSIG, ESP_LEDC_HS_SIG_OUT3) + +#define LEDC_CH11_GPIO13 \ + ESP32_PINMUX(13, ESP_NOSIG, ESP_LEDC_HS_SIG_OUT3) + +#define LEDC_CH11_GPIO14 \ + ESP32_PINMUX(14, ESP_NOSIG, ESP_LEDC_HS_SIG_OUT3) + +#define LEDC_CH11_GPIO15 \ + ESP32_PINMUX(15, ESP_NOSIG, ESP_LEDC_HS_SIG_OUT3) + +#define LEDC_CH11_GPIO16 \ + ESP32_PINMUX(16, ESP_NOSIG, ESP_LEDC_HS_SIG_OUT3) + +#define LEDC_CH11_GPIO17 \ + ESP32_PINMUX(17, ESP_NOSIG, ESP_LEDC_HS_SIG_OUT3) + +#define LEDC_CH11_GPIO18 \ + ESP32_PINMUX(18, ESP_NOSIG, ESP_LEDC_HS_SIG_OUT3) + +#define LEDC_CH11_GPIO19 \ + ESP32_PINMUX(19, ESP_NOSIG, ESP_LEDC_HS_SIG_OUT3) + +#define LEDC_CH11_GPIO20 \ + ESP32_PINMUX(20, ESP_NOSIG, ESP_LEDC_HS_SIG_OUT3) + +#define LEDC_CH11_GPIO21 \ + ESP32_PINMUX(21, ESP_NOSIG, ESP_LEDC_HS_SIG_OUT3) + +#define LEDC_CH11_GPIO22 \ + ESP32_PINMUX(22, ESP_NOSIG, ESP_LEDC_HS_SIG_OUT3) + +#define LEDC_CH11_GPIO23 \ + ESP32_PINMUX(23, ESP_NOSIG, ESP_LEDC_HS_SIG_OUT3) + +#define LEDC_CH11_GPIO25 \ + ESP32_PINMUX(25, ESP_NOSIG, ESP_LEDC_HS_SIG_OUT3) + +#define LEDC_CH11_GPIO26 \ + ESP32_PINMUX(26, ESP_NOSIG, ESP_LEDC_HS_SIG_OUT3) + +#define LEDC_CH11_GPIO27 \ + ESP32_PINMUX(27, ESP_NOSIG, ESP_LEDC_HS_SIG_OUT3) + +#define LEDC_CH11_GPIO32 \ + ESP32_PINMUX(32, ESP_NOSIG, ESP_LEDC_HS_SIG_OUT3) + +#define LEDC_CH11_GPIO33 \ + ESP32_PINMUX(33, ESP_NOSIG, ESP_LEDC_HS_SIG_OUT3) + +/* LEDC_CH12 */ +#define LEDC_CH12_GPIO0 \ + ESP32_PINMUX(0, ESP_NOSIG, ESP_LEDC_HS_SIG_OUT4) + +#define LEDC_CH12_GPIO1 \ + ESP32_PINMUX(1, ESP_NOSIG, ESP_LEDC_HS_SIG_OUT4) + +#define LEDC_CH12_GPIO2 \ + ESP32_PINMUX(2, ESP_NOSIG, ESP_LEDC_HS_SIG_OUT4) + +#define LEDC_CH12_GPIO3 \ + ESP32_PINMUX(3, ESP_NOSIG, ESP_LEDC_HS_SIG_OUT4) + +#define LEDC_CH12_GPIO4 \ + ESP32_PINMUX(4, ESP_NOSIG, ESP_LEDC_HS_SIG_OUT4) + +#define LEDC_CH12_GPIO5 \ + ESP32_PINMUX(5, ESP_NOSIG, ESP_LEDC_HS_SIG_OUT4) + +#define LEDC_CH12_GPIO6 \ + ESP32_PINMUX(6, ESP_NOSIG, ESP_LEDC_HS_SIG_OUT4) + +#define LEDC_CH12_GPIO7 \ + ESP32_PINMUX(7, ESP_NOSIG, ESP_LEDC_HS_SIG_OUT4) + +#define LEDC_CH12_GPIO8 \ + ESP32_PINMUX(8, ESP_NOSIG, ESP_LEDC_HS_SIG_OUT4) + +#define LEDC_CH12_GPIO9 \ + ESP32_PINMUX(9, ESP_NOSIG, ESP_LEDC_HS_SIG_OUT4) + +#define LEDC_CH12_GPIO10 \ + ESP32_PINMUX(10, ESP_NOSIG, ESP_LEDC_HS_SIG_OUT4) + +#define LEDC_CH12_GPIO11 \ + ESP32_PINMUX(11, ESP_NOSIG, ESP_LEDC_HS_SIG_OUT4) + +#define LEDC_CH12_GPIO12 \ + ESP32_PINMUX(12, ESP_NOSIG, ESP_LEDC_HS_SIG_OUT4) + +#define LEDC_CH12_GPIO13 \ + ESP32_PINMUX(13, ESP_NOSIG, ESP_LEDC_HS_SIG_OUT4) + +#define LEDC_CH12_GPIO14 \ + ESP32_PINMUX(14, ESP_NOSIG, ESP_LEDC_HS_SIG_OUT4) + +#define LEDC_CH12_GPIO15 \ + ESP32_PINMUX(15, ESP_NOSIG, ESP_LEDC_HS_SIG_OUT4) + +#define LEDC_CH12_GPIO16 \ + ESP32_PINMUX(16, ESP_NOSIG, ESP_LEDC_HS_SIG_OUT4) + +#define LEDC_CH12_GPIO17 \ + ESP32_PINMUX(17, ESP_NOSIG, ESP_LEDC_HS_SIG_OUT4) + +#define LEDC_CH12_GPIO18 \ + ESP32_PINMUX(18, ESP_NOSIG, ESP_LEDC_HS_SIG_OUT4) + +#define LEDC_CH12_GPIO19 \ + ESP32_PINMUX(19, ESP_NOSIG, ESP_LEDC_HS_SIG_OUT4) + +#define LEDC_CH12_GPIO20 \ + ESP32_PINMUX(20, ESP_NOSIG, ESP_LEDC_HS_SIG_OUT4) + +#define LEDC_CH12_GPIO21 \ + ESP32_PINMUX(21, ESP_NOSIG, ESP_LEDC_HS_SIG_OUT4) + +#define LEDC_CH12_GPIO22 \ + ESP32_PINMUX(22, ESP_NOSIG, ESP_LEDC_HS_SIG_OUT4) + +#define LEDC_CH12_GPIO23 \ + ESP32_PINMUX(23, ESP_NOSIG, ESP_LEDC_HS_SIG_OUT4) + +#define LEDC_CH12_GPIO25 \ + ESP32_PINMUX(25, ESP_NOSIG, ESP_LEDC_HS_SIG_OUT4) + +#define LEDC_CH12_GPIO26 \ + ESP32_PINMUX(26, ESP_NOSIG, ESP_LEDC_HS_SIG_OUT4) + +#define LEDC_CH12_GPIO27 \ + ESP32_PINMUX(27, ESP_NOSIG, ESP_LEDC_HS_SIG_OUT4) + +#define LEDC_CH12_GPIO32 \ + ESP32_PINMUX(32, ESP_NOSIG, ESP_LEDC_HS_SIG_OUT4) + +#define LEDC_CH12_GPIO33 \ + ESP32_PINMUX(33, ESP_NOSIG, ESP_LEDC_HS_SIG_OUT4) + +/* LEDC_CH13 */ +#define LEDC_CH13_GPIO0 \ + ESP32_PINMUX(0, ESP_NOSIG, ESP_LEDC_HS_SIG_OUT5) + +#define LEDC_CH13_GPIO1 \ + ESP32_PINMUX(1, ESP_NOSIG, ESP_LEDC_HS_SIG_OUT5) + +#define LEDC_CH13_GPIO2 \ + ESP32_PINMUX(2, ESP_NOSIG, ESP_LEDC_HS_SIG_OUT5) + +#define LEDC_CH13_GPIO3 \ + ESP32_PINMUX(3, ESP_NOSIG, ESP_LEDC_HS_SIG_OUT5) + +#define LEDC_CH13_GPIO4 \ + ESP32_PINMUX(4, ESP_NOSIG, ESP_LEDC_HS_SIG_OUT5) + +#define LEDC_CH13_GPIO5 \ + ESP32_PINMUX(5, ESP_NOSIG, ESP_LEDC_HS_SIG_OUT5) + +#define LEDC_CH13_GPIO6 \ + ESP32_PINMUX(6, ESP_NOSIG, ESP_LEDC_HS_SIG_OUT5) + +#define LEDC_CH13_GPIO7 \ + ESP32_PINMUX(7, ESP_NOSIG, ESP_LEDC_HS_SIG_OUT5) + +#define LEDC_CH13_GPIO8 \ + ESP32_PINMUX(8, ESP_NOSIG, ESP_LEDC_HS_SIG_OUT5) + +#define LEDC_CH13_GPIO9 \ + ESP32_PINMUX(9, ESP_NOSIG, ESP_LEDC_HS_SIG_OUT5) + +#define LEDC_CH13_GPIO10 \ + ESP32_PINMUX(10, ESP_NOSIG, ESP_LEDC_HS_SIG_OUT5) + +#define LEDC_CH13_GPIO11 \ + ESP32_PINMUX(11, ESP_NOSIG, ESP_LEDC_HS_SIG_OUT5) + +#define LEDC_CH13_GPIO12 \ + ESP32_PINMUX(12, ESP_NOSIG, ESP_LEDC_HS_SIG_OUT5) + +#define LEDC_CH13_GPIO13 \ + ESP32_PINMUX(13, ESP_NOSIG, ESP_LEDC_HS_SIG_OUT5) + +#define LEDC_CH13_GPIO14 \ + ESP32_PINMUX(14, ESP_NOSIG, ESP_LEDC_HS_SIG_OUT5) + +#define LEDC_CH13_GPIO15 \ + ESP32_PINMUX(15, ESP_NOSIG, ESP_LEDC_HS_SIG_OUT5) + +#define LEDC_CH13_GPIO16 \ + ESP32_PINMUX(16, ESP_NOSIG, ESP_LEDC_HS_SIG_OUT5) + +#define LEDC_CH13_GPIO17 \ + ESP32_PINMUX(17, ESP_NOSIG, ESP_LEDC_HS_SIG_OUT5) + +#define LEDC_CH13_GPIO18 \ + ESP32_PINMUX(18, ESP_NOSIG, ESP_LEDC_HS_SIG_OUT5) + +#define LEDC_CH13_GPIO19 \ + ESP32_PINMUX(19, ESP_NOSIG, ESP_LEDC_HS_SIG_OUT5) + +#define LEDC_CH13_GPIO20 \ + ESP32_PINMUX(20, ESP_NOSIG, ESP_LEDC_HS_SIG_OUT5) + +#define LEDC_CH13_GPIO21 \ + ESP32_PINMUX(21, ESP_NOSIG, ESP_LEDC_HS_SIG_OUT5) + +#define LEDC_CH13_GPIO22 \ + ESP32_PINMUX(22, ESP_NOSIG, ESP_LEDC_HS_SIG_OUT5) + +#define LEDC_CH13_GPIO23 \ + ESP32_PINMUX(23, ESP_NOSIG, ESP_LEDC_HS_SIG_OUT5) + +#define LEDC_CH13_GPIO25 \ + ESP32_PINMUX(25, ESP_NOSIG, ESP_LEDC_HS_SIG_OUT5) + +#define LEDC_CH13_GPIO26 \ + ESP32_PINMUX(26, ESP_NOSIG, ESP_LEDC_HS_SIG_OUT5) + +#define LEDC_CH13_GPIO27 \ + ESP32_PINMUX(27, ESP_NOSIG, ESP_LEDC_HS_SIG_OUT5) + +#define LEDC_CH13_GPIO32 \ + ESP32_PINMUX(32, ESP_NOSIG, ESP_LEDC_HS_SIG_OUT5) + +#define LEDC_CH13_GPIO33 \ + ESP32_PINMUX(33, ESP_NOSIG, ESP_LEDC_HS_SIG_OUT5) + +/* LEDC_CH14 */ +#define LEDC_CH14_GPIO0 \ + ESP32_PINMUX(0, ESP_NOSIG, ESP_LEDC_HS_SIG_OUT6) + +#define LEDC_CH14_GPIO1 \ + ESP32_PINMUX(1, ESP_NOSIG, ESP_LEDC_HS_SIG_OUT6) + +#define LEDC_CH14_GPIO2 \ + ESP32_PINMUX(2, ESP_NOSIG, ESP_LEDC_HS_SIG_OUT6) + +#define LEDC_CH14_GPIO3 \ + ESP32_PINMUX(3, ESP_NOSIG, ESP_LEDC_HS_SIG_OUT6) + +#define LEDC_CH14_GPIO4 \ + ESP32_PINMUX(4, ESP_NOSIG, ESP_LEDC_HS_SIG_OUT6) + +#define LEDC_CH14_GPIO5 \ + ESP32_PINMUX(5, ESP_NOSIG, ESP_LEDC_HS_SIG_OUT6) + +#define LEDC_CH14_GPIO6 \ + ESP32_PINMUX(6, ESP_NOSIG, ESP_LEDC_HS_SIG_OUT6) + +#define LEDC_CH14_GPIO7 \ + ESP32_PINMUX(7, ESP_NOSIG, ESP_LEDC_HS_SIG_OUT6) + +#define LEDC_CH14_GPIO8 \ + ESP32_PINMUX(8, ESP_NOSIG, ESP_LEDC_HS_SIG_OUT6) + +#define LEDC_CH14_GPIO9 \ + ESP32_PINMUX(9, ESP_NOSIG, ESP_LEDC_HS_SIG_OUT6) + +#define LEDC_CH14_GPIO10 \ + ESP32_PINMUX(10, ESP_NOSIG, ESP_LEDC_HS_SIG_OUT6) + +#define LEDC_CH14_GPIO11 \ + ESP32_PINMUX(11, ESP_NOSIG, ESP_LEDC_HS_SIG_OUT6) + +#define LEDC_CH14_GPIO12 \ + ESP32_PINMUX(12, ESP_NOSIG, ESP_LEDC_HS_SIG_OUT6) + +#define LEDC_CH14_GPIO13 \ + ESP32_PINMUX(13, ESP_NOSIG, ESP_LEDC_HS_SIG_OUT6) + +#define LEDC_CH14_GPIO14 \ + ESP32_PINMUX(14, ESP_NOSIG, ESP_LEDC_HS_SIG_OUT6) + +#define LEDC_CH14_GPIO15 \ + ESP32_PINMUX(15, ESP_NOSIG, ESP_LEDC_HS_SIG_OUT6) + +#define LEDC_CH14_GPIO16 \ + ESP32_PINMUX(16, ESP_NOSIG, ESP_LEDC_HS_SIG_OUT6) + +#define LEDC_CH14_GPIO17 \ + ESP32_PINMUX(17, ESP_NOSIG, ESP_LEDC_HS_SIG_OUT6) + +#define LEDC_CH14_GPIO18 \ + ESP32_PINMUX(18, ESP_NOSIG, ESP_LEDC_HS_SIG_OUT6) + +#define LEDC_CH14_GPIO19 \ + ESP32_PINMUX(19, ESP_NOSIG, ESP_LEDC_HS_SIG_OUT6) + +#define LEDC_CH14_GPIO20 \ + ESP32_PINMUX(20, ESP_NOSIG, ESP_LEDC_HS_SIG_OUT6) + +#define LEDC_CH14_GPIO21 \ + ESP32_PINMUX(21, ESP_NOSIG, ESP_LEDC_HS_SIG_OUT6) + +#define LEDC_CH14_GPIO22 \ + ESP32_PINMUX(22, ESP_NOSIG, ESP_LEDC_HS_SIG_OUT6) + +#define LEDC_CH14_GPIO23 \ + ESP32_PINMUX(23, ESP_NOSIG, ESP_LEDC_HS_SIG_OUT6) + +#define LEDC_CH14_GPIO25 \ + ESP32_PINMUX(25, ESP_NOSIG, ESP_LEDC_HS_SIG_OUT6) + +#define LEDC_CH14_GPIO26 \ + ESP32_PINMUX(26, ESP_NOSIG, ESP_LEDC_HS_SIG_OUT6) + +#define LEDC_CH14_GPIO27 \ + ESP32_PINMUX(27, ESP_NOSIG, ESP_LEDC_HS_SIG_OUT6) + +#define LEDC_CH14_GPIO32 \ + ESP32_PINMUX(32, ESP_NOSIG, ESP_LEDC_HS_SIG_OUT6) + +#define LEDC_CH14_GPIO33 \ + ESP32_PINMUX(33, ESP_NOSIG, ESP_LEDC_HS_SIG_OUT6) + +/* LEDC_CH15 */ +#define LEDC_CH15_GPIO0 \ + ESP32_PINMUX(0, ESP_NOSIG, ESP_LEDC_HS_SIG_OUT7) + +#define LEDC_CH15_GPIO1 \ + ESP32_PINMUX(1, ESP_NOSIG, ESP_LEDC_HS_SIG_OUT7) + +#define LEDC_CH15_GPIO2 \ + ESP32_PINMUX(2, ESP_NOSIG, ESP_LEDC_HS_SIG_OUT7) + +#define LEDC_CH15_GPIO3 \ + ESP32_PINMUX(3, ESP_NOSIG, ESP_LEDC_HS_SIG_OUT7) + +#define LEDC_CH15_GPIO4 \ + ESP32_PINMUX(4, ESP_NOSIG, ESP_LEDC_HS_SIG_OUT7) + +#define LEDC_CH15_GPIO5 \ + ESP32_PINMUX(5, ESP_NOSIG, ESP_LEDC_HS_SIG_OUT7) + +#define LEDC_CH15_GPIO6 \ + ESP32_PINMUX(6, ESP_NOSIG, ESP_LEDC_HS_SIG_OUT7) + +#define LEDC_CH15_GPIO7 \ + ESP32_PINMUX(7, ESP_NOSIG, ESP_LEDC_HS_SIG_OUT7) + +#define LEDC_CH15_GPIO8 \ + ESP32_PINMUX(8, ESP_NOSIG, ESP_LEDC_HS_SIG_OUT7) + +#define LEDC_CH15_GPIO9 \ + ESP32_PINMUX(9, ESP_NOSIG, ESP_LEDC_HS_SIG_OUT7) + +#define LEDC_CH15_GPIO10 \ + ESP32_PINMUX(10, ESP_NOSIG, ESP_LEDC_HS_SIG_OUT7) + +#define LEDC_CH15_GPIO11 \ + ESP32_PINMUX(11, ESP_NOSIG, ESP_LEDC_HS_SIG_OUT7) + +#define LEDC_CH15_GPIO12 \ + ESP32_PINMUX(12, ESP_NOSIG, ESP_LEDC_HS_SIG_OUT7) + +#define LEDC_CH15_GPIO13 \ + ESP32_PINMUX(13, ESP_NOSIG, ESP_LEDC_HS_SIG_OUT7) + +#define LEDC_CH15_GPIO14 \ + ESP32_PINMUX(14, ESP_NOSIG, ESP_LEDC_HS_SIG_OUT7) + +#define LEDC_CH15_GPIO15 \ + ESP32_PINMUX(15, ESP_NOSIG, ESP_LEDC_HS_SIG_OUT7) + +#define LEDC_CH15_GPIO16 \ + ESP32_PINMUX(16, ESP_NOSIG, ESP_LEDC_HS_SIG_OUT7) + +#define LEDC_CH15_GPIO17 \ + ESP32_PINMUX(17, ESP_NOSIG, ESP_LEDC_HS_SIG_OUT7) + +#define LEDC_CH15_GPIO18 \ + ESP32_PINMUX(18, ESP_NOSIG, ESP_LEDC_HS_SIG_OUT7) + +#define LEDC_CH15_GPIO19 \ + ESP32_PINMUX(19, ESP_NOSIG, ESP_LEDC_HS_SIG_OUT7) + +#define LEDC_CH15_GPIO20 \ + ESP32_PINMUX(20, ESP_NOSIG, ESP_LEDC_HS_SIG_OUT7) + +#define LEDC_CH15_GPIO21 \ + ESP32_PINMUX(21, ESP_NOSIG, ESP_LEDC_HS_SIG_OUT7) + +#define LEDC_CH15_GPIO22 \ + ESP32_PINMUX(22, ESP_NOSIG, ESP_LEDC_HS_SIG_OUT7) + +#define LEDC_CH15_GPIO23 \ + ESP32_PINMUX(23, ESP_NOSIG, ESP_LEDC_HS_SIG_OUT7) + +#define LEDC_CH15_GPIO25 \ + ESP32_PINMUX(25, ESP_NOSIG, ESP_LEDC_HS_SIG_OUT7) + +#define LEDC_CH15_GPIO26 \ + ESP32_PINMUX(26, ESP_NOSIG, ESP_LEDC_HS_SIG_OUT7) + +#define LEDC_CH15_GPIO27 \ + ESP32_PINMUX(27, ESP_NOSIG, ESP_LEDC_HS_SIG_OUT7) + +#define LEDC_CH15_GPIO32 \ + ESP32_PINMUX(32, ESP_NOSIG, ESP_LEDC_HS_SIG_OUT7) + +#define LEDC_CH15_GPIO33 \ + ESP32_PINMUX(33, ESP_NOSIG, ESP_LEDC_HS_SIG_OUT7) + +/* LEDC_CH2 */ +#define LEDC_CH2_GPIO0 \ + ESP32_PINMUX(0, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT2) + +#define LEDC_CH2_GPIO1 \ + ESP32_PINMUX(1, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT2) + +#define LEDC_CH2_GPIO2 \ + ESP32_PINMUX(2, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT2) + +#define LEDC_CH2_GPIO3 \ + ESP32_PINMUX(3, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT2) + +#define LEDC_CH2_GPIO4 \ + ESP32_PINMUX(4, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT2) + +#define LEDC_CH2_GPIO5 \ + ESP32_PINMUX(5, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT2) + +#define LEDC_CH2_GPIO6 \ + ESP32_PINMUX(6, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT2) + +#define LEDC_CH2_GPIO7 \ + ESP32_PINMUX(7, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT2) + +#define LEDC_CH2_GPIO8 \ + ESP32_PINMUX(8, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT2) + +#define LEDC_CH2_GPIO9 \ + ESP32_PINMUX(9, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT2) + +#define LEDC_CH2_GPIO10 \ + ESP32_PINMUX(10, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT2) + +#define LEDC_CH2_GPIO11 \ + ESP32_PINMUX(11, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT2) + +#define LEDC_CH2_GPIO12 \ + ESP32_PINMUX(12, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT2) + +#define LEDC_CH2_GPIO13 \ + ESP32_PINMUX(13, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT2) + +#define LEDC_CH2_GPIO14 \ + ESP32_PINMUX(14, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT2) + +#define LEDC_CH2_GPIO15 \ + ESP32_PINMUX(15, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT2) + +#define LEDC_CH2_GPIO16 \ + ESP32_PINMUX(16, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT2) + +#define LEDC_CH2_GPIO17 \ + ESP32_PINMUX(17, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT2) + +#define LEDC_CH2_GPIO18 \ + ESP32_PINMUX(18, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT2) + +#define LEDC_CH2_GPIO19 \ + ESP32_PINMUX(19, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT2) + +#define LEDC_CH2_GPIO20 \ + ESP32_PINMUX(20, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT2) + +#define LEDC_CH2_GPIO21 \ + ESP32_PINMUX(21, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT2) + +#define LEDC_CH2_GPIO22 \ + ESP32_PINMUX(22, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT2) + +#define LEDC_CH2_GPIO23 \ + ESP32_PINMUX(23, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT2) + +#define LEDC_CH2_GPIO25 \ + ESP32_PINMUX(25, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT2) + +#define LEDC_CH2_GPIO26 \ + ESP32_PINMUX(26, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT2) + +#define LEDC_CH2_GPIO27 \ + ESP32_PINMUX(27, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT2) + +#define LEDC_CH2_GPIO32 \ + ESP32_PINMUX(32, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT2) + +#define LEDC_CH2_GPIO33 \ + ESP32_PINMUX(33, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT2) + +/* LEDC_CH3 */ +#define LEDC_CH3_GPIO0 \ + ESP32_PINMUX(0, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT3) + +#define LEDC_CH3_GPIO1 \ + ESP32_PINMUX(1, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT3) + +#define LEDC_CH3_GPIO2 \ + ESP32_PINMUX(2, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT3) + +#define LEDC_CH3_GPIO3 \ + ESP32_PINMUX(3, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT3) + +#define LEDC_CH3_GPIO4 \ + ESP32_PINMUX(4, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT3) + +#define LEDC_CH3_GPIO5 \ + ESP32_PINMUX(5, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT3) + +#define LEDC_CH3_GPIO6 \ + ESP32_PINMUX(6, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT3) + +#define LEDC_CH3_GPIO7 \ + ESP32_PINMUX(7, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT3) + +#define LEDC_CH3_GPIO8 \ + ESP32_PINMUX(8, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT3) + +#define LEDC_CH3_GPIO9 \ + ESP32_PINMUX(9, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT3) + +#define LEDC_CH3_GPIO10 \ + ESP32_PINMUX(10, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT3) + +#define LEDC_CH3_GPIO11 \ + ESP32_PINMUX(11, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT3) + +#define LEDC_CH3_GPIO12 \ + ESP32_PINMUX(12, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT3) + +#define LEDC_CH3_GPIO13 \ + ESP32_PINMUX(13, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT3) + +#define LEDC_CH3_GPIO14 \ + ESP32_PINMUX(14, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT3) + +#define LEDC_CH3_GPIO15 \ + ESP32_PINMUX(15, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT3) + +#define LEDC_CH3_GPIO16 \ + ESP32_PINMUX(16, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT3) + +#define LEDC_CH3_GPIO17 \ + ESP32_PINMUX(17, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT3) + +#define LEDC_CH3_GPIO18 \ + ESP32_PINMUX(18, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT3) + +#define LEDC_CH3_GPIO19 \ + ESP32_PINMUX(19, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT3) + +#define LEDC_CH3_GPIO20 \ + ESP32_PINMUX(20, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT3) + +#define LEDC_CH3_GPIO21 \ + ESP32_PINMUX(21, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT3) + +#define LEDC_CH3_GPIO22 \ + ESP32_PINMUX(22, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT3) + +#define LEDC_CH3_GPIO23 \ + ESP32_PINMUX(23, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT3) + +#define LEDC_CH3_GPIO25 \ + ESP32_PINMUX(25, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT3) + +#define LEDC_CH3_GPIO26 \ + ESP32_PINMUX(26, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT3) + +#define LEDC_CH3_GPIO27 \ + ESP32_PINMUX(27, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT3) + +#define LEDC_CH3_GPIO32 \ + ESP32_PINMUX(32, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT3) + +#define LEDC_CH3_GPIO33 \ + ESP32_PINMUX(33, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT3) + +/* LEDC_CH4 */ +#define LEDC_CH4_GPIO0 \ + ESP32_PINMUX(0, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT4) + +#define LEDC_CH4_GPIO1 \ + ESP32_PINMUX(1, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT4) + +#define LEDC_CH4_GPIO2 \ + ESP32_PINMUX(2, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT4) + +#define LEDC_CH4_GPIO3 \ + ESP32_PINMUX(3, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT4) + +#define LEDC_CH4_GPIO4 \ + ESP32_PINMUX(4, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT4) + +#define LEDC_CH4_GPIO5 \ + ESP32_PINMUX(5, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT4) + +#define LEDC_CH4_GPIO6 \ + ESP32_PINMUX(6, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT4) + +#define LEDC_CH4_GPIO7 \ + ESP32_PINMUX(7, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT4) + +#define LEDC_CH4_GPIO8 \ + ESP32_PINMUX(8, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT4) + +#define LEDC_CH4_GPIO9 \ + ESP32_PINMUX(9, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT4) + +#define LEDC_CH4_GPIO10 \ + ESP32_PINMUX(10, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT4) + +#define LEDC_CH4_GPIO11 \ + ESP32_PINMUX(11, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT4) + +#define LEDC_CH4_GPIO12 \ + ESP32_PINMUX(12, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT4) + +#define LEDC_CH4_GPIO13 \ + ESP32_PINMUX(13, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT4) + +#define LEDC_CH4_GPIO14 \ + ESP32_PINMUX(14, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT4) + +#define LEDC_CH4_GPIO15 \ + ESP32_PINMUX(15, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT4) + +#define LEDC_CH4_GPIO16 \ + ESP32_PINMUX(16, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT4) + +#define LEDC_CH4_GPIO17 \ + ESP32_PINMUX(17, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT4) + +#define LEDC_CH4_GPIO18 \ + ESP32_PINMUX(18, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT4) + +#define LEDC_CH4_GPIO19 \ + ESP32_PINMUX(19, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT4) + +#define LEDC_CH4_GPIO20 \ + ESP32_PINMUX(20, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT4) + +#define LEDC_CH4_GPIO21 \ + ESP32_PINMUX(21, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT4) + +#define LEDC_CH4_GPIO22 \ + ESP32_PINMUX(22, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT4) + +#define LEDC_CH4_GPIO23 \ + ESP32_PINMUX(23, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT4) + +#define LEDC_CH4_GPIO25 \ + ESP32_PINMUX(25, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT4) + +#define LEDC_CH4_GPIO26 \ + ESP32_PINMUX(26, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT4) + +#define LEDC_CH4_GPIO27 \ + ESP32_PINMUX(27, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT4) + +#define LEDC_CH4_GPIO32 \ + ESP32_PINMUX(32, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT4) + +#define LEDC_CH4_GPIO33 \ + ESP32_PINMUX(33, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT4) + +/* LEDC_CH5 */ +#define LEDC_CH5_GPIO0 \ + ESP32_PINMUX(0, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT5) + +#define LEDC_CH5_GPIO1 \ + ESP32_PINMUX(1, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT5) + +#define LEDC_CH5_GPIO2 \ + ESP32_PINMUX(2, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT5) + +#define LEDC_CH5_GPIO3 \ + ESP32_PINMUX(3, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT5) + +#define LEDC_CH5_GPIO4 \ + ESP32_PINMUX(4, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT5) + +#define LEDC_CH5_GPIO5 \ + ESP32_PINMUX(5, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT5) + +#define LEDC_CH5_GPIO6 \ + ESP32_PINMUX(6, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT5) + +#define LEDC_CH5_GPIO7 \ + ESP32_PINMUX(7, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT5) + +#define LEDC_CH5_GPIO8 \ + ESP32_PINMUX(8, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT5) + +#define LEDC_CH5_GPIO9 \ + ESP32_PINMUX(9, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT5) + +#define LEDC_CH5_GPIO10 \ + ESP32_PINMUX(10, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT5) + +#define LEDC_CH5_GPIO11 \ + ESP32_PINMUX(11, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT5) + +#define LEDC_CH5_GPIO12 \ + ESP32_PINMUX(12, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT5) + +#define LEDC_CH5_GPIO13 \ + ESP32_PINMUX(13, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT5) + +#define LEDC_CH5_GPIO14 \ + ESP32_PINMUX(14, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT5) + +#define LEDC_CH5_GPIO15 \ + ESP32_PINMUX(15, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT5) + +#define LEDC_CH5_GPIO16 \ + ESP32_PINMUX(16, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT5) + +#define LEDC_CH5_GPIO17 \ + ESP32_PINMUX(17, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT5) + +#define LEDC_CH5_GPIO18 \ + ESP32_PINMUX(18, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT5) + +#define LEDC_CH5_GPIO19 \ + ESP32_PINMUX(19, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT5) + +#define LEDC_CH5_GPIO20 \ + ESP32_PINMUX(20, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT5) + +#define LEDC_CH5_GPIO21 \ + ESP32_PINMUX(21, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT5) + +#define LEDC_CH5_GPIO22 \ + ESP32_PINMUX(22, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT5) + +#define LEDC_CH5_GPIO23 \ + ESP32_PINMUX(23, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT5) + +#define LEDC_CH5_GPIO25 \ + ESP32_PINMUX(25, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT5) + +#define LEDC_CH5_GPIO26 \ + ESP32_PINMUX(26, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT5) + +#define LEDC_CH5_GPIO27 \ + ESP32_PINMUX(27, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT5) + +#define LEDC_CH5_GPIO32 \ + ESP32_PINMUX(32, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT5) + +#define LEDC_CH5_GPIO33 \ + ESP32_PINMUX(33, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT5) + +/* LEDC_CH6 */ +#define LEDC_CH6_GPIO0 \ + ESP32_PINMUX(0, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT6) + +#define LEDC_CH6_GPIO1 \ + ESP32_PINMUX(1, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT6) + +#define LEDC_CH6_GPIO2 \ + ESP32_PINMUX(2, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT6) + +#define LEDC_CH6_GPIO3 \ + ESP32_PINMUX(3, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT6) + +#define LEDC_CH6_GPIO4 \ + ESP32_PINMUX(4, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT6) + +#define LEDC_CH6_GPIO5 \ + ESP32_PINMUX(5, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT6) + +#define LEDC_CH6_GPIO6 \ + ESP32_PINMUX(6, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT6) + +#define LEDC_CH6_GPIO7 \ + ESP32_PINMUX(7, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT6) + +#define LEDC_CH6_GPIO8 \ + ESP32_PINMUX(8, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT6) + +#define LEDC_CH6_GPIO9 \ + ESP32_PINMUX(9, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT6) + +#define LEDC_CH6_GPIO10 \ + ESP32_PINMUX(10, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT6) + +#define LEDC_CH6_GPIO11 \ + ESP32_PINMUX(11, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT6) + +#define LEDC_CH6_GPIO12 \ + ESP32_PINMUX(12, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT6) + +#define LEDC_CH6_GPIO13 \ + ESP32_PINMUX(13, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT6) + +#define LEDC_CH6_GPIO14 \ + ESP32_PINMUX(14, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT6) + +#define LEDC_CH6_GPIO15 \ + ESP32_PINMUX(15, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT6) + +#define LEDC_CH6_GPIO16 \ + ESP32_PINMUX(16, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT6) + +#define LEDC_CH6_GPIO17 \ + ESP32_PINMUX(17, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT6) + +#define LEDC_CH6_GPIO18 \ + ESP32_PINMUX(18, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT6) + +#define LEDC_CH6_GPIO19 \ + ESP32_PINMUX(19, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT6) + +#define LEDC_CH6_GPIO20 \ + ESP32_PINMUX(20, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT6) + +#define LEDC_CH6_GPIO21 \ + ESP32_PINMUX(21, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT6) + +#define LEDC_CH6_GPIO22 \ + ESP32_PINMUX(22, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT6) + +#define LEDC_CH6_GPIO23 \ + ESP32_PINMUX(23, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT6) + +#define LEDC_CH6_GPIO25 \ + ESP32_PINMUX(25, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT6) + +#define LEDC_CH6_GPIO26 \ + ESP32_PINMUX(26, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT6) + +#define LEDC_CH6_GPIO27 \ + ESP32_PINMUX(27, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT6) + +#define LEDC_CH6_GPIO32 \ + ESP32_PINMUX(32, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT6) + +#define LEDC_CH6_GPIO33 \ + ESP32_PINMUX(33, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT6) + +/* LEDC_CH7 */ +#define LEDC_CH7_GPIO0 \ + ESP32_PINMUX(0, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT7) + +#define LEDC_CH7_GPIO1 \ + ESP32_PINMUX(1, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT7) + +#define LEDC_CH7_GPIO2 \ + ESP32_PINMUX(2, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT7) + +#define LEDC_CH7_GPIO3 \ + ESP32_PINMUX(3, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT7) + +#define LEDC_CH7_GPIO4 \ + ESP32_PINMUX(4, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT7) + +#define LEDC_CH7_GPIO5 \ + ESP32_PINMUX(5, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT7) + +#define LEDC_CH7_GPIO6 \ + ESP32_PINMUX(6, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT7) + +#define LEDC_CH7_GPIO7 \ + ESP32_PINMUX(7, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT7) + +#define LEDC_CH7_GPIO8 \ + ESP32_PINMUX(8, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT7) + +#define LEDC_CH7_GPIO9 \ + ESP32_PINMUX(9, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT7) + +#define LEDC_CH7_GPIO10 \ + ESP32_PINMUX(10, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT7) + +#define LEDC_CH7_GPIO11 \ + ESP32_PINMUX(11, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT7) + +#define LEDC_CH7_GPIO12 \ + ESP32_PINMUX(12, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT7) + +#define LEDC_CH7_GPIO13 \ + ESP32_PINMUX(13, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT7) + +#define LEDC_CH7_GPIO14 \ + ESP32_PINMUX(14, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT7) + +#define LEDC_CH7_GPIO15 \ + ESP32_PINMUX(15, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT7) + +#define LEDC_CH7_GPIO16 \ + ESP32_PINMUX(16, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT7) + +#define LEDC_CH7_GPIO17 \ + ESP32_PINMUX(17, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT7) + +#define LEDC_CH7_GPIO18 \ + ESP32_PINMUX(18, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT7) + +#define LEDC_CH7_GPIO19 \ + ESP32_PINMUX(19, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT7) + +#define LEDC_CH7_GPIO20 \ + ESP32_PINMUX(20, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT7) + +#define LEDC_CH7_GPIO21 \ + ESP32_PINMUX(21, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT7) + +#define LEDC_CH7_GPIO22 \ + ESP32_PINMUX(22, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT7) + +#define LEDC_CH7_GPIO23 \ + ESP32_PINMUX(23, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT7) + +#define LEDC_CH7_GPIO25 \ + ESP32_PINMUX(25, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT7) + +#define LEDC_CH7_GPIO26 \ + ESP32_PINMUX(26, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT7) + +#define LEDC_CH7_GPIO27 \ + ESP32_PINMUX(27, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT7) + +#define LEDC_CH7_GPIO32 \ + ESP32_PINMUX(32, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT7) + +#define LEDC_CH7_GPIO33 \ + ESP32_PINMUX(33, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT7) + +/* LEDC_CH8 */ +#define LEDC_CH8_GPIO0 \ + ESP32_PINMUX(0, ESP_NOSIG, ESP_LEDC_HS_SIG_OUT0) + +#define LEDC_CH8_GPIO1 \ + ESP32_PINMUX(1, ESP_NOSIG, ESP_LEDC_HS_SIG_OUT0) + +#define LEDC_CH8_GPIO2 \ + ESP32_PINMUX(2, ESP_NOSIG, ESP_LEDC_HS_SIG_OUT0) + +#define LEDC_CH8_GPIO3 \ + ESP32_PINMUX(3, ESP_NOSIG, ESP_LEDC_HS_SIG_OUT0) + +#define LEDC_CH8_GPIO4 \ + ESP32_PINMUX(4, ESP_NOSIG, ESP_LEDC_HS_SIG_OUT0) + +#define LEDC_CH8_GPIO5 \ + ESP32_PINMUX(5, ESP_NOSIG, ESP_LEDC_HS_SIG_OUT0) + +#define LEDC_CH8_GPIO6 \ + ESP32_PINMUX(6, ESP_NOSIG, ESP_LEDC_HS_SIG_OUT0) + +#define LEDC_CH8_GPIO7 \ + ESP32_PINMUX(7, ESP_NOSIG, ESP_LEDC_HS_SIG_OUT0) + +#define LEDC_CH8_GPIO8 \ + ESP32_PINMUX(8, ESP_NOSIG, ESP_LEDC_HS_SIG_OUT0) + +#define LEDC_CH8_GPIO9 \ + ESP32_PINMUX(9, ESP_NOSIG, ESP_LEDC_HS_SIG_OUT0) + +#define LEDC_CH8_GPIO10 \ + ESP32_PINMUX(10, ESP_NOSIG, ESP_LEDC_HS_SIG_OUT0) + +#define LEDC_CH8_GPIO11 \ + ESP32_PINMUX(11, ESP_NOSIG, ESP_LEDC_HS_SIG_OUT0) + +#define LEDC_CH8_GPIO12 \ + ESP32_PINMUX(12, ESP_NOSIG, ESP_LEDC_HS_SIG_OUT0) + +#define LEDC_CH8_GPIO13 \ + ESP32_PINMUX(13, ESP_NOSIG, ESP_LEDC_HS_SIG_OUT0) + +#define LEDC_CH8_GPIO14 \ + ESP32_PINMUX(14, ESP_NOSIG, ESP_LEDC_HS_SIG_OUT0) + +#define LEDC_CH8_GPIO15 \ + ESP32_PINMUX(15, ESP_NOSIG, ESP_LEDC_HS_SIG_OUT0) + +#define LEDC_CH8_GPIO16 \ + ESP32_PINMUX(16, ESP_NOSIG, ESP_LEDC_HS_SIG_OUT0) + +#define LEDC_CH8_GPIO17 \ + ESP32_PINMUX(17, ESP_NOSIG, ESP_LEDC_HS_SIG_OUT0) + +#define LEDC_CH8_GPIO18 \ + ESP32_PINMUX(18, ESP_NOSIG, ESP_LEDC_HS_SIG_OUT0) + +#define LEDC_CH8_GPIO19 \ + ESP32_PINMUX(19, ESP_NOSIG, ESP_LEDC_HS_SIG_OUT0) + +#define LEDC_CH8_GPIO20 \ + ESP32_PINMUX(20, ESP_NOSIG, ESP_LEDC_HS_SIG_OUT0) + +#define LEDC_CH8_GPIO21 \ + ESP32_PINMUX(21, ESP_NOSIG, ESP_LEDC_HS_SIG_OUT0) + +#define LEDC_CH8_GPIO22 \ + ESP32_PINMUX(22, ESP_NOSIG, ESP_LEDC_HS_SIG_OUT0) + +#define LEDC_CH8_GPIO23 \ + ESP32_PINMUX(23, ESP_NOSIG, ESP_LEDC_HS_SIG_OUT0) + +#define LEDC_CH8_GPIO25 \ + ESP32_PINMUX(25, ESP_NOSIG, ESP_LEDC_HS_SIG_OUT0) + +#define LEDC_CH8_GPIO26 \ + ESP32_PINMUX(26, ESP_NOSIG, ESP_LEDC_HS_SIG_OUT0) + +#define LEDC_CH8_GPIO27 \ + ESP32_PINMUX(27, ESP_NOSIG, ESP_LEDC_HS_SIG_OUT0) + +#define LEDC_CH8_GPIO32 \ + ESP32_PINMUX(32, ESP_NOSIG, ESP_LEDC_HS_SIG_OUT0) + +#define LEDC_CH8_GPIO33 \ + ESP32_PINMUX(33, ESP_NOSIG, ESP_LEDC_HS_SIG_OUT0) + +/* LEDC_CH9 */ +#define LEDC_CH9_GPIO0 \ + ESP32_PINMUX(0, ESP_NOSIG, ESP_LEDC_HS_SIG_OUT1) + +#define LEDC_CH9_GPIO1 \ + ESP32_PINMUX(1, ESP_NOSIG, ESP_LEDC_HS_SIG_OUT1) + +#define LEDC_CH9_GPIO2 \ + ESP32_PINMUX(2, ESP_NOSIG, ESP_LEDC_HS_SIG_OUT1) + +#define LEDC_CH9_GPIO3 \ + ESP32_PINMUX(3, ESP_NOSIG, ESP_LEDC_HS_SIG_OUT1) + +#define LEDC_CH9_GPIO4 \ + ESP32_PINMUX(4, ESP_NOSIG, ESP_LEDC_HS_SIG_OUT1) + +#define LEDC_CH9_GPIO5 \ + ESP32_PINMUX(5, ESP_NOSIG, ESP_LEDC_HS_SIG_OUT1) + +#define LEDC_CH9_GPIO6 \ + ESP32_PINMUX(6, ESP_NOSIG, ESP_LEDC_HS_SIG_OUT1) + +#define LEDC_CH9_GPIO7 \ + ESP32_PINMUX(7, ESP_NOSIG, ESP_LEDC_HS_SIG_OUT1) + +#define LEDC_CH9_GPIO8 \ + ESP32_PINMUX(8, ESP_NOSIG, ESP_LEDC_HS_SIG_OUT1) + +#define LEDC_CH9_GPIO9 \ + ESP32_PINMUX(9, ESP_NOSIG, ESP_LEDC_HS_SIG_OUT1) + +#define LEDC_CH9_GPIO10 \ + ESP32_PINMUX(10, ESP_NOSIG, ESP_LEDC_HS_SIG_OUT1) + +#define LEDC_CH9_GPIO11 \ + ESP32_PINMUX(11, ESP_NOSIG, ESP_LEDC_HS_SIG_OUT1) + +#define LEDC_CH9_GPIO12 \ + ESP32_PINMUX(12, ESP_NOSIG, ESP_LEDC_HS_SIG_OUT1) + +#define LEDC_CH9_GPIO13 \ + ESP32_PINMUX(13, ESP_NOSIG, ESP_LEDC_HS_SIG_OUT1) + +#define LEDC_CH9_GPIO14 \ + ESP32_PINMUX(14, ESP_NOSIG, ESP_LEDC_HS_SIG_OUT1) + +#define LEDC_CH9_GPIO15 \ + ESP32_PINMUX(15, ESP_NOSIG, ESP_LEDC_HS_SIG_OUT1) + +#define LEDC_CH9_GPIO16 \ + ESP32_PINMUX(16, ESP_NOSIG, ESP_LEDC_HS_SIG_OUT1) + +#define LEDC_CH9_GPIO17 \ + ESP32_PINMUX(17, ESP_NOSIG, ESP_LEDC_HS_SIG_OUT1) + +#define LEDC_CH9_GPIO18 \ + ESP32_PINMUX(18, ESP_NOSIG, ESP_LEDC_HS_SIG_OUT1) + +#define LEDC_CH9_GPIO19 \ + ESP32_PINMUX(19, ESP_NOSIG, ESP_LEDC_HS_SIG_OUT1) + +#define LEDC_CH9_GPIO20 \ + ESP32_PINMUX(20, ESP_NOSIG, ESP_LEDC_HS_SIG_OUT1) + +#define LEDC_CH9_GPIO21 \ + ESP32_PINMUX(21, ESP_NOSIG, ESP_LEDC_HS_SIG_OUT1) + +#define LEDC_CH9_GPIO22 \ + ESP32_PINMUX(22, ESP_NOSIG, ESP_LEDC_HS_SIG_OUT1) + +#define LEDC_CH9_GPIO23 \ + ESP32_PINMUX(23, ESP_NOSIG, ESP_LEDC_HS_SIG_OUT1) + +#define LEDC_CH9_GPIO25 \ + ESP32_PINMUX(25, ESP_NOSIG, ESP_LEDC_HS_SIG_OUT1) + +#define LEDC_CH9_GPIO26 \ + ESP32_PINMUX(26, ESP_NOSIG, ESP_LEDC_HS_SIG_OUT1) + +#define LEDC_CH9_GPIO27 \ + ESP32_PINMUX(27, ESP_NOSIG, ESP_LEDC_HS_SIG_OUT1) + +#define LEDC_CH9_GPIO32 \ + ESP32_PINMUX(32, ESP_NOSIG, ESP_LEDC_HS_SIG_OUT1) + +#define LEDC_CH9_GPIO33 \ + ESP32_PINMUX(33, ESP_NOSIG, ESP_LEDC_HS_SIG_OUT1) + +/* MCPWM0_CAP0 */ +#define MCPWM0_CAP0_GPIO0 \ + ESP32_PINMUX(0, ESP_PWM0_CAP0_IN, ESP_NOSIG) + +#define MCPWM0_CAP0_GPIO1 \ + ESP32_PINMUX(1, ESP_PWM0_CAP0_IN, ESP_NOSIG) + +#define MCPWM0_CAP0_GPIO2 \ + ESP32_PINMUX(2, ESP_PWM0_CAP0_IN, ESP_NOSIG) + +#define MCPWM0_CAP0_GPIO3 \ + ESP32_PINMUX(3, ESP_PWM0_CAP0_IN, ESP_NOSIG) + +#define MCPWM0_CAP0_GPIO4 \ + ESP32_PINMUX(4, ESP_PWM0_CAP0_IN, ESP_NOSIG) + +#define MCPWM0_CAP0_GPIO5 \ + ESP32_PINMUX(5, ESP_PWM0_CAP0_IN, ESP_NOSIG) + +#define MCPWM0_CAP0_GPIO6 \ + ESP32_PINMUX(6, ESP_PWM0_CAP0_IN, ESP_NOSIG) + +#define MCPWM0_CAP0_GPIO7 \ + ESP32_PINMUX(7, ESP_PWM0_CAP0_IN, ESP_NOSIG) + +#define MCPWM0_CAP0_GPIO8 \ + ESP32_PINMUX(8, ESP_PWM0_CAP0_IN, ESP_NOSIG) + +#define MCPWM0_CAP0_GPIO9 \ + ESP32_PINMUX(9, ESP_PWM0_CAP0_IN, ESP_NOSIG) + +#define MCPWM0_CAP0_GPIO10 \ + ESP32_PINMUX(10, ESP_PWM0_CAP0_IN, ESP_NOSIG) + +#define MCPWM0_CAP0_GPIO11 \ + ESP32_PINMUX(11, ESP_PWM0_CAP0_IN, ESP_NOSIG) + +#define MCPWM0_CAP0_GPIO12 \ + ESP32_PINMUX(12, ESP_PWM0_CAP0_IN, ESP_NOSIG) + +#define MCPWM0_CAP0_GPIO13 \ + ESP32_PINMUX(13, ESP_PWM0_CAP0_IN, ESP_NOSIG) + +#define MCPWM0_CAP0_GPIO14 \ + ESP32_PINMUX(14, ESP_PWM0_CAP0_IN, ESP_NOSIG) + +#define MCPWM0_CAP0_GPIO15 \ + ESP32_PINMUX(15, ESP_PWM0_CAP0_IN, ESP_NOSIG) + +#define MCPWM0_CAP0_GPIO16 \ + ESP32_PINMUX(16, ESP_PWM0_CAP0_IN, ESP_NOSIG) + +#define MCPWM0_CAP0_GPIO17 \ + ESP32_PINMUX(17, ESP_PWM0_CAP0_IN, ESP_NOSIG) + +#define MCPWM0_CAP0_GPIO18 \ + ESP32_PINMUX(18, ESP_PWM0_CAP0_IN, ESP_NOSIG) + +#define MCPWM0_CAP0_GPIO19 \ + ESP32_PINMUX(19, ESP_PWM0_CAP0_IN, ESP_NOSIG) + +#define MCPWM0_CAP0_GPIO20 \ + ESP32_PINMUX(20, ESP_PWM0_CAP0_IN, ESP_NOSIG) + +#define MCPWM0_CAP0_GPIO21 \ + ESP32_PINMUX(21, ESP_PWM0_CAP0_IN, ESP_NOSIG) + +#define MCPWM0_CAP0_GPIO22 \ + ESP32_PINMUX(22, ESP_PWM0_CAP0_IN, ESP_NOSIG) + +#define MCPWM0_CAP0_GPIO23 \ + ESP32_PINMUX(23, ESP_PWM0_CAP0_IN, ESP_NOSIG) + +#define MCPWM0_CAP0_GPIO25 \ + ESP32_PINMUX(25, ESP_PWM0_CAP0_IN, ESP_NOSIG) + +#define MCPWM0_CAP0_GPIO26 \ + ESP32_PINMUX(26, ESP_PWM0_CAP0_IN, ESP_NOSIG) + +#define MCPWM0_CAP0_GPIO27 \ + ESP32_PINMUX(27, ESP_PWM0_CAP0_IN, ESP_NOSIG) + +#define MCPWM0_CAP0_GPIO32 \ + ESP32_PINMUX(32, ESP_PWM0_CAP0_IN, ESP_NOSIG) + +#define MCPWM0_CAP0_GPIO33 \ + ESP32_PINMUX(33, ESP_PWM0_CAP0_IN, ESP_NOSIG) + +#define MCPWM0_CAP0_GPIO34 \ + ESP32_PINMUX(34, ESP_PWM0_CAP0_IN, ESP_NOSIG) + +#define MCPWM0_CAP0_GPIO35 \ + ESP32_PINMUX(35, ESP_PWM0_CAP0_IN, ESP_NOSIG) + +#define MCPWM0_CAP0_GPIO36 \ + ESP32_PINMUX(36, ESP_PWM0_CAP0_IN, ESP_NOSIG) + +#define MCPWM0_CAP0_GPIO37 \ + ESP32_PINMUX(37, ESP_PWM0_CAP0_IN, ESP_NOSIG) + +#define MCPWM0_CAP0_GPIO38 \ + ESP32_PINMUX(38, ESP_PWM0_CAP0_IN, ESP_NOSIG) + +#define MCPWM0_CAP0_GPIO39 \ + ESP32_PINMUX(39, ESP_PWM0_CAP0_IN, ESP_NOSIG) + +/* MCPWM0_CAP1 */ +#define MCPWM0_CAP1_GPIO0 \ + ESP32_PINMUX(0, ESP_PWM0_CAP1_IN, ESP_NOSIG) + +#define MCPWM0_CAP1_GPIO1 \ + ESP32_PINMUX(1, ESP_PWM0_CAP1_IN, ESP_NOSIG) + +#define MCPWM0_CAP1_GPIO2 \ + ESP32_PINMUX(2, ESP_PWM0_CAP1_IN, ESP_NOSIG) + +#define MCPWM0_CAP1_GPIO3 \ + ESP32_PINMUX(3, ESP_PWM0_CAP1_IN, ESP_NOSIG) + +#define MCPWM0_CAP1_GPIO4 \ + ESP32_PINMUX(4, ESP_PWM0_CAP1_IN, ESP_NOSIG) + +#define MCPWM0_CAP1_GPIO5 \ + ESP32_PINMUX(5, ESP_PWM0_CAP1_IN, ESP_NOSIG) + +#define MCPWM0_CAP1_GPIO6 \ + ESP32_PINMUX(6, ESP_PWM0_CAP1_IN, ESP_NOSIG) + +#define MCPWM0_CAP1_GPIO7 \ + ESP32_PINMUX(7, ESP_PWM0_CAP1_IN, ESP_NOSIG) + +#define MCPWM0_CAP1_GPIO8 \ + ESP32_PINMUX(8, ESP_PWM0_CAP1_IN, ESP_NOSIG) + +#define MCPWM0_CAP1_GPIO9 \ + ESP32_PINMUX(9, ESP_PWM0_CAP1_IN, ESP_NOSIG) + +#define MCPWM0_CAP1_GPIO10 \ + ESP32_PINMUX(10, ESP_PWM0_CAP1_IN, ESP_NOSIG) + +#define MCPWM0_CAP1_GPIO11 \ + ESP32_PINMUX(11, ESP_PWM0_CAP1_IN, ESP_NOSIG) + +#define MCPWM0_CAP1_GPIO12 \ + ESP32_PINMUX(12, ESP_PWM0_CAP1_IN, ESP_NOSIG) + +#define MCPWM0_CAP1_GPIO13 \ + ESP32_PINMUX(13, ESP_PWM0_CAP1_IN, ESP_NOSIG) + +#define MCPWM0_CAP1_GPIO14 \ + ESP32_PINMUX(14, ESP_PWM0_CAP1_IN, ESP_NOSIG) + +#define MCPWM0_CAP1_GPIO15 \ + ESP32_PINMUX(15, ESP_PWM0_CAP1_IN, ESP_NOSIG) + +#define MCPWM0_CAP1_GPIO16 \ + ESP32_PINMUX(16, ESP_PWM0_CAP1_IN, ESP_NOSIG) + +#define MCPWM0_CAP1_GPIO17 \ + ESP32_PINMUX(17, ESP_PWM0_CAP1_IN, ESP_NOSIG) + +#define MCPWM0_CAP1_GPIO18 \ + ESP32_PINMUX(18, ESP_PWM0_CAP1_IN, ESP_NOSIG) + +#define MCPWM0_CAP1_GPIO19 \ + ESP32_PINMUX(19, ESP_PWM0_CAP1_IN, ESP_NOSIG) + +#define MCPWM0_CAP1_GPIO20 \ + ESP32_PINMUX(20, ESP_PWM0_CAP1_IN, ESP_NOSIG) + +#define MCPWM0_CAP1_GPIO21 \ + ESP32_PINMUX(21, ESP_PWM0_CAP1_IN, ESP_NOSIG) + +#define MCPWM0_CAP1_GPIO22 \ + ESP32_PINMUX(22, ESP_PWM0_CAP1_IN, ESP_NOSIG) + +#define MCPWM0_CAP1_GPIO23 \ + ESP32_PINMUX(23, ESP_PWM0_CAP1_IN, ESP_NOSIG) + +#define MCPWM0_CAP1_GPIO25 \ + ESP32_PINMUX(25, ESP_PWM0_CAP1_IN, ESP_NOSIG) + +#define MCPWM0_CAP1_GPIO26 \ + ESP32_PINMUX(26, ESP_PWM0_CAP1_IN, ESP_NOSIG) + +#define MCPWM0_CAP1_GPIO27 \ + ESP32_PINMUX(27, ESP_PWM0_CAP1_IN, ESP_NOSIG) + +#define MCPWM0_CAP1_GPIO32 \ + ESP32_PINMUX(32, ESP_PWM0_CAP1_IN, ESP_NOSIG) + +#define MCPWM0_CAP1_GPIO33 \ + ESP32_PINMUX(33, ESP_PWM0_CAP1_IN, ESP_NOSIG) + +#define MCPWM0_CAP1_GPIO34 \ + ESP32_PINMUX(34, ESP_PWM0_CAP1_IN, ESP_NOSIG) + +#define MCPWM0_CAP1_GPIO35 \ + ESP32_PINMUX(35, ESP_PWM0_CAP1_IN, ESP_NOSIG) + +#define MCPWM0_CAP1_GPIO36 \ + ESP32_PINMUX(36, ESP_PWM0_CAP1_IN, ESP_NOSIG) + +#define MCPWM0_CAP1_GPIO37 \ + ESP32_PINMUX(37, ESP_PWM0_CAP1_IN, ESP_NOSIG) + +#define MCPWM0_CAP1_GPIO38 \ + ESP32_PINMUX(38, ESP_PWM0_CAP1_IN, ESP_NOSIG) + +#define MCPWM0_CAP1_GPIO39 \ + ESP32_PINMUX(39, ESP_PWM0_CAP1_IN, ESP_NOSIG) + +/* MCPWM0_CAP2 */ +#define MCPWM0_CAP2_GPIO0 \ + ESP32_PINMUX(0, ESP_PWM0_CAP2_IN, ESP_NOSIG) + +#define MCPWM0_CAP2_GPIO1 \ + ESP32_PINMUX(1, ESP_PWM0_CAP2_IN, ESP_NOSIG) + +#define MCPWM0_CAP2_GPIO2 \ + ESP32_PINMUX(2, ESP_PWM0_CAP2_IN, ESP_NOSIG) + +#define MCPWM0_CAP2_GPIO3 \ + ESP32_PINMUX(3, ESP_PWM0_CAP2_IN, ESP_NOSIG) + +#define MCPWM0_CAP2_GPIO4 \ + ESP32_PINMUX(4, ESP_PWM0_CAP2_IN, ESP_NOSIG) + +#define MCPWM0_CAP2_GPIO5 \ + ESP32_PINMUX(5, ESP_PWM0_CAP2_IN, ESP_NOSIG) + +#define MCPWM0_CAP2_GPIO6 \ + ESP32_PINMUX(6, ESP_PWM0_CAP2_IN, ESP_NOSIG) + +#define MCPWM0_CAP2_GPIO7 \ + ESP32_PINMUX(7, ESP_PWM0_CAP2_IN, ESP_NOSIG) + +#define MCPWM0_CAP2_GPIO8 \ + ESP32_PINMUX(8, ESP_PWM0_CAP2_IN, ESP_NOSIG) + +#define MCPWM0_CAP2_GPIO9 \ + ESP32_PINMUX(9, ESP_PWM0_CAP2_IN, ESP_NOSIG) + +#define MCPWM0_CAP2_GPIO10 \ + ESP32_PINMUX(10, ESP_PWM0_CAP2_IN, ESP_NOSIG) + +#define MCPWM0_CAP2_GPIO11 \ + ESP32_PINMUX(11, ESP_PWM0_CAP2_IN, ESP_NOSIG) + +#define MCPWM0_CAP2_GPIO12 \ + ESP32_PINMUX(12, ESP_PWM0_CAP2_IN, ESP_NOSIG) + +#define MCPWM0_CAP2_GPIO13 \ + ESP32_PINMUX(13, ESP_PWM0_CAP2_IN, ESP_NOSIG) + +#define MCPWM0_CAP2_GPIO14 \ + ESP32_PINMUX(14, ESP_PWM0_CAP2_IN, ESP_NOSIG) + +#define MCPWM0_CAP2_GPIO15 \ + ESP32_PINMUX(15, ESP_PWM0_CAP2_IN, ESP_NOSIG) + +#define MCPWM0_CAP2_GPIO16 \ + ESP32_PINMUX(16, ESP_PWM0_CAP2_IN, ESP_NOSIG) + +#define MCPWM0_CAP2_GPIO17 \ + ESP32_PINMUX(17, ESP_PWM0_CAP2_IN, ESP_NOSIG) + +#define MCPWM0_CAP2_GPIO18 \ + ESP32_PINMUX(18, ESP_PWM0_CAP2_IN, ESP_NOSIG) + +#define MCPWM0_CAP2_GPIO19 \ + ESP32_PINMUX(19, ESP_PWM0_CAP2_IN, ESP_NOSIG) + +#define MCPWM0_CAP2_GPIO20 \ + ESP32_PINMUX(20, ESP_PWM0_CAP2_IN, ESP_NOSIG) + +#define MCPWM0_CAP2_GPIO21 \ + ESP32_PINMUX(21, ESP_PWM0_CAP2_IN, ESP_NOSIG) + +#define MCPWM0_CAP2_GPIO22 \ + ESP32_PINMUX(22, ESP_PWM0_CAP2_IN, ESP_NOSIG) + +#define MCPWM0_CAP2_GPIO23 \ + ESP32_PINMUX(23, ESP_PWM0_CAP2_IN, ESP_NOSIG) + +#define MCPWM0_CAP2_GPIO25 \ + ESP32_PINMUX(25, ESP_PWM0_CAP2_IN, ESP_NOSIG) + +#define MCPWM0_CAP2_GPIO26 \ + ESP32_PINMUX(26, ESP_PWM0_CAP2_IN, ESP_NOSIG) + +#define MCPWM0_CAP2_GPIO27 \ + ESP32_PINMUX(27, ESP_PWM0_CAP2_IN, ESP_NOSIG) + +#define MCPWM0_CAP2_GPIO32 \ + ESP32_PINMUX(32, ESP_PWM0_CAP2_IN, ESP_NOSIG) + +#define MCPWM0_CAP2_GPIO33 \ + ESP32_PINMUX(33, ESP_PWM0_CAP2_IN, ESP_NOSIG) + +#define MCPWM0_CAP2_GPIO34 \ + ESP32_PINMUX(34, ESP_PWM0_CAP2_IN, ESP_NOSIG) + +#define MCPWM0_CAP2_GPIO35 \ + ESP32_PINMUX(35, ESP_PWM0_CAP2_IN, ESP_NOSIG) + +#define MCPWM0_CAP2_GPIO36 \ + ESP32_PINMUX(36, ESP_PWM0_CAP2_IN, ESP_NOSIG) + +#define MCPWM0_CAP2_GPIO37 \ + ESP32_PINMUX(37, ESP_PWM0_CAP2_IN, ESP_NOSIG) + +#define MCPWM0_CAP2_GPIO38 \ + ESP32_PINMUX(38, ESP_PWM0_CAP2_IN, ESP_NOSIG) + +#define MCPWM0_CAP2_GPIO39 \ + ESP32_PINMUX(39, ESP_PWM0_CAP2_IN, ESP_NOSIG) + +/* MCPWM0_FAULT0 */ +#define MCPWM0_FAULT0_GPIO0 \ + ESP32_PINMUX(0, ESP_PWM0_F0_IN, ESP_NOSIG) + +#define MCPWM0_FAULT0_GPIO1 \ + ESP32_PINMUX(1, ESP_PWM0_F0_IN, ESP_NOSIG) + +#define MCPWM0_FAULT0_GPIO2 \ + ESP32_PINMUX(2, ESP_PWM0_F0_IN, ESP_NOSIG) + +#define MCPWM0_FAULT0_GPIO3 \ + ESP32_PINMUX(3, ESP_PWM0_F0_IN, ESP_NOSIG) + +#define MCPWM0_FAULT0_GPIO4 \ + ESP32_PINMUX(4, ESP_PWM0_F0_IN, ESP_NOSIG) + +#define MCPWM0_FAULT0_GPIO5 \ + ESP32_PINMUX(5, ESP_PWM0_F0_IN, ESP_NOSIG) + +#define MCPWM0_FAULT0_GPIO6 \ + ESP32_PINMUX(6, ESP_PWM0_F0_IN, ESP_NOSIG) + +#define MCPWM0_FAULT0_GPIO7 \ + ESP32_PINMUX(7, ESP_PWM0_F0_IN, ESP_NOSIG) + +#define MCPWM0_FAULT0_GPIO8 \ + ESP32_PINMUX(8, ESP_PWM0_F0_IN, ESP_NOSIG) + +#define MCPWM0_FAULT0_GPIO9 \ + ESP32_PINMUX(9, ESP_PWM0_F0_IN, ESP_NOSIG) + +#define MCPWM0_FAULT0_GPIO10 \ + ESP32_PINMUX(10, ESP_PWM0_F0_IN, ESP_NOSIG) + +#define MCPWM0_FAULT0_GPIO11 \ + ESP32_PINMUX(11, ESP_PWM0_F0_IN, ESP_NOSIG) + +#define MCPWM0_FAULT0_GPIO12 \ + ESP32_PINMUX(12, ESP_PWM0_F0_IN, ESP_NOSIG) + +#define MCPWM0_FAULT0_GPIO13 \ + ESP32_PINMUX(13, ESP_PWM0_F0_IN, ESP_NOSIG) + +#define MCPWM0_FAULT0_GPIO14 \ + ESP32_PINMUX(14, ESP_PWM0_F0_IN, ESP_NOSIG) + +#define MCPWM0_FAULT0_GPIO15 \ + ESP32_PINMUX(15, ESP_PWM0_F0_IN, ESP_NOSIG) + +#define MCPWM0_FAULT0_GPIO16 \ + ESP32_PINMUX(16, ESP_PWM0_F0_IN, ESP_NOSIG) + +#define MCPWM0_FAULT0_GPIO17 \ + ESP32_PINMUX(17, ESP_PWM0_F0_IN, ESP_NOSIG) + +#define MCPWM0_FAULT0_GPIO18 \ + ESP32_PINMUX(18, ESP_PWM0_F0_IN, ESP_NOSIG) + +#define MCPWM0_FAULT0_GPIO19 \ + ESP32_PINMUX(19, ESP_PWM0_F0_IN, ESP_NOSIG) + +#define MCPWM0_FAULT0_GPIO20 \ + ESP32_PINMUX(20, ESP_PWM0_F0_IN, ESP_NOSIG) + +#define MCPWM0_FAULT0_GPIO21 \ + ESP32_PINMUX(21, ESP_PWM0_F0_IN, ESP_NOSIG) + +#define MCPWM0_FAULT0_GPIO22 \ + ESP32_PINMUX(22, ESP_PWM0_F0_IN, ESP_NOSIG) + +#define MCPWM0_FAULT0_GPIO23 \ + ESP32_PINMUX(23, ESP_PWM0_F0_IN, ESP_NOSIG) + +#define MCPWM0_FAULT0_GPIO25 \ + ESP32_PINMUX(25, ESP_PWM0_F0_IN, ESP_NOSIG) + +#define MCPWM0_FAULT0_GPIO26 \ + ESP32_PINMUX(26, ESP_PWM0_F0_IN, ESP_NOSIG) + +#define MCPWM0_FAULT0_GPIO27 \ + ESP32_PINMUX(27, ESP_PWM0_F0_IN, ESP_NOSIG) + +#define MCPWM0_FAULT0_GPIO32 \ + ESP32_PINMUX(32, ESP_PWM0_F0_IN, ESP_NOSIG) + +#define MCPWM0_FAULT0_GPIO33 \ + ESP32_PINMUX(33, ESP_PWM0_F0_IN, ESP_NOSIG) + +#define MCPWM0_FAULT0_GPIO34 \ + ESP32_PINMUX(34, ESP_PWM0_F0_IN, ESP_NOSIG) + +#define MCPWM0_FAULT0_GPIO35 \ + ESP32_PINMUX(35, ESP_PWM0_F0_IN, ESP_NOSIG) + +#define MCPWM0_FAULT0_GPIO36 \ + ESP32_PINMUX(36, ESP_PWM0_F0_IN, ESP_NOSIG) + +#define MCPWM0_FAULT0_GPIO37 \ + ESP32_PINMUX(37, ESP_PWM0_F0_IN, ESP_NOSIG) + +#define MCPWM0_FAULT0_GPIO38 \ + ESP32_PINMUX(38, ESP_PWM0_F0_IN, ESP_NOSIG) + +#define MCPWM0_FAULT0_GPIO39 \ + ESP32_PINMUX(39, ESP_PWM0_F0_IN, ESP_NOSIG) + +/* MCPWM0_FAULT1 */ +#define MCPWM0_FAULT1_GPIO0 \ + ESP32_PINMUX(0, ESP_PWM0_F1_IN, ESP_NOSIG) + +#define MCPWM0_FAULT1_GPIO1 \ + ESP32_PINMUX(1, ESP_PWM0_F1_IN, ESP_NOSIG) + +#define MCPWM0_FAULT1_GPIO2 \ + ESP32_PINMUX(2, ESP_PWM0_F1_IN, ESP_NOSIG) + +#define MCPWM0_FAULT1_GPIO3 \ + ESP32_PINMUX(3, ESP_PWM0_F1_IN, ESP_NOSIG) + +#define MCPWM0_FAULT1_GPIO4 \ + ESP32_PINMUX(4, ESP_PWM0_F1_IN, ESP_NOSIG) + +#define MCPWM0_FAULT1_GPIO5 \ + ESP32_PINMUX(5, ESP_PWM0_F1_IN, ESP_NOSIG) + +#define MCPWM0_FAULT1_GPIO6 \ + ESP32_PINMUX(6, ESP_PWM0_F1_IN, ESP_NOSIG) + +#define MCPWM0_FAULT1_GPIO7 \ + ESP32_PINMUX(7, ESP_PWM0_F1_IN, ESP_NOSIG) + +#define MCPWM0_FAULT1_GPIO8 \ + ESP32_PINMUX(8, ESP_PWM0_F1_IN, ESP_NOSIG) + +#define MCPWM0_FAULT1_GPIO9 \ + ESP32_PINMUX(9, ESP_PWM0_F1_IN, ESP_NOSIG) + +#define MCPWM0_FAULT1_GPIO10 \ + ESP32_PINMUX(10, ESP_PWM0_F1_IN, ESP_NOSIG) + +#define MCPWM0_FAULT1_GPIO11 \ + ESP32_PINMUX(11, ESP_PWM0_F1_IN, ESP_NOSIG) + +#define MCPWM0_FAULT1_GPIO12 \ + ESP32_PINMUX(12, ESP_PWM0_F1_IN, ESP_NOSIG) + +#define MCPWM0_FAULT1_GPIO13 \ + ESP32_PINMUX(13, ESP_PWM0_F1_IN, ESP_NOSIG) + +#define MCPWM0_FAULT1_GPIO14 \ + ESP32_PINMUX(14, ESP_PWM0_F1_IN, ESP_NOSIG) + +#define MCPWM0_FAULT1_GPIO15 \ + ESP32_PINMUX(15, ESP_PWM0_F1_IN, ESP_NOSIG) + +#define MCPWM0_FAULT1_GPIO16 \ + ESP32_PINMUX(16, ESP_PWM0_F1_IN, ESP_NOSIG) + +#define MCPWM0_FAULT1_GPIO17 \ + ESP32_PINMUX(17, ESP_PWM0_F1_IN, ESP_NOSIG) + +#define MCPWM0_FAULT1_GPIO18 \ + ESP32_PINMUX(18, ESP_PWM0_F1_IN, ESP_NOSIG) + +#define MCPWM0_FAULT1_GPIO19 \ + ESP32_PINMUX(19, ESP_PWM0_F1_IN, ESP_NOSIG) + +#define MCPWM0_FAULT1_GPIO20 \ + ESP32_PINMUX(20, ESP_PWM0_F1_IN, ESP_NOSIG) + +#define MCPWM0_FAULT1_GPIO21 \ + ESP32_PINMUX(21, ESP_PWM0_F1_IN, ESP_NOSIG) + +#define MCPWM0_FAULT1_GPIO22 \ + ESP32_PINMUX(22, ESP_PWM0_F1_IN, ESP_NOSIG) + +#define MCPWM0_FAULT1_GPIO23 \ + ESP32_PINMUX(23, ESP_PWM0_F1_IN, ESP_NOSIG) + +#define MCPWM0_FAULT1_GPIO25 \ + ESP32_PINMUX(25, ESP_PWM0_F1_IN, ESP_NOSIG) + +#define MCPWM0_FAULT1_GPIO26 \ + ESP32_PINMUX(26, ESP_PWM0_F1_IN, ESP_NOSIG) + +#define MCPWM0_FAULT1_GPIO27 \ + ESP32_PINMUX(27, ESP_PWM0_F1_IN, ESP_NOSIG) + +#define MCPWM0_FAULT1_GPIO32 \ + ESP32_PINMUX(32, ESP_PWM0_F1_IN, ESP_NOSIG) + +#define MCPWM0_FAULT1_GPIO33 \ + ESP32_PINMUX(33, ESP_PWM0_F1_IN, ESP_NOSIG) + +#define MCPWM0_FAULT1_GPIO34 \ + ESP32_PINMUX(34, ESP_PWM0_F1_IN, ESP_NOSIG) + +#define MCPWM0_FAULT1_GPIO35 \ + ESP32_PINMUX(35, ESP_PWM0_F1_IN, ESP_NOSIG) + +#define MCPWM0_FAULT1_GPIO36 \ + ESP32_PINMUX(36, ESP_PWM0_F1_IN, ESP_NOSIG) + +#define MCPWM0_FAULT1_GPIO37 \ + ESP32_PINMUX(37, ESP_PWM0_F1_IN, ESP_NOSIG) + +#define MCPWM0_FAULT1_GPIO38 \ + ESP32_PINMUX(38, ESP_PWM0_F1_IN, ESP_NOSIG) + +#define MCPWM0_FAULT1_GPIO39 \ + ESP32_PINMUX(39, ESP_PWM0_F1_IN, ESP_NOSIG) + +/* MCPWM0_FAULT2 */ +#define MCPWM0_FAULT2_GPIO0 \ + ESP32_PINMUX(0, ESP_PWM0_F2_IN, ESP_NOSIG) + +#define MCPWM0_FAULT2_GPIO1 \ + ESP32_PINMUX(1, ESP_PWM0_F2_IN, ESP_NOSIG) + +#define MCPWM0_FAULT2_GPIO2 \ + ESP32_PINMUX(2, ESP_PWM0_F2_IN, ESP_NOSIG) + +#define MCPWM0_FAULT2_GPIO3 \ + ESP32_PINMUX(3, ESP_PWM0_F2_IN, ESP_NOSIG) + +#define MCPWM0_FAULT2_GPIO4 \ + ESP32_PINMUX(4, ESP_PWM0_F2_IN, ESP_NOSIG) + +#define MCPWM0_FAULT2_GPIO5 \ + ESP32_PINMUX(5, ESP_PWM0_F2_IN, ESP_NOSIG) + +#define MCPWM0_FAULT2_GPIO6 \ + ESP32_PINMUX(6, ESP_PWM0_F2_IN, ESP_NOSIG) + +#define MCPWM0_FAULT2_GPIO7 \ + ESP32_PINMUX(7, ESP_PWM0_F2_IN, ESP_NOSIG) + +#define MCPWM0_FAULT2_GPIO8 \ + ESP32_PINMUX(8, ESP_PWM0_F2_IN, ESP_NOSIG) + +#define MCPWM0_FAULT2_GPIO9 \ + ESP32_PINMUX(9, ESP_PWM0_F2_IN, ESP_NOSIG) + +#define MCPWM0_FAULT2_GPIO10 \ + ESP32_PINMUX(10, ESP_PWM0_F2_IN, ESP_NOSIG) + +#define MCPWM0_FAULT2_GPIO11 \ + ESP32_PINMUX(11, ESP_PWM0_F2_IN, ESP_NOSIG) + +#define MCPWM0_FAULT2_GPIO12 \ + ESP32_PINMUX(12, ESP_PWM0_F2_IN, ESP_NOSIG) + +#define MCPWM0_FAULT2_GPIO13 \ + ESP32_PINMUX(13, ESP_PWM0_F2_IN, ESP_NOSIG) + +#define MCPWM0_FAULT2_GPIO14 \ + ESP32_PINMUX(14, ESP_PWM0_F2_IN, ESP_NOSIG) + +#define MCPWM0_FAULT2_GPIO15 \ + ESP32_PINMUX(15, ESP_PWM0_F2_IN, ESP_NOSIG) + +#define MCPWM0_FAULT2_GPIO16 \ + ESP32_PINMUX(16, ESP_PWM0_F2_IN, ESP_NOSIG) + +#define MCPWM0_FAULT2_GPIO17 \ + ESP32_PINMUX(17, ESP_PWM0_F2_IN, ESP_NOSIG) + +#define MCPWM0_FAULT2_GPIO18 \ + ESP32_PINMUX(18, ESP_PWM0_F2_IN, ESP_NOSIG) + +#define MCPWM0_FAULT2_GPIO19 \ + ESP32_PINMUX(19, ESP_PWM0_F2_IN, ESP_NOSIG) + +#define MCPWM0_FAULT2_GPIO20 \ + ESP32_PINMUX(20, ESP_PWM0_F2_IN, ESP_NOSIG) + +#define MCPWM0_FAULT2_GPIO21 \ + ESP32_PINMUX(21, ESP_PWM0_F2_IN, ESP_NOSIG) + +#define MCPWM0_FAULT2_GPIO22 \ + ESP32_PINMUX(22, ESP_PWM0_F2_IN, ESP_NOSIG) + +#define MCPWM0_FAULT2_GPIO23 \ + ESP32_PINMUX(23, ESP_PWM0_F2_IN, ESP_NOSIG) + +#define MCPWM0_FAULT2_GPIO25 \ + ESP32_PINMUX(25, ESP_PWM0_F2_IN, ESP_NOSIG) + +#define MCPWM0_FAULT2_GPIO26 \ + ESP32_PINMUX(26, ESP_PWM0_F2_IN, ESP_NOSIG) + +#define MCPWM0_FAULT2_GPIO27 \ + ESP32_PINMUX(27, ESP_PWM0_F2_IN, ESP_NOSIG) + +#define MCPWM0_FAULT2_GPIO32 \ + ESP32_PINMUX(32, ESP_PWM0_F2_IN, ESP_NOSIG) + +#define MCPWM0_FAULT2_GPIO33 \ + ESP32_PINMUX(33, ESP_PWM0_F2_IN, ESP_NOSIG) + +#define MCPWM0_FAULT2_GPIO34 \ + ESP32_PINMUX(34, ESP_PWM0_F2_IN, ESP_NOSIG) + +#define MCPWM0_FAULT2_GPIO35 \ + ESP32_PINMUX(35, ESP_PWM0_F2_IN, ESP_NOSIG) + +#define MCPWM0_FAULT2_GPIO36 \ + ESP32_PINMUX(36, ESP_PWM0_F2_IN, ESP_NOSIG) + +#define MCPWM0_FAULT2_GPIO37 \ + ESP32_PINMUX(37, ESP_PWM0_F2_IN, ESP_NOSIG) + +#define MCPWM0_FAULT2_GPIO38 \ + ESP32_PINMUX(38, ESP_PWM0_F2_IN, ESP_NOSIG) + +#define MCPWM0_FAULT2_GPIO39 \ + ESP32_PINMUX(39, ESP_PWM0_F2_IN, ESP_NOSIG) + +/* MCPWM0_OUT0A */ +#define MCPWM0_OUT0A_GPIO0 \ + ESP32_PINMUX(0, ESP_NOSIG, ESP_PWM0_OUT0A) + +#define MCPWM0_OUT0A_GPIO1 \ + ESP32_PINMUX(1, ESP_NOSIG, ESP_PWM0_OUT0A) + +#define MCPWM0_OUT0A_GPIO2 \ + ESP32_PINMUX(2, ESP_NOSIG, ESP_PWM0_OUT0A) + +#define MCPWM0_OUT0A_GPIO3 \ + ESP32_PINMUX(3, ESP_NOSIG, ESP_PWM0_OUT0A) + +#define MCPWM0_OUT0A_GPIO4 \ + ESP32_PINMUX(4, ESP_NOSIG, ESP_PWM0_OUT0A) + +#define MCPWM0_OUT0A_GPIO5 \ + ESP32_PINMUX(5, ESP_NOSIG, ESP_PWM0_OUT0A) + +#define MCPWM0_OUT0A_GPIO6 \ + ESP32_PINMUX(6, ESP_NOSIG, ESP_PWM0_OUT0A) + +#define MCPWM0_OUT0A_GPIO7 \ + ESP32_PINMUX(7, ESP_NOSIG, ESP_PWM0_OUT0A) + +#define MCPWM0_OUT0A_GPIO8 \ + ESP32_PINMUX(8, ESP_NOSIG, ESP_PWM0_OUT0A) + +#define MCPWM0_OUT0A_GPIO9 \ + ESP32_PINMUX(9, ESP_NOSIG, ESP_PWM0_OUT0A) + +#define MCPWM0_OUT0A_GPIO10 \ + ESP32_PINMUX(10, ESP_NOSIG, ESP_PWM0_OUT0A) + +#define MCPWM0_OUT0A_GPIO11 \ + ESP32_PINMUX(11, ESP_NOSIG, ESP_PWM0_OUT0A) + +#define MCPWM0_OUT0A_GPIO12 \ + ESP32_PINMUX(12, ESP_NOSIG, ESP_PWM0_OUT0A) + +#define MCPWM0_OUT0A_GPIO13 \ + ESP32_PINMUX(13, ESP_NOSIG, ESP_PWM0_OUT0A) + +#define MCPWM0_OUT0A_GPIO14 \ + ESP32_PINMUX(14, ESP_NOSIG, ESP_PWM0_OUT0A) + +#define MCPWM0_OUT0A_GPIO15 \ + ESP32_PINMUX(15, ESP_NOSIG, ESP_PWM0_OUT0A) + +#define MCPWM0_OUT0A_GPIO16 \ + ESP32_PINMUX(16, ESP_NOSIG, ESP_PWM0_OUT0A) + +#define MCPWM0_OUT0A_GPIO17 \ + ESP32_PINMUX(17, ESP_NOSIG, ESP_PWM0_OUT0A) + +#define MCPWM0_OUT0A_GPIO18 \ + ESP32_PINMUX(18, ESP_NOSIG, ESP_PWM0_OUT0A) + +#define MCPWM0_OUT0A_GPIO19 \ + ESP32_PINMUX(19, ESP_NOSIG, ESP_PWM0_OUT0A) + +#define MCPWM0_OUT0A_GPIO20 \ + ESP32_PINMUX(20, ESP_NOSIG, ESP_PWM0_OUT0A) + +#define MCPWM0_OUT0A_GPIO21 \ + ESP32_PINMUX(21, ESP_NOSIG, ESP_PWM0_OUT0A) + +#define MCPWM0_OUT0A_GPIO22 \ + ESP32_PINMUX(22, ESP_NOSIG, ESP_PWM0_OUT0A) + +#define MCPWM0_OUT0A_GPIO23 \ + ESP32_PINMUX(23, ESP_NOSIG, ESP_PWM0_OUT0A) + +#define MCPWM0_OUT0A_GPIO25 \ + ESP32_PINMUX(25, ESP_NOSIG, ESP_PWM0_OUT0A) + +#define MCPWM0_OUT0A_GPIO26 \ + ESP32_PINMUX(26, ESP_NOSIG, ESP_PWM0_OUT0A) + +#define MCPWM0_OUT0A_GPIO27 \ + ESP32_PINMUX(27, ESP_NOSIG, ESP_PWM0_OUT0A) + +#define MCPWM0_OUT0A_GPIO32 \ + ESP32_PINMUX(32, ESP_NOSIG, ESP_PWM0_OUT0A) + +#define MCPWM0_OUT0A_GPIO33 \ + ESP32_PINMUX(33, ESP_NOSIG, ESP_PWM0_OUT0A) + +/* MCPWM0_OUT0B */ +#define MCPWM0_OUT0B_GPIO0 \ + ESP32_PINMUX(0, ESP_NOSIG, ESP_PWM0_OUT0B) + +#define MCPWM0_OUT0B_GPIO1 \ + ESP32_PINMUX(1, ESP_NOSIG, ESP_PWM0_OUT0B) + +#define MCPWM0_OUT0B_GPIO2 \ + ESP32_PINMUX(2, ESP_NOSIG, ESP_PWM0_OUT0B) + +#define MCPWM0_OUT0B_GPIO3 \ + ESP32_PINMUX(3, ESP_NOSIG, ESP_PWM0_OUT0B) + +#define MCPWM0_OUT0B_GPIO4 \ + ESP32_PINMUX(4, ESP_NOSIG, ESP_PWM0_OUT0B) + +#define MCPWM0_OUT0B_GPIO5 \ + ESP32_PINMUX(5, ESP_NOSIG, ESP_PWM0_OUT0B) + +#define MCPWM0_OUT0B_GPIO6 \ + ESP32_PINMUX(6, ESP_NOSIG, ESP_PWM0_OUT0B) + +#define MCPWM0_OUT0B_GPIO7 \ + ESP32_PINMUX(7, ESP_NOSIG, ESP_PWM0_OUT0B) + +#define MCPWM0_OUT0B_GPIO8 \ + ESP32_PINMUX(8, ESP_NOSIG, ESP_PWM0_OUT0B) + +#define MCPWM0_OUT0B_GPIO9 \ + ESP32_PINMUX(9, ESP_NOSIG, ESP_PWM0_OUT0B) + +#define MCPWM0_OUT0B_GPIO10 \ + ESP32_PINMUX(10, ESP_NOSIG, ESP_PWM0_OUT0B) + +#define MCPWM0_OUT0B_GPIO11 \ + ESP32_PINMUX(11, ESP_NOSIG, ESP_PWM0_OUT0B) + +#define MCPWM0_OUT0B_GPIO12 \ + ESP32_PINMUX(12, ESP_NOSIG, ESP_PWM0_OUT0B) + +#define MCPWM0_OUT0B_GPIO13 \ + ESP32_PINMUX(13, ESP_NOSIG, ESP_PWM0_OUT0B) + +#define MCPWM0_OUT0B_GPIO14 \ + ESP32_PINMUX(14, ESP_NOSIG, ESP_PWM0_OUT0B) + +#define MCPWM0_OUT0B_GPIO15 \ + ESP32_PINMUX(15, ESP_NOSIG, ESP_PWM0_OUT0B) + +#define MCPWM0_OUT0B_GPIO16 \ + ESP32_PINMUX(16, ESP_NOSIG, ESP_PWM0_OUT0B) + +#define MCPWM0_OUT0B_GPIO17 \ + ESP32_PINMUX(17, ESP_NOSIG, ESP_PWM0_OUT0B) + +#define MCPWM0_OUT0B_GPIO18 \ + ESP32_PINMUX(18, ESP_NOSIG, ESP_PWM0_OUT0B) + +#define MCPWM0_OUT0B_GPIO19 \ + ESP32_PINMUX(19, ESP_NOSIG, ESP_PWM0_OUT0B) + +#define MCPWM0_OUT0B_GPIO20 \ + ESP32_PINMUX(20, ESP_NOSIG, ESP_PWM0_OUT0B) + +#define MCPWM0_OUT0B_GPIO21 \ + ESP32_PINMUX(21, ESP_NOSIG, ESP_PWM0_OUT0B) + +#define MCPWM0_OUT0B_GPIO22 \ + ESP32_PINMUX(22, ESP_NOSIG, ESP_PWM0_OUT0B) + +#define MCPWM0_OUT0B_GPIO23 \ + ESP32_PINMUX(23, ESP_NOSIG, ESP_PWM0_OUT0B) + +#define MCPWM0_OUT0B_GPIO25 \ + ESP32_PINMUX(25, ESP_NOSIG, ESP_PWM0_OUT0B) + +#define MCPWM0_OUT0B_GPIO26 \ + ESP32_PINMUX(26, ESP_NOSIG, ESP_PWM0_OUT0B) + +#define MCPWM0_OUT0B_GPIO27 \ + ESP32_PINMUX(27, ESP_NOSIG, ESP_PWM0_OUT0B) + +#define MCPWM0_OUT0B_GPIO32 \ + ESP32_PINMUX(32, ESP_NOSIG, ESP_PWM0_OUT0B) + +#define MCPWM0_OUT0B_GPIO33 \ + ESP32_PINMUX(33, ESP_NOSIG, ESP_PWM0_OUT0B) + +/* MCPWM0_OUT1A */ +#define MCPWM0_OUT1A_GPIO0 \ + ESP32_PINMUX(0, ESP_NOSIG, ESP_PWM0_OUT1A) + +#define MCPWM0_OUT1A_GPIO1 \ + ESP32_PINMUX(1, ESP_NOSIG, ESP_PWM0_OUT1A) + +#define MCPWM0_OUT1A_GPIO2 \ + ESP32_PINMUX(2, ESP_NOSIG, ESP_PWM0_OUT1A) + +#define MCPWM0_OUT1A_GPIO3 \ + ESP32_PINMUX(3, ESP_NOSIG, ESP_PWM0_OUT1A) + +#define MCPWM0_OUT1A_GPIO4 \ + ESP32_PINMUX(4, ESP_NOSIG, ESP_PWM0_OUT1A) + +#define MCPWM0_OUT1A_GPIO5 \ + ESP32_PINMUX(5, ESP_NOSIG, ESP_PWM0_OUT1A) + +#define MCPWM0_OUT1A_GPIO6 \ + ESP32_PINMUX(6, ESP_NOSIG, ESP_PWM0_OUT1A) + +#define MCPWM0_OUT1A_GPIO7 \ + ESP32_PINMUX(7, ESP_NOSIG, ESP_PWM0_OUT1A) + +#define MCPWM0_OUT1A_GPIO8 \ + ESP32_PINMUX(8, ESP_NOSIG, ESP_PWM0_OUT1A) + +#define MCPWM0_OUT1A_GPIO9 \ + ESP32_PINMUX(9, ESP_NOSIG, ESP_PWM0_OUT1A) + +#define MCPWM0_OUT1A_GPIO10 \ + ESP32_PINMUX(10, ESP_NOSIG, ESP_PWM0_OUT1A) + +#define MCPWM0_OUT1A_GPIO11 \ + ESP32_PINMUX(11, ESP_NOSIG, ESP_PWM0_OUT1A) + +#define MCPWM0_OUT1A_GPIO12 \ + ESP32_PINMUX(12, ESP_NOSIG, ESP_PWM0_OUT1A) + +#define MCPWM0_OUT1A_GPIO13 \ + ESP32_PINMUX(13, ESP_NOSIG, ESP_PWM0_OUT1A) + +#define MCPWM0_OUT1A_GPIO14 \ + ESP32_PINMUX(14, ESP_NOSIG, ESP_PWM0_OUT1A) + +#define MCPWM0_OUT1A_GPIO15 \ + ESP32_PINMUX(15, ESP_NOSIG, ESP_PWM0_OUT1A) + +#define MCPWM0_OUT1A_GPIO16 \ + ESP32_PINMUX(16, ESP_NOSIG, ESP_PWM0_OUT1A) + +#define MCPWM0_OUT1A_GPIO17 \ + ESP32_PINMUX(17, ESP_NOSIG, ESP_PWM0_OUT1A) + +#define MCPWM0_OUT1A_GPIO18 \ + ESP32_PINMUX(18, ESP_NOSIG, ESP_PWM0_OUT1A) + +#define MCPWM0_OUT1A_GPIO19 \ + ESP32_PINMUX(19, ESP_NOSIG, ESP_PWM0_OUT1A) + +#define MCPWM0_OUT1A_GPIO20 \ + ESP32_PINMUX(20, ESP_NOSIG, ESP_PWM0_OUT1A) + +#define MCPWM0_OUT1A_GPIO21 \ + ESP32_PINMUX(21, ESP_NOSIG, ESP_PWM0_OUT1A) + +#define MCPWM0_OUT1A_GPIO22 \ + ESP32_PINMUX(22, ESP_NOSIG, ESP_PWM0_OUT1A) + +#define MCPWM0_OUT1A_GPIO23 \ + ESP32_PINMUX(23, ESP_NOSIG, ESP_PWM0_OUT1A) + +#define MCPWM0_OUT1A_GPIO25 \ + ESP32_PINMUX(25, ESP_NOSIG, ESP_PWM0_OUT1A) + +#define MCPWM0_OUT1A_GPIO26 \ + ESP32_PINMUX(26, ESP_NOSIG, ESP_PWM0_OUT1A) + +#define MCPWM0_OUT1A_GPIO27 \ + ESP32_PINMUX(27, ESP_NOSIG, ESP_PWM0_OUT1A) + +#define MCPWM0_OUT1A_GPIO32 \ + ESP32_PINMUX(32, ESP_NOSIG, ESP_PWM0_OUT1A) + +#define MCPWM0_OUT1A_GPIO33 \ + ESP32_PINMUX(33, ESP_NOSIG, ESP_PWM0_OUT1A) + +/* MCPWM0_OUT1B */ +#define MCPWM0_OUT1B_GPIO0 \ + ESP32_PINMUX(0, ESP_NOSIG, ESP_PWM0_OUT1B) + +#define MCPWM0_OUT1B_GPIO1 \ + ESP32_PINMUX(1, ESP_NOSIG, ESP_PWM0_OUT1B) + +#define MCPWM0_OUT1B_GPIO2 \ + ESP32_PINMUX(2, ESP_NOSIG, ESP_PWM0_OUT1B) + +#define MCPWM0_OUT1B_GPIO3 \ + ESP32_PINMUX(3, ESP_NOSIG, ESP_PWM0_OUT1B) + +#define MCPWM0_OUT1B_GPIO4 \ + ESP32_PINMUX(4, ESP_NOSIG, ESP_PWM0_OUT1B) + +#define MCPWM0_OUT1B_GPIO5 \ + ESP32_PINMUX(5, ESP_NOSIG, ESP_PWM0_OUT1B) + +#define MCPWM0_OUT1B_GPIO6 \ + ESP32_PINMUX(6, ESP_NOSIG, ESP_PWM0_OUT1B) + +#define MCPWM0_OUT1B_GPIO7 \ + ESP32_PINMUX(7, ESP_NOSIG, ESP_PWM0_OUT1B) + +#define MCPWM0_OUT1B_GPIO8 \ + ESP32_PINMUX(8, ESP_NOSIG, ESP_PWM0_OUT1B) + +#define MCPWM0_OUT1B_GPIO9 \ + ESP32_PINMUX(9, ESP_NOSIG, ESP_PWM0_OUT1B) + +#define MCPWM0_OUT1B_GPIO10 \ + ESP32_PINMUX(10, ESP_NOSIG, ESP_PWM0_OUT1B) + +#define MCPWM0_OUT1B_GPIO11 \ + ESP32_PINMUX(11, ESP_NOSIG, ESP_PWM0_OUT1B) + +#define MCPWM0_OUT1B_GPIO12 \ + ESP32_PINMUX(12, ESP_NOSIG, ESP_PWM0_OUT1B) + +#define MCPWM0_OUT1B_GPIO13 \ + ESP32_PINMUX(13, ESP_NOSIG, ESP_PWM0_OUT1B) + +#define MCPWM0_OUT1B_GPIO14 \ + ESP32_PINMUX(14, ESP_NOSIG, ESP_PWM0_OUT1B) + +#define MCPWM0_OUT1B_GPIO15 \ + ESP32_PINMUX(15, ESP_NOSIG, ESP_PWM0_OUT1B) + +#define MCPWM0_OUT1B_GPIO16 \ + ESP32_PINMUX(16, ESP_NOSIG, ESP_PWM0_OUT1B) + +#define MCPWM0_OUT1B_GPIO17 \ + ESP32_PINMUX(17, ESP_NOSIG, ESP_PWM0_OUT1B) + +#define MCPWM0_OUT1B_GPIO18 \ + ESP32_PINMUX(18, ESP_NOSIG, ESP_PWM0_OUT1B) + +#define MCPWM0_OUT1B_GPIO19 \ + ESP32_PINMUX(19, ESP_NOSIG, ESP_PWM0_OUT1B) + +#define MCPWM0_OUT1B_GPIO20 \ + ESP32_PINMUX(20, ESP_NOSIG, ESP_PWM0_OUT1B) + +#define MCPWM0_OUT1B_GPIO21 \ + ESP32_PINMUX(21, ESP_NOSIG, ESP_PWM0_OUT1B) + +#define MCPWM0_OUT1B_GPIO22 \ + ESP32_PINMUX(22, ESP_NOSIG, ESP_PWM0_OUT1B) + +#define MCPWM0_OUT1B_GPIO23 \ + ESP32_PINMUX(23, ESP_NOSIG, ESP_PWM0_OUT1B) + +#define MCPWM0_OUT1B_GPIO25 \ + ESP32_PINMUX(25, ESP_NOSIG, ESP_PWM0_OUT1B) + +#define MCPWM0_OUT1B_GPIO26 \ + ESP32_PINMUX(26, ESP_NOSIG, ESP_PWM0_OUT1B) + +#define MCPWM0_OUT1B_GPIO27 \ + ESP32_PINMUX(27, ESP_NOSIG, ESP_PWM0_OUT1B) + +#define MCPWM0_OUT1B_GPIO32 \ + ESP32_PINMUX(32, ESP_NOSIG, ESP_PWM0_OUT1B) + +#define MCPWM0_OUT1B_GPIO33 \ + ESP32_PINMUX(33, ESP_NOSIG, ESP_PWM0_OUT1B) + +/* MCPWM0_OUT2A */ +#define MCPWM0_OUT2A_GPIO0 \ + ESP32_PINMUX(0, ESP_NOSIG, ESP_PWM0_OUT2A) + +#define MCPWM0_OUT2A_GPIO1 \ + ESP32_PINMUX(1, ESP_NOSIG, ESP_PWM0_OUT2A) + +#define MCPWM0_OUT2A_GPIO2 \ + ESP32_PINMUX(2, ESP_NOSIG, ESP_PWM0_OUT2A) + +#define MCPWM0_OUT2A_GPIO3 \ + ESP32_PINMUX(3, ESP_NOSIG, ESP_PWM0_OUT2A) + +#define MCPWM0_OUT2A_GPIO4 \ + ESP32_PINMUX(4, ESP_NOSIG, ESP_PWM0_OUT2A) + +#define MCPWM0_OUT2A_GPIO5 \ + ESP32_PINMUX(5, ESP_NOSIG, ESP_PWM0_OUT2A) + +#define MCPWM0_OUT2A_GPIO6 \ + ESP32_PINMUX(6, ESP_NOSIG, ESP_PWM0_OUT2A) + +#define MCPWM0_OUT2A_GPIO7 \ + ESP32_PINMUX(7, ESP_NOSIG, ESP_PWM0_OUT2A) + +#define MCPWM0_OUT2A_GPIO8 \ + ESP32_PINMUX(8, ESP_NOSIG, ESP_PWM0_OUT2A) + +#define MCPWM0_OUT2A_GPIO9 \ + ESP32_PINMUX(9, ESP_NOSIG, ESP_PWM0_OUT2A) + +#define MCPWM0_OUT2A_GPIO10 \ + ESP32_PINMUX(10, ESP_NOSIG, ESP_PWM0_OUT2A) + +#define MCPWM0_OUT2A_GPIO11 \ + ESP32_PINMUX(11, ESP_NOSIG, ESP_PWM0_OUT2A) + +#define MCPWM0_OUT2A_GPIO12 \ + ESP32_PINMUX(12, ESP_NOSIG, ESP_PWM0_OUT2A) + +#define MCPWM0_OUT2A_GPIO13 \ + ESP32_PINMUX(13, ESP_NOSIG, ESP_PWM0_OUT2A) + +#define MCPWM0_OUT2A_GPIO14 \ + ESP32_PINMUX(14, ESP_NOSIG, ESP_PWM0_OUT2A) + +#define MCPWM0_OUT2A_GPIO15 \ + ESP32_PINMUX(15, ESP_NOSIG, ESP_PWM0_OUT2A) + +#define MCPWM0_OUT2A_GPIO16 \ + ESP32_PINMUX(16, ESP_NOSIG, ESP_PWM0_OUT2A) + +#define MCPWM0_OUT2A_GPIO17 \ + ESP32_PINMUX(17, ESP_NOSIG, ESP_PWM0_OUT2A) + +#define MCPWM0_OUT2A_GPIO18 \ + ESP32_PINMUX(18, ESP_NOSIG, ESP_PWM0_OUT2A) + +#define MCPWM0_OUT2A_GPIO19 \ + ESP32_PINMUX(19, ESP_NOSIG, ESP_PWM0_OUT2A) + +#define MCPWM0_OUT2A_GPIO20 \ + ESP32_PINMUX(20, ESP_NOSIG, ESP_PWM0_OUT2A) + +#define MCPWM0_OUT2A_GPIO21 \ + ESP32_PINMUX(21, ESP_NOSIG, ESP_PWM0_OUT2A) + +#define MCPWM0_OUT2A_GPIO22 \ + ESP32_PINMUX(22, ESP_NOSIG, ESP_PWM0_OUT2A) + +#define MCPWM0_OUT2A_GPIO23 \ + ESP32_PINMUX(23, ESP_NOSIG, ESP_PWM0_OUT2A) + +#define MCPWM0_OUT2A_GPIO25 \ + ESP32_PINMUX(25, ESP_NOSIG, ESP_PWM0_OUT2A) + +#define MCPWM0_OUT2A_GPIO26 \ + ESP32_PINMUX(26, ESP_NOSIG, ESP_PWM0_OUT2A) + +#define MCPWM0_OUT2A_GPIO27 \ + ESP32_PINMUX(27, ESP_NOSIG, ESP_PWM0_OUT2A) + +#define MCPWM0_OUT2A_GPIO32 \ + ESP32_PINMUX(32, ESP_NOSIG, ESP_PWM0_OUT2A) + +#define MCPWM0_OUT2A_GPIO33 \ + ESP32_PINMUX(33, ESP_NOSIG, ESP_PWM0_OUT2A) + +/* MCPWM0_OUT2B */ +#define MCPWM0_OUT2B_GPIO0 \ + ESP32_PINMUX(0, ESP_NOSIG, ESP_PWM0_OUT2B) + +#define MCPWM0_OUT2B_GPIO1 \ + ESP32_PINMUX(1, ESP_NOSIG, ESP_PWM0_OUT2B) + +#define MCPWM0_OUT2B_GPIO2 \ + ESP32_PINMUX(2, ESP_NOSIG, ESP_PWM0_OUT2B) + +#define MCPWM0_OUT2B_GPIO3 \ + ESP32_PINMUX(3, ESP_NOSIG, ESP_PWM0_OUT2B) + +#define MCPWM0_OUT2B_GPIO4 \ + ESP32_PINMUX(4, ESP_NOSIG, ESP_PWM0_OUT2B) + +#define MCPWM0_OUT2B_GPIO5 \ + ESP32_PINMUX(5, ESP_NOSIG, ESP_PWM0_OUT2B) + +#define MCPWM0_OUT2B_GPIO6 \ + ESP32_PINMUX(6, ESP_NOSIG, ESP_PWM0_OUT2B) + +#define MCPWM0_OUT2B_GPIO7 \ + ESP32_PINMUX(7, ESP_NOSIG, ESP_PWM0_OUT2B) + +#define MCPWM0_OUT2B_GPIO8 \ + ESP32_PINMUX(8, ESP_NOSIG, ESP_PWM0_OUT2B) + +#define MCPWM0_OUT2B_GPIO9 \ + ESP32_PINMUX(9, ESP_NOSIG, ESP_PWM0_OUT2B) + +#define MCPWM0_OUT2B_GPIO10 \ + ESP32_PINMUX(10, ESP_NOSIG, ESP_PWM0_OUT2B) + +#define MCPWM0_OUT2B_GPIO11 \ + ESP32_PINMUX(11, ESP_NOSIG, ESP_PWM0_OUT2B) + +#define MCPWM0_OUT2B_GPIO12 \ + ESP32_PINMUX(12, ESP_NOSIG, ESP_PWM0_OUT2B) + +#define MCPWM0_OUT2B_GPIO13 \ + ESP32_PINMUX(13, ESP_NOSIG, ESP_PWM0_OUT2B) + +#define MCPWM0_OUT2B_GPIO14 \ + ESP32_PINMUX(14, ESP_NOSIG, ESP_PWM0_OUT2B) + +#define MCPWM0_OUT2B_GPIO15 \ + ESP32_PINMUX(15, ESP_NOSIG, ESP_PWM0_OUT2B) + +#define MCPWM0_OUT2B_GPIO16 \ + ESP32_PINMUX(16, ESP_NOSIG, ESP_PWM0_OUT2B) + +#define MCPWM0_OUT2B_GPIO17 \ + ESP32_PINMUX(17, ESP_NOSIG, ESP_PWM0_OUT2B) + +#define MCPWM0_OUT2B_GPIO18 \ + ESP32_PINMUX(18, ESP_NOSIG, ESP_PWM0_OUT2B) + +#define MCPWM0_OUT2B_GPIO19 \ + ESP32_PINMUX(19, ESP_NOSIG, ESP_PWM0_OUT2B) + +#define MCPWM0_OUT2B_GPIO20 \ + ESP32_PINMUX(20, ESP_NOSIG, ESP_PWM0_OUT2B) + +#define MCPWM0_OUT2B_GPIO21 \ + ESP32_PINMUX(21, ESP_NOSIG, ESP_PWM0_OUT2B) + +#define MCPWM0_OUT2B_GPIO22 \ + ESP32_PINMUX(22, ESP_NOSIG, ESP_PWM0_OUT2B) + +#define MCPWM0_OUT2B_GPIO23 \ + ESP32_PINMUX(23, ESP_NOSIG, ESP_PWM0_OUT2B) + +#define MCPWM0_OUT2B_GPIO25 \ + ESP32_PINMUX(25, ESP_NOSIG, ESP_PWM0_OUT2B) + +#define MCPWM0_OUT2B_GPIO26 \ + ESP32_PINMUX(26, ESP_NOSIG, ESP_PWM0_OUT2B) + +#define MCPWM0_OUT2B_GPIO27 \ + ESP32_PINMUX(27, ESP_NOSIG, ESP_PWM0_OUT2B) + +#define MCPWM0_OUT2B_GPIO32 \ + ESP32_PINMUX(32, ESP_NOSIG, ESP_PWM0_OUT2B) + +#define MCPWM0_OUT2B_GPIO33 \ + ESP32_PINMUX(33, ESP_NOSIG, ESP_PWM0_OUT2B) + +/* MCPWM0_SYNC0 */ +#define MCPWM0_SYNC0_GPIO0 \ + ESP32_PINMUX(0, ESP_PWM0_SYNC0_IN, ESP_NOSIG) + +#define MCPWM0_SYNC0_GPIO1 \ + ESP32_PINMUX(1, ESP_PWM0_SYNC0_IN, ESP_NOSIG) + +#define MCPWM0_SYNC0_GPIO2 \ + ESP32_PINMUX(2, ESP_PWM0_SYNC0_IN, ESP_NOSIG) + +#define MCPWM0_SYNC0_GPIO3 \ + ESP32_PINMUX(3, ESP_PWM0_SYNC0_IN, ESP_NOSIG) + +#define MCPWM0_SYNC0_GPIO4 \ + ESP32_PINMUX(4, ESP_PWM0_SYNC0_IN, ESP_NOSIG) + +#define MCPWM0_SYNC0_GPIO5 \ + ESP32_PINMUX(5, ESP_PWM0_SYNC0_IN, ESP_NOSIG) + +#define MCPWM0_SYNC0_GPIO6 \ + ESP32_PINMUX(6, ESP_PWM0_SYNC0_IN, ESP_NOSIG) + +#define MCPWM0_SYNC0_GPIO7 \ + ESP32_PINMUX(7, ESP_PWM0_SYNC0_IN, ESP_NOSIG) + +#define MCPWM0_SYNC0_GPIO8 \ + ESP32_PINMUX(8, ESP_PWM0_SYNC0_IN, ESP_NOSIG) + +#define MCPWM0_SYNC0_GPIO9 \ + ESP32_PINMUX(9, ESP_PWM0_SYNC0_IN, ESP_NOSIG) + +#define MCPWM0_SYNC0_GPIO10 \ + ESP32_PINMUX(10, ESP_PWM0_SYNC0_IN, ESP_NOSIG) + +#define MCPWM0_SYNC0_GPIO11 \ + ESP32_PINMUX(11, ESP_PWM0_SYNC0_IN, ESP_NOSIG) + +#define MCPWM0_SYNC0_GPIO12 \ + ESP32_PINMUX(12, ESP_PWM0_SYNC0_IN, ESP_NOSIG) + +#define MCPWM0_SYNC0_GPIO13 \ + ESP32_PINMUX(13, ESP_PWM0_SYNC0_IN, ESP_NOSIG) + +#define MCPWM0_SYNC0_GPIO14 \ + ESP32_PINMUX(14, ESP_PWM0_SYNC0_IN, ESP_NOSIG) + +#define MCPWM0_SYNC0_GPIO15 \ + ESP32_PINMUX(15, ESP_PWM0_SYNC0_IN, ESP_NOSIG) + +#define MCPWM0_SYNC0_GPIO16 \ + ESP32_PINMUX(16, ESP_PWM0_SYNC0_IN, ESP_NOSIG) + +#define MCPWM0_SYNC0_GPIO17 \ + ESP32_PINMUX(17, ESP_PWM0_SYNC0_IN, ESP_NOSIG) + +#define MCPWM0_SYNC0_GPIO18 \ + ESP32_PINMUX(18, ESP_PWM0_SYNC0_IN, ESP_NOSIG) + +#define MCPWM0_SYNC0_GPIO19 \ + ESP32_PINMUX(19, ESP_PWM0_SYNC0_IN, ESP_NOSIG) + +#define MCPWM0_SYNC0_GPIO20 \ + ESP32_PINMUX(20, ESP_PWM0_SYNC0_IN, ESP_NOSIG) + +#define MCPWM0_SYNC0_GPIO21 \ + ESP32_PINMUX(21, ESP_PWM0_SYNC0_IN, ESP_NOSIG) + +#define MCPWM0_SYNC0_GPIO22 \ + ESP32_PINMUX(22, ESP_PWM0_SYNC0_IN, ESP_NOSIG) + +#define MCPWM0_SYNC0_GPIO23 \ + ESP32_PINMUX(23, ESP_PWM0_SYNC0_IN, ESP_NOSIG) + +#define MCPWM0_SYNC0_GPIO25 \ + ESP32_PINMUX(25, ESP_PWM0_SYNC0_IN, ESP_NOSIG) + +#define MCPWM0_SYNC0_GPIO26 \ + ESP32_PINMUX(26, ESP_PWM0_SYNC0_IN, ESP_NOSIG) + +#define MCPWM0_SYNC0_GPIO27 \ + ESP32_PINMUX(27, ESP_PWM0_SYNC0_IN, ESP_NOSIG) + +#define MCPWM0_SYNC0_GPIO32 \ + ESP32_PINMUX(32, ESP_PWM0_SYNC0_IN, ESP_NOSIG) + +#define MCPWM0_SYNC0_GPIO33 \ + ESP32_PINMUX(33, ESP_PWM0_SYNC0_IN, ESP_NOSIG) + +#define MCPWM0_SYNC0_GPIO34 \ + ESP32_PINMUX(34, ESP_PWM0_SYNC0_IN, ESP_NOSIG) + +#define MCPWM0_SYNC0_GPIO35 \ + ESP32_PINMUX(35, ESP_PWM0_SYNC0_IN, ESP_NOSIG) + +#define MCPWM0_SYNC0_GPIO36 \ + ESP32_PINMUX(36, ESP_PWM0_SYNC0_IN, ESP_NOSIG) + +#define MCPWM0_SYNC0_GPIO37 \ + ESP32_PINMUX(37, ESP_PWM0_SYNC0_IN, ESP_NOSIG) + +#define MCPWM0_SYNC0_GPIO38 \ + ESP32_PINMUX(38, ESP_PWM0_SYNC0_IN, ESP_NOSIG) + +#define MCPWM0_SYNC0_GPIO39 \ + ESP32_PINMUX(39, ESP_PWM0_SYNC0_IN, ESP_NOSIG) + +/* MCPWM0_SYNC1 */ +#define MCPWM0_SYNC1_GPIO0 \ + ESP32_PINMUX(0, ESP_PWM0_SYNC1_IN, ESP_NOSIG) + +#define MCPWM0_SYNC1_GPIO1 \ + ESP32_PINMUX(1, ESP_PWM0_SYNC1_IN, ESP_NOSIG) + +#define MCPWM0_SYNC1_GPIO2 \ + ESP32_PINMUX(2, ESP_PWM0_SYNC1_IN, ESP_NOSIG) + +#define MCPWM0_SYNC1_GPIO3 \ + ESP32_PINMUX(3, ESP_PWM0_SYNC1_IN, ESP_NOSIG) + +#define MCPWM0_SYNC1_GPIO4 \ + ESP32_PINMUX(4, ESP_PWM0_SYNC1_IN, ESP_NOSIG) + +#define MCPWM0_SYNC1_GPIO5 \ + ESP32_PINMUX(5, ESP_PWM0_SYNC1_IN, ESP_NOSIG) + +#define MCPWM0_SYNC1_GPIO6 \ + ESP32_PINMUX(6, ESP_PWM0_SYNC1_IN, ESP_NOSIG) + +#define MCPWM0_SYNC1_GPIO7 \ + ESP32_PINMUX(7, ESP_PWM0_SYNC1_IN, ESP_NOSIG) + +#define MCPWM0_SYNC1_GPIO8 \ + ESP32_PINMUX(8, ESP_PWM0_SYNC1_IN, ESP_NOSIG) + +#define MCPWM0_SYNC1_GPIO9 \ + ESP32_PINMUX(9, ESP_PWM0_SYNC1_IN, ESP_NOSIG) + +#define MCPWM0_SYNC1_GPIO10 \ + ESP32_PINMUX(10, ESP_PWM0_SYNC1_IN, ESP_NOSIG) + +#define MCPWM0_SYNC1_GPIO11 \ + ESP32_PINMUX(11, ESP_PWM0_SYNC1_IN, ESP_NOSIG) + +#define MCPWM0_SYNC1_GPIO12 \ + ESP32_PINMUX(12, ESP_PWM0_SYNC1_IN, ESP_NOSIG) + +#define MCPWM0_SYNC1_GPIO13 \ + ESP32_PINMUX(13, ESP_PWM0_SYNC1_IN, ESP_NOSIG) + +#define MCPWM0_SYNC1_GPIO14 \ + ESP32_PINMUX(14, ESP_PWM0_SYNC1_IN, ESP_NOSIG) + +#define MCPWM0_SYNC1_GPIO15 \ + ESP32_PINMUX(15, ESP_PWM0_SYNC1_IN, ESP_NOSIG) + +#define MCPWM0_SYNC1_GPIO16 \ + ESP32_PINMUX(16, ESP_PWM0_SYNC1_IN, ESP_NOSIG) + +#define MCPWM0_SYNC1_GPIO17 \ + ESP32_PINMUX(17, ESP_PWM0_SYNC1_IN, ESP_NOSIG) + +#define MCPWM0_SYNC1_GPIO18 \ + ESP32_PINMUX(18, ESP_PWM0_SYNC1_IN, ESP_NOSIG) + +#define MCPWM0_SYNC1_GPIO19 \ + ESP32_PINMUX(19, ESP_PWM0_SYNC1_IN, ESP_NOSIG) + +#define MCPWM0_SYNC1_GPIO20 \ + ESP32_PINMUX(20, ESP_PWM0_SYNC1_IN, ESP_NOSIG) + +#define MCPWM0_SYNC1_GPIO21 \ + ESP32_PINMUX(21, ESP_PWM0_SYNC1_IN, ESP_NOSIG) + +#define MCPWM0_SYNC1_GPIO22 \ + ESP32_PINMUX(22, ESP_PWM0_SYNC1_IN, ESP_NOSIG) + +#define MCPWM0_SYNC1_GPIO23 \ + ESP32_PINMUX(23, ESP_PWM0_SYNC1_IN, ESP_NOSIG) + +#define MCPWM0_SYNC1_GPIO25 \ + ESP32_PINMUX(25, ESP_PWM0_SYNC1_IN, ESP_NOSIG) + +#define MCPWM0_SYNC1_GPIO26 \ + ESP32_PINMUX(26, ESP_PWM0_SYNC1_IN, ESP_NOSIG) + +#define MCPWM0_SYNC1_GPIO27 \ + ESP32_PINMUX(27, ESP_PWM0_SYNC1_IN, ESP_NOSIG) + +#define MCPWM0_SYNC1_GPIO32 \ + ESP32_PINMUX(32, ESP_PWM0_SYNC1_IN, ESP_NOSIG) + +#define MCPWM0_SYNC1_GPIO33 \ + ESP32_PINMUX(33, ESP_PWM0_SYNC1_IN, ESP_NOSIG) + +#define MCPWM0_SYNC1_GPIO34 \ + ESP32_PINMUX(34, ESP_PWM0_SYNC1_IN, ESP_NOSIG) + +#define MCPWM0_SYNC1_GPIO35 \ + ESP32_PINMUX(35, ESP_PWM0_SYNC1_IN, ESP_NOSIG) + +#define MCPWM0_SYNC1_GPIO36 \ + ESP32_PINMUX(36, ESP_PWM0_SYNC1_IN, ESP_NOSIG) + +#define MCPWM0_SYNC1_GPIO37 \ + ESP32_PINMUX(37, ESP_PWM0_SYNC1_IN, ESP_NOSIG) + +#define MCPWM0_SYNC1_GPIO38 \ + ESP32_PINMUX(38, ESP_PWM0_SYNC1_IN, ESP_NOSIG) + +#define MCPWM0_SYNC1_GPIO39 \ + ESP32_PINMUX(39, ESP_PWM0_SYNC1_IN, ESP_NOSIG) + +/* MCPWM0_SYNC2 */ +#define MCPWM0_SYNC2_GPIO0 \ + ESP32_PINMUX(0, ESP_PWM0_SYNC2_IN, ESP_NOSIG) + +#define MCPWM0_SYNC2_GPIO1 \ + ESP32_PINMUX(1, ESP_PWM0_SYNC2_IN, ESP_NOSIG) + +#define MCPWM0_SYNC2_GPIO2 \ + ESP32_PINMUX(2, ESP_PWM0_SYNC2_IN, ESP_NOSIG) + +#define MCPWM0_SYNC2_GPIO3 \ + ESP32_PINMUX(3, ESP_PWM0_SYNC2_IN, ESP_NOSIG) + +#define MCPWM0_SYNC2_GPIO4 \ + ESP32_PINMUX(4, ESP_PWM0_SYNC2_IN, ESP_NOSIG) + +#define MCPWM0_SYNC2_GPIO5 \ + ESP32_PINMUX(5, ESP_PWM0_SYNC2_IN, ESP_NOSIG) + +#define MCPWM0_SYNC2_GPIO6 \ + ESP32_PINMUX(6, ESP_PWM0_SYNC2_IN, ESP_NOSIG) + +#define MCPWM0_SYNC2_GPIO7 \ + ESP32_PINMUX(7, ESP_PWM0_SYNC2_IN, ESP_NOSIG) + +#define MCPWM0_SYNC2_GPIO8 \ + ESP32_PINMUX(8, ESP_PWM0_SYNC2_IN, ESP_NOSIG) + +#define MCPWM0_SYNC2_GPIO9 \ + ESP32_PINMUX(9, ESP_PWM0_SYNC2_IN, ESP_NOSIG) + +#define MCPWM0_SYNC2_GPIO10 \ + ESP32_PINMUX(10, ESP_PWM0_SYNC2_IN, ESP_NOSIG) + +#define MCPWM0_SYNC2_GPIO11 \ + ESP32_PINMUX(11, ESP_PWM0_SYNC2_IN, ESP_NOSIG) + +#define MCPWM0_SYNC2_GPIO12 \ + ESP32_PINMUX(12, ESP_PWM0_SYNC2_IN, ESP_NOSIG) + +#define MCPWM0_SYNC2_GPIO13 \ + ESP32_PINMUX(13, ESP_PWM0_SYNC2_IN, ESP_NOSIG) + +#define MCPWM0_SYNC2_GPIO14 \ + ESP32_PINMUX(14, ESP_PWM0_SYNC2_IN, ESP_NOSIG) + +#define MCPWM0_SYNC2_GPIO15 \ + ESP32_PINMUX(15, ESP_PWM0_SYNC2_IN, ESP_NOSIG) + +#define MCPWM0_SYNC2_GPIO16 \ + ESP32_PINMUX(16, ESP_PWM0_SYNC2_IN, ESP_NOSIG) + +#define MCPWM0_SYNC2_GPIO17 \ + ESP32_PINMUX(17, ESP_PWM0_SYNC2_IN, ESP_NOSIG) + +#define MCPWM0_SYNC2_GPIO18 \ + ESP32_PINMUX(18, ESP_PWM0_SYNC2_IN, ESP_NOSIG) + +#define MCPWM0_SYNC2_GPIO19 \ + ESP32_PINMUX(19, ESP_PWM0_SYNC2_IN, ESP_NOSIG) + +#define MCPWM0_SYNC2_GPIO20 \ + ESP32_PINMUX(20, ESP_PWM0_SYNC2_IN, ESP_NOSIG) + +#define MCPWM0_SYNC2_GPIO21 \ + ESP32_PINMUX(21, ESP_PWM0_SYNC2_IN, ESP_NOSIG) + +#define MCPWM0_SYNC2_GPIO22 \ + ESP32_PINMUX(22, ESP_PWM0_SYNC2_IN, ESP_NOSIG) + +#define MCPWM0_SYNC2_GPIO23 \ + ESP32_PINMUX(23, ESP_PWM0_SYNC2_IN, ESP_NOSIG) + +#define MCPWM0_SYNC2_GPIO25 \ + ESP32_PINMUX(25, ESP_PWM0_SYNC2_IN, ESP_NOSIG) + +#define MCPWM0_SYNC2_GPIO26 \ + ESP32_PINMUX(26, ESP_PWM0_SYNC2_IN, ESP_NOSIG) + +#define MCPWM0_SYNC2_GPIO27 \ + ESP32_PINMUX(27, ESP_PWM0_SYNC2_IN, ESP_NOSIG) + +#define MCPWM0_SYNC2_GPIO32 \ + ESP32_PINMUX(32, ESP_PWM0_SYNC2_IN, ESP_NOSIG) + +#define MCPWM0_SYNC2_GPIO33 \ + ESP32_PINMUX(33, ESP_PWM0_SYNC2_IN, ESP_NOSIG) + +#define MCPWM0_SYNC2_GPIO34 \ + ESP32_PINMUX(34, ESP_PWM0_SYNC2_IN, ESP_NOSIG) + +#define MCPWM0_SYNC2_GPIO35 \ + ESP32_PINMUX(35, ESP_PWM0_SYNC2_IN, ESP_NOSIG) + +#define MCPWM0_SYNC2_GPIO36 \ + ESP32_PINMUX(36, ESP_PWM0_SYNC2_IN, ESP_NOSIG) + +#define MCPWM0_SYNC2_GPIO37 \ + ESP32_PINMUX(37, ESP_PWM0_SYNC2_IN, ESP_NOSIG) + +#define MCPWM0_SYNC2_GPIO38 \ + ESP32_PINMUX(38, ESP_PWM0_SYNC2_IN, ESP_NOSIG) + +#define MCPWM0_SYNC2_GPIO39 \ + ESP32_PINMUX(39, ESP_PWM0_SYNC2_IN, ESP_NOSIG) + +/* MCPWM1_CAP0 */ +#define MCPWM1_CAP0_GPIO0 \ + ESP32_PINMUX(0, ESP_PWM1_CAP0_IN, ESP_NOSIG) + +#define MCPWM1_CAP0_GPIO1 \ + ESP32_PINMUX(1, ESP_PWM1_CAP0_IN, ESP_NOSIG) + +#define MCPWM1_CAP0_GPIO2 \ + ESP32_PINMUX(2, ESP_PWM1_CAP0_IN, ESP_NOSIG) + +#define MCPWM1_CAP0_GPIO3 \ + ESP32_PINMUX(3, ESP_PWM1_CAP0_IN, ESP_NOSIG) + +#define MCPWM1_CAP0_GPIO4 \ + ESP32_PINMUX(4, ESP_PWM1_CAP0_IN, ESP_NOSIG) + +#define MCPWM1_CAP0_GPIO5 \ + ESP32_PINMUX(5, ESP_PWM1_CAP0_IN, ESP_NOSIG) + +#define MCPWM1_CAP0_GPIO6 \ + ESP32_PINMUX(6, ESP_PWM1_CAP0_IN, ESP_NOSIG) + +#define MCPWM1_CAP0_GPIO7 \ + ESP32_PINMUX(7, ESP_PWM1_CAP0_IN, ESP_NOSIG) + +#define MCPWM1_CAP0_GPIO8 \ + ESP32_PINMUX(8, ESP_PWM1_CAP0_IN, ESP_NOSIG) + +#define MCPWM1_CAP0_GPIO9 \ + ESP32_PINMUX(9, ESP_PWM1_CAP0_IN, ESP_NOSIG) + +#define MCPWM1_CAP0_GPIO10 \ + ESP32_PINMUX(10, ESP_PWM1_CAP0_IN, ESP_NOSIG) + +#define MCPWM1_CAP0_GPIO11 \ + ESP32_PINMUX(11, ESP_PWM1_CAP0_IN, ESP_NOSIG) + +#define MCPWM1_CAP0_GPIO12 \ + ESP32_PINMUX(12, ESP_PWM1_CAP0_IN, ESP_NOSIG) + +#define MCPWM1_CAP0_GPIO13 \ + ESP32_PINMUX(13, ESP_PWM1_CAP0_IN, ESP_NOSIG) + +#define MCPWM1_CAP0_GPIO14 \ + ESP32_PINMUX(14, ESP_PWM1_CAP0_IN, ESP_NOSIG) + +#define MCPWM1_CAP0_GPIO15 \ + ESP32_PINMUX(15, ESP_PWM1_CAP0_IN, ESP_NOSIG) + +#define MCPWM1_CAP0_GPIO16 \ + ESP32_PINMUX(16, ESP_PWM1_CAP0_IN, ESP_NOSIG) + +#define MCPWM1_CAP0_GPIO17 \ + ESP32_PINMUX(17, ESP_PWM1_CAP0_IN, ESP_NOSIG) + +#define MCPWM1_CAP0_GPIO18 \ + ESP32_PINMUX(18, ESP_PWM1_CAP0_IN, ESP_NOSIG) + +#define MCPWM1_CAP0_GPIO19 \ + ESP32_PINMUX(19, ESP_PWM1_CAP0_IN, ESP_NOSIG) + +#define MCPWM1_CAP0_GPIO20 \ + ESP32_PINMUX(20, ESP_PWM1_CAP0_IN, ESP_NOSIG) + +#define MCPWM1_CAP0_GPIO21 \ + ESP32_PINMUX(21, ESP_PWM1_CAP0_IN, ESP_NOSIG) + +#define MCPWM1_CAP0_GPIO22 \ + ESP32_PINMUX(22, ESP_PWM1_CAP0_IN, ESP_NOSIG) + +#define MCPWM1_CAP0_GPIO23 \ + ESP32_PINMUX(23, ESP_PWM1_CAP0_IN, ESP_NOSIG) + +#define MCPWM1_CAP0_GPIO25 \ + ESP32_PINMUX(25, ESP_PWM1_CAP0_IN, ESP_NOSIG) + +#define MCPWM1_CAP0_GPIO26 \ + ESP32_PINMUX(26, ESP_PWM1_CAP0_IN, ESP_NOSIG) + +#define MCPWM1_CAP0_GPIO27 \ + ESP32_PINMUX(27, ESP_PWM1_CAP0_IN, ESP_NOSIG) + +#define MCPWM1_CAP0_GPIO32 \ + ESP32_PINMUX(32, ESP_PWM1_CAP0_IN, ESP_NOSIG) + +#define MCPWM1_CAP0_GPIO33 \ + ESP32_PINMUX(33, ESP_PWM1_CAP0_IN, ESP_NOSIG) + +#define MCPWM1_CAP0_GPIO34 \ + ESP32_PINMUX(34, ESP_PWM1_CAP0_IN, ESP_NOSIG) + +#define MCPWM1_CAP0_GPIO35 \ + ESP32_PINMUX(35, ESP_PWM1_CAP0_IN, ESP_NOSIG) + +#define MCPWM1_CAP0_GPIO36 \ + ESP32_PINMUX(36, ESP_PWM1_CAP0_IN, ESP_NOSIG) + +#define MCPWM1_CAP0_GPIO37 \ + ESP32_PINMUX(37, ESP_PWM1_CAP0_IN, ESP_NOSIG) + +#define MCPWM1_CAP0_GPIO38 \ + ESP32_PINMUX(38, ESP_PWM1_CAP0_IN, ESP_NOSIG) + +#define MCPWM1_CAP0_GPIO39 \ + ESP32_PINMUX(39, ESP_PWM1_CAP0_IN, ESP_NOSIG) + +/* MCPWM1_CAP1 */ +#define MCPWM1_CAP1_GPIO0 \ + ESP32_PINMUX(0, ESP_PWM1_CAP1_IN, ESP_NOSIG) + +#define MCPWM1_CAP1_GPIO1 \ + ESP32_PINMUX(1, ESP_PWM1_CAP1_IN, ESP_NOSIG) + +#define MCPWM1_CAP1_GPIO2 \ + ESP32_PINMUX(2, ESP_PWM1_CAP1_IN, ESP_NOSIG) + +#define MCPWM1_CAP1_GPIO3 \ + ESP32_PINMUX(3, ESP_PWM1_CAP1_IN, ESP_NOSIG) + +#define MCPWM1_CAP1_GPIO4 \ + ESP32_PINMUX(4, ESP_PWM1_CAP1_IN, ESP_NOSIG) + +#define MCPWM1_CAP1_GPIO5 \ + ESP32_PINMUX(5, ESP_PWM1_CAP1_IN, ESP_NOSIG) + +#define MCPWM1_CAP1_GPIO6 \ + ESP32_PINMUX(6, ESP_PWM1_CAP1_IN, ESP_NOSIG) + +#define MCPWM1_CAP1_GPIO7 \ + ESP32_PINMUX(7, ESP_PWM1_CAP1_IN, ESP_NOSIG) + +#define MCPWM1_CAP1_GPIO8 \ + ESP32_PINMUX(8, ESP_PWM1_CAP1_IN, ESP_NOSIG) + +#define MCPWM1_CAP1_GPIO9 \ + ESP32_PINMUX(9, ESP_PWM1_CAP1_IN, ESP_NOSIG) + +#define MCPWM1_CAP1_GPIO10 \ + ESP32_PINMUX(10, ESP_PWM1_CAP1_IN, ESP_NOSIG) + +#define MCPWM1_CAP1_GPIO11 \ + ESP32_PINMUX(11, ESP_PWM1_CAP1_IN, ESP_NOSIG) + +#define MCPWM1_CAP1_GPIO12 \ + ESP32_PINMUX(12, ESP_PWM1_CAP1_IN, ESP_NOSIG) + +#define MCPWM1_CAP1_GPIO13 \ + ESP32_PINMUX(13, ESP_PWM1_CAP1_IN, ESP_NOSIG) + +#define MCPWM1_CAP1_GPIO14 \ + ESP32_PINMUX(14, ESP_PWM1_CAP1_IN, ESP_NOSIG) + +#define MCPWM1_CAP1_GPIO15 \ + ESP32_PINMUX(15, ESP_PWM1_CAP1_IN, ESP_NOSIG) + +#define MCPWM1_CAP1_GPIO16 \ + ESP32_PINMUX(16, ESP_PWM1_CAP1_IN, ESP_NOSIG) + +#define MCPWM1_CAP1_GPIO17 \ + ESP32_PINMUX(17, ESP_PWM1_CAP1_IN, ESP_NOSIG) + +#define MCPWM1_CAP1_GPIO18 \ + ESP32_PINMUX(18, ESP_PWM1_CAP1_IN, ESP_NOSIG) + +#define MCPWM1_CAP1_GPIO19 \ + ESP32_PINMUX(19, ESP_PWM1_CAP1_IN, ESP_NOSIG) + +#define MCPWM1_CAP1_GPIO20 \ + ESP32_PINMUX(20, ESP_PWM1_CAP1_IN, ESP_NOSIG) + +#define MCPWM1_CAP1_GPIO21 \ + ESP32_PINMUX(21, ESP_PWM1_CAP1_IN, ESP_NOSIG) + +#define MCPWM1_CAP1_GPIO22 \ + ESP32_PINMUX(22, ESP_PWM1_CAP1_IN, ESP_NOSIG) + +#define MCPWM1_CAP1_GPIO23 \ + ESP32_PINMUX(23, ESP_PWM1_CAP1_IN, ESP_NOSIG) + +#define MCPWM1_CAP1_GPIO25 \ + ESP32_PINMUX(25, ESP_PWM1_CAP1_IN, ESP_NOSIG) + +#define MCPWM1_CAP1_GPIO26 \ + ESP32_PINMUX(26, ESP_PWM1_CAP1_IN, ESP_NOSIG) + +#define MCPWM1_CAP1_GPIO27 \ + ESP32_PINMUX(27, ESP_PWM1_CAP1_IN, ESP_NOSIG) + +#define MCPWM1_CAP1_GPIO32 \ + ESP32_PINMUX(32, ESP_PWM1_CAP1_IN, ESP_NOSIG) + +#define MCPWM1_CAP1_GPIO33 \ + ESP32_PINMUX(33, ESP_PWM1_CAP1_IN, ESP_NOSIG) + +#define MCPWM1_CAP1_GPIO34 \ + ESP32_PINMUX(34, ESP_PWM1_CAP1_IN, ESP_NOSIG) + +#define MCPWM1_CAP1_GPIO35 \ + ESP32_PINMUX(35, ESP_PWM1_CAP1_IN, ESP_NOSIG) + +#define MCPWM1_CAP1_GPIO36 \ + ESP32_PINMUX(36, ESP_PWM1_CAP1_IN, ESP_NOSIG) + +#define MCPWM1_CAP1_GPIO37 \ + ESP32_PINMUX(37, ESP_PWM1_CAP1_IN, ESP_NOSIG) + +#define MCPWM1_CAP1_GPIO38 \ + ESP32_PINMUX(38, ESP_PWM1_CAP1_IN, ESP_NOSIG) + +#define MCPWM1_CAP1_GPIO39 \ + ESP32_PINMUX(39, ESP_PWM1_CAP1_IN, ESP_NOSIG) + +/* MCPWM1_CAP2 */ +#define MCPWM1_CAP2_GPIO0 \ + ESP32_PINMUX(0, ESP_PWM1_CAP2_IN, ESP_NOSIG) + +#define MCPWM1_CAP2_GPIO1 \ + ESP32_PINMUX(1, ESP_PWM1_CAP2_IN, ESP_NOSIG) + +#define MCPWM1_CAP2_GPIO2 \ + ESP32_PINMUX(2, ESP_PWM1_CAP2_IN, ESP_NOSIG) + +#define MCPWM1_CAP2_GPIO3 \ + ESP32_PINMUX(3, ESP_PWM1_CAP2_IN, ESP_NOSIG) + +#define MCPWM1_CAP2_GPIO4 \ + ESP32_PINMUX(4, ESP_PWM1_CAP2_IN, ESP_NOSIG) + +#define MCPWM1_CAP2_GPIO5 \ + ESP32_PINMUX(5, ESP_PWM1_CAP2_IN, ESP_NOSIG) + +#define MCPWM1_CAP2_GPIO6 \ + ESP32_PINMUX(6, ESP_PWM1_CAP2_IN, ESP_NOSIG) + +#define MCPWM1_CAP2_GPIO7 \ + ESP32_PINMUX(7, ESP_PWM1_CAP2_IN, ESP_NOSIG) + +#define MCPWM1_CAP2_GPIO8 \ + ESP32_PINMUX(8, ESP_PWM1_CAP2_IN, ESP_NOSIG) + +#define MCPWM1_CAP2_GPIO9 \ + ESP32_PINMUX(9, ESP_PWM1_CAP2_IN, ESP_NOSIG) + +#define MCPWM1_CAP2_GPIO10 \ + ESP32_PINMUX(10, ESP_PWM1_CAP2_IN, ESP_NOSIG) + +#define MCPWM1_CAP2_GPIO11 \ + ESP32_PINMUX(11, ESP_PWM1_CAP2_IN, ESP_NOSIG) + +#define MCPWM1_CAP2_GPIO12 \ + ESP32_PINMUX(12, ESP_PWM1_CAP2_IN, ESP_NOSIG) + +#define MCPWM1_CAP2_GPIO13 \ + ESP32_PINMUX(13, ESP_PWM1_CAP2_IN, ESP_NOSIG) + +#define MCPWM1_CAP2_GPIO14 \ + ESP32_PINMUX(14, ESP_PWM1_CAP2_IN, ESP_NOSIG) + +#define MCPWM1_CAP2_GPIO15 \ + ESP32_PINMUX(15, ESP_PWM1_CAP2_IN, ESP_NOSIG) + +#define MCPWM1_CAP2_GPIO16 \ + ESP32_PINMUX(16, ESP_PWM1_CAP2_IN, ESP_NOSIG) + +#define MCPWM1_CAP2_GPIO17 \ + ESP32_PINMUX(17, ESP_PWM1_CAP2_IN, ESP_NOSIG) + +#define MCPWM1_CAP2_GPIO18 \ + ESP32_PINMUX(18, ESP_PWM1_CAP2_IN, ESP_NOSIG) + +#define MCPWM1_CAP2_GPIO19 \ + ESP32_PINMUX(19, ESP_PWM1_CAP2_IN, ESP_NOSIG) + +#define MCPWM1_CAP2_GPIO20 \ + ESP32_PINMUX(20, ESP_PWM1_CAP2_IN, ESP_NOSIG) + +#define MCPWM1_CAP2_GPIO21 \ + ESP32_PINMUX(21, ESP_PWM1_CAP2_IN, ESP_NOSIG) + +#define MCPWM1_CAP2_GPIO22 \ + ESP32_PINMUX(22, ESP_PWM1_CAP2_IN, ESP_NOSIG) + +#define MCPWM1_CAP2_GPIO23 \ + ESP32_PINMUX(23, ESP_PWM1_CAP2_IN, ESP_NOSIG) + +#define MCPWM1_CAP2_GPIO25 \ + ESP32_PINMUX(25, ESP_PWM1_CAP2_IN, ESP_NOSIG) + +#define MCPWM1_CAP2_GPIO26 \ + ESP32_PINMUX(26, ESP_PWM1_CAP2_IN, ESP_NOSIG) + +#define MCPWM1_CAP2_GPIO27 \ + ESP32_PINMUX(27, ESP_PWM1_CAP2_IN, ESP_NOSIG) + +#define MCPWM1_CAP2_GPIO32 \ + ESP32_PINMUX(32, ESP_PWM1_CAP2_IN, ESP_NOSIG) + +#define MCPWM1_CAP2_GPIO33 \ + ESP32_PINMUX(33, ESP_PWM1_CAP2_IN, ESP_NOSIG) + +#define MCPWM1_CAP2_GPIO34 \ + ESP32_PINMUX(34, ESP_PWM1_CAP2_IN, ESP_NOSIG) + +#define MCPWM1_CAP2_GPIO35 \ + ESP32_PINMUX(35, ESP_PWM1_CAP2_IN, ESP_NOSIG) + +#define MCPWM1_CAP2_GPIO36 \ + ESP32_PINMUX(36, ESP_PWM1_CAP2_IN, ESP_NOSIG) + +#define MCPWM1_CAP2_GPIO37 \ + ESP32_PINMUX(37, ESP_PWM1_CAP2_IN, ESP_NOSIG) + +#define MCPWM1_CAP2_GPIO38 \ + ESP32_PINMUX(38, ESP_PWM1_CAP2_IN, ESP_NOSIG) + +#define MCPWM1_CAP2_GPIO39 \ + ESP32_PINMUX(39, ESP_PWM1_CAP2_IN, ESP_NOSIG) + +/* MCPWM1_FAULT0 */ +#define MCPWM1_FAULT0_GPIO0 \ + ESP32_PINMUX(0, ESP_PWM1_F0_IN, ESP_NOSIG) + +#define MCPWM1_FAULT0_GPIO1 \ + ESP32_PINMUX(1, ESP_PWM1_F0_IN, ESP_NOSIG) + +#define MCPWM1_FAULT0_GPIO2 \ + ESP32_PINMUX(2, ESP_PWM1_F0_IN, ESP_NOSIG) + +#define MCPWM1_FAULT0_GPIO3 \ + ESP32_PINMUX(3, ESP_PWM1_F0_IN, ESP_NOSIG) + +#define MCPWM1_FAULT0_GPIO4 \ + ESP32_PINMUX(4, ESP_PWM1_F0_IN, ESP_NOSIG) + +#define MCPWM1_FAULT0_GPIO5 \ + ESP32_PINMUX(5, ESP_PWM1_F0_IN, ESP_NOSIG) + +#define MCPWM1_FAULT0_GPIO6 \ + ESP32_PINMUX(6, ESP_PWM1_F0_IN, ESP_NOSIG) + +#define MCPWM1_FAULT0_GPIO7 \ + ESP32_PINMUX(7, ESP_PWM1_F0_IN, ESP_NOSIG) + +#define MCPWM1_FAULT0_GPIO8 \ + ESP32_PINMUX(8, ESP_PWM1_F0_IN, ESP_NOSIG) + +#define MCPWM1_FAULT0_GPIO9 \ + ESP32_PINMUX(9, ESP_PWM1_F0_IN, ESP_NOSIG) + +#define MCPWM1_FAULT0_GPIO10 \ + ESP32_PINMUX(10, ESP_PWM1_F0_IN, ESP_NOSIG) + +#define MCPWM1_FAULT0_GPIO11 \ + ESP32_PINMUX(11, ESP_PWM1_F0_IN, ESP_NOSIG) + +#define MCPWM1_FAULT0_GPIO12 \ + ESP32_PINMUX(12, ESP_PWM1_F0_IN, ESP_NOSIG) + +#define MCPWM1_FAULT0_GPIO13 \ + ESP32_PINMUX(13, ESP_PWM1_F0_IN, ESP_NOSIG) + +#define MCPWM1_FAULT0_GPIO14 \ + ESP32_PINMUX(14, ESP_PWM1_F0_IN, ESP_NOSIG) + +#define MCPWM1_FAULT0_GPIO15 \ + ESP32_PINMUX(15, ESP_PWM1_F0_IN, ESP_NOSIG) + +#define MCPWM1_FAULT0_GPIO16 \ + ESP32_PINMUX(16, ESP_PWM1_F0_IN, ESP_NOSIG) + +#define MCPWM1_FAULT0_GPIO17 \ + ESP32_PINMUX(17, ESP_PWM1_F0_IN, ESP_NOSIG) + +#define MCPWM1_FAULT0_GPIO18 \ + ESP32_PINMUX(18, ESP_PWM1_F0_IN, ESP_NOSIG) + +#define MCPWM1_FAULT0_GPIO19 \ + ESP32_PINMUX(19, ESP_PWM1_F0_IN, ESP_NOSIG) + +#define MCPWM1_FAULT0_GPIO20 \ + ESP32_PINMUX(20, ESP_PWM1_F0_IN, ESP_NOSIG) + +#define MCPWM1_FAULT0_GPIO21 \ + ESP32_PINMUX(21, ESP_PWM1_F0_IN, ESP_NOSIG) + +#define MCPWM1_FAULT0_GPIO22 \ + ESP32_PINMUX(22, ESP_PWM1_F0_IN, ESP_NOSIG) + +#define MCPWM1_FAULT0_GPIO23 \ + ESP32_PINMUX(23, ESP_PWM1_F0_IN, ESP_NOSIG) + +#define MCPWM1_FAULT0_GPIO25 \ + ESP32_PINMUX(25, ESP_PWM1_F0_IN, ESP_NOSIG) + +#define MCPWM1_FAULT0_GPIO26 \ + ESP32_PINMUX(26, ESP_PWM1_F0_IN, ESP_NOSIG) + +#define MCPWM1_FAULT0_GPIO27 \ + ESP32_PINMUX(27, ESP_PWM1_F0_IN, ESP_NOSIG) + +#define MCPWM1_FAULT0_GPIO32 \ + ESP32_PINMUX(32, ESP_PWM1_F0_IN, ESP_NOSIG) + +#define MCPWM1_FAULT0_GPIO33 \ + ESP32_PINMUX(33, ESP_PWM1_F0_IN, ESP_NOSIG) + +#define MCPWM1_FAULT0_GPIO34 \ + ESP32_PINMUX(34, ESP_PWM1_F0_IN, ESP_NOSIG) + +#define MCPWM1_FAULT0_GPIO35 \ + ESP32_PINMUX(35, ESP_PWM1_F0_IN, ESP_NOSIG) + +#define MCPWM1_FAULT0_GPIO36 \ + ESP32_PINMUX(36, ESP_PWM1_F0_IN, ESP_NOSIG) + +#define MCPWM1_FAULT0_GPIO37 \ + ESP32_PINMUX(37, ESP_PWM1_F0_IN, ESP_NOSIG) + +#define MCPWM1_FAULT0_GPIO38 \ + ESP32_PINMUX(38, ESP_PWM1_F0_IN, ESP_NOSIG) + +#define MCPWM1_FAULT0_GPIO39 \ + ESP32_PINMUX(39, ESP_PWM1_F0_IN, ESP_NOSIG) + +/* MCPWM1_FAULT1 */ +#define MCPWM1_FAULT1_GPIO0 \ + ESP32_PINMUX(0, ESP_PWM1_F1_IN, ESP_NOSIG) + +#define MCPWM1_FAULT1_GPIO1 \ + ESP32_PINMUX(1, ESP_PWM1_F1_IN, ESP_NOSIG) + +#define MCPWM1_FAULT1_GPIO2 \ + ESP32_PINMUX(2, ESP_PWM1_F1_IN, ESP_NOSIG) + +#define MCPWM1_FAULT1_GPIO3 \ + ESP32_PINMUX(3, ESP_PWM1_F1_IN, ESP_NOSIG) + +#define MCPWM1_FAULT1_GPIO4 \ + ESP32_PINMUX(4, ESP_PWM1_F1_IN, ESP_NOSIG) + +#define MCPWM1_FAULT1_GPIO5 \ + ESP32_PINMUX(5, ESP_PWM1_F1_IN, ESP_NOSIG) + +#define MCPWM1_FAULT1_GPIO6 \ + ESP32_PINMUX(6, ESP_PWM1_F1_IN, ESP_NOSIG) + +#define MCPWM1_FAULT1_GPIO7 \ + ESP32_PINMUX(7, ESP_PWM1_F1_IN, ESP_NOSIG) + +#define MCPWM1_FAULT1_GPIO8 \ + ESP32_PINMUX(8, ESP_PWM1_F1_IN, ESP_NOSIG) + +#define MCPWM1_FAULT1_GPIO9 \ + ESP32_PINMUX(9, ESP_PWM1_F1_IN, ESP_NOSIG) + +#define MCPWM1_FAULT1_GPIO10 \ + ESP32_PINMUX(10, ESP_PWM1_F1_IN, ESP_NOSIG) + +#define MCPWM1_FAULT1_GPIO11 \ + ESP32_PINMUX(11, ESP_PWM1_F1_IN, ESP_NOSIG) + +#define MCPWM1_FAULT1_GPIO12 \ + ESP32_PINMUX(12, ESP_PWM1_F1_IN, ESP_NOSIG) + +#define MCPWM1_FAULT1_GPIO13 \ + ESP32_PINMUX(13, ESP_PWM1_F1_IN, ESP_NOSIG) + +#define MCPWM1_FAULT1_GPIO14 \ + ESP32_PINMUX(14, ESP_PWM1_F1_IN, ESP_NOSIG) + +#define MCPWM1_FAULT1_GPIO15 \ + ESP32_PINMUX(15, ESP_PWM1_F1_IN, ESP_NOSIG) + +#define MCPWM1_FAULT1_GPIO16 \ + ESP32_PINMUX(16, ESP_PWM1_F1_IN, ESP_NOSIG) + +#define MCPWM1_FAULT1_GPIO17 \ + ESP32_PINMUX(17, ESP_PWM1_F1_IN, ESP_NOSIG) + +#define MCPWM1_FAULT1_GPIO18 \ + ESP32_PINMUX(18, ESP_PWM1_F1_IN, ESP_NOSIG) + +#define MCPWM1_FAULT1_GPIO19 \ + ESP32_PINMUX(19, ESP_PWM1_F1_IN, ESP_NOSIG) + +#define MCPWM1_FAULT1_GPIO20 \ + ESP32_PINMUX(20, ESP_PWM1_F1_IN, ESP_NOSIG) + +#define MCPWM1_FAULT1_GPIO21 \ + ESP32_PINMUX(21, ESP_PWM1_F1_IN, ESP_NOSIG) + +#define MCPWM1_FAULT1_GPIO22 \ + ESP32_PINMUX(22, ESP_PWM1_F1_IN, ESP_NOSIG) + +#define MCPWM1_FAULT1_GPIO23 \ + ESP32_PINMUX(23, ESP_PWM1_F1_IN, ESP_NOSIG) + +#define MCPWM1_FAULT1_GPIO25 \ + ESP32_PINMUX(25, ESP_PWM1_F1_IN, ESP_NOSIG) + +#define MCPWM1_FAULT1_GPIO26 \ + ESP32_PINMUX(26, ESP_PWM1_F1_IN, ESP_NOSIG) + +#define MCPWM1_FAULT1_GPIO27 \ + ESP32_PINMUX(27, ESP_PWM1_F1_IN, ESP_NOSIG) + +#define MCPWM1_FAULT1_GPIO32 \ + ESP32_PINMUX(32, ESP_PWM1_F1_IN, ESP_NOSIG) + +#define MCPWM1_FAULT1_GPIO33 \ + ESP32_PINMUX(33, ESP_PWM1_F1_IN, ESP_NOSIG) + +#define MCPWM1_FAULT1_GPIO34 \ + ESP32_PINMUX(34, ESP_PWM1_F1_IN, ESP_NOSIG) + +#define MCPWM1_FAULT1_GPIO35 \ + ESP32_PINMUX(35, ESP_PWM1_F1_IN, ESP_NOSIG) + +#define MCPWM1_FAULT1_GPIO36 \ + ESP32_PINMUX(36, ESP_PWM1_F1_IN, ESP_NOSIG) + +#define MCPWM1_FAULT1_GPIO37 \ + ESP32_PINMUX(37, ESP_PWM1_F1_IN, ESP_NOSIG) + +#define MCPWM1_FAULT1_GPIO38 \ + ESP32_PINMUX(38, ESP_PWM1_F1_IN, ESP_NOSIG) + +#define MCPWM1_FAULT1_GPIO39 \ + ESP32_PINMUX(39, ESP_PWM1_F1_IN, ESP_NOSIG) + +/* MCPWM1_FAULT2 */ +#define MCPWM1_FAULT2_GPIO0 \ + ESP32_PINMUX(0, ESP_PWM1_F2_IN, ESP_NOSIG) + +#define MCPWM1_FAULT2_GPIO1 \ + ESP32_PINMUX(1, ESP_PWM1_F2_IN, ESP_NOSIG) + +#define MCPWM1_FAULT2_GPIO2 \ + ESP32_PINMUX(2, ESP_PWM1_F2_IN, ESP_NOSIG) + +#define MCPWM1_FAULT2_GPIO3 \ + ESP32_PINMUX(3, ESP_PWM1_F2_IN, ESP_NOSIG) + +#define MCPWM1_FAULT2_GPIO4 \ + ESP32_PINMUX(4, ESP_PWM1_F2_IN, ESP_NOSIG) + +#define MCPWM1_FAULT2_GPIO5 \ + ESP32_PINMUX(5, ESP_PWM1_F2_IN, ESP_NOSIG) + +#define MCPWM1_FAULT2_GPIO6 \ + ESP32_PINMUX(6, ESP_PWM1_F2_IN, ESP_NOSIG) + +#define MCPWM1_FAULT2_GPIO7 \ + ESP32_PINMUX(7, ESP_PWM1_F2_IN, ESP_NOSIG) + +#define MCPWM1_FAULT2_GPIO8 \ + ESP32_PINMUX(8, ESP_PWM1_F2_IN, ESP_NOSIG) + +#define MCPWM1_FAULT2_GPIO9 \ + ESP32_PINMUX(9, ESP_PWM1_F2_IN, ESP_NOSIG) + +#define MCPWM1_FAULT2_GPIO10 \ + ESP32_PINMUX(10, ESP_PWM1_F2_IN, ESP_NOSIG) + +#define MCPWM1_FAULT2_GPIO11 \ + ESP32_PINMUX(11, ESP_PWM1_F2_IN, ESP_NOSIG) + +#define MCPWM1_FAULT2_GPIO12 \ + ESP32_PINMUX(12, ESP_PWM1_F2_IN, ESP_NOSIG) + +#define MCPWM1_FAULT2_GPIO13 \ + ESP32_PINMUX(13, ESP_PWM1_F2_IN, ESP_NOSIG) + +#define MCPWM1_FAULT2_GPIO14 \ + ESP32_PINMUX(14, ESP_PWM1_F2_IN, ESP_NOSIG) + +#define MCPWM1_FAULT2_GPIO15 \ + ESP32_PINMUX(15, ESP_PWM1_F2_IN, ESP_NOSIG) + +#define MCPWM1_FAULT2_GPIO16 \ + ESP32_PINMUX(16, ESP_PWM1_F2_IN, ESP_NOSIG) + +#define MCPWM1_FAULT2_GPIO17 \ + ESP32_PINMUX(17, ESP_PWM1_F2_IN, ESP_NOSIG) + +#define MCPWM1_FAULT2_GPIO18 \ + ESP32_PINMUX(18, ESP_PWM1_F2_IN, ESP_NOSIG) + +#define MCPWM1_FAULT2_GPIO19 \ + ESP32_PINMUX(19, ESP_PWM1_F2_IN, ESP_NOSIG) + +#define MCPWM1_FAULT2_GPIO20 \ + ESP32_PINMUX(20, ESP_PWM1_F2_IN, ESP_NOSIG) + +#define MCPWM1_FAULT2_GPIO21 \ + ESP32_PINMUX(21, ESP_PWM1_F2_IN, ESP_NOSIG) + +#define MCPWM1_FAULT2_GPIO22 \ + ESP32_PINMUX(22, ESP_PWM1_F2_IN, ESP_NOSIG) + +#define MCPWM1_FAULT2_GPIO23 \ + ESP32_PINMUX(23, ESP_PWM1_F2_IN, ESP_NOSIG) + +#define MCPWM1_FAULT2_GPIO25 \ + ESP32_PINMUX(25, ESP_PWM1_F2_IN, ESP_NOSIG) + +#define MCPWM1_FAULT2_GPIO26 \ + ESP32_PINMUX(26, ESP_PWM1_F2_IN, ESP_NOSIG) + +#define MCPWM1_FAULT2_GPIO27 \ + ESP32_PINMUX(27, ESP_PWM1_F2_IN, ESP_NOSIG) + +#define MCPWM1_FAULT2_GPIO32 \ + ESP32_PINMUX(32, ESP_PWM1_F2_IN, ESP_NOSIG) + +#define MCPWM1_FAULT2_GPIO33 \ + ESP32_PINMUX(33, ESP_PWM1_F2_IN, ESP_NOSIG) + +#define MCPWM1_FAULT2_GPIO34 \ + ESP32_PINMUX(34, ESP_PWM1_F2_IN, ESP_NOSIG) + +#define MCPWM1_FAULT2_GPIO35 \ + ESP32_PINMUX(35, ESP_PWM1_F2_IN, ESP_NOSIG) + +#define MCPWM1_FAULT2_GPIO36 \ + ESP32_PINMUX(36, ESP_PWM1_F2_IN, ESP_NOSIG) + +#define MCPWM1_FAULT2_GPIO37 \ + ESP32_PINMUX(37, ESP_PWM1_F2_IN, ESP_NOSIG) + +#define MCPWM1_FAULT2_GPIO38 \ + ESP32_PINMUX(38, ESP_PWM1_F2_IN, ESP_NOSIG) + +#define MCPWM1_FAULT2_GPIO39 \ + ESP32_PINMUX(39, ESP_PWM1_F2_IN, ESP_NOSIG) + +/* MCPWM1_OUT0A */ +#define MCPWM1_OUT0A_GPIO0 \ + ESP32_PINMUX(0, ESP_NOSIG, ESP_PWM1_OUT0A) + +#define MCPWM1_OUT0A_GPIO1 \ + ESP32_PINMUX(1, ESP_NOSIG, ESP_PWM1_OUT0A) + +#define MCPWM1_OUT0A_GPIO2 \ + ESP32_PINMUX(2, ESP_NOSIG, ESP_PWM1_OUT0A) + +#define MCPWM1_OUT0A_GPIO3 \ + ESP32_PINMUX(3, ESP_NOSIG, ESP_PWM1_OUT0A) + +#define MCPWM1_OUT0A_GPIO4 \ + ESP32_PINMUX(4, ESP_NOSIG, ESP_PWM1_OUT0A) + +#define MCPWM1_OUT0A_GPIO5 \ + ESP32_PINMUX(5, ESP_NOSIG, ESP_PWM1_OUT0A) + +#define MCPWM1_OUT0A_GPIO6 \ + ESP32_PINMUX(6, ESP_NOSIG, ESP_PWM1_OUT0A) + +#define MCPWM1_OUT0A_GPIO7 \ + ESP32_PINMUX(7, ESP_NOSIG, ESP_PWM1_OUT0A) + +#define MCPWM1_OUT0A_GPIO8 \ + ESP32_PINMUX(8, ESP_NOSIG, ESP_PWM1_OUT0A) + +#define MCPWM1_OUT0A_GPIO9 \ + ESP32_PINMUX(9, ESP_NOSIG, ESP_PWM1_OUT0A) + +#define MCPWM1_OUT0A_GPIO10 \ + ESP32_PINMUX(10, ESP_NOSIG, ESP_PWM1_OUT0A) + +#define MCPWM1_OUT0A_GPIO11 \ + ESP32_PINMUX(11, ESP_NOSIG, ESP_PWM1_OUT0A) + +#define MCPWM1_OUT0A_GPIO12 \ + ESP32_PINMUX(12, ESP_NOSIG, ESP_PWM1_OUT0A) + +#define MCPWM1_OUT0A_GPIO13 \ + ESP32_PINMUX(13, ESP_NOSIG, ESP_PWM1_OUT0A) + +#define MCPWM1_OUT0A_GPIO14 \ + ESP32_PINMUX(14, ESP_NOSIG, ESP_PWM1_OUT0A) + +#define MCPWM1_OUT0A_GPIO15 \ + ESP32_PINMUX(15, ESP_NOSIG, ESP_PWM1_OUT0A) + +#define MCPWM1_OUT0A_GPIO16 \ + ESP32_PINMUX(16, ESP_NOSIG, ESP_PWM1_OUT0A) + +#define MCPWM1_OUT0A_GPIO17 \ + ESP32_PINMUX(17, ESP_NOSIG, ESP_PWM1_OUT0A) + +#define MCPWM1_OUT0A_GPIO18 \ + ESP32_PINMUX(18, ESP_NOSIG, ESP_PWM1_OUT0A) + +#define MCPWM1_OUT0A_GPIO19 \ + ESP32_PINMUX(19, ESP_NOSIG, ESP_PWM1_OUT0A) + +#define MCPWM1_OUT0A_GPIO20 \ + ESP32_PINMUX(20, ESP_NOSIG, ESP_PWM1_OUT0A) + +#define MCPWM1_OUT0A_GPIO21 \ + ESP32_PINMUX(21, ESP_NOSIG, ESP_PWM1_OUT0A) + +#define MCPWM1_OUT0A_GPIO22 \ + ESP32_PINMUX(22, ESP_NOSIG, ESP_PWM1_OUT0A) + +#define MCPWM1_OUT0A_GPIO23 \ + ESP32_PINMUX(23, ESP_NOSIG, ESP_PWM1_OUT0A) + +#define MCPWM1_OUT0A_GPIO25 \ + ESP32_PINMUX(25, ESP_NOSIG, ESP_PWM1_OUT0A) + +#define MCPWM1_OUT0A_GPIO26 \ + ESP32_PINMUX(26, ESP_NOSIG, ESP_PWM1_OUT0A) + +#define MCPWM1_OUT0A_GPIO27 \ + ESP32_PINMUX(27, ESP_NOSIG, ESP_PWM1_OUT0A) + +#define MCPWM1_OUT0A_GPIO32 \ + ESP32_PINMUX(32, ESP_NOSIG, ESP_PWM1_OUT0A) + +#define MCPWM1_OUT0A_GPIO33 \ + ESP32_PINMUX(33, ESP_NOSIG, ESP_PWM1_OUT0A) + +/* MCPWM1_OUT0B */ +#define MCPWM1_OUT0B_GPIO0 \ + ESP32_PINMUX(0, ESP_NOSIG, ESP_PWM1_OUT0B) + +#define MCPWM1_OUT0B_GPIO1 \ + ESP32_PINMUX(1, ESP_NOSIG, ESP_PWM1_OUT0B) + +#define MCPWM1_OUT0B_GPIO2 \ + ESP32_PINMUX(2, ESP_NOSIG, ESP_PWM1_OUT0B) + +#define MCPWM1_OUT0B_GPIO3 \ + ESP32_PINMUX(3, ESP_NOSIG, ESP_PWM1_OUT0B) + +#define MCPWM1_OUT0B_GPIO4 \ + ESP32_PINMUX(4, ESP_NOSIG, ESP_PWM1_OUT0B) + +#define MCPWM1_OUT0B_GPIO5 \ + ESP32_PINMUX(5, ESP_NOSIG, ESP_PWM1_OUT0B) + +#define MCPWM1_OUT0B_GPIO6 \ + ESP32_PINMUX(6, ESP_NOSIG, ESP_PWM1_OUT0B) + +#define MCPWM1_OUT0B_GPIO7 \ + ESP32_PINMUX(7, ESP_NOSIG, ESP_PWM1_OUT0B) + +#define MCPWM1_OUT0B_GPIO8 \ + ESP32_PINMUX(8, ESP_NOSIG, ESP_PWM1_OUT0B) + +#define MCPWM1_OUT0B_GPIO9 \ + ESP32_PINMUX(9, ESP_NOSIG, ESP_PWM1_OUT0B) + +#define MCPWM1_OUT0B_GPIO10 \ + ESP32_PINMUX(10, ESP_NOSIG, ESP_PWM1_OUT0B) + +#define MCPWM1_OUT0B_GPIO11 \ + ESP32_PINMUX(11, ESP_NOSIG, ESP_PWM1_OUT0B) + +#define MCPWM1_OUT0B_GPIO12 \ + ESP32_PINMUX(12, ESP_NOSIG, ESP_PWM1_OUT0B) + +#define MCPWM1_OUT0B_GPIO13 \ + ESP32_PINMUX(13, ESP_NOSIG, ESP_PWM1_OUT0B) + +#define MCPWM1_OUT0B_GPIO14 \ + ESP32_PINMUX(14, ESP_NOSIG, ESP_PWM1_OUT0B) + +#define MCPWM1_OUT0B_GPIO15 \ + ESP32_PINMUX(15, ESP_NOSIG, ESP_PWM1_OUT0B) + +#define MCPWM1_OUT0B_GPIO16 \ + ESP32_PINMUX(16, ESP_NOSIG, ESP_PWM1_OUT0B) + +#define MCPWM1_OUT0B_GPIO17 \ + ESP32_PINMUX(17, ESP_NOSIG, ESP_PWM1_OUT0B) + +#define MCPWM1_OUT0B_GPIO18 \ + ESP32_PINMUX(18, ESP_NOSIG, ESP_PWM1_OUT0B) + +#define MCPWM1_OUT0B_GPIO19 \ + ESP32_PINMUX(19, ESP_NOSIG, ESP_PWM1_OUT0B) + +#define MCPWM1_OUT0B_GPIO20 \ + ESP32_PINMUX(20, ESP_NOSIG, ESP_PWM1_OUT0B) + +#define MCPWM1_OUT0B_GPIO21 \ + ESP32_PINMUX(21, ESP_NOSIG, ESP_PWM1_OUT0B) + +#define MCPWM1_OUT0B_GPIO22 \ + ESP32_PINMUX(22, ESP_NOSIG, ESP_PWM1_OUT0B) + +#define MCPWM1_OUT0B_GPIO23 \ + ESP32_PINMUX(23, ESP_NOSIG, ESP_PWM1_OUT0B) + +#define MCPWM1_OUT0B_GPIO25 \ + ESP32_PINMUX(25, ESP_NOSIG, ESP_PWM1_OUT0B) + +#define MCPWM1_OUT0B_GPIO26 \ + ESP32_PINMUX(26, ESP_NOSIG, ESP_PWM1_OUT0B) + +#define MCPWM1_OUT0B_GPIO27 \ + ESP32_PINMUX(27, ESP_NOSIG, ESP_PWM1_OUT0B) + +#define MCPWM1_OUT0B_GPIO32 \ + ESP32_PINMUX(32, ESP_NOSIG, ESP_PWM1_OUT0B) + +#define MCPWM1_OUT0B_GPIO33 \ + ESP32_PINMUX(33, ESP_NOSIG, ESP_PWM1_OUT0B) + +/* MCPWM1_OUT1A */ +#define MCPWM1_OUT1A_GPIO0 \ + ESP32_PINMUX(0, ESP_NOSIG, ESP_PWM1_OUT1A) + +#define MCPWM1_OUT1A_GPIO1 \ + ESP32_PINMUX(1, ESP_NOSIG, ESP_PWM1_OUT1A) + +#define MCPWM1_OUT1A_GPIO2 \ + ESP32_PINMUX(2, ESP_NOSIG, ESP_PWM1_OUT1A) + +#define MCPWM1_OUT1A_GPIO3 \ + ESP32_PINMUX(3, ESP_NOSIG, ESP_PWM1_OUT1A) + +#define MCPWM1_OUT1A_GPIO4 \ + ESP32_PINMUX(4, ESP_NOSIG, ESP_PWM1_OUT1A) + +#define MCPWM1_OUT1A_GPIO5 \ + ESP32_PINMUX(5, ESP_NOSIG, ESP_PWM1_OUT1A) + +#define MCPWM1_OUT1A_GPIO6 \ + ESP32_PINMUX(6, ESP_NOSIG, ESP_PWM1_OUT1A) + +#define MCPWM1_OUT1A_GPIO7 \ + ESP32_PINMUX(7, ESP_NOSIG, ESP_PWM1_OUT1A) + +#define MCPWM1_OUT1A_GPIO8 \ + ESP32_PINMUX(8, ESP_NOSIG, ESP_PWM1_OUT1A) + +#define MCPWM1_OUT1A_GPIO9 \ + ESP32_PINMUX(9, ESP_NOSIG, ESP_PWM1_OUT1A) + +#define MCPWM1_OUT1A_GPIO10 \ + ESP32_PINMUX(10, ESP_NOSIG, ESP_PWM1_OUT1A) + +#define MCPWM1_OUT1A_GPIO11 \ + ESP32_PINMUX(11, ESP_NOSIG, ESP_PWM1_OUT1A) + +#define MCPWM1_OUT1A_GPIO12 \ + ESP32_PINMUX(12, ESP_NOSIG, ESP_PWM1_OUT1A) + +#define MCPWM1_OUT1A_GPIO13 \ + ESP32_PINMUX(13, ESP_NOSIG, ESP_PWM1_OUT1A) + +#define MCPWM1_OUT1A_GPIO14 \ + ESP32_PINMUX(14, ESP_NOSIG, ESP_PWM1_OUT1A) + +#define MCPWM1_OUT1A_GPIO15 \ + ESP32_PINMUX(15, ESP_NOSIG, ESP_PWM1_OUT1A) + +#define MCPWM1_OUT1A_GPIO16 \ + ESP32_PINMUX(16, ESP_NOSIG, ESP_PWM1_OUT1A) + +#define MCPWM1_OUT1A_GPIO17 \ + ESP32_PINMUX(17, ESP_NOSIG, ESP_PWM1_OUT1A) + +#define MCPWM1_OUT1A_GPIO18 \ + ESP32_PINMUX(18, ESP_NOSIG, ESP_PWM1_OUT1A) + +#define MCPWM1_OUT1A_GPIO19 \ + ESP32_PINMUX(19, ESP_NOSIG, ESP_PWM1_OUT1A) + +#define MCPWM1_OUT1A_GPIO20 \ + ESP32_PINMUX(20, ESP_NOSIG, ESP_PWM1_OUT1A) + +#define MCPWM1_OUT1A_GPIO21 \ + ESP32_PINMUX(21, ESP_NOSIG, ESP_PWM1_OUT1A) + +#define MCPWM1_OUT1A_GPIO22 \ + ESP32_PINMUX(22, ESP_NOSIG, ESP_PWM1_OUT1A) + +#define MCPWM1_OUT1A_GPIO23 \ + ESP32_PINMUX(23, ESP_NOSIG, ESP_PWM1_OUT1A) + +#define MCPWM1_OUT1A_GPIO25 \ + ESP32_PINMUX(25, ESP_NOSIG, ESP_PWM1_OUT1A) + +#define MCPWM1_OUT1A_GPIO26 \ + ESP32_PINMUX(26, ESP_NOSIG, ESP_PWM1_OUT1A) + +#define MCPWM1_OUT1A_GPIO27 \ + ESP32_PINMUX(27, ESP_NOSIG, ESP_PWM1_OUT1A) + +#define MCPWM1_OUT1A_GPIO32 \ + ESP32_PINMUX(32, ESP_NOSIG, ESP_PWM1_OUT1A) + +#define MCPWM1_OUT1A_GPIO33 \ + ESP32_PINMUX(33, ESP_NOSIG, ESP_PWM1_OUT1A) + +/* MCPWM1_OUT1B */ +#define MCPWM1_OUT1B_GPIO0 \ + ESP32_PINMUX(0, ESP_NOSIG, ESP_PWM1_OUT1B) + +#define MCPWM1_OUT1B_GPIO1 \ + ESP32_PINMUX(1, ESP_NOSIG, ESP_PWM1_OUT1B) + +#define MCPWM1_OUT1B_GPIO2 \ + ESP32_PINMUX(2, ESP_NOSIG, ESP_PWM1_OUT1B) + +#define MCPWM1_OUT1B_GPIO3 \ + ESP32_PINMUX(3, ESP_NOSIG, ESP_PWM1_OUT1B) + +#define MCPWM1_OUT1B_GPIO4 \ + ESP32_PINMUX(4, ESP_NOSIG, ESP_PWM1_OUT1B) + +#define MCPWM1_OUT1B_GPIO5 \ + ESP32_PINMUX(5, ESP_NOSIG, ESP_PWM1_OUT1B) + +#define MCPWM1_OUT1B_GPIO6 \ + ESP32_PINMUX(6, ESP_NOSIG, ESP_PWM1_OUT1B) + +#define MCPWM1_OUT1B_GPIO7 \ + ESP32_PINMUX(7, ESP_NOSIG, ESP_PWM1_OUT1B) + +#define MCPWM1_OUT1B_GPIO8 \ + ESP32_PINMUX(8, ESP_NOSIG, ESP_PWM1_OUT1B) + +#define MCPWM1_OUT1B_GPIO9 \ + ESP32_PINMUX(9, ESP_NOSIG, ESP_PWM1_OUT1B) + +#define MCPWM1_OUT1B_GPIO10 \ + ESP32_PINMUX(10, ESP_NOSIG, ESP_PWM1_OUT1B) + +#define MCPWM1_OUT1B_GPIO11 \ + ESP32_PINMUX(11, ESP_NOSIG, ESP_PWM1_OUT1B) + +#define MCPWM1_OUT1B_GPIO12 \ + ESP32_PINMUX(12, ESP_NOSIG, ESP_PWM1_OUT1B) + +#define MCPWM1_OUT1B_GPIO13 \ + ESP32_PINMUX(13, ESP_NOSIG, ESP_PWM1_OUT1B) + +#define MCPWM1_OUT1B_GPIO14 \ + ESP32_PINMUX(14, ESP_NOSIG, ESP_PWM1_OUT1B) + +#define MCPWM1_OUT1B_GPIO15 \ + ESP32_PINMUX(15, ESP_NOSIG, ESP_PWM1_OUT1B) + +#define MCPWM1_OUT1B_GPIO16 \ + ESP32_PINMUX(16, ESP_NOSIG, ESP_PWM1_OUT1B) + +#define MCPWM1_OUT1B_GPIO17 \ + ESP32_PINMUX(17, ESP_NOSIG, ESP_PWM1_OUT1B) + +#define MCPWM1_OUT1B_GPIO18 \ + ESP32_PINMUX(18, ESP_NOSIG, ESP_PWM1_OUT1B) + +#define MCPWM1_OUT1B_GPIO19 \ + ESP32_PINMUX(19, ESP_NOSIG, ESP_PWM1_OUT1B) + +#define MCPWM1_OUT1B_GPIO20 \ + ESP32_PINMUX(20, ESP_NOSIG, ESP_PWM1_OUT1B) + +#define MCPWM1_OUT1B_GPIO21 \ + ESP32_PINMUX(21, ESP_NOSIG, ESP_PWM1_OUT1B) + +#define MCPWM1_OUT1B_GPIO22 \ + ESP32_PINMUX(22, ESP_NOSIG, ESP_PWM1_OUT1B) + +#define MCPWM1_OUT1B_GPIO23 \ + ESP32_PINMUX(23, ESP_NOSIG, ESP_PWM1_OUT1B) + +#define MCPWM1_OUT1B_GPIO25 \ + ESP32_PINMUX(25, ESP_NOSIG, ESP_PWM1_OUT1B) + +#define MCPWM1_OUT1B_GPIO26 \ + ESP32_PINMUX(26, ESP_NOSIG, ESP_PWM1_OUT1B) + +#define MCPWM1_OUT1B_GPIO27 \ + ESP32_PINMUX(27, ESP_NOSIG, ESP_PWM1_OUT1B) + +#define MCPWM1_OUT1B_GPIO32 \ + ESP32_PINMUX(32, ESP_NOSIG, ESP_PWM1_OUT1B) + +#define MCPWM1_OUT1B_GPIO33 \ + ESP32_PINMUX(33, ESP_NOSIG, ESP_PWM1_OUT1B) + +/* MCPWM1_OUT2A */ +#define MCPWM1_OUT2A_GPIO0 \ + ESP32_PINMUX(0, ESP_NOSIG, ESP_PWM1_OUT2A) + +#define MCPWM1_OUT2A_GPIO1 \ + ESP32_PINMUX(1, ESP_NOSIG, ESP_PWM1_OUT2A) + +#define MCPWM1_OUT2A_GPIO2 \ + ESP32_PINMUX(2, ESP_NOSIG, ESP_PWM1_OUT2A) + +#define MCPWM1_OUT2A_GPIO3 \ + ESP32_PINMUX(3, ESP_NOSIG, ESP_PWM1_OUT2A) + +#define MCPWM1_OUT2A_GPIO4 \ + ESP32_PINMUX(4, ESP_NOSIG, ESP_PWM1_OUT2A) + +#define MCPWM1_OUT2A_GPIO5 \ + ESP32_PINMUX(5, ESP_NOSIG, ESP_PWM1_OUT2A) + +#define MCPWM1_OUT2A_GPIO6 \ + ESP32_PINMUX(6, ESP_NOSIG, ESP_PWM1_OUT2A) + +#define MCPWM1_OUT2A_GPIO7 \ + ESP32_PINMUX(7, ESP_NOSIG, ESP_PWM1_OUT2A) + +#define MCPWM1_OUT2A_GPIO8 \ + ESP32_PINMUX(8, ESP_NOSIG, ESP_PWM1_OUT2A) + +#define MCPWM1_OUT2A_GPIO9 \ + ESP32_PINMUX(9, ESP_NOSIG, ESP_PWM1_OUT2A) + +#define MCPWM1_OUT2A_GPIO10 \ + ESP32_PINMUX(10, ESP_NOSIG, ESP_PWM1_OUT2A) + +#define MCPWM1_OUT2A_GPIO11 \ + ESP32_PINMUX(11, ESP_NOSIG, ESP_PWM1_OUT2A) + +#define MCPWM1_OUT2A_GPIO12 \ + ESP32_PINMUX(12, ESP_NOSIG, ESP_PWM1_OUT2A) + +#define MCPWM1_OUT2A_GPIO13 \ + ESP32_PINMUX(13, ESP_NOSIG, ESP_PWM1_OUT2A) + +#define MCPWM1_OUT2A_GPIO14 \ + ESP32_PINMUX(14, ESP_NOSIG, ESP_PWM1_OUT2A) + +#define MCPWM1_OUT2A_GPIO15 \ + ESP32_PINMUX(15, ESP_NOSIG, ESP_PWM1_OUT2A) + +#define MCPWM1_OUT2A_GPIO16 \ + ESP32_PINMUX(16, ESP_NOSIG, ESP_PWM1_OUT2A) + +#define MCPWM1_OUT2A_GPIO17 \ + ESP32_PINMUX(17, ESP_NOSIG, ESP_PWM1_OUT2A) + +#define MCPWM1_OUT2A_GPIO18 \ + ESP32_PINMUX(18, ESP_NOSIG, ESP_PWM1_OUT2A) + +#define MCPWM1_OUT2A_GPIO19 \ + ESP32_PINMUX(19, ESP_NOSIG, ESP_PWM1_OUT2A) + +#define MCPWM1_OUT2A_GPIO20 \ + ESP32_PINMUX(20, ESP_NOSIG, ESP_PWM1_OUT2A) + +#define MCPWM1_OUT2A_GPIO21 \ + ESP32_PINMUX(21, ESP_NOSIG, ESP_PWM1_OUT2A) + +#define MCPWM1_OUT2A_GPIO22 \ + ESP32_PINMUX(22, ESP_NOSIG, ESP_PWM1_OUT2A) + +#define MCPWM1_OUT2A_GPIO23 \ + ESP32_PINMUX(23, ESP_NOSIG, ESP_PWM1_OUT2A) + +#define MCPWM1_OUT2A_GPIO25 \ + ESP32_PINMUX(25, ESP_NOSIG, ESP_PWM1_OUT2A) + +#define MCPWM1_OUT2A_GPIO26 \ + ESP32_PINMUX(26, ESP_NOSIG, ESP_PWM1_OUT2A) + +#define MCPWM1_OUT2A_GPIO27 \ + ESP32_PINMUX(27, ESP_NOSIG, ESP_PWM1_OUT2A) + +#define MCPWM1_OUT2A_GPIO32 \ + ESP32_PINMUX(32, ESP_NOSIG, ESP_PWM1_OUT2A) + +#define MCPWM1_OUT2A_GPIO33 \ + ESP32_PINMUX(33, ESP_NOSIG, ESP_PWM1_OUT2A) + +/* MCPWM1_OUT2B */ +#define MCPWM1_OUT2B_GPIO0 \ + ESP32_PINMUX(0, ESP_NOSIG, ESP_PWM1_OUT2B) + +#define MCPWM1_OUT2B_GPIO1 \ + ESP32_PINMUX(1, ESP_NOSIG, ESP_PWM1_OUT2B) + +#define MCPWM1_OUT2B_GPIO2 \ + ESP32_PINMUX(2, ESP_NOSIG, ESP_PWM1_OUT2B) + +#define MCPWM1_OUT2B_GPIO3 \ + ESP32_PINMUX(3, ESP_NOSIG, ESP_PWM1_OUT2B) + +#define MCPWM1_OUT2B_GPIO4 \ + ESP32_PINMUX(4, ESP_NOSIG, ESP_PWM1_OUT2B) + +#define MCPWM1_OUT2B_GPIO5 \ + ESP32_PINMUX(5, ESP_NOSIG, ESP_PWM1_OUT2B) + +#define MCPWM1_OUT2B_GPIO6 \ + ESP32_PINMUX(6, ESP_NOSIG, ESP_PWM1_OUT2B) + +#define MCPWM1_OUT2B_GPIO7 \ + ESP32_PINMUX(7, ESP_NOSIG, ESP_PWM1_OUT2B) + +#define MCPWM1_OUT2B_GPIO8 \ + ESP32_PINMUX(8, ESP_NOSIG, ESP_PWM1_OUT2B) + +#define MCPWM1_OUT2B_GPIO9 \ + ESP32_PINMUX(9, ESP_NOSIG, ESP_PWM1_OUT2B) + +#define MCPWM1_OUT2B_GPIO10 \ + ESP32_PINMUX(10, ESP_NOSIG, ESP_PWM1_OUT2B) + +#define MCPWM1_OUT2B_GPIO11 \ + ESP32_PINMUX(11, ESP_NOSIG, ESP_PWM1_OUT2B) + +#define MCPWM1_OUT2B_GPIO12 \ + ESP32_PINMUX(12, ESP_NOSIG, ESP_PWM1_OUT2B) + +#define MCPWM1_OUT2B_GPIO13 \ + ESP32_PINMUX(13, ESP_NOSIG, ESP_PWM1_OUT2B) + +#define MCPWM1_OUT2B_GPIO14 \ + ESP32_PINMUX(14, ESP_NOSIG, ESP_PWM1_OUT2B) + +#define MCPWM1_OUT2B_GPIO15 \ + ESP32_PINMUX(15, ESP_NOSIG, ESP_PWM1_OUT2B) + +#define MCPWM1_OUT2B_GPIO16 \ + ESP32_PINMUX(16, ESP_NOSIG, ESP_PWM1_OUT2B) + +#define MCPWM1_OUT2B_GPIO17 \ + ESP32_PINMUX(17, ESP_NOSIG, ESP_PWM1_OUT2B) + +#define MCPWM1_OUT2B_GPIO18 \ + ESP32_PINMUX(18, ESP_NOSIG, ESP_PWM1_OUT2B) + +#define MCPWM1_OUT2B_GPIO19 \ + ESP32_PINMUX(19, ESP_NOSIG, ESP_PWM1_OUT2B) + +#define MCPWM1_OUT2B_GPIO20 \ + ESP32_PINMUX(20, ESP_NOSIG, ESP_PWM1_OUT2B) + +#define MCPWM1_OUT2B_GPIO21 \ + ESP32_PINMUX(21, ESP_NOSIG, ESP_PWM1_OUT2B) + +#define MCPWM1_OUT2B_GPIO22 \ + ESP32_PINMUX(22, ESP_NOSIG, ESP_PWM1_OUT2B) + +#define MCPWM1_OUT2B_GPIO23 \ + ESP32_PINMUX(23, ESP_NOSIG, ESP_PWM1_OUT2B) + +#define MCPWM1_OUT2B_GPIO25 \ + ESP32_PINMUX(25, ESP_NOSIG, ESP_PWM1_OUT2B) + +#define MCPWM1_OUT2B_GPIO26 \ + ESP32_PINMUX(26, ESP_NOSIG, ESP_PWM1_OUT2B) + +#define MCPWM1_OUT2B_GPIO27 \ + ESP32_PINMUX(27, ESP_NOSIG, ESP_PWM1_OUT2B) + +#define MCPWM1_OUT2B_GPIO32 \ + ESP32_PINMUX(32, ESP_NOSIG, ESP_PWM1_OUT2B) + +#define MCPWM1_OUT2B_GPIO33 \ + ESP32_PINMUX(33, ESP_NOSIG, ESP_PWM1_OUT2B) + +/* MCPWM1_SYNC0 */ +#define MCPWM1_SYNC0_GPIO0 \ + ESP32_PINMUX(0, ESP_PWM1_SYNC0_IN, ESP_NOSIG) + +#define MCPWM1_SYNC0_GPIO1 \ + ESP32_PINMUX(1, ESP_PWM1_SYNC0_IN, ESP_NOSIG) + +#define MCPWM1_SYNC0_GPIO2 \ + ESP32_PINMUX(2, ESP_PWM1_SYNC0_IN, ESP_NOSIG) + +#define MCPWM1_SYNC0_GPIO3 \ + ESP32_PINMUX(3, ESP_PWM1_SYNC0_IN, ESP_NOSIG) + +#define MCPWM1_SYNC0_GPIO4 \ + ESP32_PINMUX(4, ESP_PWM1_SYNC0_IN, ESP_NOSIG) + +#define MCPWM1_SYNC0_GPIO5 \ + ESP32_PINMUX(5, ESP_PWM1_SYNC0_IN, ESP_NOSIG) + +#define MCPWM1_SYNC0_GPIO6 \ + ESP32_PINMUX(6, ESP_PWM1_SYNC0_IN, ESP_NOSIG) + +#define MCPWM1_SYNC0_GPIO7 \ + ESP32_PINMUX(7, ESP_PWM1_SYNC0_IN, ESP_NOSIG) + +#define MCPWM1_SYNC0_GPIO8 \ + ESP32_PINMUX(8, ESP_PWM1_SYNC0_IN, ESP_NOSIG) + +#define MCPWM1_SYNC0_GPIO9 \ + ESP32_PINMUX(9, ESP_PWM1_SYNC0_IN, ESP_NOSIG) + +#define MCPWM1_SYNC0_GPIO10 \ + ESP32_PINMUX(10, ESP_PWM1_SYNC0_IN, ESP_NOSIG) + +#define MCPWM1_SYNC0_GPIO11 \ + ESP32_PINMUX(11, ESP_PWM1_SYNC0_IN, ESP_NOSIG) + +#define MCPWM1_SYNC0_GPIO12 \ + ESP32_PINMUX(12, ESP_PWM1_SYNC0_IN, ESP_NOSIG) + +#define MCPWM1_SYNC0_GPIO13 \ + ESP32_PINMUX(13, ESP_PWM1_SYNC0_IN, ESP_NOSIG) + +#define MCPWM1_SYNC0_GPIO14 \ + ESP32_PINMUX(14, ESP_PWM1_SYNC0_IN, ESP_NOSIG) + +#define MCPWM1_SYNC0_GPIO15 \ + ESP32_PINMUX(15, ESP_PWM1_SYNC0_IN, ESP_NOSIG) + +#define MCPWM1_SYNC0_GPIO16 \ + ESP32_PINMUX(16, ESP_PWM1_SYNC0_IN, ESP_NOSIG) + +#define MCPWM1_SYNC0_GPIO17 \ + ESP32_PINMUX(17, ESP_PWM1_SYNC0_IN, ESP_NOSIG) + +#define MCPWM1_SYNC0_GPIO18 \ + ESP32_PINMUX(18, ESP_PWM1_SYNC0_IN, ESP_NOSIG) + +#define MCPWM1_SYNC0_GPIO19 \ + ESP32_PINMUX(19, ESP_PWM1_SYNC0_IN, ESP_NOSIG) + +#define MCPWM1_SYNC0_GPIO20 \ + ESP32_PINMUX(20, ESP_PWM1_SYNC0_IN, ESP_NOSIG) + +#define MCPWM1_SYNC0_GPIO21 \ + ESP32_PINMUX(21, ESP_PWM1_SYNC0_IN, ESP_NOSIG) + +#define MCPWM1_SYNC0_GPIO22 \ + ESP32_PINMUX(22, ESP_PWM1_SYNC0_IN, ESP_NOSIG) + +#define MCPWM1_SYNC0_GPIO23 \ + ESP32_PINMUX(23, ESP_PWM1_SYNC0_IN, ESP_NOSIG) + +#define MCPWM1_SYNC0_GPIO25 \ + ESP32_PINMUX(25, ESP_PWM1_SYNC0_IN, ESP_NOSIG) + +#define MCPWM1_SYNC0_GPIO26 \ + ESP32_PINMUX(26, ESP_PWM1_SYNC0_IN, ESP_NOSIG) + +#define MCPWM1_SYNC0_GPIO27 \ + ESP32_PINMUX(27, ESP_PWM1_SYNC0_IN, ESP_NOSIG) + +#define MCPWM1_SYNC0_GPIO32 \ + ESP32_PINMUX(32, ESP_PWM1_SYNC0_IN, ESP_NOSIG) + +#define MCPWM1_SYNC0_GPIO33 \ + ESP32_PINMUX(33, ESP_PWM1_SYNC0_IN, ESP_NOSIG) + +#define MCPWM1_SYNC0_GPIO34 \ + ESP32_PINMUX(34, ESP_PWM1_SYNC0_IN, ESP_NOSIG) + +#define MCPWM1_SYNC0_GPIO35 \ + ESP32_PINMUX(35, ESP_PWM1_SYNC0_IN, ESP_NOSIG) + +#define MCPWM1_SYNC0_GPIO36 \ + ESP32_PINMUX(36, ESP_PWM1_SYNC0_IN, ESP_NOSIG) + +#define MCPWM1_SYNC0_GPIO37 \ + ESP32_PINMUX(37, ESP_PWM1_SYNC0_IN, ESP_NOSIG) + +#define MCPWM1_SYNC0_GPIO38 \ + ESP32_PINMUX(38, ESP_PWM1_SYNC0_IN, ESP_NOSIG) + +#define MCPWM1_SYNC0_GPIO39 \ + ESP32_PINMUX(39, ESP_PWM1_SYNC0_IN, ESP_NOSIG) + +/* MCPWM1_SYNC1 */ +#define MCPWM1_SYNC1_GPIO0 \ + ESP32_PINMUX(0, ESP_PWM1_SYNC1_IN, ESP_NOSIG) + +#define MCPWM1_SYNC1_GPIO1 \ + ESP32_PINMUX(1, ESP_PWM1_SYNC1_IN, ESP_NOSIG) + +#define MCPWM1_SYNC1_GPIO2 \ + ESP32_PINMUX(2, ESP_PWM1_SYNC1_IN, ESP_NOSIG) + +#define MCPWM1_SYNC1_GPIO3 \ + ESP32_PINMUX(3, ESP_PWM1_SYNC1_IN, ESP_NOSIG) + +#define MCPWM1_SYNC1_GPIO4 \ + ESP32_PINMUX(4, ESP_PWM1_SYNC1_IN, ESP_NOSIG) + +#define MCPWM1_SYNC1_GPIO5 \ + ESP32_PINMUX(5, ESP_PWM1_SYNC1_IN, ESP_NOSIG) + +#define MCPWM1_SYNC1_GPIO6 \ + ESP32_PINMUX(6, ESP_PWM1_SYNC1_IN, ESP_NOSIG) + +#define MCPWM1_SYNC1_GPIO7 \ + ESP32_PINMUX(7, ESP_PWM1_SYNC1_IN, ESP_NOSIG) + +#define MCPWM1_SYNC1_GPIO8 \ + ESP32_PINMUX(8, ESP_PWM1_SYNC1_IN, ESP_NOSIG) + +#define MCPWM1_SYNC1_GPIO9 \ + ESP32_PINMUX(9, ESP_PWM1_SYNC1_IN, ESP_NOSIG) + +#define MCPWM1_SYNC1_GPIO10 \ + ESP32_PINMUX(10, ESP_PWM1_SYNC1_IN, ESP_NOSIG) + +#define MCPWM1_SYNC1_GPIO11 \ + ESP32_PINMUX(11, ESP_PWM1_SYNC1_IN, ESP_NOSIG) + +#define MCPWM1_SYNC1_GPIO12 \ + ESP32_PINMUX(12, ESP_PWM1_SYNC1_IN, ESP_NOSIG) + +#define MCPWM1_SYNC1_GPIO13 \ + ESP32_PINMUX(13, ESP_PWM1_SYNC1_IN, ESP_NOSIG) + +#define MCPWM1_SYNC1_GPIO14 \ + ESP32_PINMUX(14, ESP_PWM1_SYNC1_IN, ESP_NOSIG) + +#define MCPWM1_SYNC1_GPIO15 \ + ESP32_PINMUX(15, ESP_PWM1_SYNC1_IN, ESP_NOSIG) + +#define MCPWM1_SYNC1_GPIO16 \ + ESP32_PINMUX(16, ESP_PWM1_SYNC1_IN, ESP_NOSIG) + +#define MCPWM1_SYNC1_GPIO17 \ + ESP32_PINMUX(17, ESP_PWM1_SYNC1_IN, ESP_NOSIG) + +#define MCPWM1_SYNC1_GPIO18 \ + ESP32_PINMUX(18, ESP_PWM1_SYNC1_IN, ESP_NOSIG) + +#define MCPWM1_SYNC1_GPIO19 \ + ESP32_PINMUX(19, ESP_PWM1_SYNC1_IN, ESP_NOSIG) + +#define MCPWM1_SYNC1_GPIO20 \ + ESP32_PINMUX(20, ESP_PWM1_SYNC1_IN, ESP_NOSIG) + +#define MCPWM1_SYNC1_GPIO21 \ + ESP32_PINMUX(21, ESP_PWM1_SYNC1_IN, ESP_NOSIG) + +#define MCPWM1_SYNC1_GPIO22 \ + ESP32_PINMUX(22, ESP_PWM1_SYNC1_IN, ESP_NOSIG) + +#define MCPWM1_SYNC1_GPIO23 \ + ESP32_PINMUX(23, ESP_PWM1_SYNC1_IN, ESP_NOSIG) + +#define MCPWM1_SYNC1_GPIO25 \ + ESP32_PINMUX(25, ESP_PWM1_SYNC1_IN, ESP_NOSIG) + +#define MCPWM1_SYNC1_GPIO26 \ + ESP32_PINMUX(26, ESP_PWM1_SYNC1_IN, ESP_NOSIG) + +#define MCPWM1_SYNC1_GPIO27 \ + ESP32_PINMUX(27, ESP_PWM1_SYNC1_IN, ESP_NOSIG) + +#define MCPWM1_SYNC1_GPIO32 \ + ESP32_PINMUX(32, ESP_PWM1_SYNC1_IN, ESP_NOSIG) + +#define MCPWM1_SYNC1_GPIO33 \ + ESP32_PINMUX(33, ESP_PWM1_SYNC1_IN, ESP_NOSIG) + +#define MCPWM1_SYNC1_GPIO34 \ + ESP32_PINMUX(34, ESP_PWM1_SYNC1_IN, ESP_NOSIG) + +#define MCPWM1_SYNC1_GPIO35 \ + ESP32_PINMUX(35, ESP_PWM1_SYNC1_IN, ESP_NOSIG) + +#define MCPWM1_SYNC1_GPIO36 \ + ESP32_PINMUX(36, ESP_PWM1_SYNC1_IN, ESP_NOSIG) + +#define MCPWM1_SYNC1_GPIO37 \ + ESP32_PINMUX(37, ESP_PWM1_SYNC1_IN, ESP_NOSIG) + +#define MCPWM1_SYNC1_GPIO38 \ + ESP32_PINMUX(38, ESP_PWM1_SYNC1_IN, ESP_NOSIG) + +#define MCPWM1_SYNC1_GPIO39 \ + ESP32_PINMUX(39, ESP_PWM1_SYNC1_IN, ESP_NOSIG) + +/* MCPWM1_SYNC2 */ +#define MCPWM1_SYNC2_GPIO0 \ + ESP32_PINMUX(0, ESP_PWM1_SYNC2_IN, ESP_NOSIG) + +#define MCPWM1_SYNC2_GPIO1 \ + ESP32_PINMUX(1, ESP_PWM1_SYNC2_IN, ESP_NOSIG) + +#define MCPWM1_SYNC2_GPIO2 \ + ESP32_PINMUX(2, ESP_PWM1_SYNC2_IN, ESP_NOSIG) + +#define MCPWM1_SYNC2_GPIO3 \ + ESP32_PINMUX(3, ESP_PWM1_SYNC2_IN, ESP_NOSIG) + +#define MCPWM1_SYNC2_GPIO4 \ + ESP32_PINMUX(4, ESP_PWM1_SYNC2_IN, ESP_NOSIG) + +#define MCPWM1_SYNC2_GPIO5 \ + ESP32_PINMUX(5, ESP_PWM1_SYNC2_IN, ESP_NOSIG) + +#define MCPWM1_SYNC2_GPIO6 \ + ESP32_PINMUX(6, ESP_PWM1_SYNC2_IN, ESP_NOSIG) + +#define MCPWM1_SYNC2_GPIO7 \ + ESP32_PINMUX(7, ESP_PWM1_SYNC2_IN, ESP_NOSIG) + +#define MCPWM1_SYNC2_GPIO8 \ + ESP32_PINMUX(8, ESP_PWM1_SYNC2_IN, ESP_NOSIG) + +#define MCPWM1_SYNC2_GPIO9 \ + ESP32_PINMUX(9, ESP_PWM1_SYNC2_IN, ESP_NOSIG) + +#define MCPWM1_SYNC2_GPIO10 \ + ESP32_PINMUX(10, ESP_PWM1_SYNC2_IN, ESP_NOSIG) + +#define MCPWM1_SYNC2_GPIO11 \ + ESP32_PINMUX(11, ESP_PWM1_SYNC2_IN, ESP_NOSIG) + +#define MCPWM1_SYNC2_GPIO12 \ + ESP32_PINMUX(12, ESP_PWM1_SYNC2_IN, ESP_NOSIG) + +#define MCPWM1_SYNC2_GPIO13 \ + ESP32_PINMUX(13, ESP_PWM1_SYNC2_IN, ESP_NOSIG) + +#define MCPWM1_SYNC2_GPIO14 \ + ESP32_PINMUX(14, ESP_PWM1_SYNC2_IN, ESP_NOSIG) + +#define MCPWM1_SYNC2_GPIO15 \ + ESP32_PINMUX(15, ESP_PWM1_SYNC2_IN, ESP_NOSIG) + +#define MCPWM1_SYNC2_GPIO16 \ + ESP32_PINMUX(16, ESP_PWM1_SYNC2_IN, ESP_NOSIG) + +#define MCPWM1_SYNC2_GPIO17 \ + ESP32_PINMUX(17, ESP_PWM1_SYNC2_IN, ESP_NOSIG) + +#define MCPWM1_SYNC2_GPIO18 \ + ESP32_PINMUX(18, ESP_PWM1_SYNC2_IN, ESP_NOSIG) + +#define MCPWM1_SYNC2_GPIO19 \ + ESP32_PINMUX(19, ESP_PWM1_SYNC2_IN, ESP_NOSIG) + +#define MCPWM1_SYNC2_GPIO20 \ + ESP32_PINMUX(20, ESP_PWM1_SYNC2_IN, ESP_NOSIG) + +#define MCPWM1_SYNC2_GPIO21 \ + ESP32_PINMUX(21, ESP_PWM1_SYNC2_IN, ESP_NOSIG) + +#define MCPWM1_SYNC2_GPIO22 \ + ESP32_PINMUX(22, ESP_PWM1_SYNC2_IN, ESP_NOSIG) + +#define MCPWM1_SYNC2_GPIO23 \ + ESP32_PINMUX(23, ESP_PWM1_SYNC2_IN, ESP_NOSIG) + +#define MCPWM1_SYNC2_GPIO25 \ + ESP32_PINMUX(25, ESP_PWM1_SYNC2_IN, ESP_NOSIG) + +#define MCPWM1_SYNC2_GPIO26 \ + ESP32_PINMUX(26, ESP_PWM1_SYNC2_IN, ESP_NOSIG) + +#define MCPWM1_SYNC2_GPIO27 \ + ESP32_PINMUX(27, ESP_PWM1_SYNC2_IN, ESP_NOSIG) + +#define MCPWM1_SYNC2_GPIO32 \ + ESP32_PINMUX(32, ESP_PWM1_SYNC2_IN, ESP_NOSIG) + +#define MCPWM1_SYNC2_GPIO33 \ + ESP32_PINMUX(33, ESP_PWM1_SYNC2_IN, ESP_NOSIG) + +#define MCPWM1_SYNC2_GPIO34 \ + ESP32_PINMUX(34, ESP_PWM1_SYNC2_IN, ESP_NOSIG) + +#define MCPWM1_SYNC2_GPIO35 \ + ESP32_PINMUX(35, ESP_PWM1_SYNC2_IN, ESP_NOSIG) + +#define MCPWM1_SYNC2_GPIO36 \ + ESP32_PINMUX(36, ESP_PWM1_SYNC2_IN, ESP_NOSIG) + +#define MCPWM1_SYNC2_GPIO37 \ + ESP32_PINMUX(37, ESP_PWM1_SYNC2_IN, ESP_NOSIG) + +#define MCPWM1_SYNC2_GPIO38 \ + ESP32_PINMUX(38, ESP_PWM1_SYNC2_IN, ESP_NOSIG) + +#define MCPWM1_SYNC2_GPIO39 \ + ESP32_PINMUX(39, ESP_PWM1_SYNC2_IN, ESP_NOSIG) + +/* PCNT0_CH0CTRL */ +#define PCNT0_CH0CTRL_GPIO0 \ + ESP32_PINMUX(0, ESP_PCNT_CTRL_CH0_IN0, ESP_NOSIG) + +#define PCNT0_CH0CTRL_GPIO1 \ + ESP32_PINMUX(1, ESP_PCNT_CTRL_CH0_IN0, ESP_NOSIG) + +#define PCNT0_CH0CTRL_GPIO2 \ + ESP32_PINMUX(2, ESP_PCNT_CTRL_CH0_IN0, ESP_NOSIG) + +#define PCNT0_CH0CTRL_GPIO3 \ + ESP32_PINMUX(3, ESP_PCNT_CTRL_CH0_IN0, ESP_NOSIG) + +#define PCNT0_CH0CTRL_GPIO4 \ + ESP32_PINMUX(4, ESP_PCNT_CTRL_CH0_IN0, ESP_NOSIG) + +#define PCNT0_CH0CTRL_GPIO5 \ + ESP32_PINMUX(5, ESP_PCNT_CTRL_CH0_IN0, ESP_NOSIG) + +#define PCNT0_CH0CTRL_GPIO6 \ + ESP32_PINMUX(6, ESP_PCNT_CTRL_CH0_IN0, ESP_NOSIG) + +#define PCNT0_CH0CTRL_GPIO7 \ + ESP32_PINMUX(7, ESP_PCNT_CTRL_CH0_IN0, ESP_NOSIG) + +#define PCNT0_CH0CTRL_GPIO8 \ + ESP32_PINMUX(8, ESP_PCNT_CTRL_CH0_IN0, ESP_NOSIG) + +#define PCNT0_CH0CTRL_GPIO9 \ + ESP32_PINMUX(9, ESP_PCNT_CTRL_CH0_IN0, ESP_NOSIG) + +#define PCNT0_CH0CTRL_GPIO10 \ + ESP32_PINMUX(10, ESP_PCNT_CTRL_CH0_IN0, ESP_NOSIG) + +#define PCNT0_CH0CTRL_GPIO11 \ + ESP32_PINMUX(11, ESP_PCNT_CTRL_CH0_IN0, ESP_NOSIG) + +#define PCNT0_CH0CTRL_GPIO12 \ + ESP32_PINMUX(12, ESP_PCNT_CTRL_CH0_IN0, ESP_NOSIG) + +#define PCNT0_CH0CTRL_GPIO13 \ + ESP32_PINMUX(13, ESP_PCNT_CTRL_CH0_IN0, ESP_NOSIG) + +#define PCNT0_CH0CTRL_GPIO14 \ + ESP32_PINMUX(14, ESP_PCNT_CTRL_CH0_IN0, ESP_NOSIG) + +#define PCNT0_CH0CTRL_GPIO15 \ + ESP32_PINMUX(15, ESP_PCNT_CTRL_CH0_IN0, ESP_NOSIG) + +#define PCNT0_CH0CTRL_GPIO16 \ + ESP32_PINMUX(16, ESP_PCNT_CTRL_CH0_IN0, ESP_NOSIG) + +#define PCNT0_CH0CTRL_GPIO17 \ + ESP32_PINMUX(17, ESP_PCNT_CTRL_CH0_IN0, ESP_NOSIG) + +#define PCNT0_CH0CTRL_GPIO18 \ + ESP32_PINMUX(18, ESP_PCNT_CTRL_CH0_IN0, ESP_NOSIG) + +#define PCNT0_CH0CTRL_GPIO19 \ + ESP32_PINMUX(19, ESP_PCNT_CTRL_CH0_IN0, ESP_NOSIG) + +#define PCNT0_CH0CTRL_GPIO20 \ + ESP32_PINMUX(20, ESP_PCNT_CTRL_CH0_IN0, ESP_NOSIG) + +#define PCNT0_CH0CTRL_GPIO21 \ + ESP32_PINMUX(21, ESP_PCNT_CTRL_CH0_IN0, ESP_NOSIG) + +#define PCNT0_CH0CTRL_GPIO22 \ + ESP32_PINMUX(22, ESP_PCNT_CTRL_CH0_IN0, ESP_NOSIG) + +#define PCNT0_CH0CTRL_GPIO23 \ + ESP32_PINMUX(23, ESP_PCNT_CTRL_CH0_IN0, ESP_NOSIG) + +#define PCNT0_CH0CTRL_GPIO25 \ + ESP32_PINMUX(25, ESP_PCNT_CTRL_CH0_IN0, ESP_NOSIG) + +#define PCNT0_CH0CTRL_GPIO26 \ + ESP32_PINMUX(26, ESP_PCNT_CTRL_CH0_IN0, ESP_NOSIG) + +#define PCNT0_CH0CTRL_GPIO27 \ + ESP32_PINMUX(27, ESP_PCNT_CTRL_CH0_IN0, ESP_NOSIG) + +#define PCNT0_CH0CTRL_GPIO32 \ + ESP32_PINMUX(32, ESP_PCNT_CTRL_CH0_IN0, ESP_NOSIG) + +#define PCNT0_CH0CTRL_GPIO33 \ + ESP32_PINMUX(33, ESP_PCNT_CTRL_CH0_IN0, ESP_NOSIG) + +#define PCNT0_CH0CTRL_GPIO34 \ + ESP32_PINMUX(34, ESP_PCNT_CTRL_CH0_IN0, ESP_NOSIG) + +#define PCNT0_CH0CTRL_GPIO35 \ + ESP32_PINMUX(35, ESP_PCNT_CTRL_CH0_IN0, ESP_NOSIG) + +#define PCNT0_CH0CTRL_GPIO36 \ + ESP32_PINMUX(36, ESP_PCNT_CTRL_CH0_IN0, ESP_NOSIG) + +#define PCNT0_CH0CTRL_GPIO37 \ + ESP32_PINMUX(37, ESP_PCNT_CTRL_CH0_IN0, ESP_NOSIG) + +#define PCNT0_CH0CTRL_GPIO38 \ + ESP32_PINMUX(38, ESP_PCNT_CTRL_CH0_IN0, ESP_NOSIG) + +#define PCNT0_CH0CTRL_GPIO39 \ + ESP32_PINMUX(39, ESP_PCNT_CTRL_CH0_IN0, ESP_NOSIG) + +/* PCNT0_CH0SIG */ +#define PCNT0_CH0SIG_GPIO0 \ + ESP32_PINMUX(0, ESP_PCNT_SIG_CH0_IN0, ESP_NOSIG) + +#define PCNT0_CH0SIG_GPIO1 \ + ESP32_PINMUX(1, ESP_PCNT_SIG_CH0_IN0, ESP_NOSIG) + +#define PCNT0_CH0SIG_GPIO2 \ + ESP32_PINMUX(2, ESP_PCNT_SIG_CH0_IN0, ESP_NOSIG) + +#define PCNT0_CH0SIG_GPIO3 \ + ESP32_PINMUX(3, ESP_PCNT_SIG_CH0_IN0, ESP_NOSIG) + +#define PCNT0_CH0SIG_GPIO4 \ + ESP32_PINMUX(4, ESP_PCNT_SIG_CH0_IN0, ESP_NOSIG) + +#define PCNT0_CH0SIG_GPIO5 \ + ESP32_PINMUX(5, ESP_PCNT_SIG_CH0_IN0, ESP_NOSIG) + +#define PCNT0_CH0SIG_GPIO6 \ + ESP32_PINMUX(6, ESP_PCNT_SIG_CH0_IN0, ESP_NOSIG) + +#define PCNT0_CH0SIG_GPIO7 \ + ESP32_PINMUX(7, ESP_PCNT_SIG_CH0_IN0, ESP_NOSIG) + +#define PCNT0_CH0SIG_GPIO8 \ + ESP32_PINMUX(8, ESP_PCNT_SIG_CH0_IN0, ESP_NOSIG) + +#define PCNT0_CH0SIG_GPIO9 \ + ESP32_PINMUX(9, ESP_PCNT_SIG_CH0_IN0, ESP_NOSIG) + +#define PCNT0_CH0SIG_GPIO10 \ + ESP32_PINMUX(10, ESP_PCNT_SIG_CH0_IN0, ESP_NOSIG) + +#define PCNT0_CH0SIG_GPIO11 \ + ESP32_PINMUX(11, ESP_PCNT_SIG_CH0_IN0, ESP_NOSIG) + +#define PCNT0_CH0SIG_GPIO12 \ + ESP32_PINMUX(12, ESP_PCNT_SIG_CH0_IN0, ESP_NOSIG) + +#define PCNT0_CH0SIG_GPIO13 \ + ESP32_PINMUX(13, ESP_PCNT_SIG_CH0_IN0, ESP_NOSIG) + +#define PCNT0_CH0SIG_GPIO14 \ + ESP32_PINMUX(14, ESP_PCNT_SIG_CH0_IN0, ESP_NOSIG) + +#define PCNT0_CH0SIG_GPIO15 \ + ESP32_PINMUX(15, ESP_PCNT_SIG_CH0_IN0, ESP_NOSIG) + +#define PCNT0_CH0SIG_GPIO16 \ + ESP32_PINMUX(16, ESP_PCNT_SIG_CH0_IN0, ESP_NOSIG) + +#define PCNT0_CH0SIG_GPIO17 \ + ESP32_PINMUX(17, ESP_PCNT_SIG_CH0_IN0, ESP_NOSIG) + +#define PCNT0_CH0SIG_GPIO18 \ + ESP32_PINMUX(18, ESP_PCNT_SIG_CH0_IN0, ESP_NOSIG) + +#define PCNT0_CH0SIG_GPIO19 \ + ESP32_PINMUX(19, ESP_PCNT_SIG_CH0_IN0, ESP_NOSIG) + +#define PCNT0_CH0SIG_GPIO20 \ + ESP32_PINMUX(20, ESP_PCNT_SIG_CH0_IN0, ESP_NOSIG) + +#define PCNT0_CH0SIG_GPIO21 \ + ESP32_PINMUX(21, ESP_PCNT_SIG_CH0_IN0, ESP_NOSIG) + +#define PCNT0_CH0SIG_GPIO22 \ + ESP32_PINMUX(22, ESP_PCNT_SIG_CH0_IN0, ESP_NOSIG) + +#define PCNT0_CH0SIG_GPIO23 \ + ESP32_PINMUX(23, ESP_PCNT_SIG_CH0_IN0, ESP_NOSIG) + +#define PCNT0_CH0SIG_GPIO25 \ + ESP32_PINMUX(25, ESP_PCNT_SIG_CH0_IN0, ESP_NOSIG) + +#define PCNT0_CH0SIG_GPIO26 \ + ESP32_PINMUX(26, ESP_PCNT_SIG_CH0_IN0, ESP_NOSIG) + +#define PCNT0_CH0SIG_GPIO27 \ + ESP32_PINMUX(27, ESP_PCNT_SIG_CH0_IN0, ESP_NOSIG) + +#define PCNT0_CH0SIG_GPIO32 \ + ESP32_PINMUX(32, ESP_PCNT_SIG_CH0_IN0, ESP_NOSIG) + +#define PCNT0_CH0SIG_GPIO33 \ + ESP32_PINMUX(33, ESP_PCNT_SIG_CH0_IN0, ESP_NOSIG) + +#define PCNT0_CH0SIG_GPIO34 \ + ESP32_PINMUX(34, ESP_PCNT_SIG_CH0_IN0, ESP_NOSIG) + +#define PCNT0_CH0SIG_GPIO35 \ + ESP32_PINMUX(35, ESP_PCNT_SIG_CH0_IN0, ESP_NOSIG) + +#define PCNT0_CH0SIG_GPIO36 \ + ESP32_PINMUX(36, ESP_PCNT_SIG_CH0_IN0, ESP_NOSIG) + +#define PCNT0_CH0SIG_GPIO37 \ + ESP32_PINMUX(37, ESP_PCNT_SIG_CH0_IN0, ESP_NOSIG) + +#define PCNT0_CH0SIG_GPIO38 \ + ESP32_PINMUX(38, ESP_PCNT_SIG_CH0_IN0, ESP_NOSIG) + +#define PCNT0_CH0SIG_GPIO39 \ + ESP32_PINMUX(39, ESP_PCNT_SIG_CH0_IN0, ESP_NOSIG) + +/* PCNT0_CH1CTRL */ +#define PCNT0_CH1CTRL_GPIO0 \ + ESP32_PINMUX(0, ESP_PCNT_CTRL_CH1_IN0, ESP_NOSIG) + +#define PCNT0_CH1CTRL_GPIO1 \ + ESP32_PINMUX(1, ESP_PCNT_CTRL_CH1_IN0, ESP_NOSIG) + +#define PCNT0_CH1CTRL_GPIO2 \ + ESP32_PINMUX(2, ESP_PCNT_CTRL_CH1_IN0, ESP_NOSIG) + +#define PCNT0_CH1CTRL_GPIO3 \ + ESP32_PINMUX(3, ESP_PCNT_CTRL_CH1_IN0, ESP_NOSIG) + +#define PCNT0_CH1CTRL_GPIO4 \ + ESP32_PINMUX(4, ESP_PCNT_CTRL_CH1_IN0, ESP_NOSIG) + +#define PCNT0_CH1CTRL_GPIO5 \ + ESP32_PINMUX(5, ESP_PCNT_CTRL_CH1_IN0, ESP_NOSIG) + +#define PCNT0_CH1CTRL_GPIO6 \ + ESP32_PINMUX(6, ESP_PCNT_CTRL_CH1_IN0, ESP_NOSIG) + +#define PCNT0_CH1CTRL_GPIO7 \ + ESP32_PINMUX(7, ESP_PCNT_CTRL_CH1_IN0, ESP_NOSIG) + +#define PCNT0_CH1CTRL_GPIO8 \ + ESP32_PINMUX(8, ESP_PCNT_CTRL_CH1_IN0, ESP_NOSIG) + +#define PCNT0_CH1CTRL_GPIO9 \ + ESP32_PINMUX(9, ESP_PCNT_CTRL_CH1_IN0, ESP_NOSIG) + +#define PCNT0_CH1CTRL_GPIO10 \ + ESP32_PINMUX(10, ESP_PCNT_CTRL_CH1_IN0, ESP_NOSIG) + +#define PCNT0_CH1CTRL_GPIO11 \ + ESP32_PINMUX(11, ESP_PCNT_CTRL_CH1_IN0, ESP_NOSIG) + +#define PCNT0_CH1CTRL_GPIO12 \ + ESP32_PINMUX(12, ESP_PCNT_CTRL_CH1_IN0, ESP_NOSIG) + +#define PCNT0_CH1CTRL_GPIO13 \ + ESP32_PINMUX(13, ESP_PCNT_CTRL_CH1_IN0, ESP_NOSIG) + +#define PCNT0_CH1CTRL_GPIO14 \ + ESP32_PINMUX(14, ESP_PCNT_CTRL_CH1_IN0, ESP_NOSIG) + +#define PCNT0_CH1CTRL_GPIO15 \ + ESP32_PINMUX(15, ESP_PCNT_CTRL_CH1_IN0, ESP_NOSIG) + +#define PCNT0_CH1CTRL_GPIO16 \ + ESP32_PINMUX(16, ESP_PCNT_CTRL_CH1_IN0, ESP_NOSIG) + +#define PCNT0_CH1CTRL_GPIO17 \ + ESP32_PINMUX(17, ESP_PCNT_CTRL_CH1_IN0, ESP_NOSIG) + +#define PCNT0_CH1CTRL_GPIO18 \ + ESP32_PINMUX(18, ESP_PCNT_CTRL_CH1_IN0, ESP_NOSIG) + +#define PCNT0_CH1CTRL_GPIO19 \ + ESP32_PINMUX(19, ESP_PCNT_CTRL_CH1_IN0, ESP_NOSIG) + +#define PCNT0_CH1CTRL_GPIO20 \ + ESP32_PINMUX(20, ESP_PCNT_CTRL_CH1_IN0, ESP_NOSIG) + +#define PCNT0_CH1CTRL_GPIO21 \ + ESP32_PINMUX(21, ESP_PCNT_CTRL_CH1_IN0, ESP_NOSIG) + +#define PCNT0_CH1CTRL_GPIO22 \ + ESP32_PINMUX(22, ESP_PCNT_CTRL_CH1_IN0, ESP_NOSIG) + +#define PCNT0_CH1CTRL_GPIO23 \ + ESP32_PINMUX(23, ESP_PCNT_CTRL_CH1_IN0, ESP_NOSIG) + +#define PCNT0_CH1CTRL_GPIO25 \ + ESP32_PINMUX(25, ESP_PCNT_CTRL_CH1_IN0, ESP_NOSIG) + +#define PCNT0_CH1CTRL_GPIO26 \ + ESP32_PINMUX(26, ESP_PCNT_CTRL_CH1_IN0, ESP_NOSIG) + +#define PCNT0_CH1CTRL_GPIO27 \ + ESP32_PINMUX(27, ESP_PCNT_CTRL_CH1_IN0, ESP_NOSIG) + +#define PCNT0_CH1CTRL_GPIO32 \ + ESP32_PINMUX(32, ESP_PCNT_CTRL_CH1_IN0, ESP_NOSIG) + +#define PCNT0_CH1CTRL_GPIO33 \ + ESP32_PINMUX(33, ESP_PCNT_CTRL_CH1_IN0, ESP_NOSIG) + +#define PCNT0_CH1CTRL_GPIO34 \ + ESP32_PINMUX(34, ESP_PCNT_CTRL_CH1_IN0, ESP_NOSIG) + +#define PCNT0_CH1CTRL_GPIO35 \ + ESP32_PINMUX(35, ESP_PCNT_CTRL_CH1_IN0, ESP_NOSIG) + +#define PCNT0_CH1CTRL_GPIO36 \ + ESP32_PINMUX(36, ESP_PCNT_CTRL_CH1_IN0, ESP_NOSIG) + +#define PCNT0_CH1CTRL_GPIO37 \ + ESP32_PINMUX(37, ESP_PCNT_CTRL_CH1_IN0, ESP_NOSIG) + +#define PCNT0_CH1CTRL_GPIO38 \ + ESP32_PINMUX(38, ESP_PCNT_CTRL_CH1_IN0, ESP_NOSIG) + +#define PCNT0_CH1CTRL_GPIO39 \ + ESP32_PINMUX(39, ESP_PCNT_CTRL_CH1_IN0, ESP_NOSIG) + +/* PCNT0_CH1SIG */ +#define PCNT0_CH1SIG_GPIO0 \ + ESP32_PINMUX(0, ESP_PCNT_SIG_CH1_IN0, ESP_NOSIG) + +#define PCNT0_CH1SIG_GPIO1 \ + ESP32_PINMUX(1, ESP_PCNT_SIG_CH1_IN0, ESP_NOSIG) + +#define PCNT0_CH1SIG_GPIO2 \ + ESP32_PINMUX(2, ESP_PCNT_SIG_CH1_IN0, ESP_NOSIG) + +#define PCNT0_CH1SIG_GPIO3 \ + ESP32_PINMUX(3, ESP_PCNT_SIG_CH1_IN0, ESP_NOSIG) + +#define PCNT0_CH1SIG_GPIO4 \ + ESP32_PINMUX(4, ESP_PCNT_SIG_CH1_IN0, ESP_NOSIG) + +#define PCNT0_CH1SIG_GPIO5 \ + ESP32_PINMUX(5, ESP_PCNT_SIG_CH1_IN0, ESP_NOSIG) + +#define PCNT0_CH1SIG_GPIO6 \ + ESP32_PINMUX(6, ESP_PCNT_SIG_CH1_IN0, ESP_NOSIG) + +#define PCNT0_CH1SIG_GPIO7 \ + ESP32_PINMUX(7, ESP_PCNT_SIG_CH1_IN0, ESP_NOSIG) + +#define PCNT0_CH1SIG_GPIO8 \ + ESP32_PINMUX(8, ESP_PCNT_SIG_CH1_IN0, ESP_NOSIG) + +#define PCNT0_CH1SIG_GPIO9 \ + ESP32_PINMUX(9, ESP_PCNT_SIG_CH1_IN0, ESP_NOSIG) + +#define PCNT0_CH1SIG_GPIO10 \ + ESP32_PINMUX(10, ESP_PCNT_SIG_CH1_IN0, ESP_NOSIG) + +#define PCNT0_CH1SIG_GPIO11 \ + ESP32_PINMUX(11, ESP_PCNT_SIG_CH1_IN0, ESP_NOSIG) + +#define PCNT0_CH1SIG_GPIO12 \ + ESP32_PINMUX(12, ESP_PCNT_SIG_CH1_IN0, ESP_NOSIG) + +#define PCNT0_CH1SIG_GPIO13 \ + ESP32_PINMUX(13, ESP_PCNT_SIG_CH1_IN0, ESP_NOSIG) + +#define PCNT0_CH1SIG_GPIO14 \ + ESP32_PINMUX(14, ESP_PCNT_SIG_CH1_IN0, ESP_NOSIG) + +#define PCNT0_CH1SIG_GPIO15 \ + ESP32_PINMUX(15, ESP_PCNT_SIG_CH1_IN0, ESP_NOSIG) + +#define PCNT0_CH1SIG_GPIO16 \ + ESP32_PINMUX(16, ESP_PCNT_SIG_CH1_IN0, ESP_NOSIG) + +#define PCNT0_CH1SIG_GPIO17 \ + ESP32_PINMUX(17, ESP_PCNT_SIG_CH1_IN0, ESP_NOSIG) + +#define PCNT0_CH1SIG_GPIO18 \ + ESP32_PINMUX(18, ESP_PCNT_SIG_CH1_IN0, ESP_NOSIG) + +#define PCNT0_CH1SIG_GPIO19 \ + ESP32_PINMUX(19, ESP_PCNT_SIG_CH1_IN0, ESP_NOSIG) + +#define PCNT0_CH1SIG_GPIO20 \ + ESP32_PINMUX(20, ESP_PCNT_SIG_CH1_IN0, ESP_NOSIG) + +#define PCNT0_CH1SIG_GPIO21 \ + ESP32_PINMUX(21, ESP_PCNT_SIG_CH1_IN0, ESP_NOSIG) + +#define PCNT0_CH1SIG_GPIO22 \ + ESP32_PINMUX(22, ESP_PCNT_SIG_CH1_IN0, ESP_NOSIG) + +#define PCNT0_CH1SIG_GPIO23 \ + ESP32_PINMUX(23, ESP_PCNT_SIG_CH1_IN0, ESP_NOSIG) + +#define PCNT0_CH1SIG_GPIO25 \ + ESP32_PINMUX(25, ESP_PCNT_SIG_CH1_IN0, ESP_NOSIG) + +#define PCNT0_CH1SIG_GPIO26 \ + ESP32_PINMUX(26, ESP_PCNT_SIG_CH1_IN0, ESP_NOSIG) + +#define PCNT0_CH1SIG_GPIO27 \ + ESP32_PINMUX(27, ESP_PCNT_SIG_CH1_IN0, ESP_NOSIG) + +#define PCNT0_CH1SIG_GPIO32 \ + ESP32_PINMUX(32, ESP_PCNT_SIG_CH1_IN0, ESP_NOSIG) + +#define PCNT0_CH1SIG_GPIO33 \ + ESP32_PINMUX(33, ESP_PCNT_SIG_CH1_IN0, ESP_NOSIG) + +#define PCNT0_CH1SIG_GPIO34 \ + ESP32_PINMUX(34, ESP_PCNT_SIG_CH1_IN0, ESP_NOSIG) + +#define PCNT0_CH1SIG_GPIO35 \ + ESP32_PINMUX(35, ESP_PCNT_SIG_CH1_IN0, ESP_NOSIG) + +#define PCNT0_CH1SIG_GPIO36 \ + ESP32_PINMUX(36, ESP_PCNT_SIG_CH1_IN0, ESP_NOSIG) + +#define PCNT0_CH1SIG_GPIO37 \ + ESP32_PINMUX(37, ESP_PCNT_SIG_CH1_IN0, ESP_NOSIG) + +#define PCNT0_CH1SIG_GPIO38 \ + ESP32_PINMUX(38, ESP_PCNT_SIG_CH1_IN0, ESP_NOSIG) + +#define PCNT0_CH1SIG_GPIO39 \ + ESP32_PINMUX(39, ESP_PCNT_SIG_CH1_IN0, ESP_NOSIG) + +/* PCNT1_CH0CTRL */ +#define PCNT1_CH0CTRL_GPIO0 \ + ESP32_PINMUX(0, ESP_PCNT_CTRL_CH0_IN1, ESP_NOSIG) + +#define PCNT1_CH0CTRL_GPIO1 \ + ESP32_PINMUX(1, ESP_PCNT_CTRL_CH0_IN1, ESP_NOSIG) + +#define PCNT1_CH0CTRL_GPIO2 \ + ESP32_PINMUX(2, ESP_PCNT_CTRL_CH0_IN1, ESP_NOSIG) + +#define PCNT1_CH0CTRL_GPIO3 \ + ESP32_PINMUX(3, ESP_PCNT_CTRL_CH0_IN1, ESP_NOSIG) + +#define PCNT1_CH0CTRL_GPIO4 \ + ESP32_PINMUX(4, ESP_PCNT_CTRL_CH0_IN1, ESP_NOSIG) + +#define PCNT1_CH0CTRL_GPIO5 \ + ESP32_PINMUX(5, ESP_PCNT_CTRL_CH0_IN1, ESP_NOSIG) + +#define PCNT1_CH0CTRL_GPIO6 \ + ESP32_PINMUX(6, ESP_PCNT_CTRL_CH0_IN1, ESP_NOSIG) + +#define PCNT1_CH0CTRL_GPIO7 \ + ESP32_PINMUX(7, ESP_PCNT_CTRL_CH0_IN1, ESP_NOSIG) + +#define PCNT1_CH0CTRL_GPIO8 \ + ESP32_PINMUX(8, ESP_PCNT_CTRL_CH0_IN1, ESP_NOSIG) + +#define PCNT1_CH0CTRL_GPIO9 \ + ESP32_PINMUX(9, ESP_PCNT_CTRL_CH0_IN1, ESP_NOSIG) + +#define PCNT1_CH0CTRL_GPIO10 \ + ESP32_PINMUX(10, ESP_PCNT_CTRL_CH0_IN1, ESP_NOSIG) + +#define PCNT1_CH0CTRL_GPIO11 \ + ESP32_PINMUX(11, ESP_PCNT_CTRL_CH0_IN1, ESP_NOSIG) + +#define PCNT1_CH0CTRL_GPIO12 \ + ESP32_PINMUX(12, ESP_PCNT_CTRL_CH0_IN1, ESP_NOSIG) + +#define PCNT1_CH0CTRL_GPIO13 \ + ESP32_PINMUX(13, ESP_PCNT_CTRL_CH0_IN1, ESP_NOSIG) + +#define PCNT1_CH0CTRL_GPIO14 \ + ESP32_PINMUX(14, ESP_PCNT_CTRL_CH0_IN1, ESP_NOSIG) + +#define PCNT1_CH0CTRL_GPIO15 \ + ESP32_PINMUX(15, ESP_PCNT_CTRL_CH0_IN1, ESP_NOSIG) + +#define PCNT1_CH0CTRL_GPIO16 \ + ESP32_PINMUX(16, ESP_PCNT_CTRL_CH0_IN1, ESP_NOSIG) + +#define PCNT1_CH0CTRL_GPIO17 \ + ESP32_PINMUX(17, ESP_PCNT_CTRL_CH0_IN1, ESP_NOSIG) + +#define PCNT1_CH0CTRL_GPIO18 \ + ESP32_PINMUX(18, ESP_PCNT_CTRL_CH0_IN1, ESP_NOSIG) + +#define PCNT1_CH0CTRL_GPIO19 \ + ESP32_PINMUX(19, ESP_PCNT_CTRL_CH0_IN1, ESP_NOSIG) + +#define PCNT1_CH0CTRL_GPIO20 \ + ESP32_PINMUX(20, ESP_PCNT_CTRL_CH0_IN1, ESP_NOSIG) + +#define PCNT1_CH0CTRL_GPIO21 \ + ESP32_PINMUX(21, ESP_PCNT_CTRL_CH0_IN1, ESP_NOSIG) + +#define PCNT1_CH0CTRL_GPIO22 \ + ESP32_PINMUX(22, ESP_PCNT_CTRL_CH0_IN1, ESP_NOSIG) + +#define PCNT1_CH0CTRL_GPIO23 \ + ESP32_PINMUX(23, ESP_PCNT_CTRL_CH0_IN1, ESP_NOSIG) + +#define PCNT1_CH0CTRL_GPIO25 \ + ESP32_PINMUX(25, ESP_PCNT_CTRL_CH0_IN1, ESP_NOSIG) + +#define PCNT1_CH0CTRL_GPIO26 \ + ESP32_PINMUX(26, ESP_PCNT_CTRL_CH0_IN1, ESP_NOSIG) + +#define PCNT1_CH0CTRL_GPIO27 \ + ESP32_PINMUX(27, ESP_PCNT_CTRL_CH0_IN1, ESP_NOSIG) + +#define PCNT1_CH0CTRL_GPIO32 \ + ESP32_PINMUX(32, ESP_PCNT_CTRL_CH0_IN1, ESP_NOSIG) + +#define PCNT1_CH0CTRL_GPIO33 \ + ESP32_PINMUX(33, ESP_PCNT_CTRL_CH0_IN1, ESP_NOSIG) + +#define PCNT1_CH0CTRL_GPIO34 \ + ESP32_PINMUX(34, ESP_PCNT_CTRL_CH0_IN1, ESP_NOSIG) + +#define PCNT1_CH0CTRL_GPIO35 \ + ESP32_PINMUX(35, ESP_PCNT_CTRL_CH0_IN1, ESP_NOSIG) + +#define PCNT1_CH0CTRL_GPIO36 \ + ESP32_PINMUX(36, ESP_PCNT_CTRL_CH0_IN1, ESP_NOSIG) + +#define PCNT1_CH0CTRL_GPIO37 \ + ESP32_PINMUX(37, ESP_PCNT_CTRL_CH0_IN1, ESP_NOSIG) + +#define PCNT1_CH0CTRL_GPIO38 \ + ESP32_PINMUX(38, ESP_PCNT_CTRL_CH0_IN1, ESP_NOSIG) + +#define PCNT1_CH0CTRL_GPIO39 \ + ESP32_PINMUX(39, ESP_PCNT_CTRL_CH0_IN1, ESP_NOSIG) + +/* PCNT1_CH0SIG */ +#define PCNT1_CH0SIG_GPIO0 \ + ESP32_PINMUX(0, ESP_PCNT_SIG_CH0_IN1, ESP_NOSIG) + +#define PCNT1_CH0SIG_GPIO1 \ + ESP32_PINMUX(1, ESP_PCNT_SIG_CH0_IN1, ESP_NOSIG) + +#define PCNT1_CH0SIG_GPIO2 \ + ESP32_PINMUX(2, ESP_PCNT_SIG_CH0_IN1, ESP_NOSIG) + +#define PCNT1_CH0SIG_GPIO3 \ + ESP32_PINMUX(3, ESP_PCNT_SIG_CH0_IN1, ESP_NOSIG) + +#define PCNT1_CH0SIG_GPIO4 \ + ESP32_PINMUX(4, ESP_PCNT_SIG_CH0_IN1, ESP_NOSIG) + +#define PCNT1_CH0SIG_GPIO5 \ + ESP32_PINMUX(5, ESP_PCNT_SIG_CH0_IN1, ESP_NOSIG) + +#define PCNT1_CH0SIG_GPIO6 \ + ESP32_PINMUX(6, ESP_PCNT_SIG_CH0_IN1, ESP_NOSIG) + +#define PCNT1_CH0SIG_GPIO7 \ + ESP32_PINMUX(7, ESP_PCNT_SIG_CH0_IN1, ESP_NOSIG) + +#define PCNT1_CH0SIG_GPIO8 \ + ESP32_PINMUX(8, ESP_PCNT_SIG_CH0_IN1, ESP_NOSIG) + +#define PCNT1_CH0SIG_GPIO9 \ + ESP32_PINMUX(9, ESP_PCNT_SIG_CH0_IN1, ESP_NOSIG) + +#define PCNT1_CH0SIG_GPIO10 \ + ESP32_PINMUX(10, ESP_PCNT_SIG_CH0_IN1, ESP_NOSIG) + +#define PCNT1_CH0SIG_GPIO11 \ + ESP32_PINMUX(11, ESP_PCNT_SIG_CH0_IN1, ESP_NOSIG) + +#define PCNT1_CH0SIG_GPIO12 \ + ESP32_PINMUX(12, ESP_PCNT_SIG_CH0_IN1, ESP_NOSIG) + +#define PCNT1_CH0SIG_GPIO13 \ + ESP32_PINMUX(13, ESP_PCNT_SIG_CH0_IN1, ESP_NOSIG) + +#define PCNT1_CH0SIG_GPIO14 \ + ESP32_PINMUX(14, ESP_PCNT_SIG_CH0_IN1, ESP_NOSIG) + +#define PCNT1_CH0SIG_GPIO15 \ + ESP32_PINMUX(15, ESP_PCNT_SIG_CH0_IN1, ESP_NOSIG) + +#define PCNT1_CH0SIG_GPIO16 \ + ESP32_PINMUX(16, ESP_PCNT_SIG_CH0_IN1, ESP_NOSIG) + +#define PCNT1_CH0SIG_GPIO17 \ + ESP32_PINMUX(17, ESP_PCNT_SIG_CH0_IN1, ESP_NOSIG) + +#define PCNT1_CH0SIG_GPIO18 \ + ESP32_PINMUX(18, ESP_PCNT_SIG_CH0_IN1, ESP_NOSIG) + +#define PCNT1_CH0SIG_GPIO19 \ + ESP32_PINMUX(19, ESP_PCNT_SIG_CH0_IN1, ESP_NOSIG) + +#define PCNT1_CH0SIG_GPIO20 \ + ESP32_PINMUX(20, ESP_PCNT_SIG_CH0_IN1, ESP_NOSIG) + +#define PCNT1_CH0SIG_GPIO21 \ + ESP32_PINMUX(21, ESP_PCNT_SIG_CH0_IN1, ESP_NOSIG) + +#define PCNT1_CH0SIG_GPIO22 \ + ESP32_PINMUX(22, ESP_PCNT_SIG_CH0_IN1, ESP_NOSIG) + +#define PCNT1_CH0SIG_GPIO23 \ + ESP32_PINMUX(23, ESP_PCNT_SIG_CH0_IN1, ESP_NOSIG) + +#define PCNT1_CH0SIG_GPIO25 \ + ESP32_PINMUX(25, ESP_PCNT_SIG_CH0_IN1, ESP_NOSIG) + +#define PCNT1_CH0SIG_GPIO26 \ + ESP32_PINMUX(26, ESP_PCNT_SIG_CH0_IN1, ESP_NOSIG) + +#define PCNT1_CH0SIG_GPIO27 \ + ESP32_PINMUX(27, ESP_PCNT_SIG_CH0_IN1, ESP_NOSIG) + +#define PCNT1_CH0SIG_GPIO32 \ + ESP32_PINMUX(32, ESP_PCNT_SIG_CH0_IN1, ESP_NOSIG) + +#define PCNT1_CH0SIG_GPIO33 \ + ESP32_PINMUX(33, ESP_PCNT_SIG_CH0_IN1, ESP_NOSIG) + +#define PCNT1_CH0SIG_GPIO34 \ + ESP32_PINMUX(34, ESP_PCNT_SIG_CH0_IN1, ESP_NOSIG) + +#define PCNT1_CH0SIG_GPIO35 \ + ESP32_PINMUX(35, ESP_PCNT_SIG_CH0_IN1, ESP_NOSIG) + +#define PCNT1_CH0SIG_GPIO36 \ + ESP32_PINMUX(36, ESP_PCNT_SIG_CH0_IN1, ESP_NOSIG) + +#define PCNT1_CH0SIG_GPIO37 \ + ESP32_PINMUX(37, ESP_PCNT_SIG_CH0_IN1, ESP_NOSIG) + +#define PCNT1_CH0SIG_GPIO38 \ + ESP32_PINMUX(38, ESP_PCNT_SIG_CH0_IN1, ESP_NOSIG) + +#define PCNT1_CH0SIG_GPIO39 \ + ESP32_PINMUX(39, ESP_PCNT_SIG_CH0_IN1, ESP_NOSIG) + +/* PCNT1_CH1CTRL */ +#define PCNT1_CH1CTRL_GPIO0 \ + ESP32_PINMUX(0, ESP_PCNT_CTRL_CH1_IN1, ESP_NOSIG) + +#define PCNT1_CH1CTRL_GPIO1 \ + ESP32_PINMUX(1, ESP_PCNT_CTRL_CH1_IN1, ESP_NOSIG) + +#define PCNT1_CH1CTRL_GPIO2 \ + ESP32_PINMUX(2, ESP_PCNT_CTRL_CH1_IN1, ESP_NOSIG) + +#define PCNT1_CH1CTRL_GPIO3 \ + ESP32_PINMUX(3, ESP_PCNT_CTRL_CH1_IN1, ESP_NOSIG) + +#define PCNT1_CH1CTRL_GPIO4 \ + ESP32_PINMUX(4, ESP_PCNT_CTRL_CH1_IN1, ESP_NOSIG) + +#define PCNT1_CH1CTRL_GPIO5 \ + ESP32_PINMUX(5, ESP_PCNT_CTRL_CH1_IN1, ESP_NOSIG) + +#define PCNT1_CH1CTRL_GPIO6 \ + ESP32_PINMUX(6, ESP_PCNT_CTRL_CH1_IN1, ESP_NOSIG) + +#define PCNT1_CH1CTRL_GPIO7 \ + ESP32_PINMUX(7, ESP_PCNT_CTRL_CH1_IN1, ESP_NOSIG) + +#define PCNT1_CH1CTRL_GPIO8 \ + ESP32_PINMUX(8, ESP_PCNT_CTRL_CH1_IN1, ESP_NOSIG) + +#define PCNT1_CH1CTRL_GPIO9 \ + ESP32_PINMUX(9, ESP_PCNT_CTRL_CH1_IN1, ESP_NOSIG) + +#define PCNT1_CH1CTRL_GPIO10 \ + ESP32_PINMUX(10, ESP_PCNT_CTRL_CH1_IN1, ESP_NOSIG) + +#define PCNT1_CH1CTRL_GPIO11 \ + ESP32_PINMUX(11, ESP_PCNT_CTRL_CH1_IN1, ESP_NOSIG) + +#define PCNT1_CH1CTRL_GPIO12 \ + ESP32_PINMUX(12, ESP_PCNT_CTRL_CH1_IN1, ESP_NOSIG) + +#define PCNT1_CH1CTRL_GPIO13 \ + ESP32_PINMUX(13, ESP_PCNT_CTRL_CH1_IN1, ESP_NOSIG) + +#define PCNT1_CH1CTRL_GPIO14 \ + ESP32_PINMUX(14, ESP_PCNT_CTRL_CH1_IN1, ESP_NOSIG) + +#define PCNT1_CH1CTRL_GPIO15 \ + ESP32_PINMUX(15, ESP_PCNT_CTRL_CH1_IN1, ESP_NOSIG) + +#define PCNT1_CH1CTRL_GPIO16 \ + ESP32_PINMUX(16, ESP_PCNT_CTRL_CH1_IN1, ESP_NOSIG) + +#define PCNT1_CH1CTRL_GPIO17 \ + ESP32_PINMUX(17, ESP_PCNT_CTRL_CH1_IN1, ESP_NOSIG) + +#define PCNT1_CH1CTRL_GPIO18 \ + ESP32_PINMUX(18, ESP_PCNT_CTRL_CH1_IN1, ESP_NOSIG) + +#define PCNT1_CH1CTRL_GPIO19 \ + ESP32_PINMUX(19, ESP_PCNT_CTRL_CH1_IN1, ESP_NOSIG) + +#define PCNT1_CH1CTRL_GPIO20 \ + ESP32_PINMUX(20, ESP_PCNT_CTRL_CH1_IN1, ESP_NOSIG) + +#define PCNT1_CH1CTRL_GPIO21 \ + ESP32_PINMUX(21, ESP_PCNT_CTRL_CH1_IN1, ESP_NOSIG) + +#define PCNT1_CH1CTRL_GPIO22 \ + ESP32_PINMUX(22, ESP_PCNT_CTRL_CH1_IN1, ESP_NOSIG) + +#define PCNT1_CH1CTRL_GPIO23 \ + ESP32_PINMUX(23, ESP_PCNT_CTRL_CH1_IN1, ESP_NOSIG) + +#define PCNT1_CH1CTRL_GPIO25 \ + ESP32_PINMUX(25, ESP_PCNT_CTRL_CH1_IN1, ESP_NOSIG) + +#define PCNT1_CH1CTRL_GPIO26 \ + ESP32_PINMUX(26, ESP_PCNT_CTRL_CH1_IN1, ESP_NOSIG) + +#define PCNT1_CH1CTRL_GPIO27 \ + ESP32_PINMUX(27, ESP_PCNT_CTRL_CH1_IN1, ESP_NOSIG) + +#define PCNT1_CH1CTRL_GPIO32 \ + ESP32_PINMUX(32, ESP_PCNT_CTRL_CH1_IN1, ESP_NOSIG) + +#define PCNT1_CH1CTRL_GPIO33 \ + ESP32_PINMUX(33, ESP_PCNT_CTRL_CH1_IN1, ESP_NOSIG) + +#define PCNT1_CH1CTRL_GPIO34 \ + ESP32_PINMUX(34, ESP_PCNT_CTRL_CH1_IN1, ESP_NOSIG) + +#define PCNT1_CH1CTRL_GPIO35 \ + ESP32_PINMUX(35, ESP_PCNT_CTRL_CH1_IN1, ESP_NOSIG) + +#define PCNT1_CH1CTRL_GPIO36 \ + ESP32_PINMUX(36, ESP_PCNT_CTRL_CH1_IN1, ESP_NOSIG) + +#define PCNT1_CH1CTRL_GPIO37 \ + ESP32_PINMUX(37, ESP_PCNT_CTRL_CH1_IN1, ESP_NOSIG) + +#define PCNT1_CH1CTRL_GPIO38 \ + ESP32_PINMUX(38, ESP_PCNT_CTRL_CH1_IN1, ESP_NOSIG) + +#define PCNT1_CH1CTRL_GPIO39 \ + ESP32_PINMUX(39, ESP_PCNT_CTRL_CH1_IN1, ESP_NOSIG) + +/* PCNT1_CH1SIG */ +#define PCNT1_CH1SIG_GPIO0 \ + ESP32_PINMUX(0, ESP_PCNT_SIG_CH1_IN1, ESP_NOSIG) + +#define PCNT1_CH1SIG_GPIO1 \ + ESP32_PINMUX(1, ESP_PCNT_SIG_CH1_IN1, ESP_NOSIG) + +#define PCNT1_CH1SIG_GPIO2 \ + ESP32_PINMUX(2, ESP_PCNT_SIG_CH1_IN1, ESP_NOSIG) + +#define PCNT1_CH1SIG_GPIO3 \ + ESP32_PINMUX(3, ESP_PCNT_SIG_CH1_IN1, ESP_NOSIG) + +#define PCNT1_CH1SIG_GPIO4 \ + ESP32_PINMUX(4, ESP_PCNT_SIG_CH1_IN1, ESP_NOSIG) + +#define PCNT1_CH1SIG_GPIO5 \ + ESP32_PINMUX(5, ESP_PCNT_SIG_CH1_IN1, ESP_NOSIG) + +#define PCNT1_CH1SIG_GPIO6 \ + ESP32_PINMUX(6, ESP_PCNT_SIG_CH1_IN1, ESP_NOSIG) + +#define PCNT1_CH1SIG_GPIO7 \ + ESP32_PINMUX(7, ESP_PCNT_SIG_CH1_IN1, ESP_NOSIG) + +#define PCNT1_CH1SIG_GPIO8 \ + ESP32_PINMUX(8, ESP_PCNT_SIG_CH1_IN1, ESP_NOSIG) + +#define PCNT1_CH1SIG_GPIO9 \ + ESP32_PINMUX(9, ESP_PCNT_SIG_CH1_IN1, ESP_NOSIG) + +#define PCNT1_CH1SIG_GPIO10 \ + ESP32_PINMUX(10, ESP_PCNT_SIG_CH1_IN1, ESP_NOSIG) + +#define PCNT1_CH1SIG_GPIO11 \ + ESP32_PINMUX(11, ESP_PCNT_SIG_CH1_IN1, ESP_NOSIG) + +#define PCNT1_CH1SIG_GPIO12 \ + ESP32_PINMUX(12, ESP_PCNT_SIG_CH1_IN1, ESP_NOSIG) + +#define PCNT1_CH1SIG_GPIO13 \ + ESP32_PINMUX(13, ESP_PCNT_SIG_CH1_IN1, ESP_NOSIG) + +#define PCNT1_CH1SIG_GPIO14 \ + ESP32_PINMUX(14, ESP_PCNT_SIG_CH1_IN1, ESP_NOSIG) + +#define PCNT1_CH1SIG_GPIO15 \ + ESP32_PINMUX(15, ESP_PCNT_SIG_CH1_IN1, ESP_NOSIG) + +#define PCNT1_CH1SIG_GPIO16 \ + ESP32_PINMUX(16, ESP_PCNT_SIG_CH1_IN1, ESP_NOSIG) + +#define PCNT1_CH1SIG_GPIO17 \ + ESP32_PINMUX(17, ESP_PCNT_SIG_CH1_IN1, ESP_NOSIG) + +#define PCNT1_CH1SIG_GPIO18 \ + ESP32_PINMUX(18, ESP_PCNT_SIG_CH1_IN1, ESP_NOSIG) + +#define PCNT1_CH1SIG_GPIO19 \ + ESP32_PINMUX(19, ESP_PCNT_SIG_CH1_IN1, ESP_NOSIG) + +#define PCNT1_CH1SIG_GPIO20 \ + ESP32_PINMUX(20, ESP_PCNT_SIG_CH1_IN1, ESP_NOSIG) + +#define PCNT1_CH1SIG_GPIO21 \ + ESP32_PINMUX(21, ESP_PCNT_SIG_CH1_IN1, ESP_NOSIG) + +#define PCNT1_CH1SIG_GPIO22 \ + ESP32_PINMUX(22, ESP_PCNT_SIG_CH1_IN1, ESP_NOSIG) + +#define PCNT1_CH1SIG_GPIO23 \ + ESP32_PINMUX(23, ESP_PCNT_SIG_CH1_IN1, ESP_NOSIG) + +#define PCNT1_CH1SIG_GPIO25 \ + ESP32_PINMUX(25, ESP_PCNT_SIG_CH1_IN1, ESP_NOSIG) + +#define PCNT1_CH1SIG_GPIO26 \ + ESP32_PINMUX(26, ESP_PCNT_SIG_CH1_IN1, ESP_NOSIG) + +#define PCNT1_CH1SIG_GPIO27 \ + ESP32_PINMUX(27, ESP_PCNT_SIG_CH1_IN1, ESP_NOSIG) + +#define PCNT1_CH1SIG_GPIO32 \ + ESP32_PINMUX(32, ESP_PCNT_SIG_CH1_IN1, ESP_NOSIG) + +#define PCNT1_CH1SIG_GPIO33 \ + ESP32_PINMUX(33, ESP_PCNT_SIG_CH1_IN1, ESP_NOSIG) + +#define PCNT1_CH1SIG_GPIO34 \ + ESP32_PINMUX(34, ESP_PCNT_SIG_CH1_IN1, ESP_NOSIG) + +#define PCNT1_CH1SIG_GPIO35 \ + ESP32_PINMUX(35, ESP_PCNT_SIG_CH1_IN1, ESP_NOSIG) + +#define PCNT1_CH1SIG_GPIO36 \ + ESP32_PINMUX(36, ESP_PCNT_SIG_CH1_IN1, ESP_NOSIG) + +#define PCNT1_CH1SIG_GPIO37 \ + ESP32_PINMUX(37, ESP_PCNT_SIG_CH1_IN1, ESP_NOSIG) + +#define PCNT1_CH1SIG_GPIO38 \ + ESP32_PINMUX(38, ESP_PCNT_SIG_CH1_IN1, ESP_NOSIG) + +#define PCNT1_CH1SIG_GPIO39 \ + ESP32_PINMUX(39, ESP_PCNT_SIG_CH1_IN1, ESP_NOSIG) + +/* PCNT2_CH0CTRL */ +#define PCNT2_CH0CTRL_GPIO0 \ + ESP32_PINMUX(0, ESP_PCNT_CTRL_CH0_IN2, ESP_NOSIG) + +#define PCNT2_CH0CTRL_GPIO1 \ + ESP32_PINMUX(1, ESP_PCNT_CTRL_CH0_IN2, ESP_NOSIG) + +#define PCNT2_CH0CTRL_GPIO2 \ + ESP32_PINMUX(2, ESP_PCNT_CTRL_CH0_IN2, ESP_NOSIG) + +#define PCNT2_CH0CTRL_GPIO3 \ + ESP32_PINMUX(3, ESP_PCNT_CTRL_CH0_IN2, ESP_NOSIG) + +#define PCNT2_CH0CTRL_GPIO4 \ + ESP32_PINMUX(4, ESP_PCNT_CTRL_CH0_IN2, ESP_NOSIG) + +#define PCNT2_CH0CTRL_GPIO5 \ + ESP32_PINMUX(5, ESP_PCNT_CTRL_CH0_IN2, ESP_NOSIG) + +#define PCNT2_CH0CTRL_GPIO6 \ + ESP32_PINMUX(6, ESP_PCNT_CTRL_CH0_IN2, ESP_NOSIG) + +#define PCNT2_CH0CTRL_GPIO7 \ + ESP32_PINMUX(7, ESP_PCNT_CTRL_CH0_IN2, ESP_NOSIG) + +#define PCNT2_CH0CTRL_GPIO8 \ + ESP32_PINMUX(8, ESP_PCNT_CTRL_CH0_IN2, ESP_NOSIG) + +#define PCNT2_CH0CTRL_GPIO9 \ + ESP32_PINMUX(9, ESP_PCNT_CTRL_CH0_IN2, ESP_NOSIG) + +#define PCNT2_CH0CTRL_GPIO10 \ + ESP32_PINMUX(10, ESP_PCNT_CTRL_CH0_IN2, ESP_NOSIG) + +#define PCNT2_CH0CTRL_GPIO11 \ + ESP32_PINMUX(11, ESP_PCNT_CTRL_CH0_IN2, ESP_NOSIG) + +#define PCNT2_CH0CTRL_GPIO12 \ + ESP32_PINMUX(12, ESP_PCNT_CTRL_CH0_IN2, ESP_NOSIG) + +#define PCNT2_CH0CTRL_GPIO13 \ + ESP32_PINMUX(13, ESP_PCNT_CTRL_CH0_IN2, ESP_NOSIG) + +#define PCNT2_CH0CTRL_GPIO14 \ + ESP32_PINMUX(14, ESP_PCNT_CTRL_CH0_IN2, ESP_NOSIG) + +#define PCNT2_CH0CTRL_GPIO15 \ + ESP32_PINMUX(15, ESP_PCNT_CTRL_CH0_IN2, ESP_NOSIG) + +#define PCNT2_CH0CTRL_GPIO16 \ + ESP32_PINMUX(16, ESP_PCNT_CTRL_CH0_IN2, ESP_NOSIG) + +#define PCNT2_CH0CTRL_GPIO17 \ + ESP32_PINMUX(17, ESP_PCNT_CTRL_CH0_IN2, ESP_NOSIG) + +#define PCNT2_CH0CTRL_GPIO18 \ + ESP32_PINMUX(18, ESP_PCNT_CTRL_CH0_IN2, ESP_NOSIG) + +#define PCNT2_CH0CTRL_GPIO19 \ + ESP32_PINMUX(19, ESP_PCNT_CTRL_CH0_IN2, ESP_NOSIG) + +#define PCNT2_CH0CTRL_GPIO20 \ + ESP32_PINMUX(20, ESP_PCNT_CTRL_CH0_IN2, ESP_NOSIG) + +#define PCNT2_CH0CTRL_GPIO21 \ + ESP32_PINMUX(21, ESP_PCNT_CTRL_CH0_IN2, ESP_NOSIG) + +#define PCNT2_CH0CTRL_GPIO22 \ + ESP32_PINMUX(22, ESP_PCNT_CTRL_CH0_IN2, ESP_NOSIG) + +#define PCNT2_CH0CTRL_GPIO23 \ + ESP32_PINMUX(23, ESP_PCNT_CTRL_CH0_IN2, ESP_NOSIG) + +#define PCNT2_CH0CTRL_GPIO25 \ + ESP32_PINMUX(25, ESP_PCNT_CTRL_CH0_IN2, ESP_NOSIG) + +#define PCNT2_CH0CTRL_GPIO26 \ + ESP32_PINMUX(26, ESP_PCNT_CTRL_CH0_IN2, ESP_NOSIG) + +#define PCNT2_CH0CTRL_GPIO27 \ + ESP32_PINMUX(27, ESP_PCNT_CTRL_CH0_IN2, ESP_NOSIG) + +#define PCNT2_CH0CTRL_GPIO32 \ + ESP32_PINMUX(32, ESP_PCNT_CTRL_CH0_IN2, ESP_NOSIG) + +#define PCNT2_CH0CTRL_GPIO33 \ + ESP32_PINMUX(33, ESP_PCNT_CTRL_CH0_IN2, ESP_NOSIG) + +#define PCNT2_CH0CTRL_GPIO34 \ + ESP32_PINMUX(34, ESP_PCNT_CTRL_CH0_IN2, ESP_NOSIG) + +#define PCNT2_CH0CTRL_GPIO35 \ + ESP32_PINMUX(35, ESP_PCNT_CTRL_CH0_IN2, ESP_NOSIG) + +#define PCNT2_CH0CTRL_GPIO36 \ + ESP32_PINMUX(36, ESP_PCNT_CTRL_CH0_IN2, ESP_NOSIG) + +#define PCNT2_CH0CTRL_GPIO37 \ + ESP32_PINMUX(37, ESP_PCNT_CTRL_CH0_IN2, ESP_NOSIG) + +#define PCNT2_CH0CTRL_GPIO38 \ + ESP32_PINMUX(38, ESP_PCNT_CTRL_CH0_IN2, ESP_NOSIG) + +#define PCNT2_CH0CTRL_GPIO39 \ + ESP32_PINMUX(39, ESP_PCNT_CTRL_CH0_IN2, ESP_NOSIG) + +/* PCNT2_CH0SIG */ +#define PCNT2_CH0SIG_GPIO0 \ + ESP32_PINMUX(0, ESP_PCNT_SIG_CH0_IN3, ESP_NOSIG) + +#define PCNT2_CH0SIG_GPIO1 \ + ESP32_PINMUX(1, ESP_PCNT_SIG_CH0_IN3, ESP_NOSIG) + +#define PCNT2_CH0SIG_GPIO2 \ + ESP32_PINMUX(2, ESP_PCNT_SIG_CH0_IN3, ESP_NOSIG) + +#define PCNT2_CH0SIG_GPIO3 \ + ESP32_PINMUX(3, ESP_PCNT_SIG_CH0_IN3, ESP_NOSIG) + +#define PCNT2_CH0SIG_GPIO4 \ + ESP32_PINMUX(4, ESP_PCNT_SIG_CH0_IN3, ESP_NOSIG) + +#define PCNT2_CH0SIG_GPIO5 \ + ESP32_PINMUX(5, ESP_PCNT_SIG_CH0_IN3, ESP_NOSIG) + +#define PCNT2_CH0SIG_GPIO6 \ + ESP32_PINMUX(6, ESP_PCNT_SIG_CH0_IN3, ESP_NOSIG) + +#define PCNT2_CH0SIG_GPIO7 \ + ESP32_PINMUX(7, ESP_PCNT_SIG_CH0_IN3, ESP_NOSIG) + +#define PCNT2_CH0SIG_GPIO8 \ + ESP32_PINMUX(8, ESP_PCNT_SIG_CH0_IN3, ESP_NOSIG) + +#define PCNT2_CH0SIG_GPIO9 \ + ESP32_PINMUX(9, ESP_PCNT_SIG_CH0_IN3, ESP_NOSIG) + +#define PCNT2_CH0SIG_GPIO10 \ + ESP32_PINMUX(10, ESP_PCNT_SIG_CH0_IN3, ESP_NOSIG) + +#define PCNT2_CH0SIG_GPIO11 \ + ESP32_PINMUX(11, ESP_PCNT_SIG_CH0_IN3, ESP_NOSIG) + +#define PCNT2_CH0SIG_GPIO12 \ + ESP32_PINMUX(12, ESP_PCNT_SIG_CH0_IN3, ESP_NOSIG) + +#define PCNT2_CH0SIG_GPIO13 \ + ESP32_PINMUX(13, ESP_PCNT_SIG_CH0_IN3, ESP_NOSIG) + +#define PCNT2_CH0SIG_GPIO14 \ + ESP32_PINMUX(14, ESP_PCNT_SIG_CH0_IN3, ESP_NOSIG) + +#define PCNT2_CH0SIG_GPIO15 \ + ESP32_PINMUX(15, ESP_PCNT_SIG_CH0_IN3, ESP_NOSIG) + +#define PCNT2_CH0SIG_GPIO16 \ + ESP32_PINMUX(16, ESP_PCNT_SIG_CH0_IN3, ESP_NOSIG) + +#define PCNT2_CH0SIG_GPIO17 \ + ESP32_PINMUX(17, ESP_PCNT_SIG_CH0_IN3, ESP_NOSIG) + +#define PCNT2_CH0SIG_GPIO18 \ + ESP32_PINMUX(18, ESP_PCNT_SIG_CH0_IN3, ESP_NOSIG) + +#define PCNT2_CH0SIG_GPIO19 \ + ESP32_PINMUX(19, ESP_PCNT_SIG_CH0_IN3, ESP_NOSIG) + +#define PCNT2_CH0SIG_GPIO20 \ + ESP32_PINMUX(20, ESP_PCNT_SIG_CH0_IN3, ESP_NOSIG) + +#define PCNT2_CH0SIG_GPIO21 \ + ESP32_PINMUX(21, ESP_PCNT_SIG_CH0_IN3, ESP_NOSIG) + +#define PCNT2_CH0SIG_GPIO22 \ + ESP32_PINMUX(22, ESP_PCNT_SIG_CH0_IN3, ESP_NOSIG) + +#define PCNT2_CH0SIG_GPIO23 \ + ESP32_PINMUX(23, ESP_PCNT_SIG_CH0_IN3, ESP_NOSIG) + +#define PCNT2_CH0SIG_GPIO25 \ + ESP32_PINMUX(25, ESP_PCNT_SIG_CH0_IN3, ESP_NOSIG) + +#define PCNT2_CH0SIG_GPIO26 \ + ESP32_PINMUX(26, ESP_PCNT_SIG_CH0_IN3, ESP_NOSIG) + +#define PCNT2_CH0SIG_GPIO27 \ + ESP32_PINMUX(27, ESP_PCNT_SIG_CH0_IN3, ESP_NOSIG) + +#define PCNT2_CH0SIG_GPIO32 \ + ESP32_PINMUX(32, ESP_PCNT_SIG_CH0_IN3, ESP_NOSIG) + +#define PCNT2_CH0SIG_GPIO33 \ + ESP32_PINMUX(33, ESP_PCNT_SIG_CH0_IN3, ESP_NOSIG) + +#define PCNT2_CH0SIG_GPIO34 \ + ESP32_PINMUX(34, ESP_PCNT_SIG_CH0_IN3, ESP_NOSIG) + +#define PCNT2_CH0SIG_GPIO35 \ + ESP32_PINMUX(35, ESP_PCNT_SIG_CH0_IN3, ESP_NOSIG) + +#define PCNT2_CH0SIG_GPIO36 \ + ESP32_PINMUX(36, ESP_PCNT_SIG_CH0_IN3, ESP_NOSIG) + +#define PCNT2_CH0SIG_GPIO37 \ + ESP32_PINMUX(37, ESP_PCNT_SIG_CH0_IN3, ESP_NOSIG) + +#define PCNT2_CH0SIG_GPIO38 \ + ESP32_PINMUX(38, ESP_PCNT_SIG_CH0_IN3, ESP_NOSIG) + +#define PCNT2_CH0SIG_GPIO39 \ + ESP32_PINMUX(39, ESP_PCNT_SIG_CH0_IN3, ESP_NOSIG) + +/* PCNT2_CH1CTRL */ +#define PCNT2_CH1CTRL_GPIO0 \ + ESP32_PINMUX(0, ESP_PCNT_CTRL_CH1_IN2, ESP_NOSIG) + +#define PCNT2_CH1CTRL_GPIO1 \ + ESP32_PINMUX(1, ESP_PCNT_CTRL_CH1_IN2, ESP_NOSIG) + +#define PCNT2_CH1CTRL_GPIO2 \ + ESP32_PINMUX(2, ESP_PCNT_CTRL_CH1_IN2, ESP_NOSIG) + +#define PCNT2_CH1CTRL_GPIO3 \ + ESP32_PINMUX(3, ESP_PCNT_CTRL_CH1_IN2, ESP_NOSIG) + +#define PCNT2_CH1CTRL_GPIO4 \ + ESP32_PINMUX(4, ESP_PCNT_CTRL_CH1_IN2, ESP_NOSIG) + +#define PCNT2_CH1CTRL_GPIO5 \ + ESP32_PINMUX(5, ESP_PCNT_CTRL_CH1_IN2, ESP_NOSIG) + +#define PCNT2_CH1CTRL_GPIO6 \ + ESP32_PINMUX(6, ESP_PCNT_CTRL_CH1_IN2, ESP_NOSIG) + +#define PCNT2_CH1CTRL_GPIO7 \ + ESP32_PINMUX(7, ESP_PCNT_CTRL_CH1_IN2, ESP_NOSIG) + +#define PCNT2_CH1CTRL_GPIO8 \ + ESP32_PINMUX(8, ESP_PCNT_CTRL_CH1_IN2, ESP_NOSIG) + +#define PCNT2_CH1CTRL_GPIO9 \ + ESP32_PINMUX(9, ESP_PCNT_CTRL_CH1_IN2, ESP_NOSIG) + +#define PCNT2_CH1CTRL_GPIO10 \ + ESP32_PINMUX(10, ESP_PCNT_CTRL_CH1_IN2, ESP_NOSIG) + +#define PCNT2_CH1CTRL_GPIO11 \ + ESP32_PINMUX(11, ESP_PCNT_CTRL_CH1_IN2, ESP_NOSIG) + +#define PCNT2_CH1CTRL_GPIO12 \ + ESP32_PINMUX(12, ESP_PCNT_CTRL_CH1_IN2, ESP_NOSIG) + +#define PCNT2_CH1CTRL_GPIO13 \ + ESP32_PINMUX(13, ESP_PCNT_CTRL_CH1_IN2, ESP_NOSIG) + +#define PCNT2_CH1CTRL_GPIO14 \ + ESP32_PINMUX(14, ESP_PCNT_CTRL_CH1_IN2, ESP_NOSIG) + +#define PCNT2_CH1CTRL_GPIO15 \ + ESP32_PINMUX(15, ESP_PCNT_CTRL_CH1_IN2, ESP_NOSIG) + +#define PCNT2_CH1CTRL_GPIO16 \ + ESP32_PINMUX(16, ESP_PCNT_CTRL_CH1_IN2, ESP_NOSIG) + +#define PCNT2_CH1CTRL_GPIO17 \ + ESP32_PINMUX(17, ESP_PCNT_CTRL_CH1_IN2, ESP_NOSIG) + +#define PCNT2_CH1CTRL_GPIO18 \ + ESP32_PINMUX(18, ESP_PCNT_CTRL_CH1_IN2, ESP_NOSIG) + +#define PCNT2_CH1CTRL_GPIO19 \ + ESP32_PINMUX(19, ESP_PCNT_CTRL_CH1_IN2, ESP_NOSIG) + +#define PCNT2_CH1CTRL_GPIO20 \ + ESP32_PINMUX(20, ESP_PCNT_CTRL_CH1_IN2, ESP_NOSIG) + +#define PCNT2_CH1CTRL_GPIO21 \ + ESP32_PINMUX(21, ESP_PCNT_CTRL_CH1_IN2, ESP_NOSIG) + +#define PCNT2_CH1CTRL_GPIO22 \ + ESP32_PINMUX(22, ESP_PCNT_CTRL_CH1_IN2, ESP_NOSIG) + +#define PCNT2_CH1CTRL_GPIO23 \ + ESP32_PINMUX(23, ESP_PCNT_CTRL_CH1_IN2, ESP_NOSIG) + +#define PCNT2_CH1CTRL_GPIO25 \ + ESP32_PINMUX(25, ESP_PCNT_CTRL_CH1_IN2, ESP_NOSIG) + +#define PCNT2_CH1CTRL_GPIO26 \ + ESP32_PINMUX(26, ESP_PCNT_CTRL_CH1_IN2, ESP_NOSIG) + +#define PCNT2_CH1CTRL_GPIO27 \ + ESP32_PINMUX(27, ESP_PCNT_CTRL_CH1_IN2, ESP_NOSIG) + +#define PCNT2_CH1CTRL_GPIO32 \ + ESP32_PINMUX(32, ESP_PCNT_CTRL_CH1_IN2, ESP_NOSIG) + +#define PCNT2_CH1CTRL_GPIO33 \ + ESP32_PINMUX(33, ESP_PCNT_CTRL_CH1_IN2, ESP_NOSIG) + +#define PCNT2_CH1CTRL_GPIO34 \ + ESP32_PINMUX(34, ESP_PCNT_CTRL_CH1_IN2, ESP_NOSIG) + +#define PCNT2_CH1CTRL_GPIO35 \ + ESP32_PINMUX(35, ESP_PCNT_CTRL_CH1_IN2, ESP_NOSIG) + +#define PCNT2_CH1CTRL_GPIO36 \ + ESP32_PINMUX(36, ESP_PCNT_CTRL_CH1_IN2, ESP_NOSIG) + +#define PCNT2_CH1CTRL_GPIO37 \ + ESP32_PINMUX(37, ESP_PCNT_CTRL_CH1_IN2, ESP_NOSIG) + +#define PCNT2_CH1CTRL_GPIO38 \ + ESP32_PINMUX(38, ESP_PCNT_CTRL_CH1_IN2, ESP_NOSIG) + +#define PCNT2_CH1CTRL_GPIO39 \ + ESP32_PINMUX(39, ESP_PCNT_CTRL_CH1_IN2, ESP_NOSIG) + +/* PCNT2_CH1SIG */ +#define PCNT2_CH1SIG_GPIO0 \ + ESP32_PINMUX(0, ESP_PCNT_SIG_CH1_IN2, ESP_NOSIG) + +#define PCNT2_CH1SIG_GPIO1 \ + ESP32_PINMUX(1, ESP_PCNT_SIG_CH1_IN2, ESP_NOSIG) + +#define PCNT2_CH1SIG_GPIO2 \ + ESP32_PINMUX(2, ESP_PCNT_SIG_CH1_IN2, ESP_NOSIG) + +#define PCNT2_CH1SIG_GPIO3 \ + ESP32_PINMUX(3, ESP_PCNT_SIG_CH1_IN2, ESP_NOSIG) + +#define PCNT2_CH1SIG_GPIO4 \ + ESP32_PINMUX(4, ESP_PCNT_SIG_CH1_IN2, ESP_NOSIG) + +#define PCNT2_CH1SIG_GPIO5 \ + ESP32_PINMUX(5, ESP_PCNT_SIG_CH1_IN2, ESP_NOSIG) + +#define PCNT2_CH1SIG_GPIO6 \ + ESP32_PINMUX(6, ESP_PCNT_SIG_CH1_IN2, ESP_NOSIG) + +#define PCNT2_CH1SIG_GPIO7 \ + ESP32_PINMUX(7, ESP_PCNT_SIG_CH1_IN2, ESP_NOSIG) + +#define PCNT2_CH1SIG_GPIO8 \ + ESP32_PINMUX(8, ESP_PCNT_SIG_CH1_IN2, ESP_NOSIG) + +#define PCNT2_CH1SIG_GPIO9 \ + ESP32_PINMUX(9, ESP_PCNT_SIG_CH1_IN2, ESP_NOSIG) + +#define PCNT2_CH1SIG_GPIO10 \ + ESP32_PINMUX(10, ESP_PCNT_SIG_CH1_IN2, ESP_NOSIG) + +#define PCNT2_CH1SIG_GPIO11 \ + ESP32_PINMUX(11, ESP_PCNT_SIG_CH1_IN2, ESP_NOSIG) + +#define PCNT2_CH1SIG_GPIO12 \ + ESP32_PINMUX(12, ESP_PCNT_SIG_CH1_IN2, ESP_NOSIG) + +#define PCNT2_CH1SIG_GPIO13 \ + ESP32_PINMUX(13, ESP_PCNT_SIG_CH1_IN2, ESP_NOSIG) + +#define PCNT2_CH1SIG_GPIO14 \ + ESP32_PINMUX(14, ESP_PCNT_SIG_CH1_IN2, ESP_NOSIG) + +#define PCNT2_CH1SIG_GPIO15 \ + ESP32_PINMUX(15, ESP_PCNT_SIG_CH1_IN2, ESP_NOSIG) + +#define PCNT2_CH1SIG_GPIO16 \ + ESP32_PINMUX(16, ESP_PCNT_SIG_CH1_IN2, ESP_NOSIG) + +#define PCNT2_CH1SIG_GPIO17 \ + ESP32_PINMUX(17, ESP_PCNT_SIG_CH1_IN2, ESP_NOSIG) + +#define PCNT2_CH1SIG_GPIO18 \ + ESP32_PINMUX(18, ESP_PCNT_SIG_CH1_IN2, ESP_NOSIG) + +#define PCNT2_CH1SIG_GPIO19 \ + ESP32_PINMUX(19, ESP_PCNT_SIG_CH1_IN2, ESP_NOSIG) + +#define PCNT2_CH1SIG_GPIO20 \ + ESP32_PINMUX(20, ESP_PCNT_SIG_CH1_IN2, ESP_NOSIG) + +#define PCNT2_CH1SIG_GPIO21 \ + ESP32_PINMUX(21, ESP_PCNT_SIG_CH1_IN2, ESP_NOSIG) + +#define PCNT2_CH1SIG_GPIO22 \ + ESP32_PINMUX(22, ESP_PCNT_SIG_CH1_IN2, ESP_NOSIG) + +#define PCNT2_CH1SIG_GPIO23 \ + ESP32_PINMUX(23, ESP_PCNT_SIG_CH1_IN2, ESP_NOSIG) + +#define PCNT2_CH1SIG_GPIO25 \ + ESP32_PINMUX(25, ESP_PCNT_SIG_CH1_IN2, ESP_NOSIG) + +#define PCNT2_CH1SIG_GPIO26 \ + ESP32_PINMUX(26, ESP_PCNT_SIG_CH1_IN2, ESP_NOSIG) + +#define PCNT2_CH1SIG_GPIO27 \ + ESP32_PINMUX(27, ESP_PCNT_SIG_CH1_IN2, ESP_NOSIG) + +#define PCNT2_CH1SIG_GPIO32 \ + ESP32_PINMUX(32, ESP_PCNT_SIG_CH1_IN2, ESP_NOSIG) + +#define PCNT2_CH1SIG_GPIO33 \ + ESP32_PINMUX(33, ESP_PCNT_SIG_CH1_IN2, ESP_NOSIG) + +#define PCNT2_CH1SIG_GPIO34 \ + ESP32_PINMUX(34, ESP_PCNT_SIG_CH1_IN2, ESP_NOSIG) + +#define PCNT2_CH1SIG_GPIO35 \ + ESP32_PINMUX(35, ESP_PCNT_SIG_CH1_IN2, ESP_NOSIG) + +#define PCNT2_CH1SIG_GPIO36 \ + ESP32_PINMUX(36, ESP_PCNT_SIG_CH1_IN2, ESP_NOSIG) + +#define PCNT2_CH1SIG_GPIO37 \ + ESP32_PINMUX(37, ESP_PCNT_SIG_CH1_IN2, ESP_NOSIG) + +#define PCNT2_CH1SIG_GPIO38 \ + ESP32_PINMUX(38, ESP_PCNT_SIG_CH1_IN2, ESP_NOSIG) + +#define PCNT2_CH1SIG_GPIO39 \ + ESP32_PINMUX(39, ESP_PCNT_SIG_CH1_IN2, ESP_NOSIG) + +/* PCNT3_CH0CTRL */ +#define PCNT3_CH0CTRL_GPIO0 \ + ESP32_PINMUX(0, ESP_PCNT_CTRL_CH0_IN3, ESP_NOSIG) + +#define PCNT3_CH0CTRL_GPIO1 \ + ESP32_PINMUX(1, ESP_PCNT_CTRL_CH0_IN3, ESP_NOSIG) + +#define PCNT3_CH0CTRL_GPIO2 \ + ESP32_PINMUX(2, ESP_PCNT_CTRL_CH0_IN3, ESP_NOSIG) + +#define PCNT3_CH0CTRL_GPIO3 \ + ESP32_PINMUX(3, ESP_PCNT_CTRL_CH0_IN3, ESP_NOSIG) + +#define PCNT3_CH0CTRL_GPIO4 \ + ESP32_PINMUX(4, ESP_PCNT_CTRL_CH0_IN3, ESP_NOSIG) + +#define PCNT3_CH0CTRL_GPIO5 \ + ESP32_PINMUX(5, ESP_PCNT_CTRL_CH0_IN3, ESP_NOSIG) + +#define PCNT3_CH0CTRL_GPIO6 \ + ESP32_PINMUX(6, ESP_PCNT_CTRL_CH0_IN3, ESP_NOSIG) + +#define PCNT3_CH0CTRL_GPIO7 \ + ESP32_PINMUX(7, ESP_PCNT_CTRL_CH0_IN3, ESP_NOSIG) + +#define PCNT3_CH0CTRL_GPIO8 \ + ESP32_PINMUX(8, ESP_PCNT_CTRL_CH0_IN3, ESP_NOSIG) + +#define PCNT3_CH0CTRL_GPIO9 \ + ESP32_PINMUX(9, ESP_PCNT_CTRL_CH0_IN3, ESP_NOSIG) + +#define PCNT3_CH0CTRL_GPIO10 \ + ESP32_PINMUX(10, ESP_PCNT_CTRL_CH0_IN3, ESP_NOSIG) + +#define PCNT3_CH0CTRL_GPIO11 \ + ESP32_PINMUX(11, ESP_PCNT_CTRL_CH0_IN3, ESP_NOSIG) + +#define PCNT3_CH0CTRL_GPIO12 \ + ESP32_PINMUX(12, ESP_PCNT_CTRL_CH0_IN3, ESP_NOSIG) + +#define PCNT3_CH0CTRL_GPIO13 \ + ESP32_PINMUX(13, ESP_PCNT_CTRL_CH0_IN3, ESP_NOSIG) + +#define PCNT3_CH0CTRL_GPIO14 \ + ESP32_PINMUX(14, ESP_PCNT_CTRL_CH0_IN3, ESP_NOSIG) + +#define PCNT3_CH0CTRL_GPIO15 \ + ESP32_PINMUX(15, ESP_PCNT_CTRL_CH0_IN3, ESP_NOSIG) + +#define PCNT3_CH0CTRL_GPIO16 \ + ESP32_PINMUX(16, ESP_PCNT_CTRL_CH0_IN3, ESP_NOSIG) + +#define PCNT3_CH0CTRL_GPIO17 \ + ESP32_PINMUX(17, ESP_PCNT_CTRL_CH0_IN3, ESP_NOSIG) + +#define PCNT3_CH0CTRL_GPIO18 \ + ESP32_PINMUX(18, ESP_PCNT_CTRL_CH0_IN3, ESP_NOSIG) + +#define PCNT3_CH0CTRL_GPIO19 \ + ESP32_PINMUX(19, ESP_PCNT_CTRL_CH0_IN3, ESP_NOSIG) + +#define PCNT3_CH0CTRL_GPIO20 \ + ESP32_PINMUX(20, ESP_PCNT_CTRL_CH0_IN3, ESP_NOSIG) + +#define PCNT3_CH0CTRL_GPIO21 \ + ESP32_PINMUX(21, ESP_PCNT_CTRL_CH0_IN3, ESP_NOSIG) + +#define PCNT3_CH0CTRL_GPIO22 \ + ESP32_PINMUX(22, ESP_PCNT_CTRL_CH0_IN3, ESP_NOSIG) + +#define PCNT3_CH0CTRL_GPIO23 \ + ESP32_PINMUX(23, ESP_PCNT_CTRL_CH0_IN3, ESP_NOSIG) + +#define PCNT3_CH0CTRL_GPIO25 \ + ESP32_PINMUX(25, ESP_PCNT_CTRL_CH0_IN3, ESP_NOSIG) + +#define PCNT3_CH0CTRL_GPIO26 \ + ESP32_PINMUX(26, ESP_PCNT_CTRL_CH0_IN3, ESP_NOSIG) + +#define PCNT3_CH0CTRL_GPIO27 \ + ESP32_PINMUX(27, ESP_PCNT_CTRL_CH0_IN3, ESP_NOSIG) + +#define PCNT3_CH0CTRL_GPIO32 \ + ESP32_PINMUX(32, ESP_PCNT_CTRL_CH0_IN3, ESP_NOSIG) + +#define PCNT3_CH0CTRL_GPIO33 \ + ESP32_PINMUX(33, ESP_PCNT_CTRL_CH0_IN3, ESP_NOSIG) + +#define PCNT3_CH0CTRL_GPIO34 \ + ESP32_PINMUX(34, ESP_PCNT_CTRL_CH0_IN3, ESP_NOSIG) + +#define PCNT3_CH0CTRL_GPIO35 \ + ESP32_PINMUX(35, ESP_PCNT_CTRL_CH0_IN3, ESP_NOSIG) + +#define PCNT3_CH0CTRL_GPIO36 \ + ESP32_PINMUX(36, ESP_PCNT_CTRL_CH0_IN3, ESP_NOSIG) + +#define PCNT3_CH0CTRL_GPIO37 \ + ESP32_PINMUX(37, ESP_PCNT_CTRL_CH0_IN3, ESP_NOSIG) + +#define PCNT3_CH0CTRL_GPIO38 \ + ESP32_PINMUX(38, ESP_PCNT_CTRL_CH0_IN3, ESP_NOSIG) + +#define PCNT3_CH0CTRL_GPIO39 \ + ESP32_PINMUX(39, ESP_PCNT_CTRL_CH0_IN3, ESP_NOSIG) + +/* PCNT3_CH0SIG */ +#define PCNT3_CH0SIG_GPIO0 \ + ESP32_PINMUX(0, ESP_PCNT_SIG_CH0_IN3, ESP_NOSIG) + +#define PCNT3_CH0SIG_GPIO1 \ + ESP32_PINMUX(1, ESP_PCNT_SIG_CH0_IN3, ESP_NOSIG) + +#define PCNT3_CH0SIG_GPIO2 \ + ESP32_PINMUX(2, ESP_PCNT_SIG_CH0_IN3, ESP_NOSIG) + +#define PCNT3_CH0SIG_GPIO3 \ + ESP32_PINMUX(3, ESP_PCNT_SIG_CH0_IN3, ESP_NOSIG) + +#define PCNT3_CH0SIG_GPIO4 \ + ESP32_PINMUX(4, ESP_PCNT_SIG_CH0_IN3, ESP_NOSIG) + +#define PCNT3_CH0SIG_GPIO5 \ + ESP32_PINMUX(5, ESP_PCNT_SIG_CH0_IN3, ESP_NOSIG) + +#define PCNT3_CH0SIG_GPIO6 \ + ESP32_PINMUX(6, ESP_PCNT_SIG_CH0_IN3, ESP_NOSIG) + +#define PCNT3_CH0SIG_GPIO7 \ + ESP32_PINMUX(7, ESP_PCNT_SIG_CH0_IN3, ESP_NOSIG) + +#define PCNT3_CH0SIG_GPIO8 \ + ESP32_PINMUX(8, ESP_PCNT_SIG_CH0_IN3, ESP_NOSIG) + +#define PCNT3_CH0SIG_GPIO9 \ + ESP32_PINMUX(9, ESP_PCNT_SIG_CH0_IN3, ESP_NOSIG) + +#define PCNT3_CH0SIG_GPIO10 \ + ESP32_PINMUX(10, ESP_PCNT_SIG_CH0_IN3, ESP_NOSIG) + +#define PCNT3_CH0SIG_GPIO11 \ + ESP32_PINMUX(11, ESP_PCNT_SIG_CH0_IN3, ESP_NOSIG) + +#define PCNT3_CH0SIG_GPIO12 \ + ESP32_PINMUX(12, ESP_PCNT_SIG_CH0_IN3, ESP_NOSIG) + +#define PCNT3_CH0SIG_GPIO13 \ + ESP32_PINMUX(13, ESP_PCNT_SIG_CH0_IN3, ESP_NOSIG) + +#define PCNT3_CH0SIG_GPIO14 \ + ESP32_PINMUX(14, ESP_PCNT_SIG_CH0_IN3, ESP_NOSIG) + +#define PCNT3_CH0SIG_GPIO15 \ + ESP32_PINMUX(15, ESP_PCNT_SIG_CH0_IN3, ESP_NOSIG) + +#define PCNT3_CH0SIG_GPIO16 \ + ESP32_PINMUX(16, ESP_PCNT_SIG_CH0_IN3, ESP_NOSIG) + +#define PCNT3_CH0SIG_GPIO17 \ + ESP32_PINMUX(17, ESP_PCNT_SIG_CH0_IN3, ESP_NOSIG) + +#define PCNT3_CH0SIG_GPIO18 \ + ESP32_PINMUX(18, ESP_PCNT_SIG_CH0_IN3, ESP_NOSIG) + +#define PCNT3_CH0SIG_GPIO19 \ + ESP32_PINMUX(19, ESP_PCNT_SIG_CH0_IN3, ESP_NOSIG) + +#define PCNT3_CH0SIG_GPIO20 \ + ESP32_PINMUX(20, ESP_PCNT_SIG_CH0_IN3, ESP_NOSIG) + +#define PCNT3_CH0SIG_GPIO21 \ + ESP32_PINMUX(21, ESP_PCNT_SIG_CH0_IN3, ESP_NOSIG) + +#define PCNT3_CH0SIG_GPIO22 \ + ESP32_PINMUX(22, ESP_PCNT_SIG_CH0_IN3, ESP_NOSIG) + +#define PCNT3_CH0SIG_GPIO23 \ + ESP32_PINMUX(23, ESP_PCNT_SIG_CH0_IN3, ESP_NOSIG) + +#define PCNT3_CH0SIG_GPIO25 \ + ESP32_PINMUX(25, ESP_PCNT_SIG_CH0_IN3, ESP_NOSIG) + +#define PCNT3_CH0SIG_GPIO26 \ + ESP32_PINMUX(26, ESP_PCNT_SIG_CH0_IN3, ESP_NOSIG) + +#define PCNT3_CH0SIG_GPIO27 \ + ESP32_PINMUX(27, ESP_PCNT_SIG_CH0_IN3, ESP_NOSIG) + +#define PCNT3_CH0SIG_GPIO32 \ + ESP32_PINMUX(32, ESP_PCNT_SIG_CH0_IN3, ESP_NOSIG) + +#define PCNT3_CH0SIG_GPIO33 \ + ESP32_PINMUX(33, ESP_PCNT_SIG_CH0_IN3, ESP_NOSIG) + +#define PCNT3_CH0SIG_GPIO34 \ + ESP32_PINMUX(34, ESP_PCNT_SIG_CH0_IN3, ESP_NOSIG) + +#define PCNT3_CH0SIG_GPIO35 \ + ESP32_PINMUX(35, ESP_PCNT_SIG_CH0_IN3, ESP_NOSIG) + +#define PCNT3_CH0SIG_GPIO36 \ + ESP32_PINMUX(36, ESP_PCNT_SIG_CH0_IN3, ESP_NOSIG) + +#define PCNT3_CH0SIG_GPIO37 \ + ESP32_PINMUX(37, ESP_PCNT_SIG_CH0_IN3, ESP_NOSIG) + +#define PCNT3_CH0SIG_GPIO38 \ + ESP32_PINMUX(38, ESP_PCNT_SIG_CH0_IN3, ESP_NOSIG) + +#define PCNT3_CH0SIG_GPIO39 \ + ESP32_PINMUX(39, ESP_PCNT_SIG_CH0_IN3, ESP_NOSIG) + +/* PCNT3_CH1CTRL */ +#define PCNT3_CH1CTRL_GPIO0 \ + ESP32_PINMUX(0, ESP_PCNT_CTRL_CH1_IN3, ESP_NOSIG) + +#define PCNT3_CH1CTRL_GPIO1 \ + ESP32_PINMUX(1, ESP_PCNT_CTRL_CH1_IN3, ESP_NOSIG) + +#define PCNT3_CH1CTRL_GPIO2 \ + ESP32_PINMUX(2, ESP_PCNT_CTRL_CH1_IN3, ESP_NOSIG) + +#define PCNT3_CH1CTRL_GPIO3 \ + ESP32_PINMUX(3, ESP_PCNT_CTRL_CH1_IN3, ESP_NOSIG) + +#define PCNT3_CH1CTRL_GPIO4 \ + ESP32_PINMUX(4, ESP_PCNT_CTRL_CH1_IN3, ESP_NOSIG) + +#define PCNT3_CH1CTRL_GPIO5 \ + ESP32_PINMUX(5, ESP_PCNT_CTRL_CH1_IN3, ESP_NOSIG) + +#define PCNT3_CH1CTRL_GPIO6 \ + ESP32_PINMUX(6, ESP_PCNT_CTRL_CH1_IN3, ESP_NOSIG) + +#define PCNT3_CH1CTRL_GPIO7 \ + ESP32_PINMUX(7, ESP_PCNT_CTRL_CH1_IN3, ESP_NOSIG) + +#define PCNT3_CH1CTRL_GPIO8 \ + ESP32_PINMUX(8, ESP_PCNT_CTRL_CH1_IN3, ESP_NOSIG) + +#define PCNT3_CH1CTRL_GPIO9 \ + ESP32_PINMUX(9, ESP_PCNT_CTRL_CH1_IN3, ESP_NOSIG) + +#define PCNT3_CH1CTRL_GPIO10 \ + ESP32_PINMUX(10, ESP_PCNT_CTRL_CH1_IN3, ESP_NOSIG) + +#define PCNT3_CH1CTRL_GPIO11 \ + ESP32_PINMUX(11, ESP_PCNT_CTRL_CH1_IN3, ESP_NOSIG) + +#define PCNT3_CH1CTRL_GPIO12 \ + ESP32_PINMUX(12, ESP_PCNT_CTRL_CH1_IN3, ESP_NOSIG) + +#define PCNT3_CH1CTRL_GPIO13 \ + ESP32_PINMUX(13, ESP_PCNT_CTRL_CH1_IN3, ESP_NOSIG) + +#define PCNT3_CH1CTRL_GPIO14 \ + ESP32_PINMUX(14, ESP_PCNT_CTRL_CH1_IN3, ESP_NOSIG) + +#define PCNT3_CH1CTRL_GPIO15 \ + ESP32_PINMUX(15, ESP_PCNT_CTRL_CH1_IN3, ESP_NOSIG) + +#define PCNT3_CH1CTRL_GPIO16 \ + ESP32_PINMUX(16, ESP_PCNT_CTRL_CH1_IN3, ESP_NOSIG) + +#define PCNT3_CH1CTRL_GPIO17 \ + ESP32_PINMUX(17, ESP_PCNT_CTRL_CH1_IN3, ESP_NOSIG) + +#define PCNT3_CH1CTRL_GPIO18 \ + ESP32_PINMUX(18, ESP_PCNT_CTRL_CH1_IN3, ESP_NOSIG) + +#define PCNT3_CH1CTRL_GPIO19 \ + ESP32_PINMUX(19, ESP_PCNT_CTRL_CH1_IN3, ESP_NOSIG) + +#define PCNT3_CH1CTRL_GPIO20 \ + ESP32_PINMUX(20, ESP_PCNT_CTRL_CH1_IN3, ESP_NOSIG) + +#define PCNT3_CH1CTRL_GPIO21 \ + ESP32_PINMUX(21, ESP_PCNT_CTRL_CH1_IN3, ESP_NOSIG) + +#define PCNT3_CH1CTRL_GPIO22 \ + ESP32_PINMUX(22, ESP_PCNT_CTRL_CH1_IN3, ESP_NOSIG) + +#define PCNT3_CH1CTRL_GPIO23 \ + ESP32_PINMUX(23, ESP_PCNT_CTRL_CH1_IN3, ESP_NOSIG) + +#define PCNT3_CH1CTRL_GPIO25 \ + ESP32_PINMUX(25, ESP_PCNT_CTRL_CH1_IN3, ESP_NOSIG) + +#define PCNT3_CH1CTRL_GPIO26 \ + ESP32_PINMUX(26, ESP_PCNT_CTRL_CH1_IN3, ESP_NOSIG) + +#define PCNT3_CH1CTRL_GPIO27 \ + ESP32_PINMUX(27, ESP_PCNT_CTRL_CH1_IN3, ESP_NOSIG) + +#define PCNT3_CH1CTRL_GPIO32 \ + ESP32_PINMUX(32, ESP_PCNT_CTRL_CH1_IN3, ESP_NOSIG) + +#define PCNT3_CH1CTRL_GPIO33 \ + ESP32_PINMUX(33, ESP_PCNT_CTRL_CH1_IN3, ESP_NOSIG) + +#define PCNT3_CH1CTRL_GPIO34 \ + ESP32_PINMUX(34, ESP_PCNT_CTRL_CH1_IN3, ESP_NOSIG) + +#define PCNT3_CH1CTRL_GPIO35 \ + ESP32_PINMUX(35, ESP_PCNT_CTRL_CH1_IN3, ESP_NOSIG) + +#define PCNT3_CH1CTRL_GPIO36 \ + ESP32_PINMUX(36, ESP_PCNT_CTRL_CH1_IN3, ESP_NOSIG) + +#define PCNT3_CH1CTRL_GPIO37 \ + ESP32_PINMUX(37, ESP_PCNT_CTRL_CH1_IN3, ESP_NOSIG) + +#define PCNT3_CH1CTRL_GPIO38 \ + ESP32_PINMUX(38, ESP_PCNT_CTRL_CH1_IN3, ESP_NOSIG) + +#define PCNT3_CH1CTRL_GPIO39 \ + ESP32_PINMUX(39, ESP_PCNT_CTRL_CH1_IN3, ESP_NOSIG) + +/* PCNT3_CH1SIG */ +#define PCNT3_CH1SIG_GPIO0 \ + ESP32_PINMUX(0, ESP_PCNT_SIG_CH1_IN3, ESP_NOSIG) + +#define PCNT3_CH1SIG_GPIO1 \ + ESP32_PINMUX(1, ESP_PCNT_SIG_CH1_IN3, ESP_NOSIG) + +#define PCNT3_CH1SIG_GPIO2 \ + ESP32_PINMUX(2, ESP_PCNT_SIG_CH1_IN3, ESP_NOSIG) + +#define PCNT3_CH1SIG_GPIO3 \ + ESP32_PINMUX(3, ESP_PCNT_SIG_CH1_IN3, ESP_NOSIG) + +#define PCNT3_CH1SIG_GPIO4 \ + ESP32_PINMUX(4, ESP_PCNT_SIG_CH1_IN3, ESP_NOSIG) + +#define PCNT3_CH1SIG_GPIO5 \ + ESP32_PINMUX(5, ESP_PCNT_SIG_CH1_IN3, ESP_NOSIG) + +#define PCNT3_CH1SIG_GPIO6 \ + ESP32_PINMUX(6, ESP_PCNT_SIG_CH1_IN3, ESP_NOSIG) + +#define PCNT3_CH1SIG_GPIO7 \ + ESP32_PINMUX(7, ESP_PCNT_SIG_CH1_IN3, ESP_NOSIG) + +#define PCNT3_CH1SIG_GPIO8 \ + ESP32_PINMUX(8, ESP_PCNT_SIG_CH1_IN3, ESP_NOSIG) + +#define PCNT3_CH1SIG_GPIO9 \ + ESP32_PINMUX(9, ESP_PCNT_SIG_CH1_IN3, ESP_NOSIG) + +#define PCNT3_CH1SIG_GPIO10 \ + ESP32_PINMUX(10, ESP_PCNT_SIG_CH1_IN3, ESP_NOSIG) + +#define PCNT3_CH1SIG_GPIO11 \ + ESP32_PINMUX(11, ESP_PCNT_SIG_CH1_IN3, ESP_NOSIG) + +#define PCNT3_CH1SIG_GPIO12 \ + ESP32_PINMUX(12, ESP_PCNT_SIG_CH1_IN3, ESP_NOSIG) + +#define PCNT3_CH1SIG_GPIO13 \ + ESP32_PINMUX(13, ESP_PCNT_SIG_CH1_IN3, ESP_NOSIG) + +#define PCNT3_CH1SIG_GPIO14 \ + ESP32_PINMUX(14, ESP_PCNT_SIG_CH1_IN3, ESP_NOSIG) + +#define PCNT3_CH1SIG_GPIO15 \ + ESP32_PINMUX(15, ESP_PCNT_SIG_CH1_IN3, ESP_NOSIG) + +#define PCNT3_CH1SIG_GPIO16 \ + ESP32_PINMUX(16, ESP_PCNT_SIG_CH1_IN3, ESP_NOSIG) + +#define PCNT3_CH1SIG_GPIO17 \ + ESP32_PINMUX(17, ESP_PCNT_SIG_CH1_IN3, ESP_NOSIG) + +#define PCNT3_CH1SIG_GPIO18 \ + ESP32_PINMUX(18, ESP_PCNT_SIG_CH1_IN3, ESP_NOSIG) + +#define PCNT3_CH1SIG_GPIO19 \ + ESP32_PINMUX(19, ESP_PCNT_SIG_CH1_IN3, ESP_NOSIG) + +#define PCNT3_CH1SIG_GPIO20 \ + ESP32_PINMUX(20, ESP_PCNT_SIG_CH1_IN3, ESP_NOSIG) + +#define PCNT3_CH1SIG_GPIO21 \ + ESP32_PINMUX(21, ESP_PCNT_SIG_CH1_IN3, ESP_NOSIG) + +#define PCNT3_CH1SIG_GPIO22 \ + ESP32_PINMUX(22, ESP_PCNT_SIG_CH1_IN3, ESP_NOSIG) + +#define PCNT3_CH1SIG_GPIO23 \ + ESP32_PINMUX(23, ESP_PCNT_SIG_CH1_IN3, ESP_NOSIG) + +#define PCNT3_CH1SIG_GPIO25 \ + ESP32_PINMUX(25, ESP_PCNT_SIG_CH1_IN3, ESP_NOSIG) + +#define PCNT3_CH1SIG_GPIO26 \ + ESP32_PINMUX(26, ESP_PCNT_SIG_CH1_IN3, ESP_NOSIG) + +#define PCNT3_CH1SIG_GPIO27 \ + ESP32_PINMUX(27, ESP_PCNT_SIG_CH1_IN3, ESP_NOSIG) + +#define PCNT3_CH1SIG_GPIO32 \ + ESP32_PINMUX(32, ESP_PCNT_SIG_CH1_IN3, ESP_NOSIG) + +#define PCNT3_CH1SIG_GPIO33 \ + ESP32_PINMUX(33, ESP_PCNT_SIG_CH1_IN3, ESP_NOSIG) + +#define PCNT3_CH1SIG_GPIO34 \ + ESP32_PINMUX(34, ESP_PCNT_SIG_CH1_IN3, ESP_NOSIG) + +#define PCNT3_CH1SIG_GPIO35 \ + ESP32_PINMUX(35, ESP_PCNT_SIG_CH1_IN3, ESP_NOSIG) + +#define PCNT3_CH1SIG_GPIO36 \ + ESP32_PINMUX(36, ESP_PCNT_SIG_CH1_IN3, ESP_NOSIG) + +#define PCNT3_CH1SIG_GPIO37 \ + ESP32_PINMUX(37, ESP_PCNT_SIG_CH1_IN3, ESP_NOSIG) + +#define PCNT3_CH1SIG_GPIO38 \ + ESP32_PINMUX(38, ESP_PCNT_SIG_CH1_IN3, ESP_NOSIG) + +#define PCNT3_CH1SIG_GPIO39 \ + ESP32_PINMUX(39, ESP_PCNT_SIG_CH1_IN3, ESP_NOSIG) + +/* PCNT4_CH0CTRL */ +#define PCNT4_CH0CTRL_GPIO0 \ + ESP32_PINMUX(0, ESP_PCNT_CTRL_CH0_IN4, ESP_NOSIG) + +#define PCNT4_CH0CTRL_GPIO1 \ + ESP32_PINMUX(1, ESP_PCNT_CTRL_CH0_IN4, ESP_NOSIG) + +#define PCNT4_CH0CTRL_GPIO2 \ + ESP32_PINMUX(2, ESP_PCNT_CTRL_CH0_IN4, ESP_NOSIG) + +#define PCNT4_CH0CTRL_GPIO3 \ + ESP32_PINMUX(3, ESP_PCNT_CTRL_CH0_IN4, ESP_NOSIG) + +#define PCNT4_CH0CTRL_GPIO4 \ + ESP32_PINMUX(4, ESP_PCNT_CTRL_CH0_IN4, ESP_NOSIG) + +#define PCNT4_CH0CTRL_GPIO5 \ + ESP32_PINMUX(5, ESP_PCNT_CTRL_CH0_IN4, ESP_NOSIG) + +#define PCNT4_CH0CTRL_GPIO6 \ + ESP32_PINMUX(6, ESP_PCNT_CTRL_CH0_IN4, ESP_NOSIG) + +#define PCNT4_CH0CTRL_GPIO7 \ + ESP32_PINMUX(7, ESP_PCNT_CTRL_CH0_IN4, ESP_NOSIG) + +#define PCNT4_CH0CTRL_GPIO8 \ + ESP32_PINMUX(8, ESP_PCNT_CTRL_CH0_IN4, ESP_NOSIG) + +#define PCNT4_CH0CTRL_GPIO9 \ + ESP32_PINMUX(9, ESP_PCNT_CTRL_CH0_IN4, ESP_NOSIG) + +#define PCNT4_CH0CTRL_GPIO10 \ + ESP32_PINMUX(10, ESP_PCNT_CTRL_CH0_IN4, ESP_NOSIG) + +#define PCNT4_CH0CTRL_GPIO11 \ + ESP32_PINMUX(11, ESP_PCNT_CTRL_CH0_IN4, ESP_NOSIG) + +#define PCNT4_CH0CTRL_GPIO12 \ + ESP32_PINMUX(12, ESP_PCNT_CTRL_CH0_IN4, ESP_NOSIG) + +#define PCNT4_CH0CTRL_GPIO13 \ + ESP32_PINMUX(13, ESP_PCNT_CTRL_CH0_IN4, ESP_NOSIG) + +#define PCNT4_CH0CTRL_GPIO14 \ + ESP32_PINMUX(14, ESP_PCNT_CTRL_CH0_IN4, ESP_NOSIG) + +#define PCNT4_CH0CTRL_GPIO15 \ + ESP32_PINMUX(15, ESP_PCNT_CTRL_CH0_IN4, ESP_NOSIG) + +#define PCNT4_CH0CTRL_GPIO16 \ + ESP32_PINMUX(16, ESP_PCNT_CTRL_CH0_IN4, ESP_NOSIG) + +#define PCNT4_CH0CTRL_GPIO17 \ + ESP32_PINMUX(17, ESP_PCNT_CTRL_CH0_IN4, ESP_NOSIG) + +#define PCNT4_CH0CTRL_GPIO18 \ + ESP32_PINMUX(18, ESP_PCNT_CTRL_CH0_IN4, ESP_NOSIG) + +#define PCNT4_CH0CTRL_GPIO19 \ + ESP32_PINMUX(19, ESP_PCNT_CTRL_CH0_IN4, ESP_NOSIG) + +#define PCNT4_CH0CTRL_GPIO20 \ + ESP32_PINMUX(20, ESP_PCNT_CTRL_CH0_IN4, ESP_NOSIG) + +#define PCNT4_CH0CTRL_GPIO21 \ + ESP32_PINMUX(21, ESP_PCNT_CTRL_CH0_IN4, ESP_NOSIG) + +#define PCNT4_CH0CTRL_GPIO22 \ + ESP32_PINMUX(22, ESP_PCNT_CTRL_CH0_IN4, ESP_NOSIG) + +#define PCNT4_CH0CTRL_GPIO23 \ + ESP32_PINMUX(23, ESP_PCNT_CTRL_CH0_IN4, ESP_NOSIG) + +#define PCNT4_CH0CTRL_GPIO25 \ + ESP32_PINMUX(25, ESP_PCNT_CTRL_CH0_IN4, ESP_NOSIG) + +#define PCNT4_CH0CTRL_GPIO26 \ + ESP32_PINMUX(26, ESP_PCNT_CTRL_CH0_IN4, ESP_NOSIG) + +#define PCNT4_CH0CTRL_GPIO27 \ + ESP32_PINMUX(27, ESP_PCNT_CTRL_CH0_IN4, ESP_NOSIG) + +#define PCNT4_CH0CTRL_GPIO32 \ + ESP32_PINMUX(32, ESP_PCNT_CTRL_CH0_IN4, ESP_NOSIG) + +#define PCNT4_CH0CTRL_GPIO33 \ + ESP32_PINMUX(33, ESP_PCNT_CTRL_CH0_IN4, ESP_NOSIG) + +#define PCNT4_CH0CTRL_GPIO34 \ + ESP32_PINMUX(34, ESP_PCNT_CTRL_CH0_IN4, ESP_NOSIG) + +#define PCNT4_CH0CTRL_GPIO35 \ + ESP32_PINMUX(35, ESP_PCNT_CTRL_CH0_IN4, ESP_NOSIG) + +#define PCNT4_CH0CTRL_GPIO36 \ + ESP32_PINMUX(36, ESP_PCNT_CTRL_CH0_IN4, ESP_NOSIG) + +#define PCNT4_CH0CTRL_GPIO37 \ + ESP32_PINMUX(37, ESP_PCNT_CTRL_CH0_IN4, ESP_NOSIG) + +#define PCNT4_CH0CTRL_GPIO38 \ + ESP32_PINMUX(38, ESP_PCNT_CTRL_CH0_IN4, ESP_NOSIG) + +#define PCNT4_CH0CTRL_GPIO39 \ + ESP32_PINMUX(39, ESP_PCNT_CTRL_CH0_IN4, ESP_NOSIG) + +/* PCNT4_CH0SIG */ +#define PCNT4_CH0SIG_GPIO0 \ + ESP32_PINMUX(0, ESP_PCNT_SIG_CH0_IN4, ESP_NOSIG) + +#define PCNT4_CH0SIG_GPIO1 \ + ESP32_PINMUX(1, ESP_PCNT_SIG_CH0_IN4, ESP_NOSIG) + +#define PCNT4_CH0SIG_GPIO2 \ + ESP32_PINMUX(2, ESP_PCNT_SIG_CH0_IN4, ESP_NOSIG) + +#define PCNT4_CH0SIG_GPIO3 \ + ESP32_PINMUX(3, ESP_PCNT_SIG_CH0_IN4, ESP_NOSIG) + +#define PCNT4_CH0SIG_GPIO4 \ + ESP32_PINMUX(4, ESP_PCNT_SIG_CH0_IN4, ESP_NOSIG) + +#define PCNT4_CH0SIG_GPIO5 \ + ESP32_PINMUX(5, ESP_PCNT_SIG_CH0_IN4, ESP_NOSIG) + +#define PCNT4_CH0SIG_GPIO6 \ + ESP32_PINMUX(6, ESP_PCNT_SIG_CH0_IN4, ESP_NOSIG) + +#define PCNT4_CH0SIG_GPIO7 \ + ESP32_PINMUX(7, ESP_PCNT_SIG_CH0_IN4, ESP_NOSIG) + +#define PCNT4_CH0SIG_GPIO8 \ + ESP32_PINMUX(8, ESP_PCNT_SIG_CH0_IN4, ESP_NOSIG) + +#define PCNT4_CH0SIG_GPIO9 \ + ESP32_PINMUX(9, ESP_PCNT_SIG_CH0_IN4, ESP_NOSIG) + +#define PCNT4_CH0SIG_GPIO10 \ + ESP32_PINMUX(10, ESP_PCNT_SIG_CH0_IN4, ESP_NOSIG) + +#define PCNT4_CH0SIG_GPIO11 \ + ESP32_PINMUX(11, ESP_PCNT_SIG_CH0_IN4, ESP_NOSIG) + +#define PCNT4_CH0SIG_GPIO12 \ + ESP32_PINMUX(12, ESP_PCNT_SIG_CH0_IN4, ESP_NOSIG) + +#define PCNT4_CH0SIG_GPIO13 \ + ESP32_PINMUX(13, ESP_PCNT_SIG_CH0_IN4, ESP_NOSIG) + +#define PCNT4_CH0SIG_GPIO14 \ + ESP32_PINMUX(14, ESP_PCNT_SIG_CH0_IN4, ESP_NOSIG) + +#define PCNT4_CH0SIG_GPIO15 \ + ESP32_PINMUX(15, ESP_PCNT_SIG_CH0_IN4, ESP_NOSIG) + +#define PCNT4_CH0SIG_GPIO16 \ + ESP32_PINMUX(16, ESP_PCNT_SIG_CH0_IN4, ESP_NOSIG) + +#define PCNT4_CH0SIG_GPIO17 \ + ESP32_PINMUX(17, ESP_PCNT_SIG_CH0_IN4, ESP_NOSIG) + +#define PCNT4_CH0SIG_GPIO18 \ + ESP32_PINMUX(18, ESP_PCNT_SIG_CH0_IN4, ESP_NOSIG) + +#define PCNT4_CH0SIG_GPIO19 \ + ESP32_PINMUX(19, ESP_PCNT_SIG_CH0_IN4, ESP_NOSIG) + +#define PCNT4_CH0SIG_GPIO20 \ + ESP32_PINMUX(20, ESP_PCNT_SIG_CH0_IN4, ESP_NOSIG) + +#define PCNT4_CH0SIG_GPIO21 \ + ESP32_PINMUX(21, ESP_PCNT_SIG_CH0_IN4, ESP_NOSIG) + +#define PCNT4_CH0SIG_GPIO22 \ + ESP32_PINMUX(22, ESP_PCNT_SIG_CH0_IN4, ESP_NOSIG) + +#define PCNT4_CH0SIG_GPIO23 \ + ESP32_PINMUX(23, ESP_PCNT_SIG_CH0_IN4, ESP_NOSIG) + +#define PCNT4_CH0SIG_GPIO25 \ + ESP32_PINMUX(25, ESP_PCNT_SIG_CH0_IN4, ESP_NOSIG) + +#define PCNT4_CH0SIG_GPIO26 \ + ESP32_PINMUX(26, ESP_PCNT_SIG_CH0_IN4, ESP_NOSIG) + +#define PCNT4_CH0SIG_GPIO27 \ + ESP32_PINMUX(27, ESP_PCNT_SIG_CH0_IN4, ESP_NOSIG) + +#define PCNT4_CH0SIG_GPIO32 \ + ESP32_PINMUX(32, ESP_PCNT_SIG_CH0_IN4, ESP_NOSIG) + +#define PCNT4_CH0SIG_GPIO33 \ + ESP32_PINMUX(33, ESP_PCNT_SIG_CH0_IN4, ESP_NOSIG) + +#define PCNT4_CH0SIG_GPIO34 \ + ESP32_PINMUX(34, ESP_PCNT_SIG_CH0_IN4, ESP_NOSIG) + +#define PCNT4_CH0SIG_GPIO35 \ + ESP32_PINMUX(35, ESP_PCNT_SIG_CH0_IN4, ESP_NOSIG) + +#define PCNT4_CH0SIG_GPIO36 \ + ESP32_PINMUX(36, ESP_PCNT_SIG_CH0_IN4, ESP_NOSIG) + +#define PCNT4_CH0SIG_GPIO37 \ + ESP32_PINMUX(37, ESP_PCNT_SIG_CH0_IN4, ESP_NOSIG) + +#define PCNT4_CH0SIG_GPIO38 \ + ESP32_PINMUX(38, ESP_PCNT_SIG_CH0_IN4, ESP_NOSIG) + +#define PCNT4_CH0SIG_GPIO39 \ + ESP32_PINMUX(39, ESP_PCNT_SIG_CH0_IN4, ESP_NOSIG) + +/* PCNT4_CH1CTRL */ +#define PCNT4_CH1CTRL_GPIO0 \ + ESP32_PINMUX(0, ESP_PCNT_CTRL_CH1_IN4, ESP_NOSIG) + +#define PCNT4_CH1CTRL_GPIO1 \ + ESP32_PINMUX(1, ESP_PCNT_CTRL_CH1_IN4, ESP_NOSIG) + +#define PCNT4_CH1CTRL_GPIO2 \ + ESP32_PINMUX(2, ESP_PCNT_CTRL_CH1_IN4, ESP_NOSIG) + +#define PCNT4_CH1CTRL_GPIO3 \ + ESP32_PINMUX(3, ESP_PCNT_CTRL_CH1_IN4, ESP_NOSIG) + +#define PCNT4_CH1CTRL_GPIO4 \ + ESP32_PINMUX(4, ESP_PCNT_CTRL_CH1_IN4, ESP_NOSIG) + +#define PCNT4_CH1CTRL_GPIO5 \ + ESP32_PINMUX(5, ESP_PCNT_CTRL_CH1_IN4, ESP_NOSIG) + +#define PCNT4_CH1CTRL_GPIO6 \ + ESP32_PINMUX(6, ESP_PCNT_CTRL_CH1_IN4, ESP_NOSIG) + +#define PCNT4_CH1CTRL_GPIO7 \ + ESP32_PINMUX(7, ESP_PCNT_CTRL_CH1_IN4, ESP_NOSIG) + +#define PCNT4_CH1CTRL_GPIO8 \ + ESP32_PINMUX(8, ESP_PCNT_CTRL_CH1_IN4, ESP_NOSIG) + +#define PCNT4_CH1CTRL_GPIO9 \ + ESP32_PINMUX(9, ESP_PCNT_CTRL_CH1_IN4, ESP_NOSIG) + +#define PCNT4_CH1CTRL_GPIO10 \ + ESP32_PINMUX(10, ESP_PCNT_CTRL_CH1_IN4, ESP_NOSIG) + +#define PCNT4_CH1CTRL_GPIO11 \ + ESP32_PINMUX(11, ESP_PCNT_CTRL_CH1_IN4, ESP_NOSIG) + +#define PCNT4_CH1CTRL_GPIO12 \ + ESP32_PINMUX(12, ESP_PCNT_CTRL_CH1_IN4, ESP_NOSIG) + +#define PCNT4_CH1CTRL_GPIO13 \ + ESP32_PINMUX(13, ESP_PCNT_CTRL_CH1_IN4, ESP_NOSIG) + +#define PCNT4_CH1CTRL_GPIO14 \ + ESP32_PINMUX(14, ESP_PCNT_CTRL_CH1_IN4, ESP_NOSIG) + +#define PCNT4_CH1CTRL_GPIO15 \ + ESP32_PINMUX(15, ESP_PCNT_CTRL_CH1_IN4, ESP_NOSIG) + +#define PCNT4_CH1CTRL_GPIO16 \ + ESP32_PINMUX(16, ESP_PCNT_CTRL_CH1_IN4, ESP_NOSIG) + +#define PCNT4_CH1CTRL_GPIO17 \ + ESP32_PINMUX(17, ESP_PCNT_CTRL_CH1_IN4, ESP_NOSIG) + +#define PCNT4_CH1CTRL_GPIO18 \ + ESP32_PINMUX(18, ESP_PCNT_CTRL_CH1_IN4, ESP_NOSIG) + +#define PCNT4_CH1CTRL_GPIO19 \ + ESP32_PINMUX(19, ESP_PCNT_CTRL_CH1_IN4, ESP_NOSIG) + +#define PCNT4_CH1CTRL_GPIO20 \ + ESP32_PINMUX(20, ESP_PCNT_CTRL_CH1_IN4, ESP_NOSIG) + +#define PCNT4_CH1CTRL_GPIO21 \ + ESP32_PINMUX(21, ESP_PCNT_CTRL_CH1_IN4, ESP_NOSIG) + +#define PCNT4_CH1CTRL_GPIO22 \ + ESP32_PINMUX(22, ESP_PCNT_CTRL_CH1_IN4, ESP_NOSIG) + +#define PCNT4_CH1CTRL_GPIO23 \ + ESP32_PINMUX(23, ESP_PCNT_CTRL_CH1_IN4, ESP_NOSIG) + +#define PCNT4_CH1CTRL_GPIO25 \ + ESP32_PINMUX(25, ESP_PCNT_CTRL_CH1_IN4, ESP_NOSIG) + +#define PCNT4_CH1CTRL_GPIO26 \ + ESP32_PINMUX(26, ESP_PCNT_CTRL_CH1_IN4, ESP_NOSIG) + +#define PCNT4_CH1CTRL_GPIO27 \ + ESP32_PINMUX(27, ESP_PCNT_CTRL_CH1_IN4, ESP_NOSIG) + +#define PCNT4_CH1CTRL_GPIO32 \ + ESP32_PINMUX(32, ESP_PCNT_CTRL_CH1_IN4, ESP_NOSIG) + +#define PCNT4_CH1CTRL_GPIO33 \ + ESP32_PINMUX(33, ESP_PCNT_CTRL_CH1_IN4, ESP_NOSIG) + +#define PCNT4_CH1CTRL_GPIO34 \ + ESP32_PINMUX(34, ESP_PCNT_CTRL_CH1_IN4, ESP_NOSIG) + +#define PCNT4_CH1CTRL_GPIO35 \ + ESP32_PINMUX(35, ESP_PCNT_CTRL_CH1_IN4, ESP_NOSIG) + +#define PCNT4_CH1CTRL_GPIO36 \ + ESP32_PINMUX(36, ESP_PCNT_CTRL_CH1_IN4, ESP_NOSIG) + +#define PCNT4_CH1CTRL_GPIO37 \ + ESP32_PINMUX(37, ESP_PCNT_CTRL_CH1_IN4, ESP_NOSIG) + +#define PCNT4_CH1CTRL_GPIO38 \ + ESP32_PINMUX(38, ESP_PCNT_CTRL_CH1_IN4, ESP_NOSIG) + +#define PCNT4_CH1CTRL_GPIO39 \ + ESP32_PINMUX(39, ESP_PCNT_CTRL_CH1_IN4, ESP_NOSIG) + +/* PCNT4_CH1SIG */ +#define PCNT4_CH1SIG_GPIO0 \ + ESP32_PINMUX(0, ESP_PCNT_SIG_CH1_IN4, ESP_NOSIG) + +#define PCNT4_CH1SIG_GPIO1 \ + ESP32_PINMUX(1, ESP_PCNT_SIG_CH1_IN4, ESP_NOSIG) + +#define PCNT4_CH1SIG_GPIO2 \ + ESP32_PINMUX(2, ESP_PCNT_SIG_CH1_IN4, ESP_NOSIG) + +#define PCNT4_CH1SIG_GPIO3 \ + ESP32_PINMUX(3, ESP_PCNT_SIG_CH1_IN4, ESP_NOSIG) + +#define PCNT4_CH1SIG_GPIO4 \ + ESP32_PINMUX(4, ESP_PCNT_SIG_CH1_IN4, ESP_NOSIG) + +#define PCNT4_CH1SIG_GPIO5 \ + ESP32_PINMUX(5, ESP_PCNT_SIG_CH1_IN4, ESP_NOSIG) + +#define PCNT4_CH1SIG_GPIO6 \ + ESP32_PINMUX(6, ESP_PCNT_SIG_CH1_IN4, ESP_NOSIG) + +#define PCNT4_CH1SIG_GPIO7 \ + ESP32_PINMUX(7, ESP_PCNT_SIG_CH1_IN4, ESP_NOSIG) + +#define PCNT4_CH1SIG_GPIO8 \ + ESP32_PINMUX(8, ESP_PCNT_SIG_CH1_IN4, ESP_NOSIG) + +#define PCNT4_CH1SIG_GPIO9 \ + ESP32_PINMUX(9, ESP_PCNT_SIG_CH1_IN4, ESP_NOSIG) + +#define PCNT4_CH1SIG_GPIO10 \ + ESP32_PINMUX(10, ESP_PCNT_SIG_CH1_IN4, ESP_NOSIG) + +#define PCNT4_CH1SIG_GPIO11 \ + ESP32_PINMUX(11, ESP_PCNT_SIG_CH1_IN4, ESP_NOSIG) + +#define PCNT4_CH1SIG_GPIO12 \ + ESP32_PINMUX(12, ESP_PCNT_SIG_CH1_IN4, ESP_NOSIG) + +#define PCNT4_CH1SIG_GPIO13 \ + ESP32_PINMUX(13, ESP_PCNT_SIG_CH1_IN4, ESP_NOSIG) + +#define PCNT4_CH1SIG_GPIO14 \ + ESP32_PINMUX(14, ESP_PCNT_SIG_CH1_IN4, ESP_NOSIG) + +#define PCNT4_CH1SIG_GPIO15 \ + ESP32_PINMUX(15, ESP_PCNT_SIG_CH1_IN4, ESP_NOSIG) + +#define PCNT4_CH1SIG_GPIO16 \ + ESP32_PINMUX(16, ESP_PCNT_SIG_CH1_IN4, ESP_NOSIG) + +#define PCNT4_CH1SIG_GPIO17 \ + ESP32_PINMUX(17, ESP_PCNT_SIG_CH1_IN4, ESP_NOSIG) + +#define PCNT4_CH1SIG_GPIO18 \ + ESP32_PINMUX(18, ESP_PCNT_SIG_CH1_IN4, ESP_NOSIG) + +#define PCNT4_CH1SIG_GPIO19 \ + ESP32_PINMUX(19, ESP_PCNT_SIG_CH1_IN4, ESP_NOSIG) + +#define PCNT4_CH1SIG_GPIO20 \ + ESP32_PINMUX(20, ESP_PCNT_SIG_CH1_IN4, ESP_NOSIG) + +#define PCNT4_CH1SIG_GPIO21 \ + ESP32_PINMUX(21, ESP_PCNT_SIG_CH1_IN4, ESP_NOSIG) + +#define PCNT4_CH1SIG_GPIO22 \ + ESP32_PINMUX(22, ESP_PCNT_SIG_CH1_IN4, ESP_NOSIG) + +#define PCNT4_CH1SIG_GPIO23 \ + ESP32_PINMUX(23, ESP_PCNT_SIG_CH1_IN4, ESP_NOSIG) + +#define PCNT4_CH1SIG_GPIO25 \ + ESP32_PINMUX(25, ESP_PCNT_SIG_CH1_IN4, ESP_NOSIG) + +#define PCNT4_CH1SIG_GPIO26 \ + ESP32_PINMUX(26, ESP_PCNT_SIG_CH1_IN4, ESP_NOSIG) + +#define PCNT4_CH1SIG_GPIO27 \ + ESP32_PINMUX(27, ESP_PCNT_SIG_CH1_IN4, ESP_NOSIG) + +#define PCNT4_CH1SIG_GPIO32 \ + ESP32_PINMUX(32, ESP_PCNT_SIG_CH1_IN4, ESP_NOSIG) + +#define PCNT4_CH1SIG_GPIO33 \ + ESP32_PINMUX(33, ESP_PCNT_SIG_CH1_IN4, ESP_NOSIG) + +#define PCNT4_CH1SIG_GPIO34 \ + ESP32_PINMUX(34, ESP_PCNT_SIG_CH1_IN4, ESP_NOSIG) + +#define PCNT4_CH1SIG_GPIO35 \ + ESP32_PINMUX(35, ESP_PCNT_SIG_CH1_IN4, ESP_NOSIG) + +#define PCNT4_CH1SIG_GPIO36 \ + ESP32_PINMUX(36, ESP_PCNT_SIG_CH1_IN4, ESP_NOSIG) + +#define PCNT4_CH1SIG_GPIO37 \ + ESP32_PINMUX(37, ESP_PCNT_SIG_CH1_IN4, ESP_NOSIG) + +#define PCNT4_CH1SIG_GPIO38 \ + ESP32_PINMUX(38, ESP_PCNT_SIG_CH1_IN4, ESP_NOSIG) + +#define PCNT4_CH1SIG_GPIO39 \ + ESP32_PINMUX(39, ESP_PCNT_SIG_CH1_IN4, ESP_NOSIG) + +/* PCNT5_CH0CTRL */ +#define PCNT5_CH0CTRL_GPIO0 \ + ESP32_PINMUX(0, ESP_PCNT_CTRL_CH0_IN5, ESP_NOSIG) + +#define PCNT5_CH0CTRL_GPIO1 \ + ESP32_PINMUX(1, ESP_PCNT_CTRL_CH0_IN5, ESP_NOSIG) + +#define PCNT5_CH0CTRL_GPIO2 \ + ESP32_PINMUX(2, ESP_PCNT_CTRL_CH0_IN5, ESP_NOSIG) + +#define PCNT5_CH0CTRL_GPIO3 \ + ESP32_PINMUX(3, ESP_PCNT_CTRL_CH0_IN5, ESP_NOSIG) + +#define PCNT5_CH0CTRL_GPIO4 \ + ESP32_PINMUX(4, ESP_PCNT_CTRL_CH0_IN5, ESP_NOSIG) + +#define PCNT5_CH0CTRL_GPIO5 \ + ESP32_PINMUX(5, ESP_PCNT_CTRL_CH0_IN5, ESP_NOSIG) + +#define PCNT5_CH0CTRL_GPIO6 \ + ESP32_PINMUX(6, ESP_PCNT_CTRL_CH0_IN5, ESP_NOSIG) + +#define PCNT5_CH0CTRL_GPIO7 \ + ESP32_PINMUX(7, ESP_PCNT_CTRL_CH0_IN5, ESP_NOSIG) + +#define PCNT5_CH0CTRL_GPIO8 \ + ESP32_PINMUX(8, ESP_PCNT_CTRL_CH0_IN5, ESP_NOSIG) + +#define PCNT5_CH0CTRL_GPIO9 \ + ESP32_PINMUX(9, ESP_PCNT_CTRL_CH0_IN5, ESP_NOSIG) + +#define PCNT5_CH0CTRL_GPIO10 \ + ESP32_PINMUX(10, ESP_PCNT_CTRL_CH0_IN5, ESP_NOSIG) + +#define PCNT5_CH0CTRL_GPIO11 \ + ESP32_PINMUX(11, ESP_PCNT_CTRL_CH0_IN5, ESP_NOSIG) + +#define PCNT5_CH0CTRL_GPIO12 \ + ESP32_PINMUX(12, ESP_PCNT_CTRL_CH0_IN5, ESP_NOSIG) + +#define PCNT5_CH0CTRL_GPIO13 \ + ESP32_PINMUX(13, ESP_PCNT_CTRL_CH0_IN5, ESP_NOSIG) + +#define PCNT5_CH0CTRL_GPIO14 \ + ESP32_PINMUX(14, ESP_PCNT_CTRL_CH0_IN5, ESP_NOSIG) + +#define PCNT5_CH0CTRL_GPIO15 \ + ESP32_PINMUX(15, ESP_PCNT_CTRL_CH0_IN5, ESP_NOSIG) + +#define PCNT5_CH0CTRL_GPIO16 \ + ESP32_PINMUX(16, ESP_PCNT_CTRL_CH0_IN5, ESP_NOSIG) + +#define PCNT5_CH0CTRL_GPIO17 \ + ESP32_PINMUX(17, ESP_PCNT_CTRL_CH0_IN5, ESP_NOSIG) + +#define PCNT5_CH0CTRL_GPIO18 \ + ESP32_PINMUX(18, ESP_PCNT_CTRL_CH0_IN5, ESP_NOSIG) + +#define PCNT5_CH0CTRL_GPIO19 \ + ESP32_PINMUX(19, ESP_PCNT_CTRL_CH0_IN5, ESP_NOSIG) + +#define PCNT5_CH0CTRL_GPIO20 \ + ESP32_PINMUX(20, ESP_PCNT_CTRL_CH0_IN5, ESP_NOSIG) + +#define PCNT5_CH0CTRL_GPIO21 \ + ESP32_PINMUX(21, ESP_PCNT_CTRL_CH0_IN5, ESP_NOSIG) + +#define PCNT5_CH0CTRL_GPIO22 \ + ESP32_PINMUX(22, ESP_PCNT_CTRL_CH0_IN5, ESP_NOSIG) + +#define PCNT5_CH0CTRL_GPIO23 \ + ESP32_PINMUX(23, ESP_PCNT_CTRL_CH0_IN5, ESP_NOSIG) + +#define PCNT5_CH0CTRL_GPIO25 \ + ESP32_PINMUX(25, ESP_PCNT_CTRL_CH0_IN5, ESP_NOSIG) + +#define PCNT5_CH0CTRL_GPIO26 \ + ESP32_PINMUX(26, ESP_PCNT_CTRL_CH0_IN5, ESP_NOSIG) + +#define PCNT5_CH0CTRL_GPIO27 \ + ESP32_PINMUX(27, ESP_PCNT_CTRL_CH0_IN5, ESP_NOSIG) + +#define PCNT5_CH0CTRL_GPIO32 \ + ESP32_PINMUX(32, ESP_PCNT_CTRL_CH0_IN5, ESP_NOSIG) + +#define PCNT5_CH0CTRL_GPIO33 \ + ESP32_PINMUX(33, ESP_PCNT_CTRL_CH0_IN5, ESP_NOSIG) + +#define PCNT5_CH0CTRL_GPIO34 \ + ESP32_PINMUX(34, ESP_PCNT_CTRL_CH0_IN5, ESP_NOSIG) + +#define PCNT5_CH0CTRL_GPIO35 \ + ESP32_PINMUX(35, ESP_PCNT_CTRL_CH0_IN5, ESP_NOSIG) + +#define PCNT5_CH0CTRL_GPIO36 \ + ESP32_PINMUX(36, ESP_PCNT_CTRL_CH0_IN5, ESP_NOSIG) + +#define PCNT5_CH0CTRL_GPIO37 \ + ESP32_PINMUX(37, ESP_PCNT_CTRL_CH0_IN5, ESP_NOSIG) + +#define PCNT5_CH0CTRL_GPIO38 \ + ESP32_PINMUX(38, ESP_PCNT_CTRL_CH0_IN5, ESP_NOSIG) + +#define PCNT5_CH0CTRL_GPIO39 \ + ESP32_PINMUX(39, ESP_PCNT_CTRL_CH0_IN5, ESP_NOSIG) + +/* PCNT5_CH0SIG */ +#define PCNT5_CH0SIG_GPIO0 \ + ESP32_PINMUX(0, ESP_PCNT_SIG_CH0_IN5, ESP_NOSIG) + +#define PCNT5_CH0SIG_GPIO1 \ + ESP32_PINMUX(1, ESP_PCNT_SIG_CH0_IN5, ESP_NOSIG) + +#define PCNT5_CH0SIG_GPIO2 \ + ESP32_PINMUX(2, ESP_PCNT_SIG_CH0_IN5, ESP_NOSIG) + +#define PCNT5_CH0SIG_GPIO3 \ + ESP32_PINMUX(3, ESP_PCNT_SIG_CH0_IN5, ESP_NOSIG) + +#define PCNT5_CH0SIG_GPIO4 \ + ESP32_PINMUX(4, ESP_PCNT_SIG_CH0_IN5, ESP_NOSIG) + +#define PCNT5_CH0SIG_GPIO5 \ + ESP32_PINMUX(5, ESP_PCNT_SIG_CH0_IN5, ESP_NOSIG) + +#define PCNT5_CH0SIG_GPIO6 \ + ESP32_PINMUX(6, ESP_PCNT_SIG_CH0_IN5, ESP_NOSIG) + +#define PCNT5_CH0SIG_GPIO7 \ + ESP32_PINMUX(7, ESP_PCNT_SIG_CH0_IN5, ESP_NOSIG) + +#define PCNT5_CH0SIG_GPIO8 \ + ESP32_PINMUX(8, ESP_PCNT_SIG_CH0_IN5, ESP_NOSIG) + +#define PCNT5_CH0SIG_GPIO9 \ + ESP32_PINMUX(9, ESP_PCNT_SIG_CH0_IN5, ESP_NOSIG) + +#define PCNT5_CH0SIG_GPIO10 \ + ESP32_PINMUX(10, ESP_PCNT_SIG_CH0_IN5, ESP_NOSIG) + +#define PCNT5_CH0SIG_GPIO11 \ + ESP32_PINMUX(11, ESP_PCNT_SIG_CH0_IN5, ESP_NOSIG) + +#define PCNT5_CH0SIG_GPIO12 \ + ESP32_PINMUX(12, ESP_PCNT_SIG_CH0_IN5, ESP_NOSIG) + +#define PCNT5_CH0SIG_GPIO13 \ + ESP32_PINMUX(13, ESP_PCNT_SIG_CH0_IN5, ESP_NOSIG) + +#define PCNT5_CH0SIG_GPIO14 \ + ESP32_PINMUX(14, ESP_PCNT_SIG_CH0_IN5, ESP_NOSIG) + +#define PCNT5_CH0SIG_GPIO15 \ + ESP32_PINMUX(15, ESP_PCNT_SIG_CH0_IN5, ESP_NOSIG) + +#define PCNT5_CH0SIG_GPIO16 \ + ESP32_PINMUX(16, ESP_PCNT_SIG_CH0_IN5, ESP_NOSIG) + +#define PCNT5_CH0SIG_GPIO17 \ + ESP32_PINMUX(17, ESP_PCNT_SIG_CH0_IN5, ESP_NOSIG) + +#define PCNT5_CH0SIG_GPIO18 \ + ESP32_PINMUX(18, ESP_PCNT_SIG_CH0_IN5, ESP_NOSIG) + +#define PCNT5_CH0SIG_GPIO19 \ + ESP32_PINMUX(19, ESP_PCNT_SIG_CH0_IN5, ESP_NOSIG) + +#define PCNT5_CH0SIG_GPIO20 \ + ESP32_PINMUX(20, ESP_PCNT_SIG_CH0_IN5, ESP_NOSIG) + +#define PCNT5_CH0SIG_GPIO21 \ + ESP32_PINMUX(21, ESP_PCNT_SIG_CH0_IN5, ESP_NOSIG) + +#define PCNT5_CH0SIG_GPIO22 \ + ESP32_PINMUX(22, ESP_PCNT_SIG_CH0_IN5, ESP_NOSIG) + +#define PCNT5_CH0SIG_GPIO23 \ + ESP32_PINMUX(23, ESP_PCNT_SIG_CH0_IN5, ESP_NOSIG) + +#define PCNT5_CH0SIG_GPIO25 \ + ESP32_PINMUX(25, ESP_PCNT_SIG_CH0_IN5, ESP_NOSIG) + +#define PCNT5_CH0SIG_GPIO26 \ + ESP32_PINMUX(26, ESP_PCNT_SIG_CH0_IN5, ESP_NOSIG) + +#define PCNT5_CH0SIG_GPIO27 \ + ESP32_PINMUX(27, ESP_PCNT_SIG_CH0_IN5, ESP_NOSIG) + +#define PCNT5_CH0SIG_GPIO32 \ + ESP32_PINMUX(32, ESP_PCNT_SIG_CH0_IN5, ESP_NOSIG) + +#define PCNT5_CH0SIG_GPIO33 \ + ESP32_PINMUX(33, ESP_PCNT_SIG_CH0_IN5, ESP_NOSIG) + +#define PCNT5_CH0SIG_GPIO34 \ + ESP32_PINMUX(34, ESP_PCNT_SIG_CH0_IN5, ESP_NOSIG) + +#define PCNT5_CH0SIG_GPIO35 \ + ESP32_PINMUX(35, ESP_PCNT_SIG_CH0_IN5, ESP_NOSIG) + +#define PCNT5_CH0SIG_GPIO36 \ + ESP32_PINMUX(36, ESP_PCNT_SIG_CH0_IN5, ESP_NOSIG) + +#define PCNT5_CH0SIG_GPIO37 \ + ESP32_PINMUX(37, ESP_PCNT_SIG_CH0_IN5, ESP_NOSIG) + +#define PCNT5_CH0SIG_GPIO38 \ + ESP32_PINMUX(38, ESP_PCNT_SIG_CH0_IN5, ESP_NOSIG) + +#define PCNT5_CH0SIG_GPIO39 \ + ESP32_PINMUX(39, ESP_PCNT_SIG_CH0_IN5, ESP_NOSIG) + +/* PCNT5_CH1CTRL */ +#define PCNT5_CH1CTRL_GPIO0 \ + ESP32_PINMUX(0, ESP_PCNT_CTRL_CH1_IN5, ESP_NOSIG) + +#define PCNT5_CH1CTRL_GPIO1 \ + ESP32_PINMUX(1, ESP_PCNT_CTRL_CH1_IN5, ESP_NOSIG) + +#define PCNT5_CH1CTRL_GPIO2 \ + ESP32_PINMUX(2, ESP_PCNT_CTRL_CH1_IN5, ESP_NOSIG) + +#define PCNT5_CH1CTRL_GPIO3 \ + ESP32_PINMUX(3, ESP_PCNT_CTRL_CH1_IN5, ESP_NOSIG) + +#define PCNT5_CH1CTRL_GPIO4 \ + ESP32_PINMUX(4, ESP_PCNT_CTRL_CH1_IN5, ESP_NOSIG) + +#define PCNT5_CH1CTRL_GPIO5 \ + ESP32_PINMUX(5, ESP_PCNT_CTRL_CH1_IN5, ESP_NOSIG) + +#define PCNT5_CH1CTRL_GPIO6 \ + ESP32_PINMUX(6, ESP_PCNT_CTRL_CH1_IN5, ESP_NOSIG) + +#define PCNT5_CH1CTRL_GPIO7 \ + ESP32_PINMUX(7, ESP_PCNT_CTRL_CH1_IN5, ESP_NOSIG) + +#define PCNT5_CH1CTRL_GPIO8 \ + ESP32_PINMUX(8, ESP_PCNT_CTRL_CH1_IN5, ESP_NOSIG) + +#define PCNT5_CH1CTRL_GPIO9 \ + ESP32_PINMUX(9, ESP_PCNT_CTRL_CH1_IN5, ESP_NOSIG) + +#define PCNT5_CH1CTRL_GPIO10 \ + ESP32_PINMUX(10, ESP_PCNT_CTRL_CH1_IN5, ESP_NOSIG) + +#define PCNT5_CH1CTRL_GPIO11 \ + ESP32_PINMUX(11, ESP_PCNT_CTRL_CH1_IN5, ESP_NOSIG) + +#define PCNT5_CH1CTRL_GPIO12 \ + ESP32_PINMUX(12, ESP_PCNT_CTRL_CH1_IN5, ESP_NOSIG) + +#define PCNT5_CH1CTRL_GPIO13 \ + ESP32_PINMUX(13, ESP_PCNT_CTRL_CH1_IN5, ESP_NOSIG) + +#define PCNT5_CH1CTRL_GPIO14 \ + ESP32_PINMUX(14, ESP_PCNT_CTRL_CH1_IN5, ESP_NOSIG) + +#define PCNT5_CH1CTRL_GPIO15 \ + ESP32_PINMUX(15, ESP_PCNT_CTRL_CH1_IN5, ESP_NOSIG) + +#define PCNT5_CH1CTRL_GPIO16 \ + ESP32_PINMUX(16, ESP_PCNT_CTRL_CH1_IN5, ESP_NOSIG) + +#define PCNT5_CH1CTRL_GPIO17 \ + ESP32_PINMUX(17, ESP_PCNT_CTRL_CH1_IN5, ESP_NOSIG) + +#define PCNT5_CH1CTRL_GPIO18 \ + ESP32_PINMUX(18, ESP_PCNT_CTRL_CH1_IN5, ESP_NOSIG) + +#define PCNT5_CH1CTRL_GPIO19 \ + ESP32_PINMUX(19, ESP_PCNT_CTRL_CH1_IN5, ESP_NOSIG) + +#define PCNT5_CH1CTRL_GPIO20 \ + ESP32_PINMUX(20, ESP_PCNT_CTRL_CH1_IN5, ESP_NOSIG) + +#define PCNT5_CH1CTRL_GPIO21 \ + ESP32_PINMUX(21, ESP_PCNT_CTRL_CH1_IN5, ESP_NOSIG) + +#define PCNT5_CH1CTRL_GPIO22 \ + ESP32_PINMUX(22, ESP_PCNT_CTRL_CH1_IN5, ESP_NOSIG) + +#define PCNT5_CH1CTRL_GPIO23 \ + ESP32_PINMUX(23, ESP_PCNT_CTRL_CH1_IN5, ESP_NOSIG) + +#define PCNT5_CH1CTRL_GPIO25 \ + ESP32_PINMUX(25, ESP_PCNT_CTRL_CH1_IN5, ESP_NOSIG) + +#define PCNT5_CH1CTRL_GPIO26 \ + ESP32_PINMUX(26, ESP_PCNT_CTRL_CH1_IN5, ESP_NOSIG) + +#define PCNT5_CH1CTRL_GPIO27 \ + ESP32_PINMUX(27, ESP_PCNT_CTRL_CH1_IN5, ESP_NOSIG) + +#define PCNT5_CH1CTRL_GPIO32 \ + ESP32_PINMUX(32, ESP_PCNT_CTRL_CH1_IN5, ESP_NOSIG) + +#define PCNT5_CH1CTRL_GPIO33 \ + ESP32_PINMUX(33, ESP_PCNT_CTRL_CH1_IN5, ESP_NOSIG) + +#define PCNT5_CH1CTRL_GPIO34 \ + ESP32_PINMUX(34, ESP_PCNT_CTRL_CH1_IN5, ESP_NOSIG) + +#define PCNT5_CH1CTRL_GPIO35 \ + ESP32_PINMUX(35, ESP_PCNT_CTRL_CH1_IN5, ESP_NOSIG) + +#define PCNT5_CH1CTRL_GPIO36 \ + ESP32_PINMUX(36, ESP_PCNT_CTRL_CH1_IN5, ESP_NOSIG) + +#define PCNT5_CH1CTRL_GPIO37 \ + ESP32_PINMUX(37, ESP_PCNT_CTRL_CH1_IN5, ESP_NOSIG) + +#define PCNT5_CH1CTRL_GPIO38 \ + ESP32_PINMUX(38, ESP_PCNT_CTRL_CH1_IN5, ESP_NOSIG) + +#define PCNT5_CH1CTRL_GPIO39 \ + ESP32_PINMUX(39, ESP_PCNT_CTRL_CH1_IN5, ESP_NOSIG) + +/* PCNT5_CH1SIG */ +#define PCNT5_CH1SIG_GPIO0 \ + ESP32_PINMUX(0, ESP_PCNT_SIG_CH1_IN5, ESP_NOSIG) + +#define PCNT5_CH1SIG_GPIO1 \ + ESP32_PINMUX(1, ESP_PCNT_SIG_CH1_IN5, ESP_NOSIG) + +#define PCNT5_CH1SIG_GPIO2 \ + ESP32_PINMUX(2, ESP_PCNT_SIG_CH1_IN5, ESP_NOSIG) + +#define PCNT5_CH1SIG_GPIO3 \ + ESP32_PINMUX(3, ESP_PCNT_SIG_CH1_IN5, ESP_NOSIG) + +#define PCNT5_CH1SIG_GPIO4 \ + ESP32_PINMUX(4, ESP_PCNT_SIG_CH1_IN5, ESP_NOSIG) + +#define PCNT5_CH1SIG_GPIO5 \ + ESP32_PINMUX(5, ESP_PCNT_SIG_CH1_IN5, ESP_NOSIG) + +#define PCNT5_CH1SIG_GPIO6 \ + ESP32_PINMUX(6, ESP_PCNT_SIG_CH1_IN5, ESP_NOSIG) + +#define PCNT5_CH1SIG_GPIO7 \ + ESP32_PINMUX(7, ESP_PCNT_SIG_CH1_IN5, ESP_NOSIG) + +#define PCNT5_CH1SIG_GPIO8 \ + ESP32_PINMUX(8, ESP_PCNT_SIG_CH1_IN5, ESP_NOSIG) + +#define PCNT5_CH1SIG_GPIO9 \ + ESP32_PINMUX(9, ESP_PCNT_SIG_CH1_IN5, ESP_NOSIG) + +#define PCNT5_CH1SIG_GPIO10 \ + ESP32_PINMUX(10, ESP_PCNT_SIG_CH1_IN5, ESP_NOSIG) + +#define PCNT5_CH1SIG_GPIO11 \ + ESP32_PINMUX(11, ESP_PCNT_SIG_CH1_IN5, ESP_NOSIG) + +#define PCNT5_CH1SIG_GPIO12 \ + ESP32_PINMUX(12, ESP_PCNT_SIG_CH1_IN5, ESP_NOSIG) + +#define PCNT5_CH1SIG_GPIO13 \ + ESP32_PINMUX(13, ESP_PCNT_SIG_CH1_IN5, ESP_NOSIG) + +#define PCNT5_CH1SIG_GPIO14 \ + ESP32_PINMUX(14, ESP_PCNT_SIG_CH1_IN5, ESP_NOSIG) + +#define PCNT5_CH1SIG_GPIO15 \ + ESP32_PINMUX(15, ESP_PCNT_SIG_CH1_IN5, ESP_NOSIG) + +#define PCNT5_CH1SIG_GPIO16 \ + ESP32_PINMUX(16, ESP_PCNT_SIG_CH1_IN5, ESP_NOSIG) + +#define PCNT5_CH1SIG_GPIO17 \ + ESP32_PINMUX(17, ESP_PCNT_SIG_CH1_IN5, ESP_NOSIG) + +#define PCNT5_CH1SIG_GPIO18 \ + ESP32_PINMUX(18, ESP_PCNT_SIG_CH1_IN5, ESP_NOSIG) + +#define PCNT5_CH1SIG_GPIO19 \ + ESP32_PINMUX(19, ESP_PCNT_SIG_CH1_IN5, ESP_NOSIG) + +#define PCNT5_CH1SIG_GPIO20 \ + ESP32_PINMUX(20, ESP_PCNT_SIG_CH1_IN5, ESP_NOSIG) + +#define PCNT5_CH1SIG_GPIO21 \ + ESP32_PINMUX(21, ESP_PCNT_SIG_CH1_IN5, ESP_NOSIG) + +#define PCNT5_CH1SIG_GPIO22 \ + ESP32_PINMUX(22, ESP_PCNT_SIG_CH1_IN5, ESP_NOSIG) + +#define PCNT5_CH1SIG_GPIO23 \ + ESP32_PINMUX(23, ESP_PCNT_SIG_CH1_IN5, ESP_NOSIG) + +#define PCNT5_CH1SIG_GPIO25 \ + ESP32_PINMUX(25, ESP_PCNT_SIG_CH1_IN5, ESP_NOSIG) + +#define PCNT5_CH1SIG_GPIO26 \ + ESP32_PINMUX(26, ESP_PCNT_SIG_CH1_IN5, ESP_NOSIG) + +#define PCNT5_CH1SIG_GPIO27 \ + ESP32_PINMUX(27, ESP_PCNT_SIG_CH1_IN5, ESP_NOSIG) + +#define PCNT5_CH1SIG_GPIO32 \ + ESP32_PINMUX(32, ESP_PCNT_SIG_CH1_IN5, ESP_NOSIG) + +#define PCNT5_CH1SIG_GPIO33 \ + ESP32_PINMUX(33, ESP_PCNT_SIG_CH1_IN5, ESP_NOSIG) + +#define PCNT5_CH1SIG_GPIO34 \ + ESP32_PINMUX(34, ESP_PCNT_SIG_CH1_IN5, ESP_NOSIG) + +#define PCNT5_CH1SIG_GPIO35 \ + ESP32_PINMUX(35, ESP_PCNT_SIG_CH1_IN5, ESP_NOSIG) + +#define PCNT5_CH1SIG_GPIO36 \ + ESP32_PINMUX(36, ESP_PCNT_SIG_CH1_IN5, ESP_NOSIG) + +#define PCNT5_CH1SIG_GPIO37 \ + ESP32_PINMUX(37, ESP_PCNT_SIG_CH1_IN5, ESP_NOSIG) + +#define PCNT5_CH1SIG_GPIO38 \ + ESP32_PINMUX(38, ESP_PCNT_SIG_CH1_IN5, ESP_NOSIG) + +#define PCNT5_CH1SIG_GPIO39 \ + ESP32_PINMUX(39, ESP_PCNT_SIG_CH1_IN5, ESP_NOSIG) + +/* PCNT6_CH0CTRL */ +#define PCNT6_CH0CTRL_GPIO0 \ + ESP32_PINMUX(0, ESP_PCNT_CTRL_CH0_IN6, ESP_NOSIG) + +#define PCNT6_CH0CTRL_GPIO1 \ + ESP32_PINMUX(1, ESP_PCNT_CTRL_CH0_IN6, ESP_NOSIG) + +#define PCNT6_CH0CTRL_GPIO2 \ + ESP32_PINMUX(2, ESP_PCNT_CTRL_CH0_IN6, ESP_NOSIG) + +#define PCNT6_CH0CTRL_GPIO3 \ + ESP32_PINMUX(3, ESP_PCNT_CTRL_CH0_IN6, ESP_NOSIG) + +#define PCNT6_CH0CTRL_GPIO4 \ + ESP32_PINMUX(4, ESP_PCNT_CTRL_CH0_IN6, ESP_NOSIG) + +#define PCNT6_CH0CTRL_GPIO5 \ + ESP32_PINMUX(5, ESP_PCNT_CTRL_CH0_IN6, ESP_NOSIG) + +#define PCNT6_CH0CTRL_GPIO6 \ + ESP32_PINMUX(6, ESP_PCNT_CTRL_CH0_IN6, ESP_NOSIG) + +#define PCNT6_CH0CTRL_GPIO7 \ + ESP32_PINMUX(7, ESP_PCNT_CTRL_CH0_IN6, ESP_NOSIG) + +#define PCNT6_CH0CTRL_GPIO8 \ + ESP32_PINMUX(8, ESP_PCNT_CTRL_CH0_IN6, ESP_NOSIG) + +#define PCNT6_CH0CTRL_GPIO9 \ + ESP32_PINMUX(9, ESP_PCNT_CTRL_CH0_IN6, ESP_NOSIG) + +#define PCNT6_CH0CTRL_GPIO10 \ + ESP32_PINMUX(10, ESP_PCNT_CTRL_CH0_IN6, ESP_NOSIG) + +#define PCNT6_CH0CTRL_GPIO11 \ + ESP32_PINMUX(11, ESP_PCNT_CTRL_CH0_IN6, ESP_NOSIG) + +#define PCNT6_CH0CTRL_GPIO12 \ + ESP32_PINMUX(12, ESP_PCNT_CTRL_CH0_IN6, ESP_NOSIG) + +#define PCNT6_CH0CTRL_GPIO13 \ + ESP32_PINMUX(13, ESP_PCNT_CTRL_CH0_IN6, ESP_NOSIG) + +#define PCNT6_CH0CTRL_GPIO14 \ + ESP32_PINMUX(14, ESP_PCNT_CTRL_CH0_IN6, ESP_NOSIG) + +#define PCNT6_CH0CTRL_GPIO15 \ + ESP32_PINMUX(15, ESP_PCNT_CTRL_CH0_IN6, ESP_NOSIG) + +#define PCNT6_CH0CTRL_GPIO16 \ + ESP32_PINMUX(16, ESP_PCNT_CTRL_CH0_IN6, ESP_NOSIG) + +#define PCNT6_CH0CTRL_GPIO17 \ + ESP32_PINMUX(17, ESP_PCNT_CTRL_CH0_IN6, ESP_NOSIG) + +#define PCNT6_CH0CTRL_GPIO18 \ + ESP32_PINMUX(18, ESP_PCNT_CTRL_CH0_IN6, ESP_NOSIG) + +#define PCNT6_CH0CTRL_GPIO19 \ + ESP32_PINMUX(19, ESP_PCNT_CTRL_CH0_IN6, ESP_NOSIG) + +#define PCNT6_CH0CTRL_GPIO20 \ + ESP32_PINMUX(20, ESP_PCNT_CTRL_CH0_IN6, ESP_NOSIG) + +#define PCNT6_CH0CTRL_GPIO21 \ + ESP32_PINMUX(21, ESP_PCNT_CTRL_CH0_IN6, ESP_NOSIG) + +#define PCNT6_CH0CTRL_GPIO22 \ + ESP32_PINMUX(22, ESP_PCNT_CTRL_CH0_IN6, ESP_NOSIG) + +#define PCNT6_CH0CTRL_GPIO23 \ + ESP32_PINMUX(23, ESP_PCNT_CTRL_CH0_IN6, ESP_NOSIG) + +#define PCNT6_CH0CTRL_GPIO25 \ + ESP32_PINMUX(25, ESP_PCNT_CTRL_CH0_IN6, ESP_NOSIG) + +#define PCNT6_CH0CTRL_GPIO26 \ + ESP32_PINMUX(26, ESP_PCNT_CTRL_CH0_IN6, ESP_NOSIG) + +#define PCNT6_CH0CTRL_GPIO27 \ + ESP32_PINMUX(27, ESP_PCNT_CTRL_CH0_IN6, ESP_NOSIG) + +#define PCNT6_CH0CTRL_GPIO32 \ + ESP32_PINMUX(32, ESP_PCNT_CTRL_CH0_IN6, ESP_NOSIG) + +#define PCNT6_CH0CTRL_GPIO33 \ + ESP32_PINMUX(33, ESP_PCNT_CTRL_CH0_IN6, ESP_NOSIG) + +#define PCNT6_CH0CTRL_GPIO34 \ + ESP32_PINMUX(34, ESP_PCNT_CTRL_CH0_IN6, ESP_NOSIG) + +#define PCNT6_CH0CTRL_GPIO35 \ + ESP32_PINMUX(35, ESP_PCNT_CTRL_CH0_IN6, ESP_NOSIG) + +#define PCNT6_CH0CTRL_GPIO36 \ + ESP32_PINMUX(36, ESP_PCNT_CTRL_CH0_IN6, ESP_NOSIG) + +#define PCNT6_CH0CTRL_GPIO37 \ + ESP32_PINMUX(37, ESP_PCNT_CTRL_CH0_IN6, ESP_NOSIG) + +#define PCNT6_CH0CTRL_GPIO38 \ + ESP32_PINMUX(38, ESP_PCNT_CTRL_CH0_IN6, ESP_NOSIG) + +#define PCNT6_CH0CTRL_GPIO39 \ + ESP32_PINMUX(39, ESP_PCNT_CTRL_CH0_IN6, ESP_NOSIG) + +/* PCNT6_CH0SIG */ +#define PCNT6_CH0SIG_GPIO0 \ + ESP32_PINMUX(0, ESP_PCNT_SIG_CH0_IN6, ESP_NOSIG) + +#define PCNT6_CH0SIG_GPIO1 \ + ESP32_PINMUX(1, ESP_PCNT_SIG_CH0_IN6, ESP_NOSIG) + +#define PCNT6_CH0SIG_GPIO2 \ + ESP32_PINMUX(2, ESP_PCNT_SIG_CH0_IN6, ESP_NOSIG) + +#define PCNT6_CH0SIG_GPIO3 \ + ESP32_PINMUX(3, ESP_PCNT_SIG_CH0_IN6, ESP_NOSIG) + +#define PCNT6_CH0SIG_GPIO4 \ + ESP32_PINMUX(4, ESP_PCNT_SIG_CH0_IN6, ESP_NOSIG) + +#define PCNT6_CH0SIG_GPIO5 \ + ESP32_PINMUX(5, ESP_PCNT_SIG_CH0_IN6, ESP_NOSIG) + +#define PCNT6_CH0SIG_GPIO6 \ + ESP32_PINMUX(6, ESP_PCNT_SIG_CH0_IN6, ESP_NOSIG) + +#define PCNT6_CH0SIG_GPIO7 \ + ESP32_PINMUX(7, ESP_PCNT_SIG_CH0_IN6, ESP_NOSIG) + +#define PCNT6_CH0SIG_GPIO8 \ + ESP32_PINMUX(8, ESP_PCNT_SIG_CH0_IN6, ESP_NOSIG) + +#define PCNT6_CH0SIG_GPIO9 \ + ESP32_PINMUX(9, ESP_PCNT_SIG_CH0_IN6, ESP_NOSIG) + +#define PCNT6_CH0SIG_GPIO10 \ + ESP32_PINMUX(10, ESP_PCNT_SIG_CH0_IN6, ESP_NOSIG) + +#define PCNT6_CH0SIG_GPIO11 \ + ESP32_PINMUX(11, ESP_PCNT_SIG_CH0_IN6, ESP_NOSIG) + +#define PCNT6_CH0SIG_GPIO12 \ + ESP32_PINMUX(12, ESP_PCNT_SIG_CH0_IN6, ESP_NOSIG) + +#define PCNT6_CH0SIG_GPIO13 \ + ESP32_PINMUX(13, ESP_PCNT_SIG_CH0_IN6, ESP_NOSIG) + +#define PCNT6_CH0SIG_GPIO14 \ + ESP32_PINMUX(14, ESP_PCNT_SIG_CH0_IN6, ESP_NOSIG) + +#define PCNT6_CH0SIG_GPIO15 \ + ESP32_PINMUX(15, ESP_PCNT_SIG_CH0_IN6, ESP_NOSIG) + +#define PCNT6_CH0SIG_GPIO16 \ + ESP32_PINMUX(16, ESP_PCNT_SIG_CH0_IN6, ESP_NOSIG) + +#define PCNT6_CH0SIG_GPIO17 \ + ESP32_PINMUX(17, ESP_PCNT_SIG_CH0_IN6, ESP_NOSIG) + +#define PCNT6_CH0SIG_GPIO18 \ + ESP32_PINMUX(18, ESP_PCNT_SIG_CH0_IN6, ESP_NOSIG) + +#define PCNT6_CH0SIG_GPIO19 \ + ESP32_PINMUX(19, ESP_PCNT_SIG_CH0_IN6, ESP_NOSIG) + +#define PCNT6_CH0SIG_GPIO20 \ + ESP32_PINMUX(20, ESP_PCNT_SIG_CH0_IN6, ESP_NOSIG) + +#define PCNT6_CH0SIG_GPIO21 \ + ESP32_PINMUX(21, ESP_PCNT_SIG_CH0_IN6, ESP_NOSIG) + +#define PCNT6_CH0SIG_GPIO22 \ + ESP32_PINMUX(22, ESP_PCNT_SIG_CH0_IN6, ESP_NOSIG) + +#define PCNT6_CH0SIG_GPIO23 \ + ESP32_PINMUX(23, ESP_PCNT_SIG_CH0_IN6, ESP_NOSIG) + +#define PCNT6_CH0SIG_GPIO25 \ + ESP32_PINMUX(25, ESP_PCNT_SIG_CH0_IN6, ESP_NOSIG) + +#define PCNT6_CH0SIG_GPIO26 \ + ESP32_PINMUX(26, ESP_PCNT_SIG_CH0_IN6, ESP_NOSIG) + +#define PCNT6_CH0SIG_GPIO27 \ + ESP32_PINMUX(27, ESP_PCNT_SIG_CH0_IN6, ESP_NOSIG) + +#define PCNT6_CH0SIG_GPIO32 \ + ESP32_PINMUX(32, ESP_PCNT_SIG_CH0_IN6, ESP_NOSIG) + +#define PCNT6_CH0SIG_GPIO33 \ + ESP32_PINMUX(33, ESP_PCNT_SIG_CH0_IN6, ESP_NOSIG) + +#define PCNT6_CH0SIG_GPIO34 \ + ESP32_PINMUX(34, ESP_PCNT_SIG_CH0_IN6, ESP_NOSIG) + +#define PCNT6_CH0SIG_GPIO35 \ + ESP32_PINMUX(35, ESP_PCNT_SIG_CH0_IN6, ESP_NOSIG) + +#define PCNT6_CH0SIG_GPIO36 \ + ESP32_PINMUX(36, ESP_PCNT_SIG_CH0_IN6, ESP_NOSIG) + +#define PCNT6_CH0SIG_GPIO37 \ + ESP32_PINMUX(37, ESP_PCNT_SIG_CH0_IN6, ESP_NOSIG) + +#define PCNT6_CH0SIG_GPIO38 \ + ESP32_PINMUX(38, ESP_PCNT_SIG_CH0_IN6, ESP_NOSIG) + +#define PCNT6_CH0SIG_GPIO39 \ + ESP32_PINMUX(39, ESP_PCNT_SIG_CH0_IN6, ESP_NOSIG) + +/* PCNT6_CH1CTRL */ +#define PCNT6_CH1CTRL_GPIO0 \ + ESP32_PINMUX(0, ESP_PCNT_CTRL_CH1_IN6, ESP_NOSIG) + +#define PCNT6_CH1CTRL_GPIO1 \ + ESP32_PINMUX(1, ESP_PCNT_CTRL_CH1_IN6, ESP_NOSIG) + +#define PCNT6_CH1CTRL_GPIO2 \ + ESP32_PINMUX(2, ESP_PCNT_CTRL_CH1_IN6, ESP_NOSIG) + +#define PCNT6_CH1CTRL_GPIO3 \ + ESP32_PINMUX(3, ESP_PCNT_CTRL_CH1_IN6, ESP_NOSIG) + +#define PCNT6_CH1CTRL_GPIO4 \ + ESP32_PINMUX(4, ESP_PCNT_CTRL_CH1_IN6, ESP_NOSIG) + +#define PCNT6_CH1CTRL_GPIO5 \ + ESP32_PINMUX(5, ESP_PCNT_CTRL_CH1_IN6, ESP_NOSIG) + +#define PCNT6_CH1CTRL_GPIO6 \ + ESP32_PINMUX(6, ESP_PCNT_CTRL_CH1_IN6, ESP_NOSIG) + +#define PCNT6_CH1CTRL_GPIO7 \ + ESP32_PINMUX(7, ESP_PCNT_CTRL_CH1_IN6, ESP_NOSIG) + +#define PCNT6_CH1CTRL_GPIO8 \ + ESP32_PINMUX(8, ESP_PCNT_CTRL_CH1_IN6, ESP_NOSIG) + +#define PCNT6_CH1CTRL_GPIO9 \ + ESP32_PINMUX(9, ESP_PCNT_CTRL_CH1_IN6, ESP_NOSIG) + +#define PCNT6_CH1CTRL_GPIO10 \ + ESP32_PINMUX(10, ESP_PCNT_CTRL_CH1_IN6, ESP_NOSIG) + +#define PCNT6_CH1CTRL_GPIO11 \ + ESP32_PINMUX(11, ESP_PCNT_CTRL_CH1_IN6, ESP_NOSIG) + +#define PCNT6_CH1CTRL_GPIO12 \ + ESP32_PINMUX(12, ESP_PCNT_CTRL_CH1_IN6, ESP_NOSIG) + +#define PCNT6_CH1CTRL_GPIO13 \ + ESP32_PINMUX(13, ESP_PCNT_CTRL_CH1_IN6, ESP_NOSIG) + +#define PCNT6_CH1CTRL_GPIO14 \ + ESP32_PINMUX(14, ESP_PCNT_CTRL_CH1_IN6, ESP_NOSIG) + +#define PCNT6_CH1CTRL_GPIO15 \ + ESP32_PINMUX(15, ESP_PCNT_CTRL_CH1_IN6, ESP_NOSIG) + +#define PCNT6_CH1CTRL_GPIO16 \ + ESP32_PINMUX(16, ESP_PCNT_CTRL_CH1_IN6, ESP_NOSIG) + +#define PCNT6_CH1CTRL_GPIO17 \ + ESP32_PINMUX(17, ESP_PCNT_CTRL_CH1_IN6, ESP_NOSIG) + +#define PCNT6_CH1CTRL_GPIO18 \ + ESP32_PINMUX(18, ESP_PCNT_CTRL_CH1_IN6, ESP_NOSIG) + +#define PCNT6_CH1CTRL_GPIO19 \ + ESP32_PINMUX(19, ESP_PCNT_CTRL_CH1_IN6, ESP_NOSIG) + +#define PCNT6_CH1CTRL_GPIO20 \ + ESP32_PINMUX(20, ESP_PCNT_CTRL_CH1_IN6, ESP_NOSIG) + +#define PCNT6_CH1CTRL_GPIO21 \ + ESP32_PINMUX(21, ESP_PCNT_CTRL_CH1_IN6, ESP_NOSIG) + +#define PCNT6_CH1CTRL_GPIO22 \ + ESP32_PINMUX(22, ESP_PCNT_CTRL_CH1_IN6, ESP_NOSIG) + +#define PCNT6_CH1CTRL_GPIO23 \ + ESP32_PINMUX(23, ESP_PCNT_CTRL_CH1_IN6, ESP_NOSIG) + +#define PCNT6_CH1CTRL_GPIO25 \ + ESP32_PINMUX(25, ESP_PCNT_CTRL_CH1_IN6, ESP_NOSIG) + +#define PCNT6_CH1CTRL_GPIO26 \ + ESP32_PINMUX(26, ESP_PCNT_CTRL_CH1_IN6, ESP_NOSIG) + +#define PCNT6_CH1CTRL_GPIO27 \ + ESP32_PINMUX(27, ESP_PCNT_CTRL_CH1_IN6, ESP_NOSIG) + +#define PCNT6_CH1CTRL_GPIO32 \ + ESP32_PINMUX(32, ESP_PCNT_CTRL_CH1_IN6, ESP_NOSIG) + +#define PCNT6_CH1CTRL_GPIO33 \ + ESP32_PINMUX(33, ESP_PCNT_CTRL_CH1_IN6, ESP_NOSIG) + +#define PCNT6_CH1CTRL_GPIO34 \ + ESP32_PINMUX(34, ESP_PCNT_CTRL_CH1_IN6, ESP_NOSIG) + +#define PCNT6_CH1CTRL_GPIO35 \ + ESP32_PINMUX(35, ESP_PCNT_CTRL_CH1_IN6, ESP_NOSIG) + +#define PCNT6_CH1CTRL_GPIO36 \ + ESP32_PINMUX(36, ESP_PCNT_CTRL_CH1_IN6, ESP_NOSIG) + +#define PCNT6_CH1CTRL_GPIO37 \ + ESP32_PINMUX(37, ESP_PCNT_CTRL_CH1_IN6, ESP_NOSIG) + +#define PCNT6_CH1CTRL_GPIO38 \ + ESP32_PINMUX(38, ESP_PCNT_CTRL_CH1_IN6, ESP_NOSIG) + +#define PCNT6_CH1CTRL_GPIO39 \ + ESP32_PINMUX(39, ESP_PCNT_CTRL_CH1_IN6, ESP_NOSIG) + +/* PCNT6_CH1SIG */ +#define PCNT6_CH1SIG_GPIO0 \ + ESP32_PINMUX(0, ESP_PCNT_SIG_CH1_IN6, ESP_NOSIG) + +#define PCNT6_CH1SIG_GPIO1 \ + ESP32_PINMUX(1, ESP_PCNT_SIG_CH1_IN6, ESP_NOSIG) + +#define PCNT6_CH1SIG_GPIO2 \ + ESP32_PINMUX(2, ESP_PCNT_SIG_CH1_IN6, ESP_NOSIG) + +#define PCNT6_CH1SIG_GPIO3 \ + ESP32_PINMUX(3, ESP_PCNT_SIG_CH1_IN6, ESP_NOSIG) + +#define PCNT6_CH1SIG_GPIO4 \ + ESP32_PINMUX(4, ESP_PCNT_SIG_CH1_IN6, ESP_NOSIG) + +#define PCNT6_CH1SIG_GPIO5 \ + ESP32_PINMUX(5, ESP_PCNT_SIG_CH1_IN6, ESP_NOSIG) + +#define PCNT6_CH1SIG_GPIO6 \ + ESP32_PINMUX(6, ESP_PCNT_SIG_CH1_IN6, ESP_NOSIG) + +#define PCNT6_CH1SIG_GPIO7 \ + ESP32_PINMUX(7, ESP_PCNT_SIG_CH1_IN6, ESP_NOSIG) + +#define PCNT6_CH1SIG_GPIO8 \ + ESP32_PINMUX(8, ESP_PCNT_SIG_CH1_IN6, ESP_NOSIG) + +#define PCNT6_CH1SIG_GPIO9 \ + ESP32_PINMUX(9, ESP_PCNT_SIG_CH1_IN6, ESP_NOSIG) + +#define PCNT6_CH1SIG_GPIO10 \ + ESP32_PINMUX(10, ESP_PCNT_SIG_CH1_IN6, ESP_NOSIG) + +#define PCNT6_CH1SIG_GPIO11 \ + ESP32_PINMUX(11, ESP_PCNT_SIG_CH1_IN6, ESP_NOSIG) + +#define PCNT6_CH1SIG_GPIO12 \ + ESP32_PINMUX(12, ESP_PCNT_SIG_CH1_IN6, ESP_NOSIG) + +#define PCNT6_CH1SIG_GPIO13 \ + ESP32_PINMUX(13, ESP_PCNT_SIG_CH1_IN6, ESP_NOSIG) + +#define PCNT6_CH1SIG_GPIO14 \ + ESP32_PINMUX(14, ESP_PCNT_SIG_CH1_IN6, ESP_NOSIG) + +#define PCNT6_CH1SIG_GPIO15 \ + ESP32_PINMUX(15, ESP_PCNT_SIG_CH1_IN6, ESP_NOSIG) + +#define PCNT6_CH1SIG_GPIO16 \ + ESP32_PINMUX(16, ESP_PCNT_SIG_CH1_IN6, ESP_NOSIG) + +#define PCNT6_CH1SIG_GPIO17 \ + ESP32_PINMUX(17, ESP_PCNT_SIG_CH1_IN6, ESP_NOSIG) + +#define PCNT6_CH1SIG_GPIO18 \ + ESP32_PINMUX(18, ESP_PCNT_SIG_CH1_IN6, ESP_NOSIG) + +#define PCNT6_CH1SIG_GPIO19 \ + ESP32_PINMUX(19, ESP_PCNT_SIG_CH1_IN6, ESP_NOSIG) + +#define PCNT6_CH1SIG_GPIO20 \ + ESP32_PINMUX(20, ESP_PCNT_SIG_CH1_IN6, ESP_NOSIG) + +#define PCNT6_CH1SIG_GPIO21 \ + ESP32_PINMUX(21, ESP_PCNT_SIG_CH1_IN6, ESP_NOSIG) + +#define PCNT6_CH1SIG_GPIO22 \ + ESP32_PINMUX(22, ESP_PCNT_SIG_CH1_IN6, ESP_NOSIG) + +#define PCNT6_CH1SIG_GPIO23 \ + ESP32_PINMUX(23, ESP_PCNT_SIG_CH1_IN6, ESP_NOSIG) + +#define PCNT6_CH1SIG_GPIO25 \ + ESP32_PINMUX(25, ESP_PCNT_SIG_CH1_IN6, ESP_NOSIG) + +#define PCNT6_CH1SIG_GPIO26 \ + ESP32_PINMUX(26, ESP_PCNT_SIG_CH1_IN6, ESP_NOSIG) + +#define PCNT6_CH1SIG_GPIO27 \ + ESP32_PINMUX(27, ESP_PCNT_SIG_CH1_IN6, ESP_NOSIG) + +#define PCNT6_CH1SIG_GPIO32 \ + ESP32_PINMUX(32, ESP_PCNT_SIG_CH1_IN6, ESP_NOSIG) + +#define PCNT6_CH1SIG_GPIO33 \ + ESP32_PINMUX(33, ESP_PCNT_SIG_CH1_IN6, ESP_NOSIG) + +#define PCNT6_CH1SIG_GPIO34 \ + ESP32_PINMUX(34, ESP_PCNT_SIG_CH1_IN6, ESP_NOSIG) + +#define PCNT6_CH1SIG_GPIO35 \ + ESP32_PINMUX(35, ESP_PCNT_SIG_CH1_IN6, ESP_NOSIG) + +#define PCNT6_CH1SIG_GPIO36 \ + ESP32_PINMUX(36, ESP_PCNT_SIG_CH1_IN6, ESP_NOSIG) + +#define PCNT6_CH1SIG_GPIO37 \ + ESP32_PINMUX(37, ESP_PCNT_SIG_CH1_IN6, ESP_NOSIG) + +#define PCNT6_CH1SIG_GPIO38 \ + ESP32_PINMUX(38, ESP_PCNT_SIG_CH1_IN6, ESP_NOSIG) + +#define PCNT6_CH1SIG_GPIO39 \ + ESP32_PINMUX(39, ESP_PCNT_SIG_CH1_IN6, ESP_NOSIG) + +/* PCNT7_CH0CTRL */ +#define PCNT7_CH0CTRL_GPIO0 \ + ESP32_PINMUX(0, ESP_PCNT_CTRL_CH0_IN7, ESP_NOSIG) + +#define PCNT7_CH0CTRL_GPIO1 \ + ESP32_PINMUX(1, ESP_PCNT_CTRL_CH0_IN7, ESP_NOSIG) + +#define PCNT7_CH0CTRL_GPIO2 \ + ESP32_PINMUX(2, ESP_PCNT_CTRL_CH0_IN7, ESP_NOSIG) + +#define PCNT7_CH0CTRL_GPIO3 \ + ESP32_PINMUX(3, ESP_PCNT_CTRL_CH0_IN7, ESP_NOSIG) + +#define PCNT7_CH0CTRL_GPIO4 \ + ESP32_PINMUX(4, ESP_PCNT_CTRL_CH0_IN7, ESP_NOSIG) + +#define PCNT7_CH0CTRL_GPIO5 \ + ESP32_PINMUX(5, ESP_PCNT_CTRL_CH0_IN7, ESP_NOSIG) + +#define PCNT7_CH0CTRL_GPIO6 \ + ESP32_PINMUX(6, ESP_PCNT_CTRL_CH0_IN7, ESP_NOSIG) + +#define PCNT7_CH0CTRL_GPIO7 \ + ESP32_PINMUX(7, ESP_PCNT_CTRL_CH0_IN7, ESP_NOSIG) + +#define PCNT7_CH0CTRL_GPIO8 \ + ESP32_PINMUX(8, ESP_PCNT_CTRL_CH0_IN7, ESP_NOSIG) + +#define PCNT7_CH0CTRL_GPIO9 \ + ESP32_PINMUX(9, ESP_PCNT_CTRL_CH0_IN7, ESP_NOSIG) + +#define PCNT7_CH0CTRL_GPIO10 \ + ESP32_PINMUX(10, ESP_PCNT_CTRL_CH0_IN7, ESP_NOSIG) + +#define PCNT7_CH0CTRL_GPIO11 \ + ESP32_PINMUX(11, ESP_PCNT_CTRL_CH0_IN7, ESP_NOSIG) + +#define PCNT7_CH0CTRL_GPIO12 \ + ESP32_PINMUX(12, ESP_PCNT_CTRL_CH0_IN7, ESP_NOSIG) + +#define PCNT7_CH0CTRL_GPIO13 \ + ESP32_PINMUX(13, ESP_PCNT_CTRL_CH0_IN7, ESP_NOSIG) + +#define PCNT7_CH0CTRL_GPIO14 \ + ESP32_PINMUX(14, ESP_PCNT_CTRL_CH0_IN7, ESP_NOSIG) + +#define PCNT7_CH0CTRL_GPIO15 \ + ESP32_PINMUX(15, ESP_PCNT_CTRL_CH0_IN7, ESP_NOSIG) + +#define PCNT7_CH0CTRL_GPIO16 \ + ESP32_PINMUX(16, ESP_PCNT_CTRL_CH0_IN7, ESP_NOSIG) + +#define PCNT7_CH0CTRL_GPIO17 \ + ESP32_PINMUX(17, ESP_PCNT_CTRL_CH0_IN7, ESP_NOSIG) + +#define PCNT7_CH0CTRL_GPIO18 \ + ESP32_PINMUX(18, ESP_PCNT_CTRL_CH0_IN7, ESP_NOSIG) + +#define PCNT7_CH0CTRL_GPIO19 \ + ESP32_PINMUX(19, ESP_PCNT_CTRL_CH0_IN7, ESP_NOSIG) + +#define PCNT7_CH0CTRL_GPIO20 \ + ESP32_PINMUX(20, ESP_PCNT_CTRL_CH0_IN7, ESP_NOSIG) + +#define PCNT7_CH0CTRL_GPIO21 \ + ESP32_PINMUX(21, ESP_PCNT_CTRL_CH0_IN7, ESP_NOSIG) + +#define PCNT7_CH0CTRL_GPIO22 \ + ESP32_PINMUX(22, ESP_PCNT_CTRL_CH0_IN7, ESP_NOSIG) + +#define PCNT7_CH0CTRL_GPIO23 \ + ESP32_PINMUX(23, ESP_PCNT_CTRL_CH0_IN7, ESP_NOSIG) + +#define PCNT7_CH0CTRL_GPIO25 \ + ESP32_PINMUX(25, ESP_PCNT_CTRL_CH0_IN7, ESP_NOSIG) + +#define PCNT7_CH0CTRL_GPIO26 \ + ESP32_PINMUX(26, ESP_PCNT_CTRL_CH0_IN7, ESP_NOSIG) + +#define PCNT7_CH0CTRL_GPIO27 \ + ESP32_PINMUX(27, ESP_PCNT_CTRL_CH0_IN7, ESP_NOSIG) + +#define PCNT7_CH0CTRL_GPIO32 \ + ESP32_PINMUX(32, ESP_PCNT_CTRL_CH0_IN7, ESP_NOSIG) + +#define PCNT7_CH0CTRL_GPIO33 \ + ESP32_PINMUX(33, ESP_PCNT_CTRL_CH0_IN7, ESP_NOSIG) + +#define PCNT7_CH0CTRL_GPIO34 \ + ESP32_PINMUX(34, ESP_PCNT_CTRL_CH0_IN7, ESP_NOSIG) + +#define PCNT7_CH0CTRL_GPIO35 \ + ESP32_PINMUX(35, ESP_PCNT_CTRL_CH0_IN7, ESP_NOSIG) + +#define PCNT7_CH0CTRL_GPIO36 \ + ESP32_PINMUX(36, ESP_PCNT_CTRL_CH0_IN7, ESP_NOSIG) + +#define PCNT7_CH0CTRL_GPIO37 \ + ESP32_PINMUX(37, ESP_PCNT_CTRL_CH0_IN7, ESP_NOSIG) + +#define PCNT7_CH0CTRL_GPIO38 \ + ESP32_PINMUX(38, ESP_PCNT_CTRL_CH0_IN7, ESP_NOSIG) + +#define PCNT7_CH0CTRL_GPIO39 \ + ESP32_PINMUX(39, ESP_PCNT_CTRL_CH0_IN7, ESP_NOSIG) + +/* PCNT7_CH0SIG */ +#define PCNT7_CH0SIG_GPIO0 \ + ESP32_PINMUX(0, ESP_PCNT_SIG_CH0_IN7, ESP_NOSIG) + +#define PCNT7_CH0SIG_GPIO1 \ + ESP32_PINMUX(1, ESP_PCNT_SIG_CH0_IN7, ESP_NOSIG) + +#define PCNT7_CH0SIG_GPIO2 \ + ESP32_PINMUX(2, ESP_PCNT_SIG_CH0_IN7, ESP_NOSIG) + +#define PCNT7_CH0SIG_GPIO3 \ + ESP32_PINMUX(3, ESP_PCNT_SIG_CH0_IN7, ESP_NOSIG) + +#define PCNT7_CH0SIG_GPIO4 \ + ESP32_PINMUX(4, ESP_PCNT_SIG_CH0_IN7, ESP_NOSIG) + +#define PCNT7_CH0SIG_GPIO5 \ + ESP32_PINMUX(5, ESP_PCNT_SIG_CH0_IN7, ESP_NOSIG) + +#define PCNT7_CH0SIG_GPIO6 \ + ESP32_PINMUX(6, ESP_PCNT_SIG_CH0_IN7, ESP_NOSIG) + +#define PCNT7_CH0SIG_GPIO7 \ + ESP32_PINMUX(7, ESP_PCNT_SIG_CH0_IN7, ESP_NOSIG) + +#define PCNT7_CH0SIG_GPIO8 \ + ESP32_PINMUX(8, ESP_PCNT_SIG_CH0_IN7, ESP_NOSIG) + +#define PCNT7_CH0SIG_GPIO9 \ + ESP32_PINMUX(9, ESP_PCNT_SIG_CH0_IN7, ESP_NOSIG) + +#define PCNT7_CH0SIG_GPIO10 \ + ESP32_PINMUX(10, ESP_PCNT_SIG_CH0_IN7, ESP_NOSIG) + +#define PCNT7_CH0SIG_GPIO11 \ + ESP32_PINMUX(11, ESP_PCNT_SIG_CH0_IN7, ESP_NOSIG) + +#define PCNT7_CH0SIG_GPIO12 \ + ESP32_PINMUX(12, ESP_PCNT_SIG_CH0_IN7, ESP_NOSIG) + +#define PCNT7_CH0SIG_GPIO13 \ + ESP32_PINMUX(13, ESP_PCNT_SIG_CH0_IN7, ESP_NOSIG) + +#define PCNT7_CH0SIG_GPIO14 \ + ESP32_PINMUX(14, ESP_PCNT_SIG_CH0_IN7, ESP_NOSIG) + +#define PCNT7_CH0SIG_GPIO15 \ + ESP32_PINMUX(15, ESP_PCNT_SIG_CH0_IN7, ESP_NOSIG) + +#define PCNT7_CH0SIG_GPIO16 \ + ESP32_PINMUX(16, ESP_PCNT_SIG_CH0_IN7, ESP_NOSIG) + +#define PCNT7_CH0SIG_GPIO17 \ + ESP32_PINMUX(17, ESP_PCNT_SIG_CH0_IN7, ESP_NOSIG) + +#define PCNT7_CH0SIG_GPIO18 \ + ESP32_PINMUX(18, ESP_PCNT_SIG_CH0_IN7, ESP_NOSIG) + +#define PCNT7_CH0SIG_GPIO19 \ + ESP32_PINMUX(19, ESP_PCNT_SIG_CH0_IN7, ESP_NOSIG) + +#define PCNT7_CH0SIG_GPIO20 \ + ESP32_PINMUX(20, ESP_PCNT_SIG_CH0_IN7, ESP_NOSIG) + +#define PCNT7_CH0SIG_GPIO21 \ + ESP32_PINMUX(21, ESP_PCNT_SIG_CH0_IN7, ESP_NOSIG) + +#define PCNT7_CH0SIG_GPIO22 \ + ESP32_PINMUX(22, ESP_PCNT_SIG_CH0_IN7, ESP_NOSIG) + +#define PCNT7_CH0SIG_GPIO23 \ + ESP32_PINMUX(23, ESP_PCNT_SIG_CH0_IN7, ESP_NOSIG) + +#define PCNT7_CH0SIG_GPIO25 \ + ESP32_PINMUX(25, ESP_PCNT_SIG_CH0_IN7, ESP_NOSIG) + +#define PCNT7_CH0SIG_GPIO26 \ + ESP32_PINMUX(26, ESP_PCNT_SIG_CH0_IN7, ESP_NOSIG) + +#define PCNT7_CH0SIG_GPIO27 \ + ESP32_PINMUX(27, ESP_PCNT_SIG_CH0_IN7, ESP_NOSIG) + +#define PCNT7_CH0SIG_GPIO32 \ + ESP32_PINMUX(32, ESP_PCNT_SIG_CH0_IN7, ESP_NOSIG) + +#define PCNT7_CH0SIG_GPIO33 \ + ESP32_PINMUX(33, ESP_PCNT_SIG_CH0_IN7, ESP_NOSIG) + +#define PCNT7_CH0SIG_GPIO34 \ + ESP32_PINMUX(34, ESP_PCNT_SIG_CH0_IN7, ESP_NOSIG) + +#define PCNT7_CH0SIG_GPIO35 \ + ESP32_PINMUX(35, ESP_PCNT_SIG_CH0_IN7, ESP_NOSIG) + +#define PCNT7_CH0SIG_GPIO36 \ + ESP32_PINMUX(36, ESP_PCNT_SIG_CH0_IN7, ESP_NOSIG) + +#define PCNT7_CH0SIG_GPIO37 \ + ESP32_PINMUX(37, ESP_PCNT_SIG_CH0_IN7, ESP_NOSIG) + +#define PCNT7_CH0SIG_GPIO38 \ + ESP32_PINMUX(38, ESP_PCNT_SIG_CH0_IN7, ESP_NOSIG) + +#define PCNT7_CH0SIG_GPIO39 \ + ESP32_PINMUX(39, ESP_PCNT_SIG_CH0_IN7, ESP_NOSIG) + +/* PCNT7_CH1CTRL */ +#define PCNT7_CH1CTRL_GPIO0 \ + ESP32_PINMUX(0, ESP_PCNT_CTRL_CH1_IN7, ESP_NOSIG) + +#define PCNT7_CH1CTRL_GPIO1 \ + ESP32_PINMUX(1, ESP_PCNT_CTRL_CH1_IN7, ESP_NOSIG) + +#define PCNT7_CH1CTRL_GPIO2 \ + ESP32_PINMUX(2, ESP_PCNT_CTRL_CH1_IN7, ESP_NOSIG) + +#define PCNT7_CH1CTRL_GPIO3 \ + ESP32_PINMUX(3, ESP_PCNT_CTRL_CH1_IN7, ESP_NOSIG) + +#define PCNT7_CH1CTRL_GPIO4 \ + ESP32_PINMUX(4, ESP_PCNT_CTRL_CH1_IN7, ESP_NOSIG) + +#define PCNT7_CH1CTRL_GPIO5 \ + ESP32_PINMUX(5, ESP_PCNT_CTRL_CH1_IN7, ESP_NOSIG) + +#define PCNT7_CH1CTRL_GPIO6 \ + ESP32_PINMUX(6, ESP_PCNT_CTRL_CH1_IN7, ESP_NOSIG) + +#define PCNT7_CH1CTRL_GPIO7 \ + ESP32_PINMUX(7, ESP_PCNT_CTRL_CH1_IN7, ESP_NOSIG) + +#define PCNT7_CH1CTRL_GPIO8 \ + ESP32_PINMUX(8, ESP_PCNT_CTRL_CH1_IN7, ESP_NOSIG) + +#define PCNT7_CH1CTRL_GPIO9 \ + ESP32_PINMUX(9, ESP_PCNT_CTRL_CH1_IN7, ESP_NOSIG) + +#define PCNT7_CH1CTRL_GPIO10 \ + ESP32_PINMUX(10, ESP_PCNT_CTRL_CH1_IN7, ESP_NOSIG) + +#define PCNT7_CH1CTRL_GPIO11 \ + ESP32_PINMUX(11, ESP_PCNT_CTRL_CH1_IN7, ESP_NOSIG) + +#define PCNT7_CH1CTRL_GPIO12 \ + ESP32_PINMUX(12, ESP_PCNT_CTRL_CH1_IN7, ESP_NOSIG) + +#define PCNT7_CH1CTRL_GPIO13 \ + ESP32_PINMUX(13, ESP_PCNT_CTRL_CH1_IN7, ESP_NOSIG) + +#define PCNT7_CH1CTRL_GPIO14 \ + ESP32_PINMUX(14, ESP_PCNT_CTRL_CH1_IN7, ESP_NOSIG) + +#define PCNT7_CH1CTRL_GPIO15 \ + ESP32_PINMUX(15, ESP_PCNT_CTRL_CH1_IN7, ESP_NOSIG) + +#define PCNT7_CH1CTRL_GPIO16 \ + ESP32_PINMUX(16, ESP_PCNT_CTRL_CH1_IN7, ESP_NOSIG) + +#define PCNT7_CH1CTRL_GPIO17 \ + ESP32_PINMUX(17, ESP_PCNT_CTRL_CH1_IN7, ESP_NOSIG) + +#define PCNT7_CH1CTRL_GPIO18 \ + ESP32_PINMUX(18, ESP_PCNT_CTRL_CH1_IN7, ESP_NOSIG) + +#define PCNT7_CH1CTRL_GPIO19 \ + ESP32_PINMUX(19, ESP_PCNT_CTRL_CH1_IN7, ESP_NOSIG) + +#define PCNT7_CH1CTRL_GPIO20 \ + ESP32_PINMUX(20, ESP_PCNT_CTRL_CH1_IN7, ESP_NOSIG) + +#define PCNT7_CH1CTRL_GPIO21 \ + ESP32_PINMUX(21, ESP_PCNT_CTRL_CH1_IN7, ESP_NOSIG) + +#define PCNT7_CH1CTRL_GPIO22 \ + ESP32_PINMUX(22, ESP_PCNT_CTRL_CH1_IN7, ESP_NOSIG) + +#define PCNT7_CH1CTRL_GPIO23 \ + ESP32_PINMUX(23, ESP_PCNT_CTRL_CH1_IN7, ESP_NOSIG) + +#define PCNT7_CH1CTRL_GPIO25 \ + ESP32_PINMUX(25, ESP_PCNT_CTRL_CH1_IN7, ESP_NOSIG) + +#define PCNT7_CH1CTRL_GPIO26 \ + ESP32_PINMUX(26, ESP_PCNT_CTRL_CH1_IN7, ESP_NOSIG) + +#define PCNT7_CH1CTRL_GPIO27 \ + ESP32_PINMUX(27, ESP_PCNT_CTRL_CH1_IN7, ESP_NOSIG) + +#define PCNT7_CH1CTRL_GPIO32 \ + ESP32_PINMUX(32, ESP_PCNT_CTRL_CH1_IN7, ESP_NOSIG) + +#define PCNT7_CH1CTRL_GPIO33 \ + ESP32_PINMUX(33, ESP_PCNT_CTRL_CH1_IN7, ESP_NOSIG) + +#define PCNT7_CH1CTRL_GPIO34 \ + ESP32_PINMUX(34, ESP_PCNT_CTRL_CH1_IN7, ESP_NOSIG) + +#define PCNT7_CH1CTRL_GPIO35 \ + ESP32_PINMUX(35, ESP_PCNT_CTRL_CH1_IN7, ESP_NOSIG) + +#define PCNT7_CH1CTRL_GPIO36 \ + ESP32_PINMUX(36, ESP_PCNT_CTRL_CH1_IN7, ESP_NOSIG) + +#define PCNT7_CH1CTRL_GPIO37 \ + ESP32_PINMUX(37, ESP_PCNT_CTRL_CH1_IN7, ESP_NOSIG) + +#define PCNT7_CH1CTRL_GPIO38 \ + ESP32_PINMUX(38, ESP_PCNT_CTRL_CH1_IN7, ESP_NOSIG) + +#define PCNT7_CH1CTRL_GPIO39 \ + ESP32_PINMUX(39, ESP_PCNT_CTRL_CH1_IN7, ESP_NOSIG) + +/* PCNT7_CH1SIG */ +#define PCNT7_CH1SIG_GPIO0 \ + ESP32_PINMUX(0, ESP_PCNT_SIG_CH1_IN7, ESP_NOSIG) + +#define PCNT7_CH1SIG_GPIO1 \ + ESP32_PINMUX(1, ESP_PCNT_SIG_CH1_IN7, ESP_NOSIG) + +#define PCNT7_CH1SIG_GPIO2 \ + ESP32_PINMUX(2, ESP_PCNT_SIG_CH1_IN7, ESP_NOSIG) + +#define PCNT7_CH1SIG_GPIO3 \ + ESP32_PINMUX(3, ESP_PCNT_SIG_CH1_IN7, ESP_NOSIG) + +#define PCNT7_CH1SIG_GPIO4 \ + ESP32_PINMUX(4, ESP_PCNT_SIG_CH1_IN7, ESP_NOSIG) + +#define PCNT7_CH1SIG_GPIO5 \ + ESP32_PINMUX(5, ESP_PCNT_SIG_CH1_IN7, ESP_NOSIG) + +#define PCNT7_CH1SIG_GPIO6 \ + ESP32_PINMUX(6, ESP_PCNT_SIG_CH1_IN7, ESP_NOSIG) + +#define PCNT7_CH1SIG_GPIO7 \ + ESP32_PINMUX(7, ESP_PCNT_SIG_CH1_IN7, ESP_NOSIG) + +#define PCNT7_CH1SIG_GPIO8 \ + ESP32_PINMUX(8, ESP_PCNT_SIG_CH1_IN7, ESP_NOSIG) + +#define PCNT7_CH1SIG_GPIO9 \ + ESP32_PINMUX(9, ESP_PCNT_SIG_CH1_IN7, ESP_NOSIG) + +#define PCNT7_CH1SIG_GPIO10 \ + ESP32_PINMUX(10, ESP_PCNT_SIG_CH1_IN7, ESP_NOSIG) + +#define PCNT7_CH1SIG_GPIO11 \ + ESP32_PINMUX(11, ESP_PCNT_SIG_CH1_IN7, ESP_NOSIG) + +#define PCNT7_CH1SIG_GPIO12 \ + ESP32_PINMUX(12, ESP_PCNT_SIG_CH1_IN7, ESP_NOSIG) + +#define PCNT7_CH1SIG_GPIO13 \ + ESP32_PINMUX(13, ESP_PCNT_SIG_CH1_IN7, ESP_NOSIG) + +#define PCNT7_CH1SIG_GPIO14 \ + ESP32_PINMUX(14, ESP_PCNT_SIG_CH1_IN7, ESP_NOSIG) + +#define PCNT7_CH1SIG_GPIO15 \ + ESP32_PINMUX(15, ESP_PCNT_SIG_CH1_IN7, ESP_NOSIG) + +#define PCNT7_CH1SIG_GPIO16 \ + ESP32_PINMUX(16, ESP_PCNT_SIG_CH1_IN7, ESP_NOSIG) + +#define PCNT7_CH1SIG_GPIO17 \ + ESP32_PINMUX(17, ESP_PCNT_SIG_CH1_IN7, ESP_NOSIG) + +#define PCNT7_CH1SIG_GPIO18 \ + ESP32_PINMUX(18, ESP_PCNT_SIG_CH1_IN7, ESP_NOSIG) + +#define PCNT7_CH1SIG_GPIO19 \ + ESP32_PINMUX(19, ESP_PCNT_SIG_CH1_IN7, ESP_NOSIG) + +#define PCNT7_CH1SIG_GPIO20 \ + ESP32_PINMUX(20, ESP_PCNT_SIG_CH1_IN7, ESP_NOSIG) + +#define PCNT7_CH1SIG_GPIO21 \ + ESP32_PINMUX(21, ESP_PCNT_SIG_CH1_IN7, ESP_NOSIG) + +#define PCNT7_CH1SIG_GPIO22 \ + ESP32_PINMUX(22, ESP_PCNT_SIG_CH1_IN7, ESP_NOSIG) + +#define PCNT7_CH1SIG_GPIO23 \ + ESP32_PINMUX(23, ESP_PCNT_SIG_CH1_IN7, ESP_NOSIG) + +#define PCNT7_CH1SIG_GPIO25 \ + ESP32_PINMUX(25, ESP_PCNT_SIG_CH1_IN7, ESP_NOSIG) + +#define PCNT7_CH1SIG_GPIO26 \ + ESP32_PINMUX(26, ESP_PCNT_SIG_CH1_IN7, ESP_NOSIG) + +#define PCNT7_CH1SIG_GPIO27 \ + ESP32_PINMUX(27, ESP_PCNT_SIG_CH1_IN7, ESP_NOSIG) + +#define PCNT7_CH1SIG_GPIO32 \ + ESP32_PINMUX(32, ESP_PCNT_SIG_CH1_IN7, ESP_NOSIG) + +#define PCNT7_CH1SIG_GPIO33 \ + ESP32_PINMUX(33, ESP_PCNT_SIG_CH1_IN7, ESP_NOSIG) + +#define PCNT7_CH1SIG_GPIO34 \ + ESP32_PINMUX(34, ESP_PCNT_SIG_CH1_IN7, ESP_NOSIG) + +#define PCNT7_CH1SIG_GPIO35 \ + ESP32_PINMUX(35, ESP_PCNT_SIG_CH1_IN7, ESP_NOSIG) + +#define PCNT7_CH1SIG_GPIO36 \ + ESP32_PINMUX(36, ESP_PCNT_SIG_CH1_IN7, ESP_NOSIG) + +#define PCNT7_CH1SIG_GPIO37 \ + ESP32_PINMUX(37, ESP_PCNT_SIG_CH1_IN7, ESP_NOSIG) + +#define PCNT7_CH1SIG_GPIO38 \ + ESP32_PINMUX(38, ESP_PCNT_SIG_CH1_IN7, ESP_NOSIG) + +#define PCNT7_CH1SIG_GPIO39 \ + ESP32_PINMUX(39, ESP_PCNT_SIG_CH1_IN7, ESP_NOSIG) + +/* SMI_MDC */ +#define SMI_MDC_GPIO0 \ + ESP32_PINMUX(0, ESP_NOSIG, ESP_EMAC_MDC_O) + +#define SMI_MDC_GPIO1 \ + ESP32_PINMUX(1, ESP_NOSIG, ESP_EMAC_MDC_O) + +#define SMI_MDC_GPIO2 \ + ESP32_PINMUX(2, ESP_NOSIG, ESP_EMAC_MDC_O) + +#define SMI_MDC_GPIO3 \ + ESP32_PINMUX(3, ESP_NOSIG, ESP_EMAC_MDC_O) + +#define SMI_MDC_GPIO4 \ + ESP32_PINMUX(4, ESP_NOSIG, ESP_EMAC_MDC_O) + +#define SMI_MDC_GPIO5 \ + ESP32_PINMUX(5, ESP_NOSIG, ESP_EMAC_MDC_O) + +#define SMI_MDC_GPIO6 \ + ESP32_PINMUX(6, ESP_NOSIG, ESP_EMAC_MDC_O) + +#define SMI_MDC_GPIO7 \ + ESP32_PINMUX(7, ESP_NOSIG, ESP_EMAC_MDC_O) + +#define SMI_MDC_GPIO8 \ + ESP32_PINMUX(8, ESP_NOSIG, ESP_EMAC_MDC_O) + +#define SMI_MDC_GPIO9 \ + ESP32_PINMUX(9, ESP_NOSIG, ESP_EMAC_MDC_O) + +#define SMI_MDC_GPIO10 \ + ESP32_PINMUX(10, ESP_NOSIG, ESP_EMAC_MDC_O) + +#define SMI_MDC_GPIO11 \ + ESP32_PINMUX(11, ESP_NOSIG, ESP_EMAC_MDC_O) + +#define SMI_MDC_GPIO12 \ + ESP32_PINMUX(12, ESP_NOSIG, ESP_EMAC_MDC_O) + +#define SMI_MDC_GPIO13 \ + ESP32_PINMUX(13, ESP_NOSIG, ESP_EMAC_MDC_O) + +#define SMI_MDC_GPIO14 \ + ESP32_PINMUX(14, ESP_NOSIG, ESP_EMAC_MDC_O) + +#define SMI_MDC_GPIO15 \ + ESP32_PINMUX(15, ESP_NOSIG, ESP_EMAC_MDC_O) + +#define SMI_MDC_GPIO16 \ + ESP32_PINMUX(16, ESP_NOSIG, ESP_EMAC_MDC_O) + +#define SMI_MDC_GPIO17 \ + ESP32_PINMUX(17, ESP_NOSIG, ESP_EMAC_MDC_O) + +#define SMI_MDC_GPIO18 \ + ESP32_PINMUX(18, ESP_NOSIG, ESP_EMAC_MDC_O) + +#define SMI_MDC_GPIO19 \ + ESP32_PINMUX(19, ESP_NOSIG, ESP_EMAC_MDC_O) + +#define SMI_MDC_GPIO20 \ + ESP32_PINMUX(20, ESP_NOSIG, ESP_EMAC_MDC_O) + +#define SMI_MDC_GPIO21 \ + ESP32_PINMUX(21, ESP_NOSIG, ESP_EMAC_MDC_O) + +#define SMI_MDC_GPIO22 \ + ESP32_PINMUX(22, ESP_NOSIG, ESP_EMAC_MDC_O) + +#define SMI_MDC_GPIO23 \ + ESP32_PINMUX(23, ESP_NOSIG, ESP_EMAC_MDC_O) + +#define SMI_MDC_GPIO25 \ + ESP32_PINMUX(25, ESP_NOSIG, ESP_EMAC_MDC_O) + +#define SMI_MDC_GPIO26 \ + ESP32_PINMUX(26, ESP_NOSIG, ESP_EMAC_MDC_O) + +#define SMI_MDC_GPIO27 \ + ESP32_PINMUX(27, ESP_NOSIG, ESP_EMAC_MDC_O) + +#define SMI_MDC_GPIO32 \ + ESP32_PINMUX(32, ESP_NOSIG, ESP_EMAC_MDC_O) + +#define SMI_MDC_GPIO33 \ + ESP32_PINMUX(33, ESP_NOSIG, ESP_EMAC_MDC_O) + +/* SMI_MDIO */ +#define SMI_MDIO_GPIO0 \ + ESP32_PINMUX(0, ESP_EMAC_MDI_I, ESP_EMAC_MDO_O) + +#define SMI_MDIO_GPIO1 \ + ESP32_PINMUX(1, ESP_EMAC_MDI_I, ESP_EMAC_MDO_O) + +#define SMI_MDIO_GPIO2 \ + ESP32_PINMUX(2, ESP_EMAC_MDI_I, ESP_EMAC_MDO_O) + +#define SMI_MDIO_GPIO3 \ + ESP32_PINMUX(3, ESP_EMAC_MDI_I, ESP_EMAC_MDO_O) + +#define SMI_MDIO_GPIO4 \ + ESP32_PINMUX(4, ESP_EMAC_MDI_I, ESP_EMAC_MDO_O) + +#define SMI_MDIO_GPIO5 \ + ESP32_PINMUX(5, ESP_EMAC_MDI_I, ESP_EMAC_MDO_O) + +#define SMI_MDIO_GPIO6 \ + ESP32_PINMUX(6, ESP_EMAC_MDI_I, ESP_EMAC_MDO_O) + +#define SMI_MDIO_GPIO7 \ + ESP32_PINMUX(7, ESP_EMAC_MDI_I, ESP_EMAC_MDO_O) + +#define SMI_MDIO_GPIO8 \ + ESP32_PINMUX(8, ESP_EMAC_MDI_I, ESP_EMAC_MDO_O) + +#define SMI_MDIO_GPIO9 \ + ESP32_PINMUX(9, ESP_EMAC_MDI_I, ESP_EMAC_MDO_O) + +#define SMI_MDIO_GPIO10 \ + ESP32_PINMUX(10, ESP_EMAC_MDI_I, ESP_EMAC_MDO_O) + +#define SMI_MDIO_GPIO11 \ + ESP32_PINMUX(11, ESP_EMAC_MDI_I, ESP_EMAC_MDO_O) + +#define SMI_MDIO_GPIO12 \ + ESP32_PINMUX(12, ESP_EMAC_MDI_I, ESP_EMAC_MDO_O) + +#define SMI_MDIO_GPIO13 \ + ESP32_PINMUX(13, ESP_EMAC_MDI_I, ESP_EMAC_MDO_O) + +#define SMI_MDIO_GPIO14 \ + ESP32_PINMUX(14, ESP_EMAC_MDI_I, ESP_EMAC_MDO_O) + +#define SMI_MDIO_GPIO15 \ + ESP32_PINMUX(15, ESP_EMAC_MDI_I, ESP_EMAC_MDO_O) + +#define SMI_MDIO_GPIO16 \ + ESP32_PINMUX(16, ESP_EMAC_MDI_I, ESP_EMAC_MDO_O) + +#define SMI_MDIO_GPIO17 \ + ESP32_PINMUX(17, ESP_EMAC_MDI_I, ESP_EMAC_MDO_O) + +#define SMI_MDIO_GPIO18 \ + ESP32_PINMUX(18, ESP_EMAC_MDI_I, ESP_EMAC_MDO_O) + +#define SMI_MDIO_GPIO19 \ + ESP32_PINMUX(19, ESP_EMAC_MDI_I, ESP_EMAC_MDO_O) + +#define SMI_MDIO_GPIO20 \ + ESP32_PINMUX(20, ESP_EMAC_MDI_I, ESP_EMAC_MDO_O) + +#define SMI_MDIO_GPIO21 \ + ESP32_PINMUX(21, ESP_EMAC_MDI_I, ESP_EMAC_MDO_O) + +#define SMI_MDIO_GPIO22 \ + ESP32_PINMUX(22, ESP_EMAC_MDI_I, ESP_EMAC_MDO_O) + +#define SMI_MDIO_GPIO23 \ + ESP32_PINMUX(23, ESP_EMAC_MDI_I, ESP_EMAC_MDO_O) + +#define SMI_MDIO_GPIO25 \ + ESP32_PINMUX(25, ESP_EMAC_MDI_I, ESP_EMAC_MDO_O) + +#define SMI_MDIO_GPIO26 \ + ESP32_PINMUX(26, ESP_EMAC_MDI_I, ESP_EMAC_MDO_O) + +#define SMI_MDIO_GPIO27 \ + ESP32_PINMUX(27, ESP_EMAC_MDI_I, ESP_EMAC_MDO_O) + +#define SMI_MDIO_GPIO32 \ + ESP32_PINMUX(32, ESP_EMAC_MDI_I, ESP_EMAC_MDO_O) + +#define SMI_MDIO_GPIO33 \ + ESP32_PINMUX(33, ESP_EMAC_MDI_I, ESP_EMAC_MDO_O) + +/* SPIM2_CSEL */ +#define SPIM2_CSEL_GPIO0 \ + ESP32_PINMUX(0, ESP_NOSIG, ESP_HSPICS0_OUT) + +#define SPIM2_CSEL_GPIO1 \ + ESP32_PINMUX(1, ESP_NOSIG, ESP_HSPICS0_OUT) + +#define SPIM2_CSEL_GPIO2 \ + ESP32_PINMUX(2, ESP_NOSIG, ESP_HSPICS0_OUT) + +#define SPIM2_CSEL_GPIO3 \ + ESP32_PINMUX(3, ESP_NOSIG, ESP_HSPICS0_OUT) + +#define SPIM2_CSEL_GPIO4 \ + ESP32_PINMUX(4, ESP_NOSIG, ESP_HSPICS0_OUT) + +#define SPIM2_CSEL_GPIO5 \ + ESP32_PINMUX(5, ESP_NOSIG, ESP_HSPICS0_OUT) + +#define SPIM2_CSEL_GPIO6 \ + ESP32_PINMUX(6, ESP_NOSIG, ESP_HSPICS0_OUT) + +#define SPIM2_CSEL_GPIO7 \ + ESP32_PINMUX(7, ESP_NOSIG, ESP_HSPICS0_OUT) + +#define SPIM2_CSEL_GPIO8 \ + ESP32_PINMUX(8, ESP_NOSIG, ESP_HSPICS0_OUT) + +#define SPIM2_CSEL_GPIO9 \ + ESP32_PINMUX(9, ESP_NOSIG, ESP_HSPICS0_OUT) + +#define SPIM2_CSEL_GPIO10 \ + ESP32_PINMUX(10, ESP_NOSIG, ESP_HSPICS0_OUT) + +#define SPIM2_CSEL_GPIO11 \ + ESP32_PINMUX(11, ESP_NOSIG, ESP_HSPICS0_OUT) + +#define SPIM2_CSEL_GPIO12 \ + ESP32_PINMUX(12, ESP_NOSIG, ESP_HSPICS0_OUT) + +#define SPIM2_CSEL_GPIO13 \ + ESP32_PINMUX(13, ESP_NOSIG, ESP_HSPICS0_OUT) + +#define SPIM2_CSEL_GPIO14 \ + ESP32_PINMUX(14, ESP_NOSIG, ESP_HSPICS0_OUT) + +#define SPIM2_CSEL_GPIO15 \ + ESP32_PINMUX(15, ESP_NOSIG, ESP_HSPICS0_OUT) + +#define SPIM2_CSEL_GPIO16 \ + ESP32_PINMUX(16, ESP_NOSIG, ESP_HSPICS0_OUT) + +#define SPIM2_CSEL_GPIO17 \ + ESP32_PINMUX(17, ESP_NOSIG, ESP_HSPICS0_OUT) + +#define SPIM2_CSEL_GPIO18 \ + ESP32_PINMUX(18, ESP_NOSIG, ESP_HSPICS0_OUT) + +#define SPIM2_CSEL_GPIO19 \ + ESP32_PINMUX(19, ESP_NOSIG, ESP_HSPICS0_OUT) + +#define SPIM2_CSEL_GPIO20 \ + ESP32_PINMUX(20, ESP_NOSIG, ESP_HSPICS0_OUT) + +#define SPIM2_CSEL_GPIO21 \ + ESP32_PINMUX(21, ESP_NOSIG, ESP_HSPICS0_OUT) + +#define SPIM2_CSEL_GPIO22 \ + ESP32_PINMUX(22, ESP_NOSIG, ESP_HSPICS0_OUT) + +#define SPIM2_CSEL_GPIO23 \ + ESP32_PINMUX(23, ESP_NOSIG, ESP_HSPICS0_OUT) + +#define SPIM2_CSEL_GPIO25 \ + ESP32_PINMUX(25, ESP_NOSIG, ESP_HSPICS0_OUT) + +#define SPIM2_CSEL_GPIO26 \ + ESP32_PINMUX(26, ESP_NOSIG, ESP_HSPICS0_OUT) + +#define SPIM2_CSEL_GPIO27 \ + ESP32_PINMUX(27, ESP_NOSIG, ESP_HSPICS0_OUT) + +#define SPIM2_CSEL_GPIO32 \ + ESP32_PINMUX(32, ESP_NOSIG, ESP_HSPICS0_OUT) + +#define SPIM2_CSEL_GPIO33 \ + ESP32_PINMUX(33, ESP_NOSIG, ESP_HSPICS0_OUT) + +/* SPIM2_CSEL1 */ +#define SPIM2_CSEL1_GPIO0 \ + ESP32_PINMUX(0, ESP_NOSIG, ESP_HSPICS1_OUT) + +#define SPIM2_CSEL1_GPIO1 \ + ESP32_PINMUX(1, ESP_NOSIG, ESP_HSPICS1_OUT) + +#define SPIM2_CSEL1_GPIO2 \ + ESP32_PINMUX(2, ESP_NOSIG, ESP_HSPICS1_OUT) + +#define SPIM2_CSEL1_GPIO3 \ + ESP32_PINMUX(3, ESP_NOSIG, ESP_HSPICS1_OUT) + +#define SPIM2_CSEL1_GPIO4 \ + ESP32_PINMUX(4, ESP_NOSIG, ESP_HSPICS1_OUT) + +#define SPIM2_CSEL1_GPIO5 \ + ESP32_PINMUX(5, ESP_NOSIG, ESP_HSPICS1_OUT) + +#define SPIM2_CSEL1_GPIO6 \ + ESP32_PINMUX(6, ESP_NOSIG, ESP_HSPICS1_OUT) + +#define SPIM2_CSEL1_GPIO7 \ + ESP32_PINMUX(7, ESP_NOSIG, ESP_HSPICS1_OUT) + +#define SPIM2_CSEL1_GPIO8 \ + ESP32_PINMUX(8, ESP_NOSIG, ESP_HSPICS1_OUT) + +#define SPIM2_CSEL1_GPIO9 \ + ESP32_PINMUX(9, ESP_NOSIG, ESP_HSPICS1_OUT) + +#define SPIM2_CSEL1_GPIO10 \ + ESP32_PINMUX(10, ESP_NOSIG, ESP_HSPICS1_OUT) + +#define SPIM2_CSEL1_GPIO11 \ + ESP32_PINMUX(11, ESP_NOSIG, ESP_HSPICS1_OUT) + +#define SPIM2_CSEL1_GPIO12 \ + ESP32_PINMUX(12, ESP_NOSIG, ESP_HSPICS1_OUT) + +#define SPIM2_CSEL1_GPIO13 \ + ESP32_PINMUX(13, ESP_NOSIG, ESP_HSPICS1_OUT) + +#define SPIM2_CSEL1_GPIO14 \ + ESP32_PINMUX(14, ESP_NOSIG, ESP_HSPICS1_OUT) + +#define SPIM2_CSEL1_GPIO15 \ + ESP32_PINMUX(15, ESP_NOSIG, ESP_HSPICS1_OUT) + +#define SPIM2_CSEL1_GPIO16 \ + ESP32_PINMUX(16, ESP_NOSIG, ESP_HSPICS1_OUT) + +#define SPIM2_CSEL1_GPIO17 \ + ESP32_PINMUX(17, ESP_NOSIG, ESP_HSPICS1_OUT) + +#define SPIM2_CSEL1_GPIO18 \ + ESP32_PINMUX(18, ESP_NOSIG, ESP_HSPICS1_OUT) + +#define SPIM2_CSEL1_GPIO19 \ + ESP32_PINMUX(19, ESP_NOSIG, ESP_HSPICS1_OUT) + +#define SPIM2_CSEL1_GPIO20 \ + ESP32_PINMUX(20, ESP_NOSIG, ESP_HSPICS1_OUT) + +#define SPIM2_CSEL1_GPIO21 \ + ESP32_PINMUX(21, ESP_NOSIG, ESP_HSPICS1_OUT) + +#define SPIM2_CSEL1_GPIO22 \ + ESP32_PINMUX(22, ESP_NOSIG, ESP_HSPICS1_OUT) + +#define SPIM2_CSEL1_GPIO23 \ + ESP32_PINMUX(23, ESP_NOSIG, ESP_HSPICS1_OUT) + +#define SPIM2_CSEL1_GPIO25 \ + ESP32_PINMUX(25, ESP_NOSIG, ESP_HSPICS1_OUT) + +#define SPIM2_CSEL1_GPIO26 \ + ESP32_PINMUX(26, ESP_NOSIG, ESP_HSPICS1_OUT) + +#define SPIM2_CSEL1_GPIO27 \ + ESP32_PINMUX(27, ESP_NOSIG, ESP_HSPICS1_OUT) + +#define SPIM2_CSEL1_GPIO32 \ + ESP32_PINMUX(32, ESP_NOSIG, ESP_HSPICS1_OUT) + +#define SPIM2_CSEL1_GPIO33 \ + ESP32_PINMUX(33, ESP_NOSIG, ESP_HSPICS1_OUT) + +/* SPIM2_CSEL2 */ +#define SPIM2_CSEL2_GPIO0 \ + ESP32_PINMUX(0, ESP_NOSIG, ESP_HSPICS2_OUT) + +#define SPIM2_CSEL2_GPIO1 \ + ESP32_PINMUX(1, ESP_NOSIG, ESP_HSPICS2_OUT) + +#define SPIM2_CSEL2_GPIO2 \ + ESP32_PINMUX(2, ESP_NOSIG, ESP_HSPICS2_OUT) + +#define SPIM2_CSEL2_GPIO3 \ + ESP32_PINMUX(3, ESP_NOSIG, ESP_HSPICS2_OUT) + +#define SPIM2_CSEL2_GPIO4 \ + ESP32_PINMUX(4, ESP_NOSIG, ESP_HSPICS2_OUT) + +#define SPIM2_CSEL2_GPIO5 \ + ESP32_PINMUX(5, ESP_NOSIG, ESP_HSPICS2_OUT) + +#define SPIM2_CSEL2_GPIO6 \ + ESP32_PINMUX(6, ESP_NOSIG, ESP_HSPICS2_OUT) + +#define SPIM2_CSEL2_GPIO7 \ + ESP32_PINMUX(7, ESP_NOSIG, ESP_HSPICS2_OUT) + +#define SPIM2_CSEL2_GPIO8 \ + ESP32_PINMUX(8, ESP_NOSIG, ESP_HSPICS2_OUT) + +#define SPIM2_CSEL2_GPIO9 \ + ESP32_PINMUX(9, ESP_NOSIG, ESP_HSPICS2_OUT) + +#define SPIM2_CSEL2_GPIO10 \ + ESP32_PINMUX(10, ESP_NOSIG, ESP_HSPICS2_OUT) + +#define SPIM2_CSEL2_GPIO11 \ + ESP32_PINMUX(11, ESP_NOSIG, ESP_HSPICS2_OUT) + +#define SPIM2_CSEL2_GPIO12 \ + ESP32_PINMUX(12, ESP_NOSIG, ESP_HSPICS2_OUT) + +#define SPIM2_CSEL2_GPIO13 \ + ESP32_PINMUX(13, ESP_NOSIG, ESP_HSPICS2_OUT) + +#define SPIM2_CSEL2_GPIO14 \ + ESP32_PINMUX(14, ESP_NOSIG, ESP_HSPICS2_OUT) + +#define SPIM2_CSEL2_GPIO15 \ + ESP32_PINMUX(15, ESP_NOSIG, ESP_HSPICS2_OUT) + +#define SPIM2_CSEL2_GPIO16 \ + ESP32_PINMUX(16, ESP_NOSIG, ESP_HSPICS2_OUT) + +#define SPIM2_CSEL2_GPIO17 \ + ESP32_PINMUX(17, ESP_NOSIG, ESP_HSPICS2_OUT) + +#define SPIM2_CSEL2_GPIO18 \ + ESP32_PINMUX(18, ESP_NOSIG, ESP_HSPICS2_OUT) + +#define SPIM2_CSEL2_GPIO19 \ + ESP32_PINMUX(19, ESP_NOSIG, ESP_HSPICS2_OUT) + +#define SPIM2_CSEL2_GPIO20 \ + ESP32_PINMUX(20, ESP_NOSIG, ESP_HSPICS2_OUT) + +#define SPIM2_CSEL2_GPIO21 \ + ESP32_PINMUX(21, ESP_NOSIG, ESP_HSPICS2_OUT) + +#define SPIM2_CSEL2_GPIO22 \ + ESP32_PINMUX(22, ESP_NOSIG, ESP_HSPICS2_OUT) + +#define SPIM2_CSEL2_GPIO23 \ + ESP32_PINMUX(23, ESP_NOSIG, ESP_HSPICS2_OUT) + +#define SPIM2_CSEL2_GPIO25 \ + ESP32_PINMUX(25, ESP_NOSIG, ESP_HSPICS2_OUT) + +#define SPIM2_CSEL2_GPIO26 \ + ESP32_PINMUX(26, ESP_NOSIG, ESP_HSPICS2_OUT) + +#define SPIM2_CSEL2_GPIO27 \ + ESP32_PINMUX(27, ESP_NOSIG, ESP_HSPICS2_OUT) + +#define SPIM2_CSEL2_GPIO32 \ + ESP32_PINMUX(32, ESP_NOSIG, ESP_HSPICS2_OUT) + +#define SPIM2_CSEL2_GPIO33 \ + ESP32_PINMUX(33, ESP_NOSIG, ESP_HSPICS2_OUT) + +/* SPIM2_MISO */ +#define SPIM2_MISO_GPIO0 \ + ESP32_PINMUX(0, ESP_HSPIQ_IN, ESP_NOSIG) + +#define SPIM2_MISO_GPIO1 \ + ESP32_PINMUX(1, ESP_HSPIQ_IN, ESP_NOSIG) + +#define SPIM2_MISO_GPIO2 \ + ESP32_PINMUX(2, ESP_HSPIQ_IN, ESP_NOSIG) + +#define SPIM2_MISO_GPIO3 \ + ESP32_PINMUX(3, ESP_HSPIQ_IN, ESP_NOSIG) + +#define SPIM2_MISO_GPIO4 \ + ESP32_PINMUX(4, ESP_HSPIQ_IN, ESP_NOSIG) + +#define SPIM2_MISO_GPIO5 \ + ESP32_PINMUX(5, ESP_HSPIQ_IN, ESP_NOSIG) + +#define SPIM2_MISO_GPIO6 \ + ESP32_PINMUX(6, ESP_HSPIQ_IN, ESP_NOSIG) + +#define SPIM2_MISO_GPIO7 \ + ESP32_PINMUX(7, ESP_HSPIQ_IN, ESP_NOSIG) + +#define SPIM2_MISO_GPIO8 \ + ESP32_PINMUX(8, ESP_HSPIQ_IN, ESP_NOSIG) + +#define SPIM2_MISO_GPIO9 \ + ESP32_PINMUX(9, ESP_HSPIQ_IN, ESP_NOSIG) + +#define SPIM2_MISO_GPIO10 \ + ESP32_PINMUX(10, ESP_HSPIQ_IN, ESP_NOSIG) + +#define SPIM2_MISO_GPIO11 \ + ESP32_PINMUX(11, ESP_HSPIQ_IN, ESP_NOSIG) + +#define SPIM2_MISO_GPIO12 \ + ESP32_PINMUX(12, ESP_HSPIQ_IN, ESP_NOSIG) + +#define SPIM2_MISO_GPIO13 \ + ESP32_PINMUX(13, ESP_HSPIQ_IN, ESP_NOSIG) + +#define SPIM2_MISO_GPIO14 \ + ESP32_PINMUX(14, ESP_HSPIQ_IN, ESP_NOSIG) + +#define SPIM2_MISO_GPIO15 \ + ESP32_PINMUX(15, ESP_HSPIQ_IN, ESP_NOSIG) + +#define SPIM2_MISO_GPIO16 \ + ESP32_PINMUX(16, ESP_HSPIQ_IN, ESP_NOSIG) + +#define SPIM2_MISO_GPIO17 \ + ESP32_PINMUX(17, ESP_HSPIQ_IN, ESP_NOSIG) + +#define SPIM2_MISO_GPIO18 \ + ESP32_PINMUX(18, ESP_HSPIQ_IN, ESP_NOSIG) + +#define SPIM2_MISO_GPIO19 \ + ESP32_PINMUX(19, ESP_HSPIQ_IN, ESP_NOSIG) + +#define SPIM2_MISO_GPIO20 \ + ESP32_PINMUX(20, ESP_HSPIQ_IN, ESP_NOSIG) + +#define SPIM2_MISO_GPIO21 \ + ESP32_PINMUX(21, ESP_HSPIQ_IN, ESP_NOSIG) + +#define SPIM2_MISO_GPIO22 \ + ESP32_PINMUX(22, ESP_HSPIQ_IN, ESP_NOSIG) + +#define SPIM2_MISO_GPIO23 \ + ESP32_PINMUX(23, ESP_HSPIQ_IN, ESP_NOSIG) + +#define SPIM2_MISO_GPIO25 \ + ESP32_PINMUX(25, ESP_HSPIQ_IN, ESP_NOSIG) + +#define SPIM2_MISO_GPIO26 \ + ESP32_PINMUX(26, ESP_HSPIQ_IN, ESP_NOSIG) + +#define SPIM2_MISO_GPIO27 \ + ESP32_PINMUX(27, ESP_HSPIQ_IN, ESP_NOSIG) + +#define SPIM2_MISO_GPIO32 \ + ESP32_PINMUX(32, ESP_HSPIQ_IN, ESP_NOSIG) + +#define SPIM2_MISO_GPIO33 \ + ESP32_PINMUX(33, ESP_HSPIQ_IN, ESP_NOSIG) + +#define SPIM2_MISO_GPIO34 \ + ESP32_PINMUX(34, ESP_HSPIQ_IN, ESP_NOSIG) + +#define SPIM2_MISO_GPIO35 \ + ESP32_PINMUX(35, ESP_HSPIQ_IN, ESP_NOSIG) + +#define SPIM2_MISO_GPIO36 \ + ESP32_PINMUX(36, ESP_HSPIQ_IN, ESP_NOSIG) + +#define SPIM2_MISO_GPIO37 \ + ESP32_PINMUX(37, ESP_HSPIQ_IN, ESP_NOSIG) + +#define SPIM2_MISO_GPIO38 \ + ESP32_PINMUX(38, ESP_HSPIQ_IN, ESP_NOSIG) + +#define SPIM2_MISO_GPIO39 \ + ESP32_PINMUX(39, ESP_HSPIQ_IN, ESP_NOSIG) + +/* SPIM2_MOSI */ +#define SPIM2_MOSI_GPIO0 \ + ESP32_PINMUX(0, ESP_NOSIG, ESP_HSPID_OUT) + +#define SPIM2_MOSI_GPIO1 \ + ESP32_PINMUX(1, ESP_NOSIG, ESP_HSPID_OUT) + +#define SPIM2_MOSI_GPIO2 \ + ESP32_PINMUX(2, ESP_NOSIG, ESP_HSPID_OUT) + +#define SPIM2_MOSI_GPIO3 \ + ESP32_PINMUX(3, ESP_NOSIG, ESP_HSPID_OUT) + +#define SPIM2_MOSI_GPIO4 \ + ESP32_PINMUX(4, ESP_NOSIG, ESP_HSPID_OUT) + +#define SPIM2_MOSI_GPIO5 \ + ESP32_PINMUX(5, ESP_NOSIG, ESP_HSPID_OUT) + +#define SPIM2_MOSI_GPIO6 \ + ESP32_PINMUX(6, ESP_NOSIG, ESP_HSPID_OUT) + +#define SPIM2_MOSI_GPIO7 \ + ESP32_PINMUX(7, ESP_NOSIG, ESP_HSPID_OUT) + +#define SPIM2_MOSI_GPIO8 \ + ESP32_PINMUX(8, ESP_NOSIG, ESP_HSPID_OUT) + +#define SPIM2_MOSI_GPIO9 \ + ESP32_PINMUX(9, ESP_NOSIG, ESP_HSPID_OUT) + +#define SPIM2_MOSI_GPIO10 \ + ESP32_PINMUX(10, ESP_NOSIG, ESP_HSPID_OUT) + +#define SPIM2_MOSI_GPIO11 \ + ESP32_PINMUX(11, ESP_NOSIG, ESP_HSPID_OUT) + +#define SPIM2_MOSI_GPIO12 \ + ESP32_PINMUX(12, ESP_NOSIG, ESP_HSPID_OUT) + +#define SPIM2_MOSI_GPIO13 \ + ESP32_PINMUX(13, ESP_NOSIG, ESP_HSPID_OUT) + +#define SPIM2_MOSI_GPIO14 \ + ESP32_PINMUX(14, ESP_NOSIG, ESP_HSPID_OUT) + +#define SPIM2_MOSI_GPIO15 \ + ESP32_PINMUX(15, ESP_NOSIG, ESP_HSPID_OUT) + +#define SPIM2_MOSI_GPIO16 \ + ESP32_PINMUX(16, ESP_NOSIG, ESP_HSPID_OUT) + +#define SPIM2_MOSI_GPIO17 \ + ESP32_PINMUX(17, ESP_NOSIG, ESP_HSPID_OUT) + +#define SPIM2_MOSI_GPIO18 \ + ESP32_PINMUX(18, ESP_NOSIG, ESP_HSPID_OUT) + +#define SPIM2_MOSI_GPIO19 \ + ESP32_PINMUX(19, ESP_NOSIG, ESP_HSPID_OUT) + +#define SPIM2_MOSI_GPIO20 \ + ESP32_PINMUX(20, ESP_NOSIG, ESP_HSPID_OUT) + +#define SPIM2_MOSI_GPIO21 \ + ESP32_PINMUX(21, ESP_NOSIG, ESP_HSPID_OUT) + +#define SPIM2_MOSI_GPIO22 \ + ESP32_PINMUX(22, ESP_NOSIG, ESP_HSPID_OUT) + +#define SPIM2_MOSI_GPIO23 \ + ESP32_PINMUX(23, ESP_NOSIG, ESP_HSPID_OUT) + +#define SPIM2_MOSI_GPIO25 \ + ESP32_PINMUX(25, ESP_NOSIG, ESP_HSPID_OUT) + +#define SPIM2_MOSI_GPIO26 \ + ESP32_PINMUX(26, ESP_NOSIG, ESP_HSPID_OUT) + +#define SPIM2_MOSI_GPIO27 \ + ESP32_PINMUX(27, ESP_NOSIG, ESP_HSPID_OUT) + +#define SPIM2_MOSI_GPIO32 \ + ESP32_PINMUX(32, ESP_NOSIG, ESP_HSPID_OUT) + +#define SPIM2_MOSI_GPIO33 \ + ESP32_PINMUX(33, ESP_NOSIG, ESP_HSPID_OUT) + +/* SPIM2_SCLK */ +#define SPIM2_SCLK_GPIO0 \ + ESP32_PINMUX(0, ESP_NOSIG, ESP_HSPICLK_OUT) + +#define SPIM2_SCLK_GPIO1 \ + ESP32_PINMUX(1, ESP_NOSIG, ESP_HSPICLK_OUT) + +#define SPIM2_SCLK_GPIO2 \ + ESP32_PINMUX(2, ESP_NOSIG, ESP_HSPICLK_OUT) + +#define SPIM2_SCLK_GPIO3 \ + ESP32_PINMUX(3, ESP_NOSIG, ESP_HSPICLK_OUT) + +#define SPIM2_SCLK_GPIO4 \ + ESP32_PINMUX(4, ESP_NOSIG, ESP_HSPICLK_OUT) + +#define SPIM2_SCLK_GPIO5 \ + ESP32_PINMUX(5, ESP_NOSIG, ESP_HSPICLK_OUT) + +#define SPIM2_SCLK_GPIO6 \ + ESP32_PINMUX(6, ESP_NOSIG, ESP_HSPICLK_OUT) + +#define SPIM2_SCLK_GPIO7 \ + ESP32_PINMUX(7, ESP_NOSIG, ESP_HSPICLK_OUT) + +#define SPIM2_SCLK_GPIO8 \ + ESP32_PINMUX(8, ESP_NOSIG, ESP_HSPICLK_OUT) + +#define SPIM2_SCLK_GPIO9 \ + ESP32_PINMUX(9, ESP_NOSIG, ESP_HSPICLK_OUT) + +#define SPIM2_SCLK_GPIO10 \ + ESP32_PINMUX(10, ESP_NOSIG, ESP_HSPICLK_OUT) + +#define SPIM2_SCLK_GPIO11 \ + ESP32_PINMUX(11, ESP_NOSIG, ESP_HSPICLK_OUT) + +#define SPIM2_SCLK_GPIO12 \ + ESP32_PINMUX(12, ESP_NOSIG, ESP_HSPICLK_OUT) + +#define SPIM2_SCLK_GPIO13 \ + ESP32_PINMUX(13, ESP_NOSIG, ESP_HSPICLK_OUT) + +#define SPIM2_SCLK_GPIO14 \ + ESP32_PINMUX(14, ESP_NOSIG, ESP_HSPICLK_OUT) + +#define SPIM2_SCLK_GPIO15 \ + ESP32_PINMUX(15, ESP_NOSIG, ESP_HSPICLK_OUT) + +#define SPIM2_SCLK_GPIO16 \ + ESP32_PINMUX(16, ESP_NOSIG, ESP_HSPICLK_OUT) + +#define SPIM2_SCLK_GPIO17 \ + ESP32_PINMUX(17, ESP_NOSIG, ESP_HSPICLK_OUT) + +#define SPIM2_SCLK_GPIO18 \ + ESP32_PINMUX(18, ESP_NOSIG, ESP_HSPICLK_OUT) + +#define SPIM2_SCLK_GPIO19 \ + ESP32_PINMUX(19, ESP_NOSIG, ESP_HSPICLK_OUT) + +#define SPIM2_SCLK_GPIO20 \ + ESP32_PINMUX(20, ESP_NOSIG, ESP_HSPICLK_OUT) + +#define SPIM2_SCLK_GPIO21 \ + ESP32_PINMUX(21, ESP_NOSIG, ESP_HSPICLK_OUT) + +#define SPIM2_SCLK_GPIO22 \ + ESP32_PINMUX(22, ESP_NOSIG, ESP_HSPICLK_OUT) + +#define SPIM2_SCLK_GPIO23 \ + ESP32_PINMUX(23, ESP_NOSIG, ESP_HSPICLK_OUT) + +#define SPIM2_SCLK_GPIO25 \ + ESP32_PINMUX(25, ESP_NOSIG, ESP_HSPICLK_OUT) + +#define SPIM2_SCLK_GPIO26 \ + ESP32_PINMUX(26, ESP_NOSIG, ESP_HSPICLK_OUT) + +#define SPIM2_SCLK_GPIO27 \ + ESP32_PINMUX(27, ESP_NOSIG, ESP_HSPICLK_OUT) + +#define SPIM2_SCLK_GPIO32 \ + ESP32_PINMUX(32, ESP_NOSIG, ESP_HSPICLK_OUT) + +#define SPIM2_SCLK_GPIO33 \ + ESP32_PINMUX(33, ESP_NOSIG, ESP_HSPICLK_OUT) + +/* SPIM3_CSEL */ +#define SPIM3_CSEL_GPIO0 \ + ESP32_PINMUX(0, ESP_NOSIG, ESP_VSPICS0_OUT) + +#define SPIM3_CSEL_GPIO1 \ + ESP32_PINMUX(1, ESP_NOSIG, ESP_VSPICS0_OUT) + +#define SPIM3_CSEL_GPIO2 \ + ESP32_PINMUX(2, ESP_NOSIG, ESP_VSPICS0_OUT) + +#define SPIM3_CSEL_GPIO3 \ + ESP32_PINMUX(3, ESP_NOSIG, ESP_VSPICS0_OUT) + +#define SPIM3_CSEL_GPIO4 \ + ESP32_PINMUX(4, ESP_NOSIG, ESP_VSPICS0_OUT) + +#define SPIM3_CSEL_GPIO5 \ + ESP32_PINMUX(5, ESP_NOSIG, ESP_VSPICS0_OUT) + +#define SPIM3_CSEL_GPIO6 \ + ESP32_PINMUX(6, ESP_NOSIG, ESP_VSPICS0_OUT) + +#define SPIM3_CSEL_GPIO7 \ + ESP32_PINMUX(7, ESP_NOSIG, ESP_VSPICS0_OUT) + +#define SPIM3_CSEL_GPIO8 \ + ESP32_PINMUX(8, ESP_NOSIG, ESP_VSPICS0_OUT) + +#define SPIM3_CSEL_GPIO9 \ + ESP32_PINMUX(9, ESP_NOSIG, ESP_VSPICS0_OUT) + +#define SPIM3_CSEL_GPIO10 \ + ESP32_PINMUX(10, ESP_NOSIG, ESP_VSPICS0_OUT) + +#define SPIM3_CSEL_GPIO11 \ + ESP32_PINMUX(11, ESP_NOSIG, ESP_VSPICS0_OUT) + +#define SPIM3_CSEL_GPIO12 \ + ESP32_PINMUX(12, ESP_NOSIG, ESP_VSPICS0_OUT) + +#define SPIM3_CSEL_GPIO13 \ + ESP32_PINMUX(13, ESP_NOSIG, ESP_VSPICS0_OUT) + +#define SPIM3_CSEL_GPIO14 \ + ESP32_PINMUX(14, ESP_NOSIG, ESP_VSPICS0_OUT) + +#define SPIM3_CSEL_GPIO15 \ + ESP32_PINMUX(15, ESP_NOSIG, ESP_VSPICS0_OUT) + +#define SPIM3_CSEL_GPIO16 \ + ESP32_PINMUX(16, ESP_NOSIG, ESP_VSPICS0_OUT) + +#define SPIM3_CSEL_GPIO17 \ + ESP32_PINMUX(17, ESP_NOSIG, ESP_VSPICS0_OUT) + +#define SPIM3_CSEL_GPIO18 \ + ESP32_PINMUX(18, ESP_NOSIG, ESP_VSPICS0_OUT) + +#define SPIM3_CSEL_GPIO19 \ + ESP32_PINMUX(19, ESP_NOSIG, ESP_VSPICS0_OUT) + +#define SPIM3_CSEL_GPIO20 \ + ESP32_PINMUX(20, ESP_NOSIG, ESP_VSPICS0_OUT) + +#define SPIM3_CSEL_GPIO21 \ + ESP32_PINMUX(21, ESP_NOSIG, ESP_VSPICS0_OUT) + +#define SPIM3_CSEL_GPIO22 \ + ESP32_PINMUX(22, ESP_NOSIG, ESP_VSPICS0_OUT) + +#define SPIM3_CSEL_GPIO23 \ + ESP32_PINMUX(23, ESP_NOSIG, ESP_VSPICS0_OUT) + +#define SPIM3_CSEL_GPIO25 \ + ESP32_PINMUX(25, ESP_NOSIG, ESP_VSPICS0_OUT) + +#define SPIM3_CSEL_GPIO26 \ + ESP32_PINMUX(26, ESP_NOSIG, ESP_VSPICS0_OUT) + +#define SPIM3_CSEL_GPIO27 \ + ESP32_PINMUX(27, ESP_NOSIG, ESP_VSPICS0_OUT) + +#define SPIM3_CSEL_GPIO32 \ + ESP32_PINMUX(32, ESP_NOSIG, ESP_VSPICS0_OUT) + +#define SPIM3_CSEL_GPIO33 \ + ESP32_PINMUX(33, ESP_NOSIG, ESP_VSPICS0_OUT) + +/* SPIM3_CSEL1 */ +#define SPIM3_CSEL1_GPIO0 \ + ESP32_PINMUX(0, ESP_NOSIG, ESP_VSPICS1_OUT) + +#define SPIM3_CSEL1_GPIO1 \ + ESP32_PINMUX(1, ESP_NOSIG, ESP_VSPICS1_OUT) + +#define SPIM3_CSEL1_GPIO2 \ + ESP32_PINMUX(2, ESP_NOSIG, ESP_VSPICS1_OUT) + +#define SPIM3_CSEL1_GPIO3 \ + ESP32_PINMUX(3, ESP_NOSIG, ESP_VSPICS1_OUT) + +#define SPIM3_CSEL1_GPIO4 \ + ESP32_PINMUX(4, ESP_NOSIG, ESP_VSPICS1_OUT) + +#define SPIM3_CSEL1_GPIO5 \ + ESP32_PINMUX(5, ESP_NOSIG, ESP_VSPICS1_OUT) + +#define SPIM3_CSEL1_GPIO6 \ + ESP32_PINMUX(6, ESP_NOSIG, ESP_VSPICS1_OUT) + +#define SPIM3_CSEL1_GPIO7 \ + ESP32_PINMUX(7, ESP_NOSIG, ESP_VSPICS1_OUT) + +#define SPIM3_CSEL1_GPIO8 \ + ESP32_PINMUX(8, ESP_NOSIG, ESP_VSPICS1_OUT) + +#define SPIM3_CSEL1_GPIO9 \ + ESP32_PINMUX(9, ESP_NOSIG, ESP_VSPICS1_OUT) + +#define SPIM3_CSEL1_GPIO10 \ + ESP32_PINMUX(10, ESP_NOSIG, ESP_VSPICS1_OUT) + +#define SPIM3_CSEL1_GPIO11 \ + ESP32_PINMUX(11, ESP_NOSIG, ESP_VSPICS1_OUT) + +#define SPIM3_CSEL1_GPIO12 \ + ESP32_PINMUX(12, ESP_NOSIG, ESP_VSPICS1_OUT) + +#define SPIM3_CSEL1_GPIO13 \ + ESP32_PINMUX(13, ESP_NOSIG, ESP_VSPICS1_OUT) + +#define SPIM3_CSEL1_GPIO14 \ + ESP32_PINMUX(14, ESP_NOSIG, ESP_VSPICS1_OUT) + +#define SPIM3_CSEL1_GPIO15 \ + ESP32_PINMUX(15, ESP_NOSIG, ESP_VSPICS1_OUT) + +#define SPIM3_CSEL1_GPIO16 \ + ESP32_PINMUX(16, ESP_NOSIG, ESP_VSPICS1_OUT) + +#define SPIM3_CSEL1_GPIO17 \ + ESP32_PINMUX(17, ESP_NOSIG, ESP_VSPICS1_OUT) + +#define SPIM3_CSEL1_GPIO18 \ + ESP32_PINMUX(18, ESP_NOSIG, ESP_VSPICS1_OUT) + +#define SPIM3_CSEL1_GPIO19 \ + ESP32_PINMUX(19, ESP_NOSIG, ESP_VSPICS1_OUT) + +#define SPIM3_CSEL1_GPIO20 \ + ESP32_PINMUX(20, ESP_NOSIG, ESP_VSPICS1_OUT) + +#define SPIM3_CSEL1_GPIO21 \ + ESP32_PINMUX(21, ESP_NOSIG, ESP_VSPICS1_OUT) + +#define SPIM3_CSEL1_GPIO22 \ + ESP32_PINMUX(22, ESP_NOSIG, ESP_VSPICS1_OUT) + +#define SPIM3_CSEL1_GPIO23 \ + ESP32_PINMUX(23, ESP_NOSIG, ESP_VSPICS1_OUT) + +#define SPIM3_CSEL1_GPIO25 \ + ESP32_PINMUX(25, ESP_NOSIG, ESP_VSPICS1_OUT) + +#define SPIM3_CSEL1_GPIO26 \ + ESP32_PINMUX(26, ESP_NOSIG, ESP_VSPICS1_OUT) + +#define SPIM3_CSEL1_GPIO27 \ + ESP32_PINMUX(27, ESP_NOSIG, ESP_VSPICS1_OUT) + +#define SPIM3_CSEL1_GPIO32 \ + ESP32_PINMUX(32, ESP_NOSIG, ESP_VSPICS1_OUT) + +#define SPIM3_CSEL1_GPIO33 \ + ESP32_PINMUX(33, ESP_NOSIG, ESP_VSPICS1_OUT) + +/* SPIM3_CSEL2 */ +#define SPIM3_CSEL2_GPIO0 \ + ESP32_PINMUX(0, ESP_NOSIG, ESP_VSPICS2_OUT) + +#define SPIM3_CSEL2_GPIO1 \ + ESP32_PINMUX(1, ESP_NOSIG, ESP_VSPICS2_OUT) + +#define SPIM3_CSEL2_GPIO2 \ + ESP32_PINMUX(2, ESP_NOSIG, ESP_VSPICS2_OUT) + +#define SPIM3_CSEL2_GPIO3 \ + ESP32_PINMUX(3, ESP_NOSIG, ESP_VSPICS2_OUT) + +#define SPIM3_CSEL2_GPIO4 \ + ESP32_PINMUX(4, ESP_NOSIG, ESP_VSPICS2_OUT) + +#define SPIM3_CSEL2_GPIO5 \ + ESP32_PINMUX(5, ESP_NOSIG, ESP_VSPICS2_OUT) + +#define SPIM3_CSEL2_GPIO6 \ + ESP32_PINMUX(6, ESP_NOSIG, ESP_VSPICS2_OUT) + +#define SPIM3_CSEL2_GPIO7 \ + ESP32_PINMUX(7, ESP_NOSIG, ESP_VSPICS2_OUT) + +#define SPIM3_CSEL2_GPIO8 \ + ESP32_PINMUX(8, ESP_NOSIG, ESP_VSPICS2_OUT) + +#define SPIM3_CSEL2_GPIO9 \ + ESP32_PINMUX(9, ESP_NOSIG, ESP_VSPICS2_OUT) + +#define SPIM3_CSEL2_GPIO10 \ + ESP32_PINMUX(10, ESP_NOSIG, ESP_VSPICS2_OUT) + +#define SPIM3_CSEL2_GPIO11 \ + ESP32_PINMUX(11, ESP_NOSIG, ESP_VSPICS2_OUT) + +#define SPIM3_CSEL2_GPIO12 \ + ESP32_PINMUX(12, ESP_NOSIG, ESP_VSPICS2_OUT) + +#define SPIM3_CSEL2_GPIO13 \ + ESP32_PINMUX(13, ESP_NOSIG, ESP_VSPICS2_OUT) + +#define SPIM3_CSEL2_GPIO14 \ + ESP32_PINMUX(14, ESP_NOSIG, ESP_VSPICS2_OUT) + +#define SPIM3_CSEL2_GPIO15 \ + ESP32_PINMUX(15, ESP_NOSIG, ESP_VSPICS2_OUT) + +#define SPIM3_CSEL2_GPIO16 \ + ESP32_PINMUX(16, ESP_NOSIG, ESP_VSPICS2_OUT) + +#define SPIM3_CSEL2_GPIO17 \ + ESP32_PINMUX(17, ESP_NOSIG, ESP_VSPICS2_OUT) + +#define SPIM3_CSEL2_GPIO18 \ + ESP32_PINMUX(18, ESP_NOSIG, ESP_VSPICS2_OUT) + +#define SPIM3_CSEL2_GPIO19 \ + ESP32_PINMUX(19, ESP_NOSIG, ESP_VSPICS2_OUT) + +#define SPIM3_CSEL2_GPIO20 \ + ESP32_PINMUX(20, ESP_NOSIG, ESP_VSPICS2_OUT) + +#define SPIM3_CSEL2_GPIO21 \ + ESP32_PINMUX(21, ESP_NOSIG, ESP_VSPICS2_OUT) + +#define SPIM3_CSEL2_GPIO22 \ + ESP32_PINMUX(22, ESP_NOSIG, ESP_VSPICS2_OUT) + +#define SPIM3_CSEL2_GPIO23 \ + ESP32_PINMUX(23, ESP_NOSIG, ESP_VSPICS2_OUT) + +#define SPIM3_CSEL2_GPIO25 \ + ESP32_PINMUX(25, ESP_NOSIG, ESP_VSPICS2_OUT) + +#define SPIM3_CSEL2_GPIO26 \ + ESP32_PINMUX(26, ESP_NOSIG, ESP_VSPICS2_OUT) + +#define SPIM3_CSEL2_GPIO27 \ + ESP32_PINMUX(27, ESP_NOSIG, ESP_VSPICS2_OUT) + +#define SPIM3_CSEL2_GPIO32 \ + ESP32_PINMUX(32, ESP_NOSIG, ESP_VSPICS2_OUT) + +#define SPIM3_CSEL2_GPIO33 \ + ESP32_PINMUX(33, ESP_NOSIG, ESP_VSPICS2_OUT) + +/* SPIM3_MISO */ +#define SPIM3_MISO_GPIO0 \ + ESP32_PINMUX(0, ESP_VSPIQ_IN, ESP_NOSIG) + +#define SPIM3_MISO_GPIO1 \ + ESP32_PINMUX(1, ESP_VSPIQ_IN, ESP_NOSIG) + +#define SPIM3_MISO_GPIO2 \ + ESP32_PINMUX(2, ESP_VSPIQ_IN, ESP_NOSIG) + +#define SPIM3_MISO_GPIO3 \ + ESP32_PINMUX(3, ESP_VSPIQ_IN, ESP_NOSIG) + +#define SPIM3_MISO_GPIO4 \ + ESP32_PINMUX(4, ESP_VSPIQ_IN, ESP_NOSIG) + +#define SPIM3_MISO_GPIO5 \ + ESP32_PINMUX(5, ESP_VSPIQ_IN, ESP_NOSIG) + +#define SPIM3_MISO_GPIO6 \ + ESP32_PINMUX(6, ESP_VSPIQ_IN, ESP_NOSIG) + +#define SPIM3_MISO_GPIO7 \ + ESP32_PINMUX(7, ESP_VSPIQ_IN, ESP_NOSIG) + +#define SPIM3_MISO_GPIO8 \ + ESP32_PINMUX(8, ESP_VSPIQ_IN, ESP_NOSIG) + +#define SPIM3_MISO_GPIO9 \ + ESP32_PINMUX(9, ESP_VSPIQ_IN, ESP_NOSIG) + +#define SPIM3_MISO_GPIO10 \ + ESP32_PINMUX(10, ESP_VSPIQ_IN, ESP_NOSIG) + +#define SPIM3_MISO_GPIO11 \ + ESP32_PINMUX(11, ESP_VSPIQ_IN, ESP_NOSIG) + +#define SPIM3_MISO_GPIO12 \ + ESP32_PINMUX(12, ESP_VSPIQ_IN, ESP_NOSIG) + +#define SPIM3_MISO_GPIO13 \ + ESP32_PINMUX(13, ESP_VSPIQ_IN, ESP_NOSIG) + +#define SPIM3_MISO_GPIO14 \ + ESP32_PINMUX(14, ESP_VSPIQ_IN, ESP_NOSIG) + +#define SPIM3_MISO_GPIO15 \ + ESP32_PINMUX(15, ESP_VSPIQ_IN, ESP_NOSIG) + +#define SPIM3_MISO_GPIO16 \ + ESP32_PINMUX(16, ESP_VSPIQ_IN, ESP_NOSIG) + +#define SPIM3_MISO_GPIO17 \ + ESP32_PINMUX(17, ESP_VSPIQ_IN, ESP_NOSIG) + +#define SPIM3_MISO_GPIO18 \ + ESP32_PINMUX(18, ESP_VSPIQ_IN, ESP_NOSIG) + +#define SPIM3_MISO_GPIO19 \ + ESP32_PINMUX(19, ESP_VSPIQ_IN, ESP_NOSIG) + +#define SPIM3_MISO_GPIO20 \ + ESP32_PINMUX(20, ESP_VSPIQ_IN, ESP_NOSIG) + +#define SPIM3_MISO_GPIO21 \ + ESP32_PINMUX(21, ESP_VSPIQ_IN, ESP_NOSIG) + +#define SPIM3_MISO_GPIO22 \ + ESP32_PINMUX(22, ESP_VSPIQ_IN, ESP_NOSIG) + +#define SPIM3_MISO_GPIO23 \ + ESP32_PINMUX(23, ESP_VSPIQ_IN, ESP_NOSIG) + +#define SPIM3_MISO_GPIO25 \ + ESP32_PINMUX(25, ESP_VSPIQ_IN, ESP_NOSIG) + +#define SPIM3_MISO_GPIO26 \ + ESP32_PINMUX(26, ESP_VSPIQ_IN, ESP_NOSIG) + +#define SPIM3_MISO_GPIO27 \ + ESP32_PINMUX(27, ESP_VSPIQ_IN, ESP_NOSIG) + +#define SPIM3_MISO_GPIO32 \ + ESP32_PINMUX(32, ESP_VSPIQ_IN, ESP_NOSIG) + +#define SPIM3_MISO_GPIO33 \ + ESP32_PINMUX(33, ESP_VSPIQ_IN, ESP_NOSIG) + +#define SPIM3_MISO_GPIO34 \ + ESP32_PINMUX(34, ESP_VSPIQ_IN, ESP_NOSIG) + +#define SPIM3_MISO_GPIO35 \ + ESP32_PINMUX(35, ESP_VSPIQ_IN, ESP_NOSIG) + +#define SPIM3_MISO_GPIO36 \ + ESP32_PINMUX(36, ESP_VSPIQ_IN, ESP_NOSIG) + +#define SPIM3_MISO_GPIO37 \ + ESP32_PINMUX(37, ESP_VSPIQ_IN, ESP_NOSIG) + +#define SPIM3_MISO_GPIO38 \ + ESP32_PINMUX(38, ESP_VSPIQ_IN, ESP_NOSIG) + +#define SPIM3_MISO_GPIO39 \ + ESP32_PINMUX(39, ESP_VSPIQ_IN, ESP_NOSIG) + +/* SPIM3_MOSI */ +#define SPIM3_MOSI_GPIO0 \ + ESP32_PINMUX(0, ESP_NOSIG, ESP_VSPID_OUT) + +#define SPIM3_MOSI_GPIO1 \ + ESP32_PINMUX(1, ESP_NOSIG, ESP_VSPID_OUT) + +#define SPIM3_MOSI_GPIO2 \ + ESP32_PINMUX(2, ESP_NOSIG, ESP_VSPID_OUT) + +#define SPIM3_MOSI_GPIO3 \ + ESP32_PINMUX(3, ESP_NOSIG, ESP_VSPID_OUT) + +#define SPIM3_MOSI_GPIO4 \ + ESP32_PINMUX(4, ESP_NOSIG, ESP_VSPID_OUT) + +#define SPIM3_MOSI_GPIO5 \ + ESP32_PINMUX(5, ESP_NOSIG, ESP_VSPID_OUT) + +#define SPIM3_MOSI_GPIO6 \ + ESP32_PINMUX(6, ESP_NOSIG, ESP_VSPID_OUT) + +#define SPIM3_MOSI_GPIO7 \ + ESP32_PINMUX(7, ESP_NOSIG, ESP_VSPID_OUT) + +#define SPIM3_MOSI_GPIO8 \ + ESP32_PINMUX(8, ESP_NOSIG, ESP_VSPID_OUT) + +#define SPIM3_MOSI_GPIO9 \ + ESP32_PINMUX(9, ESP_NOSIG, ESP_VSPID_OUT) + +#define SPIM3_MOSI_GPIO10 \ + ESP32_PINMUX(10, ESP_NOSIG, ESP_VSPID_OUT) + +#define SPIM3_MOSI_GPIO11 \ + ESP32_PINMUX(11, ESP_NOSIG, ESP_VSPID_OUT) + +#define SPIM3_MOSI_GPIO12 \ + ESP32_PINMUX(12, ESP_NOSIG, ESP_VSPID_OUT) + +#define SPIM3_MOSI_GPIO13 \ + ESP32_PINMUX(13, ESP_NOSIG, ESP_VSPID_OUT) + +#define SPIM3_MOSI_GPIO14 \ + ESP32_PINMUX(14, ESP_NOSIG, ESP_VSPID_OUT) + +#define SPIM3_MOSI_GPIO15 \ + ESP32_PINMUX(15, ESP_NOSIG, ESP_VSPID_OUT) + +#define SPIM3_MOSI_GPIO16 \ + ESP32_PINMUX(16, ESP_NOSIG, ESP_VSPID_OUT) + +#define SPIM3_MOSI_GPIO17 \ + ESP32_PINMUX(17, ESP_NOSIG, ESP_VSPID_OUT) + +#define SPIM3_MOSI_GPIO18 \ + ESP32_PINMUX(18, ESP_NOSIG, ESP_VSPID_OUT) + +#define SPIM3_MOSI_GPIO19 \ + ESP32_PINMUX(19, ESP_NOSIG, ESP_VSPID_OUT) + +#define SPIM3_MOSI_GPIO20 \ + ESP32_PINMUX(20, ESP_NOSIG, ESP_VSPID_OUT) + +#define SPIM3_MOSI_GPIO21 \ + ESP32_PINMUX(21, ESP_NOSIG, ESP_VSPID_OUT) + +#define SPIM3_MOSI_GPIO22 \ + ESP32_PINMUX(22, ESP_NOSIG, ESP_VSPID_OUT) + +#define SPIM3_MOSI_GPIO23 \ + ESP32_PINMUX(23, ESP_NOSIG, ESP_VSPID_OUT) + +#define SPIM3_MOSI_GPIO25 \ + ESP32_PINMUX(25, ESP_NOSIG, ESP_VSPID_OUT) + +#define SPIM3_MOSI_GPIO26 \ + ESP32_PINMUX(26, ESP_NOSIG, ESP_VSPID_OUT) + +#define SPIM3_MOSI_GPIO27 \ + ESP32_PINMUX(27, ESP_NOSIG, ESP_VSPID_OUT) + +#define SPIM3_MOSI_GPIO32 \ + ESP32_PINMUX(32, ESP_NOSIG, ESP_VSPID_OUT) + +#define SPIM3_MOSI_GPIO33 \ + ESP32_PINMUX(33, ESP_NOSIG, ESP_VSPID_OUT) + +/* SPIM3_SCLK */ +#define SPIM3_SCLK_GPIO0 \ + ESP32_PINMUX(0, ESP_NOSIG, ESP_VSPICLK_OUT) + +#define SPIM3_SCLK_GPIO1 \ + ESP32_PINMUX(1, ESP_NOSIG, ESP_VSPICLK_OUT) + +#define SPIM3_SCLK_GPIO2 \ + ESP32_PINMUX(2, ESP_NOSIG, ESP_VSPICLK_OUT) + +#define SPIM3_SCLK_GPIO3 \ + ESP32_PINMUX(3, ESP_NOSIG, ESP_VSPICLK_OUT) + +#define SPIM3_SCLK_GPIO4 \ + ESP32_PINMUX(4, ESP_NOSIG, ESP_VSPICLK_OUT) + +#define SPIM3_SCLK_GPIO5 \ + ESP32_PINMUX(5, ESP_NOSIG, ESP_VSPICLK_OUT) + +#define SPIM3_SCLK_GPIO6 \ + ESP32_PINMUX(6, ESP_NOSIG, ESP_VSPICLK_OUT) + +#define SPIM3_SCLK_GPIO7 \ + ESP32_PINMUX(7, ESP_NOSIG, ESP_VSPICLK_OUT) + +#define SPIM3_SCLK_GPIO8 \ + ESP32_PINMUX(8, ESP_NOSIG, ESP_VSPICLK_OUT) + +#define SPIM3_SCLK_GPIO9 \ + ESP32_PINMUX(9, ESP_NOSIG, ESP_VSPICLK_OUT) + +#define SPIM3_SCLK_GPIO10 \ + ESP32_PINMUX(10, ESP_NOSIG, ESP_VSPICLK_OUT) + +#define SPIM3_SCLK_GPIO11 \ + ESP32_PINMUX(11, ESP_NOSIG, ESP_VSPICLK_OUT) + +#define SPIM3_SCLK_GPIO12 \ + ESP32_PINMUX(12, ESP_NOSIG, ESP_VSPICLK_OUT) + +#define SPIM3_SCLK_GPIO13 \ + ESP32_PINMUX(13, ESP_NOSIG, ESP_VSPICLK_OUT) + +#define SPIM3_SCLK_GPIO14 \ + ESP32_PINMUX(14, ESP_NOSIG, ESP_VSPICLK_OUT) + +#define SPIM3_SCLK_GPIO15 \ + ESP32_PINMUX(15, ESP_NOSIG, ESP_VSPICLK_OUT) + +#define SPIM3_SCLK_GPIO16 \ + ESP32_PINMUX(16, ESP_NOSIG, ESP_VSPICLK_OUT) + +#define SPIM3_SCLK_GPIO17 \ + ESP32_PINMUX(17, ESP_NOSIG, ESP_VSPICLK_OUT) + +#define SPIM3_SCLK_GPIO18 \ + ESP32_PINMUX(18, ESP_NOSIG, ESP_VSPICLK_OUT) + +#define SPIM3_SCLK_GPIO19 \ + ESP32_PINMUX(19, ESP_NOSIG, ESP_VSPICLK_OUT) + +#define SPIM3_SCLK_GPIO20 \ + ESP32_PINMUX(20, ESP_NOSIG, ESP_VSPICLK_OUT) + +#define SPIM3_SCLK_GPIO21 \ + ESP32_PINMUX(21, ESP_NOSIG, ESP_VSPICLK_OUT) + +#define SPIM3_SCLK_GPIO22 \ + ESP32_PINMUX(22, ESP_NOSIG, ESP_VSPICLK_OUT) + +#define SPIM3_SCLK_GPIO23 \ + ESP32_PINMUX(23, ESP_NOSIG, ESP_VSPICLK_OUT) + +#define SPIM3_SCLK_GPIO25 \ + ESP32_PINMUX(25, ESP_NOSIG, ESP_VSPICLK_OUT) + +#define SPIM3_SCLK_GPIO26 \ + ESP32_PINMUX(26, ESP_NOSIG, ESP_VSPICLK_OUT) + +#define SPIM3_SCLK_GPIO27 \ + ESP32_PINMUX(27, ESP_NOSIG, ESP_VSPICLK_OUT) + +#define SPIM3_SCLK_GPIO32 \ + ESP32_PINMUX(32, ESP_NOSIG, ESP_VSPICLK_OUT) + +#define SPIM3_SCLK_GPIO33 \ + ESP32_PINMUX(33, ESP_NOSIG, ESP_VSPICLK_OUT) + +/* TWAI_BUS_OFF */ +#define TWAI_BUS_OFF_GPIO0 \ + ESP32_PINMUX(0, ESP_NOSIG, ESP_TWAI_BUS_OFF_ON) + +#define TWAI_BUS_OFF_GPIO1 \ + ESP32_PINMUX(1, ESP_NOSIG, ESP_TWAI_BUS_OFF_ON) + +#define TWAI_BUS_OFF_GPIO2 \ + ESP32_PINMUX(2, ESP_NOSIG, ESP_TWAI_BUS_OFF_ON) + +#define TWAI_BUS_OFF_GPIO3 \ + ESP32_PINMUX(3, ESP_NOSIG, ESP_TWAI_BUS_OFF_ON) + +#define TWAI_BUS_OFF_GPIO4 \ + ESP32_PINMUX(4, ESP_NOSIG, ESP_TWAI_BUS_OFF_ON) + +#define TWAI_BUS_OFF_GPIO5 \ + ESP32_PINMUX(5, ESP_NOSIG, ESP_TWAI_BUS_OFF_ON) + +#define TWAI_BUS_OFF_GPIO6 \ + ESP32_PINMUX(6, ESP_NOSIG, ESP_TWAI_BUS_OFF_ON) + +#define TWAI_BUS_OFF_GPIO7 \ + ESP32_PINMUX(7, ESP_NOSIG, ESP_TWAI_BUS_OFF_ON) + +#define TWAI_BUS_OFF_GPIO8 \ + ESP32_PINMUX(8, ESP_NOSIG, ESP_TWAI_BUS_OFF_ON) + +#define TWAI_BUS_OFF_GPIO9 \ + ESP32_PINMUX(9, ESP_NOSIG, ESP_TWAI_BUS_OFF_ON) + +#define TWAI_BUS_OFF_GPIO10 \ + ESP32_PINMUX(10, ESP_NOSIG, ESP_TWAI_BUS_OFF_ON) + +#define TWAI_BUS_OFF_GPIO11 \ + ESP32_PINMUX(11, ESP_NOSIG, ESP_TWAI_BUS_OFF_ON) + +#define TWAI_BUS_OFF_GPIO12 \ + ESP32_PINMUX(12, ESP_NOSIG, ESP_TWAI_BUS_OFF_ON) + +#define TWAI_BUS_OFF_GPIO13 \ + ESP32_PINMUX(13, ESP_NOSIG, ESP_TWAI_BUS_OFF_ON) + +#define TWAI_BUS_OFF_GPIO14 \ + ESP32_PINMUX(14, ESP_NOSIG, ESP_TWAI_BUS_OFF_ON) + +#define TWAI_BUS_OFF_GPIO15 \ + ESP32_PINMUX(15, ESP_NOSIG, ESP_TWAI_BUS_OFF_ON) + +#define TWAI_BUS_OFF_GPIO16 \ + ESP32_PINMUX(16, ESP_NOSIG, ESP_TWAI_BUS_OFF_ON) + +#define TWAI_BUS_OFF_GPIO17 \ + ESP32_PINMUX(17, ESP_NOSIG, ESP_TWAI_BUS_OFF_ON) + +#define TWAI_BUS_OFF_GPIO18 \ + ESP32_PINMUX(18, ESP_NOSIG, ESP_TWAI_BUS_OFF_ON) + +#define TWAI_BUS_OFF_GPIO19 \ + ESP32_PINMUX(19, ESP_NOSIG, ESP_TWAI_BUS_OFF_ON) + +#define TWAI_BUS_OFF_GPIO20 \ + ESP32_PINMUX(20, ESP_NOSIG, ESP_TWAI_BUS_OFF_ON) + +#define TWAI_BUS_OFF_GPIO21 \ + ESP32_PINMUX(21, ESP_NOSIG, ESP_TWAI_BUS_OFF_ON) + +#define TWAI_BUS_OFF_GPIO22 \ + ESP32_PINMUX(22, ESP_NOSIG, ESP_TWAI_BUS_OFF_ON) + +#define TWAI_BUS_OFF_GPIO23 \ + ESP32_PINMUX(23, ESP_NOSIG, ESP_TWAI_BUS_OFF_ON) + +#define TWAI_BUS_OFF_GPIO25 \ + ESP32_PINMUX(25, ESP_NOSIG, ESP_TWAI_BUS_OFF_ON) + +#define TWAI_BUS_OFF_GPIO26 \ + ESP32_PINMUX(26, ESP_NOSIG, ESP_TWAI_BUS_OFF_ON) + +#define TWAI_BUS_OFF_GPIO27 \ + ESP32_PINMUX(27, ESP_NOSIG, ESP_TWAI_BUS_OFF_ON) + +#define TWAI_BUS_OFF_GPIO32 \ + ESP32_PINMUX(32, ESP_NOSIG, ESP_TWAI_BUS_OFF_ON) + +#define TWAI_BUS_OFF_GPIO33 \ + ESP32_PINMUX(33, ESP_NOSIG, ESP_TWAI_BUS_OFF_ON) + +/* TWAI_CLKOUT */ +#define TWAI_CLKOUT_GPIO0 \ + ESP32_PINMUX(0, ESP_NOSIG, ESP_TWAI_CLKOUT) + +#define TWAI_CLKOUT_GPIO1 \ + ESP32_PINMUX(1, ESP_NOSIG, ESP_TWAI_CLKOUT) + +#define TWAI_CLKOUT_GPIO2 \ + ESP32_PINMUX(2, ESP_NOSIG, ESP_TWAI_CLKOUT) + +#define TWAI_CLKOUT_GPIO3 \ + ESP32_PINMUX(3, ESP_NOSIG, ESP_TWAI_CLKOUT) + +#define TWAI_CLKOUT_GPIO4 \ + ESP32_PINMUX(4, ESP_NOSIG, ESP_TWAI_CLKOUT) + +#define TWAI_CLKOUT_GPIO5 \ + ESP32_PINMUX(5, ESP_NOSIG, ESP_TWAI_CLKOUT) + +#define TWAI_CLKOUT_GPIO6 \ + ESP32_PINMUX(6, ESP_NOSIG, ESP_TWAI_CLKOUT) + +#define TWAI_CLKOUT_GPIO7 \ + ESP32_PINMUX(7, ESP_NOSIG, ESP_TWAI_CLKOUT) + +#define TWAI_CLKOUT_GPIO8 \ + ESP32_PINMUX(8, ESP_NOSIG, ESP_TWAI_CLKOUT) + +#define TWAI_CLKOUT_GPIO9 \ + ESP32_PINMUX(9, ESP_NOSIG, ESP_TWAI_CLKOUT) + +#define TWAI_CLKOUT_GPIO10 \ + ESP32_PINMUX(10, ESP_NOSIG, ESP_TWAI_CLKOUT) + +#define TWAI_CLKOUT_GPIO11 \ + ESP32_PINMUX(11, ESP_NOSIG, ESP_TWAI_CLKOUT) + +#define TWAI_CLKOUT_GPIO12 \ + ESP32_PINMUX(12, ESP_NOSIG, ESP_TWAI_CLKOUT) + +#define TWAI_CLKOUT_GPIO13 \ + ESP32_PINMUX(13, ESP_NOSIG, ESP_TWAI_CLKOUT) + +#define TWAI_CLKOUT_GPIO14 \ + ESP32_PINMUX(14, ESP_NOSIG, ESP_TWAI_CLKOUT) + +#define TWAI_CLKOUT_GPIO15 \ + ESP32_PINMUX(15, ESP_NOSIG, ESP_TWAI_CLKOUT) + +#define TWAI_CLKOUT_GPIO16 \ + ESP32_PINMUX(16, ESP_NOSIG, ESP_TWAI_CLKOUT) + +#define TWAI_CLKOUT_GPIO17 \ + ESP32_PINMUX(17, ESP_NOSIG, ESP_TWAI_CLKOUT) + +#define TWAI_CLKOUT_GPIO18 \ + ESP32_PINMUX(18, ESP_NOSIG, ESP_TWAI_CLKOUT) + +#define TWAI_CLKOUT_GPIO19 \ + ESP32_PINMUX(19, ESP_NOSIG, ESP_TWAI_CLKOUT) + +#define TWAI_CLKOUT_GPIO20 \ + ESP32_PINMUX(20, ESP_NOSIG, ESP_TWAI_CLKOUT) + +#define TWAI_CLKOUT_GPIO21 \ + ESP32_PINMUX(21, ESP_NOSIG, ESP_TWAI_CLKOUT) + +#define TWAI_CLKOUT_GPIO22 \ + ESP32_PINMUX(22, ESP_NOSIG, ESP_TWAI_CLKOUT) + +#define TWAI_CLKOUT_GPIO23 \ + ESP32_PINMUX(23, ESP_NOSIG, ESP_TWAI_CLKOUT) + +#define TWAI_CLKOUT_GPIO25 \ + ESP32_PINMUX(25, ESP_NOSIG, ESP_TWAI_CLKOUT) + +#define TWAI_CLKOUT_GPIO26 \ + ESP32_PINMUX(26, ESP_NOSIG, ESP_TWAI_CLKOUT) + +#define TWAI_CLKOUT_GPIO27 \ + ESP32_PINMUX(27, ESP_NOSIG, ESP_TWAI_CLKOUT) + +#define TWAI_CLKOUT_GPIO32 \ + ESP32_PINMUX(32, ESP_NOSIG, ESP_TWAI_CLKOUT) + +#define TWAI_CLKOUT_GPIO33 \ + ESP32_PINMUX(33, ESP_NOSIG, ESP_TWAI_CLKOUT) + +/* TWAI_RX */ +#define TWAI_RX_GPIO0 \ + ESP32_PINMUX(0, ESP_TWAI_RX, ESP_NOSIG) + +#define TWAI_RX_GPIO1 \ + ESP32_PINMUX(1, ESP_TWAI_RX, ESP_NOSIG) + +#define TWAI_RX_GPIO2 \ + ESP32_PINMUX(2, ESP_TWAI_RX, ESP_NOSIG) + +#define TWAI_RX_GPIO3 \ + ESP32_PINMUX(3, ESP_TWAI_RX, ESP_NOSIG) + +#define TWAI_RX_GPIO4 \ + ESP32_PINMUX(4, ESP_TWAI_RX, ESP_NOSIG) + +#define TWAI_RX_GPIO5 \ + ESP32_PINMUX(5, ESP_TWAI_RX, ESP_NOSIG) + +#define TWAI_RX_GPIO6 \ + ESP32_PINMUX(6, ESP_TWAI_RX, ESP_NOSIG) + +#define TWAI_RX_GPIO7 \ + ESP32_PINMUX(7, ESP_TWAI_RX, ESP_NOSIG) + +#define TWAI_RX_GPIO8 \ + ESP32_PINMUX(8, ESP_TWAI_RX, ESP_NOSIG) + +#define TWAI_RX_GPIO9 \ + ESP32_PINMUX(9, ESP_TWAI_RX, ESP_NOSIG) + +#define TWAI_RX_GPIO10 \ + ESP32_PINMUX(10, ESP_TWAI_RX, ESP_NOSIG) + +#define TWAI_RX_GPIO11 \ + ESP32_PINMUX(11, ESP_TWAI_RX, ESP_NOSIG) + +#define TWAI_RX_GPIO12 \ + ESP32_PINMUX(12, ESP_TWAI_RX, ESP_NOSIG) + +#define TWAI_RX_GPIO13 \ + ESP32_PINMUX(13, ESP_TWAI_RX, ESP_NOSIG) + +#define TWAI_RX_GPIO14 \ + ESP32_PINMUX(14, ESP_TWAI_RX, ESP_NOSIG) + +#define TWAI_RX_GPIO15 \ + ESP32_PINMUX(15, ESP_TWAI_RX, ESP_NOSIG) + +#define TWAI_RX_GPIO16 \ + ESP32_PINMUX(16, ESP_TWAI_RX, ESP_NOSIG) + +#define TWAI_RX_GPIO17 \ + ESP32_PINMUX(17, ESP_TWAI_RX, ESP_NOSIG) + +#define TWAI_RX_GPIO18 \ + ESP32_PINMUX(18, ESP_TWAI_RX, ESP_NOSIG) + +#define TWAI_RX_GPIO19 \ + ESP32_PINMUX(19, ESP_TWAI_RX, ESP_NOSIG) + +#define TWAI_RX_GPIO20 \ + ESP32_PINMUX(20, ESP_TWAI_RX, ESP_NOSIG) + +#define TWAI_RX_GPIO21 \ + ESP32_PINMUX(21, ESP_TWAI_RX, ESP_NOSIG) + +#define TWAI_RX_GPIO22 \ + ESP32_PINMUX(22, ESP_TWAI_RX, ESP_NOSIG) + +#define TWAI_RX_GPIO23 \ + ESP32_PINMUX(23, ESP_TWAI_RX, ESP_NOSIG) + +#define TWAI_RX_GPIO25 \ + ESP32_PINMUX(25, ESP_TWAI_RX, ESP_NOSIG) + +#define TWAI_RX_GPIO26 \ + ESP32_PINMUX(26, ESP_TWAI_RX, ESP_NOSIG) + +#define TWAI_RX_GPIO27 \ + ESP32_PINMUX(27, ESP_TWAI_RX, ESP_NOSIG) + +#define TWAI_RX_GPIO32 \ + ESP32_PINMUX(32, ESP_TWAI_RX, ESP_NOSIG) + +#define TWAI_RX_GPIO33 \ + ESP32_PINMUX(33, ESP_TWAI_RX, ESP_NOSIG) + +#define TWAI_RX_GPIO34 \ + ESP32_PINMUX(34, ESP_TWAI_RX, ESP_NOSIG) + +#define TWAI_RX_GPIO35 \ + ESP32_PINMUX(35, ESP_TWAI_RX, ESP_NOSIG) + +#define TWAI_RX_GPIO36 \ + ESP32_PINMUX(36, ESP_TWAI_RX, ESP_NOSIG) + +#define TWAI_RX_GPIO37 \ + ESP32_PINMUX(37, ESP_TWAI_RX, ESP_NOSIG) + +#define TWAI_RX_GPIO38 \ + ESP32_PINMUX(38, ESP_TWAI_RX, ESP_NOSIG) + +#define TWAI_RX_GPIO39 \ + ESP32_PINMUX(39, ESP_TWAI_RX, ESP_NOSIG) + +/* TWAI_TX */ +#define TWAI_TX_GPIO0 \ + ESP32_PINMUX(0, ESP_NOSIG, ESP_TWAI_TX) + +#define TWAI_TX_GPIO1 \ + ESP32_PINMUX(1, ESP_NOSIG, ESP_TWAI_TX) + +#define TWAI_TX_GPIO2 \ + ESP32_PINMUX(2, ESP_NOSIG, ESP_TWAI_TX) + +#define TWAI_TX_GPIO3 \ + ESP32_PINMUX(3, ESP_NOSIG, ESP_TWAI_TX) + +#define TWAI_TX_GPIO4 \ + ESP32_PINMUX(4, ESP_NOSIG, ESP_TWAI_TX) + +#define TWAI_TX_GPIO5 \ + ESP32_PINMUX(5, ESP_NOSIG, ESP_TWAI_TX) + +#define TWAI_TX_GPIO6 \ + ESP32_PINMUX(6, ESP_NOSIG, ESP_TWAI_TX) + +#define TWAI_TX_GPIO7 \ + ESP32_PINMUX(7, ESP_NOSIG, ESP_TWAI_TX) + +#define TWAI_TX_GPIO8 \ + ESP32_PINMUX(8, ESP_NOSIG, ESP_TWAI_TX) + +#define TWAI_TX_GPIO9 \ + ESP32_PINMUX(9, ESP_NOSIG, ESP_TWAI_TX) + +#define TWAI_TX_GPIO10 \ + ESP32_PINMUX(10, ESP_NOSIG, ESP_TWAI_TX) + +#define TWAI_TX_GPIO11 \ + ESP32_PINMUX(11, ESP_NOSIG, ESP_TWAI_TX) + +#define TWAI_TX_GPIO12 \ + ESP32_PINMUX(12, ESP_NOSIG, ESP_TWAI_TX) + +#define TWAI_TX_GPIO13 \ + ESP32_PINMUX(13, ESP_NOSIG, ESP_TWAI_TX) + +#define TWAI_TX_GPIO14 \ + ESP32_PINMUX(14, ESP_NOSIG, ESP_TWAI_TX) + +#define TWAI_TX_GPIO15 \ + ESP32_PINMUX(15, ESP_NOSIG, ESP_TWAI_TX) + +#define TWAI_TX_GPIO16 \ + ESP32_PINMUX(16, ESP_NOSIG, ESP_TWAI_TX) + +#define TWAI_TX_GPIO17 \ + ESP32_PINMUX(17, ESP_NOSIG, ESP_TWAI_TX) + +#define TWAI_TX_GPIO18 \ + ESP32_PINMUX(18, ESP_NOSIG, ESP_TWAI_TX) + +#define TWAI_TX_GPIO19 \ + ESP32_PINMUX(19, ESP_NOSIG, ESP_TWAI_TX) + +#define TWAI_TX_GPIO20 \ + ESP32_PINMUX(20, ESP_NOSIG, ESP_TWAI_TX) + +#define TWAI_TX_GPIO21 \ + ESP32_PINMUX(21, ESP_NOSIG, ESP_TWAI_TX) + +#define TWAI_TX_GPIO22 \ + ESP32_PINMUX(22, ESP_NOSIG, ESP_TWAI_TX) + +#define TWAI_TX_GPIO23 \ + ESP32_PINMUX(23, ESP_NOSIG, ESP_TWAI_TX) + +#define TWAI_TX_GPIO25 \ + ESP32_PINMUX(25, ESP_NOSIG, ESP_TWAI_TX) + +#define TWAI_TX_GPIO26 \ + ESP32_PINMUX(26, ESP_NOSIG, ESP_TWAI_TX) + +#define TWAI_TX_GPIO27 \ + ESP32_PINMUX(27, ESP_NOSIG, ESP_TWAI_TX) + +#define TWAI_TX_GPIO32 \ + ESP32_PINMUX(32, ESP_NOSIG, ESP_TWAI_TX) + +#define TWAI_TX_GPIO33 \ + ESP32_PINMUX(33, ESP_NOSIG, ESP_TWAI_TX) + +/* UART0_CTS */ +#define UART0_CTS_GPIO0 \ + ESP32_PINMUX(0, ESP_U0CTS_IN, ESP_NOSIG) + +#define UART0_CTS_GPIO1 \ + ESP32_PINMUX(1, ESP_U0CTS_IN, ESP_NOSIG) + +#define UART0_CTS_GPIO2 \ + ESP32_PINMUX(2, ESP_U0CTS_IN, ESP_NOSIG) + +#define UART0_CTS_GPIO3 \ + ESP32_PINMUX(3, ESP_U0CTS_IN, ESP_NOSIG) + +#define UART0_CTS_GPIO4 \ + ESP32_PINMUX(4, ESP_U0CTS_IN, ESP_NOSIG) + +#define UART0_CTS_GPIO5 \ + ESP32_PINMUX(5, ESP_U0CTS_IN, ESP_NOSIG) + +#define UART0_CTS_GPIO6 \ + ESP32_PINMUX(6, ESP_U0CTS_IN, ESP_NOSIG) + +#define UART0_CTS_GPIO7 \ + ESP32_PINMUX(7, ESP_U0CTS_IN, ESP_NOSIG) + +#define UART0_CTS_GPIO8 \ + ESP32_PINMUX(8, ESP_U0CTS_IN, ESP_NOSIG) + +#define UART0_CTS_GPIO9 \ + ESP32_PINMUX(9, ESP_U0CTS_IN, ESP_NOSIG) + +#define UART0_CTS_GPIO10 \ + ESP32_PINMUX(10, ESP_U0CTS_IN, ESP_NOSIG) + +#define UART0_CTS_GPIO11 \ + ESP32_PINMUX(11, ESP_U0CTS_IN, ESP_NOSIG) + +#define UART0_CTS_GPIO12 \ + ESP32_PINMUX(12, ESP_U0CTS_IN, ESP_NOSIG) + +#define UART0_CTS_GPIO13 \ + ESP32_PINMUX(13, ESP_U0CTS_IN, ESP_NOSIG) + +#define UART0_CTS_GPIO14 \ + ESP32_PINMUX(14, ESP_U0CTS_IN, ESP_NOSIG) + +#define UART0_CTS_GPIO15 \ + ESP32_PINMUX(15, ESP_U0CTS_IN, ESP_NOSIG) + +#define UART0_CTS_GPIO16 \ + ESP32_PINMUX(16, ESP_U0CTS_IN, ESP_NOSIG) + +#define UART0_CTS_GPIO17 \ + ESP32_PINMUX(17, ESP_U0CTS_IN, ESP_NOSIG) + +#define UART0_CTS_GPIO18 \ + ESP32_PINMUX(18, ESP_U0CTS_IN, ESP_NOSIG) + +#define UART0_CTS_GPIO19 \ + ESP32_PINMUX(19, ESP_U0CTS_IN, ESP_NOSIG) + +#define UART0_CTS_GPIO20 \ + ESP32_PINMUX(20, ESP_U0CTS_IN, ESP_NOSIG) + +#define UART0_CTS_GPIO21 \ + ESP32_PINMUX(21, ESP_U0CTS_IN, ESP_NOSIG) + +#define UART0_CTS_GPIO22 \ + ESP32_PINMUX(22, ESP_U0CTS_IN, ESP_NOSIG) + +#define UART0_CTS_GPIO23 \ + ESP32_PINMUX(23, ESP_U0CTS_IN, ESP_NOSIG) + +#define UART0_CTS_GPIO25 \ + ESP32_PINMUX(25, ESP_U0CTS_IN, ESP_NOSIG) + +#define UART0_CTS_GPIO26 \ + ESP32_PINMUX(26, ESP_U0CTS_IN, ESP_NOSIG) + +#define UART0_CTS_GPIO27 \ + ESP32_PINMUX(27, ESP_U0CTS_IN, ESP_NOSIG) + +#define UART0_CTS_GPIO32 \ + ESP32_PINMUX(32, ESP_U0CTS_IN, ESP_NOSIG) + +#define UART0_CTS_GPIO33 \ + ESP32_PINMUX(33, ESP_U0CTS_IN, ESP_NOSIG) + +#define UART0_CTS_GPIO34 \ + ESP32_PINMUX(34, ESP_U0CTS_IN, ESP_NOSIG) + +#define UART0_CTS_GPIO35 \ + ESP32_PINMUX(35, ESP_U0CTS_IN, ESP_NOSIG) + +#define UART0_CTS_GPIO36 \ + ESP32_PINMUX(36, ESP_U0CTS_IN, ESP_NOSIG) + +#define UART0_CTS_GPIO37 \ + ESP32_PINMUX(37, ESP_U0CTS_IN, ESP_NOSIG) + +#define UART0_CTS_GPIO38 \ + ESP32_PINMUX(38, ESP_U0CTS_IN, ESP_NOSIG) + +#define UART0_CTS_GPIO39 \ + ESP32_PINMUX(39, ESP_U0CTS_IN, ESP_NOSIG) + +/* UART0_DSR */ +#define UART0_DSR_GPIO0 \ + ESP32_PINMUX(0, ESP_U0DSR_IN, ESP_NOSIG) + +#define UART0_DSR_GPIO1 \ + ESP32_PINMUX(1, ESP_U0DSR_IN, ESP_NOSIG) + +#define UART0_DSR_GPIO2 \ + ESP32_PINMUX(2, ESP_U0DSR_IN, ESP_NOSIG) + +#define UART0_DSR_GPIO3 \ + ESP32_PINMUX(3, ESP_U0DSR_IN, ESP_NOSIG) + +#define UART0_DSR_GPIO4 \ + ESP32_PINMUX(4, ESP_U0DSR_IN, ESP_NOSIG) + +#define UART0_DSR_GPIO5 \ + ESP32_PINMUX(5, ESP_U0DSR_IN, ESP_NOSIG) + +#define UART0_DSR_GPIO6 \ + ESP32_PINMUX(6, ESP_U0DSR_IN, ESP_NOSIG) + +#define UART0_DSR_GPIO7 \ + ESP32_PINMUX(7, ESP_U0DSR_IN, ESP_NOSIG) + +#define UART0_DSR_GPIO8 \ + ESP32_PINMUX(8, ESP_U0DSR_IN, ESP_NOSIG) + +#define UART0_DSR_GPIO9 \ + ESP32_PINMUX(9, ESP_U0DSR_IN, ESP_NOSIG) + +#define UART0_DSR_GPIO10 \ + ESP32_PINMUX(10, ESP_U0DSR_IN, ESP_NOSIG) + +#define UART0_DSR_GPIO11 \ + ESP32_PINMUX(11, ESP_U0DSR_IN, ESP_NOSIG) + +#define UART0_DSR_GPIO12 \ + ESP32_PINMUX(12, ESP_U0DSR_IN, ESP_NOSIG) + +#define UART0_DSR_GPIO13 \ + ESP32_PINMUX(13, ESP_U0DSR_IN, ESP_NOSIG) + +#define UART0_DSR_GPIO14 \ + ESP32_PINMUX(14, ESP_U0DSR_IN, ESP_NOSIG) + +#define UART0_DSR_GPIO15 \ + ESP32_PINMUX(15, ESP_U0DSR_IN, ESP_NOSIG) + +#define UART0_DSR_GPIO16 \ + ESP32_PINMUX(16, ESP_U0DSR_IN, ESP_NOSIG) + +#define UART0_DSR_GPIO17 \ + ESP32_PINMUX(17, ESP_U0DSR_IN, ESP_NOSIG) + +#define UART0_DSR_GPIO18 \ + ESP32_PINMUX(18, ESP_U0DSR_IN, ESP_NOSIG) + +#define UART0_DSR_GPIO19 \ + ESP32_PINMUX(19, ESP_U0DSR_IN, ESP_NOSIG) + +#define UART0_DSR_GPIO20 \ + ESP32_PINMUX(20, ESP_U0DSR_IN, ESP_NOSIG) + +#define UART0_DSR_GPIO21 \ + ESP32_PINMUX(21, ESP_U0DSR_IN, ESP_NOSIG) + +#define UART0_DSR_GPIO22 \ + ESP32_PINMUX(22, ESP_U0DSR_IN, ESP_NOSIG) + +#define UART0_DSR_GPIO23 \ + ESP32_PINMUX(23, ESP_U0DSR_IN, ESP_NOSIG) + +#define UART0_DSR_GPIO25 \ + ESP32_PINMUX(25, ESP_U0DSR_IN, ESP_NOSIG) + +#define UART0_DSR_GPIO26 \ + ESP32_PINMUX(26, ESP_U0DSR_IN, ESP_NOSIG) + +#define UART0_DSR_GPIO27 \ + ESP32_PINMUX(27, ESP_U0DSR_IN, ESP_NOSIG) + +#define UART0_DSR_GPIO32 \ + ESP32_PINMUX(32, ESP_U0DSR_IN, ESP_NOSIG) + +#define UART0_DSR_GPIO33 \ + ESP32_PINMUX(33, ESP_U0DSR_IN, ESP_NOSIG) + +#define UART0_DSR_GPIO34 \ + ESP32_PINMUX(34, ESP_U0DSR_IN, ESP_NOSIG) + +#define UART0_DSR_GPIO35 \ + ESP32_PINMUX(35, ESP_U0DSR_IN, ESP_NOSIG) + +#define UART0_DSR_GPIO36 \ + ESP32_PINMUX(36, ESP_U0DSR_IN, ESP_NOSIG) + +#define UART0_DSR_GPIO37 \ + ESP32_PINMUX(37, ESP_U0DSR_IN, ESP_NOSIG) + +#define UART0_DSR_GPIO38 \ + ESP32_PINMUX(38, ESP_U0DSR_IN, ESP_NOSIG) + +#define UART0_DSR_GPIO39 \ + ESP32_PINMUX(39, ESP_U0DSR_IN, ESP_NOSIG) + +/* UART0_DTR */ +#define UART0_DTR_GPIO0 \ + ESP32_PINMUX(0, ESP_NOSIG, ESP_U0DTR_OUT) + +#define UART0_DTR_GPIO1 \ + ESP32_PINMUX(1, ESP_NOSIG, ESP_U0DTR_OUT) + +#define UART0_DTR_GPIO2 \ + ESP32_PINMUX(2, ESP_NOSIG, ESP_U0DTR_OUT) + +#define UART0_DTR_GPIO3 \ + ESP32_PINMUX(3, ESP_NOSIG, ESP_U0DTR_OUT) + +#define UART0_DTR_GPIO4 \ + ESP32_PINMUX(4, ESP_NOSIG, ESP_U0DTR_OUT) + +#define UART0_DTR_GPIO5 \ + ESP32_PINMUX(5, ESP_NOSIG, ESP_U0DTR_OUT) + +#define UART0_DTR_GPIO6 \ + ESP32_PINMUX(6, ESP_NOSIG, ESP_U0DTR_OUT) + +#define UART0_DTR_GPIO7 \ + ESP32_PINMUX(7, ESP_NOSIG, ESP_U0DTR_OUT) + +#define UART0_DTR_GPIO8 \ + ESP32_PINMUX(8, ESP_NOSIG, ESP_U0DTR_OUT) + +#define UART0_DTR_GPIO9 \ + ESP32_PINMUX(9, ESP_NOSIG, ESP_U0DTR_OUT) + +#define UART0_DTR_GPIO10 \ + ESP32_PINMUX(10, ESP_NOSIG, ESP_U0DTR_OUT) + +#define UART0_DTR_GPIO11 \ + ESP32_PINMUX(11, ESP_NOSIG, ESP_U0DTR_OUT) + +#define UART0_DTR_GPIO12 \ + ESP32_PINMUX(12, ESP_NOSIG, ESP_U0DTR_OUT) + +#define UART0_DTR_GPIO13 \ + ESP32_PINMUX(13, ESP_NOSIG, ESP_U0DTR_OUT) + +#define UART0_DTR_GPIO14 \ + ESP32_PINMUX(14, ESP_NOSIG, ESP_U0DTR_OUT) + +#define UART0_DTR_GPIO15 \ + ESP32_PINMUX(15, ESP_NOSIG, ESP_U0DTR_OUT) + +#define UART0_DTR_GPIO16 \ + ESP32_PINMUX(16, ESP_NOSIG, ESP_U0DTR_OUT) + +#define UART0_DTR_GPIO17 \ + ESP32_PINMUX(17, ESP_NOSIG, ESP_U0DTR_OUT) + +#define UART0_DTR_GPIO18 \ + ESP32_PINMUX(18, ESP_NOSIG, ESP_U0DTR_OUT) + +#define UART0_DTR_GPIO19 \ + ESP32_PINMUX(19, ESP_NOSIG, ESP_U0DTR_OUT) + +#define UART0_DTR_GPIO20 \ + ESP32_PINMUX(20, ESP_NOSIG, ESP_U0DTR_OUT) + +#define UART0_DTR_GPIO21 \ + ESP32_PINMUX(21, ESP_NOSIG, ESP_U0DTR_OUT) + +#define UART0_DTR_GPIO22 \ + ESP32_PINMUX(22, ESP_NOSIG, ESP_U0DTR_OUT) + +#define UART0_DTR_GPIO23 \ + ESP32_PINMUX(23, ESP_NOSIG, ESP_U0DTR_OUT) + +#define UART0_DTR_GPIO25 \ + ESP32_PINMUX(25, ESP_NOSIG, ESP_U0DTR_OUT) + +#define UART0_DTR_GPIO26 \ + ESP32_PINMUX(26, ESP_NOSIG, ESP_U0DTR_OUT) + +#define UART0_DTR_GPIO27 \ + ESP32_PINMUX(27, ESP_NOSIG, ESP_U0DTR_OUT) + +#define UART0_DTR_GPIO32 \ + ESP32_PINMUX(32, ESP_NOSIG, ESP_U0DTR_OUT) + +#define UART0_DTR_GPIO33 \ + ESP32_PINMUX(33, ESP_NOSIG, ESP_U0DTR_OUT) + +#define UART0_DTR_GPIO34 \ + ESP32_PINMUX(34, ESP_NOSIG, ESP_U0DTR_OUT) + +#define UART0_DTR_GPIO35 \ + ESP32_PINMUX(35, ESP_NOSIG, ESP_U0DTR_OUT) + +#define UART0_DTR_GPIO36 \ + ESP32_PINMUX(36, ESP_NOSIG, ESP_U0DTR_OUT) + +#define UART0_DTR_GPIO37 \ + ESP32_PINMUX(37, ESP_NOSIG, ESP_U0DTR_OUT) + +#define UART0_DTR_GPIO38 \ + ESP32_PINMUX(38, ESP_NOSIG, ESP_U0DTR_OUT) + +#define UART0_DTR_GPIO39 \ + ESP32_PINMUX(39, ESP_NOSIG, ESP_U0DTR_OUT) + +/* UART0_RTS */ +#define UART0_RTS_GPIO0 \ + ESP32_PINMUX(0, ESP_NOSIG, ESP_U0RTS_OUT) + +#define UART0_RTS_GPIO1 \ + ESP32_PINMUX(1, ESP_NOSIG, ESP_U0RTS_OUT) + +#define UART0_RTS_GPIO2 \ + ESP32_PINMUX(2, ESP_NOSIG, ESP_U0RTS_OUT) + +#define UART0_RTS_GPIO3 \ + ESP32_PINMUX(3, ESP_NOSIG, ESP_U0RTS_OUT) + +#define UART0_RTS_GPIO4 \ + ESP32_PINMUX(4, ESP_NOSIG, ESP_U0RTS_OUT) + +#define UART0_RTS_GPIO5 \ + ESP32_PINMUX(5, ESP_NOSIG, ESP_U0RTS_OUT) + +#define UART0_RTS_GPIO6 \ + ESP32_PINMUX(6, ESP_NOSIG, ESP_U0RTS_OUT) + +#define UART0_RTS_GPIO7 \ + ESP32_PINMUX(7, ESP_NOSIG, ESP_U0RTS_OUT) + +#define UART0_RTS_GPIO8 \ + ESP32_PINMUX(8, ESP_NOSIG, ESP_U0RTS_OUT) + +#define UART0_RTS_GPIO9 \ + ESP32_PINMUX(9, ESP_NOSIG, ESP_U0RTS_OUT) + +#define UART0_RTS_GPIO10 \ + ESP32_PINMUX(10, ESP_NOSIG, ESP_U0RTS_OUT) + +#define UART0_RTS_GPIO11 \ + ESP32_PINMUX(11, ESP_NOSIG, ESP_U0RTS_OUT) + +#define UART0_RTS_GPIO12 \ + ESP32_PINMUX(12, ESP_NOSIG, ESP_U0RTS_OUT) + +#define UART0_RTS_GPIO13 \ + ESP32_PINMUX(13, ESP_NOSIG, ESP_U0RTS_OUT) + +#define UART0_RTS_GPIO14 \ + ESP32_PINMUX(14, ESP_NOSIG, ESP_U0RTS_OUT) + +#define UART0_RTS_GPIO15 \ + ESP32_PINMUX(15, ESP_NOSIG, ESP_U0RTS_OUT) + +#define UART0_RTS_GPIO16 \ + ESP32_PINMUX(16, ESP_NOSIG, ESP_U0RTS_OUT) + +#define UART0_RTS_GPIO17 \ + ESP32_PINMUX(17, ESP_NOSIG, ESP_U0RTS_OUT) + +#define UART0_RTS_GPIO18 \ + ESP32_PINMUX(18, ESP_NOSIG, ESP_U0RTS_OUT) + +#define UART0_RTS_GPIO19 \ + ESP32_PINMUX(19, ESP_NOSIG, ESP_U0RTS_OUT) + +#define UART0_RTS_GPIO20 \ + ESP32_PINMUX(20, ESP_NOSIG, ESP_U0RTS_OUT) + +#define UART0_RTS_GPIO21 \ + ESP32_PINMUX(21, ESP_NOSIG, ESP_U0RTS_OUT) + +#define UART0_RTS_GPIO22 \ + ESP32_PINMUX(22, ESP_NOSIG, ESP_U0RTS_OUT) + +#define UART0_RTS_GPIO23 \ + ESP32_PINMUX(23, ESP_NOSIG, ESP_U0RTS_OUT) + +#define UART0_RTS_GPIO25 \ + ESP32_PINMUX(25, ESP_NOSIG, ESP_U0RTS_OUT) + +#define UART0_RTS_GPIO26 \ + ESP32_PINMUX(26, ESP_NOSIG, ESP_U0RTS_OUT) + +#define UART0_RTS_GPIO27 \ + ESP32_PINMUX(27, ESP_NOSIG, ESP_U0RTS_OUT) + +#define UART0_RTS_GPIO32 \ + ESP32_PINMUX(32, ESP_NOSIG, ESP_U0RTS_OUT) + +#define UART0_RTS_GPIO33 \ + ESP32_PINMUX(33, ESP_NOSIG, ESP_U0RTS_OUT) + +/* UART0_RX */ +#define UART0_RX_GPIO0 \ + ESP32_PINMUX(0, ESP_U0RXD_IN, ESP_NOSIG) + +#define UART0_RX_GPIO1 \ + ESP32_PINMUX(1, ESP_U0RXD_IN, ESP_NOSIG) + +#define UART0_RX_GPIO2 \ + ESP32_PINMUX(2, ESP_U0RXD_IN, ESP_NOSIG) + +#define UART0_RX_GPIO3 \ + ESP32_PINMUX(3, ESP_U0RXD_IN, ESP_NOSIG) + +#define UART0_RX_GPIO4 \ + ESP32_PINMUX(4, ESP_U0RXD_IN, ESP_NOSIG) + +#define UART0_RX_GPIO5 \ + ESP32_PINMUX(5, ESP_U0RXD_IN, ESP_NOSIG) + +#define UART0_RX_GPIO6 \ + ESP32_PINMUX(6, ESP_U0RXD_IN, ESP_NOSIG) + +#define UART0_RX_GPIO7 \ + ESP32_PINMUX(7, ESP_U0RXD_IN, ESP_NOSIG) + +#define UART0_RX_GPIO8 \ + ESP32_PINMUX(8, ESP_U0RXD_IN, ESP_NOSIG) + +#define UART0_RX_GPIO9 \ + ESP32_PINMUX(9, ESP_U0RXD_IN, ESP_NOSIG) + +#define UART0_RX_GPIO10 \ + ESP32_PINMUX(10, ESP_U0RXD_IN, ESP_NOSIG) + +#define UART0_RX_GPIO11 \ + ESP32_PINMUX(11, ESP_U0RXD_IN, ESP_NOSIG) + +#define UART0_RX_GPIO12 \ + ESP32_PINMUX(12, ESP_U0RXD_IN, ESP_NOSIG) + +#define UART0_RX_GPIO13 \ + ESP32_PINMUX(13, ESP_U0RXD_IN, ESP_NOSIG) + +#define UART0_RX_GPIO14 \ + ESP32_PINMUX(14, ESP_U0RXD_IN, ESP_NOSIG) + +#define UART0_RX_GPIO15 \ + ESP32_PINMUX(15, ESP_U0RXD_IN, ESP_NOSIG) + +#define UART0_RX_GPIO16 \ + ESP32_PINMUX(16, ESP_U0RXD_IN, ESP_NOSIG) + +#define UART0_RX_GPIO17 \ + ESP32_PINMUX(17, ESP_U0RXD_IN, ESP_NOSIG) + +#define UART0_RX_GPIO18 \ + ESP32_PINMUX(18, ESP_U0RXD_IN, ESP_NOSIG) + +#define UART0_RX_GPIO19 \ + ESP32_PINMUX(19, ESP_U0RXD_IN, ESP_NOSIG) + +#define UART0_RX_GPIO20 \ + ESP32_PINMUX(20, ESP_U0RXD_IN, ESP_NOSIG) + +#define UART0_RX_GPIO21 \ + ESP32_PINMUX(21, ESP_U0RXD_IN, ESP_NOSIG) + +#define UART0_RX_GPIO22 \ + ESP32_PINMUX(22, ESP_U0RXD_IN, ESP_NOSIG) + +#define UART0_RX_GPIO23 \ + ESP32_PINMUX(23, ESP_U0RXD_IN, ESP_NOSIG) + +#define UART0_RX_GPIO25 \ + ESP32_PINMUX(25, ESP_U0RXD_IN, ESP_NOSIG) + +#define UART0_RX_GPIO26 \ + ESP32_PINMUX(26, ESP_U0RXD_IN, ESP_NOSIG) + +#define UART0_RX_GPIO27 \ + ESP32_PINMUX(27, ESP_U0RXD_IN, ESP_NOSIG) + +#define UART0_RX_GPIO32 \ + ESP32_PINMUX(32, ESP_U0RXD_IN, ESP_NOSIG) + +#define UART0_RX_GPIO33 \ + ESP32_PINMUX(33, ESP_U0RXD_IN, ESP_NOSIG) + +#define UART0_RX_GPIO34 \ + ESP32_PINMUX(34, ESP_U0RXD_IN, ESP_NOSIG) + +#define UART0_RX_GPIO35 \ + ESP32_PINMUX(35, ESP_U0RXD_IN, ESP_NOSIG) + +#define UART0_RX_GPIO36 \ + ESP32_PINMUX(36, ESP_U0RXD_IN, ESP_NOSIG) + +#define UART0_RX_GPIO37 \ + ESP32_PINMUX(37, ESP_U0RXD_IN, ESP_NOSIG) + +#define UART0_RX_GPIO38 \ + ESP32_PINMUX(38, ESP_U0RXD_IN, ESP_NOSIG) + +#define UART0_RX_GPIO39 \ + ESP32_PINMUX(39, ESP_U0RXD_IN, ESP_NOSIG) + +/* UART0_TX */ +#define UART0_TX_GPIO0 \ + ESP32_PINMUX(0, ESP_NOSIG, ESP_U0TXD_OUT) + +#define UART0_TX_GPIO1 \ + ESP32_PINMUX(1, ESP_NOSIG, ESP_U0TXD_OUT) + +#define UART0_TX_GPIO2 \ + ESP32_PINMUX(2, ESP_NOSIG, ESP_U0TXD_OUT) + +#define UART0_TX_GPIO3 \ + ESP32_PINMUX(3, ESP_NOSIG, ESP_U0TXD_OUT) + +#define UART0_TX_GPIO4 \ + ESP32_PINMUX(4, ESP_NOSIG, ESP_U0TXD_OUT) + +#define UART0_TX_GPIO5 \ + ESP32_PINMUX(5, ESP_NOSIG, ESP_U0TXD_OUT) + +#define UART0_TX_GPIO6 \ + ESP32_PINMUX(6, ESP_NOSIG, ESP_U0TXD_OUT) + +#define UART0_TX_GPIO7 \ + ESP32_PINMUX(7, ESP_NOSIG, ESP_U0TXD_OUT) + +#define UART0_TX_GPIO8 \ + ESP32_PINMUX(8, ESP_NOSIG, ESP_U0TXD_OUT) + +#define UART0_TX_GPIO9 \ + ESP32_PINMUX(9, ESP_NOSIG, ESP_U0TXD_OUT) + +#define UART0_TX_GPIO10 \ + ESP32_PINMUX(10, ESP_NOSIG, ESP_U0TXD_OUT) + +#define UART0_TX_GPIO11 \ + ESP32_PINMUX(11, ESP_NOSIG, ESP_U0TXD_OUT) + +#define UART0_TX_GPIO12 \ + ESP32_PINMUX(12, ESP_NOSIG, ESP_U0TXD_OUT) + +#define UART0_TX_GPIO13 \ + ESP32_PINMUX(13, ESP_NOSIG, ESP_U0TXD_OUT) + +#define UART0_TX_GPIO14 \ + ESP32_PINMUX(14, ESP_NOSIG, ESP_U0TXD_OUT) + +#define UART0_TX_GPIO15 \ + ESP32_PINMUX(15, ESP_NOSIG, ESP_U0TXD_OUT) + +#define UART0_TX_GPIO16 \ + ESP32_PINMUX(16, ESP_NOSIG, ESP_U0TXD_OUT) + +#define UART0_TX_GPIO17 \ + ESP32_PINMUX(17, ESP_NOSIG, ESP_U0TXD_OUT) + +#define UART0_TX_GPIO18 \ + ESP32_PINMUX(18, ESP_NOSIG, ESP_U0TXD_OUT) + +#define UART0_TX_GPIO19 \ + ESP32_PINMUX(19, ESP_NOSIG, ESP_U0TXD_OUT) + +#define UART0_TX_GPIO20 \ + ESP32_PINMUX(20, ESP_NOSIG, ESP_U0TXD_OUT) + +#define UART0_TX_GPIO21 \ + ESP32_PINMUX(21, ESP_NOSIG, ESP_U0TXD_OUT) + +#define UART0_TX_GPIO22 \ + ESP32_PINMUX(22, ESP_NOSIG, ESP_U0TXD_OUT) + +#define UART0_TX_GPIO23 \ + ESP32_PINMUX(23, ESP_NOSIG, ESP_U0TXD_OUT) + +#define UART0_TX_GPIO25 \ + ESP32_PINMUX(25, ESP_NOSIG, ESP_U0TXD_OUT) + +#define UART0_TX_GPIO26 \ + ESP32_PINMUX(26, ESP_NOSIG, ESP_U0TXD_OUT) + +#define UART0_TX_GPIO27 \ + ESP32_PINMUX(27, ESP_NOSIG, ESP_U0TXD_OUT) + +#define UART0_TX_GPIO32 \ + ESP32_PINMUX(32, ESP_NOSIG, ESP_U0TXD_OUT) + +#define UART0_TX_GPIO33 \ + ESP32_PINMUX(33, ESP_NOSIG, ESP_U0TXD_OUT) + +/* UART1_CTS */ +#define UART1_CTS_GPIO0 \ + ESP32_PINMUX(0, ESP_U1CTS_IN, ESP_NOSIG) + +#define UART1_CTS_GPIO1 \ + ESP32_PINMUX(1, ESP_U1CTS_IN, ESP_NOSIG) + +#define UART1_CTS_GPIO2 \ + ESP32_PINMUX(2, ESP_U1CTS_IN, ESP_NOSIG) + +#define UART1_CTS_GPIO3 \ + ESP32_PINMUX(3, ESP_U1CTS_IN, ESP_NOSIG) + +#define UART1_CTS_GPIO4 \ + ESP32_PINMUX(4, ESP_U1CTS_IN, ESP_NOSIG) + +#define UART1_CTS_GPIO5 \ + ESP32_PINMUX(5, ESP_U1CTS_IN, ESP_NOSIG) + +#define UART1_CTS_GPIO6 \ + ESP32_PINMUX(6, ESP_U1CTS_IN, ESP_NOSIG) + +#define UART1_CTS_GPIO7 \ + ESP32_PINMUX(7, ESP_U1CTS_IN, ESP_NOSIG) + +#define UART1_CTS_GPIO8 \ + ESP32_PINMUX(8, ESP_U1CTS_IN, ESP_NOSIG) + +#define UART1_CTS_GPIO9 \ + ESP32_PINMUX(9, ESP_U1CTS_IN, ESP_NOSIG) + +#define UART1_CTS_GPIO10 \ + ESP32_PINMUX(10, ESP_U1CTS_IN, ESP_NOSIG) + +#define UART1_CTS_GPIO11 \ + ESP32_PINMUX(11, ESP_U1CTS_IN, ESP_NOSIG) + +#define UART1_CTS_GPIO12 \ + ESP32_PINMUX(12, ESP_U1CTS_IN, ESP_NOSIG) + +#define UART1_CTS_GPIO13 \ + ESP32_PINMUX(13, ESP_U1CTS_IN, ESP_NOSIG) + +#define UART1_CTS_GPIO14 \ + ESP32_PINMUX(14, ESP_U1CTS_IN, ESP_NOSIG) + +#define UART1_CTS_GPIO15 \ + ESP32_PINMUX(15, ESP_U1CTS_IN, ESP_NOSIG) + +#define UART1_CTS_GPIO16 \ + ESP32_PINMUX(16, ESP_U1CTS_IN, ESP_NOSIG) + +#define UART1_CTS_GPIO17 \ + ESP32_PINMUX(17, ESP_U1CTS_IN, ESP_NOSIG) + +#define UART1_CTS_GPIO18 \ + ESP32_PINMUX(18, ESP_U1CTS_IN, ESP_NOSIG) + +#define UART1_CTS_GPIO19 \ + ESP32_PINMUX(19, ESP_U1CTS_IN, ESP_NOSIG) + +#define UART1_CTS_GPIO20 \ + ESP32_PINMUX(20, ESP_U1CTS_IN, ESP_NOSIG) + +#define UART1_CTS_GPIO21 \ + ESP32_PINMUX(21, ESP_U1CTS_IN, ESP_NOSIG) + +#define UART1_CTS_GPIO22 \ + ESP32_PINMUX(22, ESP_U1CTS_IN, ESP_NOSIG) + +#define UART1_CTS_GPIO23 \ + ESP32_PINMUX(23, ESP_U1CTS_IN, ESP_NOSIG) + +#define UART1_CTS_GPIO25 \ + ESP32_PINMUX(25, ESP_U1CTS_IN, ESP_NOSIG) + +#define UART1_CTS_GPIO26 \ + ESP32_PINMUX(26, ESP_U1CTS_IN, ESP_NOSIG) + +#define UART1_CTS_GPIO27 \ + ESP32_PINMUX(27, ESP_U1CTS_IN, ESP_NOSIG) + +#define UART1_CTS_GPIO32 \ + ESP32_PINMUX(32, ESP_U1CTS_IN, ESP_NOSIG) + +#define UART1_CTS_GPIO33 \ + ESP32_PINMUX(33, ESP_U1CTS_IN, ESP_NOSIG) + +#define UART1_CTS_GPIO34 \ + ESP32_PINMUX(34, ESP_U1CTS_IN, ESP_NOSIG) + +#define UART1_CTS_GPIO35 \ + ESP32_PINMUX(35, ESP_U1CTS_IN, ESP_NOSIG) + +#define UART1_CTS_GPIO36 \ + ESP32_PINMUX(36, ESP_U1CTS_IN, ESP_NOSIG) + +#define UART1_CTS_GPIO37 \ + ESP32_PINMUX(37, ESP_U1CTS_IN, ESP_NOSIG) + +#define UART1_CTS_GPIO38 \ + ESP32_PINMUX(38, ESP_U1CTS_IN, ESP_NOSIG) + +#define UART1_CTS_GPIO39 \ + ESP32_PINMUX(39, ESP_U1CTS_IN, ESP_NOSIG) + +/* UART1_DSR */ +#define UART1_DSR_GPIO0 \ + ESP32_PINMUX(0, ESP_U1DSR_IN, ESP_NOSIG) + +#define UART1_DSR_GPIO1 \ + ESP32_PINMUX(1, ESP_U1DSR_IN, ESP_NOSIG) + +#define UART1_DSR_GPIO2 \ + ESP32_PINMUX(2, ESP_U1DSR_IN, ESP_NOSIG) + +#define UART1_DSR_GPIO3 \ + ESP32_PINMUX(3, ESP_U1DSR_IN, ESP_NOSIG) + +#define UART1_DSR_GPIO4 \ + ESP32_PINMUX(4, ESP_U1DSR_IN, ESP_NOSIG) + +#define UART1_DSR_GPIO5 \ + ESP32_PINMUX(5, ESP_U1DSR_IN, ESP_NOSIG) + +#define UART1_DSR_GPIO6 \ + ESP32_PINMUX(6, ESP_U1DSR_IN, ESP_NOSIG) + +#define UART1_DSR_GPIO7 \ + ESP32_PINMUX(7, ESP_U1DSR_IN, ESP_NOSIG) + +#define UART1_DSR_GPIO8 \ + ESP32_PINMUX(8, ESP_U1DSR_IN, ESP_NOSIG) + +#define UART1_DSR_GPIO9 \ + ESP32_PINMUX(9, ESP_U1DSR_IN, ESP_NOSIG) + +#define UART1_DSR_GPIO10 \ + ESP32_PINMUX(10, ESP_U1DSR_IN, ESP_NOSIG) + +#define UART1_DSR_GPIO11 \ + ESP32_PINMUX(11, ESP_U1DSR_IN, ESP_NOSIG) + +#define UART1_DSR_GPIO12 \ + ESP32_PINMUX(12, ESP_U1DSR_IN, ESP_NOSIG) + +#define UART1_DSR_GPIO13 \ + ESP32_PINMUX(13, ESP_U1DSR_IN, ESP_NOSIG) + +#define UART1_DSR_GPIO14 \ + ESP32_PINMUX(14, ESP_U1DSR_IN, ESP_NOSIG) + +#define UART1_DSR_GPIO15 \ + ESP32_PINMUX(15, ESP_U1DSR_IN, ESP_NOSIG) + +#define UART1_DSR_GPIO16 \ + ESP32_PINMUX(16, ESP_U1DSR_IN, ESP_NOSIG) + +#define UART1_DSR_GPIO17 \ + ESP32_PINMUX(17, ESP_U1DSR_IN, ESP_NOSIG) + +#define UART1_DSR_GPIO18 \ + ESP32_PINMUX(18, ESP_U1DSR_IN, ESP_NOSIG) + +#define UART1_DSR_GPIO19 \ + ESP32_PINMUX(19, ESP_U1DSR_IN, ESP_NOSIG) + +#define UART1_DSR_GPIO20 \ + ESP32_PINMUX(20, ESP_U1DSR_IN, ESP_NOSIG) + +#define UART1_DSR_GPIO21 \ + ESP32_PINMUX(21, ESP_U1DSR_IN, ESP_NOSIG) + +#define UART1_DSR_GPIO22 \ + ESP32_PINMUX(22, ESP_U1DSR_IN, ESP_NOSIG) + +#define UART1_DSR_GPIO23 \ + ESP32_PINMUX(23, ESP_U1DSR_IN, ESP_NOSIG) + +#define UART1_DSR_GPIO25 \ + ESP32_PINMUX(25, ESP_U1DSR_IN, ESP_NOSIG) + +#define UART1_DSR_GPIO26 \ + ESP32_PINMUX(26, ESP_U1DSR_IN, ESP_NOSIG) + +#define UART1_DSR_GPIO27 \ + ESP32_PINMUX(27, ESP_U1DSR_IN, ESP_NOSIG) + +#define UART1_DSR_GPIO32 \ + ESP32_PINMUX(32, ESP_U1DSR_IN, ESP_NOSIG) + +#define UART1_DSR_GPIO33 \ + ESP32_PINMUX(33, ESP_U1DSR_IN, ESP_NOSIG) + +#define UART1_DSR_GPIO34 \ + ESP32_PINMUX(34, ESP_U1DSR_IN, ESP_NOSIG) + +#define UART1_DSR_GPIO35 \ + ESP32_PINMUX(35, ESP_U1DSR_IN, ESP_NOSIG) + +#define UART1_DSR_GPIO36 \ + ESP32_PINMUX(36, ESP_U1DSR_IN, ESP_NOSIG) + +#define UART1_DSR_GPIO37 \ + ESP32_PINMUX(37, ESP_U1DSR_IN, ESP_NOSIG) + +#define UART1_DSR_GPIO38 \ + ESP32_PINMUX(38, ESP_U1DSR_IN, ESP_NOSIG) + +#define UART1_DSR_GPIO39 \ + ESP32_PINMUX(39, ESP_U1DSR_IN, ESP_NOSIG) + +/* UART1_DTR */ +#define UART1_DTR_GPIO0 \ + ESP32_PINMUX(0, ESP_NOSIG, ESP_U1DTR_OUT) + +#define UART1_DTR_GPIO1 \ + ESP32_PINMUX(1, ESP_NOSIG, ESP_U1DTR_OUT) + +#define UART1_DTR_GPIO2 \ + ESP32_PINMUX(2, ESP_NOSIG, ESP_U1DTR_OUT) + +#define UART1_DTR_GPIO3 \ + ESP32_PINMUX(3, ESP_NOSIG, ESP_U1DTR_OUT) + +#define UART1_DTR_GPIO4 \ + ESP32_PINMUX(4, ESP_NOSIG, ESP_U1DTR_OUT) + +#define UART1_DTR_GPIO5 \ + ESP32_PINMUX(5, ESP_NOSIG, ESP_U1DTR_OUT) + +#define UART1_DTR_GPIO6 \ + ESP32_PINMUX(6, ESP_NOSIG, ESP_U1DTR_OUT) + +#define UART1_DTR_GPIO7 \ + ESP32_PINMUX(7, ESP_NOSIG, ESP_U1DTR_OUT) + +#define UART1_DTR_GPIO8 \ + ESP32_PINMUX(8, ESP_NOSIG, ESP_U1DTR_OUT) + +#define UART1_DTR_GPIO9 \ + ESP32_PINMUX(9, ESP_NOSIG, ESP_U1DTR_OUT) + +#define UART1_DTR_GPIO10 \ + ESP32_PINMUX(10, ESP_NOSIG, ESP_U1DTR_OUT) + +#define UART1_DTR_GPIO11 \ + ESP32_PINMUX(11, ESP_NOSIG, ESP_U1DTR_OUT) + +#define UART1_DTR_GPIO12 \ + ESP32_PINMUX(12, ESP_NOSIG, ESP_U1DTR_OUT) + +#define UART1_DTR_GPIO13 \ + ESP32_PINMUX(13, ESP_NOSIG, ESP_U1DTR_OUT) + +#define UART1_DTR_GPIO14 \ + ESP32_PINMUX(14, ESP_NOSIG, ESP_U1DTR_OUT) + +#define UART1_DTR_GPIO15 \ + ESP32_PINMUX(15, ESP_NOSIG, ESP_U1DTR_OUT) + +#define UART1_DTR_GPIO16 \ + ESP32_PINMUX(16, ESP_NOSIG, ESP_U1DTR_OUT) + +#define UART1_DTR_GPIO17 \ + ESP32_PINMUX(17, ESP_NOSIG, ESP_U1DTR_OUT) + +#define UART1_DTR_GPIO18 \ + ESP32_PINMUX(18, ESP_NOSIG, ESP_U1DTR_OUT) + +#define UART1_DTR_GPIO19 \ + ESP32_PINMUX(19, ESP_NOSIG, ESP_U1DTR_OUT) + +#define UART1_DTR_GPIO20 \ + ESP32_PINMUX(20, ESP_NOSIG, ESP_U1DTR_OUT) + +#define UART1_DTR_GPIO21 \ + ESP32_PINMUX(21, ESP_NOSIG, ESP_U1DTR_OUT) + +#define UART1_DTR_GPIO22 \ + ESP32_PINMUX(22, ESP_NOSIG, ESP_U1DTR_OUT) + +#define UART1_DTR_GPIO23 \ + ESP32_PINMUX(23, ESP_NOSIG, ESP_U1DTR_OUT) + +#define UART1_DTR_GPIO25 \ + ESP32_PINMUX(25, ESP_NOSIG, ESP_U1DTR_OUT) + +#define UART1_DTR_GPIO26 \ + ESP32_PINMUX(26, ESP_NOSIG, ESP_U1DTR_OUT) + +#define UART1_DTR_GPIO27 \ + ESP32_PINMUX(27, ESP_NOSIG, ESP_U1DTR_OUT) + +#define UART1_DTR_GPIO32 \ + ESP32_PINMUX(32, ESP_NOSIG, ESP_U1DTR_OUT) + +#define UART1_DTR_GPIO33 \ + ESP32_PINMUX(33, ESP_NOSIG, ESP_U1DTR_OUT) + +#define UART1_DTR_GPIO34 \ + ESP32_PINMUX(34, ESP_NOSIG, ESP_U1DTR_OUT) + +#define UART1_DTR_GPIO35 \ + ESP32_PINMUX(35, ESP_NOSIG, ESP_U1DTR_OUT) + +#define UART1_DTR_GPIO36 \ + ESP32_PINMUX(36, ESP_NOSIG, ESP_U1DTR_OUT) + +#define UART1_DTR_GPIO37 \ + ESP32_PINMUX(37, ESP_NOSIG, ESP_U1DTR_OUT) + +#define UART1_DTR_GPIO38 \ + ESP32_PINMUX(38, ESP_NOSIG, ESP_U1DTR_OUT) + +#define UART1_DTR_GPIO39 \ + ESP32_PINMUX(39, ESP_NOSIG, ESP_U1DTR_OUT) + +/* UART1_RTS */ +#define UART1_RTS_GPIO0 \ + ESP32_PINMUX(0, ESP_NOSIG, ESP_U1RTS_OUT) + +#define UART1_RTS_GPIO1 \ + ESP32_PINMUX(1, ESP_NOSIG, ESP_U1RTS_OUT) + +#define UART1_RTS_GPIO2 \ + ESP32_PINMUX(2, ESP_NOSIG, ESP_U1RTS_OUT) + +#define UART1_RTS_GPIO3 \ + ESP32_PINMUX(3, ESP_NOSIG, ESP_U1RTS_OUT) + +#define UART1_RTS_GPIO4 \ + ESP32_PINMUX(4, ESP_NOSIG, ESP_U1RTS_OUT) + +#define UART1_RTS_GPIO5 \ + ESP32_PINMUX(5, ESP_NOSIG, ESP_U1RTS_OUT) + +#define UART1_RTS_GPIO6 \ + ESP32_PINMUX(6, ESP_NOSIG, ESP_U1RTS_OUT) + +#define UART1_RTS_GPIO7 \ + ESP32_PINMUX(7, ESP_NOSIG, ESP_U1RTS_OUT) + +#define UART1_RTS_GPIO8 \ + ESP32_PINMUX(8, ESP_NOSIG, ESP_U1RTS_OUT) + +#define UART1_RTS_GPIO9 \ + ESP32_PINMUX(9, ESP_NOSIG, ESP_U1RTS_OUT) + +#define UART1_RTS_GPIO10 \ + ESP32_PINMUX(10, ESP_NOSIG, ESP_U1RTS_OUT) + +#define UART1_RTS_GPIO11 \ + ESP32_PINMUX(11, ESP_NOSIG, ESP_U1RTS_OUT) + +#define UART1_RTS_GPIO12 \ + ESP32_PINMUX(12, ESP_NOSIG, ESP_U1RTS_OUT) + +#define UART1_RTS_GPIO13 \ + ESP32_PINMUX(13, ESP_NOSIG, ESP_U1RTS_OUT) + +#define UART1_RTS_GPIO14 \ + ESP32_PINMUX(14, ESP_NOSIG, ESP_U1RTS_OUT) + +#define UART1_RTS_GPIO15 \ + ESP32_PINMUX(15, ESP_NOSIG, ESP_U1RTS_OUT) + +#define UART1_RTS_GPIO16 \ + ESP32_PINMUX(16, ESP_NOSIG, ESP_U1RTS_OUT) + +#define UART1_RTS_GPIO17 \ + ESP32_PINMUX(17, ESP_NOSIG, ESP_U1RTS_OUT) + +#define UART1_RTS_GPIO18 \ + ESP32_PINMUX(18, ESP_NOSIG, ESP_U1RTS_OUT) + +#define UART1_RTS_GPIO19 \ + ESP32_PINMUX(19, ESP_NOSIG, ESP_U1RTS_OUT) + +#define UART1_RTS_GPIO20 \ + ESP32_PINMUX(20, ESP_NOSIG, ESP_U1RTS_OUT) + +#define UART1_RTS_GPIO21 \ + ESP32_PINMUX(21, ESP_NOSIG, ESP_U1RTS_OUT) + +#define UART1_RTS_GPIO22 \ + ESP32_PINMUX(22, ESP_NOSIG, ESP_U1RTS_OUT) + +#define UART1_RTS_GPIO23 \ + ESP32_PINMUX(23, ESP_NOSIG, ESP_U1RTS_OUT) + +#define UART1_RTS_GPIO25 \ + ESP32_PINMUX(25, ESP_NOSIG, ESP_U1RTS_OUT) + +#define UART1_RTS_GPIO26 \ + ESP32_PINMUX(26, ESP_NOSIG, ESP_U1RTS_OUT) + +#define UART1_RTS_GPIO27 \ + ESP32_PINMUX(27, ESP_NOSIG, ESP_U1RTS_OUT) + +#define UART1_RTS_GPIO32 \ + ESP32_PINMUX(32, ESP_NOSIG, ESP_U1RTS_OUT) + +#define UART1_RTS_GPIO33 \ + ESP32_PINMUX(33, ESP_NOSIG, ESP_U1RTS_OUT) + +/* UART1_RX */ +#define UART1_RX_GPIO0 \ + ESP32_PINMUX(0, ESP_U1RXD_IN, ESP_NOSIG) + +#define UART1_RX_GPIO1 \ + ESP32_PINMUX(1, ESP_U1RXD_IN, ESP_NOSIG) + +#define UART1_RX_GPIO2 \ + ESP32_PINMUX(2, ESP_U1RXD_IN, ESP_NOSIG) + +#define UART1_RX_GPIO3 \ + ESP32_PINMUX(3, ESP_U1RXD_IN, ESP_NOSIG) + +#define UART1_RX_GPIO4 \ + ESP32_PINMUX(4, ESP_U1RXD_IN, ESP_NOSIG) + +#define UART1_RX_GPIO5 \ + ESP32_PINMUX(5, ESP_U1RXD_IN, ESP_NOSIG) + +#define UART1_RX_GPIO6 \ + ESP32_PINMUX(6, ESP_U1RXD_IN, ESP_NOSIG) + +#define UART1_RX_GPIO7 \ + ESP32_PINMUX(7, ESP_U1RXD_IN, ESP_NOSIG) + +#define UART1_RX_GPIO8 \ + ESP32_PINMUX(8, ESP_U1RXD_IN, ESP_NOSIG) + +#define UART1_RX_GPIO9 \ + ESP32_PINMUX(9, ESP_U1RXD_IN, ESP_NOSIG) + +#define UART1_RX_GPIO10 \ + ESP32_PINMUX(10, ESP_U1RXD_IN, ESP_NOSIG) + +#define UART1_RX_GPIO11 \ + ESP32_PINMUX(11, ESP_U1RXD_IN, ESP_NOSIG) + +#define UART1_RX_GPIO12 \ + ESP32_PINMUX(12, ESP_U1RXD_IN, ESP_NOSIG) + +#define UART1_RX_GPIO13 \ + ESP32_PINMUX(13, ESP_U1RXD_IN, ESP_NOSIG) + +#define UART1_RX_GPIO14 \ + ESP32_PINMUX(14, ESP_U1RXD_IN, ESP_NOSIG) + +#define UART1_RX_GPIO15 \ + ESP32_PINMUX(15, ESP_U1RXD_IN, ESP_NOSIG) + +#define UART1_RX_GPIO16 \ + ESP32_PINMUX(16, ESP_U1RXD_IN, ESP_NOSIG) + +#define UART1_RX_GPIO17 \ + ESP32_PINMUX(17, ESP_U1RXD_IN, ESP_NOSIG) + +#define UART1_RX_GPIO18 \ + ESP32_PINMUX(18, ESP_U1RXD_IN, ESP_NOSIG) + +#define UART1_RX_GPIO19 \ + ESP32_PINMUX(19, ESP_U1RXD_IN, ESP_NOSIG) + +#define UART1_RX_GPIO20 \ + ESP32_PINMUX(20, ESP_U1RXD_IN, ESP_NOSIG) + +#define UART1_RX_GPIO21 \ + ESP32_PINMUX(21, ESP_U1RXD_IN, ESP_NOSIG) + +#define UART1_RX_GPIO22 \ + ESP32_PINMUX(22, ESP_U1RXD_IN, ESP_NOSIG) + +#define UART1_RX_GPIO23 \ + ESP32_PINMUX(23, ESP_U1RXD_IN, ESP_NOSIG) + +#define UART1_RX_GPIO25 \ + ESP32_PINMUX(25, ESP_U1RXD_IN, ESP_NOSIG) + +#define UART1_RX_GPIO26 \ + ESP32_PINMUX(26, ESP_U1RXD_IN, ESP_NOSIG) + +#define UART1_RX_GPIO27 \ + ESP32_PINMUX(27, ESP_U1RXD_IN, ESP_NOSIG) + +#define UART1_RX_GPIO32 \ + ESP32_PINMUX(32, ESP_U1RXD_IN, ESP_NOSIG) + +#define UART1_RX_GPIO33 \ + ESP32_PINMUX(33, ESP_U1RXD_IN, ESP_NOSIG) + +#define UART1_RX_GPIO34 \ + ESP32_PINMUX(34, ESP_U1RXD_IN, ESP_NOSIG) + +#define UART1_RX_GPIO35 \ + ESP32_PINMUX(35, ESP_U1RXD_IN, ESP_NOSIG) + +#define UART1_RX_GPIO36 \ + ESP32_PINMUX(36, ESP_U1RXD_IN, ESP_NOSIG) + +#define UART1_RX_GPIO37 \ + ESP32_PINMUX(37, ESP_U1RXD_IN, ESP_NOSIG) + +#define UART1_RX_GPIO38 \ + ESP32_PINMUX(38, ESP_U1RXD_IN, ESP_NOSIG) + +#define UART1_RX_GPIO39 \ + ESP32_PINMUX(39, ESP_U1RXD_IN, ESP_NOSIG) + +/* UART1_TX */ +#define UART1_TX_GPIO0 \ + ESP32_PINMUX(0, ESP_NOSIG, ESP_U1TXD_OUT) + +#define UART1_TX_GPIO1 \ + ESP32_PINMUX(1, ESP_NOSIG, ESP_U1TXD_OUT) + +#define UART1_TX_GPIO2 \ + ESP32_PINMUX(2, ESP_NOSIG, ESP_U1TXD_OUT) + +#define UART1_TX_GPIO3 \ + ESP32_PINMUX(3, ESP_NOSIG, ESP_U1TXD_OUT) + +#define UART1_TX_GPIO4 \ + ESP32_PINMUX(4, ESP_NOSIG, ESP_U1TXD_OUT) + +#define UART1_TX_GPIO5 \ + ESP32_PINMUX(5, ESP_NOSIG, ESP_U1TXD_OUT) + +#define UART1_TX_GPIO6 \ + ESP32_PINMUX(6, ESP_NOSIG, ESP_U1TXD_OUT) + +#define UART1_TX_GPIO7 \ + ESP32_PINMUX(7, ESP_NOSIG, ESP_U1TXD_OUT) + +#define UART1_TX_GPIO8 \ + ESP32_PINMUX(8, ESP_NOSIG, ESP_U1TXD_OUT) + +#define UART1_TX_GPIO9 \ + ESP32_PINMUX(9, ESP_NOSIG, ESP_U1TXD_OUT) + +#define UART1_TX_GPIO10 \ + ESP32_PINMUX(10, ESP_NOSIG, ESP_U1TXD_OUT) + +#define UART1_TX_GPIO11 \ + ESP32_PINMUX(11, ESP_NOSIG, ESP_U1TXD_OUT) + +#define UART1_TX_GPIO12 \ + ESP32_PINMUX(12, ESP_NOSIG, ESP_U1TXD_OUT) + +#define UART1_TX_GPIO13 \ + ESP32_PINMUX(13, ESP_NOSIG, ESP_U1TXD_OUT) + +#define UART1_TX_GPIO14 \ + ESP32_PINMUX(14, ESP_NOSIG, ESP_U1TXD_OUT) + +#define UART1_TX_GPIO15 \ + ESP32_PINMUX(15, ESP_NOSIG, ESP_U1TXD_OUT) + +#define UART1_TX_GPIO16 \ + ESP32_PINMUX(16, ESP_NOSIG, ESP_U1TXD_OUT) + +#define UART1_TX_GPIO17 \ + ESP32_PINMUX(17, ESP_NOSIG, ESP_U1TXD_OUT) + +#define UART1_TX_GPIO18 \ + ESP32_PINMUX(18, ESP_NOSIG, ESP_U1TXD_OUT) + +#define UART1_TX_GPIO19 \ + ESP32_PINMUX(19, ESP_NOSIG, ESP_U1TXD_OUT) + +#define UART1_TX_GPIO20 \ + ESP32_PINMUX(20, ESP_NOSIG, ESP_U1TXD_OUT) + +#define UART1_TX_GPIO21 \ + ESP32_PINMUX(21, ESP_NOSIG, ESP_U1TXD_OUT) + +#define UART1_TX_GPIO22 \ + ESP32_PINMUX(22, ESP_NOSIG, ESP_U1TXD_OUT) + +#define UART1_TX_GPIO23 \ + ESP32_PINMUX(23, ESP_NOSIG, ESP_U1TXD_OUT) + +#define UART1_TX_GPIO25 \ + ESP32_PINMUX(25, ESP_NOSIG, ESP_U1TXD_OUT) + +#define UART1_TX_GPIO26 \ + ESP32_PINMUX(26, ESP_NOSIG, ESP_U1TXD_OUT) + +#define UART1_TX_GPIO27 \ + ESP32_PINMUX(27, ESP_NOSIG, ESP_U1TXD_OUT) + +#define UART1_TX_GPIO32 \ + ESP32_PINMUX(32, ESP_NOSIG, ESP_U1TXD_OUT) + +#define UART1_TX_GPIO33 \ + ESP32_PINMUX(33, ESP_NOSIG, ESP_U1TXD_OUT) + +/* UART2_CTS */ +#define UART2_CTS_GPIO0 \ + ESP32_PINMUX(0, ESP_U2CTS_IN, ESP_NOSIG) + +#define UART2_CTS_GPIO1 \ + ESP32_PINMUX(1, ESP_U2CTS_IN, ESP_NOSIG) + +#define UART2_CTS_GPIO2 \ + ESP32_PINMUX(2, ESP_U2CTS_IN, ESP_NOSIG) + +#define UART2_CTS_GPIO3 \ + ESP32_PINMUX(3, ESP_U2CTS_IN, ESP_NOSIG) + +#define UART2_CTS_GPIO4 \ + ESP32_PINMUX(4, ESP_U2CTS_IN, ESP_NOSIG) + +#define UART2_CTS_GPIO5 \ + ESP32_PINMUX(5, ESP_U2CTS_IN, ESP_NOSIG) + +#define UART2_CTS_GPIO6 \ + ESP32_PINMUX(6, ESP_U2CTS_IN, ESP_NOSIG) + +#define UART2_CTS_GPIO7 \ + ESP32_PINMUX(7, ESP_U2CTS_IN, ESP_NOSIG) + +#define UART2_CTS_GPIO8 \ + ESP32_PINMUX(8, ESP_U2CTS_IN, ESP_NOSIG) + +#define UART2_CTS_GPIO9 \ + ESP32_PINMUX(9, ESP_U2CTS_IN, ESP_NOSIG) + +#define UART2_CTS_GPIO10 \ + ESP32_PINMUX(10, ESP_U2CTS_IN, ESP_NOSIG) + +#define UART2_CTS_GPIO11 \ + ESP32_PINMUX(11, ESP_U2CTS_IN, ESP_NOSIG) + +#define UART2_CTS_GPIO12 \ + ESP32_PINMUX(12, ESP_U2CTS_IN, ESP_NOSIG) + +#define UART2_CTS_GPIO13 \ + ESP32_PINMUX(13, ESP_U2CTS_IN, ESP_NOSIG) + +#define UART2_CTS_GPIO14 \ + ESP32_PINMUX(14, ESP_U2CTS_IN, ESP_NOSIG) + +#define UART2_CTS_GPIO15 \ + ESP32_PINMUX(15, ESP_U2CTS_IN, ESP_NOSIG) + +#define UART2_CTS_GPIO16 \ + ESP32_PINMUX(16, ESP_U2CTS_IN, ESP_NOSIG) + +#define UART2_CTS_GPIO17 \ + ESP32_PINMUX(17, ESP_U2CTS_IN, ESP_NOSIG) + +#define UART2_CTS_GPIO18 \ + ESP32_PINMUX(18, ESP_U2CTS_IN, ESP_NOSIG) + +#define UART2_CTS_GPIO19 \ + ESP32_PINMUX(19, ESP_U2CTS_IN, ESP_NOSIG) + +#define UART2_CTS_GPIO20 \ + ESP32_PINMUX(20, ESP_U2CTS_IN, ESP_NOSIG) + +#define UART2_CTS_GPIO21 \ + ESP32_PINMUX(21, ESP_U2CTS_IN, ESP_NOSIG) + +#define UART2_CTS_GPIO22 \ + ESP32_PINMUX(22, ESP_U2CTS_IN, ESP_NOSIG) + +#define UART2_CTS_GPIO23 \ + ESP32_PINMUX(23, ESP_U2CTS_IN, ESP_NOSIG) + +#define UART2_CTS_GPIO25 \ + ESP32_PINMUX(25, ESP_U2CTS_IN, ESP_NOSIG) + +#define UART2_CTS_GPIO26 \ + ESP32_PINMUX(26, ESP_U2CTS_IN, ESP_NOSIG) + +#define UART2_CTS_GPIO27 \ + ESP32_PINMUX(27, ESP_U2CTS_IN, ESP_NOSIG) + +#define UART2_CTS_GPIO32 \ + ESP32_PINMUX(32, ESP_U2CTS_IN, ESP_NOSIG) + +#define UART2_CTS_GPIO33 \ + ESP32_PINMUX(33, ESP_U2CTS_IN, ESP_NOSIG) + +#define UART2_CTS_GPIO34 \ + ESP32_PINMUX(34, ESP_U2CTS_IN, ESP_NOSIG) + +#define UART2_CTS_GPIO35 \ + ESP32_PINMUX(35, ESP_U2CTS_IN, ESP_NOSIG) + +#define UART2_CTS_GPIO36 \ + ESP32_PINMUX(36, ESP_U2CTS_IN, ESP_NOSIG) + +#define UART2_CTS_GPIO37 \ + ESP32_PINMUX(37, ESP_U2CTS_IN, ESP_NOSIG) + +#define UART2_CTS_GPIO38 \ + ESP32_PINMUX(38, ESP_U2CTS_IN, ESP_NOSIG) + +#define UART2_CTS_GPIO39 \ + ESP32_PINMUX(39, ESP_U2CTS_IN, ESP_NOSIG) + +/* UART2_RTS */ +#define UART2_RTS_GPIO0 \ + ESP32_PINMUX(0, ESP_NOSIG, ESP_U2RTS_OUT) + +#define UART2_RTS_GPIO1 \ + ESP32_PINMUX(1, ESP_NOSIG, ESP_U2RTS_OUT) + +#define UART2_RTS_GPIO2 \ + ESP32_PINMUX(2, ESP_NOSIG, ESP_U2RTS_OUT) + +#define UART2_RTS_GPIO3 \ + ESP32_PINMUX(3, ESP_NOSIG, ESP_U2RTS_OUT) + +#define UART2_RTS_GPIO4 \ + ESP32_PINMUX(4, ESP_NOSIG, ESP_U2RTS_OUT) + +#define UART2_RTS_GPIO5 \ + ESP32_PINMUX(5, ESP_NOSIG, ESP_U2RTS_OUT) + +#define UART2_RTS_GPIO6 \ + ESP32_PINMUX(6, ESP_NOSIG, ESP_U2RTS_OUT) + +#define UART2_RTS_GPIO7 \ + ESP32_PINMUX(7, ESP_NOSIG, ESP_U2RTS_OUT) + +#define UART2_RTS_GPIO8 \ + ESP32_PINMUX(8, ESP_NOSIG, ESP_U2RTS_OUT) + +#define UART2_RTS_GPIO9 \ + ESP32_PINMUX(9, ESP_NOSIG, ESP_U2RTS_OUT) + +#define UART2_RTS_GPIO10 \ + ESP32_PINMUX(10, ESP_NOSIG, ESP_U2RTS_OUT) + +#define UART2_RTS_GPIO11 \ + ESP32_PINMUX(11, ESP_NOSIG, ESP_U2RTS_OUT) + +#define UART2_RTS_GPIO12 \ + ESP32_PINMUX(12, ESP_NOSIG, ESP_U2RTS_OUT) + +#define UART2_RTS_GPIO13 \ + ESP32_PINMUX(13, ESP_NOSIG, ESP_U2RTS_OUT) + +#define UART2_RTS_GPIO14 \ + ESP32_PINMUX(14, ESP_NOSIG, ESP_U2RTS_OUT) + +#define UART2_RTS_GPIO15 \ + ESP32_PINMUX(15, ESP_NOSIG, ESP_U2RTS_OUT) + +#define UART2_RTS_GPIO16 \ + ESP32_PINMUX(16, ESP_NOSIG, ESP_U2RTS_OUT) + +#define UART2_RTS_GPIO17 \ + ESP32_PINMUX(17, ESP_NOSIG, ESP_U2RTS_OUT) + +#define UART2_RTS_GPIO18 \ + ESP32_PINMUX(18, ESP_NOSIG, ESP_U2RTS_OUT) + +#define UART2_RTS_GPIO19 \ + ESP32_PINMUX(19, ESP_NOSIG, ESP_U2RTS_OUT) + +#define UART2_RTS_GPIO20 \ + ESP32_PINMUX(20, ESP_NOSIG, ESP_U2RTS_OUT) + +#define UART2_RTS_GPIO21 \ + ESP32_PINMUX(21, ESP_NOSIG, ESP_U2RTS_OUT) + +#define UART2_RTS_GPIO22 \ + ESP32_PINMUX(22, ESP_NOSIG, ESP_U2RTS_OUT) + +#define UART2_RTS_GPIO23 \ + ESP32_PINMUX(23, ESP_NOSIG, ESP_U2RTS_OUT) + +#define UART2_RTS_GPIO25 \ + ESP32_PINMUX(25, ESP_NOSIG, ESP_U2RTS_OUT) + +#define UART2_RTS_GPIO26 \ + ESP32_PINMUX(26, ESP_NOSIG, ESP_U2RTS_OUT) + +#define UART2_RTS_GPIO27 \ + ESP32_PINMUX(27, ESP_NOSIG, ESP_U2RTS_OUT) + +#define UART2_RTS_GPIO32 \ + ESP32_PINMUX(32, ESP_NOSIG, ESP_U2RTS_OUT) + +#define UART2_RTS_GPIO33 \ + ESP32_PINMUX(33, ESP_NOSIG, ESP_U2RTS_OUT) + +/* UART2_RX */ +#define UART2_RX_GPIO0 \ + ESP32_PINMUX(0, ESP_U2RXD_IN, ESP_NOSIG) + +#define UART2_RX_GPIO1 \ + ESP32_PINMUX(1, ESP_U2RXD_IN, ESP_NOSIG) + +#define UART2_RX_GPIO2 \ + ESP32_PINMUX(2, ESP_U2RXD_IN, ESP_NOSIG) + +#define UART2_RX_GPIO3 \ + ESP32_PINMUX(3, ESP_U2RXD_IN, ESP_NOSIG) + +#define UART2_RX_GPIO4 \ + ESP32_PINMUX(4, ESP_U2RXD_IN, ESP_NOSIG) + +#define UART2_RX_GPIO5 \ + ESP32_PINMUX(5, ESP_U2RXD_IN, ESP_NOSIG) + +#define UART2_RX_GPIO6 \ + ESP32_PINMUX(6, ESP_U2RXD_IN, ESP_NOSIG) + +#define UART2_RX_GPIO7 \ + ESP32_PINMUX(7, ESP_U2RXD_IN, ESP_NOSIG) + +#define UART2_RX_GPIO8 \ + ESP32_PINMUX(8, ESP_U2RXD_IN, ESP_NOSIG) + +#define UART2_RX_GPIO9 \ + ESP32_PINMUX(9, ESP_U2RXD_IN, ESP_NOSIG) + +#define UART2_RX_GPIO10 \ + ESP32_PINMUX(10, ESP_U2RXD_IN, ESP_NOSIG) + +#define UART2_RX_GPIO11 \ + ESP32_PINMUX(11, ESP_U2RXD_IN, ESP_NOSIG) + +#define UART2_RX_GPIO12 \ + ESP32_PINMUX(12, ESP_U2RXD_IN, ESP_NOSIG) + +#define UART2_RX_GPIO13 \ + ESP32_PINMUX(13, ESP_U2RXD_IN, ESP_NOSIG) + +#define UART2_RX_GPIO14 \ + ESP32_PINMUX(14, ESP_U2RXD_IN, ESP_NOSIG) + +#define UART2_RX_GPIO15 \ + ESP32_PINMUX(15, ESP_U2RXD_IN, ESP_NOSIG) + +#define UART2_RX_GPIO16 \ + ESP32_PINMUX(16, ESP_U2RXD_IN, ESP_NOSIG) + +#define UART2_RX_GPIO17 \ + ESP32_PINMUX(17, ESP_U2RXD_IN, ESP_NOSIG) + +#define UART2_RX_GPIO18 \ + ESP32_PINMUX(18, ESP_U2RXD_IN, ESP_NOSIG) + +#define UART2_RX_GPIO19 \ + ESP32_PINMUX(19, ESP_U2RXD_IN, ESP_NOSIG) + +#define UART2_RX_GPIO20 \ + ESP32_PINMUX(20, ESP_U2RXD_IN, ESP_NOSIG) + +#define UART2_RX_GPIO21 \ + ESP32_PINMUX(21, ESP_U2RXD_IN, ESP_NOSIG) + +#define UART2_RX_GPIO22 \ + ESP32_PINMUX(22, ESP_U2RXD_IN, ESP_NOSIG) + +#define UART2_RX_GPIO23 \ + ESP32_PINMUX(23, ESP_U2RXD_IN, ESP_NOSIG) + +#define UART2_RX_GPIO25 \ + ESP32_PINMUX(25, ESP_U2RXD_IN, ESP_NOSIG) + +#define UART2_RX_GPIO26 \ + ESP32_PINMUX(26, ESP_U2RXD_IN, ESP_NOSIG) + +#define UART2_RX_GPIO27 \ + ESP32_PINMUX(27, ESP_U2RXD_IN, ESP_NOSIG) + +#define UART2_RX_GPIO32 \ + ESP32_PINMUX(32, ESP_U2RXD_IN, ESP_NOSIG) + +#define UART2_RX_GPIO33 \ + ESP32_PINMUX(33, ESP_U2RXD_IN, ESP_NOSIG) + +#define UART2_RX_GPIO34 \ + ESP32_PINMUX(34, ESP_U2RXD_IN, ESP_NOSIG) + +#define UART2_RX_GPIO35 \ + ESP32_PINMUX(35, ESP_U2RXD_IN, ESP_NOSIG) + +#define UART2_RX_GPIO36 \ + ESP32_PINMUX(36, ESP_U2RXD_IN, ESP_NOSIG) + +#define UART2_RX_GPIO37 \ + ESP32_PINMUX(37, ESP_U2RXD_IN, ESP_NOSIG) + +#define UART2_RX_GPIO38 \ + ESP32_PINMUX(38, ESP_U2RXD_IN, ESP_NOSIG) + +#define UART2_RX_GPIO39 \ + ESP32_PINMUX(39, ESP_U2RXD_IN, ESP_NOSIG) + +/* UART2_TX */ +#define UART2_TX_GPIO0 \ + ESP32_PINMUX(0, ESP_NOSIG, ESP_U2TXD_OUT) + +#define UART2_TX_GPIO1 \ + ESP32_PINMUX(1, ESP_NOSIG, ESP_U2TXD_OUT) + +#define UART2_TX_GPIO2 \ + ESP32_PINMUX(2, ESP_NOSIG, ESP_U2TXD_OUT) + +#define UART2_TX_GPIO3 \ + ESP32_PINMUX(3, ESP_NOSIG, ESP_U2TXD_OUT) + +#define UART2_TX_GPIO4 \ + ESP32_PINMUX(4, ESP_NOSIG, ESP_U2TXD_OUT) + +#define UART2_TX_GPIO5 \ + ESP32_PINMUX(5, ESP_NOSIG, ESP_U2TXD_OUT) + +#define UART2_TX_GPIO6 \ + ESP32_PINMUX(6, ESP_NOSIG, ESP_U2TXD_OUT) + +#define UART2_TX_GPIO7 \ + ESP32_PINMUX(7, ESP_NOSIG, ESP_U2TXD_OUT) + +#define UART2_TX_GPIO8 \ + ESP32_PINMUX(8, ESP_NOSIG, ESP_U2TXD_OUT) + +#define UART2_TX_GPIO9 \ + ESP32_PINMUX(9, ESP_NOSIG, ESP_U2TXD_OUT) + +#define UART2_TX_GPIO10 \ + ESP32_PINMUX(10, ESP_NOSIG, ESP_U2TXD_OUT) + +#define UART2_TX_GPIO11 \ + ESP32_PINMUX(11, ESP_NOSIG, ESP_U2TXD_OUT) + +#define UART2_TX_GPIO12 \ + ESP32_PINMUX(12, ESP_NOSIG, ESP_U2TXD_OUT) + +#define UART2_TX_GPIO13 \ + ESP32_PINMUX(13, ESP_NOSIG, ESP_U2TXD_OUT) + +#define UART2_TX_GPIO14 \ + ESP32_PINMUX(14, ESP_NOSIG, ESP_U2TXD_OUT) + +#define UART2_TX_GPIO15 \ + ESP32_PINMUX(15, ESP_NOSIG, ESP_U2TXD_OUT) + +#define UART2_TX_GPIO16 \ + ESP32_PINMUX(16, ESP_NOSIG, ESP_U2TXD_OUT) + +#define UART2_TX_GPIO17 \ + ESP32_PINMUX(17, ESP_NOSIG, ESP_U2TXD_OUT) + +#define UART2_TX_GPIO18 \ + ESP32_PINMUX(18, ESP_NOSIG, ESP_U2TXD_OUT) + +#define UART2_TX_GPIO19 \ + ESP32_PINMUX(19, ESP_NOSIG, ESP_U2TXD_OUT) + +#define UART2_TX_GPIO20 \ + ESP32_PINMUX(20, ESP_NOSIG, ESP_U2TXD_OUT) + +#define UART2_TX_GPIO21 \ + ESP32_PINMUX(21, ESP_NOSIG, ESP_U2TXD_OUT) + +#define UART2_TX_GPIO22 \ + ESP32_PINMUX(22, ESP_NOSIG, ESP_U2TXD_OUT) + +#define UART2_TX_GPIO23 \ + ESP32_PINMUX(23, ESP_NOSIG, ESP_U2TXD_OUT) + +#define UART2_TX_GPIO25 \ + ESP32_PINMUX(25, ESP_NOSIG, ESP_U2TXD_OUT) + +#define UART2_TX_GPIO26 \ + ESP32_PINMUX(26, ESP_NOSIG, ESP_U2TXD_OUT) + +#define UART2_TX_GPIO27 \ + ESP32_PINMUX(27, ESP_NOSIG, ESP_U2TXD_OUT) + +#define UART2_TX_GPIO32 \ + ESP32_PINMUX(32, ESP_NOSIG, ESP_U2TXD_OUT) + +#define UART2_TX_GPIO33 \ + ESP32_PINMUX(33, ESP_NOSIG, ESP_U2TXD_OUT) + + +#endif /* INC_DT_BINDS_PINCTRL_ESP32_PINCTRL_HAL_H_ */ diff --git a/include/zephyr/dt-bindings/pinctrl/esp32c3-pinctrl.h b/include/zephyr/dt-bindings/pinctrl/esp32c3-pinctrl.h new file mode 100644 index 00000000000..2eda20f9cb3 --- /dev/null +++ b/include/zephyr/dt-bindings/pinctrl/esp32c3-pinctrl.h @@ -0,0 +1,2224 @@ +/* + * Copyright (c) 2022 Espressif Systems (Shanghai) Co., Ltd. + * + * SPDX-License-Identifier: Apache-2.0 + * + * NOTE: Autogenerated file using esp_genpinctrl.py + */ + +#ifndef INC_DT_BINDS_PINCTRL_ESP32C3_PINCTRL_HAL_H_ +#define INC_DT_BINDS_PINCTRL_ESP32C3_PINCTRL_HAL_H_ + +/* I2C0_SCL */ +#define I2C0_SCL_GPIO0 \ + ESP32_PINMUX(0, ESP_I2CEXT0_SCL_IN, ESP_I2CEXT0_SCL_OUT) + +#define I2C0_SCL_GPIO1 \ + ESP32_PINMUX(1, ESP_I2CEXT0_SCL_IN, ESP_I2CEXT0_SCL_OUT) + +#define I2C0_SCL_GPIO2 \ + ESP32_PINMUX(2, ESP_I2CEXT0_SCL_IN, ESP_I2CEXT0_SCL_OUT) + +#define I2C0_SCL_GPIO3 \ + ESP32_PINMUX(3, ESP_I2CEXT0_SCL_IN, ESP_I2CEXT0_SCL_OUT) + +#define I2C0_SCL_GPIO4 \ + ESP32_PINMUX(4, ESP_I2CEXT0_SCL_IN, ESP_I2CEXT0_SCL_OUT) + +#define I2C0_SCL_GPIO5 \ + ESP32_PINMUX(5, ESP_I2CEXT0_SCL_IN, ESP_I2CEXT0_SCL_OUT) + +#define I2C0_SCL_GPIO6 \ + ESP32_PINMUX(6, ESP_I2CEXT0_SCL_IN, ESP_I2CEXT0_SCL_OUT) + +#define I2C0_SCL_GPIO7 \ + ESP32_PINMUX(7, ESP_I2CEXT0_SCL_IN, ESP_I2CEXT0_SCL_OUT) + +#define I2C0_SCL_GPIO8 \ + ESP32_PINMUX(8, ESP_I2CEXT0_SCL_IN, ESP_I2CEXT0_SCL_OUT) + +#define I2C0_SCL_GPIO9 \ + ESP32_PINMUX(9, ESP_I2CEXT0_SCL_IN, ESP_I2CEXT0_SCL_OUT) + +#define I2C0_SCL_GPIO10 \ + ESP32_PINMUX(10, ESP_I2CEXT0_SCL_IN, ESP_I2CEXT0_SCL_OUT) + +#define I2C0_SCL_GPIO11 \ + ESP32_PINMUX(11, ESP_I2CEXT0_SCL_IN, ESP_I2CEXT0_SCL_OUT) + +#define I2C0_SCL_GPIO12 \ + ESP32_PINMUX(12, ESP_I2CEXT0_SCL_IN, ESP_I2CEXT0_SCL_OUT) + +#define I2C0_SCL_GPIO13 \ + ESP32_PINMUX(13, ESP_I2CEXT0_SCL_IN, ESP_I2CEXT0_SCL_OUT) + +#define I2C0_SCL_GPIO14 \ + ESP32_PINMUX(14, ESP_I2CEXT0_SCL_IN, ESP_I2CEXT0_SCL_OUT) + +#define I2C0_SCL_GPIO15 \ + ESP32_PINMUX(15, ESP_I2CEXT0_SCL_IN, ESP_I2CEXT0_SCL_OUT) + +#define I2C0_SCL_GPIO16 \ + ESP32_PINMUX(16, ESP_I2CEXT0_SCL_IN, ESP_I2CEXT0_SCL_OUT) + +#define I2C0_SCL_GPIO17 \ + ESP32_PINMUX(17, ESP_I2CEXT0_SCL_IN, ESP_I2CEXT0_SCL_OUT) + +#define I2C0_SCL_GPIO18 \ + ESP32_PINMUX(18, ESP_I2CEXT0_SCL_IN, ESP_I2CEXT0_SCL_OUT) + +#define I2C0_SCL_GPIO19 \ + ESP32_PINMUX(19, ESP_I2CEXT0_SCL_IN, ESP_I2CEXT0_SCL_OUT) + +#define I2C0_SCL_GPIO20 \ + ESP32_PINMUX(20, ESP_I2CEXT0_SCL_IN, ESP_I2CEXT0_SCL_OUT) + +#define I2C0_SCL_GPIO21 \ + ESP32_PINMUX(21, ESP_I2CEXT0_SCL_IN, ESP_I2CEXT0_SCL_OUT) + +/* I2C0_SDA */ +#define I2C0_SDA_GPIO0 \ + ESP32_PINMUX(0, ESP_I2CEXT0_SDA_IN, ESP_I2CEXT0_SDA_OUT) + +#define I2C0_SDA_GPIO1 \ + ESP32_PINMUX(1, ESP_I2CEXT0_SDA_IN, ESP_I2CEXT0_SDA_OUT) + +#define I2C0_SDA_GPIO2 \ + ESP32_PINMUX(2, ESP_I2CEXT0_SDA_IN, ESP_I2CEXT0_SDA_OUT) + +#define I2C0_SDA_GPIO3 \ + ESP32_PINMUX(3, ESP_I2CEXT0_SDA_IN, ESP_I2CEXT0_SDA_OUT) + +#define I2C0_SDA_GPIO4 \ + ESP32_PINMUX(4, ESP_I2CEXT0_SDA_IN, ESP_I2CEXT0_SDA_OUT) + +#define I2C0_SDA_GPIO5 \ + ESP32_PINMUX(5, ESP_I2CEXT0_SDA_IN, ESP_I2CEXT0_SDA_OUT) + +#define I2C0_SDA_GPIO6 \ + ESP32_PINMUX(6, ESP_I2CEXT0_SDA_IN, ESP_I2CEXT0_SDA_OUT) + +#define I2C0_SDA_GPIO7 \ + ESP32_PINMUX(7, ESP_I2CEXT0_SDA_IN, ESP_I2CEXT0_SDA_OUT) + +#define I2C0_SDA_GPIO8 \ + ESP32_PINMUX(8, ESP_I2CEXT0_SDA_IN, ESP_I2CEXT0_SDA_OUT) + +#define I2C0_SDA_GPIO9 \ + ESP32_PINMUX(9, ESP_I2CEXT0_SDA_IN, ESP_I2CEXT0_SDA_OUT) + +#define I2C0_SDA_GPIO10 \ + ESP32_PINMUX(10, ESP_I2CEXT0_SDA_IN, ESP_I2CEXT0_SDA_OUT) + +#define I2C0_SDA_GPIO11 \ + ESP32_PINMUX(11, ESP_I2CEXT0_SDA_IN, ESP_I2CEXT0_SDA_OUT) + +#define I2C0_SDA_GPIO12 \ + ESP32_PINMUX(12, ESP_I2CEXT0_SDA_IN, ESP_I2CEXT0_SDA_OUT) + +#define I2C0_SDA_GPIO13 \ + ESP32_PINMUX(13, ESP_I2CEXT0_SDA_IN, ESP_I2CEXT0_SDA_OUT) + +#define I2C0_SDA_GPIO14 \ + ESP32_PINMUX(14, ESP_I2CEXT0_SDA_IN, ESP_I2CEXT0_SDA_OUT) + +#define I2C0_SDA_GPIO15 \ + ESP32_PINMUX(15, ESP_I2CEXT0_SDA_IN, ESP_I2CEXT0_SDA_OUT) + +#define I2C0_SDA_GPIO16 \ + ESP32_PINMUX(16, ESP_I2CEXT0_SDA_IN, ESP_I2CEXT0_SDA_OUT) + +#define I2C0_SDA_GPIO17 \ + ESP32_PINMUX(17, ESP_I2CEXT0_SDA_IN, ESP_I2CEXT0_SDA_OUT) + +#define I2C0_SDA_GPIO18 \ + ESP32_PINMUX(18, ESP_I2CEXT0_SDA_IN, ESP_I2CEXT0_SDA_OUT) + +#define I2C0_SDA_GPIO19 \ + ESP32_PINMUX(19, ESP_I2CEXT0_SDA_IN, ESP_I2CEXT0_SDA_OUT) + +#define I2C0_SDA_GPIO20 \ + ESP32_PINMUX(20, ESP_I2CEXT0_SDA_IN, ESP_I2CEXT0_SDA_OUT) + +#define I2C0_SDA_GPIO21 \ + ESP32_PINMUX(21, ESP_I2CEXT0_SDA_IN, ESP_I2CEXT0_SDA_OUT) + +/* LEDC_CH0 */ +#define LEDC_CH0_GPIO0 \ + ESP32_PINMUX(0, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT0) + +#define LEDC_CH0_GPIO1 \ + ESP32_PINMUX(1, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT0) + +#define LEDC_CH0_GPIO2 \ + ESP32_PINMUX(2, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT0) + +#define LEDC_CH0_GPIO3 \ + ESP32_PINMUX(3, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT0) + +#define LEDC_CH0_GPIO4 \ + ESP32_PINMUX(4, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT0) + +#define LEDC_CH0_GPIO5 \ + ESP32_PINMUX(5, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT0) + +#define LEDC_CH0_GPIO6 \ + ESP32_PINMUX(6, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT0) + +#define LEDC_CH0_GPIO7 \ + ESP32_PINMUX(7, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT0) + +#define LEDC_CH0_GPIO8 \ + ESP32_PINMUX(8, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT0) + +#define LEDC_CH0_GPIO9 \ + ESP32_PINMUX(9, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT0) + +#define LEDC_CH0_GPIO10 \ + ESP32_PINMUX(10, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT0) + +#define LEDC_CH0_GPIO11 \ + ESP32_PINMUX(11, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT0) + +#define LEDC_CH0_GPIO12 \ + ESP32_PINMUX(12, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT0) + +#define LEDC_CH0_GPIO13 \ + ESP32_PINMUX(13, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT0) + +#define LEDC_CH0_GPIO14 \ + ESP32_PINMUX(14, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT0) + +#define LEDC_CH0_GPIO15 \ + ESP32_PINMUX(15, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT0) + +#define LEDC_CH0_GPIO16 \ + ESP32_PINMUX(16, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT0) + +#define LEDC_CH0_GPIO17 \ + ESP32_PINMUX(17, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT0) + +#define LEDC_CH0_GPIO18 \ + ESP32_PINMUX(18, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT0) + +#define LEDC_CH0_GPIO19 \ + ESP32_PINMUX(19, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT0) + +#define LEDC_CH0_GPIO20 \ + ESP32_PINMUX(20, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT0) + +#define LEDC_CH0_GPIO21 \ + ESP32_PINMUX(21, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT0) + +/* LEDC_CH1 */ +#define LEDC_CH1_GPIO0 \ + ESP32_PINMUX(0, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT1) + +#define LEDC_CH1_GPIO1 \ + ESP32_PINMUX(1, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT1) + +#define LEDC_CH1_GPIO2 \ + ESP32_PINMUX(2, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT1) + +#define LEDC_CH1_GPIO3 \ + ESP32_PINMUX(3, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT1) + +#define LEDC_CH1_GPIO4 \ + ESP32_PINMUX(4, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT1) + +#define LEDC_CH1_GPIO5 \ + ESP32_PINMUX(5, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT1) + +#define LEDC_CH1_GPIO6 \ + ESP32_PINMUX(6, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT1) + +#define LEDC_CH1_GPIO7 \ + ESP32_PINMUX(7, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT1) + +#define LEDC_CH1_GPIO8 \ + ESP32_PINMUX(8, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT1) + +#define LEDC_CH1_GPIO9 \ + ESP32_PINMUX(9, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT1) + +#define LEDC_CH1_GPIO10 \ + ESP32_PINMUX(10, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT1) + +#define LEDC_CH1_GPIO11 \ + ESP32_PINMUX(11, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT1) + +#define LEDC_CH1_GPIO12 \ + ESP32_PINMUX(12, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT1) + +#define LEDC_CH1_GPIO13 \ + ESP32_PINMUX(13, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT1) + +#define LEDC_CH1_GPIO14 \ + ESP32_PINMUX(14, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT1) + +#define LEDC_CH1_GPIO15 \ + ESP32_PINMUX(15, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT1) + +#define LEDC_CH1_GPIO16 \ + ESP32_PINMUX(16, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT1) + +#define LEDC_CH1_GPIO17 \ + ESP32_PINMUX(17, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT1) + +#define LEDC_CH1_GPIO18 \ + ESP32_PINMUX(18, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT1) + +#define LEDC_CH1_GPIO19 \ + ESP32_PINMUX(19, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT1) + +#define LEDC_CH1_GPIO20 \ + ESP32_PINMUX(20, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT1) + +#define LEDC_CH1_GPIO21 \ + ESP32_PINMUX(21, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT1) + +/* LEDC_CH2 */ +#define LEDC_CH2_GPIO0 \ + ESP32_PINMUX(0, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT2) + +#define LEDC_CH2_GPIO1 \ + ESP32_PINMUX(1, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT2) + +#define LEDC_CH2_GPIO2 \ + ESP32_PINMUX(2, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT2) + +#define LEDC_CH2_GPIO3 \ + ESP32_PINMUX(3, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT2) + +#define LEDC_CH2_GPIO4 \ + ESP32_PINMUX(4, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT2) + +#define LEDC_CH2_GPIO5 \ + ESP32_PINMUX(5, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT2) + +#define LEDC_CH2_GPIO6 \ + ESP32_PINMUX(6, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT2) + +#define LEDC_CH2_GPIO7 \ + ESP32_PINMUX(7, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT2) + +#define LEDC_CH2_GPIO8 \ + ESP32_PINMUX(8, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT2) + +#define LEDC_CH2_GPIO9 \ + ESP32_PINMUX(9, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT2) + +#define LEDC_CH2_GPIO10 \ + ESP32_PINMUX(10, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT2) + +#define LEDC_CH2_GPIO11 \ + ESP32_PINMUX(11, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT2) + +#define LEDC_CH2_GPIO12 \ + ESP32_PINMUX(12, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT2) + +#define LEDC_CH2_GPIO13 \ + ESP32_PINMUX(13, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT2) + +#define LEDC_CH2_GPIO14 \ + ESP32_PINMUX(14, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT2) + +#define LEDC_CH2_GPIO15 \ + ESP32_PINMUX(15, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT2) + +#define LEDC_CH2_GPIO16 \ + ESP32_PINMUX(16, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT2) + +#define LEDC_CH2_GPIO17 \ + ESP32_PINMUX(17, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT2) + +#define LEDC_CH2_GPIO18 \ + ESP32_PINMUX(18, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT2) + +#define LEDC_CH2_GPIO19 \ + ESP32_PINMUX(19, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT2) + +#define LEDC_CH2_GPIO20 \ + ESP32_PINMUX(20, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT2) + +#define LEDC_CH2_GPIO21 \ + ESP32_PINMUX(21, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT2) + +/* LEDC_CH3 */ +#define LEDC_CH3_GPIO0 \ + ESP32_PINMUX(0, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT3) + +#define LEDC_CH3_GPIO1 \ + ESP32_PINMUX(1, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT3) + +#define LEDC_CH3_GPIO2 \ + ESP32_PINMUX(2, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT3) + +#define LEDC_CH3_GPIO3 \ + ESP32_PINMUX(3, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT3) + +#define LEDC_CH3_GPIO4 \ + ESP32_PINMUX(4, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT3) + +#define LEDC_CH3_GPIO5 \ + ESP32_PINMUX(5, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT3) + +#define LEDC_CH3_GPIO6 \ + ESP32_PINMUX(6, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT3) + +#define LEDC_CH3_GPIO7 \ + ESP32_PINMUX(7, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT3) + +#define LEDC_CH3_GPIO8 \ + ESP32_PINMUX(8, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT3) + +#define LEDC_CH3_GPIO9 \ + ESP32_PINMUX(9, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT3) + +#define LEDC_CH3_GPIO10 \ + ESP32_PINMUX(10, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT3) + +#define LEDC_CH3_GPIO11 \ + ESP32_PINMUX(11, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT3) + +#define LEDC_CH3_GPIO12 \ + ESP32_PINMUX(12, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT3) + +#define LEDC_CH3_GPIO13 \ + ESP32_PINMUX(13, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT3) + +#define LEDC_CH3_GPIO14 \ + ESP32_PINMUX(14, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT3) + +#define LEDC_CH3_GPIO15 \ + ESP32_PINMUX(15, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT3) + +#define LEDC_CH3_GPIO16 \ + ESP32_PINMUX(16, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT3) + +#define LEDC_CH3_GPIO17 \ + ESP32_PINMUX(17, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT3) + +#define LEDC_CH3_GPIO18 \ + ESP32_PINMUX(18, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT3) + +#define LEDC_CH3_GPIO19 \ + ESP32_PINMUX(19, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT3) + +#define LEDC_CH3_GPIO20 \ + ESP32_PINMUX(20, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT3) + +#define LEDC_CH3_GPIO21 \ + ESP32_PINMUX(21, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT3) + +/* LEDC_CH4 */ +#define LEDC_CH4_GPIO0 \ + ESP32_PINMUX(0, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT4) + +#define LEDC_CH4_GPIO1 \ + ESP32_PINMUX(1, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT4) + +#define LEDC_CH4_GPIO2 \ + ESP32_PINMUX(2, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT4) + +#define LEDC_CH4_GPIO3 \ + ESP32_PINMUX(3, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT4) + +#define LEDC_CH4_GPIO4 \ + ESP32_PINMUX(4, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT4) + +#define LEDC_CH4_GPIO5 \ + ESP32_PINMUX(5, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT4) + +#define LEDC_CH4_GPIO6 \ + ESP32_PINMUX(6, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT4) + +#define LEDC_CH4_GPIO7 \ + ESP32_PINMUX(7, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT4) + +#define LEDC_CH4_GPIO8 \ + ESP32_PINMUX(8, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT4) + +#define LEDC_CH4_GPIO9 \ + ESP32_PINMUX(9, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT4) + +#define LEDC_CH4_GPIO10 \ + ESP32_PINMUX(10, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT4) + +#define LEDC_CH4_GPIO11 \ + ESP32_PINMUX(11, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT4) + +#define LEDC_CH4_GPIO12 \ + ESP32_PINMUX(12, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT4) + +#define LEDC_CH4_GPIO13 \ + ESP32_PINMUX(13, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT4) + +#define LEDC_CH4_GPIO14 \ + ESP32_PINMUX(14, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT4) + +#define LEDC_CH4_GPIO15 \ + ESP32_PINMUX(15, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT4) + +#define LEDC_CH4_GPIO16 \ + ESP32_PINMUX(16, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT4) + +#define LEDC_CH4_GPIO17 \ + ESP32_PINMUX(17, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT4) + +#define LEDC_CH4_GPIO18 \ + ESP32_PINMUX(18, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT4) + +#define LEDC_CH4_GPIO19 \ + ESP32_PINMUX(19, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT4) + +#define LEDC_CH4_GPIO20 \ + ESP32_PINMUX(20, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT4) + +#define LEDC_CH4_GPIO21 \ + ESP32_PINMUX(21, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT4) + +/* LEDC_CH5 */ +#define LEDC_CH5_GPIO0 \ + ESP32_PINMUX(0, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT5) + +#define LEDC_CH5_GPIO1 \ + ESP32_PINMUX(1, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT5) + +#define LEDC_CH5_GPIO2 \ + ESP32_PINMUX(2, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT5) + +#define LEDC_CH5_GPIO3 \ + ESP32_PINMUX(3, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT5) + +#define LEDC_CH5_GPIO4 \ + ESP32_PINMUX(4, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT5) + +#define LEDC_CH5_GPIO5 \ + ESP32_PINMUX(5, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT5) + +#define LEDC_CH5_GPIO6 \ + ESP32_PINMUX(6, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT5) + +#define LEDC_CH5_GPIO7 \ + ESP32_PINMUX(7, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT5) + +#define LEDC_CH5_GPIO8 \ + ESP32_PINMUX(8, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT5) + +#define LEDC_CH5_GPIO9 \ + ESP32_PINMUX(9, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT5) + +#define LEDC_CH5_GPIO10 \ + ESP32_PINMUX(10, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT5) + +#define LEDC_CH5_GPIO11 \ + ESP32_PINMUX(11, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT5) + +#define LEDC_CH5_GPIO12 \ + ESP32_PINMUX(12, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT5) + +#define LEDC_CH5_GPIO13 \ + ESP32_PINMUX(13, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT5) + +#define LEDC_CH5_GPIO14 \ + ESP32_PINMUX(14, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT5) + +#define LEDC_CH5_GPIO15 \ + ESP32_PINMUX(15, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT5) + +#define LEDC_CH5_GPIO16 \ + ESP32_PINMUX(16, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT5) + +#define LEDC_CH5_GPIO17 \ + ESP32_PINMUX(17, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT5) + +#define LEDC_CH5_GPIO18 \ + ESP32_PINMUX(18, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT5) + +#define LEDC_CH5_GPIO19 \ + ESP32_PINMUX(19, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT5) + +#define LEDC_CH5_GPIO20 \ + ESP32_PINMUX(20, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT5) + +#define LEDC_CH5_GPIO21 \ + ESP32_PINMUX(21, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT5) + +/* SPIM2_CSEL */ +#define SPIM2_CSEL_GPIO0 \ + ESP32_PINMUX(0, ESP_NOSIG, ESP_FSPICS0_OUT) + +#define SPIM2_CSEL_GPIO1 \ + ESP32_PINMUX(1, ESP_NOSIG, ESP_FSPICS0_OUT) + +#define SPIM2_CSEL_GPIO2 \ + ESP32_PINMUX(2, ESP_NOSIG, ESP_FSPICS0_OUT) + +#define SPIM2_CSEL_GPIO3 \ + ESP32_PINMUX(3, ESP_NOSIG, ESP_FSPICS0_OUT) + +#define SPIM2_CSEL_GPIO4 \ + ESP32_PINMUX(4, ESP_NOSIG, ESP_FSPICS0_OUT) + +#define SPIM2_CSEL_GPIO5 \ + ESP32_PINMUX(5, ESP_NOSIG, ESP_FSPICS0_OUT) + +#define SPIM2_CSEL_GPIO6 \ + ESP32_PINMUX(6, ESP_NOSIG, ESP_FSPICS0_OUT) + +#define SPIM2_CSEL_GPIO7 \ + ESP32_PINMUX(7, ESP_NOSIG, ESP_FSPICS0_OUT) + +#define SPIM2_CSEL_GPIO8 \ + ESP32_PINMUX(8, ESP_NOSIG, ESP_FSPICS0_OUT) + +#define SPIM2_CSEL_GPIO9 \ + ESP32_PINMUX(9, ESP_NOSIG, ESP_FSPICS0_OUT) + +#define SPIM2_CSEL_GPIO10 \ + ESP32_PINMUX(10, ESP_NOSIG, ESP_FSPICS0_OUT) + +#define SPIM2_CSEL_GPIO11 \ + ESP32_PINMUX(11, ESP_NOSIG, ESP_FSPICS0_OUT) + +#define SPIM2_CSEL_GPIO12 \ + ESP32_PINMUX(12, ESP_NOSIG, ESP_FSPICS0_OUT) + +#define SPIM2_CSEL_GPIO13 \ + ESP32_PINMUX(13, ESP_NOSIG, ESP_FSPICS0_OUT) + +#define SPIM2_CSEL_GPIO14 \ + ESP32_PINMUX(14, ESP_NOSIG, ESP_FSPICS0_OUT) + +#define SPIM2_CSEL_GPIO15 \ + ESP32_PINMUX(15, ESP_NOSIG, ESP_FSPICS0_OUT) + +#define SPIM2_CSEL_GPIO16 \ + ESP32_PINMUX(16, ESP_NOSIG, ESP_FSPICS0_OUT) + +#define SPIM2_CSEL_GPIO17 \ + ESP32_PINMUX(17, ESP_NOSIG, ESP_FSPICS0_OUT) + +#define SPIM2_CSEL_GPIO18 \ + ESP32_PINMUX(18, ESP_NOSIG, ESP_FSPICS0_OUT) + +#define SPIM2_CSEL_GPIO19 \ + ESP32_PINMUX(19, ESP_NOSIG, ESP_FSPICS0_OUT) + +#define SPIM2_CSEL_GPIO20 \ + ESP32_PINMUX(20, ESP_NOSIG, ESP_FSPICS0_OUT) + +#define SPIM2_CSEL_GPIO21 \ + ESP32_PINMUX(21, ESP_NOSIG, ESP_FSPICS0_OUT) + +/* SPIM2_CSEL1 */ +#define SPIM2_CSEL1_GPIO0 \ + ESP32_PINMUX(0, ESP_NOSIG, ESP_FSPICS1_OUT) + +#define SPIM2_CSEL1_GPIO1 \ + ESP32_PINMUX(1, ESP_NOSIG, ESP_FSPICS1_OUT) + +#define SPIM2_CSEL1_GPIO2 \ + ESP32_PINMUX(2, ESP_NOSIG, ESP_FSPICS1_OUT) + +#define SPIM2_CSEL1_GPIO3 \ + ESP32_PINMUX(3, ESP_NOSIG, ESP_FSPICS1_OUT) + +#define SPIM2_CSEL1_GPIO4 \ + ESP32_PINMUX(4, ESP_NOSIG, ESP_FSPICS1_OUT) + +#define SPIM2_CSEL1_GPIO5 \ + ESP32_PINMUX(5, ESP_NOSIG, ESP_FSPICS1_OUT) + +#define SPIM2_CSEL1_GPIO6 \ + ESP32_PINMUX(6, ESP_NOSIG, ESP_FSPICS1_OUT) + +#define SPIM2_CSEL1_GPIO7 \ + ESP32_PINMUX(7, ESP_NOSIG, ESP_FSPICS1_OUT) + +#define SPIM2_CSEL1_GPIO8 \ + ESP32_PINMUX(8, ESP_NOSIG, ESP_FSPICS1_OUT) + +#define SPIM2_CSEL1_GPIO9 \ + ESP32_PINMUX(9, ESP_NOSIG, ESP_FSPICS1_OUT) + +#define SPIM2_CSEL1_GPIO10 \ + ESP32_PINMUX(10, ESP_NOSIG, ESP_FSPICS1_OUT) + +#define SPIM2_CSEL1_GPIO11 \ + ESP32_PINMUX(11, ESP_NOSIG, ESP_FSPICS1_OUT) + +#define SPIM2_CSEL1_GPIO12 \ + ESP32_PINMUX(12, ESP_NOSIG, ESP_FSPICS1_OUT) + +#define SPIM2_CSEL1_GPIO13 \ + ESP32_PINMUX(13, ESP_NOSIG, ESP_FSPICS1_OUT) + +#define SPIM2_CSEL1_GPIO14 \ + ESP32_PINMUX(14, ESP_NOSIG, ESP_FSPICS1_OUT) + +#define SPIM2_CSEL1_GPIO15 \ + ESP32_PINMUX(15, ESP_NOSIG, ESP_FSPICS1_OUT) + +#define SPIM2_CSEL1_GPIO16 \ + ESP32_PINMUX(16, ESP_NOSIG, ESP_FSPICS1_OUT) + +#define SPIM2_CSEL1_GPIO17 \ + ESP32_PINMUX(17, ESP_NOSIG, ESP_FSPICS1_OUT) + +#define SPIM2_CSEL1_GPIO18 \ + ESP32_PINMUX(18, ESP_NOSIG, ESP_FSPICS1_OUT) + +#define SPIM2_CSEL1_GPIO19 \ + ESP32_PINMUX(19, ESP_NOSIG, ESP_FSPICS1_OUT) + +#define SPIM2_CSEL1_GPIO20 \ + ESP32_PINMUX(20, ESP_NOSIG, ESP_FSPICS1_OUT) + +#define SPIM2_CSEL1_GPIO21 \ + ESP32_PINMUX(21, ESP_NOSIG, ESP_FSPICS1_OUT) + +/* SPIM2_CSEL2 */ +#define SPIM2_CSEL2_GPIO0 \ + ESP32_PINMUX(0, ESP_NOSIG, ESP_FSPICS2_OUT) + +#define SPIM2_CSEL2_GPIO1 \ + ESP32_PINMUX(1, ESP_NOSIG, ESP_FSPICS2_OUT) + +#define SPIM2_CSEL2_GPIO2 \ + ESP32_PINMUX(2, ESP_NOSIG, ESP_FSPICS2_OUT) + +#define SPIM2_CSEL2_GPIO3 \ + ESP32_PINMUX(3, ESP_NOSIG, ESP_FSPICS2_OUT) + +#define SPIM2_CSEL2_GPIO4 \ + ESP32_PINMUX(4, ESP_NOSIG, ESP_FSPICS2_OUT) + +#define SPIM2_CSEL2_GPIO5 \ + ESP32_PINMUX(5, ESP_NOSIG, ESP_FSPICS2_OUT) + +#define SPIM2_CSEL2_GPIO6 \ + ESP32_PINMUX(6, ESP_NOSIG, ESP_FSPICS2_OUT) + +#define SPIM2_CSEL2_GPIO7 \ + ESP32_PINMUX(7, ESP_NOSIG, ESP_FSPICS2_OUT) + +#define SPIM2_CSEL2_GPIO8 \ + ESP32_PINMUX(8, ESP_NOSIG, ESP_FSPICS2_OUT) + +#define SPIM2_CSEL2_GPIO9 \ + ESP32_PINMUX(9, ESP_NOSIG, ESP_FSPICS2_OUT) + +#define SPIM2_CSEL2_GPIO10 \ + ESP32_PINMUX(10, ESP_NOSIG, ESP_FSPICS2_OUT) + +#define SPIM2_CSEL2_GPIO11 \ + ESP32_PINMUX(11, ESP_NOSIG, ESP_FSPICS2_OUT) + +#define SPIM2_CSEL2_GPIO12 \ + ESP32_PINMUX(12, ESP_NOSIG, ESP_FSPICS2_OUT) + +#define SPIM2_CSEL2_GPIO13 \ + ESP32_PINMUX(13, ESP_NOSIG, ESP_FSPICS2_OUT) + +#define SPIM2_CSEL2_GPIO14 \ + ESP32_PINMUX(14, ESP_NOSIG, ESP_FSPICS2_OUT) + +#define SPIM2_CSEL2_GPIO15 \ + ESP32_PINMUX(15, ESP_NOSIG, ESP_FSPICS2_OUT) + +#define SPIM2_CSEL2_GPIO16 \ + ESP32_PINMUX(16, ESP_NOSIG, ESP_FSPICS2_OUT) + +#define SPIM2_CSEL2_GPIO17 \ + ESP32_PINMUX(17, ESP_NOSIG, ESP_FSPICS2_OUT) + +#define SPIM2_CSEL2_GPIO18 \ + ESP32_PINMUX(18, ESP_NOSIG, ESP_FSPICS2_OUT) + +#define SPIM2_CSEL2_GPIO19 \ + ESP32_PINMUX(19, ESP_NOSIG, ESP_FSPICS2_OUT) + +#define SPIM2_CSEL2_GPIO20 \ + ESP32_PINMUX(20, ESP_NOSIG, ESP_FSPICS2_OUT) + +#define SPIM2_CSEL2_GPIO21 \ + ESP32_PINMUX(21, ESP_NOSIG, ESP_FSPICS2_OUT) + +/* SPIM2_CSEL3 */ +#define SPIM2_CSEL3_GPIO0 \ + ESP32_PINMUX(0, ESP_NOSIG, ESP_FSPICS3_OUT) + +#define SPIM2_CSEL3_GPIO1 \ + ESP32_PINMUX(1, ESP_NOSIG, ESP_FSPICS3_OUT) + +#define SPIM2_CSEL3_GPIO2 \ + ESP32_PINMUX(2, ESP_NOSIG, ESP_FSPICS3_OUT) + +#define SPIM2_CSEL3_GPIO3 \ + ESP32_PINMUX(3, ESP_NOSIG, ESP_FSPICS3_OUT) + +#define SPIM2_CSEL3_GPIO4 \ + ESP32_PINMUX(4, ESP_NOSIG, ESP_FSPICS3_OUT) + +#define SPIM2_CSEL3_GPIO5 \ + ESP32_PINMUX(5, ESP_NOSIG, ESP_FSPICS3_OUT) + +#define SPIM2_CSEL3_GPIO6 \ + ESP32_PINMUX(6, ESP_NOSIG, ESP_FSPICS3_OUT) + +#define SPIM2_CSEL3_GPIO7 \ + ESP32_PINMUX(7, ESP_NOSIG, ESP_FSPICS3_OUT) + +#define SPIM2_CSEL3_GPIO8 \ + ESP32_PINMUX(8, ESP_NOSIG, ESP_FSPICS3_OUT) + +#define SPIM2_CSEL3_GPIO9 \ + ESP32_PINMUX(9, ESP_NOSIG, ESP_FSPICS3_OUT) + +#define SPIM2_CSEL3_GPIO10 \ + ESP32_PINMUX(10, ESP_NOSIG, ESP_FSPICS3_OUT) + +#define SPIM2_CSEL3_GPIO11 \ + ESP32_PINMUX(11, ESP_NOSIG, ESP_FSPICS3_OUT) + +#define SPIM2_CSEL3_GPIO12 \ + ESP32_PINMUX(12, ESP_NOSIG, ESP_FSPICS3_OUT) + +#define SPIM2_CSEL3_GPIO13 \ + ESP32_PINMUX(13, ESP_NOSIG, ESP_FSPICS3_OUT) + +#define SPIM2_CSEL3_GPIO14 \ + ESP32_PINMUX(14, ESP_NOSIG, ESP_FSPICS3_OUT) + +#define SPIM2_CSEL3_GPIO15 \ + ESP32_PINMUX(15, ESP_NOSIG, ESP_FSPICS3_OUT) + +#define SPIM2_CSEL3_GPIO16 \ + ESP32_PINMUX(16, ESP_NOSIG, ESP_FSPICS3_OUT) + +#define SPIM2_CSEL3_GPIO17 \ + ESP32_PINMUX(17, ESP_NOSIG, ESP_FSPICS3_OUT) + +#define SPIM2_CSEL3_GPIO18 \ + ESP32_PINMUX(18, ESP_NOSIG, ESP_FSPICS3_OUT) + +#define SPIM2_CSEL3_GPIO19 \ + ESP32_PINMUX(19, ESP_NOSIG, ESP_FSPICS3_OUT) + +#define SPIM2_CSEL3_GPIO20 \ + ESP32_PINMUX(20, ESP_NOSIG, ESP_FSPICS3_OUT) + +#define SPIM2_CSEL3_GPIO21 \ + ESP32_PINMUX(21, ESP_NOSIG, ESP_FSPICS3_OUT) + +/* SPIM2_CSEL4 */ +#define SPIM2_CSEL4_GPIO0 \ + ESP32_PINMUX(0, ESP_NOSIG, ESP_FSPICS4_OUT) + +#define SPIM2_CSEL4_GPIO1 \ + ESP32_PINMUX(1, ESP_NOSIG, ESP_FSPICS4_OUT) + +#define SPIM2_CSEL4_GPIO2 \ + ESP32_PINMUX(2, ESP_NOSIG, ESP_FSPICS4_OUT) + +#define SPIM2_CSEL4_GPIO3 \ + ESP32_PINMUX(3, ESP_NOSIG, ESP_FSPICS4_OUT) + +#define SPIM2_CSEL4_GPIO4 \ + ESP32_PINMUX(4, ESP_NOSIG, ESP_FSPICS4_OUT) + +#define SPIM2_CSEL4_GPIO5 \ + ESP32_PINMUX(5, ESP_NOSIG, ESP_FSPICS4_OUT) + +#define SPIM2_CSEL4_GPIO6 \ + ESP32_PINMUX(6, ESP_NOSIG, ESP_FSPICS4_OUT) + +#define SPIM2_CSEL4_GPIO7 \ + ESP32_PINMUX(7, ESP_NOSIG, ESP_FSPICS4_OUT) + +#define SPIM2_CSEL4_GPIO8 \ + ESP32_PINMUX(8, ESP_NOSIG, ESP_FSPICS4_OUT) + +#define SPIM2_CSEL4_GPIO9 \ + ESP32_PINMUX(9, ESP_NOSIG, ESP_FSPICS4_OUT) + +#define SPIM2_CSEL4_GPIO10 \ + ESP32_PINMUX(10, ESP_NOSIG, ESP_FSPICS4_OUT) + +#define SPIM2_CSEL4_GPIO11 \ + ESP32_PINMUX(11, ESP_NOSIG, ESP_FSPICS4_OUT) + +#define SPIM2_CSEL4_GPIO12 \ + ESP32_PINMUX(12, ESP_NOSIG, ESP_FSPICS4_OUT) + +#define SPIM2_CSEL4_GPIO13 \ + ESP32_PINMUX(13, ESP_NOSIG, ESP_FSPICS4_OUT) + +#define SPIM2_CSEL4_GPIO14 \ + ESP32_PINMUX(14, ESP_NOSIG, ESP_FSPICS4_OUT) + +#define SPIM2_CSEL4_GPIO15 \ + ESP32_PINMUX(15, ESP_NOSIG, ESP_FSPICS4_OUT) + +#define SPIM2_CSEL4_GPIO16 \ + ESP32_PINMUX(16, ESP_NOSIG, ESP_FSPICS4_OUT) + +#define SPIM2_CSEL4_GPIO17 \ + ESP32_PINMUX(17, ESP_NOSIG, ESP_FSPICS4_OUT) + +#define SPIM2_CSEL4_GPIO18 \ + ESP32_PINMUX(18, ESP_NOSIG, ESP_FSPICS4_OUT) + +#define SPIM2_CSEL4_GPIO19 \ + ESP32_PINMUX(19, ESP_NOSIG, ESP_FSPICS4_OUT) + +#define SPIM2_CSEL4_GPIO20 \ + ESP32_PINMUX(20, ESP_NOSIG, ESP_FSPICS4_OUT) + +#define SPIM2_CSEL4_GPIO21 \ + ESP32_PINMUX(21, ESP_NOSIG, ESP_FSPICS4_OUT) + +/* SPIM2_CSEL5 */ +#define SPIM2_CSEL5_GPIO0 \ + ESP32_PINMUX(0, ESP_NOSIG, ESP_FSPICS5_OUT) + +#define SPIM2_CSEL5_GPIO1 \ + ESP32_PINMUX(1, ESP_NOSIG, ESP_FSPICS5_OUT) + +#define SPIM2_CSEL5_GPIO2 \ + ESP32_PINMUX(2, ESP_NOSIG, ESP_FSPICS5_OUT) + +#define SPIM2_CSEL5_GPIO3 \ + ESP32_PINMUX(3, ESP_NOSIG, ESP_FSPICS5_OUT) + +#define SPIM2_CSEL5_GPIO4 \ + ESP32_PINMUX(4, ESP_NOSIG, ESP_FSPICS5_OUT) + +#define SPIM2_CSEL5_GPIO5 \ + ESP32_PINMUX(5, ESP_NOSIG, ESP_FSPICS5_OUT) + +#define SPIM2_CSEL5_GPIO6 \ + ESP32_PINMUX(6, ESP_NOSIG, ESP_FSPICS5_OUT) + +#define SPIM2_CSEL5_GPIO7 \ + ESP32_PINMUX(7, ESP_NOSIG, ESP_FSPICS5_OUT) + +#define SPIM2_CSEL5_GPIO8 \ + ESP32_PINMUX(8, ESP_NOSIG, ESP_FSPICS5_OUT) + +#define SPIM2_CSEL5_GPIO9 \ + ESP32_PINMUX(9, ESP_NOSIG, ESP_FSPICS5_OUT) + +#define SPIM2_CSEL5_GPIO10 \ + ESP32_PINMUX(10, ESP_NOSIG, ESP_FSPICS5_OUT) + +#define SPIM2_CSEL5_GPIO11 \ + ESP32_PINMUX(11, ESP_NOSIG, ESP_FSPICS5_OUT) + +#define SPIM2_CSEL5_GPIO12 \ + ESP32_PINMUX(12, ESP_NOSIG, ESP_FSPICS5_OUT) + +#define SPIM2_CSEL5_GPIO13 \ + ESP32_PINMUX(13, ESP_NOSIG, ESP_FSPICS5_OUT) + +#define SPIM2_CSEL5_GPIO14 \ + ESP32_PINMUX(14, ESP_NOSIG, ESP_FSPICS5_OUT) + +#define SPIM2_CSEL5_GPIO15 \ + ESP32_PINMUX(15, ESP_NOSIG, ESP_FSPICS5_OUT) + +#define SPIM2_CSEL5_GPIO16 \ + ESP32_PINMUX(16, ESP_NOSIG, ESP_FSPICS5_OUT) + +#define SPIM2_CSEL5_GPIO17 \ + ESP32_PINMUX(17, ESP_NOSIG, ESP_FSPICS5_OUT) + +#define SPIM2_CSEL5_GPIO18 \ + ESP32_PINMUX(18, ESP_NOSIG, ESP_FSPICS5_OUT) + +#define SPIM2_CSEL5_GPIO19 \ + ESP32_PINMUX(19, ESP_NOSIG, ESP_FSPICS5_OUT) + +#define SPIM2_CSEL5_GPIO20 \ + ESP32_PINMUX(20, ESP_NOSIG, ESP_FSPICS5_OUT) + +#define SPIM2_CSEL5_GPIO21 \ + ESP32_PINMUX(21, ESP_NOSIG, ESP_FSPICS5_OUT) + +/* SPIM2_MISO */ +#define SPIM2_MISO_GPIO0 \ + ESP32_PINMUX(0, ESP_FSPIQ_IN, ESP_NOSIG) + +#define SPIM2_MISO_GPIO1 \ + ESP32_PINMUX(1, ESP_FSPIQ_IN, ESP_NOSIG) + +#define SPIM2_MISO_GPIO2 \ + ESP32_PINMUX(2, ESP_FSPIQ_IN, ESP_NOSIG) + +#define SPIM2_MISO_GPIO3 \ + ESP32_PINMUX(3, ESP_FSPIQ_IN, ESP_NOSIG) + +#define SPIM2_MISO_GPIO4 \ + ESP32_PINMUX(4, ESP_FSPIQ_IN, ESP_NOSIG) + +#define SPIM2_MISO_GPIO5 \ + ESP32_PINMUX(5, ESP_FSPIQ_IN, ESP_NOSIG) + +#define SPIM2_MISO_GPIO6 \ + ESP32_PINMUX(6, ESP_FSPIQ_IN, ESP_NOSIG) + +#define SPIM2_MISO_GPIO7 \ + ESP32_PINMUX(7, ESP_FSPIQ_IN, ESP_NOSIG) + +#define SPIM2_MISO_GPIO8 \ + ESP32_PINMUX(8, ESP_FSPIQ_IN, ESP_NOSIG) + +#define SPIM2_MISO_GPIO9 \ + ESP32_PINMUX(9, ESP_FSPIQ_IN, ESP_NOSIG) + +#define SPIM2_MISO_GPIO10 \ + ESP32_PINMUX(10, ESP_FSPIQ_IN, ESP_NOSIG) + +#define SPIM2_MISO_GPIO11 \ + ESP32_PINMUX(11, ESP_FSPIQ_IN, ESP_NOSIG) + +#define SPIM2_MISO_GPIO12 \ + ESP32_PINMUX(12, ESP_FSPIQ_IN, ESP_NOSIG) + +#define SPIM2_MISO_GPIO13 \ + ESP32_PINMUX(13, ESP_FSPIQ_IN, ESP_NOSIG) + +#define SPIM2_MISO_GPIO14 \ + ESP32_PINMUX(14, ESP_FSPIQ_IN, ESP_NOSIG) + +#define SPIM2_MISO_GPIO15 \ + ESP32_PINMUX(15, ESP_FSPIQ_IN, ESP_NOSIG) + +#define SPIM2_MISO_GPIO16 \ + ESP32_PINMUX(16, ESP_FSPIQ_IN, ESP_NOSIG) + +#define SPIM2_MISO_GPIO17 \ + ESP32_PINMUX(17, ESP_FSPIQ_IN, ESP_NOSIG) + +#define SPIM2_MISO_GPIO18 \ + ESP32_PINMUX(18, ESP_FSPIQ_IN, ESP_NOSIG) + +#define SPIM2_MISO_GPIO19 \ + ESP32_PINMUX(19, ESP_FSPIQ_IN, ESP_NOSIG) + +#define SPIM2_MISO_GPIO20 \ + ESP32_PINMUX(20, ESP_FSPIQ_IN, ESP_NOSIG) + +#define SPIM2_MISO_GPIO21 \ + ESP32_PINMUX(21, ESP_FSPIQ_IN, ESP_NOSIG) + +/* SPIM2_MOSI */ +#define SPIM2_MOSI_GPIO0 \ + ESP32_PINMUX(0, ESP_NOSIG, ESP_FSPID_OUT) + +#define SPIM2_MOSI_GPIO1 \ + ESP32_PINMUX(1, ESP_NOSIG, ESP_FSPID_OUT) + +#define SPIM2_MOSI_GPIO2 \ + ESP32_PINMUX(2, ESP_NOSIG, ESP_FSPID_OUT) + +#define SPIM2_MOSI_GPIO3 \ + ESP32_PINMUX(3, ESP_NOSIG, ESP_FSPID_OUT) + +#define SPIM2_MOSI_GPIO4 \ + ESP32_PINMUX(4, ESP_NOSIG, ESP_FSPID_OUT) + +#define SPIM2_MOSI_GPIO5 \ + ESP32_PINMUX(5, ESP_NOSIG, ESP_FSPID_OUT) + +#define SPIM2_MOSI_GPIO6 \ + ESP32_PINMUX(6, ESP_NOSIG, ESP_FSPID_OUT) + +#define SPIM2_MOSI_GPIO7 \ + ESP32_PINMUX(7, ESP_NOSIG, ESP_FSPID_OUT) + +#define SPIM2_MOSI_GPIO8 \ + ESP32_PINMUX(8, ESP_NOSIG, ESP_FSPID_OUT) + +#define SPIM2_MOSI_GPIO9 \ + ESP32_PINMUX(9, ESP_NOSIG, ESP_FSPID_OUT) + +#define SPIM2_MOSI_GPIO10 \ + ESP32_PINMUX(10, ESP_NOSIG, ESP_FSPID_OUT) + +#define SPIM2_MOSI_GPIO11 \ + ESP32_PINMUX(11, ESP_NOSIG, ESP_FSPID_OUT) + +#define SPIM2_MOSI_GPIO12 \ + ESP32_PINMUX(12, ESP_NOSIG, ESP_FSPID_OUT) + +#define SPIM2_MOSI_GPIO13 \ + ESP32_PINMUX(13, ESP_NOSIG, ESP_FSPID_OUT) + +#define SPIM2_MOSI_GPIO14 \ + ESP32_PINMUX(14, ESP_NOSIG, ESP_FSPID_OUT) + +#define SPIM2_MOSI_GPIO15 \ + ESP32_PINMUX(15, ESP_NOSIG, ESP_FSPID_OUT) + +#define SPIM2_MOSI_GPIO16 \ + ESP32_PINMUX(16, ESP_NOSIG, ESP_FSPID_OUT) + +#define SPIM2_MOSI_GPIO17 \ + ESP32_PINMUX(17, ESP_NOSIG, ESP_FSPID_OUT) + +#define SPIM2_MOSI_GPIO18 \ + ESP32_PINMUX(18, ESP_NOSIG, ESP_FSPID_OUT) + +#define SPIM2_MOSI_GPIO19 \ + ESP32_PINMUX(19, ESP_NOSIG, ESP_FSPID_OUT) + +#define SPIM2_MOSI_GPIO20 \ + ESP32_PINMUX(20, ESP_NOSIG, ESP_FSPID_OUT) + +#define SPIM2_MOSI_GPIO21 \ + ESP32_PINMUX(21, ESP_NOSIG, ESP_FSPID_OUT) + +/* SPIM2_SCLK */ +#define SPIM2_SCLK_GPIO0 \ + ESP32_PINMUX(0, ESP_NOSIG, ESP_FSPICLK_OUT) + +#define SPIM2_SCLK_GPIO1 \ + ESP32_PINMUX(1, ESP_NOSIG, ESP_FSPICLK_OUT) + +#define SPIM2_SCLK_GPIO2 \ + ESP32_PINMUX(2, ESP_NOSIG, ESP_FSPICLK_OUT) + +#define SPIM2_SCLK_GPIO3 \ + ESP32_PINMUX(3, ESP_NOSIG, ESP_FSPICLK_OUT) + +#define SPIM2_SCLK_GPIO4 \ + ESP32_PINMUX(4, ESP_NOSIG, ESP_FSPICLK_OUT) + +#define SPIM2_SCLK_GPIO5 \ + ESP32_PINMUX(5, ESP_NOSIG, ESP_FSPICLK_OUT) + +#define SPIM2_SCLK_GPIO6 \ + ESP32_PINMUX(6, ESP_NOSIG, ESP_FSPICLK_OUT) + +#define SPIM2_SCLK_GPIO7 \ + ESP32_PINMUX(7, ESP_NOSIG, ESP_FSPICLK_OUT) + +#define SPIM2_SCLK_GPIO8 \ + ESP32_PINMUX(8, ESP_NOSIG, ESP_FSPICLK_OUT) + +#define SPIM2_SCLK_GPIO9 \ + ESP32_PINMUX(9, ESP_NOSIG, ESP_FSPICLK_OUT) + +#define SPIM2_SCLK_GPIO10 \ + ESP32_PINMUX(10, ESP_NOSIG, ESP_FSPICLK_OUT) + +#define SPIM2_SCLK_GPIO11 \ + ESP32_PINMUX(11, ESP_NOSIG, ESP_FSPICLK_OUT) + +#define SPIM2_SCLK_GPIO12 \ + ESP32_PINMUX(12, ESP_NOSIG, ESP_FSPICLK_OUT) + +#define SPIM2_SCLK_GPIO13 \ + ESP32_PINMUX(13, ESP_NOSIG, ESP_FSPICLK_OUT) + +#define SPIM2_SCLK_GPIO14 \ + ESP32_PINMUX(14, ESP_NOSIG, ESP_FSPICLK_OUT) + +#define SPIM2_SCLK_GPIO15 \ + ESP32_PINMUX(15, ESP_NOSIG, ESP_FSPICLK_OUT) + +#define SPIM2_SCLK_GPIO16 \ + ESP32_PINMUX(16, ESP_NOSIG, ESP_FSPICLK_OUT) + +#define SPIM2_SCLK_GPIO17 \ + ESP32_PINMUX(17, ESP_NOSIG, ESP_FSPICLK_OUT) + +#define SPIM2_SCLK_GPIO18 \ + ESP32_PINMUX(18, ESP_NOSIG, ESP_FSPICLK_OUT) + +#define SPIM2_SCLK_GPIO19 \ + ESP32_PINMUX(19, ESP_NOSIG, ESP_FSPICLK_OUT) + +#define SPIM2_SCLK_GPIO20 \ + ESP32_PINMUX(20, ESP_NOSIG, ESP_FSPICLK_OUT) + +#define SPIM2_SCLK_GPIO21 \ + ESP32_PINMUX(21, ESP_NOSIG, ESP_FSPICLK_OUT) + +/* TWAI_BUS_OFF */ +#define TWAI_BUS_OFF_GPIO0 \ + ESP32_PINMUX(0, ESP_NOSIG, ESP_TWAI_BUS_OFF_ON) + +#define TWAI_BUS_OFF_GPIO1 \ + ESP32_PINMUX(1, ESP_NOSIG, ESP_TWAI_BUS_OFF_ON) + +#define TWAI_BUS_OFF_GPIO2 \ + ESP32_PINMUX(2, ESP_NOSIG, ESP_TWAI_BUS_OFF_ON) + +#define TWAI_BUS_OFF_GPIO3 \ + ESP32_PINMUX(3, ESP_NOSIG, ESP_TWAI_BUS_OFF_ON) + +#define TWAI_BUS_OFF_GPIO4 \ + ESP32_PINMUX(4, ESP_NOSIG, ESP_TWAI_BUS_OFF_ON) + +#define TWAI_BUS_OFF_GPIO5 \ + ESP32_PINMUX(5, ESP_NOSIG, ESP_TWAI_BUS_OFF_ON) + +#define TWAI_BUS_OFF_GPIO6 \ + ESP32_PINMUX(6, ESP_NOSIG, ESP_TWAI_BUS_OFF_ON) + +#define TWAI_BUS_OFF_GPIO7 \ + ESP32_PINMUX(7, ESP_NOSIG, ESP_TWAI_BUS_OFF_ON) + +#define TWAI_BUS_OFF_GPIO8 \ + ESP32_PINMUX(8, ESP_NOSIG, ESP_TWAI_BUS_OFF_ON) + +#define TWAI_BUS_OFF_GPIO9 \ + ESP32_PINMUX(9, ESP_NOSIG, ESP_TWAI_BUS_OFF_ON) + +#define TWAI_BUS_OFF_GPIO10 \ + ESP32_PINMUX(10, ESP_NOSIG, ESP_TWAI_BUS_OFF_ON) + +#define TWAI_BUS_OFF_GPIO11 \ + ESP32_PINMUX(11, ESP_NOSIG, ESP_TWAI_BUS_OFF_ON) + +#define TWAI_BUS_OFF_GPIO12 \ + ESP32_PINMUX(12, ESP_NOSIG, ESP_TWAI_BUS_OFF_ON) + +#define TWAI_BUS_OFF_GPIO13 \ + ESP32_PINMUX(13, ESP_NOSIG, ESP_TWAI_BUS_OFF_ON) + +#define TWAI_BUS_OFF_GPIO14 \ + ESP32_PINMUX(14, ESP_NOSIG, ESP_TWAI_BUS_OFF_ON) + +#define TWAI_BUS_OFF_GPIO15 \ + ESP32_PINMUX(15, ESP_NOSIG, ESP_TWAI_BUS_OFF_ON) + +#define TWAI_BUS_OFF_GPIO16 \ + ESP32_PINMUX(16, ESP_NOSIG, ESP_TWAI_BUS_OFF_ON) + +#define TWAI_BUS_OFF_GPIO17 \ + ESP32_PINMUX(17, ESP_NOSIG, ESP_TWAI_BUS_OFF_ON) + +#define TWAI_BUS_OFF_GPIO18 \ + ESP32_PINMUX(18, ESP_NOSIG, ESP_TWAI_BUS_OFF_ON) + +#define TWAI_BUS_OFF_GPIO19 \ + ESP32_PINMUX(19, ESP_NOSIG, ESP_TWAI_BUS_OFF_ON) + +#define TWAI_BUS_OFF_GPIO20 \ + ESP32_PINMUX(20, ESP_NOSIG, ESP_TWAI_BUS_OFF_ON) + +#define TWAI_BUS_OFF_GPIO21 \ + ESP32_PINMUX(21, ESP_NOSIG, ESP_TWAI_BUS_OFF_ON) + +/* TWAI_CLKOUT */ +#define TWAI_CLKOUT_GPIO0 \ + ESP32_PINMUX(0, ESP_NOSIG, ESP_TWAI_CLKOUT) + +#define TWAI_CLKOUT_GPIO1 \ + ESP32_PINMUX(1, ESP_NOSIG, ESP_TWAI_CLKOUT) + +#define TWAI_CLKOUT_GPIO2 \ + ESP32_PINMUX(2, ESP_NOSIG, ESP_TWAI_CLKOUT) + +#define TWAI_CLKOUT_GPIO3 \ + ESP32_PINMUX(3, ESP_NOSIG, ESP_TWAI_CLKOUT) + +#define TWAI_CLKOUT_GPIO4 \ + ESP32_PINMUX(4, ESP_NOSIG, ESP_TWAI_CLKOUT) + +#define TWAI_CLKOUT_GPIO5 \ + ESP32_PINMUX(5, ESP_NOSIG, ESP_TWAI_CLKOUT) + +#define TWAI_CLKOUT_GPIO6 \ + ESP32_PINMUX(6, ESP_NOSIG, ESP_TWAI_CLKOUT) + +#define TWAI_CLKOUT_GPIO7 \ + ESP32_PINMUX(7, ESP_NOSIG, ESP_TWAI_CLKOUT) + +#define TWAI_CLKOUT_GPIO8 \ + ESP32_PINMUX(8, ESP_NOSIG, ESP_TWAI_CLKOUT) + +#define TWAI_CLKOUT_GPIO9 \ + ESP32_PINMUX(9, ESP_NOSIG, ESP_TWAI_CLKOUT) + +#define TWAI_CLKOUT_GPIO10 \ + ESP32_PINMUX(10, ESP_NOSIG, ESP_TWAI_CLKOUT) + +#define TWAI_CLKOUT_GPIO11 \ + ESP32_PINMUX(11, ESP_NOSIG, ESP_TWAI_CLKOUT) + +#define TWAI_CLKOUT_GPIO12 \ + ESP32_PINMUX(12, ESP_NOSIG, ESP_TWAI_CLKOUT) + +#define TWAI_CLKOUT_GPIO13 \ + ESP32_PINMUX(13, ESP_NOSIG, ESP_TWAI_CLKOUT) + +#define TWAI_CLKOUT_GPIO14 \ + ESP32_PINMUX(14, ESP_NOSIG, ESP_TWAI_CLKOUT) + +#define TWAI_CLKOUT_GPIO15 \ + ESP32_PINMUX(15, ESP_NOSIG, ESP_TWAI_CLKOUT) + +#define TWAI_CLKOUT_GPIO16 \ + ESP32_PINMUX(16, ESP_NOSIG, ESP_TWAI_CLKOUT) + +#define TWAI_CLKOUT_GPIO17 \ + ESP32_PINMUX(17, ESP_NOSIG, ESP_TWAI_CLKOUT) + +#define TWAI_CLKOUT_GPIO18 \ + ESP32_PINMUX(18, ESP_NOSIG, ESP_TWAI_CLKOUT) + +#define TWAI_CLKOUT_GPIO19 \ + ESP32_PINMUX(19, ESP_NOSIG, ESP_TWAI_CLKOUT) + +#define TWAI_CLKOUT_GPIO20 \ + ESP32_PINMUX(20, ESP_NOSIG, ESP_TWAI_CLKOUT) + +#define TWAI_CLKOUT_GPIO21 \ + ESP32_PINMUX(21, ESP_NOSIG, ESP_TWAI_CLKOUT) + +/* TWAI_RX */ +#define TWAI_RX_GPIO0 \ + ESP32_PINMUX(0, ESP_TWAI_RX, ESP_NOSIG) + +#define TWAI_RX_GPIO1 \ + ESP32_PINMUX(1, ESP_TWAI_RX, ESP_NOSIG) + +#define TWAI_RX_GPIO2 \ + ESP32_PINMUX(2, ESP_TWAI_RX, ESP_NOSIG) + +#define TWAI_RX_GPIO3 \ + ESP32_PINMUX(3, ESP_TWAI_RX, ESP_NOSIG) + +#define TWAI_RX_GPIO4 \ + ESP32_PINMUX(4, ESP_TWAI_RX, ESP_NOSIG) + +#define TWAI_RX_GPIO5 \ + ESP32_PINMUX(5, ESP_TWAI_RX, ESP_NOSIG) + +#define TWAI_RX_GPIO6 \ + ESP32_PINMUX(6, ESP_TWAI_RX, ESP_NOSIG) + +#define TWAI_RX_GPIO7 \ + ESP32_PINMUX(7, ESP_TWAI_RX, ESP_NOSIG) + +#define TWAI_RX_GPIO8 \ + ESP32_PINMUX(8, ESP_TWAI_RX, ESP_NOSIG) + +#define TWAI_RX_GPIO9 \ + ESP32_PINMUX(9, ESP_TWAI_RX, ESP_NOSIG) + +#define TWAI_RX_GPIO10 \ + ESP32_PINMUX(10, ESP_TWAI_RX, ESP_NOSIG) + +#define TWAI_RX_GPIO11 \ + ESP32_PINMUX(11, ESP_TWAI_RX, ESP_NOSIG) + +#define TWAI_RX_GPIO12 \ + ESP32_PINMUX(12, ESP_TWAI_RX, ESP_NOSIG) + +#define TWAI_RX_GPIO13 \ + ESP32_PINMUX(13, ESP_TWAI_RX, ESP_NOSIG) + +#define TWAI_RX_GPIO14 \ + ESP32_PINMUX(14, ESP_TWAI_RX, ESP_NOSIG) + +#define TWAI_RX_GPIO15 \ + ESP32_PINMUX(15, ESP_TWAI_RX, ESP_NOSIG) + +#define TWAI_RX_GPIO16 \ + ESP32_PINMUX(16, ESP_TWAI_RX, ESP_NOSIG) + +#define TWAI_RX_GPIO17 \ + ESP32_PINMUX(17, ESP_TWAI_RX, ESP_NOSIG) + +#define TWAI_RX_GPIO18 \ + ESP32_PINMUX(18, ESP_TWAI_RX, ESP_NOSIG) + +#define TWAI_RX_GPIO19 \ + ESP32_PINMUX(19, ESP_TWAI_RX, ESP_NOSIG) + +#define TWAI_RX_GPIO20 \ + ESP32_PINMUX(20, ESP_TWAI_RX, ESP_NOSIG) + +#define TWAI_RX_GPIO21 \ + ESP32_PINMUX(21, ESP_TWAI_RX, ESP_NOSIG) + +/* TWAI_TX */ +#define TWAI_TX_GPIO0 \ + ESP32_PINMUX(0, ESP_NOSIG, ESP_TWAI_TX) + +#define TWAI_TX_GPIO1 \ + ESP32_PINMUX(1, ESP_NOSIG, ESP_TWAI_TX) + +#define TWAI_TX_GPIO2 \ + ESP32_PINMUX(2, ESP_NOSIG, ESP_TWAI_TX) + +#define TWAI_TX_GPIO3 \ + ESP32_PINMUX(3, ESP_NOSIG, ESP_TWAI_TX) + +#define TWAI_TX_GPIO4 \ + ESP32_PINMUX(4, ESP_NOSIG, ESP_TWAI_TX) + +#define TWAI_TX_GPIO5 \ + ESP32_PINMUX(5, ESP_NOSIG, ESP_TWAI_TX) + +#define TWAI_TX_GPIO6 \ + ESP32_PINMUX(6, ESP_NOSIG, ESP_TWAI_TX) + +#define TWAI_TX_GPIO7 \ + ESP32_PINMUX(7, ESP_NOSIG, ESP_TWAI_TX) + +#define TWAI_TX_GPIO8 \ + ESP32_PINMUX(8, ESP_NOSIG, ESP_TWAI_TX) + +#define TWAI_TX_GPIO9 \ + ESP32_PINMUX(9, ESP_NOSIG, ESP_TWAI_TX) + +#define TWAI_TX_GPIO10 \ + ESP32_PINMUX(10, ESP_NOSIG, ESP_TWAI_TX) + +#define TWAI_TX_GPIO11 \ + ESP32_PINMUX(11, ESP_NOSIG, ESP_TWAI_TX) + +#define TWAI_TX_GPIO12 \ + ESP32_PINMUX(12, ESP_NOSIG, ESP_TWAI_TX) + +#define TWAI_TX_GPIO13 \ + ESP32_PINMUX(13, ESP_NOSIG, ESP_TWAI_TX) + +#define TWAI_TX_GPIO14 \ + ESP32_PINMUX(14, ESP_NOSIG, ESP_TWAI_TX) + +#define TWAI_TX_GPIO15 \ + ESP32_PINMUX(15, ESP_NOSIG, ESP_TWAI_TX) + +#define TWAI_TX_GPIO16 \ + ESP32_PINMUX(16, ESP_NOSIG, ESP_TWAI_TX) + +#define TWAI_TX_GPIO17 \ + ESP32_PINMUX(17, ESP_NOSIG, ESP_TWAI_TX) + +#define TWAI_TX_GPIO18 \ + ESP32_PINMUX(18, ESP_NOSIG, ESP_TWAI_TX) + +#define TWAI_TX_GPIO19 \ + ESP32_PINMUX(19, ESP_NOSIG, ESP_TWAI_TX) + +#define TWAI_TX_GPIO20 \ + ESP32_PINMUX(20, ESP_NOSIG, ESP_TWAI_TX) + +#define TWAI_TX_GPIO21 \ + ESP32_PINMUX(21, ESP_NOSIG, ESP_TWAI_TX) + +/* UART0_CTS */ +#define UART0_CTS_GPIO0 \ + ESP32_PINMUX(0, ESP_U0CTS_IN, ESP_NOSIG) + +#define UART0_CTS_GPIO1 \ + ESP32_PINMUX(1, ESP_U0CTS_IN, ESP_NOSIG) + +#define UART0_CTS_GPIO2 \ + ESP32_PINMUX(2, ESP_U0CTS_IN, ESP_NOSIG) + +#define UART0_CTS_GPIO3 \ + ESP32_PINMUX(3, ESP_U0CTS_IN, ESP_NOSIG) + +#define UART0_CTS_GPIO4 \ + ESP32_PINMUX(4, ESP_U0CTS_IN, ESP_NOSIG) + +#define UART0_CTS_GPIO5 \ + ESP32_PINMUX(5, ESP_U0CTS_IN, ESP_NOSIG) + +#define UART0_CTS_GPIO6 \ + ESP32_PINMUX(6, ESP_U0CTS_IN, ESP_NOSIG) + +#define UART0_CTS_GPIO7 \ + ESP32_PINMUX(7, ESP_U0CTS_IN, ESP_NOSIG) + +#define UART0_CTS_GPIO8 \ + ESP32_PINMUX(8, ESP_U0CTS_IN, ESP_NOSIG) + +#define UART0_CTS_GPIO9 \ + ESP32_PINMUX(9, ESP_U0CTS_IN, ESP_NOSIG) + +#define UART0_CTS_GPIO10 \ + ESP32_PINMUX(10, ESP_U0CTS_IN, ESP_NOSIG) + +#define UART0_CTS_GPIO11 \ + ESP32_PINMUX(11, ESP_U0CTS_IN, ESP_NOSIG) + +#define UART0_CTS_GPIO12 \ + ESP32_PINMUX(12, ESP_U0CTS_IN, ESP_NOSIG) + +#define UART0_CTS_GPIO13 \ + ESP32_PINMUX(13, ESP_U0CTS_IN, ESP_NOSIG) + +#define UART0_CTS_GPIO14 \ + ESP32_PINMUX(14, ESP_U0CTS_IN, ESP_NOSIG) + +#define UART0_CTS_GPIO15 \ + ESP32_PINMUX(15, ESP_U0CTS_IN, ESP_NOSIG) + +#define UART0_CTS_GPIO16 \ + ESP32_PINMUX(16, ESP_U0CTS_IN, ESP_NOSIG) + +#define UART0_CTS_GPIO17 \ + ESP32_PINMUX(17, ESP_U0CTS_IN, ESP_NOSIG) + +#define UART0_CTS_GPIO18 \ + ESP32_PINMUX(18, ESP_U0CTS_IN, ESP_NOSIG) + +#define UART0_CTS_GPIO19 \ + ESP32_PINMUX(19, ESP_U0CTS_IN, ESP_NOSIG) + +#define UART0_CTS_GPIO20 \ + ESP32_PINMUX(20, ESP_U0CTS_IN, ESP_NOSIG) + +#define UART0_CTS_GPIO21 \ + ESP32_PINMUX(21, ESP_U0CTS_IN, ESP_NOSIG) + +/* UART0_DSR */ +#define UART0_DSR_GPIO0 \ + ESP32_PINMUX(0, ESP_U0DSR_IN, ESP_NOSIG) + +#define UART0_DSR_GPIO1 \ + ESP32_PINMUX(1, ESP_U0DSR_IN, ESP_NOSIG) + +#define UART0_DSR_GPIO2 \ + ESP32_PINMUX(2, ESP_U0DSR_IN, ESP_NOSIG) + +#define UART0_DSR_GPIO3 \ + ESP32_PINMUX(3, ESP_U0DSR_IN, ESP_NOSIG) + +#define UART0_DSR_GPIO4 \ + ESP32_PINMUX(4, ESP_U0DSR_IN, ESP_NOSIG) + +#define UART0_DSR_GPIO5 \ + ESP32_PINMUX(5, ESP_U0DSR_IN, ESP_NOSIG) + +#define UART0_DSR_GPIO6 \ + ESP32_PINMUX(6, ESP_U0DSR_IN, ESP_NOSIG) + +#define UART0_DSR_GPIO7 \ + ESP32_PINMUX(7, ESP_U0DSR_IN, ESP_NOSIG) + +#define UART0_DSR_GPIO8 \ + ESP32_PINMUX(8, ESP_U0DSR_IN, ESP_NOSIG) + +#define UART0_DSR_GPIO9 \ + ESP32_PINMUX(9, ESP_U0DSR_IN, ESP_NOSIG) + +#define UART0_DSR_GPIO10 \ + ESP32_PINMUX(10, ESP_U0DSR_IN, ESP_NOSIG) + +#define UART0_DSR_GPIO11 \ + ESP32_PINMUX(11, ESP_U0DSR_IN, ESP_NOSIG) + +#define UART0_DSR_GPIO12 \ + ESP32_PINMUX(12, ESP_U0DSR_IN, ESP_NOSIG) + +#define UART0_DSR_GPIO13 \ + ESP32_PINMUX(13, ESP_U0DSR_IN, ESP_NOSIG) + +#define UART0_DSR_GPIO14 \ + ESP32_PINMUX(14, ESP_U0DSR_IN, ESP_NOSIG) + +#define UART0_DSR_GPIO15 \ + ESP32_PINMUX(15, ESP_U0DSR_IN, ESP_NOSIG) + +#define UART0_DSR_GPIO16 \ + ESP32_PINMUX(16, ESP_U0DSR_IN, ESP_NOSIG) + +#define UART0_DSR_GPIO17 \ + ESP32_PINMUX(17, ESP_U0DSR_IN, ESP_NOSIG) + +#define UART0_DSR_GPIO18 \ + ESP32_PINMUX(18, ESP_U0DSR_IN, ESP_NOSIG) + +#define UART0_DSR_GPIO19 \ + ESP32_PINMUX(19, ESP_U0DSR_IN, ESP_NOSIG) + +#define UART0_DSR_GPIO20 \ + ESP32_PINMUX(20, ESP_U0DSR_IN, ESP_NOSIG) + +#define UART0_DSR_GPIO21 \ + ESP32_PINMUX(21, ESP_U0DSR_IN, ESP_NOSIG) + +/* UART0_DTR */ +#define UART0_DTR_GPIO0 \ + ESP32_PINMUX(0, ESP_NOSIG, ESP_U0DTR_OUT) + +#define UART0_DTR_GPIO1 \ + ESP32_PINMUX(1, ESP_NOSIG, ESP_U0DTR_OUT) + +#define UART0_DTR_GPIO2 \ + ESP32_PINMUX(2, ESP_NOSIG, ESP_U0DTR_OUT) + +#define UART0_DTR_GPIO3 \ + ESP32_PINMUX(3, ESP_NOSIG, ESP_U0DTR_OUT) + +#define UART0_DTR_GPIO4 \ + ESP32_PINMUX(4, ESP_NOSIG, ESP_U0DTR_OUT) + +#define UART0_DTR_GPIO5 \ + ESP32_PINMUX(5, ESP_NOSIG, ESP_U0DTR_OUT) + +#define UART0_DTR_GPIO6 \ + ESP32_PINMUX(6, ESP_NOSIG, ESP_U0DTR_OUT) + +#define UART0_DTR_GPIO7 \ + ESP32_PINMUX(7, ESP_NOSIG, ESP_U0DTR_OUT) + +#define UART0_DTR_GPIO8 \ + ESP32_PINMUX(8, ESP_NOSIG, ESP_U0DTR_OUT) + +#define UART0_DTR_GPIO9 \ + ESP32_PINMUX(9, ESP_NOSIG, ESP_U0DTR_OUT) + +#define UART0_DTR_GPIO10 \ + ESP32_PINMUX(10, ESP_NOSIG, ESP_U0DTR_OUT) + +#define UART0_DTR_GPIO11 \ + ESP32_PINMUX(11, ESP_NOSIG, ESP_U0DTR_OUT) + +#define UART0_DTR_GPIO12 \ + ESP32_PINMUX(12, ESP_NOSIG, ESP_U0DTR_OUT) + +#define UART0_DTR_GPIO13 \ + ESP32_PINMUX(13, ESP_NOSIG, ESP_U0DTR_OUT) + +#define UART0_DTR_GPIO14 \ + ESP32_PINMUX(14, ESP_NOSIG, ESP_U0DTR_OUT) + +#define UART0_DTR_GPIO15 \ + ESP32_PINMUX(15, ESP_NOSIG, ESP_U0DTR_OUT) + +#define UART0_DTR_GPIO16 \ + ESP32_PINMUX(16, ESP_NOSIG, ESP_U0DTR_OUT) + +#define UART0_DTR_GPIO17 \ + ESP32_PINMUX(17, ESP_NOSIG, ESP_U0DTR_OUT) + +#define UART0_DTR_GPIO18 \ + ESP32_PINMUX(18, ESP_NOSIG, ESP_U0DTR_OUT) + +#define UART0_DTR_GPIO19 \ + ESP32_PINMUX(19, ESP_NOSIG, ESP_U0DTR_OUT) + +#define UART0_DTR_GPIO20 \ + ESP32_PINMUX(20, ESP_NOSIG, ESP_U0DTR_OUT) + +#define UART0_DTR_GPIO21 \ + ESP32_PINMUX(21, ESP_NOSIG, ESP_U0DTR_OUT) + +/* UART0_RTS */ +#define UART0_RTS_GPIO0 \ + ESP32_PINMUX(0, ESP_NOSIG, ESP_U0RTS_OUT) + +#define UART0_RTS_GPIO1 \ + ESP32_PINMUX(1, ESP_NOSIG, ESP_U0RTS_OUT) + +#define UART0_RTS_GPIO2 \ + ESP32_PINMUX(2, ESP_NOSIG, ESP_U0RTS_OUT) + +#define UART0_RTS_GPIO3 \ + ESP32_PINMUX(3, ESP_NOSIG, ESP_U0RTS_OUT) + +#define UART0_RTS_GPIO4 \ + ESP32_PINMUX(4, ESP_NOSIG, ESP_U0RTS_OUT) + +#define UART0_RTS_GPIO5 \ + ESP32_PINMUX(5, ESP_NOSIG, ESP_U0RTS_OUT) + +#define UART0_RTS_GPIO6 \ + ESP32_PINMUX(6, ESP_NOSIG, ESP_U0RTS_OUT) + +#define UART0_RTS_GPIO7 \ + ESP32_PINMUX(7, ESP_NOSIG, ESP_U0RTS_OUT) + +#define UART0_RTS_GPIO8 \ + ESP32_PINMUX(8, ESP_NOSIG, ESP_U0RTS_OUT) + +#define UART0_RTS_GPIO9 \ + ESP32_PINMUX(9, ESP_NOSIG, ESP_U0RTS_OUT) + +#define UART0_RTS_GPIO10 \ + ESP32_PINMUX(10, ESP_NOSIG, ESP_U0RTS_OUT) + +#define UART0_RTS_GPIO11 \ + ESP32_PINMUX(11, ESP_NOSIG, ESP_U0RTS_OUT) + +#define UART0_RTS_GPIO12 \ + ESP32_PINMUX(12, ESP_NOSIG, ESP_U0RTS_OUT) + +#define UART0_RTS_GPIO13 \ + ESP32_PINMUX(13, ESP_NOSIG, ESP_U0RTS_OUT) + +#define UART0_RTS_GPIO14 \ + ESP32_PINMUX(14, ESP_NOSIG, ESP_U0RTS_OUT) + +#define UART0_RTS_GPIO15 \ + ESP32_PINMUX(15, ESP_NOSIG, ESP_U0RTS_OUT) + +#define UART0_RTS_GPIO16 \ + ESP32_PINMUX(16, ESP_NOSIG, ESP_U0RTS_OUT) + +#define UART0_RTS_GPIO17 \ + ESP32_PINMUX(17, ESP_NOSIG, ESP_U0RTS_OUT) + +#define UART0_RTS_GPIO18 \ + ESP32_PINMUX(18, ESP_NOSIG, ESP_U0RTS_OUT) + +#define UART0_RTS_GPIO19 \ + ESP32_PINMUX(19, ESP_NOSIG, ESP_U0RTS_OUT) + +#define UART0_RTS_GPIO20 \ + ESP32_PINMUX(20, ESP_NOSIG, ESP_U0RTS_OUT) + +#define UART0_RTS_GPIO21 \ + ESP32_PINMUX(21, ESP_NOSIG, ESP_U0RTS_OUT) + +/* UART0_RX */ +#define UART0_RX_GPIO0 \ + ESP32_PINMUX(0, ESP_U0RXD_IN, ESP_NOSIG) + +#define UART0_RX_GPIO1 \ + ESP32_PINMUX(1, ESP_U0RXD_IN, ESP_NOSIG) + +#define UART0_RX_GPIO2 \ + ESP32_PINMUX(2, ESP_U0RXD_IN, ESP_NOSIG) + +#define UART0_RX_GPIO3 \ + ESP32_PINMUX(3, ESP_U0RXD_IN, ESP_NOSIG) + +#define UART0_RX_GPIO4 \ + ESP32_PINMUX(4, ESP_U0RXD_IN, ESP_NOSIG) + +#define UART0_RX_GPIO5 \ + ESP32_PINMUX(5, ESP_U0RXD_IN, ESP_NOSIG) + +#define UART0_RX_GPIO6 \ + ESP32_PINMUX(6, ESP_U0RXD_IN, ESP_NOSIG) + +#define UART0_RX_GPIO7 \ + ESP32_PINMUX(7, ESP_U0RXD_IN, ESP_NOSIG) + +#define UART0_RX_GPIO8 \ + ESP32_PINMUX(8, ESP_U0RXD_IN, ESP_NOSIG) + +#define UART0_RX_GPIO9 \ + ESP32_PINMUX(9, ESP_U0RXD_IN, ESP_NOSIG) + +#define UART0_RX_GPIO10 \ + ESP32_PINMUX(10, ESP_U0RXD_IN, ESP_NOSIG) + +#define UART0_RX_GPIO11 \ + ESP32_PINMUX(11, ESP_U0RXD_IN, ESP_NOSIG) + +#define UART0_RX_GPIO12 \ + ESP32_PINMUX(12, ESP_U0RXD_IN, ESP_NOSIG) + +#define UART0_RX_GPIO13 \ + ESP32_PINMUX(13, ESP_U0RXD_IN, ESP_NOSIG) + +#define UART0_RX_GPIO14 \ + ESP32_PINMUX(14, ESP_U0RXD_IN, ESP_NOSIG) + +#define UART0_RX_GPIO15 \ + ESP32_PINMUX(15, ESP_U0RXD_IN, ESP_NOSIG) + +#define UART0_RX_GPIO16 \ + ESP32_PINMUX(16, ESP_U0RXD_IN, ESP_NOSIG) + +#define UART0_RX_GPIO17 \ + ESP32_PINMUX(17, ESP_U0RXD_IN, ESP_NOSIG) + +#define UART0_RX_GPIO18 \ + ESP32_PINMUX(18, ESP_U0RXD_IN, ESP_NOSIG) + +#define UART0_RX_GPIO19 \ + ESP32_PINMUX(19, ESP_U0RXD_IN, ESP_NOSIG) + +#define UART0_RX_GPIO20 \ + ESP32_PINMUX(20, ESP_U0RXD_IN, ESP_NOSIG) + +#define UART0_RX_GPIO21 \ + ESP32_PINMUX(21, ESP_U0RXD_IN, ESP_NOSIG) + +/* UART0_TX */ +#define UART0_TX_GPIO0 \ + ESP32_PINMUX(0, ESP_NOSIG, ESP_U0TXD_OUT) + +#define UART0_TX_GPIO1 \ + ESP32_PINMUX(1, ESP_NOSIG, ESP_U0TXD_OUT) + +#define UART0_TX_GPIO2 \ + ESP32_PINMUX(2, ESP_NOSIG, ESP_U0TXD_OUT) + +#define UART0_TX_GPIO3 \ + ESP32_PINMUX(3, ESP_NOSIG, ESP_U0TXD_OUT) + +#define UART0_TX_GPIO4 \ + ESP32_PINMUX(4, ESP_NOSIG, ESP_U0TXD_OUT) + +#define UART0_TX_GPIO5 \ + ESP32_PINMUX(5, ESP_NOSIG, ESP_U0TXD_OUT) + +#define UART0_TX_GPIO6 \ + ESP32_PINMUX(6, ESP_NOSIG, ESP_U0TXD_OUT) + +#define UART0_TX_GPIO7 \ + ESP32_PINMUX(7, ESP_NOSIG, ESP_U0TXD_OUT) + +#define UART0_TX_GPIO8 \ + ESP32_PINMUX(8, ESP_NOSIG, ESP_U0TXD_OUT) + +#define UART0_TX_GPIO9 \ + ESP32_PINMUX(9, ESP_NOSIG, ESP_U0TXD_OUT) + +#define UART0_TX_GPIO10 \ + ESP32_PINMUX(10, ESP_NOSIG, ESP_U0TXD_OUT) + +#define UART0_TX_GPIO11 \ + ESP32_PINMUX(11, ESP_NOSIG, ESP_U0TXD_OUT) + +#define UART0_TX_GPIO12 \ + ESP32_PINMUX(12, ESP_NOSIG, ESP_U0TXD_OUT) + +#define UART0_TX_GPIO13 \ + ESP32_PINMUX(13, ESP_NOSIG, ESP_U0TXD_OUT) + +#define UART0_TX_GPIO14 \ + ESP32_PINMUX(14, ESP_NOSIG, ESP_U0TXD_OUT) + +#define UART0_TX_GPIO15 \ + ESP32_PINMUX(15, ESP_NOSIG, ESP_U0TXD_OUT) + +#define UART0_TX_GPIO16 \ + ESP32_PINMUX(16, ESP_NOSIG, ESP_U0TXD_OUT) + +#define UART0_TX_GPIO17 \ + ESP32_PINMUX(17, ESP_NOSIG, ESP_U0TXD_OUT) + +#define UART0_TX_GPIO18 \ + ESP32_PINMUX(18, ESP_NOSIG, ESP_U0TXD_OUT) + +#define UART0_TX_GPIO19 \ + ESP32_PINMUX(19, ESP_NOSIG, ESP_U0TXD_OUT) + +#define UART0_TX_GPIO20 \ + ESP32_PINMUX(20, ESP_NOSIG, ESP_U0TXD_OUT) + +#define UART0_TX_GPIO21 \ + ESP32_PINMUX(21, ESP_NOSIG, ESP_U0TXD_OUT) + +/* UART1_CTS */ +#define UART1_CTS_GPIO0 \ + ESP32_PINMUX(0, ESP_U1CTS_IN, ESP_NOSIG) + +#define UART1_CTS_GPIO1 \ + ESP32_PINMUX(1, ESP_U1CTS_IN, ESP_NOSIG) + +#define UART1_CTS_GPIO2 \ + ESP32_PINMUX(2, ESP_U1CTS_IN, ESP_NOSIG) + +#define UART1_CTS_GPIO3 \ + ESP32_PINMUX(3, ESP_U1CTS_IN, ESP_NOSIG) + +#define UART1_CTS_GPIO4 \ + ESP32_PINMUX(4, ESP_U1CTS_IN, ESP_NOSIG) + +#define UART1_CTS_GPIO5 \ + ESP32_PINMUX(5, ESP_U1CTS_IN, ESP_NOSIG) + +#define UART1_CTS_GPIO6 \ + ESP32_PINMUX(6, ESP_U1CTS_IN, ESP_NOSIG) + +#define UART1_CTS_GPIO7 \ + ESP32_PINMUX(7, ESP_U1CTS_IN, ESP_NOSIG) + +#define UART1_CTS_GPIO8 \ + ESP32_PINMUX(8, ESP_U1CTS_IN, ESP_NOSIG) + +#define UART1_CTS_GPIO9 \ + ESP32_PINMUX(9, ESP_U1CTS_IN, ESP_NOSIG) + +#define UART1_CTS_GPIO10 \ + ESP32_PINMUX(10, ESP_U1CTS_IN, ESP_NOSIG) + +#define UART1_CTS_GPIO11 \ + ESP32_PINMUX(11, ESP_U1CTS_IN, ESP_NOSIG) + +#define UART1_CTS_GPIO12 \ + ESP32_PINMUX(12, ESP_U1CTS_IN, ESP_NOSIG) + +#define UART1_CTS_GPIO13 \ + ESP32_PINMUX(13, ESP_U1CTS_IN, ESP_NOSIG) + +#define UART1_CTS_GPIO14 \ + ESP32_PINMUX(14, ESP_U1CTS_IN, ESP_NOSIG) + +#define UART1_CTS_GPIO15 \ + ESP32_PINMUX(15, ESP_U1CTS_IN, ESP_NOSIG) + +#define UART1_CTS_GPIO16 \ + ESP32_PINMUX(16, ESP_U1CTS_IN, ESP_NOSIG) + +#define UART1_CTS_GPIO17 \ + ESP32_PINMUX(17, ESP_U1CTS_IN, ESP_NOSIG) + +#define UART1_CTS_GPIO18 \ + ESP32_PINMUX(18, ESP_U1CTS_IN, ESP_NOSIG) + +#define UART1_CTS_GPIO19 \ + ESP32_PINMUX(19, ESP_U1CTS_IN, ESP_NOSIG) + +#define UART1_CTS_GPIO20 \ + ESP32_PINMUX(20, ESP_U1CTS_IN, ESP_NOSIG) + +#define UART1_CTS_GPIO21 \ + ESP32_PINMUX(21, ESP_U1CTS_IN, ESP_NOSIG) + +/* UART1_DSR */ +#define UART1_DSR_GPIO0 \ + ESP32_PINMUX(0, ESP_U1DSR_IN, ESP_NOSIG) + +#define UART1_DSR_GPIO1 \ + ESP32_PINMUX(1, ESP_U1DSR_IN, ESP_NOSIG) + +#define UART1_DSR_GPIO2 \ + ESP32_PINMUX(2, ESP_U1DSR_IN, ESP_NOSIG) + +#define UART1_DSR_GPIO3 \ + ESP32_PINMUX(3, ESP_U1DSR_IN, ESP_NOSIG) + +#define UART1_DSR_GPIO4 \ + ESP32_PINMUX(4, ESP_U1DSR_IN, ESP_NOSIG) + +#define UART1_DSR_GPIO5 \ + ESP32_PINMUX(5, ESP_U1DSR_IN, ESP_NOSIG) + +#define UART1_DSR_GPIO6 \ + ESP32_PINMUX(6, ESP_U1DSR_IN, ESP_NOSIG) + +#define UART1_DSR_GPIO7 \ + ESP32_PINMUX(7, ESP_U1DSR_IN, ESP_NOSIG) + +#define UART1_DSR_GPIO8 \ + ESP32_PINMUX(8, ESP_U1DSR_IN, ESP_NOSIG) + +#define UART1_DSR_GPIO9 \ + ESP32_PINMUX(9, ESP_U1DSR_IN, ESP_NOSIG) + +#define UART1_DSR_GPIO10 \ + ESP32_PINMUX(10, ESP_U1DSR_IN, ESP_NOSIG) + +#define UART1_DSR_GPIO11 \ + ESP32_PINMUX(11, ESP_U1DSR_IN, ESP_NOSIG) + +#define UART1_DSR_GPIO12 \ + ESP32_PINMUX(12, ESP_U1DSR_IN, ESP_NOSIG) + +#define UART1_DSR_GPIO13 \ + ESP32_PINMUX(13, ESP_U1DSR_IN, ESP_NOSIG) + +#define UART1_DSR_GPIO14 \ + ESP32_PINMUX(14, ESP_U1DSR_IN, ESP_NOSIG) + +#define UART1_DSR_GPIO15 \ + ESP32_PINMUX(15, ESP_U1DSR_IN, ESP_NOSIG) + +#define UART1_DSR_GPIO16 \ + ESP32_PINMUX(16, ESP_U1DSR_IN, ESP_NOSIG) + +#define UART1_DSR_GPIO17 \ + ESP32_PINMUX(17, ESP_U1DSR_IN, ESP_NOSIG) + +#define UART1_DSR_GPIO18 \ + ESP32_PINMUX(18, ESP_U1DSR_IN, ESP_NOSIG) + +#define UART1_DSR_GPIO19 \ + ESP32_PINMUX(19, ESP_U1DSR_IN, ESP_NOSIG) + +#define UART1_DSR_GPIO20 \ + ESP32_PINMUX(20, ESP_U1DSR_IN, ESP_NOSIG) + +#define UART1_DSR_GPIO21 \ + ESP32_PINMUX(21, ESP_U1DSR_IN, ESP_NOSIG) + +/* UART1_DTR */ +#define UART1_DTR_GPIO0 \ + ESP32_PINMUX(0, ESP_NOSIG, ESP_U1DTR_OUT) + +#define UART1_DTR_GPIO1 \ + ESP32_PINMUX(1, ESP_NOSIG, ESP_U1DTR_OUT) + +#define UART1_DTR_GPIO2 \ + ESP32_PINMUX(2, ESP_NOSIG, ESP_U1DTR_OUT) + +#define UART1_DTR_GPIO3 \ + ESP32_PINMUX(3, ESP_NOSIG, ESP_U1DTR_OUT) + +#define UART1_DTR_GPIO4 \ + ESP32_PINMUX(4, ESP_NOSIG, ESP_U1DTR_OUT) + +#define UART1_DTR_GPIO5 \ + ESP32_PINMUX(5, ESP_NOSIG, ESP_U1DTR_OUT) + +#define UART1_DTR_GPIO6 \ + ESP32_PINMUX(6, ESP_NOSIG, ESP_U1DTR_OUT) + +#define UART1_DTR_GPIO7 \ + ESP32_PINMUX(7, ESP_NOSIG, ESP_U1DTR_OUT) + +#define UART1_DTR_GPIO8 \ + ESP32_PINMUX(8, ESP_NOSIG, ESP_U1DTR_OUT) + +#define UART1_DTR_GPIO9 \ + ESP32_PINMUX(9, ESP_NOSIG, ESP_U1DTR_OUT) + +#define UART1_DTR_GPIO10 \ + ESP32_PINMUX(10, ESP_NOSIG, ESP_U1DTR_OUT) + +#define UART1_DTR_GPIO11 \ + ESP32_PINMUX(11, ESP_NOSIG, ESP_U1DTR_OUT) + +#define UART1_DTR_GPIO12 \ + ESP32_PINMUX(12, ESP_NOSIG, ESP_U1DTR_OUT) + +#define UART1_DTR_GPIO13 \ + ESP32_PINMUX(13, ESP_NOSIG, ESP_U1DTR_OUT) + +#define UART1_DTR_GPIO14 \ + ESP32_PINMUX(14, ESP_NOSIG, ESP_U1DTR_OUT) + +#define UART1_DTR_GPIO15 \ + ESP32_PINMUX(15, ESP_NOSIG, ESP_U1DTR_OUT) + +#define UART1_DTR_GPIO16 \ + ESP32_PINMUX(16, ESP_NOSIG, ESP_U1DTR_OUT) + +#define UART1_DTR_GPIO17 \ + ESP32_PINMUX(17, ESP_NOSIG, ESP_U1DTR_OUT) + +#define UART1_DTR_GPIO18 \ + ESP32_PINMUX(18, ESP_NOSIG, ESP_U1DTR_OUT) + +#define UART1_DTR_GPIO19 \ + ESP32_PINMUX(19, ESP_NOSIG, ESP_U1DTR_OUT) + +#define UART1_DTR_GPIO20 \ + ESP32_PINMUX(20, ESP_NOSIG, ESP_U1DTR_OUT) + +#define UART1_DTR_GPIO21 \ + ESP32_PINMUX(21, ESP_NOSIG, ESP_U1DTR_OUT) + +/* UART1_RTS */ +#define UART1_RTS_GPIO0 \ + ESP32_PINMUX(0, ESP_NOSIG, ESP_U1RTS_OUT) + +#define UART1_RTS_GPIO1 \ + ESP32_PINMUX(1, ESP_NOSIG, ESP_U1RTS_OUT) + +#define UART1_RTS_GPIO2 \ + ESP32_PINMUX(2, ESP_NOSIG, ESP_U1RTS_OUT) + +#define UART1_RTS_GPIO3 \ + ESP32_PINMUX(3, ESP_NOSIG, ESP_U1RTS_OUT) + +#define UART1_RTS_GPIO4 \ + ESP32_PINMUX(4, ESP_NOSIG, ESP_U1RTS_OUT) + +#define UART1_RTS_GPIO5 \ + ESP32_PINMUX(5, ESP_NOSIG, ESP_U1RTS_OUT) + +#define UART1_RTS_GPIO6 \ + ESP32_PINMUX(6, ESP_NOSIG, ESP_U1RTS_OUT) + +#define UART1_RTS_GPIO7 \ + ESP32_PINMUX(7, ESP_NOSIG, ESP_U1RTS_OUT) + +#define UART1_RTS_GPIO8 \ + ESP32_PINMUX(8, ESP_NOSIG, ESP_U1RTS_OUT) + +#define UART1_RTS_GPIO9 \ + ESP32_PINMUX(9, ESP_NOSIG, ESP_U1RTS_OUT) + +#define UART1_RTS_GPIO10 \ + ESP32_PINMUX(10, ESP_NOSIG, ESP_U1RTS_OUT) + +#define UART1_RTS_GPIO11 \ + ESP32_PINMUX(11, ESP_NOSIG, ESP_U1RTS_OUT) + +#define UART1_RTS_GPIO12 \ + ESP32_PINMUX(12, ESP_NOSIG, ESP_U1RTS_OUT) + +#define UART1_RTS_GPIO13 \ + ESP32_PINMUX(13, ESP_NOSIG, ESP_U1RTS_OUT) + +#define UART1_RTS_GPIO14 \ + ESP32_PINMUX(14, ESP_NOSIG, ESP_U1RTS_OUT) + +#define UART1_RTS_GPIO15 \ + ESP32_PINMUX(15, ESP_NOSIG, ESP_U1RTS_OUT) + +#define UART1_RTS_GPIO16 \ + ESP32_PINMUX(16, ESP_NOSIG, ESP_U1RTS_OUT) + +#define UART1_RTS_GPIO17 \ + ESP32_PINMUX(17, ESP_NOSIG, ESP_U1RTS_OUT) + +#define UART1_RTS_GPIO18 \ + ESP32_PINMUX(18, ESP_NOSIG, ESP_U1RTS_OUT) + +#define UART1_RTS_GPIO19 \ + ESP32_PINMUX(19, ESP_NOSIG, ESP_U1RTS_OUT) + +#define UART1_RTS_GPIO20 \ + ESP32_PINMUX(20, ESP_NOSIG, ESP_U1RTS_OUT) + +#define UART1_RTS_GPIO21 \ + ESP32_PINMUX(21, ESP_NOSIG, ESP_U1RTS_OUT) + +/* UART1_RX */ +#define UART1_RX_GPIO0 \ + ESP32_PINMUX(0, ESP_U1RXD_IN, ESP_NOSIG) + +#define UART1_RX_GPIO1 \ + ESP32_PINMUX(1, ESP_U1RXD_IN, ESP_NOSIG) + +#define UART1_RX_GPIO2 \ + ESP32_PINMUX(2, ESP_U1RXD_IN, ESP_NOSIG) + +#define UART1_RX_GPIO3 \ + ESP32_PINMUX(3, ESP_U1RXD_IN, ESP_NOSIG) + +#define UART1_RX_GPIO4 \ + ESP32_PINMUX(4, ESP_U1RXD_IN, ESP_NOSIG) + +#define UART1_RX_GPIO5 \ + ESP32_PINMUX(5, ESP_U1RXD_IN, ESP_NOSIG) + +#define UART1_RX_GPIO6 \ + ESP32_PINMUX(6, ESP_U1RXD_IN, ESP_NOSIG) + +#define UART1_RX_GPIO7 \ + ESP32_PINMUX(7, ESP_U1RXD_IN, ESP_NOSIG) + +#define UART1_RX_GPIO8 \ + ESP32_PINMUX(8, ESP_U1RXD_IN, ESP_NOSIG) + +#define UART1_RX_GPIO9 \ + ESP32_PINMUX(9, ESP_U1RXD_IN, ESP_NOSIG) + +#define UART1_RX_GPIO10 \ + ESP32_PINMUX(10, ESP_U1RXD_IN, ESP_NOSIG) + +#define UART1_RX_GPIO11 \ + ESP32_PINMUX(11, ESP_U1RXD_IN, ESP_NOSIG) + +#define UART1_RX_GPIO12 \ + ESP32_PINMUX(12, ESP_U1RXD_IN, ESP_NOSIG) + +#define UART1_RX_GPIO13 \ + ESP32_PINMUX(13, ESP_U1RXD_IN, ESP_NOSIG) + +#define UART1_RX_GPIO14 \ + ESP32_PINMUX(14, ESP_U1RXD_IN, ESP_NOSIG) + +#define UART1_RX_GPIO15 \ + ESP32_PINMUX(15, ESP_U1RXD_IN, ESP_NOSIG) + +#define UART1_RX_GPIO16 \ + ESP32_PINMUX(16, ESP_U1RXD_IN, ESP_NOSIG) + +#define UART1_RX_GPIO17 \ + ESP32_PINMUX(17, ESP_U1RXD_IN, ESP_NOSIG) + +#define UART1_RX_GPIO18 \ + ESP32_PINMUX(18, ESP_U1RXD_IN, ESP_NOSIG) + +#define UART1_RX_GPIO19 \ + ESP32_PINMUX(19, ESP_U1RXD_IN, ESP_NOSIG) + +#define UART1_RX_GPIO20 \ + ESP32_PINMUX(20, ESP_U1RXD_IN, ESP_NOSIG) + +#define UART1_RX_GPIO21 \ + ESP32_PINMUX(21, ESP_U1RXD_IN, ESP_NOSIG) + +/* UART1_TX */ +#define UART1_TX_GPIO0 \ + ESP32_PINMUX(0, ESP_NOSIG, ESP_U1TXD_OUT) + +#define UART1_TX_GPIO1 \ + ESP32_PINMUX(1, ESP_NOSIG, ESP_U1TXD_OUT) + +#define UART1_TX_GPIO2 \ + ESP32_PINMUX(2, ESP_NOSIG, ESP_U1TXD_OUT) + +#define UART1_TX_GPIO3 \ + ESP32_PINMUX(3, ESP_NOSIG, ESP_U1TXD_OUT) + +#define UART1_TX_GPIO4 \ + ESP32_PINMUX(4, ESP_NOSIG, ESP_U1TXD_OUT) + +#define UART1_TX_GPIO5 \ + ESP32_PINMUX(5, ESP_NOSIG, ESP_U1TXD_OUT) + +#define UART1_TX_GPIO6 \ + ESP32_PINMUX(6, ESP_NOSIG, ESP_U1TXD_OUT) + +#define UART1_TX_GPIO7 \ + ESP32_PINMUX(7, ESP_NOSIG, ESP_U1TXD_OUT) + +#define UART1_TX_GPIO8 \ + ESP32_PINMUX(8, ESP_NOSIG, ESP_U1TXD_OUT) + +#define UART1_TX_GPIO9 \ + ESP32_PINMUX(9, ESP_NOSIG, ESP_U1TXD_OUT) + +#define UART1_TX_GPIO10 \ + ESP32_PINMUX(10, ESP_NOSIG, ESP_U1TXD_OUT) + +#define UART1_TX_GPIO11 \ + ESP32_PINMUX(11, ESP_NOSIG, ESP_U1TXD_OUT) + +#define UART1_TX_GPIO12 \ + ESP32_PINMUX(12, ESP_NOSIG, ESP_U1TXD_OUT) + +#define UART1_TX_GPIO13 \ + ESP32_PINMUX(13, ESP_NOSIG, ESP_U1TXD_OUT) + +#define UART1_TX_GPIO14 \ + ESP32_PINMUX(14, ESP_NOSIG, ESP_U1TXD_OUT) + +#define UART1_TX_GPIO15 \ + ESP32_PINMUX(15, ESP_NOSIG, ESP_U1TXD_OUT) + +#define UART1_TX_GPIO16 \ + ESP32_PINMUX(16, ESP_NOSIG, ESP_U1TXD_OUT) + +#define UART1_TX_GPIO17 \ + ESP32_PINMUX(17, ESP_NOSIG, ESP_U1TXD_OUT) + +#define UART1_TX_GPIO18 \ + ESP32_PINMUX(18, ESP_NOSIG, ESP_U1TXD_OUT) + +#define UART1_TX_GPIO19 \ + ESP32_PINMUX(19, ESP_NOSIG, ESP_U1TXD_OUT) + +#define UART1_TX_GPIO20 \ + ESP32_PINMUX(20, ESP_NOSIG, ESP_U1TXD_OUT) + +#define UART1_TX_GPIO21 \ + ESP32_PINMUX(21, ESP_NOSIG, ESP_U1TXD_OUT) + + +#endif /* INC_DT_BINDS_PINCTRL_ESP32C3_PINCTRL_HAL_H_ */ diff --git a/include/zephyr/dt-bindings/pinctrl/esp32s2-pinctrl.h b/include/zephyr/dt-bindings/pinctrl/esp32s2-pinctrl.h new file mode 100644 index 00000000000..5d97a79b176 --- /dev/null +++ b/include/zephyr/dt-bindings/pinctrl/esp32s2-pinctrl.h @@ -0,0 +1,7587 @@ +/* + * Copyright (c) 2022 Espressif Systems (Shanghai) Co., Ltd. + * + * SPDX-License-Identifier: Apache-2.0 + * + * NOTE: Autogenerated file using esp_genpinctrl.py + */ + +#ifndef INC_DT_BINDS_PINCTRL_ESP32S2_PINCTRL_HAL_H_ +#define INC_DT_BINDS_PINCTRL_ESP32S2_PINCTRL_HAL_H_ + +/* I2C0_SCL */ +#define I2C0_SCL_GPIO0 \ + ESP32_PINMUX(0, ESP_I2CEXT0_SCL_IN, ESP_I2CEXT0_SCL_OUT) + +#define I2C0_SCL_GPIO1 \ + ESP32_PINMUX(1, ESP_I2CEXT0_SCL_IN, ESP_I2CEXT0_SCL_OUT) + +#define I2C0_SCL_GPIO2 \ + ESP32_PINMUX(2, ESP_I2CEXT0_SCL_IN, ESP_I2CEXT0_SCL_OUT) + +#define I2C0_SCL_GPIO3 \ + ESP32_PINMUX(3, ESP_I2CEXT0_SCL_IN, ESP_I2CEXT0_SCL_OUT) + +#define I2C0_SCL_GPIO4 \ + ESP32_PINMUX(4, ESP_I2CEXT0_SCL_IN, ESP_I2CEXT0_SCL_OUT) + +#define I2C0_SCL_GPIO5 \ + ESP32_PINMUX(5, ESP_I2CEXT0_SCL_IN, ESP_I2CEXT0_SCL_OUT) + +#define I2C0_SCL_GPIO6 \ + ESP32_PINMUX(6, ESP_I2CEXT0_SCL_IN, ESP_I2CEXT0_SCL_OUT) + +#define I2C0_SCL_GPIO7 \ + ESP32_PINMUX(7, ESP_I2CEXT0_SCL_IN, ESP_I2CEXT0_SCL_OUT) + +#define I2C0_SCL_GPIO8 \ + ESP32_PINMUX(8, ESP_I2CEXT0_SCL_IN, ESP_I2CEXT0_SCL_OUT) + +#define I2C0_SCL_GPIO9 \ + ESP32_PINMUX(9, ESP_I2CEXT0_SCL_IN, ESP_I2CEXT0_SCL_OUT) + +#define I2C0_SCL_GPIO10 \ + ESP32_PINMUX(10, ESP_I2CEXT0_SCL_IN, ESP_I2CEXT0_SCL_OUT) + +#define I2C0_SCL_GPIO11 \ + ESP32_PINMUX(11, ESP_I2CEXT0_SCL_IN, ESP_I2CEXT0_SCL_OUT) + +#define I2C0_SCL_GPIO12 \ + ESP32_PINMUX(12, ESP_I2CEXT0_SCL_IN, ESP_I2CEXT0_SCL_OUT) + +#define I2C0_SCL_GPIO13 \ + ESP32_PINMUX(13, ESP_I2CEXT0_SCL_IN, ESP_I2CEXT0_SCL_OUT) + +#define I2C0_SCL_GPIO14 \ + ESP32_PINMUX(14, ESP_I2CEXT0_SCL_IN, ESP_I2CEXT0_SCL_OUT) + +#define I2C0_SCL_GPIO15 \ + ESP32_PINMUX(15, ESP_I2CEXT0_SCL_IN, ESP_I2CEXT0_SCL_OUT) + +#define I2C0_SCL_GPIO16 \ + ESP32_PINMUX(16, ESP_I2CEXT0_SCL_IN, ESP_I2CEXT0_SCL_OUT) + +#define I2C0_SCL_GPIO17 \ + ESP32_PINMUX(17, ESP_I2CEXT0_SCL_IN, ESP_I2CEXT0_SCL_OUT) + +#define I2C0_SCL_GPIO18 \ + ESP32_PINMUX(18, ESP_I2CEXT0_SCL_IN, ESP_I2CEXT0_SCL_OUT) + +#define I2C0_SCL_GPIO19 \ + ESP32_PINMUX(19, ESP_I2CEXT0_SCL_IN, ESP_I2CEXT0_SCL_OUT) + +#define I2C0_SCL_GPIO20 \ + ESP32_PINMUX(20, ESP_I2CEXT0_SCL_IN, ESP_I2CEXT0_SCL_OUT) + +#define I2C0_SCL_GPIO21 \ + ESP32_PINMUX(21, ESP_I2CEXT0_SCL_IN, ESP_I2CEXT0_SCL_OUT) + +#define I2C0_SCL_GPIO26 \ + ESP32_PINMUX(26, ESP_I2CEXT0_SCL_IN, ESP_I2CEXT0_SCL_OUT) + +#define I2C0_SCL_GPIO27 \ + ESP32_PINMUX(27, ESP_I2CEXT0_SCL_IN, ESP_I2CEXT0_SCL_OUT) + +#define I2C0_SCL_GPIO28 \ + ESP32_PINMUX(28, ESP_I2CEXT0_SCL_IN, ESP_I2CEXT0_SCL_OUT) + +#define I2C0_SCL_GPIO29 \ + ESP32_PINMUX(29, ESP_I2CEXT0_SCL_IN, ESP_I2CEXT0_SCL_OUT) + +#define I2C0_SCL_GPIO30 \ + ESP32_PINMUX(30, ESP_I2CEXT0_SCL_IN, ESP_I2CEXT0_SCL_OUT) + +#define I2C0_SCL_GPIO31 \ + ESP32_PINMUX(31, ESP_I2CEXT0_SCL_IN, ESP_I2CEXT0_SCL_OUT) + +#define I2C0_SCL_GPIO32 \ + ESP32_PINMUX(32, ESP_I2CEXT0_SCL_IN, ESP_I2CEXT0_SCL_OUT) + +#define I2C0_SCL_GPIO33 \ + ESP32_PINMUX(33, ESP_I2CEXT0_SCL_IN, ESP_I2CEXT0_SCL_OUT) + +#define I2C0_SCL_GPIO34 \ + ESP32_PINMUX(34, ESP_I2CEXT0_SCL_IN, ESP_I2CEXT0_SCL_OUT) + +#define I2C0_SCL_GPIO35 \ + ESP32_PINMUX(35, ESP_I2CEXT0_SCL_IN, ESP_I2CEXT0_SCL_OUT) + +#define I2C0_SCL_GPIO36 \ + ESP32_PINMUX(36, ESP_I2CEXT0_SCL_IN, ESP_I2CEXT0_SCL_OUT) + +#define I2C0_SCL_GPIO37 \ + ESP32_PINMUX(37, ESP_I2CEXT0_SCL_IN, ESP_I2CEXT0_SCL_OUT) + +#define I2C0_SCL_GPIO38 \ + ESP32_PINMUX(38, ESP_I2CEXT0_SCL_IN, ESP_I2CEXT0_SCL_OUT) + +#define I2C0_SCL_GPIO39 \ + ESP32_PINMUX(39, ESP_I2CEXT0_SCL_IN, ESP_I2CEXT0_SCL_OUT) + +#define I2C0_SCL_GPIO40 \ + ESP32_PINMUX(40, ESP_I2CEXT0_SCL_IN, ESP_I2CEXT0_SCL_OUT) + +#define I2C0_SCL_GPIO41 \ + ESP32_PINMUX(41, ESP_I2CEXT0_SCL_IN, ESP_I2CEXT0_SCL_OUT) + +#define I2C0_SCL_GPIO42 \ + ESP32_PINMUX(42, ESP_I2CEXT0_SCL_IN, ESP_I2CEXT0_SCL_OUT) + +#define I2C0_SCL_GPIO43 \ + ESP32_PINMUX(43, ESP_I2CEXT0_SCL_IN, ESP_I2CEXT0_SCL_OUT) + +#define I2C0_SCL_GPIO44 \ + ESP32_PINMUX(44, ESP_I2CEXT0_SCL_IN, ESP_I2CEXT0_SCL_OUT) + +#define I2C0_SCL_GPIO45 \ + ESP32_PINMUX(45, ESP_I2CEXT0_SCL_IN, ESP_I2CEXT0_SCL_OUT) + +/* I2C0_SDA */ +#define I2C0_SDA_GPIO0 \ + ESP32_PINMUX(0, ESP_I2CEXT0_SDA_IN, ESP_I2CEXT0_SDA_OUT) + +#define I2C0_SDA_GPIO1 \ + ESP32_PINMUX(1, ESP_I2CEXT0_SDA_IN, ESP_I2CEXT0_SDA_OUT) + +#define I2C0_SDA_GPIO2 \ + ESP32_PINMUX(2, ESP_I2CEXT0_SDA_IN, ESP_I2CEXT0_SDA_OUT) + +#define I2C0_SDA_GPIO3 \ + ESP32_PINMUX(3, ESP_I2CEXT0_SDA_IN, ESP_I2CEXT0_SDA_OUT) + +#define I2C0_SDA_GPIO4 \ + ESP32_PINMUX(4, ESP_I2CEXT0_SDA_IN, ESP_I2CEXT0_SDA_OUT) + +#define I2C0_SDA_GPIO5 \ + ESP32_PINMUX(5, ESP_I2CEXT0_SDA_IN, ESP_I2CEXT0_SDA_OUT) + +#define I2C0_SDA_GPIO6 \ + ESP32_PINMUX(6, ESP_I2CEXT0_SDA_IN, ESP_I2CEXT0_SDA_OUT) + +#define I2C0_SDA_GPIO7 \ + ESP32_PINMUX(7, ESP_I2CEXT0_SDA_IN, ESP_I2CEXT0_SDA_OUT) + +#define I2C0_SDA_GPIO8 \ + ESP32_PINMUX(8, ESP_I2CEXT0_SDA_IN, ESP_I2CEXT0_SDA_OUT) + +#define I2C0_SDA_GPIO9 \ + ESP32_PINMUX(9, ESP_I2CEXT0_SDA_IN, ESP_I2CEXT0_SDA_OUT) + +#define I2C0_SDA_GPIO10 \ + ESP32_PINMUX(10, ESP_I2CEXT0_SDA_IN, ESP_I2CEXT0_SDA_OUT) + +#define I2C0_SDA_GPIO11 \ + ESP32_PINMUX(11, ESP_I2CEXT0_SDA_IN, ESP_I2CEXT0_SDA_OUT) + +#define I2C0_SDA_GPIO12 \ + ESP32_PINMUX(12, ESP_I2CEXT0_SDA_IN, ESP_I2CEXT0_SDA_OUT) + +#define I2C0_SDA_GPIO13 \ + ESP32_PINMUX(13, ESP_I2CEXT0_SDA_IN, ESP_I2CEXT0_SDA_OUT) + +#define I2C0_SDA_GPIO14 \ + ESP32_PINMUX(14, ESP_I2CEXT0_SDA_IN, ESP_I2CEXT0_SDA_OUT) + +#define I2C0_SDA_GPIO15 \ + ESP32_PINMUX(15, ESP_I2CEXT0_SDA_IN, ESP_I2CEXT0_SDA_OUT) + +#define I2C0_SDA_GPIO16 \ + ESP32_PINMUX(16, ESP_I2CEXT0_SDA_IN, ESP_I2CEXT0_SDA_OUT) + +#define I2C0_SDA_GPIO17 \ + ESP32_PINMUX(17, ESP_I2CEXT0_SDA_IN, ESP_I2CEXT0_SDA_OUT) + +#define I2C0_SDA_GPIO18 \ + ESP32_PINMUX(18, ESP_I2CEXT0_SDA_IN, ESP_I2CEXT0_SDA_OUT) + +#define I2C0_SDA_GPIO19 \ + ESP32_PINMUX(19, ESP_I2CEXT0_SDA_IN, ESP_I2CEXT0_SDA_OUT) + +#define I2C0_SDA_GPIO20 \ + ESP32_PINMUX(20, ESP_I2CEXT0_SDA_IN, ESP_I2CEXT0_SDA_OUT) + +#define I2C0_SDA_GPIO21 \ + ESP32_PINMUX(21, ESP_I2CEXT0_SDA_IN, ESP_I2CEXT0_SDA_OUT) + +#define I2C0_SDA_GPIO26 \ + ESP32_PINMUX(26, ESP_I2CEXT0_SDA_IN, ESP_I2CEXT0_SDA_OUT) + +#define I2C0_SDA_GPIO27 \ + ESP32_PINMUX(27, ESP_I2CEXT0_SDA_IN, ESP_I2CEXT0_SDA_OUT) + +#define I2C0_SDA_GPIO28 \ + ESP32_PINMUX(28, ESP_I2CEXT0_SDA_IN, ESP_I2CEXT0_SDA_OUT) + +#define I2C0_SDA_GPIO29 \ + ESP32_PINMUX(29, ESP_I2CEXT0_SDA_IN, ESP_I2CEXT0_SDA_OUT) + +#define I2C0_SDA_GPIO30 \ + ESP32_PINMUX(30, ESP_I2CEXT0_SDA_IN, ESP_I2CEXT0_SDA_OUT) + +#define I2C0_SDA_GPIO31 \ + ESP32_PINMUX(31, ESP_I2CEXT0_SDA_IN, ESP_I2CEXT0_SDA_OUT) + +#define I2C0_SDA_GPIO32 \ + ESP32_PINMUX(32, ESP_I2CEXT0_SDA_IN, ESP_I2CEXT0_SDA_OUT) + +#define I2C0_SDA_GPIO33 \ + ESP32_PINMUX(33, ESP_I2CEXT0_SDA_IN, ESP_I2CEXT0_SDA_OUT) + +#define I2C0_SDA_GPIO34 \ + ESP32_PINMUX(34, ESP_I2CEXT0_SDA_IN, ESP_I2CEXT0_SDA_OUT) + +#define I2C0_SDA_GPIO35 \ + ESP32_PINMUX(35, ESP_I2CEXT0_SDA_IN, ESP_I2CEXT0_SDA_OUT) + +#define I2C0_SDA_GPIO36 \ + ESP32_PINMUX(36, ESP_I2CEXT0_SDA_IN, ESP_I2CEXT0_SDA_OUT) + +#define I2C0_SDA_GPIO37 \ + ESP32_PINMUX(37, ESP_I2CEXT0_SDA_IN, ESP_I2CEXT0_SDA_OUT) + +#define I2C0_SDA_GPIO38 \ + ESP32_PINMUX(38, ESP_I2CEXT0_SDA_IN, ESP_I2CEXT0_SDA_OUT) + +#define I2C0_SDA_GPIO39 \ + ESP32_PINMUX(39, ESP_I2CEXT0_SDA_IN, ESP_I2CEXT0_SDA_OUT) + +#define I2C0_SDA_GPIO40 \ + ESP32_PINMUX(40, ESP_I2CEXT0_SDA_IN, ESP_I2CEXT0_SDA_OUT) + +#define I2C0_SDA_GPIO41 \ + ESP32_PINMUX(41, ESP_I2CEXT0_SDA_IN, ESP_I2CEXT0_SDA_OUT) + +#define I2C0_SDA_GPIO42 \ + ESP32_PINMUX(42, ESP_I2CEXT0_SDA_IN, ESP_I2CEXT0_SDA_OUT) + +#define I2C0_SDA_GPIO43 \ + ESP32_PINMUX(43, ESP_I2CEXT0_SDA_IN, ESP_I2CEXT0_SDA_OUT) + +#define I2C0_SDA_GPIO44 \ + ESP32_PINMUX(44, ESP_I2CEXT0_SDA_IN, ESP_I2CEXT0_SDA_OUT) + +#define I2C0_SDA_GPIO45 \ + ESP32_PINMUX(45, ESP_I2CEXT0_SDA_IN, ESP_I2CEXT0_SDA_OUT) + +/* I2C1_SCL */ +#define I2C1_SCL_GPIO0 \ + ESP32_PINMUX(0, ESP_I2CEXT1_SCL_IN, ESP_I2CEXT1_SCL_OUT) + +#define I2C1_SCL_GPIO1 \ + ESP32_PINMUX(1, ESP_I2CEXT1_SCL_IN, ESP_I2CEXT1_SCL_OUT) + +#define I2C1_SCL_GPIO2 \ + ESP32_PINMUX(2, ESP_I2CEXT1_SCL_IN, ESP_I2CEXT1_SCL_OUT) + +#define I2C1_SCL_GPIO3 \ + ESP32_PINMUX(3, ESP_I2CEXT1_SCL_IN, ESP_I2CEXT1_SCL_OUT) + +#define I2C1_SCL_GPIO4 \ + ESP32_PINMUX(4, ESP_I2CEXT1_SCL_IN, ESP_I2CEXT1_SCL_OUT) + +#define I2C1_SCL_GPIO5 \ + ESP32_PINMUX(5, ESP_I2CEXT1_SCL_IN, ESP_I2CEXT1_SCL_OUT) + +#define I2C1_SCL_GPIO6 \ + ESP32_PINMUX(6, ESP_I2CEXT1_SCL_IN, ESP_I2CEXT1_SCL_OUT) + +#define I2C1_SCL_GPIO7 \ + ESP32_PINMUX(7, ESP_I2CEXT1_SCL_IN, ESP_I2CEXT1_SCL_OUT) + +#define I2C1_SCL_GPIO8 \ + ESP32_PINMUX(8, ESP_I2CEXT1_SCL_IN, ESP_I2CEXT1_SCL_OUT) + +#define I2C1_SCL_GPIO9 \ + ESP32_PINMUX(9, ESP_I2CEXT1_SCL_IN, ESP_I2CEXT1_SCL_OUT) + +#define I2C1_SCL_GPIO10 \ + ESP32_PINMUX(10, ESP_I2CEXT1_SCL_IN, ESP_I2CEXT1_SCL_OUT) + +#define I2C1_SCL_GPIO11 \ + ESP32_PINMUX(11, ESP_I2CEXT1_SCL_IN, ESP_I2CEXT1_SCL_OUT) + +#define I2C1_SCL_GPIO12 \ + ESP32_PINMUX(12, ESP_I2CEXT1_SCL_IN, ESP_I2CEXT1_SCL_OUT) + +#define I2C1_SCL_GPIO13 \ + ESP32_PINMUX(13, ESP_I2CEXT1_SCL_IN, ESP_I2CEXT1_SCL_OUT) + +#define I2C1_SCL_GPIO14 \ + ESP32_PINMUX(14, ESP_I2CEXT1_SCL_IN, ESP_I2CEXT1_SCL_OUT) + +#define I2C1_SCL_GPIO15 \ + ESP32_PINMUX(15, ESP_I2CEXT1_SCL_IN, ESP_I2CEXT1_SCL_OUT) + +#define I2C1_SCL_GPIO16 \ + ESP32_PINMUX(16, ESP_I2CEXT1_SCL_IN, ESP_I2CEXT1_SCL_OUT) + +#define I2C1_SCL_GPIO17 \ + ESP32_PINMUX(17, ESP_I2CEXT1_SCL_IN, ESP_I2CEXT1_SCL_OUT) + +#define I2C1_SCL_GPIO18 \ + ESP32_PINMUX(18, ESP_I2CEXT1_SCL_IN, ESP_I2CEXT1_SCL_OUT) + +#define I2C1_SCL_GPIO19 \ + ESP32_PINMUX(19, ESP_I2CEXT1_SCL_IN, ESP_I2CEXT1_SCL_OUT) + +#define I2C1_SCL_GPIO20 \ + ESP32_PINMUX(20, ESP_I2CEXT1_SCL_IN, ESP_I2CEXT1_SCL_OUT) + +#define I2C1_SCL_GPIO21 \ + ESP32_PINMUX(21, ESP_I2CEXT1_SCL_IN, ESP_I2CEXT1_SCL_OUT) + +#define I2C1_SCL_GPIO26 \ + ESP32_PINMUX(26, ESP_I2CEXT1_SCL_IN, ESP_I2CEXT1_SCL_OUT) + +#define I2C1_SCL_GPIO27 \ + ESP32_PINMUX(27, ESP_I2CEXT1_SCL_IN, ESP_I2CEXT1_SCL_OUT) + +#define I2C1_SCL_GPIO28 \ + ESP32_PINMUX(28, ESP_I2CEXT1_SCL_IN, ESP_I2CEXT1_SCL_OUT) + +#define I2C1_SCL_GPIO29 \ + ESP32_PINMUX(29, ESP_I2CEXT1_SCL_IN, ESP_I2CEXT1_SCL_OUT) + +#define I2C1_SCL_GPIO30 \ + ESP32_PINMUX(30, ESP_I2CEXT1_SCL_IN, ESP_I2CEXT1_SCL_OUT) + +#define I2C1_SCL_GPIO31 \ + ESP32_PINMUX(31, ESP_I2CEXT1_SCL_IN, ESP_I2CEXT1_SCL_OUT) + +#define I2C1_SCL_GPIO32 \ + ESP32_PINMUX(32, ESP_I2CEXT1_SCL_IN, ESP_I2CEXT1_SCL_OUT) + +#define I2C1_SCL_GPIO33 \ + ESP32_PINMUX(33, ESP_I2CEXT1_SCL_IN, ESP_I2CEXT1_SCL_OUT) + +#define I2C1_SCL_GPIO34 \ + ESP32_PINMUX(34, ESP_I2CEXT1_SCL_IN, ESP_I2CEXT1_SCL_OUT) + +#define I2C1_SCL_GPIO35 \ + ESP32_PINMUX(35, ESP_I2CEXT1_SCL_IN, ESP_I2CEXT1_SCL_OUT) + +#define I2C1_SCL_GPIO36 \ + ESP32_PINMUX(36, ESP_I2CEXT1_SCL_IN, ESP_I2CEXT1_SCL_OUT) + +#define I2C1_SCL_GPIO37 \ + ESP32_PINMUX(37, ESP_I2CEXT1_SCL_IN, ESP_I2CEXT1_SCL_OUT) + +#define I2C1_SCL_GPIO38 \ + ESP32_PINMUX(38, ESP_I2CEXT1_SCL_IN, ESP_I2CEXT1_SCL_OUT) + +#define I2C1_SCL_GPIO39 \ + ESP32_PINMUX(39, ESP_I2CEXT1_SCL_IN, ESP_I2CEXT1_SCL_OUT) + +#define I2C1_SCL_GPIO40 \ + ESP32_PINMUX(40, ESP_I2CEXT1_SCL_IN, ESP_I2CEXT1_SCL_OUT) + +#define I2C1_SCL_GPIO41 \ + ESP32_PINMUX(41, ESP_I2CEXT1_SCL_IN, ESP_I2CEXT1_SCL_OUT) + +#define I2C1_SCL_GPIO42 \ + ESP32_PINMUX(42, ESP_I2CEXT1_SCL_IN, ESP_I2CEXT1_SCL_OUT) + +#define I2C1_SCL_GPIO43 \ + ESP32_PINMUX(43, ESP_I2CEXT1_SCL_IN, ESP_I2CEXT1_SCL_OUT) + +#define I2C1_SCL_GPIO44 \ + ESP32_PINMUX(44, ESP_I2CEXT1_SCL_IN, ESP_I2CEXT1_SCL_OUT) + +#define I2C1_SCL_GPIO45 \ + ESP32_PINMUX(45, ESP_I2CEXT1_SCL_IN, ESP_I2CEXT1_SCL_OUT) + +/* I2C1_SDA */ +#define I2C1_SDA_GPIO0 \ + ESP32_PINMUX(0, ESP_I2CEXT1_SDA_IN, ESP_I2CEXT1_SDA_OUT) + +#define I2C1_SDA_GPIO1 \ + ESP32_PINMUX(1, ESP_I2CEXT1_SDA_IN, ESP_I2CEXT1_SDA_OUT) + +#define I2C1_SDA_GPIO2 \ + ESP32_PINMUX(2, ESP_I2CEXT1_SDA_IN, ESP_I2CEXT1_SDA_OUT) + +#define I2C1_SDA_GPIO3 \ + ESP32_PINMUX(3, ESP_I2CEXT1_SDA_IN, ESP_I2CEXT1_SDA_OUT) + +#define I2C1_SDA_GPIO4 \ + ESP32_PINMUX(4, ESP_I2CEXT1_SDA_IN, ESP_I2CEXT1_SDA_OUT) + +#define I2C1_SDA_GPIO5 \ + ESP32_PINMUX(5, ESP_I2CEXT1_SDA_IN, ESP_I2CEXT1_SDA_OUT) + +#define I2C1_SDA_GPIO6 \ + ESP32_PINMUX(6, ESP_I2CEXT1_SDA_IN, ESP_I2CEXT1_SDA_OUT) + +#define I2C1_SDA_GPIO7 \ + ESP32_PINMUX(7, ESP_I2CEXT1_SDA_IN, ESP_I2CEXT1_SDA_OUT) + +#define I2C1_SDA_GPIO8 \ + ESP32_PINMUX(8, ESP_I2CEXT1_SDA_IN, ESP_I2CEXT1_SDA_OUT) + +#define I2C1_SDA_GPIO9 \ + ESP32_PINMUX(9, ESP_I2CEXT1_SDA_IN, ESP_I2CEXT1_SDA_OUT) + +#define I2C1_SDA_GPIO10 \ + ESP32_PINMUX(10, ESP_I2CEXT1_SDA_IN, ESP_I2CEXT1_SDA_OUT) + +#define I2C1_SDA_GPIO11 \ + ESP32_PINMUX(11, ESP_I2CEXT1_SDA_IN, ESP_I2CEXT1_SDA_OUT) + +#define I2C1_SDA_GPIO12 \ + ESP32_PINMUX(12, ESP_I2CEXT1_SDA_IN, ESP_I2CEXT1_SDA_OUT) + +#define I2C1_SDA_GPIO13 \ + ESP32_PINMUX(13, ESP_I2CEXT1_SDA_IN, ESP_I2CEXT1_SDA_OUT) + +#define I2C1_SDA_GPIO14 \ + ESP32_PINMUX(14, ESP_I2CEXT1_SDA_IN, ESP_I2CEXT1_SDA_OUT) + +#define I2C1_SDA_GPIO15 \ + ESP32_PINMUX(15, ESP_I2CEXT1_SDA_IN, ESP_I2CEXT1_SDA_OUT) + +#define I2C1_SDA_GPIO16 \ + ESP32_PINMUX(16, ESP_I2CEXT1_SDA_IN, ESP_I2CEXT1_SDA_OUT) + +#define I2C1_SDA_GPIO17 \ + ESP32_PINMUX(17, ESP_I2CEXT1_SDA_IN, ESP_I2CEXT1_SDA_OUT) + +#define I2C1_SDA_GPIO18 \ + ESP32_PINMUX(18, ESP_I2CEXT1_SDA_IN, ESP_I2CEXT1_SDA_OUT) + +#define I2C1_SDA_GPIO19 \ + ESP32_PINMUX(19, ESP_I2CEXT1_SDA_IN, ESP_I2CEXT1_SDA_OUT) + +#define I2C1_SDA_GPIO20 \ + ESP32_PINMUX(20, ESP_I2CEXT1_SDA_IN, ESP_I2CEXT1_SDA_OUT) + +#define I2C1_SDA_GPIO21 \ + ESP32_PINMUX(21, ESP_I2CEXT1_SDA_IN, ESP_I2CEXT1_SDA_OUT) + +#define I2C1_SDA_GPIO26 \ + ESP32_PINMUX(26, ESP_I2CEXT1_SDA_IN, ESP_I2CEXT1_SDA_OUT) + +#define I2C1_SDA_GPIO27 \ + ESP32_PINMUX(27, ESP_I2CEXT1_SDA_IN, ESP_I2CEXT1_SDA_OUT) + +#define I2C1_SDA_GPIO28 \ + ESP32_PINMUX(28, ESP_I2CEXT1_SDA_IN, ESP_I2CEXT1_SDA_OUT) + +#define I2C1_SDA_GPIO29 \ + ESP32_PINMUX(29, ESP_I2CEXT1_SDA_IN, ESP_I2CEXT1_SDA_OUT) + +#define I2C1_SDA_GPIO30 \ + ESP32_PINMUX(30, ESP_I2CEXT1_SDA_IN, ESP_I2CEXT1_SDA_OUT) + +#define I2C1_SDA_GPIO31 \ + ESP32_PINMUX(31, ESP_I2CEXT1_SDA_IN, ESP_I2CEXT1_SDA_OUT) + +#define I2C1_SDA_GPIO32 \ + ESP32_PINMUX(32, ESP_I2CEXT1_SDA_IN, ESP_I2CEXT1_SDA_OUT) + +#define I2C1_SDA_GPIO33 \ + ESP32_PINMUX(33, ESP_I2CEXT1_SDA_IN, ESP_I2CEXT1_SDA_OUT) + +#define I2C1_SDA_GPIO34 \ + ESP32_PINMUX(34, ESP_I2CEXT1_SDA_IN, ESP_I2CEXT1_SDA_OUT) + +#define I2C1_SDA_GPIO35 \ + ESP32_PINMUX(35, ESP_I2CEXT1_SDA_IN, ESP_I2CEXT1_SDA_OUT) + +#define I2C1_SDA_GPIO36 \ + ESP32_PINMUX(36, ESP_I2CEXT1_SDA_IN, ESP_I2CEXT1_SDA_OUT) + +#define I2C1_SDA_GPIO37 \ + ESP32_PINMUX(37, ESP_I2CEXT1_SDA_IN, ESP_I2CEXT1_SDA_OUT) + +#define I2C1_SDA_GPIO38 \ + ESP32_PINMUX(38, ESP_I2CEXT1_SDA_IN, ESP_I2CEXT1_SDA_OUT) + +#define I2C1_SDA_GPIO39 \ + ESP32_PINMUX(39, ESP_I2CEXT1_SDA_IN, ESP_I2CEXT1_SDA_OUT) + +#define I2C1_SDA_GPIO40 \ + ESP32_PINMUX(40, ESP_I2CEXT1_SDA_IN, ESP_I2CEXT1_SDA_OUT) + +#define I2C1_SDA_GPIO41 \ + ESP32_PINMUX(41, ESP_I2CEXT1_SDA_IN, ESP_I2CEXT1_SDA_OUT) + +#define I2C1_SDA_GPIO42 \ + ESP32_PINMUX(42, ESP_I2CEXT1_SDA_IN, ESP_I2CEXT1_SDA_OUT) + +#define I2C1_SDA_GPIO43 \ + ESP32_PINMUX(43, ESP_I2CEXT1_SDA_IN, ESP_I2CEXT1_SDA_OUT) + +#define I2C1_SDA_GPIO44 \ + ESP32_PINMUX(44, ESP_I2CEXT1_SDA_IN, ESP_I2CEXT1_SDA_OUT) + +#define I2C1_SDA_GPIO45 \ + ESP32_PINMUX(45, ESP_I2CEXT1_SDA_IN, ESP_I2CEXT1_SDA_OUT) + +/* LEDC_CH0 */ +#define LEDC_CH0_GPIO0 \ + ESP32_PINMUX(0, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT0) + +#define LEDC_CH0_GPIO1 \ + ESP32_PINMUX(1, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT0) + +#define LEDC_CH0_GPIO2 \ + ESP32_PINMUX(2, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT0) + +#define LEDC_CH0_GPIO3 \ + ESP32_PINMUX(3, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT0) + +#define LEDC_CH0_GPIO4 \ + ESP32_PINMUX(4, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT0) + +#define LEDC_CH0_GPIO5 \ + ESP32_PINMUX(5, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT0) + +#define LEDC_CH0_GPIO6 \ + ESP32_PINMUX(6, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT0) + +#define LEDC_CH0_GPIO7 \ + ESP32_PINMUX(7, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT0) + +#define LEDC_CH0_GPIO8 \ + ESP32_PINMUX(8, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT0) + +#define LEDC_CH0_GPIO9 \ + ESP32_PINMUX(9, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT0) + +#define LEDC_CH0_GPIO10 \ + ESP32_PINMUX(10, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT0) + +#define LEDC_CH0_GPIO11 \ + ESP32_PINMUX(11, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT0) + +#define LEDC_CH0_GPIO12 \ + ESP32_PINMUX(12, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT0) + +#define LEDC_CH0_GPIO13 \ + ESP32_PINMUX(13, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT0) + +#define LEDC_CH0_GPIO14 \ + ESP32_PINMUX(14, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT0) + +#define LEDC_CH0_GPIO15 \ + ESP32_PINMUX(15, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT0) + +#define LEDC_CH0_GPIO16 \ + ESP32_PINMUX(16, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT0) + +#define LEDC_CH0_GPIO17 \ + ESP32_PINMUX(17, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT0) + +#define LEDC_CH0_GPIO18 \ + ESP32_PINMUX(18, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT0) + +#define LEDC_CH0_GPIO19 \ + ESP32_PINMUX(19, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT0) + +#define LEDC_CH0_GPIO20 \ + ESP32_PINMUX(20, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT0) + +#define LEDC_CH0_GPIO21 \ + ESP32_PINMUX(21, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT0) + +#define LEDC_CH0_GPIO26 \ + ESP32_PINMUX(26, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT0) + +#define LEDC_CH0_GPIO27 \ + ESP32_PINMUX(27, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT0) + +#define LEDC_CH0_GPIO28 \ + ESP32_PINMUX(28, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT0) + +#define LEDC_CH0_GPIO29 \ + ESP32_PINMUX(29, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT0) + +#define LEDC_CH0_GPIO30 \ + ESP32_PINMUX(30, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT0) + +#define LEDC_CH0_GPIO31 \ + ESP32_PINMUX(31, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT0) + +#define LEDC_CH0_GPIO32 \ + ESP32_PINMUX(32, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT0) + +#define LEDC_CH0_GPIO33 \ + ESP32_PINMUX(33, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT0) + +#define LEDC_CH0_GPIO34 \ + ESP32_PINMUX(34, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT0) + +#define LEDC_CH0_GPIO35 \ + ESP32_PINMUX(35, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT0) + +#define LEDC_CH0_GPIO36 \ + ESP32_PINMUX(36, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT0) + +#define LEDC_CH0_GPIO37 \ + ESP32_PINMUX(37, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT0) + +#define LEDC_CH0_GPIO38 \ + ESP32_PINMUX(38, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT0) + +#define LEDC_CH0_GPIO39 \ + ESP32_PINMUX(39, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT0) + +#define LEDC_CH0_GPIO40 \ + ESP32_PINMUX(40, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT0) + +#define LEDC_CH0_GPIO41 \ + ESP32_PINMUX(41, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT0) + +#define LEDC_CH0_GPIO42 \ + ESP32_PINMUX(42, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT0) + +#define LEDC_CH0_GPIO43 \ + ESP32_PINMUX(43, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT0) + +#define LEDC_CH0_GPIO44 \ + ESP32_PINMUX(44, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT0) + +#define LEDC_CH0_GPIO45 \ + ESP32_PINMUX(45, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT0) + +/* LEDC_CH1 */ +#define LEDC_CH1_GPIO0 \ + ESP32_PINMUX(0, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT1) + +#define LEDC_CH1_GPIO1 \ + ESP32_PINMUX(1, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT1) + +#define LEDC_CH1_GPIO2 \ + ESP32_PINMUX(2, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT1) + +#define LEDC_CH1_GPIO3 \ + ESP32_PINMUX(3, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT1) + +#define LEDC_CH1_GPIO4 \ + ESP32_PINMUX(4, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT1) + +#define LEDC_CH1_GPIO5 \ + ESP32_PINMUX(5, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT1) + +#define LEDC_CH1_GPIO6 \ + ESP32_PINMUX(6, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT1) + +#define LEDC_CH1_GPIO7 \ + ESP32_PINMUX(7, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT1) + +#define LEDC_CH1_GPIO8 \ + ESP32_PINMUX(8, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT1) + +#define LEDC_CH1_GPIO9 \ + ESP32_PINMUX(9, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT1) + +#define LEDC_CH1_GPIO10 \ + ESP32_PINMUX(10, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT1) + +#define LEDC_CH1_GPIO11 \ + ESP32_PINMUX(11, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT1) + +#define LEDC_CH1_GPIO12 \ + ESP32_PINMUX(12, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT1) + +#define LEDC_CH1_GPIO13 \ + ESP32_PINMUX(13, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT1) + +#define LEDC_CH1_GPIO14 \ + ESP32_PINMUX(14, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT1) + +#define LEDC_CH1_GPIO15 \ + ESP32_PINMUX(15, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT1) + +#define LEDC_CH1_GPIO16 \ + ESP32_PINMUX(16, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT1) + +#define LEDC_CH1_GPIO17 \ + ESP32_PINMUX(17, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT1) + +#define LEDC_CH1_GPIO18 \ + ESP32_PINMUX(18, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT1) + +#define LEDC_CH1_GPIO19 \ + ESP32_PINMUX(19, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT1) + +#define LEDC_CH1_GPIO20 \ + ESP32_PINMUX(20, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT1) + +#define LEDC_CH1_GPIO21 \ + ESP32_PINMUX(21, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT1) + +#define LEDC_CH1_GPIO26 \ + ESP32_PINMUX(26, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT1) + +#define LEDC_CH1_GPIO27 \ + ESP32_PINMUX(27, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT1) + +#define LEDC_CH1_GPIO28 \ + ESP32_PINMUX(28, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT1) + +#define LEDC_CH1_GPIO29 \ + ESP32_PINMUX(29, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT1) + +#define LEDC_CH1_GPIO30 \ + ESP32_PINMUX(30, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT1) + +#define LEDC_CH1_GPIO31 \ + ESP32_PINMUX(31, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT1) + +#define LEDC_CH1_GPIO32 \ + ESP32_PINMUX(32, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT1) + +#define LEDC_CH1_GPIO33 \ + ESP32_PINMUX(33, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT1) + +#define LEDC_CH1_GPIO34 \ + ESP32_PINMUX(34, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT1) + +#define LEDC_CH1_GPIO35 \ + ESP32_PINMUX(35, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT1) + +#define LEDC_CH1_GPIO36 \ + ESP32_PINMUX(36, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT1) + +#define LEDC_CH1_GPIO37 \ + ESP32_PINMUX(37, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT1) + +#define LEDC_CH1_GPIO38 \ + ESP32_PINMUX(38, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT1) + +#define LEDC_CH1_GPIO39 \ + ESP32_PINMUX(39, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT1) + +#define LEDC_CH1_GPIO40 \ + ESP32_PINMUX(40, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT1) + +#define LEDC_CH1_GPIO41 \ + ESP32_PINMUX(41, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT1) + +#define LEDC_CH1_GPIO42 \ + ESP32_PINMUX(42, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT1) + +#define LEDC_CH1_GPIO43 \ + ESP32_PINMUX(43, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT1) + +#define LEDC_CH1_GPIO44 \ + ESP32_PINMUX(44, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT1) + +#define LEDC_CH1_GPIO45 \ + ESP32_PINMUX(45, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT1) + +/* LEDC_CH2 */ +#define LEDC_CH2_GPIO0 \ + ESP32_PINMUX(0, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT2) + +#define LEDC_CH2_GPIO1 \ + ESP32_PINMUX(1, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT2) + +#define LEDC_CH2_GPIO2 \ + ESP32_PINMUX(2, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT2) + +#define LEDC_CH2_GPIO3 \ + ESP32_PINMUX(3, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT2) + +#define LEDC_CH2_GPIO4 \ + ESP32_PINMUX(4, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT2) + +#define LEDC_CH2_GPIO5 \ + ESP32_PINMUX(5, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT2) + +#define LEDC_CH2_GPIO6 \ + ESP32_PINMUX(6, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT2) + +#define LEDC_CH2_GPIO7 \ + ESP32_PINMUX(7, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT2) + +#define LEDC_CH2_GPIO8 \ + ESP32_PINMUX(8, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT2) + +#define LEDC_CH2_GPIO9 \ + ESP32_PINMUX(9, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT2) + +#define LEDC_CH2_GPIO10 \ + ESP32_PINMUX(10, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT2) + +#define LEDC_CH2_GPIO11 \ + ESP32_PINMUX(11, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT2) + +#define LEDC_CH2_GPIO12 \ + ESP32_PINMUX(12, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT2) + +#define LEDC_CH2_GPIO13 \ + ESP32_PINMUX(13, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT2) + +#define LEDC_CH2_GPIO14 \ + ESP32_PINMUX(14, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT2) + +#define LEDC_CH2_GPIO15 \ + ESP32_PINMUX(15, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT2) + +#define LEDC_CH2_GPIO16 \ + ESP32_PINMUX(16, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT2) + +#define LEDC_CH2_GPIO17 \ + ESP32_PINMUX(17, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT2) + +#define LEDC_CH2_GPIO18 \ + ESP32_PINMUX(18, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT2) + +#define LEDC_CH2_GPIO19 \ + ESP32_PINMUX(19, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT2) + +#define LEDC_CH2_GPIO20 \ + ESP32_PINMUX(20, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT2) + +#define LEDC_CH2_GPIO21 \ + ESP32_PINMUX(21, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT2) + +#define LEDC_CH2_GPIO26 \ + ESP32_PINMUX(26, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT2) + +#define LEDC_CH2_GPIO27 \ + ESP32_PINMUX(27, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT2) + +#define LEDC_CH2_GPIO28 \ + ESP32_PINMUX(28, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT2) + +#define LEDC_CH2_GPIO29 \ + ESP32_PINMUX(29, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT2) + +#define LEDC_CH2_GPIO30 \ + ESP32_PINMUX(30, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT2) + +#define LEDC_CH2_GPIO31 \ + ESP32_PINMUX(31, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT2) + +#define LEDC_CH2_GPIO32 \ + ESP32_PINMUX(32, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT2) + +#define LEDC_CH2_GPIO33 \ + ESP32_PINMUX(33, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT2) + +#define LEDC_CH2_GPIO34 \ + ESP32_PINMUX(34, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT2) + +#define LEDC_CH2_GPIO35 \ + ESP32_PINMUX(35, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT2) + +#define LEDC_CH2_GPIO36 \ + ESP32_PINMUX(36, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT2) + +#define LEDC_CH2_GPIO37 \ + ESP32_PINMUX(37, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT2) + +#define LEDC_CH2_GPIO38 \ + ESP32_PINMUX(38, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT2) + +#define LEDC_CH2_GPIO39 \ + ESP32_PINMUX(39, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT2) + +#define LEDC_CH2_GPIO40 \ + ESP32_PINMUX(40, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT2) + +#define LEDC_CH2_GPIO41 \ + ESP32_PINMUX(41, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT2) + +#define LEDC_CH2_GPIO42 \ + ESP32_PINMUX(42, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT2) + +#define LEDC_CH2_GPIO43 \ + ESP32_PINMUX(43, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT2) + +#define LEDC_CH2_GPIO44 \ + ESP32_PINMUX(44, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT2) + +#define LEDC_CH2_GPIO45 \ + ESP32_PINMUX(45, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT2) + +/* LEDC_CH3 */ +#define LEDC_CH3_GPIO0 \ + ESP32_PINMUX(0, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT3) + +#define LEDC_CH3_GPIO1 \ + ESP32_PINMUX(1, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT3) + +#define LEDC_CH3_GPIO2 \ + ESP32_PINMUX(2, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT3) + +#define LEDC_CH3_GPIO3 \ + ESP32_PINMUX(3, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT3) + +#define LEDC_CH3_GPIO4 \ + ESP32_PINMUX(4, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT3) + +#define LEDC_CH3_GPIO5 \ + ESP32_PINMUX(5, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT3) + +#define LEDC_CH3_GPIO6 \ + ESP32_PINMUX(6, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT3) + +#define LEDC_CH3_GPIO7 \ + ESP32_PINMUX(7, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT3) + +#define LEDC_CH3_GPIO8 \ + ESP32_PINMUX(8, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT3) + +#define LEDC_CH3_GPIO9 \ + ESP32_PINMUX(9, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT3) + +#define LEDC_CH3_GPIO10 \ + ESP32_PINMUX(10, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT3) + +#define LEDC_CH3_GPIO11 \ + ESP32_PINMUX(11, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT3) + +#define LEDC_CH3_GPIO12 \ + ESP32_PINMUX(12, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT3) + +#define LEDC_CH3_GPIO13 \ + ESP32_PINMUX(13, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT3) + +#define LEDC_CH3_GPIO14 \ + ESP32_PINMUX(14, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT3) + +#define LEDC_CH3_GPIO15 \ + ESP32_PINMUX(15, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT3) + +#define LEDC_CH3_GPIO16 \ + ESP32_PINMUX(16, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT3) + +#define LEDC_CH3_GPIO17 \ + ESP32_PINMUX(17, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT3) + +#define LEDC_CH3_GPIO18 \ + ESP32_PINMUX(18, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT3) + +#define LEDC_CH3_GPIO19 \ + ESP32_PINMUX(19, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT3) + +#define LEDC_CH3_GPIO20 \ + ESP32_PINMUX(20, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT3) + +#define LEDC_CH3_GPIO21 \ + ESP32_PINMUX(21, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT3) + +#define LEDC_CH3_GPIO26 \ + ESP32_PINMUX(26, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT3) + +#define LEDC_CH3_GPIO27 \ + ESP32_PINMUX(27, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT3) + +#define LEDC_CH3_GPIO28 \ + ESP32_PINMUX(28, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT3) + +#define LEDC_CH3_GPIO29 \ + ESP32_PINMUX(29, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT3) + +#define LEDC_CH3_GPIO30 \ + ESP32_PINMUX(30, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT3) + +#define LEDC_CH3_GPIO31 \ + ESP32_PINMUX(31, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT3) + +#define LEDC_CH3_GPIO32 \ + ESP32_PINMUX(32, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT3) + +#define LEDC_CH3_GPIO33 \ + ESP32_PINMUX(33, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT3) + +#define LEDC_CH3_GPIO34 \ + ESP32_PINMUX(34, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT3) + +#define LEDC_CH3_GPIO35 \ + ESP32_PINMUX(35, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT3) + +#define LEDC_CH3_GPIO36 \ + ESP32_PINMUX(36, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT3) + +#define LEDC_CH3_GPIO37 \ + ESP32_PINMUX(37, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT3) + +#define LEDC_CH3_GPIO38 \ + ESP32_PINMUX(38, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT3) + +#define LEDC_CH3_GPIO39 \ + ESP32_PINMUX(39, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT3) + +#define LEDC_CH3_GPIO40 \ + ESP32_PINMUX(40, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT3) + +#define LEDC_CH3_GPIO41 \ + ESP32_PINMUX(41, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT3) + +#define LEDC_CH3_GPIO42 \ + ESP32_PINMUX(42, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT3) + +#define LEDC_CH3_GPIO43 \ + ESP32_PINMUX(43, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT3) + +#define LEDC_CH3_GPIO44 \ + ESP32_PINMUX(44, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT3) + +#define LEDC_CH3_GPIO45 \ + ESP32_PINMUX(45, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT3) + +/* LEDC_CH4 */ +#define LEDC_CH4_GPIO0 \ + ESP32_PINMUX(0, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT4) + +#define LEDC_CH4_GPIO1 \ + ESP32_PINMUX(1, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT4) + +#define LEDC_CH4_GPIO2 \ + ESP32_PINMUX(2, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT4) + +#define LEDC_CH4_GPIO3 \ + ESP32_PINMUX(3, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT4) + +#define LEDC_CH4_GPIO4 \ + ESP32_PINMUX(4, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT4) + +#define LEDC_CH4_GPIO5 \ + ESP32_PINMUX(5, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT4) + +#define LEDC_CH4_GPIO6 \ + ESP32_PINMUX(6, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT4) + +#define LEDC_CH4_GPIO7 \ + ESP32_PINMUX(7, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT4) + +#define LEDC_CH4_GPIO8 \ + ESP32_PINMUX(8, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT4) + +#define LEDC_CH4_GPIO9 \ + ESP32_PINMUX(9, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT4) + +#define LEDC_CH4_GPIO10 \ + ESP32_PINMUX(10, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT4) + +#define LEDC_CH4_GPIO11 \ + ESP32_PINMUX(11, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT4) + +#define LEDC_CH4_GPIO12 \ + ESP32_PINMUX(12, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT4) + +#define LEDC_CH4_GPIO13 \ + ESP32_PINMUX(13, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT4) + +#define LEDC_CH4_GPIO14 \ + ESP32_PINMUX(14, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT4) + +#define LEDC_CH4_GPIO15 \ + ESP32_PINMUX(15, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT4) + +#define LEDC_CH4_GPIO16 \ + ESP32_PINMUX(16, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT4) + +#define LEDC_CH4_GPIO17 \ + ESP32_PINMUX(17, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT4) + +#define LEDC_CH4_GPIO18 \ + ESP32_PINMUX(18, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT4) + +#define LEDC_CH4_GPIO19 \ + ESP32_PINMUX(19, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT4) + +#define LEDC_CH4_GPIO20 \ + ESP32_PINMUX(20, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT4) + +#define LEDC_CH4_GPIO21 \ + ESP32_PINMUX(21, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT4) + +#define LEDC_CH4_GPIO26 \ + ESP32_PINMUX(26, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT4) + +#define LEDC_CH4_GPIO27 \ + ESP32_PINMUX(27, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT4) + +#define LEDC_CH4_GPIO28 \ + ESP32_PINMUX(28, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT4) + +#define LEDC_CH4_GPIO29 \ + ESP32_PINMUX(29, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT4) + +#define LEDC_CH4_GPIO30 \ + ESP32_PINMUX(30, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT4) + +#define LEDC_CH4_GPIO31 \ + ESP32_PINMUX(31, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT4) + +#define LEDC_CH4_GPIO32 \ + ESP32_PINMUX(32, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT4) + +#define LEDC_CH4_GPIO33 \ + ESP32_PINMUX(33, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT4) + +#define LEDC_CH4_GPIO34 \ + ESP32_PINMUX(34, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT4) + +#define LEDC_CH4_GPIO35 \ + ESP32_PINMUX(35, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT4) + +#define LEDC_CH4_GPIO36 \ + ESP32_PINMUX(36, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT4) + +#define LEDC_CH4_GPIO37 \ + ESP32_PINMUX(37, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT4) + +#define LEDC_CH4_GPIO38 \ + ESP32_PINMUX(38, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT4) + +#define LEDC_CH4_GPIO39 \ + ESP32_PINMUX(39, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT4) + +#define LEDC_CH4_GPIO40 \ + ESP32_PINMUX(40, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT4) + +#define LEDC_CH4_GPIO41 \ + ESP32_PINMUX(41, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT4) + +#define LEDC_CH4_GPIO42 \ + ESP32_PINMUX(42, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT4) + +#define LEDC_CH4_GPIO43 \ + ESP32_PINMUX(43, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT4) + +#define LEDC_CH4_GPIO44 \ + ESP32_PINMUX(44, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT4) + +#define LEDC_CH4_GPIO45 \ + ESP32_PINMUX(45, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT4) + +/* LEDC_CH5 */ +#define LEDC_CH5_GPIO0 \ + ESP32_PINMUX(0, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT5) + +#define LEDC_CH5_GPIO1 \ + ESP32_PINMUX(1, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT5) + +#define LEDC_CH5_GPIO2 \ + ESP32_PINMUX(2, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT5) + +#define LEDC_CH5_GPIO3 \ + ESP32_PINMUX(3, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT5) + +#define LEDC_CH5_GPIO4 \ + ESP32_PINMUX(4, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT5) + +#define LEDC_CH5_GPIO5 \ + ESP32_PINMUX(5, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT5) + +#define LEDC_CH5_GPIO6 \ + ESP32_PINMUX(6, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT5) + +#define LEDC_CH5_GPIO7 \ + ESP32_PINMUX(7, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT5) + +#define LEDC_CH5_GPIO8 \ + ESP32_PINMUX(8, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT5) + +#define LEDC_CH5_GPIO9 \ + ESP32_PINMUX(9, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT5) + +#define LEDC_CH5_GPIO10 \ + ESP32_PINMUX(10, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT5) + +#define LEDC_CH5_GPIO11 \ + ESP32_PINMUX(11, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT5) + +#define LEDC_CH5_GPIO12 \ + ESP32_PINMUX(12, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT5) + +#define LEDC_CH5_GPIO13 \ + ESP32_PINMUX(13, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT5) + +#define LEDC_CH5_GPIO14 \ + ESP32_PINMUX(14, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT5) + +#define LEDC_CH5_GPIO15 \ + ESP32_PINMUX(15, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT5) + +#define LEDC_CH5_GPIO16 \ + ESP32_PINMUX(16, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT5) + +#define LEDC_CH5_GPIO17 \ + ESP32_PINMUX(17, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT5) + +#define LEDC_CH5_GPIO18 \ + ESP32_PINMUX(18, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT5) + +#define LEDC_CH5_GPIO19 \ + ESP32_PINMUX(19, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT5) + +#define LEDC_CH5_GPIO20 \ + ESP32_PINMUX(20, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT5) + +#define LEDC_CH5_GPIO21 \ + ESP32_PINMUX(21, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT5) + +#define LEDC_CH5_GPIO26 \ + ESP32_PINMUX(26, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT5) + +#define LEDC_CH5_GPIO27 \ + ESP32_PINMUX(27, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT5) + +#define LEDC_CH5_GPIO28 \ + ESP32_PINMUX(28, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT5) + +#define LEDC_CH5_GPIO29 \ + ESP32_PINMUX(29, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT5) + +#define LEDC_CH5_GPIO30 \ + ESP32_PINMUX(30, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT5) + +#define LEDC_CH5_GPIO31 \ + ESP32_PINMUX(31, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT5) + +#define LEDC_CH5_GPIO32 \ + ESP32_PINMUX(32, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT5) + +#define LEDC_CH5_GPIO33 \ + ESP32_PINMUX(33, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT5) + +#define LEDC_CH5_GPIO34 \ + ESP32_PINMUX(34, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT5) + +#define LEDC_CH5_GPIO35 \ + ESP32_PINMUX(35, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT5) + +#define LEDC_CH5_GPIO36 \ + ESP32_PINMUX(36, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT5) + +#define LEDC_CH5_GPIO37 \ + ESP32_PINMUX(37, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT5) + +#define LEDC_CH5_GPIO38 \ + ESP32_PINMUX(38, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT5) + +#define LEDC_CH5_GPIO39 \ + ESP32_PINMUX(39, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT5) + +#define LEDC_CH5_GPIO40 \ + ESP32_PINMUX(40, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT5) + +#define LEDC_CH5_GPIO41 \ + ESP32_PINMUX(41, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT5) + +#define LEDC_CH5_GPIO42 \ + ESP32_PINMUX(42, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT5) + +#define LEDC_CH5_GPIO43 \ + ESP32_PINMUX(43, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT5) + +#define LEDC_CH5_GPIO44 \ + ESP32_PINMUX(44, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT5) + +#define LEDC_CH5_GPIO45 \ + ESP32_PINMUX(45, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT5) + +/* LEDC_CH6 */ +#define LEDC_CH6_GPIO0 \ + ESP32_PINMUX(0, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT6) + +#define LEDC_CH6_GPIO1 \ + ESP32_PINMUX(1, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT6) + +#define LEDC_CH6_GPIO2 \ + ESP32_PINMUX(2, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT6) + +#define LEDC_CH6_GPIO3 \ + ESP32_PINMUX(3, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT6) + +#define LEDC_CH6_GPIO4 \ + ESP32_PINMUX(4, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT6) + +#define LEDC_CH6_GPIO5 \ + ESP32_PINMUX(5, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT6) + +#define LEDC_CH6_GPIO6 \ + ESP32_PINMUX(6, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT6) + +#define LEDC_CH6_GPIO7 \ + ESP32_PINMUX(7, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT6) + +#define LEDC_CH6_GPIO8 \ + ESP32_PINMUX(8, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT6) + +#define LEDC_CH6_GPIO9 \ + ESP32_PINMUX(9, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT6) + +#define LEDC_CH6_GPIO10 \ + ESP32_PINMUX(10, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT6) + +#define LEDC_CH6_GPIO11 \ + ESP32_PINMUX(11, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT6) + +#define LEDC_CH6_GPIO12 \ + ESP32_PINMUX(12, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT6) + +#define LEDC_CH6_GPIO13 \ + ESP32_PINMUX(13, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT6) + +#define LEDC_CH6_GPIO14 \ + ESP32_PINMUX(14, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT6) + +#define LEDC_CH6_GPIO15 \ + ESP32_PINMUX(15, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT6) + +#define LEDC_CH6_GPIO16 \ + ESP32_PINMUX(16, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT6) + +#define LEDC_CH6_GPIO17 \ + ESP32_PINMUX(17, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT6) + +#define LEDC_CH6_GPIO18 \ + ESP32_PINMUX(18, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT6) + +#define LEDC_CH6_GPIO19 \ + ESP32_PINMUX(19, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT6) + +#define LEDC_CH6_GPIO20 \ + ESP32_PINMUX(20, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT6) + +#define LEDC_CH6_GPIO21 \ + ESP32_PINMUX(21, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT6) + +#define LEDC_CH6_GPIO26 \ + ESP32_PINMUX(26, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT6) + +#define LEDC_CH6_GPIO27 \ + ESP32_PINMUX(27, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT6) + +#define LEDC_CH6_GPIO28 \ + ESP32_PINMUX(28, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT6) + +#define LEDC_CH6_GPIO29 \ + ESP32_PINMUX(29, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT6) + +#define LEDC_CH6_GPIO30 \ + ESP32_PINMUX(30, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT6) + +#define LEDC_CH6_GPIO31 \ + ESP32_PINMUX(31, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT6) + +#define LEDC_CH6_GPIO32 \ + ESP32_PINMUX(32, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT6) + +#define LEDC_CH6_GPIO33 \ + ESP32_PINMUX(33, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT6) + +#define LEDC_CH6_GPIO34 \ + ESP32_PINMUX(34, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT6) + +#define LEDC_CH6_GPIO35 \ + ESP32_PINMUX(35, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT6) + +#define LEDC_CH6_GPIO36 \ + ESP32_PINMUX(36, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT6) + +#define LEDC_CH6_GPIO37 \ + ESP32_PINMUX(37, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT6) + +#define LEDC_CH6_GPIO38 \ + ESP32_PINMUX(38, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT6) + +#define LEDC_CH6_GPIO39 \ + ESP32_PINMUX(39, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT6) + +#define LEDC_CH6_GPIO40 \ + ESP32_PINMUX(40, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT6) + +#define LEDC_CH6_GPIO41 \ + ESP32_PINMUX(41, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT6) + +#define LEDC_CH6_GPIO42 \ + ESP32_PINMUX(42, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT6) + +#define LEDC_CH6_GPIO43 \ + ESP32_PINMUX(43, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT6) + +#define LEDC_CH6_GPIO44 \ + ESP32_PINMUX(44, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT6) + +#define LEDC_CH6_GPIO45 \ + ESP32_PINMUX(45, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT6) + +/* LEDC_CH7 */ +#define LEDC_CH7_GPIO0 \ + ESP32_PINMUX(0, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT7) + +#define LEDC_CH7_GPIO1 \ + ESP32_PINMUX(1, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT7) + +#define LEDC_CH7_GPIO2 \ + ESP32_PINMUX(2, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT7) + +#define LEDC_CH7_GPIO3 \ + ESP32_PINMUX(3, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT7) + +#define LEDC_CH7_GPIO4 \ + ESP32_PINMUX(4, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT7) + +#define LEDC_CH7_GPIO5 \ + ESP32_PINMUX(5, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT7) + +#define LEDC_CH7_GPIO6 \ + ESP32_PINMUX(6, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT7) + +#define LEDC_CH7_GPIO7 \ + ESP32_PINMUX(7, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT7) + +#define LEDC_CH7_GPIO8 \ + ESP32_PINMUX(8, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT7) + +#define LEDC_CH7_GPIO9 \ + ESP32_PINMUX(9, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT7) + +#define LEDC_CH7_GPIO10 \ + ESP32_PINMUX(10, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT7) + +#define LEDC_CH7_GPIO11 \ + ESP32_PINMUX(11, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT7) + +#define LEDC_CH7_GPIO12 \ + ESP32_PINMUX(12, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT7) + +#define LEDC_CH7_GPIO13 \ + ESP32_PINMUX(13, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT7) + +#define LEDC_CH7_GPIO14 \ + ESP32_PINMUX(14, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT7) + +#define LEDC_CH7_GPIO15 \ + ESP32_PINMUX(15, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT7) + +#define LEDC_CH7_GPIO16 \ + ESP32_PINMUX(16, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT7) + +#define LEDC_CH7_GPIO17 \ + ESP32_PINMUX(17, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT7) + +#define LEDC_CH7_GPIO18 \ + ESP32_PINMUX(18, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT7) + +#define LEDC_CH7_GPIO19 \ + ESP32_PINMUX(19, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT7) + +#define LEDC_CH7_GPIO20 \ + ESP32_PINMUX(20, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT7) + +#define LEDC_CH7_GPIO21 \ + ESP32_PINMUX(21, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT7) + +#define LEDC_CH7_GPIO26 \ + ESP32_PINMUX(26, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT7) + +#define LEDC_CH7_GPIO27 \ + ESP32_PINMUX(27, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT7) + +#define LEDC_CH7_GPIO28 \ + ESP32_PINMUX(28, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT7) + +#define LEDC_CH7_GPIO29 \ + ESP32_PINMUX(29, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT7) + +#define LEDC_CH7_GPIO30 \ + ESP32_PINMUX(30, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT7) + +#define LEDC_CH7_GPIO31 \ + ESP32_PINMUX(31, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT7) + +#define LEDC_CH7_GPIO32 \ + ESP32_PINMUX(32, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT7) + +#define LEDC_CH7_GPIO33 \ + ESP32_PINMUX(33, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT7) + +#define LEDC_CH7_GPIO34 \ + ESP32_PINMUX(34, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT7) + +#define LEDC_CH7_GPIO35 \ + ESP32_PINMUX(35, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT7) + +#define LEDC_CH7_GPIO36 \ + ESP32_PINMUX(36, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT7) + +#define LEDC_CH7_GPIO37 \ + ESP32_PINMUX(37, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT7) + +#define LEDC_CH7_GPIO38 \ + ESP32_PINMUX(38, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT7) + +#define LEDC_CH7_GPIO39 \ + ESP32_PINMUX(39, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT7) + +#define LEDC_CH7_GPIO40 \ + ESP32_PINMUX(40, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT7) + +#define LEDC_CH7_GPIO41 \ + ESP32_PINMUX(41, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT7) + +#define LEDC_CH7_GPIO42 \ + ESP32_PINMUX(42, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT7) + +#define LEDC_CH7_GPIO43 \ + ESP32_PINMUX(43, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT7) + +#define LEDC_CH7_GPIO44 \ + ESP32_PINMUX(44, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT7) + +#define LEDC_CH7_GPIO45 \ + ESP32_PINMUX(45, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT7) + +/* PCNT0_CH0CTRL */ +#define PCNT0_CH0CTRL_GPIO0 \ + ESP32_PINMUX(0, ESP_PCNT_CTRL_CH0_IN0, ESP_NOSIG) + +#define PCNT0_CH0CTRL_GPIO1 \ + ESP32_PINMUX(1, ESP_PCNT_CTRL_CH0_IN0, ESP_NOSIG) + +#define PCNT0_CH0CTRL_GPIO2 \ + ESP32_PINMUX(2, ESP_PCNT_CTRL_CH0_IN0, ESP_NOSIG) + +#define PCNT0_CH0CTRL_GPIO3 \ + ESP32_PINMUX(3, ESP_PCNT_CTRL_CH0_IN0, ESP_NOSIG) + +#define PCNT0_CH0CTRL_GPIO4 \ + ESP32_PINMUX(4, ESP_PCNT_CTRL_CH0_IN0, ESP_NOSIG) + +#define PCNT0_CH0CTRL_GPIO5 \ + ESP32_PINMUX(5, ESP_PCNT_CTRL_CH0_IN0, ESP_NOSIG) + +#define PCNT0_CH0CTRL_GPIO6 \ + ESP32_PINMUX(6, ESP_PCNT_CTRL_CH0_IN0, ESP_NOSIG) + +#define PCNT0_CH0CTRL_GPIO7 \ + ESP32_PINMUX(7, ESP_PCNT_CTRL_CH0_IN0, ESP_NOSIG) + +#define PCNT0_CH0CTRL_GPIO8 \ + ESP32_PINMUX(8, ESP_PCNT_CTRL_CH0_IN0, ESP_NOSIG) + +#define PCNT0_CH0CTRL_GPIO9 \ + ESP32_PINMUX(9, ESP_PCNT_CTRL_CH0_IN0, ESP_NOSIG) + +#define PCNT0_CH0CTRL_GPIO10 \ + ESP32_PINMUX(10, ESP_PCNT_CTRL_CH0_IN0, ESP_NOSIG) + +#define PCNT0_CH0CTRL_GPIO11 \ + ESP32_PINMUX(11, ESP_PCNT_CTRL_CH0_IN0, ESP_NOSIG) + +#define PCNT0_CH0CTRL_GPIO12 \ + ESP32_PINMUX(12, ESP_PCNT_CTRL_CH0_IN0, ESP_NOSIG) + +#define PCNT0_CH0CTRL_GPIO13 \ + ESP32_PINMUX(13, ESP_PCNT_CTRL_CH0_IN0, ESP_NOSIG) + +#define PCNT0_CH0CTRL_GPIO14 \ + ESP32_PINMUX(14, ESP_PCNT_CTRL_CH0_IN0, ESP_NOSIG) + +#define PCNT0_CH0CTRL_GPIO15 \ + ESP32_PINMUX(15, ESP_PCNT_CTRL_CH0_IN0, ESP_NOSIG) + +#define PCNT0_CH0CTRL_GPIO16 \ + ESP32_PINMUX(16, ESP_PCNT_CTRL_CH0_IN0, ESP_NOSIG) + +#define PCNT0_CH0CTRL_GPIO17 \ + ESP32_PINMUX(17, ESP_PCNT_CTRL_CH0_IN0, ESP_NOSIG) + +#define PCNT0_CH0CTRL_GPIO18 \ + ESP32_PINMUX(18, ESP_PCNT_CTRL_CH0_IN0, ESP_NOSIG) + +#define PCNT0_CH0CTRL_GPIO19 \ + ESP32_PINMUX(19, ESP_PCNT_CTRL_CH0_IN0, ESP_NOSIG) + +#define PCNT0_CH0CTRL_GPIO20 \ + ESP32_PINMUX(20, ESP_PCNT_CTRL_CH0_IN0, ESP_NOSIG) + +#define PCNT0_CH0CTRL_GPIO21 \ + ESP32_PINMUX(21, ESP_PCNT_CTRL_CH0_IN0, ESP_NOSIG) + +#define PCNT0_CH0CTRL_GPIO26 \ + ESP32_PINMUX(26, ESP_PCNT_CTRL_CH0_IN0, ESP_NOSIG) + +#define PCNT0_CH0CTRL_GPIO27 \ + ESP32_PINMUX(27, ESP_PCNT_CTRL_CH0_IN0, ESP_NOSIG) + +#define PCNT0_CH0CTRL_GPIO28 \ + ESP32_PINMUX(28, ESP_PCNT_CTRL_CH0_IN0, ESP_NOSIG) + +#define PCNT0_CH0CTRL_GPIO29 \ + ESP32_PINMUX(29, ESP_PCNT_CTRL_CH0_IN0, ESP_NOSIG) + +#define PCNT0_CH0CTRL_GPIO30 \ + ESP32_PINMUX(30, ESP_PCNT_CTRL_CH0_IN0, ESP_NOSIG) + +#define PCNT0_CH0CTRL_GPIO31 \ + ESP32_PINMUX(31, ESP_PCNT_CTRL_CH0_IN0, ESP_NOSIG) + +#define PCNT0_CH0CTRL_GPIO32 \ + ESP32_PINMUX(32, ESP_PCNT_CTRL_CH0_IN0, ESP_NOSIG) + +#define PCNT0_CH0CTRL_GPIO33 \ + ESP32_PINMUX(33, ESP_PCNT_CTRL_CH0_IN0, ESP_NOSIG) + +#define PCNT0_CH0CTRL_GPIO34 \ + ESP32_PINMUX(34, ESP_PCNT_CTRL_CH0_IN0, ESP_NOSIG) + +#define PCNT0_CH0CTRL_GPIO35 \ + ESP32_PINMUX(35, ESP_PCNT_CTRL_CH0_IN0, ESP_NOSIG) + +#define PCNT0_CH0CTRL_GPIO36 \ + ESP32_PINMUX(36, ESP_PCNT_CTRL_CH0_IN0, ESP_NOSIG) + +#define PCNT0_CH0CTRL_GPIO37 \ + ESP32_PINMUX(37, ESP_PCNT_CTRL_CH0_IN0, ESP_NOSIG) + +#define PCNT0_CH0CTRL_GPIO38 \ + ESP32_PINMUX(38, ESP_PCNT_CTRL_CH0_IN0, ESP_NOSIG) + +#define PCNT0_CH0CTRL_GPIO39 \ + ESP32_PINMUX(39, ESP_PCNT_CTRL_CH0_IN0, ESP_NOSIG) + +#define PCNT0_CH0CTRL_GPIO40 \ + ESP32_PINMUX(40, ESP_PCNT_CTRL_CH0_IN0, ESP_NOSIG) + +#define PCNT0_CH0CTRL_GPIO41 \ + ESP32_PINMUX(41, ESP_PCNT_CTRL_CH0_IN0, ESP_NOSIG) + +#define PCNT0_CH0CTRL_GPIO42 \ + ESP32_PINMUX(42, ESP_PCNT_CTRL_CH0_IN0, ESP_NOSIG) + +#define PCNT0_CH0CTRL_GPIO43 \ + ESP32_PINMUX(43, ESP_PCNT_CTRL_CH0_IN0, ESP_NOSIG) + +#define PCNT0_CH0CTRL_GPIO44 \ + ESP32_PINMUX(44, ESP_PCNT_CTRL_CH0_IN0, ESP_NOSIG) + +#define PCNT0_CH0CTRL_GPIO45 \ + ESP32_PINMUX(45, ESP_PCNT_CTRL_CH0_IN0, ESP_NOSIG) + +#define PCNT0_CH0CTRL_GPIO46 \ + ESP32_PINMUX(46, ESP_PCNT_CTRL_CH0_IN0, ESP_NOSIG) + +/* PCNT0_CH0SIG */ +#define PCNT0_CH0SIG_GPIO0 \ + ESP32_PINMUX(0, ESP_PCNT_SIG_CH0_IN0, ESP_NOSIG) + +#define PCNT0_CH0SIG_GPIO1 \ + ESP32_PINMUX(1, ESP_PCNT_SIG_CH0_IN0, ESP_NOSIG) + +#define PCNT0_CH0SIG_GPIO2 \ + ESP32_PINMUX(2, ESP_PCNT_SIG_CH0_IN0, ESP_NOSIG) + +#define PCNT0_CH0SIG_GPIO3 \ + ESP32_PINMUX(3, ESP_PCNT_SIG_CH0_IN0, ESP_NOSIG) + +#define PCNT0_CH0SIG_GPIO4 \ + ESP32_PINMUX(4, ESP_PCNT_SIG_CH0_IN0, ESP_NOSIG) + +#define PCNT0_CH0SIG_GPIO5 \ + ESP32_PINMUX(5, ESP_PCNT_SIG_CH0_IN0, ESP_NOSIG) + +#define PCNT0_CH0SIG_GPIO6 \ + ESP32_PINMUX(6, ESP_PCNT_SIG_CH0_IN0, ESP_NOSIG) + +#define PCNT0_CH0SIG_GPIO7 \ + ESP32_PINMUX(7, ESP_PCNT_SIG_CH0_IN0, ESP_NOSIG) + +#define PCNT0_CH0SIG_GPIO8 \ + ESP32_PINMUX(8, ESP_PCNT_SIG_CH0_IN0, ESP_NOSIG) + +#define PCNT0_CH0SIG_GPIO9 \ + ESP32_PINMUX(9, ESP_PCNT_SIG_CH0_IN0, ESP_NOSIG) + +#define PCNT0_CH0SIG_GPIO10 \ + ESP32_PINMUX(10, ESP_PCNT_SIG_CH0_IN0, ESP_NOSIG) + +#define PCNT0_CH0SIG_GPIO11 \ + ESP32_PINMUX(11, ESP_PCNT_SIG_CH0_IN0, ESP_NOSIG) + +#define PCNT0_CH0SIG_GPIO12 \ + ESP32_PINMUX(12, ESP_PCNT_SIG_CH0_IN0, ESP_NOSIG) + +#define PCNT0_CH0SIG_GPIO13 \ + ESP32_PINMUX(13, ESP_PCNT_SIG_CH0_IN0, ESP_NOSIG) + +#define PCNT0_CH0SIG_GPIO14 \ + ESP32_PINMUX(14, ESP_PCNT_SIG_CH0_IN0, ESP_NOSIG) + +#define PCNT0_CH0SIG_GPIO15 \ + ESP32_PINMUX(15, ESP_PCNT_SIG_CH0_IN0, ESP_NOSIG) + +#define PCNT0_CH0SIG_GPIO16 \ + ESP32_PINMUX(16, ESP_PCNT_SIG_CH0_IN0, ESP_NOSIG) + +#define PCNT0_CH0SIG_GPIO17 \ + ESP32_PINMUX(17, ESP_PCNT_SIG_CH0_IN0, ESP_NOSIG) + +#define PCNT0_CH0SIG_GPIO18 \ + ESP32_PINMUX(18, ESP_PCNT_SIG_CH0_IN0, ESP_NOSIG) + +#define PCNT0_CH0SIG_GPIO19 \ + ESP32_PINMUX(19, ESP_PCNT_SIG_CH0_IN0, ESP_NOSIG) + +#define PCNT0_CH0SIG_GPIO20 \ + ESP32_PINMUX(20, ESP_PCNT_SIG_CH0_IN0, ESP_NOSIG) + +#define PCNT0_CH0SIG_GPIO21 \ + ESP32_PINMUX(21, ESP_PCNT_SIG_CH0_IN0, ESP_NOSIG) + +#define PCNT0_CH0SIG_GPIO26 \ + ESP32_PINMUX(26, ESP_PCNT_SIG_CH0_IN0, ESP_NOSIG) + +#define PCNT0_CH0SIG_GPIO27 \ + ESP32_PINMUX(27, ESP_PCNT_SIG_CH0_IN0, ESP_NOSIG) + +#define PCNT0_CH0SIG_GPIO28 \ + ESP32_PINMUX(28, ESP_PCNT_SIG_CH0_IN0, ESP_NOSIG) + +#define PCNT0_CH0SIG_GPIO29 \ + ESP32_PINMUX(29, ESP_PCNT_SIG_CH0_IN0, ESP_NOSIG) + +#define PCNT0_CH0SIG_GPIO30 \ + ESP32_PINMUX(30, ESP_PCNT_SIG_CH0_IN0, ESP_NOSIG) + +#define PCNT0_CH0SIG_GPIO31 \ + ESP32_PINMUX(31, ESP_PCNT_SIG_CH0_IN0, ESP_NOSIG) + +#define PCNT0_CH0SIG_GPIO32 \ + ESP32_PINMUX(32, ESP_PCNT_SIG_CH0_IN0, ESP_NOSIG) + +#define PCNT0_CH0SIG_GPIO33 \ + ESP32_PINMUX(33, ESP_PCNT_SIG_CH0_IN0, ESP_NOSIG) + +#define PCNT0_CH0SIG_GPIO34 \ + ESP32_PINMUX(34, ESP_PCNT_SIG_CH0_IN0, ESP_NOSIG) + +#define PCNT0_CH0SIG_GPIO35 \ + ESP32_PINMUX(35, ESP_PCNT_SIG_CH0_IN0, ESP_NOSIG) + +#define PCNT0_CH0SIG_GPIO36 \ + ESP32_PINMUX(36, ESP_PCNT_SIG_CH0_IN0, ESP_NOSIG) + +#define PCNT0_CH0SIG_GPIO37 \ + ESP32_PINMUX(37, ESP_PCNT_SIG_CH0_IN0, ESP_NOSIG) + +#define PCNT0_CH0SIG_GPIO38 \ + ESP32_PINMUX(38, ESP_PCNT_SIG_CH0_IN0, ESP_NOSIG) + +#define PCNT0_CH0SIG_GPIO39 \ + ESP32_PINMUX(39, ESP_PCNT_SIG_CH0_IN0, ESP_NOSIG) + +#define PCNT0_CH0SIG_GPIO40 \ + ESP32_PINMUX(40, ESP_PCNT_SIG_CH0_IN0, ESP_NOSIG) + +#define PCNT0_CH0SIG_GPIO41 \ + ESP32_PINMUX(41, ESP_PCNT_SIG_CH0_IN0, ESP_NOSIG) + +#define PCNT0_CH0SIG_GPIO42 \ + ESP32_PINMUX(42, ESP_PCNT_SIG_CH0_IN0, ESP_NOSIG) + +#define PCNT0_CH0SIG_GPIO43 \ + ESP32_PINMUX(43, ESP_PCNT_SIG_CH0_IN0, ESP_NOSIG) + +#define PCNT0_CH0SIG_GPIO44 \ + ESP32_PINMUX(44, ESP_PCNT_SIG_CH0_IN0, ESP_NOSIG) + +#define PCNT0_CH0SIG_GPIO45 \ + ESP32_PINMUX(45, ESP_PCNT_SIG_CH0_IN0, ESP_NOSIG) + +#define PCNT0_CH0SIG_GPIO46 \ + ESP32_PINMUX(46, ESP_PCNT_SIG_CH0_IN0, ESP_NOSIG) + +/* PCNT0_CH1CTRL */ +#define PCNT0_CH1CTRL_GPIO0 \ + ESP32_PINMUX(0, ESP_PCNT_CTRL_CH1_IN0, ESP_NOSIG) + +#define PCNT0_CH1CTRL_GPIO1 \ + ESP32_PINMUX(1, ESP_PCNT_CTRL_CH1_IN0, ESP_NOSIG) + +#define PCNT0_CH1CTRL_GPIO2 \ + ESP32_PINMUX(2, ESP_PCNT_CTRL_CH1_IN0, ESP_NOSIG) + +#define PCNT0_CH1CTRL_GPIO3 \ + ESP32_PINMUX(3, ESP_PCNT_CTRL_CH1_IN0, ESP_NOSIG) + +#define PCNT0_CH1CTRL_GPIO4 \ + ESP32_PINMUX(4, ESP_PCNT_CTRL_CH1_IN0, ESP_NOSIG) + +#define PCNT0_CH1CTRL_GPIO5 \ + ESP32_PINMUX(5, ESP_PCNT_CTRL_CH1_IN0, ESP_NOSIG) + +#define PCNT0_CH1CTRL_GPIO6 \ + ESP32_PINMUX(6, ESP_PCNT_CTRL_CH1_IN0, ESP_NOSIG) + +#define PCNT0_CH1CTRL_GPIO7 \ + ESP32_PINMUX(7, ESP_PCNT_CTRL_CH1_IN0, ESP_NOSIG) + +#define PCNT0_CH1CTRL_GPIO8 \ + ESP32_PINMUX(8, ESP_PCNT_CTRL_CH1_IN0, ESP_NOSIG) + +#define PCNT0_CH1CTRL_GPIO9 \ + ESP32_PINMUX(9, ESP_PCNT_CTRL_CH1_IN0, ESP_NOSIG) + +#define PCNT0_CH1CTRL_GPIO10 \ + ESP32_PINMUX(10, ESP_PCNT_CTRL_CH1_IN0, ESP_NOSIG) + +#define PCNT0_CH1CTRL_GPIO11 \ + ESP32_PINMUX(11, ESP_PCNT_CTRL_CH1_IN0, ESP_NOSIG) + +#define PCNT0_CH1CTRL_GPIO12 \ + ESP32_PINMUX(12, ESP_PCNT_CTRL_CH1_IN0, ESP_NOSIG) + +#define PCNT0_CH1CTRL_GPIO13 \ + ESP32_PINMUX(13, ESP_PCNT_CTRL_CH1_IN0, ESP_NOSIG) + +#define PCNT0_CH1CTRL_GPIO14 \ + ESP32_PINMUX(14, ESP_PCNT_CTRL_CH1_IN0, ESP_NOSIG) + +#define PCNT0_CH1CTRL_GPIO15 \ + ESP32_PINMUX(15, ESP_PCNT_CTRL_CH1_IN0, ESP_NOSIG) + +#define PCNT0_CH1CTRL_GPIO16 \ + ESP32_PINMUX(16, ESP_PCNT_CTRL_CH1_IN0, ESP_NOSIG) + +#define PCNT0_CH1CTRL_GPIO17 \ + ESP32_PINMUX(17, ESP_PCNT_CTRL_CH1_IN0, ESP_NOSIG) + +#define PCNT0_CH1CTRL_GPIO18 \ + ESP32_PINMUX(18, ESP_PCNT_CTRL_CH1_IN0, ESP_NOSIG) + +#define PCNT0_CH1CTRL_GPIO19 \ + ESP32_PINMUX(19, ESP_PCNT_CTRL_CH1_IN0, ESP_NOSIG) + +#define PCNT0_CH1CTRL_GPIO20 \ + ESP32_PINMUX(20, ESP_PCNT_CTRL_CH1_IN0, ESP_NOSIG) + +#define PCNT0_CH1CTRL_GPIO21 \ + ESP32_PINMUX(21, ESP_PCNT_CTRL_CH1_IN0, ESP_NOSIG) + +#define PCNT0_CH1CTRL_GPIO26 \ + ESP32_PINMUX(26, ESP_PCNT_CTRL_CH1_IN0, ESP_NOSIG) + +#define PCNT0_CH1CTRL_GPIO27 \ + ESP32_PINMUX(27, ESP_PCNT_CTRL_CH1_IN0, ESP_NOSIG) + +#define PCNT0_CH1CTRL_GPIO28 \ + ESP32_PINMUX(28, ESP_PCNT_CTRL_CH1_IN0, ESP_NOSIG) + +#define PCNT0_CH1CTRL_GPIO29 \ + ESP32_PINMUX(29, ESP_PCNT_CTRL_CH1_IN0, ESP_NOSIG) + +#define PCNT0_CH1CTRL_GPIO30 \ + ESP32_PINMUX(30, ESP_PCNT_CTRL_CH1_IN0, ESP_NOSIG) + +#define PCNT0_CH1CTRL_GPIO31 \ + ESP32_PINMUX(31, ESP_PCNT_CTRL_CH1_IN0, ESP_NOSIG) + +#define PCNT0_CH1CTRL_GPIO32 \ + ESP32_PINMUX(32, ESP_PCNT_CTRL_CH1_IN0, ESP_NOSIG) + +#define PCNT0_CH1CTRL_GPIO33 \ + ESP32_PINMUX(33, ESP_PCNT_CTRL_CH1_IN0, ESP_NOSIG) + +#define PCNT0_CH1CTRL_GPIO34 \ + ESP32_PINMUX(34, ESP_PCNT_CTRL_CH1_IN0, ESP_NOSIG) + +#define PCNT0_CH1CTRL_GPIO35 \ + ESP32_PINMUX(35, ESP_PCNT_CTRL_CH1_IN0, ESP_NOSIG) + +#define PCNT0_CH1CTRL_GPIO36 \ + ESP32_PINMUX(36, ESP_PCNT_CTRL_CH1_IN0, ESP_NOSIG) + +#define PCNT0_CH1CTRL_GPIO37 \ + ESP32_PINMUX(37, ESP_PCNT_CTRL_CH1_IN0, ESP_NOSIG) + +#define PCNT0_CH1CTRL_GPIO38 \ + ESP32_PINMUX(38, ESP_PCNT_CTRL_CH1_IN0, ESP_NOSIG) + +#define PCNT0_CH1CTRL_GPIO39 \ + ESP32_PINMUX(39, ESP_PCNT_CTRL_CH1_IN0, ESP_NOSIG) + +#define PCNT0_CH1CTRL_GPIO40 \ + ESP32_PINMUX(40, ESP_PCNT_CTRL_CH1_IN0, ESP_NOSIG) + +#define PCNT0_CH1CTRL_GPIO41 \ + ESP32_PINMUX(41, ESP_PCNT_CTRL_CH1_IN0, ESP_NOSIG) + +#define PCNT0_CH1CTRL_GPIO42 \ + ESP32_PINMUX(42, ESP_PCNT_CTRL_CH1_IN0, ESP_NOSIG) + +#define PCNT0_CH1CTRL_GPIO43 \ + ESP32_PINMUX(43, ESP_PCNT_CTRL_CH1_IN0, ESP_NOSIG) + +#define PCNT0_CH1CTRL_GPIO44 \ + ESP32_PINMUX(44, ESP_PCNT_CTRL_CH1_IN0, ESP_NOSIG) + +#define PCNT0_CH1CTRL_GPIO45 \ + ESP32_PINMUX(45, ESP_PCNT_CTRL_CH1_IN0, ESP_NOSIG) + +#define PCNT0_CH1CTRL_GPIO46 \ + ESP32_PINMUX(46, ESP_PCNT_CTRL_CH1_IN0, ESP_NOSIG) + +/* PCNT0_CH1SIG */ +#define PCNT0_CH1SIG_GPIO0 \ + ESP32_PINMUX(0, ESP_PCNT_SIG_CH1_IN0, ESP_NOSIG) + +#define PCNT0_CH1SIG_GPIO1 \ + ESP32_PINMUX(1, ESP_PCNT_SIG_CH1_IN0, ESP_NOSIG) + +#define PCNT0_CH1SIG_GPIO2 \ + ESP32_PINMUX(2, ESP_PCNT_SIG_CH1_IN0, ESP_NOSIG) + +#define PCNT0_CH1SIG_GPIO3 \ + ESP32_PINMUX(3, ESP_PCNT_SIG_CH1_IN0, ESP_NOSIG) + +#define PCNT0_CH1SIG_GPIO4 \ + ESP32_PINMUX(4, ESP_PCNT_SIG_CH1_IN0, ESP_NOSIG) + +#define PCNT0_CH1SIG_GPIO5 \ + ESP32_PINMUX(5, ESP_PCNT_SIG_CH1_IN0, ESP_NOSIG) + +#define PCNT0_CH1SIG_GPIO6 \ + ESP32_PINMUX(6, ESP_PCNT_SIG_CH1_IN0, ESP_NOSIG) + +#define PCNT0_CH1SIG_GPIO7 \ + ESP32_PINMUX(7, ESP_PCNT_SIG_CH1_IN0, ESP_NOSIG) + +#define PCNT0_CH1SIG_GPIO8 \ + ESP32_PINMUX(8, ESP_PCNT_SIG_CH1_IN0, ESP_NOSIG) + +#define PCNT0_CH1SIG_GPIO9 \ + ESP32_PINMUX(9, ESP_PCNT_SIG_CH1_IN0, ESP_NOSIG) + +#define PCNT0_CH1SIG_GPIO10 \ + ESP32_PINMUX(10, ESP_PCNT_SIG_CH1_IN0, ESP_NOSIG) + +#define PCNT0_CH1SIG_GPIO11 \ + ESP32_PINMUX(11, ESP_PCNT_SIG_CH1_IN0, ESP_NOSIG) + +#define PCNT0_CH1SIG_GPIO12 \ + ESP32_PINMUX(12, ESP_PCNT_SIG_CH1_IN0, ESP_NOSIG) + +#define PCNT0_CH1SIG_GPIO13 \ + ESP32_PINMUX(13, ESP_PCNT_SIG_CH1_IN0, ESP_NOSIG) + +#define PCNT0_CH1SIG_GPIO14 \ + ESP32_PINMUX(14, ESP_PCNT_SIG_CH1_IN0, ESP_NOSIG) + +#define PCNT0_CH1SIG_GPIO15 \ + ESP32_PINMUX(15, ESP_PCNT_SIG_CH1_IN0, ESP_NOSIG) + +#define PCNT0_CH1SIG_GPIO16 \ + ESP32_PINMUX(16, ESP_PCNT_SIG_CH1_IN0, ESP_NOSIG) + +#define PCNT0_CH1SIG_GPIO17 \ + ESP32_PINMUX(17, ESP_PCNT_SIG_CH1_IN0, ESP_NOSIG) + +#define PCNT0_CH1SIG_GPIO18 \ + ESP32_PINMUX(18, ESP_PCNT_SIG_CH1_IN0, ESP_NOSIG) + +#define PCNT0_CH1SIG_GPIO19 \ + ESP32_PINMUX(19, ESP_PCNT_SIG_CH1_IN0, ESP_NOSIG) + +#define PCNT0_CH1SIG_GPIO20 \ + ESP32_PINMUX(20, ESP_PCNT_SIG_CH1_IN0, ESP_NOSIG) + +#define PCNT0_CH1SIG_GPIO21 \ + ESP32_PINMUX(21, ESP_PCNT_SIG_CH1_IN0, ESP_NOSIG) + +#define PCNT0_CH1SIG_GPIO26 \ + ESP32_PINMUX(26, ESP_PCNT_SIG_CH1_IN0, ESP_NOSIG) + +#define PCNT0_CH1SIG_GPIO27 \ + ESP32_PINMUX(27, ESP_PCNT_SIG_CH1_IN0, ESP_NOSIG) + +#define PCNT0_CH1SIG_GPIO28 \ + ESP32_PINMUX(28, ESP_PCNT_SIG_CH1_IN0, ESP_NOSIG) + +#define PCNT0_CH1SIG_GPIO29 \ + ESP32_PINMUX(29, ESP_PCNT_SIG_CH1_IN0, ESP_NOSIG) + +#define PCNT0_CH1SIG_GPIO30 \ + ESP32_PINMUX(30, ESP_PCNT_SIG_CH1_IN0, ESP_NOSIG) + +#define PCNT0_CH1SIG_GPIO31 \ + ESP32_PINMUX(31, ESP_PCNT_SIG_CH1_IN0, ESP_NOSIG) + +#define PCNT0_CH1SIG_GPIO32 \ + ESP32_PINMUX(32, ESP_PCNT_SIG_CH1_IN0, ESP_NOSIG) + +#define PCNT0_CH1SIG_GPIO33 \ + ESP32_PINMUX(33, ESP_PCNT_SIG_CH1_IN0, ESP_NOSIG) + +#define PCNT0_CH1SIG_GPIO34 \ + ESP32_PINMUX(34, ESP_PCNT_SIG_CH1_IN0, ESP_NOSIG) + +#define PCNT0_CH1SIG_GPIO35 \ + ESP32_PINMUX(35, ESP_PCNT_SIG_CH1_IN0, ESP_NOSIG) + +#define PCNT0_CH1SIG_GPIO36 \ + ESP32_PINMUX(36, ESP_PCNT_SIG_CH1_IN0, ESP_NOSIG) + +#define PCNT0_CH1SIG_GPIO37 \ + ESP32_PINMUX(37, ESP_PCNT_SIG_CH1_IN0, ESP_NOSIG) + +#define PCNT0_CH1SIG_GPIO38 \ + ESP32_PINMUX(38, ESP_PCNT_SIG_CH1_IN0, ESP_NOSIG) + +#define PCNT0_CH1SIG_GPIO39 \ + ESP32_PINMUX(39, ESP_PCNT_SIG_CH1_IN0, ESP_NOSIG) + +#define PCNT0_CH1SIG_GPIO40 \ + ESP32_PINMUX(40, ESP_PCNT_SIG_CH1_IN0, ESP_NOSIG) + +#define PCNT0_CH1SIG_GPIO41 \ + ESP32_PINMUX(41, ESP_PCNT_SIG_CH1_IN0, ESP_NOSIG) + +#define PCNT0_CH1SIG_GPIO42 \ + ESP32_PINMUX(42, ESP_PCNT_SIG_CH1_IN0, ESP_NOSIG) + +#define PCNT0_CH1SIG_GPIO43 \ + ESP32_PINMUX(43, ESP_PCNT_SIG_CH1_IN0, ESP_NOSIG) + +#define PCNT0_CH1SIG_GPIO44 \ + ESP32_PINMUX(44, ESP_PCNT_SIG_CH1_IN0, ESP_NOSIG) + +#define PCNT0_CH1SIG_GPIO45 \ + ESP32_PINMUX(45, ESP_PCNT_SIG_CH1_IN0, ESP_NOSIG) + +#define PCNT0_CH1SIG_GPIO46 \ + ESP32_PINMUX(46, ESP_PCNT_SIG_CH1_IN0, ESP_NOSIG) + +/* PCNT1_CH0CTRL */ +#define PCNT1_CH0CTRL_GPIO0 \ + ESP32_PINMUX(0, ESP_PCNT_CTRL_CH0_IN1, ESP_NOSIG) + +#define PCNT1_CH0CTRL_GPIO1 \ + ESP32_PINMUX(1, ESP_PCNT_CTRL_CH0_IN1, ESP_NOSIG) + +#define PCNT1_CH0CTRL_GPIO2 \ + ESP32_PINMUX(2, ESP_PCNT_CTRL_CH0_IN1, ESP_NOSIG) + +#define PCNT1_CH0CTRL_GPIO3 \ + ESP32_PINMUX(3, ESP_PCNT_CTRL_CH0_IN1, ESP_NOSIG) + +#define PCNT1_CH0CTRL_GPIO4 \ + ESP32_PINMUX(4, ESP_PCNT_CTRL_CH0_IN1, ESP_NOSIG) + +#define PCNT1_CH0CTRL_GPIO5 \ + ESP32_PINMUX(5, ESP_PCNT_CTRL_CH0_IN1, ESP_NOSIG) + +#define PCNT1_CH0CTRL_GPIO6 \ + ESP32_PINMUX(6, ESP_PCNT_CTRL_CH0_IN1, ESP_NOSIG) + +#define PCNT1_CH0CTRL_GPIO7 \ + ESP32_PINMUX(7, ESP_PCNT_CTRL_CH0_IN1, ESP_NOSIG) + +#define PCNT1_CH0CTRL_GPIO8 \ + ESP32_PINMUX(8, ESP_PCNT_CTRL_CH0_IN1, ESP_NOSIG) + +#define PCNT1_CH0CTRL_GPIO9 \ + ESP32_PINMUX(9, ESP_PCNT_CTRL_CH0_IN1, ESP_NOSIG) + +#define PCNT1_CH0CTRL_GPIO10 \ + ESP32_PINMUX(10, ESP_PCNT_CTRL_CH0_IN1, ESP_NOSIG) + +#define PCNT1_CH0CTRL_GPIO11 \ + ESP32_PINMUX(11, ESP_PCNT_CTRL_CH0_IN1, ESP_NOSIG) + +#define PCNT1_CH0CTRL_GPIO12 \ + ESP32_PINMUX(12, ESP_PCNT_CTRL_CH0_IN1, ESP_NOSIG) + +#define PCNT1_CH0CTRL_GPIO13 \ + ESP32_PINMUX(13, ESP_PCNT_CTRL_CH0_IN1, ESP_NOSIG) + +#define PCNT1_CH0CTRL_GPIO14 \ + ESP32_PINMUX(14, ESP_PCNT_CTRL_CH0_IN1, ESP_NOSIG) + +#define PCNT1_CH0CTRL_GPIO15 \ + ESP32_PINMUX(15, ESP_PCNT_CTRL_CH0_IN1, ESP_NOSIG) + +#define PCNT1_CH0CTRL_GPIO16 \ + ESP32_PINMUX(16, ESP_PCNT_CTRL_CH0_IN1, ESP_NOSIG) + +#define PCNT1_CH0CTRL_GPIO17 \ + ESP32_PINMUX(17, ESP_PCNT_CTRL_CH0_IN1, ESP_NOSIG) + +#define PCNT1_CH0CTRL_GPIO18 \ + ESP32_PINMUX(18, ESP_PCNT_CTRL_CH0_IN1, ESP_NOSIG) + +#define PCNT1_CH0CTRL_GPIO19 \ + ESP32_PINMUX(19, ESP_PCNT_CTRL_CH0_IN1, ESP_NOSIG) + +#define PCNT1_CH0CTRL_GPIO20 \ + ESP32_PINMUX(20, ESP_PCNT_CTRL_CH0_IN1, ESP_NOSIG) + +#define PCNT1_CH0CTRL_GPIO21 \ + ESP32_PINMUX(21, ESP_PCNT_CTRL_CH0_IN1, ESP_NOSIG) + +#define PCNT1_CH0CTRL_GPIO26 \ + ESP32_PINMUX(26, ESP_PCNT_CTRL_CH0_IN1, ESP_NOSIG) + +#define PCNT1_CH0CTRL_GPIO27 \ + ESP32_PINMUX(27, ESP_PCNT_CTRL_CH0_IN1, ESP_NOSIG) + +#define PCNT1_CH0CTRL_GPIO28 \ + ESP32_PINMUX(28, ESP_PCNT_CTRL_CH0_IN1, ESP_NOSIG) + +#define PCNT1_CH0CTRL_GPIO29 \ + ESP32_PINMUX(29, ESP_PCNT_CTRL_CH0_IN1, ESP_NOSIG) + +#define PCNT1_CH0CTRL_GPIO30 \ + ESP32_PINMUX(30, ESP_PCNT_CTRL_CH0_IN1, ESP_NOSIG) + +#define PCNT1_CH0CTRL_GPIO31 \ + ESP32_PINMUX(31, ESP_PCNT_CTRL_CH0_IN1, ESP_NOSIG) + +#define PCNT1_CH0CTRL_GPIO32 \ + ESP32_PINMUX(32, ESP_PCNT_CTRL_CH0_IN1, ESP_NOSIG) + +#define PCNT1_CH0CTRL_GPIO33 \ + ESP32_PINMUX(33, ESP_PCNT_CTRL_CH0_IN1, ESP_NOSIG) + +#define PCNT1_CH0CTRL_GPIO34 \ + ESP32_PINMUX(34, ESP_PCNT_CTRL_CH0_IN1, ESP_NOSIG) + +#define PCNT1_CH0CTRL_GPIO35 \ + ESP32_PINMUX(35, ESP_PCNT_CTRL_CH0_IN1, ESP_NOSIG) + +#define PCNT1_CH0CTRL_GPIO36 \ + ESP32_PINMUX(36, ESP_PCNT_CTRL_CH0_IN1, ESP_NOSIG) + +#define PCNT1_CH0CTRL_GPIO37 \ + ESP32_PINMUX(37, ESP_PCNT_CTRL_CH0_IN1, ESP_NOSIG) + +#define PCNT1_CH0CTRL_GPIO38 \ + ESP32_PINMUX(38, ESP_PCNT_CTRL_CH0_IN1, ESP_NOSIG) + +#define PCNT1_CH0CTRL_GPIO39 \ + ESP32_PINMUX(39, ESP_PCNT_CTRL_CH0_IN1, ESP_NOSIG) + +#define PCNT1_CH0CTRL_GPIO40 \ + ESP32_PINMUX(40, ESP_PCNT_CTRL_CH0_IN1, ESP_NOSIG) + +#define PCNT1_CH0CTRL_GPIO41 \ + ESP32_PINMUX(41, ESP_PCNT_CTRL_CH0_IN1, ESP_NOSIG) + +#define PCNT1_CH0CTRL_GPIO42 \ + ESP32_PINMUX(42, ESP_PCNT_CTRL_CH0_IN1, ESP_NOSIG) + +#define PCNT1_CH0CTRL_GPIO43 \ + ESP32_PINMUX(43, ESP_PCNT_CTRL_CH0_IN1, ESP_NOSIG) + +#define PCNT1_CH0CTRL_GPIO44 \ + ESP32_PINMUX(44, ESP_PCNT_CTRL_CH0_IN1, ESP_NOSIG) + +#define PCNT1_CH0CTRL_GPIO45 \ + ESP32_PINMUX(45, ESP_PCNT_CTRL_CH0_IN1, ESP_NOSIG) + +#define PCNT1_CH0CTRL_GPIO46 \ + ESP32_PINMUX(46, ESP_PCNT_CTRL_CH0_IN1, ESP_NOSIG) + +/* PCNT1_CH0SIG */ +#define PCNT1_CH0SIG_GPIO0 \ + ESP32_PINMUX(0, ESP_PCNT_SIG_CH0_IN1, ESP_NOSIG) + +#define PCNT1_CH0SIG_GPIO1 \ + ESP32_PINMUX(1, ESP_PCNT_SIG_CH0_IN1, ESP_NOSIG) + +#define PCNT1_CH0SIG_GPIO2 \ + ESP32_PINMUX(2, ESP_PCNT_SIG_CH0_IN1, ESP_NOSIG) + +#define PCNT1_CH0SIG_GPIO3 \ + ESP32_PINMUX(3, ESP_PCNT_SIG_CH0_IN1, ESP_NOSIG) + +#define PCNT1_CH0SIG_GPIO4 \ + ESP32_PINMUX(4, ESP_PCNT_SIG_CH0_IN1, ESP_NOSIG) + +#define PCNT1_CH0SIG_GPIO5 \ + ESP32_PINMUX(5, ESP_PCNT_SIG_CH0_IN1, ESP_NOSIG) + +#define PCNT1_CH0SIG_GPIO6 \ + ESP32_PINMUX(6, ESP_PCNT_SIG_CH0_IN1, ESP_NOSIG) + +#define PCNT1_CH0SIG_GPIO7 \ + ESP32_PINMUX(7, ESP_PCNT_SIG_CH0_IN1, ESP_NOSIG) + +#define PCNT1_CH0SIG_GPIO8 \ + ESP32_PINMUX(8, ESP_PCNT_SIG_CH0_IN1, ESP_NOSIG) + +#define PCNT1_CH0SIG_GPIO9 \ + ESP32_PINMUX(9, ESP_PCNT_SIG_CH0_IN1, ESP_NOSIG) + +#define PCNT1_CH0SIG_GPIO10 \ + ESP32_PINMUX(10, ESP_PCNT_SIG_CH0_IN1, ESP_NOSIG) + +#define PCNT1_CH0SIG_GPIO11 \ + ESP32_PINMUX(11, ESP_PCNT_SIG_CH0_IN1, ESP_NOSIG) + +#define PCNT1_CH0SIG_GPIO12 \ + ESP32_PINMUX(12, ESP_PCNT_SIG_CH0_IN1, ESP_NOSIG) + +#define PCNT1_CH0SIG_GPIO13 \ + ESP32_PINMUX(13, ESP_PCNT_SIG_CH0_IN1, ESP_NOSIG) + +#define PCNT1_CH0SIG_GPIO14 \ + ESP32_PINMUX(14, ESP_PCNT_SIG_CH0_IN1, ESP_NOSIG) + +#define PCNT1_CH0SIG_GPIO15 \ + ESP32_PINMUX(15, ESP_PCNT_SIG_CH0_IN1, ESP_NOSIG) + +#define PCNT1_CH0SIG_GPIO16 \ + ESP32_PINMUX(16, ESP_PCNT_SIG_CH0_IN1, ESP_NOSIG) + +#define PCNT1_CH0SIG_GPIO17 \ + ESP32_PINMUX(17, ESP_PCNT_SIG_CH0_IN1, ESP_NOSIG) + +#define PCNT1_CH0SIG_GPIO18 \ + ESP32_PINMUX(18, ESP_PCNT_SIG_CH0_IN1, ESP_NOSIG) + +#define PCNT1_CH0SIG_GPIO19 \ + ESP32_PINMUX(19, ESP_PCNT_SIG_CH0_IN1, ESP_NOSIG) + +#define PCNT1_CH0SIG_GPIO20 \ + ESP32_PINMUX(20, ESP_PCNT_SIG_CH0_IN1, ESP_NOSIG) + +#define PCNT1_CH0SIG_GPIO21 \ + ESP32_PINMUX(21, ESP_PCNT_SIG_CH0_IN1, ESP_NOSIG) + +#define PCNT1_CH0SIG_GPIO26 \ + ESP32_PINMUX(26, ESP_PCNT_SIG_CH0_IN1, ESP_NOSIG) + +#define PCNT1_CH0SIG_GPIO27 \ + ESP32_PINMUX(27, ESP_PCNT_SIG_CH0_IN1, ESP_NOSIG) + +#define PCNT1_CH0SIG_GPIO28 \ + ESP32_PINMUX(28, ESP_PCNT_SIG_CH0_IN1, ESP_NOSIG) + +#define PCNT1_CH0SIG_GPIO29 \ + ESP32_PINMUX(29, ESP_PCNT_SIG_CH0_IN1, ESP_NOSIG) + +#define PCNT1_CH0SIG_GPIO30 \ + ESP32_PINMUX(30, ESP_PCNT_SIG_CH0_IN1, ESP_NOSIG) + +#define PCNT1_CH0SIG_GPIO31 \ + ESP32_PINMUX(31, ESP_PCNT_SIG_CH0_IN1, ESP_NOSIG) + +#define PCNT1_CH0SIG_GPIO32 \ + ESP32_PINMUX(32, ESP_PCNT_SIG_CH0_IN1, ESP_NOSIG) + +#define PCNT1_CH0SIG_GPIO33 \ + ESP32_PINMUX(33, ESP_PCNT_SIG_CH0_IN1, ESP_NOSIG) + +#define PCNT1_CH0SIG_GPIO34 \ + ESP32_PINMUX(34, ESP_PCNT_SIG_CH0_IN1, ESP_NOSIG) + +#define PCNT1_CH0SIG_GPIO35 \ + ESP32_PINMUX(35, ESP_PCNT_SIG_CH0_IN1, ESP_NOSIG) + +#define PCNT1_CH0SIG_GPIO36 \ + ESP32_PINMUX(36, ESP_PCNT_SIG_CH0_IN1, ESP_NOSIG) + +#define PCNT1_CH0SIG_GPIO37 \ + ESP32_PINMUX(37, ESP_PCNT_SIG_CH0_IN1, ESP_NOSIG) + +#define PCNT1_CH0SIG_GPIO38 \ + ESP32_PINMUX(38, ESP_PCNT_SIG_CH0_IN1, ESP_NOSIG) + +#define PCNT1_CH0SIG_GPIO39 \ + ESP32_PINMUX(39, ESP_PCNT_SIG_CH0_IN1, ESP_NOSIG) + +#define PCNT1_CH0SIG_GPIO40 \ + ESP32_PINMUX(40, ESP_PCNT_SIG_CH0_IN1, ESP_NOSIG) + +#define PCNT1_CH0SIG_GPIO41 \ + ESP32_PINMUX(41, ESP_PCNT_SIG_CH0_IN1, ESP_NOSIG) + +#define PCNT1_CH0SIG_GPIO42 \ + ESP32_PINMUX(42, ESP_PCNT_SIG_CH0_IN1, ESP_NOSIG) + +#define PCNT1_CH0SIG_GPIO43 \ + ESP32_PINMUX(43, ESP_PCNT_SIG_CH0_IN1, ESP_NOSIG) + +#define PCNT1_CH0SIG_GPIO44 \ + ESP32_PINMUX(44, ESP_PCNT_SIG_CH0_IN1, ESP_NOSIG) + +#define PCNT1_CH0SIG_GPIO45 \ + ESP32_PINMUX(45, ESP_PCNT_SIG_CH0_IN1, ESP_NOSIG) + +#define PCNT1_CH0SIG_GPIO46 \ + ESP32_PINMUX(46, ESP_PCNT_SIG_CH0_IN1, ESP_NOSIG) + +/* PCNT1_CH1CTRL */ +#define PCNT1_CH1CTRL_GPIO0 \ + ESP32_PINMUX(0, ESP_PCNT_CTRL_CH1_IN1, ESP_NOSIG) + +#define PCNT1_CH1CTRL_GPIO1 \ + ESP32_PINMUX(1, ESP_PCNT_CTRL_CH1_IN1, ESP_NOSIG) + +#define PCNT1_CH1CTRL_GPIO2 \ + ESP32_PINMUX(2, ESP_PCNT_CTRL_CH1_IN1, ESP_NOSIG) + +#define PCNT1_CH1CTRL_GPIO3 \ + ESP32_PINMUX(3, ESP_PCNT_CTRL_CH1_IN1, ESP_NOSIG) + +#define PCNT1_CH1CTRL_GPIO4 \ + ESP32_PINMUX(4, ESP_PCNT_CTRL_CH1_IN1, ESP_NOSIG) + +#define PCNT1_CH1CTRL_GPIO5 \ + ESP32_PINMUX(5, ESP_PCNT_CTRL_CH1_IN1, ESP_NOSIG) + +#define PCNT1_CH1CTRL_GPIO6 \ + ESP32_PINMUX(6, ESP_PCNT_CTRL_CH1_IN1, ESP_NOSIG) + +#define PCNT1_CH1CTRL_GPIO7 \ + ESP32_PINMUX(7, ESP_PCNT_CTRL_CH1_IN1, ESP_NOSIG) + +#define PCNT1_CH1CTRL_GPIO8 \ + ESP32_PINMUX(8, ESP_PCNT_CTRL_CH1_IN1, ESP_NOSIG) + +#define PCNT1_CH1CTRL_GPIO9 \ + ESP32_PINMUX(9, ESP_PCNT_CTRL_CH1_IN1, ESP_NOSIG) + +#define PCNT1_CH1CTRL_GPIO10 \ + ESP32_PINMUX(10, ESP_PCNT_CTRL_CH1_IN1, ESP_NOSIG) + +#define PCNT1_CH1CTRL_GPIO11 \ + ESP32_PINMUX(11, ESP_PCNT_CTRL_CH1_IN1, ESP_NOSIG) + +#define PCNT1_CH1CTRL_GPIO12 \ + ESP32_PINMUX(12, ESP_PCNT_CTRL_CH1_IN1, ESP_NOSIG) + +#define PCNT1_CH1CTRL_GPIO13 \ + ESP32_PINMUX(13, ESP_PCNT_CTRL_CH1_IN1, ESP_NOSIG) + +#define PCNT1_CH1CTRL_GPIO14 \ + ESP32_PINMUX(14, ESP_PCNT_CTRL_CH1_IN1, ESP_NOSIG) + +#define PCNT1_CH1CTRL_GPIO15 \ + ESP32_PINMUX(15, ESP_PCNT_CTRL_CH1_IN1, ESP_NOSIG) + +#define PCNT1_CH1CTRL_GPIO16 \ + ESP32_PINMUX(16, ESP_PCNT_CTRL_CH1_IN1, ESP_NOSIG) + +#define PCNT1_CH1CTRL_GPIO17 \ + ESP32_PINMUX(17, ESP_PCNT_CTRL_CH1_IN1, ESP_NOSIG) + +#define PCNT1_CH1CTRL_GPIO18 \ + ESP32_PINMUX(18, ESP_PCNT_CTRL_CH1_IN1, ESP_NOSIG) + +#define PCNT1_CH1CTRL_GPIO19 \ + ESP32_PINMUX(19, ESP_PCNT_CTRL_CH1_IN1, ESP_NOSIG) + +#define PCNT1_CH1CTRL_GPIO20 \ + ESP32_PINMUX(20, ESP_PCNT_CTRL_CH1_IN1, ESP_NOSIG) + +#define PCNT1_CH1CTRL_GPIO21 \ + ESP32_PINMUX(21, ESP_PCNT_CTRL_CH1_IN1, ESP_NOSIG) + +#define PCNT1_CH1CTRL_GPIO26 \ + ESP32_PINMUX(26, ESP_PCNT_CTRL_CH1_IN1, ESP_NOSIG) + +#define PCNT1_CH1CTRL_GPIO27 \ + ESP32_PINMUX(27, ESP_PCNT_CTRL_CH1_IN1, ESP_NOSIG) + +#define PCNT1_CH1CTRL_GPIO28 \ + ESP32_PINMUX(28, ESP_PCNT_CTRL_CH1_IN1, ESP_NOSIG) + +#define PCNT1_CH1CTRL_GPIO29 \ + ESP32_PINMUX(29, ESP_PCNT_CTRL_CH1_IN1, ESP_NOSIG) + +#define PCNT1_CH1CTRL_GPIO30 \ + ESP32_PINMUX(30, ESP_PCNT_CTRL_CH1_IN1, ESP_NOSIG) + +#define PCNT1_CH1CTRL_GPIO31 \ + ESP32_PINMUX(31, ESP_PCNT_CTRL_CH1_IN1, ESP_NOSIG) + +#define PCNT1_CH1CTRL_GPIO32 \ + ESP32_PINMUX(32, ESP_PCNT_CTRL_CH1_IN1, ESP_NOSIG) + +#define PCNT1_CH1CTRL_GPIO33 \ + ESP32_PINMUX(33, ESP_PCNT_CTRL_CH1_IN1, ESP_NOSIG) + +#define PCNT1_CH1CTRL_GPIO34 \ + ESP32_PINMUX(34, ESP_PCNT_CTRL_CH1_IN1, ESP_NOSIG) + +#define PCNT1_CH1CTRL_GPIO35 \ + ESP32_PINMUX(35, ESP_PCNT_CTRL_CH1_IN1, ESP_NOSIG) + +#define PCNT1_CH1CTRL_GPIO36 \ + ESP32_PINMUX(36, ESP_PCNT_CTRL_CH1_IN1, ESP_NOSIG) + +#define PCNT1_CH1CTRL_GPIO37 \ + ESP32_PINMUX(37, ESP_PCNT_CTRL_CH1_IN1, ESP_NOSIG) + +#define PCNT1_CH1CTRL_GPIO38 \ + ESP32_PINMUX(38, ESP_PCNT_CTRL_CH1_IN1, ESP_NOSIG) + +#define PCNT1_CH1CTRL_GPIO39 \ + ESP32_PINMUX(39, ESP_PCNT_CTRL_CH1_IN1, ESP_NOSIG) + +#define PCNT1_CH1CTRL_GPIO40 \ + ESP32_PINMUX(40, ESP_PCNT_CTRL_CH1_IN1, ESP_NOSIG) + +#define PCNT1_CH1CTRL_GPIO41 \ + ESP32_PINMUX(41, ESP_PCNT_CTRL_CH1_IN1, ESP_NOSIG) + +#define PCNT1_CH1CTRL_GPIO42 \ + ESP32_PINMUX(42, ESP_PCNT_CTRL_CH1_IN1, ESP_NOSIG) + +#define PCNT1_CH1CTRL_GPIO43 \ + ESP32_PINMUX(43, ESP_PCNT_CTRL_CH1_IN1, ESP_NOSIG) + +#define PCNT1_CH1CTRL_GPIO44 \ + ESP32_PINMUX(44, ESP_PCNT_CTRL_CH1_IN1, ESP_NOSIG) + +#define PCNT1_CH1CTRL_GPIO45 \ + ESP32_PINMUX(45, ESP_PCNT_CTRL_CH1_IN1, ESP_NOSIG) + +#define PCNT1_CH1CTRL_GPIO46 \ + ESP32_PINMUX(46, ESP_PCNT_CTRL_CH1_IN1, ESP_NOSIG) + +/* PCNT1_CH1SIG */ +#define PCNT1_CH1SIG_GPIO0 \ + ESP32_PINMUX(0, ESP_PCNT_SIG_CH1_IN1, ESP_NOSIG) + +#define PCNT1_CH1SIG_GPIO1 \ + ESP32_PINMUX(1, ESP_PCNT_SIG_CH1_IN1, ESP_NOSIG) + +#define PCNT1_CH1SIG_GPIO2 \ + ESP32_PINMUX(2, ESP_PCNT_SIG_CH1_IN1, ESP_NOSIG) + +#define PCNT1_CH1SIG_GPIO3 \ + ESP32_PINMUX(3, ESP_PCNT_SIG_CH1_IN1, ESP_NOSIG) + +#define PCNT1_CH1SIG_GPIO4 \ + ESP32_PINMUX(4, ESP_PCNT_SIG_CH1_IN1, ESP_NOSIG) + +#define PCNT1_CH1SIG_GPIO5 \ + ESP32_PINMUX(5, ESP_PCNT_SIG_CH1_IN1, ESP_NOSIG) + +#define PCNT1_CH1SIG_GPIO6 \ + ESP32_PINMUX(6, ESP_PCNT_SIG_CH1_IN1, ESP_NOSIG) + +#define PCNT1_CH1SIG_GPIO7 \ + ESP32_PINMUX(7, ESP_PCNT_SIG_CH1_IN1, ESP_NOSIG) + +#define PCNT1_CH1SIG_GPIO8 \ + ESP32_PINMUX(8, ESP_PCNT_SIG_CH1_IN1, ESP_NOSIG) + +#define PCNT1_CH1SIG_GPIO9 \ + ESP32_PINMUX(9, ESP_PCNT_SIG_CH1_IN1, ESP_NOSIG) + +#define PCNT1_CH1SIG_GPIO10 \ + ESP32_PINMUX(10, ESP_PCNT_SIG_CH1_IN1, ESP_NOSIG) + +#define PCNT1_CH1SIG_GPIO11 \ + ESP32_PINMUX(11, ESP_PCNT_SIG_CH1_IN1, ESP_NOSIG) + +#define PCNT1_CH1SIG_GPIO12 \ + ESP32_PINMUX(12, ESP_PCNT_SIG_CH1_IN1, ESP_NOSIG) + +#define PCNT1_CH1SIG_GPIO13 \ + ESP32_PINMUX(13, ESP_PCNT_SIG_CH1_IN1, ESP_NOSIG) + +#define PCNT1_CH1SIG_GPIO14 \ + ESP32_PINMUX(14, ESP_PCNT_SIG_CH1_IN1, ESP_NOSIG) + +#define PCNT1_CH1SIG_GPIO15 \ + ESP32_PINMUX(15, ESP_PCNT_SIG_CH1_IN1, ESP_NOSIG) + +#define PCNT1_CH1SIG_GPIO16 \ + ESP32_PINMUX(16, ESP_PCNT_SIG_CH1_IN1, ESP_NOSIG) + +#define PCNT1_CH1SIG_GPIO17 \ + ESP32_PINMUX(17, ESP_PCNT_SIG_CH1_IN1, ESP_NOSIG) + +#define PCNT1_CH1SIG_GPIO18 \ + ESP32_PINMUX(18, ESP_PCNT_SIG_CH1_IN1, ESP_NOSIG) + +#define PCNT1_CH1SIG_GPIO19 \ + ESP32_PINMUX(19, ESP_PCNT_SIG_CH1_IN1, ESP_NOSIG) + +#define PCNT1_CH1SIG_GPIO20 \ + ESP32_PINMUX(20, ESP_PCNT_SIG_CH1_IN1, ESP_NOSIG) + +#define PCNT1_CH1SIG_GPIO21 \ + ESP32_PINMUX(21, ESP_PCNT_SIG_CH1_IN1, ESP_NOSIG) + +#define PCNT1_CH1SIG_GPIO26 \ + ESP32_PINMUX(26, ESP_PCNT_SIG_CH1_IN1, ESP_NOSIG) + +#define PCNT1_CH1SIG_GPIO27 \ + ESP32_PINMUX(27, ESP_PCNT_SIG_CH1_IN1, ESP_NOSIG) + +#define PCNT1_CH1SIG_GPIO28 \ + ESP32_PINMUX(28, ESP_PCNT_SIG_CH1_IN1, ESP_NOSIG) + +#define PCNT1_CH1SIG_GPIO29 \ + ESP32_PINMUX(29, ESP_PCNT_SIG_CH1_IN1, ESP_NOSIG) + +#define PCNT1_CH1SIG_GPIO30 \ + ESP32_PINMUX(30, ESP_PCNT_SIG_CH1_IN1, ESP_NOSIG) + +#define PCNT1_CH1SIG_GPIO31 \ + ESP32_PINMUX(31, ESP_PCNT_SIG_CH1_IN1, ESP_NOSIG) + +#define PCNT1_CH1SIG_GPIO32 \ + ESP32_PINMUX(32, ESP_PCNT_SIG_CH1_IN1, ESP_NOSIG) + +#define PCNT1_CH1SIG_GPIO33 \ + ESP32_PINMUX(33, ESP_PCNT_SIG_CH1_IN1, ESP_NOSIG) + +#define PCNT1_CH1SIG_GPIO34 \ + ESP32_PINMUX(34, ESP_PCNT_SIG_CH1_IN1, ESP_NOSIG) + +#define PCNT1_CH1SIG_GPIO35 \ + ESP32_PINMUX(35, ESP_PCNT_SIG_CH1_IN1, ESP_NOSIG) + +#define PCNT1_CH1SIG_GPIO36 \ + ESP32_PINMUX(36, ESP_PCNT_SIG_CH1_IN1, ESP_NOSIG) + +#define PCNT1_CH1SIG_GPIO37 \ + ESP32_PINMUX(37, ESP_PCNT_SIG_CH1_IN1, ESP_NOSIG) + +#define PCNT1_CH1SIG_GPIO38 \ + ESP32_PINMUX(38, ESP_PCNT_SIG_CH1_IN1, ESP_NOSIG) + +#define PCNT1_CH1SIG_GPIO39 \ + ESP32_PINMUX(39, ESP_PCNT_SIG_CH1_IN1, ESP_NOSIG) + +#define PCNT1_CH1SIG_GPIO40 \ + ESP32_PINMUX(40, ESP_PCNT_SIG_CH1_IN1, ESP_NOSIG) + +#define PCNT1_CH1SIG_GPIO41 \ + ESP32_PINMUX(41, ESP_PCNT_SIG_CH1_IN1, ESP_NOSIG) + +#define PCNT1_CH1SIG_GPIO42 \ + ESP32_PINMUX(42, ESP_PCNT_SIG_CH1_IN1, ESP_NOSIG) + +#define PCNT1_CH1SIG_GPIO43 \ + ESP32_PINMUX(43, ESP_PCNT_SIG_CH1_IN1, ESP_NOSIG) + +#define PCNT1_CH1SIG_GPIO44 \ + ESP32_PINMUX(44, ESP_PCNT_SIG_CH1_IN1, ESP_NOSIG) + +#define PCNT1_CH1SIG_GPIO45 \ + ESP32_PINMUX(45, ESP_PCNT_SIG_CH1_IN1, ESP_NOSIG) + +#define PCNT1_CH1SIG_GPIO46 \ + ESP32_PINMUX(46, ESP_PCNT_SIG_CH1_IN1, ESP_NOSIG) + +/* PCNT2_CH0CTRL */ +#define PCNT2_CH0CTRL_GPIO0 \ + ESP32_PINMUX(0, ESP_PCNT_CTRL_CH0_IN2, ESP_NOSIG) + +#define PCNT2_CH0CTRL_GPIO1 \ + ESP32_PINMUX(1, ESP_PCNT_CTRL_CH0_IN2, ESP_NOSIG) + +#define PCNT2_CH0CTRL_GPIO2 \ + ESP32_PINMUX(2, ESP_PCNT_CTRL_CH0_IN2, ESP_NOSIG) + +#define PCNT2_CH0CTRL_GPIO3 \ + ESP32_PINMUX(3, ESP_PCNT_CTRL_CH0_IN2, ESP_NOSIG) + +#define PCNT2_CH0CTRL_GPIO4 \ + ESP32_PINMUX(4, ESP_PCNT_CTRL_CH0_IN2, ESP_NOSIG) + +#define PCNT2_CH0CTRL_GPIO5 \ + ESP32_PINMUX(5, ESP_PCNT_CTRL_CH0_IN2, ESP_NOSIG) + +#define PCNT2_CH0CTRL_GPIO6 \ + ESP32_PINMUX(6, ESP_PCNT_CTRL_CH0_IN2, ESP_NOSIG) + +#define PCNT2_CH0CTRL_GPIO7 \ + ESP32_PINMUX(7, ESP_PCNT_CTRL_CH0_IN2, ESP_NOSIG) + +#define PCNT2_CH0CTRL_GPIO8 \ + ESP32_PINMUX(8, ESP_PCNT_CTRL_CH0_IN2, ESP_NOSIG) + +#define PCNT2_CH0CTRL_GPIO9 \ + ESP32_PINMUX(9, ESP_PCNT_CTRL_CH0_IN2, ESP_NOSIG) + +#define PCNT2_CH0CTRL_GPIO10 \ + ESP32_PINMUX(10, ESP_PCNT_CTRL_CH0_IN2, ESP_NOSIG) + +#define PCNT2_CH0CTRL_GPIO11 \ + ESP32_PINMUX(11, ESP_PCNT_CTRL_CH0_IN2, ESP_NOSIG) + +#define PCNT2_CH0CTRL_GPIO12 \ + ESP32_PINMUX(12, ESP_PCNT_CTRL_CH0_IN2, ESP_NOSIG) + +#define PCNT2_CH0CTRL_GPIO13 \ + ESP32_PINMUX(13, ESP_PCNT_CTRL_CH0_IN2, ESP_NOSIG) + +#define PCNT2_CH0CTRL_GPIO14 \ + ESP32_PINMUX(14, ESP_PCNT_CTRL_CH0_IN2, ESP_NOSIG) + +#define PCNT2_CH0CTRL_GPIO15 \ + ESP32_PINMUX(15, ESP_PCNT_CTRL_CH0_IN2, ESP_NOSIG) + +#define PCNT2_CH0CTRL_GPIO16 \ + ESP32_PINMUX(16, ESP_PCNT_CTRL_CH0_IN2, ESP_NOSIG) + +#define PCNT2_CH0CTRL_GPIO17 \ + ESP32_PINMUX(17, ESP_PCNT_CTRL_CH0_IN2, ESP_NOSIG) + +#define PCNT2_CH0CTRL_GPIO18 \ + ESP32_PINMUX(18, ESP_PCNT_CTRL_CH0_IN2, ESP_NOSIG) + +#define PCNT2_CH0CTRL_GPIO19 \ + ESP32_PINMUX(19, ESP_PCNT_CTRL_CH0_IN2, ESP_NOSIG) + +#define PCNT2_CH0CTRL_GPIO20 \ + ESP32_PINMUX(20, ESP_PCNT_CTRL_CH0_IN2, ESP_NOSIG) + +#define PCNT2_CH0CTRL_GPIO21 \ + ESP32_PINMUX(21, ESP_PCNT_CTRL_CH0_IN2, ESP_NOSIG) + +#define PCNT2_CH0CTRL_GPIO26 \ + ESP32_PINMUX(26, ESP_PCNT_CTRL_CH0_IN2, ESP_NOSIG) + +#define PCNT2_CH0CTRL_GPIO27 \ + ESP32_PINMUX(27, ESP_PCNT_CTRL_CH0_IN2, ESP_NOSIG) + +#define PCNT2_CH0CTRL_GPIO28 \ + ESP32_PINMUX(28, ESP_PCNT_CTRL_CH0_IN2, ESP_NOSIG) + +#define PCNT2_CH0CTRL_GPIO29 \ + ESP32_PINMUX(29, ESP_PCNT_CTRL_CH0_IN2, ESP_NOSIG) + +#define PCNT2_CH0CTRL_GPIO30 \ + ESP32_PINMUX(30, ESP_PCNT_CTRL_CH0_IN2, ESP_NOSIG) + +#define PCNT2_CH0CTRL_GPIO31 \ + ESP32_PINMUX(31, ESP_PCNT_CTRL_CH0_IN2, ESP_NOSIG) + +#define PCNT2_CH0CTRL_GPIO32 \ + ESP32_PINMUX(32, ESP_PCNT_CTRL_CH0_IN2, ESP_NOSIG) + +#define PCNT2_CH0CTRL_GPIO33 \ + ESP32_PINMUX(33, ESP_PCNT_CTRL_CH0_IN2, ESP_NOSIG) + +#define PCNT2_CH0CTRL_GPIO34 \ + ESP32_PINMUX(34, ESP_PCNT_CTRL_CH0_IN2, ESP_NOSIG) + +#define PCNT2_CH0CTRL_GPIO35 \ + ESP32_PINMUX(35, ESP_PCNT_CTRL_CH0_IN2, ESP_NOSIG) + +#define PCNT2_CH0CTRL_GPIO36 \ + ESP32_PINMUX(36, ESP_PCNT_CTRL_CH0_IN2, ESP_NOSIG) + +#define PCNT2_CH0CTRL_GPIO37 \ + ESP32_PINMUX(37, ESP_PCNT_CTRL_CH0_IN2, ESP_NOSIG) + +#define PCNT2_CH0CTRL_GPIO38 \ + ESP32_PINMUX(38, ESP_PCNT_CTRL_CH0_IN2, ESP_NOSIG) + +#define PCNT2_CH0CTRL_GPIO39 \ + ESP32_PINMUX(39, ESP_PCNT_CTRL_CH0_IN2, ESP_NOSIG) + +#define PCNT2_CH0CTRL_GPIO40 \ + ESP32_PINMUX(40, ESP_PCNT_CTRL_CH0_IN2, ESP_NOSIG) + +#define PCNT2_CH0CTRL_GPIO41 \ + ESP32_PINMUX(41, ESP_PCNT_CTRL_CH0_IN2, ESP_NOSIG) + +#define PCNT2_CH0CTRL_GPIO42 \ + ESP32_PINMUX(42, ESP_PCNT_CTRL_CH0_IN2, ESP_NOSIG) + +#define PCNT2_CH0CTRL_GPIO43 \ + ESP32_PINMUX(43, ESP_PCNT_CTRL_CH0_IN2, ESP_NOSIG) + +#define PCNT2_CH0CTRL_GPIO44 \ + ESP32_PINMUX(44, ESP_PCNT_CTRL_CH0_IN2, ESP_NOSIG) + +#define PCNT2_CH0CTRL_GPIO45 \ + ESP32_PINMUX(45, ESP_PCNT_CTRL_CH0_IN2, ESP_NOSIG) + +#define PCNT2_CH0CTRL_GPIO46 \ + ESP32_PINMUX(46, ESP_PCNT_CTRL_CH0_IN2, ESP_NOSIG) + +/* PCNT2_CH0SIG */ +#define PCNT2_CH0SIG_GPIO0 \ + ESP32_PINMUX(0, ESP_PCNT_SIG_CH0_IN3, ESP_NOSIG) + +#define PCNT2_CH0SIG_GPIO1 \ + ESP32_PINMUX(1, ESP_PCNT_SIG_CH0_IN3, ESP_NOSIG) + +#define PCNT2_CH0SIG_GPIO2 \ + ESP32_PINMUX(2, ESP_PCNT_SIG_CH0_IN3, ESP_NOSIG) + +#define PCNT2_CH0SIG_GPIO3 \ + ESP32_PINMUX(3, ESP_PCNT_SIG_CH0_IN3, ESP_NOSIG) + +#define PCNT2_CH0SIG_GPIO4 \ + ESP32_PINMUX(4, ESP_PCNT_SIG_CH0_IN3, ESP_NOSIG) + +#define PCNT2_CH0SIG_GPIO5 \ + ESP32_PINMUX(5, ESP_PCNT_SIG_CH0_IN3, ESP_NOSIG) + +#define PCNT2_CH0SIG_GPIO6 \ + ESP32_PINMUX(6, ESP_PCNT_SIG_CH0_IN3, ESP_NOSIG) + +#define PCNT2_CH0SIG_GPIO7 \ + ESP32_PINMUX(7, ESP_PCNT_SIG_CH0_IN3, ESP_NOSIG) + +#define PCNT2_CH0SIG_GPIO8 \ + ESP32_PINMUX(8, ESP_PCNT_SIG_CH0_IN3, ESP_NOSIG) + +#define PCNT2_CH0SIG_GPIO9 \ + ESP32_PINMUX(9, ESP_PCNT_SIG_CH0_IN3, ESP_NOSIG) + +#define PCNT2_CH0SIG_GPIO10 \ + ESP32_PINMUX(10, ESP_PCNT_SIG_CH0_IN3, ESP_NOSIG) + +#define PCNT2_CH0SIG_GPIO11 \ + ESP32_PINMUX(11, ESP_PCNT_SIG_CH0_IN3, ESP_NOSIG) + +#define PCNT2_CH0SIG_GPIO12 \ + ESP32_PINMUX(12, ESP_PCNT_SIG_CH0_IN3, ESP_NOSIG) + +#define PCNT2_CH0SIG_GPIO13 \ + ESP32_PINMUX(13, ESP_PCNT_SIG_CH0_IN3, ESP_NOSIG) + +#define PCNT2_CH0SIG_GPIO14 \ + ESP32_PINMUX(14, ESP_PCNT_SIG_CH0_IN3, ESP_NOSIG) + +#define PCNT2_CH0SIG_GPIO15 \ + ESP32_PINMUX(15, ESP_PCNT_SIG_CH0_IN3, ESP_NOSIG) + +#define PCNT2_CH0SIG_GPIO16 \ + ESP32_PINMUX(16, ESP_PCNT_SIG_CH0_IN3, ESP_NOSIG) + +#define PCNT2_CH0SIG_GPIO17 \ + ESP32_PINMUX(17, ESP_PCNT_SIG_CH0_IN3, ESP_NOSIG) + +#define PCNT2_CH0SIG_GPIO18 \ + ESP32_PINMUX(18, ESP_PCNT_SIG_CH0_IN3, ESP_NOSIG) + +#define PCNT2_CH0SIG_GPIO19 \ + ESP32_PINMUX(19, ESP_PCNT_SIG_CH0_IN3, ESP_NOSIG) + +#define PCNT2_CH0SIG_GPIO20 \ + ESP32_PINMUX(20, ESP_PCNT_SIG_CH0_IN3, ESP_NOSIG) + +#define PCNT2_CH0SIG_GPIO21 \ + ESP32_PINMUX(21, ESP_PCNT_SIG_CH0_IN3, ESP_NOSIG) + +#define PCNT2_CH0SIG_GPIO26 \ + ESP32_PINMUX(26, ESP_PCNT_SIG_CH0_IN3, ESP_NOSIG) + +#define PCNT2_CH0SIG_GPIO27 \ + ESP32_PINMUX(27, ESP_PCNT_SIG_CH0_IN3, ESP_NOSIG) + +#define PCNT2_CH0SIG_GPIO28 \ + ESP32_PINMUX(28, ESP_PCNT_SIG_CH0_IN3, ESP_NOSIG) + +#define PCNT2_CH0SIG_GPIO29 \ + ESP32_PINMUX(29, ESP_PCNT_SIG_CH0_IN3, ESP_NOSIG) + +#define PCNT2_CH0SIG_GPIO30 \ + ESP32_PINMUX(30, ESP_PCNT_SIG_CH0_IN3, ESP_NOSIG) + +#define PCNT2_CH0SIG_GPIO31 \ + ESP32_PINMUX(31, ESP_PCNT_SIG_CH0_IN3, ESP_NOSIG) + +#define PCNT2_CH0SIG_GPIO32 \ + ESP32_PINMUX(32, ESP_PCNT_SIG_CH0_IN3, ESP_NOSIG) + +#define PCNT2_CH0SIG_GPIO33 \ + ESP32_PINMUX(33, ESP_PCNT_SIG_CH0_IN3, ESP_NOSIG) + +#define PCNT2_CH0SIG_GPIO34 \ + ESP32_PINMUX(34, ESP_PCNT_SIG_CH0_IN3, ESP_NOSIG) + +#define PCNT2_CH0SIG_GPIO35 \ + ESP32_PINMUX(35, ESP_PCNT_SIG_CH0_IN3, ESP_NOSIG) + +#define PCNT2_CH0SIG_GPIO36 \ + ESP32_PINMUX(36, ESP_PCNT_SIG_CH0_IN3, ESP_NOSIG) + +#define PCNT2_CH0SIG_GPIO37 \ + ESP32_PINMUX(37, ESP_PCNT_SIG_CH0_IN3, ESP_NOSIG) + +#define PCNT2_CH0SIG_GPIO38 \ + ESP32_PINMUX(38, ESP_PCNT_SIG_CH0_IN3, ESP_NOSIG) + +#define PCNT2_CH0SIG_GPIO39 \ + ESP32_PINMUX(39, ESP_PCNT_SIG_CH0_IN3, ESP_NOSIG) + +#define PCNT2_CH0SIG_GPIO40 \ + ESP32_PINMUX(40, ESP_PCNT_SIG_CH0_IN3, ESP_NOSIG) + +#define PCNT2_CH0SIG_GPIO41 \ + ESP32_PINMUX(41, ESP_PCNT_SIG_CH0_IN3, ESP_NOSIG) + +#define PCNT2_CH0SIG_GPIO42 \ + ESP32_PINMUX(42, ESP_PCNT_SIG_CH0_IN3, ESP_NOSIG) + +#define PCNT2_CH0SIG_GPIO43 \ + ESP32_PINMUX(43, ESP_PCNT_SIG_CH0_IN3, ESP_NOSIG) + +#define PCNT2_CH0SIG_GPIO44 \ + ESP32_PINMUX(44, ESP_PCNT_SIG_CH0_IN3, ESP_NOSIG) + +#define PCNT2_CH0SIG_GPIO45 \ + ESP32_PINMUX(45, ESP_PCNT_SIG_CH0_IN3, ESP_NOSIG) + +#define PCNT2_CH0SIG_GPIO46 \ + ESP32_PINMUX(46, ESP_PCNT_SIG_CH0_IN3, ESP_NOSIG) + +/* PCNT2_CH1CTRL */ +#define PCNT2_CH1CTRL_GPIO0 \ + ESP32_PINMUX(0, ESP_PCNT_CTRL_CH1_IN2, ESP_NOSIG) + +#define PCNT2_CH1CTRL_GPIO1 \ + ESP32_PINMUX(1, ESP_PCNT_CTRL_CH1_IN2, ESP_NOSIG) + +#define PCNT2_CH1CTRL_GPIO2 \ + ESP32_PINMUX(2, ESP_PCNT_CTRL_CH1_IN2, ESP_NOSIG) + +#define PCNT2_CH1CTRL_GPIO3 \ + ESP32_PINMUX(3, ESP_PCNT_CTRL_CH1_IN2, ESP_NOSIG) + +#define PCNT2_CH1CTRL_GPIO4 \ + ESP32_PINMUX(4, ESP_PCNT_CTRL_CH1_IN2, ESP_NOSIG) + +#define PCNT2_CH1CTRL_GPIO5 \ + ESP32_PINMUX(5, ESP_PCNT_CTRL_CH1_IN2, ESP_NOSIG) + +#define PCNT2_CH1CTRL_GPIO6 \ + ESP32_PINMUX(6, ESP_PCNT_CTRL_CH1_IN2, ESP_NOSIG) + +#define PCNT2_CH1CTRL_GPIO7 \ + ESP32_PINMUX(7, ESP_PCNT_CTRL_CH1_IN2, ESP_NOSIG) + +#define PCNT2_CH1CTRL_GPIO8 \ + ESP32_PINMUX(8, ESP_PCNT_CTRL_CH1_IN2, ESP_NOSIG) + +#define PCNT2_CH1CTRL_GPIO9 \ + ESP32_PINMUX(9, ESP_PCNT_CTRL_CH1_IN2, ESP_NOSIG) + +#define PCNT2_CH1CTRL_GPIO10 \ + ESP32_PINMUX(10, ESP_PCNT_CTRL_CH1_IN2, ESP_NOSIG) + +#define PCNT2_CH1CTRL_GPIO11 \ + ESP32_PINMUX(11, ESP_PCNT_CTRL_CH1_IN2, ESP_NOSIG) + +#define PCNT2_CH1CTRL_GPIO12 \ + ESP32_PINMUX(12, ESP_PCNT_CTRL_CH1_IN2, ESP_NOSIG) + +#define PCNT2_CH1CTRL_GPIO13 \ + ESP32_PINMUX(13, ESP_PCNT_CTRL_CH1_IN2, ESP_NOSIG) + +#define PCNT2_CH1CTRL_GPIO14 \ + ESP32_PINMUX(14, ESP_PCNT_CTRL_CH1_IN2, ESP_NOSIG) + +#define PCNT2_CH1CTRL_GPIO15 \ + ESP32_PINMUX(15, ESP_PCNT_CTRL_CH1_IN2, ESP_NOSIG) + +#define PCNT2_CH1CTRL_GPIO16 \ + ESP32_PINMUX(16, ESP_PCNT_CTRL_CH1_IN2, ESP_NOSIG) + +#define PCNT2_CH1CTRL_GPIO17 \ + ESP32_PINMUX(17, ESP_PCNT_CTRL_CH1_IN2, ESP_NOSIG) + +#define PCNT2_CH1CTRL_GPIO18 \ + ESP32_PINMUX(18, ESP_PCNT_CTRL_CH1_IN2, ESP_NOSIG) + +#define PCNT2_CH1CTRL_GPIO19 \ + ESP32_PINMUX(19, ESP_PCNT_CTRL_CH1_IN2, ESP_NOSIG) + +#define PCNT2_CH1CTRL_GPIO20 \ + ESP32_PINMUX(20, ESP_PCNT_CTRL_CH1_IN2, ESP_NOSIG) + +#define PCNT2_CH1CTRL_GPIO21 \ + ESP32_PINMUX(21, ESP_PCNT_CTRL_CH1_IN2, ESP_NOSIG) + +#define PCNT2_CH1CTRL_GPIO26 \ + ESP32_PINMUX(26, ESP_PCNT_CTRL_CH1_IN2, ESP_NOSIG) + +#define PCNT2_CH1CTRL_GPIO27 \ + ESP32_PINMUX(27, ESP_PCNT_CTRL_CH1_IN2, ESP_NOSIG) + +#define PCNT2_CH1CTRL_GPIO28 \ + ESP32_PINMUX(28, ESP_PCNT_CTRL_CH1_IN2, ESP_NOSIG) + +#define PCNT2_CH1CTRL_GPIO29 \ + ESP32_PINMUX(29, ESP_PCNT_CTRL_CH1_IN2, ESP_NOSIG) + +#define PCNT2_CH1CTRL_GPIO30 \ + ESP32_PINMUX(30, ESP_PCNT_CTRL_CH1_IN2, ESP_NOSIG) + +#define PCNT2_CH1CTRL_GPIO31 \ + ESP32_PINMUX(31, ESP_PCNT_CTRL_CH1_IN2, ESP_NOSIG) + +#define PCNT2_CH1CTRL_GPIO32 \ + ESP32_PINMUX(32, ESP_PCNT_CTRL_CH1_IN2, ESP_NOSIG) + +#define PCNT2_CH1CTRL_GPIO33 \ + ESP32_PINMUX(33, ESP_PCNT_CTRL_CH1_IN2, ESP_NOSIG) + +#define PCNT2_CH1CTRL_GPIO34 \ + ESP32_PINMUX(34, ESP_PCNT_CTRL_CH1_IN2, ESP_NOSIG) + +#define PCNT2_CH1CTRL_GPIO35 \ + ESP32_PINMUX(35, ESP_PCNT_CTRL_CH1_IN2, ESP_NOSIG) + +#define PCNT2_CH1CTRL_GPIO36 \ + ESP32_PINMUX(36, ESP_PCNT_CTRL_CH1_IN2, ESP_NOSIG) + +#define PCNT2_CH1CTRL_GPIO37 \ + ESP32_PINMUX(37, ESP_PCNT_CTRL_CH1_IN2, ESP_NOSIG) + +#define PCNT2_CH1CTRL_GPIO38 \ + ESP32_PINMUX(38, ESP_PCNT_CTRL_CH1_IN2, ESP_NOSIG) + +#define PCNT2_CH1CTRL_GPIO39 \ + ESP32_PINMUX(39, ESP_PCNT_CTRL_CH1_IN2, ESP_NOSIG) + +#define PCNT2_CH1CTRL_GPIO40 \ + ESP32_PINMUX(40, ESP_PCNT_CTRL_CH1_IN2, ESP_NOSIG) + +#define PCNT2_CH1CTRL_GPIO41 \ + ESP32_PINMUX(41, ESP_PCNT_CTRL_CH1_IN2, ESP_NOSIG) + +#define PCNT2_CH1CTRL_GPIO42 \ + ESP32_PINMUX(42, ESP_PCNT_CTRL_CH1_IN2, ESP_NOSIG) + +#define PCNT2_CH1CTRL_GPIO43 \ + ESP32_PINMUX(43, ESP_PCNT_CTRL_CH1_IN2, ESP_NOSIG) + +#define PCNT2_CH1CTRL_GPIO44 \ + ESP32_PINMUX(44, ESP_PCNT_CTRL_CH1_IN2, ESP_NOSIG) + +#define PCNT2_CH1CTRL_GPIO45 \ + ESP32_PINMUX(45, ESP_PCNT_CTRL_CH1_IN2, ESP_NOSIG) + +#define PCNT2_CH1CTRL_GPIO46 \ + ESP32_PINMUX(46, ESP_PCNT_CTRL_CH1_IN2, ESP_NOSIG) + +/* PCNT2_CH1SIG */ +#define PCNT2_CH1SIG_GPIO0 \ + ESP32_PINMUX(0, ESP_PCNT_SIG_CH1_IN2, ESP_NOSIG) + +#define PCNT2_CH1SIG_GPIO1 \ + ESP32_PINMUX(1, ESP_PCNT_SIG_CH1_IN2, ESP_NOSIG) + +#define PCNT2_CH1SIG_GPIO2 \ + ESP32_PINMUX(2, ESP_PCNT_SIG_CH1_IN2, ESP_NOSIG) + +#define PCNT2_CH1SIG_GPIO3 \ + ESP32_PINMUX(3, ESP_PCNT_SIG_CH1_IN2, ESP_NOSIG) + +#define PCNT2_CH1SIG_GPIO4 \ + ESP32_PINMUX(4, ESP_PCNT_SIG_CH1_IN2, ESP_NOSIG) + +#define PCNT2_CH1SIG_GPIO5 \ + ESP32_PINMUX(5, ESP_PCNT_SIG_CH1_IN2, ESP_NOSIG) + +#define PCNT2_CH1SIG_GPIO6 \ + ESP32_PINMUX(6, ESP_PCNT_SIG_CH1_IN2, ESP_NOSIG) + +#define PCNT2_CH1SIG_GPIO7 \ + ESP32_PINMUX(7, ESP_PCNT_SIG_CH1_IN2, ESP_NOSIG) + +#define PCNT2_CH1SIG_GPIO8 \ + ESP32_PINMUX(8, ESP_PCNT_SIG_CH1_IN2, ESP_NOSIG) + +#define PCNT2_CH1SIG_GPIO9 \ + ESP32_PINMUX(9, ESP_PCNT_SIG_CH1_IN2, ESP_NOSIG) + +#define PCNT2_CH1SIG_GPIO10 \ + ESP32_PINMUX(10, ESP_PCNT_SIG_CH1_IN2, ESP_NOSIG) + +#define PCNT2_CH1SIG_GPIO11 \ + ESP32_PINMUX(11, ESP_PCNT_SIG_CH1_IN2, ESP_NOSIG) + +#define PCNT2_CH1SIG_GPIO12 \ + ESP32_PINMUX(12, ESP_PCNT_SIG_CH1_IN2, ESP_NOSIG) + +#define PCNT2_CH1SIG_GPIO13 \ + ESP32_PINMUX(13, ESP_PCNT_SIG_CH1_IN2, ESP_NOSIG) + +#define PCNT2_CH1SIG_GPIO14 \ + ESP32_PINMUX(14, ESP_PCNT_SIG_CH1_IN2, ESP_NOSIG) + +#define PCNT2_CH1SIG_GPIO15 \ + ESP32_PINMUX(15, ESP_PCNT_SIG_CH1_IN2, ESP_NOSIG) + +#define PCNT2_CH1SIG_GPIO16 \ + ESP32_PINMUX(16, ESP_PCNT_SIG_CH1_IN2, ESP_NOSIG) + +#define PCNT2_CH1SIG_GPIO17 \ + ESP32_PINMUX(17, ESP_PCNT_SIG_CH1_IN2, ESP_NOSIG) + +#define PCNT2_CH1SIG_GPIO18 \ + ESP32_PINMUX(18, ESP_PCNT_SIG_CH1_IN2, ESP_NOSIG) + +#define PCNT2_CH1SIG_GPIO19 \ + ESP32_PINMUX(19, ESP_PCNT_SIG_CH1_IN2, ESP_NOSIG) + +#define PCNT2_CH1SIG_GPIO20 \ + ESP32_PINMUX(20, ESP_PCNT_SIG_CH1_IN2, ESP_NOSIG) + +#define PCNT2_CH1SIG_GPIO21 \ + ESP32_PINMUX(21, ESP_PCNT_SIG_CH1_IN2, ESP_NOSIG) + +#define PCNT2_CH1SIG_GPIO26 \ + ESP32_PINMUX(26, ESP_PCNT_SIG_CH1_IN2, ESP_NOSIG) + +#define PCNT2_CH1SIG_GPIO27 \ + ESP32_PINMUX(27, ESP_PCNT_SIG_CH1_IN2, ESP_NOSIG) + +#define PCNT2_CH1SIG_GPIO28 \ + ESP32_PINMUX(28, ESP_PCNT_SIG_CH1_IN2, ESP_NOSIG) + +#define PCNT2_CH1SIG_GPIO29 \ + ESP32_PINMUX(29, ESP_PCNT_SIG_CH1_IN2, ESP_NOSIG) + +#define PCNT2_CH1SIG_GPIO30 \ + ESP32_PINMUX(30, ESP_PCNT_SIG_CH1_IN2, ESP_NOSIG) + +#define PCNT2_CH1SIG_GPIO31 \ + ESP32_PINMUX(31, ESP_PCNT_SIG_CH1_IN2, ESP_NOSIG) + +#define PCNT2_CH1SIG_GPIO32 \ + ESP32_PINMUX(32, ESP_PCNT_SIG_CH1_IN2, ESP_NOSIG) + +#define PCNT2_CH1SIG_GPIO33 \ + ESP32_PINMUX(33, ESP_PCNT_SIG_CH1_IN2, ESP_NOSIG) + +#define PCNT2_CH1SIG_GPIO34 \ + ESP32_PINMUX(34, ESP_PCNT_SIG_CH1_IN2, ESP_NOSIG) + +#define PCNT2_CH1SIG_GPIO35 \ + ESP32_PINMUX(35, ESP_PCNT_SIG_CH1_IN2, ESP_NOSIG) + +#define PCNT2_CH1SIG_GPIO36 \ + ESP32_PINMUX(36, ESP_PCNT_SIG_CH1_IN2, ESP_NOSIG) + +#define PCNT2_CH1SIG_GPIO37 \ + ESP32_PINMUX(37, ESP_PCNT_SIG_CH1_IN2, ESP_NOSIG) + +#define PCNT2_CH1SIG_GPIO38 \ + ESP32_PINMUX(38, ESP_PCNT_SIG_CH1_IN2, ESP_NOSIG) + +#define PCNT2_CH1SIG_GPIO39 \ + ESP32_PINMUX(39, ESP_PCNT_SIG_CH1_IN2, ESP_NOSIG) + +#define PCNT2_CH1SIG_GPIO40 \ + ESP32_PINMUX(40, ESP_PCNT_SIG_CH1_IN2, ESP_NOSIG) + +#define PCNT2_CH1SIG_GPIO41 \ + ESP32_PINMUX(41, ESP_PCNT_SIG_CH1_IN2, ESP_NOSIG) + +#define PCNT2_CH1SIG_GPIO42 \ + ESP32_PINMUX(42, ESP_PCNT_SIG_CH1_IN2, ESP_NOSIG) + +#define PCNT2_CH1SIG_GPIO43 \ + ESP32_PINMUX(43, ESP_PCNT_SIG_CH1_IN2, ESP_NOSIG) + +#define PCNT2_CH1SIG_GPIO44 \ + ESP32_PINMUX(44, ESP_PCNT_SIG_CH1_IN2, ESP_NOSIG) + +#define PCNT2_CH1SIG_GPIO45 \ + ESP32_PINMUX(45, ESP_PCNT_SIG_CH1_IN2, ESP_NOSIG) + +#define PCNT2_CH1SIG_GPIO46 \ + ESP32_PINMUX(46, ESP_PCNT_SIG_CH1_IN2, ESP_NOSIG) + +/* PCNT3_CH0CTRL */ +#define PCNT3_CH0CTRL_GPIO0 \ + ESP32_PINMUX(0, ESP_PCNT_CTRL_CH0_IN3, ESP_NOSIG) + +#define PCNT3_CH0CTRL_GPIO1 \ + ESP32_PINMUX(1, ESP_PCNT_CTRL_CH0_IN3, ESP_NOSIG) + +#define PCNT3_CH0CTRL_GPIO2 \ + ESP32_PINMUX(2, ESP_PCNT_CTRL_CH0_IN3, ESP_NOSIG) + +#define PCNT3_CH0CTRL_GPIO3 \ + ESP32_PINMUX(3, ESP_PCNT_CTRL_CH0_IN3, ESP_NOSIG) + +#define PCNT3_CH0CTRL_GPIO4 \ + ESP32_PINMUX(4, ESP_PCNT_CTRL_CH0_IN3, ESP_NOSIG) + +#define PCNT3_CH0CTRL_GPIO5 \ + ESP32_PINMUX(5, ESP_PCNT_CTRL_CH0_IN3, ESP_NOSIG) + +#define PCNT3_CH0CTRL_GPIO6 \ + ESP32_PINMUX(6, ESP_PCNT_CTRL_CH0_IN3, ESP_NOSIG) + +#define PCNT3_CH0CTRL_GPIO7 \ + ESP32_PINMUX(7, ESP_PCNT_CTRL_CH0_IN3, ESP_NOSIG) + +#define PCNT3_CH0CTRL_GPIO8 \ + ESP32_PINMUX(8, ESP_PCNT_CTRL_CH0_IN3, ESP_NOSIG) + +#define PCNT3_CH0CTRL_GPIO9 \ + ESP32_PINMUX(9, ESP_PCNT_CTRL_CH0_IN3, ESP_NOSIG) + +#define PCNT3_CH0CTRL_GPIO10 \ + ESP32_PINMUX(10, ESP_PCNT_CTRL_CH0_IN3, ESP_NOSIG) + +#define PCNT3_CH0CTRL_GPIO11 \ + ESP32_PINMUX(11, ESP_PCNT_CTRL_CH0_IN3, ESP_NOSIG) + +#define PCNT3_CH0CTRL_GPIO12 \ + ESP32_PINMUX(12, ESP_PCNT_CTRL_CH0_IN3, ESP_NOSIG) + +#define PCNT3_CH0CTRL_GPIO13 \ + ESP32_PINMUX(13, ESP_PCNT_CTRL_CH0_IN3, ESP_NOSIG) + +#define PCNT3_CH0CTRL_GPIO14 \ + ESP32_PINMUX(14, ESP_PCNT_CTRL_CH0_IN3, ESP_NOSIG) + +#define PCNT3_CH0CTRL_GPIO15 \ + ESP32_PINMUX(15, ESP_PCNT_CTRL_CH0_IN3, ESP_NOSIG) + +#define PCNT3_CH0CTRL_GPIO16 \ + ESP32_PINMUX(16, ESP_PCNT_CTRL_CH0_IN3, ESP_NOSIG) + +#define PCNT3_CH0CTRL_GPIO17 \ + ESP32_PINMUX(17, ESP_PCNT_CTRL_CH0_IN3, ESP_NOSIG) + +#define PCNT3_CH0CTRL_GPIO18 \ + ESP32_PINMUX(18, ESP_PCNT_CTRL_CH0_IN3, ESP_NOSIG) + +#define PCNT3_CH0CTRL_GPIO19 \ + ESP32_PINMUX(19, ESP_PCNT_CTRL_CH0_IN3, ESP_NOSIG) + +#define PCNT3_CH0CTRL_GPIO20 \ + ESP32_PINMUX(20, ESP_PCNT_CTRL_CH0_IN3, ESP_NOSIG) + +#define PCNT3_CH0CTRL_GPIO21 \ + ESP32_PINMUX(21, ESP_PCNT_CTRL_CH0_IN3, ESP_NOSIG) + +#define PCNT3_CH0CTRL_GPIO26 \ + ESP32_PINMUX(26, ESP_PCNT_CTRL_CH0_IN3, ESP_NOSIG) + +#define PCNT3_CH0CTRL_GPIO27 \ + ESP32_PINMUX(27, ESP_PCNT_CTRL_CH0_IN3, ESP_NOSIG) + +#define PCNT3_CH0CTRL_GPIO28 \ + ESP32_PINMUX(28, ESP_PCNT_CTRL_CH0_IN3, ESP_NOSIG) + +#define PCNT3_CH0CTRL_GPIO29 \ + ESP32_PINMUX(29, ESP_PCNT_CTRL_CH0_IN3, ESP_NOSIG) + +#define PCNT3_CH0CTRL_GPIO30 \ + ESP32_PINMUX(30, ESP_PCNT_CTRL_CH0_IN3, ESP_NOSIG) + +#define PCNT3_CH0CTRL_GPIO31 \ + ESP32_PINMUX(31, ESP_PCNT_CTRL_CH0_IN3, ESP_NOSIG) + +#define PCNT3_CH0CTRL_GPIO32 \ + ESP32_PINMUX(32, ESP_PCNT_CTRL_CH0_IN3, ESP_NOSIG) + +#define PCNT3_CH0CTRL_GPIO33 \ + ESP32_PINMUX(33, ESP_PCNT_CTRL_CH0_IN3, ESP_NOSIG) + +#define PCNT3_CH0CTRL_GPIO34 \ + ESP32_PINMUX(34, ESP_PCNT_CTRL_CH0_IN3, ESP_NOSIG) + +#define PCNT3_CH0CTRL_GPIO35 \ + ESP32_PINMUX(35, ESP_PCNT_CTRL_CH0_IN3, ESP_NOSIG) + +#define PCNT3_CH0CTRL_GPIO36 \ + ESP32_PINMUX(36, ESP_PCNT_CTRL_CH0_IN3, ESP_NOSIG) + +#define PCNT3_CH0CTRL_GPIO37 \ + ESP32_PINMUX(37, ESP_PCNT_CTRL_CH0_IN3, ESP_NOSIG) + +#define PCNT3_CH0CTRL_GPIO38 \ + ESP32_PINMUX(38, ESP_PCNT_CTRL_CH0_IN3, ESP_NOSIG) + +#define PCNT3_CH0CTRL_GPIO39 \ + ESP32_PINMUX(39, ESP_PCNT_CTRL_CH0_IN3, ESP_NOSIG) + +#define PCNT3_CH0CTRL_GPIO40 \ + ESP32_PINMUX(40, ESP_PCNT_CTRL_CH0_IN3, ESP_NOSIG) + +#define PCNT3_CH0CTRL_GPIO41 \ + ESP32_PINMUX(41, ESP_PCNT_CTRL_CH0_IN3, ESP_NOSIG) + +#define PCNT3_CH0CTRL_GPIO42 \ + ESP32_PINMUX(42, ESP_PCNT_CTRL_CH0_IN3, ESP_NOSIG) + +#define PCNT3_CH0CTRL_GPIO43 \ + ESP32_PINMUX(43, ESP_PCNT_CTRL_CH0_IN3, ESP_NOSIG) + +#define PCNT3_CH0CTRL_GPIO44 \ + ESP32_PINMUX(44, ESP_PCNT_CTRL_CH0_IN3, ESP_NOSIG) + +#define PCNT3_CH0CTRL_GPIO45 \ + ESP32_PINMUX(45, ESP_PCNT_CTRL_CH0_IN3, ESP_NOSIG) + +#define PCNT3_CH0CTRL_GPIO46 \ + ESP32_PINMUX(46, ESP_PCNT_CTRL_CH0_IN3, ESP_NOSIG) + +/* PCNT3_CH0SIG */ +#define PCNT3_CH0SIG_GPIO0 \ + ESP32_PINMUX(0, ESP_PCNT_SIG_CH0_IN3, ESP_NOSIG) + +#define PCNT3_CH0SIG_GPIO1 \ + ESP32_PINMUX(1, ESP_PCNT_SIG_CH0_IN3, ESP_NOSIG) + +#define PCNT3_CH0SIG_GPIO2 \ + ESP32_PINMUX(2, ESP_PCNT_SIG_CH0_IN3, ESP_NOSIG) + +#define PCNT3_CH0SIG_GPIO3 \ + ESP32_PINMUX(3, ESP_PCNT_SIG_CH0_IN3, ESP_NOSIG) + +#define PCNT3_CH0SIG_GPIO4 \ + ESP32_PINMUX(4, ESP_PCNT_SIG_CH0_IN3, ESP_NOSIG) + +#define PCNT3_CH0SIG_GPIO5 \ + ESP32_PINMUX(5, ESP_PCNT_SIG_CH0_IN3, ESP_NOSIG) + +#define PCNT3_CH0SIG_GPIO6 \ + ESP32_PINMUX(6, ESP_PCNT_SIG_CH0_IN3, ESP_NOSIG) + +#define PCNT3_CH0SIG_GPIO7 \ + ESP32_PINMUX(7, ESP_PCNT_SIG_CH0_IN3, ESP_NOSIG) + +#define PCNT3_CH0SIG_GPIO8 \ + ESP32_PINMUX(8, ESP_PCNT_SIG_CH0_IN3, ESP_NOSIG) + +#define PCNT3_CH0SIG_GPIO9 \ + ESP32_PINMUX(9, ESP_PCNT_SIG_CH0_IN3, ESP_NOSIG) + +#define PCNT3_CH0SIG_GPIO10 \ + ESP32_PINMUX(10, ESP_PCNT_SIG_CH0_IN3, ESP_NOSIG) + +#define PCNT3_CH0SIG_GPIO11 \ + ESP32_PINMUX(11, ESP_PCNT_SIG_CH0_IN3, ESP_NOSIG) + +#define PCNT3_CH0SIG_GPIO12 \ + ESP32_PINMUX(12, ESP_PCNT_SIG_CH0_IN3, ESP_NOSIG) + +#define PCNT3_CH0SIG_GPIO13 \ + ESP32_PINMUX(13, ESP_PCNT_SIG_CH0_IN3, ESP_NOSIG) + +#define PCNT3_CH0SIG_GPIO14 \ + ESP32_PINMUX(14, ESP_PCNT_SIG_CH0_IN3, ESP_NOSIG) + +#define PCNT3_CH0SIG_GPIO15 \ + ESP32_PINMUX(15, ESP_PCNT_SIG_CH0_IN3, ESP_NOSIG) + +#define PCNT3_CH0SIG_GPIO16 \ + ESP32_PINMUX(16, ESP_PCNT_SIG_CH0_IN3, ESP_NOSIG) + +#define PCNT3_CH0SIG_GPIO17 \ + ESP32_PINMUX(17, ESP_PCNT_SIG_CH0_IN3, ESP_NOSIG) + +#define PCNT3_CH0SIG_GPIO18 \ + ESP32_PINMUX(18, ESP_PCNT_SIG_CH0_IN3, ESP_NOSIG) + +#define PCNT3_CH0SIG_GPIO19 \ + ESP32_PINMUX(19, ESP_PCNT_SIG_CH0_IN3, ESP_NOSIG) + +#define PCNT3_CH0SIG_GPIO20 \ + ESP32_PINMUX(20, ESP_PCNT_SIG_CH0_IN3, ESP_NOSIG) + +#define PCNT3_CH0SIG_GPIO21 \ + ESP32_PINMUX(21, ESP_PCNT_SIG_CH0_IN3, ESP_NOSIG) + +#define PCNT3_CH0SIG_GPIO26 \ + ESP32_PINMUX(26, ESP_PCNT_SIG_CH0_IN3, ESP_NOSIG) + +#define PCNT3_CH0SIG_GPIO27 \ + ESP32_PINMUX(27, ESP_PCNT_SIG_CH0_IN3, ESP_NOSIG) + +#define PCNT3_CH0SIG_GPIO28 \ + ESP32_PINMUX(28, ESP_PCNT_SIG_CH0_IN3, ESP_NOSIG) + +#define PCNT3_CH0SIG_GPIO29 \ + ESP32_PINMUX(29, ESP_PCNT_SIG_CH0_IN3, ESP_NOSIG) + +#define PCNT3_CH0SIG_GPIO30 \ + ESP32_PINMUX(30, ESP_PCNT_SIG_CH0_IN3, ESP_NOSIG) + +#define PCNT3_CH0SIG_GPIO31 \ + ESP32_PINMUX(31, ESP_PCNT_SIG_CH0_IN3, ESP_NOSIG) + +#define PCNT3_CH0SIG_GPIO32 \ + ESP32_PINMUX(32, ESP_PCNT_SIG_CH0_IN3, ESP_NOSIG) + +#define PCNT3_CH0SIG_GPIO33 \ + ESP32_PINMUX(33, ESP_PCNT_SIG_CH0_IN3, ESP_NOSIG) + +#define PCNT3_CH0SIG_GPIO34 \ + ESP32_PINMUX(34, ESP_PCNT_SIG_CH0_IN3, ESP_NOSIG) + +#define PCNT3_CH0SIG_GPIO35 \ + ESP32_PINMUX(35, ESP_PCNT_SIG_CH0_IN3, ESP_NOSIG) + +#define PCNT3_CH0SIG_GPIO36 \ + ESP32_PINMUX(36, ESP_PCNT_SIG_CH0_IN3, ESP_NOSIG) + +#define PCNT3_CH0SIG_GPIO37 \ + ESP32_PINMUX(37, ESP_PCNT_SIG_CH0_IN3, ESP_NOSIG) + +#define PCNT3_CH0SIG_GPIO38 \ + ESP32_PINMUX(38, ESP_PCNT_SIG_CH0_IN3, ESP_NOSIG) + +#define PCNT3_CH0SIG_GPIO39 \ + ESP32_PINMUX(39, ESP_PCNT_SIG_CH0_IN3, ESP_NOSIG) + +#define PCNT3_CH0SIG_GPIO40 \ + ESP32_PINMUX(40, ESP_PCNT_SIG_CH0_IN3, ESP_NOSIG) + +#define PCNT3_CH0SIG_GPIO41 \ + ESP32_PINMUX(41, ESP_PCNT_SIG_CH0_IN3, ESP_NOSIG) + +#define PCNT3_CH0SIG_GPIO42 \ + ESP32_PINMUX(42, ESP_PCNT_SIG_CH0_IN3, ESP_NOSIG) + +#define PCNT3_CH0SIG_GPIO43 \ + ESP32_PINMUX(43, ESP_PCNT_SIG_CH0_IN3, ESP_NOSIG) + +#define PCNT3_CH0SIG_GPIO44 \ + ESP32_PINMUX(44, ESP_PCNT_SIG_CH0_IN3, ESP_NOSIG) + +#define PCNT3_CH0SIG_GPIO45 \ + ESP32_PINMUX(45, ESP_PCNT_SIG_CH0_IN3, ESP_NOSIG) + +#define PCNT3_CH0SIG_GPIO46 \ + ESP32_PINMUX(46, ESP_PCNT_SIG_CH0_IN3, ESP_NOSIG) + +/* PCNT3_CH1CTRL */ +#define PCNT3_CH1CTRL_GPIO0 \ + ESP32_PINMUX(0, ESP_PCNT_CTRL_CH1_IN3, ESP_NOSIG) + +#define PCNT3_CH1CTRL_GPIO1 \ + ESP32_PINMUX(1, ESP_PCNT_CTRL_CH1_IN3, ESP_NOSIG) + +#define PCNT3_CH1CTRL_GPIO2 \ + ESP32_PINMUX(2, ESP_PCNT_CTRL_CH1_IN3, ESP_NOSIG) + +#define PCNT3_CH1CTRL_GPIO3 \ + ESP32_PINMUX(3, ESP_PCNT_CTRL_CH1_IN3, ESP_NOSIG) + +#define PCNT3_CH1CTRL_GPIO4 \ + ESP32_PINMUX(4, ESP_PCNT_CTRL_CH1_IN3, ESP_NOSIG) + +#define PCNT3_CH1CTRL_GPIO5 \ + ESP32_PINMUX(5, ESP_PCNT_CTRL_CH1_IN3, ESP_NOSIG) + +#define PCNT3_CH1CTRL_GPIO6 \ + ESP32_PINMUX(6, ESP_PCNT_CTRL_CH1_IN3, ESP_NOSIG) + +#define PCNT3_CH1CTRL_GPIO7 \ + ESP32_PINMUX(7, ESP_PCNT_CTRL_CH1_IN3, ESP_NOSIG) + +#define PCNT3_CH1CTRL_GPIO8 \ + ESP32_PINMUX(8, ESP_PCNT_CTRL_CH1_IN3, ESP_NOSIG) + +#define PCNT3_CH1CTRL_GPIO9 \ + ESP32_PINMUX(9, ESP_PCNT_CTRL_CH1_IN3, ESP_NOSIG) + +#define PCNT3_CH1CTRL_GPIO10 \ + ESP32_PINMUX(10, ESP_PCNT_CTRL_CH1_IN3, ESP_NOSIG) + +#define PCNT3_CH1CTRL_GPIO11 \ + ESP32_PINMUX(11, ESP_PCNT_CTRL_CH1_IN3, ESP_NOSIG) + +#define PCNT3_CH1CTRL_GPIO12 \ + ESP32_PINMUX(12, ESP_PCNT_CTRL_CH1_IN3, ESP_NOSIG) + +#define PCNT3_CH1CTRL_GPIO13 \ + ESP32_PINMUX(13, ESP_PCNT_CTRL_CH1_IN3, ESP_NOSIG) + +#define PCNT3_CH1CTRL_GPIO14 \ + ESP32_PINMUX(14, ESP_PCNT_CTRL_CH1_IN3, ESP_NOSIG) + +#define PCNT3_CH1CTRL_GPIO15 \ + ESP32_PINMUX(15, ESP_PCNT_CTRL_CH1_IN3, ESP_NOSIG) + +#define PCNT3_CH1CTRL_GPIO16 \ + ESP32_PINMUX(16, ESP_PCNT_CTRL_CH1_IN3, ESP_NOSIG) + +#define PCNT3_CH1CTRL_GPIO17 \ + ESP32_PINMUX(17, ESP_PCNT_CTRL_CH1_IN3, ESP_NOSIG) + +#define PCNT3_CH1CTRL_GPIO18 \ + ESP32_PINMUX(18, ESP_PCNT_CTRL_CH1_IN3, ESP_NOSIG) + +#define PCNT3_CH1CTRL_GPIO19 \ + ESP32_PINMUX(19, ESP_PCNT_CTRL_CH1_IN3, ESP_NOSIG) + +#define PCNT3_CH1CTRL_GPIO20 \ + ESP32_PINMUX(20, ESP_PCNT_CTRL_CH1_IN3, ESP_NOSIG) + +#define PCNT3_CH1CTRL_GPIO21 \ + ESP32_PINMUX(21, ESP_PCNT_CTRL_CH1_IN3, ESP_NOSIG) + +#define PCNT3_CH1CTRL_GPIO26 \ + ESP32_PINMUX(26, ESP_PCNT_CTRL_CH1_IN3, ESP_NOSIG) + +#define PCNT3_CH1CTRL_GPIO27 \ + ESP32_PINMUX(27, ESP_PCNT_CTRL_CH1_IN3, ESP_NOSIG) + +#define PCNT3_CH1CTRL_GPIO28 \ + ESP32_PINMUX(28, ESP_PCNT_CTRL_CH1_IN3, ESP_NOSIG) + +#define PCNT3_CH1CTRL_GPIO29 \ + ESP32_PINMUX(29, ESP_PCNT_CTRL_CH1_IN3, ESP_NOSIG) + +#define PCNT3_CH1CTRL_GPIO30 \ + ESP32_PINMUX(30, ESP_PCNT_CTRL_CH1_IN3, ESP_NOSIG) + +#define PCNT3_CH1CTRL_GPIO31 \ + ESP32_PINMUX(31, ESP_PCNT_CTRL_CH1_IN3, ESP_NOSIG) + +#define PCNT3_CH1CTRL_GPIO32 \ + ESP32_PINMUX(32, ESP_PCNT_CTRL_CH1_IN3, ESP_NOSIG) + +#define PCNT3_CH1CTRL_GPIO33 \ + ESP32_PINMUX(33, ESP_PCNT_CTRL_CH1_IN3, ESP_NOSIG) + +#define PCNT3_CH1CTRL_GPIO34 \ + ESP32_PINMUX(34, ESP_PCNT_CTRL_CH1_IN3, ESP_NOSIG) + +#define PCNT3_CH1CTRL_GPIO35 \ + ESP32_PINMUX(35, ESP_PCNT_CTRL_CH1_IN3, ESP_NOSIG) + +#define PCNT3_CH1CTRL_GPIO36 \ + ESP32_PINMUX(36, ESP_PCNT_CTRL_CH1_IN3, ESP_NOSIG) + +#define PCNT3_CH1CTRL_GPIO37 \ + ESP32_PINMUX(37, ESP_PCNT_CTRL_CH1_IN3, ESP_NOSIG) + +#define PCNT3_CH1CTRL_GPIO38 \ + ESP32_PINMUX(38, ESP_PCNT_CTRL_CH1_IN3, ESP_NOSIG) + +#define PCNT3_CH1CTRL_GPIO39 \ + ESP32_PINMUX(39, ESP_PCNT_CTRL_CH1_IN3, ESP_NOSIG) + +#define PCNT3_CH1CTRL_GPIO40 \ + ESP32_PINMUX(40, ESP_PCNT_CTRL_CH1_IN3, ESP_NOSIG) + +#define PCNT3_CH1CTRL_GPIO41 \ + ESP32_PINMUX(41, ESP_PCNT_CTRL_CH1_IN3, ESP_NOSIG) + +#define PCNT3_CH1CTRL_GPIO42 \ + ESP32_PINMUX(42, ESP_PCNT_CTRL_CH1_IN3, ESP_NOSIG) + +#define PCNT3_CH1CTRL_GPIO43 \ + ESP32_PINMUX(43, ESP_PCNT_CTRL_CH1_IN3, ESP_NOSIG) + +#define PCNT3_CH1CTRL_GPIO44 \ + ESP32_PINMUX(44, ESP_PCNT_CTRL_CH1_IN3, ESP_NOSIG) + +#define PCNT3_CH1CTRL_GPIO45 \ + ESP32_PINMUX(45, ESP_PCNT_CTRL_CH1_IN3, ESP_NOSIG) + +#define PCNT3_CH1CTRL_GPIO46 \ + ESP32_PINMUX(46, ESP_PCNT_CTRL_CH1_IN3, ESP_NOSIG) + +/* PCNT3_CH1SIG */ +#define PCNT3_CH1SIG_GPIO0 \ + ESP32_PINMUX(0, ESP_PCNT_SIG_CH1_IN3, ESP_NOSIG) + +#define PCNT3_CH1SIG_GPIO1 \ + ESP32_PINMUX(1, ESP_PCNT_SIG_CH1_IN3, ESP_NOSIG) + +#define PCNT3_CH1SIG_GPIO2 \ + ESP32_PINMUX(2, ESP_PCNT_SIG_CH1_IN3, ESP_NOSIG) + +#define PCNT3_CH1SIG_GPIO3 \ + ESP32_PINMUX(3, ESP_PCNT_SIG_CH1_IN3, ESP_NOSIG) + +#define PCNT3_CH1SIG_GPIO4 \ + ESP32_PINMUX(4, ESP_PCNT_SIG_CH1_IN3, ESP_NOSIG) + +#define PCNT3_CH1SIG_GPIO5 \ + ESP32_PINMUX(5, ESP_PCNT_SIG_CH1_IN3, ESP_NOSIG) + +#define PCNT3_CH1SIG_GPIO6 \ + ESP32_PINMUX(6, ESP_PCNT_SIG_CH1_IN3, ESP_NOSIG) + +#define PCNT3_CH1SIG_GPIO7 \ + ESP32_PINMUX(7, ESP_PCNT_SIG_CH1_IN3, ESP_NOSIG) + +#define PCNT3_CH1SIG_GPIO8 \ + ESP32_PINMUX(8, ESP_PCNT_SIG_CH1_IN3, ESP_NOSIG) + +#define PCNT3_CH1SIG_GPIO9 \ + ESP32_PINMUX(9, ESP_PCNT_SIG_CH1_IN3, ESP_NOSIG) + +#define PCNT3_CH1SIG_GPIO10 \ + ESP32_PINMUX(10, ESP_PCNT_SIG_CH1_IN3, ESP_NOSIG) + +#define PCNT3_CH1SIG_GPIO11 \ + ESP32_PINMUX(11, ESP_PCNT_SIG_CH1_IN3, ESP_NOSIG) + +#define PCNT3_CH1SIG_GPIO12 \ + ESP32_PINMUX(12, ESP_PCNT_SIG_CH1_IN3, ESP_NOSIG) + +#define PCNT3_CH1SIG_GPIO13 \ + ESP32_PINMUX(13, ESP_PCNT_SIG_CH1_IN3, ESP_NOSIG) + +#define PCNT3_CH1SIG_GPIO14 \ + ESP32_PINMUX(14, ESP_PCNT_SIG_CH1_IN3, ESP_NOSIG) + +#define PCNT3_CH1SIG_GPIO15 \ + ESP32_PINMUX(15, ESP_PCNT_SIG_CH1_IN3, ESP_NOSIG) + +#define PCNT3_CH1SIG_GPIO16 \ + ESP32_PINMUX(16, ESP_PCNT_SIG_CH1_IN3, ESP_NOSIG) + +#define PCNT3_CH1SIG_GPIO17 \ + ESP32_PINMUX(17, ESP_PCNT_SIG_CH1_IN3, ESP_NOSIG) + +#define PCNT3_CH1SIG_GPIO18 \ + ESP32_PINMUX(18, ESP_PCNT_SIG_CH1_IN3, ESP_NOSIG) + +#define PCNT3_CH1SIG_GPIO19 \ + ESP32_PINMUX(19, ESP_PCNT_SIG_CH1_IN3, ESP_NOSIG) + +#define PCNT3_CH1SIG_GPIO20 \ + ESP32_PINMUX(20, ESP_PCNT_SIG_CH1_IN3, ESP_NOSIG) + +#define PCNT3_CH1SIG_GPIO21 \ + ESP32_PINMUX(21, ESP_PCNT_SIG_CH1_IN3, ESP_NOSIG) + +#define PCNT3_CH1SIG_GPIO26 \ + ESP32_PINMUX(26, ESP_PCNT_SIG_CH1_IN3, ESP_NOSIG) + +#define PCNT3_CH1SIG_GPIO27 \ + ESP32_PINMUX(27, ESP_PCNT_SIG_CH1_IN3, ESP_NOSIG) + +#define PCNT3_CH1SIG_GPIO28 \ + ESP32_PINMUX(28, ESP_PCNT_SIG_CH1_IN3, ESP_NOSIG) + +#define PCNT3_CH1SIG_GPIO29 \ + ESP32_PINMUX(29, ESP_PCNT_SIG_CH1_IN3, ESP_NOSIG) + +#define PCNT3_CH1SIG_GPIO30 \ + ESP32_PINMUX(30, ESP_PCNT_SIG_CH1_IN3, ESP_NOSIG) + +#define PCNT3_CH1SIG_GPIO31 \ + ESP32_PINMUX(31, ESP_PCNT_SIG_CH1_IN3, ESP_NOSIG) + +#define PCNT3_CH1SIG_GPIO32 \ + ESP32_PINMUX(32, ESP_PCNT_SIG_CH1_IN3, ESP_NOSIG) + +#define PCNT3_CH1SIG_GPIO33 \ + ESP32_PINMUX(33, ESP_PCNT_SIG_CH1_IN3, ESP_NOSIG) + +#define PCNT3_CH1SIG_GPIO34 \ + ESP32_PINMUX(34, ESP_PCNT_SIG_CH1_IN3, ESP_NOSIG) + +#define PCNT3_CH1SIG_GPIO35 \ + ESP32_PINMUX(35, ESP_PCNT_SIG_CH1_IN3, ESP_NOSIG) + +#define PCNT3_CH1SIG_GPIO36 \ + ESP32_PINMUX(36, ESP_PCNT_SIG_CH1_IN3, ESP_NOSIG) + +#define PCNT3_CH1SIG_GPIO37 \ + ESP32_PINMUX(37, ESP_PCNT_SIG_CH1_IN3, ESP_NOSIG) + +#define PCNT3_CH1SIG_GPIO38 \ + ESP32_PINMUX(38, ESP_PCNT_SIG_CH1_IN3, ESP_NOSIG) + +#define PCNT3_CH1SIG_GPIO39 \ + ESP32_PINMUX(39, ESP_PCNT_SIG_CH1_IN3, ESP_NOSIG) + +#define PCNT3_CH1SIG_GPIO40 \ + ESP32_PINMUX(40, ESP_PCNT_SIG_CH1_IN3, ESP_NOSIG) + +#define PCNT3_CH1SIG_GPIO41 \ + ESP32_PINMUX(41, ESP_PCNT_SIG_CH1_IN3, ESP_NOSIG) + +#define PCNT3_CH1SIG_GPIO42 \ + ESP32_PINMUX(42, ESP_PCNT_SIG_CH1_IN3, ESP_NOSIG) + +#define PCNT3_CH1SIG_GPIO43 \ + ESP32_PINMUX(43, ESP_PCNT_SIG_CH1_IN3, ESP_NOSIG) + +#define PCNT3_CH1SIG_GPIO44 \ + ESP32_PINMUX(44, ESP_PCNT_SIG_CH1_IN3, ESP_NOSIG) + +#define PCNT3_CH1SIG_GPIO45 \ + ESP32_PINMUX(45, ESP_PCNT_SIG_CH1_IN3, ESP_NOSIG) + +#define PCNT3_CH1SIG_GPIO46 \ + ESP32_PINMUX(46, ESP_PCNT_SIG_CH1_IN3, ESP_NOSIG) + +/* SPIM2_CSEL */ +#define SPIM2_CSEL_GPIO0 \ + ESP32_PINMUX(0, ESP_NOSIG, ESP_FSPICS0_OUT) + +#define SPIM2_CSEL_GPIO1 \ + ESP32_PINMUX(1, ESP_NOSIG, ESP_FSPICS0_OUT) + +#define SPIM2_CSEL_GPIO2 \ + ESP32_PINMUX(2, ESP_NOSIG, ESP_FSPICS0_OUT) + +#define SPIM2_CSEL_GPIO3 \ + ESP32_PINMUX(3, ESP_NOSIG, ESP_FSPICS0_OUT) + +#define SPIM2_CSEL_GPIO4 \ + ESP32_PINMUX(4, ESP_NOSIG, ESP_FSPICS0_OUT) + +#define SPIM2_CSEL_GPIO5 \ + ESP32_PINMUX(5, ESP_NOSIG, ESP_FSPICS0_OUT) + +#define SPIM2_CSEL_GPIO6 \ + ESP32_PINMUX(6, ESP_NOSIG, ESP_FSPICS0_OUT) + +#define SPIM2_CSEL_GPIO7 \ + ESP32_PINMUX(7, ESP_NOSIG, ESP_FSPICS0_OUT) + +#define SPIM2_CSEL_GPIO8 \ + ESP32_PINMUX(8, ESP_NOSIG, ESP_FSPICS0_OUT) + +#define SPIM2_CSEL_GPIO9 \ + ESP32_PINMUX(9, ESP_NOSIG, ESP_FSPICS0_OUT) + +#define SPIM2_CSEL_GPIO10 \ + ESP32_PINMUX(10, ESP_NOSIG, ESP_FSPICS0_OUT) + +#define SPIM2_CSEL_GPIO11 \ + ESP32_PINMUX(11, ESP_NOSIG, ESP_FSPICS0_OUT) + +#define SPIM2_CSEL_GPIO12 \ + ESP32_PINMUX(12, ESP_NOSIG, ESP_FSPICS0_OUT) + +#define SPIM2_CSEL_GPIO13 \ + ESP32_PINMUX(13, ESP_NOSIG, ESP_FSPICS0_OUT) + +#define SPIM2_CSEL_GPIO14 \ + ESP32_PINMUX(14, ESP_NOSIG, ESP_FSPICS0_OUT) + +#define SPIM2_CSEL_GPIO15 \ + ESP32_PINMUX(15, ESP_NOSIG, ESP_FSPICS0_OUT) + +#define SPIM2_CSEL_GPIO16 \ + ESP32_PINMUX(16, ESP_NOSIG, ESP_FSPICS0_OUT) + +#define SPIM2_CSEL_GPIO17 \ + ESP32_PINMUX(17, ESP_NOSIG, ESP_FSPICS0_OUT) + +#define SPIM2_CSEL_GPIO18 \ + ESP32_PINMUX(18, ESP_NOSIG, ESP_FSPICS0_OUT) + +#define SPIM2_CSEL_GPIO19 \ + ESP32_PINMUX(19, ESP_NOSIG, ESP_FSPICS0_OUT) + +#define SPIM2_CSEL_GPIO20 \ + ESP32_PINMUX(20, ESP_NOSIG, ESP_FSPICS0_OUT) + +#define SPIM2_CSEL_GPIO21 \ + ESP32_PINMUX(21, ESP_NOSIG, ESP_FSPICS0_OUT) + +#define SPIM2_CSEL_GPIO26 \ + ESP32_PINMUX(26, ESP_NOSIG, ESP_FSPICS0_OUT) + +#define SPIM2_CSEL_GPIO27 \ + ESP32_PINMUX(27, ESP_NOSIG, ESP_FSPICS0_OUT) + +#define SPIM2_CSEL_GPIO28 \ + ESP32_PINMUX(28, ESP_NOSIG, ESP_FSPICS0_OUT) + +#define SPIM2_CSEL_GPIO29 \ + ESP32_PINMUX(29, ESP_NOSIG, ESP_FSPICS0_OUT) + +#define SPIM2_CSEL_GPIO30 \ + ESP32_PINMUX(30, ESP_NOSIG, ESP_FSPICS0_OUT) + +#define SPIM2_CSEL_GPIO31 \ + ESP32_PINMUX(31, ESP_NOSIG, ESP_FSPICS0_OUT) + +#define SPIM2_CSEL_GPIO32 \ + ESP32_PINMUX(32, ESP_NOSIG, ESP_FSPICS0_OUT) + +#define SPIM2_CSEL_GPIO33 \ + ESP32_PINMUX(33, ESP_NOSIG, ESP_FSPICS0_OUT) + +#define SPIM2_CSEL_GPIO34 \ + ESP32_PINMUX(34, ESP_NOSIG, ESP_FSPICS0_OUT) + +#define SPIM2_CSEL_GPIO35 \ + ESP32_PINMUX(35, ESP_NOSIG, ESP_FSPICS0_OUT) + +#define SPIM2_CSEL_GPIO36 \ + ESP32_PINMUX(36, ESP_NOSIG, ESP_FSPICS0_OUT) + +#define SPIM2_CSEL_GPIO37 \ + ESP32_PINMUX(37, ESP_NOSIG, ESP_FSPICS0_OUT) + +#define SPIM2_CSEL_GPIO38 \ + ESP32_PINMUX(38, ESP_NOSIG, ESP_FSPICS0_OUT) + +#define SPIM2_CSEL_GPIO39 \ + ESP32_PINMUX(39, ESP_NOSIG, ESP_FSPICS0_OUT) + +#define SPIM2_CSEL_GPIO40 \ + ESP32_PINMUX(40, ESP_NOSIG, ESP_FSPICS0_OUT) + +#define SPIM2_CSEL_GPIO41 \ + ESP32_PINMUX(41, ESP_NOSIG, ESP_FSPICS0_OUT) + +#define SPIM2_CSEL_GPIO42 \ + ESP32_PINMUX(42, ESP_NOSIG, ESP_FSPICS0_OUT) + +#define SPIM2_CSEL_GPIO43 \ + ESP32_PINMUX(43, ESP_NOSIG, ESP_FSPICS0_OUT) + +#define SPIM2_CSEL_GPIO44 \ + ESP32_PINMUX(44, ESP_NOSIG, ESP_FSPICS0_OUT) + +#define SPIM2_CSEL_GPIO45 \ + ESP32_PINMUX(45, ESP_NOSIG, ESP_FSPICS0_OUT) + +/* SPIM2_CSEL1 */ +#define SPIM2_CSEL1_GPIO0 \ + ESP32_PINMUX(0, ESP_NOSIG, ESP_FSPICS1_OUT) + +#define SPIM2_CSEL1_GPIO1 \ + ESP32_PINMUX(1, ESP_NOSIG, ESP_FSPICS1_OUT) + +#define SPIM2_CSEL1_GPIO2 \ + ESP32_PINMUX(2, ESP_NOSIG, ESP_FSPICS1_OUT) + +#define SPIM2_CSEL1_GPIO3 \ + ESP32_PINMUX(3, ESP_NOSIG, ESP_FSPICS1_OUT) + +#define SPIM2_CSEL1_GPIO4 \ + ESP32_PINMUX(4, ESP_NOSIG, ESP_FSPICS1_OUT) + +#define SPIM2_CSEL1_GPIO5 \ + ESP32_PINMUX(5, ESP_NOSIG, ESP_FSPICS1_OUT) + +#define SPIM2_CSEL1_GPIO6 \ + ESP32_PINMUX(6, ESP_NOSIG, ESP_FSPICS1_OUT) + +#define SPIM2_CSEL1_GPIO7 \ + ESP32_PINMUX(7, ESP_NOSIG, ESP_FSPICS1_OUT) + +#define SPIM2_CSEL1_GPIO8 \ + ESP32_PINMUX(8, ESP_NOSIG, ESP_FSPICS1_OUT) + +#define SPIM2_CSEL1_GPIO9 \ + ESP32_PINMUX(9, ESP_NOSIG, ESP_FSPICS1_OUT) + +#define SPIM2_CSEL1_GPIO10 \ + ESP32_PINMUX(10, ESP_NOSIG, ESP_FSPICS1_OUT) + +#define SPIM2_CSEL1_GPIO11 \ + ESP32_PINMUX(11, ESP_NOSIG, ESP_FSPICS1_OUT) + +#define SPIM2_CSEL1_GPIO12 \ + ESP32_PINMUX(12, ESP_NOSIG, ESP_FSPICS1_OUT) + +#define SPIM2_CSEL1_GPIO13 \ + ESP32_PINMUX(13, ESP_NOSIG, ESP_FSPICS1_OUT) + +#define SPIM2_CSEL1_GPIO14 \ + ESP32_PINMUX(14, ESP_NOSIG, ESP_FSPICS1_OUT) + +#define SPIM2_CSEL1_GPIO15 \ + ESP32_PINMUX(15, ESP_NOSIG, ESP_FSPICS1_OUT) + +#define SPIM2_CSEL1_GPIO16 \ + ESP32_PINMUX(16, ESP_NOSIG, ESP_FSPICS1_OUT) + +#define SPIM2_CSEL1_GPIO17 \ + ESP32_PINMUX(17, ESP_NOSIG, ESP_FSPICS1_OUT) + +#define SPIM2_CSEL1_GPIO18 \ + ESP32_PINMUX(18, ESP_NOSIG, ESP_FSPICS1_OUT) + +#define SPIM2_CSEL1_GPIO19 \ + ESP32_PINMUX(19, ESP_NOSIG, ESP_FSPICS1_OUT) + +#define SPIM2_CSEL1_GPIO20 \ + ESP32_PINMUX(20, ESP_NOSIG, ESP_FSPICS1_OUT) + +#define SPIM2_CSEL1_GPIO21 \ + ESP32_PINMUX(21, ESP_NOSIG, ESP_FSPICS1_OUT) + +#define SPIM2_CSEL1_GPIO26 \ + ESP32_PINMUX(26, ESP_NOSIG, ESP_FSPICS1_OUT) + +#define SPIM2_CSEL1_GPIO27 \ + ESP32_PINMUX(27, ESP_NOSIG, ESP_FSPICS1_OUT) + +#define SPIM2_CSEL1_GPIO28 \ + ESP32_PINMUX(28, ESP_NOSIG, ESP_FSPICS1_OUT) + +#define SPIM2_CSEL1_GPIO29 \ + ESP32_PINMUX(29, ESP_NOSIG, ESP_FSPICS1_OUT) + +#define SPIM2_CSEL1_GPIO30 \ + ESP32_PINMUX(30, ESP_NOSIG, ESP_FSPICS1_OUT) + +#define SPIM2_CSEL1_GPIO31 \ + ESP32_PINMUX(31, ESP_NOSIG, ESP_FSPICS1_OUT) + +#define SPIM2_CSEL1_GPIO32 \ + ESP32_PINMUX(32, ESP_NOSIG, ESP_FSPICS1_OUT) + +#define SPIM2_CSEL1_GPIO33 \ + ESP32_PINMUX(33, ESP_NOSIG, ESP_FSPICS1_OUT) + +#define SPIM2_CSEL1_GPIO34 \ + ESP32_PINMUX(34, ESP_NOSIG, ESP_FSPICS1_OUT) + +#define SPIM2_CSEL1_GPIO35 \ + ESP32_PINMUX(35, ESP_NOSIG, ESP_FSPICS1_OUT) + +#define SPIM2_CSEL1_GPIO36 \ + ESP32_PINMUX(36, ESP_NOSIG, ESP_FSPICS1_OUT) + +#define SPIM2_CSEL1_GPIO37 \ + ESP32_PINMUX(37, ESP_NOSIG, ESP_FSPICS1_OUT) + +#define SPIM2_CSEL1_GPIO38 \ + ESP32_PINMUX(38, ESP_NOSIG, ESP_FSPICS1_OUT) + +#define SPIM2_CSEL1_GPIO39 \ + ESP32_PINMUX(39, ESP_NOSIG, ESP_FSPICS1_OUT) + +#define SPIM2_CSEL1_GPIO40 \ + ESP32_PINMUX(40, ESP_NOSIG, ESP_FSPICS1_OUT) + +#define SPIM2_CSEL1_GPIO41 \ + ESP32_PINMUX(41, ESP_NOSIG, ESP_FSPICS1_OUT) + +#define SPIM2_CSEL1_GPIO42 \ + ESP32_PINMUX(42, ESP_NOSIG, ESP_FSPICS1_OUT) + +#define SPIM2_CSEL1_GPIO43 \ + ESP32_PINMUX(43, ESP_NOSIG, ESP_FSPICS1_OUT) + +#define SPIM2_CSEL1_GPIO44 \ + ESP32_PINMUX(44, ESP_NOSIG, ESP_FSPICS1_OUT) + +#define SPIM2_CSEL1_GPIO45 \ + ESP32_PINMUX(45, ESP_NOSIG, ESP_FSPICS1_OUT) + +/* SPIM2_CSEL2 */ +#define SPIM2_CSEL2_GPIO0 \ + ESP32_PINMUX(0, ESP_NOSIG, ESP_FSPICS2_OUT) + +#define SPIM2_CSEL2_GPIO1 \ + ESP32_PINMUX(1, ESP_NOSIG, ESP_FSPICS2_OUT) + +#define SPIM2_CSEL2_GPIO2 \ + ESP32_PINMUX(2, ESP_NOSIG, ESP_FSPICS2_OUT) + +#define SPIM2_CSEL2_GPIO3 \ + ESP32_PINMUX(3, ESP_NOSIG, ESP_FSPICS2_OUT) + +#define SPIM2_CSEL2_GPIO4 \ + ESP32_PINMUX(4, ESP_NOSIG, ESP_FSPICS2_OUT) + +#define SPIM2_CSEL2_GPIO5 \ + ESP32_PINMUX(5, ESP_NOSIG, ESP_FSPICS2_OUT) + +#define SPIM2_CSEL2_GPIO6 \ + ESP32_PINMUX(6, ESP_NOSIG, ESP_FSPICS2_OUT) + +#define SPIM2_CSEL2_GPIO7 \ + ESP32_PINMUX(7, ESP_NOSIG, ESP_FSPICS2_OUT) + +#define SPIM2_CSEL2_GPIO8 \ + ESP32_PINMUX(8, ESP_NOSIG, ESP_FSPICS2_OUT) + +#define SPIM2_CSEL2_GPIO9 \ + ESP32_PINMUX(9, ESP_NOSIG, ESP_FSPICS2_OUT) + +#define SPIM2_CSEL2_GPIO10 \ + ESP32_PINMUX(10, ESP_NOSIG, ESP_FSPICS2_OUT) + +#define SPIM2_CSEL2_GPIO11 \ + ESP32_PINMUX(11, ESP_NOSIG, ESP_FSPICS2_OUT) + +#define SPIM2_CSEL2_GPIO12 \ + ESP32_PINMUX(12, ESP_NOSIG, ESP_FSPICS2_OUT) + +#define SPIM2_CSEL2_GPIO13 \ + ESP32_PINMUX(13, ESP_NOSIG, ESP_FSPICS2_OUT) + +#define SPIM2_CSEL2_GPIO14 \ + ESP32_PINMUX(14, ESP_NOSIG, ESP_FSPICS2_OUT) + +#define SPIM2_CSEL2_GPIO15 \ + ESP32_PINMUX(15, ESP_NOSIG, ESP_FSPICS2_OUT) + +#define SPIM2_CSEL2_GPIO16 \ + ESP32_PINMUX(16, ESP_NOSIG, ESP_FSPICS2_OUT) + +#define SPIM2_CSEL2_GPIO17 \ + ESP32_PINMUX(17, ESP_NOSIG, ESP_FSPICS2_OUT) + +#define SPIM2_CSEL2_GPIO18 \ + ESP32_PINMUX(18, ESP_NOSIG, ESP_FSPICS2_OUT) + +#define SPIM2_CSEL2_GPIO19 \ + ESP32_PINMUX(19, ESP_NOSIG, ESP_FSPICS2_OUT) + +#define SPIM2_CSEL2_GPIO20 \ + ESP32_PINMUX(20, ESP_NOSIG, ESP_FSPICS2_OUT) + +#define SPIM2_CSEL2_GPIO21 \ + ESP32_PINMUX(21, ESP_NOSIG, ESP_FSPICS2_OUT) + +#define SPIM2_CSEL2_GPIO26 \ + ESP32_PINMUX(26, ESP_NOSIG, ESP_FSPICS2_OUT) + +#define SPIM2_CSEL2_GPIO27 \ + ESP32_PINMUX(27, ESP_NOSIG, ESP_FSPICS2_OUT) + +#define SPIM2_CSEL2_GPIO28 \ + ESP32_PINMUX(28, ESP_NOSIG, ESP_FSPICS2_OUT) + +#define SPIM2_CSEL2_GPIO29 \ + ESP32_PINMUX(29, ESP_NOSIG, ESP_FSPICS2_OUT) + +#define SPIM2_CSEL2_GPIO30 \ + ESP32_PINMUX(30, ESP_NOSIG, ESP_FSPICS2_OUT) + +#define SPIM2_CSEL2_GPIO31 \ + ESP32_PINMUX(31, ESP_NOSIG, ESP_FSPICS2_OUT) + +#define SPIM2_CSEL2_GPIO32 \ + ESP32_PINMUX(32, ESP_NOSIG, ESP_FSPICS2_OUT) + +#define SPIM2_CSEL2_GPIO33 \ + ESP32_PINMUX(33, ESP_NOSIG, ESP_FSPICS2_OUT) + +#define SPIM2_CSEL2_GPIO34 \ + ESP32_PINMUX(34, ESP_NOSIG, ESP_FSPICS2_OUT) + +#define SPIM2_CSEL2_GPIO35 \ + ESP32_PINMUX(35, ESP_NOSIG, ESP_FSPICS2_OUT) + +#define SPIM2_CSEL2_GPIO36 \ + ESP32_PINMUX(36, ESP_NOSIG, ESP_FSPICS2_OUT) + +#define SPIM2_CSEL2_GPIO37 \ + ESP32_PINMUX(37, ESP_NOSIG, ESP_FSPICS2_OUT) + +#define SPIM2_CSEL2_GPIO38 \ + ESP32_PINMUX(38, ESP_NOSIG, ESP_FSPICS2_OUT) + +#define SPIM2_CSEL2_GPIO39 \ + ESP32_PINMUX(39, ESP_NOSIG, ESP_FSPICS2_OUT) + +#define SPIM2_CSEL2_GPIO40 \ + ESP32_PINMUX(40, ESP_NOSIG, ESP_FSPICS2_OUT) + +#define SPIM2_CSEL2_GPIO41 \ + ESP32_PINMUX(41, ESP_NOSIG, ESP_FSPICS2_OUT) + +#define SPIM2_CSEL2_GPIO42 \ + ESP32_PINMUX(42, ESP_NOSIG, ESP_FSPICS2_OUT) + +#define SPIM2_CSEL2_GPIO43 \ + ESP32_PINMUX(43, ESP_NOSIG, ESP_FSPICS2_OUT) + +#define SPIM2_CSEL2_GPIO44 \ + ESP32_PINMUX(44, ESP_NOSIG, ESP_FSPICS2_OUT) + +#define SPIM2_CSEL2_GPIO45 \ + ESP32_PINMUX(45, ESP_NOSIG, ESP_FSPICS2_OUT) + +/* SPIM2_CSEL3 */ +#define SPIM2_CSEL3_GPIO0 \ + ESP32_PINMUX(0, ESP_NOSIG, ESP_FSPICS3_OUT) + +#define SPIM2_CSEL3_GPIO1 \ + ESP32_PINMUX(1, ESP_NOSIG, ESP_FSPICS3_OUT) + +#define SPIM2_CSEL3_GPIO2 \ + ESP32_PINMUX(2, ESP_NOSIG, ESP_FSPICS3_OUT) + +#define SPIM2_CSEL3_GPIO3 \ + ESP32_PINMUX(3, ESP_NOSIG, ESP_FSPICS3_OUT) + +#define SPIM2_CSEL3_GPIO4 \ + ESP32_PINMUX(4, ESP_NOSIG, ESP_FSPICS3_OUT) + +#define SPIM2_CSEL3_GPIO5 \ + ESP32_PINMUX(5, ESP_NOSIG, ESP_FSPICS3_OUT) + +#define SPIM2_CSEL3_GPIO6 \ + ESP32_PINMUX(6, ESP_NOSIG, ESP_FSPICS3_OUT) + +#define SPIM2_CSEL3_GPIO7 \ + ESP32_PINMUX(7, ESP_NOSIG, ESP_FSPICS3_OUT) + +#define SPIM2_CSEL3_GPIO8 \ + ESP32_PINMUX(8, ESP_NOSIG, ESP_FSPICS3_OUT) + +#define SPIM2_CSEL3_GPIO9 \ + ESP32_PINMUX(9, ESP_NOSIG, ESP_FSPICS3_OUT) + +#define SPIM2_CSEL3_GPIO10 \ + ESP32_PINMUX(10, ESP_NOSIG, ESP_FSPICS3_OUT) + +#define SPIM2_CSEL3_GPIO11 \ + ESP32_PINMUX(11, ESP_NOSIG, ESP_FSPICS3_OUT) + +#define SPIM2_CSEL3_GPIO12 \ + ESP32_PINMUX(12, ESP_NOSIG, ESP_FSPICS3_OUT) + +#define SPIM2_CSEL3_GPIO13 \ + ESP32_PINMUX(13, ESP_NOSIG, ESP_FSPICS3_OUT) + +#define SPIM2_CSEL3_GPIO14 \ + ESP32_PINMUX(14, ESP_NOSIG, ESP_FSPICS3_OUT) + +#define SPIM2_CSEL3_GPIO15 \ + ESP32_PINMUX(15, ESP_NOSIG, ESP_FSPICS3_OUT) + +#define SPIM2_CSEL3_GPIO16 \ + ESP32_PINMUX(16, ESP_NOSIG, ESP_FSPICS3_OUT) + +#define SPIM2_CSEL3_GPIO17 \ + ESP32_PINMUX(17, ESP_NOSIG, ESP_FSPICS3_OUT) + +#define SPIM2_CSEL3_GPIO18 \ + ESP32_PINMUX(18, ESP_NOSIG, ESP_FSPICS3_OUT) + +#define SPIM2_CSEL3_GPIO19 \ + ESP32_PINMUX(19, ESP_NOSIG, ESP_FSPICS3_OUT) + +#define SPIM2_CSEL3_GPIO20 \ + ESP32_PINMUX(20, ESP_NOSIG, ESP_FSPICS3_OUT) + +#define SPIM2_CSEL3_GPIO21 \ + ESP32_PINMUX(21, ESP_NOSIG, ESP_FSPICS3_OUT) + +#define SPIM2_CSEL3_GPIO26 \ + ESP32_PINMUX(26, ESP_NOSIG, ESP_FSPICS3_OUT) + +#define SPIM2_CSEL3_GPIO27 \ + ESP32_PINMUX(27, ESP_NOSIG, ESP_FSPICS3_OUT) + +#define SPIM2_CSEL3_GPIO28 \ + ESP32_PINMUX(28, ESP_NOSIG, ESP_FSPICS3_OUT) + +#define SPIM2_CSEL3_GPIO29 \ + ESP32_PINMUX(29, ESP_NOSIG, ESP_FSPICS3_OUT) + +#define SPIM2_CSEL3_GPIO30 \ + ESP32_PINMUX(30, ESP_NOSIG, ESP_FSPICS3_OUT) + +#define SPIM2_CSEL3_GPIO31 \ + ESP32_PINMUX(31, ESP_NOSIG, ESP_FSPICS3_OUT) + +#define SPIM2_CSEL3_GPIO32 \ + ESP32_PINMUX(32, ESP_NOSIG, ESP_FSPICS3_OUT) + +#define SPIM2_CSEL3_GPIO33 \ + ESP32_PINMUX(33, ESP_NOSIG, ESP_FSPICS3_OUT) + +#define SPIM2_CSEL3_GPIO34 \ + ESP32_PINMUX(34, ESP_NOSIG, ESP_FSPICS3_OUT) + +#define SPIM2_CSEL3_GPIO35 \ + ESP32_PINMUX(35, ESP_NOSIG, ESP_FSPICS3_OUT) + +#define SPIM2_CSEL3_GPIO36 \ + ESP32_PINMUX(36, ESP_NOSIG, ESP_FSPICS3_OUT) + +#define SPIM2_CSEL3_GPIO37 \ + ESP32_PINMUX(37, ESP_NOSIG, ESP_FSPICS3_OUT) + +#define SPIM2_CSEL3_GPIO38 \ + ESP32_PINMUX(38, ESP_NOSIG, ESP_FSPICS3_OUT) + +#define SPIM2_CSEL3_GPIO39 \ + ESP32_PINMUX(39, ESP_NOSIG, ESP_FSPICS3_OUT) + +#define SPIM2_CSEL3_GPIO40 \ + ESP32_PINMUX(40, ESP_NOSIG, ESP_FSPICS3_OUT) + +#define SPIM2_CSEL3_GPIO41 \ + ESP32_PINMUX(41, ESP_NOSIG, ESP_FSPICS3_OUT) + +#define SPIM2_CSEL3_GPIO42 \ + ESP32_PINMUX(42, ESP_NOSIG, ESP_FSPICS3_OUT) + +#define SPIM2_CSEL3_GPIO43 \ + ESP32_PINMUX(43, ESP_NOSIG, ESP_FSPICS3_OUT) + +#define SPIM2_CSEL3_GPIO44 \ + ESP32_PINMUX(44, ESP_NOSIG, ESP_FSPICS3_OUT) + +#define SPIM2_CSEL3_GPIO45 \ + ESP32_PINMUX(45, ESP_NOSIG, ESP_FSPICS3_OUT) + +/* SPIM2_CSEL4 */ +#define SPIM2_CSEL4_GPIO0 \ + ESP32_PINMUX(0, ESP_NOSIG, ESP_FSPICS4_OUT) + +#define SPIM2_CSEL4_GPIO1 \ + ESP32_PINMUX(1, ESP_NOSIG, ESP_FSPICS4_OUT) + +#define SPIM2_CSEL4_GPIO2 \ + ESP32_PINMUX(2, ESP_NOSIG, ESP_FSPICS4_OUT) + +#define SPIM2_CSEL4_GPIO3 \ + ESP32_PINMUX(3, ESP_NOSIG, ESP_FSPICS4_OUT) + +#define SPIM2_CSEL4_GPIO4 \ + ESP32_PINMUX(4, ESP_NOSIG, ESP_FSPICS4_OUT) + +#define SPIM2_CSEL4_GPIO5 \ + ESP32_PINMUX(5, ESP_NOSIG, ESP_FSPICS4_OUT) + +#define SPIM2_CSEL4_GPIO6 \ + ESP32_PINMUX(6, ESP_NOSIG, ESP_FSPICS4_OUT) + +#define SPIM2_CSEL4_GPIO7 \ + ESP32_PINMUX(7, ESP_NOSIG, ESP_FSPICS4_OUT) + +#define SPIM2_CSEL4_GPIO8 \ + ESP32_PINMUX(8, ESP_NOSIG, ESP_FSPICS4_OUT) + +#define SPIM2_CSEL4_GPIO9 \ + ESP32_PINMUX(9, ESP_NOSIG, ESP_FSPICS4_OUT) + +#define SPIM2_CSEL4_GPIO10 \ + ESP32_PINMUX(10, ESP_NOSIG, ESP_FSPICS4_OUT) + +#define SPIM2_CSEL4_GPIO11 \ + ESP32_PINMUX(11, ESP_NOSIG, ESP_FSPICS4_OUT) + +#define SPIM2_CSEL4_GPIO12 \ + ESP32_PINMUX(12, ESP_NOSIG, ESP_FSPICS4_OUT) + +#define SPIM2_CSEL4_GPIO13 \ + ESP32_PINMUX(13, ESP_NOSIG, ESP_FSPICS4_OUT) + +#define SPIM2_CSEL4_GPIO14 \ + ESP32_PINMUX(14, ESP_NOSIG, ESP_FSPICS4_OUT) + +#define SPIM2_CSEL4_GPIO15 \ + ESP32_PINMUX(15, ESP_NOSIG, ESP_FSPICS4_OUT) + +#define SPIM2_CSEL4_GPIO16 \ + ESP32_PINMUX(16, ESP_NOSIG, ESP_FSPICS4_OUT) + +#define SPIM2_CSEL4_GPIO17 \ + ESP32_PINMUX(17, ESP_NOSIG, ESP_FSPICS4_OUT) + +#define SPIM2_CSEL4_GPIO18 \ + ESP32_PINMUX(18, ESP_NOSIG, ESP_FSPICS4_OUT) + +#define SPIM2_CSEL4_GPIO19 \ + ESP32_PINMUX(19, ESP_NOSIG, ESP_FSPICS4_OUT) + +#define SPIM2_CSEL4_GPIO20 \ + ESP32_PINMUX(20, ESP_NOSIG, ESP_FSPICS4_OUT) + +#define SPIM2_CSEL4_GPIO21 \ + ESP32_PINMUX(21, ESP_NOSIG, ESP_FSPICS4_OUT) + +#define SPIM2_CSEL4_GPIO26 \ + ESP32_PINMUX(26, ESP_NOSIG, ESP_FSPICS4_OUT) + +#define SPIM2_CSEL4_GPIO27 \ + ESP32_PINMUX(27, ESP_NOSIG, ESP_FSPICS4_OUT) + +#define SPIM2_CSEL4_GPIO28 \ + ESP32_PINMUX(28, ESP_NOSIG, ESP_FSPICS4_OUT) + +#define SPIM2_CSEL4_GPIO29 \ + ESP32_PINMUX(29, ESP_NOSIG, ESP_FSPICS4_OUT) + +#define SPIM2_CSEL4_GPIO30 \ + ESP32_PINMUX(30, ESP_NOSIG, ESP_FSPICS4_OUT) + +#define SPIM2_CSEL4_GPIO31 \ + ESP32_PINMUX(31, ESP_NOSIG, ESP_FSPICS4_OUT) + +#define SPIM2_CSEL4_GPIO32 \ + ESP32_PINMUX(32, ESP_NOSIG, ESP_FSPICS4_OUT) + +#define SPIM2_CSEL4_GPIO33 \ + ESP32_PINMUX(33, ESP_NOSIG, ESP_FSPICS4_OUT) + +#define SPIM2_CSEL4_GPIO34 \ + ESP32_PINMUX(34, ESP_NOSIG, ESP_FSPICS4_OUT) + +#define SPIM2_CSEL4_GPIO35 \ + ESP32_PINMUX(35, ESP_NOSIG, ESP_FSPICS4_OUT) + +#define SPIM2_CSEL4_GPIO36 \ + ESP32_PINMUX(36, ESP_NOSIG, ESP_FSPICS4_OUT) + +#define SPIM2_CSEL4_GPIO37 \ + ESP32_PINMUX(37, ESP_NOSIG, ESP_FSPICS4_OUT) + +#define SPIM2_CSEL4_GPIO38 \ + ESP32_PINMUX(38, ESP_NOSIG, ESP_FSPICS4_OUT) + +#define SPIM2_CSEL4_GPIO39 \ + ESP32_PINMUX(39, ESP_NOSIG, ESP_FSPICS4_OUT) + +#define SPIM2_CSEL4_GPIO40 \ + ESP32_PINMUX(40, ESP_NOSIG, ESP_FSPICS4_OUT) + +#define SPIM2_CSEL4_GPIO41 \ + ESP32_PINMUX(41, ESP_NOSIG, ESP_FSPICS4_OUT) + +#define SPIM2_CSEL4_GPIO42 \ + ESP32_PINMUX(42, ESP_NOSIG, ESP_FSPICS4_OUT) + +#define SPIM2_CSEL4_GPIO43 \ + ESP32_PINMUX(43, ESP_NOSIG, ESP_FSPICS4_OUT) + +#define SPIM2_CSEL4_GPIO44 \ + ESP32_PINMUX(44, ESP_NOSIG, ESP_FSPICS4_OUT) + +#define SPIM2_CSEL4_GPIO45 \ + ESP32_PINMUX(45, ESP_NOSIG, ESP_FSPICS4_OUT) + +/* SPIM2_CSEL5 */ +#define SPIM2_CSEL5_GPIO0 \ + ESP32_PINMUX(0, ESP_NOSIG, ESP_FSPICS5_OUT) + +#define SPIM2_CSEL5_GPIO1 \ + ESP32_PINMUX(1, ESP_NOSIG, ESP_FSPICS5_OUT) + +#define SPIM2_CSEL5_GPIO2 \ + ESP32_PINMUX(2, ESP_NOSIG, ESP_FSPICS5_OUT) + +#define SPIM2_CSEL5_GPIO3 \ + ESP32_PINMUX(3, ESP_NOSIG, ESP_FSPICS5_OUT) + +#define SPIM2_CSEL5_GPIO4 \ + ESP32_PINMUX(4, ESP_NOSIG, ESP_FSPICS5_OUT) + +#define SPIM2_CSEL5_GPIO5 \ + ESP32_PINMUX(5, ESP_NOSIG, ESP_FSPICS5_OUT) + +#define SPIM2_CSEL5_GPIO6 \ + ESP32_PINMUX(6, ESP_NOSIG, ESP_FSPICS5_OUT) + +#define SPIM2_CSEL5_GPIO7 \ + ESP32_PINMUX(7, ESP_NOSIG, ESP_FSPICS5_OUT) + +#define SPIM2_CSEL5_GPIO8 \ + ESP32_PINMUX(8, ESP_NOSIG, ESP_FSPICS5_OUT) + +#define SPIM2_CSEL5_GPIO9 \ + ESP32_PINMUX(9, ESP_NOSIG, ESP_FSPICS5_OUT) + +#define SPIM2_CSEL5_GPIO10 \ + ESP32_PINMUX(10, ESP_NOSIG, ESP_FSPICS5_OUT) + +#define SPIM2_CSEL5_GPIO11 \ + ESP32_PINMUX(11, ESP_NOSIG, ESP_FSPICS5_OUT) + +#define SPIM2_CSEL5_GPIO12 \ + ESP32_PINMUX(12, ESP_NOSIG, ESP_FSPICS5_OUT) + +#define SPIM2_CSEL5_GPIO13 \ + ESP32_PINMUX(13, ESP_NOSIG, ESP_FSPICS5_OUT) + +#define SPIM2_CSEL5_GPIO14 \ + ESP32_PINMUX(14, ESP_NOSIG, ESP_FSPICS5_OUT) + +#define SPIM2_CSEL5_GPIO15 \ + ESP32_PINMUX(15, ESP_NOSIG, ESP_FSPICS5_OUT) + +#define SPIM2_CSEL5_GPIO16 \ + ESP32_PINMUX(16, ESP_NOSIG, ESP_FSPICS5_OUT) + +#define SPIM2_CSEL5_GPIO17 \ + ESP32_PINMUX(17, ESP_NOSIG, ESP_FSPICS5_OUT) + +#define SPIM2_CSEL5_GPIO18 \ + ESP32_PINMUX(18, ESP_NOSIG, ESP_FSPICS5_OUT) + +#define SPIM2_CSEL5_GPIO19 \ + ESP32_PINMUX(19, ESP_NOSIG, ESP_FSPICS5_OUT) + +#define SPIM2_CSEL5_GPIO20 \ + ESP32_PINMUX(20, ESP_NOSIG, ESP_FSPICS5_OUT) + +#define SPIM2_CSEL5_GPIO21 \ + ESP32_PINMUX(21, ESP_NOSIG, ESP_FSPICS5_OUT) + +#define SPIM2_CSEL5_GPIO26 \ + ESP32_PINMUX(26, ESP_NOSIG, ESP_FSPICS5_OUT) + +#define SPIM2_CSEL5_GPIO27 \ + ESP32_PINMUX(27, ESP_NOSIG, ESP_FSPICS5_OUT) + +#define SPIM2_CSEL5_GPIO28 \ + ESP32_PINMUX(28, ESP_NOSIG, ESP_FSPICS5_OUT) + +#define SPIM2_CSEL5_GPIO29 \ + ESP32_PINMUX(29, ESP_NOSIG, ESP_FSPICS5_OUT) + +#define SPIM2_CSEL5_GPIO30 \ + ESP32_PINMUX(30, ESP_NOSIG, ESP_FSPICS5_OUT) + +#define SPIM2_CSEL5_GPIO31 \ + ESP32_PINMUX(31, ESP_NOSIG, ESP_FSPICS5_OUT) + +#define SPIM2_CSEL5_GPIO32 \ + ESP32_PINMUX(32, ESP_NOSIG, ESP_FSPICS5_OUT) + +#define SPIM2_CSEL5_GPIO33 \ + ESP32_PINMUX(33, ESP_NOSIG, ESP_FSPICS5_OUT) + +#define SPIM2_CSEL5_GPIO34 \ + ESP32_PINMUX(34, ESP_NOSIG, ESP_FSPICS5_OUT) + +#define SPIM2_CSEL5_GPIO35 \ + ESP32_PINMUX(35, ESP_NOSIG, ESP_FSPICS5_OUT) + +#define SPIM2_CSEL5_GPIO36 \ + ESP32_PINMUX(36, ESP_NOSIG, ESP_FSPICS5_OUT) + +#define SPIM2_CSEL5_GPIO37 \ + ESP32_PINMUX(37, ESP_NOSIG, ESP_FSPICS5_OUT) + +#define SPIM2_CSEL5_GPIO38 \ + ESP32_PINMUX(38, ESP_NOSIG, ESP_FSPICS5_OUT) + +#define SPIM2_CSEL5_GPIO39 \ + ESP32_PINMUX(39, ESP_NOSIG, ESP_FSPICS5_OUT) + +#define SPIM2_CSEL5_GPIO40 \ + ESP32_PINMUX(40, ESP_NOSIG, ESP_FSPICS5_OUT) + +#define SPIM2_CSEL5_GPIO41 \ + ESP32_PINMUX(41, ESP_NOSIG, ESP_FSPICS5_OUT) + +#define SPIM2_CSEL5_GPIO42 \ + ESP32_PINMUX(42, ESP_NOSIG, ESP_FSPICS5_OUT) + +#define SPIM2_CSEL5_GPIO43 \ + ESP32_PINMUX(43, ESP_NOSIG, ESP_FSPICS5_OUT) + +#define SPIM2_CSEL5_GPIO44 \ + ESP32_PINMUX(44, ESP_NOSIG, ESP_FSPICS5_OUT) + +#define SPIM2_CSEL5_GPIO45 \ + ESP32_PINMUX(45, ESP_NOSIG, ESP_FSPICS5_OUT) + +/* SPIM2_MISO */ +#define SPIM2_MISO_GPIO0 \ + ESP32_PINMUX(0, ESP_FSPIQ_IN, ESP_NOSIG) + +#define SPIM2_MISO_GPIO1 \ + ESP32_PINMUX(1, ESP_FSPIQ_IN, ESP_NOSIG) + +#define SPIM2_MISO_GPIO2 \ + ESP32_PINMUX(2, ESP_FSPIQ_IN, ESP_NOSIG) + +#define SPIM2_MISO_GPIO3 \ + ESP32_PINMUX(3, ESP_FSPIQ_IN, ESP_NOSIG) + +#define SPIM2_MISO_GPIO4 \ + ESP32_PINMUX(4, ESP_FSPIQ_IN, ESP_NOSIG) + +#define SPIM2_MISO_GPIO5 \ + ESP32_PINMUX(5, ESP_FSPIQ_IN, ESP_NOSIG) + +#define SPIM2_MISO_GPIO6 \ + ESP32_PINMUX(6, ESP_FSPIQ_IN, ESP_NOSIG) + +#define SPIM2_MISO_GPIO7 \ + ESP32_PINMUX(7, ESP_FSPIQ_IN, ESP_NOSIG) + +#define SPIM2_MISO_GPIO8 \ + ESP32_PINMUX(8, ESP_FSPIQ_IN, ESP_NOSIG) + +#define SPIM2_MISO_GPIO9 \ + ESP32_PINMUX(9, ESP_FSPIQ_IN, ESP_NOSIG) + +#define SPIM2_MISO_GPIO10 \ + ESP32_PINMUX(10, ESP_FSPIQ_IN, ESP_NOSIG) + +#define SPIM2_MISO_GPIO11 \ + ESP32_PINMUX(11, ESP_FSPIQ_IN, ESP_NOSIG) + +#define SPIM2_MISO_GPIO12 \ + ESP32_PINMUX(12, ESP_FSPIQ_IN, ESP_NOSIG) + +#define SPIM2_MISO_GPIO13 \ + ESP32_PINMUX(13, ESP_FSPIQ_IN, ESP_NOSIG) + +#define SPIM2_MISO_GPIO14 \ + ESP32_PINMUX(14, ESP_FSPIQ_IN, ESP_NOSIG) + +#define SPIM2_MISO_GPIO15 \ + ESP32_PINMUX(15, ESP_FSPIQ_IN, ESP_NOSIG) + +#define SPIM2_MISO_GPIO16 \ + ESP32_PINMUX(16, ESP_FSPIQ_IN, ESP_NOSIG) + +#define SPIM2_MISO_GPIO17 \ + ESP32_PINMUX(17, ESP_FSPIQ_IN, ESP_NOSIG) + +#define SPIM2_MISO_GPIO18 \ + ESP32_PINMUX(18, ESP_FSPIQ_IN, ESP_NOSIG) + +#define SPIM2_MISO_GPIO19 \ + ESP32_PINMUX(19, ESP_FSPIQ_IN, ESP_NOSIG) + +#define SPIM2_MISO_GPIO20 \ + ESP32_PINMUX(20, ESP_FSPIQ_IN, ESP_NOSIG) + +#define SPIM2_MISO_GPIO21 \ + ESP32_PINMUX(21, ESP_FSPIQ_IN, ESP_NOSIG) + +#define SPIM2_MISO_GPIO26 \ + ESP32_PINMUX(26, ESP_FSPIQ_IN, ESP_NOSIG) + +#define SPIM2_MISO_GPIO27 \ + ESP32_PINMUX(27, ESP_FSPIQ_IN, ESP_NOSIG) + +#define SPIM2_MISO_GPIO28 \ + ESP32_PINMUX(28, ESP_FSPIQ_IN, ESP_NOSIG) + +#define SPIM2_MISO_GPIO29 \ + ESP32_PINMUX(29, ESP_FSPIQ_IN, ESP_NOSIG) + +#define SPIM2_MISO_GPIO30 \ + ESP32_PINMUX(30, ESP_FSPIQ_IN, ESP_NOSIG) + +#define SPIM2_MISO_GPIO31 \ + ESP32_PINMUX(31, ESP_FSPIQ_IN, ESP_NOSIG) + +#define SPIM2_MISO_GPIO32 \ + ESP32_PINMUX(32, ESP_FSPIQ_IN, ESP_NOSIG) + +#define SPIM2_MISO_GPIO33 \ + ESP32_PINMUX(33, ESP_FSPIQ_IN, ESP_NOSIG) + +#define SPIM2_MISO_GPIO34 \ + ESP32_PINMUX(34, ESP_FSPIQ_IN, ESP_NOSIG) + +#define SPIM2_MISO_GPIO35 \ + ESP32_PINMUX(35, ESP_FSPIQ_IN, ESP_NOSIG) + +#define SPIM2_MISO_GPIO36 \ + ESP32_PINMUX(36, ESP_FSPIQ_IN, ESP_NOSIG) + +#define SPIM2_MISO_GPIO37 \ + ESP32_PINMUX(37, ESP_FSPIQ_IN, ESP_NOSIG) + +#define SPIM2_MISO_GPIO38 \ + ESP32_PINMUX(38, ESP_FSPIQ_IN, ESP_NOSIG) + +#define SPIM2_MISO_GPIO39 \ + ESP32_PINMUX(39, ESP_FSPIQ_IN, ESP_NOSIG) + +#define SPIM2_MISO_GPIO40 \ + ESP32_PINMUX(40, ESP_FSPIQ_IN, ESP_NOSIG) + +#define SPIM2_MISO_GPIO41 \ + ESP32_PINMUX(41, ESP_FSPIQ_IN, ESP_NOSIG) + +#define SPIM2_MISO_GPIO42 \ + ESP32_PINMUX(42, ESP_FSPIQ_IN, ESP_NOSIG) + +#define SPIM2_MISO_GPIO43 \ + ESP32_PINMUX(43, ESP_FSPIQ_IN, ESP_NOSIG) + +#define SPIM2_MISO_GPIO44 \ + ESP32_PINMUX(44, ESP_FSPIQ_IN, ESP_NOSIG) + +#define SPIM2_MISO_GPIO45 \ + ESP32_PINMUX(45, ESP_FSPIQ_IN, ESP_NOSIG) + +#define SPIM2_MISO_GPIO46 \ + ESP32_PINMUX(46, ESP_FSPIQ_IN, ESP_NOSIG) + +/* SPIM2_MOSI */ +#define SPIM2_MOSI_GPIO0 \ + ESP32_PINMUX(0, ESP_NOSIG, ESP_FSPID_OUT) + +#define SPIM2_MOSI_GPIO1 \ + ESP32_PINMUX(1, ESP_NOSIG, ESP_FSPID_OUT) + +#define SPIM2_MOSI_GPIO2 \ + ESP32_PINMUX(2, ESP_NOSIG, ESP_FSPID_OUT) + +#define SPIM2_MOSI_GPIO3 \ + ESP32_PINMUX(3, ESP_NOSIG, ESP_FSPID_OUT) + +#define SPIM2_MOSI_GPIO4 \ + ESP32_PINMUX(4, ESP_NOSIG, ESP_FSPID_OUT) + +#define SPIM2_MOSI_GPIO5 \ + ESP32_PINMUX(5, ESP_NOSIG, ESP_FSPID_OUT) + +#define SPIM2_MOSI_GPIO6 \ + ESP32_PINMUX(6, ESP_NOSIG, ESP_FSPID_OUT) + +#define SPIM2_MOSI_GPIO7 \ + ESP32_PINMUX(7, ESP_NOSIG, ESP_FSPID_OUT) + +#define SPIM2_MOSI_GPIO8 \ + ESP32_PINMUX(8, ESP_NOSIG, ESP_FSPID_OUT) + +#define SPIM2_MOSI_GPIO9 \ + ESP32_PINMUX(9, ESP_NOSIG, ESP_FSPID_OUT) + +#define SPIM2_MOSI_GPIO10 \ + ESP32_PINMUX(10, ESP_NOSIG, ESP_FSPID_OUT) + +#define SPIM2_MOSI_GPIO11 \ + ESP32_PINMUX(11, ESP_NOSIG, ESP_FSPID_OUT) + +#define SPIM2_MOSI_GPIO12 \ + ESP32_PINMUX(12, ESP_NOSIG, ESP_FSPID_OUT) + +#define SPIM2_MOSI_GPIO13 \ + ESP32_PINMUX(13, ESP_NOSIG, ESP_FSPID_OUT) + +#define SPIM2_MOSI_GPIO14 \ + ESP32_PINMUX(14, ESP_NOSIG, ESP_FSPID_OUT) + +#define SPIM2_MOSI_GPIO15 \ + ESP32_PINMUX(15, ESP_NOSIG, ESP_FSPID_OUT) + +#define SPIM2_MOSI_GPIO16 \ + ESP32_PINMUX(16, ESP_NOSIG, ESP_FSPID_OUT) + +#define SPIM2_MOSI_GPIO17 \ + ESP32_PINMUX(17, ESP_NOSIG, ESP_FSPID_OUT) + +#define SPIM2_MOSI_GPIO18 \ + ESP32_PINMUX(18, ESP_NOSIG, ESP_FSPID_OUT) + +#define SPIM2_MOSI_GPIO19 \ + ESP32_PINMUX(19, ESP_NOSIG, ESP_FSPID_OUT) + +#define SPIM2_MOSI_GPIO20 \ + ESP32_PINMUX(20, ESP_NOSIG, ESP_FSPID_OUT) + +#define SPIM2_MOSI_GPIO21 \ + ESP32_PINMUX(21, ESP_NOSIG, ESP_FSPID_OUT) + +#define SPIM2_MOSI_GPIO26 \ + ESP32_PINMUX(26, ESP_NOSIG, ESP_FSPID_OUT) + +#define SPIM2_MOSI_GPIO27 \ + ESP32_PINMUX(27, ESP_NOSIG, ESP_FSPID_OUT) + +#define SPIM2_MOSI_GPIO28 \ + ESP32_PINMUX(28, ESP_NOSIG, ESP_FSPID_OUT) + +#define SPIM2_MOSI_GPIO29 \ + ESP32_PINMUX(29, ESP_NOSIG, ESP_FSPID_OUT) + +#define SPIM2_MOSI_GPIO30 \ + ESP32_PINMUX(30, ESP_NOSIG, ESP_FSPID_OUT) + +#define SPIM2_MOSI_GPIO31 \ + ESP32_PINMUX(31, ESP_NOSIG, ESP_FSPID_OUT) + +#define SPIM2_MOSI_GPIO32 \ + ESP32_PINMUX(32, ESP_NOSIG, ESP_FSPID_OUT) + +#define SPIM2_MOSI_GPIO33 \ + ESP32_PINMUX(33, ESP_NOSIG, ESP_FSPID_OUT) + +#define SPIM2_MOSI_GPIO34 \ + ESP32_PINMUX(34, ESP_NOSIG, ESP_FSPID_OUT) + +#define SPIM2_MOSI_GPIO35 \ + ESP32_PINMUX(35, ESP_NOSIG, ESP_FSPID_OUT) + +#define SPIM2_MOSI_GPIO36 \ + ESP32_PINMUX(36, ESP_NOSIG, ESP_FSPID_OUT) + +#define SPIM2_MOSI_GPIO37 \ + ESP32_PINMUX(37, ESP_NOSIG, ESP_FSPID_OUT) + +#define SPIM2_MOSI_GPIO38 \ + ESP32_PINMUX(38, ESP_NOSIG, ESP_FSPID_OUT) + +#define SPIM2_MOSI_GPIO39 \ + ESP32_PINMUX(39, ESP_NOSIG, ESP_FSPID_OUT) + +#define SPIM2_MOSI_GPIO40 \ + ESP32_PINMUX(40, ESP_NOSIG, ESP_FSPID_OUT) + +#define SPIM2_MOSI_GPIO41 \ + ESP32_PINMUX(41, ESP_NOSIG, ESP_FSPID_OUT) + +#define SPIM2_MOSI_GPIO42 \ + ESP32_PINMUX(42, ESP_NOSIG, ESP_FSPID_OUT) + +#define SPIM2_MOSI_GPIO43 \ + ESP32_PINMUX(43, ESP_NOSIG, ESP_FSPID_OUT) + +#define SPIM2_MOSI_GPIO44 \ + ESP32_PINMUX(44, ESP_NOSIG, ESP_FSPID_OUT) + +#define SPIM2_MOSI_GPIO45 \ + ESP32_PINMUX(45, ESP_NOSIG, ESP_FSPID_OUT) + +/* SPIM2_SCLK */ +#define SPIM2_SCLK_GPIO0 \ + ESP32_PINMUX(0, ESP_NOSIG, ESP_FSPICLK_OUT) + +#define SPIM2_SCLK_GPIO1 \ + ESP32_PINMUX(1, ESP_NOSIG, ESP_FSPICLK_OUT) + +#define SPIM2_SCLK_GPIO2 \ + ESP32_PINMUX(2, ESP_NOSIG, ESP_FSPICLK_OUT) + +#define SPIM2_SCLK_GPIO3 \ + ESP32_PINMUX(3, ESP_NOSIG, ESP_FSPICLK_OUT) + +#define SPIM2_SCLK_GPIO4 \ + ESP32_PINMUX(4, ESP_NOSIG, ESP_FSPICLK_OUT) + +#define SPIM2_SCLK_GPIO5 \ + ESP32_PINMUX(5, ESP_NOSIG, ESP_FSPICLK_OUT) + +#define SPIM2_SCLK_GPIO6 \ + ESP32_PINMUX(6, ESP_NOSIG, ESP_FSPICLK_OUT) + +#define SPIM2_SCLK_GPIO7 \ + ESP32_PINMUX(7, ESP_NOSIG, ESP_FSPICLK_OUT) + +#define SPIM2_SCLK_GPIO8 \ + ESP32_PINMUX(8, ESP_NOSIG, ESP_FSPICLK_OUT) + +#define SPIM2_SCLK_GPIO9 \ + ESP32_PINMUX(9, ESP_NOSIG, ESP_FSPICLK_OUT) + +#define SPIM2_SCLK_GPIO10 \ + ESP32_PINMUX(10, ESP_NOSIG, ESP_FSPICLK_OUT) + +#define SPIM2_SCLK_GPIO11 \ + ESP32_PINMUX(11, ESP_NOSIG, ESP_FSPICLK_OUT) + +#define SPIM2_SCLK_GPIO12 \ + ESP32_PINMUX(12, ESP_NOSIG, ESP_FSPICLK_OUT) + +#define SPIM2_SCLK_GPIO13 \ + ESP32_PINMUX(13, ESP_NOSIG, ESP_FSPICLK_OUT) + +#define SPIM2_SCLK_GPIO14 \ + ESP32_PINMUX(14, ESP_NOSIG, ESP_FSPICLK_OUT) + +#define SPIM2_SCLK_GPIO15 \ + ESP32_PINMUX(15, ESP_NOSIG, ESP_FSPICLK_OUT) + +#define SPIM2_SCLK_GPIO16 \ + ESP32_PINMUX(16, ESP_NOSIG, ESP_FSPICLK_OUT) + +#define SPIM2_SCLK_GPIO17 \ + ESP32_PINMUX(17, ESP_NOSIG, ESP_FSPICLK_OUT) + +#define SPIM2_SCLK_GPIO18 \ + ESP32_PINMUX(18, ESP_NOSIG, ESP_FSPICLK_OUT) + +#define SPIM2_SCLK_GPIO19 \ + ESP32_PINMUX(19, ESP_NOSIG, ESP_FSPICLK_OUT) + +#define SPIM2_SCLK_GPIO20 \ + ESP32_PINMUX(20, ESP_NOSIG, ESP_FSPICLK_OUT) + +#define SPIM2_SCLK_GPIO21 \ + ESP32_PINMUX(21, ESP_NOSIG, ESP_FSPICLK_OUT) + +#define SPIM2_SCLK_GPIO26 \ + ESP32_PINMUX(26, ESP_NOSIG, ESP_FSPICLK_OUT) + +#define SPIM2_SCLK_GPIO27 \ + ESP32_PINMUX(27, ESP_NOSIG, ESP_FSPICLK_OUT) + +#define SPIM2_SCLK_GPIO28 \ + ESP32_PINMUX(28, ESP_NOSIG, ESP_FSPICLK_OUT) + +#define SPIM2_SCLK_GPIO29 \ + ESP32_PINMUX(29, ESP_NOSIG, ESP_FSPICLK_OUT) + +#define SPIM2_SCLK_GPIO30 \ + ESP32_PINMUX(30, ESP_NOSIG, ESP_FSPICLK_OUT) + +#define SPIM2_SCLK_GPIO31 \ + ESP32_PINMUX(31, ESP_NOSIG, ESP_FSPICLK_OUT) + +#define SPIM2_SCLK_GPIO32 \ + ESP32_PINMUX(32, ESP_NOSIG, ESP_FSPICLK_OUT) + +#define SPIM2_SCLK_GPIO33 \ + ESP32_PINMUX(33, ESP_NOSIG, ESP_FSPICLK_OUT) + +#define SPIM2_SCLK_GPIO34 \ + ESP32_PINMUX(34, ESP_NOSIG, ESP_FSPICLK_OUT) + +#define SPIM2_SCLK_GPIO35 \ + ESP32_PINMUX(35, ESP_NOSIG, ESP_FSPICLK_OUT) + +#define SPIM2_SCLK_GPIO36 \ + ESP32_PINMUX(36, ESP_NOSIG, ESP_FSPICLK_OUT) + +#define SPIM2_SCLK_GPIO37 \ + ESP32_PINMUX(37, ESP_NOSIG, ESP_FSPICLK_OUT) + +#define SPIM2_SCLK_GPIO38 \ + ESP32_PINMUX(38, ESP_NOSIG, ESP_FSPICLK_OUT) + +#define SPIM2_SCLK_GPIO39 \ + ESP32_PINMUX(39, ESP_NOSIG, ESP_FSPICLK_OUT) + +#define SPIM2_SCLK_GPIO40 \ + ESP32_PINMUX(40, ESP_NOSIG, ESP_FSPICLK_OUT) + +#define SPIM2_SCLK_GPIO41 \ + ESP32_PINMUX(41, ESP_NOSIG, ESP_FSPICLK_OUT) + +#define SPIM2_SCLK_GPIO42 \ + ESP32_PINMUX(42, ESP_NOSIG, ESP_FSPICLK_OUT) + +#define SPIM2_SCLK_GPIO43 \ + ESP32_PINMUX(43, ESP_NOSIG, ESP_FSPICLK_OUT) + +#define SPIM2_SCLK_GPIO44 \ + ESP32_PINMUX(44, ESP_NOSIG, ESP_FSPICLK_OUT) + +#define SPIM2_SCLK_GPIO45 \ + ESP32_PINMUX(45, ESP_NOSIG, ESP_FSPICLK_OUT) + +/* SPIM3_CSEL */ +#define SPIM3_CSEL_GPIO0 \ + ESP32_PINMUX(0, ESP_NOSIG, ESP_SPI3_CS0_OUT) + +#define SPIM3_CSEL_GPIO1 \ + ESP32_PINMUX(1, ESP_NOSIG, ESP_SPI3_CS0_OUT) + +#define SPIM3_CSEL_GPIO2 \ + ESP32_PINMUX(2, ESP_NOSIG, ESP_SPI3_CS0_OUT) + +#define SPIM3_CSEL_GPIO3 \ + ESP32_PINMUX(3, ESP_NOSIG, ESP_SPI3_CS0_OUT) + +#define SPIM3_CSEL_GPIO4 \ + ESP32_PINMUX(4, ESP_NOSIG, ESP_SPI3_CS0_OUT) + +#define SPIM3_CSEL_GPIO5 \ + ESP32_PINMUX(5, ESP_NOSIG, ESP_SPI3_CS0_OUT) + +#define SPIM3_CSEL_GPIO6 \ + ESP32_PINMUX(6, ESP_NOSIG, ESP_SPI3_CS0_OUT) + +#define SPIM3_CSEL_GPIO7 \ + ESP32_PINMUX(7, ESP_NOSIG, ESP_SPI3_CS0_OUT) + +#define SPIM3_CSEL_GPIO8 \ + ESP32_PINMUX(8, ESP_NOSIG, ESP_SPI3_CS0_OUT) + +#define SPIM3_CSEL_GPIO9 \ + ESP32_PINMUX(9, ESP_NOSIG, ESP_SPI3_CS0_OUT) + +#define SPIM3_CSEL_GPIO10 \ + ESP32_PINMUX(10, ESP_NOSIG, ESP_SPI3_CS0_OUT) + +#define SPIM3_CSEL_GPIO11 \ + ESP32_PINMUX(11, ESP_NOSIG, ESP_SPI3_CS0_OUT) + +#define SPIM3_CSEL_GPIO12 \ + ESP32_PINMUX(12, ESP_NOSIG, ESP_SPI3_CS0_OUT) + +#define SPIM3_CSEL_GPIO13 \ + ESP32_PINMUX(13, ESP_NOSIG, ESP_SPI3_CS0_OUT) + +#define SPIM3_CSEL_GPIO14 \ + ESP32_PINMUX(14, ESP_NOSIG, ESP_SPI3_CS0_OUT) + +#define SPIM3_CSEL_GPIO15 \ + ESP32_PINMUX(15, ESP_NOSIG, ESP_SPI3_CS0_OUT) + +#define SPIM3_CSEL_GPIO16 \ + ESP32_PINMUX(16, ESP_NOSIG, ESP_SPI3_CS0_OUT) + +#define SPIM3_CSEL_GPIO17 \ + ESP32_PINMUX(17, ESP_NOSIG, ESP_SPI3_CS0_OUT) + +#define SPIM3_CSEL_GPIO18 \ + ESP32_PINMUX(18, ESP_NOSIG, ESP_SPI3_CS0_OUT) + +#define SPIM3_CSEL_GPIO19 \ + ESP32_PINMUX(19, ESP_NOSIG, ESP_SPI3_CS0_OUT) + +#define SPIM3_CSEL_GPIO20 \ + ESP32_PINMUX(20, ESP_NOSIG, ESP_SPI3_CS0_OUT) + +#define SPIM3_CSEL_GPIO21 \ + ESP32_PINMUX(21, ESP_NOSIG, ESP_SPI3_CS0_OUT) + +#define SPIM3_CSEL_GPIO26 \ + ESP32_PINMUX(26, ESP_NOSIG, ESP_SPI3_CS0_OUT) + +#define SPIM3_CSEL_GPIO27 \ + ESP32_PINMUX(27, ESP_NOSIG, ESP_SPI3_CS0_OUT) + +#define SPIM3_CSEL_GPIO28 \ + ESP32_PINMUX(28, ESP_NOSIG, ESP_SPI3_CS0_OUT) + +#define SPIM3_CSEL_GPIO29 \ + ESP32_PINMUX(29, ESP_NOSIG, ESP_SPI3_CS0_OUT) + +#define SPIM3_CSEL_GPIO30 \ + ESP32_PINMUX(30, ESP_NOSIG, ESP_SPI3_CS0_OUT) + +#define SPIM3_CSEL_GPIO31 \ + ESP32_PINMUX(31, ESP_NOSIG, ESP_SPI3_CS0_OUT) + +#define SPIM3_CSEL_GPIO32 \ + ESP32_PINMUX(32, ESP_NOSIG, ESP_SPI3_CS0_OUT) + +#define SPIM3_CSEL_GPIO33 \ + ESP32_PINMUX(33, ESP_NOSIG, ESP_SPI3_CS0_OUT) + +#define SPIM3_CSEL_GPIO34 \ + ESP32_PINMUX(34, ESP_NOSIG, ESP_SPI3_CS0_OUT) + +#define SPIM3_CSEL_GPIO35 \ + ESP32_PINMUX(35, ESP_NOSIG, ESP_SPI3_CS0_OUT) + +#define SPIM3_CSEL_GPIO36 \ + ESP32_PINMUX(36, ESP_NOSIG, ESP_SPI3_CS0_OUT) + +#define SPIM3_CSEL_GPIO37 \ + ESP32_PINMUX(37, ESP_NOSIG, ESP_SPI3_CS0_OUT) + +#define SPIM3_CSEL_GPIO38 \ + ESP32_PINMUX(38, ESP_NOSIG, ESP_SPI3_CS0_OUT) + +#define SPIM3_CSEL_GPIO39 \ + ESP32_PINMUX(39, ESP_NOSIG, ESP_SPI3_CS0_OUT) + +#define SPIM3_CSEL_GPIO40 \ + ESP32_PINMUX(40, ESP_NOSIG, ESP_SPI3_CS0_OUT) + +#define SPIM3_CSEL_GPIO41 \ + ESP32_PINMUX(41, ESP_NOSIG, ESP_SPI3_CS0_OUT) + +#define SPIM3_CSEL_GPIO42 \ + ESP32_PINMUX(42, ESP_NOSIG, ESP_SPI3_CS0_OUT) + +#define SPIM3_CSEL_GPIO43 \ + ESP32_PINMUX(43, ESP_NOSIG, ESP_SPI3_CS0_OUT) + +#define SPIM3_CSEL_GPIO44 \ + ESP32_PINMUX(44, ESP_NOSIG, ESP_SPI3_CS0_OUT) + +#define SPIM3_CSEL_GPIO45 \ + ESP32_PINMUX(45, ESP_NOSIG, ESP_SPI3_CS0_OUT) + +/* SPIM3_CSEL1 */ +#define SPIM3_CSEL1_GPIO0 \ + ESP32_PINMUX(0, ESP_NOSIG, ESP_SPI3_CS1_OUT) + +#define SPIM3_CSEL1_GPIO1 \ + ESP32_PINMUX(1, ESP_NOSIG, ESP_SPI3_CS1_OUT) + +#define SPIM3_CSEL1_GPIO2 \ + ESP32_PINMUX(2, ESP_NOSIG, ESP_SPI3_CS1_OUT) + +#define SPIM3_CSEL1_GPIO3 \ + ESP32_PINMUX(3, ESP_NOSIG, ESP_SPI3_CS1_OUT) + +#define SPIM3_CSEL1_GPIO4 \ + ESP32_PINMUX(4, ESP_NOSIG, ESP_SPI3_CS1_OUT) + +#define SPIM3_CSEL1_GPIO5 \ + ESP32_PINMUX(5, ESP_NOSIG, ESP_SPI3_CS1_OUT) + +#define SPIM3_CSEL1_GPIO6 \ + ESP32_PINMUX(6, ESP_NOSIG, ESP_SPI3_CS1_OUT) + +#define SPIM3_CSEL1_GPIO7 \ + ESP32_PINMUX(7, ESP_NOSIG, ESP_SPI3_CS1_OUT) + +#define SPIM3_CSEL1_GPIO8 \ + ESP32_PINMUX(8, ESP_NOSIG, ESP_SPI3_CS1_OUT) + +#define SPIM3_CSEL1_GPIO9 \ + ESP32_PINMUX(9, ESP_NOSIG, ESP_SPI3_CS1_OUT) + +#define SPIM3_CSEL1_GPIO10 \ + ESP32_PINMUX(10, ESP_NOSIG, ESP_SPI3_CS1_OUT) + +#define SPIM3_CSEL1_GPIO11 \ + ESP32_PINMUX(11, ESP_NOSIG, ESP_SPI3_CS1_OUT) + +#define SPIM3_CSEL1_GPIO12 \ + ESP32_PINMUX(12, ESP_NOSIG, ESP_SPI3_CS1_OUT) + +#define SPIM3_CSEL1_GPIO13 \ + ESP32_PINMUX(13, ESP_NOSIG, ESP_SPI3_CS1_OUT) + +#define SPIM3_CSEL1_GPIO14 \ + ESP32_PINMUX(14, ESP_NOSIG, ESP_SPI3_CS1_OUT) + +#define SPIM3_CSEL1_GPIO15 \ + ESP32_PINMUX(15, ESP_NOSIG, ESP_SPI3_CS1_OUT) + +#define SPIM3_CSEL1_GPIO16 \ + ESP32_PINMUX(16, ESP_NOSIG, ESP_SPI3_CS1_OUT) + +#define SPIM3_CSEL1_GPIO17 \ + ESP32_PINMUX(17, ESP_NOSIG, ESP_SPI3_CS1_OUT) + +#define SPIM3_CSEL1_GPIO18 \ + ESP32_PINMUX(18, ESP_NOSIG, ESP_SPI3_CS1_OUT) + +#define SPIM3_CSEL1_GPIO19 \ + ESP32_PINMUX(19, ESP_NOSIG, ESP_SPI3_CS1_OUT) + +#define SPIM3_CSEL1_GPIO20 \ + ESP32_PINMUX(20, ESP_NOSIG, ESP_SPI3_CS1_OUT) + +#define SPIM3_CSEL1_GPIO21 \ + ESP32_PINMUX(21, ESP_NOSIG, ESP_SPI3_CS1_OUT) + +#define SPIM3_CSEL1_GPIO26 \ + ESP32_PINMUX(26, ESP_NOSIG, ESP_SPI3_CS1_OUT) + +#define SPIM3_CSEL1_GPIO27 \ + ESP32_PINMUX(27, ESP_NOSIG, ESP_SPI3_CS1_OUT) + +#define SPIM3_CSEL1_GPIO28 \ + ESP32_PINMUX(28, ESP_NOSIG, ESP_SPI3_CS1_OUT) + +#define SPIM3_CSEL1_GPIO29 \ + ESP32_PINMUX(29, ESP_NOSIG, ESP_SPI3_CS1_OUT) + +#define SPIM3_CSEL1_GPIO30 \ + ESP32_PINMUX(30, ESP_NOSIG, ESP_SPI3_CS1_OUT) + +#define SPIM3_CSEL1_GPIO31 \ + ESP32_PINMUX(31, ESP_NOSIG, ESP_SPI3_CS1_OUT) + +#define SPIM3_CSEL1_GPIO32 \ + ESP32_PINMUX(32, ESP_NOSIG, ESP_SPI3_CS1_OUT) + +#define SPIM3_CSEL1_GPIO33 \ + ESP32_PINMUX(33, ESP_NOSIG, ESP_SPI3_CS1_OUT) + +#define SPIM3_CSEL1_GPIO34 \ + ESP32_PINMUX(34, ESP_NOSIG, ESP_SPI3_CS1_OUT) + +#define SPIM3_CSEL1_GPIO35 \ + ESP32_PINMUX(35, ESP_NOSIG, ESP_SPI3_CS1_OUT) + +#define SPIM3_CSEL1_GPIO36 \ + ESP32_PINMUX(36, ESP_NOSIG, ESP_SPI3_CS1_OUT) + +#define SPIM3_CSEL1_GPIO37 \ + ESP32_PINMUX(37, ESP_NOSIG, ESP_SPI3_CS1_OUT) + +#define SPIM3_CSEL1_GPIO38 \ + ESP32_PINMUX(38, ESP_NOSIG, ESP_SPI3_CS1_OUT) + +#define SPIM3_CSEL1_GPIO39 \ + ESP32_PINMUX(39, ESP_NOSIG, ESP_SPI3_CS1_OUT) + +#define SPIM3_CSEL1_GPIO40 \ + ESP32_PINMUX(40, ESP_NOSIG, ESP_SPI3_CS1_OUT) + +#define SPIM3_CSEL1_GPIO41 \ + ESP32_PINMUX(41, ESP_NOSIG, ESP_SPI3_CS1_OUT) + +#define SPIM3_CSEL1_GPIO42 \ + ESP32_PINMUX(42, ESP_NOSIG, ESP_SPI3_CS1_OUT) + +#define SPIM3_CSEL1_GPIO43 \ + ESP32_PINMUX(43, ESP_NOSIG, ESP_SPI3_CS1_OUT) + +#define SPIM3_CSEL1_GPIO44 \ + ESP32_PINMUX(44, ESP_NOSIG, ESP_SPI3_CS1_OUT) + +#define SPIM3_CSEL1_GPIO45 \ + ESP32_PINMUX(45, ESP_NOSIG, ESP_SPI3_CS1_OUT) + +/* SPIM3_CSEL2 */ +#define SPIM3_CSEL2_GPIO0 \ + ESP32_PINMUX(0, ESP_NOSIG, ESP_SPI3_CS2_OUT) + +#define SPIM3_CSEL2_GPIO1 \ + ESP32_PINMUX(1, ESP_NOSIG, ESP_SPI3_CS2_OUT) + +#define SPIM3_CSEL2_GPIO2 \ + ESP32_PINMUX(2, ESP_NOSIG, ESP_SPI3_CS2_OUT) + +#define SPIM3_CSEL2_GPIO3 \ + ESP32_PINMUX(3, ESP_NOSIG, ESP_SPI3_CS2_OUT) + +#define SPIM3_CSEL2_GPIO4 \ + ESP32_PINMUX(4, ESP_NOSIG, ESP_SPI3_CS2_OUT) + +#define SPIM3_CSEL2_GPIO5 \ + ESP32_PINMUX(5, ESP_NOSIG, ESP_SPI3_CS2_OUT) + +#define SPIM3_CSEL2_GPIO6 \ + ESP32_PINMUX(6, ESP_NOSIG, ESP_SPI3_CS2_OUT) + +#define SPIM3_CSEL2_GPIO7 \ + ESP32_PINMUX(7, ESP_NOSIG, ESP_SPI3_CS2_OUT) + +#define SPIM3_CSEL2_GPIO8 \ + ESP32_PINMUX(8, ESP_NOSIG, ESP_SPI3_CS2_OUT) + +#define SPIM3_CSEL2_GPIO9 \ + ESP32_PINMUX(9, ESP_NOSIG, ESP_SPI3_CS2_OUT) + +#define SPIM3_CSEL2_GPIO10 \ + ESP32_PINMUX(10, ESP_NOSIG, ESP_SPI3_CS2_OUT) + +#define SPIM3_CSEL2_GPIO11 \ + ESP32_PINMUX(11, ESP_NOSIG, ESP_SPI3_CS2_OUT) + +#define SPIM3_CSEL2_GPIO12 \ + ESP32_PINMUX(12, ESP_NOSIG, ESP_SPI3_CS2_OUT) + +#define SPIM3_CSEL2_GPIO13 \ + ESP32_PINMUX(13, ESP_NOSIG, ESP_SPI3_CS2_OUT) + +#define SPIM3_CSEL2_GPIO14 \ + ESP32_PINMUX(14, ESP_NOSIG, ESP_SPI3_CS2_OUT) + +#define SPIM3_CSEL2_GPIO15 \ + ESP32_PINMUX(15, ESP_NOSIG, ESP_SPI3_CS2_OUT) + +#define SPIM3_CSEL2_GPIO16 \ + ESP32_PINMUX(16, ESP_NOSIG, ESP_SPI3_CS2_OUT) + +#define SPIM3_CSEL2_GPIO17 \ + ESP32_PINMUX(17, ESP_NOSIG, ESP_SPI3_CS2_OUT) + +#define SPIM3_CSEL2_GPIO18 \ + ESP32_PINMUX(18, ESP_NOSIG, ESP_SPI3_CS2_OUT) + +#define SPIM3_CSEL2_GPIO19 \ + ESP32_PINMUX(19, ESP_NOSIG, ESP_SPI3_CS2_OUT) + +#define SPIM3_CSEL2_GPIO20 \ + ESP32_PINMUX(20, ESP_NOSIG, ESP_SPI3_CS2_OUT) + +#define SPIM3_CSEL2_GPIO21 \ + ESP32_PINMUX(21, ESP_NOSIG, ESP_SPI3_CS2_OUT) + +#define SPIM3_CSEL2_GPIO26 \ + ESP32_PINMUX(26, ESP_NOSIG, ESP_SPI3_CS2_OUT) + +#define SPIM3_CSEL2_GPIO27 \ + ESP32_PINMUX(27, ESP_NOSIG, ESP_SPI3_CS2_OUT) + +#define SPIM3_CSEL2_GPIO28 \ + ESP32_PINMUX(28, ESP_NOSIG, ESP_SPI3_CS2_OUT) + +#define SPIM3_CSEL2_GPIO29 \ + ESP32_PINMUX(29, ESP_NOSIG, ESP_SPI3_CS2_OUT) + +#define SPIM3_CSEL2_GPIO30 \ + ESP32_PINMUX(30, ESP_NOSIG, ESP_SPI3_CS2_OUT) + +#define SPIM3_CSEL2_GPIO31 \ + ESP32_PINMUX(31, ESP_NOSIG, ESP_SPI3_CS2_OUT) + +#define SPIM3_CSEL2_GPIO32 \ + ESP32_PINMUX(32, ESP_NOSIG, ESP_SPI3_CS2_OUT) + +#define SPIM3_CSEL2_GPIO33 \ + ESP32_PINMUX(33, ESP_NOSIG, ESP_SPI3_CS2_OUT) + +#define SPIM3_CSEL2_GPIO34 \ + ESP32_PINMUX(34, ESP_NOSIG, ESP_SPI3_CS2_OUT) + +#define SPIM3_CSEL2_GPIO35 \ + ESP32_PINMUX(35, ESP_NOSIG, ESP_SPI3_CS2_OUT) + +#define SPIM3_CSEL2_GPIO36 \ + ESP32_PINMUX(36, ESP_NOSIG, ESP_SPI3_CS2_OUT) + +#define SPIM3_CSEL2_GPIO37 \ + ESP32_PINMUX(37, ESP_NOSIG, ESP_SPI3_CS2_OUT) + +#define SPIM3_CSEL2_GPIO38 \ + ESP32_PINMUX(38, ESP_NOSIG, ESP_SPI3_CS2_OUT) + +#define SPIM3_CSEL2_GPIO39 \ + ESP32_PINMUX(39, ESP_NOSIG, ESP_SPI3_CS2_OUT) + +#define SPIM3_CSEL2_GPIO40 \ + ESP32_PINMUX(40, ESP_NOSIG, ESP_SPI3_CS2_OUT) + +#define SPIM3_CSEL2_GPIO41 \ + ESP32_PINMUX(41, ESP_NOSIG, ESP_SPI3_CS2_OUT) + +#define SPIM3_CSEL2_GPIO42 \ + ESP32_PINMUX(42, ESP_NOSIG, ESP_SPI3_CS2_OUT) + +#define SPIM3_CSEL2_GPIO43 \ + ESP32_PINMUX(43, ESP_NOSIG, ESP_SPI3_CS2_OUT) + +#define SPIM3_CSEL2_GPIO44 \ + ESP32_PINMUX(44, ESP_NOSIG, ESP_SPI3_CS2_OUT) + +#define SPIM3_CSEL2_GPIO45 \ + ESP32_PINMUX(45, ESP_NOSIG, ESP_SPI3_CS2_OUT) + +/* SPIM3_MISO */ +#define SPIM3_MISO_GPIO0 \ + ESP32_PINMUX(0, ESP_SPI3_Q_IN, ESP_NOSIG) + +#define SPIM3_MISO_GPIO1 \ + ESP32_PINMUX(1, ESP_SPI3_Q_IN, ESP_NOSIG) + +#define SPIM3_MISO_GPIO2 \ + ESP32_PINMUX(2, ESP_SPI3_Q_IN, ESP_NOSIG) + +#define SPIM3_MISO_GPIO3 \ + ESP32_PINMUX(3, ESP_SPI3_Q_IN, ESP_NOSIG) + +#define SPIM3_MISO_GPIO4 \ + ESP32_PINMUX(4, ESP_SPI3_Q_IN, ESP_NOSIG) + +#define SPIM3_MISO_GPIO5 \ + ESP32_PINMUX(5, ESP_SPI3_Q_IN, ESP_NOSIG) + +#define SPIM3_MISO_GPIO6 \ + ESP32_PINMUX(6, ESP_SPI3_Q_IN, ESP_NOSIG) + +#define SPIM3_MISO_GPIO7 \ + ESP32_PINMUX(7, ESP_SPI3_Q_IN, ESP_NOSIG) + +#define SPIM3_MISO_GPIO8 \ + ESP32_PINMUX(8, ESP_SPI3_Q_IN, ESP_NOSIG) + +#define SPIM3_MISO_GPIO9 \ + ESP32_PINMUX(9, ESP_SPI3_Q_IN, ESP_NOSIG) + +#define SPIM3_MISO_GPIO10 \ + ESP32_PINMUX(10, ESP_SPI3_Q_IN, ESP_NOSIG) + +#define SPIM3_MISO_GPIO11 \ + ESP32_PINMUX(11, ESP_SPI3_Q_IN, ESP_NOSIG) + +#define SPIM3_MISO_GPIO12 \ + ESP32_PINMUX(12, ESP_SPI3_Q_IN, ESP_NOSIG) + +#define SPIM3_MISO_GPIO13 \ + ESP32_PINMUX(13, ESP_SPI3_Q_IN, ESP_NOSIG) + +#define SPIM3_MISO_GPIO14 \ + ESP32_PINMUX(14, ESP_SPI3_Q_IN, ESP_NOSIG) + +#define SPIM3_MISO_GPIO15 \ + ESP32_PINMUX(15, ESP_SPI3_Q_IN, ESP_NOSIG) + +#define SPIM3_MISO_GPIO16 \ + ESP32_PINMUX(16, ESP_SPI3_Q_IN, ESP_NOSIG) + +#define SPIM3_MISO_GPIO17 \ + ESP32_PINMUX(17, ESP_SPI3_Q_IN, ESP_NOSIG) + +#define SPIM3_MISO_GPIO18 \ + ESP32_PINMUX(18, ESP_SPI3_Q_IN, ESP_NOSIG) + +#define SPIM3_MISO_GPIO19 \ + ESP32_PINMUX(19, ESP_SPI3_Q_IN, ESP_NOSIG) + +#define SPIM3_MISO_GPIO20 \ + ESP32_PINMUX(20, ESP_SPI3_Q_IN, ESP_NOSIG) + +#define SPIM3_MISO_GPIO21 \ + ESP32_PINMUX(21, ESP_SPI3_Q_IN, ESP_NOSIG) + +#define SPIM3_MISO_GPIO26 \ + ESP32_PINMUX(26, ESP_SPI3_Q_IN, ESP_NOSIG) + +#define SPIM3_MISO_GPIO27 \ + ESP32_PINMUX(27, ESP_SPI3_Q_IN, ESP_NOSIG) + +#define SPIM3_MISO_GPIO28 \ + ESP32_PINMUX(28, ESP_SPI3_Q_IN, ESP_NOSIG) + +#define SPIM3_MISO_GPIO29 \ + ESP32_PINMUX(29, ESP_SPI3_Q_IN, ESP_NOSIG) + +#define SPIM3_MISO_GPIO30 \ + ESP32_PINMUX(30, ESP_SPI3_Q_IN, ESP_NOSIG) + +#define SPIM3_MISO_GPIO31 \ + ESP32_PINMUX(31, ESP_SPI3_Q_IN, ESP_NOSIG) + +#define SPIM3_MISO_GPIO32 \ + ESP32_PINMUX(32, ESP_SPI3_Q_IN, ESP_NOSIG) + +#define SPIM3_MISO_GPIO33 \ + ESP32_PINMUX(33, ESP_SPI3_Q_IN, ESP_NOSIG) + +#define SPIM3_MISO_GPIO34 \ + ESP32_PINMUX(34, ESP_SPI3_Q_IN, ESP_NOSIG) + +#define SPIM3_MISO_GPIO35 \ + ESP32_PINMUX(35, ESP_SPI3_Q_IN, ESP_NOSIG) + +#define SPIM3_MISO_GPIO36 \ + ESP32_PINMUX(36, ESP_SPI3_Q_IN, ESP_NOSIG) + +#define SPIM3_MISO_GPIO37 \ + ESP32_PINMUX(37, ESP_SPI3_Q_IN, ESP_NOSIG) + +#define SPIM3_MISO_GPIO38 \ + ESP32_PINMUX(38, ESP_SPI3_Q_IN, ESP_NOSIG) + +#define SPIM3_MISO_GPIO39 \ + ESP32_PINMUX(39, ESP_SPI3_Q_IN, ESP_NOSIG) + +#define SPIM3_MISO_GPIO40 \ + ESP32_PINMUX(40, ESP_SPI3_Q_IN, ESP_NOSIG) + +#define SPIM3_MISO_GPIO41 \ + ESP32_PINMUX(41, ESP_SPI3_Q_IN, ESP_NOSIG) + +#define SPIM3_MISO_GPIO42 \ + ESP32_PINMUX(42, ESP_SPI3_Q_IN, ESP_NOSIG) + +#define SPIM3_MISO_GPIO43 \ + ESP32_PINMUX(43, ESP_SPI3_Q_IN, ESP_NOSIG) + +#define SPIM3_MISO_GPIO44 \ + ESP32_PINMUX(44, ESP_SPI3_Q_IN, ESP_NOSIG) + +#define SPIM3_MISO_GPIO45 \ + ESP32_PINMUX(45, ESP_SPI3_Q_IN, ESP_NOSIG) + +#define SPIM3_MISO_GPIO46 \ + ESP32_PINMUX(46, ESP_SPI3_Q_IN, ESP_NOSIG) + +/* SPIM3_MOSI */ +#define SPIM3_MOSI_GPIO0 \ + ESP32_PINMUX(0, ESP_NOSIG, ESP_SPI3_D_OUT) + +#define SPIM3_MOSI_GPIO1 \ + ESP32_PINMUX(1, ESP_NOSIG, ESP_SPI3_D_OUT) + +#define SPIM3_MOSI_GPIO2 \ + ESP32_PINMUX(2, ESP_NOSIG, ESP_SPI3_D_OUT) + +#define SPIM3_MOSI_GPIO3 \ + ESP32_PINMUX(3, ESP_NOSIG, ESP_SPI3_D_OUT) + +#define SPIM3_MOSI_GPIO4 \ + ESP32_PINMUX(4, ESP_NOSIG, ESP_SPI3_D_OUT) + +#define SPIM3_MOSI_GPIO5 \ + ESP32_PINMUX(5, ESP_NOSIG, ESP_SPI3_D_OUT) + +#define SPIM3_MOSI_GPIO6 \ + ESP32_PINMUX(6, ESP_NOSIG, ESP_SPI3_D_OUT) + +#define SPIM3_MOSI_GPIO7 \ + ESP32_PINMUX(7, ESP_NOSIG, ESP_SPI3_D_OUT) + +#define SPIM3_MOSI_GPIO8 \ + ESP32_PINMUX(8, ESP_NOSIG, ESP_SPI3_D_OUT) + +#define SPIM3_MOSI_GPIO9 \ + ESP32_PINMUX(9, ESP_NOSIG, ESP_SPI3_D_OUT) + +#define SPIM3_MOSI_GPIO10 \ + ESP32_PINMUX(10, ESP_NOSIG, ESP_SPI3_D_OUT) + +#define SPIM3_MOSI_GPIO11 \ + ESP32_PINMUX(11, ESP_NOSIG, ESP_SPI3_D_OUT) + +#define SPIM3_MOSI_GPIO12 \ + ESP32_PINMUX(12, ESP_NOSIG, ESP_SPI3_D_OUT) + +#define SPIM3_MOSI_GPIO13 \ + ESP32_PINMUX(13, ESP_NOSIG, ESP_SPI3_D_OUT) + +#define SPIM3_MOSI_GPIO14 \ + ESP32_PINMUX(14, ESP_NOSIG, ESP_SPI3_D_OUT) + +#define SPIM3_MOSI_GPIO15 \ + ESP32_PINMUX(15, ESP_NOSIG, ESP_SPI3_D_OUT) + +#define SPIM3_MOSI_GPIO16 \ + ESP32_PINMUX(16, ESP_NOSIG, ESP_SPI3_D_OUT) + +#define SPIM3_MOSI_GPIO17 \ + ESP32_PINMUX(17, ESP_NOSIG, ESP_SPI3_D_OUT) + +#define SPIM3_MOSI_GPIO18 \ + ESP32_PINMUX(18, ESP_NOSIG, ESP_SPI3_D_OUT) + +#define SPIM3_MOSI_GPIO19 \ + ESP32_PINMUX(19, ESP_NOSIG, ESP_SPI3_D_OUT) + +#define SPIM3_MOSI_GPIO20 \ + ESP32_PINMUX(20, ESP_NOSIG, ESP_SPI3_D_OUT) + +#define SPIM3_MOSI_GPIO21 \ + ESP32_PINMUX(21, ESP_NOSIG, ESP_SPI3_D_OUT) + +#define SPIM3_MOSI_GPIO26 \ + ESP32_PINMUX(26, ESP_NOSIG, ESP_SPI3_D_OUT) + +#define SPIM3_MOSI_GPIO27 \ + ESP32_PINMUX(27, ESP_NOSIG, ESP_SPI3_D_OUT) + +#define SPIM3_MOSI_GPIO28 \ + ESP32_PINMUX(28, ESP_NOSIG, ESP_SPI3_D_OUT) + +#define SPIM3_MOSI_GPIO29 \ + ESP32_PINMUX(29, ESP_NOSIG, ESP_SPI3_D_OUT) + +#define SPIM3_MOSI_GPIO30 \ + ESP32_PINMUX(30, ESP_NOSIG, ESP_SPI3_D_OUT) + +#define SPIM3_MOSI_GPIO31 \ + ESP32_PINMUX(31, ESP_NOSIG, ESP_SPI3_D_OUT) + +#define SPIM3_MOSI_GPIO32 \ + ESP32_PINMUX(32, ESP_NOSIG, ESP_SPI3_D_OUT) + +#define SPIM3_MOSI_GPIO33 \ + ESP32_PINMUX(33, ESP_NOSIG, ESP_SPI3_D_OUT) + +#define SPIM3_MOSI_GPIO34 \ + ESP32_PINMUX(34, ESP_NOSIG, ESP_SPI3_D_OUT) + +#define SPIM3_MOSI_GPIO35 \ + ESP32_PINMUX(35, ESP_NOSIG, ESP_SPI3_D_OUT) + +#define SPIM3_MOSI_GPIO36 \ + ESP32_PINMUX(36, ESP_NOSIG, ESP_SPI3_D_OUT) + +#define SPIM3_MOSI_GPIO37 \ + ESP32_PINMUX(37, ESP_NOSIG, ESP_SPI3_D_OUT) + +#define SPIM3_MOSI_GPIO38 \ + ESP32_PINMUX(38, ESP_NOSIG, ESP_SPI3_D_OUT) + +#define SPIM3_MOSI_GPIO39 \ + ESP32_PINMUX(39, ESP_NOSIG, ESP_SPI3_D_OUT) + +#define SPIM3_MOSI_GPIO40 \ + ESP32_PINMUX(40, ESP_NOSIG, ESP_SPI3_D_OUT) + +#define SPIM3_MOSI_GPIO41 \ + ESP32_PINMUX(41, ESP_NOSIG, ESP_SPI3_D_OUT) + +#define SPIM3_MOSI_GPIO42 \ + ESP32_PINMUX(42, ESP_NOSIG, ESP_SPI3_D_OUT) + +#define SPIM3_MOSI_GPIO43 \ + ESP32_PINMUX(43, ESP_NOSIG, ESP_SPI3_D_OUT) + +#define SPIM3_MOSI_GPIO44 \ + ESP32_PINMUX(44, ESP_NOSIG, ESP_SPI3_D_OUT) + +#define SPIM3_MOSI_GPIO45 \ + ESP32_PINMUX(45, ESP_NOSIG, ESP_SPI3_D_OUT) + +/* SPIM3_SCLK */ +#define SPIM3_SCLK_GPIO0 \ + ESP32_PINMUX(0, ESP_NOSIG, ESP_SPI3_CLK_OUT_MUX) + +#define SPIM3_SCLK_GPIO1 \ + ESP32_PINMUX(1, ESP_NOSIG, ESP_SPI3_CLK_OUT_MUX) + +#define SPIM3_SCLK_GPIO2 \ + ESP32_PINMUX(2, ESP_NOSIG, ESP_SPI3_CLK_OUT_MUX) + +#define SPIM3_SCLK_GPIO3 \ + ESP32_PINMUX(3, ESP_NOSIG, ESP_SPI3_CLK_OUT_MUX) + +#define SPIM3_SCLK_GPIO4 \ + ESP32_PINMUX(4, ESP_NOSIG, ESP_SPI3_CLK_OUT_MUX) + +#define SPIM3_SCLK_GPIO5 \ + ESP32_PINMUX(5, ESP_NOSIG, ESP_SPI3_CLK_OUT_MUX) + +#define SPIM3_SCLK_GPIO6 \ + ESP32_PINMUX(6, ESP_NOSIG, ESP_SPI3_CLK_OUT_MUX) + +#define SPIM3_SCLK_GPIO7 \ + ESP32_PINMUX(7, ESP_NOSIG, ESP_SPI3_CLK_OUT_MUX) + +#define SPIM3_SCLK_GPIO8 \ + ESP32_PINMUX(8, ESP_NOSIG, ESP_SPI3_CLK_OUT_MUX) + +#define SPIM3_SCLK_GPIO9 \ + ESP32_PINMUX(9, ESP_NOSIG, ESP_SPI3_CLK_OUT_MUX) + +#define SPIM3_SCLK_GPIO10 \ + ESP32_PINMUX(10, ESP_NOSIG, ESP_SPI3_CLK_OUT_MUX) + +#define SPIM3_SCLK_GPIO11 \ + ESP32_PINMUX(11, ESP_NOSIG, ESP_SPI3_CLK_OUT_MUX) + +#define SPIM3_SCLK_GPIO12 \ + ESP32_PINMUX(12, ESP_NOSIG, ESP_SPI3_CLK_OUT_MUX) + +#define SPIM3_SCLK_GPIO13 \ + ESP32_PINMUX(13, ESP_NOSIG, ESP_SPI3_CLK_OUT_MUX) + +#define SPIM3_SCLK_GPIO14 \ + ESP32_PINMUX(14, ESP_NOSIG, ESP_SPI3_CLK_OUT_MUX) + +#define SPIM3_SCLK_GPIO15 \ + ESP32_PINMUX(15, ESP_NOSIG, ESP_SPI3_CLK_OUT_MUX) + +#define SPIM3_SCLK_GPIO16 \ + ESP32_PINMUX(16, ESP_NOSIG, ESP_SPI3_CLK_OUT_MUX) + +#define SPIM3_SCLK_GPIO17 \ + ESP32_PINMUX(17, ESP_NOSIG, ESP_SPI3_CLK_OUT_MUX) + +#define SPIM3_SCLK_GPIO18 \ + ESP32_PINMUX(18, ESP_NOSIG, ESP_SPI3_CLK_OUT_MUX) + +#define SPIM3_SCLK_GPIO19 \ + ESP32_PINMUX(19, ESP_NOSIG, ESP_SPI3_CLK_OUT_MUX) + +#define SPIM3_SCLK_GPIO20 \ + ESP32_PINMUX(20, ESP_NOSIG, ESP_SPI3_CLK_OUT_MUX) + +#define SPIM3_SCLK_GPIO21 \ + ESP32_PINMUX(21, ESP_NOSIG, ESP_SPI3_CLK_OUT_MUX) + +#define SPIM3_SCLK_GPIO26 \ + ESP32_PINMUX(26, ESP_NOSIG, ESP_SPI3_CLK_OUT_MUX) + +#define SPIM3_SCLK_GPIO27 \ + ESP32_PINMUX(27, ESP_NOSIG, ESP_SPI3_CLK_OUT_MUX) + +#define SPIM3_SCLK_GPIO28 \ + ESP32_PINMUX(28, ESP_NOSIG, ESP_SPI3_CLK_OUT_MUX) + +#define SPIM3_SCLK_GPIO29 \ + ESP32_PINMUX(29, ESP_NOSIG, ESP_SPI3_CLK_OUT_MUX) + +#define SPIM3_SCLK_GPIO30 \ + ESP32_PINMUX(30, ESP_NOSIG, ESP_SPI3_CLK_OUT_MUX) + +#define SPIM3_SCLK_GPIO31 \ + ESP32_PINMUX(31, ESP_NOSIG, ESP_SPI3_CLK_OUT_MUX) + +#define SPIM3_SCLK_GPIO32 \ + ESP32_PINMUX(32, ESP_NOSIG, ESP_SPI3_CLK_OUT_MUX) + +#define SPIM3_SCLK_GPIO33 \ + ESP32_PINMUX(33, ESP_NOSIG, ESP_SPI3_CLK_OUT_MUX) + +#define SPIM3_SCLK_GPIO34 \ + ESP32_PINMUX(34, ESP_NOSIG, ESP_SPI3_CLK_OUT_MUX) + +#define SPIM3_SCLK_GPIO35 \ + ESP32_PINMUX(35, ESP_NOSIG, ESP_SPI3_CLK_OUT_MUX) + +#define SPIM3_SCLK_GPIO36 \ + ESP32_PINMUX(36, ESP_NOSIG, ESP_SPI3_CLK_OUT_MUX) + +#define SPIM3_SCLK_GPIO37 \ + ESP32_PINMUX(37, ESP_NOSIG, ESP_SPI3_CLK_OUT_MUX) + +#define SPIM3_SCLK_GPIO38 \ + ESP32_PINMUX(38, ESP_NOSIG, ESP_SPI3_CLK_OUT_MUX) + +#define SPIM3_SCLK_GPIO39 \ + ESP32_PINMUX(39, ESP_NOSIG, ESP_SPI3_CLK_OUT_MUX) + +#define SPIM3_SCLK_GPIO40 \ + ESP32_PINMUX(40, ESP_NOSIG, ESP_SPI3_CLK_OUT_MUX) + +#define SPIM3_SCLK_GPIO41 \ + ESP32_PINMUX(41, ESP_NOSIG, ESP_SPI3_CLK_OUT_MUX) + +#define SPIM3_SCLK_GPIO42 \ + ESP32_PINMUX(42, ESP_NOSIG, ESP_SPI3_CLK_OUT_MUX) + +#define SPIM3_SCLK_GPIO43 \ + ESP32_PINMUX(43, ESP_NOSIG, ESP_SPI3_CLK_OUT_MUX) + +#define SPIM3_SCLK_GPIO44 \ + ESP32_PINMUX(44, ESP_NOSIG, ESP_SPI3_CLK_OUT_MUX) + +#define SPIM3_SCLK_GPIO45 \ + ESP32_PINMUX(45, ESP_NOSIG, ESP_SPI3_CLK_OUT_MUX) + +/* TWAI_BUS_OFF */ +#define TWAI_BUS_OFF_GPIO0 \ + ESP32_PINMUX(0, ESP_NOSIG, ESP_TWAI_BUS_OFF_ON) + +#define TWAI_BUS_OFF_GPIO1 \ + ESP32_PINMUX(1, ESP_NOSIG, ESP_TWAI_BUS_OFF_ON) + +#define TWAI_BUS_OFF_GPIO2 \ + ESP32_PINMUX(2, ESP_NOSIG, ESP_TWAI_BUS_OFF_ON) + +#define TWAI_BUS_OFF_GPIO3 \ + ESP32_PINMUX(3, ESP_NOSIG, ESP_TWAI_BUS_OFF_ON) + +#define TWAI_BUS_OFF_GPIO4 \ + ESP32_PINMUX(4, ESP_NOSIG, ESP_TWAI_BUS_OFF_ON) + +#define TWAI_BUS_OFF_GPIO5 \ + ESP32_PINMUX(5, ESP_NOSIG, ESP_TWAI_BUS_OFF_ON) + +#define TWAI_BUS_OFF_GPIO6 \ + ESP32_PINMUX(6, ESP_NOSIG, ESP_TWAI_BUS_OFF_ON) + +#define TWAI_BUS_OFF_GPIO7 \ + ESP32_PINMUX(7, ESP_NOSIG, ESP_TWAI_BUS_OFF_ON) + +#define TWAI_BUS_OFF_GPIO8 \ + ESP32_PINMUX(8, ESP_NOSIG, ESP_TWAI_BUS_OFF_ON) + +#define TWAI_BUS_OFF_GPIO9 \ + ESP32_PINMUX(9, ESP_NOSIG, ESP_TWAI_BUS_OFF_ON) + +#define TWAI_BUS_OFF_GPIO10 \ + ESP32_PINMUX(10, ESP_NOSIG, ESP_TWAI_BUS_OFF_ON) + +#define TWAI_BUS_OFF_GPIO11 \ + ESP32_PINMUX(11, ESP_NOSIG, ESP_TWAI_BUS_OFF_ON) + +#define TWAI_BUS_OFF_GPIO12 \ + ESP32_PINMUX(12, ESP_NOSIG, ESP_TWAI_BUS_OFF_ON) + +#define TWAI_BUS_OFF_GPIO13 \ + ESP32_PINMUX(13, ESP_NOSIG, ESP_TWAI_BUS_OFF_ON) + +#define TWAI_BUS_OFF_GPIO14 \ + ESP32_PINMUX(14, ESP_NOSIG, ESP_TWAI_BUS_OFF_ON) + +#define TWAI_BUS_OFF_GPIO15 \ + ESP32_PINMUX(15, ESP_NOSIG, ESP_TWAI_BUS_OFF_ON) + +#define TWAI_BUS_OFF_GPIO16 \ + ESP32_PINMUX(16, ESP_NOSIG, ESP_TWAI_BUS_OFF_ON) + +#define TWAI_BUS_OFF_GPIO17 \ + ESP32_PINMUX(17, ESP_NOSIG, ESP_TWAI_BUS_OFF_ON) + +#define TWAI_BUS_OFF_GPIO18 \ + ESP32_PINMUX(18, ESP_NOSIG, ESP_TWAI_BUS_OFF_ON) + +#define TWAI_BUS_OFF_GPIO19 \ + ESP32_PINMUX(19, ESP_NOSIG, ESP_TWAI_BUS_OFF_ON) + +#define TWAI_BUS_OFF_GPIO20 \ + ESP32_PINMUX(20, ESP_NOSIG, ESP_TWAI_BUS_OFF_ON) + +#define TWAI_BUS_OFF_GPIO21 \ + ESP32_PINMUX(21, ESP_NOSIG, ESP_TWAI_BUS_OFF_ON) + +#define TWAI_BUS_OFF_GPIO26 \ + ESP32_PINMUX(26, ESP_NOSIG, ESP_TWAI_BUS_OFF_ON) + +#define TWAI_BUS_OFF_GPIO27 \ + ESP32_PINMUX(27, ESP_NOSIG, ESP_TWAI_BUS_OFF_ON) + +#define TWAI_BUS_OFF_GPIO28 \ + ESP32_PINMUX(28, ESP_NOSIG, ESP_TWAI_BUS_OFF_ON) + +#define TWAI_BUS_OFF_GPIO29 \ + ESP32_PINMUX(29, ESP_NOSIG, ESP_TWAI_BUS_OFF_ON) + +#define TWAI_BUS_OFF_GPIO30 \ + ESP32_PINMUX(30, ESP_NOSIG, ESP_TWAI_BUS_OFF_ON) + +#define TWAI_BUS_OFF_GPIO31 \ + ESP32_PINMUX(31, ESP_NOSIG, ESP_TWAI_BUS_OFF_ON) + +#define TWAI_BUS_OFF_GPIO32 \ + ESP32_PINMUX(32, ESP_NOSIG, ESP_TWAI_BUS_OFF_ON) + +#define TWAI_BUS_OFF_GPIO33 \ + ESP32_PINMUX(33, ESP_NOSIG, ESP_TWAI_BUS_OFF_ON) + +#define TWAI_BUS_OFF_GPIO34 \ + ESP32_PINMUX(34, ESP_NOSIG, ESP_TWAI_BUS_OFF_ON) + +#define TWAI_BUS_OFF_GPIO35 \ + ESP32_PINMUX(35, ESP_NOSIG, ESP_TWAI_BUS_OFF_ON) + +#define TWAI_BUS_OFF_GPIO36 \ + ESP32_PINMUX(36, ESP_NOSIG, ESP_TWAI_BUS_OFF_ON) + +#define TWAI_BUS_OFF_GPIO37 \ + ESP32_PINMUX(37, ESP_NOSIG, ESP_TWAI_BUS_OFF_ON) + +#define TWAI_BUS_OFF_GPIO38 \ + ESP32_PINMUX(38, ESP_NOSIG, ESP_TWAI_BUS_OFF_ON) + +#define TWAI_BUS_OFF_GPIO39 \ + ESP32_PINMUX(39, ESP_NOSIG, ESP_TWAI_BUS_OFF_ON) + +#define TWAI_BUS_OFF_GPIO40 \ + ESP32_PINMUX(40, ESP_NOSIG, ESP_TWAI_BUS_OFF_ON) + +#define TWAI_BUS_OFF_GPIO41 \ + ESP32_PINMUX(41, ESP_NOSIG, ESP_TWAI_BUS_OFF_ON) + +#define TWAI_BUS_OFF_GPIO42 \ + ESP32_PINMUX(42, ESP_NOSIG, ESP_TWAI_BUS_OFF_ON) + +#define TWAI_BUS_OFF_GPIO43 \ + ESP32_PINMUX(43, ESP_NOSIG, ESP_TWAI_BUS_OFF_ON) + +#define TWAI_BUS_OFF_GPIO44 \ + ESP32_PINMUX(44, ESP_NOSIG, ESP_TWAI_BUS_OFF_ON) + +#define TWAI_BUS_OFF_GPIO45 \ + ESP32_PINMUX(45, ESP_NOSIG, ESP_TWAI_BUS_OFF_ON) + +/* TWAI_CLKOUT */ +#define TWAI_CLKOUT_GPIO0 \ + ESP32_PINMUX(0, ESP_NOSIG, ESP_TWAI_CLKOUT) + +#define TWAI_CLKOUT_GPIO1 \ + ESP32_PINMUX(1, ESP_NOSIG, ESP_TWAI_CLKOUT) + +#define TWAI_CLKOUT_GPIO2 \ + ESP32_PINMUX(2, ESP_NOSIG, ESP_TWAI_CLKOUT) + +#define TWAI_CLKOUT_GPIO3 \ + ESP32_PINMUX(3, ESP_NOSIG, ESP_TWAI_CLKOUT) + +#define TWAI_CLKOUT_GPIO4 \ + ESP32_PINMUX(4, ESP_NOSIG, ESP_TWAI_CLKOUT) + +#define TWAI_CLKOUT_GPIO5 \ + ESP32_PINMUX(5, ESP_NOSIG, ESP_TWAI_CLKOUT) + +#define TWAI_CLKOUT_GPIO6 \ + ESP32_PINMUX(6, ESP_NOSIG, ESP_TWAI_CLKOUT) + +#define TWAI_CLKOUT_GPIO7 \ + ESP32_PINMUX(7, ESP_NOSIG, ESP_TWAI_CLKOUT) + +#define TWAI_CLKOUT_GPIO8 \ + ESP32_PINMUX(8, ESP_NOSIG, ESP_TWAI_CLKOUT) + +#define TWAI_CLKOUT_GPIO9 \ + ESP32_PINMUX(9, ESP_NOSIG, ESP_TWAI_CLKOUT) + +#define TWAI_CLKOUT_GPIO10 \ + ESP32_PINMUX(10, ESP_NOSIG, ESP_TWAI_CLKOUT) + +#define TWAI_CLKOUT_GPIO11 \ + ESP32_PINMUX(11, ESP_NOSIG, ESP_TWAI_CLKOUT) + +#define TWAI_CLKOUT_GPIO12 \ + ESP32_PINMUX(12, ESP_NOSIG, ESP_TWAI_CLKOUT) + +#define TWAI_CLKOUT_GPIO13 \ + ESP32_PINMUX(13, ESP_NOSIG, ESP_TWAI_CLKOUT) + +#define TWAI_CLKOUT_GPIO14 \ + ESP32_PINMUX(14, ESP_NOSIG, ESP_TWAI_CLKOUT) + +#define TWAI_CLKOUT_GPIO15 \ + ESP32_PINMUX(15, ESP_NOSIG, ESP_TWAI_CLKOUT) + +#define TWAI_CLKOUT_GPIO16 \ + ESP32_PINMUX(16, ESP_NOSIG, ESP_TWAI_CLKOUT) + +#define TWAI_CLKOUT_GPIO17 \ + ESP32_PINMUX(17, ESP_NOSIG, ESP_TWAI_CLKOUT) + +#define TWAI_CLKOUT_GPIO18 \ + ESP32_PINMUX(18, ESP_NOSIG, ESP_TWAI_CLKOUT) + +#define TWAI_CLKOUT_GPIO19 \ + ESP32_PINMUX(19, ESP_NOSIG, ESP_TWAI_CLKOUT) + +#define TWAI_CLKOUT_GPIO20 \ + ESP32_PINMUX(20, ESP_NOSIG, ESP_TWAI_CLKOUT) + +#define TWAI_CLKOUT_GPIO21 \ + ESP32_PINMUX(21, ESP_NOSIG, ESP_TWAI_CLKOUT) + +#define TWAI_CLKOUT_GPIO26 \ + ESP32_PINMUX(26, ESP_NOSIG, ESP_TWAI_CLKOUT) + +#define TWAI_CLKOUT_GPIO27 \ + ESP32_PINMUX(27, ESP_NOSIG, ESP_TWAI_CLKOUT) + +#define TWAI_CLKOUT_GPIO28 \ + ESP32_PINMUX(28, ESP_NOSIG, ESP_TWAI_CLKOUT) + +#define TWAI_CLKOUT_GPIO29 \ + ESP32_PINMUX(29, ESP_NOSIG, ESP_TWAI_CLKOUT) + +#define TWAI_CLKOUT_GPIO30 \ + ESP32_PINMUX(30, ESP_NOSIG, ESP_TWAI_CLKOUT) + +#define TWAI_CLKOUT_GPIO31 \ + ESP32_PINMUX(31, ESP_NOSIG, ESP_TWAI_CLKOUT) + +#define TWAI_CLKOUT_GPIO32 \ + ESP32_PINMUX(32, ESP_NOSIG, ESP_TWAI_CLKOUT) + +#define TWAI_CLKOUT_GPIO33 \ + ESP32_PINMUX(33, ESP_NOSIG, ESP_TWAI_CLKOUT) + +#define TWAI_CLKOUT_GPIO34 \ + ESP32_PINMUX(34, ESP_NOSIG, ESP_TWAI_CLKOUT) + +#define TWAI_CLKOUT_GPIO35 \ + ESP32_PINMUX(35, ESP_NOSIG, ESP_TWAI_CLKOUT) + +#define TWAI_CLKOUT_GPIO36 \ + ESP32_PINMUX(36, ESP_NOSIG, ESP_TWAI_CLKOUT) + +#define TWAI_CLKOUT_GPIO37 \ + ESP32_PINMUX(37, ESP_NOSIG, ESP_TWAI_CLKOUT) + +#define TWAI_CLKOUT_GPIO38 \ + ESP32_PINMUX(38, ESP_NOSIG, ESP_TWAI_CLKOUT) + +#define TWAI_CLKOUT_GPIO39 \ + ESP32_PINMUX(39, ESP_NOSIG, ESP_TWAI_CLKOUT) + +#define TWAI_CLKOUT_GPIO40 \ + ESP32_PINMUX(40, ESP_NOSIG, ESP_TWAI_CLKOUT) + +#define TWAI_CLKOUT_GPIO41 \ + ESP32_PINMUX(41, ESP_NOSIG, ESP_TWAI_CLKOUT) + +#define TWAI_CLKOUT_GPIO42 \ + ESP32_PINMUX(42, ESP_NOSIG, ESP_TWAI_CLKOUT) + +#define TWAI_CLKOUT_GPIO43 \ + ESP32_PINMUX(43, ESP_NOSIG, ESP_TWAI_CLKOUT) + +#define TWAI_CLKOUT_GPIO44 \ + ESP32_PINMUX(44, ESP_NOSIG, ESP_TWAI_CLKOUT) + +#define TWAI_CLKOUT_GPIO45 \ + ESP32_PINMUX(45, ESP_NOSIG, ESP_TWAI_CLKOUT) + +/* TWAI_RX */ +#define TWAI_RX_GPIO0 \ + ESP32_PINMUX(0, ESP_TWAI_RX, ESP_NOSIG) + +#define TWAI_RX_GPIO1 \ + ESP32_PINMUX(1, ESP_TWAI_RX, ESP_NOSIG) + +#define TWAI_RX_GPIO2 \ + ESP32_PINMUX(2, ESP_TWAI_RX, ESP_NOSIG) + +#define TWAI_RX_GPIO3 \ + ESP32_PINMUX(3, ESP_TWAI_RX, ESP_NOSIG) + +#define TWAI_RX_GPIO4 \ + ESP32_PINMUX(4, ESP_TWAI_RX, ESP_NOSIG) + +#define TWAI_RX_GPIO5 \ + ESP32_PINMUX(5, ESP_TWAI_RX, ESP_NOSIG) + +#define TWAI_RX_GPIO6 \ + ESP32_PINMUX(6, ESP_TWAI_RX, ESP_NOSIG) + +#define TWAI_RX_GPIO7 \ + ESP32_PINMUX(7, ESP_TWAI_RX, ESP_NOSIG) + +#define TWAI_RX_GPIO8 \ + ESP32_PINMUX(8, ESP_TWAI_RX, ESP_NOSIG) + +#define TWAI_RX_GPIO9 \ + ESP32_PINMUX(9, ESP_TWAI_RX, ESP_NOSIG) + +#define TWAI_RX_GPIO10 \ + ESP32_PINMUX(10, ESP_TWAI_RX, ESP_NOSIG) + +#define TWAI_RX_GPIO11 \ + ESP32_PINMUX(11, ESP_TWAI_RX, ESP_NOSIG) + +#define TWAI_RX_GPIO12 \ + ESP32_PINMUX(12, ESP_TWAI_RX, ESP_NOSIG) + +#define TWAI_RX_GPIO13 \ + ESP32_PINMUX(13, ESP_TWAI_RX, ESP_NOSIG) + +#define TWAI_RX_GPIO14 \ + ESP32_PINMUX(14, ESP_TWAI_RX, ESP_NOSIG) + +#define TWAI_RX_GPIO15 \ + ESP32_PINMUX(15, ESP_TWAI_RX, ESP_NOSIG) + +#define TWAI_RX_GPIO16 \ + ESP32_PINMUX(16, ESP_TWAI_RX, ESP_NOSIG) + +#define TWAI_RX_GPIO17 \ + ESP32_PINMUX(17, ESP_TWAI_RX, ESP_NOSIG) + +#define TWAI_RX_GPIO18 \ + ESP32_PINMUX(18, ESP_TWAI_RX, ESP_NOSIG) + +#define TWAI_RX_GPIO19 \ + ESP32_PINMUX(19, ESP_TWAI_RX, ESP_NOSIG) + +#define TWAI_RX_GPIO20 \ + ESP32_PINMUX(20, ESP_TWAI_RX, ESP_NOSIG) + +#define TWAI_RX_GPIO21 \ + ESP32_PINMUX(21, ESP_TWAI_RX, ESP_NOSIG) + +#define TWAI_RX_GPIO26 \ + ESP32_PINMUX(26, ESP_TWAI_RX, ESP_NOSIG) + +#define TWAI_RX_GPIO27 \ + ESP32_PINMUX(27, ESP_TWAI_RX, ESP_NOSIG) + +#define TWAI_RX_GPIO28 \ + ESP32_PINMUX(28, ESP_TWAI_RX, ESP_NOSIG) + +#define TWAI_RX_GPIO29 \ + ESP32_PINMUX(29, ESP_TWAI_RX, ESP_NOSIG) + +#define TWAI_RX_GPIO30 \ + ESP32_PINMUX(30, ESP_TWAI_RX, ESP_NOSIG) + +#define TWAI_RX_GPIO31 \ + ESP32_PINMUX(31, ESP_TWAI_RX, ESP_NOSIG) + +#define TWAI_RX_GPIO32 \ + ESP32_PINMUX(32, ESP_TWAI_RX, ESP_NOSIG) + +#define TWAI_RX_GPIO33 \ + ESP32_PINMUX(33, ESP_TWAI_RX, ESP_NOSIG) + +#define TWAI_RX_GPIO34 \ + ESP32_PINMUX(34, ESP_TWAI_RX, ESP_NOSIG) + +#define TWAI_RX_GPIO35 \ + ESP32_PINMUX(35, ESP_TWAI_RX, ESP_NOSIG) + +#define TWAI_RX_GPIO36 \ + ESP32_PINMUX(36, ESP_TWAI_RX, ESP_NOSIG) + +#define TWAI_RX_GPIO37 \ + ESP32_PINMUX(37, ESP_TWAI_RX, ESP_NOSIG) + +#define TWAI_RX_GPIO38 \ + ESP32_PINMUX(38, ESP_TWAI_RX, ESP_NOSIG) + +#define TWAI_RX_GPIO39 \ + ESP32_PINMUX(39, ESP_TWAI_RX, ESP_NOSIG) + +#define TWAI_RX_GPIO40 \ + ESP32_PINMUX(40, ESP_TWAI_RX, ESP_NOSIG) + +#define TWAI_RX_GPIO41 \ + ESP32_PINMUX(41, ESP_TWAI_RX, ESP_NOSIG) + +#define TWAI_RX_GPIO42 \ + ESP32_PINMUX(42, ESP_TWAI_RX, ESP_NOSIG) + +#define TWAI_RX_GPIO43 \ + ESP32_PINMUX(43, ESP_TWAI_RX, ESP_NOSIG) + +#define TWAI_RX_GPIO44 \ + ESP32_PINMUX(44, ESP_TWAI_RX, ESP_NOSIG) + +#define TWAI_RX_GPIO45 \ + ESP32_PINMUX(45, ESP_TWAI_RX, ESP_NOSIG) + +#define TWAI_RX_GPIO46 \ + ESP32_PINMUX(46, ESP_TWAI_RX, ESP_NOSIG) + +/* TWAI_TX */ +#define TWAI_TX_GPIO0 \ + ESP32_PINMUX(0, ESP_NOSIG, ESP_TWAI_TX) + +#define TWAI_TX_GPIO1 \ + ESP32_PINMUX(1, ESP_NOSIG, ESP_TWAI_TX) + +#define TWAI_TX_GPIO2 \ + ESP32_PINMUX(2, ESP_NOSIG, ESP_TWAI_TX) + +#define TWAI_TX_GPIO3 \ + ESP32_PINMUX(3, ESP_NOSIG, ESP_TWAI_TX) + +#define TWAI_TX_GPIO4 \ + ESP32_PINMUX(4, ESP_NOSIG, ESP_TWAI_TX) + +#define TWAI_TX_GPIO5 \ + ESP32_PINMUX(5, ESP_NOSIG, ESP_TWAI_TX) + +#define TWAI_TX_GPIO6 \ + ESP32_PINMUX(6, ESP_NOSIG, ESP_TWAI_TX) + +#define TWAI_TX_GPIO7 \ + ESP32_PINMUX(7, ESP_NOSIG, ESP_TWAI_TX) + +#define TWAI_TX_GPIO8 \ + ESP32_PINMUX(8, ESP_NOSIG, ESP_TWAI_TX) + +#define TWAI_TX_GPIO9 \ + ESP32_PINMUX(9, ESP_NOSIG, ESP_TWAI_TX) + +#define TWAI_TX_GPIO10 \ + ESP32_PINMUX(10, ESP_NOSIG, ESP_TWAI_TX) + +#define TWAI_TX_GPIO11 \ + ESP32_PINMUX(11, ESP_NOSIG, ESP_TWAI_TX) + +#define TWAI_TX_GPIO12 \ + ESP32_PINMUX(12, ESP_NOSIG, ESP_TWAI_TX) + +#define TWAI_TX_GPIO13 \ + ESP32_PINMUX(13, ESP_NOSIG, ESP_TWAI_TX) + +#define TWAI_TX_GPIO14 \ + ESP32_PINMUX(14, ESP_NOSIG, ESP_TWAI_TX) + +#define TWAI_TX_GPIO15 \ + ESP32_PINMUX(15, ESP_NOSIG, ESP_TWAI_TX) + +#define TWAI_TX_GPIO16 \ + ESP32_PINMUX(16, ESP_NOSIG, ESP_TWAI_TX) + +#define TWAI_TX_GPIO17 \ + ESP32_PINMUX(17, ESP_NOSIG, ESP_TWAI_TX) + +#define TWAI_TX_GPIO18 \ + ESP32_PINMUX(18, ESP_NOSIG, ESP_TWAI_TX) + +#define TWAI_TX_GPIO19 \ + ESP32_PINMUX(19, ESP_NOSIG, ESP_TWAI_TX) + +#define TWAI_TX_GPIO20 \ + ESP32_PINMUX(20, ESP_NOSIG, ESP_TWAI_TX) + +#define TWAI_TX_GPIO21 \ + ESP32_PINMUX(21, ESP_NOSIG, ESP_TWAI_TX) + +#define TWAI_TX_GPIO26 \ + ESP32_PINMUX(26, ESP_NOSIG, ESP_TWAI_TX) + +#define TWAI_TX_GPIO27 \ + ESP32_PINMUX(27, ESP_NOSIG, ESP_TWAI_TX) + +#define TWAI_TX_GPIO28 \ + ESP32_PINMUX(28, ESP_NOSIG, ESP_TWAI_TX) + +#define TWAI_TX_GPIO29 \ + ESP32_PINMUX(29, ESP_NOSIG, ESP_TWAI_TX) + +#define TWAI_TX_GPIO30 \ + ESP32_PINMUX(30, ESP_NOSIG, ESP_TWAI_TX) + +#define TWAI_TX_GPIO31 \ + ESP32_PINMUX(31, ESP_NOSIG, ESP_TWAI_TX) + +#define TWAI_TX_GPIO32 \ + ESP32_PINMUX(32, ESP_NOSIG, ESP_TWAI_TX) + +#define TWAI_TX_GPIO33 \ + ESP32_PINMUX(33, ESP_NOSIG, ESP_TWAI_TX) + +#define TWAI_TX_GPIO34 \ + ESP32_PINMUX(34, ESP_NOSIG, ESP_TWAI_TX) + +#define TWAI_TX_GPIO35 \ + ESP32_PINMUX(35, ESP_NOSIG, ESP_TWAI_TX) + +#define TWAI_TX_GPIO36 \ + ESP32_PINMUX(36, ESP_NOSIG, ESP_TWAI_TX) + +#define TWAI_TX_GPIO37 \ + ESP32_PINMUX(37, ESP_NOSIG, ESP_TWAI_TX) + +#define TWAI_TX_GPIO38 \ + ESP32_PINMUX(38, ESP_NOSIG, ESP_TWAI_TX) + +#define TWAI_TX_GPIO39 \ + ESP32_PINMUX(39, ESP_NOSIG, ESP_TWAI_TX) + +#define TWAI_TX_GPIO40 \ + ESP32_PINMUX(40, ESP_NOSIG, ESP_TWAI_TX) + +#define TWAI_TX_GPIO41 \ + ESP32_PINMUX(41, ESP_NOSIG, ESP_TWAI_TX) + +#define TWAI_TX_GPIO42 \ + ESP32_PINMUX(42, ESP_NOSIG, ESP_TWAI_TX) + +#define TWAI_TX_GPIO43 \ + ESP32_PINMUX(43, ESP_NOSIG, ESP_TWAI_TX) + +#define TWAI_TX_GPIO44 \ + ESP32_PINMUX(44, ESP_NOSIG, ESP_TWAI_TX) + +#define TWAI_TX_GPIO45 \ + ESP32_PINMUX(45, ESP_NOSIG, ESP_TWAI_TX) + +/* UART0_CTS */ +#define UART0_CTS_GPIO0 \ + ESP32_PINMUX(0, ESP_U0CTS_IN, ESP_NOSIG) + +#define UART0_CTS_GPIO1 \ + ESP32_PINMUX(1, ESP_U0CTS_IN, ESP_NOSIG) + +#define UART0_CTS_GPIO2 \ + ESP32_PINMUX(2, ESP_U0CTS_IN, ESP_NOSIG) + +#define UART0_CTS_GPIO3 \ + ESP32_PINMUX(3, ESP_U0CTS_IN, ESP_NOSIG) + +#define UART0_CTS_GPIO4 \ + ESP32_PINMUX(4, ESP_U0CTS_IN, ESP_NOSIG) + +#define UART0_CTS_GPIO5 \ + ESP32_PINMUX(5, ESP_U0CTS_IN, ESP_NOSIG) + +#define UART0_CTS_GPIO6 \ + ESP32_PINMUX(6, ESP_U0CTS_IN, ESP_NOSIG) + +#define UART0_CTS_GPIO7 \ + ESP32_PINMUX(7, ESP_U0CTS_IN, ESP_NOSIG) + +#define UART0_CTS_GPIO8 \ + ESP32_PINMUX(8, ESP_U0CTS_IN, ESP_NOSIG) + +#define UART0_CTS_GPIO9 \ + ESP32_PINMUX(9, ESP_U0CTS_IN, ESP_NOSIG) + +#define UART0_CTS_GPIO10 \ + ESP32_PINMUX(10, ESP_U0CTS_IN, ESP_NOSIG) + +#define UART0_CTS_GPIO11 \ + ESP32_PINMUX(11, ESP_U0CTS_IN, ESP_NOSIG) + +#define UART0_CTS_GPIO12 \ + ESP32_PINMUX(12, ESP_U0CTS_IN, ESP_NOSIG) + +#define UART0_CTS_GPIO13 \ + ESP32_PINMUX(13, ESP_U0CTS_IN, ESP_NOSIG) + +#define UART0_CTS_GPIO14 \ + ESP32_PINMUX(14, ESP_U0CTS_IN, ESP_NOSIG) + +#define UART0_CTS_GPIO15 \ + ESP32_PINMUX(15, ESP_U0CTS_IN, ESP_NOSIG) + +#define UART0_CTS_GPIO16 \ + ESP32_PINMUX(16, ESP_U0CTS_IN, ESP_NOSIG) + +#define UART0_CTS_GPIO17 \ + ESP32_PINMUX(17, ESP_U0CTS_IN, ESP_NOSIG) + +#define UART0_CTS_GPIO18 \ + ESP32_PINMUX(18, ESP_U0CTS_IN, ESP_NOSIG) + +#define UART0_CTS_GPIO19 \ + ESP32_PINMUX(19, ESP_U0CTS_IN, ESP_NOSIG) + +#define UART0_CTS_GPIO20 \ + ESP32_PINMUX(20, ESP_U0CTS_IN, ESP_NOSIG) + +#define UART0_CTS_GPIO21 \ + ESP32_PINMUX(21, ESP_U0CTS_IN, ESP_NOSIG) + +#define UART0_CTS_GPIO26 \ + ESP32_PINMUX(26, ESP_U0CTS_IN, ESP_NOSIG) + +#define UART0_CTS_GPIO27 \ + ESP32_PINMUX(27, ESP_U0CTS_IN, ESP_NOSIG) + +#define UART0_CTS_GPIO28 \ + ESP32_PINMUX(28, ESP_U0CTS_IN, ESP_NOSIG) + +#define UART0_CTS_GPIO29 \ + ESP32_PINMUX(29, ESP_U0CTS_IN, ESP_NOSIG) + +#define UART0_CTS_GPIO30 \ + ESP32_PINMUX(30, ESP_U0CTS_IN, ESP_NOSIG) + +#define UART0_CTS_GPIO31 \ + ESP32_PINMUX(31, ESP_U0CTS_IN, ESP_NOSIG) + +#define UART0_CTS_GPIO32 \ + ESP32_PINMUX(32, ESP_U0CTS_IN, ESP_NOSIG) + +#define UART0_CTS_GPIO33 \ + ESP32_PINMUX(33, ESP_U0CTS_IN, ESP_NOSIG) + +#define UART0_CTS_GPIO34 \ + ESP32_PINMUX(34, ESP_U0CTS_IN, ESP_NOSIG) + +#define UART0_CTS_GPIO35 \ + ESP32_PINMUX(35, ESP_U0CTS_IN, ESP_NOSIG) + +#define UART0_CTS_GPIO36 \ + ESP32_PINMUX(36, ESP_U0CTS_IN, ESP_NOSIG) + +#define UART0_CTS_GPIO37 \ + ESP32_PINMUX(37, ESP_U0CTS_IN, ESP_NOSIG) + +#define UART0_CTS_GPIO38 \ + ESP32_PINMUX(38, ESP_U0CTS_IN, ESP_NOSIG) + +#define UART0_CTS_GPIO39 \ + ESP32_PINMUX(39, ESP_U0CTS_IN, ESP_NOSIG) + +#define UART0_CTS_GPIO40 \ + ESP32_PINMUX(40, ESP_U0CTS_IN, ESP_NOSIG) + +#define UART0_CTS_GPIO41 \ + ESP32_PINMUX(41, ESP_U0CTS_IN, ESP_NOSIG) + +#define UART0_CTS_GPIO42 \ + ESP32_PINMUX(42, ESP_U0CTS_IN, ESP_NOSIG) + +#define UART0_CTS_GPIO43 \ + ESP32_PINMUX(43, ESP_U0CTS_IN, ESP_NOSIG) + +#define UART0_CTS_GPIO44 \ + ESP32_PINMUX(44, ESP_U0CTS_IN, ESP_NOSIG) + +#define UART0_CTS_GPIO45 \ + ESP32_PINMUX(45, ESP_U0CTS_IN, ESP_NOSIG) + +#define UART0_CTS_GPIO46 \ + ESP32_PINMUX(46, ESP_U0CTS_IN, ESP_NOSIG) + +/* UART0_DSR */ +#define UART0_DSR_GPIO0 \ + ESP32_PINMUX(0, ESP_U0DSR_IN, ESP_NOSIG) + +#define UART0_DSR_GPIO1 \ + ESP32_PINMUX(1, ESP_U0DSR_IN, ESP_NOSIG) + +#define UART0_DSR_GPIO2 \ + ESP32_PINMUX(2, ESP_U0DSR_IN, ESP_NOSIG) + +#define UART0_DSR_GPIO3 \ + ESP32_PINMUX(3, ESP_U0DSR_IN, ESP_NOSIG) + +#define UART0_DSR_GPIO4 \ + ESP32_PINMUX(4, ESP_U0DSR_IN, ESP_NOSIG) + +#define UART0_DSR_GPIO5 \ + ESP32_PINMUX(5, ESP_U0DSR_IN, ESP_NOSIG) + +#define UART0_DSR_GPIO6 \ + ESP32_PINMUX(6, ESP_U0DSR_IN, ESP_NOSIG) + +#define UART0_DSR_GPIO7 \ + ESP32_PINMUX(7, ESP_U0DSR_IN, ESP_NOSIG) + +#define UART0_DSR_GPIO8 \ + ESP32_PINMUX(8, ESP_U0DSR_IN, ESP_NOSIG) + +#define UART0_DSR_GPIO9 \ + ESP32_PINMUX(9, ESP_U0DSR_IN, ESP_NOSIG) + +#define UART0_DSR_GPIO10 \ + ESP32_PINMUX(10, ESP_U0DSR_IN, ESP_NOSIG) + +#define UART0_DSR_GPIO11 \ + ESP32_PINMUX(11, ESP_U0DSR_IN, ESP_NOSIG) + +#define UART0_DSR_GPIO12 \ + ESP32_PINMUX(12, ESP_U0DSR_IN, ESP_NOSIG) + +#define UART0_DSR_GPIO13 \ + ESP32_PINMUX(13, ESP_U0DSR_IN, ESP_NOSIG) + +#define UART0_DSR_GPIO14 \ + ESP32_PINMUX(14, ESP_U0DSR_IN, ESP_NOSIG) + +#define UART0_DSR_GPIO15 \ + ESP32_PINMUX(15, ESP_U0DSR_IN, ESP_NOSIG) + +#define UART0_DSR_GPIO16 \ + ESP32_PINMUX(16, ESP_U0DSR_IN, ESP_NOSIG) + +#define UART0_DSR_GPIO17 \ + ESP32_PINMUX(17, ESP_U0DSR_IN, ESP_NOSIG) + +#define UART0_DSR_GPIO18 \ + ESP32_PINMUX(18, ESP_U0DSR_IN, ESP_NOSIG) + +#define UART0_DSR_GPIO19 \ + ESP32_PINMUX(19, ESP_U0DSR_IN, ESP_NOSIG) + +#define UART0_DSR_GPIO20 \ + ESP32_PINMUX(20, ESP_U0DSR_IN, ESP_NOSIG) + +#define UART0_DSR_GPIO21 \ + ESP32_PINMUX(21, ESP_U0DSR_IN, ESP_NOSIG) + +#define UART0_DSR_GPIO26 \ + ESP32_PINMUX(26, ESP_U0DSR_IN, ESP_NOSIG) + +#define UART0_DSR_GPIO27 \ + ESP32_PINMUX(27, ESP_U0DSR_IN, ESP_NOSIG) + +#define UART0_DSR_GPIO28 \ + ESP32_PINMUX(28, ESP_U0DSR_IN, ESP_NOSIG) + +#define UART0_DSR_GPIO29 \ + ESP32_PINMUX(29, ESP_U0DSR_IN, ESP_NOSIG) + +#define UART0_DSR_GPIO30 \ + ESP32_PINMUX(30, ESP_U0DSR_IN, ESP_NOSIG) + +#define UART0_DSR_GPIO31 \ + ESP32_PINMUX(31, ESP_U0DSR_IN, ESP_NOSIG) + +#define UART0_DSR_GPIO32 \ + ESP32_PINMUX(32, ESP_U0DSR_IN, ESP_NOSIG) + +#define UART0_DSR_GPIO33 \ + ESP32_PINMUX(33, ESP_U0DSR_IN, ESP_NOSIG) + +#define UART0_DSR_GPIO34 \ + ESP32_PINMUX(34, ESP_U0DSR_IN, ESP_NOSIG) + +#define UART0_DSR_GPIO35 \ + ESP32_PINMUX(35, ESP_U0DSR_IN, ESP_NOSIG) + +#define UART0_DSR_GPIO36 \ + ESP32_PINMUX(36, ESP_U0DSR_IN, ESP_NOSIG) + +#define UART0_DSR_GPIO37 \ + ESP32_PINMUX(37, ESP_U0DSR_IN, ESP_NOSIG) + +#define UART0_DSR_GPIO38 \ + ESP32_PINMUX(38, ESP_U0DSR_IN, ESP_NOSIG) + +#define UART0_DSR_GPIO39 \ + ESP32_PINMUX(39, ESP_U0DSR_IN, ESP_NOSIG) + +#define UART0_DSR_GPIO40 \ + ESP32_PINMUX(40, ESP_U0DSR_IN, ESP_NOSIG) + +#define UART0_DSR_GPIO41 \ + ESP32_PINMUX(41, ESP_U0DSR_IN, ESP_NOSIG) + +#define UART0_DSR_GPIO42 \ + ESP32_PINMUX(42, ESP_U0DSR_IN, ESP_NOSIG) + +#define UART0_DSR_GPIO43 \ + ESP32_PINMUX(43, ESP_U0DSR_IN, ESP_NOSIG) + +#define UART0_DSR_GPIO44 \ + ESP32_PINMUX(44, ESP_U0DSR_IN, ESP_NOSIG) + +#define UART0_DSR_GPIO45 \ + ESP32_PINMUX(45, ESP_U0DSR_IN, ESP_NOSIG) + +#define UART0_DSR_GPIO46 \ + ESP32_PINMUX(46, ESP_U0DSR_IN, ESP_NOSIG) + +/* UART0_DTR */ +#define UART0_DTR_GPIO0 \ + ESP32_PINMUX(0, ESP_NOSIG, ESP_U0DTR_OUT) + +#define UART0_DTR_GPIO1 \ + ESP32_PINMUX(1, ESP_NOSIG, ESP_U0DTR_OUT) + +#define UART0_DTR_GPIO2 \ + ESP32_PINMUX(2, ESP_NOSIG, ESP_U0DTR_OUT) + +#define UART0_DTR_GPIO3 \ + ESP32_PINMUX(3, ESP_NOSIG, ESP_U0DTR_OUT) + +#define UART0_DTR_GPIO4 \ + ESP32_PINMUX(4, ESP_NOSIG, ESP_U0DTR_OUT) + +#define UART0_DTR_GPIO5 \ + ESP32_PINMUX(5, ESP_NOSIG, ESP_U0DTR_OUT) + +#define UART0_DTR_GPIO6 \ + ESP32_PINMUX(6, ESP_NOSIG, ESP_U0DTR_OUT) + +#define UART0_DTR_GPIO7 \ + ESP32_PINMUX(7, ESP_NOSIG, ESP_U0DTR_OUT) + +#define UART0_DTR_GPIO8 \ + ESP32_PINMUX(8, ESP_NOSIG, ESP_U0DTR_OUT) + +#define UART0_DTR_GPIO9 \ + ESP32_PINMUX(9, ESP_NOSIG, ESP_U0DTR_OUT) + +#define UART0_DTR_GPIO10 \ + ESP32_PINMUX(10, ESP_NOSIG, ESP_U0DTR_OUT) + +#define UART0_DTR_GPIO11 \ + ESP32_PINMUX(11, ESP_NOSIG, ESP_U0DTR_OUT) + +#define UART0_DTR_GPIO12 \ + ESP32_PINMUX(12, ESP_NOSIG, ESP_U0DTR_OUT) + +#define UART0_DTR_GPIO13 \ + ESP32_PINMUX(13, ESP_NOSIG, ESP_U0DTR_OUT) + +#define UART0_DTR_GPIO14 \ + ESP32_PINMUX(14, ESP_NOSIG, ESP_U0DTR_OUT) + +#define UART0_DTR_GPIO15 \ + ESP32_PINMUX(15, ESP_NOSIG, ESP_U0DTR_OUT) + +#define UART0_DTR_GPIO16 \ + ESP32_PINMUX(16, ESP_NOSIG, ESP_U0DTR_OUT) + +#define UART0_DTR_GPIO17 \ + ESP32_PINMUX(17, ESP_NOSIG, ESP_U0DTR_OUT) + +#define UART0_DTR_GPIO18 \ + ESP32_PINMUX(18, ESP_NOSIG, ESP_U0DTR_OUT) + +#define UART0_DTR_GPIO19 \ + ESP32_PINMUX(19, ESP_NOSIG, ESP_U0DTR_OUT) + +#define UART0_DTR_GPIO20 \ + ESP32_PINMUX(20, ESP_NOSIG, ESP_U0DTR_OUT) + +#define UART0_DTR_GPIO21 \ + ESP32_PINMUX(21, ESP_NOSIG, ESP_U0DTR_OUT) + +#define UART0_DTR_GPIO26 \ + ESP32_PINMUX(26, ESP_NOSIG, ESP_U0DTR_OUT) + +#define UART0_DTR_GPIO27 \ + ESP32_PINMUX(27, ESP_NOSIG, ESP_U0DTR_OUT) + +#define UART0_DTR_GPIO28 \ + ESP32_PINMUX(28, ESP_NOSIG, ESP_U0DTR_OUT) + +#define UART0_DTR_GPIO29 \ + ESP32_PINMUX(29, ESP_NOSIG, ESP_U0DTR_OUT) + +#define UART0_DTR_GPIO30 \ + ESP32_PINMUX(30, ESP_NOSIG, ESP_U0DTR_OUT) + +#define UART0_DTR_GPIO31 \ + ESP32_PINMUX(31, ESP_NOSIG, ESP_U0DTR_OUT) + +#define UART0_DTR_GPIO32 \ + ESP32_PINMUX(32, ESP_NOSIG, ESP_U0DTR_OUT) + +#define UART0_DTR_GPIO33 \ + ESP32_PINMUX(33, ESP_NOSIG, ESP_U0DTR_OUT) + +#define UART0_DTR_GPIO34 \ + ESP32_PINMUX(34, ESP_NOSIG, ESP_U0DTR_OUT) + +#define UART0_DTR_GPIO35 \ + ESP32_PINMUX(35, ESP_NOSIG, ESP_U0DTR_OUT) + +#define UART0_DTR_GPIO36 \ + ESP32_PINMUX(36, ESP_NOSIG, ESP_U0DTR_OUT) + +#define UART0_DTR_GPIO37 \ + ESP32_PINMUX(37, ESP_NOSIG, ESP_U0DTR_OUT) + +#define UART0_DTR_GPIO38 \ + ESP32_PINMUX(38, ESP_NOSIG, ESP_U0DTR_OUT) + +#define UART0_DTR_GPIO39 \ + ESP32_PINMUX(39, ESP_NOSIG, ESP_U0DTR_OUT) + +#define UART0_DTR_GPIO40 \ + ESP32_PINMUX(40, ESP_NOSIG, ESP_U0DTR_OUT) + +#define UART0_DTR_GPIO41 \ + ESP32_PINMUX(41, ESP_NOSIG, ESP_U0DTR_OUT) + +#define UART0_DTR_GPIO42 \ + ESP32_PINMUX(42, ESP_NOSIG, ESP_U0DTR_OUT) + +#define UART0_DTR_GPIO43 \ + ESP32_PINMUX(43, ESP_NOSIG, ESP_U0DTR_OUT) + +#define UART0_DTR_GPIO44 \ + ESP32_PINMUX(44, ESP_NOSIG, ESP_U0DTR_OUT) + +#define UART0_DTR_GPIO45 \ + ESP32_PINMUX(45, ESP_NOSIG, ESP_U0DTR_OUT) + +#define UART0_DTR_GPIO46 \ + ESP32_PINMUX(46, ESP_NOSIG, ESP_U0DTR_OUT) + +/* UART0_RTS */ +#define UART0_RTS_GPIO0 \ + ESP32_PINMUX(0, ESP_NOSIG, ESP_U0RTS_OUT) + +#define UART0_RTS_GPIO1 \ + ESP32_PINMUX(1, ESP_NOSIG, ESP_U0RTS_OUT) + +#define UART0_RTS_GPIO2 \ + ESP32_PINMUX(2, ESP_NOSIG, ESP_U0RTS_OUT) + +#define UART0_RTS_GPIO3 \ + ESP32_PINMUX(3, ESP_NOSIG, ESP_U0RTS_OUT) + +#define UART0_RTS_GPIO4 \ + ESP32_PINMUX(4, ESP_NOSIG, ESP_U0RTS_OUT) + +#define UART0_RTS_GPIO5 \ + ESP32_PINMUX(5, ESP_NOSIG, ESP_U0RTS_OUT) + +#define UART0_RTS_GPIO6 \ + ESP32_PINMUX(6, ESP_NOSIG, ESP_U0RTS_OUT) + +#define UART0_RTS_GPIO7 \ + ESP32_PINMUX(7, ESP_NOSIG, ESP_U0RTS_OUT) + +#define UART0_RTS_GPIO8 \ + ESP32_PINMUX(8, ESP_NOSIG, ESP_U0RTS_OUT) + +#define UART0_RTS_GPIO9 \ + ESP32_PINMUX(9, ESP_NOSIG, ESP_U0RTS_OUT) + +#define UART0_RTS_GPIO10 \ + ESP32_PINMUX(10, ESP_NOSIG, ESP_U0RTS_OUT) + +#define UART0_RTS_GPIO11 \ + ESP32_PINMUX(11, ESP_NOSIG, ESP_U0RTS_OUT) + +#define UART0_RTS_GPIO12 \ + ESP32_PINMUX(12, ESP_NOSIG, ESP_U0RTS_OUT) + +#define UART0_RTS_GPIO13 \ + ESP32_PINMUX(13, ESP_NOSIG, ESP_U0RTS_OUT) + +#define UART0_RTS_GPIO14 \ + ESP32_PINMUX(14, ESP_NOSIG, ESP_U0RTS_OUT) + +#define UART0_RTS_GPIO15 \ + ESP32_PINMUX(15, ESP_NOSIG, ESP_U0RTS_OUT) + +#define UART0_RTS_GPIO16 \ + ESP32_PINMUX(16, ESP_NOSIG, ESP_U0RTS_OUT) + +#define UART0_RTS_GPIO17 \ + ESP32_PINMUX(17, ESP_NOSIG, ESP_U0RTS_OUT) + +#define UART0_RTS_GPIO18 \ + ESP32_PINMUX(18, ESP_NOSIG, ESP_U0RTS_OUT) + +#define UART0_RTS_GPIO19 \ + ESP32_PINMUX(19, ESP_NOSIG, ESP_U0RTS_OUT) + +#define UART0_RTS_GPIO20 \ + ESP32_PINMUX(20, ESP_NOSIG, ESP_U0RTS_OUT) + +#define UART0_RTS_GPIO21 \ + ESP32_PINMUX(21, ESP_NOSIG, ESP_U0RTS_OUT) + +#define UART0_RTS_GPIO26 \ + ESP32_PINMUX(26, ESP_NOSIG, ESP_U0RTS_OUT) + +#define UART0_RTS_GPIO27 \ + ESP32_PINMUX(27, ESP_NOSIG, ESP_U0RTS_OUT) + +#define UART0_RTS_GPIO28 \ + ESP32_PINMUX(28, ESP_NOSIG, ESP_U0RTS_OUT) + +#define UART0_RTS_GPIO29 \ + ESP32_PINMUX(29, ESP_NOSIG, ESP_U0RTS_OUT) + +#define UART0_RTS_GPIO30 \ + ESP32_PINMUX(30, ESP_NOSIG, ESP_U0RTS_OUT) + +#define UART0_RTS_GPIO31 \ + ESP32_PINMUX(31, ESP_NOSIG, ESP_U0RTS_OUT) + +#define UART0_RTS_GPIO32 \ + ESP32_PINMUX(32, ESP_NOSIG, ESP_U0RTS_OUT) + +#define UART0_RTS_GPIO33 \ + ESP32_PINMUX(33, ESP_NOSIG, ESP_U0RTS_OUT) + +#define UART0_RTS_GPIO34 \ + ESP32_PINMUX(34, ESP_NOSIG, ESP_U0RTS_OUT) + +#define UART0_RTS_GPIO35 \ + ESP32_PINMUX(35, ESP_NOSIG, ESP_U0RTS_OUT) + +#define UART0_RTS_GPIO36 \ + ESP32_PINMUX(36, ESP_NOSIG, ESP_U0RTS_OUT) + +#define UART0_RTS_GPIO37 \ + ESP32_PINMUX(37, ESP_NOSIG, ESP_U0RTS_OUT) + +#define UART0_RTS_GPIO38 \ + ESP32_PINMUX(38, ESP_NOSIG, ESP_U0RTS_OUT) + +#define UART0_RTS_GPIO39 \ + ESP32_PINMUX(39, ESP_NOSIG, ESP_U0RTS_OUT) + +#define UART0_RTS_GPIO40 \ + ESP32_PINMUX(40, ESP_NOSIG, ESP_U0RTS_OUT) + +#define UART0_RTS_GPIO41 \ + ESP32_PINMUX(41, ESP_NOSIG, ESP_U0RTS_OUT) + +#define UART0_RTS_GPIO42 \ + ESP32_PINMUX(42, ESP_NOSIG, ESP_U0RTS_OUT) + +#define UART0_RTS_GPIO43 \ + ESP32_PINMUX(43, ESP_NOSIG, ESP_U0RTS_OUT) + +#define UART0_RTS_GPIO44 \ + ESP32_PINMUX(44, ESP_NOSIG, ESP_U0RTS_OUT) + +#define UART0_RTS_GPIO45 \ + ESP32_PINMUX(45, ESP_NOSIG, ESP_U0RTS_OUT) + +/* UART0_RX */ +#define UART0_RX_GPIO0 \ + ESP32_PINMUX(0, ESP_U0RXD_IN, ESP_NOSIG) + +#define UART0_RX_GPIO1 \ + ESP32_PINMUX(1, ESP_U0RXD_IN, ESP_NOSIG) + +#define UART0_RX_GPIO2 \ + ESP32_PINMUX(2, ESP_U0RXD_IN, ESP_NOSIG) + +#define UART0_RX_GPIO3 \ + ESP32_PINMUX(3, ESP_U0RXD_IN, ESP_NOSIG) + +#define UART0_RX_GPIO4 \ + ESP32_PINMUX(4, ESP_U0RXD_IN, ESP_NOSIG) + +#define UART0_RX_GPIO5 \ + ESP32_PINMUX(5, ESP_U0RXD_IN, ESP_NOSIG) + +#define UART0_RX_GPIO6 \ + ESP32_PINMUX(6, ESP_U0RXD_IN, ESP_NOSIG) + +#define UART0_RX_GPIO7 \ + ESP32_PINMUX(7, ESP_U0RXD_IN, ESP_NOSIG) + +#define UART0_RX_GPIO8 \ + ESP32_PINMUX(8, ESP_U0RXD_IN, ESP_NOSIG) + +#define UART0_RX_GPIO9 \ + ESP32_PINMUX(9, ESP_U0RXD_IN, ESP_NOSIG) + +#define UART0_RX_GPIO10 \ + ESP32_PINMUX(10, ESP_U0RXD_IN, ESP_NOSIG) + +#define UART0_RX_GPIO11 \ + ESP32_PINMUX(11, ESP_U0RXD_IN, ESP_NOSIG) + +#define UART0_RX_GPIO12 \ + ESP32_PINMUX(12, ESP_U0RXD_IN, ESP_NOSIG) + +#define UART0_RX_GPIO13 \ + ESP32_PINMUX(13, ESP_U0RXD_IN, ESP_NOSIG) + +#define UART0_RX_GPIO14 \ + ESP32_PINMUX(14, ESP_U0RXD_IN, ESP_NOSIG) + +#define UART0_RX_GPIO15 \ + ESP32_PINMUX(15, ESP_U0RXD_IN, ESP_NOSIG) + +#define UART0_RX_GPIO16 \ + ESP32_PINMUX(16, ESP_U0RXD_IN, ESP_NOSIG) + +#define UART0_RX_GPIO17 \ + ESP32_PINMUX(17, ESP_U0RXD_IN, ESP_NOSIG) + +#define UART0_RX_GPIO18 \ + ESP32_PINMUX(18, ESP_U0RXD_IN, ESP_NOSIG) + +#define UART0_RX_GPIO19 \ + ESP32_PINMUX(19, ESP_U0RXD_IN, ESP_NOSIG) + +#define UART0_RX_GPIO20 \ + ESP32_PINMUX(20, ESP_U0RXD_IN, ESP_NOSIG) + +#define UART0_RX_GPIO21 \ + ESP32_PINMUX(21, ESP_U0RXD_IN, ESP_NOSIG) + +#define UART0_RX_GPIO26 \ + ESP32_PINMUX(26, ESP_U0RXD_IN, ESP_NOSIG) + +#define UART0_RX_GPIO27 \ + ESP32_PINMUX(27, ESP_U0RXD_IN, ESP_NOSIG) + +#define UART0_RX_GPIO28 \ + ESP32_PINMUX(28, ESP_U0RXD_IN, ESP_NOSIG) + +#define UART0_RX_GPIO29 \ + ESP32_PINMUX(29, ESP_U0RXD_IN, ESP_NOSIG) + +#define UART0_RX_GPIO30 \ + ESP32_PINMUX(30, ESP_U0RXD_IN, ESP_NOSIG) + +#define UART0_RX_GPIO31 \ + ESP32_PINMUX(31, ESP_U0RXD_IN, ESP_NOSIG) + +#define UART0_RX_GPIO32 \ + ESP32_PINMUX(32, ESP_U0RXD_IN, ESP_NOSIG) + +#define UART0_RX_GPIO33 \ + ESP32_PINMUX(33, ESP_U0RXD_IN, ESP_NOSIG) + +#define UART0_RX_GPIO34 \ + ESP32_PINMUX(34, ESP_U0RXD_IN, ESP_NOSIG) + +#define UART0_RX_GPIO35 \ + ESP32_PINMUX(35, ESP_U0RXD_IN, ESP_NOSIG) + +#define UART0_RX_GPIO36 \ + ESP32_PINMUX(36, ESP_U0RXD_IN, ESP_NOSIG) + +#define UART0_RX_GPIO37 \ + ESP32_PINMUX(37, ESP_U0RXD_IN, ESP_NOSIG) + +#define UART0_RX_GPIO38 \ + ESP32_PINMUX(38, ESP_U0RXD_IN, ESP_NOSIG) + +#define UART0_RX_GPIO39 \ + ESP32_PINMUX(39, ESP_U0RXD_IN, ESP_NOSIG) + +#define UART0_RX_GPIO40 \ + ESP32_PINMUX(40, ESP_U0RXD_IN, ESP_NOSIG) + +#define UART0_RX_GPIO41 \ + ESP32_PINMUX(41, ESP_U0RXD_IN, ESP_NOSIG) + +#define UART0_RX_GPIO42 \ + ESP32_PINMUX(42, ESP_U0RXD_IN, ESP_NOSIG) + +#define UART0_RX_GPIO43 \ + ESP32_PINMUX(43, ESP_U0RXD_IN, ESP_NOSIG) + +#define UART0_RX_GPIO44 \ + ESP32_PINMUX(44, ESP_U0RXD_IN, ESP_NOSIG) + +#define UART0_RX_GPIO45 \ + ESP32_PINMUX(45, ESP_U0RXD_IN, ESP_NOSIG) + +#define UART0_RX_GPIO46 \ + ESP32_PINMUX(46, ESP_U0RXD_IN, ESP_NOSIG) + +/* UART0_TX */ +#define UART0_TX_GPIO0 \ + ESP32_PINMUX(0, ESP_NOSIG, ESP_U0TXD_OUT) + +#define UART0_TX_GPIO1 \ + ESP32_PINMUX(1, ESP_NOSIG, ESP_U0TXD_OUT) + +#define UART0_TX_GPIO2 \ + ESP32_PINMUX(2, ESP_NOSIG, ESP_U0TXD_OUT) + +#define UART0_TX_GPIO3 \ + ESP32_PINMUX(3, ESP_NOSIG, ESP_U0TXD_OUT) + +#define UART0_TX_GPIO4 \ + ESP32_PINMUX(4, ESP_NOSIG, ESP_U0TXD_OUT) + +#define UART0_TX_GPIO5 \ + ESP32_PINMUX(5, ESP_NOSIG, ESP_U0TXD_OUT) + +#define UART0_TX_GPIO6 \ + ESP32_PINMUX(6, ESP_NOSIG, ESP_U0TXD_OUT) + +#define UART0_TX_GPIO7 \ + ESP32_PINMUX(7, ESP_NOSIG, ESP_U0TXD_OUT) + +#define UART0_TX_GPIO8 \ + ESP32_PINMUX(8, ESP_NOSIG, ESP_U0TXD_OUT) + +#define UART0_TX_GPIO9 \ + ESP32_PINMUX(9, ESP_NOSIG, ESP_U0TXD_OUT) + +#define UART0_TX_GPIO10 \ + ESP32_PINMUX(10, ESP_NOSIG, ESP_U0TXD_OUT) + +#define UART0_TX_GPIO11 \ + ESP32_PINMUX(11, ESP_NOSIG, ESP_U0TXD_OUT) + +#define UART0_TX_GPIO12 \ + ESP32_PINMUX(12, ESP_NOSIG, ESP_U0TXD_OUT) + +#define UART0_TX_GPIO13 \ + ESP32_PINMUX(13, ESP_NOSIG, ESP_U0TXD_OUT) + +#define UART0_TX_GPIO14 \ + ESP32_PINMUX(14, ESP_NOSIG, ESP_U0TXD_OUT) + +#define UART0_TX_GPIO15 \ + ESP32_PINMUX(15, ESP_NOSIG, ESP_U0TXD_OUT) + +#define UART0_TX_GPIO16 \ + ESP32_PINMUX(16, ESP_NOSIG, ESP_U0TXD_OUT) + +#define UART0_TX_GPIO17 \ + ESP32_PINMUX(17, ESP_NOSIG, ESP_U0TXD_OUT) + +#define UART0_TX_GPIO18 \ + ESP32_PINMUX(18, ESP_NOSIG, ESP_U0TXD_OUT) + +#define UART0_TX_GPIO19 \ + ESP32_PINMUX(19, ESP_NOSIG, ESP_U0TXD_OUT) + +#define UART0_TX_GPIO20 \ + ESP32_PINMUX(20, ESP_NOSIG, ESP_U0TXD_OUT) + +#define UART0_TX_GPIO21 \ + ESP32_PINMUX(21, ESP_NOSIG, ESP_U0TXD_OUT) + +#define UART0_TX_GPIO26 \ + ESP32_PINMUX(26, ESP_NOSIG, ESP_U0TXD_OUT) + +#define UART0_TX_GPIO27 \ + ESP32_PINMUX(27, ESP_NOSIG, ESP_U0TXD_OUT) + +#define UART0_TX_GPIO28 \ + ESP32_PINMUX(28, ESP_NOSIG, ESP_U0TXD_OUT) + +#define UART0_TX_GPIO29 \ + ESP32_PINMUX(29, ESP_NOSIG, ESP_U0TXD_OUT) + +#define UART0_TX_GPIO30 \ + ESP32_PINMUX(30, ESP_NOSIG, ESP_U0TXD_OUT) + +#define UART0_TX_GPIO31 \ + ESP32_PINMUX(31, ESP_NOSIG, ESP_U0TXD_OUT) + +#define UART0_TX_GPIO32 \ + ESP32_PINMUX(32, ESP_NOSIG, ESP_U0TXD_OUT) + +#define UART0_TX_GPIO33 \ + ESP32_PINMUX(33, ESP_NOSIG, ESP_U0TXD_OUT) + +#define UART0_TX_GPIO34 \ + ESP32_PINMUX(34, ESP_NOSIG, ESP_U0TXD_OUT) + +#define UART0_TX_GPIO35 \ + ESP32_PINMUX(35, ESP_NOSIG, ESP_U0TXD_OUT) + +#define UART0_TX_GPIO36 \ + ESP32_PINMUX(36, ESP_NOSIG, ESP_U0TXD_OUT) + +#define UART0_TX_GPIO37 \ + ESP32_PINMUX(37, ESP_NOSIG, ESP_U0TXD_OUT) + +#define UART0_TX_GPIO38 \ + ESP32_PINMUX(38, ESP_NOSIG, ESP_U0TXD_OUT) + +#define UART0_TX_GPIO39 \ + ESP32_PINMUX(39, ESP_NOSIG, ESP_U0TXD_OUT) + +#define UART0_TX_GPIO40 \ + ESP32_PINMUX(40, ESP_NOSIG, ESP_U0TXD_OUT) + +#define UART0_TX_GPIO41 \ + ESP32_PINMUX(41, ESP_NOSIG, ESP_U0TXD_OUT) + +#define UART0_TX_GPIO42 \ + ESP32_PINMUX(42, ESP_NOSIG, ESP_U0TXD_OUT) + +#define UART0_TX_GPIO43 \ + ESP32_PINMUX(43, ESP_NOSIG, ESP_U0TXD_OUT) + +#define UART0_TX_GPIO44 \ + ESP32_PINMUX(44, ESP_NOSIG, ESP_U0TXD_OUT) + +#define UART0_TX_GPIO45 \ + ESP32_PINMUX(45, ESP_NOSIG, ESP_U0TXD_OUT) + +/* UART1_CTS */ +#define UART1_CTS_GPIO0 \ + ESP32_PINMUX(0, ESP_U1CTS_IN, ESP_NOSIG) + +#define UART1_CTS_GPIO1 \ + ESP32_PINMUX(1, ESP_U1CTS_IN, ESP_NOSIG) + +#define UART1_CTS_GPIO2 \ + ESP32_PINMUX(2, ESP_U1CTS_IN, ESP_NOSIG) + +#define UART1_CTS_GPIO3 \ + ESP32_PINMUX(3, ESP_U1CTS_IN, ESP_NOSIG) + +#define UART1_CTS_GPIO4 \ + ESP32_PINMUX(4, ESP_U1CTS_IN, ESP_NOSIG) + +#define UART1_CTS_GPIO5 \ + ESP32_PINMUX(5, ESP_U1CTS_IN, ESP_NOSIG) + +#define UART1_CTS_GPIO6 \ + ESP32_PINMUX(6, ESP_U1CTS_IN, ESP_NOSIG) + +#define UART1_CTS_GPIO7 \ + ESP32_PINMUX(7, ESP_U1CTS_IN, ESP_NOSIG) + +#define UART1_CTS_GPIO8 \ + ESP32_PINMUX(8, ESP_U1CTS_IN, ESP_NOSIG) + +#define UART1_CTS_GPIO9 \ + ESP32_PINMUX(9, ESP_U1CTS_IN, ESP_NOSIG) + +#define UART1_CTS_GPIO10 \ + ESP32_PINMUX(10, ESP_U1CTS_IN, ESP_NOSIG) + +#define UART1_CTS_GPIO11 \ + ESP32_PINMUX(11, ESP_U1CTS_IN, ESP_NOSIG) + +#define UART1_CTS_GPIO12 \ + ESP32_PINMUX(12, ESP_U1CTS_IN, ESP_NOSIG) + +#define UART1_CTS_GPIO13 \ + ESP32_PINMUX(13, ESP_U1CTS_IN, ESP_NOSIG) + +#define UART1_CTS_GPIO14 \ + ESP32_PINMUX(14, ESP_U1CTS_IN, ESP_NOSIG) + +#define UART1_CTS_GPIO15 \ + ESP32_PINMUX(15, ESP_U1CTS_IN, ESP_NOSIG) + +#define UART1_CTS_GPIO16 \ + ESP32_PINMUX(16, ESP_U1CTS_IN, ESP_NOSIG) + +#define UART1_CTS_GPIO17 \ + ESP32_PINMUX(17, ESP_U1CTS_IN, ESP_NOSIG) + +#define UART1_CTS_GPIO18 \ + ESP32_PINMUX(18, ESP_U1CTS_IN, ESP_NOSIG) + +#define UART1_CTS_GPIO19 \ + ESP32_PINMUX(19, ESP_U1CTS_IN, ESP_NOSIG) + +#define UART1_CTS_GPIO20 \ + ESP32_PINMUX(20, ESP_U1CTS_IN, ESP_NOSIG) + +#define UART1_CTS_GPIO21 \ + ESP32_PINMUX(21, ESP_U1CTS_IN, ESP_NOSIG) + +#define UART1_CTS_GPIO26 \ + ESP32_PINMUX(26, ESP_U1CTS_IN, ESP_NOSIG) + +#define UART1_CTS_GPIO27 \ + ESP32_PINMUX(27, ESP_U1CTS_IN, ESP_NOSIG) + +#define UART1_CTS_GPIO28 \ + ESP32_PINMUX(28, ESP_U1CTS_IN, ESP_NOSIG) + +#define UART1_CTS_GPIO29 \ + ESP32_PINMUX(29, ESP_U1CTS_IN, ESP_NOSIG) + +#define UART1_CTS_GPIO30 \ + ESP32_PINMUX(30, ESP_U1CTS_IN, ESP_NOSIG) + +#define UART1_CTS_GPIO31 \ + ESP32_PINMUX(31, ESP_U1CTS_IN, ESP_NOSIG) + +#define UART1_CTS_GPIO32 \ + ESP32_PINMUX(32, ESP_U1CTS_IN, ESP_NOSIG) + +#define UART1_CTS_GPIO33 \ + ESP32_PINMUX(33, ESP_U1CTS_IN, ESP_NOSIG) + +#define UART1_CTS_GPIO34 \ + ESP32_PINMUX(34, ESP_U1CTS_IN, ESP_NOSIG) + +#define UART1_CTS_GPIO35 \ + ESP32_PINMUX(35, ESP_U1CTS_IN, ESP_NOSIG) + +#define UART1_CTS_GPIO36 \ + ESP32_PINMUX(36, ESP_U1CTS_IN, ESP_NOSIG) + +#define UART1_CTS_GPIO37 \ + ESP32_PINMUX(37, ESP_U1CTS_IN, ESP_NOSIG) + +#define UART1_CTS_GPIO38 \ + ESP32_PINMUX(38, ESP_U1CTS_IN, ESP_NOSIG) + +#define UART1_CTS_GPIO39 \ + ESP32_PINMUX(39, ESP_U1CTS_IN, ESP_NOSIG) + +#define UART1_CTS_GPIO40 \ + ESP32_PINMUX(40, ESP_U1CTS_IN, ESP_NOSIG) + +#define UART1_CTS_GPIO41 \ + ESP32_PINMUX(41, ESP_U1CTS_IN, ESP_NOSIG) + +#define UART1_CTS_GPIO42 \ + ESP32_PINMUX(42, ESP_U1CTS_IN, ESP_NOSIG) + +#define UART1_CTS_GPIO43 \ + ESP32_PINMUX(43, ESP_U1CTS_IN, ESP_NOSIG) + +#define UART1_CTS_GPIO44 \ + ESP32_PINMUX(44, ESP_U1CTS_IN, ESP_NOSIG) + +#define UART1_CTS_GPIO45 \ + ESP32_PINMUX(45, ESP_U1CTS_IN, ESP_NOSIG) + +#define UART1_CTS_GPIO46 \ + ESP32_PINMUX(46, ESP_U1CTS_IN, ESP_NOSIG) + +/* UART1_DSR */ +#define UART1_DSR_GPIO0 \ + ESP32_PINMUX(0, ESP_U1DSR_IN, ESP_NOSIG) + +#define UART1_DSR_GPIO1 \ + ESP32_PINMUX(1, ESP_U1DSR_IN, ESP_NOSIG) + +#define UART1_DSR_GPIO2 \ + ESP32_PINMUX(2, ESP_U1DSR_IN, ESP_NOSIG) + +#define UART1_DSR_GPIO3 \ + ESP32_PINMUX(3, ESP_U1DSR_IN, ESP_NOSIG) + +#define UART1_DSR_GPIO4 \ + ESP32_PINMUX(4, ESP_U1DSR_IN, ESP_NOSIG) + +#define UART1_DSR_GPIO5 \ + ESP32_PINMUX(5, ESP_U1DSR_IN, ESP_NOSIG) + +#define UART1_DSR_GPIO6 \ + ESP32_PINMUX(6, ESP_U1DSR_IN, ESP_NOSIG) + +#define UART1_DSR_GPIO7 \ + ESP32_PINMUX(7, ESP_U1DSR_IN, ESP_NOSIG) + +#define UART1_DSR_GPIO8 \ + ESP32_PINMUX(8, ESP_U1DSR_IN, ESP_NOSIG) + +#define UART1_DSR_GPIO9 \ + ESP32_PINMUX(9, ESP_U1DSR_IN, ESP_NOSIG) + +#define UART1_DSR_GPIO10 \ + ESP32_PINMUX(10, ESP_U1DSR_IN, ESP_NOSIG) + +#define UART1_DSR_GPIO11 \ + ESP32_PINMUX(11, ESP_U1DSR_IN, ESP_NOSIG) + +#define UART1_DSR_GPIO12 \ + ESP32_PINMUX(12, ESP_U1DSR_IN, ESP_NOSIG) + +#define UART1_DSR_GPIO13 \ + ESP32_PINMUX(13, ESP_U1DSR_IN, ESP_NOSIG) + +#define UART1_DSR_GPIO14 \ + ESP32_PINMUX(14, ESP_U1DSR_IN, ESP_NOSIG) + +#define UART1_DSR_GPIO15 \ + ESP32_PINMUX(15, ESP_U1DSR_IN, ESP_NOSIG) + +#define UART1_DSR_GPIO16 \ + ESP32_PINMUX(16, ESP_U1DSR_IN, ESP_NOSIG) + +#define UART1_DSR_GPIO17 \ + ESP32_PINMUX(17, ESP_U1DSR_IN, ESP_NOSIG) + +#define UART1_DSR_GPIO18 \ + ESP32_PINMUX(18, ESP_U1DSR_IN, ESP_NOSIG) + +#define UART1_DSR_GPIO19 \ + ESP32_PINMUX(19, ESP_U1DSR_IN, ESP_NOSIG) + +#define UART1_DSR_GPIO20 \ + ESP32_PINMUX(20, ESP_U1DSR_IN, ESP_NOSIG) + +#define UART1_DSR_GPIO21 \ + ESP32_PINMUX(21, ESP_U1DSR_IN, ESP_NOSIG) + +#define UART1_DSR_GPIO26 \ + ESP32_PINMUX(26, ESP_U1DSR_IN, ESP_NOSIG) + +#define UART1_DSR_GPIO27 \ + ESP32_PINMUX(27, ESP_U1DSR_IN, ESP_NOSIG) + +#define UART1_DSR_GPIO28 \ + ESP32_PINMUX(28, ESP_U1DSR_IN, ESP_NOSIG) + +#define UART1_DSR_GPIO29 \ + ESP32_PINMUX(29, ESP_U1DSR_IN, ESP_NOSIG) + +#define UART1_DSR_GPIO30 \ + ESP32_PINMUX(30, ESP_U1DSR_IN, ESP_NOSIG) + +#define UART1_DSR_GPIO31 \ + ESP32_PINMUX(31, ESP_U1DSR_IN, ESP_NOSIG) + +#define UART1_DSR_GPIO32 \ + ESP32_PINMUX(32, ESP_U1DSR_IN, ESP_NOSIG) + +#define UART1_DSR_GPIO33 \ + ESP32_PINMUX(33, ESP_U1DSR_IN, ESP_NOSIG) + +#define UART1_DSR_GPIO34 \ + ESP32_PINMUX(34, ESP_U1DSR_IN, ESP_NOSIG) + +#define UART1_DSR_GPIO35 \ + ESP32_PINMUX(35, ESP_U1DSR_IN, ESP_NOSIG) + +#define UART1_DSR_GPIO36 \ + ESP32_PINMUX(36, ESP_U1DSR_IN, ESP_NOSIG) + +#define UART1_DSR_GPIO37 \ + ESP32_PINMUX(37, ESP_U1DSR_IN, ESP_NOSIG) + +#define UART1_DSR_GPIO38 \ + ESP32_PINMUX(38, ESP_U1DSR_IN, ESP_NOSIG) + +#define UART1_DSR_GPIO39 \ + ESP32_PINMUX(39, ESP_U1DSR_IN, ESP_NOSIG) + +#define UART1_DSR_GPIO40 \ + ESP32_PINMUX(40, ESP_U1DSR_IN, ESP_NOSIG) + +#define UART1_DSR_GPIO41 \ + ESP32_PINMUX(41, ESP_U1DSR_IN, ESP_NOSIG) + +#define UART1_DSR_GPIO42 \ + ESP32_PINMUX(42, ESP_U1DSR_IN, ESP_NOSIG) + +#define UART1_DSR_GPIO43 \ + ESP32_PINMUX(43, ESP_U1DSR_IN, ESP_NOSIG) + +#define UART1_DSR_GPIO44 \ + ESP32_PINMUX(44, ESP_U1DSR_IN, ESP_NOSIG) + +#define UART1_DSR_GPIO45 \ + ESP32_PINMUX(45, ESP_U1DSR_IN, ESP_NOSIG) + +#define UART1_DSR_GPIO46 \ + ESP32_PINMUX(46, ESP_U1DSR_IN, ESP_NOSIG) + +/* UART1_DTR */ +#define UART1_DTR_GPIO0 \ + ESP32_PINMUX(0, ESP_NOSIG, ESP_U1DTR_OUT) + +#define UART1_DTR_GPIO1 \ + ESP32_PINMUX(1, ESP_NOSIG, ESP_U1DTR_OUT) + +#define UART1_DTR_GPIO2 \ + ESP32_PINMUX(2, ESP_NOSIG, ESP_U1DTR_OUT) + +#define UART1_DTR_GPIO3 \ + ESP32_PINMUX(3, ESP_NOSIG, ESP_U1DTR_OUT) + +#define UART1_DTR_GPIO4 \ + ESP32_PINMUX(4, ESP_NOSIG, ESP_U1DTR_OUT) + +#define UART1_DTR_GPIO5 \ + ESP32_PINMUX(5, ESP_NOSIG, ESP_U1DTR_OUT) + +#define UART1_DTR_GPIO6 \ + ESP32_PINMUX(6, ESP_NOSIG, ESP_U1DTR_OUT) + +#define UART1_DTR_GPIO7 \ + ESP32_PINMUX(7, ESP_NOSIG, ESP_U1DTR_OUT) + +#define UART1_DTR_GPIO8 \ + ESP32_PINMUX(8, ESP_NOSIG, ESP_U1DTR_OUT) + +#define UART1_DTR_GPIO9 \ + ESP32_PINMUX(9, ESP_NOSIG, ESP_U1DTR_OUT) + +#define UART1_DTR_GPIO10 \ + ESP32_PINMUX(10, ESP_NOSIG, ESP_U1DTR_OUT) + +#define UART1_DTR_GPIO11 \ + ESP32_PINMUX(11, ESP_NOSIG, ESP_U1DTR_OUT) + +#define UART1_DTR_GPIO12 \ + ESP32_PINMUX(12, ESP_NOSIG, ESP_U1DTR_OUT) + +#define UART1_DTR_GPIO13 \ + ESP32_PINMUX(13, ESP_NOSIG, ESP_U1DTR_OUT) + +#define UART1_DTR_GPIO14 \ + ESP32_PINMUX(14, ESP_NOSIG, ESP_U1DTR_OUT) + +#define UART1_DTR_GPIO15 \ + ESP32_PINMUX(15, ESP_NOSIG, ESP_U1DTR_OUT) + +#define UART1_DTR_GPIO16 \ + ESP32_PINMUX(16, ESP_NOSIG, ESP_U1DTR_OUT) + +#define UART1_DTR_GPIO17 \ + ESP32_PINMUX(17, ESP_NOSIG, ESP_U1DTR_OUT) + +#define UART1_DTR_GPIO18 \ + ESP32_PINMUX(18, ESP_NOSIG, ESP_U1DTR_OUT) + +#define UART1_DTR_GPIO19 \ + ESP32_PINMUX(19, ESP_NOSIG, ESP_U1DTR_OUT) + +#define UART1_DTR_GPIO20 \ + ESP32_PINMUX(20, ESP_NOSIG, ESP_U1DTR_OUT) + +#define UART1_DTR_GPIO21 \ + ESP32_PINMUX(21, ESP_NOSIG, ESP_U1DTR_OUT) + +#define UART1_DTR_GPIO26 \ + ESP32_PINMUX(26, ESP_NOSIG, ESP_U1DTR_OUT) + +#define UART1_DTR_GPIO27 \ + ESP32_PINMUX(27, ESP_NOSIG, ESP_U1DTR_OUT) + +#define UART1_DTR_GPIO28 \ + ESP32_PINMUX(28, ESP_NOSIG, ESP_U1DTR_OUT) + +#define UART1_DTR_GPIO29 \ + ESP32_PINMUX(29, ESP_NOSIG, ESP_U1DTR_OUT) + +#define UART1_DTR_GPIO30 \ + ESP32_PINMUX(30, ESP_NOSIG, ESP_U1DTR_OUT) + +#define UART1_DTR_GPIO31 \ + ESP32_PINMUX(31, ESP_NOSIG, ESP_U1DTR_OUT) + +#define UART1_DTR_GPIO32 \ + ESP32_PINMUX(32, ESP_NOSIG, ESP_U1DTR_OUT) + +#define UART1_DTR_GPIO33 \ + ESP32_PINMUX(33, ESP_NOSIG, ESP_U1DTR_OUT) + +#define UART1_DTR_GPIO34 \ + ESP32_PINMUX(34, ESP_NOSIG, ESP_U1DTR_OUT) + +#define UART1_DTR_GPIO35 \ + ESP32_PINMUX(35, ESP_NOSIG, ESP_U1DTR_OUT) + +#define UART1_DTR_GPIO36 \ + ESP32_PINMUX(36, ESP_NOSIG, ESP_U1DTR_OUT) + +#define UART1_DTR_GPIO37 \ + ESP32_PINMUX(37, ESP_NOSIG, ESP_U1DTR_OUT) + +#define UART1_DTR_GPIO38 \ + ESP32_PINMUX(38, ESP_NOSIG, ESP_U1DTR_OUT) + +#define UART1_DTR_GPIO39 \ + ESP32_PINMUX(39, ESP_NOSIG, ESP_U1DTR_OUT) + +#define UART1_DTR_GPIO40 \ + ESP32_PINMUX(40, ESP_NOSIG, ESP_U1DTR_OUT) + +#define UART1_DTR_GPIO41 \ + ESP32_PINMUX(41, ESP_NOSIG, ESP_U1DTR_OUT) + +#define UART1_DTR_GPIO42 \ + ESP32_PINMUX(42, ESP_NOSIG, ESP_U1DTR_OUT) + +#define UART1_DTR_GPIO43 \ + ESP32_PINMUX(43, ESP_NOSIG, ESP_U1DTR_OUT) + +#define UART1_DTR_GPIO44 \ + ESP32_PINMUX(44, ESP_NOSIG, ESP_U1DTR_OUT) + +#define UART1_DTR_GPIO45 \ + ESP32_PINMUX(45, ESP_NOSIG, ESP_U1DTR_OUT) + +#define UART1_DTR_GPIO46 \ + ESP32_PINMUX(46, ESP_NOSIG, ESP_U1DTR_OUT) + +/* UART1_RTS */ +#define UART1_RTS_GPIO0 \ + ESP32_PINMUX(0, ESP_NOSIG, ESP_U1RTS_OUT) + +#define UART1_RTS_GPIO1 \ + ESP32_PINMUX(1, ESP_NOSIG, ESP_U1RTS_OUT) + +#define UART1_RTS_GPIO2 \ + ESP32_PINMUX(2, ESP_NOSIG, ESP_U1RTS_OUT) + +#define UART1_RTS_GPIO3 \ + ESP32_PINMUX(3, ESP_NOSIG, ESP_U1RTS_OUT) + +#define UART1_RTS_GPIO4 \ + ESP32_PINMUX(4, ESP_NOSIG, ESP_U1RTS_OUT) + +#define UART1_RTS_GPIO5 \ + ESP32_PINMUX(5, ESP_NOSIG, ESP_U1RTS_OUT) + +#define UART1_RTS_GPIO6 \ + ESP32_PINMUX(6, ESP_NOSIG, ESP_U1RTS_OUT) + +#define UART1_RTS_GPIO7 \ + ESP32_PINMUX(7, ESP_NOSIG, ESP_U1RTS_OUT) + +#define UART1_RTS_GPIO8 \ + ESP32_PINMUX(8, ESP_NOSIG, ESP_U1RTS_OUT) + +#define UART1_RTS_GPIO9 \ + ESP32_PINMUX(9, ESP_NOSIG, ESP_U1RTS_OUT) + +#define UART1_RTS_GPIO10 \ + ESP32_PINMUX(10, ESP_NOSIG, ESP_U1RTS_OUT) + +#define UART1_RTS_GPIO11 \ + ESP32_PINMUX(11, ESP_NOSIG, ESP_U1RTS_OUT) + +#define UART1_RTS_GPIO12 \ + ESP32_PINMUX(12, ESP_NOSIG, ESP_U1RTS_OUT) + +#define UART1_RTS_GPIO13 \ + ESP32_PINMUX(13, ESP_NOSIG, ESP_U1RTS_OUT) + +#define UART1_RTS_GPIO14 \ + ESP32_PINMUX(14, ESP_NOSIG, ESP_U1RTS_OUT) + +#define UART1_RTS_GPIO15 \ + ESP32_PINMUX(15, ESP_NOSIG, ESP_U1RTS_OUT) + +#define UART1_RTS_GPIO16 \ + ESP32_PINMUX(16, ESP_NOSIG, ESP_U1RTS_OUT) + +#define UART1_RTS_GPIO17 \ + ESP32_PINMUX(17, ESP_NOSIG, ESP_U1RTS_OUT) + +#define UART1_RTS_GPIO18 \ + ESP32_PINMUX(18, ESP_NOSIG, ESP_U1RTS_OUT) + +#define UART1_RTS_GPIO19 \ + ESP32_PINMUX(19, ESP_NOSIG, ESP_U1RTS_OUT) + +#define UART1_RTS_GPIO20 \ + ESP32_PINMUX(20, ESP_NOSIG, ESP_U1RTS_OUT) + +#define UART1_RTS_GPIO21 \ + ESP32_PINMUX(21, ESP_NOSIG, ESP_U1RTS_OUT) + +#define UART1_RTS_GPIO26 \ + ESP32_PINMUX(26, ESP_NOSIG, ESP_U1RTS_OUT) + +#define UART1_RTS_GPIO27 \ + ESP32_PINMUX(27, ESP_NOSIG, ESP_U1RTS_OUT) + +#define UART1_RTS_GPIO28 \ + ESP32_PINMUX(28, ESP_NOSIG, ESP_U1RTS_OUT) + +#define UART1_RTS_GPIO29 \ + ESP32_PINMUX(29, ESP_NOSIG, ESP_U1RTS_OUT) + +#define UART1_RTS_GPIO30 \ + ESP32_PINMUX(30, ESP_NOSIG, ESP_U1RTS_OUT) + +#define UART1_RTS_GPIO31 \ + ESP32_PINMUX(31, ESP_NOSIG, ESP_U1RTS_OUT) + +#define UART1_RTS_GPIO32 \ + ESP32_PINMUX(32, ESP_NOSIG, ESP_U1RTS_OUT) + +#define UART1_RTS_GPIO33 \ + ESP32_PINMUX(33, ESP_NOSIG, ESP_U1RTS_OUT) + +#define UART1_RTS_GPIO34 \ + ESP32_PINMUX(34, ESP_NOSIG, ESP_U1RTS_OUT) + +#define UART1_RTS_GPIO35 \ + ESP32_PINMUX(35, ESP_NOSIG, ESP_U1RTS_OUT) + +#define UART1_RTS_GPIO36 \ + ESP32_PINMUX(36, ESP_NOSIG, ESP_U1RTS_OUT) + +#define UART1_RTS_GPIO37 \ + ESP32_PINMUX(37, ESP_NOSIG, ESP_U1RTS_OUT) + +#define UART1_RTS_GPIO38 \ + ESP32_PINMUX(38, ESP_NOSIG, ESP_U1RTS_OUT) + +#define UART1_RTS_GPIO39 \ + ESP32_PINMUX(39, ESP_NOSIG, ESP_U1RTS_OUT) + +#define UART1_RTS_GPIO40 \ + ESP32_PINMUX(40, ESP_NOSIG, ESP_U1RTS_OUT) + +#define UART1_RTS_GPIO41 \ + ESP32_PINMUX(41, ESP_NOSIG, ESP_U1RTS_OUT) + +#define UART1_RTS_GPIO42 \ + ESP32_PINMUX(42, ESP_NOSIG, ESP_U1RTS_OUT) + +#define UART1_RTS_GPIO43 \ + ESP32_PINMUX(43, ESP_NOSIG, ESP_U1RTS_OUT) + +#define UART1_RTS_GPIO44 \ + ESP32_PINMUX(44, ESP_NOSIG, ESP_U1RTS_OUT) + +#define UART1_RTS_GPIO45 \ + ESP32_PINMUX(45, ESP_NOSIG, ESP_U1RTS_OUT) + +/* UART1_RX */ +#define UART1_RX_GPIO0 \ + ESP32_PINMUX(0, ESP_U1RXD_IN, ESP_NOSIG) + +#define UART1_RX_GPIO1 \ + ESP32_PINMUX(1, ESP_U1RXD_IN, ESP_NOSIG) + +#define UART1_RX_GPIO2 \ + ESP32_PINMUX(2, ESP_U1RXD_IN, ESP_NOSIG) + +#define UART1_RX_GPIO3 \ + ESP32_PINMUX(3, ESP_U1RXD_IN, ESP_NOSIG) + +#define UART1_RX_GPIO4 \ + ESP32_PINMUX(4, ESP_U1RXD_IN, ESP_NOSIG) + +#define UART1_RX_GPIO5 \ + ESP32_PINMUX(5, ESP_U1RXD_IN, ESP_NOSIG) + +#define UART1_RX_GPIO6 \ + ESP32_PINMUX(6, ESP_U1RXD_IN, ESP_NOSIG) + +#define UART1_RX_GPIO7 \ + ESP32_PINMUX(7, ESP_U1RXD_IN, ESP_NOSIG) + +#define UART1_RX_GPIO8 \ + ESP32_PINMUX(8, ESP_U1RXD_IN, ESP_NOSIG) + +#define UART1_RX_GPIO9 \ + ESP32_PINMUX(9, ESP_U1RXD_IN, ESP_NOSIG) + +#define UART1_RX_GPIO10 \ + ESP32_PINMUX(10, ESP_U1RXD_IN, ESP_NOSIG) + +#define UART1_RX_GPIO11 \ + ESP32_PINMUX(11, ESP_U1RXD_IN, ESP_NOSIG) + +#define UART1_RX_GPIO12 \ + ESP32_PINMUX(12, ESP_U1RXD_IN, ESP_NOSIG) + +#define UART1_RX_GPIO13 \ + ESP32_PINMUX(13, ESP_U1RXD_IN, ESP_NOSIG) + +#define UART1_RX_GPIO14 \ + ESP32_PINMUX(14, ESP_U1RXD_IN, ESP_NOSIG) + +#define UART1_RX_GPIO15 \ + ESP32_PINMUX(15, ESP_U1RXD_IN, ESP_NOSIG) + +#define UART1_RX_GPIO16 \ + ESP32_PINMUX(16, ESP_U1RXD_IN, ESP_NOSIG) + +#define UART1_RX_GPIO17 \ + ESP32_PINMUX(17, ESP_U1RXD_IN, ESP_NOSIG) + +#define UART1_RX_GPIO18 \ + ESP32_PINMUX(18, ESP_U1RXD_IN, ESP_NOSIG) + +#define UART1_RX_GPIO19 \ + ESP32_PINMUX(19, ESP_U1RXD_IN, ESP_NOSIG) + +#define UART1_RX_GPIO20 \ + ESP32_PINMUX(20, ESP_U1RXD_IN, ESP_NOSIG) + +#define UART1_RX_GPIO21 \ + ESP32_PINMUX(21, ESP_U1RXD_IN, ESP_NOSIG) + +#define UART1_RX_GPIO26 \ + ESP32_PINMUX(26, ESP_U1RXD_IN, ESP_NOSIG) + +#define UART1_RX_GPIO27 \ + ESP32_PINMUX(27, ESP_U1RXD_IN, ESP_NOSIG) + +#define UART1_RX_GPIO28 \ + ESP32_PINMUX(28, ESP_U1RXD_IN, ESP_NOSIG) + +#define UART1_RX_GPIO29 \ + ESP32_PINMUX(29, ESP_U1RXD_IN, ESP_NOSIG) + +#define UART1_RX_GPIO30 \ + ESP32_PINMUX(30, ESP_U1RXD_IN, ESP_NOSIG) + +#define UART1_RX_GPIO31 \ + ESP32_PINMUX(31, ESP_U1RXD_IN, ESP_NOSIG) + +#define UART1_RX_GPIO32 \ + ESP32_PINMUX(32, ESP_U1RXD_IN, ESP_NOSIG) + +#define UART1_RX_GPIO33 \ + ESP32_PINMUX(33, ESP_U1RXD_IN, ESP_NOSIG) + +#define UART1_RX_GPIO34 \ + ESP32_PINMUX(34, ESP_U1RXD_IN, ESP_NOSIG) + +#define UART1_RX_GPIO35 \ + ESP32_PINMUX(35, ESP_U1RXD_IN, ESP_NOSIG) + +#define UART1_RX_GPIO36 \ + ESP32_PINMUX(36, ESP_U1RXD_IN, ESP_NOSIG) + +#define UART1_RX_GPIO37 \ + ESP32_PINMUX(37, ESP_U1RXD_IN, ESP_NOSIG) + +#define UART1_RX_GPIO38 \ + ESP32_PINMUX(38, ESP_U1RXD_IN, ESP_NOSIG) + +#define UART1_RX_GPIO39 \ + ESP32_PINMUX(39, ESP_U1RXD_IN, ESP_NOSIG) + +#define UART1_RX_GPIO40 \ + ESP32_PINMUX(40, ESP_U1RXD_IN, ESP_NOSIG) + +#define UART1_RX_GPIO41 \ + ESP32_PINMUX(41, ESP_U1RXD_IN, ESP_NOSIG) + +#define UART1_RX_GPIO42 \ + ESP32_PINMUX(42, ESP_U1RXD_IN, ESP_NOSIG) + +#define UART1_RX_GPIO43 \ + ESP32_PINMUX(43, ESP_U1RXD_IN, ESP_NOSIG) + +#define UART1_RX_GPIO44 \ + ESP32_PINMUX(44, ESP_U1RXD_IN, ESP_NOSIG) + +#define UART1_RX_GPIO45 \ + ESP32_PINMUX(45, ESP_U1RXD_IN, ESP_NOSIG) + +#define UART1_RX_GPIO46 \ + ESP32_PINMUX(46, ESP_U1RXD_IN, ESP_NOSIG) + +/* UART1_TX */ +#define UART1_TX_GPIO0 \ + ESP32_PINMUX(0, ESP_NOSIG, ESP_U1TXD_OUT) + +#define UART1_TX_GPIO1 \ + ESP32_PINMUX(1, ESP_NOSIG, ESP_U1TXD_OUT) + +#define UART1_TX_GPIO2 \ + ESP32_PINMUX(2, ESP_NOSIG, ESP_U1TXD_OUT) + +#define UART1_TX_GPIO3 \ + ESP32_PINMUX(3, ESP_NOSIG, ESP_U1TXD_OUT) + +#define UART1_TX_GPIO4 \ + ESP32_PINMUX(4, ESP_NOSIG, ESP_U1TXD_OUT) + +#define UART1_TX_GPIO5 \ + ESP32_PINMUX(5, ESP_NOSIG, ESP_U1TXD_OUT) + +#define UART1_TX_GPIO6 \ + ESP32_PINMUX(6, ESP_NOSIG, ESP_U1TXD_OUT) + +#define UART1_TX_GPIO7 \ + ESP32_PINMUX(7, ESP_NOSIG, ESP_U1TXD_OUT) + +#define UART1_TX_GPIO8 \ + ESP32_PINMUX(8, ESP_NOSIG, ESP_U1TXD_OUT) + +#define UART1_TX_GPIO9 \ + ESP32_PINMUX(9, ESP_NOSIG, ESP_U1TXD_OUT) + +#define UART1_TX_GPIO10 \ + ESP32_PINMUX(10, ESP_NOSIG, ESP_U1TXD_OUT) + +#define UART1_TX_GPIO11 \ + ESP32_PINMUX(11, ESP_NOSIG, ESP_U1TXD_OUT) + +#define UART1_TX_GPIO12 \ + ESP32_PINMUX(12, ESP_NOSIG, ESP_U1TXD_OUT) + +#define UART1_TX_GPIO13 \ + ESP32_PINMUX(13, ESP_NOSIG, ESP_U1TXD_OUT) + +#define UART1_TX_GPIO14 \ + ESP32_PINMUX(14, ESP_NOSIG, ESP_U1TXD_OUT) + +#define UART1_TX_GPIO15 \ + ESP32_PINMUX(15, ESP_NOSIG, ESP_U1TXD_OUT) + +#define UART1_TX_GPIO16 \ + ESP32_PINMUX(16, ESP_NOSIG, ESP_U1TXD_OUT) + +#define UART1_TX_GPIO17 \ + ESP32_PINMUX(17, ESP_NOSIG, ESP_U1TXD_OUT) + +#define UART1_TX_GPIO18 \ + ESP32_PINMUX(18, ESP_NOSIG, ESP_U1TXD_OUT) + +#define UART1_TX_GPIO19 \ + ESP32_PINMUX(19, ESP_NOSIG, ESP_U1TXD_OUT) + +#define UART1_TX_GPIO20 \ + ESP32_PINMUX(20, ESP_NOSIG, ESP_U1TXD_OUT) + +#define UART1_TX_GPIO21 \ + ESP32_PINMUX(21, ESP_NOSIG, ESP_U1TXD_OUT) + +#define UART1_TX_GPIO26 \ + ESP32_PINMUX(26, ESP_NOSIG, ESP_U1TXD_OUT) + +#define UART1_TX_GPIO27 \ + ESP32_PINMUX(27, ESP_NOSIG, ESP_U1TXD_OUT) + +#define UART1_TX_GPIO28 \ + ESP32_PINMUX(28, ESP_NOSIG, ESP_U1TXD_OUT) + +#define UART1_TX_GPIO29 \ + ESP32_PINMUX(29, ESP_NOSIG, ESP_U1TXD_OUT) + +#define UART1_TX_GPIO30 \ + ESP32_PINMUX(30, ESP_NOSIG, ESP_U1TXD_OUT) + +#define UART1_TX_GPIO31 \ + ESP32_PINMUX(31, ESP_NOSIG, ESP_U1TXD_OUT) + +#define UART1_TX_GPIO32 \ + ESP32_PINMUX(32, ESP_NOSIG, ESP_U1TXD_OUT) + +#define UART1_TX_GPIO33 \ + ESP32_PINMUX(33, ESP_NOSIG, ESP_U1TXD_OUT) + +#define UART1_TX_GPIO34 \ + ESP32_PINMUX(34, ESP_NOSIG, ESP_U1TXD_OUT) + +#define UART1_TX_GPIO35 \ + ESP32_PINMUX(35, ESP_NOSIG, ESP_U1TXD_OUT) + +#define UART1_TX_GPIO36 \ + ESP32_PINMUX(36, ESP_NOSIG, ESP_U1TXD_OUT) + +#define UART1_TX_GPIO37 \ + ESP32_PINMUX(37, ESP_NOSIG, ESP_U1TXD_OUT) + +#define UART1_TX_GPIO38 \ + ESP32_PINMUX(38, ESP_NOSIG, ESP_U1TXD_OUT) + +#define UART1_TX_GPIO39 \ + ESP32_PINMUX(39, ESP_NOSIG, ESP_U1TXD_OUT) + +#define UART1_TX_GPIO40 \ + ESP32_PINMUX(40, ESP_NOSIG, ESP_U1TXD_OUT) + +#define UART1_TX_GPIO41 \ + ESP32_PINMUX(41, ESP_NOSIG, ESP_U1TXD_OUT) + +#define UART1_TX_GPIO42 \ + ESP32_PINMUX(42, ESP_NOSIG, ESP_U1TXD_OUT) + +#define UART1_TX_GPIO43 \ + ESP32_PINMUX(43, ESP_NOSIG, ESP_U1TXD_OUT) + +#define UART1_TX_GPIO44 \ + ESP32_PINMUX(44, ESP_NOSIG, ESP_U1TXD_OUT) + +#define UART1_TX_GPIO45 \ + ESP32_PINMUX(45, ESP_NOSIG, ESP_U1TXD_OUT) + + +#endif /* INC_DT_BINDS_PINCTRL_ESP32S2_PINCTRL_HAL_H_ */ diff --git a/include/zephyr/dt-bindings/pinctrl/esp32s3-pinctrl.h b/include/zephyr/dt-bindings/pinctrl/esp32s3-pinctrl.h new file mode 100644 index 00000000000..f8713bec265 --- /dev/null +++ b/include/zephyr/dt-bindings/pinctrl/esp32s3-pinctrl.h @@ -0,0 +1,12661 @@ +/* + * Copyright (c) 2022 Espressif Systems (Shanghai) Co., Ltd. + * + * SPDX-License-Identifier: Apache-2.0 + * + * NOTE: Autogenerated file using esp_genpinctrl.py + */ + +#ifndef INC_DT_BINDS_PINCTRL_ESP32S3_PINCTRL_HAL_H_ +#define INC_DT_BINDS_PINCTRL_ESP32S3_PINCTRL_HAL_H_ + +/* I2C0_SCL */ +#define I2C0_SCL_GPIO0 \ + ESP32_PINMUX(0, ESP_I2CEXT0_SCL_IN, ESP_I2CEXT0_SCL_OUT) + +#define I2C0_SCL_GPIO1 \ + ESP32_PINMUX(1, ESP_I2CEXT0_SCL_IN, ESP_I2CEXT0_SCL_OUT) + +#define I2C0_SCL_GPIO2 \ + ESP32_PINMUX(2, ESP_I2CEXT0_SCL_IN, ESP_I2CEXT0_SCL_OUT) + +#define I2C0_SCL_GPIO3 \ + ESP32_PINMUX(3, ESP_I2CEXT0_SCL_IN, ESP_I2CEXT0_SCL_OUT) + +#define I2C0_SCL_GPIO4 \ + ESP32_PINMUX(4, ESP_I2CEXT0_SCL_IN, ESP_I2CEXT0_SCL_OUT) + +#define I2C0_SCL_GPIO5 \ + ESP32_PINMUX(5, ESP_I2CEXT0_SCL_IN, ESP_I2CEXT0_SCL_OUT) + +#define I2C0_SCL_GPIO6 \ + ESP32_PINMUX(6, ESP_I2CEXT0_SCL_IN, ESP_I2CEXT0_SCL_OUT) + +#define I2C0_SCL_GPIO7 \ + ESP32_PINMUX(7, ESP_I2CEXT0_SCL_IN, ESP_I2CEXT0_SCL_OUT) + +#define I2C0_SCL_GPIO8 \ + ESP32_PINMUX(8, ESP_I2CEXT0_SCL_IN, ESP_I2CEXT0_SCL_OUT) + +#define I2C0_SCL_GPIO9 \ + ESP32_PINMUX(9, ESP_I2CEXT0_SCL_IN, ESP_I2CEXT0_SCL_OUT) + +#define I2C0_SCL_GPIO10 \ + ESP32_PINMUX(10, ESP_I2CEXT0_SCL_IN, ESP_I2CEXT0_SCL_OUT) + +#define I2C0_SCL_GPIO11 \ + ESP32_PINMUX(11, ESP_I2CEXT0_SCL_IN, ESP_I2CEXT0_SCL_OUT) + +#define I2C0_SCL_GPIO12 \ + ESP32_PINMUX(12, ESP_I2CEXT0_SCL_IN, ESP_I2CEXT0_SCL_OUT) + +#define I2C0_SCL_GPIO13 \ + ESP32_PINMUX(13, ESP_I2CEXT0_SCL_IN, ESP_I2CEXT0_SCL_OUT) + +#define I2C0_SCL_GPIO14 \ + ESP32_PINMUX(14, ESP_I2CEXT0_SCL_IN, ESP_I2CEXT0_SCL_OUT) + +#define I2C0_SCL_GPIO15 \ + ESP32_PINMUX(15, ESP_I2CEXT0_SCL_IN, ESP_I2CEXT0_SCL_OUT) + +#define I2C0_SCL_GPIO16 \ + ESP32_PINMUX(16, ESP_I2CEXT0_SCL_IN, ESP_I2CEXT0_SCL_OUT) + +#define I2C0_SCL_GPIO17 \ + ESP32_PINMUX(17, ESP_I2CEXT0_SCL_IN, ESP_I2CEXT0_SCL_OUT) + +#define I2C0_SCL_GPIO18 \ + ESP32_PINMUX(18, ESP_I2CEXT0_SCL_IN, ESP_I2CEXT0_SCL_OUT) + +#define I2C0_SCL_GPIO19 \ + ESP32_PINMUX(19, ESP_I2CEXT0_SCL_IN, ESP_I2CEXT0_SCL_OUT) + +#define I2C0_SCL_GPIO20 \ + ESP32_PINMUX(20, ESP_I2CEXT0_SCL_IN, ESP_I2CEXT0_SCL_OUT) + +#define I2C0_SCL_GPIO21 \ + ESP32_PINMUX(21, ESP_I2CEXT0_SCL_IN, ESP_I2CEXT0_SCL_OUT) + +#define I2C0_SCL_GPIO26 \ + ESP32_PINMUX(26, ESP_I2CEXT0_SCL_IN, ESP_I2CEXT0_SCL_OUT) + +#define I2C0_SCL_GPIO27 \ + ESP32_PINMUX(27, ESP_I2CEXT0_SCL_IN, ESP_I2CEXT0_SCL_OUT) + +#define I2C0_SCL_GPIO28 \ + ESP32_PINMUX(28, ESP_I2CEXT0_SCL_IN, ESP_I2CEXT0_SCL_OUT) + +#define I2C0_SCL_GPIO29 \ + ESP32_PINMUX(29, ESP_I2CEXT0_SCL_IN, ESP_I2CEXT0_SCL_OUT) + +#define I2C0_SCL_GPIO30 \ + ESP32_PINMUX(30, ESP_I2CEXT0_SCL_IN, ESP_I2CEXT0_SCL_OUT) + +#define I2C0_SCL_GPIO31 \ + ESP32_PINMUX(31, ESP_I2CEXT0_SCL_IN, ESP_I2CEXT0_SCL_OUT) + +#define I2C0_SCL_GPIO32 \ + ESP32_PINMUX(32, ESP_I2CEXT0_SCL_IN, ESP_I2CEXT0_SCL_OUT) + +#define I2C0_SCL_GPIO33 \ + ESP32_PINMUX(33, ESP_I2CEXT0_SCL_IN, ESP_I2CEXT0_SCL_OUT) + +#define I2C0_SCL_GPIO34 \ + ESP32_PINMUX(34, ESP_I2CEXT0_SCL_IN, ESP_I2CEXT0_SCL_OUT) + +#define I2C0_SCL_GPIO35 \ + ESP32_PINMUX(35, ESP_I2CEXT0_SCL_IN, ESP_I2CEXT0_SCL_OUT) + +#define I2C0_SCL_GPIO36 \ + ESP32_PINMUX(36, ESP_I2CEXT0_SCL_IN, ESP_I2CEXT0_SCL_OUT) + +#define I2C0_SCL_GPIO37 \ + ESP32_PINMUX(37, ESP_I2CEXT0_SCL_IN, ESP_I2CEXT0_SCL_OUT) + +#define I2C0_SCL_GPIO38 \ + ESP32_PINMUX(38, ESP_I2CEXT0_SCL_IN, ESP_I2CEXT0_SCL_OUT) + +#define I2C0_SCL_GPIO39 \ + ESP32_PINMUX(39, ESP_I2CEXT0_SCL_IN, ESP_I2CEXT0_SCL_OUT) + +#define I2C0_SCL_GPIO40 \ + ESP32_PINMUX(40, ESP_I2CEXT0_SCL_IN, ESP_I2CEXT0_SCL_OUT) + +#define I2C0_SCL_GPIO41 \ + ESP32_PINMUX(41, ESP_I2CEXT0_SCL_IN, ESP_I2CEXT0_SCL_OUT) + +#define I2C0_SCL_GPIO42 \ + ESP32_PINMUX(42, ESP_I2CEXT0_SCL_IN, ESP_I2CEXT0_SCL_OUT) + +#define I2C0_SCL_GPIO43 \ + ESP32_PINMUX(43, ESP_I2CEXT0_SCL_IN, ESP_I2CEXT0_SCL_OUT) + +#define I2C0_SCL_GPIO44 \ + ESP32_PINMUX(44, ESP_I2CEXT0_SCL_IN, ESP_I2CEXT0_SCL_OUT) + +#define I2C0_SCL_GPIO45 \ + ESP32_PINMUX(45, ESP_I2CEXT0_SCL_IN, ESP_I2CEXT0_SCL_OUT) + +#define I2C0_SCL_GPIO46 \ + ESP32_PINMUX(46, ESP_I2CEXT0_SCL_IN, ESP_I2CEXT0_SCL_OUT) + +#define I2C0_SCL_GPIO47 \ + ESP32_PINMUX(47, ESP_I2CEXT0_SCL_IN, ESP_I2CEXT0_SCL_OUT) + +#define I2C0_SCL_GPIO48 \ + ESP32_PINMUX(48, ESP_I2CEXT0_SCL_IN, ESP_I2CEXT0_SCL_OUT) + +/* I2C0_SDA */ +#define I2C0_SDA_GPIO0 \ + ESP32_PINMUX(0, ESP_I2CEXT0_SDA_IN, ESP_I2CEXT0_SDA_OUT) + +#define I2C0_SDA_GPIO1 \ + ESP32_PINMUX(1, ESP_I2CEXT0_SDA_IN, ESP_I2CEXT0_SDA_OUT) + +#define I2C0_SDA_GPIO2 \ + ESP32_PINMUX(2, ESP_I2CEXT0_SDA_IN, ESP_I2CEXT0_SDA_OUT) + +#define I2C0_SDA_GPIO3 \ + ESP32_PINMUX(3, ESP_I2CEXT0_SDA_IN, ESP_I2CEXT0_SDA_OUT) + +#define I2C0_SDA_GPIO4 \ + ESP32_PINMUX(4, ESP_I2CEXT0_SDA_IN, ESP_I2CEXT0_SDA_OUT) + +#define I2C0_SDA_GPIO5 \ + ESP32_PINMUX(5, ESP_I2CEXT0_SDA_IN, ESP_I2CEXT0_SDA_OUT) + +#define I2C0_SDA_GPIO6 \ + ESP32_PINMUX(6, ESP_I2CEXT0_SDA_IN, ESP_I2CEXT0_SDA_OUT) + +#define I2C0_SDA_GPIO7 \ + ESP32_PINMUX(7, ESP_I2CEXT0_SDA_IN, ESP_I2CEXT0_SDA_OUT) + +#define I2C0_SDA_GPIO8 \ + ESP32_PINMUX(8, ESP_I2CEXT0_SDA_IN, ESP_I2CEXT0_SDA_OUT) + +#define I2C0_SDA_GPIO9 \ + ESP32_PINMUX(9, ESP_I2CEXT0_SDA_IN, ESP_I2CEXT0_SDA_OUT) + +#define I2C0_SDA_GPIO10 \ + ESP32_PINMUX(10, ESP_I2CEXT0_SDA_IN, ESP_I2CEXT0_SDA_OUT) + +#define I2C0_SDA_GPIO11 \ + ESP32_PINMUX(11, ESP_I2CEXT0_SDA_IN, ESP_I2CEXT0_SDA_OUT) + +#define I2C0_SDA_GPIO12 \ + ESP32_PINMUX(12, ESP_I2CEXT0_SDA_IN, ESP_I2CEXT0_SDA_OUT) + +#define I2C0_SDA_GPIO13 \ + ESP32_PINMUX(13, ESP_I2CEXT0_SDA_IN, ESP_I2CEXT0_SDA_OUT) + +#define I2C0_SDA_GPIO14 \ + ESP32_PINMUX(14, ESP_I2CEXT0_SDA_IN, ESP_I2CEXT0_SDA_OUT) + +#define I2C0_SDA_GPIO15 \ + ESP32_PINMUX(15, ESP_I2CEXT0_SDA_IN, ESP_I2CEXT0_SDA_OUT) + +#define I2C0_SDA_GPIO16 \ + ESP32_PINMUX(16, ESP_I2CEXT0_SDA_IN, ESP_I2CEXT0_SDA_OUT) + +#define I2C0_SDA_GPIO17 \ + ESP32_PINMUX(17, ESP_I2CEXT0_SDA_IN, ESP_I2CEXT0_SDA_OUT) + +#define I2C0_SDA_GPIO18 \ + ESP32_PINMUX(18, ESP_I2CEXT0_SDA_IN, ESP_I2CEXT0_SDA_OUT) + +#define I2C0_SDA_GPIO19 \ + ESP32_PINMUX(19, ESP_I2CEXT0_SDA_IN, ESP_I2CEXT0_SDA_OUT) + +#define I2C0_SDA_GPIO20 \ + ESP32_PINMUX(20, ESP_I2CEXT0_SDA_IN, ESP_I2CEXT0_SDA_OUT) + +#define I2C0_SDA_GPIO21 \ + ESP32_PINMUX(21, ESP_I2CEXT0_SDA_IN, ESP_I2CEXT0_SDA_OUT) + +#define I2C0_SDA_GPIO26 \ + ESP32_PINMUX(26, ESP_I2CEXT0_SDA_IN, ESP_I2CEXT0_SDA_OUT) + +#define I2C0_SDA_GPIO27 \ + ESP32_PINMUX(27, ESP_I2CEXT0_SDA_IN, ESP_I2CEXT0_SDA_OUT) + +#define I2C0_SDA_GPIO28 \ + ESP32_PINMUX(28, ESP_I2CEXT0_SDA_IN, ESP_I2CEXT0_SDA_OUT) + +#define I2C0_SDA_GPIO29 \ + ESP32_PINMUX(29, ESP_I2CEXT0_SDA_IN, ESP_I2CEXT0_SDA_OUT) + +#define I2C0_SDA_GPIO30 \ + ESP32_PINMUX(30, ESP_I2CEXT0_SDA_IN, ESP_I2CEXT0_SDA_OUT) + +#define I2C0_SDA_GPIO31 \ + ESP32_PINMUX(31, ESP_I2CEXT0_SDA_IN, ESP_I2CEXT0_SDA_OUT) + +#define I2C0_SDA_GPIO32 \ + ESP32_PINMUX(32, ESP_I2CEXT0_SDA_IN, ESP_I2CEXT0_SDA_OUT) + +#define I2C0_SDA_GPIO33 \ + ESP32_PINMUX(33, ESP_I2CEXT0_SDA_IN, ESP_I2CEXT0_SDA_OUT) + +#define I2C0_SDA_GPIO34 \ + ESP32_PINMUX(34, ESP_I2CEXT0_SDA_IN, ESP_I2CEXT0_SDA_OUT) + +#define I2C0_SDA_GPIO35 \ + ESP32_PINMUX(35, ESP_I2CEXT0_SDA_IN, ESP_I2CEXT0_SDA_OUT) + +#define I2C0_SDA_GPIO36 \ + ESP32_PINMUX(36, ESP_I2CEXT0_SDA_IN, ESP_I2CEXT0_SDA_OUT) + +#define I2C0_SDA_GPIO37 \ + ESP32_PINMUX(37, ESP_I2CEXT0_SDA_IN, ESP_I2CEXT0_SDA_OUT) + +#define I2C0_SDA_GPIO38 \ + ESP32_PINMUX(38, ESP_I2CEXT0_SDA_IN, ESP_I2CEXT0_SDA_OUT) + +#define I2C0_SDA_GPIO39 \ + ESP32_PINMUX(39, ESP_I2CEXT0_SDA_IN, ESP_I2CEXT0_SDA_OUT) + +#define I2C0_SDA_GPIO40 \ + ESP32_PINMUX(40, ESP_I2CEXT0_SDA_IN, ESP_I2CEXT0_SDA_OUT) + +#define I2C0_SDA_GPIO41 \ + ESP32_PINMUX(41, ESP_I2CEXT0_SDA_IN, ESP_I2CEXT0_SDA_OUT) + +#define I2C0_SDA_GPIO42 \ + ESP32_PINMUX(42, ESP_I2CEXT0_SDA_IN, ESP_I2CEXT0_SDA_OUT) + +#define I2C0_SDA_GPIO43 \ + ESP32_PINMUX(43, ESP_I2CEXT0_SDA_IN, ESP_I2CEXT0_SDA_OUT) + +#define I2C0_SDA_GPIO44 \ + ESP32_PINMUX(44, ESP_I2CEXT0_SDA_IN, ESP_I2CEXT0_SDA_OUT) + +#define I2C0_SDA_GPIO45 \ + ESP32_PINMUX(45, ESP_I2CEXT0_SDA_IN, ESP_I2CEXT0_SDA_OUT) + +#define I2C0_SDA_GPIO46 \ + ESP32_PINMUX(46, ESP_I2CEXT0_SDA_IN, ESP_I2CEXT0_SDA_OUT) + +#define I2C0_SDA_GPIO47 \ + ESP32_PINMUX(47, ESP_I2CEXT0_SDA_IN, ESP_I2CEXT0_SDA_OUT) + +#define I2C0_SDA_GPIO48 \ + ESP32_PINMUX(48, ESP_I2CEXT0_SDA_IN, ESP_I2CEXT0_SDA_OUT) + +/* I2C1_SCL */ +#define I2C1_SCL_GPIO0 \ + ESP32_PINMUX(0, ESP_I2CEXT1_SCL_IN, ESP_I2CEXT1_SCL_OUT) + +#define I2C1_SCL_GPIO1 \ + ESP32_PINMUX(1, ESP_I2CEXT1_SCL_IN, ESP_I2CEXT1_SCL_OUT) + +#define I2C1_SCL_GPIO2 \ + ESP32_PINMUX(2, ESP_I2CEXT1_SCL_IN, ESP_I2CEXT1_SCL_OUT) + +#define I2C1_SCL_GPIO3 \ + ESP32_PINMUX(3, ESP_I2CEXT1_SCL_IN, ESP_I2CEXT1_SCL_OUT) + +#define I2C1_SCL_GPIO4 \ + ESP32_PINMUX(4, ESP_I2CEXT1_SCL_IN, ESP_I2CEXT1_SCL_OUT) + +#define I2C1_SCL_GPIO5 \ + ESP32_PINMUX(5, ESP_I2CEXT1_SCL_IN, ESP_I2CEXT1_SCL_OUT) + +#define I2C1_SCL_GPIO6 \ + ESP32_PINMUX(6, ESP_I2CEXT1_SCL_IN, ESP_I2CEXT1_SCL_OUT) + +#define I2C1_SCL_GPIO7 \ + ESP32_PINMUX(7, ESP_I2CEXT1_SCL_IN, ESP_I2CEXT1_SCL_OUT) + +#define I2C1_SCL_GPIO8 \ + ESP32_PINMUX(8, ESP_I2CEXT1_SCL_IN, ESP_I2CEXT1_SCL_OUT) + +#define I2C1_SCL_GPIO9 \ + ESP32_PINMUX(9, ESP_I2CEXT1_SCL_IN, ESP_I2CEXT1_SCL_OUT) + +#define I2C1_SCL_GPIO10 \ + ESP32_PINMUX(10, ESP_I2CEXT1_SCL_IN, ESP_I2CEXT1_SCL_OUT) + +#define I2C1_SCL_GPIO11 \ + ESP32_PINMUX(11, ESP_I2CEXT1_SCL_IN, ESP_I2CEXT1_SCL_OUT) + +#define I2C1_SCL_GPIO12 \ + ESP32_PINMUX(12, ESP_I2CEXT1_SCL_IN, ESP_I2CEXT1_SCL_OUT) + +#define I2C1_SCL_GPIO13 \ + ESP32_PINMUX(13, ESP_I2CEXT1_SCL_IN, ESP_I2CEXT1_SCL_OUT) + +#define I2C1_SCL_GPIO14 \ + ESP32_PINMUX(14, ESP_I2CEXT1_SCL_IN, ESP_I2CEXT1_SCL_OUT) + +#define I2C1_SCL_GPIO15 \ + ESP32_PINMUX(15, ESP_I2CEXT1_SCL_IN, ESP_I2CEXT1_SCL_OUT) + +#define I2C1_SCL_GPIO16 \ + ESP32_PINMUX(16, ESP_I2CEXT1_SCL_IN, ESP_I2CEXT1_SCL_OUT) + +#define I2C1_SCL_GPIO17 \ + ESP32_PINMUX(17, ESP_I2CEXT1_SCL_IN, ESP_I2CEXT1_SCL_OUT) + +#define I2C1_SCL_GPIO18 \ + ESP32_PINMUX(18, ESP_I2CEXT1_SCL_IN, ESP_I2CEXT1_SCL_OUT) + +#define I2C1_SCL_GPIO19 \ + ESP32_PINMUX(19, ESP_I2CEXT1_SCL_IN, ESP_I2CEXT1_SCL_OUT) + +#define I2C1_SCL_GPIO20 \ + ESP32_PINMUX(20, ESP_I2CEXT1_SCL_IN, ESP_I2CEXT1_SCL_OUT) + +#define I2C1_SCL_GPIO21 \ + ESP32_PINMUX(21, ESP_I2CEXT1_SCL_IN, ESP_I2CEXT1_SCL_OUT) + +#define I2C1_SCL_GPIO26 \ + ESP32_PINMUX(26, ESP_I2CEXT1_SCL_IN, ESP_I2CEXT1_SCL_OUT) + +#define I2C1_SCL_GPIO27 \ + ESP32_PINMUX(27, ESP_I2CEXT1_SCL_IN, ESP_I2CEXT1_SCL_OUT) + +#define I2C1_SCL_GPIO28 \ + ESP32_PINMUX(28, ESP_I2CEXT1_SCL_IN, ESP_I2CEXT1_SCL_OUT) + +#define I2C1_SCL_GPIO29 \ + ESP32_PINMUX(29, ESP_I2CEXT1_SCL_IN, ESP_I2CEXT1_SCL_OUT) + +#define I2C1_SCL_GPIO30 \ + ESP32_PINMUX(30, ESP_I2CEXT1_SCL_IN, ESP_I2CEXT1_SCL_OUT) + +#define I2C1_SCL_GPIO31 \ + ESP32_PINMUX(31, ESP_I2CEXT1_SCL_IN, ESP_I2CEXT1_SCL_OUT) + +#define I2C1_SCL_GPIO32 \ + ESP32_PINMUX(32, ESP_I2CEXT1_SCL_IN, ESP_I2CEXT1_SCL_OUT) + +#define I2C1_SCL_GPIO33 \ + ESP32_PINMUX(33, ESP_I2CEXT1_SCL_IN, ESP_I2CEXT1_SCL_OUT) + +#define I2C1_SCL_GPIO34 \ + ESP32_PINMUX(34, ESP_I2CEXT1_SCL_IN, ESP_I2CEXT1_SCL_OUT) + +#define I2C1_SCL_GPIO35 \ + ESP32_PINMUX(35, ESP_I2CEXT1_SCL_IN, ESP_I2CEXT1_SCL_OUT) + +#define I2C1_SCL_GPIO36 \ + ESP32_PINMUX(36, ESP_I2CEXT1_SCL_IN, ESP_I2CEXT1_SCL_OUT) + +#define I2C1_SCL_GPIO37 \ + ESP32_PINMUX(37, ESP_I2CEXT1_SCL_IN, ESP_I2CEXT1_SCL_OUT) + +#define I2C1_SCL_GPIO38 \ + ESP32_PINMUX(38, ESP_I2CEXT1_SCL_IN, ESP_I2CEXT1_SCL_OUT) + +#define I2C1_SCL_GPIO39 \ + ESP32_PINMUX(39, ESP_I2CEXT1_SCL_IN, ESP_I2CEXT1_SCL_OUT) + +#define I2C1_SCL_GPIO40 \ + ESP32_PINMUX(40, ESP_I2CEXT1_SCL_IN, ESP_I2CEXT1_SCL_OUT) + +#define I2C1_SCL_GPIO41 \ + ESP32_PINMUX(41, ESP_I2CEXT1_SCL_IN, ESP_I2CEXT1_SCL_OUT) + +#define I2C1_SCL_GPIO42 \ + ESP32_PINMUX(42, ESP_I2CEXT1_SCL_IN, ESP_I2CEXT1_SCL_OUT) + +#define I2C1_SCL_GPIO43 \ + ESP32_PINMUX(43, ESP_I2CEXT1_SCL_IN, ESP_I2CEXT1_SCL_OUT) + +#define I2C1_SCL_GPIO44 \ + ESP32_PINMUX(44, ESP_I2CEXT1_SCL_IN, ESP_I2CEXT1_SCL_OUT) + +#define I2C1_SCL_GPIO45 \ + ESP32_PINMUX(45, ESP_I2CEXT1_SCL_IN, ESP_I2CEXT1_SCL_OUT) + +#define I2C1_SCL_GPIO46 \ + ESP32_PINMUX(46, ESP_I2CEXT1_SCL_IN, ESP_I2CEXT1_SCL_OUT) + +#define I2C1_SCL_GPIO47 \ + ESP32_PINMUX(47, ESP_I2CEXT1_SCL_IN, ESP_I2CEXT1_SCL_OUT) + +#define I2C1_SCL_GPIO48 \ + ESP32_PINMUX(48, ESP_I2CEXT1_SCL_IN, ESP_I2CEXT1_SCL_OUT) + +/* I2C1_SDA */ +#define I2C1_SDA_GPIO0 \ + ESP32_PINMUX(0, ESP_I2CEXT1_SDA_IN, ESP_I2CEXT1_SDA_OUT) + +#define I2C1_SDA_GPIO1 \ + ESP32_PINMUX(1, ESP_I2CEXT1_SDA_IN, ESP_I2CEXT1_SDA_OUT) + +#define I2C1_SDA_GPIO2 \ + ESP32_PINMUX(2, ESP_I2CEXT1_SDA_IN, ESP_I2CEXT1_SDA_OUT) + +#define I2C1_SDA_GPIO3 \ + ESP32_PINMUX(3, ESP_I2CEXT1_SDA_IN, ESP_I2CEXT1_SDA_OUT) + +#define I2C1_SDA_GPIO4 \ + ESP32_PINMUX(4, ESP_I2CEXT1_SDA_IN, ESP_I2CEXT1_SDA_OUT) + +#define I2C1_SDA_GPIO5 \ + ESP32_PINMUX(5, ESP_I2CEXT1_SDA_IN, ESP_I2CEXT1_SDA_OUT) + +#define I2C1_SDA_GPIO6 \ + ESP32_PINMUX(6, ESP_I2CEXT1_SDA_IN, ESP_I2CEXT1_SDA_OUT) + +#define I2C1_SDA_GPIO7 \ + ESP32_PINMUX(7, ESP_I2CEXT1_SDA_IN, ESP_I2CEXT1_SDA_OUT) + +#define I2C1_SDA_GPIO8 \ + ESP32_PINMUX(8, ESP_I2CEXT1_SDA_IN, ESP_I2CEXT1_SDA_OUT) + +#define I2C1_SDA_GPIO9 \ + ESP32_PINMUX(9, ESP_I2CEXT1_SDA_IN, ESP_I2CEXT1_SDA_OUT) + +#define I2C1_SDA_GPIO10 \ + ESP32_PINMUX(10, ESP_I2CEXT1_SDA_IN, ESP_I2CEXT1_SDA_OUT) + +#define I2C1_SDA_GPIO11 \ + ESP32_PINMUX(11, ESP_I2CEXT1_SDA_IN, ESP_I2CEXT1_SDA_OUT) + +#define I2C1_SDA_GPIO12 \ + ESP32_PINMUX(12, ESP_I2CEXT1_SDA_IN, ESP_I2CEXT1_SDA_OUT) + +#define I2C1_SDA_GPIO13 \ + ESP32_PINMUX(13, ESP_I2CEXT1_SDA_IN, ESP_I2CEXT1_SDA_OUT) + +#define I2C1_SDA_GPIO14 \ + ESP32_PINMUX(14, ESP_I2CEXT1_SDA_IN, ESP_I2CEXT1_SDA_OUT) + +#define I2C1_SDA_GPIO15 \ + ESP32_PINMUX(15, ESP_I2CEXT1_SDA_IN, ESP_I2CEXT1_SDA_OUT) + +#define I2C1_SDA_GPIO16 \ + ESP32_PINMUX(16, ESP_I2CEXT1_SDA_IN, ESP_I2CEXT1_SDA_OUT) + +#define I2C1_SDA_GPIO17 \ + ESP32_PINMUX(17, ESP_I2CEXT1_SDA_IN, ESP_I2CEXT1_SDA_OUT) + +#define I2C1_SDA_GPIO18 \ + ESP32_PINMUX(18, ESP_I2CEXT1_SDA_IN, ESP_I2CEXT1_SDA_OUT) + +#define I2C1_SDA_GPIO19 \ + ESP32_PINMUX(19, ESP_I2CEXT1_SDA_IN, ESP_I2CEXT1_SDA_OUT) + +#define I2C1_SDA_GPIO20 \ + ESP32_PINMUX(20, ESP_I2CEXT1_SDA_IN, ESP_I2CEXT1_SDA_OUT) + +#define I2C1_SDA_GPIO21 \ + ESP32_PINMUX(21, ESP_I2CEXT1_SDA_IN, ESP_I2CEXT1_SDA_OUT) + +#define I2C1_SDA_GPIO26 \ + ESP32_PINMUX(26, ESP_I2CEXT1_SDA_IN, ESP_I2CEXT1_SDA_OUT) + +#define I2C1_SDA_GPIO27 \ + ESP32_PINMUX(27, ESP_I2CEXT1_SDA_IN, ESP_I2CEXT1_SDA_OUT) + +#define I2C1_SDA_GPIO28 \ + ESP32_PINMUX(28, ESP_I2CEXT1_SDA_IN, ESP_I2CEXT1_SDA_OUT) + +#define I2C1_SDA_GPIO29 \ + ESP32_PINMUX(29, ESP_I2CEXT1_SDA_IN, ESP_I2CEXT1_SDA_OUT) + +#define I2C1_SDA_GPIO30 \ + ESP32_PINMUX(30, ESP_I2CEXT1_SDA_IN, ESP_I2CEXT1_SDA_OUT) + +#define I2C1_SDA_GPIO31 \ + ESP32_PINMUX(31, ESP_I2CEXT1_SDA_IN, ESP_I2CEXT1_SDA_OUT) + +#define I2C1_SDA_GPIO32 \ + ESP32_PINMUX(32, ESP_I2CEXT1_SDA_IN, ESP_I2CEXT1_SDA_OUT) + +#define I2C1_SDA_GPIO33 \ + ESP32_PINMUX(33, ESP_I2CEXT1_SDA_IN, ESP_I2CEXT1_SDA_OUT) + +#define I2C1_SDA_GPIO34 \ + ESP32_PINMUX(34, ESP_I2CEXT1_SDA_IN, ESP_I2CEXT1_SDA_OUT) + +#define I2C1_SDA_GPIO35 \ + ESP32_PINMUX(35, ESP_I2CEXT1_SDA_IN, ESP_I2CEXT1_SDA_OUT) + +#define I2C1_SDA_GPIO36 \ + ESP32_PINMUX(36, ESP_I2CEXT1_SDA_IN, ESP_I2CEXT1_SDA_OUT) + +#define I2C1_SDA_GPIO37 \ + ESP32_PINMUX(37, ESP_I2CEXT1_SDA_IN, ESP_I2CEXT1_SDA_OUT) + +#define I2C1_SDA_GPIO38 \ + ESP32_PINMUX(38, ESP_I2CEXT1_SDA_IN, ESP_I2CEXT1_SDA_OUT) + +#define I2C1_SDA_GPIO39 \ + ESP32_PINMUX(39, ESP_I2CEXT1_SDA_IN, ESP_I2CEXT1_SDA_OUT) + +#define I2C1_SDA_GPIO40 \ + ESP32_PINMUX(40, ESP_I2CEXT1_SDA_IN, ESP_I2CEXT1_SDA_OUT) + +#define I2C1_SDA_GPIO41 \ + ESP32_PINMUX(41, ESP_I2CEXT1_SDA_IN, ESP_I2CEXT1_SDA_OUT) + +#define I2C1_SDA_GPIO42 \ + ESP32_PINMUX(42, ESP_I2CEXT1_SDA_IN, ESP_I2CEXT1_SDA_OUT) + +#define I2C1_SDA_GPIO43 \ + ESP32_PINMUX(43, ESP_I2CEXT1_SDA_IN, ESP_I2CEXT1_SDA_OUT) + +#define I2C1_SDA_GPIO44 \ + ESP32_PINMUX(44, ESP_I2CEXT1_SDA_IN, ESP_I2CEXT1_SDA_OUT) + +#define I2C1_SDA_GPIO45 \ + ESP32_PINMUX(45, ESP_I2CEXT1_SDA_IN, ESP_I2CEXT1_SDA_OUT) + +#define I2C1_SDA_GPIO46 \ + ESP32_PINMUX(46, ESP_I2CEXT1_SDA_IN, ESP_I2CEXT1_SDA_OUT) + +#define I2C1_SDA_GPIO47 \ + ESP32_PINMUX(47, ESP_I2CEXT1_SDA_IN, ESP_I2CEXT1_SDA_OUT) + +#define I2C1_SDA_GPIO48 \ + ESP32_PINMUX(48, ESP_I2CEXT1_SDA_IN, ESP_I2CEXT1_SDA_OUT) + +/* LEDC_CH0 */ +#define LEDC_CH0_GPIO0 \ + ESP32_PINMUX(0, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT0) + +#define LEDC_CH0_GPIO1 \ + ESP32_PINMUX(1, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT0) + +#define LEDC_CH0_GPIO2 \ + ESP32_PINMUX(2, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT0) + +#define LEDC_CH0_GPIO3 \ + ESP32_PINMUX(3, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT0) + +#define LEDC_CH0_GPIO4 \ + ESP32_PINMUX(4, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT0) + +#define LEDC_CH0_GPIO5 \ + ESP32_PINMUX(5, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT0) + +#define LEDC_CH0_GPIO6 \ + ESP32_PINMUX(6, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT0) + +#define LEDC_CH0_GPIO7 \ + ESP32_PINMUX(7, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT0) + +#define LEDC_CH0_GPIO8 \ + ESP32_PINMUX(8, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT0) + +#define LEDC_CH0_GPIO9 \ + ESP32_PINMUX(9, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT0) + +#define LEDC_CH0_GPIO10 \ + ESP32_PINMUX(10, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT0) + +#define LEDC_CH0_GPIO11 \ + ESP32_PINMUX(11, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT0) + +#define LEDC_CH0_GPIO12 \ + ESP32_PINMUX(12, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT0) + +#define LEDC_CH0_GPIO13 \ + ESP32_PINMUX(13, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT0) + +#define LEDC_CH0_GPIO14 \ + ESP32_PINMUX(14, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT0) + +#define LEDC_CH0_GPIO15 \ + ESP32_PINMUX(15, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT0) + +#define LEDC_CH0_GPIO16 \ + ESP32_PINMUX(16, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT0) + +#define LEDC_CH0_GPIO17 \ + ESP32_PINMUX(17, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT0) + +#define LEDC_CH0_GPIO18 \ + ESP32_PINMUX(18, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT0) + +#define LEDC_CH0_GPIO19 \ + ESP32_PINMUX(19, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT0) + +#define LEDC_CH0_GPIO20 \ + ESP32_PINMUX(20, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT0) + +#define LEDC_CH0_GPIO21 \ + ESP32_PINMUX(21, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT0) + +#define LEDC_CH0_GPIO26 \ + ESP32_PINMUX(26, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT0) + +#define LEDC_CH0_GPIO27 \ + ESP32_PINMUX(27, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT0) + +#define LEDC_CH0_GPIO28 \ + ESP32_PINMUX(28, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT0) + +#define LEDC_CH0_GPIO29 \ + ESP32_PINMUX(29, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT0) + +#define LEDC_CH0_GPIO30 \ + ESP32_PINMUX(30, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT0) + +#define LEDC_CH0_GPIO31 \ + ESP32_PINMUX(31, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT0) + +#define LEDC_CH0_GPIO32 \ + ESP32_PINMUX(32, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT0) + +#define LEDC_CH0_GPIO33 \ + ESP32_PINMUX(33, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT0) + +#define LEDC_CH0_GPIO34 \ + ESP32_PINMUX(34, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT0) + +#define LEDC_CH0_GPIO35 \ + ESP32_PINMUX(35, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT0) + +#define LEDC_CH0_GPIO36 \ + ESP32_PINMUX(36, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT0) + +#define LEDC_CH0_GPIO37 \ + ESP32_PINMUX(37, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT0) + +#define LEDC_CH0_GPIO38 \ + ESP32_PINMUX(38, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT0) + +#define LEDC_CH0_GPIO39 \ + ESP32_PINMUX(39, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT0) + +#define LEDC_CH0_GPIO40 \ + ESP32_PINMUX(40, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT0) + +#define LEDC_CH0_GPIO41 \ + ESP32_PINMUX(41, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT0) + +#define LEDC_CH0_GPIO42 \ + ESP32_PINMUX(42, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT0) + +#define LEDC_CH0_GPIO43 \ + ESP32_PINMUX(43, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT0) + +#define LEDC_CH0_GPIO44 \ + ESP32_PINMUX(44, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT0) + +#define LEDC_CH0_GPIO45 \ + ESP32_PINMUX(45, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT0) + +#define LEDC_CH0_GPIO46 \ + ESP32_PINMUX(46, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT0) + +#define LEDC_CH0_GPIO47 \ + ESP32_PINMUX(47, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT0) + +#define LEDC_CH0_GPIO48 \ + ESP32_PINMUX(48, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT0) + +/* LEDC_CH1 */ +#define LEDC_CH1_GPIO0 \ + ESP32_PINMUX(0, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT1) + +#define LEDC_CH1_GPIO1 \ + ESP32_PINMUX(1, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT1) + +#define LEDC_CH1_GPIO2 \ + ESP32_PINMUX(2, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT1) + +#define LEDC_CH1_GPIO3 \ + ESP32_PINMUX(3, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT1) + +#define LEDC_CH1_GPIO4 \ + ESP32_PINMUX(4, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT1) + +#define LEDC_CH1_GPIO5 \ + ESP32_PINMUX(5, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT1) + +#define LEDC_CH1_GPIO6 \ + ESP32_PINMUX(6, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT1) + +#define LEDC_CH1_GPIO7 \ + ESP32_PINMUX(7, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT1) + +#define LEDC_CH1_GPIO8 \ + ESP32_PINMUX(8, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT1) + +#define LEDC_CH1_GPIO9 \ + ESP32_PINMUX(9, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT1) + +#define LEDC_CH1_GPIO10 \ + ESP32_PINMUX(10, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT1) + +#define LEDC_CH1_GPIO11 \ + ESP32_PINMUX(11, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT1) + +#define LEDC_CH1_GPIO12 \ + ESP32_PINMUX(12, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT1) + +#define LEDC_CH1_GPIO13 \ + ESP32_PINMUX(13, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT1) + +#define LEDC_CH1_GPIO14 \ + ESP32_PINMUX(14, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT1) + +#define LEDC_CH1_GPIO15 \ + ESP32_PINMUX(15, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT1) + +#define LEDC_CH1_GPIO16 \ + ESP32_PINMUX(16, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT1) + +#define LEDC_CH1_GPIO17 \ + ESP32_PINMUX(17, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT1) + +#define LEDC_CH1_GPIO18 \ + ESP32_PINMUX(18, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT1) + +#define LEDC_CH1_GPIO19 \ + ESP32_PINMUX(19, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT1) + +#define LEDC_CH1_GPIO20 \ + ESP32_PINMUX(20, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT1) + +#define LEDC_CH1_GPIO21 \ + ESP32_PINMUX(21, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT1) + +#define LEDC_CH1_GPIO26 \ + ESP32_PINMUX(26, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT1) + +#define LEDC_CH1_GPIO27 \ + ESP32_PINMUX(27, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT1) + +#define LEDC_CH1_GPIO28 \ + ESP32_PINMUX(28, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT1) + +#define LEDC_CH1_GPIO29 \ + ESP32_PINMUX(29, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT1) + +#define LEDC_CH1_GPIO30 \ + ESP32_PINMUX(30, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT1) + +#define LEDC_CH1_GPIO31 \ + ESP32_PINMUX(31, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT1) + +#define LEDC_CH1_GPIO32 \ + ESP32_PINMUX(32, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT1) + +#define LEDC_CH1_GPIO33 \ + ESP32_PINMUX(33, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT1) + +#define LEDC_CH1_GPIO34 \ + ESP32_PINMUX(34, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT1) + +#define LEDC_CH1_GPIO35 \ + ESP32_PINMUX(35, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT1) + +#define LEDC_CH1_GPIO36 \ + ESP32_PINMUX(36, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT1) + +#define LEDC_CH1_GPIO37 \ + ESP32_PINMUX(37, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT1) + +#define LEDC_CH1_GPIO38 \ + ESP32_PINMUX(38, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT1) + +#define LEDC_CH1_GPIO39 \ + ESP32_PINMUX(39, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT1) + +#define LEDC_CH1_GPIO40 \ + ESP32_PINMUX(40, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT1) + +#define LEDC_CH1_GPIO41 \ + ESP32_PINMUX(41, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT1) + +#define LEDC_CH1_GPIO42 \ + ESP32_PINMUX(42, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT1) + +#define LEDC_CH1_GPIO43 \ + ESP32_PINMUX(43, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT1) + +#define LEDC_CH1_GPIO44 \ + ESP32_PINMUX(44, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT1) + +#define LEDC_CH1_GPIO45 \ + ESP32_PINMUX(45, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT1) + +#define LEDC_CH1_GPIO46 \ + ESP32_PINMUX(46, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT1) + +#define LEDC_CH1_GPIO47 \ + ESP32_PINMUX(47, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT1) + +#define LEDC_CH1_GPIO48 \ + ESP32_PINMUX(48, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT1) + +/* LEDC_CH2 */ +#define LEDC_CH2_GPIO0 \ + ESP32_PINMUX(0, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT2) + +#define LEDC_CH2_GPIO1 \ + ESP32_PINMUX(1, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT2) + +#define LEDC_CH2_GPIO2 \ + ESP32_PINMUX(2, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT2) + +#define LEDC_CH2_GPIO3 \ + ESP32_PINMUX(3, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT2) + +#define LEDC_CH2_GPIO4 \ + ESP32_PINMUX(4, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT2) + +#define LEDC_CH2_GPIO5 \ + ESP32_PINMUX(5, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT2) + +#define LEDC_CH2_GPIO6 \ + ESP32_PINMUX(6, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT2) + +#define LEDC_CH2_GPIO7 \ + ESP32_PINMUX(7, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT2) + +#define LEDC_CH2_GPIO8 \ + ESP32_PINMUX(8, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT2) + +#define LEDC_CH2_GPIO9 \ + ESP32_PINMUX(9, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT2) + +#define LEDC_CH2_GPIO10 \ + ESP32_PINMUX(10, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT2) + +#define LEDC_CH2_GPIO11 \ + ESP32_PINMUX(11, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT2) + +#define LEDC_CH2_GPIO12 \ + ESP32_PINMUX(12, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT2) + +#define LEDC_CH2_GPIO13 \ + ESP32_PINMUX(13, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT2) + +#define LEDC_CH2_GPIO14 \ + ESP32_PINMUX(14, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT2) + +#define LEDC_CH2_GPIO15 \ + ESP32_PINMUX(15, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT2) + +#define LEDC_CH2_GPIO16 \ + ESP32_PINMUX(16, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT2) + +#define LEDC_CH2_GPIO17 \ + ESP32_PINMUX(17, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT2) + +#define LEDC_CH2_GPIO18 \ + ESP32_PINMUX(18, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT2) + +#define LEDC_CH2_GPIO19 \ + ESP32_PINMUX(19, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT2) + +#define LEDC_CH2_GPIO20 \ + ESP32_PINMUX(20, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT2) + +#define LEDC_CH2_GPIO21 \ + ESP32_PINMUX(21, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT2) + +#define LEDC_CH2_GPIO26 \ + ESP32_PINMUX(26, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT2) + +#define LEDC_CH2_GPIO27 \ + ESP32_PINMUX(27, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT2) + +#define LEDC_CH2_GPIO28 \ + ESP32_PINMUX(28, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT2) + +#define LEDC_CH2_GPIO29 \ + ESP32_PINMUX(29, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT2) + +#define LEDC_CH2_GPIO30 \ + ESP32_PINMUX(30, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT2) + +#define LEDC_CH2_GPIO31 \ + ESP32_PINMUX(31, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT2) + +#define LEDC_CH2_GPIO32 \ + ESP32_PINMUX(32, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT2) + +#define LEDC_CH2_GPIO33 \ + ESP32_PINMUX(33, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT2) + +#define LEDC_CH2_GPIO34 \ + ESP32_PINMUX(34, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT2) + +#define LEDC_CH2_GPIO35 \ + ESP32_PINMUX(35, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT2) + +#define LEDC_CH2_GPIO36 \ + ESP32_PINMUX(36, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT2) + +#define LEDC_CH2_GPIO37 \ + ESP32_PINMUX(37, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT2) + +#define LEDC_CH2_GPIO38 \ + ESP32_PINMUX(38, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT2) + +#define LEDC_CH2_GPIO39 \ + ESP32_PINMUX(39, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT2) + +#define LEDC_CH2_GPIO40 \ + ESP32_PINMUX(40, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT2) + +#define LEDC_CH2_GPIO41 \ + ESP32_PINMUX(41, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT2) + +#define LEDC_CH2_GPIO42 \ + ESP32_PINMUX(42, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT2) + +#define LEDC_CH2_GPIO43 \ + ESP32_PINMUX(43, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT2) + +#define LEDC_CH2_GPIO44 \ + ESP32_PINMUX(44, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT2) + +#define LEDC_CH2_GPIO45 \ + ESP32_PINMUX(45, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT2) + +#define LEDC_CH2_GPIO46 \ + ESP32_PINMUX(46, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT2) + +#define LEDC_CH2_GPIO47 \ + ESP32_PINMUX(47, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT2) + +#define LEDC_CH2_GPIO48 \ + ESP32_PINMUX(48, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT2) + +/* LEDC_CH3 */ +#define LEDC_CH3_GPIO0 \ + ESP32_PINMUX(0, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT3) + +#define LEDC_CH3_GPIO1 \ + ESP32_PINMUX(1, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT3) + +#define LEDC_CH3_GPIO2 \ + ESP32_PINMUX(2, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT3) + +#define LEDC_CH3_GPIO3 \ + ESP32_PINMUX(3, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT3) + +#define LEDC_CH3_GPIO4 \ + ESP32_PINMUX(4, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT3) + +#define LEDC_CH3_GPIO5 \ + ESP32_PINMUX(5, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT3) + +#define LEDC_CH3_GPIO6 \ + ESP32_PINMUX(6, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT3) + +#define LEDC_CH3_GPIO7 \ + ESP32_PINMUX(7, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT3) + +#define LEDC_CH3_GPIO8 \ + ESP32_PINMUX(8, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT3) + +#define LEDC_CH3_GPIO9 \ + ESP32_PINMUX(9, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT3) + +#define LEDC_CH3_GPIO10 \ + ESP32_PINMUX(10, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT3) + +#define LEDC_CH3_GPIO11 \ + ESP32_PINMUX(11, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT3) + +#define LEDC_CH3_GPIO12 \ + ESP32_PINMUX(12, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT3) + +#define LEDC_CH3_GPIO13 \ + ESP32_PINMUX(13, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT3) + +#define LEDC_CH3_GPIO14 \ + ESP32_PINMUX(14, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT3) + +#define LEDC_CH3_GPIO15 \ + ESP32_PINMUX(15, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT3) + +#define LEDC_CH3_GPIO16 \ + ESP32_PINMUX(16, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT3) + +#define LEDC_CH3_GPIO17 \ + ESP32_PINMUX(17, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT3) + +#define LEDC_CH3_GPIO18 \ + ESP32_PINMUX(18, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT3) + +#define LEDC_CH3_GPIO19 \ + ESP32_PINMUX(19, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT3) + +#define LEDC_CH3_GPIO20 \ + ESP32_PINMUX(20, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT3) + +#define LEDC_CH3_GPIO21 \ + ESP32_PINMUX(21, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT3) + +#define LEDC_CH3_GPIO26 \ + ESP32_PINMUX(26, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT3) + +#define LEDC_CH3_GPIO27 \ + ESP32_PINMUX(27, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT3) + +#define LEDC_CH3_GPIO28 \ + ESP32_PINMUX(28, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT3) + +#define LEDC_CH3_GPIO29 \ + ESP32_PINMUX(29, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT3) + +#define LEDC_CH3_GPIO30 \ + ESP32_PINMUX(30, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT3) + +#define LEDC_CH3_GPIO31 \ + ESP32_PINMUX(31, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT3) + +#define LEDC_CH3_GPIO32 \ + ESP32_PINMUX(32, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT3) + +#define LEDC_CH3_GPIO33 \ + ESP32_PINMUX(33, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT3) + +#define LEDC_CH3_GPIO34 \ + ESP32_PINMUX(34, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT3) + +#define LEDC_CH3_GPIO35 \ + ESP32_PINMUX(35, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT3) + +#define LEDC_CH3_GPIO36 \ + ESP32_PINMUX(36, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT3) + +#define LEDC_CH3_GPIO37 \ + ESP32_PINMUX(37, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT3) + +#define LEDC_CH3_GPIO38 \ + ESP32_PINMUX(38, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT3) + +#define LEDC_CH3_GPIO39 \ + ESP32_PINMUX(39, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT3) + +#define LEDC_CH3_GPIO40 \ + ESP32_PINMUX(40, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT3) + +#define LEDC_CH3_GPIO41 \ + ESP32_PINMUX(41, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT3) + +#define LEDC_CH3_GPIO42 \ + ESP32_PINMUX(42, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT3) + +#define LEDC_CH3_GPIO43 \ + ESP32_PINMUX(43, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT3) + +#define LEDC_CH3_GPIO44 \ + ESP32_PINMUX(44, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT3) + +#define LEDC_CH3_GPIO45 \ + ESP32_PINMUX(45, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT3) + +#define LEDC_CH3_GPIO46 \ + ESP32_PINMUX(46, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT3) + +#define LEDC_CH3_GPIO47 \ + ESP32_PINMUX(47, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT3) + +#define LEDC_CH3_GPIO48 \ + ESP32_PINMUX(48, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT3) + +/* LEDC_CH4 */ +#define LEDC_CH4_GPIO0 \ + ESP32_PINMUX(0, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT4) + +#define LEDC_CH4_GPIO1 \ + ESP32_PINMUX(1, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT4) + +#define LEDC_CH4_GPIO2 \ + ESP32_PINMUX(2, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT4) + +#define LEDC_CH4_GPIO3 \ + ESP32_PINMUX(3, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT4) + +#define LEDC_CH4_GPIO4 \ + ESP32_PINMUX(4, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT4) + +#define LEDC_CH4_GPIO5 \ + ESP32_PINMUX(5, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT4) + +#define LEDC_CH4_GPIO6 \ + ESP32_PINMUX(6, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT4) + +#define LEDC_CH4_GPIO7 \ + ESP32_PINMUX(7, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT4) + +#define LEDC_CH4_GPIO8 \ + ESP32_PINMUX(8, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT4) + +#define LEDC_CH4_GPIO9 \ + ESP32_PINMUX(9, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT4) + +#define LEDC_CH4_GPIO10 \ + ESP32_PINMUX(10, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT4) + +#define LEDC_CH4_GPIO11 \ + ESP32_PINMUX(11, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT4) + +#define LEDC_CH4_GPIO12 \ + ESP32_PINMUX(12, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT4) + +#define LEDC_CH4_GPIO13 \ + ESP32_PINMUX(13, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT4) + +#define LEDC_CH4_GPIO14 \ + ESP32_PINMUX(14, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT4) + +#define LEDC_CH4_GPIO15 \ + ESP32_PINMUX(15, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT4) + +#define LEDC_CH4_GPIO16 \ + ESP32_PINMUX(16, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT4) + +#define LEDC_CH4_GPIO17 \ + ESP32_PINMUX(17, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT4) + +#define LEDC_CH4_GPIO18 \ + ESP32_PINMUX(18, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT4) + +#define LEDC_CH4_GPIO19 \ + ESP32_PINMUX(19, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT4) + +#define LEDC_CH4_GPIO20 \ + ESP32_PINMUX(20, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT4) + +#define LEDC_CH4_GPIO21 \ + ESP32_PINMUX(21, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT4) + +#define LEDC_CH4_GPIO26 \ + ESP32_PINMUX(26, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT4) + +#define LEDC_CH4_GPIO27 \ + ESP32_PINMUX(27, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT4) + +#define LEDC_CH4_GPIO28 \ + ESP32_PINMUX(28, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT4) + +#define LEDC_CH4_GPIO29 \ + ESP32_PINMUX(29, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT4) + +#define LEDC_CH4_GPIO30 \ + ESP32_PINMUX(30, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT4) + +#define LEDC_CH4_GPIO31 \ + ESP32_PINMUX(31, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT4) + +#define LEDC_CH4_GPIO32 \ + ESP32_PINMUX(32, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT4) + +#define LEDC_CH4_GPIO33 \ + ESP32_PINMUX(33, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT4) + +#define LEDC_CH4_GPIO34 \ + ESP32_PINMUX(34, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT4) + +#define LEDC_CH4_GPIO35 \ + ESP32_PINMUX(35, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT4) + +#define LEDC_CH4_GPIO36 \ + ESP32_PINMUX(36, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT4) + +#define LEDC_CH4_GPIO37 \ + ESP32_PINMUX(37, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT4) + +#define LEDC_CH4_GPIO38 \ + ESP32_PINMUX(38, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT4) + +#define LEDC_CH4_GPIO39 \ + ESP32_PINMUX(39, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT4) + +#define LEDC_CH4_GPIO40 \ + ESP32_PINMUX(40, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT4) + +#define LEDC_CH4_GPIO41 \ + ESP32_PINMUX(41, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT4) + +#define LEDC_CH4_GPIO42 \ + ESP32_PINMUX(42, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT4) + +#define LEDC_CH4_GPIO43 \ + ESP32_PINMUX(43, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT4) + +#define LEDC_CH4_GPIO44 \ + ESP32_PINMUX(44, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT4) + +#define LEDC_CH4_GPIO45 \ + ESP32_PINMUX(45, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT4) + +#define LEDC_CH4_GPIO46 \ + ESP32_PINMUX(46, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT4) + +#define LEDC_CH4_GPIO47 \ + ESP32_PINMUX(47, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT4) + +#define LEDC_CH4_GPIO48 \ + ESP32_PINMUX(48, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT4) + +/* LEDC_CH5 */ +#define LEDC_CH5_GPIO0 \ + ESP32_PINMUX(0, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT5) + +#define LEDC_CH5_GPIO1 \ + ESP32_PINMUX(1, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT5) + +#define LEDC_CH5_GPIO2 \ + ESP32_PINMUX(2, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT5) + +#define LEDC_CH5_GPIO3 \ + ESP32_PINMUX(3, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT5) + +#define LEDC_CH5_GPIO4 \ + ESP32_PINMUX(4, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT5) + +#define LEDC_CH5_GPIO5 \ + ESP32_PINMUX(5, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT5) + +#define LEDC_CH5_GPIO6 \ + ESP32_PINMUX(6, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT5) + +#define LEDC_CH5_GPIO7 \ + ESP32_PINMUX(7, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT5) + +#define LEDC_CH5_GPIO8 \ + ESP32_PINMUX(8, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT5) + +#define LEDC_CH5_GPIO9 \ + ESP32_PINMUX(9, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT5) + +#define LEDC_CH5_GPIO10 \ + ESP32_PINMUX(10, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT5) + +#define LEDC_CH5_GPIO11 \ + ESP32_PINMUX(11, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT5) + +#define LEDC_CH5_GPIO12 \ + ESP32_PINMUX(12, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT5) + +#define LEDC_CH5_GPIO13 \ + ESP32_PINMUX(13, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT5) + +#define LEDC_CH5_GPIO14 \ + ESP32_PINMUX(14, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT5) + +#define LEDC_CH5_GPIO15 \ + ESP32_PINMUX(15, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT5) + +#define LEDC_CH5_GPIO16 \ + ESP32_PINMUX(16, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT5) + +#define LEDC_CH5_GPIO17 \ + ESP32_PINMUX(17, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT5) + +#define LEDC_CH5_GPIO18 \ + ESP32_PINMUX(18, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT5) + +#define LEDC_CH5_GPIO19 \ + ESP32_PINMUX(19, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT5) + +#define LEDC_CH5_GPIO20 \ + ESP32_PINMUX(20, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT5) + +#define LEDC_CH5_GPIO21 \ + ESP32_PINMUX(21, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT5) + +#define LEDC_CH5_GPIO26 \ + ESP32_PINMUX(26, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT5) + +#define LEDC_CH5_GPIO27 \ + ESP32_PINMUX(27, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT5) + +#define LEDC_CH5_GPIO28 \ + ESP32_PINMUX(28, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT5) + +#define LEDC_CH5_GPIO29 \ + ESP32_PINMUX(29, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT5) + +#define LEDC_CH5_GPIO30 \ + ESP32_PINMUX(30, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT5) + +#define LEDC_CH5_GPIO31 \ + ESP32_PINMUX(31, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT5) + +#define LEDC_CH5_GPIO32 \ + ESP32_PINMUX(32, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT5) + +#define LEDC_CH5_GPIO33 \ + ESP32_PINMUX(33, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT5) + +#define LEDC_CH5_GPIO34 \ + ESP32_PINMUX(34, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT5) + +#define LEDC_CH5_GPIO35 \ + ESP32_PINMUX(35, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT5) + +#define LEDC_CH5_GPIO36 \ + ESP32_PINMUX(36, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT5) + +#define LEDC_CH5_GPIO37 \ + ESP32_PINMUX(37, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT5) + +#define LEDC_CH5_GPIO38 \ + ESP32_PINMUX(38, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT5) + +#define LEDC_CH5_GPIO39 \ + ESP32_PINMUX(39, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT5) + +#define LEDC_CH5_GPIO40 \ + ESP32_PINMUX(40, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT5) + +#define LEDC_CH5_GPIO41 \ + ESP32_PINMUX(41, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT5) + +#define LEDC_CH5_GPIO42 \ + ESP32_PINMUX(42, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT5) + +#define LEDC_CH5_GPIO43 \ + ESP32_PINMUX(43, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT5) + +#define LEDC_CH5_GPIO44 \ + ESP32_PINMUX(44, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT5) + +#define LEDC_CH5_GPIO45 \ + ESP32_PINMUX(45, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT5) + +#define LEDC_CH5_GPIO46 \ + ESP32_PINMUX(46, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT5) + +#define LEDC_CH5_GPIO47 \ + ESP32_PINMUX(47, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT5) + +#define LEDC_CH5_GPIO48 \ + ESP32_PINMUX(48, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT5) + +/* LEDC_CH6 */ +#define LEDC_CH6_GPIO0 \ + ESP32_PINMUX(0, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT6) + +#define LEDC_CH6_GPIO1 \ + ESP32_PINMUX(1, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT6) + +#define LEDC_CH6_GPIO2 \ + ESP32_PINMUX(2, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT6) + +#define LEDC_CH6_GPIO3 \ + ESP32_PINMUX(3, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT6) + +#define LEDC_CH6_GPIO4 \ + ESP32_PINMUX(4, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT6) + +#define LEDC_CH6_GPIO5 \ + ESP32_PINMUX(5, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT6) + +#define LEDC_CH6_GPIO6 \ + ESP32_PINMUX(6, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT6) + +#define LEDC_CH6_GPIO7 \ + ESP32_PINMUX(7, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT6) + +#define LEDC_CH6_GPIO8 \ + ESP32_PINMUX(8, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT6) + +#define LEDC_CH6_GPIO9 \ + ESP32_PINMUX(9, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT6) + +#define LEDC_CH6_GPIO10 \ + ESP32_PINMUX(10, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT6) + +#define LEDC_CH6_GPIO11 \ + ESP32_PINMUX(11, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT6) + +#define LEDC_CH6_GPIO12 \ + ESP32_PINMUX(12, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT6) + +#define LEDC_CH6_GPIO13 \ + ESP32_PINMUX(13, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT6) + +#define LEDC_CH6_GPIO14 \ + ESP32_PINMUX(14, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT6) + +#define LEDC_CH6_GPIO15 \ + ESP32_PINMUX(15, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT6) + +#define LEDC_CH6_GPIO16 \ + ESP32_PINMUX(16, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT6) + +#define LEDC_CH6_GPIO17 \ + ESP32_PINMUX(17, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT6) + +#define LEDC_CH6_GPIO18 \ + ESP32_PINMUX(18, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT6) + +#define LEDC_CH6_GPIO19 \ + ESP32_PINMUX(19, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT6) + +#define LEDC_CH6_GPIO20 \ + ESP32_PINMUX(20, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT6) + +#define LEDC_CH6_GPIO21 \ + ESP32_PINMUX(21, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT6) + +#define LEDC_CH6_GPIO26 \ + ESP32_PINMUX(26, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT6) + +#define LEDC_CH6_GPIO27 \ + ESP32_PINMUX(27, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT6) + +#define LEDC_CH6_GPIO28 \ + ESP32_PINMUX(28, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT6) + +#define LEDC_CH6_GPIO29 \ + ESP32_PINMUX(29, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT6) + +#define LEDC_CH6_GPIO30 \ + ESP32_PINMUX(30, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT6) + +#define LEDC_CH6_GPIO31 \ + ESP32_PINMUX(31, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT6) + +#define LEDC_CH6_GPIO32 \ + ESP32_PINMUX(32, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT6) + +#define LEDC_CH6_GPIO33 \ + ESP32_PINMUX(33, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT6) + +#define LEDC_CH6_GPIO34 \ + ESP32_PINMUX(34, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT6) + +#define LEDC_CH6_GPIO35 \ + ESP32_PINMUX(35, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT6) + +#define LEDC_CH6_GPIO36 \ + ESP32_PINMUX(36, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT6) + +#define LEDC_CH6_GPIO37 \ + ESP32_PINMUX(37, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT6) + +#define LEDC_CH6_GPIO38 \ + ESP32_PINMUX(38, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT6) + +#define LEDC_CH6_GPIO39 \ + ESP32_PINMUX(39, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT6) + +#define LEDC_CH6_GPIO40 \ + ESP32_PINMUX(40, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT6) + +#define LEDC_CH6_GPIO41 \ + ESP32_PINMUX(41, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT6) + +#define LEDC_CH6_GPIO42 \ + ESP32_PINMUX(42, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT6) + +#define LEDC_CH6_GPIO43 \ + ESP32_PINMUX(43, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT6) + +#define LEDC_CH6_GPIO44 \ + ESP32_PINMUX(44, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT6) + +#define LEDC_CH6_GPIO45 \ + ESP32_PINMUX(45, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT6) + +#define LEDC_CH6_GPIO46 \ + ESP32_PINMUX(46, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT6) + +#define LEDC_CH6_GPIO47 \ + ESP32_PINMUX(47, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT6) + +#define LEDC_CH6_GPIO48 \ + ESP32_PINMUX(48, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT6) + +/* LEDC_CH7 */ +#define LEDC_CH7_GPIO0 \ + ESP32_PINMUX(0, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT7) + +#define LEDC_CH7_GPIO1 \ + ESP32_PINMUX(1, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT7) + +#define LEDC_CH7_GPIO2 \ + ESP32_PINMUX(2, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT7) + +#define LEDC_CH7_GPIO3 \ + ESP32_PINMUX(3, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT7) + +#define LEDC_CH7_GPIO4 \ + ESP32_PINMUX(4, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT7) + +#define LEDC_CH7_GPIO5 \ + ESP32_PINMUX(5, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT7) + +#define LEDC_CH7_GPIO6 \ + ESP32_PINMUX(6, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT7) + +#define LEDC_CH7_GPIO7 \ + ESP32_PINMUX(7, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT7) + +#define LEDC_CH7_GPIO8 \ + ESP32_PINMUX(8, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT7) + +#define LEDC_CH7_GPIO9 \ + ESP32_PINMUX(9, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT7) + +#define LEDC_CH7_GPIO10 \ + ESP32_PINMUX(10, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT7) + +#define LEDC_CH7_GPIO11 \ + ESP32_PINMUX(11, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT7) + +#define LEDC_CH7_GPIO12 \ + ESP32_PINMUX(12, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT7) + +#define LEDC_CH7_GPIO13 \ + ESP32_PINMUX(13, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT7) + +#define LEDC_CH7_GPIO14 \ + ESP32_PINMUX(14, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT7) + +#define LEDC_CH7_GPIO15 \ + ESP32_PINMUX(15, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT7) + +#define LEDC_CH7_GPIO16 \ + ESP32_PINMUX(16, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT7) + +#define LEDC_CH7_GPIO17 \ + ESP32_PINMUX(17, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT7) + +#define LEDC_CH7_GPIO18 \ + ESP32_PINMUX(18, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT7) + +#define LEDC_CH7_GPIO19 \ + ESP32_PINMUX(19, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT7) + +#define LEDC_CH7_GPIO20 \ + ESP32_PINMUX(20, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT7) + +#define LEDC_CH7_GPIO21 \ + ESP32_PINMUX(21, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT7) + +#define LEDC_CH7_GPIO26 \ + ESP32_PINMUX(26, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT7) + +#define LEDC_CH7_GPIO27 \ + ESP32_PINMUX(27, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT7) + +#define LEDC_CH7_GPIO28 \ + ESP32_PINMUX(28, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT7) + +#define LEDC_CH7_GPIO29 \ + ESP32_PINMUX(29, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT7) + +#define LEDC_CH7_GPIO30 \ + ESP32_PINMUX(30, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT7) + +#define LEDC_CH7_GPIO31 \ + ESP32_PINMUX(31, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT7) + +#define LEDC_CH7_GPIO32 \ + ESP32_PINMUX(32, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT7) + +#define LEDC_CH7_GPIO33 \ + ESP32_PINMUX(33, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT7) + +#define LEDC_CH7_GPIO34 \ + ESP32_PINMUX(34, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT7) + +#define LEDC_CH7_GPIO35 \ + ESP32_PINMUX(35, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT7) + +#define LEDC_CH7_GPIO36 \ + ESP32_PINMUX(36, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT7) + +#define LEDC_CH7_GPIO37 \ + ESP32_PINMUX(37, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT7) + +#define LEDC_CH7_GPIO38 \ + ESP32_PINMUX(38, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT7) + +#define LEDC_CH7_GPIO39 \ + ESP32_PINMUX(39, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT7) + +#define LEDC_CH7_GPIO40 \ + ESP32_PINMUX(40, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT7) + +#define LEDC_CH7_GPIO41 \ + ESP32_PINMUX(41, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT7) + +#define LEDC_CH7_GPIO42 \ + ESP32_PINMUX(42, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT7) + +#define LEDC_CH7_GPIO43 \ + ESP32_PINMUX(43, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT7) + +#define LEDC_CH7_GPIO44 \ + ESP32_PINMUX(44, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT7) + +#define LEDC_CH7_GPIO45 \ + ESP32_PINMUX(45, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT7) + +#define LEDC_CH7_GPIO46 \ + ESP32_PINMUX(46, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT7) + +#define LEDC_CH7_GPIO47 \ + ESP32_PINMUX(47, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT7) + +#define LEDC_CH7_GPIO48 \ + ESP32_PINMUX(48, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT7) + +/* MCPWM0_CAP0 */ +#define MCPWM0_CAP0_GPIO0 \ + ESP32_PINMUX(0, ESP_PWM0_CAP0_IN, ESP_NOSIG) + +#define MCPWM0_CAP0_GPIO1 \ + ESP32_PINMUX(1, ESP_PWM0_CAP0_IN, ESP_NOSIG) + +#define MCPWM0_CAP0_GPIO2 \ + ESP32_PINMUX(2, ESP_PWM0_CAP0_IN, ESP_NOSIG) + +#define MCPWM0_CAP0_GPIO3 \ + ESP32_PINMUX(3, ESP_PWM0_CAP0_IN, ESP_NOSIG) + +#define MCPWM0_CAP0_GPIO4 \ + ESP32_PINMUX(4, ESP_PWM0_CAP0_IN, ESP_NOSIG) + +#define MCPWM0_CAP0_GPIO5 \ + ESP32_PINMUX(5, ESP_PWM0_CAP0_IN, ESP_NOSIG) + +#define MCPWM0_CAP0_GPIO6 \ + ESP32_PINMUX(6, ESP_PWM0_CAP0_IN, ESP_NOSIG) + +#define MCPWM0_CAP0_GPIO7 \ + ESP32_PINMUX(7, ESP_PWM0_CAP0_IN, ESP_NOSIG) + +#define MCPWM0_CAP0_GPIO8 \ + ESP32_PINMUX(8, ESP_PWM0_CAP0_IN, ESP_NOSIG) + +#define MCPWM0_CAP0_GPIO9 \ + ESP32_PINMUX(9, ESP_PWM0_CAP0_IN, ESP_NOSIG) + +#define MCPWM0_CAP0_GPIO10 \ + ESP32_PINMUX(10, ESP_PWM0_CAP0_IN, ESP_NOSIG) + +#define MCPWM0_CAP0_GPIO11 \ + ESP32_PINMUX(11, ESP_PWM0_CAP0_IN, ESP_NOSIG) + +#define MCPWM0_CAP0_GPIO12 \ + ESP32_PINMUX(12, ESP_PWM0_CAP0_IN, ESP_NOSIG) + +#define MCPWM0_CAP0_GPIO13 \ + ESP32_PINMUX(13, ESP_PWM0_CAP0_IN, ESP_NOSIG) + +#define MCPWM0_CAP0_GPIO14 \ + ESP32_PINMUX(14, ESP_PWM0_CAP0_IN, ESP_NOSIG) + +#define MCPWM0_CAP0_GPIO15 \ + ESP32_PINMUX(15, ESP_PWM0_CAP0_IN, ESP_NOSIG) + +#define MCPWM0_CAP0_GPIO16 \ + ESP32_PINMUX(16, ESP_PWM0_CAP0_IN, ESP_NOSIG) + +#define MCPWM0_CAP0_GPIO17 \ + ESP32_PINMUX(17, ESP_PWM0_CAP0_IN, ESP_NOSIG) + +#define MCPWM0_CAP0_GPIO18 \ + ESP32_PINMUX(18, ESP_PWM0_CAP0_IN, ESP_NOSIG) + +#define MCPWM0_CAP0_GPIO19 \ + ESP32_PINMUX(19, ESP_PWM0_CAP0_IN, ESP_NOSIG) + +#define MCPWM0_CAP0_GPIO20 \ + ESP32_PINMUX(20, ESP_PWM0_CAP0_IN, ESP_NOSIG) + +#define MCPWM0_CAP0_GPIO21 \ + ESP32_PINMUX(21, ESP_PWM0_CAP0_IN, ESP_NOSIG) + +#define MCPWM0_CAP0_GPIO26 \ + ESP32_PINMUX(26, ESP_PWM0_CAP0_IN, ESP_NOSIG) + +#define MCPWM0_CAP0_GPIO27 \ + ESP32_PINMUX(27, ESP_PWM0_CAP0_IN, ESP_NOSIG) + +#define MCPWM0_CAP0_GPIO28 \ + ESP32_PINMUX(28, ESP_PWM0_CAP0_IN, ESP_NOSIG) + +#define MCPWM0_CAP0_GPIO29 \ + ESP32_PINMUX(29, ESP_PWM0_CAP0_IN, ESP_NOSIG) + +#define MCPWM0_CAP0_GPIO30 \ + ESP32_PINMUX(30, ESP_PWM0_CAP0_IN, ESP_NOSIG) + +#define MCPWM0_CAP0_GPIO31 \ + ESP32_PINMUX(31, ESP_PWM0_CAP0_IN, ESP_NOSIG) + +#define MCPWM0_CAP0_GPIO32 \ + ESP32_PINMUX(32, ESP_PWM0_CAP0_IN, ESP_NOSIG) + +#define MCPWM0_CAP0_GPIO33 \ + ESP32_PINMUX(33, ESP_PWM0_CAP0_IN, ESP_NOSIG) + +#define MCPWM0_CAP0_GPIO34 \ + ESP32_PINMUX(34, ESP_PWM0_CAP0_IN, ESP_NOSIG) + +#define MCPWM0_CAP0_GPIO35 \ + ESP32_PINMUX(35, ESP_PWM0_CAP0_IN, ESP_NOSIG) + +#define MCPWM0_CAP0_GPIO36 \ + ESP32_PINMUX(36, ESP_PWM0_CAP0_IN, ESP_NOSIG) + +#define MCPWM0_CAP0_GPIO37 \ + ESP32_PINMUX(37, ESP_PWM0_CAP0_IN, ESP_NOSIG) + +#define MCPWM0_CAP0_GPIO38 \ + ESP32_PINMUX(38, ESP_PWM0_CAP0_IN, ESP_NOSIG) + +#define MCPWM0_CAP0_GPIO39 \ + ESP32_PINMUX(39, ESP_PWM0_CAP0_IN, ESP_NOSIG) + +#define MCPWM0_CAP0_GPIO40 \ + ESP32_PINMUX(40, ESP_PWM0_CAP0_IN, ESP_NOSIG) + +#define MCPWM0_CAP0_GPIO41 \ + ESP32_PINMUX(41, ESP_PWM0_CAP0_IN, ESP_NOSIG) + +#define MCPWM0_CAP0_GPIO42 \ + ESP32_PINMUX(42, ESP_PWM0_CAP0_IN, ESP_NOSIG) + +#define MCPWM0_CAP0_GPIO43 \ + ESP32_PINMUX(43, ESP_PWM0_CAP0_IN, ESP_NOSIG) + +#define MCPWM0_CAP0_GPIO44 \ + ESP32_PINMUX(44, ESP_PWM0_CAP0_IN, ESP_NOSIG) + +#define MCPWM0_CAP0_GPIO45 \ + ESP32_PINMUX(45, ESP_PWM0_CAP0_IN, ESP_NOSIG) + +#define MCPWM0_CAP0_GPIO46 \ + ESP32_PINMUX(46, ESP_PWM0_CAP0_IN, ESP_NOSIG) + +#define MCPWM0_CAP0_GPIO47 \ + ESP32_PINMUX(47, ESP_PWM0_CAP0_IN, ESP_NOSIG) + +#define MCPWM0_CAP0_GPIO48 \ + ESP32_PINMUX(48, ESP_PWM0_CAP0_IN, ESP_NOSIG) + +/* MCPWM0_CAP1 */ +#define MCPWM0_CAP1_GPIO0 \ + ESP32_PINMUX(0, ESP_PWM0_CAP1_IN, ESP_NOSIG) + +#define MCPWM0_CAP1_GPIO1 \ + ESP32_PINMUX(1, ESP_PWM0_CAP1_IN, ESP_NOSIG) + +#define MCPWM0_CAP1_GPIO2 \ + ESP32_PINMUX(2, ESP_PWM0_CAP1_IN, ESP_NOSIG) + +#define MCPWM0_CAP1_GPIO3 \ + ESP32_PINMUX(3, ESP_PWM0_CAP1_IN, ESP_NOSIG) + +#define MCPWM0_CAP1_GPIO4 \ + ESP32_PINMUX(4, ESP_PWM0_CAP1_IN, ESP_NOSIG) + +#define MCPWM0_CAP1_GPIO5 \ + ESP32_PINMUX(5, ESP_PWM0_CAP1_IN, ESP_NOSIG) + +#define MCPWM0_CAP1_GPIO6 \ + ESP32_PINMUX(6, ESP_PWM0_CAP1_IN, ESP_NOSIG) + +#define MCPWM0_CAP1_GPIO7 \ + ESP32_PINMUX(7, ESP_PWM0_CAP1_IN, ESP_NOSIG) + +#define MCPWM0_CAP1_GPIO8 \ + ESP32_PINMUX(8, ESP_PWM0_CAP1_IN, ESP_NOSIG) + +#define MCPWM0_CAP1_GPIO9 \ + ESP32_PINMUX(9, ESP_PWM0_CAP1_IN, ESP_NOSIG) + +#define MCPWM0_CAP1_GPIO10 \ + ESP32_PINMUX(10, ESP_PWM0_CAP1_IN, ESP_NOSIG) + +#define MCPWM0_CAP1_GPIO11 \ + ESP32_PINMUX(11, ESP_PWM0_CAP1_IN, ESP_NOSIG) + +#define MCPWM0_CAP1_GPIO12 \ + ESP32_PINMUX(12, ESP_PWM0_CAP1_IN, ESP_NOSIG) + +#define MCPWM0_CAP1_GPIO13 \ + ESP32_PINMUX(13, ESP_PWM0_CAP1_IN, ESP_NOSIG) + +#define MCPWM0_CAP1_GPIO14 \ + ESP32_PINMUX(14, ESP_PWM0_CAP1_IN, ESP_NOSIG) + +#define MCPWM0_CAP1_GPIO15 \ + ESP32_PINMUX(15, ESP_PWM0_CAP1_IN, ESP_NOSIG) + +#define MCPWM0_CAP1_GPIO16 \ + ESP32_PINMUX(16, ESP_PWM0_CAP1_IN, ESP_NOSIG) + +#define MCPWM0_CAP1_GPIO17 \ + ESP32_PINMUX(17, ESP_PWM0_CAP1_IN, ESP_NOSIG) + +#define MCPWM0_CAP1_GPIO18 \ + ESP32_PINMUX(18, ESP_PWM0_CAP1_IN, ESP_NOSIG) + +#define MCPWM0_CAP1_GPIO19 \ + ESP32_PINMUX(19, ESP_PWM0_CAP1_IN, ESP_NOSIG) + +#define MCPWM0_CAP1_GPIO20 \ + ESP32_PINMUX(20, ESP_PWM0_CAP1_IN, ESP_NOSIG) + +#define MCPWM0_CAP1_GPIO21 \ + ESP32_PINMUX(21, ESP_PWM0_CAP1_IN, ESP_NOSIG) + +#define MCPWM0_CAP1_GPIO26 \ + ESP32_PINMUX(26, ESP_PWM0_CAP1_IN, ESP_NOSIG) + +#define MCPWM0_CAP1_GPIO27 \ + ESP32_PINMUX(27, ESP_PWM0_CAP1_IN, ESP_NOSIG) + +#define MCPWM0_CAP1_GPIO28 \ + ESP32_PINMUX(28, ESP_PWM0_CAP1_IN, ESP_NOSIG) + +#define MCPWM0_CAP1_GPIO29 \ + ESP32_PINMUX(29, ESP_PWM0_CAP1_IN, ESP_NOSIG) + +#define MCPWM0_CAP1_GPIO30 \ + ESP32_PINMUX(30, ESP_PWM0_CAP1_IN, ESP_NOSIG) + +#define MCPWM0_CAP1_GPIO31 \ + ESP32_PINMUX(31, ESP_PWM0_CAP1_IN, ESP_NOSIG) + +#define MCPWM0_CAP1_GPIO32 \ + ESP32_PINMUX(32, ESP_PWM0_CAP1_IN, ESP_NOSIG) + +#define MCPWM0_CAP1_GPIO33 \ + ESP32_PINMUX(33, ESP_PWM0_CAP1_IN, ESP_NOSIG) + +#define MCPWM0_CAP1_GPIO34 \ + ESP32_PINMUX(34, ESP_PWM0_CAP1_IN, ESP_NOSIG) + +#define MCPWM0_CAP1_GPIO35 \ + ESP32_PINMUX(35, ESP_PWM0_CAP1_IN, ESP_NOSIG) + +#define MCPWM0_CAP1_GPIO36 \ + ESP32_PINMUX(36, ESP_PWM0_CAP1_IN, ESP_NOSIG) + +#define MCPWM0_CAP1_GPIO37 \ + ESP32_PINMUX(37, ESP_PWM0_CAP1_IN, ESP_NOSIG) + +#define MCPWM0_CAP1_GPIO38 \ + ESP32_PINMUX(38, ESP_PWM0_CAP1_IN, ESP_NOSIG) + +#define MCPWM0_CAP1_GPIO39 \ + ESP32_PINMUX(39, ESP_PWM0_CAP1_IN, ESP_NOSIG) + +#define MCPWM0_CAP1_GPIO40 \ + ESP32_PINMUX(40, ESP_PWM0_CAP1_IN, ESP_NOSIG) + +#define MCPWM0_CAP1_GPIO41 \ + ESP32_PINMUX(41, ESP_PWM0_CAP1_IN, ESP_NOSIG) + +#define MCPWM0_CAP1_GPIO42 \ + ESP32_PINMUX(42, ESP_PWM0_CAP1_IN, ESP_NOSIG) + +#define MCPWM0_CAP1_GPIO43 \ + ESP32_PINMUX(43, ESP_PWM0_CAP1_IN, ESP_NOSIG) + +#define MCPWM0_CAP1_GPIO44 \ + ESP32_PINMUX(44, ESP_PWM0_CAP1_IN, ESP_NOSIG) + +#define MCPWM0_CAP1_GPIO45 \ + ESP32_PINMUX(45, ESP_PWM0_CAP1_IN, ESP_NOSIG) + +#define MCPWM0_CAP1_GPIO46 \ + ESP32_PINMUX(46, ESP_PWM0_CAP1_IN, ESP_NOSIG) + +#define MCPWM0_CAP1_GPIO47 \ + ESP32_PINMUX(47, ESP_PWM0_CAP1_IN, ESP_NOSIG) + +#define MCPWM0_CAP1_GPIO48 \ + ESP32_PINMUX(48, ESP_PWM0_CAP1_IN, ESP_NOSIG) + +/* MCPWM0_CAP2 */ +#define MCPWM0_CAP2_GPIO0 \ + ESP32_PINMUX(0, ESP_PWM0_CAP2_IN, ESP_NOSIG) + +#define MCPWM0_CAP2_GPIO1 \ + ESP32_PINMUX(1, ESP_PWM0_CAP2_IN, ESP_NOSIG) + +#define MCPWM0_CAP2_GPIO2 \ + ESP32_PINMUX(2, ESP_PWM0_CAP2_IN, ESP_NOSIG) + +#define MCPWM0_CAP2_GPIO3 \ + ESP32_PINMUX(3, ESP_PWM0_CAP2_IN, ESP_NOSIG) + +#define MCPWM0_CAP2_GPIO4 \ + ESP32_PINMUX(4, ESP_PWM0_CAP2_IN, ESP_NOSIG) + +#define MCPWM0_CAP2_GPIO5 \ + ESP32_PINMUX(5, ESP_PWM0_CAP2_IN, ESP_NOSIG) + +#define MCPWM0_CAP2_GPIO6 \ + ESP32_PINMUX(6, ESP_PWM0_CAP2_IN, ESP_NOSIG) + +#define MCPWM0_CAP2_GPIO7 \ + ESP32_PINMUX(7, ESP_PWM0_CAP2_IN, ESP_NOSIG) + +#define MCPWM0_CAP2_GPIO8 \ + ESP32_PINMUX(8, ESP_PWM0_CAP2_IN, ESP_NOSIG) + +#define MCPWM0_CAP2_GPIO9 \ + ESP32_PINMUX(9, ESP_PWM0_CAP2_IN, ESP_NOSIG) + +#define MCPWM0_CAP2_GPIO10 \ + ESP32_PINMUX(10, ESP_PWM0_CAP2_IN, ESP_NOSIG) + +#define MCPWM0_CAP2_GPIO11 \ + ESP32_PINMUX(11, ESP_PWM0_CAP2_IN, ESP_NOSIG) + +#define MCPWM0_CAP2_GPIO12 \ + ESP32_PINMUX(12, ESP_PWM0_CAP2_IN, ESP_NOSIG) + +#define MCPWM0_CAP2_GPIO13 \ + ESP32_PINMUX(13, ESP_PWM0_CAP2_IN, ESP_NOSIG) + +#define MCPWM0_CAP2_GPIO14 \ + ESP32_PINMUX(14, ESP_PWM0_CAP2_IN, ESP_NOSIG) + +#define MCPWM0_CAP2_GPIO15 \ + ESP32_PINMUX(15, ESP_PWM0_CAP2_IN, ESP_NOSIG) + +#define MCPWM0_CAP2_GPIO16 \ + ESP32_PINMUX(16, ESP_PWM0_CAP2_IN, ESP_NOSIG) + +#define MCPWM0_CAP2_GPIO17 \ + ESP32_PINMUX(17, ESP_PWM0_CAP2_IN, ESP_NOSIG) + +#define MCPWM0_CAP2_GPIO18 \ + ESP32_PINMUX(18, ESP_PWM0_CAP2_IN, ESP_NOSIG) + +#define MCPWM0_CAP2_GPIO19 \ + ESP32_PINMUX(19, ESP_PWM0_CAP2_IN, ESP_NOSIG) + +#define MCPWM0_CAP2_GPIO20 \ + ESP32_PINMUX(20, ESP_PWM0_CAP2_IN, ESP_NOSIG) + +#define MCPWM0_CAP2_GPIO21 \ + ESP32_PINMUX(21, ESP_PWM0_CAP2_IN, ESP_NOSIG) + +#define MCPWM0_CAP2_GPIO26 \ + ESP32_PINMUX(26, ESP_PWM0_CAP2_IN, ESP_NOSIG) + +#define MCPWM0_CAP2_GPIO27 \ + ESP32_PINMUX(27, ESP_PWM0_CAP2_IN, ESP_NOSIG) + +#define MCPWM0_CAP2_GPIO28 \ + ESP32_PINMUX(28, ESP_PWM0_CAP2_IN, ESP_NOSIG) + +#define MCPWM0_CAP2_GPIO29 \ + ESP32_PINMUX(29, ESP_PWM0_CAP2_IN, ESP_NOSIG) + +#define MCPWM0_CAP2_GPIO30 \ + ESP32_PINMUX(30, ESP_PWM0_CAP2_IN, ESP_NOSIG) + +#define MCPWM0_CAP2_GPIO31 \ + ESP32_PINMUX(31, ESP_PWM0_CAP2_IN, ESP_NOSIG) + +#define MCPWM0_CAP2_GPIO32 \ + ESP32_PINMUX(32, ESP_PWM0_CAP2_IN, ESP_NOSIG) + +#define MCPWM0_CAP2_GPIO33 \ + ESP32_PINMUX(33, ESP_PWM0_CAP2_IN, ESP_NOSIG) + +#define MCPWM0_CAP2_GPIO34 \ + ESP32_PINMUX(34, ESP_PWM0_CAP2_IN, ESP_NOSIG) + +#define MCPWM0_CAP2_GPIO35 \ + ESP32_PINMUX(35, ESP_PWM0_CAP2_IN, ESP_NOSIG) + +#define MCPWM0_CAP2_GPIO36 \ + ESP32_PINMUX(36, ESP_PWM0_CAP2_IN, ESP_NOSIG) + +#define MCPWM0_CAP2_GPIO37 \ + ESP32_PINMUX(37, ESP_PWM0_CAP2_IN, ESP_NOSIG) + +#define MCPWM0_CAP2_GPIO38 \ + ESP32_PINMUX(38, ESP_PWM0_CAP2_IN, ESP_NOSIG) + +#define MCPWM0_CAP2_GPIO39 \ + ESP32_PINMUX(39, ESP_PWM0_CAP2_IN, ESP_NOSIG) + +#define MCPWM0_CAP2_GPIO40 \ + ESP32_PINMUX(40, ESP_PWM0_CAP2_IN, ESP_NOSIG) + +#define MCPWM0_CAP2_GPIO41 \ + ESP32_PINMUX(41, ESP_PWM0_CAP2_IN, ESP_NOSIG) + +#define MCPWM0_CAP2_GPIO42 \ + ESP32_PINMUX(42, ESP_PWM0_CAP2_IN, ESP_NOSIG) + +#define MCPWM0_CAP2_GPIO43 \ + ESP32_PINMUX(43, ESP_PWM0_CAP2_IN, ESP_NOSIG) + +#define MCPWM0_CAP2_GPIO44 \ + ESP32_PINMUX(44, ESP_PWM0_CAP2_IN, ESP_NOSIG) + +#define MCPWM0_CAP2_GPIO45 \ + ESP32_PINMUX(45, ESP_PWM0_CAP2_IN, ESP_NOSIG) + +#define MCPWM0_CAP2_GPIO46 \ + ESP32_PINMUX(46, ESP_PWM0_CAP2_IN, ESP_NOSIG) + +#define MCPWM0_CAP2_GPIO47 \ + ESP32_PINMUX(47, ESP_PWM0_CAP2_IN, ESP_NOSIG) + +#define MCPWM0_CAP2_GPIO48 \ + ESP32_PINMUX(48, ESP_PWM0_CAP2_IN, ESP_NOSIG) + +/* MCPWM0_FAULT0 */ +#define MCPWM0_FAULT0_GPIO0 \ + ESP32_PINMUX(0, ESP_PWM0_F0_IN, ESP_NOSIG) + +#define MCPWM0_FAULT0_GPIO1 \ + ESP32_PINMUX(1, ESP_PWM0_F0_IN, ESP_NOSIG) + +#define MCPWM0_FAULT0_GPIO2 \ + ESP32_PINMUX(2, ESP_PWM0_F0_IN, ESP_NOSIG) + +#define MCPWM0_FAULT0_GPIO3 \ + ESP32_PINMUX(3, ESP_PWM0_F0_IN, ESP_NOSIG) + +#define MCPWM0_FAULT0_GPIO4 \ + ESP32_PINMUX(4, ESP_PWM0_F0_IN, ESP_NOSIG) + +#define MCPWM0_FAULT0_GPIO5 \ + ESP32_PINMUX(5, ESP_PWM0_F0_IN, ESP_NOSIG) + +#define MCPWM0_FAULT0_GPIO6 \ + ESP32_PINMUX(6, ESP_PWM0_F0_IN, ESP_NOSIG) + +#define MCPWM0_FAULT0_GPIO7 \ + ESP32_PINMUX(7, ESP_PWM0_F0_IN, ESP_NOSIG) + +#define MCPWM0_FAULT0_GPIO8 \ + ESP32_PINMUX(8, ESP_PWM0_F0_IN, ESP_NOSIG) + +#define MCPWM0_FAULT0_GPIO9 \ + ESP32_PINMUX(9, ESP_PWM0_F0_IN, ESP_NOSIG) + +#define MCPWM0_FAULT0_GPIO10 \ + ESP32_PINMUX(10, ESP_PWM0_F0_IN, ESP_NOSIG) + +#define MCPWM0_FAULT0_GPIO11 \ + ESP32_PINMUX(11, ESP_PWM0_F0_IN, ESP_NOSIG) + +#define MCPWM0_FAULT0_GPIO12 \ + ESP32_PINMUX(12, ESP_PWM0_F0_IN, ESP_NOSIG) + +#define MCPWM0_FAULT0_GPIO13 \ + ESP32_PINMUX(13, ESP_PWM0_F0_IN, ESP_NOSIG) + +#define MCPWM0_FAULT0_GPIO14 \ + ESP32_PINMUX(14, ESP_PWM0_F0_IN, ESP_NOSIG) + +#define MCPWM0_FAULT0_GPIO15 \ + ESP32_PINMUX(15, ESP_PWM0_F0_IN, ESP_NOSIG) + +#define MCPWM0_FAULT0_GPIO16 \ + ESP32_PINMUX(16, ESP_PWM0_F0_IN, ESP_NOSIG) + +#define MCPWM0_FAULT0_GPIO17 \ + ESP32_PINMUX(17, ESP_PWM0_F0_IN, ESP_NOSIG) + +#define MCPWM0_FAULT0_GPIO18 \ + ESP32_PINMUX(18, ESP_PWM0_F0_IN, ESP_NOSIG) + +#define MCPWM0_FAULT0_GPIO19 \ + ESP32_PINMUX(19, ESP_PWM0_F0_IN, ESP_NOSIG) + +#define MCPWM0_FAULT0_GPIO20 \ + ESP32_PINMUX(20, ESP_PWM0_F0_IN, ESP_NOSIG) + +#define MCPWM0_FAULT0_GPIO21 \ + ESP32_PINMUX(21, ESP_PWM0_F0_IN, ESP_NOSIG) + +#define MCPWM0_FAULT0_GPIO26 \ + ESP32_PINMUX(26, ESP_PWM0_F0_IN, ESP_NOSIG) + +#define MCPWM0_FAULT0_GPIO27 \ + ESP32_PINMUX(27, ESP_PWM0_F0_IN, ESP_NOSIG) + +#define MCPWM0_FAULT0_GPIO28 \ + ESP32_PINMUX(28, ESP_PWM0_F0_IN, ESP_NOSIG) + +#define MCPWM0_FAULT0_GPIO29 \ + ESP32_PINMUX(29, ESP_PWM0_F0_IN, ESP_NOSIG) + +#define MCPWM0_FAULT0_GPIO30 \ + ESP32_PINMUX(30, ESP_PWM0_F0_IN, ESP_NOSIG) + +#define MCPWM0_FAULT0_GPIO31 \ + ESP32_PINMUX(31, ESP_PWM0_F0_IN, ESP_NOSIG) + +#define MCPWM0_FAULT0_GPIO32 \ + ESP32_PINMUX(32, ESP_PWM0_F0_IN, ESP_NOSIG) + +#define MCPWM0_FAULT0_GPIO33 \ + ESP32_PINMUX(33, ESP_PWM0_F0_IN, ESP_NOSIG) + +#define MCPWM0_FAULT0_GPIO34 \ + ESP32_PINMUX(34, ESP_PWM0_F0_IN, ESP_NOSIG) + +#define MCPWM0_FAULT0_GPIO35 \ + ESP32_PINMUX(35, ESP_PWM0_F0_IN, ESP_NOSIG) + +#define MCPWM0_FAULT0_GPIO36 \ + ESP32_PINMUX(36, ESP_PWM0_F0_IN, ESP_NOSIG) + +#define MCPWM0_FAULT0_GPIO37 \ + ESP32_PINMUX(37, ESP_PWM0_F0_IN, ESP_NOSIG) + +#define MCPWM0_FAULT0_GPIO38 \ + ESP32_PINMUX(38, ESP_PWM0_F0_IN, ESP_NOSIG) + +#define MCPWM0_FAULT0_GPIO39 \ + ESP32_PINMUX(39, ESP_PWM0_F0_IN, ESP_NOSIG) + +#define MCPWM0_FAULT0_GPIO40 \ + ESP32_PINMUX(40, ESP_PWM0_F0_IN, ESP_NOSIG) + +#define MCPWM0_FAULT0_GPIO41 \ + ESP32_PINMUX(41, ESP_PWM0_F0_IN, ESP_NOSIG) + +#define MCPWM0_FAULT0_GPIO42 \ + ESP32_PINMUX(42, ESP_PWM0_F0_IN, ESP_NOSIG) + +#define MCPWM0_FAULT0_GPIO43 \ + ESP32_PINMUX(43, ESP_PWM0_F0_IN, ESP_NOSIG) + +#define MCPWM0_FAULT0_GPIO44 \ + ESP32_PINMUX(44, ESP_PWM0_F0_IN, ESP_NOSIG) + +#define MCPWM0_FAULT0_GPIO45 \ + ESP32_PINMUX(45, ESP_PWM0_F0_IN, ESP_NOSIG) + +#define MCPWM0_FAULT0_GPIO46 \ + ESP32_PINMUX(46, ESP_PWM0_F0_IN, ESP_NOSIG) + +#define MCPWM0_FAULT0_GPIO47 \ + ESP32_PINMUX(47, ESP_PWM0_F0_IN, ESP_NOSIG) + +#define MCPWM0_FAULT0_GPIO48 \ + ESP32_PINMUX(48, ESP_PWM0_F0_IN, ESP_NOSIG) + +/* MCPWM0_FAULT1 */ +#define MCPWM0_FAULT1_GPIO0 \ + ESP32_PINMUX(0, ESP_PWM0_F1_IN, ESP_NOSIG) + +#define MCPWM0_FAULT1_GPIO1 \ + ESP32_PINMUX(1, ESP_PWM0_F1_IN, ESP_NOSIG) + +#define MCPWM0_FAULT1_GPIO2 \ + ESP32_PINMUX(2, ESP_PWM0_F1_IN, ESP_NOSIG) + +#define MCPWM0_FAULT1_GPIO3 \ + ESP32_PINMUX(3, ESP_PWM0_F1_IN, ESP_NOSIG) + +#define MCPWM0_FAULT1_GPIO4 \ + ESP32_PINMUX(4, ESP_PWM0_F1_IN, ESP_NOSIG) + +#define MCPWM0_FAULT1_GPIO5 \ + ESP32_PINMUX(5, ESP_PWM0_F1_IN, ESP_NOSIG) + +#define MCPWM0_FAULT1_GPIO6 \ + ESP32_PINMUX(6, ESP_PWM0_F1_IN, ESP_NOSIG) + +#define MCPWM0_FAULT1_GPIO7 \ + ESP32_PINMUX(7, ESP_PWM0_F1_IN, ESP_NOSIG) + +#define MCPWM0_FAULT1_GPIO8 \ + ESP32_PINMUX(8, ESP_PWM0_F1_IN, ESP_NOSIG) + +#define MCPWM0_FAULT1_GPIO9 \ + ESP32_PINMUX(9, ESP_PWM0_F1_IN, ESP_NOSIG) + +#define MCPWM0_FAULT1_GPIO10 \ + ESP32_PINMUX(10, ESP_PWM0_F1_IN, ESP_NOSIG) + +#define MCPWM0_FAULT1_GPIO11 \ + ESP32_PINMUX(11, ESP_PWM0_F1_IN, ESP_NOSIG) + +#define MCPWM0_FAULT1_GPIO12 \ + ESP32_PINMUX(12, ESP_PWM0_F1_IN, ESP_NOSIG) + +#define MCPWM0_FAULT1_GPIO13 \ + ESP32_PINMUX(13, ESP_PWM0_F1_IN, ESP_NOSIG) + +#define MCPWM0_FAULT1_GPIO14 \ + ESP32_PINMUX(14, ESP_PWM0_F1_IN, ESP_NOSIG) + +#define MCPWM0_FAULT1_GPIO15 \ + ESP32_PINMUX(15, ESP_PWM0_F1_IN, ESP_NOSIG) + +#define MCPWM0_FAULT1_GPIO16 \ + ESP32_PINMUX(16, ESP_PWM0_F1_IN, ESP_NOSIG) + +#define MCPWM0_FAULT1_GPIO17 \ + ESP32_PINMUX(17, ESP_PWM0_F1_IN, ESP_NOSIG) + +#define MCPWM0_FAULT1_GPIO18 \ + ESP32_PINMUX(18, ESP_PWM0_F1_IN, ESP_NOSIG) + +#define MCPWM0_FAULT1_GPIO19 \ + ESP32_PINMUX(19, ESP_PWM0_F1_IN, ESP_NOSIG) + +#define MCPWM0_FAULT1_GPIO20 \ + ESP32_PINMUX(20, ESP_PWM0_F1_IN, ESP_NOSIG) + +#define MCPWM0_FAULT1_GPIO21 \ + ESP32_PINMUX(21, ESP_PWM0_F1_IN, ESP_NOSIG) + +#define MCPWM0_FAULT1_GPIO26 \ + ESP32_PINMUX(26, ESP_PWM0_F1_IN, ESP_NOSIG) + +#define MCPWM0_FAULT1_GPIO27 \ + ESP32_PINMUX(27, ESP_PWM0_F1_IN, ESP_NOSIG) + +#define MCPWM0_FAULT1_GPIO28 \ + ESP32_PINMUX(28, ESP_PWM0_F1_IN, ESP_NOSIG) + +#define MCPWM0_FAULT1_GPIO29 \ + ESP32_PINMUX(29, ESP_PWM0_F1_IN, ESP_NOSIG) + +#define MCPWM0_FAULT1_GPIO30 \ + ESP32_PINMUX(30, ESP_PWM0_F1_IN, ESP_NOSIG) + +#define MCPWM0_FAULT1_GPIO31 \ + ESP32_PINMUX(31, ESP_PWM0_F1_IN, ESP_NOSIG) + +#define MCPWM0_FAULT1_GPIO32 \ + ESP32_PINMUX(32, ESP_PWM0_F1_IN, ESP_NOSIG) + +#define MCPWM0_FAULT1_GPIO33 \ + ESP32_PINMUX(33, ESP_PWM0_F1_IN, ESP_NOSIG) + +#define MCPWM0_FAULT1_GPIO34 \ + ESP32_PINMUX(34, ESP_PWM0_F1_IN, ESP_NOSIG) + +#define MCPWM0_FAULT1_GPIO35 \ + ESP32_PINMUX(35, ESP_PWM0_F1_IN, ESP_NOSIG) + +#define MCPWM0_FAULT1_GPIO36 \ + ESP32_PINMUX(36, ESP_PWM0_F1_IN, ESP_NOSIG) + +#define MCPWM0_FAULT1_GPIO37 \ + ESP32_PINMUX(37, ESP_PWM0_F1_IN, ESP_NOSIG) + +#define MCPWM0_FAULT1_GPIO38 \ + ESP32_PINMUX(38, ESP_PWM0_F1_IN, ESP_NOSIG) + +#define MCPWM0_FAULT1_GPIO39 \ + ESP32_PINMUX(39, ESP_PWM0_F1_IN, ESP_NOSIG) + +#define MCPWM0_FAULT1_GPIO40 \ + ESP32_PINMUX(40, ESP_PWM0_F1_IN, ESP_NOSIG) + +#define MCPWM0_FAULT1_GPIO41 \ + ESP32_PINMUX(41, ESP_PWM0_F1_IN, ESP_NOSIG) + +#define MCPWM0_FAULT1_GPIO42 \ + ESP32_PINMUX(42, ESP_PWM0_F1_IN, ESP_NOSIG) + +#define MCPWM0_FAULT1_GPIO43 \ + ESP32_PINMUX(43, ESP_PWM0_F1_IN, ESP_NOSIG) + +#define MCPWM0_FAULT1_GPIO44 \ + ESP32_PINMUX(44, ESP_PWM0_F1_IN, ESP_NOSIG) + +#define MCPWM0_FAULT1_GPIO45 \ + ESP32_PINMUX(45, ESP_PWM0_F1_IN, ESP_NOSIG) + +#define MCPWM0_FAULT1_GPIO46 \ + ESP32_PINMUX(46, ESP_PWM0_F1_IN, ESP_NOSIG) + +#define MCPWM0_FAULT1_GPIO47 \ + ESP32_PINMUX(47, ESP_PWM0_F1_IN, ESP_NOSIG) + +#define MCPWM0_FAULT1_GPIO48 \ + ESP32_PINMUX(48, ESP_PWM0_F1_IN, ESP_NOSIG) + +/* MCPWM0_FAULT2 */ +#define MCPWM0_FAULT2_GPIO0 \ + ESP32_PINMUX(0, ESP_PWM0_F2_IN, ESP_NOSIG) + +#define MCPWM0_FAULT2_GPIO1 \ + ESP32_PINMUX(1, ESP_PWM0_F2_IN, ESP_NOSIG) + +#define MCPWM0_FAULT2_GPIO2 \ + ESP32_PINMUX(2, ESP_PWM0_F2_IN, ESP_NOSIG) + +#define MCPWM0_FAULT2_GPIO3 \ + ESP32_PINMUX(3, ESP_PWM0_F2_IN, ESP_NOSIG) + +#define MCPWM0_FAULT2_GPIO4 \ + ESP32_PINMUX(4, ESP_PWM0_F2_IN, ESP_NOSIG) + +#define MCPWM0_FAULT2_GPIO5 \ + ESP32_PINMUX(5, ESP_PWM0_F2_IN, ESP_NOSIG) + +#define MCPWM0_FAULT2_GPIO6 \ + ESP32_PINMUX(6, ESP_PWM0_F2_IN, ESP_NOSIG) + +#define MCPWM0_FAULT2_GPIO7 \ + ESP32_PINMUX(7, ESP_PWM0_F2_IN, ESP_NOSIG) + +#define MCPWM0_FAULT2_GPIO8 \ + ESP32_PINMUX(8, ESP_PWM0_F2_IN, ESP_NOSIG) + +#define MCPWM0_FAULT2_GPIO9 \ + ESP32_PINMUX(9, ESP_PWM0_F2_IN, ESP_NOSIG) + +#define MCPWM0_FAULT2_GPIO10 \ + ESP32_PINMUX(10, ESP_PWM0_F2_IN, ESP_NOSIG) + +#define MCPWM0_FAULT2_GPIO11 \ + ESP32_PINMUX(11, ESP_PWM0_F2_IN, ESP_NOSIG) + +#define MCPWM0_FAULT2_GPIO12 \ + ESP32_PINMUX(12, ESP_PWM0_F2_IN, ESP_NOSIG) + +#define MCPWM0_FAULT2_GPIO13 \ + ESP32_PINMUX(13, ESP_PWM0_F2_IN, ESP_NOSIG) + +#define MCPWM0_FAULT2_GPIO14 \ + ESP32_PINMUX(14, ESP_PWM0_F2_IN, ESP_NOSIG) + +#define MCPWM0_FAULT2_GPIO15 \ + ESP32_PINMUX(15, ESP_PWM0_F2_IN, ESP_NOSIG) + +#define MCPWM0_FAULT2_GPIO16 \ + ESP32_PINMUX(16, ESP_PWM0_F2_IN, ESP_NOSIG) + +#define MCPWM0_FAULT2_GPIO17 \ + ESP32_PINMUX(17, ESP_PWM0_F2_IN, ESP_NOSIG) + +#define MCPWM0_FAULT2_GPIO18 \ + ESP32_PINMUX(18, ESP_PWM0_F2_IN, ESP_NOSIG) + +#define MCPWM0_FAULT2_GPIO19 \ + ESP32_PINMUX(19, ESP_PWM0_F2_IN, ESP_NOSIG) + +#define MCPWM0_FAULT2_GPIO20 \ + ESP32_PINMUX(20, ESP_PWM0_F2_IN, ESP_NOSIG) + +#define MCPWM0_FAULT2_GPIO21 \ + ESP32_PINMUX(21, ESP_PWM0_F2_IN, ESP_NOSIG) + +#define MCPWM0_FAULT2_GPIO26 \ + ESP32_PINMUX(26, ESP_PWM0_F2_IN, ESP_NOSIG) + +#define MCPWM0_FAULT2_GPIO27 \ + ESP32_PINMUX(27, ESP_PWM0_F2_IN, ESP_NOSIG) + +#define MCPWM0_FAULT2_GPIO28 \ + ESP32_PINMUX(28, ESP_PWM0_F2_IN, ESP_NOSIG) + +#define MCPWM0_FAULT2_GPIO29 \ + ESP32_PINMUX(29, ESP_PWM0_F2_IN, ESP_NOSIG) + +#define MCPWM0_FAULT2_GPIO30 \ + ESP32_PINMUX(30, ESP_PWM0_F2_IN, ESP_NOSIG) + +#define MCPWM0_FAULT2_GPIO31 \ + ESP32_PINMUX(31, ESP_PWM0_F2_IN, ESP_NOSIG) + +#define MCPWM0_FAULT2_GPIO32 \ + ESP32_PINMUX(32, ESP_PWM0_F2_IN, ESP_NOSIG) + +#define MCPWM0_FAULT2_GPIO33 \ + ESP32_PINMUX(33, ESP_PWM0_F2_IN, ESP_NOSIG) + +#define MCPWM0_FAULT2_GPIO34 \ + ESP32_PINMUX(34, ESP_PWM0_F2_IN, ESP_NOSIG) + +#define MCPWM0_FAULT2_GPIO35 \ + ESP32_PINMUX(35, ESP_PWM0_F2_IN, ESP_NOSIG) + +#define MCPWM0_FAULT2_GPIO36 \ + ESP32_PINMUX(36, ESP_PWM0_F2_IN, ESP_NOSIG) + +#define MCPWM0_FAULT2_GPIO37 \ + ESP32_PINMUX(37, ESP_PWM0_F2_IN, ESP_NOSIG) + +#define MCPWM0_FAULT2_GPIO38 \ + ESP32_PINMUX(38, ESP_PWM0_F2_IN, ESP_NOSIG) + +#define MCPWM0_FAULT2_GPIO39 \ + ESP32_PINMUX(39, ESP_PWM0_F2_IN, ESP_NOSIG) + +#define MCPWM0_FAULT2_GPIO40 \ + ESP32_PINMUX(40, ESP_PWM0_F2_IN, ESP_NOSIG) + +#define MCPWM0_FAULT2_GPIO41 \ + ESP32_PINMUX(41, ESP_PWM0_F2_IN, ESP_NOSIG) + +#define MCPWM0_FAULT2_GPIO42 \ + ESP32_PINMUX(42, ESP_PWM0_F2_IN, ESP_NOSIG) + +#define MCPWM0_FAULT2_GPIO43 \ + ESP32_PINMUX(43, ESP_PWM0_F2_IN, ESP_NOSIG) + +#define MCPWM0_FAULT2_GPIO44 \ + ESP32_PINMUX(44, ESP_PWM0_F2_IN, ESP_NOSIG) + +#define MCPWM0_FAULT2_GPIO45 \ + ESP32_PINMUX(45, ESP_PWM0_F2_IN, ESP_NOSIG) + +#define MCPWM0_FAULT2_GPIO46 \ + ESP32_PINMUX(46, ESP_PWM0_F2_IN, ESP_NOSIG) + +#define MCPWM0_FAULT2_GPIO47 \ + ESP32_PINMUX(47, ESP_PWM0_F2_IN, ESP_NOSIG) + +#define MCPWM0_FAULT2_GPIO48 \ + ESP32_PINMUX(48, ESP_PWM0_F2_IN, ESP_NOSIG) + +/* MCPWM0_OUT0A */ +#define MCPWM0_OUT0A_GPIO0 \ + ESP32_PINMUX(0, ESP_NOSIG, ESP_PWM0_OUT0A) + +#define MCPWM0_OUT0A_GPIO1 \ + ESP32_PINMUX(1, ESP_NOSIG, ESP_PWM0_OUT0A) + +#define MCPWM0_OUT0A_GPIO2 \ + ESP32_PINMUX(2, ESP_NOSIG, ESP_PWM0_OUT0A) + +#define MCPWM0_OUT0A_GPIO3 \ + ESP32_PINMUX(3, ESP_NOSIG, ESP_PWM0_OUT0A) + +#define MCPWM0_OUT0A_GPIO4 \ + ESP32_PINMUX(4, ESP_NOSIG, ESP_PWM0_OUT0A) + +#define MCPWM0_OUT0A_GPIO5 \ + ESP32_PINMUX(5, ESP_NOSIG, ESP_PWM0_OUT0A) + +#define MCPWM0_OUT0A_GPIO6 \ + ESP32_PINMUX(6, ESP_NOSIG, ESP_PWM0_OUT0A) + +#define MCPWM0_OUT0A_GPIO7 \ + ESP32_PINMUX(7, ESP_NOSIG, ESP_PWM0_OUT0A) + +#define MCPWM0_OUT0A_GPIO8 \ + ESP32_PINMUX(8, ESP_NOSIG, ESP_PWM0_OUT0A) + +#define MCPWM0_OUT0A_GPIO9 \ + ESP32_PINMUX(9, ESP_NOSIG, ESP_PWM0_OUT0A) + +#define MCPWM0_OUT0A_GPIO10 \ + ESP32_PINMUX(10, ESP_NOSIG, ESP_PWM0_OUT0A) + +#define MCPWM0_OUT0A_GPIO11 \ + ESP32_PINMUX(11, ESP_NOSIG, ESP_PWM0_OUT0A) + +#define MCPWM0_OUT0A_GPIO12 \ + ESP32_PINMUX(12, ESP_NOSIG, ESP_PWM0_OUT0A) + +#define MCPWM0_OUT0A_GPIO13 \ + ESP32_PINMUX(13, ESP_NOSIG, ESP_PWM0_OUT0A) + +#define MCPWM0_OUT0A_GPIO14 \ + ESP32_PINMUX(14, ESP_NOSIG, ESP_PWM0_OUT0A) + +#define MCPWM0_OUT0A_GPIO15 \ + ESP32_PINMUX(15, ESP_NOSIG, ESP_PWM0_OUT0A) + +#define MCPWM0_OUT0A_GPIO16 \ + ESP32_PINMUX(16, ESP_NOSIG, ESP_PWM0_OUT0A) + +#define MCPWM0_OUT0A_GPIO17 \ + ESP32_PINMUX(17, ESP_NOSIG, ESP_PWM0_OUT0A) + +#define MCPWM0_OUT0A_GPIO18 \ + ESP32_PINMUX(18, ESP_NOSIG, ESP_PWM0_OUT0A) + +#define MCPWM0_OUT0A_GPIO19 \ + ESP32_PINMUX(19, ESP_NOSIG, ESP_PWM0_OUT0A) + +#define MCPWM0_OUT0A_GPIO20 \ + ESP32_PINMUX(20, ESP_NOSIG, ESP_PWM0_OUT0A) + +#define MCPWM0_OUT0A_GPIO21 \ + ESP32_PINMUX(21, ESP_NOSIG, ESP_PWM0_OUT0A) + +#define MCPWM0_OUT0A_GPIO26 \ + ESP32_PINMUX(26, ESP_NOSIG, ESP_PWM0_OUT0A) + +#define MCPWM0_OUT0A_GPIO27 \ + ESP32_PINMUX(27, ESP_NOSIG, ESP_PWM0_OUT0A) + +#define MCPWM0_OUT0A_GPIO28 \ + ESP32_PINMUX(28, ESP_NOSIG, ESP_PWM0_OUT0A) + +#define MCPWM0_OUT0A_GPIO29 \ + ESP32_PINMUX(29, ESP_NOSIG, ESP_PWM0_OUT0A) + +#define MCPWM0_OUT0A_GPIO30 \ + ESP32_PINMUX(30, ESP_NOSIG, ESP_PWM0_OUT0A) + +#define MCPWM0_OUT0A_GPIO31 \ + ESP32_PINMUX(31, ESP_NOSIG, ESP_PWM0_OUT0A) + +#define MCPWM0_OUT0A_GPIO32 \ + ESP32_PINMUX(32, ESP_NOSIG, ESP_PWM0_OUT0A) + +#define MCPWM0_OUT0A_GPIO33 \ + ESP32_PINMUX(33, ESP_NOSIG, ESP_PWM0_OUT0A) + +#define MCPWM0_OUT0A_GPIO34 \ + ESP32_PINMUX(34, ESP_NOSIG, ESP_PWM0_OUT0A) + +#define MCPWM0_OUT0A_GPIO35 \ + ESP32_PINMUX(35, ESP_NOSIG, ESP_PWM0_OUT0A) + +#define MCPWM0_OUT0A_GPIO36 \ + ESP32_PINMUX(36, ESP_NOSIG, ESP_PWM0_OUT0A) + +#define MCPWM0_OUT0A_GPIO37 \ + ESP32_PINMUX(37, ESP_NOSIG, ESP_PWM0_OUT0A) + +#define MCPWM0_OUT0A_GPIO38 \ + ESP32_PINMUX(38, ESP_NOSIG, ESP_PWM0_OUT0A) + +#define MCPWM0_OUT0A_GPIO39 \ + ESP32_PINMUX(39, ESP_NOSIG, ESP_PWM0_OUT0A) + +#define MCPWM0_OUT0A_GPIO40 \ + ESP32_PINMUX(40, ESP_NOSIG, ESP_PWM0_OUT0A) + +#define MCPWM0_OUT0A_GPIO41 \ + ESP32_PINMUX(41, ESP_NOSIG, ESP_PWM0_OUT0A) + +#define MCPWM0_OUT0A_GPIO42 \ + ESP32_PINMUX(42, ESP_NOSIG, ESP_PWM0_OUT0A) + +#define MCPWM0_OUT0A_GPIO43 \ + ESP32_PINMUX(43, ESP_NOSIG, ESP_PWM0_OUT0A) + +#define MCPWM0_OUT0A_GPIO44 \ + ESP32_PINMUX(44, ESP_NOSIG, ESP_PWM0_OUT0A) + +#define MCPWM0_OUT0A_GPIO45 \ + ESP32_PINMUX(45, ESP_NOSIG, ESP_PWM0_OUT0A) + +#define MCPWM0_OUT0A_GPIO46 \ + ESP32_PINMUX(46, ESP_NOSIG, ESP_PWM0_OUT0A) + +#define MCPWM0_OUT0A_GPIO47 \ + ESP32_PINMUX(47, ESP_NOSIG, ESP_PWM0_OUT0A) + +#define MCPWM0_OUT0A_GPIO48 \ + ESP32_PINMUX(48, ESP_NOSIG, ESP_PWM0_OUT0A) + +/* MCPWM0_OUT0B */ +#define MCPWM0_OUT0B_GPIO0 \ + ESP32_PINMUX(0, ESP_NOSIG, ESP_PWM0_OUT0B) + +#define MCPWM0_OUT0B_GPIO1 \ + ESP32_PINMUX(1, ESP_NOSIG, ESP_PWM0_OUT0B) + +#define MCPWM0_OUT0B_GPIO2 \ + ESP32_PINMUX(2, ESP_NOSIG, ESP_PWM0_OUT0B) + +#define MCPWM0_OUT0B_GPIO3 \ + ESP32_PINMUX(3, ESP_NOSIG, ESP_PWM0_OUT0B) + +#define MCPWM0_OUT0B_GPIO4 \ + ESP32_PINMUX(4, ESP_NOSIG, ESP_PWM0_OUT0B) + +#define MCPWM0_OUT0B_GPIO5 \ + ESP32_PINMUX(5, ESP_NOSIG, ESP_PWM0_OUT0B) + +#define MCPWM0_OUT0B_GPIO6 \ + ESP32_PINMUX(6, ESP_NOSIG, ESP_PWM0_OUT0B) + +#define MCPWM0_OUT0B_GPIO7 \ + ESP32_PINMUX(7, ESP_NOSIG, ESP_PWM0_OUT0B) + +#define MCPWM0_OUT0B_GPIO8 \ + ESP32_PINMUX(8, ESP_NOSIG, ESP_PWM0_OUT0B) + +#define MCPWM0_OUT0B_GPIO9 \ + ESP32_PINMUX(9, ESP_NOSIG, ESP_PWM0_OUT0B) + +#define MCPWM0_OUT0B_GPIO10 \ + ESP32_PINMUX(10, ESP_NOSIG, ESP_PWM0_OUT0B) + +#define MCPWM0_OUT0B_GPIO11 \ + ESP32_PINMUX(11, ESP_NOSIG, ESP_PWM0_OUT0B) + +#define MCPWM0_OUT0B_GPIO12 \ + ESP32_PINMUX(12, ESP_NOSIG, ESP_PWM0_OUT0B) + +#define MCPWM0_OUT0B_GPIO13 \ + ESP32_PINMUX(13, ESP_NOSIG, ESP_PWM0_OUT0B) + +#define MCPWM0_OUT0B_GPIO14 \ + ESP32_PINMUX(14, ESP_NOSIG, ESP_PWM0_OUT0B) + +#define MCPWM0_OUT0B_GPIO15 \ + ESP32_PINMUX(15, ESP_NOSIG, ESP_PWM0_OUT0B) + +#define MCPWM0_OUT0B_GPIO16 \ + ESP32_PINMUX(16, ESP_NOSIG, ESP_PWM0_OUT0B) + +#define MCPWM0_OUT0B_GPIO17 \ + ESP32_PINMUX(17, ESP_NOSIG, ESP_PWM0_OUT0B) + +#define MCPWM0_OUT0B_GPIO18 \ + ESP32_PINMUX(18, ESP_NOSIG, ESP_PWM0_OUT0B) + +#define MCPWM0_OUT0B_GPIO19 \ + ESP32_PINMUX(19, ESP_NOSIG, ESP_PWM0_OUT0B) + +#define MCPWM0_OUT0B_GPIO20 \ + ESP32_PINMUX(20, ESP_NOSIG, ESP_PWM0_OUT0B) + +#define MCPWM0_OUT0B_GPIO21 \ + ESP32_PINMUX(21, ESP_NOSIG, ESP_PWM0_OUT0B) + +#define MCPWM0_OUT0B_GPIO26 \ + ESP32_PINMUX(26, ESP_NOSIG, ESP_PWM0_OUT0B) + +#define MCPWM0_OUT0B_GPIO27 \ + ESP32_PINMUX(27, ESP_NOSIG, ESP_PWM0_OUT0B) + +#define MCPWM0_OUT0B_GPIO28 \ + ESP32_PINMUX(28, ESP_NOSIG, ESP_PWM0_OUT0B) + +#define MCPWM0_OUT0B_GPIO29 \ + ESP32_PINMUX(29, ESP_NOSIG, ESP_PWM0_OUT0B) + +#define MCPWM0_OUT0B_GPIO30 \ + ESP32_PINMUX(30, ESP_NOSIG, ESP_PWM0_OUT0B) + +#define MCPWM0_OUT0B_GPIO31 \ + ESP32_PINMUX(31, ESP_NOSIG, ESP_PWM0_OUT0B) + +#define MCPWM0_OUT0B_GPIO32 \ + ESP32_PINMUX(32, ESP_NOSIG, ESP_PWM0_OUT0B) + +#define MCPWM0_OUT0B_GPIO33 \ + ESP32_PINMUX(33, ESP_NOSIG, ESP_PWM0_OUT0B) + +#define MCPWM0_OUT0B_GPIO34 \ + ESP32_PINMUX(34, ESP_NOSIG, ESP_PWM0_OUT0B) + +#define MCPWM0_OUT0B_GPIO35 \ + ESP32_PINMUX(35, ESP_NOSIG, ESP_PWM0_OUT0B) + +#define MCPWM0_OUT0B_GPIO36 \ + ESP32_PINMUX(36, ESP_NOSIG, ESP_PWM0_OUT0B) + +#define MCPWM0_OUT0B_GPIO37 \ + ESP32_PINMUX(37, ESP_NOSIG, ESP_PWM0_OUT0B) + +#define MCPWM0_OUT0B_GPIO38 \ + ESP32_PINMUX(38, ESP_NOSIG, ESP_PWM0_OUT0B) + +#define MCPWM0_OUT0B_GPIO39 \ + ESP32_PINMUX(39, ESP_NOSIG, ESP_PWM0_OUT0B) + +#define MCPWM0_OUT0B_GPIO40 \ + ESP32_PINMUX(40, ESP_NOSIG, ESP_PWM0_OUT0B) + +#define MCPWM0_OUT0B_GPIO41 \ + ESP32_PINMUX(41, ESP_NOSIG, ESP_PWM0_OUT0B) + +#define MCPWM0_OUT0B_GPIO42 \ + ESP32_PINMUX(42, ESP_NOSIG, ESP_PWM0_OUT0B) + +#define MCPWM0_OUT0B_GPIO43 \ + ESP32_PINMUX(43, ESP_NOSIG, ESP_PWM0_OUT0B) + +#define MCPWM0_OUT0B_GPIO44 \ + ESP32_PINMUX(44, ESP_NOSIG, ESP_PWM0_OUT0B) + +#define MCPWM0_OUT0B_GPIO45 \ + ESP32_PINMUX(45, ESP_NOSIG, ESP_PWM0_OUT0B) + +#define MCPWM0_OUT0B_GPIO46 \ + ESP32_PINMUX(46, ESP_NOSIG, ESP_PWM0_OUT0B) + +#define MCPWM0_OUT0B_GPIO47 \ + ESP32_PINMUX(47, ESP_NOSIG, ESP_PWM0_OUT0B) + +#define MCPWM0_OUT0B_GPIO48 \ + ESP32_PINMUX(48, ESP_NOSIG, ESP_PWM0_OUT0B) + +/* MCPWM0_OUT1A */ +#define MCPWM0_OUT1A_GPIO0 \ + ESP32_PINMUX(0, ESP_NOSIG, ESP_PWM0_OUT1A) + +#define MCPWM0_OUT1A_GPIO1 \ + ESP32_PINMUX(1, ESP_NOSIG, ESP_PWM0_OUT1A) + +#define MCPWM0_OUT1A_GPIO2 \ + ESP32_PINMUX(2, ESP_NOSIG, ESP_PWM0_OUT1A) + +#define MCPWM0_OUT1A_GPIO3 \ + ESP32_PINMUX(3, ESP_NOSIG, ESP_PWM0_OUT1A) + +#define MCPWM0_OUT1A_GPIO4 \ + ESP32_PINMUX(4, ESP_NOSIG, ESP_PWM0_OUT1A) + +#define MCPWM0_OUT1A_GPIO5 \ + ESP32_PINMUX(5, ESP_NOSIG, ESP_PWM0_OUT1A) + +#define MCPWM0_OUT1A_GPIO6 \ + ESP32_PINMUX(6, ESP_NOSIG, ESP_PWM0_OUT1A) + +#define MCPWM0_OUT1A_GPIO7 \ + ESP32_PINMUX(7, ESP_NOSIG, ESP_PWM0_OUT1A) + +#define MCPWM0_OUT1A_GPIO8 \ + ESP32_PINMUX(8, ESP_NOSIG, ESP_PWM0_OUT1A) + +#define MCPWM0_OUT1A_GPIO9 \ + ESP32_PINMUX(9, ESP_NOSIG, ESP_PWM0_OUT1A) + +#define MCPWM0_OUT1A_GPIO10 \ + ESP32_PINMUX(10, ESP_NOSIG, ESP_PWM0_OUT1A) + +#define MCPWM0_OUT1A_GPIO11 \ + ESP32_PINMUX(11, ESP_NOSIG, ESP_PWM0_OUT1A) + +#define MCPWM0_OUT1A_GPIO12 \ + ESP32_PINMUX(12, ESP_NOSIG, ESP_PWM0_OUT1A) + +#define MCPWM0_OUT1A_GPIO13 \ + ESP32_PINMUX(13, ESP_NOSIG, ESP_PWM0_OUT1A) + +#define MCPWM0_OUT1A_GPIO14 \ + ESP32_PINMUX(14, ESP_NOSIG, ESP_PWM0_OUT1A) + +#define MCPWM0_OUT1A_GPIO15 \ + ESP32_PINMUX(15, ESP_NOSIG, ESP_PWM0_OUT1A) + +#define MCPWM0_OUT1A_GPIO16 \ + ESP32_PINMUX(16, ESP_NOSIG, ESP_PWM0_OUT1A) + +#define MCPWM0_OUT1A_GPIO17 \ + ESP32_PINMUX(17, ESP_NOSIG, ESP_PWM0_OUT1A) + +#define MCPWM0_OUT1A_GPIO18 \ + ESP32_PINMUX(18, ESP_NOSIG, ESP_PWM0_OUT1A) + +#define MCPWM0_OUT1A_GPIO19 \ + ESP32_PINMUX(19, ESP_NOSIG, ESP_PWM0_OUT1A) + +#define MCPWM0_OUT1A_GPIO20 \ + ESP32_PINMUX(20, ESP_NOSIG, ESP_PWM0_OUT1A) + +#define MCPWM0_OUT1A_GPIO21 \ + ESP32_PINMUX(21, ESP_NOSIG, ESP_PWM0_OUT1A) + +#define MCPWM0_OUT1A_GPIO26 \ + ESP32_PINMUX(26, ESP_NOSIG, ESP_PWM0_OUT1A) + +#define MCPWM0_OUT1A_GPIO27 \ + ESP32_PINMUX(27, ESP_NOSIG, ESP_PWM0_OUT1A) + +#define MCPWM0_OUT1A_GPIO28 \ + ESP32_PINMUX(28, ESP_NOSIG, ESP_PWM0_OUT1A) + +#define MCPWM0_OUT1A_GPIO29 \ + ESP32_PINMUX(29, ESP_NOSIG, ESP_PWM0_OUT1A) + +#define MCPWM0_OUT1A_GPIO30 \ + ESP32_PINMUX(30, ESP_NOSIG, ESP_PWM0_OUT1A) + +#define MCPWM0_OUT1A_GPIO31 \ + ESP32_PINMUX(31, ESP_NOSIG, ESP_PWM0_OUT1A) + +#define MCPWM0_OUT1A_GPIO32 \ + ESP32_PINMUX(32, ESP_NOSIG, ESP_PWM0_OUT1A) + +#define MCPWM0_OUT1A_GPIO33 \ + ESP32_PINMUX(33, ESP_NOSIG, ESP_PWM0_OUT1A) + +#define MCPWM0_OUT1A_GPIO34 \ + ESP32_PINMUX(34, ESP_NOSIG, ESP_PWM0_OUT1A) + +#define MCPWM0_OUT1A_GPIO35 \ + ESP32_PINMUX(35, ESP_NOSIG, ESP_PWM0_OUT1A) + +#define MCPWM0_OUT1A_GPIO36 \ + ESP32_PINMUX(36, ESP_NOSIG, ESP_PWM0_OUT1A) + +#define MCPWM0_OUT1A_GPIO37 \ + ESP32_PINMUX(37, ESP_NOSIG, ESP_PWM0_OUT1A) + +#define MCPWM0_OUT1A_GPIO38 \ + ESP32_PINMUX(38, ESP_NOSIG, ESP_PWM0_OUT1A) + +#define MCPWM0_OUT1A_GPIO39 \ + ESP32_PINMUX(39, ESP_NOSIG, ESP_PWM0_OUT1A) + +#define MCPWM0_OUT1A_GPIO40 \ + ESP32_PINMUX(40, ESP_NOSIG, ESP_PWM0_OUT1A) + +#define MCPWM0_OUT1A_GPIO41 \ + ESP32_PINMUX(41, ESP_NOSIG, ESP_PWM0_OUT1A) + +#define MCPWM0_OUT1A_GPIO42 \ + ESP32_PINMUX(42, ESP_NOSIG, ESP_PWM0_OUT1A) + +#define MCPWM0_OUT1A_GPIO43 \ + ESP32_PINMUX(43, ESP_NOSIG, ESP_PWM0_OUT1A) + +#define MCPWM0_OUT1A_GPIO44 \ + ESP32_PINMUX(44, ESP_NOSIG, ESP_PWM0_OUT1A) + +#define MCPWM0_OUT1A_GPIO45 \ + ESP32_PINMUX(45, ESP_NOSIG, ESP_PWM0_OUT1A) + +#define MCPWM0_OUT1A_GPIO46 \ + ESP32_PINMUX(46, ESP_NOSIG, ESP_PWM0_OUT1A) + +#define MCPWM0_OUT1A_GPIO47 \ + ESP32_PINMUX(47, ESP_NOSIG, ESP_PWM0_OUT1A) + +#define MCPWM0_OUT1A_GPIO48 \ + ESP32_PINMUX(48, ESP_NOSIG, ESP_PWM0_OUT1A) + +/* MCPWM0_OUT1B */ +#define MCPWM0_OUT1B_GPIO0 \ + ESP32_PINMUX(0, ESP_NOSIG, ESP_PWM0_OUT1B) + +#define MCPWM0_OUT1B_GPIO1 \ + ESP32_PINMUX(1, ESP_NOSIG, ESP_PWM0_OUT1B) + +#define MCPWM0_OUT1B_GPIO2 \ + ESP32_PINMUX(2, ESP_NOSIG, ESP_PWM0_OUT1B) + +#define MCPWM0_OUT1B_GPIO3 \ + ESP32_PINMUX(3, ESP_NOSIG, ESP_PWM0_OUT1B) + +#define MCPWM0_OUT1B_GPIO4 \ + ESP32_PINMUX(4, ESP_NOSIG, ESP_PWM0_OUT1B) + +#define MCPWM0_OUT1B_GPIO5 \ + ESP32_PINMUX(5, ESP_NOSIG, ESP_PWM0_OUT1B) + +#define MCPWM0_OUT1B_GPIO6 \ + ESP32_PINMUX(6, ESP_NOSIG, ESP_PWM0_OUT1B) + +#define MCPWM0_OUT1B_GPIO7 \ + ESP32_PINMUX(7, ESP_NOSIG, ESP_PWM0_OUT1B) + +#define MCPWM0_OUT1B_GPIO8 \ + ESP32_PINMUX(8, ESP_NOSIG, ESP_PWM0_OUT1B) + +#define MCPWM0_OUT1B_GPIO9 \ + ESP32_PINMUX(9, ESP_NOSIG, ESP_PWM0_OUT1B) + +#define MCPWM0_OUT1B_GPIO10 \ + ESP32_PINMUX(10, ESP_NOSIG, ESP_PWM0_OUT1B) + +#define MCPWM0_OUT1B_GPIO11 \ + ESP32_PINMUX(11, ESP_NOSIG, ESP_PWM0_OUT1B) + +#define MCPWM0_OUT1B_GPIO12 \ + ESP32_PINMUX(12, ESP_NOSIG, ESP_PWM0_OUT1B) + +#define MCPWM0_OUT1B_GPIO13 \ + ESP32_PINMUX(13, ESP_NOSIG, ESP_PWM0_OUT1B) + +#define MCPWM0_OUT1B_GPIO14 \ + ESP32_PINMUX(14, ESP_NOSIG, ESP_PWM0_OUT1B) + +#define MCPWM0_OUT1B_GPIO15 \ + ESP32_PINMUX(15, ESP_NOSIG, ESP_PWM0_OUT1B) + +#define MCPWM0_OUT1B_GPIO16 \ + ESP32_PINMUX(16, ESP_NOSIG, ESP_PWM0_OUT1B) + +#define MCPWM0_OUT1B_GPIO17 \ + ESP32_PINMUX(17, ESP_NOSIG, ESP_PWM0_OUT1B) + +#define MCPWM0_OUT1B_GPIO18 \ + ESP32_PINMUX(18, ESP_NOSIG, ESP_PWM0_OUT1B) + +#define MCPWM0_OUT1B_GPIO19 \ + ESP32_PINMUX(19, ESP_NOSIG, ESP_PWM0_OUT1B) + +#define MCPWM0_OUT1B_GPIO20 \ + ESP32_PINMUX(20, ESP_NOSIG, ESP_PWM0_OUT1B) + +#define MCPWM0_OUT1B_GPIO21 \ + ESP32_PINMUX(21, ESP_NOSIG, ESP_PWM0_OUT1B) + +#define MCPWM0_OUT1B_GPIO26 \ + ESP32_PINMUX(26, ESP_NOSIG, ESP_PWM0_OUT1B) + +#define MCPWM0_OUT1B_GPIO27 \ + ESP32_PINMUX(27, ESP_NOSIG, ESP_PWM0_OUT1B) + +#define MCPWM0_OUT1B_GPIO28 \ + ESP32_PINMUX(28, ESP_NOSIG, ESP_PWM0_OUT1B) + +#define MCPWM0_OUT1B_GPIO29 \ + ESP32_PINMUX(29, ESP_NOSIG, ESP_PWM0_OUT1B) + +#define MCPWM0_OUT1B_GPIO30 \ + ESP32_PINMUX(30, ESP_NOSIG, ESP_PWM0_OUT1B) + +#define MCPWM0_OUT1B_GPIO31 \ + ESP32_PINMUX(31, ESP_NOSIG, ESP_PWM0_OUT1B) + +#define MCPWM0_OUT1B_GPIO32 \ + ESP32_PINMUX(32, ESP_NOSIG, ESP_PWM0_OUT1B) + +#define MCPWM0_OUT1B_GPIO33 \ + ESP32_PINMUX(33, ESP_NOSIG, ESP_PWM0_OUT1B) + +#define MCPWM0_OUT1B_GPIO34 \ + ESP32_PINMUX(34, ESP_NOSIG, ESP_PWM0_OUT1B) + +#define MCPWM0_OUT1B_GPIO35 \ + ESP32_PINMUX(35, ESP_NOSIG, ESP_PWM0_OUT1B) + +#define MCPWM0_OUT1B_GPIO36 \ + ESP32_PINMUX(36, ESP_NOSIG, ESP_PWM0_OUT1B) + +#define MCPWM0_OUT1B_GPIO37 \ + ESP32_PINMUX(37, ESP_NOSIG, ESP_PWM0_OUT1B) + +#define MCPWM0_OUT1B_GPIO38 \ + ESP32_PINMUX(38, ESP_NOSIG, ESP_PWM0_OUT1B) + +#define MCPWM0_OUT1B_GPIO39 \ + ESP32_PINMUX(39, ESP_NOSIG, ESP_PWM0_OUT1B) + +#define MCPWM0_OUT1B_GPIO40 \ + ESP32_PINMUX(40, ESP_NOSIG, ESP_PWM0_OUT1B) + +#define MCPWM0_OUT1B_GPIO41 \ + ESP32_PINMUX(41, ESP_NOSIG, ESP_PWM0_OUT1B) + +#define MCPWM0_OUT1B_GPIO42 \ + ESP32_PINMUX(42, ESP_NOSIG, ESP_PWM0_OUT1B) + +#define MCPWM0_OUT1B_GPIO43 \ + ESP32_PINMUX(43, ESP_NOSIG, ESP_PWM0_OUT1B) + +#define MCPWM0_OUT1B_GPIO44 \ + ESP32_PINMUX(44, ESP_NOSIG, ESP_PWM0_OUT1B) + +#define MCPWM0_OUT1B_GPIO45 \ + ESP32_PINMUX(45, ESP_NOSIG, ESP_PWM0_OUT1B) + +#define MCPWM0_OUT1B_GPIO46 \ + ESP32_PINMUX(46, ESP_NOSIG, ESP_PWM0_OUT1B) + +#define MCPWM0_OUT1B_GPIO47 \ + ESP32_PINMUX(47, ESP_NOSIG, ESP_PWM0_OUT1B) + +#define MCPWM0_OUT1B_GPIO48 \ + ESP32_PINMUX(48, ESP_NOSIG, ESP_PWM0_OUT1B) + +/* MCPWM0_OUT2A */ +#define MCPWM0_OUT2A_GPIO0 \ + ESP32_PINMUX(0, ESP_NOSIG, ESP_PWM0_OUT2A) + +#define MCPWM0_OUT2A_GPIO1 \ + ESP32_PINMUX(1, ESP_NOSIG, ESP_PWM0_OUT2A) + +#define MCPWM0_OUT2A_GPIO2 \ + ESP32_PINMUX(2, ESP_NOSIG, ESP_PWM0_OUT2A) + +#define MCPWM0_OUT2A_GPIO3 \ + ESP32_PINMUX(3, ESP_NOSIG, ESP_PWM0_OUT2A) + +#define MCPWM0_OUT2A_GPIO4 \ + ESP32_PINMUX(4, ESP_NOSIG, ESP_PWM0_OUT2A) + +#define MCPWM0_OUT2A_GPIO5 \ + ESP32_PINMUX(5, ESP_NOSIG, ESP_PWM0_OUT2A) + +#define MCPWM0_OUT2A_GPIO6 \ + ESP32_PINMUX(6, ESP_NOSIG, ESP_PWM0_OUT2A) + +#define MCPWM0_OUT2A_GPIO7 \ + ESP32_PINMUX(7, ESP_NOSIG, ESP_PWM0_OUT2A) + +#define MCPWM0_OUT2A_GPIO8 \ + ESP32_PINMUX(8, ESP_NOSIG, ESP_PWM0_OUT2A) + +#define MCPWM0_OUT2A_GPIO9 \ + ESP32_PINMUX(9, ESP_NOSIG, ESP_PWM0_OUT2A) + +#define MCPWM0_OUT2A_GPIO10 \ + ESP32_PINMUX(10, ESP_NOSIG, ESP_PWM0_OUT2A) + +#define MCPWM0_OUT2A_GPIO11 \ + ESP32_PINMUX(11, ESP_NOSIG, ESP_PWM0_OUT2A) + +#define MCPWM0_OUT2A_GPIO12 \ + ESP32_PINMUX(12, ESP_NOSIG, ESP_PWM0_OUT2A) + +#define MCPWM0_OUT2A_GPIO13 \ + ESP32_PINMUX(13, ESP_NOSIG, ESP_PWM0_OUT2A) + +#define MCPWM0_OUT2A_GPIO14 \ + ESP32_PINMUX(14, ESP_NOSIG, ESP_PWM0_OUT2A) + +#define MCPWM0_OUT2A_GPIO15 \ + ESP32_PINMUX(15, ESP_NOSIG, ESP_PWM0_OUT2A) + +#define MCPWM0_OUT2A_GPIO16 \ + ESP32_PINMUX(16, ESP_NOSIG, ESP_PWM0_OUT2A) + +#define MCPWM0_OUT2A_GPIO17 \ + ESP32_PINMUX(17, ESP_NOSIG, ESP_PWM0_OUT2A) + +#define MCPWM0_OUT2A_GPIO18 \ + ESP32_PINMUX(18, ESP_NOSIG, ESP_PWM0_OUT2A) + +#define MCPWM0_OUT2A_GPIO19 \ + ESP32_PINMUX(19, ESP_NOSIG, ESP_PWM0_OUT2A) + +#define MCPWM0_OUT2A_GPIO20 \ + ESP32_PINMUX(20, ESP_NOSIG, ESP_PWM0_OUT2A) + +#define MCPWM0_OUT2A_GPIO21 \ + ESP32_PINMUX(21, ESP_NOSIG, ESP_PWM0_OUT2A) + +#define MCPWM0_OUT2A_GPIO26 \ + ESP32_PINMUX(26, ESP_NOSIG, ESP_PWM0_OUT2A) + +#define MCPWM0_OUT2A_GPIO27 \ + ESP32_PINMUX(27, ESP_NOSIG, ESP_PWM0_OUT2A) + +#define MCPWM0_OUT2A_GPIO28 \ + ESP32_PINMUX(28, ESP_NOSIG, ESP_PWM0_OUT2A) + +#define MCPWM0_OUT2A_GPIO29 \ + ESP32_PINMUX(29, ESP_NOSIG, ESP_PWM0_OUT2A) + +#define MCPWM0_OUT2A_GPIO30 \ + ESP32_PINMUX(30, ESP_NOSIG, ESP_PWM0_OUT2A) + +#define MCPWM0_OUT2A_GPIO31 \ + ESP32_PINMUX(31, ESP_NOSIG, ESP_PWM0_OUT2A) + +#define MCPWM0_OUT2A_GPIO32 \ + ESP32_PINMUX(32, ESP_NOSIG, ESP_PWM0_OUT2A) + +#define MCPWM0_OUT2A_GPIO33 \ + ESP32_PINMUX(33, ESP_NOSIG, ESP_PWM0_OUT2A) + +#define MCPWM0_OUT2A_GPIO34 \ + ESP32_PINMUX(34, ESP_NOSIG, ESP_PWM0_OUT2A) + +#define MCPWM0_OUT2A_GPIO35 \ + ESP32_PINMUX(35, ESP_NOSIG, ESP_PWM0_OUT2A) + +#define MCPWM0_OUT2A_GPIO36 \ + ESP32_PINMUX(36, ESP_NOSIG, ESP_PWM0_OUT2A) + +#define MCPWM0_OUT2A_GPIO37 \ + ESP32_PINMUX(37, ESP_NOSIG, ESP_PWM0_OUT2A) + +#define MCPWM0_OUT2A_GPIO38 \ + ESP32_PINMUX(38, ESP_NOSIG, ESP_PWM0_OUT2A) + +#define MCPWM0_OUT2A_GPIO39 \ + ESP32_PINMUX(39, ESP_NOSIG, ESP_PWM0_OUT2A) + +#define MCPWM0_OUT2A_GPIO40 \ + ESP32_PINMUX(40, ESP_NOSIG, ESP_PWM0_OUT2A) + +#define MCPWM0_OUT2A_GPIO41 \ + ESP32_PINMUX(41, ESP_NOSIG, ESP_PWM0_OUT2A) + +#define MCPWM0_OUT2A_GPIO42 \ + ESP32_PINMUX(42, ESP_NOSIG, ESP_PWM0_OUT2A) + +#define MCPWM0_OUT2A_GPIO43 \ + ESP32_PINMUX(43, ESP_NOSIG, ESP_PWM0_OUT2A) + +#define MCPWM0_OUT2A_GPIO44 \ + ESP32_PINMUX(44, ESP_NOSIG, ESP_PWM0_OUT2A) + +#define MCPWM0_OUT2A_GPIO45 \ + ESP32_PINMUX(45, ESP_NOSIG, ESP_PWM0_OUT2A) + +#define MCPWM0_OUT2A_GPIO46 \ + ESP32_PINMUX(46, ESP_NOSIG, ESP_PWM0_OUT2A) + +#define MCPWM0_OUT2A_GPIO47 \ + ESP32_PINMUX(47, ESP_NOSIG, ESP_PWM0_OUT2A) + +#define MCPWM0_OUT2A_GPIO48 \ + ESP32_PINMUX(48, ESP_NOSIG, ESP_PWM0_OUT2A) + +/* MCPWM0_OUT2B */ +#define MCPWM0_OUT2B_GPIO0 \ + ESP32_PINMUX(0, ESP_NOSIG, ESP_PWM0_OUT2B) + +#define MCPWM0_OUT2B_GPIO1 \ + ESP32_PINMUX(1, ESP_NOSIG, ESP_PWM0_OUT2B) + +#define MCPWM0_OUT2B_GPIO2 \ + ESP32_PINMUX(2, ESP_NOSIG, ESP_PWM0_OUT2B) + +#define MCPWM0_OUT2B_GPIO3 \ + ESP32_PINMUX(3, ESP_NOSIG, ESP_PWM0_OUT2B) + +#define MCPWM0_OUT2B_GPIO4 \ + ESP32_PINMUX(4, ESP_NOSIG, ESP_PWM0_OUT2B) + +#define MCPWM0_OUT2B_GPIO5 \ + ESP32_PINMUX(5, ESP_NOSIG, ESP_PWM0_OUT2B) + +#define MCPWM0_OUT2B_GPIO6 \ + ESP32_PINMUX(6, ESP_NOSIG, ESP_PWM0_OUT2B) + +#define MCPWM0_OUT2B_GPIO7 \ + ESP32_PINMUX(7, ESP_NOSIG, ESP_PWM0_OUT2B) + +#define MCPWM0_OUT2B_GPIO8 \ + ESP32_PINMUX(8, ESP_NOSIG, ESP_PWM0_OUT2B) + +#define MCPWM0_OUT2B_GPIO9 \ + ESP32_PINMUX(9, ESP_NOSIG, ESP_PWM0_OUT2B) + +#define MCPWM0_OUT2B_GPIO10 \ + ESP32_PINMUX(10, ESP_NOSIG, ESP_PWM0_OUT2B) + +#define MCPWM0_OUT2B_GPIO11 \ + ESP32_PINMUX(11, ESP_NOSIG, ESP_PWM0_OUT2B) + +#define MCPWM0_OUT2B_GPIO12 \ + ESP32_PINMUX(12, ESP_NOSIG, ESP_PWM0_OUT2B) + +#define MCPWM0_OUT2B_GPIO13 \ + ESP32_PINMUX(13, ESP_NOSIG, ESP_PWM0_OUT2B) + +#define MCPWM0_OUT2B_GPIO14 \ + ESP32_PINMUX(14, ESP_NOSIG, ESP_PWM0_OUT2B) + +#define MCPWM0_OUT2B_GPIO15 \ + ESP32_PINMUX(15, ESP_NOSIG, ESP_PWM0_OUT2B) + +#define MCPWM0_OUT2B_GPIO16 \ + ESP32_PINMUX(16, ESP_NOSIG, ESP_PWM0_OUT2B) + +#define MCPWM0_OUT2B_GPIO17 \ + ESP32_PINMUX(17, ESP_NOSIG, ESP_PWM0_OUT2B) + +#define MCPWM0_OUT2B_GPIO18 \ + ESP32_PINMUX(18, ESP_NOSIG, ESP_PWM0_OUT2B) + +#define MCPWM0_OUT2B_GPIO19 \ + ESP32_PINMUX(19, ESP_NOSIG, ESP_PWM0_OUT2B) + +#define MCPWM0_OUT2B_GPIO20 \ + ESP32_PINMUX(20, ESP_NOSIG, ESP_PWM0_OUT2B) + +#define MCPWM0_OUT2B_GPIO21 \ + ESP32_PINMUX(21, ESP_NOSIG, ESP_PWM0_OUT2B) + +#define MCPWM0_OUT2B_GPIO26 \ + ESP32_PINMUX(26, ESP_NOSIG, ESP_PWM0_OUT2B) + +#define MCPWM0_OUT2B_GPIO27 \ + ESP32_PINMUX(27, ESP_NOSIG, ESP_PWM0_OUT2B) + +#define MCPWM0_OUT2B_GPIO28 \ + ESP32_PINMUX(28, ESP_NOSIG, ESP_PWM0_OUT2B) + +#define MCPWM0_OUT2B_GPIO29 \ + ESP32_PINMUX(29, ESP_NOSIG, ESP_PWM0_OUT2B) + +#define MCPWM0_OUT2B_GPIO30 \ + ESP32_PINMUX(30, ESP_NOSIG, ESP_PWM0_OUT2B) + +#define MCPWM0_OUT2B_GPIO31 \ + ESP32_PINMUX(31, ESP_NOSIG, ESP_PWM0_OUT2B) + +#define MCPWM0_OUT2B_GPIO32 \ + ESP32_PINMUX(32, ESP_NOSIG, ESP_PWM0_OUT2B) + +#define MCPWM0_OUT2B_GPIO33 \ + ESP32_PINMUX(33, ESP_NOSIG, ESP_PWM0_OUT2B) + +#define MCPWM0_OUT2B_GPIO34 \ + ESP32_PINMUX(34, ESP_NOSIG, ESP_PWM0_OUT2B) + +#define MCPWM0_OUT2B_GPIO35 \ + ESP32_PINMUX(35, ESP_NOSIG, ESP_PWM0_OUT2B) + +#define MCPWM0_OUT2B_GPIO36 \ + ESP32_PINMUX(36, ESP_NOSIG, ESP_PWM0_OUT2B) + +#define MCPWM0_OUT2B_GPIO37 \ + ESP32_PINMUX(37, ESP_NOSIG, ESP_PWM0_OUT2B) + +#define MCPWM0_OUT2B_GPIO38 \ + ESP32_PINMUX(38, ESP_NOSIG, ESP_PWM0_OUT2B) + +#define MCPWM0_OUT2B_GPIO39 \ + ESP32_PINMUX(39, ESP_NOSIG, ESP_PWM0_OUT2B) + +#define MCPWM0_OUT2B_GPIO40 \ + ESP32_PINMUX(40, ESP_NOSIG, ESP_PWM0_OUT2B) + +#define MCPWM0_OUT2B_GPIO41 \ + ESP32_PINMUX(41, ESP_NOSIG, ESP_PWM0_OUT2B) + +#define MCPWM0_OUT2B_GPIO42 \ + ESP32_PINMUX(42, ESP_NOSIG, ESP_PWM0_OUT2B) + +#define MCPWM0_OUT2B_GPIO43 \ + ESP32_PINMUX(43, ESP_NOSIG, ESP_PWM0_OUT2B) + +#define MCPWM0_OUT2B_GPIO44 \ + ESP32_PINMUX(44, ESP_NOSIG, ESP_PWM0_OUT2B) + +#define MCPWM0_OUT2B_GPIO45 \ + ESP32_PINMUX(45, ESP_NOSIG, ESP_PWM0_OUT2B) + +#define MCPWM0_OUT2B_GPIO46 \ + ESP32_PINMUX(46, ESP_NOSIG, ESP_PWM0_OUT2B) + +#define MCPWM0_OUT2B_GPIO47 \ + ESP32_PINMUX(47, ESP_NOSIG, ESP_PWM0_OUT2B) + +#define MCPWM0_OUT2B_GPIO48 \ + ESP32_PINMUX(48, ESP_NOSIG, ESP_PWM0_OUT2B) + +/* MCPWM0_SYNC0 */ +#define MCPWM0_SYNC0_GPIO0 \ + ESP32_PINMUX(0, ESP_PWM0_SYNC0_IN, ESP_NOSIG) + +#define MCPWM0_SYNC0_GPIO1 \ + ESP32_PINMUX(1, ESP_PWM0_SYNC0_IN, ESP_NOSIG) + +#define MCPWM0_SYNC0_GPIO2 \ + ESP32_PINMUX(2, ESP_PWM0_SYNC0_IN, ESP_NOSIG) + +#define MCPWM0_SYNC0_GPIO3 \ + ESP32_PINMUX(3, ESP_PWM0_SYNC0_IN, ESP_NOSIG) + +#define MCPWM0_SYNC0_GPIO4 \ + ESP32_PINMUX(4, ESP_PWM0_SYNC0_IN, ESP_NOSIG) + +#define MCPWM0_SYNC0_GPIO5 \ + ESP32_PINMUX(5, ESP_PWM0_SYNC0_IN, ESP_NOSIG) + +#define MCPWM0_SYNC0_GPIO6 \ + ESP32_PINMUX(6, ESP_PWM0_SYNC0_IN, ESP_NOSIG) + +#define MCPWM0_SYNC0_GPIO7 \ + ESP32_PINMUX(7, ESP_PWM0_SYNC0_IN, ESP_NOSIG) + +#define MCPWM0_SYNC0_GPIO8 \ + ESP32_PINMUX(8, ESP_PWM0_SYNC0_IN, ESP_NOSIG) + +#define MCPWM0_SYNC0_GPIO9 \ + ESP32_PINMUX(9, ESP_PWM0_SYNC0_IN, ESP_NOSIG) + +#define MCPWM0_SYNC0_GPIO10 \ + ESP32_PINMUX(10, ESP_PWM0_SYNC0_IN, ESP_NOSIG) + +#define MCPWM0_SYNC0_GPIO11 \ + ESP32_PINMUX(11, ESP_PWM0_SYNC0_IN, ESP_NOSIG) + +#define MCPWM0_SYNC0_GPIO12 \ + ESP32_PINMUX(12, ESP_PWM0_SYNC0_IN, ESP_NOSIG) + +#define MCPWM0_SYNC0_GPIO13 \ + ESP32_PINMUX(13, ESP_PWM0_SYNC0_IN, ESP_NOSIG) + +#define MCPWM0_SYNC0_GPIO14 \ + ESP32_PINMUX(14, ESP_PWM0_SYNC0_IN, ESP_NOSIG) + +#define MCPWM0_SYNC0_GPIO15 \ + ESP32_PINMUX(15, ESP_PWM0_SYNC0_IN, ESP_NOSIG) + +#define MCPWM0_SYNC0_GPIO16 \ + ESP32_PINMUX(16, ESP_PWM0_SYNC0_IN, ESP_NOSIG) + +#define MCPWM0_SYNC0_GPIO17 \ + ESP32_PINMUX(17, ESP_PWM0_SYNC0_IN, ESP_NOSIG) + +#define MCPWM0_SYNC0_GPIO18 \ + ESP32_PINMUX(18, ESP_PWM0_SYNC0_IN, ESP_NOSIG) + +#define MCPWM0_SYNC0_GPIO19 \ + ESP32_PINMUX(19, ESP_PWM0_SYNC0_IN, ESP_NOSIG) + +#define MCPWM0_SYNC0_GPIO20 \ + ESP32_PINMUX(20, ESP_PWM0_SYNC0_IN, ESP_NOSIG) + +#define MCPWM0_SYNC0_GPIO21 \ + ESP32_PINMUX(21, ESP_PWM0_SYNC0_IN, ESP_NOSIG) + +#define MCPWM0_SYNC0_GPIO26 \ + ESP32_PINMUX(26, ESP_PWM0_SYNC0_IN, ESP_NOSIG) + +#define MCPWM0_SYNC0_GPIO27 \ + ESP32_PINMUX(27, ESP_PWM0_SYNC0_IN, ESP_NOSIG) + +#define MCPWM0_SYNC0_GPIO28 \ + ESP32_PINMUX(28, ESP_PWM0_SYNC0_IN, ESP_NOSIG) + +#define MCPWM0_SYNC0_GPIO29 \ + ESP32_PINMUX(29, ESP_PWM0_SYNC0_IN, ESP_NOSIG) + +#define MCPWM0_SYNC0_GPIO30 \ + ESP32_PINMUX(30, ESP_PWM0_SYNC0_IN, ESP_NOSIG) + +#define MCPWM0_SYNC0_GPIO31 \ + ESP32_PINMUX(31, ESP_PWM0_SYNC0_IN, ESP_NOSIG) + +#define MCPWM0_SYNC0_GPIO32 \ + ESP32_PINMUX(32, ESP_PWM0_SYNC0_IN, ESP_NOSIG) + +#define MCPWM0_SYNC0_GPIO33 \ + ESP32_PINMUX(33, ESP_PWM0_SYNC0_IN, ESP_NOSIG) + +#define MCPWM0_SYNC0_GPIO34 \ + ESP32_PINMUX(34, ESP_PWM0_SYNC0_IN, ESP_NOSIG) + +#define MCPWM0_SYNC0_GPIO35 \ + ESP32_PINMUX(35, ESP_PWM0_SYNC0_IN, ESP_NOSIG) + +#define MCPWM0_SYNC0_GPIO36 \ + ESP32_PINMUX(36, ESP_PWM0_SYNC0_IN, ESP_NOSIG) + +#define MCPWM0_SYNC0_GPIO37 \ + ESP32_PINMUX(37, ESP_PWM0_SYNC0_IN, ESP_NOSIG) + +#define MCPWM0_SYNC0_GPIO38 \ + ESP32_PINMUX(38, ESP_PWM0_SYNC0_IN, ESP_NOSIG) + +#define MCPWM0_SYNC0_GPIO39 \ + ESP32_PINMUX(39, ESP_PWM0_SYNC0_IN, ESP_NOSIG) + +#define MCPWM0_SYNC0_GPIO40 \ + ESP32_PINMUX(40, ESP_PWM0_SYNC0_IN, ESP_NOSIG) + +#define MCPWM0_SYNC0_GPIO41 \ + ESP32_PINMUX(41, ESP_PWM0_SYNC0_IN, ESP_NOSIG) + +#define MCPWM0_SYNC0_GPIO42 \ + ESP32_PINMUX(42, ESP_PWM0_SYNC0_IN, ESP_NOSIG) + +#define MCPWM0_SYNC0_GPIO43 \ + ESP32_PINMUX(43, ESP_PWM0_SYNC0_IN, ESP_NOSIG) + +#define MCPWM0_SYNC0_GPIO44 \ + ESP32_PINMUX(44, ESP_PWM0_SYNC0_IN, ESP_NOSIG) + +#define MCPWM0_SYNC0_GPIO45 \ + ESP32_PINMUX(45, ESP_PWM0_SYNC0_IN, ESP_NOSIG) + +#define MCPWM0_SYNC0_GPIO46 \ + ESP32_PINMUX(46, ESP_PWM0_SYNC0_IN, ESP_NOSIG) + +#define MCPWM0_SYNC0_GPIO47 \ + ESP32_PINMUX(47, ESP_PWM0_SYNC0_IN, ESP_NOSIG) + +#define MCPWM0_SYNC0_GPIO48 \ + ESP32_PINMUX(48, ESP_PWM0_SYNC0_IN, ESP_NOSIG) + +/* MCPWM0_SYNC1 */ +#define MCPWM0_SYNC1_GPIO0 \ + ESP32_PINMUX(0, ESP_PWM0_SYNC1_IN, ESP_NOSIG) + +#define MCPWM0_SYNC1_GPIO1 \ + ESP32_PINMUX(1, ESP_PWM0_SYNC1_IN, ESP_NOSIG) + +#define MCPWM0_SYNC1_GPIO2 \ + ESP32_PINMUX(2, ESP_PWM0_SYNC1_IN, ESP_NOSIG) + +#define MCPWM0_SYNC1_GPIO3 \ + ESP32_PINMUX(3, ESP_PWM0_SYNC1_IN, ESP_NOSIG) + +#define MCPWM0_SYNC1_GPIO4 \ + ESP32_PINMUX(4, ESP_PWM0_SYNC1_IN, ESP_NOSIG) + +#define MCPWM0_SYNC1_GPIO5 \ + ESP32_PINMUX(5, ESP_PWM0_SYNC1_IN, ESP_NOSIG) + +#define MCPWM0_SYNC1_GPIO6 \ + ESP32_PINMUX(6, ESP_PWM0_SYNC1_IN, ESP_NOSIG) + +#define MCPWM0_SYNC1_GPIO7 \ + ESP32_PINMUX(7, ESP_PWM0_SYNC1_IN, ESP_NOSIG) + +#define MCPWM0_SYNC1_GPIO8 \ + ESP32_PINMUX(8, ESP_PWM0_SYNC1_IN, ESP_NOSIG) + +#define MCPWM0_SYNC1_GPIO9 \ + ESP32_PINMUX(9, ESP_PWM0_SYNC1_IN, ESP_NOSIG) + +#define MCPWM0_SYNC1_GPIO10 \ + ESP32_PINMUX(10, ESP_PWM0_SYNC1_IN, ESP_NOSIG) + +#define MCPWM0_SYNC1_GPIO11 \ + ESP32_PINMUX(11, ESP_PWM0_SYNC1_IN, ESP_NOSIG) + +#define MCPWM0_SYNC1_GPIO12 \ + ESP32_PINMUX(12, ESP_PWM0_SYNC1_IN, ESP_NOSIG) + +#define MCPWM0_SYNC1_GPIO13 \ + ESP32_PINMUX(13, ESP_PWM0_SYNC1_IN, ESP_NOSIG) + +#define MCPWM0_SYNC1_GPIO14 \ + ESP32_PINMUX(14, ESP_PWM0_SYNC1_IN, ESP_NOSIG) + +#define MCPWM0_SYNC1_GPIO15 \ + ESP32_PINMUX(15, ESP_PWM0_SYNC1_IN, ESP_NOSIG) + +#define MCPWM0_SYNC1_GPIO16 \ + ESP32_PINMUX(16, ESP_PWM0_SYNC1_IN, ESP_NOSIG) + +#define MCPWM0_SYNC1_GPIO17 \ + ESP32_PINMUX(17, ESP_PWM0_SYNC1_IN, ESP_NOSIG) + +#define MCPWM0_SYNC1_GPIO18 \ + ESP32_PINMUX(18, ESP_PWM0_SYNC1_IN, ESP_NOSIG) + +#define MCPWM0_SYNC1_GPIO19 \ + ESP32_PINMUX(19, ESP_PWM0_SYNC1_IN, ESP_NOSIG) + +#define MCPWM0_SYNC1_GPIO20 \ + ESP32_PINMUX(20, ESP_PWM0_SYNC1_IN, ESP_NOSIG) + +#define MCPWM0_SYNC1_GPIO21 \ + ESP32_PINMUX(21, ESP_PWM0_SYNC1_IN, ESP_NOSIG) + +#define MCPWM0_SYNC1_GPIO26 \ + ESP32_PINMUX(26, ESP_PWM0_SYNC1_IN, ESP_NOSIG) + +#define MCPWM0_SYNC1_GPIO27 \ + ESP32_PINMUX(27, ESP_PWM0_SYNC1_IN, ESP_NOSIG) + +#define MCPWM0_SYNC1_GPIO28 \ + ESP32_PINMUX(28, ESP_PWM0_SYNC1_IN, ESP_NOSIG) + +#define MCPWM0_SYNC1_GPIO29 \ + ESP32_PINMUX(29, ESP_PWM0_SYNC1_IN, ESP_NOSIG) + +#define MCPWM0_SYNC1_GPIO30 \ + ESP32_PINMUX(30, ESP_PWM0_SYNC1_IN, ESP_NOSIG) + +#define MCPWM0_SYNC1_GPIO31 \ + ESP32_PINMUX(31, ESP_PWM0_SYNC1_IN, ESP_NOSIG) + +#define MCPWM0_SYNC1_GPIO32 \ + ESP32_PINMUX(32, ESP_PWM0_SYNC1_IN, ESP_NOSIG) + +#define MCPWM0_SYNC1_GPIO33 \ + ESP32_PINMUX(33, ESP_PWM0_SYNC1_IN, ESP_NOSIG) + +#define MCPWM0_SYNC1_GPIO34 \ + ESP32_PINMUX(34, ESP_PWM0_SYNC1_IN, ESP_NOSIG) + +#define MCPWM0_SYNC1_GPIO35 \ + ESP32_PINMUX(35, ESP_PWM0_SYNC1_IN, ESP_NOSIG) + +#define MCPWM0_SYNC1_GPIO36 \ + ESP32_PINMUX(36, ESP_PWM0_SYNC1_IN, ESP_NOSIG) + +#define MCPWM0_SYNC1_GPIO37 \ + ESP32_PINMUX(37, ESP_PWM0_SYNC1_IN, ESP_NOSIG) + +#define MCPWM0_SYNC1_GPIO38 \ + ESP32_PINMUX(38, ESP_PWM0_SYNC1_IN, ESP_NOSIG) + +#define MCPWM0_SYNC1_GPIO39 \ + ESP32_PINMUX(39, ESP_PWM0_SYNC1_IN, ESP_NOSIG) + +#define MCPWM0_SYNC1_GPIO40 \ + ESP32_PINMUX(40, ESP_PWM0_SYNC1_IN, ESP_NOSIG) + +#define MCPWM0_SYNC1_GPIO41 \ + ESP32_PINMUX(41, ESP_PWM0_SYNC1_IN, ESP_NOSIG) + +#define MCPWM0_SYNC1_GPIO42 \ + ESP32_PINMUX(42, ESP_PWM0_SYNC1_IN, ESP_NOSIG) + +#define MCPWM0_SYNC1_GPIO43 \ + ESP32_PINMUX(43, ESP_PWM0_SYNC1_IN, ESP_NOSIG) + +#define MCPWM0_SYNC1_GPIO44 \ + ESP32_PINMUX(44, ESP_PWM0_SYNC1_IN, ESP_NOSIG) + +#define MCPWM0_SYNC1_GPIO45 \ + ESP32_PINMUX(45, ESP_PWM0_SYNC1_IN, ESP_NOSIG) + +#define MCPWM0_SYNC1_GPIO46 \ + ESP32_PINMUX(46, ESP_PWM0_SYNC1_IN, ESP_NOSIG) + +#define MCPWM0_SYNC1_GPIO47 \ + ESP32_PINMUX(47, ESP_PWM0_SYNC1_IN, ESP_NOSIG) + +#define MCPWM0_SYNC1_GPIO48 \ + ESP32_PINMUX(48, ESP_PWM0_SYNC1_IN, ESP_NOSIG) + +/* MCPWM0_SYNC2 */ +#define MCPWM0_SYNC2_GPIO0 \ + ESP32_PINMUX(0, ESP_PWM0_SYNC2_IN, ESP_NOSIG) + +#define MCPWM0_SYNC2_GPIO1 \ + ESP32_PINMUX(1, ESP_PWM0_SYNC2_IN, ESP_NOSIG) + +#define MCPWM0_SYNC2_GPIO2 \ + ESP32_PINMUX(2, ESP_PWM0_SYNC2_IN, ESP_NOSIG) + +#define MCPWM0_SYNC2_GPIO3 \ + ESP32_PINMUX(3, ESP_PWM0_SYNC2_IN, ESP_NOSIG) + +#define MCPWM0_SYNC2_GPIO4 \ + ESP32_PINMUX(4, ESP_PWM0_SYNC2_IN, ESP_NOSIG) + +#define MCPWM0_SYNC2_GPIO5 \ + ESP32_PINMUX(5, ESP_PWM0_SYNC2_IN, ESP_NOSIG) + +#define MCPWM0_SYNC2_GPIO6 \ + ESP32_PINMUX(6, ESP_PWM0_SYNC2_IN, ESP_NOSIG) + +#define MCPWM0_SYNC2_GPIO7 \ + ESP32_PINMUX(7, ESP_PWM0_SYNC2_IN, ESP_NOSIG) + +#define MCPWM0_SYNC2_GPIO8 \ + ESP32_PINMUX(8, ESP_PWM0_SYNC2_IN, ESP_NOSIG) + +#define MCPWM0_SYNC2_GPIO9 \ + ESP32_PINMUX(9, ESP_PWM0_SYNC2_IN, ESP_NOSIG) + +#define MCPWM0_SYNC2_GPIO10 \ + ESP32_PINMUX(10, ESP_PWM0_SYNC2_IN, ESP_NOSIG) + +#define MCPWM0_SYNC2_GPIO11 \ + ESP32_PINMUX(11, ESP_PWM0_SYNC2_IN, ESP_NOSIG) + +#define MCPWM0_SYNC2_GPIO12 \ + ESP32_PINMUX(12, ESP_PWM0_SYNC2_IN, ESP_NOSIG) + +#define MCPWM0_SYNC2_GPIO13 \ + ESP32_PINMUX(13, ESP_PWM0_SYNC2_IN, ESP_NOSIG) + +#define MCPWM0_SYNC2_GPIO14 \ + ESP32_PINMUX(14, ESP_PWM0_SYNC2_IN, ESP_NOSIG) + +#define MCPWM0_SYNC2_GPIO15 \ + ESP32_PINMUX(15, ESP_PWM0_SYNC2_IN, ESP_NOSIG) + +#define MCPWM0_SYNC2_GPIO16 \ + ESP32_PINMUX(16, ESP_PWM0_SYNC2_IN, ESP_NOSIG) + +#define MCPWM0_SYNC2_GPIO17 \ + ESP32_PINMUX(17, ESP_PWM0_SYNC2_IN, ESP_NOSIG) + +#define MCPWM0_SYNC2_GPIO18 \ + ESP32_PINMUX(18, ESP_PWM0_SYNC2_IN, ESP_NOSIG) + +#define MCPWM0_SYNC2_GPIO19 \ + ESP32_PINMUX(19, ESP_PWM0_SYNC2_IN, ESP_NOSIG) + +#define MCPWM0_SYNC2_GPIO20 \ + ESP32_PINMUX(20, ESP_PWM0_SYNC2_IN, ESP_NOSIG) + +#define MCPWM0_SYNC2_GPIO21 \ + ESP32_PINMUX(21, ESP_PWM0_SYNC2_IN, ESP_NOSIG) + +#define MCPWM0_SYNC2_GPIO26 \ + ESP32_PINMUX(26, ESP_PWM0_SYNC2_IN, ESP_NOSIG) + +#define MCPWM0_SYNC2_GPIO27 \ + ESP32_PINMUX(27, ESP_PWM0_SYNC2_IN, ESP_NOSIG) + +#define MCPWM0_SYNC2_GPIO28 \ + ESP32_PINMUX(28, ESP_PWM0_SYNC2_IN, ESP_NOSIG) + +#define MCPWM0_SYNC2_GPIO29 \ + ESP32_PINMUX(29, ESP_PWM0_SYNC2_IN, ESP_NOSIG) + +#define MCPWM0_SYNC2_GPIO30 \ + ESP32_PINMUX(30, ESP_PWM0_SYNC2_IN, ESP_NOSIG) + +#define MCPWM0_SYNC2_GPIO31 \ + ESP32_PINMUX(31, ESP_PWM0_SYNC2_IN, ESP_NOSIG) + +#define MCPWM0_SYNC2_GPIO32 \ + ESP32_PINMUX(32, ESP_PWM0_SYNC2_IN, ESP_NOSIG) + +#define MCPWM0_SYNC2_GPIO33 \ + ESP32_PINMUX(33, ESP_PWM0_SYNC2_IN, ESP_NOSIG) + +#define MCPWM0_SYNC2_GPIO34 \ + ESP32_PINMUX(34, ESP_PWM0_SYNC2_IN, ESP_NOSIG) + +#define MCPWM0_SYNC2_GPIO35 \ + ESP32_PINMUX(35, ESP_PWM0_SYNC2_IN, ESP_NOSIG) + +#define MCPWM0_SYNC2_GPIO36 \ + ESP32_PINMUX(36, ESP_PWM0_SYNC2_IN, ESP_NOSIG) + +#define MCPWM0_SYNC2_GPIO37 \ + ESP32_PINMUX(37, ESP_PWM0_SYNC2_IN, ESP_NOSIG) + +#define MCPWM0_SYNC2_GPIO38 \ + ESP32_PINMUX(38, ESP_PWM0_SYNC2_IN, ESP_NOSIG) + +#define MCPWM0_SYNC2_GPIO39 \ + ESP32_PINMUX(39, ESP_PWM0_SYNC2_IN, ESP_NOSIG) + +#define MCPWM0_SYNC2_GPIO40 \ + ESP32_PINMUX(40, ESP_PWM0_SYNC2_IN, ESP_NOSIG) + +#define MCPWM0_SYNC2_GPIO41 \ + ESP32_PINMUX(41, ESP_PWM0_SYNC2_IN, ESP_NOSIG) + +#define MCPWM0_SYNC2_GPIO42 \ + ESP32_PINMUX(42, ESP_PWM0_SYNC2_IN, ESP_NOSIG) + +#define MCPWM0_SYNC2_GPIO43 \ + ESP32_PINMUX(43, ESP_PWM0_SYNC2_IN, ESP_NOSIG) + +#define MCPWM0_SYNC2_GPIO44 \ + ESP32_PINMUX(44, ESP_PWM0_SYNC2_IN, ESP_NOSIG) + +#define MCPWM0_SYNC2_GPIO45 \ + ESP32_PINMUX(45, ESP_PWM0_SYNC2_IN, ESP_NOSIG) + +#define MCPWM0_SYNC2_GPIO46 \ + ESP32_PINMUX(46, ESP_PWM0_SYNC2_IN, ESP_NOSIG) + +#define MCPWM0_SYNC2_GPIO47 \ + ESP32_PINMUX(47, ESP_PWM0_SYNC2_IN, ESP_NOSIG) + +#define MCPWM0_SYNC2_GPIO48 \ + ESP32_PINMUX(48, ESP_PWM0_SYNC2_IN, ESP_NOSIG) + +/* MCPWM1_CAP0 */ +#define MCPWM1_CAP0_GPIO0 \ + ESP32_PINMUX(0, ESP_PWM1_CAP0_IN, ESP_NOSIG) + +#define MCPWM1_CAP0_GPIO1 \ + ESP32_PINMUX(1, ESP_PWM1_CAP0_IN, ESP_NOSIG) + +#define MCPWM1_CAP0_GPIO2 \ + ESP32_PINMUX(2, ESP_PWM1_CAP0_IN, ESP_NOSIG) + +#define MCPWM1_CAP0_GPIO3 \ + ESP32_PINMUX(3, ESP_PWM1_CAP0_IN, ESP_NOSIG) + +#define MCPWM1_CAP0_GPIO4 \ + ESP32_PINMUX(4, ESP_PWM1_CAP0_IN, ESP_NOSIG) + +#define MCPWM1_CAP0_GPIO5 \ + ESP32_PINMUX(5, ESP_PWM1_CAP0_IN, ESP_NOSIG) + +#define MCPWM1_CAP0_GPIO6 \ + ESP32_PINMUX(6, ESP_PWM1_CAP0_IN, ESP_NOSIG) + +#define MCPWM1_CAP0_GPIO7 \ + ESP32_PINMUX(7, ESP_PWM1_CAP0_IN, ESP_NOSIG) + +#define MCPWM1_CAP0_GPIO8 \ + ESP32_PINMUX(8, ESP_PWM1_CAP0_IN, ESP_NOSIG) + +#define MCPWM1_CAP0_GPIO9 \ + ESP32_PINMUX(9, ESP_PWM1_CAP0_IN, ESP_NOSIG) + +#define MCPWM1_CAP0_GPIO10 \ + ESP32_PINMUX(10, ESP_PWM1_CAP0_IN, ESP_NOSIG) + +#define MCPWM1_CAP0_GPIO11 \ + ESP32_PINMUX(11, ESP_PWM1_CAP0_IN, ESP_NOSIG) + +#define MCPWM1_CAP0_GPIO12 \ + ESP32_PINMUX(12, ESP_PWM1_CAP0_IN, ESP_NOSIG) + +#define MCPWM1_CAP0_GPIO13 \ + ESP32_PINMUX(13, ESP_PWM1_CAP0_IN, ESP_NOSIG) + +#define MCPWM1_CAP0_GPIO14 \ + ESP32_PINMUX(14, ESP_PWM1_CAP0_IN, ESP_NOSIG) + +#define MCPWM1_CAP0_GPIO15 \ + ESP32_PINMUX(15, ESP_PWM1_CAP0_IN, ESP_NOSIG) + +#define MCPWM1_CAP0_GPIO16 \ + ESP32_PINMUX(16, ESP_PWM1_CAP0_IN, ESP_NOSIG) + +#define MCPWM1_CAP0_GPIO17 \ + ESP32_PINMUX(17, ESP_PWM1_CAP0_IN, ESP_NOSIG) + +#define MCPWM1_CAP0_GPIO18 \ + ESP32_PINMUX(18, ESP_PWM1_CAP0_IN, ESP_NOSIG) + +#define MCPWM1_CAP0_GPIO19 \ + ESP32_PINMUX(19, ESP_PWM1_CAP0_IN, ESP_NOSIG) + +#define MCPWM1_CAP0_GPIO20 \ + ESP32_PINMUX(20, ESP_PWM1_CAP0_IN, ESP_NOSIG) + +#define MCPWM1_CAP0_GPIO21 \ + ESP32_PINMUX(21, ESP_PWM1_CAP0_IN, ESP_NOSIG) + +#define MCPWM1_CAP0_GPIO26 \ + ESP32_PINMUX(26, ESP_PWM1_CAP0_IN, ESP_NOSIG) + +#define MCPWM1_CAP0_GPIO27 \ + ESP32_PINMUX(27, ESP_PWM1_CAP0_IN, ESP_NOSIG) + +#define MCPWM1_CAP0_GPIO28 \ + ESP32_PINMUX(28, ESP_PWM1_CAP0_IN, ESP_NOSIG) + +#define MCPWM1_CAP0_GPIO29 \ + ESP32_PINMUX(29, ESP_PWM1_CAP0_IN, ESP_NOSIG) + +#define MCPWM1_CAP0_GPIO30 \ + ESP32_PINMUX(30, ESP_PWM1_CAP0_IN, ESP_NOSIG) + +#define MCPWM1_CAP0_GPIO31 \ + ESP32_PINMUX(31, ESP_PWM1_CAP0_IN, ESP_NOSIG) + +#define MCPWM1_CAP0_GPIO32 \ + ESP32_PINMUX(32, ESP_PWM1_CAP0_IN, ESP_NOSIG) + +#define MCPWM1_CAP0_GPIO33 \ + ESP32_PINMUX(33, ESP_PWM1_CAP0_IN, ESP_NOSIG) + +#define MCPWM1_CAP0_GPIO34 \ + ESP32_PINMUX(34, ESP_PWM1_CAP0_IN, ESP_NOSIG) + +#define MCPWM1_CAP0_GPIO35 \ + ESP32_PINMUX(35, ESP_PWM1_CAP0_IN, ESP_NOSIG) + +#define MCPWM1_CAP0_GPIO36 \ + ESP32_PINMUX(36, ESP_PWM1_CAP0_IN, ESP_NOSIG) + +#define MCPWM1_CAP0_GPIO37 \ + ESP32_PINMUX(37, ESP_PWM1_CAP0_IN, ESP_NOSIG) + +#define MCPWM1_CAP0_GPIO38 \ + ESP32_PINMUX(38, ESP_PWM1_CAP0_IN, ESP_NOSIG) + +#define MCPWM1_CAP0_GPIO39 \ + ESP32_PINMUX(39, ESP_PWM1_CAP0_IN, ESP_NOSIG) + +#define MCPWM1_CAP0_GPIO40 \ + ESP32_PINMUX(40, ESP_PWM1_CAP0_IN, ESP_NOSIG) + +#define MCPWM1_CAP0_GPIO41 \ + ESP32_PINMUX(41, ESP_PWM1_CAP0_IN, ESP_NOSIG) + +#define MCPWM1_CAP0_GPIO42 \ + ESP32_PINMUX(42, ESP_PWM1_CAP0_IN, ESP_NOSIG) + +#define MCPWM1_CAP0_GPIO43 \ + ESP32_PINMUX(43, ESP_PWM1_CAP0_IN, ESP_NOSIG) + +#define MCPWM1_CAP0_GPIO44 \ + ESP32_PINMUX(44, ESP_PWM1_CAP0_IN, ESP_NOSIG) + +#define MCPWM1_CAP0_GPIO45 \ + ESP32_PINMUX(45, ESP_PWM1_CAP0_IN, ESP_NOSIG) + +#define MCPWM1_CAP0_GPIO46 \ + ESP32_PINMUX(46, ESP_PWM1_CAP0_IN, ESP_NOSIG) + +#define MCPWM1_CAP0_GPIO47 \ + ESP32_PINMUX(47, ESP_PWM1_CAP0_IN, ESP_NOSIG) + +#define MCPWM1_CAP0_GPIO48 \ + ESP32_PINMUX(48, ESP_PWM1_CAP0_IN, ESP_NOSIG) + +/* MCPWM1_CAP1 */ +#define MCPWM1_CAP1_GPIO0 \ + ESP32_PINMUX(0, ESP_PWM1_CAP1_IN, ESP_NOSIG) + +#define MCPWM1_CAP1_GPIO1 \ + ESP32_PINMUX(1, ESP_PWM1_CAP1_IN, ESP_NOSIG) + +#define MCPWM1_CAP1_GPIO2 \ + ESP32_PINMUX(2, ESP_PWM1_CAP1_IN, ESP_NOSIG) + +#define MCPWM1_CAP1_GPIO3 \ + ESP32_PINMUX(3, ESP_PWM1_CAP1_IN, ESP_NOSIG) + +#define MCPWM1_CAP1_GPIO4 \ + ESP32_PINMUX(4, ESP_PWM1_CAP1_IN, ESP_NOSIG) + +#define MCPWM1_CAP1_GPIO5 \ + ESP32_PINMUX(5, ESP_PWM1_CAP1_IN, ESP_NOSIG) + +#define MCPWM1_CAP1_GPIO6 \ + ESP32_PINMUX(6, ESP_PWM1_CAP1_IN, ESP_NOSIG) + +#define MCPWM1_CAP1_GPIO7 \ + ESP32_PINMUX(7, ESP_PWM1_CAP1_IN, ESP_NOSIG) + +#define MCPWM1_CAP1_GPIO8 \ + ESP32_PINMUX(8, ESP_PWM1_CAP1_IN, ESP_NOSIG) + +#define MCPWM1_CAP1_GPIO9 \ + ESP32_PINMUX(9, ESP_PWM1_CAP1_IN, ESP_NOSIG) + +#define MCPWM1_CAP1_GPIO10 \ + ESP32_PINMUX(10, ESP_PWM1_CAP1_IN, ESP_NOSIG) + +#define MCPWM1_CAP1_GPIO11 \ + ESP32_PINMUX(11, ESP_PWM1_CAP1_IN, ESP_NOSIG) + +#define MCPWM1_CAP1_GPIO12 \ + ESP32_PINMUX(12, ESP_PWM1_CAP1_IN, ESP_NOSIG) + +#define MCPWM1_CAP1_GPIO13 \ + ESP32_PINMUX(13, ESP_PWM1_CAP1_IN, ESP_NOSIG) + +#define MCPWM1_CAP1_GPIO14 \ + ESP32_PINMUX(14, ESP_PWM1_CAP1_IN, ESP_NOSIG) + +#define MCPWM1_CAP1_GPIO15 \ + ESP32_PINMUX(15, ESP_PWM1_CAP1_IN, ESP_NOSIG) + +#define MCPWM1_CAP1_GPIO16 \ + ESP32_PINMUX(16, ESP_PWM1_CAP1_IN, ESP_NOSIG) + +#define MCPWM1_CAP1_GPIO17 \ + ESP32_PINMUX(17, ESP_PWM1_CAP1_IN, ESP_NOSIG) + +#define MCPWM1_CAP1_GPIO18 \ + ESP32_PINMUX(18, ESP_PWM1_CAP1_IN, ESP_NOSIG) + +#define MCPWM1_CAP1_GPIO19 \ + ESP32_PINMUX(19, ESP_PWM1_CAP1_IN, ESP_NOSIG) + +#define MCPWM1_CAP1_GPIO20 \ + ESP32_PINMUX(20, ESP_PWM1_CAP1_IN, ESP_NOSIG) + +#define MCPWM1_CAP1_GPIO21 \ + ESP32_PINMUX(21, ESP_PWM1_CAP1_IN, ESP_NOSIG) + +#define MCPWM1_CAP1_GPIO26 \ + ESP32_PINMUX(26, ESP_PWM1_CAP1_IN, ESP_NOSIG) + +#define MCPWM1_CAP1_GPIO27 \ + ESP32_PINMUX(27, ESP_PWM1_CAP1_IN, ESP_NOSIG) + +#define MCPWM1_CAP1_GPIO28 \ + ESP32_PINMUX(28, ESP_PWM1_CAP1_IN, ESP_NOSIG) + +#define MCPWM1_CAP1_GPIO29 \ + ESP32_PINMUX(29, ESP_PWM1_CAP1_IN, ESP_NOSIG) + +#define MCPWM1_CAP1_GPIO30 \ + ESP32_PINMUX(30, ESP_PWM1_CAP1_IN, ESP_NOSIG) + +#define MCPWM1_CAP1_GPIO31 \ + ESP32_PINMUX(31, ESP_PWM1_CAP1_IN, ESP_NOSIG) + +#define MCPWM1_CAP1_GPIO32 \ + ESP32_PINMUX(32, ESP_PWM1_CAP1_IN, ESP_NOSIG) + +#define MCPWM1_CAP1_GPIO33 \ + ESP32_PINMUX(33, ESP_PWM1_CAP1_IN, ESP_NOSIG) + +#define MCPWM1_CAP1_GPIO34 \ + ESP32_PINMUX(34, ESP_PWM1_CAP1_IN, ESP_NOSIG) + +#define MCPWM1_CAP1_GPIO35 \ + ESP32_PINMUX(35, ESP_PWM1_CAP1_IN, ESP_NOSIG) + +#define MCPWM1_CAP1_GPIO36 \ + ESP32_PINMUX(36, ESP_PWM1_CAP1_IN, ESP_NOSIG) + +#define MCPWM1_CAP1_GPIO37 \ + ESP32_PINMUX(37, ESP_PWM1_CAP1_IN, ESP_NOSIG) + +#define MCPWM1_CAP1_GPIO38 \ + ESP32_PINMUX(38, ESP_PWM1_CAP1_IN, ESP_NOSIG) + +#define MCPWM1_CAP1_GPIO39 \ + ESP32_PINMUX(39, ESP_PWM1_CAP1_IN, ESP_NOSIG) + +#define MCPWM1_CAP1_GPIO40 \ + ESP32_PINMUX(40, ESP_PWM1_CAP1_IN, ESP_NOSIG) + +#define MCPWM1_CAP1_GPIO41 \ + ESP32_PINMUX(41, ESP_PWM1_CAP1_IN, ESP_NOSIG) + +#define MCPWM1_CAP1_GPIO42 \ + ESP32_PINMUX(42, ESP_PWM1_CAP1_IN, ESP_NOSIG) + +#define MCPWM1_CAP1_GPIO43 \ + ESP32_PINMUX(43, ESP_PWM1_CAP1_IN, ESP_NOSIG) + +#define MCPWM1_CAP1_GPIO44 \ + ESP32_PINMUX(44, ESP_PWM1_CAP1_IN, ESP_NOSIG) + +#define MCPWM1_CAP1_GPIO45 \ + ESP32_PINMUX(45, ESP_PWM1_CAP1_IN, ESP_NOSIG) + +#define MCPWM1_CAP1_GPIO46 \ + ESP32_PINMUX(46, ESP_PWM1_CAP1_IN, ESP_NOSIG) + +#define MCPWM1_CAP1_GPIO47 \ + ESP32_PINMUX(47, ESP_PWM1_CAP1_IN, ESP_NOSIG) + +#define MCPWM1_CAP1_GPIO48 \ + ESP32_PINMUX(48, ESP_PWM1_CAP1_IN, ESP_NOSIG) + +/* MCPWM1_CAP2 */ +#define MCPWM1_CAP2_GPIO0 \ + ESP32_PINMUX(0, ESP_PWM1_CAP2_IN, ESP_NOSIG) + +#define MCPWM1_CAP2_GPIO1 \ + ESP32_PINMUX(1, ESP_PWM1_CAP2_IN, ESP_NOSIG) + +#define MCPWM1_CAP2_GPIO2 \ + ESP32_PINMUX(2, ESP_PWM1_CAP2_IN, ESP_NOSIG) + +#define MCPWM1_CAP2_GPIO3 \ + ESP32_PINMUX(3, ESP_PWM1_CAP2_IN, ESP_NOSIG) + +#define MCPWM1_CAP2_GPIO4 \ + ESP32_PINMUX(4, ESP_PWM1_CAP2_IN, ESP_NOSIG) + +#define MCPWM1_CAP2_GPIO5 \ + ESP32_PINMUX(5, ESP_PWM1_CAP2_IN, ESP_NOSIG) + +#define MCPWM1_CAP2_GPIO6 \ + ESP32_PINMUX(6, ESP_PWM1_CAP2_IN, ESP_NOSIG) + +#define MCPWM1_CAP2_GPIO7 \ + ESP32_PINMUX(7, ESP_PWM1_CAP2_IN, ESP_NOSIG) + +#define MCPWM1_CAP2_GPIO8 \ + ESP32_PINMUX(8, ESP_PWM1_CAP2_IN, ESP_NOSIG) + +#define MCPWM1_CAP2_GPIO9 \ + ESP32_PINMUX(9, ESP_PWM1_CAP2_IN, ESP_NOSIG) + +#define MCPWM1_CAP2_GPIO10 \ + ESP32_PINMUX(10, ESP_PWM1_CAP2_IN, ESP_NOSIG) + +#define MCPWM1_CAP2_GPIO11 \ + ESP32_PINMUX(11, ESP_PWM1_CAP2_IN, ESP_NOSIG) + +#define MCPWM1_CAP2_GPIO12 \ + ESP32_PINMUX(12, ESP_PWM1_CAP2_IN, ESP_NOSIG) + +#define MCPWM1_CAP2_GPIO13 \ + ESP32_PINMUX(13, ESP_PWM1_CAP2_IN, ESP_NOSIG) + +#define MCPWM1_CAP2_GPIO14 \ + ESP32_PINMUX(14, ESP_PWM1_CAP2_IN, ESP_NOSIG) + +#define MCPWM1_CAP2_GPIO15 \ + ESP32_PINMUX(15, ESP_PWM1_CAP2_IN, ESP_NOSIG) + +#define MCPWM1_CAP2_GPIO16 \ + ESP32_PINMUX(16, ESP_PWM1_CAP2_IN, ESP_NOSIG) + +#define MCPWM1_CAP2_GPIO17 \ + ESP32_PINMUX(17, ESP_PWM1_CAP2_IN, ESP_NOSIG) + +#define MCPWM1_CAP2_GPIO18 \ + ESP32_PINMUX(18, ESP_PWM1_CAP2_IN, ESP_NOSIG) + +#define MCPWM1_CAP2_GPIO19 \ + ESP32_PINMUX(19, ESP_PWM1_CAP2_IN, ESP_NOSIG) + +#define MCPWM1_CAP2_GPIO20 \ + ESP32_PINMUX(20, ESP_PWM1_CAP2_IN, ESP_NOSIG) + +#define MCPWM1_CAP2_GPIO21 \ + ESP32_PINMUX(21, ESP_PWM1_CAP2_IN, ESP_NOSIG) + +#define MCPWM1_CAP2_GPIO26 \ + ESP32_PINMUX(26, ESP_PWM1_CAP2_IN, ESP_NOSIG) + +#define MCPWM1_CAP2_GPIO27 \ + ESP32_PINMUX(27, ESP_PWM1_CAP2_IN, ESP_NOSIG) + +#define MCPWM1_CAP2_GPIO28 \ + ESP32_PINMUX(28, ESP_PWM1_CAP2_IN, ESP_NOSIG) + +#define MCPWM1_CAP2_GPIO29 \ + ESP32_PINMUX(29, ESP_PWM1_CAP2_IN, ESP_NOSIG) + +#define MCPWM1_CAP2_GPIO30 \ + ESP32_PINMUX(30, ESP_PWM1_CAP2_IN, ESP_NOSIG) + +#define MCPWM1_CAP2_GPIO31 \ + ESP32_PINMUX(31, ESP_PWM1_CAP2_IN, ESP_NOSIG) + +#define MCPWM1_CAP2_GPIO32 \ + ESP32_PINMUX(32, ESP_PWM1_CAP2_IN, ESP_NOSIG) + +#define MCPWM1_CAP2_GPIO33 \ + ESP32_PINMUX(33, ESP_PWM1_CAP2_IN, ESP_NOSIG) + +#define MCPWM1_CAP2_GPIO34 \ + ESP32_PINMUX(34, ESP_PWM1_CAP2_IN, ESP_NOSIG) + +#define MCPWM1_CAP2_GPIO35 \ + ESP32_PINMUX(35, ESP_PWM1_CAP2_IN, ESP_NOSIG) + +#define MCPWM1_CAP2_GPIO36 \ + ESP32_PINMUX(36, ESP_PWM1_CAP2_IN, ESP_NOSIG) + +#define MCPWM1_CAP2_GPIO37 \ + ESP32_PINMUX(37, ESP_PWM1_CAP2_IN, ESP_NOSIG) + +#define MCPWM1_CAP2_GPIO38 \ + ESP32_PINMUX(38, ESP_PWM1_CAP2_IN, ESP_NOSIG) + +#define MCPWM1_CAP2_GPIO39 \ + ESP32_PINMUX(39, ESP_PWM1_CAP2_IN, ESP_NOSIG) + +#define MCPWM1_CAP2_GPIO40 \ + ESP32_PINMUX(40, ESP_PWM1_CAP2_IN, ESP_NOSIG) + +#define MCPWM1_CAP2_GPIO41 \ + ESP32_PINMUX(41, ESP_PWM1_CAP2_IN, ESP_NOSIG) + +#define MCPWM1_CAP2_GPIO42 \ + ESP32_PINMUX(42, ESP_PWM1_CAP2_IN, ESP_NOSIG) + +#define MCPWM1_CAP2_GPIO43 \ + ESP32_PINMUX(43, ESP_PWM1_CAP2_IN, ESP_NOSIG) + +#define MCPWM1_CAP2_GPIO44 \ + ESP32_PINMUX(44, ESP_PWM1_CAP2_IN, ESP_NOSIG) + +#define MCPWM1_CAP2_GPIO45 \ + ESP32_PINMUX(45, ESP_PWM1_CAP2_IN, ESP_NOSIG) + +#define MCPWM1_CAP2_GPIO46 \ + ESP32_PINMUX(46, ESP_PWM1_CAP2_IN, ESP_NOSIG) + +#define MCPWM1_CAP2_GPIO47 \ + ESP32_PINMUX(47, ESP_PWM1_CAP2_IN, ESP_NOSIG) + +#define MCPWM1_CAP2_GPIO48 \ + ESP32_PINMUX(48, ESP_PWM1_CAP2_IN, ESP_NOSIG) + +/* MCPWM1_FAULT0 */ +#define MCPWM1_FAULT0_GPIO0 \ + ESP32_PINMUX(0, ESP_PWM1_F0_IN, ESP_NOSIG) + +#define MCPWM1_FAULT0_GPIO1 \ + ESP32_PINMUX(1, ESP_PWM1_F0_IN, ESP_NOSIG) + +#define MCPWM1_FAULT0_GPIO2 \ + ESP32_PINMUX(2, ESP_PWM1_F0_IN, ESP_NOSIG) + +#define MCPWM1_FAULT0_GPIO3 \ + ESP32_PINMUX(3, ESP_PWM1_F0_IN, ESP_NOSIG) + +#define MCPWM1_FAULT0_GPIO4 \ + ESP32_PINMUX(4, ESP_PWM1_F0_IN, ESP_NOSIG) + +#define MCPWM1_FAULT0_GPIO5 \ + ESP32_PINMUX(5, ESP_PWM1_F0_IN, ESP_NOSIG) + +#define MCPWM1_FAULT0_GPIO6 \ + ESP32_PINMUX(6, ESP_PWM1_F0_IN, ESP_NOSIG) + +#define MCPWM1_FAULT0_GPIO7 \ + ESP32_PINMUX(7, ESP_PWM1_F0_IN, ESP_NOSIG) + +#define MCPWM1_FAULT0_GPIO8 \ + ESP32_PINMUX(8, ESP_PWM1_F0_IN, ESP_NOSIG) + +#define MCPWM1_FAULT0_GPIO9 \ + ESP32_PINMUX(9, ESP_PWM1_F0_IN, ESP_NOSIG) + +#define MCPWM1_FAULT0_GPIO10 \ + ESP32_PINMUX(10, ESP_PWM1_F0_IN, ESP_NOSIG) + +#define MCPWM1_FAULT0_GPIO11 \ + ESP32_PINMUX(11, ESP_PWM1_F0_IN, ESP_NOSIG) + +#define MCPWM1_FAULT0_GPIO12 \ + ESP32_PINMUX(12, ESP_PWM1_F0_IN, ESP_NOSIG) + +#define MCPWM1_FAULT0_GPIO13 \ + ESP32_PINMUX(13, ESP_PWM1_F0_IN, ESP_NOSIG) + +#define MCPWM1_FAULT0_GPIO14 \ + ESP32_PINMUX(14, ESP_PWM1_F0_IN, ESP_NOSIG) + +#define MCPWM1_FAULT0_GPIO15 \ + ESP32_PINMUX(15, ESP_PWM1_F0_IN, ESP_NOSIG) + +#define MCPWM1_FAULT0_GPIO16 \ + ESP32_PINMUX(16, ESP_PWM1_F0_IN, ESP_NOSIG) + +#define MCPWM1_FAULT0_GPIO17 \ + ESP32_PINMUX(17, ESP_PWM1_F0_IN, ESP_NOSIG) + +#define MCPWM1_FAULT0_GPIO18 \ + ESP32_PINMUX(18, ESP_PWM1_F0_IN, ESP_NOSIG) + +#define MCPWM1_FAULT0_GPIO19 \ + ESP32_PINMUX(19, ESP_PWM1_F0_IN, ESP_NOSIG) + +#define MCPWM1_FAULT0_GPIO20 \ + ESP32_PINMUX(20, ESP_PWM1_F0_IN, ESP_NOSIG) + +#define MCPWM1_FAULT0_GPIO21 \ + ESP32_PINMUX(21, ESP_PWM1_F0_IN, ESP_NOSIG) + +#define MCPWM1_FAULT0_GPIO26 \ + ESP32_PINMUX(26, ESP_PWM1_F0_IN, ESP_NOSIG) + +#define MCPWM1_FAULT0_GPIO27 \ + ESP32_PINMUX(27, ESP_PWM1_F0_IN, ESP_NOSIG) + +#define MCPWM1_FAULT0_GPIO28 \ + ESP32_PINMUX(28, ESP_PWM1_F0_IN, ESP_NOSIG) + +#define MCPWM1_FAULT0_GPIO29 \ + ESP32_PINMUX(29, ESP_PWM1_F0_IN, ESP_NOSIG) + +#define MCPWM1_FAULT0_GPIO30 \ + ESP32_PINMUX(30, ESP_PWM1_F0_IN, ESP_NOSIG) + +#define MCPWM1_FAULT0_GPIO31 \ + ESP32_PINMUX(31, ESP_PWM1_F0_IN, ESP_NOSIG) + +#define MCPWM1_FAULT0_GPIO32 \ + ESP32_PINMUX(32, ESP_PWM1_F0_IN, ESP_NOSIG) + +#define MCPWM1_FAULT0_GPIO33 \ + ESP32_PINMUX(33, ESP_PWM1_F0_IN, ESP_NOSIG) + +#define MCPWM1_FAULT0_GPIO34 \ + ESP32_PINMUX(34, ESP_PWM1_F0_IN, ESP_NOSIG) + +#define MCPWM1_FAULT0_GPIO35 \ + ESP32_PINMUX(35, ESP_PWM1_F0_IN, ESP_NOSIG) + +#define MCPWM1_FAULT0_GPIO36 \ + ESP32_PINMUX(36, ESP_PWM1_F0_IN, ESP_NOSIG) + +#define MCPWM1_FAULT0_GPIO37 \ + ESP32_PINMUX(37, ESP_PWM1_F0_IN, ESP_NOSIG) + +#define MCPWM1_FAULT0_GPIO38 \ + ESP32_PINMUX(38, ESP_PWM1_F0_IN, ESP_NOSIG) + +#define MCPWM1_FAULT0_GPIO39 \ + ESP32_PINMUX(39, ESP_PWM1_F0_IN, ESP_NOSIG) + +#define MCPWM1_FAULT0_GPIO40 \ + ESP32_PINMUX(40, ESP_PWM1_F0_IN, ESP_NOSIG) + +#define MCPWM1_FAULT0_GPIO41 \ + ESP32_PINMUX(41, ESP_PWM1_F0_IN, ESP_NOSIG) + +#define MCPWM1_FAULT0_GPIO42 \ + ESP32_PINMUX(42, ESP_PWM1_F0_IN, ESP_NOSIG) + +#define MCPWM1_FAULT0_GPIO43 \ + ESP32_PINMUX(43, ESP_PWM1_F0_IN, ESP_NOSIG) + +#define MCPWM1_FAULT0_GPIO44 \ + ESP32_PINMUX(44, ESP_PWM1_F0_IN, ESP_NOSIG) + +#define MCPWM1_FAULT0_GPIO45 \ + ESP32_PINMUX(45, ESP_PWM1_F0_IN, ESP_NOSIG) + +#define MCPWM1_FAULT0_GPIO46 \ + ESP32_PINMUX(46, ESP_PWM1_F0_IN, ESP_NOSIG) + +#define MCPWM1_FAULT0_GPIO47 \ + ESP32_PINMUX(47, ESP_PWM1_F0_IN, ESP_NOSIG) + +#define MCPWM1_FAULT0_GPIO48 \ + ESP32_PINMUX(48, ESP_PWM1_F0_IN, ESP_NOSIG) + +/* MCPWM1_FAULT1 */ +#define MCPWM1_FAULT1_GPIO0 \ + ESP32_PINMUX(0, ESP_PWM1_F1_IN, ESP_NOSIG) + +#define MCPWM1_FAULT1_GPIO1 \ + ESP32_PINMUX(1, ESP_PWM1_F1_IN, ESP_NOSIG) + +#define MCPWM1_FAULT1_GPIO2 \ + ESP32_PINMUX(2, ESP_PWM1_F1_IN, ESP_NOSIG) + +#define MCPWM1_FAULT1_GPIO3 \ + ESP32_PINMUX(3, ESP_PWM1_F1_IN, ESP_NOSIG) + +#define MCPWM1_FAULT1_GPIO4 \ + ESP32_PINMUX(4, ESP_PWM1_F1_IN, ESP_NOSIG) + +#define MCPWM1_FAULT1_GPIO5 \ + ESP32_PINMUX(5, ESP_PWM1_F1_IN, ESP_NOSIG) + +#define MCPWM1_FAULT1_GPIO6 \ + ESP32_PINMUX(6, ESP_PWM1_F1_IN, ESP_NOSIG) + +#define MCPWM1_FAULT1_GPIO7 \ + ESP32_PINMUX(7, ESP_PWM1_F1_IN, ESP_NOSIG) + +#define MCPWM1_FAULT1_GPIO8 \ + ESP32_PINMUX(8, ESP_PWM1_F1_IN, ESP_NOSIG) + +#define MCPWM1_FAULT1_GPIO9 \ + ESP32_PINMUX(9, ESP_PWM1_F1_IN, ESP_NOSIG) + +#define MCPWM1_FAULT1_GPIO10 \ + ESP32_PINMUX(10, ESP_PWM1_F1_IN, ESP_NOSIG) + +#define MCPWM1_FAULT1_GPIO11 \ + ESP32_PINMUX(11, ESP_PWM1_F1_IN, ESP_NOSIG) + +#define MCPWM1_FAULT1_GPIO12 \ + ESP32_PINMUX(12, ESP_PWM1_F1_IN, ESP_NOSIG) + +#define MCPWM1_FAULT1_GPIO13 \ + ESP32_PINMUX(13, ESP_PWM1_F1_IN, ESP_NOSIG) + +#define MCPWM1_FAULT1_GPIO14 \ + ESP32_PINMUX(14, ESP_PWM1_F1_IN, ESP_NOSIG) + +#define MCPWM1_FAULT1_GPIO15 \ + ESP32_PINMUX(15, ESP_PWM1_F1_IN, ESP_NOSIG) + +#define MCPWM1_FAULT1_GPIO16 \ + ESP32_PINMUX(16, ESP_PWM1_F1_IN, ESP_NOSIG) + +#define MCPWM1_FAULT1_GPIO17 \ + ESP32_PINMUX(17, ESP_PWM1_F1_IN, ESP_NOSIG) + +#define MCPWM1_FAULT1_GPIO18 \ + ESP32_PINMUX(18, ESP_PWM1_F1_IN, ESP_NOSIG) + +#define MCPWM1_FAULT1_GPIO19 \ + ESP32_PINMUX(19, ESP_PWM1_F1_IN, ESP_NOSIG) + +#define MCPWM1_FAULT1_GPIO20 \ + ESP32_PINMUX(20, ESP_PWM1_F1_IN, ESP_NOSIG) + +#define MCPWM1_FAULT1_GPIO21 \ + ESP32_PINMUX(21, ESP_PWM1_F1_IN, ESP_NOSIG) + +#define MCPWM1_FAULT1_GPIO26 \ + ESP32_PINMUX(26, ESP_PWM1_F1_IN, ESP_NOSIG) + +#define MCPWM1_FAULT1_GPIO27 \ + ESP32_PINMUX(27, ESP_PWM1_F1_IN, ESP_NOSIG) + +#define MCPWM1_FAULT1_GPIO28 \ + ESP32_PINMUX(28, ESP_PWM1_F1_IN, ESP_NOSIG) + +#define MCPWM1_FAULT1_GPIO29 \ + ESP32_PINMUX(29, ESP_PWM1_F1_IN, ESP_NOSIG) + +#define MCPWM1_FAULT1_GPIO30 \ + ESP32_PINMUX(30, ESP_PWM1_F1_IN, ESP_NOSIG) + +#define MCPWM1_FAULT1_GPIO31 \ + ESP32_PINMUX(31, ESP_PWM1_F1_IN, ESP_NOSIG) + +#define MCPWM1_FAULT1_GPIO32 \ + ESP32_PINMUX(32, ESP_PWM1_F1_IN, ESP_NOSIG) + +#define MCPWM1_FAULT1_GPIO33 \ + ESP32_PINMUX(33, ESP_PWM1_F1_IN, ESP_NOSIG) + +#define MCPWM1_FAULT1_GPIO34 \ + ESP32_PINMUX(34, ESP_PWM1_F1_IN, ESP_NOSIG) + +#define MCPWM1_FAULT1_GPIO35 \ + ESP32_PINMUX(35, ESP_PWM1_F1_IN, ESP_NOSIG) + +#define MCPWM1_FAULT1_GPIO36 \ + ESP32_PINMUX(36, ESP_PWM1_F1_IN, ESP_NOSIG) + +#define MCPWM1_FAULT1_GPIO37 \ + ESP32_PINMUX(37, ESP_PWM1_F1_IN, ESP_NOSIG) + +#define MCPWM1_FAULT1_GPIO38 \ + ESP32_PINMUX(38, ESP_PWM1_F1_IN, ESP_NOSIG) + +#define MCPWM1_FAULT1_GPIO39 \ + ESP32_PINMUX(39, ESP_PWM1_F1_IN, ESP_NOSIG) + +#define MCPWM1_FAULT1_GPIO40 \ + ESP32_PINMUX(40, ESP_PWM1_F1_IN, ESP_NOSIG) + +#define MCPWM1_FAULT1_GPIO41 \ + ESP32_PINMUX(41, ESP_PWM1_F1_IN, ESP_NOSIG) + +#define MCPWM1_FAULT1_GPIO42 \ + ESP32_PINMUX(42, ESP_PWM1_F1_IN, ESP_NOSIG) + +#define MCPWM1_FAULT1_GPIO43 \ + ESP32_PINMUX(43, ESP_PWM1_F1_IN, ESP_NOSIG) + +#define MCPWM1_FAULT1_GPIO44 \ + ESP32_PINMUX(44, ESP_PWM1_F1_IN, ESP_NOSIG) + +#define MCPWM1_FAULT1_GPIO45 \ + ESP32_PINMUX(45, ESP_PWM1_F1_IN, ESP_NOSIG) + +#define MCPWM1_FAULT1_GPIO46 \ + ESP32_PINMUX(46, ESP_PWM1_F1_IN, ESP_NOSIG) + +#define MCPWM1_FAULT1_GPIO47 \ + ESP32_PINMUX(47, ESP_PWM1_F1_IN, ESP_NOSIG) + +#define MCPWM1_FAULT1_GPIO48 \ + ESP32_PINMUX(48, ESP_PWM1_F1_IN, ESP_NOSIG) + +/* MCPWM1_FAULT2 */ +#define MCPWM1_FAULT2_GPIO0 \ + ESP32_PINMUX(0, ESP_PWM1_F2_IN, ESP_NOSIG) + +#define MCPWM1_FAULT2_GPIO1 \ + ESP32_PINMUX(1, ESP_PWM1_F2_IN, ESP_NOSIG) + +#define MCPWM1_FAULT2_GPIO2 \ + ESP32_PINMUX(2, ESP_PWM1_F2_IN, ESP_NOSIG) + +#define MCPWM1_FAULT2_GPIO3 \ + ESP32_PINMUX(3, ESP_PWM1_F2_IN, ESP_NOSIG) + +#define MCPWM1_FAULT2_GPIO4 \ + ESP32_PINMUX(4, ESP_PWM1_F2_IN, ESP_NOSIG) + +#define MCPWM1_FAULT2_GPIO5 \ + ESP32_PINMUX(5, ESP_PWM1_F2_IN, ESP_NOSIG) + +#define MCPWM1_FAULT2_GPIO6 \ + ESP32_PINMUX(6, ESP_PWM1_F2_IN, ESP_NOSIG) + +#define MCPWM1_FAULT2_GPIO7 \ + ESP32_PINMUX(7, ESP_PWM1_F2_IN, ESP_NOSIG) + +#define MCPWM1_FAULT2_GPIO8 \ + ESP32_PINMUX(8, ESP_PWM1_F2_IN, ESP_NOSIG) + +#define MCPWM1_FAULT2_GPIO9 \ + ESP32_PINMUX(9, ESP_PWM1_F2_IN, ESP_NOSIG) + +#define MCPWM1_FAULT2_GPIO10 \ + ESP32_PINMUX(10, ESP_PWM1_F2_IN, ESP_NOSIG) + +#define MCPWM1_FAULT2_GPIO11 \ + ESP32_PINMUX(11, ESP_PWM1_F2_IN, ESP_NOSIG) + +#define MCPWM1_FAULT2_GPIO12 \ + ESP32_PINMUX(12, ESP_PWM1_F2_IN, ESP_NOSIG) + +#define MCPWM1_FAULT2_GPIO13 \ + ESP32_PINMUX(13, ESP_PWM1_F2_IN, ESP_NOSIG) + +#define MCPWM1_FAULT2_GPIO14 \ + ESP32_PINMUX(14, ESP_PWM1_F2_IN, ESP_NOSIG) + +#define MCPWM1_FAULT2_GPIO15 \ + ESP32_PINMUX(15, ESP_PWM1_F2_IN, ESP_NOSIG) + +#define MCPWM1_FAULT2_GPIO16 \ + ESP32_PINMUX(16, ESP_PWM1_F2_IN, ESP_NOSIG) + +#define MCPWM1_FAULT2_GPIO17 \ + ESP32_PINMUX(17, ESP_PWM1_F2_IN, ESP_NOSIG) + +#define MCPWM1_FAULT2_GPIO18 \ + ESP32_PINMUX(18, ESP_PWM1_F2_IN, ESP_NOSIG) + +#define MCPWM1_FAULT2_GPIO19 \ + ESP32_PINMUX(19, ESP_PWM1_F2_IN, ESP_NOSIG) + +#define MCPWM1_FAULT2_GPIO20 \ + ESP32_PINMUX(20, ESP_PWM1_F2_IN, ESP_NOSIG) + +#define MCPWM1_FAULT2_GPIO21 \ + ESP32_PINMUX(21, ESP_PWM1_F2_IN, ESP_NOSIG) + +#define MCPWM1_FAULT2_GPIO26 \ + ESP32_PINMUX(26, ESP_PWM1_F2_IN, ESP_NOSIG) + +#define MCPWM1_FAULT2_GPIO27 \ + ESP32_PINMUX(27, ESP_PWM1_F2_IN, ESP_NOSIG) + +#define MCPWM1_FAULT2_GPIO28 \ + ESP32_PINMUX(28, ESP_PWM1_F2_IN, ESP_NOSIG) + +#define MCPWM1_FAULT2_GPIO29 \ + ESP32_PINMUX(29, ESP_PWM1_F2_IN, ESP_NOSIG) + +#define MCPWM1_FAULT2_GPIO30 \ + ESP32_PINMUX(30, ESP_PWM1_F2_IN, ESP_NOSIG) + +#define MCPWM1_FAULT2_GPIO31 \ + ESP32_PINMUX(31, ESP_PWM1_F2_IN, ESP_NOSIG) + +#define MCPWM1_FAULT2_GPIO32 \ + ESP32_PINMUX(32, ESP_PWM1_F2_IN, ESP_NOSIG) + +#define MCPWM1_FAULT2_GPIO33 \ + ESP32_PINMUX(33, ESP_PWM1_F2_IN, ESP_NOSIG) + +#define MCPWM1_FAULT2_GPIO34 \ + ESP32_PINMUX(34, ESP_PWM1_F2_IN, ESP_NOSIG) + +#define MCPWM1_FAULT2_GPIO35 \ + ESP32_PINMUX(35, ESP_PWM1_F2_IN, ESP_NOSIG) + +#define MCPWM1_FAULT2_GPIO36 \ + ESP32_PINMUX(36, ESP_PWM1_F2_IN, ESP_NOSIG) + +#define MCPWM1_FAULT2_GPIO37 \ + ESP32_PINMUX(37, ESP_PWM1_F2_IN, ESP_NOSIG) + +#define MCPWM1_FAULT2_GPIO38 \ + ESP32_PINMUX(38, ESP_PWM1_F2_IN, ESP_NOSIG) + +#define MCPWM1_FAULT2_GPIO39 \ + ESP32_PINMUX(39, ESP_PWM1_F2_IN, ESP_NOSIG) + +#define MCPWM1_FAULT2_GPIO40 \ + ESP32_PINMUX(40, ESP_PWM1_F2_IN, ESP_NOSIG) + +#define MCPWM1_FAULT2_GPIO41 \ + ESP32_PINMUX(41, ESP_PWM1_F2_IN, ESP_NOSIG) + +#define MCPWM1_FAULT2_GPIO42 \ + ESP32_PINMUX(42, ESP_PWM1_F2_IN, ESP_NOSIG) + +#define MCPWM1_FAULT2_GPIO43 \ + ESP32_PINMUX(43, ESP_PWM1_F2_IN, ESP_NOSIG) + +#define MCPWM1_FAULT2_GPIO44 \ + ESP32_PINMUX(44, ESP_PWM1_F2_IN, ESP_NOSIG) + +#define MCPWM1_FAULT2_GPIO45 \ + ESP32_PINMUX(45, ESP_PWM1_F2_IN, ESP_NOSIG) + +#define MCPWM1_FAULT2_GPIO46 \ + ESP32_PINMUX(46, ESP_PWM1_F2_IN, ESP_NOSIG) + +#define MCPWM1_FAULT2_GPIO47 \ + ESP32_PINMUX(47, ESP_PWM1_F2_IN, ESP_NOSIG) + +#define MCPWM1_FAULT2_GPIO48 \ + ESP32_PINMUX(48, ESP_PWM1_F2_IN, ESP_NOSIG) + +/* MCPWM1_OUT0A */ +#define MCPWM1_OUT0A_GPIO0 \ + ESP32_PINMUX(0, ESP_NOSIG, ESP_PWM1_OUT0A) + +#define MCPWM1_OUT0A_GPIO1 \ + ESP32_PINMUX(1, ESP_NOSIG, ESP_PWM1_OUT0A) + +#define MCPWM1_OUT0A_GPIO2 \ + ESP32_PINMUX(2, ESP_NOSIG, ESP_PWM1_OUT0A) + +#define MCPWM1_OUT0A_GPIO3 \ + ESP32_PINMUX(3, ESP_NOSIG, ESP_PWM1_OUT0A) + +#define MCPWM1_OUT0A_GPIO4 \ + ESP32_PINMUX(4, ESP_NOSIG, ESP_PWM1_OUT0A) + +#define MCPWM1_OUT0A_GPIO5 \ + ESP32_PINMUX(5, ESP_NOSIG, ESP_PWM1_OUT0A) + +#define MCPWM1_OUT0A_GPIO6 \ + ESP32_PINMUX(6, ESP_NOSIG, ESP_PWM1_OUT0A) + +#define MCPWM1_OUT0A_GPIO7 \ + ESP32_PINMUX(7, ESP_NOSIG, ESP_PWM1_OUT0A) + +#define MCPWM1_OUT0A_GPIO8 \ + ESP32_PINMUX(8, ESP_NOSIG, ESP_PWM1_OUT0A) + +#define MCPWM1_OUT0A_GPIO9 \ + ESP32_PINMUX(9, ESP_NOSIG, ESP_PWM1_OUT0A) + +#define MCPWM1_OUT0A_GPIO10 \ + ESP32_PINMUX(10, ESP_NOSIG, ESP_PWM1_OUT0A) + +#define MCPWM1_OUT0A_GPIO11 \ + ESP32_PINMUX(11, ESP_NOSIG, ESP_PWM1_OUT0A) + +#define MCPWM1_OUT0A_GPIO12 \ + ESP32_PINMUX(12, ESP_NOSIG, ESP_PWM1_OUT0A) + +#define MCPWM1_OUT0A_GPIO13 \ + ESP32_PINMUX(13, ESP_NOSIG, ESP_PWM1_OUT0A) + +#define MCPWM1_OUT0A_GPIO14 \ + ESP32_PINMUX(14, ESP_NOSIG, ESP_PWM1_OUT0A) + +#define MCPWM1_OUT0A_GPIO15 \ + ESP32_PINMUX(15, ESP_NOSIG, ESP_PWM1_OUT0A) + +#define MCPWM1_OUT0A_GPIO16 \ + ESP32_PINMUX(16, ESP_NOSIG, ESP_PWM1_OUT0A) + +#define MCPWM1_OUT0A_GPIO17 \ + ESP32_PINMUX(17, ESP_NOSIG, ESP_PWM1_OUT0A) + +#define MCPWM1_OUT0A_GPIO18 \ + ESP32_PINMUX(18, ESP_NOSIG, ESP_PWM1_OUT0A) + +#define MCPWM1_OUT0A_GPIO19 \ + ESP32_PINMUX(19, ESP_NOSIG, ESP_PWM1_OUT0A) + +#define MCPWM1_OUT0A_GPIO20 \ + ESP32_PINMUX(20, ESP_NOSIG, ESP_PWM1_OUT0A) + +#define MCPWM1_OUT0A_GPIO21 \ + ESP32_PINMUX(21, ESP_NOSIG, ESP_PWM1_OUT0A) + +#define MCPWM1_OUT0A_GPIO26 \ + ESP32_PINMUX(26, ESP_NOSIG, ESP_PWM1_OUT0A) + +#define MCPWM1_OUT0A_GPIO27 \ + ESP32_PINMUX(27, ESP_NOSIG, ESP_PWM1_OUT0A) + +#define MCPWM1_OUT0A_GPIO28 \ + ESP32_PINMUX(28, ESP_NOSIG, ESP_PWM1_OUT0A) + +#define MCPWM1_OUT0A_GPIO29 \ + ESP32_PINMUX(29, ESP_NOSIG, ESP_PWM1_OUT0A) + +#define MCPWM1_OUT0A_GPIO30 \ + ESP32_PINMUX(30, ESP_NOSIG, ESP_PWM1_OUT0A) + +#define MCPWM1_OUT0A_GPIO31 \ + ESP32_PINMUX(31, ESP_NOSIG, ESP_PWM1_OUT0A) + +#define MCPWM1_OUT0A_GPIO32 \ + ESP32_PINMUX(32, ESP_NOSIG, ESP_PWM1_OUT0A) + +#define MCPWM1_OUT0A_GPIO33 \ + ESP32_PINMUX(33, ESP_NOSIG, ESP_PWM1_OUT0A) + +#define MCPWM1_OUT0A_GPIO34 \ + ESP32_PINMUX(34, ESP_NOSIG, ESP_PWM1_OUT0A) + +#define MCPWM1_OUT0A_GPIO35 \ + ESP32_PINMUX(35, ESP_NOSIG, ESP_PWM1_OUT0A) + +#define MCPWM1_OUT0A_GPIO36 \ + ESP32_PINMUX(36, ESP_NOSIG, ESP_PWM1_OUT0A) + +#define MCPWM1_OUT0A_GPIO37 \ + ESP32_PINMUX(37, ESP_NOSIG, ESP_PWM1_OUT0A) + +#define MCPWM1_OUT0A_GPIO38 \ + ESP32_PINMUX(38, ESP_NOSIG, ESP_PWM1_OUT0A) + +#define MCPWM1_OUT0A_GPIO39 \ + ESP32_PINMUX(39, ESP_NOSIG, ESP_PWM1_OUT0A) + +#define MCPWM1_OUT0A_GPIO40 \ + ESP32_PINMUX(40, ESP_NOSIG, ESP_PWM1_OUT0A) + +#define MCPWM1_OUT0A_GPIO41 \ + ESP32_PINMUX(41, ESP_NOSIG, ESP_PWM1_OUT0A) + +#define MCPWM1_OUT0A_GPIO42 \ + ESP32_PINMUX(42, ESP_NOSIG, ESP_PWM1_OUT0A) + +#define MCPWM1_OUT0A_GPIO43 \ + ESP32_PINMUX(43, ESP_NOSIG, ESP_PWM1_OUT0A) + +#define MCPWM1_OUT0A_GPIO44 \ + ESP32_PINMUX(44, ESP_NOSIG, ESP_PWM1_OUT0A) + +#define MCPWM1_OUT0A_GPIO45 \ + ESP32_PINMUX(45, ESP_NOSIG, ESP_PWM1_OUT0A) + +#define MCPWM1_OUT0A_GPIO46 \ + ESP32_PINMUX(46, ESP_NOSIG, ESP_PWM1_OUT0A) + +#define MCPWM1_OUT0A_GPIO47 \ + ESP32_PINMUX(47, ESP_NOSIG, ESP_PWM1_OUT0A) + +#define MCPWM1_OUT0A_GPIO48 \ + ESP32_PINMUX(48, ESP_NOSIG, ESP_PWM1_OUT0A) + +/* MCPWM1_OUT0B */ +#define MCPWM1_OUT0B_GPIO0 \ + ESP32_PINMUX(0, ESP_NOSIG, ESP_PWM1_OUT0B) + +#define MCPWM1_OUT0B_GPIO1 \ + ESP32_PINMUX(1, ESP_NOSIG, ESP_PWM1_OUT0B) + +#define MCPWM1_OUT0B_GPIO2 \ + ESP32_PINMUX(2, ESP_NOSIG, ESP_PWM1_OUT0B) + +#define MCPWM1_OUT0B_GPIO3 \ + ESP32_PINMUX(3, ESP_NOSIG, ESP_PWM1_OUT0B) + +#define MCPWM1_OUT0B_GPIO4 \ + ESP32_PINMUX(4, ESP_NOSIG, ESP_PWM1_OUT0B) + +#define MCPWM1_OUT0B_GPIO5 \ + ESP32_PINMUX(5, ESP_NOSIG, ESP_PWM1_OUT0B) + +#define MCPWM1_OUT0B_GPIO6 \ + ESP32_PINMUX(6, ESP_NOSIG, ESP_PWM1_OUT0B) + +#define MCPWM1_OUT0B_GPIO7 \ + ESP32_PINMUX(7, ESP_NOSIG, ESP_PWM1_OUT0B) + +#define MCPWM1_OUT0B_GPIO8 \ + ESP32_PINMUX(8, ESP_NOSIG, ESP_PWM1_OUT0B) + +#define MCPWM1_OUT0B_GPIO9 \ + ESP32_PINMUX(9, ESP_NOSIG, ESP_PWM1_OUT0B) + +#define MCPWM1_OUT0B_GPIO10 \ + ESP32_PINMUX(10, ESP_NOSIG, ESP_PWM1_OUT0B) + +#define MCPWM1_OUT0B_GPIO11 \ + ESP32_PINMUX(11, ESP_NOSIG, ESP_PWM1_OUT0B) + +#define MCPWM1_OUT0B_GPIO12 \ + ESP32_PINMUX(12, ESP_NOSIG, ESP_PWM1_OUT0B) + +#define MCPWM1_OUT0B_GPIO13 \ + ESP32_PINMUX(13, ESP_NOSIG, ESP_PWM1_OUT0B) + +#define MCPWM1_OUT0B_GPIO14 \ + ESP32_PINMUX(14, ESP_NOSIG, ESP_PWM1_OUT0B) + +#define MCPWM1_OUT0B_GPIO15 \ + ESP32_PINMUX(15, ESP_NOSIG, ESP_PWM1_OUT0B) + +#define MCPWM1_OUT0B_GPIO16 \ + ESP32_PINMUX(16, ESP_NOSIG, ESP_PWM1_OUT0B) + +#define MCPWM1_OUT0B_GPIO17 \ + ESP32_PINMUX(17, ESP_NOSIG, ESP_PWM1_OUT0B) + +#define MCPWM1_OUT0B_GPIO18 \ + ESP32_PINMUX(18, ESP_NOSIG, ESP_PWM1_OUT0B) + +#define MCPWM1_OUT0B_GPIO19 \ + ESP32_PINMUX(19, ESP_NOSIG, ESP_PWM1_OUT0B) + +#define MCPWM1_OUT0B_GPIO20 \ + ESP32_PINMUX(20, ESP_NOSIG, ESP_PWM1_OUT0B) + +#define MCPWM1_OUT0B_GPIO21 \ + ESP32_PINMUX(21, ESP_NOSIG, ESP_PWM1_OUT0B) + +#define MCPWM1_OUT0B_GPIO26 \ + ESP32_PINMUX(26, ESP_NOSIG, ESP_PWM1_OUT0B) + +#define MCPWM1_OUT0B_GPIO27 \ + ESP32_PINMUX(27, ESP_NOSIG, ESP_PWM1_OUT0B) + +#define MCPWM1_OUT0B_GPIO28 \ + ESP32_PINMUX(28, ESP_NOSIG, ESP_PWM1_OUT0B) + +#define MCPWM1_OUT0B_GPIO29 \ + ESP32_PINMUX(29, ESP_NOSIG, ESP_PWM1_OUT0B) + +#define MCPWM1_OUT0B_GPIO30 \ + ESP32_PINMUX(30, ESP_NOSIG, ESP_PWM1_OUT0B) + +#define MCPWM1_OUT0B_GPIO31 \ + ESP32_PINMUX(31, ESP_NOSIG, ESP_PWM1_OUT0B) + +#define MCPWM1_OUT0B_GPIO32 \ + ESP32_PINMUX(32, ESP_NOSIG, ESP_PWM1_OUT0B) + +#define MCPWM1_OUT0B_GPIO33 \ + ESP32_PINMUX(33, ESP_NOSIG, ESP_PWM1_OUT0B) + +#define MCPWM1_OUT0B_GPIO34 \ + ESP32_PINMUX(34, ESP_NOSIG, ESP_PWM1_OUT0B) + +#define MCPWM1_OUT0B_GPIO35 \ + ESP32_PINMUX(35, ESP_NOSIG, ESP_PWM1_OUT0B) + +#define MCPWM1_OUT0B_GPIO36 \ + ESP32_PINMUX(36, ESP_NOSIG, ESP_PWM1_OUT0B) + +#define MCPWM1_OUT0B_GPIO37 \ + ESP32_PINMUX(37, ESP_NOSIG, ESP_PWM1_OUT0B) + +#define MCPWM1_OUT0B_GPIO38 \ + ESP32_PINMUX(38, ESP_NOSIG, ESP_PWM1_OUT0B) + +#define MCPWM1_OUT0B_GPIO39 \ + ESP32_PINMUX(39, ESP_NOSIG, ESP_PWM1_OUT0B) + +#define MCPWM1_OUT0B_GPIO40 \ + ESP32_PINMUX(40, ESP_NOSIG, ESP_PWM1_OUT0B) + +#define MCPWM1_OUT0B_GPIO41 \ + ESP32_PINMUX(41, ESP_NOSIG, ESP_PWM1_OUT0B) + +#define MCPWM1_OUT0B_GPIO42 \ + ESP32_PINMUX(42, ESP_NOSIG, ESP_PWM1_OUT0B) + +#define MCPWM1_OUT0B_GPIO43 \ + ESP32_PINMUX(43, ESP_NOSIG, ESP_PWM1_OUT0B) + +#define MCPWM1_OUT0B_GPIO44 \ + ESP32_PINMUX(44, ESP_NOSIG, ESP_PWM1_OUT0B) + +#define MCPWM1_OUT0B_GPIO45 \ + ESP32_PINMUX(45, ESP_NOSIG, ESP_PWM1_OUT0B) + +#define MCPWM1_OUT0B_GPIO46 \ + ESP32_PINMUX(46, ESP_NOSIG, ESP_PWM1_OUT0B) + +#define MCPWM1_OUT0B_GPIO47 \ + ESP32_PINMUX(47, ESP_NOSIG, ESP_PWM1_OUT0B) + +#define MCPWM1_OUT0B_GPIO48 \ + ESP32_PINMUX(48, ESP_NOSIG, ESP_PWM1_OUT0B) + +/* MCPWM1_OUT1A */ +#define MCPWM1_OUT1A_GPIO0 \ + ESP32_PINMUX(0, ESP_NOSIG, ESP_PWM1_OUT1A) + +#define MCPWM1_OUT1A_GPIO1 \ + ESP32_PINMUX(1, ESP_NOSIG, ESP_PWM1_OUT1A) + +#define MCPWM1_OUT1A_GPIO2 \ + ESP32_PINMUX(2, ESP_NOSIG, ESP_PWM1_OUT1A) + +#define MCPWM1_OUT1A_GPIO3 \ + ESP32_PINMUX(3, ESP_NOSIG, ESP_PWM1_OUT1A) + +#define MCPWM1_OUT1A_GPIO4 \ + ESP32_PINMUX(4, ESP_NOSIG, ESP_PWM1_OUT1A) + +#define MCPWM1_OUT1A_GPIO5 \ + ESP32_PINMUX(5, ESP_NOSIG, ESP_PWM1_OUT1A) + +#define MCPWM1_OUT1A_GPIO6 \ + ESP32_PINMUX(6, ESP_NOSIG, ESP_PWM1_OUT1A) + +#define MCPWM1_OUT1A_GPIO7 \ + ESP32_PINMUX(7, ESP_NOSIG, ESP_PWM1_OUT1A) + +#define MCPWM1_OUT1A_GPIO8 \ + ESP32_PINMUX(8, ESP_NOSIG, ESP_PWM1_OUT1A) + +#define MCPWM1_OUT1A_GPIO9 \ + ESP32_PINMUX(9, ESP_NOSIG, ESP_PWM1_OUT1A) + +#define MCPWM1_OUT1A_GPIO10 \ + ESP32_PINMUX(10, ESP_NOSIG, ESP_PWM1_OUT1A) + +#define MCPWM1_OUT1A_GPIO11 \ + ESP32_PINMUX(11, ESP_NOSIG, ESP_PWM1_OUT1A) + +#define MCPWM1_OUT1A_GPIO12 \ + ESP32_PINMUX(12, ESP_NOSIG, ESP_PWM1_OUT1A) + +#define MCPWM1_OUT1A_GPIO13 \ + ESP32_PINMUX(13, ESP_NOSIG, ESP_PWM1_OUT1A) + +#define MCPWM1_OUT1A_GPIO14 \ + ESP32_PINMUX(14, ESP_NOSIG, ESP_PWM1_OUT1A) + +#define MCPWM1_OUT1A_GPIO15 \ + ESP32_PINMUX(15, ESP_NOSIG, ESP_PWM1_OUT1A) + +#define MCPWM1_OUT1A_GPIO16 \ + ESP32_PINMUX(16, ESP_NOSIG, ESP_PWM1_OUT1A) + +#define MCPWM1_OUT1A_GPIO17 \ + ESP32_PINMUX(17, ESP_NOSIG, ESP_PWM1_OUT1A) + +#define MCPWM1_OUT1A_GPIO18 \ + ESP32_PINMUX(18, ESP_NOSIG, ESP_PWM1_OUT1A) + +#define MCPWM1_OUT1A_GPIO19 \ + ESP32_PINMUX(19, ESP_NOSIG, ESP_PWM1_OUT1A) + +#define MCPWM1_OUT1A_GPIO20 \ + ESP32_PINMUX(20, ESP_NOSIG, ESP_PWM1_OUT1A) + +#define MCPWM1_OUT1A_GPIO21 \ + ESP32_PINMUX(21, ESP_NOSIG, ESP_PWM1_OUT1A) + +#define MCPWM1_OUT1A_GPIO26 \ + ESP32_PINMUX(26, ESP_NOSIG, ESP_PWM1_OUT1A) + +#define MCPWM1_OUT1A_GPIO27 \ + ESP32_PINMUX(27, ESP_NOSIG, ESP_PWM1_OUT1A) + +#define MCPWM1_OUT1A_GPIO28 \ + ESP32_PINMUX(28, ESP_NOSIG, ESP_PWM1_OUT1A) + +#define MCPWM1_OUT1A_GPIO29 \ + ESP32_PINMUX(29, ESP_NOSIG, ESP_PWM1_OUT1A) + +#define MCPWM1_OUT1A_GPIO30 \ + ESP32_PINMUX(30, ESP_NOSIG, ESP_PWM1_OUT1A) + +#define MCPWM1_OUT1A_GPIO31 \ + ESP32_PINMUX(31, ESP_NOSIG, ESP_PWM1_OUT1A) + +#define MCPWM1_OUT1A_GPIO32 \ + ESP32_PINMUX(32, ESP_NOSIG, ESP_PWM1_OUT1A) + +#define MCPWM1_OUT1A_GPIO33 \ + ESP32_PINMUX(33, ESP_NOSIG, ESP_PWM1_OUT1A) + +#define MCPWM1_OUT1A_GPIO34 \ + ESP32_PINMUX(34, ESP_NOSIG, ESP_PWM1_OUT1A) + +#define MCPWM1_OUT1A_GPIO35 \ + ESP32_PINMUX(35, ESP_NOSIG, ESP_PWM1_OUT1A) + +#define MCPWM1_OUT1A_GPIO36 \ + ESP32_PINMUX(36, ESP_NOSIG, ESP_PWM1_OUT1A) + +#define MCPWM1_OUT1A_GPIO37 \ + ESP32_PINMUX(37, ESP_NOSIG, ESP_PWM1_OUT1A) + +#define MCPWM1_OUT1A_GPIO38 \ + ESP32_PINMUX(38, ESP_NOSIG, ESP_PWM1_OUT1A) + +#define MCPWM1_OUT1A_GPIO39 \ + ESP32_PINMUX(39, ESP_NOSIG, ESP_PWM1_OUT1A) + +#define MCPWM1_OUT1A_GPIO40 \ + ESP32_PINMUX(40, ESP_NOSIG, ESP_PWM1_OUT1A) + +#define MCPWM1_OUT1A_GPIO41 \ + ESP32_PINMUX(41, ESP_NOSIG, ESP_PWM1_OUT1A) + +#define MCPWM1_OUT1A_GPIO42 \ + ESP32_PINMUX(42, ESP_NOSIG, ESP_PWM1_OUT1A) + +#define MCPWM1_OUT1A_GPIO43 \ + ESP32_PINMUX(43, ESP_NOSIG, ESP_PWM1_OUT1A) + +#define MCPWM1_OUT1A_GPIO44 \ + ESP32_PINMUX(44, ESP_NOSIG, ESP_PWM1_OUT1A) + +#define MCPWM1_OUT1A_GPIO45 \ + ESP32_PINMUX(45, ESP_NOSIG, ESP_PWM1_OUT1A) + +#define MCPWM1_OUT1A_GPIO46 \ + ESP32_PINMUX(46, ESP_NOSIG, ESP_PWM1_OUT1A) + +#define MCPWM1_OUT1A_GPIO47 \ + ESP32_PINMUX(47, ESP_NOSIG, ESP_PWM1_OUT1A) + +#define MCPWM1_OUT1A_GPIO48 \ + ESP32_PINMUX(48, ESP_NOSIG, ESP_PWM1_OUT1A) + +/* MCPWM1_OUT1B */ +#define MCPWM1_OUT1B_GPIO0 \ + ESP32_PINMUX(0, ESP_NOSIG, ESP_PWM1_OUT1B) + +#define MCPWM1_OUT1B_GPIO1 \ + ESP32_PINMUX(1, ESP_NOSIG, ESP_PWM1_OUT1B) + +#define MCPWM1_OUT1B_GPIO2 \ + ESP32_PINMUX(2, ESP_NOSIG, ESP_PWM1_OUT1B) + +#define MCPWM1_OUT1B_GPIO3 \ + ESP32_PINMUX(3, ESP_NOSIG, ESP_PWM1_OUT1B) + +#define MCPWM1_OUT1B_GPIO4 \ + ESP32_PINMUX(4, ESP_NOSIG, ESP_PWM1_OUT1B) + +#define MCPWM1_OUT1B_GPIO5 \ + ESP32_PINMUX(5, ESP_NOSIG, ESP_PWM1_OUT1B) + +#define MCPWM1_OUT1B_GPIO6 \ + ESP32_PINMUX(6, ESP_NOSIG, ESP_PWM1_OUT1B) + +#define MCPWM1_OUT1B_GPIO7 \ + ESP32_PINMUX(7, ESP_NOSIG, ESP_PWM1_OUT1B) + +#define MCPWM1_OUT1B_GPIO8 \ + ESP32_PINMUX(8, ESP_NOSIG, ESP_PWM1_OUT1B) + +#define MCPWM1_OUT1B_GPIO9 \ + ESP32_PINMUX(9, ESP_NOSIG, ESP_PWM1_OUT1B) + +#define MCPWM1_OUT1B_GPIO10 \ + ESP32_PINMUX(10, ESP_NOSIG, ESP_PWM1_OUT1B) + +#define MCPWM1_OUT1B_GPIO11 \ + ESP32_PINMUX(11, ESP_NOSIG, ESP_PWM1_OUT1B) + +#define MCPWM1_OUT1B_GPIO12 \ + ESP32_PINMUX(12, ESP_NOSIG, ESP_PWM1_OUT1B) + +#define MCPWM1_OUT1B_GPIO13 \ + ESP32_PINMUX(13, ESP_NOSIG, ESP_PWM1_OUT1B) + +#define MCPWM1_OUT1B_GPIO14 \ + ESP32_PINMUX(14, ESP_NOSIG, ESP_PWM1_OUT1B) + +#define MCPWM1_OUT1B_GPIO15 \ + ESP32_PINMUX(15, ESP_NOSIG, ESP_PWM1_OUT1B) + +#define MCPWM1_OUT1B_GPIO16 \ + ESP32_PINMUX(16, ESP_NOSIG, ESP_PWM1_OUT1B) + +#define MCPWM1_OUT1B_GPIO17 \ + ESP32_PINMUX(17, ESP_NOSIG, ESP_PWM1_OUT1B) + +#define MCPWM1_OUT1B_GPIO18 \ + ESP32_PINMUX(18, ESP_NOSIG, ESP_PWM1_OUT1B) + +#define MCPWM1_OUT1B_GPIO19 \ + ESP32_PINMUX(19, ESP_NOSIG, ESP_PWM1_OUT1B) + +#define MCPWM1_OUT1B_GPIO20 \ + ESP32_PINMUX(20, ESP_NOSIG, ESP_PWM1_OUT1B) + +#define MCPWM1_OUT1B_GPIO21 \ + ESP32_PINMUX(21, ESP_NOSIG, ESP_PWM1_OUT1B) + +#define MCPWM1_OUT1B_GPIO26 \ + ESP32_PINMUX(26, ESP_NOSIG, ESP_PWM1_OUT1B) + +#define MCPWM1_OUT1B_GPIO27 \ + ESP32_PINMUX(27, ESP_NOSIG, ESP_PWM1_OUT1B) + +#define MCPWM1_OUT1B_GPIO28 \ + ESP32_PINMUX(28, ESP_NOSIG, ESP_PWM1_OUT1B) + +#define MCPWM1_OUT1B_GPIO29 \ + ESP32_PINMUX(29, ESP_NOSIG, ESP_PWM1_OUT1B) + +#define MCPWM1_OUT1B_GPIO30 \ + ESP32_PINMUX(30, ESP_NOSIG, ESP_PWM1_OUT1B) + +#define MCPWM1_OUT1B_GPIO31 \ + ESP32_PINMUX(31, ESP_NOSIG, ESP_PWM1_OUT1B) + +#define MCPWM1_OUT1B_GPIO32 \ + ESP32_PINMUX(32, ESP_NOSIG, ESP_PWM1_OUT1B) + +#define MCPWM1_OUT1B_GPIO33 \ + ESP32_PINMUX(33, ESP_NOSIG, ESP_PWM1_OUT1B) + +#define MCPWM1_OUT1B_GPIO34 \ + ESP32_PINMUX(34, ESP_NOSIG, ESP_PWM1_OUT1B) + +#define MCPWM1_OUT1B_GPIO35 \ + ESP32_PINMUX(35, ESP_NOSIG, ESP_PWM1_OUT1B) + +#define MCPWM1_OUT1B_GPIO36 \ + ESP32_PINMUX(36, ESP_NOSIG, ESP_PWM1_OUT1B) + +#define MCPWM1_OUT1B_GPIO37 \ + ESP32_PINMUX(37, ESP_NOSIG, ESP_PWM1_OUT1B) + +#define MCPWM1_OUT1B_GPIO38 \ + ESP32_PINMUX(38, ESP_NOSIG, ESP_PWM1_OUT1B) + +#define MCPWM1_OUT1B_GPIO39 \ + ESP32_PINMUX(39, ESP_NOSIG, ESP_PWM1_OUT1B) + +#define MCPWM1_OUT1B_GPIO40 \ + ESP32_PINMUX(40, ESP_NOSIG, ESP_PWM1_OUT1B) + +#define MCPWM1_OUT1B_GPIO41 \ + ESP32_PINMUX(41, ESP_NOSIG, ESP_PWM1_OUT1B) + +#define MCPWM1_OUT1B_GPIO42 \ + ESP32_PINMUX(42, ESP_NOSIG, ESP_PWM1_OUT1B) + +#define MCPWM1_OUT1B_GPIO43 \ + ESP32_PINMUX(43, ESP_NOSIG, ESP_PWM1_OUT1B) + +#define MCPWM1_OUT1B_GPIO44 \ + ESP32_PINMUX(44, ESP_NOSIG, ESP_PWM1_OUT1B) + +#define MCPWM1_OUT1B_GPIO45 \ + ESP32_PINMUX(45, ESP_NOSIG, ESP_PWM1_OUT1B) + +#define MCPWM1_OUT1B_GPIO46 \ + ESP32_PINMUX(46, ESP_NOSIG, ESP_PWM1_OUT1B) + +#define MCPWM1_OUT1B_GPIO47 \ + ESP32_PINMUX(47, ESP_NOSIG, ESP_PWM1_OUT1B) + +#define MCPWM1_OUT1B_GPIO48 \ + ESP32_PINMUX(48, ESP_NOSIG, ESP_PWM1_OUT1B) + +/* MCPWM1_OUT2A */ +#define MCPWM1_OUT2A_GPIO0 \ + ESP32_PINMUX(0, ESP_NOSIG, ESP_PWM1_OUT2A) + +#define MCPWM1_OUT2A_GPIO1 \ + ESP32_PINMUX(1, ESP_NOSIG, ESP_PWM1_OUT2A) + +#define MCPWM1_OUT2A_GPIO2 \ + ESP32_PINMUX(2, ESP_NOSIG, ESP_PWM1_OUT2A) + +#define MCPWM1_OUT2A_GPIO3 \ + ESP32_PINMUX(3, ESP_NOSIG, ESP_PWM1_OUT2A) + +#define MCPWM1_OUT2A_GPIO4 \ + ESP32_PINMUX(4, ESP_NOSIG, ESP_PWM1_OUT2A) + +#define MCPWM1_OUT2A_GPIO5 \ + ESP32_PINMUX(5, ESP_NOSIG, ESP_PWM1_OUT2A) + +#define MCPWM1_OUT2A_GPIO6 \ + ESP32_PINMUX(6, ESP_NOSIG, ESP_PWM1_OUT2A) + +#define MCPWM1_OUT2A_GPIO7 \ + ESP32_PINMUX(7, ESP_NOSIG, ESP_PWM1_OUT2A) + +#define MCPWM1_OUT2A_GPIO8 \ + ESP32_PINMUX(8, ESP_NOSIG, ESP_PWM1_OUT2A) + +#define MCPWM1_OUT2A_GPIO9 \ + ESP32_PINMUX(9, ESP_NOSIG, ESP_PWM1_OUT2A) + +#define MCPWM1_OUT2A_GPIO10 \ + ESP32_PINMUX(10, ESP_NOSIG, ESP_PWM1_OUT2A) + +#define MCPWM1_OUT2A_GPIO11 \ + ESP32_PINMUX(11, ESP_NOSIG, ESP_PWM1_OUT2A) + +#define MCPWM1_OUT2A_GPIO12 \ + ESP32_PINMUX(12, ESP_NOSIG, ESP_PWM1_OUT2A) + +#define MCPWM1_OUT2A_GPIO13 \ + ESP32_PINMUX(13, ESP_NOSIG, ESP_PWM1_OUT2A) + +#define MCPWM1_OUT2A_GPIO14 \ + ESP32_PINMUX(14, ESP_NOSIG, ESP_PWM1_OUT2A) + +#define MCPWM1_OUT2A_GPIO15 \ + ESP32_PINMUX(15, ESP_NOSIG, ESP_PWM1_OUT2A) + +#define MCPWM1_OUT2A_GPIO16 \ + ESP32_PINMUX(16, ESP_NOSIG, ESP_PWM1_OUT2A) + +#define MCPWM1_OUT2A_GPIO17 \ + ESP32_PINMUX(17, ESP_NOSIG, ESP_PWM1_OUT2A) + +#define MCPWM1_OUT2A_GPIO18 \ + ESP32_PINMUX(18, ESP_NOSIG, ESP_PWM1_OUT2A) + +#define MCPWM1_OUT2A_GPIO19 \ + ESP32_PINMUX(19, ESP_NOSIG, ESP_PWM1_OUT2A) + +#define MCPWM1_OUT2A_GPIO20 \ + ESP32_PINMUX(20, ESP_NOSIG, ESP_PWM1_OUT2A) + +#define MCPWM1_OUT2A_GPIO21 \ + ESP32_PINMUX(21, ESP_NOSIG, ESP_PWM1_OUT2A) + +#define MCPWM1_OUT2A_GPIO26 \ + ESP32_PINMUX(26, ESP_NOSIG, ESP_PWM1_OUT2A) + +#define MCPWM1_OUT2A_GPIO27 \ + ESP32_PINMUX(27, ESP_NOSIG, ESP_PWM1_OUT2A) + +#define MCPWM1_OUT2A_GPIO28 \ + ESP32_PINMUX(28, ESP_NOSIG, ESP_PWM1_OUT2A) + +#define MCPWM1_OUT2A_GPIO29 \ + ESP32_PINMUX(29, ESP_NOSIG, ESP_PWM1_OUT2A) + +#define MCPWM1_OUT2A_GPIO30 \ + ESP32_PINMUX(30, ESP_NOSIG, ESP_PWM1_OUT2A) + +#define MCPWM1_OUT2A_GPIO31 \ + ESP32_PINMUX(31, ESP_NOSIG, ESP_PWM1_OUT2A) + +#define MCPWM1_OUT2A_GPIO32 \ + ESP32_PINMUX(32, ESP_NOSIG, ESP_PWM1_OUT2A) + +#define MCPWM1_OUT2A_GPIO33 \ + ESP32_PINMUX(33, ESP_NOSIG, ESP_PWM1_OUT2A) + +#define MCPWM1_OUT2A_GPIO34 \ + ESP32_PINMUX(34, ESP_NOSIG, ESP_PWM1_OUT2A) + +#define MCPWM1_OUT2A_GPIO35 \ + ESP32_PINMUX(35, ESP_NOSIG, ESP_PWM1_OUT2A) + +#define MCPWM1_OUT2A_GPIO36 \ + ESP32_PINMUX(36, ESP_NOSIG, ESP_PWM1_OUT2A) + +#define MCPWM1_OUT2A_GPIO37 \ + ESP32_PINMUX(37, ESP_NOSIG, ESP_PWM1_OUT2A) + +#define MCPWM1_OUT2A_GPIO38 \ + ESP32_PINMUX(38, ESP_NOSIG, ESP_PWM1_OUT2A) + +#define MCPWM1_OUT2A_GPIO39 \ + ESP32_PINMUX(39, ESP_NOSIG, ESP_PWM1_OUT2A) + +#define MCPWM1_OUT2A_GPIO40 \ + ESP32_PINMUX(40, ESP_NOSIG, ESP_PWM1_OUT2A) + +#define MCPWM1_OUT2A_GPIO41 \ + ESP32_PINMUX(41, ESP_NOSIG, ESP_PWM1_OUT2A) + +#define MCPWM1_OUT2A_GPIO42 \ + ESP32_PINMUX(42, ESP_NOSIG, ESP_PWM1_OUT2A) + +#define MCPWM1_OUT2A_GPIO43 \ + ESP32_PINMUX(43, ESP_NOSIG, ESP_PWM1_OUT2A) + +#define MCPWM1_OUT2A_GPIO44 \ + ESP32_PINMUX(44, ESP_NOSIG, ESP_PWM1_OUT2A) + +#define MCPWM1_OUT2A_GPIO45 \ + ESP32_PINMUX(45, ESP_NOSIG, ESP_PWM1_OUT2A) + +#define MCPWM1_OUT2A_GPIO46 \ + ESP32_PINMUX(46, ESP_NOSIG, ESP_PWM1_OUT2A) + +#define MCPWM1_OUT2A_GPIO47 \ + ESP32_PINMUX(47, ESP_NOSIG, ESP_PWM1_OUT2A) + +#define MCPWM1_OUT2A_GPIO48 \ + ESP32_PINMUX(48, ESP_NOSIG, ESP_PWM1_OUT2A) + +/* MCPWM1_OUT2B */ +#define MCPWM1_OUT2B_GPIO0 \ + ESP32_PINMUX(0, ESP_NOSIG, ESP_PWM1_OUT2B) + +#define MCPWM1_OUT2B_GPIO1 \ + ESP32_PINMUX(1, ESP_NOSIG, ESP_PWM1_OUT2B) + +#define MCPWM1_OUT2B_GPIO2 \ + ESP32_PINMUX(2, ESP_NOSIG, ESP_PWM1_OUT2B) + +#define MCPWM1_OUT2B_GPIO3 \ + ESP32_PINMUX(3, ESP_NOSIG, ESP_PWM1_OUT2B) + +#define MCPWM1_OUT2B_GPIO4 \ + ESP32_PINMUX(4, ESP_NOSIG, ESP_PWM1_OUT2B) + +#define MCPWM1_OUT2B_GPIO5 \ + ESP32_PINMUX(5, ESP_NOSIG, ESP_PWM1_OUT2B) + +#define MCPWM1_OUT2B_GPIO6 \ + ESP32_PINMUX(6, ESP_NOSIG, ESP_PWM1_OUT2B) + +#define MCPWM1_OUT2B_GPIO7 \ + ESP32_PINMUX(7, ESP_NOSIG, ESP_PWM1_OUT2B) + +#define MCPWM1_OUT2B_GPIO8 \ + ESP32_PINMUX(8, ESP_NOSIG, ESP_PWM1_OUT2B) + +#define MCPWM1_OUT2B_GPIO9 \ + ESP32_PINMUX(9, ESP_NOSIG, ESP_PWM1_OUT2B) + +#define MCPWM1_OUT2B_GPIO10 \ + ESP32_PINMUX(10, ESP_NOSIG, ESP_PWM1_OUT2B) + +#define MCPWM1_OUT2B_GPIO11 \ + ESP32_PINMUX(11, ESP_NOSIG, ESP_PWM1_OUT2B) + +#define MCPWM1_OUT2B_GPIO12 \ + ESP32_PINMUX(12, ESP_NOSIG, ESP_PWM1_OUT2B) + +#define MCPWM1_OUT2B_GPIO13 \ + ESP32_PINMUX(13, ESP_NOSIG, ESP_PWM1_OUT2B) + +#define MCPWM1_OUT2B_GPIO14 \ + ESP32_PINMUX(14, ESP_NOSIG, ESP_PWM1_OUT2B) + +#define MCPWM1_OUT2B_GPIO15 \ + ESP32_PINMUX(15, ESP_NOSIG, ESP_PWM1_OUT2B) + +#define MCPWM1_OUT2B_GPIO16 \ + ESP32_PINMUX(16, ESP_NOSIG, ESP_PWM1_OUT2B) + +#define MCPWM1_OUT2B_GPIO17 \ + ESP32_PINMUX(17, ESP_NOSIG, ESP_PWM1_OUT2B) + +#define MCPWM1_OUT2B_GPIO18 \ + ESP32_PINMUX(18, ESP_NOSIG, ESP_PWM1_OUT2B) + +#define MCPWM1_OUT2B_GPIO19 \ + ESP32_PINMUX(19, ESP_NOSIG, ESP_PWM1_OUT2B) + +#define MCPWM1_OUT2B_GPIO20 \ + ESP32_PINMUX(20, ESP_NOSIG, ESP_PWM1_OUT2B) + +#define MCPWM1_OUT2B_GPIO21 \ + ESP32_PINMUX(21, ESP_NOSIG, ESP_PWM1_OUT2B) + +#define MCPWM1_OUT2B_GPIO26 \ + ESP32_PINMUX(26, ESP_NOSIG, ESP_PWM1_OUT2B) + +#define MCPWM1_OUT2B_GPIO27 \ + ESP32_PINMUX(27, ESP_NOSIG, ESP_PWM1_OUT2B) + +#define MCPWM1_OUT2B_GPIO28 \ + ESP32_PINMUX(28, ESP_NOSIG, ESP_PWM1_OUT2B) + +#define MCPWM1_OUT2B_GPIO29 \ + ESP32_PINMUX(29, ESP_NOSIG, ESP_PWM1_OUT2B) + +#define MCPWM1_OUT2B_GPIO30 \ + ESP32_PINMUX(30, ESP_NOSIG, ESP_PWM1_OUT2B) + +#define MCPWM1_OUT2B_GPIO31 \ + ESP32_PINMUX(31, ESP_NOSIG, ESP_PWM1_OUT2B) + +#define MCPWM1_OUT2B_GPIO32 \ + ESP32_PINMUX(32, ESP_NOSIG, ESP_PWM1_OUT2B) + +#define MCPWM1_OUT2B_GPIO33 \ + ESP32_PINMUX(33, ESP_NOSIG, ESP_PWM1_OUT2B) + +#define MCPWM1_OUT2B_GPIO34 \ + ESP32_PINMUX(34, ESP_NOSIG, ESP_PWM1_OUT2B) + +#define MCPWM1_OUT2B_GPIO35 \ + ESP32_PINMUX(35, ESP_NOSIG, ESP_PWM1_OUT2B) + +#define MCPWM1_OUT2B_GPIO36 \ + ESP32_PINMUX(36, ESP_NOSIG, ESP_PWM1_OUT2B) + +#define MCPWM1_OUT2B_GPIO37 \ + ESP32_PINMUX(37, ESP_NOSIG, ESP_PWM1_OUT2B) + +#define MCPWM1_OUT2B_GPIO38 \ + ESP32_PINMUX(38, ESP_NOSIG, ESP_PWM1_OUT2B) + +#define MCPWM1_OUT2B_GPIO39 \ + ESP32_PINMUX(39, ESP_NOSIG, ESP_PWM1_OUT2B) + +#define MCPWM1_OUT2B_GPIO40 \ + ESP32_PINMUX(40, ESP_NOSIG, ESP_PWM1_OUT2B) + +#define MCPWM1_OUT2B_GPIO41 \ + ESP32_PINMUX(41, ESP_NOSIG, ESP_PWM1_OUT2B) + +#define MCPWM1_OUT2B_GPIO42 \ + ESP32_PINMUX(42, ESP_NOSIG, ESP_PWM1_OUT2B) + +#define MCPWM1_OUT2B_GPIO43 \ + ESP32_PINMUX(43, ESP_NOSIG, ESP_PWM1_OUT2B) + +#define MCPWM1_OUT2B_GPIO44 \ + ESP32_PINMUX(44, ESP_NOSIG, ESP_PWM1_OUT2B) + +#define MCPWM1_OUT2B_GPIO45 \ + ESP32_PINMUX(45, ESP_NOSIG, ESP_PWM1_OUT2B) + +#define MCPWM1_OUT2B_GPIO46 \ + ESP32_PINMUX(46, ESP_NOSIG, ESP_PWM1_OUT2B) + +#define MCPWM1_OUT2B_GPIO47 \ + ESP32_PINMUX(47, ESP_NOSIG, ESP_PWM1_OUT2B) + +#define MCPWM1_OUT2B_GPIO48 \ + ESP32_PINMUX(48, ESP_NOSIG, ESP_PWM1_OUT2B) + +/* MCPWM1_SYNC0 */ +#define MCPWM1_SYNC0_GPIO0 \ + ESP32_PINMUX(0, ESP_PWM1_SYNC0_IN, ESP_NOSIG) + +#define MCPWM1_SYNC0_GPIO1 \ + ESP32_PINMUX(1, ESP_PWM1_SYNC0_IN, ESP_NOSIG) + +#define MCPWM1_SYNC0_GPIO2 \ + ESP32_PINMUX(2, ESP_PWM1_SYNC0_IN, ESP_NOSIG) + +#define MCPWM1_SYNC0_GPIO3 \ + ESP32_PINMUX(3, ESP_PWM1_SYNC0_IN, ESP_NOSIG) + +#define MCPWM1_SYNC0_GPIO4 \ + ESP32_PINMUX(4, ESP_PWM1_SYNC0_IN, ESP_NOSIG) + +#define MCPWM1_SYNC0_GPIO5 \ + ESP32_PINMUX(5, ESP_PWM1_SYNC0_IN, ESP_NOSIG) + +#define MCPWM1_SYNC0_GPIO6 \ + ESP32_PINMUX(6, ESP_PWM1_SYNC0_IN, ESP_NOSIG) + +#define MCPWM1_SYNC0_GPIO7 \ + ESP32_PINMUX(7, ESP_PWM1_SYNC0_IN, ESP_NOSIG) + +#define MCPWM1_SYNC0_GPIO8 \ + ESP32_PINMUX(8, ESP_PWM1_SYNC0_IN, ESP_NOSIG) + +#define MCPWM1_SYNC0_GPIO9 \ + ESP32_PINMUX(9, ESP_PWM1_SYNC0_IN, ESP_NOSIG) + +#define MCPWM1_SYNC0_GPIO10 \ + ESP32_PINMUX(10, ESP_PWM1_SYNC0_IN, ESP_NOSIG) + +#define MCPWM1_SYNC0_GPIO11 \ + ESP32_PINMUX(11, ESP_PWM1_SYNC0_IN, ESP_NOSIG) + +#define MCPWM1_SYNC0_GPIO12 \ + ESP32_PINMUX(12, ESP_PWM1_SYNC0_IN, ESP_NOSIG) + +#define MCPWM1_SYNC0_GPIO13 \ + ESP32_PINMUX(13, ESP_PWM1_SYNC0_IN, ESP_NOSIG) + +#define MCPWM1_SYNC0_GPIO14 \ + ESP32_PINMUX(14, ESP_PWM1_SYNC0_IN, ESP_NOSIG) + +#define MCPWM1_SYNC0_GPIO15 \ + ESP32_PINMUX(15, ESP_PWM1_SYNC0_IN, ESP_NOSIG) + +#define MCPWM1_SYNC0_GPIO16 \ + ESP32_PINMUX(16, ESP_PWM1_SYNC0_IN, ESP_NOSIG) + +#define MCPWM1_SYNC0_GPIO17 \ + ESP32_PINMUX(17, ESP_PWM1_SYNC0_IN, ESP_NOSIG) + +#define MCPWM1_SYNC0_GPIO18 \ + ESP32_PINMUX(18, ESP_PWM1_SYNC0_IN, ESP_NOSIG) + +#define MCPWM1_SYNC0_GPIO19 \ + ESP32_PINMUX(19, ESP_PWM1_SYNC0_IN, ESP_NOSIG) + +#define MCPWM1_SYNC0_GPIO20 \ + ESP32_PINMUX(20, ESP_PWM1_SYNC0_IN, ESP_NOSIG) + +#define MCPWM1_SYNC0_GPIO21 \ + ESP32_PINMUX(21, ESP_PWM1_SYNC0_IN, ESP_NOSIG) + +#define MCPWM1_SYNC0_GPIO26 \ + ESP32_PINMUX(26, ESP_PWM1_SYNC0_IN, ESP_NOSIG) + +#define MCPWM1_SYNC0_GPIO27 \ + ESP32_PINMUX(27, ESP_PWM1_SYNC0_IN, ESP_NOSIG) + +#define MCPWM1_SYNC0_GPIO28 \ + ESP32_PINMUX(28, ESP_PWM1_SYNC0_IN, ESP_NOSIG) + +#define MCPWM1_SYNC0_GPIO29 \ + ESP32_PINMUX(29, ESP_PWM1_SYNC0_IN, ESP_NOSIG) + +#define MCPWM1_SYNC0_GPIO30 \ + ESP32_PINMUX(30, ESP_PWM1_SYNC0_IN, ESP_NOSIG) + +#define MCPWM1_SYNC0_GPIO31 \ + ESP32_PINMUX(31, ESP_PWM1_SYNC0_IN, ESP_NOSIG) + +#define MCPWM1_SYNC0_GPIO32 \ + ESP32_PINMUX(32, ESP_PWM1_SYNC0_IN, ESP_NOSIG) + +#define MCPWM1_SYNC0_GPIO33 \ + ESP32_PINMUX(33, ESP_PWM1_SYNC0_IN, ESP_NOSIG) + +#define MCPWM1_SYNC0_GPIO34 \ + ESP32_PINMUX(34, ESP_PWM1_SYNC0_IN, ESP_NOSIG) + +#define MCPWM1_SYNC0_GPIO35 \ + ESP32_PINMUX(35, ESP_PWM1_SYNC0_IN, ESP_NOSIG) + +#define MCPWM1_SYNC0_GPIO36 \ + ESP32_PINMUX(36, ESP_PWM1_SYNC0_IN, ESP_NOSIG) + +#define MCPWM1_SYNC0_GPIO37 \ + ESP32_PINMUX(37, ESP_PWM1_SYNC0_IN, ESP_NOSIG) + +#define MCPWM1_SYNC0_GPIO38 \ + ESP32_PINMUX(38, ESP_PWM1_SYNC0_IN, ESP_NOSIG) + +#define MCPWM1_SYNC0_GPIO39 \ + ESP32_PINMUX(39, ESP_PWM1_SYNC0_IN, ESP_NOSIG) + +#define MCPWM1_SYNC0_GPIO40 \ + ESP32_PINMUX(40, ESP_PWM1_SYNC0_IN, ESP_NOSIG) + +#define MCPWM1_SYNC0_GPIO41 \ + ESP32_PINMUX(41, ESP_PWM1_SYNC0_IN, ESP_NOSIG) + +#define MCPWM1_SYNC0_GPIO42 \ + ESP32_PINMUX(42, ESP_PWM1_SYNC0_IN, ESP_NOSIG) + +#define MCPWM1_SYNC0_GPIO43 \ + ESP32_PINMUX(43, ESP_PWM1_SYNC0_IN, ESP_NOSIG) + +#define MCPWM1_SYNC0_GPIO44 \ + ESP32_PINMUX(44, ESP_PWM1_SYNC0_IN, ESP_NOSIG) + +#define MCPWM1_SYNC0_GPIO45 \ + ESP32_PINMUX(45, ESP_PWM1_SYNC0_IN, ESP_NOSIG) + +#define MCPWM1_SYNC0_GPIO46 \ + ESP32_PINMUX(46, ESP_PWM1_SYNC0_IN, ESP_NOSIG) + +#define MCPWM1_SYNC0_GPIO47 \ + ESP32_PINMUX(47, ESP_PWM1_SYNC0_IN, ESP_NOSIG) + +#define MCPWM1_SYNC0_GPIO48 \ + ESP32_PINMUX(48, ESP_PWM1_SYNC0_IN, ESP_NOSIG) + +/* MCPWM1_SYNC1 */ +#define MCPWM1_SYNC1_GPIO0 \ + ESP32_PINMUX(0, ESP_PWM1_SYNC1_IN, ESP_NOSIG) + +#define MCPWM1_SYNC1_GPIO1 \ + ESP32_PINMUX(1, ESP_PWM1_SYNC1_IN, ESP_NOSIG) + +#define MCPWM1_SYNC1_GPIO2 \ + ESP32_PINMUX(2, ESP_PWM1_SYNC1_IN, ESP_NOSIG) + +#define MCPWM1_SYNC1_GPIO3 \ + ESP32_PINMUX(3, ESP_PWM1_SYNC1_IN, ESP_NOSIG) + +#define MCPWM1_SYNC1_GPIO4 \ + ESP32_PINMUX(4, ESP_PWM1_SYNC1_IN, ESP_NOSIG) + +#define MCPWM1_SYNC1_GPIO5 \ + ESP32_PINMUX(5, ESP_PWM1_SYNC1_IN, ESP_NOSIG) + +#define MCPWM1_SYNC1_GPIO6 \ + ESP32_PINMUX(6, ESP_PWM1_SYNC1_IN, ESP_NOSIG) + +#define MCPWM1_SYNC1_GPIO7 \ + ESP32_PINMUX(7, ESP_PWM1_SYNC1_IN, ESP_NOSIG) + +#define MCPWM1_SYNC1_GPIO8 \ + ESP32_PINMUX(8, ESP_PWM1_SYNC1_IN, ESP_NOSIG) + +#define MCPWM1_SYNC1_GPIO9 \ + ESP32_PINMUX(9, ESP_PWM1_SYNC1_IN, ESP_NOSIG) + +#define MCPWM1_SYNC1_GPIO10 \ + ESP32_PINMUX(10, ESP_PWM1_SYNC1_IN, ESP_NOSIG) + +#define MCPWM1_SYNC1_GPIO11 \ + ESP32_PINMUX(11, ESP_PWM1_SYNC1_IN, ESP_NOSIG) + +#define MCPWM1_SYNC1_GPIO12 \ + ESP32_PINMUX(12, ESP_PWM1_SYNC1_IN, ESP_NOSIG) + +#define MCPWM1_SYNC1_GPIO13 \ + ESP32_PINMUX(13, ESP_PWM1_SYNC1_IN, ESP_NOSIG) + +#define MCPWM1_SYNC1_GPIO14 \ + ESP32_PINMUX(14, ESP_PWM1_SYNC1_IN, ESP_NOSIG) + +#define MCPWM1_SYNC1_GPIO15 \ + ESP32_PINMUX(15, ESP_PWM1_SYNC1_IN, ESP_NOSIG) + +#define MCPWM1_SYNC1_GPIO16 \ + ESP32_PINMUX(16, ESP_PWM1_SYNC1_IN, ESP_NOSIG) + +#define MCPWM1_SYNC1_GPIO17 \ + ESP32_PINMUX(17, ESP_PWM1_SYNC1_IN, ESP_NOSIG) + +#define MCPWM1_SYNC1_GPIO18 \ + ESP32_PINMUX(18, ESP_PWM1_SYNC1_IN, ESP_NOSIG) + +#define MCPWM1_SYNC1_GPIO19 \ + ESP32_PINMUX(19, ESP_PWM1_SYNC1_IN, ESP_NOSIG) + +#define MCPWM1_SYNC1_GPIO20 \ + ESP32_PINMUX(20, ESP_PWM1_SYNC1_IN, ESP_NOSIG) + +#define MCPWM1_SYNC1_GPIO21 \ + ESP32_PINMUX(21, ESP_PWM1_SYNC1_IN, ESP_NOSIG) + +#define MCPWM1_SYNC1_GPIO26 \ + ESP32_PINMUX(26, ESP_PWM1_SYNC1_IN, ESP_NOSIG) + +#define MCPWM1_SYNC1_GPIO27 \ + ESP32_PINMUX(27, ESP_PWM1_SYNC1_IN, ESP_NOSIG) + +#define MCPWM1_SYNC1_GPIO28 \ + ESP32_PINMUX(28, ESP_PWM1_SYNC1_IN, ESP_NOSIG) + +#define MCPWM1_SYNC1_GPIO29 \ + ESP32_PINMUX(29, ESP_PWM1_SYNC1_IN, ESP_NOSIG) + +#define MCPWM1_SYNC1_GPIO30 \ + ESP32_PINMUX(30, ESP_PWM1_SYNC1_IN, ESP_NOSIG) + +#define MCPWM1_SYNC1_GPIO31 \ + ESP32_PINMUX(31, ESP_PWM1_SYNC1_IN, ESP_NOSIG) + +#define MCPWM1_SYNC1_GPIO32 \ + ESP32_PINMUX(32, ESP_PWM1_SYNC1_IN, ESP_NOSIG) + +#define MCPWM1_SYNC1_GPIO33 \ + ESP32_PINMUX(33, ESP_PWM1_SYNC1_IN, ESP_NOSIG) + +#define MCPWM1_SYNC1_GPIO34 \ + ESP32_PINMUX(34, ESP_PWM1_SYNC1_IN, ESP_NOSIG) + +#define MCPWM1_SYNC1_GPIO35 \ + ESP32_PINMUX(35, ESP_PWM1_SYNC1_IN, ESP_NOSIG) + +#define MCPWM1_SYNC1_GPIO36 \ + ESP32_PINMUX(36, ESP_PWM1_SYNC1_IN, ESP_NOSIG) + +#define MCPWM1_SYNC1_GPIO37 \ + ESP32_PINMUX(37, ESP_PWM1_SYNC1_IN, ESP_NOSIG) + +#define MCPWM1_SYNC1_GPIO38 \ + ESP32_PINMUX(38, ESP_PWM1_SYNC1_IN, ESP_NOSIG) + +#define MCPWM1_SYNC1_GPIO39 \ + ESP32_PINMUX(39, ESP_PWM1_SYNC1_IN, ESP_NOSIG) + +#define MCPWM1_SYNC1_GPIO40 \ + ESP32_PINMUX(40, ESP_PWM1_SYNC1_IN, ESP_NOSIG) + +#define MCPWM1_SYNC1_GPIO41 \ + ESP32_PINMUX(41, ESP_PWM1_SYNC1_IN, ESP_NOSIG) + +#define MCPWM1_SYNC1_GPIO42 \ + ESP32_PINMUX(42, ESP_PWM1_SYNC1_IN, ESP_NOSIG) + +#define MCPWM1_SYNC1_GPIO43 \ + ESP32_PINMUX(43, ESP_PWM1_SYNC1_IN, ESP_NOSIG) + +#define MCPWM1_SYNC1_GPIO44 \ + ESP32_PINMUX(44, ESP_PWM1_SYNC1_IN, ESP_NOSIG) + +#define MCPWM1_SYNC1_GPIO45 \ + ESP32_PINMUX(45, ESP_PWM1_SYNC1_IN, ESP_NOSIG) + +#define MCPWM1_SYNC1_GPIO46 \ + ESP32_PINMUX(46, ESP_PWM1_SYNC1_IN, ESP_NOSIG) + +#define MCPWM1_SYNC1_GPIO47 \ + ESP32_PINMUX(47, ESP_PWM1_SYNC1_IN, ESP_NOSIG) + +#define MCPWM1_SYNC1_GPIO48 \ + ESP32_PINMUX(48, ESP_PWM1_SYNC1_IN, ESP_NOSIG) + +/* MCPWM1_SYNC2 */ +#define MCPWM1_SYNC2_GPIO0 \ + ESP32_PINMUX(0, ESP_PWM1_SYNC2_IN, ESP_NOSIG) + +#define MCPWM1_SYNC2_GPIO1 \ + ESP32_PINMUX(1, ESP_PWM1_SYNC2_IN, ESP_NOSIG) + +#define MCPWM1_SYNC2_GPIO2 \ + ESP32_PINMUX(2, ESP_PWM1_SYNC2_IN, ESP_NOSIG) + +#define MCPWM1_SYNC2_GPIO3 \ + ESP32_PINMUX(3, ESP_PWM1_SYNC2_IN, ESP_NOSIG) + +#define MCPWM1_SYNC2_GPIO4 \ + ESP32_PINMUX(4, ESP_PWM1_SYNC2_IN, ESP_NOSIG) + +#define MCPWM1_SYNC2_GPIO5 \ + ESP32_PINMUX(5, ESP_PWM1_SYNC2_IN, ESP_NOSIG) + +#define MCPWM1_SYNC2_GPIO6 \ + ESP32_PINMUX(6, ESP_PWM1_SYNC2_IN, ESP_NOSIG) + +#define MCPWM1_SYNC2_GPIO7 \ + ESP32_PINMUX(7, ESP_PWM1_SYNC2_IN, ESP_NOSIG) + +#define MCPWM1_SYNC2_GPIO8 \ + ESP32_PINMUX(8, ESP_PWM1_SYNC2_IN, ESP_NOSIG) + +#define MCPWM1_SYNC2_GPIO9 \ + ESP32_PINMUX(9, ESP_PWM1_SYNC2_IN, ESP_NOSIG) + +#define MCPWM1_SYNC2_GPIO10 \ + ESP32_PINMUX(10, ESP_PWM1_SYNC2_IN, ESP_NOSIG) + +#define MCPWM1_SYNC2_GPIO11 \ + ESP32_PINMUX(11, ESP_PWM1_SYNC2_IN, ESP_NOSIG) + +#define MCPWM1_SYNC2_GPIO12 \ + ESP32_PINMUX(12, ESP_PWM1_SYNC2_IN, ESP_NOSIG) + +#define MCPWM1_SYNC2_GPIO13 \ + ESP32_PINMUX(13, ESP_PWM1_SYNC2_IN, ESP_NOSIG) + +#define MCPWM1_SYNC2_GPIO14 \ + ESP32_PINMUX(14, ESP_PWM1_SYNC2_IN, ESP_NOSIG) + +#define MCPWM1_SYNC2_GPIO15 \ + ESP32_PINMUX(15, ESP_PWM1_SYNC2_IN, ESP_NOSIG) + +#define MCPWM1_SYNC2_GPIO16 \ + ESP32_PINMUX(16, ESP_PWM1_SYNC2_IN, ESP_NOSIG) + +#define MCPWM1_SYNC2_GPIO17 \ + ESP32_PINMUX(17, ESP_PWM1_SYNC2_IN, ESP_NOSIG) + +#define MCPWM1_SYNC2_GPIO18 \ + ESP32_PINMUX(18, ESP_PWM1_SYNC2_IN, ESP_NOSIG) + +#define MCPWM1_SYNC2_GPIO19 \ + ESP32_PINMUX(19, ESP_PWM1_SYNC2_IN, ESP_NOSIG) + +#define MCPWM1_SYNC2_GPIO20 \ + ESP32_PINMUX(20, ESP_PWM1_SYNC2_IN, ESP_NOSIG) + +#define MCPWM1_SYNC2_GPIO21 \ + ESP32_PINMUX(21, ESP_PWM1_SYNC2_IN, ESP_NOSIG) + +#define MCPWM1_SYNC2_GPIO26 \ + ESP32_PINMUX(26, ESP_PWM1_SYNC2_IN, ESP_NOSIG) + +#define MCPWM1_SYNC2_GPIO27 \ + ESP32_PINMUX(27, ESP_PWM1_SYNC2_IN, ESP_NOSIG) + +#define MCPWM1_SYNC2_GPIO28 \ + ESP32_PINMUX(28, ESP_PWM1_SYNC2_IN, ESP_NOSIG) + +#define MCPWM1_SYNC2_GPIO29 \ + ESP32_PINMUX(29, ESP_PWM1_SYNC2_IN, ESP_NOSIG) + +#define MCPWM1_SYNC2_GPIO30 \ + ESP32_PINMUX(30, ESP_PWM1_SYNC2_IN, ESP_NOSIG) + +#define MCPWM1_SYNC2_GPIO31 \ + ESP32_PINMUX(31, ESP_PWM1_SYNC2_IN, ESP_NOSIG) + +#define MCPWM1_SYNC2_GPIO32 \ + ESP32_PINMUX(32, ESP_PWM1_SYNC2_IN, ESP_NOSIG) + +#define MCPWM1_SYNC2_GPIO33 \ + ESP32_PINMUX(33, ESP_PWM1_SYNC2_IN, ESP_NOSIG) + +#define MCPWM1_SYNC2_GPIO34 \ + ESP32_PINMUX(34, ESP_PWM1_SYNC2_IN, ESP_NOSIG) + +#define MCPWM1_SYNC2_GPIO35 \ + ESP32_PINMUX(35, ESP_PWM1_SYNC2_IN, ESP_NOSIG) + +#define MCPWM1_SYNC2_GPIO36 \ + ESP32_PINMUX(36, ESP_PWM1_SYNC2_IN, ESP_NOSIG) + +#define MCPWM1_SYNC2_GPIO37 \ + ESP32_PINMUX(37, ESP_PWM1_SYNC2_IN, ESP_NOSIG) + +#define MCPWM1_SYNC2_GPIO38 \ + ESP32_PINMUX(38, ESP_PWM1_SYNC2_IN, ESP_NOSIG) + +#define MCPWM1_SYNC2_GPIO39 \ + ESP32_PINMUX(39, ESP_PWM1_SYNC2_IN, ESP_NOSIG) + +#define MCPWM1_SYNC2_GPIO40 \ + ESP32_PINMUX(40, ESP_PWM1_SYNC2_IN, ESP_NOSIG) + +#define MCPWM1_SYNC2_GPIO41 \ + ESP32_PINMUX(41, ESP_PWM1_SYNC2_IN, ESP_NOSIG) + +#define MCPWM1_SYNC2_GPIO42 \ + ESP32_PINMUX(42, ESP_PWM1_SYNC2_IN, ESP_NOSIG) + +#define MCPWM1_SYNC2_GPIO43 \ + ESP32_PINMUX(43, ESP_PWM1_SYNC2_IN, ESP_NOSIG) + +#define MCPWM1_SYNC2_GPIO44 \ + ESP32_PINMUX(44, ESP_PWM1_SYNC2_IN, ESP_NOSIG) + +#define MCPWM1_SYNC2_GPIO45 \ + ESP32_PINMUX(45, ESP_PWM1_SYNC2_IN, ESP_NOSIG) + +#define MCPWM1_SYNC2_GPIO46 \ + ESP32_PINMUX(46, ESP_PWM1_SYNC2_IN, ESP_NOSIG) + +#define MCPWM1_SYNC2_GPIO47 \ + ESP32_PINMUX(47, ESP_PWM1_SYNC2_IN, ESP_NOSIG) + +#define MCPWM1_SYNC2_GPIO48 \ + ESP32_PINMUX(48, ESP_PWM1_SYNC2_IN, ESP_NOSIG) + +/* PCNT0_CH0CTRL */ +#define PCNT0_CH0CTRL_GPIO0 \ + ESP32_PINMUX(0, ESP_PCNT_CTRL_CH0_IN0, ESP_NOSIG) + +#define PCNT0_CH0CTRL_GPIO1 \ + ESP32_PINMUX(1, ESP_PCNT_CTRL_CH0_IN0, ESP_NOSIG) + +#define PCNT0_CH0CTRL_GPIO2 \ + ESP32_PINMUX(2, ESP_PCNT_CTRL_CH0_IN0, ESP_NOSIG) + +#define PCNT0_CH0CTRL_GPIO3 \ + ESP32_PINMUX(3, ESP_PCNT_CTRL_CH0_IN0, ESP_NOSIG) + +#define PCNT0_CH0CTRL_GPIO4 \ + ESP32_PINMUX(4, ESP_PCNT_CTRL_CH0_IN0, ESP_NOSIG) + +#define PCNT0_CH0CTRL_GPIO5 \ + ESP32_PINMUX(5, ESP_PCNT_CTRL_CH0_IN0, ESP_NOSIG) + +#define PCNT0_CH0CTRL_GPIO6 \ + ESP32_PINMUX(6, ESP_PCNT_CTRL_CH0_IN0, ESP_NOSIG) + +#define PCNT0_CH0CTRL_GPIO7 \ + ESP32_PINMUX(7, ESP_PCNT_CTRL_CH0_IN0, ESP_NOSIG) + +#define PCNT0_CH0CTRL_GPIO8 \ + ESP32_PINMUX(8, ESP_PCNT_CTRL_CH0_IN0, ESP_NOSIG) + +#define PCNT0_CH0CTRL_GPIO9 \ + ESP32_PINMUX(9, ESP_PCNT_CTRL_CH0_IN0, ESP_NOSIG) + +#define PCNT0_CH0CTRL_GPIO10 \ + ESP32_PINMUX(10, ESP_PCNT_CTRL_CH0_IN0, ESP_NOSIG) + +#define PCNT0_CH0CTRL_GPIO11 \ + ESP32_PINMUX(11, ESP_PCNT_CTRL_CH0_IN0, ESP_NOSIG) + +#define PCNT0_CH0CTRL_GPIO12 \ + ESP32_PINMUX(12, ESP_PCNT_CTRL_CH0_IN0, ESP_NOSIG) + +#define PCNT0_CH0CTRL_GPIO13 \ + ESP32_PINMUX(13, ESP_PCNT_CTRL_CH0_IN0, ESP_NOSIG) + +#define PCNT0_CH0CTRL_GPIO14 \ + ESP32_PINMUX(14, ESP_PCNT_CTRL_CH0_IN0, ESP_NOSIG) + +#define PCNT0_CH0CTRL_GPIO15 \ + ESP32_PINMUX(15, ESP_PCNT_CTRL_CH0_IN0, ESP_NOSIG) + +#define PCNT0_CH0CTRL_GPIO16 \ + ESP32_PINMUX(16, ESP_PCNT_CTRL_CH0_IN0, ESP_NOSIG) + +#define PCNT0_CH0CTRL_GPIO17 \ + ESP32_PINMUX(17, ESP_PCNT_CTRL_CH0_IN0, ESP_NOSIG) + +#define PCNT0_CH0CTRL_GPIO18 \ + ESP32_PINMUX(18, ESP_PCNT_CTRL_CH0_IN0, ESP_NOSIG) + +#define PCNT0_CH0CTRL_GPIO19 \ + ESP32_PINMUX(19, ESP_PCNT_CTRL_CH0_IN0, ESP_NOSIG) + +#define PCNT0_CH0CTRL_GPIO20 \ + ESP32_PINMUX(20, ESP_PCNT_CTRL_CH0_IN0, ESP_NOSIG) + +#define PCNT0_CH0CTRL_GPIO21 \ + ESP32_PINMUX(21, ESP_PCNT_CTRL_CH0_IN0, ESP_NOSIG) + +#define PCNT0_CH0CTRL_GPIO26 \ + ESP32_PINMUX(26, ESP_PCNT_CTRL_CH0_IN0, ESP_NOSIG) + +#define PCNT0_CH0CTRL_GPIO27 \ + ESP32_PINMUX(27, ESP_PCNT_CTRL_CH0_IN0, ESP_NOSIG) + +#define PCNT0_CH0CTRL_GPIO28 \ + ESP32_PINMUX(28, ESP_PCNT_CTRL_CH0_IN0, ESP_NOSIG) + +#define PCNT0_CH0CTRL_GPIO29 \ + ESP32_PINMUX(29, ESP_PCNT_CTRL_CH0_IN0, ESP_NOSIG) + +#define PCNT0_CH0CTRL_GPIO30 \ + ESP32_PINMUX(30, ESP_PCNT_CTRL_CH0_IN0, ESP_NOSIG) + +#define PCNT0_CH0CTRL_GPIO31 \ + ESP32_PINMUX(31, ESP_PCNT_CTRL_CH0_IN0, ESP_NOSIG) + +#define PCNT0_CH0CTRL_GPIO32 \ + ESP32_PINMUX(32, ESP_PCNT_CTRL_CH0_IN0, ESP_NOSIG) + +#define PCNT0_CH0CTRL_GPIO33 \ + ESP32_PINMUX(33, ESP_PCNT_CTRL_CH0_IN0, ESP_NOSIG) + +#define PCNT0_CH0CTRL_GPIO34 \ + ESP32_PINMUX(34, ESP_PCNT_CTRL_CH0_IN0, ESP_NOSIG) + +#define PCNT0_CH0CTRL_GPIO35 \ + ESP32_PINMUX(35, ESP_PCNT_CTRL_CH0_IN0, ESP_NOSIG) + +#define PCNT0_CH0CTRL_GPIO36 \ + ESP32_PINMUX(36, ESP_PCNT_CTRL_CH0_IN0, ESP_NOSIG) + +#define PCNT0_CH0CTRL_GPIO37 \ + ESP32_PINMUX(37, ESP_PCNT_CTRL_CH0_IN0, ESP_NOSIG) + +#define PCNT0_CH0CTRL_GPIO38 \ + ESP32_PINMUX(38, ESP_PCNT_CTRL_CH0_IN0, ESP_NOSIG) + +#define PCNT0_CH0CTRL_GPIO39 \ + ESP32_PINMUX(39, ESP_PCNT_CTRL_CH0_IN0, ESP_NOSIG) + +#define PCNT0_CH0CTRL_GPIO40 \ + ESP32_PINMUX(40, ESP_PCNT_CTRL_CH0_IN0, ESP_NOSIG) + +#define PCNT0_CH0CTRL_GPIO41 \ + ESP32_PINMUX(41, ESP_PCNT_CTRL_CH0_IN0, ESP_NOSIG) + +#define PCNT0_CH0CTRL_GPIO42 \ + ESP32_PINMUX(42, ESP_PCNT_CTRL_CH0_IN0, ESP_NOSIG) + +#define PCNT0_CH0CTRL_GPIO43 \ + ESP32_PINMUX(43, ESP_PCNT_CTRL_CH0_IN0, ESP_NOSIG) + +#define PCNT0_CH0CTRL_GPIO44 \ + ESP32_PINMUX(44, ESP_PCNT_CTRL_CH0_IN0, ESP_NOSIG) + +#define PCNT0_CH0CTRL_GPIO45 \ + ESP32_PINMUX(45, ESP_PCNT_CTRL_CH0_IN0, ESP_NOSIG) + +#define PCNT0_CH0CTRL_GPIO46 \ + ESP32_PINMUX(46, ESP_PCNT_CTRL_CH0_IN0, ESP_NOSIG) + +#define PCNT0_CH0CTRL_GPIO47 \ + ESP32_PINMUX(47, ESP_PCNT_CTRL_CH0_IN0, ESP_NOSIG) + +#define PCNT0_CH0CTRL_GPIO48 \ + ESP32_PINMUX(48, ESP_PCNT_CTRL_CH0_IN0, ESP_NOSIG) + +/* PCNT0_CH0SIG */ +#define PCNT0_CH0SIG_GPIO0 \ + ESP32_PINMUX(0, ESP_PCNT_SIG_CH0_IN0, ESP_NOSIG) + +#define PCNT0_CH0SIG_GPIO1 \ + ESP32_PINMUX(1, ESP_PCNT_SIG_CH0_IN0, ESP_NOSIG) + +#define PCNT0_CH0SIG_GPIO2 \ + ESP32_PINMUX(2, ESP_PCNT_SIG_CH0_IN0, ESP_NOSIG) + +#define PCNT0_CH0SIG_GPIO3 \ + ESP32_PINMUX(3, ESP_PCNT_SIG_CH0_IN0, ESP_NOSIG) + +#define PCNT0_CH0SIG_GPIO4 \ + ESP32_PINMUX(4, ESP_PCNT_SIG_CH0_IN0, ESP_NOSIG) + +#define PCNT0_CH0SIG_GPIO5 \ + ESP32_PINMUX(5, ESP_PCNT_SIG_CH0_IN0, ESP_NOSIG) + +#define PCNT0_CH0SIG_GPIO6 \ + ESP32_PINMUX(6, ESP_PCNT_SIG_CH0_IN0, ESP_NOSIG) + +#define PCNT0_CH0SIG_GPIO7 \ + ESP32_PINMUX(7, ESP_PCNT_SIG_CH0_IN0, ESP_NOSIG) + +#define PCNT0_CH0SIG_GPIO8 \ + ESP32_PINMUX(8, ESP_PCNT_SIG_CH0_IN0, ESP_NOSIG) + +#define PCNT0_CH0SIG_GPIO9 \ + ESP32_PINMUX(9, ESP_PCNT_SIG_CH0_IN0, ESP_NOSIG) + +#define PCNT0_CH0SIG_GPIO10 \ + ESP32_PINMUX(10, ESP_PCNT_SIG_CH0_IN0, ESP_NOSIG) + +#define PCNT0_CH0SIG_GPIO11 \ + ESP32_PINMUX(11, ESP_PCNT_SIG_CH0_IN0, ESP_NOSIG) + +#define PCNT0_CH0SIG_GPIO12 \ + ESP32_PINMUX(12, ESP_PCNT_SIG_CH0_IN0, ESP_NOSIG) + +#define PCNT0_CH0SIG_GPIO13 \ + ESP32_PINMUX(13, ESP_PCNT_SIG_CH0_IN0, ESP_NOSIG) + +#define PCNT0_CH0SIG_GPIO14 \ + ESP32_PINMUX(14, ESP_PCNT_SIG_CH0_IN0, ESP_NOSIG) + +#define PCNT0_CH0SIG_GPIO15 \ + ESP32_PINMUX(15, ESP_PCNT_SIG_CH0_IN0, ESP_NOSIG) + +#define PCNT0_CH0SIG_GPIO16 \ + ESP32_PINMUX(16, ESP_PCNT_SIG_CH0_IN0, ESP_NOSIG) + +#define PCNT0_CH0SIG_GPIO17 \ + ESP32_PINMUX(17, ESP_PCNT_SIG_CH0_IN0, ESP_NOSIG) + +#define PCNT0_CH0SIG_GPIO18 \ + ESP32_PINMUX(18, ESP_PCNT_SIG_CH0_IN0, ESP_NOSIG) + +#define PCNT0_CH0SIG_GPIO19 \ + ESP32_PINMUX(19, ESP_PCNT_SIG_CH0_IN0, ESP_NOSIG) + +#define PCNT0_CH0SIG_GPIO20 \ + ESP32_PINMUX(20, ESP_PCNT_SIG_CH0_IN0, ESP_NOSIG) + +#define PCNT0_CH0SIG_GPIO21 \ + ESP32_PINMUX(21, ESP_PCNT_SIG_CH0_IN0, ESP_NOSIG) + +#define PCNT0_CH0SIG_GPIO26 \ + ESP32_PINMUX(26, ESP_PCNT_SIG_CH0_IN0, ESP_NOSIG) + +#define PCNT0_CH0SIG_GPIO27 \ + ESP32_PINMUX(27, ESP_PCNT_SIG_CH0_IN0, ESP_NOSIG) + +#define PCNT0_CH0SIG_GPIO28 \ + ESP32_PINMUX(28, ESP_PCNT_SIG_CH0_IN0, ESP_NOSIG) + +#define PCNT0_CH0SIG_GPIO29 \ + ESP32_PINMUX(29, ESP_PCNT_SIG_CH0_IN0, ESP_NOSIG) + +#define PCNT0_CH0SIG_GPIO30 \ + ESP32_PINMUX(30, ESP_PCNT_SIG_CH0_IN0, ESP_NOSIG) + +#define PCNT0_CH0SIG_GPIO31 \ + ESP32_PINMUX(31, ESP_PCNT_SIG_CH0_IN0, ESP_NOSIG) + +#define PCNT0_CH0SIG_GPIO32 \ + ESP32_PINMUX(32, ESP_PCNT_SIG_CH0_IN0, ESP_NOSIG) + +#define PCNT0_CH0SIG_GPIO33 \ + ESP32_PINMUX(33, ESP_PCNT_SIG_CH0_IN0, ESP_NOSIG) + +#define PCNT0_CH0SIG_GPIO34 \ + ESP32_PINMUX(34, ESP_PCNT_SIG_CH0_IN0, ESP_NOSIG) + +#define PCNT0_CH0SIG_GPIO35 \ + ESP32_PINMUX(35, ESP_PCNT_SIG_CH0_IN0, ESP_NOSIG) + +#define PCNT0_CH0SIG_GPIO36 \ + ESP32_PINMUX(36, ESP_PCNT_SIG_CH0_IN0, ESP_NOSIG) + +#define PCNT0_CH0SIG_GPIO37 \ + ESP32_PINMUX(37, ESP_PCNT_SIG_CH0_IN0, ESP_NOSIG) + +#define PCNT0_CH0SIG_GPIO38 \ + ESP32_PINMUX(38, ESP_PCNT_SIG_CH0_IN0, ESP_NOSIG) + +#define PCNT0_CH0SIG_GPIO39 \ + ESP32_PINMUX(39, ESP_PCNT_SIG_CH0_IN0, ESP_NOSIG) + +#define PCNT0_CH0SIG_GPIO40 \ + ESP32_PINMUX(40, ESP_PCNT_SIG_CH0_IN0, ESP_NOSIG) + +#define PCNT0_CH0SIG_GPIO41 \ + ESP32_PINMUX(41, ESP_PCNT_SIG_CH0_IN0, ESP_NOSIG) + +#define PCNT0_CH0SIG_GPIO42 \ + ESP32_PINMUX(42, ESP_PCNT_SIG_CH0_IN0, ESP_NOSIG) + +#define PCNT0_CH0SIG_GPIO43 \ + ESP32_PINMUX(43, ESP_PCNT_SIG_CH0_IN0, ESP_NOSIG) + +#define PCNT0_CH0SIG_GPIO44 \ + ESP32_PINMUX(44, ESP_PCNT_SIG_CH0_IN0, ESP_NOSIG) + +#define PCNT0_CH0SIG_GPIO45 \ + ESP32_PINMUX(45, ESP_PCNT_SIG_CH0_IN0, ESP_NOSIG) + +#define PCNT0_CH0SIG_GPIO46 \ + ESP32_PINMUX(46, ESP_PCNT_SIG_CH0_IN0, ESP_NOSIG) + +#define PCNT0_CH0SIG_GPIO47 \ + ESP32_PINMUX(47, ESP_PCNT_SIG_CH0_IN0, ESP_NOSIG) + +#define PCNT0_CH0SIG_GPIO48 \ + ESP32_PINMUX(48, ESP_PCNT_SIG_CH0_IN0, ESP_NOSIG) + +/* PCNT0_CH1CTRL */ +#define PCNT0_CH1CTRL_GPIO0 \ + ESP32_PINMUX(0, ESP_PCNT_CTRL_CH1_IN0, ESP_NOSIG) + +#define PCNT0_CH1CTRL_GPIO1 \ + ESP32_PINMUX(1, ESP_PCNT_CTRL_CH1_IN0, ESP_NOSIG) + +#define PCNT0_CH1CTRL_GPIO2 \ + ESP32_PINMUX(2, ESP_PCNT_CTRL_CH1_IN0, ESP_NOSIG) + +#define PCNT0_CH1CTRL_GPIO3 \ + ESP32_PINMUX(3, ESP_PCNT_CTRL_CH1_IN0, ESP_NOSIG) + +#define PCNT0_CH1CTRL_GPIO4 \ + ESP32_PINMUX(4, ESP_PCNT_CTRL_CH1_IN0, ESP_NOSIG) + +#define PCNT0_CH1CTRL_GPIO5 \ + ESP32_PINMUX(5, ESP_PCNT_CTRL_CH1_IN0, ESP_NOSIG) + +#define PCNT0_CH1CTRL_GPIO6 \ + ESP32_PINMUX(6, ESP_PCNT_CTRL_CH1_IN0, ESP_NOSIG) + +#define PCNT0_CH1CTRL_GPIO7 \ + ESP32_PINMUX(7, ESP_PCNT_CTRL_CH1_IN0, ESP_NOSIG) + +#define PCNT0_CH1CTRL_GPIO8 \ + ESP32_PINMUX(8, ESP_PCNT_CTRL_CH1_IN0, ESP_NOSIG) + +#define PCNT0_CH1CTRL_GPIO9 \ + ESP32_PINMUX(9, ESP_PCNT_CTRL_CH1_IN0, ESP_NOSIG) + +#define PCNT0_CH1CTRL_GPIO10 \ + ESP32_PINMUX(10, ESP_PCNT_CTRL_CH1_IN0, ESP_NOSIG) + +#define PCNT0_CH1CTRL_GPIO11 \ + ESP32_PINMUX(11, ESP_PCNT_CTRL_CH1_IN0, ESP_NOSIG) + +#define PCNT0_CH1CTRL_GPIO12 \ + ESP32_PINMUX(12, ESP_PCNT_CTRL_CH1_IN0, ESP_NOSIG) + +#define PCNT0_CH1CTRL_GPIO13 \ + ESP32_PINMUX(13, ESP_PCNT_CTRL_CH1_IN0, ESP_NOSIG) + +#define PCNT0_CH1CTRL_GPIO14 \ + ESP32_PINMUX(14, ESP_PCNT_CTRL_CH1_IN0, ESP_NOSIG) + +#define PCNT0_CH1CTRL_GPIO15 \ + ESP32_PINMUX(15, ESP_PCNT_CTRL_CH1_IN0, ESP_NOSIG) + +#define PCNT0_CH1CTRL_GPIO16 \ + ESP32_PINMUX(16, ESP_PCNT_CTRL_CH1_IN0, ESP_NOSIG) + +#define PCNT0_CH1CTRL_GPIO17 \ + ESP32_PINMUX(17, ESP_PCNT_CTRL_CH1_IN0, ESP_NOSIG) + +#define PCNT0_CH1CTRL_GPIO18 \ + ESP32_PINMUX(18, ESP_PCNT_CTRL_CH1_IN0, ESP_NOSIG) + +#define PCNT0_CH1CTRL_GPIO19 \ + ESP32_PINMUX(19, ESP_PCNT_CTRL_CH1_IN0, ESP_NOSIG) + +#define PCNT0_CH1CTRL_GPIO20 \ + ESP32_PINMUX(20, ESP_PCNT_CTRL_CH1_IN0, ESP_NOSIG) + +#define PCNT0_CH1CTRL_GPIO21 \ + ESP32_PINMUX(21, ESP_PCNT_CTRL_CH1_IN0, ESP_NOSIG) + +#define PCNT0_CH1CTRL_GPIO26 \ + ESP32_PINMUX(26, ESP_PCNT_CTRL_CH1_IN0, ESP_NOSIG) + +#define PCNT0_CH1CTRL_GPIO27 \ + ESP32_PINMUX(27, ESP_PCNT_CTRL_CH1_IN0, ESP_NOSIG) + +#define PCNT0_CH1CTRL_GPIO28 \ + ESP32_PINMUX(28, ESP_PCNT_CTRL_CH1_IN0, ESP_NOSIG) + +#define PCNT0_CH1CTRL_GPIO29 \ + ESP32_PINMUX(29, ESP_PCNT_CTRL_CH1_IN0, ESP_NOSIG) + +#define PCNT0_CH1CTRL_GPIO30 \ + ESP32_PINMUX(30, ESP_PCNT_CTRL_CH1_IN0, ESP_NOSIG) + +#define PCNT0_CH1CTRL_GPIO31 \ + ESP32_PINMUX(31, ESP_PCNT_CTRL_CH1_IN0, ESP_NOSIG) + +#define PCNT0_CH1CTRL_GPIO32 \ + ESP32_PINMUX(32, ESP_PCNT_CTRL_CH1_IN0, ESP_NOSIG) + +#define PCNT0_CH1CTRL_GPIO33 \ + ESP32_PINMUX(33, ESP_PCNT_CTRL_CH1_IN0, ESP_NOSIG) + +#define PCNT0_CH1CTRL_GPIO34 \ + ESP32_PINMUX(34, ESP_PCNT_CTRL_CH1_IN0, ESP_NOSIG) + +#define PCNT0_CH1CTRL_GPIO35 \ + ESP32_PINMUX(35, ESP_PCNT_CTRL_CH1_IN0, ESP_NOSIG) + +#define PCNT0_CH1CTRL_GPIO36 \ + ESP32_PINMUX(36, ESP_PCNT_CTRL_CH1_IN0, ESP_NOSIG) + +#define PCNT0_CH1CTRL_GPIO37 \ + ESP32_PINMUX(37, ESP_PCNT_CTRL_CH1_IN0, ESP_NOSIG) + +#define PCNT0_CH1CTRL_GPIO38 \ + ESP32_PINMUX(38, ESP_PCNT_CTRL_CH1_IN0, ESP_NOSIG) + +#define PCNT0_CH1CTRL_GPIO39 \ + ESP32_PINMUX(39, ESP_PCNT_CTRL_CH1_IN0, ESP_NOSIG) + +#define PCNT0_CH1CTRL_GPIO40 \ + ESP32_PINMUX(40, ESP_PCNT_CTRL_CH1_IN0, ESP_NOSIG) + +#define PCNT0_CH1CTRL_GPIO41 \ + ESP32_PINMUX(41, ESP_PCNT_CTRL_CH1_IN0, ESP_NOSIG) + +#define PCNT0_CH1CTRL_GPIO42 \ + ESP32_PINMUX(42, ESP_PCNT_CTRL_CH1_IN0, ESP_NOSIG) + +#define PCNT0_CH1CTRL_GPIO43 \ + ESP32_PINMUX(43, ESP_PCNT_CTRL_CH1_IN0, ESP_NOSIG) + +#define PCNT0_CH1CTRL_GPIO44 \ + ESP32_PINMUX(44, ESP_PCNT_CTRL_CH1_IN0, ESP_NOSIG) + +#define PCNT0_CH1CTRL_GPIO45 \ + ESP32_PINMUX(45, ESP_PCNT_CTRL_CH1_IN0, ESP_NOSIG) + +#define PCNT0_CH1CTRL_GPIO46 \ + ESP32_PINMUX(46, ESP_PCNT_CTRL_CH1_IN0, ESP_NOSIG) + +#define PCNT0_CH1CTRL_GPIO47 \ + ESP32_PINMUX(47, ESP_PCNT_CTRL_CH1_IN0, ESP_NOSIG) + +#define PCNT0_CH1CTRL_GPIO48 \ + ESP32_PINMUX(48, ESP_PCNT_CTRL_CH1_IN0, ESP_NOSIG) + +/* PCNT0_CH1SIG */ +#define PCNT0_CH1SIG_GPIO0 \ + ESP32_PINMUX(0, ESP_PCNT_SIG_CH1_IN0, ESP_NOSIG) + +#define PCNT0_CH1SIG_GPIO1 \ + ESP32_PINMUX(1, ESP_PCNT_SIG_CH1_IN0, ESP_NOSIG) + +#define PCNT0_CH1SIG_GPIO2 \ + ESP32_PINMUX(2, ESP_PCNT_SIG_CH1_IN0, ESP_NOSIG) + +#define PCNT0_CH1SIG_GPIO3 \ + ESP32_PINMUX(3, ESP_PCNT_SIG_CH1_IN0, ESP_NOSIG) + +#define PCNT0_CH1SIG_GPIO4 \ + ESP32_PINMUX(4, ESP_PCNT_SIG_CH1_IN0, ESP_NOSIG) + +#define PCNT0_CH1SIG_GPIO5 \ + ESP32_PINMUX(5, ESP_PCNT_SIG_CH1_IN0, ESP_NOSIG) + +#define PCNT0_CH1SIG_GPIO6 \ + ESP32_PINMUX(6, ESP_PCNT_SIG_CH1_IN0, ESP_NOSIG) + +#define PCNT0_CH1SIG_GPIO7 \ + ESP32_PINMUX(7, ESP_PCNT_SIG_CH1_IN0, ESP_NOSIG) + +#define PCNT0_CH1SIG_GPIO8 \ + ESP32_PINMUX(8, ESP_PCNT_SIG_CH1_IN0, ESP_NOSIG) + +#define PCNT0_CH1SIG_GPIO9 \ + ESP32_PINMUX(9, ESP_PCNT_SIG_CH1_IN0, ESP_NOSIG) + +#define PCNT0_CH1SIG_GPIO10 \ + ESP32_PINMUX(10, ESP_PCNT_SIG_CH1_IN0, ESP_NOSIG) + +#define PCNT0_CH1SIG_GPIO11 \ + ESP32_PINMUX(11, ESP_PCNT_SIG_CH1_IN0, ESP_NOSIG) + +#define PCNT0_CH1SIG_GPIO12 \ + ESP32_PINMUX(12, ESP_PCNT_SIG_CH1_IN0, ESP_NOSIG) + +#define PCNT0_CH1SIG_GPIO13 \ + ESP32_PINMUX(13, ESP_PCNT_SIG_CH1_IN0, ESP_NOSIG) + +#define PCNT0_CH1SIG_GPIO14 \ + ESP32_PINMUX(14, ESP_PCNT_SIG_CH1_IN0, ESP_NOSIG) + +#define PCNT0_CH1SIG_GPIO15 \ + ESP32_PINMUX(15, ESP_PCNT_SIG_CH1_IN0, ESP_NOSIG) + +#define PCNT0_CH1SIG_GPIO16 \ + ESP32_PINMUX(16, ESP_PCNT_SIG_CH1_IN0, ESP_NOSIG) + +#define PCNT0_CH1SIG_GPIO17 \ + ESP32_PINMUX(17, ESP_PCNT_SIG_CH1_IN0, ESP_NOSIG) + +#define PCNT0_CH1SIG_GPIO18 \ + ESP32_PINMUX(18, ESP_PCNT_SIG_CH1_IN0, ESP_NOSIG) + +#define PCNT0_CH1SIG_GPIO19 \ + ESP32_PINMUX(19, ESP_PCNT_SIG_CH1_IN0, ESP_NOSIG) + +#define PCNT0_CH1SIG_GPIO20 \ + ESP32_PINMUX(20, ESP_PCNT_SIG_CH1_IN0, ESP_NOSIG) + +#define PCNT0_CH1SIG_GPIO21 \ + ESP32_PINMUX(21, ESP_PCNT_SIG_CH1_IN0, ESP_NOSIG) + +#define PCNT0_CH1SIG_GPIO26 \ + ESP32_PINMUX(26, ESP_PCNT_SIG_CH1_IN0, ESP_NOSIG) + +#define PCNT0_CH1SIG_GPIO27 \ + ESP32_PINMUX(27, ESP_PCNT_SIG_CH1_IN0, ESP_NOSIG) + +#define PCNT0_CH1SIG_GPIO28 \ + ESP32_PINMUX(28, ESP_PCNT_SIG_CH1_IN0, ESP_NOSIG) + +#define PCNT0_CH1SIG_GPIO29 \ + ESP32_PINMUX(29, ESP_PCNT_SIG_CH1_IN0, ESP_NOSIG) + +#define PCNT0_CH1SIG_GPIO30 \ + ESP32_PINMUX(30, ESP_PCNT_SIG_CH1_IN0, ESP_NOSIG) + +#define PCNT0_CH1SIG_GPIO31 \ + ESP32_PINMUX(31, ESP_PCNT_SIG_CH1_IN0, ESP_NOSIG) + +#define PCNT0_CH1SIG_GPIO32 \ + ESP32_PINMUX(32, ESP_PCNT_SIG_CH1_IN0, ESP_NOSIG) + +#define PCNT0_CH1SIG_GPIO33 \ + ESP32_PINMUX(33, ESP_PCNT_SIG_CH1_IN0, ESP_NOSIG) + +#define PCNT0_CH1SIG_GPIO34 \ + ESP32_PINMUX(34, ESP_PCNT_SIG_CH1_IN0, ESP_NOSIG) + +#define PCNT0_CH1SIG_GPIO35 \ + ESP32_PINMUX(35, ESP_PCNT_SIG_CH1_IN0, ESP_NOSIG) + +#define PCNT0_CH1SIG_GPIO36 \ + ESP32_PINMUX(36, ESP_PCNT_SIG_CH1_IN0, ESP_NOSIG) + +#define PCNT0_CH1SIG_GPIO37 \ + ESP32_PINMUX(37, ESP_PCNT_SIG_CH1_IN0, ESP_NOSIG) + +#define PCNT0_CH1SIG_GPIO38 \ + ESP32_PINMUX(38, ESP_PCNT_SIG_CH1_IN0, ESP_NOSIG) + +#define PCNT0_CH1SIG_GPIO39 \ + ESP32_PINMUX(39, ESP_PCNT_SIG_CH1_IN0, ESP_NOSIG) + +#define PCNT0_CH1SIG_GPIO40 \ + ESP32_PINMUX(40, ESP_PCNT_SIG_CH1_IN0, ESP_NOSIG) + +#define PCNT0_CH1SIG_GPIO41 \ + ESP32_PINMUX(41, ESP_PCNT_SIG_CH1_IN0, ESP_NOSIG) + +#define PCNT0_CH1SIG_GPIO42 \ + ESP32_PINMUX(42, ESP_PCNT_SIG_CH1_IN0, ESP_NOSIG) + +#define PCNT0_CH1SIG_GPIO43 \ + ESP32_PINMUX(43, ESP_PCNT_SIG_CH1_IN0, ESP_NOSIG) + +#define PCNT0_CH1SIG_GPIO44 \ + ESP32_PINMUX(44, ESP_PCNT_SIG_CH1_IN0, ESP_NOSIG) + +#define PCNT0_CH1SIG_GPIO45 \ + ESP32_PINMUX(45, ESP_PCNT_SIG_CH1_IN0, ESP_NOSIG) + +#define PCNT0_CH1SIG_GPIO46 \ + ESP32_PINMUX(46, ESP_PCNT_SIG_CH1_IN0, ESP_NOSIG) + +#define PCNT0_CH1SIG_GPIO47 \ + ESP32_PINMUX(47, ESP_PCNT_SIG_CH1_IN0, ESP_NOSIG) + +#define PCNT0_CH1SIG_GPIO48 \ + ESP32_PINMUX(48, ESP_PCNT_SIG_CH1_IN0, ESP_NOSIG) + +/* PCNT1_CH0CTRL */ +#define PCNT1_CH0CTRL_GPIO0 \ + ESP32_PINMUX(0, ESP_PCNT_CTRL_CH0_IN1, ESP_NOSIG) + +#define PCNT1_CH0CTRL_GPIO1 \ + ESP32_PINMUX(1, ESP_PCNT_CTRL_CH0_IN1, ESP_NOSIG) + +#define PCNT1_CH0CTRL_GPIO2 \ + ESP32_PINMUX(2, ESP_PCNT_CTRL_CH0_IN1, ESP_NOSIG) + +#define PCNT1_CH0CTRL_GPIO3 \ + ESP32_PINMUX(3, ESP_PCNT_CTRL_CH0_IN1, ESP_NOSIG) + +#define PCNT1_CH0CTRL_GPIO4 \ + ESP32_PINMUX(4, ESP_PCNT_CTRL_CH0_IN1, ESP_NOSIG) + +#define PCNT1_CH0CTRL_GPIO5 \ + ESP32_PINMUX(5, ESP_PCNT_CTRL_CH0_IN1, ESP_NOSIG) + +#define PCNT1_CH0CTRL_GPIO6 \ + ESP32_PINMUX(6, ESP_PCNT_CTRL_CH0_IN1, ESP_NOSIG) + +#define PCNT1_CH0CTRL_GPIO7 \ + ESP32_PINMUX(7, ESP_PCNT_CTRL_CH0_IN1, ESP_NOSIG) + +#define PCNT1_CH0CTRL_GPIO8 \ + ESP32_PINMUX(8, ESP_PCNT_CTRL_CH0_IN1, ESP_NOSIG) + +#define PCNT1_CH0CTRL_GPIO9 \ + ESP32_PINMUX(9, ESP_PCNT_CTRL_CH0_IN1, ESP_NOSIG) + +#define PCNT1_CH0CTRL_GPIO10 \ + ESP32_PINMUX(10, ESP_PCNT_CTRL_CH0_IN1, ESP_NOSIG) + +#define PCNT1_CH0CTRL_GPIO11 \ + ESP32_PINMUX(11, ESP_PCNT_CTRL_CH0_IN1, ESP_NOSIG) + +#define PCNT1_CH0CTRL_GPIO12 \ + ESP32_PINMUX(12, ESP_PCNT_CTRL_CH0_IN1, ESP_NOSIG) + +#define PCNT1_CH0CTRL_GPIO13 \ + ESP32_PINMUX(13, ESP_PCNT_CTRL_CH0_IN1, ESP_NOSIG) + +#define PCNT1_CH0CTRL_GPIO14 \ + ESP32_PINMUX(14, ESP_PCNT_CTRL_CH0_IN1, ESP_NOSIG) + +#define PCNT1_CH0CTRL_GPIO15 \ + ESP32_PINMUX(15, ESP_PCNT_CTRL_CH0_IN1, ESP_NOSIG) + +#define PCNT1_CH0CTRL_GPIO16 \ + ESP32_PINMUX(16, ESP_PCNT_CTRL_CH0_IN1, ESP_NOSIG) + +#define PCNT1_CH0CTRL_GPIO17 \ + ESP32_PINMUX(17, ESP_PCNT_CTRL_CH0_IN1, ESP_NOSIG) + +#define PCNT1_CH0CTRL_GPIO18 \ + ESP32_PINMUX(18, ESP_PCNT_CTRL_CH0_IN1, ESP_NOSIG) + +#define PCNT1_CH0CTRL_GPIO19 \ + ESP32_PINMUX(19, ESP_PCNT_CTRL_CH0_IN1, ESP_NOSIG) + +#define PCNT1_CH0CTRL_GPIO20 \ + ESP32_PINMUX(20, ESP_PCNT_CTRL_CH0_IN1, ESP_NOSIG) + +#define PCNT1_CH0CTRL_GPIO21 \ + ESP32_PINMUX(21, ESP_PCNT_CTRL_CH0_IN1, ESP_NOSIG) + +#define PCNT1_CH0CTRL_GPIO26 \ + ESP32_PINMUX(26, ESP_PCNT_CTRL_CH0_IN1, ESP_NOSIG) + +#define PCNT1_CH0CTRL_GPIO27 \ + ESP32_PINMUX(27, ESP_PCNT_CTRL_CH0_IN1, ESP_NOSIG) + +#define PCNT1_CH0CTRL_GPIO28 \ + ESP32_PINMUX(28, ESP_PCNT_CTRL_CH0_IN1, ESP_NOSIG) + +#define PCNT1_CH0CTRL_GPIO29 \ + ESP32_PINMUX(29, ESP_PCNT_CTRL_CH0_IN1, ESP_NOSIG) + +#define PCNT1_CH0CTRL_GPIO30 \ + ESP32_PINMUX(30, ESP_PCNT_CTRL_CH0_IN1, ESP_NOSIG) + +#define PCNT1_CH0CTRL_GPIO31 \ + ESP32_PINMUX(31, ESP_PCNT_CTRL_CH0_IN1, ESP_NOSIG) + +#define PCNT1_CH0CTRL_GPIO32 \ + ESP32_PINMUX(32, ESP_PCNT_CTRL_CH0_IN1, ESP_NOSIG) + +#define PCNT1_CH0CTRL_GPIO33 \ + ESP32_PINMUX(33, ESP_PCNT_CTRL_CH0_IN1, ESP_NOSIG) + +#define PCNT1_CH0CTRL_GPIO34 \ + ESP32_PINMUX(34, ESP_PCNT_CTRL_CH0_IN1, ESP_NOSIG) + +#define PCNT1_CH0CTRL_GPIO35 \ + ESP32_PINMUX(35, ESP_PCNT_CTRL_CH0_IN1, ESP_NOSIG) + +#define PCNT1_CH0CTRL_GPIO36 \ + ESP32_PINMUX(36, ESP_PCNT_CTRL_CH0_IN1, ESP_NOSIG) + +#define PCNT1_CH0CTRL_GPIO37 \ + ESP32_PINMUX(37, ESP_PCNT_CTRL_CH0_IN1, ESP_NOSIG) + +#define PCNT1_CH0CTRL_GPIO38 \ + ESP32_PINMUX(38, ESP_PCNT_CTRL_CH0_IN1, ESP_NOSIG) + +#define PCNT1_CH0CTRL_GPIO39 \ + ESP32_PINMUX(39, ESP_PCNT_CTRL_CH0_IN1, ESP_NOSIG) + +#define PCNT1_CH0CTRL_GPIO40 \ + ESP32_PINMUX(40, ESP_PCNT_CTRL_CH0_IN1, ESP_NOSIG) + +#define PCNT1_CH0CTRL_GPIO41 \ + ESP32_PINMUX(41, ESP_PCNT_CTRL_CH0_IN1, ESP_NOSIG) + +#define PCNT1_CH0CTRL_GPIO42 \ + ESP32_PINMUX(42, ESP_PCNT_CTRL_CH0_IN1, ESP_NOSIG) + +#define PCNT1_CH0CTRL_GPIO43 \ + ESP32_PINMUX(43, ESP_PCNT_CTRL_CH0_IN1, ESP_NOSIG) + +#define PCNT1_CH0CTRL_GPIO44 \ + ESP32_PINMUX(44, ESP_PCNT_CTRL_CH0_IN1, ESP_NOSIG) + +#define PCNT1_CH0CTRL_GPIO45 \ + ESP32_PINMUX(45, ESP_PCNT_CTRL_CH0_IN1, ESP_NOSIG) + +#define PCNT1_CH0CTRL_GPIO46 \ + ESP32_PINMUX(46, ESP_PCNT_CTRL_CH0_IN1, ESP_NOSIG) + +#define PCNT1_CH0CTRL_GPIO47 \ + ESP32_PINMUX(47, ESP_PCNT_CTRL_CH0_IN1, ESP_NOSIG) + +#define PCNT1_CH0CTRL_GPIO48 \ + ESP32_PINMUX(48, ESP_PCNT_CTRL_CH0_IN1, ESP_NOSIG) + +/* PCNT1_CH0SIG */ +#define PCNT1_CH0SIG_GPIO0 \ + ESP32_PINMUX(0, ESP_PCNT_SIG_CH0_IN1, ESP_NOSIG) + +#define PCNT1_CH0SIG_GPIO1 \ + ESP32_PINMUX(1, ESP_PCNT_SIG_CH0_IN1, ESP_NOSIG) + +#define PCNT1_CH0SIG_GPIO2 \ + ESP32_PINMUX(2, ESP_PCNT_SIG_CH0_IN1, ESP_NOSIG) + +#define PCNT1_CH0SIG_GPIO3 \ + ESP32_PINMUX(3, ESP_PCNT_SIG_CH0_IN1, ESP_NOSIG) + +#define PCNT1_CH0SIG_GPIO4 \ + ESP32_PINMUX(4, ESP_PCNT_SIG_CH0_IN1, ESP_NOSIG) + +#define PCNT1_CH0SIG_GPIO5 \ + ESP32_PINMUX(5, ESP_PCNT_SIG_CH0_IN1, ESP_NOSIG) + +#define PCNT1_CH0SIG_GPIO6 \ + ESP32_PINMUX(6, ESP_PCNT_SIG_CH0_IN1, ESP_NOSIG) + +#define PCNT1_CH0SIG_GPIO7 \ + ESP32_PINMUX(7, ESP_PCNT_SIG_CH0_IN1, ESP_NOSIG) + +#define PCNT1_CH0SIG_GPIO8 \ + ESP32_PINMUX(8, ESP_PCNT_SIG_CH0_IN1, ESP_NOSIG) + +#define PCNT1_CH0SIG_GPIO9 \ + ESP32_PINMUX(9, ESP_PCNT_SIG_CH0_IN1, ESP_NOSIG) + +#define PCNT1_CH0SIG_GPIO10 \ + ESP32_PINMUX(10, ESP_PCNT_SIG_CH0_IN1, ESP_NOSIG) + +#define PCNT1_CH0SIG_GPIO11 \ + ESP32_PINMUX(11, ESP_PCNT_SIG_CH0_IN1, ESP_NOSIG) + +#define PCNT1_CH0SIG_GPIO12 \ + ESP32_PINMUX(12, ESP_PCNT_SIG_CH0_IN1, ESP_NOSIG) + +#define PCNT1_CH0SIG_GPIO13 \ + ESP32_PINMUX(13, ESP_PCNT_SIG_CH0_IN1, ESP_NOSIG) + +#define PCNT1_CH0SIG_GPIO14 \ + ESP32_PINMUX(14, ESP_PCNT_SIG_CH0_IN1, ESP_NOSIG) + +#define PCNT1_CH0SIG_GPIO15 \ + ESP32_PINMUX(15, ESP_PCNT_SIG_CH0_IN1, ESP_NOSIG) + +#define PCNT1_CH0SIG_GPIO16 \ + ESP32_PINMUX(16, ESP_PCNT_SIG_CH0_IN1, ESP_NOSIG) + +#define PCNT1_CH0SIG_GPIO17 \ + ESP32_PINMUX(17, ESP_PCNT_SIG_CH0_IN1, ESP_NOSIG) + +#define PCNT1_CH0SIG_GPIO18 \ + ESP32_PINMUX(18, ESP_PCNT_SIG_CH0_IN1, ESP_NOSIG) + +#define PCNT1_CH0SIG_GPIO19 \ + ESP32_PINMUX(19, ESP_PCNT_SIG_CH0_IN1, ESP_NOSIG) + +#define PCNT1_CH0SIG_GPIO20 \ + ESP32_PINMUX(20, ESP_PCNT_SIG_CH0_IN1, ESP_NOSIG) + +#define PCNT1_CH0SIG_GPIO21 \ + ESP32_PINMUX(21, ESP_PCNT_SIG_CH0_IN1, ESP_NOSIG) + +#define PCNT1_CH0SIG_GPIO26 \ + ESP32_PINMUX(26, ESP_PCNT_SIG_CH0_IN1, ESP_NOSIG) + +#define PCNT1_CH0SIG_GPIO27 \ + ESP32_PINMUX(27, ESP_PCNT_SIG_CH0_IN1, ESP_NOSIG) + +#define PCNT1_CH0SIG_GPIO28 \ + ESP32_PINMUX(28, ESP_PCNT_SIG_CH0_IN1, ESP_NOSIG) + +#define PCNT1_CH0SIG_GPIO29 \ + ESP32_PINMUX(29, ESP_PCNT_SIG_CH0_IN1, ESP_NOSIG) + +#define PCNT1_CH0SIG_GPIO30 \ + ESP32_PINMUX(30, ESP_PCNT_SIG_CH0_IN1, ESP_NOSIG) + +#define PCNT1_CH0SIG_GPIO31 \ + ESP32_PINMUX(31, ESP_PCNT_SIG_CH0_IN1, ESP_NOSIG) + +#define PCNT1_CH0SIG_GPIO32 \ + ESP32_PINMUX(32, ESP_PCNT_SIG_CH0_IN1, ESP_NOSIG) + +#define PCNT1_CH0SIG_GPIO33 \ + ESP32_PINMUX(33, ESP_PCNT_SIG_CH0_IN1, ESP_NOSIG) + +#define PCNT1_CH0SIG_GPIO34 \ + ESP32_PINMUX(34, ESP_PCNT_SIG_CH0_IN1, ESP_NOSIG) + +#define PCNT1_CH0SIG_GPIO35 \ + ESP32_PINMUX(35, ESP_PCNT_SIG_CH0_IN1, ESP_NOSIG) + +#define PCNT1_CH0SIG_GPIO36 \ + ESP32_PINMUX(36, ESP_PCNT_SIG_CH0_IN1, ESP_NOSIG) + +#define PCNT1_CH0SIG_GPIO37 \ + ESP32_PINMUX(37, ESP_PCNT_SIG_CH0_IN1, ESP_NOSIG) + +#define PCNT1_CH0SIG_GPIO38 \ + ESP32_PINMUX(38, ESP_PCNT_SIG_CH0_IN1, ESP_NOSIG) + +#define PCNT1_CH0SIG_GPIO39 \ + ESP32_PINMUX(39, ESP_PCNT_SIG_CH0_IN1, ESP_NOSIG) + +#define PCNT1_CH0SIG_GPIO40 \ + ESP32_PINMUX(40, ESP_PCNT_SIG_CH0_IN1, ESP_NOSIG) + +#define PCNT1_CH0SIG_GPIO41 \ + ESP32_PINMUX(41, ESP_PCNT_SIG_CH0_IN1, ESP_NOSIG) + +#define PCNT1_CH0SIG_GPIO42 \ + ESP32_PINMUX(42, ESP_PCNT_SIG_CH0_IN1, ESP_NOSIG) + +#define PCNT1_CH0SIG_GPIO43 \ + ESP32_PINMUX(43, ESP_PCNT_SIG_CH0_IN1, ESP_NOSIG) + +#define PCNT1_CH0SIG_GPIO44 \ + ESP32_PINMUX(44, ESP_PCNT_SIG_CH0_IN1, ESP_NOSIG) + +#define PCNT1_CH0SIG_GPIO45 \ + ESP32_PINMUX(45, ESP_PCNT_SIG_CH0_IN1, ESP_NOSIG) + +#define PCNT1_CH0SIG_GPIO46 \ + ESP32_PINMUX(46, ESP_PCNT_SIG_CH0_IN1, ESP_NOSIG) + +#define PCNT1_CH0SIG_GPIO47 \ + ESP32_PINMUX(47, ESP_PCNT_SIG_CH0_IN1, ESP_NOSIG) + +#define PCNT1_CH0SIG_GPIO48 \ + ESP32_PINMUX(48, ESP_PCNT_SIG_CH0_IN1, ESP_NOSIG) + +/* PCNT1_CH1CTRL */ +#define PCNT1_CH1CTRL_GPIO0 \ + ESP32_PINMUX(0, ESP_PCNT_CTRL_CH1_IN1, ESP_NOSIG) + +#define PCNT1_CH1CTRL_GPIO1 \ + ESP32_PINMUX(1, ESP_PCNT_CTRL_CH1_IN1, ESP_NOSIG) + +#define PCNT1_CH1CTRL_GPIO2 \ + ESP32_PINMUX(2, ESP_PCNT_CTRL_CH1_IN1, ESP_NOSIG) + +#define PCNT1_CH1CTRL_GPIO3 \ + ESP32_PINMUX(3, ESP_PCNT_CTRL_CH1_IN1, ESP_NOSIG) + +#define PCNT1_CH1CTRL_GPIO4 \ + ESP32_PINMUX(4, ESP_PCNT_CTRL_CH1_IN1, ESP_NOSIG) + +#define PCNT1_CH1CTRL_GPIO5 \ + ESP32_PINMUX(5, ESP_PCNT_CTRL_CH1_IN1, ESP_NOSIG) + +#define PCNT1_CH1CTRL_GPIO6 \ + ESP32_PINMUX(6, ESP_PCNT_CTRL_CH1_IN1, ESP_NOSIG) + +#define PCNT1_CH1CTRL_GPIO7 \ + ESP32_PINMUX(7, ESP_PCNT_CTRL_CH1_IN1, ESP_NOSIG) + +#define PCNT1_CH1CTRL_GPIO8 \ + ESP32_PINMUX(8, ESP_PCNT_CTRL_CH1_IN1, ESP_NOSIG) + +#define PCNT1_CH1CTRL_GPIO9 \ + ESP32_PINMUX(9, ESP_PCNT_CTRL_CH1_IN1, ESP_NOSIG) + +#define PCNT1_CH1CTRL_GPIO10 \ + ESP32_PINMUX(10, ESP_PCNT_CTRL_CH1_IN1, ESP_NOSIG) + +#define PCNT1_CH1CTRL_GPIO11 \ + ESP32_PINMUX(11, ESP_PCNT_CTRL_CH1_IN1, ESP_NOSIG) + +#define PCNT1_CH1CTRL_GPIO12 \ + ESP32_PINMUX(12, ESP_PCNT_CTRL_CH1_IN1, ESP_NOSIG) + +#define PCNT1_CH1CTRL_GPIO13 \ + ESP32_PINMUX(13, ESP_PCNT_CTRL_CH1_IN1, ESP_NOSIG) + +#define PCNT1_CH1CTRL_GPIO14 \ + ESP32_PINMUX(14, ESP_PCNT_CTRL_CH1_IN1, ESP_NOSIG) + +#define PCNT1_CH1CTRL_GPIO15 \ + ESP32_PINMUX(15, ESP_PCNT_CTRL_CH1_IN1, ESP_NOSIG) + +#define PCNT1_CH1CTRL_GPIO16 \ + ESP32_PINMUX(16, ESP_PCNT_CTRL_CH1_IN1, ESP_NOSIG) + +#define PCNT1_CH1CTRL_GPIO17 \ + ESP32_PINMUX(17, ESP_PCNT_CTRL_CH1_IN1, ESP_NOSIG) + +#define PCNT1_CH1CTRL_GPIO18 \ + ESP32_PINMUX(18, ESP_PCNT_CTRL_CH1_IN1, ESP_NOSIG) + +#define PCNT1_CH1CTRL_GPIO19 \ + ESP32_PINMUX(19, ESP_PCNT_CTRL_CH1_IN1, ESP_NOSIG) + +#define PCNT1_CH1CTRL_GPIO20 \ + ESP32_PINMUX(20, ESP_PCNT_CTRL_CH1_IN1, ESP_NOSIG) + +#define PCNT1_CH1CTRL_GPIO21 \ + ESP32_PINMUX(21, ESP_PCNT_CTRL_CH1_IN1, ESP_NOSIG) + +#define PCNT1_CH1CTRL_GPIO26 \ + ESP32_PINMUX(26, ESP_PCNT_CTRL_CH1_IN1, ESP_NOSIG) + +#define PCNT1_CH1CTRL_GPIO27 \ + ESP32_PINMUX(27, ESP_PCNT_CTRL_CH1_IN1, ESP_NOSIG) + +#define PCNT1_CH1CTRL_GPIO28 \ + ESP32_PINMUX(28, ESP_PCNT_CTRL_CH1_IN1, ESP_NOSIG) + +#define PCNT1_CH1CTRL_GPIO29 \ + ESP32_PINMUX(29, ESP_PCNT_CTRL_CH1_IN1, ESP_NOSIG) + +#define PCNT1_CH1CTRL_GPIO30 \ + ESP32_PINMUX(30, ESP_PCNT_CTRL_CH1_IN1, ESP_NOSIG) + +#define PCNT1_CH1CTRL_GPIO31 \ + ESP32_PINMUX(31, ESP_PCNT_CTRL_CH1_IN1, ESP_NOSIG) + +#define PCNT1_CH1CTRL_GPIO32 \ + ESP32_PINMUX(32, ESP_PCNT_CTRL_CH1_IN1, ESP_NOSIG) + +#define PCNT1_CH1CTRL_GPIO33 \ + ESP32_PINMUX(33, ESP_PCNT_CTRL_CH1_IN1, ESP_NOSIG) + +#define PCNT1_CH1CTRL_GPIO34 \ + ESP32_PINMUX(34, ESP_PCNT_CTRL_CH1_IN1, ESP_NOSIG) + +#define PCNT1_CH1CTRL_GPIO35 \ + ESP32_PINMUX(35, ESP_PCNT_CTRL_CH1_IN1, ESP_NOSIG) + +#define PCNT1_CH1CTRL_GPIO36 \ + ESP32_PINMUX(36, ESP_PCNT_CTRL_CH1_IN1, ESP_NOSIG) + +#define PCNT1_CH1CTRL_GPIO37 \ + ESP32_PINMUX(37, ESP_PCNT_CTRL_CH1_IN1, ESP_NOSIG) + +#define PCNT1_CH1CTRL_GPIO38 \ + ESP32_PINMUX(38, ESP_PCNT_CTRL_CH1_IN1, ESP_NOSIG) + +#define PCNT1_CH1CTRL_GPIO39 \ + ESP32_PINMUX(39, ESP_PCNT_CTRL_CH1_IN1, ESP_NOSIG) + +#define PCNT1_CH1CTRL_GPIO40 \ + ESP32_PINMUX(40, ESP_PCNT_CTRL_CH1_IN1, ESP_NOSIG) + +#define PCNT1_CH1CTRL_GPIO41 \ + ESP32_PINMUX(41, ESP_PCNT_CTRL_CH1_IN1, ESP_NOSIG) + +#define PCNT1_CH1CTRL_GPIO42 \ + ESP32_PINMUX(42, ESP_PCNT_CTRL_CH1_IN1, ESP_NOSIG) + +#define PCNT1_CH1CTRL_GPIO43 \ + ESP32_PINMUX(43, ESP_PCNT_CTRL_CH1_IN1, ESP_NOSIG) + +#define PCNT1_CH1CTRL_GPIO44 \ + ESP32_PINMUX(44, ESP_PCNT_CTRL_CH1_IN1, ESP_NOSIG) + +#define PCNT1_CH1CTRL_GPIO45 \ + ESP32_PINMUX(45, ESP_PCNT_CTRL_CH1_IN1, ESP_NOSIG) + +#define PCNT1_CH1CTRL_GPIO46 \ + ESP32_PINMUX(46, ESP_PCNT_CTRL_CH1_IN1, ESP_NOSIG) + +#define PCNT1_CH1CTRL_GPIO47 \ + ESP32_PINMUX(47, ESP_PCNT_CTRL_CH1_IN1, ESP_NOSIG) + +#define PCNT1_CH1CTRL_GPIO48 \ + ESP32_PINMUX(48, ESP_PCNT_CTRL_CH1_IN1, ESP_NOSIG) + +/* PCNT1_CH1SIG */ +#define PCNT1_CH1SIG_GPIO0 \ + ESP32_PINMUX(0, ESP_PCNT_SIG_CH1_IN1, ESP_NOSIG) + +#define PCNT1_CH1SIG_GPIO1 \ + ESP32_PINMUX(1, ESP_PCNT_SIG_CH1_IN1, ESP_NOSIG) + +#define PCNT1_CH1SIG_GPIO2 \ + ESP32_PINMUX(2, ESP_PCNT_SIG_CH1_IN1, ESP_NOSIG) + +#define PCNT1_CH1SIG_GPIO3 \ + ESP32_PINMUX(3, ESP_PCNT_SIG_CH1_IN1, ESP_NOSIG) + +#define PCNT1_CH1SIG_GPIO4 \ + ESP32_PINMUX(4, ESP_PCNT_SIG_CH1_IN1, ESP_NOSIG) + +#define PCNT1_CH1SIG_GPIO5 \ + ESP32_PINMUX(5, ESP_PCNT_SIG_CH1_IN1, ESP_NOSIG) + +#define PCNT1_CH1SIG_GPIO6 \ + ESP32_PINMUX(6, ESP_PCNT_SIG_CH1_IN1, ESP_NOSIG) + +#define PCNT1_CH1SIG_GPIO7 \ + ESP32_PINMUX(7, ESP_PCNT_SIG_CH1_IN1, ESP_NOSIG) + +#define PCNT1_CH1SIG_GPIO8 \ + ESP32_PINMUX(8, ESP_PCNT_SIG_CH1_IN1, ESP_NOSIG) + +#define PCNT1_CH1SIG_GPIO9 \ + ESP32_PINMUX(9, ESP_PCNT_SIG_CH1_IN1, ESP_NOSIG) + +#define PCNT1_CH1SIG_GPIO10 \ + ESP32_PINMUX(10, ESP_PCNT_SIG_CH1_IN1, ESP_NOSIG) + +#define PCNT1_CH1SIG_GPIO11 \ + ESP32_PINMUX(11, ESP_PCNT_SIG_CH1_IN1, ESP_NOSIG) + +#define PCNT1_CH1SIG_GPIO12 \ + ESP32_PINMUX(12, ESP_PCNT_SIG_CH1_IN1, ESP_NOSIG) + +#define PCNT1_CH1SIG_GPIO13 \ + ESP32_PINMUX(13, ESP_PCNT_SIG_CH1_IN1, ESP_NOSIG) + +#define PCNT1_CH1SIG_GPIO14 \ + ESP32_PINMUX(14, ESP_PCNT_SIG_CH1_IN1, ESP_NOSIG) + +#define PCNT1_CH1SIG_GPIO15 \ + ESP32_PINMUX(15, ESP_PCNT_SIG_CH1_IN1, ESP_NOSIG) + +#define PCNT1_CH1SIG_GPIO16 \ + ESP32_PINMUX(16, ESP_PCNT_SIG_CH1_IN1, ESP_NOSIG) + +#define PCNT1_CH1SIG_GPIO17 \ + ESP32_PINMUX(17, ESP_PCNT_SIG_CH1_IN1, ESP_NOSIG) + +#define PCNT1_CH1SIG_GPIO18 \ + ESP32_PINMUX(18, ESP_PCNT_SIG_CH1_IN1, ESP_NOSIG) + +#define PCNT1_CH1SIG_GPIO19 \ + ESP32_PINMUX(19, ESP_PCNT_SIG_CH1_IN1, ESP_NOSIG) + +#define PCNT1_CH1SIG_GPIO20 \ + ESP32_PINMUX(20, ESP_PCNT_SIG_CH1_IN1, ESP_NOSIG) + +#define PCNT1_CH1SIG_GPIO21 \ + ESP32_PINMUX(21, ESP_PCNT_SIG_CH1_IN1, ESP_NOSIG) + +#define PCNT1_CH1SIG_GPIO26 \ + ESP32_PINMUX(26, ESP_PCNT_SIG_CH1_IN1, ESP_NOSIG) + +#define PCNT1_CH1SIG_GPIO27 \ + ESP32_PINMUX(27, ESP_PCNT_SIG_CH1_IN1, ESP_NOSIG) + +#define PCNT1_CH1SIG_GPIO28 \ + ESP32_PINMUX(28, ESP_PCNT_SIG_CH1_IN1, ESP_NOSIG) + +#define PCNT1_CH1SIG_GPIO29 \ + ESP32_PINMUX(29, ESP_PCNT_SIG_CH1_IN1, ESP_NOSIG) + +#define PCNT1_CH1SIG_GPIO30 \ + ESP32_PINMUX(30, ESP_PCNT_SIG_CH1_IN1, ESP_NOSIG) + +#define PCNT1_CH1SIG_GPIO31 \ + ESP32_PINMUX(31, ESP_PCNT_SIG_CH1_IN1, ESP_NOSIG) + +#define PCNT1_CH1SIG_GPIO32 \ + ESP32_PINMUX(32, ESP_PCNT_SIG_CH1_IN1, ESP_NOSIG) + +#define PCNT1_CH1SIG_GPIO33 \ + ESP32_PINMUX(33, ESP_PCNT_SIG_CH1_IN1, ESP_NOSIG) + +#define PCNT1_CH1SIG_GPIO34 \ + ESP32_PINMUX(34, ESP_PCNT_SIG_CH1_IN1, ESP_NOSIG) + +#define PCNT1_CH1SIG_GPIO35 \ + ESP32_PINMUX(35, ESP_PCNT_SIG_CH1_IN1, ESP_NOSIG) + +#define PCNT1_CH1SIG_GPIO36 \ + ESP32_PINMUX(36, ESP_PCNT_SIG_CH1_IN1, ESP_NOSIG) + +#define PCNT1_CH1SIG_GPIO37 \ + ESP32_PINMUX(37, ESP_PCNT_SIG_CH1_IN1, ESP_NOSIG) + +#define PCNT1_CH1SIG_GPIO38 \ + ESP32_PINMUX(38, ESP_PCNT_SIG_CH1_IN1, ESP_NOSIG) + +#define PCNT1_CH1SIG_GPIO39 \ + ESP32_PINMUX(39, ESP_PCNT_SIG_CH1_IN1, ESP_NOSIG) + +#define PCNT1_CH1SIG_GPIO40 \ + ESP32_PINMUX(40, ESP_PCNT_SIG_CH1_IN1, ESP_NOSIG) + +#define PCNT1_CH1SIG_GPIO41 \ + ESP32_PINMUX(41, ESP_PCNT_SIG_CH1_IN1, ESP_NOSIG) + +#define PCNT1_CH1SIG_GPIO42 \ + ESP32_PINMUX(42, ESP_PCNT_SIG_CH1_IN1, ESP_NOSIG) + +#define PCNT1_CH1SIG_GPIO43 \ + ESP32_PINMUX(43, ESP_PCNT_SIG_CH1_IN1, ESP_NOSIG) + +#define PCNT1_CH1SIG_GPIO44 \ + ESP32_PINMUX(44, ESP_PCNT_SIG_CH1_IN1, ESP_NOSIG) + +#define PCNT1_CH1SIG_GPIO45 \ + ESP32_PINMUX(45, ESP_PCNT_SIG_CH1_IN1, ESP_NOSIG) + +#define PCNT1_CH1SIG_GPIO46 \ + ESP32_PINMUX(46, ESP_PCNT_SIG_CH1_IN1, ESP_NOSIG) + +#define PCNT1_CH1SIG_GPIO47 \ + ESP32_PINMUX(47, ESP_PCNT_SIG_CH1_IN1, ESP_NOSIG) + +#define PCNT1_CH1SIG_GPIO48 \ + ESP32_PINMUX(48, ESP_PCNT_SIG_CH1_IN1, ESP_NOSIG) + +/* PCNT2_CH0CTRL */ +#define PCNT2_CH0CTRL_GPIO0 \ + ESP32_PINMUX(0, ESP_PCNT_CTRL_CH0_IN2, ESP_NOSIG) + +#define PCNT2_CH0CTRL_GPIO1 \ + ESP32_PINMUX(1, ESP_PCNT_CTRL_CH0_IN2, ESP_NOSIG) + +#define PCNT2_CH0CTRL_GPIO2 \ + ESP32_PINMUX(2, ESP_PCNT_CTRL_CH0_IN2, ESP_NOSIG) + +#define PCNT2_CH0CTRL_GPIO3 \ + ESP32_PINMUX(3, ESP_PCNT_CTRL_CH0_IN2, ESP_NOSIG) + +#define PCNT2_CH0CTRL_GPIO4 \ + ESP32_PINMUX(4, ESP_PCNT_CTRL_CH0_IN2, ESP_NOSIG) + +#define PCNT2_CH0CTRL_GPIO5 \ + ESP32_PINMUX(5, ESP_PCNT_CTRL_CH0_IN2, ESP_NOSIG) + +#define PCNT2_CH0CTRL_GPIO6 \ + ESP32_PINMUX(6, ESP_PCNT_CTRL_CH0_IN2, ESP_NOSIG) + +#define PCNT2_CH0CTRL_GPIO7 \ + ESP32_PINMUX(7, ESP_PCNT_CTRL_CH0_IN2, ESP_NOSIG) + +#define PCNT2_CH0CTRL_GPIO8 \ + ESP32_PINMUX(8, ESP_PCNT_CTRL_CH0_IN2, ESP_NOSIG) + +#define PCNT2_CH0CTRL_GPIO9 \ + ESP32_PINMUX(9, ESP_PCNT_CTRL_CH0_IN2, ESP_NOSIG) + +#define PCNT2_CH0CTRL_GPIO10 \ + ESP32_PINMUX(10, ESP_PCNT_CTRL_CH0_IN2, ESP_NOSIG) + +#define PCNT2_CH0CTRL_GPIO11 \ + ESP32_PINMUX(11, ESP_PCNT_CTRL_CH0_IN2, ESP_NOSIG) + +#define PCNT2_CH0CTRL_GPIO12 \ + ESP32_PINMUX(12, ESP_PCNT_CTRL_CH0_IN2, ESP_NOSIG) + +#define PCNT2_CH0CTRL_GPIO13 \ + ESP32_PINMUX(13, ESP_PCNT_CTRL_CH0_IN2, ESP_NOSIG) + +#define PCNT2_CH0CTRL_GPIO14 \ + ESP32_PINMUX(14, ESP_PCNT_CTRL_CH0_IN2, ESP_NOSIG) + +#define PCNT2_CH0CTRL_GPIO15 \ + ESP32_PINMUX(15, ESP_PCNT_CTRL_CH0_IN2, ESP_NOSIG) + +#define PCNT2_CH0CTRL_GPIO16 \ + ESP32_PINMUX(16, ESP_PCNT_CTRL_CH0_IN2, ESP_NOSIG) + +#define PCNT2_CH0CTRL_GPIO17 \ + ESP32_PINMUX(17, ESP_PCNT_CTRL_CH0_IN2, ESP_NOSIG) + +#define PCNT2_CH0CTRL_GPIO18 \ + ESP32_PINMUX(18, ESP_PCNT_CTRL_CH0_IN2, ESP_NOSIG) + +#define PCNT2_CH0CTRL_GPIO19 \ + ESP32_PINMUX(19, ESP_PCNT_CTRL_CH0_IN2, ESP_NOSIG) + +#define PCNT2_CH0CTRL_GPIO20 \ + ESP32_PINMUX(20, ESP_PCNT_CTRL_CH0_IN2, ESP_NOSIG) + +#define PCNT2_CH0CTRL_GPIO21 \ + ESP32_PINMUX(21, ESP_PCNT_CTRL_CH0_IN2, ESP_NOSIG) + +#define PCNT2_CH0CTRL_GPIO26 \ + ESP32_PINMUX(26, ESP_PCNT_CTRL_CH0_IN2, ESP_NOSIG) + +#define PCNT2_CH0CTRL_GPIO27 \ + ESP32_PINMUX(27, ESP_PCNT_CTRL_CH0_IN2, ESP_NOSIG) + +#define PCNT2_CH0CTRL_GPIO28 \ + ESP32_PINMUX(28, ESP_PCNT_CTRL_CH0_IN2, ESP_NOSIG) + +#define PCNT2_CH0CTRL_GPIO29 \ + ESP32_PINMUX(29, ESP_PCNT_CTRL_CH0_IN2, ESP_NOSIG) + +#define PCNT2_CH0CTRL_GPIO30 \ + ESP32_PINMUX(30, ESP_PCNT_CTRL_CH0_IN2, ESP_NOSIG) + +#define PCNT2_CH0CTRL_GPIO31 \ + ESP32_PINMUX(31, ESP_PCNT_CTRL_CH0_IN2, ESP_NOSIG) + +#define PCNT2_CH0CTRL_GPIO32 \ + ESP32_PINMUX(32, ESP_PCNT_CTRL_CH0_IN2, ESP_NOSIG) + +#define PCNT2_CH0CTRL_GPIO33 \ + ESP32_PINMUX(33, ESP_PCNT_CTRL_CH0_IN2, ESP_NOSIG) + +#define PCNT2_CH0CTRL_GPIO34 \ + ESP32_PINMUX(34, ESP_PCNT_CTRL_CH0_IN2, ESP_NOSIG) + +#define PCNT2_CH0CTRL_GPIO35 \ + ESP32_PINMUX(35, ESP_PCNT_CTRL_CH0_IN2, ESP_NOSIG) + +#define PCNT2_CH0CTRL_GPIO36 \ + ESP32_PINMUX(36, ESP_PCNT_CTRL_CH0_IN2, ESP_NOSIG) + +#define PCNT2_CH0CTRL_GPIO37 \ + ESP32_PINMUX(37, ESP_PCNT_CTRL_CH0_IN2, ESP_NOSIG) + +#define PCNT2_CH0CTRL_GPIO38 \ + ESP32_PINMUX(38, ESP_PCNT_CTRL_CH0_IN2, ESP_NOSIG) + +#define PCNT2_CH0CTRL_GPIO39 \ + ESP32_PINMUX(39, ESP_PCNT_CTRL_CH0_IN2, ESP_NOSIG) + +#define PCNT2_CH0CTRL_GPIO40 \ + ESP32_PINMUX(40, ESP_PCNT_CTRL_CH0_IN2, ESP_NOSIG) + +#define PCNT2_CH0CTRL_GPIO41 \ + ESP32_PINMUX(41, ESP_PCNT_CTRL_CH0_IN2, ESP_NOSIG) + +#define PCNT2_CH0CTRL_GPIO42 \ + ESP32_PINMUX(42, ESP_PCNT_CTRL_CH0_IN2, ESP_NOSIG) + +#define PCNT2_CH0CTRL_GPIO43 \ + ESP32_PINMUX(43, ESP_PCNT_CTRL_CH0_IN2, ESP_NOSIG) + +#define PCNT2_CH0CTRL_GPIO44 \ + ESP32_PINMUX(44, ESP_PCNT_CTRL_CH0_IN2, ESP_NOSIG) + +#define PCNT2_CH0CTRL_GPIO45 \ + ESP32_PINMUX(45, ESP_PCNT_CTRL_CH0_IN2, ESP_NOSIG) + +#define PCNT2_CH0CTRL_GPIO46 \ + ESP32_PINMUX(46, ESP_PCNT_CTRL_CH0_IN2, ESP_NOSIG) + +#define PCNT2_CH0CTRL_GPIO47 \ + ESP32_PINMUX(47, ESP_PCNT_CTRL_CH0_IN2, ESP_NOSIG) + +#define PCNT2_CH0CTRL_GPIO48 \ + ESP32_PINMUX(48, ESP_PCNT_CTRL_CH0_IN2, ESP_NOSIG) + +/* PCNT2_CH0SIG */ +#define PCNT2_CH0SIG_GPIO0 \ + ESP32_PINMUX(0, ESP_PCNT_SIG_CH0_IN3, ESP_NOSIG) + +#define PCNT2_CH0SIG_GPIO1 \ + ESP32_PINMUX(1, ESP_PCNT_SIG_CH0_IN3, ESP_NOSIG) + +#define PCNT2_CH0SIG_GPIO2 \ + ESP32_PINMUX(2, ESP_PCNT_SIG_CH0_IN3, ESP_NOSIG) + +#define PCNT2_CH0SIG_GPIO3 \ + ESP32_PINMUX(3, ESP_PCNT_SIG_CH0_IN3, ESP_NOSIG) + +#define PCNT2_CH0SIG_GPIO4 \ + ESP32_PINMUX(4, ESP_PCNT_SIG_CH0_IN3, ESP_NOSIG) + +#define PCNT2_CH0SIG_GPIO5 \ + ESP32_PINMUX(5, ESP_PCNT_SIG_CH0_IN3, ESP_NOSIG) + +#define PCNT2_CH0SIG_GPIO6 \ + ESP32_PINMUX(6, ESP_PCNT_SIG_CH0_IN3, ESP_NOSIG) + +#define PCNT2_CH0SIG_GPIO7 \ + ESP32_PINMUX(7, ESP_PCNT_SIG_CH0_IN3, ESP_NOSIG) + +#define PCNT2_CH0SIG_GPIO8 \ + ESP32_PINMUX(8, ESP_PCNT_SIG_CH0_IN3, ESP_NOSIG) + +#define PCNT2_CH0SIG_GPIO9 \ + ESP32_PINMUX(9, ESP_PCNT_SIG_CH0_IN3, ESP_NOSIG) + +#define PCNT2_CH0SIG_GPIO10 \ + ESP32_PINMUX(10, ESP_PCNT_SIG_CH0_IN3, ESP_NOSIG) + +#define PCNT2_CH0SIG_GPIO11 \ + ESP32_PINMUX(11, ESP_PCNT_SIG_CH0_IN3, ESP_NOSIG) + +#define PCNT2_CH0SIG_GPIO12 \ + ESP32_PINMUX(12, ESP_PCNT_SIG_CH0_IN3, ESP_NOSIG) + +#define PCNT2_CH0SIG_GPIO13 \ + ESP32_PINMUX(13, ESP_PCNT_SIG_CH0_IN3, ESP_NOSIG) + +#define PCNT2_CH0SIG_GPIO14 \ + ESP32_PINMUX(14, ESP_PCNT_SIG_CH0_IN3, ESP_NOSIG) + +#define PCNT2_CH0SIG_GPIO15 \ + ESP32_PINMUX(15, ESP_PCNT_SIG_CH0_IN3, ESP_NOSIG) + +#define PCNT2_CH0SIG_GPIO16 \ + ESP32_PINMUX(16, ESP_PCNT_SIG_CH0_IN3, ESP_NOSIG) + +#define PCNT2_CH0SIG_GPIO17 \ + ESP32_PINMUX(17, ESP_PCNT_SIG_CH0_IN3, ESP_NOSIG) + +#define PCNT2_CH0SIG_GPIO18 \ + ESP32_PINMUX(18, ESP_PCNT_SIG_CH0_IN3, ESP_NOSIG) + +#define PCNT2_CH0SIG_GPIO19 \ + ESP32_PINMUX(19, ESP_PCNT_SIG_CH0_IN3, ESP_NOSIG) + +#define PCNT2_CH0SIG_GPIO20 \ + ESP32_PINMUX(20, ESP_PCNT_SIG_CH0_IN3, ESP_NOSIG) + +#define PCNT2_CH0SIG_GPIO21 \ + ESP32_PINMUX(21, ESP_PCNT_SIG_CH0_IN3, ESP_NOSIG) + +#define PCNT2_CH0SIG_GPIO26 \ + ESP32_PINMUX(26, ESP_PCNT_SIG_CH0_IN3, ESP_NOSIG) + +#define PCNT2_CH0SIG_GPIO27 \ + ESP32_PINMUX(27, ESP_PCNT_SIG_CH0_IN3, ESP_NOSIG) + +#define PCNT2_CH0SIG_GPIO28 \ + ESP32_PINMUX(28, ESP_PCNT_SIG_CH0_IN3, ESP_NOSIG) + +#define PCNT2_CH0SIG_GPIO29 \ + ESP32_PINMUX(29, ESP_PCNT_SIG_CH0_IN3, ESP_NOSIG) + +#define PCNT2_CH0SIG_GPIO30 \ + ESP32_PINMUX(30, ESP_PCNT_SIG_CH0_IN3, ESP_NOSIG) + +#define PCNT2_CH0SIG_GPIO31 \ + ESP32_PINMUX(31, ESP_PCNT_SIG_CH0_IN3, ESP_NOSIG) + +#define PCNT2_CH0SIG_GPIO32 \ + ESP32_PINMUX(32, ESP_PCNT_SIG_CH0_IN3, ESP_NOSIG) + +#define PCNT2_CH0SIG_GPIO33 \ + ESP32_PINMUX(33, ESP_PCNT_SIG_CH0_IN3, ESP_NOSIG) + +#define PCNT2_CH0SIG_GPIO34 \ + ESP32_PINMUX(34, ESP_PCNT_SIG_CH0_IN3, ESP_NOSIG) + +#define PCNT2_CH0SIG_GPIO35 \ + ESP32_PINMUX(35, ESP_PCNT_SIG_CH0_IN3, ESP_NOSIG) + +#define PCNT2_CH0SIG_GPIO36 \ + ESP32_PINMUX(36, ESP_PCNT_SIG_CH0_IN3, ESP_NOSIG) + +#define PCNT2_CH0SIG_GPIO37 \ + ESP32_PINMUX(37, ESP_PCNT_SIG_CH0_IN3, ESP_NOSIG) + +#define PCNT2_CH0SIG_GPIO38 \ + ESP32_PINMUX(38, ESP_PCNT_SIG_CH0_IN3, ESP_NOSIG) + +#define PCNT2_CH0SIG_GPIO39 \ + ESP32_PINMUX(39, ESP_PCNT_SIG_CH0_IN3, ESP_NOSIG) + +#define PCNT2_CH0SIG_GPIO40 \ + ESP32_PINMUX(40, ESP_PCNT_SIG_CH0_IN3, ESP_NOSIG) + +#define PCNT2_CH0SIG_GPIO41 \ + ESP32_PINMUX(41, ESP_PCNT_SIG_CH0_IN3, ESP_NOSIG) + +#define PCNT2_CH0SIG_GPIO42 \ + ESP32_PINMUX(42, ESP_PCNT_SIG_CH0_IN3, ESP_NOSIG) + +#define PCNT2_CH0SIG_GPIO43 \ + ESP32_PINMUX(43, ESP_PCNT_SIG_CH0_IN3, ESP_NOSIG) + +#define PCNT2_CH0SIG_GPIO44 \ + ESP32_PINMUX(44, ESP_PCNT_SIG_CH0_IN3, ESP_NOSIG) + +#define PCNT2_CH0SIG_GPIO45 \ + ESP32_PINMUX(45, ESP_PCNT_SIG_CH0_IN3, ESP_NOSIG) + +#define PCNT2_CH0SIG_GPIO46 \ + ESP32_PINMUX(46, ESP_PCNT_SIG_CH0_IN3, ESP_NOSIG) + +#define PCNT2_CH0SIG_GPIO47 \ + ESP32_PINMUX(47, ESP_PCNT_SIG_CH0_IN3, ESP_NOSIG) + +#define PCNT2_CH0SIG_GPIO48 \ + ESP32_PINMUX(48, ESP_PCNT_SIG_CH0_IN3, ESP_NOSIG) + +/* PCNT2_CH1CTRL */ +#define PCNT2_CH1CTRL_GPIO0 \ + ESP32_PINMUX(0, ESP_PCNT_CTRL_CH1_IN2, ESP_NOSIG) + +#define PCNT2_CH1CTRL_GPIO1 \ + ESP32_PINMUX(1, ESP_PCNT_CTRL_CH1_IN2, ESP_NOSIG) + +#define PCNT2_CH1CTRL_GPIO2 \ + ESP32_PINMUX(2, ESP_PCNT_CTRL_CH1_IN2, ESP_NOSIG) + +#define PCNT2_CH1CTRL_GPIO3 \ + ESP32_PINMUX(3, ESP_PCNT_CTRL_CH1_IN2, ESP_NOSIG) + +#define PCNT2_CH1CTRL_GPIO4 \ + ESP32_PINMUX(4, ESP_PCNT_CTRL_CH1_IN2, ESP_NOSIG) + +#define PCNT2_CH1CTRL_GPIO5 \ + ESP32_PINMUX(5, ESP_PCNT_CTRL_CH1_IN2, ESP_NOSIG) + +#define PCNT2_CH1CTRL_GPIO6 \ + ESP32_PINMUX(6, ESP_PCNT_CTRL_CH1_IN2, ESP_NOSIG) + +#define PCNT2_CH1CTRL_GPIO7 \ + ESP32_PINMUX(7, ESP_PCNT_CTRL_CH1_IN2, ESP_NOSIG) + +#define PCNT2_CH1CTRL_GPIO8 \ + ESP32_PINMUX(8, ESP_PCNT_CTRL_CH1_IN2, ESP_NOSIG) + +#define PCNT2_CH1CTRL_GPIO9 \ + ESP32_PINMUX(9, ESP_PCNT_CTRL_CH1_IN2, ESP_NOSIG) + +#define PCNT2_CH1CTRL_GPIO10 \ + ESP32_PINMUX(10, ESP_PCNT_CTRL_CH1_IN2, ESP_NOSIG) + +#define PCNT2_CH1CTRL_GPIO11 \ + ESP32_PINMUX(11, ESP_PCNT_CTRL_CH1_IN2, ESP_NOSIG) + +#define PCNT2_CH1CTRL_GPIO12 \ + ESP32_PINMUX(12, ESP_PCNT_CTRL_CH1_IN2, ESP_NOSIG) + +#define PCNT2_CH1CTRL_GPIO13 \ + ESP32_PINMUX(13, ESP_PCNT_CTRL_CH1_IN2, ESP_NOSIG) + +#define PCNT2_CH1CTRL_GPIO14 \ + ESP32_PINMUX(14, ESP_PCNT_CTRL_CH1_IN2, ESP_NOSIG) + +#define PCNT2_CH1CTRL_GPIO15 \ + ESP32_PINMUX(15, ESP_PCNT_CTRL_CH1_IN2, ESP_NOSIG) + +#define PCNT2_CH1CTRL_GPIO16 \ + ESP32_PINMUX(16, ESP_PCNT_CTRL_CH1_IN2, ESP_NOSIG) + +#define PCNT2_CH1CTRL_GPIO17 \ + ESP32_PINMUX(17, ESP_PCNT_CTRL_CH1_IN2, ESP_NOSIG) + +#define PCNT2_CH1CTRL_GPIO18 \ + ESP32_PINMUX(18, ESP_PCNT_CTRL_CH1_IN2, ESP_NOSIG) + +#define PCNT2_CH1CTRL_GPIO19 \ + ESP32_PINMUX(19, ESP_PCNT_CTRL_CH1_IN2, ESP_NOSIG) + +#define PCNT2_CH1CTRL_GPIO20 \ + ESP32_PINMUX(20, ESP_PCNT_CTRL_CH1_IN2, ESP_NOSIG) + +#define PCNT2_CH1CTRL_GPIO21 \ + ESP32_PINMUX(21, ESP_PCNT_CTRL_CH1_IN2, ESP_NOSIG) + +#define PCNT2_CH1CTRL_GPIO26 \ + ESP32_PINMUX(26, ESP_PCNT_CTRL_CH1_IN2, ESP_NOSIG) + +#define PCNT2_CH1CTRL_GPIO27 \ + ESP32_PINMUX(27, ESP_PCNT_CTRL_CH1_IN2, ESP_NOSIG) + +#define PCNT2_CH1CTRL_GPIO28 \ + ESP32_PINMUX(28, ESP_PCNT_CTRL_CH1_IN2, ESP_NOSIG) + +#define PCNT2_CH1CTRL_GPIO29 \ + ESP32_PINMUX(29, ESP_PCNT_CTRL_CH1_IN2, ESP_NOSIG) + +#define PCNT2_CH1CTRL_GPIO30 \ + ESP32_PINMUX(30, ESP_PCNT_CTRL_CH1_IN2, ESP_NOSIG) + +#define PCNT2_CH1CTRL_GPIO31 \ + ESP32_PINMUX(31, ESP_PCNT_CTRL_CH1_IN2, ESP_NOSIG) + +#define PCNT2_CH1CTRL_GPIO32 \ + ESP32_PINMUX(32, ESP_PCNT_CTRL_CH1_IN2, ESP_NOSIG) + +#define PCNT2_CH1CTRL_GPIO33 \ + ESP32_PINMUX(33, ESP_PCNT_CTRL_CH1_IN2, ESP_NOSIG) + +#define PCNT2_CH1CTRL_GPIO34 \ + ESP32_PINMUX(34, ESP_PCNT_CTRL_CH1_IN2, ESP_NOSIG) + +#define PCNT2_CH1CTRL_GPIO35 \ + ESP32_PINMUX(35, ESP_PCNT_CTRL_CH1_IN2, ESP_NOSIG) + +#define PCNT2_CH1CTRL_GPIO36 \ + ESP32_PINMUX(36, ESP_PCNT_CTRL_CH1_IN2, ESP_NOSIG) + +#define PCNT2_CH1CTRL_GPIO37 \ + ESP32_PINMUX(37, ESP_PCNT_CTRL_CH1_IN2, ESP_NOSIG) + +#define PCNT2_CH1CTRL_GPIO38 \ + ESP32_PINMUX(38, ESP_PCNT_CTRL_CH1_IN2, ESP_NOSIG) + +#define PCNT2_CH1CTRL_GPIO39 \ + ESP32_PINMUX(39, ESP_PCNT_CTRL_CH1_IN2, ESP_NOSIG) + +#define PCNT2_CH1CTRL_GPIO40 \ + ESP32_PINMUX(40, ESP_PCNT_CTRL_CH1_IN2, ESP_NOSIG) + +#define PCNT2_CH1CTRL_GPIO41 \ + ESP32_PINMUX(41, ESP_PCNT_CTRL_CH1_IN2, ESP_NOSIG) + +#define PCNT2_CH1CTRL_GPIO42 \ + ESP32_PINMUX(42, ESP_PCNT_CTRL_CH1_IN2, ESP_NOSIG) + +#define PCNT2_CH1CTRL_GPIO43 \ + ESP32_PINMUX(43, ESP_PCNT_CTRL_CH1_IN2, ESP_NOSIG) + +#define PCNT2_CH1CTRL_GPIO44 \ + ESP32_PINMUX(44, ESP_PCNT_CTRL_CH1_IN2, ESP_NOSIG) + +#define PCNT2_CH1CTRL_GPIO45 \ + ESP32_PINMUX(45, ESP_PCNT_CTRL_CH1_IN2, ESP_NOSIG) + +#define PCNT2_CH1CTRL_GPIO46 \ + ESP32_PINMUX(46, ESP_PCNT_CTRL_CH1_IN2, ESP_NOSIG) + +#define PCNT2_CH1CTRL_GPIO47 \ + ESP32_PINMUX(47, ESP_PCNT_CTRL_CH1_IN2, ESP_NOSIG) + +#define PCNT2_CH1CTRL_GPIO48 \ + ESP32_PINMUX(48, ESP_PCNT_CTRL_CH1_IN2, ESP_NOSIG) + +/* PCNT2_CH1SIG */ +#define PCNT2_CH1SIG_GPIO0 \ + ESP32_PINMUX(0, ESP_PCNT_SIG_CH1_IN2, ESP_NOSIG) + +#define PCNT2_CH1SIG_GPIO1 \ + ESP32_PINMUX(1, ESP_PCNT_SIG_CH1_IN2, ESP_NOSIG) + +#define PCNT2_CH1SIG_GPIO2 \ + ESP32_PINMUX(2, ESP_PCNT_SIG_CH1_IN2, ESP_NOSIG) + +#define PCNT2_CH1SIG_GPIO3 \ + ESP32_PINMUX(3, ESP_PCNT_SIG_CH1_IN2, ESP_NOSIG) + +#define PCNT2_CH1SIG_GPIO4 \ + ESP32_PINMUX(4, ESP_PCNT_SIG_CH1_IN2, ESP_NOSIG) + +#define PCNT2_CH1SIG_GPIO5 \ + ESP32_PINMUX(5, ESP_PCNT_SIG_CH1_IN2, ESP_NOSIG) + +#define PCNT2_CH1SIG_GPIO6 \ + ESP32_PINMUX(6, ESP_PCNT_SIG_CH1_IN2, ESP_NOSIG) + +#define PCNT2_CH1SIG_GPIO7 \ + ESP32_PINMUX(7, ESP_PCNT_SIG_CH1_IN2, ESP_NOSIG) + +#define PCNT2_CH1SIG_GPIO8 \ + ESP32_PINMUX(8, ESP_PCNT_SIG_CH1_IN2, ESP_NOSIG) + +#define PCNT2_CH1SIG_GPIO9 \ + ESP32_PINMUX(9, ESP_PCNT_SIG_CH1_IN2, ESP_NOSIG) + +#define PCNT2_CH1SIG_GPIO10 \ + ESP32_PINMUX(10, ESP_PCNT_SIG_CH1_IN2, ESP_NOSIG) + +#define PCNT2_CH1SIG_GPIO11 \ + ESP32_PINMUX(11, ESP_PCNT_SIG_CH1_IN2, ESP_NOSIG) + +#define PCNT2_CH1SIG_GPIO12 \ + ESP32_PINMUX(12, ESP_PCNT_SIG_CH1_IN2, ESP_NOSIG) + +#define PCNT2_CH1SIG_GPIO13 \ + ESP32_PINMUX(13, ESP_PCNT_SIG_CH1_IN2, ESP_NOSIG) + +#define PCNT2_CH1SIG_GPIO14 \ + ESP32_PINMUX(14, ESP_PCNT_SIG_CH1_IN2, ESP_NOSIG) + +#define PCNT2_CH1SIG_GPIO15 \ + ESP32_PINMUX(15, ESP_PCNT_SIG_CH1_IN2, ESP_NOSIG) + +#define PCNT2_CH1SIG_GPIO16 \ + ESP32_PINMUX(16, ESP_PCNT_SIG_CH1_IN2, ESP_NOSIG) + +#define PCNT2_CH1SIG_GPIO17 \ + ESP32_PINMUX(17, ESP_PCNT_SIG_CH1_IN2, ESP_NOSIG) + +#define PCNT2_CH1SIG_GPIO18 \ + ESP32_PINMUX(18, ESP_PCNT_SIG_CH1_IN2, ESP_NOSIG) + +#define PCNT2_CH1SIG_GPIO19 \ + ESP32_PINMUX(19, ESP_PCNT_SIG_CH1_IN2, ESP_NOSIG) + +#define PCNT2_CH1SIG_GPIO20 \ + ESP32_PINMUX(20, ESP_PCNT_SIG_CH1_IN2, ESP_NOSIG) + +#define PCNT2_CH1SIG_GPIO21 \ + ESP32_PINMUX(21, ESP_PCNT_SIG_CH1_IN2, ESP_NOSIG) + +#define PCNT2_CH1SIG_GPIO26 \ + ESP32_PINMUX(26, ESP_PCNT_SIG_CH1_IN2, ESP_NOSIG) + +#define PCNT2_CH1SIG_GPIO27 \ + ESP32_PINMUX(27, ESP_PCNT_SIG_CH1_IN2, ESP_NOSIG) + +#define PCNT2_CH1SIG_GPIO28 \ + ESP32_PINMUX(28, ESP_PCNT_SIG_CH1_IN2, ESP_NOSIG) + +#define PCNT2_CH1SIG_GPIO29 \ + ESP32_PINMUX(29, ESP_PCNT_SIG_CH1_IN2, ESP_NOSIG) + +#define PCNT2_CH1SIG_GPIO30 \ + ESP32_PINMUX(30, ESP_PCNT_SIG_CH1_IN2, ESP_NOSIG) + +#define PCNT2_CH1SIG_GPIO31 \ + ESP32_PINMUX(31, ESP_PCNT_SIG_CH1_IN2, ESP_NOSIG) + +#define PCNT2_CH1SIG_GPIO32 \ + ESP32_PINMUX(32, ESP_PCNT_SIG_CH1_IN2, ESP_NOSIG) + +#define PCNT2_CH1SIG_GPIO33 \ + ESP32_PINMUX(33, ESP_PCNT_SIG_CH1_IN2, ESP_NOSIG) + +#define PCNT2_CH1SIG_GPIO34 \ + ESP32_PINMUX(34, ESP_PCNT_SIG_CH1_IN2, ESP_NOSIG) + +#define PCNT2_CH1SIG_GPIO35 \ + ESP32_PINMUX(35, ESP_PCNT_SIG_CH1_IN2, ESP_NOSIG) + +#define PCNT2_CH1SIG_GPIO36 \ + ESP32_PINMUX(36, ESP_PCNT_SIG_CH1_IN2, ESP_NOSIG) + +#define PCNT2_CH1SIG_GPIO37 \ + ESP32_PINMUX(37, ESP_PCNT_SIG_CH1_IN2, ESP_NOSIG) + +#define PCNT2_CH1SIG_GPIO38 \ + ESP32_PINMUX(38, ESP_PCNT_SIG_CH1_IN2, ESP_NOSIG) + +#define PCNT2_CH1SIG_GPIO39 \ + ESP32_PINMUX(39, ESP_PCNT_SIG_CH1_IN2, ESP_NOSIG) + +#define PCNT2_CH1SIG_GPIO40 \ + ESP32_PINMUX(40, ESP_PCNT_SIG_CH1_IN2, ESP_NOSIG) + +#define PCNT2_CH1SIG_GPIO41 \ + ESP32_PINMUX(41, ESP_PCNT_SIG_CH1_IN2, ESP_NOSIG) + +#define PCNT2_CH1SIG_GPIO42 \ + ESP32_PINMUX(42, ESP_PCNT_SIG_CH1_IN2, ESP_NOSIG) + +#define PCNT2_CH1SIG_GPIO43 \ + ESP32_PINMUX(43, ESP_PCNT_SIG_CH1_IN2, ESP_NOSIG) + +#define PCNT2_CH1SIG_GPIO44 \ + ESP32_PINMUX(44, ESP_PCNT_SIG_CH1_IN2, ESP_NOSIG) + +#define PCNT2_CH1SIG_GPIO45 \ + ESP32_PINMUX(45, ESP_PCNT_SIG_CH1_IN2, ESP_NOSIG) + +#define PCNT2_CH1SIG_GPIO46 \ + ESP32_PINMUX(46, ESP_PCNT_SIG_CH1_IN2, ESP_NOSIG) + +#define PCNT2_CH1SIG_GPIO47 \ + ESP32_PINMUX(47, ESP_PCNT_SIG_CH1_IN2, ESP_NOSIG) + +#define PCNT2_CH1SIG_GPIO48 \ + ESP32_PINMUX(48, ESP_PCNT_SIG_CH1_IN2, ESP_NOSIG) + +/* PCNT3_CH0CTRL */ +#define PCNT3_CH0CTRL_GPIO0 \ + ESP32_PINMUX(0, ESP_PCNT_CTRL_CH0_IN3, ESP_NOSIG) + +#define PCNT3_CH0CTRL_GPIO1 \ + ESP32_PINMUX(1, ESP_PCNT_CTRL_CH0_IN3, ESP_NOSIG) + +#define PCNT3_CH0CTRL_GPIO2 \ + ESP32_PINMUX(2, ESP_PCNT_CTRL_CH0_IN3, ESP_NOSIG) + +#define PCNT3_CH0CTRL_GPIO3 \ + ESP32_PINMUX(3, ESP_PCNT_CTRL_CH0_IN3, ESP_NOSIG) + +#define PCNT3_CH0CTRL_GPIO4 \ + ESP32_PINMUX(4, ESP_PCNT_CTRL_CH0_IN3, ESP_NOSIG) + +#define PCNT3_CH0CTRL_GPIO5 \ + ESP32_PINMUX(5, ESP_PCNT_CTRL_CH0_IN3, ESP_NOSIG) + +#define PCNT3_CH0CTRL_GPIO6 \ + ESP32_PINMUX(6, ESP_PCNT_CTRL_CH0_IN3, ESP_NOSIG) + +#define PCNT3_CH0CTRL_GPIO7 \ + ESP32_PINMUX(7, ESP_PCNT_CTRL_CH0_IN3, ESP_NOSIG) + +#define PCNT3_CH0CTRL_GPIO8 \ + ESP32_PINMUX(8, ESP_PCNT_CTRL_CH0_IN3, ESP_NOSIG) + +#define PCNT3_CH0CTRL_GPIO9 \ + ESP32_PINMUX(9, ESP_PCNT_CTRL_CH0_IN3, ESP_NOSIG) + +#define PCNT3_CH0CTRL_GPIO10 \ + ESP32_PINMUX(10, ESP_PCNT_CTRL_CH0_IN3, ESP_NOSIG) + +#define PCNT3_CH0CTRL_GPIO11 \ + ESP32_PINMUX(11, ESP_PCNT_CTRL_CH0_IN3, ESP_NOSIG) + +#define PCNT3_CH0CTRL_GPIO12 \ + ESP32_PINMUX(12, ESP_PCNT_CTRL_CH0_IN3, ESP_NOSIG) + +#define PCNT3_CH0CTRL_GPIO13 \ + ESP32_PINMUX(13, ESP_PCNT_CTRL_CH0_IN3, ESP_NOSIG) + +#define PCNT3_CH0CTRL_GPIO14 \ + ESP32_PINMUX(14, ESP_PCNT_CTRL_CH0_IN3, ESP_NOSIG) + +#define PCNT3_CH0CTRL_GPIO15 \ + ESP32_PINMUX(15, ESP_PCNT_CTRL_CH0_IN3, ESP_NOSIG) + +#define PCNT3_CH0CTRL_GPIO16 \ + ESP32_PINMUX(16, ESP_PCNT_CTRL_CH0_IN3, ESP_NOSIG) + +#define PCNT3_CH0CTRL_GPIO17 \ + ESP32_PINMUX(17, ESP_PCNT_CTRL_CH0_IN3, ESP_NOSIG) + +#define PCNT3_CH0CTRL_GPIO18 \ + ESP32_PINMUX(18, ESP_PCNT_CTRL_CH0_IN3, ESP_NOSIG) + +#define PCNT3_CH0CTRL_GPIO19 \ + ESP32_PINMUX(19, ESP_PCNT_CTRL_CH0_IN3, ESP_NOSIG) + +#define PCNT3_CH0CTRL_GPIO20 \ + ESP32_PINMUX(20, ESP_PCNT_CTRL_CH0_IN3, ESP_NOSIG) + +#define PCNT3_CH0CTRL_GPIO21 \ + ESP32_PINMUX(21, ESP_PCNT_CTRL_CH0_IN3, ESP_NOSIG) + +#define PCNT3_CH0CTRL_GPIO26 \ + ESP32_PINMUX(26, ESP_PCNT_CTRL_CH0_IN3, ESP_NOSIG) + +#define PCNT3_CH0CTRL_GPIO27 \ + ESP32_PINMUX(27, ESP_PCNT_CTRL_CH0_IN3, ESP_NOSIG) + +#define PCNT3_CH0CTRL_GPIO28 \ + ESP32_PINMUX(28, ESP_PCNT_CTRL_CH0_IN3, ESP_NOSIG) + +#define PCNT3_CH0CTRL_GPIO29 \ + ESP32_PINMUX(29, ESP_PCNT_CTRL_CH0_IN3, ESP_NOSIG) + +#define PCNT3_CH0CTRL_GPIO30 \ + ESP32_PINMUX(30, ESP_PCNT_CTRL_CH0_IN3, ESP_NOSIG) + +#define PCNT3_CH0CTRL_GPIO31 \ + ESP32_PINMUX(31, ESP_PCNT_CTRL_CH0_IN3, ESP_NOSIG) + +#define PCNT3_CH0CTRL_GPIO32 \ + ESP32_PINMUX(32, ESP_PCNT_CTRL_CH0_IN3, ESP_NOSIG) + +#define PCNT3_CH0CTRL_GPIO33 \ + ESP32_PINMUX(33, ESP_PCNT_CTRL_CH0_IN3, ESP_NOSIG) + +#define PCNT3_CH0CTRL_GPIO34 \ + ESP32_PINMUX(34, ESP_PCNT_CTRL_CH0_IN3, ESP_NOSIG) + +#define PCNT3_CH0CTRL_GPIO35 \ + ESP32_PINMUX(35, ESP_PCNT_CTRL_CH0_IN3, ESP_NOSIG) + +#define PCNT3_CH0CTRL_GPIO36 \ + ESP32_PINMUX(36, ESP_PCNT_CTRL_CH0_IN3, ESP_NOSIG) + +#define PCNT3_CH0CTRL_GPIO37 \ + ESP32_PINMUX(37, ESP_PCNT_CTRL_CH0_IN3, ESP_NOSIG) + +#define PCNT3_CH0CTRL_GPIO38 \ + ESP32_PINMUX(38, ESP_PCNT_CTRL_CH0_IN3, ESP_NOSIG) + +#define PCNT3_CH0CTRL_GPIO39 \ + ESP32_PINMUX(39, ESP_PCNT_CTRL_CH0_IN3, ESP_NOSIG) + +#define PCNT3_CH0CTRL_GPIO40 \ + ESP32_PINMUX(40, ESP_PCNT_CTRL_CH0_IN3, ESP_NOSIG) + +#define PCNT3_CH0CTRL_GPIO41 \ + ESP32_PINMUX(41, ESP_PCNT_CTRL_CH0_IN3, ESP_NOSIG) + +#define PCNT3_CH0CTRL_GPIO42 \ + ESP32_PINMUX(42, ESP_PCNT_CTRL_CH0_IN3, ESP_NOSIG) + +#define PCNT3_CH0CTRL_GPIO43 \ + ESP32_PINMUX(43, ESP_PCNT_CTRL_CH0_IN3, ESP_NOSIG) + +#define PCNT3_CH0CTRL_GPIO44 \ + ESP32_PINMUX(44, ESP_PCNT_CTRL_CH0_IN3, ESP_NOSIG) + +#define PCNT3_CH0CTRL_GPIO45 \ + ESP32_PINMUX(45, ESP_PCNT_CTRL_CH0_IN3, ESP_NOSIG) + +#define PCNT3_CH0CTRL_GPIO46 \ + ESP32_PINMUX(46, ESP_PCNT_CTRL_CH0_IN3, ESP_NOSIG) + +#define PCNT3_CH0CTRL_GPIO47 \ + ESP32_PINMUX(47, ESP_PCNT_CTRL_CH0_IN3, ESP_NOSIG) + +#define PCNT3_CH0CTRL_GPIO48 \ + ESP32_PINMUX(48, ESP_PCNT_CTRL_CH0_IN3, ESP_NOSIG) + +/* PCNT3_CH0SIG */ +#define PCNT3_CH0SIG_GPIO0 \ + ESP32_PINMUX(0, ESP_PCNT_SIG_CH0_IN3, ESP_NOSIG) + +#define PCNT3_CH0SIG_GPIO1 \ + ESP32_PINMUX(1, ESP_PCNT_SIG_CH0_IN3, ESP_NOSIG) + +#define PCNT3_CH0SIG_GPIO2 \ + ESP32_PINMUX(2, ESP_PCNT_SIG_CH0_IN3, ESP_NOSIG) + +#define PCNT3_CH0SIG_GPIO3 \ + ESP32_PINMUX(3, ESP_PCNT_SIG_CH0_IN3, ESP_NOSIG) + +#define PCNT3_CH0SIG_GPIO4 \ + ESP32_PINMUX(4, ESP_PCNT_SIG_CH0_IN3, ESP_NOSIG) + +#define PCNT3_CH0SIG_GPIO5 \ + ESP32_PINMUX(5, ESP_PCNT_SIG_CH0_IN3, ESP_NOSIG) + +#define PCNT3_CH0SIG_GPIO6 \ + ESP32_PINMUX(6, ESP_PCNT_SIG_CH0_IN3, ESP_NOSIG) + +#define PCNT3_CH0SIG_GPIO7 \ + ESP32_PINMUX(7, ESP_PCNT_SIG_CH0_IN3, ESP_NOSIG) + +#define PCNT3_CH0SIG_GPIO8 \ + ESP32_PINMUX(8, ESP_PCNT_SIG_CH0_IN3, ESP_NOSIG) + +#define PCNT3_CH0SIG_GPIO9 \ + ESP32_PINMUX(9, ESP_PCNT_SIG_CH0_IN3, ESP_NOSIG) + +#define PCNT3_CH0SIG_GPIO10 \ + ESP32_PINMUX(10, ESP_PCNT_SIG_CH0_IN3, ESP_NOSIG) + +#define PCNT3_CH0SIG_GPIO11 \ + ESP32_PINMUX(11, ESP_PCNT_SIG_CH0_IN3, ESP_NOSIG) + +#define PCNT3_CH0SIG_GPIO12 \ + ESP32_PINMUX(12, ESP_PCNT_SIG_CH0_IN3, ESP_NOSIG) + +#define PCNT3_CH0SIG_GPIO13 \ + ESP32_PINMUX(13, ESP_PCNT_SIG_CH0_IN3, ESP_NOSIG) + +#define PCNT3_CH0SIG_GPIO14 \ + ESP32_PINMUX(14, ESP_PCNT_SIG_CH0_IN3, ESP_NOSIG) + +#define PCNT3_CH0SIG_GPIO15 \ + ESP32_PINMUX(15, ESP_PCNT_SIG_CH0_IN3, ESP_NOSIG) + +#define PCNT3_CH0SIG_GPIO16 \ + ESP32_PINMUX(16, ESP_PCNT_SIG_CH0_IN3, ESP_NOSIG) + +#define PCNT3_CH0SIG_GPIO17 \ + ESP32_PINMUX(17, ESP_PCNT_SIG_CH0_IN3, ESP_NOSIG) + +#define PCNT3_CH0SIG_GPIO18 \ + ESP32_PINMUX(18, ESP_PCNT_SIG_CH0_IN3, ESP_NOSIG) + +#define PCNT3_CH0SIG_GPIO19 \ + ESP32_PINMUX(19, ESP_PCNT_SIG_CH0_IN3, ESP_NOSIG) + +#define PCNT3_CH0SIG_GPIO20 \ + ESP32_PINMUX(20, ESP_PCNT_SIG_CH0_IN3, ESP_NOSIG) + +#define PCNT3_CH0SIG_GPIO21 \ + ESP32_PINMUX(21, ESP_PCNT_SIG_CH0_IN3, ESP_NOSIG) + +#define PCNT3_CH0SIG_GPIO26 \ + ESP32_PINMUX(26, ESP_PCNT_SIG_CH0_IN3, ESP_NOSIG) + +#define PCNT3_CH0SIG_GPIO27 \ + ESP32_PINMUX(27, ESP_PCNT_SIG_CH0_IN3, ESP_NOSIG) + +#define PCNT3_CH0SIG_GPIO28 \ + ESP32_PINMUX(28, ESP_PCNT_SIG_CH0_IN3, ESP_NOSIG) + +#define PCNT3_CH0SIG_GPIO29 \ + ESP32_PINMUX(29, ESP_PCNT_SIG_CH0_IN3, ESP_NOSIG) + +#define PCNT3_CH0SIG_GPIO30 \ + ESP32_PINMUX(30, ESP_PCNT_SIG_CH0_IN3, ESP_NOSIG) + +#define PCNT3_CH0SIG_GPIO31 \ + ESP32_PINMUX(31, ESP_PCNT_SIG_CH0_IN3, ESP_NOSIG) + +#define PCNT3_CH0SIG_GPIO32 \ + ESP32_PINMUX(32, ESP_PCNT_SIG_CH0_IN3, ESP_NOSIG) + +#define PCNT3_CH0SIG_GPIO33 \ + ESP32_PINMUX(33, ESP_PCNT_SIG_CH0_IN3, ESP_NOSIG) + +#define PCNT3_CH0SIG_GPIO34 \ + ESP32_PINMUX(34, ESP_PCNT_SIG_CH0_IN3, ESP_NOSIG) + +#define PCNT3_CH0SIG_GPIO35 \ + ESP32_PINMUX(35, ESP_PCNT_SIG_CH0_IN3, ESP_NOSIG) + +#define PCNT3_CH0SIG_GPIO36 \ + ESP32_PINMUX(36, ESP_PCNT_SIG_CH0_IN3, ESP_NOSIG) + +#define PCNT3_CH0SIG_GPIO37 \ + ESP32_PINMUX(37, ESP_PCNT_SIG_CH0_IN3, ESP_NOSIG) + +#define PCNT3_CH0SIG_GPIO38 \ + ESP32_PINMUX(38, ESP_PCNT_SIG_CH0_IN3, ESP_NOSIG) + +#define PCNT3_CH0SIG_GPIO39 \ + ESP32_PINMUX(39, ESP_PCNT_SIG_CH0_IN3, ESP_NOSIG) + +#define PCNT3_CH0SIG_GPIO40 \ + ESP32_PINMUX(40, ESP_PCNT_SIG_CH0_IN3, ESP_NOSIG) + +#define PCNT3_CH0SIG_GPIO41 \ + ESP32_PINMUX(41, ESP_PCNT_SIG_CH0_IN3, ESP_NOSIG) + +#define PCNT3_CH0SIG_GPIO42 \ + ESP32_PINMUX(42, ESP_PCNT_SIG_CH0_IN3, ESP_NOSIG) + +#define PCNT3_CH0SIG_GPIO43 \ + ESP32_PINMUX(43, ESP_PCNT_SIG_CH0_IN3, ESP_NOSIG) + +#define PCNT3_CH0SIG_GPIO44 \ + ESP32_PINMUX(44, ESP_PCNT_SIG_CH0_IN3, ESP_NOSIG) + +#define PCNT3_CH0SIG_GPIO45 \ + ESP32_PINMUX(45, ESP_PCNT_SIG_CH0_IN3, ESP_NOSIG) + +#define PCNT3_CH0SIG_GPIO46 \ + ESP32_PINMUX(46, ESP_PCNT_SIG_CH0_IN3, ESP_NOSIG) + +#define PCNT3_CH0SIG_GPIO47 \ + ESP32_PINMUX(47, ESP_PCNT_SIG_CH0_IN3, ESP_NOSIG) + +#define PCNT3_CH0SIG_GPIO48 \ + ESP32_PINMUX(48, ESP_PCNT_SIG_CH0_IN3, ESP_NOSIG) + +/* PCNT3_CH1CTRL */ +#define PCNT3_CH1CTRL_GPIO0 \ + ESP32_PINMUX(0, ESP_PCNT_CTRL_CH1_IN3, ESP_NOSIG) + +#define PCNT3_CH1CTRL_GPIO1 \ + ESP32_PINMUX(1, ESP_PCNT_CTRL_CH1_IN3, ESP_NOSIG) + +#define PCNT3_CH1CTRL_GPIO2 \ + ESP32_PINMUX(2, ESP_PCNT_CTRL_CH1_IN3, ESP_NOSIG) + +#define PCNT3_CH1CTRL_GPIO3 \ + ESP32_PINMUX(3, ESP_PCNT_CTRL_CH1_IN3, ESP_NOSIG) + +#define PCNT3_CH1CTRL_GPIO4 \ + ESP32_PINMUX(4, ESP_PCNT_CTRL_CH1_IN3, ESP_NOSIG) + +#define PCNT3_CH1CTRL_GPIO5 \ + ESP32_PINMUX(5, ESP_PCNT_CTRL_CH1_IN3, ESP_NOSIG) + +#define PCNT3_CH1CTRL_GPIO6 \ + ESP32_PINMUX(6, ESP_PCNT_CTRL_CH1_IN3, ESP_NOSIG) + +#define PCNT3_CH1CTRL_GPIO7 \ + ESP32_PINMUX(7, ESP_PCNT_CTRL_CH1_IN3, ESP_NOSIG) + +#define PCNT3_CH1CTRL_GPIO8 \ + ESP32_PINMUX(8, ESP_PCNT_CTRL_CH1_IN3, ESP_NOSIG) + +#define PCNT3_CH1CTRL_GPIO9 \ + ESP32_PINMUX(9, ESP_PCNT_CTRL_CH1_IN3, ESP_NOSIG) + +#define PCNT3_CH1CTRL_GPIO10 \ + ESP32_PINMUX(10, ESP_PCNT_CTRL_CH1_IN3, ESP_NOSIG) + +#define PCNT3_CH1CTRL_GPIO11 \ + ESP32_PINMUX(11, ESP_PCNT_CTRL_CH1_IN3, ESP_NOSIG) + +#define PCNT3_CH1CTRL_GPIO12 \ + ESP32_PINMUX(12, ESP_PCNT_CTRL_CH1_IN3, ESP_NOSIG) + +#define PCNT3_CH1CTRL_GPIO13 \ + ESP32_PINMUX(13, ESP_PCNT_CTRL_CH1_IN3, ESP_NOSIG) + +#define PCNT3_CH1CTRL_GPIO14 \ + ESP32_PINMUX(14, ESP_PCNT_CTRL_CH1_IN3, ESP_NOSIG) + +#define PCNT3_CH1CTRL_GPIO15 \ + ESP32_PINMUX(15, ESP_PCNT_CTRL_CH1_IN3, ESP_NOSIG) + +#define PCNT3_CH1CTRL_GPIO16 \ + ESP32_PINMUX(16, ESP_PCNT_CTRL_CH1_IN3, ESP_NOSIG) + +#define PCNT3_CH1CTRL_GPIO17 \ + ESP32_PINMUX(17, ESP_PCNT_CTRL_CH1_IN3, ESP_NOSIG) + +#define PCNT3_CH1CTRL_GPIO18 \ + ESP32_PINMUX(18, ESP_PCNT_CTRL_CH1_IN3, ESP_NOSIG) + +#define PCNT3_CH1CTRL_GPIO19 \ + ESP32_PINMUX(19, ESP_PCNT_CTRL_CH1_IN3, ESP_NOSIG) + +#define PCNT3_CH1CTRL_GPIO20 \ + ESP32_PINMUX(20, ESP_PCNT_CTRL_CH1_IN3, ESP_NOSIG) + +#define PCNT3_CH1CTRL_GPIO21 \ + ESP32_PINMUX(21, ESP_PCNT_CTRL_CH1_IN3, ESP_NOSIG) + +#define PCNT3_CH1CTRL_GPIO26 \ + ESP32_PINMUX(26, ESP_PCNT_CTRL_CH1_IN3, ESP_NOSIG) + +#define PCNT3_CH1CTRL_GPIO27 \ + ESP32_PINMUX(27, ESP_PCNT_CTRL_CH1_IN3, ESP_NOSIG) + +#define PCNT3_CH1CTRL_GPIO28 \ + ESP32_PINMUX(28, ESP_PCNT_CTRL_CH1_IN3, ESP_NOSIG) + +#define PCNT3_CH1CTRL_GPIO29 \ + ESP32_PINMUX(29, ESP_PCNT_CTRL_CH1_IN3, ESP_NOSIG) + +#define PCNT3_CH1CTRL_GPIO30 \ + ESP32_PINMUX(30, ESP_PCNT_CTRL_CH1_IN3, ESP_NOSIG) + +#define PCNT3_CH1CTRL_GPIO31 \ + ESP32_PINMUX(31, ESP_PCNT_CTRL_CH1_IN3, ESP_NOSIG) + +#define PCNT3_CH1CTRL_GPIO32 \ + ESP32_PINMUX(32, ESP_PCNT_CTRL_CH1_IN3, ESP_NOSIG) + +#define PCNT3_CH1CTRL_GPIO33 \ + ESP32_PINMUX(33, ESP_PCNT_CTRL_CH1_IN3, ESP_NOSIG) + +#define PCNT3_CH1CTRL_GPIO34 \ + ESP32_PINMUX(34, ESP_PCNT_CTRL_CH1_IN3, ESP_NOSIG) + +#define PCNT3_CH1CTRL_GPIO35 \ + ESP32_PINMUX(35, ESP_PCNT_CTRL_CH1_IN3, ESP_NOSIG) + +#define PCNT3_CH1CTRL_GPIO36 \ + ESP32_PINMUX(36, ESP_PCNT_CTRL_CH1_IN3, ESP_NOSIG) + +#define PCNT3_CH1CTRL_GPIO37 \ + ESP32_PINMUX(37, ESP_PCNT_CTRL_CH1_IN3, ESP_NOSIG) + +#define PCNT3_CH1CTRL_GPIO38 \ + ESP32_PINMUX(38, ESP_PCNT_CTRL_CH1_IN3, ESP_NOSIG) + +#define PCNT3_CH1CTRL_GPIO39 \ + ESP32_PINMUX(39, ESP_PCNT_CTRL_CH1_IN3, ESP_NOSIG) + +#define PCNT3_CH1CTRL_GPIO40 \ + ESP32_PINMUX(40, ESP_PCNT_CTRL_CH1_IN3, ESP_NOSIG) + +#define PCNT3_CH1CTRL_GPIO41 \ + ESP32_PINMUX(41, ESP_PCNT_CTRL_CH1_IN3, ESP_NOSIG) + +#define PCNT3_CH1CTRL_GPIO42 \ + ESP32_PINMUX(42, ESP_PCNT_CTRL_CH1_IN3, ESP_NOSIG) + +#define PCNT3_CH1CTRL_GPIO43 \ + ESP32_PINMUX(43, ESP_PCNT_CTRL_CH1_IN3, ESP_NOSIG) + +#define PCNT3_CH1CTRL_GPIO44 \ + ESP32_PINMUX(44, ESP_PCNT_CTRL_CH1_IN3, ESP_NOSIG) + +#define PCNT3_CH1CTRL_GPIO45 \ + ESP32_PINMUX(45, ESP_PCNT_CTRL_CH1_IN3, ESP_NOSIG) + +#define PCNT3_CH1CTRL_GPIO46 \ + ESP32_PINMUX(46, ESP_PCNT_CTRL_CH1_IN3, ESP_NOSIG) + +#define PCNT3_CH1CTRL_GPIO47 \ + ESP32_PINMUX(47, ESP_PCNT_CTRL_CH1_IN3, ESP_NOSIG) + +#define PCNT3_CH1CTRL_GPIO48 \ + ESP32_PINMUX(48, ESP_PCNT_CTRL_CH1_IN3, ESP_NOSIG) + +/* PCNT3_CH1SIG */ +#define PCNT3_CH1SIG_GPIO0 \ + ESP32_PINMUX(0, ESP_PCNT_SIG_CH1_IN3, ESP_NOSIG) + +#define PCNT3_CH1SIG_GPIO1 \ + ESP32_PINMUX(1, ESP_PCNT_SIG_CH1_IN3, ESP_NOSIG) + +#define PCNT3_CH1SIG_GPIO2 \ + ESP32_PINMUX(2, ESP_PCNT_SIG_CH1_IN3, ESP_NOSIG) + +#define PCNT3_CH1SIG_GPIO3 \ + ESP32_PINMUX(3, ESP_PCNT_SIG_CH1_IN3, ESP_NOSIG) + +#define PCNT3_CH1SIG_GPIO4 \ + ESP32_PINMUX(4, ESP_PCNT_SIG_CH1_IN3, ESP_NOSIG) + +#define PCNT3_CH1SIG_GPIO5 \ + ESP32_PINMUX(5, ESP_PCNT_SIG_CH1_IN3, ESP_NOSIG) + +#define PCNT3_CH1SIG_GPIO6 \ + ESP32_PINMUX(6, ESP_PCNT_SIG_CH1_IN3, ESP_NOSIG) + +#define PCNT3_CH1SIG_GPIO7 \ + ESP32_PINMUX(7, ESP_PCNT_SIG_CH1_IN3, ESP_NOSIG) + +#define PCNT3_CH1SIG_GPIO8 \ + ESP32_PINMUX(8, ESP_PCNT_SIG_CH1_IN3, ESP_NOSIG) + +#define PCNT3_CH1SIG_GPIO9 \ + ESP32_PINMUX(9, ESP_PCNT_SIG_CH1_IN3, ESP_NOSIG) + +#define PCNT3_CH1SIG_GPIO10 \ + ESP32_PINMUX(10, ESP_PCNT_SIG_CH1_IN3, ESP_NOSIG) + +#define PCNT3_CH1SIG_GPIO11 \ + ESP32_PINMUX(11, ESP_PCNT_SIG_CH1_IN3, ESP_NOSIG) + +#define PCNT3_CH1SIG_GPIO12 \ + ESP32_PINMUX(12, ESP_PCNT_SIG_CH1_IN3, ESP_NOSIG) + +#define PCNT3_CH1SIG_GPIO13 \ + ESP32_PINMUX(13, ESP_PCNT_SIG_CH1_IN3, ESP_NOSIG) + +#define PCNT3_CH1SIG_GPIO14 \ + ESP32_PINMUX(14, ESP_PCNT_SIG_CH1_IN3, ESP_NOSIG) + +#define PCNT3_CH1SIG_GPIO15 \ + ESP32_PINMUX(15, ESP_PCNT_SIG_CH1_IN3, ESP_NOSIG) + +#define PCNT3_CH1SIG_GPIO16 \ + ESP32_PINMUX(16, ESP_PCNT_SIG_CH1_IN3, ESP_NOSIG) + +#define PCNT3_CH1SIG_GPIO17 \ + ESP32_PINMUX(17, ESP_PCNT_SIG_CH1_IN3, ESP_NOSIG) + +#define PCNT3_CH1SIG_GPIO18 \ + ESP32_PINMUX(18, ESP_PCNT_SIG_CH1_IN3, ESP_NOSIG) + +#define PCNT3_CH1SIG_GPIO19 \ + ESP32_PINMUX(19, ESP_PCNT_SIG_CH1_IN3, ESP_NOSIG) + +#define PCNT3_CH1SIG_GPIO20 \ + ESP32_PINMUX(20, ESP_PCNT_SIG_CH1_IN3, ESP_NOSIG) + +#define PCNT3_CH1SIG_GPIO21 \ + ESP32_PINMUX(21, ESP_PCNT_SIG_CH1_IN3, ESP_NOSIG) + +#define PCNT3_CH1SIG_GPIO26 \ + ESP32_PINMUX(26, ESP_PCNT_SIG_CH1_IN3, ESP_NOSIG) + +#define PCNT3_CH1SIG_GPIO27 \ + ESP32_PINMUX(27, ESP_PCNT_SIG_CH1_IN3, ESP_NOSIG) + +#define PCNT3_CH1SIG_GPIO28 \ + ESP32_PINMUX(28, ESP_PCNT_SIG_CH1_IN3, ESP_NOSIG) + +#define PCNT3_CH1SIG_GPIO29 \ + ESP32_PINMUX(29, ESP_PCNT_SIG_CH1_IN3, ESP_NOSIG) + +#define PCNT3_CH1SIG_GPIO30 \ + ESP32_PINMUX(30, ESP_PCNT_SIG_CH1_IN3, ESP_NOSIG) + +#define PCNT3_CH1SIG_GPIO31 \ + ESP32_PINMUX(31, ESP_PCNT_SIG_CH1_IN3, ESP_NOSIG) + +#define PCNT3_CH1SIG_GPIO32 \ + ESP32_PINMUX(32, ESP_PCNT_SIG_CH1_IN3, ESP_NOSIG) + +#define PCNT3_CH1SIG_GPIO33 \ + ESP32_PINMUX(33, ESP_PCNT_SIG_CH1_IN3, ESP_NOSIG) + +#define PCNT3_CH1SIG_GPIO34 \ + ESP32_PINMUX(34, ESP_PCNT_SIG_CH1_IN3, ESP_NOSIG) + +#define PCNT3_CH1SIG_GPIO35 \ + ESP32_PINMUX(35, ESP_PCNT_SIG_CH1_IN3, ESP_NOSIG) + +#define PCNT3_CH1SIG_GPIO36 \ + ESP32_PINMUX(36, ESP_PCNT_SIG_CH1_IN3, ESP_NOSIG) + +#define PCNT3_CH1SIG_GPIO37 \ + ESP32_PINMUX(37, ESP_PCNT_SIG_CH1_IN3, ESP_NOSIG) + +#define PCNT3_CH1SIG_GPIO38 \ + ESP32_PINMUX(38, ESP_PCNT_SIG_CH1_IN3, ESP_NOSIG) + +#define PCNT3_CH1SIG_GPIO39 \ + ESP32_PINMUX(39, ESP_PCNT_SIG_CH1_IN3, ESP_NOSIG) + +#define PCNT3_CH1SIG_GPIO40 \ + ESP32_PINMUX(40, ESP_PCNT_SIG_CH1_IN3, ESP_NOSIG) + +#define PCNT3_CH1SIG_GPIO41 \ + ESP32_PINMUX(41, ESP_PCNT_SIG_CH1_IN3, ESP_NOSIG) + +#define PCNT3_CH1SIG_GPIO42 \ + ESP32_PINMUX(42, ESP_PCNT_SIG_CH1_IN3, ESP_NOSIG) + +#define PCNT3_CH1SIG_GPIO43 \ + ESP32_PINMUX(43, ESP_PCNT_SIG_CH1_IN3, ESP_NOSIG) + +#define PCNT3_CH1SIG_GPIO44 \ + ESP32_PINMUX(44, ESP_PCNT_SIG_CH1_IN3, ESP_NOSIG) + +#define PCNT3_CH1SIG_GPIO45 \ + ESP32_PINMUX(45, ESP_PCNT_SIG_CH1_IN3, ESP_NOSIG) + +#define PCNT3_CH1SIG_GPIO46 \ + ESP32_PINMUX(46, ESP_PCNT_SIG_CH1_IN3, ESP_NOSIG) + +#define PCNT3_CH1SIG_GPIO47 \ + ESP32_PINMUX(47, ESP_PCNT_SIG_CH1_IN3, ESP_NOSIG) + +#define PCNT3_CH1SIG_GPIO48 \ + ESP32_PINMUX(48, ESP_PCNT_SIG_CH1_IN3, ESP_NOSIG) + +/* SPIM2_CSEL */ +#define SPIM2_CSEL_GPIO0 \ + ESP32_PINMUX(0, ESP_NOSIG, ESP_FSPICS0_OUT) + +#define SPIM2_CSEL_GPIO1 \ + ESP32_PINMUX(1, ESP_NOSIG, ESP_FSPICS0_OUT) + +#define SPIM2_CSEL_GPIO2 \ + ESP32_PINMUX(2, ESP_NOSIG, ESP_FSPICS0_OUT) + +#define SPIM2_CSEL_GPIO3 \ + ESP32_PINMUX(3, ESP_NOSIG, ESP_FSPICS0_OUT) + +#define SPIM2_CSEL_GPIO4 \ + ESP32_PINMUX(4, ESP_NOSIG, ESP_FSPICS0_OUT) + +#define SPIM2_CSEL_GPIO5 \ + ESP32_PINMUX(5, ESP_NOSIG, ESP_FSPICS0_OUT) + +#define SPIM2_CSEL_GPIO6 \ + ESP32_PINMUX(6, ESP_NOSIG, ESP_FSPICS0_OUT) + +#define SPIM2_CSEL_GPIO7 \ + ESP32_PINMUX(7, ESP_NOSIG, ESP_FSPICS0_OUT) + +#define SPIM2_CSEL_GPIO8 \ + ESP32_PINMUX(8, ESP_NOSIG, ESP_FSPICS0_OUT) + +#define SPIM2_CSEL_GPIO9 \ + ESP32_PINMUX(9, ESP_NOSIG, ESP_FSPICS0_OUT) + +#define SPIM2_CSEL_GPIO10 \ + ESP32_PINMUX(10, ESP_NOSIG, ESP_FSPICS0_OUT) + +#define SPIM2_CSEL_GPIO11 \ + ESP32_PINMUX(11, ESP_NOSIG, ESP_FSPICS0_OUT) + +#define SPIM2_CSEL_GPIO12 \ + ESP32_PINMUX(12, ESP_NOSIG, ESP_FSPICS0_OUT) + +#define SPIM2_CSEL_GPIO13 \ + ESP32_PINMUX(13, ESP_NOSIG, ESP_FSPICS0_OUT) + +#define SPIM2_CSEL_GPIO14 \ + ESP32_PINMUX(14, ESP_NOSIG, ESP_FSPICS0_OUT) + +#define SPIM2_CSEL_GPIO15 \ + ESP32_PINMUX(15, ESP_NOSIG, ESP_FSPICS0_OUT) + +#define SPIM2_CSEL_GPIO16 \ + ESP32_PINMUX(16, ESP_NOSIG, ESP_FSPICS0_OUT) + +#define SPIM2_CSEL_GPIO17 \ + ESP32_PINMUX(17, ESP_NOSIG, ESP_FSPICS0_OUT) + +#define SPIM2_CSEL_GPIO18 \ + ESP32_PINMUX(18, ESP_NOSIG, ESP_FSPICS0_OUT) + +#define SPIM2_CSEL_GPIO19 \ + ESP32_PINMUX(19, ESP_NOSIG, ESP_FSPICS0_OUT) + +#define SPIM2_CSEL_GPIO20 \ + ESP32_PINMUX(20, ESP_NOSIG, ESP_FSPICS0_OUT) + +#define SPIM2_CSEL_GPIO21 \ + ESP32_PINMUX(21, ESP_NOSIG, ESP_FSPICS0_OUT) + +#define SPIM2_CSEL_GPIO26 \ + ESP32_PINMUX(26, ESP_NOSIG, ESP_FSPICS0_OUT) + +#define SPIM2_CSEL_GPIO27 \ + ESP32_PINMUX(27, ESP_NOSIG, ESP_FSPICS0_OUT) + +#define SPIM2_CSEL_GPIO28 \ + ESP32_PINMUX(28, ESP_NOSIG, ESP_FSPICS0_OUT) + +#define SPIM2_CSEL_GPIO29 \ + ESP32_PINMUX(29, ESP_NOSIG, ESP_FSPICS0_OUT) + +#define SPIM2_CSEL_GPIO30 \ + ESP32_PINMUX(30, ESP_NOSIG, ESP_FSPICS0_OUT) + +#define SPIM2_CSEL_GPIO31 \ + ESP32_PINMUX(31, ESP_NOSIG, ESP_FSPICS0_OUT) + +#define SPIM2_CSEL_GPIO32 \ + ESP32_PINMUX(32, ESP_NOSIG, ESP_FSPICS0_OUT) + +#define SPIM2_CSEL_GPIO33 \ + ESP32_PINMUX(33, ESP_NOSIG, ESP_FSPICS0_OUT) + +#define SPIM2_CSEL_GPIO34 \ + ESP32_PINMUX(34, ESP_NOSIG, ESP_FSPICS0_OUT) + +#define SPIM2_CSEL_GPIO35 \ + ESP32_PINMUX(35, ESP_NOSIG, ESP_FSPICS0_OUT) + +#define SPIM2_CSEL_GPIO36 \ + ESP32_PINMUX(36, ESP_NOSIG, ESP_FSPICS0_OUT) + +#define SPIM2_CSEL_GPIO37 \ + ESP32_PINMUX(37, ESP_NOSIG, ESP_FSPICS0_OUT) + +#define SPIM2_CSEL_GPIO38 \ + ESP32_PINMUX(38, ESP_NOSIG, ESP_FSPICS0_OUT) + +#define SPIM2_CSEL_GPIO39 \ + ESP32_PINMUX(39, ESP_NOSIG, ESP_FSPICS0_OUT) + +#define SPIM2_CSEL_GPIO40 \ + ESP32_PINMUX(40, ESP_NOSIG, ESP_FSPICS0_OUT) + +#define SPIM2_CSEL_GPIO41 \ + ESP32_PINMUX(41, ESP_NOSIG, ESP_FSPICS0_OUT) + +#define SPIM2_CSEL_GPIO42 \ + ESP32_PINMUX(42, ESP_NOSIG, ESP_FSPICS0_OUT) + +#define SPIM2_CSEL_GPIO43 \ + ESP32_PINMUX(43, ESP_NOSIG, ESP_FSPICS0_OUT) + +#define SPIM2_CSEL_GPIO44 \ + ESP32_PINMUX(44, ESP_NOSIG, ESP_FSPICS0_OUT) + +#define SPIM2_CSEL_GPIO45 \ + ESP32_PINMUX(45, ESP_NOSIG, ESP_FSPICS0_OUT) + +#define SPIM2_CSEL_GPIO46 \ + ESP32_PINMUX(46, ESP_NOSIG, ESP_FSPICS0_OUT) + +#define SPIM2_CSEL_GPIO47 \ + ESP32_PINMUX(47, ESP_NOSIG, ESP_FSPICS0_OUT) + +#define SPIM2_CSEL_GPIO48 \ + ESP32_PINMUX(48, ESP_NOSIG, ESP_FSPICS0_OUT) + +/* SPIM2_CSEL1 */ +#define SPIM2_CSEL1_GPIO0 \ + ESP32_PINMUX(0, ESP_NOSIG, ESP_FSPICS1_OUT) + +#define SPIM2_CSEL1_GPIO1 \ + ESP32_PINMUX(1, ESP_NOSIG, ESP_FSPICS1_OUT) + +#define SPIM2_CSEL1_GPIO2 \ + ESP32_PINMUX(2, ESP_NOSIG, ESP_FSPICS1_OUT) + +#define SPIM2_CSEL1_GPIO3 \ + ESP32_PINMUX(3, ESP_NOSIG, ESP_FSPICS1_OUT) + +#define SPIM2_CSEL1_GPIO4 \ + ESP32_PINMUX(4, ESP_NOSIG, ESP_FSPICS1_OUT) + +#define SPIM2_CSEL1_GPIO5 \ + ESP32_PINMUX(5, ESP_NOSIG, ESP_FSPICS1_OUT) + +#define SPIM2_CSEL1_GPIO6 \ + ESP32_PINMUX(6, ESP_NOSIG, ESP_FSPICS1_OUT) + +#define SPIM2_CSEL1_GPIO7 \ + ESP32_PINMUX(7, ESP_NOSIG, ESP_FSPICS1_OUT) + +#define SPIM2_CSEL1_GPIO8 \ + ESP32_PINMUX(8, ESP_NOSIG, ESP_FSPICS1_OUT) + +#define SPIM2_CSEL1_GPIO9 \ + ESP32_PINMUX(9, ESP_NOSIG, ESP_FSPICS1_OUT) + +#define SPIM2_CSEL1_GPIO10 \ + ESP32_PINMUX(10, ESP_NOSIG, ESP_FSPICS1_OUT) + +#define SPIM2_CSEL1_GPIO11 \ + ESP32_PINMUX(11, ESP_NOSIG, ESP_FSPICS1_OUT) + +#define SPIM2_CSEL1_GPIO12 \ + ESP32_PINMUX(12, ESP_NOSIG, ESP_FSPICS1_OUT) + +#define SPIM2_CSEL1_GPIO13 \ + ESP32_PINMUX(13, ESP_NOSIG, ESP_FSPICS1_OUT) + +#define SPIM2_CSEL1_GPIO14 \ + ESP32_PINMUX(14, ESP_NOSIG, ESP_FSPICS1_OUT) + +#define SPIM2_CSEL1_GPIO15 \ + ESP32_PINMUX(15, ESP_NOSIG, ESP_FSPICS1_OUT) + +#define SPIM2_CSEL1_GPIO16 \ + ESP32_PINMUX(16, ESP_NOSIG, ESP_FSPICS1_OUT) + +#define SPIM2_CSEL1_GPIO17 \ + ESP32_PINMUX(17, ESP_NOSIG, ESP_FSPICS1_OUT) + +#define SPIM2_CSEL1_GPIO18 \ + ESP32_PINMUX(18, ESP_NOSIG, ESP_FSPICS1_OUT) + +#define SPIM2_CSEL1_GPIO19 \ + ESP32_PINMUX(19, ESP_NOSIG, ESP_FSPICS1_OUT) + +#define SPIM2_CSEL1_GPIO20 \ + ESP32_PINMUX(20, ESP_NOSIG, ESP_FSPICS1_OUT) + +#define SPIM2_CSEL1_GPIO21 \ + ESP32_PINMUX(21, ESP_NOSIG, ESP_FSPICS1_OUT) + +#define SPIM2_CSEL1_GPIO26 \ + ESP32_PINMUX(26, ESP_NOSIG, ESP_FSPICS1_OUT) + +#define SPIM2_CSEL1_GPIO27 \ + ESP32_PINMUX(27, ESP_NOSIG, ESP_FSPICS1_OUT) + +#define SPIM2_CSEL1_GPIO28 \ + ESP32_PINMUX(28, ESP_NOSIG, ESP_FSPICS1_OUT) + +#define SPIM2_CSEL1_GPIO29 \ + ESP32_PINMUX(29, ESP_NOSIG, ESP_FSPICS1_OUT) + +#define SPIM2_CSEL1_GPIO30 \ + ESP32_PINMUX(30, ESP_NOSIG, ESP_FSPICS1_OUT) + +#define SPIM2_CSEL1_GPIO31 \ + ESP32_PINMUX(31, ESP_NOSIG, ESP_FSPICS1_OUT) + +#define SPIM2_CSEL1_GPIO32 \ + ESP32_PINMUX(32, ESP_NOSIG, ESP_FSPICS1_OUT) + +#define SPIM2_CSEL1_GPIO33 \ + ESP32_PINMUX(33, ESP_NOSIG, ESP_FSPICS1_OUT) + +#define SPIM2_CSEL1_GPIO34 \ + ESP32_PINMUX(34, ESP_NOSIG, ESP_FSPICS1_OUT) + +#define SPIM2_CSEL1_GPIO35 \ + ESP32_PINMUX(35, ESP_NOSIG, ESP_FSPICS1_OUT) + +#define SPIM2_CSEL1_GPIO36 \ + ESP32_PINMUX(36, ESP_NOSIG, ESP_FSPICS1_OUT) + +#define SPIM2_CSEL1_GPIO37 \ + ESP32_PINMUX(37, ESP_NOSIG, ESP_FSPICS1_OUT) + +#define SPIM2_CSEL1_GPIO38 \ + ESP32_PINMUX(38, ESP_NOSIG, ESP_FSPICS1_OUT) + +#define SPIM2_CSEL1_GPIO39 \ + ESP32_PINMUX(39, ESP_NOSIG, ESP_FSPICS1_OUT) + +#define SPIM2_CSEL1_GPIO40 \ + ESP32_PINMUX(40, ESP_NOSIG, ESP_FSPICS1_OUT) + +#define SPIM2_CSEL1_GPIO41 \ + ESP32_PINMUX(41, ESP_NOSIG, ESP_FSPICS1_OUT) + +#define SPIM2_CSEL1_GPIO42 \ + ESP32_PINMUX(42, ESP_NOSIG, ESP_FSPICS1_OUT) + +#define SPIM2_CSEL1_GPIO43 \ + ESP32_PINMUX(43, ESP_NOSIG, ESP_FSPICS1_OUT) + +#define SPIM2_CSEL1_GPIO44 \ + ESP32_PINMUX(44, ESP_NOSIG, ESP_FSPICS1_OUT) + +#define SPIM2_CSEL1_GPIO45 \ + ESP32_PINMUX(45, ESP_NOSIG, ESP_FSPICS1_OUT) + +#define SPIM2_CSEL1_GPIO46 \ + ESP32_PINMUX(46, ESP_NOSIG, ESP_FSPICS1_OUT) + +#define SPIM2_CSEL1_GPIO47 \ + ESP32_PINMUX(47, ESP_NOSIG, ESP_FSPICS1_OUT) + +#define SPIM2_CSEL1_GPIO48 \ + ESP32_PINMUX(48, ESP_NOSIG, ESP_FSPICS1_OUT) + +/* SPIM2_CSEL2 */ +#define SPIM2_CSEL2_GPIO0 \ + ESP32_PINMUX(0, ESP_NOSIG, ESP_FSPICS2_OUT) + +#define SPIM2_CSEL2_GPIO1 \ + ESP32_PINMUX(1, ESP_NOSIG, ESP_FSPICS2_OUT) + +#define SPIM2_CSEL2_GPIO2 \ + ESP32_PINMUX(2, ESP_NOSIG, ESP_FSPICS2_OUT) + +#define SPIM2_CSEL2_GPIO3 \ + ESP32_PINMUX(3, ESP_NOSIG, ESP_FSPICS2_OUT) + +#define SPIM2_CSEL2_GPIO4 \ + ESP32_PINMUX(4, ESP_NOSIG, ESP_FSPICS2_OUT) + +#define SPIM2_CSEL2_GPIO5 \ + ESP32_PINMUX(5, ESP_NOSIG, ESP_FSPICS2_OUT) + +#define SPIM2_CSEL2_GPIO6 \ + ESP32_PINMUX(6, ESP_NOSIG, ESP_FSPICS2_OUT) + +#define SPIM2_CSEL2_GPIO7 \ + ESP32_PINMUX(7, ESP_NOSIG, ESP_FSPICS2_OUT) + +#define SPIM2_CSEL2_GPIO8 \ + ESP32_PINMUX(8, ESP_NOSIG, ESP_FSPICS2_OUT) + +#define SPIM2_CSEL2_GPIO9 \ + ESP32_PINMUX(9, ESP_NOSIG, ESP_FSPICS2_OUT) + +#define SPIM2_CSEL2_GPIO10 \ + ESP32_PINMUX(10, ESP_NOSIG, ESP_FSPICS2_OUT) + +#define SPIM2_CSEL2_GPIO11 \ + ESP32_PINMUX(11, ESP_NOSIG, ESP_FSPICS2_OUT) + +#define SPIM2_CSEL2_GPIO12 \ + ESP32_PINMUX(12, ESP_NOSIG, ESP_FSPICS2_OUT) + +#define SPIM2_CSEL2_GPIO13 \ + ESP32_PINMUX(13, ESP_NOSIG, ESP_FSPICS2_OUT) + +#define SPIM2_CSEL2_GPIO14 \ + ESP32_PINMUX(14, ESP_NOSIG, ESP_FSPICS2_OUT) + +#define SPIM2_CSEL2_GPIO15 \ + ESP32_PINMUX(15, ESP_NOSIG, ESP_FSPICS2_OUT) + +#define SPIM2_CSEL2_GPIO16 \ + ESP32_PINMUX(16, ESP_NOSIG, ESP_FSPICS2_OUT) + +#define SPIM2_CSEL2_GPIO17 \ + ESP32_PINMUX(17, ESP_NOSIG, ESP_FSPICS2_OUT) + +#define SPIM2_CSEL2_GPIO18 \ + ESP32_PINMUX(18, ESP_NOSIG, ESP_FSPICS2_OUT) + +#define SPIM2_CSEL2_GPIO19 \ + ESP32_PINMUX(19, ESP_NOSIG, ESP_FSPICS2_OUT) + +#define SPIM2_CSEL2_GPIO20 \ + ESP32_PINMUX(20, ESP_NOSIG, ESP_FSPICS2_OUT) + +#define SPIM2_CSEL2_GPIO21 \ + ESP32_PINMUX(21, ESP_NOSIG, ESP_FSPICS2_OUT) + +#define SPIM2_CSEL2_GPIO26 \ + ESP32_PINMUX(26, ESP_NOSIG, ESP_FSPICS2_OUT) + +#define SPIM2_CSEL2_GPIO27 \ + ESP32_PINMUX(27, ESP_NOSIG, ESP_FSPICS2_OUT) + +#define SPIM2_CSEL2_GPIO28 \ + ESP32_PINMUX(28, ESP_NOSIG, ESP_FSPICS2_OUT) + +#define SPIM2_CSEL2_GPIO29 \ + ESP32_PINMUX(29, ESP_NOSIG, ESP_FSPICS2_OUT) + +#define SPIM2_CSEL2_GPIO30 \ + ESP32_PINMUX(30, ESP_NOSIG, ESP_FSPICS2_OUT) + +#define SPIM2_CSEL2_GPIO31 \ + ESP32_PINMUX(31, ESP_NOSIG, ESP_FSPICS2_OUT) + +#define SPIM2_CSEL2_GPIO32 \ + ESP32_PINMUX(32, ESP_NOSIG, ESP_FSPICS2_OUT) + +#define SPIM2_CSEL2_GPIO33 \ + ESP32_PINMUX(33, ESP_NOSIG, ESP_FSPICS2_OUT) + +#define SPIM2_CSEL2_GPIO34 \ + ESP32_PINMUX(34, ESP_NOSIG, ESP_FSPICS2_OUT) + +#define SPIM2_CSEL2_GPIO35 \ + ESP32_PINMUX(35, ESP_NOSIG, ESP_FSPICS2_OUT) + +#define SPIM2_CSEL2_GPIO36 \ + ESP32_PINMUX(36, ESP_NOSIG, ESP_FSPICS2_OUT) + +#define SPIM2_CSEL2_GPIO37 \ + ESP32_PINMUX(37, ESP_NOSIG, ESP_FSPICS2_OUT) + +#define SPIM2_CSEL2_GPIO38 \ + ESP32_PINMUX(38, ESP_NOSIG, ESP_FSPICS2_OUT) + +#define SPIM2_CSEL2_GPIO39 \ + ESP32_PINMUX(39, ESP_NOSIG, ESP_FSPICS2_OUT) + +#define SPIM2_CSEL2_GPIO40 \ + ESP32_PINMUX(40, ESP_NOSIG, ESP_FSPICS2_OUT) + +#define SPIM2_CSEL2_GPIO41 \ + ESP32_PINMUX(41, ESP_NOSIG, ESP_FSPICS2_OUT) + +#define SPIM2_CSEL2_GPIO42 \ + ESP32_PINMUX(42, ESP_NOSIG, ESP_FSPICS2_OUT) + +#define SPIM2_CSEL2_GPIO43 \ + ESP32_PINMUX(43, ESP_NOSIG, ESP_FSPICS2_OUT) + +#define SPIM2_CSEL2_GPIO44 \ + ESP32_PINMUX(44, ESP_NOSIG, ESP_FSPICS2_OUT) + +#define SPIM2_CSEL2_GPIO45 \ + ESP32_PINMUX(45, ESP_NOSIG, ESP_FSPICS2_OUT) + +#define SPIM2_CSEL2_GPIO46 \ + ESP32_PINMUX(46, ESP_NOSIG, ESP_FSPICS2_OUT) + +#define SPIM2_CSEL2_GPIO47 \ + ESP32_PINMUX(47, ESP_NOSIG, ESP_FSPICS2_OUT) + +#define SPIM2_CSEL2_GPIO48 \ + ESP32_PINMUX(48, ESP_NOSIG, ESP_FSPICS2_OUT) + +/* SPIM2_CSEL3 */ +#define SPIM2_CSEL3_GPIO0 \ + ESP32_PINMUX(0, ESP_NOSIG, ESP_FSPICS3_OUT) + +#define SPIM2_CSEL3_GPIO1 \ + ESP32_PINMUX(1, ESP_NOSIG, ESP_FSPICS3_OUT) + +#define SPIM2_CSEL3_GPIO2 \ + ESP32_PINMUX(2, ESP_NOSIG, ESP_FSPICS3_OUT) + +#define SPIM2_CSEL3_GPIO3 \ + ESP32_PINMUX(3, ESP_NOSIG, ESP_FSPICS3_OUT) + +#define SPIM2_CSEL3_GPIO4 \ + ESP32_PINMUX(4, ESP_NOSIG, ESP_FSPICS3_OUT) + +#define SPIM2_CSEL3_GPIO5 \ + ESP32_PINMUX(5, ESP_NOSIG, ESP_FSPICS3_OUT) + +#define SPIM2_CSEL3_GPIO6 \ + ESP32_PINMUX(6, ESP_NOSIG, ESP_FSPICS3_OUT) + +#define SPIM2_CSEL3_GPIO7 \ + ESP32_PINMUX(7, ESP_NOSIG, ESP_FSPICS3_OUT) + +#define SPIM2_CSEL3_GPIO8 \ + ESP32_PINMUX(8, ESP_NOSIG, ESP_FSPICS3_OUT) + +#define SPIM2_CSEL3_GPIO9 \ + ESP32_PINMUX(9, ESP_NOSIG, ESP_FSPICS3_OUT) + +#define SPIM2_CSEL3_GPIO10 \ + ESP32_PINMUX(10, ESP_NOSIG, ESP_FSPICS3_OUT) + +#define SPIM2_CSEL3_GPIO11 \ + ESP32_PINMUX(11, ESP_NOSIG, ESP_FSPICS3_OUT) + +#define SPIM2_CSEL3_GPIO12 \ + ESP32_PINMUX(12, ESP_NOSIG, ESP_FSPICS3_OUT) + +#define SPIM2_CSEL3_GPIO13 \ + ESP32_PINMUX(13, ESP_NOSIG, ESP_FSPICS3_OUT) + +#define SPIM2_CSEL3_GPIO14 \ + ESP32_PINMUX(14, ESP_NOSIG, ESP_FSPICS3_OUT) + +#define SPIM2_CSEL3_GPIO15 \ + ESP32_PINMUX(15, ESP_NOSIG, ESP_FSPICS3_OUT) + +#define SPIM2_CSEL3_GPIO16 \ + ESP32_PINMUX(16, ESP_NOSIG, ESP_FSPICS3_OUT) + +#define SPIM2_CSEL3_GPIO17 \ + ESP32_PINMUX(17, ESP_NOSIG, ESP_FSPICS3_OUT) + +#define SPIM2_CSEL3_GPIO18 \ + ESP32_PINMUX(18, ESP_NOSIG, ESP_FSPICS3_OUT) + +#define SPIM2_CSEL3_GPIO19 \ + ESP32_PINMUX(19, ESP_NOSIG, ESP_FSPICS3_OUT) + +#define SPIM2_CSEL3_GPIO20 \ + ESP32_PINMUX(20, ESP_NOSIG, ESP_FSPICS3_OUT) + +#define SPIM2_CSEL3_GPIO21 \ + ESP32_PINMUX(21, ESP_NOSIG, ESP_FSPICS3_OUT) + +#define SPIM2_CSEL3_GPIO26 \ + ESP32_PINMUX(26, ESP_NOSIG, ESP_FSPICS3_OUT) + +#define SPIM2_CSEL3_GPIO27 \ + ESP32_PINMUX(27, ESP_NOSIG, ESP_FSPICS3_OUT) + +#define SPIM2_CSEL3_GPIO28 \ + ESP32_PINMUX(28, ESP_NOSIG, ESP_FSPICS3_OUT) + +#define SPIM2_CSEL3_GPIO29 \ + ESP32_PINMUX(29, ESP_NOSIG, ESP_FSPICS3_OUT) + +#define SPIM2_CSEL3_GPIO30 \ + ESP32_PINMUX(30, ESP_NOSIG, ESP_FSPICS3_OUT) + +#define SPIM2_CSEL3_GPIO31 \ + ESP32_PINMUX(31, ESP_NOSIG, ESP_FSPICS3_OUT) + +#define SPIM2_CSEL3_GPIO32 \ + ESP32_PINMUX(32, ESP_NOSIG, ESP_FSPICS3_OUT) + +#define SPIM2_CSEL3_GPIO33 \ + ESP32_PINMUX(33, ESP_NOSIG, ESP_FSPICS3_OUT) + +#define SPIM2_CSEL3_GPIO34 \ + ESP32_PINMUX(34, ESP_NOSIG, ESP_FSPICS3_OUT) + +#define SPIM2_CSEL3_GPIO35 \ + ESP32_PINMUX(35, ESP_NOSIG, ESP_FSPICS3_OUT) + +#define SPIM2_CSEL3_GPIO36 \ + ESP32_PINMUX(36, ESP_NOSIG, ESP_FSPICS3_OUT) + +#define SPIM2_CSEL3_GPIO37 \ + ESP32_PINMUX(37, ESP_NOSIG, ESP_FSPICS3_OUT) + +#define SPIM2_CSEL3_GPIO38 \ + ESP32_PINMUX(38, ESP_NOSIG, ESP_FSPICS3_OUT) + +#define SPIM2_CSEL3_GPIO39 \ + ESP32_PINMUX(39, ESP_NOSIG, ESP_FSPICS3_OUT) + +#define SPIM2_CSEL3_GPIO40 \ + ESP32_PINMUX(40, ESP_NOSIG, ESP_FSPICS3_OUT) + +#define SPIM2_CSEL3_GPIO41 \ + ESP32_PINMUX(41, ESP_NOSIG, ESP_FSPICS3_OUT) + +#define SPIM2_CSEL3_GPIO42 \ + ESP32_PINMUX(42, ESP_NOSIG, ESP_FSPICS3_OUT) + +#define SPIM2_CSEL3_GPIO43 \ + ESP32_PINMUX(43, ESP_NOSIG, ESP_FSPICS3_OUT) + +#define SPIM2_CSEL3_GPIO44 \ + ESP32_PINMUX(44, ESP_NOSIG, ESP_FSPICS3_OUT) + +#define SPIM2_CSEL3_GPIO45 \ + ESP32_PINMUX(45, ESP_NOSIG, ESP_FSPICS3_OUT) + +#define SPIM2_CSEL3_GPIO46 \ + ESP32_PINMUX(46, ESP_NOSIG, ESP_FSPICS3_OUT) + +#define SPIM2_CSEL3_GPIO47 \ + ESP32_PINMUX(47, ESP_NOSIG, ESP_FSPICS3_OUT) + +#define SPIM2_CSEL3_GPIO48 \ + ESP32_PINMUX(48, ESP_NOSIG, ESP_FSPICS3_OUT) + +/* SPIM2_CSEL4 */ +#define SPIM2_CSEL4_GPIO0 \ + ESP32_PINMUX(0, ESP_NOSIG, ESP_FSPICS4_OUT) + +#define SPIM2_CSEL4_GPIO1 \ + ESP32_PINMUX(1, ESP_NOSIG, ESP_FSPICS4_OUT) + +#define SPIM2_CSEL4_GPIO2 \ + ESP32_PINMUX(2, ESP_NOSIG, ESP_FSPICS4_OUT) + +#define SPIM2_CSEL4_GPIO3 \ + ESP32_PINMUX(3, ESP_NOSIG, ESP_FSPICS4_OUT) + +#define SPIM2_CSEL4_GPIO4 \ + ESP32_PINMUX(4, ESP_NOSIG, ESP_FSPICS4_OUT) + +#define SPIM2_CSEL4_GPIO5 \ + ESP32_PINMUX(5, ESP_NOSIG, ESP_FSPICS4_OUT) + +#define SPIM2_CSEL4_GPIO6 \ + ESP32_PINMUX(6, ESP_NOSIG, ESP_FSPICS4_OUT) + +#define SPIM2_CSEL4_GPIO7 \ + ESP32_PINMUX(7, ESP_NOSIG, ESP_FSPICS4_OUT) + +#define SPIM2_CSEL4_GPIO8 \ + ESP32_PINMUX(8, ESP_NOSIG, ESP_FSPICS4_OUT) + +#define SPIM2_CSEL4_GPIO9 \ + ESP32_PINMUX(9, ESP_NOSIG, ESP_FSPICS4_OUT) + +#define SPIM2_CSEL4_GPIO10 \ + ESP32_PINMUX(10, ESP_NOSIG, ESP_FSPICS4_OUT) + +#define SPIM2_CSEL4_GPIO11 \ + ESP32_PINMUX(11, ESP_NOSIG, ESP_FSPICS4_OUT) + +#define SPIM2_CSEL4_GPIO12 \ + ESP32_PINMUX(12, ESP_NOSIG, ESP_FSPICS4_OUT) + +#define SPIM2_CSEL4_GPIO13 \ + ESP32_PINMUX(13, ESP_NOSIG, ESP_FSPICS4_OUT) + +#define SPIM2_CSEL4_GPIO14 \ + ESP32_PINMUX(14, ESP_NOSIG, ESP_FSPICS4_OUT) + +#define SPIM2_CSEL4_GPIO15 \ + ESP32_PINMUX(15, ESP_NOSIG, ESP_FSPICS4_OUT) + +#define SPIM2_CSEL4_GPIO16 \ + ESP32_PINMUX(16, ESP_NOSIG, ESP_FSPICS4_OUT) + +#define SPIM2_CSEL4_GPIO17 \ + ESP32_PINMUX(17, ESP_NOSIG, ESP_FSPICS4_OUT) + +#define SPIM2_CSEL4_GPIO18 \ + ESP32_PINMUX(18, ESP_NOSIG, ESP_FSPICS4_OUT) + +#define SPIM2_CSEL4_GPIO19 \ + ESP32_PINMUX(19, ESP_NOSIG, ESP_FSPICS4_OUT) + +#define SPIM2_CSEL4_GPIO20 \ + ESP32_PINMUX(20, ESP_NOSIG, ESP_FSPICS4_OUT) + +#define SPIM2_CSEL4_GPIO21 \ + ESP32_PINMUX(21, ESP_NOSIG, ESP_FSPICS4_OUT) + +#define SPIM2_CSEL4_GPIO26 \ + ESP32_PINMUX(26, ESP_NOSIG, ESP_FSPICS4_OUT) + +#define SPIM2_CSEL4_GPIO27 \ + ESP32_PINMUX(27, ESP_NOSIG, ESP_FSPICS4_OUT) + +#define SPIM2_CSEL4_GPIO28 \ + ESP32_PINMUX(28, ESP_NOSIG, ESP_FSPICS4_OUT) + +#define SPIM2_CSEL4_GPIO29 \ + ESP32_PINMUX(29, ESP_NOSIG, ESP_FSPICS4_OUT) + +#define SPIM2_CSEL4_GPIO30 \ + ESP32_PINMUX(30, ESP_NOSIG, ESP_FSPICS4_OUT) + +#define SPIM2_CSEL4_GPIO31 \ + ESP32_PINMUX(31, ESP_NOSIG, ESP_FSPICS4_OUT) + +#define SPIM2_CSEL4_GPIO32 \ + ESP32_PINMUX(32, ESP_NOSIG, ESP_FSPICS4_OUT) + +#define SPIM2_CSEL4_GPIO33 \ + ESP32_PINMUX(33, ESP_NOSIG, ESP_FSPICS4_OUT) + +#define SPIM2_CSEL4_GPIO34 \ + ESP32_PINMUX(34, ESP_NOSIG, ESP_FSPICS4_OUT) + +#define SPIM2_CSEL4_GPIO35 \ + ESP32_PINMUX(35, ESP_NOSIG, ESP_FSPICS4_OUT) + +#define SPIM2_CSEL4_GPIO36 \ + ESP32_PINMUX(36, ESP_NOSIG, ESP_FSPICS4_OUT) + +#define SPIM2_CSEL4_GPIO37 \ + ESP32_PINMUX(37, ESP_NOSIG, ESP_FSPICS4_OUT) + +#define SPIM2_CSEL4_GPIO38 \ + ESP32_PINMUX(38, ESP_NOSIG, ESP_FSPICS4_OUT) + +#define SPIM2_CSEL4_GPIO39 \ + ESP32_PINMUX(39, ESP_NOSIG, ESP_FSPICS4_OUT) + +#define SPIM2_CSEL4_GPIO40 \ + ESP32_PINMUX(40, ESP_NOSIG, ESP_FSPICS4_OUT) + +#define SPIM2_CSEL4_GPIO41 \ + ESP32_PINMUX(41, ESP_NOSIG, ESP_FSPICS4_OUT) + +#define SPIM2_CSEL4_GPIO42 \ + ESP32_PINMUX(42, ESP_NOSIG, ESP_FSPICS4_OUT) + +#define SPIM2_CSEL4_GPIO43 \ + ESP32_PINMUX(43, ESP_NOSIG, ESP_FSPICS4_OUT) + +#define SPIM2_CSEL4_GPIO44 \ + ESP32_PINMUX(44, ESP_NOSIG, ESP_FSPICS4_OUT) + +#define SPIM2_CSEL4_GPIO45 \ + ESP32_PINMUX(45, ESP_NOSIG, ESP_FSPICS4_OUT) + +#define SPIM2_CSEL4_GPIO46 \ + ESP32_PINMUX(46, ESP_NOSIG, ESP_FSPICS4_OUT) + +#define SPIM2_CSEL4_GPIO47 \ + ESP32_PINMUX(47, ESP_NOSIG, ESP_FSPICS4_OUT) + +#define SPIM2_CSEL4_GPIO48 \ + ESP32_PINMUX(48, ESP_NOSIG, ESP_FSPICS4_OUT) + +/* SPIM2_CSEL5 */ +#define SPIM2_CSEL5_GPIO0 \ + ESP32_PINMUX(0, ESP_NOSIG, ESP_FSPICS5_OUT) + +#define SPIM2_CSEL5_GPIO1 \ + ESP32_PINMUX(1, ESP_NOSIG, ESP_FSPICS5_OUT) + +#define SPIM2_CSEL5_GPIO2 \ + ESP32_PINMUX(2, ESP_NOSIG, ESP_FSPICS5_OUT) + +#define SPIM2_CSEL5_GPIO3 \ + ESP32_PINMUX(3, ESP_NOSIG, ESP_FSPICS5_OUT) + +#define SPIM2_CSEL5_GPIO4 \ + ESP32_PINMUX(4, ESP_NOSIG, ESP_FSPICS5_OUT) + +#define SPIM2_CSEL5_GPIO5 \ + ESP32_PINMUX(5, ESP_NOSIG, ESP_FSPICS5_OUT) + +#define SPIM2_CSEL5_GPIO6 \ + ESP32_PINMUX(6, ESP_NOSIG, ESP_FSPICS5_OUT) + +#define SPIM2_CSEL5_GPIO7 \ + ESP32_PINMUX(7, ESP_NOSIG, ESP_FSPICS5_OUT) + +#define SPIM2_CSEL5_GPIO8 \ + ESP32_PINMUX(8, ESP_NOSIG, ESP_FSPICS5_OUT) + +#define SPIM2_CSEL5_GPIO9 \ + ESP32_PINMUX(9, ESP_NOSIG, ESP_FSPICS5_OUT) + +#define SPIM2_CSEL5_GPIO10 \ + ESP32_PINMUX(10, ESP_NOSIG, ESP_FSPICS5_OUT) + +#define SPIM2_CSEL5_GPIO11 \ + ESP32_PINMUX(11, ESP_NOSIG, ESP_FSPICS5_OUT) + +#define SPIM2_CSEL5_GPIO12 \ + ESP32_PINMUX(12, ESP_NOSIG, ESP_FSPICS5_OUT) + +#define SPIM2_CSEL5_GPIO13 \ + ESP32_PINMUX(13, ESP_NOSIG, ESP_FSPICS5_OUT) + +#define SPIM2_CSEL5_GPIO14 \ + ESP32_PINMUX(14, ESP_NOSIG, ESP_FSPICS5_OUT) + +#define SPIM2_CSEL5_GPIO15 \ + ESP32_PINMUX(15, ESP_NOSIG, ESP_FSPICS5_OUT) + +#define SPIM2_CSEL5_GPIO16 \ + ESP32_PINMUX(16, ESP_NOSIG, ESP_FSPICS5_OUT) + +#define SPIM2_CSEL5_GPIO17 \ + ESP32_PINMUX(17, ESP_NOSIG, ESP_FSPICS5_OUT) + +#define SPIM2_CSEL5_GPIO18 \ + ESP32_PINMUX(18, ESP_NOSIG, ESP_FSPICS5_OUT) + +#define SPIM2_CSEL5_GPIO19 \ + ESP32_PINMUX(19, ESP_NOSIG, ESP_FSPICS5_OUT) + +#define SPIM2_CSEL5_GPIO20 \ + ESP32_PINMUX(20, ESP_NOSIG, ESP_FSPICS5_OUT) + +#define SPIM2_CSEL5_GPIO21 \ + ESP32_PINMUX(21, ESP_NOSIG, ESP_FSPICS5_OUT) + +#define SPIM2_CSEL5_GPIO26 \ + ESP32_PINMUX(26, ESP_NOSIG, ESP_FSPICS5_OUT) + +#define SPIM2_CSEL5_GPIO27 \ + ESP32_PINMUX(27, ESP_NOSIG, ESP_FSPICS5_OUT) + +#define SPIM2_CSEL5_GPIO28 \ + ESP32_PINMUX(28, ESP_NOSIG, ESP_FSPICS5_OUT) + +#define SPIM2_CSEL5_GPIO29 \ + ESP32_PINMUX(29, ESP_NOSIG, ESP_FSPICS5_OUT) + +#define SPIM2_CSEL5_GPIO30 \ + ESP32_PINMUX(30, ESP_NOSIG, ESP_FSPICS5_OUT) + +#define SPIM2_CSEL5_GPIO31 \ + ESP32_PINMUX(31, ESP_NOSIG, ESP_FSPICS5_OUT) + +#define SPIM2_CSEL5_GPIO32 \ + ESP32_PINMUX(32, ESP_NOSIG, ESP_FSPICS5_OUT) + +#define SPIM2_CSEL5_GPIO33 \ + ESP32_PINMUX(33, ESP_NOSIG, ESP_FSPICS5_OUT) + +#define SPIM2_CSEL5_GPIO34 \ + ESP32_PINMUX(34, ESP_NOSIG, ESP_FSPICS5_OUT) + +#define SPIM2_CSEL5_GPIO35 \ + ESP32_PINMUX(35, ESP_NOSIG, ESP_FSPICS5_OUT) + +#define SPIM2_CSEL5_GPIO36 \ + ESP32_PINMUX(36, ESP_NOSIG, ESP_FSPICS5_OUT) + +#define SPIM2_CSEL5_GPIO37 \ + ESP32_PINMUX(37, ESP_NOSIG, ESP_FSPICS5_OUT) + +#define SPIM2_CSEL5_GPIO38 \ + ESP32_PINMUX(38, ESP_NOSIG, ESP_FSPICS5_OUT) + +#define SPIM2_CSEL5_GPIO39 \ + ESP32_PINMUX(39, ESP_NOSIG, ESP_FSPICS5_OUT) + +#define SPIM2_CSEL5_GPIO40 \ + ESP32_PINMUX(40, ESP_NOSIG, ESP_FSPICS5_OUT) + +#define SPIM2_CSEL5_GPIO41 \ + ESP32_PINMUX(41, ESP_NOSIG, ESP_FSPICS5_OUT) + +#define SPIM2_CSEL5_GPIO42 \ + ESP32_PINMUX(42, ESP_NOSIG, ESP_FSPICS5_OUT) + +#define SPIM2_CSEL5_GPIO43 \ + ESP32_PINMUX(43, ESP_NOSIG, ESP_FSPICS5_OUT) + +#define SPIM2_CSEL5_GPIO44 \ + ESP32_PINMUX(44, ESP_NOSIG, ESP_FSPICS5_OUT) + +#define SPIM2_CSEL5_GPIO45 \ + ESP32_PINMUX(45, ESP_NOSIG, ESP_FSPICS5_OUT) + +#define SPIM2_CSEL5_GPIO46 \ + ESP32_PINMUX(46, ESP_NOSIG, ESP_FSPICS5_OUT) + +#define SPIM2_CSEL5_GPIO47 \ + ESP32_PINMUX(47, ESP_NOSIG, ESP_FSPICS5_OUT) + +#define SPIM2_CSEL5_GPIO48 \ + ESP32_PINMUX(48, ESP_NOSIG, ESP_FSPICS5_OUT) + +/* SPIM2_MISO */ +#define SPIM2_MISO_GPIO0 \ + ESP32_PINMUX(0, ESP_FSPIQ_IN, ESP_NOSIG) + +#define SPIM2_MISO_GPIO1 \ + ESP32_PINMUX(1, ESP_FSPIQ_IN, ESP_NOSIG) + +#define SPIM2_MISO_GPIO2 \ + ESP32_PINMUX(2, ESP_FSPIQ_IN, ESP_NOSIG) + +#define SPIM2_MISO_GPIO3 \ + ESP32_PINMUX(3, ESP_FSPIQ_IN, ESP_NOSIG) + +#define SPIM2_MISO_GPIO4 \ + ESP32_PINMUX(4, ESP_FSPIQ_IN, ESP_NOSIG) + +#define SPIM2_MISO_GPIO5 \ + ESP32_PINMUX(5, ESP_FSPIQ_IN, ESP_NOSIG) + +#define SPIM2_MISO_GPIO6 \ + ESP32_PINMUX(6, ESP_FSPIQ_IN, ESP_NOSIG) + +#define SPIM2_MISO_GPIO7 \ + ESP32_PINMUX(7, ESP_FSPIQ_IN, ESP_NOSIG) + +#define SPIM2_MISO_GPIO8 \ + ESP32_PINMUX(8, ESP_FSPIQ_IN, ESP_NOSIG) + +#define SPIM2_MISO_GPIO9 \ + ESP32_PINMUX(9, ESP_FSPIQ_IN, ESP_NOSIG) + +#define SPIM2_MISO_GPIO10 \ + ESP32_PINMUX(10, ESP_FSPIQ_IN, ESP_NOSIG) + +#define SPIM2_MISO_GPIO11 \ + ESP32_PINMUX(11, ESP_FSPIQ_IN, ESP_NOSIG) + +#define SPIM2_MISO_GPIO12 \ + ESP32_PINMUX(12, ESP_FSPIQ_IN, ESP_NOSIG) + +#define SPIM2_MISO_GPIO13 \ + ESP32_PINMUX(13, ESP_FSPIQ_IN, ESP_NOSIG) + +#define SPIM2_MISO_GPIO14 \ + ESP32_PINMUX(14, ESP_FSPIQ_IN, ESP_NOSIG) + +#define SPIM2_MISO_GPIO15 \ + ESP32_PINMUX(15, ESP_FSPIQ_IN, ESP_NOSIG) + +#define SPIM2_MISO_GPIO16 \ + ESP32_PINMUX(16, ESP_FSPIQ_IN, ESP_NOSIG) + +#define SPIM2_MISO_GPIO17 \ + ESP32_PINMUX(17, ESP_FSPIQ_IN, ESP_NOSIG) + +#define SPIM2_MISO_GPIO18 \ + ESP32_PINMUX(18, ESP_FSPIQ_IN, ESP_NOSIG) + +#define SPIM2_MISO_GPIO19 \ + ESP32_PINMUX(19, ESP_FSPIQ_IN, ESP_NOSIG) + +#define SPIM2_MISO_GPIO20 \ + ESP32_PINMUX(20, ESP_FSPIQ_IN, ESP_NOSIG) + +#define SPIM2_MISO_GPIO21 \ + ESP32_PINMUX(21, ESP_FSPIQ_IN, ESP_NOSIG) + +#define SPIM2_MISO_GPIO26 \ + ESP32_PINMUX(26, ESP_FSPIQ_IN, ESP_NOSIG) + +#define SPIM2_MISO_GPIO27 \ + ESP32_PINMUX(27, ESP_FSPIQ_IN, ESP_NOSIG) + +#define SPIM2_MISO_GPIO28 \ + ESP32_PINMUX(28, ESP_FSPIQ_IN, ESP_NOSIG) + +#define SPIM2_MISO_GPIO29 \ + ESP32_PINMUX(29, ESP_FSPIQ_IN, ESP_NOSIG) + +#define SPIM2_MISO_GPIO30 \ + ESP32_PINMUX(30, ESP_FSPIQ_IN, ESP_NOSIG) + +#define SPIM2_MISO_GPIO31 \ + ESP32_PINMUX(31, ESP_FSPIQ_IN, ESP_NOSIG) + +#define SPIM2_MISO_GPIO32 \ + ESP32_PINMUX(32, ESP_FSPIQ_IN, ESP_NOSIG) + +#define SPIM2_MISO_GPIO33 \ + ESP32_PINMUX(33, ESP_FSPIQ_IN, ESP_NOSIG) + +#define SPIM2_MISO_GPIO34 \ + ESP32_PINMUX(34, ESP_FSPIQ_IN, ESP_NOSIG) + +#define SPIM2_MISO_GPIO35 \ + ESP32_PINMUX(35, ESP_FSPIQ_IN, ESP_NOSIG) + +#define SPIM2_MISO_GPIO36 \ + ESP32_PINMUX(36, ESP_FSPIQ_IN, ESP_NOSIG) + +#define SPIM2_MISO_GPIO37 \ + ESP32_PINMUX(37, ESP_FSPIQ_IN, ESP_NOSIG) + +#define SPIM2_MISO_GPIO38 \ + ESP32_PINMUX(38, ESP_FSPIQ_IN, ESP_NOSIG) + +#define SPIM2_MISO_GPIO39 \ + ESP32_PINMUX(39, ESP_FSPIQ_IN, ESP_NOSIG) + +#define SPIM2_MISO_GPIO40 \ + ESP32_PINMUX(40, ESP_FSPIQ_IN, ESP_NOSIG) + +#define SPIM2_MISO_GPIO41 \ + ESP32_PINMUX(41, ESP_FSPIQ_IN, ESP_NOSIG) + +#define SPIM2_MISO_GPIO42 \ + ESP32_PINMUX(42, ESP_FSPIQ_IN, ESP_NOSIG) + +#define SPIM2_MISO_GPIO43 \ + ESP32_PINMUX(43, ESP_FSPIQ_IN, ESP_NOSIG) + +#define SPIM2_MISO_GPIO44 \ + ESP32_PINMUX(44, ESP_FSPIQ_IN, ESP_NOSIG) + +#define SPIM2_MISO_GPIO45 \ + ESP32_PINMUX(45, ESP_FSPIQ_IN, ESP_NOSIG) + +#define SPIM2_MISO_GPIO46 \ + ESP32_PINMUX(46, ESP_FSPIQ_IN, ESP_NOSIG) + +#define SPIM2_MISO_GPIO47 \ + ESP32_PINMUX(47, ESP_FSPIQ_IN, ESP_NOSIG) + +#define SPIM2_MISO_GPIO48 \ + ESP32_PINMUX(48, ESP_FSPIQ_IN, ESP_NOSIG) + +/* SPIM2_MOSI */ +#define SPIM2_MOSI_GPIO0 \ + ESP32_PINMUX(0, ESP_NOSIG, ESP_FSPID_OUT) + +#define SPIM2_MOSI_GPIO1 \ + ESP32_PINMUX(1, ESP_NOSIG, ESP_FSPID_OUT) + +#define SPIM2_MOSI_GPIO2 \ + ESP32_PINMUX(2, ESP_NOSIG, ESP_FSPID_OUT) + +#define SPIM2_MOSI_GPIO3 \ + ESP32_PINMUX(3, ESP_NOSIG, ESP_FSPID_OUT) + +#define SPIM2_MOSI_GPIO4 \ + ESP32_PINMUX(4, ESP_NOSIG, ESP_FSPID_OUT) + +#define SPIM2_MOSI_GPIO5 \ + ESP32_PINMUX(5, ESP_NOSIG, ESP_FSPID_OUT) + +#define SPIM2_MOSI_GPIO6 \ + ESP32_PINMUX(6, ESP_NOSIG, ESP_FSPID_OUT) + +#define SPIM2_MOSI_GPIO7 \ + ESP32_PINMUX(7, ESP_NOSIG, ESP_FSPID_OUT) + +#define SPIM2_MOSI_GPIO8 \ + ESP32_PINMUX(8, ESP_NOSIG, ESP_FSPID_OUT) + +#define SPIM2_MOSI_GPIO9 \ + ESP32_PINMUX(9, ESP_NOSIG, ESP_FSPID_OUT) + +#define SPIM2_MOSI_GPIO10 \ + ESP32_PINMUX(10, ESP_NOSIG, ESP_FSPID_OUT) + +#define SPIM2_MOSI_GPIO11 \ + ESP32_PINMUX(11, ESP_NOSIG, ESP_FSPID_OUT) + +#define SPIM2_MOSI_GPIO12 \ + ESP32_PINMUX(12, ESP_NOSIG, ESP_FSPID_OUT) + +#define SPIM2_MOSI_GPIO13 \ + ESP32_PINMUX(13, ESP_NOSIG, ESP_FSPID_OUT) + +#define SPIM2_MOSI_GPIO14 \ + ESP32_PINMUX(14, ESP_NOSIG, ESP_FSPID_OUT) + +#define SPIM2_MOSI_GPIO15 \ + ESP32_PINMUX(15, ESP_NOSIG, ESP_FSPID_OUT) + +#define SPIM2_MOSI_GPIO16 \ + ESP32_PINMUX(16, ESP_NOSIG, ESP_FSPID_OUT) + +#define SPIM2_MOSI_GPIO17 \ + ESP32_PINMUX(17, ESP_NOSIG, ESP_FSPID_OUT) + +#define SPIM2_MOSI_GPIO18 \ + ESP32_PINMUX(18, ESP_NOSIG, ESP_FSPID_OUT) + +#define SPIM2_MOSI_GPIO19 \ + ESP32_PINMUX(19, ESP_NOSIG, ESP_FSPID_OUT) + +#define SPIM2_MOSI_GPIO20 \ + ESP32_PINMUX(20, ESP_NOSIG, ESP_FSPID_OUT) + +#define SPIM2_MOSI_GPIO21 \ + ESP32_PINMUX(21, ESP_NOSIG, ESP_FSPID_OUT) + +#define SPIM2_MOSI_GPIO26 \ + ESP32_PINMUX(26, ESP_NOSIG, ESP_FSPID_OUT) + +#define SPIM2_MOSI_GPIO27 \ + ESP32_PINMUX(27, ESP_NOSIG, ESP_FSPID_OUT) + +#define SPIM2_MOSI_GPIO28 \ + ESP32_PINMUX(28, ESP_NOSIG, ESP_FSPID_OUT) + +#define SPIM2_MOSI_GPIO29 \ + ESP32_PINMUX(29, ESP_NOSIG, ESP_FSPID_OUT) + +#define SPIM2_MOSI_GPIO30 \ + ESP32_PINMUX(30, ESP_NOSIG, ESP_FSPID_OUT) + +#define SPIM2_MOSI_GPIO31 \ + ESP32_PINMUX(31, ESP_NOSIG, ESP_FSPID_OUT) + +#define SPIM2_MOSI_GPIO32 \ + ESP32_PINMUX(32, ESP_NOSIG, ESP_FSPID_OUT) + +#define SPIM2_MOSI_GPIO33 \ + ESP32_PINMUX(33, ESP_NOSIG, ESP_FSPID_OUT) + +#define SPIM2_MOSI_GPIO34 \ + ESP32_PINMUX(34, ESP_NOSIG, ESP_FSPID_OUT) + +#define SPIM2_MOSI_GPIO35 \ + ESP32_PINMUX(35, ESP_NOSIG, ESP_FSPID_OUT) + +#define SPIM2_MOSI_GPIO36 \ + ESP32_PINMUX(36, ESP_NOSIG, ESP_FSPID_OUT) + +#define SPIM2_MOSI_GPIO37 \ + ESP32_PINMUX(37, ESP_NOSIG, ESP_FSPID_OUT) + +#define SPIM2_MOSI_GPIO38 \ + ESP32_PINMUX(38, ESP_NOSIG, ESP_FSPID_OUT) + +#define SPIM2_MOSI_GPIO39 \ + ESP32_PINMUX(39, ESP_NOSIG, ESP_FSPID_OUT) + +#define SPIM2_MOSI_GPIO40 \ + ESP32_PINMUX(40, ESP_NOSIG, ESP_FSPID_OUT) + +#define SPIM2_MOSI_GPIO41 \ + ESP32_PINMUX(41, ESP_NOSIG, ESP_FSPID_OUT) + +#define SPIM2_MOSI_GPIO42 \ + ESP32_PINMUX(42, ESP_NOSIG, ESP_FSPID_OUT) + +#define SPIM2_MOSI_GPIO43 \ + ESP32_PINMUX(43, ESP_NOSIG, ESP_FSPID_OUT) + +#define SPIM2_MOSI_GPIO44 \ + ESP32_PINMUX(44, ESP_NOSIG, ESP_FSPID_OUT) + +#define SPIM2_MOSI_GPIO45 \ + ESP32_PINMUX(45, ESP_NOSIG, ESP_FSPID_OUT) + +#define SPIM2_MOSI_GPIO46 \ + ESP32_PINMUX(46, ESP_NOSIG, ESP_FSPID_OUT) + +#define SPIM2_MOSI_GPIO47 \ + ESP32_PINMUX(47, ESP_NOSIG, ESP_FSPID_OUT) + +#define SPIM2_MOSI_GPIO48 \ + ESP32_PINMUX(48, ESP_NOSIG, ESP_FSPID_OUT) + +/* SPIM2_SCLK */ +#define SPIM2_SCLK_GPIO0 \ + ESP32_PINMUX(0, ESP_NOSIG, ESP_FSPICLK_OUT) + +#define SPIM2_SCLK_GPIO1 \ + ESP32_PINMUX(1, ESP_NOSIG, ESP_FSPICLK_OUT) + +#define SPIM2_SCLK_GPIO2 \ + ESP32_PINMUX(2, ESP_NOSIG, ESP_FSPICLK_OUT) + +#define SPIM2_SCLK_GPIO3 \ + ESP32_PINMUX(3, ESP_NOSIG, ESP_FSPICLK_OUT) + +#define SPIM2_SCLK_GPIO4 \ + ESP32_PINMUX(4, ESP_NOSIG, ESP_FSPICLK_OUT) + +#define SPIM2_SCLK_GPIO5 \ + ESP32_PINMUX(5, ESP_NOSIG, ESP_FSPICLK_OUT) + +#define SPIM2_SCLK_GPIO6 \ + ESP32_PINMUX(6, ESP_NOSIG, ESP_FSPICLK_OUT) + +#define SPIM2_SCLK_GPIO7 \ + ESP32_PINMUX(7, ESP_NOSIG, ESP_FSPICLK_OUT) + +#define SPIM2_SCLK_GPIO8 \ + ESP32_PINMUX(8, ESP_NOSIG, ESP_FSPICLK_OUT) + +#define SPIM2_SCLK_GPIO9 \ + ESP32_PINMUX(9, ESP_NOSIG, ESP_FSPICLK_OUT) + +#define SPIM2_SCLK_GPIO10 \ + ESP32_PINMUX(10, ESP_NOSIG, ESP_FSPICLK_OUT) + +#define SPIM2_SCLK_GPIO11 \ + ESP32_PINMUX(11, ESP_NOSIG, ESP_FSPICLK_OUT) + +#define SPIM2_SCLK_GPIO12 \ + ESP32_PINMUX(12, ESP_NOSIG, ESP_FSPICLK_OUT) + +#define SPIM2_SCLK_GPIO13 \ + ESP32_PINMUX(13, ESP_NOSIG, ESP_FSPICLK_OUT) + +#define SPIM2_SCLK_GPIO14 \ + ESP32_PINMUX(14, ESP_NOSIG, ESP_FSPICLK_OUT) + +#define SPIM2_SCLK_GPIO15 \ + ESP32_PINMUX(15, ESP_NOSIG, ESP_FSPICLK_OUT) + +#define SPIM2_SCLK_GPIO16 \ + ESP32_PINMUX(16, ESP_NOSIG, ESP_FSPICLK_OUT) + +#define SPIM2_SCLK_GPIO17 \ + ESP32_PINMUX(17, ESP_NOSIG, ESP_FSPICLK_OUT) + +#define SPIM2_SCLK_GPIO18 \ + ESP32_PINMUX(18, ESP_NOSIG, ESP_FSPICLK_OUT) + +#define SPIM2_SCLK_GPIO19 \ + ESP32_PINMUX(19, ESP_NOSIG, ESP_FSPICLK_OUT) + +#define SPIM2_SCLK_GPIO20 \ + ESP32_PINMUX(20, ESP_NOSIG, ESP_FSPICLK_OUT) + +#define SPIM2_SCLK_GPIO21 \ + ESP32_PINMUX(21, ESP_NOSIG, ESP_FSPICLK_OUT) + +#define SPIM2_SCLK_GPIO26 \ + ESP32_PINMUX(26, ESP_NOSIG, ESP_FSPICLK_OUT) + +#define SPIM2_SCLK_GPIO27 \ + ESP32_PINMUX(27, ESP_NOSIG, ESP_FSPICLK_OUT) + +#define SPIM2_SCLK_GPIO28 \ + ESP32_PINMUX(28, ESP_NOSIG, ESP_FSPICLK_OUT) + +#define SPIM2_SCLK_GPIO29 \ + ESP32_PINMUX(29, ESP_NOSIG, ESP_FSPICLK_OUT) + +#define SPIM2_SCLK_GPIO30 \ + ESP32_PINMUX(30, ESP_NOSIG, ESP_FSPICLK_OUT) + +#define SPIM2_SCLK_GPIO31 \ + ESP32_PINMUX(31, ESP_NOSIG, ESP_FSPICLK_OUT) + +#define SPIM2_SCLK_GPIO32 \ + ESP32_PINMUX(32, ESP_NOSIG, ESP_FSPICLK_OUT) + +#define SPIM2_SCLK_GPIO33 \ + ESP32_PINMUX(33, ESP_NOSIG, ESP_FSPICLK_OUT) + +#define SPIM2_SCLK_GPIO34 \ + ESP32_PINMUX(34, ESP_NOSIG, ESP_FSPICLK_OUT) + +#define SPIM2_SCLK_GPIO35 \ + ESP32_PINMUX(35, ESP_NOSIG, ESP_FSPICLK_OUT) + +#define SPIM2_SCLK_GPIO36 \ + ESP32_PINMUX(36, ESP_NOSIG, ESP_FSPICLK_OUT) + +#define SPIM2_SCLK_GPIO37 \ + ESP32_PINMUX(37, ESP_NOSIG, ESP_FSPICLK_OUT) + +#define SPIM2_SCLK_GPIO38 \ + ESP32_PINMUX(38, ESP_NOSIG, ESP_FSPICLK_OUT) + +#define SPIM2_SCLK_GPIO39 \ + ESP32_PINMUX(39, ESP_NOSIG, ESP_FSPICLK_OUT) + +#define SPIM2_SCLK_GPIO40 \ + ESP32_PINMUX(40, ESP_NOSIG, ESP_FSPICLK_OUT) + +#define SPIM2_SCLK_GPIO41 \ + ESP32_PINMUX(41, ESP_NOSIG, ESP_FSPICLK_OUT) + +#define SPIM2_SCLK_GPIO42 \ + ESP32_PINMUX(42, ESP_NOSIG, ESP_FSPICLK_OUT) + +#define SPIM2_SCLK_GPIO43 \ + ESP32_PINMUX(43, ESP_NOSIG, ESP_FSPICLK_OUT) + +#define SPIM2_SCLK_GPIO44 \ + ESP32_PINMUX(44, ESP_NOSIG, ESP_FSPICLK_OUT) + +#define SPIM2_SCLK_GPIO45 \ + ESP32_PINMUX(45, ESP_NOSIG, ESP_FSPICLK_OUT) + +#define SPIM2_SCLK_GPIO46 \ + ESP32_PINMUX(46, ESP_NOSIG, ESP_FSPICLK_OUT) + +#define SPIM2_SCLK_GPIO47 \ + ESP32_PINMUX(47, ESP_NOSIG, ESP_FSPICLK_OUT) + +#define SPIM2_SCLK_GPIO48 \ + ESP32_PINMUX(48, ESP_NOSIG, ESP_FSPICLK_OUT) + +/* SPIM3_CSEL */ +#define SPIM3_CSEL_GPIO0 \ + ESP32_PINMUX(0, ESP_NOSIG, ESP_SPI3_CS0_OUT) + +#define SPIM3_CSEL_GPIO1 \ + ESP32_PINMUX(1, ESP_NOSIG, ESP_SPI3_CS0_OUT) + +#define SPIM3_CSEL_GPIO2 \ + ESP32_PINMUX(2, ESP_NOSIG, ESP_SPI3_CS0_OUT) + +#define SPIM3_CSEL_GPIO3 \ + ESP32_PINMUX(3, ESP_NOSIG, ESP_SPI3_CS0_OUT) + +#define SPIM3_CSEL_GPIO4 \ + ESP32_PINMUX(4, ESP_NOSIG, ESP_SPI3_CS0_OUT) + +#define SPIM3_CSEL_GPIO5 \ + ESP32_PINMUX(5, ESP_NOSIG, ESP_SPI3_CS0_OUT) + +#define SPIM3_CSEL_GPIO6 \ + ESP32_PINMUX(6, ESP_NOSIG, ESP_SPI3_CS0_OUT) + +#define SPIM3_CSEL_GPIO7 \ + ESP32_PINMUX(7, ESP_NOSIG, ESP_SPI3_CS0_OUT) + +#define SPIM3_CSEL_GPIO8 \ + ESP32_PINMUX(8, ESP_NOSIG, ESP_SPI3_CS0_OUT) + +#define SPIM3_CSEL_GPIO9 \ + ESP32_PINMUX(9, ESP_NOSIG, ESP_SPI3_CS0_OUT) + +#define SPIM3_CSEL_GPIO10 \ + ESP32_PINMUX(10, ESP_NOSIG, ESP_SPI3_CS0_OUT) + +#define SPIM3_CSEL_GPIO11 \ + ESP32_PINMUX(11, ESP_NOSIG, ESP_SPI3_CS0_OUT) + +#define SPIM3_CSEL_GPIO12 \ + ESP32_PINMUX(12, ESP_NOSIG, ESP_SPI3_CS0_OUT) + +#define SPIM3_CSEL_GPIO13 \ + ESP32_PINMUX(13, ESP_NOSIG, ESP_SPI3_CS0_OUT) + +#define SPIM3_CSEL_GPIO14 \ + ESP32_PINMUX(14, ESP_NOSIG, ESP_SPI3_CS0_OUT) + +#define SPIM3_CSEL_GPIO15 \ + ESP32_PINMUX(15, ESP_NOSIG, ESP_SPI3_CS0_OUT) + +#define SPIM3_CSEL_GPIO16 \ + ESP32_PINMUX(16, ESP_NOSIG, ESP_SPI3_CS0_OUT) + +#define SPIM3_CSEL_GPIO17 \ + ESP32_PINMUX(17, ESP_NOSIG, ESP_SPI3_CS0_OUT) + +#define SPIM3_CSEL_GPIO18 \ + ESP32_PINMUX(18, ESP_NOSIG, ESP_SPI3_CS0_OUT) + +#define SPIM3_CSEL_GPIO19 \ + ESP32_PINMUX(19, ESP_NOSIG, ESP_SPI3_CS0_OUT) + +#define SPIM3_CSEL_GPIO20 \ + ESP32_PINMUX(20, ESP_NOSIG, ESP_SPI3_CS0_OUT) + +#define SPIM3_CSEL_GPIO21 \ + ESP32_PINMUX(21, ESP_NOSIG, ESP_SPI3_CS0_OUT) + +#define SPIM3_CSEL_GPIO26 \ + ESP32_PINMUX(26, ESP_NOSIG, ESP_SPI3_CS0_OUT) + +#define SPIM3_CSEL_GPIO27 \ + ESP32_PINMUX(27, ESP_NOSIG, ESP_SPI3_CS0_OUT) + +#define SPIM3_CSEL_GPIO28 \ + ESP32_PINMUX(28, ESP_NOSIG, ESP_SPI3_CS0_OUT) + +#define SPIM3_CSEL_GPIO29 \ + ESP32_PINMUX(29, ESP_NOSIG, ESP_SPI3_CS0_OUT) + +#define SPIM3_CSEL_GPIO30 \ + ESP32_PINMUX(30, ESP_NOSIG, ESP_SPI3_CS0_OUT) + +#define SPIM3_CSEL_GPIO31 \ + ESP32_PINMUX(31, ESP_NOSIG, ESP_SPI3_CS0_OUT) + +#define SPIM3_CSEL_GPIO32 \ + ESP32_PINMUX(32, ESP_NOSIG, ESP_SPI3_CS0_OUT) + +#define SPIM3_CSEL_GPIO33 \ + ESP32_PINMUX(33, ESP_NOSIG, ESP_SPI3_CS0_OUT) + +#define SPIM3_CSEL_GPIO34 \ + ESP32_PINMUX(34, ESP_NOSIG, ESP_SPI3_CS0_OUT) + +#define SPIM3_CSEL_GPIO35 \ + ESP32_PINMUX(35, ESP_NOSIG, ESP_SPI3_CS0_OUT) + +#define SPIM3_CSEL_GPIO36 \ + ESP32_PINMUX(36, ESP_NOSIG, ESP_SPI3_CS0_OUT) + +#define SPIM3_CSEL_GPIO37 \ + ESP32_PINMUX(37, ESP_NOSIG, ESP_SPI3_CS0_OUT) + +#define SPIM3_CSEL_GPIO38 \ + ESP32_PINMUX(38, ESP_NOSIG, ESP_SPI3_CS0_OUT) + +#define SPIM3_CSEL_GPIO39 \ + ESP32_PINMUX(39, ESP_NOSIG, ESP_SPI3_CS0_OUT) + +#define SPIM3_CSEL_GPIO40 \ + ESP32_PINMUX(40, ESP_NOSIG, ESP_SPI3_CS0_OUT) + +#define SPIM3_CSEL_GPIO41 \ + ESP32_PINMUX(41, ESP_NOSIG, ESP_SPI3_CS0_OUT) + +#define SPIM3_CSEL_GPIO42 \ + ESP32_PINMUX(42, ESP_NOSIG, ESP_SPI3_CS0_OUT) + +#define SPIM3_CSEL_GPIO43 \ + ESP32_PINMUX(43, ESP_NOSIG, ESP_SPI3_CS0_OUT) + +#define SPIM3_CSEL_GPIO44 \ + ESP32_PINMUX(44, ESP_NOSIG, ESP_SPI3_CS0_OUT) + +#define SPIM3_CSEL_GPIO45 \ + ESP32_PINMUX(45, ESP_NOSIG, ESP_SPI3_CS0_OUT) + +#define SPIM3_CSEL_GPIO46 \ + ESP32_PINMUX(46, ESP_NOSIG, ESP_SPI3_CS0_OUT) + +#define SPIM3_CSEL_GPIO47 \ + ESP32_PINMUX(47, ESP_NOSIG, ESP_SPI3_CS0_OUT) + +#define SPIM3_CSEL_GPIO48 \ + ESP32_PINMUX(48, ESP_NOSIG, ESP_SPI3_CS0_OUT) + +/* SPIM3_CSEL1 */ +#define SPIM3_CSEL1_GPIO0 \ + ESP32_PINMUX(0, ESP_NOSIG, ESP_SPI3_CS1_OUT) + +#define SPIM3_CSEL1_GPIO1 \ + ESP32_PINMUX(1, ESP_NOSIG, ESP_SPI3_CS1_OUT) + +#define SPIM3_CSEL1_GPIO2 \ + ESP32_PINMUX(2, ESP_NOSIG, ESP_SPI3_CS1_OUT) + +#define SPIM3_CSEL1_GPIO3 \ + ESP32_PINMUX(3, ESP_NOSIG, ESP_SPI3_CS1_OUT) + +#define SPIM3_CSEL1_GPIO4 \ + ESP32_PINMUX(4, ESP_NOSIG, ESP_SPI3_CS1_OUT) + +#define SPIM3_CSEL1_GPIO5 \ + ESP32_PINMUX(5, ESP_NOSIG, ESP_SPI3_CS1_OUT) + +#define SPIM3_CSEL1_GPIO6 \ + ESP32_PINMUX(6, ESP_NOSIG, ESP_SPI3_CS1_OUT) + +#define SPIM3_CSEL1_GPIO7 \ + ESP32_PINMUX(7, ESP_NOSIG, ESP_SPI3_CS1_OUT) + +#define SPIM3_CSEL1_GPIO8 \ + ESP32_PINMUX(8, ESP_NOSIG, ESP_SPI3_CS1_OUT) + +#define SPIM3_CSEL1_GPIO9 \ + ESP32_PINMUX(9, ESP_NOSIG, ESP_SPI3_CS1_OUT) + +#define SPIM3_CSEL1_GPIO10 \ + ESP32_PINMUX(10, ESP_NOSIG, ESP_SPI3_CS1_OUT) + +#define SPIM3_CSEL1_GPIO11 \ + ESP32_PINMUX(11, ESP_NOSIG, ESP_SPI3_CS1_OUT) + +#define SPIM3_CSEL1_GPIO12 \ + ESP32_PINMUX(12, ESP_NOSIG, ESP_SPI3_CS1_OUT) + +#define SPIM3_CSEL1_GPIO13 \ + ESP32_PINMUX(13, ESP_NOSIG, ESP_SPI3_CS1_OUT) + +#define SPIM3_CSEL1_GPIO14 \ + ESP32_PINMUX(14, ESP_NOSIG, ESP_SPI3_CS1_OUT) + +#define SPIM3_CSEL1_GPIO15 \ + ESP32_PINMUX(15, ESP_NOSIG, ESP_SPI3_CS1_OUT) + +#define SPIM3_CSEL1_GPIO16 \ + ESP32_PINMUX(16, ESP_NOSIG, ESP_SPI3_CS1_OUT) + +#define SPIM3_CSEL1_GPIO17 \ + ESP32_PINMUX(17, ESP_NOSIG, ESP_SPI3_CS1_OUT) + +#define SPIM3_CSEL1_GPIO18 \ + ESP32_PINMUX(18, ESP_NOSIG, ESP_SPI3_CS1_OUT) + +#define SPIM3_CSEL1_GPIO19 \ + ESP32_PINMUX(19, ESP_NOSIG, ESP_SPI3_CS1_OUT) + +#define SPIM3_CSEL1_GPIO20 \ + ESP32_PINMUX(20, ESP_NOSIG, ESP_SPI3_CS1_OUT) + +#define SPIM3_CSEL1_GPIO21 \ + ESP32_PINMUX(21, ESP_NOSIG, ESP_SPI3_CS1_OUT) + +#define SPIM3_CSEL1_GPIO26 \ + ESP32_PINMUX(26, ESP_NOSIG, ESP_SPI3_CS1_OUT) + +#define SPIM3_CSEL1_GPIO27 \ + ESP32_PINMUX(27, ESP_NOSIG, ESP_SPI3_CS1_OUT) + +#define SPIM3_CSEL1_GPIO28 \ + ESP32_PINMUX(28, ESP_NOSIG, ESP_SPI3_CS1_OUT) + +#define SPIM3_CSEL1_GPIO29 \ + ESP32_PINMUX(29, ESP_NOSIG, ESP_SPI3_CS1_OUT) + +#define SPIM3_CSEL1_GPIO30 \ + ESP32_PINMUX(30, ESP_NOSIG, ESP_SPI3_CS1_OUT) + +#define SPIM3_CSEL1_GPIO31 \ + ESP32_PINMUX(31, ESP_NOSIG, ESP_SPI3_CS1_OUT) + +#define SPIM3_CSEL1_GPIO32 \ + ESP32_PINMUX(32, ESP_NOSIG, ESP_SPI3_CS1_OUT) + +#define SPIM3_CSEL1_GPIO33 \ + ESP32_PINMUX(33, ESP_NOSIG, ESP_SPI3_CS1_OUT) + +#define SPIM3_CSEL1_GPIO34 \ + ESP32_PINMUX(34, ESP_NOSIG, ESP_SPI3_CS1_OUT) + +#define SPIM3_CSEL1_GPIO35 \ + ESP32_PINMUX(35, ESP_NOSIG, ESP_SPI3_CS1_OUT) + +#define SPIM3_CSEL1_GPIO36 \ + ESP32_PINMUX(36, ESP_NOSIG, ESP_SPI3_CS1_OUT) + +#define SPIM3_CSEL1_GPIO37 \ + ESP32_PINMUX(37, ESP_NOSIG, ESP_SPI3_CS1_OUT) + +#define SPIM3_CSEL1_GPIO38 \ + ESP32_PINMUX(38, ESP_NOSIG, ESP_SPI3_CS1_OUT) + +#define SPIM3_CSEL1_GPIO39 \ + ESP32_PINMUX(39, ESP_NOSIG, ESP_SPI3_CS1_OUT) + +#define SPIM3_CSEL1_GPIO40 \ + ESP32_PINMUX(40, ESP_NOSIG, ESP_SPI3_CS1_OUT) + +#define SPIM3_CSEL1_GPIO41 \ + ESP32_PINMUX(41, ESP_NOSIG, ESP_SPI3_CS1_OUT) + +#define SPIM3_CSEL1_GPIO42 \ + ESP32_PINMUX(42, ESP_NOSIG, ESP_SPI3_CS1_OUT) + +#define SPIM3_CSEL1_GPIO43 \ + ESP32_PINMUX(43, ESP_NOSIG, ESP_SPI3_CS1_OUT) + +#define SPIM3_CSEL1_GPIO44 \ + ESP32_PINMUX(44, ESP_NOSIG, ESP_SPI3_CS1_OUT) + +#define SPIM3_CSEL1_GPIO45 \ + ESP32_PINMUX(45, ESP_NOSIG, ESP_SPI3_CS1_OUT) + +#define SPIM3_CSEL1_GPIO46 \ + ESP32_PINMUX(46, ESP_NOSIG, ESP_SPI3_CS1_OUT) + +#define SPIM3_CSEL1_GPIO47 \ + ESP32_PINMUX(47, ESP_NOSIG, ESP_SPI3_CS1_OUT) + +#define SPIM3_CSEL1_GPIO48 \ + ESP32_PINMUX(48, ESP_NOSIG, ESP_SPI3_CS1_OUT) + +/* SPIM3_CSEL2 */ +#define SPIM3_CSEL2_GPIO0 \ + ESP32_PINMUX(0, ESP_NOSIG, ESP_SPI3_CS2_OUT) + +#define SPIM3_CSEL2_GPIO1 \ + ESP32_PINMUX(1, ESP_NOSIG, ESP_SPI3_CS2_OUT) + +#define SPIM3_CSEL2_GPIO2 \ + ESP32_PINMUX(2, ESP_NOSIG, ESP_SPI3_CS2_OUT) + +#define SPIM3_CSEL2_GPIO3 \ + ESP32_PINMUX(3, ESP_NOSIG, ESP_SPI3_CS2_OUT) + +#define SPIM3_CSEL2_GPIO4 \ + ESP32_PINMUX(4, ESP_NOSIG, ESP_SPI3_CS2_OUT) + +#define SPIM3_CSEL2_GPIO5 \ + ESP32_PINMUX(5, ESP_NOSIG, ESP_SPI3_CS2_OUT) + +#define SPIM3_CSEL2_GPIO6 \ + ESP32_PINMUX(6, ESP_NOSIG, ESP_SPI3_CS2_OUT) + +#define SPIM3_CSEL2_GPIO7 \ + ESP32_PINMUX(7, ESP_NOSIG, ESP_SPI3_CS2_OUT) + +#define SPIM3_CSEL2_GPIO8 \ + ESP32_PINMUX(8, ESP_NOSIG, ESP_SPI3_CS2_OUT) + +#define SPIM3_CSEL2_GPIO9 \ + ESP32_PINMUX(9, ESP_NOSIG, ESP_SPI3_CS2_OUT) + +#define SPIM3_CSEL2_GPIO10 \ + ESP32_PINMUX(10, ESP_NOSIG, ESP_SPI3_CS2_OUT) + +#define SPIM3_CSEL2_GPIO11 \ + ESP32_PINMUX(11, ESP_NOSIG, ESP_SPI3_CS2_OUT) + +#define SPIM3_CSEL2_GPIO12 \ + ESP32_PINMUX(12, ESP_NOSIG, ESP_SPI3_CS2_OUT) + +#define SPIM3_CSEL2_GPIO13 \ + ESP32_PINMUX(13, ESP_NOSIG, ESP_SPI3_CS2_OUT) + +#define SPIM3_CSEL2_GPIO14 \ + ESP32_PINMUX(14, ESP_NOSIG, ESP_SPI3_CS2_OUT) + +#define SPIM3_CSEL2_GPIO15 \ + ESP32_PINMUX(15, ESP_NOSIG, ESP_SPI3_CS2_OUT) + +#define SPIM3_CSEL2_GPIO16 \ + ESP32_PINMUX(16, ESP_NOSIG, ESP_SPI3_CS2_OUT) + +#define SPIM3_CSEL2_GPIO17 \ + ESP32_PINMUX(17, ESP_NOSIG, ESP_SPI3_CS2_OUT) + +#define SPIM3_CSEL2_GPIO18 \ + ESP32_PINMUX(18, ESP_NOSIG, ESP_SPI3_CS2_OUT) + +#define SPIM3_CSEL2_GPIO19 \ + ESP32_PINMUX(19, ESP_NOSIG, ESP_SPI3_CS2_OUT) + +#define SPIM3_CSEL2_GPIO20 \ + ESP32_PINMUX(20, ESP_NOSIG, ESP_SPI3_CS2_OUT) + +#define SPIM3_CSEL2_GPIO21 \ + ESP32_PINMUX(21, ESP_NOSIG, ESP_SPI3_CS2_OUT) + +#define SPIM3_CSEL2_GPIO26 \ + ESP32_PINMUX(26, ESP_NOSIG, ESP_SPI3_CS2_OUT) + +#define SPIM3_CSEL2_GPIO27 \ + ESP32_PINMUX(27, ESP_NOSIG, ESP_SPI3_CS2_OUT) + +#define SPIM3_CSEL2_GPIO28 \ + ESP32_PINMUX(28, ESP_NOSIG, ESP_SPI3_CS2_OUT) + +#define SPIM3_CSEL2_GPIO29 \ + ESP32_PINMUX(29, ESP_NOSIG, ESP_SPI3_CS2_OUT) + +#define SPIM3_CSEL2_GPIO30 \ + ESP32_PINMUX(30, ESP_NOSIG, ESP_SPI3_CS2_OUT) + +#define SPIM3_CSEL2_GPIO31 \ + ESP32_PINMUX(31, ESP_NOSIG, ESP_SPI3_CS2_OUT) + +#define SPIM3_CSEL2_GPIO32 \ + ESP32_PINMUX(32, ESP_NOSIG, ESP_SPI3_CS2_OUT) + +#define SPIM3_CSEL2_GPIO33 \ + ESP32_PINMUX(33, ESP_NOSIG, ESP_SPI3_CS2_OUT) + +#define SPIM3_CSEL2_GPIO34 \ + ESP32_PINMUX(34, ESP_NOSIG, ESP_SPI3_CS2_OUT) + +#define SPIM3_CSEL2_GPIO35 \ + ESP32_PINMUX(35, ESP_NOSIG, ESP_SPI3_CS2_OUT) + +#define SPIM3_CSEL2_GPIO36 \ + ESP32_PINMUX(36, ESP_NOSIG, ESP_SPI3_CS2_OUT) + +#define SPIM3_CSEL2_GPIO37 \ + ESP32_PINMUX(37, ESP_NOSIG, ESP_SPI3_CS2_OUT) + +#define SPIM3_CSEL2_GPIO38 \ + ESP32_PINMUX(38, ESP_NOSIG, ESP_SPI3_CS2_OUT) + +#define SPIM3_CSEL2_GPIO39 \ + ESP32_PINMUX(39, ESP_NOSIG, ESP_SPI3_CS2_OUT) + +#define SPIM3_CSEL2_GPIO40 \ + ESP32_PINMUX(40, ESP_NOSIG, ESP_SPI3_CS2_OUT) + +#define SPIM3_CSEL2_GPIO41 \ + ESP32_PINMUX(41, ESP_NOSIG, ESP_SPI3_CS2_OUT) + +#define SPIM3_CSEL2_GPIO42 \ + ESP32_PINMUX(42, ESP_NOSIG, ESP_SPI3_CS2_OUT) + +#define SPIM3_CSEL2_GPIO43 \ + ESP32_PINMUX(43, ESP_NOSIG, ESP_SPI3_CS2_OUT) + +#define SPIM3_CSEL2_GPIO44 \ + ESP32_PINMUX(44, ESP_NOSIG, ESP_SPI3_CS2_OUT) + +#define SPIM3_CSEL2_GPIO45 \ + ESP32_PINMUX(45, ESP_NOSIG, ESP_SPI3_CS2_OUT) + +#define SPIM3_CSEL2_GPIO46 \ + ESP32_PINMUX(46, ESP_NOSIG, ESP_SPI3_CS2_OUT) + +#define SPIM3_CSEL2_GPIO47 \ + ESP32_PINMUX(47, ESP_NOSIG, ESP_SPI3_CS2_OUT) + +#define SPIM3_CSEL2_GPIO48 \ + ESP32_PINMUX(48, ESP_NOSIG, ESP_SPI3_CS2_OUT) + +/* SPIM3_MISO */ +#define SPIM3_MISO_GPIO0 \ + ESP32_PINMUX(0, ESP_SPI3_Q_IN, ESP_NOSIG) + +#define SPIM3_MISO_GPIO1 \ + ESP32_PINMUX(1, ESP_SPI3_Q_IN, ESP_NOSIG) + +#define SPIM3_MISO_GPIO2 \ + ESP32_PINMUX(2, ESP_SPI3_Q_IN, ESP_NOSIG) + +#define SPIM3_MISO_GPIO3 \ + ESP32_PINMUX(3, ESP_SPI3_Q_IN, ESP_NOSIG) + +#define SPIM3_MISO_GPIO4 \ + ESP32_PINMUX(4, ESP_SPI3_Q_IN, ESP_NOSIG) + +#define SPIM3_MISO_GPIO5 \ + ESP32_PINMUX(5, ESP_SPI3_Q_IN, ESP_NOSIG) + +#define SPIM3_MISO_GPIO6 \ + ESP32_PINMUX(6, ESP_SPI3_Q_IN, ESP_NOSIG) + +#define SPIM3_MISO_GPIO7 \ + ESP32_PINMUX(7, ESP_SPI3_Q_IN, ESP_NOSIG) + +#define SPIM3_MISO_GPIO8 \ + ESP32_PINMUX(8, ESP_SPI3_Q_IN, ESP_NOSIG) + +#define SPIM3_MISO_GPIO9 \ + ESP32_PINMUX(9, ESP_SPI3_Q_IN, ESP_NOSIG) + +#define SPIM3_MISO_GPIO10 \ + ESP32_PINMUX(10, ESP_SPI3_Q_IN, ESP_NOSIG) + +#define SPIM3_MISO_GPIO11 \ + ESP32_PINMUX(11, ESP_SPI3_Q_IN, ESP_NOSIG) + +#define SPIM3_MISO_GPIO12 \ + ESP32_PINMUX(12, ESP_SPI3_Q_IN, ESP_NOSIG) + +#define SPIM3_MISO_GPIO13 \ + ESP32_PINMUX(13, ESP_SPI3_Q_IN, ESP_NOSIG) + +#define SPIM3_MISO_GPIO14 \ + ESP32_PINMUX(14, ESP_SPI3_Q_IN, ESP_NOSIG) + +#define SPIM3_MISO_GPIO15 \ + ESP32_PINMUX(15, ESP_SPI3_Q_IN, ESP_NOSIG) + +#define SPIM3_MISO_GPIO16 \ + ESP32_PINMUX(16, ESP_SPI3_Q_IN, ESP_NOSIG) + +#define SPIM3_MISO_GPIO17 \ + ESP32_PINMUX(17, ESP_SPI3_Q_IN, ESP_NOSIG) + +#define SPIM3_MISO_GPIO18 \ + ESP32_PINMUX(18, ESP_SPI3_Q_IN, ESP_NOSIG) + +#define SPIM3_MISO_GPIO19 \ + ESP32_PINMUX(19, ESP_SPI3_Q_IN, ESP_NOSIG) + +#define SPIM3_MISO_GPIO20 \ + ESP32_PINMUX(20, ESP_SPI3_Q_IN, ESP_NOSIG) + +#define SPIM3_MISO_GPIO21 \ + ESP32_PINMUX(21, ESP_SPI3_Q_IN, ESP_NOSIG) + +#define SPIM3_MISO_GPIO26 \ + ESP32_PINMUX(26, ESP_SPI3_Q_IN, ESP_NOSIG) + +#define SPIM3_MISO_GPIO27 \ + ESP32_PINMUX(27, ESP_SPI3_Q_IN, ESP_NOSIG) + +#define SPIM3_MISO_GPIO28 \ + ESP32_PINMUX(28, ESP_SPI3_Q_IN, ESP_NOSIG) + +#define SPIM3_MISO_GPIO29 \ + ESP32_PINMUX(29, ESP_SPI3_Q_IN, ESP_NOSIG) + +#define SPIM3_MISO_GPIO30 \ + ESP32_PINMUX(30, ESP_SPI3_Q_IN, ESP_NOSIG) + +#define SPIM3_MISO_GPIO31 \ + ESP32_PINMUX(31, ESP_SPI3_Q_IN, ESP_NOSIG) + +#define SPIM3_MISO_GPIO32 \ + ESP32_PINMUX(32, ESP_SPI3_Q_IN, ESP_NOSIG) + +#define SPIM3_MISO_GPIO33 \ + ESP32_PINMUX(33, ESP_SPI3_Q_IN, ESP_NOSIG) + +#define SPIM3_MISO_GPIO34 \ + ESP32_PINMUX(34, ESP_SPI3_Q_IN, ESP_NOSIG) + +#define SPIM3_MISO_GPIO35 \ + ESP32_PINMUX(35, ESP_SPI3_Q_IN, ESP_NOSIG) + +#define SPIM3_MISO_GPIO36 \ + ESP32_PINMUX(36, ESP_SPI3_Q_IN, ESP_NOSIG) + +#define SPIM3_MISO_GPIO37 \ + ESP32_PINMUX(37, ESP_SPI3_Q_IN, ESP_NOSIG) + +#define SPIM3_MISO_GPIO38 \ + ESP32_PINMUX(38, ESP_SPI3_Q_IN, ESP_NOSIG) + +#define SPIM3_MISO_GPIO39 \ + ESP32_PINMUX(39, ESP_SPI3_Q_IN, ESP_NOSIG) + +#define SPIM3_MISO_GPIO40 \ + ESP32_PINMUX(40, ESP_SPI3_Q_IN, ESP_NOSIG) + +#define SPIM3_MISO_GPIO41 \ + ESP32_PINMUX(41, ESP_SPI3_Q_IN, ESP_NOSIG) + +#define SPIM3_MISO_GPIO42 \ + ESP32_PINMUX(42, ESP_SPI3_Q_IN, ESP_NOSIG) + +#define SPIM3_MISO_GPIO43 \ + ESP32_PINMUX(43, ESP_SPI3_Q_IN, ESP_NOSIG) + +#define SPIM3_MISO_GPIO44 \ + ESP32_PINMUX(44, ESP_SPI3_Q_IN, ESP_NOSIG) + +#define SPIM3_MISO_GPIO45 \ + ESP32_PINMUX(45, ESP_SPI3_Q_IN, ESP_NOSIG) + +#define SPIM3_MISO_GPIO46 \ + ESP32_PINMUX(46, ESP_SPI3_Q_IN, ESP_NOSIG) + +#define SPIM3_MISO_GPIO47 \ + ESP32_PINMUX(47, ESP_SPI3_Q_IN, ESP_NOSIG) + +#define SPIM3_MISO_GPIO48 \ + ESP32_PINMUX(48, ESP_SPI3_Q_IN, ESP_NOSIG) + +/* SPIM3_MOSI */ +#define SPIM3_MOSI_GPIO0 \ + ESP32_PINMUX(0, ESP_NOSIG, ESP_SPI3_D_OUT) + +#define SPIM3_MOSI_GPIO1 \ + ESP32_PINMUX(1, ESP_NOSIG, ESP_SPI3_D_OUT) + +#define SPIM3_MOSI_GPIO2 \ + ESP32_PINMUX(2, ESP_NOSIG, ESP_SPI3_D_OUT) + +#define SPIM3_MOSI_GPIO3 \ + ESP32_PINMUX(3, ESP_NOSIG, ESP_SPI3_D_OUT) + +#define SPIM3_MOSI_GPIO4 \ + ESP32_PINMUX(4, ESP_NOSIG, ESP_SPI3_D_OUT) + +#define SPIM3_MOSI_GPIO5 \ + ESP32_PINMUX(5, ESP_NOSIG, ESP_SPI3_D_OUT) + +#define SPIM3_MOSI_GPIO6 \ + ESP32_PINMUX(6, ESP_NOSIG, ESP_SPI3_D_OUT) + +#define SPIM3_MOSI_GPIO7 \ + ESP32_PINMUX(7, ESP_NOSIG, ESP_SPI3_D_OUT) + +#define SPIM3_MOSI_GPIO8 \ + ESP32_PINMUX(8, ESP_NOSIG, ESP_SPI3_D_OUT) + +#define SPIM3_MOSI_GPIO9 \ + ESP32_PINMUX(9, ESP_NOSIG, ESP_SPI3_D_OUT) + +#define SPIM3_MOSI_GPIO10 \ + ESP32_PINMUX(10, ESP_NOSIG, ESP_SPI3_D_OUT) + +#define SPIM3_MOSI_GPIO11 \ + ESP32_PINMUX(11, ESP_NOSIG, ESP_SPI3_D_OUT) + +#define SPIM3_MOSI_GPIO12 \ + ESP32_PINMUX(12, ESP_NOSIG, ESP_SPI3_D_OUT) + +#define SPIM3_MOSI_GPIO13 \ + ESP32_PINMUX(13, ESP_NOSIG, ESP_SPI3_D_OUT) + +#define SPIM3_MOSI_GPIO14 \ + ESP32_PINMUX(14, ESP_NOSIG, ESP_SPI3_D_OUT) + +#define SPIM3_MOSI_GPIO15 \ + ESP32_PINMUX(15, ESP_NOSIG, ESP_SPI3_D_OUT) + +#define SPIM3_MOSI_GPIO16 \ + ESP32_PINMUX(16, ESP_NOSIG, ESP_SPI3_D_OUT) + +#define SPIM3_MOSI_GPIO17 \ + ESP32_PINMUX(17, ESP_NOSIG, ESP_SPI3_D_OUT) + +#define SPIM3_MOSI_GPIO18 \ + ESP32_PINMUX(18, ESP_NOSIG, ESP_SPI3_D_OUT) + +#define SPIM3_MOSI_GPIO19 \ + ESP32_PINMUX(19, ESP_NOSIG, ESP_SPI3_D_OUT) + +#define SPIM3_MOSI_GPIO20 \ + ESP32_PINMUX(20, ESP_NOSIG, ESP_SPI3_D_OUT) + +#define SPIM3_MOSI_GPIO21 \ + ESP32_PINMUX(21, ESP_NOSIG, ESP_SPI3_D_OUT) + +#define SPIM3_MOSI_GPIO26 \ + ESP32_PINMUX(26, ESP_NOSIG, ESP_SPI3_D_OUT) + +#define SPIM3_MOSI_GPIO27 \ + ESP32_PINMUX(27, ESP_NOSIG, ESP_SPI3_D_OUT) + +#define SPIM3_MOSI_GPIO28 \ + ESP32_PINMUX(28, ESP_NOSIG, ESP_SPI3_D_OUT) + +#define SPIM3_MOSI_GPIO29 \ + ESP32_PINMUX(29, ESP_NOSIG, ESP_SPI3_D_OUT) + +#define SPIM3_MOSI_GPIO30 \ + ESP32_PINMUX(30, ESP_NOSIG, ESP_SPI3_D_OUT) + +#define SPIM3_MOSI_GPIO31 \ + ESP32_PINMUX(31, ESP_NOSIG, ESP_SPI3_D_OUT) + +#define SPIM3_MOSI_GPIO32 \ + ESP32_PINMUX(32, ESP_NOSIG, ESP_SPI3_D_OUT) + +#define SPIM3_MOSI_GPIO33 \ + ESP32_PINMUX(33, ESP_NOSIG, ESP_SPI3_D_OUT) + +#define SPIM3_MOSI_GPIO34 \ + ESP32_PINMUX(34, ESP_NOSIG, ESP_SPI3_D_OUT) + +#define SPIM3_MOSI_GPIO35 \ + ESP32_PINMUX(35, ESP_NOSIG, ESP_SPI3_D_OUT) + +#define SPIM3_MOSI_GPIO36 \ + ESP32_PINMUX(36, ESP_NOSIG, ESP_SPI3_D_OUT) + +#define SPIM3_MOSI_GPIO37 \ + ESP32_PINMUX(37, ESP_NOSIG, ESP_SPI3_D_OUT) + +#define SPIM3_MOSI_GPIO38 \ + ESP32_PINMUX(38, ESP_NOSIG, ESP_SPI3_D_OUT) + +#define SPIM3_MOSI_GPIO39 \ + ESP32_PINMUX(39, ESP_NOSIG, ESP_SPI3_D_OUT) + +#define SPIM3_MOSI_GPIO40 \ + ESP32_PINMUX(40, ESP_NOSIG, ESP_SPI3_D_OUT) + +#define SPIM3_MOSI_GPIO41 \ + ESP32_PINMUX(41, ESP_NOSIG, ESP_SPI3_D_OUT) + +#define SPIM3_MOSI_GPIO42 \ + ESP32_PINMUX(42, ESP_NOSIG, ESP_SPI3_D_OUT) + +#define SPIM3_MOSI_GPIO43 \ + ESP32_PINMUX(43, ESP_NOSIG, ESP_SPI3_D_OUT) + +#define SPIM3_MOSI_GPIO44 \ + ESP32_PINMUX(44, ESP_NOSIG, ESP_SPI3_D_OUT) + +#define SPIM3_MOSI_GPIO45 \ + ESP32_PINMUX(45, ESP_NOSIG, ESP_SPI3_D_OUT) + +#define SPIM3_MOSI_GPIO46 \ + ESP32_PINMUX(46, ESP_NOSIG, ESP_SPI3_D_OUT) + +#define SPIM3_MOSI_GPIO47 \ + ESP32_PINMUX(47, ESP_NOSIG, ESP_SPI3_D_OUT) + +#define SPIM3_MOSI_GPIO48 \ + ESP32_PINMUX(48, ESP_NOSIG, ESP_SPI3_D_OUT) + +/* SPIM3_SCLK */ +#define SPIM3_SCLK_GPIO0 \ + ESP32_PINMUX(0, ESP_NOSIG, ESP_SPI3_CLK_OUT) + +#define SPIM3_SCLK_GPIO1 \ + ESP32_PINMUX(1, ESP_NOSIG, ESP_SPI3_CLK_OUT) + +#define SPIM3_SCLK_GPIO2 \ + ESP32_PINMUX(2, ESP_NOSIG, ESP_SPI3_CLK_OUT) + +#define SPIM3_SCLK_GPIO3 \ + ESP32_PINMUX(3, ESP_NOSIG, ESP_SPI3_CLK_OUT) + +#define SPIM3_SCLK_GPIO4 \ + ESP32_PINMUX(4, ESP_NOSIG, ESP_SPI3_CLK_OUT) + +#define SPIM3_SCLK_GPIO5 \ + ESP32_PINMUX(5, ESP_NOSIG, ESP_SPI3_CLK_OUT) + +#define SPIM3_SCLK_GPIO6 \ + ESP32_PINMUX(6, ESP_NOSIG, ESP_SPI3_CLK_OUT) + +#define SPIM3_SCLK_GPIO7 \ + ESP32_PINMUX(7, ESP_NOSIG, ESP_SPI3_CLK_OUT) + +#define SPIM3_SCLK_GPIO8 \ + ESP32_PINMUX(8, ESP_NOSIG, ESP_SPI3_CLK_OUT) + +#define SPIM3_SCLK_GPIO9 \ + ESP32_PINMUX(9, ESP_NOSIG, ESP_SPI3_CLK_OUT) + +#define SPIM3_SCLK_GPIO10 \ + ESP32_PINMUX(10, ESP_NOSIG, ESP_SPI3_CLK_OUT) + +#define SPIM3_SCLK_GPIO11 \ + ESP32_PINMUX(11, ESP_NOSIG, ESP_SPI3_CLK_OUT) + +#define SPIM3_SCLK_GPIO12 \ + ESP32_PINMUX(12, ESP_NOSIG, ESP_SPI3_CLK_OUT) + +#define SPIM3_SCLK_GPIO13 \ + ESP32_PINMUX(13, ESP_NOSIG, ESP_SPI3_CLK_OUT) + +#define SPIM3_SCLK_GPIO14 \ + ESP32_PINMUX(14, ESP_NOSIG, ESP_SPI3_CLK_OUT) + +#define SPIM3_SCLK_GPIO15 \ + ESP32_PINMUX(15, ESP_NOSIG, ESP_SPI3_CLK_OUT) + +#define SPIM3_SCLK_GPIO16 \ + ESP32_PINMUX(16, ESP_NOSIG, ESP_SPI3_CLK_OUT) + +#define SPIM3_SCLK_GPIO17 \ + ESP32_PINMUX(17, ESP_NOSIG, ESP_SPI3_CLK_OUT) + +#define SPIM3_SCLK_GPIO18 \ + ESP32_PINMUX(18, ESP_NOSIG, ESP_SPI3_CLK_OUT) + +#define SPIM3_SCLK_GPIO19 \ + ESP32_PINMUX(19, ESP_NOSIG, ESP_SPI3_CLK_OUT) + +#define SPIM3_SCLK_GPIO20 \ + ESP32_PINMUX(20, ESP_NOSIG, ESP_SPI3_CLK_OUT) + +#define SPIM3_SCLK_GPIO21 \ + ESP32_PINMUX(21, ESP_NOSIG, ESP_SPI3_CLK_OUT) + +#define SPIM3_SCLK_GPIO26 \ + ESP32_PINMUX(26, ESP_NOSIG, ESP_SPI3_CLK_OUT) + +#define SPIM3_SCLK_GPIO27 \ + ESP32_PINMUX(27, ESP_NOSIG, ESP_SPI3_CLK_OUT) + +#define SPIM3_SCLK_GPIO28 \ + ESP32_PINMUX(28, ESP_NOSIG, ESP_SPI3_CLK_OUT) + +#define SPIM3_SCLK_GPIO29 \ + ESP32_PINMUX(29, ESP_NOSIG, ESP_SPI3_CLK_OUT) + +#define SPIM3_SCLK_GPIO30 \ + ESP32_PINMUX(30, ESP_NOSIG, ESP_SPI3_CLK_OUT) + +#define SPIM3_SCLK_GPIO31 \ + ESP32_PINMUX(31, ESP_NOSIG, ESP_SPI3_CLK_OUT) + +#define SPIM3_SCLK_GPIO32 \ + ESP32_PINMUX(32, ESP_NOSIG, ESP_SPI3_CLK_OUT) + +#define SPIM3_SCLK_GPIO33 \ + ESP32_PINMUX(33, ESP_NOSIG, ESP_SPI3_CLK_OUT) + +#define SPIM3_SCLK_GPIO34 \ + ESP32_PINMUX(34, ESP_NOSIG, ESP_SPI3_CLK_OUT) + +#define SPIM3_SCLK_GPIO35 \ + ESP32_PINMUX(35, ESP_NOSIG, ESP_SPI3_CLK_OUT) + +#define SPIM3_SCLK_GPIO36 \ + ESP32_PINMUX(36, ESP_NOSIG, ESP_SPI3_CLK_OUT) + +#define SPIM3_SCLK_GPIO37 \ + ESP32_PINMUX(37, ESP_NOSIG, ESP_SPI3_CLK_OUT) + +#define SPIM3_SCLK_GPIO38 \ + ESP32_PINMUX(38, ESP_NOSIG, ESP_SPI3_CLK_OUT) + +#define SPIM3_SCLK_GPIO39 \ + ESP32_PINMUX(39, ESP_NOSIG, ESP_SPI3_CLK_OUT) + +#define SPIM3_SCLK_GPIO40 \ + ESP32_PINMUX(40, ESP_NOSIG, ESP_SPI3_CLK_OUT) + +#define SPIM3_SCLK_GPIO41 \ + ESP32_PINMUX(41, ESP_NOSIG, ESP_SPI3_CLK_OUT) + +#define SPIM3_SCLK_GPIO42 \ + ESP32_PINMUX(42, ESP_NOSIG, ESP_SPI3_CLK_OUT) + +#define SPIM3_SCLK_GPIO43 \ + ESP32_PINMUX(43, ESP_NOSIG, ESP_SPI3_CLK_OUT) + +#define SPIM3_SCLK_GPIO44 \ + ESP32_PINMUX(44, ESP_NOSIG, ESP_SPI3_CLK_OUT) + +#define SPIM3_SCLK_GPIO45 \ + ESP32_PINMUX(45, ESP_NOSIG, ESP_SPI3_CLK_OUT) + +#define SPIM3_SCLK_GPIO46 \ + ESP32_PINMUX(46, ESP_NOSIG, ESP_SPI3_CLK_OUT) + +#define SPIM3_SCLK_GPIO47 \ + ESP32_PINMUX(47, ESP_NOSIG, ESP_SPI3_CLK_OUT) + +#define SPIM3_SCLK_GPIO48 \ + ESP32_PINMUX(48, ESP_NOSIG, ESP_SPI3_CLK_OUT) + +/* TWAI_BUS_OFF */ +#define TWAI_BUS_OFF_GPIO0 \ + ESP32_PINMUX(0, ESP_NOSIG, ESP_TWAI_BUS_OFF_ON) + +#define TWAI_BUS_OFF_GPIO1 \ + ESP32_PINMUX(1, ESP_NOSIG, ESP_TWAI_BUS_OFF_ON) + +#define TWAI_BUS_OFF_GPIO2 \ + ESP32_PINMUX(2, ESP_NOSIG, ESP_TWAI_BUS_OFF_ON) + +#define TWAI_BUS_OFF_GPIO3 \ + ESP32_PINMUX(3, ESP_NOSIG, ESP_TWAI_BUS_OFF_ON) + +#define TWAI_BUS_OFF_GPIO4 \ + ESP32_PINMUX(4, ESP_NOSIG, ESP_TWAI_BUS_OFF_ON) + +#define TWAI_BUS_OFF_GPIO5 \ + ESP32_PINMUX(5, ESP_NOSIG, ESP_TWAI_BUS_OFF_ON) + +#define TWAI_BUS_OFF_GPIO6 \ + ESP32_PINMUX(6, ESP_NOSIG, ESP_TWAI_BUS_OFF_ON) + +#define TWAI_BUS_OFF_GPIO7 \ + ESP32_PINMUX(7, ESP_NOSIG, ESP_TWAI_BUS_OFF_ON) + +#define TWAI_BUS_OFF_GPIO8 \ + ESP32_PINMUX(8, ESP_NOSIG, ESP_TWAI_BUS_OFF_ON) + +#define TWAI_BUS_OFF_GPIO9 \ + ESP32_PINMUX(9, ESP_NOSIG, ESP_TWAI_BUS_OFF_ON) + +#define TWAI_BUS_OFF_GPIO10 \ + ESP32_PINMUX(10, ESP_NOSIG, ESP_TWAI_BUS_OFF_ON) + +#define TWAI_BUS_OFF_GPIO11 \ + ESP32_PINMUX(11, ESP_NOSIG, ESP_TWAI_BUS_OFF_ON) + +#define TWAI_BUS_OFF_GPIO12 \ + ESP32_PINMUX(12, ESP_NOSIG, ESP_TWAI_BUS_OFF_ON) + +#define TWAI_BUS_OFF_GPIO13 \ + ESP32_PINMUX(13, ESP_NOSIG, ESP_TWAI_BUS_OFF_ON) + +#define TWAI_BUS_OFF_GPIO14 \ + ESP32_PINMUX(14, ESP_NOSIG, ESP_TWAI_BUS_OFF_ON) + +#define TWAI_BUS_OFF_GPIO15 \ + ESP32_PINMUX(15, ESP_NOSIG, ESP_TWAI_BUS_OFF_ON) + +#define TWAI_BUS_OFF_GPIO16 \ + ESP32_PINMUX(16, ESP_NOSIG, ESP_TWAI_BUS_OFF_ON) + +#define TWAI_BUS_OFF_GPIO17 \ + ESP32_PINMUX(17, ESP_NOSIG, ESP_TWAI_BUS_OFF_ON) + +#define TWAI_BUS_OFF_GPIO18 \ + ESP32_PINMUX(18, ESP_NOSIG, ESP_TWAI_BUS_OFF_ON) + +#define TWAI_BUS_OFF_GPIO19 \ + ESP32_PINMUX(19, ESP_NOSIG, ESP_TWAI_BUS_OFF_ON) + +#define TWAI_BUS_OFF_GPIO20 \ + ESP32_PINMUX(20, ESP_NOSIG, ESP_TWAI_BUS_OFF_ON) + +#define TWAI_BUS_OFF_GPIO21 \ + ESP32_PINMUX(21, ESP_NOSIG, ESP_TWAI_BUS_OFF_ON) + +#define TWAI_BUS_OFF_GPIO26 \ + ESP32_PINMUX(26, ESP_NOSIG, ESP_TWAI_BUS_OFF_ON) + +#define TWAI_BUS_OFF_GPIO27 \ + ESP32_PINMUX(27, ESP_NOSIG, ESP_TWAI_BUS_OFF_ON) + +#define TWAI_BUS_OFF_GPIO28 \ + ESP32_PINMUX(28, ESP_NOSIG, ESP_TWAI_BUS_OFF_ON) + +#define TWAI_BUS_OFF_GPIO29 \ + ESP32_PINMUX(29, ESP_NOSIG, ESP_TWAI_BUS_OFF_ON) + +#define TWAI_BUS_OFF_GPIO30 \ + ESP32_PINMUX(30, ESP_NOSIG, ESP_TWAI_BUS_OFF_ON) + +#define TWAI_BUS_OFF_GPIO31 \ + ESP32_PINMUX(31, ESP_NOSIG, ESP_TWAI_BUS_OFF_ON) + +#define TWAI_BUS_OFF_GPIO32 \ + ESP32_PINMUX(32, ESP_NOSIG, ESP_TWAI_BUS_OFF_ON) + +#define TWAI_BUS_OFF_GPIO33 \ + ESP32_PINMUX(33, ESP_NOSIG, ESP_TWAI_BUS_OFF_ON) + +#define TWAI_BUS_OFF_GPIO34 \ + ESP32_PINMUX(34, ESP_NOSIG, ESP_TWAI_BUS_OFF_ON) + +#define TWAI_BUS_OFF_GPIO35 \ + ESP32_PINMUX(35, ESP_NOSIG, ESP_TWAI_BUS_OFF_ON) + +#define TWAI_BUS_OFF_GPIO36 \ + ESP32_PINMUX(36, ESP_NOSIG, ESP_TWAI_BUS_OFF_ON) + +#define TWAI_BUS_OFF_GPIO37 \ + ESP32_PINMUX(37, ESP_NOSIG, ESP_TWAI_BUS_OFF_ON) + +#define TWAI_BUS_OFF_GPIO38 \ + ESP32_PINMUX(38, ESP_NOSIG, ESP_TWAI_BUS_OFF_ON) + +#define TWAI_BUS_OFF_GPIO39 \ + ESP32_PINMUX(39, ESP_NOSIG, ESP_TWAI_BUS_OFF_ON) + +#define TWAI_BUS_OFF_GPIO40 \ + ESP32_PINMUX(40, ESP_NOSIG, ESP_TWAI_BUS_OFF_ON) + +#define TWAI_BUS_OFF_GPIO41 \ + ESP32_PINMUX(41, ESP_NOSIG, ESP_TWAI_BUS_OFF_ON) + +#define TWAI_BUS_OFF_GPIO42 \ + ESP32_PINMUX(42, ESP_NOSIG, ESP_TWAI_BUS_OFF_ON) + +#define TWAI_BUS_OFF_GPIO43 \ + ESP32_PINMUX(43, ESP_NOSIG, ESP_TWAI_BUS_OFF_ON) + +#define TWAI_BUS_OFF_GPIO44 \ + ESP32_PINMUX(44, ESP_NOSIG, ESP_TWAI_BUS_OFF_ON) + +#define TWAI_BUS_OFF_GPIO45 \ + ESP32_PINMUX(45, ESP_NOSIG, ESP_TWAI_BUS_OFF_ON) + +#define TWAI_BUS_OFF_GPIO46 \ + ESP32_PINMUX(46, ESP_NOSIG, ESP_TWAI_BUS_OFF_ON) + +#define TWAI_BUS_OFF_GPIO47 \ + ESP32_PINMUX(47, ESP_NOSIG, ESP_TWAI_BUS_OFF_ON) + +#define TWAI_BUS_OFF_GPIO48 \ + ESP32_PINMUX(48, ESP_NOSIG, ESP_TWAI_BUS_OFF_ON) + +/* TWAI_CLKOUT */ +#define TWAI_CLKOUT_GPIO0 \ + ESP32_PINMUX(0, ESP_NOSIG, ESP_TWAI_CLKOUT) + +#define TWAI_CLKOUT_GPIO1 \ + ESP32_PINMUX(1, ESP_NOSIG, ESP_TWAI_CLKOUT) + +#define TWAI_CLKOUT_GPIO2 \ + ESP32_PINMUX(2, ESP_NOSIG, ESP_TWAI_CLKOUT) + +#define TWAI_CLKOUT_GPIO3 \ + ESP32_PINMUX(3, ESP_NOSIG, ESP_TWAI_CLKOUT) + +#define TWAI_CLKOUT_GPIO4 \ + ESP32_PINMUX(4, ESP_NOSIG, ESP_TWAI_CLKOUT) + +#define TWAI_CLKOUT_GPIO5 \ + ESP32_PINMUX(5, ESP_NOSIG, ESP_TWAI_CLKOUT) + +#define TWAI_CLKOUT_GPIO6 \ + ESP32_PINMUX(6, ESP_NOSIG, ESP_TWAI_CLKOUT) + +#define TWAI_CLKOUT_GPIO7 \ + ESP32_PINMUX(7, ESP_NOSIG, ESP_TWAI_CLKOUT) + +#define TWAI_CLKOUT_GPIO8 \ + ESP32_PINMUX(8, ESP_NOSIG, ESP_TWAI_CLKOUT) + +#define TWAI_CLKOUT_GPIO9 \ + ESP32_PINMUX(9, ESP_NOSIG, ESP_TWAI_CLKOUT) + +#define TWAI_CLKOUT_GPIO10 \ + ESP32_PINMUX(10, ESP_NOSIG, ESP_TWAI_CLKOUT) + +#define TWAI_CLKOUT_GPIO11 \ + ESP32_PINMUX(11, ESP_NOSIG, ESP_TWAI_CLKOUT) + +#define TWAI_CLKOUT_GPIO12 \ + ESP32_PINMUX(12, ESP_NOSIG, ESP_TWAI_CLKOUT) + +#define TWAI_CLKOUT_GPIO13 \ + ESP32_PINMUX(13, ESP_NOSIG, ESP_TWAI_CLKOUT) + +#define TWAI_CLKOUT_GPIO14 \ + ESP32_PINMUX(14, ESP_NOSIG, ESP_TWAI_CLKOUT) + +#define TWAI_CLKOUT_GPIO15 \ + ESP32_PINMUX(15, ESP_NOSIG, ESP_TWAI_CLKOUT) + +#define TWAI_CLKOUT_GPIO16 \ + ESP32_PINMUX(16, ESP_NOSIG, ESP_TWAI_CLKOUT) + +#define TWAI_CLKOUT_GPIO17 \ + ESP32_PINMUX(17, ESP_NOSIG, ESP_TWAI_CLKOUT) + +#define TWAI_CLKOUT_GPIO18 \ + ESP32_PINMUX(18, ESP_NOSIG, ESP_TWAI_CLKOUT) + +#define TWAI_CLKOUT_GPIO19 \ + ESP32_PINMUX(19, ESP_NOSIG, ESP_TWAI_CLKOUT) + +#define TWAI_CLKOUT_GPIO20 \ + ESP32_PINMUX(20, ESP_NOSIG, ESP_TWAI_CLKOUT) + +#define TWAI_CLKOUT_GPIO21 \ + ESP32_PINMUX(21, ESP_NOSIG, ESP_TWAI_CLKOUT) + +#define TWAI_CLKOUT_GPIO26 \ + ESP32_PINMUX(26, ESP_NOSIG, ESP_TWAI_CLKOUT) + +#define TWAI_CLKOUT_GPIO27 \ + ESP32_PINMUX(27, ESP_NOSIG, ESP_TWAI_CLKOUT) + +#define TWAI_CLKOUT_GPIO28 \ + ESP32_PINMUX(28, ESP_NOSIG, ESP_TWAI_CLKOUT) + +#define TWAI_CLKOUT_GPIO29 \ + ESP32_PINMUX(29, ESP_NOSIG, ESP_TWAI_CLKOUT) + +#define TWAI_CLKOUT_GPIO30 \ + ESP32_PINMUX(30, ESP_NOSIG, ESP_TWAI_CLKOUT) + +#define TWAI_CLKOUT_GPIO31 \ + ESP32_PINMUX(31, ESP_NOSIG, ESP_TWAI_CLKOUT) + +#define TWAI_CLKOUT_GPIO32 \ + ESP32_PINMUX(32, ESP_NOSIG, ESP_TWAI_CLKOUT) + +#define TWAI_CLKOUT_GPIO33 \ + ESP32_PINMUX(33, ESP_NOSIG, ESP_TWAI_CLKOUT) + +#define TWAI_CLKOUT_GPIO34 \ + ESP32_PINMUX(34, ESP_NOSIG, ESP_TWAI_CLKOUT) + +#define TWAI_CLKOUT_GPIO35 \ + ESP32_PINMUX(35, ESP_NOSIG, ESP_TWAI_CLKOUT) + +#define TWAI_CLKOUT_GPIO36 \ + ESP32_PINMUX(36, ESP_NOSIG, ESP_TWAI_CLKOUT) + +#define TWAI_CLKOUT_GPIO37 \ + ESP32_PINMUX(37, ESP_NOSIG, ESP_TWAI_CLKOUT) + +#define TWAI_CLKOUT_GPIO38 \ + ESP32_PINMUX(38, ESP_NOSIG, ESP_TWAI_CLKOUT) + +#define TWAI_CLKOUT_GPIO39 \ + ESP32_PINMUX(39, ESP_NOSIG, ESP_TWAI_CLKOUT) + +#define TWAI_CLKOUT_GPIO40 \ + ESP32_PINMUX(40, ESP_NOSIG, ESP_TWAI_CLKOUT) + +#define TWAI_CLKOUT_GPIO41 \ + ESP32_PINMUX(41, ESP_NOSIG, ESP_TWAI_CLKOUT) + +#define TWAI_CLKOUT_GPIO42 \ + ESP32_PINMUX(42, ESP_NOSIG, ESP_TWAI_CLKOUT) + +#define TWAI_CLKOUT_GPIO43 \ + ESP32_PINMUX(43, ESP_NOSIG, ESP_TWAI_CLKOUT) + +#define TWAI_CLKOUT_GPIO44 \ + ESP32_PINMUX(44, ESP_NOSIG, ESP_TWAI_CLKOUT) + +#define TWAI_CLKOUT_GPIO45 \ + ESP32_PINMUX(45, ESP_NOSIG, ESP_TWAI_CLKOUT) + +#define TWAI_CLKOUT_GPIO46 \ + ESP32_PINMUX(46, ESP_NOSIG, ESP_TWAI_CLKOUT) + +#define TWAI_CLKOUT_GPIO47 \ + ESP32_PINMUX(47, ESP_NOSIG, ESP_TWAI_CLKOUT) + +#define TWAI_CLKOUT_GPIO48 \ + ESP32_PINMUX(48, ESP_NOSIG, ESP_TWAI_CLKOUT) + +/* TWAI_RX */ +#define TWAI_RX_GPIO0 \ + ESP32_PINMUX(0, ESP_TWAI_RX, ESP_NOSIG) + +#define TWAI_RX_GPIO1 \ + ESP32_PINMUX(1, ESP_TWAI_RX, ESP_NOSIG) + +#define TWAI_RX_GPIO2 \ + ESP32_PINMUX(2, ESP_TWAI_RX, ESP_NOSIG) + +#define TWAI_RX_GPIO3 \ + ESP32_PINMUX(3, ESP_TWAI_RX, ESP_NOSIG) + +#define TWAI_RX_GPIO4 \ + ESP32_PINMUX(4, ESP_TWAI_RX, ESP_NOSIG) + +#define TWAI_RX_GPIO5 \ + ESP32_PINMUX(5, ESP_TWAI_RX, ESP_NOSIG) + +#define TWAI_RX_GPIO6 \ + ESP32_PINMUX(6, ESP_TWAI_RX, ESP_NOSIG) + +#define TWAI_RX_GPIO7 \ + ESP32_PINMUX(7, ESP_TWAI_RX, ESP_NOSIG) + +#define TWAI_RX_GPIO8 \ + ESP32_PINMUX(8, ESP_TWAI_RX, ESP_NOSIG) + +#define TWAI_RX_GPIO9 \ + ESP32_PINMUX(9, ESP_TWAI_RX, ESP_NOSIG) + +#define TWAI_RX_GPIO10 \ + ESP32_PINMUX(10, ESP_TWAI_RX, ESP_NOSIG) + +#define TWAI_RX_GPIO11 \ + ESP32_PINMUX(11, ESP_TWAI_RX, ESP_NOSIG) + +#define TWAI_RX_GPIO12 \ + ESP32_PINMUX(12, ESP_TWAI_RX, ESP_NOSIG) + +#define TWAI_RX_GPIO13 \ + ESP32_PINMUX(13, ESP_TWAI_RX, ESP_NOSIG) + +#define TWAI_RX_GPIO14 \ + ESP32_PINMUX(14, ESP_TWAI_RX, ESP_NOSIG) + +#define TWAI_RX_GPIO15 \ + ESP32_PINMUX(15, ESP_TWAI_RX, ESP_NOSIG) + +#define TWAI_RX_GPIO16 \ + ESP32_PINMUX(16, ESP_TWAI_RX, ESP_NOSIG) + +#define TWAI_RX_GPIO17 \ + ESP32_PINMUX(17, ESP_TWAI_RX, ESP_NOSIG) + +#define TWAI_RX_GPIO18 \ + ESP32_PINMUX(18, ESP_TWAI_RX, ESP_NOSIG) + +#define TWAI_RX_GPIO19 \ + ESP32_PINMUX(19, ESP_TWAI_RX, ESP_NOSIG) + +#define TWAI_RX_GPIO20 \ + ESP32_PINMUX(20, ESP_TWAI_RX, ESP_NOSIG) + +#define TWAI_RX_GPIO21 \ + ESP32_PINMUX(21, ESP_TWAI_RX, ESP_NOSIG) + +#define TWAI_RX_GPIO26 \ + ESP32_PINMUX(26, ESP_TWAI_RX, ESP_NOSIG) + +#define TWAI_RX_GPIO27 \ + ESP32_PINMUX(27, ESP_TWAI_RX, ESP_NOSIG) + +#define TWAI_RX_GPIO28 \ + ESP32_PINMUX(28, ESP_TWAI_RX, ESP_NOSIG) + +#define TWAI_RX_GPIO29 \ + ESP32_PINMUX(29, ESP_TWAI_RX, ESP_NOSIG) + +#define TWAI_RX_GPIO30 \ + ESP32_PINMUX(30, ESP_TWAI_RX, ESP_NOSIG) + +#define TWAI_RX_GPIO31 \ + ESP32_PINMUX(31, ESP_TWAI_RX, ESP_NOSIG) + +#define TWAI_RX_GPIO32 \ + ESP32_PINMUX(32, ESP_TWAI_RX, ESP_NOSIG) + +#define TWAI_RX_GPIO33 \ + ESP32_PINMUX(33, ESP_TWAI_RX, ESP_NOSIG) + +#define TWAI_RX_GPIO34 \ + ESP32_PINMUX(34, ESP_TWAI_RX, ESP_NOSIG) + +#define TWAI_RX_GPIO35 \ + ESP32_PINMUX(35, ESP_TWAI_RX, ESP_NOSIG) + +#define TWAI_RX_GPIO36 \ + ESP32_PINMUX(36, ESP_TWAI_RX, ESP_NOSIG) + +#define TWAI_RX_GPIO37 \ + ESP32_PINMUX(37, ESP_TWAI_RX, ESP_NOSIG) + +#define TWAI_RX_GPIO38 \ + ESP32_PINMUX(38, ESP_TWAI_RX, ESP_NOSIG) + +#define TWAI_RX_GPIO39 \ + ESP32_PINMUX(39, ESP_TWAI_RX, ESP_NOSIG) + +#define TWAI_RX_GPIO40 \ + ESP32_PINMUX(40, ESP_TWAI_RX, ESP_NOSIG) + +#define TWAI_RX_GPIO41 \ + ESP32_PINMUX(41, ESP_TWAI_RX, ESP_NOSIG) + +#define TWAI_RX_GPIO42 \ + ESP32_PINMUX(42, ESP_TWAI_RX, ESP_NOSIG) + +#define TWAI_RX_GPIO43 \ + ESP32_PINMUX(43, ESP_TWAI_RX, ESP_NOSIG) + +#define TWAI_RX_GPIO44 \ + ESP32_PINMUX(44, ESP_TWAI_RX, ESP_NOSIG) + +#define TWAI_RX_GPIO45 \ + ESP32_PINMUX(45, ESP_TWAI_RX, ESP_NOSIG) + +#define TWAI_RX_GPIO46 \ + ESP32_PINMUX(46, ESP_TWAI_RX, ESP_NOSIG) + +#define TWAI_RX_GPIO47 \ + ESP32_PINMUX(47, ESP_TWAI_RX, ESP_NOSIG) + +#define TWAI_RX_GPIO48 \ + ESP32_PINMUX(48, ESP_TWAI_RX, ESP_NOSIG) + +/* TWAI_TX */ +#define TWAI_TX_GPIO0 \ + ESP32_PINMUX(0, ESP_NOSIG, ESP_TWAI_TX) + +#define TWAI_TX_GPIO1 \ + ESP32_PINMUX(1, ESP_NOSIG, ESP_TWAI_TX) + +#define TWAI_TX_GPIO2 \ + ESP32_PINMUX(2, ESP_NOSIG, ESP_TWAI_TX) + +#define TWAI_TX_GPIO3 \ + ESP32_PINMUX(3, ESP_NOSIG, ESP_TWAI_TX) + +#define TWAI_TX_GPIO4 \ + ESP32_PINMUX(4, ESP_NOSIG, ESP_TWAI_TX) + +#define TWAI_TX_GPIO5 \ + ESP32_PINMUX(5, ESP_NOSIG, ESP_TWAI_TX) + +#define TWAI_TX_GPIO6 \ + ESP32_PINMUX(6, ESP_NOSIG, ESP_TWAI_TX) + +#define TWAI_TX_GPIO7 \ + ESP32_PINMUX(7, ESP_NOSIG, ESP_TWAI_TX) + +#define TWAI_TX_GPIO8 \ + ESP32_PINMUX(8, ESP_NOSIG, ESP_TWAI_TX) + +#define TWAI_TX_GPIO9 \ + ESP32_PINMUX(9, ESP_NOSIG, ESP_TWAI_TX) + +#define TWAI_TX_GPIO10 \ + ESP32_PINMUX(10, ESP_NOSIG, ESP_TWAI_TX) + +#define TWAI_TX_GPIO11 \ + ESP32_PINMUX(11, ESP_NOSIG, ESP_TWAI_TX) + +#define TWAI_TX_GPIO12 \ + ESP32_PINMUX(12, ESP_NOSIG, ESP_TWAI_TX) + +#define TWAI_TX_GPIO13 \ + ESP32_PINMUX(13, ESP_NOSIG, ESP_TWAI_TX) + +#define TWAI_TX_GPIO14 \ + ESP32_PINMUX(14, ESP_NOSIG, ESP_TWAI_TX) + +#define TWAI_TX_GPIO15 \ + ESP32_PINMUX(15, ESP_NOSIG, ESP_TWAI_TX) + +#define TWAI_TX_GPIO16 \ + ESP32_PINMUX(16, ESP_NOSIG, ESP_TWAI_TX) + +#define TWAI_TX_GPIO17 \ + ESP32_PINMUX(17, ESP_NOSIG, ESP_TWAI_TX) + +#define TWAI_TX_GPIO18 \ + ESP32_PINMUX(18, ESP_NOSIG, ESP_TWAI_TX) + +#define TWAI_TX_GPIO19 \ + ESP32_PINMUX(19, ESP_NOSIG, ESP_TWAI_TX) + +#define TWAI_TX_GPIO20 \ + ESP32_PINMUX(20, ESP_NOSIG, ESP_TWAI_TX) + +#define TWAI_TX_GPIO21 \ + ESP32_PINMUX(21, ESP_NOSIG, ESP_TWAI_TX) + +#define TWAI_TX_GPIO26 \ + ESP32_PINMUX(26, ESP_NOSIG, ESP_TWAI_TX) + +#define TWAI_TX_GPIO27 \ + ESP32_PINMUX(27, ESP_NOSIG, ESP_TWAI_TX) + +#define TWAI_TX_GPIO28 \ + ESP32_PINMUX(28, ESP_NOSIG, ESP_TWAI_TX) + +#define TWAI_TX_GPIO29 \ + ESP32_PINMUX(29, ESP_NOSIG, ESP_TWAI_TX) + +#define TWAI_TX_GPIO30 \ + ESP32_PINMUX(30, ESP_NOSIG, ESP_TWAI_TX) + +#define TWAI_TX_GPIO31 \ + ESP32_PINMUX(31, ESP_NOSIG, ESP_TWAI_TX) + +#define TWAI_TX_GPIO32 \ + ESP32_PINMUX(32, ESP_NOSIG, ESP_TWAI_TX) + +#define TWAI_TX_GPIO33 \ + ESP32_PINMUX(33, ESP_NOSIG, ESP_TWAI_TX) + +#define TWAI_TX_GPIO34 \ + ESP32_PINMUX(34, ESP_NOSIG, ESP_TWAI_TX) + +#define TWAI_TX_GPIO35 \ + ESP32_PINMUX(35, ESP_NOSIG, ESP_TWAI_TX) + +#define TWAI_TX_GPIO36 \ + ESP32_PINMUX(36, ESP_NOSIG, ESP_TWAI_TX) + +#define TWAI_TX_GPIO37 \ + ESP32_PINMUX(37, ESP_NOSIG, ESP_TWAI_TX) + +#define TWAI_TX_GPIO38 \ + ESP32_PINMUX(38, ESP_NOSIG, ESP_TWAI_TX) + +#define TWAI_TX_GPIO39 \ + ESP32_PINMUX(39, ESP_NOSIG, ESP_TWAI_TX) + +#define TWAI_TX_GPIO40 \ + ESP32_PINMUX(40, ESP_NOSIG, ESP_TWAI_TX) + +#define TWAI_TX_GPIO41 \ + ESP32_PINMUX(41, ESP_NOSIG, ESP_TWAI_TX) + +#define TWAI_TX_GPIO42 \ + ESP32_PINMUX(42, ESP_NOSIG, ESP_TWAI_TX) + +#define TWAI_TX_GPIO43 \ + ESP32_PINMUX(43, ESP_NOSIG, ESP_TWAI_TX) + +#define TWAI_TX_GPIO44 \ + ESP32_PINMUX(44, ESP_NOSIG, ESP_TWAI_TX) + +#define TWAI_TX_GPIO45 \ + ESP32_PINMUX(45, ESP_NOSIG, ESP_TWAI_TX) + +#define TWAI_TX_GPIO46 \ + ESP32_PINMUX(46, ESP_NOSIG, ESP_TWAI_TX) + +#define TWAI_TX_GPIO47 \ + ESP32_PINMUX(47, ESP_NOSIG, ESP_TWAI_TX) + +#define TWAI_TX_GPIO48 \ + ESP32_PINMUX(48, ESP_NOSIG, ESP_TWAI_TX) + +/* UART0_CTS */ +#define UART0_CTS_GPIO0 \ + ESP32_PINMUX(0, ESP_U0CTS_IN, ESP_NOSIG) + +#define UART0_CTS_GPIO1 \ + ESP32_PINMUX(1, ESP_U0CTS_IN, ESP_NOSIG) + +#define UART0_CTS_GPIO2 \ + ESP32_PINMUX(2, ESP_U0CTS_IN, ESP_NOSIG) + +#define UART0_CTS_GPIO3 \ + ESP32_PINMUX(3, ESP_U0CTS_IN, ESP_NOSIG) + +#define UART0_CTS_GPIO4 \ + ESP32_PINMUX(4, ESP_U0CTS_IN, ESP_NOSIG) + +#define UART0_CTS_GPIO5 \ + ESP32_PINMUX(5, ESP_U0CTS_IN, ESP_NOSIG) + +#define UART0_CTS_GPIO6 \ + ESP32_PINMUX(6, ESP_U0CTS_IN, ESP_NOSIG) + +#define UART0_CTS_GPIO7 \ + ESP32_PINMUX(7, ESP_U0CTS_IN, ESP_NOSIG) + +#define UART0_CTS_GPIO8 \ + ESP32_PINMUX(8, ESP_U0CTS_IN, ESP_NOSIG) + +#define UART0_CTS_GPIO9 \ + ESP32_PINMUX(9, ESP_U0CTS_IN, ESP_NOSIG) + +#define UART0_CTS_GPIO10 \ + ESP32_PINMUX(10, ESP_U0CTS_IN, ESP_NOSIG) + +#define UART0_CTS_GPIO11 \ + ESP32_PINMUX(11, ESP_U0CTS_IN, ESP_NOSIG) + +#define UART0_CTS_GPIO12 \ + ESP32_PINMUX(12, ESP_U0CTS_IN, ESP_NOSIG) + +#define UART0_CTS_GPIO13 \ + ESP32_PINMUX(13, ESP_U0CTS_IN, ESP_NOSIG) + +#define UART0_CTS_GPIO14 \ + ESP32_PINMUX(14, ESP_U0CTS_IN, ESP_NOSIG) + +#define UART0_CTS_GPIO15 \ + ESP32_PINMUX(15, ESP_U0CTS_IN, ESP_NOSIG) + +#define UART0_CTS_GPIO16 \ + ESP32_PINMUX(16, ESP_U0CTS_IN, ESP_NOSIG) + +#define UART0_CTS_GPIO17 \ + ESP32_PINMUX(17, ESP_U0CTS_IN, ESP_NOSIG) + +#define UART0_CTS_GPIO18 \ + ESP32_PINMUX(18, ESP_U0CTS_IN, ESP_NOSIG) + +#define UART0_CTS_GPIO19 \ + ESP32_PINMUX(19, ESP_U0CTS_IN, ESP_NOSIG) + +#define UART0_CTS_GPIO20 \ + ESP32_PINMUX(20, ESP_U0CTS_IN, ESP_NOSIG) + +#define UART0_CTS_GPIO21 \ + ESP32_PINMUX(21, ESP_U0CTS_IN, ESP_NOSIG) + +#define UART0_CTS_GPIO26 \ + ESP32_PINMUX(26, ESP_U0CTS_IN, ESP_NOSIG) + +#define UART0_CTS_GPIO27 \ + ESP32_PINMUX(27, ESP_U0CTS_IN, ESP_NOSIG) + +#define UART0_CTS_GPIO28 \ + ESP32_PINMUX(28, ESP_U0CTS_IN, ESP_NOSIG) + +#define UART0_CTS_GPIO29 \ + ESP32_PINMUX(29, ESP_U0CTS_IN, ESP_NOSIG) + +#define UART0_CTS_GPIO30 \ + ESP32_PINMUX(30, ESP_U0CTS_IN, ESP_NOSIG) + +#define UART0_CTS_GPIO31 \ + ESP32_PINMUX(31, ESP_U0CTS_IN, ESP_NOSIG) + +#define UART0_CTS_GPIO32 \ + ESP32_PINMUX(32, ESP_U0CTS_IN, ESP_NOSIG) + +#define UART0_CTS_GPIO33 \ + ESP32_PINMUX(33, ESP_U0CTS_IN, ESP_NOSIG) + +#define UART0_CTS_GPIO34 \ + ESP32_PINMUX(34, ESP_U0CTS_IN, ESP_NOSIG) + +#define UART0_CTS_GPIO35 \ + ESP32_PINMUX(35, ESP_U0CTS_IN, ESP_NOSIG) + +#define UART0_CTS_GPIO36 \ + ESP32_PINMUX(36, ESP_U0CTS_IN, ESP_NOSIG) + +#define UART0_CTS_GPIO37 \ + ESP32_PINMUX(37, ESP_U0CTS_IN, ESP_NOSIG) + +#define UART0_CTS_GPIO38 \ + ESP32_PINMUX(38, ESP_U0CTS_IN, ESP_NOSIG) + +#define UART0_CTS_GPIO39 \ + ESP32_PINMUX(39, ESP_U0CTS_IN, ESP_NOSIG) + +#define UART0_CTS_GPIO40 \ + ESP32_PINMUX(40, ESP_U0CTS_IN, ESP_NOSIG) + +#define UART0_CTS_GPIO41 \ + ESP32_PINMUX(41, ESP_U0CTS_IN, ESP_NOSIG) + +#define UART0_CTS_GPIO42 \ + ESP32_PINMUX(42, ESP_U0CTS_IN, ESP_NOSIG) + +#define UART0_CTS_GPIO43 \ + ESP32_PINMUX(43, ESP_U0CTS_IN, ESP_NOSIG) + +#define UART0_CTS_GPIO44 \ + ESP32_PINMUX(44, ESP_U0CTS_IN, ESP_NOSIG) + +#define UART0_CTS_GPIO45 \ + ESP32_PINMUX(45, ESP_U0CTS_IN, ESP_NOSIG) + +#define UART0_CTS_GPIO46 \ + ESP32_PINMUX(46, ESP_U0CTS_IN, ESP_NOSIG) + +#define UART0_CTS_GPIO47 \ + ESP32_PINMUX(47, ESP_U0CTS_IN, ESP_NOSIG) + +#define UART0_CTS_GPIO48 \ + ESP32_PINMUX(48, ESP_U0CTS_IN, ESP_NOSIG) + +/* UART0_DSR */ +#define UART0_DSR_GPIO0 \ + ESP32_PINMUX(0, ESP_U0DSR_IN, ESP_NOSIG) + +#define UART0_DSR_GPIO1 \ + ESP32_PINMUX(1, ESP_U0DSR_IN, ESP_NOSIG) + +#define UART0_DSR_GPIO2 \ + ESP32_PINMUX(2, ESP_U0DSR_IN, ESP_NOSIG) + +#define UART0_DSR_GPIO3 \ + ESP32_PINMUX(3, ESP_U0DSR_IN, ESP_NOSIG) + +#define UART0_DSR_GPIO4 \ + ESP32_PINMUX(4, ESP_U0DSR_IN, ESP_NOSIG) + +#define UART0_DSR_GPIO5 \ + ESP32_PINMUX(5, ESP_U0DSR_IN, ESP_NOSIG) + +#define UART0_DSR_GPIO6 \ + ESP32_PINMUX(6, ESP_U0DSR_IN, ESP_NOSIG) + +#define UART0_DSR_GPIO7 \ + ESP32_PINMUX(7, ESP_U0DSR_IN, ESP_NOSIG) + +#define UART0_DSR_GPIO8 \ + ESP32_PINMUX(8, ESP_U0DSR_IN, ESP_NOSIG) + +#define UART0_DSR_GPIO9 \ + ESP32_PINMUX(9, ESP_U0DSR_IN, ESP_NOSIG) + +#define UART0_DSR_GPIO10 \ + ESP32_PINMUX(10, ESP_U0DSR_IN, ESP_NOSIG) + +#define UART0_DSR_GPIO11 \ + ESP32_PINMUX(11, ESP_U0DSR_IN, ESP_NOSIG) + +#define UART0_DSR_GPIO12 \ + ESP32_PINMUX(12, ESP_U0DSR_IN, ESP_NOSIG) + +#define UART0_DSR_GPIO13 \ + ESP32_PINMUX(13, ESP_U0DSR_IN, ESP_NOSIG) + +#define UART0_DSR_GPIO14 \ + ESP32_PINMUX(14, ESP_U0DSR_IN, ESP_NOSIG) + +#define UART0_DSR_GPIO15 \ + ESP32_PINMUX(15, ESP_U0DSR_IN, ESP_NOSIG) + +#define UART0_DSR_GPIO16 \ + ESP32_PINMUX(16, ESP_U0DSR_IN, ESP_NOSIG) + +#define UART0_DSR_GPIO17 \ + ESP32_PINMUX(17, ESP_U0DSR_IN, ESP_NOSIG) + +#define UART0_DSR_GPIO18 \ + ESP32_PINMUX(18, ESP_U0DSR_IN, ESP_NOSIG) + +#define UART0_DSR_GPIO19 \ + ESP32_PINMUX(19, ESP_U0DSR_IN, ESP_NOSIG) + +#define UART0_DSR_GPIO20 \ + ESP32_PINMUX(20, ESP_U0DSR_IN, ESP_NOSIG) + +#define UART0_DSR_GPIO21 \ + ESP32_PINMUX(21, ESP_U0DSR_IN, ESP_NOSIG) + +#define UART0_DSR_GPIO26 \ + ESP32_PINMUX(26, ESP_U0DSR_IN, ESP_NOSIG) + +#define UART0_DSR_GPIO27 \ + ESP32_PINMUX(27, ESP_U0DSR_IN, ESP_NOSIG) + +#define UART0_DSR_GPIO28 \ + ESP32_PINMUX(28, ESP_U0DSR_IN, ESP_NOSIG) + +#define UART0_DSR_GPIO29 \ + ESP32_PINMUX(29, ESP_U0DSR_IN, ESP_NOSIG) + +#define UART0_DSR_GPIO30 \ + ESP32_PINMUX(30, ESP_U0DSR_IN, ESP_NOSIG) + +#define UART0_DSR_GPIO31 \ + ESP32_PINMUX(31, ESP_U0DSR_IN, ESP_NOSIG) + +#define UART0_DSR_GPIO32 \ + ESP32_PINMUX(32, ESP_U0DSR_IN, ESP_NOSIG) + +#define UART0_DSR_GPIO33 \ + ESP32_PINMUX(33, ESP_U0DSR_IN, ESP_NOSIG) + +#define UART0_DSR_GPIO34 \ + ESP32_PINMUX(34, ESP_U0DSR_IN, ESP_NOSIG) + +#define UART0_DSR_GPIO35 \ + ESP32_PINMUX(35, ESP_U0DSR_IN, ESP_NOSIG) + +#define UART0_DSR_GPIO36 \ + ESP32_PINMUX(36, ESP_U0DSR_IN, ESP_NOSIG) + +#define UART0_DSR_GPIO37 \ + ESP32_PINMUX(37, ESP_U0DSR_IN, ESP_NOSIG) + +#define UART0_DSR_GPIO38 \ + ESP32_PINMUX(38, ESP_U0DSR_IN, ESP_NOSIG) + +#define UART0_DSR_GPIO39 \ + ESP32_PINMUX(39, ESP_U0DSR_IN, ESP_NOSIG) + +#define UART0_DSR_GPIO40 \ + ESP32_PINMUX(40, ESP_U0DSR_IN, ESP_NOSIG) + +#define UART0_DSR_GPIO41 \ + ESP32_PINMUX(41, ESP_U0DSR_IN, ESP_NOSIG) + +#define UART0_DSR_GPIO42 \ + ESP32_PINMUX(42, ESP_U0DSR_IN, ESP_NOSIG) + +#define UART0_DSR_GPIO43 \ + ESP32_PINMUX(43, ESP_U0DSR_IN, ESP_NOSIG) + +#define UART0_DSR_GPIO44 \ + ESP32_PINMUX(44, ESP_U0DSR_IN, ESP_NOSIG) + +#define UART0_DSR_GPIO45 \ + ESP32_PINMUX(45, ESP_U0DSR_IN, ESP_NOSIG) + +#define UART0_DSR_GPIO46 \ + ESP32_PINMUX(46, ESP_U0DSR_IN, ESP_NOSIG) + +#define UART0_DSR_GPIO47 \ + ESP32_PINMUX(47, ESP_U0DSR_IN, ESP_NOSIG) + +#define UART0_DSR_GPIO48 \ + ESP32_PINMUX(48, ESP_U0DSR_IN, ESP_NOSIG) + +/* UART0_DTR */ +#define UART0_DTR_GPIO0 \ + ESP32_PINMUX(0, ESP_NOSIG, ESP_U0DTR_OUT) + +#define UART0_DTR_GPIO1 \ + ESP32_PINMUX(1, ESP_NOSIG, ESP_U0DTR_OUT) + +#define UART0_DTR_GPIO2 \ + ESP32_PINMUX(2, ESP_NOSIG, ESP_U0DTR_OUT) + +#define UART0_DTR_GPIO3 \ + ESP32_PINMUX(3, ESP_NOSIG, ESP_U0DTR_OUT) + +#define UART0_DTR_GPIO4 \ + ESP32_PINMUX(4, ESP_NOSIG, ESP_U0DTR_OUT) + +#define UART0_DTR_GPIO5 \ + ESP32_PINMUX(5, ESP_NOSIG, ESP_U0DTR_OUT) + +#define UART0_DTR_GPIO6 \ + ESP32_PINMUX(6, ESP_NOSIG, ESP_U0DTR_OUT) + +#define UART0_DTR_GPIO7 \ + ESP32_PINMUX(7, ESP_NOSIG, ESP_U0DTR_OUT) + +#define UART0_DTR_GPIO8 \ + ESP32_PINMUX(8, ESP_NOSIG, ESP_U0DTR_OUT) + +#define UART0_DTR_GPIO9 \ + ESP32_PINMUX(9, ESP_NOSIG, ESP_U0DTR_OUT) + +#define UART0_DTR_GPIO10 \ + ESP32_PINMUX(10, ESP_NOSIG, ESP_U0DTR_OUT) + +#define UART0_DTR_GPIO11 \ + ESP32_PINMUX(11, ESP_NOSIG, ESP_U0DTR_OUT) + +#define UART0_DTR_GPIO12 \ + ESP32_PINMUX(12, ESP_NOSIG, ESP_U0DTR_OUT) + +#define UART0_DTR_GPIO13 \ + ESP32_PINMUX(13, ESP_NOSIG, ESP_U0DTR_OUT) + +#define UART0_DTR_GPIO14 \ + ESP32_PINMUX(14, ESP_NOSIG, ESP_U0DTR_OUT) + +#define UART0_DTR_GPIO15 \ + ESP32_PINMUX(15, ESP_NOSIG, ESP_U0DTR_OUT) + +#define UART0_DTR_GPIO16 \ + ESP32_PINMUX(16, ESP_NOSIG, ESP_U0DTR_OUT) + +#define UART0_DTR_GPIO17 \ + ESP32_PINMUX(17, ESP_NOSIG, ESP_U0DTR_OUT) + +#define UART0_DTR_GPIO18 \ + ESP32_PINMUX(18, ESP_NOSIG, ESP_U0DTR_OUT) + +#define UART0_DTR_GPIO19 \ + ESP32_PINMUX(19, ESP_NOSIG, ESP_U0DTR_OUT) + +#define UART0_DTR_GPIO20 \ + ESP32_PINMUX(20, ESP_NOSIG, ESP_U0DTR_OUT) + +#define UART0_DTR_GPIO21 \ + ESP32_PINMUX(21, ESP_NOSIG, ESP_U0DTR_OUT) + +#define UART0_DTR_GPIO26 \ + ESP32_PINMUX(26, ESP_NOSIG, ESP_U0DTR_OUT) + +#define UART0_DTR_GPIO27 \ + ESP32_PINMUX(27, ESP_NOSIG, ESP_U0DTR_OUT) + +#define UART0_DTR_GPIO28 \ + ESP32_PINMUX(28, ESP_NOSIG, ESP_U0DTR_OUT) + +#define UART0_DTR_GPIO29 \ + ESP32_PINMUX(29, ESP_NOSIG, ESP_U0DTR_OUT) + +#define UART0_DTR_GPIO30 \ + ESP32_PINMUX(30, ESP_NOSIG, ESP_U0DTR_OUT) + +#define UART0_DTR_GPIO31 \ + ESP32_PINMUX(31, ESP_NOSIG, ESP_U0DTR_OUT) + +#define UART0_DTR_GPIO32 \ + ESP32_PINMUX(32, ESP_NOSIG, ESP_U0DTR_OUT) + +#define UART0_DTR_GPIO33 \ + ESP32_PINMUX(33, ESP_NOSIG, ESP_U0DTR_OUT) + +#define UART0_DTR_GPIO34 \ + ESP32_PINMUX(34, ESP_NOSIG, ESP_U0DTR_OUT) + +#define UART0_DTR_GPIO35 \ + ESP32_PINMUX(35, ESP_NOSIG, ESP_U0DTR_OUT) + +#define UART0_DTR_GPIO36 \ + ESP32_PINMUX(36, ESP_NOSIG, ESP_U0DTR_OUT) + +#define UART0_DTR_GPIO37 \ + ESP32_PINMUX(37, ESP_NOSIG, ESP_U0DTR_OUT) + +#define UART0_DTR_GPIO38 \ + ESP32_PINMUX(38, ESP_NOSIG, ESP_U0DTR_OUT) + +#define UART0_DTR_GPIO39 \ + ESP32_PINMUX(39, ESP_NOSIG, ESP_U0DTR_OUT) + +#define UART0_DTR_GPIO40 \ + ESP32_PINMUX(40, ESP_NOSIG, ESP_U0DTR_OUT) + +#define UART0_DTR_GPIO41 \ + ESP32_PINMUX(41, ESP_NOSIG, ESP_U0DTR_OUT) + +#define UART0_DTR_GPIO42 \ + ESP32_PINMUX(42, ESP_NOSIG, ESP_U0DTR_OUT) + +#define UART0_DTR_GPIO43 \ + ESP32_PINMUX(43, ESP_NOSIG, ESP_U0DTR_OUT) + +#define UART0_DTR_GPIO44 \ + ESP32_PINMUX(44, ESP_NOSIG, ESP_U0DTR_OUT) + +#define UART0_DTR_GPIO45 \ + ESP32_PINMUX(45, ESP_NOSIG, ESP_U0DTR_OUT) + +#define UART0_DTR_GPIO46 \ + ESP32_PINMUX(46, ESP_NOSIG, ESP_U0DTR_OUT) + +#define UART0_DTR_GPIO47 \ + ESP32_PINMUX(47, ESP_NOSIG, ESP_U0DTR_OUT) + +#define UART0_DTR_GPIO48 \ + ESP32_PINMUX(48, ESP_NOSIG, ESP_U0DTR_OUT) + +/* UART0_RTS */ +#define UART0_RTS_GPIO0 \ + ESP32_PINMUX(0, ESP_NOSIG, ESP_U0RTS_OUT) + +#define UART0_RTS_GPIO1 \ + ESP32_PINMUX(1, ESP_NOSIG, ESP_U0RTS_OUT) + +#define UART0_RTS_GPIO2 \ + ESP32_PINMUX(2, ESP_NOSIG, ESP_U0RTS_OUT) + +#define UART0_RTS_GPIO3 \ + ESP32_PINMUX(3, ESP_NOSIG, ESP_U0RTS_OUT) + +#define UART0_RTS_GPIO4 \ + ESP32_PINMUX(4, ESP_NOSIG, ESP_U0RTS_OUT) + +#define UART0_RTS_GPIO5 \ + ESP32_PINMUX(5, ESP_NOSIG, ESP_U0RTS_OUT) + +#define UART0_RTS_GPIO6 \ + ESP32_PINMUX(6, ESP_NOSIG, ESP_U0RTS_OUT) + +#define UART0_RTS_GPIO7 \ + ESP32_PINMUX(7, ESP_NOSIG, ESP_U0RTS_OUT) + +#define UART0_RTS_GPIO8 \ + ESP32_PINMUX(8, ESP_NOSIG, ESP_U0RTS_OUT) + +#define UART0_RTS_GPIO9 \ + ESP32_PINMUX(9, ESP_NOSIG, ESP_U0RTS_OUT) + +#define UART0_RTS_GPIO10 \ + ESP32_PINMUX(10, ESP_NOSIG, ESP_U0RTS_OUT) + +#define UART0_RTS_GPIO11 \ + ESP32_PINMUX(11, ESP_NOSIG, ESP_U0RTS_OUT) + +#define UART0_RTS_GPIO12 \ + ESP32_PINMUX(12, ESP_NOSIG, ESP_U0RTS_OUT) + +#define UART0_RTS_GPIO13 \ + ESP32_PINMUX(13, ESP_NOSIG, ESP_U0RTS_OUT) + +#define UART0_RTS_GPIO14 \ + ESP32_PINMUX(14, ESP_NOSIG, ESP_U0RTS_OUT) + +#define UART0_RTS_GPIO15 \ + ESP32_PINMUX(15, ESP_NOSIG, ESP_U0RTS_OUT) + +#define UART0_RTS_GPIO16 \ + ESP32_PINMUX(16, ESP_NOSIG, ESP_U0RTS_OUT) + +#define UART0_RTS_GPIO17 \ + ESP32_PINMUX(17, ESP_NOSIG, ESP_U0RTS_OUT) + +#define UART0_RTS_GPIO18 \ + ESP32_PINMUX(18, ESP_NOSIG, ESP_U0RTS_OUT) + +#define UART0_RTS_GPIO19 \ + ESP32_PINMUX(19, ESP_NOSIG, ESP_U0RTS_OUT) + +#define UART0_RTS_GPIO20 \ + ESP32_PINMUX(20, ESP_NOSIG, ESP_U0RTS_OUT) + +#define UART0_RTS_GPIO21 \ + ESP32_PINMUX(21, ESP_NOSIG, ESP_U0RTS_OUT) + +#define UART0_RTS_GPIO26 \ + ESP32_PINMUX(26, ESP_NOSIG, ESP_U0RTS_OUT) + +#define UART0_RTS_GPIO27 \ + ESP32_PINMUX(27, ESP_NOSIG, ESP_U0RTS_OUT) + +#define UART0_RTS_GPIO28 \ + ESP32_PINMUX(28, ESP_NOSIG, ESP_U0RTS_OUT) + +#define UART0_RTS_GPIO29 \ + ESP32_PINMUX(29, ESP_NOSIG, ESP_U0RTS_OUT) + +#define UART0_RTS_GPIO30 \ + ESP32_PINMUX(30, ESP_NOSIG, ESP_U0RTS_OUT) + +#define UART0_RTS_GPIO31 \ + ESP32_PINMUX(31, ESP_NOSIG, ESP_U0RTS_OUT) + +#define UART0_RTS_GPIO32 \ + ESP32_PINMUX(32, ESP_NOSIG, ESP_U0RTS_OUT) + +#define UART0_RTS_GPIO33 \ + ESP32_PINMUX(33, ESP_NOSIG, ESP_U0RTS_OUT) + +#define UART0_RTS_GPIO34 \ + ESP32_PINMUX(34, ESP_NOSIG, ESP_U0RTS_OUT) + +#define UART0_RTS_GPIO35 \ + ESP32_PINMUX(35, ESP_NOSIG, ESP_U0RTS_OUT) + +#define UART0_RTS_GPIO36 \ + ESP32_PINMUX(36, ESP_NOSIG, ESP_U0RTS_OUT) + +#define UART0_RTS_GPIO37 \ + ESP32_PINMUX(37, ESP_NOSIG, ESP_U0RTS_OUT) + +#define UART0_RTS_GPIO38 \ + ESP32_PINMUX(38, ESP_NOSIG, ESP_U0RTS_OUT) + +#define UART0_RTS_GPIO39 \ + ESP32_PINMUX(39, ESP_NOSIG, ESP_U0RTS_OUT) + +#define UART0_RTS_GPIO40 \ + ESP32_PINMUX(40, ESP_NOSIG, ESP_U0RTS_OUT) + +#define UART0_RTS_GPIO41 \ + ESP32_PINMUX(41, ESP_NOSIG, ESP_U0RTS_OUT) + +#define UART0_RTS_GPIO42 \ + ESP32_PINMUX(42, ESP_NOSIG, ESP_U0RTS_OUT) + +#define UART0_RTS_GPIO43 \ + ESP32_PINMUX(43, ESP_NOSIG, ESP_U0RTS_OUT) + +#define UART0_RTS_GPIO44 \ + ESP32_PINMUX(44, ESP_NOSIG, ESP_U0RTS_OUT) + +#define UART0_RTS_GPIO45 \ + ESP32_PINMUX(45, ESP_NOSIG, ESP_U0RTS_OUT) + +#define UART0_RTS_GPIO46 \ + ESP32_PINMUX(46, ESP_NOSIG, ESP_U0RTS_OUT) + +#define UART0_RTS_GPIO47 \ + ESP32_PINMUX(47, ESP_NOSIG, ESP_U0RTS_OUT) + +#define UART0_RTS_GPIO48 \ + ESP32_PINMUX(48, ESP_NOSIG, ESP_U0RTS_OUT) + +/* UART0_RX */ +#define UART0_RX_GPIO0 \ + ESP32_PINMUX(0, ESP_U0RXD_IN, ESP_NOSIG) + +#define UART0_RX_GPIO1 \ + ESP32_PINMUX(1, ESP_U0RXD_IN, ESP_NOSIG) + +#define UART0_RX_GPIO2 \ + ESP32_PINMUX(2, ESP_U0RXD_IN, ESP_NOSIG) + +#define UART0_RX_GPIO3 \ + ESP32_PINMUX(3, ESP_U0RXD_IN, ESP_NOSIG) + +#define UART0_RX_GPIO4 \ + ESP32_PINMUX(4, ESP_U0RXD_IN, ESP_NOSIG) + +#define UART0_RX_GPIO5 \ + ESP32_PINMUX(5, ESP_U0RXD_IN, ESP_NOSIG) + +#define UART0_RX_GPIO6 \ + ESP32_PINMUX(6, ESP_U0RXD_IN, ESP_NOSIG) + +#define UART0_RX_GPIO7 \ + ESP32_PINMUX(7, ESP_U0RXD_IN, ESP_NOSIG) + +#define UART0_RX_GPIO8 \ + ESP32_PINMUX(8, ESP_U0RXD_IN, ESP_NOSIG) + +#define UART0_RX_GPIO9 \ + ESP32_PINMUX(9, ESP_U0RXD_IN, ESP_NOSIG) + +#define UART0_RX_GPIO10 \ + ESP32_PINMUX(10, ESP_U0RXD_IN, ESP_NOSIG) + +#define UART0_RX_GPIO11 \ + ESP32_PINMUX(11, ESP_U0RXD_IN, ESP_NOSIG) + +#define UART0_RX_GPIO12 \ + ESP32_PINMUX(12, ESP_U0RXD_IN, ESP_NOSIG) + +#define UART0_RX_GPIO13 \ + ESP32_PINMUX(13, ESP_U0RXD_IN, ESP_NOSIG) + +#define UART0_RX_GPIO14 \ + ESP32_PINMUX(14, ESP_U0RXD_IN, ESP_NOSIG) + +#define UART0_RX_GPIO15 \ + ESP32_PINMUX(15, ESP_U0RXD_IN, ESP_NOSIG) + +#define UART0_RX_GPIO16 \ + ESP32_PINMUX(16, ESP_U0RXD_IN, ESP_NOSIG) + +#define UART0_RX_GPIO17 \ + ESP32_PINMUX(17, ESP_U0RXD_IN, ESP_NOSIG) + +#define UART0_RX_GPIO18 \ + ESP32_PINMUX(18, ESP_U0RXD_IN, ESP_NOSIG) + +#define UART0_RX_GPIO19 \ + ESP32_PINMUX(19, ESP_U0RXD_IN, ESP_NOSIG) + +#define UART0_RX_GPIO20 \ + ESP32_PINMUX(20, ESP_U0RXD_IN, ESP_NOSIG) + +#define UART0_RX_GPIO21 \ + ESP32_PINMUX(21, ESP_U0RXD_IN, ESP_NOSIG) + +#define UART0_RX_GPIO26 \ + ESP32_PINMUX(26, ESP_U0RXD_IN, ESP_NOSIG) + +#define UART0_RX_GPIO27 \ + ESP32_PINMUX(27, ESP_U0RXD_IN, ESP_NOSIG) + +#define UART0_RX_GPIO28 \ + ESP32_PINMUX(28, ESP_U0RXD_IN, ESP_NOSIG) + +#define UART0_RX_GPIO29 \ + ESP32_PINMUX(29, ESP_U0RXD_IN, ESP_NOSIG) + +#define UART0_RX_GPIO30 \ + ESP32_PINMUX(30, ESP_U0RXD_IN, ESP_NOSIG) + +#define UART0_RX_GPIO31 \ + ESP32_PINMUX(31, ESP_U0RXD_IN, ESP_NOSIG) + +#define UART0_RX_GPIO32 \ + ESP32_PINMUX(32, ESP_U0RXD_IN, ESP_NOSIG) + +#define UART0_RX_GPIO33 \ + ESP32_PINMUX(33, ESP_U0RXD_IN, ESP_NOSIG) + +#define UART0_RX_GPIO34 \ + ESP32_PINMUX(34, ESP_U0RXD_IN, ESP_NOSIG) + +#define UART0_RX_GPIO35 \ + ESP32_PINMUX(35, ESP_U0RXD_IN, ESP_NOSIG) + +#define UART0_RX_GPIO36 \ + ESP32_PINMUX(36, ESP_U0RXD_IN, ESP_NOSIG) + +#define UART0_RX_GPIO37 \ + ESP32_PINMUX(37, ESP_U0RXD_IN, ESP_NOSIG) + +#define UART0_RX_GPIO38 \ + ESP32_PINMUX(38, ESP_U0RXD_IN, ESP_NOSIG) + +#define UART0_RX_GPIO39 \ + ESP32_PINMUX(39, ESP_U0RXD_IN, ESP_NOSIG) + +#define UART0_RX_GPIO40 \ + ESP32_PINMUX(40, ESP_U0RXD_IN, ESP_NOSIG) + +#define UART0_RX_GPIO41 \ + ESP32_PINMUX(41, ESP_U0RXD_IN, ESP_NOSIG) + +#define UART0_RX_GPIO42 \ + ESP32_PINMUX(42, ESP_U0RXD_IN, ESP_NOSIG) + +#define UART0_RX_GPIO43 \ + ESP32_PINMUX(43, ESP_U0RXD_IN, ESP_NOSIG) + +#define UART0_RX_GPIO44 \ + ESP32_PINMUX(44, ESP_U0RXD_IN, ESP_NOSIG) + +#define UART0_RX_GPIO45 \ + ESP32_PINMUX(45, ESP_U0RXD_IN, ESP_NOSIG) + +#define UART0_RX_GPIO46 \ + ESP32_PINMUX(46, ESP_U0RXD_IN, ESP_NOSIG) + +#define UART0_RX_GPIO47 \ + ESP32_PINMUX(47, ESP_U0RXD_IN, ESP_NOSIG) + +#define UART0_RX_GPIO48 \ + ESP32_PINMUX(48, ESP_U0RXD_IN, ESP_NOSIG) + +/* UART0_TX */ +#define UART0_TX_GPIO0 \ + ESP32_PINMUX(0, ESP_NOSIG, ESP_U0TXD_OUT) + +#define UART0_TX_GPIO1 \ + ESP32_PINMUX(1, ESP_NOSIG, ESP_U0TXD_OUT) + +#define UART0_TX_GPIO2 \ + ESP32_PINMUX(2, ESP_NOSIG, ESP_U0TXD_OUT) + +#define UART0_TX_GPIO3 \ + ESP32_PINMUX(3, ESP_NOSIG, ESP_U0TXD_OUT) + +#define UART0_TX_GPIO4 \ + ESP32_PINMUX(4, ESP_NOSIG, ESP_U0TXD_OUT) + +#define UART0_TX_GPIO5 \ + ESP32_PINMUX(5, ESP_NOSIG, ESP_U0TXD_OUT) + +#define UART0_TX_GPIO6 \ + ESP32_PINMUX(6, ESP_NOSIG, ESP_U0TXD_OUT) + +#define UART0_TX_GPIO7 \ + ESP32_PINMUX(7, ESP_NOSIG, ESP_U0TXD_OUT) + +#define UART0_TX_GPIO8 \ + ESP32_PINMUX(8, ESP_NOSIG, ESP_U0TXD_OUT) + +#define UART0_TX_GPIO9 \ + ESP32_PINMUX(9, ESP_NOSIG, ESP_U0TXD_OUT) + +#define UART0_TX_GPIO10 \ + ESP32_PINMUX(10, ESP_NOSIG, ESP_U0TXD_OUT) + +#define UART0_TX_GPIO11 \ + ESP32_PINMUX(11, ESP_NOSIG, ESP_U0TXD_OUT) + +#define UART0_TX_GPIO12 \ + ESP32_PINMUX(12, ESP_NOSIG, ESP_U0TXD_OUT) + +#define UART0_TX_GPIO13 \ + ESP32_PINMUX(13, ESP_NOSIG, ESP_U0TXD_OUT) + +#define UART0_TX_GPIO14 \ + ESP32_PINMUX(14, ESP_NOSIG, ESP_U0TXD_OUT) + +#define UART0_TX_GPIO15 \ + ESP32_PINMUX(15, ESP_NOSIG, ESP_U0TXD_OUT) + +#define UART0_TX_GPIO16 \ + ESP32_PINMUX(16, ESP_NOSIG, ESP_U0TXD_OUT) + +#define UART0_TX_GPIO17 \ + ESP32_PINMUX(17, ESP_NOSIG, ESP_U0TXD_OUT) + +#define UART0_TX_GPIO18 \ + ESP32_PINMUX(18, ESP_NOSIG, ESP_U0TXD_OUT) + +#define UART0_TX_GPIO19 \ + ESP32_PINMUX(19, ESP_NOSIG, ESP_U0TXD_OUT) + +#define UART0_TX_GPIO20 \ + ESP32_PINMUX(20, ESP_NOSIG, ESP_U0TXD_OUT) + +#define UART0_TX_GPIO21 \ + ESP32_PINMUX(21, ESP_NOSIG, ESP_U0TXD_OUT) + +#define UART0_TX_GPIO26 \ + ESP32_PINMUX(26, ESP_NOSIG, ESP_U0TXD_OUT) + +#define UART0_TX_GPIO27 \ + ESP32_PINMUX(27, ESP_NOSIG, ESP_U0TXD_OUT) + +#define UART0_TX_GPIO28 \ + ESP32_PINMUX(28, ESP_NOSIG, ESP_U0TXD_OUT) + +#define UART0_TX_GPIO29 \ + ESP32_PINMUX(29, ESP_NOSIG, ESP_U0TXD_OUT) + +#define UART0_TX_GPIO30 \ + ESP32_PINMUX(30, ESP_NOSIG, ESP_U0TXD_OUT) + +#define UART0_TX_GPIO31 \ + ESP32_PINMUX(31, ESP_NOSIG, ESP_U0TXD_OUT) + +#define UART0_TX_GPIO32 \ + ESP32_PINMUX(32, ESP_NOSIG, ESP_U0TXD_OUT) + +#define UART0_TX_GPIO33 \ + ESP32_PINMUX(33, ESP_NOSIG, ESP_U0TXD_OUT) + +#define UART0_TX_GPIO34 \ + ESP32_PINMUX(34, ESP_NOSIG, ESP_U0TXD_OUT) + +#define UART0_TX_GPIO35 \ + ESP32_PINMUX(35, ESP_NOSIG, ESP_U0TXD_OUT) + +#define UART0_TX_GPIO36 \ + ESP32_PINMUX(36, ESP_NOSIG, ESP_U0TXD_OUT) + +#define UART0_TX_GPIO37 \ + ESP32_PINMUX(37, ESP_NOSIG, ESP_U0TXD_OUT) + +#define UART0_TX_GPIO38 \ + ESP32_PINMUX(38, ESP_NOSIG, ESP_U0TXD_OUT) + +#define UART0_TX_GPIO39 \ + ESP32_PINMUX(39, ESP_NOSIG, ESP_U0TXD_OUT) + +#define UART0_TX_GPIO40 \ + ESP32_PINMUX(40, ESP_NOSIG, ESP_U0TXD_OUT) + +#define UART0_TX_GPIO41 \ + ESP32_PINMUX(41, ESP_NOSIG, ESP_U0TXD_OUT) + +#define UART0_TX_GPIO42 \ + ESP32_PINMUX(42, ESP_NOSIG, ESP_U0TXD_OUT) + +#define UART0_TX_GPIO43 \ + ESP32_PINMUX(43, ESP_NOSIG, ESP_U0TXD_OUT) + +#define UART0_TX_GPIO44 \ + ESP32_PINMUX(44, ESP_NOSIG, ESP_U0TXD_OUT) + +#define UART0_TX_GPIO45 \ + ESP32_PINMUX(45, ESP_NOSIG, ESP_U0TXD_OUT) + +#define UART0_TX_GPIO46 \ + ESP32_PINMUX(46, ESP_NOSIG, ESP_U0TXD_OUT) + +#define UART0_TX_GPIO47 \ + ESP32_PINMUX(47, ESP_NOSIG, ESP_U0TXD_OUT) + +#define UART0_TX_GPIO48 \ + ESP32_PINMUX(48, ESP_NOSIG, ESP_U0TXD_OUT) + +/* UART1_CTS */ +#define UART1_CTS_GPIO0 \ + ESP32_PINMUX(0, ESP_U1CTS_IN, ESP_NOSIG) + +#define UART1_CTS_GPIO1 \ + ESP32_PINMUX(1, ESP_U1CTS_IN, ESP_NOSIG) + +#define UART1_CTS_GPIO2 \ + ESP32_PINMUX(2, ESP_U1CTS_IN, ESP_NOSIG) + +#define UART1_CTS_GPIO3 \ + ESP32_PINMUX(3, ESP_U1CTS_IN, ESP_NOSIG) + +#define UART1_CTS_GPIO4 \ + ESP32_PINMUX(4, ESP_U1CTS_IN, ESP_NOSIG) + +#define UART1_CTS_GPIO5 \ + ESP32_PINMUX(5, ESP_U1CTS_IN, ESP_NOSIG) + +#define UART1_CTS_GPIO6 \ + ESP32_PINMUX(6, ESP_U1CTS_IN, ESP_NOSIG) + +#define UART1_CTS_GPIO7 \ + ESP32_PINMUX(7, ESP_U1CTS_IN, ESP_NOSIG) + +#define UART1_CTS_GPIO8 \ + ESP32_PINMUX(8, ESP_U1CTS_IN, ESP_NOSIG) + +#define UART1_CTS_GPIO9 \ + ESP32_PINMUX(9, ESP_U1CTS_IN, ESP_NOSIG) + +#define UART1_CTS_GPIO10 \ + ESP32_PINMUX(10, ESP_U1CTS_IN, ESP_NOSIG) + +#define UART1_CTS_GPIO11 \ + ESP32_PINMUX(11, ESP_U1CTS_IN, ESP_NOSIG) + +#define UART1_CTS_GPIO12 \ + ESP32_PINMUX(12, ESP_U1CTS_IN, ESP_NOSIG) + +#define UART1_CTS_GPIO13 \ + ESP32_PINMUX(13, ESP_U1CTS_IN, ESP_NOSIG) + +#define UART1_CTS_GPIO14 \ + ESP32_PINMUX(14, ESP_U1CTS_IN, ESP_NOSIG) + +#define UART1_CTS_GPIO15 \ + ESP32_PINMUX(15, ESP_U1CTS_IN, ESP_NOSIG) + +#define UART1_CTS_GPIO16 \ + ESP32_PINMUX(16, ESP_U1CTS_IN, ESP_NOSIG) + +#define UART1_CTS_GPIO17 \ + ESP32_PINMUX(17, ESP_U1CTS_IN, ESP_NOSIG) + +#define UART1_CTS_GPIO18 \ + ESP32_PINMUX(18, ESP_U1CTS_IN, ESP_NOSIG) + +#define UART1_CTS_GPIO19 \ + ESP32_PINMUX(19, ESP_U1CTS_IN, ESP_NOSIG) + +#define UART1_CTS_GPIO20 \ + ESP32_PINMUX(20, ESP_U1CTS_IN, ESP_NOSIG) + +#define UART1_CTS_GPIO21 \ + ESP32_PINMUX(21, ESP_U1CTS_IN, ESP_NOSIG) + +#define UART1_CTS_GPIO26 \ + ESP32_PINMUX(26, ESP_U1CTS_IN, ESP_NOSIG) + +#define UART1_CTS_GPIO27 \ + ESP32_PINMUX(27, ESP_U1CTS_IN, ESP_NOSIG) + +#define UART1_CTS_GPIO28 \ + ESP32_PINMUX(28, ESP_U1CTS_IN, ESP_NOSIG) + +#define UART1_CTS_GPIO29 \ + ESP32_PINMUX(29, ESP_U1CTS_IN, ESP_NOSIG) + +#define UART1_CTS_GPIO30 \ + ESP32_PINMUX(30, ESP_U1CTS_IN, ESP_NOSIG) + +#define UART1_CTS_GPIO31 \ + ESP32_PINMUX(31, ESP_U1CTS_IN, ESP_NOSIG) + +#define UART1_CTS_GPIO32 \ + ESP32_PINMUX(32, ESP_U1CTS_IN, ESP_NOSIG) + +#define UART1_CTS_GPIO33 \ + ESP32_PINMUX(33, ESP_U1CTS_IN, ESP_NOSIG) + +#define UART1_CTS_GPIO34 \ + ESP32_PINMUX(34, ESP_U1CTS_IN, ESP_NOSIG) + +#define UART1_CTS_GPIO35 \ + ESP32_PINMUX(35, ESP_U1CTS_IN, ESP_NOSIG) + +#define UART1_CTS_GPIO36 \ + ESP32_PINMUX(36, ESP_U1CTS_IN, ESP_NOSIG) + +#define UART1_CTS_GPIO37 \ + ESP32_PINMUX(37, ESP_U1CTS_IN, ESP_NOSIG) + +#define UART1_CTS_GPIO38 \ + ESP32_PINMUX(38, ESP_U1CTS_IN, ESP_NOSIG) + +#define UART1_CTS_GPIO39 \ + ESP32_PINMUX(39, ESP_U1CTS_IN, ESP_NOSIG) + +#define UART1_CTS_GPIO40 \ + ESP32_PINMUX(40, ESP_U1CTS_IN, ESP_NOSIG) + +#define UART1_CTS_GPIO41 \ + ESP32_PINMUX(41, ESP_U1CTS_IN, ESP_NOSIG) + +#define UART1_CTS_GPIO42 \ + ESP32_PINMUX(42, ESP_U1CTS_IN, ESP_NOSIG) + +#define UART1_CTS_GPIO43 \ + ESP32_PINMUX(43, ESP_U1CTS_IN, ESP_NOSIG) + +#define UART1_CTS_GPIO44 \ + ESP32_PINMUX(44, ESP_U1CTS_IN, ESP_NOSIG) + +#define UART1_CTS_GPIO45 \ + ESP32_PINMUX(45, ESP_U1CTS_IN, ESP_NOSIG) + +#define UART1_CTS_GPIO46 \ + ESP32_PINMUX(46, ESP_U1CTS_IN, ESP_NOSIG) + +#define UART1_CTS_GPIO47 \ + ESP32_PINMUX(47, ESP_U1CTS_IN, ESP_NOSIG) + +#define UART1_CTS_GPIO48 \ + ESP32_PINMUX(48, ESP_U1CTS_IN, ESP_NOSIG) + +/* UART1_DSR */ +#define UART1_DSR_GPIO0 \ + ESP32_PINMUX(0, ESP_U1DSR_IN, ESP_NOSIG) + +#define UART1_DSR_GPIO1 \ + ESP32_PINMUX(1, ESP_U1DSR_IN, ESP_NOSIG) + +#define UART1_DSR_GPIO2 \ + ESP32_PINMUX(2, ESP_U1DSR_IN, ESP_NOSIG) + +#define UART1_DSR_GPIO3 \ + ESP32_PINMUX(3, ESP_U1DSR_IN, ESP_NOSIG) + +#define UART1_DSR_GPIO4 \ + ESP32_PINMUX(4, ESP_U1DSR_IN, ESP_NOSIG) + +#define UART1_DSR_GPIO5 \ + ESP32_PINMUX(5, ESP_U1DSR_IN, ESP_NOSIG) + +#define UART1_DSR_GPIO6 \ + ESP32_PINMUX(6, ESP_U1DSR_IN, ESP_NOSIG) + +#define UART1_DSR_GPIO7 \ + ESP32_PINMUX(7, ESP_U1DSR_IN, ESP_NOSIG) + +#define UART1_DSR_GPIO8 \ + ESP32_PINMUX(8, ESP_U1DSR_IN, ESP_NOSIG) + +#define UART1_DSR_GPIO9 \ + ESP32_PINMUX(9, ESP_U1DSR_IN, ESP_NOSIG) + +#define UART1_DSR_GPIO10 \ + ESP32_PINMUX(10, ESP_U1DSR_IN, ESP_NOSIG) + +#define UART1_DSR_GPIO11 \ + ESP32_PINMUX(11, ESP_U1DSR_IN, ESP_NOSIG) + +#define UART1_DSR_GPIO12 \ + ESP32_PINMUX(12, ESP_U1DSR_IN, ESP_NOSIG) + +#define UART1_DSR_GPIO13 \ + ESP32_PINMUX(13, ESP_U1DSR_IN, ESP_NOSIG) + +#define UART1_DSR_GPIO14 \ + ESP32_PINMUX(14, ESP_U1DSR_IN, ESP_NOSIG) + +#define UART1_DSR_GPIO15 \ + ESP32_PINMUX(15, ESP_U1DSR_IN, ESP_NOSIG) + +#define UART1_DSR_GPIO16 \ + ESP32_PINMUX(16, ESP_U1DSR_IN, ESP_NOSIG) + +#define UART1_DSR_GPIO17 \ + ESP32_PINMUX(17, ESP_U1DSR_IN, ESP_NOSIG) + +#define UART1_DSR_GPIO18 \ + ESP32_PINMUX(18, ESP_U1DSR_IN, ESP_NOSIG) + +#define UART1_DSR_GPIO19 \ + ESP32_PINMUX(19, ESP_U1DSR_IN, ESP_NOSIG) + +#define UART1_DSR_GPIO20 \ + ESP32_PINMUX(20, ESP_U1DSR_IN, ESP_NOSIG) + +#define UART1_DSR_GPIO21 \ + ESP32_PINMUX(21, ESP_U1DSR_IN, ESP_NOSIG) + +#define UART1_DSR_GPIO26 \ + ESP32_PINMUX(26, ESP_U1DSR_IN, ESP_NOSIG) + +#define UART1_DSR_GPIO27 \ + ESP32_PINMUX(27, ESP_U1DSR_IN, ESP_NOSIG) + +#define UART1_DSR_GPIO28 \ + ESP32_PINMUX(28, ESP_U1DSR_IN, ESP_NOSIG) + +#define UART1_DSR_GPIO29 \ + ESP32_PINMUX(29, ESP_U1DSR_IN, ESP_NOSIG) + +#define UART1_DSR_GPIO30 \ + ESP32_PINMUX(30, ESP_U1DSR_IN, ESP_NOSIG) + +#define UART1_DSR_GPIO31 \ + ESP32_PINMUX(31, ESP_U1DSR_IN, ESP_NOSIG) + +#define UART1_DSR_GPIO32 \ + ESP32_PINMUX(32, ESP_U1DSR_IN, ESP_NOSIG) + +#define UART1_DSR_GPIO33 \ + ESP32_PINMUX(33, ESP_U1DSR_IN, ESP_NOSIG) + +#define UART1_DSR_GPIO34 \ + ESP32_PINMUX(34, ESP_U1DSR_IN, ESP_NOSIG) + +#define UART1_DSR_GPIO35 \ + ESP32_PINMUX(35, ESP_U1DSR_IN, ESP_NOSIG) + +#define UART1_DSR_GPIO36 \ + ESP32_PINMUX(36, ESP_U1DSR_IN, ESP_NOSIG) + +#define UART1_DSR_GPIO37 \ + ESP32_PINMUX(37, ESP_U1DSR_IN, ESP_NOSIG) + +#define UART1_DSR_GPIO38 \ + ESP32_PINMUX(38, ESP_U1DSR_IN, ESP_NOSIG) + +#define UART1_DSR_GPIO39 \ + ESP32_PINMUX(39, ESP_U1DSR_IN, ESP_NOSIG) + +#define UART1_DSR_GPIO40 \ + ESP32_PINMUX(40, ESP_U1DSR_IN, ESP_NOSIG) + +#define UART1_DSR_GPIO41 \ + ESP32_PINMUX(41, ESP_U1DSR_IN, ESP_NOSIG) + +#define UART1_DSR_GPIO42 \ + ESP32_PINMUX(42, ESP_U1DSR_IN, ESP_NOSIG) + +#define UART1_DSR_GPIO43 \ + ESP32_PINMUX(43, ESP_U1DSR_IN, ESP_NOSIG) + +#define UART1_DSR_GPIO44 \ + ESP32_PINMUX(44, ESP_U1DSR_IN, ESP_NOSIG) + +#define UART1_DSR_GPIO45 \ + ESP32_PINMUX(45, ESP_U1DSR_IN, ESP_NOSIG) + +#define UART1_DSR_GPIO46 \ + ESP32_PINMUX(46, ESP_U1DSR_IN, ESP_NOSIG) + +#define UART1_DSR_GPIO47 \ + ESP32_PINMUX(47, ESP_U1DSR_IN, ESP_NOSIG) + +#define UART1_DSR_GPIO48 \ + ESP32_PINMUX(48, ESP_U1DSR_IN, ESP_NOSIG) + +/* UART1_DTR */ +#define UART1_DTR_GPIO0 \ + ESP32_PINMUX(0, ESP_NOSIG, ESP_U1DTR_OUT) + +#define UART1_DTR_GPIO1 \ + ESP32_PINMUX(1, ESP_NOSIG, ESP_U1DTR_OUT) + +#define UART1_DTR_GPIO2 \ + ESP32_PINMUX(2, ESP_NOSIG, ESP_U1DTR_OUT) + +#define UART1_DTR_GPIO3 \ + ESP32_PINMUX(3, ESP_NOSIG, ESP_U1DTR_OUT) + +#define UART1_DTR_GPIO4 \ + ESP32_PINMUX(4, ESP_NOSIG, ESP_U1DTR_OUT) + +#define UART1_DTR_GPIO5 \ + ESP32_PINMUX(5, ESP_NOSIG, ESP_U1DTR_OUT) + +#define UART1_DTR_GPIO6 \ + ESP32_PINMUX(6, ESP_NOSIG, ESP_U1DTR_OUT) + +#define UART1_DTR_GPIO7 \ + ESP32_PINMUX(7, ESP_NOSIG, ESP_U1DTR_OUT) + +#define UART1_DTR_GPIO8 \ + ESP32_PINMUX(8, ESP_NOSIG, ESP_U1DTR_OUT) + +#define UART1_DTR_GPIO9 \ + ESP32_PINMUX(9, ESP_NOSIG, ESP_U1DTR_OUT) + +#define UART1_DTR_GPIO10 \ + ESP32_PINMUX(10, ESP_NOSIG, ESP_U1DTR_OUT) + +#define UART1_DTR_GPIO11 \ + ESP32_PINMUX(11, ESP_NOSIG, ESP_U1DTR_OUT) + +#define UART1_DTR_GPIO12 \ + ESP32_PINMUX(12, ESP_NOSIG, ESP_U1DTR_OUT) + +#define UART1_DTR_GPIO13 \ + ESP32_PINMUX(13, ESP_NOSIG, ESP_U1DTR_OUT) + +#define UART1_DTR_GPIO14 \ + ESP32_PINMUX(14, ESP_NOSIG, ESP_U1DTR_OUT) + +#define UART1_DTR_GPIO15 \ + ESP32_PINMUX(15, ESP_NOSIG, ESP_U1DTR_OUT) + +#define UART1_DTR_GPIO16 \ + ESP32_PINMUX(16, ESP_NOSIG, ESP_U1DTR_OUT) + +#define UART1_DTR_GPIO17 \ + ESP32_PINMUX(17, ESP_NOSIG, ESP_U1DTR_OUT) + +#define UART1_DTR_GPIO18 \ + ESP32_PINMUX(18, ESP_NOSIG, ESP_U1DTR_OUT) + +#define UART1_DTR_GPIO19 \ + ESP32_PINMUX(19, ESP_NOSIG, ESP_U1DTR_OUT) + +#define UART1_DTR_GPIO20 \ + ESP32_PINMUX(20, ESP_NOSIG, ESP_U1DTR_OUT) + +#define UART1_DTR_GPIO21 \ + ESP32_PINMUX(21, ESP_NOSIG, ESP_U1DTR_OUT) + +#define UART1_DTR_GPIO26 \ + ESP32_PINMUX(26, ESP_NOSIG, ESP_U1DTR_OUT) + +#define UART1_DTR_GPIO27 \ + ESP32_PINMUX(27, ESP_NOSIG, ESP_U1DTR_OUT) + +#define UART1_DTR_GPIO28 \ + ESP32_PINMUX(28, ESP_NOSIG, ESP_U1DTR_OUT) + +#define UART1_DTR_GPIO29 \ + ESP32_PINMUX(29, ESP_NOSIG, ESP_U1DTR_OUT) + +#define UART1_DTR_GPIO30 \ + ESP32_PINMUX(30, ESP_NOSIG, ESP_U1DTR_OUT) + +#define UART1_DTR_GPIO31 \ + ESP32_PINMUX(31, ESP_NOSIG, ESP_U1DTR_OUT) + +#define UART1_DTR_GPIO32 \ + ESP32_PINMUX(32, ESP_NOSIG, ESP_U1DTR_OUT) + +#define UART1_DTR_GPIO33 \ + ESP32_PINMUX(33, ESP_NOSIG, ESP_U1DTR_OUT) + +#define UART1_DTR_GPIO34 \ + ESP32_PINMUX(34, ESP_NOSIG, ESP_U1DTR_OUT) + +#define UART1_DTR_GPIO35 \ + ESP32_PINMUX(35, ESP_NOSIG, ESP_U1DTR_OUT) + +#define UART1_DTR_GPIO36 \ + ESP32_PINMUX(36, ESP_NOSIG, ESP_U1DTR_OUT) + +#define UART1_DTR_GPIO37 \ + ESP32_PINMUX(37, ESP_NOSIG, ESP_U1DTR_OUT) + +#define UART1_DTR_GPIO38 \ + ESP32_PINMUX(38, ESP_NOSIG, ESP_U1DTR_OUT) + +#define UART1_DTR_GPIO39 \ + ESP32_PINMUX(39, ESP_NOSIG, ESP_U1DTR_OUT) + +#define UART1_DTR_GPIO40 \ + ESP32_PINMUX(40, ESP_NOSIG, ESP_U1DTR_OUT) + +#define UART1_DTR_GPIO41 \ + ESP32_PINMUX(41, ESP_NOSIG, ESP_U1DTR_OUT) + +#define UART1_DTR_GPIO42 \ + ESP32_PINMUX(42, ESP_NOSIG, ESP_U1DTR_OUT) + +#define UART1_DTR_GPIO43 \ + ESP32_PINMUX(43, ESP_NOSIG, ESP_U1DTR_OUT) + +#define UART1_DTR_GPIO44 \ + ESP32_PINMUX(44, ESP_NOSIG, ESP_U1DTR_OUT) + +#define UART1_DTR_GPIO45 \ + ESP32_PINMUX(45, ESP_NOSIG, ESP_U1DTR_OUT) + +#define UART1_DTR_GPIO46 \ + ESP32_PINMUX(46, ESP_NOSIG, ESP_U1DTR_OUT) + +#define UART1_DTR_GPIO47 \ + ESP32_PINMUX(47, ESP_NOSIG, ESP_U1DTR_OUT) + +#define UART1_DTR_GPIO48 \ + ESP32_PINMUX(48, ESP_NOSIG, ESP_U1DTR_OUT) + +/* UART1_RTS */ +#define UART1_RTS_GPIO0 \ + ESP32_PINMUX(0, ESP_NOSIG, ESP_U1RTS_OUT) + +#define UART1_RTS_GPIO1 \ + ESP32_PINMUX(1, ESP_NOSIG, ESP_U1RTS_OUT) + +#define UART1_RTS_GPIO2 \ + ESP32_PINMUX(2, ESP_NOSIG, ESP_U1RTS_OUT) + +#define UART1_RTS_GPIO3 \ + ESP32_PINMUX(3, ESP_NOSIG, ESP_U1RTS_OUT) + +#define UART1_RTS_GPIO4 \ + ESP32_PINMUX(4, ESP_NOSIG, ESP_U1RTS_OUT) + +#define UART1_RTS_GPIO5 \ + ESP32_PINMUX(5, ESP_NOSIG, ESP_U1RTS_OUT) + +#define UART1_RTS_GPIO6 \ + ESP32_PINMUX(6, ESP_NOSIG, ESP_U1RTS_OUT) + +#define UART1_RTS_GPIO7 \ + ESP32_PINMUX(7, ESP_NOSIG, ESP_U1RTS_OUT) + +#define UART1_RTS_GPIO8 \ + ESP32_PINMUX(8, ESP_NOSIG, ESP_U1RTS_OUT) + +#define UART1_RTS_GPIO9 \ + ESP32_PINMUX(9, ESP_NOSIG, ESP_U1RTS_OUT) + +#define UART1_RTS_GPIO10 \ + ESP32_PINMUX(10, ESP_NOSIG, ESP_U1RTS_OUT) + +#define UART1_RTS_GPIO11 \ + ESP32_PINMUX(11, ESP_NOSIG, ESP_U1RTS_OUT) + +#define UART1_RTS_GPIO12 \ + ESP32_PINMUX(12, ESP_NOSIG, ESP_U1RTS_OUT) + +#define UART1_RTS_GPIO13 \ + ESP32_PINMUX(13, ESP_NOSIG, ESP_U1RTS_OUT) + +#define UART1_RTS_GPIO14 \ + ESP32_PINMUX(14, ESP_NOSIG, ESP_U1RTS_OUT) + +#define UART1_RTS_GPIO15 \ + ESP32_PINMUX(15, ESP_NOSIG, ESP_U1RTS_OUT) + +#define UART1_RTS_GPIO16 \ + ESP32_PINMUX(16, ESP_NOSIG, ESP_U1RTS_OUT) + +#define UART1_RTS_GPIO17 \ + ESP32_PINMUX(17, ESP_NOSIG, ESP_U1RTS_OUT) + +#define UART1_RTS_GPIO18 \ + ESP32_PINMUX(18, ESP_NOSIG, ESP_U1RTS_OUT) + +#define UART1_RTS_GPIO19 \ + ESP32_PINMUX(19, ESP_NOSIG, ESP_U1RTS_OUT) + +#define UART1_RTS_GPIO20 \ + ESP32_PINMUX(20, ESP_NOSIG, ESP_U1RTS_OUT) + +#define UART1_RTS_GPIO21 \ + ESP32_PINMUX(21, ESP_NOSIG, ESP_U1RTS_OUT) + +#define UART1_RTS_GPIO26 \ + ESP32_PINMUX(26, ESP_NOSIG, ESP_U1RTS_OUT) + +#define UART1_RTS_GPIO27 \ + ESP32_PINMUX(27, ESP_NOSIG, ESP_U1RTS_OUT) + +#define UART1_RTS_GPIO28 \ + ESP32_PINMUX(28, ESP_NOSIG, ESP_U1RTS_OUT) + +#define UART1_RTS_GPIO29 \ + ESP32_PINMUX(29, ESP_NOSIG, ESP_U1RTS_OUT) + +#define UART1_RTS_GPIO30 \ + ESP32_PINMUX(30, ESP_NOSIG, ESP_U1RTS_OUT) + +#define UART1_RTS_GPIO31 \ + ESP32_PINMUX(31, ESP_NOSIG, ESP_U1RTS_OUT) + +#define UART1_RTS_GPIO32 \ + ESP32_PINMUX(32, ESP_NOSIG, ESP_U1RTS_OUT) + +#define UART1_RTS_GPIO33 \ + ESP32_PINMUX(33, ESP_NOSIG, ESP_U1RTS_OUT) + +#define UART1_RTS_GPIO34 \ + ESP32_PINMUX(34, ESP_NOSIG, ESP_U1RTS_OUT) + +#define UART1_RTS_GPIO35 \ + ESP32_PINMUX(35, ESP_NOSIG, ESP_U1RTS_OUT) + +#define UART1_RTS_GPIO36 \ + ESP32_PINMUX(36, ESP_NOSIG, ESP_U1RTS_OUT) + +#define UART1_RTS_GPIO37 \ + ESP32_PINMUX(37, ESP_NOSIG, ESP_U1RTS_OUT) + +#define UART1_RTS_GPIO38 \ + ESP32_PINMUX(38, ESP_NOSIG, ESP_U1RTS_OUT) + +#define UART1_RTS_GPIO39 \ + ESP32_PINMUX(39, ESP_NOSIG, ESP_U1RTS_OUT) + +#define UART1_RTS_GPIO40 \ + ESP32_PINMUX(40, ESP_NOSIG, ESP_U1RTS_OUT) + +#define UART1_RTS_GPIO41 \ + ESP32_PINMUX(41, ESP_NOSIG, ESP_U1RTS_OUT) + +#define UART1_RTS_GPIO42 \ + ESP32_PINMUX(42, ESP_NOSIG, ESP_U1RTS_OUT) + +#define UART1_RTS_GPIO43 \ + ESP32_PINMUX(43, ESP_NOSIG, ESP_U1RTS_OUT) + +#define UART1_RTS_GPIO44 \ + ESP32_PINMUX(44, ESP_NOSIG, ESP_U1RTS_OUT) + +#define UART1_RTS_GPIO45 \ + ESP32_PINMUX(45, ESP_NOSIG, ESP_U1RTS_OUT) + +#define UART1_RTS_GPIO46 \ + ESP32_PINMUX(46, ESP_NOSIG, ESP_U1RTS_OUT) + +#define UART1_RTS_GPIO47 \ + ESP32_PINMUX(47, ESP_NOSIG, ESP_U1RTS_OUT) + +#define UART1_RTS_GPIO48 \ + ESP32_PINMUX(48, ESP_NOSIG, ESP_U1RTS_OUT) + +/* UART1_RX */ +#define UART1_RX_GPIO0 \ + ESP32_PINMUX(0, ESP_U1RXD_IN, ESP_NOSIG) + +#define UART1_RX_GPIO1 \ + ESP32_PINMUX(1, ESP_U1RXD_IN, ESP_NOSIG) + +#define UART1_RX_GPIO2 \ + ESP32_PINMUX(2, ESP_U1RXD_IN, ESP_NOSIG) + +#define UART1_RX_GPIO3 \ + ESP32_PINMUX(3, ESP_U1RXD_IN, ESP_NOSIG) + +#define UART1_RX_GPIO4 \ + ESP32_PINMUX(4, ESP_U1RXD_IN, ESP_NOSIG) + +#define UART1_RX_GPIO5 \ + ESP32_PINMUX(5, ESP_U1RXD_IN, ESP_NOSIG) + +#define UART1_RX_GPIO6 \ + ESP32_PINMUX(6, ESP_U1RXD_IN, ESP_NOSIG) + +#define UART1_RX_GPIO7 \ + ESP32_PINMUX(7, ESP_U1RXD_IN, ESP_NOSIG) + +#define UART1_RX_GPIO8 \ + ESP32_PINMUX(8, ESP_U1RXD_IN, ESP_NOSIG) + +#define UART1_RX_GPIO9 \ + ESP32_PINMUX(9, ESP_U1RXD_IN, ESP_NOSIG) + +#define UART1_RX_GPIO10 \ + ESP32_PINMUX(10, ESP_U1RXD_IN, ESP_NOSIG) + +#define UART1_RX_GPIO11 \ + ESP32_PINMUX(11, ESP_U1RXD_IN, ESP_NOSIG) + +#define UART1_RX_GPIO12 \ + ESP32_PINMUX(12, ESP_U1RXD_IN, ESP_NOSIG) + +#define UART1_RX_GPIO13 \ + ESP32_PINMUX(13, ESP_U1RXD_IN, ESP_NOSIG) + +#define UART1_RX_GPIO14 \ + ESP32_PINMUX(14, ESP_U1RXD_IN, ESP_NOSIG) + +#define UART1_RX_GPIO15 \ + ESP32_PINMUX(15, ESP_U1RXD_IN, ESP_NOSIG) + +#define UART1_RX_GPIO16 \ + ESP32_PINMUX(16, ESP_U1RXD_IN, ESP_NOSIG) + +#define UART1_RX_GPIO17 \ + ESP32_PINMUX(17, ESP_U1RXD_IN, ESP_NOSIG) + +#define UART1_RX_GPIO18 \ + ESP32_PINMUX(18, ESP_U1RXD_IN, ESP_NOSIG) + +#define UART1_RX_GPIO19 \ + ESP32_PINMUX(19, ESP_U1RXD_IN, ESP_NOSIG) + +#define UART1_RX_GPIO20 \ + ESP32_PINMUX(20, ESP_U1RXD_IN, ESP_NOSIG) + +#define UART1_RX_GPIO21 \ + ESP32_PINMUX(21, ESP_U1RXD_IN, ESP_NOSIG) + +#define UART1_RX_GPIO26 \ + ESP32_PINMUX(26, ESP_U1RXD_IN, ESP_NOSIG) + +#define UART1_RX_GPIO27 \ + ESP32_PINMUX(27, ESP_U1RXD_IN, ESP_NOSIG) + +#define UART1_RX_GPIO28 \ + ESP32_PINMUX(28, ESP_U1RXD_IN, ESP_NOSIG) + +#define UART1_RX_GPIO29 \ + ESP32_PINMUX(29, ESP_U1RXD_IN, ESP_NOSIG) + +#define UART1_RX_GPIO30 \ + ESP32_PINMUX(30, ESP_U1RXD_IN, ESP_NOSIG) + +#define UART1_RX_GPIO31 \ + ESP32_PINMUX(31, ESP_U1RXD_IN, ESP_NOSIG) + +#define UART1_RX_GPIO32 \ + ESP32_PINMUX(32, ESP_U1RXD_IN, ESP_NOSIG) + +#define UART1_RX_GPIO33 \ + ESP32_PINMUX(33, ESP_U1RXD_IN, ESP_NOSIG) + +#define UART1_RX_GPIO34 \ + ESP32_PINMUX(34, ESP_U1RXD_IN, ESP_NOSIG) + +#define UART1_RX_GPIO35 \ + ESP32_PINMUX(35, ESP_U1RXD_IN, ESP_NOSIG) + +#define UART1_RX_GPIO36 \ + ESP32_PINMUX(36, ESP_U1RXD_IN, ESP_NOSIG) + +#define UART1_RX_GPIO37 \ + ESP32_PINMUX(37, ESP_U1RXD_IN, ESP_NOSIG) + +#define UART1_RX_GPIO38 \ + ESP32_PINMUX(38, ESP_U1RXD_IN, ESP_NOSIG) + +#define UART1_RX_GPIO39 \ + ESP32_PINMUX(39, ESP_U1RXD_IN, ESP_NOSIG) + +#define UART1_RX_GPIO40 \ + ESP32_PINMUX(40, ESP_U1RXD_IN, ESP_NOSIG) + +#define UART1_RX_GPIO41 \ + ESP32_PINMUX(41, ESP_U1RXD_IN, ESP_NOSIG) + +#define UART1_RX_GPIO42 \ + ESP32_PINMUX(42, ESP_U1RXD_IN, ESP_NOSIG) + +#define UART1_RX_GPIO43 \ + ESP32_PINMUX(43, ESP_U1RXD_IN, ESP_NOSIG) + +#define UART1_RX_GPIO44 \ + ESP32_PINMUX(44, ESP_U1RXD_IN, ESP_NOSIG) + +#define UART1_RX_GPIO45 \ + ESP32_PINMUX(45, ESP_U1RXD_IN, ESP_NOSIG) + +#define UART1_RX_GPIO46 \ + ESP32_PINMUX(46, ESP_U1RXD_IN, ESP_NOSIG) + +#define UART1_RX_GPIO47 \ + ESP32_PINMUX(47, ESP_U1RXD_IN, ESP_NOSIG) + +#define UART1_RX_GPIO48 \ + ESP32_PINMUX(48, ESP_U1RXD_IN, ESP_NOSIG) + +/* UART1_TX */ +#define UART1_TX_GPIO0 \ + ESP32_PINMUX(0, ESP_NOSIG, ESP_U1TXD_OUT) + +#define UART1_TX_GPIO1 \ + ESP32_PINMUX(1, ESP_NOSIG, ESP_U1TXD_OUT) + +#define UART1_TX_GPIO2 \ + ESP32_PINMUX(2, ESP_NOSIG, ESP_U1TXD_OUT) + +#define UART1_TX_GPIO3 \ + ESP32_PINMUX(3, ESP_NOSIG, ESP_U1TXD_OUT) + +#define UART1_TX_GPIO4 \ + ESP32_PINMUX(4, ESP_NOSIG, ESP_U1TXD_OUT) + +#define UART1_TX_GPIO5 \ + ESP32_PINMUX(5, ESP_NOSIG, ESP_U1TXD_OUT) + +#define UART1_TX_GPIO6 \ + ESP32_PINMUX(6, ESP_NOSIG, ESP_U1TXD_OUT) + +#define UART1_TX_GPIO7 \ + ESP32_PINMUX(7, ESP_NOSIG, ESP_U1TXD_OUT) + +#define UART1_TX_GPIO8 \ + ESP32_PINMUX(8, ESP_NOSIG, ESP_U1TXD_OUT) + +#define UART1_TX_GPIO9 \ + ESP32_PINMUX(9, ESP_NOSIG, ESP_U1TXD_OUT) + +#define UART1_TX_GPIO10 \ + ESP32_PINMUX(10, ESP_NOSIG, ESP_U1TXD_OUT) + +#define UART1_TX_GPIO11 \ + ESP32_PINMUX(11, ESP_NOSIG, ESP_U1TXD_OUT) + +#define UART1_TX_GPIO12 \ + ESP32_PINMUX(12, ESP_NOSIG, ESP_U1TXD_OUT) + +#define UART1_TX_GPIO13 \ + ESP32_PINMUX(13, ESP_NOSIG, ESP_U1TXD_OUT) + +#define UART1_TX_GPIO14 \ + ESP32_PINMUX(14, ESP_NOSIG, ESP_U1TXD_OUT) + +#define UART1_TX_GPIO15 \ + ESP32_PINMUX(15, ESP_NOSIG, ESP_U1TXD_OUT) + +#define UART1_TX_GPIO16 \ + ESP32_PINMUX(16, ESP_NOSIG, ESP_U1TXD_OUT) + +#define UART1_TX_GPIO17 \ + ESP32_PINMUX(17, ESP_NOSIG, ESP_U1TXD_OUT) + +#define UART1_TX_GPIO18 \ + ESP32_PINMUX(18, ESP_NOSIG, ESP_U1TXD_OUT) + +#define UART1_TX_GPIO19 \ + ESP32_PINMUX(19, ESP_NOSIG, ESP_U1TXD_OUT) + +#define UART1_TX_GPIO20 \ + ESP32_PINMUX(20, ESP_NOSIG, ESP_U1TXD_OUT) + +#define UART1_TX_GPIO21 \ + ESP32_PINMUX(21, ESP_NOSIG, ESP_U1TXD_OUT) + +#define UART1_TX_GPIO26 \ + ESP32_PINMUX(26, ESP_NOSIG, ESP_U1TXD_OUT) + +#define UART1_TX_GPIO27 \ + ESP32_PINMUX(27, ESP_NOSIG, ESP_U1TXD_OUT) + +#define UART1_TX_GPIO28 \ + ESP32_PINMUX(28, ESP_NOSIG, ESP_U1TXD_OUT) + +#define UART1_TX_GPIO29 \ + ESP32_PINMUX(29, ESP_NOSIG, ESP_U1TXD_OUT) + +#define UART1_TX_GPIO30 \ + ESP32_PINMUX(30, ESP_NOSIG, ESP_U1TXD_OUT) + +#define UART1_TX_GPIO31 \ + ESP32_PINMUX(31, ESP_NOSIG, ESP_U1TXD_OUT) + +#define UART1_TX_GPIO32 \ + ESP32_PINMUX(32, ESP_NOSIG, ESP_U1TXD_OUT) + +#define UART1_TX_GPIO33 \ + ESP32_PINMUX(33, ESP_NOSIG, ESP_U1TXD_OUT) + +#define UART1_TX_GPIO34 \ + ESP32_PINMUX(34, ESP_NOSIG, ESP_U1TXD_OUT) + +#define UART1_TX_GPIO35 \ + ESP32_PINMUX(35, ESP_NOSIG, ESP_U1TXD_OUT) + +#define UART1_TX_GPIO36 \ + ESP32_PINMUX(36, ESP_NOSIG, ESP_U1TXD_OUT) + +#define UART1_TX_GPIO37 \ + ESP32_PINMUX(37, ESP_NOSIG, ESP_U1TXD_OUT) + +#define UART1_TX_GPIO38 \ + ESP32_PINMUX(38, ESP_NOSIG, ESP_U1TXD_OUT) + +#define UART1_TX_GPIO39 \ + ESP32_PINMUX(39, ESP_NOSIG, ESP_U1TXD_OUT) + +#define UART1_TX_GPIO40 \ + ESP32_PINMUX(40, ESP_NOSIG, ESP_U1TXD_OUT) + +#define UART1_TX_GPIO41 \ + ESP32_PINMUX(41, ESP_NOSIG, ESP_U1TXD_OUT) + +#define UART1_TX_GPIO42 \ + ESP32_PINMUX(42, ESP_NOSIG, ESP_U1TXD_OUT) + +#define UART1_TX_GPIO43 \ + ESP32_PINMUX(43, ESP_NOSIG, ESP_U1TXD_OUT) + +#define UART1_TX_GPIO44 \ + ESP32_PINMUX(44, ESP_NOSIG, ESP_U1TXD_OUT) + +#define UART1_TX_GPIO45 \ + ESP32_PINMUX(45, ESP_NOSIG, ESP_U1TXD_OUT) + +#define UART1_TX_GPIO46 \ + ESP32_PINMUX(46, ESP_NOSIG, ESP_U1TXD_OUT) + +#define UART1_TX_GPIO47 \ + ESP32_PINMUX(47, ESP_NOSIG, ESP_U1TXD_OUT) + +#define UART1_TX_GPIO48 \ + ESP32_PINMUX(48, ESP_NOSIG, ESP_U1TXD_OUT) + +/* UART2_CTS */ +#define UART2_CTS_GPIO0 \ + ESP32_PINMUX(0, ESP_U2CTS_IN, ESP_NOSIG) + +#define UART2_CTS_GPIO1 \ + ESP32_PINMUX(1, ESP_U2CTS_IN, ESP_NOSIG) + +#define UART2_CTS_GPIO2 \ + ESP32_PINMUX(2, ESP_U2CTS_IN, ESP_NOSIG) + +#define UART2_CTS_GPIO3 \ + ESP32_PINMUX(3, ESP_U2CTS_IN, ESP_NOSIG) + +#define UART2_CTS_GPIO4 \ + ESP32_PINMUX(4, ESP_U2CTS_IN, ESP_NOSIG) + +#define UART2_CTS_GPIO5 \ + ESP32_PINMUX(5, ESP_U2CTS_IN, ESP_NOSIG) + +#define UART2_CTS_GPIO6 \ + ESP32_PINMUX(6, ESP_U2CTS_IN, ESP_NOSIG) + +#define UART2_CTS_GPIO7 \ + ESP32_PINMUX(7, ESP_U2CTS_IN, ESP_NOSIG) + +#define UART2_CTS_GPIO8 \ + ESP32_PINMUX(8, ESP_U2CTS_IN, ESP_NOSIG) + +#define UART2_CTS_GPIO9 \ + ESP32_PINMUX(9, ESP_U2CTS_IN, ESP_NOSIG) + +#define UART2_CTS_GPIO10 \ + ESP32_PINMUX(10, ESP_U2CTS_IN, ESP_NOSIG) + +#define UART2_CTS_GPIO11 \ + ESP32_PINMUX(11, ESP_U2CTS_IN, ESP_NOSIG) + +#define UART2_CTS_GPIO12 \ + ESP32_PINMUX(12, ESP_U2CTS_IN, ESP_NOSIG) + +#define UART2_CTS_GPIO13 \ + ESP32_PINMUX(13, ESP_U2CTS_IN, ESP_NOSIG) + +#define UART2_CTS_GPIO14 \ + ESP32_PINMUX(14, ESP_U2CTS_IN, ESP_NOSIG) + +#define UART2_CTS_GPIO15 \ + ESP32_PINMUX(15, ESP_U2CTS_IN, ESP_NOSIG) + +#define UART2_CTS_GPIO16 \ + ESP32_PINMUX(16, ESP_U2CTS_IN, ESP_NOSIG) + +#define UART2_CTS_GPIO17 \ + ESP32_PINMUX(17, ESP_U2CTS_IN, ESP_NOSIG) + +#define UART2_CTS_GPIO18 \ + ESP32_PINMUX(18, ESP_U2CTS_IN, ESP_NOSIG) + +#define UART2_CTS_GPIO19 \ + ESP32_PINMUX(19, ESP_U2CTS_IN, ESP_NOSIG) + +#define UART2_CTS_GPIO20 \ + ESP32_PINMUX(20, ESP_U2CTS_IN, ESP_NOSIG) + +#define UART2_CTS_GPIO21 \ + ESP32_PINMUX(21, ESP_U2CTS_IN, ESP_NOSIG) + +#define UART2_CTS_GPIO26 \ + ESP32_PINMUX(26, ESP_U2CTS_IN, ESP_NOSIG) + +#define UART2_CTS_GPIO27 \ + ESP32_PINMUX(27, ESP_U2CTS_IN, ESP_NOSIG) + +#define UART2_CTS_GPIO28 \ + ESP32_PINMUX(28, ESP_U2CTS_IN, ESP_NOSIG) + +#define UART2_CTS_GPIO29 \ + ESP32_PINMUX(29, ESP_U2CTS_IN, ESP_NOSIG) + +#define UART2_CTS_GPIO30 \ + ESP32_PINMUX(30, ESP_U2CTS_IN, ESP_NOSIG) + +#define UART2_CTS_GPIO31 \ + ESP32_PINMUX(31, ESP_U2CTS_IN, ESP_NOSIG) + +#define UART2_CTS_GPIO32 \ + ESP32_PINMUX(32, ESP_U2CTS_IN, ESP_NOSIG) + +#define UART2_CTS_GPIO33 \ + ESP32_PINMUX(33, ESP_U2CTS_IN, ESP_NOSIG) + +#define UART2_CTS_GPIO34 \ + ESP32_PINMUX(34, ESP_U2CTS_IN, ESP_NOSIG) + +#define UART2_CTS_GPIO35 \ + ESP32_PINMUX(35, ESP_U2CTS_IN, ESP_NOSIG) + +#define UART2_CTS_GPIO36 \ + ESP32_PINMUX(36, ESP_U2CTS_IN, ESP_NOSIG) + +#define UART2_CTS_GPIO37 \ + ESP32_PINMUX(37, ESP_U2CTS_IN, ESP_NOSIG) + +#define UART2_CTS_GPIO38 \ + ESP32_PINMUX(38, ESP_U2CTS_IN, ESP_NOSIG) + +#define UART2_CTS_GPIO39 \ + ESP32_PINMUX(39, ESP_U2CTS_IN, ESP_NOSIG) + +#define UART2_CTS_GPIO40 \ + ESP32_PINMUX(40, ESP_U2CTS_IN, ESP_NOSIG) + +#define UART2_CTS_GPIO41 \ + ESP32_PINMUX(41, ESP_U2CTS_IN, ESP_NOSIG) + +#define UART2_CTS_GPIO42 \ + ESP32_PINMUX(42, ESP_U2CTS_IN, ESP_NOSIG) + +#define UART2_CTS_GPIO43 \ + ESP32_PINMUX(43, ESP_U2CTS_IN, ESP_NOSIG) + +#define UART2_CTS_GPIO44 \ + ESP32_PINMUX(44, ESP_U2CTS_IN, ESP_NOSIG) + +#define UART2_CTS_GPIO45 \ + ESP32_PINMUX(45, ESP_U2CTS_IN, ESP_NOSIG) + +#define UART2_CTS_GPIO46 \ + ESP32_PINMUX(46, ESP_U2CTS_IN, ESP_NOSIG) + +#define UART2_CTS_GPIO47 \ + ESP32_PINMUX(47, ESP_U2CTS_IN, ESP_NOSIG) + +#define UART2_CTS_GPIO48 \ + ESP32_PINMUX(48, ESP_U2CTS_IN, ESP_NOSIG) + +/* UART2_RTS */ +#define UART2_RTS_GPIO0 \ + ESP32_PINMUX(0, ESP_NOSIG, ESP_U2RTS_OUT) + +#define UART2_RTS_GPIO1 \ + ESP32_PINMUX(1, ESP_NOSIG, ESP_U2RTS_OUT) + +#define UART2_RTS_GPIO2 \ + ESP32_PINMUX(2, ESP_NOSIG, ESP_U2RTS_OUT) + +#define UART2_RTS_GPIO3 \ + ESP32_PINMUX(3, ESP_NOSIG, ESP_U2RTS_OUT) + +#define UART2_RTS_GPIO4 \ + ESP32_PINMUX(4, ESP_NOSIG, ESP_U2RTS_OUT) + +#define UART2_RTS_GPIO5 \ + ESP32_PINMUX(5, ESP_NOSIG, ESP_U2RTS_OUT) + +#define UART2_RTS_GPIO6 \ + ESP32_PINMUX(6, ESP_NOSIG, ESP_U2RTS_OUT) + +#define UART2_RTS_GPIO7 \ + ESP32_PINMUX(7, ESP_NOSIG, ESP_U2RTS_OUT) + +#define UART2_RTS_GPIO8 \ + ESP32_PINMUX(8, ESP_NOSIG, ESP_U2RTS_OUT) + +#define UART2_RTS_GPIO9 \ + ESP32_PINMUX(9, ESP_NOSIG, ESP_U2RTS_OUT) + +#define UART2_RTS_GPIO10 \ + ESP32_PINMUX(10, ESP_NOSIG, ESP_U2RTS_OUT) + +#define UART2_RTS_GPIO11 \ + ESP32_PINMUX(11, ESP_NOSIG, ESP_U2RTS_OUT) + +#define UART2_RTS_GPIO12 \ + ESP32_PINMUX(12, ESP_NOSIG, ESP_U2RTS_OUT) + +#define UART2_RTS_GPIO13 \ + ESP32_PINMUX(13, ESP_NOSIG, ESP_U2RTS_OUT) + +#define UART2_RTS_GPIO14 \ + ESP32_PINMUX(14, ESP_NOSIG, ESP_U2RTS_OUT) + +#define UART2_RTS_GPIO15 \ + ESP32_PINMUX(15, ESP_NOSIG, ESP_U2RTS_OUT) + +#define UART2_RTS_GPIO16 \ + ESP32_PINMUX(16, ESP_NOSIG, ESP_U2RTS_OUT) + +#define UART2_RTS_GPIO17 \ + ESP32_PINMUX(17, ESP_NOSIG, ESP_U2RTS_OUT) + +#define UART2_RTS_GPIO18 \ + ESP32_PINMUX(18, ESP_NOSIG, ESP_U2RTS_OUT) + +#define UART2_RTS_GPIO19 \ + ESP32_PINMUX(19, ESP_NOSIG, ESP_U2RTS_OUT) + +#define UART2_RTS_GPIO20 \ + ESP32_PINMUX(20, ESP_NOSIG, ESP_U2RTS_OUT) + +#define UART2_RTS_GPIO21 \ + ESP32_PINMUX(21, ESP_NOSIG, ESP_U2RTS_OUT) + +#define UART2_RTS_GPIO26 \ + ESP32_PINMUX(26, ESP_NOSIG, ESP_U2RTS_OUT) + +#define UART2_RTS_GPIO27 \ + ESP32_PINMUX(27, ESP_NOSIG, ESP_U2RTS_OUT) + +#define UART2_RTS_GPIO28 \ + ESP32_PINMUX(28, ESP_NOSIG, ESP_U2RTS_OUT) + +#define UART2_RTS_GPIO29 \ + ESP32_PINMUX(29, ESP_NOSIG, ESP_U2RTS_OUT) + +#define UART2_RTS_GPIO30 \ + ESP32_PINMUX(30, ESP_NOSIG, ESP_U2RTS_OUT) + +#define UART2_RTS_GPIO31 \ + ESP32_PINMUX(31, ESP_NOSIG, ESP_U2RTS_OUT) + +#define UART2_RTS_GPIO32 \ + ESP32_PINMUX(32, ESP_NOSIG, ESP_U2RTS_OUT) + +#define UART2_RTS_GPIO33 \ + ESP32_PINMUX(33, ESP_NOSIG, ESP_U2RTS_OUT) + +#define UART2_RTS_GPIO34 \ + ESP32_PINMUX(34, ESP_NOSIG, ESP_U2RTS_OUT) + +#define UART2_RTS_GPIO35 \ + ESP32_PINMUX(35, ESP_NOSIG, ESP_U2RTS_OUT) + +#define UART2_RTS_GPIO36 \ + ESP32_PINMUX(36, ESP_NOSIG, ESP_U2RTS_OUT) + +#define UART2_RTS_GPIO37 \ + ESP32_PINMUX(37, ESP_NOSIG, ESP_U2RTS_OUT) + +#define UART2_RTS_GPIO38 \ + ESP32_PINMUX(38, ESP_NOSIG, ESP_U2RTS_OUT) + +#define UART2_RTS_GPIO39 \ + ESP32_PINMUX(39, ESP_NOSIG, ESP_U2RTS_OUT) + +#define UART2_RTS_GPIO40 \ + ESP32_PINMUX(40, ESP_NOSIG, ESP_U2RTS_OUT) + +#define UART2_RTS_GPIO41 \ + ESP32_PINMUX(41, ESP_NOSIG, ESP_U2RTS_OUT) + +#define UART2_RTS_GPIO42 \ + ESP32_PINMUX(42, ESP_NOSIG, ESP_U2RTS_OUT) + +#define UART2_RTS_GPIO43 \ + ESP32_PINMUX(43, ESP_NOSIG, ESP_U2RTS_OUT) + +#define UART2_RTS_GPIO44 \ + ESP32_PINMUX(44, ESP_NOSIG, ESP_U2RTS_OUT) + +#define UART2_RTS_GPIO45 \ + ESP32_PINMUX(45, ESP_NOSIG, ESP_U2RTS_OUT) + +#define UART2_RTS_GPIO46 \ + ESP32_PINMUX(46, ESP_NOSIG, ESP_U2RTS_OUT) + +#define UART2_RTS_GPIO47 \ + ESP32_PINMUX(47, ESP_NOSIG, ESP_U2RTS_OUT) + +#define UART2_RTS_GPIO48 \ + ESP32_PINMUX(48, ESP_NOSIG, ESP_U2RTS_OUT) + +/* UART2_RX */ +#define UART2_RX_GPIO0 \ + ESP32_PINMUX(0, ESP_U2RXD_IN, ESP_NOSIG) + +#define UART2_RX_GPIO1 \ + ESP32_PINMUX(1, ESP_U2RXD_IN, ESP_NOSIG) + +#define UART2_RX_GPIO2 \ + ESP32_PINMUX(2, ESP_U2RXD_IN, ESP_NOSIG) + +#define UART2_RX_GPIO3 \ + ESP32_PINMUX(3, ESP_U2RXD_IN, ESP_NOSIG) + +#define UART2_RX_GPIO4 \ + ESP32_PINMUX(4, ESP_U2RXD_IN, ESP_NOSIG) + +#define UART2_RX_GPIO5 \ + ESP32_PINMUX(5, ESP_U2RXD_IN, ESP_NOSIG) + +#define UART2_RX_GPIO6 \ + ESP32_PINMUX(6, ESP_U2RXD_IN, ESP_NOSIG) + +#define UART2_RX_GPIO7 \ + ESP32_PINMUX(7, ESP_U2RXD_IN, ESP_NOSIG) + +#define UART2_RX_GPIO8 \ + ESP32_PINMUX(8, ESP_U2RXD_IN, ESP_NOSIG) + +#define UART2_RX_GPIO9 \ + ESP32_PINMUX(9, ESP_U2RXD_IN, ESP_NOSIG) + +#define UART2_RX_GPIO10 \ + ESP32_PINMUX(10, ESP_U2RXD_IN, ESP_NOSIG) + +#define UART2_RX_GPIO11 \ + ESP32_PINMUX(11, ESP_U2RXD_IN, ESP_NOSIG) + +#define UART2_RX_GPIO12 \ + ESP32_PINMUX(12, ESP_U2RXD_IN, ESP_NOSIG) + +#define UART2_RX_GPIO13 \ + ESP32_PINMUX(13, ESP_U2RXD_IN, ESP_NOSIG) + +#define UART2_RX_GPIO14 \ + ESP32_PINMUX(14, ESP_U2RXD_IN, ESP_NOSIG) + +#define UART2_RX_GPIO15 \ + ESP32_PINMUX(15, ESP_U2RXD_IN, ESP_NOSIG) + +#define UART2_RX_GPIO16 \ + ESP32_PINMUX(16, ESP_U2RXD_IN, ESP_NOSIG) + +#define UART2_RX_GPIO17 \ + ESP32_PINMUX(17, ESP_U2RXD_IN, ESP_NOSIG) + +#define UART2_RX_GPIO18 \ + ESP32_PINMUX(18, ESP_U2RXD_IN, ESP_NOSIG) + +#define UART2_RX_GPIO19 \ + ESP32_PINMUX(19, ESP_U2RXD_IN, ESP_NOSIG) + +#define UART2_RX_GPIO20 \ + ESP32_PINMUX(20, ESP_U2RXD_IN, ESP_NOSIG) + +#define UART2_RX_GPIO21 \ + ESP32_PINMUX(21, ESP_U2RXD_IN, ESP_NOSIG) + +#define UART2_RX_GPIO26 \ + ESP32_PINMUX(26, ESP_U2RXD_IN, ESP_NOSIG) + +#define UART2_RX_GPIO27 \ + ESP32_PINMUX(27, ESP_U2RXD_IN, ESP_NOSIG) + +#define UART2_RX_GPIO28 \ + ESP32_PINMUX(28, ESP_U2RXD_IN, ESP_NOSIG) + +#define UART2_RX_GPIO29 \ + ESP32_PINMUX(29, ESP_U2RXD_IN, ESP_NOSIG) + +#define UART2_RX_GPIO30 \ + ESP32_PINMUX(30, ESP_U2RXD_IN, ESP_NOSIG) + +#define UART2_RX_GPIO31 \ + ESP32_PINMUX(31, ESP_U2RXD_IN, ESP_NOSIG) + +#define UART2_RX_GPIO32 \ + ESP32_PINMUX(32, ESP_U2RXD_IN, ESP_NOSIG) + +#define UART2_RX_GPIO33 \ + ESP32_PINMUX(33, ESP_U2RXD_IN, ESP_NOSIG) + +#define UART2_RX_GPIO34 \ + ESP32_PINMUX(34, ESP_U2RXD_IN, ESP_NOSIG) + +#define UART2_RX_GPIO35 \ + ESP32_PINMUX(35, ESP_U2RXD_IN, ESP_NOSIG) + +#define UART2_RX_GPIO36 \ + ESP32_PINMUX(36, ESP_U2RXD_IN, ESP_NOSIG) + +#define UART2_RX_GPIO37 \ + ESP32_PINMUX(37, ESP_U2RXD_IN, ESP_NOSIG) + +#define UART2_RX_GPIO38 \ + ESP32_PINMUX(38, ESP_U2RXD_IN, ESP_NOSIG) + +#define UART2_RX_GPIO39 \ + ESP32_PINMUX(39, ESP_U2RXD_IN, ESP_NOSIG) + +#define UART2_RX_GPIO40 \ + ESP32_PINMUX(40, ESP_U2RXD_IN, ESP_NOSIG) + +#define UART2_RX_GPIO41 \ + ESP32_PINMUX(41, ESP_U2RXD_IN, ESP_NOSIG) + +#define UART2_RX_GPIO42 \ + ESP32_PINMUX(42, ESP_U2RXD_IN, ESP_NOSIG) + +#define UART2_RX_GPIO43 \ + ESP32_PINMUX(43, ESP_U2RXD_IN, ESP_NOSIG) + +#define UART2_RX_GPIO44 \ + ESP32_PINMUX(44, ESP_U2RXD_IN, ESP_NOSIG) + +#define UART2_RX_GPIO45 \ + ESP32_PINMUX(45, ESP_U2RXD_IN, ESP_NOSIG) + +#define UART2_RX_GPIO46 \ + ESP32_PINMUX(46, ESP_U2RXD_IN, ESP_NOSIG) + +#define UART2_RX_GPIO47 \ + ESP32_PINMUX(47, ESP_U2RXD_IN, ESP_NOSIG) + +#define UART2_RX_GPIO48 \ + ESP32_PINMUX(48, ESP_U2RXD_IN, ESP_NOSIG) + +/* UART2_TX */ +#define UART2_TX_GPIO0 \ + ESP32_PINMUX(0, ESP_NOSIG, ESP_U2TXD_OUT) + +#define UART2_TX_GPIO1 \ + ESP32_PINMUX(1, ESP_NOSIG, ESP_U2TXD_OUT) + +#define UART2_TX_GPIO2 \ + ESP32_PINMUX(2, ESP_NOSIG, ESP_U2TXD_OUT) + +#define UART2_TX_GPIO3 \ + ESP32_PINMUX(3, ESP_NOSIG, ESP_U2TXD_OUT) + +#define UART2_TX_GPIO4 \ + ESP32_PINMUX(4, ESP_NOSIG, ESP_U2TXD_OUT) + +#define UART2_TX_GPIO5 \ + ESP32_PINMUX(5, ESP_NOSIG, ESP_U2TXD_OUT) + +#define UART2_TX_GPIO6 \ + ESP32_PINMUX(6, ESP_NOSIG, ESP_U2TXD_OUT) + +#define UART2_TX_GPIO7 \ + ESP32_PINMUX(7, ESP_NOSIG, ESP_U2TXD_OUT) + +#define UART2_TX_GPIO8 \ + ESP32_PINMUX(8, ESP_NOSIG, ESP_U2TXD_OUT) + +#define UART2_TX_GPIO9 \ + ESP32_PINMUX(9, ESP_NOSIG, ESP_U2TXD_OUT) + +#define UART2_TX_GPIO10 \ + ESP32_PINMUX(10, ESP_NOSIG, ESP_U2TXD_OUT) + +#define UART2_TX_GPIO11 \ + ESP32_PINMUX(11, ESP_NOSIG, ESP_U2TXD_OUT) + +#define UART2_TX_GPIO12 \ + ESP32_PINMUX(12, ESP_NOSIG, ESP_U2TXD_OUT) + +#define UART2_TX_GPIO13 \ + ESP32_PINMUX(13, ESP_NOSIG, ESP_U2TXD_OUT) + +#define UART2_TX_GPIO14 \ + ESP32_PINMUX(14, ESP_NOSIG, ESP_U2TXD_OUT) + +#define UART2_TX_GPIO15 \ + ESP32_PINMUX(15, ESP_NOSIG, ESP_U2TXD_OUT) + +#define UART2_TX_GPIO16 \ + ESP32_PINMUX(16, ESP_NOSIG, ESP_U2TXD_OUT) + +#define UART2_TX_GPIO17 \ + ESP32_PINMUX(17, ESP_NOSIG, ESP_U2TXD_OUT) + +#define UART2_TX_GPIO18 \ + ESP32_PINMUX(18, ESP_NOSIG, ESP_U2TXD_OUT) + +#define UART2_TX_GPIO19 \ + ESP32_PINMUX(19, ESP_NOSIG, ESP_U2TXD_OUT) + +#define UART2_TX_GPIO20 \ + ESP32_PINMUX(20, ESP_NOSIG, ESP_U2TXD_OUT) + +#define UART2_TX_GPIO21 \ + ESP32_PINMUX(21, ESP_NOSIG, ESP_U2TXD_OUT) + +#define UART2_TX_GPIO26 \ + ESP32_PINMUX(26, ESP_NOSIG, ESP_U2TXD_OUT) + +#define UART2_TX_GPIO27 \ + ESP32_PINMUX(27, ESP_NOSIG, ESP_U2TXD_OUT) + +#define UART2_TX_GPIO28 \ + ESP32_PINMUX(28, ESP_NOSIG, ESP_U2TXD_OUT) + +#define UART2_TX_GPIO29 \ + ESP32_PINMUX(29, ESP_NOSIG, ESP_U2TXD_OUT) + +#define UART2_TX_GPIO30 \ + ESP32_PINMUX(30, ESP_NOSIG, ESP_U2TXD_OUT) + +#define UART2_TX_GPIO31 \ + ESP32_PINMUX(31, ESP_NOSIG, ESP_U2TXD_OUT) + +#define UART2_TX_GPIO32 \ + ESP32_PINMUX(32, ESP_NOSIG, ESP_U2TXD_OUT) + +#define UART2_TX_GPIO33 \ + ESP32_PINMUX(33, ESP_NOSIG, ESP_U2TXD_OUT) + +#define UART2_TX_GPIO34 \ + ESP32_PINMUX(34, ESP_NOSIG, ESP_U2TXD_OUT) + +#define UART2_TX_GPIO35 \ + ESP32_PINMUX(35, ESP_NOSIG, ESP_U2TXD_OUT) + +#define UART2_TX_GPIO36 \ + ESP32_PINMUX(36, ESP_NOSIG, ESP_U2TXD_OUT) + +#define UART2_TX_GPIO37 \ + ESP32_PINMUX(37, ESP_NOSIG, ESP_U2TXD_OUT) + +#define UART2_TX_GPIO38 \ + ESP32_PINMUX(38, ESP_NOSIG, ESP_U2TXD_OUT) + +#define UART2_TX_GPIO39 \ + ESP32_PINMUX(39, ESP_NOSIG, ESP_U2TXD_OUT) + +#define UART2_TX_GPIO40 \ + ESP32_PINMUX(40, ESP_NOSIG, ESP_U2TXD_OUT) + +#define UART2_TX_GPIO41 \ + ESP32_PINMUX(41, ESP_NOSIG, ESP_U2TXD_OUT) + +#define UART2_TX_GPIO42 \ + ESP32_PINMUX(42, ESP_NOSIG, ESP_U2TXD_OUT) + +#define UART2_TX_GPIO43 \ + ESP32_PINMUX(43, ESP_NOSIG, ESP_U2TXD_OUT) + +#define UART2_TX_GPIO44 \ + ESP32_PINMUX(44, ESP_NOSIG, ESP_U2TXD_OUT) + +#define UART2_TX_GPIO45 \ + ESP32_PINMUX(45, ESP_NOSIG, ESP_U2TXD_OUT) + +#define UART2_TX_GPIO46 \ + ESP32_PINMUX(46, ESP_NOSIG, ESP_U2TXD_OUT) + +#define UART2_TX_GPIO47 \ + ESP32_PINMUX(47, ESP_NOSIG, ESP_U2TXD_OUT) + +#define UART2_TX_GPIO48 \ + ESP32_PINMUX(48, ESP_NOSIG, ESP_U2TXD_OUT) + + +#endif /* INC_DT_BINDS_PINCTRL_ESP32S3_PINCTRL_HAL_H_ */ diff --git a/west.yml b/west.yml index cd02b7125f9..47d6da5a1b6 100644 --- a/west.yml +++ b/west.yml @@ -152,7 +152,7 @@ manifest: groups: - hal - name: hal_espressif - revision: b6d2ea66a0047204ffc5ec8725ec45a671ab397b + revision: 754be4745295a45c26d42c916a8600cdcefddd4e path: modules/hal/espressif west-commands: west/west-commands.yml groups: From ecda72079edbcd86acca93a1cfb3fd07bb5b891b Mon Sep 17 00:00:00 2001 From: Sylvio Alves Date: Tue, 12 Dec 2023 10:04:05 -0300 Subject: [PATCH 1494/3723] esp32: overlays: remove unused dt-binding headers All overlay headers are not necessary to be included. Signed-off-by: Sylvio Alves --- samples/basic/blinky_pwm/boards/esp32_devkitc_wroom.overlay | 1 - samples/basic/blinky_pwm/boards/esp32c3_devkitm.overlay | 1 - samples/basic/blinky_pwm/boards/esp32c3_luatos_core.overlay | 1 - samples/basic/blinky_pwm/boards/esp32c3_luatos_core_usb.overlay | 1 - samples/basic/blinky_pwm/boards/esp32s2_saola.overlay | 1 - samples/basic/blinky_pwm/boards/esp32s3_devkitm.overlay | 1 - samples/basic/blinky_pwm/boards/esp32s3_luatos_core.overlay | 1 - samples/basic/blinky_pwm/boards/esp32s3_luatos_core_usb.overlay | 1 - samples/basic/blinky_pwm/boards/xiao_esp32s3.overlay | 1 - samples/sensor/qdec/boards/esp32s3_devkitm.overlay | 2 -- samples/sensor/qdec/boards/esp32s3_luatos_core.overlay | 2 -- samples/sensor/qdec/boards/esp32s3_luatos_core_usb.overlay | 2 -- tests/drivers/pwm/pwm_api/boards/esp32_devkitc_wroom.overlay | 1 - tests/drivers/pwm/pwm_api/boards/esp32c3_devkitm.overlay | 1 - tests/drivers/pwm/pwm_api/boards/esp32c3_luatos_core.overlay | 1 - .../drivers/pwm/pwm_api/boards/esp32c3_luatos_core_usb.overlay | 1 - tests/drivers/pwm/pwm_api/boards/esp32s2_saola.overlay | 1 - tests/drivers/pwm/pwm_api/boards/esp32s3_devkitm.overlay | 1 - tests/drivers/pwm/pwm_api/boards/esp32s3_luatos_core.overlay | 1 - .../drivers/pwm/pwm_api/boards/esp32s3_luatos_core_usb.overlay | 1 - .../drivers/pwm/pwm_loopback/boards/esp32_devkitc_wroom.overlay | 1 - tests/drivers/pwm/pwm_loopback/boards/esp32s3_devkitm.overlay | 1 - .../drivers/pwm/pwm_loopback/boards/esp32s3_luatos_core.overlay | 1 - .../pwm/pwm_loopback/boards/esp32s3_luatos_core_usb.overlay | 1 - tests/drivers/pwm/pwm_loopback/boards/yd_esp32.overlay | 1 - 25 files changed, 28 deletions(-) diff --git a/samples/basic/blinky_pwm/boards/esp32_devkitc_wroom.overlay b/samples/basic/blinky_pwm/boards/esp32_devkitc_wroom.overlay index fc5466c9cbe..a9a1d685e99 100644 --- a/samples/basic/blinky_pwm/boards/esp32_devkitc_wroom.overlay +++ b/samples/basic/blinky_pwm/boards/esp32_devkitc_wroom.overlay @@ -6,7 +6,6 @@ */ #include -#include / { aliases { diff --git a/samples/basic/blinky_pwm/boards/esp32c3_devkitm.overlay b/samples/basic/blinky_pwm/boards/esp32c3_devkitm.overlay index a438cc5246b..a9a1d685e99 100644 --- a/samples/basic/blinky_pwm/boards/esp32c3_devkitm.overlay +++ b/samples/basic/blinky_pwm/boards/esp32c3_devkitm.overlay @@ -6,7 +6,6 @@ */ #include -#include / { aliases { diff --git a/samples/basic/blinky_pwm/boards/esp32c3_luatos_core.overlay b/samples/basic/blinky_pwm/boards/esp32c3_luatos_core.overlay index a438cc5246b..a9a1d685e99 100644 --- a/samples/basic/blinky_pwm/boards/esp32c3_luatos_core.overlay +++ b/samples/basic/blinky_pwm/boards/esp32c3_luatos_core.overlay @@ -6,7 +6,6 @@ */ #include -#include / { aliases { diff --git a/samples/basic/blinky_pwm/boards/esp32c3_luatos_core_usb.overlay b/samples/basic/blinky_pwm/boards/esp32c3_luatos_core_usb.overlay index a438cc5246b..a9a1d685e99 100644 --- a/samples/basic/blinky_pwm/boards/esp32c3_luatos_core_usb.overlay +++ b/samples/basic/blinky_pwm/boards/esp32c3_luatos_core_usb.overlay @@ -6,7 +6,6 @@ */ #include -#include / { aliases { diff --git a/samples/basic/blinky_pwm/boards/esp32s2_saola.overlay b/samples/basic/blinky_pwm/boards/esp32s2_saola.overlay index 5709c54d180..a9a1d685e99 100644 --- a/samples/basic/blinky_pwm/boards/esp32s2_saola.overlay +++ b/samples/basic/blinky_pwm/boards/esp32s2_saola.overlay @@ -6,7 +6,6 @@ */ #include -#include / { aliases { diff --git a/samples/basic/blinky_pwm/boards/esp32s3_devkitm.overlay b/samples/basic/blinky_pwm/boards/esp32s3_devkitm.overlay index c6ca7b5a52b..99d9e2d9bfd 100644 --- a/samples/basic/blinky_pwm/boards/esp32s3_devkitm.overlay +++ b/samples/basic/blinky_pwm/boards/esp32s3_devkitm.overlay @@ -5,7 +5,6 @@ */ #include -#include / { aliases { diff --git a/samples/basic/blinky_pwm/boards/esp32s3_luatos_core.overlay b/samples/basic/blinky_pwm/boards/esp32s3_luatos_core.overlay index 61152f82f94..70069ad3b10 100644 --- a/samples/basic/blinky_pwm/boards/esp32s3_luatos_core.overlay +++ b/samples/basic/blinky_pwm/boards/esp32s3_luatos_core.overlay @@ -5,7 +5,6 @@ */ #include -#include / { aliases { diff --git a/samples/basic/blinky_pwm/boards/esp32s3_luatos_core_usb.overlay b/samples/basic/blinky_pwm/boards/esp32s3_luatos_core_usb.overlay index 61152f82f94..70069ad3b10 100644 --- a/samples/basic/blinky_pwm/boards/esp32s3_luatos_core_usb.overlay +++ b/samples/basic/blinky_pwm/boards/esp32s3_luatos_core_usb.overlay @@ -5,7 +5,6 @@ */ #include -#include / { aliases { diff --git a/samples/basic/blinky_pwm/boards/xiao_esp32s3.overlay b/samples/basic/blinky_pwm/boards/xiao_esp32s3.overlay index 045056613e0..86ffa3dcdf0 100644 --- a/samples/basic/blinky_pwm/boards/xiao_esp32s3.overlay +++ b/samples/basic/blinky_pwm/boards/xiao_esp32s3.overlay @@ -5,7 +5,6 @@ */ #include -#include / { aliases { diff --git a/samples/sensor/qdec/boards/esp32s3_devkitm.overlay b/samples/sensor/qdec/boards/esp32s3_devkitm.overlay index d347ea85345..4562dd868bb 100644 --- a/samples/sensor/qdec/boards/esp32s3_devkitm.overlay +++ b/samples/sensor/qdec/boards/esp32s3_devkitm.overlay @@ -4,8 +4,6 @@ * Copyright (c) 2023 Espressif Systems (Shanghai) Co., Ltd. */ -#include - / { aliases { qdec0 = &pcnt; diff --git a/samples/sensor/qdec/boards/esp32s3_luatos_core.overlay b/samples/sensor/qdec/boards/esp32s3_luatos_core.overlay index d347ea85345..4562dd868bb 100644 --- a/samples/sensor/qdec/boards/esp32s3_luatos_core.overlay +++ b/samples/sensor/qdec/boards/esp32s3_luatos_core.overlay @@ -4,8 +4,6 @@ * Copyright (c) 2023 Espressif Systems (Shanghai) Co., Ltd. */ -#include - / { aliases { qdec0 = &pcnt; diff --git a/samples/sensor/qdec/boards/esp32s3_luatos_core_usb.overlay b/samples/sensor/qdec/boards/esp32s3_luatos_core_usb.overlay index d347ea85345..4562dd868bb 100644 --- a/samples/sensor/qdec/boards/esp32s3_luatos_core_usb.overlay +++ b/samples/sensor/qdec/boards/esp32s3_luatos_core_usb.overlay @@ -4,8 +4,6 @@ * Copyright (c) 2023 Espressif Systems (Shanghai) Co., Ltd. */ -#include - / { aliases { qdec0 = &pcnt; diff --git a/tests/drivers/pwm/pwm_api/boards/esp32_devkitc_wroom.overlay b/tests/drivers/pwm/pwm_api/boards/esp32_devkitc_wroom.overlay index 5020742bcc7..409f7dc30a7 100644 --- a/tests/drivers/pwm/pwm_api/boards/esp32_devkitc_wroom.overlay +++ b/tests/drivers/pwm/pwm_api/boards/esp32_devkitc_wroom.overlay @@ -5,7 +5,6 @@ */ #include -#include / { aliases { diff --git a/tests/drivers/pwm/pwm_api/boards/esp32c3_devkitm.overlay b/tests/drivers/pwm/pwm_api/boards/esp32c3_devkitm.overlay index 5c0a5285e6e..409f7dc30a7 100644 --- a/tests/drivers/pwm/pwm_api/boards/esp32c3_devkitm.overlay +++ b/tests/drivers/pwm/pwm_api/boards/esp32c3_devkitm.overlay @@ -5,7 +5,6 @@ */ #include -#include / { aliases { diff --git a/tests/drivers/pwm/pwm_api/boards/esp32c3_luatos_core.overlay b/tests/drivers/pwm/pwm_api/boards/esp32c3_luatos_core.overlay index 5c0a5285e6e..409f7dc30a7 100644 --- a/tests/drivers/pwm/pwm_api/boards/esp32c3_luatos_core.overlay +++ b/tests/drivers/pwm/pwm_api/boards/esp32c3_luatos_core.overlay @@ -5,7 +5,6 @@ */ #include -#include / { aliases { diff --git a/tests/drivers/pwm/pwm_api/boards/esp32c3_luatos_core_usb.overlay b/tests/drivers/pwm/pwm_api/boards/esp32c3_luatos_core_usb.overlay index 5c0a5285e6e..409f7dc30a7 100644 --- a/tests/drivers/pwm/pwm_api/boards/esp32c3_luatos_core_usb.overlay +++ b/tests/drivers/pwm/pwm_api/boards/esp32c3_luatos_core_usb.overlay @@ -5,7 +5,6 @@ */ #include -#include / { aliases { diff --git a/tests/drivers/pwm/pwm_api/boards/esp32s2_saola.overlay b/tests/drivers/pwm/pwm_api/boards/esp32s2_saola.overlay index 47106eda136..409f7dc30a7 100644 --- a/tests/drivers/pwm/pwm_api/boards/esp32s2_saola.overlay +++ b/tests/drivers/pwm/pwm_api/boards/esp32s2_saola.overlay @@ -5,7 +5,6 @@ */ #include -#include / { aliases { diff --git a/tests/drivers/pwm/pwm_api/boards/esp32s3_devkitm.overlay b/tests/drivers/pwm/pwm_api/boards/esp32s3_devkitm.overlay index 23fd331d41a..409f7dc30a7 100644 --- a/tests/drivers/pwm/pwm_api/boards/esp32s3_devkitm.overlay +++ b/tests/drivers/pwm/pwm_api/boards/esp32s3_devkitm.overlay @@ -5,7 +5,6 @@ */ #include -#include / { aliases { diff --git a/tests/drivers/pwm/pwm_api/boards/esp32s3_luatos_core.overlay b/tests/drivers/pwm/pwm_api/boards/esp32s3_luatos_core.overlay index 23fd331d41a..409f7dc30a7 100644 --- a/tests/drivers/pwm/pwm_api/boards/esp32s3_luatos_core.overlay +++ b/tests/drivers/pwm/pwm_api/boards/esp32s3_luatos_core.overlay @@ -5,7 +5,6 @@ */ #include -#include / { aliases { diff --git a/tests/drivers/pwm/pwm_api/boards/esp32s3_luatos_core_usb.overlay b/tests/drivers/pwm/pwm_api/boards/esp32s3_luatos_core_usb.overlay index 23fd331d41a..409f7dc30a7 100644 --- a/tests/drivers/pwm/pwm_api/boards/esp32s3_luatos_core_usb.overlay +++ b/tests/drivers/pwm/pwm_api/boards/esp32s3_luatos_core_usb.overlay @@ -5,7 +5,6 @@ */ #include -#include / { aliases { diff --git a/tests/drivers/pwm/pwm_loopback/boards/esp32_devkitc_wroom.overlay b/tests/drivers/pwm/pwm_loopback/boards/esp32_devkitc_wroom.overlay index aa4cd2ff6d9..b0d4e1e0381 100644 --- a/tests/drivers/pwm/pwm_loopback/boards/esp32_devkitc_wroom.overlay +++ b/tests/drivers/pwm/pwm_loopback/boards/esp32_devkitc_wroom.overlay @@ -5,7 +5,6 @@ */ #include -#include / { pwm_loopback_0 { diff --git a/tests/drivers/pwm/pwm_loopback/boards/esp32s3_devkitm.overlay b/tests/drivers/pwm/pwm_loopback/boards/esp32s3_devkitm.overlay index 4c9f9e5ff53..64e50d19693 100644 --- a/tests/drivers/pwm/pwm_loopback/boards/esp32s3_devkitm.overlay +++ b/tests/drivers/pwm/pwm_loopback/boards/esp32s3_devkitm.overlay @@ -5,7 +5,6 @@ */ #include -#include / { pwm_loopback_0 { diff --git a/tests/drivers/pwm/pwm_loopback/boards/esp32s3_luatos_core.overlay b/tests/drivers/pwm/pwm_loopback/boards/esp32s3_luatos_core.overlay index 4c9f9e5ff53..64e50d19693 100644 --- a/tests/drivers/pwm/pwm_loopback/boards/esp32s3_luatos_core.overlay +++ b/tests/drivers/pwm/pwm_loopback/boards/esp32s3_luatos_core.overlay @@ -5,7 +5,6 @@ */ #include -#include / { pwm_loopback_0 { diff --git a/tests/drivers/pwm/pwm_loopback/boards/esp32s3_luatos_core_usb.overlay b/tests/drivers/pwm/pwm_loopback/boards/esp32s3_luatos_core_usb.overlay index 4c9f9e5ff53..64e50d19693 100644 --- a/tests/drivers/pwm/pwm_loopback/boards/esp32s3_luatos_core_usb.overlay +++ b/tests/drivers/pwm/pwm_loopback/boards/esp32s3_luatos_core_usb.overlay @@ -5,7 +5,6 @@ */ #include -#include / { pwm_loopback_0 { diff --git a/tests/drivers/pwm/pwm_loopback/boards/yd_esp32.overlay b/tests/drivers/pwm/pwm_loopback/boards/yd_esp32.overlay index aa4cd2ff6d9..b0d4e1e0381 100644 --- a/tests/drivers/pwm/pwm_loopback/boards/yd_esp32.overlay +++ b/tests/drivers/pwm/pwm_loopback/boards/yd_esp32.overlay @@ -5,7 +5,6 @@ */ #include -#include / { pwm_loopback_0 { From 746a3b943db8f56a58138f17bb58986c34797880 Mon Sep 17 00:00:00 2001 From: Christopher Friedt Date: Wed, 13 Dec 2023 19:57:42 -0500 Subject: [PATCH 1495/3723] tests: posix: use consistent min stack sizes * Use PTHREAD_STACK_MIN as provided by the specification instead of a hard-coded value of 1024 * add extra stack size to semaphore tests Signed-off-by: Christopher Friedt --- tests/posix/common/src/key.c | 2 +- tests/posix/common/src/mqueue.c | 2 +- tests/posix/common/src/mutex.c | 3 ++- tests/posix/common/src/pthread.c | 2 +- tests/posix/common/src/rwlock.c | 2 +- tests/posix/common/src/semaphore.c | 3 ++- 6 files changed, 8 insertions(+), 6 deletions(-) diff --git a/tests/posix/common/src/key.c b/tests/posix/common/src/key.c index eeadf8f0058..58e67a313ac 100644 --- a/tests/posix/common/src/key.c +++ b/tests/posix/common/src/key.c @@ -11,7 +11,7 @@ #define N_THR 2 #define N_KEY 2 -#define STACKSZ (1024 + CONFIG_TEST_EXTRA_STACK_SIZE) +#define STACKSZ (MAX(1024, PTHREAD_STACK_MIN) + CONFIG_TEST_EXTRA_STACK_SIZE) #define BUFFSZ 48 K_THREAD_STACK_ARRAY_DEFINE(stackp, N_THR, STACKSZ); diff --git a/tests/posix/common/src/mqueue.c b/tests/posix/common/src/mqueue.c index 7d1ec257323..65df6fbe777 100644 --- a/tests/posix/common/src/mqueue.c +++ b/tests/posix/common/src/mqueue.c @@ -12,7 +12,7 @@ #include #define N_THR 2 -#define STACKSZ (1024 + CONFIG_TEST_EXTRA_STACK_SIZE) +#define STACKSZ (MAX(1024, PTHREAD_STACK_MIN) + CONFIG_TEST_EXTRA_STACK_SIZE) #define SENDER_THREAD 0 #define RECEIVER_THREAD 1 #define MESSAGE_SIZE 16 diff --git a/tests/posix/common/src/mutex.c b/tests/posix/common/src/mutex.c index 01c49220727..6a63f98e451 100644 --- a/tests/posix/common/src/mutex.c +++ b/tests/posix/common/src/mutex.c @@ -7,9 +7,10 @@ #include #include +#include #include -#define STACK_SIZE (1024 + CONFIG_TEST_EXTRA_STACK_SIZE) +#define STACK_SIZE (MAX(1024, PTHREAD_STACK_MIN) + CONFIG_TEST_EXTRA_STACK_SIZE) static K_THREAD_STACK_DEFINE(stack, STACK_SIZE); diff --git a/tests/posix/common/src/pthread.c b/tests/posix/common/src/pthread.c index 3ff1092df27..58041c7e801 100644 --- a/tests/posix/common/src/pthread.c +++ b/tests/posix/common/src/pthread.c @@ -13,7 +13,7 @@ #define N_THR_E 3 #define N_THR_T 4 #define BOUNCES 64 -#define STACKS (1024 + CONFIG_TEST_EXTRA_STACK_SIZE) +#define STACKS (MAX(1024, PTHREAD_STACK_MIN) + CONFIG_TEST_EXTRA_STACK_SIZE) #define THREAD_PRIORITY 3 #define ONE_SECOND 1 diff --git a/tests/posix/common/src/rwlock.c b/tests/posix/common/src/rwlock.c index aebf459c323..43c573a7007 100644 --- a/tests/posix/common/src/rwlock.c +++ b/tests/posix/common/src/rwlock.c @@ -10,7 +10,7 @@ #include #define N_THR 3 -#define STACKSZ (1024 + CONFIG_TEST_EXTRA_STACK_SIZE) +#define STACKSZ (MAX(1024, PTHREAD_STACK_MIN) + CONFIG_TEST_EXTRA_STACK_SIZE) K_THREAD_STACK_ARRAY_DEFINE(stack, N_THR, STACKSZ); pthread_rwlock_t rwlock; diff --git a/tests/posix/common/src/semaphore.c b/tests/posix/common/src/semaphore.c index 622a34dc073..fef4ddfb0fe 100644 --- a/tests/posix/common/src/semaphore.c +++ b/tests/posix/common/src/semaphore.c @@ -8,9 +8,10 @@ #include #include +#include #include -#define STACK_SIZE 1024 +#define STACK_SIZE (MAX(1024, PTHREAD_STACK_MIN) + CONFIG_TEST_EXTRA_STACK_SIZE) sem_t sema; void *dummy_sem; From eb7e4bed981fa1990d43de6d24ddde5197fde1ca Mon Sep 17 00:00:00 2001 From: Christopher Friedt Date: Wed, 13 Dec 2023 19:43:10 -0500 Subject: [PATCH 1496/3723] posix: pthread_attr: use space in struct more efficiently This change reduces the space occupied by struct pthread_attr which is the internal type used for pthread_attr_t. We cap the stack size at 16 bits (so up to 65536 bytes) and since a stack size of 0 is invalid, we can encode the stack size by simply subtracting 1 or adding 1 when setting or getting. The schedpolicy is capped at 2 bits and initialized, cancellable, and detached are given 1 bit. Signed-off-by: Christopher Friedt --- include/zephyr/posix/posix_types.h | 13 ++- include/zephyr/posix/pthread.h | 11 ++- lib/posix/pthread.c | 138 +++++++++++++++-------------- 3 files changed, 84 insertions(+), 78 deletions(-) diff --git a/include/zephyr/posix/posix_types.h b/include/zephyr/posix/posix_types.h index 25009dc88bc..566fd63f1fb 100644 --- a/include/zephyr/posix/posix_types.h +++ b/include/zephyr/posix/posix_types.h @@ -37,14 +37,13 @@ typedef unsigned long timer_t; /* Thread attributes */ struct pthread_attr { - int priority; void *stack; - uint32_t stacksize; - uint32_t flags; - uint32_t delayedstart; - uint32_t schedpolicy; - int32_t detachstate; - uint32_t initialized; + uint16_t stacksize; + int8_t priority; + uint8_t schedpolicy: 2; + bool initialized: 1; + bool cancelstate: 1; + bool detachstate: 1; }; #if defined(CONFIG_MINIMAL_LIBC) || defined(CONFIG_PICOLIBC) || defined(CONFIG_ARMCLANG_STD_LIBC) \ || defined(CONFIG_ARCMWDT_LIBC) diff --git a/include/zephyr/posix/pthread.h b/include/zephyr/posix/pthread.h index ccb1c71a4bd..d380e691d66 100644 --- a/include/zephyr/posix/pthread.h +++ b/include/zephyr/posix/pthread.h @@ -19,9 +19,14 @@ extern "C" { #endif -/* Pthread detach/joinable */ -#define PTHREAD_CREATE_DETACHED 0 -#define PTHREAD_CREATE_JOINABLE 1 +/* + * Pthread detach/joinable + * Undefine possibly predefined values by external toolchain headers + */ +#undef PTHREAD_CREATE_DETACHED +#define PTHREAD_CREATE_DETACHED 1 +#undef PTHREAD_CREATE_JOINABLE +#define PTHREAD_CREATE_JOINABLE 0 /* Pthread resource visibility */ #define PTHREAD_PROCESS_PRIVATE 0 diff --git a/lib/posix/pthread.c b/lib/posix/pthread.c index e809b539c6a..207236e085c 100644 --- a/lib/posix/pthread.c +++ b/lib/posix/pthread.c @@ -18,6 +18,17 @@ #include #include +#define ZEPHYR_TO_POSIX_PRIORITY(_zprio) \ + (((_zprio) < 0) ? (-1 * ((_zprio) + 1)) : (CONFIG_NUM_PREEMPT_PRIORITIES - (_zprio)-1)) + +#define POSIX_TO_ZEPHYR_PRIORITY(_prio, _pol) \ + (((_pol) == SCHED_FIFO) ? (-1 * ((_prio) + 1)) \ + : (CONFIG_NUM_PREEMPT_PRIORITIES - (_prio)-1)) + +#define DEFAULT_PTHREAD_PRIORITY \ + POSIX_TO_ZEPHYR_PRIORITY(K_LOWEST_APPLICATION_THREAD_PRIO, DEFAULT_PTHREAD_POLICY) +#define DEFAULT_PTHREAD_POLICY (IS_ENABLED(CONFIG_PREEMPT_ENABLED) ? SCHED_RR : SCHED_FIFO) + LOG_MODULE_REGISTER(pthread, CONFIG_PTHREAD_LOG_LEVEL); #ifdef CONFIG_DYNAMIC_THREAD_STACK_SIZE @@ -26,9 +37,18 @@ LOG_MODULE_REGISTER(pthread, CONFIG_PTHREAD_LOG_LEVEL); #define DYNAMIC_STACK_SIZE 0 #endif -#define _pthread_cancel_pos LOG2(PTHREAD_CANCEL_DISABLE) +/* The maximum allowed stack size (for this implementation) */ +#define PTHREAD_STACK_MAX (UINT16_MAX + 1) + +static inline size_t __get_attr_stacksize(const struct pthread_attr *attr) +{ + return attr->stacksize + 1; +} -#define PTHREAD_INIT_FLAGS PTHREAD_CANCEL_ENABLE +static inline void __set_attr_stacksize(struct pthread_attr *attr, size_t size) +{ + attr->stacksize = size - 1; +} struct __pthread_cleanup { void (*routine)(void *arg); @@ -45,6 +65,9 @@ enum posix_thread_qid { POSIX_THREAD_DONE_Q, }; +/* only 2 bits in struct pthread_attr for schedpolicy */ +BUILD_ASSERT(SCHED_OTHER < BIT(2) && SCHED_FIFO < BIT(2) && SCHED_RR < BIT(2)); + BUILD_ASSERT((PTHREAD_CREATE_DETACHED == 0 || PTHREAD_CREATE_JOINABLE == 0) && (PTHREAD_CREATE_DETACHED == 1 || PTHREAD_CREATE_JOINABLE == 1)); @@ -60,18 +83,13 @@ static struct k_spinlock pthread_pool_lock; static int pthread_concurrency; static const struct pthread_attr init_pthread_attrs = { - .priority = 0, .stack = NULL, .stacksize = 0, - .flags = PTHREAD_INIT_FLAGS, - .delayedstart = 0, -#if defined(CONFIG_PREEMPT_ENABLED) - .schedpolicy = SCHED_RR, -#else - .schedpolicy = SCHED_FIFO, -#endif - .detachstate = PTHREAD_CREATE_JOINABLE, + .priority = DEFAULT_PTHREAD_PRIORITY, + .schedpolicy = DEFAULT_PTHREAD_POLICY, .initialized = true, + .cancelstate = PTHREAD_CANCEL_ENABLE, + .detachstate = PTHREAD_CREATE_JOINABLE, }; /* @@ -201,35 +219,27 @@ static bool is_posix_policy_prio_valid(uint32_t priority, int policy) static uint32_t zephyr_to_posix_priority(int32_t z_prio, int *policy) { - uint32_t prio; - if (z_prio < 0) { - *policy = SCHED_FIFO; - prio = -1 * (z_prio + 1); - __ASSERT_NO_MSG(prio < CONFIG_NUM_COOP_PRIORITIES); + __ASSERT_NO_MSG(z_prio < CONFIG_NUM_COOP_PRIORITIES); } else { - *policy = SCHED_RR; - prio = (CONFIG_NUM_PREEMPT_PRIORITIES - z_prio - 1); - __ASSERT_NO_MSG(prio < CONFIG_NUM_PREEMPT_PRIORITIES); + __ASSERT_NO_MSG(z_prio < CONFIG_NUM_PREEMPT_PRIORITIES); } - return prio; + *policy = (z_prio < 0) ? SCHED_FIFO : SCHED_RR; + return ZEPHYR_TO_POSIX_PRIORITY(z_prio); } static int32_t posix_to_zephyr_priority(uint32_t priority, int policy) { - int32_t prio; - if (policy == SCHED_FIFO) { - /* Zephyr COOP priority starts from -1 */ + /* COOP: highest [CONFIG_NUM_COOP_PRIORITIES, -1] lowest */ __ASSERT_NO_MSG(priority < CONFIG_NUM_COOP_PRIORITIES); - prio = -1 * (priority + 1); } else { + /* PREEMPT: lowest [0, CONFIG_NUM_PREEMPT_PRIORITIES - 1] highest */ __ASSERT_NO_MSG(priority < CONFIG_NUM_PREEMPT_PRIORITIES); - prio = (CONFIG_NUM_PREEMPT_PRIORITIES - priority - 1); } - return prio; + return POSIX_TO_ZEPHYR_PRIORITY(priority, policy); } /** @@ -242,8 +252,8 @@ int pthread_attr_setschedparam(pthread_attr_t *_attr, const struct sched_param * struct pthread_attr *attr = (struct pthread_attr *)_attr; int priority = schedparam->sched_priority; - if ((attr == NULL) || (attr->initialized == 0U) || - (is_posix_policy_prio_valid(priority, attr->schedpolicy) == false)) { + if (attr == NULL || !attr->initialized || + is_posix_policy_prio_valid(priority, attr->schedpolicy == false)) { LOG_ERR("Invalid pthread_attr_t or sched_param"); return EINVAL; } @@ -266,8 +276,13 @@ int pthread_attr_setstack(pthread_attr_t *_attr, void *stackaddr, size_t stacksi return EACCES; } + if (stacksize == 0 || stacksize < PTHREAD_STACK_MIN || stacksize > PTHREAD_STACK_MAX) { + LOG_ERR("Invalid stacksize %zu", stacksize); + return EINVAL; + } + attr->stack = stackaddr; - attr->stacksize = stacksize; + __set_attr_stacksize(attr, stacksize); return 0; } @@ -279,8 +294,9 @@ static bool pthread_attr_is_valid(const struct pthread_attr *attr) } /* caller-provided thread stack */ - if (attr->initialized == 0U || attr->stack == NULL || attr->stacksize == 0) { - LOG_ERR("pthread_attr_t is not initialized, has a NULL stack, or is of size 0"); + if (!attr->initialized || attr->stack == NULL || attr->stacksize == 0 || + __get_attr_stacksize(attr) < PTHREAD_STACK_MIN) { + LOG_ERR("pthread_attr_t is not initialized, has a NULL stack, or invalid size"); return false; } @@ -290,19 +306,6 @@ static bool pthread_attr_is_valid(const struct pthread_attr *attr) return false; } - /* require a valid detachstate */ - if (!(attr->detachstate == PTHREAD_CREATE_JOINABLE || - attr->detachstate == PTHREAD_CREATE_DETACHED)) { - LOG_ERR("Invalid detachstate %d", attr->detachstate); - return false; - } - - /* we cannot create an essential thread (i.e. one that may not abort) */ - if ((attr->flags & K_ESSENTIAL) != 0) { - LOG_ERR("Cannot create an essential thread"); - return false; - } - return true; } @@ -431,11 +434,12 @@ int pthread_create(pthread_t *th, const pthread_attr_t *_attr, void *(*threadrou if (attr == NULL) { attr = &attr_storage; - attr->stacksize = DYNAMIC_STACK_SIZE; - attr->stack = - k_thread_stack_alloc(attr->stacksize, k_is_user_context() ? K_USER : 0); + BUILD_ASSERT(DYNAMIC_STACK_SIZE <= PTHREAD_STACK_MAX); + __set_attr_stacksize(attr, DYNAMIC_STACK_SIZE); + attr->stack = k_thread_stack_alloc(__get_attr_stacksize(attr), + k_is_user_context() ? K_USER : 0); if (attr->stack == NULL) { - LOG_ERR("Unable to allocate stack of size %u", attr->stacksize); + LOG_ERR("Unable to allocate stack of size %u", DYNAMIC_STACK_SIZE); return EAGAIN; } LOG_DBG("Allocated thread stack %p", attr->stack); @@ -454,9 +458,7 @@ int pthread_create(pthread_t *th, const pthread_attr_t *_attr, void *(*threadrou sys_dlist_append(&run_q, &t->q_node); t->qid = POSIX_THREAD_RUN_Q; t->detachstate = attr->detachstate; - if ((BIT(_pthread_cancel_pos) & attr->flags) != 0) { - t->cancel_state = PTHREAD_CANCEL_ENABLE; - } + t->cancel_state = attr->cancelstate; t->cancel_pending = false; sys_slist_init(&t->key_list); sys_slist_init(&t->cleanup_list); @@ -491,10 +493,8 @@ int pthread_create(pthread_t *th, const pthread_attr_t *_attr, void *(*threadrou /* spawn the thread */ k_thread_create(&t->thread, attr->stack, attr->stacksize, zephyr_thread_wrapper, (void *)arg, threadroutine, - IS_ENABLED(CONFIG_PTHREAD_CREATE_BARRIER) ? UINT_TO_POINTER(barrier) - : NULL, - posix_to_zephyr_priority(attr->priority, attr->schedpolicy), attr->flags, - K_MSEC(attr->delayedstart)); + IS_ENABLED(CONFIG_PTHREAD_CREATE_BARRIER) ? UINT_TO_POINTER(barrier) : NULL, + posix_to_zephyr_priority(attr->priority, attr->schedpolicy), 0, K_NO_WAIT); if (IS_ENABLED(CONFIG_PTHREAD_CREATE_BARRIER)) { /* wait for the spawned thread to cross our barrier */ @@ -664,15 +664,16 @@ int pthread_setschedparam(pthread_t pthread, int policy, const struct sched_para * * See IEEE 1003.1 */ -int pthread_attr_init(pthread_attr_t *attr) +int pthread_attr_init(pthread_attr_t *_attr) { + struct pthread_attr *const attr = (struct pthread_attr *)_attr; if (attr == NULL) { LOG_ERR("Invalid attr pointer"); return ENOMEM; } - (void)memcpy(attr, &init_pthread_attrs, sizeof(pthread_attr_t)); + (void)memcpy(attr, &init_pthread_attrs, sizeof(struct pthread_attr)); return 0; } @@ -747,7 +748,7 @@ void pthread_exit(void *retval) CODE_UNREACHABLE; } - /* Make a thread as cancelable before exiting */ + /* Mark a thread as cancellable before exiting */ key = k_spin_lock(&pthread_pool_lock); self->cancel_state = PTHREAD_CANCEL_ENABLE; k_spin_unlock(&pthread_pool_lock, key); @@ -870,7 +871,7 @@ int pthread_attr_getdetachstate(const pthread_attr_t *_attr, int *detachstate) { const struct pthread_attr *attr = (const struct pthread_attr *)_attr; - if ((attr == NULL) || (attr->initialized == 0U)) { + if ((attr == NULL) || (attr->initialized == false)) { return EINVAL; } @@ -887,8 +888,9 @@ int pthread_attr_setdetachstate(pthread_attr_t *_attr, int detachstate) { struct pthread_attr *attr = (struct pthread_attr *)_attr; - if ((attr == NULL) || (attr->initialized == 0U) || - (detachstate != PTHREAD_CREATE_DETACHED && detachstate != PTHREAD_CREATE_JOINABLE)) { + if ((attr == NULL) || (attr->initialized == false) || + ((detachstate != PTHREAD_CREATE_DETACHED) && + (detachstate != PTHREAD_CREATE_JOINABLE))) { return EINVAL; } @@ -939,11 +941,11 @@ int pthread_attr_getstacksize(const pthread_attr_t *_attr, size_t *stacksize) { const struct pthread_attr *attr = (const struct pthread_attr *)_attr; - if ((attr == NULL) || (attr->initialized == 0U)) { + if ((attr == NULL) || (attr->initialized == false)) { return EINVAL; } - *stacksize = attr->stacksize; + *stacksize = __get_attr_stacksize(attr); return 0; } @@ -960,11 +962,11 @@ int pthread_attr_setstacksize(pthread_attr_t *_attr, size_t stacksize) return EINVAL; } - if (stacksize < PTHREAD_STACK_MIN) { + if (stacksize == 0 || stacksize < PTHREAD_STACK_MIN || stacksize > PTHREAD_STACK_MAX) { return EINVAL; } - attr->stacksize = stacksize; + __set_attr_stacksize(attr, stacksize); return 0; } @@ -977,12 +979,12 @@ int pthread_attr_getstack(const pthread_attr_t *_attr, void **stackaddr, size_t { const struct pthread_attr *attr = (const struct pthread_attr *)_attr; - if ((attr == NULL) || (attr->initialized == 0U)) { + if ((attr == NULL) || (attr->initialized == false)) { return EINVAL; } *stackaddr = attr->stack; - *stacksize = attr->stacksize; + *stacksize = __get_attr_stacksize(attr); return 0; } @@ -995,7 +997,7 @@ int pthread_attr_getschedparam(const pthread_attr_t *_attr, struct sched_param * { struct pthread_attr *attr = (struct pthread_attr *)_attr; - if ((attr == NULL) || (attr->initialized == 0U)) { + if ((attr == NULL) || (attr->initialized == false)) { return EINVAL; } From a7d2c5cb32cf9fb5bb728b0f4be4f1a767dee11e Mon Sep 17 00:00:00 2001 From: Christopher Friedt Date: Wed, 13 Dec 2023 20:10:17 -0500 Subject: [PATCH 1497/3723] posix: implement pthread_getguardsize() pthread_setguardsize() Implement pthread_getguardsize() and pthread_setguardsize(). pthread_getguardsize() and pthread_setguardsize() are required by the POSIX_THREADS_EXT Option Group as detailed in Section E.1 of IEEE-1003.1-2017. However, they were formerly part of XSI_THREADS_EXT. The XSI_THREADS_EXT Option Group was required for PSE51, PSE52, PSE53, and PSE54 conformance. Signed-off-by: Christopher Friedt --- include/zephyr/posix/posix_types.h | 2 ++ include/zephyr/posix/pthread.h | 2 ++ lib/posix/Kconfig.pthread | 13 +++++++++ lib/posix/pthread.c | 44 ++++++++++++++++++++++++++++-- 4 files changed, 59 insertions(+), 2 deletions(-) diff --git a/include/zephyr/posix/posix_types.h b/include/zephyr/posix/posix_types.h index 566fd63f1fb..fb77f191bac 100644 --- a/include/zephyr/posix/posix_types.h +++ b/include/zephyr/posix/posix_types.h @@ -39,8 +39,10 @@ typedef unsigned long timer_t; struct pthread_attr { void *stack; uint16_t stacksize; + uint16_t guardsize; int8_t priority; uint8_t schedpolicy: 2; + uint8_t guardsize_msbit: 1; bool initialized: 1; bool cancelstate: 1; bool detachstate: 1; diff --git a/include/zephyr/posix/pthread.h b/include/zephyr/posix/pthread.h index d380e691d66..55d617715f5 100644 --- a/include/zephyr/posix/pthread.h +++ b/include/zephyr/posix/pthread.h @@ -428,7 +428,9 @@ static inline int pthread_rwlockattr_init(pthread_rwlockattr_t *attr) return 0; } +int pthread_attr_getguardsize(const pthread_attr_t *ZRESTRICT attr, size_t *ZRESTRICT guardsize); int pthread_attr_getstacksize(const pthread_attr_t *attr, size_t *stacksize); +int pthread_attr_setguardsize(pthread_attr_t *attr, size_t guardsize); int pthread_attr_setstacksize(pthread_attr_t *attr, size_t stacksize); int pthread_attr_setschedpolicy(pthread_attr_t *attr, int policy); int pthread_attr_getschedpolicy(const pthread_attr_t *attr, int *policy); diff --git a/lib/posix/Kconfig.pthread b/lib/posix/Kconfig.pthread index 388a30c5fa4..c27f55b68b9 100644 --- a/lib/posix/Kconfig.pthread +++ b/lib/posix/Kconfig.pthread @@ -27,4 +27,17 @@ config PTHREAD_RECYCLER_DELAY_MS Note: this option should be considered temporary and will likely be removed once a more synchronous solution is available. +config POSIX_PTHREAD_ATTR_GUARDSIZE_DEFAULT + int "Default size of stack guard area" + range 0 65536 + default 0 + help + This is the default amount of space to reserve at the overflow end of a + pthread stack. Since Zephyr already supports both software-based stack + protection (canaries) and hardware-based stack protection (MMU or MPU), + this is set to 0 by default. However, a conforming application would be + required to set this to PAGESIZE. Eventually, this option might + facilitate a more dynamic approach to guard areas (via software or + hardware) but for now it simply increases the size of thread stacks. + endif diff --git a/lib/posix/pthread.c b/lib/posix/pthread.c index 207236e085c..a1f74908f13 100644 --- a/lib/posix/pthread.c +++ b/lib/posix/pthread.c @@ -50,6 +50,17 @@ static inline void __set_attr_stacksize(struct pthread_attr *attr, size_t size) attr->stacksize = size - 1; } +static inline size_t __get_attr_guardsize(const struct pthread_attr *attr) +{ + return (attr->guardsize_msbit * BIT(16)) | attr->guardsize; +} + +static inline void __set_attr_guardsize(struct pthread_attr *attr, size_t size) +{ + attr->guardsize_msbit = size == PTHREAD_STACK_MAX; + attr->guardsize = size & BIT_MASK(16); +} + struct __pthread_cleanup { void (*routine)(void *arg); void *arg; @@ -85,8 +96,10 @@ static int pthread_concurrency; static const struct pthread_attr init_pthread_attrs = { .stack = NULL, .stacksize = 0, + .guardsize = (BIT_MASK(16) & CONFIG_POSIX_PTHREAD_ATTR_GUARDSIZE_DEFAULT), .priority = DEFAULT_PTHREAD_PRIORITY, .schedpolicy = DEFAULT_PTHREAD_POLICY, + .guardsize_msbit = (BIT(16) & CONFIG_POSIX_PTHREAD_ATTR_GUARDSIZE_DEFAULT), .initialized = true, .cancelstate = PTHREAD_CANCEL_ENABLE, .detachstate = PTHREAD_CREATE_JOINABLE, @@ -253,7 +266,7 @@ int pthread_attr_setschedparam(pthread_attr_t *_attr, const struct sched_param * int priority = schedparam->sched_priority; if (attr == NULL || !attr->initialized || - is_posix_policy_prio_valid(priority, attr->schedpolicy == false)) { + !is_posix_policy_prio_valid(priority, attr->schedpolicy)) { LOG_ERR("Invalid pthread_attr_t or sched_param"); return EINVAL; } @@ -436,7 +449,8 @@ int pthread_create(pthread_t *th, const pthread_attr_t *_attr, void *(*threadrou attr = &attr_storage; BUILD_ASSERT(DYNAMIC_STACK_SIZE <= PTHREAD_STACK_MAX); __set_attr_stacksize(attr, DYNAMIC_STACK_SIZE); - attr->stack = k_thread_stack_alloc(__get_attr_stacksize(attr), + attr->stack = k_thread_stack_alloc(__get_attr_stacksize(attr) + + __get_attr_guardsize(attr), k_is_user_context() ? K_USER : 0); if (attr->stack == NULL) { LOG_ERR("Unable to allocate stack of size %u", DYNAMIC_STACK_SIZE); @@ -988,6 +1002,32 @@ int pthread_attr_getstack(const pthread_attr_t *_attr, void **stackaddr, size_t return 0; } +int pthread_attr_getguardsize(const pthread_attr_t *ZRESTRICT _attr, size_t *ZRESTRICT guardsize) +{ + struct pthread_attr *const attr = (struct pthread_attr *)_attr; + + if (attr == NULL || guardsize == NULL || !attr->initialized) { + return EINVAL; + } + + *guardsize = __get_attr_guardsize(attr); + + return 0; +} + +int pthread_attr_setguardsize(pthread_attr_t *_attr, size_t guardsize) +{ + struct pthread_attr *const attr = (struct pthread_attr *)_attr; + + if (attr == NULL || !attr->initialized || guardsize > PTHREAD_STACK_MAX) { + return EINVAL; + } + + __set_attr_guardsize(attr, guardsize); + + return 0; +} + /** * @brief Get thread attributes object scheduling parameters. * From 5e245bd42ee87411ae60a09f16a77dd527d4e484 Mon Sep 17 00:00:00 2001 From: Christopher Friedt Date: Wed, 13 Dec 2023 19:21:50 -0500 Subject: [PATCH 1498/3723] tests: posix: tests for pthread_getguardsize() pthread_setguardsize() Add tests for pthread_getguardsize() and pthread_setguardsize(). Signed-off-by: Christopher Friedt --- tests/posix/common/src/pthread.c | 47 +++++++++++++++++++++++++++++++- 1 file changed, 46 insertions(+), 1 deletion(-) diff --git a/tests/posix/common/src/pthread.c b/tests/posix/common/src/pthread.c index 58041c7e801..cdaed3eba2e 100644 --- a/tests/posix/common/src/pthread.c +++ b/tests/posix/common/src/pthread.c @@ -17,6 +17,9 @@ #define THREAD_PRIORITY 3 #define ONE_SECOND 1 +/* arbitrary number that is also a legal stack size */ +#define OKAY_STACK_SIZE (STACKS + 42) + /* Macros to test invalid states */ #define PTHREAD_CANCEL_INVALID -1 #define SCHED_INVALID -1 @@ -572,7 +575,7 @@ ZTEST(posix_apis, test_pthread_attr_stacksize) { size_t act_size; pthread_attr_t attr; - const size_t exp_size = 0xB105F00D; + const size_t exp_size = OKAY_STACK_SIZE; /* TESTPOINT: specify a custom stack size via pthread_attr_t */ zassert_equal(0, pthread_attr_init(&attr), "pthread_attr_init() failed"); @@ -931,3 +934,45 @@ ZTEST(posix_apis, test_pthread_cleanup) zassert_ok(pthread_create(&th, NULL, test_pthread_cleanup_entry, NULL)); zassert_ok(pthread_join(th, NULL)); } + +ZTEST(posix_apis, test_pthread_attr_getguardsize) +{ + size_t size_after; + pthread_attr_t attr; + const size_t size_before = OKAY_STACK_SIZE; + + attr = (pthread_attr_t){0}; + zassert_equal(pthread_attr_getguardsize(&attr, &size_after), EINVAL); + zassert_ok(pthread_attr_init(&attr)); + zassert_equal(pthread_attr_getguardsize(NULL, NULL), EINVAL); + zassert_equal(pthread_attr_getguardsize(NULL, &size_after), EINVAL); + zassert_equal(pthread_attr_getguardsize(&attr, NULL), EINVAL); + size_after = size_before; + zassert_ok(pthread_attr_getguardsize(&attr, &size_after)); + zassert_not_equal(size_before, size_after); + zassert_equal(size_after, CONFIG_POSIX_PTHREAD_ATTR_GUARDSIZE_DEFAULT); + zassert_ok(pthread_attr_destroy(&attr)); +} + +ZTEST(posix_apis, test_pthread_attr_setguardsize) +{ + size_t size_after; + size_t size_before; + pthread_attr_t attr; + size_t sizes[] = {0, OKAY_STACK_SIZE, UINT16_MAX}; + + attr = (pthread_attr_t){0}; + zassert_equal(pthread_attr_setguardsize(&attr, 0), EINVAL); + zassert_ok(pthread_attr_init(&attr)); + zassert_equal(pthread_attr_setguardsize(NULL, SIZE_MAX), EINVAL); + zassert_equal(pthread_attr_setguardsize(NULL, 0), EINVAL); + zassert_equal(pthread_attr_setguardsize(&attr, SIZE_MAX), EINVAL); + for (size_t i = 0; i < ARRAY_SIZE(sizes); ++i) { + size_after = ~sizes[i]; + size_before = sizes[i]; + zassert_ok(pthread_attr_setguardsize(&attr, size_before)); + zassert_ok(pthread_attr_getguardsize(&attr, &size_after)); + zassert_equal(size_before, size_after); + } + zassert_ok(pthread_attr_destroy(&attr)); +} From 5c78c66fc2a57308cb03d9ce6e5e97050731ef4d Mon Sep 17 00:00:00 2001 From: Christopher Friedt Date: Wed, 13 Dec 2023 19:34:13 -0500 Subject: [PATCH 1499/3723] tests: posix: headers: check for pthread get / set guardsize Add checks to ensure that pthread_getguardsize() and pthread_setguardsize() are callable. Signed-off-by: Christopher Friedt --- tests/posix/headers/src/pthread_h.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/tests/posix/headers/src/pthread_h.c b/tests/posix/headers/src/pthread_h.c index 354a79dbfdf..82e71c5c216 100644 --- a/tests/posix/headers/src/pthread_h.c +++ b/tests/posix/headers/src/pthread_h.c @@ -64,7 +64,7 @@ ZTEST(posix_headers, test_pthread_h) zassert_not_null(pthread_atfork); zassert_not_null(pthread_attr_destroy); zassert_not_null(pthread_attr_getdetachstate); - /* zassert_not_null(pthread_attr_getguardsize); */ /* not implemented */ + zassert_not_null(pthread_attr_getguardsize); /* zassert_not_null(pthread_attr_getinheritsched); */ /* not implemented */ zassert_not_null(pthread_attr_getschedparam); zassert_not_null(pthread_attr_getschedpolicy); @@ -73,7 +73,7 @@ ZTEST(posix_headers, test_pthread_h) zassert_not_null(pthread_attr_getstacksize); zassert_not_null(pthread_attr_init); zassert_not_null(pthread_attr_setdetachstate); - /* zassert_not_null(pthread_attr_setguardsize); */ /* not implemented */ + zassert_not_null(pthread_attr_setguardsize); /* zassert_not_null(pthread_attr_setinheritsched); */ /* not implemented */ zassert_not_null(pthread_attr_setschedparam); zassert_not_null(pthread_attr_setschedpolicy); From dbd4b82f1c33efe5bb164fec4f4cb58b03445522 Mon Sep 17 00:00:00 2001 From: Christopher Friedt Date: Wed, 13 Dec 2023 19:23:20 -0500 Subject: [PATCH 1500/3723] doc: posix: support pthread_getguardsize pthread_setguardsize Mark pthread_getguardsize() and pthread_getguardsize() as supported. Signed-off-by: Christopher Friedt --- doc/services/portability/posix/option_groups/index.rst | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/doc/services/portability/posix/option_groups/index.rst b/doc/services/portability/posix/option_groups/index.rst index 5e13aea0bc9..893754f647d 100644 --- a/doc/services/portability/posix/option_groups/index.rst +++ b/doc/services/portability/posix/option_groups/index.rst @@ -77,8 +77,8 @@ This table lists service support status in Zephyr: :header: API, Supported :widths: 50,10 - pthread_attr_getguardsize(), - pthread_attr_setguardsize(), + pthread_attr_getguardsize(),yes + pthread_attr_setguardsize(),yes pthread_mutexattr_gettype(),yes pthread_mutexattr_settype(),yes From 95f8c2666a3cb6ef103d14c5aab4950fbd9ff99d Mon Sep 17 00:00:00 2001 From: Lars Knudsen Date: Tue, 12 Dec 2023 19:02:37 +0100 Subject: [PATCH 1501/3723] samples: WebUSB: Fix MS OS 2.0 descriptor The sample did not correctly select the WinUSB driver for the WebUSB interface as required on Windows when CDC ACM was included in the build configuration (the case for e.g. nRF52840 Dongle). Introduce correct function subset header in the MS OS 2.0 descriptor. Signed-off-by: Lars Knudsen --- samples/subsys/usb/webusb/src/main.c | 20 ++++++++++++++++++++ 1 file changed, 20 insertions(+) diff --git a/samples/subsys/usb/webusb/src/main.c b/samples/subsys/usb/webusb/src/main.c index d9e40d9b991..69317465877 100644 --- a/samples/subsys/usb/webusb/src/main.c +++ b/samples/subsys/usb/webusb/src/main.c @@ -40,6 +40,9 @@ LOG_MODULE_REGISTER(main); static struct msosv2_descriptor_t { struct msosv2_descriptor_set_header header; +#if defined(CONFIG_USB_CDC_ACM) + struct msosv2_function_subset_header subset_header; +#endif struct msosv2_compatible_id webusb_compatible_id; struct msosv2_guids_property webusb_guids_property; } __packed msosv2_descriptor = { @@ -52,6 +55,23 @@ static struct msosv2_descriptor_t { .dwWindowsVersion = 0x06030000, .wTotalLength = sizeof(struct msosv2_descriptor_t), }, +#if defined(CONFIG_USB_CDC_ACM) + /* If CONFIG_USB_CDC_ACM is selected, extra interfaces will be added on build time, + * making the target a composite device, which requires an extra Function + * Subset Header. + */ + .subset_header = { + .wLength = sizeof(struct msosv2_function_subset_header), + .wDescriptorType = MS_OS_20_SUBSET_HEADER_FUNCTION, + /* The WebUSB interface number becomes the first when CDC_ACM is enabled by + * configuration. Beware that if this sample is used as as inspiration for + * applications, where the WebUSB interface is no longer the first, + * remember to adjust bFirstInterface. + */ + .bFirstInterface = 0, + .wSubsetLength = 160 + }, +#endif .webusb_compatible_id = { .wLength = sizeof(struct msosv2_compatible_id), .wDescriptorType = MS_OS_20_FEATURE_COMPATIBLE_ID, From e9aa3e36a9a8153c84786778a50e71198854f54a Mon Sep 17 00:00:00 2001 From: Grzegorz Chwierut Date: Wed, 20 Dec 2023 09:51:01 +0100 Subject: [PATCH 1502/3723] twister: second fix for hardware map detection When scanning ports the manufacture field is not always filled. It must be checked before using. Signed-off-by: Grzegorz Chwierut --- scripts/pylib/twister/twisterlib/hardwaremap.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/scripts/pylib/twister/twisterlib/hardwaremap.py b/scripts/pylib/twister/twisterlib/hardwaremap.py index 438f5cf5d4a..27bca007185 100644 --- a/scripts/pylib/twister/twisterlib/hardwaremap.py +++ b/scripts/pylib/twister/twisterlib/hardwaremap.py @@ -287,7 +287,7 @@ def readlink(link): serial_devices = list_ports.comports() logger.info("Scanning connected hardware...") for d in serial_devices: - if d.manufacturer.casefold() in [m.casefold() for m in self.manufacturer]: + if d.manufacturer and d.manufacturer.casefold() in [m.casefold() for m in self.manufacturer]: # TI XDS110 can have multiple serial devices for a single board # assume endpoint 0 is the serial, skip all others From a7dccc4475f342c9b89f484f796001bc1c6d8a97 Mon Sep 17 00:00:00 2001 From: Daniel Leung Date: Mon, 11 Dec 2023 15:32:37 -0800 Subject: [PATCH 1503/3723] kernel: mmu: mitigate range check overflow issue It is possible that address + size will overflow the available address space and the pointer wraps around back to zero. Some of these have been fixed in previous commits. This fixes the remaining ones with regard to Z_PHYS_RAM_START/_END, and Z_VIRT_RAM_START/_END. Fixes #65542 Signed-off-by: Daniel Leung --- kernel/include/mmu.h | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/kernel/include/mmu.h b/kernel/include/mmu.h index 4920ac39c98..88795560e4c 100644 --- a/kernel/include/mmu.h +++ b/kernel/include/mmu.h @@ -186,7 +186,8 @@ static inline void *z_page_frame_to_virt(struct z_page_frame *pf) static inline bool z_is_page_frame(uintptr_t phys) { z_assert_phys_aligned(phys); - return (phys >= Z_PHYS_RAM_START) && (phys < Z_PHYS_RAM_END); + return IN_RANGE(phys, (uintptr_t)Z_PHYS_RAM_START, + (uintptr_t)(Z_PHYS_RAM_END - 1)); } static inline struct z_page_frame *z_phys_to_page_frame(uintptr_t phys) @@ -206,7 +207,12 @@ static inline void z_mem_assert_virtual_region(uint8_t *addr, size_t size) "unaligned size %zu", size); __ASSERT(!Z_DETECT_POINTER_OVERFLOW(addr, size), "region %p size %zu zero or wraps around", addr, size); - __ASSERT(addr >= Z_VIRT_RAM_START && addr + size < Z_VIRT_RAM_END, + __ASSERT(IN_RANGE((uintptr_t)addr, + (uintptr_t)Z_VIRT_RAM_START, + ((uintptr_t)Z_VIRT_RAM_END - 1)) && + IN_RANGE(((uintptr_t)addr + size - 1), + (uintptr_t)Z_VIRT_RAM_START, + ((uintptr_t)Z_VIRT_RAM_END - 1)), "invalid virtual address region %p (%zu)", addr, size); } From c0e6629b7bac4c7f4bd429d175b7671933fbdbf2 Mon Sep 17 00:00:00 2001 From: Fabio Baltieri Date: Tue, 19 Dec 2023 11:02:16 +0000 Subject: [PATCH 1504/3723] input: npcx_kbd: setup the interrupt to falling edge only The driver works on active low signals only, change the interrupt configuration to trigger on falling edges only. Signed-off-by: Fabio Baltieri --- drivers/input/input_npcx_kbd.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/input/input_npcx_kbd.c b/drivers/input/input_npcx_kbd.c index ba6dc398d1a..7b2469d1d5f 100644 --- a/drivers/input/input_npcx_kbd.c +++ b/drivers/input/input_npcx_kbd.c @@ -132,7 +132,7 @@ static void npcx_kbd_init_ksi_wui_callback(const struct device *dev, npcx_miwu_manage_callback(callback, 1); /* Configure MIWU setting and enable its interrupt */ - npcx_miwu_interrupt_configure(wui, NPCX_MIWU_MODE_EDGE, NPCX_MIWU_TRIG_BOTH); + npcx_miwu_interrupt_configure(wui, NPCX_MIWU_MODE_EDGE, NPCX_MIWU_TRIG_LOW); npcx_miwu_irq_enable(wui); } From 700f6409486c6f34f315d59b384e5207e885d36b Mon Sep 17 00:00:00 2001 From: Aleksander Wasaznik Date: Tue, 19 Dec 2023 09:22:11 +0100 Subject: [PATCH 1505/3723] Bluetooth: ATT: Reject read-by-uuid rsp outside range A bad peer responding to read-by-uuid can return handles outside the requested range. This confuses the stack. In particular, the "continue" and "end" logic in the same function relies on this assumption. This bad peer was a real issue at UPF, and it caused an infinite loop during discovery. Fixes: https://github.com/zephyrproject-rtos/zephyr/issues/50686 Signed-off-by: Aleksander Wasaznik --- subsys/bluetooth/host/gatt.c | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/subsys/bluetooth/host/gatt.c b/subsys/bluetooth/host/gatt.c index 0012fb3b7d5..451c3d29f7f 100644 --- a/subsys/bluetooth/host/gatt.c +++ b/subsys/bluetooth/host/gatt.c @@ -4558,6 +4558,9 @@ static void parse_read_by_uuid(struct bt_conn *conn, { const struct bt_att_read_type_rsp *rsp = pdu; + const uint16_t req_start_handle = params->by_uuid.start_handle; + const uint16_t req_end_handle = params->by_uuid.end_handle; + /* Parse values found */ for (length--, pdu = rsp->data; length; length -= rsp->len, pdu = (const uint8_t *)pdu + rsp->len) { @@ -4577,6 +4580,15 @@ static void parse_read_by_uuid(struct bt_conn *conn, LOG_DBG("handle 0x%04x len %u value %u", handle, rsp->len, len); + if (!IN_RANGE(handle, req_start_handle, req_end_handle)) { + LOG_WRN("Bad peer: ATT read-by-uuid rsp: " + "Handle 0x%04x is outside requested range 0x%04x-0x%04x. " + "Aborting read.", + handle, req_start_handle, req_end_handle); + params->func(conn, BT_ATT_ERR_UNLIKELY, params, NULL, 0); + return; + } + /* Update start_handle */ params->by_uuid.start_handle = handle; From 6d41e6835259d4c6ede50b00b0ba4b84f80eeca6 Mon Sep 17 00:00:00 2001 From: Jukka Rissanen Date: Tue, 19 Dec 2023 11:16:59 +0200 Subject: [PATCH 1506/3723] net: ipv4: Check localhost for incoming packet If we receive a packet from non localhost interface, then drop it if either source or destination address is a localhost address. Signed-off-by: Jukka Rissanen --- subsys/net/ip/ipv4.c | 10 +++++++++- subsys/net/ip/net_core.c | 2 +- subsys/net/ip/net_private.h | 6 ++++-- tests/net/icmpv4/src/main.c | 8 ++++---- tests/net/virtual/src/main.c | 2 +- 5 files changed, 19 insertions(+), 9 deletions(-) diff --git a/subsys/net/ip/ipv4.c b/subsys/net/ip/ipv4.c index fad04229c97..e873ab82650 100644 --- a/subsys/net/ip/ipv4.c +++ b/subsys/net/ip/ipv4.c @@ -232,7 +232,7 @@ int net_ipv4_parse_hdr_options(struct net_pkt *pkt, } #endif -enum net_verdict net_ipv4_input(struct net_pkt *pkt) +enum net_verdict net_ipv4_input(struct net_pkt *pkt, bool is_loopback) { NET_PKT_DATA_ACCESS_CONTIGUOUS_DEFINE(ipv4_access, struct net_ipv4_hdr); NET_PKT_DATA_ACCESS_DEFINE(udp_access, struct net_udp_hdr); @@ -293,6 +293,14 @@ enum net_verdict net_ipv4_input(struct net_pkt *pkt) net_pkt_update_length(pkt, pkt_len); } + if (!is_loopback) { + if (net_ipv4_is_addr_loopback((struct in_addr *)hdr->dst) || + net_ipv4_is_addr_loopback((struct in_addr *)hdr->src)) { + NET_DBG("DROP: localhost packet"); + goto drop; + } + } + if (net_ipv4_is_addr_mcast((struct in_addr *)hdr->src)) { NET_DBG("DROP: src addr is %s", "mcast"); goto drop; diff --git a/subsys/net/ip/net_core.c b/subsys/net/ip/net_core.c index 92e35013efc..45f489dbb46 100644 --- a/subsys/net/ip/net_core.c +++ b/subsys/net/ip/net_core.c @@ -135,7 +135,7 @@ static inline enum net_verdict process_data(struct net_pkt *pkt, if (IS_ENABLED(CONFIG_NET_IPV6) && vtc_vhl == 0x60) { return net_ipv6_input(pkt, is_loopback); } else if (IS_ENABLED(CONFIG_NET_IPV4) && vtc_vhl == 0x40) { - return net_ipv4_input(pkt); + return net_ipv4_input(pkt, is_loopback); } NET_DBG("Unknown IP family packet (0x%x)", NET_IPV6_HDR(pkt)->vtc & 0xf0); diff --git a/subsys/net/ip/net_private.h b/subsys/net/ip/net_private.h index f39049c2c60..b3fef2dee9f 100644 --- a/subsys/net/ip/net_private.h +++ b/subsys/net/ip/net_private.h @@ -107,12 +107,14 @@ static inline bool net_context_is_recv_pktinfo_set(struct net_context *context) #endif #if defined(CONFIG_NET_NATIVE) -enum net_verdict net_ipv4_input(struct net_pkt *pkt); +enum net_verdict net_ipv4_input(struct net_pkt *pkt, bool is_loopback); enum net_verdict net_ipv6_input(struct net_pkt *pkt, bool is_loopback); #else -static inline enum net_verdict net_ipv4_input(struct net_pkt *pkt) +static inline enum net_verdict net_ipv4_input(struct net_pkt *pkt, + bool is_loopback) { ARG_UNUSED(pkt); + ARG_UNUSED(is_loopback); return NET_CONTINUE; } diff --git a/tests/net/icmpv4/src/main.c b/tests/net/icmpv4/src/main.c index c48e480a769..afa5c007280 100644 --- a/tests/net/icmpv4/src/main.c +++ b/tests/net/icmpv4/src/main.c @@ -452,7 +452,7 @@ static void icmpv4_send_echo_req(void) zassert_true(false, "EchoRequest packet prep failed"); } - if (net_ipv4_input(pkt)) { + if (net_ipv4_input(pkt, false)) { net_pkt_unref(pkt); zassert_true(false, "Failed to send"); } @@ -474,7 +474,7 @@ static void icmpv4_send_echo_rep(void) zassert_true(false, "EchoReply packet prep failed"); } - if (net_ipv4_input(pkt)) { + if (net_ipv4_input(pkt, false)) { net_pkt_unref(pkt); zassert_true(false, "Failed to send"); } @@ -494,7 +494,7 @@ ZTEST(net_icmpv4, test_icmpv4_send_echo_req_opt) zassert_true(false, "EchoRequest with opts packet prep failed"); } - if (net_ipv4_input(pkt)) { + if (net_ipv4_input(pkt, false)) { net_pkt_unref(pkt); zassert_true(false, "Failed to send"); } @@ -510,7 +510,7 @@ ZTEST(net_icmpv4, test_send_echo_req_bad_opt) "EchoRequest with bad opts packet prep failed"); } - if (net_ipv4_input(pkt)) { + if (net_ipv4_input(pkt, false)) { net_pkt_unref(pkt); } } diff --git a/tests/net/virtual/src/main.c b/tests/net/virtual/src/main.c index be0ba1715b6..b124f14a5ba 100644 --- a/tests/net/virtual/src/main.c +++ b/tests/net/virtual/src/main.c @@ -1040,7 +1040,7 @@ static void test_virtual_recv_data_from_tunnel(int remote_ip, net_pkt_cursor_init(outer); if (peer_addr.sa_family == AF_INET) { - verdict = net_ipv4_input(outer); + verdict = net_ipv4_input(outer, false); } else { verdict = net_ipv6_input(outer, false); } From 19392a6d2b5eee26ba62fcc6f61e769b4cebaa32 Mon Sep 17 00:00:00 2001 From: Jukka Rissanen Date: Tue, 19 Dec 2023 12:31:37 +0200 Subject: [PATCH 1507/3723] net: ipv4: Drop packet if source address is my address If we receive a packet where the source address is our own address, then we should drop it. Signed-off-by: Jukka Rissanen --- subsys/net/ip/ipv4.c | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/subsys/net/ip/ipv4.c b/subsys/net/ip/ipv4.c index e873ab82650..1c40d8f1788 100644 --- a/subsys/net/ip/ipv4.c +++ b/subsys/net/ip/ipv4.c @@ -299,6 +299,11 @@ enum net_verdict net_ipv4_input(struct net_pkt *pkt, bool is_loopback) NET_DBG("DROP: localhost packet"); goto drop; } + + if (net_ipv4_is_my_addr((struct in_addr *)hdr->src)) { + NET_DBG("DROP: src addr is %s", "mine"); + goto drop; + } } if (net_ipv4_is_addr_mcast((struct in_addr *)hdr->src)) { From 434c93ddfbc53de7fcfc55954e4451600debe092 Mon Sep 17 00:00:00 2001 From: Jordan Yates Date: Tue, 19 Dec 2023 18:15:58 +1000 Subject: [PATCH 1508/3723] net: conn_mgr: output events as hex Networking events are masks of bits, which are almost impossible to read as decimal, and trivial to read as hex. Also unifies the format string across multiple outputs for some flash savings. Signed-off-by: Jordan Yates --- subsys/net/conn_mgr/events_handler.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/subsys/net/conn_mgr/events_handler.c b/subsys/net/conn_mgr/events_handler.c index c02787bf4fb..21677770ce3 100644 --- a/subsys/net/conn_mgr/events_handler.c +++ b/subsys/net/conn_mgr/events_handler.c @@ -24,7 +24,7 @@ static void conn_mgr_iface_events_handler(struct net_mgmt_event_callback *cb, { int idx; - NET_DBG("Iface event %u received on iface %d (%p)", mgmt_event, + NET_DBG("%s event 0x%x received on iface %d (%p)", "Iface", mgmt_event, net_if_get_by_iface(iface), iface); if ((mgmt_event & CONN_MGR_IFACE_EVENTS_MASK) != mgmt_event) { @@ -62,7 +62,7 @@ static void conn_mgr_ipv6_events_handler(struct net_mgmt_event_callback *cb, { int idx; - NET_DBG("IPv6 event %u received on iface %d (%p)", mgmt_event, + NET_DBG("%s event 0x%x received on iface %d (%p)", "IPv6", mgmt_event, net_if_get_by_iface(iface), iface); if ((mgmt_event & CONN_MGR_IPV6_EVENTS_MASK) != mgmt_event) { @@ -120,7 +120,7 @@ static void conn_mgr_ipv4_events_handler(struct net_mgmt_event_callback *cb, { int idx; - NET_DBG("IPv4 event %u received on iface %d (%p)", mgmt_event, + NET_DBG("%s event 0x%x received on iface %d (%p)", "IPv4", mgmt_event, net_if_get_by_iface(iface), iface); if ((mgmt_event & CONN_MGR_IPV4_EVENTS_MASK) != mgmt_event) { From 1ef0ec55c9b2d6b4697dc9bcf2b5bf5bbe956fbd Mon Sep 17 00:00:00 2001 From: Jordan Yates Date: Tue, 19 Dec 2023 18:18:50 +1000 Subject: [PATCH 1509/3723] net: ip: dhcpv4: remove address on interface down Any received address is no longer valid once the interface goes down. Leaving the address assigned results in the L4 interface transitioning through the following on reconnection: UP: Interface is connected DOWN: Old address is removed by DHCP UP: New address is re-added by DHCP Signed-off-by: Jordan Yates --- subsys/net/ip/dhcpv4.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/subsys/net/ip/dhcpv4.c b/subsys/net/ip/dhcpv4.c index 918b71d1d6b..6285952e440 100644 --- a/subsys/net/ip/dhcpv4.c +++ b/subsys/net/ip/dhcpv4.c @@ -1163,6 +1163,10 @@ static void dhcpv4_iface_event_handler(struct net_mgmt_event_callback *cb, iface->config.dhcpv4.state = NET_DHCPV4_RENEWING; NET_DBG("enter state=%s", net_dhcpv4_state_name( iface->config.dhcpv4.state)); + /* Remove any bound address as interface is gone */ + if (!net_if_ipv4_addr_rm(iface, &iface->config.dhcpv4.requested_ip)) { + NET_DBG("Failed to remove addr from iface"); + } } } else if (mgmt_event == NET_EVENT_IF_UP) { NET_DBG("Interface %p coming up", iface); From f772bd11069a9646eb689c379aadd85385d468ff Mon Sep 17 00:00:00 2001 From: Anas Nashif Date: Tue, 19 Dec 2023 08:33:55 -0500 Subject: [PATCH 1510/3723] ci: codecov: use gcovr and upload cobertura style file Use gcovr to generate reports and upload cobertura style file instead of previously lcov info file. We have been seeing issues with lcov format and code being reporting as not covered although by inspecting the generate output files, they should be. The XML format we generate is otherwise easier to parse and deal with. Also reduce frequency to twice a day. Fixes #66656 Signed-off-by: Anas Nashif --- .github/workflows/codecov.yaml | 38 +++++++++++++++++----------------- 1 file changed, 19 insertions(+), 19 deletions(-) diff --git a/.github/workflows/codecov.yaml b/.github/workflows/codecov.yaml index 9e841025993..6eb6e79b86b 100644 --- a/.github/workflows/codecov.yaml +++ b/.github/workflows/codecov.yaml @@ -2,7 +2,7 @@ name: Code Coverage with codecov on: schedule: - - cron: '25 */3 * * 1-5' + - cron: '25 06,18 * * 1-5' concurrency: group: ${{ github.workflow }}-${{ github.event_name }}-${{ github.head_ref || github.ref }} @@ -88,27 +88,25 @@ jobs: export ZEPHYR_BASE=${PWD} export ZEPHYR_TOOLCHAIN_VARIANT=zephyr mkdir -p coverage/reports - ./scripts/twister --force-color -N -v --filter runnable -p ${{ matrix.platform }} --coverage -T tests - - - name: Generate Coverage Report - run: | - mv twister-out/coverage.info lcov.pre.info - lcov -q --remove lcov.pre.info mylib.c --remove lcov.pre.info tests/\* \ - --remove lcov.pre.info samples/\* --remove lcov.pre.info ext/\* \ - --remove lcov.pre.info *generated* \ - -o coverage/reports/${{ matrix.platform }}.info --rc lcov_branch_coverage=1 + pip3 install gcovr + ./scripts/twister -i --force-color -N -v --filter runnable -p ${{ matrix.platform }} --coverage -T tests --coverage-tool gcovr - name: ccache stats post run: | ccache -s ccache -p + - name: Rename coverage files + if: always() + run: | + cp twister-out/coverage.json coverage/reports/${{ matrix.platform }}.json + - name: Upload Coverage Results if: always() uses: actions/upload-artifact@v3 with: name: Coverage Data (Subset ${{ matrix.platform }}) - path: coverage/reports/${{ matrix.platform }}.info + path: coverage/reports/${{ matrix.platform }}.json codecov-results: name: "Publish Coverage Results" @@ -129,14 +127,14 @@ jobs: - name: Move coverage files run: | - mv ./coverage/reports/*/*.info ./coverage/reports + mv ./coverage/reports/*/*.json ./coverage/reports ls -la ./coverage/reports - name: Generate list of coverage files id: get-coverage-files shell: cmake -P {0} run: | - file(GLOB INPUT_FILES_LIST "coverage/reports/*.info") + file(GLOB INPUT_FILES_LIST "coverage/reports/*.json") set(MERGELIST "") set(FILELIST "") foreach(ITEM ${INPUT_FILES_LIST}) @@ -150,7 +148,7 @@ jobs: foreach(ITEM ${INPUT_FILES_LIST}) get_filename_component(f ${ITEM} NAME) if(MERGELIST STREQUAL "") - set(MERGELIST "-a ${f}") + set(MERGELIST "--add-tracefile ${f}") else() set(MERGELIST "${MERGELIST} -a ${f}") endif() @@ -160,17 +158,19 @@ jobs: - name: Merge coverage files run: | - sudo apt-get update - sudo apt-get install -y lcov cd ./coverage/reports - lcov ${{ steps.get-coverage-files.outputs.mergefiles }} -o merged.info --rc lcov_branch_coverage=1 + pip3 install gcovr + gcovr ${{ steps.get-coverage-files.outputs.mergefiles }} --merge-mode-functions=separate --json merged.json + gcovr ${{ steps.get-coverage-files.outputs.mergefiles }} --merge-mode-functions=separate --cobertura merged.xml - name: Upload Merged Coverage Results if: always() uses: actions/upload-artifact@v3 with: name: Merged Coverage Data - path: merged.info + path: | + coverage/reports/merged.json + coverage/reports/merged.xml - name: Upload coverage to Codecov if: always() @@ -180,4 +180,4 @@ jobs: env_vars: OS,PYTHON fail_ci_if_error: false verbose: true - files: merged.info + files: merged.xml From 05315ea6afe7f205a3088c397cf1afdff1e84e4e Mon Sep 17 00:00:00 2001 From: Anas Nashif Date: Tue, 19 Dec 2023 08:37:58 -0500 Subject: [PATCH 1511/3723] kernel: fatal: remove LCOV exclusion line is already excluded as part of the function. Signed-off-by: Anas Nashif --- kernel/fatal.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/kernel/fatal.c b/kernel/fatal.c index 688c9030a1b..dae2eb60950 100644 --- a/kernel/fatal.c +++ b/kernel/fatal.c @@ -42,7 +42,7 @@ __weak void k_sys_fatal_error_handler(unsigned int reason, LOG_PANIC(); LOG_ERR("Halting system"); arch_system_halt(reason); - CODE_UNREACHABLE; /* LCOV_EXCL_LINE */ + CODE_UNREACHABLE; } /* LCOV_EXCL_STOP */ From 8bfa8556b0d109e3d5cd67d1eb712eca50dfe6aa Mon Sep 17 00:00:00 2001 From: Anas Nashif Date: Tue, 19 Dec 2023 08:56:04 -0500 Subject: [PATCH 1512/3723] ci: codecov: add mps2_an385 as a coverage platform Add one more ARM based platform to get more code coverage. Signed-off-by: Anas Nashif --- .github/workflows/codecov.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/codecov.yaml b/.github/workflows/codecov.yaml index 6eb6e79b86b..57ea8b0f3c9 100644 --- a/.github/workflows/codecov.yaml +++ b/.github/workflows/codecov.yaml @@ -20,7 +20,7 @@ jobs: strategy: fail-fast: false matrix: - platform: ["native_sim", "qemu_x86", "unit_testing"] + platform: ["mps2_an385", "native_sim", "qemu_x86", "unit_testing"] env: ZEPHYR_SDK_INSTALL_DIR: /opt/toolchains/zephyr-sdk-0.16.4 steps: From 2b43582236093fa656a28a399e70289ef0c8f5df Mon Sep 17 00:00:00 2001 From: Anas Nashif Date: Tue, 19 Dec 2023 10:06:48 -0500 Subject: [PATCH 1513/3723] tests: add a tag for nano libc tests tag nano libc tests with nano so we can exclude them if needed. Now they cause issues when collecting coverage information from tests. Signed-off-by: Anas Nashif --- tests/kernel/common/testcase.yaml | 4 ++++ tests/lib/cbprintf_package/testcase.yaml | 4 ++++ 2 files changed, 8 insertions(+) diff --git a/tests/kernel/common/testcase.yaml b/tests/kernel/common/testcase.yaml index 7ed13606b86..91e505c85a4 100644 --- a/tests/kernel/common/testcase.yaml +++ b/tests/kernel/common/testcase.yaml @@ -29,11 +29,15 @@ tests: extra_configs: - CONFIG_MINIMAL_LIBC=y kernel.common.nano32: + tags: + - nano filter: not CONFIG_KERNEL_COHERENCE extra_configs: - CONFIG_CBPRINTF_NANO=y - CONFIG_CBPRINTF_REDUCED_INTEGRAL=y kernel.common.nano64: + tags: + - nano filter: not CONFIG_KERNEL_COHERENCE extra_configs: - CONFIG_CBPRINTF_NANO=y diff --git a/tests/lib/cbprintf_package/testcase.yaml b/tests/lib/cbprintf_package/testcase.yaml index 4a07f4ec788..f1761003c8a 100644 --- a/tests/lib/cbprintf_package/testcase.yaml +++ b/tests/lib/cbprintf_package/testcase.yaml @@ -61,6 +61,8 @@ tests: - native_sim libraries.cbprintf.package_nano: + tags: + - nano extra_configs: - CONFIG_CBPRINTF_NANO=y integration_platforms: @@ -129,6 +131,8 @@ tests: - native_sim libraries.cbprintf.package_nano_cpp: + tags: + - nano extra_configs: - CONFIG_CPP=y - CONFIG_CBPRINTF_NANO=y From 0175f9627b9d1b31717d17a3bad0d48fb24bc702 Mon Sep 17 00:00:00 2001 From: Anas Nashif Date: Tue, 19 Dec 2023 11:32:39 -0500 Subject: [PATCH 1514/3723] ci: codecov: increase stack size for tests Increase stack size for tests and exclude nono libc scenarios causing some issues with coverage collection. Signed-off-by: Anas Nashif --- .github/workflows/codecov.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/codecov.yaml b/.github/workflows/codecov.yaml index 57ea8b0f3c9..85545cdc712 100644 --- a/.github/workflows/codecov.yaml +++ b/.github/workflows/codecov.yaml @@ -89,7 +89,7 @@ jobs: export ZEPHYR_TOOLCHAIN_VARIANT=zephyr mkdir -p coverage/reports pip3 install gcovr - ./scripts/twister -i --force-color -N -v --filter runnable -p ${{ matrix.platform }} --coverage -T tests --coverage-tool gcovr + ./scripts/twister -i --force-color -N -v --filter runnable -p ${{ matrix.platform }} --coverage -T tests --coverage-tool gcovr -xCONFIG_TEST_EXTRA_STACK_SIZE=4096 -e nano - name: ccache stats post run: | From 29084585544472b30d7fb3212ca33a3816b0a85b Mon Sep 17 00:00:00 2001 From: Erwan Gouriou Date: Tue, 19 Dec 2023 14:37:37 +0100 Subject: [PATCH 1515/3723] soc: stm32wba: hci_if: Implement HW_RNG_EnableClock API STM32WBA controller uses a PKA driver to perform cyphering operations on keys. Since PKA hardware block requires RNG clock to be enabled, a synchronization with zephyr RNG driver is needed. Use RNG enable status to check if RNG could be switched off or needs to be switched on. Similarly in entropy driver, don't cut RNG clock if PKA is enabled. Signed-off-by: Erwan Gouriou --- drivers/entropy/entropy_stm32.c | 5 ++ soc/arm/st_stm32/stm32wba/hci_if/bleplat.c | 61 ++++++++++++++++++++-- 2 files changed, 61 insertions(+), 5 deletions(-) diff --git a/drivers/entropy/entropy_stm32.c b/drivers/entropy/entropy_stm32.c index bb3ba116345..910a40c6640 100644 --- a/drivers/entropy/entropy_stm32.c +++ b/drivers/entropy/entropy_stm32.c @@ -22,6 +22,7 @@ #include #include #include +#include #include #include #include @@ -116,6 +117,10 @@ static int entropy_stm32_suspend(void) #ifdef CONFIG_SOC_SERIES_STM32WBAX uint32_t wait_cycles, rng_rate; + if (LL_PKA_IsEnabled(PKA)) { + return 0; + } + if (clock_control_get_rate(dev_data->clock, (clock_control_subsys_t) &dev_cfg->pclken[0], &rng_rate) < 0) { diff --git a/soc/arm/st_stm32/stm32wba/hci_if/bleplat.c b/soc/arm/st_stm32/stm32wba/hci_if/bleplat.c index 7c1ed1aa962..d7d66b34514 100644 --- a/soc/arm/st_stm32/stm32wba/hci_if/bleplat.c +++ b/soc/arm/st_stm32/stm32wba/hci_if/bleplat.c @@ -7,6 +7,10 @@ #include #include #include +#include +#include + +#include #include "bleplat.h" #include "bpka.h" @@ -16,7 +20,15 @@ LOG_MODULE_REGISTER(ble_plat); RAMCFG_HandleTypeDef hramcfg_SRAM1; -const struct device *rng_dev; +const struct device *rng_dev = DEVICE_DT_GET(DT_CHOSEN(zephyr_entropy)); + +struct entropy_stm32_rng_dev_data { + RNG_TypeDef *rng; +}; + +struct entropy_stm32_rng_dev_cfg { + struct stm32_pclken *pclken; +}; void BLEPLAT_Init(void) { @@ -92,9 +104,48 @@ void Error_Handler(void) LOG_ERR(""); } +void enable_rng_clock(bool enable) +{ + const struct entropy_stm32_rng_dev_cfg *dev_cfg = rng_dev->config; + struct entropy_stm32_rng_dev_data *dev_data = rng_dev->data; + struct stm32_pclken *rng_pclken; + const struct device *rcc; + unsigned int key; + + rcc = DEVICE_DT_GET(STM32_CLOCK_CONTROL_NODE); + rng_pclken = (clock_control_subsys_t)&dev_cfg->pclken[0]; + + key = irq_lock(); + + /* Enable/Disable RNG clock only if not in use */ + if (!LL_RNG_IsEnabled((RNG_TypeDef *)dev_data->rng)) { + if (enable) { + clock_control_on(rcc, rng_pclken); + } else { + clock_control_off(rcc, rng_pclken); + } + } + + irq_unlock(key); +} + +/* PKA IP requires RNG clock to be enabled + * These APIs are used by BLE controller to enable/disable RNG clock, + * based on PKA needs. + */ +void HW_RNG_DisableClock(uint8_t user_mask) +{ + ARG_UNUSED(user_mask); + + enable_rng_clock(false); +} + +void HW_RNG_EnableClock(uint8_t user_mask) +{ + ARG_UNUSED(user_mask); + + enable_rng_clock(true); +} + /* BLE ctlr should not disable HSI on its own */ void SCM_HSI_CLK_OFF(void) {} - -/* BLE ctlr should not alter RNG clocks */ -void HW_RNG_DisableClock(uint8_t) {} -void HW_RNG_EnableClock(uint8_t) {} From 7c09139d6f2c59074c019eec7addec5dbe5e40e1 Mon Sep 17 00:00:00 2001 From: Erwan Gouriou Date: Wed, 28 Sep 2022 09:22:07 +0200 Subject: [PATCH 1516/3723] west.yml: Use STM32WBA BLE lib with Flash manager Flash coexistence facility is provided by a dedicated BLE controller driver added in hal_stm32 WBA lib. Signed-off-by: Erwan Gouriou --- west.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/west.yml b/west.yml index 47d6da5a1b6..49d94d9a9ba 100644 --- a/west.yml +++ b/west.yml @@ -229,7 +229,7 @@ manifest: groups: - hal - name: hal_stm32 - revision: d183c9c9f56dfed04da0b8e150424177ab9ce51e + revision: 22925907a6faeb601fc9a0d8cbb65c4b26d38043 path: modules/hal/stm32 groups: - hal From f6555aa95ec10566cdce551024cf80ce867ce30a Mon Sep 17 00:00:00 2001 From: Erwan Gouriou Date: Tue, 19 Dec 2023 17:07:37 +0100 Subject: [PATCH 1517/3723] drivers: flash: stm32wba: Use STM32WBA Flash manager for RF coexistence When Bluetooth is enabled, it is required to arbitrate flash accesses between RF and write accesses (for user activity). A dedicated flash manager is provided as part of STM32WBA BLE lib. Implement a dedicated driver using FM Apis to handle RF activity. Signed-off-by: Erwan Gouriou --- drivers/flash/CMakeLists.txt | 32 ++-- drivers/flash/Kconfig.stm32 | 2 + drivers/flash/flash_stm32wba_fm.c | 241 ++++++++++++++++++++++++++++++ 3 files changed, 263 insertions(+), 12 deletions(-) create mode 100644 drivers/flash/flash_stm32wba_fm.c diff --git a/drivers/flash/CMakeLists.txt b/drivers/flash/CMakeLists.txt index 4a02268a2b4..75bafb85941 100644 --- a/drivers/flash/CMakeLists.txt +++ b/drivers/flash/CMakeLists.txt @@ -68,20 +68,28 @@ endif() if(CONFIG_SOC_FLASH_STM32) if(CONFIG_SOC_SERIES_STM32H7X) zephyr_library_sources_ifdef(CONFIG_DT_HAS_ST_STM32H7_FLASH_CONTROLLER_ENABLED flash_stm32h7x.c) + elseif(CONFIG_SOC_SERIES_STM32WBAX) + if(CONFIG_BT_STM32WBA) + # BLE is enabled. Use implementation over Flash Manager for coexistence wit RF activities + zephyr_library_sources(flash_stm32wba_fm.c) + else() + zephyr_library_sources_ifdef(CONFIG_DT_HAS_ST_STM32_FLASH_CONTROLLER_ENABLED flash_stm32.c flash_stm32wbax.c) + endif() else() - zephyr_library_sources(flash_stm32.c) - zephyr_library_sources_ifdef(CONFIG_FLASH_EX_OP_ENABLED flash_stm32_ex_op.c) + if(CONFIG_DT_HAS_ST_STM32_FLASH_CONTROLLER_ENABLED) + zephyr_library_sources(flash_stm32.c) + zephyr_library_sources_ifdef(CONFIG_FLASH_EX_OP_ENABLED flash_stm32_ex_op.c) - zephyr_library_sources_ifdef(CONFIG_DT_HAS_ST_STM32F1_FLASH_CONTROLLER_ENABLED flash_stm32f1x.c) - zephyr_library_sources_ifdef(CONFIG_DT_HAS_ST_STM32F2_FLASH_CONTROLLER_ENABLED flash_stm32f2x.c) - zephyr_library_sources_ifdef(CONFIG_DT_HAS_ST_STM32F4_FLASH_CONTROLLER_ENABLED flash_stm32f4x.c) - zephyr_library_sources_ifdef(CONFIG_DT_HAS_ST_STM32F7_FLASH_CONTROLLER_ENABLED flash_stm32f7x.c) - zephyr_library_sources_ifdef(CONFIG_DT_HAS_ST_STM32L4_FLASH_CONTROLLER_ENABLED flash_stm32l4x.c) - zephyr_library_sources_ifdef(CONFIG_DT_HAS_ST_STM32L5_FLASH_CONTROLLER_ENABLED flash_stm32l5x.c) - zephyr_library_sources_ifdef(CONFIG_DT_HAS_ST_STM32WB_FLASH_CONTROLLER_ENABLED flash_stm32wbx.c) - zephyr_library_sources_ifdef(CONFIG_DT_HAS_ST_STM32G0_FLASH_CONTROLLER_ENABLED flash_stm32g0x.c) - zephyr_library_sources_ifdef(CONFIG_DT_HAS_ST_STM32G4_FLASH_CONTROLLER_ENABLED flash_stm32g4x.c) - zephyr_library_sources_ifdef(CONFIG_DT_HAS_ST_STM32WBA_FLASH_CONTROLLER_ENABLED flash_stm32wbax.c) + zephyr_library_sources_ifdef(CONFIG_DT_HAS_ST_STM32F1_FLASH_CONTROLLER_ENABLED flash_stm32f1x.c) + zephyr_library_sources_ifdef(CONFIG_DT_HAS_ST_STM32F2_FLASH_CONTROLLER_ENABLED flash_stm32f2x.c) + zephyr_library_sources_ifdef(CONFIG_DT_HAS_ST_STM32F4_FLASH_CONTROLLER_ENABLED flash_stm32f4x.c) + zephyr_library_sources_ifdef(CONFIG_DT_HAS_ST_STM32F7_FLASH_CONTROLLER_ENABLED flash_stm32f7x.c) + zephyr_library_sources_ifdef(CONFIG_DT_HAS_ST_STM32L4_FLASH_CONTROLLER_ENABLED flash_stm32l4x.c) + zephyr_library_sources_ifdef(CONFIG_DT_HAS_ST_STM32L5_FLASH_CONTROLLER_ENABLED flash_stm32l5x.c) + zephyr_library_sources_ifdef(CONFIG_DT_HAS_ST_STM32WB_FLASH_CONTROLLER_ENABLED flash_stm32wbx.c) + zephyr_library_sources_ifdef(CONFIG_DT_HAS_ST_STM32G0_FLASH_CONTROLLER_ENABLED flash_stm32g0x.c) + zephyr_library_sources_ifdef(CONFIG_DT_HAS_ST_STM32G4_FLASH_CONTROLLER_ENABLED flash_stm32g4x.c) + endif() endif() endif() diff --git a/drivers/flash/Kconfig.stm32 b/drivers/flash/Kconfig.stm32 index 5344d818322..a452ab8b98d 100644 --- a/drivers/flash/Kconfig.stm32 +++ b/drivers/flash/Kconfig.stm32 @@ -14,6 +14,8 @@ config SOC_FLASH_STM32 select FLASH_PAGE_LAYOUT select FLASH_HAS_PAGE_LAYOUT select MPU_ALLOW_FLASH_WRITE if ARM_MPU + select USE_STM32_HAL_FLASH if BT_STM32WBA + select USE_STM32_HAL_FLASH_EX if BT_STM32WBA help Enable flash driver for STM32 series diff --git a/drivers/flash/flash_stm32wba_fm.c b/drivers/flash/flash_stm32wba_fm.c new file mode 100644 index 00000000000..2628f650dcc --- /dev/null +++ b/drivers/flash/flash_stm32wba_fm.c @@ -0,0 +1,241 @@ +/* + * Copyright (c) 2023 STMicroelectronics + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include +#include +#include +#include + +#define DT_DRV_COMPAT st_stm32wba_flash_controller + +#include +LOG_MODULE_REGISTER(flash_stm32wba, CONFIG_FLASH_LOG_LEVEL); + +#include "flash_stm32.h" +#include "flash_manager.h" +#include "flash_driver.h" + +/* Let's wait for double the max erase time to be sure that the operation is + * completed. + */ +#define STM32_FLASH_TIMEOUT \ + (2 * DT_PROP(DT_INST(0, st_stm32_nv_flash), max_erase_time)) + +extern struct k_work_q ble_ctlr_work_q; +struct k_work fm_work; + +static const struct flash_parameters flash_stm32_parameters = { + .write_block_size = FLASH_STM32_WRITE_BLOCK_SIZE, + .erase_value = 0xff, +}; + +K_SEM_DEFINE(flash_busy, 0, 1); + +static void flash_callback(FM_FlashOp_Status_t status) +{ + LOG_DBG("%d", status); + + k_sem_give(&flash_busy); +} + +struct FM_CallbackNode cb_ptr = { + .Callback = flash_callback +}; + +void FM_ProcessRequest(void) +{ + k_work_submit_to_queue(&ble_ctlr_work_q, &fm_work); +} + +void FM_BackgroundProcess_Entry(struct k_work *work) +{ + ARG_UNUSED(work); + + FM_BackgroundProcess(); +} + +bool flash_stm32_valid_range(const struct device *dev, off_t offset, + uint32_t len, bool write) +{ + if (write && !flash_stm32_valid_write(offset, len)) { + return false; + } + return flash_stm32_range_exists(dev, offset, len); +} + + +static inline void flash_stm32_sem_take(const struct device *dev) +{ + k_sem_take(&FLASH_STM32_PRIV(dev)->sem, K_FOREVER); +} + +static inline void flash_stm32_sem_give(const struct device *dev) +{ + k_sem_give(&FLASH_STM32_PRIV(dev)->sem); +} + +static int flash_stm32_read(const struct device *dev, off_t offset, + void *data, + size_t len) +{ + if (!flash_stm32_valid_range(dev, offset, len, false)) { + LOG_ERR("Read range invalid. Offset: %p, len: %zu", + (void *) offset, len); + return -EINVAL; + } + + if (!len) { + return 0; + } + + flash_stm32_sem_take(dev); + + memcpy(data, (uint8_t *) CONFIG_FLASH_BASE_ADDRESS + offset, len); + + flash_stm32_sem_give(dev); + + return 0; +} + +static int flash_stm32_erase(const struct device *dev, off_t offset, + size_t len) +{ + int rc; + int sect_num = (len / FLASH_PAGE_SIZE) + 1; + + if (!flash_stm32_valid_range(dev, offset, len, true)) { + LOG_ERR("Erase range invalid. Offset: %p, len: %zu", + (void *)offset, len); + return -EINVAL; + } + + if (!len) { + return 0; + } + + flash_stm32_sem_take(dev); + + LOG_DBG("Erase offset: %p, page: %ld, len: %zu, sect num: %d", + (void *)offset, offset / FLASH_PAGE_SIZE, len, sect_num); + + rc = FM_Erase(offset / FLASH_PAGE_SIZE, sect_num, &cb_ptr); + if (rc == 0) { + k_sem_take(&flash_busy, K_FOREVER); + } else { + LOG_DBG("Erase operation rejected. err = %d", rc); + } + + flash_stm32_sem_give(dev); + + return rc; +} + +static int flash_stm32_write(const struct device *dev, off_t offset, + const void *data, size_t len) +{ + int rc; + + if (!flash_stm32_valid_range(dev, offset, len, true)) { + LOG_ERR("Write range invalid. Offset: %p, len: %zu", + (void *)offset, len); + return -EINVAL; + } + + if (!len) { + return 0; + } + + flash_stm32_sem_take(dev); + + LOG_DBG("Write offset: %p, len: %zu", (void *)offset, len); + + rc = FM_Write((uint32_t *)data, + (uint32_t *)(CONFIG_FLASH_BASE_ADDRESS + offset), + (int32_t)len/4, &cb_ptr); + if (rc == 0) { + k_sem_take(&flash_busy, K_FOREVER); + } else { + LOG_DBG("Write operation rejected. err = %d", rc); + } + + flash_stm32_sem_give(dev); + + return rc; +} + +static const struct flash_parameters * + flash_stm32_get_parameters(const struct device *dev) +{ + ARG_UNUSED(dev); + + return &flash_stm32_parameters; +} + +static struct flash_stm32_priv flash_data = { + .regs = (FLASH_TypeDef *) DT_INST_REG_ADDR(0), +}; + +void flash_stm32wba_page_layout(const struct device *dev, + const struct flash_pages_layout **layout, + size_t *layout_size) +{ + static struct flash_pages_layout stm32wba_flash_layout = { + .pages_count = 0, + .pages_size = 0, + }; + + ARG_UNUSED(dev); + + if (stm32wba_flash_layout.pages_count == 0) { + stm32wba_flash_layout.pages_count = FLASH_SIZE / FLASH_PAGE_SIZE; + stm32wba_flash_layout.pages_size = FLASH_PAGE_SIZE; + } + + *layout = &stm32wba_flash_layout; + *layout_size = 1; +} + +static const struct flash_driver_api flash_stm32_api = { + .erase = flash_stm32_erase, + .write = flash_stm32_write, + .read = flash_stm32_read, + .get_parameters = flash_stm32_get_parameters, +#ifdef CONFIG_FLASH_PAGE_LAYOUT + .page_layout = flash_stm32wba_page_layout, +#endif +}; + +static int stm32_flash_init(const struct device *dev) +{ + k_sem_init(&FLASH_STM32_PRIV(dev)->sem, 1, 1); + + LOG_DBG("Flash initialized. BS: %zu", + flash_stm32_parameters.write_block_size); + + k_work_init(&fm_work, &FM_BackgroundProcess_Entry); + + /* Enable flash driver system flag */ + FD_SetStatus(FD_FLASHACCESS_RFTS, LL_FLASH_DISABLE); + FD_SetStatus(FD_FLASHACCESS_RFTS_BYPASS, LL_FLASH_ENABLE); + FD_SetStatus(FD_FLASHACCESS_SYSTEM, LL_FLASH_ENABLE); + +#if ((CONFIG_FLASH_LOG_LEVEL >= LOG_LEVEL_DBG) && CONFIG_FLASH_PAGE_LAYOUT) + const struct flash_pages_layout *layout; + size_t layout_size; + + flash_stm32wba_page_layout(dev, &layout, &layout_size); + for (size_t i = 0; i < layout_size; i++) { + LOG_DBG("Block %zu: bs: %zu count: %zu", i, + layout[i].pages_size, layout[i].pages_count); + } +#endif + + return 0; +} + +DEVICE_DT_INST_DEFINE(0, stm32_flash_init, NULL, + &flash_data, NULL, POST_KERNEL, + CONFIG_FLASH_INIT_PRIORITY, &flash_stm32_api); From c81e2ff68a55ec64819e6ae267992342df4b626b Mon Sep 17 00:00:00 2001 From: Erwan Gouriou Date: Tue, 19 Dec 2023 17:08:29 +0100 Subject: [PATCH 1518/3723] boards: nucleo_wba52cg: Add a user flash partition This partition could be used by application. Signed-off-by: Erwan Gouriou --- boards/arm/nucleo_wba55cg/nucleo_wba55cg.dts | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/boards/arm/nucleo_wba55cg/nucleo_wba55cg.dts b/boards/arm/nucleo_wba55cg/nucleo_wba55cg.dts index b0510c624ad..163a1bb5ae2 100644 --- a/boards/arm/nucleo_wba55cg/nucleo_wba55cg.dts +++ b/boards/arm/nucleo_wba55cg/nucleo_wba55cg.dts @@ -133,3 +133,18 @@ stm32_lp_tick_source: &lptim1 { &rng { status = "okay"; }; + +&flash0 { + partitions { + compatible = "fixed-partitions"; + #address-cells = <1>; + #size-cells = <1>; + + /* Last 16K of flash: Min 2 sectors */ + storage_partition: partition@f8000 { + label = "storage"; + reg = <0x000f8000 DT_SIZE_K(16)>; + }; + + }; +}; From 098df08bbc7f2a29729383a5ceea75338a7f2f84 Mon Sep 17 00:00:00 2001 From: Erwan Gouriou Date: Tue, 19 Dec 2023 17:10:56 +0100 Subject: [PATCH 1519/3723] drivers: bluetooth: stm32wba: Configure flash manager Configure flash manager at BLE init. Signed-off-by: Erwan Gouriou --- drivers/bluetooth/hci/hci_stm32wba.c | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/drivers/bluetooth/hci/hci_stm32wba.c b/drivers/bluetooth/hci/hci_stm32wba.c index 357c3a8dac4..0b9aad74a6e 100644 --- a/drivers/bluetooth/hci/hci_stm32wba.c +++ b/drivers/bluetooth/hci/hci_stm32wba.c @@ -21,8 +21,7 @@ #include "blestack.h" #include "app_conf.h" #include "ll_sys.h" -/* TODO: Enable Flash Manager once available */ -/* #include "flash_driver.h" */ +#include "flash_driver.h" #define LOG_LEVEL CONFIG_BT_HCI_DRIVER_LOG_LEVEL #include @@ -360,7 +359,9 @@ static int bt_hci_stm32wba_open(void) ret = bt_ble_ctlr_init(); /* TODO. Enable Flash manager once available */ - /* FD_SetStatus(FD_FLASHACCESS_RFTS_BYPASS, LL_FLASH_DISABLE); */ + if (IS_ENABLED(CONFIG_FLASH)) { + FD_SetStatus(FD_FLASHACCESS_RFTS_BYPASS, LL_FLASH_DISABLE); + } return ret; } From ed5352ffcee186368fdfc60b9589c788deb52f09 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Benjamin=20Cab=C3=A9?= Date: Wed, 8 Nov 2023 10:45:15 +0100 Subject: [PATCH 1520/3723] coc: Update Code of Conduct to latest Contributor Covenant MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit As per the changelog of the Contributor Covenant between versions 1.4 and 2.1, the main changes are: 2.0 - Emphasizes 'community' over 'project' scope, effectively merging the Community Covenant into the Contributor Covenant - Adds expectation about accepting responsibility and apologizing to those affected by mistakes, and learning from the experience to the list - Adds sexual attention and advances of any kind as unacceptable behavior example - Moves enforcement responsibilities from project maintainers to community leaders - Adds responsibility to communicate reasons for moderation decisions when removing, editing, or rejecting contributions not aligned to the Code of Conduct - Requires community leaders to respect privacy and security of the reporter of any incident, not just confidentiality - Provides a template for code of conduct enforcement 2.1 - Adds 'caste' and 'color' to the preamble Signed-off-by: Benjamin Cabé --- CODE_OF_CONDUCT.md | 163 +++++++++++++++++++++++++++++++-------------- 1 file changed, 112 insertions(+), 51 deletions(-) diff --git a/CODE_OF_CONDUCT.md b/CODE_OF_CONDUCT.md index 18d668a1332..f81c519c783 100644 --- a/CODE_OF_CONDUCT.md +++ b/CODE_OF_CONDUCT.md @@ -2,77 +2,138 @@ ## Our Pledge -In the interest of fostering an open and welcoming environment, we as -contributors and maintainers pledge to making participation in our project and -our community a harassment-free experience for everyone, regardless of age, body -size, disability, ethnicity, sex characteristics, gender identity and expression, -level of experience, education, socio-economic status, nationality, personal -appearance, race, religion, or sexual identity and orientation. +We as members, contributors, and leaders pledge to make participation in our +community a harassment-free experience for everyone, regardless of age, body +size, visible or invisible disability, ethnicity, sex characteristics, gender +identity and expression, level of experience, education, socio-economic status, +nationality, personal appearance, race, caste, color, religion, or sexual +identity and orientation. + +We pledge to act and interact in ways that contribute to an open, welcoming, +diverse, inclusive, and healthy community. ## Our Standards -Examples of behavior that contributes to creating a positive environment -include: +Examples of behavior that contributes to a positive environment for our +community include: -* Using welcoming and inclusive language -* Being respectful of differing viewpoints and experiences -* Gracefully accepting constructive criticism -* Focusing on what is best for the community -* Showing empathy towards other community members +* Demonstrating empathy and kindness toward other people +* Being respectful of differing opinions, viewpoints, and experiences +* Giving and gracefully accepting constructive feedback +* Accepting responsibility and apologizing to those affected by our mistakes, + and learning from the experience +* Focusing on what is best not just for us as individuals, but for the overall + community -Examples of unacceptable behavior by participants include: +Examples of unacceptable behavior include: -* The use of sexualized language or imagery and unwelcome sexual attention or - advances -* Trolling, insulting/derogatory comments, and personal or political attacks +* The use of sexualized language or imagery, and sexual attention or advances of + any kind +* Trolling, insulting or derogatory comments, and personal or political attacks * Public or private harassment -* Publishing others' private information, such as a physical or electronic - address, without explicit permission +* Publishing others' private information, such as a physical or email address, + without their explicit permission * Other conduct which could reasonably be considered inappropriate in a - professional setting + professional setting -## Our Responsibilities +## Enforcement Responsibilities -Project maintainers are responsible for clarifying the standards of acceptable -behavior and are expected to take appropriate and fair corrective action in -response to any instances of unacceptable behavior. +Community leaders are responsible for clarifying and enforcing our standards of +acceptable behavior and will take appropriate and fair corrective action in +response to any behavior that they deem inappropriate, threatening, offensive, +or harmful. -Project maintainers have the right and responsibility to remove, edit, or -reject comments, commits, code, wiki edits, issues, and other contributions -that are not aligned to this Code of Conduct, or to ban temporarily or -permanently any contributor for other behaviors that they deem inappropriate, -threatening, offensive, or harmful. +Community leaders have the right and responsibility to remove, edit, or reject +comments, commits, code, wiki edits, issues, and other contributions that are +not aligned to this Code of Conduct, and will communicate reasons for moderation +decisions when appropriate. ## Scope -This Code of Conduct applies both within project spaces and in public spaces -when an individual is representing the project or its community. Examples of -representing a project or community include using an official project e-mail -address, posting via an official social media account, or acting as an appointed -representative at an online or offline event. Representation of a project may be -further defined and clarified by project maintainers. +This Code of Conduct applies within all community spaces, and also applies when +an individual is officially representing the community in public spaces. +Examples of representing our community include using an official e-mail address, +posting via an official social media account, or acting as an appointed +representative at an online or offline event. ## Enforcement Instances of abusive, harassing, or otherwise unacceptable behavior may be -reported by contacting the project team at conduct@zephyrproject.org. -Reports will be received by Kate Stewart (Linux Foundation) and Amy Occhialino -(Intel). All complaints will be reviewed and investigated, and will result in a -response that is deemed necessary and appropriate to the circumstances. The -project team is obligated to maintain confidentiality with regard to the -reporter of an incident. Further details of specific enforcement policies may -be posted separately. - -Project maintainers who do not follow or enforce the Code of Conduct in good -faith may face temporary or permanent repercussions as determined by other -members of the project's leadership. +reported to the community leaders responsible for enforcement at +conduct@zephyrproject.org. Reports will be received by the Chair of the Zephyr +Governing Board, the Zephyr Project Director (Linux Foundation), and the Zephyr +Project Developer Advocate (Linux Foundation). You may refer to the [Governing +Board](https://zephyrproject.org/governing-board/) and [Linux Foundation +Staff](https://zephyrproject.org/staff/) web pages to identify who are the +individuals currently holding these positions. +All complaints will be reviewed and investigated promptly and fairly. + +All community leaders are obligated to respect the privacy and security of the +reporter of any incident. + +## Enforcement Guidelines + +Community leaders will follow these Community Impact Guidelines in determining +the consequences for any action they deem in violation of this Code of Conduct: + +### 1. Correction + +**Community Impact**: Use of inappropriate language or other behavior deemed +unprofessional or unwelcome in the community. + +**Consequence**: A private, written warning from community leaders, providing +clarity around the nature of the violation and an explanation of why the +behavior was inappropriate. A public apology may be requested. + +### 2. Warning + +**Community Impact**: A violation through a single incident or series of +actions. + +**Consequence**: A warning with consequences for continued behavior. No +interaction with the people involved, including unsolicited interaction with +those enforcing the Code of Conduct, for a specified period of time. This +includes avoiding interactions in community spaces as well as external channels +like social media. Violating these terms may lead to a temporary or permanent +ban. + +### 3. Temporary Ban + +**Community Impact**: A serious violation of community standards, including +sustained inappropriate behavior. + +**Consequence**: A temporary ban from any sort of interaction or public +communication with the community for a specified period of time. No public or +private interaction with the people involved, including unsolicited interaction +with those enforcing the Code of Conduct, is allowed during this period. +Violating these terms may lead to a permanent ban. + +### 4. Permanent Ban + +**Community Impact**: Demonstrating a pattern of violation of community +standards, including sustained inappropriate behavior, harassment of an +individual, or aggression toward or disparagement of classes of individuals. + +**Consequence**: A permanent ban from any sort of public interaction within the +community. ## Attribution -This Code of Conduct is adapted from the [Contributor Covenant][homepage], version 1.4, -available at https://www.contributor-covenant.org/version/1/4/code-of-conduct.html +This Code of Conduct is adapted from the [Contributor Covenant][homepage], +version 2.1, available at +[https://www.contributor-covenant.org/version/2/1/code_of_conduct.html][v2.1]. +The only changes made by The Zephyr Project to the original document were to +make explicit who the recipients of Code of Conduct incident reports are. -[homepage]: https://www.contributor-covenant.org +Community Impact Guidelines were inspired by +[Mozilla's code of conduct enforcement ladder][Mozilla CoC]. -For answers to common questions about this code of conduct, see -https://www.contributor-covenant.org/faq +For answers to common questions about this code of conduct, see the FAQ at +[https://www.contributor-covenant.org/faq][FAQ]. Translations are available at +[https://www.contributor-covenant.org/translations][translations]. + +[homepage]: https://www.contributor-covenant.org +[v2.1]: https://www.contributor-covenant.org/version/2/1/code_of_conduct.html +[Mozilla CoC]: https://github.com/mozilla/diversity +[FAQ]: https://www.contributor-covenant.org/faq +[translations]: https://www.contributor-covenant.org/translations From 4c731f27c6da917d7f4abaa10270bb2440423b17 Mon Sep 17 00:00:00 2001 From: Benedikt Schmidt Date: Tue, 19 Dec 2023 16:42:34 +0100 Subject: [PATCH 1521/3723] shell: modules: do not use k_thread_foreach with shell callbacks Always use k_thread_foreach_unlocked with callbacks which print something out to the shell, as they might call arch_irq_unlock. Fixes #66660. Signed-off-by: Benedikt Schmidt --- subsys/shell/modules/kernel_service.c | 17 +++++++++-------- 1 file changed, 9 insertions(+), 8 deletions(-) diff --git a/subsys/shell/modules/kernel_service.c b/subsys/shell/modules/kernel_service.c index 8c82322729a..f204b2ecb02 100644 --- a/subsys/shell/modules/kernel_service.c +++ b/subsys/shell/modules/kernel_service.c @@ -197,11 +197,12 @@ static int cmd_kernel_threads(const struct shell *sh, shell_print(sh, "Scheduler: %u since last call", sys_clock_elapsed()); shell_print(sh, "Threads:"); -#ifdef CONFIG_SMP + /* + * Use the unlocked version as the callback itself might call + * arch_irq_unlock. + */ k_thread_foreach_unlocked(shell_tdata_dump, (void *)sh); -#else - k_thread_foreach(shell_tdata_dump, (void *)sh); -#endif + return 0; } @@ -245,11 +246,11 @@ static int cmd_kernel_stacks(const struct shell *sh, memset(pad, ' ', MAX((THREAD_MAX_NAM_LEN - strlen("IRQ 00")), 1)); -#ifdef CONFIG_SMP + /* + * Use the unlocked version as the callback itself might call + * arch_irq_unlock. + */ k_thread_foreach_unlocked(shell_stack_dump, (void *)sh); -#else - k_thread_foreach(shell_stack_dump, (void *)sh); -#endif /* Placeholder logic for interrupt stack until we have better * kernel support, including dumping arch-specific exception-related From 109c53dae8e75d4d13ecf98448f1e5d2eff63903 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Benjamin=20Cab=C3=A9?= Date: Wed, 20 Dec 2023 20:05:12 +0100 Subject: [PATCH 1522/3723] doc: kconfig: redirect: Add redirects for some old URLs MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Documentation pages around Kconfig have moved around on a couple of occasions in the past [1] [2] and current redirects were dysfonctional (leading /) and incomplete, while an entire set of redirects was also missing. This notably fixes the "browse latest development version of this page" link on https://docs.zephyrproject.org/2.7.5/guides/build/kconfig/tips.html or a link to the "Kconfig tips" page as found in Kconfiglib's current README (https://pypi.org/project/kconfiglib/) [1] commit 5342bc64ddc2bb733bb08041b6029cb9299266eb [2] commit 5c884184286435142e92bd034215f9abff0d8bb6 Fixes #66701 Signed-off-by: Benjamin Cabé --- doc/_scripts/redirects.py | 15 +++++++++++---- scripts/ci/check_compliance.py | 2 +- 2 files changed, 12 insertions(+), 5 deletions(-) diff --git a/doc/_scripts/redirects.py b/doc/_scripts/redirects.py index dfabef8b880..b1d199a0d2f 100644 --- a/doc/_scripts/redirects.py +++ b/doc/_scripts/redirects.py @@ -33,10 +33,11 @@ ('guides/bluetooth/index', 'connectivity/bluetooth/index'), ('guides/bluetooth/sm-pics', 'connectivity/bluetooth/sm-pics'), ('guides/build/index', 'build/cmake/index'), - ('guides/build/kconfig/extensions', '/build/kconfig/extensions'), - ('guides/build/kconfig/menuconfig', '/build/kconfig/menuconfig'), - ('guides/build/kconfig/setting', '/build/kconfig/setting'), - ('guides/build/kconfig/tips', '/build/kconfig/tips'), + ('guides/build/kconfig/extensions', 'build/kconfig/extensions'), + ('guides/build/kconfig/menuconfig', 'build/kconfig/menuconfig'), + ('guides/build/kconfig/preprocessor-functions', 'build/kconfig/preprocessor-functions'), + ('guides/build/kconfig/setting', 'build/kconfig/setting'), + ('guides/build/kconfig/tips', 'build/kconfig/tips'), ('guides/coccinelle', 'develop/tools/coccinelle'), ('guides/code-relocation', 'kernel/code-relocation'), ('guides/crypto/index', 'services/crypto/index'), @@ -60,6 +61,12 @@ ('guides/flash_debug/host-tools', 'develop/flash_debug/host-tools'), ('guides/flash_debug/index', 'develop/flash_debug/index'), ('guides/flash_debug/probes', 'develop/flash_debug/probes'), + ('guides/kconfig/extensions', 'build/kconfig/extensions'), + ('guides/kconfig/index', 'build/kconfig/index'), + ('guides/kconfig/menuconfig', 'build/kconfig/menuconfig'), + ('guides/kconfig/preprocessor-functions', 'build/kconfig/preprocessor-functions'), + ('guides/kconfig/setting', 'build/kconfig/setting'), + ('guides/kconfig/tips', 'build/kconfig/tips'), ('guides/modules', 'develop/modules'), ('guides/networking/index', 'connectivity/networking/index'), ('guides/optimizations/index', 'develop/optimizations/index'), diff --git a/scripts/ci/check_compliance.py b/scripts/ci/check_compliance.py index 94e6b99f4ec..0d8e472f6c6 100755 --- a/scripts/ci/check_compliance.py +++ b/scripts/ci/check_compliance.py @@ -513,7 +513,7 @@ def check_no_pointless_menuconfigs(self, kconf): self.failure("""\ Found pointless 'menuconfig' symbols without children. Use regular 'config' symbols instead. See -https://docs.zephyrproject.org/latest/guides/kconfig/tips.html#menuconfig-symbols. +https://docs.zephyrproject.org/latest/build/kconfig/tips.html#menuconfig-symbols. """ + "\n".join(f"{node.item.name:35} {node.filename}:{node.linenr}" for node in bad_mconfs)) From 978b0bb5ea5e863ab236136cbd708dd93be40e5c Mon Sep 17 00:00:00 2001 From: Fabio Baltieri Date: Sat, 25 Nov 2023 22:34:56 +0000 Subject: [PATCH 1523/3723] tests: input: add a gpio-kbd-matrix test suite Add an initial test suite for the gpio-kbd-matrix driver. Signed-off-by: Fabio Baltieri --- .../input/gpio_kbd_matrix/CMakeLists.txt | 11 + tests/drivers/input/gpio_kbd_matrix/Kconfig | 7 + .../gpio_kbd_matrix/boards/native_sim.overlay | 49 +++ .../boards/native_sim_64.overlay | 7 + tests/drivers/input/gpio_kbd_matrix/prj.conf | 6 + .../drivers/input/gpio_kbd_matrix/src/main.c | 414 ++++++++++++++++++ .../input/gpio_kbd_matrix/testcase.yaml | 13 + 7 files changed, 507 insertions(+) create mode 100644 tests/drivers/input/gpio_kbd_matrix/CMakeLists.txt create mode 100644 tests/drivers/input/gpio_kbd_matrix/Kconfig create mode 100644 tests/drivers/input/gpio_kbd_matrix/boards/native_sim.overlay create mode 100644 tests/drivers/input/gpio_kbd_matrix/boards/native_sim_64.overlay create mode 100644 tests/drivers/input/gpio_kbd_matrix/prj.conf create mode 100644 tests/drivers/input/gpio_kbd_matrix/src/main.c create mode 100644 tests/drivers/input/gpio_kbd_matrix/testcase.yaml diff --git a/tests/drivers/input/gpio_kbd_matrix/CMakeLists.txt b/tests/drivers/input/gpio_kbd_matrix/CMakeLists.txt new file mode 100644 index 00000000000..fa79887347f --- /dev/null +++ b/tests/drivers/input/gpio_kbd_matrix/CMakeLists.txt @@ -0,0 +1,11 @@ +# SPDX-License-Identifier: Apache-2.0 + +cmake_minimum_required(VERSION 3.20.0) +find_package(Zephyr REQUIRED HINTS $ENV{ZEPHYR_BASE}) + +project(input_gpio_kbd_matrix) + +target_include_directories(app PRIVATE ${ZEPHYR_BASE}/drivers/input) + +FILE(GLOB app_sources src/*.c) +target_sources(app PRIVATE ${app_sources}) diff --git a/tests/drivers/input/gpio_kbd_matrix/Kconfig b/tests/drivers/input/gpio_kbd_matrix/Kconfig new file mode 100644 index 00000000000..1a3f4a7c4f3 --- /dev/null +++ b/tests/drivers/input/gpio_kbd_matrix/Kconfig @@ -0,0 +1,7 @@ +# Copyright 2023 Google LLC +# SPDX-License-Identifier: Apache-2.0 + +config INPUT_KBD_DRIVE_COLUMN_HOOK + default y + +source "Kconfig.zephyr" diff --git a/tests/drivers/input/gpio_kbd_matrix/boards/native_sim.overlay b/tests/drivers/input/gpio_kbd_matrix/boards/native_sim.overlay new file mode 100644 index 00000000000..3554df0c732 --- /dev/null +++ b/tests/drivers/input/gpio_kbd_matrix/boards/native_sim.overlay @@ -0,0 +1,49 @@ +/* + * Copyright 2023 Google LLC + * + * SPDX-License-Identifier: Apache-2.0 + */ + +&gpio0 { + ngpios = <12>; +}; + +/ { + kbd_matrix_interrupt: kbd-matrix-interrupt { + compatible = "gpio-kbd-matrix"; + row-gpios = <&gpio0 0 (GPIO_PULL_UP | GPIO_ACTIVE_LOW)>, + <&gpio0 1 (GPIO_PULL_UP | GPIO_ACTIVE_LOW)>; + col-gpios = <&gpio0 2 GPIO_ACTIVE_LOW>, + <&gpio0 3 GPIO_ACTIVE_LOW>; + debounce-down-ms = <80>; + debounce-up-ms = <40>; + poll-timeout-ms = <500>; + }; + + kbd_matrix_poll: kbd-matrix-poll { + compatible = "gpio-kbd-matrix"; + row-gpios = <&gpio0 4 (GPIO_PULL_UP | GPIO_ACTIVE_LOW)>, + <&gpio0 5 (GPIO_PULL_UP | GPIO_ACTIVE_LOW)>; + col-gpios = <&gpio0 6 GPIO_ACTIVE_LOW>, + <&gpio0 7 GPIO_ACTIVE_LOW>; + debounce-down-ms = <40>; + debounce-up-ms = <80>; + poll-timeout-ms = <500>; + idle-mode = "poll"; + col-drive-inactive; + }; + + kbd_matrix_scan: kbd-matrix-scan { + compatible = "gpio-kbd-matrix"; + /* pins out of sequence to test non direct read */ + row-gpios = <&gpio0 9 (GPIO_PULL_UP | GPIO_ACTIVE_LOW)>, + <&gpio0 8 (GPIO_PULL_UP | GPIO_ACTIVE_LOW)>; + col-gpios = <&gpio0 11 GPIO_ACTIVE_LOW>, + <&gpio0 10 GPIO_ACTIVE_LOW>; + debounce-down-ms = <80>; + debounce-up-ms = <40>; + poll-timeout-ms = <0>; + col-drive-inactive; + idle-mode = "scan"; + }; +}; diff --git a/tests/drivers/input/gpio_kbd_matrix/boards/native_sim_64.overlay b/tests/drivers/input/gpio_kbd_matrix/boards/native_sim_64.overlay new file mode 100644 index 00000000000..1cf720283b3 --- /dev/null +++ b/tests/drivers/input/gpio_kbd_matrix/boards/native_sim_64.overlay @@ -0,0 +1,7 @@ +/* + * Copyright 2023 Google LLC + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include "native_sim.overlay" diff --git a/tests/drivers/input/gpio_kbd_matrix/prj.conf b/tests/drivers/input/gpio_kbd_matrix/prj.conf new file mode 100644 index 00000000000..5cd6cb6ceb3 --- /dev/null +++ b/tests/drivers/input/gpio_kbd_matrix/prj.conf @@ -0,0 +1,6 @@ +# SPDX-License-Identifier: Apache-2.0 + +CONFIG_ZTEST=y +CONFIG_GPIO=y +CONFIG_INPUT=y +CONFIG_INPUT_MODE_SYNCHRONOUS=y diff --git a/tests/drivers/input/gpio_kbd_matrix/src/main.c b/tests/drivers/input/gpio_kbd_matrix/src/main.c new file mode 100644 index 00000000000..9600b510f0a --- /dev/null +++ b/tests/drivers/input/gpio_kbd_matrix/src/main.c @@ -0,0 +1,414 @@ +/* + * Copyright 2023 Google LLC + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include +#include +#include +#include +#include +#include + +#define INTERRUPT_NODE DT_NODELABEL(kbd_matrix_interrupt) +#define POLL_NODE DT_NODELABEL(kbd_matrix_poll) +#define SCAN_NODE DT_NODELABEL(kbd_matrix_scan) + +static const struct device *dev_interrupt = DEVICE_DT_GET_OR_NULL(INTERRUPT_NODE); +static const struct device *dev_poll = DEVICE_DT_GET_OR_NULL(POLL_NODE); +static const struct device *dev_scan = DEVICE_DT_GET_OR_NULL(SCAN_NODE); + +#define INTERRUPT_R0_PIN DT_GPIO_PIN_BY_IDX(INTERRUPT_NODE, row_gpios, 0) +#define INTERRUPT_R1_PIN DT_GPIO_PIN_BY_IDX(INTERRUPT_NODE, row_gpios, 1) +#define INTERRUPT_C0_PIN DT_GPIO_PIN_BY_IDX(INTERRUPT_NODE, col_gpios, 0) +#define INTERRUPT_C1_PIN DT_GPIO_PIN_BY_IDX(INTERRUPT_NODE, col_gpios, 1) + +#define POLL_R0_PIN DT_GPIO_PIN_BY_IDX(POLL_NODE, row_gpios, 0) +#define POLL_R1_PIN DT_GPIO_PIN_BY_IDX(POLL_NODE, row_gpios, 1) +#define POLL_C0_PIN DT_GPIO_PIN_BY_IDX(POLL_NODE, col_gpios, 0) +#define POLL_C1_PIN DT_GPIO_PIN_BY_IDX(POLL_NODE, col_gpios, 1) + +#define SCAN_R0_PIN DT_GPIO_PIN_BY_IDX(SCAN_NODE, row_gpios, 0) +#define SCAN_R1_PIN DT_GPIO_PIN_BY_IDX(SCAN_NODE, row_gpios, 1) +#define SCAN_C0_PIN DT_GPIO_PIN_BY_IDX(SCAN_NODE, col_gpios, 0) +#define SCAN_C1_PIN DT_GPIO_PIN_BY_IDX(SCAN_NODE, col_gpios, 1) + +static const struct device *dev_gpio = DEVICE_DT_GET(DT_NODELABEL(gpio0)); + +enum { + KBD_DEV_INTERRUPT, + KBD_DEV_POLL, + KBD_DEV_SCAN, +}; + +#define KBD_DEV_COUNT (KBD_DEV_SCAN + 1) + +#define COL_COUNT 2 + +BUILD_ASSERT(DT_PROP_LEN(INTERRUPT_NODE, col_gpios) == COL_COUNT); +BUILD_ASSERT(DT_PROP_LEN(POLL_NODE, col_gpios) == COL_COUNT); +BUILD_ASSERT(DT_PROP_LEN(SCAN_NODE, col_gpios) == COL_COUNT); + +static uint8_t test_rows[KBD_DEV_COUNT][COL_COUNT]; +static int scan_set_count[KBD_DEV_COUNT]; + +static void gpio_kbd_scan_set_row(const struct device *dev, uint8_t row) +{ + if (dev == dev_interrupt) { + gpio_emul_input_set(dev_gpio, INTERRUPT_R0_PIN, !(row & BIT(0))); + gpio_emul_input_set(dev_gpio, INTERRUPT_R1_PIN, !(row & BIT(1))); + return; + } else if (dev == dev_poll) { + gpio_emul_input_set(dev_gpio, POLL_R0_PIN, !(row & BIT(0))); + gpio_emul_input_set(dev_gpio, POLL_R1_PIN, !(row & BIT(1))); + return; + } else if (dev == dev_scan) { + gpio_emul_input_set(dev_gpio, SCAN_R0_PIN, !(row & BIT(0))); + gpio_emul_input_set(dev_gpio, SCAN_R1_PIN, !(row & BIT(1))); + return; + } + + TC_PRINT("unknown device: %s\n", dev->name); +} + +void input_kbd_matrix_drive_column_hook(const struct device *dev, int col) +{ + gpio_flags_t flags0, flags1; + + if (col >= COL_COUNT) { + TC_PRINT("invalid column: %d\n", col); + return; + } + + if (dev == dev_interrupt) { + scan_set_count[KBD_DEV_INTERRUPT]++; + gpio_kbd_scan_set_row(dev, test_rows[KBD_DEV_INTERRUPT][col]); + + /* Verify that columns are NOT driven. */ + gpio_emul_flags_get(dev_gpio, INTERRUPT_C0_PIN, &flags0); + gpio_emul_flags_get(dev_gpio, INTERRUPT_C1_PIN, &flags1); + switch (col) { + case 0: + zassert_equal(flags0 & GPIO_DIR_MASK, GPIO_OUTPUT); + zassert_equal(flags1 & GPIO_DIR_MASK, GPIO_INPUT); + break; + case 1: + zassert_equal(flags0 & GPIO_DIR_MASK, GPIO_INPUT); + zassert_equal(flags1 & GPIO_DIR_MASK, GPIO_OUTPUT); + break; + case INPUT_KBD_MATRIX_COLUMN_DRIVE_NONE: + zassert_equal(flags0 & GPIO_DIR_MASK, GPIO_INPUT); + zassert_equal(flags1 & GPIO_DIR_MASK, GPIO_INPUT); + break; + case INPUT_KBD_MATRIX_COLUMN_DRIVE_ALL: + zassert_equal(flags0 & GPIO_DIR_MASK, GPIO_OUTPUT); + zassert_equal(flags1 & GPIO_DIR_MASK, GPIO_OUTPUT); + break; + } + + return; + } else if (dev == dev_poll) { + scan_set_count[KBD_DEV_POLL]++; + gpio_kbd_scan_set_row(dev, test_rows[KBD_DEV_POLL][col]); + + /* Verify that columns are always driven */ + gpio_emul_flags_get(dev_gpio, POLL_C0_PIN, &flags0); + gpio_emul_flags_get(dev_gpio, POLL_C1_PIN, &flags1); + zassert_equal(flags0 & GPIO_DIR_MASK, GPIO_OUTPUT); + zassert_equal(flags1 & GPIO_DIR_MASK, GPIO_OUTPUT); + + switch (col) { + case 0: + zassert_equal(gpio_emul_output_get(dev_gpio, POLL_C0_PIN), 0); + zassert_equal(gpio_emul_output_get(dev_gpio, POLL_C1_PIN), 1); + break; + case 1: + zassert_equal(gpio_emul_output_get(dev_gpio, POLL_C0_PIN), 1); + zassert_equal(gpio_emul_output_get(dev_gpio, POLL_C1_PIN), 0); + break; + case INPUT_KBD_MATRIX_COLUMN_DRIVE_NONE: + zassert_equal(gpio_emul_output_get(dev_gpio, POLL_C0_PIN), 1); + zassert_equal(gpio_emul_output_get(dev_gpio, POLL_C1_PIN), 1); + break; + case INPUT_KBD_MATRIX_COLUMN_DRIVE_ALL: + zassert_equal(gpio_emul_output_get(dev_gpio, POLL_C0_PIN), 0); + zassert_equal(gpio_emul_output_get(dev_gpio, POLL_C1_PIN), 0); + break; + } + + return; + } else if (dev == dev_scan) { + scan_set_count[KBD_DEV_SCAN]++; + gpio_kbd_scan_set_row(dev, test_rows[KBD_DEV_SCAN][col]); + + /* Verify that columns are always driven */ + gpio_emul_flags_get(dev_gpio, SCAN_C0_PIN, &flags0); + gpio_emul_flags_get(dev_gpio, SCAN_C1_PIN, &flags1); + zassert_equal(flags0 & GPIO_DIR_MASK, GPIO_OUTPUT); + zassert_equal(flags1 & GPIO_DIR_MASK, GPIO_OUTPUT); + + switch (col) { + case 0: + zassert_equal(gpio_emul_output_get(dev_gpio, SCAN_C0_PIN), 0); + zassert_equal(gpio_emul_output_get(dev_gpio, SCAN_C1_PIN), 1); + break; + case 1: + zassert_equal(gpio_emul_output_get(dev_gpio, SCAN_C0_PIN), 1); + zassert_equal(gpio_emul_output_get(dev_gpio, SCAN_C1_PIN), 0); + break; + case INPUT_KBD_MATRIX_COLUMN_DRIVE_NONE: + zassert_equal(gpio_emul_output_get(dev_gpio, SCAN_C0_PIN), 1); + zassert_equal(gpio_emul_output_get(dev_gpio, SCAN_C1_PIN), 1); + break; + case INPUT_KBD_MATRIX_COLUMN_DRIVE_ALL: + zassert_equal(gpio_emul_output_get(dev_gpio, SCAN_C0_PIN), 0); + zassert_equal(gpio_emul_output_get(dev_gpio, SCAN_C1_PIN), 0); + break; + } + + return; + } + + TC_PRINT("unknown device: %s\n", dev->name); +} + +/* support stuff */ + +static struct { + int row; + int col; + int val; + int event_count; +} test_event_data; + +static int last_checked_event_count; + +#define assert_no_new_events() \ + zassert_equal(last_checked_event_count, test_event_data.event_count); + +#define assert_new_event(_row, _col, _val) { \ + last_checked_event_count++; \ + zassert_equal(last_checked_event_count, test_event_data.event_count); \ + zassert_equal(_row, test_event_data.row); \ + zassert_equal(_col, test_event_data.col); \ + zassert_equal(_val, test_event_data.val); \ +} + +static void test_cb(struct input_event *evt) +{ + static int row, col, val; + + switch (evt->code) { + case INPUT_ABS_X: + col = evt->value; + break; + case INPUT_ABS_Y: + row = evt->value; + break; + case INPUT_BTN_TOUCH: + val = evt->value; + break; + } + + if (evt->sync) { + test_event_data.row = row; + test_event_data.col = col; + test_event_data.val = val; + test_event_data.event_count++; + TC_PRINT("input event: count=%d row=%d col=%d val=%d\n", + test_event_data.event_count, row, col, val); + } +} +INPUT_CALLBACK_DEFINE(NULL, test_cb); + +/* actual tests */ + +ZTEST(gpio_kbd_scan, test_gpio_kbd_scan_interrupt) +{ + const struct device *dev = dev_interrupt; + + if (dev == NULL) { + ztest_test_skip(); + return; + } + + const struct input_kbd_matrix_common_config *cfg = dev->config; + uint8_t *rows = test_rows[KBD_DEV_INTERRUPT]; + int *set_count = &scan_set_count[KBD_DEV_INTERRUPT]; + int prev_count; + gpio_flags_t flags; + + k_sleep(K_SECONDS(1)); + assert_no_new_events(); + zassert_equal(*set_count, 1); + + /* Verify that interrupts are enabled. */ + gpio_emul_flags_get(dev_gpio, INTERRUPT_R0_PIN, &flags); + zassert_equal(flags & GPIO_INT_ENABLE, GPIO_INT_ENABLE); + gpio_emul_flags_get(dev_gpio, INTERRUPT_R1_PIN, &flags); + zassert_equal(flags & GPIO_INT_ENABLE, GPIO_INT_ENABLE); + + rows[0] = BIT(0); + gpio_kbd_scan_set_row(dev, 0x01); + k_sleep(K_USEC(cfg->debounce_down_us * 1.5)); + assert_new_event(0, 0, 1); + + rows[1] = BIT(1); + k_sleep(K_USEC(cfg->debounce_down_us * 1.5)); + assert_new_event(1, 1, 1); + + rows[0] = 0x00; + k_sleep(K_USEC(cfg->debounce_up_us * 1.5)); + assert_new_event(0, 0, 0); + + rows[1] = 0x00; + k_sleep(K_USEC(cfg->debounce_up_us * 1.5)); + assert_new_event(1, 1, 0); + + k_sleep(K_MSEC(cfg->poll_timeout_ms * 1.5)); + + /* Check that scanning is NOT running */ + prev_count = *set_count; + k_sleep(K_MSEC(cfg->poll_timeout_ms * 10)); + assert_no_new_events(); + TC_PRINT("scan_set_count=%d, prev_count=%d\n", *set_count, prev_count); + zassert_equal(*set_count, prev_count); + + /* Verify that interrupts are still enabled. */ + gpio_emul_flags_get(dev_gpio, INTERRUPT_R0_PIN, &flags); + zassert_equal(flags & GPIO_INT_ENABLE, GPIO_INT_ENABLE); + gpio_emul_flags_get(dev_gpio, INTERRUPT_R1_PIN, &flags); + zassert_equal(flags & GPIO_INT_ENABLE, GPIO_INT_ENABLE); +} + +ZTEST(gpio_kbd_scan, test_gpio_kbd_scan_poll) +{ + const struct device *dev = dev_poll; + + if (dev == NULL) { + ztest_test_skip(); + return; + } + + const struct input_kbd_matrix_common_config *cfg = dev->config; + uint8_t *rows = test_rows[KBD_DEV_POLL]; + int *set_count = &scan_set_count[KBD_DEV_POLL]; + int prev_count; + gpio_flags_t flags; + + k_sleep(K_SECONDS(1)); + assert_no_new_events(); + zassert_equal(*set_count, 0); + + /* Verify that interrupts are NOT enabled. */ + gpio_emul_flags_get(dev_gpio, POLL_R0_PIN, &flags); + zassert_equal(flags & GPIO_INT_MASK, 0); + gpio_emul_flags_get(dev_gpio, POLL_R1_PIN, &flags); + zassert_equal(flags & GPIO_INT_MASK, 0); + + rows[0] = BIT(0); + gpio_kbd_scan_set_row(dev, 0x01); + k_sleep(K_USEC(cfg->debounce_down_us * 1.5)); + assert_new_event(0, 0, 1); + + rows[1] = BIT(1); + k_sleep(K_USEC(cfg->debounce_down_us * 1.5)); + assert_new_event(1, 1, 1); + + rows[0] = 0x00; + k_sleep(K_USEC(cfg->debounce_up_us * 1.5)); + assert_new_event(0, 0, 0); + + rows[1] = 0x00; + k_sleep(K_USEC(cfg->debounce_up_us * 1.5)); + assert_new_event(1, 1, 0); + + k_sleep(K_MSEC(cfg->poll_timeout_ms * 1.5)); + + /* Check that scanning is NOT running */ + prev_count = *set_count; + k_sleep(K_MSEC(cfg->poll_timeout_ms * 10)); + assert_no_new_events(); + TC_PRINT("scan_set_count=%d, prev_count=%d\n", *set_count, prev_count); + zassert_equal(*set_count, prev_count); + + /* Verify that interrupts are still NOT enabled. */ + gpio_emul_flags_get(dev_gpio, POLL_R0_PIN, &flags); + zassert_equal(flags & GPIO_INT_MASK, 0); + gpio_emul_flags_get(dev_gpio, POLL_R1_PIN, &flags); + zassert_equal(flags & GPIO_INT_MASK, 0); +} + +ZTEST(gpio_kbd_scan, test_gpio_kbd_scan_scan) +{ + const struct device *dev = dev_scan; + + if (dev == NULL) { + ztest_test_skip(); + return; + } + + const struct input_kbd_matrix_common_config *cfg = dev->config; + uint8_t *rows = test_rows[KBD_DEV_SCAN]; + int *set_count = &scan_set_count[KBD_DEV_SCAN]; + int prev_count; + int delta_count; + gpio_flags_t flags; + + /* check that scanning is already running */ + prev_count = *set_count; + k_sleep(K_SECONDS(1)); + assert_no_new_events(); + delta_count = *set_count - prev_count; + TC_PRINT("scan_set_count=%d, delta=%d\n", *set_count, delta_count); + zassert_true(delta_count > 100); + + /* Verify that interrupts are NOT enabled. */ + gpio_emul_flags_get(dev_gpio, SCAN_R0_PIN, &flags); + zassert_equal(flags & GPIO_INT_MASK, 0); + gpio_emul_flags_get(dev_gpio, SCAN_R1_PIN, &flags); + zassert_equal(flags & GPIO_INT_MASK, 0); + + rows[0] = BIT(0); + gpio_kbd_scan_set_row(dev, 0x01); + k_sleep(K_USEC(cfg->debounce_down_us * 1.5)); + assert_new_event(0, 0, 1); + + rows[1] = BIT(1); + k_sleep(K_USEC(cfg->debounce_down_us * 1.5)); + assert_new_event(1, 1, 1); + + rows[0] = 0x00; + k_sleep(K_USEC(cfg->debounce_up_us * 1.5)); + assert_new_event(0, 0, 0); + + rows[1] = 0x00; + k_sleep(K_USEC(cfg->debounce_up_us * 1.5)); + assert_new_event(1, 1, 0); + + k_sleep(K_MSEC(cfg->poll_timeout_ms * 1.5)); + + /* Check that scanning is still running */ + prev_count = *set_count; + k_sleep(K_SECONDS(1)); + assert_no_new_events(); + delta_count = *set_count - prev_count; + TC_PRINT("scan_set_count=%d, delta=%d\n", *set_count, delta_count); + zassert_true(delta_count > 100); + + /* Verify that interrupts are still NOT enabled. */ + gpio_emul_flags_get(dev_gpio, SCAN_R0_PIN, &flags); + zassert_equal(flags & GPIO_INT_MASK, 0); + gpio_emul_flags_get(dev_gpio, SCAN_R1_PIN, &flags); + zassert_equal(flags & GPIO_INT_MASK, 0); +} + +static void gpio_kbd_scan_before(void *data) +{ + last_checked_event_count = 0; + memset(&test_event_data, 0, sizeof(test_event_data)); + memset(&scan_set_count, 0, sizeof(scan_set_count)); +} + +ZTEST_SUITE(gpio_kbd_scan, NULL, NULL, gpio_kbd_scan_before, NULL, NULL); diff --git a/tests/drivers/input/gpio_kbd_matrix/testcase.yaml b/tests/drivers/input/gpio_kbd_matrix/testcase.yaml new file mode 100644 index 00000000000..a92532de3a0 --- /dev/null +++ b/tests/drivers/input/gpio_kbd_matrix/testcase.yaml @@ -0,0 +1,13 @@ +# SPDX-License-Identifier: Apache-2.0 + +common: + platform_allow: + - native_sim + - native_sim_64 + tags: + - drivers + - input + integration_platforms: + - native_sim +tests: + input.input_gpio_kbd_matrix: {} From 8c83185f6e3d5b41ea86aa01bccd82fc07cb1de5 Mon Sep 17 00:00:00 2001 From: Fabio Baltieri Date: Fri, 10 Nov 2023 17:01:56 +0000 Subject: [PATCH 1524/3723] tests: add an kbd_matrix test suite Add an initial test suite for the keyboard scanning input library. Signed-off-by: Fabio Baltieri --- tests/drivers/input/kbd_matrix/CMakeLists.txt | 11 + tests/drivers/input/kbd_matrix/Kconfig | 10 + .../input/kbd_matrix/actual-key-mask.overlay | 9 + .../kbd_matrix/boards/native_sim.overlay | 17 + .../kbd_matrix/boards/native_sim_64.overlay | 7 + .../dts/bindings/test-kbd-scan.yaml | 8 + .../kbd_matrix/no-ghostkey-check.overlay | 9 + tests/drivers/input/kbd_matrix/prj.conf | 5 + tests/drivers/input/kbd_matrix/src/main.c | 408 ++++++++++++++++++ tests/drivers/input/kbd_matrix/testcase.yaml | 22 + 10 files changed, 506 insertions(+) create mode 100644 tests/drivers/input/kbd_matrix/CMakeLists.txt create mode 100644 tests/drivers/input/kbd_matrix/Kconfig create mode 100644 tests/drivers/input/kbd_matrix/actual-key-mask.overlay create mode 100644 tests/drivers/input/kbd_matrix/boards/native_sim.overlay create mode 100644 tests/drivers/input/kbd_matrix/boards/native_sim_64.overlay create mode 100644 tests/drivers/input/kbd_matrix/dts/bindings/test-kbd-scan.yaml create mode 100644 tests/drivers/input/kbd_matrix/no-ghostkey-check.overlay create mode 100644 tests/drivers/input/kbd_matrix/prj.conf create mode 100644 tests/drivers/input/kbd_matrix/src/main.c create mode 100644 tests/drivers/input/kbd_matrix/testcase.yaml diff --git a/tests/drivers/input/kbd_matrix/CMakeLists.txt b/tests/drivers/input/kbd_matrix/CMakeLists.txt new file mode 100644 index 00000000000..3b212ad34e4 --- /dev/null +++ b/tests/drivers/input/kbd_matrix/CMakeLists.txt @@ -0,0 +1,11 @@ +# SPDX-License-Identifier: Apache-2.0 + +cmake_minimum_required(VERSION 3.20.0) +find_package(Zephyr REQUIRED HINTS $ENV{ZEPHYR_BASE}) + +project(input_kbd_matrix) + +target_include_directories(app PRIVATE ${ZEPHYR_BASE}/drivers/input) + +FILE(GLOB app_sources src/*.c) +target_sources(app PRIVATE ${app_sources}) diff --git a/tests/drivers/input/kbd_matrix/Kconfig b/tests/drivers/input/kbd_matrix/Kconfig new file mode 100644 index 00000000000..83f78c3a5b7 --- /dev/null +++ b/tests/drivers/input/kbd_matrix/Kconfig @@ -0,0 +1,10 @@ +# Copyright 2023 Google LLC +# SPDX-License-Identifier: Apache-2.0 + +config INPUT_KBD_MATRIX + default y + +config INPUT_KBD_DRIVE_COLUMN_HOOK + default y + +source "Kconfig.zephyr" diff --git a/tests/drivers/input/kbd_matrix/actual-key-mask.overlay b/tests/drivers/input/kbd_matrix/actual-key-mask.overlay new file mode 100644 index 00000000000..1ccb6425c0d --- /dev/null +++ b/tests/drivers/input/kbd_matrix/actual-key-mask.overlay @@ -0,0 +1,9 @@ +/* + * Copyright 2023 Google LLC + * + * SPDX-License-Identifier: Apache-2.0 + */ + +&test_kbd_scan { + actual-key-mask = <0x07 0x07 0x03>; +}; diff --git a/tests/drivers/input/kbd_matrix/boards/native_sim.overlay b/tests/drivers/input/kbd_matrix/boards/native_sim.overlay new file mode 100644 index 00000000000..9fb55ff3e46 --- /dev/null +++ b/tests/drivers/input/kbd_matrix/boards/native_sim.overlay @@ -0,0 +1,17 @@ +/* + * Copyright 2023 Google LLC + * + * SPDX-License-Identifier: Apache-2.0 + */ + +/ { + test_kbd_scan: test-kbd-scan { + compatible = "test-kbd-scan"; + row-size = <3>; + col-size = <3>; + poll-period-ms = <5>; + debounce-down-ms = <40>; + debounce-up-ms = <80>; + poll-timeout-ms = <500>; + }; +}; diff --git a/tests/drivers/input/kbd_matrix/boards/native_sim_64.overlay b/tests/drivers/input/kbd_matrix/boards/native_sim_64.overlay new file mode 100644 index 00000000000..1cf720283b3 --- /dev/null +++ b/tests/drivers/input/kbd_matrix/boards/native_sim_64.overlay @@ -0,0 +1,7 @@ +/* + * Copyright 2023 Google LLC + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include "native_sim.overlay" diff --git a/tests/drivers/input/kbd_matrix/dts/bindings/test-kbd-scan.yaml b/tests/drivers/input/kbd_matrix/dts/bindings/test-kbd-scan.yaml new file mode 100644 index 00000000000..afa35b8b26d --- /dev/null +++ b/tests/drivers/input/kbd_matrix/dts/bindings/test-kbd-scan.yaml @@ -0,0 +1,8 @@ +# Copyright 2023 Google LLC +# SPDX-License-Identifier: Apache-2.0 + +description: Keyboard scan test binding + +compatible: "test-kbd-scan" + +include: kbd-matrix-common.yaml diff --git a/tests/drivers/input/kbd_matrix/no-ghostkey-check.overlay b/tests/drivers/input/kbd_matrix/no-ghostkey-check.overlay new file mode 100644 index 00000000000..a23b37c84c4 --- /dev/null +++ b/tests/drivers/input/kbd_matrix/no-ghostkey-check.overlay @@ -0,0 +1,9 @@ +/* + * Copyright 2023 Google LLC + * + * SPDX-License-Identifier: Apache-2.0 + */ + +&test_kbd_scan { + no-ghostkey-check; +}; diff --git a/tests/drivers/input/kbd_matrix/prj.conf b/tests/drivers/input/kbd_matrix/prj.conf new file mode 100644 index 00000000000..bc713698bbf --- /dev/null +++ b/tests/drivers/input/kbd_matrix/prj.conf @@ -0,0 +1,5 @@ +# SPDX-License-Identifier: Apache-2.0 + +CONFIG_ZTEST=y +CONFIG_INPUT=y +CONFIG_INPUT_MODE_SYNCHRONOUS=y diff --git a/tests/drivers/input/kbd_matrix/src/main.c b/tests/drivers/input/kbd_matrix/src/main.c new file mode 100644 index 00000000000..609257c4c7a --- /dev/null +++ b/tests/drivers/input/kbd_matrix/src/main.c @@ -0,0 +1,408 @@ +/* + * Copyright 2023 Google LLC + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include +#include +#include +#include +#include +#include + +#define TEST_KBD_SCAN_NODE DT_INST(0, test_kbd_scan) + +/* test driver */ + +/* Mock data for every valid column. */ +static struct { + kbd_row_t rows[3]; + int col; + bool detect_mode; +} state; + +static void test_drive_column(const struct device *dev, int col) +{ + state.col = col; +} + +static kbd_row_t test_read_row(const struct device *dev) +{ + if (state.col == INPUT_KBD_MATRIX_COLUMN_DRIVE_NONE || + state.col == INPUT_KBD_MATRIX_COLUMN_DRIVE_ALL) { + return 0; + } + + return state.rows[state.col]; +} + +static void test_set_detect_mode(const struct device *dev, bool enabled) +{ + TC_PRINT("detect mode: enabled=%d\n", enabled); + state.detect_mode = enabled; +} + +static const struct input_kbd_matrix_api test_api = { + .drive_column = test_drive_column, + .read_row = test_read_row, + .set_detect_mode = test_set_detect_mode, +}; + +INPUT_KBD_MATRIX_DT_DEFINE(TEST_KBD_SCAN_NODE); + +static const struct input_kbd_matrix_common_config + test_cfg = INPUT_KBD_MATRIX_DT_COMMON_CONFIG_INIT( + TEST_KBD_SCAN_NODE, &test_api); + +static struct input_kbd_matrix_common_data test_data; + +DEVICE_DT_DEFINE(TEST_KBD_SCAN_NODE, input_kbd_matrix_common_init, NULL, + &test_data, &test_cfg, + POST_KERNEL, CONFIG_KERNEL_INIT_PRIORITY_DEVICE, NULL); + +static const struct device *const test_dev = DEVICE_DT_GET(TEST_KBD_SCAN_NODE); + +/* The test only supports a 3 column matrix */ +BUILD_ASSERT(DT_PROP(TEST_KBD_SCAN_NODE, col_size) == 3); + +/* support stuff */ + +static const struct device *column_hook_last_dev; +static int column_hook_last_col; + +void input_kbd_matrix_drive_column_hook(const struct device *dev, int col) +{ + column_hook_last_dev = dev; + column_hook_last_col = col; +} + +static void state_set_rows_by_column(kbd_row_t c0, kbd_row_t c1, kbd_row_t c2) +{ + memcpy(&state.rows, (kbd_row_t[]){c0, c1, c2}, sizeof(state.rows)); + TC_PRINT("set state [" PRIkbdrow " " PRIkbdrow " " PRIkbdrow "]\n", c0, c1, c2); +} + +static struct { + int row; + int col; + int val; + int event_count; +} test_event_data; + +static int last_checked_event_count; + +#define assert_no_new_events() \ + zassert_equal(last_checked_event_count, test_event_data.event_count); + +#define assert_new_event(_row, _col, _val) { \ + last_checked_event_count++; \ + zassert_equal(last_checked_event_count, test_event_data.event_count); \ + zassert_equal(_row, test_event_data.row); \ + zassert_equal(_col, test_event_data.col); \ + zassert_equal(_val, test_event_data.val); \ +} + +static void test_cb(struct input_event *evt) +{ + static int row, col, val; + + switch (evt->code) { + case INPUT_ABS_X: + col = evt->value; + break; + case INPUT_ABS_Y: + row = evt->value; + break; + case INPUT_BTN_TOUCH: + val = evt->value; + break; + } + + if (evt->sync) { + test_event_data.row = row; + test_event_data.col = col; + test_event_data.val = val; + test_event_data.event_count++; + TC_PRINT("input event: count=%d row=%d col=%d val=%d\n", + test_event_data.event_count, row, col, val); + } +} +INPUT_CALLBACK_DEFINE(test_dev, test_cb); + +#define WAIT_FOR_IDLE_TIMEOUT_US (5 * USEC_PER_SEC) + +static void kbd_scan_wait_for_idle(void) +{ + bool to; + + to = WAIT_FOR(state.detect_mode, + WAIT_FOR_IDLE_TIMEOUT_US, + k_sleep(K_MSEC(100))); + + zassert_true(to, "timeout waiting for idle state"); +} + +/* actual tests */ + +/* no event before debounce time, event after */ +ZTEST(kbd_scan, test_kbd_scan) +{ + const struct input_kbd_matrix_common_config *cfg = test_dev->config; + + input_kbd_matrix_poll_start(test_dev); + + state_set_rows_by_column(0x00, BIT(2), 0x00); + k_sleep(K_USEC(cfg->debounce_down_us / 2)); + assert_no_new_events(); + + k_sleep(K_USEC(cfg->debounce_down_us)); + assert_new_event(2, 1, 1); + + state_set_rows_by_column(0x00, 0x00, 0x00); + k_sleep(K_USEC(cfg->debounce_up_us / 2)); + assert_no_new_events(); + + k_sleep(K_USEC(cfg->debounce_up_us)); + assert_new_event(2, 1, 0); + + kbd_scan_wait_for_idle(); + assert_no_new_events(); + + zassert_equal(column_hook_last_dev, test_dev); + zassert_equal(column_hook_last_col, INPUT_KBD_MATRIX_COLUMN_DRIVE_ALL); +} + +/* no event for short glitches */ +ZTEST(kbd_scan, test_kbd_scan_glitch) +{ + const struct input_kbd_matrix_common_config *cfg = test_dev->config; + + input_kbd_matrix_poll_start(test_dev); + + state_set_rows_by_column(0x00, BIT(2), 0x00); + k_sleep(K_USEC(cfg->debounce_down_us / 2)); + assert_no_new_events(); + + state_set_rows_by_column(0x00, 0x00, 0x00); + k_sleep(K_USEC(cfg->debounce_down_us)); + assert_no_new_events(); + + kbd_scan_wait_for_idle(); + assert_no_new_events(); +} + +/* very bouncy key delays events indefinitely */ +ZTEST(kbd_scan, test_kbd_long_debounce) +{ + const struct input_kbd_matrix_common_config *cfg = test_dev->config; + + input_kbd_matrix_poll_start(test_dev); + + state_set_rows_by_column(0x00, BIT(2), 0x00); + k_sleep(K_USEC(cfg->debounce_down_us / 2)); + assert_no_new_events(); + + for (int i = 0; i < 10; i++) { + state_set_rows_by_column(0x00, 0x00, 0x00); + k_sleep(K_USEC(cfg->debounce_down_us / 2)); + assert_no_new_events(); + + state_set_rows_by_column(0x00, BIT(2), 0x00); + k_sleep(K_USEC(cfg->debounce_down_us / 2)); + assert_no_new_events(); + } + + k_sleep(K_USEC(cfg->debounce_down_us)); + assert_new_event(2, 1, 1); + + state_set_rows_by_column(0x00, 0x00, 0x00); + k_sleep(K_USEC(cfg->debounce_up_us / 2)); + assert_no_new_events(); + + for (int i = 0; i < 10; i++) { + state_set_rows_by_column(0x00, BIT(2), 0x00); + k_sleep(K_USEC(cfg->debounce_up_us / 2)); + assert_no_new_events(); + + state_set_rows_by_column(0x00, 0x00, 0x00); + k_sleep(K_USEC(cfg->debounce_up_us / 2)); + assert_no_new_events(); + } + + k_sleep(K_USEC(cfg->debounce_up_us)); + assert_new_event(2, 1, 0); + + kbd_scan_wait_for_idle(); + assert_no_new_events(); +} + +/* ghosting keys should not produce any event */ +ZTEST(kbd_scan, test_kbd_ghosting_check) +{ + const struct input_kbd_matrix_common_config *cfg = test_dev->config; + + if (cfg->ghostkey_check == false) { + ztest_test_skip(); + return; + } + + input_kbd_matrix_poll_start(test_dev); + + state_set_rows_by_column(BIT(0), 0x00, 0x00); + k_sleep(K_USEC(cfg->debounce_down_us * 1.5)); + assert_new_event(0, 0, 1); + + state_set_rows_by_column(BIT(0), BIT(1), 0x00); + k_sleep(K_USEC(cfg->debounce_down_us * 1.5)); + assert_new_event(1, 1, 1); + + /* ghosting */ + state_set_rows_by_column(BIT(0) | BIT(1), BIT(0) | BIT(1), 0x00); + k_sleep(K_USEC(cfg->debounce_down_us * 10)); + assert_no_new_events(); + + /* back to not ghosting anymore */ + state_set_rows_by_column(BIT(0), BIT(1), 0x00); + k_sleep(K_USEC(cfg->debounce_down_us * 10)); + assert_no_new_events(); + + state_set_rows_by_column(0x00, BIT(1), 0x00); + k_sleep(K_USEC(cfg->debounce_up_us * 1.5)); + assert_new_event(0, 0, 0); + + state_set_rows_by_column(0x00, 0x00, 0x00); + k_sleep(K_USEC(cfg->debounce_up_us * 1.5)); + assert_new_event(1, 1, 0); + + kbd_scan_wait_for_idle(); + assert_no_new_events(); +} + +/* ghosting keys can be disabled */ +ZTEST(kbd_scan, test_kbd_no_ghosting_check) +{ + const struct input_kbd_matrix_common_config *cfg = test_dev->config; + + if (cfg->ghostkey_check == true) { + ztest_test_skip(); + return; + } + + input_kbd_matrix_poll_start(test_dev); + + state_set_rows_by_column(BIT(0), 0x00, 0x00); + k_sleep(K_USEC(cfg->debounce_down_us * 1.5)); + assert_new_event(0, 0, 1); + + state_set_rows_by_column(BIT(0), BIT(1), 0x00); + k_sleep(K_USEC(cfg->debounce_down_us * 1.5)); + assert_new_event(1, 1, 1); + + state_set_rows_by_column(BIT(0) | BIT(1), BIT(1), 0x00); + k_sleep(K_USEC(cfg->debounce_down_us * 1.5)); + assert_new_event(1, 0, 1); + + state_set_rows_by_column(BIT(0) | BIT(1), BIT(0) | BIT(1), 0x00); + k_sleep(K_USEC(cfg->debounce_down_us * 1.5)); + assert_new_event(0, 1, 1); + + k_sleep(K_USEC(cfg->debounce_down_us * 10)); + assert_no_new_events(); + + state_set_rows_by_column(BIT(1), BIT(0) | BIT(1), 0x00); + k_sleep(K_USEC(cfg->debounce_up_us * 1.5)); + assert_new_event(0, 0, 0); + + state_set_rows_by_column(BIT(1), BIT(0), 0x00); + k_sleep(K_USEC(cfg->debounce_up_us * 1.5)); + assert_new_event(1, 1, 0); + + state_set_rows_by_column(0x00, BIT(0), 0x00); + k_sleep(K_USEC(cfg->debounce_up_us * 1.5)); + assert_new_event(1, 0, 0); + + state_set_rows_by_column(0x00, 0x00, 0x00); + k_sleep(K_USEC(cfg->debounce_up_us * 1.5)); + assert_new_event(0, 1, 0); + + kbd_scan_wait_for_idle(); + assert_no_new_events(); +} + +/* keymap is applied and can skip ghosting */ +ZTEST(kbd_scan, test_kbd_actual_keymap) +{ + const struct input_kbd_matrix_common_config *cfg = test_dev->config; + + if (cfg->actual_key_mask == NULL) { + ztest_test_skip(); + return; + } + + input_kbd_matrix_poll_start(test_dev); + + state_set_rows_by_column(BIT(0), 0x00, 0x00); + k_sleep(K_USEC(cfg->debounce_down_us * 1.5)); + assert_new_event(0, 0, 1); + + state_set_rows_by_column(BIT(0), 0x00, BIT(0)); + k_sleep(K_USEC(cfg->debounce_down_us * 1.5)); + assert_new_event(0, 2, 1); + + /* ghosting cleared by the keymap */ + state_set_rows_by_column(BIT(0) | BIT(2), 0x00, BIT(0) | BIT(2)); + k_sleep(K_USEC(cfg->debounce_down_us * 1.5)); + assert_new_event(2, 0, 1); + + state_set_rows_by_column(BIT(0) | BIT(2), 0x00, BIT(2)); + k_sleep(K_USEC(cfg->debounce_up_us * 1.5)); + assert_new_event(0, 2, 0); + + state_set_rows_by_column(BIT(2), 0x00, BIT(2)); + k_sleep(K_USEC(cfg->debounce_up_us * 1.5)); + assert_new_event(0, 0, 0); + + state_set_rows_by_column(BIT(2), 0x00, 0x00); + k_sleep(K_USEC(cfg->debounce_up_us * 1.5)); + assert_no_new_events(); + + state_set_rows_by_column(0x00, 0x00, 0x00); + k_sleep(K_USEC(cfg->debounce_up_us * 1.5)); + assert_new_event(2, 0, 0); + + kbd_scan_wait_for_idle(); + assert_no_new_events(); +} +static void *kbd_scan_setup(void) +{ + const struct input_kbd_matrix_common_config *cfg = test_dev->config; + + TC_PRINT("actual kbd-matrix timing: poll_period_us=%d " + "debounce_down_us=%d debounce_up_us=%d\n", + cfg->poll_period_us, + cfg->debounce_down_us, + cfg->debounce_up_us); + + return NULL; +} + +static void kbd_scan_before(void *data) +{ + memset(&state, 0, sizeof(state)); + state.detect_mode = true; + + last_checked_event_count = 0; + memset(&test_event_data, 0, sizeof(test_event_data)); +} + +static void kbd_scan_after(void *data) +{ + /* Clear the test data so if a test fails early the testsuite does not + * hang indefinitely. + */ + state_set_rows_by_column(0x00, 0x00, 0x00); + kbd_scan_wait_for_idle(); +} + +ZTEST_SUITE(kbd_scan, NULL, kbd_scan_setup, kbd_scan_before, kbd_scan_after, NULL); diff --git a/tests/drivers/input/kbd_matrix/testcase.yaml b/tests/drivers/input/kbd_matrix/testcase.yaml new file mode 100644 index 00000000000..8ee5a9aa7a6 --- /dev/null +++ b/tests/drivers/input/kbd_matrix/testcase.yaml @@ -0,0 +1,22 @@ +# SPDX-License-Identifier: Apache-2.0 + +common: + platform_allow: + - native_sim + - native_sim_64 + tags: + - drivers + - input + integration_platforms: + - native_sim +tests: + input.input_kbd_matrix: {} + input.input_kbd_matrix.no_ghostkey_check: + extra_args: + - EXTRA_DTC_OVERLAY_FILE=no-ghostkey-check.overlay + input.input_kbd_matrix.actual_key_mask: + extra_args: + - EXTRA_DTC_OVERLAY_FILE=actual-key-mask.overlay + input.input_kbd_matrix.row_16_bit: + extra_args: + - CONFIG_INPUT_KBD_MATRIX_16_BIT_ROW=y From 6c4751220a3c0abf5e7e2342e12b671e036e4cf2 Mon Sep 17 00:00:00 2001 From: Aaron Ye Date: Tue, 19 Dec 2023 10:15:02 +0800 Subject: [PATCH 1525/3723] boards: arm: apollo4p_evb: Update the support feature. This commit updates the support features in document and yaml files of Ambiq apollo4p_evb and apollo4p_blue_kxr_evb. Signed-off-by: Aaron Ye --- .../arm/apollo4p_blue_kxr_evb/apollo4p_blue_kxr_evb.yaml | 8 ++++++++ boards/arm/apollo4p_blue_kxr_evb/doc/index.rst | 6 ++++++ boards/arm/apollo4p_evb/apollo4p_evb.yaml | 5 +++++ boards/arm/apollo4p_evb/doc/index.rst | 6 ++++++ 4 files changed, 25 insertions(+) diff --git a/boards/arm/apollo4p_blue_kxr_evb/apollo4p_blue_kxr_evb.yaml b/boards/arm/apollo4p_blue_kxr_evb/apollo4p_blue_kxr_evb.yaml index bbdf0477a36..d9e9f244d86 100644 --- a/boards/arm/apollo4p_blue_kxr_evb/apollo4p_blue_kxr_evb.yaml +++ b/boards/arm/apollo4p_blue_kxr_evb/apollo4p_blue_kxr_evb.yaml @@ -9,6 +9,14 @@ toolchain: - gnuarmemb supported: - uart + - watchdog + - counter + - gpio + - spi + - i2c + - clock_control + - ble testing: ignore_tags: - net +vendor: ambiq diff --git a/boards/arm/apollo4p_blue_kxr_evb/doc/index.rst b/boards/arm/apollo4p_blue_kxr_evb/doc/index.rst index 35592c0b911..75aa74ac34e 100644 --- a/boards/arm/apollo4p_blue_kxr_evb/doc/index.rst +++ b/boards/arm/apollo4p_blue_kxr_evb/doc/index.rst @@ -49,6 +49,12 @@ The Apollo4 Blue Plus KXR EVB board configuration supports the following hardwar +-----------+------------+-------------------------------------+ | WDT | on-chip | watchdog | +-----------+------------+-------------------------------------+ +| SPI(M) | on-chip | spi | ++-----------+------------+-------------------------------------+ +| I2C(M) | on-chip | i2c | ++-----------+------------+-------------------------------------+ +| CLOCK | on-chip | clock_control | ++-----------+------------+-------------------------------------+ | RADIO | on-chip | bluetooth | +-----------+------------+-------------------------------------+ diff --git a/boards/arm/apollo4p_evb/apollo4p_evb.yaml b/boards/arm/apollo4p_evb/apollo4p_evb.yaml index b2c0ecd954b..1aa0fbf75d4 100644 --- a/boards/arm/apollo4p_evb/apollo4p_evb.yaml +++ b/boards/arm/apollo4p_evb/apollo4p_evb.yaml @@ -9,6 +9,11 @@ toolchain: - gnuarmemb supported: - uart + - watchdog + - counter + - gpio + - spi + - i2c testing: ignore_tags: - net diff --git a/boards/arm/apollo4p_evb/doc/index.rst b/boards/arm/apollo4p_evb/doc/index.rst index 21b967893e1..42f0f360329 100644 --- a/boards/arm/apollo4p_evb/doc/index.rst +++ b/boards/arm/apollo4p_evb/doc/index.rst @@ -46,6 +46,12 @@ The Apollo4P EVB board configuration supports the following hardware features: +-----------+------------+-------------------------------------+ | UART | on-chip | serial | +-----------+------------+-------------------------------------+ +| WDT | on-chip | watchdog | ++-----------+------------+-------------------------------------+ +| SPI(M) | on-chip | spi | ++-----------+------------+-------------------------------------+ +| I2C(M) | on-chip | i2c | ++-----------+------------+-------------------------------------+ The default configuration can be found in the defconfig file: ``boards/arm/apollo4p_evb/apollo4p_evb_defconfig``. From 5f83c3fe4d94f17538e9a6e23ad75a63a8793cc8 Mon Sep 17 00:00:00 2001 From: Aaron Ye Date: Tue, 19 Dec 2023 10:15:03 +0800 Subject: [PATCH 1526/3723] dts: arm: ambiq: Use DT_FREQ macro for frequency configuration. This commit updates the Ambiq Apollo4x series soc clock frequency of defined instances to align with context of these dts files. Signed-off-by: Aaron Ye --- boards/arm/apollo4p_blue_kxr_evb/apollo4p_blue_kxr_evb.dts | 2 +- dts/arm/ambiq/ambiq_apollo4p.dtsi | 3 ++- dts/arm/ambiq/ambiq_apollo4p_blue.dtsi | 2 +- 3 files changed, 4 insertions(+), 3 deletions(-) diff --git a/boards/arm/apollo4p_blue_kxr_evb/apollo4p_blue_kxr_evb.dts b/boards/arm/apollo4p_blue_kxr_evb/apollo4p_blue_kxr_evb.dts index e14a8bd3372..cb4014a4f08 100644 --- a/boards/arm/apollo4p_blue_kxr_evb/apollo4p_blue_kxr_evb.dts +++ b/boards/arm/apollo4p_blue_kxr_evb/apollo4p_blue_kxr_evb.dts @@ -82,7 +82,7 @@ compatible = "ambiq,spi"; pinctrl-0 = <&spi1_default>; pinctrl-names = "default"; - clock-frequency = <1000000>; + clock-frequency = ; status = "okay"; }; diff --git a/dts/arm/ambiq/ambiq_apollo4p.dtsi b/dts/arm/ambiq/ambiq_apollo4p.dtsi index 10aa631a12e..390a0b3358a 100644 --- a/dts/arm/ambiq/ambiq_apollo4p.dtsi +++ b/dts/arm/ambiq/ambiq_apollo4p.dtsi @@ -2,6 +2,7 @@ #include #include +#include #include #include @@ -9,7 +10,7 @@ clocks { uartclk: apb-pclk { compatible = "fixed-clock"; - clock-frequency = <24000000>; + clock-frequency = ; #clock-cells = <0>; }; }; diff --git a/dts/arm/ambiq/ambiq_apollo4p_blue.dtsi b/dts/arm/ambiq/ambiq_apollo4p_blue.dtsi index c0baab83b80..5df5c7d4b47 100644 --- a/dts/arm/ambiq/ambiq_apollo4p_blue.dtsi +++ b/dts/arm/ambiq/ambiq_apollo4p_blue.dtsi @@ -10,7 +10,7 @@ clocks { uartclk: apb-pclk { compatible = "fixed-clock"; - clock-frequency = <24000000>; + clock-frequency = ; #clock-cells = <0>; }; xo32m: xo32m { From d470f464eb43d8905f9264035e3c797648a050ac Mon Sep 17 00:00:00 2001 From: Marc-Antoine Riou Date: Thu, 16 Nov 2023 09:03:28 +0100 Subject: [PATCH 1527/3723] samples: ipc: Fix length of message to send in openamp rsc table sample Sample openamp_rsc_table was sending too many characters to master. It was displayed as unrecognised character when reading message on master. Signed-off-by: Marc-Antoine Riou --- samples/subsys/ipc/openamp_rsc_table/src/main_remote.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/samples/subsys/ipc/openamp_rsc_table/src/main_remote.c b/samples/subsys/ipc/openamp_rsc_table/src/main_remote.c index ebee382cdf8..60aac82313c 100644 --- a/samples/subsys/ipc/openamp_rsc_table/src/main_remote.c +++ b/samples/subsys/ipc/openamp_rsc_table/src/main_remote.c @@ -321,7 +321,7 @@ void app_rpmsg_tty(void *arg1, void *arg2, void *arg3) if (tty_msg.len) { snprintf(tx_buff, 13, "TTY 0x%04x: ", tty_ept.addr); memcpy(&tx_buff[12], tty_msg.data, tty_msg.len); - rpmsg_send(&tty_ept, tx_buff, tty_msg.len + 13); + rpmsg_send(&tty_ept, tx_buff, tty_msg.len + 12); rpmsg_release_rx_buffer(&tty_ept, tty_msg.data); } tty_msg.len = 0; From 71138d4001e162d53bf076a1b23dc24bf6f1830a Mon Sep 17 00:00:00 2001 From: Marc-Antoine Riou Date: Mon, 11 Dec 2023 16:45:33 +0100 Subject: [PATCH 1528/3723] samples: ipc: Add logs in openamp rsc table loops Add logs in both of the openamp rsc table loops to stick with what is shown in Zephyr documentation. Prefix each message with the loop name and unify logs with those from rpmsg_client_sample module. Signed-off-by: Marc-Antoine Riou --- samples/subsys/ipc/openamp_rsc_table/src/main_remote.c | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/samples/subsys/ipc/openamp_rsc_table/src/main_remote.c b/samples/subsys/ipc/openamp_rsc_table/src/main_remote.c index 60aac82313c..50c93f3905c 100644 --- a/samples/subsys/ipc/openamp_rsc_table/src/main_remote.c +++ b/samples/subsys/ipc/openamp_rsc_table/src/main_remote.c @@ -291,6 +291,8 @@ void app_rpmsg_client_sample(void *arg1, void *arg2, void *arg3) while (msg_cnt < 100) { k_sem_take(&data_sc_sem, K_FOREVER); msg_cnt++; + printk("[Linux sample client] incoming msg %d: %.*s\n", msg_cnt, sc_msg.len, + (char *)sc_msg.data); rpmsg_send(&sc_ept, sc_msg.data, sc_msg.len); } rpmsg_destroy_ept(&sc_ept); @@ -309,7 +311,7 @@ void app_rpmsg_tty(void *arg1, void *arg2, void *arg3) k_sem_take(&data_tty_sem, K_FOREVER); - printk("\r\nOpenAMP[remote] Linux tty responder started\r\n"); + printk("\r\nOpenAMP[remote] Linux TTY responder started\r\n"); tty_ept.priv = &tty_msg; ret = rpmsg_create_ept(&tty_ept, rpdev, "rpmsg-tty", @@ -319,6 +321,7 @@ void app_rpmsg_tty(void *arg1, void *arg2, void *arg3) while (tty_ept.addr != RPMSG_ADDR_ANY) { k_sem_take(&data_tty_sem, K_FOREVER); if (tty_msg.len) { + printk("[Linux TTY] incoming msg: %.*s", tty_msg.len, (char *)tty_msg.data); snprintf(tx_buff, 13, "TTY 0x%04x: ", tty_ept.addr); memcpy(&tx_buff[12], tty_msg.data, tty_msg.len); rpmsg_send(&tty_ept, tx_buff, tty_msg.len + 12); @@ -342,7 +345,7 @@ void rpmsg_mng_task(void *arg1, void *arg2, void *arg3) unsigned int len; int ret = 0; - printk("\r\nOpenAMP[remote] linux responder demo started\r\n"); + printk("\r\nOpenAMP[remote] Linux responder demo started\r\n"); /* Initialize platform */ ret = platform_init(); From 8e1bc2b0581ea92a659f9b4576e7a741544a65ec Mon Sep 17 00:00:00 2001 From: Marc-Antoine Riou Date: Mon, 11 Dec 2023 17:05:03 +0100 Subject: [PATCH 1529/3723] samples: ipc: Update openamp rsc table documentation This change follow the recent commit that update openamp rsc table logs. Add the logs for both samples sample client & TTY responder, as well as for both sides Linux & Zephyr. Remove the serial connection to Zephyr because it is board specific. Signed-off-by: Marc-Antoine Riou --- .../subsys/ipc/openamp_rsc_table/README.rst | 107 ++++++++++++------ 1 file changed, 72 insertions(+), 35 deletions(-) diff --git a/samples/subsys/ipc/openamp_rsc_table/README.rst b/samples/subsys/ipc/openamp_rsc_table/README.rst index 95eaabfae60..a0d46e3a4bd 100644 --- a/samples/subsys/ipc/openamp_rsc_table/README.rst +++ b/samples/subsys/ipc/openamp_rsc_table/README.rst @@ -18,69 +18,89 @@ a Linux kernel OS on the main processor and a Zephyr application on the co-processor. Building the application -************************* +************************ Zephyr -------- +====== .. zephyr-app-commands:: :zephyr-app: samples/subsys/ipc/openamp_rsc_table :goals: test -Linux ------- - -Enable SAMPLE_RPMSG_CLIENT configuration to build and install -the rpmsg_client_sample.ko module on the target. +Running the client sample +************************* -Running the sample -******************* +Linux setup +=========== -Zephyr console ---------------- +Enable ``SAMPLE_RPMSG_CLIENT`` configuration to build the :file:`rpmsg_client_sample.ko` module. -Open a serial terminal (minicom, putty, etc.) and connect the board with the -following settings: +Zephyr setup +============ -- Speed: 115200 -- Data: 8 bits -- Parity: None -- Stop bits: 1 - -Reset the board. +Open a serial terminal (minicom, putty, etc.) and connect to the board using default serial port settings. Linux console ---------------- +============= -Open a Linux shell (minicom, ssh, etc.) and insert a module into the Linux Kernel +Open a Linux shell (minicom, ssh, etc.) and insert the ``rpmsg_client_sample`` module into the Linux Kernel. +Right after, logs should be displayed to notify channel creation/destruction and incoming message. .. code-block:: console root@linuxshell: insmod rpmsg_client_sample.ko + [ 44.625407] rpmsg_client_sample virtio0.rpmsg-client-sample.-1.1024: new channel: 0x401 -> 0x400! + [ 44.631401] rpmsg_client_sample virtio0.rpmsg-client-sample.-1.1024: incoming msg 1 (src: 0x400) + [ 44.640614] rpmsg_client_sample virtio0.rpmsg-client-sample.-1.1024: incoming msg 2 (src: 0x400) + ... + [ 45.152269] rpmsg_client_sample virtio0.rpmsg-client-sample.-1.1024: incoming msg 99 (src: 0x400) + [ 45.157678] rpmsg_client_sample virtio0.rpmsg-client-sample.-1.1024: incoming msg 100 (src: 0x400) + [ 45.158822] rpmsg_client_sample virtio0.rpmsg-client-sample.-1.1024: goodbye! + [ 45.159741] virtio_rpmsg_bus virtio0: destroying channel rpmsg-client-sample addr 0x400 + [ 45.160856] rpmsg_client_sample virtio0.rpmsg-client-sample.-1.1024: rpmsg sample client driver is removed -Result on Zephyr console on boot --------------------------------- -The following message will appear on the corresponding Zephyr console: +Zephyr console +============== + +For each message received, its content is displayed as shown down below then sent back to Linux. .. code-block:: console - ***** Booting Zephyr OS v#.##.#-####-g########## ***** - Starting application thread! + *** Booting Zephyr OS build zephyr-v#.#.#-####-g########## *** + Starting application threads! + + OpenAMP[remote] Linux responder demo started + + OpenAMP[remote] Linux sample client responder started - OpenAMP demo started - Remote core received message 1: hello world! - Remote core received message 2: hello world! - Remote core received message 3: hello world! + OpenAMP[remote] Linux TTY responder started + [Linux sample client] incoming msg 1: hello world! + [Linux sample client] incoming msg 2: hello world! ... - Remote core received message 100: hello world! - OpenAMP demo ended. + [Linux sample client] incoming msg 99: hello world! + [Linux sample client] incoming msg 100: hello world! + OpenAMP Linux sample client responder ended + + +Running the rpmsg TTY demo +************************** + +Linux setup +=========== +Enable ``RPMSG_TTY`` in the kernel configuration. -rpmsg TTY demo on Linux console -------------------------------- +Zephyr setup +============ -On the Linux console send a message to Zephyr which answers with the "TTY " prefix. +Open a serial terminal (minicom, putty, etc.) and connect to the board using default serial port settings. + +Linux console +============= + +Open a Linux shell (minicom, ssh, etc.) and print the messages coming through the rpmsg-tty endpoint created during the sample initialization. +On the Linux console, send a message to Zephyr which answers with the :samp:`TTY {}:` prefix. corresponds to the Zephyr rpmsg-tty endpoint address: .. code-block:: console @@ -88,3 +108,20 @@ On the Linux console send a message to Zephyr which answers with the "TTY " $> cat /dev/ttyRPMSG0 & $> echo "Hello Zephyr" >/dev/ttyRPMSG0 TTY 0x0401: Hello Zephyr + +Zephyr console +============== + +On the Zephyr console, the received message is displayed as shown below, then sent back to Linux. + +.. code-block:: console + + *** Booting Zephyr OS build zephyr-v#.#.#-####-g########## *** + Starting application threads! + + OpenAMP[remote] Linux responder demo started + + OpenAMP[remote] Linux sample client responder started + + OpenAMP[remote] Linux TTY responder started + [Linux TTY] incoming msg: Hello Zephyr From e05d964b461ea6d1df846bf54dab464232ece6e2 Mon Sep 17 00:00:00 2001 From: Magdalena Kasenberg Date: Wed, 20 Dec 2023 16:47:34 +0100 Subject: [PATCH 1530/3723] bluetooth: audio: broadcast: Fix missing update of meta_len The length of the updated metadata was not updated. Fixes the CAP/INI/BST/BV-13-C test case. Signed-off-by: Magdalena Kasenberg --- subsys/bluetooth/audio/bap_broadcast_source.c | 1 + 1 file changed, 1 insertion(+) diff --git a/subsys/bluetooth/audio/bap_broadcast_source.c b/subsys/bluetooth/audio/bap_broadcast_source.c index 8978e2816cb..26b79b04666 100644 --- a/subsys/bluetooth/audio/bap_broadcast_source.c +++ b/subsys/bluetooth/audio/bap_broadcast_source.c @@ -938,6 +938,7 @@ int bt_bap_broadcast_source_update_metadata(struct bt_bap_broadcast_source *sour SYS_SLIST_FOR_EACH_CONTAINER(&source->subgroups, subgroup, _node) { memset(subgroup->codec_cfg->meta, 0, sizeof(subgroup->codec_cfg->meta)); memcpy(subgroup->codec_cfg->meta, meta, meta_len); + subgroup->codec_cfg->meta_len = meta_len; } return 0; From 8cf199fb04a6a78ea67a588712f187969ed1818b Mon Sep 17 00:00:00 2001 From: Manuel Aebischer Date: Wed, 20 Dec 2023 21:21:55 +0100 Subject: [PATCH 1531/3723] drivers: usb_dc_rpi_pico: previosuly used endpoint may remain locked When reconfiguring a previously used endpoint, it may still be locked when a write was taking place when e.g. the host application crashed. The call to udc_rpi_cancel_endpoint seems to do a proper cleanup of the endpoint, i.e. the write semaphore will be released. Fixes #66723. Signed-off-by: Manuel Aebischer --- drivers/usb/device/usb_dc_rpi_pico.c | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/drivers/usb/device/usb_dc_rpi_pico.c b/drivers/usb/device/usb_dc_rpi_pico.c index e3599c00bfe..38e88afae39 100644 --- a/drivers/usb/device/usb_dc_rpi_pico.c +++ b/drivers/usb/device/usb_dc_rpi_pico.c @@ -679,6 +679,13 @@ int usb_dc_ep_disable(const uint8_t ep) return 0; } + /* If this endpoint has previously been used and e.g. the host application + * crashed, the endpoint may remain locked even after reconfiguration + * because the write semaphore is never given back. + * udc_rpi_cancel_endpoint() handles this so the endpoint can be written again. + */ + udc_rpi_cancel_endpoint(ep); + uint8_t val = *ep_state->ep_ctl & ~EP_CTRL_ENABLE_BITS; *ep_state->ep_ctl = val; From c067f4d26316efd6f8e683c9a6814b31e0d40666 Mon Sep 17 00:00:00 2001 From: Henrik Brix Andersen Date: Thu, 21 Dec 2023 22:19:56 +0100 Subject: [PATCH 1532/3723] drivers: can: native_linux: add missing return value check Check return value from linux_socketcan_set_mode_fd() function call. Fixes: #66798 Signed-off-by: Henrik Brix Andersen --- drivers/can/can_native_linux.c | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/drivers/can/can_native_linux.c b/drivers/can/can_native_linux.c index 5ada2a5b47c..bd93415c134 100644 --- a/drivers/can/can_native_linux.c +++ b/drivers/can/can_native_linux.c @@ -292,6 +292,7 @@ static int can_native_linux_stop(const struct device *dev) static int can_native_linux_set_mode(const struct device *dev, can_mode_t mode) { struct can_native_linux_data *data = dev->data; + int err; #ifdef CONFIG_CAN_FD_MODE if ((mode & ~(CAN_MODE_LOOPBACK | CAN_MODE_FD)) != 0) { @@ -313,7 +314,11 @@ static int can_native_linux_set_mode(const struct device *dev, can_mode_t mode) data->loopback = (mode & CAN_MODE_LOOPBACK) != 0; data->mode_fd = (mode & CAN_MODE_FD) != 0; - linux_socketcan_set_mode_fd(data->dev_fd, data->mode_fd); + err = linux_socketcan_set_mode_fd(data->dev_fd, data->mode_fd); + if (err != 0) { + LOG_ERR("failed to set mode"); + return -EIO; + } return 0; } From 6d5d06689bac60960a3393ee4f73eb9f5ad400ce Mon Sep 17 00:00:00 2001 From: Henrik Brix Andersen Date: Thu, 21 Dec 2023 22:21:31 +0100 Subject: [PATCH 1533/3723] drivers: can: native_linux: leave room for null termination of string Only copy up to IFNAMSIZ - 1 number of characters of the interface name to leave room for null termination of string. Fixes: #66777 Signed-off-by: Henrik Brix Andersen --- drivers/can/can_native_linux_adapt.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/can/can_native_linux_adapt.c b/drivers/can/can_native_linux_adapt.c index 675dd01de79..c588591e080 100644 --- a/drivers/can/can_native_linux_adapt.c +++ b/drivers/can/can_native_linux_adapt.c @@ -55,7 +55,7 @@ int linux_socketcan_iface_open(const char *if_name) (void)memset(&ifr, 0, sizeof(ifr)); (void)memset(&addr, 0, sizeof(addr)); - strncpy(ifr.ifr_name, if_name, IFNAMSIZ); + strncpy(ifr.ifr_name, if_name, IFNAMSIZ - 1); ret = ioctl(fd, SIOCGIFINDEX, (void *)&ifr); if (ret < 0) { From 2842f206ebfbc94d7d9b31adbe8fdccf45932c6f Mon Sep 17 00:00:00 2001 From: Jonas Woerner Date: Tue, 12 Dec 2023 18:36:51 +0100 Subject: [PATCH 1534/3723] Bluetooth: Host: add hci error to errno translation for INVALID_PARAM now returns -EINVAL if invalid parameters a are supplied Signed-off-by: Jonas Woerner --- subsys/bluetooth/host/hci_core.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/subsys/bluetooth/host/hci_core.c b/subsys/bluetooth/host/hci_core.c index b003afa56d5..2f54298b41b 100644 --- a/subsys/bluetooth/host/hci_core.c +++ b/subsys/bluetooth/host/hci_core.c @@ -340,6 +340,8 @@ int bt_hci_cmd_send_sync(uint16_t opcode, struct net_buf *buf, return -ECONNREFUSED; case BT_HCI_ERR_INSUFFICIENT_RESOURCES: return -ENOMEM; + case BT_HCI_ERR_INVALID_PARAM: + return -EINVAL; default: return -EIO; } From c146833fc81542626df34453140d061ec158ce7e Mon Sep 17 00:00:00 2001 From: "Najumon B.A" Date: Mon, 11 Dec 2023 19:11:43 +0530 Subject: [PATCH 1535/3723] drivers: pcie: fix for mmio size region calculation I/O or memory decoding should be disabled via the command register before sizing BAR for calculation MMIO size Signed-off-by: Najumon B.A --- drivers/pcie/host/pcie.c | 21 +++++++++++++++------ 1 file changed, 15 insertions(+), 6 deletions(-) diff --git a/drivers/pcie/host/pcie.c b/drivers/pcie/host/pcie.c index a4d9fdbe504..d827e326fd7 100644 --- a/drivers/pcie/host/pcie.c +++ b/drivers/pcie/host/pcie.c @@ -126,6 +126,8 @@ static bool pcie_get_bar(pcie_bdf_t bdf, bool io) { uint32_t reg = bar_index + PCIE_CONF_BAR0; + uint32_t cmd_reg = pcie_conf_read(bdf, PCIE_CONF_CMDSTAT); + bool ret = false; #ifdef CONFIG_PCIE_CONTROLLER const struct device *dev; #endif @@ -156,6 +158,9 @@ static bool pcie_get_bar(pcie_bdf_t bdf, return false; } + /* IO/memory decode should be disabled before sizing/update BAR. */ + pcie_conf_write(bdf, PCIE_CONF_CMDSTAT, cmd_reg & (~0x3)); + pcie_conf_write(bdf, reg, 0xFFFFFFFFU); size = pcie_conf_read(bdf, reg); pcie_conf_write(bdf, reg, (uint32_t)phys_addr); @@ -167,7 +172,7 @@ static bool pcie_get_bar(pcie_bdf_t bdf, if (PCIE_CONF_BAR_ADDR(phys_addr) == PCIE_CONF_BAR_INVAL64 || PCIE_CONF_BAR_ADDR(phys_addr) == PCIE_CONF_BAR_NONE) { /* Discard on invalid address */ - return false; + goto err_exit; } pcie_conf_write(bdf, reg, 0xFFFFFFFFU); @@ -176,20 +181,20 @@ static bool pcie_get_bar(pcie_bdf_t bdf, } else if (PCIE_CONF_BAR_ADDR(phys_addr) == PCIE_CONF_BAR_INVAL || PCIE_CONF_BAR_ADDR(phys_addr) == PCIE_CONF_BAR_NONE) { /* Discard on invalid address */ - return false; + goto err_exit; } if (PCIE_CONF_BAR_IO(phys_addr)) { size = PCIE_CONF_BAR_IO_ADDR(size); if (size == 0) { /* Discard on invalid size */ - return false; + goto err_exit; } } else { size = PCIE_CONF_BAR_ADDR(size); if (size == 0) { /* Discard on invalid size */ - return false; + goto err_exit; } } @@ -201,14 +206,18 @@ static bool pcie_get_bar(pcie_bdf_t bdf, PCIE_CONF_BAR_ADDR(phys_addr) : PCIE_CONF_BAR_IO_ADDR(phys_addr), &bar->phys_addr)) { - return false; + goto err_exit; } #else bar->phys_addr = PCIE_CONF_BAR_ADDR(phys_addr); #endif /* CONFIG_PCIE_CONTROLLER */ bar->size = size & ~(size-1); - return true; + ret = true; +err_exit: + pcie_conf_write(bdf, PCIE_CONF_CMDSTAT, cmd_reg); + + return ret; } /** From 32276bc2c1042e52dc35c3ed6810408a63804f25 Mon Sep 17 00:00:00 2001 From: TOKITA Hiroshi Date: Thu, 23 Nov 2023 15:30:06 +0900 Subject: [PATCH 1536/3723] drivers: clock_control: ra: fix initialization of the clock_hw_cycles We should set the z_clock_hw_cycles_per_sec as the value of the system clock frequency. There was a mistake in referencing the clock source set before initialization. I corrected it to reflect the clock value after initialization. Signed-off-by: TOKITA Hiroshi --- drivers/clock_control/clock_control_ra.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/drivers/clock_control/clock_control_ra.c b/drivers/clock_control/clock_control_ra.c index d3549c1e7c4..6211717b56a 100644 --- a/drivers/clock_control/clock_control_ra.c +++ b/drivers/clock_control/clock_control_ra.c @@ -289,6 +289,8 @@ static int clock_control_ra_init(const struct device *dev) SYSTEM_write32(SCKDIVCR_OFFSET, SCKDIVCR_INIT_VALUE); SYSTEM_write8(SCKSCR_OFFSET, SCKSCR_INIT_VALUE); + /* re-read system clock setting and apply to hw_cycles */ + sysclk = SYSTEM_read8(SCKSCR_OFFSET); z_clock_hw_cycles_per_sec = clock_freqs[sysclk]; SYSTEM_write8(OPCCR_OFFSET, 0); From 4dde6dc0f18785cb104b1d8327f2ff9f0cc2cc3e Mon Sep 17 00:00:00 2001 From: TOKITA Hiroshi Date: Sat, 25 Nov 2023 14:11:52 +0900 Subject: [PATCH 1537/3723] dts: arm: renesas: ra: Enable built-in clock by default The hoco, moco, and loco are always available. Enable these by default. Signed-off-by: TOKITA Hiroshi --- dts/arm/renesas/ra/ra-cm4-common.dtsi | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/dts/arm/renesas/ra/ra-cm4-common.dtsi b/dts/arm/renesas/ra/ra-cm4-common.dtsi index 60157ab8b72..80e2f877c8a 100644 --- a/dts/arm/renesas/ra/ra-cm4-common.dtsi +++ b/dts/arm/renesas/ra/ra-cm4-common.dtsi @@ -39,21 +39,21 @@ hoco: hoco { compatible = "fixed-clock"; clock-frequency = <24000000>; - status = "disabled"; + status = "okay"; #clock-cells = <0>; }; moco: moco { compatible = "fixed-clock"; clock-frequency = <8000000>; - status = "disabled"; + status = "okay"; #clock-cells = <0>; }; loco: loco { compatible = "fixed-clock"; clock-frequency = <32768>; - status = "disabled"; + status = "okay"; #clock-cells = <0>; }; From 2f2d8143f4f94b65a35e20ddde686bf9fc0d7177 Mon Sep 17 00:00:00 2001 From: TOKITA Hiroshi Date: Thu, 23 Nov 2023 17:34:48 +0900 Subject: [PATCH 1538/3723] dt-bindings: interrupt-controller: ra-icu: Correct event numbers The 64 is a missing entry in this event number table. All after the 64th entry have shifted one before. https://www.renesas.com/jp/ja/document/mah/renesas-ra4m1-group-users-manual-hardware?r=1054146#G17.2544398 I corrected the after of the 64th entry to the correct number. Signed-off-by: TOKITA Hiroshi --- .../interrupt-controller/renesas-ra-icu.h | 237 +++++++++--------- 1 file changed, 119 insertions(+), 118 deletions(-) diff --git a/include/zephyr/dt-bindings/interrupt-controller/renesas-ra-icu.h b/include/zephyr/dt-bindings/interrupt-controller/renesas-ra-icu.h index 77372b76e21..4df6bfeae52 100644 --- a/include/zephyr/dt-bindings/interrupt-controller/renesas-ra-icu.h +++ b/include/zephyr/dt-bindings/interrupt-controller/renesas-ra-icu.h @@ -70,123 +70,124 @@ #define RA_ICU_IIC1_EEI (61 << 8) #define RA_ICU_SSIE0_SSITXI (62 << 8) #define RA_ICU_SSIE0_SSIRXI (63 << 8) -#define RA_ICU_SSIE0_SSIF (64 << 8) -#define RA_ICU_CTSU_CTSUWR (65 << 8) -#define RA_ICU_CTSU_CTSURD (66 << 8) -#define RA_ICU_CTSU_CTSUFN (67 << 8) -#define RA_ICU_KEY_INTKR (68 << 8) -#define RA_ICU_DOC_DOPCI (69 << 8) -#define RA_ICU_CAC_FERRI (70 << 8) -#define RA_ICU_CAC_MENDI (71 << 8) -#define RA_ICU_CAC_OVFI (72 << 8) -#define RA_ICU_CAN0_ERS (73 << 8) -#define RA_ICU_CAN0_RXF (74 << 8) -#define RA_ICU_CAN0_TXF (75 << 8) -#define RA_ICU_CAN0_RXM (76 << 8) -#define RA_ICU_CAN0_TXM (77 << 8) -#define RA_ICU_IOPORT_GROUP1 (78 << 8) -#define RA_ICU_IOPORT_GROUP2 (79 << 8) -#define RA_ICU_IOPORT_GROUP3 (80 << 8) -#define RA_ICU_IOPORT_GROUP4 (81 << 8) -#define RA_ICU_ELC_SWEVT0 (82 << 8) -#define RA_ICU_ELC_SWEVT1 (83 << 8) -#define RA_ICU_POEG_GROUP0 (84 << 8) -#define RA_ICU_POEG_GROUP1 (85 << 8) -#define RA_ICU_GPT0_CCMPA (86 << 8) -#define RA_ICU_GPT0_CCMPB (87 << 8) -#define RA_ICU_GPT0_CMPC (88 << 8) -#define RA_ICU_GPT0_CMPD (89 << 8) -#define RA_ICU_GPT0_CMPE (90 << 8) -#define RA_ICU_GPT0_CMPF (91 << 8) -#define RA_ICU_GPT0_OVF (92 << 8) -#define RA_ICU_GPT0_UDF (93 << 8) -#define RA_ICU_GPT1_CCMPA (94 << 8) -#define RA_ICU_GPT1_CCMPB (95 << 8) -#define RA_ICU_GPT1_CMPC (96 << 8) -#define RA_ICU_GPT1_CMPD (97 << 8) -#define RA_ICU_GPT1_CMPE (98 << 8) -#define RA_ICU_GPT1_CMPF (99 << 8) -#define RA_ICU_GPT1_OVF (100 << 8) -#define RA_ICU_GPT1_UDF (101 << 8) -#define RA_ICU_GPT2_CCMPA (102 << 8) -#define RA_ICU_GPT2_CCMPB (103 << 8) -#define RA_ICU_GPT2_CMPC (104 << 8) -#define RA_ICU_GPT2_CMPD (105 << 8) -#define RA_ICU_GPT2_CMPE (106 << 8) -#define RA_ICU_GPT2_CMPF (107 << 8) -#define RA_ICU_GPT2_OVF (108 << 8) -#define RA_ICU_GPT2_UDF (109 << 8) -#define RA_ICU_GPT3_CCMPA (110 << 8) -#define RA_ICU_GPT3_CCMPB (111 << 8) -#define RA_ICU_GPT3_CMPC (112 << 8) -#define RA_ICU_GPT3_CMPD (113 << 8) -#define RA_ICU_GPT3_CMPE (114 << 8) -#define RA_ICU_GPT3_CMPF (115 << 8) -#define RA_ICU_GPT3_OVF (116 << 8) -#define RA_ICU_GPT3_UDF (117 << 8) -#define RA_ICU_GPT4_CCMPA (118 << 8) -#define RA_ICU_GPT4_CCMPB (119 << 8) -#define RA_ICU_GPT4_CMPC (120 << 8) -#define RA_ICU_GPT4_CMPD (121 << 8) -#define RA_ICU_GPT4_CMPE (122 << 8) -#define RA_ICU_GPT4_CMPF (123 << 8) -#define RA_ICU_GPT4_OVF (124 << 8) -#define RA_ICU_GPT4_UDF (125 << 8) -#define RA_ICU_GPT5_CCMPA (126 << 8) -#define RA_ICU_GPT5_CCMPB (127 << 8) -#define RA_ICU_GPT5_CMPC (128 << 8) -#define RA_ICU_GPT5_CMPD (129 << 8) -#define RA_ICU_GPT5_CMPE (130 << 8) -#define RA_ICU_GPT5_CMPF (131 << 8) -#define RA_ICU_GPT5_OVF (132 << 8) -#define RA_ICU_GPT5_UDF (133 << 8) -#define RA_ICU_GPT6_CCMPA (134 << 8) -#define RA_ICU_GPT6_CCMPB (135 << 8) -#define RA_ICU_GPT6_CMPC (136 << 8) -#define RA_ICU_GPT6_CMPD (137 << 8) -#define RA_ICU_GPT6_CMPE (138 << 8) -#define RA_ICU_GPT6_CMPF (139 << 8) -#define RA_ICU_GPT6_OVF (140 << 8) -#define RA_ICU_GPT6_UDF (141 << 8) -#define RA_ICU_GPT7_CCMPA (142 << 8) -#define RA_ICU_GPT7_CCMPB (143 << 8) -#define RA_ICU_GPT7_CMPC (144 << 8) -#define RA_ICU_GPT7_CMPD (145 << 8) -#define RA_ICU_GPT7_CMPE (146 << 8) -#define RA_ICU_GPT7_CMPF (147 << 8) -#define RA_ICU_GPT7_OVF (148 << 8) -#define RA_ICU_GPT7_UDF (149 << 8) -#define RA_ICU_GPT_UVWEDGE (150 << 8) -#define RA_ICU_SCI0_RXI (151 << 8) -#define RA_ICU_SCI0_TXI (152 << 8) -#define RA_ICU_SCI0_TEI (153 << 8) -#define RA_ICU_SCI0_ERI (154 << 8) -#define RA_ICU_SCI0_AM (155 << 8) -#define RA_ICU_SCI0_RXI_OR_ERI (156 << 8) -#define RA_ICU_SCI1_RXI (157 << 8) -#define RA_ICU_SCI1_TXI (158 << 8) -#define RA_ICU_SCI1_TEI (159 << 8) -#define RA_ICU_SCI1_ERI (160 << 8) -#define RA_ICU_SCI1_AM (161 << 8) -#define RA_ICU_SCI2_RXI (162 << 8) -#define RA_ICU_SCI2_TXI (163 << 8) -#define RA_ICU_SCI2_TEI (164 << 8) -#define RA_ICU_SCI2_ERI (165 << 8) -#define RA_ICU_SCI2_AM (166 << 8) -#define RA_ICU_SCI9_RXI (167 << 8) -#define RA_ICU_SCI9_TXI (168 << 8) -#define RA_ICU_SCI9_TEI (169 << 8) -#define RA_ICU_SCI9_ERI (170 << 8) -#define RA_ICU_SCI9_AM (171 << 8) -#define RA_ICU_SPI0_SPRI (172 << 8) -#define RA_ICU_SPI0_SPTI (173 << 8) -#define RA_ICU_SPI0_SPII (174 << 8) -#define RA_ICU_SPI0_SPEI (175 << 8) -#define RA_ICU_SPI0_SPTEND (176 << 8) -#define RA_ICU_SPI1_SPRI (177 << 8) -#define RA_ICU_SPI1_SPTI (178 << 8) -#define RA_ICU_SPI1_SPII (179 << 8) -#define RA_ICU_SPI1_SPEI (180 << 8) -#define RA_ICU_SPI1_SPTEND (181 << 8) + +#define RA_ICU_SSIE0_SSIF (65 << 8) +#define RA_ICU_CTSU_CTSUWR (66 << 8) +#define RA_ICU_CTSU_CTSURD (67 << 8) +#define RA_ICU_CTSU_CTSUFN (68 << 8) +#define RA_ICU_KEY_INTKR (69 << 8) +#define RA_ICU_DOC_DOPCI (70 << 8) +#define RA_ICU_CAC_FERRI (71 << 8) +#define RA_ICU_CAC_MENDI (72 << 8) +#define RA_ICU_CAC_OVFI (73 << 8) +#define RA_ICU_CAN0_ERS (74 << 8) +#define RA_ICU_CAN0_RXF (75 << 8) +#define RA_ICU_CAN0_TXF (76 << 8) +#define RA_ICU_CAN0_RXM (77 << 8) +#define RA_ICU_CAN0_TXM (78 << 8) +#define RA_ICU_IOPORT_GROUP1 (70 << 8) +#define RA_ICU_IOPORT_GROUP2 (80 << 8) +#define RA_ICU_IOPORT_GROUP3 (81 << 8) +#define RA_ICU_IOPORT_GROUP4 (82 << 8) +#define RA_ICU_ELC_SWEVT0 (83 << 8) +#define RA_ICU_ELC_SWEVT1 (84 << 8) +#define RA_ICU_POEG_GROUP0 (85 << 8) +#define RA_ICU_POEG_GROUP1 (86 << 8) +#define RA_ICU_GPT0_CCMPA (87 << 8) +#define RA_ICU_GPT0_CCMPB (88 << 8) +#define RA_ICU_GPT0_CMPC (89 << 8) +#define RA_ICU_GPT0_CMPD (90 << 8) +#define RA_ICU_GPT0_CMPE (91 << 8) +#define RA_ICU_GPT0_CMPF (92 << 8) +#define RA_ICU_GPT0_OVF (93 << 8) +#define RA_ICU_GPT0_UDF (94 << 8) +#define RA_ICU_GPT1_CCMPA (95 << 8) +#define RA_ICU_GPT1_CCMPB (96 << 8) +#define RA_ICU_GPT1_CMPC (97 << 8) +#define RA_ICU_GPT1_CMPD (98 << 8) +#define RA_ICU_GPT1_CMPE (99 << 8) +#define RA_ICU_GPT1_CMPF (100 << 8) +#define RA_ICU_GPT1_OVF (101 << 8) +#define RA_ICU_GPT1_UDF (102 << 8) +#define RA_ICU_GPT2_CCMPA (103 << 8) +#define RA_ICU_GPT2_CCMPB (104 << 8) +#define RA_ICU_GPT2_CMPC (105 << 8) +#define RA_ICU_GPT2_CMPD (106 << 8) +#define RA_ICU_GPT2_CMPE (107 << 8) +#define RA_ICU_GPT2_CMPF (108 << 8) +#define RA_ICU_GPT2_OVF (109 << 8) +#define RA_ICU_GPT2_UDF (110 << 8) +#define RA_ICU_GPT3_CCMPA (111 << 8) +#define RA_ICU_GPT3_CCMPB (112 << 8) +#define RA_ICU_GPT3_CMPC (113 << 8) +#define RA_ICU_GPT3_CMPD (114 << 8) +#define RA_ICU_GPT3_CMPE (115 << 8) +#define RA_ICU_GPT3_CMPF (116 << 8) +#define RA_ICU_GPT3_OVF (117 << 8) +#define RA_ICU_GPT3_UDF (118 << 8) +#define RA_ICU_GPT4_CCMPA (119 << 8) +#define RA_ICU_GPT4_CCMPB (120 << 8) +#define RA_ICU_GPT4_CMPC (121 << 8) +#define RA_ICU_GPT4_CMPD (122 << 8) +#define RA_ICU_GPT4_CMPE (123 << 8) +#define RA_ICU_GPT4_CMPF (124 << 8) +#define RA_ICU_GPT4_OVF (125 << 8) +#define RA_ICU_GPT4_UDF (126 << 8) +#define RA_ICU_GPT5_CCMPA (127 << 8) +#define RA_ICU_GPT5_CCMPB (128 << 8) +#define RA_ICU_GPT5_CMPC (129 << 8) +#define RA_ICU_GPT5_CMPD (130 << 8) +#define RA_ICU_GPT5_CMPE (131 << 8) +#define RA_ICU_GPT5_CMPF (132 << 8) +#define RA_ICU_GPT5_OVF (133 << 8) +#define RA_ICU_GPT5_UDF (134 << 8) +#define RA_ICU_GPT6_CCMPA (135 << 8) +#define RA_ICU_GPT6_CCMPB (136 << 8) +#define RA_ICU_GPT6_CMPC (137 << 8) +#define RA_ICU_GPT6_CMPD (138 << 8) +#define RA_ICU_GPT6_CMPE (139 << 8) +#define RA_ICU_GPT6_CMPF (140 << 8) +#define RA_ICU_GPT6_OVF (141 << 8) +#define RA_ICU_GPT6_UDF (142 << 8) +#define RA_ICU_GPT7_CCMPA (143 << 8) +#define RA_ICU_GPT7_CCMPB (144 << 8) +#define RA_ICU_GPT7_CMPC (145 << 8) +#define RA_ICU_GPT7_CMPD (146 << 8) +#define RA_ICU_GPT7_CMPE (147 << 8) +#define RA_ICU_GPT7_CMPF (148 << 8) +#define RA_ICU_GPT7_OVF (149 << 8) +#define RA_ICU_GPT7_UDF (150 << 8) +#define RA_ICU_GPT_UVWEDGE (151 << 8) +#define RA_ICU_SCI0_RXI (152 << 8) +#define RA_ICU_SCI0_TXI (153 << 8) +#define RA_ICU_SCI0_TEI (154 << 8) +#define RA_ICU_SCI0_ERI (155 << 8) +#define RA_ICU_SCI0_AM (156 << 8) +#define RA_ICU_SCI0_RXI_OR_ERI (157 << 8) +#define RA_ICU_SCI1_RXI (158 << 8) +#define RA_ICU_SCI1_TXI (159 << 8) +#define RA_ICU_SCI1_TEI (160 << 8) +#define RA_ICU_SCI1_ERI (161 << 8) +#define RA_ICU_SCI1_AM (162 << 8) +#define RA_ICU_SCI2_RXI (163 << 8) +#define RA_ICU_SCI2_TXI (164 << 8) +#define RA_ICU_SCI2_TEI (165 << 8) +#define RA_ICU_SCI2_ERI (166 << 8) +#define RA_ICU_SCI2_AM (167 << 8) +#define RA_ICU_SCI9_RXI (168 << 8) +#define RA_ICU_SCI9_TXI (169 << 8) +#define RA_ICU_SCI9_TEI (170 << 8) +#define RA_ICU_SCI9_ERI (171 << 8) +#define RA_ICU_SCI9_AM (172 << 8) +#define RA_ICU_SPI0_SPRI (173 << 8) +#define RA_ICU_SPI0_SPTI (174 << 8) +#define RA_ICU_SPI0_SPII (175 << 8) +#define RA_ICU_SPI0_SPEI (176 << 8) +#define RA_ICU_SPI0_SPTEND (177 << 8) +#define RA_ICU_SPI1_SPRI (178 << 8) +#define RA_ICU_SPI1_SPTI (179 << 8) +#define RA_ICU_SPI1_SPII (180 << 8) +#define RA_ICU_SPI1_SPEI (181 << 8) +#define RA_ICU_SPI1_SPTEND (182 << 8) #endif /* ZEPHYR_DT_BINDINGS_INTERRUPT_CONTROLLER_RENESAS_RA_ICU_H_ */ From 096635b21272ac177c356bcc68673b4324864c35 Mon Sep 17 00:00:00 2001 From: Anisetti Avinash Krishna Date: Thu, 21 Dec 2023 12:05:13 +0530 Subject: [PATCH 1539/3723] drivers: dma: intel_lpss: update LPSS DMA init interface Update LPSS DMA init interface which is common and independent of parent-node. Signed-off-by: Anisetti Avinash Krishna --- drivers/dma/dma_intel_lpss.c | 37 +++--------------------------------- 1 file changed, 3 insertions(+), 34 deletions(-) diff --git a/drivers/dma/dma_intel_lpss.c b/drivers/dma/dma_intel_lpss.c index 346b78ff334..02d97010df3 100644 --- a/drivers/dma/dma_intel_lpss.c +++ b/drivers/dma/dma_intel_lpss.c @@ -24,7 +24,6 @@ LOG_MODULE_REGISTER(dma_intel_lpss, CONFIG_DMA_LOG_LEVEL); struct dma_intel_lpss_cfg { struct dw_dma_dev_cfg dw_cfg; - const struct device *parent; }; int dma_intel_lpss_setup(const struct device *dev) @@ -45,28 +44,6 @@ void dma_intel_lpss_set_base(const struct device *dev, uintptr_t base) dev_cfg->dw_cfg.base = base; } -static int dma_intel_lpss_init(const struct device *dev) -{ - struct dma_intel_lpss_cfg *dev_cfg = (struct dma_intel_lpss_cfg *)dev->config; - uint32_t base; - int ret; - - if (device_is_ready(dev_cfg->parent)) { - base = DEVICE_MMIO_GET(dev_cfg->parent) + DMA_INTEL_LPSS_OFFSET; - dev_cfg->dw_cfg.base = base; - } - - ret = dma_intel_lpss_setup(dev); - - if (ret != 0) { - LOG_ERR("failed to initialize LPSS DMA %s", dev->name); - goto out; - } - ret = 0; -out: - return ret; -} - int dma_intel_lpss_reload(const struct device *dev, uint32_t channel, uint64_t src, uint64_t dst, size_t size) { @@ -155,12 +132,6 @@ static const struct dma_driver_api dma_intel_lpss_driver_api = { .stop = dw_dma_stop, }; -#define DMA_LPSS_INIT_VAL_0 49 /* When parent device depends on DMA */ -#define DMA_LPSS_INIT_VAL_1 80 /* When DMA device depends on parent */ - -#define DMA_LPSS_INIT_VAL(n)\ - _CONCAT(DMA_LPSS_INIT_VAL_, DT_INST_NODE_HAS_PROP(n, dma_parent)) - #define DMA_INTEL_LPSS_INIT(n) \ \ static struct dw_drv_plat_data dma_intel_lpss##n = { \ @@ -179,8 +150,6 @@ static const struct dma_driver_api dma_intel_lpss_driver_api = { .dw_cfg = { \ .base = 0, \ }, \ - IF_ENABLED(DT_INST_NODE_HAS_PROP(n, dma_parent), \ - (.parent = DEVICE_DT_GET(DT_INST_PHANDLE(n, dma_parent)),))\ }; \ \ static struct dw_dma_dev_data dma_intel_lpss##n##_data = { \ @@ -188,11 +157,11 @@ static const struct dma_driver_api dma_intel_lpss_driver_api = { }; \ \ DEVICE_DT_INST_DEFINE(n, \ - &dma_intel_lpss_init, \ + NULL, \ NULL, \ &dma_intel_lpss##n##_data, \ - &dma_intel_lpss##n##_config, POST_KERNEL, \ - DMA_LPSS_INIT_VAL(n), \ + &dma_intel_lpss##n##_config, PRE_KERNEL_1, \ + CONFIG_DMA_INIT_PRIORITY, \ &dma_intel_lpss_driver_api); \ DT_INST_FOREACH_STATUS_OKAY(DMA_INTEL_LPSS_INIT) From a0ce427848579aacc92da5e9ccf5cd78cadbd9eb Mon Sep 17 00:00:00 2001 From: Anisetti Avinash Krishna Date: Thu, 21 Dec 2023 12:22:23 +0530 Subject: [PATCH 1540/3723] drivers: dma: intel_lpss: enable reload API for 32bit DMA address Enable dma_reload API for DMA 32bit address transfer. Signed-off-by: Anisetti Avinash Krishna --- drivers/dma/dma_intel_lpss.c | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/drivers/dma/dma_intel_lpss.c b/drivers/dma/dma_intel_lpss.c index 02d97010df3..ad004fc1cf8 100644 --- a/drivers/dma/dma_intel_lpss.c +++ b/drivers/dma/dma_intel_lpss.c @@ -44,8 +44,13 @@ void dma_intel_lpss_set_base(const struct device *dev, uintptr_t base) dev_cfg->dw_cfg.base = base; } +#ifdef CONFIG_DMA_64BIT int dma_intel_lpss_reload(const struct device *dev, uint32_t channel, uint64_t src, uint64_t dst, size_t size) +#else +int dma_intel_lpss_reload(const struct device *dev, uint32_t channel, + uint32_t src, uint32_t dst, size_t size) +#endif { struct dw_dma_dev_data *const dev_data = dev->data; struct dma_intel_lpss_cfg *lpss_dev_cfg = (struct dma_intel_lpss_cfg *)dev->config; From 53b717edd6d58a9678780bb4a75bf8fae6c1c622 Mon Sep 17 00:00:00 2001 From: Anisetti Avinash Krishna Date: Thu, 21 Dec 2023 12:33:10 +0530 Subject: [PATCH 1541/3723] drivers: i2c: i2c_dw: update DMA node access in I2C dw Update DMA node access from paren-node to dmas property in dts instance. Signed-off-by: Anisetti Avinash Krishna --- drivers/i2c/i2c_dw.c | 35 +++++++++++++++++++++++------------ drivers/i2c/i2c_dw.h | 5 ++++- 2 files changed, 27 insertions(+), 13 deletions(-) diff --git a/drivers/i2c/i2c_dw.c b/drivers/i2c/i2c_dw.c index ca4485606b7..3dd006fb5ae 100644 --- a/drivers/i2c/i2c_dw.c +++ b/drivers/i2c/i2c_dw.c @@ -74,9 +74,10 @@ void cb_i2c_idma_transfer(const struct device *dma, void *user_data, uint32_t channel, int status) { const struct device *dev = (const struct device *)user_data; + const struct i2c_dw_rom_config * const rom = dev->config; struct i2c_dw_dev_config *const dw = dev->data; - dma_stop(dw->dma_dev, channel); + dma_stop(rom->dma_dev, channel); i2c_dw_enable_idma(dev, false); if (status) { @@ -104,11 +105,12 @@ inline void *i2c_dw_dr_phy_addr(const struct device *dev) int32_t i2c_dw_idma_rx_transfer(const struct device *dev) { struct i2c_dw_dev_config *const dw = dev->data; + const struct i2c_dw_rom_config * const rom = dev->config; struct dma_config dma_cfg = { 0 }; struct dma_block_config dma_block_cfg = { 0 }; - if (!device_is_ready(dw->dma_dev)) { + if (!device_is_ready(rom->dma_dev)) { LOG_DBG("DMA device is not ready"); return -ENODEV; } @@ -131,12 +133,12 @@ int32_t i2c_dw_idma_rx_transfer(const struct device *dev) dma_block_cfg.source_address = (uint64_t)i2c_dw_dr_phy_addr(dev); dw->xfr_status = false; - if (dma_config(dw->dma_dev, DMA_INTEL_LPSS_RX_CHAN, &dma_cfg)) { + if (dma_config(rom->dma_dev, DMA_INTEL_LPSS_RX_CHAN, &dma_cfg)) { LOG_DBG("Error transfer"); return -EIO; } - if (dma_start(dw->dma_dev, DMA_INTEL_LPSS_RX_CHAN)) { + if (dma_start(rom->dma_dev, DMA_INTEL_LPSS_RX_CHAN)) { LOG_DBG("Error transfer"); return -EIO; } @@ -150,12 +152,13 @@ int32_t i2c_dw_idma_rx_transfer(const struct device *dev) int32_t i2c_dw_idma_tx_transfer(const struct device *dev, uint64_t data) { + const struct i2c_dw_rom_config * const rom = dev->config; struct i2c_dw_dev_config *const dw = dev->data; struct dma_config dma_cfg = { 0 }; struct dma_block_config dma_block_cfg = { 0 }; - if (!device_is_ready(dw->dma_dev)) { + if (!device_is_ready(rom->dma_dev)) { LOG_DBG("DMA device is not ready"); return -ENODEV; } @@ -178,12 +181,12 @@ int32_t i2c_dw_idma_tx_transfer(const struct device *dev, dma_block_cfg.dest_address = (uint64_t)i2c_dw_dr_phy_addr(dev); dw->xfr_status = false; - if (dma_config(dw->dma_dev, DMA_INTEL_LPSS_TX_CHAN, &dma_cfg)) { + if (dma_config(rom->dma_dev, DMA_INTEL_LPSS_TX_CHAN, &dma_cfg)) { LOG_DBG("Error transfer"); return -EIO; } - if (dma_start(dw->dma_dev, DMA_INTEL_LPSS_TX_CHAN)) { + if (dma_start(rom->dma_dev, DMA_INTEL_LPSS_TX_CHAN)) { LOG_DBG("Error trnasfer"); return -EIO; } @@ -390,8 +393,9 @@ static void i2c_dw_isr(const struct device *port) uint32_t stat = sys_read32(reg_base + IDMA_REG_INTR_STS); if (stat & IDMA_TX_RX_CHAN_MASK) { + const struct i2c_dw_rom_config * const rom = port->config; /* Handle the DMA interrupt */ - dma_intel_lpss_isr(dw->dma_dev); + dma_intel_lpss_isr(rom->dma_dev); } #endif @@ -1049,11 +1053,11 @@ static int i2c_dw_initialize(const struct device *dev) pcie_set_cmd(rom->pcie->bdf, PCIE_CONF_CMDSTAT_MASTER, true); #ifdef CONFIG_I2C_DW_LPSS_DMA - size_t nhdls = 0; - const device_handle_t *hdls; + uintptr_t base; - hdls = device_supported_handles_get(dev, &nhdls); - dw->dma_dev = device_from_handle(*hdls); + base = DEVICE_MMIO_GET(dev) + DMA_INTEL_LPSS_OFFSET; + dma_intel_lpss_set_base(rom->dma_dev, base); + dma_intel_lpss_setup(rom->dma_dev); /* Assign physical & virtual address to dma instance */ dw->phy_addr = mbar.phys_addr; @@ -1184,6 +1188,12 @@ static int i2c_dw_initialize(const struct device *dev) #define I2C_CONFIG_REG_INIT(n) \ _CONCAT(I2C_CONFIG_REG_INIT_PCIE, DT_INST_ON_BUS(n, pcie))(n) +#define I2C_CONFIG_DMA_INIT(n) \ + COND_CODE_1(CONFIG_I2C_DW_LPSS_DMA, \ + (COND_CODE_1(DT_INST_NODE_HAS_PROP(n, dmas), \ + (.dma_dev = DEVICE_DT_GET(DT_INST_DMAS_CTLR_BY_IDX(n, 0)),), \ + ())), ()) + #define I2C_DEVICE_INIT_DW(n) \ PINCTRL_DW_DEFINE(n); \ I2C_PCIE_DEFINE(n); \ @@ -1195,6 +1205,7 @@ static int i2c_dw_initialize(const struct device *dev) RESET_DW_CONFIG(n) \ PINCTRL_DW_CONFIG(n) \ I2C_DW_INIT_PCIE(n) \ + I2C_CONFIG_DMA_INIT(n) \ }; \ static struct i2c_dw_dev_config i2c_##n##_runtime; \ I2C_DEVICE_DT_INST_DEFINE(n, i2c_dw_initialize, NULL, \ diff --git a/drivers/i2c/i2c_dw.h b/drivers/i2c/i2c_dw.h index 34427504708..c25246bbafe 100644 --- a/drivers/i2c/i2c_dw.h +++ b/drivers/i2c/i2c_dw.h @@ -104,6 +104,10 @@ struct i2c_dw_rom_config { #if DT_ANY_INST_ON_BUS_STATUS_OKAY(pcie) struct pcie_dev *pcie; #endif /* I2C_DW_PCIE_ENABLED */ + +#ifdef CONFIG_I2C_DW_LPSS_DMA + const struct device *dma_dev; +#endif }; struct i2c_dw_dev_config { @@ -124,7 +128,6 @@ struct i2c_dw_dev_config { uint8_t xfr_flags; bool support_hs_mode; #ifdef CONFIG_I2C_DW_LPSS_DMA - const struct device *dma_dev; uintptr_t phy_addr; uintptr_t base_addr; /* For dma transfer */ From 6bc401f30af37fe8be6aa68162096c2c218a1c43 Mon Sep 17 00:00:00 2001 From: Anisetti Avinash Krishna Date: Thu, 21 Dec 2023 12:38:04 +0530 Subject: [PATCH 1542/3723] dts: x86: intel: raptor_lake: update DMA and I2C instance Update DMA and I2C to support latest LPSS DMA interface. Signed-off-by: Anisetti Avinash Krishna --- dts/x86/intel/raptor_lake.dtsi | 42 +++++++++++++++++----------------- 1 file changed, 21 insertions(+), 21 deletions(-) diff --git a/dts/x86/intel/raptor_lake.dtsi b/dts/x86/intel/raptor_lake.dtsi index ab3e9958928..bafee1dc403 100644 --- a/dts/x86/intel/raptor_lake.dtsi +++ b/dts/x86/intel/raptor_lake.dtsi @@ -62,6 +62,12 @@ status = "okay"; }; + i2c0_dma: i2c0_dma { + compatible = "intel,lpss"; + #dma-cells = <1>; + status = "okay"; + }; + i2c0: i2c0 { compatible = "snps,designware-i2c"; clock-frequency = ; @@ -71,13 +77,13 @@ device-id = <0x7acc>; interrupts = ; interrupt-parent = <&intc>; + dmas = <&i2c0_dma 0>; status = "okay"; }; - i2c0_dma: i2c0_dma { + i2c1_dma: i2c1_dma { compatible = "intel,lpss"; - dma-parent = <&i2c0>; #dma-cells = <1>; status = "disabled"; }; @@ -91,13 +97,13 @@ device-id = <0x7acd>; interrupts = ; interrupt-parent = <&intc>; + dmas = <&i2c1_dma 0>; status = "disabled"; }; - i2c1_dma: i2c1_dma { + i2c2_dma: i2c2_dma { compatible = "intel,lpss"; - dma-parent = <&i2c1>; #dma-cells = <1>; status = "disabled"; }; @@ -113,13 +119,13 @@ device-id = <0x7ace>; interrupts = ; interrupt-parent = <&intc>; + dmas = <&i2c2_dma 0>; status = "disabled"; }; - i2c2_dma: i2c2_dma { + i2c3_dma: i2c3_dma { compatible = "intel,lpss"; - dma-parent = <&i2c2>; #dma-cells = <1>; status = "disabled"; }; @@ -133,13 +139,13 @@ device-id = <0x7acf>; interrupts = ; interrupt-parent = <&intc>; + dmas = <&i2c3_dma 0>; status = "disabled"; }; - i2c3_dma: i2c3_dma { + i2c4_dma: i2c4_dma { compatible = "intel,lpss"; - dma-parent = <&i2c3>; #dma-cells = <1>; status = "disabled"; }; @@ -153,13 +159,13 @@ device-id = <0x7afc>; interrupts = ; interrupt-parent = <&intc>; + dmas = <&i2c4_dma 0>; status = "disabled"; }; - i2c4_dma: i2c4_dma { + i2c5_dma: i2c5_dma { compatible = "intel,lpss"; - dma-parent = <&i2c4>; #dma-cells = <1>; status = "disabled"; }; @@ -173,13 +179,13 @@ device-id = <0x7afd>; interrupts = ; interrupt-parent = <&intc>; + dmas = <&i2c5_dma 0>; status = "disabled"; }; - i2c5_dma: i2c5_dma { + i2c6_dma: i2c6_dma { compatible = "intel,lpss"; - dma-parent = <&i2c5>; #dma-cells = <1>; status = "disabled"; }; @@ -193,13 +199,13 @@ device-id = <0x7ada>; interrupts = ; interrupt-parent = <&intc>; + dmas = <&i2c6_dma 0>; status = "disabled"; }; - i2c6_dma: i2c6_dma { + i2c7_dma: i2c7_dma { compatible = "intel,lpss"; - dma-parent = <&i2c6>; #dma-cells = <1>; status = "disabled"; }; @@ -213,17 +219,11 @@ device-id = <0x7adb>; interrupts = ; interrupt-parent = <&intc>; + dmas = <&i2c7_dma 0>; status = "disabled"; }; - i2c7_dma: i2c7_dma { - compatible = "intel,lpss"; - dma-parent = <&i2c7>; - #dma-cells = <1>; - status = "disabled"; - }; - spi0: spi0 { compatible = "intel,penwell-spi"; vendor-id = <0x8086>; From 2052e9f19bb57ca9ae6725683b9731ef0206d38f Mon Sep 17 00:00:00 2001 From: Anisetti Avinash Krishna Date: Thu, 21 Dec 2023 12:20:23 +0530 Subject: [PATCH 1543/3723] dts: bindings: dma: intel_lpss: remove parent-node Remove parent node to make a common interface for LPSS DMA. Signed-off-by: Anisetti Avinash Krishna --- dts/bindings/dma/intel,lpss.yaml | 5 ----- 1 file changed, 5 deletions(-) diff --git a/dts/bindings/dma/intel,lpss.yaml b/dts/bindings/dma/intel,lpss.yaml index 5f1954216f0..d9fc4a60f11 100644 --- a/dts/bindings/dma/intel,lpss.yaml +++ b/dts/bindings/dma/intel,lpss.yaml @@ -11,10 +11,5 @@ properties: "#dma-cells": const: 1 - dma-parent: - type: phandle - description: | - Parent device for LPSS DMA to get its base address. - dma-cells: - channel From eb12e5454f6df8eb253753c968b80c9059e9357e Mon Sep 17 00:00:00 2001 From: Kelly Helmut Lord Date: Wed, 4 Oct 2023 21:16:43 -0400 Subject: [PATCH 1544/3723] board: Add support for Adafruit QT PY RP2040 Adding support for the Adafruit QT PY RP2040. Signed-off-by: Kelly Helmut Lord Signed-off-by: Ian Wakely --- .../arm/adafruit_qt_py_rp2040/Kconfig.board | 6 + .../adafruit_qt_py_rp2040/Kconfig.defconfig | 22 +++ .../adafruit_qt_py_rp2040-pinctrl.dtsi | 64 +++++++++ .../adafruit_qt_py_rp2040.dts | 119 ++++++++++++++++ .../adafruit_qt_py_rp2040.yaml | 23 ++++ .../adafruit_qt_py_rp2040_defconfig | 27 ++++ boards/arm/adafruit_qt_py_rp2040/board.cmake | 6 + .../doc/img/qtpy_rp2040.jpg | Bin 0 -> 87281 bytes .../arm/adafruit_qt_py_rp2040/doc/index.rst | 129 ++++++++++++++++++ .../seeed_xiao_connector.dtsi | 29 ++++ 10 files changed, 425 insertions(+) create mode 100644 boards/arm/adafruit_qt_py_rp2040/Kconfig.board create mode 100644 boards/arm/adafruit_qt_py_rp2040/Kconfig.defconfig create mode 100644 boards/arm/adafruit_qt_py_rp2040/adafruit_qt_py_rp2040-pinctrl.dtsi create mode 100644 boards/arm/adafruit_qt_py_rp2040/adafruit_qt_py_rp2040.dts create mode 100644 boards/arm/adafruit_qt_py_rp2040/adafruit_qt_py_rp2040.yaml create mode 100644 boards/arm/adafruit_qt_py_rp2040/adafruit_qt_py_rp2040_defconfig create mode 100644 boards/arm/adafruit_qt_py_rp2040/board.cmake create mode 100644 boards/arm/adafruit_qt_py_rp2040/doc/img/qtpy_rp2040.jpg create mode 100644 boards/arm/adafruit_qt_py_rp2040/doc/index.rst create mode 100644 boards/arm/adafruit_qt_py_rp2040/seeed_xiao_connector.dtsi diff --git a/boards/arm/adafruit_qt_py_rp2040/Kconfig.board b/boards/arm/adafruit_qt_py_rp2040/Kconfig.board new file mode 100644 index 00000000000..f2c8db2c341 --- /dev/null +++ b/boards/arm/adafruit_qt_py_rp2040/Kconfig.board @@ -0,0 +1,6 @@ +# Copyright (c) 2022 Kelly Lord +# SPDX-License-Identifier: Apache-2.0 + +config BOARD_ADAFRUIT_QT_PY_RP2040 + bool "Adafruit QT Py RP2040 Board" + depends on SOC_RP2040 diff --git a/boards/arm/adafruit_qt_py_rp2040/Kconfig.defconfig b/boards/arm/adafruit_qt_py_rp2040/Kconfig.defconfig new file mode 100644 index 00000000000..705a49ac152 --- /dev/null +++ b/boards/arm/adafruit_qt_py_rp2040/Kconfig.defconfig @@ -0,0 +1,22 @@ +# Copyright (c) 2022 Peter Johanson +# SPDX-License-Identifier: Apache-2.0 + +if BOARD_ADAFRUIT_QT_PY_RP2040 + +config BOARD + default "adafruit_qt_py_rp2040" + +config RP2_FLASH_W25Q080 + default y + +if I2C_DW + +config I2C_DW_CLOCK_SPEED + default 125 + +endif #I2C_DW + +config USB_SELF_POWERED + default n + +endif # BOARD_ADAFRUIT_QT_PY_RP2040 diff --git a/boards/arm/adafruit_qt_py_rp2040/adafruit_qt_py_rp2040-pinctrl.dtsi b/boards/arm/adafruit_qt_py_rp2040/adafruit_qt_py_rp2040-pinctrl.dtsi new file mode 100644 index 00000000000..2048e0580e0 --- /dev/null +++ b/boards/arm/adafruit_qt_py_rp2040/adafruit_qt_py_rp2040-pinctrl.dtsi @@ -0,0 +1,64 @@ +/* + * Copyright (c) 2021, Yonatan Schachter + * Copyright (c) 2022, Peter Johanson + * SPDX-License-Identifier: Apache-2.0 + */ + +#include + +&pinctrl { + uart1_default: uart1_default { + group1 { + pinmux = ; + }; + group2 { + pinmux = ; + input-enable; + }; + }; + + i2c0_default: i2c0_default { + group1 { + pinmux = ; + input-enable; + }; + group2 { + pinmux = ; + input-enable; + }; + }; + + i2c1_default: i2c1_default { + group1 { + pinmux = ; + input-enable; + }; + group2 { + pinmux = ; + input-enable; + }; + }; + + spi0_default: spi0_default { + group1 { + pinmux = ; + }; + group2 { + pinmux = ; + input-enable; + }; + group3 { + pinmux = ; + }; + }; + + adc_default: adc_default { + group1 { + pinmux = , , , ; + input-enable; + }; + }; + + clocks_default: clocks_default { + }; +}; diff --git a/boards/arm/adafruit_qt_py_rp2040/adafruit_qt_py_rp2040.dts b/boards/arm/adafruit_qt_py_rp2040/adafruit_qt_py_rp2040.dts new file mode 100644 index 00000000000..b42c48ab4d9 --- /dev/null +++ b/boards/arm/adafruit_qt_py_rp2040/adafruit_qt_py_rp2040.dts @@ -0,0 +1,119 @@ +/* + * Copyright (c) 2021 Yonatan Schachter + * Copyright (c) 2022 Peter Johanson + * + * SPDX-License-Identifier: Apache-2.0 + */ + +/dts-v1/; + +#include +#include "adafruit_qt_py_rp2040-pinctrl.dtsi" +#include "seeed_xiao_connector.dtsi" +#include + +/ { + chosen { + zephyr,sram = &sram0; + zephyr,flash = &flash0; + zephyr,flash-controller = &ssi; + zephyr,console = &uart1; + zephyr,shell-uart = &uart1; + zephyr,code-partition = &code_partition; + }; + + aliases { + watchdog0 = &wdt0; + }; +}; + +&flash0 { + reg = <0x10000000 DT_SIZE_M(8)>; + + partitions { + compatible = "fixed-partitions"; + #address-cells = <1>; + #size-cells = <1>; + + /* Reserved memory for the second stage bootloader */ + second_stage_bootloader: partition@0 { + label = "second_stage_bootloader"; + reg = <0x00000000 0x100>; + read-only; + }; + + /* + * Usable flash. Starts at 0x100, after the bootloader. The partition + * size is 8MB minus the 0x100 bytes taken by the bootloader. + */ + code_partition: partition@100 { + label = "code-partition"; + reg = <0x100 (DT_SIZE_M(8) - 0x100)>; + read-only; + }; + }; +}; + +&clocks { + pinctrl-0 = <&clocks_default>; + pinctrl-names = "default"; +}; + +&uart1 { + current-speed = <115200>; + status = "okay"; + pinctrl-0 = <&uart1_default>; + pinctrl-names = "default"; +}; + +&gpio0 { + status = "okay"; +}; + +&i2c0 { + clock-frequency = ; + status = "okay"; + pinctrl-0 = <&i2c0_default>; + pinctrl-names = "default"; +}; + +&i2c1 { + pinctrl-0 = <&i2c1_default>; + pinctrl-names = "default"; + status = "okay"; + clock-frequency = ; +}; + +&spi0 { + clock-frequency = ; + status = "okay"; + pinctrl-0 = <&spi0_default>; + pinctrl-names = "default"; +}; + +&timer { + status = "okay"; +}; + +&wdt0 { + status = "okay"; +}; + +&adc { + status = "okay"; + pinctrl-0 = <&adc_default>; + pinctrl-names = "default"; +}; + +&pio0 { + status = "okay"; +}; + +zephyr_udc0: &usbd { + status = "okay"; +}; + +&vreg { + regulator-always-on; + regulator-allowed-modes = ; +}; diff --git a/boards/arm/adafruit_qt_py_rp2040/adafruit_qt_py_rp2040.yaml b/boards/arm/adafruit_qt_py_rp2040/adafruit_qt_py_rp2040.yaml new file mode 100644 index 00000000000..2348e9cec55 --- /dev/null +++ b/boards/arm/adafruit_qt_py_rp2040/adafruit_qt_py_rp2040.yaml @@ -0,0 +1,23 @@ +identifier: adafruit_qt_py_rp2040 +name: Adafruit QT Py RP2040 +type: mcu +arch: arm +flash: 8192 +ram: 264 +toolchain: + - zephyr + - gnuarmemb + - xtools +supported: + - uart + - gpio + - adc + - i2c + - spi + - hwinfo + - watchdog + - pwm + - flash + - dma + - counter + - clock diff --git a/boards/arm/adafruit_qt_py_rp2040/adafruit_qt_py_rp2040_defconfig b/boards/arm/adafruit_qt_py_rp2040/adafruit_qt_py_rp2040_defconfig new file mode 100644 index 00000000000..d0987d6025f --- /dev/null +++ b/boards/arm/adafruit_qt_py_rp2040/adafruit_qt_py_rp2040_defconfig @@ -0,0 +1,27 @@ +# SPDX-License-Identifier: Apache-2.0 + +CONFIG_SOC_SERIES_RP2XXX=y +CONFIG_SOC_RP2040=y +CONFIG_BOARD_ADAFRUIT_QT_PY_RP2040=y + +CONFIG_SYS_CLOCK_HW_CYCLES_PER_SEC=125000000 + +# enable uart driver +CONFIG_SERIAL=y +CONFIG_UART_INTERRUPT_DRIVEN=y + +# enable console +CONFIG_CONSOLE=y +CONFIG_UART_CONSOLE=y + +# Enable reset by default +CONFIG_RESET=y + +# Enable clock control by default +CONFIG_CLOCK_CONTROL=y + +# Code partition needed to target the correct flash range +CONFIG_USE_DT_CODE_PARTITION=y + +# Output UF2 by default, native bootloader supports it. +CONFIG_BUILD_OUTPUT_UF2=y diff --git a/boards/arm/adafruit_qt_py_rp2040/board.cmake b/boards/arm/adafruit_qt_py_rp2040/board.cmake new file mode 100644 index 00000000000..affc290a869 --- /dev/null +++ b/boards/arm/adafruit_qt_py_rp2040/board.cmake @@ -0,0 +1,6 @@ +# SPDX-License-Identifier: Apache-2.0 +# Copyright (c) 2023 TOKITA Hiroshi + +board_runner_args(uf2 "--board-id=RPI-RP2") + +include(${ZEPHYR_BASE}/boards/common/uf2.board.cmake) diff --git a/boards/arm/adafruit_qt_py_rp2040/doc/img/qtpy_rp2040.jpg b/boards/arm/adafruit_qt_py_rp2040/doc/img/qtpy_rp2040.jpg new file mode 100644 index 0000000000000000000000000000000000000000..c1a7ab1dc28c42c234980144b742917e3f86900c GIT binary patch literal 87281 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 Xvmc0?W4tBrR~IFo&Uh&Q-@^X^nUu|3 literal 0 HcmV?d00001 diff --git a/boards/arm/adafruit_qt_py_rp2040/doc/index.rst b/boards/arm/adafruit_qt_py_rp2040/doc/index.rst new file mode 100644 index 00000000000..19b5a832223 --- /dev/null +++ b/boards/arm/adafruit_qt_py_rp2040/doc/index.rst @@ -0,0 +1,129 @@ +.. _adafruit_qt_py_rp2040: + +Adafruit QT Py RP2040 +##################### + +Overview +******** + +The Adafruit QT Py RP2040 is a small, low-cost, versatile board from +Adafruit. It is equipped with an RP2040 SoC, an on-board RGB Neopixel, +a USB connector, and a STEMMA QT connector. The USB bootloader allows +it to be flashed without any adapter, in a drag-and-drop manner. + +Hardware +******** +- Dual core Arm Cortex-M0+ processor running up to 133MHz +- 264KB on-chip SRAM +- 8MB on-board QSPI flash with XIP capabilities +- 11 GPIO pins +- 4 Analog inputs +- 2 UART peripherals +- 2 SPI controllers +- 2 I2C controllers (one via STEMMA QT connector) +- 16 PWM channels +- USB 1.1 controller (host/device) +- 8 Programmable I/O (PIO) for custom peripherals +- On-board RGB LED +- 1 Watchdog timer peripheral + + +.. figure:: img/qtpy_rp2040.jpg + :align: center + :alt: Adafruit QT Py RP2040 + + Adafruit QT Py RP2040 (Image courtesy of Adafruit) + +Supported Features +================== + +The adafruit_qt_py_rp2040 board configuration supports the following +hardware features: + +.. list-table:: + :header-rows: 1 + + * - Peripheral + - Kconfig option + - Devicetree compatible + * - NVIC + - N/A + - :dtcompatible:`arm,v6m-nvic` + * - UART + - :kconfig:option:`CONFIG_SERIAL` + - :dtcompatible:`raspberrypi,pico-uart` + * - GPIO + - :kconfig:option:`CONFIG_GPIO` + - :dtcompatible:`raspberrypi,pico-gpio` + * - ADC + - :kconfig:option:`CONFIG_ADC` + - :dtcompatible:`raspberrypi,pico-adc` + * - I2C + - :kconfig:option:`CONFIG_I2C` + - :dtcompatible:`snps,designware-i2c` + * - SPI + - :kconfig:option:`CONFIG_SPI` + - :dtcompatible:`raspberrypi,pico-spi` + * - USB Device + - :kconfig:option:`CONFIG_USB_DEVICE_STACK` + - :dtcompatible:`raspberrypi,pico-usbd` + * - HWINFO + - :kconfig:option:`CONFIG_HWINFO` + - N/A + * - Watchdog Timer (WDT) + - :kconfig:option:`CONFIG_WATCHDOG` + - :dtcompatible:`raspberrypi,pico-watchdog` + * - PWM + - :kconfig:option:`CONFIG_PWM` + - :dtcompatible:`raspberrypi,pico-pwm` + * - Flash + - :kconfig:option:`CONFIG_FLASH` + - :dtcompatible:`raspberrypi,pico-flash` + * - UART (PIO) + - :kconfig:option:`CONFIG_SERIAL` + - :dtcompatible:`raspberrypi,pico-uart-pio` + +Pin Mapping +=========== + +The peripherals of the RP2040 SoC can be routed to various pins on the board. +The configuration of these routes can be modified through DTS. Please refer to +the datasheet to see the possible routings for each peripheral. + +Default Zephyr Peripheral Mapping: +---------------------------------- + +.. rst-class:: rst-columns + +- UART1_TX : P20 +- UART1_RX : P5 +- I2C0_SDA : P24 +- I2C0_SCL : P25 +- I2C1_SDA : P22 +- I2C1_SCL : P23 +- SPI0_RX : P4 +- SPI0_SCK : P6 +- SPI0_TX : P3 + +Programming and Debugging +************************* + +Flashing +======== + +Using UF2 +--------- + +Since it doesn't expose the SWD pins, you must flash the Adafruit QT Py RP2040 with +a UF2 file. By default, building an app for this board will generate a +`build/zephyr/zephyr.uf2` file. If the QT Py RP2040 is powered on with the `BOOTSEL` +button pressed, it will appear on the host as a mass storage device. The +UF2 file should be drag-and-dropped to the device, which will flash the QT Py RP2040. + +.. target-notes:: + +.. _Getting Started with Raspberry Pi Pico: + https://datasheets.raspberrypi.com/pico/getting-started-with-pico.pdf + +.. _Primary Guide\: Adafruit QT Py RP2040: + https://learn.adafruit.com/adafruit-qt-py-2040 diff --git a/boards/arm/adafruit_qt_py_rp2040/seeed_xiao_connector.dtsi b/boards/arm/adafruit_qt_py_rp2040/seeed_xiao_connector.dtsi new file mode 100644 index 00000000000..69e21b54c12 --- /dev/null +++ b/boards/arm/adafruit_qt_py_rp2040/seeed_xiao_connector.dtsi @@ -0,0 +1,29 @@ +/* + * Copyright (c) 2023 Ian Wakely + * + * SPDX-License-Identifier: Apache-2.0 + */ + +/ { + xiao_d: connector { + compatible = "seeed,xiao-gpio"; + #gpio-cells = <2>; + gpio-map-mask = <0xffffffff 0xffffffc0>; + gpio-map-pass-thru = <0 0x3f>; + gpio-map = <0 0 &gpio0 29 0>, /* D0 */ + <1 0 &gpio0 28 0>, /* D1 */ + <2 0 &gpio0 27 0>, /* D2 */ + <3 0 &gpio0 26 0>, /* D3 */ + <4 0 &gpio0 24 0>, /* D4 */ + <5 0 &gpio0 25 0>, /* D5 */ + <6 0 &gpio0 20 0>, /* D6 */ + <7 0 &gpio0 5 0>, /* D7 */ + <8 0 &gpio0 6 0>, /* D8 */ + <9 0 &gpio0 4 0>, /* D9 */ + <10 0 &gpio0 3 0>; /* D10 */ + }; +}; + +xiao_spi: &spi0 {}; +xiao_i2c: &i2c0 {}; +xiao_serial: &uart1 {}; From 9835957df0e49f9eb1418da8109c8629017fcb7c Mon Sep 17 00:00:00 2001 From: Ian Wakely Date: Thu, 21 Dec 2023 11:07:37 -0500 Subject: [PATCH 1545/3723] board: adafruit_qt_py_rp2040: Adding test overlay. Adding a board overlay for the ADC API driver test. Signed-off-by: Ian Wakely --- .../boards/adafruit_qt_py_rp2040.overlay | 32 +++++++++++++++++++ 1 file changed, 32 insertions(+) create mode 100644 tests/drivers/adc/adc_api/boards/adafruit_qt_py_rp2040.overlay diff --git a/tests/drivers/adc/adc_api/boards/adafruit_qt_py_rp2040.overlay b/tests/drivers/adc/adc_api/boards/adafruit_qt_py_rp2040.overlay new file mode 100644 index 00000000000..2bd79f9f4f1 --- /dev/null +++ b/tests/drivers/adc/adc_api/boards/adafruit_qt_py_rp2040.overlay @@ -0,0 +1,32 @@ +/* + * Copyright (c) 2023 Benjamin Björnsson + * + * SPDX-License-Identifier: Apache-2.0 + */ + +/ { + zephyr,user { + io-channels = <&adc 0>, <&adc 1>; + }; +}; + +&adc { + #address-cells = <1>; + #size-cells = <0>; + + channel@0 { + reg = <0>; + zephyr,gain = "ADC_GAIN_1"; + zephyr,reference = "ADC_REF_INTERNAL"; + zephyr,acquisition-time = ; + zephyr,resolution = <12>; + }; + + channel@1 { + reg = <1>; + zephyr,gain = "ADC_GAIN_1"; + zephyr,reference = "ADC_REF_INTERNAL"; + zephyr,acquisition-time = ; + zephyr,resolution = <12>; + }; +}; From 1a0b6745bdd003e9baa16da42be1dde1b7a5dead Mon Sep 17 00:00:00 2001 From: Jukka Rissanen Date: Wed, 20 Dec 2023 09:48:04 +0200 Subject: [PATCH 1546/3723] net: shell: Print more Ethernet statistics Various Ethernet error statistics values were not printed by the shell. Signed-off-by: Jukka Rissanen --- subsys/net/lib/shell/stats.c | 41 ++++++++++++++++++++++++++++++++++++ 1 file changed, 41 insertions(+) diff --git a/subsys/net/lib/shell/stats.c b/subsys/net/lib/shell/stats.c index 666a98e35d7..7e38cf48594 100644 --- a/subsys/net/lib/shell/stats.c +++ b/subsys/net/lib/shell/stats.c @@ -67,6 +67,47 @@ static void print_eth_stats(struct net_if *iface, struct net_stats_eth *data, PR("Send restarts : %u\n", data->tx_restart_queue); PR("Unknown protocol : %u\n", data->unknown_protocol); + PR("Checksum offload : RX good %u errors %u\n", + data->csum.rx_csum_offload_good, + data->csum.rx_csum_offload_errors); + PR("Flow control : RX xon %u xoff %u TX xon %u xoff %u\n", + data->flow_control.rx_flow_control_xon, + data->flow_control.rx_flow_control_xoff, + data->flow_control.tx_flow_control_xon, + data->flow_control.tx_flow_control_xoff); + PR("ECC errors : uncorrected %u corrected %u\n", + data->error_details.uncorr_ecc_errors, + data->error_details.corr_ecc_errors); + PR("HW timestamp : RX cleared %u TX timeout %u skipped %u\n", + data->hw_timestamp.rx_hwtstamp_cleared, + data->hw_timestamp.tx_hwtstamp_timeouts, + data->hw_timestamp.tx_hwtstamp_skipped); + + PR("RX errors : %5s %5s %5s %5s %5s %5s %5s %5s %5s %5s %5s\n", + "Len", "Over", "CRC", "Frame", "NoBuf", "Miss", "Long", "Short", + "Align", "DMA", "Alloc"); + PR(" %5u %5u %5u %5u %5u %5u %5u %5u %5u %5u %5u\n", + data->error_details.rx_length_errors, + data->error_details.rx_over_errors, + data->error_details.rx_crc_errors, + data->error_details.rx_frame_errors, + data->error_details.rx_no_buffer_count, + data->error_details.rx_missed_errors, + data->error_details.rx_long_length_errors, + data->error_details.rx_short_length_errors, + data->error_details.rx_align_errors, + data->error_details.rx_dma_failed, + data->error_details.rx_buf_alloc_failed); + PR("TX errors : %5s %8s %5s %10s %7s %5s\n", + "Abort", "Carrier", "Fifo", "Heartbeat", "Window", "DMA"); + PR(" %5u %8u %5u %10u %7u %5u\n", + data->error_details.tx_aborted_errors, + data->error_details.tx_carrier_errors, + data->error_details.tx_fifo_errors, + data->error_details.tx_heartbeat_errors, + data->error_details.tx_window_errors, + data->error_details.tx_dma_failed); + #if defined(CONFIG_NET_STATISTICS_ETHERNET_VENDOR) if (data->vendor) { PR("Vendor specific statistics for Ethernet " From 79599a15d4c6e7b39c77f13ad579c0a603e1c3a6 Mon Sep 17 00:00:00 2001 From: Erwan Gouriou Date: Wed, 28 Sep 2022 09:22:07 +0200 Subject: [PATCH 1547/3723] soc: stm32: stmw32wba: Get stop mode compatible with BLE Supporting Stop1 mode while BLE RF is enabled requires some specific adaptation and usage of STM32WBA Cube BLE controller scm API. scm (Secure clock manager) is in charge of switching clock depending on RF status and should be informed of PM stop modes scheduling. Signed-off-by: Erwan Gouriou --- soc/arm/st_stm32/stm32wba/Kconfig.series | 1 + soc/arm/st_stm32/stm32wba/power.c | 73 ++++++++++++++++++------ 2 files changed, 58 insertions(+), 16 deletions(-) diff --git a/soc/arm/st_stm32/stm32wba/Kconfig.series b/soc/arm/st_stm32/stm32wba/Kconfig.series index 28edaf07790..5cdaaa7e672 100644 --- a/soc/arm/st_stm32/stm32wba/Kconfig.series +++ b/soc/arm/st_stm32/stm32wba/Kconfig.series @@ -15,6 +15,7 @@ config SOC_SERIES_STM32WBAX select ARMV8_M_DSP select CPU_CORTEX_M_HAS_DWT select HAS_STM32CUBE + select USE_STM32_HAL_PWR_EX select HAS_PM help Enable support for STM32WBA MCU series diff --git a/soc/arm/st_stm32/stm32wba/power.c b/soc/arm/st_stm32/stm32wba/power.c index 018c27ee0b8..89d9f5e72ed 100644 --- a/soc/arm/st_stm32/stm32wba/power.c +++ b/soc/arm/st_stm32/stm32wba/power.c @@ -8,19 +8,45 @@ #include #include -#include #include #include #include +#include #include #include #include +#ifdef CONFIG_BT_STM32WBA +#include "scm.h" +#endif + #include + LOG_MODULE_DECLARE(soc, CONFIG_SOC_LOG_LEVEL); void set_mode_stop(uint8_t substate_id) { + + LL_PWR_ClearFlag_STOP(); + LL_RCC_ClearResetFlags(); + + /* Erratum 2.2.15: + * Disabling ICACHE is required before entering stop mode + */ + LL_ICACHE_Disable(); + while (LL_ICACHE_IsEnabled() == 1U) { + } + + +#ifdef CONFIG_BT_STM32WBA + scm_setwaitstates(LP); +#endif + /* Set SLEEPDEEP bit of Cortex System Control Register */ + LL_LPM_EnableDeepSleep(); + + while (LL_PWR_IsActiveFlag_ACTVOS() == 0) { + } + switch (substate_id) { case 1: /* enter STOP0 mode */ LL_PWR_SetPowerMode(LL_PWR_MODE_STOP0); @@ -34,13 +60,6 @@ void set_mode_stop(uint8_t substate_id) } } -void set_mode_standby(uint8_t substate_id) -{ - ARG_UNUSED(substate_id); - /* Select standby mode */ - LL_PWR_SetPowerMode(LL_PWR_MODE_STANDBY); -} - /* Invoke Low Power/System Off specific Tasks */ void pm_state_set(enum pm_state state, uint8_t substate_id) { @@ -49,17 +68,13 @@ void pm_state_set(enum pm_state state, uint8_t substate_id) set_mode_stop(substate_id); break; case PM_STATE_STANDBY: - /* To be tested */ - set_mode_standby(substate_id); - break; + /* Not supported today */ + __fallthrough; default: LOG_DBG("Unsupported power state %u", state); return; } - /* Set SLEEPDEEP bit of Cortex System Control Register */ - LL_LPM_EnableDeepSleep(); - /* Select mode entry : WFE or WFI and enter the CPU selected mode */ k_cpu_idle(); } @@ -67,6 +82,21 @@ void pm_state_set(enum pm_state state, uint8_t substate_id) /* Handle SOC specific activity after Low Power Mode Exit */ void pm_state_exit_post_ops(enum pm_state state, uint8_t substate_id) { + /* Erratum 2.2.15: + * Enable ICACHE when exiting stop mode + */ + LL_ICACHE_Enable(); + while (LL_ICACHE_IsEnabled() == 0U) { + } + +#ifdef CONFIG_BT_STM32WBA + if (LL_PWR_IsActiveFlag_STOP() == 1U) { + scm_setup(); + } else { + scm_setwaitstates(RUN); + } +#endif + switch (state) { case PM_STATE_SUSPEND_TO_IDLE: if (substate_id <= 2) { @@ -87,8 +117,11 @@ void pm_state_exit_post_ops(enum pm_state state, uint8_t substate_id) LOG_DBG("Unsupported power state %u", state); break; } - /* need to restore the clock */ + + /* When BLE is enabled, clock restoration is performed by SCM */ +#if !defined(CONFIG_BT_STM32WBA) stm32_clock_control_init(NULL); +#endif /* * System is now in active mode. @@ -101,9 +134,17 @@ void pm_state_exit_post_ops(enum pm_state state, uint8_t substate_id) /* Initialize STM32 Power */ static int stm32_power_init(void) { - /* enable Power clock */ + +#ifdef CONFIG_BT_STM32WBA + scm_init(); +#endif + LL_AHB4_GRP1_EnableClock(LL_AHB4_GRP1_PERIPH_PWR); + LL_PWR_EnableUltraLowPowerMode(); + + LL_FLASH_EnableSleepPowerDown(); + return 0; } From 3f61150d0ab9f876da9745fd9d2efa5532f22aee Mon Sep 17 00:00:00 2001 From: Erwan Gouriou Date: Wed, 20 Dec 2023 09:33:49 +0100 Subject: [PATCH 1548/3723] drivers: clock_control: stm32wba: set regu voltage after clk configuration Call to set_regu_voltage() is required also after the clock configuration has been performed. Signed-off-by: Erwan Gouriou --- drivers/clock_control/clock_stm32_ll_wba.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/drivers/clock_control/clock_stm32_ll_wba.c b/drivers/clock_control/clock_stm32_ll_wba.c index 8b9da70017a..111cebff6b2 100644 --- a/drivers/clock_control/clock_stm32_ll_wba.c +++ b/drivers/clock_control/clock_stm32_ll_wba.c @@ -551,6 +551,9 @@ int stm32_clock_control_init(const struct device *dev) LL_SetFlashLatency(CONFIG_SYS_CLOCK_HW_CYCLES_PER_SEC); } + /* Set voltage regulator to comply with targeted system frequency */ + set_regu_voltage(CONFIG_SYS_CLOCK_HW_CYCLES_PER_SEC); + SystemCoreClock = CONFIG_SYS_CLOCK_HW_CYCLES_PER_SEC; /* Set bus prescalers prescaler */ From 0a3b601ace3c7934dea70a6feb742c74ca560dd3 Mon Sep 17 00:00:00 2001 From: Erwan Gouriou Date: Wed, 20 Dec 2023 09:35:03 +0100 Subject: [PATCH 1549/3723] boards: nucleo_wba55cg: Provide sleep configuration to usart1 Useful to achieve minimum consumption in stop mode. Signed-off-by: Erwan Gouriou --- boards/arm/nucleo_wba55cg/nucleo_wba55cg.dts | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/boards/arm/nucleo_wba55cg/nucleo_wba55cg.dts b/boards/arm/nucleo_wba55cg/nucleo_wba55cg.dts index 163a1bb5ae2..3a2ad07c1b0 100644 --- a/boards/arm/nucleo_wba55cg/nucleo_wba55cg.dts +++ b/boards/arm/nucleo_wba55cg/nucleo_wba55cg.dts @@ -90,7 +90,8 @@ clocks = <&rcc STM32_CLOCK_BUS_APB2 0x00004000>, <&rcc STM32_SRC_HSI16 USART1_SEL(2)>; pinctrl-0 = <&usart1_tx_pb12 &usart1_rx_pa8>; - pinctrl-names = "default"; + pinctrl-1 = <&analog_pb12 &analog_pa8>; + pinctrl-names = "default", "sleep"; current-speed = <115200>; status = "okay"; }; From 800edb2b69ef132791330246fa70d3ff189ac4a5 Mon Sep 17 00:00:00 2001 From: Francois Ramu Date: Wed, 20 Dec 2023 13:35:15 +0100 Subject: [PATCH 1550/3723] dts: arm: stm32f7 declares sram0 as zephyr, memory-region Declare the SRAM0 region as memory-region for the stm32f745 serie. Will be included for the stm32f746 for the stm32f765 serie. Will be included for the stm32f767 for the stm32f722 serie. Will be included for the stm32f723 Signed-off-by: Francois Ramu --- dts/arm/st/f7/stm32f722.dtsi | 3 ++- dts/arm/st/f7/stm32f745.dtsi | 3 ++- dts/arm/st/f7/stm32f765.dtsi | 3 ++- 3 files changed, 6 insertions(+), 3 deletions(-) diff --git a/dts/arm/st/f7/stm32f722.dtsi b/dts/arm/st/f7/stm32f722.dtsi index 172f1d8e32b..0784e99265b 100644 --- a/dts/arm/st/f7/stm32f722.dtsi +++ b/dts/arm/st/f7/stm32f722.dtsi @@ -12,8 +12,9 @@ */ sram0: memory@20010000 { - compatible = "mmio-sram"; + compatible = "zephyr,memory-region", "mmio-sram"; reg = <0x20010000 DT_SIZE_K(192)>; + zephyr,memory-region = "SRAM0"; }; dtcm: memory@20000000 { diff --git a/dts/arm/st/f7/stm32f745.dtsi b/dts/arm/st/f7/stm32f745.dtsi index b4e7b55a948..551e3af6f3f 100644 --- a/dts/arm/st/f7/stm32f745.dtsi +++ b/dts/arm/st/f7/stm32f745.dtsi @@ -10,8 +10,9 @@ /* 64KB DTCM @ 20000000, 240KB SRAM1 @ 20010000, 16KB SRAM2 @ 2004C000 */ sram0: memory@20010000 { - compatible = "mmio-sram"; + compatible = "zephyr,memory-region", "mmio-sram"; reg = <0x20010000 DT_SIZE_K(256)>; + zephyr,memory-region = "SRAM0"; }; dtcm: memory@20000000 { diff --git a/dts/arm/st/f7/stm32f765.dtsi b/dts/arm/st/f7/stm32f765.dtsi index 642a7a75521..b53203be760 100644 --- a/dts/arm/st/f7/stm32f765.dtsi +++ b/dts/arm/st/f7/stm32f765.dtsi @@ -12,8 +12,9 @@ */ sram0: memory@20020000 { - compatible = "mmio-sram"; + compatible = "zephyr,memory-region", "mmio-sram"; reg = <0x20020000 DT_SIZE_K(384)>; + zephyr,memory-region = "SRAM0"; }; dtcm: memory@20000000 { From 82bace6e0d331f3bbb1b21b8e1b584b1260dd7fd Mon Sep 17 00:00:00 2001 From: Francois Ramu Date: Wed, 20 Dec 2023 10:49:20 +0100 Subject: [PATCH 1551/3723] tests: drivers: dma test on stm32f7 requires nocache memory Config the sram0 to be non-cachable to PASS the DMA testcases chan_blen_transfer and loop_transfer on the stm32f746zg and stm32f767zi nucleo boards. The CONFIG_NOCACHE_MEMORY is useless as the memory region gets the NOCACHE ATTRibutes for stm32H7 or stm32F7 as well. Signed-off-by: Francois Ramu --- .../drivers/dma/chan_blen_transfer/boards/nucleo_f746zg.conf | 1 - .../dma/chan_blen_transfer/boards/nucleo_f746zg.overlay | 5 +++++ .../drivers/dma/chan_blen_transfer/boards/nucleo_f767zi.conf | 2 ++ .../dma/chan_blen_transfer/boards/nucleo_f767zi.overlay | 5 +++++ .../drivers/dma/chan_blen_transfer/boards/nucleo_h743zi.conf | 3 --- tests/drivers/dma/loop_transfer/boards/nucleo_f746zg.conf | 1 - tests/drivers/dma/loop_transfer/boards/nucleo_f746zg.overlay | 5 +++++ tests/drivers/dma/loop_transfer/boards/nucleo_f767zi.conf | 1 - tests/drivers/dma/loop_transfer/boards/nucleo_f767zi.overlay | 5 +++++ tests/drivers/dma/loop_transfer/boards/nucleo_h743zi.conf | 3 --- 10 files changed, 22 insertions(+), 9 deletions(-) create mode 100644 tests/drivers/dma/chan_blen_transfer/boards/nucleo_f767zi.conf diff --git a/tests/drivers/dma/chan_blen_transfer/boards/nucleo_f746zg.conf b/tests/drivers/dma/chan_blen_transfer/boards/nucleo_f746zg.conf index dfcf761a148..ded0d42ac56 100644 --- a/tests/drivers/dma/chan_blen_transfer/boards/nucleo_f746zg.conf +++ b/tests/drivers/dma/chan_blen_transfer/boards/nucleo_f746zg.conf @@ -1,3 +1,2 @@ CONFIG_DMA_TRANSFER_CHANNEL_NR_0=0 CONFIG_DMA_TRANSFER_CHANNEL_NR_1=1 -CONFIG_NOCACHE_MEMORY=y diff --git a/tests/drivers/dma/chan_blen_transfer/boards/nucleo_f746zg.overlay b/tests/drivers/dma/chan_blen_transfer/boards/nucleo_f746zg.overlay index b0436e37a7e..185e392a70d 100644 --- a/tests/drivers/dma/chan_blen_transfer/boards/nucleo_f746zg.overlay +++ b/tests/drivers/dma/chan_blen_transfer/boards/nucleo_f746zg.overlay @@ -5,3 +5,8 @@ */ test_dma0: &dma2 { }; + +/* The test driver expects the SRAM0 region to be non-cachable */ +&sram0 { + zephyr,memory-attr = <( DT_MEM_ARM(ATTR_MPU_RAM_NOCACHE) )>; +}; diff --git a/tests/drivers/dma/chan_blen_transfer/boards/nucleo_f767zi.conf b/tests/drivers/dma/chan_blen_transfer/boards/nucleo_f767zi.conf new file mode 100644 index 00000000000..ded0d42ac56 --- /dev/null +++ b/tests/drivers/dma/chan_blen_transfer/boards/nucleo_f767zi.conf @@ -0,0 +1,2 @@ +CONFIG_DMA_TRANSFER_CHANNEL_NR_0=0 +CONFIG_DMA_TRANSFER_CHANNEL_NR_1=1 diff --git a/tests/drivers/dma/chan_blen_transfer/boards/nucleo_f767zi.overlay b/tests/drivers/dma/chan_blen_transfer/boards/nucleo_f767zi.overlay index 34515723219..b7a5c05779c 100644 --- a/tests/drivers/dma/chan_blen_transfer/boards/nucleo_f767zi.overlay +++ b/tests/drivers/dma/chan_blen_transfer/boards/nucleo_f767zi.overlay @@ -11,3 +11,8 @@ test_dma0: &dma2 { status = "okay"; }; + +/* The test driver expects the SRAM0 region to be non-cachable */ +&sram0 { + zephyr,memory-attr = <( DT_MEM_ARM(ATTR_MPU_RAM_NOCACHE) )>; +}; diff --git a/tests/drivers/dma/chan_blen_transfer/boards/nucleo_h743zi.conf b/tests/drivers/dma/chan_blen_transfer/boards/nucleo_h743zi.conf index 05e4ba8623e..f746e071d59 100644 --- a/tests/drivers/dma/chan_blen_transfer/boards/nucleo_h743zi.conf +++ b/tests/drivers/dma/chan_blen_transfer/boards/nucleo_h743zi.conf @@ -7,6 +7,3 @@ CONFIG_DMA_LOOP_TRANSFER_NUMBER_OF_DMAS=2 # has access to this section. CONFIG_CODE_DATA_RELOCATION=y CONFIG_DMA_LOOP_TRANSFER_RELOCATE_SECTION="SRAM4" - -# Required for SRAM4 to be non-cachable -CONFIG_NOCACHE_MEMORY=y diff --git a/tests/drivers/dma/loop_transfer/boards/nucleo_f746zg.conf b/tests/drivers/dma/loop_transfer/boards/nucleo_f746zg.conf index b6d33586de1..1caaeefe359 100644 --- a/tests/drivers/dma/loop_transfer/boards/nucleo_f746zg.conf +++ b/tests/drivers/dma/loop_transfer/boards/nucleo_f746zg.conf @@ -1,2 +1 @@ -CONFIG_NOCACHE_MEMORY=y CONFIG_DMA_LOOP_TRANSFER_CHANNEL_NR=0 diff --git a/tests/drivers/dma/loop_transfer/boards/nucleo_f746zg.overlay b/tests/drivers/dma/loop_transfer/boards/nucleo_f746zg.overlay index b0436e37a7e..185e392a70d 100644 --- a/tests/drivers/dma/loop_transfer/boards/nucleo_f746zg.overlay +++ b/tests/drivers/dma/loop_transfer/boards/nucleo_f746zg.overlay @@ -5,3 +5,8 @@ */ test_dma0: &dma2 { }; + +/* The test driver expects the SRAM0 region to be non-cachable */ +&sram0 { + zephyr,memory-attr = <( DT_MEM_ARM(ATTR_MPU_RAM_NOCACHE) )>; +}; diff --git a/tests/drivers/dma/loop_transfer/boards/nucleo_f767zi.conf b/tests/drivers/dma/loop_transfer/boards/nucleo_f767zi.conf index b6d33586de1..1caaeefe359 100644 --- a/tests/drivers/dma/loop_transfer/boards/nucleo_f767zi.conf +++ b/tests/drivers/dma/loop_transfer/boards/nucleo_f767zi.conf @@ -1,2 +1 @@ -CONFIG_NOCACHE_MEMORY=y CONFIG_DMA_LOOP_TRANSFER_CHANNEL_NR=0 diff --git a/tests/drivers/dma/loop_transfer/boards/nucleo_f767zi.overlay b/tests/drivers/dma/loop_transfer/boards/nucleo_f767zi.overlay index 34515723219..b7a5c05779c 100644 --- a/tests/drivers/dma/loop_transfer/boards/nucleo_f767zi.overlay +++ b/tests/drivers/dma/loop_transfer/boards/nucleo_f767zi.overlay @@ -11,3 +11,8 @@ test_dma0: &dma2 { status = "okay"; }; + +/* The test driver expects the SRAM0 region to be non-cachable */ +&sram0 { + zephyr,memory-attr = <( DT_MEM_ARM(ATTR_MPU_RAM_NOCACHE) )>; +}; diff --git a/tests/drivers/dma/loop_transfer/boards/nucleo_h743zi.conf b/tests/drivers/dma/loop_transfer/boards/nucleo_h743zi.conf index a179977c116..7257bece8b2 100644 --- a/tests/drivers/dma/loop_transfer/boards/nucleo_h743zi.conf +++ b/tests/drivers/dma/loop_transfer/boards/nucleo_h743zi.conf @@ -6,6 +6,3 @@ CONFIG_DMA_LOOP_TRANSFER_NUMBER_OF_DMAS=2 # has access to this section. CONFIG_CODE_DATA_RELOCATION=y CONFIG_DMA_LOOP_TRANSFER_RELOCATE_SECTION="SRAM4" - -# Required for SRAM4 to be non-cachable -CONFIG_NOCACHE_MEMORY=y From f68fbd69840fa6c796b8318c3b183f48379e5081 Mon Sep 17 00:00:00 2001 From: Sylvio Alves Date: Fri, 15 Dec 2023 14:17:22 -0300 Subject: [PATCH 1552/3723] driver: ble: esp32: implement deinit function Current ESP32 BLE interface does not allow disabling BLE. This PR adds proper deinit call. Signed-off-by: Sylvio Alves --- drivers/bluetooth/hci/hci_esp32.c | 35 ++++++++++++++++++++++++++++++- west.yml | 2 +- 2 files changed, 35 insertions(+), 2 deletions(-) diff --git a/drivers/bluetooth/hci/hci_esp32.c b/drivers/bluetooth/hci/hci_esp32.c index 8dae220dd94..121157d41bb 100644 --- a/drivers/bluetooth/hci/hci_esp32.c +++ b/drivers/bluetooth/hci/hci_esp32.c @@ -303,6 +303,25 @@ static int bt_esp32_ble_init(void) return 0; } +static int bt_esp32_ble_deinit(void) +{ + int ret; + + ret = esp_bt_controller_disable(); + if (ret) { + LOG_ERR("Bluetooth controller disable failed %d", ret); + return ret; + } + + ret = esp_bt_controller_deinit(); + if (ret) { + LOG_ERR("Bluetooth controller deinit failed %d", ret); + return ret; + } + + return 0; +} + static int bt_esp32_open(void) { int err; @@ -317,10 +336,25 @@ static int bt_esp32_open(void) return 0; } +static int bt_esp32_close(void) +{ + int err; + + err = bt_esp32_ble_deinit(); + if (err) { + return err; + } + + LOG_DBG("ESP32 BT stopped"); + + return 0; +} + static const struct bt_hci_driver drv = { .name = "BT ESP32", .open = bt_esp32_open, .send = bt_esp32_send, + .close = bt_esp32_close, .bus = BT_HCI_DRIVER_BUS_IPM, #if defined(CONFIG_BT_DRIVER_QUIRK_NO_AUTO_DLE) .quirks = BT_QUIRK_NO_AUTO_DLE, @@ -329,7 +363,6 @@ static const struct bt_hci_driver drv = { static int bt_esp32_init(void) { - bt_hci_driver_register(&drv); return 0; diff --git a/west.yml b/west.yml index 49d94d9a9ba..fcb32b7bea9 100644 --- a/west.yml +++ b/west.yml @@ -152,7 +152,7 @@ manifest: groups: - hal - name: hal_espressif - revision: 754be4745295a45c26d42c916a8600cdcefddd4e + revision: e98ce93e916eebdc4a0c5bceef864289447e3d63 path: modules/hal/espressif west-commands: west/west-commands.yml groups: From 071cad2e762b04e7ea782a1742ab35b802bbcd78 Mon Sep 17 00:00:00 2001 From: Seppo Takalo Date: Wed, 20 Dec 2023 14:48:41 +0200 Subject: [PATCH 1553/3723] net: lwm2m: Deprecate lwm2m_get/set_u64 Deprecate lwm2m_set_u64() and lwm2m_get_u64 as only LWM2M_RES_TYPE_S64 exist. Unsigned variant is not defined. Technically these might have worked OK, but it is undefined what happens to large unsigned values when those are converted to various payload formats (like CBOR) that might decode numbers differently depending of their signedness. Signed-off-by: Seppo Takalo --- include/zephyr/net/lwm2m.h | 10 ++++++++++ subsys/net/lib/lwm2m/lwm2m_registry.c | 4 ++-- subsys/net/lib/lwm2m/lwm2m_shell.c | 10 ---------- .../net/lib/lwm2m/lwm2m_registry/src/lwm2m_registry.c | 10 ---------- 4 files changed, 12 insertions(+), 22 deletions(-) diff --git a/include/zephyr/net/lwm2m.h b/include/zephyr/net/lwm2m.h index 3fca8bffae3..c643c32f0bf 100644 --- a/include/zephyr/net/lwm2m.h +++ b/include/zephyr/net/lwm2m.h @@ -1009,11 +1009,16 @@ int lwm2m_engine_set_u64(const char *pathstr, uint64_t value); /** * @brief Set resource (instance) value (u64) * + * @deprecated Unsigned 64bit value type does not exits. + * This is internally handled as a int64_t. + * Use lwm2m_set_s64() instead. + * * @param[in] path LwM2M path as a struct * @param[in] value u64 value * * @return 0 for success or negative in case of error. */ +__deprecated int lwm2m_set_u64(const struct lwm2m_obj_path *path, uint64_t value); /** @@ -1335,11 +1340,16 @@ int lwm2m_engine_get_u64(const char *pathstr, uint64_t *value); /** * @brief Get resource (instance) value (u64) * + * @deprecated Unsigned 64bit value type does not exits. + * This is internally handled as a int64_t. + * Use lwm2m_get_s64() instead. + * @param[in] path LwM2M path as a struct * @param[out] value u64 buffer to copy data into * * @return 0 for success or negative in case of error. */ +__deprecated int lwm2m_get_u64(const struct lwm2m_obj_path *path, uint64_t *value); /** diff --git a/subsys/net/lib/lwm2m/lwm2m_registry.c b/subsys/net/lib/lwm2m/lwm2m_registry.c index 210c5525756..1701b7f7412 100644 --- a/subsys/net/lib/lwm2m/lwm2m_registry.c +++ b/subsys/net/lib/lwm2m/lwm2m_registry.c @@ -890,7 +890,7 @@ int lwm2m_engine_set_u64(const char *pathstr, uint64_t value) if (ret < 0) { return ret; } - return lwm2m_set_u64(&path, value); + return lwm2m_set_s64(&path, (int64_t) value); } int lwm2m_set_s8(const struct lwm2m_obj_path *path, int8_t value) @@ -1378,7 +1378,7 @@ int lwm2m_engine_get_u64(const char *pathstr, uint64_t *value) if (ret < 0) { return ret; } - return lwm2m_get_u64(&path, value); + return lwm2m_get_s64(&path, (int64_t *) value); } int lwm2m_get_s8(const struct lwm2m_obj_path *path, int8_t *value) diff --git a/subsys/net/lib/lwm2m/lwm2m_shell.c b/subsys/net/lib/lwm2m/lwm2m_shell.c index 5dc891178ff..13f38fefe66 100644 --- a/subsys/net/lib/lwm2m/lwm2m_shell.c +++ b/subsys/net/lib/lwm2m/lwm2m_shell.c @@ -246,14 +246,6 @@ static int cmd_read(const struct shell *sh, size_t argc, char **argv) goto out; } shell_print(sh, "%d\n", temp); - } else if (strcmp(dtype, "-u64") == 0) { - uint64_t temp = 0; - - ret = lwm2m_get_u64(&path, &temp); - if (ret != 0) { - goto out; - } - shell_print(sh, "%lld\n", temp); } else if (strcmp(dtype, "-f") == 0) { double temp = 0; @@ -349,8 +341,6 @@ static int cmd_write(const struct shell *sh, size_t argc, char **argv) ret = lwm2m_set_u16(&path, strtoul(value, &e, 10)); } else if (strcmp(dtype, "-u32") == 0) { ret = lwm2m_set_u32(&path, strtoul(value, &e, 10)); - } else if (strcmp(dtype, "-u64") == 0) { - ret = lwm2m_set_u64(&path, strtoull(value, &e, 10)); } else if (strcmp(dtype, "-b") == 0) { ret = lwm2m_set_bool(&path, strtoul(value, &e, 10)); } else if (strcmp(dtype, "-t") == 0) { diff --git a/tests/net/lib/lwm2m/lwm2m_registry/src/lwm2m_registry.c b/tests/net/lib/lwm2m/lwm2m_registry/src/lwm2m_registry.c index d4c0a7757a6..8e99f666b7f 100644 --- a/tests/net/lib/lwm2m/lwm2m_registry/src/lwm2m_registry.c +++ b/tests/net/lib/lwm2m/lwm2m_registry/src/lwm2m_registry.c @@ -203,16 +203,6 @@ ZTEST(lwm2m_registry, test_get_set) zassert_equal(strlen(buf), 0); } -ZTEST(lwm2m_registry, test_missing_u64) -{ - /* This data type is missing, so use S64 resource instead */ - uint64_t u64 = 123; - - zassert_equal(lwm2m_set_u64(&LWM2M_OBJ(32768, 0, LWM2M_RES_TYPE_S64), u64), 0); - zassert_equal(lwm2m_get_u64(&LWM2M_OBJ(32768, 0, LWM2M_RES_TYPE_S64), &u64), 0); - zassert_equal(u64, 123); -} - ZTEST(lwm2m_registry, test_temp_sensor) { int ret; From f296ea58a3d6601bf5a24cbd58728ca0df8dee27 Mon Sep 17 00:00:00 2001 From: Anas Nashif Date: Mon, 18 Dec 2023 13:28:42 -0500 Subject: [PATCH 1554/3723] tests: ieee802154: fix test identifier Fix test identifier and use correct component. Signed-off-by: Anas Nashif --- tests/drivers/build_all/ieee802154/testcase.yaml | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/tests/drivers/build_all/ieee802154/testcase.yaml b/tests/drivers/build_all/ieee802154/testcase.yaml index 399f3fac3cf..1d9ab3617f9 100644 --- a/tests/drivers/build_all/ieee802154/testcase.yaml +++ b/tests/drivers/build_all/ieee802154/testcase.yaml @@ -4,19 +4,19 @@ common: - ieee802154 build_only: true tests: - ieee802154.build.external: + drivers.ieee802154.build.external: platform_allow: - native_posix - native_sim - ieee802154.build.cc13xx_cc26xx: + drivers.ieee802154.build.cc13xx_cc26xx: platform_allow: cc1352r_sensortag - ieee802154.build.kw41z: + drivers.ieee802154.build.kw41z: platform_allow: frdm_kw41z - ieee802154.build.mcr20a: + drivers.ieee802154.build.mcr20a: platform_allow: usb_kw24d512 - ieee802154.build.nrf5: + drivers.ieee802154.build.nrf5: platform_allow: nrf52840dk_nrf52840 - ieee802154.build.telink_b91: + drivers.ieee802154.build.telink_b91: platform_allow: tlsr9518adk80d - ieee802154.build.upipe: + drivers.ieee802154.build.upipe: platform_allow: qemu_x86 From e86b44751cb4e5079fe24e0f6c1c2bece6a099d9 Mon Sep 17 00:00:00 2001 From: Anas Nashif Date: Mon, 18 Dec 2023 13:29:00 -0500 Subject: [PATCH 1555/3723] tests: usb: move bc12 tests under tests/drivers/usb Move bc12 under usb, this is not a standalone driver subsystem. Signed-off-by: Anas Nashif --- tests/drivers/{ => usb}/bc12/CMakeLists.txt | 0 tests/drivers/{ => usb}/bc12/boards/native_sim.conf | 0 tests/drivers/{ => usb}/bc12/boards/native_sim.overlay | 0 tests/drivers/{ => usb}/bc12/prj.conf | 0 tests/drivers/{ => usb}/bc12/src/charging_mode.c | 0 tests/drivers/{ => usb}/bc12/src/pd_mode.c | 0 tests/drivers/{ => usb}/bc12/testcase.yaml | 0 7 files changed, 0 insertions(+), 0 deletions(-) rename tests/drivers/{ => usb}/bc12/CMakeLists.txt (100%) rename tests/drivers/{ => usb}/bc12/boards/native_sim.conf (100%) rename tests/drivers/{ => usb}/bc12/boards/native_sim.overlay (100%) rename tests/drivers/{ => usb}/bc12/prj.conf (100%) rename tests/drivers/{ => usb}/bc12/src/charging_mode.c (100%) rename tests/drivers/{ => usb}/bc12/src/pd_mode.c (100%) rename tests/drivers/{ => usb}/bc12/testcase.yaml (100%) diff --git a/tests/drivers/bc12/CMakeLists.txt b/tests/drivers/usb/bc12/CMakeLists.txt similarity index 100% rename from tests/drivers/bc12/CMakeLists.txt rename to tests/drivers/usb/bc12/CMakeLists.txt diff --git a/tests/drivers/bc12/boards/native_sim.conf b/tests/drivers/usb/bc12/boards/native_sim.conf similarity index 100% rename from tests/drivers/bc12/boards/native_sim.conf rename to tests/drivers/usb/bc12/boards/native_sim.conf diff --git a/tests/drivers/bc12/boards/native_sim.overlay b/tests/drivers/usb/bc12/boards/native_sim.overlay similarity index 100% rename from tests/drivers/bc12/boards/native_sim.overlay rename to tests/drivers/usb/bc12/boards/native_sim.overlay diff --git a/tests/drivers/bc12/prj.conf b/tests/drivers/usb/bc12/prj.conf similarity index 100% rename from tests/drivers/bc12/prj.conf rename to tests/drivers/usb/bc12/prj.conf diff --git a/tests/drivers/bc12/src/charging_mode.c b/tests/drivers/usb/bc12/src/charging_mode.c similarity index 100% rename from tests/drivers/bc12/src/charging_mode.c rename to tests/drivers/usb/bc12/src/charging_mode.c diff --git a/tests/drivers/bc12/src/pd_mode.c b/tests/drivers/usb/bc12/src/pd_mode.c similarity index 100% rename from tests/drivers/bc12/src/pd_mode.c rename to tests/drivers/usb/bc12/src/pd_mode.c diff --git a/tests/drivers/bc12/testcase.yaml b/tests/drivers/usb/bc12/testcase.yaml similarity index 100% rename from tests/drivers/bc12/testcase.yaml rename to tests/drivers/usb/bc12/testcase.yaml From cf640fef619ae77794560efd6e4298b5764066cf Mon Sep 17 00:00:00 2001 From: Anas Nashif Date: Sat, 28 Oct 2023 12:42:51 -0400 Subject: [PATCH 1556/3723] MAINTAINERS: add 2 new keys: tags, tests Add two new keys: tags, tests. tags for aligning with what we use in tests and samples and tests to associate areas and components with tests. Signed-off-by: Anas Nashif --- scripts/get_maintainer.py | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/scripts/get_maintainer.py b/scripts/get_maintainer.py index 08ecc1b8989..8e2a09b2152 100755 --- a/scripts/get_maintainer.py +++ b/scripts/get_maintainer.py @@ -191,6 +191,8 @@ def __init__(self, filename=None): area.collaborators = area_dict.get("collaborators", []) area.inform = area_dict.get("inform", []) area.labels = area_dict.get("labels", []) + area.tests = area_dict.get("tests", []) + area.tags = area_dict.get("tags", []) area.description = area_dict.get("description") # area._match_fn(path) tests if the path matches files and/or @@ -403,12 +405,16 @@ def _print_areas(areas): \tcollaborators: {} \tinform: {} \tlabels: {} +\ttests: {} +\ttags: {} \tdescription: {}""".format(area.name, area.status, ", ".join(area.maintainers), ", ".join(area.collaborators), ", ".join(area.inform), ", ".join(area.labels), + ", ".join(area.tests), + ", ".join(area.tags), area.description or "")) @@ -479,7 +485,7 @@ def ferr(msg): ok_keys = {"status", "maintainers", "collaborators", "inform", "files", "files-exclude", "files-regex", "files-regex-exclude", - "labels", "description"} + "labels", "description", "tests", "tags"} ok_status = {"maintained", "odd fixes", "unmaintained", "obsolete"} ok_status_s = ", ".join('"' + s + '"' for s in ok_status) # For messages @@ -504,7 +510,7 @@ def ferr(msg): "for area '{}'".format(area_name)) for list_name in "maintainers", "collaborators", "inform", "files", \ - "files-regex", "labels": + "files-regex", "labels", "tags", "tests": if list_name in area_dict: lst = area_dict[list_name] if not (isinstance(lst, list) and From 8ade97c1d2146478d8d4338ab3809c791d4b94f2 Mon Sep 17 00:00:00 2001 From: Anas Nashif Date: Tue, 7 Nov 2023 13:38:52 +0000 Subject: [PATCH 1557/3723] MAINTAINERS: add related tests to areas Add a reference to related tests in each area. Signed-off-by: Anas Nashif --- MAINTAINERS.yml | 276 +++++++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 272 insertions(+), 4 deletions(-) diff --git a/MAINTAINERS.yml b/MAINTAINERS.yml index 21603d8b785..1696d41853c 100644 --- a/MAINTAINERS.yml +++ b/MAINTAINERS.yml @@ -125,6 +125,8 @@ ACPI: - tests/lib/acpi/ labels: - "area: ACPI" + tests: + - acpi ARC arch: status: maintained @@ -142,6 +144,8 @@ ARC arch: - doc/hardware/arch/arc-support-status.rst labels: - "area: ARC" + tests: + - arch.arc ARM arch: status: maintained @@ -166,6 +170,8 @@ ARM arch: - boards/arm/qemu_cortex_m0/ labels: - "area: ARM" + tests: + - arch.arm ARM64 arch: status: maintained @@ -184,6 +190,8 @@ ARM64 arch: - dts/arm64/ labels: - "area: ARM64" + tests: + - arch.arm64 ARM Platforms: status: odd fixes @@ -204,6 +212,8 @@ ARM SiP SVC: - drivers/sip_svc/ labels: - "area: ARM SiP SVC" + tests: + - sip_svc MIPS arch: status: odd fixes @@ -214,6 +224,8 @@ MIPS arch: - boards/mips/ labels: - "area: MIPS" + tests: + - arch.mips Ambiq Platforms: status: maintained @@ -257,6 +269,8 @@ Binary Descriptors: - tests/subsys/bindesc/ labels: - "area: Binary Descriptors" + tests: + - bindesc Bluetooth: status: maintained @@ -297,6 +311,8 @@ Bluetooth: - tests/bluetooth/shell/audio* labels: - "area: Bluetooth" + tests: + - bluetooth Bluetooth controller: status: maintained @@ -317,6 +333,8 @@ Bluetooth controller: labels: - "area: Bluetooth Controller" - "area: Bluetooth" + tests: + - bluetooth.controller Bluetooth Host: status: maintained @@ -362,6 +380,8 @@ Bluetooth Mesh: labels: - "area: Bluetooth Mesh" - "area: Bluetooth" + tests: + - bluetooth.mesh Bluetooth Audio: status: maintained @@ -386,6 +406,8 @@ Bluetooth Audio: labels: - "area: Bluetooth Audio" - "area: Bluetooth" + tests: + - bluetooth.audio Build system: status: maintained @@ -407,6 +429,8 @@ Build system: - tests/cmake/ labels: - "area: Build System" + tests: + - buildsystem Board/SoC configuration: status: maintained @@ -436,6 +460,8 @@ Board/SoC configuration: - samples/cpp/ labels: - "area: C++" + tests: + - cpp Cache: status: maintained @@ -448,8 +474,11 @@ Cache: - include/zephyr/cache.h - doc/hardware/cache/index.rst - drivers/cache/ + - tests/kernel/cache/ labels: - "area: Cache" + tests: + - kernel.cache C library: status: maintained @@ -465,6 +494,8 @@ C library: - tests/lib/newlib/ labels: - "area: C Library" + tests: + - libraries.libc CMSIS API layer: status: odd fixes @@ -479,6 +510,9 @@ CMSIS API layer: labels: - "area: CMSIS API Layer" - "area: Portability" + tests: + - portability.cmsis_rtos_v1 + - portability.cmsis_rtos_v2 DSP subsystem: status: maintained @@ -494,6 +528,8 @@ DSP subsystem: - doc/services/dsp/ labels: - "area: DSP" + tests: + - zdsp CMSIS-DSP integration: status: maintained @@ -508,6 +544,8 @@ CMSIS-DSP integration: - tests/lib/cmsis_dsp/ labels: - "area: CMSIS-DSP" + tests: + - libraries.cmsis_dsp CMSIS-NN integration: status: maintained @@ -521,6 +559,8 @@ CMSIS-NN integration: - tests/lib/cmsis_nn/ labels: - "area: CMSIS-NN" + tests: + - libraries.cmsis_nn Coding Guidelines: status: maintained @@ -564,6 +604,8 @@ Common Architecture Interface: - doc/hardware/porting/arch.rst labels: - "area: Architectures" + tests: + - arch Console: status: odd fixes @@ -572,6 +614,8 @@ Console: - subsys/console/ labels: - "area: Console" + tests: + - sample.console Debug: status: maintained @@ -589,6 +633,8 @@ Debug: - doc/services/debugging/ labels: - "area: Debugging" + tests: + - debug Demand Paging: status: maintained @@ -600,6 +646,9 @@ Demand Paging: - nashif files: - subsys/demand_paging/ + - tests/kernel/mem_protect/demand_paging/ + tests: + - kernel.demand_paging Device Driver Model: status: maintained @@ -617,6 +666,8 @@ Device Driver Model: - doc/kernel/drivers/ labels: - "area: Device Model" + tests: + - kernel.device DFU: status: maintained @@ -629,6 +680,8 @@ DFU: - tests/subsys/dfu/ labels: - "area: DFU" + tests: + - dfu Devicetree: status: maintained @@ -645,6 +698,8 @@ Devicetree: - include/zephyr/devicetree.h labels: - "area: Devicetree" + tests: + - libraries.devicetree Devicetree Bindings: status: maintained @@ -674,6 +729,8 @@ Disk: - include/zephyr/sd/ labels: - "area: Disk Access" + tests: + - drivers.disk Display drivers: status: odd fixes @@ -765,6 +822,8 @@ Release Notes: - include/zephyr/dt-bindings/adc/ labels: - "area: ADC" + tests: + - drivers.adc "Drivers: Audio": status: odd fixes @@ -791,6 +850,8 @@ Release Notes: - doc/hardware/peripherals/bbram.rst labels: - "area: Battery Backed RAM (bbram)" + tests: + - drivers.bbram "Drivers: Aux display": status: maintained @@ -805,6 +866,8 @@ Release Notes: - doc/hardware/peripherals/auxdisplay.rst labels: - "area: Aux display" + tests: + - sample.drivers.auxdisplay "Drivers: CAN": status: maintained @@ -842,6 +905,9 @@ Release Notes: - tests/subsys/canbus/ labels: - "area: CAN" + tests: + - drivers.can + - canbus "Drivers: Charger": status: maintained @@ -856,6 +922,8 @@ Release Notes: - doc/hardware/peripherals/charger.rst labels: - "area: Charger" + tests: + - drivers.charger "Drivers: Clock control": status: maintained @@ -871,6 +939,8 @@ Release Notes: - doc/hardware/peripherals/clock_control.rst labels: - "area: Clock control" + tests: + - drivers.clock "Drivers: Console": status: odd fixes @@ -881,6 +951,8 @@ Release Notes: - samples/subsys/console/ labels: - "area: Console" + tests: + - drivers.console "Drivers: Coredump": status: maintained @@ -894,6 +966,8 @@ Release Notes: - doc/hardware/peripherals/coredump.rst labels: - "area: Coredump" + tests: + - debug.codedump "Drivers: Counter": status: maintained @@ -908,6 +982,8 @@ Release Notes: - tests/drivers/build_all/counter/ labels: - "area: Counter" + tests: + - drivers.counter "Drivers: Crypto": status: maintained @@ -921,6 +997,8 @@ Release Notes: - tests/crypto/ labels: - "area: Crypto / RNG" + tests: + - crypto "Drivers: DAC": status: maintained @@ -935,6 +1013,8 @@ Release Notes: - tests/drivers/build_all/dac/ labels: - "area: DAC" + tests: + - drivers.dac "Drivers: DAI": status: maintained @@ -963,6 +1043,8 @@ Release Notes: - include/zephyr/dt-bindings/dma/ labels: - "area: DMA" + tests: + - drivers.dma "Drivers: EDAC": status: maintained @@ -977,6 +1059,8 @@ Release Notes: - doc/hardware/peripherals/edac/ labels: - "area: EDAC" + tests: + - edac "Drivers: EEPROM": status: maintained @@ -991,6 +1075,8 @@ Release Notes: - doc/hardware/peripherals/eeprom.rst labels: - "area: EEPROM" + tests: + - drivers.eeprom "Drivers: Entropy": status: maintained @@ -1003,6 +1089,8 @@ Release Notes: - doc/hardware/peripherals/entropy.rst labels: - "area: Crypto / RNG" + tests: + - drivers.entropy "Drivers: ESPI": status: maintained @@ -1019,8 +1107,12 @@ Release Notes: - dts/bindings/espi/ - doc/hardware/peripherals/espi.rst - include/zephyr/drivers/espi_saf.h + - tests/drivers/espi/ labels: - "area: eSPI" + tests: + - sample.drivers.espi + - drivers.espi "Drivers: Ethernet": status: odd fixes @@ -1032,6 +1124,8 @@ Release Notes: - tests/drivers/ethernet/ labels: - "area: Ethernet" + tests: + - net.ethernet "Drivers: Flash": status: maintained @@ -1047,6 +1141,8 @@ Release Notes: - doc/hardware/peripherals/flash.rst labels: - "area: Flash" + tests: + - drivers.flash "Drivers: FPGA": status: maintained @@ -1064,6 +1160,8 @@ Release Notes: - tests/drivers/build_all/fpga/ labels: - "area: FPGA" + tests: + - drivers.fpga "Drivers: Fuel Gauge": status: maintained @@ -1078,6 +1176,8 @@ Release Notes: - doc/hardware/peripherals/fuel_gauge.rst labels: - "area: Fuel Gauge" + tests: + - drivers.fuel_gauge "Drivers: GPIO": status: odd fixes @@ -1094,6 +1194,8 @@ Release Notes: - tests/drivers/build_all/gpio/ labels: - "area: GPIO" + tests: + - drivers.gpio "Drivers: GNSS": status: maintained @@ -1108,6 +1210,8 @@ Release Notes: - tests/drivers/gnss/ labels: - "area: GNSS" + tests: + - drivers.gnss "Drivers: HW Info": status: maintained @@ -1121,6 +1225,8 @@ Release Notes: - doc/hardware/peripherals/hwinfo.rst labels: - "area: HWINFO" + tests: + - drivers.hwinfo "Drivers: I2C": status: maintained @@ -1137,6 +1243,8 @@ Release Notes: - tests/boards/frdm_k64f/i2c/ labels: - "area: I2C" + tests: + - drivers.i2c "Drivers: I2S": status: maintained @@ -1151,6 +1259,8 @@ Release Notes: - samples/drivers/i2s/ labels: - "area: I2S" + tests: + - drivers.i2s "Drivers: I3C": status: maintained @@ -1167,6 +1277,8 @@ Release Notes: - tests/drivers/build_all/i3c/ labels: - "area: I3C" + tests: + - drivers.i3c "Drivers: IEEE 802.15.4": status: maintained @@ -1208,6 +1320,8 @@ Release Notes: Inter-processor mailboxes labels: - "area: IPM" + tests: + - drivers.ipm "Drivers: kscan": status: maintained @@ -1218,14 +1332,14 @@ Release Notes: files: - drivers/kscan/ - include/zephyr/drivers/kscan.h - - samples/drivers/espi/ - samples/drivers/kscan/ - tests/drivers/kscan/ - - tests/drivers/espi/ - dts/bindings/kscan/ - doc/hardware/peripherals/kscan.rst labels: - "area: Kscan" + tests: + - drivers.kscan "Drivers: LED": status: maintained @@ -1243,6 +1357,8 @@ Release Notes: - doc/hardware/peripherals/led.rst labels: - "area: LED" + tests: + - drivers.led "Drivers: LED Strip": status: maintained @@ -1256,6 +1372,8 @@ Release Notes: - tests/drivers/build_all/led_strip/ labels: - "area: LED" + tests: + - drivers.led_strip "Drivers: MFD": status: odd fixes @@ -1269,6 +1387,8 @@ Release Notes: - tests/drivers/build_all/mfd/ labels: - "area: MFD" + tests: + - drivers.mfd "Drivers: Modem": status: maintained @@ -1281,6 +1401,8 @@ Release Notes: - include/zephyr/drivers/modem/ labels: - "area: Modem Drivers" + tests: + - drivers.modem "Drivers: Regulators": status: maintained @@ -1299,6 +1421,8 @@ Release Notes: - doc/hardware/peripherals/regulators.rst labels: - "area: Regulators" + tests: + - drivers.regulator "Drivers: Retained Memory": status: maintained @@ -1312,6 +1436,8 @@ Release Notes: - doc/hardware/peripherals/retained_mem.rst labels: - "area: Retained Memory" + tests: + - drivers.retained_mem "Drivers: RTC": status: maintained @@ -1325,6 +1451,8 @@ Release Notes: - include/zephyr/drivers/rtc.h labels: - "area: RTC" + tests: + - drivers.rtc "Drivers: PCI": status: maintained @@ -1354,6 +1482,8 @@ Release Notes: - doc/hardware/peripherals/peci.rst labels: - "area: PECI" + tests: + - samples.drivers.peci "Drivers: Pin Control": status: maintained @@ -1369,6 +1499,8 @@ Release Notes: - include/zephyr/dt-bindings/pinctrl/ labels: - "area: Pinctrl" + tests: + - drivers.pinctrl "Drivers: PTP Clock": status: maintained @@ -1411,6 +1543,8 @@ Release Notes: - include/zephyr/drivers/pwm.h labels: - "area: PWM" + tests: + - drivers.pwm "Drivers: SDHC": status: maintained @@ -1424,6 +1558,8 @@ Release Notes: - doc/hardware/peripherals/sdhc.rst labels: - "area: Disk Access" + tests: + - drivers.sdhc "Drivers: Serial/UART": status: maintained @@ -1440,6 +1576,8 @@ Release Notes: - doc/hardware/peripherals/uart.rst labels: - "area: UART" + tests: + - drivers.uart "Drivers: Sensors": status: maintained @@ -1463,6 +1601,8 @@ Release Notes: - tests/drivers/build_all/sensor/ labels: - "area: Sensors" + tests: + - drivers.sensors "Drivers: SMBus": status: maintained @@ -1477,6 +1617,8 @@ Release Notes: - doc/hardware/peripherals/smbus.rst labels: - "area: SMBus" + tests: + - drivers.smbus "Drivers: SPI": status: maintained @@ -1491,6 +1633,8 @@ Release Notes: - doc/hardware/peripherals/spi.rst labels: - "area: SPI" + tests: + - drivers.spi "Drivers: System timer": status: maintained @@ -1532,6 +1676,8 @@ Release Notes: - samples/drivers/w1/ labels: - "area: W1" + tests: + - drivers.w1 "Drivers: Watchdog": status: odd fixes @@ -1547,6 +1693,8 @@ Release Notes: - tests/drivers/watchdog/ labels: - "area: Watchdog" + tests: + - drivers.watchdog "Drivers: Wi-Fi": status: maintained @@ -1602,6 +1750,8 @@ Release Notes: - include/zephyr/drivers/virtualization/ivshmem.h labels: - "area: Virtualization" + tests: + - drivers.virtualization EC Host Commands: status: maintained @@ -1613,6 +1763,8 @@ EC Host Commands: - tests/subsys/mgmt/ec_host_cmd/ labels: - "area: ec_host_cmd" + tests: + - mgmt.ec_host_cmd Xen Platform: status: maintained @@ -1646,6 +1798,8 @@ Filesystems: - tests/subsys/fs/ labels: - "area: File System" + tests: + - filesystem "Filesystems: FatFs reentrant support": status: maintained @@ -1656,6 +1810,8 @@ Filesystems: - tests/subsys/fs/fat_fs_api/src/test_fat_file_reentrant.c labels: - "area: File System" + tests: + - filesystem.fat Formatted Output: status: maintained @@ -1672,6 +1828,9 @@ Formatted Output: - doc/services/formatted_output.rst labels: - "area: Formatting Output" + tests: + - utilities.prf + - libraries.cbprintf Google Platforms: status: maintained @@ -1695,6 +1854,9 @@ Hash Utilities: Hash Functions and Hash Maps (Hash Tables) labels: - "area: hash utils" + tests: + - libraries.hash_function + - libraries.hash_map Input: status: maintained @@ -1717,6 +1879,9 @@ Input: Input subsystem and drivers labels: - "area: Input" + tests: + - drivers.input + - input IPC: status: maintained @@ -1732,6 +1897,8 @@ IPC: Inter-Processor Communication labels: - "area: IPC" + tests: + - ipc JSON Web Token: status: maintained @@ -1748,6 +1915,9 @@ JSON Web Token: - tests/lib/json/ labels: - "area: JSON" + tests: + - libraries.encoding.json + - libraries.encoding.jwt Kconfig: status: odd fixes @@ -1765,6 +1935,8 @@ Kconfig: description: >- See https://docs.zephyrproject.org/latest/build/kconfig/index.html and https://docs.zephyrproject.org/latest/hardware/porting/board_porting.html#default-board-configuration + tests: + - kconfig Kernel: status: maintained @@ -1790,6 +1962,8 @@ Kernel: - tests/kernel/mem_protect/ labels: - "area: Kernel" + tests: + - kernel Base OS: status: maintained @@ -1841,6 +2015,8 @@ Little FS: Little FS labels: - "area: File System" + tests: + - filesystem.littlefs Logging: status: maintained @@ -1863,6 +2039,8 @@ Logging: - tests/lib/spsc_pbuf/ labels: - "area: Logging" + tests: + - logging LoRa and LoRaWAN: status: maintained @@ -1882,6 +2060,8 @@ LoRa and LoRaWAN: - doc/connectivity/lora_lorawan/index.rst labels: - "area: LoRa" + tests: + - sample.driver.lora MAINTAINERS file: status: maintained @@ -1910,6 +2090,9 @@ Mbed TLS: - "area: Crypto / RNG" description: >- Mbed TLS module implementing the PSA Crypto API and TLS. + tests: + - benchmark.crypto.mbedtls + - crypto.mbedtls MCU Manager: status: maintained @@ -1925,6 +2108,8 @@ MCU Manager: - doc/services/device_mgmt/ labels: - "area: mcumgr" + tests: + - mgmt.mcumgr Modbus: status: maintained @@ -1938,8 +2123,10 @@ Modbus: - doc/services/modbus/ labels: - "area: modbus" + tests: + - modbus -Modem Modules: +Modem: status: maintained maintainers: - bjarki-trackunit @@ -1951,6 +2138,8 @@ Modem Modules: - samples/net/cellular_modem/ labels: - "area: Modem" + tests: + - modem OSDP: status: maintained @@ -1965,6 +2154,8 @@ OSDP: - samples/subsys/mgmt/osdp/ labels: - "area: OSDP" + tests: + - sample.mgmt.osdp hawkBit: status: odd fixes @@ -1976,6 +2167,8 @@ hawkBit: - samples/subsys/mgmt/hawkbit/ labels: - "area: hawkBit" + tests: + - sample.net.hawkbit "mgmt: updatehub": status: maintained @@ -1988,6 +2181,8 @@ hawkBit: - "area: updatehub" description: >- UpdateHub embedded Firmware Over-The-Air (FOTA) upgrade agent + tests: + - sample.net.updatehub Native POSIX/Sim and POSIX arch: status: maintained @@ -2013,6 +2208,8 @@ Native POSIX/Sim and POSIX arch: - "area: native port" description: >- POSIX architecture and SOC, native_posix & native_sim boards, and related drivers + tests: + - boards.native_posix Networking: status: maintained @@ -2053,6 +2250,8 @@ Networking: - tests/net/wifi/ labels: - "area: Networking" + tests: + - net "Networking: BSD sockets": status: odd fixes @@ -2065,6 +2264,8 @@ Networking: - tests/net/socket/ labels: - "area: Sockets" + tests: + - net.socket "Networking: Buffers": status: maintained @@ -2080,6 +2281,8 @@ Networking: - tests/net/buf/ labels: - "area: Networking Buffers" + tests: + - net.buf "Networking: Connection Manager": status: maintained @@ -2096,6 +2299,8 @@ Networking: - doc/connectivity/networking/conn_mgr/ labels: - "area: Networking" + tests: + - net.conn_mgr "Networking: CoAP": status: maintained @@ -2109,6 +2314,8 @@ Networking: - tests/net/lib/coap/ labels: - "area: Networking" + tests: + - net.coap "Networking: gPTP": status: maintained @@ -2123,6 +2330,8 @@ Networking: - subsys/net/l2/ethernet/gptp/ labels: - "area: Networking" + tests: + - sample.net.gptp "Networking: LWM2M": status: maintained @@ -2136,6 +2345,8 @@ Networking: - subsys/net/lib/lwm2m/ labels: - "area: LWM2M" + tests: + - net.lwm2m "Networking: MQTT": status: maintained @@ -2150,6 +2361,8 @@ Networking: - tests/net/lib/mqtt_sn*/ labels: - "area: Networking" + tests: + - net.mqtt "Networking: MQTT-SN": status: maintained @@ -2163,6 +2376,8 @@ Networking: - samples/net/mqtt_sn_publisher/ labels: - "area: Networking" + tests: + - net.mqtt_sn "Networking: Native IEEE 802.15.4": status: maintained @@ -2179,6 +2394,8 @@ Networking: - tests/net/ieee802154/ labels: - "area: IEEE 802.15.4" + tests: + - net.ieee802154 "Networking: OpenThread": status: maintained @@ -2197,6 +2414,8 @@ Networking: labels: - "area: Networking" - "area: OpenThread" + tests: + - openthread "Networking: Wi-Fi": status: maintained @@ -2214,6 +2433,8 @@ Networking: labels: - "area: Networking" - "area: Wi-Fi" + tests: + - net.wifi NIOS-2 arch: status: maintained @@ -2229,6 +2450,8 @@ NIOS-2 arch: - boards/nios2/qemu_nios2/ labels: - "area: NIOS2" + tests: + - boards.altera_max10 nRF BSIM: status: maintained @@ -2242,6 +2465,8 @@ nRF BSIM: - tests/bsim/*/ labels: - "platform: nRF BSIM" + tests: + - boards.nrf52_bsim POSIX API layer: status: maintained @@ -2256,6 +2481,9 @@ POSIX API layer: - doc/services/portability/posix/ labels: - "area: POSIX" + tests: + - libraries.fdtable + - portability.posix Power management: status: maintained @@ -2275,6 +2503,8 @@ Power management: - drivers/power_domain/ labels: - "area: Power Management" + tests: + - pm RISCV arch: status: maintained @@ -2300,6 +2530,8 @@ RISCV arch: - drivers/interrupt_controller/intc_plic.c labels: - "area: RISCV" + tests: + - arch.riscv Retention: status: maintained @@ -2341,6 +2573,8 @@ Sensor Subsystem: - samples/subsys/sensing/ labels: - "area: Sensor Subsystem" + tests: + - sample.sensing Stats: status: odd fixes @@ -2384,6 +2618,8 @@ Settings: - doc/services/settings/ labels: - "area: Settings" + tests: + - settings Shell: status: maintained @@ -2399,6 +2635,8 @@ Shell: - doc/services/shell/ labels: - "area: Shell" + tests: + - shell Shields: status: maintained @@ -2414,6 +2652,8 @@ Shields: - samples/shields/ labels: - "area: Shields" + tests: + - sample.shields SPARC arch: status: odd fixes @@ -2441,6 +2681,8 @@ State machine framework: - tests/lib/smf/ labels: - "area: State Machine Framework" + tests: + - libraries.smf ADI Platforms: status: maintained @@ -2647,7 +2889,6 @@ Intel Platforms (Agilex): - boards/arm64/intel_*/ - soc/arm64/intel_*/ - dts/arm64/intel/ - - samples/boards/intel_adsp/ - dts/bindings/*/intel,agilex* labels: - "platform: Intel SoC FPGA Agilex" @@ -2951,6 +3192,8 @@ RTIO: - doc/services/rtio/ labels: - "area: RTIO" + tests: + - rtio Storage: status: odd fixes @@ -2961,6 +3204,8 @@ Storage: - doc/services/storage/ labels: - "area: Storage" + tests: + - storage Sysbuild: status: maintained @@ -2975,6 +3220,8 @@ Sysbuild: - doc/build/sysbuild/ labels: - "area: Sysbuild" + tests: + - sample.application_development.sysbuild Task Watchdog: status: maintained @@ -2987,6 +3234,8 @@ Task Watchdog: - doc/services/task_wdt/index.rst labels: - "area: Task Watchdog" + tests: + - sample.task_wdt "Drivers: Time Aware GPIO": status: maintained @@ -2999,6 +3248,8 @@ Task Watchdog: - samples/drivers/misc/timeaware_gpio/ labels: - "area: Time Aware GPIO" + tests: + - sample.drivers.misc.timeaware_gpio TF-M Integration: status: maintained @@ -3012,6 +3263,8 @@ TF-M Integration: - doc/services/tfm/ labels: - "area: TF-M" + tests: + - tfm "Toolchain Integration": @@ -3080,6 +3333,8 @@ Tracing: - tests/subsys/tracing/ labels: - "area: tracing" + tests: + - tracing USB: status: maintained @@ -3100,6 +3355,9 @@ USB: - scripts/generate_usb_vif/ labels: - "area: USB" + tests: + - usb + - drivers.usb USB-C: status: maintained @@ -3118,6 +3376,8 @@ USB-C: - doc/hardware/peripherals/usbc_vbus.rst labels: - "area: USB-C" + tests: + - sample.usbc Userspace: status: maintained @@ -3146,6 +3406,8 @@ Userspace: - include/zephyr/kernel/mm/demand_paging.h labels: - "area: Userspace" + tests: + - kernel.memory_protection VFS: status: maintained @@ -3159,6 +3421,8 @@ VFS: labels: - "area: File System" + tests: + - filesystem West: status: maintained @@ -3965,6 +4229,8 @@ zbus: - doc/services/zbus/ labels: - "area: zbus" + tests: + - message_bus.zbus "Linkable Loadable Extensions": status: maintained @@ -3981,3 +4247,5 @@ zbus: - doc/services/llext/ labels: - "area: Linkable Loadable Extensions" + tests: + - llext From e710c9ce9ea8b218be36ad1ec5a70aba328c1a8e Mon Sep 17 00:00:00 2001 From: Anas Nashif Date: Fri, 15 Dec 2023 16:28:17 -0500 Subject: [PATCH 1558/3723] MAINTAINERS: Cover as many files as possible Gone through orphaned files and added those to relevant areas and created new areas. Initially, some of the areas have the minimal required data, i.e. without maintainers or collaborators which can be filled in later. Signed-off-by: Anas Nashif --- MAINTAINERS.yml | 303 +++++++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 299 insertions(+), 4 deletions(-) diff --git a/MAINTAINERS.yml b/MAINTAINERS.yml index 1696d41853c..91c7cc5cbc3 100644 --- a/MAINTAINERS.yml +++ b/MAINTAINERS.yml @@ -168,6 +168,7 @@ ARM arch: - doc/hardware/arch/arm_cortex_m.rst - boards/arm/qemu_cortex_m3/ - boards/arm/qemu_cortex_m0/ + - soc/arm/* labels: - "area: ARM" tests: @@ -199,9 +200,20 @@ ARM Platforms: - boards/arm/mps*/ - soc/arm/arm/ - boards/arm/v2m_*/ + - dts/arm/armv*.dtsi labels: - "platform: ARM" +ASPEED Platforms: + status: odd fixes + files: + - soc/arm/aspeed/ + - dts/arm/aspeed/ + - drivers/*/*_ast10x0.c + - drivers/*/Kconfig.aspeed + labels: + - "platform: ASPEED" + ARM SiP SVC: status: odd fixes files: @@ -409,6 +421,15 @@ Bluetooth Audio: tests: - bluetooth.audio +Bootloaders: + status: odd fixes + files: + - tests/boot/ + labels: + - "area: Bootloader" + tests: + - bootloader + Build system: status: maintained maintainers: @@ -427,6 +448,10 @@ Build system: - doc/develop/modules.rst - scripts/build/ - tests/cmake/ + - misc/empty_file.c + - misc/generated/ + - snippets/ + - modules/Kconfig.sysbuild labels: - "area: Build System" tests: @@ -664,6 +689,7 @@ Device Driver Model: - include/zephyr/init.h - tests/kernel/device/ - doc/kernel/drivers/ + - tests/misc/check_init_priorities/ labels: - "area: Device Model" tests: @@ -708,6 +734,7 @@ Devicetree Bindings: files: - dts/bindings/ - include/zephyr/dt-bindings/ + - dts/binding-template.yaml labels: - "area: Devicetree Binding" @@ -745,6 +772,7 @@ Display drivers: - subsys/fb/ - samples/subsys/display/ - doc/hardware/peripherals/display/ + - tests/drivers/*/display/ labels: - "area: Display" @@ -756,6 +784,9 @@ Documentation: collaborators: - nashif files: + - CODE_OF_CONDUCT.md + - CONTRIBUTING.rst + - doc/glossary.rst - doc/contribute/ - doc/develop/ - doc/introduction/ @@ -771,6 +802,7 @@ Documentation: - doc/known-warnings.txt - doc/templates/sample.tmpl - doc/templates/board.tmpl + - boards/index.rst files-exclude: - doc/releases/migration-guide-* - doc/releases/release-notes-* @@ -920,6 +952,7 @@ Release Notes: - include/zephyr/drivers/charger.h - tests/drivers/charger/ - doc/hardware/peripherals/charger.rst + - tests/drivers/build_all/charger/ labels: - "area: Charger" tests: @@ -1030,6 +1063,19 @@ Release Notes: labels: - "area: DAI" +"Drivers: Devmux": + status: maintained + maintainers: + - cfriedt + files: + - drivers/misc/devmux/ + - include/zephyr/drivers/misc/devmux/ + - tests/drivers/console_switching/ + labels: + - "area: Devmux" + tests: + - drivers.devmux + "Drivers: DMA": status: maintained maintainers: @@ -1068,10 +1114,12 @@ Release Notes: - henrikbrixandersen files: - drivers/eeprom/ + - include/zephyr/drivers/eeprom/eeprom_fake.h - dts/bindings/mtd/*eeprom* - include/zephyr/drivers/eeprom.h - samples/drivers/eeprom/ - tests/drivers/eeprom/ + - tests/drivers/*/eeprom/ - doc/hardware/peripherals/eeprom.rst labels: - "area: EEPROM" @@ -1122,6 +1170,7 @@ Release Notes: - tests/drivers/build_all/ethernet/ - dts/bindings/ethernet/ - tests/drivers/ethernet/ + - include/zephyr/drivers/ethernet/ labels: - "area: Ethernet" tests: @@ -1139,6 +1188,8 @@ Release Notes: - samples/drivers/soc_flash_nrf/ - tests/drivers/flash/ - doc/hardware/peripherals/flash.rst + - include/zephyr/drivers/flash/ + - tests/drivers/flash_simulator/ labels: - "area: Flash" tests: @@ -1228,6 +1279,15 @@ Release Notes: tests: - drivers.hwinfo +"Drivers: Hardware Spinlock": + status: odd fixes + files: + - drivers/hwspinlock/ + - dts/bindings/hwspinlock/ + - include/zephyr/drivers/hwspinlock.h + labels: + - "area: Hardware Spinlock" + "Drivers: I2C": status: maintained maintainers: @@ -1240,7 +1300,8 @@ Release Notes: - tests/drivers/i2c/ - doc/hardware/peripherals/i2c.rst - include/zephyr/dt-bindings/i2c/ - - tests/boards/frdm_k64f/i2c/ + - tests/boards/*/i2c/ + - tests/drivers/*/i2c/ labels: - "area: I2C" tests: @@ -1291,19 +1352,90 @@ Release Notes: - jukkar files: - drivers/ieee802154/ + - include/zephyr/drivers/ieee802154/ - include/zephyr/net/ieee802154_radio.h + - tests/drivers/build_all/ieee802154/ labels: - "area: IEEE 802.15.4" + tests: + - drivers.ieee802154 + +"Drivers: Mbox": + status: maintained + maintainers: + - carlocaione + files: + - include/zephyr/drivers/mbox.h + - drivers/mbox/ + - samples/drivers/mbox/ + - dts/bindings/mbox/ + - doc/hardware/peripherals/mbox.rst + labels: + - "area: mbox" + tests: + - sample.drivers.mbox + +"Drivers: MEMC": + status: odd fixes + files: + - drivers/memc/ + - samples/drivers/memc/ + - tests/drivers/memc/ + labels: + - "area: MEMC" + tests: + - samples.drivers.memc + - drivers.memc + +"Drivers: MDIO": + status: odd fixes + files: + - doc/hardware/peripherals/mdio.rst + - drivers/mdio/ + - include/zephyr/drivers/mdio.h + - tests/drivers/build_all/mdio/ + labels: + - "area: MDIO" + tests: + - drivers.mdio + +"Drivers: MIPI-DSI": + status: odd fixes + files: + - drivers/mipi_dsi/ + - doc/hardware/peripherals/mipi_dsi.rst + - include/zephyr/drivers/mipi_dsi.h + - include/zephyr/drivers/mipi_dsi/ + - tests/drivers/mipi_dsi/ + - include/zephyr/dt-bindings/mipi_dsi/ + - dts/bindings/mipi-dsi/ + labels: + - "area: MIPI-DSI" + tests: + - drivers.mipi_dsi + +"Drivers: Reset": + status: odd fixes + files: + - drivers/reset/ + - include/zephyr/drivers/reset.h -"Drivers: Interrupt controllers": +"Interrupt Handling": status: odd fixes files: - drivers/interrupt_controller/ - dts/bindings/interrupt-controller/ - include/zephyr/drivers/interrupt_controller/ - include/zephyr/dt-bindings/interrupt-controller/ + - include/zephyr/irq* + - include/zephyr/sw_isr_table.h + - include/zephyr/shared_irq.h + - tests/drivers/interrupt_controller/ + - tests/drivers/build_all/interrupt_controller/ labels: - "area: Interrupt Controller" + tests: + - drivers.interrupt_controller "Drivers: IPM": status: odd fixes @@ -1355,6 +1487,7 @@ Release Notes: - samples/drivers/led_*/ - tests/drivers/led/ - doc/hardware/peripherals/led.rst + - tests/drivers/build_all/led/ labels: - "area: LED" tests: @@ -1370,6 +1503,7 @@ Release Notes: - dts/bindings/led_strip/ - include/zephyr/drivers/led_strip.h - tests/drivers/build_all/led_strip/ + - include/zephyr/drivers/led_strip/ labels: - "area: LED" tests: @@ -1449,6 +1583,7 @@ Release Notes: - tests/drivers/rtc/ - doc/hardware/peripherals/rtc.rst - include/zephyr/drivers/rtc.h + - tests/drivers/build_all/rtc/ labels: - "area: RTC" tests: @@ -1502,6 +1637,19 @@ Release Notes: tests: - drivers.pinctrl +"Drivers: PS2": + status: odd fixes + files: + - drivers/ps2/ + - doc/hardware/peripherals/ps2.rst + - include/zephyr/drivers/ps2.h + - samples/drivers/ps2/ + - dts/bindings/ps2/ + labels: + - "area: PS2" + tests: + - sample.drivers.espi.ps2 + "Drivers: PTP Clock": status: maintained maintainers: @@ -1541,6 +1689,7 @@ Release Notes: - doc/hardware/peripherals/pwm.rst - tests/drivers/build_all/pwm/ - include/zephyr/drivers/pwm.h + - include/zephyr/drivers/pwm/ labels: - "area: PWM" tests: @@ -1574,6 +1723,8 @@ Release Notes: - tests/drivers/uart/ - tests/drivers/build_all/uart/ - doc/hardware/peripherals/uart.rst + - include/zephyr/drivers/serial/ + - include/zephyr/drivers/uart_pipe.h labels: - "area: UART" tests: @@ -1657,8 +1808,11 @@ Release Notes: - include/zephyr/drivers/video.h - include/zephyr/drivers/video-controls.h - doc/hardware/peripherals/video.rst + - tests/drivers/*/video/ labels: - "area: Video" + tests: + - drivers.video "Drivers: W1": status: maintained @@ -1691,6 +1845,7 @@ Release Notes: - include/zephyr/drivers/watchdog.h - samples/drivers/watchdog/ - tests/drivers/watchdog/ + - tests/drivers/build_all/watchdog/ labels: - "area: Watchdog" tests: @@ -1893,6 +2048,7 @@ IPC: - samples/subsys/ipc/ - subsys/ipc/ - tests/subsys/ipc/ + - doc/services/ipc/ description: >- Inter-Processor Communication labels: @@ -1952,6 +2108,8 @@ Kernel: files: - doc/kernel/ - include/zephyr/kernel*.h + - include/zephyr/spinlock.h + - include/zephyr/fatal.h - kernel/ - tests/kernel/ - include/zephyr/sys_clock.h @@ -1965,6 +2123,31 @@ Kernel: tests: - kernel +Utilities: + status: maintained + files: + - lib/crc/ + - tests/unit/timeutil/ + - tests/unit/time_units/ + - tests/unit/rbtree/ + - tests/unit/math_extras/ + - tests/unit/crc/ + - tests/unit/base64/ + - tests/unit/math_extras/ + - tests/unit/list/ + - tests/unit/intmath/ + - tests/misc/print_format/ + - tests/unit/pot/ + - tests/lib/time/ + - tests/lib/onoff/ + - tests/lib/sys_util/ + - tests/lib/sprintf/ + - tests/lib/ringbuffer/ + - tests/lib/notify/ + - tests/lib/linear_range/ + labels: + - "area: Utilities" + Base OS: status: maintained maintainers: @@ -1989,6 +2172,36 @@ Base OS: labels: - "area: Base OS" +Heap Management: + status: maintained + maintainers: + - npitre + - andyross + files: + - tests/lib/shared_multi_heap/ + - lib/heap/ + - tests/lib/heap/ + - tests/lib/heap_align/ + - tests/lib/multi_heap/ + - include/zephyr/multi_heap/ + +Memory Management: + status: maintained + maintainers: + - carlocaione + - dcpleung + files: + - subsys/mem_mgmt/ + - lib/mem_blocks/ + - tests/subsys/mem_mgmt/ + - include/zephyr/mem_mgmt/mem_attr_heap.h + - tests/lib/mem_alloc/ + - tests/lib/mem_blocks/ + - doc/services/mem_mgmt/ + - include/zephyr/mem_mgmt/mem_attr.h + - tests/lib/mem_blocks_stats/ + - tests/drivers/mm/ + Laird Connectivity platforms: status: maintained maintainers: @@ -2005,6 +2218,19 @@ Laird Connectivity platforms: labels: - "platform: Laird Connectivity" +Linker Scripts: + status: maintained + maintainers: + - nashif + files: + - include/zephyr/linker/ + - tests/misc/iterable_sections/ + - tests/application_development/code_relocation/ + labels: + - "area: Linker Scripts" + tests: + - linker + Little FS: status: odd fixes files: @@ -2106,6 +2332,7 @@ MCU Manager: - samples/subsys/mgmt/mcumgr/ - tests/subsys/mgmt/mcumgr/ - doc/services/device_mgmt/ + - scripts/utils/migrate_mcumgr_kconfigs.py labels: - "area: mcumgr" tests: @@ -2136,6 +2363,7 @@ Modem: - tests/subsys/modem/ - doc/services/modem/ - samples/net/cellular_modem/ + - include/zephyr/drivers/cellular.h labels: - "area: Modem" tests: @@ -2176,6 +2404,7 @@ hawkBit: - nandojve files: - subsys/mgmt/updatehub/ + - include/zephyr/mgmt/updatehub.h - samples/subsys/mgmt/updatehub/ labels: - "area: updatehub" @@ -2209,7 +2438,7 @@ Native POSIX/Sim and POSIX arch: description: >- POSIX architecture and SOC, native_posix & native_sim boards, and related drivers tests: - - boards.native_posix + - boards.native_sim Networking: status: maintained @@ -2220,12 +2449,14 @@ Networking: - tbursztyka - ssharks files: + - scripts/net/ - drivers/net/ - include/zephyr/net/ - samples/net/ - subsys/net/ - doc/connectivity/networking/ - tests/net/ + - tests/unit/net_timeout/ files-exclude: - doc/connectivity/networking/api/gptp.rst - doc/connectivity/networking/api/ieee802154.rst @@ -2442,12 +2673,14 @@ NIOS-2 arch: - nashif files: - arch/nios2/ + - dts/nios2/intel/ - boards/common/nios2.board.cmake - boards/nios2/ - soc/nios2/ - include/zephyr/arch/nios2/ - tests/boards/altera_max10/ - boards/nios2/qemu_nios2/ + - scripts/support/quartus-flash.py labels: - "area: NIOS2" tests: @@ -2468,6 +2701,14 @@ nRF BSIM: tests: - boards.nrf52_bsim +Open AMP: + status: maintained + maintainers: + - carlocaione + files: + - lib/open-amp/ + + POSIX API layer: status: maintained maintainers: @@ -2506,6 +2747,14 @@ Power management: tests: - pm +"Quicklogic Platform": + status: odd fixes + files: + - soc/arm/quicklogic_eos_s3/ + - dts/arm/quicklogic/ + labels: + - "platform: Quicklogic" + RISCV arch: status: maintained maintainers: @@ -2605,6 +2854,8 @@ Twister: - scripts/pylib/pytest-twister-harness/ - doc/develop/test/pytest.rst - tests/test_config.yaml + - scripts/utils/twister_to_list.py + - tests/robot/common.robot labels: - "area: Twister" @@ -2706,6 +2957,13 @@ ADI Platforms: labels: - "platform: ADI" +Broadcom Platforms: + status: odd fixes + files: + - dts/arm/broadcom/ + - soc/arm/bcm_vk/ + - boards/arm/bcm95840*/ + GD32 Platforms: status: maintained maintainers: @@ -2890,6 +3148,7 @@ Intel Platforms (Agilex): - soc/arm64/intel_*/ - dts/arm64/intel/ - dts/bindings/*/intel,agilex* + - dts/arm/intel_socfpga_std/ labels: - "platform: Intel SoC FPGA Agilex" @@ -3004,6 +3263,15 @@ Renesas SmartBond Platforms: Renesas SmartBond SOCs, dts files, and related drivers. Renesas boards based on SmartBond SoCs. +Renesas Platforms: + status: odd fixes + files: + - soc/arm/renesas_ra/ + - dts/arm/renesas/ra/ + - soc/arm/renesas_rzt2m/ + labels: + - "platforms: Renesas" + Renesas R-Car Platforms: status: maintained maintainers: @@ -3012,6 +3280,7 @@ Renesas R-Car Platforms: collaborators: - xakep-amatop files: + - dts/arm/renesas/rcar/ - boards/arm/rcar_*/ - boards/arm64/rcar_*/ - drivers/*/*rcar* @@ -3021,6 +3290,7 @@ Renesas R-Car Platforms: - dts/bindings/*/*rcar* - soc/arm/renesas_rcar/ - soc/arm64/renesas_rcar/ + - dts/arm/renesas/rzt2m.dtsi labels: - "platform: Renesas R-Car" description: >- @@ -3122,6 +3392,7 @@ TI SimpleLink Platforms: - dts/bindings/*/ti,* - soc/arm/ti_simplelink/ - dts/bindings/*/ti,* + - modules/Kconfig.simplelink labels: - "platform: TI SimpleLink" @@ -3140,6 +3411,14 @@ TI K3 Platforms: labels: - "platform: TI K3" +TI Platforms: + status: odd fixes + files: + - soc/arm/ti_lm3s6965/ + - dts/arm/ti/lm3s6965.dtsi + labels: + - "platform: TI" + Xilinx Platforms: status: odd fixes collaborators: @@ -3170,6 +3449,8 @@ Infineon Platforms: - drivers/*/*xmc*.c - drivers/*/*/*xmc* - dts/arm/infineon/ + - dts/arm/cypress/ + - soc/arm/cypress/ - dts/bindings/*/*infineon* - soc/arm/infineon_*/ labels: @@ -3237,6 +3518,17 @@ Task Watchdog: tests: - sample.task_wdt +"Drivers: Syscon": + status: maintained + maintainers: + - carlocaione + files: + - include/zephyr/drivers/syscon.h + - drivers/syscon/ + - tests/drivers/syscon/ + tests: + - drivers.syscon + "Drivers: Time Aware GPIO": status: maintained maintainers: @@ -3350,6 +3642,7 @@ USB: - samples/subsys/usb/ - subsys/usb/ - tests/subsys/usb/ + - tests/drivers/usb/ - tests/drivers/udc/ - doc/connectivity/usb/ - scripts/generate_usb_vif/ @@ -4114,6 +4407,7 @@ Xtensa arch: - boards/xtensa/xt-sim/ - soc/xtensa/dc233c/ - soc/xtensa/sample_controller/ + - soc/xtensa/CMakeLists.txt labels: - "area: Xtensa" @@ -4154,7 +4448,7 @@ Continuous Integration: labels: - "area: Continuous Integration" -ZTest: +Test Framework (Ztest): status: maintained maintainers: - nashif @@ -4185,6 +4479,7 @@ Emulation: - tristan-google files: - subsys/emul/ + - include/zephyr/drivers/emul_* - include/zephyr/drivers/emul.h - include/zephyr/drivers/espi_emul.h - include/zephyr/drivers/i2c_emul.h From 0b999c0943001c0faeafacbceda0c277f194bbe2 Mon Sep 17 00:00:00 2001 From: Anas Nashif Date: Wed, 20 Dec 2023 08:07:43 -0500 Subject: [PATCH 1559/3723] lib: move utilities into own folder Move various utilities out of lib into own folder for better assignement and management in the maintainer file. lib/os has become another dumping ground for everything and it the Kconfig and contents in that folder became difficult to manage, configure and test. Signed-off-by: Anas Nashif --- MAINTAINERS.yml | 19 +++++++++-- lib/CMakeLists.txt | 1 + lib/Kconfig | 2 ++ lib/os/CMakeLists.txt | 17 ---------- lib/os/Kconfig | 54 ----------------------------- lib/utils/CMakeLists.txt | 27 +++++++++++++++ lib/utils/Kconfig | 60 +++++++++++++++++++++++++++++++++ lib/{os => utils}/base64.c | 0 lib/{os => utils}/bitarray.c | 0 lib/{os => utils}/dec.c | 0 lib/{os => utils}/hex.c | 0 lib/{os => utils}/json.c | 0 lib/{os => utils}/notify.c | 0 lib/{os => utils}/onoff.c | 0 lib/{os => utils}/rb.c | 0 lib/{os => utils}/ring_buffer.c | 0 lib/{os => utils}/timeutil.c | 0 lib/{os => utils}/utf8.c | 0 lib/{os => utils}/winstream.c | 0 tests/unit/base64/main.c | 2 +- tests/unit/rbtree/main.c | 2 +- tests/unit/timeutil/main.c | 2 +- tests/unit/util/CMakeLists.txt | 2 +- tests/unit/winstream/main.c | 2 +- 24 files changed, 112 insertions(+), 78 deletions(-) create mode 100644 lib/utils/CMakeLists.txt create mode 100644 lib/utils/Kconfig rename lib/{os => utils}/base64.c (100%) rename lib/{os => utils}/bitarray.c (100%) rename lib/{os => utils}/dec.c (100%) rename lib/{os => utils}/hex.c (100%) rename lib/{os => utils}/json.c (100%) rename lib/{os => utils}/notify.c (100%) rename lib/{os => utils}/onoff.c (100%) rename lib/{os => utils}/rb.c (100%) rename lib/{os => utils}/ring_buffer.c (100%) rename lib/{os => utils}/timeutil.c (100%) rename lib/{os => utils}/utf8.c (100%) rename lib/{os => utils}/winstream.c (100%) diff --git a/MAINTAINERS.yml b/MAINTAINERS.yml index 91c7cc5cbc3..8b1a9075d4a 100644 --- a/MAINTAINERS.yml +++ b/MAINTAINERS.yml @@ -2066,7 +2066,7 @@ JSON Web Token: files: - subsys/jwt/ - include/zephyr/data/ - - lib/os/json.c + - lib/utils/json.c - tests/subsys/jwt/ - tests/lib/json/ labels: @@ -2125,8 +2125,15 @@ Kernel: Utilities: status: maintained + maintainers: + - andyross + - nashif + collaborators: + - dcpleung + - peter-mitsis files: - lib/crc/ + - lib/utils/ - tests/unit/timeutil/ - tests/unit/time_units/ - tests/unit/rbtree/ @@ -2136,7 +2143,6 @@ Utilities: - tests/unit/math_extras/ - tests/unit/list/ - tests/unit/intmath/ - - tests/misc/print_format/ - tests/unit/pot/ - tests/lib/time/ - tests/lib/onoff/ @@ -2147,6 +2153,10 @@ Utilities: - tests/lib/linear_range/ labels: - "area: Utilities" + tests: + - utilities + - libraries.ring_buffer + - libraries.linear_range Base OS: status: maintained @@ -2159,6 +2169,9 @@ Base OS: files: - include/zephyr/sys/ - lib/os/ + - tests/misc/print_format/ + - tests/lib/p4workq/ + - tests/lib/fdtable/ files-exclude: - include/zephyr/sys/cbprintf* - tests/unit/cbprintf/ @@ -2171,6 +2184,8 @@ Base OS: - lib/os/mpsc_pbuf.c labels: - "area: Base OS" + tests: + - printk Heap Management: status: maintained diff --git a/lib/CMakeLists.txt b/lib/CMakeLists.txt index 75387fdbb9a..c2abdd9559d 100644 --- a/lib/CMakeLists.txt +++ b/lib/CMakeLists.txt @@ -13,6 +13,7 @@ add_subdirectory(hash) add_subdirectory(heap) add_subdirectory(mem_blocks) add_subdirectory(os) +add_subdirectory(utils) add_subdirectory_ifdef(CONFIG_SMF smf) add_subdirectory_ifdef(CONFIG_OPENAMP open-amp) add_subdirectory_ifdef(CONFIG_ACPI acpi) diff --git a/lib/Kconfig b/lib/Kconfig index 1b95bde76b1..af6717bc22e 100644 --- a/lib/Kconfig +++ b/lib/Kconfig @@ -26,4 +26,6 @@ source "lib/smf/Kconfig" source "lib/acpi/Kconfig" source "lib/runtime/Kconfig" + +source "lib/utils/Kconfig" endmenu diff --git a/lib/os/CMakeLists.txt b/lib/os/CMakeLists.txt index 47d4501ca0b..3a52bebab04 100644 --- a/lib/os/CMakeLists.txt +++ b/lib/os/CMakeLists.txt @@ -4,23 +4,14 @@ zephyr_syscall_header( ${ZEPHYR_BASE}/include/zephyr/sys/mutex.h ) -zephyr_sources_ifdef(CONFIG_BASE64 base64.c) - zephyr_sources( cbprintf_packaged.c - dec.c - hex.c printk.c - rb.c sem.c thread_entry.c - timeutil.c - bitarray.c ) zephyr_sources_ifdef(CONFIG_FDTABLE fdtable.c) -zephyr_sources_ifdef(CONFIG_ONOFF onoff.c) -zephyr_sources_ifdef(CONFIG_NOTIFY notify.c) zephyr_sources_ifdef(CONFIG_CBPRINTF_COMPLETE cbprintf_complete.c) zephyr_sources_ifdef(CONFIG_CBPRINTF_NANO cbprintf_nano.c) @@ -29,10 +20,6 @@ if(NOT CONFIG_PICOLIBC) zephyr_sources(cbprintf.c) endif() -zephyr_sources_ifdef(CONFIG_JSON_LIBRARY json.c) - -zephyr_sources_ifdef(CONFIG_RING_BUFFER ring_buffer.c) - if (CONFIG_ASSERT OR CONFIG_ASSERT_VERBOSE) zephyr_sources(assert.c) endif() @@ -47,10 +34,6 @@ zephyr_sources_ifdef(CONFIG_SCHED_DEADLINE p4wq.c) zephyr_sources_ifdef(CONFIG_REBOOT reboot.c) -zephyr_sources_ifdef(CONFIG_UTF8 utf8.c) - -zephyr_sources_ifdef(CONFIG_WINSTREAM winstream.c) - zephyr_sources_ifdef(CONFIG_POWEROFF poweroff.c) zephyr_library_include_directories( diff --git a/lib/os/Kconfig b/lib/os/Kconfig index 2f67b2da4dc..14b6241b72c 100644 --- a/lib/os/Kconfig +++ b/lib/os/Kconfig @@ -10,29 +10,6 @@ config FDTABLE for any I/O object implementing POSIX I/O semantics (i.e. read/write + aux operations). -config JSON_LIBRARY - bool "Build JSON library" - help - Build a minimal JSON parsing/encoding library. Used by sample - applications such as the NATS client. - -config RING_BUFFER - bool "Ring buffers" - help - Enable usage of ring buffers. This is similar to kernel FIFOs but ring - buffers manage their own buffer memory and can store arbitrary data. - For optimal performance, use buffer sizes that are a power of 2. - -config NOTIFY - bool "Asynchronous Notifications" - help - Use this API to support async transactions. - -config BASE64 - bool "Base64 encoding and decoding" - help - Enable base64 encoding and decoding functionality - config PRINTK_SYNC bool "Serialize printk() calls" default y if SMP && MP_MAX_NUM_CPUS > 1 && !(EFI_CONSOLE && LOG) @@ -50,14 +27,6 @@ config MPSC_PBUF storing variable length packets in a circular way and operate directly on the buffer memory. -config ONOFF - bool "On-Off Manager" - select NOTIFY - help - An on-off manager supports an arbitrary number of clients of a - service which has a binary state. Example applications are power - rails, clocks, and binary device power management. - config SPSC_PBUF bool "Single producer, single consumer packet buffer" help @@ -119,23 +88,6 @@ config SPSC_PBUF_UTILIZATION endif # SPSC_PBUF -config WINSTREAM - bool "Lockless shared memory window byte stream" - help - Winstream is a byte stream IPC for use in shared memory - "windows", generally for transmit to non-Zephyr contexts that - can't share Zephyr APIs or data structures. - -if WINSTREAM -config WINSTREAM_STDLIB_MEMCOPY - bool "Use standard memcpy() in winstream" - help - The sys_winstream utility is sometimes used in early boot - environments before the standard library is usable. By - default it uses a simple internal bytewise memcpy(). Set - this to use the one from the standard library. -endif - if MPSC_PBUF config MPSC_CLEAR_ALLOCATED bool "Clear allocated packet" @@ -161,12 +113,6 @@ config POWEROFF help Enable support for system power off. -config UTF8 - bool "UTF-8 string operation supported" - help - Enable the utf8 API. The API implements functions to specifically - handle UTF-8 encoded strings. - rsource "Kconfig.cbprintf" endmenu diff --git a/lib/utils/CMakeLists.txt b/lib/utils/CMakeLists.txt new file mode 100644 index 00000000000..e0e1673f445 --- /dev/null +++ b/lib/utils/CMakeLists.txt @@ -0,0 +1,27 @@ +# SPDX-License-Identifier: Apache-2.0 + +zephyr_sources_ifdef(CONFIG_BASE64 base64.c) + +zephyr_sources( + dec.c + hex.c + rb.c + timeutil.c + bitarray.c + ) + +zephyr_sources_ifdef(CONFIG_ONOFF onoff.c) +zephyr_sources_ifdef(CONFIG_NOTIFY notify.c) + +zephyr_sources_ifdef(CONFIG_JSON_LIBRARY json.c) + +zephyr_sources_ifdef(CONFIG_RING_BUFFER ring_buffer.c) + +zephyr_sources_ifdef(CONFIG_UTF8 utf8.c) + +zephyr_sources_ifdef(CONFIG_WINSTREAM winstream.c) + +zephyr_library_include_directories( + ${ZEPHYR_BASE}/kernel/include + ${ZEPHYR_BASE}/arch/${ARCH}/include +) diff --git a/lib/utils/Kconfig b/lib/utils/Kconfig new file mode 100644 index 00000000000..340c0ac42c2 --- /dev/null +++ b/lib/utils/Kconfig @@ -0,0 +1,60 @@ +# Copyright (c) 2016 Intel Corporation +# SPDX-License-Identifier: Apache-2.0 + +menu "Utility Library" + +config JSON_LIBRARY + bool "Build JSON library" + help + Build a minimal JSON parsing/encoding library. Used by sample + applications such as the NATS client. + +config RING_BUFFER + bool "Ring buffers" + help + Enable usage of ring buffers. This is similar to kernel FIFOs but ring + buffers manage their own buffer memory and can store arbitrary data. + For optimal performance, use buffer sizes that are a power of 2. + +config NOTIFY + bool "Asynchronous Notifications" + help + Use this API to support async transactions. + +config BASE64 + bool "Base64 encoding and decoding" + help + Enable base64 encoding and decoding functionality + +config ONOFF + bool "On-Off Manager" + select NOTIFY + help + An on-off manager supports an arbitrary number of clients of a + service which has a binary state. Example applications are power + rails, clocks, and binary device power management. + +config WINSTREAM + bool "Lockless shared memory window byte stream" + help + Winstream is a byte stream IPC for use in shared memory + "windows", generally for transmit to non-Zephyr contexts that + can't share Zephyr APIs or data structures. + +if WINSTREAM +config WINSTREAM_STDLIB_MEMCOPY + bool "Use standard memcpy() in winstream" + help + The sys_winstream utility is sometimes used in early boot + environments before the standard library is usable. By + default it uses a simple internal bytewise memcpy(). Set + this to use the one from the standard library. +endif + +config UTF8 + bool "UTF-8 string operation supported" + help + Enable the utf8 API. The API implements functions to specifically + handle UTF-8 encoded strings. + +endmenu diff --git a/lib/os/base64.c b/lib/utils/base64.c similarity index 100% rename from lib/os/base64.c rename to lib/utils/base64.c diff --git a/lib/os/bitarray.c b/lib/utils/bitarray.c similarity index 100% rename from lib/os/bitarray.c rename to lib/utils/bitarray.c diff --git a/lib/os/dec.c b/lib/utils/dec.c similarity index 100% rename from lib/os/dec.c rename to lib/utils/dec.c diff --git a/lib/os/hex.c b/lib/utils/hex.c similarity index 100% rename from lib/os/hex.c rename to lib/utils/hex.c diff --git a/lib/os/json.c b/lib/utils/json.c similarity index 100% rename from lib/os/json.c rename to lib/utils/json.c diff --git a/lib/os/notify.c b/lib/utils/notify.c similarity index 100% rename from lib/os/notify.c rename to lib/utils/notify.c diff --git a/lib/os/onoff.c b/lib/utils/onoff.c similarity index 100% rename from lib/os/onoff.c rename to lib/utils/onoff.c diff --git a/lib/os/rb.c b/lib/utils/rb.c similarity index 100% rename from lib/os/rb.c rename to lib/utils/rb.c diff --git a/lib/os/ring_buffer.c b/lib/utils/ring_buffer.c similarity index 100% rename from lib/os/ring_buffer.c rename to lib/utils/ring_buffer.c diff --git a/lib/os/timeutil.c b/lib/utils/timeutil.c similarity index 100% rename from lib/os/timeutil.c rename to lib/utils/timeutil.c diff --git a/lib/os/utf8.c b/lib/utils/utf8.c similarity index 100% rename from lib/os/utf8.c rename to lib/utils/utf8.c diff --git a/lib/os/winstream.c b/lib/utils/winstream.c similarity index 100% rename from lib/os/winstream.c rename to lib/utils/winstream.c diff --git a/tests/unit/base64/main.c b/tests/unit/base64/main.c index 51eb6332645..f2deba1e3f0 100644 --- a/tests/unit/base64/main.c +++ b/tests/unit/base64/main.c @@ -27,7 +27,7 @@ #include #include -#include "../../../lib/os/base64.c" +#include "../../../lib/utils/base64.c" static const unsigned char base64_test_dec[64] = { 0x24, 0x48, 0x6E, 0x56, 0x87, 0x62, 0x5A, 0xBD, diff --git a/tests/unit/rbtree/main.c b/tests/unit/rbtree/main.c index ebec04f6da1..9e9bc4ab934 100644 --- a/tests/unit/rbtree/main.c +++ b/tests/unit/rbtree/main.c @@ -6,7 +6,7 @@ #include #include -#include "../../../lib/os/rb.c" +#include "../../../lib/utils/rb.c" #define _CHECK(n) \ zassert_true(!!(n), "Tree check failed: [ " #n " ] @%d", __LINE__) diff --git a/tests/unit/timeutil/main.c b/tests/unit/timeutil/main.c index 79d6e007c5d..6937d8fe81e 100644 --- a/tests/unit/timeutil/main.c +++ b/tests/unit/timeutil/main.c @@ -6,7 +6,7 @@ #include #include "timeutil_test.h" -#include "../../../lib/os/timeutil.c" +#include "../../../lib/utils/timeutil.c" void timeutil_check(const struct timeutil_test_data *tp, size_t count) diff --git a/tests/unit/util/CMakeLists.txt b/tests/unit/util/CMakeLists.txt index 8e8a49ce1b1..a78fab2bfd5 100644 --- a/tests/unit/util/CMakeLists.txt +++ b/tests/unit/util/CMakeLists.txt @@ -4,4 +4,4 @@ cmake_minimum_required(VERSION 3.20.0) project(util) find_package(Zephyr COMPONENTS unittest REQUIRED HINTS $ENV{ZEPHYR_BASE}) -target_sources(testbinary PRIVATE main.c maincxx.cxx ${ZEPHYR_BASE}/lib/os/dec.c) +target_sources(testbinary PRIVATE main.c maincxx.cxx ${ZEPHYR_BASE}/lib/utils/dec.c) diff --git a/tests/unit/winstream/main.c b/tests/unit/winstream/main.c index 14728c70922..3136b98c088 100644 --- a/tests/unit/winstream/main.c +++ b/tests/unit/winstream/main.c @@ -8,7 +8,7 @@ /* This, uh, seems to be the standard way to unit test library code. * Or so I gather from tests/unit/rbtree ... */ -#include "../../../lib/os/winstream.c" +#include "../../../lib/utils/winstream.c" #define BUFLEN 64 From 8e3a3b484521d3feaf4be52b4841006d5f89f538 Mon Sep 17 00:00:00 2001 From: Dmitrii Golovanov Date: Wed, 20 Dec 2023 16:34:37 +0100 Subject: [PATCH 1560/3723] twister: coverage: GCOVR as defautlt coverage reporting tool Twister now uses GCOVR by default as the more reliable code coverage reporting tool instead of LCOV. Signed-off-by: Dmitrii Golovanov --- doc/develop/test/coverage.rst | 6 +++++- scripts/pylib/twister/twisterlib/environment.py | 2 +- 2 files changed, 6 insertions(+), 2 deletions(-) diff --git a/doc/develop/test/coverage.rst b/doc/develop/test/coverage.rst index 84eadad1a21..60faffa1a90 100644 --- a/doc/develop/test/coverage.rst +++ b/doc/develop/test/coverage.rst @@ -142,7 +142,11 @@ or:: $ twister --coverage -p native_sim -T tests/bluetooth -which will produce ``twister-out/coverage/index.html`` with the report. +which will produce ``twister-out/coverage/index.html`` report as well as +the coverage data collected by ``gcovr`` tool in ``twister-out/coverage.json``. + +Other reports might be chosen with ``--coverage-tool`` and ``--coverage-formats`` +command line options. The process differs for unit tests, which are built with the host toolchain and require a different board:: diff --git a/scripts/pylib/twister/twisterlib/environment.py b/scripts/pylib/twister/twisterlib/environment.py index 03ac103b894..b2b00296ff8 100644 --- a/scripts/pylib/twister/twisterlib/environment.py +++ b/scripts/pylib/twister/twisterlib/environment.py @@ -305,7 +305,7 @@ def add_parse_arguments(parser = None): "This option may be used multiple times. " "Default to what was selected with --platform.") - parser.add_argument("--coverage-tool", choices=['lcov', 'gcovr'], default='lcov', + parser.add_argument("--coverage-tool", choices=['lcov', 'gcovr'], default='gcovr', help="Tool to use to generate coverage report.") parser.add_argument("--coverage-formats", action="store", default=None, # default behavior is set in run_coverage From f688532412432987682716de60bdf17f2afd4b38 Mon Sep 17 00:00:00 2001 From: Dmitrii Golovanov Date: Wed, 20 Dec 2023 16:41:54 +0100 Subject: [PATCH 1561/3723] twister: coverage: Add command line options check for reporting Additional checks for Twister command line options `--coverage-tool` and `--coverage-formats`. Signed-off-by: Dmitrii Golovanov --- scripts/pylib/twister/twisterlib/coverage.py | 6 ++++++ scripts/pylib/twister/twisterlib/environment.py | 16 +++++++++++++--- 2 files changed, 19 insertions(+), 3 deletions(-) diff --git a/scripts/pylib/twister/twisterlib/coverage.py b/scripts/pylib/twister/twisterlib/coverage.py index 91265a2665a..18aba2bc162 100644 --- a/scripts/pylib/twister/twisterlib/coverage.py +++ b/scripts/pylib/twister/twisterlib/coverage.py @@ -14,6 +14,12 @@ logger = logging.getLogger('twister') logger.setLevel(logging.DEBUG) +supported_coverage_formats = { + "gcovr": ["html", "xml", "csv", "txt", "coveralls", "sonarqube"], + "lcov": ["html", "lcov"] +} + + class CoverageTool: """ Base class for every supported coverage tool """ diff --git a/scripts/pylib/twister/twisterlib/environment.py b/scripts/pylib/twister/twisterlib/environment.py index b2b00296ff8..7e9c7dee7dd 100644 --- a/scripts/pylib/twister/twisterlib/environment.py +++ b/scripts/pylib/twister/twisterlib/environment.py @@ -16,6 +16,7 @@ import re import argparse from datetime import datetime, timezone +from twisterlib.coverage import supported_coverage_formats logger = logging.getLogger('twister') logger.setLevel(logging.DEBUG) @@ -309,9 +310,11 @@ def add_parse_arguments(parser = None): help="Tool to use to generate coverage report.") parser.add_argument("--coverage-formats", action="store", default=None, # default behavior is set in run_coverage - help="Output formats to use for generated coverage reports, as a comma-separated list. " - "Default to html. " - "Valid options are html, xml, csv, txt, coveralls, sonarqube, lcov.") + help="Output formats to use for generated coverage reports, as a comma-separated list. " + + "Valid options for 'gcovr' tool are: " + + ','.join(supported_coverage_formats['gcovr']) + " (html - default)." + + " Valid options for 'lcov' tool are: " + + ','.join(supported_coverage_formats['lcov']) + " (html,lcov - default).") parser.add_argument("--test-config", action="store", default=os.path.join(ZEPHYR_BASE, "tests", "test_config.yaml"), help="Path to file with plans and test configurations.") @@ -759,6 +762,13 @@ def parse_arguments(parser, args, options = None): if not options.coverage_platform: options.coverage_platform = options.platform + if options.coverage_formats: + for coverage_format in options.coverage_formats.split(','): + if coverage_format not in supported_coverage_formats[options.coverage_tool]: + logger.error(f"Unsupported coverage report formats:'{options.coverage_formats}' " + f"for {options.coverage_tool}") + sys.exit(1) + if options.enable_valgrind and not shutil.which("valgrind"): logger.error("valgrind enabled but valgrind executable not found") sys.exit(1) From 6bf63b252a92515a6118b556e78aec8a66398663 Mon Sep 17 00:00:00 2001 From: James Anderson Date: Sun, 17 Dec 2023 15:48:16 -0800 Subject: [PATCH 1562/3723] boards: arm: add usb_otg_hs instance to stm32f429i_disc1 This adds the pins for the board's USB Micro-B connector to the device tree as zephyr_udc0, allowing USB examples to run natively on the board Signed-off-by: James Anderson --- boards/arm/stm32f429i_disc1/doc/index.rst | 11 +++++++++++ boards/arm/stm32f429i_disc1/stm32f429i_disc1.dts | 6 ++++++ 2 files changed, 17 insertions(+) diff --git a/boards/arm/stm32f429i_disc1/doc/index.rst b/boards/arm/stm32f429i_disc1/doc/index.rst index b2787dc7d98..ba2317772a3 100644 --- a/boards/arm/stm32f429i_disc1/doc/index.rst +++ b/boards/arm/stm32f429i_disc1/doc/index.rst @@ -97,6 +97,8 @@ The Zephyr stm32f429i_disc1 board configuration supports the following hardware +-----------+------------+-------------------------------------+ | FMC | on-chip | memc (SDRAM) | +-----------+------------+-------------------------------------+ +| OTG_HS | on-chip | usbotg_hs | ++-----------+------------+-------------------------------------+ Other hardware features are not yet supported on Zephyr porting. @@ -130,6 +132,9 @@ Default Zephyr Peripheral Mapping: - SPI_5_SCK : PF7 - SPI_5_MISO : PF8 - SPI_5_MOSI : PF9 +- OTG_HS_ID : PB12 +- OTG_HS_DM : PB14 +- OTG_HS_DP : PB15 System Clock ============ @@ -144,6 +149,12 @@ Serial Port The STM32F429I-DISC1 Discovery kit has up to 8 UARTs. The Zephyr console output is assigned to UART1. The default communication settings are 115200 8N1. +USB Port +=========== + +The STM32F429I-DISC1 Discovery kit has a USB FS capable Micro-B port. It is connected to the on-chip +OTG_HS peripheral, but operates in FS mode only since no HS PHY is present. The board supports device +and host OTG operation, but only device mode has been tested with Zephyr at this time. Programming and Debugging ************************* diff --git a/boards/arm/stm32f429i_disc1/stm32f429i_disc1.dts b/boards/arm/stm32f429i_disc1/stm32f429i_disc1.dts index 60b8c2874f9..0f36273b309 100644 --- a/boards/arm/stm32f429i_disc1/stm32f429i_disc1.dts +++ b/boards/arm/stm32f429i_disc1/stm32f429i_disc1.dts @@ -247,3 +247,9 @@ def-back-color-green = <0xFF>; def-back-color-blue = <0xFF>; }; + +zephyr_udc0: &usbotg_hs { + pinctrl-0 = <&usb_otg_hs_dm_pb14 &usb_otg_hs_dp_pb15 &usb_otg_hs_id_pb12>; + pinctrl-names = "default"; + status = "okay"; +}; From b728ff9ed365f6f7176daf7b5ee2046c8e396cb6 Mon Sep 17 00:00:00 2001 From: Mariusz Skamra Date: Fri, 7 Jul 2023 14:54:37 +0200 Subject: [PATCH 1563/3723] Bluetooth: audio: tbs: Factor out GTBS and TBS common code This refactors the code to remove code duplicates by creating common tbs_inst object. Signed-off-by: Mariusz Skamra --- subsys/bluetooth/audio/tbs.c | 1091 +++++++++++++--------------------- 1 file changed, 414 insertions(+), 677 deletions(-) diff --git a/subsys/bluetooth/audio/tbs.c b/subsys/bluetooth/audio/tbs.c index 06b5d7d2e3c..3d8323b2968 100644 --- a/subsys/bluetooth/audio/tbs.c +++ b/subsys/bluetooth/audio/tbs.c @@ -25,17 +25,11 @@ LOG_MODULE_REGISTER(bt_tbs, CONFIG_BT_TBS_LOG_LEVEL); #define BT_TBS_VALID_STATUS_FLAGS(val) ((val) <= (BIT(0) | BIT(1))) -#define IS_GTBS_CHRC(_attr) \ - IS_ENABLED(CONFIG_BT_GTBS) && BT_AUDIO_CHRC_USER_DATA(_attr) == >bs_inst -/* TODO: Have tbs_service_inst include gtbs_service_inst and use CONTAINER_OF - * to get a specific TBS instance from a GTBS pointer. - */ -struct tbs_service_inst { +struct service_inst { /* Attribute values */ char provider_name[CONFIG_BT_TBS_MAX_PROVIDER_NAME_LENGTH]; char uci[BT_TBS_MAX_UCI_SIZE]; - char uri_scheme_list[CONFIG_BT_TBS_MAX_SCHEME_LIST_LENGTH]; uint8_t technology; uint8_t signal_strength; uint8_t signal_strength_interval; @@ -43,52 +37,33 @@ struct tbs_service_inst { uint16_t optional_opcodes; uint16_t status_flags; struct bt_tbs_in_uri incoming_uri; - struct bt_tbs_terminate_reason terminate_reason; struct bt_tbs_in_uri friendly_name; struct bt_tbs_in_uri in_call; - /* Instance values */ - uint8_t index; - struct bt_tbs_call calls[CONFIG_BT_TBS_MAX_CALLS]; bool notify_current_calls; bool notify_call_states; bool pending_signal_strength_notification; struct k_work_delayable reporting_interval_work; - /* TODO: The TBS (service) and the Telephone Bearers should be separated - * into two different instances. This is due to the addition of GTBS, - * where we now are in a state where this isn't a 1-to-1 correlation - * between TBS and the Telephone Bearers - */ - struct bt_gatt_service *service_p; + /** Service Attributes */ + const struct bt_gatt_attr *attrs; + /** Service Attribute count */ + size_t attr_count; }; -struct gtbs_service_inst { +struct tbs_service_inst { + struct service_inst inst; + /* Attribute values */ - char provider_name[CONFIG_BT_TBS_MAX_PROVIDER_NAME_LENGTH]; - char uci[BT_TBS_MAX_UCI_SIZE]; - uint8_t technology; - uint8_t signal_strength; - uint8_t signal_strength_interval; - uint8_t ccid; - uint16_t optional_opcodes; - uint16_t status_flags; - struct bt_tbs_in_uri incoming_uri; - struct bt_tbs_in_uri friendly_name; - struct bt_tbs_in_uri in_call; + char uri_scheme_list[CONFIG_BT_TBS_MAX_SCHEME_LIST_LENGTH]; + struct bt_tbs_terminate_reason terminate_reason; /* Instance values */ - bool notify_current_calls; - bool notify_call_states; - bool pending_signal_strength_notification; - struct k_work_delayable reporting_interval_work; + struct bt_tbs_call calls[CONFIG_BT_TBS_MAX_CALLS]; +}; - /* TODO: The TBS (service) and the Telephone Bearers should be separated - * into two different instances. This is due to the addition of GTBS, - * where we now are in a state where this isn't a 1-to-1 correlation - * between TBS and the Telephone Bearers - */ - const struct bt_gatt_service_static *service_p; +struct gtbs_service_inst { + struct service_inst inst; }; #if defined(CONFIG_BT_GTBS) @@ -110,6 +85,43 @@ static uint8_t held_calls_cnt; static struct bt_tbs_cb *tbs_cbs; +static bool inst_is_gtbs(const struct service_inst *inst) +{ + return IS_ENABLED(CONFIG_BT_GTBS) && inst == >bs_inst.inst; +} + +static uint8_t inst_index(const struct service_inst *inst) +{ + const struct tbs_service_inst *tbs; + ptrdiff_t index = 0; + + __ASSERT_NO_MSG(inst); + + if (inst_is_gtbs(inst)) { + return BT_TBS_GTBS_INDEX; + } + + tbs = CONTAINER_OF(inst, struct tbs_service_inst, inst); + + index = tbs - svc_insts; + __ASSERT(index >= 0 && index < ARRAY_SIZE(svc_insts), "Invalid tbs_inst pointer"); + + return (uint8_t)index; +} + +static struct service_inst *inst_lookup_index(uint8_t index) +{ + if (IS_ENABLED(CONFIG_BT_GTBS) && index == BT_TBS_GTBS_INDEX) { + return >bs_inst.inst; + } + + if (index < CONFIG_BT_TBS_BEARER_COUNT) { + return &svc_insts[index].inst; + } + + return NULL; +} + static struct bt_tbs_call *lookup_call_in_inst(struct tbs_service_inst *inst, uint8_t call_index) { @@ -151,24 +163,31 @@ static struct bt_tbs_call *lookup_call(uint8_t call_index) return NULL; } -static struct tbs_service_inst *lookup_inst_by_ccc(const struct bt_gatt_attr *ccc) +static bool inst_check_attr(struct service_inst *inst, const struct bt_gatt_attr *attr) +{ + for (size_t j = 0; j < inst->attr_count; j++) { + if (&inst->attrs[j] == attr) { + return true; + } + } + + return false; +} + +static struct service_inst *lookup_inst_by_attr(const struct bt_gatt_attr *attr) { - if (ccc == NULL) { + if (attr == NULL) { return NULL; } for (int i = 0; i < ARRAY_SIZE(svc_insts); i++) { - struct tbs_service_inst *inst = &svc_insts[i]; - - if (inst->service_p == NULL) { - continue; + if (inst_check_attr(&svc_insts[i].inst, attr)) { + return &svc_insts[i].inst; } + } - for (size_t j = 0; j < inst->service_p->attr_count; j++) { - if (inst->service_p->attrs[j].user_data == ccc->user_data) { - return inst; - } - } + if (IS_ENABLED(CONFIG_BT_GTBS) && inst_check_attr(>bs_inst.inst, attr)) { + return >bs_inst.inst; } return NULL; @@ -260,37 +279,22 @@ static struct tbs_service_inst *lookup_inst_by_uri_scheme(const char *uri, return NULL; } -static struct tbs_service_inst *lookup_inst_by_work(const struct k_work *work) -{ - if (work == NULL) { - return NULL; - } - - for (size_t i = 0; i < ARRAY_SIZE(svc_insts); i++) { - if (&svc_insts[i].reporting_interval_work.work == work) { - return &svc_insts[i]; - } - } - - return NULL; -} - static void tbs_set_terminate_reason(struct tbs_service_inst *inst, uint8_t call_index, uint8_t reason) { inst->terminate_reason.call_index = call_index; inst->terminate_reason.reason = reason; - LOG_DBG("Index %u: call index 0x%02x, reason %s", inst->index, call_index, + LOG_DBG("Index %u: call index 0x%02x, reason %s", inst_index(&inst->inst), call_index, bt_tbs_term_reason_str(reason)); bt_gatt_notify_uuid(NULL, BT_UUID_TBS_TERMINATE_REASON, - inst->service_p->attrs, + inst->inst.attrs, (void *)&inst->terminate_reason, sizeof(inst->terminate_reason)); if (IS_ENABLED(CONFIG_BT_GTBS)) { bt_gatt_notify_uuid(NULL, BT_UUID_TBS_TERMINATE_REASON, - gtbs_inst.service_p->attrs, + gtbs_inst.inst.attrs, (void *)&inst->terminate_reason, sizeof(inst->terminate_reason)); } @@ -329,55 +333,47 @@ static uint8_t next_free_call_index(void) return BT_TBS_FREE_CALL_INDEX; } -static void net_buf_put_call_state(const void *inst_p) +static void net_buf_put_call_states_by_inst(const struct tbs_service_inst *inst, + struct net_buf_simple *buf) { const struct bt_tbs_call *call; const struct bt_tbs_call *calls; size_t call_count; - if (inst_p == NULL) { - return; + calls = inst->calls; + call_count = ARRAY_SIZE(inst->calls); + + for (size_t i = 0; i < call_count; i++) { + call = &calls[i]; + if (call->index == BT_TBS_FREE_CALL_INDEX) { + continue; + } + + net_buf_simple_add_u8(buf, call->index); + net_buf_simple_add_u8(buf, call->state); + net_buf_simple_add_u8(buf, call->flags); } +} - net_buf_simple_reset(&read_buf); +static void net_buf_put_call_states(const struct service_inst *inst, struct net_buf_simple *buf) +{ + net_buf_simple_reset(buf); - if (IS_ENABLED(CONFIG_BT_GTBS) && inst_p == >bs_inst) { + if (inst_is_gtbs(inst)) { for (size_t i = 0; i < ARRAY_SIZE(svc_insts); i++) { - calls = svc_insts[i].calls; - call_count = ARRAY_SIZE(svc_insts[i].calls); - - for (size_t j = 0; j < call_count; j++) { - call = &calls[j]; - if (call->index == BT_TBS_FREE_CALL_INDEX) { - continue; - } - - net_buf_simple_add_u8(&read_buf, call->index); - net_buf_simple_add_u8(&read_buf, call->state); - net_buf_simple_add_u8(&read_buf, call->flags); - } - + net_buf_put_call_states_by_inst(&svc_insts[i], buf); } } else { - const struct tbs_service_inst *inst = (struct tbs_service_inst *)inst_p; + struct tbs_service_inst *service_inst; - calls = inst->calls; - call_count = ARRAY_SIZE(inst->calls); + service_inst = CONTAINER_OF(inst, struct tbs_service_inst, inst); - for (int i = 0; i < call_count; i++) { - call = &calls[i]; - if (call->index == BT_TBS_FREE_CALL_INDEX) { - continue; - } - - net_buf_simple_add_u8(&read_buf, call->index); - net_buf_simple_add_u8(&read_buf, call->state); - net_buf_simple_add_u8(&read_buf, call->flags); - } + net_buf_put_call_states_by_inst(service_inst, buf); } } -static void net_buf_put_current_calls(const void *inst_p) +static void net_buf_put_current_calls_by_inst(const struct tbs_service_inst *inst, + struct net_buf_simple *buf) { const struct bt_tbs_call *call; const struct bt_tbs_call *calls; @@ -385,199 +381,139 @@ static void net_buf_put_current_calls(const void *inst_p) size_t uri_length; size_t item_len; - if (inst_p == NULL) { - return; + calls = inst->calls; + call_count = ARRAY_SIZE(inst->calls); + + for (size_t i = 0; i < call_count; i++) { + call = &calls[i]; + if (call->index == BT_TBS_FREE_CALL_INDEX) { + continue; + } + + uri_length = strlen(call->remote_uri); + item_len = sizeof(call->index) + sizeof(call->state) + sizeof(call->flags) + + uri_length; + net_buf_simple_add_u8(buf, item_len); + net_buf_simple_add_u8(buf, call->index); + net_buf_simple_add_u8(buf, call->state); + net_buf_simple_add_u8(buf, call->flags); + net_buf_simple_add_mem(buf, call->remote_uri, uri_length); } +} - net_buf_simple_reset(&read_buf); +static void net_buf_put_current_calls(const struct service_inst *inst, struct net_buf_simple *buf) +{ + net_buf_simple_reset(buf); - if (IS_ENABLED(CONFIG_BT_GTBS) && inst_p == >bs_inst) { + if (inst_is_gtbs(inst)) { for (size_t i = 0; i < ARRAY_SIZE(svc_insts); i++) { - calls = svc_insts[i].calls; - call_count = ARRAY_SIZE(svc_insts[i].calls); - - for (size_t j = 0; j < call_count; j++) { - call = &calls[j]; - if (call->index == BT_TBS_FREE_CALL_INDEX) { - continue; - } - uri_length = strlen(call->remote_uri); - item_len = sizeof(call->index) + sizeof(call->state) + - sizeof(call->flags) + uri_length; - - net_buf_simple_add_u8(&read_buf, item_len); - net_buf_simple_add_u8(&read_buf, call->index); - net_buf_simple_add_u8(&read_buf, call->state); - net_buf_simple_add_u8(&read_buf, call->flags); - net_buf_simple_add_mem(&read_buf, - call->remote_uri, - uri_length); - } - + net_buf_put_current_calls_by_inst(&svc_insts[i], buf); } } else { - const struct tbs_service_inst *inst = (struct tbs_service_inst *)inst_p; + struct tbs_service_inst *service_inst; - calls = inst->calls; - call_count = ARRAY_SIZE(inst->calls); + service_inst = CONTAINER_OF(inst, struct tbs_service_inst, inst); - for (size_t i = 0; i < call_count; i++) { - call = &calls[i]; - if (call->index == BT_TBS_FREE_CALL_INDEX) { - continue; - } - - uri_length = strlen(call->remote_uri); - item_len = sizeof(call->index) + sizeof(call->state) + - sizeof(call->flags) + uri_length; - net_buf_simple_add_u8(&read_buf, item_len); - net_buf_simple_add_u8(&read_buf, call->index); - net_buf_simple_add_u8(&read_buf, call->state); - net_buf_simple_add_u8(&read_buf, call->flags); - net_buf_simple_add_mem(&read_buf, call->remote_uri, - uri_length); - } + net_buf_put_current_calls_by_inst(service_inst, buf); } } -static int notify_calls(const struct tbs_service_inst *inst) +static int inst_notify_calls(const struct service_inst *inst) { - int err = 0; - - if (inst == NULL) { - return -EINVAL; - } + int err; - if (IS_ENABLED(CONFIG_BT_GTBS)) { - if (gtbs_inst.notify_call_states) { - net_buf_put_call_state(>bs_inst); - - err = bt_gatt_notify_uuid(NULL, BT_UUID_TBS_CALL_STATE, - gtbs_inst.service_p->attrs, - read_buf.data, read_buf.len); - if (err != 0) { - return err; - } - } - - if (gtbs_inst.notify_current_calls) { - net_buf_put_current_calls(>bs_inst); + if (inst->notify_call_states) { + net_buf_put_call_states(inst, &read_buf); - err = bt_gatt_notify_uuid( - NULL, BT_UUID_TBS_LIST_CURRENT_CALLS, - gtbs_inst.service_p->attrs, - read_buf.data, read_buf.len); - if (err != 0) { - return err; - } + err = bt_gatt_notify_uuid(NULL, BT_UUID_TBS_CALL_STATE, inst->attrs, + read_buf.data, read_buf.len); + if (err != 0) { + return err; } } - if (inst->notify_call_states) { - net_buf_put_call_state(inst); + if (inst->notify_current_calls) { + net_buf_put_current_calls(inst, &read_buf); - err = bt_gatt_notify_uuid(NULL, BT_UUID_TBS_CALL_STATE, - inst->service_p->attrs, + err = bt_gatt_notify_uuid(NULL, BT_UUID_TBS_LIST_CURRENT_CALLS, inst->attrs, read_buf.data, read_buf.len); if (err != 0) { return err; } } - if (inst->notify_current_calls) { - net_buf_put_current_calls(inst); - err = bt_gatt_notify_uuid(NULL, BT_UUID_TBS_LIST_CURRENT_CALLS, - inst->service_p->attrs, - read_buf.data, read_buf.len); + return 0; +} + +static int notify_calls(const struct tbs_service_inst *inst) +{ + if (inst == NULL) { + return -EINVAL; + } + + if (IS_ENABLED(CONFIG_BT_GTBS)) { + int err; + + err = inst_notify_calls(>bs_inst.inst); if (err != 0) { return err; } } - return err; + return inst_notify_calls(&inst->inst); } static ssize_t read_provider_name(struct bt_conn *conn, const struct bt_gatt_attr *attr, void *buf, uint16_t len, uint16_t offset) { - const char *provider_name; + const struct service_inst *inst = BT_AUDIO_CHRC_USER_DATA(attr); - if (IS_GTBS_CHRC(attr)) { - provider_name = gtbs_inst.provider_name; - LOG_DBG("GTBS: Provider name %s", provider_name); - } else { - const struct tbs_service_inst *inst = BT_AUDIO_CHRC_USER_DATA(attr); - - provider_name = inst->provider_name; - LOG_DBG("Index %u, Provider name %s", inst->index, provider_name); - } + LOG_DBG("Index %u, Provider name %s", inst_index(inst), inst->provider_name); return bt_gatt_attr_read(conn, attr, buf, len, offset, - provider_name, - strlen(provider_name)); + inst->provider_name, strlen(inst->provider_name)); } static void provider_name_cfg_changed(const struct bt_gatt_attr *attr, uint16_t value) { - const struct tbs_service_inst *inst = lookup_inst_by_ccc(attr); + const struct service_inst *inst = lookup_inst_by_attr(attr); if (inst != NULL) { - LOG_DBG("Index %u: value 0x%04x", inst->index, value); - } else if (IS_ENABLED(CONFIG_BT_GTBS)) { - LOG_DBG("GTBS: value 0x%04x", value); + LOG_DBG("Index %u: value 0x%04x", inst_index(inst), value); } } static ssize_t read_uci(struct bt_conn *conn, const struct bt_gatt_attr *attr, void *buf, uint16_t len, uint16_t offset) { - const char *uci; + const struct service_inst *inst = BT_AUDIO_CHRC_USER_DATA(attr); - if (IS_GTBS_CHRC(attr)) { - uci = gtbs_inst.uci; - LOG_DBG("GTBS: UCI %s", uci); - } else { - const struct tbs_service_inst *inst = BT_AUDIO_CHRC_USER_DATA(attr); + LOG_DBG("Index %u: UCI %s", inst_index(inst), inst->uci); - uci = inst->uci; - LOG_DBG("Index %u: UCI %s", inst->index, uci); - } - - return bt_gatt_attr_read(conn, attr, buf, len, offset, - uci, strlen(uci)); + return bt_gatt_attr_read(conn, attr, buf, len, offset, inst->uci, strlen(inst->uci)); } static ssize_t read_technology(struct bt_conn *conn, const struct bt_gatt_attr *attr, void *buf, uint16_t len, uint16_t offset) { - uint8_t technology; - - if (IS_GTBS_CHRC(attr)) { - technology = gtbs_inst.technology; - LOG_DBG("GTBS: Technology 0x%02X", technology); - } else { - const struct tbs_service_inst *inst = BT_AUDIO_CHRC_USER_DATA(attr); + const struct service_inst *inst = BT_AUDIO_CHRC_USER_DATA(attr); - technology = inst->technology; - LOG_DBG("Index %u: Technology 0x%02X", inst->index, technology); - } + LOG_DBG("Index %u: Technology 0x%02x", inst_index(inst), inst->technology); return bt_gatt_attr_read(conn, attr, buf, len, offset, - &technology, sizeof(technology)); + &inst->technology, sizeof(inst->technology)); } static void technology_cfg_changed(const struct bt_gatt_attr *attr, uint16_t value) { - const struct tbs_service_inst *inst = lookup_inst_by_ccc(attr); + const struct service_inst *inst = lookup_inst_by_attr(attr); if (inst != NULL) { - LOG_DBG("Index %u: value 0x%04x", inst->index, value); - } else if (IS_ENABLED(CONFIG_BT_GTBS)) { - LOG_DBG("GTBS: value 0x%04x", value); + LOG_DBG("Index %u: value 0x%04x", inst_index(inst), value); } } @@ -585,9 +521,11 @@ static ssize_t read_uri_scheme_list(struct bt_conn *conn, const struct bt_gatt_attr *attr, void *buf, uint16_t len, uint16_t offset) { + const struct service_inst *inst_p = BT_AUDIO_CHRC_USER_DATA(attr); + net_buf_simple_reset(&read_buf); - if (IS_GTBS_CHRC(attr)) { + if (inst_is_gtbs(inst_p)) { /* TODO: Make uri schemes unique */ for (size_t i = 0; i < ARRAY_SIZE(svc_insts); i++) { size_t uri_len = strlen(svc_insts[i].uri_scheme_list); @@ -605,12 +543,15 @@ static ssize_t read_uri_scheme_list(struct bt_conn *conn, LOG_DBG("GTBS: URI scheme %.*s", read_buf.len, read_buf.data); } else { - const struct tbs_service_inst *inst = BT_AUDIO_CHRC_USER_DATA(attr); + const struct tbs_service_inst *inst; + + inst = CONTAINER_OF(inst_p, struct tbs_service_inst, inst); net_buf_simple_add_mem(&read_buf, inst->uri_scheme_list, strlen(inst->uri_scheme_list)); - LOG_DBG("Index %u: URI scheme %.*s", inst->index, read_buf.len, read_buf.data); + LOG_DBG("Index %u: URI scheme %.*s", + inst_index(inst_p), read_buf.len, read_buf.data); } return bt_gatt_attr_read(conn, attr, buf, len, offset, @@ -620,12 +561,10 @@ static ssize_t read_uri_scheme_list(struct bt_conn *conn, static void uri_scheme_list_cfg_changed(const struct bt_gatt_attr *attr, uint16_t value) { - const struct tbs_service_inst *inst = lookup_inst_by_ccc(attr); + const struct service_inst *inst = lookup_inst_by_attr(attr); if (inst != NULL) { - LOG_DBG("Index %u: value 0x%04x", inst->index, value); - } else if (IS_ENABLED(CONFIG_BT_GTBS)) { - LOG_DBG("GTBS: value 0x%04x", value); + LOG_DBG("Index %u: value 0x%04x", inst_index(inst), value); } } @@ -633,31 +572,21 @@ static ssize_t read_signal_strength(struct bt_conn *conn, const struct bt_gatt_attr *attr, void *buf, uint16_t len, uint16_t offset) { - uint8_t signal_strength; + const struct service_inst *inst = BT_AUDIO_CHRC_USER_DATA(attr); - if (IS_GTBS_CHRC(attr)) { - signal_strength = gtbs_inst.signal_strength; - LOG_DBG("GTBS: Signal strength 0x%02x", signal_strength); - } else { - const struct tbs_service_inst *inst = BT_AUDIO_CHRC_USER_DATA(attr); - - signal_strength = inst->signal_strength; - LOG_DBG("Index %u: Signal strength 0x%02x", inst->index, signal_strength); - } + LOG_DBG("Index %u: Signal strength 0x%02x", inst_index(inst), inst->signal_strength); return bt_gatt_attr_read(conn, attr, buf, len, offset, - &signal_strength, sizeof(signal_strength)); + &inst->signal_strength, sizeof(inst->signal_strength)); } static void signal_strength_cfg_changed(const struct bt_gatt_attr *attr, uint16_t value) { - const struct tbs_service_inst *inst = lookup_inst_by_ccc(attr); + const struct service_inst *inst = lookup_inst_by_attr(attr); if (inst != NULL) { - LOG_DBG("Index %u: value 0x%04x", inst->index, value); - } else if (IS_ENABLED(CONFIG_BT_GTBS)) { - LOG_DBG("GTBS: value 0x%04x", value); + LOG_DBG("Index %u: value 0x%04x", inst_index(inst), value); } } @@ -666,26 +595,18 @@ static ssize_t read_signal_strength_interval(struct bt_conn *conn, void *buf, uint16_t len, uint16_t offset) { - uint8_t signal_strength_interval; + const struct service_inst *inst = BT_AUDIO_CHRC_USER_DATA(attr); if (!is_authorized(conn)) { return BT_GATT_ERR(BT_ATT_ERR_AUTHORIZATION); } - if (IS_GTBS_CHRC(attr)) { - signal_strength_interval = gtbs_inst.signal_strength_interval; - LOG_DBG("GTBS: Signal strength interval 0x%02x", signal_strength_interval); - } else { - const struct tbs_service_inst *inst = BT_AUDIO_CHRC_USER_DATA(attr); - - signal_strength_interval = inst->signal_strength_interval; - LOG_DBG("Index %u: Signal strength interval 0x%02x", inst->index, - signal_strength_interval); - } + LOG_DBG("Index %u: Signal strength interval 0x%02x", + inst_index(inst), inst->signal_strength_interval); return bt_gatt_attr_read(conn, attr, buf, len, offset, - &signal_strength_interval, - sizeof(signal_strength_interval)); + &inst->signal_strength_interval, + sizeof(inst->signal_strength_interval)); } static ssize_t write_signal_strength_interval(struct bt_conn *conn, @@ -693,6 +614,7 @@ static ssize_t write_signal_strength_interval(struct bt_conn *conn, const void *buf, uint16_t len, uint16_t offset, uint8_t flags) { + struct service_inst *inst = BT_AUDIO_CHRC_USER_DATA(attr); struct net_buf_simple net_buf; uint8_t signal_strength_interval; @@ -711,15 +633,8 @@ static ssize_t write_signal_strength_interval(struct bt_conn *conn, net_buf_simple_init_with_data(&net_buf, (void *)buf, len); signal_strength_interval = net_buf_simple_pull_u8(&net_buf); - if (IS_GTBS_CHRC(attr)) { - gtbs_inst.signal_strength_interval = signal_strength_interval; - LOG_DBG("GTBS: 0x%02x", signal_strength_interval); - } else { - struct tbs_service_inst *inst = BT_AUDIO_CHRC_USER_DATA(attr); - - inst->signal_strength_interval = signal_strength_interval; - LOG_DBG("Index %u: 0x%02x", inst->index, signal_strength_interval); - } + inst->signal_strength_interval = signal_strength_interval; + LOG_DBG("Index %u: 0x%02x", inst_index(inst), signal_strength_interval); return len; } @@ -727,14 +642,11 @@ static ssize_t write_signal_strength_interval(struct bt_conn *conn, static void current_calls_cfg_changed(const struct bt_gatt_attr *attr, uint16_t value) { - struct tbs_service_inst *inst = lookup_inst_by_ccc(attr); + struct service_inst *inst = lookup_inst_by_attr(attr); if (inst != NULL) { - LOG_DBG("Index %u: value 0x%04x", inst->index, value); + LOG_DBG("Index %u: value 0x%04x", inst_index(inst), value); inst->notify_current_calls = (value == BT_GATT_CCC_NOTIFY); - } else if (IS_ENABLED(CONFIG_BT_GTBS)) { - LOG_DBG("GTBS: value 0x%04x", value); - gtbs_inst.notify_current_calls = (value == BT_GATT_CCC_NOTIFY); } } @@ -742,15 +654,11 @@ static ssize_t read_current_calls(struct bt_conn *conn, const struct bt_gatt_attr *attr, void *buf, uint16_t len, uint16_t offset) { - net_buf_put_current_calls(BT_AUDIO_CHRC_USER_DATA(attr)); + const struct service_inst *inst = BT_AUDIO_CHRC_USER_DATA(attr); - if (IS_GTBS_CHRC(attr)) { - LOG_DBG("GTBS"); - } else { - const struct tbs_service_inst *inst = BT_AUDIO_CHRC_USER_DATA(attr); + LOG_DBG("Index %u", inst_index(inst)); - LOG_DBG("Index %u", inst->index); - } + net_buf_put_current_calls(inst, &read_buf); if (offset == 0) { LOG_HEXDUMP_DBG(read_buf.data, read_buf.len, "Current calls"); @@ -764,51 +672,32 @@ static ssize_t read_ccid(struct bt_conn *conn, const struct bt_gatt_attr *attr, void *buf, uint16_t len, uint16_t offset) { - uint8_t ccid; - - if (IS_GTBS_CHRC(attr)) { - ccid = gtbs_inst.ccid; - LOG_DBG("GTBS: CCID 0x%02X", ccid); - } else { - const struct tbs_service_inst *inst = BT_AUDIO_CHRC_USER_DATA(attr); + const struct service_inst *inst = BT_AUDIO_CHRC_USER_DATA(attr); - ccid = inst->ccid; - LOG_DBG("Index %u: CCID 0x%02X", inst->index, ccid); - } + LOG_DBG("Index %u: CCID 0x%02x", inst_index(inst), inst->ccid); - return bt_gatt_attr_read(conn, attr, buf, len, offset, - &ccid, sizeof(ccid)); + return bt_gatt_attr_read(conn, attr, buf, len, offset, &inst->ccid, sizeof(inst->ccid)); } static ssize_t read_status_flags(struct bt_conn *conn, const struct bt_gatt_attr *attr, void *buf, uint16_t len, uint16_t offset) { - uint16_t status_flags; - - if (IS_GTBS_CHRC(attr)) { - status_flags = gtbs_inst.status_flags; - LOG_DBG("GTBS: status_flags 0x%04X", status_flags); - } else { - const struct tbs_service_inst *inst = BT_AUDIO_CHRC_USER_DATA(attr); + const struct service_inst *inst = BT_AUDIO_CHRC_USER_DATA(attr); - status_flags = inst->status_flags; - LOG_DBG("Index %u: status_flags 0x%04X", inst->index, status_flags); - } + LOG_DBG("Index %u: status_flags 0x%04x", inst_index(inst), inst->status_flags); return bt_gatt_attr_read(conn, attr, buf, len, offset, - &status_flags, sizeof(status_flags)); + &inst->status_flags, sizeof(inst->status_flags)); } static void status_flags_cfg_changed(const struct bt_gatt_attr *attr, uint16_t value) { - const struct tbs_service_inst *inst = lookup_inst_by_ccc(attr); + const struct service_inst *inst = lookup_inst_by_attr(attr); if (inst != NULL) { - LOG_DBG("Index %u: value 0x%04x", inst->index, value); - } else if (IS_ENABLED(CONFIG_BT_GTBS)) { - LOG_DBG("GTBS: value 0x%04x", value); + LOG_DBG("Index %u: value 0x%04x", inst_index(inst), value); } } @@ -817,20 +706,14 @@ static ssize_t read_incoming_uri(struct bt_conn *conn, void *buf, uint16_t len, uint16_t offset) { + const struct service_inst *inst = BT_AUDIO_CHRC_USER_DATA(attr); const struct bt_tbs_in_uri *inc_call_target; size_t val_len; - if (IS_GTBS_CHRC(attr)) { - inc_call_target = >bs_inst.incoming_uri; - LOG_DBG("GTBS: call index 0x%02X, URI %s", inc_call_target->call_index, - inc_call_target->uri); - } else { - const struct tbs_service_inst *inst = BT_AUDIO_CHRC_USER_DATA(attr); + inc_call_target = &inst->incoming_uri; - inc_call_target = &inst->incoming_uri; - LOG_DBG("Index %u: call index 0x%02X, URI %s", inst->index, - inc_call_target->call_index, inc_call_target->uri); - } + LOG_DBG("Index %u: call index 0x%02x, URI %s", inst_index(inst), + inc_call_target->call_index, inc_call_target->uri); if (!inc_call_target->call_index) { LOG_DBG("URI not set"); @@ -848,12 +731,10 @@ static ssize_t read_incoming_uri(struct bt_conn *conn, static void incoming_uri_cfg_changed(const struct bt_gatt_attr *attr, uint16_t value) { - const struct tbs_service_inst *inst = lookup_inst_by_ccc(attr); + const struct service_inst *inst = lookup_inst_by_attr(attr); if (inst != NULL) { - LOG_DBG("Index %u: value 0x%04x", inst->index, value); - } else if (IS_ENABLED(CONFIG_BT_GTBS)) { - LOG_DBG("GTBS: value 0x%04x", value); + LOG_DBG("Index %u: value 0x%04x", inst_index(inst), value); } } @@ -861,15 +742,11 @@ static ssize_t read_call_state(struct bt_conn *conn, const struct bt_gatt_attr *attr, void *buf, uint16_t len, uint16_t offset) { - net_buf_put_call_state(BT_AUDIO_CHRC_USER_DATA(attr)); + const struct service_inst *inst = BT_AUDIO_CHRC_USER_DATA(attr); - if (IS_GTBS_CHRC(attr)) { - LOG_DBG("GTBS"); - } else { - const struct tbs_service_inst *inst = BT_AUDIO_CHRC_USER_DATA(attr); + LOG_DBG("Index %u", inst_index(inst)); - LOG_DBG("Index %u", inst->index); - } + net_buf_put_call_states(inst, &read_buf); if (offset == 0) { LOG_HEXDUMP_DBG(read_buf.data, read_buf.len, "Call state"); @@ -882,14 +759,11 @@ static ssize_t read_call_state(struct bt_conn *conn, static void call_state_cfg_changed(const struct bt_gatt_attr *attr, uint16_t value) { - struct tbs_service_inst *inst = lookup_inst_by_ccc(attr); + struct service_inst *inst = lookup_inst_by_attr(attr); if (inst != NULL) { - LOG_DBG("Index %u: value 0x%04x", inst->index, value); + LOG_DBG("Index %u: value 0x%04x", inst_index(inst), value); inst->notify_call_states = (value == BT_GATT_CCC_NOTIFY); - } else if (IS_ENABLED(CONFIG_BT_GTBS)) { - LOG_DBG("GTBS: value 0x%04x", value); - gtbs_inst.notify_call_states = (value == BT_GATT_CCC_NOTIFY); } } @@ -982,7 +856,7 @@ static uint8_t tbs_hold_call(struct tbs_service_inst *inst, { struct bt_tbs_call *call = lookup_call_in_inst(inst, ccp->call_index); - if ((inst->optional_opcodes & BT_TBS_FEATURE_HOLD) == 0) { + if ((inst->inst.optional_opcodes & BT_TBS_FEATURE_HOLD) == 0) { return BT_TBS_RESULT_CODE_OPCODE_NOT_SUPPORTED; } @@ -1008,7 +882,7 @@ static uint8_t retrieve_call(struct tbs_service_inst *inst, { struct bt_tbs_call *call = lookup_call_in_inst(inst, ccp->call_index); - if ((inst->optional_opcodes & BT_TBS_FEATURE_HOLD) == 0) { + if ((inst->inst.optional_opcodes & BT_TBS_FEATURE_HOLD) == 0) { return BT_TBS_RESULT_CODE_OPCODE_NOT_SUPPORTED; } @@ -1101,7 +975,7 @@ static uint8_t join_calls(struct tbs_service_inst *inst, struct bt_tbs_call *joined_calls[CONFIG_BT_TBS_MAX_CALLS]; uint8_t call_state; - if ((inst->optional_opcodes & BT_TBS_FEATURE_JOIN) == 0) { + if ((inst->inst.optional_opcodes & BT_TBS_FEATURE_JOIN) == 0) { return BT_TBS_RESULT_CODE_OPCODE_NOT_SUPPORTED; } @@ -1200,7 +1074,7 @@ static void notify_app(struct bt_conn *conn, struct tbs_service_inst *inst, uint call = lookup_call_in_inst(inst, call_index); if (call == NULL) { - LOG_DBG("Could not find call by call index 0x%02X", call_index); + LOG_DBG("Could not find call by call index 0x%02x", call_index); break; } @@ -1256,11 +1130,12 @@ static ssize_t write_call_cp(struct bt_conn *conn, const void *buf, uint16_t len, uint16_t offset, uint8_t flags) { - struct tbs_service_inst *inst = NULL; + struct service_inst *inst = BT_AUDIO_CHRC_USER_DATA(attr); const union bt_tbs_call_cp_t *ccp = (union bt_tbs_call_cp_t *)buf; + struct tbs_service_inst *tbs = NULL; uint8_t status; uint8_t call_index = 0; - const bool is_gtbs = IS_GTBS_CHRC(attr); + const bool is_gtbs = inst_is_gtbs(inst); if (!is_authorized(conn)) { return BT_GATT_ERR(BT_ATT_ERR_AUTHORIZATION); @@ -1274,14 +1149,8 @@ static ssize_t write_call_cp(struct bt_conn *conn, return BT_GATT_ERR(BT_ATT_ERR_INVALID_ATTRIBUTE_LEN); } - if (is_gtbs) { - LOG_DBG("GTBS: Processing the %s opcode", bt_tbs_opcode_str(ccp->opcode)); - } else { - inst = BT_AUDIO_CHRC_USER_DATA(attr); - - LOG_DBG("Index %u: Processing the %s opcode", inst->index, - bt_tbs_opcode_str(ccp->opcode)); - } + LOG_DBG("Index %u: Processing the %s opcode", + inst_index(inst), bt_tbs_opcode_str(ccp->opcode)); switch (ccp->opcode) { case BT_TBS_CALL_OPCODE_ACCEPT: @@ -1292,14 +1161,16 @@ static ssize_t write_call_cp(struct bt_conn *conn, call_index = ccp->accept.call_index; if (is_gtbs) { - inst = lookup_inst_by_call_index(call_index); - if (inst == NULL) { + tbs = lookup_inst_by_call_index(call_index); + if (tbs == NULL) { status = BT_TBS_RESULT_CODE_INVALID_CALL_INDEX; break; } + } else { + tbs = CONTAINER_OF(inst, struct tbs_service_inst, inst); } - status = accept_call(inst, &ccp->accept); + status = accept_call(tbs, &ccp->accept); break; case BT_TBS_CALL_OPCODE_TERMINATE: if (len != sizeof(ccp->terminate)) { @@ -1309,15 +1180,16 @@ static ssize_t write_call_cp(struct bt_conn *conn, call_index = ccp->terminate.call_index; if (is_gtbs) { - inst = lookup_inst_by_call_index(call_index); - if (inst == NULL) { + tbs = lookup_inst_by_call_index(call_index); + if (tbs == NULL) { status = BT_TBS_RESULT_CODE_INVALID_CALL_INDEX; break; } + } else { + tbs = CONTAINER_OF(inst, struct tbs_service_inst, inst); } - status = terminate_call(inst, &ccp->terminate, - BT_TBS_REASON_CLIENT_TERMINATED); + status = terminate_call(tbs, &ccp->terminate, BT_TBS_REASON_CLIENT_TERMINATED); break; case BT_TBS_CALL_OPCODE_HOLD: if (len != sizeof(ccp->hold)) { @@ -1327,14 +1199,16 @@ static ssize_t write_call_cp(struct bt_conn *conn, call_index = ccp->hold.call_index; if (is_gtbs) { - inst = lookup_inst_by_call_index(call_index); - if (inst == NULL) { + tbs = lookup_inst_by_call_index(call_index); + if (tbs == NULL) { status = BT_TBS_RESULT_CODE_INVALID_CALL_INDEX; break; } + } else { + tbs = CONTAINER_OF(inst, struct tbs_service_inst, inst); } - status = tbs_hold_call(inst, &ccp->hold); + status = tbs_hold_call(tbs, &ccp->hold); break; case BT_TBS_CALL_OPCODE_RETRIEVE: if (len != sizeof(ccp->retrieve)) { @@ -1344,14 +1218,16 @@ static ssize_t write_call_cp(struct bt_conn *conn, call_index = ccp->retrieve.call_index; if (is_gtbs) { - inst = lookup_inst_by_call_index(call_index); - if (inst == NULL) { + tbs = lookup_inst_by_call_index(call_index); + if (tbs == NULL) { status = BT_TBS_RESULT_CODE_INVALID_CALL_INDEX; break; } + } else { + tbs = CONTAINER_OF(inst, struct tbs_service_inst, inst); } - status = retrieve_call(inst, &ccp->retrieve); + status = retrieve_call(tbs, &ccp->retrieve); break; case BT_TBS_CALL_OPCODE_ORIGINATE: { @@ -1362,20 +1238,20 @@ static ssize_t write_call_cp(struct bt_conn *conn, } if (is_gtbs) { - inst = lookup_inst_by_uri_scheme(ccp->originate.uri, - uri_len); - if (inst == NULL) { + tbs = lookup_inst_by_uri_scheme(ccp->originate.uri, uri_len); + if (tbs == NULL) { /* TODO: Couldn't find fitting TBS instance; * use the first. If we want to be * restrictive about URIs, return * Invalid Caller ID instead */ - inst = &svc_insts[0]; + tbs = &svc_insts[0]; } + } else { + tbs = CONTAINER_OF(inst, struct tbs_service_inst, inst); } - status = originate_call(inst, &ccp->originate, uri_len, - &call_index); + status = originate_call(tbs, &ccp->originate, uri_len, &call_index); break; } case BT_TBS_CALL_OPCODE_JOIN: @@ -1389,14 +1265,16 @@ static ssize_t write_call_cp(struct bt_conn *conn, call_index = ccp->join.call_indexes[0]; if (is_gtbs) { - inst = lookup_inst_by_call_index(call_index); - if (inst == NULL) { + tbs = lookup_inst_by_call_index(call_index); + if (tbs == NULL) { status = BT_TBS_RESULT_CODE_INVALID_CALL_INDEX; break; } + } else { + tbs = CONTAINER_OF(inst, struct tbs_service_inst, inst); } - status = join_calls(inst, &ccp->join, call_index_cnt); + status = join_calls(tbs, &ccp->join, call_index_cnt); break; } default: @@ -1405,21 +1283,10 @@ static ssize_t write_call_cp(struct bt_conn *conn, break; } - if (inst != NULL) { - if (is_gtbs) { - LOG_DBG("GTBS: Processed the %s opcode with status %s " - "for call index %u", - bt_tbs_opcode_str(ccp->opcode), - bt_tbs_status_str(status), - call_index); - } else { - LOG_DBG("Index %u: Processed the %s opcode with status " - "%s for call index %u", - inst->index, - bt_tbs_opcode_str(ccp->opcode), - bt_tbs_status_str(status), - call_index); - } + if (tbs != NULL) { + LOG_DBG("Index %u: Processed the %s opcode with status %s for call index %u", + inst_index(inst), bt_tbs_opcode_str(ccp->opcode), bt_tbs_status_str(status), + call_index); if (status == BT_TBS_RESULT_CODE_SUCCESS) { const struct bt_tbs_call *call = lookup_call(call_index); @@ -1441,9 +1308,9 @@ static ssize_t write_call_cp(struct bt_conn *conn, notify_ccp(conn, attr, call_index, ccp->opcode, status); } /* else local operation; don't notify */ - if (inst != NULL && status == BT_TBS_RESULT_CODE_SUCCESS) { - notify_calls(inst); - notify_app(conn, inst, len, ccp, status, call_index); + if (tbs != NULL && status == BT_TBS_RESULT_CODE_SUCCESS) { + notify_calls(tbs); + notify_app(conn, tbs, len, ccp, status, call_index); } return len; @@ -1451,12 +1318,10 @@ static ssize_t write_call_cp(struct bt_conn *conn, static void call_cp_cfg_changed(const struct bt_gatt_attr *attr, uint16_t value) { - const struct tbs_service_inst *inst = lookup_inst_by_ccc(attr); + const struct service_inst *inst = lookup_inst_by_attr(attr); if (inst != NULL) { - LOG_DBG("Index %u: value 0x%04x", inst->index, value); - } else if (IS_ENABLED(CONFIG_BT_GTBS)) { - LOG_DBG("GTBS: value 0x%04x", value); + LOG_DBG("Index %u: value 0x%04x", inst_index(inst), value); } } @@ -1464,31 +1329,21 @@ static ssize_t read_optional_opcodes(struct bt_conn *conn, const struct bt_gatt_attr *attr, void *buf, uint16_t len, uint16_t offset) { - uint16_t optional_opcodes; + const struct service_inst *inst = BT_AUDIO_CHRC_USER_DATA(attr); - if (IS_GTBS_CHRC(attr)) { - optional_opcodes = gtbs_inst.optional_opcodes; - LOG_DBG("GTBS: Supported opcodes 0x%02x", optional_opcodes); - } else { - const struct tbs_service_inst *inst = BT_AUDIO_CHRC_USER_DATA(attr); - - optional_opcodes = inst->optional_opcodes; - LOG_DBG("Index %u: Supported opcodes 0x%02x", inst->index, optional_opcodes); - } + LOG_DBG("Index %u: Supported opcodes 0x%02x", inst_index(inst), inst->optional_opcodes); return bt_gatt_attr_read(conn, attr, buf, len, offset, - &optional_opcodes, sizeof(optional_opcodes)); + &inst->optional_opcodes, sizeof(inst->optional_opcodes)); } static void terminate_reason_cfg_changed(const struct bt_gatt_attr *attr, uint16_t value) { - const struct tbs_service_inst *inst = lookup_inst_by_ccc(attr); + const struct service_inst *inst = lookup_inst_by_attr(attr); if (inst != NULL) { - LOG_DBG("Index %u: value 0x%04x", inst->index, value); - } else if (IS_ENABLED(CONFIG_BT_GTBS)) { - LOG_DBG("GTBS: value 0x%04x", value); + LOG_DBG("Index %u: value 0x%04x", inst_index(inst), value); } } @@ -1496,20 +1351,12 @@ static ssize_t read_friendly_name(struct bt_conn *conn, const struct bt_gatt_attr *attr, void *buf, uint16_t len, uint16_t offset) { - const struct bt_tbs_in_uri *friendly_name; + const struct service_inst *inst = BT_AUDIO_CHRC_USER_DATA(attr); + const struct bt_tbs_in_uri *friendly_name = &inst->friendly_name; size_t val_len; - if (IS_GTBS_CHRC(attr)) { - friendly_name = >bs_inst.friendly_name; - LOG_DBG("GTBS: call index 0x%02X, URI %s", friendly_name->call_index, - friendly_name->uri); - } else { - const struct tbs_service_inst *inst = BT_AUDIO_CHRC_USER_DATA(attr); - - friendly_name = &inst->friendly_name; - LOG_DBG("Index %u: call index 0x%02X, URI %s", inst->index, - friendly_name->call_index, friendly_name->uri); - } + LOG_DBG("Index: 0x%02x call index 0x%02x, URI %s", + inst_index(inst), friendly_name->call_index, friendly_name->uri); if (friendly_name->call_index == BT_TBS_FREE_CALL_INDEX) { LOG_DBG("URI not set"); @@ -1526,12 +1373,10 @@ static ssize_t read_friendly_name(struct bt_conn *conn, static void friendly_name_cfg_changed(const struct bt_gatt_attr *attr, uint16_t value) { - const struct tbs_service_inst *inst = lookup_inst_by_ccc(attr); + const struct service_inst *inst = lookup_inst_by_attr(attr); if (inst != NULL) { - LOG_DBG("Index %u: value 0x%04x", inst->index, value); - } else if (IS_ENABLED(CONFIG_BT_GTBS)) { - LOG_DBG("GTBS: value 0x%04x", value); + LOG_DBG("Index %u: value 0x%04x", inst_index(inst), value); } } @@ -1539,19 +1384,12 @@ static ssize_t read_incoming_call(struct bt_conn *conn, const struct bt_gatt_attr *attr, void *buf, uint16_t len, uint16_t offset) { - const struct bt_tbs_in_uri *remote_uri; + const struct service_inst *inst = BT_AUDIO_CHRC_USER_DATA(attr); + const struct bt_tbs_in_uri *remote_uri = &inst->in_call; size_t val_len; - if (IS_GTBS_CHRC(attr)) { - remote_uri = >bs_inst.in_call; - LOG_DBG("GTBS: call index 0x%02X, URI %s", remote_uri->call_index, remote_uri->uri); - } else { - const struct tbs_service_inst *inst = BT_AUDIO_CHRC_USER_DATA(attr); - - remote_uri = &inst->in_call; - LOG_DBG("Index %u: call index 0x%02X, URI %s", inst->index, remote_uri->call_index, - remote_uri->uri); - } + LOG_DBG("Index: 0x%02x call index 0x%02x, URI %s", + inst_index(inst), remote_uri->call_index, remote_uri->uri); if (remote_uri->call_index == BT_TBS_FREE_CALL_INDEX) { LOG_DBG("URI not set"); @@ -1568,12 +1406,10 @@ static ssize_t read_incoming_call(struct bt_conn *conn, static void in_call_cfg_changed(const struct bt_gatt_attr *attr, uint16_t value) { - const struct tbs_service_inst *inst = lookup_inst_by_ccc(attr); + const struct service_inst *inst = lookup_inst_by_attr(attr); if (inst != NULL) { - LOG_DBG("Index %u: value 0x%04x", inst->index, value); - } else if (IS_ENABLED(CONFIG_BT_GTBS)) { - LOG_DBG("GTBS: value 0x%04x", value); + LOG_DBG("Index %u: value 0x%04x", inst_index(inst), value); } } @@ -1704,7 +1540,7 @@ static void in_call_cfg_changed(const struct bt_gatt_attr *attr, BT_TBS_CHR_INCOMING_CALL(_inst), \ BT_TBS_CHR_FRIENDLY_NAME(_inst) -#define BT_TBS_SERVICE_DEFINITION(_inst) { BT_TBS_SERVICE_DEFINE(BT_UUID_TBS, &(_inst)) } +#define BT_TBS_SERVICE_DEFINITION(_inst) { BT_TBS_SERVICE_DEFINE(BT_UUID_TBS, &(_inst).inst) } /* * Defining this as extern make it possible to link code that otherwise would @@ -1714,7 +1550,7 @@ extern const struct bt_gatt_service_static gtbs_svc; /* TODO: Can we make the multiple service instance more generic? */ #if CONFIG_BT_GTBS -BT_GATT_SERVICE_DEFINE(gtbs_svc, BT_TBS_SERVICE_DEFINE(BT_UUID_GTBS, >bs_inst)); +BT_GATT_SERVICE_DEFINE(gtbs_svc, BT_TBS_SERVICE_DEFINE(BT_UUID_GTBS, >bs_inst.inst)); #endif /* CONFIG_BT_GTBS */ BT_GATT_SERVICE_INSTANCE_DEFINE(tbs_service_list, svc_insts, CONFIG_BT_TBS_BEARER_COUNT, @@ -1722,37 +1558,54 @@ BT_GATT_SERVICE_INSTANCE_DEFINE(tbs_service_list, svc_insts, CONFIG_BT_TBS_BEARE static void signal_interval_timeout(struct k_work *work) { - struct tbs_service_inst *inst = lookup_inst_by_work(work); + struct k_work_delayable *dwork = k_work_delayable_from_work(work); + struct service_inst *inst = CONTAINER_OF(dwork, struct service_inst, + reporting_interval_work); + + if (!inst->pending_signal_strength_notification) { + return; + } - if (inst && inst->pending_signal_strength_notification) { - bt_gatt_notify_uuid(NULL, BT_UUID_TBS_SIGNAL_STRENGTH, - inst->service_p->attrs, - &inst->signal_strength, - sizeof(inst->signal_strength)); + bt_gatt_notify_uuid(NULL, BT_UUID_TBS_SIGNAL_STRENGTH, inst->attrs, &inst->signal_strength, + sizeof(inst->signal_strength)); - if (inst->signal_strength_interval) { - k_work_reschedule( - &inst->reporting_interval_work, - K_SECONDS(inst->signal_strength_interval)); - } + if (inst->signal_strength_interval) { + k_work_reschedule(&inst->reporting_interval_work, + K_SECONDS(inst->signal_strength_interval)); + } + + inst->pending_signal_strength_notification = false; +} - inst->pending_signal_strength_notification = false; - } else if (IS_ENABLED(CONFIG_BT_GTBS) && - gtbs_inst.pending_signal_strength_notification) { +static void tbs_inst_init(struct service_inst *inst, const struct bt_gatt_attr *attrs, + size_t attr_count, const char *provider_name) +{ + LOG_DBG("inst %p index 0x%02x provider_name %s", inst, inst_index(inst), provider_name); - bt_gatt_notify_uuid(NULL, BT_UUID_TBS_SIGNAL_STRENGTH, - gtbs_inst.service_p->attrs, - >bs_inst.signal_strength, - sizeof(gtbs_inst.signal_strength)); + inst->ccid = bt_ccid_get_value(); + (void)strcpy(inst->provider_name, provider_name); + (void)strcpy(inst->uci, CONFIG_BT_TBS_UCI); + inst->optional_opcodes = CONFIG_BT_TBS_SUPPORTED_FEATURES; + inst->technology = CONFIG_BT_TBS_TECHNOLOGY; + inst->signal_strength_interval = CONFIG_BT_TBS_SIGNAL_STRENGTH_INTERVAL; + inst->status_flags = CONFIG_BT_TBS_STATUS_FLAGS; + inst->attrs = attrs; + inst->attr_count = attr_count; - if (gtbs_inst.signal_strength_interval) { - k_work_reschedule( - >bs_inst.reporting_interval_work, - K_SECONDS(gtbs_inst.signal_strength_interval)); - } + k_work_init_delayable(&inst->reporting_interval_work, signal_interval_timeout); +} - gtbs_inst.pending_signal_strength_notification = false; - } +static void gtbs_service_inst_init(struct gtbs_service_inst *inst, + const struct bt_gatt_service_static *service) +{ + tbs_inst_init(&inst->inst, service->attrs, service->attr_count, "Generic TBS"); +} + +static void tbs_service_inst_init(struct tbs_service_inst *inst, struct bt_gatt_service *service) +{ + tbs_inst_init(&inst->inst, service->attrs, service->attr_count, + CONFIG_BT_TBS_PROVIDER_NAME); + (void)strcpy(inst->uri_scheme_list, CONFIG_BT_TBS_URI_SCHEMES_LIST); } static int bt_tbs_init(void) @@ -1760,41 +1613,16 @@ static int bt_tbs_init(void) for (size_t i = 0; i < ARRAY_SIZE(svc_insts); i++) { int err; - svc_insts[i].service_p = &tbs_service_list[i]; - - err = bt_gatt_service_register(svc_insts[i].service_p); + err = bt_gatt_service_register(&tbs_service_list[i]); if (err != 0) { LOG_ERR("Could not register TBS[%d]: %d", i, err); } - } - - if (IS_ENABLED(CONFIG_BT_GTBS)) { - gtbs_inst.service_p = >bs_svc; - (void)strcpy(gtbs_inst.provider_name, "Generic TBS"); - gtbs_inst.optional_opcodes = CONFIG_BT_TBS_SUPPORTED_FEATURES; - gtbs_inst.ccid = bt_ccid_get_value(); - (void)strcpy(gtbs_inst.uci, "un000"); - k_work_init_delayable(>bs_inst.reporting_interval_work, - signal_interval_timeout); + tbs_service_inst_init(&svc_insts[i], &tbs_service_list[i]); } - for (int i = 0; i < ARRAY_SIZE(svc_insts); i++) { - /* Init default values */ - svc_insts[i].index = i; - svc_insts[i].ccid = bt_ccid_get_value(); - (void)strcpy(svc_insts[i].provider_name, - CONFIG_BT_TBS_PROVIDER_NAME); - (void)strcpy(svc_insts[i].uci, CONFIG_BT_TBS_UCI); - (void)strcpy(svc_insts[i].uri_scheme_list, - CONFIG_BT_TBS_URI_SCHEMES_LIST); - svc_insts[i].optional_opcodes = CONFIG_BT_TBS_SUPPORTED_FEATURES; - svc_insts[i].technology = CONFIG_BT_TBS_TECHNOLOGY; - svc_insts[i].signal_strength_interval = CONFIG_BT_TBS_SIGNAL_STRENGTH_INTERVAL; - svc_insts[i].status_flags = CONFIG_BT_TBS_STATUS_FLAGS; - - k_work_init_delayable(&svc_insts[i].reporting_interval_work, - signal_interval_timeout); + if (IS_ENABLED(CONFIG_BT_GTBS)) { + gtbs_service_inst_init(>bs_inst, >bs_svc); } return 0; @@ -1881,6 +1709,7 @@ int bt_tbs_terminate(uint8_t call_index) int bt_tbs_originate(uint8_t bearer_index, char *remote_uri, uint8_t *call_index) { + struct service_inst *tbs = inst_lookup_index(bearer_index); struct tbs_service_inst *inst; uint8_t buf[CONFIG_BT_TBS_MAX_URI_LENGTH + sizeof(struct bt_tbs_call_cp_originate)]; @@ -1888,7 +1717,7 @@ int bt_tbs_originate(uint8_t bearer_index, char *remote_uri, (struct bt_tbs_call_cp_originate *)buf; size_t uri_len; - if (bearer_index >= CONFIG_BT_TBS_BEARER_COUNT) { + if (tbs == NULL || inst_is_gtbs(tbs)) { return -EINVAL; } else if (!bt_tbs_valid_uri(remote_uri)) { LOG_DBG("Invalid URI %s", remote_uri); @@ -1897,7 +1726,7 @@ int bt_tbs_originate(uint8_t bearer_index, char *remote_uri, uri_len = strlen(remote_uri); - inst = &svc_insts[bearer_index]; + inst = CONTAINER_OF(tbs, struct tbs_service_inst, inst); ccp->opcode = BT_TBS_CALL_OPCODE_ORIGINATE; (void)memcpy(ccp->uri, remote_uri, uri_len); @@ -2039,16 +1868,52 @@ int bt_tbs_remote_terminate(uint8_t call_index) return status; } -int bt_tbs_remote_incoming(uint8_t bearer_index, const char *to, - const char *from, const char *friendly_name) +static void tbs_inst_remote_incoming(struct service_inst *inst, const char *to, const char *from, + const char *friendly_name, const struct bt_tbs_call *call) { - struct tbs_service_inst *inst; - struct bt_tbs_call *call = NULL; size_t local_uri_ind_len; size_t remote_uri_ind_len; size_t friend_name_ind_len; - if (bearer_index >= CONFIG_BT_TBS_BEARER_COUNT) { + __ASSERT_NO_MSG(to != NULL); + __ASSERT_NO_MSG(from != NULL); + + local_uri_ind_len = strlen(to) + 1; + remote_uri_ind_len = strlen(from) + 1; + + inst->in_call.call_index = call->index; + (void)strcpy(inst->in_call.uri, from); + + inst->incoming_uri.call_index = call->index; + (void)strcpy(inst->incoming_uri.uri, to); + + bt_gatt_notify_uuid(NULL, BT_UUID_TBS_INCOMING_URI, inst->attrs, &inst->incoming_uri, + local_uri_ind_len); + + bt_gatt_notify_uuid(NULL, BT_UUID_TBS_INCOMING_CALL, inst->attrs, &inst->in_call, + remote_uri_ind_len); + + if (friendly_name) { + inst->friendly_name.call_index = call->index; + utf8_lcpy(inst->friendly_name.uri, friendly_name, sizeof(inst->friendly_name.uri)); + friend_name_ind_len = strlen(from) + 1; + + bt_gatt_notify_uuid(NULL, BT_UUID_TBS_FRIENDLY_NAME, inst->attrs, + &inst->friendly_name, friend_name_ind_len); + } else { + inst->friendly_name.call_index = BT_TBS_FREE_CALL_INDEX; + bt_gatt_notify_uuid(NULL, BT_UUID_TBS_FRIENDLY_NAME, inst->attrs, NULL, 0); + } +} + +int bt_tbs_remote_incoming(uint8_t bearer_index, const char *to, + const char *from, const char *friendly_name) +{ + struct service_inst *inst = inst_lookup_index(bearer_index); + struct tbs_service_inst *service_inst; + struct bt_tbs_call *call = NULL; + + if (inst == NULL || inst_is_gtbs(inst)) { return -EINVAL; } else if (!bt_tbs_valid_uri(to)) { LOG_DBG("Invalid \"to\" URI: %s", to); @@ -2058,15 +1923,12 @@ int bt_tbs_remote_incoming(uint8_t bearer_index, const char *to, return -EINVAL; } - local_uri_ind_len = strlen(to) + 1; - remote_uri_ind_len = strlen(from) + 1; - - inst = &svc_insts[bearer_index]; + service_inst = CONTAINER_OF(inst, struct tbs_service_inst, inst); /* New call - Look for unused call item */ for (int i = 0; i < CONFIG_BT_TBS_MAX_CALLS; i++) { - if (inst->calls[i].index == BT_TBS_FREE_CALL_INDEX) { - call = &inst->calls[i]; + if (service_inst->calls[i].index == BT_TBS_FREE_CALL_INDEX) { + call = &service_inst->calls[i]; break; } } @@ -2086,69 +1948,13 @@ int bt_tbs_remote_incoming(uint8_t bearer_index, const char *to, (void)strcpy(call->remote_uri, from); call->state = BT_TBS_CALL_STATE_INCOMING; - inst->in_call.call_index = call->index; - (void)strcpy(inst->in_call.uri, from); - - inst->incoming_uri.call_index = call->index; - (void)strcpy(inst->incoming_uri.uri, to); - - bt_gatt_notify_uuid(NULL, BT_UUID_TBS_INCOMING_URI, - inst->service_p->attrs, - &inst->incoming_uri, local_uri_ind_len); - - bt_gatt_notify_uuid(NULL, BT_UUID_TBS_INCOMING_CALL, - inst->service_p->attrs, - &inst->in_call, remote_uri_ind_len); - - if (friendly_name) { - inst->friendly_name.call_index = call->index; - utf8_lcpy(inst->friendly_name.uri, friendly_name, sizeof(inst->friendly_name.uri)); - friend_name_ind_len = strlen(from) + 1; - - bt_gatt_notify_uuid(NULL, BT_UUID_TBS_FRIENDLY_NAME, - inst->service_p->attrs, - &inst->friendly_name, - friend_name_ind_len); - } else { - inst->friendly_name.call_index = BT_TBS_FREE_CALL_INDEX; - bt_gatt_notify_uuid(NULL, BT_UUID_TBS_FRIENDLY_NAME, - inst->service_p->attrs, NULL, 0); - } + tbs_inst_remote_incoming(inst, to, from, friendly_name, call); if (IS_ENABLED(CONFIG_BT_GTBS)) { - gtbs_inst.in_call.call_index = call->index; - (void)strcpy(gtbs_inst.in_call.uri, from); - - gtbs_inst.incoming_uri.call_index = call->index; - (void)strcpy(gtbs_inst.incoming_uri.uri, to); - - bt_gatt_notify_uuid(NULL, BT_UUID_TBS_INCOMING_URI, - gtbs_inst.service_p->attrs, - >bs_inst.incoming_uri, local_uri_ind_len); - - bt_gatt_notify_uuid(NULL, BT_UUID_TBS_INCOMING_CALL, - gtbs_inst.service_p->attrs, - >bs_inst.in_call, remote_uri_ind_len); - - if (friendly_name) { - gtbs_inst.friendly_name.call_index = call->index; - utf8_lcpy(inst->friendly_name.uri, friendly_name, - sizeof(inst->friendly_name.uri)); - friend_name_ind_len = strlen(from) + 1; - - bt_gatt_notify_uuid(NULL, BT_UUID_TBS_FRIENDLY_NAME, - gtbs_inst.service_p->attrs, - >bs_inst.friendly_name, - friend_name_ind_len); - } else { - gtbs_inst.friendly_name.call_index = 0; - bt_gatt_notify_uuid(NULL, BT_UUID_TBS_FRIENDLY_NAME, - gtbs_inst.service_p->attrs, - NULL, 0); - } + tbs_inst_remote_incoming(>bs_inst.inst, to, from, friendly_name, call); } - notify_calls(inst); + notify_calls(service_inst); LOG_DBG("New call with call index %u", call->index); @@ -2157,71 +1963,45 @@ int bt_tbs_remote_incoming(uint8_t bearer_index, const char *to, int bt_tbs_set_bearer_provider_name(uint8_t bearer_index, const char *name) { + struct service_inst *inst = inst_lookup_index(bearer_index); const size_t len = strlen(name); - const struct bt_gatt_attr *attr; if (len >= CONFIG_BT_TBS_MAX_PROVIDER_NAME_LENGTH || len == 0) { return -EINVAL; - } else if (bearer_index >= CONFIG_BT_TBS_BEARER_COUNT) { - if (!(IS_ENABLED(CONFIG_BT_GTBS) && - bearer_index == BT_TBS_GTBS_INDEX)) { - return -EINVAL; - } + } else if (inst == NULL) { + return -EINVAL; } - if (bearer_index == BT_TBS_GTBS_INDEX) { - if (strcmp(gtbs_inst.provider_name, name) == 0) { - return 0; - } - - (void)strcpy(gtbs_inst.provider_name, name); - attr = gtbs_inst.service_p->attrs; - } else { - if (strcmp(svc_insts[bearer_index].provider_name, name) == 0) { - return 0; - } - - (void)strcpy(svc_insts[bearer_index].provider_name, name); - attr = svc_insts[bearer_index].service_p->attrs; + if (strcmp(inst->provider_name, name) == 0) { + return 0; } - bt_gatt_notify_uuid(NULL, BT_UUID_TBS_PROVIDER_NAME, - attr, name, strlen(name)); + (void)strcpy(inst->provider_name, name); + + bt_gatt_notify_uuid(NULL, BT_UUID_TBS_PROVIDER_NAME, inst->attrs, inst->provider_name, + strlen(inst->provider_name)); return 0; } int bt_tbs_set_bearer_technology(uint8_t bearer_index, uint8_t new_technology) { - const struct bt_gatt_attr *attr; + struct service_inst *inst = inst_lookup_index(bearer_index); if (new_technology < BT_TBS_TECHNOLOGY_3G || new_technology > BT_TBS_TECHNOLOGY_IP) { return -EINVAL; - } else if (bearer_index >= CONFIG_BT_TBS_BEARER_COUNT) { - if (!(IS_ENABLED(CONFIG_BT_GTBS) && - bearer_index == BT_TBS_GTBS_INDEX)) { - return -EINVAL; - } + } else if (inst == NULL) { + return -EINVAL; } - if (bearer_index == BT_TBS_GTBS_INDEX) { - if (gtbs_inst.technology == new_technology) { - return 0; - } - - gtbs_inst.technology = new_technology; - attr = gtbs_inst.service_p->attrs; - } else { - if (svc_insts[bearer_index].technology == new_technology) { - return 0; - } - - svc_insts[bearer_index].technology = new_technology; - attr = svc_insts[bearer_index].service_p->attrs; + if (inst->technology == new_technology) { + return 0; } - bt_gatt_notify_uuid(NULL, BT_UUID_TBS_TECHNOLOGY, - attr, &new_technology, sizeof(new_technology)); + inst->technology = new_technology; + + bt_gatt_notify_uuid(NULL, BT_UUID_TBS_TECHNOLOGY, inst->attrs, &inst->technology, + sizeof(inst->technology)); return 0; } @@ -2229,66 +2009,36 @@ int bt_tbs_set_bearer_technology(uint8_t bearer_index, uint8_t new_technology) int bt_tbs_set_signal_strength(uint8_t bearer_index, uint8_t new_signal_strength) { - const struct bt_gatt_attr *attr; + struct service_inst *inst = inst_lookup_index(bearer_index); uint32_t timer_status; uint8_t interval; - struct k_work_delayable *reporting_interval_work; - struct tbs_service_inst *inst; if (new_signal_strength > BT_TBS_SIGNAL_STRENGTH_MAX && new_signal_strength != BT_TBS_SIGNAL_STRENGTH_UNKNOWN) { return -EINVAL; - } else if (bearer_index >= CONFIG_BT_TBS_BEARER_COUNT) { - if (!(IS_ENABLED(CONFIG_BT_GTBS) && - bearer_index == BT_TBS_GTBS_INDEX)) { - return -EINVAL; - } + } else if (inst == NULL) { + return -EINVAL; } - if (bearer_index == BT_TBS_GTBS_INDEX) { - if (gtbs_inst.signal_strength == new_signal_strength) { - return 0; - } - - gtbs_inst.signal_strength = new_signal_strength; - attr = gtbs_inst.service_p->attrs; - timer_status = k_work_delayable_remaining_get( - >bs_inst.reporting_interval_work); - interval = gtbs_inst.signal_strength_interval; - reporting_interval_work = >bs_inst.reporting_interval_work; - } else { - inst = &svc_insts[bearer_index]; - if (inst->signal_strength == new_signal_strength) { - return 0; - } - - inst->signal_strength = new_signal_strength; - attr = inst->service_p->attrs; - timer_status = k_work_delayable_remaining_get( - &inst->reporting_interval_work); - interval = inst->signal_strength_interval; - reporting_interval_work = &inst->reporting_interval_work; + if (inst->signal_strength == new_signal_strength) { + return 0; } + inst->signal_strength = new_signal_strength; + timer_status = k_work_delayable_remaining_get(&inst->reporting_interval_work); + interval = inst->signal_strength_interval; + if (timer_status == 0) { const k_timeout_t delay = K_SECONDS(interval); - bt_gatt_notify_uuid(NULL, BT_UUID_TBS_SIGNAL_STRENGTH, - attr, &new_signal_strength, - sizeof(new_signal_strength)); + bt_gatt_notify_uuid(NULL, BT_UUID_TBS_SIGNAL_STRENGTH, inst->attrs, + &inst->signal_strength, sizeof(inst->signal_strength)); if (interval) { - k_work_reschedule(reporting_interval_work, delay); + k_work_reschedule(&inst->reporting_interval_work, delay); } } else { - if (bearer_index == BT_TBS_GTBS_INDEX) { - LOG_DBG("GTBS: Reporting signal strength in %d ms", timer_status); - gtbs_inst.pending_signal_strength_notification = true; - - } else { - LOG_DBG("Index %u: Reporting signal strength in %d ms", bearer_index, - timer_status); - inst->pending_signal_strength_notification = true; - } + LOG_DBG("Index %u: Reporting signal strength in %d ms", bearer_index, timer_status); + inst->pending_signal_strength_notification = true; } return 0; @@ -2296,35 +2046,22 @@ int bt_tbs_set_signal_strength(uint8_t bearer_index, int bt_tbs_set_status_flags(uint8_t bearer_index, uint16_t status_flags) { - const struct bt_gatt_attr *attr; + struct service_inst *inst = inst_lookup_index(bearer_index); if (!BT_TBS_VALID_STATUS_FLAGS(status_flags)) { return -EINVAL; - } else if (bearer_index >= CONFIG_BT_TBS_BEARER_COUNT) { - if (!(IS_ENABLED(CONFIG_BT_GTBS) && - bearer_index == BT_TBS_GTBS_INDEX)) { - return -EINVAL; - } + } else if (inst == NULL) { + return -EINVAL; } - if (bearer_index == BT_TBS_GTBS_INDEX) { - if (gtbs_inst.status_flags == status_flags) { - return 0; - } - - gtbs_inst.status_flags = status_flags; - attr = gtbs_inst.service_p->attrs; - } else { - if (svc_insts[bearer_index].status_flags == status_flags) { - return 0; - } - - svc_insts[bearer_index].status_flags = status_flags; - attr = svc_insts[bearer_index].service_p->attrs; + if (inst->status_flags == status_flags) { + return 0; } + inst->status_flags = status_flags; + bt_gatt_notify_uuid(NULL, BT_UUID_TBS_STATUS_FLAGS, - attr, &status_flags, sizeof(status_flags)); + inst->attrs, &status_flags, sizeof(status_flags)); return 0; } @@ -2372,7 +2109,7 @@ int bt_tbs_set_uri_scheme_list(uint8_t bearer_index, const char **uri_list, LOG_DBG("TBS instance %u uri prefix list is now %s", bearer_index, inst->uri_scheme_list); bt_gatt_notify_uuid(NULL, BT_UUID_TBS_URI_LIST, - inst->service_p->attrs, &inst->uri_scheme_list, + inst->inst.attrs, &inst->uri_scheme_list, strlen(inst->uri_scheme_list)); if (IS_ENABLED(CONFIG_BT_GTBS)) { @@ -2396,7 +2133,7 @@ int bt_tbs_set_uri_scheme_list(uint8_t bearer_index, const char **uri_list, LOG_DBG("GTBS: URI scheme %.*s", uri_scheme_buf.len, uri_scheme_buf.data); bt_gatt_notify_uuid(NULL, BT_UUID_TBS_URI_LIST, - gtbs_inst.service_p->attrs, + inst->inst.attrs, uri_scheme_buf.data, uri_scheme_buf.len); } From 1894fa19794e629eb17672d40452b880d3bd80b3 Mon Sep 17 00:00:00 2001 From: Mariusz Skamra Date: Mon, 24 Jul 2023 10:43:27 +0200 Subject: [PATCH 1564/3723] Bluetooth: audio: tbs: Simplify bt_tbs_set_signal_strength function Simplify the function flow, by sending the signal strength notification in one place, the reporting_interval_work handler. Signed-off-by: Mariusz Skamra --- subsys/bluetooth/audio/tbs.c | 18 +++++------------- 1 file changed, 5 insertions(+), 13 deletions(-) diff --git a/subsys/bluetooth/audio/tbs.c b/subsys/bluetooth/audio/tbs.c index 3d8323b2968..5eaf6830eb6 100644 --- a/subsys/bluetooth/audio/tbs.c +++ b/subsys/bluetooth/audio/tbs.c @@ -2011,7 +2011,6 @@ int bt_tbs_set_signal_strength(uint8_t bearer_index, { struct service_inst *inst = inst_lookup_index(bearer_index); uint32_t timer_status; - uint8_t interval; if (new_signal_strength > BT_TBS_SIGNAL_STRENGTH_MAX && new_signal_strength != BT_TBS_SIGNAL_STRENGTH_UNKNOWN) { @@ -2025,22 +2024,15 @@ int bt_tbs_set_signal_strength(uint8_t bearer_index, } inst->signal_strength = new_signal_strength; - timer_status = k_work_delayable_remaining_get(&inst->reporting_interval_work); - interval = inst->signal_strength_interval; + inst->pending_signal_strength_notification = true; + timer_status = k_work_delayable_remaining_get(&inst->reporting_interval_work); if (timer_status == 0) { - const k_timeout_t delay = K_SECONDS(interval); - - bt_gatt_notify_uuid(NULL, BT_UUID_TBS_SIGNAL_STRENGTH, inst->attrs, - &inst->signal_strength, sizeof(inst->signal_strength)); - if (interval) { - k_work_reschedule(&inst->reporting_interval_work, delay); - } - } else { - LOG_DBG("Index %u: Reporting signal strength in %d ms", bearer_index, timer_status); - inst->pending_signal_strength_notification = true; + k_work_reschedule(&inst->reporting_interval_work, K_NO_WAIT); } + LOG_DBG("Index %u: Reporting signal strength in %d ms", bearer_index, timer_status); + return 0; } From 2bb88554677e9e41bf5aaa54f80c43963e403d75 Mon Sep 17 00:00:00 2001 From: Mariusz Skamra Date: Tue, 25 Jul 2023 10:10:43 +0200 Subject: [PATCH 1565/3723] Bluetooth: audio: tbs: Add call_alloc/call_free helper functions This removes duplicated code by adding helper functions to allocate and free bt_tbs_call objects. Signed-off-by: Mariusz Skamra --- subsys/bluetooth/audio/tbs.c | 107 ++++++++++++-------------- subsys/bluetooth/audio/tbs_client.c | 2 +- subsys/bluetooth/audio/tbs_internal.h | 6 +- 3 files changed, 52 insertions(+), 63 deletions(-) diff --git a/subsys/bluetooth/audio/tbs.c b/subsys/bluetooth/audio/tbs.c index 5eaf6830eb6..0ab0c63b616 100644 --- a/subsys/bluetooth/audio/tbs.c +++ b/subsys/bluetooth/audio/tbs.c @@ -7,8 +7,8 @@ */ #include +#include #include - #include #include @@ -333,6 +333,42 @@ static uint8_t next_free_call_index(void) return BT_TBS_FREE_CALL_INDEX; } +static struct bt_tbs_call *call_alloc(struct tbs_service_inst *inst, uint8_t state, const char *uri, + uint16_t uri_len) +{ + struct bt_tbs_call *free_call = NULL; + + for (size_t i = 0; i < ARRAY_SIZE(inst->calls); i++) { + if (inst->calls[i].index == BT_TBS_FREE_CALL_INDEX) { + free_call = &inst->calls[i]; + break; + } + } + + if (free_call == NULL) { + return NULL; + } + + __ASSERT_NO_MSG(uri_len < sizeof(free_call->remote_uri)); + + memset(free_call, 0, sizeof(*free_call)); + + /* Get the next free call_index */ + free_call->index = next_free_call_index(); + __ASSERT_NO_MSG(free_call->index != BT_TBS_FREE_CALL_INDEX); + + free_call->state = state; + (void)memcpy(free_call->remote_uri, uri, uri_len); + free_call->remote_uri[uri_len] = '\0'; + + return free_call; +} + +static void call_free(struct bt_tbs_call *call) +{ + call->index = BT_TBS_FREE_CALL_INDEX; +} + static void net_buf_put_call_states_by_inst(const struct tbs_service_inst *inst, struct net_buf_simple *buf) { @@ -845,7 +881,7 @@ static uint8_t terminate_call(struct tbs_service_inst *inst, return BT_TBS_RESULT_CODE_INVALID_CALL_INDEX; } - call->index = BT_TBS_FREE_CALL_INDEX; + call_free(call); tbs_set_terminate_reason(inst, ccp->call_index, reason); return BT_TBS_RESULT_CODE_SUCCESS; @@ -907,15 +943,7 @@ static int originate_call(struct tbs_service_inst *inst, const struct bt_tbs_call_cp_originate *ccp, uint16_t uri_len, uint8_t *call_index) { - struct bt_tbs_call *call = NULL; - - /* New call - Look for unused call item */ - for (int i = 0; i < CONFIG_BT_TBS_MAX_CALLS; i++) { - if (inst->calls[i].index == BT_TBS_FREE_CALL_INDEX) { - call = &inst->calls[i]; - break; - } - } + struct bt_tbs_call *call; /* Only allow one active outgoing call */ for (int i = 0; i < CONFIG_BT_TBS_MAX_CALLS; i++) { @@ -924,37 +952,15 @@ static int originate_call(struct tbs_service_inst *inst, } } - if (call == NULL) { - return BT_TBS_RESULT_CODE_OUT_OF_RESOURCES; - } - - call->index = next_free_call_index(); - - if (call->index == BT_TBS_FREE_CALL_INDEX) { - return BT_TBS_RESULT_CODE_OUT_OF_RESOURCES; - } - - if (uri_len == 0 || uri_len > CONFIG_BT_TBS_MAX_URI_LENGTH) { - call->index = BT_TBS_FREE_CALL_INDEX; + if (!bt_tbs_valid_uri(ccp->uri, uri_len)) { return BT_TBS_RESULT_CODE_INVALID_URI; } - (void)memcpy(call->remote_uri, ccp->uri, uri_len); - call->remote_uri[uri_len] = '\0'; - if (!bt_tbs_valid_uri(call->remote_uri)) { - LOG_DBG("Invalid URI: %s", call->remote_uri); - call->index = BT_TBS_FREE_CALL_INDEX; - - return BT_TBS_RESULT_CODE_INVALID_URI; + call = call_alloc(inst, BT_TBS_CALL_STATE_DIALING, ccp->uri, uri_len); + if (call == NULL) { + return BT_TBS_RESULT_CODE_OUT_OF_RESOURCES; } - /* We need to notify dialing state for test, - * even though we don't have an internal dialing state. - */ - call->state = BT_TBS_CALL_STATE_DIALING; - if (call->index != BT_TBS_FREE_CALL_INDEX) { - *call_index = call->index; - } BT_TBS_CALL_FLAG_SET_OUTGOING(call->flags); hold_other_calls(inst, 1, &call->index); @@ -965,6 +971,7 @@ static int originate_call(struct tbs_service_inst *inst, LOG_DBG("New call with call index %u", call->index); + *call_index = call->index; return BT_TBS_RESULT_CODE_SUCCESS; } @@ -1719,7 +1726,7 @@ int bt_tbs_originate(uint8_t bearer_index, char *remote_uri, if (tbs == NULL || inst_is_gtbs(tbs)) { return -EINVAL; - } else if (!bt_tbs_valid_uri(remote_uri)) { + } else if (!bt_tbs_valid_uri(remote_uri, strlen(remote_uri))) { LOG_DBG("Invalid URI %s", remote_uri); return -EINVAL; } @@ -1915,39 +1922,23 @@ int bt_tbs_remote_incoming(uint8_t bearer_index, const char *to, if (inst == NULL || inst_is_gtbs(inst)) { return -EINVAL; - } else if (!bt_tbs_valid_uri(to)) { + } else if (!bt_tbs_valid_uri(to, strlen(to))) { LOG_DBG("Invalid \"to\" URI: %s", to); return -EINVAL; - } else if (!bt_tbs_valid_uri(from)) { + } else if (!bt_tbs_valid_uri(from, strlen(from))) { LOG_DBG("Invalid \"from\" URI: %s", from); return -EINVAL; } service_inst = CONTAINER_OF(inst, struct tbs_service_inst, inst); - /* New call - Look for unused call item */ - for (int i = 0; i < CONFIG_BT_TBS_MAX_CALLS; i++) { - if (service_inst->calls[i].index == BT_TBS_FREE_CALL_INDEX) { - call = &service_inst->calls[i]; - break; - } - } - + call = call_alloc(service_inst, BT_TBS_CALL_STATE_INCOMING, from, strlen(from)); if (call == NULL) { - return -BT_TBS_RESULT_CODE_OUT_OF_RESOURCES; - } - - call->index = next_free_call_index(); - - if (call->index == BT_TBS_FREE_CALL_INDEX) { - return -BT_TBS_RESULT_CODE_OUT_OF_RESOURCES; + return -ENOMEM; } BT_TBS_CALL_FLAG_SET_INCOMING(call->flags); - (void)strcpy(call->remote_uri, from); - call->state = BT_TBS_CALL_STATE_INCOMING; - tbs_inst_remote_incoming(inst, to, from, friendly_name, call); if (IS_ENABLED(CONFIG_BT_GTBS)) { diff --git a/subsys/bluetooth/audio/tbs_client.c b/subsys/bluetooth/audio/tbs_client.c index 181f951b918..475544f7b20 100644 --- a/subsys/bluetooth/audio/tbs_client.c +++ b/subsys/bluetooth/audio/tbs_client.c @@ -1785,7 +1785,7 @@ int bt_tbs_client_originate_call(struct bt_conn *conn, uint8_t inst_index, if (conn == NULL) { return -ENOTCONN; - } else if (!bt_tbs_valid_uri(uri)) { + } else if (!bt_tbs_valid_uri(uri, strlen(uri))) { LOG_DBG("Invalid URI: %s", uri); return -EINVAL; } diff --git a/subsys/bluetooth/audio/tbs_internal.h b/subsys/bluetooth/audio/tbs_internal.h index edb62972bca..c1c5f32d650 100644 --- a/subsys/bluetooth/audio/tbs_internal.h +++ b/subsys/bluetooth/audio/tbs_internal.h @@ -172,18 +172,16 @@ static inline const char *bt_tbs_term_reason_str(uint8_t reason) * character. Minimal uri is "a:b". * * @param uri The uri "scheme:id" + * @param len The length of uri * @return true If the above is true * @return false If the above is not true */ -static inline bool bt_tbs_valid_uri(const char *uri) +static inline bool bt_tbs_valid_uri(const char *uri, size_t len) { - size_t len; - if (!uri) { return false; } - len = strlen(uri); if (len > CONFIG_BT_TBS_MAX_URI_LENGTH || len < BT_TBS_MIN_URI_LEN) { return false; From 547ffdab6e16bfde8d9fc6d49872c110d46e099c Mon Sep 17 00:00:00 2001 From: Emil Gydesen Date: Wed, 20 Dec 2023 08:36:04 +0100 Subject: [PATCH 1566/3723] Bluetooth: MICP: Add mic_ctlr_get_by_conn Add function to get a MICP microphone controller instance from a connection pointer. This is effectively the reverse of bt_micp_mic_ctlr_conn_get, and works similar to bt_vcp_vol_ctlr_get_by_conn. Signed-off-by: Emil Gydesen --- include/zephyr/bluetooth/audio/micp.h | 14 +++++++++ subsys/bluetooth/audio/micp_mic_ctlr.c | 40 ++++++++++++++++++++------ 2 files changed, 46 insertions(+), 8 deletions(-) diff --git a/include/zephyr/bluetooth/audio/micp.h b/include/zephyr/bluetooth/audio/micp.h index e5cbf523be0..f33d1d8ebef 100644 --- a/include/zephyr/bluetooth/audio/micp.h +++ b/include/zephyr/bluetooth/audio/micp.h @@ -217,6 +217,20 @@ int bt_micp_mic_ctlr_included_get(struct bt_micp_mic_ctlr *mic_ctlr, int bt_micp_mic_ctlr_conn_get(const struct bt_micp_mic_ctlr *mic_ctlr, struct bt_conn **conn); +/** + * @brief Get the volume controller from a connection pointer + * + * Get the Volume Control Profile Volume Controller pointer from a connection pointer. + * Only volume controllers that have been initiated via bt_micp_mic_ctlr_discover() can be + * retrieved. + * + * @param conn Connection pointer. + * + * @retval Pointer to a Microphone Control Profile Microphone Controller instance + * @retval NULL if @p conn is NULL or if the connection has not done discovery yet + */ +struct bt_micp_mic_ctlr *bt_micp_mic_ctlr_get_by_conn(const struct bt_conn *conn); + /** * @brief Discover Microphone Control Service * diff --git a/subsys/bluetooth/audio/micp_mic_ctlr.c b/subsys/bluetooth/audio/micp_mic_ctlr.c index 4865ccb28ce..0bceb26d189 100644 --- a/subsys/bluetooth/audio/micp_mic_ctlr.c +++ b/subsys/bluetooth/audio/micp_mic_ctlr.c @@ -33,6 +33,11 @@ static struct bt_micp_mic_ctlr_cb *micp_mic_ctlr_cb; static struct bt_micp_mic_ctlr mic_ctlrs[CONFIG_BT_MAX_CONN]; static const struct bt_uuid *mics_uuid = BT_UUID_MICS; +static struct bt_micp_mic_ctlr *mic_ctlr_get_by_conn(const struct bt_conn *conn) +{ + return &mic_ctlrs[bt_conn_index(conn)]; +} + static uint8_t mute_notify_handler(struct bt_conn *conn, struct bt_gatt_subscribe_params *params, const void *data, uint16_t length) @@ -44,7 +49,7 @@ static uint8_t mute_notify_handler(struct bt_conn *conn, return BT_GATT_ITER_CONTINUE; } - mic_ctlr = &mic_ctlrs[bt_conn_index(conn)]; + mic_ctlr = mic_ctlr_get_by_conn(conn); if (data != NULL) { if (length == sizeof(*mute_val)) { @@ -66,9 +71,9 @@ static uint8_t micp_mic_ctlr_read_mute_cb(struct bt_conn *conn, uint8_t err, struct bt_gatt_read_params *params, const void *data, uint16_t length) { + struct bt_micp_mic_ctlr *mic_ctlr = mic_ctlr_get_by_conn(conn); uint8_t cb_err = err; uint8_t mute_val = 0; - struct bt_micp_mic_ctlr *mic_ctlr = &mic_ctlrs[bt_conn_index(conn)]; mic_ctlr->busy = false; @@ -94,7 +99,7 @@ static uint8_t micp_mic_ctlr_read_mute_cb(struct bt_conn *conn, uint8_t err, static void micp_mic_ctlr_write_mics_mute_cb(struct bt_conn *conn, uint8_t err, struct bt_gatt_write_params *params) { - struct bt_micp_mic_ctlr *mic_ctlr = &mic_ctlrs[bt_conn_index(conn)]; + struct bt_micp_mic_ctlr *mic_ctlr = mic_ctlr_get_by_conn(conn); uint8_t mute_val = mic_ctlr->mute_val_buf[0]; LOG_DBG("Write %s (0x%02X)", err ? "failed" : "successful", err); @@ -155,7 +160,7 @@ static uint8_t micp_discover_include_func( struct bt_conn *conn, const struct bt_gatt_attr *attr, struct bt_gatt_discover_params *params) { - struct bt_micp_mic_ctlr *mic_ctlr = &mic_ctlrs[bt_conn_index(conn)]; + struct bt_micp_mic_ctlr *mic_ctlr = mic_ctlr_get_by_conn(conn); if (attr == NULL) { LOG_DBG("Discover include complete for MICS: %u AICS", mic_ctlr->aics_inst_cnt); @@ -218,7 +223,7 @@ static uint8_t micp_discover_func(struct bt_conn *conn, const struct bt_gatt_attr *attr, struct bt_gatt_discover_params *params) { - struct bt_micp_mic_ctlr *mic_ctlr = &mic_ctlrs[bt_conn_index(conn)]; + struct bt_micp_mic_ctlr *mic_ctlr = mic_ctlr_get_by_conn(conn); if (attr == NULL) { int err = 0; @@ -290,7 +295,7 @@ static uint8_t primary_discover_func(struct bt_conn *conn, const struct bt_gatt_attr *attr, struct bt_gatt_discover_params *params) { - struct bt_micp_mic_ctlr *mic_ctlr = &mic_ctlrs[bt_conn_index(conn)]; + struct bt_micp_mic_ctlr *mic_ctlr = mic_ctlr_get_by_conn(conn); if (attr == NULL) { LOG_DBG("Could not find a MICS instance on the server"); @@ -359,7 +364,7 @@ static void micp_mic_ctlr_reset(struct bt_micp_mic_ctlr *mic_ctlr) static void disconnected(struct bt_conn *conn, uint8_t reason) { - struct bt_micp_mic_ctlr *mic_ctlr = &mic_ctlrs[bt_conn_index(conn)]; + struct bt_micp_mic_ctlr *mic_ctlr = mic_ctlr_get_by_conn(conn); if (mic_ctlr->conn == conn) { micp_mic_ctlr_reset(mic_ctlr); @@ -390,7 +395,7 @@ int bt_micp_mic_ctlr_discover(struct bt_conn *conn, struct bt_micp_mic_ctlr **mi return -EINVAL; } - mic_ctlr = &mic_ctlrs[bt_conn_index(conn)]; + mic_ctlr = mic_ctlr_get_by_conn(conn); (void)memset(&mic_ctlr->discover_params, 0, sizeof(mic_ctlr->discover_params)); @@ -481,6 +486,25 @@ int bt_micp_mic_ctlr_included_get(struct bt_micp_mic_ctlr *mic_ctlr, return 0; } +struct bt_micp_mic_ctlr *bt_micp_mic_ctlr_get_by_conn(const struct bt_conn *conn) +{ + struct bt_micp_mic_ctlr *mic_ctlr; + + CHECKIF(conn == NULL) { + LOG_DBG("NULL conn pointer"); + return NULL; + } + + mic_ctlr = mic_ctlr_get_by_conn(conn); + if (mic_ctlr->conn == NULL) { + LOG_DBG("conn %p is not associated with microphone controller. Do discovery first", + (void *)conn); + return NULL; + } + + return mic_ctlr; +} + int bt_micp_mic_ctlr_conn_get(const struct bt_micp_mic_ctlr *mic_ctlr, struct bt_conn **conn) { CHECKIF(mic_ctlr == NULL) { From 8ad22f7df40b11e5763b71869a33b45690e90e6c Mon Sep 17 00:00:00 2001 From: Anas Nashif Date: Wed, 20 Dec 2023 11:42:41 -0500 Subject: [PATCH 1567/3723] twister: coverage: verify existence of tools before trying to use them Verify we have the coverage tool we want to use, otherwise we will end up with many warnings and errors during coverage data collection. Signed-off-by: Anas Nashif --- scripts/pylib/twister/twisterlib/coverage.py | 31 ++++++++++++++++++-- 1 file changed, 28 insertions(+), 3 deletions(-) diff --git a/scripts/pylib/twister/twisterlib/coverage.py b/scripts/pylib/twister/twisterlib/coverage.py index 18aba2bc162..4fe4e609ddd 100644 --- a/scripts/pylib/twister/twisterlib/coverage.py +++ b/scripts/pylib/twister/twisterlib/coverage.py @@ -3,6 +3,7 @@ # Copyright (c) 2018-2022 Intel Corporation # SPDX-License-Identifier: Apache-2.0 +import sys import os import logging import pathlib @@ -155,9 +156,11 @@ def get_version(self): version_output = result.stdout.strip().replace('lcov: LCOV version ', '') return version_output except subprocess.CalledProcessError as e: - logger.error(f"Unsable to determine lcov version: {e}") - - return "" + logger.error(f"Unable to determine lcov version: {e}") + sys.exit(1) + except FileNotFoundError as e: + logger.error(f"Unable to to find lcov tool: {e}") + sys.exit(1) def add_ignore_file(self, pattern): self.ignores.append('*' + pattern + '*') @@ -243,6 +246,24 @@ def __init__(self): super().__init__() self.ignores = [] self.output_formats = "html" + self.version = self.get_version() + + def get_version(self): + try: + result = subprocess.run(['gcovr', '--version'], + stdout=subprocess.PIPE, + stderr=subprocess.PIPE, + text=True, check=True) + version_lines = result.stdout.strip().split('\n') + if version_lines: + version_output = version_lines[0].replace('gcovr ', '') + return version_output + except subprocess.CalledProcessError as e: + logger.error(f"Unable to determine gcovr version: {e}") + sys.exit(1) + except FileNotFoundError as e: + logger.error(f"Unable to to find gcovr tool: {e}") + sys.exit(1) def add_ignore_file(self, pattern): self.ignores.append('.*' + pattern + '.*') @@ -337,8 +358,12 @@ def run_coverage(testplan, options): options.gcov_tool = "gcov" elif os.path.exists(zephyr_sdk_gcov_tool): options.gcov_tool = zephyr_sdk_gcov_tool + else: + logger.error(f"Can't find a suitable gcov tool. Use --gcov-tool or set ZEPHYR_SDK_INSTALL_DIR.") + sys.exit(1) logger.info("Generating coverage files...") + logger.info(f"Using gcov tool: {options.gcov_tool}") coverage_tool = CoverageTool.factory(options.coverage_tool) coverage_tool.gcov_tool = options.gcov_tool coverage_tool.base_dir = os.path.abspath(options.coverage_basedir) From f6a78954963d8efc3ff567ae569513cf5fa976d7 Mon Sep 17 00:00:00 2001 From: Keith Short Date: Fri, 22 Dec 2023 10:40:38 -0700 Subject: [PATCH 1568/3723] twister: Fix exception when running coverage Fix an exception when running coverage using gcov or llvm-cov. Fixes https://github.com/zephyrproject-rtos/zephyr/issues/66897 Signed-off-by: Keith Short --- scripts/pylib/twister/twisterlib/coverage.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/scripts/pylib/twister/twisterlib/coverage.py b/scripts/pylib/twister/twisterlib/coverage.py index 4fe4e609ddd..105d3255b27 100644 --- a/scripts/pylib/twister/twisterlib/coverage.py +++ b/scripts/pylib/twister/twisterlib/coverage.py @@ -365,7 +365,7 @@ def run_coverage(testplan, options): logger.info("Generating coverage files...") logger.info(f"Using gcov tool: {options.gcov_tool}") coverage_tool = CoverageTool.factory(options.coverage_tool) - coverage_tool.gcov_tool = options.gcov_tool + coverage_tool.gcov_tool = str(options.gcov_tool) coverage_tool.base_dir = os.path.abspath(options.coverage_basedir) # Apply output format default if options.coverage_formats is not None: From 66a06d955a36ce5f9cd31ffb97b941820a250edf Mon Sep 17 00:00:00 2001 From: Fabio Baltieri Date: Thu, 21 Dec 2023 18:55:04 +0000 Subject: [PATCH 1569/3723] input: use K_KERNEL_STACK_SIZEOF to set the thread stack size Use K_KERNEL_STACK_SIZEOF instead of the config directly to set the stack size in k_thread_create() calls. Signed-off-by: Fabio Baltieri --- drivers/input/input_kbd_matrix.c | 2 +- drivers/input/linux_evdev.c | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/input/input_kbd_matrix.c b/drivers/input/input_kbd_matrix.c index 39bebf5c496..6cbba73d9df 100644 --- a/drivers/input/input_kbd_matrix.c +++ b/drivers/input/input_kbd_matrix.c @@ -315,7 +315,7 @@ int input_kbd_matrix_common_init(const struct device *dev) k_sem_init(&data->poll_lock, 0, 1); k_thread_create(&data->thread, data->thread_stack, - CONFIG_INPUT_KBD_MATRIX_THREAD_STACK_SIZE, + K_KERNEL_STACK_SIZEOF(data->thread_stack), input_kbd_matrix_polling_thread, (void *)dev, NULL, NULL, CONFIG_INPUT_KBD_MATRIX_THREAD_PRIORITY, 0, K_NO_WAIT); diff --git a/drivers/input/linux_evdev.c b/drivers/input/linux_evdev.c index 20ba7419b1d..55d412d567c 100644 --- a/drivers/input/linux_evdev.c +++ b/drivers/input/linux_evdev.c @@ -98,7 +98,7 @@ static int linux_evdev_init(const struct device *dev) linux_evdev_fd = linux_evdev_open(linux_evdev_path); k_thread_create(&linux_evdev_thread, linux_evdev_thread_stack, - CONFIG_ARCH_POSIX_RECOMMENDED_STACK_SIZE, + K_KERNEL_STACK_SIZEOF(linux_evdev_thread_stack), linux_evdev_thread_fn, (void *)dev, NULL, NULL, CONFIG_NATIVE_LINUX_EVDEV_THREAD_PRIORITY, 0, K_NO_WAIT); From beb43bdf202b3ba6d12039057985861509c7cea0 Mon Sep 17 00:00:00 2001 From: Daniel DeGrasse Date: Sun, 4 Dec 2022 00:46:38 -0600 Subject: [PATCH 1570/3723] soc: arm: nxp: add MK22F12 definition Add SOC definition for MK22F12 series, larger LQFP-144 K22 series parts that feature additional peripheral instances. Additionally, these parts differ from the standard MK22 in the following ways: - SYSMPU peripheral is present, so an MPU definition is required - No external oscillator divider is present This commit also updates the NXP HAL to include pin control files for these SOCs. Signed-off-by: Daniel DeGrasse --- dts/arm/nxp/nxp_k22fx512.dtsi | 51 ++++++++++++++++ soc/arm/nxp_kinetis/k2x/CMakeLists.txt | 5 ++ .../nxp_kinetis/k2x/Kconfig.defconfig.mk22f12 | 3 + .../k2x/Kconfig.defconfig.mk22fx12 | 17 ++++++ .../nxp_kinetis/k2x/Kconfig.defconfig.series | 3 - soc/arm/nxp_kinetis/k2x/Kconfig.soc | 22 +++++++ soc/arm/nxp_kinetis/k2x/nxp_mpu_regions.c | 59 +++++++++++++++++++ soc/arm/nxp_kinetis/k2x/soc.c | 2 + 8 files changed, 159 insertions(+), 3 deletions(-) create mode 100644 dts/arm/nxp/nxp_k22fx512.dtsi create mode 100644 soc/arm/nxp_kinetis/k2x/Kconfig.defconfig.mk22fx12 create mode 100644 soc/arm/nxp_kinetis/k2x/nxp_mpu_regions.c diff --git a/dts/arm/nxp/nxp_k22fx512.dtsi b/dts/arm/nxp/nxp_k22fx512.dtsi new file mode 100644 index 00000000000..4b2962019c0 --- /dev/null +++ b/dts/arm/nxp/nxp_k22fx512.dtsi @@ -0,0 +1,51 @@ +/* + * Copyright 2023 Daniel DeGrasse + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include + +/ { + soc { + i2c2: i2c@400e6000 { + compatible = "nxp,kinetis-i2c"; + clock-frequency = ; + #address-cells = <1>; + #size-cells = <0>; + reg = <0x400e6000 0x1000>; + interrupts = <74 0>; + clocks = <&sim KINETIS_SIM_BUS_CLK 0x1028 6>; + status = "disabled"; + }; + + spi2: spi@400ac000 { + reg = <0x400ac000 0x88>; + interrupts = <65 3>; + clocks = <&sim KINETIS_SIM_BUS_CLK 0x1030 12>; + #address-cells = <1>; + #size-cells = <0>; + status = "disabled"; + }; + + uart4: uart@400ea000 { + compatible = "nxp,kinetis-uart"; + reg = <0x400ea000 0x1000>; + interrupts = <66 0>, <67 0>; + interrupt-names = "status", "error"; + clocks = <&sim KINETIS_SIM_BUS_CLK 0x1028 10>; + + status = "disabled"; + }; + + uart5: uart@400eb000 { + compatible = "nxp,kinetis-uart"; + reg = <0x400eb000 0x1000>; + interrupts = <68 0>, <69 0>; + interrupt-names = "status", "error"; + clocks = <&sim KINETIS_SIM_BUS_CLK 0x1028 11>; + + status = "disabled"; + }; + }; +}; diff --git a/soc/arm/nxp_kinetis/k2x/CMakeLists.txt b/soc/arm/nxp_kinetis/k2x/CMakeLists.txt index 017787396e4..8ff38d089ce 100644 --- a/soc/arm/nxp_kinetis/k2x/CMakeLists.txt +++ b/soc/arm/nxp_kinetis/k2x/CMakeLists.txt @@ -9,4 +9,9 @@ zephyr_sources( soc.c ) +if(DEFINED CONFIG_ARM_MPU AND DEFINED CONFIG_CPU_HAS_NXP_MPU) + # MK22F12 series MCUs have NXP MPU + zephyr_sources(nxp_mpu_regions.c) +endif() + set(SOC_LINKER_SCRIPT ${ZEPHYR_BASE}/include/zephyr/arch/arm/cortex_m/scripts/linker.ld CACHE INTERNAL "") diff --git a/soc/arm/nxp_kinetis/k2x/Kconfig.defconfig.mk22f12 b/soc/arm/nxp_kinetis/k2x/Kconfig.defconfig.mk22f12 index 3e2e2f50ef7..01f0ec78f2f 100644 --- a/soc/arm/nxp_kinetis/k2x/Kconfig.defconfig.mk22f12 +++ b/soc/arm/nxp_kinetis/k2x/Kconfig.defconfig.mk22f12 @@ -11,4 +11,7 @@ config SOC config GPIO default y +config NUM_IRQS + default 74 + endif # SOC_MK22F12 diff --git a/soc/arm/nxp_kinetis/k2x/Kconfig.defconfig.mk22fx12 b/soc/arm/nxp_kinetis/k2x/Kconfig.defconfig.mk22fx12 new file mode 100644 index 00000000000..963fdf87162 --- /dev/null +++ b/soc/arm/nxp_kinetis/k2x/Kconfig.defconfig.mk22fx12 @@ -0,0 +1,17 @@ +# Copyright 2023 Daniel DeGrasse +# SPDX-License-Identifier: Apache-2.0 + +# Kinetis MK22FX12 configuration options + +if SOC_MK22F12 + +config SOC + default "mk22f12" + +config NUM_IRQS + default 81 + +config CPU_HAS_CUSTOM_FIXED_SOC_MPU_REGIONS + default y + +endif # SOC_MK22F12 diff --git a/soc/arm/nxp_kinetis/k2x/Kconfig.defconfig.series b/soc/arm/nxp_kinetis/k2x/Kconfig.defconfig.series index 4cec6645964..254fd251014 100644 --- a/soc/arm/nxp_kinetis/k2x/Kconfig.defconfig.series +++ b/soc/arm/nxp_kinetis/k2x/Kconfig.defconfig.series @@ -12,9 +12,6 @@ if SOC_SERIES_KINETIS_K2X config SOC_SERIES default "k2x" -config NUM_IRQS - default 74 - source "soc/arm/nxp_kinetis/k2x/Kconfig.defconfig.mk*" endif # SOC_SERIES_KINETIS_K2X diff --git a/soc/arm/nxp_kinetis/k2x/Kconfig.soc b/soc/arm/nxp_kinetis/k2x/Kconfig.soc index 5653d6cd75a..0535ac2e684 100644 --- a/soc/arm/nxp_kinetis/k2x/Kconfig.soc +++ b/soc/arm/nxp_kinetis/k2x/Kconfig.soc @@ -26,6 +26,24 @@ config SOC_MK22F51212 select HAS_MCUX_DAC select HAS_MCUX_RCM +# Note- the MK22F12 SKU is a legacy SOC, no longer officially supported by +# NXP's MCUX SDK, and not recommended for new designs. +config SOC_MK22F12 + bool "SOC_MK22F12" + select HAS_MCUX + select HAS_MCUX_SMC + select HAS_MCUX_ADC16 + select HAS_MCUX_FTFX + select HAS_MCUX_FTM + select HAS_MCUX_RNGA + select HAS_MCUX_SIM + select HAS_OSC + select HAS_MCG + select CPU_HAS_FPU + select HAS_MCUX_DAC + select HAS_MCUX_RCM + select CPU_HAS_NXP_MPU + endchoice if SOC_SERIES_KINETIS_K2X @@ -36,9 +54,13 @@ config SOC_PART_NUMBER_MK22FN512VLH12 config SOC_PART_NUMBER_MK22FX512AVLK12 bool +config SOC_PART_NUMBER_MK22FX512VLQ12 + bool + config SOC_PART_NUMBER_KINETIS_K2X string default "MK22FN512VLH12" if SOC_PART_NUMBER_MK22FN512VLH12 + default "MK22FX512VLQ12" if SOC_PART_NUMBER_MK22FX512VLQ12 help This string holds the full part number of the SoC. It is a hidden option that you should not set directly. The part number selection choice defines diff --git a/soc/arm/nxp_kinetis/k2x/nxp_mpu_regions.c b/soc/arm/nxp_kinetis/k2x/nxp_mpu_regions.c new file mode 100644 index 00000000000..30a5cff42ea --- /dev/null +++ b/soc/arm/nxp_kinetis/k2x/nxp_mpu_regions.c @@ -0,0 +1,59 @@ +/* + * Copyright 2023 Daniel DeGrasse + * + * SPDX-License-Identifier: Apache-2.0 + */ +#include +#include + +static const struct nxp_mpu_region mpu_regions[] = { + /* Region 0 */ + /* Debugger access can't be disabled; ENET and USB devices will not be able + * to access RAM when their regions are dynamically disabled in NXP MPU. + */ + MPU_REGION_ENTRY("DEBUGGER_0", + 0, + 0xFFFFFFFF, + REGION_DEBUGGER_AND_DEVICE_ATTR), + + /* The NXP MPU does not give precedence to memory regions like the ARM + * MPU, which means that if one region grants access then another + * region cannot revoke access. If an application enables hardware + * stack protection, we need to disable supervisor writes from the core + * to the stack guard region. As a result, we cannot have a single + * background region that enables supervisor read/write access from the + * core to the entire address space, and instead define two background + * regions that together cover the entire address space except for + * SRAM. + */ + + /* Region 1 */ + MPU_REGION_ENTRY("BACKGROUND_0", + 0, + CONFIG_SRAM_BASE_ADDRESS-1, + REGION_BACKGROUND_ATTR), + /* Region 2 */ + MPU_REGION_ENTRY("BACKGROUND_1", + CONFIG_SRAM_BASE_ADDRESS + + (CONFIG_SRAM_SIZE * 1024), + 0xFFFFFFFF, + REGION_BACKGROUND_ATTR), + /* Region 3 */ + MPU_REGION_ENTRY("FLASH_0", + CONFIG_FLASH_BASE_ADDRESS, + (CONFIG_FLASH_BASE_ADDRESS + + (CONFIG_FLASH_SIZE * 1024) - 1), + REGION_FLASH_ATTR), + /* Region 4 */ + MPU_REGION_ENTRY("RAM_U_0", + CONFIG_SRAM_BASE_ADDRESS, + (CONFIG_SRAM_BASE_ADDRESS + + (CONFIG_SRAM_SIZE * 1024) - 1), + REGION_RAM_ATTR), +}; + +const struct nxp_mpu_config mpu_config = { + .num_regions = ARRAY_SIZE(mpu_regions), + .mpu_regions = mpu_regions, + .sram_region = 4, +}; diff --git a/soc/arm/nxp_kinetis/k2x/soc.c b/soc/arm/nxp_kinetis/k2x/soc.c index 67ea1183401..d5108fb49d9 100644 --- a/soc/arm/nxp_kinetis/k2x/soc.c +++ b/soc/arm/nxp_kinetis/k2x/soc.c @@ -49,7 +49,9 @@ static const osc_config_t oscConfig = { .oscerConfig = { .enableMode = 0U, /* Disable external reference clock */ +#if FSL_FEATURE_OSC_HAS_EXT_REF_CLOCK_DIVIDER .erclkDiv = 0U, +#endif }, }; From fcd139d7af98c5da85447429bfc848625813f087 Mon Sep 17 00:00:00 2001 From: Christopher Friedt Date: Fri, 22 Dec 2023 14:54:07 -0500 Subject: [PATCH 1571/3723] posix: pthread: support stack sizes larger than 65k A previous size optimization capped the pthread_attr_t stacksize property at 65536. Some Zephyr users felt that was not large enough for specific use cases. Modify struct pthread_attr to support large stack sizes by default with the flexibility to allow users to vary the number of bits used for both stacksizes and guardsizes. The default guardsize remains zero sinze Zephyr's stack allocators already pad stacks with a guard area based on other config parameters, and since Zephyr is already designed to support both SW and HW stack protection at the kernel layer. Signed-off-by: Christopher Friedt --- include/zephyr/posix/posix_types.h | 10 +--- lib/posix/Kconfig.pthread | 21 ++++++- lib/posix/posix_internal.h | 12 ++++ lib/posix/pthread.c | 90 ++++++++++++------------------ 4 files changed, 70 insertions(+), 63 deletions(-) diff --git a/include/zephyr/posix/posix_types.h b/include/zephyr/posix/posix_types.h index fb77f191bac..175943950b7 100644 --- a/include/zephyr/posix/posix_types.h +++ b/include/zephyr/posix/posix_types.h @@ -38,15 +38,9 @@ typedef unsigned long timer_t; /* Thread attributes */ struct pthread_attr { void *stack; - uint16_t stacksize; - uint16_t guardsize; - int8_t priority; - uint8_t schedpolicy: 2; - uint8_t guardsize_msbit: 1; - bool initialized: 1; - bool cancelstate: 1; - bool detachstate: 1; + uint32_t details[2]; }; + #if defined(CONFIG_MINIMAL_LIBC) || defined(CONFIG_PICOLIBC) || defined(CONFIG_ARMCLANG_STD_LIBC) \ || defined(CONFIG_ARCMWDT_LIBC) typedef struct pthread_attr pthread_attr_t; diff --git a/lib/posix/Kconfig.pthread b/lib/posix/Kconfig.pthread index c27f55b68b9..8870b725109 100644 --- a/lib/posix/Kconfig.pthread +++ b/lib/posix/Kconfig.pthread @@ -27,9 +27,28 @@ config PTHREAD_RECYCLER_DELAY_MS Note: this option should be considered temporary and will likely be removed once a more synchronous solution is available. +config POSIX_PTHREAD_ATTR_STACKSIZE_BITS + int "Significant bits for pthread_attr_t stacksize" + range 8 31 + default 23 + help + This value plays a part in determining the maximum supported + pthread_attr_t stacksize. Valid stacksizes are in the range + [1, N], where N = 1 << M, and M is this configuration value. + +config POSIX_PTHREAD_ATTR_GUARDSIZE_BITS + int "Significant bits for pthread_attr_t guardsize" + range 1 31 + default 9 + help + This value plays a part in determining the maximum supported + pthread_attr_t guardsize. Valid guardsizes are in the range + [0, N-1], where N = 1 << M, and M is this configuration value. + + Actual guardsize values may be rounded-up. + config POSIX_PTHREAD_ATTR_GUARDSIZE_DEFAULT int "Default size of stack guard area" - range 0 65536 default 0 help This is the default amount of space to reserve at the overflow end of a diff --git a/lib/posix/posix_internal.h b/lib/posix/posix_internal.h index 4fcafaa58cf..1e6bb0aeb33 100644 --- a/lib/posix/posix_internal.h +++ b/lib/posix/posix_internal.h @@ -22,6 +22,18 @@ */ #define PTHREAD_OBJ_MASK_INIT 0x80000000 +struct posix_thread_attr { + void *stack; + /* the following two bitfields should combine to be 32-bits in size */ + uint32_t stacksize : CONFIG_POSIX_PTHREAD_ATTR_STACKSIZE_BITS; + uint16_t guardsize : CONFIG_POSIX_PTHREAD_ATTR_GUARDSIZE_BITS; + int8_t priority; + uint8_t schedpolicy: 2; + bool initialized: 1; + bool cancelstate: 1; + bool detachstate: 1; +}; + struct posix_thread { struct k_thread thread; diff --git a/lib/posix/pthread.c b/lib/posix/pthread.c index a1f74908f13..131242866a0 100644 --- a/lib/posix/pthread.c +++ b/lib/posix/pthread.c @@ -29,6 +29,9 @@ POSIX_TO_ZEPHYR_PRIORITY(K_LOWEST_APPLICATION_THREAD_PRIO, DEFAULT_PTHREAD_POLICY) #define DEFAULT_PTHREAD_POLICY (IS_ENABLED(CONFIG_PREEMPT_ENABLED) ? SCHED_RR : SCHED_FIFO) +#define PTHREAD_STACK_MAX BIT(CONFIG_POSIX_PTHREAD_ATTR_STACKSIZE_BITS) +#define PTHREAD_GUARD_MAX BIT_MASK(CONFIG_POSIX_PTHREAD_ATTR_GUARDSIZE_BITS) + LOG_MODULE_REGISTER(pthread, CONFIG_PTHREAD_LOG_LEVEL); #ifdef CONFIG_DYNAMIC_THREAD_STACK_SIZE @@ -37,28 +40,14 @@ LOG_MODULE_REGISTER(pthread, CONFIG_PTHREAD_LOG_LEVEL); #define DYNAMIC_STACK_SIZE 0 #endif -/* The maximum allowed stack size (for this implementation) */ -#define PTHREAD_STACK_MAX (UINT16_MAX + 1) - -static inline size_t __get_attr_stacksize(const struct pthread_attr *attr) +static inline size_t __get_attr_stacksize(const struct posix_thread_attr *attr) { return attr->stacksize + 1; } -static inline void __set_attr_stacksize(struct pthread_attr *attr, size_t size) -{ - attr->stacksize = size - 1; -} - -static inline size_t __get_attr_guardsize(const struct pthread_attr *attr) +static inline void __set_attr_stacksize(struct posix_thread_attr *attr, size_t stacksize) { - return (attr->guardsize_msbit * BIT(16)) | attr->guardsize; -} - -static inline void __set_attr_guardsize(struct pthread_attr *attr, size_t size) -{ - attr->guardsize_msbit = size == PTHREAD_STACK_MAX; - attr->guardsize = size & BIT_MASK(16); + attr->stacksize = stacksize - 1; } struct __pthread_cleanup { @@ -76,7 +65,7 @@ enum posix_thread_qid { POSIX_THREAD_DONE_Q, }; -/* only 2 bits in struct pthread_attr for schedpolicy */ +/* only 2 bits in struct posix_thread_attr for schedpolicy */ BUILD_ASSERT(SCHED_OTHER < BIT(2) && SCHED_FIFO < BIT(2) && SCHED_RR < BIT(2)); BUILD_ASSERT((PTHREAD_CREATE_DETACHED == 0 || PTHREAD_CREATE_JOINABLE == 0) && @@ -85,6 +74,9 @@ BUILD_ASSERT((PTHREAD_CREATE_DETACHED == 0 || PTHREAD_CREATE_JOINABLE == 0) && BUILD_ASSERT((PTHREAD_CANCEL_ENABLE == 0 || PTHREAD_CANCEL_DISABLE == 0) && (PTHREAD_CANCEL_ENABLE == 1 || PTHREAD_CANCEL_DISABLE == 1)); +BUILD_ASSERT(CONFIG_POSIX_PTHREAD_ATTR_STACKSIZE_BITS + CONFIG_POSIX_PTHREAD_ATTR_GUARDSIZE_BITS <= + 32); + static void posix_thread_recycle(void); static sys_dlist_t ready_q = SYS_DLIST_STATIC_INIT(&ready_q); static sys_dlist_t run_q = SYS_DLIST_STATIC_INIT(&run_q); @@ -93,18 +85,6 @@ static struct posix_thread posix_thread_pool[CONFIG_MAX_PTHREAD_COUNT]; static struct k_spinlock pthread_pool_lock; static int pthread_concurrency; -static const struct pthread_attr init_pthread_attrs = { - .stack = NULL, - .stacksize = 0, - .guardsize = (BIT_MASK(16) & CONFIG_POSIX_PTHREAD_ATTR_GUARDSIZE_DEFAULT), - .priority = DEFAULT_PTHREAD_PRIORITY, - .schedpolicy = DEFAULT_PTHREAD_POLICY, - .guardsize_msbit = (BIT(16) & CONFIG_POSIX_PTHREAD_ATTR_GUARDSIZE_DEFAULT), - .initialized = true, - .cancelstate = PTHREAD_CANCEL_ENABLE, - .detachstate = PTHREAD_CREATE_JOINABLE, -}; - /* * We reserve the MSB to mark a pthread_t as initialized (from the * perspective of the application). With a linear space, this means that @@ -262,7 +242,7 @@ static int32_t posix_to_zephyr_priority(uint32_t priority, int policy) */ int pthread_attr_setschedparam(pthread_attr_t *_attr, const struct sched_param *schedparam) { - struct pthread_attr *attr = (struct pthread_attr *)_attr; + struct posix_thread_attr *attr = (struct posix_thread_attr *)_attr; int priority = schedparam->sched_priority; if (attr == NULL || !attr->initialized || @@ -282,7 +262,7 @@ int pthread_attr_setschedparam(pthread_attr_t *_attr, const struct sched_param * */ int pthread_attr_setstack(pthread_attr_t *_attr, void *stackaddr, size_t stacksize) { - struct pthread_attr *attr = (struct pthread_attr *)_attr; + struct posix_thread_attr *attr = (struct posix_thread_attr *)_attr; if (stackaddr == NULL) { LOG_ERR("NULL stack address"); @@ -299,7 +279,7 @@ int pthread_attr_setstack(pthread_attr_t *_attr, void *stackaddr, size_t stacksi return 0; } -static bool pthread_attr_is_valid(const struct pthread_attr *attr) +static bool pthread_attr_is_valid(const struct posix_thread_attr *attr) { /* auto-alloc thread stack */ if (attr == NULL) { @@ -438,8 +418,8 @@ int pthread_create(pthread_t *th, const pthread_attr_t *_attr, void *(*threadrou k_spinlock_key_t key; pthread_barrier_t barrier; struct posix_thread *t = NULL; - struct pthread_attr attr_storage = init_pthread_attrs; - struct pthread_attr *attr = (struct pthread_attr *)_attr; + struct posix_thread_attr attr_storage; + struct posix_thread_attr *attr = (struct posix_thread_attr *)_attr; if (!pthread_attr_is_valid(attr)) { return EINVAL; @@ -447,10 +427,10 @@ int pthread_create(pthread_t *th, const pthread_attr_t *_attr, void *(*threadrou if (attr == NULL) { attr = &attr_storage; + (void)pthread_attr_init((pthread_attr_t *)attr); BUILD_ASSERT(DYNAMIC_STACK_SIZE <= PTHREAD_STACK_MAX); __set_attr_stacksize(attr, DYNAMIC_STACK_SIZE); - attr->stack = k_thread_stack_alloc(__get_attr_stacksize(attr) + - __get_attr_guardsize(attr), + attr->stack = k_thread_stack_alloc(__get_attr_stacksize(attr) + attr->guardsize, k_is_user_context() ? K_USER : 0); if (attr->stack == NULL) { LOG_ERR("Unable to allocate stack of size %u", DYNAMIC_STACK_SIZE); @@ -505,7 +485,7 @@ int pthread_create(pthread_t *th, const pthread_attr_t *_attr, void *(*threadrou } /* spawn the thread */ - k_thread_create(&t->thread, attr->stack, attr->stacksize, zephyr_thread_wrapper, + k_thread_create(&t->thread, attr->stack, __get_attr_stacksize(attr), zephyr_thread_wrapper, (void *)arg, threadroutine, IS_ENABLED(CONFIG_PTHREAD_CREATE_BARRIER) ? UINT_TO_POINTER(barrier) : NULL, posix_to_zephyr_priority(attr->priority, attr->schedpolicy), 0, K_NO_WAIT); @@ -680,14 +660,16 @@ int pthread_setschedparam(pthread_t pthread, int policy, const struct sched_para */ int pthread_attr_init(pthread_attr_t *_attr) { - struct pthread_attr *const attr = (struct pthread_attr *)_attr; + struct posix_thread_attr *const attr = (struct posix_thread_attr *)_attr; if (attr == NULL) { LOG_ERR("Invalid attr pointer"); return ENOMEM; } - (void)memcpy(attr, &init_pthread_attrs, sizeof(struct pthread_attr)); + *attr = (struct posix_thread_attr){0}; + attr->guardsize = CONFIG_POSIX_PTHREAD_ATTR_GUARDSIZE_DEFAULT; + attr->initialized = true; return 0; } @@ -883,7 +865,7 @@ int pthread_detach(pthread_t pthread) */ int pthread_attr_getdetachstate(const pthread_attr_t *_attr, int *detachstate) { - const struct pthread_attr *attr = (const struct pthread_attr *)_attr; + const struct posix_thread_attr *attr = (const struct posix_thread_attr *)_attr; if ((attr == NULL) || (attr->initialized == false)) { return EINVAL; @@ -900,7 +882,7 @@ int pthread_attr_getdetachstate(const pthread_attr_t *_attr, int *detachstate) */ int pthread_attr_setdetachstate(pthread_attr_t *_attr, int detachstate) { - struct pthread_attr *attr = (struct pthread_attr *)_attr; + struct posix_thread_attr *attr = (struct posix_thread_attr *)_attr; if ((attr == NULL) || (attr->initialized == false) || ((detachstate != PTHREAD_CREATE_DETACHED) && @@ -919,7 +901,7 @@ int pthread_attr_setdetachstate(pthread_attr_t *_attr, int detachstate) */ int pthread_attr_getschedpolicy(const pthread_attr_t *_attr, int *policy) { - const struct pthread_attr *attr = (const struct pthread_attr *)_attr; + const struct posix_thread_attr *attr = (const struct posix_thread_attr *)_attr; if ((attr == NULL) || (attr->initialized == 0U)) { return EINVAL; @@ -936,7 +918,7 @@ int pthread_attr_getschedpolicy(const pthread_attr_t *_attr, int *policy) */ int pthread_attr_setschedpolicy(pthread_attr_t *_attr, int policy) { - struct pthread_attr *attr = (struct pthread_attr *)_attr; + struct posix_thread_attr *attr = (struct posix_thread_attr *)_attr; if ((attr == NULL) || (attr->initialized == 0U) || !valid_posix_policy(policy)) { return EINVAL; @@ -953,7 +935,7 @@ int pthread_attr_setschedpolicy(pthread_attr_t *_attr, int policy) */ int pthread_attr_getstacksize(const pthread_attr_t *_attr, size_t *stacksize) { - const struct pthread_attr *attr = (const struct pthread_attr *)_attr; + const struct posix_thread_attr *attr = (const struct posix_thread_attr *)_attr; if ((attr == NULL) || (attr->initialized == false)) { return EINVAL; @@ -970,7 +952,7 @@ int pthread_attr_getstacksize(const pthread_attr_t *_attr, size_t *stacksize) */ int pthread_attr_setstacksize(pthread_attr_t *_attr, size_t stacksize) { - struct pthread_attr *attr = (struct pthread_attr *)_attr; + struct posix_thread_attr *attr = (struct posix_thread_attr *)_attr; if ((attr == NULL) || (attr->initialized == 0U)) { return EINVAL; @@ -991,7 +973,7 @@ int pthread_attr_setstacksize(pthread_attr_t *_attr, size_t stacksize) */ int pthread_attr_getstack(const pthread_attr_t *_attr, void **stackaddr, size_t *stacksize) { - const struct pthread_attr *attr = (const struct pthread_attr *)_attr; + const struct posix_thread_attr *attr = (const struct posix_thread_attr *)_attr; if ((attr == NULL) || (attr->initialized == false)) { return EINVAL; @@ -1004,26 +986,26 @@ int pthread_attr_getstack(const pthread_attr_t *_attr, void **stackaddr, size_t int pthread_attr_getguardsize(const pthread_attr_t *ZRESTRICT _attr, size_t *ZRESTRICT guardsize) { - struct pthread_attr *const attr = (struct pthread_attr *)_attr; + struct posix_thread_attr *const attr = (struct posix_thread_attr *)_attr; if (attr == NULL || guardsize == NULL || !attr->initialized) { return EINVAL; } - *guardsize = __get_attr_guardsize(attr); + *guardsize = attr->guardsize; return 0; } int pthread_attr_setguardsize(pthread_attr_t *_attr, size_t guardsize) { - struct pthread_attr *const attr = (struct pthread_attr *)_attr; + struct posix_thread_attr *const attr = (struct posix_thread_attr *)_attr; - if (attr == NULL || !attr->initialized || guardsize > PTHREAD_STACK_MAX) { + if (attr == NULL || !attr->initialized || guardsize > PTHREAD_GUARD_MAX) { return EINVAL; } - __set_attr_guardsize(attr, guardsize); + attr->guardsize = guardsize; return 0; } @@ -1035,7 +1017,7 @@ int pthread_attr_setguardsize(pthread_attr_t *_attr, size_t guardsize) */ int pthread_attr_getschedparam(const pthread_attr_t *_attr, struct sched_param *schedparam) { - struct pthread_attr *attr = (struct pthread_attr *)_attr; + struct posix_thread_attr *attr = (struct posix_thread_attr *)_attr; if ((attr == NULL) || (attr->initialized == false)) { return EINVAL; @@ -1052,7 +1034,7 @@ int pthread_attr_getschedparam(const pthread_attr_t *_attr, struct sched_param * */ int pthread_attr_destroy(pthread_attr_t *_attr) { - struct pthread_attr *attr = (struct pthread_attr *)_attr; + struct posix_thread_attr *attr = (struct posix_thread_attr *)_attr; if ((attr != NULL) && (attr->initialized != 0U)) { attr->initialized = false; From b702c8e8f01f09cb73ef554b129db0773f9f98a5 Mon Sep 17 00:00:00 2001 From: Christopher Friedt Date: Fri, 22 Dec 2023 15:03:25 -0500 Subject: [PATCH 1572/3723] tests: posix: pthread: test that big stacks can be allocated In some cases, users want to allocate (comparatively) massive thread stacks. Add a test to ensure we can allocate such a stack by default. Signed-off-by: Christopher Friedt --- tests/posix/common/src/pthread.c | 20 ++++++++++++++++++-- 1 file changed, 18 insertions(+), 2 deletions(-) diff --git a/tests/posix/common/src/pthread.c b/tests/posix/common/src/pthread.c index cdaed3eba2e..f8fe650ceeb 100644 --- a/tests/posix/common/src/pthread.c +++ b/tests/posix/common/src/pthread.c @@ -18,7 +18,7 @@ #define ONE_SECOND 1 /* arbitrary number that is also a legal stack size */ -#define OKAY_STACK_SIZE (STACKS + 42) +#define OKAY_STACK_SIZE (STACKS + 1) /* Macros to test invalid states */ #define PTHREAD_CANCEL_INVALID -1 @@ -959,11 +959,14 @@ ZTEST(posix_apis, test_pthread_attr_setguardsize) size_t size_after; size_t size_before; pthread_attr_t attr; - size_t sizes[] = {0, OKAY_STACK_SIZE, UINT16_MAX}; + size_t sizes[] = {0, BIT_MASK(CONFIG_POSIX_PTHREAD_ATTR_GUARDSIZE_BITS / 2), + BIT_MASK(CONFIG_POSIX_PTHREAD_ATTR_GUARDSIZE_BITS)}; attr = (pthread_attr_t){0}; zassert_equal(pthread_attr_setguardsize(&attr, 0), EINVAL); zassert_ok(pthread_attr_init(&attr)); + zassert_ok(pthread_attr_getguardsize(&attr, &size_before)); + zassert_equal(size_before, CONFIG_POSIX_PTHREAD_ATTR_GUARDSIZE_DEFAULT); zassert_equal(pthread_attr_setguardsize(NULL, SIZE_MAX), EINVAL); zassert_equal(pthread_attr_setguardsize(NULL, 0), EINVAL); zassert_equal(pthread_attr_setguardsize(&attr, SIZE_MAX), EINVAL); @@ -976,3 +979,16 @@ ZTEST(posix_apis, test_pthread_attr_setguardsize) } zassert_ok(pthread_attr_destroy(&attr)); } + +ZTEST(posix_apis, test_pthread_attr_large_stacksize) +{ + size_t actual_size; + const size_t expect_size = BIT(CONFIG_POSIX_PTHREAD_ATTR_STACKSIZE_BITS); + pthread_attr_t attr; + + zassert_ok(pthread_attr_init(&attr)); + zassert_ok(pthread_attr_setstacksize(&attr, expect_size)); + zassert_ok(pthread_attr_getstacksize(&attr, &actual_size)); + zassert_equal(actual_size, expect_size); + zassert_ok(pthread_attr_destroy(&attr)); +} From 2312897055d19ce11ddfa496052e400afb8893f4 Mon Sep 17 00:00:00 2001 From: Rodrigo Peixoto Date: Sun, 24 Dec 2023 12:13:56 -0300 Subject: [PATCH 1573/3723] Build System: clang-format: add K_SPINLOCK to FOR_EACH The K_SPINLOCK is been indented wrongly by clang-format. It fixes that adding the K_SPINLOCK to the FOR_EACH section rule tells the formatter to follow the rule to indent the code. Signed-off-by: Rodrigo Peixoto --- .clang-format | 1 + 1 file changed, 1 insertion(+) diff --git a/.clang-format b/.clang-format index 603c00c59b1..15012747148 100644 --- a/.clang-format +++ b/.clang-format @@ -67,6 +67,7 @@ ForEachMacros: - 'Z_GENLIST_FOR_EACH_NODE_SAFE' - 'STRUCT_SECTION_FOREACH' - 'TYPE_SECTION_FOREACH' + - 'K_SPINLOCK' IfMacros: - 'CHECKIF' # Disabled for now, see bug https://github.com/zephyrproject-rtos/zephyr/issues/48520 From ff62faac072bf35a882cfbd49295d7c3cb37e544 Mon Sep 17 00:00:00 2001 From: Lucas Tamborrino Date: Thu, 21 Dec 2023 14:11:35 -0300 Subject: [PATCH 1574/3723] soc: xtensa: esp32s2/s3: remove HEAP_MEM_POOL_ADD_SIZE_SOC There is no need for this config here and it is messing with total sys heap calculation. Signed-off-by: Lucas Tamborrino --- soc/xtensa/espressif_esp32/esp32s2/Kconfig.defconfig.series | 3 --- soc/xtensa/espressif_esp32/esp32s3/Kconfig.defconfig.series | 3 --- 2 files changed, 6 deletions(-) diff --git a/soc/xtensa/espressif_esp32/esp32s2/Kconfig.defconfig.series b/soc/xtensa/espressif_esp32/esp32s2/Kconfig.defconfig.series index f3abfd5f017..177c5184e98 100644 --- a/soc/xtensa/espressif_esp32/esp32s2/Kconfig.defconfig.series +++ b/soc/xtensa/espressif_esp32/esp32s2/Kconfig.defconfig.series @@ -18,9 +18,6 @@ config MP_MAX_NUM_CPUS config ISR_STACK_SIZE default 2048 -config HEAP_MEM_POOL_ADD_SIZE_SOC - def_int 32768 - config ESPTOOLPY_FLASHFREQ_80M default y diff --git a/soc/xtensa/espressif_esp32/esp32s3/Kconfig.defconfig.series b/soc/xtensa/espressif_esp32/esp32s3/Kconfig.defconfig.series index 99de5f6661d..30d0480cad2 100644 --- a/soc/xtensa/espressif_esp32/esp32s3/Kconfig.defconfig.series +++ b/soc/xtensa/espressif_esp32/esp32s3/Kconfig.defconfig.series @@ -6,9 +6,6 @@ if SOC_SERIES_ESP32S3 config SOC_SERIES default "esp32s3" -config HEAP_MEM_POOL_ADD_SIZE_SOC - def_int 32768 - config MINIMAL_LIBC_OPTIMIZE_STRING_FOR_SIZE default n From 915f0fd74c6065b39ab84b2ecafce57000c822a7 Mon Sep 17 00:00:00 2001 From: Hang Fan Date: Sat, 23 Dec 2023 21:19:16 +0800 Subject: [PATCH 1575/3723] Bluetooth: Shell: Fix coverity issue in cmd_adv_data Fix wrong parameter type to avoid Unsigned compared against 0 Fixes: https://github.com/zephyrproject-rtos/zephyr/issues/65578 Signed-off-by: Hang Fan --- subsys/bluetooth/shell/bt.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/subsys/bluetooth/shell/bt.c b/subsys/bluetooth/shell/bt.c index ca3c7c3c0ea..e65e85262a7 100644 --- a/subsys/bluetooth/shell/bt.c +++ b/subsys/bluetooth/shell/bt.c @@ -2001,7 +2001,7 @@ static int cmd_adv_data(const struct shell *sh, size_t argc, char *argv[]) size_t hex_data_len; size_t ad_len = 0; size_t sd_len = 0; - size_t len = 0; + ssize_t len = 0; bool discoverable = false; size_t *data_len; int err; From 4e7950e4bd91c790422c2bbf3ec3b897d270420d Mon Sep 17 00:00:00 2001 From: Jerzy Kasenberg Date: Thu, 19 Oct 2023 12:00:39 +0200 Subject: [PATCH 1576/3723] drivers: hwinfo: implemented hardware info support for Smartbond Only reset cause is supported as there is no common unique id present on those chips. Unique ID can be put in OTP but there is no single specification for this. Signed-off-by: Jerzy Kasenberg --- boards/arm/da14695_dk_usb/da14695_dk_usb.yaml | 1 + boards/arm/da1469x_dk_pro/da1469x_dk_pro.yaml | 1 + drivers/hwinfo/CMakeLists.txt | 1 + drivers/hwinfo/Kconfig | 7 +++ drivers/hwinfo/hwinfo_smartbond.c | 63 +++++++++++++++++++ 5 files changed, 73 insertions(+) create mode 100644 drivers/hwinfo/hwinfo_smartbond.c diff --git a/boards/arm/da14695_dk_usb/da14695_dk_usb.yaml b/boards/arm/da14695_dk_usb/da14695_dk_usb.yaml index 1bb6100e339..bc55d5ada4d 100644 --- a/boards/arm/da14695_dk_usb/da14695_dk_usb.yaml +++ b/boards/arm/da14695_dk_usb/da14695_dk_usb.yaml @@ -10,6 +10,7 @@ toolchain: supported: - arduino_gpio - gpio + - hwinfo - watchdog - i2c - spi diff --git a/boards/arm/da1469x_dk_pro/da1469x_dk_pro.yaml b/boards/arm/da1469x_dk_pro/da1469x_dk_pro.yaml index e31a2749002..4d35304c622 100644 --- a/boards/arm/da1469x_dk_pro/da1469x_dk_pro.yaml +++ b/boards/arm/da1469x_dk_pro/da1469x_dk_pro.yaml @@ -11,6 +11,7 @@ supported: - arduino_gpio - counter - gpio + - hwinfo - watchdog - i2c - spi diff --git a/drivers/hwinfo/CMakeLists.txt b/drivers/hwinfo/CMakeLists.txt index 437fbf969cf..ab3b587dc75 100644 --- a/drivers/hwinfo/CMakeLists.txt +++ b/drivers/hwinfo/CMakeLists.txt @@ -25,5 +25,6 @@ zephyr_library_sources_ifdef(CONFIG_HWINFO_SAM_RSTC hwinfo_sam_rstc.c) zephyr_library_sources_ifdef(CONFIG_HWINFO_SAM hwinfo_sam.c) zephyr_library_sources_ifdef(CONFIG_HWINFO_SAM0 hwinfo_sam0.c) zephyr_library_sources_ifdef(CONFIG_HWINFO_SAM4L hwinfo_sam4l.c) +zephyr_library_sources_ifdef(CONFIG_HWINFO_SMARTBOND hwinfo_smartbond.c) zephyr_library_sources_ifdef(CONFIG_HWINFO_STM32 hwinfo_stm32.c) zephyr_library_sources_ifdef(CONFIG_HWINFO_ANDES hwinfo_andes.c) diff --git a/drivers/hwinfo/Kconfig b/drivers/hwinfo/Kconfig index 7c4cc7f0805..f293ab60b7f 100644 --- a/drivers/hwinfo/Kconfig +++ b/drivers/hwinfo/Kconfig @@ -149,6 +149,13 @@ config HWINFO_SAM0 help Enable Atmel SAM0 hwinfo driver. +config HWINFO_SMARTBOND + bool "Smartbond device reset cause" + default y + depends on SOC_FAMILY_SMARTBOND + help + Enable Smartbond reset cause hwinfo driver. + config HWINFO_ESP32 bool "ESP32 device ID" default y diff --git a/drivers/hwinfo/hwinfo_smartbond.c b/drivers/hwinfo/hwinfo_smartbond.c new file mode 100644 index 00000000000..f19c7770d60 --- /dev/null +++ b/drivers/hwinfo/hwinfo_smartbond.c @@ -0,0 +1,63 @@ +/* + * Copyright (c) 2023 Jerzy Kasenberg. + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include +#include +#include + +int z_impl_hwinfo_get_reset_cause(uint32_t *cause) +{ + int ret = 0; + uint32_t reason = CRG_TOP->RESET_STAT_REG; + uint32_t flags = 0; + + /* + * When POR is detected other bits are not valid. + */ + if (reason & CRG_TOP_RESET_STAT_REG_PORESET_STAT_Msk) { + flags = RESET_POR; + } else { + if (reason & CRG_TOP_RESET_STAT_REG_HWRESET_STAT_Msk) { + flags |= RESET_PIN; + } + if (reason & CRG_TOP_RESET_STAT_REG_SWRESET_STAT_Msk) { + flags |= RESET_SOFTWARE; + } + if (reason & CRG_TOP_RESET_STAT_REG_WDOGRESET_STAT_Msk) { + flags |= RESET_WATCHDOG; + } + if (reason & CRG_TOP_RESET_STAT_REG_CMAC_WDOGRESET_STAT_Msk) { + flags |= RESET_WATCHDOG; + } + if (reason & CRG_TOP_RESET_STAT_REG_SWD_HWRESET_STAT_Msk) { + flags |= RESET_DEBUG; + } + } + + *cause = flags; + + return ret; +} + +int z_impl_hwinfo_clear_reset_cause(void) +{ + int ret = 0; + + CRG_TOP->RESET_STAT_REG = 0; + + return ret; +} + +int z_impl_hwinfo_get_supported_reset_cause(uint32_t *supported) +{ + *supported = (RESET_PIN + | RESET_SOFTWARE + | RESET_POR + | RESET_WATCHDOG + | RESET_DEBUG); + + return 0; +} From 501e67acd22c8b31b420fdfec4924efcde918b99 Mon Sep 17 00:00:00 2001 From: Mateusz Junkier Date: Wed, 15 Nov 2023 20:33:38 +0100 Subject: [PATCH 1577/3723] pm: increase coverage - add missing test assert cover missing lines reported by codecov Signed-off-by: Mateusz Junkier --- tests/subsys/pm/device_runtime_api/src/main.c | 1 + 1 file changed, 1 insertion(+) diff --git a/tests/subsys/pm/device_runtime_api/src/main.c b/tests/subsys/pm/device_runtime_api/src/main.c index 2288d64675a..f2b21aaabd5 100644 --- a/tests/subsys/pm/device_runtime_api/src/main.c +++ b/tests/subsys/pm/device_runtime_api/src/main.c @@ -270,6 +270,7 @@ ZTEST(device_runtime_api, test_unsupported) zassert_equal(pm_device_runtime_disable(dev), -ENOTSUP, ""); zassert_equal(pm_device_runtime_get(dev), 0, ""); zassert_equal(pm_device_runtime_put(dev), 0, ""); + zassert_false(pm_device_runtime_put_async(dev), ""); } int dev_pm_control(const struct device *dev, enum pm_device_action action) From 949e5120d3f8234d43a60c4b0e760e7ff30b38bb Mon Sep 17 00:00:00 2001 From: Mateusz Junkier Date: Wed, 15 Nov 2023 22:00:09 +0100 Subject: [PATCH 1578/3723] pm: increase coverage - add missing api tests add missing api tests reported by codecov Signed-off-by: Mateusz Junkier --- tests/subsys/pm/device_runtime_api/src/main.c | 2 +- tests/subsys/pm/power_mgmt/src/main.c | 27 +++++++++++++++++++ 2 files changed, 28 insertions(+), 1 deletion(-) diff --git a/tests/subsys/pm/device_runtime_api/src/main.c b/tests/subsys/pm/device_runtime_api/src/main.c index f2b21aaabd5..186ad7e6c78 100644 --- a/tests/subsys/pm/device_runtime_api/src/main.c +++ b/tests/subsys/pm/device_runtime_api/src/main.c @@ -270,7 +270,7 @@ ZTEST(device_runtime_api, test_unsupported) zassert_equal(pm_device_runtime_disable(dev), -ENOTSUP, ""); zassert_equal(pm_device_runtime_get(dev), 0, ""); zassert_equal(pm_device_runtime_put(dev), 0, ""); - zassert_false(pm_device_runtime_put_async(dev), ""); + zassert_false(pm_device_runtime_put_async(dev, K_NO_WAIT), ""); } int dev_pm_control(const struct device *dev, enum pm_device_action action) diff --git a/tests/subsys/pm/power_mgmt/src/main.c b/tests/subsys/pm/power_mgmt/src/main.c index 7931386c4ec..4cd219ed5c3 100644 --- a/tests/subsys/pm/power_mgmt/src/main.c +++ b/tests/subsys/pm/power_mgmt/src/main.c @@ -27,7 +27,9 @@ static bool idle_entered; static bool testing_device_runtime; static bool testing_device_order; static bool testing_device_lock; +static bool testing_force_state; +enum pm_state forced_state; static const struct device *device_dummy; static struct dummy_driver_api *api; @@ -180,6 +182,12 @@ void pm_state_set(enum pm_state state, uint8_t substate_id) return; } + if (testing_force_state) { + /* if forced to given power state was called */ + set_pm = true; + zassert_equal(state, forced_state, NULL); + testing_force_state = false; + } /* at this point, notify_pm_state_entry() implemented in * this file has been called and set_pm should have been set @@ -444,6 +452,25 @@ ZTEST(power_management_1cpu, test_device_state_lock) testing_device_lock = false; } +ZTEST(power_management_1cpu, test_empty_states) +{ + const struct pm_state_info *cpu_states; + uint8_t state = pm_state_cpu_get_all(1u, &cpu_states); + + zassert_equal(state, 0, NULL); +} + +ZTEST(power_management_1cpu, test_force_state) +{ + forced_state = PM_STATE_STANDBY; + bool ret = pm_state_force(0, &(struct pm_state_info) {forced_state, 0, 0}); + + zassert_equal(ret, true, "Error in force state"); + + testing_force_state = true; + k_sleep(K_SECONDS(1U)); +} + void power_management_1cpu_teardown(void *data) { pm_notifier_unregister(¬ifier); From fa25c0b0b8842cdec386d1a40081bd6d3e66519f Mon Sep 17 00:00:00 2001 From: Daniel Leung Date: Fri, 1 Dec 2023 16:51:46 -0800 Subject: [PATCH 1579/3723] xtensa: mmu: invalidate mem domain TLBs during page table swap This adds a kconfig to enable invalidating the TLBs related to the incoming thread's memory domain during page table swaps. It provides a workaround, if needed, to clear out stale TLB entries used by the thread being swapped out. Those stale entries may contain incorrect permissions and rings. Signed-off-by: Daniel Leung --- arch/xtensa/Kconfig | 6 ++++++ arch/xtensa/core/ptables.c | 13 +++++++++++++ 2 files changed, 19 insertions(+) diff --git a/arch/xtensa/Kconfig b/arch/xtensa/Kconfig index 4f7643b0cff..aa888e8331a 100644 --- a/arch/xtensa/Kconfig +++ b/arch/xtensa/Kconfig @@ -153,6 +153,12 @@ config XTENSA_MMU_DOUBLE_MAP This option specifies that the memory is mapped in two distinct region, cached and uncached. + config XTENSA_INVALIDATE_MEM_DOMAIN_TLB_ON_SWAP + bool + help + This invalidates all TLBs referred by the incoming thread's + memory domain when swapping page tables. + endif # XTENSA_MMU config XTENSA_SYSCALL_USE_HELPER diff --git a/arch/xtensa/core/ptables.c b/arch/xtensa/core/ptables.c index b6d81e21db1..ec8295f6144 100644 --- a/arch/xtensa/core/ptables.c +++ b/arch/xtensa/core/ptables.c @@ -1095,6 +1095,19 @@ void xtensa_swap_update_page_tables(struct k_thread *incoming) &(incoming->mem_domain_info.mem_domain->arch); xtensa_set_paging(domain->asid, ptables); + +#ifdef CONFIG_XTENSA_INVALIDATE_MEM_DOMAIN_TLB_ON_SWAP + struct k_mem_domain *mem_domain = incoming->mem_domain_info.mem_domain; + + for (int idx = 0; idx < mem_domain->num_partitions; idx++) { + struct k_mem_partition *part = &mem_domain->partitions[idx]; + uintptr_t end = part->start + part->size; + + for (uintptr_t addr = part->start; addr < end; addr += CONFIG_MMU_PAGE_SIZE) { + xtensa_dtlb_vaddr_invalidate((void *)addr); + } + } +#endif } #endif /* CONFIG_USERSPACE */ From debb9f63523d27439be1ee5899561ce4944019bf Mon Sep 17 00:00:00 2001 From: Daniel Leung Date: Fri, 1 Dec 2023 17:14:31 -0800 Subject: [PATCH 1580/3723] xtensa: dc233c: force invalidating TLBs during page table swap QEMU MMU tracing showed that there might be something wrong with its Xtensa MMU implementation, which result in access violation when running samples/userspace/hello_world_user. Here is the MMU trace from QEMU from failed runs: get_pte: autorefill(00109020): PTE va = 20000424, pa = 0010c424 get_physical_addr_mmu: autorefill(00109020): 00109000 -> 00109006 xtensa_cpu_tlb_fill(00109020, 1, 0) -> 00109020, ret = 0 xtensa_cpu_tlb_fill(00109028, 1, 0) -> 00109028, ret = 0 xtensa_cpu_tlb_fill(00109014, 0, 2) -> 00103050, ret = 26 The place where it fails is during reading from 0x109014. From the trace above, the auto-refill maps 0x109000 correctly with ring 0 and RW access with WB cache (which should be correct the first time under kernel mode). The page 0x109000 is the libc partition which needs to be accessible from user thread. However, when accessing that page, the returned physical address became 0x103050 (and resulting in load/store access violation). We always identity map memory pages so it should never return a different physical address. After forcing TLB invalidation during page table swaps, the MMU trace is: get_pte: autorefill(00109020): PTE va = 20000424, pa = 0010c424 get_physical_addr_mmu: autorefill(00109020): 00109000 -> 00109006 xtensa_cpu_tlb_fill(00109020, 1, 0) -> 00109020, ret = 0 get_pte: autorefill(00109028): PTE va = 21000424, pa = 0010e424 get_physical_addr_mmu: autorefill(00109028): 00109000 -> 00109022 xtensa_cpu_tlb_fill(00109028, 1, 0) -> 00109028, ret = 0 get_pte: autorefill(00109014): PTE va = 21000424, pa = 0010e424 get_physical_addr_mmu: autorefill(00109014): 00109000 -> 00109022 xtensa_cpu_tlb_fill(00109014, 0, 2) -> 00109014, ret = 0 xtensa_cpu_tlb_fill(00109020, 0, 0) -> 00109020, ret = 0 Here, when the same page is accessed, it got the correct PTE entry, which is ring 2 with RW access mode (but no cache). Actually accessing the variable via virtual address returns the correct physical address: 0x109014. So workaround that by forcing TLB invalidation during page swap. Fixes #66029 Signed-off-by: Daniel Leung --- soc/xtensa/dc233c/Kconfig.soc | 1 + 1 file changed, 1 insertion(+) diff --git a/soc/xtensa/dc233c/Kconfig.soc b/soc/xtensa/dc233c/Kconfig.soc index aac2fb89fbb..ecbe77a9feb 100644 --- a/soc/xtensa/dc233c/Kconfig.soc +++ b/soc/xtensa/dc233c/Kconfig.soc @@ -12,3 +12,4 @@ config SOC_XTENSA_DC233C select CPU_HAS_MMU select ARCH_HAS_RESERVED_PAGE_FRAMES if XTENSA_MMU select ARCH_HAS_USERSPACE if XTENSA_MMU + select XTENSA_INVALIDATE_MEM_DOMAIN_TLB_ON_SWAP if XTENSA_MMU From d64ce2531d152de54300119c662d2f5f26a74908 Mon Sep 17 00:00:00 2001 From: Dawid Niedzwiecki Date: Wed, 6 Dec 2023 08:29:16 +0100 Subject: [PATCH 1581/3723] mgmt: ec_host_cmd: add PM for SPI STM32 backend The SPI STM32 Host Command backend doesn't use general SPI driver, so it has to implement Power Management on its own. The suspend procedure includes: setting pins to the sleep state, disabling device clock and disabling CS pin interrupt. Signed-off-by: Dawid Niedzwiecki --- .../backends/ec_host_cmd_backend_spi_stm32.c | 107 +++++++++++++++++- 1 file changed, 106 insertions(+), 1 deletion(-) diff --git a/subsys/mgmt/ec_host_cmd/backends/ec_host_cmd_backend_spi_stm32.c b/subsys/mgmt/ec_host_cmd/backends/ec_host_cmd_backend_spi_stm32.c index 52ee12ea0fd..55a58ad6627 100644 --- a/subsys/mgmt/ec_host_cmd/backends/ec_host_cmd_backend_spi_stm32.c +++ b/subsys/mgmt/ec_host_cmd/backends/ec_host_cmd_backend_spi_stm32.c @@ -15,6 +15,7 @@ LOG_MODULE_REGISTER(host_cmd_spi, CONFIG_EC_HC_LOG_LEVEL); #include +#include #include #include #include @@ -23,6 +24,9 @@ LOG_MODULE_REGISTER(host_cmd_spi, CONFIG_EC_HC_LOG_LEVEL); #include #include #include +#include +#include +#include #include /* The default compatible string of a SPI devicetree node has to be replaced with the one @@ -159,6 +163,9 @@ struct ec_host_cmd_spi_ctx { struct dma_stream *dma_tx; enum spi_host_command_state state; int prepare_rx_later; +#ifdef CONFIG_PM + ATOMIC_DEFINE(pm_policy_lock_on, 1); +#endif /* CONFIG_PM */ }; static const uint8_t out_preamble[4] = { @@ -260,6 +267,32 @@ static int expected_size(const struct ec_host_cmd_request_header *header) return sizeof(*header) + header->data_len; } +#ifdef CONFIG_PM +static void ec_host_cmd_pm_policy_state_lock_get(struct ec_host_cmd_spi_ctx *hc_spi) +{ + if (!atomic_test_and_set_bit(hc_spi->pm_policy_lock_on, 0)) { + pm_policy_state_lock_get(PM_STATE_SUSPEND_TO_IDLE, PM_ALL_SUBSTATES); + } +} + +static void ec_host_cmd_pm_policy_state_lock_put(struct ec_host_cmd_spi_ctx *hc_spi) +{ + if (atomic_test_and_clear_bit(hc_spi->pm_policy_lock_on, 0)) { + pm_policy_state_lock_put(PM_STATE_SUSPEND_TO_IDLE, PM_ALL_SUBSTATES); + } +} +#else +static inline void ec_host_cmd_pm_policy_state_lock_get(struct ec_host_cmd_spi_ctx *hc_spi) +{ + ARG_UNUSED(hc_spi); +} + +static void ec_host_cmd_pm_policy_state_lock_put(struct ec_host_cmd_spi_ctx *hc_spi) +{ + ARG_UNUSED(hc_spi); +} +#endif /* CONFIG_PM */ + static void dma_callback(const struct device *dev, void *arg, uint32_t channel, int status) { struct ec_host_cmd_spi_ctx *hc_spi = arg; @@ -588,8 +621,10 @@ void gpio_cb_nss(const struct device *port, struct gpio_callback *cb, gpio_port_ SPI_TypeDef *spi = cfg->spi; int ret; - /* CS deasserted. Setup fo the next transaction */ + /* CS deasserted. Setup for the next transaction */ if (gpio_pin_get(hc_spi->cs.port, hc_spi->cs.pin)) { + ec_host_cmd_pm_policy_state_lock_put(hc_spi); + /* CS asserted during processing a command. Prepare for receiving after * sending response. */ @@ -616,6 +651,8 @@ void gpio_cb_nss(const struct device *port, struct gpio_callback *cb, gpio_port_ int exp_size; hc_spi->state = SPI_HOST_CMD_STATE_RECEIVING; + /* Don't allow system to suspend until the end of transfer. */ + ec_host_cmd_pm_policy_state_lock_get(hc_spi); /* Set TX register to send status */ tx_status(spi, EC_SPI_RECEIVING); @@ -745,6 +782,74 @@ struct ec_host_cmd_backend *ec_host_cmd_backend_get_spi(struct gpio_dt_spec *cs) return &ec_host_cmd_spi; } +#ifdef CONFIG_PM_DEVICE +static int ec_host_cmd_spi_stm32_pm_action(const struct device *dev, + enum pm_device_action action) +{ + const struct ec_host_cmd_backend *backend = (struct ec_host_cmd_backend *)dev->data; + struct ec_host_cmd_spi_ctx *hc_spi = (struct ec_host_cmd_spi_ctx *)backend->ctx; + const struct ec_host_cmd_spi_cfg *cfg = hc_spi->spi_config; + int err; + + switch (action) { + case PM_DEVICE_ACTION_RESUME: + /* Set pins to active state */ + err = pinctrl_apply_state(cfg->pcfg, PINCTRL_STATE_DEFAULT); + if (err < 0) { + return err; + } + + /* Enable device clock */ + err = clock_control_on(DEVICE_DT_GET(STM32_CLOCK_CONTROL_NODE), + (clock_control_subsys_t)&cfg->pclken[0]); + if (err < 0) { + return err; + } + /* Enable CS interrupts. */ + gpio_pin_interrupt_configure_dt(&hc_spi->cs, GPIO_INT_EDGE_BOTH); + + break; + case PM_DEVICE_ACTION_SUSPEND: +#ifdef SPI_SR_BSY + /* Wait 10ms for the end of transaction to prevent corruption of the last + * transfer + */ + WAIT_FOR((LL_SPI_IsActiveFlag_BSY(cfg->spi) == 0), 10 * USEC_PER_MSEC, NULL); +#endif + /* Disable unnecessary interrupts. */ + gpio_pin_interrupt_configure_dt(&hc_spi->cs, GPIO_INT_DISABLE); + + /* Stop device clock. */ + err = clock_control_off(DEVICE_DT_GET(STM32_CLOCK_CONTROL_NODE), + (clock_control_subsys_t)&cfg->pclken[0]); + if (err != 0) { + return err; + } + + /* Move pins to sleep state */ + err = pinctrl_apply_state(cfg->pcfg, PINCTRL_STATE_SLEEP); + if ((err < 0) && (err != -ENOENT)) { + /* If returning -ENOENT, no pins where defined for sleep mode. */ + return err; + } + + break; + default: + return -ENOTSUP; + } + + return 0; +} +#endif /* CONFIG_PM_DEVICE */ + +PM_DEVICE_DT_DEFINE(DT_CHOSEN(zephyr_host_cmd_spi_backend), ec_host_cmd_spi_stm32_pm_action); + +DEVICE_DT_DEFINE(DT_CHOSEN(zephyr_host_cmd_spi_backend), + NULL, + PM_DEVICE_DT_GET(DT_CHOSEN(zephyr_host_cmd_spi_backend)), + &ec_host_cmd_spi, NULL, + PRE_KERNEL_1, CONFIG_EC_HOST_CMD_INIT_PRIORITY, NULL); + #ifdef CONFIG_EC_HOST_CMD_INITIALIZE_AT_BOOT static int host_cmd_init(void) { From c2266dd3a0c7bd43beb9509b8ded8ed5af8d388b Mon Sep 17 00:00:00 2001 From: Ian Wakely Date: Sun, 3 Dec 2023 20:29:16 -0500 Subject: [PATCH 1582/3723] board: Adding support for W5500 Eval Board. The W5500_EVB_PICO is an evaluation board for the Wiznet W5500 ethernet mac/phy based on the Raspberry Pi Pico. Signed-off-by: Ian Wakely --- boards/arm/w5500_evb_pico/Kconfig.board | 7 + boards/arm/w5500_evb_pico/Kconfig.defconfig | 30 ++ boards/arm/w5500_evb_pico/board.cmake | 36 +++ .../doc/img/w5500_evb_pico_side.png | Bin 0 -> 40108 bytes boards/arm/w5500_evb_pico/doc/index.rst | 293 ++++++++++++++++++ boards/arm/w5500_evb_pico/support/openocd.cfg | 11 + .../w5500_evb_pico-pinctrl.dtsi | 60 ++++ boards/arm/w5500_evb_pico/w5500_evb_pico.dts | 194 ++++++++++++ boards/arm/w5500_evb_pico/w5500_evb_pico.yaml | 23 ++ .../w5500_evb_pico/w5500_evb_pico_defconfig | 14 + 10 files changed, 668 insertions(+) create mode 100644 boards/arm/w5500_evb_pico/Kconfig.board create mode 100644 boards/arm/w5500_evb_pico/Kconfig.defconfig create mode 100644 boards/arm/w5500_evb_pico/board.cmake create mode 100644 boards/arm/w5500_evb_pico/doc/img/w5500_evb_pico_side.png create mode 100644 boards/arm/w5500_evb_pico/doc/index.rst create mode 100644 boards/arm/w5500_evb_pico/support/openocd.cfg create mode 100644 boards/arm/w5500_evb_pico/w5500_evb_pico-pinctrl.dtsi create mode 100644 boards/arm/w5500_evb_pico/w5500_evb_pico.dts create mode 100644 boards/arm/w5500_evb_pico/w5500_evb_pico.yaml create mode 100644 boards/arm/w5500_evb_pico/w5500_evb_pico_defconfig diff --git a/boards/arm/w5500_evb_pico/Kconfig.board b/boards/arm/w5500_evb_pico/Kconfig.board new file mode 100644 index 00000000000..9c863d899dc --- /dev/null +++ b/boards/arm/w5500_evb_pico/Kconfig.board @@ -0,0 +1,7 @@ +# Copyright (c) 2021 Yonatan Schachter +# Copyright (c) 2023 Ian Wakely +# SPDX-License-Identifier: Apache-2.0 + +config BOARD_W5500_EVB_PICO + bool "Wiznet W5500 Evaluation Board" + depends on SOC_RP2040 diff --git a/boards/arm/w5500_evb_pico/Kconfig.defconfig b/boards/arm/w5500_evb_pico/Kconfig.defconfig new file mode 100644 index 00000000000..5e569b40cc9 --- /dev/null +++ b/boards/arm/w5500_evb_pico/Kconfig.defconfig @@ -0,0 +1,30 @@ +# Copyright (c) 2021 Yonatan Schachter +# Copyright (c) 2023 Ian Wakely +# SPDX-License-Identifier: Apache-2.0 + +if BOARD_W5500_EVB_PICO + +config BOARD + default "w5500_evb_pico" if BOARD_W5500_EVB_PICO + +config RP2_FLASH_W25Q080 + default y + +if NETWORKING + +config NET_L2_ETHERNET + default y + +endif # NETWORKING + +if I2C_DW + +config I2C_DW_CLOCK_SPEED + default 125 + +endif #I2C_DW + +config USB_SELF_POWERED + default n + +endif # BOARD_W5500_EVB_PICO diff --git a/boards/arm/w5500_evb_pico/board.cmake b/boards/arm/w5500_evb_pico/board.cmake new file mode 100644 index 00000000000..e95d4d3767f --- /dev/null +++ b/boards/arm/w5500_evb_pico/board.cmake @@ -0,0 +1,36 @@ +# SPDX-License-Identifier: Apache-2.0 + +# This configuration allows selecting what debug adapter debugging w5500_evb_pico +# by a command-line argument. +# It is mainly intended to support both the 'picoprobe' and 'raspberrypi-swd' +# adapter described in "Getting started with Raspberry Pi Pico". +# And any other SWD debug adapter might also be usable with this configuration. + +# Set RPI_PICO_DEBUG_ADAPTER to select debug adapter by command-line arguments. +# e.g.) west build -b w5500_evb_pico -- -DRPI_PICO_DEBUG_ADAPTER=raspberrypi-swd +# The value is treated as a part of an interface file name that +# the debugger's configuration file. +# The value must be the 'stem' part of the name of one of the files +# in the openocd interface configuration file. +# The setting is store to CMakeCache.txt. +if ("${RPI_PICO_DEBUG_ADAPTER}" STREQUAL "") + set(RPI_PICO_DEBUG_ADAPTER "cmsis-dap") +endif() + +board_runner_args(openocd --cmd-pre-init "source [find interface/${RPI_PICO_DEBUG_ADAPTER}.cfg]") +board_runner_args(openocd --cmd-pre-init "transport select swd") +board_runner_args(openocd --cmd-pre-init "source [find target/rp2040.cfg]") + +# The adapter speed is expected to be set by interface configuration. +# But if not so, set 2000 to adapter speed. +board_runner_args(openocd --cmd-pre-init "set_adapter_speed_if_not_set 2000") + +board_runner_args(jlink "--device=RP2040_M0_0") +board_runner_args(uf2 "--board-id=RPI-RP2") +board_runner_args(pyocd "--target=rp2040") + +include(${ZEPHYR_BASE}/boards/common/openocd.board.cmake) +include(${ZEPHYR_BASE}/boards/common/jlink.board.cmake) +include(${ZEPHYR_BASE}/boards/common/uf2.board.cmake) +include(${ZEPHYR_BASE}/boards/common/blackmagicprobe.board.cmake) +include(${ZEPHYR_BASE}/boards/common/pyocd.board.cmake) diff --git a/boards/arm/w5500_evb_pico/doc/img/w5500_evb_pico_side.png b/boards/arm/w5500_evb_pico/doc/img/w5500_evb_pico_side.png new file mode 100644 index 0000000000000000000000000000000000000000..d592fd2c85f68b3989e0d0374b41fe51b5e2259e GIT binary patch literal 40108 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 literal 0 HcmV?d00001 diff --git a/boards/arm/w5500_evb_pico/doc/index.rst b/boards/arm/w5500_evb_pico/doc/index.rst new file mode 100644 index 00000000000..63d63370f76 --- /dev/null +++ b/boards/arm/w5500_evb_pico/doc/index.rst @@ -0,0 +1,293 @@ +.. _w5500_evb_pico: + +Wiznet W5500 Evaluation Pico +############################ + +Overview +******** + +W5500-EVB-Pico is a microcontroller evaluation board based on the Raspberry +Pi RP2040 and fully hardwired TCP/IP controller W5500 - and basically works +the same as Raspberry Pi Pico board but with additional Ethernet via W5500. +The USB bootloader allows the ability to flash without any adapter, in a +drag-and-drop manner. It is also possible to flash and debug the boards with +their SWD interface, using an external adapter. + +Hardware +******** +- Dual core Arm Cortex-M0+ processor running up to 133MHz +- 264KB on-chip SRAM +- 16MB on-board QSPI flash with XIP capabilities +- 26 GPIO pins +- 3 Analog inputs +- 2 UART peripherals +- 2 SPI controllers +- 2 I2C controllers +- 16 PWM channels +- USB 1.1 controller (host/device) +- 8 Programmable I/O (PIO) for custom peripherals +- On-board LED +- 1 Watchdog timer peripheral +- Wiznet W5500 Ethernet MAC/PHY + + +.. figure:: img/w5500_evb_pico_side.png + :align: center + :alt: W5500 Evaluation Board + + Wiznet W5500_EVB_PICO evaluation board (Image courtesy of Wiznet) + +Supported Features +================== + +The w5500_evb_pico board configuration supports the following +hardware features: + +.. list-table:: + :header-rows: 1 + + * - Peripheral + - Kconfig option + - Devicetree compatible + * - NVIC + - N/A + - :dtcompatible:`arm,v6m-nvic` + * - UART + - :kconfig:option:`CONFIG_SERIAL` + - :dtcompatible:`raspberrypi,pico-uart` + * - GPIO + - :kconfig:option:`CONFIG_GPIO` + - :dtcompatible:`raspberrypi,pico-gpio` + * - ADC + - :kconfig:option:`CONFIG_ADC` + - :dtcompatible:`raspberrypi,pico-adc` + * - I2C + - :kconfig:option:`CONFIG_I2C` + - :dtcompatible:`snps,designware-i2c` + * - SPI + - :kconfig:option:`CONFIG_SPI` + - :dtcompatible:`raspberrypi,pico-spi` + * - USB Device + - :kconfig:option:`CONFIG_USB_DEVICE_STACK` + - :dtcompatible:`raspberrypi,pico-usbd` + * - HWINFO + - :kconfig:option:`CONFIG_HWINFO` + - N/A + * - Watchdog Timer (WDT) + - :kconfig:option:`CONFIG_WATCHDOG` + - :dtcompatible:`raspberrypi,pico-watchdog` + * - PWM + - :kconfig:option:`CONFIG_PWM` + - :dtcompatible:`raspberrypi,pico-pwm` + * - Flash + - :kconfig:option:`CONFIG_FLASH` + - :dtcompatible:`raspberrypi,pico-flash` + * - UART (PIO) + - :kconfig:option:`CONFIG_SERIAL` + - :dtcompatible:`raspberrypi,pico-uart-pio` + * - SPI (PIO) + - :kconfig:option:`CONFIG_SPI` + - :dtcompatible:`raspberrypi,pico-spi-pio` + * - W5500 Ethernet + - :kconfig:option:`CONFIG_NETWORKING` + - :dtcompatible:`wiznet,w5500` + +Pin Mapping +=========== + +The peripherals of the RP2040 SoC can be routed to various pins on the board. +The configuration of these routes can be modified through DTS. Please refer to +the datasheet to see the possible routings for each peripheral. + +External pin mapping on the W5500_EVB_PICO is identical to the Raspberry Pi +Pico. Since GPIO 25 is routed to the on-board LED on, similar to the Raspberry +Pi Pico, the blinky example works as intended. The W5500 is routed to the SPI0 +(P16-P19), with the reset and interrupt signal for the W5500 routed to P20 and +P21, respectively. All of these are shared with the edge connector on the +board. + +Refer to `W55500 Evaluation Board Documentation`_ for a board schematic and +other certifications. + +Default Zephyr Peripheral Mapping: +---------------------------------- + +.. rst-class:: rst-columns + +- UART0_TX : P0 +- UART0_RX : P1 +- I2C0_SDA : P4 +- I2C0_SCL : P5 +- I2C1_SDA : P14 +- I2C1_SCL : P15 +- SPI0_RX : P16 +- SPI0_CSN : P17 +- SPI0_SCK : P18 +- SPI0_TX : P19 +- W5500 Reset : P20 +- W5500 Interrupt : P21 +- ADC_CH0 : P26 +- ADC_CH1 : P27 +- ADC_CH2 : P28 +- ADC_CH3 : P29 + +Programming and Debugging +************************* + +Flashing +======== + +Using SEGGER JLink +------------------ + +You can Flash the w5500_evb_pico with a SEGGER JLink debug probe as described in +:ref:`Building, Flashing and Debugging `. + +Here is an example of building and flashing the :zephyr:code-sample:`blinky` application. + +.. zephyr-app-commands:: + :zephyr-app: samples/basic/blinky + :board: w5500_evb_pico + :goals: build + +.. code-block:: bash + + west flash --runner jlink + +Using OpenOCD +------------- + +To use PicoProbe, You must configure **udev**. + +Create a file in /etc/udev.rules.d with any name, and write the line below. + +.. code-block:: bash + + ATTRS{idVendor}=="2e8a", ATTRS{idProduct}=="000c", MODE="660", GROUP="plugdev", TAG+="uaccess" + +This example is valid for the case that the user joins to `plugdev` groups. + +The Raspberry Pi Pico, and thus the W55500 Evaluation Board, has an SWD +interface that can be used to program and debug the on board RP2040. This +interface can be utilized by OpenOCD. To use it with the RP2040, OpenOCD +version 0.12.0 or later is needed. + +If you are using a Debian based system (including RaspberryPi OS, Ubuntu. and +more), using the `pico_setup.sh`_ script is a convenient way to set up the +forked version of OpenOCD. + +Depending on the interface used (such as JLink), you might need to +checkout to a branch that supports this interface, before proceeding. +Build and install OpenOCD as described in the README. + +Here is an example of building and flashing the :zephyr:code-sample:`blinky` +application. + +.. zephyr-app-commands:: + :zephyr-app: samples/basic/blinky + :board: w5500_evb_pico + :goals: build flash + :gen-args: -DOPENOCD=/usr/local/bin/openocd -DOPENOCD_DEFAULT_PATH=/usr/local/share/openocd/scripts -DRPI_PICO_DEBUG_ADAPTER=picoprobe + +Set the environment variables **OPENOCD** to `/usr/local/bin/openocd` and +**OPENOCD_DEFAULT_PATH** to `/usr/local/share/openocd/scripts`. This should +work with the OpenOCD that was installed with the default configuration. This +configuration also works with an environment that is set up by the +`pico_setup.sh`_ script. + +**RPI_PICO_DEBUG_ADAPTER** specifies what debug adapter is used for debugging. + +If **RPI_PICO_DEBUG_ADAPTER** was not assigned, `picoprobe` is used by default. +The other supported adapters are `raspberrypi-swd`, `jlink` and +`blackmagicprobe`. How to connect `picoprobe` and `raspberrypi-swd` is +described in `Getting Started with Raspberry Pi Pico`_. Any other SWD debug +adapter maybe also work with this configuration. + +The value of **RPI_PICO_DEBUG_ADAPTER** is cached, so it can be omitted from +`west flash` and `west debug` if it was previously set while running +`west build`. + +**RPI_PICO_DEBUG_ADAPTER** is used in an argument to OpenOCD as +`"source [find interface/${RPI_PICO_DEBUG_ADAPTER}.cfg]"`. Thus, +**RPI_PICO_DEBUG_ADAPTER** needs to be assigned the file name of the debug +adapter. + +You can also flash the board with the following +command that directly calls OpenOCD (assuming a SEGGER JLink adapter is used): + +.. code-block:: console + + $ openocd -f interface/jlink.cfg -c 'transport select swd' -f target/rp2040.cfg -c "adapter speed 2000" -c 'targets rp2040.core0' -c 'program path/to/zephyr.elf verify reset exit' + +Using UF2 +--------- + +If you don't have an SWD adapter, you can flash the Raspberry Pi Pico with +a UF2 file. By default, building an app for this board will generate a +`build/zephyr/zephyr.uf2` file. If the Pico is powered on with the `BOOTSEL` +button pressed, it will appear on the host as a mass storage device. The +UF2 file should be drag-and-dropped to the device, which will flash the Pico. + +Debugging +========= + +The SWD interface can also be used to debug the board. To achieve this, you can +either use SEGGER JLink or OpenOCD. + +Using SEGGER JLink +------------------ + +Use a SEGGER JLink debug probe and follow the instruction in +:ref:`Building, Flashing and Debugging`. + + +Using OpenOCD +------------- + +Install OpenOCD as described for flashing the board. + +Here is an example for debugging the :zephyr:code-sample:`blinky` application. + +.. zephyr-app-commands:: + :zephyr-app: samples/basic/blinky + :board: w5500_evb_pico + :maybe-skip-config: + :goals: debug + :gen-args: -DOPENOCD=/usr/local/bin/openocd -DOPENOCD_DEFAULT_PATH=/usr/local/share/openocd/scripts -DRPI_PICO_DEBUG_ADAPTER=raspberrypi-swd + +As with flashing, you can specify the debug adapter by specifying +**RPI_PICO_DEBUG_ADAPTER** at `west build` time. No needs to specify it at +`west debug` time. + +You can also debug with OpenOCD and gdb launching from command-line. +Run the following command: + +.. code-block:: console + + $ openocd -f interface/jlink.cfg -c 'transport select swd' -f target/rp2040.cfg -c "adapter speed 2000" -c 'targets rp2040.core0' + +On another terminal, run: + +.. code-block:: console + + $ gdb-multiarch + +Inside gdb, run: + +.. code-block:: console + + (gdb) tar ext :3333 + (gdb) file path/to/zephyr.elf + +You can then start debugging the board. + +.. target-notes:: + +.. _pico_setup.sh: + https://raw.githubusercontent.com/raspberrypi/pico-setup/master/pico_setup.sh + +.. _Getting Started with Raspberry Pi Pico: + https://datasheets.raspberrypi.com/pico/getting-started-with-pico.pdf + +.. _W55500 Evaluation Board Documentation: + https://docs.wiznet.io/Product/iEthernet/W5500/w5500-evb-pico diff --git a/boards/arm/w5500_evb_pico/support/openocd.cfg b/boards/arm/w5500_evb_pico/support/openocd.cfg new file mode 100644 index 00000000000..a9918980457 --- /dev/null +++ b/boards/arm/w5500_evb_pico/support/openocd.cfg @@ -0,0 +1,11 @@ +# Copyright (c) 2022 Tokita, Hiroshi +# SPDX-License-Identifier: Apache-2.0 + +# Checking and set 'adapter speed'. +# Set adapter speed that assigned by argument if not be seted. +proc set_adapter_speed_if_not_set { speed } { + puts "checking adapter speed..." + if { [catch {adapter speed} ret] } { + adapter speed $speed + } +} diff --git a/boards/arm/w5500_evb_pico/w5500_evb_pico-pinctrl.dtsi b/boards/arm/w5500_evb_pico/w5500_evb_pico-pinctrl.dtsi new file mode 100644 index 00000000000..761354420c6 --- /dev/null +++ b/boards/arm/w5500_evb_pico/w5500_evb_pico-pinctrl.dtsi @@ -0,0 +1,60 @@ +/* + * Copyright (c) 2021, Yonatan Schachter + * SPDX-License-Identifier: Apache-2.0 + */ + +#include + +&pinctrl { + uart0_default: uart0_default { + group1 { + pinmux = ; + }; + group2 { + pinmux = ; + input-enable; + }; + }; + + i2c0_default: i2c0_default { + group1 { + pinmux = , ; + input-enable; + input-schmitt-enable; + }; + }; + + i2c1_default: i2c1_default { + group1 { + pinmux = , ; + input-enable; + input-schmitt-enable; + }; + }; + + spi0_default: spi0_default { + group1 { + pinmux = , , ; + }; + group2 { + pinmux = ; + input-enable; + }; + }; + + pwm_ch4b_default: pwm_ch4b_default { + group1 { + pinmux = ; + }; + }; + + adc_default: adc_default { + group1 { + pinmux = , , , ; + input-enable; + }; + }; + + clocks_default: clocks_default { + }; +}; diff --git a/boards/arm/w5500_evb_pico/w5500_evb_pico.dts b/boards/arm/w5500_evb_pico/w5500_evb_pico.dts new file mode 100644 index 00000000000..c14cb0b7d64 --- /dev/null +++ b/boards/arm/w5500_evb_pico/w5500_evb_pico.dts @@ -0,0 +1,194 @@ +/* + * Copyright (c) 2021 Yonatan Schachter + * Copyright (c) 2023 Ian Wakely + * + * SPDX-License-Identifier: Apache-2.0 + */ + +/dts-v1/; + +#include + +#include +#include "w5500_evb_pico-pinctrl.dtsi" +#include + +#include + +/ { + chosen { + zephyr,sram = &sram0; + zephyr,flash = &flash0; + zephyr,flash-controller = &ssi; + zephyr,console = &uart0; + zephyr,shell-uart = &uart0; + zephyr,code-partition = &code_partition; + }; + + pico_header: connector { + compatible = "raspberrypi,pico-header"; + #gpio-cells = <2>; + gpio-map-mask = <0xffffffff 0xffffffc0>; + gpio-map-pass-thru = <0 0x3f>; + gpio-map = <0 0 &gpio0 0 0>, /* GP0 */ + <1 0 &gpio0 1 0>, /* GP1 */ + <2 0 &gpio0 2 0>, /* GP2 */ + <3 0 &gpio0 3 0>, /* GP3 */ + <4 0 &gpio0 4 0>, /* GP4 */ + <5 0 &gpio0 5 0>, /* GP5 */ + <6 0 &gpio0 6 0>, /* GP6 */ + <7 0 &gpio0 7 0>, /* GP7 */ + <8 0 &gpio0 8 0>, /* GP8 */ + <9 0 &gpio0 9 0>, /* GP9 */ + <10 0 &gpio0 10 0>, /* GP10 */ + <11 0 &gpio0 11 0>, /* GP11 */ + <12 0 &gpio0 12 0>, /* GP12 */ + <13 0 &gpio0 13 0>, /* GP13 */ + <14 0 &gpio0 14 0>, /* GP14 */ + <15 0 &gpio0 15 0>, /* GP15 */ + <16 0 &gpio0 16 0>, /* GP16 */ + <17 0 &gpio0 17 0>, /* GP17 */ + <18 0 &gpio0 18 0>, /* GP18 */ + <19 0 &gpio0 19 0>, /* GP19 */ + <20 0 &gpio0 20 0>, /* GP20 */ + <21 0 &gpio0 21 0>, /* GP21 */ + <22 0 &gpio0 22 0>, /* GP22 */ + <26 0 &gpio0 26 0>, /* GP26 */ + <27 0 &gpio0 27 0>, /* GP27 */ + <28 0 &gpio0 28 0>; /* GP28 */ + }; + + leds { + compatible = "gpio-leds"; + led0: led_0 { + gpios = <&gpio0 25 GPIO_ACTIVE_HIGH>; + label = "LED"; + }; + }; + + pwm_leds { + compatible = "pwm-leds"; + status = "disabled"; + pwm_led0: pwm_led_0 { + pwms = <&pwm 9 PWM_MSEC(20) PWM_POLARITY_NORMAL>; + label = "PWM_LED"; + }; + }; + + aliases { + led0 = &led0; + pwm-led0 = &pwm_led0; + watchdog0 = &wdt0; + }; +}; + +&flash0 { + /* 16MB of flash minus the 0x100 used for + * the second stage bootloader + */ + reg = <0x10000000 DT_SIZE_M(16)>; + + partitions { + compatible = "fixed-partitions"; + #address-cells = <1>; + #size-cells = <1>; + + /* Reserved memory for the second stage bootloader */ + second_stage_bootloader: partition@0 { + label = "second_stage_bootloader"; + reg = <0x00000000 0x100>; + read-only; + }; + + /* + * Usable flash. Starts at 0x100, after the bootloader. The partition + * size is 16MB minus the 0x100 bytes taken by the bootloader. + */ + code_partition: partition@100 { + label = "code-partition"; + reg = <0x100 (DT_SIZE_M(16) - 0x100)>; + read-only; + }; + }; +}; + +&clocks { + pinctrl-0 = <&clocks_default>; + pinctrl-names = "default"; +}; + +&uart0 { + current-speed = <115200>; + status = "okay"; + pinctrl-0 = <&uart0_default>; + pinctrl-names = "default"; +}; + +&gpio0 { + status = "okay"; +}; + +&i2c0 { + clock-frequency = ; + status = "okay"; + pinctrl-0 = <&i2c0_default>; + pinctrl-names = "default"; +}; + +&i2c1 { + pinctrl-0 = <&i2c1_default>; + pinctrl-names = "default"; + status = "disabled"; + clock-frequency = ; +}; + +&spi0 { + clock-frequency = ; + status = "okay"; + pinctrl-0 = <&spi0_default>; + pinctrl-names = "default"; + cs-gpios = <&gpio0 17 GPIO_ACTIVE_LOW>; + + ethernet: w5500@0 { + compatible = "wiznet,w5500"; + reg = <0x0>; + spi-max-frequency = <50000000>; + int-gpios = <&gpio0 21 GPIO_ACTIVE_LOW>; + reset-gpios = <&gpio0 20 GPIO_ACTIVE_LOW>; + local-mac-address = [00 00 00 01 02 03]; + status = "okay"; + }; +}; + +&timer { + status = "okay"; +}; + +&wdt0 { + status = "okay"; +}; + +&adc { + status = "okay"; + pinctrl-0 = <&adc_default>; + pinctrl-names = "default"; +}; + +zephyr_udc0: &usbd { + status = "okay"; +}; + +&pwm { + pinctrl-0 = <&pwm_ch4b_default>; + pinctrl-names = "default"; + divider-int-0 = <255>; +}; + +&vreg { + regulator-always-on; + regulator-allowed-modes = ; +}; + +pico_spi: &spi0 {}; +pico_i2c0: &i2c0 {}; +pico_i2c1: &i2c1 {}; diff --git a/boards/arm/w5500_evb_pico/w5500_evb_pico.yaml b/boards/arm/w5500_evb_pico/w5500_evb_pico.yaml new file mode 100644 index 00000000000..85246c0ef1d --- /dev/null +++ b/boards/arm/w5500_evb_pico/w5500_evb_pico.yaml @@ -0,0 +1,23 @@ +identifier: w5500_evb_pico +name: Wiznet W5500 Evaluation Board +type: mcu +arch: arm +flash: 16384 +ram: 264 +toolchain: + - zephyr + - gnuarmemb + - xtools +supported: + - uart + - gpio + - adc + - i2c + - spi + - hwinfo + - watchdog + - pwm + - flash + - dma + - counter + - clock diff --git a/boards/arm/w5500_evb_pico/w5500_evb_pico_defconfig b/boards/arm/w5500_evb_pico/w5500_evb_pico_defconfig new file mode 100644 index 00000000000..ec36f85040c --- /dev/null +++ b/boards/arm/w5500_evb_pico/w5500_evb_pico_defconfig @@ -0,0 +1,14 @@ +CONFIG_SOC_SERIES_RP2XXX=y +CONFIG_SOC_RP2040=y +CONFIG_BOARD_W5500_EVB_PICO=y +CONFIG_SYS_CLOCK_HW_CYCLES_PER_SEC=125000000 +CONFIG_SERIAL=y +CONFIG_CONSOLE=y +CONFIG_UART_CONSOLE=y +CONFIG_GPIO=y +CONFIG_USE_DT_CODE_PARTITION=y +CONFIG_BUILD_OUTPUT_UF2=y +CONFIG_BUILD_OUTPUT_HEX=y +CONFIG_UART_INTERRUPT_DRIVEN=y +CONFIG_RESET=y +CONFIG_CLOCK_CONTROL=y From 2a647c81cf55670f8a9c38753d9e9dcb42ecdf1c Mon Sep 17 00:00:00 2001 From: Ian Wakely Date: Thu, 14 Dec 2023 06:21:40 -0500 Subject: [PATCH 1583/3723] board: Fixing ADC API tests for W5500_EVB_PICO. When duplicating the rpi_pico board, I had missed this test file. Signed-off-by: Ian Wakely --- .../adc/adc_api/boards/w5500_evb_pico.overlay | 32 +++++++++++++++++++ 1 file changed, 32 insertions(+) create mode 100644 tests/drivers/adc/adc_api/boards/w5500_evb_pico.overlay diff --git a/tests/drivers/adc/adc_api/boards/w5500_evb_pico.overlay b/tests/drivers/adc/adc_api/boards/w5500_evb_pico.overlay new file mode 100644 index 00000000000..2bd79f9f4f1 --- /dev/null +++ b/tests/drivers/adc/adc_api/boards/w5500_evb_pico.overlay @@ -0,0 +1,32 @@ +/* + * Copyright (c) 2023 Benjamin Björnsson + * + * SPDX-License-Identifier: Apache-2.0 + */ + +/ { + zephyr,user { + io-channels = <&adc 0>, <&adc 1>; + }; +}; + +&adc { + #address-cells = <1>; + #size-cells = <0>; + + channel@0 { + reg = <0>; + zephyr,gain = "ADC_GAIN_1"; + zephyr,reference = "ADC_REF_INTERNAL"; + zephyr,acquisition-time = ; + zephyr,resolution = <12>; + }; + + channel@1 { + reg = <1>; + zephyr,gain = "ADC_GAIN_1"; + zephyr,reference = "ADC_REF_INTERNAL"; + zephyr,acquisition-time = ; + zephyr,resolution = <12>; + }; +}; From 0bbd834e14f86dca465e40d1559666dee647a1d1 Mon Sep 17 00:00:00 2001 From: Andrei Emeltchenko Date: Wed, 28 Jun 2023 16:38:13 +0300 Subject: [PATCH 1584/3723] raptor_lake: Rename raptor_lake.dts to raptor_lake_s Rename old rpl_crb to rpl_s_crb, which is needed for adding other Raptor Lake boards. Main changes should be in the board device tree configuration raptor_lake_p vs raptor_lake_s. Signed-off-by: Andrei Emeltchenko --- boards/x86/intel_rpl/intel_rpl_s_crb.dts | 2 +- dts/x86/intel/{raptor_lake.dtsi => raptor_lake_s.dtsi} | 0 2 files changed, 1 insertion(+), 1 deletion(-) rename dts/x86/intel/{raptor_lake.dtsi => raptor_lake_s.dtsi} (100%) diff --git a/boards/x86/intel_rpl/intel_rpl_s_crb.dts b/boards/x86/intel_rpl/intel_rpl_s_crb.dts index 5301b373022..9a18aa57266 100644 --- a/boards/x86/intel_rpl/intel_rpl_s_crb.dts +++ b/boards/x86/intel_rpl/intel_rpl_s_crb.dts @@ -9,7 +9,7 @@ #define DT_DRAM_SIZE DT_SIZE_M(2048) -#include +#include / { model = "intel_rpl_s_crb"; diff --git a/dts/x86/intel/raptor_lake.dtsi b/dts/x86/intel/raptor_lake_s.dtsi similarity index 100% rename from dts/x86/intel/raptor_lake.dtsi rename to dts/x86/intel/raptor_lake_s.dtsi From 465c34ef5803a0008a898eb18551ec7cfc47d377 Mon Sep 17 00:00:00 2001 From: Andrei Emeltchenko Date: Thu, 17 Aug 2023 15:48:14 +0300 Subject: [PATCH 1585/3723] boards: Add Raptor Lake P board configuration Add board configuration for Intel Raptor Lake P board. Signed-off-by: Andrei Emeltchenko --- boards/x86/intel_rpl/Kconfig.board | 8 +- boards/x86/intel_rpl/Kconfig.defconfig | 16 +- boards/x86/intel_rpl/intel_rpl_p_crb.dts | 28 ++ boards/x86/intel_rpl/intel_rpl_p_crb.yaml | 22 + .../x86/intel_rpl/intel_rpl_p_crb_defconfig | 15 + dts/x86/intel/raptor_lake_p.dtsi | 474 ++++++++++++++++++ 6 files changed, 557 insertions(+), 6 deletions(-) create mode 100644 boards/x86/intel_rpl/intel_rpl_p_crb.dts create mode 100644 boards/x86/intel_rpl/intel_rpl_p_crb.yaml create mode 100644 boards/x86/intel_rpl/intel_rpl_p_crb_defconfig create mode 100644 dts/x86/intel/raptor_lake_p.dtsi diff --git a/boards/x86/intel_rpl/Kconfig.board b/boards/x86/intel_rpl/Kconfig.board index f806be34a88..0424004d10b 100644 --- a/boards/x86/intel_rpl/Kconfig.board +++ b/boards/x86/intel_rpl/Kconfig.board @@ -1,4 +1,4 @@ -# Copyright (c) 2022 Intel Corporation +# Copyright (c) 2022-2023 Intel Corporation # SPDX-License-Identifier: Apache-2.0 config BOARD_INTEL_RPL_S_CRB @@ -6,3 +6,9 @@ config BOARD_INTEL_RPL_S_CRB depends on SOC_RAPTOR_LAKE select X86_64 select HAS_COVERAGE_SUPPORT + +config BOARD_INTEL_RPL_P_CRB + bool "Raptor Lake P CRB" + depends on SOC_RAPTOR_LAKE + select X86_64 + select HAS_COVERAGE_SUPPORT diff --git a/boards/x86/intel_rpl/Kconfig.defconfig b/boards/x86/intel_rpl/Kconfig.defconfig index 10ae8ff2682..1a71b32f84c 100644 --- a/boards/x86/intel_rpl/Kconfig.defconfig +++ b/boards/x86/intel_rpl/Kconfig.defconfig @@ -1,10 +1,11 @@ -# Copyright (c) 2022 Intel Corporation +# Copyright (c) 2022-2023 Intel Corporation # SPDX-License-Identifier: Apache-2.0 -if BOARD_INTEL_RPL_S_CRB +if BOARD_INTEL_RPL_S_CRB || BOARD_INTEL_RPL_P_CRB config BOARD - default "intel_rpl_s_crb" + default "intel_rpl_p_crb" if BOARD_INTEL_RPL_P_CRB + default "intel_rpl_s_crb" if BOARD_INTEL_RPL_S_CRB config BUILD_OUTPUT_STRIPPED default y @@ -54,6 +55,11 @@ config DMA_DW_CHANNEL_COUNT endif config UART_NS16550_INTEL_LPSS_DMA - default y + default y if BOARD_INTEL_RPL_S_CRB + +if SHELL +config SHELL_STACK_SIZE + default 320000 +endif -endif # BOARD_INTEL_RPL_S_CRB +endif # BOARD_INTEL_RPL_S_CRB || BOARD_INTEL_RPL_P_CRB diff --git a/boards/x86/intel_rpl/intel_rpl_p_crb.dts b/boards/x86/intel_rpl/intel_rpl_p_crb.dts new file mode 100644 index 00000000000..ea07719a9b5 --- /dev/null +++ b/boards/x86/intel_rpl/intel_rpl_p_crb.dts @@ -0,0 +1,28 @@ +/* + * Copyright (c) 2023 Intel Corporation + * SPDX-License-Identifier: Apache-2.0 + */ + +/dts-v1/; + +#include + +#define DT_DRAM_SIZE DT_SIZE_M(2048) + +#include + +/ { + model = "intel_rpl_p_crb"; + compatible = "intel,raptor-lake-crb"; + + chosen { + zephyr,sram = &dram0; + zephyr,console = &uart0; + zephyr,shell-uart = &uart0; + }; + + aliases { + watchdog0 = &tco_wdt; + rtc = &rtc; + }; +}; diff --git a/boards/x86/intel_rpl/intel_rpl_p_crb.yaml b/boards/x86/intel_rpl/intel_rpl_p_crb.yaml new file mode 100644 index 00000000000..2e6504dd32f --- /dev/null +++ b/boards/x86/intel_rpl/intel_rpl_p_crb.yaml @@ -0,0 +1,22 @@ +identifier: intel_rpl_p_crb +name: Raptor Lake P CRB +type: mcu +arch: x86 +toolchain: + - zephyr +ram: 2048 +supported: + - acpi + - smp + - smbus + - watchdog + - rtc + - pwm + - gpio + - spi + - i2c +testing: + ignore_tags: + - net + - bluetooth +vendor: intel diff --git a/boards/x86/intel_rpl/intel_rpl_p_crb_defconfig b/boards/x86/intel_rpl/intel_rpl_p_crb_defconfig new file mode 100644 index 00000000000..09fd65cf261 --- /dev/null +++ b/boards/x86/intel_rpl/intel_rpl_p_crb_defconfig @@ -0,0 +1,15 @@ +# SPDX-License-Identifier: Apache-2.0 + +CONFIG_SOC_RAPTOR_LAKE=y +CONFIG_BOARD_INTEL_RPL_P_CRB=y +CONFIG_PIC_DISABLE=y +CONFIG_LOAPIC=y +CONFIG_CONSOLE=y +CONFIG_SERIAL=y +CONFIG_UART_NS16550=y +CONFIG_UART_NS16550_VARIANT_NS16750=y +CONFIG_UART_CONSOLE=y +CONFIG_X2APIC=y +CONFIG_SMP=y +CONFIG_BUILD_OUTPUT_EFI=y +CONFIG_BUILD_NO_GAP_FILL=y diff --git a/dts/x86/intel/raptor_lake_p.dtsi b/dts/x86/intel/raptor_lake_p.dtsi new file mode 100644 index 00000000000..8f7dec863e2 --- /dev/null +++ b/dts/x86/intel/raptor_lake_p.dtsi @@ -0,0 +1,474 @@ +/* + * Copyright (c) 2023 Intel Corporation. + * SPDX-License-Identifier: Apache-2.0 + */ + +#include "skeleton.dtsi" +#include +#include +#include +#include + +/ { + cpus { + #address-cells = <1>; + #size-cells = <0>; + + cpu@0 { + compatible = "intel,raptor-lake"; + device_type = "cpu"; + d-cache-line-size = <64>; + reg = <0>; + }; + }; + + dram0: memory@0 { + device_type = "memory"; + reg = <0x0 DT_DRAM_SIZE>; + }; + + intc: ioapic@fec00000 { + compatible = "intel,ioapic"; + reg = <0xfec00000 0x1000>; + interrupt-controller; + #interrupt-cells = <3>; + }; + + intc_loapic: loapic@fee00000 { + compatible = "intel,loapic"; + reg = <0xfee00000 0x1000>; + interrupt-controller; + #interrupt-cells = <3>; + #address-cells = <1>; + }; + + pcie0: pcie0 { + compatible = "intel,pcie"; + #address-cells = <1>; + #size-cells = <1>; + ranges; + + smbus0: smbus0 { + compatible = "intel,pch-smbus"; + #address-cells = <1>; + #size-cells = <0>; + vendor-id = <0x8086>; + device-id = <0x51a3>; + interrupts = <16 IRQ_TYPE_LOWEST_LEVEL_LOW 3>; + interrupt-parent = <&intc>; + + status = "okay"; + }; + + uart0: uart0 { + compatible = "ns16550"; + vendor-id = <0x8086>; + device-id = <0x51a8>; + reg-shift = <2>; + clock-frequency = <1843200>; + interrupts = ; + interrupt-parent = <&intc>; + current-speed = <115200>; + + status = "okay"; + }; + + uart1: uart1 { + compatible = "ns16550"; + vendor-id = <0x8086>; + device-id = <0x51A9>; + reg-shift = <2>; + clock-frequency = <1843200>; + interrupts = ; + interrupt-parent = <&intc>; + current-speed = <115200>; + + status = "okay"; + }; + + spi0: spi0 { + compatible = "intel,penwell-spi"; + #address-cells = <1>; + #size-cells = <0>; + vendor-id = <0x8086>; + device-id = <0x51aa>; + pw,cs-mode = <0>; + pw,cs-output = <0>; + pw,fifo-depth = <64>; + cs-gpios = <&gpio_4_e 10 GPIO_ACTIVE_LOW>; + clock-frequency = <100000000>; + interrupts = ; + interrupt-parent = <&intc>; + + status = "okay"; + }; + + spi1: spi1 { + compatible = "intel,penwell-spi"; + #address-cells = <1>; + #size-cells = <0>; + vendor-id = <0x8086>; + device-id = <0x51ab>; + pw,cs-mode = <0>; + pw,cs-output = <0>; + pw,fifo-depth = <64>; + cs-gpios = <&gpio_4_f 16 GPIO_ACTIVE_LOW>; + clock-frequency = <100000000>; + interrupts = ; + interrupt-parent = <&intc>; + + status = "disabled"; + }; + + spi2: spi2 { + compatible = "intel,penwell-spi"; + #address-cells = <1>; + #size-cells = <0>; + vendor-id = <0x8086>; + device-id = <0x51fb>; + pw,cs-mode = <0>; + pw,cs-output = <0>; + pw,fifo-depth = <64>; + cs-gpios = <&gpio_1_d 9 GPIO_ACTIVE_LOW>; + clock-frequency = <100000000>; + interrupts = ; + interrupt-parent = <&intc>; + + status = "disabled"; + }; + + i2c0: i2c0 { + compatible = "snps,designware-i2c"; + #address-cells = <1>; + #size-cells = <0>; + clock-frequency = ; + vendor-id = <0x8086>; + device-id = <0x51e8>; + interrupts = ; + interrupt-parent = <&intc>; + + status = "okay"; + }; + + i2c1: i2c1 { + compatible = "snps,designware-i2c"; + #address-cells = <1>; + #size-cells = <0>; + clock-frequency = ; + vendor-id = <0x8086>; + device-id = <0x51e9>; + interrupts = ; + interrupt-parent = <&intc>; + + status = "okay"; + }; + + i2c2: i2c2 { + compatible = "snps,designware-i2c"; + #address-cells = <1>; + #size-cells = <0>; + clock-frequency = ; + vendor-id = <0x8086>; + device-id = <0x51ea>; + interrupts = ; + interrupt-parent = <&intc>; + + status = "disabled"; + }; + + i2c3: i2c3 { + compatible = "snps,designware-i2c"; + #address-cells = <1>; + #size-cells = <0>; + clock-frequency = ; + vendor-id = <0x8086>; + device-id = <0x51eb>; + interrupts = ; + interrupt-parent = <&intc>; + + status = "disabled"; + }; + + i2c4: i2c4 { + compatible = "snps,designware-i2c"; + #address-cells = <1>; + #size-cells = <0>; + clock-frequency = ; + vendor-id = <0x8086>; + device-id = <0x51c5>; + interrupts = ; + interrupt-parent = <&intc>; + + status = "disabled"; + }; + + i2c5: i2c5 { + compatible = "snps,designware-i2c"; + #address-cells = <1>; + #size-cells = <0>; + clock-frequency = ; + vendor-id = <0x8086>; + device-id = <0x51c6>; + interrupts = ; + interrupt-parent = <&intc>; + + status = "disabled"; + }; + + i2c6: i2c6 { + compatible = "snps,designware-i2c"; + #address-cells = <1>; + #size-cells = <0>; + clock-frequency = ; + vendor-id = <0x8086>; + device-id = <0x51d8>; + interrupts = ; + interrupt-parent = <&intc>; + + status = "disabled"; + }; + + i2c7: i2c7 { + compatible = "snps,designware-i2c"; + #address-cells = <1>; + #size-cells = <0>; + clock-frequency = ; + vendor-id = <0x8086>; + device-id = <0x51d9>; + interrupts = ; + interrupt-parent = <&intc>; + + status = "disabled"; + }; + }; + + soc { + compatible = "simple-bus"; + #address-cells = <1>; + #size-cells = <1>; + ranges; + + gpio_0_b: gpio@fd6e0700 { + compatible = "intel,gpio"; + reg = <0xfd6e0700 0x1000>; + interrupts = <14 IRQ_TYPE_LOWEST_LEVEL_LOW 3>; + interrupt-parent = <&intc>; + + group-index = <0x0>; + gpio-controller; + #gpio-cells = <2>; + + ngpios = <24>; + pin-offset = <0>; + + status = "okay"; + }; + + gpio_0_t: gpio@fd6e08a0 { + compatible = "intel,gpio"; + reg = <0xfd6e08a0 0x1000>; + interrupts = <14 IRQ_TYPE_LOWEST_LEVEL_LOW 3>; + interrupt-parent = <&intc>; + + group-index = <0x1>; + gpio-controller; + #gpio-cells = <2>; + + ngpios = <4>; + pin-offset = <25>; + + status = "okay"; + }; + + gpio_0_a: gpio@fd6e09a0 { + compatible = "intel,gpio"; + reg = <0xfd6e09a0 0x1000>; + interrupts = <14 IRQ_TYPE_LOWEST_LEVEL_LOW 3>; + interrupt-parent = <&intc>; + + group-index = <0x2>; + gpio-controller; + #gpio-cells = <2>; + + ngpios = <24>; + pin-offset = <41>; + + status = "okay"; + }; + + gpio_1_s: gpio@fd6d0700 { + compatible = "intel,gpio"; + reg = <0xfd6d0700 0x1000>; + interrupts = <14 IRQ_TYPE_LOWEST_LEVEL_LOW 3>; + interrupt-parent = <&intc>; + + group-index = <0x0>; + gpio-controller; + #gpio-cells = <2>; + + ngpios = <8>; + pin-offset = <0>; + + status = "okay"; + }; + + gpio_1_h: gpio@fd6d0780 { + compatible = "intel,gpio"; + reg = <0xfd6d0780 0x1000>; + interrupts = <14 IRQ_TYPE_LOWEST_LEVEL_LOW 3>; + interrupt-parent = <&intc>; + + group-index = <0x1>; + gpio-controller; + #gpio-cells = <2>; + + ngpios = <24>; + pin-offset = <8>; + + status = "okay"; + }; + + + gpio_1_d: gpio@fd6d0900 { + compatible = "intel,gpio"; + reg = <0xfd6d0900 0x1000>; + interrupts = <14 IRQ_TYPE_LOWEST_LEVEL_LOW 3>; + interrupt-parent = <&intc>; + + group-index = <0x2>; + gpio-controller; + #gpio-cells = <2>; + + ngpios = <20>; + pin-offset = <25>; + + status = "okay"; + }; + + gpio_2_gpd: gpio@fd6c0700 { + compatible = "intel,gpio"; + reg = <0xfd6c0700 0x1000>; + interrupts = <14 IRQ_TYPE_LOWEST_LEVEL_LOW 3>; + interrupt-parent = <&intc>; + + group-index = <0x0>; + gpio-controller; + #gpio-cells = <2>; + + ngpios = <12>; + pin-offset = <0>; + + status = "okay"; + }; + + gpio_4_c: gpio@fd6a0700 { + compatible = "intel,gpio"; + reg = <0xfd6a0700 0x1000>; + interrupts = <14 IRQ_TYPE_LOWEST_LEVEL_LOW 3>; + interrupt-parent = <&intc>; + + group-index = <0x0>; + gpio-controller; + #gpio-cells = <2>; + + ngpios = <24>; + pin-offset = <0>; + + status = "okay"; + }; + + gpio_4_f: gpio@fd6a0880 { + compatible = "intel,gpio"; + reg = <0xfd6a0880 0x1000>; + interrupts = <14 IRQ_TYPE_LOWEST_LEVEL_LOW 3>; + interrupt-parent = <&intc>; + + group-index = <0x1>; + gpio-controller; + #gpio-cells = <2>; + + ngpios = <24>; + pin-offset = <24>; + + status = "okay"; + }; + + gpio_4_e: gpio@fd6a0a70 { + compatible = "intel,gpio"; + reg = <0xfd6a0a70 0x1000>; + interrupts = <14 IRQ_TYPE_LOWEST_LEVEL_LOW 3>; + interrupt-parent = <&intc>; + + group-index = <0x3>; + gpio-controller; + #gpio-cells = <2>; + + ngpios = <24>; + pin-offset = <57>; + + status = "okay"; + }; + + gpio_5_r: gpio@fd690700 { + compatible = "intel,gpio"; + reg = <0xfd690700 0x1000>; + interrupts = <14 IRQ_TYPE_LOWEST_LEVEL_LOW 3>; + interrupt-parent = <&intc>; + + group-index = <0x0>; + gpio-controller; + #gpio-cells = <2>; + + ngpios = <8>; + pin-offset = <0>; + + status = "okay"; + }; + + tgpio: tgpio@fe001200 { + compatible = "intel,timeaware-gpio"; + reg = <0xfe001200 0x100>; + timer-clock = <19200000>; + max-pins = <2>; + + status = "okay"; + }; + + rtc: counter: rtc@70 { + compatible = "motorola,mc146818"; + reg = <0x70 0x0D 0x71 0x0D>; + interrupts = <8 IRQ_TYPE_LOWEST_EDGE_RISING 3>; + interrupt-parent = <&intc>; + alarms-count = <1>; + + status = "okay"; + }; + + hpet: hpet@fed00000 { + compatible = "intel,hpet"; + reg = <0xfed00000 0x400>; + interrupts = <2 IRQ_TYPE_FIXED_EDGE_RISING 4>; + interrupt-parent = <&intc>; + + status = "okay"; + }; + + tco_wdt: tco_wdt@400 { + compatible = "intel,tco-wdt"; + reg = <0x0400 0x20>; + + status = "disabled"; + }; + + pwm0: pwm0@fd6d0000 { + compatible = "intel,blinky-pwm"; + reg = <0xfd6d0000 0x400>; + reg-offset = <0x204>; + clock-frequency = <32768>; + max-pins = <1>; + #pwm-cells = <2>; + + status = "okay"; + }; + }; +}; From b7609ff5a837b0574cdf5e3cbe87e4d3b808a5c9 Mon Sep 17 00:00:00 2001 From: Anisetti Avinash Krishna Date: Fri, 11 Aug 2023 12:38:01 +0530 Subject: [PATCH 1586/3723] soc: x86: raptor_lake: soc_gpio : Modified to support RPL-P Added Modifications to support RPL-P platform. Signed-off-by: Anisetti Avinash Krishna --- soc/x86/raptor_lake/soc_gpio.h | 14 +++++++++++--- 1 file changed, 11 insertions(+), 3 deletions(-) diff --git a/soc/x86/raptor_lake/soc_gpio.h b/soc/x86/raptor_lake/soc_gpio.h index 544df564a08..6901cab9221 100644 --- a/soc/x86/raptor_lake/soc_gpio.h +++ b/soc/x86/raptor_lake/soc_gpio.h @@ -15,14 +15,22 @@ #ifndef __SOC_GPIO_H_ #define __SOC_GPIO_H_ +#if defined(CONFIG_BOARD_INTEL_RPL_S_CRB) #define GPIO_INTEL_NR_SUBDEVS 13 - #define REG_PAD_OWNER_BASE 0x00A0 #define REG_GPI_INT_STS_BASE 0x0200 -#define PAD_CFG0_PMODE_MASK (0x07 << 10) - #define REG_GPI_INT_EN_BASE 0x0220 #define REG_PAD_HOST_SW_OWNER 0x150 + +#elif defined(CONFIG_BOARD_INTEL_RPL_P_CRB) +#define GPIO_INTEL_NR_SUBDEVS 11 +#define REG_PAD_OWNER_BASE 0x0020 +#define REG_GPI_INT_STS_BASE 0x0100 +#define REG_GPI_INT_EN_BASE 0x0120 +#define REG_PAD_HOST_SW_OWNER 0x0B0 +#endif + +#define PAD_CFG0_PMODE_MASK (0x07 << 10) #define PAD_BASE_ADDR_MASK 0xfff #define GPIO_REG_BASE(reg_base) \ From b14feec6c47656b133fb2b85a5c037f442a22e85 Mon Sep 17 00:00:00 2001 From: Anisetti Avinash Krishna Date: Fri, 11 Aug 2023 12:41:53 +0530 Subject: [PATCH 1587/3723] boards: x86: rpl_crb: rpl_p_crb: Enabled GPIO in RPL-p Enabled GPIO basic api test for RPL-P platform Signed-off-by: Anisetti Avinash Krishna --- .../gpio_basic_api/boards/intel_rpl_p_crb.overlay | 13 +++++++++++++ 1 file changed, 13 insertions(+) create mode 100644 tests/drivers/gpio/gpio_basic_api/boards/intel_rpl_p_crb.overlay diff --git a/tests/drivers/gpio/gpio_basic_api/boards/intel_rpl_p_crb.overlay b/tests/drivers/gpio/gpio_basic_api/boards/intel_rpl_p_crb.overlay new file mode 100644 index 00000000000..14a6f676558 --- /dev/null +++ b/tests/drivers/gpio/gpio_basic_api/boards/intel_rpl_p_crb.overlay @@ -0,0 +1,13 @@ +/* + * Copyright (c) 2023 Intel Corporation + * + * SPDX-License-Identifier: Apache-2.0 + */ +/ { + resources { + compatible = "test-gpio-basic-api"; + + out-gpios = <&gpio_4_e 13 0>; + in-gpios = <&gpio_4_e 12 0>; + }; +}; From 3974882b427910a0d6beb5942e67c97a6dca2a2c Mon Sep 17 00:00:00 2001 From: Bindu S Date: Thu, 14 Sep 2023 15:27:29 +0530 Subject: [PATCH 1588/3723] tests: drivers: spi: spi_loopback: Enabled SPI in RPL-P Added overlay and conf to enable SPI tests on RPL-P board. Signed-off-by: Bindu S --- .../spi_loopback/boards/intel_rpl_p_crb.conf | 4 +++ .../boards/intel_rpl_p_crb.overlay | 25 +++++++++++++++++++ 2 files changed, 29 insertions(+) create mode 100644 tests/drivers/spi/spi_loopback/boards/intel_rpl_p_crb.conf create mode 100644 tests/drivers/spi/spi_loopback/boards/intel_rpl_p_crb.overlay diff --git a/tests/drivers/spi/spi_loopback/boards/intel_rpl_p_crb.conf b/tests/drivers/spi/spi_loopback/boards/intel_rpl_p_crb.conf new file mode 100644 index 00000000000..469a8f7c445 --- /dev/null +++ b/tests/drivers/spi/spi_loopback/boards/intel_rpl_p_crb.conf @@ -0,0 +1,4 @@ +CONFIG_SPI=y +CONFIG_SPI_ASYNC=n +CONFIG_GPIO=y +CONFIG_SPI_LOOPBACK_MODE_LOOP=y diff --git a/tests/drivers/spi/spi_loopback/boards/intel_rpl_p_crb.overlay b/tests/drivers/spi/spi_loopback/boards/intel_rpl_p_crb.overlay new file mode 100644 index 00000000000..403a7fff2da --- /dev/null +++ b/tests/drivers/spi/spi_loopback/boards/intel_rpl_p_crb.overlay @@ -0,0 +1,25 @@ +/* + * Copyright (c) 2023 Intel Corporation + * + * SPDX-License-Identifier: Apache-2.0 + */ + +/* External Loopback: Short MOSI & MISO */ + +&spi0 { + pw,cs-mode = <0>; + pw,cs-output = <0>; + status = "okay"; + + 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 f806c04abe0810dd2b556aaf2f096aa43e1511f3 Mon Sep 17 00:00:00 2001 From: Bindu S Date: Fri, 15 Sep 2023 10:59:29 +0530 Subject: [PATCH 1589/3723] samples: sensor: Enable bme280 sensor using I2C driver for RPL-P Added overlay to enable bme280 sensor using i2c on intel_rpl_p_crb board. Signed-off-by: Bindu S --- .../sensor/bme280/boards/intel_rpl_p_crb.overlay | 13 +++++++++++++ 1 file changed, 13 insertions(+) create mode 100644 samples/sensor/bme280/boards/intel_rpl_p_crb.overlay diff --git a/samples/sensor/bme280/boards/intel_rpl_p_crb.overlay b/samples/sensor/bme280/boards/intel_rpl_p_crb.overlay new file mode 100644 index 00000000000..5868d248950 --- /dev/null +++ b/samples/sensor/bme280/boards/intel_rpl_p_crb.overlay @@ -0,0 +1,13 @@ +/* + * Copyright (c) 2023 Intel Corporation + * + * SPDX-License-Identifier: Apache-2.0 + */ + +&i2c1 { + bme280@76 { + compatible = "bosch,bme280"; + reg = <0x76>; + status = "okay"; + }; +}; From 5d0ba230b8eefd68b56b23f981d9a102e6d30ff8 Mon Sep 17 00:00:00 2001 From: Andrei Emeltchenko Date: Wed, 20 Dec 2023 14:27:20 +0200 Subject: [PATCH 1590/3723] tests: samples: watchdog: Add intel_rpl_p_crb overlay Add overlay to enable watchdog for build test and sample. Signed-off-by: Andrei Emeltchenko --- samples/drivers/watchdog/boards/intel_rpl_p_crb.overlay | 9 +++++++++ .../wdt_basic_api/boards/intel_rpl_p_crb.overlay | 9 +++++++++ 2 files changed, 18 insertions(+) create mode 100644 samples/drivers/watchdog/boards/intel_rpl_p_crb.overlay create mode 100644 tests/drivers/watchdog/wdt_basic_api/boards/intel_rpl_p_crb.overlay diff --git a/samples/drivers/watchdog/boards/intel_rpl_p_crb.overlay b/samples/drivers/watchdog/boards/intel_rpl_p_crb.overlay new file mode 100644 index 00000000000..660b55c0512 --- /dev/null +++ b/samples/drivers/watchdog/boards/intel_rpl_p_crb.overlay @@ -0,0 +1,9 @@ +/* + * Copyright (c) 2023 Intel Corporation + * + * SPDX-License-Identifier: Apache-2.0 + */ + +&tco_wdt { + status = "okay"; +}; diff --git a/tests/drivers/watchdog/wdt_basic_api/boards/intel_rpl_p_crb.overlay b/tests/drivers/watchdog/wdt_basic_api/boards/intel_rpl_p_crb.overlay new file mode 100644 index 00000000000..660b55c0512 --- /dev/null +++ b/tests/drivers/watchdog/wdt_basic_api/boards/intel_rpl_p_crb.overlay @@ -0,0 +1,9 @@ +/* + * Copyright (c) 2023 Intel Corporation + * + * SPDX-License-Identifier: Apache-2.0 + */ + +&tco_wdt { + status = "okay"; +}; From c62e371b3c2612f8ff8602125c81aec3826fb47f Mon Sep 17 00:00:00 2001 From: Andrei Emeltchenko Date: Fri, 22 Dec 2023 11:24:02 +0200 Subject: [PATCH 1591/3723] samples: bme280: Fix indentation for ADL-N overlay Fix indentation in the intel_adl_crb board overlay file. Signed-off-by: Andrei Emeltchenko --- samples/sensor/bme280/boards/intel_adl_crb.overlay | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/samples/sensor/bme280/boards/intel_adl_crb.overlay b/samples/sensor/bme280/boards/intel_adl_crb.overlay index 6b24f92e9af..957dd83180a 100644 --- a/samples/sensor/bme280/boards/intel_adl_crb.overlay +++ b/samples/sensor/bme280/boards/intel_adl_crb.overlay @@ -5,9 +5,9 @@ */ &i2c0 { - bme280@76 { - compatible = "bosch,bme280"; - reg = <0x76>; + bme280@76 { + compatible = "bosch,bme280"; + reg = <0x76>; status = "okay"; - }; + }; }; From c771a66c6c711a69d87947c93907b23222aa8f3f Mon Sep 17 00:00:00 2001 From: Andrei Emeltchenko Date: Thu, 21 Dec 2023 12:46:57 +0200 Subject: [PATCH 1592/3723] boards: intel_rpl: Update documentation for Raptor Lake Update documentation to include Raptor Lake P and update link to the correct online datasheet. Signed-off-by: Andrei Emeltchenko --- boards/x86/intel_rpl/doc/index.rst | 40 ++++++++++++++++++++---------- 1 file changed, 27 insertions(+), 13 deletions(-) diff --git a/boards/x86/intel_rpl/doc/index.rst b/boards/x86/intel_rpl/doc/index.rst index b9c64ded19e..7c3d7758484 100644 --- a/boards/x86/intel_rpl/doc/index.rst +++ b/boards/x86/intel_rpl/doc/index.rst @@ -1,23 +1,37 @@ -.. _intel_rpl_s_crb: +.. _intel_rpl_crb: -Raptor Lake S CRB -################# +Raptor Lake CRB +############### Overview ******** -Raptor Lake Reference Board (RPL CRB) is an example implementation of a -compact single board computer with high performance for IoT edge devices. +Raptor Lake processor is a 13th generation 64-bit multi-core processor built +on a 10-nanometer technology process. Raptor Lake is based on a Hybrid +architecture, utilizing P-cores for performance and E-Cores for efficiency. -This board configuration enables kernel support for the `RPL`_ board. +Raptor Lake S and Raptor Lake P processor lines are supported. -.. note:: - This board configuration works on the variant of `RPL`_ - boards containing Intel |reg| Core |trade| SoC. +The S-Processor line is a 2-Chip Platform that includes the Processor Die and +Platform Controller Hub (PCH-S) Die in the Package. + +The P-Processor line is a 2-Die Multi Chip Package (MCP) that includes the +Processor Die and Platform Controller Hub (PCH-P) Die on the same package as +the Processor Die. + +For more information about Raptor Lake Processor lines, P-cores, and E-cores +please refer to `RPL`_. + +Raptor Lake Customer Reference Board (RPL CRB) is an example implementation of a +compact single board computer with high performance for IoT edge devices. The +supported boards are `intel_rpl_s_crb` and `intel_rpl_p_crb`. + +These board configurations enable kernel support for the supported Raptor Lake +boards. Hardware ******** -General information about the board can be found at the `RPL`_ website. +General information about the board can be found at the `RPL`_. .. include:: ../../../../soc/x86/raptor_lake/doc/supported_features.txt @@ -25,11 +39,11 @@ General information about the board can be found at the `RPL`_ website. Connections and IOs =================== -Refer to the `RPL`_ website for more information. +Refer to the `RPL`_ for more information. Programming and Debugging ************************* -Use the following procedures for booting an image on a RPL CRB board. +Use the following procedures for booting an image on an RPL CRB board. .. contents:: :depth: 1 @@ -58,4 +72,4 @@ Booting the Raptor Lake S CRB Board using UEFI .. include:: ../../common/efi_boot.rst :start-after: start_include_here -.. _RPL: https://www.intel.com/content/www/us/en/newsroom/resources/13th-gen-core.html#gs.glf2fn +.. _RPL: https://edc.intel.com/content/www/us/en/design/products/platforms/details/raptor-lake-s/13th-generation-core-processors-datasheet-volume-1-of-2/ From ba80bc713442c158a1b51b21bcd8b4831f28bbe2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Th=C3=A9o=20Battrel?= Date: Thu, 21 Dec 2023 09:52:35 +0100 Subject: [PATCH 1593/3723] Tests: Bluetooth: Fix conn_stress compilation warn MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit On newer GCC version warnings were emitted because of a `memcpy`. The size parameter was larger than the source's size because it was using the size of the destination, which was a `bt_uuid_128` when the source is a `bt_uuid_16`. Fix the issue by creating a new variable for CCC UUID in both the central and peripheral code. The variable need to be static because the discover parameters must remain valid until the start of the discover attribute callback. Signed-off-by: Théo Battrel --- .../bsim/bluetooth/host/misc/conn_stress/central/src/main.c | 6 ++++-- .../bluetooth/host/misc/conn_stress/peripheral/src/main.c | 6 ++++-- 2 files changed, 8 insertions(+), 4 deletions(-) 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 32da1c63df5..96ca51c448a 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 @@ -96,6 +96,8 @@ static struct conn_info conn_infos[CONFIG_BT_MAX_CONN] = {0}; static uint32_t conn_interval_max, notification_size; static uint8_t vnd_value[CHARACTERISTIC_DATA_MAX_LEN]; +static const struct bt_uuid_16 ccc_uuid = BT_UUID_INIT_16(BT_UUID_GATT_CCC_VAL); + void clear_info(struct conn_info *info) { /* clear everything except the address + sub params + uuid (lifetime > connection) */ @@ -250,8 +252,8 @@ static uint8_t discover_func(struct bt_conn *conn, const struct bt_gatt_attr *at } else if (conn_info_ref->discover_params.type == BT_GATT_DISCOVER_CHARACTERISTIC) { LOG_DBG("Service Characteristic Found"); - memcpy(&conn_info_ref->uuid, BT_UUID_GATT_CCC, sizeof(conn_info_ref->uuid)); - conn_info_ref->discover_params.uuid = &conn_info_ref->uuid.uuid; + + conn_info_ref->discover_params.uuid = &ccc_uuid.uuid; conn_info_ref->discover_params.start_handle = attr->handle + 2; conn_info_ref->discover_params.type = BT_GATT_DISCOVER_DESCRIPTOR; conn_info_ref->subscribe_params.value_handle = bt_gatt_attr_value_handle(attr); 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 f78228b0be8..d0e0b9fb6a3 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 @@ -94,6 +94,8 @@ static struct bt_uuid_128 uuid = BT_UUID_INIT_128(0); static struct bt_gatt_discover_params discover_params; static struct bt_gatt_subscribe_params subscribe_params; +static const struct bt_uuid_16 ccc_uuid = BT_UUID_INIT_16(BT_UUID_GATT_CCC_VAL); + static void vnd_ccc_cfg_changed(const struct bt_gatt_attr *attr, uint16_t value) { central_subscription = (value == BT_GATT_CCC_NOTIFY) ? 1 : 0; @@ -277,8 +279,8 @@ static uint8_t discover_func(struct bt_conn *conn, const struct bt_gatt_attr *at } else if (discover_params.type == BT_GATT_DISCOVER_CHARACTERISTIC) { LOG_DBG("Service Characteristic Found"); - memcpy(&uuid, BT_UUID_GATT_CCC, sizeof(uuid)); - params->uuid = &uuid.uuid; + + params->uuid = &ccc_uuid.uuid; params->start_handle = attr->handle + 2; params->type = BT_GATT_DISCOVER_DESCRIPTOR; subscribe_params.value_handle = bt_gatt_attr_value_handle(attr); From dc6e7aa4b15b11094f2604c35180f7c72656896d Mon Sep 17 00:00:00 2001 From: Seppo Takalo Date: Thu, 21 Dec 2023 14:35:35 +0200 Subject: [PATCH 1594/3723] net: lwm2m: Add transmission state indicator to RX as well Refactored the socket state indication into its own function that checks the state of TX queues as well as number of pending CoAP responses. Check the state after receiving a packet, as it might have been a last Ack packet we have been waiting. Signed-off-by: Seppo Takalo --- subsys/net/lib/lwm2m/lwm2m_engine.c | 72 +++++++++++++++++++---------- 1 file changed, 47 insertions(+), 25 deletions(-) diff --git a/subsys/net/lib/lwm2m/lwm2m_engine.c b/subsys/net/lib/lwm2m/lwm2m_engine.c index d5a289a111f..639f65ea0fa 100644 --- a/subsys/net/lib/lwm2m/lwm2m_engine.c +++ b/subsys/net/lib/lwm2m/lwm2m_engine.c @@ -630,6 +630,50 @@ static int64_t check_notifications(struct lwm2m_ctx *ctx, const int64_t timestam return next; } +/** + * @brief Check TX queue states as well as number or pending CoAP transmissions. + * + * If all queues are empty and there is no packet we are currently transmitting and no + * CoAP responses (pendings) we are waiting, inform the application by a callback + * that socket is in state LWM2M_SOCKET_STATE_NO_DATA. + * Otherwise, before sending a packet, depending on the state of the queues, inform with + * one of the ONGOING, ONE_RESPONSE or LAST indicators. + * + * @param ctx Client context. + * @param ongoing_tx Current packet to be transmitted or NULL. + */ +static void hint_socket_state(struct lwm2m_ctx *ctx, struct lwm2m_message *ongoing_tx) +{ + if (!ctx->set_socket_state) { + return; + } + +#if defined(CONFIG_LWM2M_QUEUE_MODE_ENABLED) + bool empty = sys_slist_is_empty(&ctx->pending_sends) && + sys_slist_is_empty(&ctx->queued_messages); +#else + bool empty = sys_slist_is_empty(&ctx->pending_sends); +#endif + size_t pendings = coap_pendings_count(ctx->pendings, ARRAY_SIZE(ctx->pendings)); + + if (ongoing_tx) { + /* Check if more than current TX is in pendings list*/ + if (pendings > 1) { + empty = false; + } + + if (!empty) { + ctx->set_socket_state(ctx->sock_fd, LWM2M_SOCKET_STATE_ONGOING); + } else if (ongoing_tx->type == COAP_TYPE_CON) { + ctx->set_socket_state(ctx->sock_fd, LWM2M_SOCKET_STATE_ONE_RESPONSE); + } else { + ctx->set_socket_state(ctx->sock_fd, LWM2M_SOCKET_STATE_LAST); + } + } else if (empty && pendings == 0) { + ctx->set_socket_state(ctx->sock_fd, LWM2M_SOCKET_STATE_NO_DATA); + } +} + static int socket_recv_message(struct lwm2m_ctx *client_ctx) { static uint8_t in_buf[NET_IPV6_MTU]; @@ -684,31 +728,7 @@ static int socket_send_message(struct lwm2m_ctx *ctx) coap_pending_cycle(msg->pending); } - if (ctx->set_socket_state) { -#if defined(CONFIG_LWM2M_QUEUE_MODE_ENABLED) - bool empty = sys_slist_is_empty(&ctx->pending_sends) && - sys_slist_is_empty(&ctx->queued_messages); -#else - bool empty = sys_slist_is_empty(&ctx->pending_sends); -#endif - if (coap_pendings_count(ctx->pendings, ARRAY_SIZE(ctx->pendings)) > 1) { - empty = false; - } - - if (!empty) { - ctx->set_socket_state(ctx->sock_fd, LWM2M_SOCKET_STATE_ONGOING); - } else { - switch (msg->type) { - case COAP_TYPE_CON: - ctx->set_socket_state(ctx->sock_fd, - LWM2M_SOCKET_STATE_ONE_RESPONSE); - break; - default: - ctx->set_socket_state(ctx->sock_fd, LWM2M_SOCKET_STATE_LAST); - break; - } - } - } + hint_socket_state(ctx, msg); rc = zsock_send(msg->ctx->sock_fd, msg->cpkt.data, msg->cpkt.offset, 0); @@ -847,6 +867,8 @@ static void socket_loop(void *p1, void *p2, void *p3) break; } } + + hint_socket_state(sock_ctx[i], NULL); } if (sock_fds[i].revents & ZSOCK_POLLOUT) { From 3f148d6bb47e87b729d86c2ab8f80fad5ccbf8fb Mon Sep 17 00:00:00 2001 From: Chekhov Ma Date: Wed, 13 Dec 2023 11:51:13 +0800 Subject: [PATCH 1595/3723] arch: arm: mmu: generate mmu region entry from devicetree Many peripherals have multiple instances, whether each of them are enabled are not known. Adding all available instances into "mmu_regions" array may not be the best choice. This commit adds a macro to generate mmu region entry in "mmu_regions" from devicetree. Used with "DT_FOREACH_STATUS_OKAY_VARGS", it generates mmu region entry for all nodes enabled and compatiable to a certain driver. Signed-off-by: Chekhov Ma --- include/zephyr/arch/arm/mmu/arm_mmu.h | 39 +++++++++++++++++++++++++++ include/zephyr/arch/arm64/arm_mmu.h | 39 +++++++++++++++++++++++++++ 2 files changed, 78 insertions(+) diff --git a/include/zephyr/arch/arm/mmu/arm_mmu.h b/include/zephyr/arch/arm/mmu/arm_mmu.h index a4f0fe34b4d..4179436615d 100644 --- a/include/zephyr/arch/arm/mmu/arm_mmu.h +++ b/include/zephyr/arch/arm/mmu/arm_mmu.h @@ -67,6 +67,45 @@ #define MMU_REGION_FLAT_ENTRY(name, adr, sz, attrs) \ MMU_REGION_ENTRY(name, adr, adr, sz, attrs) +/* + * @brief Auto generate mmu region entry for node_id + * + * Example usage: + * + * @code{.c} + * DT_FOREACH_STATUS_OKAY_VARGS(nxp_imx_gpio, + * MMU_REGION_DT_FLAT_ENTRY, + * (MT_DEVICE_nGnRnE | MT_P_RW_U_NA | MT_NS)) + * @endcode + * + * @note Since devicetree_generated.h does not include + * node_id##_P_reg_FOREACH_PROP_ELEM* definitions, + * we can't automate dts node with multiple reg + * entries. + */ +#define MMU_REGION_DT_FLAT_ENTRY(node_id, attrs) \ + MMU_REGION_FLAT_ENTRY(DT_NODE_FULL_NAME(node_id), \ + DT_REG_ADDR(node_id), \ + DT_REG_SIZE(node_id), \ + attrs), + +/* + * @brief Auto generate mmu region entry for status = "okay" + * nodes compatible to a driver + * + * Example usage: + * + * @code{.c} + * MMU_REGION_DT_COMPAT_FOREACH_FLAT_ENTRY(nxp_imx_gpio, + * (MT_DEVICE_nGnRnE | MT_P_RW_U_NA | MT_NS)) + * @endcode + * + * @note This is a wrapper of @ref MMU_REGION_DT_FLAT_ENTRY + */ +#define MMU_REGION_DT_COMPAT_FOREACH_FLAT_ENTRY(compat, attr) \ + DT_FOREACH_STATUS_OKAY_VARGS(compat, \ + MMU_REGION_DT_FLAT_ENTRY, attr) + /* Region definition data structure */ struct arm_mmu_region { /* Region Base Physical Address */ diff --git a/include/zephyr/arch/arm64/arm_mmu.h b/include/zephyr/arch/arm64/arm_mmu.h index 6f71ac25897..b0c197b9b2b 100644 --- a/include/zephyr/arch/arm64/arm_mmu.h +++ b/include/zephyr/arch/arm64/arm_mmu.h @@ -207,6 +207,45 @@ struct arm_mmu_ptables { #define MMU_REGION_FLAT_ENTRY(name, adr, sz, attrs) \ MMU_REGION_ENTRY(name, adr, adr, sz, attrs) +/* + * @brief Auto generate mmu region entry for node_id + * + * Example usage: + * + * @code{.c} + * DT_FOREACH_STATUS_OKAY_VARGS(nxp_imx_gpio, + * MMU_REGION_DT_FLAT_ENTRY, + * (MT_DEVICE_nGnRnE | MT_P_RW_U_NA | MT_NS)) + * @endcode + * + * @note Since devicetree_generated.h does not include + * node_id##_P_reg_FOREACH_PROP_ELEM* definitions, + * we can't automate dts node with multiple reg + * entries. + */ +#define MMU_REGION_DT_FLAT_ENTRY(node_id, attrs) \ + MMU_REGION_FLAT_ENTRY(DT_NODE_FULL_NAME(node_id), \ + DT_REG_ADDR(node_id), \ + DT_REG_SIZE(node_id), \ + attrs), + +/* + * @brief Auto generate mmu region entry for status = "okay" + * nodes compatible to a driver + * + * Example usage: + * + * @code{.c} + * MMU_REGION_DT_COMPAT_FOREACH_FLAT_ENTRY(nxp_imx_gpio, + * (MT_DEVICE_nGnRnE | MT_P_RW_U_NA | MT_NS)) + * @endcode + * + * @note This is a wrapper of @ref MMU_REGION_DT_FLAT_ENTRY + */ +#define MMU_REGION_DT_COMPAT_FOREACH_FLAT_ENTRY(compat, attr) \ + DT_FOREACH_STATUS_OKAY_VARGS(compat, \ + MMU_REGION_DT_FLAT_ENTRY, attr) + /* Kernel macros for memory attribution * (access permissions and cache-ability). * From 81c5a093f3421cf985e6cb8f00f7e89362c5c82c Mon Sep 17 00:00:00 2001 From: Chekhov Ma Date: Fri, 8 Dec 2023 13:50:08 +0800 Subject: [PATCH 1596/3723] imx93: auto generate mmu_regions array from dt compatiable Adopt the "MMU_REGION_DT_FLAT_ENTRY" macro to automatically generate elements in "mmu_regions" according to devicetree "compatible" and "status". Signed-off-by: Chekhov Ma --- soc/arm64/nxp_imx/mimx9/mmu_regions.c | 13 +++---------- 1 file changed, 3 insertions(+), 10 deletions(-) diff --git a/soc/arm64/nxp_imx/mimx9/mmu_regions.c b/soc/arm64/nxp_imx/mimx9/mmu_regions.c index 6dd767c2c9c..15ca8c39618 100644 --- a/soc/arm64/nxp_imx/mimx9/mmu_regions.c +++ b/soc/arm64/nxp_imx/mimx9/mmu_regions.c @@ -30,21 +30,14 @@ static const struct arm_mmu_region mmu_regions[] = { DT_REG_SIZE(DT_NODELABEL(ana_pll)), MT_DEVICE_nGnRnE | MT_P_RW_U_NA | MT_NS), - MMU_REGION_FLAT_ENTRY("UART1", - DT_REG_ADDR(DT_NODELABEL(lpuart1)), - DT_REG_SIZE(DT_NODELABEL(lpuart1)), - MT_DEVICE_nGnRnE | MT_P_RW_U_NA | MT_NS), - - MMU_REGION_FLAT_ENTRY("UART2", - DT_REG_ADDR(DT_NODELABEL(lpuart2)), - DT_REG_SIZE(DT_NODELABEL(lpuart2)), - MT_DEVICE_nGnRnE | MT_P_RW_U_NA | MT_NS), - MMU_REGION_FLAT_ENTRY("IOMUXC", DT_REG_ADDR(DT_NODELABEL(iomuxc)), DT_REG_SIZE(DT_NODELABEL(iomuxc)), MT_DEVICE_nGnRnE | MT_P_RW_U_NA | MT_NS), + MMU_REGION_DT_COMPAT_FOREACH_FLAT_ENTRY(nxp_kinetis_lpuart, + (MT_DEVICE_nGnRnE | MT_P_RW_U_NA | MT_NS)) + #if CONFIG_SOF MMU_REGION_FLAT_ENTRY("MU2_A", DT_REG_ADDR(DT_NODELABEL(mu2_a)), From d1c6bb5cb4b96812b48a55646fda863c900316ce Mon Sep 17 00:00:00 2001 From: Chekhov Ma Date: Fri, 8 Dec 2023 13:50:27 +0800 Subject: [PATCH 1597/3723] imx8m: auto generate mmu_regions array from dt compatiable Adopt the "MMU_REGION_DT_FLAT_ENTRY" macro to automatically generate elements in "mmu_regions" according to devicetree "compatible" and "status". Signed-off-by: Chekhov Ma --- soc/arm64/nxp_imx/mimx8m/mmu_regions.c | 13 +++---------- 1 file changed, 3 insertions(+), 10 deletions(-) diff --git a/soc/arm64/nxp_imx/mimx8m/mmu_regions.c b/soc/arm64/nxp_imx/mimx8m/mmu_regions.c index 4add4386ef5..e6dd90ecc28 100644 --- a/soc/arm64/nxp_imx/mimx8m/mmu_regions.c +++ b/soc/arm64/nxp_imx/mimx8m/mmu_regions.c @@ -25,25 +25,18 @@ static const struct arm_mmu_region mmu_regions[] = { DT_REG_SIZE(DT_NODELABEL(ccm)), MT_DEVICE_nGnRnE | MT_P_RW_U_NA | MT_NS), - MMU_REGION_FLAT_ENTRY("UART2", - DT_REG_ADDR(DT_NODELABEL(uart2)), - DT_REG_SIZE(DT_NODELABEL(uart2)), - MT_DEVICE_nGnRnE | MT_P_RW_U_NA | MT_NS), - MMU_REGION_FLAT_ENTRY("ANA_PLL", DT_REG_ADDR(DT_NODELABEL(ana_pll)), DT_REG_SIZE(DT_NODELABEL(ana_pll)), MT_DEVICE_nGnRnE | MT_P_RW_U_NA | MT_NS), - MMU_REGION_FLAT_ENTRY("UART4", - DT_REG_ADDR(DT_NODELABEL(uart4)), - DT_REG_SIZE(DT_NODELABEL(uart4)), - MT_DEVICE_nGnRnE | MT_P_RW_U_NA | MT_NS), - MMU_REGION_FLAT_ENTRY("IOMUXC", DT_REG_ADDR(DT_NODELABEL(iomuxc)), DT_REG_SIZE(DT_NODELABEL(iomuxc)), MT_DEVICE_nGnRnE | MT_P_RW_U_NA | MT_NS), + + MMU_REGION_DT_COMPAT_FOREACH_FLAT_ENTRY(nxp_imx_iuart, + (MT_DEVICE_nGnRnE | MT_P_RW_U_NA | MT_NS)) }; const struct arm_mmu_config mmu_config = { From 7525cc79431b7186a563f3ee5add42fd56e3b286 Mon Sep 17 00:00:00 2001 From: Dmitrii Golovanov Date: Fri, 22 Dec 2023 20:43:14 +0100 Subject: [PATCH 1598/3723] twister: coverage: Remove dead code at BinaryHandler BinaryHandler.hanlde() method was trying to call GCOV and fails silently because of incorrect call parameters. Moreover, even being fixed, this call is not needed here as it attempts to find and process .gcno and .gcna files (using wrong paths) to create .gcov coverage text reports. Currently the CoverageTool class does all data processing and report generation using GCOVR or LCOV tools instead of direct calls to GCOV. Signed-off-by: Dmitrii Golovanov --- scripts/pylib/twister/twisterlib/handlers.py | 4 ---- scripts/tests/twister/test_handlers.py | 7 ------- 2 files changed, 11 deletions(-) diff --git a/scripts/pylib/twister/twisterlib/handlers.py b/scripts/pylib/twister/twisterlib/handlers.py index 0d6ec5976c7..da902cc5ef6 100755 --- a/scripts/pylib/twister/twisterlib/handlers.py +++ b/scripts/pylib/twister/twisterlib/handlers.py @@ -326,10 +326,6 @@ def handle(self, harness): handler_time = time.time() - start_time - if self.options.coverage: - subprocess.call(["GCOV_PREFIX=" + self.build_dir, - "gcov", self.sourcedir, "-b", "-s", self.build_dir], shell=True) - # FIXME: This is needed when killing the simulator, the console is # garbled and needs to be reset. Did not find a better way to do that. if sys.stdout.isatty(): diff --git a/scripts/tests/twister/test_handlers.py b/scripts/tests/twister/test_handlers.py index e66b73055c8..931df46e674 100644 --- a/scripts/tests/twister/test_handlers.py +++ b/scripts/tests/twister/test_handlers.py @@ -640,13 +640,6 @@ def mock_thread(target, *args, **kwargs): handler._update_instance_info.assert_called_once() handler._final_handle_actions.assert_called_once() - if coverage: - call_mock.assert_any_call( - ['GCOV_PREFIX=build_dir', 'gcov', 'source_dir', - '-b', '-s', 'build_dir'], - shell=True - ) - if isatty: call_mock.assert_any_call(['stty', 'sane'], stdin=mock.ANY) From 250d50e8b69bede0076a75f5271f5e9e5ba12fe2 Mon Sep 17 00:00:00 2001 From: Pisit Sawangvonganan Date: Mon, 25 Dec 2023 00:10:03 +0700 Subject: [PATCH 1599/3723] drivers: rtc: set 'rtc_driver_api' as 'static const' This change marks each instance of the 'rtc_driver_api' as 'static const'. The rationale is that 'rtc_driver_api' is used for declaring internal module interfaces and is not intended to be modified at runtime. By using 'static const', we ensure immutability, leading to usage of only .rodata and a reduction in the .data area. Signed-off-by: Pisit Sawangvonganan --- drivers/rtc/rtc_emul.c | 2 +- drivers/rtc/rtc_fake.c | 2 +- drivers/rtc/rtc_ll_stm32.c | 2 +- drivers/rtc/rtc_mc146818.c | 2 +- drivers/rtc/rtc_sam.c | 2 +- drivers/rtc/rtc_smartbond.c | 2 +- 6 files changed, 6 insertions(+), 6 deletions(-) diff --git a/drivers/rtc/rtc_emul.c b/drivers/rtc/rtc_emul.c index bf95fa87813..9ce6b5dbc25 100644 --- a/drivers/rtc/rtc_emul.c +++ b/drivers/rtc/rtc_emul.c @@ -461,7 +461,7 @@ static int rtc_emul_get_calibration(const struct device *dev, int32_t *calibrati } #endif /* CONFIG_RTC_CALIBRATION */ -struct rtc_driver_api rtc_emul_driver_api = { +static const struct rtc_driver_api rtc_emul_driver_api = { .set_time = rtc_emul_set_time, .get_time = rtc_emul_get_time, #ifdef CONFIG_RTC_ALARM diff --git a/drivers/rtc/rtc_fake.c b/drivers/rtc/rtc_fake.c index 3a96da7141d..f02cf48b2e8 100644 --- a/drivers/rtc/rtc_fake.c +++ b/drivers/rtc/rtc_fake.c @@ -70,7 +70,7 @@ static void fake_rtc_reset_rule_before(const struct ztest_unit_test *test, void ZTEST_RULE(fake_rtc_reset_rule, fake_rtc_reset_rule_before, NULL); #endif /* CONFIG_ZTEST */ -struct rtc_driver_api rtc_fake_driver_api = { +static const struct rtc_driver_api rtc_fake_driver_api = { .set_time = rtc_fake_set_time, .get_time = rtc_fake_get_time, #ifdef CONFIG_RTC_ALARM diff --git a/drivers/rtc/rtc_ll_stm32.c b/drivers/rtc/rtc_ll_stm32.c index ca0f9dc24e1..020cd22ae2b 100644 --- a/drivers/rtc/rtc_ll_stm32.c +++ b/drivers/rtc/rtc_ll_stm32.c @@ -390,7 +390,7 @@ static int rtc_stm32_get_calibration(const struct device *dev, int32_t *calibrat #endif #endif /* CONFIG_RTC_CALIBRATION */ -struct rtc_driver_api rtc_stm32_driver_api = { +static const struct rtc_driver_api rtc_stm32_driver_api = { .set_time = rtc_stm32_set_time, .get_time = rtc_stm32_get_time, /* RTC_ALARM not supported */ diff --git a/drivers/rtc/rtc_mc146818.c b/drivers/rtc/rtc_mc146818.c index 6ecdfafa634..15d36c623b0 100644 --- a/drivers/rtc/rtc_mc146818.c +++ b/drivers/rtc/rtc_mc146818.c @@ -495,7 +495,7 @@ static void rtc_mc146818_isr(const struct device *dev) #endif } -struct rtc_driver_api rtc_mc146818_driver_api = { +static const struct rtc_driver_api rtc_mc146818_driver_api = { .set_time = rtc_mc146818_set_time, .get_time = rtc_mc146818_get_time, #if defined(CONFIG_RTC_ALARM) diff --git a/drivers/rtc/rtc_sam.c b/drivers/rtc/rtc_sam.c index 059a2b1b33e..e50edd94e3c 100644 --- a/drivers/rtc/rtc_sam.c +++ b/drivers/rtc/rtc_sam.c @@ -645,7 +645,7 @@ static int rtc_sam_get_calibration(const struct device *dev, int32_t *calibratio } #endif /* CONFIG_RTC_CALIBRATION */ -static struct rtc_driver_api rtc_sam_driver_api = { +static const struct rtc_driver_api rtc_sam_driver_api = { .set_time = rtc_sam_set_time, .get_time = rtc_sam_get_time, #ifdef CONFIG_RTC_ALARM diff --git a/drivers/rtc/rtc_smartbond.c b/drivers/rtc/rtc_smartbond.c index a16c8ebaeef..bfac974e874 100644 --- a/drivers/rtc/rtc_smartbond.c +++ b/drivers/rtc/rtc_smartbond.c @@ -561,7 +561,7 @@ static int rtc_smartbond_update_set_callback(const struct device *dev, rtc_updat } #endif -struct rtc_driver_api rtc_smartbond_driver_api = { +static const struct rtc_driver_api rtc_smartbond_driver_api = { .get_time = rtc_smartbond_get_time, .set_time = rtc_smartbond_set_time, #if defined(CONFIG_RTC_ALARM) From 4307882dd17b98e0396604cf2d2aab4d0656c098 Mon Sep 17 00:00:00 2001 From: Fabio Baltieri Date: Mon, 11 Dec 2023 16:11:12 +0000 Subject: [PATCH 1600/3723] input: kbd_matrix: add actual key mask runtime control Add an option to enable a input_kbd_matrix_actual_key_mask_set API to enable or disable keys dynamically in the mask. This can be useful if the exact key mask is determined in runtime and the device is using a single firmware for multiple matrix configurations. Signed-off-by: Fabio Baltieri --- drivers/input/Kconfig.kbd_matrix | 7 ++++ drivers/input/input_kbd_matrix.c | 16 ++++++++ include/zephyr/input/input_kbd_matrix.h | 32 ++++++++++++++-- tests/drivers/input/kbd_matrix/src/main.c | 39 ++++++++++++++++++++ tests/drivers/input/kbd_matrix/testcase.yaml | 4 ++ 5 files changed, 95 insertions(+), 3 deletions(-) diff --git a/drivers/input/Kconfig.kbd_matrix b/drivers/input/Kconfig.kbd_matrix index 2ff139acde0..cbacb9ca4c0 100644 --- a/drivers/input/Kconfig.kbd_matrix +++ b/drivers/input/Kconfig.kbd_matrix @@ -27,6 +27,13 @@ config INPUT_KBD_MATRIX_16_BIT_ROW Use a 16 bit type for the internal structure, allow using a matrix with up to 16 rows if the driver supports it. +config INPUT_KBD_ACTUAL_KEY_MASK_DYNAMIC + bool "Allow runtime changes to the actual key mask" + help + If enabled, the actual key mask data is stored in RAM, and a + input_kbd_matrix_actual_key_mask_set() function is available to + change the content at runtime. + config INPUT_SHELL_KBD_MATRIX_STATE bool "Input kbd_matrix_state shell command" depends on INPUT_SHELL diff --git a/drivers/input/input_kbd_matrix.c b/drivers/input/input_kbd_matrix.c index 6cbba73d9df..2b6c11231e9 100644 --- a/drivers/input/input_kbd_matrix.c +++ b/drivers/input/input_kbd_matrix.c @@ -323,3 +323,19 @@ int input_kbd_matrix_common_init(const struct device *dev) return 0; } + +#if CONFIG_INPUT_KBD_ACTUAL_KEY_MASK_DYNAMIC +int input_kbd_matrix_actual_key_mask_set(const struct device *dev, + uint8_t row, uint8_t col, bool enabled) +{ + const struct input_kbd_matrix_common_config *cfg = dev->config; + + if (row >= cfg->row_size || col >= cfg->col_size) { + return -EINVAL; + } + + WRITE_BIT(cfg->actual_key_mask[col], row, enabled); + + return 0; +} +#endif diff --git a/include/zephyr/input/input_kbd_matrix.h b/include/zephyr/input/input_kbd_matrix.h index 2ae1ee56b16..00692a1cf55 100644 --- a/include/zephyr/input/input_kbd_matrix.h +++ b/include/zephyr/input/input_kbd_matrix.h @@ -38,6 +38,31 @@ typedef uint8_t kbd_row_t; #define PRIkbdrow "%02x" #endif +#if CONFIG_INPUT_KBD_ACTUAL_KEY_MASK_DYNAMIC +#define INPUT_KBD_ACTUAL_KEY_MASK_CONST +/** + * @brief Enables or disables a specific row, column combination in the actual + * key mask. + * + * This allows enabling or disabling spcific row, column combination in the + * actual key mask in runtime. It can be useful if some of the keys are not + * present in some configuration, and the specific configuration is determined + * in runtime. Requires CONFIG_INPUT_KBD_ACTUAL_KEY_MASK_DYNAMIC=y. + * + * @param dev Pointer to the keyboard matrix device. + * @param row The matrix row to enable or disable. + * @param col The matrix column to enable or disable. + * @param enabled Whether the specificied row, col has to be enabled or disabled. + * + * @retval 0 If the change is successful. + * @retval -errno Negative errno if row or col are out of range for the device. + */ +int input_kbd_matrix_actual_key_mask_set(const struct device *dev, + uint8_t row, uint8_t col, bool enabled); +#else +#define INPUT_KBD_ACTUAL_KEY_MASK_CONST const +#endif + /** Maximum number of rows */ #define INPUT_KBD_MATRIX_ROW_BITS NUM_BITS(kbd_row_t) @@ -90,7 +115,7 @@ struct input_kbd_matrix_common_config { uint32_t debounce_up_us; uint32_t settle_time_us; bool ghostkey_check; - const kbd_row_t *actual_key_mask; + INPUT_KBD_ACTUAL_KEY_MASK_CONST kbd_row_t *actual_key_mask; /* extra data pointers */ kbd_row_t *matrix_stable_state; @@ -114,8 +139,9 @@ struct input_kbd_matrix_common_config { IF_ENABLED(DT_NODE_HAS_PROP(node_id, actual_key_mask), ( \ BUILD_ASSERT(DT_PROP_LEN(node_id, actual_key_mask) == _col_size, \ "actual-key-mask size does not match the number of columns"); \ - static const kbd_row_t INPUT_KBD_MATRIX_DATA_NAME(node_id, actual_key_mask)[_col_size] = \ - DT_PROP(node_id, actual_key_mask); \ + static INPUT_KBD_ACTUAL_KEY_MASK_CONST kbd_row_t \ + INPUT_KBD_MATRIX_DATA_NAME(node_id, actual_key_mask)[_col_size] = \ + DT_PROP(node_id, actual_key_mask); \ )) \ static kbd_row_t INPUT_KBD_MATRIX_DATA_NAME(node_id, stable_state)[_col_size]; \ static kbd_row_t INPUT_KBD_MATRIX_DATA_NAME(node_id, unstable_state)[_col_size]; \ diff --git a/tests/drivers/input/kbd_matrix/src/main.c b/tests/drivers/input/kbd_matrix/src/main.c index 609257c4c7a..0bb9112fc6f 100644 --- a/tests/drivers/input/kbd_matrix/src/main.c +++ b/tests/drivers/input/kbd_matrix/src/main.c @@ -374,6 +374,45 @@ ZTEST(kbd_scan, test_kbd_actual_keymap) kbd_scan_wait_for_idle(); assert_no_new_events(); } + +ZTEST(kbd_scan, test_kbd_actual_key_map_set) +{ +#if CONFIG_INPUT_KBD_ACTUAL_KEY_MASK_DYNAMIC + kbd_row_t mask[4] = {0x00, 0xff, 0x00, 0x00}; + const struct input_kbd_matrix_common_config cfg = { + .row_size = 3, + .col_size = 4, + .actual_key_mask = mask, + }; + const struct device fake_dev = { + .config = &cfg, + }; + int ret; + + ret = input_kbd_matrix_actual_key_mask_set(&fake_dev, 0, 0, true); + zassert_equal(ret, 0); + zassert_equal(mask[0], 0x01); + + ret = input_kbd_matrix_actual_key_mask_set(&fake_dev, 2, 1, false); + zassert_equal(ret, 0); + zassert_equal(mask[1], 0xfb); + + ret = input_kbd_matrix_actual_key_mask_set(&fake_dev, 2, 3, true); + zassert_equal(ret, 0); + zassert_equal(mask[3], 0x04); + + ret = input_kbd_matrix_actual_key_mask_set(&fake_dev, 3, 0, true); + zassert_equal(ret, -EINVAL); + + ret = input_kbd_matrix_actual_key_mask_set(&fake_dev, 0, 4, true); + zassert_equal(ret, -EINVAL); + + zassert_equal(memcmp(mask, (uint8_t[]){0x01, 0xfb, 0x00, 0x04}, 4), 0); +#else + ztest_test_skip(); +#endif +} + static void *kbd_scan_setup(void) { const struct input_kbd_matrix_common_config *cfg = test_dev->config; diff --git a/tests/drivers/input/kbd_matrix/testcase.yaml b/tests/drivers/input/kbd_matrix/testcase.yaml index 8ee5a9aa7a6..fc49c031a68 100644 --- a/tests/drivers/input/kbd_matrix/testcase.yaml +++ b/tests/drivers/input/kbd_matrix/testcase.yaml @@ -17,6 +17,10 @@ tests: input.input_kbd_matrix.actual_key_mask: extra_args: - EXTRA_DTC_OVERLAY_FILE=actual-key-mask.overlay + input.input_kbd_matrix.actual_key_mask_dynamic: + extra_args: + - EXTRA_DTC_OVERLAY_FILE=actual-key-mask.overlay + - CONFIG_INPUT_KBD_ACTUAL_KEY_MASK_DYNAMIC=y input.input_kbd_matrix.row_16_bit: extra_args: - CONFIG_INPUT_KBD_MATRIX_16_BIT_ROW=y From ff8970318d6a16200ecda686ca77091c9d9c89bb Mon Sep 17 00:00:00 2001 From: Fabio Baltieri Date: Mon, 11 Dec 2023 19:42:35 +0000 Subject: [PATCH 1601/3723] input: define optional functions when generating documentation Add a defined(__DOXYGEN__) condition for the optional APIs so that they get included in the documentation. Signed-off-by: Fabio Baltieri --- include/zephyr/input/input_kbd_matrix.h | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/include/zephyr/input/input_kbd_matrix.h b/include/zephyr/input/input_kbd_matrix.h index 00692a1cf55..7d3f4f37c43 100644 --- a/include/zephyr/input/input_kbd_matrix.h +++ b/include/zephyr/input/input_kbd_matrix.h @@ -38,7 +38,7 @@ typedef uint8_t kbd_row_t; #define PRIkbdrow "%02x" #endif -#if CONFIG_INPUT_KBD_ACTUAL_KEY_MASK_DYNAMIC +#if defined(CONFIG_INPUT_KBD_ACTUAL_KEY_MASK_DYNAMIC) || defined(__DOXYGEN__) #define INPUT_KBD_ACTUAL_KEY_MASK_CONST /** * @brief Enables or disables a specific row, column combination in the actual @@ -47,7 +47,8 @@ typedef uint8_t kbd_row_t; * This allows enabling or disabling spcific row, column combination in the * actual key mask in runtime. It can be useful if some of the keys are not * present in some configuration, and the specific configuration is determined - * in runtime. Requires CONFIG_INPUT_KBD_ACTUAL_KEY_MASK_DYNAMIC=y. + * in runtime. Requires @kconfig{CONFIG_INPUT_KBD_ACTUAL_KEY_MASK_DYNAMIC} to + * be enabled. * * @param dev Pointer to the keyboard matrix device. * @param row The matrix row to enable or disable. @@ -276,12 +277,13 @@ struct input_kbd_matrix_common_data { */ void input_kbd_matrix_poll_start(const struct device *dev); -#ifdef CONFIG_INPUT_KBD_DRIVE_COLUMN_HOOK +#if defined(CONFIG_INPUT_KBD_DRIVE_COLUMN_HOOK) || defined(__DOXYGEN__) /** * @brief Drive column hook * * This can be implemented by the application to handle column selection - * quirks. Called after the driver specific drive_column function. + * quirks. Called after the driver specific drive_column function. Requires + * @kconfig{CONFIG_INPUT_KBD_DRIVE_COLUMN_HOOK} to be enabled. * * @param dev Keyboard matrix device instance. * @param col The column to drive, or From 87d056bd31b14b680e6f011134c7ce433c4462f6 Mon Sep 17 00:00:00 2001 From: Flavio Ceolin Date: Fri, 22 Dec 2023 20:55:52 +0000 Subject: [PATCH 1602/3723] syscall: Fix static analysis compalins Since K_SYSCALL_MEMORY can be called with signed/unsigned size types, if we check if size >= 0, static anlysis will complain about it when size in unsigned. Signed-off-by: Flavio Ceolin --- include/zephyr/internal/syscall_handler.h | 19 ++++++++++++++++++- 1 file changed, 18 insertions(+), 1 deletion(-) diff --git a/include/zephyr/internal/syscall_handler.h b/include/zephyr/internal/syscall_handler.h index 74352ef484b..3917e4c44c0 100644 --- a/include/zephyr/internal/syscall_handler.h +++ b/include/zephyr/internal/syscall_handler.h @@ -394,6 +394,22 @@ int k_usermode_string_copy(char *dst, const char *src, size_t maxlen); */ #define K_SYSCALL_VERIFY(expr) K_SYSCALL_VERIFY_MSG(expr, #expr) +/** + * @brief Macro to check if size is negative + * + * K_SYSCALL_MEMORY can be called with signed/unsigned types + * and because of that if we check if size is greater or equal to + * zero, many static analyzers complain about no effect expression. + * + * @param ptr Memory area to examine + * @param size Size of the memory area + * @return true if size is valid, false otherwise + * @note This is an internal API. Do not use unless you are extending + * functionality in the Zephyr tree. + */ +#define K_SYSCALL_MEMORY_SIZE_CHECK(ptr, size) \ + (((uintptr_t)ptr + size) >= (uintptr_t)ptr) + /** * @brief Runtime check that a user thread has read and/or write permission to * a memory area @@ -413,7 +429,8 @@ int k_usermode_string_copy(char *dst, const char *src, size_t maxlen); * functionality in the Zephyr tree. */ #define K_SYSCALL_MEMORY(ptr, size, write) \ - K_SYSCALL_VERIFY_MSG((size >= 0) && !Z_DETECT_POINTER_OVERFLOW(ptr, size) \ + K_SYSCALL_VERIFY_MSG(K_SYSCALL_MEMORY_SIZE_CHECK(ptr, size) \ + && !Z_DETECT_POINTER_OVERFLOW(ptr, size) \ && (arch_buffer_validate((void *)ptr, size, write) \ == 0), \ "Memory region %p (size %zu) %s access denied", \ From 1f67dcbd89954c2c649d6cfc8f9d559d780ed0a9 Mon Sep 17 00:00:00 2001 From: Christopher Friedt Date: Mon, 18 Dec 2023 15:13:01 -0500 Subject: [PATCH 1603/3723] posix: remove deprecated non-standard PTHREAD_MUTEX_DEFINE, etc Remove the previously deprecated and non-standard macros * PTHREAD_MUTEX_DEFINE() * PTHREAD_COND_DEFINE() Signed-off-by: Christopher Friedt --- include/zephyr/posix/pthread.h | 24 ------------------------ tests/posix/common/src/pthread.c | 9 +++------ 2 files changed, 3 insertions(+), 30 deletions(-) diff --git a/include/zephyr/posix/pthread.h b/include/zephyr/posix/pthread.h index 55d617715f5..636a2844180 100644 --- a/include/zephyr/posix/pthread.h +++ b/include/zephyr/posix/pthread.h @@ -52,18 +52,6 @@ extern "C" { */ #define PTHREAD_COND_INITIALIZER (-1) -/** - * @brief Declare a pthread condition variable - * - * Declaration API for a pthread condition variable. This is not a - * POSIX API, it's provided to better conform with Zephyr's allocation - * strategies for kernel objects. - * - * @param name Symbol name of the condition variable - * @deprecated Use @c PTHREAD_COND_INITIALIZER instead. - */ -#define PTHREAD_COND_DEFINE(name) pthread_cond_t name = PTHREAD_COND_INITIALIZER - /** * @brief POSIX threading compatibility API * @@ -148,18 +136,6 @@ int pthread_condattr_setclock(pthread_condattr_t *att, clockid_t clock_id); */ #define PTHREAD_MUTEX_INITIALIZER (-1) -/** - * @brief Declare a pthread mutex - * - * Declaration API for a pthread mutex. This is not a POSIX API, it's - * provided to better conform with Zephyr's allocation strategies for - * kernel objects. - * - * @param name Symbol name of the mutex - * @deprecated Use @c PTHREAD_MUTEX_INITIALIZER instead. - */ -#define PTHREAD_MUTEX_DEFINE(name) pthread_mutex_t name = PTHREAD_MUTEX_INITIALIZER - /* * Mutex attributes - type * diff --git a/tests/posix/common/src/pthread.c b/tests/posix/common/src/pthread.c index f8fe650ceeb..16c4af2e360 100644 --- a/tests/posix/common/src/pthread.c +++ b/tests/posix/common/src/pthread.c @@ -33,12 +33,9 @@ K_THREAD_STACK_ARRAY_DEFINE(stack_1, 1, 32); void *thread_top_exec(void *p1); void *thread_top_term(void *p1); -PTHREAD_MUTEX_DEFINE(lock); - -PTHREAD_COND_DEFINE(cvar0); - -PTHREAD_COND_DEFINE(cvar1); - +static pthread_mutex_t lock = PTHREAD_MUTEX_INITIALIZER; +static pthread_cond_t cvar0 = PTHREAD_COND_INITIALIZER; +static pthread_cond_t cvar1 = PTHREAD_COND_INITIALIZER; static pthread_barrier_t barrier; sem_t main_sem; From 0bf5cbc1c8ee2a6acb4b5da23ad237b4a3b18d0d Mon Sep 17 00:00:00 2001 From: Flavio Ceolin Date: Wed, 27 Dec 2023 16:36:02 -0800 Subject: [PATCH 1604/3723] syscall_handler: Fix warnings in K_SYSCALL_MEMORY Put parenthesis around parameters in K_SYSCALL_MEMORY_SIZE_CHECK to avoid possible warnings during the macro expansion. Signed-off-by: Flavio Ceolin --- include/zephyr/internal/syscall_handler.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/include/zephyr/internal/syscall_handler.h b/include/zephyr/internal/syscall_handler.h index 3917e4c44c0..a9b9a642c76 100644 --- a/include/zephyr/internal/syscall_handler.h +++ b/include/zephyr/internal/syscall_handler.h @@ -408,7 +408,7 @@ int k_usermode_string_copy(char *dst, const char *src, size_t maxlen); * functionality in the Zephyr tree. */ #define K_SYSCALL_MEMORY_SIZE_CHECK(ptr, size) \ - (((uintptr_t)ptr + size) >= (uintptr_t)ptr) + (((uintptr_t)(ptr) + (size)) >= (uintptr_t)(ptr)) /** * @brief Runtime check that a user thread has read and/or write permission to From 6342aa3cc06858575b0d6e69d4a98658ae8a49b0 Mon Sep 17 00:00:00 2001 From: Christopher Friedt Date: Thu, 28 Dec 2023 01:24:13 -0500 Subject: [PATCH 1605/3723] lib: support linking to POSIX API with 3rd-party libc Previously it was not possible to link to Zephyr's POSIX API under lib/posix when building with `CONFIG_EXTERNAL_LIBC=y`. This small change allows that to work as expected. Signed-off-by: Christopher Friedt --- lib/CMakeLists.txt | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/lib/CMakeLists.txt b/lib/CMakeLists.txt index c2abdd9559d..5bdb98aad5d 100644 --- a/lib/CMakeLists.txt +++ b/lib/CMakeLists.txt @@ -4,10 +4,10 @@ add_compile_options($) add_subdirectory(crc) -if(NOT CONFIG_EXTERNAL_LIBC) +if(NOT CONFIG_NATIVE_LIBC) add_subdirectory(libc) -add_subdirectory(posix) endif() +add_subdirectory(posix) add_subdirectory_ifdef(CONFIG_CPP cpp) add_subdirectory(hash) add_subdirectory(heap) From be6cf5c268c43dcde2d10c5233ff17a21a913afc Mon Sep 17 00:00:00 2001 From: Jaro Van Landschoot Date: Thu, 7 Dec 2023 14:22:51 +0100 Subject: [PATCH 1606/3723] soc: arm: atmel_sam: Sys_arch_reboot using RSTC The previous implementation of the sys_arch_reboot function for the Atmel SAM series was using NVIC_SystemReset. This caused a reboot time of around 20 seconds on a SAM4SA16CA, which is now reduced by directly writing to the reset controller control register (RSTC_CR). Signed-off-by: Jaro Van Landschoot Co-authored-by: Gerson Fernando Budke --- soc/arm/atmel_sam/common/CMakeLists.txt | 1 + soc/arm/atmel_sam/common/soc_power.c | 37 +++++++++++++++++++++++++ 2 files changed, 38 insertions(+) create mode 100644 soc/arm/atmel_sam/common/soc_power.c diff --git a/soc/arm/atmel_sam/common/CMakeLists.txt b/soc/arm/atmel_sam/common/CMakeLists.txt index 2d5a6c35a33..3fe8bdd1d6d 100644 --- a/soc/arm/atmel_sam/common/CMakeLists.txt +++ b/soc/arm/atmel_sam/common/CMakeLists.txt @@ -4,6 +4,7 @@ zephyr_include_directories(.) zephyr_library_sources_ifndef(CONFIG_SOC_SERIES_SAM4L soc_pmc.c) zephyr_library_sources_ifndef(CONFIG_SOC_SERIES_SAM4L soc_gpio.c) zephyr_library_sources_ifndef(CONFIG_SOC_SERIES_SAM4L soc_supc.c) +zephyr_library_sources_ifndef(CONFIG_SOC_SERIES_SAM4L soc_power.c) zephyr_library_sources_ifndef(CONFIG_SOC_SERIES_SAM4L soc_poweroff.c) zephyr_library_sources_ifdef(CONFIG_SOC_SERIES_SAM4L soc_sam4l_pm.c) diff --git a/soc/arm/atmel_sam/common/soc_power.c b/soc/arm/atmel_sam/common/soc_power.c new file mode 100644 index 00000000000..08499b98b10 --- /dev/null +++ b/soc/arm/atmel_sam/common/soc_power.c @@ -0,0 +1,37 @@ +/* + * Copyright (c) 2023 Basalte bv + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#define SAM_DT_RSTC_DRIVER DT_INST(0, atmel_sam_rstc) + +#include +#if defined(CONFIG_REBOOT) +#include +#endif + +#if defined(CONFIG_REBOOT) +#if DT_NODE_HAS_STATUS(SAM_DT_RSTC_DRIVER, okay) + +void sys_arch_reboot(int type) +{ + Rstc *regs = (Rstc *)DT_REG_ADDR(SAM_DT_RSTC_DRIVER); + + switch (type) { + case SYS_REBOOT_COLD: + regs->RSTC_CR = RSTC_CR_KEY_PASSWD + | RSTC_CR_PROCRST +#if defined(CONFIG_SOC_SERIES_SAM3X) || defined(CONFIG_SOC_SERIES_SAM4S) || \ + defined(CONFIG_SOC_SERIES_SAM4E) + | RSTC_CR_PERRST +#endif /* CONFIG_SOC_SERIES_SAM3X || CONFIG_SOC_SERIES_SAM4S || CONFIG_SOC_SERIES_SAM4E */ + ; + break; + default: + break; + } +} + +#endif /* DT_NODE_HAS_STATUS */ +#endif /* CONFIG_REBOOT */ From b4cd9c462aacb11dba62a94bb86489ccb6e691f7 Mon Sep 17 00:00:00 2001 From: Pieter De Gendt Date: Thu, 21 Dec 2023 12:44:16 +0100 Subject: [PATCH 1607/3723] sys: util_macro: Add IF_DISABLED Add the opposite for IF_ENABLED macro. Signed-off-by: Pieter De Gendt --- include/zephyr/sys/util_macro.h | 24 ++++++++++++++++++++++++ 1 file changed, 24 insertions(+) diff --git a/include/zephyr/sys/util_macro.h b/include/zephyr/sys/util_macro.h index 02d0e9885a6..81df23f9150 100644 --- a/include/zephyr/sys/util_macro.h +++ b/include/zephyr/sys/util_macro.h @@ -223,6 +223,30 @@ extern "C" { #define IF_ENABLED(_flag, _code) \ COND_CODE_1(_flag, _code, ()) +/** + * @brief Insert code if @p _flag is not defined as 1. + * + * This expands to nothing if @p _flag is defined and equal to 1; + * it expands to @p _code otherwise. + * + * Example: + * + * IF_DISABLED(CONFIG_FLAG, (uint32_t foo;)) + * + * If @p CONFIG_FLAG isn't defined or different than 1, this expands to: + * + * uint32_t foo; + * + * and to nothing otherwise. + * + * IF_DISABLED does the opposite of IF_ENABLED. + * + * @param _flag evaluated flag + * @param _code result if @p _flag does not expand to 1; must be in parentheses + */ +#define IF_DISABLED(_flag, _code) \ + COND_CODE_1(_flag, (), _code) + /** * @brief Check if a macro has a replacement expression * From cc920696edca50989bd04f55276e46256f1f9a66 Mon Sep 17 00:00:00 2001 From: Pieter De Gendt Date: Thu, 21 Dec 2023 12:46:09 +0100 Subject: [PATCH 1608/3723] tests: unit: util: Add tests for IF_DISABLED Add a testcase for the IF_DISABLED macro. Signed-off-by: Pieter De Gendt --- tests/unit/util/main.c | 8 ++++++++ tests/unit/util/test.inc | 22 ++++++++++++++++++++++ 2 files changed, 30 insertions(+) diff --git a/tests/unit/util/main.c b/tests/unit/util/main.c index bce626f9fe4..3c93968db46 100644 --- a/tests/unit/util/main.c +++ b/tests/unit/util/main.c @@ -38,6 +38,10 @@ ZTEST(util_cxx, test_IF_ENABLED) { run_IF_ENABLED(); } +ZTEST(util_cxx, test_IF_DISABLED) { + run_IF_DISABLED(); +} + ZTEST(util_cxx, test_LISTIFY) { run_LISTIFY(); } @@ -186,6 +190,10 @@ ZTEST(util_cc, test_IF_ENABLED) { run_IF_ENABLED(); } +ZTEST(util_cc, test_IF_DISABLED) { + run_IF_DISABLED(); +} + ZTEST(util_cc, test_LISTIFY) { run_LISTIFY(); } diff --git a/tests/unit/util/test.inc b/tests/unit/util/test.inc index c47cc7ab7e2..f16f1039d45 100644 --- a/tests/unit/util/test.inc +++ b/tests/unit/util/test.inc @@ -162,6 +162,28 @@ skipped: #undef test_IF_ENABLED_FLAG_B } +void run_IF_DISABLED(void) +{ + #define test_IF_DISABLED_FLAG_A 0 + #define test_IF_DISABLED_FLAG_B 1 + + IF_DISABLED(test_IF_DISABLED_FLAG_A, (goto skipped_a;)) + /* location should be skipped if IF_DISABLED macro is correct. */ + zassert_false(true, "location A should be skipped"); +skipped_a: + IF_DISABLED(test_IF_DISABLED_FLAG_B, (zassert_false(true, "");)) + + IF_DISABLED(test_IF_DISABLED_FLAG_C, (goto skipped_c;)) + /* location should be skipped if IF_DISABLED macro is correct. */ + zassert_false(true, "location C should be skipped"); +skipped_c: + + zassert_true(true, ""); + + #undef test_IF_DISABLED_FLAG_A + #undef test_IF_DISABLED_FLAG_B +} + void run_LISTIFY(void) { int ab0 = 1; From 4a1744663647e5e1c29748ce3caaa01852d54d5c Mon Sep 17 00:00:00 2001 From: Andrei Emeltchenko Date: Fri, 22 Dec 2023 13:05:14 +0200 Subject: [PATCH 1609/3723] drivers: pcie: Remove magic number Use definitions instead of magic numbers. Signed-off-by: Andrei Emeltchenko --- drivers/pcie/host/pcie.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/drivers/pcie/host/pcie.c b/drivers/pcie/host/pcie.c index d827e326fd7..52c7053e5b7 100644 --- a/drivers/pcie/host/pcie.c +++ b/drivers/pcie/host/pcie.c @@ -159,7 +159,8 @@ static bool pcie_get_bar(pcie_bdf_t bdf, } /* IO/memory decode should be disabled before sizing/update BAR. */ - pcie_conf_write(bdf, PCIE_CONF_CMDSTAT, cmd_reg & (~0x3)); + pcie_conf_write(bdf, PCIE_CONF_CMDSTAT, + cmd_reg & (~(PCIE_CONF_CMDSTAT_IO | PCIE_CONF_CMDSTAT_MEM))); pcie_conf_write(bdf, reg, 0xFFFFFFFFU); size = pcie_conf_read(bdf, reg); From fc8b53bf106b16902f51b2f9857b2518cba16724 Mon Sep 17 00:00:00 2001 From: Andrei Emeltchenko Date: Fri, 22 Dec 2023 15:53:07 +0200 Subject: [PATCH 1610/3723] drivers: pcie: Read register before actual usage Move reading PCIE_CONF_CMDSTAT before actual usage. There are four return branches before value is used. Signed-off-by: Andrei Emeltchenko --- drivers/pcie/host/pcie.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/drivers/pcie/host/pcie.c b/drivers/pcie/host/pcie.c index 52c7053e5b7..d8e04a9ed73 100644 --- a/drivers/pcie/host/pcie.c +++ b/drivers/pcie/host/pcie.c @@ -126,7 +126,7 @@ static bool pcie_get_bar(pcie_bdf_t bdf, bool io) { uint32_t reg = bar_index + PCIE_CONF_BAR0; - uint32_t cmd_reg = pcie_conf_read(bdf, PCIE_CONF_CMDSTAT); + uint32_t cmd_reg; bool ret = false; #ifdef CONFIG_PCIE_CONTROLLER const struct device *dev; @@ -158,6 +158,8 @@ static bool pcie_get_bar(pcie_bdf_t bdf, return false; } + cmd_reg = pcie_conf_read(bdf, PCIE_CONF_CMDSTAT); + /* IO/memory decode should be disabled before sizing/update BAR. */ pcie_conf_write(bdf, PCIE_CONF_CMDSTAT, cmd_reg & (~(PCIE_CONF_CMDSTAT_IO | PCIE_CONF_CMDSTAT_MEM))); From 82cd7ad9b630309f76cd6631626800d8a2103acf Mon Sep 17 00:00:00 2001 From: Gaetan Perrot Date: Mon, 25 Dec 2023 14:20:30 +0900 Subject: [PATCH 1611/3723] drivers: dac: sam: Add max value check Add max size check to dac sam and sam0 There is no size check in dac_sam_write_value and dac_sam0_write_value. Besides, the ret value should also be different. Fixes #65021 signed-off-by: Gaetan Perrot --- drivers/dac/dac_sam.c | 5 +++++ drivers/dac/dac_sam0.c | 7 +++++++ 2 files changed, 12 insertions(+) diff --git a/drivers/dac/dac_sam.c b/drivers/dac/dac_sam.c index de4680b3ff6..df8b96f66e9 100644 --- a/drivers/dac/dac_sam.c +++ b/drivers/dac/dac_sam.c @@ -107,6 +107,11 @@ static int dac_sam_write_value(const struct device *dev, uint8_t channel, return -EINVAL; } + if (value >= BIT(12)) { + LOG_ERR("value %d out of range", value); + return -EINVAL; + } + k_sem_take(&dev_data->dac_channels[channel].sem, K_FOREVER); /* Trigger conversion */ diff --git a/drivers/dac/dac_sam0.c b/drivers/dac/dac_sam0.c index 2b96b8bc30d..95f561d4a6a 100644 --- a/drivers/dac/dac_sam0.c +++ b/drivers/dac/dac_sam0.c @@ -11,6 +11,8 @@ #include #include #include +#include +LOG_MODULE_REGISTER(dac_sam0, CONFIG_DAC_LOG_LEVEL); /* * Maps between the DTS reference property names and register values. Note that @@ -37,6 +39,11 @@ static int dac_sam0_write_value(const struct device *dev, uint8_t channel, const struct dac_sam0_cfg *const cfg = dev->config; Dac *regs = cfg->regs; + if (value >= BIT(12)) { + LOG_ERR("value %d out of range", value); + return -EINVAL; + } + regs->DATA.reg = (uint16_t)value; return 0; From b46d961abf74175f2a003ac4af3a2421ba2d193b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Krzysztof=20Chru=C5=9Bci=C5=84ski?= Date: Wed, 20 Dec 2023 15:51:37 +0100 Subject: [PATCH 1612/3723] tests: lib: cbprintf_package: Add test case for cbprintf_convert MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Add test case for converting statically generated package which contains RO and RW indexes. Converting shall append RW string and discard RO index. Signed-off-by: Krzysztof Chruściński --- tests/lib/cbprintf_package/src/main.c | 42 +++++++++++++++++++++++++++ 1 file changed, 42 insertions(+) diff --git a/tests/lib/cbprintf_package/src/main.c b/tests/lib/cbprintf_package/src/main.c index 3059e686029..7451d8012b8 100644 --- a/tests/lib/cbprintf_package/src/main.c +++ b/tests/lib/cbprintf_package/src/main.c @@ -893,6 +893,48 @@ ZTEST(cbprintf_package, test_cbprintf_package_convert) } +ZTEST(cbprintf_package, test_cbprintf_package_convert_static) +{ + int slen, clen, olen; + static const char test_str[] = "test %s"; + char test_str1[] = "test str1"; + /* Store indexes of rw strings. */ + uint32_t flags = CBPRINTF_PACKAGE_ADD_RW_STR_POS | + CBPRINTF_PACKAGE_FIRST_RO_STR_CNT(0) | + CBPRINTF_PACKAGE_ADD_STRING_IDXS; + struct test_cbprintf_covert_ctx ctx; + +#define TEST_FMT test_str, test_str1 + char exp_str[256]; + + snprintfcb(exp_str, sizeof(exp_str), TEST_FMT); + + CBPRINTF_STATIC_PACKAGE(NULL, 0, slen, CBPRINTF_PACKAGE_ALIGNMENT, flags, TEST_FMT); + zassert_true(slen > 0); + + uint8_t __aligned(CBPRINTF_PACKAGE_ALIGNMENT) spackage[slen]; + + memset(&ctx, 0, sizeof(ctx)); + memset(spackage, 0, slen); + + CBPRINTF_STATIC_PACKAGE(spackage, slen, olen, CBPRINTF_PACKAGE_ALIGNMENT, flags, TEST_FMT); + zassert_equal(olen, slen); + + uint32_t copy_flags = CBPRINTF_PACKAGE_CONVERT_RW_STR; + + clen = cbprintf_package_convert(spackage, slen, NULL, 0, copy_flags, NULL, 0); + zassert_true(clen == slen + sizeof(test_str1) + 1/*null*/ - 2 /* arg+ro idx gone*/); + + clen = cbprintf_package_convert(spackage, slen, convert_cb, &ctx, copy_flags, NULL, 0); + zassert_true(clen > 0); + zassert_true(ctx.null); + zassert_equal((int)ctx.offset, clen); + + check_package(ctx.buf, ctx.offset, exp_str); +#undef TEST_FMT + +} + /** * @brief Log information about variable sizes and alignment. * From c48d61a4b46427d8cf3f599edf2e3cee3bd07893 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Krzysztof=20Chru=C5=9Bci=C5=84ski?= Date: Wed, 20 Dec 2023 15:53:05 +0100 Subject: [PATCH 1613/3723] lib: os: cbprintf: Fix size miscalculation in cbprintf_convert MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit When package contained RO string positions and flag indicates that they shall not be kept, length was miscalculated which could lead to failures (e.g. memory corruption). Signed-off-by: Krzysztof Chruściński --- lib/os/cbprintf_packaged.c | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/lib/os/cbprintf_packaged.c b/lib/os/cbprintf_packaged.c index 3e71034f316..1c208c42e67 100644 --- a/lib/os/cbprintf_packaged.c +++ b/lib/os/cbprintf_packaged.c @@ -982,9 +982,7 @@ int cbprintf_package_convert(void *in_packaged, str_pos++; } } else { - if (ros_nbr && flags & CBPRINTF_PACKAGE_CONVERT_KEEP_RO_STR) { - str_pos += ros_nbr; - } + str_pos += ros_nbr; } bool drop_ro_str_pos = !(flags & From 3458527a2ced40c8d7c28871b16b641ddbcf3a2e Mon Sep 17 00:00:00 2001 From: Christopher Friedt Date: Fri, 22 Dec 2023 18:07:17 -0500 Subject: [PATCH 1614/3723] posix: pthread_getspecific: fix for coverity issue cid 334909 * remove unneeded line of code that duplicated the first part of the SYS_SLIST_FOR_EACH_NODE() expansion. * return NULL if pthread_self() is not a valid pthread Signed-off-by: Christopher Friedt --- lib/posix/key.c | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/lib/posix/key.c b/lib/posix/key.c index df9062362ed..611db537212 100644 --- a/lib/posix/key.c +++ b/lib/posix/key.c @@ -248,12 +248,17 @@ int pthread_setspecific(pthread_key_t key, const void *value) void *pthread_getspecific(pthread_key_t key) { pthread_key_obj *key_obj; - struct posix_thread *thread = to_posix_thread(pthread_self()); + struct posix_thread *thread; pthread_thread_data *thread_spec_data; void *value = NULL; sys_snode_t *node_l; k_spinlock_key_t key_key; + thread = to_posix_thread(pthread_self()); + if (thread == NULL) { + return NULL; + } + key_key = k_spin_lock(&pthread_key_lock); key_obj = get_posix_key(key); @@ -262,8 +267,6 @@ void *pthread_getspecific(pthread_key_t key) return NULL; } - node_l = sys_slist_peek_head(&(thread->key_list)); - /* Traverse the list of keys set by the thread, looking for key */ SYS_SLIST_FOR_EACH_NODE(&(thread->key_list), node_l) { From ec69e64d4c35061251415a10839d0e63c2954655 Mon Sep 17 00:00:00 2001 From: Christopher Friedt Date: Fri, 22 Dec 2023 19:39:31 -0500 Subject: [PATCH 1615/3723] posix: pthread_setspecific: fix for coverity issue cid 334906 * return EINVAL if pthread_self() is not a valid pthread Signed-off-by: Christopher Friedt --- lib/posix/key.c | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/lib/posix/key.c b/lib/posix/key.c index 611db537212..20237f36712 100644 --- a/lib/posix/key.c +++ b/lib/posix/key.c @@ -174,13 +174,18 @@ int pthread_key_delete(pthread_key_t key) int pthread_setspecific(pthread_key_t key, const void *value) { pthread_key_obj *key_obj; - struct posix_thread *thread = to_posix_thread(pthread_self()); + struct posix_thread *thread; struct pthread_key_data *key_data; pthread_thread_data *thread_spec_data; k_spinlock_key_t key_key; sys_snode_t *node_l; int retval = 0; + thread = to_posix_thread(pthread_self()); + if (thread == NULL) { + return EINVAL; + } + /* Traverse the list of keys set by the thread, looking for key. * If the key is already in the list, re-assign its value. * Else add the key to the thread's list. From e8ba19e0eee25cbaf694e0472ea0c266be69a3c3 Mon Sep 17 00:00:00 2001 From: Christopher Friedt Date: Fri, 22 Dec 2023 17:48:28 -0500 Subject: [PATCH 1616/3723] docs: posix: aep: correct some typos * use _POSIX_AEP_REALTIME_DEDICATED instead of CONTROLLER * use _POSIX_AEP_REALTIME_DEDICATED instead of MINIMAL in comment Signed-off-by: Christopher Friedt --- doc/services/portability/posix/aep/index.rst | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/doc/services/portability/posix/aep/index.rst b/doc/services/portability/posix/aep/index.rst index 857635c1031..30b3e517cd5 100644 --- a/doc/services/portability/posix/aep/index.rst +++ b/doc/services/portability/posix/aep/index.rst @@ -122,13 +122,13 @@ Realtime Controller System Profile (PSE52) Dedicated Realtime System Profile (PSE53) ========================================= -.. Conforming implementations shall define _POSIX_AEP_REALTIME_MINIMAL to the value 200312L +.. Conforming implementations shall define _POSIX_AEP_REALTIME_DEDICATED to the value 200312L .. csv-table:: PSE53 System Interfaces :header: Symbol, Support, Remarks :widths: 50, 10, 50 - _POSIX_AEP_REALTIME_CONTROLLER, -1, + _POSIX_AEP_REALTIME_DEDICATED, -1, .. csv-table:: PSE53 Option Groups :header: Symbol, Support, Remarks From 23ad1177a207089767df1eea981367f756c623f3 Mon Sep 17 00:00:00 2001 From: Alberto Escolar Piedras Date: Thu, 28 Dec 2023 14:25:54 +0100 Subject: [PATCH 1617/3723] Revert "lib: support linking to POSIX API with 3rd-party libc" This reverts commit 6342aa3cc06858575b0d6e69d4a98658ae8a49b0. This commit should never have been merged. Apart from the fact that this change was rejected in previous review, this change is wrong, for 2 reasons: 1. The POSIX_API (POSIX compatibility shim) cannot be built if the host libC is used. 2. The Zephyr libC CMake files were guarded so they would not be dragged when CONFIG_EXTERNAL_LIBC was selected. Signed-off-by: Alberto Escolar Piedras --- lib/CMakeLists.txt | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/lib/CMakeLists.txt b/lib/CMakeLists.txt index 5bdb98aad5d..c2abdd9559d 100644 --- a/lib/CMakeLists.txt +++ b/lib/CMakeLists.txt @@ -4,10 +4,10 @@ add_compile_options($) add_subdirectory(crc) -if(NOT CONFIG_NATIVE_LIBC) +if(NOT CONFIG_EXTERNAL_LIBC) add_subdirectory(libc) -endif() add_subdirectory(posix) +endif() add_subdirectory_ifdef(CONFIG_CPP cpp) add_subdirectory(hash) add_subdirectory(heap) From c05a483ba4251589b713a1231fb6ad4c75cebbaa Mon Sep 17 00:00:00 2001 From: Alberto Escolar Piedras Date: Thu, 28 Dec 2023 14:29:27 +0100 Subject: [PATCH 1618/3723] lib posix: Allow building the POSIX_API library without the host libC In theory one may want to build the POSIX compability shim with a different C library than one provided with Zephyr, so let's not prevent it. Signed-off-by: Alberto Escolar Piedras --- lib/CMakeLists.txt | 2 ++ 1 file changed, 2 insertions(+) diff --git a/lib/CMakeLists.txt b/lib/CMakeLists.txt index c2abdd9559d..7a0ee04e4ac 100644 --- a/lib/CMakeLists.txt +++ b/lib/CMakeLists.txt @@ -6,6 +6,8 @@ add_compile_options($) add_subdirectory(crc) if(NOT CONFIG_EXTERNAL_LIBC) add_subdirectory(libc) +endif() +if(NOT CONFIG_NATIVE_LIBC) add_subdirectory(posix) endif() add_subdirectory_ifdef(CONFIG_CPP cpp) From aa4416624dceef29ec9ca78820c9fe5d3868f62c Mon Sep 17 00:00:00 2001 From: Anas Nashif Date: Fri, 22 Dec 2023 19:44:57 -0500 Subject: [PATCH 1619/3723] twister: coverage: cleanup how we set gcov tool Make sure we set the gcov tool in a consistent way and avoid issues where path is set as Path instead of a string. Signed-off-by: Anas Nashif --- scripts/pylib/twister/twisterlib/coverage.py | 17 ++++++++++------- 1 file changed, 10 insertions(+), 7 deletions(-) diff --git a/scripts/pylib/twister/twisterlib/coverage.py b/scripts/pylib/twister/twisterlib/coverage.py index 105d3255b27..0466215809d 100644 --- a/scripts/pylib/twister/twisterlib/coverage.py +++ b/scripts/pylib/twister/twisterlib/coverage.py @@ -190,7 +190,7 @@ def _generate(self, outdir, coveragelog): branch_coverage = "lcov_branch_coverage=1" ignore_errors = [] - cmd = ["lcov", "--gcov-tool", str(self.gcov_tool), + cmd = ["lcov", "--gcov-tool", self.gcov_tool, "--capture", "--directory", outdir, "--rc", branch_coverage, "--output-file", coveragefile] @@ -293,7 +293,7 @@ def _generate(self, outdir, coveragelog): # We want to remove tests/* and tests/ztest/test/* but save tests/ztest cmd = ["gcovr", "-r", self.base_dir, "--gcov-ignore-parse-errors=negative_hits.warn_once_per_file", - "--gcov-executable", str(self.gcov_tool), + "--gcov-executable", self.gcov_tool, "-e", "tests/*"] cmd += excludes + mode_options + ["--json", "-o", coveragefile, outdir] cmd_str = " ".join(cmd) @@ -333,6 +333,7 @@ def _generate(self, outdir, coveragelog): def run_coverage(testplan, options): use_system_gcov = False + gcov_tool = None for plat in options.coverage_platform: _plat = testplan.get_platform(plat) @@ -353,19 +354,21 @@ def run_coverage(testplan, options): os.symlink(llvm_cov, gcov_lnk) except OSError: shutil.copy(llvm_cov, gcov_lnk) - options.gcov_tool = gcov_lnk + gcov_tool = gcov_lnk elif use_system_gcov: - options.gcov_tool = "gcov" + gcov_tool = "gcov" elif os.path.exists(zephyr_sdk_gcov_tool): - options.gcov_tool = zephyr_sdk_gcov_tool + gcov_tool = zephyr_sdk_gcov_tool else: logger.error(f"Can't find a suitable gcov tool. Use --gcov-tool or set ZEPHYR_SDK_INSTALL_DIR.") sys.exit(1) + else: + gcov_tool = str(options.gcov_tool) logger.info("Generating coverage files...") - logger.info(f"Using gcov tool: {options.gcov_tool}") + logger.info(f"Using gcov tool: {gcov_tool}") coverage_tool = CoverageTool.factory(options.coverage_tool) - coverage_tool.gcov_tool = str(options.gcov_tool) + coverage_tool.gcov_tool = gcov_tool coverage_tool.base_dir = os.path.abspath(options.coverage_basedir) # Apply output format default if options.coverage_formats is not None: From e67b12e63611291ac567bac4abfb9d43ecac0ce8 Mon Sep 17 00:00:00 2001 From: Fabio Baltieri Date: Thu, 28 Dec 2023 21:51:30 +0000 Subject: [PATCH 1620/3723] lib: posix: tag the fallthrough case as __fallthrough Use the __fallthrough directive on the switch fallthrough case and drop the comment instead. This informs the compiler that the fallthrough is intentional and silence any possible warning about it. Drop the not reached case as I think that that part can actually be reached since there are breaks in some of the cases. Signed-off-by: Fabio Baltieri --- lib/posix/fnmatch.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/lib/posix/fnmatch.c b/lib/posix/fnmatch.c index 338891fd9b3..b5285851359 100644 --- a/lib/posix/fnmatch.c +++ b/lib/posix/fnmatch.c @@ -44,6 +44,7 @@ #include #include +#include #define EOS '\0' @@ -243,7 +244,7 @@ static int fnmatchx(const char *pattern, const char *string, int flags, size_t r --pattern; } } - /* FALLTHROUGH */ + __fallthrough; default: if (c != FOLDCASE(*string++, flags)) { return FNM_NOMATCH; @@ -252,7 +253,6 @@ static int fnmatchx(const char *pattern, const char *string, int flags, size_t r break; } } - /* NOTREACHED */ } int fnmatch(const char *pattern, const char *string, int flags) From 10156f5f1d9c87d2076ebed13aa3e5d75869a8f1 Mon Sep 17 00:00:00 2001 From: Christopher Friedt Date: Fri, 29 Dec 2023 10:06:44 -0500 Subject: [PATCH 1621/3723] posix: mqueue: pop mode as int with va_arg() There was some discussion about whether it was suitable to have an architecture-specific workaround in mqueue.c after that workaround was copied to a different source file in a PR. The original issue was that newlib and picolibc declare mode_t to be unsigned short instead of unsigned long when __svr4__ is not defined along with __sparc__. This is specifically impactful, because va_arg() deals (mainly) with 32-bit and 64-bit values that are all naturally aligned to 4 bytes. #if defined(__sparc__) && !defined(__sparc_v9__) #ifdef __svr4__ typedef unsigned long __mode_t; #else typedef unsigned short __mode_t; #endif A uint16_t is naturally aligned to 2 bytes, so not only would a 16-bit mode_t be corrupted, it would also generate a warning with recent gcc versions which is promoted to error (rightfully so) when run through CI. mqueue.c:61:35: error: 'mode_t' {aka 'short unsigned int'} is promoted to 'int' when passed through '...' [-Werror] 61 | mode = va_arg(va, mode_t); Instead of using an architecture-specific workaround, simply add a build assert that the size of mode_t is less than or equal to the size of an int, and use an int to retrieve it via va_arg(). Signed-off-by: Christopher Friedt # Please enter the commit message for your changes. Lines starting # with '#' will be kept; you may remove them yourself if you want to. # An empty message aborts the commit. # # Date: Fri Dec 29 10:06:44 2023 -0500 # # On branch posix-mqueue-always-use-int-for-mode-t-va-arg # Changes to be committed: # modified: lib/posix/mqueue.c # modified: tests/posix/common/testcase.yaml # --- lib/posix/mqueue.c | 14 ++------------ tests/posix/common/testcase.yaml | 3 --- 2 files changed, 2 insertions(+), 15 deletions(-) diff --git a/lib/posix/mqueue.c b/lib/posix/mqueue.c index 5c3d5e5e5d9..47e660111bb 100644 --- a/lib/posix/mqueue.c +++ b/lib/posix/mqueue.c @@ -38,17 +38,6 @@ static int receive_message(mqueue_desc *mqd, char *msg_ptr, size_t msg_len, k_timeout_t timeout); static void remove_mq(mqueue_object *msg_queue); -#if defined(__sparc__) -/* - * mode_t is defined as "unsigned short" on SPARC newlib. This type is promoted - * to "int" when passed through '...' so we should pass the promoted type to - * va_arg(). - */ -#define PROMOTED_MODE_T int -#else -#define PROMOTED_MODE_T mode_t -#endif - /** * @brief Open a message queue. * @@ -69,7 +58,8 @@ mqd_t mq_open(const char *name, int oflags, ...) va_start(va, oflags); if ((oflags & O_CREAT) != 0) { - mode = va_arg(va, PROMOTED_MODE_T); + BUILD_ASSERT(sizeof(mode_t) <= sizeof(int)); + mode = va_arg(va, unsigned int); attrs = va_arg(va, struct mq_attr*); } va_end(va); diff --git a/tests/posix/common/testcase.yaml b/tests/posix/common/testcase.yaml index cb48095c67c..03f7ee381ac 100644 --- a/tests/posix/common/testcase.yaml +++ b/tests/posix/common/testcase.yaml @@ -1,9 +1,6 @@ common: filter: not (CONFIG_NATIVE_BUILD and CONFIG_EXTERNAL_LIBC) - # FIXME: qemu_leon3 is excluded because of the alignment-related failure - # reported in the GitHub issue zephyrproject-rtos/zephyr#48992. platform_exclude: - - qemu_leon3 - native_posix - native_posix_64 tags: posix From fdea8518783a5d8c4421595341f8332ac5714167 Mon Sep 17 00:00:00 2001 From: Armin Brauns Date: Tue, 24 Oct 2023 12:53:02 +0000 Subject: [PATCH 1622/3723] task_wdt: start feeding hardware watchdog immediately after init Without this, the hardware watchdog would expire if no task watchdogs were registered within one hardware watchdog period after init. Start the background channel immediately after init to avoid this. Signed-off-by: Armin Brauns --- subsys/task_wdt/task_wdt.c | 1 + 1 file changed, 1 insertion(+) diff --git a/subsys/task_wdt/task_wdt.c b/subsys/task_wdt/task_wdt.c index b7171a14e23..1a4e21cf3eb 100644 --- a/subsys/task_wdt/task_wdt.c +++ b/subsys/task_wdt/task_wdt.c @@ -147,6 +147,7 @@ int task_wdt_init(const struct device *hw_wdt) } k_timer_init(&timer, task_wdt_trigger, NULL); + schedule_next_timeout(sys_clock_tick_get()); return 0; } From fdacddda08d38979c6368afc07a09b1aaa836266 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Martin=20=C3=85berg?= Date: Thu, 28 Sep 2023 20:07:13 +0200 Subject: [PATCH 1623/3723] posix: timer: Fix timer_obj alignment MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This makes sure the heap posix_timer_slab provides objects aligned compatible with the type timer_obj. It was previously set to align at 4 bytes. One example where this failed was on the SPARC which requires access to int64_t to be 8-byte aligned. In particular, struct timer_obj contains fields of type k_timer_t and struct _timeout. With this commit we now get the information on required alignment for struct timer_obj from the compiler by using __alignof__(). Signed-off-by: Martin Åberg --- lib/posix/timer.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/posix/timer.c b/lib/posix/timer.c index 39668a1c402..da4272f3bf1 100644 --- a/lib/posix/timer.c +++ b/lib/posix/timer.c @@ -29,7 +29,7 @@ struct timer_obj { }; K_MEM_SLAB_DEFINE(posix_timer_slab, sizeof(struct timer_obj), - CONFIG_MAX_TIMER_COUNT, 4); + CONFIG_MAX_TIMER_COUNT, __alignof__(struct timer_obj)); static void zephyr_timer_wrapper(struct k_timer *ztimer) { From dd58f80fe2f21410bfa69df6d7ce837bf7cdee9c Mon Sep 17 00:00:00 2001 From: Flavio Ceolin Date: Tue, 14 Nov 2023 23:04:51 -0800 Subject: [PATCH 1624/3723] doc: Static Analysis requirement Sets static analysis an indispensable requirement for our project releases. Static analysis is not merely a tool but a proactive strategy to unearth and address potential issues in the early stages of development, long before they mature into critical vulnerabilities. By scrutinizing code at rest, static analysis unveils latent defects and potential security risks, thus bolstering the resilience of our software against future threats. Fixes: #64591 Signed-off-by: Flavio Ceolin --- doc/contribute/guidelines.rst | 15 ++++++++++++--- doc/project/project_roles.rst | 22 ++++++++++++++++++++++ doc/project/release_process.rst | 15 +++++++++++---- 3 files changed, 45 insertions(+), 7 deletions(-) diff --git a/doc/contribute/guidelines.rst b/doc/contribute/guidelines.rst index b3dd735dd42..06a70f0845d 100644 --- a/doc/contribute/guidelines.rst +++ b/doc/contribute/guidelines.rst @@ -532,9 +532,18 @@ results you have to create an account yourself. From the Zephyr project page, you may select "Add me to project" to be added to the project. New members must be approved by an admin. -Coverity scans the Zephyr codebase weekly. GitHub issues are automatically -created for any problems found and assigned to the maintainers of the affected -areas. +Static analysis of the Zephyr codebase is conducted on a bi-weekly basis. GitHub +issues are automatically created for any issues detected by static analysis +tools. These issues will have the same (or equivalent) priority initially +defined by the tool. + +To ensure accountability and efficient issue resolution, they are assigned to +the respective maintainer who is responsible for the affected code. + +A dedicated team comprising members with expertise in static analysis, code +quality, and software security ensures the effectiveness of the static +analysis process and verifies that identified issues are properly +triaged and resolved in a timely manner. Workflow ======== diff --git a/doc/project/project_roles.rst b/doc/project/project_roles.rst index 2d1a74b573f..e6f7b6d9d56 100644 --- a/doc/project/project_roles.rst +++ b/doc/project/project_roles.rst @@ -123,6 +123,8 @@ in addition to those listed for Contributors and Collaborators: * Responsibility to ensure all contributions of the project have been reviewed within reasonable time. * Responsibility to enforce the code of conduct. +* Responsibility to triage static analysis issues in their code area. + See :ref:`static_analysis`. Contributors or Collaborators are promoted to the Maintainer role by adding the GitHub user name to one or more ``maintainers`` sections of the @@ -168,6 +170,26 @@ the latter is not possible. * Solicit approvals from maintainers of the subsystems affected * Responsibility to drive the :ref:`pr_technical_escalation` process +Static Analysis Audit Team +++++++++++++++++++++++++++ + +The Static Analysis Audit team works closely with the release engineering +team to ensure that static analysis defects opened during a release +cycle are properly addressed. The team has the following rights and +responsibilities: + +* Right to revert any change in a static analysis tool (e.g: Coverity) + that does not follow the project expectations. +* Responsibility to inform code owners about improper classifications. +* Responsibility to alert TSC if any issues are not adequately addressed by the + responsible code owners. + +Joining the Static Analysis Audit team + +* Contributors highly involved in the project with some expertise + in static analysis. + + .. _release-engineering-team: Release Engineering Team diff --git a/doc/project/release_process.rst b/doc/project/release_process.rst index e1e07c417c8..7523cb951a3 100644 --- a/doc/project/release_process.rst +++ b/doc/project/release_process.rst @@ -94,8 +94,8 @@ At that point, the whole process starts over again. Release Quality Criteria ************************ -The current backlog of prioritized bugs shall be used as a quality metric to -gate the final release. The following counts shall be used: +The current backlog of prioritized bugs shall also be used as a quality metric +to gate the final release. The following counts shall be used: .. csv-table:: Bug Count Release Thresholds :header: "High", "Medium", "Low" @@ -109,6 +109,10 @@ gate the final release. The following counts shall be used: The "low" bug count target of <50 will be a phased approach starting with 150 for release 2.4.0, 100 for release 2.5.0, and 50 for release 2.6.0 +The final release must not contain any static analysis high-critical issues +that can potentially compromise the functionality, security, or reliability of +our software. High-critical issues represent vulnerabilities that, if left +unresolved, could have severe consequences. Release Milestones @@ -269,8 +273,11 @@ components provided by the project: - Compliance with published coding guidelines, style guides and naming conventions and documentation of deviations. -- Regular static analysis on the complete tree using available commercial and - open-source tools and documentation of deviations and false positives. +- Static analysis reports + + - Regular static analysis on the complete tree using available commercial and + open-source tools, and documentation of deviations and false positives. + - Documented components and APIS - Requirements Catalog - Verification Plans From 70ae47587ab9877f7b40357e5edbbd2e41702cc4 Mon Sep 17 00:00:00 2001 From: Kai Meinhard Date: Mon, 4 Dec 2023 16:23:57 +0100 Subject: [PATCH 1625/3723] LOG: DICT: Forward the User Context Void pointer to backend The dictionary logging passed the full log_output structure to the backend instead of the user context void pointer. Signed-off-by: Kai Meinhard --- subsys/logging/log_output_dict.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/subsys/logging/log_output_dict.c b/subsys/logging/log_output_dict.c index 065ffcc4a3c..79b99b3b15e 100644 --- a/subsys/logging/log_output_dict.c +++ b/subsys/logging/log_output_dict.c @@ -45,18 +45,18 @@ void log_dict_output_msg_process(const struct log_output *output, 0U; buffer_write(output->func, (uint8_t *)&output_hdr, sizeof(output_hdr), - (void *)output); + (void *)output->control_block->ctx); size_t len; uint8_t *data = log_msg_get_package(msg, &len); if (len > 0U) { - buffer_write(output->func, data, len, (void *)output); + buffer_write(output->func, data, len, (void *)output->control_block->ctx); } data = log_msg_get_data(msg, &len); if (len > 0U) { - buffer_write(output->func, data, len, (void *)output); + buffer_write(output->func, data, len, (void *)output->control_block->ctx); } log_output_flush(output); @@ -70,5 +70,5 @@ void log_dict_output_dropped_process(const struct log_output *output, uint32_t c msg.num_dropped_messages = MIN(cnt, 9999); buffer_write(output->func, (uint8_t *)&msg, sizeof(msg), - (void *)output); + (void *)output->control_block->ctx); } From c18808950a1a899609338bcb419abed5635492ab Mon Sep 17 00:00:00 2001 From: Francois Ramu Date: Thu, 14 Dec 2023 15:20:09 +0100 Subject: [PATCH 1626/3723] drivers: flash: stm32 ospi flash driver erase large size Erase operation with block of 64KByte larger size than the default 4K sector size if the flash supports. Signed-off-by: Francois Ramu --- drivers/flash/flash_stm32_ospi.c | 33 +++++++++++++++++--------------- 1 file changed, 18 insertions(+), 15 deletions(-) diff --git a/drivers/flash/flash_stm32_ospi.c b/drivers/flash/flash_stm32_ospi.c index eb84564ddea..9d2ed2412dc 100644 --- a/drivers/flash/flash_stm32_ospi.c +++ b/drivers/flash/flash_stm32_ospi.c @@ -1048,10 +1048,20 @@ static int flash_stm32_ospi_erase(const struct device *dev, off_t addr, break; } } else { - /* Sector erase */ - LOG_DBG("Sector Erase"); - + /* Sector or Block erase depending on the size */ + LOG_INF("Sector/Block Erase"); + + cmd_erase.AddressMode = + (dev_cfg->data_mode == OSPI_OPI_MODE) + ? HAL_OSPI_ADDRESS_8_LINES + : HAL_OSPI_ADDRESS_1_LINE; + cmd_erase.AddressDtrMode = + (dev_cfg->data_rate == OSPI_DTR_TRANSFER) + ? HAL_OSPI_ADDRESS_DTR_ENABLE + : HAL_OSPI_ADDRESS_DTR_DISABLE; + cmd_erase.AddressSize = stm32_ospi_hal_address_size(dev); cmd_erase.Address = addr; + const struct jesd216_erase_type *erase_types = dev_data->erase_types; const struct jesd216_erase_type *bet = NULL; @@ -1063,12 +1073,12 @@ static int flash_stm32_ospi_erase(const struct device *dev, off_t addr, if ((etp->exp != 0) && SPI_NOR_IS_ALIGNED(addr, etp->exp) - && SPI_NOR_IS_ALIGNED(size, etp->exp) + && (size >= BIT(etp->exp)) && ((bet == NULL) || (etp->exp > bet->exp))) { bet = etp; cmd_erase.Instruction = bet->cmd; - } else { + } else if (bet == NULL) { /* Use the default sector erase cmd */ if (dev_cfg->data_mode == OSPI_OPI_MODE) { cmd_erase.Instruction = SPI_NOR_OCMD_SE; @@ -1079,22 +1089,15 @@ static int flash_stm32_ospi_erase(const struct device *dev, off_t addr, ? SPI_NOR_CMD_SE_4B : SPI_NOR_CMD_SE; } - cmd_erase.AddressMode = - (dev_cfg->data_mode == OSPI_OPI_MODE) - ? HAL_OSPI_ADDRESS_8_LINES - : HAL_OSPI_ADDRESS_1_LINE; - cmd_erase.AddressDtrMode = - (dev_cfg->data_rate == OSPI_DTR_TRANSFER) - ? HAL_OSPI_ADDRESS_DTR_ENABLE - : HAL_OSPI_ADDRESS_DTR_DISABLE; - cmd_erase.AddressSize = stm32_ospi_hal_address_size(dev); - cmd_erase.Address = addr; /* Avoid using wrong erase type, * if zero entries are found in erase_types */ bet = NULL; } } + LOG_INF("Sector/Block Erase addr 0x%x, asize 0x%x amode 0x%x instr 0x%x", + cmd_erase.Address, cmd_erase.AddressSize, + cmd_erase.AddressMode, cmd_erase.Instruction); ospi_send_cmd(dev, &cmd_erase); From 47d3d9f44846245ba01f7a2cbce7ae04b1a4a07d Mon Sep 17 00:00:00 2001 From: Erwan Gouriou Date: Thu, 7 Dec 2023 15:13:38 +0100 Subject: [PATCH 1627/3723] boards: Add support for stm32h750b_dk Basic support added: - gpio - uart Signed-off-by: Erwan Gouriou --- boards/arm/stm32h750b_dk/Kconfig.board | 8 + boards/arm/stm32h750b_dk/Kconfig.defconfig | 11 ++ .../stm32h750b_dk/arduino_r3_connector.dtsi | 36 +++++ boards/arm/stm32h750b_dk/board.cmake | 7 + .../stm32h750b_dk/doc/img/stm32h750b_dk.png | Bin 0 -> 60103 bytes boards/arm/stm32h750b_dk/doc/index.rst | 145 ++++++++++++++++++ boards/arm/stm32h750b_dk/stm32h750b_dk.dts | 83 ++++++++++ boards/arm/stm32h750b_dk/stm32h750b_dk.yaml | 15 ++ .../arm/stm32h750b_dk/stm32h750b_dk_defconfig | 29 ++++ boards/arm/stm32h750b_dk/support/openocd.cfg | 30 ++++ 10 files changed, 364 insertions(+) create mode 100644 boards/arm/stm32h750b_dk/Kconfig.board create mode 100644 boards/arm/stm32h750b_dk/Kconfig.defconfig create mode 100644 boards/arm/stm32h750b_dk/arduino_r3_connector.dtsi create mode 100644 boards/arm/stm32h750b_dk/board.cmake create mode 100644 boards/arm/stm32h750b_dk/doc/img/stm32h750b_dk.png create mode 100644 boards/arm/stm32h750b_dk/doc/index.rst create mode 100644 boards/arm/stm32h750b_dk/stm32h750b_dk.dts create mode 100644 boards/arm/stm32h750b_dk/stm32h750b_dk.yaml create mode 100644 boards/arm/stm32h750b_dk/stm32h750b_dk_defconfig create mode 100644 boards/arm/stm32h750b_dk/support/openocd.cfg diff --git a/boards/arm/stm32h750b_dk/Kconfig.board b/boards/arm/stm32h750b_dk/Kconfig.board new file mode 100644 index 00000000000..afa01489528 --- /dev/null +++ b/boards/arm/stm32h750b_dk/Kconfig.board @@ -0,0 +1,8 @@ +# STM32H735G Discovery board configuration + +# Copyright (c) 2023 STMicroelectronics +# SPDX-License-Identifier: Apache-2.0 + +config BOARD_STM32H750B_DK + bool "STM32H750B Discovery Kit" + depends on SOC_STM32H750XX diff --git a/boards/arm/stm32h750b_dk/Kconfig.defconfig b/boards/arm/stm32h750b_dk/Kconfig.defconfig new file mode 100644 index 00000000000..48576f5706d --- /dev/null +++ b/boards/arm/stm32h750b_dk/Kconfig.defconfig @@ -0,0 +1,11 @@ +# STM32H750B DK board configuration + +# Copyright (c) 2023 STMicroelectronics +# SPDX-License-Identifier: Apache-2.0 + +if BOARD_STM32H750B_DK + +config BOARD + default "stm32h750b_dk" + +endif # BOARD_STM32H750B_DK diff --git a/boards/arm/stm32h750b_dk/arduino_r3_connector.dtsi b/boards/arm/stm32h750b_dk/arduino_r3_connector.dtsi new file mode 100644 index 00000000000..d5b1e520459 --- /dev/null +++ b/boards/arm/stm32h750b_dk/arduino_r3_connector.dtsi @@ -0,0 +1,36 @@ +/* + * Copyright (c) 2023 STMicroelectronics + * + * SPDX-License-Identifier: Apache-2.0 + */ + +/ { + arduino_header: connector { + compatible = "arduino-header-r3"; + #gpio-cells = <2>; + gpio-map-mask = <0xffffffff 0xffffffc0>; + gpio-map-pass-thru = <0 0x3f>; + gpio-map = <0 0 &gpioc 0 0>, /* A0 */ + <1 0 &gpiof 8 0>, /* A1 */ + <2 0 &gpioa 0 0>, /* A2 */ + <3 0 &gpioa 1 0>, /* A3 */ + <4 0 &gpioc 2 0>, /* A4 */ + <5 0 &gpioc 3 0>, /* A5 */ + <6 0 &gpiob 7 0>, /* D0 */ + <7 0 &gpiob 6 0>, /* D1 */ + <8 0 &gpiog 3 0>, /* D2 */ + <9 0 &gpioa 6 0>, /* D3 */ + <10 0 &gpiok 1 0>, /* D4 */ + <11 0 &gpioa 8 0>, /* D5 */ + <12 0 &gpioe 6 0>, /* D6 */ + <13 0 &gpioi 8 0>, /* D7 */ + <14 0 &gpioe 3 0>, /* D8 */ + <15 0 &gpioh 15 0>, /* D9 */ + <16 0 &gpiob 4 0>, /* D10 */ + <17 0 &gpiob 15 0>, /* D11 */ + <18 0 &gpioi 2 0>, /* D12 */ + <19 0 &gpiod 3 0>, /* D13 */ + <20 0 &gpiod 13 0>, /* D14 */ + <21 0 &gpiod 12 0>; /* D15 */ + }; +}; diff --git a/boards/arm/stm32h750b_dk/board.cmake b/boards/arm/stm32h750b_dk/board.cmake new file mode 100644 index 00000000000..6500e7b1a4a --- /dev/null +++ b/boards/arm/stm32h750b_dk/board.cmake @@ -0,0 +1,7 @@ +# SPDX-License-Identifier: Apache-2.0 + +board_runner_args(jlink "--device=STM32H735IG" "--speed=4000") +board_runner_args(openocd --target-handle=_CHIPNAME.cpu0) + +include(${ZEPHYR_BASE}/boards/common/openocd.board.cmake) +include(${ZEPHYR_BASE}/boards/common/jlink.board.cmake) diff --git a/boards/arm/stm32h750b_dk/doc/img/stm32h750b_dk.png b/boards/arm/stm32h750b_dk/doc/img/stm32h750b_dk.png new file mode 100644 index 0000000000000000000000000000000000000000..7a01651524020a3058f93e45f420040ec72309b6 GIT binary patch literal 60103 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 literal 0 HcmV?d00001 diff --git a/boards/arm/stm32h750b_dk/doc/index.rst b/boards/arm/stm32h750b_dk/doc/index.rst new file mode 100644 index 00000000000..5b61e499e8f --- /dev/null +++ b/boards/arm/stm32h750b_dk/doc/index.rst @@ -0,0 +1,145 @@ +.. _stm32h750b_dk_board: + +ST STM32H750B Discovery Kit +########################### + +Overview +******** + +The STM32H750B-DK Discovery kit is a complete demonstration and development +platform for Arm® Cortex®-M7 core-based STM32H750XBH6 microcontroller, with +128Kbytes of Flash memory and 1 Mbytes of SRAM. + +The STM32H750B-DK Discovery kit is used as a reference design for user +application development before porting to the final product, thus simplifying +the application development. + +The full range of hardware features available on the board helps users to enhance +their application development by an evaluation of all the peripherals (such as +USB OTG FS, Ethernet, microSD™ card, USART, CAN FD, SAI audio DAC stereo with +audio jack input and output, MEMS digital microphone, HyperRAM™, +Octo-SPI Flash memory, RGB interface LCD with capacitive touch panel, and others). +ARDUINO® Uno V3, Pmod™ and STMod+ connectors provide easy connection to extension +shields or daughterboards for specific applications. + +STLINK-V3E is integrated into the board, as the embedded in-circuit debugger and +programmer for the STM32 MCU and USB Virtual COM port bridge. STM32H750B-DK board +comes with the STM32CubeH7 MCU Package, which provides an STM32 comprehensive +software HAL library as well as various software examples. + +.. image:: img/stm32h750b_dk.png + :align: center + :alt: STM32H750B-DK + +More information about the board can be found at the `STM32H750B-DK website`_. +More information about STM32H750 can be found here: + +- `STM32H750 on www.st.com`_ +- `STM32H750xx reference manual`_ +- `STM32H750xx datasheet`_ + +Supported Features +================== + +The current Zephyr stm32h750b_dk board configuration supports the following hardware features: + ++-----------+------------+-------------------------------------+ +| Interface | Controller | Driver/Component | ++===========+============+=====================================+ +| NVIC | on-chip | nested vector interrupt controller | ++-----------+------------+-------------------------------------+ +| UART | on-chip | serial port-polling; | +| | | serial port-interrupt | ++-----------+------------+-------------------------------------+ +| PINMUX | on-chip | pinmux | ++-----------+------------+-------------------------------------+ +| GPIO | on-chip | gpio | ++-----------+------------+-------------------------------------+ + + +Other hardware features are not yet supported on Zephyr porting. + +The default configuration per core can be found in the defconfig file: +``boards/arm/stm32h750b_dk/stm32h750b_dk_defconfig`` + +Pin Mapping +=========== + +For mode details please refer to `STM32H750B-DK website`_. + +Default Zephyr Peripheral Mapping: +---------------------------------- + +- UART_3 TX/RX : PB10/PB11 (ST-Link Virtual Port Com) +- LD1 : PJ2 +- LD2 : PI13 + +System Clock +============ + +The STM32H750B System Clock can be driven by an internal or external oscillator, +as well as by the main PLL clock. By default, the System clock +is driven by the PLL clock at 480MHz. PLL clock is feed by a 25MHz high speed external clock. + +Serial Port +=========== + +The STM32H750B Discovery kit has up to 6 UARTs. +The Zephyr console output is assigned to UART3 which connected to the onboard ST-LINK/V3.0. Virtual +COM port interface. Default communication settings are 115200 8N1. + + +Programming and Debugging +************************* + +See :ref:`build_an_application` for more information about application builds. + + +Flashing +======== + +Connect the STM32H750B-DK to your host computer using the ST-LINK +USB port, then run a serial host program to connect with the board. For example: + +.. code-block:: console + + $ minicom -b 115200 -D /dev/ttyACM0 + +You can then build and flash applications in the usual way. +Here is an example for the :ref:`hello_world` application. + +.. zephyr-app-commands:: + :zephyr-app: samples/hello_world + :board: stm32h750b_dk + :goals: build flash + +You should see the following message in the serial host program: + +.. code-block:: console + + $ Hello World! stm32h750b_dk + + +Debugging +========= + +You can debug an application in the usual way. Here is an example for the +:ref:`hello_world` application. + +.. zephyr-app-commands:: + :zephyr-app: samples/hello_world + :board: stm32h750b_dk + :goals: debug + + +.. _STM32H750B-DK website: + https://www.st.com/en/evaluation-tools/stm32h750b-dk.html + +.. _STM32H750 on www.st.com: + https://www.st.com/en/microcontrollers-microprocessors/stm32h750-value-line.html + +.. _STM32H750xx reference manual: + https://www.st.com/resource/en/reference_manual/rm0433-stm32h742-stm32h743753-and-stm32h750-value-line-advanced-armbased-32bit-mcus-stmicroelectronics.pdf + +.. _STM32H750xx datasheet: + https://www.st.com/resource/en/datasheet/stm32h750ib.pdf diff --git a/boards/arm/stm32h750b_dk/stm32h750b_dk.dts b/boards/arm/stm32h750b_dk/stm32h750b_dk.dts new file mode 100644 index 00000000000..52222253796 --- /dev/null +++ b/boards/arm/stm32h750b_dk/stm32h750b_dk.dts @@ -0,0 +1,83 @@ +/* + * Copyright (c) 2023 STMicroelectronics + * + * SPDX-License-Identifier: Apache-2.0 + */ + +/dts-v1/; +#include +#include +#include + +/ { + model = "STMicroelectronics STM32H750B DISCOVERY KIT"; + compatible = "st,stm32h750b-dk"; + + chosen { + zephyr,console = &usart3; + zephyr,shell-uart = &usart3; + zephyr,sram = &sram0; + zephyr,flash = &flash0; + }; + + leds { + compatible = "gpio-leds"; + red_led: led_1 { + gpios = <&gpioi 13 GPIO_ACTIVE_LOW>; + label = "USER1 LD6"; + }; + green_led: led_2 { + gpios = <&gpioj 2 GPIO_ACTIVE_LOW>; + label = "USER2 LD7"; + }; + }; + + gpio_keys { + compatible = "gpio-keys"; + user_button: button { + label = "User"; + gpios = <&gpioc 13 GPIO_ACTIVE_HIGH>; + zephyr,code = ; + }; + }; + + aliases { + led0 = &green_led; + led1 = &red_led; + sw0 = &user_button; + }; +}; + +&clk_hse { + clock-frequency = ; + hse-bypass; + status = "okay"; +}; + +&pll { + div-m = <5>; + mul-n = <192>; + div-p = <2>; + div-q = <4>; + div-r = <4>; + clocks = <&clk_hse>; + status = "okay"; +}; + +&rcc { + clocks = <&pll>; + clock-frequency = ; + d1cpre = <1>; + hpre = <2>; + d1ppre = <2>; + d2ppre1 = <2>; + d2ppre2 = <2>; + d3ppre = <2>; +}; + +&usart3 { + pinctrl-0 = <&usart3_tx_pb10 &usart3_rx_pb11>; + pinctrl-names = "default"; + current-speed = <115200>; + status = "okay"; +}; diff --git a/boards/arm/stm32h750b_dk/stm32h750b_dk.yaml b/boards/arm/stm32h750b_dk/stm32h750b_dk.yaml new file mode 100644 index 00000000000..126376b1464 --- /dev/null +++ b/boards/arm/stm32h750b_dk/stm32h750b_dk.yaml @@ -0,0 +1,15 @@ +identifier: stm32h750b_dk +name: ST STM32H750B Discovery Kit +type: mcu +arch: arm +toolchain: + - zephyr + - gnuarmemb + - xtools +ram: 1024 +flash: 128 +supported: + - arduino_gpio + - gpio + - dma +vendor: st diff --git a/boards/arm/stm32h750b_dk/stm32h750b_dk_defconfig b/boards/arm/stm32h750b_dk/stm32h750b_dk_defconfig new file mode 100644 index 00000000000..64cab9ff714 --- /dev/null +++ b/boards/arm/stm32h750b_dk/stm32h750b_dk_defconfig @@ -0,0 +1,29 @@ +# Copyright (c) 2023 STMicroelectronics +# SPDX-License-Identifier: Apache-2.0 + +CONFIG_SOC_SERIES_STM32H7X=y +CONFIG_SOC_STM32H750XX=y + +# Enable the internal SMPS regulator +CONFIG_POWER_SUPPLY_LDO=y + +# Enable MPU +CONFIG_ARM_MPU=y + +# Enable HW stack protection +CONFIG_HW_STACK_PROTECTION=y + +CONFIG_SERIAL=y + +# console +CONFIG_CONSOLE=y +CONFIG_UART_CONSOLE=y + +# enable GPIO +CONFIG_GPIO=y + +# Enable Clocks +CONFIG_CLOCK_CONTROL=y + +# enable pin controller +CONFIG_PINCTRL=y diff --git a/boards/arm/stm32h750b_dk/support/openocd.cfg b/boards/arm/stm32h750b_dk/support/openocd.cfg new file mode 100644 index 00000000000..e77a5dbb76c --- /dev/null +++ b/boards/arm/stm32h750b_dk/support/openocd.cfg @@ -0,0 +1,30 @@ +source [find interface/stlink-dap.cfg] +transport select dapdirect_swd + +set WORKAREASIZE 0x2000 +set CHIPNAME STM32H750XB +set BOARDNAME STM23H750B_DK + +source [find target/stm32h7x.cfg] + +# Use connect_assert_srst here to be able to program +# even when core is in sleep mode +reset_config srst_only srst_nogate connect_assert_srst + +$_CHIPNAME.cpu0 configure -event gdb-attach { + echo "Debugger attaching: halting execution" + gdb_breakpoint_override hard +} + +$_CHIPNAME.cpu0 configure -event gdb-detach { + echo "Debugger detaching: resuming execution" + resume +} + +# Due to the use of connect_assert_srst, running gdb requires +# to reset halt just after openocd init. +rename init old_init +proc init {} { + old_init + reset halt +} From b79a3415a9c3f1d3e1dd26b16fed35f9f2a02e29 Mon Sep 17 00:00:00 2001 From: Mariusz Skamra Date: Thu, 28 Dec 2023 10:11:27 +0100 Subject: [PATCH 1628/3723] Bluetooth: audio: has_client: Move bt_has_client structure to header This moves bt_has_client instance structure to has_internal.h header file to be able to access to the instance members in tests. Signed-off-by: Mariusz Skamra --- subsys/bluetooth/audio/has_client.c | 167 +++++++++++--------------- subsys/bluetooth/audio/has_internal.h | 37 ++++++ 2 files changed, 108 insertions(+), 96 deletions(-) diff --git a/subsys/bluetooth/audio/has_client.c b/subsys/bluetooth/audio/has_client.c index c5bd983ce9a..437fa425e21 100644 --- a/subsys/bluetooth/audio/has_client.c +++ b/subsys/bluetooth/audio/has_client.c @@ -19,48 +19,14 @@ LOG_MODULE_REGISTER(bt_has_client, CONFIG_BT_HAS_CLIENT_LOG_LEVEL); -#define HAS_INST(_has) CONTAINER_OF(_has, struct has_inst, has) +#define HAS_INST(_has) CONTAINER_OF(_has, struct bt_has_client, has) #define HANDLE_IS_VALID(handle) ((handle) != 0x0000) - -enum { - HAS_DISCOVER_IN_PROGRESS, - HAS_CP_OPERATION_IN_PROGRESS, - - HAS_NUM_FLAGS, /* keep as last */ -}; - -static struct has_inst { - /** Common profile reference object */ - struct bt_has has; - - /** Profile connection reference */ - struct bt_conn *conn; - - /** Internal flags */ - ATOMIC_DEFINE(flags, HAS_NUM_FLAGS); - - /* GATT procedure parameters */ - union { - struct { - struct bt_uuid_16 uuid; - union { - struct bt_gatt_read_params read; - struct bt_gatt_discover_params discover; - }; - }; - struct bt_gatt_write_params write; - } params; - - struct bt_gatt_subscribe_params features_subscription; - struct bt_gatt_subscribe_params control_point_subscription; - struct bt_gatt_subscribe_params active_index_subscription; -} has_insts[CONFIG_BT_MAX_CONN]; - +static struct bt_has_client clients[CONFIG_BT_MAX_CONN]; static const struct bt_has_client_cb *client_cb; -static struct has_inst *inst_by_conn(struct bt_conn *conn) +static struct bt_has_client *inst_by_conn(struct bt_conn *conn) { - struct has_inst *inst = &has_insts[bt_conn_index(conn)]; + struct bt_has_client *inst = &clients[bt_conn_index(conn)]; if (inst->conn == conn) { return inst; @@ -69,14 +35,14 @@ static struct has_inst *inst_by_conn(struct bt_conn *conn) return NULL; } -static void inst_cleanup(struct has_inst *inst) +static void inst_cleanup(struct bt_has_client *inst) { bt_conn_unref(inst->conn); (void)memset(inst, 0, sizeof(*inst)); } -static enum bt_has_capabilities get_capabilities(const struct has_inst *inst) +static enum bt_has_capabilities get_capabilities(const struct bt_has_client *inst) { enum bt_has_capabilities caps = 0; @@ -88,7 +54,7 @@ static enum bt_has_capabilities get_capabilities(const struct has_inst *inst) return caps; } -static void handle_read_preset_rsp(struct has_inst *inst, struct net_buf_simple *buf) +static void handle_read_preset_rsp(struct bt_has_client *inst, struct net_buf_simple *buf) { const struct bt_has_cp_read_preset_rsp *pdu; struct bt_has_preset_record record; @@ -124,7 +90,8 @@ static void handle_read_preset_rsp(struct has_inst *inst, struct net_buf_simple client_cb->preset_read_rsp(&inst->has, 0, &record, !!pdu->is_last); } -static void handle_generic_update(struct has_inst *inst, struct net_buf_simple *buf, bool is_last) +static void handle_generic_update(struct bt_has_client *inst, struct net_buf_simple *buf, + bool is_last) { const struct bt_has_cp_generic_update *pdu; struct bt_has_preset_record record; @@ -154,7 +121,8 @@ static void handle_generic_update(struct has_inst *inst, struct net_buf_simple * client_cb->preset_update(&inst->has, pdu->prev_index, &record, is_last); } -static void handle_preset_deleted(struct has_inst *inst, struct net_buf_simple *buf, bool is_last) +static void handle_preset_deleted(struct bt_has_client *inst, struct net_buf_simple *buf, + bool is_last) { if (buf->len < sizeof(uint8_t)) { LOG_ERR("malformed PDU"); @@ -164,7 +132,7 @@ static void handle_preset_deleted(struct has_inst *inst, struct net_buf_simple * client_cb->preset_deleted(&inst->has, net_buf_simple_pull_u8(buf), is_last); } -static void handle_preset_availability(struct has_inst *inst, struct net_buf_simple *buf, +static void handle_preset_availability(struct bt_has_client *inst, struct net_buf_simple *buf, bool available, bool is_last) { if (buf->len < sizeof(uint8_t)) { @@ -176,7 +144,7 @@ static void handle_preset_availability(struct has_inst *inst, struct net_buf_sim is_last); } -static void handle_preset_changed(struct has_inst *inst, struct net_buf_simple *buf) +static void handle_preset_changed(struct bt_has_client *inst, struct net_buf_simple *buf) { const struct bt_has_cp_preset_changed *pdu; @@ -223,7 +191,8 @@ static uint8_t control_point_notify_cb(struct bt_conn *conn, struct bt_gatt_subscribe_params *params, const void *data, uint16_t len) { - struct has_inst *inst = CONTAINER_OF(params, struct has_inst, control_point_subscription); + struct bt_has_client *inst = CONTAINER_OF(params, struct bt_has_client, + control_point_subscription); const struct bt_has_cp_hdr *hdr; struct net_buf_simple buf; @@ -259,11 +228,11 @@ static uint8_t control_point_notify_cb(struct bt_conn *conn, return BT_GATT_ITER_CONTINUE; } -static void discover_complete(struct has_inst *inst) +static void discover_complete(struct bt_has_client *inst) { LOG_DBG("conn %p", (void *)inst->conn); - atomic_clear_bit(inst->flags, HAS_DISCOVER_IN_PROGRESS); + atomic_clear_bit(inst->flags, HAS_CLIENT_DISCOVER_IN_PROGRESS); client_cb->discover(inst->conn, 0, &inst->has, inst->has.features & BT_HAS_FEAT_HEARING_AID_TYPE_MASK, @@ -283,7 +252,8 @@ static void discover_failed(struct bt_conn *conn, int err) client_cb->discover(conn, err, NULL, 0, 0); } -static int cp_write(struct has_inst *inst, struct net_buf_simple *buf, bt_gatt_write_func_t func) +static int cp_write(struct bt_has_client *inst, struct net_buf_simple *buf, + bt_gatt_write_func_t func) { const uint16_t value_handle = inst->control_point_subscription.value_handle; @@ -303,18 +273,18 @@ static int cp_write(struct has_inst *inst, struct net_buf_simple *buf, bt_gatt_w static void read_presets_req_cb(struct bt_conn *conn, uint8_t err, struct bt_gatt_write_params *params) { - struct has_inst *inst = CONTAINER_OF(params, struct has_inst, params.write); + struct bt_has_client *inst = CONTAINER_OF(params, struct bt_has_client, params.write); LOG_DBG("conn %p err 0x%02x param %p", (void *)conn, err, params); - atomic_clear_bit(inst->flags, HAS_CP_OPERATION_IN_PROGRESS); + atomic_clear_bit(inst->flags, HAS_CLIENT_CP_OPERATION_IN_PROGRESS); if (err) { client_cb->preset_read_rsp(&inst->has, err, NULL, true); } } -static int read_presets_req(struct has_inst *inst, uint8_t start_index, uint8_t num_presets) +static int read_presets_req(struct bt_has_client *inst, uint8_t start_index, uint8_t num_presets) { struct bt_has_cp_hdr *hdr; struct bt_has_cp_read_presets_req *req; @@ -336,18 +306,18 @@ static int read_presets_req(struct has_inst *inst, uint8_t start_index, uint8_t static void set_active_preset_cb(struct bt_conn *conn, uint8_t err, struct bt_gatt_write_params *params) { - struct has_inst *inst = CONTAINER_OF(params, struct has_inst, params.write); + struct bt_has_client *inst = CONTAINER_OF(params, struct bt_has_client, params.write); LOG_DBG("conn %p err 0x%02x param %p", (void *)conn, err, params); - atomic_clear_bit(inst->flags, HAS_CP_OPERATION_IN_PROGRESS); + atomic_clear_bit(inst->flags, HAS_CLIENT_CP_OPERATION_IN_PROGRESS); if (err) { client_cb->preset_switch(&inst->has, err, inst->has.active_index); } } -static int preset_set(struct has_inst *inst, uint8_t opcode, uint8_t index) +static int preset_set(struct bt_has_client *inst, uint8_t opcode, uint8_t index) { struct bt_has_cp_hdr *hdr; struct bt_has_cp_set_active_preset *req; @@ -364,7 +334,7 @@ static int preset_set(struct has_inst *inst, uint8_t opcode, uint8_t index) return cp_write(inst, &buf, set_active_preset_cb); } -static int preset_set_next_or_prev(struct has_inst *inst, uint8_t opcode) +static int preset_set_next_or_prev(struct bt_has_client *inst, uint8_t opcode) { struct bt_has_cp_hdr *hdr; @@ -378,7 +348,7 @@ static int preset_set_next_or_prev(struct has_inst *inst, uint8_t opcode) return cp_write(inst, &buf, set_active_preset_cb); } -static uint8_t active_index_update(struct has_inst *inst, const void *data, uint16_t len) +static uint8_t active_index_update(struct bt_has_client *inst, const void *data, uint16_t len) { struct net_buf_simple buf; const uint8_t prev = inst->has.active_index; @@ -396,7 +366,8 @@ static uint8_t active_preset_notify_cb(struct bt_conn *conn, struct bt_gatt_subscribe_params *params, const void *data, uint16_t len) { - struct has_inst *inst = CONTAINER_OF(params, struct has_inst, active_index_subscription); + struct bt_has_client *inst = CONTAINER_OF(params, struct bt_has_client, + active_index_subscription); uint8_t prev; LOG_DBG("conn %p params %p data %p len %u", (void *)conn, params, data, len); @@ -420,7 +391,7 @@ static uint8_t active_preset_notify_cb(struct bt_conn *conn, prev = active_index_update(inst, data, len); - if (atomic_test_bit(inst->flags, HAS_DISCOVER_IN_PROGRESS)) { + if (atomic_test_bit(inst->flags, HAS_CLIENT_DISCOVER_IN_PROGRESS)) { /* Got notification during discovery process, postpone the active_index callback * until discovery is complete. */ @@ -437,7 +408,8 @@ static uint8_t active_preset_notify_cb(struct bt_conn *conn, static void active_index_subscribe_cb(struct bt_conn *conn, uint8_t att_err, struct bt_gatt_subscribe_params *params) { - struct has_inst *inst = CONTAINER_OF(params, struct has_inst, active_index_subscription); + struct bt_has_client *inst = CONTAINER_OF(params, struct bt_has_client, + active_index_subscription); LOG_DBG("conn %p att_err 0x%02x params %p", (void *)inst->conn, att_err, params); @@ -451,7 +423,7 @@ static void active_index_subscribe_cb(struct bt_conn *conn, uint8_t att_err, } } -static int active_index_subscribe(struct has_inst *inst, uint16_t value_handle) +static int active_index_subscribe(struct bt_has_client *inst, uint16_t value_handle) { LOG_DBG("conn %p handle 0x%04x", (void *)inst->conn, value_handle); @@ -471,7 +443,7 @@ static uint8_t active_index_read_cb(struct bt_conn *conn, uint8_t att_err, struct bt_gatt_read_params *params, const void *data, uint16_t len) { - struct has_inst *inst = CONTAINER_OF(params, struct has_inst, params.read); + struct bt_has_client *inst = CONTAINER_OF(params, struct bt_has_client, params.read); int err = att_err; LOG_DBG("conn %p att_err 0x%02x params %p data %p len %u", (void *)conn, att_err, params, @@ -500,7 +472,7 @@ static uint8_t active_index_read_cb(struct bt_conn *conn, uint8_t att_err, return BT_GATT_ITER_STOP; } -static int active_index_read(struct has_inst *inst) +static int active_index_read(struct bt_has_client *inst) { LOG_DBG("conn %p", (void *)inst->conn); @@ -520,7 +492,8 @@ static int active_index_read(struct has_inst *inst) static void control_point_subscribe_cb(struct bt_conn *conn, uint8_t att_err, struct bt_gatt_subscribe_params *params) { - struct has_inst *inst = CONTAINER_OF(params, struct has_inst, control_point_subscription); + struct bt_has_client *inst = CONTAINER_OF(params, struct bt_has_client, + control_point_subscription); int err = att_err; LOG_DBG("conn %p att_err 0x%02x", (void *)inst->conn, att_err); @@ -544,7 +517,7 @@ static void control_point_subscribe_cb(struct bt_conn *conn, uint8_t att_err, discover_failed(conn, err); } -static int control_point_subscribe(struct has_inst *inst, uint16_t value_handle, +static int control_point_subscribe(struct bt_has_client *inst, uint16_t value_handle, uint8_t properties) { LOG_DBG("conn %p handle 0x%04x", (void *)inst->conn, value_handle); @@ -569,7 +542,7 @@ static int control_point_subscribe(struct has_inst *inst, uint16_t value_handle, static uint8_t control_point_discover_cb(struct bt_conn *conn, const struct bt_gatt_attr *attr, struct bt_gatt_discover_params *params) { - struct has_inst *inst = CONTAINER_OF(params, struct has_inst, params.discover); + struct bt_has_client *inst = CONTAINER_OF(params, struct bt_has_client, params.discover); const struct bt_gatt_chrc *chrc; int err; @@ -596,7 +569,7 @@ static uint8_t control_point_discover_cb(struct bt_conn *conn, const struct bt_g return BT_GATT_ITER_STOP; } -static int control_point_discover(struct has_inst *inst) +static int control_point_discover(struct bt_has_client *inst) { LOG_DBG("conn %p", (void *)inst->conn); @@ -613,7 +586,7 @@ static int control_point_discover(struct has_inst *inst) return bt_gatt_discover(inst->conn, &inst->params.discover); } -static void features_update(struct has_inst *inst, const void *data, uint16_t len) +static void features_update(struct bt_has_client *inst, const void *data, uint16_t len) { struct net_buf_simple buf; @@ -627,7 +600,7 @@ static void features_update(struct has_inst *inst, const void *data, uint16_t le static uint8_t features_read_cb(struct bt_conn *conn, uint8_t att_err, struct bt_gatt_read_params *params, const void *data, uint16_t len) { - struct has_inst *inst = CONTAINER_OF(params, struct has_inst, params.read); + struct bt_has_client *inst = CONTAINER_OF(params, struct bt_has_client, params.read); int err = att_err; LOG_DBG("conn %p att_err 0x%02x params %p data %p len %u", (void *)conn, att_err, params, @@ -662,7 +635,7 @@ static uint8_t features_read_cb(struct bt_conn *conn, uint8_t att_err, return BT_GATT_ITER_STOP; } -static int features_read(struct has_inst *inst, uint16_t value_handle) +static int features_read(struct bt_has_client *inst, uint16_t value_handle) { LOG_DBG("conn %p handle 0x%04x", (void *)inst->conn, value_handle); @@ -679,7 +652,8 @@ static int features_read(struct has_inst *inst, uint16_t value_handle) static void features_subscribe_cb(struct bt_conn *conn, uint8_t att_err, struct bt_gatt_subscribe_params *params) { - struct has_inst *inst = CONTAINER_OF(params, struct has_inst, features_subscription); + struct bt_has_client *inst = CONTAINER_OF(params, struct bt_has_client, + features_subscription); int err = att_err; LOG_DBG("conn %p att_err 0x%02x params %p", (void *)conn, att_err, params); @@ -706,7 +680,8 @@ static void features_subscribe_cb(struct bt_conn *conn, uint8_t att_err, static uint8_t features_notify_cb(struct bt_conn *conn, struct bt_gatt_subscribe_params *params, const void *data, uint16_t len) { - struct has_inst *inst = CONTAINER_OF(params, struct has_inst, features_subscription); + struct bt_has_client *inst = CONTAINER_OF(params, struct bt_has_client, + features_subscription); LOG_DBG("conn %p params %p data %p len %u", (void *)conn, params, data, len); @@ -732,7 +707,7 @@ static uint8_t features_notify_cb(struct bt_conn *conn, struct bt_gatt_subscribe return BT_GATT_ITER_CONTINUE; } -static int features_subscribe(struct has_inst *inst, uint16_t value_handle) +static int features_subscribe(struct bt_has_client *inst, uint16_t value_handle) { LOG_DBG("conn %p handle 0x%04x", (void *)inst->conn, value_handle); @@ -751,7 +726,7 @@ static int features_subscribe(struct has_inst *inst, uint16_t value_handle) static uint8_t features_discover_cb(struct bt_conn *conn, const struct bt_gatt_attr *attr, struct bt_gatt_discover_params *params) { - struct has_inst *inst = CONTAINER_OF(params, struct has_inst, params.discover); + struct bt_has_client *inst = CONTAINER_OF(params, struct bt_has_client, params.discover); const struct bt_gatt_chrc *chrc; int err; @@ -790,7 +765,7 @@ static uint8_t features_discover_cb(struct bt_conn *conn, const struct bt_gatt_a return BT_GATT_ITER_STOP; } -static int features_discover(struct has_inst *inst) +static int features_discover(struct bt_has_client *inst) { LOG_DBG("conn %p", (void *)inst->conn); @@ -832,7 +807,7 @@ int bt_has_client_cb_register(const struct bt_has_client_cb *cb) */ int bt_has_client_discover(struct bt_conn *conn) { - struct has_inst *inst; + struct bt_has_client *inst; int err; LOG_DBG("conn %p", (void *)conn); @@ -841,10 +816,10 @@ int bt_has_client_discover(struct bt_conn *conn) return -EINVAL; } - inst = &has_insts[bt_conn_index(conn)]; + inst = &clients[bt_conn_index(conn)]; - if (atomic_test_bit(inst->flags, HAS_CP_OPERATION_IN_PROGRESS) || - atomic_test_and_set_bit(inst->flags, HAS_DISCOVER_IN_PROGRESS)) { + if (atomic_test_bit(inst->flags, HAS_CLIENT_CP_OPERATION_IN_PROGRESS) || + atomic_test_and_set_bit(inst->flags, HAS_CLIENT_DISCOVER_IN_PROGRESS)) { return -EBUSY; } @@ -856,7 +831,7 @@ int bt_has_client_discover(struct bt_conn *conn) err = features_discover(inst); if (err) { - atomic_clear_bit(inst->flags, HAS_DISCOVER_IN_PROGRESS); + atomic_clear_bit(inst->flags, HAS_CLIENT_DISCOVER_IN_PROGRESS); } return err; @@ -864,7 +839,7 @@ int bt_has_client_discover(struct bt_conn *conn) int bt_has_client_conn_get(const struct bt_has *has, struct bt_conn **conn) { - struct has_inst *inst = HAS_INST(has); + struct bt_has_client *inst = HAS_INST(has); *conn = bt_conn_ref(inst->conn); @@ -873,7 +848,7 @@ int bt_has_client_conn_get(const struct bt_has *has, struct bt_conn **conn) int bt_has_client_presets_read(struct bt_has *has, uint8_t start_index, uint8_t count) { - struct has_inst *inst = HAS_INST(has); + struct bt_has_client *inst = HAS_INST(has); int err; LOG_DBG("conn %p start_index 0x%02x count %d", (void *)inst->conn, start_index, count); @@ -882,8 +857,8 @@ int bt_has_client_presets_read(struct bt_has *has, uint8_t start_index, uint8_t return -ENOTCONN; } - if (atomic_test_bit(inst->flags, HAS_DISCOVER_IN_PROGRESS) || - atomic_test_and_set_bit(inst->flags, HAS_CP_OPERATION_IN_PROGRESS)) { + if (atomic_test_bit(inst->flags, HAS_CLIENT_DISCOVER_IN_PROGRESS) || + atomic_test_and_set_bit(inst->flags, HAS_CLIENT_CP_OPERATION_IN_PROGRESS)) { return -EBUSY; } @@ -897,7 +872,7 @@ int bt_has_client_presets_read(struct bt_has *has, uint8_t start_index, uint8_t err = read_presets_req(inst, start_index, count); if (err) { - atomic_clear_bit(inst->flags, HAS_CP_OPERATION_IN_PROGRESS); + atomic_clear_bit(inst->flags, HAS_CLIENT_CP_OPERATION_IN_PROGRESS); } return err; @@ -905,7 +880,7 @@ int bt_has_client_presets_read(struct bt_has *has, uint8_t start_index, uint8_t int bt_has_client_preset_set(struct bt_has *has, uint8_t index, bool sync) { - struct has_inst *inst = HAS_INST(has); + struct bt_has_client *inst = HAS_INST(has); uint8_t opcode; LOG_DBG("conn %p index 0x%02x", (void *)inst->conn, index); @@ -922,8 +897,8 @@ int bt_has_client_preset_set(struct bt_has *has, uint8_t index, bool sync) return -EOPNOTSUPP; } - if (atomic_test_bit(inst->flags, HAS_DISCOVER_IN_PROGRESS) || - atomic_test_and_set_bit(inst->flags, HAS_CP_OPERATION_IN_PROGRESS)) { + if (atomic_test_bit(inst->flags, HAS_CLIENT_DISCOVER_IN_PROGRESS) || + atomic_test_and_set_bit(inst->flags, HAS_CLIENT_CP_OPERATION_IN_PROGRESS)) { return -EBUSY; } @@ -934,7 +909,7 @@ int bt_has_client_preset_set(struct bt_has *has, uint8_t index, bool sync) int bt_has_client_preset_next(struct bt_has *has, bool sync) { - struct has_inst *inst = HAS_INST(has); + struct bt_has_client *inst = HAS_INST(has); uint8_t opcode; LOG_DBG("conn %p sync %d", (void *)inst->conn, sync); @@ -947,8 +922,8 @@ int bt_has_client_preset_next(struct bt_has *has, bool sync) return -EOPNOTSUPP; } - if (atomic_test_bit(inst->flags, HAS_DISCOVER_IN_PROGRESS) || - atomic_test_and_set_bit(inst->flags, HAS_CP_OPERATION_IN_PROGRESS)) { + if (atomic_test_bit(inst->flags, HAS_CLIENT_DISCOVER_IN_PROGRESS) || + atomic_test_and_set_bit(inst->flags, HAS_CLIENT_CP_OPERATION_IN_PROGRESS)) { return -EBUSY; } @@ -959,7 +934,7 @@ int bt_has_client_preset_next(struct bt_has *has, bool sync) int bt_has_client_preset_prev(struct bt_has *has, bool sync) { - struct has_inst *inst = HAS_INST(has); + struct bt_has_client *inst = HAS_INST(has); uint8_t opcode; LOG_DBG("conn %p sync %d", (void *)inst->conn, sync); @@ -972,8 +947,8 @@ int bt_has_client_preset_prev(struct bt_has *has, bool sync) return -EOPNOTSUPP; } - if (atomic_test_bit(inst->flags, HAS_DISCOVER_IN_PROGRESS) || - atomic_test_and_set_bit(inst->flags, HAS_CP_OPERATION_IN_PROGRESS)) { + if (atomic_test_bit(inst->flags, HAS_CLIENT_DISCOVER_IN_PROGRESS) || + atomic_test_and_set_bit(inst->flags, HAS_CLIENT_CP_OPERATION_IN_PROGRESS)) { return -EBUSY; } @@ -984,13 +959,13 @@ int bt_has_client_preset_prev(struct bt_has *has, bool sync) static void disconnected(struct bt_conn *conn, uint8_t reason) { - struct has_inst *inst = inst_by_conn(conn); + struct bt_has_client *inst = inst_by_conn(conn); if (!inst) { return; } - if (atomic_test_bit(inst->flags, HAS_DISCOVER_IN_PROGRESS)) { + if (atomic_test_bit(inst->flags, HAS_CLIENT_DISCOVER_IN_PROGRESS)) { discover_failed(conn, -ECONNABORTED); } diff --git a/subsys/bluetooth/audio/has_internal.h b/subsys/bluetooth/audio/has_internal.h index c4152eaea1c..5c5dc6b9410 100644 --- a/subsys/bluetooth/audio/has_internal.h +++ b/subsys/bluetooth/audio/has_internal.h @@ -8,6 +8,9 @@ * SPDX-License-Identifier: Apache-2.0 */ +#include +#include + /* Control Point opcodes */ #define BT_HAS_OP_READ_PRESET_REQ 0x01 #define BT_HAS_OP_READ_PRESET_RSP 0x02 @@ -139,3 +142,37 @@ static inline const char *bt_has_change_id_str(uint8_t change_id) return "Unknown changeId"; } } + +enum has_client_flags { + HAS_CLIENT_DISCOVER_IN_PROGRESS, + HAS_CLIENT_CP_OPERATION_IN_PROGRESS, + + HAS_CLIENT_NUM_FLAGS, /* keep as last */ +}; + +struct bt_has_client { + /** Common profile reference object */ + struct bt_has has; + + /** Profile connection reference */ + struct bt_conn *conn; + + /** Internal flags */ + ATOMIC_DEFINE(flags, HAS_CLIENT_NUM_FLAGS); + + /* GATT procedure parameters */ + union { + struct { + struct bt_uuid_16 uuid; + union { + struct bt_gatt_read_params read; + struct bt_gatt_discover_params discover; + }; + }; + struct bt_gatt_write_params write; + } params; + + struct bt_gatt_subscribe_params features_subscription; + struct bt_gatt_subscribe_params control_point_subscription; + struct bt_gatt_subscribe_params active_index_subscription; +}; From 4a77bdb4e805b65baa89641d71eee8c0ea575d57 Mon Sep 17 00:00:00 2001 From: Mariusz Skamra Date: Thu, 14 Dec 2023 15:21:10 +0100 Subject: [PATCH 1629/3723] tests: Bluetooth: tester: Add initial support for HAP This adds initial support for Hearing Aid Profile BTP service commands. Signed-off-by: Mariusz Skamra --- tests/bluetooth/tester/CMakeLists.txt | 4 + tests/bluetooth/tester/overlay-le-audio.conf | 2 + tests/bluetooth/tester/src/btp/btp.h | 4 +- tests/bluetooth/tester/src/btp/btp_hap.h | 61 ++++ tests/bluetooth/tester/src/btp/bttester.h | 3 + tests/bluetooth/tester/src/btp_core.c | 13 + tests/bluetooth/tester/src/btp_hap.c | 277 +++++++++++++++++++ 7 files changed, 363 insertions(+), 1 deletion(-) create mode 100644 tests/bluetooth/tester/src/btp/btp_hap.h create mode 100644 tests/bluetooth/tester/src/btp_hap.c diff --git a/tests/bluetooth/tester/CMakeLists.txt b/tests/bluetooth/tester/CMakeLists.txt index 24b3353b513..6ec469dc0fd 100644 --- a/tests/bluetooth/tester/CMakeLists.txt +++ b/tests/bluetooth/tester/CMakeLists.txt @@ -63,3 +63,7 @@ endif() if(CONFIG_BT_MCC OR CONFIG_BT_MCS) target_sources(app PRIVATE src/btp_mcp.c) endif() + +if(CONFIG_BT_HAS) + target_sources(app PRIVATE src/btp_hap.c) +endif() diff --git a/tests/bluetooth/tester/overlay-le-audio.conf b/tests/bluetooth/tester/overlay-le-audio.conf index 3536a2712da..330ea3c6b99 100644 --- a/tests/bluetooth/tester/overlay-le-audio.conf +++ b/tests/bluetooth/tester/overlay-le-audio.conf @@ -90,6 +90,8 @@ CONFIG_BT_HAS=y CONFIG_BT_HAS_PRESET_COUNT=6 CONFIG_BT_HAS_PRESET_NAME_DYNAMIC=y +CONFIG_BT_HAS_CLIENT=y + # CSIS CONFIG_BT_CSIP_SET_MEMBER=y diff --git a/tests/bluetooth/tester/src/btp/btp.h b/tests/bluetooth/tester/src/btp/btp.h index a88118e895d..e9c6f5ce65f 100644 --- a/tests/bluetooth/tester/src/btp/btp.h +++ b/tests/bluetooth/tester/src/btp/btp.h @@ -32,6 +32,7 @@ #include "btp_cas.h" #include "btp_mcp.h" #include "btp_mcs.h" +#include "btp_hap.h" #define BTP_MTU 1024 #define BTP_DATA_MAX_SIZE (BTP_MTU - sizeof(struct btp_hdr)) @@ -63,8 +64,9 @@ #define BTP_SERVICE_ID_CAS 21 #define BTP_SERVICE_ID_MCP 22 #define BTP_SERVICE_ID_GMCS 23 +#define BTP_SERVICE_ID_HAP 24 -#define BTP_SERVICE_ID_MAX BTP_SERVICE_ID_GMCS +#define BTP_SERVICE_ID_MAX BTP_SERVICE_ID_HAP #define BTP_STATUS_SUCCESS 0x00 #define BTP_STATUS_FAILED 0x01 diff --git a/tests/bluetooth/tester/src/btp/btp_hap.h b/tests/bluetooth/tester/src/btp/btp_hap.h new file mode 100644 index 00000000000..a304a6b87a6 --- /dev/null +++ b/tests/bluetooth/tester/src/btp/btp_hap.h @@ -0,0 +1,61 @@ +/* btp_hap.h - Bluetooth tester headers */ + +/* + * Copyright (c) 2023 Codecoup + * + * SPDX-License-Identifier: Apache-2.0 + */ +#include + +/* HAP commands */ +#define BTP_HAP_READ_SUPPORTED_COMMANDS 0x01 +struct btp_hap_read_supported_commands_rp { + uint8_t data[0]; +} __packed; + +#define BTP_HAP_HA_OPT_PRESETS_SYNC 0x01 +#define BTP_HAP_HA_OPT_PRESETS_INDEPENDENT 0x02 +#define BTP_HAP_HA_OPT_PRESETS_DYNAMIC 0x04 +#define BTP_HAP_HA_OPT_PRESETS_WRITABLE 0x08 + +#define BTP_HAP_HA_INIT 0x02 +struct btp_hap_ha_init_cmd { + uint8_t type; + uint16_t opts; +} __packed; + +#define BTP_HAP_HARC_INIT 0x03 +#define BTP_HAP_HAUC_INIT 0x04 +#define BTP_HAP_IAC_INIT 0x05 + +#define BTP_HAP_IAC_DISCOVER 0x06 +struct btp_hap_iac_discover_cmd { + bt_addr_le_t address; +} __packed; + +#define BTP_HAP_IAC_SET_ALERT 0x07 +struct btp_hap_iac_set_alert_cmd { + bt_addr_le_t address; + uint8_t alert; +} __packed; + +#define BTP_HAP_HAUC_DISCOVER 0x08 +struct btp_hap_hauc_discover_cmd { + bt_addr_le_t address; +} __packed; + +/* HAP events */ +#define BT_HAP_EV_IAC_DISCOVERY_COMPLETE 0x80 +struct btp_hap_iac_discovery_complete_ev { + bt_addr_le_t address; + uint8_t status; +} __packed; + +#define BT_HAP_EV_HAUC_DISCOVERY_COMPLETE 0x81 +struct btp_hap_hauc_discovery_complete_ev { + bt_addr_le_t address; + uint8_t status; + uint16_t has_hearing_aid_features_handle; + uint16_t has_control_point_handle; + uint16_t has_active_preset_index_handle; +} __packed; diff --git a/tests/bluetooth/tester/src/btp/bttester.h b/tests/bluetooth/tester/src/btp/bttester.h index 9c545cd4a46..c4e6397bebb 100644 --- a/tests/bluetooth/tester/src/btp/bttester.h +++ b/tests/bluetooth/tester/src/btp/bttester.h @@ -120,3 +120,6 @@ uint8_t tester_unregister_mcp(void); uint8_t tester_init_mcs(void); uint8_t tester_unregister_mcs(void); + +uint8_t tester_init_hap(void); +uint8_t tester_unregister_hap(void); diff --git a/tests/bluetooth/tester/src/btp_core.c b/tests/bluetooth/tester/src/btp_core.c index 757d8816c8e..b76bd884105 100644 --- a/tests/bluetooth/tester/src/btp_core.c +++ b/tests/bluetooth/tester/src/btp_core.c @@ -98,6 +98,9 @@ static uint8_t supported_services(const void *cmd, uint16_t cmd_len, #if defined(CONFIG_BT_MCS) tester_set_bit(rp->data, BTP_SERVICE_ID_GMCS); #endif /* CONFIG_BT_MCS */ +#if defined(CONFIG_BT_HAS) + tester_set_bit(rp->data, BTP_SERVICE_ID_HAP); +#endif /* CONFIG_BT_HAS */ *rsp_len = sizeof(*rp) + 2; @@ -211,6 +214,11 @@ static uint8_t register_service(const void *cmd, uint16_t cmd_len, status = tester_init_mcs(); break; #endif /* CONFIG_BT_MCS */ +#if defined(CONFIG_BT_HAS) + case BTP_SERVICE_ID_HAP: + status = tester_init_hap(); + break; +#endif /* CONFIG_BT_HAS */ default: LOG_WRN("unknown id: 0x%02x", cp->id); status = BTP_STATUS_FAILED; @@ -328,6 +336,11 @@ static uint8_t unregister_service(const void *cmd, uint16_t cmd_len, status = tester_unregister_mcs(); break; #endif /* CONFIG_BT_MCS */ +#if defined(CONFIG_BT_HAS) + case BTP_SERVICE_ID_HAP: + status = tester_unregister_hap(); + break; +#endif /* CONFIG_BT_HAS */ default: LOG_WRN("unknown id: 0x%x", cp->id); status = BTP_STATUS_FAILED; diff --git a/tests/bluetooth/tester/src/btp_hap.c b/tests/bluetooth/tester/src/btp_hap.c new file mode 100644 index 00000000000..88dba7e8fbb --- /dev/null +++ b/tests/bluetooth/tester/src/btp_hap.c @@ -0,0 +1,277 @@ +/* btp_hap.c - Bluetooth HAP Tester */ + +/* + * Copyright (c) 2023 Codecoup + * + * SPDX-License-Identifier: Apache-2.0 + */ +#include +#include +#include +#include +#include +#include + +#include "../bluetooth/audio/has_internal.h" +#include "btp/btp.h" + +#include +LOG_MODULE_REGISTER(bttester_hap, CONFIG_BTTESTER_LOG_LEVEL); + +static uint8_t read_supported_commands(const void *cmd, uint16_t cmd_len, void *rsp, + uint16_t *rsp_len) +{ + struct btp_hap_read_supported_commands_rp *rp = rsp; + + tester_set_bit(rp->data, BTP_HAP_READ_SUPPORTED_COMMANDS); + tester_set_bit(rp->data, BTP_HAP_HA_INIT); + tester_set_bit(rp->data, BTP_HAP_HAUC_INIT); + tester_set_bit(rp->data, BTP_HAP_IAC_INIT); + tester_set_bit(rp->data, BTP_HAP_IAC_DISCOVER); + tester_set_bit(rp->data, BTP_HAP_IAC_SET_ALERT); + tester_set_bit(rp->data, BTP_HAP_HAUC_DISCOVER); + + *rsp_len = sizeof(*rp) + 1; + + return BTP_STATUS_SUCCESS; +} + +static uint8_t ha_init(const void *cmd, uint16_t cmd_len, void *rsp, uint16_t *rsp_len) +{ + const struct btp_hap_ha_init_cmd *cp = cmd; + struct bt_has_features_param params; + const uint16_t opts = sys_le16_to_cpu(cp->opts); + const bool presets_sync = (opts & BTP_HAP_HA_OPT_PRESETS_SYNC) > 0; + const bool presets_independent = (opts & BTP_HAP_HA_OPT_PRESETS_INDEPENDENT) > 0; + const bool presets_writable = (opts & BTP_HAP_HA_OPT_PRESETS_WRITABLE) > 0; + const bool presets_dynamic = (opts & BTP_HAP_HA_OPT_PRESETS_DYNAMIC) > 0; + int err; + + if (!IS_ENABLED(CONFIG_BT_HAS_PRESET_SUPPORT) && + (presets_sync || presets_independent || presets_writable || presets_dynamic)) { + return BTP_STATUS_VAL(-ENOTSUP); + } + + /* Only dynamic presets are supported */ + if (!presets_dynamic) { + return BTP_STATUS_VAL(-ENOTSUP); + } + + /* Preset name writable support mismatch */ + if (presets_writable != IS_ENABLED(CONFIG_BT_HAS_PRESET_NAME_DYNAMIC)) { + return BTP_STATUS_VAL(-ENOTSUP); + } + + params.type = cp->type; + params.preset_sync_support = presets_sync; + params.independent_presets = presets_independent; + + if (cp->type == BT_HAS_HEARING_AID_TYPE_BANDED) { + err = bt_pacs_set_location(BT_AUDIO_DIR_SINK, BT_AUDIO_LOCATION_FRONT_LEFT | + BT_AUDIO_LOCATION_FRONT_RIGHT); + } else { + err = bt_pacs_set_location(BT_AUDIO_DIR_SINK, BT_AUDIO_LOCATION_FRONT_LEFT); + } + + if (err != 0) { + return BTP_STATUS_VAL(err); + } + + err = bt_has_register(¶ms); + if (err != 0) { + return BTP_STATUS_VAL(err); + } + + return BTP_STATUS_SUCCESS; +} + +static void has_client_discover_cb(struct bt_conn *conn, int err, struct bt_has *has, + enum bt_has_hearing_aid_type type, enum bt_has_capabilities caps) +{ + struct btp_hap_hauc_discovery_complete_ev ev = { 0 }; + + LOG_DBG("conn %p err %d", (void *)conn, err); + + bt_addr_le_copy(&ev.address, bt_conn_get_dst(conn)); + ev.status = BTP_STATUS_VAL(err); + + if (err != 0 && err != BT_ATT_ERR_ATTRIBUTE_NOT_FOUND) { + LOG_DBG("Client discovery failed: %d", err); + } else { + struct bt_has_client *inst = CONTAINER_OF(has, struct bt_has_client, has); + + ev.has_hearing_aid_features_handle = inst->features_subscription.value_handle; + ev.has_control_point_handle = inst->control_point_subscription.value_handle; + ev.has_active_preset_index_handle = inst->active_index_subscription.value_handle; + } + + tester_event(BTP_SERVICE_ID_HAP, BT_HAP_EV_HAUC_DISCOVERY_COMPLETE, &ev, sizeof(ev)); +} + +static void has_client_preset_switch_cb(struct bt_has *has, int err, uint8_t index) +{ + +} + +static const struct bt_has_client_cb has_client_cb = { + .discover = has_client_discover_cb, + .preset_switch = has_client_preset_switch_cb, +}; + +static uint8_t hauc_init(const void *cmd, uint16_t cmd_len, void *rsp, uint16_t *rsp_len) +{ + int err; + + err = bt_has_client_cb_register(&has_client_cb); + if (err != 0) { + LOG_DBG("Failed to register client callbacks: %d", err); + return BTP_STATUS_FAILED; + } + + return BTP_STATUS_SUCCESS; +} + +static void ias_client_discover_cb(struct bt_conn *conn, int err) +{ + struct btp_hap_iac_discovery_complete_ev ev; + struct bt_conn_info info; + + bt_conn_get_info(conn, &info); + + bt_addr_le_copy(&ev.address, info.le.dst); + if (err < 0) { + ev.status = BT_ATT_ERR_UNLIKELY; + } else { + ev.status = (uint8_t)err; + } + + tester_event(BTP_SERVICE_ID_HAP, BT_HAP_EV_IAC_DISCOVERY_COMPLETE, &ev, sizeof(ev)); +} + +static const struct bt_ias_client_cb ias_client_cb = { + .discover = ias_client_discover_cb, +}; + +static uint8_t iac_init(const void *cmd, uint16_t cmd_len, void *rsp, uint16_t *rsp_len) +{ + int err; + + err = bt_ias_client_cb_register(&ias_client_cb); + if (err != 0) { + return BTP_STATUS_VAL(err); + } + + return BTP_STATUS_SUCCESS; +} + +static uint8_t iac_discover(const void *cmd, uint16_t cmd_len, void *rsp, uint16_t *rsp_len) +{ + const struct btp_hap_iac_discover_cmd *cp = cmd; + struct bt_conn *conn; + int err; + + conn = bt_conn_lookup_addr_le(BT_ID_DEFAULT, &cp->address); + if (!conn) { + LOG_ERR("Unknown connection"); + return BTP_STATUS_FAILED; + } + + err = bt_ias_discover(conn); + + bt_conn_unref(conn); + + return BTP_STATUS_VAL(err); +} + +static uint8_t iac_set_alert(const void *cmd, uint16_t cmd_len, void *rsp, uint16_t *rsp_len) +{ + const struct btp_hap_iac_set_alert_cmd *cp = cmd; + struct bt_conn *conn; + int err; + + conn = bt_conn_lookup_addr_le(BT_ID_DEFAULT, &cp->address); + if (!conn) { + LOG_ERR("Unknown connection"); + return BTP_STATUS_FAILED; + } + + err = bt_ias_client_alert_write(conn, (enum bt_ias_alert_lvl)cp->alert); + + bt_conn_unref(conn); + + return BTP_STATUS_VAL(err); +} + +static uint8_t hauc_discover(const void *cmd, uint16_t cmd_len, void *rsp, uint16_t *rsp_len) +{ + const struct btp_hap_hauc_discover_cmd *cp = cmd; + struct bt_conn *conn; + int err; + + conn = bt_conn_lookup_addr_le(BT_ID_DEFAULT, &cp->address); + if (!conn) { + LOG_ERR("Unknown connection"); + return BTP_STATUS_FAILED; + } + + err = bt_has_client_discover(conn); + if (err != 0) { + LOG_DBG("Failed to discover remote HAS: %d", err); + } + + bt_conn_unref(conn); + + return BTP_STATUS_VAL(err); +} + +static const struct btp_handler hap_handlers[] = { + { + .opcode = BTP_HAP_READ_SUPPORTED_COMMANDS, + .index = BTP_INDEX_NONE, + .expect_len = 0, + .func = read_supported_commands, + }, + { + .opcode = BTP_HAP_HA_INIT, + .expect_len = sizeof(struct btp_hap_ha_init_cmd), + .func = ha_init, + }, + { + .opcode = BTP_HAP_HAUC_INIT, + .expect_len = 0, + .func = hauc_init, + }, + { + .opcode = BTP_HAP_IAC_INIT, + .expect_len = 0, + .func = iac_init, + }, + { + .opcode = BTP_HAP_IAC_DISCOVER, + .expect_len = sizeof(struct btp_hap_iac_discover_cmd), + .func = iac_discover, + }, + { + .opcode = BTP_HAP_IAC_SET_ALERT, + .expect_len = sizeof(struct btp_hap_iac_set_alert_cmd), + .func = iac_set_alert, + }, + { + .opcode = BTP_HAP_HAUC_DISCOVER, + .expect_len = sizeof(struct btp_hap_hauc_discover_cmd), + .func = hauc_discover, + }, +}; + +uint8_t tester_init_hap(void) +{ + tester_register_command_handlers(BTP_SERVICE_ID_HAP, hap_handlers, + ARRAY_SIZE(hap_handlers)); + + return BTP_STATUS_SUCCESS; +} + +uint8_t tester_unregister_hap(void) +{ + return BTP_STATUS_SUCCESS; +} From 9ad8e1ab7448f21af3074c993ff6c8240336dcbd Mon Sep 17 00:00:00 2001 From: cyliang tw Date: Tue, 19 Dec 2023 20:38:20 +0800 Subject: [PATCH 1630/3723] drivers: adc: support Nuvoton numaker series Add Nuvoton numaker series adc controller, including async read feature. Signed-off-by: cyliang tw --- drivers/adc/CMakeLists.txt | 1 + drivers/adc/Kconfig | 2 + drivers/adc/Kconfig.numaker | 14 + drivers/adc/adc_numaker.c | 395 ++++++++++++++++++++++ dts/arm/nuvoton/m46x.dtsi | 40 +++ dts/bindings/adc/nuvoton,numaker-adc.yaml | 32 ++ modules/Kconfig.nuvoton | 4 + 7 files changed, 488 insertions(+) create mode 100644 drivers/adc/Kconfig.numaker create mode 100644 drivers/adc/adc_numaker.c create mode 100644 dts/bindings/adc/nuvoton,numaker-adc.yaml diff --git a/drivers/adc/CMakeLists.txt b/drivers/adc/CMakeLists.txt index 34536f4c4e0..808fb1a6698 100644 --- a/drivers/adc/CMakeLists.txt +++ b/drivers/adc/CMakeLists.txt @@ -48,3 +48,4 @@ zephyr_library_sources_ifdef(CONFIG_ADC_MAX1125X adc_max1125x.c) zephyr_library_sources_ifdef(CONFIG_ADC_MAX11102_17 adc_max11102_17.c) zephyr_library_sources_ifdef(CONFIG_ADC_AD5592 adc_ad5592.c) zephyr_library_sources_ifdef(CONFIG_ADC_LTC2451 adc_ltc2451.c) +zephyr_library_sources_ifdef(CONFIG_ADC_NUMAKER adc_numaker.c) diff --git a/drivers/adc/Kconfig b/drivers/adc/Kconfig index 6dd41582bd0..721de86c98f 100644 --- a/drivers/adc/Kconfig +++ b/drivers/adc/Kconfig @@ -119,4 +119,6 @@ source "drivers/adc/Kconfig.ad5592" source "drivers/adc/Kconfig.ltc2451" +source "drivers/adc/Kconfig.numaker" + endif # ADC diff --git a/drivers/adc/Kconfig.numaker b/drivers/adc/Kconfig.numaker new file mode 100644 index 00000000000..ea5f1288beb --- /dev/null +++ b/drivers/adc/Kconfig.numaker @@ -0,0 +1,14 @@ +# NUMAKER ADC Driver configuration options + +# Copyright (c) 2023 Nuvoton Technology Corporation. +# SPDX-License-Identifier: Apache-2.0 + +config ADC_NUMAKER + bool "Nuvoton NuMaker MCU ADC driver" + default y + select HAS_NUMAKER_ADC + depends on DT_HAS_NUVOTON_NUMAKER_ADC_ENABLED + help + This option enables the ADC driver for Nuvoton NuMaker family of + processors. + Say y if you wish to enable NuMaker ADC. diff --git a/drivers/adc/adc_numaker.c b/drivers/adc/adc_numaker.c new file mode 100644 index 00000000000..4fae17f422d --- /dev/null +++ b/drivers/adc/adc_numaker.c @@ -0,0 +1,395 @@ +/* + * Copyright (c) 2023 Nuvoton Technology Corporation. + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#define DT_DRV_COMPAT nuvoton_numaker_adc + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#define ADC_CONTEXT_USES_KERNEL_TIMER +#include "adc_context.h" + +LOG_MODULE_REGISTER(adc_numaker, CONFIG_ADC_LOG_LEVEL); + +/* Device config */ +struct adc_numaker_config { + /* eadc base address */ + EADC_T *eadc_base; + uint8_t channel_cnt; + const struct reset_dt_spec reset; + /* clock configuration */ + uint32_t clk_modidx; + uint32_t clk_src; + uint32_t clk_div; + const struct device *clk_dev; + const struct pinctrl_dev_config *pincfg; + void (*irq_config_func)(const struct device *dev); +}; + +/* Driver context/data */ +struct adc_numaker_data { + struct adc_context ctx; + const struct device *dev; + uint16_t *buffer; + uint16_t *buf_end; + uint16_t *repeat_buffer; + bool is_differential; + uint32_t channels; +}; + +static int adc_numaker_channel_setup(const struct device *dev, + const struct adc_channel_cfg *chan_cfg) +{ + const struct adc_numaker_config *cfg = dev->config; + struct adc_numaker_data *data = dev->data; + + if (chan_cfg->acquisition_time != ADC_ACQ_TIME_DEFAULT) { + LOG_ERR("Not support acquisition time"); + return -ENOTSUP; + } + + if (chan_cfg->gain != ADC_GAIN_1) { + LOG_ERR("Not support channel gain"); + return -ENOTSUP; + } + + if (chan_cfg->reference != ADC_REF_INTERNAL) { + LOG_ERR("Not support channel reference"); + return -ENOTSUP; + } + + if (chan_cfg->channel_id >= cfg->channel_cnt) { + LOG_ERR("Invalid channel (%u)", chan_cfg->channel_id); + return -EINVAL; + } + + data->is_differential = (chan_cfg->differential) ? true : false; + + return 0; +} + +static int m_adc_numaker_validate_buffer_size(const struct device *dev, + const struct adc_sequence *sequence) +{ + const struct adc_numaker_config *cfg = dev->config; + uint8_t channel_cnt = 0; + uint32_t mask; + size_t needed_size; + + for (mask = BIT(cfg->channel_cnt - 1); mask != 0; mask >>= 1) { + if (mask & sequence->channels) { + channel_cnt++; + } + } + + needed_size = channel_cnt * sizeof(uint16_t); + if (sequence->options) { + needed_size *= (1 + sequence->options->extra_samplings); + } + + if (sequence->buffer_size < needed_size) { + return -ENOBUFS; + } + + return 0; +} + +static void adc_numaker_isr(const struct device *dev) +{ + const struct adc_numaker_config *cfg = dev->config; + EADC_T *eadc = cfg->eadc_base; + struct adc_numaker_data *const data = dev->data; + uint32_t channel_mask = data->channels; + uint32_t module_mask = channel_mask; + uint32_t module_id; + uint16_t conv_data; + uint32_t pend_flag; + + /* Clear pending flag first */ + pend_flag = eadc->PENDSTS; + eadc->PENDSTS = pend_flag; + LOG_DBG("ADC ISR pend flag: 0x%X\n", pend_flag); + LOG_DBG("ADC ISR STATUS2[0x%x] STATUS3[0x%x]", eadc->STATUS2, eadc->STATUS3); + /* Complete the conversion of channels. + * Check EAC idle by EADC_STATUS2_BUSY_Msk + * Check trigger source coming by EADC_STATUS2_ADOVIF_Msk + * Confirm all sample modules are idle by EADC_STATUS2_ADOVIF_Msk + */ + if (!(eadc->STATUS2 & EADC_STATUS2_BUSY_Msk) && + ((eadc->STATUS3 & EADC_STATUS3_CURSPL_Msk) == EADC_STATUS3_CURSPL_Msk)) { + /* Stop the conversion for sample module */ + EADC_STOP_CONV(eadc, module_mask); + + /* Disable sample module A/D ADINT0 interrupt. */ + EADC_DISABLE_INT(eadc, BIT0); + + /* Disable the sample module ADINT0 interrupt source */ + EADC_DISABLE_SAMPLE_MODULE_INT(eadc, 0, module_mask); + + /* Get conversion data of each sample module for selected channel */ + while (module_mask) { + module_id = find_lsb_set(module_mask) - 1; + + conv_data = EADC_GET_CONV_DATA(eadc, module_id); + if (data->buffer < data->buf_end) { + *data->buffer++ = conv_data; + LOG_DBG("ADC ISR id=%d, data=0x%x", module_id, conv_data); + } + module_mask &= ~BIT(module_id); + + /* Disable all channels on each sample module */ + eadc->SCTL[module_id] = 0; + } + + /* Disable ADC */ + EADC_Close(eadc); + + /* Inform sampling is done */ + adc_context_on_sampling_done(&data->ctx, data->dev); + } + + /* Clear the A/D ADINT0 interrupt flag */ + EADC_CLR_INT_FLAG(eadc, EADC_STATUS2_ADIF0_Msk); +} + +static void m_adc_numaker_start_scan(const struct device *dev) +{ + const struct adc_numaker_config *cfg = dev->config; + EADC_T *eadc = cfg->eadc_base; + struct adc_numaker_data *const data = dev->data; + uint32_t channel_mask = data->channels; + uint32_t module_mask = channel_mask; + uint32_t channel_id; + uint32_t module_id; + + /* Configure the sample module, analog input channel and software trigger source */ + while (channel_mask) { + channel_id = find_lsb_set(channel_mask) - 1; + module_id = channel_id; + channel_mask &= ~BIT(channel_id); + EADC_ConfigSampleModule(eadc, module_id, + EADC_SOFTWARE_TRIGGER, channel_id); + } + + /* Clear the A/D ADINT0 interrupt flag for safe */ + EADC_CLR_INT_FLAG(eadc, EADC_STATUS2_ADIF0_Msk); + + /* Enable sample module A/D ADINT0 interrupt. */ + EADC_ENABLE_INT(eadc, BIT0); + + /* Enable sample module interrupt ADINT0. */ + EADC_ENABLE_SAMPLE_MODULE_INT(eadc, 0, module_mask); + + /* Start conversion */ + EADC_START_CONV(eadc, module_mask); +} + +/* Implement ADC API functions of adc_context.h + * - adc_context_start_sampling() + * - adc_context_update_buffer_pointer() + */ +static void adc_context_start_sampling(struct adc_context *ctx) +{ + struct adc_numaker_data *const data = + CONTAINER_OF(ctx, struct adc_numaker_data, ctx); + + data->repeat_buffer = data->buffer; + data->channels = ctx->sequence.channels; + + /* Start ADC conversion for sample modules/channels */ + m_adc_numaker_start_scan(data->dev); +} + +static void adc_context_update_buffer_pointer(struct adc_context *ctx, + bool repeat_sampling) +{ + struct adc_numaker_data *data = + CONTAINER_OF(ctx, struct adc_numaker_data, ctx); + + if (repeat_sampling) { + data->buffer = data->repeat_buffer; + } +} + +static int m_adc_numaker_start_read(const struct device *dev, + const struct adc_sequence *sequence) +{ + const struct adc_numaker_config *cfg = dev->config; + struct adc_numaker_data *data = dev->data; + EADC_T *eadc = cfg->eadc_base; + int err; + + err = m_adc_numaker_validate_buffer_size(dev, sequence); + if (err) { + LOG_ERR("ADC provided buffer is too small"); + return err; + } + + if (!sequence->resolution) { + LOG_ERR("ADC resolution is not valid"); + return -EINVAL; + } + LOG_DBG("Configure resolution=%d", sequence->resolution); + + /* Enable the A/D converter */ + if (data->is_differential) { + err = EADC_Open(eadc, EADC_CTL_DIFFEN_DIFFERENTIAL); + } else { + err = EADC_Open(eadc, EADC_CTL_DIFFEN_SINGLE_END); + } + + if (err) { + LOG_ERR("ADC Open fail (%u)", err); + return -ENODEV; + } + + data->buffer = sequence->buffer; + data->buf_end = data->buffer + sequence->buffer_size / sizeof(uint16_t); + + /* Start ADC conversion */ + adc_context_start_read(&data->ctx, sequence); + + return adc_context_wait_for_completion(&data->ctx); +} + +static int adc_numaker_read(const struct device *dev, + const struct adc_sequence *sequence) +{ + struct adc_numaker_data *data = dev->data; + int err; + + adc_context_lock(&data->ctx, false, NULL); + err = m_adc_numaker_start_read(dev, sequence); + adc_context_release(&data->ctx, err); + + return err; +} + +#ifdef CONFIG_ADC_ASYNC +static int adc_numaker_read_async(const struct device *dev, + const struct adc_sequence *sequence, + struct k_poll_signal *async) +{ + struct adc_numaker_data *data = dev->data; + int err; + + adc_context_lock(&data->ctx, true, async); + err = m_adc_numaker_start_read(dev, sequence); + adc_context_release(&data->ctx, err); + + return err; +} +#endif + +static const struct adc_driver_api adc_numaker_driver_api = { + .channel_setup = adc_numaker_channel_setup, + .read = adc_numaker_read, +#ifdef CONFIG_ADC_ASYNC + .read_async = adc_numaker_read_async, +#endif +}; + +static int adc_numaker_init(const struct device *dev) +{ + const struct adc_numaker_config *cfg = dev->config; + struct adc_numaker_data *data = dev->data; + int err; + struct numaker_scc_subsys scc_subsys; + + /* Validate this module's reset object */ + if (!device_is_ready(cfg->reset.dev)) { + LOG_ERR("reset controller not ready"); + return -ENODEV; + } + + data->dev = dev; + + SYS_UnlockReg(); + + /* CLK controller */ + memset(&scc_subsys, 0x00, sizeof(scc_subsys)); + scc_subsys.subsys_id = NUMAKER_SCC_SUBSYS_ID_PCC; + scc_subsys.pcc.clk_modidx = cfg->clk_modidx; + scc_subsys.pcc.clk_src = cfg->clk_src; + scc_subsys.pcc.clk_div = cfg->clk_div; + + /* Equivalent to CLK_EnableModuleClock() */ + err = clock_control_on(cfg->clk_dev, (clock_control_subsys_t)&scc_subsys); + if (err != 0) { + goto done; + } + /* Equivalent to CLK_SetModuleClock() */ + err = clock_control_configure(cfg->clk_dev, (clock_control_subsys_t)&scc_subsys, NULL); + if (err != 0) { + goto done; + } + + err = pinctrl_apply_state(cfg->pincfg, PINCTRL_STATE_DEFAULT); + if (err) { + LOG_ERR("Failed to apply pinctrl state"); + goto done; + } + + /* Reset EADC to default state, same as BSP's SYS_ResetModule(id_rst) */ + reset_line_toggle_dt(&cfg->reset); + + /* Enable NVIC */ + cfg->irq_config_func(dev); + + /* Init mutex of adc_context */ + adc_context_unlock_unconditionally(&data->ctx); + +done: + SYS_LockReg(); + return err; +} + +#define ADC_NUMAKER_IRQ_CONFIG_FUNC(n) \ + static void adc_numaker_irq_config_func_##n(const struct device *dev) \ + { \ + IRQ_CONNECT(DT_INST_IRQN(n), \ + DT_INST_IRQ(n, priority), \ + adc_numaker_isr, \ + DEVICE_DT_INST_GET(n), 0); \ + \ + irq_enable(DT_INST_IRQN(n)); \ + } + +#define ADC_NUMAKER_INIT(inst) \ + PINCTRL_DT_INST_DEFINE(inst); \ + ADC_NUMAKER_IRQ_CONFIG_FUNC(inst) \ + \ + static const struct adc_numaker_config adc_numaker_cfg_##inst = { \ + .eadc_base = (EADC_T *)DT_INST_REG_ADDR(inst), \ + .channel_cnt = DT_INST_PROP(inst, channels), \ + .reset = RESET_DT_SPEC_INST_GET(inst), \ + .clk_modidx = DT_INST_CLOCKS_CELL(inst, clock_module_index), \ + .clk_src = DT_INST_CLOCKS_CELL(inst, clock_source), \ + .clk_div = DT_INST_CLOCKS_CELL(inst, clock_divider), \ + .clk_dev = DEVICE_DT_GET(DT_PARENT(DT_INST_CLOCKS_CTLR(inst))), \ + .pincfg = PINCTRL_DT_INST_DEV_CONFIG_GET(inst), \ + .irq_config_func = adc_numaker_irq_config_func_##inst, \ + }; \ + \ + static struct adc_numaker_data adc_numaker_data_##inst = { \ + ADC_CONTEXT_INIT_TIMER(adc_numaker_data_##inst, ctx), \ + ADC_CONTEXT_INIT_LOCK(adc_numaker_data_##inst, ctx), \ + ADC_CONTEXT_INIT_SYNC(adc_numaker_data_##inst, ctx), \ + }; \ + DEVICE_DT_INST_DEFINE(inst, \ + &adc_numaker_init, NULL, \ + &adc_numaker_data_##inst, &adc_numaker_cfg_##inst, \ + POST_KERNEL, CONFIG_ADC_INIT_PRIORITY, \ + &adc_numaker_driver_api); + +DT_INST_FOREACH_STATUS_OKAY(ADC_NUMAKER_INIT) diff --git a/dts/arm/nuvoton/m46x.dtsi b/dts/arm/nuvoton/m46x.dtsi index bb0b95c4c80..03e62e817ea 100644 --- a/dts/arm/nuvoton/m46x.dtsi +++ b/dts/arm/nuvoton/m46x.dtsi @@ -11,6 +11,7 @@ #include #include #include +#include / { chosen { @@ -563,6 +564,45 @@ #address-cells = <1>; #size-cells = <0>; }; + + eadc0: eadc@40043000 { + compatible = "nuvoton,numaker-adc"; + reg = <0x40043000 0xffc>; + interrupts = <42 0>; + resets = <&rst NUMAKER_EADC0_RST>; + clocks = <&pcc NUMAKER_EADC0_MODULE + NUMAKER_CLK_CLKSEL0_EADC0SEL_HCLK + NUMAKER_CLK_CLKDIV0_EADC0(12)>; + channels = <19>; + status = "disabled"; + #io-channel-cells = <1>; + }; + + eadc1: eadc@4004b000 { + compatible = "nuvoton,numaker-adc"; + reg = <0x4004b000 0xffc>; + interrupts = <104 0>; + resets = <&rst NUMAKER_EADC1_RST>; + clocks = <&pcc NUMAKER_EADC1_MODULE + NUMAKER_CLK_CLKSEL0_EADC1SEL_HCLK + NUMAKER_CLK_CLKDIV2_EADC1(12)>; + channels = <19>; + status = "disabled"; + #io-channel-cells = <1>; + }; + + eadc2: eadc@40097000 { + compatible = "nuvoton,numaker-adc"; + reg = <0x40097000 0xffc>; + interrupts = <124 0>; + resets = <&rst NUMAKER_EADC2_RST>; + clocks = <&pcc NUMAKER_EADC2_MODULE + NUMAKER_CLK_CLKSEL0_EADC2SEL_HCLK + NUMAKER_CLK_CLKDIV5_EADC2(12)>; + channels = <19>; + status = "disabled"; + #io-channel-cells = <1>; + }; }; }; diff --git a/dts/bindings/adc/nuvoton,numaker-adc.yaml b/dts/bindings/adc/nuvoton,numaker-adc.yaml new file mode 100644 index 00000000000..66708431381 --- /dev/null +++ b/dts/bindings/adc/nuvoton,numaker-adc.yaml @@ -0,0 +1,32 @@ +# Copyright (c) 2023 Nuvoton Technology Corporation. +# SPDX-License-Identifier: Apache-2.0 + +description: Nuvoton, NuMaker ADC controller + +compatible: "nuvoton,numaker-adc" + +include: [adc-controller.yaml, reset-device.yaml, pinctrl-device.yaml] + +properties: + reg: + required: true + + interrupts: + required: true + + resets: + required: true + + clocks: + required: true + + channels: + type: int + description: Number of channels + required: true + + "#io-channel-cells": + const: 1 + +io-channel-cells: + - input diff --git a/modules/Kconfig.nuvoton b/modules/Kconfig.nuvoton index 4413c29423e..bc4ac6d158f 100644 --- a/modules/Kconfig.nuvoton +++ b/modules/Kconfig.nuvoton @@ -67,4 +67,8 @@ menu "Nuvoton NuMaker drivers" bool "NuMaker CAN FD" help Enable Nuvoton CAN FD HAL module driver + config HAS_NUMAKER_ADC + bool "NuMaker ADC" + help + Enable Nuvoton ADC HAL module driver endmenu From d00125875c8297e10d2b21a739f732f7dd781130 Mon Sep 17 00:00:00 2001 From: cyliang tw Date: Tue, 19 Dec 2023 20:39:38 +0800 Subject: [PATCH 1631/3723] tests: drivers: adc: adc_api: support numaker_pfm_m467 Add support for Nuvoton numaker board numaker_pfm_m467. Signed-off-by: cyliang tw --- .../adc_api/boards/numaker_pfm_m467.overlay | 40 +++++++++++++++++++ west.yml | 2 +- 2 files changed, 41 insertions(+), 1 deletion(-) create mode 100644 tests/drivers/adc/adc_api/boards/numaker_pfm_m467.overlay diff --git a/tests/drivers/adc/adc_api/boards/numaker_pfm_m467.overlay b/tests/drivers/adc/adc_api/boards/numaker_pfm_m467.overlay new file mode 100644 index 00000000000..518379facf0 --- /dev/null +++ b/tests/drivers/adc/adc_api/boards/numaker_pfm_m467.overlay @@ -0,0 +1,40 @@ +/* SPDX-License-Identifier: Apache-2.0 */ + +/ { + zephyr,user { + io-channels = <&eadc0 0>, <&eadc0 2>; + }; +}; + +&pinctrl { + /* EVB's UNO Pin A4 & D0 for channel 0 & 2 --> PB0, PB2 */ + eadc0_default: eadc0_default { + group0 { + pinmux = , ; + }; + }; +}; + +&eadc0 { + status = "okay"; + pinctrl-0 = <&eadc0_default>; + pinctrl-names = "default"; + #address-cells = <1>; + #size-cells = <0>; + + channel@0 { + reg = <0>; + zephyr,gain = "ADC_GAIN_1"; + zephyr,reference = "ADC_REF_INTERNAL"; + zephyr,acquisition-time = ; + zephyr,resolution = <10>; + }; + + channel@2 { + reg = <2>; + zephyr,gain = "ADC_GAIN_1"; + zephyr,reference = "ADC_REF_INTERNAL"; + zephyr,acquisition-time = ; + zephyr,resolution = <10>; + }; +}; diff --git a/west.yml b/west.yml index fcb32b7bea9..71d85b47763 100644 --- a/west.yml +++ b/west.yml @@ -188,7 +188,7 @@ manifest: groups: - hal - name: hal_nuvoton - revision: 584190e131655de1046088bd0d0735d83429ec7c + revision: 68a91bb343ff47e40dbd9189a7d6e3ee801a7135 path: modules/hal/nuvoton groups: - hal From 864b1c57f61f9dc2d2344cc3c5c1d2ca69536614 Mon Sep 17 00:00:00 2001 From: Jeremy Bettis Date: Wed, 20 Dec 2023 18:41:47 +0000 Subject: [PATCH 1632/3723] drivers: Wrap register accesses in ECREG Similar to other ITE drivers, wrap register accesses in ECREG. This will allow mocking out the registers in tests. Bug #66401 Signed-off-by: Jeremy Bettis --- drivers/gpio/gpio_ite_it8xxx2_v2.c | 69 +++++++++++++++--------------- 1 file changed, 35 insertions(+), 34 deletions(-) diff --git a/drivers/gpio/gpio_ite_it8xxx2_v2.c b/drivers/gpio/gpio_ite_it8xxx2_v2.c index 71a7ee37b50..fc88060d210 100644 --- a/drivers/gpio/gpio_ite_it8xxx2_v2.c +++ b/drivers/gpio/gpio_ite_it8xxx2_v2.c @@ -7,6 +7,7 @@ #define DT_DRV_COMPAT ite_it8xxx2_gpio_v2 +#include #include #include #include @@ -86,14 +87,14 @@ static int gpio_ite_configure(const struct device *dev, k_spinlock_key_t key = k_spin_lock(&data->lock); if (flags == GPIO_DISCONNECTED) { - *reg_gpcr = GPCR_PORT_PIN_MODE_TRISTATE; + ECREG(reg_gpcr) = GPCR_PORT_PIN_MODE_TRISTATE; /* * Since not all GPIOs can be to configured as tri-state, * prompt error if pin doesn't support the flag. */ - if (*reg_gpcr != GPCR_PORT_PIN_MODE_TRISTATE) { + if (ECREG(reg_gpcr) != GPCR_PORT_PIN_MODE_TRISTATE) { /* Go back to default setting (input) */ - *reg_gpcr = GPCR_PORT_PIN_MODE_INPUT; + ECREG(reg_gpcr) = GPCR_PORT_PIN_MODE_INPUT; LOG_ERR("Cannot config the node-gpio@%x, pin=%d as tri-state", (uint32_t)reg_gpdr, pin); rc = -ENOTSUP; @@ -112,9 +113,9 @@ static int gpio_ite_configure(const struct device *dev, * when changing the line to an output. */ if (flags & GPIO_OPEN_DRAIN) { - *reg_gpotr |= mask; + ECREG(reg_gpotr) |= mask; } else { - *reg_gpotr &= ~mask; + ECREG(reg_gpotr) &= ~mask; } /* 1.8V or 3.3V */ @@ -124,10 +125,10 @@ static int gpio_ite_configure(const struct device *dev, if (volt == IT8XXX2_GPIO_VOLTAGE_1P8) { __ASSERT(!(flags & GPIO_PULL_UP), "Don't enable internal pullup if 1.8V voltage is used"); - *reg_p18scr |= mask; + ECREG(reg_p18scr) |= mask; data->volt_default_set &= ~mask; } else if (volt == IT8XXX2_GPIO_VOLTAGE_3P3) { - *reg_p18scr &= ~mask; + ECREG(reg_p18scr) &= ~mask; /* * A variable is needed to store the difference between * 3.3V and default so that the flag can be distinguished @@ -135,7 +136,7 @@ static int gpio_ite_configure(const struct device *dev, */ data->volt_default_set &= ~mask; } else if (volt == IT8XXX2_GPIO_VOLTAGE_DEFAULT) { - *reg_p18scr &= ~mask; + ECREG(reg_p18scr) &= ~mask; data->volt_default_set |= mask; } else { rc = -EINVAL; @@ -146,31 +147,31 @@ static int gpio_ite_configure(const struct device *dev, /* If output, set level before changing type to an output. */ if (flags & GPIO_OUTPUT) { if (flags & GPIO_OUTPUT_INIT_HIGH) { - *reg_gpdr |= mask; + ECREG(reg_gpdr) |= mask; } else if (flags & GPIO_OUTPUT_INIT_LOW) { - *reg_gpdr &= ~mask; + ECREG(reg_gpdr) &= ~mask; } } /* Set input or output. */ if (flags & GPIO_OUTPUT) { - *reg_gpcr = (*reg_gpcr | GPCR_PORT_PIN_MODE_OUTPUT) & + ECREG(reg_gpcr) = (ECREG(reg_gpcr) | GPCR_PORT_PIN_MODE_OUTPUT) & ~GPCR_PORT_PIN_MODE_INPUT; } else { - *reg_gpcr = (*reg_gpcr | GPCR_PORT_PIN_MODE_INPUT) & + ECREG(reg_gpcr) = (ECREG(reg_gpcr) | GPCR_PORT_PIN_MODE_INPUT) & ~GPCR_PORT_PIN_MODE_OUTPUT; } /* Handle pullup / pulldown */ if (flags & GPIO_PULL_UP) { - *reg_gpcr = (*reg_gpcr | GPCR_PORT_PIN_MODE_PULLUP) & + ECREG(reg_gpcr) = (ECREG(reg_gpcr) | GPCR_PORT_PIN_MODE_PULLUP) & ~GPCR_PORT_PIN_MODE_PULLDOWN; } else if (flags & GPIO_PULL_DOWN) { - *reg_gpcr = (*reg_gpcr | GPCR_PORT_PIN_MODE_PULLDOWN) & + ECREG(reg_gpcr) = (ECREG(reg_gpcr) | GPCR_PORT_PIN_MODE_PULLDOWN) & ~GPCR_PORT_PIN_MODE_PULLUP; } else { /* No pull up/down */ - *reg_gpcr &= ~(GPCR_PORT_PIN_MODE_PULLUP | + ECREG(reg_gpcr) &= ~(GPCR_PORT_PIN_MODE_PULLUP | GPCR_PORT_PIN_MODE_PULLDOWN); } @@ -195,7 +196,7 @@ static int gpio_ite_get_config(const struct device *dev, k_spinlock_key_t key = k_spin_lock(&data->lock); /* push-pull or open-drain */ - if (*reg_gpotr & mask) { + if (ECREG(reg_gpotr) & mask) { flags |= GPIO_OPEN_DRAIN; } @@ -204,7 +205,7 @@ static int gpio_ite_get_config(const struct device *dev, if (data->volt_default_set & mask) { flags |= IT8XXX2_GPIO_VOLTAGE_DEFAULT; } else { - if (*reg_p18scr & mask) { + if (ECREG(reg_p18scr) & mask) { flags |= IT8XXX2_GPIO_VOLTAGE_1P8; } else { flags |= IT8XXX2_GPIO_VOLTAGE_3P3; @@ -213,26 +214,26 @@ static int gpio_ite_get_config(const struct device *dev, } /* set input or output. */ - if (*reg_gpcr & GPCR_PORT_PIN_MODE_OUTPUT) { + if (ECREG(reg_gpcr) & GPCR_PORT_PIN_MODE_OUTPUT) { flags |= GPIO_OUTPUT; /* set level */ - if (*reg_gpdr & mask) { + if (ECREG(reg_gpdr) & mask) { flags |= GPIO_OUTPUT_HIGH; } else { flags |= GPIO_OUTPUT_LOW; } } - if (*reg_gpcr & GPCR_PORT_PIN_MODE_INPUT) { + if (ECREG(reg_gpcr) & GPCR_PORT_PIN_MODE_INPUT) { flags |= GPIO_INPUT; /* pullup / pulldown */ - if (*reg_gpcr & GPCR_PORT_PIN_MODE_PULLUP) { + if (ECREG(reg_gpcr) & GPCR_PORT_PIN_MODE_PULLUP) { flags |= GPIO_PULL_UP; } - if (*reg_gpcr & GPCR_PORT_PIN_MODE_PULLDOWN) { + if (ECREG(reg_gpcr) & GPCR_PORT_PIN_MODE_PULLDOWN) { flags |= GPIO_PULL_DOWN; } } @@ -251,7 +252,7 @@ static int gpio_ite_port_get_raw(const struct device *dev, volatile uint8_t *reg_gpdmr = (uint8_t *)gpio_config->reg_gpdmr; /* Get raw bits of GPIO mirror register */ - *value = *reg_gpdmr; + *value = ECREG(reg_gpdmr); return 0; } @@ -265,9 +266,9 @@ static int gpio_ite_port_set_masked_raw(const struct device *dev, uint8_t masked_value = value & mask; struct gpio_ite_data *data = dev->data; k_spinlock_key_t key = k_spin_lock(&data->lock); - uint8_t out = *reg_gpdr; + uint8_t out = ECREG(reg_gpdr); - *reg_gpdr = ((out & ~mask) | masked_value); + ECREG(reg_gpdr) = ((out & ~mask) | masked_value); k_spin_unlock(&data->lock, key); return 0; @@ -282,7 +283,7 @@ static int gpio_ite_port_set_bits_raw(const struct device *dev, k_spinlock_key_t key = k_spin_lock(&data->lock); /* Set raw bits of GPIO data register */ - *reg_gpdr |= pins; + ECREG(reg_gpdr) |= pins; k_spin_unlock(&data->lock, key); return 0; @@ -297,7 +298,7 @@ static int gpio_ite_port_clear_bits_raw(const struct device *dev, k_spinlock_key_t key = k_spin_lock(&data->lock); /* Clear raw bits of GPIO data register */ - *reg_gpdr &= ~pins; + ECREG(reg_gpdr) &= ~pins; k_spin_unlock(&data->lock, key); return 0; @@ -312,7 +313,7 @@ static int gpio_ite_port_toggle_bits(const struct device *dev, k_spinlock_key_t key = k_spin_lock(&data->lock); /* Toggle raw bits of GPIO data register */ - *reg_gpdr ^= pins; + ECREG(reg_gpdr) ^= pins; k_spin_unlock(&data->lock, key); return 0; @@ -349,7 +350,7 @@ static void gpio_ite_isr(const void *arg) /* Should be safe even without spinlock. */ /* Clear the WUC status register. */ - *reg_wuesr = wuc_mask; + ECREG(reg_wuesr) = wuc_mask; /* The callbacks are user code, and therefore should * not hold the lock. */ @@ -404,21 +405,21 @@ static int gpio_ite_pin_interrupt_configure(const struct device *dev, /* Set both edges interrupt. */ if ((trig & GPIO_INT_TRIG_BOTH) == GPIO_INT_TRIG_BOTH) { - *reg_wubemr |= wuc_mask; + ECREG(reg_wubemr) |= wuc_mask; } else { - *reg_wubemr &= ~wuc_mask; + ECREG(reg_wubemr) &= ~wuc_mask; } if (trig & GPIO_INT_TRIG_LOW) { - *reg_wuemr |= wuc_mask; + ECREG(reg_wuemr) |= wuc_mask; } else { - *reg_wuemr &= ~wuc_mask; + ECREG(reg_wuemr) &= ~wuc_mask; } /* * Always write 1 to clear the WUC status register after * modifying edge mode selection register (WUBEMR and WUEMR). */ - *reg_wuesr = wuc_mask; + ECREG(reg_wuesr) = wuc_mask; k_spin_unlock(&data->lock, key); } From 5ceea4fbdd881797a0e194e2e8fd62ffdf8520ad Mon Sep 17 00:00:00 2001 From: Jeremy Bettis Date: Wed, 20 Dec 2023 18:43:12 +0000 Subject: [PATCH 1633/3723] drivers: Use #if Use #if instead of IS_ENABLED for CONFIG_SOC_IT8XXX2_GPIO_GROUP_K_L_DEFAULT_PULL_DOWN, otherwise DTS files are required to provide gpiok and gpiol even if they are not used. Bug #66401 Signed-off-by: Jeremy Bettis --- drivers/gpio/gpio_ite_it8xxx2_v2.c | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/drivers/gpio/gpio_ite_it8xxx2_v2.c b/drivers/gpio/gpio_ite_it8xxx2_v2.c index fc88060d210..1b9fc172a59 100644 --- a/drivers/gpio/gpio_ite_it8xxx2_v2.c +++ b/drivers/gpio/gpio_ite_it8xxx2_v2.c @@ -478,18 +478,18 @@ DEVICE_DT_INST_DEFINE(inst, \ DT_INST_FOREACH_STATUS_OKAY(GPIO_ITE_DEV_CFG_DATA) +#ifdef CONFIG_SOC_IT8XXX2_GPIO_GROUP_K_L_DEFAULT_PULL_DOWN static int gpio_it8xxx2_init_set(void) { - if (IS_ENABLED(CONFIG_SOC_IT8XXX2_GPIO_GROUP_K_L_DEFAULT_PULL_DOWN)) { - const struct device *const gpiok = DEVICE_DT_GET(DT_NODELABEL(gpiok)); - const struct device *const gpiol = DEVICE_DT_GET(DT_NODELABEL(gpiol)); + const struct device *const gpiok = DEVICE_DT_GET(DT_NODELABEL(gpiok)); + const struct device *const gpiol = DEVICE_DT_GET(DT_NODELABEL(gpiol)); - for (int i = 0; i < 8; i++) { - gpio_pin_configure(gpiok, i, GPIO_INPUT | GPIO_PULL_DOWN); - gpio_pin_configure(gpiol, i, GPIO_INPUT | GPIO_PULL_DOWN); - } + for (int i = 0; i < 8; i++) { + gpio_pin_configure(gpiok, i, GPIO_INPUT | GPIO_PULL_DOWN); + gpio_pin_configure(gpiol, i, GPIO_INPUT | GPIO_PULL_DOWN); } return 0; } SYS_INIT(gpio_it8xxx2_init_set, PRE_KERNEL_1, CONFIG_GPIO_INIT_PRIORITY); +#endif /* CONFIG_SOC_IT8XXX2_GPIO_GROUP_K_L_DEFAULT_PULL_DOWN */ From 6c567d489974933f152a532a7e9400b8f6b9bc5d Mon Sep 17 00:00:00 2001 From: Jeremy Bettis Date: Wed, 20 Dec 2023 22:36:20 +0000 Subject: [PATCH 1634/3723] tests: Add unittest for gpio_ite_it8xxx2_v2 Add a unittest for 100% of the lines in gpio_ite_it8xxx2_v2. The test fakes the registers by overriding the ECREG macro to call a function provided by the test. Does not test the code guarded by CONFIG_SOC_IT8XXX2_GPIO_GROUP_K_L_DEFAULT_PULL_DOWN Bug #66401 Signed-off-by: Jeremy Bettis --- .../gpio/gpio_ite_it8xxx2_v2/CMakeLists.txt | 23 + .../drivers/gpio/gpio_ite_it8xxx2_v2/Kconfig | 12 + .../boards/native_sim.overlay | 45 ++ .../include/chip_chipregs.h | 20 + .../include/zephyr/arch/cpu.h | 16 + .../drivers/gpio/gpio_ite_it8xxx2_v2/prj.conf | 9 + .../gpio/gpio_ite_it8xxx2_v2/src/main.c | 460 ++++++++++++++++++ .../gpio/gpio_ite_it8xxx2_v2/testcase.yaml | 14 + 8 files changed, 599 insertions(+) create mode 100644 tests/drivers/gpio/gpio_ite_it8xxx2_v2/CMakeLists.txt create mode 100644 tests/drivers/gpio/gpio_ite_it8xxx2_v2/Kconfig create mode 100644 tests/drivers/gpio/gpio_ite_it8xxx2_v2/boards/native_sim.overlay create mode 100644 tests/drivers/gpio/gpio_ite_it8xxx2_v2/include/chip_chipregs.h create mode 100644 tests/drivers/gpio/gpio_ite_it8xxx2_v2/include/zephyr/arch/cpu.h create mode 100644 tests/drivers/gpio/gpio_ite_it8xxx2_v2/prj.conf create mode 100644 tests/drivers/gpio/gpio_ite_it8xxx2_v2/src/main.c create mode 100644 tests/drivers/gpio/gpio_ite_it8xxx2_v2/testcase.yaml diff --git a/tests/drivers/gpio/gpio_ite_it8xxx2_v2/CMakeLists.txt b/tests/drivers/gpio/gpio_ite_it8xxx2_v2/CMakeLists.txt new file mode 100644 index 00000000000..bf01055ffc3 --- /dev/null +++ b/tests/drivers/gpio/gpio_ite_it8xxx2_v2/CMakeLists.txt @@ -0,0 +1,23 @@ +# Copyright 2023 The ChromiumOS Authors +# +# SPDX-License-Identifier: Apache-2.0 + +cmake_minimum_required(VERSION 3.20.0) + +find_package(Zephyr REQUIRED HINTS $ENV{ZEPHYR_BASE}) +project(gpio_ite_it8xxx2_v2) + +target_include_directories(app PRIVATE + include +) + +zephyr_include_directories( + include + ${ZEPHYR_BASE}/soc/riscv/riscv-ite/common + ${ZEPHYR_BASE}/soc/riscv/riscv-ite/it8xxx2 +) + +target_sources(app + PRIVATE + src/main.c +) diff --git a/tests/drivers/gpio/gpio_ite_it8xxx2_v2/Kconfig b/tests/drivers/gpio/gpio_ite_it8xxx2_v2/Kconfig new file mode 100644 index 00000000000..bb5e43e8e20 --- /dev/null +++ b/tests/drivers/gpio/gpio_ite_it8xxx2_v2/Kconfig @@ -0,0 +1,12 @@ +# Copyright 2023 The ChromiumOS Authors +# +# SPDX-License-Identifier: Apache-2.0 + +source "Kconfig.zephyr" + +config SOC_IT8XXX2_GPIO_GROUP_K_L_DEFAULT_PULL_DOWN + bool + default n +config HAS_ITE_INTC + bool + default y diff --git a/tests/drivers/gpio/gpio_ite_it8xxx2_v2/boards/native_sim.overlay b/tests/drivers/gpio/gpio_ite_it8xxx2_v2/boards/native_sim.overlay new file mode 100644 index 00000000000..7f22c83ffb1 --- /dev/null +++ b/tests/drivers/gpio/gpio_ite_it8xxx2_v2/boards/native_sim.overlay @@ -0,0 +1,45 @@ +/* + * Copyright 2023 The ChromiumOS Authors + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include +#include +#include + +/ { + intc: interrupt-controller@f03f00 { + compatible = "vnd,intc"; + #address-cells = <0>; + #interrupt-cells = <2>; + interrupt-controller; + reg = <0x00f03f00 0x0100>; + }; + + gpioa: gpio@f01601 { + compatible = "ite,it8xxx2-gpio-v2"; + reg = <0x00f01601 1 /* GPDR (set) */ + 0x00f01618 1 /* GPDMR (get) */ + 0x00f01630 1 /* GPOTR */ + 0x00f01648 1 /* P18SCR */ + 0x00f01660 8>; /* GPCR */ + ngpios = <8>; + gpio-controller; + interrupts = <9 IRQ_TYPE_LEVEL_HIGH + 2 IRQ_TYPE_LEVEL_HIGH + 3 IRQ_TYPE_LEVEL_HIGH + 4 IRQ_TYPE_LEVEL_HIGH + 5 IRQ_TYPE_LEVEL_HIGH + 6 IRQ_TYPE_LEVEL_HIGH + 7 IRQ_TYPE_LEVEL_HIGH + 8 IRQ_TYPE_LEVEL_HIGH>; + interrupt-parent = <&intc>; + wuc-base = <0xf01b20 0xf01b20 0xf01b20 0xf01b1c + 0xf01b1c 0xf01b1c 0xf01b1c 0xf01b24>; + wuc-mask = ; + has-volt-sel = <1 1 1 1 1 1 1 1>; + #gpio-cells = <2>; + }; +}; diff --git a/tests/drivers/gpio/gpio_ite_it8xxx2_v2/include/chip_chipregs.h b/tests/drivers/gpio/gpio_ite_it8xxx2_v2/include/chip_chipregs.h new file mode 100644 index 00000000000..3372a845aa9 --- /dev/null +++ b/tests/drivers/gpio/gpio_ite_it8xxx2_v2/include/chip_chipregs.h @@ -0,0 +1,20 @@ +/* + * Copyright 2023 The ChromiumOS Authors + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include <../soc/riscv/riscv-ite/common/chip_chipregs.h> + +/* + * Macros for emulated hardware registers access. + */ +#undef ECREG +#undef ECREG_u16 +#undef ECREG_u32 +#define ECREG(x) (*((volatile unsigned char *)fake_ecreg((intptr_t)x))) +#define ECREG_u16(x) (*((volatile unsigned short *)fake_ecreg((intptr_t)x))) +#define ECREG_u32(x) (*((volatile unsigned long *)fake_ecreg((intptr_t)x))) + +unsigned int *fake_ecreg(intptr_t r); +uint8_t ite_intc_get_irq_num(void); diff --git a/tests/drivers/gpio/gpio_ite_it8xxx2_v2/include/zephyr/arch/cpu.h b/tests/drivers/gpio/gpio_ite_it8xxx2_v2/include/zephyr/arch/cpu.h new file mode 100644 index 00000000000..ab921224676 --- /dev/null +++ b/tests/drivers/gpio/gpio_ite_it8xxx2_v2/include/zephyr/arch/cpu.h @@ -0,0 +1,16 @@ +/* + * Copyright 2023 The ChromiumOS Authors + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include +#include + +int arch_irq_connect_dynamic(unsigned int irq, unsigned int priority, + void (*routine)(const void *parameter), + const void *parameter, uint32_t flags); +int arch_irq_disconnect_dynamic(unsigned int irq, unsigned int priority, + void (*routine)(const void *parameter), + const void *parameter, uint32_t flags); +typedef struct z_thread_stack_element k_thread_stack_t; diff --git a/tests/drivers/gpio/gpio_ite_it8xxx2_v2/prj.conf b/tests/drivers/gpio/gpio_ite_it8xxx2_v2/prj.conf new file mode 100644 index 00000000000..cf7d90e583c --- /dev/null +++ b/tests/drivers/gpio/gpio_ite_it8xxx2_v2/prj.conf @@ -0,0 +1,9 @@ +# Copyright 2023 The ChromiumOS Authors +# +# SPDX-License-Identifier: Apache-2.0 + +CONFIG_ZTEST=y +CONFIG_GPIO_ITE_IT8XXX2_V2=y +CONFIG_GPIO=y +CONFIG_DYNAMIC_INTERRUPTS=y +CONFIG_GPIO_GET_CONFIG=y diff --git a/tests/drivers/gpio/gpio_ite_it8xxx2_v2/src/main.c b/tests/drivers/gpio/gpio_ite_it8xxx2_v2/src/main.c new file mode 100644 index 00000000000..4272fbe42f9 --- /dev/null +++ b/tests/drivers/gpio/gpio_ite_it8xxx2_v2/src/main.c @@ -0,0 +1,460 @@ +/* + * Copyright 2023 The ChromiumOS Authors + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include +#include +#include +#include +#include + +#define MY_GPIO DT_NODELABEL(gpioa) + +const struct device *const gpio_dev = DEVICE_DT_GET(MY_GPIO); +static struct { + uint8_t fake; + uint8_t gpdmr; + uint8_t gpdr; + uint8_t gpotr; + uint8_t p18scr; + uint8_t wuemr, wuesr, wubemr; + uint8_t gpcr[DT_REG_SIZE_BY_IDX(MY_GPIO, 4)]; + bool clear_gpcr_before_read; +} registers; +static int callback_called; +static struct gpio_callback callback_struct; + +/* These values must match what is set in the dts overlay. */ +#define TEST_PIN 1 +#define TEST_IRQ DT_IRQ_BY_IDX(MY_GPIO, TEST_PIN, irq) +#define TEST_MASK DT_PROP_BY_IDX(MY_GPIO, wuc_mask, TEST_PIN) + +DEFINE_FFF_GLOBALS; + +uint8_t ite_intc_get_irq_num(void) +{ + return posix_get_current_irq(); +} + +unsigned int *fake_ecreg(intptr_t r) +{ + switch (r) { + case DT_REG_ADDR_BY_IDX(MY_GPIO, 0): /* GPDR */ + return (unsigned int *)®isters.gpdr; + case DT_REG_ADDR_BY_IDX(MY_GPIO, 1): /* GPDMR */ + return (unsigned int *)®isters.gpdmr; + case DT_REG_ADDR_BY_IDX(MY_GPIO, 2): /* GPOTR */ + return (unsigned int *)®isters.gpotr; + case DT_REG_ADDR_BY_IDX(MY_GPIO, 3): /* P18SCR */ + return (unsigned int *)®isters.p18scr; + case DT_PROP_BY_IDX(MY_GPIO, wuc_base, TEST_PIN): + return (unsigned int *)®isters.wuemr; + case DT_PROP_BY_IDX(MY_GPIO, wuc_base, TEST_PIN) + 1: + return (unsigned int *)®isters.wuesr; + case DT_PROP_BY_IDX(MY_GPIO, wuc_base, TEST_PIN) + 3: + return (unsigned int *)®isters.wubemr; + } + if (r >= DT_REG_ADDR_BY_IDX(MY_GPIO, 4) && + r < DT_REG_ADDR_BY_IDX(MY_GPIO, 4) + DT_REG_SIZE_BY_IDX(MY_GPIO, 4)) { + if (registers.clear_gpcr_before_read) { + registers.gpcr[r - DT_REG_ADDR_BY_IDX(MY_GPIO, 4)] = 0; + } + return (unsigned int *)®isters.gpcr[r - DT_REG_ADDR_BY_IDX(MY_GPIO, 4)]; + } + zassert_unreachable("Register access: %x", r); + return (unsigned int *)®isters.fake; +} + +static void callback(const struct device *port, struct gpio_callback *cb, gpio_port_pins_t pins) +{ + callback_called++; + zexpect_equal(pins, BIT(TEST_PIN)); +} + +static void before_test(void *fixture) +{ + callback_called = 0; + memset(®isters, 0, sizeof(registers)); +} + +static void after_test(void *fixture) +{ + if (callback_struct.handler != NULL) { + zassert_ok(gpio_remove_callback(gpio_dev, &callback_struct)); + } + callback_struct.handler = NULL; +} + +ZTEST_SUITE(gpio_ite_it8xxx2_v2, NULL, NULL, before_test, after_test, NULL); + +ZTEST(gpio_ite_it8xxx2_v2, test_get_active_high) +{ + zassert_true(device_is_ready(gpio_dev)); + zassert_ok(gpio_pin_configure(gpio_dev, TEST_PIN, GPIO_INPUT | GPIO_ACTIVE_HIGH)); + zexpect_equal(registers.gpotr, 0, "gpotr=%x", registers.gpotr); + zexpect_equal(registers.p18scr, 0); + zexpect_equal(registers.gpcr[TEST_PIN], GPCR_PORT_PIN_MODE_INPUT, "gpcr[%d]=%x", TEST_PIN, + registers.gpcr[TEST_PIN]); + registers.gpdmr = (uint8_t)~BIT(TEST_PIN); + zassert_false(gpio_pin_get(gpio_dev, TEST_PIN)); + registers.gpdmr = BIT(TEST_PIN); + zassert_true(gpio_pin_get(gpio_dev, TEST_PIN)); +} + +ZTEST(gpio_ite_it8xxx2_v2, test_get_active_low) +{ + zassert_true(device_is_ready(gpio_dev)); + zassert_ok(gpio_pin_configure(gpio_dev, TEST_PIN, GPIO_INPUT | GPIO_ACTIVE_LOW)); + zexpect_equal(registers.gpotr, 0, "gpotr=%x", registers.gpotr); + zexpect_equal(registers.p18scr, 0); + zexpect_equal(registers.gpcr[TEST_PIN], GPCR_PORT_PIN_MODE_INPUT, "gpcr[%d]=%x", TEST_PIN, + registers.gpcr[TEST_PIN]); + registers.gpdmr = (uint8_t)~BIT(TEST_PIN); + zassert_true(gpio_pin_get(gpio_dev, TEST_PIN)); + registers.gpdmr = BIT(TEST_PIN); + zassert_false(gpio_pin_get(gpio_dev, TEST_PIN)); +} + +ZTEST(gpio_ite_it8xxx2_v2, test_interrupt_edge_rising) +{ + zassert_true(device_is_ready(gpio_dev)); + zassert_ok(gpio_pin_configure(gpio_dev, TEST_PIN, GPIO_INPUT | GPIO_ACTIVE_HIGH)); + + gpio_init_callback(&callback_struct, &callback, BIT(TEST_PIN)); + zassert_ok(gpio_add_callback(gpio_dev, &callback_struct)); + zassert_ok(gpio_pin_interrupt_configure(gpio_dev, TEST_PIN, GPIO_INT_EDGE_TO_ACTIVE)); + zexpect_equal(registers.gpotr, 0, "gpotr=%x", registers.gpotr); + zexpect_equal(registers.p18scr, 0); + zexpect_equal(registers.gpcr[TEST_PIN], GPCR_PORT_PIN_MODE_INPUT, "gpcr[%d]=%x", TEST_PIN, + registers.gpcr[TEST_PIN]); + zexpect_equal(registers.wubemr, 0, "wubemr=%x", registers.wubemr); + zexpect_equal(registers.wuemr, 0, "wuemr=%x", registers.wuemr); + zexpect_equal(registers.wuesr, TEST_MASK, "wuesr=%x", registers.wuesr); + registers.wuesr = 0; + + registers.gpdmr = BIT(TEST_PIN); + /* Mock the hardware interrupt. */ + posix_sw_set_pending_IRQ(TEST_IRQ); + k_sleep(K_MSEC(100)); + zassert_equal(callback_called, 1, "callback_called=%d", callback_called); +} + +ZTEST(gpio_ite_it8xxx2_v2, test_interrupt_enable_disable) +{ + zassert_true(device_is_ready(gpio_dev)); + zassert_ok(gpio_pin_configure(gpio_dev, TEST_PIN, GPIO_INPUT | GPIO_ACTIVE_HIGH)); + + gpio_init_callback(&callback_struct, &callback, BIT(TEST_PIN)); + zassert_ok(gpio_add_callback(gpio_dev, &callback_struct)); + zassert_ok(gpio_pin_interrupt_configure(gpio_dev, TEST_PIN, GPIO_INT_EDGE_TO_ACTIVE)); + zexpect_equal(registers.gpotr, 0, "gpotr=%x", registers.gpotr); + zexpect_equal(registers.p18scr, 0); + zexpect_equal(registers.gpcr[TEST_PIN], GPCR_PORT_PIN_MODE_INPUT, "gpcr[%d]=%x", TEST_PIN, + registers.gpcr[TEST_PIN]); + zexpect_equal(registers.wubemr, 0, "wubemr=%x", registers.wubemr); + zexpect_equal(registers.wuemr, 0, "wuemr=%x", registers.wuemr); + zexpect_equal(registers.wuesr, TEST_MASK, "wuesr=%x", registers.wuesr); + registers.wuesr = 0; + + registers.gpdmr = BIT(TEST_PIN); + /* Mock the hardware interrupt. */ + posix_sw_set_pending_IRQ(TEST_IRQ); + k_sleep(K_MSEC(100)); + zassert_equal(callback_called, 1, "callback_called=%d", callback_called); + registers.gpdmr = 0; + + zassert_ok(gpio_pin_interrupt_configure(gpio_dev, TEST_PIN, GPIO_INT_MODE_DISABLED)); + registers.gpdmr = BIT(TEST_PIN); + /* Mock the hardware interrupt, should be ignored */ + posix_sw_set_pending_IRQ(TEST_IRQ); + k_sleep(K_MSEC(100)); + zassert_equal(callback_called, 1, "callback_called=%d", callback_called); + /* Clear the missed interrupt */ + posix_sw_clear_pending_IRQ(TEST_IRQ); + registers.gpdmr = 0; + + zassert_ok(gpio_pin_interrupt_configure(gpio_dev, TEST_PIN, GPIO_INT_EDGE_TO_ACTIVE)); + registers.gpdmr = BIT(TEST_PIN); + /* Mock the hardware interrupt */ + posix_sw_set_pending_IRQ(TEST_IRQ); + k_sleep(K_MSEC(100)); + zassert_equal(callback_called, 2, "callback_called=%d", callback_called); +} + +ZTEST(gpio_ite_it8xxx2_v2, test_interrupt_edge_falling) +{ + zassert_true(device_is_ready(gpio_dev)); + zassert_ok(gpio_pin_configure(gpio_dev, TEST_PIN, GPIO_INPUT | GPIO_ACTIVE_HIGH)); + + gpio_init_callback(&callback_struct, &callback, BIT(TEST_PIN)); + zassert_ok(gpio_add_callback(gpio_dev, &callback_struct)); + zassert_ok(gpio_pin_interrupt_configure(gpio_dev, TEST_PIN, GPIO_INT_EDGE_TO_INACTIVE)); + zexpect_equal(registers.gpotr, 0, "gpotr=%x", registers.gpotr); + zexpect_equal(registers.p18scr, 0); + zexpect_equal(registers.gpcr[TEST_PIN], GPCR_PORT_PIN_MODE_INPUT, "gpcr[%d]=%x", TEST_PIN, + registers.gpcr[TEST_PIN]); + zexpect_equal(registers.wubemr, 0, "wubemr=%x", registers.wubemr); + zexpect_equal(registers.wuemr, TEST_MASK, "wuemr=%x", registers.wuemr); + zexpect_equal(registers.wuesr, TEST_MASK, "wuesr=%x", registers.wuesr); + registers.wuesr = 0; + + registers.gpdmr = (uint8_t)~BIT(TEST_PIN); + /* Mock the hardware interrupt. */ + posix_sw_set_pending_IRQ(TEST_IRQ); + k_sleep(K_MSEC(100)); + zassert_equal(callback_called, 1, "callback_called=%d", callback_called); +} + +ZTEST(gpio_ite_it8xxx2_v2, test_interrupt_edge_both) +{ + zassert_true(device_is_ready(gpio_dev)); + zassert_ok(gpio_pin_configure(gpio_dev, TEST_PIN, GPIO_INPUT | GPIO_ACTIVE_HIGH)); + + gpio_init_callback(&callback_struct, &callback, BIT(TEST_PIN)); + zassert_ok(gpio_add_callback(gpio_dev, &callback_struct)); + zassert_ok(gpio_pin_interrupt_configure(gpio_dev, TEST_PIN, GPIO_INT_EDGE_BOTH)); + zexpect_equal(registers.gpotr, 0, "gpotr=%x", registers.gpotr); + zexpect_equal(registers.p18scr, 0); + zexpect_equal(registers.gpcr[TEST_PIN], GPCR_PORT_PIN_MODE_INPUT, "gpcr[%d]=%x", TEST_PIN, + registers.gpcr[TEST_PIN]); + zexpect_equal(registers.wubemr, TEST_MASK, "wubemr=%x", registers.wubemr); + zexpect_equal(registers.wuemr, TEST_MASK, "wuemr=%x", registers.wuemr); + zexpect_equal(registers.wuesr, TEST_MASK, "wuesr=%x", registers.wuesr); + registers.wuesr = 0; + + registers.gpdmr = BIT(TEST_PIN); + /* Mock the hardware interrupt. */ + posix_sw_set_pending_IRQ(TEST_IRQ); + k_sleep(K_MSEC(100)); + zassert_equal(callback_called, 1, "callback_called=%d", callback_called); + registers.gpdmr &= ~BIT(TEST_PIN); + /* Mock the hardware interrupt. */ + posix_sw_set_pending_IRQ(TEST_IRQ); + k_sleep(K_MSEC(100)); + zassert_equal(callback_called, 2, "callback_called=%d", callback_called); +} + +ZTEST(gpio_ite_it8xxx2_v2, test_interrupt_level_active) +{ + zassert_true(device_is_ready(gpio_dev)); + zassert_ok(gpio_pin_configure(gpio_dev, TEST_PIN, GPIO_INPUT | GPIO_ACTIVE_HIGH)); + zassert_equal(gpio_pin_interrupt_configure(gpio_dev, TEST_PIN, GPIO_INT_LEVEL_ACTIVE), + -ENOTSUP); + zexpect_equal(registers.gpotr, 0, "gpotr=%x", registers.gpotr); + zexpect_equal(registers.p18scr, 0); + zexpect_equal(registers.gpcr[TEST_PIN], GPCR_PORT_PIN_MODE_INPUT, "gpcr[%d]=%x", TEST_PIN, + registers.gpcr[TEST_PIN]); + zexpect_equal(registers.wubemr, 0, "wubemr=%x", registers.wubemr); + zexpect_equal(registers.wuemr, 0, "wuemr=%x", registers.wuemr); + zexpect_equal(registers.wuesr, 0, "wuesr=%x", registers.wuesr); +} + +ZTEST(gpio_ite_it8xxx2_v2, test_interrupt_level_inactive) +{ + zassert_true(device_is_ready(gpio_dev)); + zassert_ok(gpio_pin_configure(gpio_dev, TEST_PIN, GPIO_INPUT | GPIO_ACTIVE_HIGH)); + zassert_equal(gpio_pin_interrupt_configure(gpio_dev, TEST_PIN, GPIO_INT_LEVEL_INACTIVE), + -ENOTSUP); + zexpect_equal(registers.gpotr, 0, "gpotr=%x", registers.gpotr); + zexpect_equal(registers.p18scr, 0); + zexpect_equal(registers.gpcr[TEST_PIN], GPCR_PORT_PIN_MODE_INPUT, "gpcr[%d]=%x", TEST_PIN, + registers.gpcr[TEST_PIN]); + zexpect_equal(registers.wubemr, 0, "wubemr=%x", registers.wubemr); + zexpect_equal(registers.wuemr, 0, "wuemr=%x", registers.wuemr); + zexpect_equal(registers.wuesr, 0, "wuesr=%x", registers.wuesr); +} + +ZTEST(gpio_ite_it8xxx2_v2, test_set_active_high) +{ + gpio_flags_t flags; + + zassert_true(device_is_ready(gpio_dev)); + zassert_ok(gpio_pin_configure(gpio_dev, TEST_PIN, GPIO_OUTPUT_INACTIVE | GPIO_ACTIVE_HIGH)); + zexpect_equal(registers.gpotr, 0, "gpotr=%x", registers.gpotr); + zexpect_equal(registers.p18scr, 0); + zexpect_equal(registers.gpcr[TEST_PIN], GPCR_PORT_PIN_MODE_OUTPUT, "gpcr[%d]=%x", TEST_PIN, + registers.gpcr[TEST_PIN]); + + zexpect_equal(registers.gpdr, 0, "gpdr=%x", registers.gpdr); + zassert_ok(gpio_pin_set(gpio_dev, TEST_PIN, true)); + zexpect_equal(registers.gpdr, BIT(TEST_PIN), "gpdr=%x", registers.gpdr); + zassert_ok(gpio_pin_set(gpio_dev, TEST_PIN, false)); + zexpect_equal(registers.gpdr, 0, "gpdr=%x", registers.gpdr); + zassert_ok(gpio_port_toggle_bits(gpio_dev, BIT(TEST_PIN))); + zexpect_equal(registers.gpdr, BIT(TEST_PIN), "gpdr=%x", registers.gpdr); + registers.gpdr = 0; + zassert_ok(gpio_port_set_masked(gpio_dev, BIT(TEST_PIN), 255)); + zexpect_equal(registers.gpdr, BIT(TEST_PIN), "gpdr=%x", registers.gpdr); + registers.gpdr = 255; + zassert_ok(gpio_port_set_masked(gpio_dev, BIT(TEST_PIN), 0)); + zexpect_equal(registers.gpdr, (uint8_t)~BIT(TEST_PIN), "gpdr=%x", registers.gpdr); + + registers.gpdr = BIT(TEST_PIN); + zassert_ok(gpio_pin_get_config(gpio_dev, TEST_PIN, &flags)); + zexpect_equal(flags, GPIO_OUTPUT_HIGH, "flags=%x", flags); + registers.gpdr = 0; + zassert_ok(gpio_pin_get_config(gpio_dev, TEST_PIN, &flags)); + zexpect_equal(flags, GPIO_OUTPUT_LOW, "flags=%x", flags); +} + +ZTEST(gpio_ite_it8xxx2_v2, test_set_active_low) +{ + gpio_flags_t flags; + + zassert_true(device_is_ready(gpio_dev)); + zassert_ok(gpio_pin_configure(gpio_dev, TEST_PIN, GPIO_OUTPUT_INACTIVE | GPIO_ACTIVE_LOW)); + zexpect_equal(registers.gpotr, 0, "gpotr=%x", registers.gpotr); + zexpect_equal(registers.p18scr, 0); + zexpect_equal(registers.gpcr[TEST_PIN], GPCR_PORT_PIN_MODE_OUTPUT, "gpcr[%d]=%x", TEST_PIN, + registers.gpcr[TEST_PIN]); + + zexpect_equal(registers.gpdr, BIT(TEST_PIN), "gpdr=%x", registers.gpdr); + zassert_ok(gpio_pin_set(gpio_dev, TEST_PIN, true)); + zexpect_equal(registers.gpdr, 0, "gpdr=%x", registers.gpdr); + zassert_ok(gpio_pin_set(gpio_dev, TEST_PIN, false)); + zexpect_equal(registers.gpdr, BIT(TEST_PIN), "gpdr=%x", registers.gpdr); + zassert_ok(gpio_port_toggle_bits(gpio_dev, BIT(TEST_PIN))); + zexpect_equal(registers.gpdr, 0, "gpdr=%x", registers.gpdr); + registers.gpdr = 255; + zassert_ok(gpio_port_set_masked(gpio_dev, BIT(TEST_PIN), 255)); + zexpect_equal(registers.gpdr, (uint8_t)~BIT(TEST_PIN), "gpdr=%x", registers.gpdr); + registers.gpdr = 0; + zassert_ok(gpio_port_set_masked(gpio_dev, BIT(TEST_PIN), 0)); + zexpect_equal(registers.gpdr, BIT(TEST_PIN), "gpdr=%x", registers.gpdr); + + registers.gpdr = 0; + zassert_ok(gpio_pin_get_config(gpio_dev, TEST_PIN, &flags)); + zexpect_equal(flags, GPIO_OUTPUT_LOW, "flags=%x", flags); + registers.gpdr = BIT(TEST_PIN); + zassert_ok(gpio_pin_get_config(gpio_dev, TEST_PIN, &flags)); + zexpect_equal(flags, GPIO_OUTPUT_HIGH, "flags=%x", flags); +} + +/* The next few tests just verify that the registers are set as expected on configure. */ + +ZTEST(gpio_ite_it8xxx2_v2, test_open_source) +{ + zassert_true(device_is_ready(gpio_dev)); + zassert_equal(gpio_pin_configure(gpio_dev, TEST_PIN, GPIO_OPEN_SOURCE), -ENOTSUP); + zexpect_equal(registers.gpotr, 0, "gpotr=%x", registers.gpotr); + zexpect_equal(registers.p18scr, 0); + zexpect_equal(registers.gpcr[TEST_PIN], 0, "gpcr[%d]=%x", TEST_PIN, + registers.gpcr[TEST_PIN]); +} + +ZTEST(gpio_ite_it8xxx2_v2, test_open_drain_output) +{ + gpio_flags_t flags; + + zassert_true(device_is_ready(gpio_dev)); + zassert_ok(gpio_pin_configure(gpio_dev, TEST_PIN, GPIO_OUTPUT | GPIO_OPEN_DRAIN)); + zexpect_equal(registers.gpotr, BIT(TEST_PIN), "gpotr=%x", registers.gpotr); + zexpect_equal(registers.p18scr, 0); + zexpect_equal(registers.gpcr[TEST_PIN], GPCR_PORT_PIN_MODE_OUTPUT, "gpcr[%d]=%x", TEST_PIN, + registers.gpcr[TEST_PIN]); + + zassert_ok(gpio_pin_get_config(gpio_dev, TEST_PIN, &flags)); + zexpect_equal(flags, GPIO_OUTPUT_LOW | GPIO_OPEN_DRAIN, "flags=%x", flags); +} + +ZTEST(gpio_ite_it8xxx2_v2, test_pull_up_input) +{ + gpio_flags_t flags; + + zassert_true(device_is_ready(gpio_dev)); + zassert_ok(gpio_pin_configure(gpio_dev, TEST_PIN, GPIO_INPUT | GPIO_PULL_UP)); + zexpect_equal(registers.gpotr, 0, "gpotr=%x", registers.gpotr); + zexpect_equal(registers.p18scr, 0); + zexpect_equal(registers.gpcr[TEST_PIN], + GPCR_PORT_PIN_MODE_INPUT | GPCR_PORT_PIN_MODE_PULLUP, "gpcr[%d]=%x", TEST_PIN, + registers.gpcr[TEST_PIN]); + + zassert_ok(gpio_pin_get_config(gpio_dev, TEST_PIN, &flags)); + zexpect_equal(flags, GPIO_INPUT | GPIO_PULL_UP, "flags=%x", flags); +} + +ZTEST(gpio_ite_it8xxx2_v2, test_pull_down_input) +{ + gpio_flags_t flags; + + zassert_true(device_is_ready(gpio_dev)); + zassert_ok(gpio_pin_configure(gpio_dev, TEST_PIN, GPIO_INPUT | GPIO_PULL_DOWN)); + zexpect_equal(registers.gpotr, 0, "gpotr=%x", registers.gpotr); + zexpect_equal(registers.p18scr, 0); + zexpect_equal(registers.gpcr[TEST_PIN], + GPCR_PORT_PIN_MODE_INPUT | GPCR_PORT_PIN_MODE_PULLDOWN, "gpcr[%d]=%x", + TEST_PIN, registers.gpcr[TEST_PIN]); + + zassert_ok(gpio_pin_get_config(gpio_dev, TEST_PIN, &flags)); + zexpect_equal(flags, GPIO_INPUT | GPIO_PULL_DOWN, "flags=%x", flags); +} + +ZTEST(gpio_ite_it8xxx2_v2, test_disconnected_tristate_supported) +{ + gpio_flags_t flags; + + zassert_true(device_is_ready(gpio_dev)); + zassert_ok(gpio_pin_configure(gpio_dev, TEST_PIN, GPIO_DISCONNECTED)); + zexpect_equal(registers.gpotr, 0, "gpotr=%x", registers.gpotr); + zexpect_equal(registers.p18scr, 0); + zexpect_equal(registers.gpcr[TEST_PIN], GPCR_PORT_PIN_MODE_TRISTATE, "gpcr[%d]=%x", + TEST_PIN, registers.gpcr[TEST_PIN]); + + zassert_ok(gpio_pin_get_config(gpio_dev, TEST_PIN, &flags)); + zexpect_equal(flags, GPIO_PULL_UP | GPIO_PULL_DOWN | GPIO_INPUT | IT8XXX2_GPIO_VOLTAGE_3P3, + "flags=%x", flags); +} + +ZTEST(gpio_ite_it8xxx2_v2, test_disconnected_tristate_unsupported) +{ + registers.clear_gpcr_before_read = true; + zassert_true(device_is_ready(gpio_dev)); + zassert_equal(gpio_pin_configure(gpio_dev, TEST_PIN, GPIO_DISCONNECTED), -ENOTSUP); + zexpect_equal(registers.gpotr, 0, "gpotr=%x", registers.gpotr); + zexpect_equal(registers.p18scr, 0); + zexpect_equal(registers.gpcr[TEST_PIN], GPCR_PORT_PIN_MODE_INPUT, "gpcr[%d]=%x", TEST_PIN, + registers.gpcr[TEST_PIN]); +} + +ZTEST(gpio_ite_it8xxx2_v2, test_input_1P8V) +{ + gpio_flags_t flags; + + zassert_true(device_is_ready(gpio_dev)); + zassert_ok(gpio_pin_configure(gpio_dev, TEST_PIN, GPIO_INPUT | IT8XXX2_GPIO_VOLTAGE_1P8)); + zexpect_equal(registers.gpotr, 0, "gpotr=%x", registers.gpotr); + zexpect_equal(registers.p18scr, BIT(TEST_PIN)); + zexpect_equal(registers.gpcr[TEST_PIN], GPCR_PORT_PIN_MODE_INPUT, "gpcr[%d]=%x", TEST_PIN, + registers.gpcr[TEST_PIN]); + + zassert_ok(gpio_pin_get_config(gpio_dev, TEST_PIN, &flags)); + zexpect_equal(flags, GPIO_INPUT | IT8XXX2_GPIO_VOLTAGE_1P8, "flags=%x", flags); +} + +ZTEST(gpio_ite_it8xxx2_v2, test_input_3P3V) +{ + gpio_flags_t flags; + + zassert_true(device_is_ready(gpio_dev)); + zassert_ok(gpio_pin_configure(gpio_dev, TEST_PIN, GPIO_INPUT | IT8XXX2_GPIO_VOLTAGE_3P3)); + zexpect_equal(registers.gpotr, 0, "gpotr=%x", registers.gpotr); + zexpect_equal(registers.p18scr, 0); + zexpect_equal(registers.gpcr[TEST_PIN], GPCR_PORT_PIN_MODE_INPUT, "gpcr[%d]=%x", TEST_PIN, + registers.gpcr[TEST_PIN]); + + zassert_ok(gpio_pin_get_config(gpio_dev, TEST_PIN, &flags)); + zexpect_equal(flags, GPIO_INPUT | IT8XXX2_GPIO_VOLTAGE_3P3, "flags=%x", flags); +} + +ZTEST(gpio_ite_it8xxx2_v2, test_input_5V) +{ + zassert_true(device_is_ready(gpio_dev)); + zassert_equal(gpio_pin_configure(gpio_dev, TEST_PIN, GPIO_INPUT | IT8XXX2_GPIO_VOLTAGE_5P0), + -EINVAL); + zexpect_equal(registers.gpotr, 0, "gpotr=%x", registers.gpotr); + zexpect_equal(registers.p18scr, 0); + zexpect_equal(registers.gpcr[TEST_PIN], 0, "gpcr[%d]=%x", TEST_PIN, + registers.gpcr[TEST_PIN]); +} diff --git a/tests/drivers/gpio/gpio_ite_it8xxx2_v2/testcase.yaml b/tests/drivers/gpio/gpio_ite_it8xxx2_v2/testcase.yaml new file mode 100644 index 00000000000..67cc43b474b --- /dev/null +++ b/tests/drivers/gpio/gpio_ite_it8xxx2_v2/testcase.yaml @@ -0,0 +1,14 @@ +# Copyright 2023 The ChromiumOS Authors +# +# SPDX-License-Identifier: Apache-2.0 + +tests: + gpio.gpio_ite_it8xxx2_v2: + tags: + - drivers + - gpio + depends_on: gpio + platform_allow: + - native_sim + integration_platforms: + - native_sim From 5a727a382a1c79eed627c579a097075c8ee3dc8f Mon Sep 17 00:00:00 2001 From: Jeremy Bettis Date: Wed, 20 Dec 2023 23:00:35 +0000 Subject: [PATCH 1635/3723] drivers: Add level intrs in gpio_ite_it8xxx2_v2 Implement level based gpio interrupts, by using a worker queue to repeatedly call the gpio callbacks until the gpio is no longer active. Update unit test for new interrupts. Bug #66401 Signed-off-by: Jeremy Bettis --- drivers/gpio/gpio_ite_it8xxx2_v2.c | 56 +++++++++++++++++-- .../gpio/gpio_ite_it8xxx2_v2/src/main.c | 45 ++++++++++++--- 2 files changed, 89 insertions(+), 12 deletions(-) diff --git a/drivers/gpio/gpio_ite_it8xxx2_v2.c b/drivers/gpio/gpio_ite_it8xxx2_v2.c index 1b9fc172a59..a05e480f558 100644 --- a/drivers/gpio/gpio_ite_it8xxx2_v2.c +++ b/drivers/gpio/gpio_ite_it8xxx2_v2.c @@ -19,6 +19,7 @@ #include #include #include +#include #include #include #include @@ -61,6 +62,10 @@ struct gpio_ite_data { sys_slist_t callbacks; uint8_t volt_default_set; struct k_spinlock lock; + uint8_t level_isr_high; + uint8_t level_isr_low; + const struct device *instance; + struct k_work interrupt_worker; }; /** @@ -359,6 +364,30 @@ static void gpio_ite_isr(const void *arg) break; } } + /* Reschedule worker */ + k_work_submit(&data->interrupt_worker); +} + +static void gpio_ite_interrupt_worker(struct k_work *work) +{ + struct gpio_ite_data * const data = CONTAINER_OF( + work, struct gpio_ite_data, interrupt_worker); + gpio_port_value_t value; + gpio_port_value_t triggered_int; + + gpio_ite_port_get_raw(data->instance, &value); + + k_spinlock_key_t key = k_spin_lock(&data->lock); + + triggered_int = (value & data->level_isr_high) | (~value & data->level_isr_low); + k_spin_unlock(&data->lock, key); + + if (triggered_int != 0) { + gpio_fire_callbacks(&data->callbacks, data->instance, + triggered_int); + /* Reschedule worker */ + k_work_submit(&data->interrupt_worker); + } } static int gpio_ite_pin_interrupt_configure(const struct device *dev, @@ -386,11 +415,6 @@ static int gpio_ite_pin_interrupt_configure(const struct device *dev, #endif /* CONFIG_GPIO_ENABLE_DISABLE_INTERRUPT */ } - if (mode == GPIO_INT_MODE_LEVEL) { - LOG_ERR("Level trigger mode not supported"); - return -ENOTSUP; - } - /* Disable irq before configuring it */ irq_disable(gpio_irq); @@ -415,6 +439,19 @@ static int gpio_ite_pin_interrupt_configure(const struct device *dev, } else { ECREG(reg_wuemr) &= ~wuc_mask; } + + if (mode == GPIO_INT_MODE_LEVEL) { + if (trig & GPIO_INT_TRIG_LOW) { + data->level_isr_low |= BIT(pin); + data->level_isr_high &= ~BIT(pin); + } else { + data->level_isr_low &= ~BIT(pin); + data->level_isr_high |= BIT(pin); + } + } else { + data->level_isr_low &= ~BIT(pin); + data->level_isr_high &= ~BIT(pin); + } /* * Always write 1 to clear the WUC status register after * modifying edge mode selection register (WUBEMR and WUEMR). @@ -426,6 +463,7 @@ static int gpio_ite_pin_interrupt_configure(const struct device *dev, /* Enable GPIO interrupt */ irq_connect_dynamic(gpio_irq, 0, gpio_ite_isr, dev, 0); irq_enable(gpio_irq); + k_work_submit(&data->interrupt_worker); return 0; } @@ -446,6 +484,14 @@ static const struct gpio_driver_api gpio_ite_driver_api = { static int gpio_ite_init(const struct device *dev) { + struct gpio_ite_data *data = dev->data; + k_spinlock_key_t key = k_spin_lock(&data->lock); + + data->instance = dev; + k_work_init(&data->interrupt_worker, + gpio_ite_interrupt_worker); + k_spin_unlock(&data->lock, key); + return 0; } diff --git a/tests/drivers/gpio/gpio_ite_it8xxx2_v2/src/main.c b/tests/drivers/gpio/gpio_ite_it8xxx2_v2/src/main.c index 4272fbe42f9..2746bb11439 100644 --- a/tests/drivers/gpio/gpio_ite_it8xxx2_v2/src/main.c +++ b/tests/drivers/gpio/gpio_ite_it8xxx2_v2/src/main.c @@ -71,6 +71,11 @@ static void callback(const struct device *port, struct gpio_callback *cb, gpio_p { callback_called++; zexpect_equal(pins, BIT(TEST_PIN)); + + /* If the callback has been called 5 or more times, toggle the pin in the input register. */ + if (callback_called >= 5) { + registers.gpdmr ^= pins; + } } static void before_test(void *fixture) @@ -236,34 +241,60 @@ ZTEST(gpio_ite_it8xxx2_v2, test_interrupt_edge_both) zassert_equal(callback_called, 2, "callback_called=%d", callback_called); } +/* Tests both the active level case and the interrupt not firing at configure case. */ ZTEST(gpio_ite_it8xxx2_v2, test_interrupt_level_active) { zassert_true(device_is_ready(gpio_dev)); zassert_ok(gpio_pin_configure(gpio_dev, TEST_PIN, GPIO_INPUT | GPIO_ACTIVE_HIGH)); - zassert_equal(gpio_pin_interrupt_configure(gpio_dev, TEST_PIN, GPIO_INT_LEVEL_ACTIVE), - -ENOTSUP); + + gpio_init_callback(&callback_struct, &callback, BIT(TEST_PIN)); + zassert_ok(gpio_add_callback(gpio_dev, &callback_struct)); + zassert_ok(gpio_pin_interrupt_configure(gpio_dev, TEST_PIN, GPIO_INT_LEVEL_ACTIVE)); zexpect_equal(registers.gpotr, 0, "gpotr=%x", registers.gpotr); zexpect_equal(registers.p18scr, 0); zexpect_equal(registers.gpcr[TEST_PIN], GPCR_PORT_PIN_MODE_INPUT, "gpcr[%d]=%x", TEST_PIN, registers.gpcr[TEST_PIN]); zexpect_equal(registers.wubemr, 0, "wubemr=%x", registers.wubemr); zexpect_equal(registers.wuemr, 0, "wuemr=%x", registers.wuemr); - zexpect_equal(registers.wuesr, 0, "wuesr=%x", registers.wuesr); + zexpect_equal(registers.wuesr, TEST_MASK, "wuesr=%x", registers.wuesr); + registers.wuesr = 0; + k_sleep(K_MSEC(100)); + zexpect_equal(callback_called, 0, "callback_called=%d", callback_called); + + registers.gpdmr = BIT(TEST_PIN); + /* Mock the hardware interrupt. */ + posix_sw_set_pending_IRQ(TEST_IRQ); + k_sleep(K_MSEC(100)); + zexpect_equal(callback_called, 5, "callback_called=%d", callback_called); } +/* Tests both the inactive level case and the interrupt already firing at configure case. */ ZTEST(gpio_ite_it8xxx2_v2, test_interrupt_level_inactive) { zassert_true(device_is_ready(gpio_dev)); zassert_ok(gpio_pin_configure(gpio_dev, TEST_PIN, GPIO_INPUT | GPIO_ACTIVE_HIGH)); - zassert_equal(gpio_pin_interrupt_configure(gpio_dev, TEST_PIN, GPIO_INT_LEVEL_INACTIVE), - -ENOTSUP); + + gpio_init_callback(&callback_struct, &callback, BIT(TEST_PIN)); + zassert_ok(gpio_add_callback(gpio_dev, &callback_struct)); + zassert_ok(gpio_pin_interrupt_configure(gpio_dev, TEST_PIN, GPIO_INT_LEVEL_INACTIVE)); zexpect_equal(registers.gpotr, 0, "gpotr=%x", registers.gpotr); zexpect_equal(registers.p18scr, 0); zexpect_equal(registers.gpcr[TEST_PIN], GPCR_PORT_PIN_MODE_INPUT, "gpcr[%d]=%x", TEST_PIN, registers.gpcr[TEST_PIN]); zexpect_equal(registers.wubemr, 0, "wubemr=%x", registers.wubemr); - zexpect_equal(registers.wuemr, 0, "wuemr=%x", registers.wuemr); - zexpect_equal(registers.wuesr, 0, "wuesr=%x", registers.wuesr); + zexpect_equal(registers.wuemr, TEST_MASK, "wuemr=%x", registers.wuemr); + zexpect_equal(registers.wuesr, TEST_MASK, "wuesr=%x", registers.wuesr); + registers.wuesr = 0; + k_sleep(K_MSEC(100)); + /* The interrupt was already active when we started. */ + zexpect_equal(callback_called, 5, "callback_called=%d", callback_called); + + registers.gpdmr = 0; + callback_called = 0; + /* Mock the hardware interrupt. */ + posix_sw_set_pending_IRQ(TEST_IRQ); + k_sleep(K_MSEC(100)); + zexpect_equal(callback_called, 5, "callback_called=%d", callback_called); } ZTEST(gpio_ite_it8xxx2_v2, test_set_active_high) From a3e39cb0e5193f448b2c2066a2c0a649203a1b71 Mon Sep 17 00:00:00 2001 From: Fabio Baltieri Date: Fri, 22 Dec 2023 12:17:19 +0000 Subject: [PATCH 1636/3723] logging: make CONFIG_LOG_ALWAYS_RUNTIME build check less ambiguous When these fails the compiler just prints "Option must be enabled" with no reference to what option, so one has to look at the code to find out. Mention the actual option in the error to make these unambiguous. Signed-off-by: Fabio Baltieri --- subsys/logging/log_core.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/subsys/logging/log_core.c b/subsys/logging/log_core.c index de96cfe2fb3..3539556ac25 100644 --- a/subsys/logging/log_core.c +++ b/subsys/logging/log_core.c @@ -65,9 +65,11 @@ LOG_MODULE_REGISTER(log); #ifndef CONFIG_LOG_ALWAYS_RUNTIME BUILD_ASSERT(!IS_ENABLED(CONFIG_NO_OPTIMIZATIONS), - "Option must be enabled when CONFIG_NO_OPTIMIZATIONS is set"); + "CONFIG_LOG_ALWAYS_RUNTIME must be enabled when " + "CONFIG_NO_OPTIMIZATIONS is set"); BUILD_ASSERT(!IS_ENABLED(CONFIG_LOG_MODE_IMMEDIATE), - "Option must be enabled when CONFIG_LOG_MODE_IMMEDIATE is set"); + "CONFIG_LOG_ALWAYS_RUNTIME must be enabled when " + "CONFIG_LOG_MODE_IMMEDIATE is set"); #endif static const log_format_func_t format_table[] = { From 6564e8b756c95d3cc5b5e473d5b6b27d31c6cdb2 Mon Sep 17 00:00:00 2001 From: Tomi Fontanilles Date: Fri, 29 Dec 2023 11:23:38 +0200 Subject: [PATCH 1637/3723] modem: cmux: fix frame data length encoding In cases where the data is bigger than 127 bytes, the first bit of the second byte of the data length field used to always be set. This is wrong as according to the 3GPP 27.010 spec only the first bit of the first byte is the EA bit; all the others denote the data length. Signed-off-by: Tomi Fontanilles --- subsys/modem/modem_cmux.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/subsys/modem/modem_cmux.c b/subsys/modem/modem_cmux.c index 29ff41c1ca7..3ace00d6583 100644 --- a/subsys/modem/modem_cmux.c +++ b/subsys/modem/modem_cmux.c @@ -232,7 +232,7 @@ static uint16_t modem_cmux_transmit_frame(struct modem_cmux *cmux, byte = data_len << 1; fcs = crc8(&byte, 1, MODEM_CMUX_FCS_POLYNOMIAL, fcs, true); ring_buf_put(&cmux->transmit_rb, &byte, 1); - byte = 0x01 | (data_len >> 7); + byte = data_len >> 7; ring_buf_put(&cmux->transmit_rb, &byte, 1); } else { byte = 0x01 | (data_len << 1); From 04437376aa73fb5680a7decc7bbb71978bebe676 Mon Sep 17 00:00:00 2001 From: Keith Packard Date: Fri, 29 Dec 2023 12:14:05 -0800 Subject: [PATCH 1638/3723] boards/posix: Handle SDL2 compile vars with multiple values When transforming SDL2_LIBRARIES and SDL2_INCLUDE_DIRS into compile options, each member needs to be preceeded by -l or -I. Use the cmake list(TRANFORM) operation to prepend the flag to each list element instead of just prepending the flag to the entire list. Signed-off-by: Keith Packard --- boards/posix/common/sdl/CMakeLists.txt | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/boards/posix/common/sdl/CMakeLists.txt b/boards/posix/common/sdl/CMakeLists.txt index a790845afd8..0e20283324c 100644 --- a/boards/posix/common/sdl/CMakeLists.txt +++ b/boards/posix/common/sdl/CMakeLists.txt @@ -12,8 +12,10 @@ if (CONFIG_NATIVE_APPLICATION) zephyr_include_directories(${SDL2_INCLUDE_DIRS}) zephyr_compile_options(${SDL2_CFLAGS_OTHER}) else() - target_link_options(native_simulator INTERFACE "-l${SDL2_LIBRARIES}") - target_compile_options(native_simulator INTERFACE "-I${SDL2_INCLUDE_DIRS}" ${SDL2_CFLAGS_OTHER}) + list(TRANSFORM SDL2_LIBRARIES PREPEND "-l" OUTPUT_VARIABLE SDL2_LIBRARIES_OPTION) + target_link_options(native_simulator INTERFACE "${SDL2_LIBRARIES_OPTION}") + list(TRANSFORM SDL2_INCLUDE_DIRS PREPEND "-I" OUTPUT_VARIABLE SDL2_INCLUDE_DIRS_OPTION) + target_compile_options(native_simulator INTERFACE "${SDL2_INCLUDE_DIRS_OPTION}" ${SDL2_CFLAGS_OTHER}) endif() zephyr_library_sources(sdl_events.c) From 49f9d8e19c29bd5661bfb5e49c0a4c04871eb054 Mon Sep 17 00:00:00 2001 From: Jamie McCrae Date: Thu, 14 Dec 2023 09:41:03 +0000 Subject: [PATCH 1639/3723] sysbuild: kconfig: Unset shield config value variable Fixes an issue with shields that have Kconfig file fragments when being used with sysbuild, they would be loaded into sysbuild itself which would then fail because it does not have the Kconfig tree that zephyr applications have Signed-off-by: Jamie McCrae --- share/sysbuild/cmake/modules/sysbuild_kconfig.cmake | 3 +++ 1 file changed, 3 insertions(+) diff --git a/share/sysbuild/cmake/modules/sysbuild_kconfig.cmake b/share/sysbuild/cmake/modules/sysbuild_kconfig.cmake index 12ab32e55c2..23932d4494f 100644 --- a/share/sysbuild/cmake/modules/sysbuild_kconfig.cmake +++ b/share/sysbuild/cmake/modules/sysbuild_kconfig.cmake @@ -67,6 +67,9 @@ if(DEFINED BOARD_REVISION) set(BOARD_REVISION_CONFIG "${CMAKE_CURRENT_BINARY_DIR}/empty.conf") endif() +# Unset shield configuration files if set to prevent including in sysbuild +set(shield_conf_files) + list(APPEND ZEPHYR_KCONFIG_MODULES_DIR BOARD=${BOARD}) set(KCONFIG_NAMESPACE SB_CONFIG) From c6cb2d694256203800042f06ecc298b950da267c Mon Sep 17 00:00:00 2001 From: Bjarki Arge Andreasen Date: Mon, 25 Dec 2023 09:44:46 +0100 Subject: [PATCH 1640/3723] drivers: retained_mem: Add generic retained register driver Devices like the ATSAM series chips have retained registers which are used to store memory. The memory is accessed just like RAM, but since they are registers, their size and address is used directly. This commit adds a near complete copy of the generic retained ram driver and bindings file, adding the reg property to the bindings file, and updating the init macro in the driver to use the reg address and size. Signed-off-by: Bjarki Arge Andreasen --- drivers/retained_mem/CMakeLists.txt | 1 + drivers/retained_mem/Kconfig.zephyr | 7 + .../retained_mem/retained_mem_zephyr_reg.c | 135 ++++++++++++++++++ .../retained_mem/zephyr,retained-reg.yaml | 19 +++ 4 files changed, 162 insertions(+) create mode 100644 drivers/retained_mem/retained_mem_zephyr_reg.c create mode 100644 dts/bindings/retained_mem/zephyr,retained-reg.yaml diff --git a/drivers/retained_mem/CMakeLists.txt b/drivers/retained_mem/CMakeLists.txt index c119347a767..4f9322c3a89 100644 --- a/drivers/retained_mem/CMakeLists.txt +++ b/drivers/retained_mem/CMakeLists.txt @@ -6,3 +6,4 @@ zephyr_library() zephyr_library_sources_ifdef(CONFIG_USERSPACE retained_mem_handlers.c) zephyr_library_sources_ifdef(CONFIG_RETAINED_MEM_NRF_GPREGRET retained_mem_nrf_gpregret.c) zephyr_library_sources_ifdef(CONFIG_RETAINED_MEM_ZEPHYR_RAM retained_mem_zephyr_ram.c) +zephyr_library_sources_ifdef(CONFIG_RETAINED_MEM_ZEPHYR_REG retained_mem_zephyr_reg.c) diff --git a/drivers/retained_mem/Kconfig.zephyr b/drivers/retained_mem/Kconfig.zephyr index 4a4231c4968..0348efbab10 100644 --- a/drivers/retained_mem/Kconfig.zephyr +++ b/drivers/retained_mem/Kconfig.zephyr @@ -7,3 +7,10 @@ config RETAINED_MEM_ZEPHYR_RAM depends on DT_HAS_ZEPHYR_RETAINED_RAM_ENABLED help Enable driver for retained memory in RAM. + +config RETAINED_MEM_ZEPHYR_REG + bool "Generic Zephyr register retained memory driver" + default y + depends on DT_HAS_ZEPHYR_RETAINED_REG_ENABLED + help + Enable driver for retained memory in retained registers. diff --git a/drivers/retained_mem/retained_mem_zephyr_reg.c b/drivers/retained_mem/retained_mem_zephyr_reg.c new file mode 100644 index 00000000000..a302e175a6e --- /dev/null +++ b/drivers/retained_mem/retained_mem_zephyr_reg.c @@ -0,0 +1,135 @@ +/* + * Copyright (c) 2023, Nordic Semiconductor ASA + * Copyright (c) 2023, Bjarki Arge Andreasen + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#define DT_DRV_COMPAT zephyr_retained_reg + +#include +#include +#include +#include +#include +#include +#include + +LOG_MODULE_REGISTER(retained_mem_zephyr_reg, CONFIG_RETAINED_MEM_LOG_LEVEL); + +struct zephyr_retained_mem_reg_data { +#ifdef CONFIG_RETAINED_MEM_MUTEXES + struct k_mutex lock; +#endif +}; + +struct zephyr_retained_mem_reg_config { + uint8_t *address; + size_t size; +}; + +static inline void zephyr_retained_mem_reg_lock_take(const struct device *dev) +{ +#ifdef CONFIG_RETAINED_MEM_MUTEXES + struct zephyr_retained_mem_reg_data *data = dev->data; + + k_mutex_lock(&data->lock, K_FOREVER); +#else + ARG_UNUSED(dev); +#endif +} + +static inline void zephyr_retained_mem_reg_lock_release(const struct device *dev) +{ +#ifdef CONFIG_RETAINED_MEM_MUTEXES + struct zephyr_retained_mem_reg_data *data = dev->data; + + k_mutex_unlock(&data->lock); +#else + ARG_UNUSED(dev); +#endif +} + +static int zephyr_retained_mem_reg_init(const struct device *dev) +{ +#ifdef CONFIG_RETAINED_MEM_MUTEXES + struct zephyr_retained_mem_reg_data *data = dev->data; + + k_mutex_init(&data->lock); +#endif + + return 0; +} + +static ssize_t zephyr_retained_mem_reg_size(const struct device *dev) +{ + const struct zephyr_retained_mem_reg_config *config = dev->config; + + return (ssize_t)config->size; +} + +static int zephyr_retained_mem_reg_read(const struct device *dev, off_t offset, uint8_t *buffer, + size_t size) +{ + const struct zephyr_retained_mem_reg_config *config = dev->config; + + zephyr_retained_mem_reg_lock_take(dev); + + memcpy(buffer, (config->address + offset), size); + + zephyr_retained_mem_reg_lock_release(dev); + + return 0; +} + +static int zephyr_retained_mem_reg_write(const struct device *dev, off_t offset, + const uint8_t *buffer, size_t size) +{ + const struct zephyr_retained_mem_reg_config *config = dev->config; + + zephyr_retained_mem_reg_lock_take(dev); + + memcpy((config->address + offset), buffer, size); + + zephyr_retained_mem_reg_lock_release(dev); + + return 0; +} + +static int zephyr_retained_mem_reg_clear(const struct device *dev) +{ + const struct zephyr_retained_mem_reg_config *config = dev->config; + + zephyr_retained_mem_reg_lock_take(dev); + + memset(config->address, 0, config->size); + + zephyr_retained_mem_reg_lock_release(dev); + + return 0; +} + +static const struct retained_mem_driver_api zephyr_retained_mem_reg_api = { + .size = zephyr_retained_mem_reg_size, + .read = zephyr_retained_mem_reg_read, + .write = zephyr_retained_mem_reg_write, + .clear = zephyr_retained_mem_reg_clear, +}; + +#define ZEPHYR_RETAINED_MEM_REG_DEVICE(inst) \ + static struct zephyr_retained_mem_reg_data zephyr_retained_mem_reg_data_##inst; \ + static const struct zephyr_retained_mem_reg_config \ + zephyr_retained_mem_reg_config_##inst = { \ + .address = (uint8_t *)DT_INST_REG_ADDR(inst), \ + .size = DT_INST_REG_SIZE(inst), \ + }; \ + DEVICE_DT_INST_DEFINE(inst, \ + &zephyr_retained_mem_reg_init, \ + NULL, \ + &zephyr_retained_mem_reg_data_##inst, \ + &zephyr_retained_mem_reg_config_##inst, \ + POST_KERNEL, \ + CONFIG_RETAINED_MEM_INIT_PRIORITY, \ + &zephyr_retained_mem_reg_api); + +DT_INST_FOREACH_STATUS_OKAY(ZEPHYR_RETAINED_MEM_REG_DEVICE) diff --git a/dts/bindings/retained_mem/zephyr,retained-reg.yaml b/dts/bindings/retained_mem/zephyr,retained-reg.yaml new file mode 100644 index 00000000000..12c9a530390 --- /dev/null +++ b/dts/bindings/retained_mem/zephyr,retained-reg.yaml @@ -0,0 +1,19 @@ +# Copyright (c) 2023 Nordic Semiconductor ASA +# Copyright (c) 2023 Bjarki Arge Andreasen +# SPDX-License-Identifier: Apache-2.0 + +description: Retained register based retained memory area. + +compatible: "zephyr,retained-reg" + +include: base.yaml + +properties: + "#address-cells": + const: 1 + + "#size-cells": + const: 1 + + reg: + required: true From e90d69f97986fcf9c070495ddedca6571f292959 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Krzysztof=20Chru=C5=9Bci=C5=84ski?= Date: Wed, 13 Dec 2023 17:03:58 +0100 Subject: [PATCH 1641/3723] scripts: checkpatch.pl: Add exceptions for FOR_EACH_NONEMPTY_TERM macro MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Add exception for macro which is not terminated with semicolon. Signed-off-by: Krzysztof Chruściński --- scripts/checkpatch.pl | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/scripts/checkpatch.pl b/scripts/checkpatch.pl index fd82a880c1f..110eed8ec56 100755 --- a/scripts/checkpatch.pl +++ b/scripts/checkpatch.pl @@ -3739,7 +3739,7 @@ sub process { # if/while/etc brace do not go on next line, unless defining a do while loop, # or if that brace on the next line is for something else - if ($line =~ /(.*)\b((?:if|while|for|switch|(?:[A-Z_]+|)FOR_EACH[A-Z_]+)\s*\(|do\b|else\b)/ && $line !~ /^.\s*\#/) { + if ($line =~ /(.*)\b((?:if|while|for|switch|(?:[A-Z_]+|)FOR_EACH(?!_NONEMPTY_TERM)[A-Z_]+)\s*\(|do\b|else\b)/ && $line !~ /^.\s*\#/) { my $pre_ctx = "$1$2"; my ($level, @ctx) = ctx_statement_level($linenr, $realcnt, 0); @@ -3785,7 +3785,7 @@ sub process { } # Check relative indent for conditionals and blocks. - if ($line =~ /\b(?:(?:if|while|for|(?:[A-Z_]+|)FOR_EACH[A-Z_]+)\s*\(|(?:do|else)\b)/ && $line !~ /^.\s*#/ && $line !~ /\}\s*while\s*/) { + if ($line =~ /\b(?:(?:if|while|for|(?:[A-Z_]+|)FOR_EACH(?!_NONEMPTY_TERM|_IDX|_FIXED_ARG|_IDX_FIXED_ARG)[A-Z_]+)\s*\(|(?:do|else)\b)/ && $line !~ /^.\s*#/ && $line !~ /\}\s*while\s*/) { ($stat, $cond, $line_nr_next, $remain_next, $off_next) = ctx_statement_block($linenr, $realcnt, 0) if (!defined $stat); From 7b872d11ba283c7c86eebb9083f07756e7673509 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Krzysztof=20Chru=C5=9Bci=C5=84ski?= Date: Tue, 21 Nov 2023 12:14:06 +0100 Subject: [PATCH 1642/3723] tests: unit: util: Rework test structure for C++ testing MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Rework test structure to handle C++ test in a better way. Similar approach already applied in other tests which are executed for C and C++. Getting rid of test.inc which due to non-standard extension was not covered by complience check. Signed-off-by: Krzysztof Chruściński --- tests/unit/util/CMakeLists.txt | 7 +- tests/unit/util/main.c | 718 +++++++++++++++++++++++---------- tests/unit/util/maincxx.cxx | 11 - tests/unit/util/test.inc | 652 ------------------------------ tests/unit/util/testcase.yaml | 11 +- 5 files changed, 526 insertions(+), 873 deletions(-) delete mode 100644 tests/unit/util/maincxx.cxx delete mode 100644 tests/unit/util/test.inc diff --git a/tests/unit/util/CMakeLists.txt b/tests/unit/util/CMakeLists.txt index a78fab2bfd5..a8f1f4e76db 100644 --- a/tests/unit/util/CMakeLists.txt +++ b/tests/unit/util/CMakeLists.txt @@ -4,4 +4,9 @@ cmake_minimum_required(VERSION 3.20.0) project(util) find_package(Zephyr COMPONENTS unittest REQUIRED HINTS $ENV{ZEPHYR_BASE}) -target_sources(testbinary PRIVATE main.c maincxx.cxx ${ZEPHYR_BASE}/lib/utils/dec.c) +target_sources(testbinary PRIVATE main.c ${ZEPHYR_BASE}/lib/utils/dec.c) + +if(CONFIG_CPP) + # When testing for C++ force test file C++ compilation + set_source_files_properties(main.c ${ZEPHYR_BASE}/lib/utils/dec.c PROPERTIES LANGUAGE CXX) +endif() diff --git a/tests/unit/util/main.c b/tests/unit/util/main.c index 3c93968db46..d5698fc85f5 100644 --- a/tests/unit/util/main.c +++ b/tests/unit/util/main.c @@ -8,308 +8,614 @@ #include #include -#include "test.inc" +ZTEST(util, test_u8_to_dec) { + char text[4]; + uint8_t len; + + len = u8_to_dec(text, sizeof(text), 0); + zassert_equal(len, 1, "Length of 0 is not 1"); + zassert_equal(strcmp(text, "0"), 0, + "Value=0 is not converted to \"0\""); + + len = u8_to_dec(text, sizeof(text), 1); + zassert_equal(len, 1, "Length of 1 is not 1"); + zassert_equal(strcmp(text, "1"), 0, + "Value=1 is not converted to \"1\""); + + len = u8_to_dec(text, sizeof(text), 11); + zassert_equal(len, 2, "Length of 11 is not 2"); + zassert_equal(strcmp(text, "11"), 0, + "Value=10 is not converted to \"11\""); + + len = u8_to_dec(text, sizeof(text), 100); + zassert_equal(len, 3, "Length of 100 is not 3"); + zassert_equal(strcmp(text, "100"), 0, + "Value=100 is not converted to \"100\""); + + len = u8_to_dec(text, sizeof(text), 101); + zassert_equal(len, 3, "Length of 101 is not 3"); + zassert_equal(strcmp(text, "101"), 0, + "Value=101 is not converted to \"101\""); + + len = u8_to_dec(text, sizeof(text), 255); + zassert_equal(len, 3, "Length of 255 is not 3"); + zassert_equal(strcmp(text, "255"), 0, + "Value=255 is not converted to \"255\""); + + memset(text, 0, sizeof(text)); + len = u8_to_dec(text, 2, 123); + zassert_equal(len, 2, + "Length of converted value using 2 byte buffer isn't 2"); + zassert_equal( + strcmp(text, "12"), 0, + "Value=123 is not converted to \"12\" using 2-byte buffer"); + + memset(text, 0, sizeof(text)); + len = u8_to_dec(text, 1, 123); + zassert_equal(len, 1, + "Length of converted value using 1 byte buffer isn't 1"); + zassert_equal( + strcmp(text, "1"), 0, + "Value=123 is not converted to \"1\" using 1-byte buffer"); + + memset(text, 0, sizeof(text)); + len = u8_to_dec(text, 0, 123); + zassert_equal(len, 0, + "Length of converted value using 0 byte buffer isn't 0"); +} + +ZTEST(util, test_COND_CODE_1) { + #define TEST_DEFINE_1 1 + #define TEST_DEFINE_0 0 + /* Test validates that expected code has been injected. Failure would + * be seen in compilation (lack of variable or ununsed variable. + */ + COND_CODE_1(1, (uint32_t x0 = 1;), (uint32_t y0;)) + zassert_true((x0 == 1)); + + COND_CODE_1(NOT_EXISTING_DEFINE, (uint32_t x1 = 1;), (uint32_t y1 = 1;)) + zassert_true((y1 == 1)); + + COND_CODE_1(TEST_DEFINE_1, (uint32_t x2 = 1;), (uint32_t y2 = 1;)) + zassert_true((x2 == 1)); + + COND_CODE_1(2, (uint32_t x3 = 1;), (uint32_t y3 = 1;)) + zassert_true((y3 == 1)); +} + +ZTEST(util, test_COND_CODE_0) { + /* Test validates that expected code has been injected. Failure would + * be seen in compilation (lack of variable or ununsed variable. + */ + COND_CODE_0(0, (uint32_t x0 = 1;), (uint32_t y0;)) + zassert_true((x0 == 1)); + + COND_CODE_0(NOT_EXISTING_DEFINE, (uint32_t x1 = 1;), (uint32_t y1 = 1;)) + zassert_true((y1 == 1)); + + COND_CODE_0(TEST_DEFINE_0, (uint32_t x2 = 1;), (uint32_t y2 = 1;)) + zassert_true((x2 == 1)); + + COND_CODE_0(2, (uint32_t x3 = 1;), (uint32_t y3 = 1;)) + zassert_true((y3 == 1)); +} + +#undef ZERO +#undef SEVEN +#undef A_BUILD_ERROR +#define ZERO 0 +#define SEVEN 7 +#define A_BUILD_ERROR (this would be a build error if you used || or &&) +ZTEST(util, test_UTIL_OR) { + zassert_equal(UTIL_OR(SEVEN, A_BUILD_ERROR), 7); + zassert_equal(UTIL_OR(7, 0), 7); + zassert_equal(UTIL_OR(SEVEN, ZERO), 7); + zassert_equal(UTIL_OR(0, 7), 7); + zassert_equal(UTIL_OR(ZERO, SEVEN), 7); + zassert_equal(UTIL_OR(0, 0), 0); + zassert_equal(UTIL_OR(ZERO, ZERO), 0); +} + +ZTEST(util, test_UTIL_AND) { + zassert_equal(UTIL_AND(ZERO, A_BUILD_ERROR), 0); + zassert_equal(UTIL_AND(7, 0), 0); + zassert_equal(UTIL_AND(SEVEN, ZERO), 0); + zassert_equal(UTIL_AND(0, 7), 0); + zassert_equal(UTIL_AND(ZERO, SEVEN), 0); + zassert_equal(UTIL_AND(0, 0), 0); + zassert_equal(UTIL_AND(ZERO, ZERO), 0); + zassert_equal(UTIL_AND(7, 7), 7); + zassert_equal(UTIL_AND(7, SEVEN), 7); + zassert_equal(UTIL_AND(SEVEN, 7), 7); + zassert_equal(UTIL_AND(SEVEN, SEVEN), 7); +} + +ZTEST(util, test_IF_ENABLED) { + #define test_IF_ENABLED_FLAG_A 1 + #define test_IF_ENABLED_FLAG_B 0 + + IF_ENABLED(test_IF_ENABLED_FLAG_A, (goto skipped;)) + /* location should be skipped if IF_ENABLED macro is correct. */ + zassert_false(true, "location should be skipped"); +skipped: + IF_ENABLED(test_IF_ENABLED_FLAG_B, (zassert_false(true, "");)) -#if __cplusplus -extern "C" { -#endif + IF_ENABLED(test_IF_ENABLED_FLAG_C, (zassert_false(true, "");)) -ZTEST(util_cxx, test_u8_to_dec) { - run_u8_to_dec(); -} + zassert_true(true, ""); -ZTEST(util_cxx, test_COND_CODE_1) { - run_COND_CODE_1(); + #undef test_IF_ENABLED_FLAG_A + #undef test_IF_ENABLED_FLAG_B } -ZTEST(util_cxx, test_COND_CODE_0) { - run_COND_CODE_0(); -} +ZTEST(util, test_LISTIFY) { + int ab0 = 1; + int ab1 = 1; +#define A_PTR(x, name0, name1) &UTIL_CAT(UTIL_CAT(name0, name1), x) -ZTEST(util_cxx, test_UTIL_OR) { - run_UTIL_OR(); -} + int *a[] = { LISTIFY(2, A_PTR, (,), a, b) }; -ZTEST(util_cxx, test_UTIL_AND) { - run_UTIL_AND(); + zassert_equal(ARRAY_SIZE(a), 2); + zassert_equal(a[0], &ab0); + zassert_equal(a[1], &ab1); } -ZTEST(util_cxx, test_IF_ENABLED) { - run_IF_ENABLED(); -} +ZTEST(util, test_MACRO_MAP_CAT) { + int item_a_item_b_item_c_ = 1; -ZTEST(util_cxx, test_IF_DISABLED) { - run_IF_DISABLED(); +#undef FOO +#define FOO(x) item_##x##_ + zassert_equal(MACRO_MAP_CAT(FOO, a, b, c), 1, "MACRO_MAP_CAT"); +#undef FOO } -ZTEST(util_cxx, test_LISTIFY) { - run_LISTIFY(); -} +static int inc_func(bool cleanup) +{ + static int a; -ZTEST(util_cxx, test_MACRO_MAP_CAT) { - run_MACRO_MAP_CAT(); -} + if (cleanup) { + a = 1; + } -ZTEST(util_cxx, test_z_max_z_min_z_clamp) { - run_z_max_z_min_z_clamp(); + return a++; } -ZTEST(util_cxx, test_CLAMP) { - run_CLAMP(); +/* Test checks if @ref Z_MAX, @ref Z_MIN and @ref Z_CLAMP return correct result + * and perform single evaluation of input arguments. + */ +ZTEST(util, test_z_max_z_min_z_clamp) { + zassert_equal(Z_MAX(inc_func(true), 0), 1, "Unexpected macro result"); + /* Z_MAX should have call inc_func only once */ + zassert_equal(inc_func(false), 2, "Unexpected return value"); + + zassert_equal(Z_MIN(inc_func(false), 2), 2, "Unexpected macro result"); + /* Z_MIN should have call inc_func only once */ + zassert_equal(inc_func(false), 4, "Unexpected return value"); + + zassert_equal(Z_CLAMP(inc_func(false), 1, 3), 3, "Unexpected macro result"); + /* Z_CLAMP should have call inc_func only once */ + zassert_equal(inc_func(false), 6, "Unexpected return value"); + + zassert_equal(Z_CLAMP(inc_func(false), 10, 15), 10, + "Unexpected macro result"); + /* Z_CLAMP should have call inc_func only once */ + zassert_equal(inc_func(false), 8, "Unexpected return value"); +} + +ZTEST(util, test_CLAMP) { + zassert_equal(CLAMP(5, 3, 7), 5, "Unexpected clamp result"); + zassert_equal(CLAMP(3, 3, 7), 3, "Unexpected clamp result"); + zassert_equal(CLAMP(7, 3, 7), 7, "Unexpected clamp result"); + zassert_equal(CLAMP(1, 3, 7), 3, "Unexpected clamp result"); + zassert_equal(CLAMP(8, 3, 7), 7, "Unexpected clamp result"); + + zassert_equal(CLAMP(-5, -7, -3), -5, "Unexpected clamp result"); + zassert_equal(CLAMP(-9, -7, -3), -7, "Unexpected clamp result"); + zassert_equal(CLAMP(1, -7, -3), -3, "Unexpected clamp result"); + + zassert_equal(CLAMP(0xffffffffaULL, 0xffffffff0ULL, 0xfffffffffULL), + 0xffffffffaULL, "Unexpected clamp result"); +} + +ZTEST(util, test_IN_RANGE) { + zassert_true(IN_RANGE(0, 0, 0), "Unexpected IN_RANGE result"); + zassert_true(IN_RANGE(1, 0, 1), "Unexpected IN_RANGE result"); + zassert_true(IN_RANGE(1, 0, 2), "Unexpected IN_RANGE result"); + zassert_true(IN_RANGE(-1, -2, 2), "Unexpected IN_RANGE result"); + zassert_true(IN_RANGE(-3, -5, -1), "Unexpected IN_RANGE result"); + zassert_true(IN_RANGE(0, 0, UINT64_MAX), "Unexpected IN_RANGE result"); + zassert_true(IN_RANGE(UINT64_MAX, 0, UINT64_MAX), "Unexpected IN_RANGE result"); + zassert_true(IN_RANGE(0, INT64_MIN, INT64_MAX), "Unexpected IN_RANGE result"); + zassert_true(IN_RANGE(INT64_MIN, INT64_MIN, INT64_MAX), "Unexpected IN_RANGE result"); + zassert_true(IN_RANGE(INT64_MAX, INT64_MIN, INT64_MAX), "Unexpected IN_RANGE result"); + + zassert_false(IN_RANGE(5, 0, 2), "Unexpected IN_RANGE result"); + zassert_false(IN_RANGE(5, 10, 0), "Unexpected IN_RANGE result"); + zassert_false(IN_RANGE(-1, 0, 1), "Unexpected IN_RANGE result"); +} + +ZTEST(util, test_FOR_EACH) { + #define FOR_EACH_MACRO_TEST(arg) *buf++ = arg + + uint8_t array[3] = {0}; + uint8_t *buf = array; + + FOR_EACH(FOR_EACH_MACRO_TEST, (;), 1, 2, 3); + + zassert_equal(array[0], 1, "Unexpected value %d", array[0]); + zassert_equal(array[1], 2, "Unexpected value %d", array[1]); + zassert_equal(array[2], 3, "Unexpected value %d", array[2]); +} + +ZTEST(util, test_FOR_EACH_NONEMPTY_TERM) { + #define SQUARE(arg) (arg * arg) + #define SWALLOW_VA_ARGS_1(...) EMPTY + #define SWALLOW_VA_ARGS_2(...) + #define REPEAT_VA_ARGS(...) __VA_ARGS__ + + uint8_t array[] = { + FOR_EACH_NONEMPTY_TERM(SQUARE, (,)) + FOR_EACH_NONEMPTY_TERM(SQUARE, (,),) + FOR_EACH_NONEMPTY_TERM(SQUARE, (,), ,) + FOR_EACH_NONEMPTY_TERM(SQUARE, (,), EMPTY, EMPTY) + FOR_EACH_NONEMPTY_TERM(SQUARE, (,), SWALLOW_VA_ARGS_1(a, b)) + FOR_EACH_NONEMPTY_TERM(SQUARE, (,), SWALLOW_VA_ARGS_2(c, d)) + FOR_EACH_NONEMPTY_TERM(SQUARE, (,), 1) + FOR_EACH_NONEMPTY_TERM(SQUARE, (,), 2, 3) + FOR_EACH_NONEMPTY_TERM(SQUARE, (,), REPEAT_VA_ARGS(4)) + FOR_EACH_NONEMPTY_TERM(SQUARE, (,), REPEAT_VA_ARGS(5, 6)) + 255 + }; + + size_t size = ARRAY_SIZE(array); + + zassert_equal(size, 7, "Unexpected size %d", size); + zassert_equal(array[0], 1, "Unexpected value %d", array[0]); + zassert_equal(array[1], 4, "Unexpected value %d", array[1]); + zassert_equal(array[2], 9, "Unexpected value %d", array[2]); + zassert_equal(array[3], 16, "Unexpected value %d", array[3]); + zassert_equal(array[4], 25, "Unexpected value %d", array[4]); + zassert_equal(array[5], 36, "Unexpected value %d", array[5]); + zassert_equal(array[6], 255, "Unexpected value %d", array[6]); +} + +static void fsum(uint32_t incr, uint32_t *sum) +{ + *sum = *sum + incr; } -ZTEST(util_cxx, test_IN_RANGE) { - run_IN_RANGE(); -} +ZTEST(util, test_FOR_EACH_FIXED_ARG) { + uint32_t sum = 0; -ZTEST(util_cxx, test_FOR_EACH) { - run_FOR_EACH(); -} + FOR_EACH_FIXED_ARG(fsum, (;), &sum, 1, 2, 3); -ZTEST(util_cxx, test_FOR_EACH_NONEMPTY_TERM) { - run_FOR_EACH_NONEMPTY_TERM(); + zassert_equal(sum, 6, "Unexpected value %d", sum); } -ZTEST(util_cxx, test_FOR_EACH_FIXED_ARG) { - run_FOR_EACH_FIXED_ARG(); -} +ZTEST(util, test_FOR_EACH_IDX) { + #define FOR_EACH_IDX_MACRO_TEST(n, arg) uint8_t a##n = arg -ZTEST(util_cxx, test_FOR_EACH_IDX) { - run_FOR_EACH_IDX(); -} + FOR_EACH_IDX(FOR_EACH_IDX_MACRO_TEST, (;), 1, 2, 3); -ZTEST(util_cxx, test_FOR_EACH_IDX_FIXED_ARG) { - run_FOR_EACH_IDX_FIXED_ARG(); -} + zassert_equal(a0, 1, "Unexpected value %d", a0); + zassert_equal(a1, 2, "Unexpected value %d", a1); + zassert_equal(a2, 3, "Unexpected value %d", a2); -ZTEST(util_cxx, test_IS_EMPTY) { - run_IS_EMPTY(); -} + #define FOR_EACH_IDX_MACRO_TEST2(n, arg) array[n] = arg + uint8_t array[32] = {0}; -ZTEST(util_cxx, test_IS_EQ) { - run_IS_EQ(); -} + FOR_EACH_IDX(FOR_EACH_IDX_MACRO_TEST2, (;), 1, 2, 3, 4, 5, 6, 7, 8, + 9, 10, 11, 12, 13, 14, 15); + for (int i = 0; i < 15; i++) { + zassert_equal(array[i], i + 1, + "Unexpected value: %d", array[i]); + } + zassert_equal(array[15], 0, "Unexpected value: %d", array[15]); -ZTEST(util_cxx, test_LIST_DROP_EMPTY) { - run_LIST_DROP_EMPTY(); -} + #define FOR_EACH_IDX_MACRO_TEST3(n, arg) &a##n -ZTEST(util_cxx, test_nested_FOR_EACH) { - run_nested_FOR_EACH(); -} + uint8_t *a[] = { + FOR_EACH_IDX(FOR_EACH_IDX_MACRO_TEST3, (,), 1, 2, 3) + }; -ZTEST(util_cxx, test_GET_ARG_N) { - run_GET_ARG_N(); + zassert_equal(ARRAY_SIZE(a), 3, "Unexpected value:%zu", ARRAY_SIZE(a)); } -ZTEST(util_cxx, test_GET_ARGS_LESS_N) { - run_GET_ARGS_LESS_N(); -} +ZTEST(util, test_FOR_EACH_IDX_FIXED_ARG) { + #undef FOO + #define FOO(n, arg, fixed_arg) \ + uint8_t fixed_arg##n = arg -ZTEST(util_cxx, test_mixing_GET_ARG_and_FOR_EACH) { - run_mixing_GET_ARG_and_FOR_EACH(); -} + FOR_EACH_IDX_FIXED_ARG(FOO, (;), a, 1, 2, 3); -ZTEST(util_cxx, test_IS_ARRAY_ELEMENT) -{ - run_IS_ARRAY_ELEMENT(); + zassert_equal(a0, 1, "Unexpected value %d", a0); + zassert_equal(a1, 2, "Unexpected value %d", a1); + zassert_equal(a2, 3, "Unexpected value %d", a2); } -ZTEST(util_cxx, test_ARRAY_INDEX) -{ - run_ARRAY_INDEX(); +ZTEST(util, test_IS_EMPTY) { + #define test_IS_EMPTY_REAL_EMPTY + #define test_IS_EMPTY_NOT_EMPTY XXX_DO_NOT_REPLACE_XXX + zassert_true(IS_EMPTY(test_IS_EMPTY_REAL_EMPTY), + "Expected to be empty"); + zassert_false(IS_EMPTY(test_IS_EMPTY_NOT_EMPTY), + "Expected to be non-empty"); + zassert_false(IS_EMPTY("string"), + "Expected to be non-empty"); + zassert_false(IS_EMPTY(&test_IS_EMPTY), + "Expected to be non-empty"); } -ZTEST(util_cxx, test_PART_OF_ARRAY) -{ - run_PART_OF_ARRAY(); -} +ZTEST(util, test_IS_EQ) { + zassert_true(IS_EQ(0, 0), "Unexpected IS_EQ result"); + zassert_true(IS_EQ(1, 1), "Unexpected IS_EQ result"); + zassert_true(IS_EQ(7, 7), "Unexpected IS_EQ result"); -ZTEST(util_cxx, test_ARRAY_INDEX_FLOOR) -{ - run_ARRAY_INDEX_FLOOR(); -} - -ZTEST(util_cxx, test_BIT_MASK) -{ - run_BIT_MASK(); + zassert_false(IS_EQ(0, 1), "Unexpected IS_EQ result"); + zassert_false(IS_EQ(1, 7), "Unexpected IS_EQ result"); + zassert_false(IS_EQ(7, 0), "Unexpected IS_EQ result"); } -ZTEST(util_cxx, test_BIT_MASK64) -{ - run_BIT_MASK64(); -} +ZTEST(util, test_LIST_DROP_EMPTY) { + /* + * The real definition should be: + * #define TEST_BROKEN_LIST ,Henry,,Dorsett,Case, + * but checkpatch complains, so below equivalent is defined. + */ + #define TEST_BROKEN_LIST EMPTY, Henry, EMPTY, Dorsett, Case, + #define TEST_FIXED_LIST LIST_DROP_EMPTY(TEST_BROKEN_LIST) + static const char *const arr[] = { + FOR_EACH(STRINGIFY, (,), TEST_FIXED_LIST) + }; -ZTEST(util_cxx, test_IS_BIT_MASK) -{ - run_IS_BIT_MASK(); + zassert_equal(ARRAY_SIZE(arr), 3, "Failed to cleanup list"); + zassert_equal(strcmp(arr[0], "Henry"), 0, "Failed at 0"); + zassert_equal(strcmp(arr[1], "Dorsett"), 0, "Failed at 1"); + zassert_equal(strcmp(arr[2], "Case"), 0, "Failed at 0"); } -ZTEST(util_cxx, test_IS_SHIFTED_BIT_MASK) -{ - run_IS_SHIFTED_BIT_MASK(); -} +ZTEST(util, test_nested_FOR_EACH) { + #define FOO_1(x) a##x = x + #define FOO_2(x) int x -ZTEST(util_cxx, test_DIV_ROUND_UP) -{ - run_DIV_ROUND_UP(); -} + FOR_EACH(FOO_2, (;), FOR_EACH(FOO_1, (,), 0, 1, 2)); -ZTEST(util_cxx, test_DIV_ROUND_CLOSEST) -{ - run_DIV_ROUND_CLOSEST(); + zassert_equal(a0, 0); + zassert_equal(a1, 1); + zassert_equal(a2, 2); } -ZTEST_SUITE(util_cxx, NULL, NULL, NULL, NULL, NULL); +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); -#if __cplusplus + zassert_equal(a, 10); + zassert_equal(b, 100); + zassert_equal(c, 1000); } -#endif -ZTEST(util_cc, test_u8_to_dec) { - run_u8_to_dec(); -} +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) }; -ZTEST(util_cc, test_COND_CODE_1) { - run_COND_CODE_1(); -} + zassert_equal(sizeof(a), 3); -ZTEST(util_cc, test_COND_CODE_0) { - run_COND_CODE_0(); -} + zassert_equal(sizeof(b), 2); + zassert_equal(b[0], 2); + zassert_equal(b[1], 3); -ZTEST(util_cc, test_UTIL_OR) { - run_UTIL_OR(); + zassert_equal(sizeof(c), 1); + zassert_equal(c[0], 3); } -ZTEST(util_cc, test_UTIL_AND) { - run_UTIL_AND(); -} +ZTEST(util, test_mixing_GET_ARG_and_FOR_EACH) { + #undef TEST_MACRO + #define TEST_MACRO(x) x, + int i; -ZTEST(util_cc, test_IF_ENABLED) { - run_IF_ENABLED(); -} + i = GET_ARG_N(3, FOR_EACH(TEST_MACRO, (), 1, 2, 3, 4, 5)); + zassert_equal(i, 3); -ZTEST(util_cc, test_IF_DISABLED) { - run_IF_DISABLED(); -} + i = GET_ARG_N(2, 1, GET_ARGS_LESS_N(2, 1, 2, 3, 4, 5)); + zassert_equal(i, 3); -ZTEST(util_cc, test_LISTIFY) { - run_LISTIFY(); -} + #undef TEST_MACRO + #undef TEST_MACRO2 + #define TEST_MACRO(x) GET_ARG_N(3, 1, 2, x), + #define TEST_MACRO2(...) FOR_EACH(TEST_MACRO, (), __VA_ARGS__) + int a[] = { + LIST_DROP_EMPTY(TEST_MACRO2(1, 2, 3, 4)), 5 + }; -ZTEST(util_cc, test_MACRO_MAP_CAT) { - run_MACRO_MAP_CAT(); + zassert_equal(ARRAY_SIZE(a), 5); + zassert_equal(a[0], 1); + zassert_equal(a[1], 2); + zassert_equal(a[2], 3); + zassert_equal(a[3], 4); + zassert_equal(a[4], 5); } -ZTEST(util_cc, test_z_max_z_min_z_clamp) { - run_z_max_z_min_z_clamp(); -} +ZTEST(util, test_IS_ARRAY_ELEMENT) +{ + size_t i; + size_t array[3]; + uint8_t *const alias = (uint8_t *)array; -ZTEST(util_cc, test_CLAMP) { - run_CLAMP(); -} + zassert_false(IS_ARRAY_ELEMENT(array, &array[-1])); + zassert_false(IS_ARRAY_ELEMENT(array, &array[ARRAY_SIZE(array)])); + zassert_false(IS_ARRAY_ELEMENT(array, &alias[1])); -ZTEST(util_cc, test_IN_RANGE) { - run_IN_RANGE(); + for (i = 0; i < ARRAY_SIZE(array); ++i) { + zassert_true(IS_ARRAY_ELEMENT(array, &array[i])); + } } -ZTEST(util_cc, test_FOR_EACH) { - run_FOR_EACH(); -} +ZTEST(util, test_ARRAY_INDEX) +{ + size_t i; + size_t array[] = {0, 1, 2, 3}; -ZTEST(util_cc, test_FOR_EACH_NONEMPTY_TERM) { - run_FOR_EACH_NONEMPTY_TERM(); + for (i = 0; i < ARRAY_SIZE(array); ++i) { + zassert_equal(array[ARRAY_INDEX(array, &array[i])], i); + } } -ZTEST(util_cc, test_FOR_EACH_FIXED_ARG) { - run_FOR_EACH_FIXED_ARG(); -} +ZTEST(util, test_PART_OF_ARRAY) +{ + size_t i; + size_t array[3]; + uint8_t *const alias = (uint8_t *)array; -ZTEST(util_cc, test_FOR_EACH_IDX) { - run_FOR_EACH_IDX(); -} + ARG_UNUSED(i); + ARG_UNUSED(alias); -ZTEST(util_cc, test_FOR_EACH_IDX_FIXED_ARG) { - run_FOR_EACH_IDX_FIXED_ARG(); -} + zassert_false(PART_OF_ARRAY(array, &array[-1])); + zassert_false(PART_OF_ARRAY(array, &array[ARRAY_SIZE(array)])); -ZTEST(util_cc, test_IS_EMPTY) { - run_IS_EMPTY(); -} + for (i = 0; i < ARRAY_SIZE(array); ++i) { + zassert_true(PART_OF_ARRAY(array, &array[i])); + } -ZTEST(util_cc, test_IS_EQ) { - run_IS_EQ(); + zassert_true(PART_OF_ARRAY(array, &alias[1])); } -ZTEST(util_cc, test_LIST_DROP_EMPTY) { - run_LIST_DROP_EMPTY(); -} +ZTEST(util, test_ARRAY_INDEX_FLOOR) +{ + size_t i; + size_t array[] = {0, 1, 2, 3}; + uint8_t *const alias = (uint8_t *)array; -ZTEST(util_cc, test_nested_FOR_EACH) { - run_nested_FOR_EACH(); -} + for (i = 0; i < ARRAY_SIZE(array); ++i) { + zassert_equal(array[ARRAY_INDEX_FLOOR(array, &array[i])], i); + } -ZTEST(util_cc, test_GET_ARG_N) { - run_GET_ARG_N(); + zassert_equal(array[ARRAY_INDEX_FLOOR(array, &alias[1])], 0); } -ZTEST(util_cc, test_GET_ARGS_LESS_N) { - run_GET_ARGS_LESS_N(); -} +ZTEST(util, test_BIT_MASK) +{ + uint32_t bitmask0 = BIT_MASK(0); + uint32_t bitmask1 = BIT_MASK(1); + uint32_t bitmask2 = BIT_MASK(2); + uint32_t bitmask31 = BIT_MASK(31); -ZTEST(util_cc, test_mixing_GET_ARG_and_FOR_EACH) { - run_mixing_GET_ARG_and_FOR_EACH(); + zassert_equal(0x00000000UL, bitmask0); + zassert_equal(0x00000001UL, bitmask1); + zassert_equal(0x00000003UL, bitmask2); + zassert_equal(0x7ffffffFUL, bitmask31); } -ZTEST(util_cc, test_IS_ARRAY_ELEMENT) +ZTEST(util, test_BIT_MASK64) { - run_IS_ARRAY_ELEMENT(); -} + uint64_t bitmask0 = BIT64_MASK(0); + uint64_t bitmask1 = BIT64_MASK(1); + uint64_t bitmask2 = BIT64_MASK(2); + uint64_t bitmask63 = BIT64_MASK(63); -ZTEST(util_cc, test_ARRAY_INDEX) -{ - run_ARRAY_INDEX(); + zassert_equal(0x0000000000000000ULL, bitmask0); + zassert_equal(0x0000000000000001ULL, bitmask1); + zassert_equal(0x0000000000000003ULL, bitmask2); + zassert_equal(0x7fffffffffffffffULL, bitmask63); } -ZTEST(util_cc, test_PART_OF_ARRAY) +ZTEST(util, test_IS_BIT_MASK) { - run_PART_OF_ARRAY(); -} - -ZTEST(util_cc, test_ARRAY_INDEX_FLOOR) + uint32_t zero32 = 0UL; + uint64_t zero64 = 0ULL; + uint32_t bitmask1 = 0x00000001UL; + uint32_t bitmask2 = 0x00000003UL; + uint32_t bitmask31 = 0x7fffffffUL; + uint32_t bitmask32 = 0xffffffffUL; + uint64_t bitmask63 = 0x7fffffffffffffffULL; + uint64_t bitmask64 = 0xffffffffffffffffULL; + + uint32_t not_bitmask32 = 0xfffffffeUL; + uint64_t not_bitmask64 = 0xfffffffffffffffeULL; + + zassert_true(IS_BIT_MASK(zero32)); + zassert_true(IS_BIT_MASK(zero64)); + zassert_true(IS_BIT_MASK(bitmask1)); + zassert_true(IS_BIT_MASK(bitmask2)); + zassert_true(IS_BIT_MASK(bitmask31)); + zassert_true(IS_BIT_MASK(bitmask32)); + zassert_true(IS_BIT_MASK(bitmask63)); + zassert_true(IS_BIT_MASK(bitmask64)); + zassert_false(IS_BIT_MASK(not_bitmask32)); + zassert_false(IS_BIT_MASK(not_bitmask64)); + + zassert_true(IS_BIT_MASK(0)); + zassert_true(IS_BIT_MASK(0x00000001UL)); + zassert_true(IS_BIT_MASK(0x00000003UL)); + zassert_true(IS_BIT_MASK(0x7fffffffUL)); + zassert_true(IS_BIT_MASK(0xffffffffUL)); + zassert_true(IS_BIT_MASK(0x7fffffffffffffffUL)); + zassert_true(IS_BIT_MASK(0xffffffffffffffffUL)); + zassert_false(IS_BIT_MASK(0xfffffffeUL)); + zassert_false(IS_BIT_MASK(0xfffffffffffffffeULL)); + zassert_false(IS_BIT_MASK(0x00000002UL)); + zassert_false(IS_BIT_MASK(0x8000000000000000ULL)); +} + +ZTEST(util, test_IS_SHIFTED_BIT_MASK) { - run_ARRAY_INDEX_FLOOR(); -} + uint32_t bitmask32_shift1 = 0xfffffffeUL; + uint32_t bitmask32_shift31 = 0x80000000UL; + uint64_t bitmask64_shift1 = 0xfffffffffffffffeULL; + uint64_t bitmask64_shift63 = 0x8000000000000000ULL; -ZTEST(util_cc, test_BIT_MASK) -{ - run_BIT_MASK(); -} + zassert_true(IS_SHIFTED_BIT_MASK(bitmask32_shift1, 1)); + zassert_true(IS_SHIFTED_BIT_MASK(bitmask32_shift31, 31)); + zassert_true(IS_SHIFTED_BIT_MASK(bitmask64_shift1, 1)); + zassert_true(IS_SHIFTED_BIT_MASK(bitmask64_shift63, 63)); -ZTEST(util_cc, test_BIT_MASK64) -{ - run_BIT_MASK64(); + zassert_true(IS_SHIFTED_BIT_MASK(0xfffffffeUL, 1)); + zassert_true(IS_SHIFTED_BIT_MASK(0xfffffffffffffffeULL, 1)); + zassert_true(IS_SHIFTED_BIT_MASK(0x80000000UL, 31)); + zassert_true(IS_SHIFTED_BIT_MASK(0x8000000000000000ULL, 63)); } -ZTEST(util_cc, test_IS_BIT_MASK) +ZTEST(util, test_DIV_ROUND_UP) { - run_IS_BIT_MASK(); + zassert_equal(DIV_ROUND_UP(0, 1), 0); + zassert_equal(DIV_ROUND_UP(1, 2), 1); + zassert_equal(DIV_ROUND_UP(3, 2), 2); } -ZTEST(util_cc, test_IS_SHIFTED_BIT_MASK) +ZTEST(util, test_DIV_ROUND_CLOSEST) { - run_IS_SHIFTED_BIT_MASK(); -} - -ZTEST(util_cc, test_DIV_ROUND_UP) + zassert_equal(DIV_ROUND_CLOSEST(0, 1), 0); + /* 5 / 2 = 2.5 -> 3 */ + zassert_equal(DIV_ROUND_CLOSEST(5, 2), 3); + zassert_equal(DIV_ROUND_CLOSEST(5, -2), -3); + zassert_equal(DIV_ROUND_CLOSEST(-5, 2), -3); + zassert_equal(DIV_ROUND_CLOSEST(-5, -2), 3); + /* 7 / 3 = 2.(3) -> 2 */ + zassert_equal(DIV_ROUND_CLOSEST(7, 3), 2); + zassert_equal(DIV_ROUND_CLOSEST(-7, 3), -2); +} + +ZTEST(util, test_IF_DISABLED) { - run_DIV_ROUND_UP(); -} + #define test_IF_DISABLED_FLAG_A 0 + #define test_IF_DISABLED_FLAG_B 1 -ZTEST(util_cc, test_DIV_ROUND_CLOSEST) -{ - run_DIV_ROUND_CLOSEST(); + IF_DISABLED(test_IF_DISABLED_FLAG_A, (goto skipped_a;)) + /* location should be skipped if IF_DISABLED macro is correct. */ + zassert_false(true, "location A should be skipped"); +skipped_a: + IF_DISABLED(test_IF_DISABLED_FLAG_B, (zassert_false(true, "");)) + + IF_DISABLED(test_IF_DISABLED_FLAG_C, (goto skipped_c;)) + /* location should be skipped if IF_DISABLED macro is correct. */ + zassert_false(true, "location C should be skipped"); +skipped_c: + + zassert_true(true, ""); + + #undef test_IF_DISABLED_FLAG_A + #undef test_IF_DISABLED_FLAG_B } -ZTEST_SUITE(util_cc, NULL, NULL, NULL, NULL, NULL); +ZTEST_SUITE(util, NULL, NULL, NULL, NULL, NULL); diff --git a/tests/unit/util/maincxx.cxx b/tests/unit/util/maincxx.cxx deleted file mode 100644 index ad13cfa3a11..00000000000 --- a/tests/unit/util/maincxx.cxx +++ /dev/null @@ -1,11 +0,0 @@ -/* - * Copyright (c) 2019 Oticon A/S - * - * SPDX-License-Identifier: Apache-2.0 - */ - -#include -#include -#include - -#include "test.inc" diff --git a/tests/unit/util/test.inc b/tests/unit/util/test.inc deleted file mode 100644 index f16f1039d45..00000000000 --- a/tests/unit/util/test.inc +++ /dev/null @@ -1,652 +0,0 @@ -/* - * Copyright (c) 2019 Oticon A/S - * - * SPDX-License-Identifier: Apache-2.0 - */ - -#include -#include -#include - -/** - * @brief Test of u8_to_dec - * - * This test verifies conversion of various input values. - * - */ -void run_u8_to_dec(void) -{ - char text[4]; - uint8_t len; - - len = u8_to_dec(text, sizeof(text), 0); - zassert_equal(len, 1, "Length of 0 is not 1"); - zassert_equal(strcmp(text, "0"), 0, - "Value=0 is not converted to \"0\""); - - len = u8_to_dec(text, sizeof(text), 1); - zassert_equal(len, 1, "Length of 1 is not 1"); - zassert_equal(strcmp(text, "1"), 0, - "Value=1 is not converted to \"1\""); - - len = u8_to_dec(text, sizeof(text), 11); - zassert_equal(len, 2, "Length of 11 is not 2"); - zassert_equal(strcmp(text, "11"), 0, - "Value=10 is not converted to \"11\""); - - len = u8_to_dec(text, sizeof(text), 100); - zassert_equal(len, 3, "Length of 100 is not 3"); - zassert_equal(strcmp(text, "100"), 0, - "Value=100 is not converted to \"100\""); - - len = u8_to_dec(text, sizeof(text), 101); - zassert_equal(len, 3, "Length of 101 is not 3"); - zassert_equal(strcmp(text, "101"), 0, - "Value=101 is not converted to \"101\""); - - len = u8_to_dec(text, sizeof(text), 255); - zassert_equal(len, 3, "Length of 255 is not 3"); - zassert_equal(strcmp(text, "255"), 0, - "Value=255 is not converted to \"255\""); - - memset(text, 0, sizeof(text)); - len = u8_to_dec(text, 2, 123); - zassert_equal(len, 2, - "Length of converted value using 2 byte buffer isn't 2"); - zassert_equal( - strcmp(text, "12"), 0, - "Value=123 is not converted to \"12\" using 2-byte buffer"); - - memset(text, 0, sizeof(text)); - len = u8_to_dec(text, 1, 123); - zassert_equal(len, 1, - "Length of converted value using 1 byte buffer isn't 1"); - zassert_equal( - strcmp(text, "1"), 0, - "Value=123 is not converted to \"1\" using 1-byte buffer"); - - memset(text, 0, sizeof(text)); - len = u8_to_dec(text, 0, 123); - zassert_equal(len, 0, - "Length of converted value using 0 byte buffer isn't 0"); -} - -#define TEST_DEFINE_1 1 -#define TEST_DEFINE_0 0 - -void run_COND_CODE_1(void) -{ - /* Test validates that expected code has been injected. Failure would - * be seen in compilation (lack of variable or ununsed variable. - */ - COND_CODE_1(1, (uint32_t x0 = 1;), (uint32_t y0;)) - zassert_true((x0 == 1)); - - COND_CODE_1(NOT_EXISTING_DEFINE, (uint32_t x1 = 1;), (uint32_t y1 = 1;)) - zassert_true((y1 == 1)); - - COND_CODE_1(TEST_DEFINE_1, (uint32_t x2 = 1;), (uint32_t y2 = 1;)) - zassert_true((x2 == 1)); - - COND_CODE_1(2, (uint32_t x3 = 1;), (uint32_t y3 = 1;)) - zassert_true((y3 == 1)); -} - -void run_COND_CODE_0(void) -{ - /* Test validates that expected code has been injected. Failure would - * be seen in compilation (lack of variable or ununsed variable. - */ - COND_CODE_0(0, (uint32_t x0 = 1;), (uint32_t y0;)) - zassert_true((x0 == 1)); - - COND_CODE_0(NOT_EXISTING_DEFINE, (uint32_t x1 = 1;), (uint32_t y1 = 1;)) - zassert_true((y1 == 1)); - - COND_CODE_0(TEST_DEFINE_0, (uint32_t x2 = 1;), (uint32_t y2 = 1;)) - zassert_true((x2 == 1)); - - COND_CODE_0(2, (uint32_t x3 = 1;), (uint32_t y3 = 1;)) - zassert_true((y3 == 1)); -} - -#undef ZERO -#undef SEVEN -#undef A_BUILD_ERROR -#define ZERO 0 -#define SEVEN 7 -#define A_BUILD_ERROR (this would be a build error if you used || or &&) - -void run_UTIL_OR(void) -{ - zassert_equal(UTIL_OR(SEVEN, A_BUILD_ERROR), 7); - zassert_equal(UTIL_OR(7, 0), 7); - zassert_equal(UTIL_OR(SEVEN, ZERO), 7); - zassert_equal(UTIL_OR(0, 7), 7); - zassert_equal(UTIL_OR(ZERO, SEVEN), 7); - zassert_equal(UTIL_OR(0, 0), 0); - zassert_equal(UTIL_OR(ZERO, ZERO), 0); -} - -void run_UTIL_AND(void) -{ - zassert_equal(UTIL_AND(ZERO, A_BUILD_ERROR), 0); - zassert_equal(UTIL_AND(7, 0), 0); - zassert_equal(UTIL_AND(SEVEN, ZERO), 0); - zassert_equal(UTIL_AND(0, 7), 0); - zassert_equal(UTIL_AND(ZERO, SEVEN), 0); - zassert_equal(UTIL_AND(0, 0), 0); - zassert_equal(UTIL_AND(ZERO, ZERO), 0); - zassert_equal(UTIL_AND(7, 7), 7); - zassert_equal(UTIL_AND(7, SEVEN), 7); - zassert_equal(UTIL_AND(SEVEN, 7), 7); - zassert_equal(UTIL_AND(SEVEN, SEVEN), 7); -} - -void run_IF_ENABLED(void) -{ - #define test_IF_ENABLED_FLAG_A 1 - #define test_IF_ENABLED_FLAG_B 0 - - IF_ENABLED(test_IF_ENABLED_FLAG_A, (goto skipped;)) - /* location should be skipped if IF_ENABLED macro is correct. */ - zassert_false(true, "location should be skipped"); -skipped: - IF_ENABLED(test_IF_ENABLED_FLAG_B, (zassert_false(true, "");)) - - IF_ENABLED(test_IF_ENABLED_FLAG_C, (zassert_false(true, "");)) - - zassert_true(true, ""); - - #undef test_IF_ENABLED_FLAG_A - #undef test_IF_ENABLED_FLAG_B -} - -void run_IF_DISABLED(void) -{ - #define test_IF_DISABLED_FLAG_A 0 - #define test_IF_DISABLED_FLAG_B 1 - - IF_DISABLED(test_IF_DISABLED_FLAG_A, (goto skipped_a;)) - /* location should be skipped if IF_DISABLED macro is correct. */ - zassert_false(true, "location A should be skipped"); -skipped_a: - IF_DISABLED(test_IF_DISABLED_FLAG_B, (zassert_false(true, "");)) - - IF_DISABLED(test_IF_DISABLED_FLAG_C, (goto skipped_c;)) - /* location should be skipped if IF_DISABLED macro is correct. */ - zassert_false(true, "location C should be skipped"); -skipped_c: - - zassert_true(true, ""); - - #undef test_IF_DISABLED_FLAG_A - #undef test_IF_DISABLED_FLAG_B -} - -void run_LISTIFY(void) -{ - int ab0 = 1; - int ab1 = 1; -#define A_PTR(x, name0, name1) &UTIL_CAT(UTIL_CAT(name0, name1), x) - - int *a[] = { LISTIFY(2, A_PTR, (,), a, b) }; - - zassert_equal(ARRAY_SIZE(a), 2); - zassert_equal(a[0], &ab0); - zassert_equal(a[1], &ab1); -} - -void run_MACRO_MAP_CAT(void) -{ - int item_a_item_b_item_c_ = 1; - -#undef FOO -#define FOO(x) item_##x##_ - zassert_equal(MACRO_MAP_CAT(FOO, a, b, c), 1, "MACRO_MAP_CAT"); -#undef FOO -} - -static int inc_func(bool cleanup) -{ - static int a; - - if (cleanup) { - a = 1; - } - - return a++; -} - -/* Test checks if @ref Z_MAX, @ref Z_MIN and @ref Z_CLAMP return correct result - * and perform single evaluation of input arguments. - */ -void run_z_max_z_min_z_clamp(void) -{ - zassert_equal(Z_MAX(inc_func(true), 0), 1, "Unexpected macro result"); - /* Z_MAX should have call inc_func only once */ - zassert_equal(inc_func(false), 2, "Unexpected return value"); - - zassert_equal(Z_MIN(inc_func(false), 2), 2, "Unexpected macro result"); - /* Z_MIN should have call inc_func only once */ - zassert_equal(inc_func(false), 4, "Unexpected return value"); - - zassert_equal(Z_CLAMP(inc_func(false), 1, 3), 3, "Unexpected macro result"); - /* Z_CLAMP should have call inc_func only once */ - zassert_equal(inc_func(false), 6, "Unexpected return value"); - - zassert_equal(Z_CLAMP(inc_func(false), 10, 15), 10, - "Unexpected macro result"); - /* Z_CLAMP should have call inc_func only once */ - zassert_equal(inc_func(false), 8, "Unexpected return value"); -} - -void run_CLAMP(void) -{ - zassert_equal(CLAMP(5, 3, 7), 5, "Unexpected clamp result"); - zassert_equal(CLAMP(3, 3, 7), 3, "Unexpected clamp result"); - zassert_equal(CLAMP(7, 3, 7), 7, "Unexpected clamp result"); - zassert_equal(CLAMP(1, 3, 7), 3, "Unexpected clamp result"); - zassert_equal(CLAMP(8, 3, 7), 7, "Unexpected clamp result"); - - zassert_equal(CLAMP(-5, -7, -3), -5, "Unexpected clamp result"); - zassert_equal(CLAMP(-9, -7, -3), -7, "Unexpected clamp result"); - zassert_equal(CLAMP(1, -7, -3), -3, "Unexpected clamp result"); - - zassert_equal(CLAMP(0xffffffffaULL, 0xffffffff0ULL, 0xfffffffffULL), - 0xffffffffaULL, "Unexpected clamp result"); -} - -void run_IN_RANGE(void) -{ - zassert_true(IN_RANGE(0, 0, 0), "Unexpected IN_RANGE result"); - zassert_true(IN_RANGE(1, 0, 1), "Unexpected IN_RANGE result"); - zassert_true(IN_RANGE(1, 0, 2), "Unexpected IN_RANGE result"); - zassert_true(IN_RANGE(-1, -2, 2), "Unexpected IN_RANGE result"); - zassert_true(IN_RANGE(-3, -5, -1), "Unexpected IN_RANGE result"); - zassert_true(IN_RANGE(0, 0, UINT64_MAX), "Unexpected IN_RANGE result"); - zassert_true(IN_RANGE(UINT64_MAX, 0, UINT64_MAX), "Unexpected IN_RANGE result"); - zassert_true(IN_RANGE(0, INT64_MIN, INT64_MAX), "Unexpected IN_RANGE result"); - zassert_true(IN_RANGE(INT64_MIN, INT64_MIN, INT64_MAX), "Unexpected IN_RANGE result"); - zassert_true(IN_RANGE(INT64_MAX, INT64_MIN, INT64_MAX), "Unexpected IN_RANGE result"); - - zassert_false(IN_RANGE(5, 0, 2), "Unexpected IN_RANGE result"); - zassert_false(IN_RANGE(5, 10, 0), "Unexpected IN_RANGE result"); - zassert_false(IN_RANGE(-1, 0, 1), "Unexpected IN_RANGE result"); -} - -void run_FOR_EACH(void) -{ - #define FOR_EACH_MACRO_TEST(arg) *buf++ = arg - - uint8_t array[3] = {0}; - uint8_t *buf = array; - - FOR_EACH(FOR_EACH_MACRO_TEST, (;), 1, 2, 3); - - zassert_equal(array[0], 1, "Unexpected value %d", array[0]); - zassert_equal(array[1], 2, "Unexpected value %d", array[1]); - zassert_equal(array[2], 3, "Unexpected value %d", array[2]); -} - -void run_FOR_EACH_NONEMPTY_TERM(void) -{ - #define SQUARE(arg) (arg * arg) - #define SWALLOW_VA_ARGS_1(...) EMPTY - #define SWALLOW_VA_ARGS_2(...) - #define REPEAT_VA_ARGS(...) __VA_ARGS__ - - uint8_t array[] = { - FOR_EACH_NONEMPTY_TERM(SQUARE, (,)) - FOR_EACH_NONEMPTY_TERM(SQUARE, (,),) - FOR_EACH_NONEMPTY_TERM(SQUARE, (,), ,) - FOR_EACH_NONEMPTY_TERM(SQUARE, (,), EMPTY, EMPTY) - FOR_EACH_NONEMPTY_TERM(SQUARE, (,), SWALLOW_VA_ARGS_1(a, b)) - FOR_EACH_NONEMPTY_TERM(SQUARE, (,), SWALLOW_VA_ARGS_2(c, d)) - FOR_EACH_NONEMPTY_TERM(SQUARE, (,), 1) - FOR_EACH_NONEMPTY_TERM(SQUARE, (,), 2, 3) - FOR_EACH_NONEMPTY_TERM(SQUARE, (,), REPEAT_VA_ARGS(4)) - FOR_EACH_NONEMPTY_TERM(SQUARE, (,), REPEAT_VA_ARGS(5, 6)) - 255 - }; - - size_t size = ARRAY_SIZE(array); - - zassert_equal(size, 7, "Unexpected size %d", size); - zassert_equal(array[0], 1, "Unexpected value %d", array[0]); - zassert_equal(array[1], 4, "Unexpected value %d", array[1]); - zassert_equal(array[2], 9, "Unexpected value %d", array[2]); - zassert_equal(array[3], 16, "Unexpected value %d", array[3]); - zassert_equal(array[4], 25, "Unexpected value %d", array[4]); - zassert_equal(array[5], 36, "Unexpected value %d", array[5]); - zassert_equal(array[6], 255, "Unexpected value %d", array[6]); -} - -static void fsum(uint32_t incr, uint32_t *sum) -{ - *sum = *sum + incr; -} - -void run_FOR_EACH_FIXED_ARG(void) -{ - uint32_t sum = 0; - - FOR_EACH_FIXED_ARG(fsum, (;), &sum, 1, 2, 3); - - zassert_equal(sum, 6, "Unexpected value %d", sum); -} - -void run_FOR_EACH_IDX(void) -{ - #define FOR_EACH_IDX_MACRO_TEST(n, arg) uint8_t a##n = arg - - FOR_EACH_IDX(FOR_EACH_IDX_MACRO_TEST, (;), 1, 2, 3); - - zassert_equal(a0, 1, "Unexpected value %d", a0); - zassert_equal(a1, 2, "Unexpected value %d", a1); - zassert_equal(a2, 3, "Unexpected value %d", a2); - - #define FOR_EACH_IDX_MACRO_TEST2(n, arg) array[n] = arg - uint8_t array[32] = {0}; - - FOR_EACH_IDX(FOR_EACH_IDX_MACRO_TEST2, (;), 1, 2, 3, 4, 5, 6, 7, 8, - 9, 10, 11, 12, 13, 14, 15); - for (int i = 0; i < 15; i++) { - zassert_equal(array[i], i + 1, - "Unexpected value: %d", array[i]); - } - zassert_equal(array[15], 0, "Unexpected value: %d", array[15]); - - #define FOR_EACH_IDX_MACRO_TEST3(n, arg) &a##n - - uint8_t *a[] = { - FOR_EACH_IDX(FOR_EACH_IDX_MACRO_TEST3, (,), 1, 2, 3) - }; - - zassert_equal(ARRAY_SIZE(a), 3, "Unexpected value:%zu", ARRAY_SIZE(a)); -} - -void run_FOR_EACH_IDX_FIXED_ARG(void) -{ - #undef FOO - #define FOO(n, arg, fixed_arg) \ - uint8_t fixed_arg##n = arg - - FOR_EACH_IDX_FIXED_ARG(FOO, (;), a, 1, 2, 3); - - zassert_equal(a0, 1, "Unexpected value %d", a0); - zassert_equal(a1, 2, "Unexpected value %d", a1); - zassert_equal(a2, 3, "Unexpected value %d", a2); -} - -void run_IS_EMPTY(void) -{ - #define test_IS_EMPTY_REAL_EMPTY - #define test_IS_EMPTY_NOT_EMPTY XXX_DO_NOT_REPLACE_XXX - zassert_true(IS_EMPTY(test_IS_EMPTY_REAL_EMPTY), - "Expected to be empty"); - zassert_false(IS_EMPTY(test_IS_EMPTY_NOT_EMPTY), - "Expected to be non-empty"); - zassert_false(IS_EMPTY("string"), - "Expected to be non-empty"); - zassert_false(IS_EMPTY(&test_IS_EMPTY), - "Expected to be non-empty"); -} - -void run_IS_EQ(void) -{ - zassert_true(IS_EQ(0, 0), "Unexpected IS_EQ result"); - zassert_true(IS_EQ(1, 1), "Unexpected IS_EQ result"); - zassert_true(IS_EQ(7, 7), "Unexpected IS_EQ result"); - - zassert_false(IS_EQ(0, 1), "Unexpected IS_EQ result"); - zassert_false(IS_EQ(1, 7), "Unexpected IS_EQ result"); - zassert_false(IS_EQ(7, 0), "Unexpected IS_EQ result"); -} - -void run_LIST_DROP_EMPTY(void) -{ - /* - * The real definition should be: - * #define TEST_BROKEN_LIST ,Henry,,Dorsett,Case, - * but checkpatch complains, so below equivalent is defined. - */ - #define TEST_BROKEN_LIST EMPTY, Henry, EMPTY, Dorsett, Case, - #define TEST_FIXED_LIST LIST_DROP_EMPTY(TEST_BROKEN_LIST) - static const char *const arr[] = { - FOR_EACH(STRINGIFY, (,), TEST_FIXED_LIST) - }; - - zassert_equal(ARRAY_SIZE(arr), 3, "Failed to cleanup list"); - zassert_equal(strcmp(arr[0], "Henry"), 0, "Failed at 0"); - zassert_equal(strcmp(arr[1], "Dorsett"), 0, "Failed at 1"); - zassert_equal(strcmp(arr[2], "Case"), 0, "Failed at 0"); -} - -void run_nested_FOR_EACH(void) -{ - #define FOO_1(x) a##x = x - #define FOO_2(x) int x - - FOR_EACH(FOO_2, (;), FOR_EACH(FOO_1, (,), 0, 1, 2)); - - zassert_equal(a0, 0); - zassert_equal(a1, 1); - zassert_equal(a2, 2); -} - -void run_GET_ARG_N(void) -{ - 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); - - zassert_equal(a, 10); - zassert_equal(b, 100); - zassert_equal(c, 1000); -} - -void run_GET_ARGS_LESS_N(void) -{ - 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) }; - - zassert_equal(sizeof(a), 3); - - zassert_equal(sizeof(b), 2); - zassert_equal(b[0], 2); - zassert_equal(b[1], 3); - - zassert_equal(sizeof(c), 1); - zassert_equal(c[0], 3); -} - -void run_mixing_GET_ARG_and_FOR_EACH(void) -{ - #undef TEST_MACRO - #define TEST_MACRO(x) x, - int i; - - i = GET_ARG_N(3, FOR_EACH(TEST_MACRO, (), 1, 2, 3, 4, 5)); - zassert_equal(i, 3); - - i = GET_ARG_N(2, 1, GET_ARGS_LESS_N(2, 1, 2, 3, 4, 5)); - zassert_equal(i, 3); - - #undef TEST_MACRO - #undef TEST_MACRO2 - #define TEST_MACRO(x) GET_ARG_N(3, 1, 2, x), - #define TEST_MACRO2(...) FOR_EACH(TEST_MACRO, (), __VA_ARGS__) - int a[] = { - LIST_DROP_EMPTY(TEST_MACRO2(1, 2, 3, 4)), 5 - }; - - zassert_equal(ARRAY_SIZE(a), 5); - zassert_equal(a[0], 1); - zassert_equal(a[1], 2); - zassert_equal(a[2], 3); - zassert_equal(a[3], 4); - zassert_equal(a[4], 5); -} - -void run_IS_ARRAY_ELEMENT(void) -{ - size_t i; - size_t array[3]; - uint8_t *const alias = (uint8_t *)array; - - zassert_false(IS_ARRAY_ELEMENT(array, &array[-1])); - zassert_false(IS_ARRAY_ELEMENT(array, &array[ARRAY_SIZE(array)])); - zassert_false(IS_ARRAY_ELEMENT(array, &alias[1])); - - for (i = 0; i < ARRAY_SIZE(array); ++i) { - zassert_true(IS_ARRAY_ELEMENT(array, &array[i])); - } -} - -void run_ARRAY_INDEX(void) -{ - size_t i; - size_t array[] = {0, 1, 2, 3}; - - for (i = 0; i < ARRAY_SIZE(array); ++i) { - zassert_equal(array[ARRAY_INDEX(array, &array[i])], i); - } - - /* ARRAY_INDEX(array, &alias[1]) asserts with CONFIG_ASSERT=y */ -} - -void run_PART_OF_ARRAY(void) -{ - size_t i; - size_t array[3]; - uint8_t *const alias = (uint8_t *)array; - - ARG_UNUSED(i); - ARG_UNUSED(alias); - - zassert_false(PART_OF_ARRAY(array, &array[-1])); - zassert_false(PART_OF_ARRAY(array, &array[ARRAY_SIZE(array)])); - - for (i = 0; i < ARRAY_SIZE(array); ++i) { - zassert_true(PART_OF_ARRAY(array, &array[i])); - } - - zassert_true(PART_OF_ARRAY(array, &alias[1])); -} - -void run_ARRAY_INDEX_FLOOR(void) -{ - size_t i; - size_t array[] = {0, 1, 2, 3}; - uint8_t *const alias = (uint8_t *)array; - - for (i = 0; i < ARRAY_SIZE(array); ++i) { - zassert_equal(array[ARRAY_INDEX_FLOOR(array, &array[i])], i); - } - - zassert_equal(array[ARRAY_INDEX_FLOOR(array, &alias[1])], 0); -} - -void run_BIT_MASK(void) -{ - uint32_t bitmask0 = BIT_MASK(0); - uint32_t bitmask1 = BIT_MASK(1); - uint32_t bitmask2 = BIT_MASK(2); - uint32_t bitmask31 = BIT_MASK(31); - - zassert_equal(0x00000000UL, bitmask0); - zassert_equal(0x00000001UL, bitmask1); - zassert_equal(0x00000003UL, bitmask2); - zassert_equal(0x7ffffffFUL, bitmask31); -} - -void run_BIT_MASK64(void) -{ - uint64_t bitmask0 = BIT64_MASK(0); - uint64_t bitmask1 = BIT64_MASK(1); - uint64_t bitmask2 = BIT64_MASK(2); - uint64_t bitmask63 = BIT64_MASK(63); - - zassert_equal(0x0000000000000000ULL, bitmask0); - zassert_equal(0x0000000000000001ULL, bitmask1); - zassert_equal(0x0000000000000003ULL, bitmask2); - zassert_equal(0x7fffffffffffffffULL, bitmask63); -} - -void run_IS_BIT_MASK(void) -{ - uint32_t zero32 = 0UL; - uint64_t zero64 = 0ULL; - uint32_t bitmask1 = 0x00000001UL; - uint32_t bitmask2 = 0x00000003UL; - uint32_t bitmask31 = 0x7fffffffUL; - uint32_t bitmask32 = 0xffffffffUL; - uint64_t bitmask63 = 0x7fffffffffffffffULL; - uint64_t bitmask64 = 0xffffffffffffffffULL; - - uint32_t not_bitmask32 = 0xfffffffeUL; - uint64_t not_bitmask64 = 0xfffffffffffffffeULL; - - zassert_true(IS_BIT_MASK(zero32)); - zassert_true(IS_BIT_MASK(zero64)); - zassert_true(IS_BIT_MASK(bitmask1)); - zassert_true(IS_BIT_MASK(bitmask2)); - zassert_true(IS_BIT_MASK(bitmask31)); - zassert_true(IS_BIT_MASK(bitmask32)); - zassert_true(IS_BIT_MASK(bitmask63)); - zassert_true(IS_BIT_MASK(bitmask64)); - zassert_false(IS_BIT_MASK(not_bitmask32)); - zassert_false(IS_BIT_MASK(not_bitmask64)); - - zassert_true(IS_BIT_MASK(0)); - zassert_true(IS_BIT_MASK(0x00000001UL)); - zassert_true(IS_BIT_MASK(0x00000003UL)); - zassert_true(IS_BIT_MASK(0x7fffffffUL)); - zassert_true(IS_BIT_MASK(0xffffffffUL)); - zassert_true(IS_BIT_MASK(0x7fffffffffffffffUL)); - zassert_true(IS_BIT_MASK(0xffffffffffffffffUL)); - zassert_false(IS_BIT_MASK(0xfffffffeUL)); - zassert_false(IS_BIT_MASK(0xfffffffffffffffeULL)); - zassert_false(IS_BIT_MASK(0x00000002UL)); - zassert_false(IS_BIT_MASK(0x8000000000000000ULL)); -} - -void run_IS_SHIFTED_BIT_MASK(void) -{ - uint32_t bitmask32_shift1 = 0xfffffffeUL; - uint32_t bitmask32_shift31 = 0x80000000UL; - uint64_t bitmask64_shift1 = 0xfffffffffffffffeULL; - uint64_t bitmask64_shift63 = 0x8000000000000000ULL; - - zassert_true(IS_SHIFTED_BIT_MASK(bitmask32_shift1, 1)); - zassert_true(IS_SHIFTED_BIT_MASK(bitmask32_shift31, 31)); - zassert_true(IS_SHIFTED_BIT_MASK(bitmask64_shift1, 1)); - zassert_true(IS_SHIFTED_BIT_MASK(bitmask64_shift63, 63)); - - zassert_true(IS_SHIFTED_BIT_MASK(0xfffffffeUL, 1)); - zassert_true(IS_SHIFTED_BIT_MASK(0xfffffffffffffffeULL, 1)); - zassert_true(IS_SHIFTED_BIT_MASK(0x80000000UL, 31)); - zassert_true(IS_SHIFTED_BIT_MASK(0x8000000000000000ULL, 63)); -} - -void run_DIV_ROUND_UP(void) -{ - zassert_equal(DIV_ROUND_UP(0, 1), 0); - zassert_equal(DIV_ROUND_UP(1, 2), 1); - zassert_equal(DIV_ROUND_UP(3, 2), 2); -} - -void run_DIV_ROUND_CLOSEST(void) -{ - zassert_equal(DIV_ROUND_CLOSEST(0, 1), 0); - /* 5 / 2 = 2.5 -> 3 */ - zassert_equal(DIV_ROUND_CLOSEST(5, 2), 3); - zassert_equal(DIV_ROUND_CLOSEST(5, -2), -3); - zassert_equal(DIV_ROUND_CLOSEST(-5, 2), -3); - zassert_equal(DIV_ROUND_CLOSEST(-5, -2), 3); - /* 7 / 3 = 2.(3) -> 2 */ - zassert_equal(DIV_ROUND_CLOSEST(7, 3), 2); - zassert_equal(DIV_ROUND_CLOSEST(-7, 3), -2); -} diff --git a/tests/unit/util/testcase.yaml b/tests/unit/util/testcase.yaml index f78098c177e..e428516e6fc 100644 --- a/tests/unit/util/testcase.yaml +++ b/tests/unit/util/testcase.yaml @@ -1,6 +1,11 @@ +common: + tags: + - lib + - utilities tests: utilities.dec: - tags: - - lib - - utilities type: unit + utilities.dec.cpp: + type: unit + extra_configs: + - CONFIG_CPP=y From c0bb064d4e38d11d4df9e0090619c832c1a267a5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Krzysztof=20Chru=C5=9Bci=C5=84ski?= Date: Tue, 21 Nov 2023 14:22:02 +0100 Subject: [PATCH 1643/3723] tests: unit: util: Fix compliance check warnings MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit As code is moved from test.inc to main.c a compliance check is run for the first time on that code. Fixing warnings. Signed-off-by: Krzysztof Chruściński --- tests/unit/util/main.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/tests/unit/util/main.c b/tests/unit/util/main.c index d5698fc85f5..c1dbca35bdc 100644 --- a/tests/unit/util/main.c +++ b/tests/unit/util/main.c @@ -68,7 +68,7 @@ ZTEST(util, test_COND_CODE_1) { #define TEST_DEFINE_1 1 #define TEST_DEFINE_0 0 /* Test validates that expected code has been injected. Failure would - * be seen in compilation (lack of variable or ununsed variable. + * be seen in compilation (lack of variable or unused variable). */ COND_CODE_1(1, (uint32_t x0 = 1;), (uint32_t y0;)) zassert_true((x0 == 1)); @@ -85,7 +85,7 @@ ZTEST(util, test_COND_CODE_1) { ZTEST(util, test_COND_CODE_0) { /* Test validates that expected code has been injected. Failure would - * be seen in compilation (lack of variable or ununsed variable. + * be seen in compilation (lack of variable or unused variable). */ COND_CODE_0(0, (uint32_t x0 = 1;), (uint32_t y0;)) zassert_true((x0 == 1)); @@ -173,7 +173,7 @@ static int inc_func(bool cleanup) { static int a; - if (cleanup) { + if (cleanup) { a = 1; } From 75ac40e6d85bb4288cc4687140fcb95c907c6ca0 Mon Sep 17 00:00:00 2001 From: TOKITA Hiroshi Date: Thu, 23 Nov 2023 16:29:34 +0900 Subject: [PATCH 1644/3723] drivers: serial: ra: Cleaned up useless initialization and bad naming DEVICE_MMIO_MAP() is an unnecessary process, so delete it. I created uart_ra.c based on uart_rcar.c, but I forgot to correct the name. I fixed it. Signed-off-by: TOKITA Hiroshi --- drivers/serial/uart_ra.c | 10 ++++------ 1 file changed, 4 insertions(+), 6 deletions(-) diff --git a/drivers/serial/uart_ra.c b/drivers/serial/uart_ra.c index a93ffff4b45..7dff32f21a3 100644 --- a/drivers/serial/uart_ra.c +++ b/drivers/serial/uart_ra.c @@ -340,8 +340,6 @@ static int uart_ra_init(const struct device *dev) return ret; } - DEVICE_MMIO_MAP(dev, K_MEM_CACHE_NONE); - ret = uart_ra_configure(dev, &data->current_config); if (ret != 0) { return ret; @@ -360,7 +358,7 @@ static const struct uart_driver_api uart_ra_driver_api = { }; /* Device Instantiation */ -#define UART_RCAR_INIT_CFG(n) \ +#define UART_RA_INIT_CFG(n) \ PINCTRL_DT_DEFINE(DT_INST_PARENT(n)); \ static const struct uart_ra_cfg uart_ra_cfg_##n = { \ .regs = DT_REG_ADDR(DT_INST_PARENT(n)), \ @@ -370,8 +368,8 @@ static const struct uart_driver_api uart_ra_driver_api = { .pcfg = PINCTRL_DT_DEV_CONFIG_GET(DT_INST_PARENT(n)), \ } -#define UART_RCAR_INIT(n) \ - UART_RCAR_INIT_CFG(n); \ +#define UART_RA_INIT(n) \ + UART_RA_INIT_CFG(n); \ \ static struct uart_ra_data uart_ra_data_##n = { \ .current_config = { \ @@ -392,4 +390,4 @@ static const struct uart_driver_api uart_ra_driver_api = { &uart_ra_driver_api); \ \ -DT_INST_FOREACH_STATUS_OKAY(UART_RCAR_INIT) +DT_INST_FOREACH_STATUS_OKAY(UART_RA_INIT) From bccd281b3d56a92fcf7c9b88d37bfafd785ad86b Mon Sep 17 00:00:00 2001 From: TOKITA Hiroshi Date: Thu, 23 Nov 2023 23:10:13 +0900 Subject: [PATCH 1645/3723] drivers: interrupt_controller: ra_icu: Adding `disconnect_dynamic` Adding `ra_icu_irq_disconnect_dynamic()` corresponds with `ra_icu_irq_connect_dynamic()`. Signed-off-by: TOKITA Hiroshi --- drivers/interrupt_controller/intc_ra_icu.c | 18 ++++++++++++++++++ .../drivers/interrupt_controller/intc_ra_icu.h | 4 ++++ 2 files changed, 22 insertions(+) diff --git a/drivers/interrupt_controller/intc_ra_icu.c b/drivers/interrupt_controller/intc_ra_icu.c index 167673f187f..ace1fb4b3c3 100644 --- a/drivers/interrupt_controller/intc_ra_icu.c +++ b/drivers/interrupt_controller/intc_ra_icu.c @@ -104,5 +104,23 @@ int ra_icu_irq_connect_dynamic(unsigned int irq, unsigned int priority, return irqn; } +int ra_icu_irq_disconnect_dynamic(unsigned int irq, unsigned int priority, + void (*routine)(const void *parameter), const void *parameter, + uint32_t flags) +{ + int irqn = irq; + + if (irq == RA_ICU_IRQ_UNSPECIFIED) { + return -EINVAL; + } + + irq_disable(irqn); + sys_write32(0, IELSRn_REG(irqn)); + z_isr_install(irqn, z_irq_spurious, NULL); + z_arm_irq_priority_set(irqn, 0, 0); + + return 0; +} + DEVICE_DT_INST_DEFINE(0, NULL, NULL, NULL, NULL, PRE_KERNEL_1, CONFIG_INTC_INIT_PRIORITY, NULL); diff --git a/include/zephyr/drivers/interrupt_controller/intc_ra_icu.h b/include/zephyr/drivers/interrupt_controller/intc_ra_icu.h index fcbef647d29..d347d81cad8 100644 --- a/include/zephyr/drivers/interrupt_controller/intc_ra_icu.h +++ b/include/zephyr/drivers/interrupt_controller/intc_ra_icu.h @@ -35,4 +35,8 @@ extern int ra_icu_irq_connect_dynamic(unsigned int irq, unsigned int priority, void (*routine)(const void *parameter), const void *parameter, uint32_t flags); +extern int ra_icu_irq_disconnect_dynamic(unsigned int irq, unsigned int priority, + void (*routine)(const void *parameter), + const void *parameter, uint32_t flags); + #endif /* ZEPHYR_DRIVERS_INTERRUPT_CONTROLLER_INTC_RA_ICU_H_ */ From 2de161ce4e63f9fb0bb9f5ae042e2b78022c0e3f Mon Sep 17 00:00:00 2001 From: TOKITA Hiroshi Date: Sat, 23 Dec 2023 13:23:02 +0900 Subject: [PATCH 1646/3723] drivers: interrupt_controller: ra_icu: Don't enable on irq connecting Don't execute `irq_enable` in process of the `ra_icu_irq_connect_dynamic`. The caller of `ra_icu_irq_connect_dynamic` is only `gpio_ra_pin_configure` at this time. `gpio_ra_pin_configure` calls `irq_enable` just after called `ra_icu_irq_connect_dynamic`. So removing 'irq_enable' from 'ra_icu_irq_connect_dynamic' has no effect on behavior. Signed-off-by: TOKITA Hiroshi --- drivers/interrupt_controller/intc_ra_icu.c | 1 - 1 file changed, 1 deletion(-) diff --git a/drivers/interrupt_controller/intc_ra_icu.c b/drivers/interrupt_controller/intc_ra_icu.c index ace1fb4b3c3..1b9c2294758 100644 --- a/drivers/interrupt_controller/intc_ra_icu.c +++ b/drivers/interrupt_controller/intc_ra_icu.c @@ -99,7 +99,6 @@ int ra_icu_irq_connect_dynamic(unsigned int irq, unsigned int priority, z_isr_install(irqn, routine, parameter); z_arm_irq_priority_set(irqn, priority, flags); ra_icu_irq_configure(event, intcfg); - irq_enable(irqn); return irqn; } From b1172d812d7efe2b220927b5f2648f86c903cb65 Mon Sep 17 00:00:00 2001 From: TOKITA Hiroshi Date: Sat, 25 Nov 2023 11:36:52 +0900 Subject: [PATCH 1647/3723] drivers: serial: ra: adding support interrupt driven mode Add support interrupt driven mode for Renesas RA UART driver. Signed-off-by: TOKITA Hiroshi --- .../arduino_uno_r4_minima_defconfig | 1 + drivers/serial/uart_ra.c | 391 +++++++++++++++++- 2 files changed, 371 insertions(+), 21 deletions(-) diff --git a/boards/arm/arduino_uno_r4/arduino_uno_r4_minima_defconfig b/boards/arm/arduino_uno_r4/arduino_uno_r4_minima_defconfig index 8d44c120b3e..57abb934998 100644 --- a/boards/arm/arduino_uno_r4/arduino_uno_r4_minima_defconfig +++ b/boards/arm/arduino_uno_r4/arduino_uno_r4_minima_defconfig @@ -10,6 +10,7 @@ CONFIG_BUILD_OUTPUT_HEX=y # enable uart driver CONFIG_SERIAL=y +CONFIG_UART_INTERRUPT_DRIVEN=y # enable console CONFIG_CONSOLE=y diff --git a/drivers/serial/uart_ra.c b/drivers/serial/uart_ra.c index 7dff32f21a3..4dcc1174502 100644 --- a/drivers/serial/uart_ra.c +++ b/drivers/serial/uart_ra.c @@ -8,24 +8,41 @@ #include #include +#include #include +#include #include #include LOG_MODULE_REGISTER(ra_uart_sci, CONFIG_UART_LOG_LEVEL); +enum { + UART_RA_INT_RXI, + UART_RA_INT_TXI, + UART_RA_INT_ERI, + NUM_OF_UART_RA_INT, +}; + struct uart_ra_cfg { mem_addr_t regs; const struct device *clock_dev; clock_control_subsys_t clock_id; const struct pinctrl_dev_config *pcfg; +#ifdef CONFIG_UART_INTERRUPT_DRIVEN + int (*irq_config_func)(const struct device *dev); +#endif }; struct uart_ra_data { struct uart_config current_config; uint32_t clk_rate; struct k_spinlock lock; +#ifdef CONFIG_UART_INTERRUPT_DRIVEN + uint32_t irqn[NUM_OF_UART_RA_INT]; + uart_irq_callback_user_data_t callback; + void *cb_data; +#endif }; #define REG_MASK(reg) (BIT_MASK(_CONCAT(reg, _LEN)) << _CONCAT(reg, _POS)) @@ -219,6 +236,12 @@ static int uart_ra_poll_in(const struct device *dev, unsigned char *p_char) k_spinlock_key_t key = k_spin_lock(&data->lock); + /* If interrupts are enabled, return -EINVAL */ + if ((uart_ra_read_8(dev, SCR) & REG_MASK(SCR_RIE))) { + ret = -EINVAL; + goto unlock; + } + if ((uart_ra_read_8(dev, SSR) & REG_MASK(SSR_RDRF)) == 0) { ret = -1; goto unlock; @@ -234,14 +257,57 @@ static int uart_ra_poll_in(const struct device *dev, unsigned char *p_char) static void uart_ra_poll_out(const struct device *dev, unsigned char out_char) { struct uart_ra_data *data = dev->data; + uint8_t reg_val; k_spinlock_key_t key = k_spin_lock(&data->lock); + while (!(uart_ra_read_8(dev, SSR) & REG_MASK(SSR_TEND)) || + !(uart_ra_read_8(dev, SSR) & REG_MASK(SSR_TDRE))) { + ; + } + + /* If interrupts are enabled, temporarily disable them */ + reg_val = uart_ra_read_8(dev, SCR); + uart_ra_write_8(dev, SCR, reg_val & ~REG_MASK(SCR_TIE)); + uart_ra_write_8(dev, TDR, out_char); while (!(uart_ra_read_8(dev, SSR) & REG_MASK(SSR_TEND)) || !(uart_ra_read_8(dev, SSR) & REG_MASK(SSR_TDRE))) { ; } + + uart_ra_write_8(dev, SCR, reg_val); + k_spin_unlock(&data->lock, key); +} + +static int uart_ra_err_check(const struct device *dev) +{ + struct uart_ra_data *data = dev->data; + + uint8_t reg_val; + int errors = 0; + k_spinlock_key_t key; + + key = k_spin_lock(&data->lock); + reg_val = uart_ra_read_8(dev, SSR); + + if (reg_val & REG_MASK(SSR_PER)) { + errors |= UART_ERROR_PARITY; + } + + if (reg_val & REG_MASK(SSR_FER)) { + errors |= UART_ERROR_FRAMING; + } + + if (reg_val & REG_MASK(SSR_ORER)) { + errors |= UART_ERROR_OVERRUN; + } + + reg_val &= ~(REG_MASK(SSR_PER) | REG_MASK(SSR_FER) | REG_MASK(SSR_ORER)); + uart_ra_write_8(dev, SSR, reg_val); + k_spin_unlock(&data->lock, key); + + return errors; } static int uart_ra_configure(const struct device *dev, @@ -345,16 +411,257 @@ static int uart_ra_init(const struct device *dev) return ret; } +#ifdef CONFIG_UART_INTERRUPT_DRIVEN + ret = config->irq_config_func(dev); + if (ret != 0) { + return ret; + } +#endif + return 0; } +#ifdef CONFIG_UART_INTERRUPT_DRIVEN + +static bool uart_ra_irq_is_enabled(const struct device *dev, + uint32_t irq) +{ + return uart_ra_read_8(dev, SCR) & irq; +} + +static int uart_ra_fifo_fill(const struct device *dev, + const uint8_t *tx_data, + int len) +{ + struct uart_ra_data *data = dev->data; + uint8_t reg_val; + k_spinlock_key_t key; + + if (len <= 0 || tx_data == NULL) { + return 0; + } + + key = k_spin_lock(&data->lock); + reg_val = uart_ra_read_8(dev, SCR); + reg_val &= ~(REG_MASK(SCR_TIE)); + uart_ra_write_8(dev, SCR, reg_val); + + uart_ra_write_8(dev, TDR, tx_data[0]); + + reg_val |= REG_MASK(SCR_TIE); + uart_ra_write_8(dev, SCR, reg_val); + + k_spin_unlock(&data->lock, key); + + return 1; +} + +static int uart_ra_fifo_read(const struct device *dev, uint8_t *rx_data, + const int size) +{ + uint8_t data; + + if (size <= 0) { + return 0; + } + + if ((uart_ra_read_8(dev, SSR) & REG_MASK(SSR_RDRF)) == 0) { + return 0; + } + + data = uart_ra_read_8(dev, RDR); + + if (rx_data) { + rx_data[0] = data; + } + + return 1; +} + +static void uart_ra_irq_tx_enable(const struct device *dev) +{ + struct uart_ra_data *data = dev->data; + k_spinlock_key_t key; + uint16_t reg_val; + + key = k_spin_lock(&data->lock); + + reg_val = uart_ra_read_8(dev, SCR); + reg_val |= (REG_MASK(SCR_TIE)); + uart_ra_write_8(dev, SCR, reg_val); + + irq_enable(data->irqn[UART_RA_INT_TXI]); + + k_spin_unlock(&data->lock, key); +} + +static void uart_ra_irq_tx_disable(const struct device *dev) +{ + struct uart_ra_data *data = dev->data; + k_spinlock_key_t key; + uint16_t reg_val; + + key = k_spin_lock(&data->lock); + + reg_val = uart_ra_read_8(dev, SCR); + reg_val &= ~(REG_MASK(SCR_TIE)); + uart_ra_write_8(dev, SCR, reg_val); + + irq_disable(data->irqn[UART_RA_INT_TXI]); + + k_spin_unlock(&data->lock, key); +} + +static int uart_ra_irq_tx_ready(const struct device *dev) +{ + const uint8_t reg_val = uart_ra_read_8(dev, SSR); + const uint8_t mask = REG_MASK(SSR_TEND) & REG_MASK(SSR_TDRE); + + return (reg_val & mask) == mask; +} + +static void uart_ra_irq_rx_enable(const struct device *dev) +{ + struct uart_ra_data *data = dev->data; + k_spinlock_key_t key; + uint16_t reg_val; + + key = k_spin_lock(&data->lock); + + reg_val = uart_ra_read_8(dev, SCR); + reg_val |= REG_MASK(SCR_RIE); + uart_ra_write_8(dev, SCR, reg_val); + + irq_enable(data->irqn[UART_RA_INT_RXI]); + + k_spin_unlock(&data->lock, key); +} + +static void uart_ra_irq_rx_disable(const struct device *dev) +{ + struct uart_ra_data *data = dev->data; + k_spinlock_key_t key; + uint16_t reg_val; + + key = k_spin_lock(&data->lock); + + reg_val = uart_ra_read_8(dev, SCR); + reg_val &= ~REG_MASK(SCR_RIE); + uart_ra_write_8(dev, SCR, reg_val); + + irq_disable(data->irqn[UART_RA_INT_RXI]); + + k_spin_unlock(&data->lock, key); +} + +static int uart_ra_irq_rx_ready(const struct device *dev) +{ + return !!(uart_ra_read_8(dev, SSR) & REG_MASK(SSR_RDRF)); +} + +static void uart_ra_irq_err_enable(const struct device *dev) +{ + struct uart_ra_data *data = dev->data; + + irq_enable(data->irqn[UART_RA_INT_ERI]); +} + +static void uart_ra_irq_err_disable(const struct device *dev) +{ + struct uart_ra_data *data = dev->data; + + irq_disable(data->irqn[UART_RA_INT_ERI]); +} + +static int uart_ra_irq_is_pending(const struct device *dev) +{ + return (uart_ra_irq_rx_ready(dev) && uart_ra_irq_is_enabled(dev, REG_MASK(SCR_RIE))) || + (uart_ra_irq_tx_ready(dev) && uart_ra_irq_is_enabled(dev, REG_MASK(SCR_TIE))); +} + +static int uart_ra_irq_update(const struct device *dev) +{ + return 1; +} + +static void uart_ra_irq_callback_set(const struct device *dev, + uart_irq_callback_user_data_t cb, + void *cb_data) +{ + struct uart_ra_data *data = dev->data; + + data->callback = cb; + data->cb_data = cb_data; +} + +/** + * @brief Interrupt service routine. + * + * This simply calls the callback function, if one exists. + * + * @param arg Argument to ISR. + */ +static inline void uart_ra_isr(const struct device *dev) +{ + struct uart_ra_data *data = dev->data; + + if (data->callback) { + data->callback(dev, data->cb_data); + } +} + +static void uart_ra_isr_rxi(const void *param) +{ + const struct device *dev = param; + struct uart_ra_data *data = dev->data; + + uart_ra_isr(dev); + ra_icu_clear_int_flag(data->irqn[UART_RA_INT_RXI]); +} + +static void uart_ra_isr_txi(const void *param) +{ + const struct device *dev = param; + struct uart_ra_data *data = dev->data; + + uart_ra_isr(dev); + ra_icu_clear_int_flag(data->irqn[UART_RA_INT_TXI]); +} + +static void uart_ra_isr_eri(const void *param) +{ + const struct device *dev = param; + struct uart_ra_data *data = dev->data; + + uart_ra_isr(dev); + ra_icu_clear_int_flag(data->irqn[UART_RA_INT_ERI]); +} + +#endif /* CONFIG_UART_INTERRUPT_DRIVEN */ + static const struct uart_driver_api uart_ra_driver_api = { .poll_in = uart_ra_poll_in, .poll_out = uart_ra_poll_out, + .err_check = uart_ra_err_check, #ifdef CONFIG_UART_USE_RUNTIME_CONFIGURE .configure = uart_ra_configure, .config_get = uart_ra_config_get, #endif +#ifdef CONFIG_UART_INTERRUPT_DRIVEN + .fifo_fill = uart_ra_fifo_fill, + .fifo_read = uart_ra_fifo_read, + .irq_tx_enable = uart_ra_irq_tx_enable, + .irq_tx_disable = uart_ra_irq_tx_disable, + .irq_tx_ready = uart_ra_irq_tx_ready, + .irq_rx_enable = uart_ra_irq_rx_enable, + .irq_rx_disable = uart_ra_irq_rx_disable, + .irq_rx_ready = uart_ra_irq_rx_ready, + .irq_err_enable = uart_ra_irq_err_enable, + .irq_err_disable = uart_ra_irq_err_disable, + .irq_is_pending = uart_ra_irq_is_pending, + .irq_update = uart_ra_irq_update, + .irq_callback_set = uart_ra_irq_callback_set, +#endif /* CONFIG_UART_INTERRUPT_DRIVEN */ }; /* Device Instantiation */ @@ -366,28 +673,70 @@ static const struct uart_driver_api uart_ra_driver_api = { .clock_id = \ (clock_control_subsys_t)DT_CLOCKS_CELL_BY_IDX(DT_INST_PARENT(n), 0, id), \ .pcfg = PINCTRL_DT_DEV_CONFIG_GET(DT_INST_PARENT(n)), \ + IF_ENABLED(CONFIG_UART_INTERRUPT_DRIVEN, ( \ + .irq_config_func = irq_config_func_##n, \ + )) \ } -#define UART_RA_INIT(n) \ - UART_RA_INIT_CFG(n); \ - \ - static struct uart_ra_data uart_ra_data_##n = { \ - .current_config = { \ - .baudrate = DT_INST_PROP(n, current_speed), \ - .parity = UART_CFG_PARITY_NONE, \ - .stop_bits = UART_CFG_STOP_BITS_1, \ - .data_bits = UART_CFG_DATA_BITS_8, \ - .flow_ctrl = UART_CFG_FLOW_CTRL_NONE, \ - }, \ - }; \ - \ - DEVICE_DT_INST_DEFINE(n, \ - uart_ra_init, \ - NULL, \ - &uart_ra_data_##n, \ - &uart_ra_cfg_##n, \ - PRE_KERNEL_1, CONFIG_SERIAL_INIT_PRIORITY, \ - &uart_ra_driver_api); \ - \ +#ifdef CONFIG_UART_INTERRUPT_DRIVEN + +#define RA_IRQ_CONNECT_DYNAMIC(n, name, dev, isr) \ + ra_icu_irq_connect_dynamic(DT_IRQ_BY_NAME(DT_INST_PARENT(n), name, irq), \ + DT_IRQ_BY_NAME(DT_INST_PARENT(n), name, priority), isr, dev, \ + DT_IRQ_BY_NAME(DT_INST_PARENT(n), name, flags)); + +#define RA_IRQ_DISCONNECT_DYNAMIC(n, name, dev, isr) \ + ra_icu_irq_disconnect_dynamic(irqn, 0, NULL, NULL, 0) + +#define UART_RA_CONFIG_FUNC(n) \ + static int irq_config_func_##n(const struct device *dev) \ + { \ + struct uart_ra_data *data = dev->data; \ + int irqn; \ + \ + irqn = RA_IRQ_CONNECT_DYNAMIC(n, rxi, dev, uart_ra_isr_rxi); \ + if (irqn < 0) { \ + return irqn; \ + } \ + data->irqn[UART_RA_INT_RXI] = irqn; \ + irqn = RA_IRQ_CONNECT_DYNAMIC(n, txi, dev, uart_ra_isr_txi); \ + if (irqn < 0) { \ + goto err_txi; \ + } \ + data->irqn[UART_RA_INT_TXI] = irqn; \ + irqn = RA_IRQ_CONNECT_DYNAMIC(n, eri, dev, uart_ra_isr_eri); \ + if (irqn < 0) { \ + goto err_eri; \ + } \ + data->irqn[UART_RA_INT_ERI] = irqn; \ + return 0; \ + \ +err_eri: \ + RA_IRQ_DISCONNECT_DYNAMIC(data->irq[UART_RA_INT_TXI], eri, dev, uart_ra_isr_eri); \ +err_txi: \ + RA_IRQ_DISCONNECT_DYNAMIC(data->irq[UART_RA_INT_RXI], txi, dev, uart_ra_isr_txi); \ + \ + return irqn; \ + } +#else +#define UART_RA_CONFIG_FUNC(n) +#endif + +#define UART_RA_INIT(n) \ + UART_RA_CONFIG_FUNC(n) \ + UART_RA_INIT_CFG(n); \ + \ + static struct uart_ra_data uart_ra_data_##n = { \ + .current_config = { \ + .baudrate = DT_INST_PROP(n, current_speed), \ + .parity = UART_CFG_PARITY_NONE, \ + .stop_bits = UART_CFG_STOP_BITS_1, \ + .data_bits = UART_CFG_DATA_BITS_8, \ + .flow_ctrl = UART_CFG_FLOW_CTRL_NONE, \ + }, \ + }; \ + \ + DEVICE_DT_INST_DEFINE(n, uart_ra_init, NULL, &uart_ra_data_##n, &uart_ra_cfg_##n, \ + PRE_KERNEL_1, CONFIG_SERIAL_INIT_PRIORITY, &uart_ra_driver_api); DT_INST_FOREACH_STATUS_OKAY(UART_RA_INIT) From e6486bf598c391b4e30372b50255cf5bbb84cddd Mon Sep 17 00:00:00 2001 From: TOKITA Hiroshi Date: Sat, 30 Dec 2023 21:34:56 +0900 Subject: [PATCH 1648/3723] drivers: interrupt_controller: ra_icu: minor cleanups - Corrected indentation with clang-format Signed-off-by: TOKITA Hiroshi --- drivers/interrupt_controller/intc_ra_icu.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/drivers/interrupt_controller/intc_ra_icu.c b/drivers/interrupt_controller/intc_ra_icu.c index 1b9c2294758..57b9ac731ab 100644 --- a/drivers/interrupt_controller/intc_ra_icu.c +++ b/drivers/interrupt_controller/intc_ra_icu.c @@ -121,5 +121,4 @@ int ra_icu_irq_disconnect_dynamic(unsigned int irq, unsigned int priority, return 0; } -DEVICE_DT_INST_DEFINE(0, NULL, NULL, NULL, NULL, PRE_KERNEL_1, CONFIG_INTC_INIT_PRIORITY, - NULL); +DEVICE_DT_INST_DEFINE(0, NULL, NULL, NULL, NULL, PRE_KERNEL_1, CONFIG_INTC_INIT_PRIORITY, NULL); From 89982b711bbda3cdeb2da6a7250ccab4f088ba10 Mon Sep 17 00:00:00 2001 From: TOKITA Hiroshi Date: Sat, 30 Dec 2023 21:35:43 +0900 Subject: [PATCH 1649/3723] drivers: serial: ra: minor cleanups - Corrected indentation with clang-format Signed-off-by: TOKITA Hiroshi --- drivers/serial/uart_ra.c | 34 +++++++++++----------------------- 1 file changed, 11 insertions(+), 23 deletions(-) diff --git a/drivers/serial/uart_ra.c b/drivers/serial/uart_ra.c index 4dcc1174502..f9c1607bfca 100644 --- a/drivers/serial/uart_ra.c +++ b/drivers/serial/uart_ra.c @@ -182,40 +182,35 @@ struct uart_ra_data { #define LSR_PNUM_POS (8) #define LSR_PNUM_LEN (5) -static uint8_t uart_ra_read_8(const struct device *dev, - uint32_t offs) +static uint8_t uart_ra_read_8(const struct device *dev, uint32_t offs) { const struct uart_ra_cfg *config = dev->config; return sys_read8(config->regs + offs); } -static void uart_ra_write_8(const struct device *dev, - uint32_t offs, uint8_t value) +static void uart_ra_write_8(const struct device *dev, uint32_t offs, uint8_t value) { const struct uart_ra_cfg *config = dev->config; sys_write8(value, config->regs + offs); } -static uint16_t uart_ra_read_16(const struct device *dev, - uint32_t offs) +static uint16_t uart_ra_read_16(const struct device *dev, uint32_t offs) { const struct uart_ra_cfg *config = dev->config; return sys_read16(config->regs + offs); } -static void uart_ra_write_16(const struct device *dev, - uint32_t offs, uint16_t value) +static void uart_ra_write_16(const struct device *dev, uint32_t offs, uint16_t value) { const struct uart_ra_cfg *config = dev->config; sys_write16(value, config->regs + offs); } -static void uart_ra_set_baudrate(const struct device *dev, - uint32_t baud_rate) +static void uart_ra_set_baudrate(const struct device *dev, uint32_t baud_rate) { struct uart_ra_data *data = dev->data; uint8_t reg_val; @@ -310,8 +305,7 @@ static int uart_ra_err_check(const struct device *dev) return errors; } -static int uart_ra_configure(const struct device *dev, - const struct uart_config *cfg) +static int uart_ra_configure(const struct device *dev, const struct uart_config *cfg) { struct uart_ra_data *data = dev->data; @@ -369,8 +363,7 @@ static int uart_ra_configure(const struct device *dev, } #ifdef CONFIG_UART_USE_RUNTIME_CONFIGURE -static int uart_ra_config_get(const struct device *dev, - struct uart_config *cfg) +static int uart_ra_config_get(const struct device *dev, struct uart_config *cfg) { struct uart_ra_data *data = dev->data; @@ -423,15 +416,12 @@ static int uart_ra_init(const struct device *dev) #ifdef CONFIG_UART_INTERRUPT_DRIVEN -static bool uart_ra_irq_is_enabled(const struct device *dev, - uint32_t irq) +static bool uart_ra_irq_is_enabled(const struct device *dev, uint32_t irq) { return uart_ra_read_8(dev, SCR) & irq; } -static int uart_ra_fifo_fill(const struct device *dev, - const uint8_t *tx_data, - int len) +static int uart_ra_fifo_fill(const struct device *dev, const uint8_t *tx_data, int len) { struct uart_ra_data *data = dev->data; uint8_t reg_val; @@ -456,8 +446,7 @@ static int uart_ra_fifo_fill(const struct device *dev, return 1; } -static int uart_ra_fifo_read(const struct device *dev, uint8_t *rx_data, - const int size) +static int uart_ra_fifo_read(const struct device *dev, uint8_t *rx_data, const int size) { uint8_t data; @@ -584,8 +573,7 @@ static int uart_ra_irq_update(const struct device *dev) return 1; } -static void uart_ra_irq_callback_set(const struct device *dev, - uart_irq_callback_user_data_t cb, +static void uart_ra_irq_callback_set(const struct device *dev, uart_irq_callback_user_data_t cb, void *cb_data) { struct uart_ra_data *data = dev->data; From 054353a75daac5522a765251201e93b4a722882f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?J=C4=99drzej=20Ciupis?= Date: Mon, 18 Dec 2023 12:15:56 +0100 Subject: [PATCH 1650/3723] modules: hal_nordic: reorganize nrf_802154 Kconfig MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit There are multiple Kconfig symbols that are only available when the radio hardware is present. As a result, the nRF 802.15.4 radio driver is more difficult to configure on multicore architectures. Also, such solution goes against the principle of hiding the details of the platform behind the driver's interface. This commit moves all the Kconfig options that correspond to settings present in common nRF 802.15.4 configuration header so that they're available no matter if the API is serialized. Signed-off-by: Jędrzej Ciupis --- modules/hal_nordic/Kconfig | 119 +++++++++---------- modules/hal_nordic/nrf_802154/CMakeLists.txt | 46 ++++--- 2 files changed, 75 insertions(+), 90 deletions(-) diff --git a/modules/hal_nordic/Kconfig b/modules/hal_nordic/Kconfig index 44c12e88685..b461c094ef4 100644 --- a/modules/hal_nordic/Kconfig +++ b/modules/hal_nordic/Kconfig @@ -43,30 +43,6 @@ config NRF_802154_MULTIPROTOCOL_SUPPORT in the driver, this option must be enabled. Otherwise, the driver assumes that access to the radio peripheral is granted indefinitely. -config NRF_802154_ENCRYPTION - bool "nRF 802.15.4 AES-CCM* authentication & encryption" - depends on !CRYPTO_NRF_ECB - -choice NRF_802154_CCA_MODE - prompt "nRF IEEE 802.15.4 CCA mode" - default NRF_802154_CCA_MODE_ED - help - CCA mode - -config NRF_802154_CCA_MODE_ED - bool "Energy Above Threshold" - -config NRF_802154_CCA_MODE_CARRIER - bool "Carrier Seen" - -config NRF_802154_CCA_MODE_CARRIER_AND_ED - bool "Energy Above Threshold AND Carrier Seen" - -config NRF_802154_CCA_MODE_CARRIER_OR_ED - bool "Energy Above Threshold OR Carrier Seen" - -endchoice - choice NRF_802154_SL_TYPE prompt "nRF IEEE 802.15.4 Service Layer Type" @@ -77,43 +53,6 @@ config NRF_802154_SL_OPENSOURCE endchoice -config NRF_802154_CCA_ED_THRESHOLD - int "nRF IEEE 802.15.4 CCA Energy Detection threshold" - default 45 - help - If energy detected in a given channel is above the value then the - channel is deemed busy. The unit is defined as per 802.15.4-2006 spec. - -config NRF_802154_CCA_CORR_THRESHOLD - int "nRF IEEE 802.15.4 CCA Correlator threshold" - default 45 - -config NRF_802154_CCA_CORR_LIMIT - int "nRF IEEE 802.15.4 CCA Correlator limit" - default 2 - help - Limit for occurrences above correlator threshold. When not equal to - zero the correlator based signal detect is enabled. - -config NRF_802154_PENDING_SHORT_ADDRESSES - int "nRF 802.15.4 pending short addresses" - default 16 - help - Number of slots containing short addresses of nodes for which pending data is stored - -config NRF_802154_PENDING_EXTENDED_ADDRESSES - int "nRF 802.15.4 pending extended addresses" - default 16 - help - Number of slots containing extended addresses of nodes for which pending data is stored - -config NRF_802154_RX_BUFFERS - int "nRF 802.15.4 receive buffers" - default 16 - help - Number of buffers in nRF 802.15.4 driver receive queue. If this value is modified, - its serialization host counterpart must be set to the exact same value. - config NRF_802154_TEMPERATURE_UPDATE bool "nRF 802.15.4 temperature update" default y @@ -192,7 +131,47 @@ config NRF_802154_SER_DEFAULT_RESPONSE_TIMEOUT This option specifies default timeout of spinel status response in milliseconds. -if NRF_802154_SER_HOST +endmenu # NRF_802154_SER_HOST || NRF_802154_SER_RADIO + +if NRF_802154_RADIO_DRIVER || NRF_802154_SERIALIZATION + +choice NRF_802154_CCA_MODE + prompt "nRF IEEE 802.15.4 CCA mode" + default NRF_802154_CCA_MODE_ED + help + CCA mode + +config NRF_802154_CCA_MODE_ED + bool "Energy Above Threshold" + +config NRF_802154_CCA_MODE_CARRIER + bool "Carrier Seen" + +config NRF_802154_CCA_MODE_CARRIER_AND_ED + bool "Energy Above Threshold AND Carrier Seen" + +config NRF_802154_CCA_MODE_CARRIER_OR_ED + bool "Energy Above Threshold OR Carrier Seen" + +endchoice + +config NRF_802154_CCA_ED_THRESHOLD + int "nRF IEEE 802.15.4 CCA Energy Detection threshold" + default 45 + help + If energy detected in a given channel is above the value then the + channel is deemed busy. The unit is defined as per 802.15.4-2006 spec. + +config NRF_802154_CCA_CORR_THRESHOLD + int "nRF IEEE 802.15.4 CCA Correlator threshold" + default 45 + +config NRF_802154_CCA_CORR_LIMIT + int "nRF IEEE 802.15.4 CCA Correlator limit" + default 2 + help + Limit for occurrences above correlator threshold. When not equal to + zero the correlator based signal detect is enabled. config NRF_802154_RX_BUFFERS int "nRF 802.15.4 receive buffers" @@ -201,11 +180,21 @@ config NRF_802154_RX_BUFFERS Number of buffers in nRF 802.15.4 driver serialization host's receive queue. If this value is modified, its remote counterpart must be set to the exact same value. -endif +config NRF_802154_PENDING_SHORT_ADDRESSES + int "nRF 802.15.4 pending short addresses" + default 16 + help + Number of slots containing short addresses of nodes for which pending data is stored -endmenu # NRF_802154_SER_HOST || NRF_802154_SER_RADIO +config NRF_802154_PENDING_EXTENDED_ADDRESSES + int "nRF 802.15.4 pending extended addresses" + default 16 + help + Number of slots containing extended addresses of nodes for which pending data is stored -if NRF_802154_RADIO_DRIVER || NRF_802154_SERIALIZATION +config NRF_802154_ENCRYPTION + bool "nRF 802.15.4 AES-CCM* authentication & encryption" + depends on !CRYPTO_NRF_ECB config NRF_802154_CARRIER_FUNCTIONS bool "nRF 802.15.4 carrier functions" diff --git a/modules/hal_nordic/nrf_802154/CMakeLists.txt b/modules/hal_nordic/nrf_802154/CMakeLists.txt index cd5ace0b278..a274a019e25 100644 --- a/modules/hal_nordic/nrf_802154/CMakeLists.txt +++ b/modules/hal_nordic/nrf_802154/CMakeLists.txt @@ -12,24 +12,6 @@ if (CONFIG_NRF_802154_RADIO_DRIVER) sl_opensource/platform/nrf_802154_irq_zephyr.c sl_opensource/platform/nrf_802154_temperature_zephyr.c ) - - target_compile_definitions(zephyr-802154-interface - INTERFACE - # CCA mode options - NRF_802154_CCA_CORR_LIMIT_DEFAULT=${CONFIG_NRF_802154_CCA_CORR_LIMIT} - NRF_802154_CCA_CORR_THRESHOLD_DEFAULT=${CONFIG_NRF_802154_CCA_CORR_THRESHOLD} - NRF_802154_CCA_ED_THRESHOLD_DEFAULT=${CONFIG_NRF_802154_CCA_ED_THRESHOLD} - ) - - if (CONFIG_NRF_802154_CCA_MODE_ED) - target_compile_definitions(zephyr-802154-interface INTERFACE NRF_802154_CCA_MODE_DEFAULT=NRF_RADIO_CCA_MODE_ED) - elseif (CONFIG_NRF_802154_CCA_MODE_CARRIER) - target_compile_definitions(zephyr-802154-interface INTERFACE NRF_802154_CCA_MODE_DEFAULT=NRF_RADIO_CCA_MODE_CARRIER) - elseif (CONFIG_NRF_802154_CCA_MODE_CARRIER_AND_ED) - target_compile_definitions(zephyr-802154-interface INTERFACE NRF_802154_CCA_MODE_DEFAULT=NRF_RADIO_CCA_MODE_CARRIER_AND_ED) - elseif (CONFIG_NRF_802154_CCA_MODE_CARRIER_OR_ED) - target_compile_definitions(zephyr-802154-interface INTERFACE NRF_802154_CCA_MODE_DEFAULT=NRF_RADIO_CCA_MODE_CARRIER_OR_ED) - endif() endif () if (CONFIG_NRF_802154_SERIALIZATION) @@ -69,8 +51,23 @@ target_compile_definitions(zephyr-802154-interface # ACK timeout NRF_802154_ACK_TIMEOUT_ENABLED=1 + + # CCA mode options + NRF_802154_CCA_CORR_LIMIT_DEFAULT=${CONFIG_NRF_802154_CCA_CORR_LIMIT} + NRF_802154_CCA_CORR_THRESHOLD_DEFAULT=${CONFIG_NRF_802154_CCA_CORR_THRESHOLD} + NRF_802154_CCA_ED_THRESHOLD_DEFAULT=${CONFIG_NRF_802154_CCA_ED_THRESHOLD} ) +if (CONFIG_NRF_802154_CCA_MODE_ED) + target_compile_definitions(zephyr-802154-interface INTERFACE NRF_802154_CCA_MODE_DEFAULT=NRF_RADIO_CCA_MODE_ED) +elseif (CONFIG_NRF_802154_CCA_MODE_CARRIER) + target_compile_definitions(zephyr-802154-interface INTERFACE NRF_802154_CCA_MODE_DEFAULT=NRF_RADIO_CCA_MODE_CARRIER) +elseif (CONFIG_NRF_802154_CCA_MODE_CARRIER_AND_ED) + target_compile_definitions(zephyr-802154-interface INTERFACE NRF_802154_CCA_MODE_DEFAULT=NRF_RADIO_CCA_MODE_CARRIER_AND_ED) +elseif (CONFIG_NRF_802154_CCA_MODE_CARRIER_OR_ED) + target_compile_definitions(zephyr-802154-interface INTERFACE NRF_802154_CCA_MODE_DEFAULT=NRF_RADIO_CCA_MODE_CARRIER_OR_ED) +endif() + if (CONFIG_NRF_802154_ENCRYPTION) target_compile_definitions(zephyr-802154-interface INTERFACE NRF_802154_ENCRYPTION_ENABLED=1) target_compile_definitions(zephyr-802154-interface INTERFACE NRF_802154_SECURITY_WRITER_ENABLED=1) @@ -93,13 +90,12 @@ else() target_compile_definitions(zephyr-802154-interface INTERFACE NRF_802154_CARRIER_FUNCTIONS_ENABLED=0) endif() -if (CONFIG_NRF_802154_RADIO_DRIVER OR CONFIG_NRF_802154_SERIALIZATION) - target_compile_definitions(zephyr-802154-interface INTERFACE NRF_802154_ENERGY_DETECTED_VERSION=1) - if (CONFIG_NRF_802154_ASSERT_ZEPHYR OR CONFIG_NRF_802154_ASSERT_ZEPHYR_MINIMAL) - target_include_directories(zephyr-802154-interface INTERFACE include) - target_compile_definitions(zephyr-802154-interface INTERFACE NRF_802154_PLATFORM_ASSERT_INCLUDE=\"nrf_802154_assert_zephyr.h\") - target_sources(nrf-802154-platform PRIVATE nrf_802154_assert_handler.c) - endif() +target_compile_definitions(zephyr-802154-interface INTERFACE NRF_802154_ENERGY_DETECTED_VERSION=1) + +if (CONFIG_NRF_802154_ASSERT_ZEPHYR OR CONFIG_NRF_802154_ASSERT_ZEPHYR_MINIMAL) + target_include_directories(zephyr-802154-interface INTERFACE include) + target_compile_definitions(zephyr-802154-interface INTERFACE NRF_802154_PLATFORM_ASSERT_INCLUDE=\"nrf_802154_assert_zephyr.h\") + target_sources(nrf-802154-platform PRIVATE nrf_802154_assert_handler.c) endif() set(NRF52_SERIES ${CONFIG_SOC_SERIES_NRF52X}) From 57ee911891049e5e7845fad1506dca5ab56fb014 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?J=C4=99drzej=20Ciupis?= Date: Mon, 18 Dec 2023 12:20:26 +0100 Subject: [PATCH 1651/3723] modules: hal_nordic: new nrf_802154 configuration option MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This commit adds a new Kconfig for the nRF 802.15.4 radio driver that allows the user to specify the number of encryption keys the driver can simultaneously store. Signed-off-by: Jędrzej Ciupis --- modules/hal_nordic/Kconfig | 6 ++++++ modules/hal_nordic/nrf_802154/CMakeLists.txt | 3 +++ 2 files changed, 9 insertions(+) diff --git a/modules/hal_nordic/Kconfig b/modules/hal_nordic/Kconfig index b461c094ef4..6f77bbea427 100644 --- a/modules/hal_nordic/Kconfig +++ b/modules/hal_nordic/Kconfig @@ -196,6 +196,12 @@ config NRF_802154_ENCRYPTION bool "nRF 802.15.4 AES-CCM* authentication & encryption" depends on !CRYPTO_NRF_ECB +config NRF_802154_SECURITY_KEY_STORAGE_SIZE + int "nRF 802.15.4 security key storage size" + default 3 + help + Number of encryption keys that the nRF 802.15.4 Radio Driver can store simultaneously. + config NRF_802154_CARRIER_FUNCTIONS bool "nRF 802.15.4 carrier functions" help diff --git a/modules/hal_nordic/nrf_802154/CMakeLists.txt b/modules/hal_nordic/nrf_802154/CMakeLists.txt index a274a019e25..763f9625be8 100644 --- a/modules/hal_nordic/nrf_802154/CMakeLists.txt +++ b/modules/hal_nordic/nrf_802154/CMakeLists.txt @@ -56,6 +56,9 @@ target_compile_definitions(zephyr-802154-interface NRF_802154_CCA_CORR_LIMIT_DEFAULT=${CONFIG_NRF_802154_CCA_CORR_LIMIT} NRF_802154_CCA_CORR_THRESHOLD_DEFAULT=${CONFIG_NRF_802154_CCA_CORR_THRESHOLD} NRF_802154_CCA_ED_THRESHOLD_DEFAULT=${CONFIG_NRF_802154_CCA_ED_THRESHOLD} + + # Key storage size + NRF_802154_SECURITY_KEY_STORAGE_SIZE=${CONFIG_NRF_802154_SECURITY_KEY_STORAGE_SIZE} ) if (CONFIG_NRF_802154_CCA_MODE_ED) From 5f8dabf44cfe10dea90b66ccd9b55d767af513dc Mon Sep 17 00:00:00 2001 From: Jamie McCrae Date: Wed, 20 Dec 2023 07:50:31 +0000 Subject: [PATCH 1652/3723] boards: deprecated: Remove boards deprecated pre-Zephyr 2.7 Removes deprecated boards that were added in/before September 2021, which would be prior to the release of Zephyr 2.7. Signed-off-by: Jamie McCrae --- boards/deprecated.cmake | 12 ------------ 1 file changed, 12 deletions(-) diff --git a/boards/deprecated.cmake b/boards/deprecated.cmake index f238347203a..270d5f5e1a9 100644 --- a/boards/deprecated.cmake +++ b/boards/deprecated.cmake @@ -8,16 +8,4 @@ # To add a board rename, add a line in following format: # set(_DEPRECATED ) -set(bl5340_dvk_cpuappns_DEPRECATED bl5340_dvk_cpuapp_ns) -set(bt6x0_DEPRECATED bt610) -set(mps2_an521_nonsecure_DEPRECATED mps2_an521_ns) -set(musca_b1_nonsecure_DEPRECATED musca_b1_ns) -set(musca_s1_nonsecure_DEPRECATED musca_s1_ns) -set(nrf5340dk_nrf5340_cpuappns_DEPRECATED nrf5340dk_nrf5340_cpuapp_ns) -set(nrf9160dk_nrf9160ns_DEPRECATED nrf9160dk_nrf9160_ns) -set(circuitdojo_feather_nrf9160ns_DEPRECATED circuitdojo_feather_nrf9160_ns) -set(nrf9160_innblue21ns_DEPRECATED nrf9160_innblue21_ns) -set(nrf9160_innblue22ns_DEPRECATED nrf9160_innblue22_ns) -set(sparkfun_thing_plus_nrf9160ns_DEPRECATED sparkfun_thing_plus_nrf9160_ns) -set(thingy53_nrf5340_cpuappns_DEPRECATED thingy53_nrf5340_cpuapp_ns) set(esp32_DEPRECATED esp32_devkitc_wrover) From 4e5ef76b15f330a5667a9362605e7a0ca86b668f Mon Sep 17 00:00:00 2001 From: Jukka Rissanen Date: Fri, 22 Dec 2023 13:57:16 +0200 Subject: [PATCH 1653/3723] net: lib: mdns_responder: Fix interface count check The original idea was to check that we have enough network interfaces in the system. The check needs to verify max IPv4 and IPv6 supported interfaces instead of always checking IPv6 one. Fixes: #66843 Coverity-CID: 334899 Signed-off-by: Jukka Rissanen --- subsys/net/lib/dns/mdns_responder.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/subsys/net/lib/dns/mdns_responder.c b/subsys/net/lib/dns/mdns_responder.c index ce9e14511e5..90f958725bc 100644 --- a/subsys/net/lib/dns/mdns_responder.c +++ b/subsys/net/lib/dns/mdns_responder.c @@ -663,7 +663,7 @@ static int init_listener(void) (iface_count > MAX_IPV4_IFACE_COUNT && MAX_IPV4_IFACE_COUNT > 0)) { NET_WARN("You have %d interfaces configured but there " "are %d network interfaces in the system.", - MAX(MAX_IPV6_IFACE_COUNT, + MAX(MAX_IPV4_IFACE_COUNT, MAX_IPV6_IFACE_COUNT), iface_count); } From 8f97c1c2ee9f8de84e04c6ceaa1ee7bf4fe5a4cf Mon Sep 17 00:00:00 2001 From: Jukka Rissanen Date: Fri, 22 Dec 2023 14:09:11 +0200 Subject: [PATCH 1654/3723] net: lib: sockets: Initialize iovec to 0 at start of func Make sure iovec is initialized to a value so that there is no possibility that it is accessed uninitialized. Fixes: #66838 Coverity-CID: 334911 Signed-off-by: Jukka Rissanen --- subsys/net/lib/sockets/sockets.c | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/subsys/net/lib/sockets/sockets.c b/subsys/net/lib/sockets/sockets.c index 4664b18424e..53ff23a9081 100644 --- a/subsys/net/lib/sockets/sockets.c +++ b/subsys/net/lib/sockets/sockets.c @@ -1544,7 +1544,7 @@ static ssize_t zsock_recv_stream_timed(struct net_context *ctx, struct msghdr *m { int res; k_timepoint_t end; - size_t recv_len = 0, iovec, available_len, max_iovlen = 0; + size_t recv_len = 0, iovec = 0, available_len, max_iovlen = 0; const bool waitall = (flags & ZSOCK_MSG_WAITALL) == ZSOCK_MSG_WAITALL; if (msg != NULL && buf == NULL) { @@ -1552,8 +1552,6 @@ static ssize_t zsock_recv_stream_timed(struct net_context *ctx, struct msghdr *m return -EINVAL; } - iovec = 0; - buf = msg->msg_iov[iovec].iov_base; available_len = msg->msg_iov[iovec].iov_len; msg->msg_iov[iovec].iov_len = 0; From b8184ca3b7bb96fe024784f211a2fed4feac13c0 Mon Sep 17 00:00:00 2001 From: Pisit Sawangvonganan Date: Sat, 23 Dec 2023 13:50:33 +0700 Subject: [PATCH 1655/3723] lib: crc: address absence of crc4, crc4_ti in crc_types array Added CRC4 and CRC4_TI to the supported crc_types[] array. On some SoCs, like ESP32-S3, missing values can cause hardfaults due to attempts to access the zero address. Signed-off-by: Pisit Sawangvonganan --- lib/crc/crc_shell.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/lib/crc/crc_shell.c b/lib/crc/crc_shell.c index e75d88623e1..32393ff6f6e 100644 --- a/lib/crc/crc_shell.c +++ b/lib/crc/crc_shell.c @@ -19,9 +19,11 @@ #include static const char *const crc_types[] = { + [CRC4] = "4", + [CRC4_TI] = "4_ti", [CRC7_BE] = "7_be", [CRC8] = "8", - [CRC8_CCITT] "8_ccitt", + [CRC8_CCITT] = "8_ccitt", [CRC16] = "16", [CRC16_ANSI] = "16_ansi", [CRC16_CCITT] = "16_ccitt", From 4ae558c505bf995041e8c4fffa30effdd176b210 Mon Sep 17 00:00:00 2001 From: Junfan Song Date: Fri, 29 Dec 2023 10:58:17 +0800 Subject: [PATCH 1656/3723] kernel: work: Fix race in workqueue thread After a call to k_work_flush returns the sync variable may still be modified by the workq. This is because the work queue thread continues to modify the flag in sync even after k_work_flush returns. This commit adds K_WORK_FLUSHING_BIT, and with this bit, we moved the logic of waking up the caller from handle_flush to the finalize_flush_locked in workq, so that after waking up the caller, the workqueue will no longer operate on sync. Fixes: #64530 Signed-off-by: Junfan Song --- include/zephyr/kernel.h | 17 ++++++++++++----- kernel/work.c | 39 +++++++++++++++++++++++++++++---------- 2 files changed, 41 insertions(+), 15 deletions(-) diff --git a/include/zephyr/kernel.h b/include/zephyr/kernel.h index adf121f72ee..9f2b750d166 100644 --- a/include/zephyr/kernel.h +++ b/include/zephyr/kernel.h @@ -3289,7 +3289,7 @@ void k_work_init(struct k_work *work, * @param work pointer to the work item. * * @return a mask of flags K_WORK_DELAYED, K_WORK_QUEUED, - * K_WORK_RUNNING, and K_WORK_CANCELING. + * K_WORK_RUNNING, K_WORK_CANCELING, and K_WORK_FLUSHING. */ int k_work_busy_get(const struct k_work *work); @@ -3545,9 +3545,9 @@ k_work_delayable_from_work(struct k_work *work); * * @param dwork pointer to the delayable work item. * - * @return a mask of flags K_WORK_DELAYED, K_WORK_QUEUED, K_WORK_RUNNING, and - * K_WORK_CANCELING. A zero return value indicates the work item appears to - * be idle. + * @return a mask of flags K_WORK_DELAYED, K_WORK_QUEUED, K_WORK_RUNNING, + * K_WORK_CANCELING, and K_WORK_FLUSHING. A zero return value indicates the + * work item appears to be idle. */ int k_work_delayable_busy_get(const struct k_work_delayable *dwork); @@ -3795,9 +3795,10 @@ enum { K_WORK_CANCELING_BIT = 1, K_WORK_QUEUED_BIT = 2, K_WORK_DELAYED_BIT = 3, + K_WORK_FLUSHING_BIT = 4, K_WORK_MASK = BIT(K_WORK_DELAYED_BIT) | BIT(K_WORK_QUEUED_BIT) - | BIT(K_WORK_RUNNING_BIT) | BIT(K_WORK_CANCELING_BIT), + | BIT(K_WORK_RUNNING_BIT) | BIT(K_WORK_CANCELING_BIT) | BIT(K_WORK_FLUSHING_BIT), /* Static work flags */ K_WORK_DELAYABLE_BIT = 8, @@ -3848,6 +3849,12 @@ enum { * Accessed via k_work_busy_get(). May co-occur with other flags. */ K_WORK_DELAYED = BIT(K_WORK_DELAYED_BIT), + + /** @brief Flag indicating a synced work item that is being flushed. + * + * Accessed via k_work_busy_get(). May co-occur with other flags. + */ + K_WORK_FLUSHING = BIT(K_WORK_FLUSHING_BIT), }; /** @brief A structure used to submit work. */ diff --git a/kernel/work.c b/kernel/work.c index c5d7c9b5bb8..a56aa67829c 100644 --- a/kernel/work.c +++ b/kernel/work.c @@ -63,18 +63,14 @@ static inline uint32_t flags_get(const uint32_t *flagp) static struct k_spinlock lock; /* Invoked by work thread */ -static void handle_flush(struct k_work *work) -{ - struct z_work_flusher *flusher - = CONTAINER_OF(work, struct z_work_flusher, work); - - k_sem_give(&flusher->sem); -} +static void handle_flush(struct k_work *work) { } static inline void init_flusher(struct z_work_flusher *flusher) { + struct k_work *work = &flusher->work; k_sem_init(&flusher->sem, 0, 1); k_work_init(&flusher->work, handle_flush); + flag_set(&work->flags, K_WORK_FLUSHING_BIT); } /* List of pending cancellations. */ @@ -96,6 +92,26 @@ static inline void init_work_cancel(struct z_work_canceller *canceler, sys_slist_append(&pending_cancels, &canceler->node); } +/* Comeplete flushing of a work item. + * + * Invoked with work lock held. + * + * Invoked from a work queue thread. + * + * Reschedules. + * + * @param work the work structure that has completed flushing. + */ +static void finalize_flush_locked(struct k_work *work) +{ + struct z_work_flusher *flusher + = CONTAINER_OF(work, struct z_work_flusher, work); + + flag_clear(&work->flags, K_WORK_FLUSHING_BIT); + + k_sem_give(&flusher->sem); +}; + /* Complete cancellation of a work item and unlock held lock. * * Invoked with work lock held. @@ -672,13 +688,16 @@ static void work_queue_main(void *workq_ptr, void *p2, void *p3) handler(work); /* Mark the work item as no longer running and deal - * with any cancellation issued while it was running. - * Clear the BUSY flag and optionally yield to prevent - * starving other threads. + * with any cancellation and flushing issued while it + * was running. Clear the BUSY flag and optionally + * yield to prevent starving other threads. */ key = k_spin_lock(&lock); flag_clear(&work->flags, K_WORK_RUNNING_BIT); + if (flag_test(&work->flags, K_WORK_FLUSHING_BIT)) { + finalize_flush_locked(work); + } if (flag_test(&work->flags, K_WORK_CANCELING_BIT)) { finalize_cancel_locked(work); } From 173e4983fdc9094ef5c0480ec196014aa1c57bfd Mon Sep 17 00:00:00 2001 From: Chun-Chieh Li Date: Thu, 21 Dec 2023 15:05:04 +0800 Subject: [PATCH 1657/3723] drivers: wifi: esp_at: fix last rx data loss in Passive Receive mode In Passive Receive mode, ESP modem will buffer rx data. This fix makes the data still available to user, even though the peer has closed the socket. Otherwise, user will fail to get the last rx data, when the socket is closed by the peer. Signed-off-by: Chun-Chieh Li --- drivers/wifi/esp_at/esp_socket.c | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/drivers/wifi/esp_at/esp_socket.c b/drivers/wifi/esp_at/esp_socket.c index e3600ea5366..6a4147e528b 100644 --- a/drivers/wifi/esp_at/esp_socket.c +++ b/drivers/wifi/esp_at/esp_socket.c @@ -151,8 +151,16 @@ void esp_socket_rx(struct esp_socket *sock, struct net_buf *buf, flags = esp_socket_flags(sock); +#ifdef CONFIG_WIFI_ESP_AT_PASSIVE_MODE + /* In Passive Receive mode, ESP modem will buffer rx data and make it still + * available even though the peer has closed the connection. + */ + if (!(flags & ESP_SOCK_CONNECTED) && + !(flags & ESP_SOCK_CLOSE_PENDING)) { +#else if (!(flags & ESP_SOCK_CONNECTED) || (flags & ESP_SOCK_CLOSE_PENDING)) { +#endif LOG_DBG("Received data on closed link %d", sock->link_id); return; } From 6f55309659ed8fd5d96d7ecf4819a7987e43bd23 Mon Sep 17 00:00:00 2001 From: Bjarki Arge Andreasen Date: Fri, 29 Dec 2023 10:44:28 +0100 Subject: [PATCH 1658/3723] modem: cellular: Restructure cellular API to fit device driver model The current cellular API header is not written to conform with the device driver model. This commit fixes that. Signed-off-by: Bjarki Arge Andreasen --- include/zephyr/drivers/cellular.h | 100 +++++++++++++++++++++++++++--- 1 file changed, 92 insertions(+), 8 deletions(-) diff --git a/include/zephyr/drivers/cellular.h b/include/zephyr/drivers/cellular.h index 445cd83857c..b4202d81b0a 100644 --- a/include/zephyr/drivers/cellular.h +++ b/include/zephyr/drivers/cellular.h @@ -53,6 +53,7 @@ struct cellular_network { uint16_t size; }; +/** Cellular signal type */ enum cellular_signal_type { CELLULAR_SIGNAL_RSSI, CELLULAR_SIGNAL_RSRP, @@ -75,6 +76,33 @@ enum cellular_modem_info_type { CELLULAR_MODEM_INFO_SIM_ICCID, }; +/** API for configuring networks */ +typedef int (*cellular_api_configure_networks)(const struct device *dev, + const struct cellular_network *networks, + uint8_t size); + +/** API for getting supported networks */ +typedef int (*cellular_api_get_supported_networks)(const struct device *dev, + const struct cellular_network **networks, + uint8_t *size); + +/** API for getting network signal strength */ +typedef int (*cellular_api_get_signal)(const struct device *dev, + const enum cellular_signal_type type, int16_t *value); + +/** API for getting modem information */ +typedef int (*cellular_api_get_modem_info)(const struct device *dev, + const enum cellular_modem_info_type type, + char *info, size_t size); + +/** Cellular driver API */ +__subsystem struct cellular_driver_api { + cellular_api_configure_networks configure_networks; + cellular_api_get_supported_networks get_supported_networks; + cellular_api_get_signal get_signal; + cellular_api_get_modem_info get_modem_info; +}; + /** * @brief Configure cellular networks for the device * @@ -96,8 +124,21 @@ enum cellular_modem_info_type { * @retval -ENOTSUP if API is not supported by cellular network device. * @retval Negative errno-code otherwise. */ -int cellular_configure_networks(const struct device *dev, const struct cellular_network *networks, - uint8_t size); +__syscall int cellular_configure_networks(const struct device *dev, + const struct cellular_network *networks, uint8_t size); + +static inline int z_impl_cellular_configure_networks(const struct device *dev, + const struct cellular_network *networks, + uint8_t size) +{ + const struct cellular_driver_api *api = (const struct cellular_driver_api *)dev->api; + + if (api->configure_networks == NULL) { + return -ENOTSUP; + } + + return api->configure_networks(dev, networks, size); +} /** * @brief Get supported cellular networks for the device @@ -110,8 +151,22 @@ int cellular_configure_networks(const struct device *dev, const struct cellular_ * @retval -ENOTSUP if API is not supported by cellular network device. * @retval Negative errno-code otherwise. */ -int cellular_get_supported_networks(const struct device *dev, - const struct cellular_network **networks, uint8_t *size); +__syscall int cellular_get_supported_networks(const struct device *dev, + const struct cellular_network **networks, + uint8_t *size); + +static inline int z_impl_cellular_get_supported_networks(const struct device *dev, + const struct cellular_network **networks, + uint8_t *size) +{ + const struct cellular_driver_api *api = (const struct cellular_driver_api *)dev->api; + + if (api->get_supported_networks == NULL) { + return -ENOTSUP; + } + + return api->get_supported_networks(dev, networks, size); +} /** * @brief Get signal for the device @@ -125,8 +180,21 @@ int cellular_get_supported_networks(const struct device *dev, * @retval -ENODATA if device is not in a state where signal can be polled * @retval Negative errno-code otherwise. */ -int cellular_get_signal(const struct device *dev, const enum cellular_signal_type type, - int16_t *value); +__syscall int cellular_get_signal(const struct device *dev, const enum cellular_signal_type type, + int16_t *value); + +static inline int z_impl_cellular_get_signal(const struct device *dev, + const enum cellular_signal_type type, + int16_t *value) +{ + const struct cellular_driver_api *api = (const struct cellular_driver_api *)dev->api; + + if (api->get_signal == NULL) { + return -ENOTSUP; + } + + return api->get_signal(dev, type, value); +} /** * @brief Get modem info for the device @@ -141,8 +209,22 @@ int cellular_get_signal(const struct device *dev, const enum cellular_signal_typ * @retval -ENODATA if modem does not provide info requested * @retval Negative errno-code from chat module otherwise. */ -int cellular_get_modem_info(const struct device *dev, const enum cellular_modem_info_type type, - char *info, size_t size); +__syscall int cellular_get_modem_info(const struct device *dev, + const enum cellular_modem_info_type type, + char *info, size_t size); + +static inline int z_impl_cellular_get_modem_info(const struct device *dev, + const enum cellular_modem_info_type type, + char *info, size_t size) +{ + const struct cellular_driver_api *api = (const struct cellular_driver_api *)dev->api; + + if (api->get_modem_info == NULL) { + return -ENOTSUP; + } + + return api->get_modem_info(dev, type, info, size); +} #ifdef __cplusplus } @@ -152,4 +234,6 @@ int cellular_get_modem_info(const struct device *dev, const enum cellular_modem_ * @} */ +#include + #endif /* ZEPHYR_INCLUDE_DRIVERS_CELLULAR_H_ */ From f9491034bec762be4d99bdb798f758514502075a Mon Sep 17 00:00:00 2001 From: Bjarki Arge Andreasen Date: Fri, 29 Dec 2023 10:48:44 +0100 Subject: [PATCH 1659/3723] modem: modem_cellular: Update driver to implement cellular API Move the implementations of the cellular API in modem_cellular.c to an cellular_driver_structure, and implement this API structure withing the device drivers. Signed-off-by: Bjarki Arge Andreasen --- drivers/modem/modem_cellular.c | 165 ++++++++++++++++-------------- include/zephyr/drivers/cellular.h | 46 +++------ 2 files changed, 104 insertions(+), 107 deletions(-) diff --git a/drivers/modem/modem_cellular.c b/drivers/modem/modem_cellular.c index ad1bb920cd5..ea39cecabaf 100644 --- a/drivers/modem/modem_cellular.c +++ b/drivers/modem/modem_cellular.c @@ -1263,6 +1263,80 @@ static void modem_cellular_cmux_handler(struct modem_cmux *cmux, enum modem_cmux } } +static int modem_cellular_get_signal(const struct device *dev, + const enum cellular_signal_type type, + int16_t *value) +{ + int ret; + struct modem_cellular_data *data = (struct modem_cellular_data *)dev->data; + const struct modem_cellular_config *config = (struct modem_cellular_config *)dev->config; + + if (config->get_signal_chat_script == NULL) { + return -ENOTSUP; + } + + if ((data->state != MODEM_CELLULAR_STATE_AWAIT_REGISTERED) && + (data->state != MODEM_CELLULAR_STATE_CARRIER_ON)) { + return -ENODATA; + } + + ret = modem_chat_run_script(&data->chat, config->get_signal_chat_script); + if (ret != 0) { + return ret; + } + + switch (type) { + case CELLULAR_SIGNAL_RSSI: { + *value = data->rssi; + } break; + case CELLULAR_SIGNAL_RSRP: + return -ENOTSUP; + case CELLULAR_SIGNAL_RSRQ: + return -ENOTSUP; + } + + return ret; +} + +static int modem_cellular_get_modem_info(const struct device *dev, + enum cellular_modem_info_type type, + char *info, size_t size) +{ + int ret = 0; + struct modem_cellular_data *data = (struct modem_cellular_data *)dev->data; + + switch (type) { + case CELLULAR_MODEM_INFO_IMEI: + strncpy(info, &data->imei[0], MIN(size, sizeof(data->imei))); + break; + case CELLULAR_MODEM_INFO_SIM_IMSI: + strncpy(info, &data->imsi[0], MIN(size, sizeof(data->imsi))); + break; + case CELLULAR_MODEM_INFO_SIM_ICCID: + strncpy(info, &data->iccid[0], MIN(size, sizeof(data->iccid))); + break; + case CELLULAR_MODEM_INFO_MANUFACTURER: + strncpy(info, &data->manufacturer[0], MIN(size, sizeof(data->manufacturer))); + break; + case CELLULAR_MODEM_INFO_FW_VERSION: + strncpy(info, &data->fw_version[0], MIN(size, sizeof(data->fw_version))); + break; + case CELLULAR_MODEM_INFO_MODEL_ID: + strncpy(info, &data->model_id[0], MIN(size, sizeof(data->model_id))); + break; + default: + ret = -ENODATA; + break; + } + + return ret; +} + +const static struct cellular_driver_api modem_cellular_api = { + .get_signal = modem_cellular_get_signal, + .get_modem_info = modem_cellular_get_modem_info, +}; + #ifdef CONFIG_PM_DEVICE static int modem_cellular_pm_action(const struct device *dev, enum pm_device_action action) { @@ -1828,7 +1902,8 @@ MODEM_CHAT_SCRIPT_DEFINE(telit_me910g1_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, NULL); + &MODEM_CELLULAR_INST_NAME(config, inst), POST_KERNEL, 99, \ + &modem_cellular_api); #define MODEM_CELLULAR_DEVICE_QUECTEL_EG25_G(inst) \ MODEM_PPP_DEFINE(MODEM_CELLULAR_INST_NAME(ppp, inst), NULL, 98, 1500, 64); \ @@ -1857,7 +1932,8 @@ MODEM_CHAT_SCRIPT_DEFINE(telit_me910g1_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, NULL); + &MODEM_CELLULAR_INST_NAME(config, inst), POST_KERNEL, 99, \ + &modem_cellular_api); #define MODEM_CELLULAR_DEVICE_GSM_PPP(inst) \ MODEM_PPP_DEFINE(MODEM_CELLULAR_INST_NAME(ppp, inst), NULL, 98, 1500, 64); \ @@ -1885,7 +1961,8 @@ MODEM_CHAT_SCRIPT_DEFINE(telit_me910g1_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, NULL); + &MODEM_CELLULAR_INST_NAME(config, inst), POST_KERNEL, 99, \ + &modem_cellular_api); #define MODEM_CELLULAR_DEVICE_SIMCOM_SIM7080(inst) \ MODEM_PPP_DEFINE(MODEM_CELLULAR_INST_NAME(ppp, inst), NULL, 98, 1500, 64); \ @@ -1913,7 +1990,8 @@ MODEM_CHAT_SCRIPT_DEFINE(telit_me910g1_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, NULL); + &MODEM_CELLULAR_INST_NAME(config, inst), POST_KERNEL, 99, \ + &modem_cellular_api); #define MODEM_CELLULAR_DEVICE_U_BLOX_SARA_R4(inst) \ MODEM_PPP_DEFINE(MODEM_CELLULAR_INST_NAME(ppp, inst), NULL, 98, 1500, 64); \ @@ -1941,7 +2019,8 @@ MODEM_CHAT_SCRIPT_DEFINE(telit_me910g1_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, NULL); + &MODEM_CELLULAR_INST_NAME(config, inst), POST_KERNEL, 99, \ + &modem_cellular_api); #define MODEM_CELLULAR_DEVICE_U_BLOX_SARA_R5(inst) \ MODEM_PPP_DEFINE(MODEM_CELLULAR_INST_NAME(ppp, inst), NULL, 98, 1500, 64); \ @@ -1970,7 +2049,8 @@ MODEM_CHAT_SCRIPT_DEFINE(telit_me910g1_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, NULL); + &MODEM_CELLULAR_INST_NAME(config, inst), POST_KERNEL, 99, \ + &modem_cellular_api); #define MODEM_CELLULAR_DEVICE_SWIR_HL7800(inst) \ MODEM_PPP_DEFINE(MODEM_CELLULAR_INST_NAME(ppp, inst), NULL, 98, 1500, 64); \ @@ -1998,7 +2078,8 @@ MODEM_CHAT_SCRIPT_DEFINE(telit_me910g1_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, NULL); + &MODEM_CELLULAR_INST_NAME(config, inst), POST_KERNEL, 99, \ + &modem_cellular_api); #define MODEM_CELLULAR_DEVICE_TELIT_ME910G1(inst) \ MODEM_PPP_DEFINE(MODEM_CELLULAR_INST_NAME(ppp, inst), NULL, 98, 1500, 64); \ @@ -2026,7 +2107,8 @@ MODEM_CHAT_SCRIPT_DEFINE(telit_me910g1_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, NULL); + &MODEM_CELLULAR_INST_NAME(config, inst), POST_KERNEL, 99, \ + &modem_cellular_api); #define DT_DRV_COMPAT quectel_bg95 DT_INST_FOREACH_STATUS_OKAY(MODEM_CELLULAR_DEVICE_QUECTEL_BG95) @@ -2059,70 +2141,3 @@ DT_INST_FOREACH_STATUS_OKAY(MODEM_CELLULAR_DEVICE_SWIR_HL7800) #define DT_DRV_COMPAT telit_me910g1 DT_INST_FOREACH_STATUS_OKAY(MODEM_CELLULAR_DEVICE_TELIT_ME910G1) #undef DT_DRV_COMPAT - -int cellular_get_modem_info(const struct device *dev, enum cellular_modem_info_type type, - char *info, size_t size) -{ - int ret = 0; - struct modem_cellular_data *data = (struct modem_cellular_data *)dev->data; - - switch (type) { - case CELLULAR_MODEM_INFO_IMEI: - strncpy(info, &data->imei[0], MIN(size, sizeof(data->imei))); - break; - case CELLULAR_MODEM_INFO_SIM_IMSI: - strncpy(info, &data->imsi[0], MIN(size, sizeof(data->imsi))); - break; - case CELLULAR_MODEM_INFO_SIM_ICCID: - strncpy(info, &data->iccid[0], MIN(size, sizeof(data->iccid))); - break; - case CELLULAR_MODEM_INFO_MANUFACTURER: - strncpy(info, &data->manufacturer[0], MIN(size, sizeof(data->manufacturer))); - break; - case CELLULAR_MODEM_INFO_FW_VERSION: - strncpy(info, &data->fw_version[0], MIN(size, sizeof(data->fw_version))); - break; - case CELLULAR_MODEM_INFO_MODEL_ID: - strncpy(info, &data->model_id[0], MIN(size, sizeof(data->model_id))); - break; - default: - ret = -ENODATA; - break; - } - - return ret; -} - -int cellular_get_signal(const struct device *dev, const enum cellular_signal_type type, - int16_t *value) -{ - int ret; - struct modem_cellular_data *data = (struct modem_cellular_data *)dev->data; - const struct modem_cellular_config *config = (struct modem_cellular_config *)dev->config; - - if (config->get_signal_chat_script == NULL) { - return -ENOTSUP; - } - - if ((data->state != MODEM_CELLULAR_STATE_AWAIT_REGISTERED) && - (data->state != MODEM_CELLULAR_STATE_CARRIER_ON)) { - return -ENODATA; - } - - ret = modem_chat_run_script(&data->chat, config->get_signal_chat_script); - if (ret != 0) { - return ret; - } - - switch (type) { - case CELLULAR_SIGNAL_RSSI: { - *value = data->rssi; - } break; - case CELLULAR_SIGNAL_RSRP: - return -ENOTSUP; - case CELLULAR_SIGNAL_RSRQ: - return -ENOTSUP; - } - - return ret; -} diff --git a/include/zephyr/drivers/cellular.h b/include/zephyr/drivers/cellular.h index b4202d81b0a..fba05e6e440 100644 --- a/include/zephyr/drivers/cellular.h +++ b/include/zephyr/drivers/cellular.h @@ -124,17 +124,13 @@ __subsystem struct cellular_driver_api { * @retval -ENOTSUP if API is not supported by cellular network device. * @retval Negative errno-code otherwise. */ -__syscall int cellular_configure_networks(const struct device *dev, - const struct cellular_network *networks, uint8_t size); - -static inline int z_impl_cellular_configure_networks(const struct device *dev, - const struct cellular_network *networks, - uint8_t size) +static inline int cellular_configure_networks(const struct device *dev, + const struct cellular_network *networks, uint8_t size) { const struct cellular_driver_api *api = (const struct cellular_driver_api *)dev->api; if (api->configure_networks == NULL) { - return -ENOTSUP; + return -ENOSYS; } return api->configure_networks(dev, networks, size); @@ -151,18 +147,14 @@ static inline int z_impl_cellular_configure_networks(const struct device *dev, * @retval -ENOTSUP if API is not supported by cellular network device. * @retval Negative errno-code otherwise. */ -__syscall int cellular_get_supported_networks(const struct device *dev, - const struct cellular_network **networks, - uint8_t *size); - -static inline int z_impl_cellular_get_supported_networks(const struct device *dev, - const struct cellular_network **networks, - uint8_t *size) +static inline int cellular_get_supported_networks(const struct device *dev, + const struct cellular_network **networks, + uint8_t *size) { const struct cellular_driver_api *api = (const struct cellular_driver_api *)dev->api; if (api->get_supported_networks == NULL) { - return -ENOTSUP; + return -ENOSYS; } return api->get_supported_networks(dev, networks, size); @@ -180,17 +172,13 @@ static inline int z_impl_cellular_get_supported_networks(const struct device *de * @retval -ENODATA if device is not in a state where signal can be polled * @retval Negative errno-code otherwise. */ -__syscall int cellular_get_signal(const struct device *dev, const enum cellular_signal_type type, - int16_t *value); - -static inline int z_impl_cellular_get_signal(const struct device *dev, - const enum cellular_signal_type type, - int16_t *value) +static inline int cellular_get_signal(const struct device *dev, + const enum cellular_signal_type type, int16_t *value) { const struct cellular_driver_api *api = (const struct cellular_driver_api *)dev->api; if (api->get_signal == NULL) { - return -ENOTSUP; + return -ENOSYS; } return api->get_signal(dev, type, value); @@ -209,18 +197,14 @@ static inline int z_impl_cellular_get_signal(const struct device *dev, * @retval -ENODATA if modem does not provide info requested * @retval Negative errno-code from chat module otherwise. */ -__syscall int cellular_get_modem_info(const struct device *dev, - const enum cellular_modem_info_type type, - char *info, size_t size); - -static inline int z_impl_cellular_get_modem_info(const struct device *dev, - const enum cellular_modem_info_type type, - char *info, size_t size) +static inline int cellular_get_modem_info(const struct device *dev, + const enum cellular_modem_info_type type, char *info, + size_t size) { const struct cellular_driver_api *api = (const struct cellular_driver_api *)dev->api; if (api->get_modem_info == NULL) { - return -ENOTSUP; + return -ENOSYS; } return api->get_modem_info(dev, type, info, size); @@ -234,6 +218,4 @@ static inline int z_impl_cellular_get_modem_info(const struct device *dev, * @} */ -#include - #endif /* ZEPHYR_INCLUDE_DRIVERS_CELLULAR_H_ */ From 572c5e6d5a6a10f7c5cf9f7313626b6f89453d6f Mon Sep 17 00:00:00 2001 From: Bjarki Arge Andreasen Date: Fri, 29 Dec 2023 13:02:48 +0100 Subject: [PATCH 1660/3723] modem: modem_cellular: Rework cellular_get_signal implementation The modem_cellular.c driver now uses a common script to get signal strenght, which is run on demand. This is more efficient than polling it, and simpler since every modem doesn't have to define their own variant of the script. Additionally, the CSQ handler now stores the "raw" rssi value returned from AT+CSQ to be parsed by the cellular_modem_get_signal implementation. Signed-off-by: Bjarki Arge Andreasen --- drivers/modem/modem_cellular.c | 107 ++++++++++++++++++--------------- 1 file changed, 58 insertions(+), 49 deletions(-) diff --git a/drivers/modem/modem_cellular.c b/drivers/modem/modem_cellular.c index ea39cecabaf..78958bdec2c 100644 --- a/drivers/modem/modem_cellular.c +++ b/drivers/modem/modem_cellular.c @@ -94,7 +94,7 @@ struct modem_cellular_data { uint8_t registration_status_gsm; uint8_t registration_status_gprs; uint8_t registration_status_lte; - int8_t rssi; + uint8_t rssi; uint8_t imei[MODEM_CELLULAR_DATA_IMEI_LEN]; uint8_t model_id[MODEM_CELLULAR_DATA_MODEL_ID_LEN]; uint8_t imsi[MODEM_CELLULAR_DATA_IMSI_LEN]; @@ -131,7 +131,6 @@ struct modem_cellular_config { const struct modem_chat_script *init_chat_script; const struct modem_chat_script *dial_chat_script; const struct modem_chat_script *periodic_chat_script; - const struct modem_chat_script *get_signal_chat_script; }; static const char *modem_cellular_state_str(enum modem_cellular_state state) @@ -332,28 +331,13 @@ static void modem_cellular_chat_on_cgmr(struct modem_chat *chat, char **argv, ui static void modem_cellular_chat_on_csq(struct modem_chat *chat, char **argv, uint16_t argc, void *user_data) { - uint8_t rssi; - - /* AT+CSQ returns a response +CSQ: , where: - * - rssi is a integer from 0 to 31 whose values describes a signal strength - * between -113 dBm for 0 and -51dbM for 31 or unknown for 99 - * - ber is an integer from 0 to 7 that describes the error rate, it can also - * be 99 for an unknown error rate - */ struct modem_cellular_data *data = (struct modem_cellular_data *)user_data; if (argc != 3) { return; } - /* Read rssi */ - rssi = atoi(argv[1]); - - if (rssi == 99) { - return; - } - - data->rssi = (-113 + (2 * rssi)); + data->rssi = (uint8_t)atoi(argv[1]); } static void modem_cellular_chat_on_imsi(struct modem_chat *chat, char **argv, uint16_t argc, @@ -1263,36 +1247,78 @@ static void modem_cellular_cmux_handler(struct modem_cmux *cmux, enum modem_cmux } } +MODEM_CHAT_SCRIPT_CMDS_DEFINE(get_signal_csq_chat_script_cmds, + MODEM_CHAT_SCRIPT_CMD_RESP("AT+CSQ", csq_match), + MODEM_CHAT_SCRIPT_CMD_RESP("", ok_match)); + +MODEM_CHAT_SCRIPT_DEFINE(get_signal_csq_chat_script, get_signal_csq_chat_script_cmds, + abort_matches, modem_cellular_chat_callback_handler, 2); + +static inline int modem_cellular_csq_parse_rssi(uint8_t rssi, int16_t *value) +{ + /* AT+CSQ returns a response +CSQ: , where: + * - rssi is a integer from 0 to 31 whose values describes a signal strength + * between -113 dBm for 0 and -51dbM for 31 or unknown for 99 + * - ber is an integer from 0 to 7 that describes the error rate, it can also + * be 99 for an unknown error rate + */ + if (rssi == 99) { + return -EINVAL; + } + + *value = (int16_t)(-113 + (2 * rssi)); + return 0; +} + static int modem_cellular_get_signal(const struct device *dev, const enum cellular_signal_type type, int16_t *value) { - int ret; + int ret = -ENOTSUP; struct modem_cellular_data *data = (struct modem_cellular_data *)dev->data; - const struct modem_cellular_config *config = (struct modem_cellular_config *)dev->config; - - if (config->get_signal_chat_script == NULL) { - return -ENOTSUP; - } if ((data->state != MODEM_CELLULAR_STATE_AWAIT_REGISTERED) && (data->state != MODEM_CELLULAR_STATE_CARRIER_ON)) { return -ENODATA; } - ret = modem_chat_run_script(&data->chat, config->get_signal_chat_script); - if (ret != 0) { + /* Run chat script */ + switch (type) { + case CELLULAR_SIGNAL_RSSI: + ret = modem_chat_run_script(&data->chat, &get_signal_csq_chat_script); + break; + + case CELLULAR_SIGNAL_RSRP: + case CELLULAR_SIGNAL_RSRQ: + /* TODO: Run CESQ script */ + ret = -ENOTSUP; + break; + + default: + ret = -ENOTSUP; + break; + } + + /* Verify chat script ran successfully */ + if (ret < 0) { return ret; } + /* Parse received value */ switch (type) { - case CELLULAR_SIGNAL_RSSI: { - *value = data->rssi; - } break; + case CELLULAR_SIGNAL_RSSI: + ret = modem_cellular_csq_parse_rssi(data->rssi, value); + break; + case CELLULAR_SIGNAL_RSRP: - return -ENOTSUP; case CELLULAR_SIGNAL_RSRQ: - return -ENOTSUP; + /* TODO: Validate and set values */ + ret = -ENODATA; + break; + + default: + ret = -ENOTSUP; + break; } return ret; @@ -1517,19 +1543,11 @@ MODEM_CHAT_SCRIPT_DEFINE(quectel_bg95_dial_chat_script, quectel_bg95_dial_chat_s MODEM_CHAT_SCRIPT_CMDS_DEFINE(quectel_bg95_periodic_chat_script_cmds, MODEM_CHAT_SCRIPT_CMD_RESP("AT+CREG?", ok_match), MODEM_CHAT_SCRIPT_CMD_RESP("AT+CEREG?", ok_match), - MODEM_CHAT_SCRIPT_CMD_RESP("AT+CGREG?", ok_match), - MODEM_CHAT_SCRIPT_CMD_RESP("AT+CSQ", csq_match)); + MODEM_CHAT_SCRIPT_CMD_RESP("AT+CGREG?", ok_match)); MODEM_CHAT_SCRIPT_DEFINE(quectel_bg95_periodic_chat_script, quectel_bg95_periodic_chat_script_cmds, abort_matches, modem_cellular_chat_callback_handler, 4); - -MODEM_CHAT_SCRIPT_CMDS_DEFINE(quectel_bg95_get_signal_chat_script_cmds, - MODEM_CHAT_SCRIPT_CMD_RESP("AT+CSQ", csq_match)); - -MODEM_CHAT_SCRIPT_DEFINE(quectel_bg95_get_signal_chat_script, - quectel_bg95_get_signal_chat_script_cmds, abort_matches, - modem_cellular_chat_callback_handler, 4); #endif #if DT_HAS_COMPAT_STATUS_OKAY(quectel_eg25_g) @@ -1580,13 +1598,6 @@ MODEM_CHAT_SCRIPT_CMDS_DEFINE(quectel_eg25_g_periodic_chat_script_cmds, MODEM_CHAT_SCRIPT_DEFINE(quectel_eg25_g_periodic_chat_script, quectel_eg25_g_periodic_chat_script_cmds, abort_matches, modem_cellular_chat_callback_handler, 4); - -MODEM_CHAT_SCRIPT_CMDS_DEFINE(quectel_eg25_g_get_signal_chat_script_cmds, - MODEM_CHAT_SCRIPT_CMD_RESP("AT+CSQ", csq_match)); - -MODEM_CHAT_SCRIPT_DEFINE(quectel_eg25_g_get_signal_chat_script, - quectel_eg25_g_get_signal_chat_script_cmds, abort_matches, - modem_cellular_chat_callback_handler, 4); #endif #if DT_HAS_COMPAT_STATUS_OKAY(zephyr_gsm_ppp) @@ -1895,7 +1906,6 @@ MODEM_CHAT_SCRIPT_DEFINE(telit_me910g1_periodic_chat_script, .init_chat_script = &quectel_bg95_init_chat_script, \ .dial_chat_script = &quectel_bg95_dial_chat_script, \ .periodic_chat_script = &_CONCAT(DT_DRV_COMPAT, _periodic_chat_script), \ - .get_signal_chat_script = &_CONCAT(DT_DRV_COMPAT, _get_signal_chat_script), \ }; \ \ PM_DEVICE_DT_INST_DEFINE(inst, modem_cellular_pm_action); \ @@ -1925,7 +1935,6 @@ MODEM_CHAT_SCRIPT_DEFINE(telit_me910g1_periodic_chat_script, .init_chat_script = &quectel_eg25_g_init_chat_script, \ .dial_chat_script = &quectel_eg25_g_dial_chat_script, \ .periodic_chat_script = &_CONCAT(DT_DRV_COMPAT, _periodic_chat_script), \ - .get_signal_chat_script = &_CONCAT(DT_DRV_COMPAT, _get_signal_chat_script), \ }; \ \ PM_DEVICE_DT_INST_DEFINE(inst, modem_cellular_pm_action); \ From 1ee092673a13c1f74da932c6ca27fc634304d118 Mon Sep 17 00:00:00 2001 From: Bjarki Arge Andreasen Date: Fri, 29 Dec 2023 13:33:24 +0100 Subject: [PATCH 1661/3723] modem: modem_cellular.c: Remove non standard QCCID handler The QCCID handler is Quectel specific and as such may not be part of the modem cellular driver which only supports commands defined in 3GPP TS 27.007 Signed-off-by: Bjarki Arge Andreasen --- drivers/modem/modem_cellular.c | 16 ---------------- 1 file changed, 16 deletions(-) diff --git a/drivers/modem/modem_cellular.c b/drivers/modem/modem_cellular.c index 78958bdec2c..16530edde6c 100644 --- a/drivers/modem/modem_cellular.c +++ b/drivers/modem/modem_cellular.c @@ -348,14 +348,6 @@ static void modem_cellular_chat_on_imsi(struct modem_chat *chat, char **argv, ui strncpy(data->imsi, (char *)argv[1], sizeof(data->imsi)); } -static void modem_cellular_chat_on_iccid(struct modem_chat *chat, char **argv, uint16_t argc, - void *user_data) -{ - struct modem_cellular_data *data = (struct modem_cellular_data *)user_data; - - strncpy(data->iccid, (char *)argv[1], sizeof(data->iccid)); -} - static bool modem_cellular_is_registered(struct modem_cellular_data *data) { return (data->registration_status_gsm == 1) @@ -407,7 +399,6 @@ MODEM_CHAT_MATCH_DEFINE(imei_match, "", "", modem_cellular_chat_on_imei); MODEM_CHAT_MATCH_DEFINE(cgmm_match, "", "", modem_cellular_chat_on_cgmm); MODEM_CHAT_MATCH_DEFINE(csq_match, "+CSQ: ", ",", modem_cellular_chat_on_csq); MODEM_CHAT_MATCH_DEFINE(cimi_match, "", "", modem_cellular_chat_on_imsi); -MODEM_CHAT_MATCH_DEFINE(ccid_match, "+QCCID: ", "", modem_cellular_chat_on_iccid); MODEM_CHAT_MATCH_DEFINE(cgmi_match, "", "", modem_cellular_chat_on_cgmi); MODEM_CHAT_MATCH_DEFINE(cgmr_match, "", "", modem_cellular_chat_on_cgmr); @@ -1338,9 +1329,6 @@ static int modem_cellular_get_modem_info(const struct device *dev, case CELLULAR_MODEM_INFO_SIM_IMSI: strncpy(info, &data->imsi[0], MIN(size, sizeof(data->imsi))); break; - case CELLULAR_MODEM_INFO_SIM_ICCID: - strncpy(info, &data->iccid[0], MIN(size, sizeof(data->iccid))); - break; case CELLULAR_MODEM_INFO_MANUFACTURER: strncpy(info, &data->manufacturer[0], MIN(size, sizeof(data->manufacturer))); break; @@ -1522,8 +1510,6 @@ MODEM_CHAT_SCRIPT_CMDS_DEFINE(quectel_bg95_init_chat_script_cmds, MODEM_CHAT_SCRIPT_CMD_RESP("", ok_match), MODEM_CHAT_SCRIPT_CMD_RESP("AT+CIMI", cimi_match), MODEM_CHAT_SCRIPT_CMD_RESP("", ok_match), - MODEM_CHAT_SCRIPT_CMD_RESP("AT+QCCID", ccid_match), - MODEM_CHAT_SCRIPT_CMD_RESP("", ok_match), MODEM_CHAT_SCRIPT_CMD_RESP_NONE("AT+CMUX=0,0,5,127", 300)); MODEM_CHAT_SCRIPT_DEFINE(quectel_bg95_init_chat_script, quectel_bg95_init_chat_script_cmds, @@ -1571,8 +1557,6 @@ MODEM_CHAT_SCRIPT_CMDS_DEFINE( MODEM_CHAT_SCRIPT_CMD_RESP("", ok_match), MODEM_CHAT_SCRIPT_CMD_RESP("AT+CIMI", cimi_match), MODEM_CHAT_SCRIPT_CMD_RESP("", ok_match), - MODEM_CHAT_SCRIPT_CMD_RESP("AT+QCCID", ccid_match), - MODEM_CHAT_SCRIPT_CMD_RESP("", ok_match), MODEM_CHAT_SCRIPT_CMD_RESP_NONE("AT+CMUX=0,0,5,127,10,3,30,10,2", 100)); MODEM_CHAT_SCRIPT_DEFINE(quectel_eg25_g_init_chat_script, quectel_eg25_g_init_chat_script_cmds, From bc2826c1cb27aa0deed5fcb6ac703fa4e0eba077 Mon Sep 17 00:00:00 2001 From: Henrik Brix Andersen Date: Tue, 2 Jan 2024 11:15:37 +0100 Subject: [PATCH 1662/3723] drivers: gpio: pca953x: check return values from I2C API functions Check the return values from the I2C API functions called in init() and fail driver initialization if unsuccessful. Fixes: #66827 Signed-off-by: Henrik Brix Andersen --- drivers/gpio/gpio_pca953x.c | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/drivers/gpio/gpio_pca953x.c b/drivers/gpio/gpio_pca953x.c index 5bdb5ba8fd9..81898e83382 100644 --- a/drivers/gpio/gpio_pca953x.c +++ b/drivers/gpio/gpio_pca953x.c @@ -444,12 +444,18 @@ static int gpio_pca953x_init(const struct device *dev) rc = gpio_add_callback(cfg->gpio_int.port, &drv_data->gpio_cb); + if (rc) { + goto out; + } + /* This may not present on all variants of device */ if (cfg->input_latch > -1) { - i2c_reg_write_byte_dt(&cfg->i2c, REG_INPUT_LATCH_PORT0, cfg->input_latch); + rc = i2c_reg_write_byte_dt(&cfg->i2c, REG_INPUT_LATCH_PORT0, + cfg->input_latch); } if (cfg->interrupt_mask > -1) { - i2c_reg_write_byte_dt(&cfg->i2c, REG_INT_MASK_PORT0, cfg->interrupt_mask); + rc = i2c_reg_write_byte_dt(&cfg->i2c, REG_INT_MASK_PORT0, + cfg->interrupt_mask); } } out: From 8f0abaf87ff4c3da513e7a720bfd7bb56265f283 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jan=20M=C3=BCller?= Date: Tue, 2 Jan 2024 15:42:51 +0100 Subject: [PATCH 1663/3723] Doc: Clearify bt_conn_set_security documentation MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Clearify the sec parameter in the documentation of bt_conn_set_security. This should make the API documentation easier to understand. Signed-off-by: Jan Müller --- include/zephyr/bluetooth/conn.h | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/include/zephyr/bluetooth/conn.h b/include/zephyr/bluetooth/conn.h index bdc644d82e9..df79a8967f9 100644 --- a/include/zephyr/bluetooth/conn.h +++ b/include/zephyr/bluetooth/conn.h @@ -871,11 +871,12 @@ int bt_le_set_auto_conn(const bt_addr_le_t *addr, * the device has bond information or is already paired and the keys are too * weak then the pairing procedure will be initiated. * - * This function may return error if required level of security is not possible - * to achieve due to local or remote device limitation (e.g., input output - * capabilities), or if the maximum number of paired devices has been reached. + * This function may return an error if the required level of security defined using + * @p sec is not possible to achieve due to local or remote device limitation + * (e.g., input output capabilities), or if the maximum number of paired devices + * has been reached. * - * This function may return error if the pairing procedure has already been + * This function may return an error if the pairing procedure has already been * initiated by the local device or the peer device. * * @note When @kconfig{CONFIG_BT_SMP_SC_ONLY} is enabled then the security @@ -888,7 +889,7 @@ int bt_le_set_auto_conn(const bt_addr_le_t *addr, * procedure will always be initiated. * * @param conn Connection object. - * @param sec Requested security level. + * @param sec Requested minimum security level. * * @return 0 on success or negative error */ From ec42d825eca588f3d58eb934b6f694d5b1b859c9 Mon Sep 17 00:00:00 2001 From: Jukka Rissanen Date: Thu, 21 Dec 2023 16:23:13 +0200 Subject: [PATCH 1664/3723] net: context: Fix the v4 mapped address handling in sendto If we receive a IPv4 packet to v4 mapped address, the relevant net_context is bound to IPv6. This causes issues if we try to get the family from the context struct in sendto. Fix this by checking if the destination address is IPv4 but the socket is bound to IPv6 and v4 mapping is enabled. If all these criterias are set, then set the family of the packet separately and do not get it from net_context. Signed-off-by: Jukka Rissanen --- subsys/net/ip/net_context.c | 61 +++++++++++++++++++++---------------- 1 file changed, 34 insertions(+), 27 deletions(-) diff --git a/subsys/net/ip/net_context.c b/subsys/net/ip/net_context.c index 0d4b8ea60c9..ae7a4a4e848 100644 --- a/subsys/net/ip/net_context.c +++ b/subsys/net/ip/net_context.c @@ -1744,6 +1744,7 @@ static int context_write_data(struct net_pkt *pkt, const void *buf, } static int context_setup_udp_packet(struct net_context *context, + sa_family_t family, struct net_pkt *pkt, const void *buf, size_t len, @@ -1754,16 +1755,14 @@ static int context_setup_udp_packet(struct net_context *context, int ret = -EINVAL; uint16_t dst_port = 0U; - if (IS_ENABLED(CONFIG_NET_IPV6) && - net_context_get_family(context) == AF_INET6) { + if (IS_ENABLED(CONFIG_NET_IPV6) && family == AF_INET6) { struct sockaddr_in6 *addr6 = (struct sockaddr_in6 *)dst_addr; dst_port = addr6->sin6_port; ret = net_context_create_ipv6_new(context, pkt, NULL, &addr6->sin6_addr); - } else if (IS_ENABLED(CONFIG_NET_IPV4) && - net_context_get_family(context) == AF_INET) { + } else if (IS_ENABLED(CONFIG_NET_IPV4) && family == AF_INET) { struct sockaddr_in *addr4 = (struct sockaddr_in *)dst_addr; dst_port = addr4->sin_port; @@ -1798,6 +1797,7 @@ static int context_setup_udp_packet(struct net_context *context, } static void context_finalize_packet(struct net_context *context, + sa_family_t family, struct net_pkt *pkt) { /* This function is meant to be temporary: once all moved to new @@ -1806,16 +1806,15 @@ static void context_finalize_packet(struct net_context *context, net_pkt_cursor_init(pkt); - if (IS_ENABLED(CONFIG_NET_IPV6) && - net_context_get_family(context) == AF_INET6) { + if (IS_ENABLED(CONFIG_NET_IPV6) && family == AF_INET6) { net_ipv6_finalize(pkt, net_context_get_proto(context)); - } else if (IS_ENABLED(CONFIG_NET_IPV4) && - net_context_get_family(context) == AF_INET) { + } else if (IS_ENABLED(CONFIG_NET_IPV4) && family == AF_INET) { net_ipv4_finalize(pkt, net_context_get_proto(context)); } } static struct net_pkt *context_alloc_pkt(struct net_context *context, + sa_family_t family, size_t len, k_timeout_t timeout) { struct net_pkt *pkt; @@ -1828,13 +1827,14 @@ static struct net_pkt *context_alloc_pkt(struct net_context *context, } net_pkt_set_iface(pkt, net_context_get_iface(context)); - net_pkt_set_family(pkt, net_context_get_family(context)); + net_pkt_set_family(pkt, family); net_pkt_set_context(pkt, context); if (net_pkt_alloc_buffer(pkt, len, net_context_get_proto(context), timeout)) { net_pkt_unref(pkt); + return NULL; } @@ -1842,7 +1842,7 @@ static struct net_pkt *context_alloc_pkt(struct net_context *context, } #endif pkt = net_pkt_alloc_with_buffer(net_context_get_iface(context), len, - net_context_get_family(context), + family, net_context_get_proto(context), timeout); if (pkt) { @@ -1880,6 +1880,7 @@ static int context_sendto(struct net_context *context, const struct msghdr *msghdr = NULL; struct net_if *iface; struct net_pkt *pkt = NULL; + sa_family_t family; size_t tmp_len; int ret; @@ -1898,8 +1899,20 @@ static int context_sendto(struct net_context *context, return -EDESTADDRREQ; } - if (IS_ENABLED(CONFIG_NET_IPV6) && - net_context_get_family(context) == AF_INET6) { + /* Are we trying to send IPv4 packet to mapped V6 address, in that case + * we need to set the family to AF_INET so that various checks below + * are done to the packet correctly and we actually send an IPv4 pkt. + */ + if (IS_ENABLED(CONFIG_NET_IPV4_MAPPING_TO_IPV6) && + IS_ENABLED(CONFIG_NET_IPV6) && + net_context_get_family(context) == AF_INET6 && + dst_addr->sa_family == AF_INET) { + family = AF_INET; + } else { + family = net_context_get_family(context); + } + + if (IS_ENABLED(CONFIG_NET_IPV6) && family == AF_INET6) { const struct sockaddr_in6 *addr6 = (const struct sockaddr_in6 *)dst_addr; @@ -1939,8 +1952,7 @@ static int context_sendto(struct net_context *context, net_context_set_iface(context, iface); } - } else if (IS_ENABLED(CONFIG_NET_IPV4) && - net_context_get_family(context) == AF_INET) { + } else if (IS_ENABLED(CONFIG_NET_IPV4) && family == AF_INET) { const struct sockaddr_in *addr4 = (const struct sockaddr_in *)dst_addr; struct sockaddr_in mapped; @@ -1992,8 +2004,7 @@ static int context_sendto(struct net_context *context, net_context_set_iface(context, iface); } - } else if (IS_ENABLED(CONFIG_NET_SOCKETS_PACKET) && - net_context_get_family(context) == AF_PACKET) { + } else if (IS_ENABLED(CONFIG_NET_SOCKETS_PACKET) && family == AF_PACKET) { struct sockaddr_ll *ll_addr = (struct sockaddr_ll *)dst_addr; if (msghdr) { @@ -2043,8 +2054,7 @@ static int context_sendto(struct net_context *context, } } - } else if (IS_ENABLED(CONFIG_NET_SOCKETS_CAN) && - net_context_get_family(context) == AF_CAN) { + } else if (IS_ENABLED(CONFIG_NET_SOCKETS_CAN) && family == AF_CAN) { struct sockaddr_can *can_addr = (struct sockaddr_can *)dst_addr; if (msghdr) { @@ -2083,8 +2093,7 @@ static int context_sendto(struct net_context *context, return -EDESTADDRREQ; } } else { - NET_DBG("Invalid protocol family %d", - net_context_get_family(context)); + NET_DBG("Invalid protocol family %d", family); return -EINVAL; } @@ -2110,7 +2119,7 @@ static int context_sendto(struct net_context *context, goto skip_alloc; } - pkt = context_alloc_pkt(context, len, PKT_WAIT_TIME); + pkt = context_alloc_pkt(context, family, len, PKT_WAIT_TIME); if (!pkt) { NET_ERR("Failed to allocate net_pkt"); return -ENOBUFS; @@ -2169,13 +2178,13 @@ static int context_sendto(struct net_context *context, } } else if (IS_ENABLED(CONFIG_NET_UDP) && net_context_get_proto(context) == IPPROTO_UDP) { - ret = context_setup_udp_packet(context, pkt, buf, len, msghdr, + ret = context_setup_udp_packet(context, family, pkt, buf, len, msghdr, dst_addr, addrlen); if (ret < 0) { goto fail; } - context_finalize_packet(context, pkt); + context_finalize_packet(context, family, pkt); ret = net_send_data(pkt); } else if (IS_ENABLED(CONFIG_NET_TCP) && @@ -2189,8 +2198,7 @@ static int context_sendto(struct net_context *context, len = ret; ret = net_tcp_send_data(context, cb, user_data); - } else if (IS_ENABLED(CONFIG_NET_SOCKETS_PACKET) && - net_context_get_family(context) == AF_PACKET) { + } else if (IS_ENABLED(CONFIG_NET_SOCKETS_PACKET) && family == AF_PACKET) { ret = context_write_data(pkt, buf, len, msghdr); if (ret < 0) { goto fail; @@ -2219,8 +2227,7 @@ static int context_sendto(struct net_context *context, } else { net_if_queue_tx(net_pkt_iface(pkt), pkt); } - } else if (IS_ENABLED(CONFIG_NET_SOCKETS_CAN) && - net_context_get_family(context) == AF_CAN && + } else if (IS_ENABLED(CONFIG_NET_SOCKETS_CAN) && family == AF_CAN && net_context_get_proto(context) == CAN_RAW) { ret = context_write_data(pkt, buf, len, msghdr); if (ret < 0) { From 3c0a6058b518f7d5dfbbadc9e857cc605632264b Mon Sep 17 00:00:00 2001 From: Fabian Pflug Date: Thu, 21 Dec 2023 15:27:42 +0100 Subject: [PATCH 1665/3723] drivers: pwm: stm32: Catch overflows in 2-channel capture When not using 4 channel capture, overflows were never reported to the application, because the check was in the four_channel_capture_support branch. Signed-off-by: Fabian Pflug --- drivers/pwm/pwm_stm32.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/drivers/pwm/pwm_stm32.c b/drivers/pwm/pwm_stm32.c index 4d899b19fea..c8e44633ad5 100644 --- a/drivers/pwm/pwm_stm32.c +++ b/drivers/pwm/pwm_stm32.c @@ -732,11 +732,11 @@ static void pwm_stm32_isr(const struct device *dev) /* Still waiting for a complete capture */ return; } + } - if (cpt->overflows) { - LOG_ERR("counter overflow during PWM capture"); - status = -ERANGE; - } + if (cpt->overflows) { + LOG_ERR("counter overflow during PWM capture"); + status = -ERANGE; } if (!cpt->continuous) { From ed8578d566d974b95da727d729f3e97074cc3286 Mon Sep 17 00:00:00 2001 From: Bjarki Arge Andreasen Date: Sat, 23 Dec 2023 13:57:22 +0100 Subject: [PATCH 1666/3723] pm: device_runtime: Add missing include to header The device_runtime header includes references to struct device and k_timeout_t, but only zephyr/device.h is included. k_timeout_t is in zephyr/kernel, so it must also be included. Signed-off-by: Bjarki Arge Andreasen --- include/zephyr/pm/device_runtime.h | 1 + 1 file changed, 1 insertion(+) diff --git a/include/zephyr/pm/device_runtime.h b/include/zephyr/pm/device_runtime.h index 3a320b9ccbc..3510a910f3a 100644 --- a/include/zephyr/pm/device_runtime.h +++ b/include/zephyr/pm/device_runtime.h @@ -9,6 +9,7 @@ #define ZEPHYR_INCLUDE_PM_DEVICE_RUNTIME_H_ #include +#include #ifdef __cplusplus extern "C" { From 3ebe8142945e53828c1a6c91f4b134adece4af33 Mon Sep 17 00:00:00 2001 From: Bjarki Arge Andreasen Date: Mon, 25 Dec 2023 09:26:47 +0100 Subject: [PATCH 1667/3723] modem: chat: Patch invalid dereference The chat module contains an array of three lists of matches, one of which are static, two of which are contained within the currently running script. The current match, which is an object stored in one of the three lists, is stored in its own pointer in the chat module context. A memory error occurs when the script is stopped, while the chat module is using one of the matches stored withing the script. This commit clears the match pointer when the script is stopped if the match is stored within the script. Signed-off-by: Bjarki Arge Andreasen --- subsys/modem/modem_chat.c | 14 +++++++++++++- 1 file changed, 13 insertions(+), 1 deletion(-) diff --git a/subsys/modem/modem_chat.c b/subsys/modem/modem_chat.c index 0ab1175f980..7cf7692c514 100644 --- a/subsys/modem/modem_chat.c +++ b/subsys/modem/modem_chat.c @@ -60,7 +60,7 @@ static void modem_chat_log_received_command(struct modem_chat *chat) static void modem_chat_script_stop(struct modem_chat *chat, enum modem_chat_script_result result) { - if (!chat || !chat->script) { + if ((chat == NULL) || (chat->script == NULL)) { return; } @@ -78,6 +78,14 @@ static void modem_chat_script_stop(struct modem_chat *chat, enum modem_chat_scri chat->script->callback(chat, result, chat->user_data); } + /* Clear parse_match in case it is stored in the script being stopped */ + if ((chat->parse_match != NULL) && + ((chat->parse_match_type == MODEM_CHAT_MATCHES_INDEX_ABORT) || + (chat->parse_match_type == MODEM_CHAT_MATCHES_INDEX_RESPONSE))) { + chat->parse_match = NULL; + chat->parse_match_len = 0; + } + /* Clear reference to script */ chat->script = NULL; @@ -822,4 +830,8 @@ void modem_chat_release(struct modem_chat *chat) chat->parse_match = NULL; chat->parse_match_len = 0; chat->parse_arg_len = 0; + chat->matches[MODEM_CHAT_MATCHES_INDEX_ABORT] = NULL; + chat->matches_size[MODEM_CHAT_MATCHES_INDEX_ABORT] = 0; + chat->matches[MODEM_CHAT_MATCHES_INDEX_RESPONSE] = NULL; + chat->matches_size[MODEM_CHAT_MATCHES_INDEX_RESPONSE] = 0; } From 48fa603da37e6161c299af52bccad6165222548f Mon Sep 17 00:00:00 2001 From: Bjarki Arge Andreasen Date: Wed, 6 Dec 2023 18:22:28 +0100 Subject: [PATCH 1668/3723] modem: cmux: Patch resync mechanism The CMUX resync mechanism can get stuck between states MODEM_CMUX_RECEIVE_STATE_RESYNC_0 and MODEM_CMUX_RECEIVE_STATE_RESYNC_1 if the resync flags, which are sent only once in state MODEM_CMUX_RECEIVE_STATE_SOF, are not responded to, or the response is lost. This patch ensures resync flags are sent from states MODEM_CMUX_RECEIVE_STATE_SOF, MODEM_CMUX_RECEIVE_STATE_RESYNC_1 and MODEM_CMUX_RECEIVE_STATE_RESYNC_2 if its determined that the resync flags are not being responded to. Signed-off-by: Bjarki Arge Andreasen --- subsys/modem/modem_cmux.c | 15 ++++++++++----- 1 file changed, 10 insertions(+), 5 deletions(-) diff --git a/subsys/modem/modem_cmux.c b/subsys/modem/modem_cmux.c index 3ace00d6583..7f40fa6e95d 100644 --- a/subsys/modem/modem_cmux.c +++ b/subsys/modem/modem_cmux.c @@ -638,10 +638,16 @@ static void modem_cmux_on_frame(struct modem_cmux *cmux) modem_cmux_on_dlci_frame(cmux); } +static void modem_cmux_transmit_resync(struct modem_cmux *cmux) +{ + static const uint8_t resync[3] = {0xF9, 0xF9, 0xF9}; + + modem_pipe_transmit(cmux->pipe, resync, sizeof(resync)); +} + static void modem_cmux_process_received_byte(struct modem_cmux *cmux, uint8_t byte) { uint8_t fcs; - static const uint8_t resync[3] = {0xF9, 0xF9, 0xF9}; switch (cmux->receive_state) { case MODEM_CMUX_RECEIVE_STATE_SOF: @@ -650,10 +656,7 @@ static void modem_cmux_process_received_byte(struct modem_cmux *cmux, uint8_t by break; } - /* Send resync flags */ - modem_pipe_transmit(cmux->pipe, resync, sizeof(resync)); - - /* Await resync flags */ + modem_cmux_transmit_resync(cmux); cmux->receive_state = MODEM_CMUX_RECEIVE_STATE_RESYNC_0; break; @@ -668,6 +671,7 @@ static void modem_cmux_process_received_byte(struct modem_cmux *cmux, uint8_t by if (byte == 0xF9) { cmux->receive_state = MODEM_CMUX_RECEIVE_STATE_RESYNC_2; } else { + modem_cmux_transmit_resync(cmux); cmux->receive_state = MODEM_CMUX_RECEIVE_STATE_RESYNC_0; } @@ -677,6 +681,7 @@ static void modem_cmux_process_received_byte(struct modem_cmux *cmux, uint8_t by if (byte == 0xF9) { cmux->receive_state = MODEM_CMUX_RECEIVE_STATE_RESYNC_3; } else { + modem_cmux_transmit_resync(cmux); cmux->receive_state = MODEM_CMUX_RECEIVE_STATE_RESYNC_0; } From b3fdb7477b11adcb99c44870afc5a2417e873ff3 Mon Sep 17 00:00:00 2001 From: Andy Sinclair Date: Tue, 28 Nov 2023 14:10:01 +0000 Subject: [PATCH 1669/3723] drivers: regulator: fixed: Removed pin state setting from init The setting of initial state in handled by the common driver, which calls the enable function for any regulator that has regulator-boot-on set, and is not already enabled. Signed-off-by: Andy Sinclair --- drivers/regulator/regulator_fixed.c | 20 +++++--------------- 1 file changed, 5 insertions(+), 15 deletions(-) diff --git a/drivers/regulator/regulator_fixed.c b/drivers/regulator/regulator_fixed.c index c0b58273987..5e7151f4941 100644 --- a/drivers/regulator/regulator_fixed.c +++ b/drivers/regulator/regulator_fixed.c @@ -84,33 +84,23 @@ static const struct regulator_driver_api regulator_fixed_api = { static int regulator_fixed_init(const struct device *dev) { const struct regulator_fixed_config *cfg = dev->config; - bool init_enabled; - int ret; regulator_common_data_init(dev); - init_enabled = regulator_common_is_init_enabled(dev); - if (cfg->enable.port != NULL) { if (!gpio_is_ready_dt(&cfg->enable)) { LOG_ERR("GPIO port: %s not ready", cfg->enable.port->name); return -ENODEV; } - if (init_enabled) { - ret = gpio_pin_configure_dt(&cfg->enable, GPIO_OUTPUT_ACTIVE); - if (ret < 0) { - return ret; - } - } else { - ret = gpio_pin_configure_dt(&cfg->enable, GPIO_OUTPUT_INACTIVE); - if (ret < 0) { - return ret; - } + int ret = gpio_pin_configure_dt(&cfg->enable, GPIO_OUTPUT); + + if (ret < 0) { + return ret; } } - return regulator_common_init(dev, init_enabled); + return regulator_common_init(dev, false); } #define REGULATOR_FIXED_DEFINE(inst) \ From 4d9ad941d74a09539c8852b41ec1c93f17c8da27 Mon Sep 17 00:00:00 2001 From: Ryan McClelland Date: Sun, 10 Dec 2023 11:49:44 -0800 Subject: [PATCH 1670/3723] manifest: zscilib: update revision for double promotion fix Update zscilib, this is needed for the double promotion fix Signed-off-by: Ryan McClelland --- submanifests/optional.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/submanifests/optional.yaml b/submanifests/optional.yaml index 54b3d77c0cb..b50e9479933 100644 --- a/submanifests/optional.yaml +++ b/submanifests/optional.yaml @@ -60,7 +60,7 @@ manifest: - optional - name: zscilib path: modules/lib/zscilib - revision: 34a94b0995683822fa3626dcd5d838301c94c350 + revision: a4bb6cfd6800e14373261904825f7f34a3a7f2e5 remote: upstream groups: - optional From 61cb7d4358025691a476a79ed1fb1573cb8c4461 Mon Sep 17 00:00:00 2001 From: Tomasz Lissowski Date: Mon, 11 Sep 2023 11:31:39 +0200 Subject: [PATCH 1671/3723] adsp: hda: accept 16 byte alignment for HDA buffer size HDA DMA driver uses an excessive value of 128 bytes as required alignment for DMA buffer size. This may result in the correct buffer size (e.g. 32-byte aligned, which is DT-compliant) being silently truncated before writing it into DGBS register. This patch changes the requirement to the value implied by DGBS register format (effectively reduces to 16 bytes). Signed-off-by: Tomasz Lissowski --- soc/xtensa/intel_adsp/common/include/intel_adsp_hda.h | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/soc/xtensa/intel_adsp/common/include/intel_adsp_hda.h b/soc/xtensa/intel_adsp/common/include/intel_adsp_hda.h index 9a123a71b15..0b3f86890a1 100644 --- a/soc/xtensa/intel_adsp/common/include/intel_adsp_hda.h +++ b/soc/xtensa/intel_adsp/common/include/intel_adsp_hda.h @@ -28,6 +28,8 @@ /* Buffers must be 128 byte aligned, this mask enforces that */ #define HDA_ALIGN_MASK 0xFFFFFF80 +/* Buffer size must match the mask of BS field in DGBS register */ +#define HDA_BUFFER_SIZE_MASK 0x00FFFFF0 /* Calculate base address of the stream registers */ #define HDA_ADDR(base, regblock_size, stream) ((base) + (stream)*(regblock_size)) @@ -159,14 +161,14 @@ static inline int intel_adsp_hda_set_buffer(uint32_t base, */ uint32_t addr = (uint32_t)arch_xtensa_cached_ptr(buf); uint32_t aligned_addr = addr & HDA_ALIGN_MASK; - uint32_t aligned_size = buf_size & HDA_ALIGN_MASK; + uint32_t aligned_size = buf_size & HDA_BUFFER_SIZE_MASK; __ASSERT(aligned_addr == addr, "Buffer must be 128 byte aligned"); __ASSERT(aligned_addr >= L2_SRAM_BASE && aligned_addr < L2_SRAM_BASE + L2_SRAM_SIZE, "Buffer must be in L2 address space"); __ASSERT(aligned_size == buf_size, - "Buffer must be 128 byte aligned in size"); + "Buffer must be 16 byte aligned in size"); __ASSERT(aligned_addr + aligned_size < L2_SRAM_BASE + L2_SRAM_SIZE, "Buffer must end in L2 address space"); From 1dc9028316634a78e56e0a43c1c7e08613d71eaf Mon Sep 17 00:00:00 2001 From: Robert Lubos Date: Wed, 13 Dec 2023 16:28:22 +0100 Subject: [PATCH 1672/3723] net: sockets: tls: Add function to obtain underlying ssl context For test purposes only. Should not be used in regular applications. Signed-off-by: Robert Lubos --- subsys/net/lib/sockets/sockets_tls.c | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/subsys/net/lib/sockets/sockets_tls.c b/subsys/net/lib/sockets/sockets_tls.c index ba490d325a9..fd87f0b23e0 100644 --- a/subsys/net/lib/sockets/sockets_tls.c +++ b/subsys/net/lib/sockets/sockets_tls.c @@ -3352,6 +3352,21 @@ int ztls_setsockopt_ctx(struct tls_context *ctx, int level, int optname, return 0; } +#if defined(CONFIG_NET_TEST) +mbedtls_ssl_context *ztls_get_mbedtls_ssl_context(int fd) +{ + struct tls_context *ctx; + + ctx = z_get_fd_obj(fd, (const struct fd_op_vtable *) + &tls_sock_fd_op_vtable, EBADF); + if (ctx == NULL) { + return NULL; + } + + return &ctx->ssl; +} +#endif /* CONFIG_NET_TEST */ + static ssize_t tls_sock_read_vmeth(void *obj, void *buffer, size_t count) { return ztls_recvfrom_ctx(obj, buffer, count, 0, NULL, 0); From 5b3b462eed823a21c2dc6d2cf004c33215c8282c Mon Sep 17 00:00:00 2001 From: Robert Lubos Date: Fri, 15 Dec 2023 11:20:47 +0100 Subject: [PATCH 1673/3723] net: sockets: tls: Add flag indicating that session is closed In case TLS session is closed at the TLS level (and thus recv() reports 0 to the application) a certain race occurs between consecutive recv() call, and TCP session teardown. As mbedtls_ssl_read() only reports session close upon receiving CLOSE alert, consecutive non-blocking recv() calls would report EAGAIN instead of connection closed, if called before underlying TCP connection was closed. Fix this, by storing the information that TLS session has ended at TLS socket level. The new flag will be checked before attempting further mbed TLS actions, so that connection status is reported correctly. Signed-off-by: Robert Lubos --- subsys/net/lib/sockets/sockets_tls.c | 39 +++++++++++++++++++--------- 1 file changed, 27 insertions(+), 12 deletions(-) diff --git a/subsys/net/lib/sockets/sockets_tls.c b/subsys/net/lib/sockets/sockets_tls.c index fd87f0b23e0..bdcc2b39e22 100644 --- a/subsys/net/lib/sockets/sockets_tls.c +++ b/subsys/net/lib/sockets/sockets_tls.c @@ -123,12 +123,24 @@ struct tls_dtls_cid { /** TLS context information. */ __net_socket struct tls_context { - /** Information whether TLS context is used. */ - bool is_used; - /** Underlying TCP/UDP socket. */ int sock; + /** Information whether TLS context is used. */ + bool is_used : 1; + + /** Information whether TLS context was initialized. */ + bool is_initialized : 1; + + /** Information whether underlying socket is listening. */ + bool is_listening : 1; + + /** Information whether TLS handshake is currently in progress. */ + bool handshake_in_progress : 1; + + /** Session ended at the TLS/DTLS level. */ + bool session_closed : 1; + /** Socket type. */ enum net_sock_type type; @@ -138,15 +150,6 @@ __net_socket struct tls_context { /** Socket flags passed to a socket call. */ int flags; - /** Information whether TLS context was initialized. */ - bool is_initialized; - - /** Information whether underlying socket is listening. */ - bool is_listening; - - /** Information whether TLS handshake is currently in progress. */ - bool handshake_in_progress; - /** Information whether TLS handshake is complete or not. */ struct k_sem tls_established; @@ -2202,6 +2205,10 @@ static ssize_t send_tls(struct tls_context *ctx, const void *buf, k_timepoint_t end; int ret; + if (ctx->session_closed) { + return 0; + } + if (!is_block) { timeout = K_NO_WAIT; } else { @@ -2413,6 +2420,10 @@ static ssize_t recv_tls(struct tls_context *ctx, void *buf, k_timepoint_t end; int ret; + if (ctx->session_closed) { + return 0; + } + if (!is_block) { timeout = K_NO_WAIT; } else { @@ -2431,6 +2442,7 @@ static ssize_t recv_tls(struct tls_context *ctx, void *buf, /* Peer notified that it's closing the * connection. */ + ctx->session_closed = true; break; } @@ -2439,6 +2451,7 @@ static ssize_t recv_tls(struct tls_context *ctx, void *buf, * supported. See mbedtls_ssl_read API * documentation. */ + ctx->session_closed = true; break; } @@ -2856,6 +2869,8 @@ static int ztls_socket_data_check(struct tls_context *ctx) if (ret != 0) { return -ENOMEM; } + } else { + ctx->session_closed = true; } return -ENOTCONN; From 0a1bee48bf08089ba91d1be0834e33e9bf8a18ad Mon Sep 17 00:00:00 2001 From: Robert Lubos Date: Fri, 15 Dec 2023 13:20:05 +0100 Subject: [PATCH 1674/3723] net: sockets: tls: Improve POLLERR error reporting In case a socket error was caused by TLS layer, it was not reported with POLLERR. This commit fixes this. Signed-off-by: Robert Lubos --- subsys/net/lib/sockets/sockets_tls.c | 100 +++++++++++++++++++++++++-- 1 file changed, 93 insertions(+), 7 deletions(-) diff --git a/subsys/net/lib/sockets/sockets_tls.c b/subsys/net/lib/sockets/sockets_tls.c index bdcc2b39e22..295bf5c2bb3 100644 --- a/subsys/net/lib/sockets/sockets_tls.c +++ b/subsys/net/lib/sockets/sockets_tls.c @@ -150,6 +150,9 @@ __net_socket struct tls_context { /** Socket flags passed to a socket call. */ int flags; + /* Indicates whether socket is in error state at TLS/DTLS level. */ + int error; + /** Information whether TLS handshake is complete or not. */ struct k_sem tls_established; @@ -1235,6 +1238,7 @@ static int tls_mbedtls_handshake(struct tls_context *context, ret = tls_mbedtls_reset(context); if (ret == 0) { NET_ERR("TLS handshake timeout"); + context->error = ETIMEDOUT; ret = -ETIMEDOUT; break; } @@ -1245,6 +1249,7 @@ static int tls_mbedtls_handshake(struct tls_context *context, NET_ERR("TLS handshake error: -0x%x", -ret); ret = tls_mbedtls_reset(context); if (ret == 0) { + context->error = ECONNABORTED; ret = -ECONNABORTED; break; } @@ -1252,6 +1257,7 @@ static int tls_mbedtls_handshake(struct tls_context *context, /* Avoid constant loop if tls_mbedtls_reset fails */ NET_ERR("TLS reset error: -0x%x", -ret); + context->error = ECONNABORTED; ret = -ECONNABORTED; break; } @@ -2205,6 +2211,11 @@ static ssize_t send_tls(struct tls_context *ctx, const void *buf, k_timepoint_t end; int ret; + if (ctx->error != 0) { + errno = ctx->error; + return -1; + } + if (ctx->session_closed) { return 0; } @@ -2249,8 +2260,18 @@ static ssize_t send_tls(struct tls_context *ctx, const void *buf, break; } } else { - (void)tls_mbedtls_reset(ctx); - errno = EIO; + /* MbedTLS API documentation requires session to + * be reset in other error cases + */ + ret = tls_mbedtls_reset(ctx); + if (ret != 0) { + ctx->error = ENOMEM; + errno = ENOMEM; + } else { + ctx->error = ECONNABORTED; + errno = ECONNABORTED; + } + break; } } while (true); @@ -2302,6 +2323,9 @@ static ssize_t sendto_dtls_client(struct tls_context *ctx, const void *buf, goto error; } + /* Client socket ready to use again. */ + ctx->error = 0; + tls_session_store(ctx, &ctx->dtls_peer_addr, ctx->dtls_peer_addrlen); } @@ -2420,6 +2444,11 @@ static ssize_t recv_tls(struct tls_context *ctx, void *buf, k_timepoint_t end; int ret; + if (ctx->error != 0) { + errno = ctx->error; + return -1; + } + if (ctx->session_closed) { return 0; } @@ -2514,6 +2543,11 @@ static ssize_t recvfrom_dtls_common(struct tls_context *ctx, void *buf, k_timeout_t timeout; k_timepoint_t end; + if (ctx->error != 0) { + errno = ctx->error; + return -1; + } + if (!is_block) { timeout = K_NO_WAIT; } else { @@ -2628,14 +2662,17 @@ static ssize_t recvfrom_dtls_client(struct tls_context *ctx, void *buf, /* Peer notified that it's closing the connection. */ ret = tls_mbedtls_reset(ctx); if (ret == 0) { + ctx->error = ENOTCONN; ret = -ENOTCONN; } else { + ctx->error = ENOMEM; ret = -ENOMEM; } break; case MBEDTLS_ERR_SSL_TIMEOUT: (void)mbedtls_ssl_close_notify(&ctx->ssl); + ctx->error = ETIMEDOUT; ret = -ETIMEDOUT; break; @@ -2647,7 +2684,18 @@ static ssize_t recvfrom_dtls_client(struct tls_context *ctx, void *buf, break; default: - ret = -EIO; + /* MbedTLS API documentation requires session to + * be reset in other error cases + */ + ret = tls_mbedtls_reset(ctx); + if (ret != 0) { + ctx->error = ENOMEM; + errno = ENOMEM; + } else { + ctx->error = ECONNABORTED; + ret = -ECONNABORTED; + } + break; } @@ -2701,6 +2749,9 @@ static ssize_t recvfrom_dtls_server(struct tls_context *ctx, void *buf, continue; } + + /* Server socket ready to use again. */ + ctx->error = 0; } ret = recvfrom_dtls_common(ctx, buf, max_len, flags, @@ -2721,6 +2772,7 @@ static ssize_t recvfrom_dtls_server(struct tls_context *ctx, void *buf, if (ret == 0) { repeat = true; } else { + ctx->error = ENOMEM; ret = -ENOMEM; } break; @@ -2733,7 +2785,15 @@ static ssize_t recvfrom_dtls_server(struct tls_context *ctx, void *buf, break; default: - ret = -EIO; + ret = tls_mbedtls_reset(ctx); + if (ret != 0) { + ctx->error = ENOMEM; + errno = ENOMEM; + } else { + ctx->error = ECONNABORTED; + ret = -ECONNABORTED; + } + break; } } while (repeat); @@ -2881,8 +2941,15 @@ static int ztls_socket_data_check(struct tls_context *ctx) return 0; } - /* Treat any other error as fatal. */ - return -EIO; + /* MbedTLS API documentation requires session to + * be reset in other error cases + */ + ret = tls_mbedtls_reset(ctx); + if (ret != 0) { + return -ENOMEM; + } + + return -ECONNABORTED; } return mbedtls_ssl_get_bytes_avail(&ctx->ssl); @@ -2921,6 +2988,7 @@ static int ztls_poll_update_pollin(int fd, struct tls_context *ctx, pfd->revents |= ZSOCK_POLLHUP; goto next; } else if (ret < 0) { + ctx->error = -ret; pfd->revents |= ZSOCK_POLLERR; goto next; } else if (ret == 0) { @@ -3182,7 +3250,25 @@ int ztls_getsockopt_ctx(struct tls_context *ctx, int level, int optname, return -1; } return err; - } else if (level != SOL_TLS) { + } + + /* In case error was set on a socket at the TLS layer (for example due + * to receiving TLS alert), handle SO_ERROR here, and report that error. + * Otherwise, forward the SO_ERROR option request to the underlying + * TCP/UDP socket to handle. + */ + if ((level == SOL_SOCKET) && (optname == SO_ERROR) && ctx->error != 0) { + if (*optlen != sizeof(int)) { + errno = EINVAL; + return -1; + } + + *(int *)optval = ctx->error; + + return 0; + } + + if (level != SOL_TLS) { return zsock_getsockopt(ctx->sock, level, optname, optval, optlen); } From c0d5d2fbd51e8e206b2b7aeb66bdee7351bdf962 Mon Sep 17 00:00:00 2001 From: Robert Lubos Date: Tue, 19 Dec 2023 13:12:52 +0100 Subject: [PATCH 1675/3723] net: sockets: tls: Allow handshake during poll() When using DTLS socket, the application may choose to monitor socket with poll() before handshake has been complete. This could lead to potential crash (as the TLS context may have been left uninitialized) and unexpected POLLIN reports (while handshake was still not complete). This commit fixes the above - POLLIN will only be reported once handshake is complete and data is available Signed-off-by: Robert Lubos --- subsys/net/lib/sockets/sockets_tls.c | 41 ++++++++++++++++++++++++++++ 1 file changed, 41 insertions(+) diff --git a/subsys/net/lib/sockets/sockets_tls.c b/subsys/net/lib/sockets/sockets_tls.c index 295bf5c2bb3..ca5479d5d54 100644 --- a/subsys/net/lib/sockets/sockets_tls.c +++ b/subsys/net/lib/sockets/sockets_tls.c @@ -2910,10 +2910,51 @@ static int ztls_poll_prepare_ctx(struct tls_context *ctx, return ret; } +#include + static int ztls_socket_data_check(struct tls_context *ctx) { int ret; + if (ctx->type == SOCK_STREAM) { + if (!ctx->is_initialized) { + return -ENOTCONN; + } + } +#if defined(CONFIG_NET_SOCKETS_ENABLE_DTLS) + else { + if (!ctx->is_initialized) { + bool is_server = ctx->options.role == MBEDTLS_SSL_IS_SERVER; + + ret = tls_mbedtls_init(ctx, is_server); + if (ret < 0) { + return -ENOMEM; + } + } + + if (!is_handshake_complete(ctx)) { + ret = tls_mbedtls_handshake(ctx, K_NO_WAIT); + if (ret < 0) { + if (ret == -EAGAIN) { + return 0; + } + + ret = tls_mbedtls_reset(ctx); + if (ret != 0) { + return -ENOMEM; + } + + return 0; + } + + /* Socket ready to use again. */ + ctx->error = 0; + + return 0; + } + } +#endif /* CONFIG_NET_SOCKETS_ENABLE_DTLS */ + ctx->flags = ZSOCK_MSG_DONTWAIT; ret = mbedtls_ssl_read(&ctx->ssl, NULL, 0); From 898aa9ed9abde1b309cf64e8769db412f6c95b83 Mon Sep 17 00:00:00 2001 From: Robert Lubos Date: Tue, 19 Dec 2023 14:38:43 +0100 Subject: [PATCH 1676/3723] net: sockets: tls: Align DTLS connect() behavior with regular TLS DTLS socket is not really connection-less as UDP, as it required the DTLS handshake to take place before the socket is usable. Therefore, align the DTLS connect() behavior with regular TLS. The change is backward compatible. connect() call is still optional for DTLS socket (the handshake can still take place from send()/recv()) and a socket option was provided to disable DTLS handshake on connect(). Signed-off-by: Robert Lubos --- include/zephyr/net/socket.h | 8 ++++ subsys/net/lib/sockets/sockets_tls.c | 63 +++++++++++++++++++++++----- 2 files changed, 61 insertions(+), 10 deletions(-) diff --git a/include/zephyr/net/socket.h b/include/zephyr/net/socket.h index a61b8604973..3eca4347a85 100644 --- a/include/zephyr/net/socket.h +++ b/include/zephyr/net/socket.h @@ -232,6 +232,14 @@ struct zsock_pollfd { * connection ID, otherwise will contain the length of the CID value. */ #define TLS_DTLS_PEER_CID_VALUE 17 +/** Socket option to configure DTLS socket behavior on connect(). + * If set, DTLS connect() will execute the handshake with the configured peer. + * This is the default behavior. + * Otherwise, DTLS connect() will only configure peer address (as with regular + * UDP socket) and will not attempt to execute DTLS handshake. The handshake + * will take place in consecutive send()/recv() call. + */ +#define TLS_DTLS_HANDSHAKE_ON_CONNECT 18 /* Valid values for @ref TLS_PEER_VERIFY option */ #define TLS_PEER_VERIFY_NONE 0 /**< Peer verification disabled. */ diff --git a/subsys/net/lib/sockets/sockets_tls.c b/subsys/net/lib/sockets/sockets_tls.c index ca5479d5d54..49222758ae2 100644 --- a/subsys/net/lib/sockets/sockets_tls.c +++ b/subsys/net/lib/sockets/sockets_tls.c @@ -202,6 +202,8 @@ __net_socket struct tls_context { uint32_t dtls_handshake_timeout_max; struct tls_dtls_cid dtls_cid; + + bool dtls_handshake_on_connect; #endif /* CONFIG_NET_SOCKETS_ENABLE_DTLS */ } options; @@ -465,6 +467,7 @@ static struct tls_context *tls_alloc(void) MBEDTLS_SSL_DTLS_TIMEOUT_DFL_MAX; tls->options.dtls_cid.cid_len = 0; tls->options.dtls_cid.enabled = false; + tls->options.dtls_handshake_on_connect = true; #endif #if defined(MBEDTLS_X509_CRT_PARSE_C) mbedtls_x509_crt_init(&tls->ca_chain); @@ -1822,6 +1825,37 @@ static int tls_opt_dtls_connection_id_status_get(struct tls_context *context, #endif } +static int tls_opt_dtls_handshake_on_connect_set(struct tls_context *context, + const void *optval, + socklen_t optlen) +{ + int *val = (int *)optval; + + if (!optval) { + return -EINVAL; + } + + if (sizeof(int) != optlen) { + return -EINVAL; + } + + context->options.dtls_handshake_on_connect = (bool)*val; + + return 0; +} + +static int tls_opt_dtls_handshake_on_connect_get(struct tls_context *context, + void *optval, + socklen_t *optlen) +{ + if (*optlen != sizeof(int)) { + return -EINVAL; + } + + *(int *)optval = context->options.dtls_handshake_on_connect; + + return 0; +} #endif /* CONFIG_NET_SOCKETS_ENABLE_DTLS */ static int tls_opt_alpn_list_get(struct tls_context *context, @@ -2099,8 +2133,17 @@ int ztls_connect_ctx(struct tls_context *ctx, const struct sockaddr *addr, (void)zsock_fcntl(ctx->sock, F_SETFL, sock_flags); } - if (ctx->type == SOCK_STREAM) { - /* Do the handshake for TLS, not DTLS. */ +#if defined(CONFIG_NET_SOCKETS_ENABLE_DTLS) + if (ctx->type == SOCK_DGRAM) { + dtls_peer_address_set(ctx, addr, addrlen); + } +#endif + + if (ctx->type == SOCK_STREAM +#if defined(CONFIG_NET_SOCKETS_ENABLE_DTLS) + || (ctx->type == SOCK_DGRAM && ctx->options.dtls_handshake_on_connect) +#endif + ) { ret = tls_mbedtls_init(ctx, false); if (ret < 0) { goto error; @@ -2120,14 +2163,6 @@ int ztls_connect_ctx(struct tls_context *ctx, const struct sockaddr *addr, } tls_session_store(ctx, addr, addrlen); - } else { -#if defined(CONFIG_NET_SOCKETS_ENABLE_DTLS) - /* Just store the address. */ - dtls_peer_address_set(ctx, addr, addrlen); -#else - ret = -ENOTSUP; - goto error; -#endif /* CONFIG_NET_SOCKETS_ENABLE_DTLS */ } return 0; @@ -3359,6 +3394,10 @@ int ztls_getsockopt_ctx(struct tls_context *ctx, int level, int optname, err = tls_opt_dtls_peer_connection_id_value_get(ctx, optval, optlen); break; + + case TLS_DTLS_HANDSHAKE_ON_CONNECT: + err = tls_opt_dtls_handshake_on_connect_get(ctx, optval, optlen); + break; #endif /* CONFIG_NET_SOCKETS_ENABLE_DTLS */ default: @@ -3472,6 +3511,10 @@ int ztls_setsockopt_ctx(struct tls_context *ctx, int level, int optname, err = tls_opt_dtls_connection_id_value_set(ctx, optval, optlen); break; + case TLS_DTLS_HANDSHAKE_ON_CONNECT: + err = tls_opt_dtls_handshake_on_connect_set(ctx, optval, optlen); + break; + #endif /* CONFIG_NET_SOCKETS_ENABLE_DTLS */ case TLS_NATIVE: From f70715eeb3039b14f74f5232b169fb9586ec587a Mon Sep 17 00:00:00 2001 From: Robert Lubos Date: Fri, 8 Dec 2023 16:56:55 +0100 Subject: [PATCH 1677/3723] tests: net: socket: tls: Add more tests covering poll() Add new test cases, covering TLS/DTLS socket poll() functionality. Signed-off-by: Robert Lubos --- tests/net/socket/tls/CMakeLists.txt | 1 + tests/net/socket/tls/src/main.c | 467 +++++++++++++++++++++++----- 2 files changed, 388 insertions(+), 80 deletions(-) diff --git a/tests/net/socket/tls/CMakeLists.txt b/tests/net/socket/tls/CMakeLists.txt index 2d38911a56f..ee917f3608f 100644 --- a/tests/net/socket/tls/CMakeLists.txt +++ b/tests/net/socket/tls/CMakeLists.txt @@ -5,5 +5,6 @@ find_package(Zephyr REQUIRED HINTS $ENV{ZEPHYR_BASE}) project(socket_tls) target_include_directories(app PRIVATE ${ZEPHYR_BASE}/subsys/net/ip) +target_include_directories(app PRIVATE ${ZEPHYR_BASE}/subsys/net/lib/sockets) FILE(GLOB app_sources src/*.c) target_sources(app PRIVATE ${app_sources}) diff --git a/tests/net/socket/tls/src/main.c b/tests/net/socket/tls/src/main.c index 7467f33b059..576c24b0206 100644 --- a/tests/net/socket/tls/src/main.c +++ b/tests/net/socket/tls/src/main.c @@ -12,6 +12,7 @@ LOG_MODULE_REGISTER(net_test, CONFIG_NET_SOCKETS_LOG_LEVEL); #include #include #include +#include #include "../../socket_helpers.h" @@ -170,12 +171,12 @@ static void test_eof(int sock) zassert_equal(recved, 0, ""); /* Calling again should be OK. */ - recved = recv(sock, rx_buf, sizeof(rx_buf), 0); + recved = recv(sock, rx_buf, sizeof(rx_buf), ZSOCK_MSG_DONTWAIT); zassert_equal(recved, 0, ""); /* Calling when TCP connection is fully torn down should be still OK. */ k_sleep(TCP_TEARDOWN_TIMEOUT); - recved = recv(sock, rx_buf, sizeof(rx_buf), 0); + recved = recv(sock, rx_buf, sizeof(rx_buf), ZSOCK_MSG_DONTWAIT); zassert_equal(recved, 0, ""); } @@ -269,6 +270,18 @@ static void client_connect_work_handler(struct k_work *work) sizeof(struct sockaddr_in) : sizeof(struct sockaddr_in6)); } +static void dtls_client_connect_send_work_handler(struct k_work *work) +{ + struct k_work_delayable *dwork = k_work_delayable_from_work(work); + struct connect_data *data = + CONTAINER_OF(dwork, struct connect_data, work); + uint8_t tx_buf = 0; + + test_connect(data->sock, data->addr, data->addr->sa_family == AF_INET ? + sizeof(struct sockaddr_in) : sizeof(struct sockaddr_in6)); + test_send(data->sock, &tx_buf, sizeof(tx_buf), 0); +} + static void test_prepare_tls_connection(sa_family_t family, int *c_sock, int *s_sock, int *new_sock) { @@ -316,6 +329,66 @@ static void test_prepare_tls_connection(sa_family_t family, int *c_sock, test_work_wait(&test_data.work); } +static void test_prepare_dtls_connection(sa_family_t family, int *c_sock, + int *s_sock) +{ + struct sockaddr c_saddr; + struct sockaddr s_saddr; + socklen_t exp_addrlen = family == AF_INET6 ? + sizeof(struct sockaddr_in6) : + sizeof(struct sockaddr_in); + struct connect_data test_data; + int role = TLS_DTLS_ROLE_SERVER; + struct pollfd fds[1]; + uint8_t rx_buf; + int ret; + + + if (family == AF_INET6) { + prepare_sock_dtls_v6(MY_IPV6_ADDR, ANY_PORT, c_sock, + (struct sockaddr_in6 *)&c_saddr, + IPPROTO_DTLS_1_2); + prepare_sock_dtls_v6(MY_IPV6_ADDR, ANY_PORT, s_sock, + (struct sockaddr_in6 *)&s_saddr, + IPPROTO_DTLS_1_2); + } else { + prepare_sock_dtls_v4(MY_IPV4_ADDR, ANY_PORT, c_sock, + (struct sockaddr_in *)&c_saddr, + IPPROTO_DTLS_1_2); + prepare_sock_dtls_v4(MY_IPV4_ADDR, ANY_PORT, s_sock, + (struct sockaddr_in *)&s_saddr, + IPPROTO_DTLS_1_2); + } + + test_config_psk(*s_sock, *c_sock); + + zassert_equal(setsockopt(*s_sock, SOL_TLS, TLS_DTLS_ROLE, + &role, sizeof(role)), + 0, "setsockopt() failed"); + + test_bind(*s_sock, &s_saddr, exp_addrlen); + + test_data.sock = *c_sock; + test_data.addr = &s_saddr; + k_work_init_delayable(&test_data.work, dtls_client_connect_send_work_handler); + test_work_reschedule(&test_data.work, K_NO_WAIT); + + /* DTLS has no separate call like accept() to know when the handshake + * is complete, therefore send a dummy byte once handshake is done to + * unblock poll(). + */ + fds[0].fd = *s_sock; + fds[0].events = POLLIN; + ret = poll(fds, 1, 1000); + zassert_equal(ret, 1, "poll() did not report data ready"); + + /* Flush the dummy byte. */ + ret = recv(*s_sock, &rx_buf, sizeof(rx_buf), 0); + zassert_equal(ret, sizeof(rx_buf), "recv() failed"); + + test_work_wait(&test_data.work); +} + ZTEST(net_socket_tls, test_v4_msg_waitall) { struct test_msg_waitall_data test_data = { @@ -454,31 +527,17 @@ static void send_work_handler(struct k_work *work) test_send(test_data->sock, test_data->data, test_data->datalen, 0); } -void test_msg_trunc(int sock_c, int sock_s, struct sockaddr *addr_c, - socklen_t addrlen_c, struct sockaddr *addr_s, - socklen_t addrlen_s) +void test_msg_trunc(sa_family_t family) { int rv; uint8_t rx_buf[sizeof(TEST_STR_SMALL) - 1]; - int role = TLS_DTLS_ROLE_SERVER; struct send_data test_data = { .data = TEST_STR_SMALL, .datalen = sizeof(TEST_STR_SMALL) - 1 }; + int sock_c, sock_s; - test_config_psk(sock_s, sock_c); - - rv = setsockopt(sock_s, SOL_TLS, TLS_DTLS_ROLE, &role, sizeof(role)); - zassert_equal(rv, 0, "failed to set DTLS server role"); - - rv = bind(sock_s, addr_s, addrlen_s); - zassert_equal(rv, 0, "server bind failed"); - - rv = bind(sock_c, addr_c, addrlen_c); - zassert_equal(rv, 0, "client bind failed"); - - rv = connect(sock_c, addr_s, addrlen_s); - zassert_equal(rv, 0, "connect failed"); + test_prepare_dtls_connection(family, &sock_c, &sock_s); /* MSG_TRUNC */ @@ -505,36 +564,19 @@ void test_msg_trunc(int sock_c, int sock_s, struct sockaddr *addr_c, zassert_equal(rv, 0, "close failed"); test_work_wait(&test_data.tx_work); + + /* Small delay for the final alert exchange */ + k_msleep(10); } ZTEST(net_socket_tls, test_v4_msg_trunc) { - int client_sock; - int server_sock; - struct sockaddr_in client_addr; - struct sockaddr_in server_addr; - - prepare_sock_dtls_v4(MY_IPV4_ADDR, ANY_PORT, &client_sock, &client_addr, IPPROTO_DTLS_1_2); - prepare_sock_dtls_v4(MY_IPV4_ADDR, ANY_PORT, &server_sock, &server_addr, IPPROTO_DTLS_1_2); - - test_msg_trunc(client_sock, server_sock, - (struct sockaddr *)&client_addr, sizeof(client_addr), - (struct sockaddr *)&server_addr, sizeof(server_addr)); + test_msg_trunc(AF_INET); } ZTEST(net_socket_tls, test_v6_msg_trunc) { - int client_sock; - int server_sock; - struct sockaddr_in6 client_addr; - struct sockaddr_in6 server_addr; - - prepare_sock_dtls_v6(MY_IPV6_ADDR, ANY_PORT, &client_sock, &client_addr, IPPROTO_DTLS_1_2); - prepare_sock_dtls_v6(MY_IPV6_ADDR, ANY_PORT, &server_sock, &server_addr, IPPROTO_DTLS_1_2); - - test_msg_trunc(client_sock, server_sock, - (struct sockaddr *)&client_addr, sizeof(client_addr), - (struct sockaddr *)&server_addr, sizeof(server_addr)); + test_msg_trunc(AF_INET6); } struct test_sendmsg_data { @@ -552,13 +594,10 @@ static void test_sendmsg_tx_work_handler(struct k_work *work) test_sendmsg(test_data->sock, test_data->msg, 0); } -static void test_dtls_sendmsg(int sock_c, int sock_s, struct sockaddr *addr_c, - socklen_t addrlen_c, struct sockaddr *addr_s, - socklen_t addrlen_s) +static void test_dtls_sendmsg(sa_family_t family) { int rv; uint8_t rx_buf[sizeof(TEST_STR_SMALL) - 1]; - int role = TLS_DTLS_ROLE_SERVER; struct iovec iov[3] = { {}, { @@ -571,20 +610,9 @@ static void test_dtls_sendmsg(int sock_c, int sock_s, struct sockaddr *addr_c, struct test_sendmsg_data test_data = { .msg = &msg, }; + int sock_c, sock_s; - test_config_psk(sock_s, sock_c); - - rv = setsockopt(sock_s, SOL_TLS, TLS_DTLS_ROLE, &role, sizeof(role)); - zassert_equal(rv, 0, "failed to set DTLS server role"); - - rv = bind(sock_s, addr_s, addrlen_s); - zassert_equal(rv, 0, "server bind failed"); - - rv = bind(sock_c, addr_c, addrlen_c); - zassert_equal(rv, 0, "client bind failed"); - - rv = connect(sock_c, addr_s, addrlen_s); - zassert_equal(rv, 0, "connect failed"); + test_prepare_dtls_connection(family, &sock_c, &sock_s); test_data.sock = sock_c; k_work_init_delayable(&test_data.tx_work, test_sendmsg_tx_work_handler); @@ -630,36 +658,19 @@ static void test_dtls_sendmsg(int sock_c, int sock_s, struct sockaddr *addr_c, zassert_equal(rv, 0, "close failed"); rv = close(sock_s); zassert_equal(rv, 0, "close failed"); + + /* Small delay for the final alert exchange */ + k_msleep(10); } ZTEST(net_socket_tls, test_v4_dtls_sendmsg) { - int client_sock; - int server_sock; - struct sockaddr_in client_addr; - struct sockaddr_in server_addr; - - prepare_sock_dtls_v4(MY_IPV4_ADDR, ANY_PORT, &client_sock, &client_addr, IPPROTO_DTLS_1_2); - prepare_sock_dtls_v4(MY_IPV4_ADDR, ANY_PORT, &server_sock, &server_addr, IPPROTO_DTLS_1_2); - - test_dtls_sendmsg(client_sock, server_sock, - (struct sockaddr *)&client_addr, sizeof(client_addr), - (struct sockaddr *)&server_addr, sizeof(server_addr)); + test_dtls_sendmsg(AF_INET); } ZTEST(net_socket_tls, test_v6_dtls_sendmsg) { - int client_sock; - int server_sock; - struct sockaddr_in6 client_addr; - struct sockaddr_in6 server_addr; - - prepare_sock_dtls_v6(MY_IPV6_ADDR, ANY_PORT, &client_sock, &client_addr, IPPROTO_DTLS_1_2); - prepare_sock_dtls_v6(MY_IPV6_ADDR, ANY_PORT, &server_sock, &server_addr, IPPROTO_DTLS_1_2); - - test_dtls_sendmsg(client_sock, server_sock, - (struct sockaddr *)&client_addr, sizeof(client_addr), - (struct sockaddr *)&server_addr, sizeof(server_addr)); + test_dtls_sendmsg(AF_INET6); } struct close_data { @@ -1015,6 +1026,22 @@ ZTEST(net_socket_tls, test_recv_block) k_sleep(TCP_TEARDOWN_TIMEOUT); } +ZTEST(net_socket_tls, test_recv_eof_on_close) +{ + int c_sock, s_sock, new_sock; + + test_prepare_tls_connection(AF_INET6, &c_sock, &s_sock, &new_sock); + test_close(c_sock); + + /* Verify recv() reports EOF */ + test_eof(new_sock); + + test_close(new_sock); + test_close(s_sock); + + k_sleep(TCP_TEARDOWN_TIMEOUT); +} + #define TLS_RECORD_OVERHEAD 81 ZTEST(net_socket_tls, test_send_non_block) @@ -1360,6 +1387,286 @@ ZTEST(net_socket_tls, test_send_while_recv) k_sleep(TCP_TEARDOWN_TIMEOUT); } +ZTEST(net_socket_tls, test_poll_tls_pollin) +{ + uint8_t rx_buf[sizeof(TEST_STR_SMALL) - 1]; + int c_sock, s_sock, new_sock, ret; + struct pollfd fds[1]; + + test_prepare_tls_connection(AF_INET6, &c_sock, &s_sock, &new_sock); + + fds[0].fd = new_sock; + fds[0].events = POLLIN; + + ret = poll(fds, 1, 0); + zassert_equal(ret, 0, "Unexpected poll() event"); + + ret = send(c_sock, TEST_STR_SMALL, sizeof(TEST_STR_SMALL) - 1, 0); + zassert_equal(ret, strlen(TEST_STR_SMALL), "send() failed"); + + ret = poll(fds, 1, 100); + zassert_equal(ret, 1, "poll() should've report event"); + zassert_equal(fds[0].revents, POLLIN, "No POLLIN event"); + + /* Check that data is really available */ + ret = recv(new_sock, rx_buf, sizeof(rx_buf), ZSOCK_MSG_DONTWAIT); + zassert_equal(ret, sizeof(TEST_STR_SMALL) - 1, "recv() failed"); + zassert_mem_equal(rx_buf, TEST_STR_SMALL, ret, "Invalid data received"); + + test_close(c_sock); + test_close(new_sock); + test_close(s_sock); + + k_sleep(TCP_TEARDOWN_TIMEOUT); +} + +ZTEST(net_socket_tls, test_poll_dtls_pollin) +{ + uint8_t rx_buf[sizeof(TEST_STR_SMALL) - 1]; + struct send_data test_data = { + .data = TEST_STR_SMALL, + .datalen = sizeof(TEST_STR_SMALL) - 1 + }; + int c_sock, s_sock, ret; + struct pollfd fds[1]; + + test_prepare_dtls_connection(AF_INET6, &c_sock, &s_sock); + + fds[0].fd = s_sock; + fds[0].events = POLLIN; + + ret = poll(fds, 1, 0); + zassert_equal(ret, 0, "Unexpected poll() event"); + + test_data.sock = c_sock; + k_work_init_delayable(&test_data.tx_work, send_work_handler); + test_work_reschedule(&test_data.tx_work, K_NO_WAIT); + + ret = poll(fds, 1, 100); + zassert_equal(ret, 1, "poll() should've report event"); + zassert_equal(fds[0].revents, POLLIN, "No POLLIN event"); + + /* Check that data is really available */ + ret = recv(s_sock, rx_buf, sizeof(rx_buf), ZSOCK_MSG_DONTWAIT); + zassert_equal(ret, sizeof(TEST_STR_SMALL) - 1, "recv() failed"); + zassert_mem_equal(rx_buf, TEST_STR_SMALL, ret, "Invalid data received"); + + test_close(c_sock); + test_close(s_sock); + + /* Small delay for the final alert exchange */ + k_msleep(10); +} + +ZTEST(net_socket_tls, test_poll_tls_pollout) +{ + int buf_optval = TLS_RECORD_OVERHEAD + sizeof(TEST_STR_SMALL) - 1; + uint8_t rx_buf[sizeof(TEST_STR_SMALL) - 1]; + int c_sock, s_sock, new_sock, ret; + struct pollfd fds[1]; + + test_prepare_tls_connection(AF_INET6, &c_sock, &s_sock, &new_sock); + + fds[0].fd = c_sock; + fds[0].events = POLLOUT; + + ret = poll(fds, 1, 0); + zassert_equal(ret, 1, "poll() should've report event"); + zassert_equal(fds[0].revents, POLLOUT, "No POLLOUT event"); + + /* Simulate window full scenario with SO_RCVBUF option. */ + ret = setsockopt(new_sock, SOL_SOCKET, SO_RCVBUF, &buf_optval, + sizeof(buf_optval)); + zassert_equal(ret, 0, "setsockopt failed (%d)", errno); + + /* Fill out the window */ + ret = send(c_sock, TEST_STR_SMALL, strlen(TEST_STR_SMALL), 0); + zassert_equal(ret, strlen(TEST_STR_SMALL), "send() failed"); + + /* Wait for ACK (empty window, min. 100 ms due to silly window + * protection). + */ + k_sleep(K_MSEC(150)); + + /* poll() shouldn't report POLLOUT now */ + ret = poll(fds, 1, 0); + zassert_equal(ret, 0, "Unexpected poll() event"); + + /* Consume the data, and check if the client sock is writeable again */ + ret = recv(new_sock, rx_buf, sizeof(rx_buf), ZSOCK_MSG_DONTWAIT); + zassert_equal(ret, sizeof(TEST_STR_SMALL) - 1, "recv() failed"); + zassert_mem_equal(rx_buf, TEST_STR_SMALL, ret, "Invalid data received"); + + ret = poll(fds, 1, 100); + zassert_equal(ret, 1, "poll() should've report event"); + zassert_equal(fds[0].revents, POLLOUT, "No POLLOUT event"); + + test_close(c_sock); + test_close(new_sock); + test_close(s_sock); + + k_sleep(TCP_TEARDOWN_TIMEOUT); +} + +ZTEST(net_socket_tls, test_poll_dtls_pollout) +{ + struct pollfd fds[1]; + int c_sock, s_sock, ret; + + test_prepare_dtls_connection(AF_INET6, &c_sock, &s_sock); + + fds[0].fd = c_sock; + fds[0].events = POLLOUT; + + /* DTLS socket should always be writeable. */ + ret = poll(fds, 1, 0); + zassert_equal(ret, 1, "poll() should've report event"); + zassert_equal(fds[0].revents, POLLOUT, "No POLLOUT event"); + + test_close(c_sock); + test_close(s_sock); + + /* Small delay for the final alert exchange */ + k_msleep(10); +} + +ZTEST(net_socket_tls, test_poll_tls_pollhup) +{ + struct pollfd fds[1]; + uint8_t rx_buf; + int c_sock, s_sock, new_sock, ret; + + test_prepare_tls_connection(AF_INET6, &c_sock, &s_sock, &new_sock); + + fds[0].fd = new_sock; + fds[0].events = POLLIN; + + test_close(c_sock); + + ret = poll(fds, 1, 100); + zassert_equal(ret, 1, "poll() should've report event"); + zassert_true(fds[0].revents & POLLIN, "No POLLIN event"); + zassert_true(fds[0].revents & POLLHUP, "No POLLHUP event"); + + /* Check that connection was indeed closed */ + ret = recv(new_sock, &rx_buf, sizeof(rx_buf), ZSOCK_MSG_DONTWAIT); + zassert_equal(ret, 0, "recv() did not report connection close"); + + test_close(new_sock); + test_close(s_sock); + + k_sleep(TCP_TEARDOWN_TIMEOUT); +} + +ZTEST(net_socket_tls, test_poll_dtls_pollhup) +{ + struct pollfd fds[1]; + uint8_t rx_buf; + int c_sock, s_sock, ret; + + test_prepare_dtls_connection(AF_INET6, &c_sock, &s_sock); + + fds[0].fd = s_sock; + fds[0].events = POLLIN; + + test_close(c_sock); + + ret = poll(fds, 1, 100); + zassert_equal(ret, 1, "poll() should've report event"); + zassert_equal(fds[0].revents, POLLHUP, "No POLLHUP event"); + + /* Check that connection was indeed closed */ + ret = recv(s_sock, &rx_buf, sizeof(rx_buf), ZSOCK_MSG_DONTWAIT); + zassert_equal(ret, -1, "recv() should report EAGAIN"); + zassert_equal(errno, EAGAIN, "Unexpected errno value: %d", errno); + + test_close(s_sock); + + /* Small delay for the final alert exchange */ + k_msleep(10); +} + +mbedtls_ssl_context *ztls_get_mbedtls_ssl_context(int fd); + +ZTEST(net_socket_tls, test_poll_tls_pollerr) +{ + uint8_t rx_buf; + int c_sock, s_sock, new_sock, ret; + struct pollfd fds[1]; + int optval; + socklen_t optlen = sizeof(optval); + mbedtls_ssl_context *ssl_ctx; + + test_prepare_tls_connection(AF_INET6, &c_sock, &s_sock, &new_sock); + + fds[0].fd = new_sock; + fds[0].events = POLLIN; + + /* Get access to the underlying ssl context, and send alert. */ + ssl_ctx = ztls_get_mbedtls_ssl_context(c_sock); + mbedtls_ssl_send_alert_message(ssl_ctx, MBEDTLS_SSL_ALERT_LEVEL_FATAL, + MBEDTLS_SSL_ALERT_MSG_INTERNAL_ERROR); + + ret = poll(fds, 1, 100); + zassert_equal(ret, 1, "poll() should've report event"); + zassert_true(fds[0].revents & POLLERR, "No POLLERR event"); + + ret = getsockopt(new_sock, SOL_SOCKET, SO_ERROR, &optval, &optlen); + zassert_equal(ret, 0, "getsockopt failed (%d)", errno); + zassert_equal(optval, ECONNABORTED, "getsockopt got invalid error %d", + optval); + + ret = recv(new_sock, &rx_buf, sizeof(rx_buf), ZSOCK_MSG_DONTWAIT); + zassert_equal(ret, -1, "recv() did not report error"); + zassert_equal(errno, ECONNABORTED, "Unexpected errno value: %d", errno); + + test_close(c_sock); + test_close(new_sock); + test_close(s_sock); + + k_sleep(TCP_TEARDOWN_TIMEOUT); +} + +ZTEST(net_socket_tls, test_poll_dtls_pollerr) +{ + uint8_t rx_buf; + int c_sock, s_sock, ret; + struct pollfd fds[1]; + int optval; + socklen_t optlen = sizeof(optval); + mbedtls_ssl_context *ssl_ctx; + + test_prepare_dtls_connection(AF_INET6, &c_sock, &s_sock); + + fds[0].fd = s_sock; + fds[0].events = POLLIN; + + /* Get access to the underlying ssl context, and send alert. */ + ssl_ctx = ztls_get_mbedtls_ssl_context(c_sock); + mbedtls_ssl_send_alert_message(ssl_ctx, MBEDTLS_SSL_ALERT_LEVEL_FATAL, + MBEDTLS_SSL_ALERT_MSG_INTERNAL_ERROR); + + ret = poll(fds, 1, 100); + zassert_equal(ret, 1, "poll() should've report event"); + zassert_true(fds[0].revents & POLLERR, "No POLLERR event"); + + ret = getsockopt(s_sock, SOL_SOCKET, SO_ERROR, &optval, &optlen); + zassert_equal(ret, 0, "getsockopt failed (%d)", errno); + zassert_equal(optval, ECONNABORTED, "getsockopt got invalid error %d", + optval); + + /* DTLS server socket should recover and be ready to accept new session. */ + ret = recv(s_sock, &rx_buf, sizeof(rx_buf), ZSOCK_MSG_DONTWAIT); + zassert_equal(ret, -1, "recv() did not report error"); + zassert_equal(errno, EAGAIN, "Unexpected errno value: %d", errno); + + test_close(c_sock); + test_close(s_sock); + + /* Small delay for the final alert exchange */ + k_msleep(10); +} + static void *tls_tests_setup(void) { k_work_queue_init(&tls_test_work_queue); From 48601fde9690f6c9ce38550548f02e0d65165430 Mon Sep 17 00:00:00 2001 From: Robert Lubos Date: Thu, 14 Dec 2023 17:06:10 +0100 Subject: [PATCH 1678/3723] tests: net: socket: tls: Make sure sockets are closed on test failure Add after() function for the test suite, which does cleanup on still open sockets. Otherwise, an individual test case failure affects all other test cases, blurring the test suite results. Signed-off-by: Robert Lubos --- tests/net/socket/tls/src/main.c | 306 ++++++++++++++------------------ 1 file changed, 138 insertions(+), 168 deletions(-) diff --git a/tests/net/socket/tls/src/main.c b/tests/net/socket/tls/src/main.c index 576c24b0206..1e81e2eb6f3 100644 --- a/tests/net/socket/tls/src/main.c +++ b/tests/net/socket/tls/src/main.c @@ -35,6 +35,8 @@ LOG_MODULE_REGISTER(net_test, CONFIG_NET_SOCKETS_LOG_LEVEL); K_THREAD_STACK_DEFINE(tls_test_work_queue_stack, TLS_TEST_WORK_QUEUE_STACK_SIZE); static struct k_work_q tls_test_work_queue; +int c_sock = -1, s_sock = -1, new_sock = -1; + static void test_work_reschedule(struct k_work_delayable *dwork, k_timeout_t delay) { @@ -161,6 +163,24 @@ static void test_close(int sock) "close failed"); } +static void test_sockets_close(void) +{ + if (c_sock >= 0) { + test_close(c_sock); + c_sock = -1; + } + + if (s_sock >= 0) { + test_close(s_sock); + s_sock = -1; + } + + if (new_sock >= 0) { + test_close(new_sock); + new_sock = -1; + } +} + static void test_eof(int sock) { char rx_buf[1]; @@ -282,8 +302,7 @@ static void dtls_client_connect_send_work_handler(struct k_work *work) test_send(data->sock, &tx_buf, sizeof(tx_buf), 0); } -static void test_prepare_tls_connection(sa_family_t family, int *c_sock, - int *s_sock, int *new_sock) +static void test_prepare_tls_connection(sa_family_t family) { struct sockaddr c_saddr; struct sockaddr s_saddr; @@ -295,42 +314,41 @@ static void test_prepare_tls_connection(sa_family_t family, int *c_sock, struct connect_data test_data; if (family == AF_INET6) { - prepare_sock_tls_v6(MY_IPV6_ADDR, ANY_PORT, c_sock, + prepare_sock_tls_v6(MY_IPV6_ADDR, ANY_PORT, &c_sock, (struct sockaddr_in6 *)&c_saddr, IPPROTO_TLS_1_2); - prepare_sock_tls_v6(MY_IPV6_ADDR, ANY_PORT, s_sock, + prepare_sock_tls_v6(MY_IPV6_ADDR, ANY_PORT, &s_sock, (struct sockaddr_in6 *)&s_saddr, IPPROTO_TLS_1_2); } else { - prepare_sock_tls_v4(MY_IPV4_ADDR, ANY_PORT, c_sock, + prepare_sock_tls_v4(MY_IPV4_ADDR, ANY_PORT, &c_sock, (struct sockaddr_in *)&c_saddr, IPPROTO_TLS_1_2); - prepare_sock_tls_v4(MY_IPV4_ADDR, ANY_PORT, s_sock, + prepare_sock_tls_v4(MY_IPV4_ADDR, ANY_PORT, &s_sock, (struct sockaddr_in *)&s_saddr, IPPROTO_TLS_1_2); } - test_config_psk(*s_sock, *c_sock); + test_config_psk(s_sock, c_sock); - test_bind(*s_sock, &s_saddr, exp_addrlen); - test_listen(*s_sock); + test_bind(s_sock, &s_saddr, exp_addrlen); + test_listen(s_sock); /* Helper work for the connect operation - need to handle client/server * in parallel due to handshake. */ - test_data.sock = *c_sock; + test_data.sock = c_sock; test_data.addr = &s_saddr; k_work_init_delayable(&test_data.work, client_connect_work_handler); test_work_reschedule(&test_data.work, K_NO_WAIT); - test_accept(*s_sock, new_sock, &addr, &addrlen); + test_accept(s_sock, &new_sock, &addr, &addrlen); zassert_equal(addrlen, exp_addrlen, "Wrong addrlen"); test_work_wait(&test_data.work); } -static void test_prepare_dtls_connection(sa_family_t family, int *c_sock, - int *s_sock) +static void test_prepare_dtls_connection(sa_family_t family) { struct sockaddr c_saddr; struct sockaddr s_saddr; @@ -345,30 +363,30 @@ static void test_prepare_dtls_connection(sa_family_t family, int *c_sock, if (family == AF_INET6) { - prepare_sock_dtls_v6(MY_IPV6_ADDR, ANY_PORT, c_sock, + prepare_sock_dtls_v6(MY_IPV6_ADDR, ANY_PORT, &c_sock, (struct sockaddr_in6 *)&c_saddr, IPPROTO_DTLS_1_2); - prepare_sock_dtls_v6(MY_IPV6_ADDR, ANY_PORT, s_sock, + prepare_sock_dtls_v6(MY_IPV6_ADDR, ANY_PORT, &s_sock, (struct sockaddr_in6 *)&s_saddr, IPPROTO_DTLS_1_2); } else { - prepare_sock_dtls_v4(MY_IPV4_ADDR, ANY_PORT, c_sock, + prepare_sock_dtls_v4(MY_IPV4_ADDR, ANY_PORT, &c_sock, (struct sockaddr_in *)&c_saddr, IPPROTO_DTLS_1_2); - prepare_sock_dtls_v4(MY_IPV4_ADDR, ANY_PORT, s_sock, + prepare_sock_dtls_v4(MY_IPV4_ADDR, ANY_PORT, &s_sock, (struct sockaddr_in *)&s_saddr, IPPROTO_DTLS_1_2); } - test_config_psk(*s_sock, *c_sock); + test_config_psk(s_sock, c_sock); - zassert_equal(setsockopt(*s_sock, SOL_TLS, TLS_DTLS_ROLE, + zassert_equal(setsockopt(s_sock, SOL_TLS, TLS_DTLS_ROLE, &role, sizeof(role)), 0, "setsockopt() failed"); - test_bind(*s_sock, &s_saddr, exp_addrlen); + test_bind(s_sock, &s_saddr, exp_addrlen); - test_data.sock = *c_sock; + test_data.sock = c_sock; test_data.addr = &s_saddr; k_work_init_delayable(&test_data.work, dtls_client_connect_send_work_handler); test_work_reschedule(&test_data.work, K_NO_WAIT); @@ -377,13 +395,13 @@ static void test_prepare_dtls_connection(sa_family_t family, int *c_sock, * is complete, therefore send a dummy byte once handshake is done to * unblock poll(). */ - fds[0].fd = *s_sock; + fds[0].fd = s_sock; fds[0].events = POLLIN; ret = poll(fds, 1, 1000); zassert_equal(ret, 1, "poll() did not report data ready"); /* Flush the dummy byte. */ - ret = recv(*s_sock, &rx_buf, sizeof(rx_buf), 0); + ret = recv(s_sock, &rx_buf, sizeof(rx_buf), 0); zassert_equal(ret, sizeof(rx_buf), "recv() failed"); test_work_wait(&test_data.work); @@ -394,9 +412,6 @@ ZTEST(net_socket_tls, test_v4_msg_waitall) struct test_msg_waitall_data test_data = { .data = TEST_STR_SMALL, }; - int c_sock; - int s_sock; - int new_sock; int ret; uint8_t rx_buf[sizeof(TEST_STR_SMALL) - 1] = { 0 }; struct timeval timeo_optval = { @@ -404,7 +419,7 @@ ZTEST(net_socket_tls, test_v4_msg_waitall) .tv_usec = 500000, }; - test_prepare_tls_connection(AF_INET, &c_sock, &s_sock, &new_sock); + test_prepare_tls_connection(AF_INET); /* Regular MSG_WAITALL - make sure recv returns only after * requested amount is received. @@ -443,9 +458,7 @@ ZTEST(net_socket_tls, test_v4_msg_waitall) "Invalid data received"); test_work_wait(&test_data.tx_work); - test_close(new_sock); - test_close(s_sock); - test_close(c_sock); + test_sockets_close(); k_sleep(TCP_TEARDOWN_TIMEOUT); } @@ -455,9 +468,6 @@ ZTEST(net_socket_tls, test_v6_msg_waitall) struct test_msg_waitall_data test_data = { .data = TEST_STR_SMALL, }; - int c_sock; - int s_sock; - int new_sock; int ret; uint8_t rx_buf[sizeof(TEST_STR_SMALL) - 1] = { 0 }; struct timeval timeo_optval = { @@ -465,7 +475,7 @@ ZTEST(net_socket_tls, test_v6_msg_waitall) .tv_usec = 500000, }; - test_prepare_tls_connection(AF_INET6, &c_sock, &s_sock, &new_sock); + test_prepare_tls_connection(AF_INET6); /* Regular MSG_WAITALL - make sure recv returns only after * requested amount is received. @@ -504,9 +514,7 @@ ZTEST(net_socket_tls, test_v6_msg_waitall) "Invalid data received"); test_work_wait(&test_data.tx_work); - test_close(new_sock); - test_close(s_sock); - test_close(c_sock); + test_sockets_close(); k_sleep(TCP_TEARDOWN_TIMEOUT); } @@ -535,33 +543,29 @@ void test_msg_trunc(sa_family_t family) .data = TEST_STR_SMALL, .datalen = sizeof(TEST_STR_SMALL) - 1 }; - int sock_c, sock_s; - test_prepare_dtls_connection(family, &sock_c, &sock_s); + test_prepare_dtls_connection(family); /* MSG_TRUNC */ - test_data.sock = sock_c; + test_data.sock = c_sock; k_work_init_delayable(&test_data.tx_work, send_work_handler); test_work_reschedule(&test_data.tx_work, K_MSEC(10)); memset(rx_buf, 0, sizeof(rx_buf)); - rv = recv(sock_s, rx_buf, 2, ZSOCK_MSG_TRUNC); + rv = recv(s_sock, rx_buf, 2, ZSOCK_MSG_TRUNC); zassert_equal(rv, sizeof(TEST_STR_SMALL) - 1, "MSG_TRUNC flag failed"); zassert_mem_equal(rx_buf, TEST_STR_SMALL, 2, "invalid rx data"); zassert_equal(rx_buf[2], 0, "received more than requested"); /* The remaining data should've been discarded */ - rv = recv(sock_s, rx_buf, sizeof(rx_buf), ZSOCK_MSG_DONTWAIT); + rv = recv(s_sock, rx_buf, sizeof(rx_buf), ZSOCK_MSG_DONTWAIT); zassert_equal(rv, -1, "consecutive recv should've failed"); zassert_equal(errno, EAGAIN, "incorrect errno value"); /* MSG_PEEK not supported by DTLS socket */ - rv = close(sock_c); - zassert_equal(rv, 0, "close failed"); - rv = close(sock_s); - zassert_equal(rv, 0, "close failed"); + test_sockets_close(); test_work_wait(&test_data.tx_work); @@ -610,11 +614,10 @@ static void test_dtls_sendmsg(sa_family_t family) struct test_sendmsg_data test_data = { .msg = &msg, }; - int sock_c, sock_s; - test_prepare_dtls_connection(family, &sock_c, &sock_s); + test_prepare_dtls_connection(family); - test_data.sock = sock_c; + test_data.sock = c_sock; k_work_init_delayable(&test_data.tx_work, test_sendmsg_tx_work_handler); /* sendmsg() with single fragment */ @@ -625,7 +628,7 @@ static void test_dtls_sendmsg(sa_family_t family) test_work_reschedule(&test_data.tx_work, K_MSEC(10)); memset(rx_buf, 0, sizeof(rx_buf)); - rv = recv(sock_s, rx_buf, sizeof(rx_buf), 0); + rv = recv(s_sock, rx_buf, sizeof(rx_buf), 0); zassert_equal(rv, sizeof(TEST_STR_SMALL) - 1, "recv failed"); zassert_mem_equal(rx_buf, TEST_STR_SMALL, sizeof(TEST_STR_SMALL) - 1, "invalid rx data"); @@ -639,7 +642,7 @@ static void test_dtls_sendmsg(sa_family_t family) test_work_reschedule(&test_data.tx_work, K_MSEC(10)); memset(rx_buf, 0, sizeof(rx_buf)); - rv = recv(sock_s, rx_buf, sizeof(rx_buf), 0); + rv = recv(s_sock, rx_buf, sizeof(rx_buf), 0); zassert_equal(rv, sizeof(TEST_STR_SMALL) - 1, "recv failed"); zassert_mem_equal(rx_buf, TEST_STR_SMALL, sizeof(TEST_STR_SMALL) - 1, "invalid rx data"); @@ -650,14 +653,11 @@ static void test_dtls_sendmsg(sa_family_t family) iov[0].iov_base = TEST_STR_SMALL; iov[0].iov_len = sizeof(TEST_STR_SMALL) - 1; - rv = sendmsg(sock_c, &msg, 0); + rv = sendmsg(c_sock, &msg, 0); zassert_equal(rv, -1, "sendmsg succeeded"); zassert_equal(errno, EMSGSIZE, "incorrect errno value"); - rv = close(sock_c); - zassert_equal(rv, 0, "close failed"); - rv = close(sock_s); - zassert_equal(rv, 0, "close failed"); + test_sockets_close(); /* Small delay for the final alert exchange */ k_msleep(10); @@ -675,7 +675,7 @@ ZTEST(net_socket_tls, test_v6_dtls_sendmsg) struct close_data { struct k_work_delayable work; - int fd; + int *fd; }; static void close_work(struct k_work *work) @@ -683,13 +683,12 @@ static void close_work(struct k_work *work) struct k_work_delayable *dwork = k_work_delayable_from_work(work); struct close_data *data = CONTAINER_OF(dwork, struct close_data, work); - close(data->fd); + close(*data->fd); + *data->fd = -1; } ZTEST(net_socket_tls, test_close_while_accept) { - int s_sock; - int new_sock; struct sockaddr_in6 s_saddr; struct sockaddr addr; socklen_t addrlen = sizeof(addr); @@ -704,7 +703,7 @@ ZTEST(net_socket_tls, test_close_while_accept) /* Schedule close() from workqueue */ k_work_init_delayable(&close_work_data.work, close_work); - close_work_data.fd = s_sock; + close_work_data.fd = &s_sock; test_work_reschedule(&close_work_data.work, K_MSEC(10)); /* Start blocking accept(), which should be unblocked by close() from @@ -719,25 +718,25 @@ ZTEST(net_socket_tls, test_close_while_accept) ZTEST(net_socket_tls, test_close_while_recv) { - int c_sock, s_sock, new_sock, ret; + int ret; struct close_data close_work_data; uint8_t rx_buf; - test_prepare_tls_connection(AF_INET6, &c_sock, &s_sock, &new_sock); + test_prepare_tls_connection(AF_INET6); /* Schedule close() from workqueue */ k_work_init_delayable(&close_work_data.work, close_work); - close_work_data.fd = new_sock; + close_work_data.fd = &new_sock; test_work_reschedule(&close_work_data.work, K_MSEC(10)); ret = recv(new_sock, &rx_buf, sizeof(rx_buf), 0); zassert_equal(ret, -1, "recv did not return error"); zassert_equal(errno, EINTR, "Unexpected errno value: %d", errno); - test_close(s_sock); - test_close(c_sock); - test_work_wait(&close_work_data.work); + + test_sockets_close(); + k_sleep(TCP_TEARDOWN_TIMEOUT); } @@ -745,7 +744,6 @@ ZTEST(net_socket_tls, test_connect_timeout) { struct sockaddr_in6 c_saddr; struct sockaddr_in6 s_saddr; - int c_sock; int ret; prepare_sock_tls_v6(MY_IPV6_ADDR, ANY_PORT, &c_sock, &c_saddr, @@ -765,7 +763,7 @@ ZTEST(net_socket_tls, test_connect_timeout) zassert_equal(errno, ETIMEDOUT, "connect should be timed out, got %d", errno); - test_close(c_sock); + test_sockets_close(); loopback_set_packet_drop_ratio(0.0f); k_sleep(TCP_TEARDOWN_TIMEOUT); @@ -775,7 +773,6 @@ ZTEST(net_socket_tls, test_connect_closed_port) { struct sockaddr_in6 c_saddr; struct sockaddr_in6 s_saddr; - int c_sock; int ret; prepare_sock_tls_v6(MY_IPV6_ADDR, ANY_PORT, &c_sock, &c_saddr, @@ -793,7 +790,7 @@ ZTEST(net_socket_tls, test_connect_closed_port) zassert_equal(errno, ETIMEDOUT, "connect should fail, got %d", errno); - test_close(c_sock); + test_sockets_close(); k_sleep(TCP_TEARDOWN_TIMEOUT); } @@ -808,7 +805,6 @@ static void fake_tcp_server_work(struct k_work *work) struct k_work_delayable *dwork = k_work_delayable_from_work(work); struct fake_tcp_server_data *data = CONTAINER_OF(dwork, struct fake_tcp_server_data, work); - int new_sock; test_accept(data->sock, &new_sock, NULL, 0); @@ -830,6 +826,7 @@ static void fake_tcp_server_work(struct k_work *work) out: test_close(new_sock); + new_sock = -1; } static void test_prepare_fake_tcp_server(struct fake_tcp_server_data *s_data, @@ -862,7 +859,6 @@ ZTEST(net_socket_tls, test_connect_invalid_handshake_data) struct fake_tcp_server_data server_data; struct sockaddr_in6 c_saddr; struct sockaddr_in6 s_saddr; - int c_sock, s_sock; prepare_sock_tls_v6(MY_IPV6_ADDR, ANY_PORT, &c_sock, &c_saddr, IPPROTO_TLS_1_2); @@ -877,9 +873,11 @@ ZTEST(net_socket_tls, test_connect_invalid_handshake_data) "connect should fail, got %d", errno); test_close(c_sock); - test_close(s_sock); + c_sock = -1; test_work_wait(&server_data.work); + test_sockets_close(); + k_sleep(TCP_TEARDOWN_TIMEOUT); } @@ -888,7 +886,6 @@ ZTEST(net_socket_tls, test_connect_no_handshake_data) struct fake_tcp_server_data server_data; struct sockaddr_in6 c_saddr; struct sockaddr s_saddr; - int c_sock, s_sock; prepare_sock_tls_v6(MY_IPV6_ADDR, ANY_PORT, &c_sock, &c_saddr, IPPROTO_TLS_1_2); @@ -902,16 +899,14 @@ ZTEST(net_socket_tls, test_connect_no_handshake_data) zassert_equal(errno, ECONNABORTED, "connect should fail, got %d", errno); - test_close(c_sock); - test_close(s_sock); - test_work_wait(&server_data.work); + test_sockets_close(); + k_sleep(TCP_TEARDOWN_TIMEOUT); } ZTEST(net_socket_tls, test_accept_non_block) { - int s_sock, new_sock; uint32_t timestamp; struct sockaddr_in6 s_saddr; @@ -929,12 +924,11 @@ ZTEST(net_socket_tls, test_accept_non_block) zassert_equal(new_sock, -1, "accept did not return error"); zassert_equal(errno, EAGAIN, "Unexpected errno value: %d", errno); - test_close(s_sock); + test_sockets_close(); } ZTEST(net_socket_tls, test_accept_invalid_handshake_data) { - int s_sock, c_sock, new_sock; struct sockaddr_in6 s_saddr; struct sockaddr_in6 c_saddr; @@ -954,16 +948,15 @@ ZTEST(net_socket_tls, test_accept_invalid_handshake_data) zassert_equal(new_sock, -1, "accept did not return error"); zassert_equal(errno, ECONNABORTED, "Unexpected errno value: %d", errno); - test_close(s_sock); - test_close(c_sock); + test_sockets_close(); } ZTEST(net_socket_tls, test_recv_non_block) { - int c_sock, s_sock, new_sock, ret; + int ret; uint8_t rx_buf[sizeof(TEST_STR_SMALL) - 1] = { 0 }; - test_prepare_tls_connection(AF_INET6, &c_sock, &s_sock, &new_sock); + test_prepare_tls_connection(AF_INET6); /* Verify ZSOCK_MSG_DONTWAIT flag first */ ret = recv(new_sock, rx_buf, sizeof(rx_buf), ZSOCK_MSG_DONTWAIT); @@ -992,23 +985,21 @@ ZTEST(net_socket_tls, test_recv_non_block) zassert_equal(ret, -1, "recv() should've failed"); zassert_equal(errno, EAGAIN, "Unexpected errno value: %d", errno); - test_close(c_sock); - test_close(new_sock); - test_close(s_sock); + test_sockets_close(); k_sleep(TCP_TEARDOWN_TIMEOUT); } ZTEST(net_socket_tls, test_recv_block) { - int c_sock, s_sock, new_sock, ret; + int ret; uint8_t rx_buf[sizeof(TEST_STR_SMALL) - 1] = { 0 }; struct send_data test_data = { .data = TEST_STR_SMALL, .datalen = sizeof(TEST_STR_SMALL) - 1 }; - test_prepare_tls_connection(AF_INET6, &c_sock, &s_sock, &new_sock); + test_prepare_tls_connection(AF_INET6); test_data.sock = c_sock; k_work_init_delayable(&test_data.tx_work, send_work_handler); @@ -1019,25 +1010,22 @@ ZTEST(net_socket_tls, test_recv_block) zassert_equal(ret, sizeof(TEST_STR_SMALL) - 1, "recv() failed"); zassert_mem_equal(rx_buf, TEST_STR_SMALL, ret, "Invalid data received"); - test_close(c_sock); - test_close(new_sock); - test_close(s_sock); + test_sockets_close(); k_sleep(TCP_TEARDOWN_TIMEOUT); } ZTEST(net_socket_tls, test_recv_eof_on_close) { - int c_sock, s_sock, new_sock; + test_prepare_tls_connection(AF_INET6); - test_prepare_tls_connection(AF_INET6, &c_sock, &s_sock, &new_sock); test_close(c_sock); + c_sock = -1; /* Verify recv() reports EOF */ test_eof(new_sock); - test_close(new_sock); - test_close(s_sock); + test_sockets_close(); k_sleep(TCP_TEARDOWN_TIMEOUT); } @@ -1046,11 +1034,11 @@ ZTEST(net_socket_tls, test_recv_eof_on_close) ZTEST(net_socket_tls, test_send_non_block) { - int c_sock, s_sock, new_sock, ret; + int ret; uint8_t rx_buf[sizeof(TEST_STR_SMALL) - 1] = { 0 }; int buf_optval = TLS_RECORD_OVERHEAD + sizeof(TEST_STR_SMALL) - 1; - test_prepare_tls_connection(AF_INET6, &c_sock, &s_sock, &new_sock); + test_prepare_tls_connection(AF_INET6); /* Simulate window full scenario with SO_RCVBUF option. */ ret = setsockopt(new_sock, SOL_SOCKET, SO_RCVBUF, &buf_optval, @@ -1099,9 +1087,7 @@ ZTEST(net_socket_tls, test_send_non_block) zassert_equal(ret, -1, "recv() should've failed"); zassert_equal(errno, EAGAIN, "Unexpected errno value: %d", errno); - test_close(c_sock); - test_close(new_sock); - test_close(s_sock); + test_sockets_close(); k_sleep(TCP_TEARDOWN_TIMEOUT); } @@ -1137,7 +1123,7 @@ static void recv_work_handler(struct k_work *work) ZTEST(net_socket_tls, test_send_block) { - int c_sock, s_sock, new_sock, ret; + int ret; int buf_optval = TLS_RECORD_OVERHEAD + sizeof(TEST_STR_SMALL) - 1; uint8_t rx_buf[sizeof(TEST_STR_SMALL) - 1] = { 0 }; struct recv_data test_data = { @@ -1145,7 +1131,7 @@ ZTEST(net_socket_tls, test_send_block) .datalen = sizeof(TEST_STR_SMALL) - 1 }; - test_prepare_tls_connection(AF_INET6, &c_sock, &s_sock, &new_sock); + test_prepare_tls_connection(AF_INET6); /* Simulate window full scenario with SO_RCVBUF option. */ ret = setsockopt(new_sock, SOL_SOCKET, SO_RCVBUF, &buf_optval, @@ -1179,9 +1165,7 @@ ZTEST(net_socket_tls, test_send_block) zassert_equal(ret, -1, "recv() should've failed"); zassert_equal(errno, EAGAIN, "Unexpected errno value: %d", errno); - test_close(c_sock); - test_close(new_sock); - test_close(s_sock); + test_sockets_close(); k_sleep(TCP_TEARDOWN_TIMEOUT); } @@ -1198,9 +1182,9 @@ ZTEST(net_socket_tls, test_so_rcvtimeo) .data = TEST_STR_SMALL, .datalen = sizeof(TEST_STR_SMALL) - 1 }; - int c_sock, s_sock, new_sock, ret; + int ret; - test_prepare_tls_connection(AF_INET6, &c_sock, &s_sock, &new_sock); + test_prepare_tls_connection(AF_INET6); ret = setsockopt(c_sock, SOL_SOCKET, SO_RCVTIMEO, &optval, sizeof(optval)); @@ -1224,9 +1208,7 @@ ZTEST(net_socket_tls, test_so_rcvtimeo) zassert_equal(ret, sizeof(TEST_STR_SMALL) - 1, "recv() failed"); zassert_mem_equal(rx_buf, TEST_STR_SMALL, ret, "Invalid data received"); - test_close(c_sock); - test_close(new_sock); - test_close(s_sock); + test_sockets_close(); k_sleep(TCP_TEARDOWN_TIMEOUT); } @@ -1243,9 +1225,9 @@ ZTEST(net_socket_tls, test_so_sndtimeo) .data = TEST_STR_SMALL, .datalen = sizeof(TEST_STR_SMALL) - 1 }; - int c_sock, s_sock, new_sock, ret; + int ret; - test_prepare_tls_connection(AF_INET6, &c_sock, &s_sock, &new_sock); + test_prepare_tls_connection(AF_INET6); ret = setsockopt(c_sock, SOL_SOCKET, SO_SNDTIMEO, &timeo_optval, sizeof(timeo_optval)); @@ -1280,18 +1262,14 @@ ZTEST(net_socket_tls, test_so_sndtimeo) ret = send(c_sock, TEST_STR_SMALL, strlen(TEST_STR_SMALL), 0); zassert_equal(ret, strlen(TEST_STR_SMALL), "send() failed"); - test_close(c_sock); - test_close(new_sock); - test_close(s_sock); + test_sockets_close(); k_sleep(TCP_TEARDOWN_TIMEOUT); } ZTEST(net_socket_tls, test_shutdown_rd_synchronous) { - int c_sock, s_sock, new_sock; - - test_prepare_tls_connection(AF_INET6, &c_sock, &s_sock, &new_sock); + test_prepare_tls_connection(AF_INET6); /* Shutdown reception */ test_shutdown(c_sock, ZSOCK_SHUT_RD); @@ -1299,9 +1277,7 @@ ZTEST(net_socket_tls, test_shutdown_rd_synchronous) /* EOF should be notified by recv() */ test_eof(c_sock); - test_close(new_sock); - test_close(s_sock); - test_close(c_sock); + test_sockets_close(); k_sleep(TCP_TEARDOWN_TIMEOUT); } @@ -1323,12 +1299,11 @@ static void shutdown_work(struct k_work *work) ZTEST(net_socket_tls, test_shutdown_rd_while_recv) { - int c_sock, s_sock, new_sock; struct shutdown_data test_data = { .how = ZSOCK_SHUT_RD, }; - test_prepare_tls_connection(AF_INET6, &c_sock, &s_sock, &new_sock); + test_prepare_tls_connection(AF_INET6); /* Schedule reception shutdown from workqueue */ k_work_init_delayable(&test_data.work, shutdown_work); @@ -1338,9 +1313,7 @@ ZTEST(net_socket_tls, test_shutdown_rd_while_recv) /* EOF should be notified by recv() */ test_eof(c_sock); - test_close(new_sock); - test_close(s_sock); - test_close(c_sock); + test_sockets_close(); k_sleep(TCP_TEARDOWN_TIMEOUT); } @@ -1356,9 +1329,9 @@ ZTEST(net_socket_tls, test_send_while_recv) .data = TEST_STR_SMALL, .datalen = sizeof(TEST_STR_SMALL) - 1 }; - int c_sock, s_sock, new_sock, ret; + int ret; - test_prepare_tls_connection(AF_INET6, &c_sock, &s_sock, &new_sock); + test_prepare_tls_connection(AF_INET6); test_data_c.sock = c_sock; k_work_init_delayable(&test_data_c.tx_work, send_work_handler); @@ -1380,9 +1353,7 @@ ZTEST(net_socket_tls, test_send_while_recv) zassert_equal(ret, sizeof(TEST_STR_SMALL) - 1, "recv() failed"); zassert_mem_equal(rx_buf, TEST_STR_SMALL, ret, "Invalid data received"); - test_close(c_sock); - test_close(new_sock); - test_close(s_sock); + test_sockets_close(); k_sleep(TCP_TEARDOWN_TIMEOUT); } @@ -1390,10 +1361,10 @@ ZTEST(net_socket_tls, test_send_while_recv) ZTEST(net_socket_tls, test_poll_tls_pollin) { uint8_t rx_buf[sizeof(TEST_STR_SMALL) - 1]; - int c_sock, s_sock, new_sock, ret; + int ret; struct pollfd fds[1]; - test_prepare_tls_connection(AF_INET6, &c_sock, &s_sock, &new_sock); + test_prepare_tls_connection(AF_INET6); fds[0].fd = new_sock; fds[0].events = POLLIN; @@ -1413,9 +1384,7 @@ ZTEST(net_socket_tls, test_poll_tls_pollin) zassert_equal(ret, sizeof(TEST_STR_SMALL) - 1, "recv() failed"); zassert_mem_equal(rx_buf, TEST_STR_SMALL, ret, "Invalid data received"); - test_close(c_sock); - test_close(new_sock); - test_close(s_sock); + test_sockets_close(); k_sleep(TCP_TEARDOWN_TIMEOUT); } @@ -1427,10 +1396,10 @@ ZTEST(net_socket_tls, test_poll_dtls_pollin) .data = TEST_STR_SMALL, .datalen = sizeof(TEST_STR_SMALL) - 1 }; - int c_sock, s_sock, ret; + int ret; struct pollfd fds[1]; - test_prepare_dtls_connection(AF_INET6, &c_sock, &s_sock); + test_prepare_dtls_connection(AF_INET6); fds[0].fd = s_sock; fds[0].events = POLLIN; @@ -1451,8 +1420,7 @@ ZTEST(net_socket_tls, test_poll_dtls_pollin) zassert_equal(ret, sizeof(TEST_STR_SMALL) - 1, "recv() failed"); zassert_mem_equal(rx_buf, TEST_STR_SMALL, ret, "Invalid data received"); - test_close(c_sock); - test_close(s_sock); + test_sockets_close(); /* Small delay for the final alert exchange */ k_msleep(10); @@ -1462,10 +1430,10 @@ ZTEST(net_socket_tls, test_poll_tls_pollout) { int buf_optval = TLS_RECORD_OVERHEAD + sizeof(TEST_STR_SMALL) - 1; uint8_t rx_buf[sizeof(TEST_STR_SMALL) - 1]; - int c_sock, s_sock, new_sock, ret; + int ret; struct pollfd fds[1]; - test_prepare_tls_connection(AF_INET6, &c_sock, &s_sock, &new_sock); + test_prepare_tls_connection(AF_INET6); fds[0].fd = c_sock; fds[0].events = POLLOUT; @@ -1501,9 +1469,7 @@ ZTEST(net_socket_tls, test_poll_tls_pollout) zassert_equal(ret, 1, "poll() should've report event"); zassert_equal(fds[0].revents, POLLOUT, "No POLLOUT event"); - test_close(c_sock); - test_close(new_sock); - test_close(s_sock); + test_sockets_close(); k_sleep(TCP_TEARDOWN_TIMEOUT); } @@ -1511,9 +1477,9 @@ ZTEST(net_socket_tls, test_poll_tls_pollout) ZTEST(net_socket_tls, test_poll_dtls_pollout) { struct pollfd fds[1]; - int c_sock, s_sock, ret; + int ret; - test_prepare_dtls_connection(AF_INET6, &c_sock, &s_sock); + test_prepare_dtls_connection(AF_INET6); fds[0].fd = c_sock; fds[0].events = POLLOUT; @@ -1523,8 +1489,7 @@ ZTEST(net_socket_tls, test_poll_dtls_pollout) zassert_equal(ret, 1, "poll() should've report event"); zassert_equal(fds[0].revents, POLLOUT, "No POLLOUT event"); - test_close(c_sock); - test_close(s_sock); + test_sockets_close(); /* Small delay for the final alert exchange */ k_msleep(10); @@ -1534,14 +1499,15 @@ ZTEST(net_socket_tls, test_poll_tls_pollhup) { struct pollfd fds[1]; uint8_t rx_buf; - int c_sock, s_sock, new_sock, ret; + int ret; - test_prepare_tls_connection(AF_INET6, &c_sock, &s_sock, &new_sock); + test_prepare_tls_connection(AF_INET6); fds[0].fd = new_sock; fds[0].events = POLLIN; test_close(c_sock); + c_sock = -1; ret = poll(fds, 1, 100); zassert_equal(ret, 1, "poll() should've report event"); @@ -1552,8 +1518,7 @@ ZTEST(net_socket_tls, test_poll_tls_pollhup) ret = recv(new_sock, &rx_buf, sizeof(rx_buf), ZSOCK_MSG_DONTWAIT); zassert_equal(ret, 0, "recv() did not report connection close"); - test_close(new_sock); - test_close(s_sock); + test_sockets_close(); k_sleep(TCP_TEARDOWN_TIMEOUT); } @@ -1562,14 +1527,15 @@ ZTEST(net_socket_tls, test_poll_dtls_pollhup) { struct pollfd fds[1]; uint8_t rx_buf; - int c_sock, s_sock, ret; + int ret; - test_prepare_dtls_connection(AF_INET6, &c_sock, &s_sock); + test_prepare_dtls_connection(AF_INET6); fds[0].fd = s_sock; fds[0].events = POLLIN; test_close(c_sock); + c_sock = -1; ret = poll(fds, 1, 100); zassert_equal(ret, 1, "poll() should've report event"); @@ -1580,7 +1546,7 @@ ZTEST(net_socket_tls, test_poll_dtls_pollhup) zassert_equal(ret, -1, "recv() should report EAGAIN"); zassert_equal(errno, EAGAIN, "Unexpected errno value: %d", errno); - test_close(s_sock); + test_sockets_close(); /* Small delay for the final alert exchange */ k_msleep(10); @@ -1591,13 +1557,13 @@ mbedtls_ssl_context *ztls_get_mbedtls_ssl_context(int fd); ZTEST(net_socket_tls, test_poll_tls_pollerr) { uint8_t rx_buf; - int c_sock, s_sock, new_sock, ret; + int ret; struct pollfd fds[1]; int optval; socklen_t optlen = sizeof(optval); mbedtls_ssl_context *ssl_ctx; - test_prepare_tls_connection(AF_INET6, &c_sock, &s_sock, &new_sock); + test_prepare_tls_connection(AF_INET6); fds[0].fd = new_sock; fds[0].events = POLLIN; @@ -1620,9 +1586,7 @@ ZTEST(net_socket_tls, test_poll_tls_pollerr) zassert_equal(ret, -1, "recv() did not report error"); zassert_equal(errno, ECONNABORTED, "Unexpected errno value: %d", errno); - test_close(c_sock); - test_close(new_sock); - test_close(s_sock); + test_sockets_close(); k_sleep(TCP_TEARDOWN_TIMEOUT); } @@ -1630,13 +1594,13 @@ ZTEST(net_socket_tls, test_poll_tls_pollerr) ZTEST(net_socket_tls, test_poll_dtls_pollerr) { uint8_t rx_buf; - int c_sock, s_sock, ret; + int ret; struct pollfd fds[1]; int optval; socklen_t optlen = sizeof(optval); mbedtls_ssl_context *ssl_ctx; - test_prepare_dtls_connection(AF_INET6, &c_sock, &s_sock); + test_prepare_dtls_connection(AF_INET6); fds[0].fd = s_sock; fds[0].events = POLLIN; @@ -1660,8 +1624,7 @@ ZTEST(net_socket_tls, test_poll_dtls_pollerr) zassert_equal(ret, -1, "recv() did not report error"); zassert_equal(errno, EAGAIN, "Unexpected errno value: %d", errno); - test_close(c_sock); - test_close(s_sock); + test_sockets_close(); /* Small delay for the final alert exchange */ k_msleep(10); @@ -1677,4 +1640,11 @@ static void *tls_tests_setup(void) return NULL; } -ZTEST_SUITE(net_socket_tls, NULL, tls_tests_setup, NULL, NULL, NULL); +static void tls_tests_after(void *arg) +{ + ARG_UNUSED(arg); + + test_sockets_close(); +} + +ZTEST_SUITE(net_socket_tls, NULL, tls_tests_setup, NULL, tls_tests_after, NULL); From 8d3d48e0575b59b19b559884ab4bce86ec5667a5 Mon Sep 17 00:00:00 2001 From: Jukka Rissanen Date: Fri, 22 Dec 2023 15:16:33 +0200 Subject: [PATCH 1679/3723] net: ipv6: Check that received src address is not mine Drop received packet if the source address is the same as the device address. Signed-off-by: Jukka Rissanen --- subsys/net/ip/ipv6.c | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/subsys/net/ip/ipv6.c b/subsys/net/ip/ipv6.c index 1be86c4d157..8276d9a7f8f 100644 --- a/subsys/net/ip/ipv6.c +++ b/subsys/net/ip/ipv6.c @@ -520,6 +520,11 @@ enum net_verdict net_ipv6_input(struct net_pkt *pkt, bool is_loopback) NET_DBG("DROP: invalid scope multicast packet"); goto drop; } + + if (net_ipv6_is_my_addr((struct in6_addr *)hdr->src)) { + NET_DBG("DROP: src addr is %s", "mine"); + goto drop; + } } /* Reconstruct TC field. */ From 155e2149f2506cc82432d3c9c7b20db353fa58d1 Mon Sep 17 00:00:00 2001 From: Jukka Rissanen Date: Wed, 27 Dec 2023 11:01:31 +0200 Subject: [PATCH 1680/3723] tests: net: ipv6: Adjust the source address of test pkt We would drop the received packet if the source address is our address so tweak the test and make source address different. Signed-off-by: Jukka Rissanen --- tests/net/ipv6/src/main.c | 24 ++++++++++++------------ 1 file changed, 12 insertions(+), 12 deletions(-) diff --git a/tests/net/ipv6/src/main.c b/tests/net/ipv6/src/main.c index 6d8a1a5deee..ea734afae3e 100644 --- a/tests/net/ipv6/src/main.c +++ b/tests/net/ipv6/src/main.c @@ -1293,7 +1293,7 @@ ZTEST(net_ipv6, test_src_localaddr_recv) struct in6_addr localaddr = { { { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0x1 } } }; struct in6_addr addr = { { { 0x20, 0x01, 0x0d, 0xb8, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0x1 } } }; + 0, 0, 0, 0, 0, 0, 0, 0x10 } } }; enum net_verdict verdict; verdict = recv_msg(&localaddr, &addr); @@ -1306,7 +1306,7 @@ ZTEST(net_ipv6, test_dst_localaddr_recv) struct in6_addr localaddr = { { { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0x1 } } }; struct in6_addr addr = { { { 0x20, 0x01, 0x0d, 0xb8, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0x1 } } }; + 0, 0, 0, 0, 0, 0, 0, 0x10 } } }; enum net_verdict verdict; verdict = recv_msg(&addr, &localaddr); @@ -1319,7 +1319,7 @@ ZTEST(net_ipv6, test_dst_iface_scope_mcast_recv) struct in6_addr mcast_iface = { { { 0xff, 0x01, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 } } }; struct in6_addr addr = { { { 0x20, 0x01, 0x0d, 0xb8, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0x1 } } }; + 0, 0, 0, 0, 0, 0, 0, 0x10 } } }; enum net_verdict verdict; verdict = recv_msg(&addr, &mcast_iface); @@ -1332,7 +1332,7 @@ ZTEST(net_ipv6, test_dst_zero_scope_mcast_recv) struct in6_addr mcast_zero = { { { 0xff, 0x00, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 } } }; struct in6_addr addr = { { { 0x20, 0x01, 0x0d, 0xb8, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0x1 } } }; + 0, 0, 0, 0, 0, 0, 0, 0x10 } } }; enum net_verdict verdict; verdict = recv_msg(&addr, &mcast_zero); @@ -1345,7 +1345,7 @@ ZTEST(net_ipv6, test_dst_site_scope_mcast_recv_drop) struct in6_addr mcast_site = { { { 0xff, 0x05, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 } } }; struct in6_addr addr = { { { 0x20, 0x01, 0x0d, 0xb8, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0x1 } } }; + 0, 0, 0, 0, 0, 0, 0, 0x10 } } }; enum net_verdict verdict; verdict = recv_msg(&addr, &mcast_site); @@ -1432,7 +1432,7 @@ ZTEST(net_ipv6, test_dst_site_scope_mcast_recv_ok) struct in6_addr mcast_all_dhcp = { { { 0xff, 0x05, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0x01, 0, 0, 0, 0x03 } } }; struct in6_addr addr = { { { 0x20, 0x01, 0x0d, 0xb8, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0x1 } } }; + 0, 0, 0, 0, 0, 0, 0, 0x10 } } }; enum net_verdict verdict; struct net_context *ctx; @@ -1461,7 +1461,7 @@ ZTEST(net_ipv6, test_dst_org_scope_mcast_recv) struct in6_addr mcast_org = { { { 0xff, 0x08, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 } } }; struct in6_addr addr = { { { 0x20, 0x01, 0x0d, 0xb8, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0x1 } } }; + 0, 0, 0, 0, 0, 0, 0, 0x10 } } }; enum net_verdict verdict; verdict = recv_msg(&addr, &mcast_org); @@ -1474,7 +1474,7 @@ ZTEST(net_ipv6, test_dst_iface_scope_mcast_send) struct in6_addr mcast_iface = { { { 0xff, 0x01, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 } } }; struct in6_addr addr = { { { 0x20, 0x01, 0x0d, 0xb8, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0x1 } } }; + 0, 0, 0, 0, 0, 0, 0, 0x10 } } }; struct net_if_mcast_addr *maddr; struct net_context *ctx; int ret; @@ -1516,7 +1516,7 @@ ZTEST(net_ipv6, test_dst_unknown_group_mcast_recv) }; struct in6_addr in6_addr_any = IN6ADDR_ANY_INIT; struct in6_addr addr = { { { 0x20, 0x01, 0x0d, 0xb8, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0x1 } } }; + 0, 0, 0, 0, 0, 0x10 } } }; struct net_context *ctx; enum net_verdict verdict; @@ -1546,7 +1546,7 @@ ZTEST(net_ipv6, test_y_dst_unjoined_group_mcast_recv) }; struct in6_addr in6_addr_any = IN6ADDR_ANY_INIT; struct in6_addr addr = { { { 0x20, 0x01, 0x0d, 0xb8, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0x1 } } }; + 0, 0, 0, 0, 0, 0x10 } } }; struct net_if_mcast_addr *maddr; struct net_context *ctx; enum net_verdict verdict; @@ -1592,7 +1592,7 @@ ZTEST(net_ipv6, test_dst_is_other_iface_mcast_recv) 0x08 } } }; struct in6_addr in6_addr_any = IN6ADDR_ANY_INIT; struct in6_addr addr = { { { 0x20, 0x01, 0x0d, 0xb8, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0x1 } } }; + 0, 0, 0, 0, 0, 0x10 } } }; struct net_if *test_iface = net_if_get_first_by_type(&NET_L2_GET_NAME(DUMMY)); struct net_if_mcast_addr *maddr; struct net_context *ctx; @@ -1633,7 +1633,7 @@ ZTEST(net_ipv6, test_no_nd_flag) { bool ret; struct in6_addr addr = { { { 0x20, 0x01, 0x0d, 0xb8, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0x99, 0x1 } } }; + 0, 0, 0, 0, 0, 0, 0x99, 0x10 } } }; struct net_if *iface = TEST_NET_IF; struct net_if_addr *ifaddr; From fa0e04e2edb82bf880b274d9532fcf2729f4d674 Mon Sep 17 00:00:00 2001 From: Jukka Rissanen Date: Wed, 27 Dec 2023 14:37:55 +0200 Subject: [PATCH 1681/3723] tests: net: dhcpv6: Adjust the source address of test pkt We would drop the received packet if the source address is our address so tweak the test and make source address different. Signed-off-by: Jukka Rissanen --- tests/net/dhcpv6/src/main.c | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/tests/net/dhcpv6/src/main.c b/tests/net/dhcpv6/src/main.c index 80046c96ec9..02463d20a2b 100644 --- a/tests/net/dhcpv6/src/main.c +++ b/tests/net/dhcpv6/src/main.c @@ -127,6 +127,7 @@ static struct net_pkt *test_dhcpv6_create_message( test_dhcpv6_options_fn_t set_options_fn) { struct in6_addr *local_addr; + struct in6_addr peer_addr; struct net_pkt *pkt; local_addr = net_if_ipv6_get_ll(iface, NET_ADDR_ANY_STATE); @@ -134,13 +135,20 @@ static struct net_pkt *test_dhcpv6_create_message( return NULL; } + /* Create a peer address from my address but invert the last byte + * so that the address is not the same. This is needed as we drop + * the packet if source address is our own address. + */ + memcpy(&peer_addr, local_addr, sizeof(peer_addr)); + peer_addr.s6_addr[15] = ~peer_addr.s6_addr[15]; + pkt = net_pkt_alloc_with_buffer(iface, TEST_MSG_SIZE, AF_INET6, IPPROTO_UDP, K_FOREVER); if (pkt == NULL) { return NULL; } - if (net_ipv6_create(pkt, local_addr, local_addr) < 0 || + if (net_ipv6_create(pkt, &peer_addr, local_addr) < 0 || net_udp_create(pkt, htons(DHCPV6_SERVER_PORT), htons(DHCPV6_CLIENT_PORT)) < 0) { goto fail; From 9981e69b9106619a2ef28faf2c168b5ea2cab7d0 Mon Sep 17 00:00:00 2001 From: Torsten Rasmussen Date: Wed, 3 Jan 2024 11:21:12 +0100 Subject: [PATCH 1682/3723] cmake: update description of board_runner_args() function Update description of board_runner_args() function so that it is described that app_set_runner_args macro must be defined before the call to `find_package(Zephyr)`. Signed-off-by: Torsten Rasmussen --- cmake/modules/extensions.cmake | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cmake/modules/extensions.cmake b/cmake/modules/extensions.cmake index 6bdd55433eb..5a216fc1a79 100644 --- a/cmake/modules/extensions.cmake +++ b/cmake/modules/extensions.cmake @@ -773,7 +773,7 @@ endmacro() # # Within application CMakeLists.txt files, ensure that all calls to # board_runner_args() are part of a macro named app_set_runner_args(), -# like this, which is defined before including the boilerplate file: +# like this, which is defined before calling 'find_package(Zephyr)': # macro(app_set_runner_args) # board_runner_args(runner "--some-app-setting=value") # endmacro() From 11613e08e71d52db0438e4d25780f40489793ce4 Mon Sep 17 00:00:00 2001 From: Maciej Baczmanski Date: Wed, 3 Jan 2024 11:24:45 +0100 Subject: [PATCH 1683/3723] net: openthread: increase TCAT stack size Running TCAT with PSA crypto API causes stack overflow. Increased stack size. Signed-off-by: Maciej Baczmanski --- modules/openthread/Kconfig.thread | 1 + 1 file changed, 1 insertion(+) diff --git a/modules/openthread/Kconfig.thread b/modules/openthread/Kconfig.thread index 66e039b7300..542992e7fa1 100644 --- a/modules/openthread/Kconfig.thread +++ b/modules/openthread/Kconfig.thread @@ -184,6 +184,7 @@ config OPENTHREAD_DEFAULT_TX_POWER config OPENTHREAD_BLE_TCAT_THREAD_STACK_SIZE int "Openthread default TCAT stack size" + default 5120 if OPENTHREAD_CRYPTO_PSA default 4200 help Openthread default TCAT stack size. From 42335036b7ee0d896a22102ea9d822f624aefa0a Mon Sep 17 00:00:00 2001 From: Christopher Friedt Date: Wed, 27 Dec 2023 17:53:54 -0500 Subject: [PATCH 1684/3723] include: util: add array for-each macros AFAIK, we do not have array for-each loops. Seemed like an obvious gap to fill, so introduce two variants: * ARRAY_FOR_EACH(array, idx_var) * ARRAY_FOR_EACH_PTR(array, ptr_var) Signed-off-by: Christopher Friedt --- include/zephyr/sys/util.h | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) diff --git a/include/zephyr/sys/util.h b/include/zephyr/sys/util.h index a812ee4d37e..45ae2008999 100644 --- a/include/zephyr/sys/util.h +++ b/include/zephyr/sys/util.h @@ -202,6 +202,24 @@ extern "C" { (POINTER_TO_UINT(ptr) - POINTER_TO_UINT(array)) / sizeof((array)[0]); \ }) +/** + * @brief Iterate over members of an array using an index variable + * + * @param array the array in question + * @param idx name of array index variable + */ +#define ARRAY_FOR_EACH(array, idx) for (size_t idx = 0; (idx) < ARRAY_SIZE(array); ++(idx)) + +/** + * @brief Iterate over members of an array using a pointer + * + * @param array the array in question + * @param ptr pointer to an element of @p array + */ +#define ARRAY_FOR_EACH_PTR(array, ptr) \ + for (__typeof__(*(array)) *ptr = (array); (size_t)((ptr) - (array)) < ARRAY_SIZE(array); \ + ++(ptr)) + /** * @brief Validate if two entities have a compatible type * From 1695b5a0b2e372c2875001b472b041d1f1d55df0 Mon Sep 17 00:00:00 2001 From: Christopher Friedt Date: Tue, 2 Jan 2024 10:17:43 -0500 Subject: [PATCH 1685/3723] tests: unit: util: add array for-each tests Add tests for the following two macros * ARRAY_FOR_EACH(array, idx_var) * ARRAY_FOR_EACH_PTR(array, ptr_var) Signed-off-by: Christopher Friedt --- tests/unit/util/main.c | 28 ++++++++++++++++++++++++++++ 1 file changed, 28 insertions(+) diff --git a/tests/unit/util/main.c b/tests/unit/util/main.c index c1dbca35bdc..e10455e263a 100644 --- a/tests/unit/util/main.c +++ b/tests/unit/util/main.c @@ -462,6 +462,34 @@ ZTEST(util, test_ARRAY_INDEX) } } +ZTEST(util, test_ARRAY_FOR_EACH) +{ + size_t j = -1; + size_t array[3]; + + ARRAY_FOR_EACH(array, i) { + j = i + 1; + } + + zassert_equal(j, ARRAY_SIZE(array)); +} + +ZTEST(util, test_ARRAY_FOR_EACH_PTR) +{ + size_t j = 0; + size_t array[3]; + size_t *ptr[3]; + + ARRAY_FOR_EACH_PTR(array, p) { + ptr[j] = p; + ++j; + } + + zassert_equal(ptr[0], &array[0]); + zassert_equal(ptr[1], &array[1]); + zassert_equal(ptr[2], &array[2]); +} + ZTEST(util, test_PART_OF_ARRAY) { size_t i; From e0383a6f9d5083a3ad9214536bcb8563eaa6081e Mon Sep 17 00:00:00 2001 From: Christopher Friedt Date: Wed, 27 Dec 2023 17:55:19 -0500 Subject: [PATCH 1686/3723] posix: clock: check for invalid ns in clock_settime() The clock_settime() function should not accept an input timespec with nanosecond values < 0 or >= NSEC_PER_SEC. Signed-off-by: Christopher Friedt --- lib/posix/clock.c | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/lib/posix/clock.c b/lib/posix/clock.c index d7ca3969aa8..9fef8586b48 100644 --- a/lib/posix/clock.c +++ b/lib/posix/clock.c @@ -92,6 +92,11 @@ int clock_settime(clockid_t clock_id, const struct timespec *tp) return -1; } + if (tp->tv_nsec < 0 || tp->tv_nsec >= NSEC_PER_SEC) { + errno = EINVAL; + return -1; + } + uint64_t elapsed_nsecs = k_ticks_to_ns_floor64(k_uptime_ticks()); int64_t delta = (int64_t)NSEC_PER_SEC * tp->tv_sec + tp->tv_nsec - elapsed_nsecs; From 95a22b12174621aeba8ca3e0e61f7c66f03202bf Mon Sep 17 00:00:00 2001 From: Christopher Friedt Date: Thu, 28 Dec 2023 01:43:52 -0500 Subject: [PATCH 1687/3723] posix: clock: clock_gettime() should not be a syscall We try to implement Zephyr's POSIX API as regular library functions, so remove the __syscall annotation from clock_gettime() and implement the syscall portion of it under the hood. This also adds a bit of a micro-optimization in that we can do a lot of processing outside of the system call. In fact, processing CLOCK_MONOTONIC likely does not require any syscall other than k_uptime_ticks(). Signed-off-by: Christopher Friedt --- include/zephyr/posix/time.h | 8 ------ lib/posix/CMakeLists.txt | 2 +- lib/posix/clock.c | 50 ++++++++++++++++++++++++++----------- lib/posix/posix_clock.h | 19 ++++++++++++++ 4 files changed, 56 insertions(+), 23 deletions(-) create mode 100644 lib/posix/posix_clock.h diff --git a/include/zephyr/posix/time.h b/include/zephyr/posix/time.h index 85cb7f8ae42..ea7e68cb079 100644 --- a/include/zephyr/posix/time.h +++ b/include/zephyr/posix/time.h @@ -82,11 +82,7 @@ static inline int32_t _ts_to_ms(const struct timespec *to) return (to->tv_sec * MSEC_PER_SEC) + (to->tv_nsec / NSEC_PER_MSEC); } -#if defined(CONFIG_ARCH_POSIX) && defined(CONFIG_EXTERNAL_LIBC) int clock_gettime(clockid_t clock_id, struct timespec *ts); -#else -__syscall int clock_gettime(clockid_t clock_id, struct timespec *ts); -#endif /* CONFIG_ARCH_POSIX */ int clock_settime(clockid_t clock_id, const struct timespec *ts); /* Timer APIs */ int timer_create(clockid_t clockId, struct sigevent *evp, timer_t *timerid); @@ -103,10 +99,6 @@ int clock_nanosleep(clockid_t clock_id, int flags, } #endif -#if !(defined(CONFIG_ARCH_POSIX) && defined(CONFIG_EXTERNAL_LIBC)) -#include -#endif /* CONFIG_ARCH_POSIX */ - #else /* ZEPHYR_INCLUDE_POSIX_TIME_H_ */ /* Read the toolchain header when finds itself on the * first attempt. diff --git a/lib/posix/CMakeLists.txt b/lib/posix/CMakeLists.txt index c6b3a88aeab..e73c78d40e4 100644 --- a/lib/posix/CMakeLists.txt +++ b/lib/posix/CMakeLists.txt @@ -3,7 +3,7 @@ set(GEN_DIR ${ZEPHYR_BINARY_DIR}/include/generated) zephyr_syscall_header( - ${ZEPHYR_BASE}/include/zephyr/posix/time.h + posix_clock.h ) zephyr_interface_library_named(posix_subsys) diff --git a/lib/posix/clock.c b/lib/posix/clock.c index 9fef8586b48..0d085a6d0d0 100644 --- a/lib/posix/clock.c +++ b/lib/posix/clock.c @@ -3,6 +3,9 @@ * * SPDX-License-Identifier: Apache-2.0 */ + +#include "posix_clock.h" + #include #include #include @@ -25,10 +28,40 @@ static struct k_spinlock rt_clock_base_lock; * * See IEEE 1003.1 */ -int z_impl_clock_gettime(clockid_t clock_id, struct timespec *ts) +int z_impl___posix_clock_get_base(clockid_t clock_id, struct timespec *base) +{ + switch (clock_id) { + case CLOCK_MONOTONIC: + base->tv_sec = 0; + base->tv_nsec = 0; + break; + + case CLOCK_REALTIME: + K_SPINLOCK(&rt_clock_base_lock) { + *base = rt_clock_base; + } + break; + + default: + errno = EINVAL; + return -1; + } + + return 0; +} + +#ifdef CONFIG_USERSPACE +int z_vrfy___posix_clock_get_base(clockid_t clock_id, struct timespec *ts) +{ + K_OOPS(K_SYSCALL_MEMORY_WRITE(ts, sizeof(*ts))); + return z_impl___posix_clock_get_base(clock_id, ts); +} +#include +#endif + +int clock_gettime(clockid_t clock_id, struct timespec *ts) { struct timespec base; - k_spinlock_key_t key; switch (clock_id) { case CLOCK_MONOTONIC: @@ -37,9 +70,7 @@ int z_impl_clock_gettime(clockid_t clock_id, struct timespec *ts) break; case CLOCK_REALTIME: - key = k_spin_lock(&rt_clock_base_lock); - base = rt_clock_base; - k_spin_unlock(&rt_clock_base_lock, key); + (void)__posix_clock_get_base(clock_id, &base); break; default: @@ -65,15 +96,6 @@ int z_impl_clock_gettime(clockid_t clock_id, struct timespec *ts) return 0; } -#ifdef CONFIG_USERSPACE -int z_vrfy_clock_gettime(clockid_t clock_id, struct timespec *ts) -{ - K_OOPS(K_SYSCALL_MEMORY_WRITE(ts, sizeof(*ts))); - return z_impl_clock_gettime(clock_id, ts); -} -#include -#endif - /** * @brief Set the time of the specified clock. * diff --git a/lib/posix/posix_clock.h b/lib/posix/posix_clock.h new file mode 100644 index 00000000000..a665f4ce06d --- /dev/null +++ b/lib/posix/posix_clock.h @@ -0,0 +1,19 @@ +/* + * Copyright (c) 2023, Meta + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#ifndef ZEPHYR_LIB_POSIX_POSIX_CLOCK_H_ +#define ZEPHYR_LIB_POSIX_POSIX_CLOCK_H_ + +#include + +#include +#include + +__syscall int __posix_clock_get_base(clockid_t clock_id, struct timespec *ts); + +#include + +#endif From 67a74e43504eea33eb539d172a2f6fd03d41c917 Mon Sep 17 00:00:00 2001 From: Christopher Friedt Date: Wed, 27 Dec 2023 17:56:27 -0500 Subject: [PATCH 1688/3723] tests: posix: test_realtime: improve test reliability Previously posix_apis.test_realtime was failing (very) frequently in CI, and in particular, when running on Qemu, POSIX, or SMP targets. We are using CLOCK_REALTIME for this test, which incurs an additional syscall overhead above CLOCK_MONOTONIC. The act of sleeping itself also incurs a syscall overhead. The latency from one iteration to the next of the internal loop is a bit of a random process due to scheduler or clock noise (although the noise itself is still bounded). In order to make this test robust against such noise, assert only on the average time from one iteration to the next, rather than the instantaneous time. Rather than calculating a sample mean, use a running average (aka Cumulative Moving Average) to save some bytes. Report results, including low and high watermarks before asserting that the average iteration time within expected range. ============================================================== START - test_realtime I: n: 20, sleep: 100, margin: 10, lo: 110, avg: 110, hi: 110 PASS - test_realtime in 2.198 seconds ============================================================== Expect to see the low and high watermarks change more on Qemu and POSIX platforms when running several jobs in parallel with twister (such as in CI). Signed-off-by: Christopher Friedt --- tests/posix/common/Kconfig | 27 ++++ tests/posix/common/src/clock.c | 256 ++++++++++++++++++++++----------- 2 files changed, 200 insertions(+), 83 deletions(-) create mode 100644 tests/posix/common/Kconfig diff --git a/tests/posix/common/Kconfig b/tests/posix/common/Kconfig new file mode 100644 index 00000000000..18b0b82daee --- /dev/null +++ b/tests/posix/common/Kconfig @@ -0,0 +1,27 @@ +# Copyright (c) 2023, Meta +# SPDX-License-Identifier: Apache-2.0 + +# Options specific to clock.c / test_realtime + +config TEST_CLOCK_RT_ITERATIONS + int "Number of iterations to check clock_gettime() reliability" + range 10 100 + default 20 + help + This option is specific to posix_apis.test_realtime in clock.c + +config TEST_CLOCK_RT_SLEEP_MS + int "Time to sleep between iterations in milliseconds" + range 50 1000 + default 100 + help + This option is specific to posix_apis.test_realtime in clock.c + +config TEST_CLOCK_RT_ERROR_MS + int "Maximum overshoot (error) in milliseconds" + range 10 500 + default 10 + help + This option is specific to posix_apis.test_realtime in clock.c + +source "Kconfig.zephyr" diff --git a/tests/posix/common/src/clock.c b/tests/posix/common/src/clock.c index 154fa6c8da0..3677e606c16 100644 --- a/tests/posix/common/src/clock.c +++ b/tests/posix/common/src/clock.c @@ -1,5 +1,6 @@ /* * Copyright (c) 2018 Intel Corporation + * Copyright (c) 2023, Meta * * SPDX-License-Identifier: Apache-2.0 */ @@ -8,118 +9,207 @@ #include #include +#include #define SLEEP_SECONDS 1 #define CLOCK_INVALID -1 -ZTEST(posix_apis, test_clock) -{ - int64_t nsecs_elapsed, secs_elapsed; - struct timespec ts, te; +LOG_MODULE_REGISTER(clock_test, LOG_LEVEL_DBG); - printk("POSIX clock APIs\n"); +/* Set a particular time. In this case, the output of: `date +%s -d 2018-01-01T15:45:01Z` */ +static const struct timespec ref_ts = {1514821501, NSEC_PER_SEC / 2U}; - /* TESTPOINT: Pass invalid clock type */ - zassert_equal(clock_gettime(CLOCK_INVALID, &ts), -1, - NULL); - zassert_equal(errno, EINVAL); +static const clockid_t clocks[] = { + CLOCK_MONOTONIC, + CLOCK_REALTIME, +}; +static const bool settable[] = { + false, + true, +}; + +static inline int64_t ts_to_ns(const struct timespec *ts) +{ + return ts->tv_sec * NSEC_PER_SEC + ts->tv_nsec; +} + +static inline void tv_to_ts(const struct timeval *tv, struct timespec *ts) +{ + ts->tv_sec = tv->tv_sec; + ts->tv_nsec = tv->tv_usec * NSEC_PER_USEC; +} - zassert_ok(clock_gettime(CLOCK_MONOTONIC, &ts)); - zassert_ok(k_sleep(K_SECONDS(SLEEP_SECONDS))); - zassert_ok(clock_gettime(CLOCK_MONOTONIC, &te)); +#define _tp_op(_a, _b, _op) (ts_to_ns(_a) _op ts_to_ns(_b)) - if (te.tv_nsec >= ts.tv_nsec) { - secs_elapsed = te.tv_sec - ts.tv_sec; - nsecs_elapsed = te.tv_nsec - ts.tv_nsec; - } else { - nsecs_elapsed = NSEC_PER_SEC + te.tv_nsec - ts.tv_nsec; - secs_elapsed = (te.tv_sec - ts.tv_sec - 1); +#define _decl_op(_type, _name, _op) \ + static inline _type _name(const struct timespec *_a, const struct timespec *_b) \ + { \ + return _tp_op(_a, _b, _op); \ } - /*TESTPOINT: Check if POSIX clock API test passes*/ - zassert_equal(secs_elapsed, SLEEP_SECONDS, - "POSIX clock API test failed"); +_decl_op(bool, tp_eq, ==); /* a == b */ +_decl_op(bool, tp_lt, <); /* a < b */ +_decl_op(bool, tp_gt, >); /* a > b */ +_decl_op(bool, tp_le, <=); /* a <= b */ +_decl_op(bool, tp_ge, >=); /* a >= b */ +_decl_op(int64_t, tp_diff, -); /* a - b */ + +/* lo <= (a - b) < hi */ +static inline bool tp_diff_in_range_ns(const struct timespec *a, const struct timespec *b, + int64_t lo, int64_t hi) +{ + int64_t diff = tp_diff(a, b); - printk("POSIX clock APIs test done\n"); + return diff >= lo && diff < hi; } -ZTEST(posix_apis, test_realtime) +ZTEST(posix_apis, test_clock_gettime) { - int ret; - struct timespec rts, mts; - struct timeval tv; + struct timespec ts; - ret = clock_gettime(CLOCK_MONOTONIC, &mts); - zassert_equal(ret, 0, "Fail to get monotonic clock"); - - ret = clock_gettime(CLOCK_REALTIME, &rts); - zassert_equal(ret, 0, "Fail to get realtime clock"); + /* ensure argument validation is performed */ + errno = 0; + zassert_equal(clock_gettime(CLOCK_INVALID, &ts), -1); + zassert_equal(errno, EINVAL); - /* Set a particular time. In this case, the output of: - * `date +%s -d 2018-01-01T15:45:01Z` - */ - struct timespec nts; - nts.tv_sec = 1514821501; - nts.tv_nsec = NSEC_PER_SEC / 2U; + if (false) { + /* undefined behaviour */ + errno = 0; + zassert_equal(clock_gettime(clocks[0], NULL), -1); + zassert_equal(errno, EINVAL); + } - /* TESTPOINT: Pass invalid clock type */ - zassert_equal(clock_settime(CLOCK_INVALID, &nts), -1, - NULL); - zassert_equal(errno, EINVAL); + /* verify that we can call clock_gettime() on supported clocks */ + ARRAY_FOR_EACH(clocks, i) + { + ts = (struct timespec){-1, -1}; + zassert_ok(clock_gettime(clocks[i], &ts)); + zassert_not_equal(ts.tv_sec, -1); + zassert_not_equal(ts.tv_nsec, -1); + } +} - ret = clock_settime(CLOCK_MONOTONIC, &nts); - zassert_not_equal(ret, 0, "Should not be able to set monotonic time"); +ZTEST(posix_apis, test_gettimeofday) +{ + struct timeval tv; + struct timespec ts; + struct timespec rts; + + if (false) { + /* undefined behaviour */ + errno = 0; + zassert_equal(gettimeofday(NULL, NULL), -1); + zassert_equal(errno, EINVAL); + } - ret = clock_settime(CLOCK_REALTIME, &nts); - zassert_equal(ret, 0, "Fail to set realtime clock"); + /* Validate gettimeofday API */ + zassert_ok(gettimeofday(&tv, NULL)); + zassert_ok(clock_gettime(CLOCK_REALTIME, &rts)); - /* - * Loop 20 times, sleeping a little bit for each, making sure - * that the arithmetic roughly makes sense. This tries to - * catch all of the boundary conditions of the clock to make - * sure there are no errors in the arithmetic. + /* TESTPOINT: Check if time obtained from + * gettimeofday is same or more than obtained + * from clock_gettime */ - int64_t last_delta = 0; - for (int i = 1; i <= 20; i++) { - usleep(USEC_PER_MSEC * 90U); - ret = clock_gettime(CLOCK_REALTIME, &rts); - zassert_equal(ret, 0, "Fail to read realtime clock"); + tv_to_ts(&tv, &ts); + zassert_true(tp_ge(&rts, &ts)); +} - int64_t delta = - ((int64_t)rts.tv_sec * NSEC_PER_SEC - - (int64_t)nts.tv_sec * NSEC_PER_SEC) + - ((int64_t)rts.tv_nsec - (int64_t)nts.tv_nsec); +ZTEST(posix_apis, test_clock_settime) +{ + int64_t diff_ns; + struct timespec ts = {0}; - /* Make the delta milliseconds. */ - delta /= (NSEC_PER_SEC / 1000U); + BUILD_ASSERT(ARRAY_SIZE(settable) == ARRAY_SIZE(clocks)); - zassert_true(delta > last_delta, "Clock moved backward"); - int64_t error = delta - last_delta; + /* ensure argument validation is performed */ + errno = 0; + zassert_equal(clock_settime(CLOCK_INVALID, &ts), -1); + zassert_equal(errno, EINVAL); - /* printk("Delta %d: %lld\n", i, delta); */ + if (false) { + /* undefined behaviour */ + errno = 0; + zassert_equal(clock_settime(CLOCK_REALTIME, NULL), -1); + zassert_equal(errno, EINVAL); + } - /* Allow for a little drift upward, but not - * downward - */ - zassert_true(error >= 90, "Clock inaccurate %d", error); - zassert_true(error <= 110, "Clock inaccurate %d", error); + /* verify nanoseconds */ + errno = 0; + ts = (struct timespec){0, NSEC_PER_SEC}; + zassert_equal(clock_settime(CLOCK_REALTIME, &ts), -1); + zassert_equal(errno, EINVAL); + errno = 0; + ts = (struct timespec){0, -1}; + zassert_equal(clock_settime(CLOCK_REALTIME, &ts), -1); + zassert_equal(errno, EINVAL); - last_delta = delta; + ARRAY_FOR_EACH(clocks, i) + { + if (!settable[i]) { + /* should fail attempting to set unsettable clocks */ + errno = 0; + zassert_equal(clock_settime(clocks[i], &ts), -1); + zassert_equal(errno, EINVAL); + continue; + } + + zassert_ok(clock_settime(clocks[i], &ref_ts)); + + /* read-back the time */ + zassert_ok(clock_gettime(clocks[i], &ts)); + /* dt should be >= 0, but definitely <= 1s */ + diff_ns = tp_diff(&ts, &ref_ts); + zassert_true(diff_ns >= 0 && diff_ns <= NSEC_PER_SEC); } +} - /* Validate gettimeofday API */ - ret = gettimeofday(&tv, NULL); - zassert_equal(ret, 0); +ZTEST(posix_apis, test_realtime) +{ + struct timespec then, now; + /* + * For calculating cumulative moving average + * Note: we do not want to assert any individual samples due to scheduler noise. + * The CMA filters out the noise so we can make an assertion (on average). + * https://en.wikipedia.org/wiki/Moving_average#Cumulative_moving_average + */ + int64_t cma_prev = 0; + int64_t cma; + int64_t x_i; + /* lower and uppoer boundary for assertion */ + int64_t lo = CONFIG_TEST_CLOCK_RT_SLEEP_MS; + int64_t hi = CONFIG_TEST_CLOCK_RT_SLEEP_MS + CONFIG_TEST_CLOCK_RT_ERROR_MS; + /* lower and upper watermark */ + int64_t lo_wm = INT64_MAX; + int64_t hi_wm = INT64_MIN; + + /* Loop n times, sleeping a little bit for each */ + (void)clock_gettime(CLOCK_REALTIME, &then); + for (int i = 0; i < CONFIG_TEST_CLOCK_RT_ITERATIONS; ++i) { + + zassert_ok(k_usleep(USEC_PER_MSEC * CONFIG_TEST_CLOCK_RT_SLEEP_MS)); + (void)clock_gettime(CLOCK_REALTIME, &now); - ret = clock_gettime(CLOCK_REALTIME, &rts); - zassert_equal(ret, 0); + /* Make the delta milliseconds. */ + x_i = tp_diff(&now, &then) / NSEC_PER_MSEC; + then = now; + + if (x_i < lo_wm) { + /* update low watermark */ + lo_wm = x_i; + } + + if (x_i > hi_wm) { + /* update high watermark */ + hi_wm = x_i; + } + + /* compute cumulative running average */ + cma = (x_i + i * cma_prev) / (i + 1); + cma_prev = cma; + } - /* TESTPOINT: Check if time obtained from - * gettimeofday is same or more than obtained - * from clock_gettime - */ - zassert_true(rts.tv_sec >= tv.tv_sec, "gettimeofday didn't" - " provide correct result"); - zassert_true(rts.tv_nsec >= tv.tv_usec * NSEC_PER_USEC, - "gettimeofday didn't provide correct result"); + LOG_INF("n: %d, sleep: %d, margin: %d, lo: %lld, avg: %lld, hi: %lld", + CONFIG_TEST_CLOCK_RT_ITERATIONS, CONFIG_TEST_CLOCK_RT_SLEEP_MS, + CONFIG_TEST_CLOCK_RT_ERROR_MS, lo_wm, cma, hi_wm); + zassert_between_inclusive(cma, lo, hi); } From c25ac487af84e71498788577af4ee2e62291e34f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sebastian=20B=C3=B8e?= Date: Mon, 18 Dec 2023 10:29:54 +0100 Subject: [PATCH 1689/3723] tests: crypto: rand32: Check return code of sys_csrand_get MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Check the return code of sys_csrand_get when testing the function. Ignoring it is bad practice and can also be a security issue if users copy-paste this test code. Signed-off-by: Sebastian Bøe --- tests/crypto/rand32/src/main.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/tests/crypto/rand32/src/main.c b/tests/crypto/rand32/src/main.c index 1f2492e69e3..5436c627cd5 100644 --- a/tests/crypto/rand32/src/main.c +++ b/tests/crypto/rand32/src/main.c @@ -90,7 +90,10 @@ ZTEST(rand32_common, test_rand32) printk("Generating bulk fill cryptographically secure random numbers\n"); memset(buf, 0, sizeof(buf)); - sys_csrand_get(buf, sizeof(buf)); + + int err = sys_csrand_get(buf, sizeof(buf)); + + zassert_true(err == 0, "sys_csrand_get returned an error"); for (rnd_cnt = 0; rnd_cnt < (N_VALUES - 1); rnd_cnt++) { gen = buf[rnd_cnt]; From c992707251efc208130ada7d0a54f19ce038c199 Mon Sep 17 00:00:00 2001 From: Rodrigo Peixoto Date: Tue, 5 Sep 2023 12:48:55 -0300 Subject: [PATCH 1690/3723] zbus: add priority boost feature Replace mutexes with semaphores to protect the channels in conjunction with a priority boost algorithm based on the observers' priority. Signed-off-by: Rodrigo Peixoto --- cmake/linker_script/common/common-rom.cmake | 1 + include/zephyr/linker/common-ram.ld | 1 - .../linker/common-rom/common-rom-misc.ld | 1 + include/zephyr/zbus/zbus.h | 189 ++++++++---- subsys/zbus/Kconfig | 7 + subsys/zbus/zbus.c | 282 +++++++++++++++--- subsys/zbus/zbus_runtime_observers.c | 16 +- 7 files changed, 396 insertions(+), 101 deletions(-) diff --git a/cmake/linker_script/common/common-rom.cmake b/cmake/linker_script/common/common-rom.cmake index d79fa223fc5..d955c8ad0b6 100644 --- a/cmake/linker_script/common/common-rom.cmake +++ b/cmake/linker_script/common/common-rom.cmake @@ -216,6 +216,7 @@ endif() if(CONFIG_ZBUS) zephyr_iterable_section(NAME zbus_channel KVMA RAM_REGION GROUP RODATA_REGION SUBALIGN 4) + zephyr_iterable_section(NAME zbus_observer KVMA RAM_REGION GROUP RODATA_REGION SUBALIGN 4) zephyr_iterable_section(NAME zbus_channel_observation KVMA RAM_REGION GROUP RODATA_REGION SUBALIGN 4) endif() diff --git a/include/zephyr/linker/common-ram.ld b/include/zephyr/linker/common-ram.ld index 7bb6e55f1c1..df70b13ca73 100644 --- a/include/zephyr/linker/common-ram.ld +++ b/include/zephyr/linker/common-ram.ld @@ -133,7 +133,6 @@ #endif /* CONFIG_SENSING */ #if defined(CONFIG_ZBUS) - ITERABLE_SECTION_RAM(zbus_observer, 4) ITERABLE_SECTION_RAM(zbus_channel_observation_mask, 1) #endif /* CONFIG_ZBUS */ diff --git a/include/zephyr/linker/common-rom/common-rom-misc.ld b/include/zephyr/linker/common-rom/common-rom-misc.ld index 1fbf777ba55..189a9e31885 100644 --- a/include/zephyr/linker/common-rom/common-rom-misc.ld +++ b/include/zephyr/linker/common-rom/common-rom-misc.ld @@ -36,6 +36,7 @@ #if defined(CONFIG_ZBUS) ITERABLE_SECTION_ROM(zbus_channel, 4) + ITERABLE_SECTION_ROM(zbus_observer, 4) ITERABLE_SECTION_ROM(zbus_channel_observation, 4) #endif /* CONFIG_ZBUS */ diff --git a/include/zephyr/zbus/zbus.h b/include/zephyr/zbus/zbus.h index 285338d4732..2c0c0622aed 100644 --- a/include/zephyr/zbus/zbus.h +++ b/include/zephyr/zbus/zbus.h @@ -38,10 +38,17 @@ struct zbus_channel_data { */ int16_t observers_end_idx; - /** Access control mutex. Points to the mutex used to avoid race conditions + /** Access control semaphore. Points to the semaphore used to avoid race conditions * for accessing the channel. */ - struct k_mutex mutex; + struct k_sem sem; + +#if defined(CONFIG_ZBUS_PRIORITY_BOOST) + /** Highest observer priority. Indicates the priority that the VDED will use to boost the + * notification process avoiding preemptions. + */ + int highest_observer_priority; +#endif /* CONFIG_ZBUS_PRIORITY_BOOST */ #if defined(CONFIG_ZBUS_RUNTIME_OBSERVERS) || defined(__DOXYGEN__) /** Channel observer list. Represents the channel's observers list, it can be empty @@ -96,6 +103,16 @@ enum __packed zbus_observer_type { ZBUS_OBSERVER_MSG_SUBSCRIBER_TYPE, }; +struct zbus_observer_data { + /** Enabled flag. Indicates if observer is receiving notification. */ + bool enabled; + +#if defined(CONFIG_ZBUS_PRIORITY_BOOST) + /** Subscriber attached thread priority. */ + int priority; +#endif /* CONFIG_ZBUS_PRIORITY_BOOST */ +}; + /** * @brief Type used to represent an observer. * @@ -119,8 +136,8 @@ struct zbus_observer { /** Type indication. */ enum zbus_observer_type type; - /** Enabled flag. Indicates if observer is receiving notification. */ - bool enabled; + /** Mutable observer data struct. */ + struct zbus_observer_data *const data; union { /** Observer message queue. It turns the observer into a subscriber. */ @@ -154,6 +171,8 @@ struct zbus_channel_observation { #define _ZBUS_CPP_EXTERN #endif /* __cplusplus */ +#define ZBUS_MIN_THREAD_PRIORITY (CONFIG_NUM_PREEMPT_PRIORITIES - 1) + #if defined(CONFIG_ZBUS_ASSERT_MOCK) #define _ZBUS_ASSERT(_cond, _fmt, ...) \ do { \ @@ -233,6 +252,7 @@ struct zbus_channel_observation { /** @endcond */ +/* clang-format off */ /** * @brief Add a static channel observervation. * @@ -246,11 +266,15 @@ struct zbus_channel_observation { */ #define ZBUS_CHAN_ADD_OBS_WITH_MASK(_chan, _obs, _masked, _prio) \ const STRUCT_SECTION_ITERABLE(zbus_channel_observation, \ - _CONCAT(_CONCAT(_chan, zz), _CONCAT(_prio, _obs))) = { \ - .chan = &_chan, .obs = &_obs}; \ + _CONCAT(_CONCAT(_chan, zz), _CONCAT(_prio, _obs))) = { \ + .chan = &_chan, \ + .obs = &_obs, \ + }; \ STRUCT_SECTION_ITERABLE(zbus_channel_observation_mask, \ _CONCAT(_CONCAT(_CONCAT(_chan, zz), _CONCAT(_prio, _obs)), \ _mask)) = {.enabled = _masked} +/* clang-format on */ + /** * @brief Add a static channel observervation. * @@ -290,6 +314,7 @@ struct zbus_channel_observation { */ #define ZBUS_OBSERVERS(...) __VA_ARGS__ +/* clang-format off */ /** * @brief Zbus channel definition. * @@ -305,20 +330,29 @@ struct zbus_channel_observation { * first the highest priority. * @param _init_val The message initialization. */ -#define ZBUS_CHAN_DEFINE(_name, _type, _validator, _user_data, _observers, _init_val) \ - static _type _CONCAT(_zbus_message_, _name) = _init_val; \ - static struct zbus_channel_data _CONCAT(_zbus_chan_data_, _name) = { \ - .observers_start_idx = -1, .observers_end_idx = -1}; \ - static K_MUTEX_DEFINE(_CONCAT(_zbus_mutex_, _name)); \ - _ZBUS_CPP_EXTERN const STRUCT_SECTION_ITERABLE(zbus_channel, _name) = { \ - ZBUS_CHANNEL_NAME_INIT(_name) /* Maybe removed */ \ - .message = &_CONCAT(_zbus_message_, _name), \ - .message_size = sizeof(_type), .user_data = _user_data, .validator = (_validator), \ - .data = &_CONCAT(_zbus_chan_data_, _name)}; \ - /* Extern declaration of observers */ \ - ZBUS_OBS_DECLARE(_observers); \ - /* Create all channel observations from observers list */ \ +#define ZBUS_CHAN_DEFINE(_name, _type, _validator, _user_data, _observers, _init_val) \ + static _type _CONCAT(_zbus_message_, _name) = _init_val; \ + static struct zbus_channel_data _CONCAT(_zbus_chan_data_, _name) = { \ + .observers_start_idx = -1, \ + .observers_end_idx = -1, \ + IF_ENABLED(CONFIG_ZBUS_PRIORITY_BOOST, ( \ + .highest_observer_priority = ZBUS_MIN_THREAD_PRIORITY, \ + )) \ + }; \ + static K_MUTEX_DEFINE(_CONCAT(_zbus_mutex_, _name)); \ + _ZBUS_CPP_EXTERN const STRUCT_SECTION_ITERABLE(zbus_channel, _name) = { \ + ZBUS_CHANNEL_NAME_INIT(_name) /* Maybe removed */ \ + .message = &_CONCAT(_zbus_message_, _name), \ + .message_size = sizeof(_type), \ + .user_data = _user_data, \ + .validator = _validator, \ + .data = &_CONCAT(_zbus_chan_data_, _name), \ + }; \ + /* Extern declaration of observers */ \ + ZBUS_OBS_DECLARE(_observers); \ + /* Create all channel observations from observers list */ \ FOR_EACH_FIXED_ARG_NONEMPTY_TERM(_ZBUS_CHAN_OBSERVATION, (;), _name, _observers) +/* clang-format on */ /** * @brief Initialize a message. @@ -334,6 +368,7 @@ struct zbus_channel_observation { _val, ##__VA_ARGS__ \ } +/* clang-format off */ /** * @brief Define and initialize a subscriber. * @@ -345,13 +380,25 @@ struct zbus_channel_observation { * @param[in] _queue_size The notification queue's size. * @param[in] _enable The subscriber initial enable state. */ -#define ZBUS_SUBSCRIBER_DEFINE_WITH_ENABLE(_name, _queue_size, _enable) \ - K_MSGQ_DEFINE(_zbus_observer_queue_##_name, sizeof(const struct zbus_channel *), \ - _queue_size, sizeof(const struct zbus_channel *)); \ - STRUCT_SECTION_ITERABLE(zbus_observer, _name) = { \ - ZBUS_OBSERVER_NAME_INIT(_name) /* Name field */ \ - .type = ZBUS_OBSERVER_SUBSCRIBER_TYPE, \ - .enabled = _enable, .queue = &_zbus_observer_queue_##_name} +#define ZBUS_SUBSCRIBER_DEFINE_WITH_ENABLE(_name, _queue_size, _enable) \ + K_MSGQ_DEFINE(_zbus_observer_queue_##_name, \ + sizeof(const struct zbus_channel *), \ + _queue_size, sizeof(const struct zbus_channel *) \ + ); \ + static struct zbus_observer_data _CONCAT(_zbus_obs_data_, _name) = { \ + .enabled = _enable, \ + IF_ENABLED(CONFIG_ZBUS_PRIORITY_BOOST, ( \ + .priority = ZBUS_MIN_THREAD_PRIORITY, \ + )) \ + }; \ + STRUCT_SECTION_ITERABLE(zbus_observer, _name) = { \ + ZBUS_OBSERVER_NAME_INIT(_name) /* Name field */ \ + .type = ZBUS_OBSERVER_SUBSCRIBER_TYPE, \ + .data = &_CONCAT(_zbus_obs_data_, _name), \ + .queue = &_zbus_observer_queue_##_name, \ + } +/* clang-format on */ + /** * @brief Define and initialize a subscriber. * @@ -366,6 +413,7 @@ struct zbus_channel_observation { #define ZBUS_SUBSCRIBER_DEFINE(_name, _queue_size) \ ZBUS_SUBSCRIBER_DEFINE_WITH_ENABLE(_name, _queue_size, true) +/* clang-format off */ /** * @brief Define and initialize a listener. * @@ -378,10 +426,20 @@ struct zbus_channel_observation { * @param[in] _enable The listener initial enable state. */ #define ZBUS_LISTENER_DEFINE_WITH_ENABLE(_name, _cb, _enable) \ - STRUCT_SECTION_ITERABLE(zbus_observer, \ - _name) = {ZBUS_OBSERVER_NAME_INIT(_name) /* Name field */ \ - .type = ZBUS_OBSERVER_LISTENER_TYPE, \ - .enabled = _enable, .callback = (_cb)} + static struct zbus_observer_data _CONCAT(_zbus_obs_data_, _name) = { \ + .enabled = _enable, \ + IF_ENABLED(CONFIG_ZBUS_PRIORITY_BOOST, ( \ + .priority = ZBUS_MIN_THREAD_PRIORITY, \ + )) \ + }; \ + STRUCT_SECTION_ITERABLE(zbus_observer, _name) = { \ + ZBUS_OBSERVER_NAME_INIT(_name) /* Name field */ \ + .type = ZBUS_OBSERVER_LISTENER_TYPE, \ + .data = &_CONCAT(_zbus_obs_data_, _name), \ + .callback = (_cb) \ + } +/* clang-format on */ + /** * @brief Define and initialize a listener. * @@ -394,6 +452,7 @@ struct zbus_channel_observation { */ #define ZBUS_LISTENER_DEFINE(_name, _cb) ZBUS_LISTENER_DEFINE_WITH_ENABLE(_name, _cb, true) +/* clang-format off */ /** * @brief Define and initialize a message subscriber. * @@ -404,14 +463,21 @@ struct zbus_channel_observation { * @param[in] _name The subscriber's name. * @param[in] _enable The subscriber's initial state. */ -#define ZBUS_MSG_SUBSCRIBER_DEFINE_WITH_ENABLE(_name, _enable) \ - static K_FIFO_DEFINE(_zbus_observer_fifo_##_name); \ - STRUCT_SECTION_ITERABLE(zbus_observer, _name) = { \ - ZBUS_OBSERVER_NAME_INIT(_name) /* Name field */ \ - .type = ZBUS_OBSERVER_MSG_SUBSCRIBER_TYPE, \ - .enabled = _enable, \ - .message_fifo = &_zbus_observer_fifo_##_name, \ +#define ZBUS_MSG_SUBSCRIBER_DEFINE_WITH_ENABLE(_name, _enable) \ + static K_FIFO_DEFINE(_zbus_observer_fifo_##_name); \ + static struct zbus_observer_data _CONCAT(_zbus_obs_data_, _name) = { \ + .enabled = _enable, \ + IF_ENABLED(CONFIG_ZBUS_PRIORITY_BOOST, ( \ + .priority = ZBUS_MIN_THREAD_PRIORITY, \ + )) \ + }; \ + STRUCT_SECTION_ITERABLE(zbus_observer, _name) = { \ + ZBUS_OBSERVER_NAME_INIT(_name) /* Name field */ \ + .type = ZBUS_OBSERVER_MSG_SUBSCRIBER_TYPE, \ + .data = &_CONCAT(_zbus_obs_data_, _name), \ + .message_fifo = &_zbus_observer_fifo_##_name, \ } +/* clang-format on */ /** * @brief Define and initialize an enabled message subscriber. @@ -501,8 +567,6 @@ int zbus_chan_claim(const struct zbus_channel *chan, k_timeout_t timeout); * @param chan The channel's reference. * * @retval 0 Channel finished. - * @retval -EPERM The channel was claimed by other thread. - * @retval -EINVAL The channel's mutex is not locked. * @retval -EFAULT A parameter is incorrect, or the function context is invalid (inside an ISR). The * function only returns this value when the CONFIG_ZBUS_ASSERT_MOCK is enabled. */ @@ -519,9 +583,9 @@ int zbus_chan_finish(const struct zbus_channel *chan); * or one of the special values K_NO_WAIT and K_FOREVER. * * @retval 0 Channel notified. - * @retval -EPERM The current thread does not own the channel. - * @retval -EBUSY The channel's mutex returned without waiting. - * @retval -EAGAIN Timeout to acquiring the channel's mutex. + * @retval -EBUSY The channel's semaphore returned without waiting. + * @retval -EAGAIN Timeout to take the channel's semaphore. + * @retval -ENOMEM There is not more buffer on the messgage buffers pool. * @retval -EFAULT A parameter is incorrect, the notification could not be sent to one or more * observer, or the function context is invalid (inside an ISR). The function only returns this * value when the CONFIG_ZBUS_ASSERT_MOCK is enabled. @@ -553,7 +617,7 @@ static inline const char *zbus_chan_name(const struct zbus_channel *chan) * * This routine returns the reference of a channel message. * - * @warning This function must only be used directly for acquired (locked by mutex) channels. This + * @warning This function must only be used directly for already locked channels. This * can be done inside a listener for the receiving channel or after claim a channel. * * @param chan The channel's reference. @@ -574,7 +638,7 @@ static inline void *zbus_chan_msg(const struct zbus_channel *chan) * inside listeners to access the message directly. In this way zbus prevents the listener of * changing the notifying channel's message during the notification process. * - * @warning This function must only be used directly for acquired (locked by mutex) channels. This + * @warning This function must only be used directly for already locked channels. This * can be done inside a listener for the receiving channel or after claim a channel. * * @param chan The channel's constant reference. @@ -685,14 +749,7 @@ struct zbus_observer_node { * @retval -EFAULT A parameter is incorrect, or the function context is invalid (inside an ISR). The * function only returns this value when the CONFIG_ZBUS_ASSERT_MOCK is enabled. */ -static inline int zbus_obs_set_enable(struct zbus_observer *obs, bool enabled) -{ - _ZBUS_ASSERT(obs != NULL, "obs is required"); - - obs->enabled = enabled; - - return 0; -} +int zbus_obs_set_enable(struct zbus_observer *obs, bool enabled); /** * @brief Get the observer state. @@ -709,7 +766,7 @@ static inline int zbus_obs_is_enabled(struct zbus_observer *obs, bool *enable) _ZBUS_ASSERT(obs != NULL, "obs is required"); _ZBUS_ASSERT(enable != NULL, "enable is required"); - *enable = obs->enabled; + *enable = obs->data->enabled; return 0; } @@ -766,6 +823,32 @@ static inline const char *zbus_obs_name(const struct zbus_observer *obs) #endif +#if defined(CONFIG_ZBUS_PRIORITY_BOOST) || defined(__DOXYGEN__) + +/** + * @brief Set the observer thread priority by attaching it to a thread. + * + * @param[in] obs The observer's reference. + * + * @retval 0 Observer detached from the thread. + * @retval -EFAULT A parameter is incorrect, or the function context is invalid (inside an ISR). The + * function only returns this value when the CONFIG_ZBUS_ASSERT_MOCK is enabled. + */ +int zbus_obs_attach_to_thread(const struct zbus_observer *obs); + +/** + * @brief Clear the observer thread priority by detaching it from a thread. + * + * @param[in] obs The observer's reference. + * + * @retval 0 Observer detached from the thread. + * @retval -EFAULT A parameter is incorrect, or the function context is invalid (inside an ISR). The + * function only returns this value when the CONFIG_ZBUS_ASSERT_MOCK is enabled. + */ +int zbus_obs_detach_from_thread(const struct zbus_observer *obs); + +#endif /* CONFIG_ZBUS_PRIORITY_BOOST */ + /** * @brief Wait for a channel notification. * diff --git a/subsys/zbus/Kconfig b/subsys/zbus/Kconfig index 72f6c0c5614..dfb839abe02 100644 --- a/subsys/zbus/Kconfig +++ b/subsys/zbus/Kconfig @@ -53,6 +53,13 @@ endif # ZBUS_MSG_SUBSCRIBER config ZBUS_RUNTIME_OBSERVERS bool "Runtime observers support." +config ZBUS_PRIORITY_BOOST + bool "ZBus priority boost algorithm" + default y + help + ZBus implements the Highest Locker Protocol that relies on the observers’ thread priority + to determine a temporary publisher priority. + config ZBUS_ASSERT_MOCK bool "Zbus assert mock for test purposes." help diff --git a/subsys/zbus/zbus.c b/subsys/zbus/zbus.c index 959ef59aa8e..d16cc27d965 100644 --- a/subsys/zbus/zbus.c +++ b/subsys/zbus/zbus.c @@ -12,6 +12,13 @@ #include LOG_MODULE_REGISTER(zbus, CONFIG_ZBUS_LOG_LEVEL); +#if defined(CONFIG_ZBUS_PRIORITY_BOOST) +/* Available only when the priority boost is enabled */ +static struct k_spinlock _zbus_chan_slock; +#endif /* CONFIG_ZBUS_PRIORITY_BOOST */ + +static struct k_spinlock obs_slock; + #if defined(CONFIG_ZBUS_MSG_SUBSCRIBER) #if defined(CONFIG_ZBUS_MSG_SUBSCRIBER_BUF_ALLOC_DYNAMIC) @@ -69,7 +76,7 @@ int _zbus_init(void) ++(curr->data->observers_end_idx); } STRUCT_SECTION_FOREACH(zbus_channel, chan) { - k_mutex_init(&chan->data->mutex); + k_sem_init(&chan->data->sem, 1, 1); #if defined(CONFIG_ZBUS_RUNTIME_OBSERVERS) sys_slist_init(&chan->data->observers); @@ -145,7 +152,7 @@ static inline int _zbus_vded_exec(const struct zbus_channel *chan, k_timepoint_t const struct zbus_observer *obs = observation->obs; - if (!obs->enabled || observation_mask->enabled) { + if (!obs->data->enabled || observation_mask->enabled) { continue; } @@ -174,7 +181,7 @@ static inline int _zbus_vded_exec(const struct zbus_channel *chan, k_timepoint_t const struct zbus_observer *obs = obs_nd->obs; - if (!obs->enabled) { + if (!obs->data->enabled) { continue; } @@ -191,21 +198,171 @@ static inline int _zbus_vded_exec(const struct zbus_channel *chan, k_timepoint_t return last_error; } +#if defined(CONFIG_ZBUS_PRIORITY_BOOST) + +static inline void chan_update_hop(const struct zbus_channel *chan) +{ + struct zbus_channel_observation *observation; + struct zbus_channel_observation_mask *observation_mask; + + int chan_highest_observer_priority = ZBUS_MIN_THREAD_PRIORITY; + + K_SPINLOCK(&_zbus_chan_slock) { + const int limit = chan->data->observers_end_idx; + + for (int16_t i = chan->data->observers_start_idx; i < limit; ++i) { + STRUCT_SECTION_GET(zbus_channel_observation, i, &observation); + STRUCT_SECTION_GET(zbus_channel_observation_mask, i, &observation_mask); + + __ASSERT(observation != NULL, "observation must be not NULL"); + + const struct zbus_observer *obs = observation->obs; + + if (!obs->data->enabled || observation_mask->enabled) { + continue; + } + + if (chan_highest_observer_priority > obs->data->priority) { + chan_highest_observer_priority = obs->data->priority; + } + } + chan->data->highest_observer_priority = chan_highest_observer_priority; + } +} + +static inline void update_all_channels_hop(const struct zbus_observer *obs) +{ + struct zbus_channel_observation *observation; + + int count; + + STRUCT_SECTION_COUNT(zbus_channel_observation, &count); + + for (int16_t i = 0; i < count; ++i) { + STRUCT_SECTION_GET(zbus_channel_observation, i, &observation); + + if (obs != observation->obs) { + continue; + } + + chan_update_hop(observation->chan); + } +} + +int zbus_obs_attach_to_thread(const struct zbus_observer *obs) +{ + _ZBUS_ASSERT(!k_is_in_isr(), "cannot attach to an ISR"); + _ZBUS_ASSERT(obs != NULL, "obs is required"); + + int current_thread_priority = k_thread_priority_get(k_current_get()); + + K_SPINLOCK(&obs_slock) { + if (obs->data->priority != current_thread_priority) { + obs->data->priority = current_thread_priority; + + update_all_channels_hop(obs); + } + } + + return 0; +} + +int zbus_obs_detach_from_thread(const struct zbus_observer *obs) +{ + _ZBUS_ASSERT(!k_is_in_isr(), "cannot detach from an ISR"); + _ZBUS_ASSERT(obs != NULL, "obs is required"); + + K_SPINLOCK(&obs_slock) { + obs->data->priority = ZBUS_MIN_THREAD_PRIORITY; + + update_all_channels_hop(obs); + } + + return 0; +} + +#else + +static inline void update_all_channels_hop(const struct zbus_observer *obs) +{ +} + +#endif /* CONFIG_ZBUS_PRIORITY_BOOST */ + +static inline int chan_lock(const struct zbus_channel *chan, k_timeout_t timeout, int *prio) +{ + bool boosting = false; + +#if defined(CONFIG_ZBUS_PRIORITY_BOOST) + if (!k_is_in_isr()) { + *prio = k_thread_priority_get(k_current_get()); + + K_SPINLOCK(&_zbus_chan_slock) { + if (*prio > chan->data->highest_observer_priority) { + int new_prio = chan->data->highest_observer_priority - 1; + + new_prio = MAX(new_prio, 0); + + /* Elevating priority since the highest_observer_priority is + * greater than the current thread + */ + k_thread_priority_set(k_current_get(), new_prio); + + boosting = true; + } + } + } +#endif /* CONFIG_ZBUS_PRIORITY_BOOST */ + + int err = k_sem_take(&chan->data->sem, timeout); + + if (err) { + /* When the priority boost is disabled, this IF will be optimized out. */ + if (boosting) { + /* Restoring thread priority since the semaphore is not available */ + k_thread_priority_set(k_current_get(), *prio); + } + + return err; + } + + return 0; +} + +static inline void chan_unlock(const struct zbus_channel *chan, int prio) +{ + k_sem_give(&chan->data->sem); + +#if defined(CONFIG_ZBUS_PRIORITY_BOOST) + /* During the unlock phase, with the priority boost enabled, the priority must be + * restored to the original value in case it was elevated + */ + if (prio < ZBUS_MIN_THREAD_PRIORITY) { + k_thread_priority_set(k_current_get(), prio); + } +#endif /* CONFIG_ZBUS_PRIORITY_BOOST */ +} + int zbus_chan_pub(const struct zbus_channel *chan, const void *msg, k_timeout_t timeout) { int err; - _ZBUS_ASSERT(!k_is_in_isr(), "zbus cannot be used inside ISRs"); _ZBUS_ASSERT(chan != NULL, "chan is required"); _ZBUS_ASSERT(msg != NULL, "msg is required"); + if (k_is_in_isr()) { + timeout = K_NO_WAIT; + } + k_timepoint_t end_time = sys_timepoint_calc(timeout); if (chan->validator != NULL && !chan->validator(msg, chan->message_size)) { return -ENOMSG; } - err = k_mutex_lock(&chan->data->mutex, timeout); + int context_priority = ZBUS_MIN_THREAD_PRIORITY; + + err = chan_lock(chan, timeout, &context_priority); if (err) { return err; } @@ -214,56 +371,67 @@ int zbus_chan_pub(const struct zbus_channel *chan, const void *msg, k_timeout_t err = _zbus_vded_exec(chan, end_time); - k_mutex_unlock(&chan->data->mutex); + chan_unlock(chan, context_priority); return err; } int zbus_chan_read(const struct zbus_channel *chan, void *msg, k_timeout_t timeout) { - int err; - - _ZBUS_ASSERT(!k_is_in_isr(), "zbus cannot be used inside ISRs"); _ZBUS_ASSERT(chan != NULL, "chan is required"); _ZBUS_ASSERT(msg != NULL, "msg is required"); - err = k_mutex_lock(&chan->data->mutex, timeout); + if (k_is_in_isr()) { + timeout = K_NO_WAIT; + } + + int err = k_sem_take(&chan->data->sem, timeout); if (err) { return err; } memcpy(msg, chan->message, chan->message_size); - return k_mutex_unlock(&chan->data->mutex); + k_sem_give(&chan->data->sem); + + return 0; } int zbus_chan_notify(const struct zbus_channel *chan, k_timeout_t timeout) { int err; - _ZBUS_ASSERT(!k_is_in_isr(), "zbus cannot be used inside ISRs"); _ZBUS_ASSERT(chan != NULL, "chan is required"); + if (k_is_in_isr()) { + timeout = K_NO_WAIT; + } + k_timepoint_t end_time = sys_timepoint_calc(timeout); - err = k_mutex_lock(&chan->data->mutex, timeout); + int context_priority = ZBUS_MIN_THREAD_PRIORITY; + + err = chan_lock(chan, timeout, &context_priority); if (err) { return err; } err = _zbus_vded_exec(chan, end_time); - k_mutex_unlock(&chan->data->mutex); + chan_unlock(chan, context_priority); return err; } int zbus_chan_claim(const struct zbus_channel *chan, k_timeout_t timeout) { - _ZBUS_ASSERT(!k_is_in_isr(), "zbus cannot be used inside ISRs"); _ZBUS_ASSERT(chan != NULL, "chan is required"); - int err = k_mutex_lock(&chan->data->mutex, timeout); + if (k_is_in_isr()) { + timeout = K_NO_WAIT; + } + + int err = k_sem_take(&chan->data->sem, timeout); if (err) { return err; @@ -274,18 +442,17 @@ int zbus_chan_claim(const struct zbus_channel *chan, k_timeout_t timeout) int zbus_chan_finish(const struct zbus_channel *chan) { - _ZBUS_ASSERT(!k_is_in_isr(), "zbus cannot be used inside ISRs"); _ZBUS_ASSERT(chan != NULL, "chan is required"); - int err = k_mutex_unlock(&chan->data->mutex); + k_sem_give(&chan->data->sem); - return err; + return 0; } int zbus_sub_wait(const struct zbus_observer *sub, const struct zbus_channel **chan, k_timeout_t timeout) { - _ZBUS_ASSERT(!k_is_in_isr(), "zbus cannot be used inside ISRs"); + _ZBUS_ASSERT(!k_is_in_isr(), "zbus_sub_wait cannot be used inside ISRs"); _ZBUS_ASSERT(sub != NULL, "sub is required"); _ZBUS_ASSERT(sub->type == ZBUS_OBSERVER_SUBSCRIBER_TYPE, "sub must be a SUBSCRIBER"); _ZBUS_ASSERT(sub->queue != NULL, "sub queue is required"); @@ -299,7 +466,7 @@ int zbus_sub_wait(const struct zbus_observer *sub, const struct zbus_channel **c int zbus_sub_wait_msg(const struct zbus_observer *sub, const struct zbus_channel **chan, void *msg, k_timeout_t timeout) { - _ZBUS_ASSERT(!k_is_in_isr(), "zbus subscribers cannot be used inside ISRs"); + _ZBUS_ASSERT(!k_is_in_isr(), "zbus_sub_wait_msg cannot be used inside ISRs"); _ZBUS_ASSERT(sub != NULL, "sub is required"); _ZBUS_ASSERT(sub->type == ZBUS_OBSERVER_MSG_SUBSCRIBER_TYPE, "sub must be a MSG_SUBSCRIBER"); @@ -330,22 +497,35 @@ int zbus_obs_set_chan_notification_mask(const struct zbus_observer *obs, _ZBUS_ASSERT(obs != NULL, "obs is required"); _ZBUS_ASSERT(chan != NULL, "chan is required"); + int err = -ESRCH; + struct zbus_channel_observation *observation; struct zbus_channel_observation_mask *observation_mask; - for (int16_t i = chan->data->observers_start_idx, limit = chan->data->observers_end_idx; - i < limit; ++i) { - STRUCT_SECTION_GET(zbus_channel_observation, i, &observation); - STRUCT_SECTION_GET(zbus_channel_observation_mask, i, &observation_mask); + K_SPINLOCK(&obs_slock) { + for (int16_t i = chan->data->observers_start_idx, + limit = chan->data->observers_end_idx; + i < limit; ++i) { + STRUCT_SECTION_GET(zbus_channel_observation, i, &observation); + STRUCT_SECTION_GET(zbus_channel_observation_mask, i, &observation_mask); - _ZBUS_ASSERT(observation != NULL, "observation must be not NULL"); + __ASSERT(observation != NULL, "observation must be not NULL"); + + if (observation->obs == obs) { + if (observation_mask->enabled != masked) { + observation_mask->enabled = masked; - if (observation->obs == obs) { - observation_mask->enabled = masked; - return 0; + update_all_channels_hop(obs); + } + + err = 0; + + K_SPINLOCK_BREAK; + } } } - return -ESRCH; + + return err; } int zbus_obs_is_chan_notification_masked(const struct zbus_observer *obs, @@ -354,20 +534,44 @@ int zbus_obs_is_chan_notification_masked(const struct zbus_observer *obs, _ZBUS_ASSERT(obs != NULL, "obs is required"); _ZBUS_ASSERT(chan != NULL, "chan is required"); + int err = -ESRCH; + struct zbus_channel_observation *observation; struct zbus_channel_observation_mask *observation_mask; - for (int16_t i = chan->data->observers_start_idx, limit = chan->data->observers_end_idx; - i < limit; ++i) { - STRUCT_SECTION_GET(zbus_channel_observation, i, &observation); - STRUCT_SECTION_GET(zbus_channel_observation_mask, i, &observation_mask); + K_SPINLOCK(&obs_slock) { + const int limit = chan->data->observers_end_idx; - _ZBUS_ASSERT(observation != NULL, "observation must be not NULL"); + for (int16_t i = chan->data->observers_start_idx; i < limit; ++i) { + STRUCT_SECTION_GET(zbus_channel_observation, i, &observation); + STRUCT_SECTION_GET(zbus_channel_observation_mask, i, &observation_mask); - if (observation->obs == obs) { - *masked = observation_mask->enabled; - return 0; + __ASSERT(observation != NULL, "observation must be not NULL"); + + if (observation->obs == obs) { + *masked = observation_mask->enabled; + + err = 0; + + K_SPINLOCK_BREAK; + } + } + } + + return err; +} + +int zbus_obs_set_enable(struct zbus_observer *obs, bool enabled) +{ + _ZBUS_ASSERT(obs != NULL, "obs is required"); + + K_SPINLOCK(&obs_slock) { + if (obs->data->enabled != enabled) { + obs->data->enabled = enabled; + + update_all_channels_hop(obs); } } - return -ESRCH; + + return 0; } diff --git a/subsys/zbus/zbus_runtime_observers.c b/subsys/zbus/zbus_runtime_observers.c index 5fc47484dee..56c7cbb4530 100644 --- a/subsys/zbus/zbus_runtime_observers.c +++ b/subsys/zbus/zbus_runtime_observers.c @@ -19,7 +19,7 @@ int zbus_chan_add_obs(const struct zbus_channel *chan, const struct zbus_observe _ZBUS_ASSERT(chan != NULL, "chan is required"); _ZBUS_ASSERT(obs != NULL, "obs is required"); - err = k_mutex_lock(&chan->data->mutex, timeout); + err = k_sem_take(&chan->data->sem, timeout); if (err) { return err; } @@ -31,7 +31,7 @@ int zbus_chan_add_obs(const struct zbus_channel *chan, const struct zbus_observe __ASSERT(observation != NULL, "observation must be not NULL"); if (observation->obs == obs) { - k_mutex_unlock(&chan->data->mutex); + k_sem_give(&chan->data->sem); return -EEXIST; } @@ -40,7 +40,7 @@ int zbus_chan_add_obs(const struct zbus_channel *chan, const struct zbus_observe /* Check if the observer is already a runtime observer */ SYS_SLIST_FOR_EACH_CONTAINER_SAFE(&chan->data->observers, obs_nd, tmp, node) { if (obs_nd->obs == obs) { - k_mutex_unlock(&chan->data->mutex); + k_sem_give(&chan->data->sem); return -EALREADY; } @@ -51,7 +51,7 @@ int zbus_chan_add_obs(const struct zbus_channel *chan, const struct zbus_observe if (new_obs_nd == NULL) { LOG_ERR("Could not allocate observer node the heap is full!"); - k_mutex_unlock(&chan->data->mutex); + k_sem_give(&chan->data->sem); return -ENOMEM; } @@ -60,7 +60,7 @@ int zbus_chan_add_obs(const struct zbus_channel *chan, const struct zbus_observe sys_slist_append(&chan->data->observers, &new_obs_nd->node); - k_mutex_unlock(&chan->data->mutex); + k_sem_give(&chan->data->sem); return 0; } @@ -76,7 +76,7 @@ int zbus_chan_rm_obs(const struct zbus_channel *chan, const struct zbus_observer _ZBUS_ASSERT(chan != NULL, "chan is required"); _ZBUS_ASSERT(obs != NULL, "obs is required"); - err = k_mutex_lock(&chan->data->mutex, timeout); + err = k_sem_take(&chan->data->sem, timeout); if (err) { return err; } @@ -87,7 +87,7 @@ int zbus_chan_rm_obs(const struct zbus_channel *chan, const struct zbus_observer k_free(obs_nd); - k_mutex_unlock(&chan->data->mutex); + k_sem_give(&chan->data->sem); return 0; } @@ -95,7 +95,7 @@ int zbus_chan_rm_obs(const struct zbus_channel *chan, const struct zbus_observer prev_obs_nd = obs_nd; } - k_mutex_unlock(&chan->data->mutex); + k_sem_give(&chan->data->sem); return -ENODATA; } From 73f0bcc7fc811437df5082e5170ee845bd3dd942 Mon Sep 17 00:00:00 2001 From: Rodrigo Peixoto Date: Wed, 27 Sep 2023 16:52:54 -0300 Subject: [PATCH 1691/3723] tests: zbus: fix unit tests to work with priority boost The test considers using zbus inside ISR. Signed-off-by: Rodrigo Peixoto --- tests/subsys/zbus/unittests/src/main.c | 96 ++++++++++++++++++----- tests/subsys/zbus/unittests/testcase.yaml | 9 ++- 2 files changed, 83 insertions(+), 22 deletions(-) diff --git a/tests/subsys/zbus/unittests/src/main.c b/tests/subsys/zbus/unittests/src/main.c index 7c3ff76230a..2e92dc633ba 100644 --- a/tests/subsys/zbus/unittests/src/main.c +++ b/tests/subsys/zbus/unittests/src/main.c @@ -211,9 +211,9 @@ static void wq_dh_cb(struct k_work *item) { struct action_msg a = {0}; - zassert_equal(-EBUSY, zbus_chan_pub(&aux2_chan, &a, K_NO_WAIT), "It must not be valid"); + zassert_equal(-EBUSY, zbus_chan_pub(&aux2_chan, &a, K_NO_WAIT), "It must not be invalid"); - zassert_equal(-EBUSY, zbus_chan_read(&aux2_chan, &a, K_NO_WAIT), "It must not be valid"); + zassert_equal(-EBUSY, zbus_chan_read(&aux2_chan, &a, K_NO_WAIT), "It must not be invalid"); zassert_equal(-EBUSY, zbus_chan_notify(&aux2_chan, K_NO_WAIT), "It must not be invalid"); @@ -223,13 +223,24 @@ static void wq_dh_cb(struct k_work *item) ZBUS_SUBSCRIBER_DEFINE(sub1, 1); ZBUS_MSG_SUBSCRIBER_DEFINE_WITH_ENABLE(foo_msg_sub, false); ZBUS_MSG_SUBSCRIBER_DEFINE_WITH_ENABLE(foo2_msg_sub, false); + static K_FIFO_DEFINE(_zbus_observer_fifo_invalid_obs); + +/* clang-format off */ +static struct zbus_observer_data _zbus_obs_data_invalid_obs = { + .enabled = false, + IF_ENABLED(CONFIG_ZBUS_PRIORITY_BOOST, ( + .priority = ATOMIC_INIT(CONFIG_NUM_PREEMPT_PRIORITIES - 1) + )) +}; + STRUCT_SECTION_ITERABLE(zbus_observer, invalid_obs) = { ZBUS_OBSERVER_NAME_INIT(invalid_obs) /* Name field */ - .type = ZBUS_OBSERVER_MSG_SUBSCRIBER_TYPE + 10, - .enabled = false, - .message_fifo = &_zbus_observer_fifo_invalid_obs, + .type = ZBUS_OBSERVER_MSG_SUBSCRIBER_TYPE + 10, + .data = &_zbus_obs_data_invalid_obs, + .message_fifo = &_zbus_observer_fifo_invalid_obs }; +/* clang-format on */ ZTEST(basic, test_specification_based__zbus_chan) { @@ -283,11 +294,11 @@ ZTEST(basic, test_specification_based__zbus_chan) k_msleep(100); - zassert_equal(0, zbus_chan_pub(&aux2_chan, &a, K_NO_WAIT), "It must not be valid"); + zassert_equal(-EBUSY, zbus_chan_pub(&aux2_chan, &a, K_NO_WAIT), "It must not be valid"); - zassert_equal(0, zbus_chan_read(&aux2_chan, &a, K_NO_WAIT), "It must not be valid"); + zassert_equal(-EBUSY, zbus_chan_read(&aux2_chan, &a, K_NO_WAIT), "It must not be valid"); - zassert_equal(0, zbus_chan_notify(&aux2_chan, K_NO_WAIT), "It must not be invalid"); + zassert_equal(-EBUSY, zbus_chan_notify(&aux2_chan, K_NO_WAIT), "It must not be invalid"); zassert_equal(0, zbus_chan_finish(&aux2_chan), "It must finish correctly"); @@ -324,15 +335,16 @@ ZTEST(basic, test_specification_based__zbus_chan) "the msgq"); /* Trying to call the zbus functions in a ISR context. None must work */ - ISR_OP(PUB_ISR, -EFAULT); - ISR_OP(PUB_ISR_INVAL, -EFAULT); - ISR_OP(READ_ISR, -EFAULT); - ISR_OP(READ_ISR_INVAL, -EFAULT); - ISR_OP(NOTIFY_ISR, -EFAULT); - ISR_OP(NOTIFY_ISR_INVAL, -EFAULT); - ISR_OP(CLAIM_ISR, -EFAULT); - ISR_OP(CLAIM_ISR_INVAL, -EFAULT); - ISR_OP(FINISH_ISR, -EFAULT); + ISR_OP(PUB_ISR, 0); + ISR_OP(PUB_ISR_INVAL, 0); + ISR_OP(READ_ISR, 0); + ISR_OP(READ_ISR_INVAL, 0); + ISR_OP(NOTIFY_ISR, 0); + ISR_OP(NOTIFY_ISR_INVAL, 0); + ISR_OP(CLAIM_ISR, 0); + ISR_OP(FINISH_ISR, 0); + ISR_OP(CLAIM_ISR_INVAL, 0); + ISR_OP(FINISH_ISR, 0); ISR_OP(FINISH_ISR_INVAL, -EFAULT); ISR_OP(ADD_OBS_ISR, -EFAULT); ISR_OP(ADD_OBS_ISR_INVAL, -EFAULT); @@ -700,10 +712,22 @@ ZTEST(basic, test_specification_based__zbus_obs_set_chan_notification_mask) ZBUS_SUBSCRIBER_DEFINE(foo_sub, 1); -STRUCT_SECTION_ITERABLE(zbus_observer, - invalid_sub) = {ZBUS_OBSERVER_NAME_INIT(invalid_sub) /* Name field */ - .type = ZBUS_OBSERVER_SUBSCRIBER_TYPE, - .enabled = false, .queue = NULL}; +/* clang-format off */ +static struct zbus_observer_data _zbus_obs_data_invalid_sub = { + .enabled = false, + IF_ENABLED(CONFIG_ZBUS_PRIORITY_BOOST, ( + .priority = ATOMIC_INIT(CONFIG_NUM_PREEMPT_PRIORITIES - 1) + )) +}; + +STRUCT_SECTION_ITERABLE(zbus_observer, invalid_sub) = { + ZBUS_OBSERVER_NAME_INIT(invalid_sub) /* Name field */ + .type = ZBUS_OBSERVER_SUBSCRIBER_TYPE, + .data = &_zbus_obs_data_invalid_sub, + .queue = NULL +}; +/* clang-format on */ + static void isr_sub_wait(const void *operation) { const struct zbus_channel *chan; @@ -760,4 +784,34 @@ ZTEST(basic, test_specification_based__zbus_sub_wait_msg) irq_offload(isr_sub_wait_msg, NULL); } +#if defined(CONFIG_ZBUS_PRIORITY_BOOST) +static void isr_obs_attach_detach(const void *operation) +{ + zassert_equal(-EFAULT, zbus_obs_attach_to_thread(NULL), NULL); + zassert_equal(-EFAULT, zbus_obs_attach_to_thread(&foo_sub), NULL); + zassert_equal(-EFAULT, zbus_obs_attach_to_thread(&invalid_sub), NULL); + + zassert_equal(-EFAULT, zbus_obs_detach_from_thread(NULL), NULL); + zassert_equal(-EFAULT, zbus_obs_detach_from_thread(&foo_sub), NULL); + zassert_equal(-EFAULT, zbus_obs_detach_from_thread(&invalid_sub), NULL); +} + +ZTEST(basic, test_specification_based__zbus_obs_attach_detach) +{ + zassert_equal(-EFAULT, zbus_obs_attach_to_thread(NULL), NULL); + zassert_equal(0, zbus_obs_attach_to_thread(&foo_sub), NULL); + zassert_equal(0, zbus_obs_detach_from_thread(&foo_sub), NULL); + zassert_equal(0, zbus_obs_attach_to_thread(&invalid_sub), NULL); + zassert_equal(0, zbus_obs_detach_from_thread(&invalid_sub), NULL); + zassert_equal(-EFAULT, zbus_obs_detach_from_thread(NULL), NULL); + + irq_offload(isr_obs_attach_detach, NULL); +} +#else +ZTEST(basic, test_specification_based__zbus_obs_attach_detach) +{ + ztest_test_skip(); +} +#endif + ZTEST_SUITE(basic, NULL, NULL, NULL, NULL, NULL); diff --git a/tests/subsys/zbus/unittests/testcase.yaml b/tests/subsys/zbus/unittests/testcase.yaml index 342bfd5f30f..6b7076cb680 100644 --- a/tests/subsys/zbus/unittests/testcase.yaml +++ b/tests/subsys/zbus/unittests/testcase.yaml @@ -1,6 +1,13 @@ tests: - message_bus.zbus.hard_and_readonly_channels: + message_bus.zbus.general_unittests: platform_exclude: fvp_base_revc_2xaemv8a_smp_ns tags: zbus integration_platforms: - native_sim + message_bus.zbus.general_unittests_without_priority_boost: + platform_exclude: fvp_base_revc_2xaemv8a_smp_ns + tags: zbus + integration_platforms: + - native_sim + extra_configs: + - CONFIG_ZBUS_PRIORITY_BOOST=n From fb7515e27b8bd76caf6b671aa400a3a29a1099b6 Mon Sep 17 00:00:00 2001 From: Rodrigo Peixoto Date: Wed, 27 Sep 2023 16:49:49 -0300 Subject: [PATCH 1692/3723] samples: zbus: fix samples to work with priority boost Adjust the sample to work with the priority boost. It illustrates zbus being used inside an ISR instead of into the main function. Signed-off-by: Rodrigo Peixoto --- samples/subsys/zbus/msg_subscriber/src/main.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/samples/subsys/zbus/msg_subscriber/src/main.c b/samples/subsys/zbus/msg_subscriber/src/main.c index 16022b011de..aa5bb42c4f1 100644 --- a/samples/subsys/zbus/msg_subscriber/src/main.c +++ b/samples/subsys/zbus/msg_subscriber/src/main.c @@ -154,9 +154,9 @@ static void subscriber_task(void *sub) } K_THREAD_DEFINE(subscriber_task_id17, CONFIG_MAIN_STACK_SIZE, subscriber_task, &bar_sub1, NULL, - NULL, 3, 0, 0); + NULL, 2, 0, 0); K_THREAD_DEFINE(subscriber_task_id18, CONFIG_MAIN_STACK_SIZE, subscriber_task, &bar_sub2, NULL, - NULL, 3, 0, 0); + NULL, 4, 0, 0); ZBUS_CHAN_ADD_OBS(acc_data_chan, bar_sub2, 3); ZBUS_CHAN_ADD_OBS(acc_data_chan, bar_msg_sub10, 3); @@ -167,9 +167,10 @@ ZBUS_CHAN_ADD_OBS(acc_data_chan, bar_msg_sub14, 3); ZBUS_CHAN_ADD_OBS(acc_data_chan, bar_msg_sub15, 3); ZBUS_CHAN_ADD_OBS(acc_data_chan, bar_msg_sub16, 3); +static struct acc_msg acc = {.x = 1, .y = 10, .z = 100}; + int main(void) { - struct acc_msg acc = {.x = 1, .y = 10, .z = 100}; total_allocated = 0; @@ -186,7 +187,6 @@ int main(void) acc.x += 1; acc.y += 10; acc.z += 100; - k_msleep(1000); } From 2cfd28e5ca990ea2cf15c17373e016f68a2a5ba6 Mon Sep 17 00:00:00 2001 From: Rodrigo Peixoto Date: Thu, 7 Dec 2023 07:57:56 -0300 Subject: [PATCH 1693/3723] tests: zbus: add HLP priority boost tests Add the dedicated tests for HLP priority boost. Signed-off-by: Rodrigo Peixoto --- .../zbus/hlp_priority_boost/CMakeLists.txt | 8 + tests/subsys/zbus/hlp_priority_boost/prj.conf | 5 + .../subsys/zbus/hlp_priority_boost/src/main.c | 180 ++++++++++++++++++ .../zbus/hlp_priority_boost/src/messages.h | 20 ++ .../zbus/hlp_priority_boost/testcase.yaml | 6 + 5 files changed, 219 insertions(+) create mode 100644 tests/subsys/zbus/hlp_priority_boost/CMakeLists.txt create mode 100644 tests/subsys/zbus/hlp_priority_boost/prj.conf create mode 100644 tests/subsys/zbus/hlp_priority_boost/src/main.c create mode 100644 tests/subsys/zbus/hlp_priority_boost/src/messages.h create mode 100644 tests/subsys/zbus/hlp_priority_boost/testcase.yaml diff --git a/tests/subsys/zbus/hlp_priority_boost/CMakeLists.txt b/tests/subsys/zbus/hlp_priority_boost/CMakeLists.txt new file mode 100644 index 00000000000..cdfe01e1715 --- /dev/null +++ b/tests/subsys/zbus/hlp_priority_boost/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(test_user_data) + +FILE(GLOB app_sources src/*.c) +target_sources(app PRIVATE ${app_sources}) diff --git a/tests/subsys/zbus/hlp_priority_boost/prj.conf b/tests/subsys/zbus/hlp_priority_boost/prj.conf new file mode 100644 index 00000000000..23dc9572a10 --- /dev/null +++ b/tests/subsys/zbus/hlp_priority_boost/prj.conf @@ -0,0 +1,5 @@ +CONFIG_ZTEST=y +CONFIG_ASSERT=y +CONFIG_ZBUS=y +CONFIG_ZBUS_MSG_SUBSCRIBER=y +CONFIG_HEAP_MEM_POOL_SIZE=1024 diff --git a/tests/subsys/zbus/hlp_priority_boost/src/main.c b/tests/subsys/zbus/hlp_priority_boost/src/main.c new file mode 100644 index 00000000000..fb5dca3e961 --- /dev/null +++ b/tests/subsys/zbus/hlp_priority_boost/src/main.c @@ -0,0 +1,180 @@ +/* + * Copyright (c) 2023 Rodrigo Peixoto + * SPDX-License-Identifier: Apache-2.0 + */ + +#include "messages.h" + +#include +#include +#include +#include +LOG_MODULE_DECLARE(zbus, CONFIG_ZBUS_LOG_LEVEL); + +#define STACK_SIZE (CONFIG_MAIN_STACK_SIZE + CONFIG_TEST_EXTRA_STACK_SIZE) + +static struct k_thread pub_thread; +static K_THREAD_STACK_DEFINE(pub_thread_sz, STACK_SIZE); +static struct k_thread s1_thread; +static K_THREAD_STACK_DEFINE(s1_thread_sz, STACK_SIZE); +static struct k_thread ms1_thread; +static K_THREAD_STACK_DEFINE(ms1_thread_sz, STACK_SIZE); + +struct msg_testing_01 { + int seq; + bool must_detach; +}; + +ZBUS_CHAN_DEFINE(chan_testing_01, /* Name */ + struct msg_testing_01, /* Message type */ + + NULL, /* Validator */ + NULL, /* User data */ + ZBUS_OBSERVERS(lis1, sub1, msub1), /* observers */ + ZBUS_MSG_INIT(0) /* Initial value major 0, minor 1, build 1023 */ +); + +static void consumer_sub_thread(void *ptr1, void *ptr2, void *ptr3) +{ + ARG_UNUSED(ptr3); + + zbus_obs_attach_to_thread(ptr1); + + char *name = ptr2; + struct zbus_observer *sub = ptr1; + const struct zbus_channel *chan; + struct msg_testing_01 msg; + + while (1) { + if (zbus_sub_wait(sub, &chan, K_FOREVER) != 0) { + k_oops(); + } + zbus_chan_read(chan, &msg, K_FOREVER); + + printk("%s level: %d\n", name, msg.seq); + + if (msg.must_detach) { + zbus_obs_detach_from_thread(sub); + } + } +} + +ZBUS_SUBSCRIBER_DEFINE(sub1, 4); + +static void consumer_msg_sub_thread(void *ptr1, void *ptr2, void *ptr3) +{ + ARG_UNUSED(ptr3); + + zbus_obs_attach_to_thread(ptr1); + + char *name = ptr2; + struct zbus_observer *msub = ptr1; + const struct zbus_channel *chan; + struct msg_testing_01 msg; + + while (1) { + if (zbus_sub_wait_msg(msub, &chan, &msg, K_FOREVER) != 0) { + k_oops(); + } + printk("%s level: %d\n", name, msg.seq); + + if (msg.must_detach) { + zbus_obs_detach_from_thread(msub); + } + } +} + +ZBUS_MSG_SUBSCRIBER_DEFINE(msub1); + +static K_SEM_DEFINE(sync_sem, 1, 1); +static K_SEM_DEFINE(done_sem, 0, 1); + +static struct msg_testing_01 msg = {.seq = 0}; + +static void publisher_thread(void *ptr1, void *ptr2, void *ptr3) +{ + ARG_UNUSED(ptr1); + ARG_UNUSED(ptr2); + ARG_UNUSED(ptr3); + + while (1) { + k_sem_take(&sync_sem, K_FOREVER); + zbus_chan_pub(&chan_testing_01, &msg, K_FOREVER); + k_msleep(100); + k_sem_give(&done_sem); + } +} + +static inline void _pub_and_sync(void) +{ + k_sem_give(&sync_sem); + k_sem_take(&done_sem, K_FOREVER); +} + +static k_tid_t pub_thread_id; + +static int prio; + +static void listener_callback(const struct zbus_channel *chan) +{ + prio = k_thread_priority_get(pub_thread_id); +} + +ZBUS_LISTENER_DEFINE(lis1, listener_callback); + +ZTEST(hlp_priority_boost, test_priority_elevation) +{ + pub_thread_id = k_thread_create(&pub_thread, pub_thread_sz, STACK_SIZE, publisher_thread, + NULL, NULL, NULL, K_PRIO_PREEMPT(8), 0, K_NO_WAIT); + (void)k_thread_create(&s1_thread, s1_thread_sz, STACK_SIZE, consumer_sub_thread, &sub1, + "sub1", NULL, K_PRIO_PREEMPT(3), 0, K_NO_WAIT); + (void)k_thread_create(&ms1_thread, ms1_thread_sz, STACK_SIZE, consumer_msg_sub_thread, + &msub1, "msub1", NULL, K_PRIO_PREEMPT(2), 0, K_NO_WAIT); + + _pub_and_sync(); + zassert_true(prio == 1, "The priority must be 1, but it is %d", prio); + + ++msg.seq; + + zbus_obs_set_enable(&msub1, false); + _pub_and_sync(); + zassert_true(prio == 2, "The priority must be 2, but it is %d", prio); + zbus_obs_set_enable(&msub1, true); + + ++msg.seq; + + _pub_and_sync(); + zassert_true(prio == 1, "The priority must be 1, but it is %d", prio); + + ++msg.seq; + + zbus_obs_set_chan_notification_mask(&msub1, &chan_testing_01, true); + bool is_masked; + + zbus_obs_is_chan_notification_masked(&msub1, &chan_testing_01, &is_masked); + zassert_true(is_masked, NULL); + _pub_and_sync(); + zassert_true(prio == 2, "The priority must be 2, but it is %d", prio); + zbus_obs_set_chan_notification_mask(&msub1, &chan_testing_01, false); + + ++msg.seq; + + zbus_obs_set_enable(&msub1, false); + zbus_obs_set_enable(&sub1, false); + _pub_and_sync(); + zassert_true(prio == 8, "The priority must be 8, but it is %d", prio); + zbus_obs_set_chan_notification_mask(&msub1, &chan_testing_01, false); + zbus_obs_set_enable(&msub1, true); + zbus_obs_set_enable(&sub1, true); + + ++msg.seq; + msg.must_detach = true; + _pub_and_sync(); + zassert_true(prio == 1, "The priority must be 1, but it is %d", prio); + ++msg.seq; + /* Checking if the detach command took effect on both observers */ + _pub_and_sync(); + zassert_true(prio == 8, "The priority must be 8, but it is %d", prio); +} + +ZTEST_SUITE(hlp_priority_boost, NULL, NULL, NULL, NULL, NULL); diff --git a/tests/subsys/zbus/hlp_priority_boost/src/messages.h b/tests/subsys/zbus/hlp_priority_boost/src/messages.h new file mode 100644 index 00000000000..9e15469e5ed --- /dev/null +++ b/tests/subsys/zbus/hlp_priority_boost/src/messages.h @@ -0,0 +1,20 @@ +/* + * Copyright (c) 2022 Rodrigo Peixoto + * SPDX-License-Identifier: Apache-2.0 + */ +#ifndef _ZBUS_MESSAGES_H_ +#define _ZBUS_MESSAGES_H_ +#include + +struct version_msg { + uint8_t major; + uint8_t minor; + uint16_t build; +}; + +struct foo_msg { + int a; + int b; +}; + +#endif /* _ZBUS_MESSAGES_H_ */ diff --git a/tests/subsys/zbus/hlp_priority_boost/testcase.yaml b/tests/subsys/zbus/hlp_priority_boost/testcase.yaml new file mode 100644 index 00000000000..f83e54f59e9 --- /dev/null +++ b/tests/subsys/zbus/hlp_priority_boost/testcase.yaml @@ -0,0 +1,6 @@ +tests: + message_bus.zbus.hlp_priority_boost: + platform_exclude: fvp_base_revc_2xaemv8a_smp_ns + tags: zbus + integration_platforms: + - native_sim From 01981910ec2a3776ca5bb98ea5ffe8ff75e90db0 Mon Sep 17 00:00:00 2001 From: Rodrigo Peixoto Date: Sun, 10 Dec 2023 15:01:41 -0300 Subject: [PATCH 1694/3723] samples: zbus: add priority boost sample to zbus This sample illustrates how to properly use zbus priority boost feature. Signed-off-by: Rodrigo Peixoto --- .../subsys/zbus/priority_boost/CMakeLists.txt | 8 + samples/subsys/zbus/priority_boost/README.rst | 197 ++++++++++++++++++ samples/subsys/zbus/priority_boost/prj.conf | 6 + .../subsys/zbus/priority_boost/sample.yaml | 81 +++++++ samples/subsys/zbus/priority_boost/src/main.c | 148 +++++++++++++ .../with_hlp_priority_boost_feature.svg | 75 +++++++ .../without_hlp_priority_boost_feature.svg | 67 ++++++ ...us_publishing_process_example_scenario.svg | 35 ++++ 8 files changed, 617 insertions(+) create mode 100644 samples/subsys/zbus/priority_boost/CMakeLists.txt create mode 100644 samples/subsys/zbus/priority_boost/README.rst create mode 100644 samples/subsys/zbus/priority_boost/prj.conf create mode 100644 samples/subsys/zbus/priority_boost/sample.yaml create mode 100644 samples/subsys/zbus/priority_boost/src/main.c create mode 100644 samples/subsys/zbus/priority_boost/with_hlp_priority_boost_feature.svg create mode 100644 samples/subsys/zbus/priority_boost/without_hlp_priority_boost_feature.svg create mode 100644 samples/subsys/zbus/priority_boost/zbus_publishing_process_example_scenario.svg diff --git a/samples/subsys/zbus/priority_boost/CMakeLists.txt b/samples/subsys/zbus/priority_boost/CMakeLists.txt new file mode 100644 index 00000000000..f2d9b727321 --- /dev/null +++ b/samples/subsys/zbus/priority_boost/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(priority_boost) + +file(GLOB app_sources src/*.c) +target_sources(app PRIVATE ${app_sources}) diff --git a/samples/subsys/zbus/priority_boost/README.rst b/samples/subsys/zbus/priority_boost/README.rst new file mode 100644 index 00000000000..ca903a7183c --- /dev/null +++ b/samples/subsys/zbus/priority_boost/README.rst @@ -0,0 +1,197 @@ +.. zephyr:code-sample:: zbus-priority-boost + :name: zbus Priority Boost + :relevant-api: zbus_apis + + Illustrates zbus priority boost feature with a priority inversion scenario. + +Overview +******** +This sample implements a simple application that illustrates the priority boost feature. The +application implements the below figure scenario. When the priority boost feature is disabled, the +execution sequence presents a priority inversion problem, which may not affect much of the +developer's application. Those who want to avoid priority inversions between message subscribers and +plain subscribers should use the priority boost strategy. + +.. code-block:: c + + ZBUS_CHAN_DEFINE(chan_a, + int, + NULL, + NULL, + ZBUS_OBSERVERS(l1, ms1, ms2, s1, l2), + 0 + ); + + +.. figure:: zbus_publishing_process_example_scenario.svg + :alt: ZBus priority boost scenario example. + :width: 45% + +.. note:: + + The developer must use the :c:func:`zbus_obs_attach_to_thread` function to ensure a proper + priority boost execution. + + +Building and Running +******************** + +The figure below illustrates the execution of the cited scenario but with the priority boost +disabled. + +.. figure:: without_hlp_priority_boost_feature.svg + :alt: ZBus example scenario for priority boost disabled. + :width: 70% + + +It can be built and executed on QEMU as follows: + +.. zephyr-app-commands:: + :zephyr-app: samples/subsys/zbus/priority_boost -- -DCONFIG_ZBUS_PRIORITY_BOOST=n + :host-os: unix + :board: qemu_x86 + :goals: run + +Sample Output +============= + +.. code-block:: console + + I: -------------- + I: 0 -> T1: prio before 5 + I: 0 ---> L1: T1 prio 5 + I: 0 -> MS1: T1 prio 5 + I: 0 -> MS2: T1 prio 5 + I: 0 ---> L2: T1 prio 5 + I: 0 -> T1: prio after 5 + I: N -> S1: T1 prio 5 + I: 0 -> S1: T1 prio 5 + I: -------------- + I: 1 -> T1: prio before 5 + I: 1 ---> L1: T1 prio 5 + I: 1 -> MS1: T1 prio 5 + I: 1 -> MS2: T1 prio 5 + I: 1 ---> L2: T1 prio 5 + I: 1 -> T1: prio after 5 + I: N -> S1: T1 prio 5 + I: 1 -> S1: T1 prio 5 + I: -------------- + I: 2 -> T1: prio before 5 + I: 2 ---> L1: T1 prio 5 + I: 2 -> MS1: T1 prio 5 + I: 2 ---> L2: T1 prio 5 + I: 2 -> T1: prio after 5 + I: 2 -> MS2: T1 prio 5 + I: -------------- + I: 3 -> T1: prio before 5 + I: 3 ---> L1: T1 prio 5 + I: 3 -> MS1: T1 prio 5 + I: 3 ---> L2: T1 prio 5 + I: 3 -> T1: prio after 5 + I: 3 -> MS2: T1 prio 5 + I: -------------- + I: 4 -> T1: prio before 5 + I: 4 ---> L1: T1 prio 5 + I: 4 ---> L2: T1 prio 5 + I: 4 -> T1: prio after 5 + I: 4 -> MS2: T1 prio 5 + I: -------------- + I: 5 -> T1: prio before 5 + I: 5 ---> L1: T1 prio 5 + I: 5 ---> L2: T1 prio 5 + I: 5 -> T1: prio after 5 + I: 5 -> MS2: T1 prio 5 + I: -------------- + I: 6 -> T1: prio before 5 + I: 6 ---> L1: T1 prio 5 + I: 6 -> MS1: T1 prio 5 + I: 6 -> MS2: T1 prio 5 + I: 6 ---> L2: T1 prio 5 + I: 6 -> T1: prio after 5 + I: N -> S1: T1 prio 5 + I: 6 -> S1: T1 prio 5 + I: -------------- + + + +Exit QEMU by pressing :kbd:`CTRL+A` :kbd:`x`. + + +The figure below illustrates the execution of the same scenario but with the priority boost enabled. +The developer must enable the priority boost and properly attach all the observers to their threads. + +.. figure:: with_hlp_priority_boost_feature.svg + :alt: ZBus example scenario for priority boost enabled. + :width: 75% + +To execute the sample with priority boost feature enabled, run the following command: + +.. zephyr-app-commands:: + :zephyr-app: samples/subsys/zbus/priority_boost -- -DCONFIG_ZBUS_PRIORITY_BOOST=y + :host-os: unix + :board: qemu_x86 + :goals: run + +Sample Output +============= + +.. code-block:: console + + I: -------------- + I: 0 -> T1: prio before 5 + I: 0 ---> L1: T1 prio 1 + I: 0 ---> L2: T1 prio 1 + I: N -> S1: T1 prio 5 + I: 0 -> S1: T1 prio 5 + I: 0 -> MS1: T1 prio 5 + I: 0 -> MS2: T1 prio 5 + I: 0 -> T1: prio after 5 + I: -------------- + I: 1 -> T1: prio before 5 + I: 1 ---> L1: T1 prio 1 + I: 1 ---> L2: T1 prio 1 + I: N -> S1: T1 prio 5 + I: 1 -> S1: T1 prio 5 + I: 1 -> MS1: T1 prio 5 + I: 1 -> MS2: T1 prio 5 + I: 1 -> T1: prio after 5 + I: -------------- + I: 2 -> T1: prio before 5 + I: 2 ---> L1: T1 prio 2 + I: 2 ---> L2: T1 prio 2 + I: 2 -> MS1: T1 prio 5 + I: 2 -> MS2: T1 prio 5 + I: 2 -> T1: prio after 5 + I: -------------- + I: 3 -> T1: prio before 5 + I: 3 ---> L1: T1 prio 2 + I: 3 ---> L2: T1 prio 2 + I: 3 -> MS1: T1 prio 5 + I: 3 -> MS2: T1 prio 5 + I: 3 -> T1: prio after 5 + I: -------------- + I: 4 -> T1: prio before 5 + I: 4 ---> L1: T1 prio 3 + I: 4 ---> L2: T1 prio 3 + I: 4 -> MS2: T1 prio 5 + I: 4 -> T1: prio after 5 + I: -------------- + I: 5 -> T1: prio before 5 + I: 5 ---> L1: T1 prio 3 + I: 5 ---> L2: T1 prio 3 + I: 5 -> MS2: T1 prio 5 + I: 5 -> T1: prio after 5 + I: -------------- + I: 6 -> T1: prio before 5 + I: 6 ---> L1: T1 prio 1 + I: 6 ---> L2: T1 prio 1 + I: N -> S1: T1 prio 5 + I: 6 -> S1: T1 prio 5 + I: 6 -> MS1: T1 prio 5 + I: 6 -> MS2: T1 prio 5 + I: 6 -> T1: prio after 5 + I: -------------- + + + +Exit QEMU by pressing :kbd:`CTRL+A` :kbd:`x`. diff --git a/samples/subsys/zbus/priority_boost/prj.conf b/samples/subsys/zbus/priority_boost/prj.conf new file mode 100644 index 00000000000..67af0befda1 --- /dev/null +++ b/samples/subsys/zbus/priority_boost/prj.conf @@ -0,0 +1,6 @@ +CONFIG_LOG=y +CONFIG_LOG_MODE_MINIMAL=y +CONFIG_ZBUS_LOG_LEVEL_INF=y +CONFIG_ZBUS=y +CONFIG_ZBUS_MSG_SUBSCRIBER=y +CONFIG_HEAP_MEM_POOL_SIZE=1024 diff --git a/samples/subsys/zbus/priority_boost/sample.yaml b/samples/subsys/zbus/priority_boost/sample.yaml new file mode 100644 index 00000000000..5bbdc772030 --- /dev/null +++ b/samples/subsys/zbus/priority_boost/sample.yaml @@ -0,0 +1,81 @@ +sample: + name: Priority boost +tests: + sample.zbus.non_priority_boost: + harness: console + harness_config: + type: multi_line + ordered: false + regex: + - "I: 0 -> T1: prio before 5" + - "I: 0 ---> L1: T1 prio 5" + - "I: 0 ---> L2: T1 prio 5" + - "I: 0 -> T1: prio after 5" + - "I: 1 -> T1: prio before 5" + - "I: 1 ---> L1: T1 prio 5" + - "I: 1 ---> L2: T1 prio 5" + - "I: 1 -> T1: prio after 5" + - "I: 2 -> T1: prio before 5" + - "I: 2 ---> L1: T1 prio 5" + - "I: 2 ---> L2: T1 prio 5" + - "I: 2 -> T1: prio after 5" + - "I: 3 -> T1: prio before 5" + - "I: 3 ---> L1: T1 prio 5" + - "I: 3 ---> L2: T1 prio 5" + - "I: 3 -> T1: prio after 5" + - "I: 4 -> T1: prio before 5" + - "I: 4 ---> L1: T1 prio 5" + - "I: 4 ---> L2: T1 prio 5" + - "I: 4 -> T1: prio after 5" + - "I: 5 -> T1: prio before 5" + - "I: 5 ---> L1: T1 prio 5" + - "I: 5 ---> L2: T1 prio 5" + - "I: 5 -> T1: prio after 5" + - "I: 6 -> T1: prio before 5" + - "I: 6 ---> L1: T1 prio 5" + - "I: 6 ---> L2: T1 prio 5" + - "I: 6 -> T1: prio after 5" + extra_configs: + - CONFIG_ZBUS_PRIORITY_BOOST=n + tags: zbus + integration_platforms: + - qemu_x86 + sample.zbus.priority_boost: + harness: console + harness_config: + type: multi_line + ordered: false + regex: + - "I: 0 -> T1: prio before 5" + - "I: 0 ---> L1: T1 prio 1" + - "I: 0 ---> L2: T1 prio 1" + - "I: 0 -> T1: prio after 5" + - "I: 1 -> T1: prio before 5" + - "I: 1 ---> L1: T1 prio 1" + - "I: 1 ---> L2: T1 prio 1" + - "I: 1 -> T1: prio after 5" + - "I: 2 -> T1: prio before 5" + - "I: 2 ---> L1: T1 prio 2" + - "I: 2 ---> L2: T1 prio 2" + - "I: 2 -> T1: prio after 5" + - "I: 3 -> T1: prio before 5" + - "I: 3 ---> L1: T1 prio 2" + - "I: 3 ---> L2: T1 prio 2" + - "I: 3 -> T1: prio after 5" + - "I: 4 -> T1: prio before 5" + - "I: 4 ---> L1: T1 prio 3" + - "I: 4 ---> L2: T1 prio 3" + - "I: 4 -> T1: prio after 5" + - "I: 5 -> T1: prio before 5" + - "I: 5 ---> L1: T1 prio 3" + - "I: 5 ---> L2: T1 prio 3" + - "I: 5 -> T1: prio after 5" + - "I: 6 -> T1: prio before 5" + - "I: 6 ---> L1: T1 prio 1" + - "I: 6 ---> L2: T1 prio 1" + - "I: 6 -> T1: prio after 5" + extra_configs: + - CONFIG_ZBUS_PRIORITY_BOOST=y + tags: zbus + integration_platforms: + - qemu_x86 diff --git a/samples/subsys/zbus/priority_boost/src/main.c b/samples/subsys/zbus/priority_boost/src/main.c new file mode 100644 index 00000000000..b54a44468c2 --- /dev/null +++ b/samples/subsys/zbus/priority_boost/src/main.c @@ -0,0 +1,148 @@ +/* + * Copyright (c) 2023 Rodrigo Peixoto + * SPDX-License-Identifier: Apache-2.0 + */ + +#include +#include +#include +LOG_MODULE_DECLARE(zbus, CONFIG_ZBUS_LOG_LEVEL); + +ZBUS_CHAN_DEFINE(chan_a, int, NULL, NULL, ZBUS_OBSERVERS(l1, ms1, ms2, s1, l2), 0); + +static void t1_thread(void *ptr1, void *ptr2, void *ptr3); +K_THREAD_DEFINE(t1_id, CONFIG_MAIN_STACK_SIZE, t1_thread, NULL, NULL, NULL, 5, 0, 0); + +ZBUS_SUBSCRIBER_DEFINE(s1, 4); +static void s1_thread(void *ptr1, void *ptr2, void *ptr3) +{ + ARG_UNUSED(ptr1); + ARG_UNUSED(ptr2); + ARG_UNUSED(ptr3); + + int err; + int a = 0; + const struct zbus_channel *chan; + + IF_ENABLED(CONFIG_ZBUS_PRIORITY_BOOST, (zbus_obs_attach_to_thread(&s1);)); + + while (1) { + err = zbus_sub_wait(&s1, &chan, K_FOREVER); + if (err) { + return; + } + + /* Faking some workload */ + k_busy_wait(200000); + + LOG_INF("N -> S1: T1 prio %d", k_thread_priority_get(t1_id)); + + err = zbus_chan_read(chan, &a, K_FOREVER); + if (err) { + return; + } + LOG_INF("%d -> S1: T1 prio %d", a, k_thread_priority_get(t1_id)); + } +} +K_THREAD_DEFINE(s1_id, CONFIG_MAIN_STACK_SIZE, s1_thread, NULL, NULL, NULL, 2, 0, 0); + +ZBUS_MSG_SUBSCRIBER_DEFINE(ms1); +static void ms1_thread(void *ptr1, void *ptr2, void *ptr3) +{ + ARG_UNUSED(ptr1); + ARG_UNUSED(ptr2); + ARG_UNUSED(ptr3); + + int err; + const struct zbus_channel *chan; + int a = 0; + + IF_ENABLED(CONFIG_ZBUS_PRIORITY_BOOST, (zbus_obs_attach_to_thread(&ms1);)); + + while (1) { + err = zbus_sub_wait_msg(&ms1, &chan, &a, K_FOREVER); + if (err) { + return; + } + + /* Faking some workload */ + k_busy_wait(200000); + + LOG_INF("%d -> MS1: T1 prio %d", a, k_thread_priority_get(t1_id)); + } +} +K_THREAD_DEFINE(ms1_id, CONFIG_MAIN_STACK_SIZE, ms1_thread, NULL, NULL, NULL, 3, 0, 0); + +ZBUS_MSG_SUBSCRIBER_DEFINE(ms2); +static void ms2_thread(void *ptr1, void *ptr2, void *ptr3) +{ + ARG_UNUSED(ptr1); + ARG_UNUSED(ptr2); + ARG_UNUSED(ptr3); + + int err; + const struct zbus_channel *chan; + int a = 0; + + IF_ENABLED(CONFIG_ZBUS_PRIORITY_BOOST, (zbus_obs_attach_to_thread(&ms2);)); + + while (1) { + err = zbus_sub_wait_msg(&ms2, &chan, &a, K_FOREVER); + if (err) { + return; + } + + /* Faking some workload */ + k_busy_wait(200 * USEC_PER_MSEC); + + LOG_INF("%d -> MS2: T1 prio %d", a, k_thread_priority_get(t1_id)); + } +} +K_THREAD_DEFINE(ms2_id, CONFIG_MAIN_STACK_SIZE, ms2_thread, NULL, NULL, NULL, 4, 0, 0); + +static void l1_callback(const struct zbus_channel *chan) +{ + LOG_INF("%d ---> L1: T1 prio %d", *((int *)zbus_chan_const_msg(chan)), + k_thread_priority_get(t1_id)); +} +ZBUS_LISTENER_DEFINE(l1, l1_callback); + +static void l2_callback(const struct zbus_channel *chan) +{ + LOG_INF("%d ---> L2: T1 prio %d", *((int *)zbus_chan_const_msg(chan)), + k_thread_priority_get(t1_id)); +} +ZBUS_LISTENER_DEFINE(l2, l2_callback); + +static void t1_thread(void *ptr1, void *ptr2, void *ptr3) +{ + ARG_UNUSED(ptr1); + ARG_UNUSED(ptr2); + ARG_UNUSED(ptr3); + + int err; + int a = 0; + + while (1) { + LOG_INF("--------------"); + + if (a == 2) { + zbus_obs_set_enable(&s1, false); + } else if (a == 4) { + zbus_obs_set_enable(&ms1, false); + } else if (a == 6) { + zbus_obs_set_enable(&s1, true); + zbus_obs_set_enable(&ms1, true); + } + + LOG_INF("%d -> T1: prio before %d", a, k_thread_priority_get(k_current_get())); + err = zbus_chan_pub(&chan_a, &a, K_FOREVER); + if (err) { + return; + } + LOG_INF("%d -> T1: prio after %d", a, k_thread_priority_get(k_current_get())); + ++a; + + k_msleep(2000); + } +} diff --git a/samples/subsys/zbus/priority_boost/with_hlp_priority_boost_feature.svg b/samples/subsys/zbus/priority_boost/with_hlp_priority_boost_feature.svg new file mode 100644 index 00000000000..e1c58da9b28 --- /dev/null +++ b/samples/subsys/zbus/priority_boost/with_hlp_priority_boost_feature.svg @@ -0,0 +1,75 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/samples/subsys/zbus/priority_boost/without_hlp_priority_boost_feature.svg b/samples/subsys/zbus/priority_boost/without_hlp_priority_boost_feature.svg new file mode 100644 index 00000000000..c912344567a --- /dev/null +++ b/samples/subsys/zbus/priority_boost/without_hlp_priority_boost_feature.svg @@ -0,0 +1,67 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/samples/subsys/zbus/priority_boost/zbus_publishing_process_example_scenario.svg b/samples/subsys/zbus/priority_boost/zbus_publishing_process_example_scenario.svg new file mode 100644 index 00000000000..bf2df426e3a --- /dev/null +++ b/samples/subsys/zbus/priority_boost/zbus_publishing_process_example_scenario.svg @@ -0,0 +1,35 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + From 690460a06a212cb27a4b0865a6e8d19f6ef4556b Mon Sep 17 00:00:00 2001 From: Rodrigo Peixoto Date: Mon, 11 Dec 2023 15:51:01 -0300 Subject: [PATCH 1695/3723] doc: zbus: add priority boost documentation Add priority boost documentation. Replace the ISR limitation since it is not valid anymore. Signed-off-by: Rodrigo Peixoto --- .../zbus_publishing_process_example_HLP.svg | 75 +++++++++++ doc/services/zbus/index.rst | 118 ++++++++++++++---- 2 files changed, 169 insertions(+), 24 deletions(-) create mode 100644 doc/services/zbus/images/zbus_publishing_process_example_HLP.svg diff --git a/doc/services/zbus/images/zbus_publishing_process_example_HLP.svg b/doc/services/zbus/images/zbus_publishing_process_example_HLP.svg new file mode 100644 index 00000000000..fcd9f64c581 --- /dev/null +++ b/doc/services/zbus/images/zbus_publishing_process_example_HLP.svg @@ -0,0 +1,75 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/doc/services/zbus/index.rst b/doc/services/zbus/index.rst index 82851ee1234..909c3f9be10 100644 --- a/doc/services/zbus/index.rst +++ b/doc/services/zbus/index.rst @@ -56,12 +56,10 @@ The bus comprises: ZBus anatomy. The bus makes the publish, read, claim, finish, notify, and subscribe actions available over -channels. Publishing, reading, claiming, and finishing are available in all RTOS thread contexts. -However, it cannot run inside Interrupt Service Routines (ISR) because it uses mutexes to control -channel access, and mutexes cannot work appropriately inside ISRs. The publish and read operations -are simple and fast; the procedure is a mutex locking followed by a memory copy to and from a shared -memory region and then a mutex unlocking. Another essential aspect of zbus is the observers. There -are three types of observers: +channels. Publishing, reading, claiming, and finishing are available in all RTOS thread contexts, +including ISRs. The publish and read operations are simple and fast; the procedure is channel +locking followed by a memory copy to and from a shared memory region and then a channel unlocking. +Another essential aspect of zbus is the observers. There are three types of observers: .. figure:: images/zbus_type_of_observers.svg :alt: ZBus observers type @@ -146,12 +144,12 @@ the solutions that can be done with zbus and make it a good fit as an open-sourc Virtual Distributed Event Dispatcher ==================================== -The VDED execution always happens in the publishing's (thread) context. So it cannot occur inside an -Interrupt Service Routine (ISR). Therefore, the IRSs must only access channels indirectly. The basic -description of the execution is as follows: +The VDED execution always happens in the publisher's context. It can be a thread or an ISR. Be +careful with publications inside ISR because the scheduler won't preempt the VDED. Use that wisely. +The basic description of the execution is as follows: -* The channel mutex is acquired; +* The channel lock is acquired; * The channel receives the new message via direct copy (by a raw :c:func:`memcpy`); * The event dispatcher logic executes the listeners, sends a copy of the message to the message subscribers, and pushes the channel's reference to the subscribers' notification message queue in @@ -216,7 +214,7 @@ priority. * - a - T1 starts and, at some point, publishes to channel A. * - b - - The publishing (VDED) process starts. The VDED locks the channel A's mutex. + - The publishing (VDED) process starts. The VDED locks the channel A. * - c - The VDED copies the T1 message to the channel A message. @@ -273,7 +271,7 @@ Thus, the table below describes the activities (represented by a letter) of the * - a - T1 starts and, at some point, publishes to channel A. * - b - - The publishing (VDED) process starts. The VDED locks the channel A's mutex. + - The publishing (VDED) process starts. The VDED locks the channel A. * - c - The VDED copies the T1 message to the channel A message. @@ -291,13 +289,7 @@ Thus, the table below describes the activities (represented by a letter) of the After that, the T1 regain MCU. * - h - - The VDED pushes the notification message to the queue of S1. Notice the thread gets ready to - execute right after receiving the notification. However, it goes to a pending state because - it cannot access the channel since it is still locked. At that moment, the T1 thread gets its - priority elevated (priority inheritance due to the mutex) to the highest pending thread - (caused by channel A unavailability). In that case, S1's priority. It ensures the T1 will - finish the VDED execution as quickly as possible without preemption from threads with - priority below the engaged ones. + - The VDED pushes the notification message to the queue of S1. * - i - VDED finishes the publishing by unlocking channel A. @@ -308,6 +300,81 @@ Thus, the table below describes the activities (represented by a letter) of the (as simple as lock, memory copy, unlock), continues its execution, and goes out the CPU. +HLP priority boost +------------------ +ZBus implements the Highest Locker Protocol that relies on the observers' thread priority to +determine a temporary publisher priority. The protocol considers the channel's Highest Observer +Priority (HOP); even if the observer is not waiting for a message on the channel, it is considered +in the calculation. The VDED will elevate the publisher's priority based on the HOP to ensure small +latency and as few preemptions as possible. + +.. note:: + The priority boost is enabled by default. To deactivate it, you must set the + :kconfig:option:`CONFIG_ZBUS_PRIORITY_BOOST` configuration. + +.. warning:: + ZBus priority boost does not consider runtime observers on the HOP calculations. + +The figure below illustrates the actions performed during the VDED execution when T1 publishes to +channel A. The scenario considers the priority boost feature and the following priorities: T1 < MS1 +< MS2 < S1. + +.. figure:: images/zbus_publishing_process_example_HLP.svg + :alt: ZBus publishing process details using priority boost. + :width: 85% + + ZBus VDED execution detail with priority boost enabled and for priority T1 < MS1 < MS2 < S1. + +To properly use the priority boost, attaching the observer to a thread is necessary. When the +subscriber is attached to a thread, it assumes its priority, and the priority boost algorithm will +consider the observer's priority. The following code illustrates the thread-attaching function. + + +.. code-block:: c + :emphasize-lines: 10 + + ZBUS_SUBSCRIBER_DEFINE(s1, 4); + void s1_thread(void *ptr1, void *ptr2, void *ptr3) + { + ARG_UNUSED(ptr1); + ARG_UNUSED(ptr2); + ARG_UNUSED(ptr3); + + const struct zbus_channel *chan; + + zbus_obs_attach_to_thread(&s1); + + while (1) { + zbus_sub_wait(&s1, &chan, K_FOREVER); + + /* Subscriber implementation */ + + } + } + K_THREAD_DEFINE(s1_id, CONFIG_MAIN_STACK_SIZE, s1_thread, NULL, NULL, NULL, 2, 0, 0); + +On the above code, the :c:func:`zbus_obs_attach_to_thread` will set the ``s1`` observer with +priority two as the thread has that priority. It is possible to reverse that by detaching the +observer using the :c:func:`zbus_obs_detach_from_thread`. Only enabled observers and observations +will be considered on the channel HOP calculation. Masking a specific observation of a channel will +affect the channel HOP. + +In summary, the benefits of the feature are: + +* The HLP is more effective for zbus than the mutexes priority inheritance; +* No bounded priority inversion will happen among the publisher and the observers; +* No other threads (that are not involved in the communication) with priority between T1 and S1 can + preempt T1, avoiding unbounded priority inversion; +* Message subscribers will wait for the VDED to finish the message delivery process. So the VDED + execution will be faster and more consistent; +* The HLP priority is dynamic and can change in execution; +* ZBus operations can be used inside ISRs; +* The priority boosting feature can be turned off, and plain semaphores can be used as the channel + lock mechanism; +* The Highest Locker Protocol's major disadvantage, the Inheritance-related Priority Inversion, is + acceptable in the zbus scenario since it will ensure a small bus latency. + + Limitations =========== @@ -508,7 +575,7 @@ sample, it's OK to use stack allocated messages since VDED copies the data inter zbus_chan_pub(&acc_chan, &acc1, K_SECONDS(1)); .. warning:: - Do not use this function inside an ISR. + Only use this function inside an ISR with a :c:macro:`K_NO_WAIT` timeout. .. _reading from a channel: @@ -525,7 +592,7 @@ read the message. Otherwise, the operation fails. zbus_chan_read(&acc_chan, &acc, K_MSEC(500)); .. warning:: - Do not use this function inside an ISR. + Only use this function inside an ISR with a :c:macro:`K_NO_WAIT` timeout. .. warning:: Choose the timeout of :c:func:`zbus_chan_read` after receiving a notification from @@ -548,7 +615,7 @@ exchange. See the code example under `Claim and finish a channel`_ where this ma zbus_chan_notify(&acc_chan, K_NO_WAIT); .. warning:: - Do not use this function inside an ISR. + Only use this function inside an ISR with a :c:macro:`K_NO_WAIT` timeout. Declaring channels and observers ================================ @@ -668,7 +735,7 @@ Listeners message access ------------------------ For performance purposes, listeners can access the receiving channel message directly since they -already have the mutex lock for it. To access the channel's message, the listener should use the +already have the channel locked for it. To access the channel's message, the listener should use the :c:func:`zbus_chan_const_msg` because the channel passed as an argument to the listener function is a constant pointer to the channel. The const pointer return type tells developers not to modify the message. @@ -709,7 +776,7 @@ channel, all the actions are available again. inconsistencies and scheduling issues. .. warning:: - Do not use these functions inside an ISR. + Only use this function inside an ISR with a :c:macro:`K_NO_WAIT` timeout. The following code builds on the examples above and claims the ``acc_chan`` to set the ``user_data`` to the channel. Suppose we would like to count how many times the channels exchange messages. We @@ -788,6 +855,8 @@ available: a host via serial; * :zephyr:code-sample:`zbus-remote-mock` illustrates how to implement an external mock (on the host) to send and receive messages to and from the bus; +* :zephyr:code-sample:`zbus-priority-boost` illustrates zbus priority boost feature with a priority + inversion scenario; * :zephyr:code-sample:`zbus-runtime-obs-registration` illustrates a way of using the runtime observer registration feature; * :zephyr:code-sample:`zbus-confirmed-channel` implements a way of implement confirmed channel only @@ -816,6 +885,7 @@ For enabling zbus, it is necessary to enable the :kconfig:option:`CONFIG_ZBUS` o Related configuration options: +* :kconfig:option:`CONFIG_ZBUS_PRIORITY_BOOST` zbus Highest Locker Protocol implementation; * :kconfig:option:`CONFIG_ZBUS_CHANNELS_SYS_INIT_PRIORITY` determine the :c:macro:`SYS_INIT` priority used by zbus to organize the channels observations by channel; * :kconfig:option:`CONFIG_ZBUS_CHANNEL_NAME` enables the name of channels to be available inside the From 89bd024a1c403b8372583cdb54a38ff54666d85f Mon Sep 17 00:00:00 2001 From: Tomas Galbicka Date: Thu, 21 Dec 2023 11:30:40 +0000 Subject: [PATCH 1696/3723] drivers: mbox: Add nxp mbox multi-channel support Current implementation of NXP mbox driver mbox_nxp_imx_mu is using only one channel 0. This commit adds support for multiple mbox channels as is indented by mbox drivers. Change done in .send api signaling mode leveraging provided channel id to select correct General Purpose Interrupt. Another change done in IRQHandler to check and handle all channels. Signed-off-by: Tomas Galbicka --- drivers/mbox/mbox_nxp_imx_mu.c | 40 +++++++++++++++++++--------------- 1 file changed, 22 insertions(+), 18 deletions(-) diff --git a/drivers/mbox/mbox_nxp_imx_mu.c b/drivers/mbox/mbox_nxp_imx_mu.c index 3c708b95eca..ddaac07e392 100644 --- a/drivers/mbox/mbox_nxp_imx_mu.c +++ b/drivers/mbox/mbox_nxp_imx_mu.c @@ -38,7 +38,7 @@ static int nxp_imx_mu_send(const struct device *dev, uint32_t channel, /* Signalling mode. */ if (msg == NULL) { return MU_TriggerInterrupts( - cfg->base, kMU_GenInt0InterruptTrigger); + cfg->base, kMU_GenInt0InterruptTrigger >> channel); } /* Data transfer mode. */ @@ -149,27 +149,31 @@ static const struct mbox_driver_api nxp_imx_mu_driver_api = { const struct device *dev = DEVICE_DT_INST_GET(idx); \ const struct nxp_imx_mu_data *data = dev->data; \ const struct nxp_imx_mu_config *config = dev->config; \ - int channel = 0; \ struct mbox_msg msg; \ struct mbox_msg *callback_msg_ptr = NULL; \ uint32_t flag = MU_GetStatusFlags(config->base); \ \ - if ((flag & kMU_Rx0FullFlag) == kMU_Rx0FullFlag) { \ - mu_##idx##_received_data = \ - MU_ReceiveMsgNonBlocking(config->base, 0); \ - msg.data = (const void *)&mu_##idx##_received_data; \ - msg.size = MU_MBOX_SIZE; \ - callback_msg_ptr = &msg; \ - } else if ((flag & kMU_GenInt0Flag) == kMU_GenInt0Flag) { \ - MU_ClearStatusFlags(config->base, kMU_GenInt0Flag); \ - callback_msg_ptr = NULL; \ - } \ - \ - if (data->cb[channel]) { \ - data->cb[channel](dev, channel, \ - data->user_data[channel], \ - callback_msg_ptr); \ - } \ + for (int i_channel = 0; i_channel < MU_MAX_CHANNELS; i_channel++) { \ + if ((flag & (kMU_Rx0FullFlag >> i_channel)) == \ + (kMU_Rx0FullFlag >> i_channel)) { \ + mu_##idx##_received_data = \ + MU_ReceiveMsgNonBlocking(config->base, 0); \ + msg.data = (const void *)&mu_##idx##_received_data; \ + msg.size = MU_MBOX_SIZE; \ + callback_msg_ptr = &msg; \ + } else if ((flag & (kMU_GenInt0Flag >> i_channel)) == \ + (kMU_GenInt0Flag >> i_channel)) { \ + MU_ClearStatusFlags(config->base, \ + (kMU_GenInt0Flag >> i_channel)); \ + callback_msg_ptr = NULL; \ + } \ + \ + if (data->cb[i_channel]) { \ + data->cb[i_channel](dev, i_channel, \ + data->user_data[i_channel], \ + callback_msg_ptr); \ + } \ + } \ } #define MU_INST(idx) \ From 68581caa744d1e1b7353ccdec9ff805806c58703 Mon Sep 17 00:00:00 2001 From: Gaetan Perrot Date: Thu, 21 Dec 2023 11:01:54 +0900 Subject: [PATCH 1697/3723] kernel: need_swap zephyrproject-rtos#66299 Enhancement on void z_reschedule_irqlock(uint32_t key) to avoid useless context switch signed-off-by: Gaetan Perrot --- kernel/sched.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/kernel/sched.c b/kernel/sched.c index f2fd98d0cfd..2e15b665960 100644 --- a/kernel/sched.c +++ b/kernel/sched.c @@ -1094,7 +1094,7 @@ void z_reschedule(struct k_spinlock *lock, k_spinlock_key_t key) void z_reschedule_irqlock(uint32_t key) { - if (resched(key)) { + if (resched(key) && need_swap()) { z_swap_irqlock(key); } else { irq_unlock(key); From 3d783166f8039277e4464755de0166bdb6d30adc Mon Sep 17 00:00:00 2001 From: Hake Huang Date: Wed, 27 Dec 2023 19:20:59 +0800 Subject: [PATCH 1698/3723] dts: fix frdm_kw41z ram size issue frdm_kw41z ram size is 96k not 128k(starting from 0x20000000) fixing: #66154 Signed-off-by: Hake Huang --- dts/arm/nxp/nxp_kw41z.dtsi | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/dts/arm/nxp/nxp_kw41z.dtsi b/dts/arm/nxp/nxp_kw41z.dtsi index f5eaa94d819..87c69d17f5e 100644 --- a/dts/arm/nxp/nxp_kw41z.dtsi +++ b/dts/arm/nxp/nxp_kw41z.dtsi @@ -32,7 +32,7 @@ sram0: memory@20000000 { compatible = "mmio-sram"; - reg = <0x20000000 DT_SIZE_K(128)>; + reg = <0x20000000 DT_SIZE_K(96)>; }; /* Dummy pinctrl node, filled with pin mux options at board level */ From ccc97125f83265749623acc6b0625bbb0aa467bd Mon Sep 17 00:00:00 2001 From: Ali Hozhabri Date: Tue, 2 Jan 2024 10:39:46 +0100 Subject: [PATCH 1699/3723] drivers: bluetooth: hci: Fix uninitialized array index, issue #66806 Fix issue #66806, caused by PR #65172. Return -EINVAL from bt_spi_get_header if op is neither SPI_READ nor SPI_WRITE. Signed-off-by: Ali Hozhabri --- drivers/bluetooth/hci/spi.c | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/drivers/bluetooth/hci/spi.c b/drivers/bluetooth/hci/spi.c index 69a102ae696..afad8fcf2ba 100644 --- a/drivers/bluetooth/hci/spi.c +++ b/drivers/bluetooth/hci/spi.c @@ -200,6 +200,8 @@ static int bt_spi_get_header(uint8_t op, uint16_t *size) size_offset = STATUS_HEADER_TOREAD; } else if (op == SPI_WRITE) { size_offset = STATUS_HEADER_TOWRITE; + } else { + return -EINVAL; } attempts = IRQ_HIGH_MAX_READ; do { @@ -274,6 +276,8 @@ static int bt_spi_get_header(uint8_t op, uint16_t *size) /* To make sure we have a minimum delay from previous release cs */ cs_delay = 100; size_offset = STATUS_HEADER_TOWRITE; + } else { + return -EINVAL; } assert_cs(cs_delay); @@ -303,6 +307,9 @@ static int bt_spi_get_header(uint8_t op, uint16_t *size) uint8_t size_offset; int ret; + if (!(op == SPI_READ || op == SPI_WRITE)) { + return -EINVAL; + } if (reading) { size_offset = STATUS_HEADER_TOREAD; } From dd48c2c2401e89e1d0de9523f48e4146a76a6e77 Mon Sep 17 00:00:00 2001 From: Jamie McCrae Date: Tue, 2 Jan 2024 16:12:08 +0000 Subject: [PATCH 1700/3723] doc: api: Change retained memory status to unstable Changes the API support level of retained memory from experimental to unstable, now that there are 3 drivers Signed-off-by: Jamie McCrae --- doc/develop/api/overview.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/doc/develop/api/overview.rst b/doc/develop/api/overview.rst index 6572ab0f161..20d03836c75 100644 --- a/doc/develop/api/overview.rst +++ b/doc/develop/api/overview.rst @@ -290,7 +290,7 @@ between major releases are available in the :ref:`zephyr_release_notes`. - 3.1 * - :ref:`retained_mem_api` - - Experimental + - Unstable - 3.4 * - :ref:`retention_api` From d142958fb618fb377dddd30574f636bf50f5c3e3 Mon Sep 17 00:00:00 2001 From: Jamie McCrae Date: Tue, 2 Jan 2024 16:13:52 +0000 Subject: [PATCH 1701/3723] doc: release: 3.6: Add retained memory changes Adds a note about a new backend and API status upgrade Signed-off-by: Jamie McCrae --- doc/releases/release-notes-3.6.rst | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/doc/releases/release-notes-3.6.rst b/doc/releases/release-notes-3.6.rst index 265f994c600..c86fb41d09a 100644 --- a/doc/releases/release-notes-3.6.rst +++ b/doc/releases/release-notes-3.6.rst @@ -202,6 +202,10 @@ Drivers and Sensors * Retained memory + * Retained memory driver backend for registers has been added. + + * Retained memory API status changed from experimental to unstable. + * RTC * SDHC From c3e8b731eff5beb5b28aef248bbc8ed20a2c7419 Mon Sep 17 00:00:00 2001 From: Aaron Ye Date: Fri, 29 Dec 2023 14:38:34 +0800 Subject: [PATCH 1702/3723] soc: arm: ambiq: Remove the redundant configurations. These non-cached SRAM size and base address configurations are not needed now. Signed-off-by: Aaron Ye --- soc/arm/ambiq/apollo4x/Kconfig.defconfig.apollo4p | 8 -------- soc/arm/ambiq/apollo4x/Kconfig.defconfig.apollo4p_blue | 8 -------- 2 files changed, 16 deletions(-) diff --git a/soc/arm/ambiq/apollo4x/Kconfig.defconfig.apollo4p b/soc/arm/ambiq/apollo4x/Kconfig.defconfig.apollo4p index 2d672184b4b..3e465e71ddb 100644 --- a/soc/arm/ambiq/apollo4x/Kconfig.defconfig.apollo4p +++ b/soc/arm/ambiq/apollo4x/Kconfig.defconfig.apollo4p @@ -7,12 +7,4 @@ if SOC_APOLLO4P config NUM_IRQS default 83 -DT_NODE_SRAM := /memory@0 - -config SRAM_NC_SIZE - default $(dt_node_reg_size_int,$(DT_NODE_SRAM),1,K) - -config SRAM_NC_BASE_ADDRESS - default $(dt_node_reg_addr_hex,$(DT_NODE_SRAM),1) - endif # SOC_APOLLO4P diff --git a/soc/arm/ambiq/apollo4x/Kconfig.defconfig.apollo4p_blue b/soc/arm/ambiq/apollo4x/Kconfig.defconfig.apollo4p_blue index 2d791dd4a46..3a96b8b6022 100644 --- a/soc/arm/ambiq/apollo4x/Kconfig.defconfig.apollo4p_blue +++ b/soc/arm/ambiq/apollo4x/Kconfig.defconfig.apollo4p_blue @@ -7,12 +7,4 @@ if SOC_APOLLO4P_BLUE config NUM_IRQS default 83 -DT_NODE_SRAM := /memory@0 - -config SRAM_NC_SIZE - default $(dt_node_reg_size_int,$(DT_NODE_SRAM),1,K) - -config SRAM_NC_BASE_ADDRESS - default $(dt_node_reg_addr_hex,$(DT_NODE_SRAM),1) - endif # SOC_APOLLO4P_BLUE From ed6da68f5b9492b32a5a34de408b7bd6c885af92 Mon Sep 17 00:00:00 2001 From: Emil Lindqvist Date: Wed, 1 Nov 2023 11:54:23 +0100 Subject: [PATCH 1703/3723] i2s: stm32h7: add i2s support for stm32h7 mcu family This commit modifies the I2S driver to work for STM32H7 family of MCU's. Currently only TX is working. Tested on nucleo_stm32h743zi. Requires dma1 & dmamux1 to be enabled. Signed-off-by: Emil Lindqvist --- drivers/i2s/Kconfig.stm32 | 2 +- drivers/i2s/i2s_ll_stm32.c | 62 +++++++++++++++++++++-- dts/arm/st/h7/stm32h7.dtsi | 42 +++++++++++++++ dts/arm/st/h7/stm32h7a3.dtsi | 13 +++++ dts/bindings/i2s/st,stm32-i2s-common.yaml | 31 ++++++++++++ dts/bindings/i2s/st,stm32-i2s.yaml | 27 +--------- dts/bindings/i2s/st,stm32h7-i2s.yaml | 8 +++ 7 files changed, 153 insertions(+), 32 deletions(-) create mode 100644 dts/bindings/i2s/st,stm32-i2s-common.yaml create mode 100644 dts/bindings/i2s/st,stm32h7-i2s.yaml diff --git a/drivers/i2s/Kconfig.stm32 b/drivers/i2s/Kconfig.stm32 index 8ef499ce7c9..26a5e827544 100644 --- a/drivers/i2s/Kconfig.stm32 +++ b/drivers/i2s/Kconfig.stm32 @@ -10,7 +10,7 @@ menuconfig I2S_STM32 select DMA help Enable I2S support on the STM32 family of processors. - (Tested on the STM32F4 series) + (Tested on the STM32F4 & STM32H7 series) if I2S_STM32 diff --git a/drivers/i2s/i2s_ll_stm32.c b/drivers/i2s/i2s_ll_stm32.c index 7ff2d2c3b6e..168e8097dd0 100644 --- a/drivers/i2s/i2s_ll_stm32.c +++ b/drivers/i2s/i2s_ll_stm32.c @@ -22,11 +22,7 @@ #include LOG_MODULE_REGISTER(i2s_ll_stm32); -/* FIXME change to - * #if __DCACHE_PRESENT == 1 - * when cache support is added - */ -#if 0 +#if __DCACHE_PRESENT == 1 #define DCACHE_INVALIDATE(addr, size) \ SCB_InvalidateDCache_by_Addr((uint32_t *)addr, size) #define DCACHE_CLEAN(addr, size) \ @@ -187,6 +183,9 @@ static int i2s_stm32_configure(const struct device *dev, enum i2s_dir dir, int ret; if (dir == I2S_DIR_RX) { +#if DT_HAS_COMPAT_STATUS_OKAY(st_stm32h7_i2s) + return -ENOSYS; +#endif stream = &dev_data->rx; } else if (dir == I2S_DIR_TX) { stream = &dev_data->tx; @@ -549,7 +548,11 @@ static void dma_rx_callback(const struct device *dma_dev, void *arg, ret = reload_dma(stream->dev_dma, stream->dma_channel, &stream->dma_cfg, +#if DT_HAS_COMPAT_STATUS_OKAY(st_stm32h7_i2s) + (void *)LL_SPI_DMA_GetRxRegAddr(cfg->i2s), +#else (void *)LL_SPI_DMA_GetRegAddr(cfg->i2s), +#endif stream->mem_block, stream->cfg.block_size); if (ret < 0) { @@ -634,7 +637,11 @@ static void dma_tx_callback(const struct device *dma_dev, void *arg, ret = reload_dma(stream->dev_dma, stream->dma_channel, &stream->dma_cfg, stream->mem_block, +#if DT_HAS_COMPAT_STATUS_OKAY(st_stm32h7_i2s) + (void *)LL_SPI_DMA_GetTxRegAddr(cfg->i2s), +#else (void *)LL_SPI_DMA_GetRegAddr(cfg->i2s), +#endif stream->cfg.block_size); if (ret < 0) { LOG_DBG("Failed to start TX DMA transfer: %d", ret); @@ -649,6 +656,7 @@ static void dma_tx_callback(const struct device *dma_dev, void *arg, static uint32_t i2s_stm32_irq_count; static uint32_t i2s_stm32_irq_ovr_count; +static uint32_t i2s_stm32_irq_udr_count; static void i2s_stm32_isr(const struct device *dev) { @@ -665,6 +673,12 @@ static void i2s_stm32_isr(const struct device *dev) LL_I2S_ClearFlag_OVR(cfg->i2s); } + /* NOTE: UDR error must be explicitly cleared on STM32H7 */ + if (LL_I2S_IsActiveFlag_UDR(cfg->i2s)) { + i2s_stm32_irq_udr_count++; + LL_I2S_ClearFlag_UDR(cfg->i2s); + } + i2s_stm32_irq_count++; } @@ -736,7 +750,11 @@ static int rx_stream_start(struct stream *stream, const struct device *dev) ret = start_dma(stream->dev_dma, stream->dma_channel, &stream->dma_cfg, +#if DT_HAS_COMPAT_STATUS_OKAY(st_stm32h7_i2s) + (void *)LL_SPI_DMA_GetRxRegAddr(cfg->i2s), +#else (void *)LL_SPI_DMA_GetRegAddr(cfg->i2s), +#endif stream->src_addr_increment, stream->mem_block, stream->dst_addr_increment, stream->fifo_threshold, stream->cfg.block_size); @@ -747,8 +765,17 @@ static int rx_stream_start(struct stream *stream, const struct device *dev) LL_I2S_EnableDMAReq_RX(cfg->i2s); +#if DT_HAS_COMPAT_STATUS_OKAY(st_stm32h7_i2s) + LL_I2S_EnableIT_OVR(cfg->i2s); + LL_I2S_EnableIT_UDR(cfg->i2s); + LL_I2S_EnableIT_FRE(cfg->i2s); + LL_I2S_Enable(cfg->i2s); + LL_SPI_StartMasterTransfer(cfg->i2s); +#else LL_I2S_EnableIT_ERR(cfg->i2s); LL_I2S_Enable(cfg->i2s); +#endif + return 0; } @@ -781,7 +808,11 @@ static int tx_stream_start(struct stream *stream, const struct device *dev) ret = start_dma(stream->dev_dma, stream->dma_channel, &stream->dma_cfg, stream->mem_block, stream->src_addr_increment, +#if DT_HAS_COMPAT_STATUS_OKAY(st_stm32h7_i2s) + (void *)LL_SPI_DMA_GetTxRegAddr(cfg->i2s), +#else (void *)LL_SPI_DMA_GetRegAddr(cfg->i2s), +#endif stream->dst_addr_increment, stream->fifo_threshold, stream->cfg.block_size); if (ret < 0) { @@ -791,8 +822,17 @@ static int tx_stream_start(struct stream *stream, const struct device *dev) LL_I2S_EnableDMAReq_TX(cfg->i2s); +#if DT_HAS_COMPAT_STATUS_OKAY(st_stm32h7_i2s) + LL_I2S_EnableIT_OVR(cfg->i2s); + LL_I2S_EnableIT_UDR(cfg->i2s); + LL_I2S_EnableIT_FRE(cfg->i2s); + + LL_I2S_Enable(cfg->i2s); + LL_SPI_StartMasterTransfer(cfg->i2s); +#else LL_I2S_EnableIT_ERR(cfg->i2s); LL_I2S_Enable(cfg->i2s); +#endif return 0; } @@ -802,7 +842,13 @@ static void rx_stream_disable(struct stream *stream, const struct device *dev) const struct i2s_stm32_cfg *cfg = dev->config; LL_I2S_DisableDMAReq_RX(cfg->i2s); +#if DT_HAS_COMPAT_STATUS_OKAY(st_stm32h7_i2s) + LL_I2S_DisableIT_OVR(cfg->i2s); + LL_I2S_DisableIT_UDR(cfg->i2s); + LL_I2S_DisableIT_FRE(cfg->i2s); +#else LL_I2S_DisableIT_ERR(cfg->i2s); +#endif dma_stop(stream->dev_dma, stream->dma_channel); if (stream->mem_block != NULL) { @@ -820,7 +866,13 @@ static void tx_stream_disable(struct stream *stream, const struct device *dev) const struct i2s_stm32_cfg *cfg = dev->config; LL_I2S_DisableDMAReq_TX(cfg->i2s); +#if DT_HAS_COMPAT_STATUS_OKAY(st_stm32h7_i2s) + LL_I2S_DisableIT_OVR(cfg->i2s); + LL_I2S_DisableIT_UDR(cfg->i2s); + LL_I2S_DisableIT_FRE(cfg->i2s); +#else LL_I2S_DisableIT_ERR(cfg->i2s); +#endif dma_stop(stream->dev_dma, stream->dma_channel); if (stream->mem_block != NULL) { diff --git a/dts/arm/st/h7/stm32h7.dtsi b/dts/arm/st/h7/stm32h7.dtsi index 9dcd1353132..8b6ae8041bb 100644 --- a/dts/arm/st/h7/stm32h7.dtsi +++ b/dts/arm/st/h7/stm32h7.dtsi @@ -466,6 +466,48 @@ status = "disabled"; }; + i2s1: i2s@40013000 { + compatible = "st,stm32h7-i2s", "st,stm32-i2s"; + #address-cells = <1>; + #size-cells = <0>; + reg = <0x40013000 0x400>; + clocks = <&rcc STM32_CLOCK_BUS_APB2 0x00001000>, + <&rcc STM32_SRC_PLL1_Q SPI123_SEL(0)>; + dmas = <&dmamux1 0 38 (STM32_DMA_PERIPH_TX | STM32_DMA_PRIORITY_HIGH) + &dmamux1 1 37 (STM32_DMA_PERIPH_RX | STM32_DMA_PRIORITY_HIGH)>; + dma-names = "tx", "rx"; + interrupts = <35 3>; + status = "disabled"; + }; + + i2s2: i2s@40003800 { + compatible = "st,stm32h7-i2s", "st,stm32-i2s"; + #address-cells = <1>; + #size-cells = <0>; + reg = <0x40003800 0x400>; + clocks = <&rcc STM32_CLOCK_BUS_APB1 0x00004000>, + <&rcc STM32_SRC_PLL1_Q SPI123_SEL(0)>; + dmas = <&dmamux1 0 40 (STM32_DMA_PERIPH_TX | STM32_DMA_PRIORITY_HIGH) + &dmamux1 1 39 (STM32_DMA_PERIPH_RX | STM32_DMA_PRIORITY_HIGH)>; + dma-names = "tx", "rx"; + interrupts = <36 0>; + status = "disabled"; + }; + + i2s3: i2s@40003c00 { + compatible = "st,stm32h7-i2s", "st,stm32-i2s"; + #address-cells = <1>; + #size-cells = <0>; + reg = <0x40003c00 0x400>; + clocks = <&rcc STM32_CLOCK_BUS_APB1 0x00008000>, + <&rcc STM32_SRC_PLL1_Q SPI123_SEL(0)>; + dmas = <&dmamux1 0 62 (STM32_DMA_PERIPH_TX | STM32_DMA_PRIORITY_HIGH) + &dmamux1 1 61 (STM32_DMA_PERIPH_RX | STM32_DMA_PRIORITY_HIGH)>; + dma-names = "tx", "rx"; + interrupts = <51 0>; + status = "disabled"; + }; + fdcan1: can@4000a000 { compatible = "st,stm32h7-fdcan"; reg = <0x4000a000 0x400>, <0x4000ac00 0x350>; diff --git a/dts/arm/st/h7/stm32h7a3.dtsi b/dts/arm/st/h7/stm32h7a3.dtsi index 7f85387ca06..8ff4353855a 100644 --- a/dts/arm/st/h7/stm32h7a3.dtsi +++ b/dts/arm/st/h7/stm32h7a3.dtsi @@ -79,6 +79,19 @@ status = "disabled"; }; + i2s6: i2s@58001400 { + compatible = "st,stm32h7-i2s", "st,stm32-i2s"; + #address-cells = <1>; + #size-cells = <0>; + reg = <0x58001400 0x400>; + clocks = <&rcc STM32_CLOCK_BUS_APB4 0x00000020>, + <&rcc STM32_SRC_PLL1_Q SPI6_SEL(0)>; + dmas = <&dmamux2 0 12 0x20440 &dmamux2 1 11 0x20480>; + dma-names = "tx", "rx"; + interrupts = <86 0>; + status = "disabled"; + }; + rng: rng@48021800 { nist-config = <0xf00d00>; health-test-magic = <0x17590abc>; diff --git a/dts/bindings/i2s/st,stm32-i2s-common.yaml b/dts/bindings/i2s/st,stm32-i2s-common.yaml new file mode 100644 index 00000000000..09e13c449e9 --- /dev/null +++ b/dts/bindings/i2s/st,stm32-i2s-common.yaml @@ -0,0 +1,31 @@ +# Copyright (c) 2018, STMicroelectronics +# SPDX-License-Identifier: Apache-2.0 + +# Common fields for STM32 I2S peripherals. + +include: [i2s-controller.yaml, pinctrl-device.yaml] + +properties: + reg: + required: true + + interrupts: + required: true + + dmas: + required: true + + dma-names: + required: true + + pinctrl-0: + required: true + + pinctrl-names: + required: true + + mck-enabled: + type: boolean + description: | + Master Clock Output function. + An mck pin must be listed within pinctrl-0 when enabling this property. diff --git a/dts/bindings/i2s/st,stm32-i2s.yaml b/dts/bindings/i2s/st,stm32-i2s.yaml index 1de415d0ddf..263e787d465 100644 --- a/dts/bindings/i2s/st,stm32-i2s.yaml +++ b/dts/bindings/i2s/st,stm32-i2s.yaml @@ -5,29 +5,4 @@ description: STM32 I2S controller compatible: "st,stm32-i2s" -include: [i2s-controller.yaml, pinctrl-device.yaml] - -properties: - reg: - required: true - - interrupts: - required: true - - dmas: - required: true - - dma-names: - required: true - - pinctrl-0: - required: true - - pinctrl-names: - required: true - - mck-enabled: - type: boolean - description: | - Master Clock Output function. - An mck pin must be listed within pinctrl-0 when enabling this property. +include: st,stm32-i2s-common.yaml diff --git a/dts/bindings/i2s/st,stm32h7-i2s.yaml b/dts/bindings/i2s/st,stm32h7-i2s.yaml new file mode 100644 index 00000000000..8fa3bf89c5b --- /dev/null +++ b/dts/bindings/i2s/st,stm32h7-i2s.yaml @@ -0,0 +1,8 @@ +# Copyright (c) 2018, STMicroelectronics +# SPDX-License-Identifier: Apache-2.0 + +description: STM32H7 I2S controller + +compatible: "st,stm32h7-i2s" + +include: st,stm32-i2s-common.yaml From cafe9a5632c9a796588cf05bf87191c3282c3bc6 Mon Sep 17 00:00:00 2001 From: Bartosz Bilas Date: Tue, 2 Jan 2024 13:18:08 +0100 Subject: [PATCH 1704/3723] drivers: regulator: max20335: fix unused-const-variable warnings There can be a case where not all regulators are being used, resulting in an unused-const-variable warning, so let's add a __maybe_unused keyword to suppress it. Signed-off-by: Bartosz Bilas --- drivers/regulator/regulator_max20335.c | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/drivers/regulator/regulator_max20335.c b/drivers/regulator/regulator_max20335.c index 5395c1de699..699edd8162f 100644 --- a/drivers/regulator/regulator_max20335.c +++ b/drivers/regulator/regulator_max20335.c @@ -67,7 +67,7 @@ static const struct linear_range buck12_current_limit_range = static const struct linear_range ldo1_range = LINEAR_RANGE_INIT(800000, 100000U, 0x0U, 0x1CU); static const struct linear_range ldo23_range = LINEAR_RANGE_INIT(900000, 100000U, 0x0U, 0x1FU); -static const struct regulator_max20335_desc buck1_desc = { +static const struct regulator_max20335_desc __maybe_unused buck1_desc = { .vsel_reg = MAX20335_BUCK1_VSET, .enable_mask = MAX20335_BUCK_EN_MASK, .enable_val = MAX20335_BUCK_EN, @@ -76,7 +76,7 @@ static const struct regulator_max20335_desc buck1_desc = { .ua_range = &buck12_current_limit_range, }; -static const struct regulator_max20335_desc buck2_desc = { +static const struct regulator_max20335_desc __maybe_unused buck2_desc = { .vsel_reg = MAX20335_BUCK2_VSET, .enable_mask = MAX20335_BUCK_EN_MASK, .enable_val = MAX20335_BUCK_EN, @@ -85,7 +85,7 @@ static const struct regulator_max20335_desc buck2_desc = { .ua_range = &buck12_current_limit_range, }; -static const struct regulator_max20335_desc ldo1_desc = { +static const struct regulator_max20335_desc __maybe_unused ldo1_desc = { .vsel_reg = MAX20335_LDO1_VSET, .enable_mask = MAX20335_LDO_EN_MASK, .enable_val = MAX20335_LDO_EN, @@ -93,7 +93,7 @@ static const struct regulator_max20335_desc ldo1_desc = { .uv_range = &ldo1_range, }; -static const struct regulator_max20335_desc ldo2_desc = { +static const struct regulator_max20335_desc __maybe_unused ldo2_desc = { .vsel_reg = MAX20335_LDO2_VSET, .enable_mask = MAX20335_LDO_EN_MASK, .enable_val = MAX20335_LDO_EN, @@ -101,7 +101,7 @@ static const struct regulator_max20335_desc ldo2_desc = { .uv_range = &ldo23_range, }; -static const struct regulator_max20335_desc ldo3_desc = { +static const struct regulator_max20335_desc __maybe_unused ldo3_desc = { .vsel_reg = MAX20335_LDO3_VSET, .enable_mask = MAX20335_LDO_EN_MASK, .enable_val = MAX20335_LDO_EN, From 21e37498e330f0c2896fcb8f4dd6f3f10c478bb8 Mon Sep 17 00:00:00 2001 From: Henrik Brix Andersen Date: Wed, 3 Jan 2024 14:08:00 +0100 Subject: [PATCH 1705/3723] Bluetooth: Audio: fix doxygen warnings Fix doxygen warnings ("warning: found tag without matching ") from building the Bluetooth Audio API documention. Signed-off-by: Henrik Brix Andersen --- .../zephyr/bluetooth/audio/gmap_lc3_preset.h | 32 +++++++++---------- 1 file changed, 16 insertions(+), 16 deletions(-) diff --git a/include/zephyr/bluetooth/audio/gmap_lc3_preset.h b/include/zephyr/bluetooth/audio/gmap_lc3_preset.h index 695df5dd79e..71289da2292 100644 --- a/include/zephyr/bluetooth/audio/gmap_lc3_preset.h +++ b/include/zephyr/bluetooth/audio/gmap_lc3_preset.h @@ -17,7 +17,7 @@ * @brief Helper to declare LC3 32_1_gr codec configuration * * @param _loc Audio channel location bitfield (@ref bt_audio_location) - * @param _stream_context Stream context (BT_AUDIO_CONTEXT_*) + * @param _stream_context Stream context (``BT_AUDIO_CONTEXT_*``) */ #define BT_GMAP_LC3_PRESET_32_1_GR(_loc, _stream_context) \ BT_BAP_LC3_PRESET(BT_AUDIO_CODEC_LC3_CONFIG_32_1(_loc, _stream_context), \ @@ -27,7 +27,7 @@ * @brief Helper to declare LC3 32_2_gr codec configuration * * @param _loc Audio channel location bitfield (@ref bt_audio_location) - * @param _stream_context Stream context (BT_AUDIO_CONTEXT_*) + * @param _stream_context Stream context (``BT_AUDIO_CONTEXT_*``) */ #define BT_GMAP_LC3_PRESET_32_2_GR(_loc, _stream_context) \ BT_BAP_LC3_PRESET(BT_AUDIO_CODEC_LC3_CONFIG_32_2(_loc, _stream_context), \ @@ -37,7 +37,7 @@ * @brief Helper to declare LC3 48_1_gr codec configuration * * @param _loc Audio channel location bitfield (@ref bt_audio_location) - * @param _stream_context Stream context (BT_AUDIO_CONTEXT_*) + * @param _stream_context Stream context (``BT_AUDIO_CONTEXT_*``) */ #define BT_GMAP_LC3_PRESET_48_1_GR(_loc, _stream_context) \ BT_BAP_LC3_PRESET(BT_AUDIO_CODEC_LC3_CONFIG_48_1(_loc, _stream_context), \ @@ -49,7 +49,7 @@ * Mandatory to support as both unicast client and server * * @param _loc Audio channel location bitfield (@ref bt_audio_location) - * @param _stream_context Stream context (BT_AUDIO_CONTEXT_*) + * @param _stream_context Stream context (``BT_AUDIO_CONTEXT_*``) */ #define BT_GMAP_LC3_PRESET_48_2_GR(_loc, _stream_context) \ BT_BAP_LC3_PRESET(BT_AUDIO_CODEC_LC3_CONFIG_48_2(_loc, _stream_context), \ @@ -59,7 +59,7 @@ * @brief Helper to declare LC3 48_3_gr codec configuration * * @param _loc Audio channel location bitfield (@ref bt_audio_location) - * @param _stream_context Stream context (BT_AUDIO_CONTEXT_*) + * @param _stream_context Stream context (``BT_AUDIO_CONTEXT_*``) */ #define BT_GMAP_LC3_PRESET_48_3_GR(_loc, _stream_context) \ BT_BAP_LC3_PRESET(BT_AUDIO_CODEC_LC3_CONFIG_48_3(_loc, _stream_context), \ @@ -71,7 +71,7 @@ * Mandatory to support as unicast server * * @param _loc Audio channel location bitfield (@ref bt_audio_location) - * @param _stream_context Stream context (BT_AUDIO_CONTEXT_*) + * @param _stream_context Stream context (``BT_AUDIO_CONTEXT_*``) */ #define BT_GMAP_LC3_PRESET_48_4_GR(_loc, _stream_context) \ BT_BAP_LC3_PRESET(BT_AUDIO_CODEC_LC3_CONFIG_48_4(_loc, _stream_context), \ @@ -81,7 +81,7 @@ * @brief Helper to declare LC3 16_1_gs codec configuration * * @param _loc Audio channel location bitfield (@ref bt_audio_location) - * @param _stream_context Stream context (BT_AUDIO_CONTEXT_*) + * @param _stream_context Stream context (``BT_AUDIO_CONTEXT_*``) */ #define BT_GMAP_LC3_PRESET_16_1_GS(_loc, _stream_context) \ BT_BAP_LC3_PRESET(BT_AUDIO_CODEC_LC3_CONFIG_16_1(_loc, _stream_context), \ @@ -91,7 +91,7 @@ * @brief Helper to declare LC3 16_2_gs codec configuration * * @param _loc Audio channel location bitfield (@ref bt_audio_location) - * @param _stream_context Stream context (BT_AUDIO_CONTEXT_*) + * @param _stream_context Stream context (``BT_AUDIO_CONTEXT_*``) */ #define BT_GMAP_LC3_PRESET_16_2_GS(_loc, _stream_context) \ BT_BAP_LC3_PRESET(BT_AUDIO_CODEC_LC3_CONFIG_16_2(_loc, _stream_context), \ @@ -101,7 +101,7 @@ * @brief Helper to declare LC3 32_1_gs codec configuration * * @param _loc Audio channel location bitfield (@ref bt_audio_location) - * @param _stream_context Stream context (BT_AUDIO_CONTEXT_*) + * @param _stream_context Stream context (``BT_AUDIO_CONTEXT_*``) */ #define BT_GMAP_LC3_PRESET_32_1_GS(_loc, _stream_context) \ BT_BAP_LC3_PRESET(BT_AUDIO_CODEC_LC3_CONFIG_32_1(_loc, _stream_context), \ @@ -111,7 +111,7 @@ * @brief Helper to declare LC3 32_2_gs codec configuration * * @param _loc Audio channel location bitfield (@ref bt_audio_location) - * @param _stream_context Stream context (BT_AUDIO_CONTEXT_*) + * @param _stream_context Stream context (``BT_AUDIO_CONTEXT_*``) */ #define BT_GMAP_LC3_PRESET_32_2_GS(_loc, _stream_context) \ BT_BAP_LC3_PRESET(BT_AUDIO_CODEC_LC3_CONFIG_32_2(_loc, _stream_context), \ @@ -121,7 +121,7 @@ * @brief Helper to declare LC3 48_1_gs codec configuration * * @param _loc Audio channel location bitfield (@ref bt_audio_location) - * @param _stream_context Stream context (BT_AUDIO_CONTEXT_*) + * @param _stream_context Stream context (``BT_AUDIO_CONTEXT_*``) */ #define BT_GMAP_LC3_PRESET_48_1_GS(_loc, _stream_context) \ BT_BAP_LC3_PRESET(BT_AUDIO_CODEC_LC3_CONFIG_48_1(_loc, _stream_context), \ @@ -131,7 +131,7 @@ * @brief Helper to declare LC3 48_2_gs codec configuration * * @param _loc Audio channel location bitfield (@ref bt_audio_location) - * @param _stream_context Stream context (BT_AUDIO_CONTEXT_*) + * @param _stream_context Stream context (``BT_AUDIO_CONTEXT_*``) */ #define BT_GMAP_LC3_PRESET_48_2_GS(_loc, _stream_context) \ BT_BAP_LC3_PRESET(BT_AUDIO_CODEC_LC3_CONFIG_48_2(_loc, _stream_context), \ @@ -143,7 +143,7 @@ * @brief Helper to declare LC3 48_1_g codec configuration * * @param _loc Audio channel location bitfield (@ref bt_audio_location) - * @param _stream_context Stream context (BT_AUDIO_CONTEXT_*) + * @param _stream_context Stream context (``BT_AUDIO_CONTEXT_*``) */ #define BT_GMAP_LC3_PRESET_48_1_G(_loc, _stream_context) \ BT_BAP_LC3_PRESET(BT_AUDIO_CODEC_LC3_CONFIG_48_1(_loc, _stream_context), \ @@ -153,7 +153,7 @@ * @brief Helper to declare LC3 48_2_g codec configuration * * @param _loc Audio channel location bitfield (@ref bt_audio_location) - * @param _stream_context Stream context (BT_AUDIO_CONTEXT_*) + * @param _stream_context Stream context (``BT_AUDIO_CONTEXT_*``) */ #define BT_GMAP_LC3_PRESET_48_2_G(_loc, _stream_context) \ BT_BAP_LC3_PRESET(BT_AUDIO_CODEC_LC3_CONFIG_48_2(_loc, _stream_context), \ @@ -163,7 +163,7 @@ * @brief Helper to declare LC3 48_3_g codec configuration * * @param _loc Audio channel location bitfield (@ref bt_audio_location) - * @param _stream_context Stream context (BT_AUDIO_CONTEXT_*) + * @param _stream_context Stream context (``BT_AUDIO_CONTEXT_*``) */ #define BT_GMAP_LC3_PRESET_48_3_G(_loc, _stream_context) \ BT_BAP_LC3_PRESET(BT_AUDIO_CODEC_LC3_CONFIG_48_3(_loc, _stream_context), \ @@ -173,7 +173,7 @@ * @brief Helper to declare LC3 48_4_g codec configuration * * @param _loc Audio channel location bitfield (@ref bt_audio_location) - * @param _stream_context Stream context (BT_AUDIO_CONTEXT_*) + * @param _stream_context Stream context (``BT_AUDIO_CONTEXT_*``) */ #define BT_GMAP_LC3_PRESET_48_4_G(_loc, _stream_context) \ BT_BAP_LC3_PRESET(BT_AUDIO_CODEC_LC3_CONFIG_48_4(_loc, _stream_context), \ From 4a4543569eac499f324be0e28bfbd8ea19f06edd Mon Sep 17 00:00:00 2001 From: Petr Hlineny Date: Thu, 23 Nov 2023 17:02:37 +0100 Subject: [PATCH 1706/3723] drivers: rtc: stm32: Fixes RTC issues related to device runtime pm When device runtime pm is enabled, Backup Domain protection is active most of the time. RTC driver need this protection to be disabled in order to set the time or calibration. This fix disable the protection in set time and set calibration functions. Fixes: 62843 Signed-off-by: Petr Hlineny --- drivers/rtc/rtc_ll_stm32.c | 24 ++++++++++++++++++++++++ 1 file changed, 24 insertions(+) diff --git a/drivers/rtc/rtc_ll_stm32.c b/drivers/rtc/rtc_ll_stm32.c index 020cd22ae2b..7d37de4c9a7 100644 --- a/drivers/rtc/rtc_ll_stm32.c +++ b/drivers/rtc/rtc_ll_stm32.c @@ -181,6 +181,10 @@ static int rtc_stm32_init(const struct device *dev) err = rtc_stm32_configure(dev); +#if defined(PWR_CR_DBP) || defined(PWR_CR1_DBP) || defined(PWR_DBPCR_DBP) || defined(PWR_DBPR_DBP) + LL_PWR_DisableBkUpAccess(); +#endif /* PWR_CR_DBP || PWR_CR1_DBP || PWR_DBPR_DBP */ + return err; } @@ -208,10 +212,18 @@ static int rtc_stm32_set_time(const struct device *dev, const struct rtc_time *t } LOG_INF("Setting clock"); + +#if defined(PWR_CR_DBP) || defined(PWR_CR1_DBP) || defined(PWR_DBPCR_DBP) || defined(PWR_DBPR_DBP) + LL_PWR_EnableBkUpAccess(); +#endif /* PWR_CR_DBP || PWR_CR1_DBP || PWR_DBPR_DBP */ + LL_RTC_DisableWriteProtection(RTC); err = rtc_stm32_enter_initialization_mode(true); if (err) { +#if defined(PWR_CR_DBP) || defined(PWR_CR1_DBP) || defined(PWR_DBPCR_DBP) || defined(PWR_DBPR_DBP) + LL_PWR_DisableBkUpAccess(); +#endif /* PWR_CR_DBP || PWR_CR1_DBP || PWR_DBPR_DBP */ k_mutex_unlock(&data->lock); return err; } @@ -237,6 +249,10 @@ static int rtc_stm32_set_time(const struct device *dev, const struct rtc_time *t LL_RTC_EnableWriteProtection(RTC); +#if defined(PWR_CR_DBP) || defined(PWR_CR1_DBP) || defined(PWR_DBPCR_DBP) || defined(PWR_DBPR_DBP) + LL_PWR_DisableBkUpAccess(); +#endif /* PWR_CR_DBP || PWR_CR1_DBP || PWR_DBPR_DBP */ + k_mutex_unlock(&data->lock); return err; @@ -359,12 +375,20 @@ static int rtc_stm32_set_calibration(const struct device *dev, int32_t calibrati return -EIO; } +#if defined(PWR_CR_DBP) || defined(PWR_CR1_DBP) || defined(PWR_DBPCR_DBP) || defined(PWR_DBPR_DBP) + LL_PWR_EnableBkUpAccess(); +#endif /* PWR_CR_DBP || PWR_CR1_DBP || PWR_DBPR_DBP */ + LL_RTC_DisableWriteProtection(RTC); MODIFY_REG(RTC->CALR, RTC_CALR_CALP | RTC_CALR_CALM, calp | calm); LL_RTC_EnableWriteProtection(RTC); +#if defined(PWR_CR_DBP) || defined(PWR_CR1_DBP) || defined(PWR_DBPCR_DBP) || defined(PWR_DBPR_DBP) + LL_PWR_DisableBkUpAccess(); +#endif /* PWR_CR_DBP || PWR_CR1_DBP || PWR_DBPR_DBP */ + return 0; } From 784a5b82e72c9d874d93d58d733c79a96b50b3f4 Mon Sep 17 00:00:00 2001 From: Petr Hlineny Date: Thu, 23 Nov 2023 17:05:17 +0100 Subject: [PATCH 1707/3723] drivers: rtc: stm32: Replaces Enter init mode function with LL function Use LL_RTC_EnterInitMode and LL_RTC_DisableInitMode instead of rtc_stm32_enter_initialization_mode and rtc_stm32_leave_initialization_mode. Signed-off-by: Petr Hlineny --- drivers/rtc/rtc_ll_stm32.c | 46 +++++++++----------------------------- 1 file changed, 11 insertions(+), 35 deletions(-) diff --git a/drivers/rtc/rtc_ll_stm32.c b/drivers/rtc/rtc_ll_stm32.c index 7d37de4c9a7..36f6558811c 100644 --- a/drivers/rtc/rtc_ll_stm32.c +++ b/drivers/rtc/rtc_ll_stm32.c @@ -77,34 +77,6 @@ struct rtc_stm32_data { struct k_mutex lock; }; -static int rtc_stm32_enter_initialization_mode(bool kernel_available) -{ - if (kernel_available) { - LL_RTC_EnableInitMode(RTC); - bool success = WAIT_FOR(LL_RTC_IsActiveFlag_INIT(RTC), RTC_TIMEOUT, k_msleep(1)); - - if (!success) { - return -EIO; - } - } else { - /* kernel is not available so use the blocking but otherwise equivalent function - * provided by LL - */ - ErrorStatus status = LL_RTC_EnterInitMode(RTC); - - if (status != SUCCESS) { - return -EIO; - } - } - - return 0; -} - -static inline void rtc_stm32_leave_initialization_mode(void) -{ - LL_RTC_DisableInitMode(RTC); -} - static int rtc_stm32_configure(const struct device *dev) { const struct rtc_stm32_config *cfg = dev->config; @@ -123,14 +95,17 @@ static int rtc_stm32_configure(const struct device *dev) if ((hour_format != LL_RTC_HOURFORMAT_24HOUR) || (sync_prescaler != cfg->sync_prescaler) || (async_prescaler != cfg->async_prescaler)) { - err = rtc_stm32_enter_initialization_mode(false); - if (err == 0) { + ErrorStatus status = LL_RTC_EnterInitMode(RTC); + + if (status == SUCCESS) { LL_RTC_SetHourFormat(RTC, LL_RTC_HOURFORMAT_24HOUR); LL_RTC_SetSynchPrescaler(RTC, cfg->sync_prescaler); LL_RTC_SetAsynchPrescaler(RTC, cfg->async_prescaler); + } else { + err = -EIO; } - rtc_stm32_leave_initialization_mode(); + LL_RTC_DisableInitMode(RTC); } #ifdef RTC_CR_BYPSHAD @@ -219,13 +194,14 @@ static int rtc_stm32_set_time(const struct device *dev, const struct rtc_time *t LL_RTC_DisableWriteProtection(RTC); - err = rtc_stm32_enter_initialization_mode(true); - if (err) { + ErrorStatus status = LL_RTC_EnterInitMode(RTC); + + if (status != SUCCESS) { #if defined(PWR_CR_DBP) || defined(PWR_CR1_DBP) || defined(PWR_DBPCR_DBP) || defined(PWR_DBPR_DBP) LL_PWR_DisableBkUpAccess(); #endif /* PWR_CR_DBP || PWR_CR1_DBP || PWR_DBPR_DBP */ k_mutex_unlock(&data->lock); - return err; + return -EIO; } LL_RTC_DATE_SetYear(RTC, bin2bcd(real_year - RTC_YEAR_REF)); @@ -245,7 +221,7 @@ static int rtc_stm32_set_time(const struct device *dev, const struct rtc_time *t LL_RTC_TIME_SetMinute(RTC, bin2bcd(timeptr->tm_min)); LL_RTC_TIME_SetSecond(RTC, bin2bcd(timeptr->tm_sec)); - rtc_stm32_leave_initialization_mode(); + LL_RTC_DisableInitMode(RTC); LL_RTC_EnableWriteProtection(RTC); From 0ed8f10d8a9f183d97534f731c6ba78dce6221ff Mon Sep 17 00:00:00 2001 From: Petr Hlineny Date: Thu, 23 Nov 2023 17:07:18 +0100 Subject: [PATCH 1708/3723] drivers: rtc: stm32: Updated scope of hsem This commit updates the scope of hsem. Signed-off-by: Petr Hlineny --- drivers/rtc/rtc_ll_stm32.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/drivers/rtc/rtc_ll_stm32.c b/drivers/rtc/rtc_ll_stm32.c index 36f6558811c..8e1ee9419b5 100644 --- a/drivers/rtc/rtc_ll_stm32.c +++ b/drivers/rtc/rtc_ll_stm32.c @@ -139,7 +139,6 @@ static int rtc_stm32_init(const struct device *dev) k_mutex_init(&data->lock); /* Enable Backup access */ - z_stm32_hsem_lock(CFG_HW_RCC_SEMID, HSEM_LOCK_DEFAULT_RETRY); #if defined(PWR_CR_DBP) || defined(PWR_CR1_DBP) || defined(PWR_DBPCR_DBP) || defined(PWR_DBPR_DBP) LL_PWR_EnableBkUpAccess(); #endif /* PWR_CR_DBP || PWR_CR1_DBP || PWR_DBPR_DBP */ @@ -150,6 +149,8 @@ static int rtc_stm32_init(const struct device *dev) return -EIO; } + z_stm32_hsem_lock(CFG_HW_RCC_SEMID, HSEM_LOCK_DEFAULT_RETRY); + LL_RCC_EnableRTC(); z_stm32_hsem_unlock(CFG_HW_RCC_SEMID); From 603c3af895b0f03d792252412a2255d97791df09 Mon Sep 17 00:00:00 2001 From: George Beckstein Date: Mon, 27 Nov 2023 15:43:58 -0500 Subject: [PATCH 1709/3723] drivers: flash : stm32: STM32L4P5xx fix page calculation from offset This fix adds the STM32L4P5xx to the list of devices that have an offset-to-page shift calculation of 12 bits. Previously, the driver would only shift the offset by 11 bits when calculating the page to erase. This would prevent the driver from erasing the correct page. Signed-off-by: George Beckstein --- drivers/flash/flash_stm32l4x.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/flash/flash_stm32l4x.c b/drivers/flash/flash_stm32l4x.c index ead57fb3df4..e82bf1db303 100644 --- a/drivers/flash/flash_stm32l4x.c +++ b/drivers/flash/flash_stm32l4x.c @@ -23,7 +23,7 @@ LOG_MODULE_REGISTER(LOG_DOMAIN); #if !defined(STM32L4R5xx) && !defined(STM32L4R7xx) && !defined(STM32L4R9xx) && \ !defined(STM32L4S5xx) && !defined(STM32L4S7xx) && !defined(STM32L4S9xx) && \ - !defined(STM32L4Q5xx) + !defined(STM32L4Q5xx) && !defined(STM32L4P5xx) #define STM32L4X_PAGE_SHIFT 11 #else #define STM32L4X_PAGE_SHIFT 12 From 2a994326959f6903578a6212d56c5d7ade88050c Mon Sep 17 00:00:00 2001 From: Fabio Baltieri Date: Thu, 4 Jan 2024 11:42:58 +0000 Subject: [PATCH 1710/3723] input: kbd_matrix: fail gracefully if changing an undefined key mask Add a check to input_kbd_matrix_actual_key_mask_set() to return an error if trying to change a key mask but the device does not define a keymask in the first place. Signed-off-by: Fabio Baltieri --- drivers/input/input_kbd_matrix.c | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/drivers/input/input_kbd_matrix.c b/drivers/input/input_kbd_matrix.c index 2b6c11231e9..095a9bb0cfd 100644 --- a/drivers/input/input_kbd_matrix.c +++ b/drivers/input/input_kbd_matrix.c @@ -334,6 +334,11 @@ int input_kbd_matrix_actual_key_mask_set(const struct device *dev, return -EINVAL; } + if (cfg->actual_key_mask == NULL) { + LOG_WRN("actual-key-mask not defined for %s", dev->name); + return -EINVAL; + } + WRITE_BIT(cfg->actual_key_mask[col], row, enabled); return 0; From aefbbe278815401158f2da236a893e0cad3cf540 Mon Sep 17 00:00:00 2001 From: Christopher Friedt Date: Mon, 1 Jan 2024 18:40:48 -0500 Subject: [PATCH 1711/3723] tests: posix: common: key: remove overspecified pthread_attr_t Much of tests/posix/common still overspecifies pthread_attr_t options. Default thread attributes are perfectly fine for the vast majority of spawned threads in this testsuite, so simply use a NULL pthread_attr_t* argument. This fixes piles of bugs because we have not properly used pthread_attr_destroy() appropriately. Signed-off-by: Christopher Friedt --- tests/posix/common/src/key.c | 171 +++++++---------------------------- 1 file changed, 35 insertions(+), 136 deletions(-) diff --git a/tests/posix/common/src/key.c b/tests/posix/common/src/key.c index 58e67a313ac..dbeddc3b6d0 100644 --- a/tests/posix/common/src/key.c +++ b/tests/posix/common/src/key.c @@ -10,102 +10,54 @@ #include #define N_THR 2 -#define N_KEY 2 -#define STACKSZ (MAX(1024, PTHREAD_STACK_MIN) + CONFIG_TEST_EXTRA_STACK_SIZE) +#define N_KEY 2 #define BUFFSZ 48 -K_THREAD_STACK_ARRAY_DEFINE(stackp, N_THR, STACKSZ); - -pthread_key_t key, keys[N_KEY]; +static pthread_key_t key; +static pthread_key_t keys[N_KEY]; static pthread_once_t key_once = PTHREAD_ONCE_INIT; static pthread_once_t keys_once = PTHREAD_ONCE_INIT; -void *thread_top(void *p1) +static void *thread_top(void *p1) { - int ret = -1; - void *value; - void *getval; char *buffer[BUFFSZ]; value = k_malloc(sizeof(buffer)); - - zassert_true((int) POINTER_TO_INT(value), - "thread could not allocate storage"); - - ret = pthread_setspecific(key, value); - - /* TESTPOINT: Check if thread's value is associated with key */ - zassert_false(ret, "pthread_setspecific failed"); - - getval = 0; - - getval = pthread_getspecific(key); - - /* TESTPOINT: Check if pthread_getspecific returns the same value - * set by pthread_setspecific - */ - zassert_equal(value, getval, - "set and retrieved values are different"); - - printk("set value = %d and retrieved value = %d\n", - (int) POINTER_TO_INT(value), (int) POINTER_TO_INT(getval)); + zassert_not_null(value, "thread could not allocate storage"); + zassert_ok(pthread_setspecific(key, value), "pthread_setspecific failed"); + zassert_equal(pthread_getspecific(key), value, "set and retrieved values are different"); + k_free(value); return NULL; } -void *thread_func(void *p1) +static void *thread_func(void *p1) { - int i, ret = -1; - void *value; - void *getval; char *buffer[BUFFSZ]; value = k_malloc(sizeof(buffer)); - - zassert_true((int) POINTER_TO_INT(value), - "thread could not allocate storage"); - - for (i = 0; i < N_KEY; i++) { - ret = pthread_setspecific(keys[i], value); - - /* TESTPOINT: Check if thread's value is associated with keys */ - zassert_false(ret, "pthread_setspecific failed"); - } - - for (i = 0; i < N_KEY; i++) { - getval = 0; - getval = pthread_getspecific(keys[i]); - - /* TESTPOINT: Check if pthread_getspecific returns the same - * value set by pthread_setspecific for each of the keys - */ - zassert_equal(value, getval, - "set and retrieved values are different"); - - printk("key %d: set value = %d and retrieved value = %d\n", - i, (int) POINTER_TO_INT(value), - (int) POINTER_TO_INT(getval)); + zassert_not_null(value, "thread could not allocate storage"); + for (int i = 0; i < N_KEY; i++) { + zassert_ok(pthread_setspecific(keys[i], value), "pthread_setspecific failed"); + zassert_equal(pthread_getspecific(keys[i]), value, + "set and retrieved values are different"); } + k_free(value); return NULL; } static void make_key(void) { - int ret = 0; - - ret = pthread_key_create(&key, NULL); - zassert_false(ret, "insufficient memory to create key"); + zassert_ok(pthread_key_create(&key, NULL), "insufficient memory to create key"); } static void make_keys(void) { - int i, ret = 0; - - for (i = 0; i < N_KEY; i++) { - ret = pthread_key_create(&keys[i], NULL); - zassert_false(ret, "insufficient memory to create keys"); + for (int i = 0; i < N_KEY; i++) { + zassert_ok(pthread_key_create(&keys[i], NULL), + "insufficient memory to create keys"); } } @@ -124,94 +76,41 @@ static void make_keys(void) ZTEST(posix_apis, test_key_1toN_thread) { - int i, ret = -1; - - pthread_attr_t attr[N_THR]; - struct sched_param schedparam; - pthread_t newthread[N_THR]; void *retval; + pthread_t newthread[N_THR]; - ret = pthread_once(&key_once, make_key); - - /* TESTPOINT: Check if key is created */ - zassert_false(ret, "attempt to create key failed"); - - printk("\nDifferent threads set different values to same key:\n"); - - /* Creating threads with lowest application priority */ - for (i = 0; i < N_THR; i++) { - ret = pthread_attr_init(&attr[i]); - if (ret != 0) { - zassert_false(pthread_attr_destroy(&attr[i]), - "Unable to destroy pthread object attr"); - zassert_false(pthread_attr_init(&attr[i]), - "Unable to create pthread object attr"); - } - - schedparam.sched_priority = 2; - pthread_attr_setschedparam(&attr[i], &schedparam); - pthread_attr_setstack(&attr[i], &stackp[i][0], STACKSZ); + zassert_ok(pthread_once(&key_once, make_key), "attempt to create key failed"); - ret = pthread_create(&newthread[i], &attr[i], thread_top, - INT_TO_POINTER(i)); + /* Different threads set different values to same key */ - /* TESTPOINT: Check if threads are created successfully */ - zassert_false(ret, "attempt to create threads failed"); + for (int i = 0; i < N_THR; i++) { + zassert_ok(pthread_create(&newthread[i], NULL, thread_top, NULL), + "attempt to create thread %d failed", i); } - for (i = 0; i < N_THR; i++) { - printk("thread %d: ", i); - pthread_join(newthread[i], &retval); + for (int i = 0; i < N_THR; i++) { + zassert_ok(pthread_join(newthread[i], &retval), "failed to join thread %d", i); } - ret = pthread_key_delete(key); - - /* TESTPOINT: Check if key is deleted */ - zassert_false(ret, "attempt to delete key failed"); - printk("\n"); + zassert_ok(pthread_key_delete(key), "attempt to delete key failed"); } ZTEST(posix_apis, test_key_Nto1_thread) { - int i, ret = -1; - - pthread_attr_t attr; - struct sched_param schedparam; pthread_t newthread; - ret = pthread_once(&keys_once, make_keys); - - /* TESTPOINT: Check if keys are created successfully */ - zassert_false(ret, "attempt to create keys failed"); - - printk("\nSingle thread associates its value with different keys:\n"); - ret = pthread_attr_init(&attr); - if (ret != 0) { - zassert_false(pthread_attr_destroy(&attr), - "Unable to destroy pthread object attr"); - zassert_false(pthread_attr_init(&attr), - "Unable to create pthread object attr"); - } - - schedparam.sched_priority = 2; - pthread_attr_setschedparam(&attr, &schedparam); - pthread_attr_setstack(&attr, &stackp[0][0], STACKSZ); - - ret = pthread_create(&newthread, &attr, thread_func, - (void *)0); + zassert_ok(pthread_once(&keys_once, make_keys), "attempt to create keys failed"); - /*TESTPOINT: Check if thread is created successfully */ - zassert_false(ret, "attempt to create thread failed"); + /* Single thread associates its value with different keys */ - pthread_join(newthread, NULL); + zassert_ok(pthread_create(&newthread, NULL, thread_func, NULL), + "attempt to create thread failed"); - for (i = 0; i < N_KEY; i++) { - ret = pthread_key_delete(keys[i]); + zassert_ok(pthread_join(newthread, NULL), "failed to join thread"); - /* TESTPOINT: Check if keys are deleted */ - zassert_false(ret, "attempt to delete keys failed"); + for (int i = 0; i < N_KEY; i++) { + zassert_ok(pthread_key_delete(keys[i]), "attempt to delete keys[%d] failed", i); } - printk("\n"); } ZTEST(posix_apis, test_key_resource_leak) From bfb4a5141cb76a3d4ecbe0a7c01e7f75ccd7f0ba Mon Sep 17 00:00:00 2001 From: Christopher Friedt Date: Mon, 1 Jan 2024 18:44:32 -0500 Subject: [PATCH 1712/3723] tests: posix: common: mqueue: remove overspecified pthread_attr_t Much of tests/posix/common still overspecifies pthread_attr_t options. Default thread attributes are perfectly fine for the vast majority of spawned threads in this testsuite, so simply use a NULL pthread_attr_t* argument. This fixes piles of bugs because we have not properly used pthread_attr_destroy() appropriately. Signed-off-by: Christopher Friedt --- tests/posix/common/src/mqueue.c | 33 +++++++++------------------------ 1 file changed, 9 insertions(+), 24 deletions(-) diff --git a/tests/posix/common/src/mqueue.c b/tests/posix/common/src/mqueue.c index 65df6fbe777..4ddfdea2da9 100644 --- a/tests/posix/common/src/mqueue.c +++ b/tests/posix/common/src/mqueue.c @@ -11,15 +11,12 @@ #include #include -#define N_THR 2 -#define STACKSZ (MAX(1024, PTHREAD_STACK_MIN) + CONFIG_TEST_EXTRA_STACK_SIZE) +#define N_THR 2 #define SENDER_THREAD 0 #define RECEIVER_THREAD 1 #define MESSAGE_SIZE 16 #define MESG_COUNT_PERMQ 4 -K_THREAD_STACK_ARRAY_DEFINE(stacks, N_THR, STACKSZ); - char queue[16] = "server"; char send_data[MESSAGE_SIZE] = "timed data send"; @@ -60,7 +57,8 @@ void *receiver_thread(void *p1) clock_gettime(CLOCK_MONOTONIC, &curtime); curtime.tv_sec += 1; mq_timedreceive(mqd, rec_data, MESSAGE_SIZE, 0, &curtime); - zassert_false(strcmp(rec_data, send_data), "Error in data reception"); + zassert_false(strcmp(rec_data, send_data), "Error in data reception. exp: %s act: %s", + send_data, rec_data); usleep(USEC_PER_MSEC); zassert_false(mq_close(mqd), "unable to close message queue descriptor."); @@ -72,9 +70,9 @@ ZTEST(posix_apis, test_mqueue) { mqd_t mqd; struct mq_attr attrs; - int32_t mode = 0777, flags = O_RDWR | O_CREAT, ret, i; + int32_t mode = 0777; + int flags = O_RDWR | O_CREAT; void *retval; - pthread_attr_t attr[N_THR]; pthread_t newthread[N_THR]; attrs.mq_msgsize = MESSAGE_SIZE; @@ -82,28 +80,15 @@ ZTEST(posix_apis, test_mqueue) mqd = mq_open(queue, flags, mode, &attrs); - for (i = 0; i < N_THR; i++) { + for (int i = 0; i < N_THR; i++) { /* Creating threads */ - zassert_ok(pthread_attr_init(&attr[i])); - pthread_attr_setstack(&attr[i], &stacks[i][0], STACKSZ); - - if (i % 2) { - ret = pthread_create(&newthread[i], &attr[i], - sender_thread, - INT_TO_POINTER(i)); - } else { - ret = pthread_create(&newthread[i], &attr[i], - receiver_thread, - INT_TO_POINTER(i)); - } - - zassert_false(ret, "Not enough space to create new thread"); - zassert_equal(pthread_attr_destroy(&attr[i]), 0); + zassert_ok(pthread_create(&newthread[i], NULL, + (i % 2 == 0) ? receiver_thread : sender_thread, NULL)); } usleep(USEC_PER_MSEC * 10U); - for (i = 0; i < N_THR; i++) { + for (int i = 0; i < N_THR; i++) { pthread_join(newthread[i], &retval); } From d9cffcfc36abd0d0d9d3fb0d6b6984eb7fc7013d Mon Sep 17 00:00:00 2001 From: Christopher Friedt Date: Mon, 1 Jan 2024 18:45:38 -0500 Subject: [PATCH 1713/3723] tests: posix: common: mutex: remove overspecified pthread_attr_t Much of tests/posix/common still overspecifies pthread_attr_t options. Default thread attributes are perfectly fine for the vast majority of spawned threads in this testsuite, so simply use a NULL pthread_attr_t* argument. This fixes piles of bugs because we have not properly used pthread_attr_destroy() appropriately. Signed-off-by: Christopher Friedt --- tests/posix/common/src/mutex.c | 139 +++++++++------------------------ 1 file changed, 39 insertions(+), 100 deletions(-) diff --git a/tests/posix/common/src/mutex.c b/tests/posix/common/src/mutex.c index 6a63f98e451..ded1055f7dc 100644 --- a/tests/posix/common/src/mutex.c +++ b/tests/posix/common/src/mutex.c @@ -10,14 +10,8 @@ #include #include -#define STACK_SIZE (MAX(1024, PTHREAD_STACK_MIN) + CONFIG_TEST_EXTRA_STACK_SIZE) - -static K_THREAD_STACK_DEFINE(stack, STACK_SIZE); - #define SLEEP_MS 100 -pthread_mutex_t mutex1; -pthread_mutex_t mutex2; pthread_mutex_t mutex; void *normal_mutex_entry(void *p1) @@ -27,7 +21,7 @@ void *normal_mutex_entry(void *p1) /* Sleep for maximum 300 ms as main thread is sleeping for 100 ms */ for (i = 0; i < 3; i++) { - rc = pthread_mutex_trylock(&mutex1); + rc = pthread_mutex_trylock(&mutex); if (rc == 0) { break; } @@ -36,74 +30,62 @@ void *normal_mutex_entry(void *p1) zassert_false(rc, "try lock failed"); TC_PRINT("mutex lock is taken\n"); - zassert_false(pthread_mutex_unlock(&mutex1), "mutex unlock is failed"); + zassert_false(pthread_mutex_unlock(&mutex), "mutex unlock is failed"); return NULL; } void *recursive_mutex_entry(void *p1) { - zassert_false(pthread_mutex_lock(&mutex2), "mutex is not taken"); - zassert_false(pthread_mutex_lock(&mutex2), "mutex is not taken 2nd time"); + zassert_false(pthread_mutex_lock(&mutex), "mutex is not taken"); + zassert_false(pthread_mutex_lock(&mutex), "mutex is not taken 2nd time"); TC_PRINT("recursive mutex lock is taken\n"); - zassert_false(pthread_mutex_unlock(&mutex2), "mutex is not unlocked"); - zassert_false(pthread_mutex_unlock(&mutex2), "mutex is not unlocked"); + zassert_false(pthread_mutex_unlock(&mutex), "mutex is not unlocked"); + zassert_false(pthread_mutex_unlock(&mutex), "mutex is not unlocked"); return NULL; } -/** - * @brief Test to demonstrate PTHREAD_MUTEX_NORMAL - * - * @details Mutex type is setup as normal. pthread_mutex_trylock - * and pthread_mutex_lock are tested with mutex type being - * normal. - */ -ZTEST(posix_apis, test_mutex_normal) +static void test_mutex_common(int type, void *(*entry)(void *arg)) { - pthread_t thread_1; - pthread_attr_t attr; - pthread_mutexattr_t mut_attr; + pthread_t th; + int protocol; + int actual_type; struct sched_param schedparam; - int schedpolicy = SCHED_FIFO; - int ret, type, protocol, temp; + pthread_mutexattr_t mut_attr = {0}; schedparam.sched_priority = 2; - ret = pthread_attr_init(&attr); - if (ret != 0) { - zassert_false(pthread_attr_destroy(&attr), - "Unable to destroy pthread object attrib"); - zassert_false(pthread_attr_init(&attr), "Unable to create pthread object attrib"); - } - - pthread_attr_setstack(&attr, &stack, STACK_SIZE); - pthread_attr_setschedpolicy(&attr, schedpolicy); - pthread_attr_setschedparam(&attr, &schedparam); - temp = pthread_mutexattr_settype(&mut_attr, PTHREAD_MUTEX_NORMAL); - zassert_false(temp, "setting mutex type is failed"); - temp = pthread_mutex_init(&mutex1, &mut_attr); - zassert_false(temp, "mutex initialization is failed"); + zassert_ok(pthread_mutexattr_settype(&mut_attr, type), "setting mutex type is failed"); + zassert_ok(pthread_mutex_init(&mutex, &mut_attr), "mutex initialization is failed"); - temp = pthread_mutexattr_gettype(&mut_attr, &type); - zassert_false(temp, "reading mutex type is failed"); - temp = pthread_mutexattr_getprotocol(&mut_attr, &protocol); - zassert_false(temp, "reading mutex protocol is failed"); + zassert_ok(pthread_mutexattr_gettype(&mut_attr, &actual_type), + "reading mutex type is failed"); + zassert_ok(pthread_mutexattr_getprotocol(&mut_attr, &protocol), + "reading mutex protocol is failed"); - pthread_mutex_lock(&mutex1); - - zassert_equal(type, PTHREAD_MUTEX_NORMAL, "mutex type is not normal"); + zassert_ok(pthread_mutex_lock(&mutex)); + zassert_equal(actual_type, type, "mutex type is not normal"); zassert_equal(protocol, PTHREAD_PRIO_NONE, "mutex protocol is not prio_none"); - ret = pthread_create(&thread_1, &attr, &normal_mutex_entry, NULL); - if (ret) { - TC_PRINT("Thread1 creation failed %d", ret); - } + zassert_ok(pthread_create(&th, NULL, entry, NULL)); + k_msleep(SLEEP_MS); - pthread_mutex_unlock(&mutex1); + zassert_ok(pthread_mutex_unlock(&mutex)); + + zassert_ok(pthread_join(th, NULL)); + zassert_ok(pthread_mutex_destroy(&mutex), "Destroying mutex is failed"); +} - pthread_join(thread_1, NULL); - temp = pthread_mutex_destroy(&mutex1); - zassert_false(temp, "Destroying mutex is failed"); +/** + * @brief Test to demonstrate PTHREAD_MUTEX_NORMAL + * + * @details Mutex type is setup as normal. pthread_mutex_trylock + * and pthread_mutex_lock are tested with mutex type being + * normal. + */ +ZTEST(posix_apis, test_mutex_normal) +{ + test_mutex_common(PTHREAD_MUTEX_NORMAL, normal_mutex_entry); } /** @@ -115,45 +97,7 @@ ZTEST(posix_apis, test_mutex_normal) */ ZTEST(posix_apis, test_mutex_recursive) { - pthread_t thread_2; - pthread_attr_t attr2; - pthread_mutexattr_t mut_attr2; - struct sched_param schedparam2; - int schedpolicy = SCHED_FIFO; - int ret, type, protocol, temp; - - schedparam2.sched_priority = 2; - ret = pthread_attr_init(&attr2); - if (ret != 0) { - zassert_false(pthread_attr_destroy(&attr2), - "Unable to destroy pthread object attrib"); - zassert_false(pthread_attr_init(&attr2), "Unable to create pthread object attrib"); - } - - pthread_attr_setstack(&attr2, &stack, STACK_SIZE); - pthread_attr_setschedpolicy(&attr2, schedpolicy); - pthread_attr_setschedparam(&attr2, &schedparam2); - - temp = pthread_mutexattr_settype(&mut_attr2, PTHREAD_MUTEX_RECURSIVE); - zassert_false(temp, "setting mutex2 type is failed"); - temp = pthread_mutex_init(&mutex2, &mut_attr2); - zassert_false(temp, "mutex2 initialization is failed"); - - temp = pthread_mutexattr_gettype(&mut_attr2, &type); - zassert_false(temp, "reading mutex2 type is failed"); - temp = pthread_mutexattr_getprotocol(&mut_attr2, &protocol); - zassert_false(temp, "reading mutex2 protocol is failed"); - - zassert_equal(type, PTHREAD_MUTEX_RECURSIVE, "mutex2 type is not recursive"); - - zassert_equal(protocol, PTHREAD_PRIO_NONE, "mutex2 protocol is not prio_none"); - ret = pthread_create(&thread_2, &attr2, &recursive_mutex_entry, NULL); - - zassert_false(ret, "Thread2 creation failed"); - - pthread_join(thread_2, NULL); - temp = pthread_mutex_destroy(&mutex2); - zassert_false(temp, "Destroying mutex2 is failed"); + test_mutex_common(PTHREAD_MUTEX_RECURSIVE, recursive_mutex_entry); } /** @@ -228,23 +172,19 @@ ZTEST(posix_apis, test_mutex_timedlock) { void *ret; pthread_t th; - pthread_attr_t attr; - - zassert_ok(pthread_attr_init(&attr)); - zassert_ok(pthread_attr_setstack(&attr, &stack, STACK_SIZE)); zassert_ok(pthread_mutex_init(&mutex, NULL)); printk("Expecting timedlock with timeout of %d ms to fail\n", TIMEDLOCK_TIMEOUT_MS); zassert_ok(pthread_mutex_lock(&mutex)); - zassert_ok(pthread_create(&th, &attr, test_mutex_timedlock_fn, &mutex)); + zassert_ok(pthread_create(&th, NULL, test_mutex_timedlock_fn, &mutex)); zassert_ok(pthread_join(th, &ret)); /* ensure timeout occurs */ zassert_equal(ETIMEDOUT, POINTER_TO_INT(ret)); printk("Expecting timedlock with timeout of %d ms to succeed after 100ms\n", TIMEDLOCK_TIMEOUT_MS); - zassert_ok(pthread_create(&th, &attr, test_mutex_timedlock_fn, &mutex)); + zassert_ok(pthread_create(&th, NULL, test_mutex_timedlock_fn, &mutex)); /* unlock before timeout expires */ k_msleep(TIMEDLOCK_TIMEOUT_DELAY_MS); zassert_ok(pthread_mutex_unlock(&mutex)); @@ -253,5 +193,4 @@ ZTEST(posix_apis, test_mutex_timedlock) zassert_ok(POINTER_TO_INT(ret)); zassert_ok(pthread_mutex_destroy(&mutex)); - zassert_ok(pthread_attr_destroy(&attr)); } From 90021b81d5f41edd88afe239552007d16532580a Mon Sep 17 00:00:00 2001 From: Christopher Friedt Date: Mon, 1 Jan 2024 19:20:09 -0500 Subject: [PATCH 1714/3723] tests: posix: common: pthread: do not overspecify pthread_attr_t Much of tests/posix/common still overspecifies pthread_attr_t options. Default thread attributes are perfectly fine for the vast majority of spawned threads in this testsuite, so simply use a NULL pthread_attr_t* argument. This fixes piles of bugs because we have not properly used pthread_attr_destroy() appropriately. This is only a partial cleanup for pthread.c Signed-off-by: Christopher Friedt --- tests/posix/common/src/pthread.c | 20 ++++++++------------ 1 file changed, 8 insertions(+), 12 deletions(-) diff --git a/tests/posix/common/src/pthread.c b/tests/posix/common/src/pthread.c index 16c4af2e360..7cf2405c2b4 100644 --- a/tests/posix/common/src/pthread.c +++ b/tests/posix/common/src/pthread.c @@ -710,7 +710,7 @@ ZTEST(posix_apis, test_sched_policy) } /* get pmin and pmax for policies[policy] */ - for (int i = 0; i < 2; ++i) { + for (int i = 0; i < ARRAY_SIZE(prios); ++i) { errno = 0; if (i == 0) { pmin = sched_get_priority_min(policies[policy]); @@ -749,7 +749,7 @@ ZTEST(posix_apis, test_sched_policy) zassert_equal(pmax, nprio[policy] - 1, "unexpected pmax for %s", policy_names[policy]); /* test happy paths */ - for (int i = 0; i < 2; ++i) { + for (int i = 0; i < ARRAY_SIZE(prios); ++i) { /* create threads with min and max priority levels */ zassert_ok(pthread_attr_init(&attr), "pthread_attr_init() failed for %s (%d) of %s", prios[i], @@ -774,6 +774,10 @@ ZTEST(posix_apis, test_sched_policy) zassert_ok(pthread_join(th, NULL), "pthread_join() failed for %s (%d) of %s", prios[i], param.sched_priority, policy_names[policy]); + + zassert_ok(pthread_attr_destroy(&attr), + "pthread_attr_destroy() failed for %s (%d) of %s", prios[i], + param.sched_priority, policy_names[policy]); } } } @@ -845,12 +849,8 @@ ZTEST(posix_apis, test_pthread_return_val) { pthread_t pth; void *ret = NULL; - pthread_attr_t attr; - - zassert_ok(pthread_attr_init(&attr)); - zassert_ok(pthread_attr_setstack(&attr, &stack_e[0][0], STACKS)); - zassert_ok(pthread_create(&pth, &attr, non_null_retval, NULL)); + zassert_ok(pthread_create(&pth, NULL, non_null_retval, NULL)); zassert_ok(pthread_join(pth, &ret)); zassert_equal(ret, (void *)BIOS_FOOD); } @@ -865,12 +865,8 @@ static void *detached(void *arg) ZTEST(posix_apis, test_pthread_join_detached) { pthread_t pth; - pthread_attr_t attr; - - zassert_ok(pthread_attr_init(&attr)); - zassert_ok(pthread_attr_setstack(&attr, &stack_e[0][0], STACKS)); - zassert_ok(pthread_create(&pth, &attr, detached, NULL)); + zassert_ok(pthread_create(&pth, NULL, detached, NULL)); zassert_ok(pthread_detach(pth)); /* note, this was required to be EINVAL previously but is now undefined behaviour */ zassert_not_equal(0, pthread_join(pth, NULL)); From e14f362547026f03c081733c7fd01d4d1ec4dcb4 Mon Sep 17 00:00:00 2001 From: Christopher Friedt Date: Tue, 2 Jan 2024 06:58:14 -0500 Subject: [PATCH 1715/3723] tests: posix: common: sem: remove overspecified pthread_attr_t Much of tests/posix/common still overspecifies pthread_attr_t options. Default thread attributes are perfectly fine for the vast majority of spawned threads in this testsuite, so simply use a NULL pthread_attr_t* argument. This fixes piles of bugs because we have not properly used pthread_attr_destroy() appropriately. Signed-off-by: Christopher Friedt --- tests/posix/common/src/semaphore.c | 42 +++--------------------------- 1 file changed, 4 insertions(+), 38 deletions(-) diff --git a/tests/posix/common/src/semaphore.c b/tests/posix/common/src/semaphore.c index fef4ddfb0fe..921ddbb4a41 100644 --- a/tests/posix/common/src/semaphore.c +++ b/tests/posix/common/src/semaphore.c @@ -11,15 +11,8 @@ #include #include -#define STACK_SIZE (MAX(1024, PTHREAD_STACK_MIN) + CONFIG_TEST_EXTRA_STACK_SIZE) - -sem_t sema; -void *dummy_sem; - -struct sched_param schedparam; -int schedpolicy = SCHED_FIFO; - -static K_THREAD_STACK_DEFINE(stack, STACK_SIZE); +static sem_t sema; +static void *dummy_sem; static void *child_func(void *p1) { @@ -27,34 +20,12 @@ static void *child_func(void *p1) return NULL; } -void initialize_thread_attr(pthread_attr_t *attr) -{ - int ret; - - schedparam.sched_priority = 1; - - ret = pthread_attr_init(attr); - if (ret != 0) { - zassert_equal(pthread_attr_destroy(attr), 0, - "Unable to destroy pthread object attrib"); - zassert_equal(pthread_attr_init(attr), 0, - "Unable to create pthread object attrib"); - } - - pthread_attr_setstack(attr, &stack, STACK_SIZE); - pthread_attr_setschedpolicy(attr, schedpolicy); - pthread_attr_setschedparam(attr, &schedparam); -} - ZTEST(posix_apis, test_semaphore) { pthread_t thread1, thread2; - pthread_attr_t attr1, attr2; int val, ret; struct timespec abstime; - initialize_thread_attr(&attr1); - /* TESTPOINT: Check if sema value is less than * CONFIG_SEM_VALUE_MAX */ @@ -79,7 +50,7 @@ ZTEST(posix_apis, test_semaphore) zassert_equal(sem_trywait(&sema), -1); zassert_equal(errno, EAGAIN); - ret = pthread_create(&thread1, &attr1, child_func, NULL); + ret = pthread_create(&thread1, NULL, child_func, NULL); zassert_equal(ret, 0, "Thread creation failed"); zassert_equal(clock_gettime(CLOCK_REALTIME, &abstime), 0, @@ -105,9 +76,6 @@ ZTEST(posix_apis, test_semaphore) zassert_equal(sem_destroy(&sema), 0, "semaphore is not destroyed"); - zassert_equal(pthread_attr_destroy(&attr1), 0, - "Unable to destroy pthread object attrib"); - /* TESTPOINT: Initialize sema with 1 */ zassert_equal(sem_init(&sema, 0, 1), 0, "sem_init failed"); zassert_equal(sem_getvalue(&sema, &val), 0); @@ -120,9 +88,7 @@ ZTEST(posix_apis, test_semaphore) /* TESTPOINT: take semaphore which is initialized with 1 */ zassert_equal(sem_trywait(&sema), 0); - initialize_thread_attr(&attr2); - - zassert_equal(pthread_create(&thread2, &attr2, child_func, NULL), 0, + zassert_equal(pthread_create(&thread2, NULL, child_func, NULL), 0, "Thread creation failed"); /* TESTPOINT: Wait and acquire semaphore till thread2 gives */ From 80e3f4aee6d1273ef8b464701f1e13d187baa89b Mon Sep 17 00:00:00 2001 From: Christopher Friedt Date: Tue, 2 Jan 2024 12:25:59 -0500 Subject: [PATCH 1716/3723] tests: posix: common: rwlock: remove overspecified pthread_attr_t Much of tests/posix/common still overspecifies pthread_attr_t options. Default thread attributes are perfectly fine for the vast majority of spawned threads in this testsuite, so simply use a NULL pthread_attr_t* argument. This fixes piles of bugs because we have not properly used pthread_attr_destroy() appropriately. Signed-off-by: Christopher Friedt --- tests/posix/common/src/rwlock.c | 114 ++++++++++++-------------------- 1 file changed, 43 insertions(+), 71 deletions(-) diff --git a/tests/posix/common/src/rwlock.c b/tests/posix/common/src/rwlock.c index 43c573a7007..b7d3ac2abe2 100644 --- a/tests/posix/common/src/rwlock.c +++ b/tests/posix/common/src/rwlock.c @@ -6,59 +6,50 @@ #include +#include #include #include #define N_THR 3 -#define STACKSZ (MAX(1024, PTHREAD_STACK_MIN) + CONFIG_TEST_EXTRA_STACK_SIZE) -K_THREAD_STACK_ARRAY_DEFINE(stack, N_THR, STACKSZ); -pthread_rwlock_t rwlock; +LOG_MODULE_REGISTER(posix_rwlock_test); + +static pthread_rwlock_t rwlock; static void *thread_top(void *p1) { - pthread_t pthread; - uint32_t policy, ret = 0U; - struct sched_param param; - int id = POINTER_TO_INT(p1); - - pthread = (pthread_t) pthread_self(); - pthread_getschedparam(pthread, &policy, ¶m); - printk("Thread %d scheduling policy = %d & priority %d started\n", - id, policy, param.sched_priority); + int ret; + pthread_t id; + id = (pthread_t)pthread_self(); ret = pthread_rwlock_tryrdlock(&rwlock); - if (ret) { - printk("Not able to get RD lock on trying, try again\n"); - zassert_false(pthread_rwlock_rdlock(&rwlock), - "Failed to acquire write lock"); + if (ret != 0) { + LOG_DBG("Not able to get RD lock on trying, try again"); + zassert_ok(pthread_rwlock_rdlock(&rwlock), "Failed to acquire write lock"); } - printk("Thread %d got RD lock\n", id); + LOG_DBG("Thread %d got RD lock", id); usleep(USEC_PER_MSEC); - printk("Thread %d releasing RD lock\n", id); - zassert_false(pthread_rwlock_unlock(&rwlock), "Failed to unlock"); + LOG_DBG("Thread %d releasing RD lock", id); + zassert_ok(pthread_rwlock_unlock(&rwlock), "Failed to unlock"); - printk("Thread %d acquiring WR lock\n", id); + LOG_DBG("Thread %d acquiring WR lock", id); ret = pthread_rwlock_trywrlock(&rwlock); - if (ret != 0U) { - zassert_false(pthread_rwlock_wrlock(&rwlock), - "Failed to acquire WR lock"); + if (ret != 0) { + zassert_ok(pthread_rwlock_wrlock(&rwlock), "Failed to acquire WR lock"); } - printk("Thread %d acquired WR lock\n", id); + LOG_DBG("Thread %d acquired WR lock", id); usleep(USEC_PER_MSEC); - printk("Thread %d releasing WR lock\n", id); - zassert_false(pthread_rwlock_unlock(&rwlock), "Failed to unlock"); - pthread_exit(NULL); + LOG_DBG("Thread %d releasing WR lock", id); + zassert_ok(pthread_rwlock_unlock(&rwlock), "Failed to unlock"); + return NULL; } ZTEST(posix_apis, test_rw_lock) { - int32_t i, ret; - pthread_attr_t attr[N_THR]; - struct sched_param schedparam; + int ret; pthread_t newthread[N_THR]; struct timespec time; void *status; @@ -75,72 +66,53 @@ ZTEST(posix_apis, test_rw_lock) zassert_equal(pthread_rwlock_timedrdlock(&rwlock, &time), EINVAL); zassert_equal(pthread_rwlock_unlock(&rwlock), EINVAL); - zassert_false(pthread_rwlock_init(&rwlock, NULL), - "Failed to create rwlock"); - printk("\nmain acquire WR lock and 3 threads acquire RD lock\n"); - zassert_false(pthread_rwlock_timedwrlock(&rwlock, &time), - "Failed to acquire write lock"); + zassert_ok(pthread_rwlock_init(&rwlock, NULL), "Failed to create rwlock"); + LOG_DBG("main acquire WR lock and 3 threads acquire RD lock"); + zassert_ok(pthread_rwlock_timedwrlock(&rwlock, &time), "Failed to acquire write lock"); /* Creating N preemptive threads in increasing order of priority */ - for (i = 0; i < N_THR; i++) { - zassert_equal(pthread_attr_init(&attr[i]), 0, - "Unable to create pthread object attrib"); - - /* Setting scheduling priority */ - schedparam.sched_priority = i + 1; - pthread_attr_setschedparam(&attr[i], &schedparam); - - /* Setting stack */ - pthread_attr_setstack(&attr[i], &stack[i][0], STACKSZ); - - ret = pthread_create(&newthread[i], &attr[i], thread_top, - INT_TO_POINTER(i)); - zassert_false(ret, "Low memory to thread new thread"); - + for (int i = 0; i < N_THR; i++) { + zassert_ok(pthread_create(&newthread[i], NULL, thread_top, NULL), + "Low memory to thread new thread"); } /* Delay to give change to child threads to run */ usleep(USEC_PER_MSEC); - printk("Parent thread releasing WR lock\n"); - zassert_false(pthread_rwlock_unlock(&rwlock), "Failed to unlock"); + LOG_DBG("Parent thread releasing WR lock"); + zassert_ok(pthread_rwlock_unlock(&rwlock), "Failed to unlock"); /* Let child threads acquire RD Lock */ usleep(USEC_PER_MSEC); - printk("Parent thread acquiring WR lock again\n"); + LOG_DBG("Parent thread acquiring WR lock again"); time.tv_sec = 2; time.tv_nsec = 0; ret = pthread_rwlock_timedwrlock(&rwlock, &time); - if (ret) { - zassert_false(pthread_rwlock_wrlock(&rwlock), - "Failed to acquire write lock"); + zassert_ok(pthread_rwlock_wrlock(&rwlock), "Failed to acquire write lock"); } - printk("Parent thread acquired WR lock again\n"); + LOG_DBG("Parent thread acquired WR lock again"); usleep(USEC_PER_MSEC); - printk("Parent thread releasing WR lock again\n"); - zassert_false(pthread_rwlock_unlock(&rwlock), "Failed to unlock"); + LOG_DBG("Parent thread releasing WR lock again"); + zassert_ok(pthread_rwlock_unlock(&rwlock), "Failed to unlock"); - printk("\n3 threads acquire WR lock\n"); - printk("Main thread acquiring RD lock\n"); + LOG_DBG("3 threads acquire WR lock"); + LOG_DBG("Main thread acquiring RD lock"); ret = pthread_rwlock_timedrdlock(&rwlock, &time); - if (ret != 0) { - zassert_false(pthread_rwlock_rdlock(&rwlock), "Failed to lock"); + zassert_ok(pthread_rwlock_rdlock(&rwlock), "Failed to lock"); } - printk("Main thread acquired RD lock\n"); + LOG_DBG("Main thread acquired RD lock"); usleep(USEC_PER_MSEC); - printk("Main thread releasing RD lock\n"); - zassert_false(pthread_rwlock_unlock(&rwlock), "Failed to unlock"); + LOG_DBG("Main thread releasing RD lock"); + zassert_ok(pthread_rwlock_unlock(&rwlock), "Failed to unlock"); - for (i = 0; i < N_THR; i++) { - zassert_false(pthread_join(newthread[i], &status), - "Failed to join"); + for (int i = 0; i < N_THR; i++) { + zassert_ok(pthread_join(newthread[i], &status), "Failed to join"); } - zassert_false(pthread_rwlock_destroy(&rwlock), - "Failed to destroy rwlock"); + zassert_ok(pthread_rwlock_destroy(&rwlock), "Failed to destroy rwlock"); } From 74468ebc0983e3a68abbf6b5ca65ab516d3a9388 Mon Sep 17 00:00:00 2001 From: Ian Morris Date: Mon, 4 Dec 2023 19:12:27 -0800 Subject: [PATCH 1717/3723] dts: arm: renesas: ra: fix incorrect node name for sci devices The sci devices described in the device tree source for RA MCUs are incorrectly specified as being UARTs when they should be SCIs (serial communication interfaces) which can not only operate as UARTs but also as I2C, SPI etc. Signed-off-by: Ian Morris --- dts/arm/renesas/ra/ra-cm4-common.dtsi | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/dts/arm/renesas/ra/ra-cm4-common.dtsi b/dts/arm/renesas/ra/ra-cm4-common.dtsi index 80e2f877c8a..4ef18141e6c 100644 --- a/dts/arm/renesas/ra/ra-cm4-common.dtsi +++ b/dts/arm/renesas/ra/ra-cm4-common.dtsi @@ -247,7 +247,7 @@ }; sci0: sci@40070000 { - compatible = "renesas,ra-uart-sci"; + compatible = "renesas,ra-sci"; reg = <0x40070000 0x20>; interrupts = , , @@ -266,7 +266,7 @@ }; sci1: sci@40070020 { - compatible = "renesas,ra-uart-sci"; + compatible = "renesas,ra-sci"; reg = <0x40070020 0x20>; interrupts = , , @@ -284,7 +284,7 @@ }; sci9: sci@40070120 { - compatible = "renesas,ra-uart-sci"; + compatible = "renesas,ra-sci"; reg = <0x40070120 0x20>; interrupts = , , From a75f441efaf707bc4eee7f13ef6cb4957cc65ded Mon Sep 17 00:00:00 2001 From: Alberto Escolar Piedras Date: Sat, 23 Dec 2023 13:52:11 +0100 Subject: [PATCH 1718/3723] docs: emulators: Created new emulators page Created new emulators page, and moved the current page to be a page dedicated to bus emulators. Signed-off-by: Alberto Escolar Piedras --- doc/hardware/emulator/bus_emulators.rst | 189 ++++++++++++++++++ doc/hardware/emulator/index.rst | 250 +++++++----------------- doc/hardware/index.rst | 1 + 3 files changed, 266 insertions(+), 174 deletions(-) create mode 100644 doc/hardware/emulator/bus_emulators.rst diff --git a/doc/hardware/emulator/bus_emulators.rst b/doc/hardware/emulator/bus_emulators.rst new file mode 100644 index 00000000000..5baa7dcafff --- /dev/null +++ b/doc/hardware/emulator/bus_emulators.rst @@ -0,0 +1,189 @@ +.. _bus_emul: + +External Bus and Bus Connected Peripherals Emulators +#################################################### + +Overview +======== + +Zephyr supports a simple emulator framework to support testing of drivers +without requiring real hardware. + +Emulators are used to emulate hardware devices, to support testing of +various subsystems. For example, it is possible to write an emulator +for an I2C compass such that it appears on the I2C bus and can be used +just like a real hardware device. + +Emulators often implement special features for testing. For example a +compass may support returning bogus data if the I2C bus speed is too +high, or may return invalid measurements if calibration has not yet +been completed. This allows for testing that high-level code can +handle these situations correctly. Test coverage can therefore +approach 100% if all failure conditions are emulated. + +Concept +======= + +The diagram below shows application code / high-level tests at the top. +This is the ultimate application we want to run. + +.. figure:: img/arch.png + :align: center + :alt: Emulator architecture showing tests, emulators and drivers + +Below that are peripheral drivers, such as the AT24 EEPROM driver. We can test +peripheral drivers using an emulation driver connected via a native_sim I2C +controller/emulator which passes I2C traffic from the AT24 driver to the AT24 +simulator. + +Separately we can test the STM32 and NXP I2C drivers on real hardware using API +tests. These require some sort of device attached to the bus, but with this, we +can validate much of the driver functionality. + +Putting the two together, we can test the application and peripheral code +entirely on native_sim. Since we know that the I2C driver on the real hardware +works, we should expect the application and peripheral drivers to work on the +real hardware also. + +Using the above framework we can test an entire application (e.g. Embedded +Controller) on native_sim using emulators for all non-chip drivers: + +.. figure:: img/app.png + :align: center + :alt: Example system, using emulators to implement a PC EC + +The 'real' code is shown in green. The Zephyr emulation-framework code is shown +in yellow. The blue boxes are the extra code we have to write to emulate the +peripherals. + +With this approach we can: + +* Write individual tests for each driver (green), covering all failure modes, + error conditions, etc. + +* Ensure 100% test coverage for drivers (green) + +* Write tests for combinations of drivers, such as GPIOs provided by an I2C GPIO + expander driver talking over an I2C bus, with the GPIOs controlling a charger. + All of this can work in the emulated environment or on real hardware. + +* Write a complex application that ties together all of these pieces and runs on + native_sim. We can develop on a host, use source-level debugging, etc. + +* Transfer the application to any board which provides the required features + (e.g. I2C, enough GPIOs), by adding Kconfig and devicetree fragments. + +Creating a Device Driver Emulator +================================= + +The emulator subsystem is modeled on the :ref:`device_model_api`. You create +an emulator instance using one of the :c:func:`EMUL_DT_DEFINE()` or +:c:func:`EMUL_DT_INST_DEFINE()` APIs. + +Emulators for peripheral devices reuse the same devicetree node as the real +device driver. This means that your emulator defines `DT_DRV_COMPAT` using the +same ``compat`` value from the real driver. + +.. code-block:: C + + /* From drivers/sensor/bm160/bm160.c */ + #define DT_DRV_COMPAT bosch_bmi160 + + /* From subsys/emul/emul_bmi160.c */ + #define DT_DRV_COMPAT bosch_bmi160 + +The ``EMUL_DT_DEFINE()`` function accepts two API types: + + #. ``bus_api`` - This points to the API for the upstream bus that the emulator + connects to. The ``bus_api`` parameter is required. The supported + emulated bus types include I2C, SPI, and eSPI. + #. ``_backend_api`` - This points to the device-class specific backend API for + the emulator. The ``_backend_api`` parameter is optional. + +The diagram below demonstrates the logical organization of the ``bus_api`` and +``_backend_api`` using the BC1.2 charging detector driver as the model +device-class. + +.. figure:: img/device_class_emulator.png + :align: center + :alt: Device class example, demonstrating BC1.2 charging detectors. + +The real code is shown in green, while the emulator code is shown in yellow. + +The ``bus_api`` connects the BC1.2 emulators to the ``native_sim`` I2C +controller. The real BC1.2 drivers are unchanged and operate exactly as if there +was a physical I2C controller present in the system. The ``native_sim`` I2C +controller uses the ``bus_api`` to initiate register reads and writes to the +emulator. + +The ``_backend_api`` provides a mechanism for tests to manipulate the emulator +out of band. Each device class defines it's own API functions. The backend API +functions focus on high-level behavior and do not provide hooks for specific +emulators. + +In the case of the BC1.2 charging detector the backend API provides functions +to simulate connecting and disconnecting a charger to the emulated BC1.2 device. +Each emulator is responsible for updating the correct vendor specific registers +and potentially signalling an interrupt. + +Example test flow: + + #. Test registers BC1.2 detection callback using the Zephyr BC1.2 driver API. + #. Test connects a charger using the BC1.2 emulator backend. + #. Test verifies B1.2 detection callback invoked with correct charger type. + #. Test disconnects a charger using the BC1.2 emulator backend. + +With this architecture, the same test can be used will all supported drivers in +the same driver class. + +Available Emulators +=================== + +Zephyr includes the following emulators: + +* EEPROM, which uses a file as the EEPROM contents + +* I2C emulator driver, allowing drivers to be connected to an emulator so that + tests can be performed without access to the real hardware + +* SPI emulator driver, which does the same for SPI + +* eSPI emulator driver, which does the same for eSPI. The emulator is being + developed to support more functionalities. + +* CAN loopback driver + +A GPIO emulator is planned but is not yet complete. + +Samples +======= + +Here are some examples present in Zephyr: + +#. Bosch BMI160 sensor driver connected via both I2C and SPI to an emulator: + + .. zephyr-app-commands:: + :app: tests/drivers/sensor/accel/ + :board: native_sim + :goals: build + +#. Simple test of the EEPROM emulator: + + .. zephyr-app-commands:: + :app: tests/drivers/eeprom/api + :board: native_sim + :goals: build + +#. The same test can be built with a second EEPROM which is an Atmel AT24 EEPROM driver + connected via I2C an emulator: + + .. zephyr-app-commands:: + :app: tests/drivers/eeprom/api + :board: native_sim + :goals: build + :gen-args: -DDTC_OVERLAY_FILE=at2x_emul.overlay -DOVERLAY_CONFIG=at2x_emul.conf + +API Reference +************* + +.. doxygengroup:: io_emulators diff --git a/doc/hardware/emulator/index.rst b/doc/hardware/emulator/index.rst index 4373480a3e0..0029de31700 100644 --- a/doc/hardware/emulator/index.rst +++ b/doc/hardware/emulator/index.rst @@ -1,189 +1,91 @@ .. _emulators: -Peripheral and Hardware Emulators -################################# +Zephyr's device emulators/simulators +#################################### Overview ======== -Zephyr supports a simple emulator framework to support testing of drivers -without requiring real hardware. +Zephyr includes in its codebase a set of device emulators/simulators. +With this we refer to SW components which are built together with the embedded SW +and present themselves as devices of a given class to the rest of the system. -Emulators are used to emulate hardware devices, to support testing of -various subsystems. For example, it is possible to write an emulator -for an I2C compass such that it appears on the I2C bus and can be used -just like a real hardware device. +These device emulators/simulators can be built for any target which has sufficient RAM and flash, +even if some may have extra functionality which is only available in some targets. -Emulators often implement special features for testing. For example a -compass may support returning bogus data if the I2C bus speed is too -high, or may return invalid measurements if calibration has not yet -been completed. This allows for testing that high-level code can -handle these situations correctly. Test coverage can therefore -approach 100% if all failure conditions are emulated. +.. note:: -Concept -======= + | Zephyr also includes and uses many other types of simulators/emulators, including CPU and + platform simulators, radio simulators, and several build targets which allow running the + embedded code in the development host. + | Some of Zephyr communication controllers/drivers include also either loopback modes or loopback + devices. + | This page does not cover any of these. -The diagram below shows application code / high-level tests at the top. -This is the ultimate application we want to run. +.. note:: + Drivers which are specific to some platform, like for example the + :ref:`native_sim specific drivers ` which + emulate a peripheral class by connecting to host APIs are not covered by this page. -.. figure:: img/arch.png - :align: center - :alt: Emulator architecture showing tests, emulators and drivers - -Below that are peripheral drivers, such as the AT24 EEPROM driver. We can test -peripheral drivers using an emulation driver connected via a native_sim I2C -controller/emulator which passes I2C traffic from the AT24 driver to the AT24 -simulator. - -Separately we can test the STM32 and NXP I2C drivers on real hardware using API -tests. These require some sort of device attached to the bus, but with this, we -can validate much of the driver functionality. - -Putting the two together, we can test the application and peripheral code -entirely on native_sim. Since we know that the I2C driver on the real hardware -works, we should expect the application and peripheral drivers to work on the -real hardware also. - -Using the above framework we can test an entire application (e.g. Embedded -Controller) on native_sim using emulators for all non-chip drivers: - -.. figure:: img/app.png - :align: center - :alt: Example system, using emulators to implement a PC EC - -The 'real' code is shown in green. The Zephyr emulation-framework code is shown -in yellow. The blue boxes are the extra code we have to write to emulate the -peripherals. - -With this approach we can: - -* Write individual tests for each driver (green), covering all failure modes, - error conditions, etc. - -* Ensure 100% test coverage for drivers (green) - -* Write tests for combinations of drivers, such as GPIOs provided by an I2C GPIO - expander driver talking over an I2C bus, with the GPIOs controlling a charger. - All of this can work in the emulated environment or on real hardware. - -* Write a complex application that ties together all of these pieces and runs on - native_sim. We can develop on a host, use source-level debugging, etc. - -* Transfer the application to any board which provides the required features - (e.g. I2C, enough GPIOs), by adding Kconfig and devicetree fragments. - -Creating a Device Driver Emulator -================================= - -The emulator subsystem is modeled on the :ref:`device_model_api`. You create -an emulator instance using one of the :c:func:`EMUL_DT_DEFINE()` or -:c:func:`EMUL_DT_INST_DEFINE()` APIs. - -Emulators for peripheral devices reuse the same devicetree node as the real -device driver. This means that your emulator defines `DT_DRV_COMPAT` using the -same ``compat`` value from the real driver. - -.. code-block:: C - - /* From drivers/sensor/bm160/bm160.c */ - #define DT_DRV_COMPAT bosch_bmi160 - - /* From subsys/emul/emul_bmi160.c */ - #define DT_DRV_COMPAT bosch_bmi160 - -The ``EMUL_DT_DEFINE()`` function accepts two API types: - - #. ``bus_api`` - This points to the API for the upstream bus that the emulator - connects to. The ``bus_api`` parameter is required. The supported - emulated bus types include I2C, SPI, and eSPI. - #. ``_backend_api`` - This points to the device-class specific backend API for - the emulator. The ``_backend_api`` parameter is optional. - -The diagram below demonstrates the logical organization of the ``bus_api`` and -``_backend_api`` using the BC1.2 charging detector driver as the model -device-class. - -.. figure:: img/device_class_emulator.png - :align: center - :alt: Device class example, demonstrating BC1.2 charging detectors. - -The real code is shown in green, while the emulator code is shown in yellow. - -The ``bus_api`` connects the BC1.2 emulators to the ``native_sim`` I2C -controller. The real BC1.2 drivers are unchanged and operate exactly as if there -was a physical I2C controller present in the system. The ``native_sim`` I2C -controller uses the ``bus_api`` to initiate register reads and writes to the -emulator. - -The ``_backend_api`` provides a mechanism for tests to manipulate the emulator -out of band. Each device class defines it's own API functions. The backend API -functions focus on high-level behavior and do not provide hooks for specific -emulators. - -In the case of the BC1.2 charging detector the backend API provides functions -to simulate connecting and disconnecting a charger to the emulated BC1.2 device. -Each emulator is responsible for updating the correct vendor specific registers -and potentially signalling an interrupt. - -Example test flow: - - #. Test registers BC1.2 detection callback using the Zephyr BC1.2 driver API. - #. Test connects a charger using the BC1.2 emulator backend. - #. Test verifies B1.2 detection callback invoked with correct charger type. - #. Test disconnects a charger using the BC1.2 emulator backend. - -With this architecture, the same test can be used will all supported drivers in -the same driver class. Available Emulators =================== -Zephyr includes the following emulators: - -* EEPROM, which uses a file as the EEPROM contents - -* I2C emulator driver, allowing drivers to be connected to an emulator so that - tests can be performed without access to the real hardware - -* SPI emulator driver, which does the same for SPI - -* eSPI emulator driver, which does the same for eSPI. The emulator is being - developed to support more functionalities. - -* CAN loopback driver - -A GPIO emulator is planned but is not yet complete. - -Samples -======= - -Here are some examples present in Zephyr: - -#. Bosch BMI160 sensor driver connected via both I2C and SPI to an emulator: - - .. zephyr-app-commands:: - :app: tests/drivers/sensor/accel/ - :board: native_sim - :goals: build - -#. Simple test of the EEPROM emulator: - - .. zephyr-app-commands:: - :app: tests/drivers/eeprom/api - :board: native_sim - :goals: build - -#. The same test can be built with a second EEPROM which is an Atmel AT24 EEPROM driver - connected via I2C an emulator: - - .. zephyr-app-commands:: - :app: tests/drivers/eeprom/api - :board: native_sim - :goals: build - :gen-args: -DDTC_OVERLAY_FILE=at2x_emul.overlay -DOVERLAY_CONFIG=at2x_emul.conf - -API Reference -************* - -.. doxygengroup:: io_emulators +**ADC emulator** + * A fake driver which pretends to be actual ADC, and can be used for testing higher-level API + for ADC devices. + * Main Kconfig option: :kconfig:option:`CONFIG_ADC_EMUL` + * DT binding: :dtcompatible:`zephyr,adc-emul` + +**DMA emulator** + * Emulated DMA controller + * Main Kconfig option: :kconfig:option:`CONFIG_DMA_EMUL` + * DT binding: :dtcompatible:`zephyr,dma-emul` + +**EEPROM emulator** + * Emulate an EEPROM on a flash partition + * Main Kconfig option: :kconfig:option:`CONFIG_EEPROM_EMULATOR` + * DT binding: :dtcompatible:`zephyr,emu-eeprom` + +**EEPROM simulator** + * Emulate an EEPROM on RAM + * Main Kconfig option: :kconfig:option:`CONFIG_EEPROM_SIMULATOR` + * DT binding: :dtcompatible:`zephyr,sim-eeprom` + * Note: For :ref:`native targets ` it is also possible to keep the content + as a file on the host filesystem. + +**External bus and bus connected peripheral emulators** + * :ref:`Documentation ` + * Allow emulating external buses like I2C or SPI and peripherals connected to them. + +**Flash simulator** + * Emulate a flash on RAM + * Main Kconfig option: :kconfig:option:`CONFIG_FLASH_SIMULATOR` + * DT binding: :dtcompatible:`zephyr,sim-flash` + * Note: For native targets it is also possible to keep the content as a file on the host + filesystem. Check :ref:`the native_sim flash simulator section `. + +**GPIO emulator** + * Emulated GPIO controllers which can be driven from SW + * Main Kconfig option: :kconfig:option:`CONFIG_GPIO_EMUL` + * DT binding: :dtcompatible:`zephyr,gpio-emul` + +**I2C emulator** + * Emulated I2C bus. See :ref:`bus emulators `. + * Main Kconfig option: :kconfig:option:`CONFIG_I2C_EMUL` + * DT binding: :dtcompatible:`zephyr,i2c-emul-controller` + +**RTC emulator** + * Emulates an RTC with a timed work-queue item. + * Main Kconfig option: :kconfig:option:`CONFIG_RTC_EMUL` + * DT binding: :dtcompatible:`zephyr,rtc-emul` + +**SPI emulator** + * Emulated SPI bus. See :ref:`bus emulators `. + * Main Kconfig option: :kconfig:option:`CONFIG_SPI_EMUL` + * DT binding: :dtcompatible:`zephyr,spi-emul-controller` + +**UART emulator** + * Emulated UART bus. See :ref:`bus emulators `. + * Main Kconfig option: :kconfig:option:`CONFIG_UART_EMUL` + * DT binding: :dtcompatible:`zephyr,uart-emul` diff --git a/doc/hardware/index.rst b/doc/hardware/index.rst index c9ba1c92f8a..72e9cc5fd05 100644 --- a/doc/hardware/index.rst +++ b/doc/hardware/index.rst @@ -10,6 +10,7 @@ Hardware Support barriers/index.rst cache/index.rst emulator/index.rst + emulator/bus_emulators.rst peripherals/index.rst pinctrl/index.rst porting/index From 4f41a34f12e6d80c4634b8798d162d126d666cf3 Mon Sep 17 00:00:00 2001 From: Alberto Escolar Piedras Date: Sat, 23 Dec 2023 15:19:30 +0100 Subject: [PATCH 1719/3723] docs: Bus emulators: Limit content to only bus emulation Limit the content of this page to only cover the bus emulators and their peripherals. Until now, there was some out of place references to emulators of a completely different type which did not match the descriptions in this page. Signed-off-by: Alberto Escolar Piedras --- doc/hardware/emulator/bus_emulators.rst | 17 ++--------------- 1 file changed, 2 insertions(+), 15 deletions(-) diff --git a/doc/hardware/emulator/bus_emulators.rst b/doc/hardware/emulator/bus_emulators.rst index 5baa7dcafff..93201c2b826 100644 --- a/doc/hardware/emulator/bus_emulators.rst +++ b/doc/hardware/emulator/bus_emulators.rst @@ -6,10 +6,10 @@ External Bus and Bus Connected Peripherals Emulators Overview ======== -Zephyr supports a simple emulator framework to support testing of drivers +Zephyr supports a simple emulator framework to support testing of external peripheral drivers without requiring real hardware. -Emulators are used to emulate hardware devices, to support testing of +Emulators are used to emulate external hardware devices, to support testing of various subsystems. For example, it is possible to write an emulator for an I2C compass such that it appears on the I2C bus and can be used just like a real hardware device. @@ -141,8 +141,6 @@ Available Emulators Zephyr includes the following emulators: -* EEPROM, which uses a file as the EEPROM contents - * I2C emulator driver, allowing drivers to be connected to an emulator so that tests can be performed without access to the real hardware @@ -151,10 +149,6 @@ Zephyr includes the following emulators: * eSPI emulator driver, which does the same for eSPI. The emulator is being developed to support more functionalities. -* CAN loopback driver - -A GPIO emulator is planned but is not yet complete. - Samples ======= @@ -167,13 +161,6 @@ Here are some examples present in Zephyr: :board: native_sim :goals: build -#. Simple test of the EEPROM emulator: - - .. zephyr-app-commands:: - :app: tests/drivers/eeprom/api - :board: native_sim - :goals: build - #. The same test can be built with a second EEPROM which is an Atmel AT24 EEPROM driver connected via I2C an emulator: From 5cc190228dd790b871cca1763c6afbc1379caea4 Mon Sep 17 00:00:00 2001 From: Alberto Escolar Piedras Date: Sat, 23 Dec 2023 15:52:53 +0100 Subject: [PATCH 1720/3723] docs: Bus emulators: Misc fixes * Convert png figures to svg * Remove app.png and the paragraph which elaborated on it. (It was very specific to some particular user case, and having it did not improve understanding) * Correct all references to "native_posix drivers" to the be just "emulated drivers" (they are not native_sim specific) * Correct path for a file which was moved Signed-off-by: Alberto Escolar Piedras --- doc/hardware/emulator/bus_emulators.rst | 18 +++++------------- doc/hardware/emulator/img/app.png | Bin 54403 -> 0 bytes doc/hardware/emulator/img/arch.png | Bin 31742 -> 0 bytes doc/hardware/emulator/img/arch.svg | 4 ++++ .../emulator/img/device_class_emulator.png | Bin 30794 -> 0 bytes .../emulator/img/device_class_emulator.svg | 4 ++++ 6 files changed, 13 insertions(+), 13 deletions(-) delete mode 100644 doc/hardware/emulator/img/app.png delete mode 100644 doc/hardware/emulator/img/arch.png create mode 100644 doc/hardware/emulator/img/arch.svg delete mode 100644 doc/hardware/emulator/img/device_class_emulator.png create mode 100644 doc/hardware/emulator/img/device_class_emulator.svg diff --git a/doc/hardware/emulator/bus_emulators.rst b/doc/hardware/emulator/bus_emulators.rst index 93201c2b826..3568b0abbdc 100644 --- a/doc/hardware/emulator/bus_emulators.rst +++ b/doc/hardware/emulator/bus_emulators.rst @@ -27,12 +27,12 @@ Concept The diagram below shows application code / high-level tests at the top. This is the ultimate application we want to run. -.. figure:: img/arch.png +.. figure:: img/arch.svg :align: center :alt: Emulator architecture showing tests, emulators and drivers Below that are peripheral drivers, such as the AT24 EEPROM driver. We can test -peripheral drivers using an emulation driver connected via a native_sim I2C +peripheral drivers using an emulation driver connected via a emulated I2C controller/emulator which passes I2C traffic from the AT24 driver to the AT24 simulator. @@ -46,15 +46,7 @@ works, we should expect the application and peripheral drivers to work on the real hardware also. Using the above framework we can test an entire application (e.g. Embedded -Controller) on native_sim using emulators for all non-chip drivers: - -.. figure:: img/app.png - :align: center - :alt: Example system, using emulators to implement a PC EC - -The 'real' code is shown in green. The Zephyr emulation-framework code is shown -in yellow. The blue boxes are the extra code we have to write to emulate the -peripherals. +Controller) on native_sim using emulators for all non-chip drivers. With this approach we can: @@ -89,7 +81,7 @@ same ``compat`` value from the real driver. /* From drivers/sensor/bm160/bm160.c */ #define DT_DRV_COMPAT bosch_bmi160 - /* From subsys/emul/emul_bmi160.c */ + /* From drivers/sensor/bmi160/emul_bmi160.c */ #define DT_DRV_COMPAT bosch_bmi160 The ``EMUL_DT_DEFINE()`` function accepts two API types: @@ -104,7 +96,7 @@ The diagram below demonstrates the logical organization of the ``bus_api`` and ``_backend_api`` using the BC1.2 charging detector driver as the model device-class. -.. figure:: img/device_class_emulator.png +.. figure:: img/device_class_emulator.svg :align: center :alt: Device class example, demonstrating BC1.2 charging detectors. diff --git a/doc/hardware/emulator/img/app.png b/doc/hardware/emulator/img/app.png deleted file mode 100644 index 25173530ca205e71fc3b3ef78096a14a6f26b9cb..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 54403 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 z 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 Uzm919uYq)Uy85}Sb4q9e0LC5=PXGV_ diff --git a/doc/hardware/emulator/img/arch.png b/doc/hardware/emulator/img/arch.png deleted file mode 100644 index eac62bf9da65553285fe6abfd462fdd1107e7cfa..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 31742 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 diff --git a/doc/hardware/emulator/img/arch.svg b/doc/hardware/emulator/img/arch.svg new file mode 100644 index 00000000000..6aa5e703a70 --- /dev/null +++ b/doc/hardware/emulator/img/arch.svg @@ -0,0 +1,4 @@ + + + +
Application
code / tests
Application...
Peripheral drivers
Peripheral drivers
Bus controller emulator
Bus controller em...
Peripheral
emulator
Peripheral...
API tests
API tests
STM32 drivers
STM32 drivers
NXP drivers
NXP drivers
STM32
HW
STM32...
NXP
HW
NXP...
Text is not SVG - cannot display
\ No newline at end of file diff --git a/doc/hardware/emulator/img/device_class_emulator.png b/doc/hardware/emulator/img/device_class_emulator.png deleted file mode 100644 index ad64956fe6859dedaf9a0d3bf5934026aece3f6f..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 30794 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: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 + + +
Tests
Tests
BC1.2 Driver API
BC1.2 Driver API
Diodes
BC1.2 Driver
Diodes...
Mediatek BC1.2 Driver
Mediatek BC1....
I2C controller emulator
I2C controlle...
Diodes BC1.2 Emulator
Diodes BC1.2...
Mediatek BC1.2 Emulator
Mediatek BC1....
bus_api
bus_api
BC1.2 Backend API
BC1.2 Backend API
_backend API
_backend API
Text is not SVG - cannot display
\ No newline at end of file From 312e000a5fd1a05fe8422300af5c4452e2a69e25 Mon Sep 17 00:00:00 2001 From: Robert Lubos Date: Wed, 3 Jan 2024 15:32:03 +0100 Subject: [PATCH 1721/3723] tests: net: socket: tls: Fix race on TCP socket close One of the tests closed the underlying TCP connection right after establishing one. This caused a certain race between incoming TLS handshake data and entering FIN1 state (experienced on nrF52840), where the TLS handshake data could be received after the FIN1 state was entered, causing the server side to send RST packet. This disrupted the test flow, as graceful TCP connection teardown was expected. Fix this, by adding a small delay for such case to avoid the race. Signed-off-by: Robert Lubos --- tests/net/socket/tls/src/main.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/tests/net/socket/tls/src/main.c b/tests/net/socket/tls/src/main.c index 1e81e2eb6f3..d5e9d6721bc 100644 --- a/tests/net/socket/tls/src/main.c +++ b/tests/net/socket/tls/src/main.c @@ -809,6 +809,10 @@ static void fake_tcp_server_work(struct k_work *work) test_accept(data->sock, &new_sock, NULL, 0); if (!data->reply) { + /* Add small delay to avoid race between incoming data and + * sending FIN. + */ + k_msleep(10); goto out; } From e517af4cff25c27deedfbd40f472b209f2f8621b Mon Sep 17 00:00:00 2001 From: Fabio Baltieri Date: Sun, 6 Aug 2023 23:33:37 +0100 Subject: [PATCH 1722/3723] charger: add a driver for bq25180 Add a driver for the TI BQ25180. Implement enable/disable and current set/get. Signed-off-by: Fabio Baltieri --- drivers/charger/CMakeLists.txt | 1 + drivers/charger/Kconfig | 1 + drivers/charger/Kconfig.bq25180 | 11 ++ drivers/charger/charger_bq25180.c | 218 +++++++++++++++++++++++ dts/bindings/charger/ti,bq25180.yaml | 30 ++++ tests/drivers/build_all/charger/i2c.dtsi | 6 + 6 files changed, 267 insertions(+) create mode 100644 drivers/charger/Kconfig.bq25180 create mode 100644 drivers/charger/charger_bq25180.c create mode 100644 dts/bindings/charger/ti,bq25180.yaml diff --git a/drivers/charger/CMakeLists.txt b/drivers/charger/CMakeLists.txt index ce70f0590c6..60b80b0ed25 100644 --- a/drivers/charger/CMakeLists.txt +++ b/drivers/charger/CMakeLists.txt @@ -4,6 +4,7 @@ zephyr_library() zephyr_syscall_header(${ZEPHYR_BASE}/include/zephyr/drivers/charger.h) zephyr_library_sources_ifdef(CONFIG_CHARGER_BQ24190 charger_bq24190.c) +zephyr_library_sources_ifdef(CONFIG_CHARGER_BQ25180 charger_bq25180.c) zephyr_library_sources_ifdef(CONFIG_CHARGER_MAX20335 charger_max20335.c) zephyr_library_sources_ifdef(CONFIG_SBS_CHARGER sbs_charger.c) zephyr_library_sources_ifdef(CONFIG_USERSPACE charger_handlers.c) diff --git a/drivers/charger/Kconfig b/drivers/charger/Kconfig index 9c7873168a5..ce2c3d8b8d3 100644 --- a/drivers/charger/Kconfig +++ b/drivers/charger/Kconfig @@ -21,6 +21,7 @@ config CHARGER_INIT_PRIORITY source "drivers/charger/Kconfig.sbs_charger" source "drivers/charger/Kconfig.bq24190" +source "drivers/charger/Kconfig.bq25180" source "drivers/charger/Kconfig.max20335" endif # CHARGER diff --git a/drivers/charger/Kconfig.bq25180 b/drivers/charger/Kconfig.bq25180 new file mode 100644 index 00000000000..44bdc9b32ee --- /dev/null +++ b/drivers/charger/Kconfig.bq25180 @@ -0,0 +1,11 @@ +# Copyright 2024 Google LLC +# +# SPDX-License-Identifier: Apache-2.0 + +config CHARGER_BQ25180 + bool "BQ25180 Battery Charger" + default y + depends on DT_HAS_TI_BQ25180_ENABLED + select I2C + help + Enable BQ25180 battery charger driver. diff --git a/drivers/charger/charger_bq25180.c b/drivers/charger/charger_bq25180.c new file mode 100644 index 00000000000..7063377c589 --- /dev/null +++ b/drivers/charger/charger_bq25180.c @@ -0,0 +1,218 @@ +/* + * Copyright 2024 Google LLC + * + * SPDX-License-Identifier: Apache-2.0 + * + * BQ25180 Datasheet: https://www.ti.com/lit/gpn/bq25180 + */ + +#define DT_DRV_COMPAT ti_bq25180 + +#include +#include +#include +#include +#include +#include + +LOG_MODULE_REGISTER(bq25180, CONFIG_CHARGER_LOG_LEVEL); + +#define BQ25180_STAT0 0x00 +#define BQ25180_STAT1 0x01 +#define BQ25180_FLAG0 0x02 +#define BQ25180_VBAT_CTRL 0x03 +#define BQ25180_ICHG_CTRL 0x04 +#define BQ25180_IC_CTRL 0x07 +#define BQ25180_SHIP_RST 0x09 +#define BQ25180_MASK_ID 0x0c + +#define BQ25180_ICHG_CHG_DIS BIT(7) +#define BQ25180_ICHG_MSK GENMASK(6, 0) +#define BQ25180_WATCHDOG_SEL_1_MSK GENMASK(1, 0) +#define BQ25180_WATCHDOG_DISABLE 0x03 +#define BQ25180_DEVICE_ID_MSK GENMASK(3, 0) +#define BQ25180_DEVICE_ID 0x00 +#define BQ25180_SHIP_RST_EN_RST_SHIP_MSK GENMASK(6, 5) +#define BQ25180_SHIP_RST_EN_RST_SHIP_ADAPTER 0x20 +#define BQ25180_SHIP_RST_EN_RST_SHIP_BUTTON 0x40 + +/* Charging current limits */ +#define BQ25180_CURRENT_MIN_MA 5 +#define BQ25180_CURRENT_MAX_MA 1000 + +struct bq25180_config { + struct i2c_dt_spec i2c; + uint32_t initial_current_microamp; +}; + +/* + * For ICHG <= 35mA = ICHGCODE + 5mA + * For ICHG > 35mA = 40 + ((ICHGCODE-31)*10)mA. + * Maximum programmable current = 1000mA + * + * Return: value between 0 and 127, negative on error. + */ +static int bq25180_ma_to_ichg(uint32_t current_ma, uint8_t *ichg) +{ + if (!IN_RANGE(current_ma, BQ25180_CURRENT_MIN_MA, BQ25180_CURRENT_MAX_MA)) { + LOG_WRN("charging current out of range: %dmA, " + "clamping to the nearest limit", current_ma); + } + current_ma = CLAMP(current_ma, BQ25180_CURRENT_MIN_MA, BQ25180_CURRENT_MAX_MA); + + if (current_ma <= 35) { + *ichg = current_ma - 5; + return 0; + } + + *ichg = (current_ma - 40) / 10 + 31; + + return 0; +} + +static uint32_t bq25180_ichg_to_ma(uint8_t ichg) +{ + ichg &= BQ25180_ICHG_MSK; + + if (ichg <= 30) { + return (ichg + 5); + } + + return (ichg - 31) * 10 + 40; +} + +static int bq25183_charge_enable(const struct device *dev, const bool enable) +{ + const struct bq25180_config *cfg = dev->config; + uint8_t value = enable ? 0 : BQ25180_ICHG_CHG_DIS; + int ret; + + ret = i2c_reg_update_byte_dt(&cfg->i2c, BQ25180_ICHG_CTRL, + BQ25180_ICHG_CHG_DIS, value); + if (ret < 0) { + return ret; + } + + return 0; +} + +static int bq25180_set_charge_current(const struct device *dev, + uint32_t const_charge_current_ua) +{ + const struct bq25180_config *cfg = dev->config; + uint8_t val; + int ret; + + ret = bq25180_ma_to_ichg(const_charge_current_ua / 1000, &val); + if (ret < 0) { + return ret; + } + + ret = i2c_reg_update_byte_dt(&cfg->i2c, BQ25180_ICHG_CTRL, + BQ25180_ICHG_MSK, val); + if (ret < 0) { + return ret; + } + + return 0; +} + +static int bq25180_get_charge_current(const struct device *dev, + uint32_t *const_charge_current_ua) +{ + const struct bq25180_config *cfg = dev->config; + uint8_t val; + int ret; + + ret = i2c_reg_read_byte_dt(&cfg->i2c, BQ25180_ICHG_CTRL, &val); + if (ret < 0) { + return ret; + } + + *const_charge_current_ua = bq25180_ichg_to_ma(val) * 1000; + + return 0; +} + +static int bq25180_get_prop(const struct device *dev, charger_prop_t prop, + union charger_propval *val) +{ + switch (prop) { + case CHARGER_PROP_CONSTANT_CHARGE_CURRENT_UA: + return bq25180_get_charge_current(dev, &val->const_charge_current_ua); + default: + return -ENOTSUP; + } +} + +static int bq25180_set_prop(const struct device *dev, charger_prop_t prop, + const union charger_propval *val) +{ + switch (prop) { + case CHARGER_PROP_CONSTANT_CHARGE_CURRENT_UA: + return bq25180_set_charge_current(dev, val->const_charge_current_ua); + default: + return -ENOTSUP; + } +} + +static const struct charger_driver_api bq25180_api = { + .get_property = bq25180_get_prop, + .set_property = bq25180_set_prop, + .charge_enable = bq25183_charge_enable, +}; + +static int bq25180_init(const struct device *dev) +{ + const struct bq25180_config *cfg = dev->config; + uint8_t val; + int ret; + + ret = i2c_reg_read_byte_dt(&cfg->i2c, BQ25180_MASK_ID, &val); + if (ret < 0) { + return ret; + } + + val &= BQ25180_DEVICE_ID_MSK; + if (val != BQ25180_DEVICE_ID) { + LOG_ERR("Invalid device id: %02x", val); + return -EINVAL; + } + + /* Disable the watchdog */ + ret = i2c_reg_update_byte_dt(&cfg->i2c, BQ25180_IC_CTRL, + BQ25180_WATCHDOG_SEL_1_MSK, + BQ25180_WATCHDOG_DISABLE); + if (ret < 0) { + return ret; + } + + if (cfg->initial_current_microamp > 0) { + ret = bq25180_ma_to_ichg(cfg->initial_current_microamp / 1000, &val); + if (ret < 0) { + return ret; + } + + ret = i2c_reg_update_byte_dt(&cfg->i2c, BQ25180_ICHG_CTRL, + BQ25180_ICHG_MSK, val); + if (ret < 0) { + return ret; + } + } + + return 0; +} + +#define CHARGER_BQ25180_INIT(inst) \ + static const struct bq25180_config bq25180_config_##inst = { \ + .i2c = I2C_DT_SPEC_INST_GET(inst), \ + .initial_current_microamp = DT_INST_PROP( \ + inst, constant_charge_current_max_microamp), \ + }; \ + \ + DEVICE_DT_INST_DEFINE(inst, bq25180_init, NULL, NULL, \ + &bq25180_config_##inst, POST_KERNEL, \ + CONFIG_CHARGER_INIT_PRIORITY, \ + &bq25180_api); + +DT_INST_FOREACH_STATUS_OKAY(CHARGER_BQ25180_INIT) diff --git a/dts/bindings/charger/ti,bq25180.yaml b/dts/bindings/charger/ti,bq25180.yaml new file mode 100644 index 00000000000..be3b336aa50 --- /dev/null +++ b/dts/bindings/charger/ti,bq25180.yaml @@ -0,0 +1,30 @@ +# Copyright 2024 Google LLC +# SPDX-License-Identifier: Apache-2.0 + +description: | + BQ25180 I2C Controlled, 1-Cell, 1-A Linear Battery Charger with Power Path + and Ship Mode. + + The device has a single child node for the charger. For example: + + bq25180@6a { + compatible = "ti,bq25180"; + reg = <0x6a>; + + constant-charge-current-max-microamp = <500000>; + }; + +compatible: "ti,bq25180" + +include: [battery.yaml, i2c-device.yaml] + + +properties: + constant-charge-current-max-microamp: + type: int + default: 0 + description: | + Charge current set at init time in uA, available range is 5 mA to 800 mA. + The value specified will be rounded down to the closest implemented + value. If set to 0 (default) skip setting the charge current value at + driver initialization. diff --git a/tests/drivers/build_all/charger/i2c.dtsi b/tests/drivers/build_all/charger/i2c.dtsi index c30efdcfcb8..b6365e97470 100644 --- a/tests/drivers/build_all/charger/i2c.dtsi +++ b/tests/drivers/build_all/charger/i2c.dtsi @@ -28,3 +28,9 @@ max20335@1 { constant-charge-voltage-max-microvolt = <4050000>; }; }; + +bq25180@2 { + compatible = "ti,bq25180"; + reg = <0x2>; + constant-charge-current-max-microamp = <500000>; +}; From ef867e4c7e2882cbd4b901cc0d537e0fe440ae5c Mon Sep 17 00:00:00 2001 From: Jeppe Odgaard Date: Mon, 4 Sep 2023 09:13:59 +0200 Subject: [PATCH 1723/3723] drivers: spi: align dspi and lpspi spi_mcux_transfer_next_packet Add return code to lpspi spi_mcux_transfer_next_packet and print the kStatus_* return code since it information is lost when translated to errno. Signed-off-by: Jeppe Odgaard --- drivers/spi/spi_mcux_dspi.c | 6 +++--- drivers/spi/spi_mcux_lpspi.c | 14 ++++++++++---- 2 files changed, 13 insertions(+), 7 deletions(-) diff --git a/drivers/spi/spi_mcux_dspi.c b/drivers/spi/spi_mcux_dspi.c index 63bccd70499..14d47db4dd9 100644 --- a/drivers/spi/spi_mcux_dspi.c +++ b/drivers/spi/spi_mcux_dspi.c @@ -195,11 +195,11 @@ static int spi_mcux_transfer_next_packet(const struct device *dev) status = DSPI_MasterTransferNonBlocking(base, &data->handle, &transfer); if (status != kStatus_Success) { - LOG_ERR("Transfer could not start"); + LOG_ERR("Transfer could not start on %s: %d", dev->name, status); + return status == kDSPI_Busy ? -EBUSY : -EINVAL; } - return status == kStatus_Success ? 0 : - status == kDSPI_Busy ? -EBUSY : -EINVAL; + return 0; } static void spi_mcux_isr(const struct device *dev) diff --git a/drivers/spi/spi_mcux_lpspi.c b/drivers/spi/spi_mcux_lpspi.c index 9bda7a98c9b..e1155be3d7c 100644 --- a/drivers/spi/spi_mcux_lpspi.c +++ b/drivers/spi/spi_mcux_lpspi.c @@ -81,7 +81,7 @@ struct spi_mcux_data { #endif }; -static void spi_mcux_transfer_next_packet(const struct device *dev) +static int spi_mcux_transfer_next_packet(const struct device *dev) { const struct spi_mcux_config *config = dev->config; struct spi_mcux_data *data = dev->data; @@ -94,7 +94,7 @@ static void spi_mcux_transfer_next_packet(const struct device *dev) /* nothing left to rx or tx, we're done! */ spi_context_cs_control(&data->ctx, false); spi_context_complete(&data->ctx, dev, 0); - return; + return 0; } transfer.configFlags = kLPSPI_MasterPcsContinuous | @@ -144,8 +144,11 @@ static void spi_mcux_transfer_next_packet(const struct device *dev) status = LPSPI_MasterTransferNonBlocking(base, &data->handle, &transfer); if (status != kStatus_Success) { - LOG_ERR("Transfer could not start"); + LOG_ERR("Transfer could not start on %s: %d", dev->name, status); + return status == kStatus_LPSPI_Busy ? -EBUSY : -EINVAL; } + + return 0; } static void spi_mcux_isr(const struct device *dev) @@ -582,7 +585,10 @@ static int transceive(const struct device *dev, spi_context_cs_control(&data->ctx, true); - spi_mcux_transfer_next_packet(dev); + ret = spi_mcux_transfer_next_packet(dev); + if (ret) { + goto out; + } ret = spi_context_wait_for_completion(&data->ctx); out: From 734adf52c6034d1d2d36468b6bfe708019d11c2e Mon Sep 17 00:00:00 2001 From: Chekhov Ma Date: Wed, 13 Dec 2023 11:40:51 +0800 Subject: [PATCH 1724/3723] driver: mucx_lpi2c: enable runtime mmio configuration Enable runtime mmio configuration in mcux_lpi2c driver. The fsl_lpi2c driver relies on physical address to determine instance number. So mmap flag 'K_MEM_DIRECT_MAP' is required. Signed-off-by: Chekhov Ma --- drivers/i2c/i2c_mcux_lpi2c.c | 62 +++++++++++++++++++++--------------- 1 file changed, 37 insertions(+), 25 deletions(-) diff --git a/drivers/i2c/i2c_mcux_lpi2c.c b/drivers/i2c/i2c_mcux_lpi2c.c index cc6d7954b58..e1706e3af27 100644 --- a/drivers/i2c/i2c_mcux_lpi2c.c +++ b/drivers/i2c/i2c_mcux_lpi2c.c @@ -32,8 +32,13 @@ LOG_MODULE_REGISTER(mcux_lpi2c); */ #define SCAN_DELAY_US(baudrate) (12 * USEC_PER_SEC / baudrate) +/* Required by DEVICE_MMIO_NAMED_* macros */ +#define DEV_CFG(_dev) \ + ((const struct mcux_lpi2c_config *)(_dev)->config) +#define DEV_DATA(_dev) ((struct mcux_lpi2c_data *)(_dev)->data) + struct mcux_lpi2c_config { - LPI2C_Type *base; + DEVICE_MMIO_NAMED_ROM(reg_base); const struct device *clock_dev; clock_control_subsys_t clock_subsys; void (*irq_config_func)(const struct device *dev); @@ -47,6 +52,7 @@ struct mcux_lpi2c_config { }; struct mcux_lpi2c_data { + DEVICE_MMIO_NAMED_RAM(reg_base); lpi2c_master_handle_t handle; struct k_sem lock; struct k_sem device_sync_sem; @@ -66,7 +72,7 @@ static int mcux_lpi2c_configure(const struct device *dev, { const struct mcux_lpi2c_config *config = dev->config; struct mcux_lpi2c_data *data = dev->data; - LPI2C_Type *base = config->base; + LPI2C_Type *base = (LPI2C_Type *)DEVICE_MMIO_NAMED_GET(dev, reg_base); uint32_t clock_freq; uint32_t baudrate; int ret; @@ -138,11 +144,11 @@ static uint32_t mcux_lpi2c_convert_flags(int msg_flags) } static int mcux_lpi2c_transfer(const struct device *dev, struct i2c_msg *msgs, - uint8_t num_msgs, uint16_t addr) + uint8_t num_msgs, uint16_t addr) { const struct mcux_lpi2c_config *config = dev->config; struct mcux_lpi2c_data *data = dev->data; - LPI2C_Type *base = config->base; + LPI2C_Type *base = (LPI2C_Type *)DEVICE_MMIO_NAMED_GET(dev, reg_base); lpi2c_master_transfer_t transfer; status_t status; int ret = 0; @@ -306,6 +312,7 @@ static void mcux_lpi2c_slave_irq_handler(const struct device *dev) { const struct mcux_lpi2c_config *config = dev->config; struct mcux_lpi2c_data *data = dev->data; + LPI2C_Type *base = (LPI2C_Type *)DEVICE_MMIO_NAMED_GET(dev, reg_base); const struct i2c_target_callbacks *target_cb = data->target_cfg->callbacks; int ret; uint32_t flags; @@ -319,11 +326,11 @@ static void mcux_lpi2c_slave_irq_handler(const struct device *dev) * every byte. For these reason, we handle the LPI2C IRQ * directly. */ - flags = LPI2C_SlaveGetStatusFlags(config->base); + flags = LPI2C_SlaveGetStatusFlags(base); if (flags & kLPI2C_SlaveAddressValidFlag) { /* Read Slave address to clear flag */ - LPI2C_SlaveGetReceivedAddress(config->base); + LPI2C_SlaveGetReceivedAddress(base); data->first_tx = true; /* Reset to sending ACK, in case we NAK'ed before */ data->send_ack = true; @@ -384,26 +391,27 @@ static void mcux_lpi2c_slave_irq_handler(const struct device *dev) } if (flags & kLPI2C_SlaveStopDetectFlag) { - LPI2C_SlaveClearStatusFlags(config->base, flags); + LPI2C_SlaveClearStatusFlags(base, flags); if (target_cb->stop) { target_cb->stop(data->target_cfg); } } if (flags & kLPI2C_SlaveTransmitAckFlag) { - LPI2C_SlaveTransmitAck(config->base, data->send_ack); + LPI2C_SlaveTransmitAck(base, data->send_ack); } } static int mcux_lpi2c_target_register(const struct device *dev, - struct i2c_target_config *target_config) + struct i2c_target_config *target_config) { const struct mcux_lpi2c_config *config = dev->config; struct mcux_lpi2c_data *data = dev->data; + LPI2C_Type *base = (LPI2C_Type *)DEVICE_MMIO_NAMED_GET(dev, reg_base); lpi2c_slave_config_t slave_config; uint32_t clock_freq; - LPI2C_MasterDeinit(config->base); + LPI2C_MasterDeinit(base); /* Get the clock frequency */ if (clock_control_get_rate(config->clock_dev, config->clock_subsys, @@ -430,11 +438,11 @@ static int mcux_lpi2c_target_register(const struct device *dev, * this behavior may cause issues with some I2C controllers. */ slave_config.sclStall.enableAck = true; - LPI2C_SlaveInit(config->base, &slave_config, clock_freq); + LPI2C_SlaveInit(base, &slave_config, clock_freq); /* Clear all flags. */ - LPI2C_SlaveClearStatusFlags(config->base, (uint32_t)kLPI2C_SlaveClearFlags); + LPI2C_SlaveClearStatusFlags(base, (uint32_t)kLPI2C_SlaveClearFlags); /* Enable interrupt */ - LPI2C_SlaveEnableInterrupts(config->base, + LPI2C_SlaveEnableInterrupts(base, (kLPI2C_SlaveTxReadyFlag | kLPI2C_SlaveRxReadyFlag | kLPI2C_SlaveStopDetectFlag | @@ -448,6 +456,7 @@ static int mcux_lpi2c_target_unregister(const struct device *dev, { const struct mcux_lpi2c_config *config = dev->config; struct mcux_lpi2c_data *data = dev->data; + LPI2C_Type *base = (LPI2C_Type *)DEVICE_MMIO_NAMED_GET(dev, reg_base); if (!data->target_attached) { return -EINVAL; @@ -456,7 +465,7 @@ static int mcux_lpi2c_target_unregister(const struct device *dev, data->target_cfg = NULL; data->target_attached = false; - LPI2C_SlaveDeinit(config->base); + LPI2C_SlaveDeinit(base); return 0; } @@ -464,9 +473,8 @@ static int mcux_lpi2c_target_unregister(const struct device *dev, static void mcux_lpi2c_isr(const struct device *dev) { - const struct mcux_lpi2c_config *config = dev->config; struct mcux_lpi2c_data *data = dev->data; - LPI2C_Type *base = config->base; + LPI2C_Type *base = (LPI2C_Type *)DEVICE_MMIO_NAMED_GET(dev, reg_base); #ifdef CONFIG_I2C_TARGET if (data->target_attached) { @@ -481,11 +489,15 @@ static int mcux_lpi2c_init(const struct device *dev) { const struct mcux_lpi2c_config *config = dev->config; struct mcux_lpi2c_data *data = dev->data; - LPI2C_Type *base = config->base; + LPI2C_Type *base; uint32_t clock_freq, bitrate_cfg; lpi2c_master_config_t master_config; int error; + DEVICE_MMIO_NAMED_MAP(dev, reg_base, K_MEM_CACHE_NONE | K_MEM_DIRECT_MAP); + + base = (LPI2C_Type *)DEVICE_MMIO_NAMED_GET(dev, reg_base); + k_sem_init(&data->lock, 1, 1); k_sem_init(&data->device_sync_sem, 0, K_SEM_MAX_LIMIT); @@ -549,7 +561,7 @@ static const struct i2c_driver_api mcux_lpi2c_driver_api = { static void mcux_lpi2c_config_func_##n(const struct device *dev); \ \ static const struct mcux_lpi2c_config mcux_lpi2c_config_##n = { \ - .base = (LPI2C_Type *)DT_INST_REG_ADDR(n), \ + DEVICE_MMIO_NAMED_ROM_INIT(reg_base, DT_DRV_INST(n)), \ .clock_dev = DEVICE_DT_GET(DT_INST_CLOCKS_CTLR(n)), \ .clock_subsys = \ (clock_control_subsys_t)DT_INST_CLOCKS_CELL(n, name),\ @@ -566,17 +578,17 @@ static const struct i2c_driver_api mcux_lpi2c_driver_api = { static struct mcux_lpi2c_data mcux_lpi2c_data_##n; \ \ I2C_DEVICE_DT_INST_DEFINE(n, mcux_lpi2c_init, NULL, \ - &mcux_lpi2c_data_##n, \ - &mcux_lpi2c_config_##n, POST_KERNEL, \ - CONFIG_I2C_INIT_PRIORITY, \ - &mcux_lpi2c_driver_api); \ + &mcux_lpi2c_data_##n, \ + &mcux_lpi2c_config_##n, POST_KERNEL, \ + CONFIG_I2C_INIT_PRIORITY, \ + &mcux_lpi2c_driver_api); \ \ static void mcux_lpi2c_config_func_##n(const struct device *dev) \ { \ IRQ_CONNECT(DT_INST_IRQN(n), \ - DT_INST_IRQ(n, priority), \ - mcux_lpi2c_isr, \ - DEVICE_DT_INST_GET(n), 0); \ + DT_INST_IRQ(n, priority), \ + mcux_lpi2c_isr, \ + DEVICE_DT_INST_GET(n), 0); \ \ irq_enable(DT_INST_IRQN(n)); \ } From 4a82128c69303b54e2c34dfd573f5eb67cd750bc Mon Sep 17 00:00:00 2001 From: Chekhov Ma Date: Fri, 22 Dec 2023 11:29:56 +0800 Subject: [PATCH 1725/3723] soc: imx93: enable lpi2c - Add LPI2C1 ~ LPI2C8 instances to soc dtsi. - Expand clock dt-bindings for LPI2C to instance 7 & 8. - Add LPUART and LPI2C driver in imx9 Kconfig. Signed-off-by: Chekhov Ma --- dts/arm64/nxp/nxp_mimx93_a55.dtsi | 97 +++++++++++++++++++ .../zephyr/dt-bindings/clock/imx_ccm_rev2.h | 2 + 2 files changed, 99 insertions(+) diff --git a/dts/arm64/nxp/nxp_mimx93_a55.dtsi b/dts/arm64/nxp/nxp_mimx93_a55.dtsi index 22a61e2dfca..f1d6319edd6 100644 --- a/dts/arm64/nxp/nxp_mimx93_a55.dtsi +++ b/dts/arm64/nxp/nxp_mimx93_a55.dtsi @@ -9,6 +9,7 @@ #include #include #include +#include / { #address-cells = <1>; @@ -94,4 +95,100 @@ clocks = <&ccm IMX_CCM_LPUART2_CLK 0x6c 24>; status = "disabled"; }; + + lpi2c1: i2c@44340000 { + compatible = "nxp,imx-lpi2c"; + clock-frequency = ; + #address-cells = <1>; + #size-cells = <0>; + reg = <0x44340000 0x4000>; + interrupts = ; + interrupt-parent = <&gic>; + clocks = <&ccm IMX_CCM_LPI2C1_CLK 0x70 6>; + status = "disabled"; + }; + + lpi2c2: i2c@44350000 { + compatible = "nxp,imx-lpi2c"; + clock-frequency = ; + #address-cells = <1>; + #size-cells = <0>; + reg = <0x44350000 0x4000>; + interrupts = ; + interrupt-parent = <&gic>; + clocks = <&ccm IMX_CCM_LPI2C2_CLK 0x70 8>; + status = "disabled"; + }; + + lpi2c3: i2c@42530000 { + compatible = "nxp,imx-lpi2c"; + clock-frequency = ; + #address-cells = <1>; + #size-cells = <0>; + reg = <0x42530000 0x4000>; + interrupts = ; + interrupt-parent = <&gic>; + clocks = <&ccm IMX_CCM_LPI2C3_CLK 0x70 10>; + status = "disabled"; + }; + + lpi2c4: i2c@42540000 { + compatible = "nxp,imx-lpi2c"; + clock-frequency = ; + #address-cells = <1>; + #size-cells = <0>; + reg = <0x42540000 0x4000>; + interrupts = ; + interrupt-parent = <&gic>; + clocks = <&ccm IMX_CCM_LPI2C4_CLK 0x80 24>; + status = "disabled"; + }; + + lpi2c5: i2c@426b0000 { + compatible = "nxp,imx-lpi2c"; + clock-frequency = ; + #address-cells = <1>; + #size-cells = <0>; + reg = <0x426b0000 0x4000>; + interrupts = ; + interrupt-parent = <&gic>; + clocks = <&ccm IMX_CCM_LPI2C5_CLK 0x80 24>; + status = "disabled"; + }; + + lpi2c6: i2c@426c0000 { + compatible = "nxp,imx-lpi2c"; + clock-frequency = ; + #address-cells = <1>; + #size-cells = <0>; + reg = <0x426c0000 0x4000>; + interrupts = ; + interrupt-parent = <&gic>; + clocks = <&ccm IMX_CCM_LPI2C6_CLK 0x80 24>; + status = "disabled"; + }; + + lpi2c7: i2c@426d0000 { + compatible = "nxp,imx-lpi2c"; + clock-frequency = ; + #address-cells = <1>; + #size-cells = <0>; + reg = <0x426d0000 0x4000>; + interrupts = ; + interrupt-parent = <&gic>; + clocks = <&ccm IMX_CCM_LPI2C7_CLK 0x80 24>; + status = "disabled"; + }; + + lpi2c8: i2c@426e0000 { + compatible = "nxp,imx-lpi2c"; + clock-frequency = ; + #address-cells = <1>; + #size-cells = <0>; + reg = <0x426e0000 0x4000>; + interrupts = ; + interrupt-parent = <&gic>; + clocks = <&ccm IMX_CCM_LPI2C8_CLK 0x80 24>; + status = "disabled"; + }; }; diff --git a/include/zephyr/dt-bindings/clock/imx_ccm_rev2.h b/include/zephyr/dt-bindings/clock/imx_ccm_rev2.h index fc7be3628d8..6caf9db10ce 100644 --- a/include/zephyr/dt-bindings/clock/imx_ccm_rev2.h +++ b/include/zephyr/dt-bindings/clock/imx_ccm_rev2.h @@ -42,6 +42,8 @@ #define IMX_CCM_LPI2C4_CLK 0x403UL #define IMX_CCM_LPI2C5_CLK 0x404UL #define IMX_CCM_LPI2C6_CLK 0x405UL +#define IMX_CCM_LPI2C7_CLK 0x406UL +#define IMX_CCM_LPI2C8_CLK 0x407UL /* LPSPI */ #define IMX_CCM_LPSPI_CLK 0x500UL From 13ba5316ded8b671f6b198ead99cbbd5e99724d3 Mon Sep 17 00:00:00 2001 From: Chekhov Ma Date: Fri, 8 Dec 2023 15:22:03 +0800 Subject: [PATCH 1726/3723] boards: mimx93_evk_a55: enable lpi2c - Enable LPI2C 1,2,4 in i.MX93 EVK board dts. Signed-off-by: Chekhov Ma --- .../arm64/mimx93_evk/mimx93_evk-pinctrl.dtsi | 45 +++++++++++++++++++ boards/arm64/mimx93_evk/mimx93_evk_a55.dts | 15 +++++++ boards/arm64/mimx93_evk/mimx93_evk_a55.yaml | 3 ++ 3 files changed, 63 insertions(+) diff --git a/boards/arm64/mimx93_evk/mimx93_evk-pinctrl.dtsi b/boards/arm64/mimx93_evk/mimx93_evk-pinctrl.dtsi index 83070adf93f..352b304b704 100644 --- a/boards/arm64/mimx93_evk/mimx93_evk-pinctrl.dtsi +++ b/boards/arm64/mimx93_evk/mimx93_evk-pinctrl.dtsi @@ -26,4 +26,49 @@ drive-strength = "x5"; }; }; + + i2c1_default: i2c1_default { + group0 { + pinmux = <&iomuxc1_i2c1_scl_lpi2c_scl_lpi2c1_scl>, + <&iomuxc1_i2c1_sda_lpi2c_sda_lpi2c1_sda>; + drive-strength = "x5"; + drive-open-drain; + slew-rate = "fast"; + input-enable; + }; + }; + + i2c2_default: i2c2_default { + group0 { + pinmux = <&iomuxc1_i2c2_scl_lpi2c_scl_lpi2c2_scl>, + <&iomuxc1_i2c2_sda_lpi2c_sda_lpi2c2_sda>; + drive-strength = "x5"; + drive-open-drain; + slew-rate = "fast"; + input-enable; + }; + }; + + i2c3_default: i2c3_default { + group0 { + pinmux = <&iomuxc1_gpio_io01_lpi2c_scl_lpi2c3_scl>, + <&iomuxc1_gpio_io00_lpi2c_sda_lpi2c3_sda>; + drive-strength = "x5"; + drive-open-drain; + slew-rate = "fast"; + input-enable; + }; + }; + + i2c4_default: i2c4_default { + group0 { + pinmux = <&iomuxc1_gpio_io03_lpi2c_scl_lpi2c4_scl>, + <&iomuxc1_gpio_io02_lpi2c_sda_lpi2c4_sda>; + drive-strength = "x5"; + drive-open-drain; + slew-rate = "fast"; + input-enable; + }; + }; + }; diff --git a/boards/arm64/mimx93_evk/mimx93_evk_a55.dts b/boards/arm64/mimx93_evk/mimx93_evk_a55.dts index 375bb2f7a0e..0a707f9ef14 100644 --- a/boards/arm64/mimx93_evk/mimx93_evk_a55.dts +++ b/boards/arm64/mimx93_evk/mimx93_evk_a55.dts @@ -45,3 +45,18 @@ pinctrl-0 = <&uart2_default>; pinctrl-names = "default"; }; + + +&lpi2c1{ + status = "disabled"; + clock-frequency = ; + pinctrl-0 = <&i2c1_default>; + pinctrl-names = "default"; +}; + +&lpi2c2{ + status = "disabled"; + clock-frequency = ; + pinctrl-0 = <&i2c2_default>; + pinctrl-names = "default"; +}; diff --git a/boards/arm64/mimx93_evk/mimx93_evk_a55.yaml b/boards/arm64/mimx93_evk/mimx93_evk_a55.yaml index 72e4c677fc0..9d91cfe9e59 100644 --- a/boards/arm64/mimx93_evk/mimx93_evk_a55.yaml +++ b/boards/arm64/mimx93_evk/mimx93_evk_a55.yaml @@ -6,6 +6,9 @@ toolchain: - zephyr - cross-compile ram: 1024 +supported: + - uart + - i2c testing: ignore_tags: - net From 0ce4399a03eb534d2f704613a1b397142036134b Mon Sep 17 00:00:00 2001 From: Chekhov Ma Date: Wed, 13 Dec 2023 14:27:32 +0800 Subject: [PATCH 1727/3723] driver: mucx_lpspi: enable runtime mmio configuration Enable runtime mmio configuration in mcux_lpspi driver. The fsl_lpspi driver relies on physical address to determine instance number. So mmap flag 'K_MEM_DIRECT_MAP' is required. Signed-off-by: Chekhov Ma --- drivers/spi/spi_mcux_lpspi.c | 102 +++++++++++++++++++---------------- 1 file changed, 55 insertions(+), 47 deletions(-) diff --git a/drivers/spi/spi_mcux_lpspi.c b/drivers/spi/spi_mcux_lpspi.c index e1155be3d7c..a1b805d98e0 100644 --- a/drivers/spi/spi_mcux_lpspi.c +++ b/drivers/spi/spi_mcux_lpspi.c @@ -28,8 +28,13 @@ LOG_MODULE_REGISTER(spi_mcux_lpspi, CONFIG_SPI_LOG_LEVEL); #define CHIP_SELECT_COUNT 4 #define MAX_DATA_WIDTH 4096 +/* Required by DEVICE_MMIO_NAMED_* macros */ +#define DEV_CFG(_dev) \ + ((const struct spi_mcux_config *)(_dev)->config) +#define DEV_DATA(_dev) ((struct spi_mcux_data *)(_dev)->data) + struct spi_mcux_config { - LPSPI_Type *base; + DEVICE_MMIO_NAMED_ROM(reg_base); const struct device *clock_dev; clock_control_subsys_t clock_subsys; void (*irq_config_func)(const struct device *dev); @@ -56,6 +61,7 @@ struct stream { #endif struct spi_mcux_data { + DEVICE_MMIO_NAMED_RAM(reg_base); const struct device *dev; lpspi_master_handle_t handle; struct spi_context ctx; @@ -83,9 +89,9 @@ struct spi_mcux_data { static int spi_mcux_transfer_next_packet(const struct device *dev) { - const struct spi_mcux_config *config = dev->config; + /* const struct spi_mcux_config *config = dev->config; */ struct spi_mcux_data *data = dev->data; - LPSPI_Type *base = config->base; + LPSPI_Type *base = (LPSPI_Type *)DEVICE_MMIO_NAMED_GET(dev, reg_base); struct spi_context *ctx = &data->ctx; lpspi_transfer_t transfer; status_t status; @@ -98,7 +104,7 @@ static int spi_mcux_transfer_next_packet(const struct device *dev) } transfer.configFlags = kLPSPI_MasterPcsContinuous | - (ctx->config->slave << LPSPI_MASTER_PCS_SHIFT); + (ctx->config->slave << LPSPI_MASTER_PCS_SHIFT); if (ctx->tx_len == 0) { /* rx only, nothing to tx */ @@ -153,9 +159,9 @@ static int spi_mcux_transfer_next_packet(const struct device *dev) static void spi_mcux_isr(const struct device *dev) { - const struct spi_mcux_config *config = dev->config; + /* const struct spi_mcux_config *config = dev->config; */ struct spi_mcux_data *data = dev->data; - LPSPI_Type *base = config->base; + LPSPI_Type *base = (LPSPI_Type *)DEVICE_MMIO_NAMED_GET(dev, reg_base); LPSPI_MasterTransferHandleIRQ(base, &data->handle); } @@ -182,11 +188,11 @@ static void spi_mcux_master_transfer_callback(LPSPI_Type *base, } static int spi_mcux_configure(const struct device *dev, - const struct spi_config *spi_cfg) + const struct spi_config *spi_cfg) { const struct spi_mcux_config *config = dev->config; struct spi_mcux_data *data = dev->data; - LPSPI_Type *base = config->base; + LPSPI_Type *base = (LPSPI_Type *)DEVICE_MMIO_NAMED_GET(dev, reg_base); lpspi_master_config_t master_config; uint32_t clock_freq; uint32_t word_size; @@ -205,15 +211,15 @@ static int spi_mcux_configure(const struct device *dev, if (spi_cfg->slave > CHIP_SELECT_COUNT) { LOG_ERR("Slave %d is greater than %d", - spi_cfg->slave, - CHIP_SELECT_COUNT); + spi_cfg->slave, + CHIP_SELECT_COUNT); return -EINVAL; } word_size = SPI_WORD_SIZE_GET(spi_cfg->operation); if (word_size > MAX_DATA_WIDTH) { LOG_ERR("Word size %d is greater than %d", - word_size, MAX_DATA_WIDTH); + word_size, MAX_DATA_WIDTH); return -EINVAL; } @@ -335,10 +341,10 @@ static void spi_mcux_dma_callback(const struct device *dev, void *arg, static int spi_mcux_dma_tx_load(const struct device *dev, const uint8_t *buf, size_t len) { - const struct spi_mcux_config *cfg = dev->config; + /* const struct spi_mcux_config *cfg = dev->config; */ struct spi_mcux_data *data = dev->data; struct dma_block_config *blk_cfg; - LPSPI_Type *base = cfg->base; + LPSPI_Type *base = (LPSPI_Type *)DEVICE_MMIO_NAMED_GET(dev, reg_base); /* remember active TX DMA channel (used in callback) */ struct stream *stream = &data->dma_tx; @@ -378,10 +384,10 @@ static int spi_mcux_dma_tx_load(const struct device *dev, const uint8_t *buf, si static int spi_mcux_dma_rx_load(const struct device *dev, uint8_t *buf, size_t len) { - const struct spi_mcux_config *cfg = dev->config; + /*const struct spi_mcux_config *cfg = dev->config; */ struct spi_mcux_data *data = dev->data; struct dma_block_config *blk_cfg; - LPSPI_Type *base = cfg->base; + LPSPI_Type *base = (LPSPI_Type *)DEVICE_MMIO_NAMED_GET(dev, reg_base); /* retrieve active RX DMA channel (used in callback) */ struct stream *stream = &data->dma_rx; @@ -480,16 +486,16 @@ static inline int spi_mcux_dma_rxtx_load(const struct device *dev, } static int transceive_dma(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) + 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) { - const struct spi_mcux_config *config = dev->config; + /* const struct spi_mcux_config *config = dev->config; */ struct spi_mcux_data *data = dev->data; - LPSPI_Type *base = config->base; + LPSPI_Type *base = (LPSPI_Type *)DEVICE_MMIO_NAMED_GET(dev, reg_base); int ret; size_t dma_size; @@ -564,12 +570,12 @@ static int transceive_dma(const struct device *dev, #endif 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) + 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_mcux_data *data = dev->data; int ret; @@ -599,9 +605,9 @@ static int transceive(const struct device *dev, static int spi_mcux_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) + const struct spi_config *spi_cfg, + const struct spi_buf_set *tx_bufs, + const struct spi_buf_set *rx_bufs) { #ifdef CONFIG_SPI_MCUX_LPSPI_DMA const struct spi_mcux_data *data = dev->data; @@ -616,11 +622,11 @@ static int spi_mcux_transceive(const struct device *dev, #ifdef CONFIG_SPI_ASYNC static int spi_mcux_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) + 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) { #ifdef CONFIG_SPI_MCUX_LPSPI_DMA struct spi_mcux_data *data = dev->data; @@ -637,7 +643,7 @@ static int spi_mcux_transceive_async(const struct device *dev, #endif /* CONFIG_SPI_ASYNC */ static int spi_mcux_release(const struct device *dev, - const struct spi_config *spi_cfg) + const struct spi_config *spi_cfg) { struct spi_mcux_data *data = dev->data; @@ -652,6 +658,8 @@ static int spi_mcux_init(const struct device *dev) const struct spi_mcux_config *config = dev->config; struct spi_mcux_data *data = dev->data; + DEVICE_MMIO_NAMED_MAP(dev, reg_base, K_MEM_CACHE_NONE | K_MEM_DIRECT_MAP); + config->irq_config_func(dev); err = spi_context_cs_configure_all(&data->ctx); @@ -714,19 +722,19 @@ static void spi_mcux_iodev_next(const struct device *dev, bool completion); static void spi_mcux_iodev_start(const struct device *dev) { - const struct spi_mcux_config *config = dev->config; + /* const struct spi_mcux_config *config = dev->config; */ struct spi_mcux_data *data = dev->data; struct rtio_sqe *sqe = &data->txn_curr->sqe; struct spi_dt_spec *spi_dt_spec = sqe->iodev->data; struct spi_config *spi_cfg = &spi_dt_spec->config; struct rtio_iodev_sqe *txn_head = data->txn_head; - LPSPI_Type *base = config->base; + LPSPI_Type *base = (LPSPI_Type *)DEVICE_MMIO_NAMED_GET(dev, reg_base); lpspi_transfer_t transfer; status_t status; transfer.configFlags = kLPSPI_MasterPcsContinuous | - (spi_cfg->slave << LPSPI_MASTER_PCS_SHIFT); + (spi_cfg->slave << LPSPI_MASTER_PCS_SHIFT); switch (sqe->op) { case RTIO_OP_RX: @@ -895,7 +903,7 @@ static const struct spi_driver_api spi_mcux_driver_api = { static void spi_mcux_config_func_##n(const struct device *dev); \ \ static const struct spi_mcux_config spi_mcux_config_##n = { \ - .base = (LPSPI_Type *) DT_INST_REG_ADDR(n), \ + DEVICE_MMIO_NAMED_ROM_INIT(reg_base, DT_DRV_INST(n)), \ .clock_dev = DEVICE_DT_GET(DT_INST_CLOCKS_CTLR(n)), \ .clock_subsys = \ (clock_control_subsys_t)DT_INST_CLOCKS_CELL(n, name), \ @@ -924,15 +932,15 @@ static const struct spi_driver_api spi_mcux_driver_api = { }; \ \ DEVICE_DT_INST_DEFINE(n, &spi_mcux_init, NULL, \ - &spi_mcux_data_##n, \ - &spi_mcux_config_##n, POST_KERNEL, \ - CONFIG_SPI_INIT_PRIORITY, \ - &spi_mcux_driver_api); \ + &spi_mcux_data_##n, \ + &spi_mcux_config_##n, POST_KERNEL, \ + CONFIG_SPI_INIT_PRIORITY, \ + &spi_mcux_driver_api); \ \ static void spi_mcux_config_func_##n(const struct device *dev) \ { \ IRQ_CONNECT(DT_INST_IRQN(n), DT_INST_IRQ(n, priority), \ - spi_mcux_isr, DEVICE_DT_INST_GET(n), 0); \ + spi_mcux_isr, DEVICE_DT_INST_GET(n), 0); \ \ irq_enable(DT_INST_IRQN(n)); \ } From 81cf8db0ed51a8349f4d58c697344f8cf6d2b0bf Mon Sep 17 00:00:00 2001 From: Chekhov Ma Date: Tue, 5 Dec 2023 15:46:21 +0800 Subject: [PATCH 1728/3723] soc: imx93: enable lpspi - Add LPSPI1 ~ LPSPI8 instances to soc dtsi. - Expand clock dt-bindings for LPSPI to instance 7 & 8. - Add LPSPI driver in imx9 Kconfig. Signed-off-by: Chekhov Ma --- dts/arm64/nxp/nxp_mimx93_a55.dtsi | 88 +++++++++++++++++++ .../zephyr/dt-bindings/clock/imx_ccm_rev2.h | 2 + 2 files changed, 90 insertions(+) diff --git a/dts/arm64/nxp/nxp_mimx93_a55.dtsi b/dts/arm64/nxp/nxp_mimx93_a55.dtsi index f1d6319edd6..bfedef48381 100644 --- a/dts/arm64/nxp/nxp_mimx93_a55.dtsi +++ b/dts/arm64/nxp/nxp_mimx93_a55.dtsi @@ -191,4 +191,92 @@ clocks = <&ccm IMX_CCM_LPI2C8_CLK 0x80 24>; status = "disabled"; }; + + lpspi1: spi@44360000 { + compatible = "nxp,imx-lpspi"; + reg = <0x44360000 0x4000>; + interrupts = ; + interrupt-parent = <&gic>; + status = "disabled"; + clocks = <&ccm IMX_CCM_LPSPI1_CLK 0x6c 0>; + #address-cells = <1>; + #size-cells = <0>; + }; + + lpspi2: spi@44370000 { + compatible = "nxp,imx-lpspi"; + reg = <0x44370000 0x4000>; + interrupts = ; + interrupt-parent = <&gic>; + status = "disabled"; + clocks = <&ccm IMX_CCM_LPSPI2_CLK 0x6c 2>; + #address-cells = <1>; + #size-cells = <0>; + }; + + lpspi3: spi@42550000 { + compatible = "nxp,imx-lpspi"; + reg = <0x42550000 0x4000>; + interrupts = ; + interrupt-parent = <&gic>; + status = "disabled"; + clocks = <&ccm IMX_CCM_LPSPI3_CLK 0x6c 4>; + #address-cells = <1>; + #size-cells = <0>; + }; + + lpspi4: spi@42560000 { + compatible = "nxp,imx-lpspi"; + reg = <0x42560000 0x4000>; + interrupts = ; + interrupt-parent = <&gic>; + status = "disabled"; + clocks = <&ccm IMX_CCM_LPSPI4_CLK 0x6c 6>; + #address-cells = <1>; + #size-cells = <0>; + }; + + lpspi5: spi@426f0000 { + compatible = "nxp,imx-lpspi"; + reg = <0x426f0000 0x4000>; + interrupts = ; + interrupt-parent = <&gic>; + status = "disabled"; + clocks = <&ccm IMX_CCM_LPSPI5_CLK 0x6c 6>; + #address-cells = <1>; + #size-cells = <0>; + }; + + lpspi6: spi@42700000 { + compatible = "nxp,imx-lpspi"; + reg = <0x42700000 0x4000>; + interrupts = ; + interrupt-parent = <&gic>; + status = "disabled"; + clocks = <&ccm IMX_CCM_LPSPI6_CLK 0x6c 6>; + #address-cells = <1>; + #size-cells = <0>; + }; + + lpspi7: spi@42710000 { + compatible = "nxp,imx-lpspi"; + reg = <0x42710000 0x4000>; + interrupts = ; + interrupt-parent = <&gic>; + status = "disabled"; + clocks = <&ccm IMX_CCM_LPSPI7_CLK 0x6c 0>; + #address-cells = <1>; + #size-cells = <0>; + }; + + lpspi8: spi@42720000 { + compatible = "nxp,imx-lpspi"; + reg = <0x42720000 0x4000>; + interrupts = ; + interrupt-parent = <&gic>; + status = "disabled"; + clocks = <&ccm IMX_CCM_LPSPI8_CLK 0x6c 2>; + #address-cells = <1>; + #size-cells = <0>; + }; }; diff --git a/include/zephyr/dt-bindings/clock/imx_ccm_rev2.h b/include/zephyr/dt-bindings/clock/imx_ccm_rev2.h index 6caf9db10ce..fe011525846 100644 --- a/include/zephyr/dt-bindings/clock/imx_ccm_rev2.h +++ b/include/zephyr/dt-bindings/clock/imx_ccm_rev2.h @@ -53,6 +53,8 @@ #define IMX_CCM_LPSPI4_CLK 0x503UL #define IMX_CCM_LPSPI5_CLK 0x504UL #define IMX_CCM_LPSPI6_CLK 0x505UL +#define IMX_CCM_LPSPI7_CLK 0x506UL +#define IMX_CCM_LPSPI8_CLK 0x507UL /* USDHC */ #define IMX_CCM_USDHC1_CLK 0x600UL From 8cc07772372f2251d334be1121f5c7cd1a1c054f Mon Sep 17 00:00:00 2001 From: Chekhov Ma Date: Fri, 8 Dec 2023 15:22:28 +0800 Subject: [PATCH 1729/3723] boards: mimx93_evk_a55: enable lpspi - Enable LPSPI 3 in i.MX93 EVK board dts. Signed-off-by: Chekhov Ma --- boards/arm64/mimx93_evk/mimx93_evk-pinctrl.dtsi | 12 ++++++++++++ boards/arm64/mimx93_evk/mimx93_evk_a55.dts | 7 +++++++ boards/arm64/mimx93_evk/mimx93_evk_a55.yaml | 1 + 3 files changed, 20 insertions(+) diff --git a/boards/arm64/mimx93_evk/mimx93_evk-pinctrl.dtsi b/boards/arm64/mimx93_evk/mimx93_evk-pinctrl.dtsi index 352b304b704..31e35907f86 100644 --- a/boards/arm64/mimx93_evk/mimx93_evk-pinctrl.dtsi +++ b/boards/arm64/mimx93_evk/mimx93_evk-pinctrl.dtsi @@ -71,4 +71,16 @@ }; }; + spi3_default: spi3_default { + group0 { + pinmux = <&iomuxc1_gpio_io07_lpspi_pcs_lpspi3_pcs1>, + <&iomuxc1_gpio_io08_lpspi_pcs_lpspi3_pcs0>, + <&iomuxc1_gpio_io09_lpspi_sin_lpspi3_sin>, + <&iomuxc1_gpio_io10_lpspi_sout_lpspi3_sout>, + <&iomuxc1_gpio_io11_lpspi_sck_lpspi3_sck>; + slew-rate = "fast"; + drive-strength = "x5"; + }; + }; + }; diff --git a/boards/arm64/mimx93_evk/mimx93_evk_a55.dts b/boards/arm64/mimx93_evk/mimx93_evk_a55.dts index 0a707f9ef14..2fb9d0e9c12 100644 --- a/boards/arm64/mimx93_evk/mimx93_evk_a55.dts +++ b/boards/arm64/mimx93_evk/mimx93_evk_a55.dts @@ -60,3 +60,10 @@ pinctrl-0 = <&i2c2_default>; pinctrl-names = "default"; }; + +&lpspi3 { + status = "disabled"; + clock-frequency = <1000000>; + pinctrl-0 = <&spi3_default>; + pinctrl-names = "default"; +}; diff --git a/boards/arm64/mimx93_evk/mimx93_evk_a55.yaml b/boards/arm64/mimx93_evk/mimx93_evk_a55.yaml index 9d91cfe9e59..a57ec92ea4f 100644 --- a/boards/arm64/mimx93_evk/mimx93_evk_a55.yaml +++ b/boards/arm64/mimx93_evk/mimx93_evk_a55.yaml @@ -9,6 +9,7 @@ ram: 1024 supported: - uart - i2c + - spi testing: ignore_tags: - net From b2626faced57b47db47988bc4d40beb076727ce0 Mon Sep 17 00:00:00 2001 From: Andrej Butok Date: Tue, 5 Dec 2023 15:27:51 +0100 Subject: [PATCH 1730/3723] boards: mimxrt1040_evk: add LinkServer and Pyocd Add LinkServer and Pyocd runners for the MIMXRT1040-EVK board. Signed-off-by: Andrej Butok --- boards/arm/mimxrt1040_evk/board.cmake | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/boards/arm/mimxrt1040_evk/board.cmake b/boards/arm/mimxrt1040_evk/board.cmake index 54d459f5c08..10e09bc1405 100644 --- a/boards/arm/mimxrt1040_evk/board.cmake +++ b/boards/arm/mimxrt1040_evk/board.cmake @@ -5,5 +5,9 @@ # board_runner_args(jlink "--device=MIMXRT1042XXX6B") +board_runner_args(linkserver "--device=MIMXRT1042xxxxB:MIMXRT1040-EVK") +board_runner_args(pyocd "--target=MIMXRT1042XJM5B") include(${ZEPHYR_BASE}/boards/common/jlink.board.cmake) +include(${ZEPHYR_BASE}/boards/common/linkserver.board.cmake) +include(${ZEPHYR_BASE}/boards/common/pyocd.board.cmake) From 3f2ded34559e28995da6fbbefbafbf70d829c6a4 Mon Sep 17 00:00:00 2001 From: Derek Snell Date: Wed, 13 Sep 2023 15:51:11 -0400 Subject: [PATCH 1731/3723] soc: arm: nxp_imx: r5xx: add Kconfig to clock FC0 from FRO Flexcomm0 has option to clock from FRO. Signed-off-by: Derek Snell --- soc/arm/nxp_imx/rt5xx/Kconfig.soc | 14 +++++++++++++- soc/arm/nxp_imx/rt5xx/soc.c | 8 ++++++-- 2 files changed, 19 insertions(+), 3 deletions(-) diff --git a/soc/arm/nxp_imx/rt5xx/Kconfig.soc b/soc/arm/nxp_imx/rt5xx/Kconfig.soc index 2c82c533de9..c2e8fecffae 100644 --- a/soc/arm/nxp_imx/rt5xx/Kconfig.soc +++ b/soc/arm/nxp_imx/rt5xx/Kconfig.soc @@ -1,6 +1,6 @@ # i.MX RT5XX Series -# Copyright (c) 2022, NXP +# Copyright 2022-2023, NXP # SPDX-License-Identifier: Apache-2.0 choice @@ -129,4 +129,16 @@ config IMXRT5XX_CODE_CACHE Enable code cache for FlexSPI region at boot. If this Kconfig is cleared, the CACHE64 controller will be disabled during SOC init +choice FLEXCOMM0_CLK_SRC + prompt "Clock source for Flexcomm0" + default FLEXCOMM0_CLK_SRC_FRG + +config FLEXCOMM0_CLK_SRC_FRG + bool "FRG is source of Flexcomm0 clock" + +config FLEXCOMM0_CLK_SRC_FRO + bool "FRO_DIV4 is source of Flexcomm0 clock" + +endchoice + endif # SOC_SERIES_IMX_RT5XX diff --git a/soc/arm/nxp_imx/rt5xx/soc.c b/soc/arm/nxp_imx/rt5xx/soc.c index d834d3e55bc..8df0f2fe23e 100644 --- a/soc/arm/nxp_imx/rt5xx/soc.c +++ b/soc/arm/nxp_imx/rt5xx/soc.c @@ -281,8 +281,12 @@ void __weak rt5xx_clock_init(void) /* Switch SYSTICK_CLK to MAIN_CLK_DIV */ CLOCK_AttachClk(kMAIN_CLK_DIV_to_SYSTICK_CLK); #if DT_NODE_HAS_COMPAT_STATUS(DT_NODELABEL(flexcomm0), nxp_lpc_usart, okay) - /* Switch FLEXCOMM0 to FRG */ - CLOCK_AttachClk(kFRG_to_FLEXCOMM0); + #ifdef CONFIG_FLEXCOMM0_CLK_SRC_FRG + /* Switch FLEXCOMM0 to FRG */ + CLOCK_AttachClk(kFRG_to_FLEXCOMM0); + #elif defined(CONFIG_FLEXCOMM0_CLK_SRC_FRO) + CLOCK_AttachClk(kFRO_DIV4_to_FLEXCOMM0); + #endif #endif #if CONFIG_USB_DC_NXP_LPCIP3511 usb_device_clock_init(); From 44885cbca592e9cda13f976a788a839d7671ebf1 Mon Sep 17 00:00:00 2001 From: Derek Snell Date: Wed, 13 Sep 2023 16:27:55 -0400 Subject: [PATCH 1732/3723] boards: mimxrt595: add CONFIG_MIPI_DPHY_CLK_SRC Give option in soc.c to initialize the MIPI DPHY clock from the default AUX1_PLL, or from the FRO using CONFIG_MIPI_DPHY_CLK_SRC_FRO. Signed-off-by: Derek Snell --- soc/arm/nxp_imx/rt5xx/Kconfig.soc | 12 ++++++++++++ soc/arm/nxp_imx/rt5xx/soc.c | 11 ++++++++++- 2 files changed, 22 insertions(+), 1 deletion(-) diff --git a/soc/arm/nxp_imx/rt5xx/Kconfig.soc b/soc/arm/nxp_imx/rt5xx/Kconfig.soc index c2e8fecffae..35b86c2e903 100644 --- a/soc/arm/nxp_imx/rt5xx/Kconfig.soc +++ b/soc/arm/nxp_imx/rt5xx/Kconfig.soc @@ -141,4 +141,16 @@ config FLEXCOMM0_CLK_SRC_FRO endchoice +choice MIPI_DPHY_CLK_SRC + prompt "Clock source for MIPI DPHY" + default MIPI_DPHY_CLK_SRC_AUX1_PLL + +config MIPI_DPHY_CLK_SRC_AUX1_PLL + bool "AUX1_PLL is source of MIPI_DPHY clock" + +config MIPI_DPHY_CLK_SRC_FRO + bool "FRO 192/96M is source of MIPI_DPHY clock" + +endchoice + endif # SOC_SERIES_IMX_RT5XX diff --git a/soc/arm/nxp_imx/rt5xx/soc.c b/soc/arm/nxp_imx/rt5xx/soc.c index 8df0f2fe23e..85e4a900413 100644 --- a/soc/arm/nxp_imx/rt5xx/soc.c +++ b/soc/arm/nxp_imx/rt5xx/soc.c @@ -462,12 +462,21 @@ void __weak imxrt_pre_init_display_interface(void) * We set the divider of the PFD3 output of the SYSPLL, which has a * fixed multiplied of 18, and use this output frequency for the DPHY. */ + +#ifdef CONFIG_MIPI_DPHY_CLK_SRC_AUX1_PLL + /* Note: AUX1 PLL clock is system pll clock * 18 / pfd. + * system pll clock is configured at 528MHz by default. + */ CLOCK_AttachClk(kAUX1_PLL_to_MIPI_DPHY_CLK); CLOCK_InitSysPfd(kCLOCK_Pfd3, ((CLOCK_GetSysPllFreq() * 18ull) / ((unsigned long long)(DT_PROP(DT_NODELABEL(mipi_dsi), phy_clock))))); CLOCK_SetClkDiv(kCLOCK_DivDphyClk, 1); - +#elif defined(CONFIG_MIPI_DPHY_CLK_SRC_FRO) + CLOCK_AttachClk(kFRO_DIV1_to_MIPI_DPHY_CLK); + CLOCK_SetClkDiv(kCLOCK_DivDphyClk, + (CLK_FRO_CLK / DT_PROP(DT_NODELABEL(mipi_dsi), phy_clock))); +#endif /* Clear DSI control reset (Note that DPHY reset is cleared later)*/ RESET_ClearPeripheralReset(kMIPI_DSI_CTRL_RST_SHIFT_RSTn); } From 747aacbf1cc29f24707c86bc37716569235dc4cd Mon Sep 17 00:00:00 2001 From: Andrej Butok Date: Fri, 15 Dec 2023 15:59:17 +0100 Subject: [PATCH 1733/3723] boards: lpcxpresso55s: Set CONFIG_MCUBOOT_BOOTLOADER_MODE_OVERWRITE_ONLY Set CONFIG_MCUBOOT_BOOTLOADER_MODE_OVERWRITE_ONLY=y for lpcxpresso55sxx boards. Synchronize with their default MCUBoot configuration. Signed-off-by: Andrej Butok --- boards/arm/lpcxpresso55s06/Kconfig.defconfig | 7 +++++++ boards/arm/lpcxpresso55s16/Kconfig.defconfig | 7 +++++++ boards/arm/lpcxpresso55s28/Kconfig.defconfig | 7 +++++++ boards/arm/lpcxpresso55s36/Kconfig.defconfig | 7 +++++++ boards/arm/lpcxpresso55s69/Kconfig.defconfig | 7 +++++++ 5 files changed, 35 insertions(+) diff --git a/boards/arm/lpcxpresso55s06/Kconfig.defconfig b/boards/arm/lpcxpresso55s06/Kconfig.defconfig index 57d53c1489a..48340c5f589 100644 --- a/boards/arm/lpcxpresso55s06/Kconfig.defconfig +++ b/boards/arm/lpcxpresso55s06/Kconfig.defconfig @@ -8,4 +8,11 @@ if BOARD_LPCXPRESSO55S06 config BOARD default "lpcxpresso55s06" +if BOOTLOADER_MCUBOOT +choice MCUBOOT_BOOTLOADER_MODE + # Board only supports MCUBoot via "upgrade only" method: + default MCUBOOT_BOOTLOADER_MODE_OVERWRITE_ONLY +endchoice +endif #BOOTLOADER_MCUBOOT + endif # BOARD_LPCXPRESSO55S06 diff --git a/boards/arm/lpcxpresso55s16/Kconfig.defconfig b/boards/arm/lpcxpresso55s16/Kconfig.defconfig index 49ed6830ed2..2979ac8808d 100644 --- a/boards/arm/lpcxpresso55s16/Kconfig.defconfig +++ b/boards/arm/lpcxpresso55s16/Kconfig.defconfig @@ -12,4 +12,11 @@ config FXOS8700_DRDY_INT1 default y depends on FXOS8700_TRIGGER +if BOOTLOADER_MCUBOOT +choice MCUBOOT_BOOTLOADER_MODE + # Board only supports MCUBoot via "upgrade only" method: + default MCUBOOT_BOOTLOADER_MODE_OVERWRITE_ONLY +endchoice +endif #BOOTLOADER_MCUBOOT + endif # BOARD_LPCXPRESSO55S16 diff --git a/boards/arm/lpcxpresso55s28/Kconfig.defconfig b/boards/arm/lpcxpresso55s28/Kconfig.defconfig index 40e95c1b388..ee3fd9685c4 100644 --- a/boards/arm/lpcxpresso55s28/Kconfig.defconfig +++ b/boards/arm/lpcxpresso55s28/Kconfig.defconfig @@ -37,4 +37,11 @@ config FLASH_LOAD_SIZE default $(dt_chosen_reg_size_hex,$(DT_CHOSEN_Z_CODE_PARTITION)) depends on BOARD_LPCXPRESSO55S28 && TRUSTED_EXECUTION_SECURE +if BOOTLOADER_MCUBOOT +choice MCUBOOT_BOOTLOADER_MODE + # Board only supports MCUBoot via "upgrade only" method: + default MCUBOOT_BOOTLOADER_MODE_OVERWRITE_ONLY +endchoice +endif #BOOTLOADER_MCUBOOT + endif # BOARD_LPCXPRESSO55S28 diff --git a/boards/arm/lpcxpresso55s36/Kconfig.defconfig b/boards/arm/lpcxpresso55s36/Kconfig.defconfig index 3f3b1305bf7..fd3ea5cd189 100644 --- a/boards/arm/lpcxpresso55s36/Kconfig.defconfig +++ b/boards/arm/lpcxpresso55s36/Kconfig.defconfig @@ -8,4 +8,11 @@ if BOARD_LPCXPRESSO55S36 config BOARD default "lpcxpresso55s36" +if BOOTLOADER_MCUBOOT +choice MCUBOOT_BOOTLOADER_MODE + # Board only supports MCUBoot via "upgrade only" method: + default MCUBOOT_BOOTLOADER_MODE_OVERWRITE_ONLY +endchoice +endif #BOOTLOADER_MCUBOOT + endif # BOARD_LPCXPRESSO55S36 diff --git a/boards/arm/lpcxpresso55s69/Kconfig.defconfig b/boards/arm/lpcxpresso55s69/Kconfig.defconfig index 7c98507e35c..c8bc5421e09 100644 --- a/boards/arm/lpcxpresso55s69/Kconfig.defconfig +++ b/boards/arm/lpcxpresso55s69/Kconfig.defconfig @@ -55,4 +55,11 @@ choice TFM_PROFILE_TYPE default TFM_PROFILE_TYPE_MEDIUM endchoice +if BOOTLOADER_MCUBOOT +choice MCUBOOT_BOOTLOADER_MODE + # Board only supports MCUBoot via "upgrade only" method: + default MCUBOOT_BOOTLOADER_MODE_OVERWRITE_ONLY +endchoice +endif #BOOTLOADER_MCUBOOT + endif # BOARD_LPCXPRESSO55S69_CPU0 || BOARD_LPCXPRESSO55S69_CPU1 From 35e267d64971b81407a37d546920b4959cb1cb4d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Manuel=20Arg=C3=BCelles?= Date: Sat, 16 Dec 2023 11:54:31 +0700 Subject: [PATCH 1734/3723] drivers: pwm: mcux_ftm: support multiple interrupts MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Rework the interrupt handlers of the FTM driver to support SoCs on which FTM channels and overflow are routed through individual interrupts, as opposed to a single OR'ed interrupt. Signed-off-by: Manuel Argüelles --- drivers/pwm/pwm_mcux_ftm.c | 76 ++++++++++++++++++++++++++++++++++---- 1 file changed, 68 insertions(+), 8 deletions(-) diff --git a/drivers/pwm/pwm_mcux_ftm.c b/drivers/pwm/pwm_mcux_ftm.c index 0f9d7deccf2..9f57be2dd71 100644 --- a/drivers/pwm/pwm_mcux_ftm.c +++ b/drivers/pwm/pwm_mcux_ftm.c @@ -383,11 +383,24 @@ static void mcux_ftm_capture_second_edge(const struct device *dev, uint32_t chan } } -static void mcux_ftm_isr(const struct device *dev) +static bool mcux_ftm_handle_overflow(const struct device *dev) { const struct mcux_ftm_config *config = dev->config; struct mcux_ftm_data *data = dev->data; - bool overflow = false; + + if (FTM_GetStatusFlags(config->base) & kFTM_TimeOverflowFlag) { + data->overflows++; + FTM_ClearStatusFlags(config->base, kFTM_TimeOverflowFlag); + return true; + } + + return false; +} + +static void mcux_ftm_irq_handler(const struct device *dev, uint32_t chan_start, uint32_t chan_end) +{ + const struct mcux_ftm_config *config = dev->config; + bool overflow; uint32_t flags; uint32_t irqs; uint16_t cnt; @@ -397,13 +410,9 @@ static void mcux_ftm_isr(const struct device *dev) irqs = FTM_GetEnabledInterrupts(config->base); cnt = config->base->CNT; - if (flags & kFTM_TimeOverflowFlag) { - data->overflows++; - overflow = true; - FTM_ClearStatusFlags(config->base, kFTM_TimeOverflowFlag); - } + overflow = mcux_ftm_handle_overflow(dev); - for (ch = 0; ch < MAX_CHANNELS; ch++) { + for (ch = chan_start; ch < chan_end; ch++) { if ((flags & BIT(ch)) && (irqs & BIT(ch))) { if (ch & 1) { mcux_ftm_capture_second_edge(dev, ch, cnt, overflow); @@ -496,6 +505,14 @@ static const struct pwm_driver_api mcux_ftm_driver_api = { #define TO_FTM_PRESCALE_DIVIDE(val) _DO_CONCAT(kFTM_Prescale_Divide_, val) #ifdef CONFIG_PWM_CAPTURE +#if IS_EQ(DT_NUM_IRQS(DT_DRV_INST(0)), 1) +static void mcux_ftm_isr(const struct device *dev) +{ + const struct mcux_ftm_config *cfg = dev->config; + + mcux_ftm_irq_handler(dev, 0, cfg->channel_count); +} + #define FTM_CONFIG_FUNC(n) \ static void mcux_ftm_config_func_##n(const struct device *dev) \ { \ @@ -503,6 +520,49 @@ static void mcux_ftm_config_func_##n(const struct device *dev) \ mcux_ftm_isr, DEVICE_DT_INST_GET(n), 0); \ irq_enable(DT_INST_IRQN(n)); \ } +#else /* Multiple interrupts */ +#define FTM_ISR_FUNC_NAME(suffix) _DO_CONCAT(mcux_ftm_isr_, suffix) +#define FTM_ISR_FUNC(chan_start, chan_end) \ +static void mcux_ftm_isr_##chan_start##_##chan_end(const struct device *dev) \ +{ \ + mcux_ftm_irq_handler(dev, chan_start, chan_end + 1); \ +} + +#define FTM_ISR_CONFIG(node_id, prop, idx) \ +do { \ + IRQ_CONNECT(DT_IRQ_BY_IDX(node_id, idx, irq), \ + DT_IRQ_BY_IDX(node_id, idx, priority), \ + FTM_ISR_FUNC_NAME(DT_STRING_TOKEN_BY_IDX(node_id, prop, idx)), \ + DEVICE_DT_GET(node_id), \ + 0); \ + irq_enable(DT_IRQ_BY_IDX(node_id, idx, irq)); \ +} while (false); + +#define FTM_CONFIG_FUNC(n) \ +static void mcux_ftm_config_func_##n(const struct device *dev) \ +{ \ + DT_INST_FOREACH_PROP_ELEM(n, interrupt_names, FTM_ISR_CONFIG) \ +} + +#if DT_INST_IRQ_HAS_NAME(0, overflow) +static void mcux_ftm_isr_overflow(const struct device *dev) +{ + mcux_ftm_handle_overflow(dev); +} +#endif +#if DT_INST_IRQ_HAS_NAME(0, 0_1) +FTM_ISR_FUNC(0, 1) +#endif +#if DT_INST_IRQ_HAS_NAME(0, 2_3) +FTM_ISR_FUNC(2, 3) +#endif +#if DT_INST_IRQ_HAS_NAME(0, 4_5) +FTM_ISR_FUNC(4, 5) +#endif +#if DT_INST_IRQ_HAS_NAME(0, 6_7) +FTM_ISR_FUNC(6, 7) +#endif +#endif /* IS_EQ(DT_NUM_IRQS(DT_DRV_INST(0)), 1) */ #define FTM_CFG_CAPTURE_INIT(n) \ .irq_config_func = mcux_ftm_config_func_##n #define FTM_INIT_CFG(n) FTM_DECLARE_CFG(n, FTM_CFG_CAPTURE_INIT(n)) From aeebe484f275c84ff56fd22a7e1dce7fefa603d9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Manuel=20Arg=C3=BCelles?= Date: Sat, 16 Dec 2023 11:54:31 +0700 Subject: [PATCH 1735/3723] soc: arm: nxp_s32: s32k1: add FlexTimer support MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Add support for FlexTimer (FTM) module on S32K1xx devices. Signed-off-by: Manuel Argüelles --- dts/arm/nxp/nxp_s32k146.dtsi | 2 + dts/arm/nxp/nxp_s32k1xx.dtsi | 80 ++++++++++++++++++++++++++++ soc/arm/nxp_s32/s32k1/Kconfig.series | 1 + west.yml | 2 +- 4 files changed, 84 insertions(+), 1 deletion(-) diff --git a/dts/arm/nxp/nxp_s32k146.dtsi b/dts/arm/nxp/nxp_s32k146.dtsi index b875f09ce65..be62957cae2 100644 --- a/dts/arm/nxp/nxp_s32k146.dtsi +++ b/dts/arm/nxp/nxp_s32k146.dtsi @@ -34,6 +34,8 @@ }; /delete-node/ &lpi2c1; +/delete-node/ &ftm6; +/delete-node/ &ftm7; &nvic { arm,num-irq-priority-bits = <4>; diff --git a/dts/arm/nxp/nxp_s32k1xx.dtsi b/dts/arm/nxp/nxp_s32k1xx.dtsi index 5a5a32fefa6..dc0763a0e9f 100644 --- a/dts/arm/nxp/nxp_s32k1xx.dtsi +++ b/dts/arm/nxp/nxp_s32k1xx.dtsi @@ -202,5 +202,85 @@ nxp,kinetis-port = <&porte>; status = "disabled"; }; + + ftm0: ftm@40038000 { + compatible = "nxp,kinetis-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 = <&clock NXP_S32_RTC_CLK>; + prescaler = <1>; + status = "disabled"; + }; + + ftm1: ftm@40039000 { + compatible = "nxp,kinetis-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 = <&clock NXP_S32_RTC_CLK>; + prescaler = <1>; + status = "disabled"; + }; + + ftm2: ftm@4003a000 { + compatible = "nxp,kinetis-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 = <&clock NXP_S32_RTC_CLK>; + prescaler = <1>; + status = "disabled"; + }; + + ftm3: ftm@40026000 { + compatible = "nxp,kinetis-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 = <&clock NXP_S32_RTC_CLK>; + prescaler = <1>; + status = "disabled"; + }; + + ftm4: ftm@4006e000 { + compatible = "nxp,kinetis-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 = <&clock NXP_S32_RTC_CLK>; + prescaler = <1>; + status = "disabled"; + }; + + ftm5: ftm@4006f000 { + compatible = "nxp,kinetis-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 = <&clock NXP_S32_RTC_CLK>; + prescaler = <1>; + status = "disabled"; + }; + + ftm6: ftm@40070000 { + compatible = "nxp,kinetis-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 = <&clock NXP_S32_RTC_CLK>; + prescaler = <1>; + status = "disabled"; + }; + + ftm7: ftm@40071000 { + compatible = "nxp,kinetis-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 = <&clock NXP_S32_RTC_CLK>; + prescaler = <1>; + status = "disabled"; + }; }; }; diff --git a/soc/arm/nxp_s32/s32k1/Kconfig.series b/soc/arm/nxp_s32/s32k1/Kconfig.series index 9b6f0086509..df7070e8e75 100644 --- a/soc/arm/nxp_s32/s32k1/Kconfig.series +++ b/soc/arm/nxp_s32/s32k1/Kconfig.series @@ -16,5 +16,6 @@ config SOC_SERIES_S32K1XX select HAS_MCUX_LPUART select HAS_MCUX_LPI2C select HAS_MCUX_LPSPI + select HAS_MCUX_FTM help Enable support for NXP S32K1XX MCU series. diff --git a/west.yml b/west.yml index 71d85b47763..65db6c88a7b 100644 --- a/west.yml +++ b/west.yml @@ -193,7 +193,7 @@ manifest: groups: - hal - name: hal_nxp - revision: ed3efff426ce56230be189d99ce985ceafece4a4 + revision: 4605f6715c6a55121da8fcbff060e01c4383c1e9 path: modules/hal/nxp groups: - hal From a38eb9b2101bfff54fa1041edf18611838b4367f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Manuel=20Arg=C3=BCelles?= Date: Sat, 16 Dec 2023 11:54:31 +0700 Subject: [PATCH 1736/3723] boards: arm: ucans32k1sic: enable FlexTimer/PWM support MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Enable FlexTimer (FTM) as a PWM controller for this board. Use the RGB LED controlled by FTM0 as PWM-LEDs for the samples and tests. Signed-off-by: Manuel Argüelles --- boards/arm/ucans32k1sic/doc/index.rst | 34 +++++++++---- .../ucans32k1sic/ucans32k1sic-pinctrl.dtsi | 23 +++++++++ boards/arm/ucans32k1sic/ucans32k1sic.dts | 50 +++++++++++++++++++ boards/arm/ucans32k1sic/ucans32k1sic.yaml | 1 + 4 files changed, 99 insertions(+), 9 deletions(-) diff --git a/boards/arm/ucans32k1sic/doc/index.rst b/boards/arm/ucans32k1sic/doc/index.rst index 1291eeb9890..efeb6911d7e 100644 --- a/boards/arm/ucans32k1sic/doc/index.rst +++ b/boards/arm/ucans32k1sic/doc/index.rst @@ -49,6 +49,7 @@ GPIO on-chip gpio LPUART on-chip serial LPI2C on-chip i2c LPSPI on-chip spi +FTM on-chip pwm ============ ========== ================================ The default configuration can be found in the Kconfig file @@ -67,15 +68,30 @@ children nodes with the desired pinmux configuration to the singleton node LEDs ---- -The UCANS32K1SIC board has one user RGB LED: - -======================= ============== ===== -Devicetree node Label Pin -======================= ============== ===== -led0 / led1_red LED1_RGB_RED PTD15 -led1 / led1_green LED1_RGB_GREEN PTD16 -led2 / led1_blue LED1_RGB_BLUE PTD0 -======================= ============== ===== +The UCANS32K1SIC board has one user RGB LED that can be used either as a GPIO +LED or as a PWM LED. + +.. table:: RGB LED as GPIO LED + :widths: auto + + =============== ================ =============== ===== + Devicetree node Devicetree alias Label Pin + =============== ================ =============== ===== + led1_red led0 LED1_RGB_RED PTD15 + led1_green led1 LED1_RGB_GREEN PTD16 + led1_blue led2 LED1_RGB_BLUE PTD0 + =============== ================ =============== ===== + +.. table:: RGB LED as PWM LED + :widths: auto + + =============== ======================== ================== ================ + Devicetree node Devicetree alias Label Pin + =============== ======================== ================== ================ + led1_red_pwm pwm-led0 / red-pwm-led LED1_RGB_RED_PWM PTD15 / FTM0_CH0 + led1_green_pwm pwm-led1 / green-pwm-led LED1_RGB_GREEN_PWM PTD16 / FTM0_CH1 + led1_blue_pwm pwm-led2 / blue-pwm-led LED1_RGB_BLUE_PWM PTD0 / FTM0_CH2 + =============== ======================== ================== ================ The user can control the LEDs in any way. An output of ``0`` illuminates the LED. diff --git a/boards/arm/ucans32k1sic/ucans32k1sic-pinctrl.dtsi b/boards/arm/ucans32k1sic/ucans32k1sic-pinctrl.dtsi index d3926d9866e..b1451d26287 100644 --- a/boards/arm/ucans32k1sic/ucans32k1sic-pinctrl.dtsi +++ b/boards/arm/ucans32k1sic/ucans32k1sic-pinctrl.dtsi @@ -37,4 +37,27 @@ drive-strength = "low"; }; }; + + ftm0_default: ftm0_default { + group0 { + pinmux = , + , + ; + drive-strength = "low"; + }; + }; + + ftm1_default: ftm1_default { + group0 { + pinmux = ; + drive-strength = "low"; + }; + }; + + ftm2_default: ftm2_default { + group0 { + pinmux = ; + drive-strength = "low"; + }; + }; }; diff --git a/boards/arm/ucans32k1sic/ucans32k1sic.dts b/boards/arm/ucans32k1sic/ucans32k1sic.dts index 49b30d168e2..23a380b4c44 100644 --- a/boards/arm/ucans32k1sic/ucans32k1sic.dts +++ b/boards/arm/ucans32k1sic/ucans32k1sic.dts @@ -7,6 +7,7 @@ /dts-v1/; #include #include +#include #include #include "ucans32k1sic-pinctrl.dtsi" @@ -26,6 +27,13 @@ led0 = &led1_red; led1 = &led1_green; led2 = &led1_blue; + pwm-led0 = &led1_red_pwm; + pwm-led1 = &led1_green_pwm; + pwm-led2 = &led1_blue_pwm; + red-pwm-led = &led1_red_pwm; + green-pwm-led = &led1_green_pwm; + blue-pwm-led = &led1_blue_pwm; + pwm-0 = &ftm0; sw0 = &button_3; i2c-0 = &lpi2c0; }; @@ -47,6 +55,23 @@ }; }; + pwmleds { + compatible = "pwm-leds"; + + led1_red_pwm: led_pwm_0 { + pwms = <&ftm0 0 PWM_MSEC(20) PWM_POLARITY_INVERTED>; + label = "LED1_RGB_RED_PWM"; + }; + led1_green_pwm: led_pwm_1 { + pwms = <&ftm0 1 PWM_MSEC(20) PWM_POLARITY_INVERTED>; + label = "LED1_RGB_GREEN_PWM"; + }; + led1_blue_pwm: led_pwm_2 { + pwms = <&ftm0 2 PWM_MSEC(20) PWM_POLARITY_INVERTED>; + label = "LED1_RGB_BLUE_PWM"; + }; + }; + gpio_keys { compatible = "gpio-keys"; @@ -104,3 +129,28 @@ pinctrl-names = "default"; status = "okay"; }; + +&ftm0 { + compatible = "nxp,kinetis-ftm-pwm"; + pinctrl-0 = <&ftm0_default>; + pinctrl-names = "default"; + prescaler = <128>; + #pwm-cells = <3>; + status = "okay"; +}; + +&ftm1 { + compatible = "nxp,kinetis-ftm-pwm"; + pinctrl-0 = <&ftm1_default>; + pinctrl-names = "default"; + #pwm-cells = <3>; + status = "okay"; +}; + +&ftm2 { + compatible = "nxp,kinetis-ftm-pwm"; + pinctrl-0 = <&ftm2_default>; + pinctrl-names = "default"; + #pwm-cells = <3>; + status = "okay"; +}; diff --git a/boards/arm/ucans32k1sic/ucans32k1sic.yaml b/boards/arm/ucans32k1sic/ucans32k1sic.yaml index 8519980aa60..fd0b23a40b9 100644 --- a/boards/arm/ucans32k1sic/ucans32k1sic.yaml +++ b/boards/arm/ucans32k1sic/ucans32k1sic.yaml @@ -17,3 +17,4 @@ supported: - pinctrl - i2c - spi + - pwm From 7e2600d3092166279dda42bdb6d56a43f4dd8562 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Manuel=20Arg=C3=BCelles?= Date: Sat, 16 Dec 2023 11:54:31 +0700 Subject: [PATCH 1737/3723] tests: drivers: pwm: add overlays for ucans32k1sic MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Enable pwm tests on ucans32k1sic board. Signed-off-by: Manuel Argüelles --- .../pwm_loopback/boards/ucans32k1sic.overlay | 43 +++++++++++++++++++ 1 file changed, 43 insertions(+) create mode 100644 tests/drivers/pwm/pwm_loopback/boards/ucans32k1sic.overlay diff --git a/tests/drivers/pwm/pwm_loopback/boards/ucans32k1sic.overlay b/tests/drivers/pwm/pwm_loopback/boards/ucans32k1sic.overlay new file mode 100644 index 00000000000..01c43d6a27b --- /dev/null +++ b/tests/drivers/pwm/pwm_loopback/boards/ucans32k1sic.overlay @@ -0,0 +1,43 @@ +/* + * Copyright 2023 NXP + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include + +/ { + pwm_loopback_0 { + compatible = "test-pwm-loopback"; + pwms = <&ftm1 1 0 PWM_POLARITY_NORMAL>, /* PTB3, P1.3 */ + <&ftm0 4 0 PWM_POLARITY_NORMAL>; /* PTB4, P1.4 */ + }; +}; + +&pinctrl { + ftm0_loopback: ftm0_loopback { + group0 { + pinmux = ; + drive-strength = "low"; + }; + }; + + ftm1_loopback: ftm1_loopback { + group0 { + pinmux = ; + drive-strength = "low"; + }; + }; +}; + +&ftm0 { + pinctrl-0 = <&ftm0_loopback>; + prescaler = <32>; + status = "okay"; +}; + +&ftm1 { + pinctrl-0 = <&ftm1_loopback>; + prescaler = <128>; + status = "okay"; +}; From f6235e03cfc88eafa84b9984c0bc75bf511a782c Mon Sep 17 00:00:00 2001 From: Marc Desvaux Date: Wed, 20 Dec 2023 11:34:14 +0100 Subject: [PATCH 1738/3723] boards: arm: enable CONFIG_USB_DC_HAS_HS_SUPPORT enable CONFIG_USB_DC_HAS_HS_SUPPORT when we use only OTG_HS and not OTG_FS. in that case TEST_BULK_EP_MPS (Endpoint max packet size) equal 512 and not 64 it is the case for nucleo_h723zg and for nucleo_h7a3zi_q Signed-off-by: Marc Desvaux --- boards/arm/nucleo_h723zg/Kconfig.defconfig | 4 ++++ boards/arm/nucleo_h7a3zi_q/Kconfig.defconfig | 4 ++++ 2 files changed, 8 insertions(+) diff --git a/boards/arm/nucleo_h723zg/Kconfig.defconfig b/boards/arm/nucleo_h723zg/Kconfig.defconfig index 7b5c327e97d..26f4491a7ad 100644 --- a/boards/arm/nucleo_h723zg/Kconfig.defconfig +++ b/boards/arm/nucleo_h723zg/Kconfig.defconfig @@ -15,4 +15,8 @@ config NET_L2_ETHERNET endif # NETWORKING +config USB_DC_HAS_HS_SUPPORT + default y + depends on USB_DC_STM32 + endif # BOARD_NUCLEO_H723ZG diff --git a/boards/arm/nucleo_h7a3zi_q/Kconfig.defconfig b/boards/arm/nucleo_h7a3zi_q/Kconfig.defconfig index 922423e3669..ec43ace7dcb 100644 --- a/boards/arm/nucleo_h7a3zi_q/Kconfig.defconfig +++ b/boards/arm/nucleo_h7a3zi_q/Kconfig.defconfig @@ -8,4 +8,8 @@ if BOARD_NUCLEO_H7A3ZI_Q config BOARD default "nucleo_h7a3zi_q" +config USB_DC_HAS_HS_SUPPORT + default y + depends on USB_DC_STM32 + endif # BOARD_NUCLEO_H7A3ZI_Q From 1bbaaeffb0c24b4252ffd6f72e2c6781bb1ef853 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?J=C4=99drzej=20Ciupis?= Date: Wed, 3 Jan 2024 08:46:08 +0100 Subject: [PATCH 1739/3723] manifest: update hal_nordic revision MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This commit updates revision of hal_nordic to bring the latest changes in the nRF IEEE 802.15.4 driver. Signed-off-by: Jędrzej Ciupis --- west.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/west.yml b/west.yml index 65db6c88a7b..d67fa039322 100644 --- a/west.yml +++ b/west.yml @@ -183,7 +183,7 @@ manifest: groups: - hal - name: hal_nordic - revision: b9633ecea67bf52925d4c61455046223b46402b1 + revision: 3786c55424d4d64c62dd25219de31618cef26fdf path: modules/hal/nordic groups: - hal From 5767998d4f7f9ef89a6983e4c540215676051e7a Mon Sep 17 00:00:00 2001 From: Eduardo Montoya Date: Tue, 31 Oct 2023 09:42:36 +0100 Subject: [PATCH 1740/3723] drivers: ieee802154: nrf: make selective tx power the default MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Remove `IEEE802154_SELECTIVE_TXPOWER` option. Cache the tx power value in nRF5 driver and make use of it on each operation. Signed-off-by: Eduardo Montoya Signed-off-by: Jędrzej Ciupis --- doc/releases/release-notes-3.6.rst | 2 ++ drivers/ieee802154/Kconfig | 5 ----- drivers/ieee802154/ieee802154_nrf5.c | 24 +++++++++++------------- drivers/ieee802154/ieee802154_nrf5.h | 3 +++ include/zephyr/net/ieee802154_pkt.h | 18 ------------------ modules/openthread/platform/radio.c | 7 +------ 6 files changed, 17 insertions(+), 42 deletions(-) diff --git a/doc/releases/release-notes-3.6.rst b/doc/releases/release-notes-3.6.rst index c86fb41d09a..86528e4adf6 100644 --- a/doc/releases/release-notes-3.6.rst +++ b/doc/releases/release-notes-3.6.rst @@ -182,6 +182,8 @@ Drivers and Sensors * IEEE 802.15.4 + * Removed :kconfig:option:`CONFIG_IEEE802154_SELECTIVE_TXPOWER` Kconfig option. + * Interrupt Controller * Input diff --git a/drivers/ieee802154/Kconfig b/drivers/ieee802154/Kconfig index feccd4a6001..d692024b096 100644 --- a/drivers/ieee802154/Kconfig +++ b/drivers/ieee802154/Kconfig @@ -98,11 +98,6 @@ config IEEE802154_CSL_DEBUG help Enable support for CSL debugging by avoiding sleep state in favor of receive state. -config IEEE802154_SELECTIVE_TXPOWER - bool "Support selective TX power setting" - help - Enable support for selectively setting TX power for every transmission request. - module = IEEE802154_DRIVER module-str = IEEE 802.15.4 driver module-help = Sets log level for IEEE 802.15.4 Device Drivers. diff --git a/drivers/ieee802154/ieee802154_nrf5.c b/drivers/ieee802154/ieee802154_nrf5.c index df01f530abf..8401cac961a 100644 --- a/drivers/ieee802154/ieee802154_nrf5.c +++ b/drivers/ieee802154/ieee802154_nrf5.c @@ -375,7 +375,7 @@ static int nrf5_set_txpower(const struct device *dev, int16_t dbm) LOG_DBG("%d", dbm); - nrf_802154_tx_power_set(dbm); + nrf5_data.txpwr = dbm; return 0; } @@ -454,10 +454,8 @@ static bool nrf5_tx_immediate(struct net_pkt *pkt, uint8_t *payload, bool cca) }, .cca = cca, .tx_power = { - .use_metadata_value = IS_ENABLED(CONFIG_IEEE802154_SELECTIVE_TXPOWER), -#if defined(CONFIG_IEEE802154_SELECTIVE_TXPOWER) - .power = net_pkt_ieee802154_txpwr(pkt), -#endif + .use_metadata_value = true, + .power = nrf5_data.txpwr, }, }; @@ -473,10 +471,8 @@ static bool nrf5_tx_csma_ca(struct net_pkt *pkt, uint8_t *payload) .dynamic_data_is_set = net_pkt_ieee802154_mac_hdr_rdy(pkt), }, .tx_power = { - .use_metadata_value = IS_ENABLED(CONFIG_IEEE802154_SELECTIVE_TXPOWER), -#if defined(CONFIG_IEEE802154_SELECTIVE_TXPOWER) - .power = net_pkt_ieee802154_txpwr(pkt), -#endif + .use_metadata_value = true, + .power = nrf5_data.txpwr, }, }; @@ -519,10 +515,8 @@ static bool nrf5_tx_at(struct nrf5_802154_data *nrf5_radio, struct net_pkt *pkt, .cca = cca, .channel = nrf_802154_channel_get(), .tx_power = { - .use_metadata_value = IS_ENABLED(CONFIG_IEEE802154_SELECTIVE_TXPOWER), -#if defined(CONFIG_IEEE802154_SELECTIVE_TXPOWER) - .power = net_pkt_ieee802154_txpwr(pkt), -#endif + .use_metadata_value = true, + .power = nrf5_data.txpwr, }, #if defined(CONFIG_IEEE802154_NRF5_MULTIPLE_CCA) .extra_cca_attempts = max_extra_cca_attempts, @@ -660,6 +654,8 @@ static int nrf5_start(const struct device *dev) { ARG_UNUSED(dev); + nrf_802154_tx_power_set(nrf5_data.txpwr); + if (!nrf_802154_receive()) { LOG_ERR("Failed to enter receive state"); return -EIO; @@ -702,6 +698,8 @@ static int nrf5_continuous_carrier(const struct device *dev) { ARG_UNUSED(dev); + nrf_802154_tx_power_set(nrf5_data.txpwr); + if (!nrf_802154_continuous_carrier()) { LOG_ERR("Failed to enter continuous carrier state"); return -EIO; diff --git a/drivers/ieee802154/ieee802154_nrf5.h b/drivers/ieee802154/ieee802154_nrf5.h index 9115fe0bdae..79b47827d72 100644 --- a/drivers/ieee802154/ieee802154_nrf5.h +++ b/drivers/ieee802154/ieee802154_nrf5.h @@ -97,6 +97,9 @@ struct nrf5_802154_data { uint8_t max_extra_cca_attempts; #endif + /* The TX power in dBm. */ + int8_t txpwr; + #if defined(CONFIG_NRF_802154_SER_HOST) && defined(CONFIG_IEEE802154_CSL_ENDPOINT) /* The last configured value of CSL period in units of 10 symbols. */ uint32_t csl_period; diff --git a/include/zephyr/net/ieee802154_pkt.h b/include/zephyr/net/ieee802154_pkt.h index d5fdc712b49..3270f994248 100644 --- a/include/zephyr/net/ieee802154_pkt.h +++ b/include/zephyr/net/ieee802154_pkt.h @@ -59,12 +59,6 @@ struct net_pkt_cb_ieee802154 { */ uint8_t rssi; }; -#if defined(CONFIG_IEEE802154_SELECTIVE_TXPOWER) - /* TX packets */ - struct { - int8_t txpwr; /* TX power in dBm. */ - }; -#endif /* CONFIG_IEEE802154_SELECTIVE_TXPOWER */ }; /* Flags */ @@ -185,18 +179,6 @@ static inline void net_pkt_set_ieee802154_rssi_dbm(struct net_pkt *pkt, int16_t CODE_UNREACHABLE; } -#if defined(CONFIG_IEEE802154_SELECTIVE_TXPOWER) -static inline int8_t net_pkt_ieee802154_txpwr(struct net_pkt *pkt) -{ - return net_pkt_cb_ieee802154(pkt)->txpwr; -} - -static inline void net_pkt_set_ieee802154_txpwr(struct net_pkt *pkt, int8_t txpwr) -{ - net_pkt_cb_ieee802154(pkt)->txpwr = txpwr; -} -#endif /* CONFIG_IEEE802154_SELECTIVE_TXPOWER */ - static inline bool net_pkt_ieee802154_ack_fpb(struct net_pkt *pkt) { return net_pkt_cb_ieee802154(pkt)->ack_fpb; diff --git a/modules/openthread/platform/radio.c b/modules/openthread/platform/radio.c index 631d00bdca6..480907380a2 100644 --- a/modules/openthread/platform/radio.c +++ b/modules/openthread/platform/radio.c @@ -384,13 +384,8 @@ void transmit_message(struct k_work *tx_job) channel = sTransmitFrame.mChannel; - radio_api->set_channel(radio_dev, sTransmitFrame.mChannel); - -#if defined(CONFIG_IEEE802154_SELECTIVE_TXPOWER) - net_pkt_set_ieee802154_txpwr(tx_pkt, get_transmit_power_for_channel(channel)); -#else + radio_api->set_channel(radio_dev, channel); radio_api->set_txpower(radio_dev, get_transmit_power_for_channel(channel)); -#endif /* CONFIG_IEEE802154_SELECTIVE_TXPOWER */ net_pkt_set_ieee802154_frame_secured(tx_pkt, sTransmitFrame.mInfo.mTxInfo.mIsSecurityProcessed); From 780b12854c11f10f6b3e4b21ae02eaa1b2965736 Mon Sep 17 00:00:00 2001 From: Eduardo Montoya Date: Tue, 31 Oct 2023 10:24:18 +0100 Subject: [PATCH 1741/3723] drivers: ieee802154: nrf: cache radio channel MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Cache configured radio channel and apply them only when a relevant radio task is requested. This allows to configure the channel in the transmit metadata, thus avoiding unneeded `nrf_802154` API calls in some scenarios. Signed-off-by: Eduardo Montoya Signed-off-by: Jędrzej Ciupis --- drivers/ieee802154/ieee802154_nrf5.c | 18 ++++++++++++++++-- drivers/ieee802154/ieee802154_nrf5.h | 3 +++ 2 files changed, 19 insertions(+), 2 deletions(-) diff --git a/drivers/ieee802154/ieee802154_nrf5.c b/drivers/ieee802154/ieee802154_nrf5.c index 8401cac961a..22863a52e67 100644 --- a/drivers/ieee802154/ieee802154_nrf5.c +++ b/drivers/ieee802154/ieee802154_nrf5.c @@ -254,6 +254,8 @@ static int nrf5_cca(const struct device *dev) { struct nrf5_802154_data *nrf5_radio = NRF5_802154_DATA(dev); + nrf_802154_channel_set(nrf5_data.channel); + if (!nrf_802154_cca()) { LOG_DBG("CCA failed"); return -EBUSY; @@ -279,7 +281,7 @@ static int nrf5_set_channel(const struct device *dev, uint16_t channel) return channel < 11 ? -ENOTSUP : -EINVAL; } - nrf_802154_channel_set(channel); + nrf5_data.channel = channel; return 0; } @@ -292,6 +294,8 @@ static int nrf5_energy_scan_start(const struct device *dev, ARG_UNUSED(dev); + nrf_802154_channel_set(nrf5_data.channel); + if (nrf5_data.energy_scan_done == NULL) { nrf5_data.energy_scan_done = done_cb; @@ -457,6 +461,10 @@ static bool nrf5_tx_immediate(struct net_pkt *pkt, uint8_t *payload, bool cca) .use_metadata_value = true, .power = nrf5_data.txpwr, }, + .tx_channel = { + .use_metadata_value = true, + .channel = nrf5_data.channel, + }, }; return nrf_802154_transmit_raw(payload, &metadata); @@ -474,6 +482,10 @@ static bool nrf5_tx_csma_ca(struct net_pkt *pkt, uint8_t *payload) .use_metadata_value = true, .power = nrf5_data.txpwr, }, + .tx_channel = { + .use_metadata_value = true, + .channel = nrf5_data.channel, + }, }; return nrf_802154_transmit_csma_ca_raw(payload, &metadata); @@ -513,7 +525,7 @@ static bool nrf5_tx_at(struct nrf5_802154_data *nrf5_radio, struct net_pkt *pkt, .dynamic_data_is_set = net_pkt_ieee802154_mac_hdr_rdy(pkt), }, .cca = cca, - .channel = nrf_802154_channel_get(), + .channel = nrf5_data.channel, .tx_power = { .use_metadata_value = true, .power = nrf5_data.txpwr, @@ -655,6 +667,7 @@ static int nrf5_start(const struct device *dev) ARG_UNUSED(dev); nrf_802154_tx_power_set(nrf5_data.txpwr); + nrf_802154_channel_set(nrf5_data.channel); if (!nrf_802154_receive()) { LOG_ERR("Failed to enter receive state"); @@ -699,6 +712,7 @@ static int nrf5_continuous_carrier(const struct device *dev) ARG_UNUSED(dev); nrf_802154_tx_power_set(nrf5_data.txpwr); + nrf_802154_channel_set(nrf5_data.channel); if (!nrf_802154_continuous_carrier()) { LOG_ERR("Failed to enter continuous carrier state"); diff --git a/drivers/ieee802154/ieee802154_nrf5.h b/drivers/ieee802154/ieee802154_nrf5.h index 79b47827d72..b9f46dff307 100644 --- a/drivers/ieee802154/ieee802154_nrf5.h +++ b/drivers/ieee802154/ieee802154_nrf5.h @@ -100,6 +100,9 @@ struct nrf5_802154_data { /* The TX power in dBm. */ int8_t txpwr; + /* The radio channel. */ + uint8_t channel; + #if defined(CONFIG_NRF_802154_SER_HOST) && defined(CONFIG_IEEE802154_CSL_ENDPOINT) /* The last configured value of CSL period in units of 10 symbols. */ uint32_t csl_period; From 586eca8ad27951727440c61e7fcaf4e67eb4502c Mon Sep 17 00:00:00 2001 From: Eduardo Montoya Date: Tue, 31 Oct 2023 10:23:51 +0100 Subject: [PATCH 1742/3723] drivers: ieee802154: nrf5: add `IEEE802154_RX_ON_WHEN_IDLE` capability Add `IEEE802154_RX_ON_WHEN_IDLE` capability. Signed-off-by: Eduardo Montoya --- drivers/ieee802154/ieee802154_nrf5.c | 21 +++++++-------------- 1 file changed, 7 insertions(+), 14 deletions(-) diff --git a/drivers/ieee802154/ieee802154_nrf5.c b/drivers/ieee802154/ieee802154_nrf5.c index 22863a52e67..379655cd3ce 100644 --- a/drivers/ieee802154/ieee802154_nrf5.c +++ b/drivers/ieee802154/ieee802154_nrf5.c @@ -236,6 +236,7 @@ static void nrf5_get_capabilities_at_boot(void) ((caps & NRF_802154_CAPABILITY_DELAYED_TX) ? IEEE802154_HW_TXTIME : 0UL) | ((caps & NRF_802154_CAPABILITY_DELAYED_RX) ? IEEE802154_HW_RXTIME : 0UL) | IEEE802154_HW_SLEEP_TO_TX | + IEEE802154_RX_ON_WHEN_IDLE | ((caps & NRF_802154_CAPABILITY_SECURITY) ? IEEE802154_HW_TX_SEC : 0UL) #if defined(CONFIG_IEEE802154_NRF5_MULTIPLE_CCA) | IEEE802154_OPENTHREAD_HW_MULTIPLE_CCA @@ -987,6 +988,10 @@ static int nrf5_configure(const struct device *dev, break; #endif /* CONFIG_IEEE802154_NRF5_MULTIPLE_CCA */ + case IEEE802154_CONFIG_RX_ON_WHEN_IDLE: + nrf_802154_rx_on_when_idle_set(config->rx_on_when_idle); + break; + default: return -EINVAL; } @@ -1064,20 +1069,8 @@ void nrf_802154_receive_failed(nrf_802154_rx_error_t error, uint32_t id) const struct device *dev = nrf5_get_device(); #if defined(CONFIG_IEEE802154_CSL_ENDPOINT) - if (id == DRX_SLOT_RX) { - __ASSERT_NO_MSG(nrf5_data.event_handler); -#if !defined(CONFIG_IEEE802154_CSL_DEBUG) - /* When CSL debug option is used we intentionally avoid notifying the higher layer - * about the finalization of a DRX slot, so that the radio stays in receive state - * for receiving "out of slot" frames. - * As a side effect, regular failure notifications would be reported with the - * incorrect ID. - */ - nrf5_data.event_handler(dev, IEEE802154_EVENT_RX_OFF, NULL); -#endif - if (error == NRF_802154_RX_ERROR_DELAYED_TIMEOUT) { - return; - } + if (id == DRX_SLOT_RX && error == NRF_802154_RX_ERROR_DELAYED_TIMEOUT) { + return; } #else ARG_UNUSED(id); From 80e1482dddd6b96f0632ecea1301a21ee8daa8ec Mon Sep 17 00:00:00 2001 From: Pisit Sawangvonganan Date: Mon, 25 Dec 2023 22:16:28 +0700 Subject: [PATCH 1743/3723] drivers: ieee802154: set 'ieee802154_radio_api' as 'static const' This change marks each instance of the 'api' as 'static const'. The rationale is that 'api' is used for declaring internal module interfaces and is not intended to be modified at runtime. By using 'static const', we ensure immutability, leading to usage of only .rodata and a reduction in the .data area. Signed-off-by: Pisit Sawangvonganan --- drivers/ieee802154/ieee802154_b91.c | 2 +- drivers/ieee802154/ieee802154_cc1200.c | 2 +- drivers/ieee802154/ieee802154_cc13xx_cc26xx.c | 2 +- drivers/ieee802154/ieee802154_cc13xx_cc26xx_subg.c | 2 +- drivers/ieee802154/ieee802154_cc2520.c | 2 +- drivers/ieee802154/ieee802154_dw1000.c | 2 +- drivers/ieee802154/ieee802154_kw41z.c | 2 +- drivers/ieee802154/ieee802154_mcr20a.c | 2 +- drivers/ieee802154/ieee802154_nrf5.c | 2 +- drivers/ieee802154/ieee802154_rf2xx.c | 2 +- drivers/ieee802154/ieee802154_uart_pipe.c | 2 +- 11 files changed, 11 insertions(+), 11 deletions(-) diff --git a/drivers/ieee802154/ieee802154_b91.c b/drivers/ieee802154/ieee802154_b91.c index 0557c533944..e19356a272a 100644 --- a/drivers/ieee802154/ieee802154_b91.c +++ b/drivers/ieee802154/ieee802154_b91.c @@ -617,7 +617,7 @@ static int b91_attr_get(const struct device *dev, enum ieee802154_attr attr, } /* IEEE802154 driver APIs structure */ -static struct ieee802154_radio_api b91_radio_api = { +static const struct ieee802154_radio_api b91_radio_api = { .iface_api.init = b91_iface_init, .get_capabilities = b91_get_capabilities, .cca = b91_cca, diff --git a/drivers/ieee802154/ieee802154_cc1200.c b/drivers/ieee802154/ieee802154_cc1200.c index e5f8ea36670..7bc3aa3ed12 100644 --- a/drivers/ieee802154/ieee802154_cc1200.c +++ b/drivers/ieee802154/ieee802154_cc1200.c @@ -813,7 +813,7 @@ static const struct cc1200_config cc1200_config = { static struct cc1200_context cc1200_context_data; -static struct ieee802154_radio_api cc1200_radio_api = { +static const struct ieee802154_radio_api cc1200_radio_api = { .iface_api.init = cc1200_iface_init, .get_capabilities = cc1200_get_capabilities, diff --git a/drivers/ieee802154/ieee802154_cc13xx_cc26xx.c b/drivers/ieee802154/ieee802154_cc13xx_cc26xx.c index 5d5a53ed08e..263b98d2823 100644 --- a/drivers/ieee802154/ieee802154_cc13xx_cc26xx.c +++ b/drivers/ieee802154/ieee802154_cc13xx_cc26xx.c @@ -570,7 +570,7 @@ static void ieee802154_cc13xx_cc26xx_iface_init(struct net_if *iface) ieee802154_init(iface); } -static struct ieee802154_radio_api ieee802154_cc13xx_cc26xx_radio_api = { +static const struct ieee802154_radio_api ieee802154_cc13xx_cc26xx_radio_api = { .iface_api.init = ieee802154_cc13xx_cc26xx_iface_init, .get_capabilities = ieee802154_cc13xx_cc26xx_get_capabilities, diff --git a/drivers/ieee802154/ieee802154_cc13xx_cc26xx_subg.c b/drivers/ieee802154/ieee802154_cc13xx_cc26xx_subg.c index ea626908d16..dbaa02ff9eb 100644 --- a/drivers/ieee802154/ieee802154_cc13xx_cc26xx_subg.c +++ b/drivers/ieee802154/ieee802154_cc13xx_cc26xx_subg.c @@ -909,7 +909,7 @@ static void ieee802154_cc13xx_cc26xx_subg_iface_init(struct net_if *iface) ieee802154_init(iface); } -static struct ieee802154_radio_api +static const struct ieee802154_radio_api ieee802154_cc13xx_cc26xx_subg_radio_api = { .iface_api.init = ieee802154_cc13xx_cc26xx_subg_iface_init, diff --git a/drivers/ieee802154/ieee802154_cc2520.c b/drivers/ieee802154/ieee802154_cc2520.c index cf7c1091661..1f86d20d02f 100644 --- a/drivers/ieee802154/ieee802154_cc2520.c +++ b/drivers/ieee802154/ieee802154_cc2520.c @@ -1057,7 +1057,7 @@ static const struct cc2520_config cc2520_config = { static struct cc2520_context cc2520_context_data; -static struct ieee802154_radio_api cc2520_radio_api = { +static const struct ieee802154_radio_api cc2520_radio_api = { .iface_api.init = cc2520_iface_init, .get_capabilities = cc2520_get_capabilities, diff --git a/drivers/ieee802154/ieee802154_dw1000.c b/drivers/ieee802154/ieee802154_dw1000.c index d20df488966..13d5e047544 100644 --- a/drivers/ieee802154/ieee802154_dw1000.c +++ b/drivers/ieee802154/ieee802154_dw1000.c @@ -1659,7 +1659,7 @@ static void dwt_iface_api_init(struct net_if *iface) LOG_INF("Iface initialized"); } -static struct ieee802154_radio_api dwt_radio_api = { +static const struct ieee802154_radio_api dwt_radio_api = { .iface_api.init = dwt_iface_api_init, .get_capabilities = dwt_get_capabilities, diff --git a/drivers/ieee802154/ieee802154_kw41z.c b/drivers/ieee802154/ieee802154_kw41z.c index aee802ad6ff..40064c6df7b 100644 --- a/drivers/ieee802154/ieee802154_kw41z.c +++ b/drivers/ieee802154/ieee802154_kw41z.c @@ -1091,7 +1091,7 @@ static int kw41z_attr_get(const struct device *dev, enum ieee802154_attr attr, &drv_attr.phy_supported_channels, value); } -static struct ieee802154_radio_api kw41z_radio_api = { +static const struct ieee802154_radio_api kw41z_radio_api = { .iface_api.init = kw41z_iface_init, .get_capabilities = kw41z_get_capabilities, diff --git a/drivers/ieee802154/ieee802154_mcr20a.c b/drivers/ieee802154/ieee802154_mcr20a.c index 6a1e5a99727..2e6ed142861 100644 --- a/drivers/ieee802154/ieee802154_mcr20a.c +++ b/drivers/ieee802154/ieee802154_mcr20a.c @@ -1452,7 +1452,7 @@ static const struct mcr20a_config mcr20a_config = { static struct mcr20a_context mcr20a_context_data; -static struct ieee802154_radio_api mcr20a_radio_api = { +static const struct ieee802154_radio_api mcr20a_radio_api = { .iface_api.init = mcr20a_iface_init, .get_capabilities = mcr20a_get_capabilities, diff --git a/drivers/ieee802154/ieee802154_nrf5.c b/drivers/ieee802154/ieee802154_nrf5.c index 379655cd3ce..108bcd2e14a 100644 --- a/drivers/ieee802154/ieee802154_nrf5.c +++ b/drivers/ieee802154/ieee802154_nrf5.c @@ -1199,7 +1199,7 @@ static const struct nrf5_802154_config nrf5_radio_cfg = { .irq_config_func = nrf5_irq_config, }; -static struct ieee802154_radio_api nrf5_radio_api = { +static const struct ieee802154_radio_api nrf5_radio_api = { .iface_api.init = nrf5_iface_init, .get_capabilities = nrf5_get_capabilities, diff --git a/drivers/ieee802154/ieee802154_rf2xx.c b/drivers/ieee802154/ieee802154_rf2xx.c index ac7f13580d0..4d7c188ce67 100644 --- a/drivers/ieee802154/ieee802154_rf2xx.c +++ b/drivers/ieee802154/ieee802154_rf2xx.c @@ -1084,7 +1084,7 @@ static void rf2xx_iface_init(struct net_if *iface) ieee802154_init(iface); } -static struct ieee802154_radio_api rf2xx_radio_api = { +static const struct ieee802154_radio_api rf2xx_radio_api = { .iface_api.init = rf2xx_iface_init, .get_capabilities = rf2xx_get_capabilities, diff --git a/drivers/ieee802154/ieee802154_uart_pipe.c b/drivers/ieee802154/ieee802154_uart_pipe.c index cdb420d9747..72bcf5b8ebf 100644 --- a/drivers/ieee802154/ieee802154_uart_pipe.c +++ b/drivers/ieee802154/ieee802154_uart_pipe.c @@ -392,7 +392,7 @@ static void upipe_iface_init(struct net_if *iface) static struct upipe_context upipe_context_data; -static struct ieee802154_radio_api upipe_radio_api = { +static const struct ieee802154_radio_api upipe_radio_api = { .iface_api.init = upipe_iface_init, .get_capabilities = upipe_get_capabilities, From 3ffcd754697ae3d09816d8420e23460de0a36f91 Mon Sep 17 00:00:00 2001 From: Pisit Sawangvonganan Date: Mon, 25 Dec 2023 21:35:04 +0700 Subject: [PATCH 1744/3723] drivers: spi: set 'spi_driver_api' as 'static const' This change marks each instance of the 'spi_driver_api' as 'static const'. The rationale is that 'spi_driver_api' is used for declaring internal module interfaces and is not intended to be modified at runtime. By using 'static const', we ensure immutability, leading to usage of only .rodata and a reduction in the .data area. Signed-off-by: Pisit Sawangvonganan --- drivers/spi/mspi_ambiq.c | 2 +- drivers/spi/spi_ambiq.c | 2 +- drivers/spi/spi_andes_atcspi200.c | 2 +- drivers/spi/spi_b91.c | 2 +- drivers/spi/spi_bitbang.c | 2 +- drivers/spi/spi_emul.c | 2 +- drivers/spi/spi_gd32.c | 2 +- drivers/spi/spi_gecko.c | 2 +- drivers/spi/spi_litespi.c | 2 +- drivers/spi/spi_numaker.c | 6 ++++-- drivers/spi/spi_oc_simple.c | 2 +- drivers/spi/spi_opentitan.c | 2 +- drivers/spi/spi_pl022.c | 2 +- drivers/spi/spi_rpi_pico_pio.c | 2 +- drivers/spi/spi_sifive.c | 2 +- 15 files changed, 18 insertions(+), 16 deletions(-) diff --git a/drivers/spi/mspi_ambiq.c b/drivers/spi/mspi_ambiq.c index 03ad8b2c0ac..0f24fcdfe4f 100644 --- a/drivers/spi/mspi_ambiq.c +++ b/drivers/spi/mspi_ambiq.c @@ -197,7 +197,7 @@ static int mspi_ambiq_release(const struct device *dev, const struct spi_config return 0; } -static struct spi_driver_api mspi_ambiq_driver_api = { +static const struct spi_driver_api mspi_ambiq_driver_api = { .transceive = mspi_ambiq_transceive, .release = mspi_ambiq_release, }; diff --git a/drivers/spi/spi_ambiq.c b/drivers/spi/spi_ambiq.c index 16614798e32..61d71e3f567 100644 --- a/drivers/spi/spi_ambiq.c +++ b/drivers/spi/spi_ambiq.c @@ -219,7 +219,7 @@ static int spi_ambiq_release(const struct device *dev, const struct spi_config * return 0; } -static struct spi_driver_api spi_ambiq_driver_api = { +static const struct spi_driver_api spi_ambiq_driver_api = { .transceive = spi_ambiq_transceive, .release = spi_ambiq_release, }; diff --git a/drivers/spi/spi_andes_atcspi200.c b/drivers/spi/spi_andes_atcspi200.c index 87726fd90ca..3ae422c7673 100644 --- a/drivers/spi/spi_andes_atcspi200.c +++ b/drivers/spi/spi_andes_atcspi200.c @@ -283,7 +283,7 @@ int spi_atcspi200_init(const struct device *dev) return 0; } -static struct spi_driver_api spi_atcspi200_api = { +static const struct spi_driver_api spi_atcspi200_api = { .transceive = spi_atcspi200_transceive, #ifdef CONFIG_SPI_ASYNC .transceive_async = spi_atcspi200_transceive_async, diff --git a/drivers/spi/spi_b91.c b/drivers/spi/spi_b91.c index bdc580a521f..ed250eaa62b 100644 --- a/drivers/spi/spi_b91.c +++ b/drivers/spi/spi_b91.c @@ -452,7 +452,7 @@ static int spi_b91_release(const struct device *dev, } /* SPI driver APIs structure */ -static struct spi_driver_api spi_b91_api = { +static const struct spi_driver_api spi_b91_api = { .transceive = spi_b91_transceive, .release = spi_b91_release, #ifdef CONFIG_SPI_ASYNC diff --git a/drivers/spi/spi_bitbang.c b/drivers/spi/spi_bitbang.c index cf6a2973934..cffd25abd9a 100644 --- a/drivers/spi/spi_bitbang.c +++ b/drivers/spi/spi_bitbang.c @@ -247,7 +247,7 @@ int spi_bitbang_release(const struct device *dev, return 0; } -static struct spi_driver_api spi_bitbang_api = { +static const struct spi_driver_api spi_bitbang_api = { .transceive = spi_bitbang_transceive, .release = spi_bitbang_release, #ifdef CONFIG_SPI_ASYNC diff --git a/drivers/spi/spi_emul.c b/drivers/spi/spi_emul.c index 9c8f3a6cd70..5d60acae802 100644 --- a/drivers/spi/spi_emul.c +++ b/drivers/spi/spi_emul.c @@ -109,7 +109,7 @@ int spi_emul_register(const struct device *dev, struct spi_emul *emul) /* Device instantiation */ -static struct spi_driver_api spi_emul_api = { +static const struct spi_driver_api spi_emul_api = { .transceive = spi_emul_io, }; diff --git a/drivers/spi/spi_gd32.c b/drivers/spi/spi_gd32.c index 7f9ecaf90fb..c5c37a82f21 100644 --- a/drivers/spi/spi_gd32.c +++ b/drivers/spi/spi_gd32.c @@ -567,7 +567,7 @@ static int spi_gd32_release(const struct device *dev, return 0; } -static struct spi_driver_api spi_gd32_driver_api = { +static const struct spi_driver_api spi_gd32_driver_api = { .transceive = spi_gd32_transceive, #ifdef CONFIG_SPI_ASYNC .transceive_async = spi_gd32_transceive_async, diff --git a/drivers/spi/spi_gecko.c b/drivers/spi/spi_gecko.c index c223986d8d4..d07485793b0 100644 --- a/drivers/spi/spi_gecko.c +++ b/drivers/spi/spi_gecko.c @@ -357,7 +357,7 @@ static int spi_gecko_release(const struct device *dev, } /* Device Instantiation */ -static struct spi_driver_api spi_gecko_api = { +static const struct spi_driver_api spi_gecko_api = { .transceive = spi_gecko_transceive, #ifdef CONFIG_SPI_ASYNC .transceive_async = spi_gecko_transceive_async, diff --git a/drivers/spi/spi_litespi.c b/drivers/spi/spi_litespi.c index 974f94af5ee..dff26a6fc31 100644 --- a/drivers/spi/spi_litespi.c +++ b/drivers/spi/spi_litespi.c @@ -160,7 +160,7 @@ static int spi_litespi_release(const struct device *dev, } /* Device Instantiation */ -static struct spi_driver_api spi_litespi_api = { +static const struct spi_driver_api spi_litespi_api = { .transceive = spi_litespi_transceive, #ifdef CONFIG_SPI_ASYNC .transceive_async = spi_litespi_transceive_async, diff --git a/drivers/spi/spi_numaker.c b/drivers/spi/spi_numaker.c index 372f96271ad..eda34014ebb 100644 --- a/drivers/spi/spi_numaker.c +++ b/drivers/spi/spi_numaker.c @@ -270,8 +270,10 @@ static int spi_numaker_release(const struct device *dev, const struct spi_config return 0; } -static struct spi_driver_api spi_numaker_driver_api = {.transceive = spi_numaker_transceive, - .release = spi_numaker_release}; +static const struct spi_driver_api spi_numaker_driver_api = { + .transceive = spi_numaker_transceive, + .release = spi_numaker_release +}; static int spi_numaker_init(const struct device *dev) { diff --git a/drivers/spi/spi_oc_simple.c b/drivers/spi/spi_oc_simple.c index 3b8f9c126cf..a0f7296b2a9 100644 --- a/drivers/spi/spi_oc_simple.c +++ b/drivers/spi/spi_oc_simple.c @@ -179,7 +179,7 @@ int spi_oc_simple_release(const struct device *dev, return 0; } -static struct spi_driver_api spi_oc_simple_api = { +static const struct spi_driver_api spi_oc_simple_api = { .transceive = spi_oc_simple_transceive, .release = spi_oc_simple_release, #ifdef CONFIG_SPI_ASYNC diff --git a/drivers/spi/spi_opentitan.c b/drivers/spi/spi_opentitan.c index 3116315d929..e8d7b8dc926 100644 --- a/drivers/spi/spi_opentitan.c +++ b/drivers/spi/spi_opentitan.c @@ -301,7 +301,7 @@ static int spi_opentitan_release(const struct device *dev, /* Device Instantiation */ -static struct spi_driver_api spi_opentitan_api = { +static const struct spi_driver_api spi_opentitan_api = { .transceive = spi_opentitan_transceive, #ifdef CONFIG_SPI_ASYNC .transceive_async = spi_opentitan_transceive_async, diff --git a/drivers/spi/spi_pl022.c b/drivers/spi/spi_pl022.c index 2565ce66957..ed30dddf1e1 100644 --- a/drivers/spi/spi_pl022.c +++ b/drivers/spi/spi_pl022.c @@ -886,7 +886,7 @@ static int spi_pl022_release(const struct device *dev, return 0; } -static struct spi_driver_api spi_pl022_api = { +static const struct spi_driver_api spi_pl022_api = { .transceive = spi_pl022_transceive, #if defined(CONFIG_SPI_ASYNC) .transceive_async = spi_pl022_transceive_async, diff --git a/drivers/spi/spi_rpi_pico_pio.c b/drivers/spi/spi_rpi_pico_pio.c index db348f2d5aa..ed5179e3466 100644 --- a/drivers/spi/spi_rpi_pico_pio.c +++ b/drivers/spi/spi_rpi_pico_pio.c @@ -330,7 +330,7 @@ int spi_pico_pio_release(const struct device *dev, const struct spi_config *spi_ return 0; } -static struct spi_driver_api spi_pico_pio_api = { +static const struct spi_driver_api spi_pico_pio_api = { .transceive = spi_pico_pio_transceive, .release = spi_pico_pio_release, }; diff --git a/drivers/spi/spi_sifive.c b/drivers/spi/spi_sifive.c index c302e67ba80..1b5f178c2a6 100644 --- a/drivers/spi/spi_sifive.c +++ b/drivers/spi/spi_sifive.c @@ -272,7 +272,7 @@ static int spi_sifive_release(const struct device *dev, /* Device Instantiation */ -static struct spi_driver_api spi_sifive_api = { +static const struct spi_driver_api spi_sifive_api = { .transceive = spi_sifive_transceive, .release = spi_sifive_release, }; From 5f99c36ca17904f22b9decf1d60e2a877936a38e Mon Sep 17 00:00:00 2001 From: Erik Brockhoff Date: Wed, 3 Jan 2024 10:02:05 +0100 Subject: [PATCH 1745/3723] Bluetooth: controller: fix procedure collision handling If an instant based remote procedure 'overtakes' a local ditto the local procedure will be 'completed' by remote rejection but collision flag would not get set ensuring that a new local conflicting procedure cannot be started before the remote is completed. This can thus lead to invalid local initiation. Added unittest to cover case Fix by ensuring collision flag is set also in the above mentioned scenario. Signed-off-by: Erik Brockhoff --- .../controller/ll_sw/ull_llcp_remote.c | 6 + .../controller/ctrl_conn_update/src/main.c | 266 ++++++++++++++++++ 2 files changed, 272 insertions(+) diff --git a/subsys/bluetooth/controller/ll_sw/ull_llcp_remote.c b/subsys/bluetooth/controller/ll_sw/ull_llcp_remote.c index cb4f0995688..2263cd1b23d 100644 --- a/subsys/bluetooth/controller/ll_sw/ull_llcp_remote.c +++ b/subsys/bluetooth/controller/ll_sw/ull_llcp_remote.c @@ -621,6 +621,12 @@ static void rr_st_idle(struct ll_conn *conn, uint8_t evt, void *param) ctx_local->rx_opcode = PDU_DATA_LLCTRL_TYPE_UNUSED; } + /* + * Block/'hold back' future incompatible local procedures + * in case we run a procedure with instant + */ + rr_set_collision(conn, with_instant); + /* Run remote procedure */ rr_act_run(conn); rr_set_state(conn, RR_STATE_ACTIVE); diff --git a/tests/bluetooth/controller/ctrl_conn_update/src/main.c b/tests/bluetooth/controller/ctrl_conn_update/src/main.c index 9e0b07227f1..937f7183334 100644 --- a/tests/bluetooth/controller/ctrl_conn_update/src/main.c +++ b/tests/bluetooth/controller/ctrl_conn_update/src/main.c @@ -4194,6 +4194,272 @@ ZTEST(periph_rem, test_conn_update_periph_rem_collision) zassert_equal(llcp_ctx_buffers_free(), test_ctx_buffers_cnt(), "Free CTX buffers %d", llcp_ctx_buffers_free()); } + +/* + * (A) + * Central-initiated Connection Parameters Request procedure. + * Central requests change in LE connection parameters, peripheral’s Host accepts. + * + * and + * + * (B) + * Peripheral-initiated Connection Parameters Request procedure. + * Peripheral requests change in LE connection parameters, central’s Host accepts. + * + * NOTE: + * Peripheral-initiated Connection Parameters Request procedure is paused. + * Central-initiated Connection Parameters Request procedure is finished. + * Peripheral-initiated Connection Parameters Request procedure is resumed. + * + * +-----+ +-------+ +-----+ + * | UT | | LL_P | | LT | + * +-----+ +-------+ +-----+ + * | | | + * | LE Connection Update | | + * |-------------------------->| | (B) + * | | LL_CONNECTION_PARAM_REQ | + * | |<--------------------------| (A) + * | | LL_CONNECTION_PARAM_REQ | + * | |-------------------------->| (B) + * | | | + * | | | + * | | | + * | LE Remote Connection | | + * | Parameter Request | | + * |<--------------------------| | (A) + * | LE Remote Connection | | + * | Parameter Request | | + * | Reply | | + * |-------------------------->| | (A) + * | | LL_REJECT_EXT_IND | + * | |<--------------------------| (B) + * | | | + * | LE Connection Update | | + * | Complete (collision) | | + * |<--------------------------| | (B) + * | | LL_CONNECTION_PARAM_RSP | + * | |-------------------------->| (A) + * | | | + * | LE Connection Update | | + * |-------------------------->| | (B) + * | | | + * | <------------------------> | + * | < LOCAL PROCEDURE PAUSED > | + * | <------------------------> | + * | | | + * | | LL_CONNECTION_UPDATE_IND | + * | |<--------------------------| (A) + * | | | + * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + * | | | + * | LE Connection Update | | + * | Complete | | + * |<--------------------------| | (A) + * | | | + * | <-------------------------> | + * | < LOCAL PROCEDURE RESUMED > | + * | <-------------------------> | + * | | | + * | | LL_CONNECTION_PARAM_REQ | + * | |-------------------------->| (B) + * | | | + * | | LL_CONNECTION_UPDATE_IND | + * | |<--------------------------| (B) + * | | | + * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + * | | | + * | LE Connection Update | | + * | Complete | | + * |<--------------------------| | (B) + * | | | + */ +ZTEST(periph_rem, test_conn_update_periph_rem_late_collision) +{ + uint8_t err; + struct node_tx *tx; + struct node_rx_pdu *ntf; + uint16_t instant; + struct pdu_data_llctrl_reject_ext_ind reject_ext_ind = { + .reject_opcode = PDU_DATA_LLCTRL_TYPE_CONN_PARAM_REQ, + .error_code = BT_HCI_ERR_LL_PROC_COLLISION + }; + struct node_rx_pu cu1 = { .status = BT_HCI_ERR_LL_PROC_COLLISION }; + struct node_rx_pu cu = { .status = BT_HCI_ERR_SUCCESS }; + + /* Role */ + test_set_role(&conn, BT_HCI_ROLE_PERIPHERAL); + + /* Connect */ + ull_cp_state_set(&conn, ULL_CP_CONNECTED); + + /*******************/ + + /* (B) Initiate a Connection Parameter Request Procedure */ + err = ull_cp_conn_update(&conn, req_B->interval_min, req_B->interval_max, req_B->latency, + req_B->timeout, NULL); + zassert_equal(err, BT_HCI_ERR_SUCCESS); + + /* Prepare */ + event_prepare(&conn); + + /*******************/ + + /* (A) Rx */ + lt_tx(LL_CONNECTION_PARAM_REQ, &conn, &conn_param_req); + + /* Done */ + event_done(&conn); + + /*******************/ + + /* Prepare */ + event_prepare(&conn); + + /* (B) Tx Queue should have one LL Control PDU */ + req_B->reference_conn_event_count = event_counter(&conn) - 1; + lt_rx(LL_CONNECTION_PARAM_REQ, &conn, &tx, req_B); + lt_rx_q_is_empty(&conn); + + /* Done */ + event_done(&conn); + + /*******************/ + /* (A) There should be one host notification */ + ut_rx_pdu(LL_CONNECTION_PARAM_REQ, &ntf, &conn_param_req); + ut_rx_q_is_empty(); + + /* Release Ntf */ + release_ntf(ntf); + + /*******************/ + /* Rx */ + lt_tx(LL_REJECT_EXT_IND, &conn, &reject_ext_ind); + + /* (A) */ + ull_cp_conn_param_req_reply(&conn); + + /*******************/ + + /* Prepare */ + event_prepare(&conn); + conn_param_rsp.reference_conn_event_count = conn_param_req.reference_conn_event_count; + + /* (A) Tx Queue should have one LL Control PDU */ + lt_rx(LL_CONNECTION_PARAM_RSP, &conn, &tx, &conn_param_rsp); + lt_rx_q_is_empty(&conn); + + /* Done */ + event_done(&conn); + + /* (A) There should be one host notification */ + ut_rx_node(NODE_CONN_UPDATE, &ntf, &cu1); + ut_rx_q_is_empty(); + + /* Release Ntf */ + release_ntf(ntf); + + /* (B) Initiate a Connection Parameter Request Procedure */ + err = ull_cp_conn_update(&conn, req_B->interval_min, req_B->interval_max, req_B->latency, + req_B->timeout, NULL); + + /* Prepare */ + event_prepare(&conn); + /* Done */ + event_done(&conn); + + + /* (A) Rx */ + conn_update_ind.instant = event_counter(&conn) + 6U; + instant = conn_update_ind.instant; + lt_tx(LL_CONNECTION_UPDATE_IND, &conn, &conn_update_ind); + /* Prepare */ + event_prepare(&conn); + + /* Done */ + event_done(&conn); + + /* Release Tx */ + ull_cp_release_tx(&conn, tx); + + /* */ + while (!is_instant_reached(&conn, instant)) { + /* Prepare */ + event_prepare(&conn); + + /* (A) Tx Queue should NOT have a LL Control PDU */ + lt_rx_q_is_empty(&conn); + + /* Done */ + event_done(&conn); + + /* (A) There should NOT be a host notification */ + ut_rx_q_is_empty(); + } + + /* Prepare */ + event_prepare(&conn); + + /* (B) Tx Queue should have one LL Control PDU */ + req_B->reference_conn_event_count = event_counter(&conn) - 1; + lt_rx(LL_CONNECTION_PARAM_REQ, &conn, &tx, req_B); + lt_rx_q_is_empty(&conn); + + /* Done */ + event_done(&conn); + + /* (A) There should be one host notification */ + ut_rx_node(NODE_CONN_UPDATE, &ntf, &cu); + ut_rx_q_is_empty(); + + /* Release Ntf */ + release_ntf(ntf); + + /* Prepare */ + event_prepare(&conn); + + /* (B) Tx Queue should NOT have a LL Control PDU */ + lt_rx_q_is_empty(&conn); + + /* (B) Rx */ + cu_ind_B->instant = instant = event_counter(&conn) + 6; + lt_tx(LL_CONNECTION_UPDATE_IND, &conn, cu_ind_B); + + /* Done */ + event_done(&conn); + + /* */ + while (!is_instant_reached(&conn, instant)) { + /* Prepare */ + event_prepare(&conn); + + /* (B) Tx Queue should NOT have a LL Control PDU */ + lt_rx_q_is_empty(&conn); + + /* Done */ + event_done(&conn); + + /* (B) There should NOT be a host notification */ + ut_rx_q_is_empty(); + } + + /* Prepare */ + event_prepare(&conn); + + /* (B) Tx Queue should NOT have a LL Control PDU */ + lt_rx_q_is_empty(&conn); + + /* Done */ + event_done(&conn); + + /* (B) There should be one host notification */ + ut_rx_node(NODE_CONN_UPDATE, &ntf, &cu); + ut_rx_q_is_empty(); + + /* Release Ntf */ + release_ntf(ntf); + zassert_equal(llcp_ctx_buffers_free(), test_ctx_buffers_cnt(), + "Free CTX buffers %d", llcp_ctx_buffers_free()); +} #else /* CONFIG_BT_CTLR_CONN_PARAM_REQ */ /* From 71c549e908b669639c7c4452d67f72e1a6cb0c04 Mon Sep 17 00:00:00 2001 From: Alberto Escolar Piedras Date: Wed, 3 Jan 2024 10:09:55 +0100 Subject: [PATCH 1746/3723] CI bsim workflow: Update changed-files action version Dependabot has foud in a fork that we are using a too old GitHub action version, which contains this vulnerability: https://www.cve.org/CVERecord?id=CVE-2023-51664 https://github.com/tj-actions/changed-files/security/advisories/GHSA-mcph-m25j-8j63 We do not use the output listing all changed files, so we should not be exposed, but nonetheless, let's update it. Signed-off-by: Alberto Escolar Piedras --- .github/workflows/bsim-tests.yaml | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/.github/workflows/bsim-tests.yaml b/.github/workflows/bsim-tests.yaml index e4f76dec506..75a65577975 100644 --- a/.github/workflows/bsim-tests.yaml +++ b/.github/workflows/bsim-tests.yaml @@ -80,7 +80,7 @@ jobs: west forall -c 'git reset --hard HEAD' - name: Check common triggering files - uses: tj-actions/changed-files@v35 + uses: tj-actions/changed-files@v41 id: check-common-files with: files: | @@ -95,7 +95,7 @@ jobs: tests/bsim/* - name: Check if Bluethooth files changed - uses: tj-actions/changed-files@v35 + uses: tj-actions/changed-files@v41 id: check-bluetooth-files with: files: | @@ -104,7 +104,7 @@ jobs: subsys/bluetooth/** - name: Check if Networking files changed - uses: tj-actions/changed-files@v35 + uses: tj-actions/changed-files@v41 id: check-networking-files with: files: | From 85dfe3df1422fd104a38bb1241235d92bc079d31 Mon Sep 17 00:00:00 2001 From: Juha Ylinen Date: Wed, 3 Jan 2024 13:08:57 +0200 Subject: [PATCH 1747/3723] net: lwm2m: Delay triggering registration update Add short delay before triggering registration update. This allows postponing the update from application side if needed. Signed-off-by: Juha Ylinen --- subsys/net/lib/lwm2m/lwm2m_rd_client.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/subsys/net/lib/lwm2m/lwm2m_rd_client.c b/subsys/net/lib/lwm2m/lwm2m_rd_client.c index 6b3fbcccc68..95b576cb1c6 100644 --- a/subsys/net/lib/lwm2m/lwm2m_rd_client.c +++ b/subsys/net/lib/lwm2m/lwm2m_rd_client.c @@ -1132,7 +1132,7 @@ static void sm_registration_done(void) if (sm_is_registered() && (client.trigger_update || now >= next_update())) { - set_sm_state(ENGINE_UPDATE_REGISTRATION); + set_sm_state_delayed(ENGINE_UPDATE_REGISTRATION, DELAY_FOR_ACK); } else if (IS_ENABLED(CONFIG_LWM2M_QUEUE_MODE_ENABLED) && (client.engine_state != ENGINE_REGISTRATION_DONE_RX_OFF) && (now >= next_rx_off())) { From 7c53fa86ffa019a8497dd9a2b3943d5976769f07 Mon Sep 17 00:00:00 2001 From: Juha Ylinen Date: Wed, 3 Jan 2024 16:09:28 +0200 Subject: [PATCH 1748/3723] net: lwm2m: Fix deadlock when calling lwm2m_engine_pause() lwm2m_engine_pause() caused deadlock if it was called within engine thread. Remove while loop from lwm2m_engine_resume(). Signed-off-by: Juha Ylinen --- subsys/net/lib/lwm2m/lwm2m_engine.c | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/subsys/net/lib/lwm2m/lwm2m_engine.c b/subsys/net/lib/lwm2m/lwm2m_engine.c index 639f65ea0fa..e08bb4ca17e 100644 --- a/subsys/net/lib/lwm2m/lwm2m_engine.c +++ b/subsys/net/lib/lwm2m/lwm2m_engine.c @@ -1259,6 +1259,12 @@ int lwm2m_engine_pause(void) suspend_engine_thread = true; lwm2m_engine_wake_up(); + /* Check if pause requested within a engine thread, a callback for example. */ + if (engine_thread_id == k_current_get()) { + LOG_DBG("Pause requested"); + return 0; + } + while (active_engine_thread) { k_msleep(10); } @@ -1275,10 +1281,7 @@ int lwm2m_engine_resume(void) k_thread_resume(engine_thread_id); lwm2m_engine_wake_up(); - while (!active_engine_thread) { - k_msleep(10); - } - LOG_INF("LWM2M engine thread resume"); + return 0; } From 87c8b897b3a1481c900b21f63a82c8c510ed8058 Mon Sep 17 00:00:00 2001 From: Emil Gydesen Date: Wed, 3 Jan 2024 13:31:58 +0100 Subject: [PATCH 1749/3723] include: util: Add mem_xor functions Add functions to do XOR on arrays of memory, with one that takes arbitrary sizes and one for 32 bits and 128 bits as those are common sizes for this functionality. Signed-off-by: Emil Gydesen --- include/zephyr/sys/util.h | 39 ++++++++++ subsys/bluetooth/audio/csip_crypto.c | 13 +--- .../controller/ll_sw/nordic/lll/lll_adv_iso.c | 1 + .../ll_sw/nordic/lll/lll_sync_iso.c | 1 + .../bluetooth/controller/ll_sw/ull_conn_iso.c | 1 + subsys/bluetooth/controller/util/mem.c | 18 ----- subsys/bluetooth/controller/util/mem.h | 2 - subsys/bluetooth/host/smp.c | 13 +--- tests/unit/util/main.c | 71 +++++++++++++++++++ 9 files changed, 117 insertions(+), 42 deletions(-) diff --git a/include/zephyr/sys/util.h b/include/zephyr/sys/util.h index 45ae2008999..97bfd3aa714 100644 --- a/include/zephyr/sys/util.h +++ b/include/zephyr/sys/util.h @@ -657,6 +657,45 @@ char *utf8_lcpy(char *dst, const char *src, size_t n); (((buflen) != 0) && \ ((UINTPTR_MAX - (uintptr_t)(addr)) <= ((uintptr_t)((buflen) - 1)))) +/** + * @brief XOR n bytes + * + * @param dst Destination of where to store result. Shall be @p len bytes. + * @param src1 First source. Shall be @p len bytes. + * @param src2 Second source. Shall be @p len bytes. + * @param len Number of bytes to XOR. + */ +static inline void mem_xor_n(uint8_t *dst, const uint8_t *src1, const uint8_t *src2, size_t len) +{ + while (len--) { + *dst++ = *src1++ ^ *src2++; + } +} + +/** + * @brief XOR 32 bits + * + * @param dst Destination of where to store result. Shall be 32 bits. + * @param src1 First source. Shall be 32 bits. + * @param src2 Second source. Shall be 32 bits. + */ +static inline void mem_xor_32(uint8_t dst[4], const uint8_t src1[4], const uint8_t src2[4]) +{ + mem_xor_n(dst, src1, src2, 4U); +} + +/** + * @brief XOR 128 bits + * + * @param dst Destination of where to store result. Shall be 128 bits. + * @param src1 First source. Shall be 128 bits. + * @param src2 Second source. Shall be 128 bits. + */ +static inline void mem_xor_128(uint8_t dst[16], const uint8_t src1[16], const uint8_t src2[16]) +{ + mem_xor_n(dst, src1, src2, 16); +} + #ifdef __cplusplus } #endif diff --git a/subsys/bluetooth/audio/csip_crypto.c b/subsys/bluetooth/audio/csip_crypto.c index d51855f02a5..d880ca36ce1 100644 --- a/subsys/bluetooth/audio/csip_crypto.c +++ b/subsys/bluetooth/audio/csip_crypto.c @@ -17,6 +17,7 @@ #include #include #include +#include #include "common/bt_str.h" @@ -51,16 +52,6 @@ static int aes_cmac(const uint8_t key[BT_CSIP_CRYPTO_KEY_SIZE], return 0; } -static void xor_128(const uint8_t a[16], const uint8_t b[16], uint8_t out[16]) -{ - size_t len = 16; - /* TODO: Identical to the xor_128 from smp.c: Move to util */ - - while (len--) { - *out++ = *a++ ^ *b++; - } -} - int bt_csip_sih(const uint8_t sirk[BT_CSIP_SET_SIRK_SIZE], uint8_t r[BT_CSIP_CRYPTO_PRAND_SIZE], uint8_t out[BT_CSIP_CRYPTO_HASH_SIZE]) { @@ -229,7 +220,7 @@ int bt_csip_sef(const uint8_t k[BT_CSIP_CRYPTO_KEY_SIZE], sys_mem_swap(k1_out, sizeof(k1_out)); } - xor_128(k1_out, sirk, out_sirk); + mem_xor_128(out_sirk, k1_out, sirk); LOG_DBG("out %s", bt_hex(out_sirk, BT_CSIP_SET_SIRK_SIZE)); return 0; diff --git a/subsys/bluetooth/controller/ll_sw/nordic/lll/lll_adv_iso.c b/subsys/bluetooth/controller/ll_sw/nordic/lll/lll_adv_iso.c index 20e3fe528e1..f5e566a7bcc 100644 --- a/subsys/bluetooth/controller/ll_sw/nordic/lll/lll_adv_iso.c +++ b/subsys/bluetooth/controller/ll_sw/nordic/lll/lll_adv_iso.c @@ -9,6 +9,7 @@ #include #include +#include #include "hal/cpu.h" #include "hal/ccm.h" diff --git a/subsys/bluetooth/controller/ll_sw/nordic/lll/lll_sync_iso.c b/subsys/bluetooth/controller/ll_sw/nordic/lll/lll_sync_iso.c index 12e9fd342b9..d4611425f2c 100644 --- a/subsys/bluetooth/controller/ll_sw/nordic/lll/lll_sync_iso.c +++ b/subsys/bluetooth/controller/ll_sw/nordic/lll/lll_sync_iso.c @@ -9,6 +9,7 @@ #include #include +#include #include "hal/cpu.h" #include "hal/ccm.h" diff --git a/subsys/bluetooth/controller/ll_sw/ull_conn_iso.c b/subsys/bluetooth/controller/ll_sw/ull_conn_iso.c index 2ec6a73b4a4..467460d2f30 100644 --- a/subsys/bluetooth/controller/ll_sw/ull_conn_iso.c +++ b/subsys/bluetooth/controller/ll_sw/ull_conn_iso.c @@ -6,6 +6,7 @@ #include #include +#include #include #include "util/util.h" diff --git a/subsys/bluetooth/controller/util/mem.c b/subsys/bluetooth/controller/util/mem.c index 1bd67ee7eb1..e0450ac815b 100644 --- a/subsys/bluetooth/controller/util/mem.c +++ b/subsys/bluetooth/controller/util/mem.c @@ -134,24 +134,6 @@ uint8_t mem_nz(uint8_t *src, uint16_t len) return 0; } -/** - * @brief XOR bytes - */ -inline void mem_xor_n(uint8_t *dst, uint8_t *src1, uint8_t *src2, uint16_t len) -{ - while (len--) { - *dst++ = *src1++ ^ *src2++; - } -} - -/** - * @brief XOR 32-bits - */ -void mem_xor_32(uint8_t *dst, uint8_t *src1, uint8_t *src2) -{ - mem_xor_n(dst, src1, src2, 4U); -} - /** * @brief Unit test */ diff --git a/subsys/bluetooth/controller/util/mem.h b/subsys/bluetooth/controller/util/mem.h index 8a8bdb3a62d..4a345ab253f 100644 --- a/subsys/bluetooth/controller/util/mem.h +++ b/subsys/bluetooth/controller/util/mem.h @@ -63,7 +63,5 @@ uint16_t mem_index_get(const void *mem, const void *mem_pool, uint16_t mem_size) void mem_rcopy(uint8_t *dst, uint8_t const *src, uint16_t len); uint8_t mem_nz(uint8_t *src, uint16_t len); -void mem_xor_n(uint8_t *dst, uint8_t *src1, uint8_t *src2, uint16_t len); -void mem_xor_32(uint8_t *dst, uint8_t *src1, uint8_t *src2); uint32_t mem_ut(void); diff --git a/subsys/bluetooth/host/smp.c b/subsys/bluetooth/host/smp.c index 2c110dc43a3..95809d23768 100644 --- a/subsys/bluetooth/host/smp.c +++ b/subsys/bluetooth/host/smp.c @@ -1829,15 +1829,6 @@ static uint8_t smp_send_pairing_random(struct bt_smp *smp) } #if !defined(CONFIG_BT_SMP_SC_PAIR_ONLY) -static void xor_128(const uint8_t p[16], const uint8_t q[16], uint8_t r[16]) -{ - size_t len = 16; - - while (len--) { - *r++ = *p++ ^ *q++; - } -} - static int smp_c1(const uint8_t k[16], const uint8_t r[16], const uint8_t preq[7], const uint8_t pres[7], const bt_addr_le_t *ia, const bt_addr_le_t *ra, @@ -1864,7 +1855,7 @@ static int smp_c1(const uint8_t k[16], const uint8_t r[16], /* c1 = e(k, e(k, r XOR p1) XOR p2) */ /* Using enc_data as temporary output buffer */ - xor_128(r, p1, enc_data); + mem_xor_128(enc_data, r, p1); err = bt_encrypt_le(k, enc_data, enc_data); if (err) { @@ -1878,7 +1869,7 @@ static int smp_c1(const uint8_t k[16], const uint8_t r[16], LOG_DBG("p2 %s", bt_hex(p2, 16)); - xor_128(enc_data, p2, enc_data); + mem_xor_128(enc_data, p2, enc_data); return bt_encrypt_le(k, enc_data, enc_data); } diff --git a/tests/unit/util/main.c b/tests/unit/util/main.c index e10455e263a..fc8af19d34a 100644 --- a/tests/unit/util/main.c +++ b/tests/unit/util/main.c @@ -646,4 +646,75 @@ ZTEST(util, test_IF_DISABLED) #undef test_IF_DISABLED_FLAG_B } +ZTEST(util, test_mem_xor_n) +{ + const size_t max_len = 128; + uint8_t expected_result[max_len]; + uint8_t src1[max_len]; + uint8_t src2[max_len]; + uint8_t dst[max_len]; + + memset(expected_result, 0, sizeof(expected_result)); + memset(src1, 0, sizeof(src1)); + memset(src2, 0, sizeof(src2)); + memset(dst, 0, sizeof(dst)); + + for (size_t i = 0U; i < max_len; i++) { + const size_t len = i; + + for (size_t j = 0U; j < len; j++) { + src1[j] = 0x33; + src2[j] = 0x0F; + expected_result[j] = 0x3C; + } + + mem_xor_n(dst, src1, src2, len); + zassert_mem_equal(expected_result, dst, len); + } +} + +ZTEST(util, test_mem_xor_32) +{ + uint8_t expected_result[4]; + uint8_t src1[4]; + uint8_t src2[4]; + uint8_t dst[4]; + + memset(expected_result, 0, sizeof(expected_result)); + memset(src1, 0, sizeof(src1)); + memset(src2, 0, sizeof(src2)); + memset(dst, 0, sizeof(dst)); + + for (size_t i = 0U; i < 4; i++) { + src1[i] = 0x43; + src2[i] = 0x0F; + expected_result[i] = 0x4C; + } + + mem_xor_32(dst, src1, src2); + zassert_mem_equal(expected_result, dst, 4); +} + +ZTEST(util, test_mem_xor_128) +{ + uint8_t expected_result[16]; + uint8_t src1[16]; + uint8_t src2[16]; + uint8_t dst[16]; + + memset(expected_result, 0, sizeof(expected_result)); + memset(src1, 0, sizeof(src1)); + memset(src2, 0, sizeof(src2)); + memset(dst, 0, sizeof(dst)); + + for (size_t i = 0U; i < 16; i++) { + src1[i] = 0x53; + src2[i] = 0x0F; + expected_result[i] = 0x5C; + } + + mem_xor_128(dst, src1, src2); + zassert_mem_equal(expected_result, dst, 16); +} + ZTEST_SUITE(util, NULL, NULL, NULL, NULL, NULL); From 7ef10d0f718dd65e38f80f48f1c3e199acef02e0 Mon Sep 17 00:00:00 2001 From: Bartosz Bilas Date: Wed, 3 Jan 2024 18:26:49 +0100 Subject: [PATCH 1750/3723] drivers: regulator: add regulator-init-microamp property It allows setting regulator current value during driver initialization automatically. Signed-off-by: Bartosz Bilas --- drivers/regulator/regulator_common.c | 7 +++++++ dts/bindings/regulator/regulator.yaml | 4 ++++ include/zephyr/drivers/regulator.h | 4 ++++ 3 files changed, 15 insertions(+) diff --git a/drivers/regulator/regulator_common.c b/drivers/regulator/regulator_common.c index 14866a3738f..f4f583d6f88 100644 --- a/drivers/regulator/regulator_common.c +++ b/drivers/regulator/regulator_common.c @@ -49,6 +49,13 @@ int regulator_common_init(const struct device *dev, bool is_enabled) } } + if (config->init_ua > INT32_MIN) { + ret = regulator_set_current_limit(dev, config->init_ua, config->init_ua); + if (ret < 0) { + return ret; + } + } + /* If we have valid range values, we try to match them before enabling */ if ((config->min_uv > INT32_MIN) || (config->max_uv < INT32_MAX)) { diff --git a/dts/bindings/regulator/regulator.yaml b/dts/bindings/regulator/regulator.yaml index 167355d9224..635bfa49596 100644 --- a/dts/bindings/regulator/regulator.yaml +++ b/dts/bindings/regulator/regulator.yaml @@ -31,6 +31,10 @@ properties: type: int description: Offset applied to voltages to compensate for voltage drops + regulator-init-microamp: + type: int + description: Current set during initialisation + regulator-min-microamp: type: int description: smallest current consumers may set diff --git a/include/zephyr/drivers/regulator.h b/include/zephyr/drivers/regulator.h index bad9de28239..7cf905f774e 100644 --- a/include/zephyr/drivers/regulator.h +++ b/include/zephyr/drivers/regulator.h @@ -140,6 +140,8 @@ struct regulator_common_config { int32_t min_ua; /** Maximum allowed current, in microamps. */ int32_t max_ua; + /** Initial current, in microamps. */ + int32_t init_ua; /** Startup delay, in microseconds. */ uint32_t startup_delay_us; /** Off to on delay, in microseconds. */ @@ -171,6 +173,8 @@ struct regulator_common_config { INT32_MIN), \ .max_ua = DT_PROP_OR(node_id, regulator_max_microamp, \ INT32_MAX), \ + .init_ua = DT_PROP_OR(node_id, regulator_init_microamp, \ + INT32_MIN), \ .startup_delay_us = DT_PROP_OR(node_id, startup_delay_us, 0), \ .off_on_delay_us = DT_PROP_OR(node_id, off_on_delay_us, 0), \ .allowed_modes = (const regulator_mode_t []) \ From 37305fa06b9423b906f68b0e1725420d7fc5c5f5 Mon Sep 17 00:00:00 2001 From: Fang Huang Date: Fri, 8 Dec 2023 11:30:42 +0800 Subject: [PATCH 1751/3723] logging: mipi_syst: Add CONFIG_LOG_MIPI_SYST_DISABLE_TIMESTAMP This adds user configurable CONFIG_LOG_MIPI_SYST_DISABLE_TIMESTAMP Kconfig option to use it for macro MIPI_SYST_PCFG_ENABLE_TIMESTAMP. Moving macro definition of MIPI_SYST_PCFG_ENABLE_TIMESTAMP from mipi-sys-t library to platform.h which defaulted to undef. CONFIG_LOG_MIPI_SYST_DISABLE_TIMESTAMP gives flexibility to users when needn't use mipi-sys-t protocol timestamp. Signed-off-by: Fang Huang --- subsys/logging/Kconfig.formatting | 5 +++++ subsys/logging/mipi_syst/platform.h | 6 +++++- 2 files changed, 10 insertions(+), 1 deletion(-) diff --git a/subsys/logging/Kconfig.formatting b/subsys/logging/Kconfig.formatting index 271ca066d2c..44b9244e296 100644 --- a/subsys/logging/Kconfig.formatting +++ b/subsys/logging/Kconfig.formatting @@ -38,6 +38,11 @@ config LOG_MIPI_SYST_USE_CATALOG help Use MIPI Sys-T Catalog for logging instead of plain text. +config LOG_MIPI_SYST_DISABLE_TIMESTAMP + bool "Disable MIPI Sys-T protocol timestamp" + help + Remove the timestamp from the MIPI Sys-T protocol. + config LOG_MIPI_SYST_CATALOG_ARGS_BUFFER_SIZE int "Size of temporary arguments buffer when using Sys-T Catalog" depends on LOG_MIPI_SYST_USE_CATALOG diff --git a/subsys/logging/mipi_syst/platform.h b/subsys/logging/mipi_syst/platform.h index 3c456817523..27b19fa113f 100644 --- a/subsys/logging/mipi_syst/platform.h +++ b/subsys/logging/mipi_syst/platform.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2019 Intel Corporation + * Copyright (c) 2019 - 2023 Intel Corporation * * SPDX-License-Identifier: Apache-2.0 */ @@ -13,6 +13,10 @@ extern "C" { #endif +#if defined(CONFIG_LOG_MIPI_SYST_DISABLE_TIMESTAMP) +#undef MIPI_SYST_PCFG_ENABLE_TIMESTAMP +#endif + #define MIPI_SYST_PCFG_PRINTF_ARGBUF_SIZE CONFIG_LOG_MIPI_SYST_ARGS_BUFFER_SIZE #if defined(CONFIG_MIPI_SYST_STP) From 8aaf40ab7fee40ccb55d84a6c342b120dc97bb16 Mon Sep 17 00:00:00 2001 From: Yves Vandervennet Date: Thu, 4 Jan 2024 11:45:17 -0600 Subject: [PATCH 1752/3723] linkserver: nxp: enable linkserver to be the default runner This commit sets linkserver as the runner, if none was set in the board's board.cmake file. This change will enable NXP to make linkserver the default runner for the NXP boards. Signed-off-by: Yves Vandervennet --- boards/common/linkserver.board.cmake | 2 ++ 1 file changed, 2 insertions(+) diff --git a/boards/common/linkserver.board.cmake b/boards/common/linkserver.board.cmake index 743eef57399..74de78449c6 100644 --- a/boards/common/linkserver.board.cmake +++ b/boards/common/linkserver.board.cmake @@ -1,4 +1,6 @@ # Copyright 2023 NXP # SPDX-License-Identifier: Apache-2.0 +board_set_flasher_ifnset(linkserver) +board_set_debugger_ifnset(linkserver) board_finalize_runner_args(linkserver "--dt-flash=y") From 7127c2a7333fb6fc6ea2416e73dba86318205f96 Mon Sep 17 00:00:00 2001 From: Jonathan Rico Date: Thu, 4 Jan 2024 12:15:17 +0100 Subject: [PATCH 1753/3723] tests: Bluetooth: Add debug options to host/l2cap/stress Enable quality-of-life kconfig options. Add destroy callbacks to track lifetime of app buffers. Signed-off-by: Jonathan Rico --- .../bsim/bluetooth/host/l2cap/stress/prj.conf | 7 +++++ .../bluetooth/host/l2cap/stress/src/main.c | 27 ++++++++++++++++--- 2 files changed, 31 insertions(+), 3 deletions(-) diff --git a/tests/bsim/bluetooth/host/l2cap/stress/prj.conf b/tests/bsim/bluetooth/host/l2cap/stress/prj.conf index 3560a1b1f4b..a28127716fc 100644 --- a/tests/bsim/bluetooth/host/l2cap/stress/prj.conf +++ b/tests/bsim/bluetooth/host/l2cap/stress/prj.conf @@ -46,3 +46,10 @@ CONFIG_BT_MAX_CONN=10 CONFIG_LOG=y CONFIG_ASSERT=y CONFIG_NET_BUF_POOL_USAGE=y + +CONFIG_BT_L2CAP_LOG_LEVEL_DBG=y +# CONFIG_BT_CONN_LOG_LEVEL_DBG=y +CONFIG_LOG_THREAD_ID_PREFIX=y +CONFIG_THREAD_NAME=y + +CONFIG_ARCH_POSIX_TRAP_ON_FATAL=y diff --git a/tests/bsim/bluetooth/host/l2cap/stress/src/main.c b/tests/bsim/bluetooth/host/l2cap/stress/src/main.c index 08e988fcd36..1eed057519b 100644 --- a/tests/bsim/bluetooth/host/l2cap/stress/src/main.c +++ b/tests/bsim/bluetooth/host/l2cap/stress/src/main.c @@ -23,20 +23,41 @@ CREATE_FLAG(flag_l2cap_connected); #define NUM_SEGMENTS 10 #define RESCHEDULE_DELAY K_MSEC(100) +static void sdu_destroy(struct net_buf *buf) +{ + LOG_DBG("%p", buf); + + net_buf_destroy(buf); +} + +static void segment_destroy(struct net_buf *buf) +{ + LOG_DBG("%p", buf); + + net_buf_destroy(buf); +} + +static void rx_destroy(struct net_buf *buf) +{ + LOG_DBG("%p", buf); + + net_buf_destroy(buf); +} + /* Only one SDU per link will be transmitted at a time */ NET_BUF_POOL_DEFINE(sdu_tx_pool, CONFIG_BT_MAX_CONN, BT_L2CAP_SDU_BUF_SIZE(SDU_LEN), - CONFIG_BT_CONN_TX_USER_DATA_SIZE, NULL); + CONFIG_BT_CONN_TX_USER_DATA_SIZE, sdu_destroy); NET_BUF_POOL_DEFINE(segment_pool, /* MTU + 4 l2cap hdr + 4 ACL hdr */ NUM_SEGMENTS, BT_L2CAP_BUF_SIZE(CONFIG_BT_L2CAP_TX_MTU), - CONFIG_BT_CONN_TX_USER_DATA_SIZE, NULL); + CONFIG_BT_CONN_TX_USER_DATA_SIZE, segment_destroy); /* Only one SDU per link will be received at a time */ NET_BUF_POOL_DEFINE(sdu_rx_pool, CONFIG_BT_MAX_CONN, BT_L2CAP_SDU_BUF_SIZE(SDU_LEN), - 8, NULL); + 8, rx_destroy); static uint8_t tx_data[SDU_LEN]; static uint16_t rx_cnt; From 61f834ee671300639a54b53b67e547683d12f4d7 Mon Sep 17 00:00:00 2001 From: Jonathan Rico Date: Wed, 3 Jan 2024 09:37:05 +0100 Subject: [PATCH 1754/3723] Bluetooth: L2CAP: don't use `bt_l2cap_send` internally Prevents confusion, as the similarly-named `l2cap_send()` also unrefs the buffer if it fails to send. Signed-off-by: Jonathan Rico --- subsys/bluetooth/host/l2cap.c | 36 +++++++++++------------------------ 1 file changed, 11 insertions(+), 25 deletions(-) diff --git a/subsys/bluetooth/host/l2cap.c b/subsys/bluetooth/host/l2cap.c index ba632c1875a..66c7038f3ce 100644 --- a/subsys/bluetooth/host/l2cap.c +++ b/subsys/bluetooth/host/l2cap.c @@ -475,20 +475,22 @@ static struct net_buf *l2cap_create_le_sig_pdu(uint8_t code, uint8_t ident, * Any other cleanup in failure to send should be handled by the disconnected * handler. */ -static inline void l2cap_send(struct bt_conn *conn, uint16_t cid, - struct net_buf *buf) +static inline int l2cap_send(struct bt_conn *conn, uint16_t cid, struct net_buf *buf) { - if (bt_l2cap_send(conn, cid, buf)) { + int err = bt_l2cap_send(conn, cid, buf); + + if (err) { net_buf_unref(buf); } + + return err; } #if defined(CONFIG_BT_L2CAP_DYNAMIC_CHANNEL) static void l2cap_chan_send_req(struct bt_l2cap_chan *chan, struct net_buf *buf, k_timeout_t timeout) { - if (bt_l2cap_send(chan->conn, BT_L2CAP_CID_LE_SIG, buf)) { - net_buf_unref(buf); + if (l2cap_send(chan->conn, BT_L2CAP_CID_LE_SIG, buf)) { return; } @@ -1204,8 +1206,7 @@ static void le_conn_req(struct bt_l2cap *l2cap, uint8_t ident, rsp: rsp->result = sys_cpu_to_le16(result); - if (bt_l2cap_send(conn, BT_L2CAP_CID_LE_SIG, buf)) { - net_buf_unref(buf); + if (l2cap_send(conn, BT_L2CAP_CID_LE_SIG, buf)) { return; } @@ -1324,8 +1325,7 @@ static void le_ecred_conn_req(struct bt_l2cap *l2cap, uint8_t ident, net_buf_add_mem(buf, dcid, sizeof(scid) * req_cid_count); - if (bt_l2cap_send(conn, BT_L2CAP_CID_LE_SIG, buf)) { - net_buf_unref(buf); + if (l2cap_send(conn, BT_L2CAP_CID_LE_SIG, buf)) { goto callback; } @@ -2344,7 +2344,6 @@ static void l2cap_chan_send_credits(struct bt_l2cap_le_chan *chan, #if defined(CONFIG_BT_L2CAP_SEG_RECV) static int l2cap_chan_send_credits_pdu(struct bt_conn *conn, uint16_t cid, uint16_t credits) { - int err; struct net_buf *buf; struct bt_l2cap_le_credits *ev; @@ -2359,13 +2358,7 @@ static int l2cap_chan_send_credits_pdu(struct bt_conn *conn, uint16_t cid, uint1 .credits = sys_cpu_to_le16(credits), }; - err = bt_l2cap_send(conn, BT_L2CAP_CID_LE_SIG, buf); - if (err) { - net_buf_unref(buf); - return err; - } - - return 0; + return l2cap_send(conn, BT_L2CAP_CID_LE_SIG, buf); } /** @@ -2782,7 +2775,6 @@ int bt_l2cap_update_conn_param(struct bt_conn *conn, { struct bt_l2cap_conn_param_req *req; struct net_buf *buf; - int err; buf = l2cap_create_le_sig_pdu(BT_L2CAP_CONN_PARAM_REQ, get_ident(), sizeof(*req)); @@ -2796,13 +2788,7 @@ int bt_l2cap_update_conn_param(struct bt_conn *conn, req->latency = sys_cpu_to_le16(param->latency); req->timeout = sys_cpu_to_le16(param->timeout); - err = bt_l2cap_send(conn, BT_L2CAP_CID_LE_SIG, buf); - if (err) { - net_buf_unref(buf); - return err; - } - - return 0; + return l2cap_send(conn, BT_L2CAP_CID_LE_SIG, buf); } static void l2cap_connected(struct bt_l2cap_chan *chan) From 79e86472c3b6810b689a12f624c6d5ecdfff996b Mon Sep 17 00:00:00 2001 From: Jonathan Rico Date: Thu, 4 Jan 2024 09:55:47 +0100 Subject: [PATCH 1755/3723] Bluetooth: L2CAP: clarify BT_L2CAP_STATUS_OUT Makes it clearer what that bit means: If set, the channel has capacity to send at least one PDU. If unset, the channel ran out of credits and won't be able to send anything until the peer sends credits back. Also add debug logs. Signed-off-by: Jonathan Rico --- include/zephyr/bluetooth/l2cap.h | 2 +- subsys/bluetooth/host/l2cap.c | 14 ++++++++------ 2 files changed, 9 insertions(+), 7 deletions(-) diff --git a/include/zephyr/bluetooth/l2cap.h b/include/zephyr/bluetooth/l2cap.h index d9241e7af21..3386c38bdb3 100644 --- a/include/zephyr/bluetooth/l2cap.h +++ b/include/zephyr/bluetooth/l2cap.h @@ -120,7 +120,7 @@ typedef enum bt_l2cap_chan_state { /** @brief Status of L2CAP channel. */ typedef enum bt_l2cap_chan_status { - /** Channel output status */ + /** Channel can send at least one PDU */ BT_L2CAP_STATUS_OUT, /** @brief Channel shutdown status diff --git a/subsys/bluetooth/host/l2cap.c b/subsys/bluetooth/host/l2cap.c index 66c7038f3ce..44a013f14b9 100644 --- a/subsys/bluetooth/host/l2cap.c +++ b/subsys/bluetooth/host/l2cap.c @@ -973,9 +973,11 @@ static void l2cap_chan_tx_give_credits(struct bt_l2cap_le_chan *chan, atomic_add(&chan->tx.credits, credits); - if (!atomic_test_and_set_bit(chan->chan.status, BT_L2CAP_STATUS_OUT) && - chan->chan.ops->status) { - chan->chan.ops->status(&chan->chan, chan->chan.status); + if (!atomic_test_and_set_bit(chan->chan.status, BT_L2CAP_STATUS_OUT)) { + LOG_DBG("chan %p unpaused", chan); + if (chan->chan.ops->status) { + chan->chan.ops->status(&chan->chan, chan->chan.status); + } } } @@ -2045,11 +2047,11 @@ static int l2cap_chan_le_send(struct bt_l2cap_le_chan *ch, return err; } - /* Check if there is no credits left clear output status and notify its - * change. - */ + /* Notify channel user that it can't send anymore on this channel. */ if (!atomic_get(&ch->tx.credits)) { + LOG_DBG("chan %p paused", ch); atomic_clear_bit(ch->chan.status, BT_L2CAP_STATUS_OUT); + if (ch->chan.ops->status) { ch->chan.ops->status(&ch->chan, ch->chan.status); } From b3971d01129676f566ab813f2cb34ffbfb12d8d1 Mon Sep 17 00:00:00 2001 From: Bjarki Arge Andreasen Date: Thu, 4 Jan 2024 13:32:35 +0100 Subject: [PATCH 1756/3723] modem: cmux: Add DLCI receive buffer overrun LOG WRN DLCI receive buffer may overrun if data is not processed fast enough. This error was not reported before this patch, resulting in unexplained missing bytes. Signed-off-by: Bjarki Arge Andreasen --- subsys/modem/modem_cmux.c | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/subsys/modem/modem_cmux.c b/subsys/modem/modem_cmux.c index 7f40fa6e95d..258f969c498 100644 --- a/subsys/modem/modem_cmux.c +++ b/subsys/modem/modem_cmux.c @@ -546,6 +546,7 @@ static void modem_cmux_on_dlci_frame_ua(struct modem_cmux_dlci *dlci) static void modem_cmux_on_dlci_frame_uih(struct modem_cmux_dlci *dlci) { struct modem_cmux *cmux = dlci->cmux; + uint32_t written; if (dlci->state != MODEM_CMUX_DLCI_STATE_OPEN) { LOG_DBG("Unexpected UIH frame"); @@ -553,8 +554,11 @@ static void modem_cmux_on_dlci_frame_uih(struct modem_cmux_dlci *dlci) } k_mutex_lock(&dlci->receive_rb_lock, K_FOREVER); - ring_buf_put(&dlci->receive_rb, cmux->frame.data, cmux->frame.data_len); + written = ring_buf_put(&dlci->receive_rb, cmux->frame.data, cmux->frame.data_len); k_mutex_unlock(&dlci->receive_rb_lock); + if (written != cmux->frame.data_len) { + LOG_WRN("DLCI %u receive buffer overrun", dlci->dlci_address); + } modem_pipe_notify_receive_ready(&dlci->pipe); } From 6291a57e67d12d570429039064f284c0d08d1c32 Mon Sep 17 00:00:00 2001 From: Peter Mitsis Date: Tue, 2 Jan 2024 13:54:15 -0500 Subject: [PATCH 1757/3723] tests: latency_measure: Tidy up header inclusions Moves the inclusion of the app_memdomain header file into the tests' utils.h so that any file that includes this can make use of the BENCH_BMEM macro. Signed-off-by: Peter Mitsis --- tests/benchmarks/latency_measure/src/main.c | 1 - tests/benchmarks/latency_measure/src/timing_sc.c | 1 - tests/benchmarks/latency_measure/src/utils.h | 1 + 3 files changed, 1 insertion(+), 2 deletions(-) diff --git a/tests/benchmarks/latency_measure/src/main.c b/tests/benchmarks/latency_measure/src/main.c index 499ce1273f1..efd67c210ec 100644 --- a/tests/benchmarks/latency_measure/src/main.c +++ b/tests/benchmarks/latency_measure/src/main.c @@ -12,7 +12,6 @@ #include #include -#include #include "utils.h" #include "timing_sc.h" #include diff --git a/tests/benchmarks/latency_measure/src/timing_sc.c b/tests/benchmarks/latency_measure/src/timing_sc.c index 051b9d1810b..9397a258b5a 100644 --- a/tests/benchmarks/latency_measure/src/timing_sc.c +++ b/tests/benchmarks/latency_measure/src/timing_sc.c @@ -11,7 +11,6 @@ */ #include -#include #include "utils.h" #include "timing_sc.h" diff --git a/tests/benchmarks/latency_measure/src/utils.h b/tests/benchmarks/latency_measure/src/utils.h index 62d2fb7259e..cbba26d4fe0 100644 --- a/tests/benchmarks/latency_measure/src/utils.h +++ b/tests/benchmarks/latency_measure/src/utils.h @@ -15,6 +15,7 @@ #include #include #include +#include #define START_STACK_SIZE (512 + CONFIG_TEST_EXTRA_STACK_SIZE) #define ALT_STACK_SIZE (512 + CONFIG_TEST_EXTRA_STACK_SIZE) From 911182c6b94a0274b245e94b787d26745e0d2452 Mon Sep 17 00:00:00 2001 From: Peter Mitsis Date: Wed, 3 Jan 2024 13:40:06 -0500 Subject: [PATCH 1758/3723] tests: latency_measure: Change reporting strings Changes the summary lines used in the latency_measure benchmark so that they follow a consistent pattern. OBJECT action. This makes it easier to locate results belonging to a particular object group. It also has the benefit to keep results colocated should the output be sorted by an external tool. Signed-off-by: Peter Mitsis --- .../benchmarks/latency_measure/src/heap_malloc_free.c | 4 ++-- tests/benchmarks/latency_measure/src/int_to_thread.c | 6 +++--- .../benchmarks/latency_measure/src/mutex_lock_unlock.c | 4 ++-- .../latency_measure/src/sema_test_signal_release.c | 8 ++++---- tests/benchmarks/latency_measure/src/thread.c | 10 +++++----- .../latency_measure/src/thread_switch_yield.c | 6 +++--- 6 files changed, 19 insertions(+), 19 deletions(-) diff --git a/tests/benchmarks/latency_measure/src/heap_malloc_free.c b/tests/benchmarks/latency_measure/src/heap_malloc_free.c index cdb81e0f5b7..4ff93cdc806 100644 --- a/tests/benchmarks/latency_measure/src/heap_malloc_free.c +++ b/tests/benchmarks/latency_measure/src/heap_malloc_free.c @@ -63,9 +63,9 @@ void heap_malloc_free(void) notes = "Memory heap too small--increase it."; } - PRINT_STATS_AVG("Average time for heap malloc", sum_malloc, count, + PRINT_STATS_AVG("HEAP malloc.immediate", sum_malloc, count, failed, notes); - PRINT_STATS_AVG("Average time for heap free", sum_free, count, + PRINT_STATS_AVG("HEAP free.immediate", sum_free, count, failed, notes); timing_stop(); diff --git a/tests/benchmarks/latency_measure/src/int_to_thread.c b/tests/benchmarks/latency_measure/src/int_to_thread.c index ad3cf70fad7..62fa8cdca6c 100644 --- a/tests/benchmarks/latency_measure/src/int_to_thread.c +++ b/tests/benchmarks/latency_measure/src/int_to_thread.c @@ -174,7 +174,7 @@ int int_to_thread(uint32_t num_iterations) sum -= timestamp_overhead_adjustment(0, 0); - PRINT_STATS_AVG("Switch from ISR back to interrupted thread", + PRINT_STATS_AVG("ISR resume.interrupted.thread.kernel", (uint32_t)sum, num_iterations, false, ""); /* ************** */ @@ -183,7 +183,7 @@ int int_to_thread(uint32_t num_iterations) sum -= timestamp_overhead_adjustment(0, 0); - PRINT_STATS_AVG("Switch from ISR to another thread (kernel)", + PRINT_STATS_AVG("ISR resume.different.thread.kernel", (uint32_t)sum, num_iterations, false, ""); /* ************** */ @@ -193,7 +193,7 @@ int int_to_thread(uint32_t num_iterations) sum -= timestamp_overhead_adjustment(0, K_USER); - PRINT_STATS_AVG("Switch from ISR to another thread (user)", + PRINT_STATS_AVG("ISR resume.different.thread.user", (uint32_t)sum, num_iterations, false, ""); #endif diff --git a/tests/benchmarks/latency_measure/src/mutex_lock_unlock.c b/tests/benchmarks/latency_measure/src/mutex_lock_unlock.c index 2f78f45d386..6011f697606 100644 --- a/tests/benchmarks/latency_measure/src/mutex_lock_unlock.c +++ b/tests/benchmarks/latency_measure/src/mutex_lock_unlock.c @@ -94,7 +94,7 @@ int mutex_lock_unlock(uint32_t num_iterations, uint32_t options) k_sem_give(&pause_sem); snprintf(description, sizeof(description), - "Lock a mutex from %s thread", + "MUTEX lock.immediate.recursive.%s", (options & K_USER) == K_USER ? "user" : "kernel"); PRINT_STATS_AVG(description, (uint32_t)cycles, num_iterations, false, ""); @@ -102,7 +102,7 @@ int mutex_lock_unlock(uint32_t num_iterations, uint32_t options) cycles = timestamp.cycles; snprintf(description, sizeof(description), - "Unlock a mutex from %s thread", + "MUTEX unlock.immediate.recursive.%s", (options & K_USER) == K_USER ? "user" : "kernel"); PRINT_STATS_AVG(description, (uint32_t)cycles, num_iterations, false, ""); diff --git a/tests/benchmarks/latency_measure/src/sema_test_signal_release.c b/tests/benchmarks/latency_measure/src/sema_test_signal_release.c index 7610200332c..bd3078cf42c 100644 --- a/tests/benchmarks/latency_measure/src/sema_test_signal_release.c +++ b/tests/benchmarks/latency_measure/src/sema_test_signal_release.c @@ -139,7 +139,7 @@ void sema_context_switch(uint32_t num_iterations, cycles -= timestamp_overhead_adjustment(start_options, alt_options); snprintf(description, sizeof(description), - "Take a semaphore (context switch %c -> %c)", + "SEMAPHORE take.blocking.(%c -> %c)", ((start_options & K_USER) == K_USER) ? 'U' : 'K', ((alt_options & K_USER) == K_USER) ? 'U' : 'K'); PRINT_STATS_AVG(description, (uint32_t)cycles, @@ -155,7 +155,7 @@ void sema_context_switch(uint32_t num_iterations, cycles -= timestamp_overhead_adjustment(start_options, alt_options); snprintf(description, sizeof(description), - "Give a semaphore (context switch %c -> %c)", + "SEMAPHORE give.wake+ctx.(%c -> %c)", ((alt_options & K_USER) == K_USER) ? 'U' : 'K', ((start_options & K_USER) == K_USER) ? 'U' : 'K'); PRINT_STATS_AVG(description, (uint32_t)cycles, @@ -255,7 +255,7 @@ int sema_test_signal(uint32_t num_iterations, uint32_t options) cycles = timestamp.cycles; snprintf(description, sizeof(description), - "Give a semaphore (no waiters) from %s thread", + "SEMAPHORE give.immediate.%s", (options & K_USER) == K_USER ? "user" : "kernel"); PRINT_STATS_AVG(description, (uint32_t)cycles, @@ -274,7 +274,7 @@ int sema_test_signal(uint32_t num_iterations, uint32_t options) cycles = timestamp.cycles; snprintf(description, sizeof(description), - "Take a semaphore (no blocking) from %s thread", + "SEMAPHORE take.immediate.%s", (options & K_USER) == K_USER ? "user" : "kernel"); PRINT_STATS_AVG(description, (uint32_t)cycles, diff --git a/tests/benchmarks/latency_measure/src/thread.c b/tests/benchmarks/latency_measure/src/thread.c index 4448b0e2304..99c7c9f534d 100644 --- a/tests/benchmarks/latency_measure/src/thread.c +++ b/tests/benchmarks/latency_measure/src/thread.c @@ -248,7 +248,7 @@ int thread_ops(uint32_t num_iterations, uint32_t start_options, uint32_t alt_opt /* Only report stats if created */ snprintf(description, sizeof(description), - "Create %s thread from %s thread", + "THREAD create.%s.from.%s", (alt_options & K_USER) != 0 ? "user" : "kernel", (start_options & K_USER) != 0 ? "user" : "kernel"); @@ -261,7 +261,7 @@ int thread_ops(uint32_t num_iterations, uint32_t start_options, uint32_t alt_opt k_sem_give(&pause_sem); snprintf(description, sizeof(description), - "Start %s thread from %s thread", + "THREAD start.%s.from.%s", (alt_options & K_USER) != 0 ? "user" : "kernel", (start_options & K_USER) != 0 ? "user" : "kernel"); @@ -273,7 +273,7 @@ int thread_ops(uint32_t num_iterations, uint32_t start_options, uint32_t alt_opt k_sem_give(&pause_sem); snprintf(description, sizeof(description), - "Suspend %s thread from %s thread", + "THREAD suspend.%s.from.%s", (alt_options & K_USER) != 0 ? "user" : "kernel", (start_options & K_USER) != 0 ? "user" : "kernel"); @@ -285,7 +285,7 @@ int thread_ops(uint32_t num_iterations, uint32_t start_options, uint32_t alt_opt k_sem_give(&pause_sem); snprintf(description, sizeof(description), - "Resume %s thread from %s thread", + "THREAD resume.%s.from.%s", (alt_options & K_USER) != 0 ? "user" : "kernel", (start_options & K_USER) != 0 ? "user" : "kernel"); @@ -297,7 +297,7 @@ int thread_ops(uint32_t num_iterations, uint32_t start_options, uint32_t alt_opt k_sem_give(&pause_sem); snprintf(description, sizeof(description), - "Abort %s thread from %s thread", + "THREAD abort.%s.from.%s", (alt_options & K_USER) != 0 ? "user" : "kernel", (start_options & K_USER) != 0 ? "user" : "kernel"); diff --git a/tests/benchmarks/latency_measure/src/thread_switch_yield.c b/tests/benchmarks/latency_measure/src/thread_switch_yield.c index 44ccc5932c5..f0e626d53a7 100644 --- a/tests/benchmarks/latency_measure/src/thread_switch_yield.c +++ b/tests/benchmarks/latency_measure/src/thread_switch_yield.c @@ -131,7 +131,7 @@ static void thread_switch_yield_common(const char *description, sum -= timestamp_overhead_adjustment(start_options, alt_options); snprintf(summary, sizeof(summary), - "%s (%c -> %c)", + "%s.(%c -> %c)", description, (start_options & K_USER) == K_USER ? 'U' : 'K', (alt_options & K_USER) == K_USER ? 'U' : 'K'); @@ -148,8 +148,8 @@ void thread_switch_yield(uint32_t num_iterations, bool is_cooperative) : k_thread_priority_get(k_current_get()) - 1; snprintf(description, sizeof(description), - "%s threads ctx switch via k_yield", - is_cooperative ? "Cooperative" : "Preemptive"); + "THREAD yield.%s.ctx", + is_cooperative ? "cooperative" : "preemptive"); /* Kernel -> Kernel */ thread_switch_yield_common(description, num_iterations, 0, 0, From c2d2cf6d2be43f872ed9d5ddeaa489e36a0e441d Mon Sep 17 00:00:00 2001 From: Peter Mitsis Date: Tue, 2 Jan 2024 13:23:42 -0500 Subject: [PATCH 1759/3723] tests: latency_measure: Add LIFO support Adds LIFO support to the latency_measure benchmark test. This covers both k_lifo_put() and k_lifo_get() with and without context switches as well as variations for userspace support. Signed-off-by: Peter Mitsis --- tests/benchmarks/latency_measure/src/lifo.c | 330 ++++++++++++++++++++ tests/benchmarks/latency_measure/src/main.c | 17 +- 2 files changed, 346 insertions(+), 1 deletion(-) create mode 100644 tests/benchmarks/latency_measure/src/lifo.c diff --git a/tests/benchmarks/latency_measure/src/lifo.c b/tests/benchmarks/latency_measure/src/lifo.c new file mode 100644 index 00000000000..052f7b212ff --- /dev/null +++ b/tests/benchmarks/latency_measure/src/lifo.c @@ -0,0 +1,330 @@ +/* + * Copyright (c) 2024 Intel Corporation + * + * SPDX-License-Identifier: Apache-2.0 + */ + +/* + * @file measure time for various LIFO operations + * + * This file contains the tests that measures the times for the following + * LIFO operations from both kernel threads and user threads: + * 1. Immediately adding a data item to a LIFO + * 2. Immediately removing a data item from a LIFO + * 3. Immediately adding a data item to a LIFO with allocation + * 4. Immediately removing a data item from a LIFO with allocation + * 5. Blocking on removing a data item from a LIFO + * 6. Waking (and context switching to) a thread blocked on a LIFO via + * k_lifo_put(). + * 7. Waking (and context switching to) a thread blocked on a LIFO via + * k_lifo_alloc_put(). + */ + +#include +#include +#include "utils.h" +#include "timing_sc.h" + +#define STACK_SIZE (512 + CONFIG_TEST_EXTRA_STACK_SIZE) + +static K_LIFO_DEFINE(lifo); + +BENCH_BMEM uintptr_t lifo_data[5]; + +static void lifo_put_get_thread_entry(void *p1, void *p2, void *p3) +{ + uint32_t num_iterations = (uint32_t)(uintptr_t)p1; + uint32_t options = (uint32_t)(uintptr_t)p2; + timing_t start; + timing_t mid; + timing_t finish; + uint64_t put_sum = 0ULL; + uint64_t get_sum = 0ULL; + uintptr_t *data; + + if ((options & K_USER) == 0) { + for (uint32_t i = 0; i < num_iterations; i++) { + start = timing_timestamp_get(); + + k_lifo_put(&lifo, lifo_data); + + mid = timing_timestamp_get(); + + data = k_lifo_get(&lifo, K_NO_WAIT); + + finish = timing_timestamp_get(); + + put_sum += timing_cycles_get(&start, &mid); + get_sum += timing_cycles_get(&mid, &finish); + } + + timestamp.cycles = put_sum; + k_sem_take(&pause_sem, K_FOREVER); + + timestamp.cycles = get_sum; + k_sem_take(&pause_sem, K_FOREVER); + + put_sum = 0ULL; + get_sum = 0ULL; + } + + for (uint32_t i = 0; i < num_iterations; i++) { + start = timing_timestamp_get(); + + k_lifo_alloc_put(&lifo, lifo_data); + + mid = timing_timestamp_get(); + + data = k_lifo_get(&lifo, K_NO_WAIT); + + finish = timing_timestamp_get(); + + put_sum += timing_cycles_get(&start, &mid); + get_sum += timing_cycles_get(&mid, &finish); + } + + timestamp.cycles = put_sum; + k_sem_take(&pause_sem, K_FOREVER); + + timestamp.cycles = get_sum; +} + +int lifo_ops(uint32_t num_iterations, uint32_t options) +{ + int priority; + uint64_t cycles; + char description[80]; + + priority = k_thread_priority_get(k_current_get()); + + timing_start(); + + k_thread_create(&start_thread, start_stack, + K_THREAD_STACK_SIZEOF(start_stack), + lifo_put_get_thread_entry, + (void *)(uintptr_t)num_iterations, + (void *)(uintptr_t)options, NULL, + priority - 1, options, K_FOREVER); + + k_thread_access_grant(&start_thread, &pause_sem, &lifo); + + k_thread_start(&start_thread); + + if ((options & K_USER) == 0) { + snprintf(description, sizeof(description), + "LIFO put.immediate.%s", + options & K_USER ? "user" : "kernel"); + + cycles = timestamp.cycles; + cycles -= timestamp_overhead_adjustment(options, options); + PRINT_STATS_AVG(description, (uint32_t)cycles, + num_iterations, false, ""); + k_sem_give(&pause_sem); + + snprintf(description, sizeof(description), + "LIFO get.immediate.%s", + options & K_USER ? "user" : "kernel"); + cycles = timestamp.cycles; + cycles -= timestamp_overhead_adjustment(options, options); + PRINT_STATS_AVG(description, (uint32_t)cycles, + num_iterations, false, ""); + k_sem_give(&pause_sem); + } + + snprintf(description, sizeof(description), + "LIFO put.alloc.immediate.%s", + options & K_USER ? "user" : "kernel"); + + cycles = timestamp.cycles; + PRINT_STATS_AVG(description, (uint32_t)cycles, + num_iterations, false, ""); + k_sem_give(&pause_sem); + + snprintf(description, sizeof(description), + "LIFO get.free.immediate.%s", + options & K_USER ? "user" : "kernel"); + cycles = timestamp.cycles; + PRINT_STATS_AVG(description, (uint32_t)cycles, + num_iterations, false, ""); + + k_thread_join(&start_thread, K_FOREVER); + + timing_stop(); + + return 0; +} + +static void alt_thread_entry(void *p1, void *p2, void *p3) +{ + uint32_t num_iterations = (uint32_t)(uintptr_t)p1; + uint32_t options = (uint32_t)(uintptr_t)p2; + timing_t start; + timing_t mid; + timing_t finish; + uint64_t sum[4] = {0ULL, 0ULL, 0ULL, 0ULL}; + uintptr_t *data; + uint32_t i; + + if ((options & K_USER) == 0) { + + /* Used with k_lifo_put() */ + + for (i = 0; i < num_iterations; i++) { + + /* 1. Block waiting for data on LIFO */ + + start = timing_timestamp_get(); + + data = k_lifo_get(&lifo, K_FOREVER); + + /* 3. Data obtained. */ + + finish = timing_timestamp_get(); + + mid = timestamp.sample; + + sum[0] += timing_cycles_get(&start, &mid); + sum[1] += timing_cycles_get(&mid, &finish); + } + } + + /* Used with k_lifo_alloc_put() */ + + for (i = 0; i < num_iterations; i++) { + + /* 4. Block waiting for data on LIFO */ + + start = timing_timestamp_get(); + + data = k_lifo_get(&lifo, K_FOREVER); + + /* 6. Data obtained */ + + finish = timing_timestamp_get(); + + mid = timestamp.sample; + + sum[2] += timing_cycles_get(&start, &mid); + sum[3] += timing_cycles_get(&mid, &finish); + } + + if ((options & K_USER) == 0) { + timestamp.cycles = sum[0]; + k_sem_take(&pause_sem, K_FOREVER); + timestamp.cycles = sum[1]; + k_sem_take(&pause_sem, K_FOREVER); + } + + timestamp.cycles = sum[2]; + k_sem_take(&pause_sem, K_FOREVER); + timestamp.cycles = sum[3]; +} + +static void start_thread_entry(void *p1, void *p2, void *p3) +{ + uint32_t num_iterations = (uint32_t)(uintptr_t)p1; + uint32_t options = (uint32_t)(uintptr_t)p2; + uint32_t i; + + k_thread_start(&alt_thread); + + if ((options & K_USER) == 0) { + for (i = 0; i < num_iterations; i++) { + + /* 2. Add data thereby waking alt thread */ + + timestamp.sample = timing_timestamp_get(); + + k_lifo_put(&lifo, lifo_data); + + } + } + + for (i = 0; i < num_iterations; i++) { + + /* 5. Add data thereby waking alt thread */ + + timestamp.sample = timing_timestamp_get(); + + k_lifo_alloc_put(&lifo, lifo_data); + + } + + k_thread_join(&alt_thread, K_FOREVER); +} + +int lifo_blocking_ops(uint32_t num_iterations, uint32_t start_options, + uint32_t alt_options) +{ + int priority; + uint64_t cycles; + char description[80]; + + priority = k_thread_priority_get(k_current_get()); + + timing_start(); + + k_thread_create(&start_thread, start_stack, + K_THREAD_STACK_SIZEOF(start_stack), + start_thread_entry, + (void *)(uintptr_t)num_iterations, + (void *)(uintptr_t)(start_options | alt_options), NULL, + priority - 1, start_options, K_FOREVER); + + k_thread_create(&alt_thread, alt_stack, + K_THREAD_STACK_SIZEOF(alt_stack), + alt_thread_entry, + (void *)(uintptr_t)num_iterations, + (void *)(uintptr_t)(start_options | alt_options), NULL, + priority - 2, alt_options, K_FOREVER); + + k_thread_access_grant(&start_thread, &alt_thread, &pause_sem, &lifo); + k_thread_access_grant(&alt_thread, &pause_sem, &lifo); + + k_thread_start(&start_thread); + + if (((start_options | alt_options) & K_USER) == 0) { + snprintf(description, sizeof(description), + "LIFO get.blocking.(%s -> %s)", + alt_options & K_USER ? "U" : "K", + start_options & K_USER ? "U" : "K"); + + cycles = timestamp.cycles; + PRINT_STATS_AVG(description, (uint32_t)cycles, + num_iterations, false, ""); + k_sem_give(&pause_sem); + + snprintf(description, sizeof(description), + "LIFO put.wake+ctx.(%s -> %s)", + start_options & K_USER ? "U" : "K", + alt_options & K_USER ? "U" : "K"); + cycles = timestamp.cycles; + PRINT_STATS_AVG(description, (uint32_t)cycles, + num_iterations, false, ""); + k_sem_give(&pause_sem); + } + + snprintf(description, sizeof(description), + "LIFO get.free.blocking.(%s -> %s)", + alt_options & K_USER ? "U" : "K", + start_options & K_USER ? "U" : "K"); + + cycles = timestamp.cycles; + PRINT_STATS_AVG(description, (uint32_t)cycles, + num_iterations, false, ""); + k_sem_give(&pause_sem); + + snprintf(description, sizeof(description), + "LIFO put.alloc.wake+ctx.(%s -> %s)", + start_options & K_USER ? "U" : "K", + alt_options & K_USER ? "U" : "K"); + cycles = timestamp.cycles; + PRINT_STATS_AVG(description, (uint32_t)cycles, + num_iterations, false, ""); + + k_thread_join(&start_thread, K_FOREVER); + + timing_stop(); + + return 0; +} diff --git a/tests/benchmarks/latency_measure/src/main.c b/tests/benchmarks/latency_measure/src/main.c index efd67c210ec..e1b2aaea8b9 100644 --- a/tests/benchmarks/latency_measure/src/main.c +++ b/tests/benchmarks/latency_measure/src/main.c @@ -1,6 +1,6 @@ /* * Copyright (c) 2012-2015 Wind River Systems, Inc. - * Copyright (c) 2023 Intel Corporation. + * Copyright (c) 2023,2024 Intel Corporation. * * SPDX-License-Identifier: Apache-2.0 */ @@ -46,6 +46,9 @@ extern void sema_context_switch(uint32_t num_iterations, uint32_t start_options, uint32_t alt_options); extern int thread_ops(uint32_t num_iterations, uint32_t start_options, uint32_t alt_options); +extern int lifo_ops(uint32_t num_iterations, uint32_t options); +extern int lifo_blocking_ops(uint32_t num_iterations, uint32_t start_options, + uint32_t alt_options); extern void heap_malloc_free(void); static void test_thread(void *arg1, void *arg2, void *arg3) @@ -89,6 +92,18 @@ static void test_thread(void *arg1, void *arg2, void *arg3) thread_ops(NUM_ITERATIONS, K_USER, 0); #endif + lifo_ops(NUM_ITERATIONS, 0); +#ifdef CONFIG_USERSPACE + lifo_ops(NUM_ITERATIONS, K_USER); +#endif + + lifo_blocking_ops(NUM_ITERATIONS, 0, 0); +#ifdef CONFIG_USERSPACE + lifo_blocking_ops(NUM_ITERATIONS, 0, K_USER); + lifo_blocking_ops(NUM_ITERATIONS, K_USER, 0); + lifo_blocking_ops(NUM_ITERATIONS, K_USER, K_USER); +#endif + sema_test_signal(NUM_ITERATIONS, 0); #ifdef CONFIG_USERSPACE sema_test_signal(NUM_ITERATIONS, K_USER); From 7103b0cdeb100919ea8459f15cf8823cdb28e891 Mon Sep 17 00:00:00 2001 From: Peter Mitsis Date: Wed, 3 Jan 2024 13:29:01 -0500 Subject: [PATCH 1760/3723] tests: latency_measure: Add FIFO support Adds FIFO support to the latency_measure benchmark. This covers both k_fifo_put() and k_fifo_get() with and without context switches as well as variations for userspace support. Signed-off-by: Peter Mitsis --- tests/benchmarks/latency_measure/src/fifo.c | 330 ++++++++++++++++++++ tests/benchmarks/latency_measure/src/main.c | 16 + 2 files changed, 346 insertions(+) create mode 100644 tests/benchmarks/latency_measure/src/fifo.c diff --git a/tests/benchmarks/latency_measure/src/fifo.c b/tests/benchmarks/latency_measure/src/fifo.c new file mode 100644 index 00000000000..4bd1750e89a --- /dev/null +++ b/tests/benchmarks/latency_measure/src/fifo.c @@ -0,0 +1,330 @@ +/* + * Copyright (c) 2024 Intel Corporation + * + * SPDX-License-Identifier: Apache-2.0 + */ + +/* + * @file measure time for various FIFO operations + * + * This file contains the tests that measures the times for the following + * FIFO operations from both kernel threads and user threads: + * 1. Immediately adding a data item to a FIFO + * 2. Immediately removing a data item from a FIFO + * 3. Immediately adding a data item to a FIFO with allocation + * 4. Immediately removing a data item from a FIFO with allocation + * 5. Blocking on removing a data item from a FIFO + * 6. Waking (and context switching to) a thread blocked on a FIFO via + * k_fifo_put(). + * 7. Waking (and context switching to) a thread blocked on a FIFO via + * k_fifo_alloc_put(). + */ + +#include +#include +#include "utils.h" +#include "timing_sc.h" + +#define STACK_SIZE (512 + CONFIG_TEST_EXTRA_STACK_SIZE) + +static K_FIFO_DEFINE(fifo); + +BENCH_BMEM uintptr_t fifo_data[5]; + +static void fifo_put_get_thread_entry(void *p1, void *p2, void *p3) +{ + uint32_t num_iterations = (uint32_t)(uintptr_t)p1; + uint32_t options = (uint32_t)(uintptr_t)p2; + timing_t start; + timing_t mid; + timing_t finish; + uint64_t put_sum = 0ULL; + uint64_t get_sum = 0ULL; + uintptr_t *data; + + if ((options & K_USER) == 0) { + for (uint32_t i = 0; i < num_iterations; i++) { + start = timing_timestamp_get(); + + k_fifo_put(&fifo, fifo_data); + + mid = timing_timestamp_get(); + + data = k_fifo_get(&fifo, K_NO_WAIT); + + finish = timing_timestamp_get(); + + put_sum += timing_cycles_get(&start, &mid); + get_sum += timing_cycles_get(&mid, &finish); + } + + timestamp.cycles = put_sum; + k_sem_take(&pause_sem, K_FOREVER); + + timestamp.cycles = get_sum; + k_sem_take(&pause_sem, K_FOREVER); + + put_sum = 0ULL; + get_sum = 0ULL; + } + + for (uint32_t i = 0; i < num_iterations; i++) { + start = timing_timestamp_get(); + + k_fifo_alloc_put(&fifo, fifo_data); + + mid = timing_timestamp_get(); + + data = k_fifo_get(&fifo, K_NO_WAIT); + + finish = timing_timestamp_get(); + + put_sum += timing_cycles_get(&start, &mid); + get_sum += timing_cycles_get(&mid, &finish); + } + + timestamp.cycles = put_sum; + k_sem_take(&pause_sem, K_FOREVER); + + timestamp.cycles = get_sum; +} + +int fifo_ops(uint32_t num_iterations, uint32_t options) +{ + int priority; + uint64_t cycles; + char description[80]; + + priority = k_thread_priority_get(k_current_get()); + + timing_start(); + + k_thread_create(&start_thread, start_stack, + K_THREAD_STACK_SIZEOF(start_stack), + fifo_put_get_thread_entry, + (void *)(uintptr_t)num_iterations, + (void *)(uintptr_t)options, NULL, + priority - 1, options, K_FOREVER); + + k_thread_access_grant(&start_thread, &pause_sem, &fifo); + + k_thread_start(&start_thread); + + if ((options & K_USER) == 0) { + snprintf(description, sizeof(description), + "FIFO put.immediate.%s", + options & K_USER ? "user" : "kernel"); + + cycles = timestamp.cycles; + cycles -= timestamp_overhead_adjustment(options, options); + PRINT_STATS_AVG(description, (uint32_t)cycles, + num_iterations, false, ""); + k_sem_give(&pause_sem); + + snprintf(description, sizeof(description), + "FIFO get.immediate.%s", + options & K_USER ? "user" : "kernel"); + cycles = timestamp.cycles; + cycles -= timestamp_overhead_adjustment(options, options); + PRINT_STATS_AVG(description, (uint32_t)cycles, + num_iterations, false, ""); + k_sem_give(&pause_sem); + } + + snprintf(description, sizeof(description), + "FIFO put.alloc.immediate.%s", + options & K_USER ? "user" : "kernel"); + + cycles = timestamp.cycles; + PRINT_STATS_AVG(description, (uint32_t)cycles, + num_iterations, false, ""); + k_sem_give(&pause_sem); + + snprintf(description, sizeof(description), + "FIFO get.free.immediate.%s", + options & K_USER ? "user" : "kernel"); + cycles = timestamp.cycles; + PRINT_STATS_AVG(description, (uint32_t)cycles, + num_iterations, false, ""); + + k_thread_join(&start_thread, K_FOREVER); + + timing_stop(); + + return 0; +} + +static void alt_thread_entry(void *p1, void *p2, void *p3) +{ + uint32_t num_iterations = (uint32_t)(uintptr_t)p1; + uint32_t options = (uint32_t)(uintptr_t)p2; + timing_t start; + timing_t mid; + timing_t finish; + uint64_t sum[4] = {0ULL, 0ULL, 0ULL, 0ULL}; + uintptr_t *data; + uint32_t i; + + if ((options & K_USER) == 0) { + + /* Used with k_fifo_put() */ + + for (i = 0; i < num_iterations; i++) { + + /* 1. Block waiting for data on FIFO */ + + start = timing_timestamp_get(); + + data = k_fifo_get(&fifo, K_FOREVER); + + /* 3. Data obtained. */ + + finish = timing_timestamp_get(); + + mid = timestamp.sample; + + sum[0] += timing_cycles_get(&start, &mid); + sum[1] += timing_cycles_get(&mid, &finish); + } + } + + /* Used with k_fifo_alloc_put() */ + + for (i = 0; i < num_iterations; i++) { + + /* 4. Block waiting for data on FIFO */ + + start = timing_timestamp_get(); + + data = k_fifo_get(&fifo, K_FOREVER); + + /* 6. Data obtained */ + + finish = timing_timestamp_get(); + + mid = timestamp.sample; + + sum[2] += timing_cycles_get(&start, &mid); + sum[3] += timing_cycles_get(&mid, &finish); + } + + if ((options & K_USER) == 0) { + timestamp.cycles = sum[0]; + k_sem_take(&pause_sem, K_FOREVER); + timestamp.cycles = sum[1]; + k_sem_take(&pause_sem, K_FOREVER); + } + + timestamp.cycles = sum[2]; + k_sem_take(&pause_sem, K_FOREVER); + timestamp.cycles = sum[3]; +} + +static void start_thread_entry(void *p1, void *p2, void *p3) +{ + uint32_t num_iterations = (uint32_t)(uintptr_t)p1; + uint32_t options = (uint32_t)(uintptr_t)p2; + uint32_t i; + + k_thread_start(&alt_thread); + + if ((options & K_USER) == 0) { + for (i = 0; i < num_iterations; i++) { + + /* 2. Add data thereby waking alt thread */ + + timestamp.sample = timing_timestamp_get(); + + k_fifo_put(&fifo, fifo_data); + + } + } + + for (i = 0; i < num_iterations; i++) { + + /* 5. Add data thereby waking alt thread */ + + timestamp.sample = timing_timestamp_get(); + + k_fifo_alloc_put(&fifo, fifo_data); + + } + + k_thread_join(&alt_thread, K_FOREVER); +} + +int fifo_blocking_ops(uint32_t num_iterations, uint32_t start_options, + uint32_t alt_options) +{ + int priority; + uint64_t cycles; + char description[80]; + + priority = k_thread_priority_get(k_current_get()); + + timing_start(); + + k_thread_create(&start_thread, start_stack, + K_THREAD_STACK_SIZEOF(start_stack), + start_thread_entry, + (void *)(uintptr_t)num_iterations, + (void *)(uintptr_t)(start_options | alt_options), NULL, + priority - 1, start_options, K_FOREVER); + + k_thread_create(&alt_thread, alt_stack, + K_THREAD_STACK_SIZEOF(alt_stack), + alt_thread_entry, + (void *)(uintptr_t)num_iterations, + (void *)(uintptr_t)(start_options | alt_options), NULL, + priority - 2, alt_options, K_FOREVER); + + k_thread_access_grant(&start_thread, &alt_thread, &pause_sem, &fifo); + k_thread_access_grant(&alt_thread, &pause_sem, &fifo); + + k_thread_start(&start_thread); + + if (((start_options | alt_options) & K_USER) == 0) { + snprintf(description, sizeof(description), + "FIFO get.blocking.(%s -> %s)", + alt_options & K_USER ? "U" : "K", + start_options & K_USER ? "U" : "K"); + + cycles = timestamp.cycles; + PRINT_STATS_AVG(description, (uint32_t)cycles, + num_iterations, false, ""); + k_sem_give(&pause_sem); + + snprintf(description, sizeof(description), + "FIFO put.wake+ctx.(%s -> %s)", + start_options & K_USER ? "U" : "K", + alt_options & K_USER ? "U" : "K"); + cycles = timestamp.cycles; + PRINT_STATS_AVG(description, (uint32_t)cycles, + num_iterations, false, ""); + k_sem_give(&pause_sem); + } + + snprintf(description, sizeof(description), + "FIFO get.free.blocking.(%s -> %s)", + alt_options & K_USER ? "U" : "K", + start_options & K_USER ? "U" : "K"); + + cycles = timestamp.cycles; + PRINT_STATS_AVG(description, (uint32_t)cycles, + num_iterations, false, ""); + k_sem_give(&pause_sem); + + snprintf(description, sizeof(description), + "FIFO put.alloc.wake+ctx.(%s -> %s)", + start_options & K_USER ? "U" : "K", + alt_options & K_USER ? "U" : "K"); + cycles = timestamp.cycles; + PRINT_STATS_AVG(description, (uint32_t)cycles, + num_iterations, false, ""); + + k_thread_join(&start_thread, K_FOREVER); + + timing_stop(); + + return 0; +} diff --git a/tests/benchmarks/latency_measure/src/main.c b/tests/benchmarks/latency_measure/src/main.c index e1b2aaea8b9..fcd01b86243 100644 --- a/tests/benchmarks/latency_measure/src/main.c +++ b/tests/benchmarks/latency_measure/src/main.c @@ -46,6 +46,9 @@ extern void sema_context_switch(uint32_t num_iterations, uint32_t start_options, uint32_t alt_options); extern int thread_ops(uint32_t num_iterations, uint32_t start_options, uint32_t alt_options); +extern int fifo_ops(uint32_t num_iterations, uint32_t options); +extern int fifo_blocking_ops(uint32_t num_iterations, uint32_t start_options, + uint32_t alt_options); extern int lifo_ops(uint32_t num_iterations, uint32_t options); extern int lifo_blocking_ops(uint32_t num_iterations, uint32_t start_options, uint32_t alt_options); @@ -92,6 +95,19 @@ static void test_thread(void *arg1, void *arg2, void *arg3) thread_ops(NUM_ITERATIONS, K_USER, 0); #endif + fifo_ops(NUM_ITERATIONS, 0); +#ifdef CONFIG_USERSPACE + fifo_ops(NUM_ITERATIONS, K_USER); +#endif + + fifo_blocking_ops(NUM_ITERATIONS, 0, 0); +#ifdef CONFIG_USERSPACE + fifo_blocking_ops(NUM_ITERATIONS, 0, K_USER); + fifo_blocking_ops(NUM_ITERATIONS, K_USER, 0); + fifo_blocking_ops(NUM_ITERATIONS, K_USER, K_USER); +#endif + + lifo_ops(NUM_ITERATIONS, 0); #ifdef CONFIG_USERSPACE lifo_ops(NUM_ITERATIONS, K_USER); From 38010c111e2342e0c574ee88c8704a39ee7e6006 Mon Sep 17 00:00:00 2001 From: Peter Mitsis Date: Wed, 3 Jan 2024 14:50:46 -0500 Subject: [PATCH 1761/3723] test: latency_measure: Update sample output Updates the sample output in the latency_measure benchmark's README file. Signed-off-by: Peter Mitsis --- tests/benchmarks/latency_measure/README.rst | 194 ++++++++++++-------- 1 file changed, 121 insertions(+), 73 deletions(-) diff --git a/tests/benchmarks/latency_measure/README.rst b/tests/benchmarks/latency_measure/README.rst index 7f17e979697..a061d8c5a52 100644 --- a/tests/benchmarks/latency_measure/README.rst +++ b/tests/benchmarks/latency_measure/README.rst @@ -8,14 +8,18 @@ including: * Context switch time between cooperative threads using k_yield * Time to switch from ISR back to interrupted thread * Time from ISR to executing a different thread (rescheduled) -* Times to signal a semaphore then test that semaphore -* Times to signal a semaphore then test that semaphore with a context switch +* Time to signal a semaphore then test that semaphore +* Time to signal a semaphore then test that semaphore with a context switch * Times to lock a mutex then unlock that mutex * Time it takes to create a new thread (without starting it) * Time it takes to start a newly created thread * Time it takes to suspend a thread * Time it takes to resume a suspended thread * Time it takes to abort a thread +* Time it takes to add data to a FIFO/LIFO +* Time it takes to retrieve data from a FIFO/LIFO +* Time it takes to wait on a FIFO/LIFO (and context switch) +* Time it takes to wake and switch to a thread waiting on a FIFO/LIFO * Measure average time to alloc memory from heap then free that memory When userspace is enabled using the prj_user.conf configuration file, this benchmark will @@ -29,81 +33,125 @@ threads: Sample output of the benchmark (without userspace enabled):: - *** Booting Zephyr OS build v3.5.0-rc1-139-gdab69aeed11d *** - START - Time Measurement - Timing results: Clock frequency: 120 MHz - Preemptive threads ctx switch via k_yield (K -> K) : 519 cycles , 4325 ns : - Cooperative threads ctx switch via k_yield (K -> K) : 519 cycles , 4325 ns : - Switch from ISR back to interrupted thread : 508 cycles , 4241 ns : - Switch from ISR to another thread (kernel) : 554 cycles , 4616 ns : - Create kernel thread from kernel thread : 396 cycles , 3308 ns : - Start kernel thread from kernel thread : 603 cycles , 5033 ns : - Suspend kernel thread from kernel thread : 599 cycles , 4992 ns : - Resume kernel thread from kernel thread : 547 cycles , 4558 ns : - Abort kernel thread from kernel thread : 339 cycles , 2825 ns : - Give a semaphore (no waiters) from kernel thread : 134 cycles , 1116 ns : - Take a semaphore (no blocking) from kernel thread : 53 cycles , 441 ns : - Take a semaphore (context switch K -> K) : 689 cycles , 5742 ns : - Give a semaphore (context switch K -> K) : 789 cycles , 6575 ns : - Lock a mutex from kernel thread : 94 cycles , 783 ns : - Unlock a mutex from kernel thread : 24 cycles , 200 ns : - Average time for heap malloc : 620 cycles , 5166 ns : - Average time for heap free : 431 cycles , 3591 ns : + *** Booting Zephyr OS build zephyr-v3.5.0-3537-g5dbe0ce2622d *** + THREAD yield.preemptive.ctx.(K -> K) : 344 cycles , 2866 ns : + THREAD yield.cooperative.ctx.(K -> K) : 344 cycles , 2867 ns : + ISR resume.interrupted.thread.kernel : 498 cycles , 4158 ns : + ISR resume.different.thread.kernel : 383 cycles , 3199 ns : + THREAD create.kernel.from.kernel : 401 cycles , 3349 ns : + THREAD start.kernel.from.kernel : 418 cycles , 3491 ns : + THREAD suspend.kernel.from.kernel : 433 cycles , 3616 ns : + THREAD resume.kernel.from.kernel : 351 cycles , 2933 ns : + THREAD abort.kernel.from.kernel : 349 cycles , 2909 ns : + FIFO put.immediate.kernel : 294 cycles , 2450 ns : + FIFO get.immediate.kernel : 135 cycles , 1133 ns : + FIFO put.alloc.immediate.kernel : 906 cycles , 7550 ns : + FIFO get.free.immediate.kernel : 570 cycles , 4750 ns : + FIFO get.blocking.(K -> K) : 545 cycles , 4542 ns : + FIFO put.wake+ctx.(K -> K) : 675 cycles , 5625 ns : + FIFO get.free.blocking.(K -> K) : 555 cycles , 4625 ns : + FIFO put.alloc.wake+ctx.(K -> K) : 670 cycles , 5583 ns : + LIFO put.immediate.kernel : 282 cycles , 2350 ns : + LIFO get.immediate.kernel : 135 cycles , 1133 ns : + LIFO put.alloc.immediate.kernel : 903 cycles , 7526 ns : + LIFO get.free.immediate.kernel : 570 cycles , 4750 ns : + LIFO get.blocking.(K -> K) : 542 cycles , 4524 ns : + LIFO put.wake+ctx.(K -> K) : 670 cycles , 5584 ns : + LIFO get.free.blocking.(K -> K) : 547 cycles , 4558 ns : + LIFO put.alloc.wake+ctx.(K -> K) : 670 cycles , 5583 ns : + SEMAPHORE give.immediate.kernel : 165 cycles , 1375 ns : + SEMAPHORE take.immediate.kernel : 69 cycles , 575 ns : + SEMAPHORE take.blocking.(K -> K) : 489 cycles , 4075 ns : + SEMAPHORE give.wake+ctx.(K -> K) : 604 cycles , 5033 ns : + MUTEX lock.immediate.recursive.kernel : 115 cycles , 958 ns : + MUTEX unlock.immediate.recursive.kernel : 40 cycles , 333 ns : + HEAP malloc.immediate : 615 cycles , 5125 ns : + HEAP free.immediate : 431 cycles , 3591 ns : =================================================================== PROJECT EXECUTION SUCCESSFUL Sample output of the benchmark (with userspace enabled):: - *** Booting Zephyr OS build v3.5.0-rc1-139-gdab69aeed11d *** - START - Time Measurement - Timing results: Clock frequency: 120 MHz - Preemptive threads ctx switch via k_yield (K -> K) : 1195 cycles , 9958 ns : - Preemptive threads ctx switch via k_yield (U -> U) : 1485 cycles , 12379 ns : - Preemptive threads ctx switch via k_yield (K -> U) : 1390 cycles , 11587 ns : - Preemptive threads ctx switch via k_yield (U -> K) : 1289 cycles , 10749 ns : - Cooperative threads ctx switch via k_yield (K -> K) : 1185 cycles , 9875 ns : - Cooperative threads ctx switch via k_yield (U -> U) : 1475 cycles , 12295 ns : - Cooperative threads ctx switch via k_yield (K -> U) : 1380 cycles , 11504 ns : - Cooperative threads ctx switch via k_yield (U -> K) : 1280 cycles , 10666 ns : - Switch from ISR back to interrupted thread : 1130 cycles , 9416 ns : - Switch from ISR to another thread (kernel) : 1184 cycles , 9874 ns : - Switch from ISR to another thread (user) : 1390 cycles , 11583 ns : - Create kernel thread from kernel thread : 985 cycles , 8208 ns : - Start kernel thread from kernel thread : 1275 cycles , 10625 ns : - Suspend kernel thread from kernel thread : 1220 cycles , 10167 ns : - Resume kernel thread from kernel thread : 1193 cycles , 9942 ns : - Abort kernel thread from kernel thread : 2555 cycles , 21292 ns : - Create user thread from kernel thread : 849 cycles , 7083 ns : - Start user thread from kernel thread : 6715 cycles , 55960 ns : - Suspend user thread from kernel thread : 1585 cycles , 13208 ns : - Resume user thread from kernel thread : 1383 cycles , 11525 ns : - Abort user thread from kernel thread : 2420 cycles , 20167 ns : - Create user thread from user thread : 2110 cycles , 17584 ns : - Start user thread from user thread : 7070 cycles , 58919 ns : - Suspend user thread from user thread : 1784 cycles , 14874 ns : - Resume user thread from user thread : 1740 cycles , 14502 ns : - Abort user thread from user thread : 3000 cycles , 25000 ns : - Start kernel thread from user thread : 1630 cycles , 13583 ns : - Suspend kernel thread from user thread : 1420 cycles , 11833 ns : - Resume kernel thread from user thread : 1550 cycles , 12917 ns : - Abort kernel thread from user thread : 3135 cycles , 26125 ns : - Give a semaphore (no waiters) from kernel thread : 160 cycles , 1333 ns : - Take a semaphore (no blocking) from kernel thread : 95 cycles , 791 ns : - Give a semaphore (no waiters) from user thread : 380 cycles , 3166 ns : - Take a semaphore (no blocking) from user thread : 315 cycles , 2625 ns : - Take a semaphore (context switch K -> K) : 1340 cycles , 11167 ns : - Give a semaphore (context switch K -> K) : 1460 cycles , 12167 ns : - Take a semaphore (context switch K -> U) : 1540 cycles , 12838 ns : - Give a semaphore (context switch U -> K) : 1800 cycles , 15000 ns : - Take a semaphore (context switch U -> K) : 1690 cycles , 14084 ns : - Give a semaphore (context switch K -> U) : 1650 cycles , 13750 ns : - Take a semaphore (context switch U -> U) : 1890 cycles , 15756 ns : - Give a semaphore (context switch U -> U) : 1990 cycles , 16583 ns : - Lock a mutex from kernel thread : 105 cycles , 875 ns : - Unlock a mutex from kernel thread : 17 cycles , 141 ns : - Lock a mutex from user thread : 330 cycles , 2750 ns : - Unlock a mutex from user thread : 255 cycles , 2125 ns : - Average time for heap malloc : 606 cycles , 5058 ns : - Average time for heap free : 422 cycles , 3516 ns : + *** Booting Zephyr OS build zephyr-v3.5.0-3537-g5dbe0ce2622d *** + THREAD yield.preemptive.ctx.(K -> K) : 990 cycles , 8250 ns : + THREAD yield.preemptive.ctx.(U -> U) : 1285 cycles , 10712 ns : + THREAD yield.preemptive.ctx.(K -> U) : 1178 cycles , 9817 ns : + THREAD yield.preemptive.ctx.(U -> K) : 1097 cycles , 9145 ns : + THREAD yield.cooperative.ctx.(K -> K) : 990 cycles , 8250 ns : + THREAD yield.cooperative.ctx.(U -> U) : 1285 cycles , 10712 ns : + THREAD yield.cooperative.ctx.(K -> U) : 1178 cycles , 9817 ns : + THREAD yield.cooperative.ctx.(U -> K) : 1097 cycles , 9146 ns : + ISR resume.interrupted.thread.kernel : 1120 cycles , 9333 ns : + ISR resume.different.thread.kernel : 1010 cycles , 8417 ns : + ISR resume.different.thread.user : 1207 cycles , 10062 ns : + THREAD create.kernel.from.kernel : 955 cycles , 7958 ns : + THREAD start.kernel.from.kernel : 1095 cycles , 9126 ns : + THREAD suspend.kernel.from.kernel : 1064 cycles , 8874 ns : + THREAD resume.kernel.from.kernel : 999 cycles , 8333 ns : + THREAD abort.kernel.from.kernel : 2280 cycles , 19000 ns : + THREAD create.user.from.kernel : 822 cycles , 6855 ns : + THREAD start.user.from.kernel : 6572 cycles , 54774 ns : + THREAD suspend.user.from.kernel : 1422 cycles , 11857 ns : + THREAD resume.user.from.kernel : 1177 cycles , 9812 ns : + THREAD abort.user.from.kernel : 2147 cycles , 17897 ns : + THREAD create.user.from.user : 2105 cycles , 17542 ns : + THREAD start.user.from.user : 6960 cycles , 58002 ns : + THREAD suspend user.from.user : 1610 cycles , 13417 ns : + THREAD resume user.from.user : 1565 cycles , 13042 ns : + THREAD abort user.from.user : 2780 cycles , 23167 ns : + THREAD start.kernel.from.user : 1482 cycles , 12353 ns : + THREAD suspend.kernel.from.user : 1252 cycles , 10437 ns : + THREAD resume.kernel.from.user : 1387 cycles , 11564 ns : + THREAD abort.kernel.from.user : 2912 cycles , 24272 ns : + FIFO put.immediate.kernel : 314 cycles , 2624 ns : + FIFO get.immediate.kernel : 215 cycles , 1792 ns : + FIFO put.alloc.immediate.kernel : 1025 cycles , 8541 ns : + FIFO get.free.immediate.kernel : 655 cycles , 5458 ns : + FIFO put.alloc.immediate.user : 1740 cycles , 14500 ns : + FIFO get.free.immediate.user : 1410 cycles , 11751 ns : + FIFO get.blocking.(K -> K) : 1249 cycles , 10416 ns : + FIFO put.wake+ctx.(K -> K) : 1320 cycles , 11000 ns : + FIFO get.free.blocking.(K -> K) : 1235 cycles , 10292 ns : + FIFO put.alloc.wake+ctx.(K -> K) : 1355 cycles , 11292 ns : + FIFO get.free.blocking.(U -> K) : 1750 cycles , 14584 ns : + FIFO put.alloc.wake+ctx.(K -> U) : 1680 cycles , 14001 ns : + FIFO get.free.blocking.(K -> U) : 1555 cycles , 12959 ns : + FIFO put.alloc.wake+ctx.(U -> K) : 1845 cycles , 15375 ns : + FIFO get.free.blocking.(U -> U) : 2070 cycles , 17251 ns : + FIFO put.alloc.wake+ctx.(U -> U) : 2170 cycles , 18084 ns : + LIFO put.immediate.kernel : 299 cycles , 2499 ns : + LIFO get.immediate.kernel : 204 cycles , 1708 ns : + LIFO put.alloc.immediate.kernel : 1015 cycles , 8459 ns : + LIFO get.free.immediate.kernel : 645 cycles , 5375 ns : + LIFO put.alloc.immediate.user : 1760 cycles , 14668 ns : + LIFO get.free.immediate.user : 1400 cycles , 11667 ns : + LIFO get.blocking.(K -> K) : 1234 cycles , 10291 ns : + LIFO put.wake+ctx.(K -> K) : 1315 cycles , 10959 ns : + LIFO get.free.blocking.(K -> K) : 1230 cycles , 10251 ns : + LIFO put.alloc.wake+ctx.(K -> K) : 1345 cycles , 11208 ns : + LIFO get.free.blocking.(U -> K) : 1745 cycles , 14544 ns : + LIFO put.alloc.wake+ctx.(K -> U) : 1680 cycles , 14000 ns : + LIFO get.free.blocking.(K -> U) : 1555 cycles , 12958 ns : + LIFO put.alloc.wake+ctx.(U -> K) : 1855 cycles , 15459 ns : + LIFO get.free.blocking.(U -> U) : 2070 cycles , 17251 ns : + LIFO put.alloc.wake+ctx.(U -> U) : 2190 cycles , 18251 ns : + SEMAPHORE give.immediate.kernel : 210 cycles , 1750 ns : + SEMAPHORE take.immediate.kernel : 145 cycles , 1208 ns : + SEMAPHORE give.immediate.user : 715 cycles , 5959 ns : + SEMAPHORE take.immediate.user : 660 cycles , 5500 ns : + SEMAPHORE take.blocking.(K -> K) : 1150 cycles , 9584 ns : + SEMAPHORE give.wake+ctx.(K -> K) : 1279 cycles , 10666 ns : + SEMAPHORE take.blocking.(K -> U) : 1343 cycles , 11192 ns : + SEMAPHORE give.wake+ctx.(U -> K) : 1637 cycles , 13645 ns : + SEMAPHORE take.blocking.(U -> K) : 1522 cycles , 12688 ns : + SEMAPHORE give.wake+ctx.(K -> U) : 1472 cycles , 12270 ns : + SEMAPHORE take.blocking.(U -> U) : 1715 cycles , 14296 ns : + SEMAPHORE give.wake+ctx.(U -> U) : 1830 cycles , 15250 ns : + MUTEX lock.immediate.recursive.kernel : 150 cycles , 1250 ns : + MUTEX unlock.immediate.recursive.kernel : 57 cycles , 475 ns : + MUTEX lock.immediate.recursive.user : 670 cycles , 5583 ns : + MUTEX unlock.immediate.recursive.user : 595 cycles , 4959 ns : + HEAP malloc.immediate : 629 cycles , 5241 ns : + HEAP free.immediate : 414 cycles , 3450 ns : =================================================================== PROJECT EXECUTION SUCCESSFUL From 2b20f01d86a8d1ea0066e870fced6cc7ac60424b Mon Sep 17 00:00:00 2001 From: Peter Marheine Date: Thu, 4 Jan 2024 11:00:47 +1100 Subject: [PATCH 1762/3723] twister: move lcov version handling to helpers This moves handling of changed lcov arguments in lcov 2.0 into helper functions, significantly simplifying Lcov._generate() to reduce the visual noise of extra arguments that are required but unimportant to the task at hand. Signed-off-by: Peter Marheine --- scripts/pylib/twister/twisterlib/coverage.py | 93 ++++++++++---------- 1 file changed, 45 insertions(+), 48 deletions(-) diff --git a/scripts/pylib/twister/twisterlib/coverage.py b/scripts/pylib/twister/twisterlib/coverage.py index 0466215809d..fbc04e9c7c3 100644 --- a/scripts/pylib/twister/twisterlib/coverage.py +++ b/scripts/pylib/twister/twisterlib/coverage.py @@ -168,75 +168,72 @@ def add_ignore_file(self, pattern): def add_ignore_directory(self, pattern): self.ignores.append('*/' + pattern + '/*') - @staticmethod - def run_command(cmd, coveragelog): + @property + def is_lcov_v2(self): + return self.version.startswith("2") + + def run_command(self, cmd, coveragelog): + if self.is_lcov_v2: + # The --ignore-errors source option is added for genhtml as well as + # lcov to avoid it exiting due to + # samples/application_development/external_lib/ + cmd += [ + "--ignore-errors", "inconsistent,inconsistent", + "--ignore-errors", "negative,negative", + "--ignore-errors", "unused,unused", + "--ignore-errors", "empty,empty", + "--ignore-errors", "mismatch,mismatch", + ] + cmd_str = " ".join(cmd) logger.debug(f"Running {cmd_str}...") return subprocess.call(cmd, stdout=coveragelog) - def _generate(self, outdir, coveragelog): - coveragefile = os.path.join(outdir, "coverage.info") - ztestfile = os.path.join(outdir, "ztest.info") - if self.version.startswith("2"): + def run_lcov(self, args, coveragelog): + if self.is_lcov_v2: branch_coverage = "branch_coverage=1" - ignore_errors = [ - "--ignore-errors", "inconsistent,inconsistent", - "--ignore-errors", "negative,negative", - "--ignore-errors", "unused,unused", - "--ignore-errors", "empty,empty", - "--ignore-errors", "mismatch,mismatch" - ] else: branch_coverage = "lcov_branch_coverage=1" - ignore_errors = [] - - cmd = ["lcov", "--gcov-tool", self.gcov_tool, - "--capture", "--directory", outdir, - "--rc", branch_coverage, - "--output-file", coveragefile] - cmd = cmd + ignore_errors - self.run_command(cmd, coveragelog) - # We want to remove tests/* and tests/ztest/test/* but save tests/ztest - cmd = ["lcov", "--gcov-tool", self.gcov_tool, "--extract", - coveragefile, - os.path.join(self.base_dir, "tests", "ztest", "*"), - "--output-file", ztestfile, - "--rc", branch_coverage] - cmd = cmd + ignore_errors - self.run_command(cmd, coveragelog) + cmd = [ + "lcov", "--gcov-tool", self.gcov_tool, + "--rc", branch_coverage, + ] + args + return self.run_command(cmd, coveragelog) + + def _generate(self, outdir, coveragelog): + coveragefile = os.path.join(outdir, "coverage.info") + ztestfile = os.path.join(outdir, "ztest.info") + + cmd = ["--capture", "--directory", outdir, "--output-file", coveragefile] + self.run_lcov(cmd, coveragelog) + + # We want to remove tests/* and tests/ztest/test/* but save tests/ztest + cmd = ["--extract", coveragefile, + os.path.join(self.base_dir, "tests", "ztest", "*"), + "--output-file", ztestfile] + self.run_lcov(cmd, coveragelog) if os.path.exists(ztestfile) and os.path.getsize(ztestfile) > 0: - cmd = ["lcov", "--gcov-tool", self.gcov_tool, "--remove", - ztestfile, - os.path.join(self.base_dir, "tests/ztest/test/*"), - "--output-file", ztestfile, - "--rc", branch_coverage] - cmd = cmd + ignore_errors - self.run_command(cmd, coveragelog) + cmd = ["--remove", ztestfile, + os.path.join(self.base_dir, "tests/ztest/test/*"), + "--output-file", ztestfile] + self.run_lcov(cmd, coveragelog) files = [coveragefile, ztestfile] else: files = [coveragefile] for i in self.ignores: - cmd = ["lcov", "--gcov-tool", self.gcov_tool, "--remove", - coveragefile, i, - "--output-file", coveragefile, - "--rc", branch_coverage] - cmd = cmd + ignore_errors - self.run_command(cmd, coveragelog) + cmd = ["--remove", coveragefile, i, "--output-file", coveragefile] + self.run_lcov(cmd, coveragelog) if 'html' not in self.output_formats.split(','): return 0 - # The --ignore-errors source option is added to avoid it exiting due to - # samples/application_development/external_lib/ cmd = ["genhtml", "--legend", "--branch-coverage", - "--prefix", self.base_dir, - "-output-directory", - os.path.join(outdir, "coverage")] + files - cmd = cmd + ignore_errors + "--prefix", self.base_dir, + "-output-directory", os.path.join(outdir, "coverage")] + files return self.run_command(cmd, coveragelog) From 0a9728f87e41e2956cfd47de97c8f57e41b13aaa Mon Sep 17 00:00:00 2001 From: Peter Marheine Date: Wed, 3 Jan 2024 09:16:48 +1100 Subject: [PATCH 1763/3723] twister: support parallel coverage with lcov >=2.0 lcov 2.0 added support for processing coverage data in parallel, which provides a large speedup when processing many files, at the cost of some additional overhead. When running the Chrome EC tests with coverage, parallel reporting on a 36C72T machine reduces the time spent generating coverage reports by 40 minutes (from approximately 1 hour to 20 minutes total runtime), at the cost of about 3x greater CPU time overall (assumed to be overhead for parallel processing, likely from spawning much larger numbers of subprocesses). The level of lcov parallelism is taken from the --jobs option passed to twister, allowing lcov to choose if unspecified. Signed-off-by: Peter Marheine --- scripts/pylib/twister/twisterlib/coverage.py | 20 +++++++++++++++----- 1 file changed, 15 insertions(+), 5 deletions(-) diff --git a/scripts/pylib/twister/twisterlib/coverage.py b/scripts/pylib/twister/twisterlib/coverage.py index fbc04e9c7c3..556f5b359ba 100644 --- a/scripts/pylib/twister/twisterlib/coverage.py +++ b/scripts/pylib/twister/twisterlib/coverage.py @@ -31,9 +31,9 @@ def __init__(self): self.output_formats = None @staticmethod - def factory(tool): + def factory(tool, jobs=None): if tool == 'lcov': - t = Lcov() + t = Lcov(jobs) elif tool == 'gcovr': t = Gcovr() else: @@ -141,11 +141,12 @@ def generate(self, outdir): class Lcov(CoverageTool): - def __init__(self): + def __init__(self, jobs=None): super().__init__() self.ignores = [] self.output_formats = "lcov,html" self.version = self.get_version() + self.jobs = jobs def get_version(self): try: @@ -192,13 +193,22 @@ def run_command(self, cmd, coveragelog): def run_lcov(self, args, coveragelog): if self.is_lcov_v2: branch_coverage = "branch_coverage=1" + if self.jobs is None: + # Default: --parallel=0 will autodetect appropriate parallelism + parallel = ["--parallel", "0"] + elif self.jobs == 1: + # Serial execution requested, don't parallelize at all + parallel = [] + else: + parallel = ["--parallel", str(self.jobs)] else: branch_coverage = "lcov_branch_coverage=1" + parallel = [] cmd = [ "lcov", "--gcov-tool", self.gcov_tool, "--rc", branch_coverage, - ] + args + ] + parallel + args return self.run_command(cmd, coveragelog) def _generate(self, outdir, coveragelog): @@ -364,7 +374,7 @@ def run_coverage(testplan, options): logger.info("Generating coverage files...") logger.info(f"Using gcov tool: {gcov_tool}") - coverage_tool = CoverageTool.factory(options.coverage_tool) + coverage_tool = CoverageTool.factory(options.coverage_tool, jobs=options.jobs) coverage_tool.gcov_tool = gcov_tool coverage_tool.base_dir = os.path.abspath(options.coverage_basedir) # Apply output format default From d211284c20bc066d49dc50c5989426c9b7dd3e2c Mon Sep 17 00:00:00 2001 From: Ali Hozhabri Date: Wed, 20 Dec 2023 15:18:47 +0100 Subject: [PATCH 1764/3723] boards: arm: sensortile_box_pro: Add BLE support to SensorTile_box_pro Add BLE feature to SensorTile.box PRO board. Signed-off-by: Ali Hozhabri --- .../arm/sensortile_box_pro/Kconfig.defconfig | 18 +++++++++++++++ .../sensortile_box_pro/sensortile_box_pro.dts | 22 +++++++++++++++++-- .../sensortile_box_pro.yaml | 1 + 3 files changed, 39 insertions(+), 2 deletions(-) diff --git a/boards/arm/sensortile_box_pro/Kconfig.defconfig b/boards/arm/sensortile_box_pro/Kconfig.defconfig index e37f5e4f5bf..48b55275be3 100644 --- a/boards/arm/sensortile_box_pro/Kconfig.defconfig +++ b/boards/arm/sensortile_box_pro/Kconfig.defconfig @@ -8,6 +8,24 @@ if BOARD_SENSORTILE_BOX_PRO config BOARD default "sensortile_box_pro" +if BT + +config SPI + default y + +choice BT_HCI_BUS_TYPE + default BT_SPI +endchoice + +config BT_BLUENRG_ACI + default y + +# Disable Flow control +config BT_HCI_ACL_FLOW_CONTROL + default n + +endif # BT + config SPI_STM32_INTERRUPT default y depends on SPI diff --git a/boards/arm/sensortile_box_pro/sensortile_box_pro.dts b/boards/arm/sensortile_box_pro/sensortile_box_pro.dts index a9090366709..0a5be03e4a9 100644 --- a/boards/arm/sensortile_box_pro/sensortile_box_pro.dts +++ b/boards/arm/sensortile_box_pro/sensortile_box_pro.dts @@ -158,10 +158,28 @@ stm32_lp_tick_source: &lptim1 { }; &spi1 { - pinctrl-0 = <&spi1_nss_pe12 &spi1_sck_pe13 - &spi1_miso_pe14 &spi1_mosi_pe15>; + pinctrl-0 = <&spi1_sck_pa5 &spi1_miso_pa6 &spi1_mosi_pa7>; pinctrl-names = "default"; + cs-gpios = <&gpioa 2 GPIO_ACTIVE_LOW>; status = "okay"; + + bluenrg-lp@0 { + compatible = "zephyr,bt-hci-spi", "st,hci-spi-v2"; + reg = <0>; + irq-gpios = <&gpiod 1 (GPIO_ACTIVE_HIGH | GPIO_PULL_DOWN)>; + reset-gpios = <&gpiod 4 GPIO_ACTIVE_LOW>; + spi-cpol; + spi-cpha; + spi-hold-cs; + spi-max-frequency = ; + controller-data-delay-us = <0>; + reset-assert-duration-ms = <6>; + }; +}; + +&spi1_sck_pa5 { + /delete-property/ bias-pull-down; + bias-pull-up; /* Idle state for the clock pin is high-level due to SPI mode 3 */ }; &spi2 { diff --git a/boards/arm/sensortile_box_pro/sensortile_box_pro.yaml b/boards/arm/sensortile_box_pro/sensortile_box_pro.yaml index da81ee182e1..14624c77f7d 100644 --- a/boards/arm/sensortile_box_pro/sensortile_box_pro.yaml +++ b/boards/arm/sensortile_box_pro/sensortile_box_pro.yaml @@ -9,6 +9,7 @@ toolchain: supported: - pwm - spi + - ble - i2c - gpio - usb device From 9853bf7c983bfa4718ccddd4d89342c960282a7a Mon Sep 17 00:00:00 2001 From: Hake Huang Date: Fri, 5 Jan 2024 15:47:49 +0800 Subject: [PATCH 1765/3723] boards: doc: align board ram usage with dts settings the ram size is used in twister for case filter, so need align them with real setting. Signed-off-by: Hake Huang --- boards/arm/frdm_k64f/frdm_k64f.yaml | 2 +- boards/arm/frdm_kw41z/frdm_kw41z.yaml | 2 +- boards/arm/lpcxpresso11u68/lpcxpresso11u68.yaml | 2 ++ boards/arm/mimx8mm_evk/mimx8mm_evk.yaml | 4 ++-- boards/arm/mimx8mm_phyboard_polis/mimx8mm_phyboard_polis.yaml | 4 ++-- boards/arm/mimx8mq_evk/mimx8mq_evk_cm4.yaml | 4 ++-- boards/arm/mimxrt1010_evk/mimxrt1010_evk.yaml | 2 +- boards/arm/twr_kv58f220m/twr_kv58f220m.yaml | 2 +- 8 files changed, 12 insertions(+), 10 deletions(-) diff --git a/boards/arm/frdm_k64f/frdm_k64f.yaml b/boards/arm/frdm_k64f/frdm_k64f.yaml index a9e99911776..b4de8b219e1 100644 --- a/boards/arm/frdm_k64f/frdm_k64f.yaml +++ b/boards/arm/frdm_k64f/frdm_k64f.yaml @@ -2,7 +2,7 @@ identifier: frdm_k64f name: NXP FRDM-K64F type: mcu arch: arm -ram: 256 +ram: 192 flash: 1024 toolchain: - zephyr diff --git a/boards/arm/frdm_kw41z/frdm_kw41z.yaml b/boards/arm/frdm_kw41z/frdm_kw41z.yaml index 72c7cb4abf3..63cffff2786 100644 --- a/boards/arm/frdm_kw41z/frdm_kw41z.yaml +++ b/boards/arm/frdm_kw41z/frdm_kw41z.yaml @@ -2,7 +2,7 @@ identifier: frdm_kw41z name: NXP FRDM-KW41Z type: mcu arch: arm -ram: 128 +ram: 96 flash: 512 toolchain: - zephyr diff --git a/boards/arm/lpcxpresso11u68/lpcxpresso11u68.yaml b/boards/arm/lpcxpresso11u68/lpcxpresso11u68.yaml index e59360c084b..192ca797f62 100644 --- a/boards/arm/lpcxpresso11u68/lpcxpresso11u68.yaml +++ b/boards/arm/lpcxpresso11u68/lpcxpresso11u68.yaml @@ -2,6 +2,8 @@ identifier: lpcxpresso11u68 name: NXP LPCxpresso 11U68 type: mcu arch: arm +ram: 32 +flash: 256 toolchain: - zephyr supported: diff --git a/boards/arm/mimx8mm_evk/mimx8mm_evk.yaml b/boards/arm/mimx8mm_evk/mimx8mm_evk.yaml index 8854d16ac55..4c1779778ba 100644 --- a/boards/arm/mimx8mm_evk/mimx8mm_evk.yaml +++ b/boards/arm/mimx8mm_evk/mimx8mm_evk.yaml @@ -8,8 +8,8 @@ identifier: mimx8mm_evk name: NXP i.MX8M Mini EVK type: mcu arch: arm -ram: 32 -flash: 32 +ram: 128 +flash: 128 toolchain: - zephyr - gnuarmemb diff --git a/boards/arm/mimx8mm_phyboard_polis/mimx8mm_phyboard_polis.yaml b/boards/arm/mimx8mm_phyboard_polis/mimx8mm_phyboard_polis.yaml index ee0fd50bf5f..399336291f9 100644 --- a/boards/arm/mimx8mm_phyboard_polis/mimx8mm_phyboard_polis.yaml +++ b/boards/arm/mimx8mm_phyboard_polis/mimx8mm_phyboard_polis.yaml @@ -8,8 +8,8 @@ identifier: mimx8mm_phyboard_polis name: Phyboard Polis i.MX8M Mini type: mcu arch: arm -ram: 32 -flash: 32 +ram: 128 +flash: 128 toolchain: - zephyr - gnuarmemb diff --git a/boards/arm/mimx8mq_evk/mimx8mq_evk_cm4.yaml b/boards/arm/mimx8mq_evk/mimx8mq_evk_cm4.yaml index 580b8cef0f3..f5fee9cea2f 100644 --- a/boards/arm/mimx8mq_evk/mimx8mq_evk_cm4.yaml +++ b/boards/arm/mimx8mq_evk/mimx8mq_evk_cm4.yaml @@ -8,8 +8,8 @@ identifier: mimx8mq_evk_cm4 name: NXP i.MX8MQ EVK CM4 type: mcu arch: arm -ram: 32 -flash: 32 +ram: 128 +flash: 128 toolchain: - zephyr - gnuarmemb diff --git a/boards/arm/mimxrt1010_evk/mimxrt1010_evk.yaml b/boards/arm/mimxrt1010_evk/mimxrt1010_evk.yaml index 302b3c64d80..e611af6c798 100644 --- a/boards/arm/mimxrt1010_evk/mimxrt1010_evk.yaml +++ b/boards/arm/mimxrt1010_evk/mimxrt1010_evk.yaml @@ -13,7 +13,7 @@ toolchain: - zephyr - gnuarmemb - xtools -ram: 32 +ram: 64 flash: 16384 supported: - arduino_gpio diff --git a/boards/arm/twr_kv58f220m/twr_kv58f220m.yaml b/boards/arm/twr_kv58f220m/twr_kv58f220m.yaml index 810d96c2ae6..6118c0c0b11 100644 --- a/boards/arm/twr_kv58f220m/twr_kv58f220m.yaml +++ b/boards/arm/twr_kv58f220m/twr_kv58f220m.yaml @@ -6,7 +6,7 @@ toolchain: - zephyr - gnuarmemb - xtools -ram: 256 +ram: 128 flash: 1024 supported: - i2c From 9784bd06b6fa983d153453885a3b6469465a3a35 Mon Sep 17 00:00:00 2001 From: Jacob Siverskog Date: Fri, 5 Jan 2024 10:33:11 +0100 Subject: [PATCH 1766/3723] boards: lpcxpresso55s69: fix crystal frequency this corresponds to soc/arm/nxp_lpc/lpc55xxx/soc.c:129. also, 16MHz is used on the lpc55s69-evk. Signed-off-by: Jacob Siverskog --- boards/arm/lpcxpresso55s69/doc/index.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/boards/arm/lpcxpresso55s69/doc/index.rst b/boards/arm/lpcxpresso55s69/doc/index.rst index 408cd18aa91..d6c16095f53 100644 --- a/boards/arm/lpcxpresso55s69/doc/index.rst +++ b/boards/arm/lpcxpresso55s69/doc/index.rst @@ -256,7 +256,7 @@ Dual Core samples System Clock ============ -The LPC55S69 SoC is configured to use PLL1 clocked from the external 24MHz +The LPC55S69 SoC is configured to use PLL1 clocked from the external 16MHz crystal, running at 144MHz as a source for the system clock. When the flash controller is enabled, the core clock will be reduced to 96MHz. The application may reconfigure clocks after initialization, provided that the core clock is From c58710c6023fd30df9aa190a1e6ea360b59e34aa Mon Sep 17 00:00:00 2001 From: Alberto Escolar Piedras Date: Thu, 28 Dec 2023 12:49:16 +0100 Subject: [PATCH 1767/3723] lib/posix getopt: Fix include Let's try to use the host unistd.h when building with the host library only, instead of assuming that the native boards are always built with it. This fixes a build error when building for native boards using minimal libc. Signed-off-by: Alberto Escolar Piedras --- lib/posix/getopt/getopt.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/posix/getopt/getopt.c b/lib/posix/getopt/getopt.c index 514af721cb5..c17a0ff04c2 100644 --- a/lib/posix/getopt/getopt.c +++ b/lib/posix/getopt/getopt.c @@ -30,7 +30,7 @@ */ #include -#ifdef CONFIG_ARCH_POSIX +#ifdef CONFIG_NATIVE_LIBC #include #else #include From b802e42c6f930d94269d41432b2baed74856f4f0 Mon Sep 17 00:00:00 2001 From: Alberto Escolar Piedras Date: Wed, 3 Jan 2024 15:19:15 +0100 Subject: [PATCH 1768/3723] posix kconfig: Improve depends on host libC Improve a depends on the host libC. It is technically correct, but NATIVE_LIBC is shorter and clearer than "ARCH_POSIX && EXTERNAL_LIBC" Signed-off-by: Alberto Escolar Piedras --- lib/posix/Kconfig.clock | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/posix/Kconfig.clock b/lib/posix/Kconfig.clock index 95c88769d73..e9b83a12d0a 100644 --- a/lib/posix/Kconfig.clock +++ b/lib/posix/Kconfig.clock @@ -5,7 +5,7 @@ config POSIX_CLOCK bool "POSIX clock, timer, and sleep APIs" default y if POSIX_API - depends on !(ARCH_POSIX && EXTERNAL_LIBC) + depends on !NATIVE_LIBC help This enables POSIX clock\_\*(), timer\_\*(), and \*sleep() functions. From 6140948ffb4829ab9577bad1120c94712fba91d3 Mon Sep 17 00:00:00 2001 From: Lukasz Mrugala Date: Thu, 7 Dec 2023 13:56:38 +0000 Subject: [PATCH 1769/3723] scripts: tests: twister: TestInstance tests refactor Prepares the test_testinstance.py for expansion of its tests Signed-off-by: Lukasz Mrugala --- scripts/tests/twister/test_testinstance.py | 111 ++++++++++++++++----- 1 file changed, 87 insertions(+), 24 deletions(-) diff --git a/scripts/tests/twister/test_testinstance.py b/scripts/tests/twister/test_testinstance.py index 73a3c8f7dfb..d0de7060225 100644 --- a/scripts/tests/twister/test_testinstance.py +++ b/scripts/tests/twister/test_testinstance.py @@ -15,13 +15,14 @@ ZEPHYR_BASE = os.getenv("ZEPHYR_BASE") sys.path.insert(0, os.path.join(ZEPHYR_BASE, "scripts/pylib/twister")) + from twisterlib.testinstance import TestInstance from twisterlib.error import BuildError from twisterlib.runner import TwisterRunner from expr_parser import reserved -TESTDATA_1 = [ +TESTDATA_PART_1 = [ (False, False, "console", "na", "qemu", False, [], (False, True)), (False, False, "console", "native", "qemu", False, [], (False, True)), (True, False, "console", "native", "nsim", False, [], (True, False)), @@ -30,14 +31,30 @@ (False, False, "sensor", "na", "", False, [], (True, False)), (False, True, "sensor", "native", "", True, [], (True, False)), ] -@pytest.mark.parametrize("build_only, slow, harness, platform_type, platform_sim, device_testing,fixture, expected", TESTDATA_1) -def test_check_build_or_run(class_testplan, all_testsuites_dict, platforms_list, build_only, slow, harness, platform_type, platform_sim, device_testing, fixture, expected): +@pytest.mark.parametrize( + "build_only, slow, harness, platform_type, platform_sim, device_testing,fixture, expected", + TESTDATA_PART_1 +) +def test_check_build_or_run( + class_testplan, + all_testsuites_dict, + platforms_list, + build_only, + slow, + harness, + platform_type, + platform_sim, + device_testing, + fixture, + expected +): """" Test to check the conditions for build_only and run scenarios Scenario 1: Test when different parameters are passed, build_only and run are set correctly Scenario 2: Test if build_only is enabled when the OS is Windows""" class_testplan.testsuites = all_testsuites_dict - testsuite = class_testplan.testsuites.get('scripts/tests/twister/test_data/testsuites/tests/test_a/test_a.check_1') + testsuite = class_testplan.testsuites.get('scripts/tests/twister/test_data/testsuites/tests/' + 'test_a/test_a.check_1') print(testsuite) class_testplan.platforms = platforms_list @@ -57,27 +74,52 @@ def test_check_build_or_run(class_testplan, all_testsuites_dict, platforms_list, run = testinstance.check_runnable() assert not run -TESTDATA_2 = [ - (True, True, True, ["demo_board_2"], "native", None, '\nCONFIG_COVERAGE=y\nCONFIG_COVERAGE_DUMP=y\nCONFIG_ASAN=y\nCONFIG_UBSAN=y'), - (True, False, True, ["demo_board_2"], "native", None, '\nCONFIG_COVERAGE=y\nCONFIG_COVERAGE_DUMP=y\nCONFIG_ASAN=y'), - (False, False, True, ["demo_board_2"], 'native', None, '\nCONFIG_COVERAGE=y\nCONFIG_COVERAGE_DUMP=y'), - (True, False, True, ["demo_board_2"], 'mcu', None, '\nCONFIG_COVERAGE=y\nCONFIG_COVERAGE_DUMP=y'), +TESTDATA_PART_2 = [ + (True, True, True, ["demo_board_2"], "native", + None, '\nCONFIG_COVERAGE=y\nCONFIG_COVERAGE_DUMP=y\nCONFIG_ASAN=y\nCONFIG_UBSAN=y'), + (True, False, True, ["demo_board_2"], "native", + None, '\nCONFIG_COVERAGE=y\nCONFIG_COVERAGE_DUMP=y\nCONFIG_ASAN=y'), + (False, False, True, ["demo_board_2"], 'native', + None, '\nCONFIG_COVERAGE=y\nCONFIG_COVERAGE_DUMP=y'), + (True, False, True, ["demo_board_2"], 'mcu', + None, '\nCONFIG_COVERAGE=y\nCONFIG_COVERAGE_DUMP=y'), (False, False, False, ["demo_board_2"], 'native', None, ''), (False, False, True, ['demo_board_1'], 'native', None, ''), (True, False, False, ["demo_board_2"], 'native', None, '\nCONFIG_ASAN=y'), (False, True, False, ["demo_board_2"], 'native', None, '\nCONFIG_UBSAN=y'), - (False, False, False, ["demo_board_2"], 'native', ["CONFIG_LOG=y"], 'CONFIG_LOG=y'), - (False, False, False, ["demo_board_2"], 'native', ["arch:x86_demo:CONFIG_LOG=y"], 'CONFIG_LOG=y'), - (False, False, False, ["demo_board_2"], 'native', ["arch:arm_demo:CONFIG_LOG=y"], ''), - (False, False, False, ["demo_board_2"], 'native', ["platform:demo_board_2:CONFIG_LOG=y"], 'CONFIG_LOG=y'), - (False, False, False, ["demo_board_2"], 'native', ["platform:demo_board_1:CONFIG_LOG=y"], ''), + (False, False, False, ["demo_board_2"], 'native', + ["CONFIG_LOG=y"], 'CONFIG_LOG=y'), + (False, False, False, ["demo_board_2"], 'native', + ["arch:x86_demo:CONFIG_LOG=y"], 'CONFIG_LOG=y'), + (False, False, False, ["demo_board_2"], 'native', + ["arch:arm_demo:CONFIG_LOG=y"], ''), + (False, False, False, ["demo_board_2"], 'native', + ["platform:demo_board_2:CONFIG_LOG=y"], 'CONFIG_LOG=y'), + (False, False, False, ["demo_board_2"], 'native', + ["platform:demo_board_1:CONFIG_LOG=y"], ''), ] -@pytest.mark.parametrize("enable_asan, enable_ubsan, enable_coverage, coverage_platform, platform_type, extra_configs, expected_content", TESTDATA_2) -def test_create_overlay(class_testplan, all_testsuites_dict, platforms_list, enable_asan, enable_ubsan, enable_coverage, coverage_platform, platform_type, extra_configs, expected_content): +@pytest.mark.parametrize( + 'enable_asan, enable_ubsan, enable_coverage, coverage_platform, platform_type,' + ' extra_configs, expected_content', + TESTDATA_PART_2 +) +def test_create_overlay( + class_testplan, + all_testsuites_dict, + platforms_list, + enable_asan, + enable_ubsan, + enable_coverage, + coverage_platform, + platform_type, + extra_configs, + expected_content +): """Test correct content is written to testcase_extra.conf based on if conditions.""" class_testplan.testsuites = all_testsuites_dict - testcase = class_testplan.testsuites.get('scripts/tests/twister/test_data/testsuites/samples/test_app/sample_test.app') + testcase = class_testplan.testsuites.get('scripts/tests/twister/test_data/testsuites/samples/' + 'test_app/sample_test.app') if extra_configs: testcase.extra_configs = extra_configs @@ -92,7 +134,8 @@ def test_create_overlay(class_testplan, all_testsuites_dict, platforms_list, ena def test_calculate_sizes(class_testplan, all_testsuites_dict, platforms_list): """ Test Calculate sizes method for zephyr elf""" class_testplan.testsuites = all_testsuites_dict - testcase = class_testplan.testsuites.get('scripts/tests/twister/test_data/testsuites/samples/test_app/sample_test.app') + testcase = class_testplan.testsuites.get('scripts/tests/twister/test_data/testsuites/samples/' + 'test_app/sample_test.app') class_testplan.platforms = platforms_list platform = class_testplan.get_platform("demo_board_2") testinstance = TestInstance(testcase, platform, class_testplan.env.outdir) @@ -100,14 +143,34 @@ def test_calculate_sizes(class_testplan, all_testsuites_dict, platforms_list): with pytest.raises(BuildError): assert testinstance.calculate_sizes() == "Missing/multiple output ELF binary" -TESTDATA_3 = [ - ('CONFIG_ARCH_HAS_THREAD_LOCAL_STORAGE and CONFIG_TOOLCHAIN_SUPPORTS_THREAD_LOCAL_STORAGE and not (CONFIG_TOOLCHAIN_ARCMWDT_SUPPORTS_THREAD_LOCAL_STORAGE and CONFIG_USERSPACE)', ['kconfig']), - ('(dt_compat_enabled("st,stm32-flash-controller") or dt_compat_enabled("st,stm32h7-flash-controller")) and dt_label_with_parent_compat_enabled("storage_partition", "fixed-partitions")', ['dts']), - ('((CONFIG_FLASH_HAS_DRIVER_ENABLED and not CONFIG_TRUSTED_EXECUTION_NONSECURE) and dt_label_with_parent_compat_enabled("storage_partition", "fixed-partitions")) or (CONFIG_FLASH_HAS_DRIVER_ENABLED and CONFIG_TRUSTED_EXECUTION_NONSECURE and dt_label_with_parent_compat_enabled("slot1_ns_partition", "fixed-partitions"))', ['dts', 'kconfig']), - ('((CONFIG_CPU_AARCH32_CORTEX_R or CONFIG_CPU_CORTEX_M) and CONFIG_CPU_HAS_FPU and TOOLCHAIN_HAS_NEWLIB == 1) or CONFIG_ARCH_POSIX', ['full']) +TESTDATA_PART_3 = [ + ( + 'CONFIG_ARCH_HAS_THREAD_LOCAL_STORAGE and' \ + ' CONFIG_TOOLCHAIN_SUPPORTS_THREAD_LOCAL_STORAGE and' \ + ' not (CONFIG_TOOLCHAIN_ARCMWDT_SUPPORTS_THREAD_LOCAL_STORAGE and CONFIG_USERSPACE)', + ['kconfig'] + ), + ( + '(dt_compat_enabled("st,stm32-flash-controller") or' \ + ' dt_compat_enabled("st,stm32h7-flash-controller")) and' \ + ' dt_label_with_parent_compat_enabled("storage_partition", "fixed-partitions")', + ['dts'] + ), + ( + '((CONFIG_FLASH_HAS_DRIVER_ENABLED and not CONFIG_TRUSTED_EXECUTION_NONSECURE) and' \ + ' dt_label_with_parent_compat_enabled("storage_partition", "fixed-partitions")) or' \ + ' (CONFIG_FLASH_HAS_DRIVER_ENABLED and CONFIG_TRUSTED_EXECUTION_NONSECURE and' \ + ' dt_label_with_parent_compat_enabled("slot1_ns_partition", "fixed-partitions"))', + ['dts', 'kconfig'] + ), + ( + '((CONFIG_CPU_AARCH32_CORTEX_R or CONFIG_CPU_CORTEX_M) and' \ + ' CONFIG_CPU_HAS_FPU and TOOLCHAIN_HAS_NEWLIB == 1) or CONFIG_ARCH_POSIX', + ['full'] + ) ] -@pytest.mark.parametrize("filter_expr, expected_stages", TESTDATA_3) +@pytest.mark.parametrize("filter_expr, expected_stages", TESTDATA_PART_3) def test_which_filter_stages(filter_expr, expected_stages): logic_keys = reserved.keys() stages = TwisterRunner.get_cmake_filter_stages(filter_expr, logic_keys) From 3b8a326dc0f09336c4dd04623906e4e36bb2a22c Mon Sep 17 00:00:00 2001 From: Lukasz Mrugala Date: Thu, 7 Dec 2023 15:04:18 +0000 Subject: [PATCH 1770/3723] scripts: tests: twister: TestInstance test expansion TestInstance unit tests were added. The module is now 100% covered by them. Signed-off-by: Lukasz Mrugala --- scripts/tests/twister/test_testinstance.py | 422 ++++++++++++++++++++- 1 file changed, 420 insertions(+), 2 deletions(-) diff --git a/scripts/tests/twister/test_testinstance.py b/scripts/tests/twister/test_testinstance.py index d0de7060225..52c51b2b278 100644 --- a/scripts/tests/twister/test_testinstance.py +++ b/scripts/tests/twister/test_testinstance.py @@ -7,11 +7,11 @@ Tests for testinstance class """ +from contextlib import nullcontext import os import sys import pytest - -from unittest import mock +import mock ZEPHYR_BASE = os.getenv("ZEPHYR_BASE") sys.path.insert(0, os.path.join(ZEPHYR_BASE, "scripts/pylib/twister")) @@ -19,6 +19,7 @@ from twisterlib.testinstance import TestInstance from twisterlib.error import BuildError from twisterlib.runner import TwisterRunner +from twisterlib.handlers import QEMUHandler from expr_parser import reserved @@ -175,3 +176,420 @@ def test_which_filter_stages(filter_expr, expected_stages): logic_keys = reserved.keys() stages = TwisterRunner.get_cmake_filter_stages(filter_expr, logic_keys) assert sorted(stages) == sorted(expected_stages) + + +@pytest.fixture(name='testinstance') +def sample_testinstance(all_testsuites_dict, class_testplan, platforms_list, request): + testsuite_path = 'scripts/tests/twister/test_data/testsuites' + if request.param['testsuite_kind'] == 'sample': + testsuite_path += '/samples/test_app/sample_test.app' + elif request.param['testsuite_kind'] == 'tests': + testsuite_path += '/tests/test_a/test_a.check_1' + + class_testplan.testsuites = all_testsuites_dict + testsuite = class_testplan.testsuites.get(testsuite_path) + class_testplan.platforms = platforms_list + platform = class_testplan.get_platform(request.param.get('board_name', 'demo_board_2')) + + testinstance = TestInstance(testsuite, platform, class_testplan.env.outdir) + return testinstance + + +TESTDATA_1 = [ + (False), + (True), +] + +@pytest.mark.parametrize('detailed_test_id', TESTDATA_1) +def test_testinstance_init(all_testsuites_dict, class_testplan, platforms_list, detailed_test_id): + testsuite_path = 'scripts/tests/twister/test_data/testsuites/samples/test_app/sample_test.app' + class_testplan.testsuites = all_testsuites_dict + testsuite = class_testplan.testsuites.get(testsuite_path) + testsuite.detailed_test_id = detailed_test_id + class_testplan.platforms = platforms_list + platform = class_testplan.get_platform("demo_board_2") + + testinstance = TestInstance(testsuite, platform, class_testplan.env.outdir) + + if detailed_test_id: + assert testinstance.build_dir == os.path.join(class_testplan.env.outdir, platform.name, testsuite_path) + else: + assert testinstance.build_dir == os.path.join(class_testplan.env.outdir, platform.name, testsuite.source_dir_rel, testsuite.name) + + +@pytest.mark.parametrize('testinstance', [{'testsuite_kind': 'sample'}], indirect=True) +def test_testinstance_add_filter(testinstance): + reason = 'dummy reason' + filter_type = 'dummy type' + + testinstance.add_filter(reason, filter_type) + + assert {'type': filter_type, 'reason': reason} in testinstance.filters + assert testinstance.status == 'filtered' + assert testinstance.reason == reason + assert testinstance.filter_type == filter_type + + +def test_testinstance_init_cases(all_testsuites_dict, class_testplan, platforms_list): + testsuite_path = 'scripts/tests/twister/test_data/testsuites/tests/test_a/test_a.check_1' + class_testplan.testsuites = all_testsuites_dict + testsuite = class_testplan.testsuites.get(testsuite_path) + class_testplan.platforms = platforms_list + platform = class_testplan.get_platform("demo_board_2") + + testinstance = TestInstance(testsuite, platform, class_testplan.env.outdir) + + testinstance.init_cases() + + assert all( + [ + any( + [ + tcc.name == tc.name and tcc.freeform == tc.freeform \ + for tcc in testinstance.testsuite.testcases + ] + ) for tc in testsuite.testcases + ] + ) + + +@pytest.mark.parametrize('testinstance', [{'testsuite_kind': 'sample'}], indirect=True) +def test_testinstance_get_run_id(testinstance): + res = testinstance._get_run_id() + + assert isinstance(res, str) + + +TESTDATA_2 = [ + ('another reason', 'another reason'), + (None, 'dummy reason'), +] + +@pytest.mark.parametrize('reason, expected_reason', TESTDATA_2) +@pytest.mark.parametrize('testinstance', [{'testsuite_kind': 'tests'}], indirect=True) +def test_testinstance_add_missing_case_status(testinstance, reason, expected_reason): + testinstance.reason = 'dummy reason' + + status = 'passed' + + assert len(testinstance.testcases) > 1, 'Selected testsuite does not have enough testcases.' + + testinstance.testcases[0].status = 'started' + testinstance.testcases[-1].status = None + + testinstance.add_missing_case_status(status, reason) + + assert testinstance.testcases[0].status == 'failed' + assert testinstance.testcases[-1].status == 'passed' + assert testinstance.testcases[-1].reason == expected_reason + + +def test_testinstance_dunders(all_testsuites_dict, class_testplan, platforms_list): + testsuite_path = 'scripts/tests/twister/test_data/testsuites/samples/test_app/sample_test.app' + class_testplan.testsuites = all_testsuites_dict + testsuite = class_testplan.testsuites.get(testsuite_path) + class_testplan.platforms = platforms_list + platform = class_testplan.get_platform("demo_board_2") + + testinstance = TestInstance(testsuite, platform, class_testplan.env.outdir) + testinstance_copy = TestInstance(testsuite, platform, class_testplan.env.outdir) + + d = testinstance.__getstate__() + + d['name'] = 'dummy name' + testinstance_copy.__setstate__(d) + + d['name'] = 'another name' + testinstance.__setstate__(d) + + assert testinstance < testinstance_copy + + testinstance_copy.__setstate__(d) + + assert not testinstance < testinstance_copy + assert not testinstance_copy < testinstance + + assert testinstance.__repr__() == f'' + + +@pytest.mark.parametrize('testinstance', [{'testsuite_kind': 'tests'}], indirect=True) +def test_testinstance_set_case_status_by_name(testinstance): + name = 'test_a.check_1.2a' + status = 'dummy status' + reason = 'dummy reason' + + tc = testinstance.set_case_status_by_name(name, status, reason) + + assert tc.name == name + assert tc.status == status + assert tc.reason == reason + + tc = testinstance.set_case_status_by_name(name, status, None) + + assert tc.reason == reason + + +@pytest.mark.parametrize('testinstance', [{'testsuite_kind': 'tests'}], indirect=True) +def test_testinstance_add_testcase(testinstance): + name = 'test_a.check_1.3a' + freeform = True + + tc = testinstance.add_testcase(name, freeform) + + assert tc in testinstance.testcases + + +@pytest.mark.parametrize('testinstance', [{'testsuite_kind': 'tests'}], indirect=True) +def test_testinstance_get_case_by_name(testinstance): + name = 'test_a.check_1.2a' + + tc = testinstance.get_case_by_name(name) + + assert tc.name == name + + name = 'test_a.check_1.3a' + + tc = testinstance.get_case_by_name(name) + + assert tc is None + + +@pytest.mark.parametrize('testinstance', [{'testsuite_kind': 'tests'}], indirect=True) +def test_testinstance_get_case_or_create(caplog, testinstance): + name = 'test_a.check_1.2a' + + tc = testinstance.get_case_or_create(name) + + assert tc.name == name + + name = 'test_a.check_1.3a' + + tc = testinstance.get_case_or_create(name) + + assert tc.name == name + assert 'Could not find a matching testcase for test_a.check_1.3a' in caplog.text + + +TESTDATA_3 = [ + (None, 'nonexistent harness', False), + ('nonexistent fixture', 'console', False), + (None, 'console', True), + ('dummy fixture', 'console', True), +] + +@pytest.mark.parametrize( + 'fixture, harness, expected_can_run', + TESTDATA_3, + ids=['improper harness', 'fixture not in list', 'no fixture specified', 'fixture in list'] +) +def test_testinstance_testsuite_runnable( + all_testsuites_dict, + class_testplan, + fixture, + harness, + expected_can_run +): + testsuite_path = 'scripts/tests/twister/test_data/testsuites/samples/test_app/sample_test.app' + class_testplan.testsuites = all_testsuites_dict + testsuite = class_testplan.testsuites.get(testsuite_path) + + testsuite.harness = harness + testsuite.harness_config['fixture'] = fixture + + fixtures = ['dummy fixture'] + + can_run = TestInstance.testsuite_runnable(testsuite, fixtures)\ + + assert can_run == expected_can_run + + +TESTDATA_4 = [ + (True, mock.ANY, mock.ANY, mock.ANY, None, [], False), + (False, True, mock.ANY, mock.ANY, 'device', [], True), + (False, False, 'qemu', mock.ANY, 'qemu', ['QEMU_PIPE=1'], True), + (False, False, 'dummy sim', mock.ANY, 'dummy sim', [], True), + (False, False, 'na', 'unit', 'unit', ['COVERAGE=1'], True), + (False, False, 'na', 'dummy type', '', [], False), +] + +@pytest.mark.parametrize( + 'preexisting_handler, device_testing, platform_sim, testsuite_type,' \ + ' expected_handler_type, expected_handler_args, expected_handler_ready', + TESTDATA_4, + ids=['preexisting handler', 'device testing', 'qemu simulation', + 'non-qemu simulation with exec', 'unit teting', 'no handler'] +) +@pytest.mark.parametrize('testinstance', [{'testsuite_kind': 'tests'}], indirect=True) +def test_testinstance_setup_handler( + testinstance, + preexisting_handler, + device_testing, + platform_sim, + testsuite_type, + expected_handler_type, + expected_handler_args, + expected_handler_ready +): + testinstance.handler = mock.Mock() if preexisting_handler else None + testinstance.platform.simulation = platform_sim + testinstance.platform.simulation_exec = 'dummy exec' + testinstance.testsuite.type = testsuite_type + env = mock.Mock( + options=mock.Mock( + device_testing=device_testing, + enable_coverage=True + ) + ) + + with mock.patch.object(QEMUHandler, 'get_fifo', return_value=1), \ + mock.patch('shutil.which', return_value=True): + testinstance.setup_handler(env) + + if expected_handler_type: + assert testinstance.handler.type_str == expected_handler_type + assert testinstance.handler.ready == expected_handler_ready + assert all([arg in testinstance.handler.args for arg in expected_handler_args]) + + +TESTDATA_5 = [ + ('nt', 'renode', mock.ANY, mock.ANY, + mock.ANY, mock.ANY, mock.ANY, + mock.ANY, mock.ANY, mock.ANY, mock.ANY, False), + ('linux', mock.ANY, mock.ANY, mock.ANY, + True, mock.ANY, mock.ANY, + mock.ANY, mock.ANY, mock.ANY, mock.ANY, False), + ('linux', mock.ANY, mock.ANY, mock.ANY, + False, True, mock.ANY, + False, mock.ANY, mock.ANY, mock.ANY, False), + ('linux', 'qemu', mock.ANY, mock.ANY, + False, mock.ANY, 'pytest', + mock.ANY, 'not runnable', mock.ANY, None, True), + ('linux', 'renode', 'renode', True, + False, mock.ANY, 'console', + mock.ANY, 'not runnable', [], None, True), + ('linux', 'renode', 'renode', False, + False, mock.ANY, 'not pytest', + mock.ANY, 'not runnable', mock.ANY, None, False), + ('linux', 'qemu', mock.ANY, mock.ANY, + False, mock.ANY, 'console', + mock.ANY, 'not runnable', ['?'], mock.Mock(duts=[mock.Mock(platform='demo_board_2', fixtures=[])]), True), +] + +@pytest.mark.parametrize( + 'os_name, platform_sim, platform_sim_exec, exec_exists,' \ + ' testsuite_build_only, testsuite_slow, testsuite_harness,' \ + ' enable_slow, filter, fixtures, hardware_map, expected', + TESTDATA_5, + ids=['windows', 'build only', 'skip slow', 'pytest harness', 'sim', 'no sim', 'hardware map'] +) +@pytest.mark.parametrize('testinstance', [{'testsuite_kind': 'tests'}], indirect=True) +def test_testinstance_check_runnable( + testinstance, + os_name, + platform_sim, + platform_sim_exec, + exec_exists, + testsuite_build_only, + testsuite_slow, + testsuite_harness, + enable_slow, + filter, + fixtures, + hardware_map, + expected +): + testinstance.platform.simulation = platform_sim + testinstance.platform.simulation_exec = platform_sim_exec + testinstance.testsuite.build_only = testsuite_build_only + testinstance.testsuite.slow = testsuite_slow + testinstance.testsuite.harness = testsuite_harness + + with mock.patch('os.name', os_name), \ + mock.patch('shutil.which', return_value=exec_exists): + res = testinstance.check_runnable(enable_slow, filter, fixtures, hardware_map) + + assert res == expected + + +TESTDATA_6 = [ + (True, 'build.log'), + (False, ''), +] + +@pytest.mark.parametrize('from_buildlog, expected_buildlog_filepath', TESTDATA_6) +@pytest.mark.parametrize('testinstance', [{'testsuite_kind': 'tests'}], indirect=True) +def test_testinstance_calculate_sizes(testinstance, from_buildlog, expected_buildlog_filepath): + expected_elf_filepath = 'dummy.elf' + expected_extra_sections = [] + expected_warning = True + testinstance.get_elf_file = mock.Mock(return_value='dummy.elf') + testinstance.get_buildlog_file = mock.Mock(return_value='build.log') + + sc_mock = mock.Mock() + mock_sc = mock.Mock(return_value=sc_mock) + + with mock.patch('twisterlib.testinstance.SizeCalculator', mock_sc): + res = testinstance.calculate_sizes(from_buildlog, expected_warning) + + assert res == sc_mock + mock_sc.assert_called_once_with( + elf_filename=expected_elf_filepath, + extra_sections=expected_extra_sections, + buildlog_filepath=expected_buildlog_filepath, + generate_warning=expected_warning + ) + + +TESTDATA_7 = [ + (True, None), + (False, BuildError), +] + +@pytest.mark.parametrize('sysbuild, expected_error', TESTDATA_7) +@pytest.mark.parametrize('testinstance', [{'testsuite_kind': 'tests'}], indirect=True) +def test_testinstance_get_elf_file(caplog, tmp_path, testinstance, sysbuild, expected_error): + sysbuild_dir = tmp_path / 'sysbuild' + sysbuild_dir.mkdir() + zephyr_dir = sysbuild_dir / 'zephyr' + zephyr_dir.mkdir() + sysbuild_elf = zephyr_dir / 'dummy.elf' + sysbuild_elf.write_bytes(b'0') + sysbuild_elf2 = zephyr_dir / 'dummy2.elf' + sysbuild_elf2.write_bytes(b'0') + + testinstance.testsuite.sysbuild = sysbuild + testinstance.domains = mock.Mock( + get_default_domain=mock.Mock( + return_value=mock.Mock( + build_dir=sysbuild_dir + ) + ) + ) + + with pytest.raises(expected_error) if expected_error else nullcontext(): + testinstance.get_elf_file() + + if expected_error is None: + assert 'multiple ELF files detected: ' in caplog.text + + +TESTDATA_8 = [ + (True, None), + (False, BuildError), +] + +@pytest.mark.parametrize('create_build_log, expected_error', TESTDATA_8) +@pytest.mark.parametrize('testinstance', [{'testsuite_kind': 'tests'}], indirect=True) +def test_testinstance_get_buildlog_file(tmp_path, testinstance, create_build_log, expected_error): + if create_build_log: + build_dir = tmp_path / 'build' + build_dir.mkdir() + build_log = build_dir / 'build.log' + build_log.write_text('') + testinstance.build_dir = build_dir + + with pytest.raises(expected_error) if expected_error else nullcontext(): + res = testinstance.get_buildlog_file() + + if expected_error is None: + assert res == str(build_log) From 8ce15abb60838afe34481688b8eb41cd70f819dd Mon Sep 17 00:00:00 2001 From: Lukasz Mrugala Date: Mon, 4 Dec 2023 14:42:13 +0000 Subject: [PATCH 1771/3723] scripts: tests: twister: TestPlan unit test refactoring TestPlan test file renamed and shortened before expansion. Signed-off-by: Lukasz Mrugala --- ...est_testplan_class.py => test_testplan.py} | 104 ++++++++---------- 1 file changed, 44 insertions(+), 60 deletions(-) rename scripts/tests/twister/{test_testplan_class.py => test_testplan.py} (83%) diff --git a/scripts/tests/twister/test_testplan_class.py b/scripts/tests/twister/test_testplan.py similarity index 83% rename from scripts/tests/twister/test_testplan_class.py rename to scripts/tests/twister/test_testplan.py index f825bc82710..e3a02404def 100644 --- a/scripts/tests/twister/test_testplan_class.py +++ b/scripts/tests/twister/test_testplan.py @@ -4,7 +4,7 @@ # SPDX-License-Identifier: Apache-2.0 ''' -This test file contains testsuites for Testsuite class of twister +This test file contains testsuites for testsuite.py module of twister ''' import sys import os @@ -20,7 +20,7 @@ from twisterlib.quarantine import Quarantine -def test_testplan_add_testsuites(class_testplan): +def test_testplan_add_testsuites_short(class_testplan): """ Testing add_testcase function of Testsuite class in twister """ # Test 1: Check the list of testsuites after calling add testsuites function is as expected class_testplan.SAMPLE_FILENAME = 'test_sample_app.yaml' @@ -49,7 +49,7 @@ def test_testplan_add_testsuites(class_testplan): assert all(isinstance(n, TestSuite) for n in class_testplan.testsuites.values()) @pytest.mark.parametrize("board_root_dir", [("board_config_file_not_exist"), ("board_config")]) -def test_add_configurations(test_data, class_env, board_root_dir): +def test_add_configurations_short(test_data, class_env, board_root_dir): """ Testing add_configurations function of TestPlan class in Twister Test : Asserting on default platforms list """ @@ -64,7 +64,7 @@ def test_add_configurations(test_data, class_env, board_root_dir): assert sorted(plan.default_platforms) != sorted(['demo_board_1']) -def test_get_all_testsuites(class_testplan, all_testsuites_dict): +def test_get_all_testsuites_short(class_testplan, all_testsuites_dict): """ Testing get_all_testsuites function of TestPlan class in Twister """ plan = class_testplan plan.testsuites = all_testsuites_dict @@ -81,11 +81,10 @@ def test_get_all_testsuites(class_testplan, all_testsuites_dict): 'test_d.check_1.unit_1b', 'test_e.check_1.1a', 'test_e.check_1.1b', 'test_config.main'] - print(sorted(plan.get_all_tests())) - print(sorted(expected_tests)) + assert sorted(plan.get_all_tests()) == sorted(expected_tests) -def test_get_platforms(class_testplan, platforms_list): +def test_get_platforms_short(class_testplan, platforms_list): """ Testing get_platforms function of TestPlan class in Twister """ plan = class_testplan plan.platforms = platforms_list @@ -241,7 +240,7 @@ def test_apply_filters_part3(class_testplan, all_testsuites_dict, platforms_list filtered_instances = list(filter(lambda item: item.status == "filtered", class_testplan.instances.values())) assert not filtered_instances -def test_add_instances(test_data, class_env, all_testsuites_dict, platforms_list): +def test_add_instances_short(test_data, class_env, all_testsuites_dict, platforms_list): """ Testing add_instances() function of TestPlan class in Twister Test 1: instances dictionary keys have expected values (Platform Name + Testcase Name) Test 2: Values of 'instances' dictionary in Testsuite class are an @@ -311,7 +310,7 @@ def test_add_instances(test_data, class_env, all_testsuites_dict, platforms_list 'multifiles', 'empty' ]) -def test_quarantine(class_testplan, platforms_list, test_data, +def test_quarantine_short(class_testplan, platforms_list, test_data, quarantine_files, quarantine_verify, expected_val): """ Testing quarantine feature in Twister """ @@ -336,72 +335,57 @@ def test_quarantine(class_testplan, platforms_list, test_data, assert instance.status == 'filtered' assert instance.reason == "Not under quarantine" else: - print(testname) if testname in expected_val: assert instance.status == 'filtered' assert instance.reason == "Quarantine: " + expected_val[testname] else: assert not instance.status -def test_required_snippets_app(class_testplan, all_testsuites_dict, platforms_list): - """ Testing required_snippets function of TestPlan class in Twister - Ensure that app snippets work and are only applied to boards that support the snippet - """ - plan = class_testplan - testsuite = class_testplan.testsuites.get('scripts/tests/twister/test_data/testsuites/tests/test_d/test_d.check_1') - plan.platforms = platforms_list - plan.platform_names = [p.name for p in platforms_list] - plan.testsuites = {'scripts/tests/twister/test_data/testsuites/tests/test_d/test_d.check_1': testsuite} - - for _, testcase in plan.testsuites.items(): - testcase.exclude_platform = [] - testcase.required_snippets = ['dummy'] - testcase.build_on_all = True - - plan.apply_filters() - - filtered_instances = list(filter(lambda item: item.status == "filtered", plan.instances.values())) - for d in filtered_instances: - assert d.reason == "Snippet not supported" -def test_required_snippets_global(class_testplan, all_testsuites_dict, platforms_list): - """ Testing required_snippets function of TestPlan class in Twister - Ensure that global snippets work and application does not fail - """ - plan = class_testplan - testsuite = class_testplan.testsuites.get('scripts/tests/twister/test_data/testsuites/tests/test_c/test_c.check_1') - plan.platforms = platforms_list - plan.platform_names = [p.name for p in platforms_list] - plan.testsuites = {'scripts/tests/twister/test_data/testsuites/tests/test_c/test_c.check_1': testsuite} - - for _, testcase in plan.testsuites.items(): - testcase.exclude_platform = [] - testcase.required_snippets = ['cdc-acm-console'] - testcase.build_on_all = True - - plan.apply_filters() - - filtered_instances = list(filter(lambda item: item.status == "filtered", plan.instances.values())) - assert len(filtered_instances) == 0 +TESTDATA_PART4 = [ + (os.path.join('test_d', 'test_d.check_1'), ['dummy'], + None, 'Snippet not supported'), + (os.path.join('test_c', 'test_c.check_1'), ['cdc-acm-console'], + 0, None), + (os.path.join('test_d', 'test_d.check_1'), ['dummy', 'cdc-acm-console'], + 2, 'Snippet not supported'), +] -def test_required_snippets_multiple(class_testplan, all_testsuites_dict, platforms_list): - """ Testing required_snippets function of TestPlan class in Twister - Ensure that multiple snippets can be used and are applied - """ +@pytest.mark.parametrize( + 'testpath, required_snippets, expected_filtered_len, expected_filtered_reason', + TESTDATA_PART4, + ids=['app', 'global', 'multiple'] +) +def test_required_snippets_short( + class_testplan, + all_testsuites_dict, + platforms_list, + testpath, + required_snippets, + expected_filtered_len, + expected_filtered_reason +): + """ Testing required_snippets function of TestPlan class in Twister """ plan = class_testplan - testsuite = class_testplan.testsuites.get('scripts/tests/twister/test_data/testsuites/tests/test_d/test_d.check_1') + testpath = os.path.join('scripts', 'tests', 'twister', 'test_data', + 'testsuites', 'tests', testpath) + testsuite = class_testplan.testsuites.get(testpath) plan.platforms = platforms_list plan.platform_names = [p.name for p in platforms_list] - plan.testsuites = {'scripts/tests/twister/test_data/testsuites/tests/test_d/test_d.check_1': testsuite} + plan.testsuites = {testpath: testsuite} for _, testcase in plan.testsuites.items(): testcase.exclude_platform = [] - testcase.required_snippets = ['dummy', 'cdc-acm-console'] + testcase.required_snippets = required_snippets testcase.build_on_all = True plan.apply_filters() - filtered_instances = list(filter(lambda item: item.status == "filtered", plan.instances.values())) - assert len(filtered_instances) == 2 - for d in filtered_instances: - assert d.reason == "Snippet not supported" + filtered_instances = list( + filter(lambda item: item.status == "filtered", plan.instances.values()) + ) + if expected_filtered_len is not None: + assert len(filtered_instances) == expected_filtered_len + if expected_filtered_reason is not None: + for d in filtered_instances: + assert d.reason == expected_filtered_reason From 56625fc88763855338f750a843672c5584861c87 Mon Sep 17 00:00:00 2001 From: Lukasz Mrugala Date: Mon, 4 Dec 2023 16:30:57 +0000 Subject: [PATCH 1772/3723] scripts: tests: twister: Testplan unit test expansion All functions/methods except apply_filters() covered explicitely. 86% coverage achieved. Signed-off-by: Lukasz Mrugala --- scripts/tests/twister/test_testplan.py | 1387 +++++++++++++++++++++++- 1 file changed, 1386 insertions(+), 1 deletion(-) diff --git a/scripts/tests/twister/test_testplan.py b/scripts/tests/twister/test_testplan.py index e3a02404def..ed61759750f 100644 --- a/scripts/tests/twister/test_testplan.py +++ b/scripts/tests/twister/test_testplan.py @@ -8,16 +8,20 @@ ''' import sys import os +import mock import pytest +from contextlib import nullcontext + ZEPHYR_BASE = os.getenv("ZEPHYR_BASE") sys.path.insert(0, os.path.join(ZEPHYR_BASE, "scripts/pylib/twister")) -from twisterlib.testplan import TestPlan +from twisterlib.testplan import TestPlan, change_skip_to_error_if_integration from twisterlib.testinstance import TestInstance from twisterlib.testsuite import TestSuite from twisterlib.platform import Platform from twisterlib.quarantine import Quarantine +from twisterlib.error import TwisterRuntimeError def test_testplan_add_testsuites_short(class_testplan): @@ -374,6 +378,8 @@ def test_required_snippets_short( plan.platform_names = [p.name for p in platforms_list] plan.testsuites = {testpath: testsuite} + print(plan.testsuites) + for _, testcase in plan.testsuites.items(): testcase.exclude_platform = [] testcase.required_snippets = required_snippets @@ -389,3 +395,1382 @@ def test_required_snippets_short( if expected_filtered_reason is not None: for d in filtered_instances: assert d.reason == expected_filtered_reason + + +def test_testplan_get_level(): + testplan = TestPlan(env=mock.Mock()) + lvl1 = mock.Mock() + lvl1.name = 'a lvl' + lvl2 = mock.Mock() + lvl2.name = 'a lvl' + lvl3 = mock.Mock() + lvl3.name = 'other lvl' + testplan.levels.append(lvl1) + testplan.levels.append(lvl2) + testplan.levels.append(lvl3) + + name = 'a lvl' + + res = testplan.get_level(name) + assert res == lvl1 + + res = testplan.get_level(name) + assert res == lvl1 + + testplan.levels.remove(lvl1) + testplan.levels.remove(lvl2) + + res = testplan.get_level(name) + assert res is None + + +TESTDATA_1 = [ + ('', {}), + ( +"""\ +levels: + - name: lvl1 + adds: + - sc1 + - sc2 + inherits: [] + - name: lvl2 + adds: + - sc1-1 + - sc1-2 + inherits: [lvl1] +""", + { + 'lvl1': ['sc1', 'sc2'], + 'lvl2': ['sc1-1', 'sc1-2', 'sc1', 'sc2'] + } + ), +] + +@pytest.mark.parametrize( + 'config_yaml, expected_scenarios', + TESTDATA_1, + ids=['no config', 'valid config'] +) +def test_testplan_parse_configuration(tmp_path, config_yaml, expected_scenarios): + testplan = TestPlan(env=mock.Mock()) + testplan.scenarios = ['sc1', 'sc1-1', 'sc1-2', 'sc2'] + + tmp_config_file = tmp_path / 'config_file.yaml' + if config_yaml: + tmp_config_file.write_text(config_yaml) + + with pytest.raises(TwisterRuntimeError) if not config_yaml else nullcontext(): + testplan.parse_configuration(tmp_config_file) + + if not testplan.levels: + assert expected_scenarios == {} + for level in testplan.levels: + assert sorted(level.scenarios) == sorted(expected_scenarios[level.name]) + + +TESTDATA_2 = [ + ([], [], False), + (['ts1.tc3'], [], True), + (['ts2.tc2'], ['- ts2'], False), +] + +@pytest.mark.parametrize( + 'sub_tests, expected_outs, expect_error', + TESTDATA_2, + ids=['no subtests', 'subtests not found', 'valid subtests'] +) +def test_testplan_find_subtests( + capfd, + sub_tests, + expected_outs, + expect_error +): + testplan = TestPlan(env=mock.Mock()) + testplan.options = mock.Mock(sub_test=sub_tests) + testplan.run_individual_testsuite = [] + testplan.testsuites = { + 'ts1': mock.Mock( + testcases=[ + mock.Mock(), + mock.Mock(), + ] + ), + 'ts2': mock.Mock( + testcases=[ + mock.Mock(), + mock.Mock(), + mock.Mock(), + ] + ) + } + testplan.testsuites['ts1'].name = 'ts1' + testplan.testsuites['ts1'].testcases[0].name = 'ts1.tc1' + testplan.testsuites['ts1'].testcases[1].name = 'ts1.tc2' + testplan.testsuites['ts2'].name = 'ts2' + testplan.testsuites['ts2'].testcases[0].name = 'ts2.tc1' + testplan.testsuites['ts2'].testcases[1].name = 'ts2.tc2' + testplan.testsuites['ts2'].testcases[2].name = 'ts2.tc3' + + with pytest.raises(TwisterRuntimeError) if expect_error else nullcontext(): + testplan.find_subtests() + + out, err = capfd.readouterr() + sys.stdout.write(out) + sys.stdout.write(err) + + assert all([printout in out for printout in expected_outs]) + + +TESTDATA_3 = [ + (0, 0, [], False, [], TwisterRuntimeError, []), + (1, 1, [], False, [], TwisterRuntimeError, []), + (1, 0, [], True, [], TwisterRuntimeError, ['No quarantine list given to be verified']), +# (1, 0, ['qfile.yaml'], False, ['# empty'], None, ['Quarantine file qfile.yaml is empty']), + (1, 0, ['qfile.yaml'], False, ['- platforms:\n - demo_board_3\n comment: "board_3"'], None, []), +] + +@pytest.mark.parametrize( + 'added_testsuite_count, load_errors, ql, qv, ql_data, exception, expected_logs', + TESTDATA_3, + ids=['no tests', 'load errors', 'quarantine verify without quarantine list', +# 'empty quarantine file', + 'valid quarantine file'] +) +def test_testplan_discover( + tmp_path, + caplog, + added_testsuite_count, + load_errors, + ql, + qv, + ql_data, + exception, + expected_logs +): + for qf, data in zip(ql, ql_data): + tmp_qf = tmp_path / qf + tmp_qf.write_text(data) + + testplan = TestPlan(env=mock.Mock()) + testplan.options = mock.Mock( + test='ts1', + quarantine_list=[tmp_path / qf for qf in ql], + quarantine_verify=qv, + ) + testplan.testsuites = { + 'ts1': mock.Mock(id=1), + 'ts2': mock.Mock(id=2), + } + testplan.run_individual_testsuite = 'ts0' + testplan.load_errors = load_errors + testplan.add_testsuites = mock.Mock(return_value=added_testsuite_count) + testplan.find_subtests = mock.Mock() + testplan.report_duplicates = mock.Mock() + testplan.parse_configuration = mock.Mock() + testplan.add_configurations = mock.Mock() + + with pytest.raises(exception) if exception else nullcontext(): + testplan.discover() + + testplan.add_testsuites.assert_called_once_with(testsuite_filter='ts1') + assert all([log in caplog.text for log in expected_logs]) + + +TESTDATA_4 = [ + (None, None, None, None, '00', + TwisterRuntimeError, [], []), + (None, True, None, None, '6/4', + TwisterRuntimeError, set(['t-p3', 't-p4', 't-p1', 't-p2']), []), + (None, None, 'load_tests.json', None, '0/4', + TwisterRuntimeError, set(['lt-p1', 'lt-p3', 'lt-p4', 'lt-p2']), []), + ('suffix', None, None, True, '2/4', + None, set(['ts-p4', 'ts-p2', 'ts-p3']), [2, 4]), +] + +@pytest.mark.parametrize( + 'report_suffix, only_failed, load_tests, test_only, subset,' \ + ' exception, expected_selected_platforms, expected_generate_subset_args', + TESTDATA_4, + ids=['apply_filters only', 'only failed', 'load tests', 'test only'] +) +def test_testplan_load( + tmp_path, + report_suffix, + only_failed, + load_tests, + test_only, + subset, + exception, + expected_selected_platforms, + expected_generate_subset_args +): + twister_json = """\ +{ + "testsuites": [ + { + "name": "ts1", + "platform": "t-p1", + "testcases": [] + }, + { + "name": "ts1", + "platform": "t-p2", + "testcases": [] + }, + { + "name": "ts2", + "platform": "t-p3", + "testcases": [] + }, + { + "name": "ts2", + "platform": "t-p4", + "testcases": [] + } + ] +} +""" + twister_file = tmp_path / 'twister.json' + twister_file.write_text(twister_json) + + twister_suffix_json = """\ +{ + "testsuites": [ + { + "name": "ts1", + "platform": "ts-p1", + "testcases": [] + }, + { + "name": "ts1", + "platform": "ts-p2", + "testcases": [] + }, + { + "name": "ts2", + "platform": "ts-p3", + "testcases": [] + }, + { + "name": "ts2", + "platform": "ts-p4", + "testcases": [] + } + ] +} +""" + twister_suffix_file = tmp_path / 'twister_suffix.json' + twister_suffix_file.write_text(twister_suffix_json) + + load_tests_json = """\ +{ + "testsuites": [ + { + "name": "ts1", + "platform": "lt-p1", + "testcases": [] + }, + { + "name": "ts1", + "platform": "lt-p2", + "testcases": [] + }, + { + "name": "ts2", + "platform": "lt-p3", + \"testcases": [] + }, + { + "name": "ts2", + "platform": "lt-p4", + "testcases": [] + } + ] +} +""" + load_tests_file = tmp_path / 'load_tests.json' + load_tests_file.write_text(load_tests_json) + + testplan = TestPlan(env=mock.Mock(outdir=tmp_path)) + testplan.testsuites = { + 'ts1': mock.Mock(testcases=[], extra_configs=[]), + 'ts2': mock.Mock(testcases=[], extra_configs=[]), + } + testplan.testsuites['ts1'].name = 'ts1' + testplan.testsuites['ts2'].name = 'ts2' + testplan.options = mock.Mock( + outdir=tmp_path, + report_suffix=report_suffix, + only_failed=only_failed, + load_tests=tmp_path / load_tests if load_tests else None, + test_only=test_only, + exclude_platform=['t-p0', 't-p1', + 'ts-p0', 'ts-p1', + 'lt-p0', 'lt-p1'], + platform=['t-p1', 't-p2', 't-p3', 't-p4', + 'ts-p1', 'ts-p2', 'ts-p3', 'ts-p4', + 'lt-p1', 'lt-p2', 'lt-p3', 'lt-p4'], + subset=subset + ) + testplan.platforms=[mock.Mock(), mock.Mock(), mock.Mock(), mock.Mock(), + mock.Mock(), mock.Mock(), mock.Mock(), mock.Mock(), + mock.Mock(), mock.Mock(), mock.Mock(), mock.Mock()] + testplan.platforms[0].name = 't-p1' + testplan.platforms[1].name = 't-p2' + testplan.platforms[2].name = 't-p3' + testplan.platforms[3].name = 't-p4' + testplan.platforms[4].name = 'ts-p1' + testplan.platforms[5].name = 'ts-p2' + testplan.platforms[6].name = 'ts-p3' + testplan.platforms[7].name = 'ts-p4' + testplan.platforms[8].name = 'lt-p1' + testplan.platforms[9].name = 'lt-p2' + testplan.platforms[10].name = 'lt-p3' + testplan.platforms[11].name = 'lt-p4' + testplan.generate_subset = mock.Mock() + testplan.apply_filters = mock.Mock() + + with mock.patch('twisterlib.testinstance.TestInstance.create_overlay', mock.Mock()), \ + pytest.raises(exception) if exception else nullcontext(): + testplan.load() + + assert testplan.selected_platforms == expected_selected_platforms + if expected_generate_subset_args: + testplan.generate_subset.assert_called_once_with(*expected_generate_subset_args) + else: + testplan.generate_subset.assert_not_called() + + +TESTDATA_5 = [ + (False, False, None, 1, 2, + ['plat1/testA', 'plat1/testB', 'plat1/testC', + 'plat3/testA', 'plat3/testB', 'plat3/testC']), + (False, False, None, 1, 5, + ['plat1/testA', + 'plat3/testA', 'plat3/testB', 'plat3/testC']), + (False, False, None, 2, 2, + ['plat2/testA', 'plat2/testB']), + (True, False, None, 1, 2, + ['plat1/testA', 'plat2/testA', 'plat1/testB', + 'plat3/testA', 'plat3/testB', 'plat3/testC']), + (True, False, None, 2, 2, + ['plat2/testB', 'plat1/testC']), + (True, True, 123, 1, 2, + ['plat2/testA', 'plat2/testB', 'plat1/testC', + 'plat3/testB', 'plat3/testA', 'plat3/testC']), + (True, True, 123, 2, 2, + ['plat1/testB', 'plat1/testA']), +] + +@pytest.mark.parametrize( + 'device_testing, shuffle, seed, subset, sets, expected_subset', + TESTDATA_5, + ids=['subset 1', 'subset 1 out of 5', 'subset 2', + 'device testing, subset 1', 'device testing, subset 2', + 'device testing, shuffle with seed, subset 1', + 'device testing, shuffle with seed, subset 2'] +) +def test_testplan_generate_subset( + device_testing, + shuffle, + seed, + subset, + sets, + expected_subset +): + testplan = TestPlan(env=mock.Mock()) + testplan.options = mock.Mock( + device_testing=device_testing, + shuffle_tests=shuffle, + shuffle_tests_seed=seed + ) + testplan.instances = { + 'plat1/testA': mock.Mock(status=None), + 'plat1/testB': mock.Mock(status=None), + 'plat1/testC': mock.Mock(status=None), + 'plat2/testA': mock.Mock(status=None), + 'plat2/testB': mock.Mock(status=None), + 'plat3/testA': mock.Mock(status='skipped'), + 'plat3/testB': mock.Mock(status='skipped'), + 'plat3/testC': mock.Mock(status='error'), + } + + testplan.generate_subset(subset, sets) + + assert [instance for instance in testplan.instances.keys()] == \ + expected_subset + + +def test_testplan_handle_modules(): + testplan = TestPlan(env=mock.Mock()) + + modules = [mock.Mock(meta={'name': 'name1'}), + mock.Mock(meta={'name': 'name2'})] + + with mock.patch('twisterlib.testplan.parse_modules', return_value=modules): + testplan.handle_modules() + + assert testplan.modules == ['name1', 'name2'] + + +TESTDATA_6 = [ + (True, False, False, 0, 'report_test_tree'), + (True, True, False, 0, 'report_test_tree'), + (True, False, True, 0, 'report_test_tree'), + (True, True, True, 0, 'report_test_tree'), + (False, True, False, 0, 'report_test_list'), + (False, True, True, 0, 'report_test_list'), + (False, False, True, 0, 'report_tag_list'), + (False, False, False, 1, None), +] + +@pytest.mark.parametrize( + 'test_tree, list_tests, list_tags, expected_res, expected_method', + TESTDATA_6, + ids=['test tree', 'test tree + test list', 'test tree + tag list', + 'test tree + test list + tag list', 'test list', + 'test list + tag list', 'tag list', 'no report'] +) +def test_testplan_report( + test_tree, + list_tests, + list_tags, + expected_res, + expected_method +): + testplan = TestPlan(env=mock.Mock()) + testplan.report_test_tree = mock.Mock() + testplan.report_test_list = mock.Mock() + testplan.report_tag_list = mock.Mock() + + testplan.options = mock.Mock( + test_tree=test_tree, + list_tests=list_tests, + list_tags=list_tags, + ) + + res = testplan.report() + + assert res == expected_res + + methods = ['report_test_tree', 'report_test_list', 'report_tag_list'] + if expected_method: + methods.remove(expected_method) + getattr(testplan, expected_method).assert_called_once() + for method in methods: + getattr(testplan, method).assert_not_called() + + +TESTDATA_7 = [ + ( + [ + mock.Mock( + yamlfile='a.yaml', + scenarios=['scenario1', 'scenario2'] + ), + mock.Mock( + yamlfile='b.yaml', + scenarios=['scenario1'] + ) + ], + TwisterRuntimeError, + 'Duplicated test scenarios found:\n' \ + '- scenario1 found in:\n' \ + ' - a.yaml\n' \ + ' - b.yaml\n', + [] + ), + ( + [ + mock.Mock( + yamlfile='a.yaml', + scenarios=['scenario.a.1', 'scenario.a.2'] + ), + mock.Mock( + yamlfile='b.yaml', + scenarios=['scenario.b.1'] + ) + ], + None, + None, + ['No duplicates found.'] + ), +] + +@pytest.mark.parametrize( + 'testsuites, expected_error, error_msg, expected_logs', + TESTDATA_7, + ids=['a duplicate', 'no duplicates'] +) +def test_testplan_report_duplicates( + capfd, + caplog, + testsuites, + expected_error, + error_msg, + expected_logs +): + def mock_get(name): + return list(filter(lambda x: name in x.scenarios, testsuites)) + + testplan = TestPlan(env=mock.Mock()) + testplan.scenarios = [scenario for testsuite in testsuites \ + for scenario in testsuite.scenarios] + testplan.get_testsuite = mock.Mock(side_effect=mock_get) + + with pytest.raises(expected_error) if expected_error is not None else \ + nullcontext() as err: + testplan.report_duplicates() + + if expected_error: + assert str(err._excinfo[1]) == error_msg + + assert all([log in caplog.text for log in expected_logs]) + + +def test_testplan_report_tag_list(capfd): + testplan = TestPlan(env=mock.Mock()) + testplan.testsuites = { + 'testsuite0': mock.Mock(tags=set(['tag1', 'tag2'])), + 'testsuite1': mock.Mock(tags=set(['tag1', 'tag2', 'tag3'])), + 'testsuite2': mock.Mock(tags=set(['tag1', 'tag3'])), + 'testsuite3': mock.Mock(tags=set(['tag'])) + } + + testplan.report_tag_list() + + out,err = capfd.readouterr() + sys.stdout.write(out) + sys.stderr.write(err) + + assert '- tag' in out + assert '- tag1' in out + assert '- tag2' in out + assert '- tag3' in out + + +def test_testplan_report_test_tree(capfd): + testplan = TestPlan(env=mock.Mock()) + testplan.get_all_tests = mock.Mock( + return_value=['1.dummy.case.1', '1.dummy.case.2', + '2.dummy.case.1', '2.dummy.case.2', + '3.dummy.case.1', '3.dummy.case.2', + '4.dummy.case.1', '4.dummy.case.2', + '5.dummy.case.1', '5.dummy.case.2', + 'sample.group1.case1', 'sample.group1.case2', + 'sample.group2.case', 'sample.group3.case1', + 'sample.group3.case2', 'sample.group3.case3'] + ) + + testplan.report_test_tree() + + out,err = capfd.readouterr() + sys.stdout.write(out) + sys.stderr.write(err) + + expected = """ +Testsuite +├── Samples +│ ├── group1 +│ │ ├── sample.group1.case1 +│ │ └── sample.group1.case2 +│ ├── group2 +│ │ └── sample.group2.case +│ └── group3 +│ ├── sample.group3.case1 +│ ├── sample.group3.case2 +│ └── sample.group3.case3 +└── Tests + ├── 1 + │ └── dummy + │ ├── 1.dummy.case.1 + │ └── 1.dummy.case.2 + ├── 2 + │ └── dummy + │ ├── 2.dummy.case.1 + │ └── 2.dummy.case.2 + ├── 3 + │ └── dummy + │ ├── 3.dummy.case.1 + │ └── 3.dummy.case.2 + ├── 4 + │ └── dummy + │ ├── 4.dummy.case.1 + │ └── 4.dummy.case.2 + └── 5 + └── dummy + ├── 5.dummy.case.1 + └── 5.dummy.case.2 +""" + expected = expected[1:] + + assert expected in out + + +def test_testplan_report_test_list(capfd): + testplan = TestPlan(env=mock.Mock()) + testplan.get_all_tests = mock.Mock( + return_value=['4.dummy.case.1', '4.dummy.case.2', + '3.dummy.case.2', '2.dummy.case.2', + '1.dummy.case.1', '1.dummy.case.2', + '3.dummy.case.1', '2.dummy.case.1', + '5.dummy.case.1', '5.dummy.case.2'] + ) + + testplan.report_test_list() + + out,err = capfd.readouterr() + sys.stdout.write(out) + sys.stderr.write(err) + + assert ' - 1.dummy.case.1\n' \ + ' - 1.dummy.case.2\n' \ + ' - 2.dummy.case.1\n' \ + ' - 2.dummy.case.2\n' \ + ' - 3.dummy.case.1\n' \ + ' - 3.dummy.case.2\n' \ + ' - 4.dummy.case.1\n' \ + ' - 4.dummy.case.2\n' \ + ' - 5.dummy.case.1\n' \ + ' - 5.dummy.case.2\n' \ + '10 total.' in out + + +def test_testplan_config(caplog): + testplan = TestPlan(env=mock.Mock()) + testplan.coverage_platform = 'dummy cov' + + testplan.config() + + assert 'coverage platform: dummy cov' in caplog.text + + +def test_testplan_info(capfd): + TestPlan.info('dummy text') + + out, err = capfd.readouterr() + sys.stdout.write(out) + sys.stderr.write(err) + + assert 'dummy text\n' in out + + +TESTDATA_8 = [ + (False, False, ['p1e2', 'p2', 'p3', 'p3@B'], ['p2']), + (False, True, None, None), + (True, False, ['p1e2', 'p2', 'p3', 'p3@B'], ['p3']), +] + +@pytest.mark.parametrize( + 'override_default_platforms, create_duplicate, expected_platform_names, expected_defaults', + TESTDATA_8, + ids=['no override defaults', 'create duplicate', 'override defaults'] +) +def test_testplan_add_configurations( + tmp_path, + override_default_platforms, + create_duplicate, + expected_platform_names, + expected_defaults +): + # tmp_path + # └ boards <- board root + # ├ arch1 + # │ ├ p1 + # │ | ├ p1e1.yaml + # │ | └ p1e2.yaml + # │ └ p2 + # │ ├ p2.yaml + # │ └ p2-1.yaml <- duplicate + # │ └ p2-2.yaml <- load error + # └ arch2 + # └ p3 + # ├ p3.yaml + # └ p3_B.conf + + tmp_board_root_dir = tmp_path / 'boards' + tmp_board_root_dir.mkdir() + + tmp_arch1_dir = tmp_board_root_dir / 'arch1' + tmp_arch1_dir.mkdir() + + tmp_p1_dir = tmp_arch1_dir / 'p1' + tmp_p1_dir.mkdir() + + p1e1_yaml = """\ +identifier: p1e1 +name: Platform 1 Edition 1 +type: native +arch: arch1 +vendor: vendor1 +toolchain: + - zephyr +twister: False +""" + p1e1_yamlfile = tmp_p1_dir / 'p1e1.yaml' + p1e1_yamlfile.write_text(p1e1_yaml) + + p1e2_yaml = """\ +identifier: p1e2 +name: Platform 1 Edition 2 +type: native +arch: arch1 +vendor: vendor1 +toolchain: + - zephyr +""" + p1e2_yamlfile = tmp_p1_dir / 'p1e2.yaml' + p1e2_yamlfile.write_text(p1e2_yaml) + + tmp_p2_dir = tmp_arch1_dir / 'p2' + tmp_p2_dir.mkdir() + + p2_yaml = """\ +identifier: p2 +name: Platform 2 +type: sim +arch: arch1 +vendor: vendor2 +toolchain: + - zephyr +testing: + default: True +""" + p2_yamlfile = tmp_p2_dir / 'p2.yaml' + p2_yamlfile.write_text(p2_yaml) + + if create_duplicate: + p2_yamlfile = tmp_p2_dir / 'p2-1.yaml' + p2_yamlfile.write_text(p2_yaml) + + p2_2_yaml = """\ +testing: + ć#@%!#!#^#@%@:1.0 +identifier: p2_2 +name: Platform 2 2 +type: sim +arch: arch1 +vendor: vendor2 +toolchain: + - zephyr +""" + p2_2_yamlfile = tmp_p2_dir / 'p2-2.yaml' + p2_2_yamlfile.write_text(p2_2_yaml) + + tmp_arch2_dir = tmp_board_root_dir / 'arch2' + tmp_arch2_dir.mkdir() + + tmp_p3_dir = tmp_arch2_dir / 'p3' + tmp_p3_dir.mkdir() + + p3_yaml = """\ +identifier: p3 +name: Platform 3 +type: unit +arch: arch2 +vendor: vendor3 +toolchain: + - zephyr +""" + p3_yamlfile = tmp_p3_dir / 'p3.yaml' + p3_yamlfile.write_text(p3_yaml) + p3_yamlfile = tmp_p3_dir / 'p3_B.conf' + p3_yamlfile.write_text('') + + env = mock.Mock(board_roots=[tmp_board_root_dir]) + + testplan = TestPlan(env=env) + + testplan.test_config = { + 'platforms': { + 'override_default_platforms': override_default_platforms, + 'default_platforms': ['p3', 'p1e1'] + } + } + + with pytest.raises(Exception) if create_duplicate else nullcontext(): + testplan.add_configurations() + + if expected_defaults is not None: + assert sorted(expected_defaults) == sorted(testplan.default_platforms) + if expected_platform_names is not None: + assert sorted(expected_platform_names) == sorted(testplan.platform_names) + + +def test_testplan_get_all_tests(): + testplan = TestPlan(env=mock.Mock()) + tc1 = mock.Mock() + tc1.name = 'tc1' + tc2 = mock.Mock() + tc2.name = 'tc2' + tc3 = mock.Mock() + tc3.name = 'tc3' + tc4 = mock.Mock() + tc4.name = 'tc4' + tc5 = mock.Mock() + tc5.name = 'tc5' + ts1 = mock.Mock(testcases=[tc1, tc2]) + ts2 = mock.Mock(testcases=[tc3, tc4, tc5]) + testplan.testsuites = { + 'ts1': ts1, + 'ts2': ts2 + } + + res = testplan.get_all_tests() + + assert sorted(res) == ['tc1', 'tc2', 'tc3', 'tc4', 'tc5'] + + +TESTDATA_9 = [ + ([], False, 7), + ([], True, 5), + (['good_test/dummy.common.1', 'good_test/dummy.common.2', 'good_test/dummy.common.3'], False, 3), + (['good_test/dummy.common.1', 'good_test/dummy.common.2', 'good_test/dummy.common.3'], True, 0), +] + +@pytest.mark.parametrize( + 'testsuite_filter, use_alt_root, expected_suite_count', + TESTDATA_9, + ids=['no testsuite filter', 'no testsuite filter, alt root', + 'testsuite filter', 'testsuite filter, alt root'] +) +def test_testplan_add_testsuites(tmp_path, testsuite_filter, use_alt_root, expected_suite_count): + # tmp_path + # ├ tests <- test root + # │ ├ good_test + # │ │ └ testcase.yaml + # │ ├ wrong_test + # │ │ └ testcase.yaml + # │ ├ good_sample + # │ │ └ sample.yaml + # │ └ others + # │ └ other.txt + # └ other_tests <- alternate test root + # └ good_test + # └ testcase.yaml + tmp_test_root_dir = tmp_path / 'tests' + tmp_test_root_dir.mkdir() + + tmp_good_test_dir = tmp_test_root_dir / 'good_test' + tmp_good_test_dir.mkdir() + testcase_yaml_1 = """\ +tests: + dummy.common.1: + build_on_all: true + dummy.common.2: + build_on_all: true + dummy.common.3: + build_on_all: true + dummy.special: + build_on_all: false +""" + testfile_1 = tmp_good_test_dir / 'testcase.yaml' + testfile_1.write_text(testcase_yaml_1) + + tmp_bad_test_dir = tmp_test_root_dir / 'wrong_test' + tmp_bad_test_dir.mkdir() + testcase_yaml_2 = """\ +tests: + wrong: + yaml: {]} +""" + testfile_2 = tmp_bad_test_dir / 'testcase.yaml' + testfile_2.write_text(testcase_yaml_2) + + tmp_good_sample_dir = tmp_test_root_dir / 'good_sample' + tmp_good_sample_dir.mkdir() + samplecase_yaml_1 = """\ +tests: + sample.dummy.common.1: + tags: + - samples + sample.dummy.common.2: + tags: + - samples + sample.dummy.special.1: + tags: + - samples +""" + samplefile_1 = tmp_good_sample_dir / 'sample.yaml' + samplefile_1.write_text(samplecase_yaml_1) + + tmp_other_dir = tmp_test_root_dir / 'others' + tmp_other_dir.mkdir() + _ = tmp_other_dir / 'other.txt' + + tmp_alt_test_root_dir = tmp_path / 'other_tests' + tmp_alt_test_root_dir.mkdir() + + tmp_alt_good_test_dir = tmp_alt_test_root_dir / 'good_test' + tmp_alt_good_test_dir.mkdir() + testcase_yaml_3 = """\ +tests: + dummy.alt.1: + build_on_all: true + dummy.alt.2: + build_on_all: true +""" + testfile_3 = tmp_alt_good_test_dir / 'testcase.yaml' + testfile_3.write_text(testcase_yaml_3) + + env = mock.Mock( + test_roots=[tmp_test_root_dir], + alt_config_root=[tmp_alt_test_root_dir] if use_alt_root else [] + ) + + testplan = TestPlan(env=env) + + res = testplan.add_testsuites(testsuite_filter) + + assert res == expected_suite_count + + +def test_testplan_str(): + testplan = TestPlan(env=mock.Mock()) + testplan.name = 'my name' + + res = testplan.__str__() + + assert res == 'my name' + + +TESTDATA_10 = [ + ('a platform', True), + ('other platform', False), +] + +@pytest.mark.parametrize( + 'name, expect_found', + TESTDATA_10, + ids=['platform exists', 'no platform'] +) +def test_testplan_get_platform(name, expect_found): + testplan = TestPlan(env=mock.Mock()) + p1 = mock.Mock() + p1.name = 'some platform' + p2 = mock.Mock() + p2.name = 'a platform' + testplan.platforms = [p1, p2] + + res = testplan.get_platform(name) + + if expect_found: + assert res.name == name + else: + assert res is None + + +TESTDATA_11 = [ + (True, 'runnable'), + (False, 'buildable'), +] + +@pytest.mark.parametrize( + 'device_testing, expected_tfilter', + TESTDATA_11, + ids=['device testing', 'no device testing'] +) +def test_testplan_load_from_file(caplog, device_testing, expected_tfilter): + def get_platform(name): + p = mock.Mock() + p.name = name + return p + + ts1tc1 = mock.Mock() + ts1tc1.name = 'TS1.tc1' + ts1 = mock.Mock(testcases=[ts1tc1]) + ts1.name = 'TestSuite 1' + ts2 = mock.Mock(testcases=[]) + ts2.name = 'TestSuite 2' + ts3tc1 = mock.Mock() + ts3tc1.name = 'TS3.tc1' + ts3tc2 = mock.Mock() + ts3tc2.name = 'TS3.tc2' + ts3 = mock.Mock(testcases=[ts3tc1, ts3tc2]) + ts3.name = 'TestSuite 3' + ts4tc1 = mock.Mock() + ts4tc1.name = 'TS4.tc1' + ts4 = mock.Mock(testcases=[ts4tc1]) + ts4.name = 'TestSuite 4' + ts5 = mock.Mock(testcases=[]) + ts5.name = 'TestSuite 5' + + testplan = TestPlan(env=mock.Mock(outdir=os.path.join('out', 'dir'))) + testplan.options = mock.Mock(device_testing=device_testing, test_only=True) + testplan.testsuites = { + 'TestSuite 1': ts1, + 'TestSuite 2': ts2, + 'TestSuite 3': ts3, + 'TestSuite 4': ts4, + 'TestSuite 5': ts5 + } + + testplan.get_platform = mock.Mock(side_effect=get_platform) + + testplan_data = """\ +{ + "testsuites": [ + { + "name": "TestSuite 1", + "platform": "Platform 1", + "run_id": 1, + "execution_time": 60.00, + "used_ram": 4096, + "available_ram": 12278, + "used_rom": 1024, + "available_rom": 1047552, + "status": "passed", + "reason": "OK", + "testcases": [ + { + "identifier": "TS1.tc1", + "status": "passed", + "reason": "passed", + "execution_time": 60.00, + "log": "" + } + ] + }, + { + "name": "TestSuite 2", + "platform": "Platform 1" + }, + { + "name": "TestSuite 3", + "platform": "Platform 1", + "run_id": 1, + "execution_time": 360.00, + "used_ram": 4096, + "available_ram": 12278, + "used_rom": 1024, + "available_rom": 1047552, + "status": "error", + "reason": "File Not Found Error", + "testcases": [ + { + "identifier": "TS3.tc1", + "status": "error", + "reason": "File Not Found Error.", + "execution_time": 360.00, + "log": "[ERROR]: File 'dummy.yaml' not found!\\nClosing..." + }, + { + "identifier": "TS3.tc2" + } + ] + }, + { + "name": "TestSuite 4", + "platform": "Platform 1", + "execution_time": 360.00, + "used_ram": 4096, + "available_ram": 12278, + "used_rom": 1024, + "available_rom": 1047552, + "status": "skipped", + "reason": "Not in requested test list.", + "testcases": [ + { + "identifier": "TS4.tc1", + "status": "skipped", + "reason": "Not in requested test list.", + "execution_time": 360.00, + "log": "[INFO] Parsing..." + }, + { + "identifier": "TS3.tc2" + } + ] + }, + { + "name": "TestSuite 5", + "platform": "Platform 2" + } + ] +} +""" + + filter_platform = ['Platform 1'] + + check_runnable_mock = mock.Mock(return_value=True) + + with mock.patch('builtins.open', mock.mock_open(read_data=testplan_data)), \ + mock.patch('twisterlib.testinstance.TestInstance.check_runnable', check_runnable_mock), \ + mock.patch('twisterlib.testinstance.TestInstance.create_overlay', mock.Mock()): + testplan.load_from_file('dummy.yaml', filter_platform) + + expected_instances = { + 'Platform 1/TestSuite 1': { + 'metrics': { + 'handler_time': 60.0, + 'used_ram': 4096, + 'used_rom': 1024, + 'available_ram': 12278, + 'available_rom': 1047552 + }, + 'retries': 0, + 'testcases': { + 'TS1.tc1': { + 'status': 'passed', + 'reason': None, + 'duration': 60.0, + 'output': '' + } + } + }, + 'Platform 1/TestSuite 2': { + 'metrics': { + 'handler_time': 0, + 'used_ram': 0, + 'used_rom': 0, + 'available_ram': 0, + 'available_rom': 0 + }, + 'retries': 0, + 'testcases': [] + }, + 'Platform 1/TestSuite 3': { + 'metrics': { + 'handler_time': 360.0, + 'used_ram': 4096, + 'used_rom': 1024, + 'available_ram': 12278, + 'available_rom': 1047552 + }, + 'retries': 1, + 'testcases': { + 'TS3.tc1': { + 'status': 'error', + 'reason': None, + 'duration': 360.0, + 'output': '[ERROR]: File \'dummy.yaml\' not found!\nClosing...' + }, + 'TS3.tc2': { + 'status': None, + 'reason': None, + 'duration': 0, + 'output': '' + } + } + }, + 'Platform 1/TestSuite 4': { + 'metrics': { + 'handler_time': 360.0, + 'used_ram': 4096, + 'used_rom': 1024, + 'available_ram': 12278, + 'available_rom': 1047552 + }, + 'retries': 0, + 'testcases': { + 'TS4.tc1': { + 'status': 'skipped', + 'reason': 'Not in requested test list.', + 'duration': 360.0, + 'output': '[INFO] Parsing...' + } + } + }, + } + + for n, i in testplan.instances.items(): + assert expected_instances[n]['metrics'] == i.metrics + assert expected_instances[n]['retries'] == i.retries + for t in i.testcases: + assert expected_instances[n]['testcases'][str(t)]['status'] == t.status + assert expected_instances[n]['testcases'][str(t)]['reason'] == t.reason + assert expected_instances[n]['testcases'][str(t)]['duration'] == t.duration + assert expected_instances[n]['testcases'][str(t)]['output'] == t.output + + check_runnable_mock.assert_called_with(mock.ANY, expected_tfilter, mock.ANY, mock.ANY) + + expected_logs = [ + 'loading TestSuite 1...', + 'loading TestSuite 2...', + 'loading TestSuite 3...', + 'loading TestSuite 4...', + ] + assert all([log in caplog.text for log in expected_logs]) + + +def test_testplan_add_instances(): + testplan = TestPlan(env=mock.Mock()) + instance1 = mock.Mock() + instance1.name = 'instance 1' + instance2 = mock.Mock() + instance2.name = 'instance 2' + instance_list = [instance1, instance2] + + testplan.add_instances(instance_list) + + assert testplan.instances == { + 'instance 1': instance1, + 'instance 2': instance2, + } + + +def test_testplan_get_testsuite(): + testplan = TestPlan(env=mock.Mock()) + testplan.testsuites = { + 'testsuite0': mock.Mock(testcases=[mock.Mock(), mock.Mock()]), + 'testsuite1': mock.Mock(testcases=[mock.Mock()]), + 'testsuite2': mock.Mock(testcases=[mock.Mock(), mock.Mock()]), + 'testsuite3': mock.Mock(testcases=[]) + } + testplan.testsuites['testsuite0'].testcases[0].name = 'testcase name 0' + testplan.testsuites['testsuite0'].testcases[1].name = 'testcase name 1' + testplan.testsuites['testsuite1'].testcases[0].name = 'sample id' + testplan.testsuites['testsuite2'].testcases[0].name = 'dummy id' + testplan.testsuites['testsuite2'].testcases[1].name = 'sample id' + + id = 'sample id' + + res = testplan.get_testsuite(id) + + assert len(res) == 2 + assert testplan.testsuites['testsuite1'] in res + assert testplan.testsuites['testsuite2'] in res + + +def test_testplan_verify_platforms_existence(caplog): + testplan = TestPlan(env=mock.Mock()) + testplan.platform_names = ['a platform', 'other platform'] + + platform_names = ['other platform', 'some platform'] + log_info = 'PLATFORM ERROR' + + with pytest.raises(SystemExit) as se: + testplan.verify_platforms_existence(platform_names, log_info) + + assert str(se.value) == '2' + assert 'PLATFORM ERROR - unrecognized platform - some platform' + + +TESTDATA_12 = [ + (True), + (False) +] + +@pytest.mark.parametrize( + 'exists', + TESTDATA_12, + ids=['links dir exists', 'links dir does not exist'] +) +def test_testplan_create_build_dir_links(exists): + outdir = os.path.join('out', 'dir') + instances_linked = [] + + def mock_link(links_dir_path, instance): + assert links_dir_path == os.path.join(outdir, 'twister_links') + instances_linked.append(instance) + + instances = { + 'inst0': mock.Mock(status='passed'), + 'inst1': mock.Mock(status='skipped'), + 'inst2': mock.Mock(status='error'), + } + expected_instances = [instances['inst0'], instances['inst2']] + + testplan = TestPlan(env=mock.Mock(outdir=outdir)) + testplan._create_build_dir_link = mock.Mock(side_effect=mock_link) + testplan.instances = instances + + with mock.patch('os.path.exists', return_value=exists), \ + mock.patch('os.mkdir', mock.Mock()) as mkdir_mock: + testplan.create_build_dir_links() + + if not exists: + mkdir_mock.assert_called_once() + + assert expected_instances == instances_linked + + +TESTDATA_13 = [ + ('nt'), + ('Linux') +] + +@pytest.mark.parametrize( + 'os_name', + TESTDATA_13, +) +def test_testplan_create_build_dir_link(os_name): + testplan = TestPlan(env=mock.Mock()) + links_dir_path = os.path.join('links', 'path') + instance_build_dir = os.path.join('some', 'far', 'off', 'build', 'dir') + instance = mock.Mock(build_dir=instance_build_dir) + + def mock_makedirs(path, exist_ok=False): + assert exist_ok + assert path == instance_build_dir + + def mock_symlink(source, target): + assert source == instance_build_dir + assert target == os.path.join('links', 'path', 'test_0') + + def mock_call(cmd, shell=False): + assert shell + assert cmd == ['mklink', '/J', os.path.join('links', 'path', 'test_0'), + instance_build_dir] + + with mock.patch('os.name', os_name), \ + mock.patch('os.symlink', side_effect=mock_symlink), \ + mock.patch('os.makedirs', side_effect=mock_makedirs), \ + mock.patch('subprocess.call', side_effect=mock_call): + testplan._create_build_dir_link(links_dir_path, instance) + + assert instance.build_dir == os.path.join('links', 'path', 'test_0') + assert testplan.link_dir_counter == 1 + + +TESTDATA_14 = [ + ('bad platform', 'dummy reason', [], + 'dummy status', 'dummy reason'), + ('good platform', 'quarantined', [], + 'error', 'quarantined but is one of the integration platforms'), + ('good platform', 'dummy reason', [{'type': 'command line filter'}], + 'dummy status', 'dummy reason'), + ('good platform', 'dummy reason', [{'type': 'Skip filter'}], + 'dummy status', 'dummy reason'), + ('good platform', 'dummy reason', [{'type': 'platform key filter'}], + 'dummy status', 'dummy reason'), + ('good platform', 'dummy reason', [{'type': 'Toolchain filter'}], + 'dummy status', 'dummy reason'), + ('good platform', 'dummy reason', [{'type': 'Module filter'}], + 'dummy status', 'dummy reason'), + ('good platform', 'dummy reason', [{'type': 'testsuite filter'}], + 'error', 'dummy reason but is one of the integration platforms'), +] + +@pytest.mark.parametrize( + 'platform_name, reason, filters,' \ + ' expected_status, expected_reason', + TESTDATA_14, + ids=['wrong platform', 'quarantined', 'command line filtered', + 'skip filtered', 'platform key filtered', 'toolchain filtered', + 'module filtered', 'skip to error change'] +) +def test_change_skip_to_error_if_integration( + platform_name, + reason, + filters, + expected_status, + expected_reason +): + options = mock.Mock() + platform = mock.Mock() + platform.name = platform_name + testsuite = mock.Mock(integration_platforms=['good platform', 'a platform']) + instance = mock.Mock( + testsuite=testsuite, + platform=platform, + filters=filters, + status='dummy status', + reason=reason + ) + + change_skip_to_error_if_integration(options, instance) + + assert instance.status == expected_status + assert instance.reason == expected_reason From 97757e48d67c6c55265b5048a00fa3f23e964600 Mon Sep 17 00:00:00 2001 From: Lukasz Mrugala Date: Tue, 5 Dec 2023 14:26:39 +0000 Subject: [PATCH 1773/3723] scripts: tests: twister: Platform module test expansion Added a unit test for the platform.py module. It covers 99% of the code. The 1% is unreachable. Signed-off-by: Lukasz Mrugala --- scripts/tests/twister/test_platform.py | 129 +++++++++++++++++++++++++ 1 file changed, 129 insertions(+) create mode 100644 scripts/tests/twister/test_platform.py diff --git a/scripts/tests/twister/test_platform.py b/scripts/tests/twister/test_platform.py new file mode 100644 index 00000000000..c40a10a9b78 --- /dev/null +++ b/scripts/tests/twister/test_platform.py @@ -0,0 +1,129 @@ +#!/usr/bin/env python3 +# Copyright (c) 2023 Intel Corporation +# +# SPDX-License-Identifier: Apache-2.0 + +''' +This test file contains tests for platform.py module of twister +''' +import sys +import os +import mock +import pytest + +ZEPHYR_BASE = os.getenv("ZEPHYR_BASE") +sys.path.insert(0, os.path.join(ZEPHYR_BASE, "scripts/pylib/twister")) + +from twisterlib.platform import Platform + + +TESTDATA_1 = [ + ( +"""\ +identifier: dummy empty +arch: arch0 +""", + { + 'name': 'dummy empty', + 'arch': 'arch0', + 'twister': True, + 'ram': 128, + 'timeout_multiplier': 1.0, + 'ignore_tags': [], + 'only_tags': [], + 'default': False, + 'binaries': [], + 'flash': 512, + 'supported': set(), + 'vendor': '', + 'tier': -1, + 'type': 'na', + 'simulation': 'na', + 'simulation_exec': None, + 'supported_toolchains': [], + 'env': [], + 'env_satisfied': True + }, + '' + ), + ( +"""\ +identifier: dummy full +arch: riscv32 +twister: true +ram: 1024 +testing: + timeout_multiplier: 2.0 + ignore_tags: + - tag1 + - tag2 + only_tags: + - tag3 + default: true + binaries: + - dummy.exe + - dummy.bin +flash: 4096 +supported: + - ble + - netif:openthread + - gpio +vendor: vendor1 +tier: 1 +type: unit +simulation: nsim +simulation_exec: nsimdrv +toolchain: + - zephyr + - llvm +env: + - dummynonexistentvar +""", + { + 'name': 'dummy full', + 'arch': 'riscv32', + 'twister': True, + 'ram': 1024, + 'timeout_multiplier': 2.0, + 'ignore_tags': ['tag1', 'tag2'], + 'only_tags': ['tag3'], + 'default': True, + 'binaries': ['dummy.exe', 'dummy.bin'], + 'flash': 4096, + 'supported': set(['ble', 'netif', 'openthread', 'gpio']), + 'vendor': 'vendor1', + 'tier': 1, + 'type': 'unit', + 'simulation': 'nsim', + 'simulation_exec': 'nsimdrv', + 'supported_toolchains': ['zephyr', 'llvm', 'cross-compile', 'xtools'], + 'env': ['dummynonexistentvar'], + 'env_satisfied': False + }, + '' + ), +] + +@pytest.mark.parametrize( + 'platform_text, expected_data, expected_repr', + TESTDATA_1, + ids=['almost empty specification', 'full specification'] +) +def test_platform_load(platform_text, expected_data, expected_repr): + platform = Platform() + + with mock.patch('builtins.open', mock.mock_open(read_data=platform_text)): + platform.load('dummy.yaml') + + for k, v in expected_data.items(): + if not hasattr(platform, k): + assert False, f'No key {k} in platform {platform}' + att = getattr(platform, k) + if isinstance(v, list) and not isinstance(att, list): + assert False, f'Value mismatch in key {k} in platform {platform}' + if isinstance(v, list): + assert sorted(att) == sorted(v) + else: + assert att == v + + assert platform.__repr__() == expected_repr From cf174804fb07023e653b2617f4c2cc385a433290 Mon Sep 17 00:00:00 2001 From: Piotr Narajowski Date: Tue, 5 Dec 2023 15:08:38 +0100 Subject: [PATCH 1774/3723] bluetooth: tester: Add CCP Tests Adding support for remaining CCP test cases. Also removing callback descriptions from btp files not to get confused with header files. Signed-off-by: Piotr Narajowski --- tests/bluetooth/tester/overlay-le-audio.conf | 4 +- tests/bluetooth/tester/src/btp/btp_ccp.h | 156 ++++ tests/bluetooth/tester/src/btp_ccp.c | 736 ++++++++++++++++--- 3 files changed, 792 insertions(+), 104 deletions(-) diff --git a/tests/bluetooth/tester/overlay-le-audio.conf b/tests/bluetooth/tester/overlay-le-audio.conf index 330ea3c6b99..eb2abbf1a68 100644 --- a/tests/bluetooth/tester/overlay-le-audio.conf +++ b/tests/bluetooth/tester/overlay-le-audio.conf @@ -98,7 +98,9 @@ CONFIG_BT_CSIP_SET_MEMBER=y # CCP CONFIG_BT_ATT_TX_COUNT=12 CONFIG_BT_TBS_CLIENT_GTBS=y -CONFIG_BT_TBS_CLIENT_TBS=n +CONFIG_BT_TBS_CLIENT_TBS=y +CONFIG_BT_TBS_CLIENT_CCID=y +CONFIG_BT_TBS_CLIENT_MAX_CALLS=2 # CAS CONFIG_BT_CAP_ACCEPTOR=y diff --git a/tests/bluetooth/tester/src/btp/btp_ccp.h b/tests/bluetooth/tester/src/btp/btp_ccp.h index 1792637de2e..cfaee2bf8bf 100644 --- a/tests/bluetooth/tester/src/btp/btp_ccp.h +++ b/tests/bluetooth/tester/src/btp/btp_ccp.h @@ -46,6 +46,113 @@ struct btp_ccp_read_call_state_cmd { uint8_t inst_index; } __packed; +#define BTP_CCP_READ_BEARER_NAME 0x07 +struct btp_ccp_read_bearer_name_cmd { + bt_addr_le_t address; + uint8_t inst_index; +} __packed; + +#define BTP_CCP_READ_BEARER_UCI 0x08 +struct btp_ccp_read_bearer_uci_cmd { + bt_addr_le_t address; + uint8_t inst_index; +} __packed; + +#define BTP_CCP_READ_BEARER_TECH 0x09 +struct btp_ccp_read_bearer_technology_cmd { + bt_addr_le_t address; + uint8_t inst_index; +} __packed; + +#define BTP_CCP_READ_URI_LIST 0x0a +struct btp_ccp_read_uri_list_cmd { + bt_addr_le_t address; + uint8_t inst_index; +} __packed; + +#define BTP_CCP_READ_SIGNAL_STRENGTH 0x0b +struct btp_ccp_read_signal_strength_cmd { + bt_addr_le_t address; + uint8_t inst_index; +} __packed; + +#define BTP_CCP_READ_SIGNAL_INTERVAL 0x0c +struct btp_ccp_read_signal_interval_cmd { + bt_addr_le_t address; + uint8_t inst_index; +} __packed; + +#define BTP_CCP_READ_CURRENT_CALLS 0x0d +struct btp_ccp_read_current_calls_cmd { + bt_addr_le_t address; + uint8_t inst_index; +} __packed; + +#define BTP_CCP_READ_CCID 0x0e +struct btp_ccp_read_ccid_cmd { + bt_addr_le_t address; + uint8_t inst_index; +} __packed; + +#define BTP_CCP_READ_CALL_URI 0x0f +struct btp_ccp_read_call_uri_cmd { + bt_addr_le_t address; + uint8_t inst_index; +} __packed; + +#define BTP_CCP_READ_STATUS_FLAGS 0x10 +struct btp_ccp_read_status_flags_cmd { + bt_addr_le_t address; + uint8_t inst_index; +} __packed; + +#define BTP_CCP_READ_OPTIONAL_OPCODES 0x11 +struct btp_ccp_read_optional_opcodes_cmd { + bt_addr_le_t address; + uint8_t inst_index; +} __packed; + +#define BTP_CCP_READ_FRIENDLY_NAME 0x12 +struct btp_ccp_read_friendly_name_cmd { + bt_addr_le_t address; + uint8_t inst_index; +} __packed; + +#define BTP_CCP_READ_REMOTE_URI 0x13 +struct btp_ccp_read_remote_uri_cmd { + bt_addr_le_t address; + uint8_t inst_index; +} __packed; + +#define BTP_CCP_SET_SIGNAL_INTERVAL 0x14 +struct btp_ccp_set_signal_interval_cmd { + bt_addr_le_t address; + uint8_t inst_index; + uint8_t interval; +} __packed; + +#define BTP_CCP_HOLD_CALL 0x15 +struct btp_ccp_hold_call_cmd { + bt_addr_le_t address; + uint8_t inst_index; + uint8_t call_id; +} __packed; + +#define BTP_CCP_RETRIEVE_CALL 0x16 +struct btp_ccp_retrieve_call_cmd { + bt_addr_le_t address; + uint8_t inst_index; + uint8_t call_id; +} __packed; + +#define BTP_CCP_JOIN_CALLS 0x17 +struct btp_ccp_join_calls_cmd { + bt_addr_le_t address; + uint8_t inst_index; + uint8_t count; + uint8_t call_index[]; +} __packed; + /* CCP events */ #define BTP_CCP_EV_DISCOVERED 0x80 struct btp_ccp_discovered_ev { @@ -61,3 +168,52 @@ struct btp_ccp_call_states_ev { uint8_t call_count; struct bt_tbs_client_call_state call_states[0]; } __packed; + +#define BTP_CCP_EV_CHRC_HANDLES 0x82 +struct btp_ccp_chrc_handles_ev { + uint16_t provider_name; + uint16_t bearer_uci; + uint16_t bearer_technology; + uint16_t uri_list; + uint16_t signal_strength; + uint16_t signal_interval; + uint16_t current_calls; + uint16_t ccid; + uint16_t status_flags; + uint16_t bearer_uri; + uint16_t call_state; + uint16_t control_point; + uint16_t optional_opcodes; + uint16_t termination_reason; + uint16_t incoming_call; + uint16_t friendly_name; +}; + +#define BTP_CCP_EV_CHRC_VAL 0x83 +struct btp_ccp_chrc_val_ev { + bt_addr_le_t address; + uint8_t status; + uint8_t inst_index; + uint8_t value; +}; + +#define BTP_CCP_EV_CHRC_STR 0x84 +struct btp_ccp_chrc_str_ev { + bt_addr_le_t address; + uint8_t status; + uint8_t inst_index; + uint8_t data_len; + char data[0]; +} __packed; + +#define BTP_CCP_EV_CP 0x85 +struct btp_ccp_cp_ev { + bt_addr_le_t address; + uint8_t status; +} __packed; + +#define BTP_CCP_EV_CURRENT_CALLS 0x86 +struct btp_ccp_current_calls_ev { + bt_addr_le_t address; + uint8_t status; +} __packed; diff --git a/tests/bluetooth/tester/src/btp_ccp.c b/tests/bluetooth/tester/src/btp_ccp.c index 6c0d18258c3..aad1431a883 100644 --- a/tests/bluetooth/tester/src/btp_ccp.c +++ b/tests/bluetooth/tester/src/btp_ccp.c @@ -9,10 +9,17 @@ #include "zephyr/sys/byteorder.h" #include +#include <../../subsys/bluetooth/audio/tbs_internal.h> + #include #define LOG_MODULE_NAME bttester_ccp LOG_MODULE_REGISTER(LOG_MODULE_NAME, CONFIG_BTTESTER_LOG_LEVEL); +struct btp_ccp_chrc_handles_ev tbs_handles; +struct bt_tbs_instance *tbs_inst; +static uint8_t inst_ccid; +static bool send_ev; + static uint8_t ccp_supported_commands(const void *cmd, uint16_t cmd_len, void *rsp, uint16_t *rsp_len) { @@ -25,6 +32,29 @@ static uint8_t ccp_supported_commands(const void *cmd, uint16_t cmd_len, tester_set_bit(rp->data, BTP_CCP_TERMINATE_CALL); tester_set_bit(rp->data, BTP_CCP_ORIGINATE_CALL); tester_set_bit(rp->data, BTP_CCP_READ_CALL_STATE); + tester_set_bit(rp->data, BTP_CCP_READ_BEARER_NAME); + + /* octet 1 */ + tester_set_bit(rp->data, BTP_CCP_READ_BEARER_UCI); + tester_set_bit(rp->data, BTP_CCP_READ_BEARER_TECH); + tester_set_bit(rp->data, BTP_CCP_READ_URI_LIST); + tester_set_bit(rp->data, BTP_CCP_READ_SIGNAL_STRENGTH); + tester_set_bit(rp->data, BTP_CCP_READ_SIGNAL_INTERVAL); + tester_set_bit(rp->data, BTP_CCP_READ_CURRENT_CALLS); + tester_set_bit(rp->data, BTP_CCP_READ_CCID); + + /* octet 2 */ + tester_set_bit(rp->data, BTP_CCP_READ_CALL_URI); + tester_set_bit(rp->data, BTP_CCP_READ_STATUS_FLAGS); + tester_set_bit(rp->data, BTP_CCP_READ_OPTIONAL_OPCODES); + tester_set_bit(rp->data, BTP_CCP_READ_FRIENDLY_NAME); + tester_set_bit(rp->data, BTP_CCP_READ_REMOTE_URI); + tester_set_bit(rp->data, BTP_CCP_SET_SIGNAL_INTERVAL); + tester_set_bit(rp->data, BTP_CCP_HOLD_CALL); + + /* octet 3 */ + tester_set_bit(rp->data, BTP_CCP_RETRIEVE_CALL); + tester_set_bit(rp->data, BTP_CCP_JOIN_CALLS); *rsp_len = sizeof(*rp) + 1; @@ -42,96 +72,100 @@ static void tbs_client_discovered_ev(int err, uint8_t tbs_count, bool gtbs_found tester_event(BTP_SERVICE_ID_CCP, BTP_CCP_EV_DISCOVERED, &ev, sizeof(ev)); } -/** - * @brief Callback function for ccp_discover. - * - * @param conn The connection that was used to discover CCP for a - * device. - * @param err Error value. BT_TBS_CLIENT_RESULT_CODE_*, - * GATT error or errno value. - * @param tbs_count Number of TBS instances on peer device. - * @param gtbs_found Whether or not the server has a Generic TBS instance. - */ -static void tbs_client_discover_cb(struct bt_conn *conn, - int err, - uint8_t tbs_count, - bool gtbs_found) +static void tbs_chrc_handles_ev(struct btp_ccp_chrc_handles_ev *tbs_handles) { - LOG_DBG("Discovered TBS - err (%u) GTBS (%u)", err, gtbs_found); + struct btp_ccp_chrc_handles_ev ev; + + ev.provider_name = sys_cpu_to_le16(tbs_handles->provider_name); + ev.bearer_uci = sys_cpu_to_le16(tbs_handles->bearer_uci); + ev.bearer_technology = sys_cpu_to_le16(tbs_handles->bearer_technology); + ev.uri_list = sys_cpu_to_le16(tbs_handles->uri_list); + ev.signal_strength = sys_cpu_to_le16(tbs_handles->signal_strength); + ev.signal_interval = sys_cpu_to_le16(tbs_handles->signal_interval); + ev.current_calls = sys_cpu_to_le16(tbs_handles->current_calls); + ev.ccid = sys_cpu_to_le16(tbs_handles->ccid); + ev.status_flags = sys_cpu_to_le16(tbs_handles->status_flags); + ev.bearer_uri = sys_cpu_to_le16(tbs_handles->bearer_uri); + ev.call_state = sys_cpu_to_le16(tbs_handles->call_state); + ev.control_point = sys_cpu_to_le16(tbs_handles->control_point); + ev.optional_opcodes = sys_cpu_to_le16(tbs_handles->optional_opcodes); + ev.termination_reason = sys_cpu_to_le16(tbs_handles->termination_reason); + ev.incoming_call = sys_cpu_to_le16(tbs_handles->incoming_call); + ev.friendly_name = sys_cpu_to_le16(tbs_handles->friendly_name); + + tester_event(BTP_SERVICE_ID_CCP, BTP_CCP_EV_CHRC_HANDLES, &ev, sizeof(ev)); +} - tbs_client_discovered_ev(err, tbs_count, gtbs_found); +static void tbs_client_chrc_val_ev(struct bt_conn *conn, uint8_t status, uint8_t inst_index, + uint32_t value) +{ + struct btp_ccp_chrc_val_ev ev; + + bt_addr_le_copy(&ev.address, bt_conn_get_dst(conn)); + + ev.status = status; + ev.inst_index = inst_index; + ev.value = value; + + tester_event(BTP_SERVICE_ID_CCP, BTP_CCP_EV_CHRC_VAL, &ev, sizeof(ev)); } -/** - * @brief Callback function for the CCP call control functions. - * - * @param conn The connection used in the function. - * @param err Error value. BT_TBS_CLIENT_RESULT_CODE_*, - * GATT error or errno value. - * @param inst_index The index of the TBS instance that was updated. - * @param call_index The call index. For #bt_tbs_client_originate_call this will - * always be 0, and does not reflect the actual call index. - */ -static void tbs_client_originate_call_cb(struct bt_conn *conn, - int err, - uint8_t inst_index, - uint8_t call_index) +static void tbs_client_chrc_str_ev(struct bt_conn *conn, uint8_t status, uint8_t inst_index, + uint8_t data_len, const char *data) { - LOG_DBG("Originate call - err (%u) Call Index (%u)", err, call_index); + struct btp_ccp_chrc_str_ev *ev; + + tester_rsp_buffer_lock(); + tester_rsp_buffer_allocate(sizeof(*ev) + data_len, (uint8_t **)&ev); + bt_addr_le_copy(&ev->address, bt_conn_get_dst(conn)); + ev->status = status; + ev->inst_index = inst_index; + ev->data_len = data_len; + memcpy(ev->data, data, data_len); + + tester_event(BTP_SERVICE_ID_CCP, BTP_CCP_EV_CHRC_STR, ev, sizeof(*ev) + data_len); + + tester_rsp_buffer_free(); + tester_rsp_buffer_unlock(); } -/** - * @brief Callback function for the CCP call control functions. - * - * @param conn The connection used in the function. - * @param err Error value. BT_TBS_CLIENT_RESULT_CODE_*, - * GATT error or errno value. - * @param inst_index The index of the TBS instance that was updated. - * @param call_index The call index. For #bt_tbs_client_originate_call this will - * always be 0, and does not reflect the actual call index. - */ -static void tbs_client_terminate_call_cb(struct bt_conn *conn, - int err, - uint8_t inst_index, - uint8_t call_index) +static void tbs_client_cp_ev(struct bt_conn *conn, uint8_t status) { - LOG_DBG("Terminate call - err (%u) Call Index (%u)", err, call_index); + struct btp_ccp_cp_ev ev; + + bt_addr_le_copy(&ev.address, bt_conn_get_dst(conn)); + + ev.status = status; + + tester_event(BTP_SERVICE_ID_CCP, BTP_CCP_EV_CP, &ev, sizeof(ev)); } -/** - * @brief Callback function for the CCP call control functions. - * - * @param conn The connection used in the function. - * @param err Error value. BT_TBS_CLIENT_RESULT_CODE_*, - * GATT error or errno value. - * @param inst_index The index of the TBS instance that was updated. - * @param call_index The call index. For #bt_tbs_client_originate_call this will - * always be 0, and does not reflect the actual call index. - */ -static void tbs_client_accept_call_cb(struct bt_conn *conn, - int err, - uint8_t inst_index, - uint8_t call_index) +static void tbs_client_current_calls_ev(struct bt_conn *conn, uint8_t status) { - LOG_DBG("Accept call - err (%u) Call Index (%u)", err, call_index); + struct btp_ccp_current_calls_ev ev; + + bt_addr_le_copy(&ev.address, bt_conn_get_dst(conn)); + + ev.status = status; + + tester_event(BTP_SERVICE_ID_CCP, BTP_CCP_EV_CURRENT_CALLS, &ev, sizeof(ev)); } -/** - * @brief Callback function for the CCP call control functions. - * - * @param conn The connection used in the function. - * @param err Error value. BT_TBS_CLIENT_RESULT_CODE_*, - * GATT error or errno value. - * @param inst_index The index of the TBS instance that was updated. - * @param call_index The call index. For #bt_tbs_client_originate_call this will - * always be 0, and does not reflect the actual call index. - */ -static void tbs_client_retrieve_call_cb(struct bt_conn *conn, - int err, - uint8_t inst_index, - uint8_t call_index) +static void tbs_client_discover_cb(struct bt_conn *conn, int err, uint8_t tbs_count, + bool gtbs_found) { - LOG_DBG("Retrieve call - err (%u) Call Index (%u)", err, call_index); + if (err) { + LOG_DBG("Discovery Failed (%d)", err); + return; + } + + LOG_DBG("Discovered TBS - err (%u) GTBS (%u)", err, gtbs_found); + + bt_tbs_client_read_ccid(conn, 0xFF); + + tbs_client_discovered_ev(err, tbs_count, gtbs_found); + + send_ev = true; } typedef struct bt_tbs_client_call_state bt_tbs_client_call_state_t; @@ -160,17 +194,6 @@ static void tbs_client_call_states_ev(int err, tester_event(BTP_SERVICE_ID_CCP, BTP_CCP_EV_CALL_STATES, buf->data, buf->len); } -/** - * @brief Callback function for ccp_read_call_state. - * - * @param conn The connection used in the function. - * @param err Error value. BT_TBS_CLIENT_RESULT_CODE_*, - * GATT error or errno value. - * @param inst_index The index of the TBS instance that was updated. - * @param call_count Number of call states read. - * @param call_states Array of call states. The array is not kept by - * the client, so must be copied to be saved. - */ static void tbs_client_call_states_cb(struct bt_conn *conn, int err, uint8_t inst_index, @@ -182,16 +205,6 @@ static void tbs_client_call_states_cb(struct bt_conn *conn, tbs_client_call_states_ev(err, inst_index, call_count, call_states); } -/** - * @brief Callback function for ccp_read_termination_reason. - * - * @param conn The connection used in the function. - * @param err Error value. BT_TBS_CLIENT_RESULT_CODE_*, - * GATT error or errno value. - * @param inst_index The index of the TBS instance that was updated. - * @param call_index The call index. - * @param reason The termination reason. - */ static void tbs_client_termination_reason_cb(struct bt_conn *conn, int err, uint8_t inst_index, @@ -202,14 +215,90 @@ static void tbs_client_termination_reason_cb(struct bt_conn *conn, err, call_index, reason); } +static void tbs_client_read_string_cb(struct bt_conn *conn, int err, uint8_t inst_index, + const char *value) +{ + LOG_DBG("TBS Client read string characteristic value cb"); + + uint8_t data_len = strlen(value); + + tbs_client_chrc_str_ev(conn, err ? BTP_STATUS_FAILED : BTP_STATUS_SUCCESS, inst_index, + data_len, value); +} + +static void tbs_client_read_val_cb(struct bt_conn *conn, int err, uint8_t inst_index, + uint32_t value) +{ + LOG_DBG("TBS Client read characteristic value cb"); + + tbs_client_chrc_val_ev(conn, err ? BTP_STATUS_FAILED : BTP_STATUS_SUCCESS, inst_index, + value); + + if (send_ev == true) { + inst_ccid = value; + + tbs_inst = bt_tbs_client_get_by_ccid(conn, inst_ccid); + + tbs_handles.provider_name = tbs_inst->name_sub_params.value_handle; + tbs_handles.bearer_uci = tbs_inst->bearer_uci_handle; + tbs_handles.bearer_technology = tbs_inst->technology_sub_params.value_handle; + tbs_handles.uri_list = tbs_inst->uri_list_handle; + tbs_handles.signal_strength = tbs_inst->signal_strength_sub_params.value_handle; + tbs_handles.signal_interval = tbs_inst->signal_interval_handle; + tbs_handles.current_calls = tbs_inst->current_calls_sub_params.value_handle; + tbs_handles.ccid = tbs_inst->ccid_handle; + tbs_handles.status_flags = tbs_inst->status_flags_sub_params.value_handle; + tbs_handles.bearer_uri = tbs_inst->in_target_uri_sub_params.value_handle; + tbs_handles.call_state = tbs_inst->call_state_sub_params.value_handle; + tbs_handles.control_point = tbs_inst->call_cp_sub_params.value_handle; + tbs_handles.optional_opcodes = tbs_inst->optional_opcodes_handle; + tbs_handles.termination_reason = tbs_inst->termination_reason_handle; + tbs_handles.incoming_call = tbs_inst->incoming_call_sub_params.value_handle; + tbs_handles.friendly_name = tbs_inst->friendly_name_sub_params.value_handle; + + tbs_chrc_handles_ev(&tbs_handles); + send_ev = false; + } +} + +static void tbs_client_current_calls_cb(struct bt_conn *conn, int err, uint8_t inst_index, + uint8_t call_count, const struct bt_tbs_client_call *calls) +{ + LOG_DBG(""); + + tbs_client_current_calls_ev(conn, err); +} + +static void tbs_client_cp_cb(struct bt_conn *conn, int err, uint8_t inst_index, uint8_t call_index) +{ + LOG_DBG(""); + + tbs_client_cp_ev(conn, err); +} + static const struct bt_tbs_client_cb tbs_client_callbacks = { .discover = tbs_client_discover_cb, - .originate_call = tbs_client_originate_call_cb, - .terminate_call = tbs_client_terminate_call_cb, - .accept_call = tbs_client_accept_call_cb, - .retrieve_call = tbs_client_retrieve_call_cb, + .originate_call = tbs_client_cp_cb, + .terminate_call = tbs_client_cp_cb, .call_state = tbs_client_call_states_cb, - .termination_reason = tbs_client_termination_reason_cb + .termination_reason = tbs_client_termination_reason_cb, + .bearer_provider_name = tbs_client_read_string_cb, + .bearer_uci = tbs_client_read_string_cb, + .technology = tbs_client_read_val_cb, + .uri_list = tbs_client_read_string_cb, + .signal_strength = tbs_client_read_val_cb, + .signal_interval = tbs_client_read_val_cb, + .current_calls = tbs_client_current_calls_cb, + .ccid = tbs_client_read_val_cb, + .call_uri = tbs_client_read_string_cb, + .status_flags = tbs_client_read_val_cb, + .optional_opcodes = tbs_client_read_val_cb, + .friendly_name = tbs_client_read_string_cb, + .remote_uri = tbs_client_read_string_cb, + .accept_call = tbs_client_cp_cb, + .hold_call = tbs_client_cp_cb, + .retrieve_call = tbs_client_cp_cb, + .join_calls = tbs_client_cp_cb, }; static uint8_t ccp_discover_tbs(const void *cmd, uint16_t cmd_len, @@ -293,6 +382,362 @@ static uint8_t ccp_read_call_state(const void *cmd, uint16_t cmd_len, return BTP_STATUS_VAL(err); } +static uint8_t ccp_read_bearer_name(const void *cmd, uint16_t cmd_len, void *rsp, + uint16_t *rsp_len) +{ + const struct btp_ccp_read_bearer_name_cmd *cp = cmd; + struct bt_conn *conn; + int err; + + conn = bt_conn_lookup_addr_le(BT_ID_DEFAULT, &cp->address); + if (!conn) { + LOG_ERR("Unknown connection"); + return BTP_STATUS_FAILED; + } + + err = bt_tbs_client_read_bearer_provider_name(conn, cp->inst_index); + if (err) { + return BTP_STATUS_FAILED; + } + + return BTP_STATUS_SUCCESS; +} + +static uint8_t ccp_read_bearer_uci(const void *cmd, uint16_t cmd_len, void *rsp, + uint16_t *rsp_len) +{ + const struct btp_ccp_read_bearer_uci_cmd *cp = cmd; + struct bt_conn *conn; + int err; + + conn = bt_conn_lookup_addr_le(BT_ID_DEFAULT, &cp->address); + if (!conn) { + LOG_ERR("Unknown connection"); + return BTP_STATUS_FAILED; + } + + err = bt_tbs_client_read_bearer_uci(conn, cp->inst_index); + if (err) { + return BTP_STATUS_FAILED; + } + + return BTP_STATUS_SUCCESS; +} + +static uint8_t ccp_read_bearer_tech(const void *cmd, uint16_t cmd_len, void *rsp, + uint16_t *rsp_len) +{ + const struct btp_ccp_read_bearer_technology_cmd *cp = cmd; + struct bt_conn *conn; + int err; + + conn = bt_conn_lookup_addr_le(BT_ID_DEFAULT, &cp->address); + if (!conn) { + LOG_ERR("Unknown connection"); + return BTP_STATUS_FAILED; + } + + err = bt_tbs_client_read_technology(conn, cp->inst_index); + if (err) { + return BTP_STATUS_FAILED; + } + + return BTP_STATUS_SUCCESS; +} + +static uint8_t ccp_read_uri_list(const void *cmd, uint16_t cmd_len, void *rsp, uint16_t *rsp_len) +{ + const struct btp_ccp_read_uri_list_cmd *cp = cmd; + struct bt_conn *conn; + int err; + + conn = bt_conn_lookup_addr_le(BT_ID_DEFAULT, &cp->address); + if (!conn) { + LOG_ERR("Unknown connection"); + return BTP_STATUS_FAILED; + } + + err = bt_tbs_client_read_uri_list(conn, cp->inst_index); + if (err) { + return BTP_STATUS_FAILED; + } + + return BTP_STATUS_SUCCESS; +} + +static uint8_t ccp_read_signal_strength(const void *cmd, uint16_t cmd_len, void *rsp, + uint16_t *rsp_len) +{ + const struct btp_ccp_read_signal_strength_cmd *cp = cmd; + struct bt_conn *conn; + int err; + + conn = bt_conn_lookup_addr_le(BT_ID_DEFAULT, &cp->address); + if (!conn) { + LOG_ERR("Unknown connection"); + return BTP_STATUS_FAILED; + } + + err = bt_tbs_client_read_signal_strength(conn, cp->inst_index); + if (err) { + return BTP_STATUS_FAILED; + } + + return BTP_STATUS_SUCCESS; +} + +static uint8_t ccp_read_signal_interval(const void *cmd, uint16_t cmd_len, void *rsp, + uint16_t *rsp_len) +{ + const struct btp_ccp_read_signal_interval_cmd *cp = cmd; + struct bt_conn *conn; + int err; + + conn = bt_conn_lookup_addr_le(BT_ID_DEFAULT, &cp->address); + if (!conn) { + LOG_ERR("Unknown connection"); + return BTP_STATUS_FAILED; + } + + err = bt_tbs_client_read_signal_interval(conn, cp->inst_index); + if (err) { + return BTP_STATUS_FAILED; + } + + return BTP_STATUS_SUCCESS; +} + +static uint8_t ccp_read_current_calls(const void *cmd, uint16_t cmd_len, void *rsp, + uint16_t *rsp_len) +{ + const struct btp_ccp_read_current_calls_cmd *cp = cmd; + struct bt_conn *conn; + int err; + + conn = bt_conn_lookup_addr_le(BT_ID_DEFAULT, &cp->address); + if (!conn) { + LOG_ERR("Unknown connection"); + return BTP_STATUS_FAILED; + } + + err = bt_tbs_client_read_current_calls(conn, cp->inst_index); + if (err) { + return BTP_STATUS_FAILED; + } + + return BTP_STATUS_SUCCESS; +} + +static uint8_t ccp_read_ccid(const void *cmd, uint16_t cmd_len, void *rsp, + uint16_t *rsp_len) +{ + const struct btp_ccp_read_ccid_cmd *cp = cmd; + struct bt_conn *conn; + int err; + + conn = bt_conn_lookup_addr_le(BT_ID_DEFAULT, &cp->address); + if (!conn) { + LOG_ERR("Unknown connection"); + return BTP_STATUS_FAILED; + } + + err = bt_tbs_client_read_ccid(conn, cp->inst_index); + if (err) { + return BTP_STATUS_FAILED; + } + + return BTP_STATUS_SUCCESS; +} + +static uint8_t ccp_read_call_uri(const void *cmd, uint16_t cmd_len, void *rsp, + uint16_t *rsp_len) +{ + const struct btp_ccp_read_call_uri_cmd *cp = cmd; + struct bt_conn *conn; + int err; + + conn = bt_conn_lookup_addr_le(BT_ID_DEFAULT, &cp->address); + if (!conn) { + LOG_ERR("Unknown connection"); + return BTP_STATUS_FAILED; + } + + err = bt_tbs_client_read_call_uri(conn, cp->inst_index); + if (err) { + return BTP_STATUS_FAILED; + } + + return BTP_STATUS_SUCCESS; +} + +static uint8_t ccp_read_status_flags(const void *cmd, uint16_t cmd_len, void *rsp, + uint16_t *rsp_len) +{ + const struct btp_ccp_read_status_flags_cmd *cp = cmd; + struct bt_conn *conn; + int err; + + conn = bt_conn_lookup_addr_le(BT_ID_DEFAULT, &cp->address); + if (!conn) { + LOG_ERR("Unknown connection"); + return BTP_STATUS_FAILED; + } + + err = bt_tbs_client_read_status_flags(conn, cp->inst_index); + if (err) { + return BTP_STATUS_FAILED; + } + + return BTP_STATUS_SUCCESS; +} + +static uint8_t ccp_read_optional_opcodes(const void *cmd, uint16_t cmd_len, void *rsp, + uint16_t *rsp_len) +{ + const struct btp_ccp_read_optional_opcodes_cmd *cp = cmd; + struct bt_conn *conn; + int err; + + conn = bt_conn_lookup_addr_le(BT_ID_DEFAULT, &cp->address); + if (!conn) { + LOG_ERR("Unknown connection"); + return BTP_STATUS_FAILED; + } + + err = bt_tbs_client_read_optional_opcodes(conn, cp->inst_index); + if (err) { + return BTP_STATUS_FAILED; + } + + return BTP_STATUS_SUCCESS; +} + +static uint8_t ccp_read_friendly_name(const void *cmd, uint16_t cmd_len, void *rsp, + uint16_t *rsp_len) +{ + const struct btp_ccp_read_friendly_name_cmd *cp = cmd; + struct bt_conn *conn; + int err; + + conn = bt_conn_lookup_addr_le(BT_ID_DEFAULT, &cp->address); + if (!conn) { + LOG_ERR("Unknown connection"); + return BTP_STATUS_FAILED; + } + + err = bt_tbs_client_read_friendly_name(conn, cp->inst_index); + if (err) { + return BTP_STATUS_FAILED; + } + + return BTP_STATUS_SUCCESS; +} + +static uint8_t ccp_read_remote_uri(const void *cmd, uint16_t cmd_len, void *rsp, + uint16_t *rsp_len) +{ + const struct btp_ccp_read_remote_uri_cmd *cp = cmd; + struct bt_conn *conn; + int err; + + conn = bt_conn_lookup_addr_le(BT_ID_DEFAULT, &cp->address); + if (!conn) { + LOG_ERR("Unknown connection"); + return BTP_STATUS_FAILED; + } + + err = bt_tbs_client_read_remote_uri(conn, cp->inst_index); + if (err) { + return BTP_STATUS_FAILED; + } + + return BTP_STATUS_SUCCESS; +} + +static uint8_t ccp_set_signal_interval(const void *cmd, uint16_t cmd_len, void *rsp, + uint16_t *rsp_len) +{ + const struct btp_ccp_set_signal_interval_cmd *cp = cmd; + struct bt_conn *conn; + int err; + + conn = bt_conn_lookup_addr_le(BT_ID_DEFAULT, &cp->address); + if (!conn) { + LOG_ERR("Unknown connection"); + return BTP_STATUS_FAILED; + } + + err = bt_tbs_client_set_signal_strength_interval(conn, cp->inst_index, cp->interval); + if (err) { + return BTP_STATUS_FAILED; + } + + return BTP_STATUS_SUCCESS; +} + +static uint8_t ccp_hold_call(const void *cmd, uint16_t cmd_len, void *rsp, uint16_t *rsp_len) +{ + const struct btp_ccp_hold_call_cmd *cp = cmd; + struct bt_conn *conn; + int err; + + conn = bt_conn_lookup_addr_le(BT_ID_DEFAULT, &cp->address); + if (!conn) { + LOG_ERR("Unknown connection"); + return BTP_STATUS_FAILED; + } + + err = bt_tbs_client_hold_call(conn, cp->inst_index, cp->call_id); + if (err) { + return BTP_STATUS_FAILED; + } + + return BTP_STATUS_SUCCESS; +} + +static uint8_t ccp_retrieve_call(const void *cmd, uint16_t cmd_len, void *rsp, uint16_t *rsp_len) +{ + const struct btp_ccp_retrieve_call_cmd *cp = cmd; + struct bt_conn *conn; + int err; + + conn = bt_conn_lookup_addr_le(BT_ID_DEFAULT, &cp->address); + if (!conn) { + LOG_ERR("Unknown connection"); + return BTP_STATUS_FAILED; + } + + err = bt_tbs_client_retrieve_call(conn, cp->inst_index, cp->call_id); + if (err) { + return BTP_STATUS_FAILED; + } + + return BTP_STATUS_SUCCESS; +} + +static uint8_t ccp_join_calls(const void *cmd, uint16_t cmd_len, void *rsp, uint16_t *rsp_len) +{ + const struct btp_ccp_join_calls_cmd *cp = cmd; + const uint8_t *call_index; + struct bt_conn *conn; + int err; + + conn = bt_conn_lookup_addr_le(BT_ID_DEFAULT, &cp->address); + if (!conn) { + LOG_ERR("Unknown connection"); + return BTP_STATUS_FAILED; + } + + call_index = cp->call_index; + + err = bt_tbs_client_join_calls(conn, cp->inst_index, call_index, cp->count); + if (err) { + return BTP_STATUS_FAILED; + } + + return BTP_STATUS_SUCCESS; +} + static const struct btp_handler ccp_handlers[] = { { .opcode = BTP_CCP_READ_SUPPORTED_COMMANDS, @@ -324,7 +769,92 @@ static const struct btp_handler ccp_handlers[] = { .opcode = BTP_CCP_READ_CALL_STATE, .expect_len = sizeof(struct btp_ccp_read_call_state_cmd), .func = ccp_read_call_state - } + }, + { + .opcode = BTP_CCP_READ_BEARER_NAME, + .expect_len = sizeof(struct btp_ccp_read_bearer_name_cmd), + .func = ccp_read_bearer_name + }, + { + .opcode = BTP_CCP_READ_BEARER_UCI, + .expect_len = sizeof(struct btp_ccp_read_bearer_uci_cmd), + .func = ccp_read_bearer_uci + }, + { + .opcode = BTP_CCP_READ_BEARER_TECH, + .expect_len = sizeof(struct btp_ccp_read_bearer_technology_cmd), + .func = ccp_read_bearer_tech + }, + { + .opcode = BTP_CCP_READ_URI_LIST, + .expect_len = sizeof(struct btp_ccp_read_uri_list_cmd), + .func = ccp_read_uri_list + }, + { + .opcode = BTP_CCP_READ_SIGNAL_STRENGTH, + .expect_len = sizeof(struct btp_ccp_read_signal_strength_cmd), + .func = ccp_read_signal_strength + }, + { + .opcode = BTP_CCP_READ_SIGNAL_INTERVAL, + .expect_len = sizeof(struct btp_ccp_read_signal_interval_cmd), + .func = ccp_read_signal_interval + }, + { + .opcode = BTP_CCP_READ_CURRENT_CALLS, + .expect_len = sizeof(struct btp_ccp_read_current_calls_cmd), + .func = ccp_read_current_calls + }, + { + .opcode = BTP_CCP_READ_CCID, + .expect_len = sizeof(struct btp_ccp_read_ccid_cmd), + .func = ccp_read_ccid + }, + { + .opcode = BTP_CCP_READ_CALL_URI, + .expect_len = sizeof(struct btp_ccp_read_call_uri_cmd), + .func = ccp_read_call_uri + }, + { + .opcode = BTP_CCP_READ_STATUS_FLAGS, + .expect_len = sizeof(struct btp_ccp_read_status_flags_cmd), + .func = ccp_read_status_flags + }, + { + .opcode = BTP_CCP_READ_OPTIONAL_OPCODES, + .expect_len = sizeof(struct btp_ccp_read_optional_opcodes_cmd), + .func = ccp_read_optional_opcodes + }, + { + .opcode = BTP_CCP_READ_FRIENDLY_NAME, + .expect_len = sizeof(struct btp_ccp_read_friendly_name_cmd), + .func = ccp_read_friendly_name + }, + { + .opcode = BTP_CCP_READ_REMOTE_URI, + .expect_len = sizeof(struct btp_ccp_read_remote_uri_cmd), + .func = ccp_read_remote_uri + }, + { + .opcode = BTP_CCP_SET_SIGNAL_INTERVAL, + .expect_len = sizeof(struct btp_ccp_set_signal_interval_cmd), + .func = ccp_set_signal_interval + }, + { + .opcode = BTP_CCP_HOLD_CALL, + .expect_len = sizeof(struct btp_ccp_hold_call_cmd), + .func = ccp_hold_call + }, + { + .opcode = BTP_CCP_RETRIEVE_CALL, + .expect_len = sizeof(struct btp_ccp_retrieve_call_cmd), + .func = ccp_retrieve_call + }, + { + .opcode = BTP_CCP_JOIN_CALLS, + .expect_len = BTP_HANDLER_LENGTH_VARIABLE, + .func = ccp_join_calls + }, }; uint8_t tester_init_ccp(void) From 0044640be63771f1f91132635195d94141f0eac0 Mon Sep 17 00:00:00 2001 From: Chaitanya Tata Date: Fri, 22 Dec 2023 13:55:12 +0530 Subject: [PATCH 1775/3723] wifi: shell: Fix the arg count for reg domain Missed accounting for "-f" option. Signed-off-by: Chaitanya Tata --- subsys/net/l2/wifi/wifi_shell.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/subsys/net/l2/wifi/wifi_shell.c b/subsys/net/l2/wifi/wifi_shell.c index 3aa674e73b7..c3100c9ad2c 100644 --- a/subsys/net/l2/wifi/wifi_shell.c +++ b/subsys/net/l2/wifi/wifi_shell.c @@ -1688,7 +1688,7 @@ SHELL_STATIC_SUBCMD_SET_CREATE(wifi_commands, "[-f]: Force to use this regulatory hint over any other regulatory hints\n" "Note: This may cause regulatory compliance issues, use it at your own risk.", cmd_wifi_reg_domain, - 1, 1), + 1, 2), SHELL_CMD_ARG(mode, NULL, "mode operational setting\n" "This command may be used to set the Wi-Fi device into a specific mode of operation\n" "parameters:" From 9b55802d982b1f1b01cfdcc1597b749d3abc8154 Mon Sep 17 00:00:00 2001 From: Chaitanya Tata Date: Fri, 22 Dec 2023 13:57:20 +0530 Subject: [PATCH 1776/3723] wifi: shell: Fix optional arg count for connect Fix an extra optional arg. Signed-off-by: Chaitanya Tata --- subsys/net/l2/wifi/wifi_shell.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/subsys/net/l2/wifi/wifi_shell.c b/subsys/net/l2/wifi/wifi_shell.c index c3100c9ad2c..dbec138fea0 100644 --- a/subsys/net/l2/wifi/wifi_shell.c +++ b/subsys/net/l2/wifi/wifi_shell.c @@ -1653,7 +1653,7 @@ SHELL_STATIC_SUBCMD_SET_CREATE(wifi_commands, "[MFP (optional: needs security type to be specified)]\n" ": 0:Disable, 1:Optional, 2:Required", cmd_wifi_connect, - 2, 5), + 2, 4), SHELL_CMD_ARG(disconnect, NULL, "Disconnect from the Wi-Fi AP", cmd_wifi_disconnect, 1, 0), From 30c492d5de735052f733d58d5071edcafa1103c0 Mon Sep 17 00:00:00 2001 From: Chaitanya Tata Date: Fri, 22 Dec 2023 13:59:52 +0530 Subject: [PATCH 1777/3723] wifi: shell: Fix help for PS command Clearly mark the args as optional. Signed-off-by: Chaitanya Tata --- subsys/net/l2/wifi/wifi_shell.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/subsys/net/l2/wifi/wifi_shell.c b/subsys/net/l2/wifi/wifi_shell.c index dbec138fea0..6ef745670ab 100644 --- a/subsys/net/l2/wifi/wifi_shell.c +++ b/subsys/net/l2/wifi/wifi_shell.c @@ -1657,7 +1657,8 @@ SHELL_STATIC_SUBCMD_SET_CREATE(wifi_commands, SHELL_CMD_ARG(disconnect, NULL, "Disconnect from the Wi-Fi AP", cmd_wifi_disconnect, 1, 0), - SHELL_CMD_ARG(ps, NULL, "Configure Wi-F PS on/off, no arguments will dump config", + SHELL_CMD_ARG(ps, NULL, "Configure or display Wi-Fi power save state\n" + "[on/off]\n", cmd_wifi_ps, 1, 1), SHELL_CMD_ARG(ps_mode, From 467a89e6a47d65f9f1784af6bfada53d94d1eafd Mon Sep 17 00:00:00 2001 From: Chaitanya Tata Date: Fri, 22 Dec 2023 14:00:50 +0530 Subject: [PATCH 1778/3723] wifi: shell: Remove the unnecessary text in scan We are using standard notation to differentiate optional and mandatory, so, no need for a heading. Signed-off-by: Chaitanya Tata --- subsys/net/l2/wifi/wifi_shell.c | 1 - 1 file changed, 1 deletion(-) diff --git a/subsys/net/l2/wifi/wifi_shell.c b/subsys/net/l2/wifi/wifi_shell.c index 6ef745670ab..d6d14c86bf1 100644 --- a/subsys/net/l2/wifi/wifi_shell.c +++ b/subsys/net/l2/wifi/wifi_shell.c @@ -1669,7 +1669,6 @@ SHELL_STATIC_SUBCMD_SET_CREATE(wifi_commands, 0), SHELL_CMD_ARG(scan, NULL, "Scan for Wi-Fi APs\n" - "OPTIONAL PARAMETERS:\n" "[-t, --type ] : Preferred mode of scan. The actual mode of scan can depend on factors such as the Wi-Fi chip implementation, regulatory domain restrictions. Default type is active.\n" "[-b, --bands ] : Bands to be scanned where 2: 2.4 GHz, 5: 5 GHz, 6: 6 GHz.\n" "[-a, --dwell_time_active ] : Active scan dwell time (in ms) on a channel. Range 5 ms to 1000 ms.\n" From 352f63c909a0fb2a65d1980700050454a4f8c0e2 Mon Sep 17 00:00:00 2001 From: Chaitanya Tata Date: Fri, 22 Dec 2023 14:02:42 +0530 Subject: [PATCH 1779/3723] wifi: shell: Fix the help for reg domain Separate the two optional parameters and add help. Signed-off-by: Chaitanya Tata --- subsys/net/l2/wifi/wifi_shell.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/subsys/net/l2/wifi/wifi_shell.c b/subsys/net/l2/wifi/wifi_shell.c index d6d14c86bf1..890bb8f121e 100644 --- a/subsys/net/l2/wifi/wifi_shell.c +++ b/subsys/net/l2/wifi/wifi_shell.c @@ -1684,7 +1684,7 @@ SHELL_STATIC_SUBCMD_SET_CREATE(wifi_commands, SHELL_CMD(twt, &wifi_twt_ops, "Manage TWT flows", NULL), SHELL_CMD_ARG(reg_domain, NULL, "Set or Get Wi-Fi regulatory domain\n" - "Usage: wifi reg_domain [ISO/IEC 3166-1 alpha2] [-f]\n" + "[ISO/IEC 3166-1 alpha2]: Regulatory domain\n" "[-f]: Force to use this regulatory hint over any other regulatory hints\n" "Note: This may cause regulatory compliance issues, use it at your own risk.", cmd_wifi_reg_domain, From 7e7dc7629664a257b1879bb221e48550a67658cd Mon Sep 17 00:00:00 2001 From: Chaitanya Tata Date: Fri, 22 Dec 2023 14:07:36 +0530 Subject: [PATCH 1780/3723] wifi: shell: Remove the unnecessary text The parameters heading is implied and doesn't have the newline, so, just remove it. Signed-off-by: Chaitanya Tata --- subsys/net/l2/wifi/wifi_shell.c | 3 --- 1 file changed, 3 deletions(-) diff --git a/subsys/net/l2/wifi/wifi_shell.c b/subsys/net/l2/wifi/wifi_shell.c index 890bb8f121e..a983e5c18f5 100644 --- a/subsys/net/l2/wifi/wifi_shell.c +++ b/subsys/net/l2/wifi/wifi_shell.c @@ -1691,7 +1691,6 @@ SHELL_STATIC_SUBCMD_SET_CREATE(wifi_commands, 1, 2), SHELL_CMD_ARG(mode, NULL, "mode operational setting\n" "This command may be used to set the Wi-Fi device into a specific mode of operation\n" - "parameters:" "[-i, --if-index ] : Interface index.\n" "[-s, --sta] : Station mode.\n" "[-m, --monitor] : Monitor mode.\n" @@ -1711,7 +1710,6 @@ SHELL_STATIC_SUBCMD_SET_CREATE(wifi_commands, "This command is used to set packet filter setting when\n" "monitor, TX-Injection and promiscuous mode is enabled.\n" "The different packet filter modes are control, management, data and enable all filters\n" - "parameters:" "[-i, --if-index ] : Interface index.\n" "[-a, --all] : Enable all packet filter modes\n" "[-m, --mgmt] : Enable management packets to allowed up the stack.\n" @@ -1730,7 +1728,6 @@ SHELL_STATIC_SUBCMD_SET_CREATE(wifi_commands, "This command is used to set the channel when\n" "monitor or TX-Injection mode is enabled.\n" "Currently 20 MHz is only supported and no BW parameter is provided\n" - "parameters:" "[-i, --if-index ] : Interface index.\n" "[-c, --channel ] : Set a specific channel number to the lower layer.\n" "[-g, --get] : Get current set channel number from the lower layer.\n" From 352ee50af7e3ab330c5f8f1ff075c3551a49a27b Mon Sep 17 00:00:00 2001 From: Chaitanya Tata Date: Fri, 22 Dec 2023 14:15:11 +0530 Subject: [PATCH 1781/3723] wifi: shell: Fix the inconsistency in commands separation For better readability, below rules will help: * Each command should be separated by a newline * Each command should end with a full stop (intermediate statements shouldn't have full stops) Signed-off-by: Chaitanya Tata --- subsys/net/l2/wifi/wifi_shell.c | 98 ++++++++++++++++----------------- 1 file changed, 49 insertions(+), 49 deletions(-) diff --git a/subsys/net/l2/wifi/wifi_shell.c b/subsys/net/l2/wifi/wifi_shell.c index a983e5c18f5..27f3fcb583a 100644 --- a/subsys/net/l2/wifi/wifi_shell.c +++ b/subsys/net/l2/wifi/wifi_shell.c @@ -1601,7 +1601,7 @@ static int cmd_wifi_packet_filter(const struct shell *sh, size_t argc, char *arg SHELL_STATIC_SUBCMD_SET_CREATE(wifi_cmd_ap, SHELL_CMD_ARG(disable, NULL, - "Disable Access Point mode", + "Disable Access Point mode.\n", cmd_wifi_ap_disable, 1, 0), SHELL_CMD_ARG(enable, NULL, @@ -1611,7 +1611,7 @@ SHELL_STATIC_SUBCMD_SET_CREATE(wifi_cmd_ap, "[Security type: valid only for secure SSIDs]\n" "0:None, 1:WPA2-PSK, 2:WPA2-PSK-256, 3:SAE, 4:WAPI, 5:EAP, 6:WEP, 7: WPA-PSK\n" "[MFP (optional: needs security type to be specified)]\n" - ": 0:Disable, 1:Optional, 2:Required", + ": 0:Disable, 1:Optional, 2:Required.\n", cmd_wifi_ap_enable, 2, 4), SHELL_SUBCMD_SET_END @@ -1619,30 +1619,30 @@ SHELL_STATIC_SUBCMD_SET_CREATE(wifi_cmd_ap, SHELL_STATIC_SUBCMD_SET_CREATE(wifi_twt_ops, SHELL_CMD_ARG(quick_setup, NULL, " Start a TWT flow with defaults:\n" - " \n", + " .\n", cmd_wifi_twt_setup_quick, 3, 0), SHELL_CMD_ARG(setup, NULL, " Start a TWT flow:\n" "\n" "\n" " " - " \n", + " .\n", cmd_wifi_twt_setup, 11, 0), SHELL_CMD_ARG(teardown, NULL, " Teardown a TWT flow:\n" "\n" "\n" - " \n", + " .\n", cmd_wifi_twt_teardown, 5, 0), - SHELL_CMD_ARG(teardown_all, NULL, " Teardown all TWT flows\n", + SHELL_CMD_ARG(teardown_all, NULL, " Teardown all TWT flows.\n", cmd_wifi_twt_teardown_all, 1, 0), SHELL_SUBCMD_SET_END ); SHELL_STATIC_SUBCMD_SET_CREATE(wifi_commands, - SHELL_CMD(ap, &wifi_cmd_ap, "Access Point mode commands", NULL), + SHELL_CMD(ap, &wifi_cmd_ap, "Access Point mode commands.\n", NULL), SHELL_CMD_ARG(connect, NULL, "Connect to a Wi-Fi AP\n" "\"\"\n" @@ -1651,108 +1651,108 @@ SHELL_STATIC_SUBCMD_SET_CREATE(wifi_commands, "[Security type: valid only for secure SSIDs]\n" "0:None, 1:WPA2-PSK, 2:WPA2-PSK-256, 3:SAE, 4:WAPI, 5:EAP, 6:WEP, 7: WPA-PSK\n" "[MFP (optional: needs security type to be specified)]\n" - ": 0:Disable, 1:Optional, 2:Required", + ": 0:Disable, 1:Optional, 2:Required.\n", cmd_wifi_connect, 2, 4), - SHELL_CMD_ARG(disconnect, NULL, "Disconnect from the Wi-Fi AP", + SHELL_CMD_ARG(disconnect, NULL, "Disconnect from the Wi-Fi AP.\n", cmd_wifi_disconnect, 1, 0), - SHELL_CMD_ARG(ps, NULL, "Configure or display Wi-Fi power save state\n" + SHELL_CMD_ARG(ps, NULL, "Configure or display Wi-Fi power save state.\n" "[on/off]\n", cmd_wifi_ps, 1, 1), SHELL_CMD_ARG(ps_mode, NULL, - "\n", + ".\n", cmd_wifi_ps_mode, 2, 0), SHELL_CMD_ARG(scan, NULL, "Scan for Wi-Fi APs\n" - "[-t, --type ] : Preferred mode of scan. The actual mode of scan can depend on factors such as the Wi-Fi chip implementation, regulatory domain restrictions. Default type is active.\n" - "[-b, --bands ] : Bands to be scanned where 2: 2.4 GHz, 5: 5 GHz, 6: 6 GHz.\n" - "[-a, --dwell_time_active ] : Active scan dwell time (in ms) on a channel. Range 5 ms to 1000 ms.\n" - "[-p, --dwell_time_passive ] : Passive scan dwell time (in ms) on a channel. Range 10 ms to 1000 ms.\n" - "[-s, --ssid : SSID to scan for. Can be provided multiple times.\n" - "[-m, --max_bss ] : Maximum BSSes to scan for. Range 1 - 65535.\n" + "[-t, --type ] : Preferred mode of scan. The actual mode of scan can depend on factors such as the Wi-Fi chip implementation, regulatory domain restrictions. Default type is active\n" + "[-b, --bands ] : Bands to be scanned where 2: 2.4 GHz, 5: 5 GHz, 6: 6 GHz\n" + "[-a, --dwell_time_active ] : Active scan dwell time (in ms) on a channel. Range 5 ms to 1000 ms\n" + "[-p, --dwell_time_passive ] : Passive scan dwell time (in ms) on a channel. Range 10 ms to 1000 ms\n" + "[-s, --ssid : SSID to scan for. Can be provided multiple times\n" + "[-m, --max_bss ] : Maximum BSSes to scan for. Range 1 - 65535\n" "[-c, --chans ] : Channels to be scanned. The channels must be specified in the form band1:chan1,chan2_band2:chan3,..etc. band1, band2 must be valid band values and chan1, chan2, chan3 must be specified as a list of comma separated values where each value is either a single channel or a channel range specified as chan_start-chan_end. Each band channel set has to be separated by a _. For example, a valid channel specification can be 2:1,6-11,14_5:36,149-165,44\n" - "[-h, --help] : Print out the help for the scan command.", + "[-h, --help] : Print out the help for the scan command.\n", cmd_wifi_scan, 1, 8), - SHELL_CMD_ARG(statistics, NULL, "Wi-Fi interface statistics", cmd_wifi_stats, 1, 0), - SHELL_CMD_ARG(status, NULL, "Status of the Wi-Fi interface", cmd_wifi_status, 1, 0), - SHELL_CMD(twt, &wifi_twt_ops, "Manage TWT flows", NULL), + SHELL_CMD_ARG(statistics, NULL, "Wi-Fi interface statistics.\n", cmd_wifi_stats, 1, 0), + SHELL_CMD_ARG(status, NULL, "Status of the Wi-Fi interface.\n", cmd_wifi_status, 1, 0), + SHELL_CMD(twt, &wifi_twt_ops, "Manage TWT flows.\n", NULL), SHELL_CMD_ARG(reg_domain, NULL, "Set or Get Wi-Fi regulatory domain\n" "[ISO/IEC 3166-1 alpha2]: Regulatory domain\n" "[-f]: Force to use this regulatory hint over any other regulatory hints\n" - "Note: This may cause regulatory compliance issues, use it at your own risk.", + "Note: This may cause regulatory compliance issues, use it at your own risk.\n", cmd_wifi_reg_domain, 1, 2), SHELL_CMD_ARG(mode, NULL, "mode operational setting\n" "This command may be used to set the Wi-Fi device into a specific mode of operation\n" - "[-i, --if-index ] : Interface index.\n" - "[-s, --sta] : Station mode.\n" - "[-m, --monitor] : Monitor mode.\n" - "[-p, --promiscuous] : Promiscuous mode.\n" - "[-t, --tx-injection] : TX-Injection mode.\n" - "[-a, --ap] : AP mode.\n" - "[-k, --softap] : Softap mode.\n" - "[-h, --help] : Help.\n" - "[-g, --get] : Get current mode for a specific interface index.\n" + "[-i, --if-index ] : Interface index\n" + "[-s, --sta] : Station mode\n" + "[-m, --monitor] : Monitor mode\n" + "[-p, --promiscuous] : Promiscuous mode\n" + "[-t, --tx-injection] : TX-Injection mode\n" + "[-a, --ap] : AP mode\n" + "[-k, --softap] : Softap mode\n" + "[-h, --help] : Help\n" + "[-g, --get] : Get current mode for a specific interface index\n" "Usage: Get operation example for interface index 1\n" "wifi mode -g -i1\n" "Set operation example for interface index 1 - set station+promiscuous\n" - "wifi mode -i1 -sp\n", + "wifi mode -i1 -sp.\n", cmd_wifi_mode, 1, 9), SHELL_CMD_ARG(packet_filter, NULL, "mode filter setting\n" "This command is used to set packet filter setting when\n" - "monitor, TX-Injection and promiscuous mode is enabled.\n" + "monitor, TX-Injection and promiscuous mode is enabled\n" "The different packet filter modes are control, management, data and enable all filters\n" - "[-i, --if-index ] : Interface index.\n" + "[-i, --if-index ] : Interface index\n" "[-a, --all] : Enable all packet filter modes\n" - "[-m, --mgmt] : Enable management packets to allowed up the stack.\n" - "[-c, --ctrl] : Enable control packets to be allowed up the stack.\n" - "[-d, --data] : Enable Data packets to be allowed up the stack.\n" - "[-g, --get] : Get current filter settings for a specific interface index.\n" + "[-m, --mgmt] : Enable management packets to allowed up the stack\n" + "[-c, --ctrl] : Enable control packets to be allowed up the stack\n" + "[-d, --data] : Enable Data packets to be allowed up the stack\n" + "[-g, --get] : Get current filter settings for a specific interface index\n" "[-b, --capture-len ] : Capture length buffer size for each packet to be captured\n" - "[-h, --help] : Help.\n" + "[-h, --help] : Help\n" "Usage: Get operation example for interface index 1\n" "wifi packet_filter -g -i1\n" "Set operation example for interface index 1 - set data+management frame filter\n" - "wifi packet_filter -i1 -md\n", + "wifi packet_filter -i1 -md.\n", cmd_wifi_packet_filter, 1, 8), SHELL_CMD_ARG(channel, NULL, "wifi channel setting\n" "This command is used to set the channel when\n" - "monitor or TX-Injection mode is enabled.\n" + "monitor or TX-Injection mode is enabled\n" "Currently 20 MHz is only supported and no BW parameter is provided\n" - "[-i, --if-index ] : Interface index.\n" - "[-c, --channel ] : Set a specific channel number to the lower layer.\n" - "[-g, --get] : Get current set channel number from the lower layer.\n" - "[-h, --help] : Help.\n" + "[-i, --if-index ] : Interface index\n" + "[-c, --channel ] : Set a specific channel number to the lower layer\n" + "[-g, --get] : Get current set channel number from the lower layer\n" + "[-h, --help] : Help\n" "Usage: Get operation example for interface index 1\n" "wifi channel -g -i1\n" "Set operation example for interface index 1 (setting channel 5)\n" - "wifi -i1 -c5\n", + "wifi -i1 -c5.\n", cmd_wifi_channel, 1, 4), SHELL_CMD_ARG(ps_timeout, NULL, - " - PS inactivity timer(in ms)", + " - PS inactivity timer(in ms).\n", cmd_wifi_ps_timeout, 2, 0), SHELL_CMD_ARG(ps_listen_interval, NULL, - " - Listen interval in the range of <0-65535>", + " - Listen interval in the range of <0-65535>.\n", cmd_wifi_listen_interval, 2, 0), SHELL_CMD_ARG(ps_wakeup_mode, NULL, - "\n", + ".\n", cmd_wifi_ps_wakeup_mode, 2, 0), From 66f63455ea6a22b21fb5449966aad92d1860c219 Mon Sep 17 00:00:00 2001 From: Chaitanya Tata Date: Fri, 22 Dec 2023 14:20:22 +0530 Subject: [PATCH 1782/3723] shell: Add a space after colon Just a cosmetic change, but IMHO the help looks much better now :). Signed-off-by: Chaitanya Tata --- subsys/shell/shell_help.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/subsys/shell/shell_help.c b/subsys/shell/shell_help.c index 53bf00953c1..235e2111032 100644 --- a/subsys/shell/shell_help.c +++ b/subsys/shell/shell_help.c @@ -139,7 +139,7 @@ static void help_item_print(const struct shell *sh, const char *item_name, z_cursor_next_line_move(sh); return; } else { - z_shell_fprintf(sh, SHELL_NORMAL, "%s:", tabulator); + z_shell_fprintf(sh, SHELL_NORMAL, "%s: ", tabulator); } /* print option help */ formatted_text_print(sh, item_help, offset, false); From 9e6542b0cc0a69ba18b8f9bd7d53ac6b51740db3 Mon Sep 17 00:00:00 2001 From: Chaitanya Tata Date: Wed, 3 Jan 2024 13:13:13 +0530 Subject: [PATCH 1783/3723] wifi: shell: Use case insensitive comparison The help text uses the capital case as its an acronym, but passing capital case fails. Also extend that to others as well. Signed-off-by: Chaitanya Tata --- subsys/net/l2/wifi/wifi_shell.c | 13 +++++++------ 1 file changed, 7 insertions(+), 6 deletions(-) diff --git a/subsys/net/l2/wifi/wifi_shell.c b/subsys/net/l2/wifi/wifi_shell.c index 27f3fcb583a..c7899635105 100644 --- a/subsys/net/l2/wifi/wifi_shell.c +++ b/subsys/net/l2/wifi/wifi_shell.c @@ -15,6 +15,7 @@ LOG_MODULE_REGISTER(net_wifi_shell, LOG_LEVEL_INF); #include #include #include +#include #include #include #include @@ -782,9 +783,9 @@ static int cmd_wifi_ps(const struct shell *sh, size_t argc, char *argv[]) return 0; } - if (!strncmp(argv[1], "on", 2)) { + if (!strncasecmp(argv[1], "on", 2)) { params.enabled = WIFI_PS_ENABLED; - } else if (!strncmp(argv[1], "off", 3)) { + } else if (!strncasecmp(argv[1], "off", 3)) { params.enabled = WIFI_PS_DISABLED; } else { shell_fprintf(sh, SHELL_WARNING, "Invalid argument\n"); @@ -813,9 +814,9 @@ static int cmd_wifi_ps_mode(const struct shell *sh, size_t argc, char *argv[]) context.sh = sh; - if (!strncmp(argv[1], "legacy", 6)) { + if (!strncasecmp(argv[1], "legacy", 6)) { params.mode = WIFI_PS_MODE_LEGACY; - } else if (!strncmp(argv[1], "wmm", 3)) { + } else if (!strncasecmp(argv[1], "WMM", 4)) { params.mode = WIFI_PS_MODE_WMM; } else { shell_fprintf(sh, SHELL_WARNING, "Invalid PS mode\n"); @@ -1243,9 +1244,9 @@ static int cmd_wifi_ps_wakeup_mode(const struct shell *sh, size_t argc, char *ar context.sh = sh; - if (!strncmp(argv[1], "dtim", 4)) { + if (!strncasecmp(argv[1], "dtim", 4)) { params.wakeup_mode = WIFI_PS_WAKEUP_MODE_DTIM; - } else if (!strncmp(argv[1], "listen_interval", 15)) { + } else if (!strncasecmp(argv[1], "listen_interval", 15)) { params.wakeup_mode = WIFI_PS_WAKEUP_MODE_LISTEN_INTERVAL; } else { shell_fprintf(sh, SHELL_WARNING, "Invalid argument\n"); From e2788525e0ac82c2597770703caac81caf6a55c3 Mon Sep 17 00:00:00 2001 From: Henrik Brix Andersen Date: Fri, 5 Jan 2024 13:37:19 +0100 Subject: [PATCH 1784/3723] doc: Update copyright notice in the documentation Update copyright notice to reflect current year. Signed-off-by: Henrik Brix Andersen --- doc/conf.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/doc/conf.py b/doc/conf.py index af4b11fd0bb..f8bfb06e199 100644 --- a/doc/conf.py +++ b/doc/conf.py @@ -38,7 +38,7 @@ # -- Project -------------------------------------------------------------- project = "Zephyr Project" -copyright = "2015-2023 Zephyr Project members and individual contributors" +copyright = "2015-2024 Zephyr Project members and individual contributors" author = "The Zephyr Project Contributors" # parse version from 'VERSION' file From b3e1cc9f4fb28eb7977abdaacea6a0f381a67590 Mon Sep 17 00:00:00 2001 From: Arkadiusz Cholewinski Date: Mon, 2 Oct 2023 15:04:29 +0200 Subject: [PATCH 1785/3723] PM: Add testing pm_device_state_str function. Add testing pm_device_state_str function in device_driver_init testcase. Signed-off-by: Arkadiusz Cholewinski --- tests/subsys/pm/device_driver_init/src/main.c | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/tests/subsys/pm/device_driver_init/src/main.c b/tests/subsys/pm/device_driver_init/src/main.c index f423b1d683c..d2f9f78fd3a 100644 --- a/tests/subsys/pm/device_driver_init/src/main.c +++ b/tests/subsys/pm/device_driver_init/src/main.c @@ -32,23 +32,26 @@ ZTEST(device_driver_init, test_device_driver_init) #if IS_ENABLED(CONFIG_PM_DEVICE_RUNTIME) enum pm_device_state state; int rc; - + state = -1; + zassert_equal(strcmp("", pm_device_state_str(state)), 0, "Invalid device state"); /* No device runtime PM, starts on */ DEVICE_STATE_IS(DT_NODELABEL(test_reg), PM_DEVICE_STATE_ACTIVE); DEVICE_STATE_IS(DT_NODELABEL(test_reg_chained), PM_DEVICE_STATE_ACTIVE); POWER_GPIO_CONFIG_IS(DT_NODELABEL(test_reg), GPIO_OUTPUT_HIGH); POWER_GPIO_CONFIG_IS(DT_NODELABEL(test_reg_chained), GPIO_OUTPUT_HIGH); - + zassert_equal(strcmp("active", pm_device_state_str(state)), 0, "Invalid device state"); /* Device powered, zephyr,pm-device-runtime-auto, starts suspended */ DEVICE_STATE_IS(DT_NODELABEL(test_reg_chained_auto), PM_DEVICE_STATE_SUSPENDED); DEVICE_STATE_IS(DT_NODELABEL(test_reg_auto), PM_DEVICE_STATE_SUSPENDED); POWER_GPIO_CONFIG_IS(DT_NODELABEL(test_reg_chained_auto), GPIO_OUTPUT_LOW); POWER_GPIO_CONFIG_IS(DT_NODELABEL(test_reg_auto), GPIO_OUTPUT_LOW); + zassert_equal(strcmp("suspended", pm_device_state_str(state)), 0, "Invalid device state"); /* Device not powered, starts off */ DEVICE_STATE_IS(DT_NODELABEL(test_reg_auto_chained), PM_DEVICE_STATE_OFF); DEVICE_STATE_IS(DT_NODELABEL(test_reg_auto_chained_auto), PM_DEVICE_STATE_OFF); POWER_GPIO_CONFIG_IS(DT_NODELABEL(test_reg_auto_chained), GPIO_DISCONNECTED); POWER_GPIO_CONFIG_IS(DT_NODELABEL(test_reg_auto_chained_auto), GPIO_DISCONNECTED); + zassert_equal(strcmp("off", pm_device_state_str(state)), 0, "Invalid device state"); #else /* Every regulator should be in "active" mode automatically. * State checking via GPIO as PM API is disabled. From 7d3eee7b272d9947c690ec30396786f6c9aeb4a7 Mon Sep 17 00:00:00 2001 From: Flavio Ceolin Date: Fri, 15 Dec 2023 12:19:41 -0800 Subject: [PATCH 1786/3723] doc: vuln: Add CVEs under embargo Add placeholders for CVEs under embargo. Signed-off-by: Flavio Ceolin --- doc/security/vulnerabilities.rst | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/doc/security/vulnerabilities.rst b/doc/security/vulnerabilities.rst index 2ee308c6450..a03b5202a02 100644 --- a/doc/security/vulnerabilities.rst +++ b/doc/security/vulnerabilities.rst @@ -1596,3 +1596,19 @@ This has been fixed in main for v3.5.0 - `PR 63605 fix for main `_ + + +CVE-2023-5779 +------------- + +Under embargo until 2024-01-23 + +CVE-2023-6249 +------------- + +Under embargo until 2024-02-18 + +CVE-2023-6749 +------------- + +Under embargo until 2024-02-18 From 747991d52883ee51e010d44a3c95cf2b7694d5a5 Mon Sep 17 00:00:00 2001 From: Jamie McCrae Date: Fri, 5 Jan 2024 08:29:46 +0000 Subject: [PATCH 1787/3723] samples: drivers: uart: native_tty: Remove superfluous cmake lines Removes some lines that appear to have been used for debug that are not needed Signed-off-by: Jamie McCrae --- samples/drivers/uart/native_tty/CMakeLists.txt | 3 --- 1 file changed, 3 deletions(-) diff --git a/samples/drivers/uart/native_tty/CMakeLists.txt b/samples/drivers/uart/native_tty/CMakeLists.txt index c0fa477a106..528ed22fc56 100644 --- a/samples/drivers/uart/native_tty/CMakeLists.txt +++ b/samples/drivers/uart/native_tty/CMakeLists.txt @@ -4,8 +4,5 @@ cmake_minimum_required(VERSION 3.20.0) find_package(Zephyr REQUIRED HINTS $ENV{ZEPHYR_BASE}) project(native_tty) -set(CMAKE_EXPORT_COMPILE_COMMANDS on) -zephyr_compile_options(-fdiagnostics-color=always) - file(GLOB app_sources src/main.c) target_sources(app PRIVATE ${app_sources}) From d7af6f371034f31b9440b27c694b0be3c87491d3 Mon Sep 17 00:00:00 2001 From: Tomasz Leman Date: Tue, 5 Dec 2023 09:39:39 +0100 Subject: [PATCH 1788/3723] intel_adsp: ipc: pm action in busy state Currently SOF has disabled CONFIG_PM_DEVICE_RUNTIME_EXCLUSIVE option and use pm_suspend_devices() to suspend and resume IPC device during D3 power flow. The pm_suspend_devices() function skips suspending devices that are busy. In very rare cases, the IPC device is busy during the power state transition, which results in the device not being restored during reboot. This happens when FW sends a message to the HOST and waits for ACK, and the HOST simultaneously sends a SET_DX message to the DSP. This suspend/resume logic in IPC driver does not work well when the system enters the D3 state because it is not a suspend state, but rather a power-off. IPC does not require suspending, only reinitialization when exiting D3. We cannot avoid this one missing ACK and it cannot block the DSP from turning off. When FW receives a SET_DX message it checks whether it can enter the D3 state and then returns an error (via IPC) or calls the pm_state_force function. Success response is sent directly from power_down assembly and not via ipc driver. This is because after receiving the response, the HOST will turn off the DSP. In order for the transition to D3 to take place, only the primary core can be active, all pipes must be stopped (and therefore all modules in FW). The only active thread at this time is the Idle thread. Driver on the host will not send another ipc because is still waiting for response. FW can try to send only two notification: - FW exception: from this place there is no return to continue the power transition, - log buffer status: skipped, they remain in the queue without being sent. I'm moving pm_device_busy_clear(dev) from IRQ handler to intel_adsp_ipc_send_message function so the pending ACK does not block power transition. Signed-off-by: Tomasz Leman --- soc/xtensa/intel_adsp/common/ipc.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/soc/xtensa/intel_adsp/common/ipc.c b/soc/xtensa/intel_adsp/common/ipc.c index cdb5757d356..6ae1956ffac 100644 --- a/soc/xtensa/intel_adsp/common/ipc.c +++ b/soc/xtensa/intel_adsp/common/ipc.c @@ -82,7 +82,6 @@ void z_intel_adsp_ipc_isr(const void *devarg) } regs->ida = INTEL_ADSP_IPC_DONE; - pm_device_busy_clear(dev); } k_spin_unlock(&devdata->lock, key); @@ -163,6 +162,7 @@ int intel_adsp_ipc_send_message(const struct device *dev, config->regs->idd = ext_data; config->regs->idr = data | INTEL_ADSP_IPC_BUSY; k_spin_unlock(&devdata->lock, key); + pm_device_busy_clear(dev); return 0; } From 96c20d831e69b4a5d9e660b05fba113175902d18 Mon Sep 17 00:00:00 2001 From: Flavio Ceolin Date: Fri, 5 Jan 2024 10:10:45 -0800 Subject: [PATCH 1789/3723] doc: roles: Remove ambiguity for static analysis Remove possible ambiguity in the static analysis audit team rights and responsabilities. Signed-off-by: Flavio Ceolin --- doc/project/project_roles.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/doc/project/project_roles.rst b/doc/project/project_roles.rst index e6f7b6d9d56..a57a7b46def 100644 --- a/doc/project/project_roles.rst +++ b/doc/project/project_roles.rst @@ -178,7 +178,7 @@ team to ensure that static analysis defects opened during a release cycle are properly addressed. The team has the following rights and responsibilities: -* Right to revert any change in a static analysis tool (e.g: Coverity) +* Right to revert any triage in a static analysis tool (e.g: Coverity) that does not follow the project expectations. * Responsibility to inform code owners about improper classifications. * Responsibility to alert TSC if any issues are not adequately addressed by the From ae0ad38e6b49db7a72c8a1f3fd9232212942d372 Mon Sep 17 00:00:00 2001 From: Grzegorz Ferenc Date: Tue, 28 Nov 2023 13:55:17 +0100 Subject: [PATCH 1790/3723] doc: contribute: fix heading formatting Fixed several headings in the contribute section that were not following the documentation guidelines for headings. Signed-off-by: Grzegorz Ferenc --- doc/contribute/bin_blobs.rst | 26 ++++++++++----------- doc/contribute/contributor_expectations.rst | 11 ++++----- doc/contribute/external.rst | 22 ++++++++--------- 3 files changed, 28 insertions(+), 31 deletions(-) diff --git a/doc/contribute/bin_blobs.rst b/doc/contribute/bin_blobs.rst index efc25b609e1..14c181e4058 100644 --- a/doc/contribute/bin_blobs.rst +++ b/doc/contribute/bin_blobs.rst @@ -1,7 +1,7 @@ .. _bin-blobs: Binary Blobs -************ +############ In the context of an operating system that supports multiple architectures and many different IC families, some functionality may be unavailable without the @@ -22,7 +22,7 @@ therefore free to create Zephyr-based downstream software which uses binary blobs if they cannot meet the requirements described in this page. Software license -================ +**************** Most binary blobs are distributed under proprietary licenses which vary significantly in nature and conditions. It is up to the vendor to specify the @@ -30,7 +30,7 @@ license as part of the blob submission process. Blob vendors may impose a click-through or other EULA-like workflow when users fetch and install blobs. Hosting -======= +******* Blobs must be hosted on the Internet and managed by third-party infrastructure. Two potential examples are Git repositories and web servers managed by @@ -40,7 +40,7 @@ The Zephyr Project does not host binary blobs in its Git repositories or anywhere else. Fetching blobs -============== +************** Blobs are fetched from official third-party sources by the :ref:`west blobs ` command. @@ -76,7 +76,7 @@ Any accompanying code, including interface header files for the blobs, must be present in the corresponding module repository. Tainting -======== +******** Inclusion of binary blobs will taint the Zephyr build. The definition of tainting originates in the `Linux kernel @@ -96,7 +96,7 @@ Tainting will be communicated to the user in the following manners: .. _bin-blobs-types: Allowed types -============= +************* The following binary blob types are acceptable in Zephyr: @@ -121,7 +121,7 @@ In case of disagreement, the TSC is the arbiter of whether a particular blob fits in one of the above types. Precompiled library-specific requirements -========================================= +***************************************** This section contains additional requirements specific to precompiled library blobs. @@ -132,14 +132,14 @@ distribution if it is discovered that the blob fails to meet these requirements later on. Interface header files ----------------------- +====================== The precompiled library must be accompanied by one or more header files, distributed under a non-copyleft OSI approved license, that define the interface to the library. Allowed dependencies --------------------- +==================== This section defines requirements related to external symbols that a library blob requires the build system to provide. @@ -155,7 +155,7 @@ blob requires the build system to provide. released under an OSI approved license and documented using Doxygen Toolchain requirements ----------------------- +====================== Precompiled library blobs must be in a data format which is compatible with and can be linked by a toolchain supported by the Zephyr Project. This is required @@ -164,7 +164,7 @@ compiler and/or linker flags, however. For example, a porting layer may require special flags, or a static archive may require use of specific linker flags. Limited scope -------------- +============= Allowing arbitrary library blobs carries a risk of degrading the degree to which the upstream Zephyr software distribution is open source. As an extreme @@ -188,7 +188,7 @@ At the discretion of the release team, the project may remove support for a hardware target if it cannot pass this test suite. Support and maintenance -======================= +*********************** The Zephyr Project is not expected to be responsible for the maintenance and support of contributed binary blobs. As a consequence, at the discretion of the @@ -226,7 +226,7 @@ regularly scheduled execution of the CI infrastructure. .. _blobs-process: Submission and review process -============================= +***************************** For references to binary blobs to be included in the project, they must be reviewed and accepted by the Technical Steering Committee (TSC). This process is diff --git a/doc/contribute/contributor_expectations.rst b/doc/contribute/contributor_expectations.rst index aeb90c33d68..cba1627a1b9 100644 --- a/doc/contribute/contributor_expectations.rst +++ b/doc/contribute/contributor_expectations.rst @@ -3,9 +3,6 @@ Contributor Expectations ######################## -Overview -******** - The Zephyr project encourages :ref:`contributors ` to submit changes as smaller pull requests. Smaller pull requests (PRs) have the following benefits: @@ -30,7 +27,7 @@ benefits: Defining Smaller PRs -==================== +******************** - Smaller PRs should encompass one self-contained logical change. @@ -55,7 +52,7 @@ Defining Smaller PRs Multiple Commits on a Single PR -=============================== +******************************* Contributors are further encouraged to break up PRs into multiple commits. Keep in mind each commit in the PR must still build cleanly and pass all the CI @@ -72,7 +69,7 @@ the PR into multiple commits targeting these specific changes: #. Update the documentation Large Changes -============= +************* Large changes to the Zephyr project must submit an :ref:`RFC proposal ` describing the full scope of change and future work. The RFC proposal provides @@ -265,7 +262,7 @@ the steps below: .. _reviewer-expectations: Reviewer Expectations -##################### +********************* - Be respectful when commenting on PRs. Refer to the Zephyr `Code of Conduct`_ for more details. diff --git a/doc/contribute/external.rst b/doc/contribute/external.rst index e602c94df09..c154bc3a698 100644 --- a/doc/contribute/external.rst +++ b/doc/contribute/external.rst @@ -1,7 +1,7 @@ .. _external-contributions: Contributing External Components -******************************** +################################ In some cases it is desirable to leverage existing, external source code in order to avoid re-implementing basic functionality or features that are readily @@ -21,7 +21,7 @@ code analysis, testing or simulation please refer to the :ref:`external-tooling` section at the end of the page. Software License -================ +**************** .. note:: @@ -49,7 +49,7 @@ for contributed code, we ensure that the Zephyr community can develop products with the Zephyr Project without concerns over patent or copyright issues. Merit -===== +***** Just like with any other regular contribution, one that contains external code needs to be evaluated for merit. However, in the particular case of code that @@ -68,14 +68,14 @@ into the project: Are there other open source project that implement the same functionality? Mode of integration -=================== +******************* There are two ways of integrating external source code into the Zephyr Project, and careful consideration must be taken to choose the appropriate one for each particular case. Integration in the main tree ----------------------------- +============================ The first way to integrate external source code into the project is to simply import the source code files into the main ``zephyr`` repository. This @@ -94,7 +94,7 @@ This mode of integration can be applicable to both small and large external codebases, but it is typically used more commonly with the former. Integration as a module ------------------------ +======================= The second way of integrating external source code into the project is to import the whole or parts of the third-party open source project into a separate @@ -104,7 +104,7 @@ thus it is not automatically subject to the requirements of the previous section. Integration in main manifest file (west.yaml) -+++++++++++++++++++++++++++++++++++++++++++++ +--------------------------------------------- Integrating external code into the main :file:`west.yml` manifest file is limited to code that is used by a Zephyr subsystem (libraries), by a platform, @@ -117,7 +117,7 @@ Integrated modules will not be removed from the tree without a detailed migration plan. Integration as optional modules -+++++++++++++++++++++++++++++++ +------------------------------- Standalone or loose integration of modules/projects without any incoming dependencies shall be made optional and shall be kept standalone. Optional @@ -137,7 +137,7 @@ repository) and all sample or test code shall be maintained as part of the modul over time. Integration as external modules -+++++++++++++++++++++++++++++++ +------------------------------- Similar to optional modules, but added to the Zephyr project as an entry in the documentation using a pre-defined template. This type of modules exists outside the @@ -145,7 +145,7 @@ Zephyr project manifest with documentation instructing users and developers how to integrate the functionality. Ongoing maintenance -=================== +******************* Regardless of the mode of integration, external source code that is integrated in Zephyr requires regular ongoing maintenance. The submitter of the proposal to @@ -157,7 +157,7 @@ process. .. _external-src-process: Submission and review process -============================= +***************************** Before external source code can be included in the project, it must be reviewed and accepted by the Technical Steering Committee (TSC) and, in some cases, by From ccd843ecbd6b670cfa296150bee4999580e8350b Mon Sep 17 00:00:00 2001 From: Jakob Krantz Date: Fri, 22 Dec 2023 15:13:01 +0100 Subject: [PATCH 1791/3723] driver: display: sdl: Fix input together with SDL_DISPLAY_ZOOM_PCT Using SDL_DISPLAY_ZOOM_PCT would cause mouse pointer/touch input to not click at the correct position. Signed-off-by: Jakob Krantz --- drivers/display/display_sdl_bottom.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/drivers/display/display_sdl_bottom.c b/drivers/display/display_sdl_bottom.c index 92c09f36fcd..bfeb70a8dba 100644 --- a/drivers/display/display_sdl_bottom.c +++ b/drivers/display/display_sdl_bottom.c @@ -29,6 +29,8 @@ int sdl_display_init_bottom(uint16_t height, uint16_t width, uint16_t zoom_pct, return -1; } + SDL_RenderSetLogicalSize(*renderer, width, height); + *texture = SDL_CreateTexture(*renderer, SDL_PIXELFORMAT_ARGB8888, SDL_TEXTUREACCESS_STATIC, width, height); if (*texture == NULL) { From 7382dbd13acabcdedf395984595f5898173602e8 Mon Sep 17 00:00:00 2001 From: Mike Szczys Date: Tue, 26 Dec 2023 17:11:28 -0600 Subject: [PATCH 1792/3723] boards: xtensa: m5stack_core2: swap-xy touch input Swap the lvgl X/Y touch input coordinates to match the orientation of the screen. Signed-off-by: Mike Szczys --- boards/xtensa/m5stack_core2/m5stack_core2.dts | 1 + 1 file changed, 1 insertion(+) diff --git a/boards/xtensa/m5stack_core2/m5stack_core2.dts b/boards/xtensa/m5stack_core2/m5stack_core2.dts index 5aa8e88bf2c..c17b540ca5d 100644 --- a/boards/xtensa/m5stack_core2/m5stack_core2.dts +++ b/boards/xtensa/m5stack_core2/m5stack_core2.dts @@ -46,6 +46,7 @@ lvgl_pointer { compatible = "zephyr,lvgl-pointer-input"; input = <&ft5336_touch>; + swap-xy; }; }; From 6f226eb153aac3026c276baa66cd8309d4b557ad Mon Sep 17 00:00:00 2001 From: Jamie McCrae Date: Tue, 14 Nov 2023 07:49:45 +0000 Subject: [PATCH 1793/3723] various: Remove BOOTLOADER_SRAM_SIZE overrides Removes settings this Kconfig to 0, because the default already is 0 Signed-off-by: Jamie McCrae --- boards/arm/ast1030_evb/ast1030_evb_defconfig | 1 - boards/arm/scobc_module1/scobc_module1_defconfig | 1 - soc/arm/ti_simplelink/cc32xx/Kconfig.defconfig.cc3220sf | 4 ---- soc/arm/ti_simplelink/cc32xx/Kconfig.defconfig.cc3235sf | 4 ---- 4 files changed, 10 deletions(-) diff --git a/boards/arm/ast1030_evb/ast1030_evb_defconfig b/boards/arm/ast1030_evb/ast1030_evb_defconfig index 6a0e696b39b..62278d44213 100644 --- a/boards/arm/ast1030_evb/ast1030_evb_defconfig +++ b/boards/arm/ast1030_evb/ast1030_evb_defconfig @@ -5,7 +5,6 @@ CONFIG_SOC_SERIES_AST10X0=y CONFIG_SYS_CLOCK_HW_CYCLES_PER_SEC=200000000 CONFIG_MAIN_STACK_SIZE=4096 -CONFIG_BOOTLOADER_SRAM_SIZE=0 CONFIG_FLASH_SIZE=0 CONFIG_FLASH_BASE_ADDRESS=0x0 CONFIG_XIP=n diff --git a/boards/arm/scobc_module1/scobc_module1_defconfig b/boards/arm/scobc_module1/scobc_module1_defconfig index 8ec2b679557..ecadcfc07bd 100644 --- a/boards/arm/scobc_module1/scobc_module1_defconfig +++ b/boards/arm/scobc_module1/scobc_module1_defconfig @@ -14,4 +14,3 @@ CONFIG_UART_CONSOLE=y CONFIG_XIP=n CONFIG_FLASH_SIZE=0 CONFIG_FLASH_BASE_ADDRESS=0x0 -CONFIG_BOOTLOADER_SRAM_SIZE=0 diff --git a/soc/arm/ti_simplelink/cc32xx/Kconfig.defconfig.cc3220sf b/soc/arm/ti_simplelink/cc32xx/Kconfig.defconfig.cc3220sf index e082df05a80..461802f2155 100644 --- a/soc/arm/ti_simplelink/cc32xx/Kconfig.defconfig.cc3220sf +++ b/soc/arm/ti_simplelink/cc32xx/Kconfig.defconfig.cc3220sf @@ -19,10 +19,6 @@ config ROM_START_OFFSET default 0x800 if XIP default 0x0 if !XIP -# Override the setting in misc/Kconfig to allow full use of SRAM: -config BOOTLOADER_SRAM_SIZE - default 0 if !XIP - if !XIP config FLASH_SIZE default 0 diff --git a/soc/arm/ti_simplelink/cc32xx/Kconfig.defconfig.cc3235sf b/soc/arm/ti_simplelink/cc32xx/Kconfig.defconfig.cc3235sf index 86c881a40f9..37852a154a0 100644 --- a/soc/arm/ti_simplelink/cc32xx/Kconfig.defconfig.cc3235sf +++ b/soc/arm/ti_simplelink/cc32xx/Kconfig.defconfig.cc3235sf @@ -20,10 +20,6 @@ config ROM_START_OFFSET default 0x800 if XIP default 0x0 if !XIP -# Override the setting in misc/Kconfig to allow full use of SRAM: -config BOOTLOADER_SRAM_SIZE - default 0 if !XIP - if !XIP config FLASH_SIZE default 0 From d548a7f0838e3ed5e773e897ca25921ec4510503 Mon Sep 17 00:00:00 2001 From: Jamie McCrae Date: Tue, 14 Nov 2023 07:50:48 +0000 Subject: [PATCH 1794/3723] kconfig: Deprecate BOOTLOADER_SRAM_SIZE This Kconfig is seemingly unused with exception to a single board, whose maintainers have been unresponsive for a long time. It is not useful to any other board and can be set in dts, therefore deprecate it and schedule removal after the Zephyr 3.7 release Signed-off-by: Jamie McCrae --- Kconfig.zephyr | 16 +++++++++++++++- 1 file changed, 15 insertions(+), 1 deletion(-) diff --git a/Kconfig.zephyr b/Kconfig.zephyr index 8b48eca6fcd..c384c8053f9 100644 --- a/Kconfig.zephyr +++ b/Kconfig.zephyr @@ -872,7 +872,7 @@ config IS_BOOTLOADER a separate Zephyr image payload. config BOOTLOADER_SRAM_SIZE - int "SRAM reserved for bootloader" + int "SRAM reserved for bootloader [DEPRECATED]" default 0 depends on !XIP || IS_BOOTLOADER depends on ARM || XTENSA @@ -883,6 +883,20 @@ config BOOTLOADER_SRAM_SIZE - Zephyr is a !XIP image, which implicitly assumes existence of a bootloader that loads the Zephyr !XIP image onto SRAM. + This option is deprecated, users should transition to using DTS to set this, if needed. + To be removed after Zephyr 3.7 release. + +config BOOTLOADER_SRAM_SIZE_DEPRECATED + bool + default y + select DEPRECATED + depends on BOOTLOADER_SRAM_SIZE != 0 + depends on !XIP || IS_BOOTLOADER + depends on ARM || XTENSA + help + Non-prompt symbol to indicate that the deprecated BOOTLOADER_SRAM_SIZE Kconfig has a + non-0 value. Please transition to using devicetree. + config BOOTLOADER_ESP_IDF bool "ESP-IDF bootloader support" depends on SOC_FAMILY_ESP32 && !BOOTLOADER_MCUBOOT && !MCUBOOT From 46b0d036e28538596ff3e6b97b55a3a8251bea84 Mon Sep 17 00:00:00 2001 From: Jamie McCrae Date: Tue, 14 Nov 2023 07:56:39 +0000 Subject: [PATCH 1795/3723] doc: release: 3.6: Add note on deprecating Kconfig Adds a note that CONFIG_BOOTLOADER_SRAM_SIZE has been deprecated Signed-off-by: Jamie McCrae --- doc/releases/release-notes-3.6.rst | 3 +++ 1 file changed, 3 insertions(+) diff --git a/doc/releases/release-notes-3.6.rst b/doc/releases/release-notes-3.6.rst index 86528e4adf6..e191ab73ffa 100644 --- a/doc/releases/release-notes-3.6.rst +++ b/doc/releases/release-notes-3.6.rst @@ -138,6 +138,9 @@ Build system and infrastructure * Added MCUboot image size reduction to sysbuild images which include MCUboot which prevents issues with building firmware images that are too large for MCUboot to swap. +* Deprecated :kconfig:option:`CONFIG_BOOTLOADER_SRAM_SIZE`, users of this should transition to + having RAM set up properly in their board devicetree files. + Drivers and Sensors ******************* From a417392f7668e7556ae4e3b15acc64c051750ef4 Mon Sep 17 00:00:00 2001 From: Bryan Zhu Date: Tue, 19 Dec 2023 09:21:27 +0800 Subject: [PATCH 1796/3723] timer: ambiq_stimer: Correct set_timeout's delta clock calculation In sys_clock_set_timeout(), input "ticks" is used to compute next timeout point, Ambiq's STimer API used to sets next timeout has input parameter as ui32Delta, which inside the API is using "this value to add to the STimer counter and load into the comparator register" according to its spec, thus the this delta clock is almost equivalent to input "ticks"'s concept, and is not related to last_count, it should be computed directly from input "ticks". This correction fixes the test case failure at zephyr\tests\kernel\tickless\tickless_concept. Signed-off-by: Bryan Zhu --- drivers/timer/ambiq_stimer.c | 22 +++++++--------------- 1 file changed, 7 insertions(+), 15 deletions(-) diff --git a/drivers/timer/ambiq_stimer.c b/drivers/timer/ambiq_stimer.c index bcef78dd1ac..8a469f35907 100644 --- a/drivers/timer/ambiq_stimer.c +++ b/drivers/timer/ambiq_stimer.c @@ -80,23 +80,15 @@ void sys_clock_set_timeout(int32_t ticks, bool idle) return; } - k_spinlock_key_t key = k_spin_lock(&g_lock); - - uint64_t now = am_hal_stimer_counter_get(); - uint32_t adj, cyc = ticks * CYC_PER_TICK; - - /* Round up to next tick boundary. */ - adj = (uint32_t)(now - g_last_count) + (CYC_PER_TICK - 1); - if (cyc <= MAX_CYCLES - adj) { - cyc += adj; - } else { - cyc = MAX_CYCLES; + if (ticks == K_TICKS_FOREVER) { + return; } - cyc = (cyc / CYC_PER_TICK) * CYC_PER_TICK; - if ((int32_t)(cyc + g_last_count - now) < MIN_DELAY) { - cyc += CYC_PER_TICK; - } + ticks = MIN(MAX_TICKS, ticks); + /* If tick is 0, set delta cyc to MIN_DELAY to trigger tick isr asap */ + uint32_t cyc = MAX(ticks * CYC_PER_TICK, MIN_DELAY); + + k_spinlock_key_t key = k_spin_lock(&g_lock); am_hal_stimer_compare_delta_set(0, cyc); From 71b846fab694d6d54b341895ad8e9309cbcc4ace Mon Sep 17 00:00:00 2001 From: Yves Vandervennet Date: Mon, 18 Dec 2023 11:42:20 -0600 Subject: [PATCH 1797/3723] boards: frdm_k64f: enable linkserver support - board.cmake is augmented for LinkServer (now the default runner for this board) - the board's doc file is updated as well Signed-off-by: Yves Vandervennet --- boards/arm/frdm_k64f/board.cmake | 3 +++ boards/arm/frdm_k64f/doc/index.rst | 22 +++++++++++++++++----- 2 files changed, 20 insertions(+), 5 deletions(-) diff --git a/boards/arm/frdm_k64f/board.cmake b/boards/arm/frdm_k64f/board.cmake index a7302350a26..d2fafeb4a00 100644 --- a/boards/arm/frdm_k64f/board.cmake +++ b/boards/arm/frdm_k64f/board.cmake @@ -1,8 +1,11 @@ # SPDX-License-Identifier: Apache-2.0 board_runner_args(jlink "--device=MK64FN1M0xxx12") +board_runner_args(linkserver "--device=MK64FN1M0xxx12:FRDM-K64F") + board_runner_args(pyocd "--target=k64f") +include(${ZEPHYR_BASE}/boards/common/linkserver.board.cmake) include(${ZEPHYR_BASE}/boards/common/pyocd.board.cmake) include(${ZEPHYR_BASE}/boards/common/jlink.board.cmake) include(${ZEPHYR_BASE}/boards/common/openocd.board.cmake) diff --git a/boards/arm/frdm_k64f/doc/index.rst b/boards/arm/frdm_k64f/doc/index.rst index e2fce31a9b1..acbf2260561 100644 --- a/boards/arm/frdm_k64f/doc/index.rst +++ b/boards/arm/frdm_k64f/doc/index.rst @@ -246,11 +246,23 @@ instructions to update from the CMSIS-DAP bootloader to the DAPLink bootloader. .. group-tab:: OpenSDA DAPLink Onboard (Recommended) - Install the :ref:`pyocd-debug-host-tools` and make sure they are in your search - path. + Install the :ref:`linkserver-debug-host-tools` and make sure they are in your + search path. LinkServer works with the default CMSIS-DAP firmware included in + the on-board debugger. + + Linkserver is the default for this board, ``west flash`` and ``west debug`` will + call the linkserver runner. + + .. code-block:: console + + west flash + + Alternatively, pyOCD can be used to flash and debug the board by using the + ``-r pyocd`` option with West. pyOCD is installed when you complete the + :ref:`gs_python_deps` step in the Getting Started Guide. The runners supported + by NXP are LinkServer and JLink. pyOCD is another potential option, but NXP + does not test or support the pyOCD runner. - Follow the instructions in :ref:`opensda-daplink-onboard-debug-probe` to program - the `OpenSDA DAPLink FRDM-K64F Firmware`_. .. group-tab:: OpenSDA JLink Onboard @@ -269,7 +281,7 @@ instructions to update from the CMSIS-DAP bootloader to the DAPLink bootloader. Add the arguments ``-DBOARD_FLASH_RUNNER=jlink`` and ``-DBOARD_DEBUG_RUNNER=jlink`` when you invoke ``west build`` to override the - default runner from pyOCD to J-Link: + default runner to J-Link: .. zephyr-app-commands:: :zephyr-app: samples/hello_world From 929d551b02943b9e5c762a2e144984e578df4b33 Mon Sep 17 00:00:00 2001 From: Yves Vandervennet Date: Tue, 19 Dec 2023 16:22:27 -0500 Subject: [PATCH 1798/3723] boards: mimxrt685_evk: enable linkserver support - board.cmake is augmented for LinkServer (now the default runner for this board) - the board's doc file is updated as well Signed-off-by: Yves Vandervennet --- boards/arm/mimxrt685_evk/board.cmake | 2 ++ boards/arm/mimxrt685_evk/doc/index.rst | 28 ++++++++++++++++++++++++-- 2 files changed, 28 insertions(+), 2 deletions(-) diff --git a/boards/arm/mimxrt685_evk/board.cmake b/boards/arm/mimxrt685_evk/board.cmake index a399d5f6398..79e6f768dd1 100644 --- a/boards/arm/mimxrt685_evk/board.cmake +++ b/boards/arm/mimxrt685_evk/board.cmake @@ -5,5 +5,7 @@ # board_runner_args(jlink "--device=MIMXRT685S_M33" "--reset-after-load") +board_runner_args(linkserver "--device=MIMXRT685S:EVK-MIMXRT685") +include(${ZEPHYR_BASE}/boards/common/linkserver.board.cmake) include(${ZEPHYR_BASE}/boards/common/jlink.board.cmake) diff --git a/boards/arm/mimxrt685_evk/doc/index.rst b/boards/arm/mimxrt685_evk/doc/index.rst index f0236e3a64f..579cd1e4087 100644 --- a/boards/arm/mimxrt685_evk/doc/index.rst +++ b/boards/arm/mimxrt685_evk/doc/index.rst @@ -227,6 +227,20 @@ configured by default to use the LPC-Link2. .. tabs:: + .. group-tab:: LinkServer CMSIS-DAP + + 1. Install the :ref:`linkserver-debug-host-tools` and make sure they are in your + search path. LinkServer works with the default CMSIS-DAP firmware included in + the on-board debugger. + 2. Make sure the jumpers JP17, JP18 and JP19 are installed. + + linkserver is the default runner for this board + + .. code-block:: console + + west flash + west debug + .. group-tab:: LPCLink2 JLink Onboard @@ -236,6 +250,11 @@ configured by default to use the LPC-Link2. 3. Follow the instructions in :ref:`lpclink2-jlink-onboard-debug-probe` to program the J-Link firmware. Please make sure you have the latest firmware for this board. + .. code-block:: console + + west flash -r jlink + west debug -r jlink + .. group-tab:: JLink External @@ -248,6 +267,11 @@ configured by default to use the LPC-Link2. See :ref:`jlink-external-debug-probe` for more information. + .. code-block:: console + + west flash -r jlink + west debug -r jlink + Configuring a Console ===================== @@ -263,7 +287,7 @@ Flashing ======== Here is an example for the :ref:`hello_world` application. This example uses the -:ref:`jlink-debug-host-tools` as default. +:ref:`linkserver-debug-host-tools` as default. .. zephyr-app-commands:: :zephyr-app: samples/hello_world @@ -282,7 +306,7 @@ Debugging ========= Here is an example for the :ref:`hello_world` application. This example uses the -:ref:`jlink-debug-host-tools` as default. +:ref:`linkserver-debug-host-tools` as default. .. zephyr-app-commands:: :zephyr-app: samples/hello_world From d0283f9b158ddb36e79ec490a1f7f0ddbe3fb04c Mon Sep 17 00:00:00 2001 From: Maciej Baczmanski Date: Thu, 4 Jan 2024 10:27:34 +0100 Subject: [PATCH 1799/3723] net: openthread: add missing cmake option Added `OT_PLATFORM_POWER_CALIBRATION` and set to always off as in Zephyr power calibration is handled by Radio Driver. Signed-off-by: Maciej Baczmanski --- modules/openthread/CMakeLists.txt | 1 + .../platform/openthread-core-zephyr-config.h | 11 ----------- 2 files changed, 1 insertion(+), 11 deletions(-) diff --git a/modules/openthread/CMakeLists.txt b/modules/openthread/CMakeLists.txt index 6691084eebd..c9ccf074649 100644 --- a/modules/openthread/CMakeLists.txt +++ b/modules/openthread/CMakeLists.txt @@ -15,6 +15,7 @@ endmacro() set(OT_BUILD_EXECUTABLES OFF CACHE BOOL "Disable OpenThread samples") set(OT_BUILTIN_MBEDTLS_MANAGEMENT OFF CACHE BOOL "Use Zephyr's mbedTLS heap") set(OT_PLATFORM "zephyr" CACHE STRING "Zephyr as a target platform") +set(OT_PLATFORM_POWER_CALIBRATION OFF CACHE BOOL "Use Zephyr's power calibration handled by Radio Driver") set(OT_THREAD_VERSION ${CONFIG_OPENTHREAD_THREAD_VERSION} CACHE STRING "User selected Thread stack version") set(OT_CLI_TRANSPORT "CONSOLE" CACHE STRING "Set CLI to use console interpreter") diff --git a/modules/openthread/platform/openthread-core-zephyr-config.h b/modules/openthread/platform/openthread-core-zephyr-config.h index 773cd170f2c..71a087ca0b5 100644 --- a/modules/openthread/platform/openthread-core-zephyr-config.h +++ b/modules/openthread/platform/openthread-core-zephyr-config.h @@ -438,17 +438,6 @@ #define OPENTHREAD_CONFIG_POWER_CALIBRATION_ENABLE 0 #endif -/** - * @def OPENTHREAD_CONFIG_PLATFORM_POWER_CALIBRATION_ENABLE - * - * In Zephyr, power calibration is handled by Radio Driver, so it can't be handled on OT level. - * - */ -#ifndef OPENTHREAD_CONFIG_PLATFORM_POWER_CALIBRATION_ENABLE -#define OPENTHREAD_CONFIG_PLATFORM_POWER_CALIBRATION_ENABLE 0 -#endif - - /** * @def OPENTHREAD_CONFIG_RADIO_STATS * From 5752a8f3be729322cf02ff6835e4aa647af5516d Mon Sep 17 00:00:00 2001 From: Marcin Jelinski Date: Thu, 4 Jan 2024 14:23:54 +0100 Subject: [PATCH 1800/3723] samples: ipc: multi_endpoint: Fix synchronisation of data receiving The incorrect semaphore was used for the ipc1 instance to synchronise the data receiving. This commit fixes it. Signed-off-by: Marcin Jelinski --- samples/subsys/ipc/ipc_service/multi_endpoint/remote/src/main.c | 2 +- samples/subsys/ipc/ipc_service/multi_endpoint/src/main.c | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/samples/subsys/ipc/ipc_service/multi_endpoint/remote/src/main.c b/samples/subsys/ipc/ipc_service/multi_endpoint/remote/src/main.c index 9b288f8a6a1..f285f4b6d23 100644 --- a/samples/subsys/ipc/ipc_service/multi_endpoint/remote/src/main.c +++ b/samples/subsys/ipc/ipc_service/multi_endpoint/remote/src/main.c @@ -193,7 +193,7 @@ static void ipc1_ept_recv(const void *data, size_t len, void *priv) { ipc1_received_data = *((uint8_t *) data); - k_sem_give(&ipc0B_data_sem); + k_sem_give(&ipc1_data_sem); } static struct ipc_ept_cfg ipc1_ept_cfg = { diff --git a/samples/subsys/ipc/ipc_service/multi_endpoint/src/main.c b/samples/subsys/ipc/ipc_service/multi_endpoint/src/main.c index 78d7af05288..4ad5659df38 100644 --- a/samples/subsys/ipc/ipc_service/multi_endpoint/src/main.c +++ b/samples/subsys/ipc/ipc_service/multi_endpoint/src/main.c @@ -190,7 +190,7 @@ static void ipc1_ept_recv(const void *data, size_t len, void *priv) { ipc1_received_data = *((uint8_t *) data); - k_sem_give(&ipc0B_data_sem); + k_sem_give(&ipc1_data_sem); } static struct ipc_ept_cfg ipc1_ept_cfg = { From 7940c728ab12b04f62875bd893df594fc261c50f Mon Sep 17 00:00:00 2001 From: Henrik Brix Andersen Date: Mon, 11 Dec 2023 10:53:56 +0100 Subject: [PATCH 1801/3723] doc: hardware: peripherals: can: add CAN shell documentation Add documentation for the CAN shell module. Signed-off-by: Henrik Brix Andersen --- doc/hardware/peripherals/can/index.rst | 1 + doc/hardware/peripherals/can/shell.rst | 266 +++++++++++++++++++++++++ 2 files changed, 267 insertions(+) create mode 100644 doc/hardware/peripherals/can/shell.rst diff --git a/doc/hardware/peripherals/can/index.rst b/doc/hardware/peripherals/can/index.rst index 6e96fb15cb2..c605bdd0301 100644 --- a/doc/hardware/peripherals/can/index.rst +++ b/doc/hardware/peripherals/can/index.rst @@ -8,3 +8,4 @@ Controller Area Network (CAN) controller.rst transceiver.rst + shell.rst diff --git a/doc/hardware/peripherals/can/shell.rst b/doc/hardware/peripherals/can/shell.rst new file mode 100644 index 00000000000..cfd016843d0 --- /dev/null +++ b/doc/hardware/peripherals/can/shell.rst @@ -0,0 +1,266 @@ +.. _can_shell: + +CAN Shell +######### + +.. contents:: + :local: + :depth: 1 + +Overview +******** + +The CAN shell provides a ``can`` command with a set of subcommands for the :ref:`shell ` +module. It allows for testing and exploring the :ref:`can_api` driver API through an interactive +interface without having to write a dedicated application. The CAN shell can also be enabled in +existing applications to aid in interactive debugging of CAN issues. + +The CAN shell provides access to most CAN controller features, including inspection, configuration, +sending and receiving of CAN frames, and bus recovery. + +In order to enable the CAN shell, the following :ref:`Kconfig ` options must be enabled: + +* :kconfig:option:`CONFIG_SHELL` +* :kconfig:option:`CONFIG_CAN` +* :kconfig:option:`CONFIG_CAN_SHELL` + +The following :ref:`Kconfig ` options enable additional subcommands and features of the +``can`` command: + +* :kconfig:option:`CONFIG_CAN_FD_MODE` enables CAN FD specific subcommands (e.g. for setting the + timing for the CAN FD data phase). +* :kconfig:option:`CONFIG_CAN_RX_TIMESTAMP` enables printing of timestamps for received CAN frames. +* :kconfig:option:`CONFIG_CAN_STATS` enables printing of various statistics for the CAN controller + in the ``can show`` subcommand. This depends on :kconfig:option:`CONFIG_STATS` being enabled as + well. +* :kconfig:option:`CONFIG_CAN_AUTO_BUS_OFF_RECOVERY` enables the ``can recover`` subcommand when + disabled. + +For example, building the :ref:`hello_world` sample for the :ref:`frdm_k64f` with the CAN shell and +CAN statistics enabled: + +.. zephyr-app-commands:: + :zephyr-app: samples/hello_world + :board: frdm_k64f + :gen-args: -DCONFIG_SHELL=y -DCONFIG_CAN=y -DCONFIG_CAN_SHELL=y -DCONFIG_STATS=y -DCONFIG_CAN_STATS=y + :goals: build + +See the :ref:`shell ` documentation for general instructions on how to connect and +interact with the shell. The CAN shell comes with built-in help (unless +:kconfig:option:`CONFIG_SHELL_HELP` is disabled). The built-in help messages can be printed by +passing ``-h`` or ``--help`` to the ``can`` command or any of its subcommands. All subcommands also +support tab-completion of their arguments. + +.. tip:: + All of the CAN shell subcommands take the name of a CAN controller as their first argument, which + also supports tab-completion. A list of all devices available can be obtained using the ``device + list`` shell command when :kconfig:option:`CONFIG_DEVICE_SHELL` is enabled. The examples below + all use the device name ``can@0``. + +Inspection +********** + +The properties of a given CAN controller can be inspected using the ``can show`` subcommand as shown +below. The properties include the core CAN clock rate, the maximum supported bitrate, the number of +RX filters supported, capabilities, current state, error counters, timing limits, and more: + +.. code-block:: console + + uart:~$ can show can@0 + core clock: 144000000 Hz + max bitrate: 5000000 bps + max std filters: 15 + max ext filters: 15 + capabilities: normal loopback listen-only fd + state: stopped + rx errors: 0 + tx errors: 0 + timing: sjw 1..128, prop_seg 0..0, phase_seg1 2..256, phase_seg2 2..128, prescaler 1..512 + timing data: sjw 1..16, prop_seg 0..0, phase_seg1 1..32, phase_seg2 1..16, prescaler 1..32 + statistics: + bit errors: 0 + bit0 errors: 0 + bit1 errors: 0 + stuff errors: 0 + crc errors: 0 + form errors: 0 + ack errors: 0 + rx overruns: 0 + +.. note:: + The statistics are only printed if :kconfig:option:`CONFIG_CAN_STATS` is enabled. + +Configuration +************* + +The CAN shell allows for configuring the CAN controller mode and timing, along with starting and +stopping the processing of CAN frames. + +.. note:: + The CAN controller mode and timing can only be changed while the CAN controller is stopped, which + is the initial setting upon boot-up. The initial CAN controller mode is set to ``normal`` and the + initial timing is set according to the ``bus-speed``, ``sample-point``, ``bus-speed-data``, and + ``sample-point-data`` :ref:`devicetree` properties. + +Timing +====== + +The classic CAN bitrate/CAN FD arbitration phase bitrate can be configured using the ``can bitrate`` +subcommand as shown below. The bitrate is specified in bits per second. + +.. code-block:: console + + uart:~$ can bitrate can@0 125000 + setting bitrate to 125000 bps + +If :kconfig:option:`CONFIG_CAN_FD_MODE` is enabled, the data phase bitrate can be configured using +the ``can dbitrate`` subcommand as shown below. The bitrate is specified in bits per second. + +.. code-block:: console + + uart:~$ can dbitrate can@0 1000000 + setting data bitrate to 1000000 bps + +Both of these subcommands allow specifying an optional sample point in per mille and a +(Re)Synchronization Jump Width (SJW) in Time Quanta as positional arguments. Refer to the +interactive help of the subcommands for more details. + +It is also possible to configure the raw bit timing using the ``can timing`` and ``can dtiming`` +subcommands. Refer to the interactive help output for these subcommands for details on the required +arguments. + +Mode +==== + +The CAN shell allows for setting the mode of the CAN controller using the ``can mode`` +subcommand. An example for enabling loopback mode is shown below. + +.. code-block:: console + + uart:~$ can mode can@0 loopback + setting mode 0x00000001 + +The subcommand accepts multiple modes given on the same command line (e.g. ``can mode can@0 fd +loopback`` for setting CAN FD and loopback mode). Vendor-specific modes can be specified in +hexadecimal. + +Starting and Stopping +===================== + +After the timing and mode has been configured as needed, the CAN controller can be started using the +``can start`` subcommand as shown below. This will enable reception and transmission of CAN frames. + +.. code-block:: console + + uart:~$ can start can@0 + starting can@0 + +Prior to reconfiguring the timing or mode, the CAN controller needs to be stopped using the ``can +stop`` subcommand as shown below: + +.. code-block:: console + + uart:~$ can stop can@0 + stopping can@0 + +Receiving +********* + +In order to receive CAN frames, one or more CAN RX filters need to be configured. CAN RX filters are +added using the ``can filter add`` subcommand as shown below. The subcommand accepts a CAN ID in +hexadecimal format along with an optional CAN ID mask, also in hexadecimal format, for setting which +bits in the CAN ID are to be matched. Refer to the interactive help output for this subcommand for +further details on the supported arguments. + +.. code-block:: console + + uart:~$ can filter add can@0 010 + adding filter with standard (11-bit) CAN ID 0x010, CAN ID mask 0x7ff, data frames 1, RTR frames 0, CAN FD frames 0 + filter ID: 0 + +The filter ID (0 in the example above) returned is to be used when removing the CAN RX filter. + +Received CAN frames matching the added filter(s) are printed to the shell. A few examples are shown below: + +.. code-block:: console + + # Flags ID Size Data bytes + -- 010 [8] 01 02 03 04 05 06 07 08 + B- 010 [08] 01 02 03 04 05 06 07 08 + BP 010 [03] 01 aa bb + -- 00000010 [0] + -- 010 [1] 20 + -- 010 [8] remote transmission request + +The columns have the following meaning: + +* Flags + + * ``B``: The frame has the CAN FD Baud Rate Switch (BRS) flag set. + * ``P``: The frame has the CAN FD Error State Indicator (ESI) flag set. The transmitting node is + in error-passive state. + * ``-``: Unset flag. + +* ID + + * ``010``: The standard (11-bit) CAN ID of the frame in hexadecimal format, here 10h. + * ``00000010``: The extended (29-bit) CAN ID of the frame in hexadecimal format, here 10h. + +* Size + + * ``[8]``: The number of frame data bytes in decimal format, here a classic CAN frame with 8 data + bytes. + * ``[08]``: The number of frame data bytes in decimal format, here a CAN FD frame with 8 data + bytes. + +* Data bytes + + * ``01 02 03 04 05 06 07 08``: The frame data bytes in hexadecimal format, here the numbers from 1 + through 8. + * ``remote transmission request``: The frame is a Remote Transmission Request (RTR) frame and thus + carries no data bytes. + +.. tip:: + If :kconfig:option:`CONFIG_CAN_RX_TIMESTAMP` is enabled, each line will be prepended with a + timestamp from the free-running timestamp counter in the CAN controller. + +Configured CAN RX filters can be removed again using the ``can filter remove`` subcommand as shown +below. The filter ID is the ID returned by the ``can filter add`` subcommand (0 in the example +below). + +.. code-block:: console + + uart:~$ can filter remove can@0 0 + removing filter with ID 0 + +Sending +******* + +CAN frames can be queued for transmission using the ``can send`` subcommand as shown below. The +subcommand accepts a CAN ID in hexadecimal format and optionally a number of data bytes, also +specified in hexadecimal. Refer to the interactive help output for this subcommand for further +details on the supported arguments. + +.. code-block:: console + + uart:~$ can send can@0 010 1 2 3 4 5 6 7 8 + enqueuing CAN frame #2 with standard (11-bit) CAN ID 0x010, RTR 0, CAN FD 0, BRS 0, DLC 8 + CAN frame #2 successfully sent + +Bus Recovery +************ + +The ``can recover`` subcommand can be used for initiating recovery from a CAN bus-off event as shown +below: + +.. code-block:: console + + uart:~$ can recover can@0 + recovering, no timeout + +The subcommand accepts an optional bus recovery timeout in milliseconds. If no timeout is specified, +the command will wait indefinitely for the bus recovery to succeed. + +.. note:: + The ``recover`` subcommand is only available if + :kconfig:option:`CONFIG_CAN_AUTO_BUS_OFF_RECOVERY` is disabled. From 5f4545d9dda480a551f0e05927598db5dd0f6000 Mon Sep 17 00:00:00 2001 From: Bjarki Arge Andreasen Date: Fri, 5 Jan 2024 12:48:24 +0100 Subject: [PATCH 1802/3723] doc: peripherals: Add emulated RTC doc to docs Adds documentation of emulated RTC behavior. Signed-off-by: Bjarki Arge Andreasen --- doc/hardware/peripherals/rtc.rst | 21 +++++++++++++++++++++ 1 file changed, 21 insertions(+) diff --git a/doc/hardware/peripherals/rtc.rst b/doc/hardware/peripherals/rtc.rst index d2552d078ee..ae69df0b446 100644 --- a/doc/hardware/peripherals/rtc.rst +++ b/doc/hardware/peripherals/rtc.rst @@ -126,3 +126,24 @@ be printed to the console. .. note:: The tests take up to 30 seconds each if they are testing real hardware. + +.. _rtc_api_emul_dev: + +RTC emulated device +******************* + +The emulated RTC device fully implements the RTC API, and will behave like a real +RTC device, with the following limitations: + +* RTC time is not persistent across application initialization. +* RTC alarms are not persistent across application initialization. +* RTC time will drift over time. + +Every time an application is initialized, the RTC's time and alarms are reset. Reading +the time using :c:func:`rtc_get_time` will return ``-ENODATA``, until the time is +set using :c:func:`rtc_set_time`. The RTC will then behave as a real RTC, until the +application is reset. + +The emulated RTC device driver is built for the compatible +:dtcompatible:`zephyr,rtc-emul` and will be included if :kconfig:option:`CONFIG_RTC` +is selected. From de855162a779ab975c72ec16a034876dbb2b4f7f Mon Sep 17 00:00:00 2001 From: Bjarki Arge Andreasen Date: Fri, 5 Jan 2024 13:00:22 +0100 Subject: [PATCH 1803/3723] doc: emul: Adjust reference to emulated RTC docs Add reference to section in RTC peripheral documentation which covers the emulated RTC. Signed-off-by: Bjarki Arge Andreasen --- doc/hardware/emulator/index.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/doc/hardware/emulator/index.rst b/doc/hardware/emulator/index.rst index 0029de31700..0b3a809e4dd 100644 --- a/doc/hardware/emulator/index.rst +++ b/doc/hardware/emulator/index.rst @@ -76,7 +76,7 @@ Available Emulators * DT binding: :dtcompatible:`zephyr,i2c-emul-controller` **RTC emulator** - * Emulates an RTC with a timed work-queue item. + * Emulated RTC peripheral. See :ref:`RTC emulated device section ` * Main Kconfig option: :kconfig:option:`CONFIG_RTC_EMUL` * DT binding: :dtcompatible:`zephyr,rtc-emul` From a8914c56d2c8340cb62662fa5c6e7becb32765da Mon Sep 17 00:00:00 2001 From: Peter Mitsis Date: Thu, 4 Jan 2024 11:25:03 -0500 Subject: [PATCH 1804/3723] tests: latency_measure: Add events Adds events to the latency_measure benchmark. Signed-off-by: Peter Mitsis --- tests/benchmarks/latency_measure/prj.conf | 3 + .../benchmarks/latency_measure/prj_user.conf | 3 + tests/benchmarks/latency_measure/src/events.c | 282 ++++++++++++++++++ tests/benchmarks/latency_measure/src/main.c | 17 +- tests/benchmarks/latency_measure/src/utils.h | 4 +- 5 files changed, 306 insertions(+), 3 deletions(-) create mode 100644 tests/benchmarks/latency_measure/src/events.c diff --git a/tests/benchmarks/latency_measure/prj.conf b/tests/benchmarks/latency_measure/prj.conf index a1ca84e4dc1..89ec3458703 100644 --- a/tests/benchmarks/latency_measure/prj.conf +++ b/tests/benchmarks/latency_measure/prj.conf @@ -27,3 +27,6 @@ CONFIG_APPLICATION_DEFINED_SYSCALL=y # Disable time slicing CONFIG_TIMESLICING=n + +# Enable events +CONFIG_EVENTS=y diff --git a/tests/benchmarks/latency_measure/prj_user.conf b/tests/benchmarks/latency_measure/prj_user.conf index 62ce8cafb52..7119db2962d 100644 --- a/tests/benchmarks/latency_measure/prj_user.conf +++ b/tests/benchmarks/latency_measure/prj_user.conf @@ -28,3 +28,6 @@ CONFIG_USERSPACE=y # Disable time slicing CONFIG_TIMESLICING=n + +# Enable events +CONFIG_EVENTS=y diff --git a/tests/benchmarks/latency_measure/src/events.c b/tests/benchmarks/latency_measure/src/events.c new file mode 100644 index 00000000000..dac6f8ea1fa --- /dev/null +++ b/tests/benchmarks/latency_measure/src/events.c @@ -0,0 +1,282 @@ +/* + * Copyright (c) 2024 Intel Corporation + * + * SPDX-License-Identifier: Apache-2.0 + */ + +/* + * @file measure time for various event operations + * + * This file contains the tests that measure the times for manipulating + * event objects from both kernel and user threads: + * 1. Immediately posting and setting events + * 2. Immediately receiving any or all events. + * 3. Blocking to receive either any or all events. + * 4. Waking (and switching to) a thread waiting for any or all events. + */ + +#include +#include +#include "utils.h" +#include "timing_sc.h" + +#define BENCH_EVENT_SET 0x1234 +#define ALL_EVENTS 0xFFFFFFFF + +static K_EVENT_DEFINE(event_set); + +static void event_ops_entry(void *p1, void *p2, void *p3) +{ + uint32_t num_iterations = (uint32_t)(uintptr_t)p1; + uint32_t options = (uint32_t)(uintptr_t)p2; + timing_t start; + timing_t finish; + uint32_t i; + uint64_t cycles; + char description[80]; + + k_event_clear(&event_set, ALL_EVENTS); + + start = timing_timestamp_get(); + for (i = 0; i < num_iterations; i++) { + k_event_post(&event_set, BENCH_EVENT_SET); + } + finish = timing_timestamp_get(); + + snprintf(description, sizeof(description), + "EVENTS post.immediate.%s", + (options & K_USER) ? "user" : "kernel"); + cycles = timing_cycles_get(&start, &finish); + PRINT_STATS_AVG(description, (uint32_t)cycles, + num_iterations, false, ""); + + start = timing_timestamp_get(); + for (i = 0; i < num_iterations; i++) { + k_event_set(&event_set, BENCH_EVENT_SET); + } + finish = timing_timestamp_get(); + + snprintf(description, sizeof(description), + "EVENTS set.immediate.%s", + (options & K_USER) ? "user" : "kernel"); + cycles = timing_cycles_get(&start, &finish); + PRINT_STATS_AVG(description, (uint32_t)cycles, + num_iterations, false, ""); + + start = timing_timestamp_get(); + for (i = 0; i < num_iterations; i++) { + k_event_wait(&event_set, BENCH_EVENT_SET, false, K_FOREVER); + } + finish = timing_timestamp_get(); + + snprintf(description, sizeof(description), + "EVENTS wait.immediate.%s", + (options & K_USER) ? "user" : "kernel"); + cycles = timing_cycles_get(&start, &finish); + PRINT_STATS_AVG(description, (uint32_t)cycles, + num_iterations, false, ""); + + start = timing_timestamp_get(); + for (i = 0; i < num_iterations; i++) { + k_event_wait_all(&event_set, BENCH_EVENT_SET, false, K_FOREVER); + } + finish = timing_timestamp_get(); + + snprintf(description, sizeof(description), + "EVENTS wait_all.immediate.%s", + (options & K_USER) ? "user" : "kernel"); + cycles = timing_cycles_get(&start, &finish); + PRINT_STATS_AVG(description, (uint32_t)cycles, + num_iterations, false, ""); +} + +static void start_thread_entry(void *p1, void *p2, void *p3) +{ + uint32_t num_iterations = (uint32_t)(uintptr_t)p1; + uint32_t options = (uint32_t)(uintptr_t)p2; + uint32_t alt_options = (uint32_t)(uintptr_t)p3; + uint32_t i; + uint64_t cycles; + char description[80]; + + k_thread_start(&alt_thread); + + for (i = 0; i < num_iterations; i++) { + + /* 2. Set the events to wake alt_thread */ + + timestamp.sample = timing_timestamp_get(); + k_event_set(&event_set, BENCH_EVENT_SET); + } + + snprintf(description, sizeof(description), + "EVENTS wait.blocking.(%c -> %c)", + (alt_options & K_USER) ? 'U' : 'K', + (options & K_USER) ? 'U' : 'K'); + cycles = timestamp.cycles - + timestamp_overhead_adjustment(options, alt_options); + PRINT_STATS_AVG(description, (uint32_t)cycles, + num_iterations, false, ""); + k_sem_give(&pause_sem); + + snprintf(description, sizeof(description), + "EVENTS set.wake+ctx.(%c -> %c)", + (options & K_USER) ? 'U' : 'K', + (alt_options & K_USER) ? 'U' : 'K'); + cycles = timestamp.cycles - + timestamp_overhead_adjustment(options, alt_options); + PRINT_STATS_AVG(description, (uint32_t)cycles, + num_iterations, false, ""); + k_sem_give(&pause_sem); + + for (i = 0; i < num_iterations; i++) { + + /* 5. Post the events to wake alt_thread */ + + timestamp.sample = timing_timestamp_get(); + k_event_post(&event_set, BENCH_EVENT_SET); + } + + snprintf(description, sizeof(description), + "EVENTS wait_all.blocking.(%c -> %c)", + (alt_options & K_USER) ? 'U' : 'K', + (options & K_USER) ? 'U' : 'K'); + cycles = timestamp.cycles; + PRINT_STATS_AVG(description, (uint32_t)cycles, + num_iterations, false, ""); + k_sem_give(&pause_sem); + + snprintf(description, sizeof(description), + "EVENTS post.wake+ctx.(%c -> %c)", + (options & K_USER) ? 'U' : 'K', + (alt_options & K_USER) ? 'U' : 'K'); + cycles = timestamp.cycles; + PRINT_STATS_AVG(description, (uint32_t)cycles, + num_iterations, false, ""); + + k_thread_join(&alt_thread, K_FOREVER); +} + +static void alt_thread_entry(void *p1, void *p2, void *p3) +{ + uint32_t num_iterations = (uint32_t)(uintptr_t)p1; + uint32_t i; + timing_t start; + timing_t mid; + timing_t finish; + uint64_t sum1 = 0ULL; + uint64_t sum2 = 0ULL; + + for (i = 0; i < num_iterations; i++) { + + /* 1. Wait for any of the events */ + + start = timing_timestamp_get(); + k_event_wait(&event_set, BENCH_EVENT_SET, true, K_FOREVER); + + /* 3. Record the final timestamp */ + + finish = timing_timestamp_get(); + mid = timestamp.sample; + + sum1 += timing_cycles_get(&start, &mid); + sum2 += timing_cycles_get(&mid, &finish); + } + + /* Let start_thread print the results */ + + timestamp.cycles = sum1; + k_sem_take(&pause_sem, K_FOREVER); + + timestamp.cycles = sum2; + k_sem_take(&pause_sem, K_FOREVER); + + sum1 = 0ULL; + sum2 = 0ULL; + + for (i = 0; i < num_iterations; i++) { + + /* 4. Wait for all of the events */ + + start = timing_timestamp_get(); + k_event_wait_all(&event_set, BENCH_EVENT_SET, true, K_FOREVER); + + /* 6. Record the final timestamp */ + + finish = timing_timestamp_get(); + mid = timestamp.sample; + + sum1 += timing_cycles_get(&start, &mid); + sum2 += timing_cycles_get(&mid, &finish); + } + + /* Let start_thread print the results */ + + timestamp.cycles = sum1; + k_sem_take(&pause_sem, K_FOREVER); + + timestamp.cycles = sum2; +} + +int event_ops(uint32_t num_iterations, uint32_t options) +{ + int priority; + + priority = k_thread_priority_get(k_current_get()); + + timing_start(); + + k_thread_create(&start_thread, start_stack, + K_THREAD_STACK_SIZEOF(start_stack), + event_ops_entry, + (void *)(uintptr_t)num_iterations, + (void *)(uintptr_t)options, NULL, + priority - 1, options, K_FOREVER); + + k_thread_access_grant(&start_thread, &event_set); + + k_thread_start(&start_thread); + + k_thread_join(&start_thread, K_FOREVER); + + timing_stop(); + + return 0; +} + +int event_blocking_ops(uint32_t num_iterations, uint32_t start_options, + uint32_t alt_options) +{ + int priority; + + priority = k_thread_priority_get(k_current_get()); + + timing_start(); + + k_thread_create(&start_thread, start_stack, + K_THREAD_STACK_SIZEOF(start_stack), + start_thread_entry, + (void *)(uintptr_t)num_iterations, + (void *)(uintptr_t)start_options, + (void *)(uintptr_t)alt_options, + priority - 1, start_options, K_FOREVER); + + k_thread_create(&alt_thread, alt_stack, + K_THREAD_STACK_SIZEOF(alt_stack), + alt_thread_entry, + (void *)(uintptr_t)num_iterations, + (void *)(uintptr_t)alt_options, NULL, + priority - 2, alt_options, K_FOREVER); + + k_thread_access_grant(&start_thread, &alt_thread, &event_set, + &pause_sem); + k_thread_access_grant(&alt_thread, &event_set, &pause_sem); + + k_thread_start(&start_thread); + + k_thread_join(&start_thread, K_FOREVER); + + timing_stop(); + + return 0; +} diff --git a/tests/benchmarks/latency_measure/src/main.c b/tests/benchmarks/latency_measure/src/main.c index fcd01b86243..d499e65ad6f 100644 --- a/tests/benchmarks/latency_measure/src/main.c +++ b/tests/benchmarks/latency_measure/src/main.c @@ -29,7 +29,7 @@ K_APPMEM_PARTITION_DEFINE(bench_mem_partition); #endif K_THREAD_STACK_DEFINE(start_stack, START_STACK_SIZE); -K_THREAD_STACK_DEFINE(alt_stack, START_STACK_SIZE); +K_THREAD_STACK_DEFINE(alt_stack, ALT_STACK_SIZE); K_SEM_DEFINE(pause_sem, 0, 1); @@ -52,6 +52,9 @@ extern int fifo_blocking_ops(uint32_t num_iterations, uint32_t start_options, extern int lifo_ops(uint32_t num_iterations, uint32_t options); extern int lifo_blocking_ops(uint32_t num_iterations, uint32_t start_options, uint32_t alt_options); +extern int event_ops(uint32_t num_iterations, uint32_t options); +extern int event_blocking_ops(uint32_t num_iterations, uint32_t start_options, + uint32_t alt_options); extern void heap_malloc_free(void); static void test_thread(void *arg1, void *arg2, void *arg3) @@ -120,6 +123,18 @@ static void test_thread(void *arg1, void *arg2, void *arg3) lifo_blocking_ops(NUM_ITERATIONS, K_USER, K_USER); #endif + event_ops(NUM_ITERATIONS, 0); +#ifdef CONFIG_USERSPACE + event_ops(NUM_ITERATIONS, K_USER); +#endif + + event_blocking_ops(NUM_ITERATIONS, 0, 0); +#ifdef CONFIG_USERSPACE + event_blocking_ops(NUM_ITERATIONS, 0, K_USER); + event_blocking_ops(NUM_ITERATIONS, K_USER, 0); + event_blocking_ops(NUM_ITERATIONS, K_USER, K_USER); +#endif + sema_test_signal(NUM_ITERATIONS, 0); #ifdef CONFIG_USERSPACE sema_test_signal(NUM_ITERATIONS, K_USER); diff --git a/tests/benchmarks/latency_measure/src/utils.h b/tests/benchmarks/latency_measure/src/utils.h index cbba26d4fe0..7f3f0bde4e1 100644 --- a/tests/benchmarks/latency_measure/src/utils.h +++ b/tests/benchmarks/latency_measure/src/utils.h @@ -17,8 +17,8 @@ #include #include -#define START_STACK_SIZE (512 + CONFIG_TEST_EXTRA_STACK_SIZE) -#define ALT_STACK_SIZE (512 + CONFIG_TEST_EXTRA_STACK_SIZE) +#define START_STACK_SIZE (1024 + CONFIG_TEST_EXTRA_STACK_SIZE) +#define ALT_STACK_SIZE (1024 + CONFIG_TEST_EXTRA_STACK_SIZE) #ifdef CONFIG_USERSPACE #define BENCH_BMEM K_APP_BMEM(bench_mem_partition) From 8d40d3ba3000e5011a53df8508168930746daccb Mon Sep 17 00:00:00 2001 From: Peter Mitsis Date: Fri, 5 Jan 2024 10:53:22 -0500 Subject: [PATCH 1805/3723] tests: latency_measure: Update sample output Updates the sample output in the latency_measure benchmark's README file to cover events. Signed-off-by: Peter Mitsis --- tests/benchmarks/latency_measure/README.rst | 35 +++++++++++++++++++++ 1 file changed, 35 insertions(+) diff --git a/tests/benchmarks/latency_measure/README.rst b/tests/benchmarks/latency_measure/README.rst index a061d8c5a52..7e6f5787ab8 100644 --- a/tests/benchmarks/latency_measure/README.rst +++ b/tests/benchmarks/latency_measure/README.rst @@ -20,6 +20,9 @@ including: * Time it takes to retrieve data from a FIFO/LIFO * Time it takes to wait on a FIFO/LIFO (and context switch) * Time it takes to wake and switch to a thread waiting on a FIFO/LIFO +* Time it takes to send and receive events +* Time it takes to wait for events (and context switch) +* Time it takes to wake and switch to a thread waiting for events * Measure average time to alloc memory from heap then free that memory When userspace is enabled using the prj_user.conf configuration file, this benchmark will @@ -59,6 +62,14 @@ Sample output of the benchmark (without userspace enabled):: LIFO put.wake+ctx.(K -> K) : 670 cycles , 5584 ns : LIFO get.free.blocking.(K -> K) : 547 cycles , 4558 ns : LIFO put.alloc.wake+ctx.(K -> K) : 670 cycles , 5583 ns : + EVENTS post.immediate.kernel : 220 cycles , 1833 ns : + EVENTS set.immediate.kernel : 225 cycles , 1875 ns : + EVENTS wait.immediate.kernel : 125 cycles , 1041 ns : + EVENTS wait_all.immediate.kernel : 145 cycles , 1208 ns : + EVENTS wait.blocking.(K -> K) : 594 cycles , 4958 ns : + EVENTS set.wake+ctx.(K -> K) : 774 cycles , 6451 ns : + EVENTS wait_all.blocking.(K -> K) : 605 cycles , 5042 ns : + EVENTS post.wake+ctx.(K -> K) : 785 cycles , 6542 ns : SEMAPHORE give.immediate.kernel : 165 cycles , 1375 ns : SEMAPHORE take.immediate.kernel : 69 cycles , 575 ns : SEMAPHORE take.blocking.(K -> K) : 489 cycles , 4075 ns : @@ -135,6 +146,30 @@ Sample output of the benchmark (with userspace enabled):: LIFO put.alloc.wake+ctx.(U -> K) : 1855 cycles , 15459 ns : LIFO get.free.blocking.(U -> U) : 2070 cycles , 17251 ns : LIFO put.alloc.wake+ctx.(U -> U) : 2190 cycles , 18251 ns : + EVENTS post.immediate.kernel : 285 cycles , 2375 ns : + EVENTS set.immediate.kernel : 285 cycles , 2375 ns : + EVENTS wait.immediate.kernel : 215 cycles , 1791 ns : + EVENTS wait_all.immediate.kernel : 215 cycles , 1791 ns : + EVENTS post.immediate.user : 775 cycles , 6459 ns : + EVENTS set.immediate.user : 780 cycles , 6500 ns : + EVENTS wait.immediate.user : 715 cycles , 5959 ns : + EVENTS wait_all.immediate.user : 720 cycles , 6000 ns : + EVENTS wait.blocking.(K -> K) : 1212 cycles , 10108 ns : + EVENTS set.wake+ctx.(K -> K) : 1450 cycles , 12084 ns : + EVENTS wait_all.blocking.(K -> K) : 1260 cycles , 10500 ns : + EVENTS post.wake+ctx.(K -> K) : 1490 cycles , 12417 ns : + EVENTS wait.blocking.(U -> K) : 1577 cycles , 13145 ns : + EVENTS set.wake+ctx.(K -> U) : 1617 cycles , 13479 ns : + EVENTS wait_all.blocking.(U -> K) : 1760 cycles , 14667 ns : + EVENTS post.wake+ctx.(K -> U) : 1790 cycles , 14917 ns : + EVENTS wait.blocking.(K -> U) : 1400 cycles , 11671 ns : + EVENTS set.wake+ctx.(U -> K) : 1812 cycles , 15104 ns : + EVENTS wait_all.blocking.(K -> U) : 1580 cycles , 13167 ns : + EVENTS post.wake+ctx.(U -> K) : 1985 cycles , 16542 ns : + EVENTS wait.blocking.(U -> U) : 1765 cycles , 14709 ns : + EVENTS set.wake+ctx.(U -> U) : 1979 cycles , 16499 ns : + EVENTS wait_all.blocking.(U -> U) : 2080 cycles , 17334 ns : + EVENTS post.wake+ctx.(U -> U) : 2285 cycles , 19043 ns : SEMAPHORE give.immediate.kernel : 210 cycles , 1750 ns : SEMAPHORE take.immediate.kernel : 145 cycles , 1208 ns : SEMAPHORE give.immediate.user : 715 cycles , 5959 ns : From 5993192ec1ac81484e4e5f14e1688298dacd3ead Mon Sep 17 00:00:00 2001 From: Mathieu Choplain Date: Fri, 5 Jan 2024 17:38:58 +0100 Subject: [PATCH 1806/3723] llext: fix incorrect elf64_sym structure The elf64_sym structure was defined as having the members order as the elf32_sym structure, which is incorrect. Use the correct layout as defined by the ELF specification (see https://refspecs.linuxfoundation.org/elf/gabi4+/ch4.symtab.html) Signed-off-by: Mathieu Choplain --- include/zephyr/llext/elf.h | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/include/zephyr/llext/elf.h b/include/zephyr/llext/elf.h index 6dc3cc4e5c8..a9fd8f86a94 100644 --- a/include/zephyr/llext/elf.h +++ b/include/zephyr/llext/elf.h @@ -231,16 +231,16 @@ struct elf32_sym { struct elf64_sym { /** Name of the symbol as an index into the symbol string table */ elf64_word st_name; - /** Value or location of the symbol */ - elf64_addr st_value; - /** Size of the symbol */ - elf64_xword st_size; /** Symbol binding and type information */ unsigned char st_info; /** Symbol visibility */ unsigned char st_other; /** Symbols related section given by section header index */ elf64_half st_shndx; + /** Value or location of the symbol */ + elf64_addr st_value; + /** Size of the symbol */ + elf64_xword st_size; }; #define SHN_UNDEF 0 From 991a85361ee03ec78b10272c28accce9cd7e90bf Mon Sep 17 00:00:00 2001 From: Mathieu Choplain Date: Fri, 5 Jan 2024 17:42:42 +0100 Subject: [PATCH 1807/3723] llext: use generic attributes instead of GCC's Replace the GCC-syntax attributes used for LL_EXTENSION_SYMBOL with the toolchain-independent versions provided in toolchain.h Signed-off-by: Mathieu Choplain --- include/zephyr/llext/symbol.h | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/include/zephyr/llext/symbol.h b/include/zephyr/llext/symbol.h index 2c6505ee12f..19f34649026 100644 --- a/include/zephyr/llext/symbol.h +++ b/include/zephyr/llext/symbol.h @@ -8,6 +8,7 @@ #define ZEPHYR_LLEXT_SYMBOL_H #include +#include #include #ifdef __cplusplus @@ -78,8 +79,9 @@ struct llext_symtable { .name = STRINGIFY(x), .addr = &x, \ } -#define LL_EXTENSION_SYMBOL(x) struct llext_symbol __attribute__((section(".exported_sym"), used)) \ - symbol_##x = {STRINGIFY(x), &x} +#define LL_EXTENSION_SYMBOL(x) \ + struct llext_symbol Z_GENERIC_SECTION(".exported_sym") __used \ + symbol_##x = {STRINGIFY(x), &x} /** * @brief Export a system call to a table of symbols From bba517fa1484f8715037d14953a32f11a69ca0b8 Mon Sep 17 00:00:00 2001 From: Fabio Baltieri Date: Wed, 27 Dec 2023 16:53:16 +0000 Subject: [PATCH 1808/3723] input: tweak actual-key-mask description Tweak the actual-key-mask description, apply some leftover feedback from the prevoius PR. Signed-off-by: Fabio Baltieri --- drivers/input/Kconfig.kbd_matrix | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/drivers/input/Kconfig.kbd_matrix b/drivers/input/Kconfig.kbd_matrix index cbacb9ca4c0..18f17b815a9 100644 --- a/drivers/input/Kconfig.kbd_matrix +++ b/drivers/input/Kconfig.kbd_matrix @@ -30,9 +30,9 @@ config INPUT_KBD_MATRIX_16_BIT_ROW config INPUT_KBD_ACTUAL_KEY_MASK_DYNAMIC bool "Allow runtime changes to the actual key mask" help - If enabled, the actual key mask data is stored in RAM, and a - input_kbd_matrix_actual_key_mask_set() function is available to - change the content at runtime. + If enabled, the actual-key-mask devicetree property data is stored in + RAM, and a input_kbd_matrix_actual_key_mask_set() function is + available to change the content at runtime. config INPUT_SHELL_KBD_MATRIX_STATE bool "Input kbd_matrix_state shell command" From 79e10f0d0f1b479d2443c89f93e12aa00e9e8964 Mon Sep 17 00:00:00 2001 From: Fabio Baltieri Date: Fri, 1 Dec 2023 14:56:08 +0000 Subject: [PATCH 1809/3723] doc: input: add a dedicated GPIO keyboard documentation This driver supports few different hardware configurations, add a document page showing some of them next to some schematics snippets Signed-off-by: Fabio Baltieri --- doc/services/input/diodes-cr.svg | 6140 ++++++++++++++++++++++++++++++ doc/services/input/diodes-rc.svg | 6140 ++++++++++++++++++++++++++++++ doc/services/input/gpio-kbd.rst | 240 ++ doc/services/input/index.rst | 14 +- doc/services/input/no-diodes.svg | 2689 +++++++++++++ doc/services/input/no-sw4.svg | 2496 ++++++++++++ 6 files changed, 17714 insertions(+), 5 deletions(-) create mode 100644 doc/services/input/diodes-cr.svg create mode 100644 doc/services/input/diodes-rc.svg create mode 100644 doc/services/input/gpio-kbd.rst create mode 100644 doc/services/input/no-diodes.svg create mode 100644 doc/services/input/no-sw4.svg diff --git a/doc/services/input/diodes-cr.svg b/doc/services/input/diodes-cr.svg new file mode 100644 index 00000000000..d374b8e0c41 --- /dev/null +++ b/doc/services/input/diodes-cr.svg @@ -0,0 +1,6140 @@ + + + + SVG Image created as keyboard-matrix-testboard-diodes-cr.svg date 2023/12/18 09:58:32 + Image generated by Eeschema-SVG + + + + + + + + + + + + + + + + + + + + + + + + + SW6 + + SW6 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + SW1 + + SW1 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + D4 + + D4 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + D2 + + D2 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + SW3 + + SW3 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + SW2 + + SW2 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + D1 + + D1 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + SW9 + + SW9 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + SW5 + + SW5 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + D6 + + D6 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + SW7 + + SW7 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + SW4 + + SW4 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + D5 + + D5 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + D7 + + D7 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + D3 + + D3 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + SW8 + + SW8 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + D8 + + D8 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + D9 + + D9 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + ROW2 + + ROW2 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + COL1 + + + COL1 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + ROW1 + + ROW1 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + COL2 + + + COL2 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + COL0 + + + COL0 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + ROW0 + + ROW0 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + SW4 + + SW4 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + D1 + + D1 + + + + + + + + + + + + + + + + + + + + + + + + + SW1 + + SW1 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + D4 + + D4 + + + + + + + + + + + + + + + + + + + + + + + SW9 + + SW9 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + D6 + + D6 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + D5 + + D5 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + SW8 + + SW8 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + D8 + + D8 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + D9 + + D9 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + D7 + + D7 + + + + + + + + + + + + + + + + + + + + + + SW7 + + SW7 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + SW2 + + SW2 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + D2 + + D2 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + SW3 + + SW3 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + SW5 + + SW5 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + D3 + + D3 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + SW6 + + SW6 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/doc/services/input/diodes-rc.svg b/doc/services/input/diodes-rc.svg new file mode 100644 index 00000000000..91e0f9607ab --- /dev/null +++ b/doc/services/input/diodes-rc.svg @@ -0,0 +1,6140 @@ + + + + SVG Image created as keyboard-matrix-testboard-diodes-rc.svg date 2023/12/18 09:58:32 + Image generated by Eeschema-SVG + + + + + + + + + + + + + + + + + + + + + + + + + SW7 + + SW7 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + SW2 + + SW2 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + D3 + + D3 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + D2 + + D2 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + D6 + + D6 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + SW3 + + SW3 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + D5 + + D5 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + SW1 + + SW1 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + D1 + + D1 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + SW4 + + SW4 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + D4 + + D4 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + D7 + + D7 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + SW5 + + SW5 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + D9 + + D9 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + SW6 + + SW6 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + SW9 + + SW9 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + D8 + + D8 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + SW8 + + SW8 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + COL0 + + + COL0 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + ROW0 + + ROW0 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + ROW1 + + ROW1 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + ROW2 + + ROW2 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + COL2 + + + COL2 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + COL1 + + + COL1 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + SW8 + + SW8 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + D8 + + D8 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + SW9 + + SW9 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + SW6 + + SW6 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + D9 + + D9 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + SW5 + + SW5 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + D7 + + D7 + + + + + + + + + + + + + + + + + + + + + + SW7 + + SW7 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + D4 + + D4 + + + + + + + + + + + + + + + + + + + + + + + SW4 + + SW4 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + D1 + + D1 + + + + + + + + + + + + + + + + + + + + + + + + + SW1 + + SW1 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + D5 + + D5 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + SW3 + + SW3 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + D6 + + D6 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + D2 + + D2 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + D3 + + D3 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + SW2 + + SW2 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/doc/services/input/gpio-kbd.rst b/doc/services/input/gpio-kbd.rst new file mode 100644 index 00000000000..fffabc7ac79 --- /dev/null +++ b/doc/services/input/gpio-kbd.rst @@ -0,0 +1,240 @@ +.. _gpio-kbd: + +GPIO Keyboard Matrix +#################### + +The :dtcompatible:`gpio-kbd-matrix` driver supports a large variety of keyboard +matrix hardware configurations and has numerous options to change its behavior. +This is an overview of some common setups and how they can be supported by the +driver. + +The conventional configuration for all of these is that the driver reads on the +row GPIOs (inputs) and selects on the columns GPIOs (output). + +Base use case, no isolation diodes, interrupt capable GPIOs +*********************************************************** + +This is the common configuration found on consumer keyboards with membrane +switches and flexible circuit boards, no isolation diodes, requires ghosting +detection (which is enabled by default). + +.. figure:: no-diodes.svg + :align: center + :width: 50% + + A 3x3 matrix, no diodes + +The system must support GPIO interrupts, and the interrupt can be enabled on all +row GPIOs at the same time. + +.. code-block:: devicetree + + kbd-matrix { + compatible = "gpio-kbd-matrix"; + row-gpios = <&gpio0 0 (GPIO_PULL_UP | GPIO_ACTIVE_LOW)>, + <&gpio0 1 (GPIO_PULL_UP | GPIO_ACTIVE_LOW)>, + <&gpio0 2 (GPIO_PULL_UP | GPIO_ACTIVE_LOW)>; + col-gpios = <&gpio0 3 GPIO_ACTIVE_LOW>, + <&gpio0 4 GPIO_ACTIVE_LOW>, + <&gpio0 5 GPIO_ACTIVE_LOW>; + }; + +In this configuration the matrix scanning library enters idle mode once all +keys are released, and the keyboard matrix thread only wakes up when a key has +been pressed. + +GPIOs for columns that are not currently selected are configured in high +impedance mode. This means that the row state may need some time to settle to +avoid misreading the key state from a column to the following one. The settle +time can be tweaked by changing the ``settle-time-us`` property. + +Isolation diodes +**************** + +If the matrix has isolation diodes for every key, then it's possible to: + + - disable ghosting detection, allowing any key combination to be detected + - configuring the driver to drive unselected columns GPIO to inactive state + rather than high impedance, this allows to reduce the settle time + (potentially down to 0), and use the more efficient port wide GPIO read APIs + (happens automatically if the GPIO pins are sequential) + +Matrixes with diodes going from rows to columns must use pull-ups on rows and +active low columns. + +.. figure:: diodes-rc.svg + :align: center + :width: 50% + + A 3x3 matrix with row to column isolation diodes. + +.. code-block:: devicetree + + kbd-matrix { + compatible = "gpio-kbd-matrix"; + row-gpios = <&gpio0 0 (GPIO_PULL_UP | GPIO_ACTIVE_LOW)>, + <&gpio0 1 (GPIO_PULL_UP | GPIO_ACTIVE_LOW)>, + <&gpio0 2 (GPIO_PULL_UP | GPIO_ACTIVE_LOW)>; + col-gpios = <&gpio0 3 GPIO_ACTIVE_LOW>, + <&gpio0 4 GPIO_ACTIVE_LOW>, + <&gpio0 5 GPIO_ACTIVE_LOW>; + col-drive-inactive; + settle-time-us = <0>; + no-ghostkey-check; + }; + +Matrixes with diodes going from columns to rows must use pull-downs on rows and +active high columns. + +.. figure:: diodes-cr.svg + :align: center + :width: 50% + + A 3x3 matrix with column to row isolation diodes. + +.. code-block:: devicetree + + kbd-matrix { + compatible = "gpio-kbd-matrix"; + row-gpios = <&gpio0 0 (GPIO_PULL_DOWN | GPIO_ACTIVE_HIGH)>, + <&gpio0 1 (GPIO_PULL_DOWN | GPIO_ACTIVE_HIGH)>, + <&gpio0 2 (GPIO_PULL_DOWN | GPIO_ACTIVE_HIGH)>; + col-gpios = <&gpio0 3 GPIO_ACTIVE_HIGH>, + <&gpio0 4 GPIO_ACTIVE_HIGH>, + <&gpio0 5 GPIO_ACTIVE_HIGH>; + col-drive-inactive; + settle-time-us = <0>; + no-ghostkey-check; + }; + +GPIO with no interrupt support +****************************** + +Some GPIO controllers have limitations on GPIO interrupts, and may not support +enabling interrupts on all row GPIOs at the same time. + +In this case, the driver can be configured to not use interrupt at all, and +instead idle by selecting all columns and keep polling on the row GPIOs, which +is a single GPIO API operation if the pins are sequential. + +This configuration can be enabled by setting the ``idle-mode`` property to +``poll``: + +.. code-block:: devicetree + + kbd-matrix { + compatible = "gpio-kbd-matrix"; + ... + idle-mode = "poll"; + }; + +GPIO multiplexer +**************** + +In more extreme cases, such as if the columns are using a multiplexer and it's +impossible to select all of them at the same time, the driver can be configured +to scan continuously. + +This can be done by setting ``idle-mode`` to ``scan`` and ``poll-timeout-ms`` +to ``0``. + +.. code-block:: devicetree + + kbd-matrix { + compatible = "gpio-kbd-matrix"; + ... + poll-timeout-ms = <0>; + idle-mode = "scan"; + }; + +Row and column GPIO selection +***************************** + +If the row GPIOs are sequential and on the same gpio controller, the driver +automatically switches API to read from the whole GPIO port rather than the +individual pins. This is particularly useful if the GPIOs are not memory +mapped, for example on an I2C or SPI port expander, as this significantly +reduces the number of transactions on the corresponding bus. + +The same is true for column GPIOs, but only if the matrix is configured for +``col-drive-inactive``, so that is only usable for matrixes with isolation +diodes. + +16 bit row support +****************** + +The driver uses an 8 bit datatype to store the row state by default, which +limits the matrix row size to 8. This can be increased to 16 by enabling the +:kconfig:option:`CONFIG_INPUT_KBD_MATRIX_16_BIT_ROW` option. + +Actual key mask configuration +***************************** + +If the key matrix is not complete, a map of the keys that are actually +populated can be specified using the `actual-key-mask` property. This allows +the matrix state to be filtered to remove keys that are not present before +ghosting detection, potentially allowing key combinations that would otherwise +be blocked by it. + +For example for a 3x3 matrix missing a key: + +.. figure:: no-sw4.svg + :align: center + :width: 50% + + A 3x3 matrix missing a key. + +.. code-block:: devicetree + + kbd-matrix { + compatible = "gpio-kbd-matrix"; + ... + actual-key-mask = <0x07 0x05 0x07>; + }; + +Would allow, for example, to detect pressing ``Sw0``, ``SW1`` and ``SW3`` at +the same time without triggering anti ghosting. + +The actual key mask can be changed in runtime by enabling +:kconfig:option:`CONFIG_INPUT_KBD_ACTUAL_KEY_MASK_DYNAMIC` and the using the +:c:func:`input_kbd_matrix_actual_key_mask_set` API. + +Keyboard matrix shell commands +****************************** + +The shell command ``kbd_matrix_state_dump`` can be used to test the +functionality of any keyboard matrix driver implemented using the keyboard +matrix library. Once enabled it logs the state of the matrix every time it +changes, and once disabled it prints an or-mask of any key that has been +detected, which can be used to set the ``actual-key-mask`` property. + +The command can be enabled using the +:kconfig:option:`CONFIG_INPUT_SHELL_KBD_MATRIX_STATE`. + +Example usage: + +.. code-block:: console + + uart:~$ device list + devices: + - kbd-matrix (READY) + uart:~$ input kbd_matrix_state_dump kbd-matrix + Keyboard state logging enabled for kbd-matrix + [00:01:41.678,466] input: kbd-matrix state [01 -- -- --] (1) + [00:01:41.784,912] input: kbd-matrix state [-- -- -- --] (0) + ... + press more buttons + ... + uart:~$ input kbd_matrix_state_dump off + Keyboard state logging disabled + [00:01:47.967,651] input: kbd-matrix key-mask [07 05 07 --] (8) + +Keyboard matrix library +*********************** + +The GPIO keyboard matrix driver is based on a generic keyboard matrix library, +which implements the core functionalities such as scanning delays, debouncing, +idle mode etc. This can be reused to implement other keyboard matrix drivers, +potentially application specific. + +.. doxygengroup:: input_kbd_matrix diff --git a/doc/services/input/index.rst b/doc/services/input/index.rst index b18c57beb30..1ec83803689 100644 --- a/doc/services/input/index.rst +++ b/doc/services/input/index.rst @@ -78,6 +78,15 @@ compatibility device node, for example: }; }; +Driver Documentation +******************** + +.. toctree:: + :maxdepth: 1 + + gpio-kbd.rst + + API Reference ************* @@ -87,8 +96,3 @@ Input Event Definitions *********************** .. doxygengroup:: input_events - -Keyboard Matrix API Reference -***************************** - -.. doxygengroup:: input_kbd_matrix diff --git a/doc/services/input/no-diodes.svg b/doc/services/input/no-diodes.svg new file mode 100644 index 00000000000..ced8ad7ce78 --- /dev/null +++ b/doc/services/input/no-diodes.svg @@ -0,0 +1,2689 @@ + + + + SVG Image created as keyboard-matrix-testboard-no-diodes.svg date 2023/12/18 09:58:32 + Image generated by Eeschema-SVG + + + + + + + + + + + + + + + + + + + + + + + + + SW4 + + SW4 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + SW7 + + SW7 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + SW8 + + SW8 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + SW1 + + SW1 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + SW5 + + SW5 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + SW9 + + SW9 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + SW2 + + SW2 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + SW6 + + SW6 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + SW3 + + SW3 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + ROW0 + + ROW0 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + ROW1 + + ROW1 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + COL2 + + + COL2 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + ROW2 + + ROW2 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + COL0 + + + COL0 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + COL1 + + + COL1 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/doc/services/input/no-sw4.svg b/doc/services/input/no-sw4.svg new file mode 100644 index 00000000000..b79188fbe92 --- /dev/null +++ b/doc/services/input/no-sw4.svg @@ -0,0 +1,2496 @@ + + + + SVG Image created as keyboard-matrix-testboard-no-sw4.svg date 2023/12/18 09:58:32 + Image generated by Eeschema-SVG + + + + + + + + + + + + + + + + + + + + + + + + + SW7 + + SW7 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + SW3 + + SW3 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + SW8 + + SW8 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + SW1 + + SW1 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + SW6 + + SW6 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + SW2 + + SW2 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + SW4 + + SW4 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + SW9 + + SW9 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + COL2 + + + COL2 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + COL0 + + + COL0 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + COL1 + + + COL1 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + ROW0 + + ROW0 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + ROW1 + + ROW1 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + ROW2 + + ROW2 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + From fff24fee1460bbe5ffb71a5497b24c40a3d43310 Mon Sep 17 00:00:00 2001 From: Francois Ramu Date: Wed, 3 Jan 2024 12:58:58 +0100 Subject: [PATCH 1810/3723] drivers: usb: stm32U5 usb device controller Like the stm32H5, stm32u5 usb device has an independent power supply, but control bit is PWR_SVMCR_USV. The control bit for the stm32H5 is PWR_USBSCR_USB33SV (no change) Signed-off-by: Francois Ramu --- drivers/usb/device/usb_dc_stm32.c | 5 +++-- drivers/usb/udc/udc_stm32.c | 4 ++-- 2 files changed, 5 insertions(+), 4 deletions(-) diff --git a/drivers/usb/device/usb_dc_stm32.c b/drivers/usb/device/usb_dc_stm32.c index d1434d3ab4b..326c6e284a2 100644 --- a/drivers/usb/device/usb_dc_stm32.c +++ b/drivers/usb/device/usb_dc_stm32.c @@ -217,13 +217,14 @@ static int usb_dc_stm32_clock_enable(void) return -ENODEV; } -#ifdef PWR_USBSCR_USB33SV +#if defined(PWR_USBSCR_USB33SV) || defined(PWR_SVMCR_USV) + /* * VDDUSB independent USB supply (PWR clock is on) * with LL_PWR_EnableVDDUSB function (higher case) */ LL_PWR_EnableVDDUSB(); -#endif /* PWR_USBSCR_USB33SV */ +#endif /* PWR_USBSCR_USB33SV or PWR_SVMCR_USV */ if (DT_INST_NUM_CLOCKS(0) > 1) { if (clock_control_configure(clk, (clock_control_subsys_t)&pclken[1], diff --git a/drivers/usb/udc/udc_stm32.c b/drivers/usb/udc/udc_stm32.c index bfa3ee8e0f7..e11228619b8 100644 --- a/drivers/usb/udc/udc_stm32.c +++ b/drivers/usb/udc/udc_stm32.c @@ -914,13 +914,13 @@ static int priv_clock_enable(void) return -ENODEV; } -#if defined(PWR_USBSCR_USB33SV) +#if defined(PWR_USBSCR_USB33SV) || defined(PWR_SVMCR_USV) /* * VDDUSB independent USB supply (PWR clock is on) * with LL_PWR_EnableVDDUSB function (higher case) */ LL_PWR_EnableVDDUSB(); -#endif /* PWR_USBSCR_USB33SV */ +#endif /* PWR_USBSCR_USB33SV or PWR_SVMCR_USV */ #if defined(CONFIG_SOC_SERIES_STM32H7X) LL_PWR_EnableUSBVoltageDetector(); From 7441ff0e7e4f2c8867f0f7b91818eddfe563aab7 Mon Sep 17 00:00:00 2001 From: Jakub Zymelka Date: Thu, 4 Jan 2024 15:14:17 +0100 Subject: [PATCH 1811/3723] boards: arm: nrf5340_audio_dk_cpunet_reset: switch to HAL Change the GPIOTE driver to HAL to prevent instantiation issues with a multi-instance GPIOTE driver. Signed-off-by: Jakub Zymelka --- .../nrf5340_audio_dk_cpunet_reset.c | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/boards/arm/nrf5340_audio_dk_nrf5340/nrf5340_audio_dk_cpunet_reset.c b/boards/arm/nrf5340_audio_dk_nrf5340/nrf5340_audio_dk_cpunet_reset.c index 4368ca303fc..f9082e6ca40 100644 --- a/boards/arm/nrf5340_audio_dk_nrf5340/nrf5340_audio_dk_cpunet_reset.c +++ b/boards/arm/nrf5340_audio_dk_nrf5340/nrf5340_audio_dk_cpunet_reset.c @@ -10,8 +10,7 @@ #include #include - -#include +#include LOG_MODULE_REGISTER(nrf5340_audio_dk_nrf5340_cpuapp, CONFIG_LOG_DEFAULT_LEVEL); @@ -25,11 +24,11 @@ static int core_config(void) { nrf_gpiote_latency_t latency; - latency = nrfx_gpiote_latency_get(); + latency = nrf_gpiote_latency_get(NRF_GPIOTE); if (latency != NRF_GPIOTE_LATENCY_LOWPOWER) { LOG_DBG("Setting gpiote latency to low power"); - nrfx_gpiote_latency_set(NRF_GPIOTE_LATENCY_LOWPOWER); + nrf_gpiote_latency_set(NRF_GPIOTE, NRF_GPIOTE_LATENCY_LOWPOWER); } return 0; From dfbcc8911a94f01de22a90282de5a00b8a30ec12 Mon Sep 17 00:00:00 2001 From: Jakub Zymelka Date: Thu, 4 Jan 2024 16:06:15 +0100 Subject: [PATCH 1812/3723] dts: arm: add new gpiote instances definition Added GPIOTE0, GPIOTE1 instances for legacy devices, GPIOTE20, GPIOTE30 for Moonlight and GPIOTE130, GPIOTE131 instances for Haltium. Signed-off-by: Jakub Zymelka --- dts/arm/nordic/nrf51822.dtsi | 4 +- dts/arm/nordic/nrf52805.dtsi | 4 +- dts/arm/nordic/nrf52810.dtsi | 4 +- dts/arm/nordic/nrf52811.dtsi | 4 +- dts/arm/nordic/nrf52820.dtsi | 4 +- dts/arm/nordic/nrf52832.dtsi | 4 +- dts/arm/nordic/nrf52833.dtsi | 5 +- dts/arm/nordic/nrf52840.dtsi | 5 +- dts/arm/nordic/nrf5340_cpuapp.dtsi | 17 ++++--- .../nordic/nrf5340_cpuapp_peripherals.dtsi | 2 + .../nordic/nrf5340_cpuapp_peripherals_ns.dtsi | 20 -------- dts/arm/nordic/nrf5340_cpuappns.dtsi | 22 +++++---- dts/arm/nordic/nrf5340_cpunet.dtsi | 5 +- dts/arm/nordic/nrf91.dtsi | 17 ++++++- dts/arm/nordic/nrf91_peripherals.dtsi | 1 + dts/arm/nordic/nrf91ns.dtsi | 9 +++- dts/bindings/gpio/nordic,nrf-gpio.yaml | 5 ++ dts/bindings/gpio/nordic,nrf-gpiote.yaml | 12 +++++ modules/hal_nordic/nrfx/Kconfig | 33 ++++++++++++- modules/hal_nordic/nrfx/nrfx_config.h | 21 ++++++--- .../nrfx/nrfx_config_nrf5340_application.h | 11 ++--- modules/hal_nordic/nrfx/nrfx_config_nrf91.h | 10 ++-- soc/arm/nordic_nrf/Kconfig.peripherals | 19 +++++++- soc/arm/nordic_nrf/common/soc_nrf_common.h | 46 +++++++++++++++++++ soc/arm/nordic_nrf/validate_base_addresses.c | 10 ++++ 25 files changed, 221 insertions(+), 73 deletions(-) delete mode 100644 dts/arm/nordic/nrf5340_cpuapp_peripherals_ns.dtsi diff --git a/dts/arm/nordic/nrf51822.dtsi b/dts/arm/nordic/nrf51822.dtsi index 222ccd4854c..020711a7e7f 100644 --- a/dts/arm/nordic/nrf51822.dtsi +++ b/dts/arm/nordic/nrf51822.dtsi @@ -131,11 +131,12 @@ status = "disabled"; }; - gpiote: gpiote@40006000 { + gpiote: gpiote0: gpiote@40006000 { compatible = "nordic,nrf-gpiote"; reg = <0x40006000 0x1000>; interrupts = <6 NRF_DEFAULT_IRQ_PRIORITY>; status = "disabled"; + instance = <0>; }; adc: adc@40007000 { @@ -316,6 +317,7 @@ #gpio-cells = <2>; status = "disabled"; port = <0>; + gpiote-instance = <&gpiote>; }; }; }; diff --git a/dts/arm/nordic/nrf52805.dtsi b/dts/arm/nordic/nrf52805.dtsi index dd7845588e7..a54e8eca9c6 100644 --- a/dts/arm/nordic/nrf52805.dtsi +++ b/dts/arm/nordic/nrf52805.dtsi @@ -132,11 +132,12 @@ status = "disabled"; }; - gpiote: gpiote@40006000 { + gpiote: gpiote0: gpiote@40006000 { compatible = "nordic,nrf-gpiote"; reg = <0x40006000 0x1000>; interrupts = <6 5>; status = "disabled"; + instance = <0>; }; adc: adc@40007000 { @@ -311,6 +312,7 @@ #gpio-cells = <2>; status = "disabled"; port = <0>; + gpiote-instance = <&gpiote>; }; }; }; diff --git a/dts/arm/nordic/nrf52810.dtsi b/dts/arm/nordic/nrf52810.dtsi index 82f5afb99f6..ce5a2bce779 100644 --- a/dts/arm/nordic/nrf52810.dtsi +++ b/dts/arm/nordic/nrf52810.dtsi @@ -136,11 +136,12 @@ status = "disabled"; }; - gpiote: gpiote@40006000 { + gpiote: gpiote0: gpiote@40006000 { compatible = "nordic,nrf-gpiote"; reg = <0x40006000 0x1000>; interrupts = <6 5>; status = "disabled"; + instance = <0>; }; adc: adc@40007000 { @@ -337,6 +338,7 @@ #gpio-cells = <2>; status = "disabled"; port = <0>; + gpiote-instance = <&gpiote>; }; }; }; diff --git a/dts/arm/nordic/nrf52811.dtsi b/dts/arm/nordic/nrf52811.dtsi index 9e03d5edb32..9c9a3fa6b77 100644 --- a/dts/arm/nordic/nrf52811.dtsi +++ b/dts/arm/nordic/nrf52811.dtsi @@ -167,11 +167,12 @@ status = "disabled"; }; - gpiote: gpiote@40006000 { + gpiote: gpiote0: gpiote@40006000 { compatible = "nordic,nrf-gpiote"; reg = <0x40006000 0x1000>; interrupts = <6 5>; status = "disabled"; + instance = <0>; }; adc: adc@40007000 { @@ -372,6 +373,7 @@ #gpio-cells = <2>; status = "disabled"; port = <0>; + gpiote-instance = <&gpiote>; }; }; }; diff --git a/dts/arm/nordic/nrf52820.dtsi b/dts/arm/nordic/nrf52820.dtsi index 71ff85afbeb..c210a7c23aa 100644 --- a/dts/arm/nordic/nrf52820.dtsi +++ b/dts/arm/nordic/nrf52820.dtsi @@ -180,11 +180,12 @@ status = "disabled"; }; - gpiote: gpiote@40006000 { + gpiote: gpiote0: gpiote@40006000 { compatible = "nordic,nrf-gpiote"; reg = <0x40006000 0x1000>; interrupts = <6 5>; status = "disabled"; + instance = <0>; }; timer0: timer@40008000 { @@ -389,6 +390,7 @@ #gpio-cells = <2>; status = "disabled"; port = <0>; + gpiote-instance = <&gpiote>; }; }; }; diff --git a/dts/arm/nordic/nrf52832.dtsi b/dts/arm/nordic/nrf52832.dtsi index 69de3aa591a..2e1fd68946b 100644 --- a/dts/arm/nordic/nrf52832.dtsi +++ b/dts/arm/nordic/nrf52832.dtsi @@ -179,11 +179,12 @@ status = "okay"; }; - gpiote: gpiote@40006000 { + gpiote: gpiote0: gpiote@40006000 { compatible = "nordic,nrf-gpiote"; reg = <0x40006000 0x1000>; interrupts = <6 5>; status = "disabled"; + instance = <0>; }; adc: adc@40007000 { @@ -465,6 +466,7 @@ #gpio-cells = <2>; status = "disabled"; port = <0>; + gpiote-instance = <&gpiote>; }; }; }; diff --git a/dts/arm/nordic/nrf52833.dtsi b/dts/arm/nordic/nrf52833.dtsi index 8003649385c..d55f0f6df9e 100644 --- a/dts/arm/nordic/nrf52833.dtsi +++ b/dts/arm/nordic/nrf52833.dtsi @@ -186,11 +186,12 @@ status = "okay"; }; - gpiote: gpiote@40006000 { + gpiote: gpiote0: gpiote@40006000 { compatible = "nordic,nrf-gpiote"; reg = <0x40006000 0x1000>; interrupts = <6 5>; status = "disabled"; + instance = <0>; }; adc: adc@40007000 { @@ -521,6 +522,7 @@ #gpio-cells = <2>; status = "disabled"; port = <0>; + gpiote-instance = <&gpiote>; }; gpio1: gpio@50000300 { @@ -532,6 +534,7 @@ ngpios = <10>; status = "disabled"; port = <1>; + gpiote-instance = <&gpiote>; }; }; }; diff --git a/dts/arm/nordic/nrf52840.dtsi b/dts/arm/nordic/nrf52840.dtsi index 24710e8e0ff..e833835198b 100644 --- a/dts/arm/nordic/nrf52840.dtsi +++ b/dts/arm/nordic/nrf52840.dtsi @@ -181,11 +181,12 @@ status = "okay"; }; - gpiote: gpiote@40006000 { + gpiote: gpiote0: gpiote@40006000 { compatible = "nordic,nrf-gpiote"; reg = <0x40006000 0x1000>; interrupts = <6 5>; status = "disabled"; + instance = <0>; }; adc: adc@40007000 { @@ -525,6 +526,7 @@ #gpio-cells = <2>; status = "disabled"; port = <0>; + gpiote-instance = <&gpiote>; }; gpio1: gpio@50000300 { @@ -536,6 +538,7 @@ ngpios = <16>; status = "disabled"; port = <1>; + gpiote-instance = <&gpiote>; }; cryptocell: crypto@5002a000 { diff --git a/dts/arm/nordic/nrf5340_cpuapp.dtsi b/dts/arm/nordic/nrf5340_cpuapp.dtsi index 77762990e13..bc6b5316519 100644 --- a/dts/arm/nordic/nrf5340_cpuapp.dtsi +++ b/dts/arm/nordic/nrf5340_cpuapp.dtsi @@ -84,6 +84,16 @@ reg = <0x5000d000 0x1000>; interrupts = <13 5>; status = "disabled"; + instance = <0>; + }; + + /* Additional Non-Secure GPIOTE instance */ + gpiote1: gpiote@4002f000 { + compatible = "nordic,nrf-gpiote"; + reg = <0x4002f000 0x1000>; + interrupts = <47 5>; + status = "disabled"; + instance = <1>; }; cryptocell: crypto@50844000 { @@ -104,10 +114,3 @@ &nvic { arm,num-irq-priority-bits = <3>; }; - -/* - * Include the non-secure peripherals file here since - * it expects to be at the root level. This provides - * a node for GPIOTE1. - */ -#include "nrf5340_cpuapp_peripherals_ns.dtsi" diff --git a/dts/arm/nordic/nrf5340_cpuapp_peripherals.dtsi b/dts/arm/nordic/nrf5340_cpuapp_peripherals.dtsi index 5e2e91f20b7..94e764ec52c 100644 --- a/dts/arm/nordic/nrf5340_cpuapp_peripherals.dtsi +++ b/dts/arm/nordic/nrf5340_cpuapp_peripherals.dtsi @@ -527,6 +527,7 @@ gpio0: gpio@842500 { #gpio-cells = <2>; status = "disabled"; port = <0>; + gpiote-instance = <&gpiote>; }; gpio1: gpio@842800 { @@ -537,6 +538,7 @@ gpio1: gpio@842800 { ngpios = <16>; status = "disabled"; port = <1>; + gpiote-instance = <&gpiote>; }; ieee802154: ieee802154 { diff --git a/dts/arm/nordic/nrf5340_cpuapp_peripherals_ns.dtsi b/dts/arm/nordic/nrf5340_cpuapp_peripherals_ns.dtsi deleted file mode 100644 index 5cfe561e613..00000000000 --- a/dts/arm/nordic/nrf5340_cpuapp_peripherals_ns.dtsi +++ /dev/null @@ -1,20 +0,0 @@ -/* - * Copyright (c) 2019 Nordic Semiconductor ASA - * - * SPDX-License-Identifier: Apache-2.0 - */ - -/* - * GPIOTE1 is always accessible as a non-secure peripheral. - */ - -/ { - soc { - gpiote1: gpiote@4002f000 { - compatible = "nordic,nrf-gpiote"; - reg = <0x4002f000 0x1000>; - interrupts = <47 5>; - status = "disabled"; - }; - }; -}; diff --git a/dts/arm/nordic/nrf5340_cpuappns.dtsi b/dts/arm/nordic/nrf5340_cpuappns.dtsi index b5278745e5d..aa97c337067 100644 --- a/dts/arm/nordic/nrf5340_cpuappns.dtsi +++ b/dts/arm/nordic/nrf5340_cpuappns.dtsi @@ -48,6 +48,19 @@ */ #include "nrf5340_cpuapp_peripherals.dtsi" }; + + /* + * GPIOTE1 is always accessible as a non-secure peripheral, + * so we give it the 'gpiote' label for use when building + * code for this target. + */ + gpiote: gpiote1: gpiote@4002f000 { + compatible = "nordic,nrf-gpiote"; + reg = <0x4002f000 0x1000>; + interrupts = <47 5>; + status = "disabled"; + instance = <1>; + }; }; /* Default IPC description */ @@ -64,12 +77,3 @@ &nvic { arm,num-irq-priority-bits = <3>; }; - -/* - * Include the non-secure peripherals file here since - * it expects to be at the root level, adding a 'gpiote' label - * for the GPIOTE1 peripheral defined in that file which is - * always accessible as a non-secure peripheral. - */ -#include "nrf5340_cpuapp_peripherals_ns.dtsi" -gpiote: &gpiote1 {}; diff --git a/dts/arm/nordic/nrf5340_cpunet.dtsi b/dts/arm/nordic/nrf5340_cpunet.dtsi index 63c7e920f81..6c1e66e73aa 100644 --- a/dts/arm/nordic/nrf5340_cpunet.dtsi +++ b/dts/arm/nordic/nrf5340_cpunet.dtsi @@ -108,11 +108,12 @@ status = "okay"; }; - gpiote: gpiote@4100a000 { + gpiote: gpiote0: gpiote@4100a000 { compatible = "nordic,nrf-gpiote"; reg = <0x4100a000 0x1000>; interrupts = <10 5>; status = "disabled"; + instance = <0>; }; wdt: wdt0: watchdog@4100b000 { @@ -317,6 +318,7 @@ #gpio-cells = <2>; status = "disabled"; port = <0>; + gpiote-instance = <&gpiote>; }; gpio1: gpio@418c0800 { @@ -327,6 +329,7 @@ ngpios = <16>; status = "disabled"; port = <1>; + gpiote-instance = <&gpiote>; }; }; diff --git a/dts/arm/nordic/nrf91.dtsi b/dts/arm/nordic/nrf91.dtsi index d166059c01d..81be475d775 100644 --- a/dts/arm/nordic/nrf91.dtsi +++ b/dts/arm/nordic/nrf91.dtsi @@ -59,11 +59,26 @@ status = "okay"; }; - gpiote: gpiote@5000d000 { + /* + * GPIOTE0 is always accessible as a secure peripheral, + * so we give it the 'gpiote' label for use when building + * code for this target. + */ + gpiote: gpiote0: gpiote@5000d000 { compatible = "nordic,nrf-gpiote"; reg = <0x5000d000 0x1000>; interrupts = <13 5>; status = "disabled"; + instance = <0>; + }; + + /* Additional Non-Secure GPIOTE instance */ + gpiote1: gpiote@40031000 { + compatible = "nordic,nrf-gpiote"; + reg = <0x40031000 0x1000>; + interrupts = <49 5>; + status = "disabled"; + instance = <1>; }; spu: spu@50003000 { diff --git a/dts/arm/nordic/nrf91_peripherals.dtsi b/dts/arm/nordic/nrf91_peripherals.dtsi index d6078e79120..b6ed30990be 100644 --- a/dts/arm/nordic/nrf91_peripherals.dtsi +++ b/dts/arm/nordic/nrf91_peripherals.dtsi @@ -313,6 +313,7 @@ gpio0: gpio@842500 { #gpio-cells = <2>; status = "disabled"; port = <0>; + gpiote-instance = <&gpiote>; }; rtc0: rtc@14000 { diff --git a/dts/arm/nordic/nrf91ns.dtsi b/dts/arm/nordic/nrf91ns.dtsi index cff60f5f3c6..22510b0cfac 100644 --- a/dts/arm/nordic/nrf91ns.dtsi +++ b/dts/arm/nordic/nrf91ns.dtsi @@ -45,12 +45,17 @@ #include "nrf91_peripherals.dtsi" }; - /* Additional Non-Secure peripherals */ - gpiote: gpiote@40031000 { + /* + * GPIOTE1 is always accessible as a non-secure peripheral, + * so we give it the 'gpiote' label for use when building + * code for this target. + */ + gpiote: gpiote1: gpiote@40031000 { compatible = "nordic,nrf-gpiote"; reg = <0x40031000 0x1000>; interrupts = <49 5>; status = "disabled"; + instance = <1>; }; }; diff --git a/dts/bindings/gpio/nordic,nrf-gpio.yaml b/dts/bindings/gpio/nordic,nrf-gpio.yaml index 550acd1a865..097a99d8fa9 100644 --- a/dts/bindings/gpio/nordic,nrf-gpio.yaml +++ b/dts/bindings/gpio/nordic,nrf-gpio.yaml @@ -11,6 +11,11 @@ properties: reg: required: true + gpiote-instance: + type: phandle + description: | + GPIOTE instance that can be used with this GPIO port. + "#gpio-cells": const: 2 diff --git a/dts/bindings/gpio/nordic,nrf-gpiote.yaml b/dts/bindings/gpio/nordic,nrf-gpiote.yaml index 49ddba3595b..cefc3385afe 100644 --- a/dts/bindings/gpio/nordic,nrf-gpiote.yaml +++ b/dts/bindings/gpio/nordic,nrf-gpiote.yaml @@ -13,3 +13,15 @@ properties: interrupts: required: true + + instance: + type: int + required: true + description: | + The GPIOTE instance number. GPIOTE instance GPIOTE0 has: + + instance = <0>; + + And GPIOTE1 has: + + instance = <1>; diff --git a/modules/hal_nordic/nrfx/Kconfig b/modules/hal_nordic/nrfx/Kconfig index c4bfcc2d60e..a92aa93d9a2 100644 --- a/modules/hal_nordic/nrfx/Kconfig +++ b/modules/hal_nordic/nrfx/Kconfig @@ -63,8 +63,37 @@ config NRFX_EGU5 select NRFX_EGU config NRFX_GPIOTE - bool "GPIOTE driver" - depends on $(dt_has_compat,$(DT_COMPAT_NORDIC_NRF_GPIOTE)) + bool + +config NRFX_GPIOTE0 + bool "GPIOTE0 driver instance" + depends on $(dt_nodelabel_has_compat,gpiote0,$(DT_COMPAT_NORDIC_NRF_GPIOTE)) + select NRFX_GPIOTE + +config NRFX_GPIOTE1 + bool "GPIOTE1 driver instance" + depends on $(dt_nodelabel_has_compat,gpiote1,$(DT_COMPAT_NORDIC_NRF_GPIOTE)) + select NRFX_GPIOTE + +config NRFX_GPIOTE20 + bool "NRFX_GPIOTE20 driver instance" + depends on $(dt_nodelabel_has_compat,gpiote20,$(DT_COMPAT_NORDIC_NRF_GPIOTE)) + select NRFX_GPIOTE + +config NRFX_GPIOTE30 + bool "NRFX_GPIOTE30 driver instance" + depends on $(dt_nodelabel_has_compat,gpiote30,$(DT_COMPAT_NORDIC_NRF_GPIOTE)) + select NRFX_GPIOTE + +config NRFX_GPIOTE130 + bool "NRFX_GPIOTE130 driver instance" + depends on $(dt_nodelabel_has_compat,gpiote130,$(DT_COMPAT_NORDIC_NRF_GPIOTE)) + select NRFX_GPIOTE + +config NRFX_GPIOTE131 + bool "NRFX_GPIOTE131 driver instance" + depends on $(dt_nodelabel_has_compat,gpiote131,$(DT_COMPAT_NORDIC_NRF_GPIOTE)) + select NRFX_GPIOTE config NRFX_GPIOTE_NUM_OF_EVT_HANDLERS int "Number of event handlers" diff --git a/modules/hal_nordic/nrfx/nrfx_config.h b/modules/hal_nordic/nrfx/nrfx_config.h index a285d1c86db..72617325684 100644 --- a/modules/hal_nordic/nrfx/nrfx_config.h +++ b/modules/hal_nordic/nrfx/nrfx_config.h @@ -117,15 +117,24 @@ #ifdef CONFIG_NRFX_GPIOTE #define NRFX_GPIOTE_ENABLED 1 -#if (defined(CONFIG_SOC_SERIES_NRF91X) || defined(CONFIG_SOC_SERIES_NRF53X)) \ - && defined(NRF_TRUSTZONE_NONSECURE) -#define NRFX_GPIOTE1_ENABLED 1 -#else +#endif +#ifdef CONFIG_NRFX_GPIOTE0 #define NRFX_GPIOTE0_ENABLED 1 #endif +#ifdef CONFIG_NRFX_GPIOTE1 +#define NRFX_GPIOTE1_ENABLED 1 +#endif +#ifdef CONFIG_NRFX_GPIOTE20 +#define NRFX_GPIOTE20_ENABLED 1 +#endif +#ifdef CONFIG_NRFX_GPIOTE30 +#define NRFX_GPIOTE30_ENABLED 1 +#endif +#ifdef CONFIG_NRFX_GPIOTE130 +#define NRFX_GPIOTE130_ENABLED 1 #endif -#ifdef CONFIG_NRFX_GPIOTE_LOG -#define NRFX_GPIOTE_CONFIG_LOG_ENABLED 1 +#ifdef CONFIG_NRFX_GPIOTE131 +#define NRFX_GPIOTE131_ENABLED 1 #endif #ifdef CONFIG_NRFX_GPIOTE_NUM_OF_EVT_HANDLERS diff --git a/modules/hal_nordic/nrfx/nrfx_config_nrf5340_application.h b/modules/hal_nordic/nrfx/nrfx_config_nrf5340_application.h index 4a42f92ca98..18bcc40b2ac 100644 --- a/modules/hal_nordic/nrfx/nrfx_config_nrf5340_application.h +++ b/modules/hal_nordic/nrfx/nrfx_config_nrf5340_application.h @@ -83,6 +83,7 @@ * between secure and non-secure mapping. */ #if defined(NRF_TRUSTZONE_NONSECURE) +#define NRF_GPIOTE NRF_GPIOTE1 #define NRF_GPIOTE1 NRF_GPIOTE1_NS #else #define NRF_CACHE NRF_CACHE_S @@ -91,20 +92,14 @@ #define NRF_CRYPTOCELL NRF_CRYPTOCELL_S #define NRF_CTI NRF_CTI_S #define NRF_FICR NRF_FICR_S +#define NRF_GPIOTE NRF_GPIOTE0 #define NRF_GPIOTE0 NRF_GPIOTE0_S +#define NRF_GPIOTE1 NRF_GPIOTE1_NS #define NRF_SPU NRF_SPU_S #define NRF_TAD NRF_TAD_S #define NRF_UICR NRF_UICR_S #endif -/* Fixups for the GPIOTE driver. */ -#if defined(NRF_TRUSTZONE_NONSECURE) -#define NRF_GPIOTE NRF_GPIOTE1 -#else -#define NRF_GPIOTE NRF_GPIOTE0 -#endif - - /** * @brief NRFX_DEFAULT_IRQ_PRIORITY * diff --git a/modules/hal_nordic/nrfx/nrfx_config_nrf91.h b/modules/hal_nordic/nrfx/nrfx_config_nrf91.h index 873be583a35..c6029a18628 100644 --- a/modules/hal_nordic/nrfx/nrfx_config_nrf91.h +++ b/modules/hal_nordic/nrfx/nrfx_config_nrf91.h @@ -67,25 +67,21 @@ * between secure and non-secure mapping. */ #if defined(NRF_TRUSTZONE_NONSECURE) +#define NRF_GPIOTE NRF_GPIOTE1 #define NRF_GPIOTE1 NRF_GPIOTE1_NS #else #define NRF_CC_HOST_RGF NRF_CC_HOST_RGF_S #define NRF_CRYPTOCELL NRF_CRYPTOCELL_S #define NRF_CTRL_AP_PERI NRF_CTRL_AP_PERI_S #define NRF_FICR NRF_FICR_S +#define NRF_GPIOTE NRF_GPIOTE0 #define NRF_GPIOTE0 NRF_GPIOTE0_S +#define NRF_GPIOTE1 NRF_GPIOTE1_NS #define NRF_SPU NRF_SPU_S #define NRF_TAD NRF_TAD_S #define NRF_UICR NRF_UICR_S #endif -/* Fixups for the GPIOTE driver. */ -#if defined(NRF_TRUSTZONE_NONSECURE) -#define NRF_GPIOTE NRF_GPIOTE1 -#else -#define NRF_GPIOTE NRF_GPIOTE0 -#endif - /** * @brief NRFX_DEFAULT_IRQ_PRIORITY * diff --git a/soc/arm/nordic_nrf/Kconfig.peripherals b/soc/arm/nordic_nrf/Kconfig.peripherals index 55f44ccbc21..9e637f2661e 100644 --- a/soc/arm/nordic_nrf/Kconfig.peripherals +++ b/soc/arm/nordic_nrf/Kconfig.peripherals @@ -69,8 +69,23 @@ config HAS_HW_NRF_GPIO0 config HAS_HW_NRF_GPIO1 def_bool $(dt_nodelabel_enabled_with_compat,gpio1,$(DT_COMPAT_NORDIC_NRF_GPIO)) -config HAS_HW_NRF_GPIOTE - def_bool $(dt_compat_enabled,$(DT_COMPAT_NORDIC_NRF_GPIOTE)) +config HAS_HW_NRF_GPIOTE0 + def_bool $(dt_nodelabel_enabled_with_compat,gpiote0,$(DT_COMPAT_NORDIC_NRF_GPIOTE)) + +config HAS_HW_NRF_GPIOTE1 + def_bool $(dt_nodelabel_enabled_with_compat,gpiote1,$(DT_COMPAT_NORDIC_NRF_GPIOTE)) + +config HAS_HW_NRF_GPIOTE20 + def_bool $(dt_nodelabel_enabled_with_compat,gpiote20,$(DT_COMPAT_NORDIC_NRF_GPIOTE)) + +config HAS_HW_NRF_GPIOTE30 + def_bool $(dt_nodelabel_enabled_with_compat,gpiote30,$(DT_COMPAT_NORDIC_NRF_GPIOTE)) + +config HAS_HW_NRF_GPIOTE130 + def_bool $(dt_nodelabel_enabled_with_compat,gpiote130,$(DT_COMPAT_NORDIC_NRF_GPIOTE)) + +config HAS_HW_NRF_GPIOTE131 + def_bool $(dt_nodelabel_enabled_with_compat,gpiote131,$(DT_COMPAT_NORDIC_NRF_GPIOTE)) config HAS_HW_NRF_I2S0 def_bool $(dt_nodelabel_enabled_with_compat,i2s0,$(DT_COMPAT_NORDIC_NRF_I2S)) diff --git a/soc/arm/nordic_nrf/common/soc_nrf_common.h b/soc/arm/nordic_nrf/common/soc_nrf_common.h index 4c00d7c0237..1e5e603967b 100644 --- a/soc/arm/nordic_nrf/common/soc_nrf_common.h +++ b/soc/arm/nordic_nrf/common/soc_nrf_common.h @@ -149,6 +149,52 @@ (NRF_DT_GPIOS_TO_PSEL(node_id, prop)), \ (default_value)) +/** + * @brief Convert a devicetree GPIO phandle+specifier to GPIOTE instance number. + * + * Some of nRF SoCs may have more instances of GPIOTE. + * To handle this, we use the "gpiote-instance" property of the GPIO node. + * + * This macro converts a devicetree GPIO phandle array value + * "<&gpioX pin ...>" to a GPIOTE instance number. + * + * Examples: + * + * &gpiote0 { + * instance = <0>; + * }; + * + * &gpiote20 { + * instance = <20>; + * }; + * + * &gpio0 { + * gpiote-instance = <&gpiote0>; + * } + * + * &gpio1 { + * gpiote-instance = <&gpiote20>; + * } + * + * foo: my-node { + * tx-gpios = <&gpio0 4 ...>; + * rx-gpios = <&gpio0 5 ...>, <&gpio1 5 ...>; + * }; + * + * NRF_DT_GPIOTE_INST_BY_IDX(DT_NODELABEL(foo), tx_gpios, 0) // = 0 + * NRF_DT_GPIOTE_INST_BY_IDX(DT_NODELABEL(foo), rx_gpios, 1) // = 20 + */ +#define NRF_DT_GPIOTE_INST_BY_IDX(node_id, prop, idx) \ + DT_PROP(DT_PHANDLE(DT_GPIO_CTLR_BY_IDX(node_id, prop, idx), \ + gpiote_instance), \ + instance) + +/** + * @brief Equivalent to NRF_DT_GPIOTE_INST_BY_IDX(node_id, prop, 0) + */ +#define NRF_DT_GPIOTE_INST(node_id, prop) \ + NRF_DT_GPIOTE_INST_BY_IDX(node_id, prop, 0) + /** * Error out the build if 'prop' is set on node 'node_id' and * DT_GPIO_CTLR(node_id, prop) is not an SoC GPIO controller, diff --git a/soc/arm/nordic_nrf/validate_base_addresses.c b/soc/arm/nordic_nrf/validate_base_addresses.c index 58aaa5a7513..ee440c3252c 100644 --- a/soc/arm/nordic_nrf/validate_base_addresses.c +++ b/soc/arm/nordic_nrf/validate_base_addresses.c @@ -16,6 +16,10 @@ #define NRF_CTRLAP NRF_CTRL_AP_PERI #endif +#if !defined(NRF_GPIOTE0) && defined(NRF_GPIOTE) +#define NRF_GPIOTE0 NRF_GPIOTE +#endif + #if !defined(NRF_I2S0) && defined(NRF_I2S) #define NRF_I2S0 NRF_I2S #endif @@ -141,6 +145,12 @@ CHECK_DT_REG(flash_controller, NRF_NVMC); CHECK_DT_REG(gpio0, NRF_P0); CHECK_DT_REG(gpio1, NRF_P1); CHECK_DT_REG(gpiote, NRF_GPIOTE); +CHECK_DT_REG(gpiote0, NRF_GPIOTE0); +CHECK_DT_REG(gpiote1, NRF_GPIOTE1); +CHECK_DT_REG(gpiote20, NRF_GPIOTE20); +CHECK_DT_REG(gpiote30, NRF_GPIOTE30); +CHECK_DT_REG(gpiote130, NRF_GPIOTE130); +CHECK_DT_REG(gpiote131, NRF_GPIOTE131); CHECK_I2C_REG(i2c0, 0); CHECK_I2C_REG(i2c1, 1); CHECK_DT_REG(i2c2, NRF_TWIM2); From c546c8b96be8f7bf4289ce6bb546bfdf78d5e3fb Mon Sep 17 00:00:00 2001 From: Jakub Zymelka Date: Thu, 4 Jan 2024 16:18:40 +0100 Subject: [PATCH 1813/3723] boards: arm: set gpiote status to okay as default After adding new GPIOTE instances, there is a need to enable the instance for individual boards. Signed-off-by: Jakub Zymelka --- .../arm/arduino_nano_33_ble/arduino_nano_33_ble-common.dtsi | 4 ++++ boards/arm/bl654_usb/bl654_usb.dts | 4 ++++ 2 files changed, 8 insertions(+) diff --git a/boards/arm/arduino_nano_33_ble/arduino_nano_33_ble-common.dtsi b/boards/arm/arduino_nano_33_ble/arduino_nano_33_ble-common.dtsi index 200db7f94c7..3d31ede313f 100644 --- a/boards/arm/arduino_nano_33_ble/arduino_nano_33_ble-common.dtsi +++ b/boards/arm/arduino_nano_33_ble/arduino_nano_33_ble-common.dtsi @@ -189,6 +189,10 @@ arduino_spi: &spi2 { status = "okay"; }; +&gpiote { + status = "okay"; +}; + &pwm0 { status = "okay"; pinctrl-0 = <&pwm0_default>; diff --git a/boards/arm/bl654_usb/bl654_usb.dts b/boards/arm/bl654_usb/bl654_usb.dts index 80600290dbf..fa814f4b80e 100644 --- a/boards/arm/bl654_usb/bl654_usb.dts +++ b/boards/arm/bl654_usb/bl654_usb.dts @@ -59,6 +59,10 @@ status = "okay"; }; +&gpiote { + status = "okay"; +}; + &pwm0 { status = "okay"; pinctrl-0 = <&pwm0_default>; From ade49f081df6fab0db6288bad25be4f5eff7ef3a Mon Sep 17 00:00:00 2001 From: Jakub Zymelka Date: Mon, 8 Jan 2024 09:45:46 +0100 Subject: [PATCH 1814/3723] modules: hal_nordic: nrfx: update API version to 3.2.0 Updated API version enables multi-instance GPIOTE driver. Additionally obsolete symbol that was used to specify API version in the past was removed. Affected drivers have been adjusted and appropriate changes in affected files have been made. Signed-off-by: Jakub Zymelka --- drivers/adc/adc_nrfx_saadc.c | 4 +- drivers/display/display_nrf_led_matrix.c | 22 +- drivers/gpio/Kconfig.nrfx | 7 +- drivers/gpio/gpio_nrfx.c | 229 +++++++++++-------- drivers/pwm/pwm_nrf_sw.c | 20 +- drivers/spi/spi_nrfx_common.c | 31 ++- drivers/spi/spi_nrfx_common.h | 11 +- drivers/spi/spi_nrfx_spi.c | 7 +- drivers/spi/spi_nrfx_spim.c | 20 +- drivers/watchdog/wdt_nrfx.c | 16 +- modules/hal_nordic/nrfx/nrfx_config.h | 6 - modules/hal_nordic/nrfx/nrfx_config_common.h | 2 +- samples/boards/nrf/nrfx/Kconfig | 10 + samples/boards/nrf/nrfx/prj.conf | 1 - samples/boards/nrf/nrfx/src/main.c | 51 +++-- 15 files changed, 270 insertions(+), 167 deletions(-) diff --git a/drivers/adc/adc_nrfx_saadc.c b/drivers/adc/adc_nrfx_saadc.c index 72a20f47fc9..6d1973ca0aa 100644 --- a/drivers/adc/adc_nrfx_saadc.c +++ b/drivers/adc/adc_nrfx_saadc.c @@ -170,7 +170,7 @@ static void adc_context_update_buffer_pointer(struct adc_context *ctx, if (!repeat) { nrf_saadc_buffer_pointer_set( NRF_SAADC, - nrf_saadc_buffer_pointer_get(NRF_SAADC) + + (uint16_t *)nrf_saadc_buffer_pointer_get(NRF_SAADC) + nrf_saadc_amount_get(NRF_SAADC)); } } @@ -256,7 +256,7 @@ static int check_buffer_size(const struct adc_sequence *sequence, { size_t needed_buffer_size; - needed_buffer_size = active_channels * sizeof(nrf_saadc_value_t); + needed_buffer_size = active_channels * sizeof(uint16_t); if (sequence->options) { needed_buffer_size *= (1 + sequence->options->extra_samplings); } diff --git a/drivers/display/display_nrf_led_matrix.c b/drivers/display/display_nrf_led_matrix.c index 5468347551d..d88bc760e76 100644 --- a/drivers/display/display_nrf_led_matrix.c +++ b/drivers/display/display_nrf_led_matrix.c @@ -7,6 +7,7 @@ #include #include #include +#include #include #ifdef PWM_PRESENT #include @@ -89,6 +90,8 @@ struct display_drv_config { NRF_TIMER_Type *timer; #if USE_PWM NRF_PWM_Type *pwm; +#else + nrfx_gpiote_t gpiote; #endif uint8_t rows[ROW_COUNT]; uint8_t cols[COL_COUNT]; @@ -324,7 +327,7 @@ static void prepare_pixel_pulse(const struct device *dev, /* First timer channel is used for timing the period of pulses. */ nrf_timer_cc_set(dev_config->timer, 1 + channel_idx, pulse); - NRF_GPIOTE->CONFIG[dev_data->gpiote_ch[channel_idx]] = gpiote_cfg; + dev_config->gpiote.p_reg->CONFIG[dev_data->gpiote_ch[channel_idx]] = gpiote_cfg; #endif /* USE_PWM */ } @@ -354,7 +357,7 @@ static void timer_irq_handler(void *arg) } #else for (int i = 0; i < GROUP_SIZE; ++i) { - NRF_GPIOTE->CONFIG[dev_data->gpiote_ch[i]] = 0; + dev_config->gpiote.p_reg->CONFIG[dev_data->gpiote_ch[i]] = 0; } #endif @@ -450,7 +453,7 @@ static int instance_init(const struct device *dev) return -ENOMEM; } - err = nrfx_gpiote_channel_alloc(gpiote_ch); + err = nrfx_gpiote_channel_alloc(&dev_config->gpiote, gpiote_ch); if (err != NRFX_SUCCESS) { LOG_ERR("Failed to allocate GPIOTE channel."); /* Do not bother with freeing resources allocated @@ -463,7 +466,7 @@ static int instance_init(const struct device *dev) nrf_ppi_channel_endpoint_setup(NRF_PPI, ppi_ch, nrf_timer_event_address_get(dev_config->timer, nrf_timer_compare_event_get(1 + i)), - nrf_gpiote_event_address_get(NRF_GPIOTE, + nrf_gpiote_event_address_get(dev_config->gpiote.p_reg, nrf_gpiote_out_task_get(*gpiote_ch))); nrf_ppi_channel_enable(NRF_PPI, ppi_ch); } @@ -514,6 +517,14 @@ static struct display_drv_data instance_data = { .blanking = true, }; +#if !USE_PWM +#define CHECK_GPIOTE_INST(node_id, prop, idx) \ + BUILD_ASSERT(NRF_DT_GPIOTE_INST_BY_IDX(node_id, prop, idx) == \ + NRF_DT_GPIOTE_INST_BY_IDX(node_id, prop, 0), \ + "All column GPIOs must use the same GPIOTE instance"); +DT_FOREACH_PROP_ELEM(MATRIX_NODE, col_gpios, CHECK_GPIOTE_INST) +#endif + #define GET_PIN_INFO(node_id, pha, idx) \ (DT_GPIO_PIN_BY_IDX(node_id, pha, idx) | \ (DT_PROP_BY_PHANDLE_IDX(node_id, pha, idx, port) << 5) | \ @@ -530,6 +541,9 @@ static const struct display_drv_config instance_config = { .timer = (NRF_TIMER_Type *)DT_REG_ADDR(TIMER_NODE), #if USE_PWM .pwm = (NRF_PWM_Type *)DT_REG_ADDR(PWM_NODE), +#else + .gpiote = NRFX_GPIOTE_INSTANCE( + NRF_DT_GPIOTE_INST_BY_IDX(MATRIX_NODE, col_gpios, 0)), #endif .rows = { DT_FOREACH_PROP_ELEM(MATRIX_NODE, row_gpios, GET_PIN_INFO) }, .cols = { DT_FOREACH_PROP_ELEM(MATRIX_NODE, col_gpios, GET_PIN_INFO) }, diff --git a/drivers/gpio/Kconfig.nrfx b/drivers/gpio/Kconfig.nrfx index 356c43cb5fa..760a45204fd 100644 --- a/drivers/gpio/Kconfig.nrfx +++ b/drivers/gpio/Kconfig.nrfx @@ -5,7 +5,12 @@ menuconfig GPIO_NRFX bool "nRF GPIO driver" default y depends on DT_HAS_NORDIC_NRF_GPIO_ENABLED - select NRFX_GPIOTE + select NRFX_GPIOTE0 if HAS_HW_NRF_GPIOTE0 + select NRFX_GPIOTE1 if HAS_HW_NRF_GPIOTE1 + select NRFX_GPIOTE20 if HAS_HW_NRF_GPIOTE20 + select NRFX_GPIOTE30 if HAS_HW_NRF_GPIOTE30 + select NRFX_GPIOTE130 if HAS_HW_NRF_GPIOTE130 + select NRFX_GPIOTE131 if HAS_HW_NRF_GPIOTE131 help Enable GPIO driver for nRF line of MCUs. diff --git a/drivers/gpio/gpio_nrfx.c b/drivers/gpio/gpio_nrfx.c index 0aa282dda37..d89c964cc90 100644 --- a/drivers/gpio/gpio_nrfx.c +++ b/drivers/gpio/gpio_nrfx.c @@ -3,6 +3,7 @@ * * SPDX-License-Identifier: Apache-2.0 */ + #define DT_DRV_COMPAT nordic_nrf_gpio #include @@ -25,6 +26,7 @@ struct gpio_nrfx_cfg { NRF_GPIO_Type *port; uint32_t edge_sense; uint8_t port_num; + nrfx_gpiote_t gpiote; }; static inline struct gpio_nrfx_data *get_port_data(const struct device *port) @@ -37,131 +39,139 @@ static inline const struct gpio_nrfx_cfg *get_port_cfg(const struct device *port return port->config; } -static int get_drive(gpio_flags_t flags, nrf_gpio_pin_drive_t *drive) +static bool has_gpiote(const struct gpio_nrfx_cfg *cfg) +{ + return cfg->gpiote.p_reg != NULL; +} + +static nrf_gpio_pin_pull_t get_pull(gpio_flags_t flags) +{ + if (flags & GPIO_PULL_UP) { + return NRF_GPIO_PIN_PULLUP; + } else if (flags & GPIO_PULL_DOWN) { + return NRF_GPIO_PIN_PULLDOWN; + } + + return NRF_GPIO_PIN_NOPULL; +} + +static int gpio_nrfx_pin_configure(const struct device *port, gpio_pin_t pin, + gpio_flags_t flags) { + nrfx_err_t err = NRFX_SUCCESS; + uint8_t ch; + bool free_ch = false; + const struct gpio_nrfx_cfg *cfg = get_port_cfg(port); + nrfx_gpiote_pin_t abs_pin = NRF_GPIO_PIN_MAP(cfg->port_num, pin); + nrf_gpio_pin_pull_t pull = get_pull(flags); + nrf_gpio_pin_drive_t drive; + switch (flags & (NRF_GPIO_DRIVE_MSK | GPIO_OPEN_DRAIN)) { case NRF_GPIO_DRIVE_S0S1: - *drive = NRF_GPIO_PIN_S0S1; + drive = NRF_GPIO_PIN_S0S1; break; case NRF_GPIO_DRIVE_S0H1: - *drive = NRF_GPIO_PIN_S0H1; + drive = NRF_GPIO_PIN_S0H1; break; case NRF_GPIO_DRIVE_H0S1: - *drive = NRF_GPIO_PIN_H0S1; + drive = NRF_GPIO_PIN_H0S1; break; case NRF_GPIO_DRIVE_H0H1: - *drive = NRF_GPIO_PIN_H0H1; + drive = NRF_GPIO_PIN_H0H1; break; case NRF_GPIO_DRIVE_S0 | GPIO_OPEN_DRAIN: - *drive = NRF_GPIO_PIN_S0D1; + drive = NRF_GPIO_PIN_S0D1; break; case NRF_GPIO_DRIVE_H0 | GPIO_OPEN_DRAIN: - *drive = NRF_GPIO_PIN_H0D1; + drive = NRF_GPIO_PIN_H0D1; break; case NRF_GPIO_DRIVE_S1 | GPIO_OPEN_SOURCE: - *drive = NRF_GPIO_PIN_D0S1; + drive = NRF_GPIO_PIN_D0S1; break; case NRF_GPIO_DRIVE_H1 | GPIO_OPEN_SOURCE: - *drive = NRF_GPIO_PIN_D0H1; + drive = NRF_GPIO_PIN_D0H1; break; default: return -EINVAL; } - return 0; -} - -static nrf_gpio_pin_pull_t get_pull(gpio_flags_t flags) -{ - if (flags & GPIO_PULL_UP) { - return NRF_GPIO_PIN_PULLUP; - } else if (flags & GPIO_PULL_DOWN) { - return NRF_GPIO_PIN_PULLDOWN; + if (flags & GPIO_OUTPUT_INIT_HIGH) { + nrf_gpio_port_out_set(cfg->port, BIT(pin)); + } else if (flags & GPIO_OUTPUT_INIT_LOW) { + nrf_gpio_port_out_clear(cfg->port, BIT(pin)); } - return NRF_GPIO_PIN_NOPULL; -} + if (!has_gpiote(cfg)) { + nrf_gpio_pin_dir_t dir = (flags & GPIO_OUTPUT) + ? NRF_GPIO_PIN_DIR_OUTPUT + : NRF_GPIO_PIN_DIR_INPUT; + nrf_gpio_pin_input_t input = (flags & GPIO_INPUT) + ? NRF_GPIO_PIN_INPUT_CONNECT + : NRF_GPIO_PIN_INPUT_DISCONNECT; -static int gpio_nrfx_pin_configure(const struct device *port, gpio_pin_t pin, - gpio_flags_t flags) -{ - nrfx_err_t err = NRFX_SUCCESS; - uint8_t ch; - bool free_ch = false; - const struct gpio_nrfx_cfg *cfg = get_port_cfg(port); - nrfx_gpiote_pin_t abs_pin = NRF_GPIO_PIN_MAP(cfg->port_num, pin); + nrf_gpio_reconfigure(abs_pin, &dir, &input, &pull, &drive, NULL); + return 0; + } /* Get the GPIOTE channel associated with this pin, if any. It needs * to be freed when the pin is reconfigured or disconnected. */ if (IS_ENABLED(CONFIG_GPIO_NRFX_INTERRUPT)) { - err = nrfx_gpiote_channel_get(abs_pin, &ch); + err = nrfx_gpiote_channel_get(&cfg->gpiote, abs_pin, &ch); free_ch = (err == NRFX_SUCCESS); } if ((flags & (GPIO_INPUT | GPIO_OUTPUT)) == GPIO_DISCONNECTED) { /* Ignore the error code. The pin may not have been used. */ - (void)nrfx_gpiote_pin_uninit(abs_pin); - - if (free_ch) { - err = nrfx_gpiote_channel_free(ch); - __ASSERT_NO_MSG(err == NRFX_SUCCESS); + (void)nrfx_gpiote_pin_uninit(&cfg->gpiote, abs_pin); + } else { + /* Remove previously configured trigger when pin is reconfigured. */ + if (IS_ENABLED(CONFIG_GPIO_NRFX_INTERRUPT)) { + nrfx_gpiote_trigger_config_t trigger_config = { + .trigger = NRFX_GPIOTE_TRIGGER_NONE, + }; + nrfx_gpiote_input_pin_config_t input_pin_config = { + .p_trigger_config = &trigger_config, + }; + + err = nrfx_gpiote_input_configure(&cfg->gpiote, + abs_pin, &input_pin_config); + if (err != NRFX_SUCCESS) { + return -EINVAL; + } } - return 0; - } - - if (IS_ENABLED(CONFIG_GPIO_NRFX_INTERRUPT)) { - nrfx_gpiote_trigger_config_t trigger_config = { - .trigger = NRFX_GPIOTE_TRIGGER_NONE - }; + if (flags & GPIO_OUTPUT) { + nrfx_gpiote_output_config_t output_config = { + .drive = drive, + .input_connect = (flags & GPIO_INPUT) + ? NRF_GPIO_PIN_INPUT_CONNECT + : NRF_GPIO_PIN_INPUT_DISCONNECT, + .pull = pull, + }; + + err = nrfx_gpiote_output_configure(&cfg->gpiote, + abs_pin, &output_config, NULL); + } else { + nrfx_gpiote_input_pin_config_t input_pin_config = { + .p_pull_config = &pull, + }; + + err = nrfx_gpiote_input_configure(&cfg->gpiote, + abs_pin, &input_pin_config); + } - /* Remove previously configured trigger when pin is reconfigured. */ - err = nrfx_gpiote_input_configure(abs_pin, NULL, &trigger_config, NULL); if (err != NRFX_SUCCESS) { return -EINVAL; } - - if (free_ch) { - err = nrfx_gpiote_channel_free(ch); - __ASSERT_NO_MSG(err == NRFX_SUCCESS); - } } - if (flags & GPIO_OUTPUT) { - nrf_gpio_pin_drive_t drive; - int rv = get_drive(flags, &drive); - - if (rv != 0) { - return rv; - } - - nrfx_gpiote_output_config_t output_config = { - .drive = drive, - .input_connect = (flags & GPIO_INPUT) ? - NRF_GPIO_PIN_INPUT_CONNECT : - NRF_GPIO_PIN_INPUT_DISCONNECT, - .pull = get_pull(flags) - }; - - - if (flags & GPIO_OUTPUT_INIT_HIGH) { - nrf_gpio_port_out_set(cfg->port, BIT(pin)); - } else if (flags & GPIO_OUTPUT_INIT_LOW) { - nrf_gpio_port_out_clear(cfg->port, BIT(pin)); - } - - err = nrfx_gpiote_output_configure(abs_pin, &output_config, NULL); - return (err != NRFX_SUCCESS) ? -EINVAL : 0; + if (IS_ENABLED(CONFIG_GPIO_NRFX_INTERRUPT) && free_ch) { + err = nrfx_gpiote_channel_free(&cfg->gpiote, ch); + __ASSERT_NO_MSG(err == NRFX_SUCCESS); } - nrfx_gpiote_input_config_t input_config = { - .pull = get_pull(flags) - }; - - err = nrfx_gpiote_input_configure(abs_pin, &input_config, NULL, NULL); - - return (err != NRFX_SUCCESS) ? -EINVAL : 0; + return 0; } static int gpio_nrfx_port_get_raw(const struct device *port, @@ -242,12 +252,17 @@ static int gpio_nrfx_pin_interrupt_configure(const struct device *port, enum gpio_int_mode mode, enum gpio_int_trig trig) { - uint32_t abs_pin = NRF_GPIO_PIN_MAP(get_port_cfg(port)->port_num, pin); + const struct gpio_nrfx_cfg *cfg = get_port_cfg(port); + uint32_t abs_pin = NRF_GPIO_PIN_MAP(cfg->port_num, pin); nrfx_err_t err; uint8_t ch; + if (!has_gpiote(cfg)) { + return -ENOTSUP; + } + if (mode == GPIO_INT_MODE_DISABLED) { - nrfx_gpiote_trigger_disable(abs_pin); + nrfx_gpiote_trigger_disable(&cfg->gpiote, abs_pin); return 0; } @@ -255,16 +270,19 @@ static int gpio_nrfx_pin_interrupt_configure(const struct device *port, nrfx_gpiote_trigger_config_t trigger_config = { .trigger = get_trigger(mode, trig), }; + nrfx_gpiote_input_pin_config_t input_pin_config = { + .p_trigger_config = &trigger_config, + }; /* If edge mode is to be used and pin is not configured to use sense for * edge use IN event. */ - if (!(BIT(pin) & get_port_cfg(port)->edge_sense) && + if (!(BIT(pin) & cfg->edge_sense) && (mode == GPIO_INT_MODE_EDGE) && (nrf_gpio_pin_dir_get(abs_pin) == NRF_GPIO_PIN_DIR_INPUT)) { - err = nrfx_gpiote_channel_get(abs_pin, &ch); + err = nrfx_gpiote_channel_get(&cfg->gpiote, abs_pin, &ch); if (err == NRFX_ERROR_INVALID_PARAM) { - err = nrfx_gpiote_channel_alloc(&ch); + err = nrfx_gpiote_channel_alloc(&cfg->gpiote, &ch); if (err != NRFX_SUCCESS) { return -ENOMEM; } @@ -273,12 +291,12 @@ static int gpio_nrfx_pin_interrupt_configure(const struct device *port, trigger_config.p_in_channel = &ch; } - err = nrfx_gpiote_input_configure(abs_pin, NULL, &trigger_config, NULL); + err = nrfx_gpiote_input_configure(&cfg->gpiote, abs_pin, &input_pin_config); if (err != NRFX_SUCCESS) { return -EINVAL; } - nrfx_gpiote_trigger_enable(abs_pin, true); + nrfx_gpiote_trigger_enable(&cfg->gpiote, abs_pin, true); return 0; } @@ -367,26 +385,31 @@ static void nrfx_gpio_handler(nrfx_gpiote_pin_t abs_pin, } #endif /* CONFIG_GPIO_NRFX_INTERRUPT */ -#define GPIOTE_NODE DT_INST(0, nordic_nrf_gpiote) +#define GPIOTE_IRQ_HANDLER_CONNECT(node_id) \ + IRQ_CONNECT(DT_IRQN(node_id), DT_IRQ(node_id, priority), nrfx_isr, \ + NRFX_CONCAT(nrfx_gpiote_, DT_PROP(node_id, instance), _irq_handler), 0); static int gpio_nrfx_init(const struct device *port) { + const struct gpio_nrfx_cfg *cfg = get_port_cfg(port); nrfx_err_t err; - if (nrfx_gpiote_is_init()) { + if (!has_gpiote(cfg)) { + return 0; + } + + if (nrfx_gpiote_init_check(&cfg->gpiote)) { return 0; } - err = nrfx_gpiote_init(0/*not used*/); + err = nrfx_gpiote_init(&cfg->gpiote, 0 /*not used*/); if (err != NRFX_SUCCESS) { return -EIO; } #ifdef CONFIG_GPIO_NRFX_INTERRUPT - nrfx_gpiote_global_callback_set(nrfx_gpio_handler, NULL); - - IRQ_CONNECT(DT_IRQN(GPIOTE_NODE), DT_IRQ(GPIOTE_NODE, priority), - nrfx_isr, nrfx_gpiote_irq_handler, 0); + nrfx_gpiote_global_callback_set(&cfg->gpiote, nrfx_gpio_handler, NULL); + DT_FOREACH_STATUS_OKAY(nordic_nrf_gpiote, GPIOTE_IRQ_HANDLER_CONNECT); #endif /* CONFIG_GPIO_NRFX_INTERRUPT */ return 0; @@ -408,12 +431,27 @@ static const struct gpio_driver_api gpio_nrfx_drv_api_funcs = { #endif }; +#define GPIOTE_PHANDLE(id) DT_INST_PHANDLE(id, gpiote_instance) +#define GPIOTE_INST(id) DT_PROP(GPIOTE_PHANDLE(id), instance) + +#define GPIOTE_INSTANCE(id) \ + COND_CODE_1(DT_INST_NODE_HAS_PROP(id, gpiote_instance), \ + (NRFX_GPIOTE_INSTANCE(GPIOTE_INST(id))), \ + ({ .p_reg = NULL })) + /* Device instantiation is done with node labels because 'port_num' is * the peripheral number by SoC numbering. We therefore cannot use * DT_INST APIs here without wider changes. */ +#define GPIOTE_CHECK(id) \ + COND_CODE_1(DT_INST_NODE_HAS_PROP(id, gpiote_instance), \ + (BUILD_ASSERT(DT_NODE_HAS_STATUS(GPIOTE_PHANDLE(id), okay), \ + "Please enable GPIOTE instance for used GPIO port!")), \ + ()) + #define GPIO_NRF_DEVICE(id) \ + GPIOTE_CHECK(id); \ static const struct gpio_nrfx_cfg gpio_nrfx_p##id##_cfg = { \ .common = { \ .port_pin_mask = \ @@ -421,7 +459,8 @@ static const struct gpio_driver_api gpio_nrfx_drv_api_funcs = { }, \ .port = _CONCAT(NRF_P, DT_INST_PROP(id, port)), \ .port_num = DT_INST_PROP(id, port), \ - .edge_sense = DT_INST_PROP_OR(id, sense_edge_mask, 0) \ + .edge_sense = DT_INST_PROP_OR(id, sense_edge_mask, 0), \ + .gpiote = GPIOTE_INSTANCE(id), \ }; \ \ static struct gpio_nrfx_data gpio_nrfx_p##id##_data; \ diff --git a/drivers/pwm/pwm_nrf_sw.c b/drivers/pwm/pwm_nrf_sw.c index f367bb59899..2b9a22a38f0 100644 --- a/drivers/pwm/pwm_nrf_sw.c +++ b/drivers/pwm/pwm_nrf_sw.c @@ -62,6 +62,7 @@ struct pwm_config { NRF_RTC_Type *rtc; NRF_TIMER_Type *timer; }; + nrfx_gpiote_t gpiote[PWM_0_MAP_SIZE]; uint8_t psel_ch[PWM_0_MAP_SIZE]; uint8_t initially_inverted; uint8_t map_size; @@ -123,6 +124,7 @@ static int pwm_nrf_sw_set_cycles(const struct device *dev, uint32_t channel, const struct pwm_config *config = dev->config; NRF_TIMER_Type *timer = pwm_config_timer(config); NRF_RTC_Type *rtc = pwm_config_rtc(config); + NRF_GPIOTE_Type *gpiote; struct pwm_data *data = dev->data; uint32_t ppi_mask; uint8_t active_level; @@ -161,6 +163,7 @@ static int pwm_nrf_sw_set_cycles(const struct device *dev, uint32_t channel, } } + gpiote = config->gpiote[channel].p_reg; psel_ch = config->psel_ch[channel]; gpiote_ch = data->gpiote_ch[channel]; ppi_chs = data->ppi_ch[channel]; @@ -186,7 +189,7 @@ static int pwm_nrf_sw_set_cycles(const struct device *dev, uint32_t channel, : active_level); /* clear GPIOTE config */ - nrf_gpiote_te_default(NRF_GPIOTE, gpiote_ch); + nrf_gpiote_te_default(gpiote, gpiote_ch); /* No PWM generation for this channel. */ data->pulse_cycles[channel] = 0U; @@ -235,7 +238,7 @@ static int pwm_nrf_sw_set_cycles(const struct device *dev, uint32_t channel, } /* Configure GPIOTE - toggle task with proper initial output value. */ - NRF_GPIOTE->CONFIG[gpiote_ch] = + gpiote->CONFIG[gpiote_ch] = (GPIOTE_CONFIG_MODE_Task << GPIOTE_CONFIG_MODE_Pos) | ((uint32_t)psel_ch << 8) | (GPIOTE_CONFIG_POLARITY_Toggle << GPIOTE_CONFIG_POLARITY_Pos) | @@ -256,9 +259,9 @@ static int pwm_nrf_sw_set_cycles(const struct device *dev, uint32_t channel, pulse_end_task = period_end_task = nrf_gpiote_out_task_get(gpiote_ch); #endif uint32_t pulse_end_task_address = - nrf_gpiote_task_address_get(NRF_GPIOTE, pulse_end_task); + nrf_gpiote_task_address_get(gpiote, pulse_end_task); uint32_t period_end_task_address = - nrf_gpiote_task_address_get(NRF_GPIOTE, period_end_task); + nrf_gpiote_task_address_get(gpiote, period_end_task); if (USE_RTC) { uint32_t clear_task_address = @@ -359,7 +362,8 @@ static int pwm_nrf_sw_init(const struct device *dev) } } - err = nrfx_gpiote_channel_alloc(&data->gpiote_ch[i]); + err = nrfx_gpiote_channel_alloc(&config->gpiote[i], + &data->gpiote_ch[i]); if (err != NRFX_SUCCESS) { /* Do not free allocated resource. It is a fatal condition, * system requires reconfiguration. @@ -402,8 +406,14 @@ static int pwm_nrf_sw_init(const struct device *dev) ((DT_GPIO_FLAGS_BY_IDX(_node_id, _prop, _idx) & GPIO_ACTIVE_LOW) \ ? BIT(_idx) : 0) | +#define GPIOTE_AND_COMMA(_node_id, _prop, _idx) \ + NRFX_GPIOTE_INSTANCE(NRF_DT_GPIOTE_INST_BY_IDX(_node_id, _prop, _idx)), + static const struct pwm_config pwm_nrf_sw_0_config = { COND_CODE_1(USE_RTC, (.rtc), (.timer)) = GENERATOR_ADDR, + .gpiote = { + DT_INST_FOREACH_PROP_ELEM(0, channel_gpios, GPIOTE_AND_COMMA) + }, .psel_ch = { DT_INST_FOREACH_PROP_ELEM(0, channel_gpios, PSEL_AND_COMMA) }, diff --git a/drivers/spi/spi_nrfx_common.c b/drivers/spi/spi_nrfx_common.c index 1ef233cfab3..04a11c2367a 100644 --- a/drivers/spi/spi_nrfx_common.c +++ b/drivers/spi/spi_nrfx_common.c @@ -6,40 +6,39 @@ #include "spi_nrfx_common.h" #include -#include -int spi_nrfx_wake_init(uint32_t wake_pin) +int spi_nrfx_wake_init(const nrfx_gpiote_t *gpiote, uint32_t wake_pin) { - nrfx_gpiote_input_config_t input_config = { - .pull = NRF_GPIO_PIN_PULLDOWN, - }; + nrf_gpio_pin_pull_t pull_config = NRF_GPIO_PIN_PULLDOWN; uint8_t ch; nrfx_gpiote_trigger_config_t trigger_config = { .trigger = NRFX_GPIOTE_TRIGGER_HITOLO, .p_in_channel = &ch, }; + nrfx_gpiote_input_pin_config_t input_config = { + .p_pull_config = &pull_config, + .p_trigger_config = &trigger_config, + .p_handler_config = NULL, + }; nrfx_err_t res; - res = nrfx_gpiote_channel_alloc(&ch); + res = nrfx_gpiote_channel_alloc(gpiote, &ch); if (res != NRFX_SUCCESS) { return -ENODEV; } - res = nrfx_gpiote_input_configure(wake_pin, - &input_config, - &trigger_config, - NULL); + res = nrfx_gpiote_input_configure(gpiote, wake_pin, &input_config); if (res != NRFX_SUCCESS) { - nrfx_gpiote_channel_free(ch); + nrfx_gpiote_channel_free(gpiote, ch); return -EIO; } return 0; } -int spi_nrfx_wake_request(uint32_t wake_pin) +int spi_nrfx_wake_request(const nrfx_gpiote_t *gpiote, uint32_t wake_pin) { - nrf_gpiote_event_t trigger_event = nrfx_gpiote_in_event_get(wake_pin); + nrf_gpiote_event_t trigger_event = nrfx_gpiote_in_event_get(gpiote, wake_pin); uint32_t start_cycles; uint32_t max_wait_cycles = DIV_ROUND_UP(CONFIG_SPI_NRFX_WAKE_TIMEOUT_US * @@ -51,7 +50,7 @@ int spi_nrfx_wake_request(uint32_t wake_pin) * The expected time to wait is quite short so it is not worth paying * the overhead of context switching to handle the interrupt. */ - nrfx_gpiote_trigger_enable(wake_pin, false); + nrfx_gpiote_trigger_enable(gpiote, wake_pin, false); /* Enable pull-up on the WAKE line. After the slave device sees the * WAKE line going high, it will force the line to go low. This will * be caught by the enabled trigger and the loop below waits for that. @@ -59,7 +58,7 @@ int spi_nrfx_wake_request(uint32_t wake_pin) nrf_gpio_cfg_input(wake_pin, NRF_GPIO_PIN_PULLUP); start_cycles = k_cycle_get_32(); - while (!nrf_gpiote_event_check(NRF_GPIOTE, trigger_event)) { + while (!nrf_gpiote_event_check(gpiote->p_reg, trigger_event)) { uint32_t elapsed_cycles = k_cycle_get_32() - start_cycles; if (elapsed_cycles >= max_wait_cycles) { @@ -68,7 +67,7 @@ int spi_nrfx_wake_request(uint32_t wake_pin) } } - nrfx_gpiote_trigger_disable(wake_pin); + nrfx_gpiote_trigger_disable(gpiote, wake_pin); nrf_gpio_cfg_input(wake_pin, NRF_GPIO_PIN_PULLDOWN); return err; diff --git a/drivers/spi/spi_nrfx_common.h b/drivers/spi/spi_nrfx_common.h index 515ed5c6f1f..0cf17e2a035 100644 --- a/drivers/spi/spi_nrfx_common.h +++ b/drivers/spi/spi_nrfx_common.h @@ -8,10 +8,17 @@ #define ZEPHYR_DRIVERS_SPI_NRFX_COMMON_H_ #include +#include #define WAKE_PIN_NOT_USED UINT32_MAX -int spi_nrfx_wake_init(uint32_t wake_pin); -int spi_nrfx_wake_request(uint32_t wake_pin); +#define WAKE_GPIOTE_INSTANCE(node_id) \ + COND_CODE_1(DT_NODE_HAS_PROP(node_id, wake_gpios), \ + (NRFX_GPIOTE_INSTANCE( \ + NRF_DT_GPIOTE_INST(node_id, wake_gpios))), \ + ({0})) + +int spi_nrfx_wake_init(const nrfx_gpiote_t *gpiote, uint32_t wake_pin); +int spi_nrfx_wake_request(const nrfx_gpiote_t *gpiote, uint32_t wake_pin); #endif /* ZEPHYR_DRIVERS_SPI_NRFX_COMMON_H_ */ diff --git a/drivers/spi/spi_nrfx_spi.c b/drivers/spi/spi_nrfx_spi.c index fd1dc5d933c..04d7853d11d 100644 --- a/drivers/spi/spi_nrfx_spi.c +++ b/drivers/spi/spi_nrfx_spi.c @@ -31,6 +31,7 @@ struct spi_nrfx_config { void (*irq_connect)(void); const struct pinctrl_dev_config *pcfg; uint32_t wake_pin; + nrfx_gpiote_t wake_gpiote; }; static void event_handler(const nrfx_spi_evt_t *p_event, void *p_context); @@ -237,7 +238,8 @@ static int transceive(const struct device *dev, dev_data->busy = true; if (dev_config->wake_pin != WAKE_PIN_NOT_USED) { - error = spi_nrfx_wake_request(dev_config->wake_pin); + error = spi_nrfx_wake_request(&dev_config->wake_gpiote, + dev_config->wake_pin); if (error == -ETIMEDOUT) { LOG_WRN("Waiting for WAKE acknowledgment timed out"); /* If timeout occurs, try to perform the transfer @@ -381,7 +383,7 @@ static int spi_nrfx_init(const struct device *dev) } if (dev_config->wake_pin != WAKE_PIN_NOT_USED) { - err = spi_nrfx_wake_init(dev_config->wake_pin); + err = spi_nrfx_wake_init(&dev_config->wake_gpiote, dev_config->wake_pin); if (err == -ENODEV) { LOG_ERR("Failed to allocate GPIOTE channel for WAKE"); return err; @@ -444,6 +446,7 @@ static int spi_nrfx_init(const struct device *dev) .pcfg = PINCTRL_DT_DEV_CONFIG_GET(SPI(idx)), \ .wake_pin = NRF_DT_GPIOS_TO_PSEL_OR(SPI(idx), wake_gpios, \ WAKE_PIN_NOT_USED), \ + .wake_gpiote = WAKE_GPIOTE_INSTANCE(SPI(idx)), \ }; \ BUILD_ASSERT(!DT_NODE_HAS_PROP(SPI(idx), wake_gpios) || \ !(DT_GPIO_FLAGS(SPI(idx), wake_gpios) & GPIO_ACTIVE_LOW), \ diff --git a/drivers/spi/spi_nrfx_spim.c b/drivers/spi/spi_nrfx_spim.c index 1338bd0a4dc..95b737d6cf5 100644 --- a/drivers/spi/spi_nrfx_spim.c +++ b/drivers/spi/spi_nrfx_spim.c @@ -9,7 +9,6 @@ #include #include #ifdef CONFIG_SOC_NRF52832_ALLOW_SPIM_DESPITE_PAN_58 -#include #include #endif #ifdef CONFIG_SOC_NRF5340_CPUAPP @@ -64,6 +63,7 @@ struct spi_nrfx_config { bool anomaly_58_workaround; #endif uint32_t wake_pin; + nrfx_gpiote_t wake_gpiote; }; static void event_handler(const nrfx_spim_evt_t *p_event, void *p_context); @@ -207,6 +207,8 @@ static int configure(const struct device *dev, } #ifdef CONFIG_SOC_NRF52832_ALLOW_SPIM_DESPITE_PAN_58 +static const nrfx_gpiote_t gpiote = NRFX_GPIOTE_INSTANCE(0); + /* * Brief Workaround for transmitting 1 byte with SPIM. * @@ -226,15 +228,15 @@ static void anomaly_58_workaround_setup(const struct device *dev) NRF_SPIM_Type *spim = dev_config->spim.p_reg; uint32_t ppi_ch = dev_data->ppi_ch; uint32_t gpiote_ch = dev_data->gpiote_ch; - uint32_t eep = (uint32_t)&NRF_GPIOTE->EVENTS_IN[gpiote_ch]; + uint32_t eep = (uint32_t)&gpiote.p_reg->EVENTS_IN[gpiote_ch]; uint32_t tep = (uint32_t)&spim->TASKS_STOP; dev_data->anomaly_58_workaround_active = true; /* Create an event when SCK toggles */ - nrf_gpiote_event_configure(NRF_GPIOTE, gpiote_ch, spim->PSEL.SCK, + nrf_gpiote_event_configure(gpiote.p_reg, gpiote_ch, spim->PSEL.SCK, GPIOTE_CONFIG_POLARITY_Toggle); - nrf_gpiote_event_enable(NRF_GPIOTE, gpiote_ch); + nrf_gpiote_event_enable(gpiote.p_reg, gpiote_ch); /* Stop the spim instance when SCK toggles */ nrf_ppi_channel_endpoint_setup(NRF_PPI, ppi_ch, eep, tep); @@ -253,7 +255,7 @@ static void anomaly_58_workaround_clear(struct spi_nrfx_data *dev_data) if (dev_data->anomaly_58_workaround_active) { nrf_ppi_channel_disable(NRF_PPI, ppi_ch); - nrf_gpiote_task_disable(NRF_GPIOTE, gpiote_ch); + nrf_gpiote_task_disable(gpiote.p_reg, gpiote_ch); dev_data->anomaly_58_workaround_active = false; } @@ -274,7 +276,7 @@ static int anomaly_58_workaround_init(const struct device *dev) return -ENODEV; } - err_code = nrfx_gpiote_channel_alloc(&dev_data->gpiote_ch); + err_code = nrfx_gpiote_channel_alloc(&gpiote, &dev_data->gpiote_ch); if (err_code != NRFX_SUCCESS) { LOG_ERR("Failed to allocate GPIOTE channel"); return -ENODEV; @@ -426,7 +428,8 @@ static int transceive(const struct device *dev, dev_data->busy = true; if (dev_config->wake_pin != WAKE_PIN_NOT_USED) { - error = spi_nrfx_wake_request(dev_config->wake_pin); + error = spi_nrfx_wake_request(&dev_config->wake_gpiote, + dev_config->wake_pin); if (error == -ETIMEDOUT) { LOG_WRN("Waiting for WAKE acknowledgment timed out"); /* If timeout occurs, try to perform the transfer @@ -574,7 +577,7 @@ static int spi_nrfx_init(const struct device *dev) } if (dev_config->wake_pin != WAKE_PIN_NOT_USED) { - err = spi_nrfx_wake_init(dev_config->wake_pin); + err = spi_nrfx_wake_init(&dev_config->wake_gpiote, dev_config->wake_pin); if (err == -ENODEV) { LOG_ERR("Failed to allocate GPIOTE channel for WAKE"); return err; @@ -665,6 +668,7 @@ static int spi_nrfx_init(const struct device *dev) ()) \ .wake_pin = NRF_DT_GPIOS_TO_PSEL_OR(SPIM(idx), wake_gpios, \ WAKE_PIN_NOT_USED), \ + .wake_gpiote = WAKE_GPIOTE_INSTANCE(SPIM(idx)), \ }; \ BUILD_ASSERT(!SPIM_HAS_PROP(idx, wake_gpios) || \ !(DT_GPIO_FLAGS(SPIM(idx), wake_gpios) & GPIO_ACTIVE_LOW),\ diff --git a/drivers/watchdog/wdt_nrfx.c b/drivers/watchdog/wdt_nrfx.c index 363a1174e91..8967d1e162b 100644 --- a/drivers/watchdog/wdt_nrfx.c +++ b/drivers/watchdog/wdt_nrfx.c @@ -145,8 +145,12 @@ static const struct wdt_driver_api wdt_nrfx_driver_api = { .feed = wdt_nrf_feed, }; -static void wdt_event_handler(const struct device *dev, uint32_t requests) +static void wdt_event_handler(const struct device *dev, nrf_wdt_event_t event_type, + uint32_t requests, void *p_context) { + (void)event_type; + (void)p_context; + struct wdt_nrfx_data *data = dev->data; while (requests) { @@ -162,9 +166,12 @@ static void wdt_event_handler(const struct device *dev, uint32_t requests) #define WDT(idx) DT_NODELABEL(wdt##idx) #define WDT_NRFX_WDT_DEVICE(idx) \ - static void wdt_##idx##_event_handler(uint32_t requests) \ + static void wdt_##idx##_event_handler(nrf_wdt_event_t event_type, \ + uint32_t requests, \ + void *p_context) \ { \ - wdt_event_handler(DEVICE_DT_GET(WDT(idx)), requests); \ + wdt_event_handler(DEVICE_DT_GET(WDT(idx)), event_type, \ + requests, p_context); \ } \ static int wdt_##idx##_init(const struct device *dev) \ { \ @@ -174,7 +181,8 @@ static void wdt_event_handler(const struct device *dev, uint32_t requests) nrfx_isr, nrfx_wdt_##idx##_irq_handler, 0); \ err_code = nrfx_wdt_init(&config->wdt, \ NULL, \ - wdt_##idx##_event_handler); \ + wdt_##idx##_event_handler, \ + NULL); \ if (err_code != NRFX_SUCCESS) { \ return -EBUSY; \ } \ diff --git a/modules/hal_nordic/nrfx/nrfx_config.h b/modules/hal_nordic/nrfx/nrfx_config.h index 72617325684..57417644c32 100644 --- a/modules/hal_nordic/nrfx/nrfx_config.h +++ b/modules/hal_nordic/nrfx/nrfx_config.h @@ -9,12 +9,6 @@ #include -/* - * NRFX API version 2.10 flag. - * When the flag is set NRFX API is compatible with the newest NRFX release. - */ -#define NRFX_CONFIG_API_VER_2_10 1 - /* * These are mappings of Kconfig options enabling nrfx drivers and particular * peripheral instances to the corresponding symbols used inside of nrfx. diff --git a/modules/hal_nordic/nrfx/nrfx_config_common.h b/modules/hal_nordic/nrfx/nrfx_config_common.h index 8c0a58713a0..28a3a15b0de 100644 --- a/modules/hal_nordic/nrfx/nrfx_config_common.h +++ b/modules/hal_nordic/nrfx/nrfx_config_common.h @@ -18,7 +18,7 @@ /** @brief Symbol specifying minor version of the nrfx API to be used. */ #ifndef NRFX_CONFIG_API_VER_MINOR -#define NRFX_CONFIG_API_VER_MINOR 0 +#define NRFX_CONFIG_API_VER_MINOR 2 #endif /** @brief Symbol specifying micro version of the nrfx API to be used. */ diff --git a/samples/boards/nrf/nrfx/Kconfig b/samples/boards/nrf/nrfx/Kconfig index 0d54067202a..09076c9da49 100644 --- a/samples/boards/nrf/nrfx/Kconfig +++ b/samples/boards/nrf/nrfx/Kconfig @@ -7,4 +7,14 @@ config NRFX_DPPI config NRFX_PPI default HAS_HW_NRF_PPI +config NRFX_GPIOTE0 + default y if SOC_SERIES_NRF51X || \ + SOC_SERIES_NRF52X || \ + (SOC_SERIES_NRF53X && !TRUSTED_EXECUTION_NONSECURE) || \ + (SOC_SERIES_NRF91X && !TRUSTED_EXECUTION_NONSECURE) + +config NRFX_GPIOTE1 + default y if (SOC_SERIES_NRF53X && TRUSTED_EXECUTION_NONSECURE) || \ + (SOC_SERIES_NRF91X && TRUSTED_EXECUTION_NONSECURE) + source "Kconfig.zephyr" diff --git a/samples/boards/nrf/nrfx/prj.conf b/samples/boards/nrf/nrfx/prj.conf index 32cbfc3279c..d4f0c29699f 100644 --- a/samples/boards/nrf/nrfx/prj.conf +++ b/samples/boards/nrf/nrfx/prj.conf @@ -1,4 +1,3 @@ CONFIG_GPIO=n -CONFIG_NRFX_GPIOTE=y CONFIG_LOG=y CONFIG_LOG_PROCESS_THREAD_SLEEP_MS=100 diff --git a/samples/boards/nrf/nrfx/src/main.c b/samples/boards/nrf/nrfx/src/main.c index 615b800545e..0643b1c0911 100644 --- a/samples/boards/nrf/nrfx/src/main.c +++ b/samples/boards/nrf/nrfx/src/main.c @@ -21,6 +21,15 @@ LOG_MODULE_REGISTER(nrfx_sample, LOG_LEVEL_INF); #define INPUT_PIN DT_GPIO_PIN(DT_ALIAS(sw0), gpios) #define OUTPUT_PIN DT_GPIO_PIN(DT_ALIAS(led0), gpios) +#define GPIOTE_INST NRF_DT_GPIOTE_INST(DT_ALIAS(sw0), gpios) +#define GPIOTE_NODE DT_NODELABEL(_CONCAT(gpiote, GPIOTE_INST)) + +BUILD_ASSERT(NRF_DT_GPIOTE_INST(DT_ALIAS(led0), gpios) == GPIOTE_INST, + "Both sw0 and led0 GPIOs must use the same GPIOTE instance"); +BUILD_ASSERT(IS_ENABLED(_CONCAT(CONFIG_, _CONCAT(NRFX_GPIOTE, GPIOTE_INST))), + "NRFX_GPIOTE" STRINGIFY(GPIOTE_INST) " must be enabled in Kconfig"); + + static void button_handler(nrfx_gpiote_pin_t pin, nrfx_gpiote_trigger_t trigger, void *context) @@ -35,28 +44,28 @@ int main(void) nrfx_err_t err; uint8_t in_channel, out_channel; uint8_t ppi_channel; + const nrfx_gpiote_t gpiote = NRFX_GPIOTE_INSTANCE(GPIOTE_INST); - /* Connect GPIOTE_0 IRQ to nrfx_gpiote_irq_handler */ - IRQ_CONNECT(DT_IRQN(DT_NODELABEL(gpiote)), - DT_IRQ(DT_NODELABEL(gpiote), priority), - nrfx_isr, nrfx_gpiote_irq_handler, 0); + /* Connect GPIOTE instance IRQ to irq handler */ + IRQ_CONNECT(DT_IRQN(GPIOTE_NODE), DT_IRQ(GPIOTE_NODE, priority), nrfx_isr, + NRFX_CONCAT(nrfx_gpiote_, GPIOTE_INST, _irq_handler), 0); /* Initialize GPIOTE (the interrupt priority passed as the parameter * here is ignored, see nrfx_glue.h). */ - err = nrfx_gpiote_init(0); + err = nrfx_gpiote_init(&gpiote, 0); if (err != NRFX_SUCCESS) { LOG_ERR("nrfx_gpiote_init error: 0x%08X", err); return 0; } - err = nrfx_gpiote_channel_alloc(&in_channel); + err = nrfx_gpiote_channel_alloc(&gpiote, &in_channel); if (err != NRFX_SUCCESS) { LOG_ERR("Failed to allocate in_channel, error: 0x%08X", err); return 0; } - err = nrfx_gpiote_channel_alloc(&out_channel); + err = nrfx_gpiote_channel_alloc(&gpiote, &out_channel); if (err != NRFX_SUCCESS) { LOG_ERR("Failed to allocate out_channel, error: 0x%08X", err); return 0; @@ -65,20 +74,22 @@ int main(void) /* Initialize input pin to generate event on high to low transition * (falling edge) and call button_handler() */ - static const nrfx_gpiote_input_config_t input_config = { - .pull = NRF_GPIO_PIN_PULLUP, - }; - const nrfx_gpiote_trigger_config_t trigger_config = { + static const nrf_gpio_pin_pull_t pull_config = NRF_GPIO_PIN_PULLUP; + nrfx_gpiote_trigger_config_t trigger_config = { .trigger = NRFX_GPIOTE_TRIGGER_HITOLO, .p_in_channel = &in_channel, }; static const nrfx_gpiote_handler_config_t handler_config = { .handler = button_handler, }; - err = nrfx_gpiote_input_configure(INPUT_PIN, - &input_config, - &trigger_config, - &handler_config); + nrfx_gpiote_input_pin_config_t input_config = { + .p_pull_config = &pull_config, + .p_trigger_config = &trigger_config, + .p_handler_config = &handler_config + }; + + err = nrfx_gpiote_input_configure(&gpiote, INPUT_PIN, &input_config); + if (err != NRFX_SUCCESS) { LOG_ERR("nrfx_gpiote_input_configure error: 0x%08X", err); return 0; @@ -97,7 +108,7 @@ int main(void) .polarity = NRF_GPIOTE_POLARITY_TOGGLE, .init_val = 1, }; - err = nrfx_gpiote_output_configure(OUTPUT_PIN, + err = nrfx_gpiote_output_configure(&gpiote, OUTPUT_PIN, &output_config, &task_config); if (err != NRFX_SUCCESS) { @@ -105,8 +116,8 @@ int main(void) return 0; } - nrfx_gpiote_trigger_enable(INPUT_PIN, true); - nrfx_gpiote_out_task_enable(OUTPUT_PIN); + nrfx_gpiote_trigger_enable(&gpiote, INPUT_PIN, true); + nrfx_gpiote_out_task_enable(&gpiote, OUTPUT_PIN); LOG_INF("nrfx_gpiote initialized"); @@ -122,8 +133,8 @@ int main(void) * the button is pressed, the LED pin will be toggled. */ nrfx_gppi_channel_endpoints_setup(ppi_channel, - nrfx_gpiote_in_event_address_get(INPUT_PIN), - nrfx_gpiote_out_task_address_get(OUTPUT_PIN)); + nrfx_gpiote_in_event_address_get(&gpiote, INPUT_PIN), + nrfx_gpiote_out_task_address_get(&gpiote, OUTPUT_PIN)); /* Enable the channel. */ nrfx_gppi_channels_enable(BIT(ppi_channel)); From 1c0302d2fcb238a90a4c64add5cbdae3f2638715 Mon Sep 17 00:00:00 2001 From: Dawid Niedzwiecki Date: Thu, 4 Jan 2024 09:09:15 +0100 Subject: [PATCH 1815/3723] drivers: gpio: stm32: fix init power state Set suspended as initial power state, only when the CONFIG_PM_DEVICE_RUNTIME config is enabled. The initial state was incorrect, when CONFIG_PM_DEVICE=y and CONFIG_PM_DEVICE_RUNTIME=n. In that case, the power state was SUSPENDED, but the device was actually enabled. Signed-off-by: Dawid Niedzwiecki --- drivers/gpio/gpio_stm32.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/drivers/gpio/gpio_stm32.c b/drivers/gpio/gpio_stm32.c index 877dbb4882c..fe6d98d7a35 100644 --- a/drivers/gpio/gpio_stm32.c +++ b/drivers/gpio/gpio_stm32.c @@ -719,7 +719,9 @@ static int gpio_stm32_init(const struct device *dev) return ret; } - pm_device_init_suspended(dev); + if (IS_ENABLED(CONFIG_PM_DEVICE_RUNTIME)) { + pm_device_init_suspended(dev); + } (void)pm_device_runtime_enable(dev); return 0; From d6ebf1efa88e548a586345b6d2dcefaf19e783f8 Mon Sep 17 00:00:00 2001 From: Alexander Kozhinov Date: Fri, 29 Dec 2023 23:02:38 +0100 Subject: [PATCH 1816/3723] drivers: clock_control: clock_stm32_ll_h7.c Reduce code-complexity of stm32_clock_control_init() function, which is used and exists for both M4/M7 cores. Replace dublicated code by proper preprocessor guarding. This change shall reduce code-errors and copy-paste errors since same functional code is present only once now. Identify even more common code Signed-off-by: Alexander Kozhinov --- drivers/clock_control/clock_stm32_ll_h7.c | 19 +++++-------------- 1 file changed, 5 insertions(+), 14 deletions(-) diff --git a/drivers/clock_control/clock_stm32_ll_h7.c b/drivers/clock_control/clock_stm32_ll_h7.c index 23856ff7e2d..9d76004c92f 100644 --- a/drivers/clock_control/clock_stm32_ll_h7.c +++ b/drivers/clock_control/clock_stm32_ll_h7.c @@ -824,14 +824,13 @@ static int set_up_plls(void) return 0; } -#if defined(CONFIG_CPU_CORTEX_M7) int stm32_clock_control_init(const struct device *dev) { + int r = 0; + +#if defined(CONFIG_CPU_CORTEX_M7) uint32_t old_hclk_freq = 0; uint32_t new_hclk_freq = 0; - int r; - - ARG_UNUSED(dev); /* HW semaphore Clock enable */ #if defined(CONFIG_SOC_STM32H7A3XX) || defined(CONFIG_SOC_STM32H7A3XXQ) || \ @@ -917,23 +916,15 @@ int stm32_clock_control_init(const struct device *dev) optimize_regulator_voltage_scale(CONFIG_SYS_CLOCK_HW_CYCLES_PER_SEC); z_stm32_hsem_unlock(CFG_HW_RCC_SEMID); +#endif /* CONFIG_CPU_CORTEX_M7 */ - /* Update CMSIS variable */ - SystemCoreClock = CONFIG_SYS_CLOCK_HW_CYCLES_PER_SEC; - - return r; -} -#else -int stm32_clock_control_init(const struct device *dev) -{ ARG_UNUSED(dev); /* Update CMSIS variable */ SystemCoreClock = CONFIG_SYS_CLOCK_HW_CYCLES_PER_SEC; - return 0; + return r; } -#endif /* CONFIG_CPU_CORTEX_M7 */ #if defined(STM32_HSE_CSS) void __weak stm32_hse_css_callback(void) {} From 974bb50044f6d75a4b51f4c65684830aa8e7588a Mon Sep 17 00:00:00 2001 From: Francois Ramu Date: Thu, 4 Jan 2024 09:10:16 +0100 Subject: [PATCH 1817/3723] boards: arm: stm32h573i_dk is connected to a 512Mbit octoflash Corrects the size of the external octoFlash connected to the mcu of the stm32h573i disco kit from STMicroelectonics Signed-off-by: Francois Ramu --- boards/arm/stm32h573i_dk/doc/index.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/boards/arm/stm32h573i_dk/doc/index.rst b/boards/arm/stm32h573i_dk/doc/index.rst index f7806f52dde..515371632db 100644 --- a/boards/arm/stm32h573i_dk/doc/index.rst +++ b/boards/arm/stm32h573i_dk/doc/index.rst @@ -17,7 +17,7 @@ the STM32H573I-DK Discovery board: - USB Type-C |trade| Host and device with USB power-delivery controller - SAI Audio DAC stereo with one audio jacks for input/output, - ST MEMS digital microphone with PDM interface -- Octo-SPI interface connected to 152Mbit Octo-SPI NORFlash memory device (MX25LM51245GXDI00 from MACRONIX) +- Octo-SPI interface connected to 512Mbit Octo-SPI NORFlash memory device (MX25LM51245GXDI00 from MACRONIX) - 10/100-Mbit Ethernet, - microSD |trade| - A Wi‑Fi® add-on board From 54539b2590e26b0c5d54d917f1b580b40fb259dc Mon Sep 17 00:00:00 2001 From: Abderrahmane Jarmouni Date: Wed, 3 Jan 2024 18:53:54 +0100 Subject: [PATCH 1818/3723] board: arm: nucleo-l4r5zi: flashing Add the possibility to flash nucleo-l4r5zi board using west STM32CubeProgrammer runner. Signed-off-by: Abderrahmane Jarmouni --- boards/arm/nucleo_l4r5zi/board.cmake | 2 ++ boards/arm/nucleo_l4r5zi/doc/index.rst | 21 +++++++++++++++++++-- 2 files changed, 21 insertions(+), 2 deletions(-) diff --git a/boards/arm/nucleo_l4r5zi/board.cmake b/boards/arm/nucleo_l4r5zi/board.cmake index 037f4a5fd14..0def9a56111 100644 --- a/boards/arm/nucleo_l4r5zi/board.cmake +++ b/boards/arm/nucleo_l4r5zi/board.cmake @@ -1,6 +1,8 @@ # SPDX-License-Identifier: Apache-2.0 +board_runner_args(stm32cubeprogrammer "--port=swd" "--reset-mode=hw") board_runner_args(jlink "--device=STM32L4R5ZI" "--speed=4000") +include(${ZEPHYR_BASE}/boards/common/stm32cubeprogrammer.board.cmake) include(${ZEPHYR_BASE}/boards/common/openocd.board.cmake) include(${ZEPHYR_BASE}/boards/common/jlink.board.cmake) diff --git a/boards/arm/nucleo_l4r5zi/doc/index.rst b/boards/arm/nucleo_l4r5zi/doc/index.rst index 9adb38a2c59..15072f81cdf 100644 --- a/boards/arm/nucleo_l4r5zi/doc/index.rst +++ b/boards/arm/nucleo_l4r5zi/doc/index.rst @@ -219,9 +219,23 @@ Ethernet over USB is configured as the default network interface (EEM) Programming and Debugging ************************* +The NUCLEO-L4R5ZI board includes a ST-LINK/V2 embedded debug tool interface. + +The board is configured to be flashed using west `STM32CubeProgrammer`_ runner, +so its installation is required to be able to flash the board. + +Alternatively, openocd (provided in Zephyr SDK) or JLink can also be used to +flash the board using the ``--runner`` (or ``-r``) option: + +.. code-block:: console + + $ west flash --runner openocd + $ west flash --runner jlink + Connect the Nucleo L4R5ZI to your host computer using the USB port. -Then build and flash an application. Here is an example for the -:ref:`hello_world` application. +Then build and flash an application. + +Here is an example for the :ref:`hello_world` application. Run a serial host program to connect with your Nucleo board: @@ -256,3 +270,6 @@ You should see the following message on the console: .. _STM32 ST-LINK utility: https://www.st.com/content/st_com/en/products/development-tools/software-development-tools/stm32-software-development-tools/stm32-programmers/stsw-link004.html + +.. _STM32CubeProgrammer: + https://www.st.com/en/development-tools/stm32cubeprog.html From 0d4b46f51cd973bee697d9c3d4b1ae8c5a5641b7 Mon Sep 17 00:00:00 2001 From: Chamira Perera Date: Tue, 2 Jan 2024 15:25:31 +1100 Subject: [PATCH 1819/3723] drivers: ethernet: stm32: Enabling HW checksum offloading for STM32H7. This change adds support for enabling ethernet MAC hardware checksum offloading for STM32H7 based devices. In Section 58.5.9 of the STM32H7 reference manual it mentions that the STM32H7 ethernet MAC supports a Checksum Offload Module (COE). I have tested the changes on my end where I enabled CONFIG_ETH_STM32_HW_CHECKSUM and ensured that an application that runs Zephyr on the STM32H7 can interoperate with a device with a completely different implementation. Also, I deliberately made the software not populate the IPv4 and UDP header checksum fields in their respective headers and the COE was able to populate the IPv4 and UDP header checksums. Given that CONFIG_ETH_STM32_HW_CHECKSUM is not enabled by default application developers have the option to either enable it or disable it. Signed-off-by: Chamira Perera --- drivers/ethernet/Kconfig.stm32_hal | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/ethernet/Kconfig.stm32_hal b/drivers/ethernet/Kconfig.stm32_hal index 4f5f79d1f63..8161ea31f5f 100644 --- a/drivers/ethernet/Kconfig.stm32_hal +++ b/drivers/ethernet/Kconfig.stm32_hal @@ -137,7 +137,7 @@ config ETH_STM32_AUTO_NEGOTIATION_ENABLE config ETH_STM32_HW_CHECKSUM bool "Use TX and RX hardware checksum" - depends on (!SOC_SERIES_STM32H7X && !SOC_SERIES_STM32H5X ) + depends on !SOC_SERIES_STM32H5X help Enable receive and transmit checksum offload to enhance throughput performances. From 2307228442aa6a3824f13373cee9a297fb2b047c Mon Sep 17 00:00:00 2001 From: Alexander Kozhinov Date: Sun, 31 Dec 2023 17:02:40 +0100 Subject: [PATCH 1820/3723] boards: arm: nucleo_h745zi_q: nucleo_h745zi_q_m7.dts Change div-q to fulfill FDCAN clock requirements Signed-off-by: Alexander Kozhinov --- boards/arm/nucleo_h745zi_q/nucleo_h745zi_q_m7.dts | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/boards/arm/nucleo_h745zi_q/nucleo_h745zi_q_m7.dts b/boards/arm/nucleo_h745zi_q/nucleo_h745zi_q_m7.dts index d63b4ff8a58..184232867bb 100644 --- a/boards/arm/nucleo_h745zi_q/nucleo_h745zi_q_m7.dts +++ b/boards/arm/nucleo_h745zi_q/nucleo_h745zi_q_m7.dts @@ -6,7 +6,6 @@ /dts-v1/; #include -#include #include "nucleo_h745zi_q.dtsi" /* @@ -63,7 +62,7 @@ div-m = <1>; mul-n = <120>; div-p = <2>; - div-q = <2>; + div-q = <8>; div-r = <2>; clocks = <&clk_hse>; status = "okay"; From 164e4b6fa3e48c1d857d7b70af978de9ebf6f4f3 Mon Sep 17 00:00:00 2001 From: Dawid Niedzwiecki Date: Fri, 22 Dec 2023 14:10:24 +0100 Subject: [PATCH 1821/3723] clock_control: stm32f4: add PLLR division factor Some STM32F4xx chips have an R division factor in PLL. Add possibility to configure that. Even though the output from the R division is not used, it can be increased to reduce power consumption. Signed-off-by: Dawid Niedzwiecki --- drivers/clock_control/clock_stm32f2_f4_f7.c | 3 +++ dts/bindings/clock/st,stm32f4-pll-clock.yaml | 7 +++++++ 2 files changed, 10 insertions(+) diff --git a/drivers/clock_control/clock_stm32f2_f4_f7.c b/drivers/clock_control/clock_stm32f2_f4_f7.c index 6131fcd4c06..a10fede6887 100644 --- a/drivers/clock_control/clock_stm32f2_f4_f7.c +++ b/drivers/clock_control/clock_stm32f2_f4_f7.c @@ -56,6 +56,9 @@ uint32_t get_pllsrc_frequency(void) __unused void config_pll_sysclock(void) { +#if defined(STM32_SRC_PLL_R) && STM32_PLL_R_ENABLED && defined(RCC_PLLCFGR_PLLR) + MODIFY_REG(RCC->PLLCFGR, RCC_PLLCFGR_PLLR, pllr(STM32_PLL_R_DIVISOR)); +#endif LL_RCC_PLL_ConfigDomain_SYS(get_pll_source(), pllm(STM32_PLL_M_DIVISOR), STM32_PLL_N_MULTIPLIER, diff --git a/dts/bindings/clock/st,stm32f4-pll-clock.yaml b/dts/bindings/clock/st,stm32f4-pll-clock.yaml index 137a15822ac..1346ec8a55f 100644 --- a/dts/bindings/clock/st,stm32f4-pll-clock.yaml +++ b/dts/bindings/clock/st,stm32f4-pll-clock.yaml @@ -61,3 +61,10 @@ properties: Main PLL (PLL) division factor for USB OTG FS, SDMMC and random number generator clocks. Valid range: 2 - 15 + + div-r: + type: int + description: | + Main PLL (PLL) division factor for I2S and DFSDM + generator clocks. + Valid range: 2 - 7 From 4b889e9e014ba4463bb567ae78b3dc90a80ac6be Mon Sep 17 00:00:00 2001 From: TOKITA Hiroshi Date: Sun, 24 Dec 2023 14:12:46 +0900 Subject: [PATCH 1822/3723] boards: riscv: stamp_c3: Update sys_timer configuration The esp32c3 systimer has been fixed in PR #53453, but stamp_c3 was not included, so we will update it to catch up with this fix Signed-off-by: TOKITA Hiroshi --- boards/riscv/stamp_c3/stamp_c3_defconfig | 2 -- 1 file changed, 2 deletions(-) diff --git a/boards/riscv/stamp_c3/stamp_c3_defconfig b/boards/riscv/stamp_c3/stamp_c3_defconfig index 3b5efc64fa1..021a4e84162 100644 --- a/boards/riscv/stamp_c3/stamp_c3_defconfig +++ b/boards/riscv/stamp_c3/stamp_c3_defconfig @@ -5,8 +5,6 @@ CONFIG_SOC_SERIES_ESP32C3=y CONFIG_MAIN_STACK_SIZE=2048 -CONFIG_SYS_CLOCK_HW_CYCLES_PER_SEC=1000000 - CONFIG_CONSOLE=y CONFIG_SERIAL=y CONFIG_UART_CONSOLE=y From 01e94e0766d5c3e5f9bf4817998759fc14509c67 Mon Sep 17 00:00:00 2001 From: Bjarki Arge Andreasen Date: Sat, 23 Dec 2023 14:17:43 +0100 Subject: [PATCH 1823/3723] soc: arm: stm32: Fix invalid Kconfig PM entry in defconfig file The defconfig.series file for the stm32f4 incorrectly redefines the PM Kconfig in order to select two dependencies, COUNTER and COUNTER_RTC_STM32_SUBSECONDS, instead of setting a default for them if PM is included. This commit fixes the error described above. Signed-off-by: Bjarki Arge Andreasen --- soc/arm/st_stm32/stm32f4/Kconfig.defconfig.series | 12 +++++++++--- 1 file changed, 9 insertions(+), 3 deletions(-) diff --git a/soc/arm/st_stm32/stm32f4/Kconfig.defconfig.series b/soc/arm/st_stm32/stm32f4/Kconfig.defconfig.series index 067dcfc003f..26eead6bef8 100644 --- a/soc/arm/st_stm32/stm32f4/Kconfig.defconfig.series +++ b/soc/arm/st_stm32/stm32f4/Kconfig.defconfig.series @@ -17,8 +17,14 @@ config TASK_WDT_HW_FALLBACK_DELAY depends on TASK_WDT_HW_FALLBACK default 200 -config PM - select COUNTER - select COUNTER_RTC_STM32_SUBSECONDS if DT_HAS_ST_STM32_RTC_ENABLED +if PM + +config COUNTER + default y + +config COUNTER_RTC_STM32_SUBSECONDS + default y if DT_HAS_ST_STM32_RTC_ENABLED + +endif # PM endif # SOC_SERIES_STM32F4X From 95c5f9b6f3521403a9443685f7b062d6c116c279 Mon Sep 17 00:00:00 2001 From: Bjarki Arge Andreasen Date: Wed, 3 Jan 2024 14:16:08 +0100 Subject: [PATCH 1824/3723] soc: arm: stm32f4 increase IDLE stack in case of PM When Power Management is enabled (CONFIG_PM=y), the CONFIG_IDLE_STACK_SIZE of 320 is not enough : Increase its size to 512. Signed-off-by: Francois Ramu Signed-off-by: Bjarki Arge Andreasen --- soc/arm/st_stm32/stm32f4/Kconfig.defconfig.series | 3 +++ 1 file changed, 3 insertions(+) diff --git a/soc/arm/st_stm32/stm32f4/Kconfig.defconfig.series b/soc/arm/st_stm32/stm32f4/Kconfig.defconfig.series index 26eead6bef8..63725609480 100644 --- a/soc/arm/st_stm32/stm32f4/Kconfig.defconfig.series +++ b/soc/arm/st_stm32/stm32f4/Kconfig.defconfig.series @@ -25,6 +25,9 @@ config COUNTER config COUNTER_RTC_STM32_SUBSECONDS default y if DT_HAS_ST_STM32_RTC_ENABLED +config IDLE_STACK_SIZE + default 512 + endif # PM endif # SOC_SERIES_STM32F4X From 37520006f387ed8f6c68c1d6101aa1bdf5ebb5c8 Mon Sep 17 00:00:00 2001 From: Steffen Jahnke Date: Mon, 18 Dec 2023 12:59:55 +0000 Subject: [PATCH 1825/3723] boards: arm: add PAN1783A-PA evaluation board The PAN1783A-PA evaluation board is a development tool for the nRF5340 from Nordic Semiconductor and the third evaluation board variant for the PAN1783 Module. The power amplifier (PA) version includes FEM support. Signed-off-by: Steffen Jahnke --- .../CMakeLists.txt | 4 +- .../{pan1783_pan1783a_evb => pan1783}/Kconfig | 6 +- .../Kconfig.board | 8 ++ .../Kconfig.defconfig | 10 ++- .../board.cmake | 4 +- boards/arm/pan1783/doc/img/pan1783_evb.webp | Bin 0 -> 42252 bytes boards/arm/pan1783/doc/index.rst | 73 ++++++++++++++++++ .../pan1783_cpuapp_common-pinctrl.dtsi} | 0 .../pan1783_cpuapp_common.dtsi} | 4 +- .../pan1783_cpuapp_partition_conf.dtsi} | 2 +- .../pan1783_cpunet-pinctrl.dtsi} | 0 .../pan1783_cpunet_common.dtsi} | 4 +- .../pan1783_cpunet_reset.c} | 2 + .../pan1783_evb_cpuapp.dts | 2 +- .../pan1783_evb_cpuapp.yaml | 0 .../pan1783_evb_cpuapp_defconfig | 0 .../pan1783_evb_cpunet.dts | 4 +- .../pan1783_evb_cpunet.yaml | 0 .../pan1783_evb_cpunet_defconfig | 0 .../pan1783_shared_sram_planning_conf.dtsi} | 0 .../pan1783a_evb_cpuapp.dts | 2 +- .../pan1783a_evb_cpuapp.yaml | 0 .../pan1783a_evb_cpuapp_defconfig | 0 .../pan1783a_evb_cpunet.dts | 4 +- .../pan1783a_evb_cpunet.yaml | 0 .../pan1783a_evb_cpunet_defconfig | 0 boards/arm/pan1783/pan1783a_pa_evb_cpuapp.dts | 30 +++++++ .../arm/pan1783/pan1783a_pa_evb_cpuapp.yaml | 21 +++++ .../pan1783/pan1783a_pa_evb_cpuapp_defconfig | 25 ++++++ boards/arm/pan1783/pan1783a_pa_evb_cpunet.dts | 33 ++++++++ .../arm/pan1783/pan1783a_pa_evb_cpunet.yaml | 14 ++++ .../pan1783/pan1783a_pa_evb_cpunet_defconfig | 18 +++++ .../pre_dt_board.cmake | 0 .../doc/img/pan1783_evb.jpg | Bin 57564 -> 0 bytes .../doc/img/pan1783a_evb.jpg | Bin 62330 -> 0 bytes boards/arm/pan1783_pan1783a_evb/doc/index.rst | 62 --------------- 36 files changed, 249 insertions(+), 83 deletions(-) rename boards/arm/{pan1783_pan1783a_evb => pan1783}/CMakeLists.txt (59%) rename boards/arm/{pan1783_pan1783a_evb => pan1783}/Kconfig (83%) rename boards/arm/{pan1783_pan1783a_evb => pan1783}/Kconfig.board (70%) rename boards/arm/{pan1783_pan1783a_evb => pan1783}/Kconfig.defconfig (54%) rename boards/arm/{pan1783_pan1783a_evb => pan1783}/board.cmake (82%) create mode 100644 boards/arm/pan1783/doc/img/pan1783_evb.webp create mode 100644 boards/arm/pan1783/doc/index.rst rename boards/arm/{pan1783_pan1783a_evb/pan1783_pan1783a_cpuapp_common-pinctrl.dtsi => pan1783/pan1783_cpuapp_common-pinctrl.dtsi} (100%) rename boards/arm/{pan1783_pan1783a_evb/pan1783_pan1783a_cpuapp_common.dtsi => pan1783/pan1783_cpuapp_common.dtsi} (98%) rename boards/arm/{pan1783_pan1783a_evb/pan1783_pan1783a_cpuapp_partition_conf.dtsi => pan1783/pan1783_cpuapp_partition_conf.dtsi} (93%) rename boards/arm/{pan1783_pan1783a_evb/pan1783_pan1783a_cpunet-pinctrl.dtsi => pan1783/pan1783_cpunet-pinctrl.dtsi} (100%) rename boards/arm/{pan1783_pan1783a_evb/pan1783_pan1783a_cpunet_common.dtsi => pan1783/pan1783_cpunet_common.dtsi} (97%) rename boards/arm/{pan1783_pan1783a_evb/pan1783_pan1783a_evb_cpunet_reset.c => pan1783/pan1783_cpunet_reset.c} (90%) rename boards/arm/{pan1783_pan1783a_evb => pan1783}/pan1783_evb_cpuapp.dts (90%) rename boards/arm/{pan1783_pan1783a_evb => pan1783}/pan1783_evb_cpuapp.yaml (100%) rename boards/arm/{pan1783_pan1783a_evb => pan1783}/pan1783_evb_cpuapp_defconfig (100%) rename boards/arm/{pan1783_pan1783a_evb => pan1783}/pan1783_evb_cpunet.dts (80%) rename boards/arm/{pan1783_pan1783a_evb => pan1783}/pan1783_evb_cpunet.yaml (100%) rename boards/arm/{pan1783_pan1783a_evb => pan1783}/pan1783_evb_cpunet_defconfig (100%) rename boards/arm/{pan1783_pan1783a_evb/pan1783_pan1783a_shared_sram_planning_conf.dtsi => pan1783/pan1783_shared_sram_planning_conf.dtsi} (100%) rename boards/arm/{pan1783_pan1783a_evb => pan1783}/pan1783a_evb_cpuapp.dts (90%) rename boards/arm/{pan1783_pan1783a_evb => pan1783}/pan1783a_evb_cpuapp.yaml (100%) rename boards/arm/{pan1783_pan1783a_evb => pan1783}/pan1783a_evb_cpuapp_defconfig (100%) rename boards/arm/{pan1783_pan1783a_evb => pan1783}/pan1783a_evb_cpunet.dts (80%) rename boards/arm/{pan1783_pan1783a_evb => pan1783}/pan1783a_evb_cpunet.yaml (100%) rename boards/arm/{pan1783_pan1783a_evb => pan1783}/pan1783a_evb_cpunet_defconfig (100%) create mode 100644 boards/arm/pan1783/pan1783a_pa_evb_cpuapp.dts create mode 100644 boards/arm/pan1783/pan1783a_pa_evb_cpuapp.yaml create mode 100644 boards/arm/pan1783/pan1783a_pa_evb_cpuapp_defconfig create mode 100644 boards/arm/pan1783/pan1783a_pa_evb_cpunet.dts create mode 100644 boards/arm/pan1783/pan1783a_pa_evb_cpunet.yaml create mode 100644 boards/arm/pan1783/pan1783a_pa_evb_cpunet_defconfig rename boards/arm/{pan1783_pan1783a_evb => pan1783}/pre_dt_board.cmake (100%) delete mode 100644 boards/arm/pan1783_pan1783a_evb/doc/img/pan1783_evb.jpg delete mode 100644 boards/arm/pan1783_pan1783a_evb/doc/img/pan1783a_evb.jpg delete mode 100644 boards/arm/pan1783_pan1783a_evb/doc/index.rst diff --git a/boards/arm/pan1783_pan1783a_evb/CMakeLists.txt b/boards/arm/pan1783/CMakeLists.txt similarity index 59% rename from boards/arm/pan1783_pan1783a_evb/CMakeLists.txt rename to boards/arm/pan1783/CMakeLists.txt index 9530e370252..a582b3cc819 100644 --- a/boards/arm/pan1783_pan1783a_evb/CMakeLists.txt +++ b/boards/arm/pan1783/CMakeLists.txt @@ -1,7 +1,7 @@ # Copyright (c) 2023 Panasonic Industrial Devices Europe GmbH # SPDX-License-Identifier: Apache-2.0 -if((CONFIG_BOARD_PAN1783_EVB_CPUAPP OR CONFIG_BOARD_PAN1783A_EVB_CPUAPP) AND (CONFIG_BOARD_ENABLE_CPUNET)) +if((CONFIG_BOARD_PAN1783_EVB_CPUAPP OR CONFIG_BOARD_PAN1783A_EVB_CPUAPP OR CONFIG_BOARD_PAN1783A_PA_EVB_CPUAPP) AND (CONFIG_BOARD_ENABLE_CPUNET)) zephyr_library() - zephyr_library_sources(pan1783_pan1783a_evb_cpunet_reset.c) + zephyr_library_sources(pan1783_cpunet_reset.c) endif() diff --git a/boards/arm/pan1783_pan1783a_evb/Kconfig b/boards/arm/pan1783/Kconfig similarity index 83% rename from boards/arm/pan1783_pan1783a_evb/Kconfig rename to boards/arm/pan1783/Kconfig index a699840cad9..e4f58398459 100644 --- a/boards/arm/pan1783_pan1783a_evb/Kconfig +++ b/boards/arm/pan1783/Kconfig @@ -3,7 +3,7 @@ # Copyright (c) 2023 Panasonic Industrial Devices Europe GmbH # SPDX-License-Identifier: Apache-2.0 -if BOARD_PAN1783_EVB_CPUAPP || BOARD_PAN1783A_EVB_CPUAPP +if BOARD_PAN1783_EVB_CPUAPP || BOARD_PAN1783A_EVB_CPUAPP || BOARD_PAN1783A_PA_EVB_CPUAPP config BOARD_ENABLE_DCDC_APP bool "Application MCU DCDC converter" @@ -35,6 +35,7 @@ config DOMAIN_CPUNET_BOARD string default "pan1783_evb_cpunet" if BOARD_PAN1783_EVB_CPUAPP default "pan1783a_evb_cpunet" if BOARD_PAN1783A_EVB_CPUAPP + default "pan1783a_pa_evb_cpunet" if BOARD_PAN1783A_PA_EVB_CPUAPP depends on BOARD_ENABLE_CPUNET help The board which will be used for CPUNET domain when creating a multi @@ -42,12 +43,13 @@ config DOMAIN_CPUNET_BOARD another board. For example hci_ipc on the nRF5340_cpunet for Bluetooth applications. -endif # BOARD_PAN1783_EVB_CPUAPP || BOARD_PAN1783A_EVB_CPUAPP +endif # BOARD_PAN1783_EVB_CPUAPP || BOARD_PAN1783A_EVB_CPUAPP || BOARD_PAN1783A_PA_EVB_CPUAPP config DOMAIN_CPUAPP_BOARD string default "pan1783_evb_cpuapp" if BOARD_PAN1783_EVB_CPUNET default "pan1783a_evb_cpuapp" if BOARD_PAN1783A_EVB_CPUNET + default "pan1783a_pa_evb_cpuapp" if BOARD_PAN1783A_PA_EVB_CPUNET help The board which will be used for CPUAPP domain when creating a multi image application where one or more images should be located on diff --git a/boards/arm/pan1783_pan1783a_evb/Kconfig.board b/boards/arm/pan1783/Kconfig.board similarity index 70% rename from boards/arm/pan1783_pan1783a_evb/Kconfig.board rename to boards/arm/pan1783/Kconfig.board index cfb5629b24c..3fcaaf39e56 100644 --- a/boards/arm/pan1783_pan1783a_evb/Kconfig.board +++ b/boards/arm/pan1783/Kconfig.board @@ -11,6 +11,10 @@ config BOARD_PAN1783A_EVB_CPUAPP bool "PAN1783A EVB (nRF5340) Application MCU" depends on SOC_NRF5340_CPUAPP_QKAA +config BOARD_PAN1783A_PA_EVB_CPUAPP + bool "PAN1783A-PA EVB (nRF5340) Application MCU" + depends on SOC_NRF5340_CPUAPP_QKAA + config BOARD_PAN1783_EVB_CPUNET bool "PAN1783 EVB (NRF5340) Network MCU" depends on SOC_NRF5340_CPUNET_QKAA @@ -18,3 +22,7 @@ config BOARD_PAN1783_EVB_CPUNET config BOARD_PAN1783A_EVB_CPUNET bool "PAN1783A EVB (NRF5340) Network MCU" depends on SOC_NRF5340_CPUNET_QKAA + +config BOARD_PAN1783A_PA_EVB_CPUNET + bool "PAN1783A-PA EVB (NRF5340) Network MCU" + depends on SOC_NRF5340_CPUNET_QKAA diff --git a/boards/arm/pan1783_pan1783a_evb/Kconfig.defconfig b/boards/arm/pan1783/Kconfig.defconfig similarity index 54% rename from boards/arm/pan1783_pan1783a_evb/Kconfig.defconfig rename to boards/arm/pan1783/Kconfig.defconfig index 34daddb0ea7..47c02a95b7f 100644 --- a/boards/arm/pan1783_pan1783a_evb/Kconfig.defconfig +++ b/boards/arm/pan1783/Kconfig.defconfig @@ -6,13 +6,15 @@ config BOARD default "pan1783_evb_cpuapp" if BOARD_PAN1783_EVB_CPUAPP default "pan1783a_evb_cpuapp" if BOARD_PAN1783A_EVB_CPUAPP + default "pan1783a_pa_evb_cpuapp" if BOARD_PAN1783A_PA_EVB_CPUAPP default "pan1783_evb_cpunet" if BOARD_PAN1783_EVB_CPUNET default "pan1783a_evb_cpunet" if BOARD_PAN1783A_EVB_CPUNET + default "pan1783a_pa_evb_cpunet" if BOARD_PAN1783A_PA_EVB_CPUNET config MBOX_NRFX_IPC default MBOX -if BOARD_PAN1783_EVB_CPUAPP || BOARD_PAN1783A_EVB_CPUAPP +if BOARD_PAN1783_EVB_CPUAPP || BOARD_PAN1783A_EVB_CPUAPP || BOARD_PAN1783A_PA_EVB_CPUAPP choice BT_HCI_BUS_TYPE default BT_HCI_IPC if BT @@ -22,11 +24,11 @@ config HEAP_MEM_POOL_ADD_SIZE_BOARD int default 4096 if BT_HCI_IPC -endif # BOARD_PAN1783_EVB_CPUAPP || BOARD_PAN1783A_EVB_CPUAPP +endif # BOARD_PAN1783_EVB_CPUAPP || BOARD_PAN1783A_EVB_CPUAPP || BOARD_PAN1783A_PA_EVB_CPUAPP -if BOARD_PAN1783_EVB_CPUNET || BOARD_PAN1783A_EVB_CPUNET +if BOARD_PAN1783_EVB_CPUNET || BOARD_PAN1783A_EVB_CPUNET || BOARD_PAN1783A_PA_EVB_CPUNET config BT_CTLR default y if BT -endif # BOARD_PAN1783_EVB_CPUNET || BOARD_PAN1783A_EVB_CPUNET +endif # BOARD_PAN1783_EVB_CPUNET || BOARD_PAN1783A_EVB_CPUNET || BOARD_PAN1783A_PA_EVB_CPUNET diff --git a/boards/arm/pan1783_pan1783a_evb/board.cmake b/boards/arm/pan1783/board.cmake similarity index 82% rename from boards/arm/pan1783_pan1783a_evb/board.cmake rename to boards/arm/pan1783/board.cmake index 5fe4b0507c7..e8a33e8c7bf 100644 --- a/boards/arm/pan1783_pan1783a_evb/board.cmake +++ b/boards/arm/pan1783/board.cmake @@ -1,10 +1,10 @@ # SPDX-License-Identifier: Apache-2.0 -if(CONFIG_BOARD_PAN1783_EVB_CPUAPP OR CONFIG_BOARD_PAN1783A_EVB_CPUAPP) +if(CONFIG_BOARD_PAN1783_EVB_CPUAPP OR CONFIG_BOARD_PAN1783A_EVB_CPUAPP OR CONFIG_BOARD_PAN1783A_PA_EVB_CPUAPP) board_runner_args(jlink "--device=nrf5340_xxaa_app" "--speed=4000") endif() -if(CONFIG_BOARD_PAN1783_EVB_CPUNET OR CONFIG_BOARD_PAN1783A_EVB_CPUNET) +if(CONFIG_BOARD_PAN1783_EVB_CPUNET OR CONFIG_BOARD_PAN1783A_EVB_CPUNET OR CONFIG_BOARD_PAN1783A_PA_EVB_CPUNET) board_runner_args(jlink "--device=nrf5340_xxaa_net" "--speed=4000") endif() diff --git a/boards/arm/pan1783/doc/img/pan1783_evb.webp b/boards/arm/pan1783/doc/img/pan1783_evb.webp new file mode 100644 index 0000000000000000000000000000000000000000..314252de2399ed2853958847b426f1dbe8bfdc63 GIT binary patch literal 42252 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"&#d89rF?bUTwn%Vjr-dKk4z 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 literal 0 HcmV?d00001 diff --git a/boards/arm/pan1783/doc/index.rst b/boards/arm/pan1783/doc/index.rst new file mode 100644 index 00000000000..95b8b94444b --- /dev/null +++ b/boards/arm/pan1783/doc/index.rst @@ -0,0 +1,73 @@ +.. _pan1783_evb: + +PAN1783, PAN1783A and PAN1783A-PA Evaluation Boards +################################################### + +Overview +******** + +The PAN1783, PAN1783A and PAN1783A-PA Evaluation Boards (pan1783_evb, +pan1783a_evb, pan1783a_pa_evb) are development tools for the PAN1783, +PAN1783A and PAN1783A-PA Modules which are based on the nRF5340 chipset +from Nordic Semiconductor. + +More information about the PAN1783, PAN1783A, PAN1783A-PA Modules and +Evaluation Boards can be found on the `product website`_. + +PAN1783 EVB +*********** + +.. figure:: img/pan1783_evb.webp + :align: center + :alt: PAN1783 EVB + + PAN1783 EVB (Credit: Panasonic) + +PAN1783A EVB +************ + +The PAN1783A EVB essentially looks like a PAN1783 EVB, except that it is +equipped with a UFL connector on X4. + +PAN1783A-PA EVB +*************** + +The PAN1783A-PA EVB essentially resembles a PAN1783 EVB, with the addition +of a UFL connector on X4 and a power amplifier. + +Usage +***** + +For detailed information, you can find the +`pan1783_evb user guide`_ / `pan1783a_evb user guide`_ / `pan1783a_pa_evb user guide`_ +for the Evaluation Boards in the `Panasonic Wireless Connectivity Development Hub`_. + +The User Guide contains (amongst other things) detailed information about + +* pin mapping +* powering options +* breakout pin header interface +* current consumption measurement +* software development + +The schematics for the PAN1783/PAN1783A/PAN1783A-PA Evaluation Boards are +available in the `download section PAN1783`_ / `download section PAN1783A`_ / `download section PAN1783A-PA`_ +of the `Panasonic Wireless Connectivity Development Hub`_. + +Programming and Debugging +************************* + +Please use the ``pan1783_evb_cpuapp``, ``pan1783a_evb_cpuapp`` or +``pan1783a_pa_evb_cpuapp`` for application core and ``pan1783_evb_cpunet``, +``pan1783a_evb_cpunet`` or ``pan1783a_pa_evb_cpunet`` board configuration +for network core when :ref:`build_an_application` and :ref:`application_run`. + +.. target-notes:: +.. _product website: https://industry.panasonic.eu/products/devices/wireless-connectivity/bluetooth-low-energy-modules +.. _Panasonic Wireless Connectivity Development Hub: https://pideu.panasonic.de/development-hub/ +.. _pan1783_evb user guide: https://pideu.panasonic.de/development-hub/pan1783/evaluation_board/user_guide/ +.. _pan1783a_evb user guide: https://pideu.panasonic.de/development-hub/pan1783a/evaluation_board/user_guide/ +.. _pan1783a_pa_evb user guide: https://pideu.panasonic.de/development-hub/pan1783a_pa/evaluation_board/user_guide/ +.. _download section PAN1783: https://pideu.panasonic.de/development-hub/pan1783/downloads/ +.. _download section PAN1783A: https://pideu.panasonic.de/development-hub/pan1783a/downloads/ +.. _download section PAN1783A-PA: https://pideu.panasonic.de/development-hub/pan1783a_pa/downloads/ diff --git a/boards/arm/pan1783_pan1783a_evb/pan1783_pan1783a_cpuapp_common-pinctrl.dtsi b/boards/arm/pan1783/pan1783_cpuapp_common-pinctrl.dtsi similarity index 100% rename from boards/arm/pan1783_pan1783a_evb/pan1783_pan1783a_cpuapp_common-pinctrl.dtsi rename to boards/arm/pan1783/pan1783_cpuapp_common-pinctrl.dtsi diff --git a/boards/arm/pan1783_pan1783a_evb/pan1783_pan1783a_cpuapp_common.dtsi b/boards/arm/pan1783/pan1783_cpuapp_common.dtsi similarity index 98% rename from boards/arm/pan1783_pan1783a_evb/pan1783_pan1783a_cpuapp_common.dtsi rename to boards/arm/pan1783/pan1783_cpuapp_common.dtsi index 82f49665338..77d093a5d40 100644 --- a/boards/arm/pan1783_pan1783a_evb/pan1783_pan1783a_cpuapp_common.dtsi +++ b/boards/arm/pan1783/pan1783_cpuapp_common.dtsi @@ -3,7 +3,7 @@ * * SPDX-License-Identifier: Apache-2.0 */ -#include "pan1783_pan1783a_cpuapp_common-pinctrl.dtsi" +#include "pan1783_cpuapp_common-pinctrl.dtsi" #include / { @@ -297,4 +297,4 @@ zephyr_udc0: &usbd { }; /* Include partition configuration file */ -#include "pan1783_pan1783a_cpuapp_partition_conf.dtsi" +#include "pan1783_cpuapp_partition_conf.dtsi" diff --git a/boards/arm/pan1783_pan1783a_evb/pan1783_pan1783a_cpuapp_partition_conf.dtsi b/boards/arm/pan1783/pan1783_cpuapp_partition_conf.dtsi similarity index 93% rename from boards/arm/pan1783_pan1783a_evb/pan1783_pan1783a_cpuapp_partition_conf.dtsi rename to boards/arm/pan1783/pan1783_cpuapp_partition_conf.dtsi index 0ddf9287c7e..6eb6792c996 100644 --- a/boards/arm/pan1783_pan1783a_evb/pan1783_pan1783a_cpuapp_partition_conf.dtsi +++ b/boards/arm/pan1783/pan1783_cpuapp_partition_conf.dtsi @@ -35,4 +35,4 @@ }; /* Include shared RAM configuration file */ -#include "pan1783_pan1783a_shared_sram_planning_conf.dtsi" +#include "pan1783_shared_sram_planning_conf.dtsi" diff --git a/boards/arm/pan1783_pan1783a_evb/pan1783_pan1783a_cpunet-pinctrl.dtsi b/boards/arm/pan1783/pan1783_cpunet-pinctrl.dtsi similarity index 100% rename from boards/arm/pan1783_pan1783a_evb/pan1783_pan1783a_cpunet-pinctrl.dtsi rename to boards/arm/pan1783/pan1783_cpunet-pinctrl.dtsi diff --git a/boards/arm/pan1783_pan1783a_evb/pan1783_pan1783a_cpunet_common.dtsi b/boards/arm/pan1783/pan1783_cpunet_common.dtsi similarity index 97% rename from boards/arm/pan1783_pan1783a_evb/pan1783_pan1783a_cpunet_common.dtsi rename to boards/arm/pan1783/pan1783_cpunet_common.dtsi index 8cd2d154e8e..5b5e7735e4a 100644 --- a/boards/arm/pan1783_pan1783a_evb/pan1783_pan1783a_cpunet_common.dtsi +++ b/boards/arm/pan1783/pan1783_cpunet_common.dtsi @@ -3,7 +3,7 @@ * * SPDX-License-Identifier: Apache-2.0 */ -#include "pan1783_pan1783a_cpunet-pinctrl.dtsi" +#include "pan1783_cpunet-pinctrl.dtsi" #include / { @@ -204,4 +204,4 @@ arduino_spi: &spi0 { }; /* Include shared RAM configuration file */ -#include "pan1783_pan1783a_shared_sram_planning_conf.dtsi" +#include "pan1783_shared_sram_planning_conf.dtsi" diff --git a/boards/arm/pan1783_pan1783a_evb/pan1783_pan1783a_evb_cpunet_reset.c b/boards/arm/pan1783/pan1783_cpunet_reset.c similarity index 90% rename from boards/arm/pan1783_pan1783a_evb/pan1783_pan1783a_evb_cpunet_reset.c rename to boards/arm/pan1783/pan1783_cpunet_reset.c index 0c957e0ed3b..529051ec629 100644 --- a/boards/arm/pan1783_pan1783a_evb/pan1783_pan1783a_evb_cpunet_reset.c +++ b/boards/arm/pan1783/pan1783_cpunet_reset.c @@ -15,6 +15,8 @@ LOG_MODULE_REGISTER(pan1783_evb_cpuapp, CONFIG_LOG_DEFAULT_LEVEL); #elif defined(CONFIG_BOARD_PAN1783A_EVB_CPUAPP) LOG_MODULE_REGISTER(pan1783a_evb_cpuapp, CONFIG_LOG_DEFAULT_LEVEL); +#elif defined(CONFIG_BOARD_PAN1783A_PA_EVB_CPUAPP) +LOG_MODULE_REGISTER(pan1783a_pa_evb_cpuapp, CONFIG_LOG_DEFAULT_LEVEL); #else #error "No board selected!" #endif diff --git a/boards/arm/pan1783_pan1783a_evb/pan1783_evb_cpuapp.dts b/boards/arm/pan1783/pan1783_evb_cpuapp.dts similarity index 90% rename from boards/arm/pan1783_pan1783a_evb/pan1783_evb_cpuapp.dts rename to boards/arm/pan1783/pan1783_evb_cpuapp.dts index b65858f89fa..54f71dd87d5 100644 --- a/boards/arm/pan1783_pan1783a_evb/pan1783_evb_cpuapp.dts +++ b/boards/arm/pan1783/pan1783_evb_cpuapp.dts @@ -6,7 +6,7 @@ /dts-v1/; #include -#include "pan1783_pan1783a_cpuapp_common.dtsi" +#include "pan1783_cpuapp_common.dtsi" / { model = "Panasonic PAN1783 EVB (NRF5340) Application"; diff --git a/boards/arm/pan1783_pan1783a_evb/pan1783_evb_cpuapp.yaml b/boards/arm/pan1783/pan1783_evb_cpuapp.yaml similarity index 100% rename from boards/arm/pan1783_pan1783a_evb/pan1783_evb_cpuapp.yaml rename to boards/arm/pan1783/pan1783_evb_cpuapp.yaml diff --git a/boards/arm/pan1783_pan1783a_evb/pan1783_evb_cpuapp_defconfig b/boards/arm/pan1783/pan1783_evb_cpuapp_defconfig similarity index 100% rename from boards/arm/pan1783_pan1783a_evb/pan1783_evb_cpuapp_defconfig rename to boards/arm/pan1783/pan1783_evb_cpuapp_defconfig diff --git a/boards/arm/pan1783_pan1783a_evb/pan1783_evb_cpunet.dts b/boards/arm/pan1783/pan1783_evb_cpunet.dts similarity index 80% rename from boards/arm/pan1783_pan1783a_evb/pan1783_evb_cpunet.dts rename to boards/arm/pan1783/pan1783_evb_cpunet.dts index bd84c622126..7063e53af46 100644 --- a/boards/arm/pan1783_pan1783a_evb/pan1783_evb_cpunet.dts +++ b/boards/arm/pan1783/pan1783_evb_cpunet.dts @@ -6,7 +6,7 @@ /dts-v1/; #include -#include "pan1783_pan1783a_cpunet_common.dtsi" +#include "pan1783_cpunet_common.dtsi" / { model = "Panasonic PAN1783 EVB (NRF5340) Network"; @@ -20,4 +20,4 @@ }; /* Include shared RAM configuration file */ -#include "pan1783_pan1783a_shared_sram_planning_conf.dtsi" +#include "pan1783_shared_sram_planning_conf.dtsi" diff --git a/boards/arm/pan1783_pan1783a_evb/pan1783_evb_cpunet.yaml b/boards/arm/pan1783/pan1783_evb_cpunet.yaml similarity index 100% rename from boards/arm/pan1783_pan1783a_evb/pan1783_evb_cpunet.yaml rename to boards/arm/pan1783/pan1783_evb_cpunet.yaml diff --git a/boards/arm/pan1783_pan1783a_evb/pan1783_evb_cpunet_defconfig b/boards/arm/pan1783/pan1783_evb_cpunet_defconfig similarity index 100% rename from boards/arm/pan1783_pan1783a_evb/pan1783_evb_cpunet_defconfig rename to boards/arm/pan1783/pan1783_evb_cpunet_defconfig diff --git a/boards/arm/pan1783_pan1783a_evb/pan1783_pan1783a_shared_sram_planning_conf.dtsi b/boards/arm/pan1783/pan1783_shared_sram_planning_conf.dtsi similarity index 100% rename from boards/arm/pan1783_pan1783a_evb/pan1783_pan1783a_shared_sram_planning_conf.dtsi rename to boards/arm/pan1783/pan1783_shared_sram_planning_conf.dtsi diff --git a/boards/arm/pan1783_pan1783a_evb/pan1783a_evb_cpuapp.dts b/boards/arm/pan1783/pan1783a_evb_cpuapp.dts similarity index 90% rename from boards/arm/pan1783_pan1783a_evb/pan1783a_evb_cpuapp.dts rename to boards/arm/pan1783/pan1783a_evb_cpuapp.dts index dc3ff1357e4..29f0dcb796c 100644 --- a/boards/arm/pan1783_pan1783a_evb/pan1783a_evb_cpuapp.dts +++ b/boards/arm/pan1783/pan1783a_evb_cpuapp.dts @@ -6,7 +6,7 @@ /dts-v1/; #include -#include "pan1783_pan1783a_cpuapp_common.dtsi" +#include "pan1783_cpuapp_common.dtsi" / { model = "Panasonic PAN1783A EVB (NRF5340) Application"; diff --git a/boards/arm/pan1783_pan1783a_evb/pan1783a_evb_cpuapp.yaml b/boards/arm/pan1783/pan1783a_evb_cpuapp.yaml similarity index 100% rename from boards/arm/pan1783_pan1783a_evb/pan1783a_evb_cpuapp.yaml rename to boards/arm/pan1783/pan1783a_evb_cpuapp.yaml diff --git a/boards/arm/pan1783_pan1783a_evb/pan1783a_evb_cpuapp_defconfig b/boards/arm/pan1783/pan1783a_evb_cpuapp_defconfig similarity index 100% rename from boards/arm/pan1783_pan1783a_evb/pan1783a_evb_cpuapp_defconfig rename to boards/arm/pan1783/pan1783a_evb_cpuapp_defconfig diff --git a/boards/arm/pan1783_pan1783a_evb/pan1783a_evb_cpunet.dts b/boards/arm/pan1783/pan1783a_evb_cpunet.dts similarity index 80% rename from boards/arm/pan1783_pan1783a_evb/pan1783a_evb_cpunet.dts rename to boards/arm/pan1783/pan1783a_evb_cpunet.dts index 8be0b5966a8..9cd0409a432 100644 --- a/boards/arm/pan1783_pan1783a_evb/pan1783a_evb_cpunet.dts +++ b/boards/arm/pan1783/pan1783a_evb_cpunet.dts @@ -6,7 +6,7 @@ /dts-v1/; #include -#include "pan1783_pan1783a_cpunet_common.dtsi" +#include "pan1783_cpunet_common.dtsi" / { model = "Panasonic PAN1783A EVB (NRF5340) Network"; @@ -20,4 +20,4 @@ }; /* Include shared RAM configuration file */ -#include "pan1783_pan1783a_shared_sram_planning_conf.dtsi" +#include "pan1783_shared_sram_planning_conf.dtsi" diff --git a/boards/arm/pan1783_pan1783a_evb/pan1783a_evb_cpunet.yaml b/boards/arm/pan1783/pan1783a_evb_cpunet.yaml similarity index 100% rename from boards/arm/pan1783_pan1783a_evb/pan1783a_evb_cpunet.yaml rename to boards/arm/pan1783/pan1783a_evb_cpunet.yaml diff --git a/boards/arm/pan1783_pan1783a_evb/pan1783a_evb_cpunet_defconfig b/boards/arm/pan1783/pan1783a_evb_cpunet_defconfig similarity index 100% rename from boards/arm/pan1783_pan1783a_evb/pan1783a_evb_cpunet_defconfig rename to boards/arm/pan1783/pan1783a_evb_cpunet_defconfig diff --git a/boards/arm/pan1783/pan1783a_pa_evb_cpuapp.dts b/boards/arm/pan1783/pan1783a_pa_evb_cpuapp.dts new file mode 100644 index 00000000000..aba6e9281e2 --- /dev/null +++ b/boards/arm/pan1783/pan1783a_pa_evb_cpuapp.dts @@ -0,0 +1,30 @@ +/* + * Copyright (c) 2023 Panasonic Industrial Devices Europe GmbH + * + * SPDX-License-Identifier: Apache-2.0 + */ + +/dts-v1/; +#include +#include "pan1783_cpuapp_common.dtsi" + +/ { + model = "Panasonic PAN1783A-PA EVB (NRF5340) Application"; + compatible = "panasonic,pan1783a_pa-evb-cpuapp"; + + chosen { + zephyr,sram = &sram0_image; + zephyr,flash = &flash0; + zephyr,code-partition = &slot0_partition; + zephyr,sram-secure-partition = &sram0_s; + }; +}; + +&gpio_fwd { + /delete-node/ uart; + + status = "okay"; + fem { + gpios = <&gpio0 19 0>, <&gpio0 21 0>; + }; +}; diff --git a/boards/arm/pan1783/pan1783a_pa_evb_cpuapp.yaml b/boards/arm/pan1783/pan1783a_pa_evb_cpuapp.yaml new file mode 100644 index 00000000000..0bc70dab273 --- /dev/null +++ b/boards/arm/pan1783/pan1783a_pa_evb_cpuapp.yaml @@ -0,0 +1,21 @@ +identifier: pan1783a_pa_evb_cpuapp +name: PAN1783A-PA-EVB-application-MCU +type: mcu +arch: arm +toolchain: + - gnuarmemb + - xtools + - zephyr +ram: 448 +flash: 1024 +supported: + - gpio + - i2c + - i2s + - pwm + - watchdog + - usb_cdc + - usb_device + - netif:openthread + - gpio +vendor: panasonic diff --git a/boards/arm/pan1783/pan1783a_pa_evb_cpuapp_defconfig b/boards/arm/pan1783/pan1783a_pa_evb_cpuapp_defconfig new file mode 100644 index 00000000000..f58bdce8bfc --- /dev/null +++ b/boards/arm/pan1783/pan1783a_pa_evb_cpuapp_defconfig @@ -0,0 +1,25 @@ +# SPDX-License-Identifier: Apache-2.0 + +CONFIG_SOC_SERIES_NRF53X=y +CONFIG_SOC_NRF5340_CPUAPP_QKAA=y +CONFIG_BOARD_PAN1783A_PA_EVB_CPUAPP=y + +# Enable MPU +CONFIG_ARM_MPU=y + +# Enable hardware stack protection +CONFIG_HW_STACK_PROTECTION=y + +# enable GPIO +CONFIG_GPIO=y + +# Enable uart driver +CONFIG_SERIAL=y + +# enable console +CONFIG_CONSOLE=y +CONFIG_UART_CONSOLE=y + +# clock config +CONFIG_CLOCK_CONTROL_NRF_K32SRC_RC=y +CONFIG_CLOCK_CONTROL_NRF_K32SRC_XTAL=n diff --git a/boards/arm/pan1783/pan1783a_pa_evb_cpunet.dts b/boards/arm/pan1783/pan1783a_pa_evb_cpunet.dts new file mode 100644 index 00000000000..1b345aaa945 --- /dev/null +++ b/boards/arm/pan1783/pan1783a_pa_evb_cpunet.dts @@ -0,0 +1,33 @@ +/* + * Copyright (c) 2023 Panasonic Industrial Devices Europe GmbH + * + * SPDX-License-Identifier: Apache-2.0 + */ + +/dts-v1/; +#include +#include "pan1783_cpunet_common.dtsi" + +/ { + model = "Panasonic PAN1783A-PA EVB (NRF5340) Network"; + compatible = "panasonic,pan1783a_pa-evb-cpunet"; + + chosen { + zephyr,sram = &sram1; + zephyr,flash = &flash1; + zephyr,code-partition = &slot0_partition; + }; + + nrf_radio_fem: fem_node { + compatible = "skyworks,sky66407-11", "generic-fem-two-ctrl-pins"; + ctx-gpios = <&gpio0 19 GPIO_ACTIVE_HIGH>; + crx-gpios = <&gpio0 21 GPIO_ACTIVE_HIGH>; + }; +}; + +&radio { + fem = <&nrf_radio_fem>; +}; + +/* Include shared RAM configuration file */ +#include "pan1783_shared_sram_planning_conf.dtsi" diff --git a/boards/arm/pan1783/pan1783a_pa_evb_cpunet.yaml b/boards/arm/pan1783/pan1783a_pa_evb_cpunet.yaml new file mode 100644 index 00000000000..98a2f2908de --- /dev/null +++ b/boards/arm/pan1783/pan1783a_pa_evb_cpunet.yaml @@ -0,0 +1,14 @@ +identifier: pan1783a_pa_evb_cpunet +name: PAN1783A-PA-EVB-network-MCU +type: mcu +arch: arm +toolchain: + - gnuarmemb + - xtools + - zephyr +ram: 64 +flash: 256 +supported: + - watchdog + - gpio +vendor: panasonic diff --git a/boards/arm/pan1783/pan1783a_pa_evb_cpunet_defconfig b/boards/arm/pan1783/pan1783a_pa_evb_cpunet_defconfig new file mode 100644 index 00000000000..3ba18cd433a --- /dev/null +++ b/boards/arm/pan1783/pan1783a_pa_evb_cpunet_defconfig @@ -0,0 +1,18 @@ +# SPDX-License-Identifier: Apache-2.0 + +CONFIG_SOC_SERIES_NRF53X=y +CONFIG_SOC_NRF5340_CPUNET_QKAA=y +CONFIG_BOARD_PAN1783A_PA_EVB_CPUNET=y + +# Enable MPU +CONFIG_ARM_MPU=y + +# Enable hardware stack protection +CONFIG_HW_STACK_PROTECTION=y + +# enable GPIO +CONFIG_GPIO=y + +# clock config +CONFIG_CLOCK_CONTROL_NRF_K32SRC_RC=y +CONFIG_CLOCK_CONTROL_NRF_K32SRC_XTAL=n diff --git a/boards/arm/pan1783_pan1783a_evb/pre_dt_board.cmake b/boards/arm/pan1783/pre_dt_board.cmake similarity index 100% rename from boards/arm/pan1783_pan1783a_evb/pre_dt_board.cmake rename to boards/arm/pan1783/pre_dt_board.cmake diff --git a/boards/arm/pan1783_pan1783a_evb/doc/img/pan1783_evb.jpg b/boards/arm/pan1783_pan1783a_evb/doc/img/pan1783_evb.jpg deleted file mode 100644 index 273253cfcf95df400908654c03accc1f7336bc33..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 57564 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

q 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 Date: Tue, 19 Dec 2023 10:28:11 +0000 Subject: [PATCH 1826/3723] maintainers: Added Panasonic boards to the MAINTAINERS.yml file Added maintainer for the pan17*_evb evaluation boards. Signed-off-by: Steffen Jahnke --- MAINTAINERS.yml | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/MAINTAINERS.yml b/MAINTAINERS.yml index 8b1a9075d4a..92782837327 100644 --- a/MAINTAINERS.yml +++ b/MAINTAINERS.yml @@ -3474,6 +3474,15 @@ Infineon Platforms: Infineon SOCs, dts files and related drivers. Infineon Proto, Pioneer, Eval and Relax boards. +Panasonic Platforms: + status: maintained + maintainers: + - pideu-sj + files: + - boards/arm/pan17*/ + labels: + - "platform: Panasonic" + RTIO: status: maintained maintainers: From 2f515d26f227c98371ab298b12604339ff9b0474 Mon Sep 17 00:00:00 2001 From: Yong Cong Sin Date: Sat, 23 Dec 2023 17:32:16 +0800 Subject: [PATCH 1827/3723] dts: bindings: vendor-prefixes: add renode prefix Add renode binding prefix. Signed-off-by: Yong Cong Sin --- 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 4096d5cad0d..231fa50da0f 100644 --- a/dts/bindings/vendor-prefixes.txt +++ b/dts/bindings/vendor-prefixes.txt @@ -512,6 +512,7 @@ rda Unisoc Communications, Inc. realtek Realtek Semiconductor Corp. remarkable reMarkable AS renesas Renesas Electronics Corporation +renode Antmicro's open source simulation and virtual development framework rex iMX6 Rex Project rervision Shenzhen Rervision Technology Co., Ltd. revotics Revolution Robotics, Inc. (Revotics) From d0a3a50fbea53471af230a9c5d6aee4ff8a6e2a1 Mon Sep 17 00:00:00 2001 From: Yong Cong Sin Date: Sat, 23 Dec 2023 17:32:56 +0800 Subject: [PATCH 1828/3723] dts: riscv: add a SoC dtsi for Renode RISC-V Virt SoC RISCV32 simulation dtsi for Renode. Signed-off-by: Yong Cong Sin --- dts/riscv/renode_riscv32_virt.dtsi | 97 ++++++++++++++++++++++++++++++ 1 file changed, 97 insertions(+) create mode 100644 dts/riscv/renode_riscv32_virt.dtsi diff --git a/dts/riscv/renode_riscv32_virt.dtsi b/dts/riscv/renode_riscv32_virt.dtsi new file mode 100644 index 00000000000..a0db375501f --- /dev/null +++ b/dts/riscv/renode_riscv32_virt.dtsi @@ -0,0 +1,97 @@ +/* + * Copyright (c) 2023 Meta + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include + +/ { + #address-cells = <1>; + #size-cells = <1>; + + cpus { + #address-cells = <1>; + #size-cells = <0>; + cpu@0 { + clock-frequency = <0>; + compatible = "renode,virt", "riscv"; + device_type = "cpu"; + reg = <0>; + riscv,isa = "rv32imac_zicsr_zifencei"; + hlic: interrupt-controller { + compatible = "riscv,cpu-intc"; + #address-cells = <0>; + #interrupt-cells = <1>; + interrupt-controller; + }; + }; + }; + + soc { + #address-cells = <1>; + #size-cells = <1>; + compatible = "renode,virt-soc", "simple-bus"; + ranges; + + flash0: flash@80000000 { + compatible = "soc-nv-flash"; + reg = <0x80000000 DT_SIZE_M(4)>; + }; + + sram0: memory@80400000 { + compatible = "mmio-sram"; + reg = <0x80400000 DT_SIZE_M(4)>; + }; + + clint: clint@2000000 { + compatible = "sifive,clint0"; + interrupts-extended = <&hlic 3>, <&hlic 7>; + reg = <0x2000000 0x10000>; + }; + + plic0: interrupt-controller@c000000 { + compatible = "sifive,plic-1.0.0"; + #address-cells = <0>; + #interrupt-cells = <2>; + interrupt-controller; + interrupts-extended = <&hlic 11>; + reg = <0xc000000 0x04000000>; + riscv,max-priority = <1>; + riscv,ndev = <1023>; + }; + + plic1: interrupt-controller@8000000 { + compatible = "sifive,plic-1.0.0"; + #address-cells = <0>; + #interrupt-cells = <2>; + interrupt-controller; + interrupts-extended = <&hlic 4>; + reg = <0x8000000 0x04000000>; + riscv,max-priority = <1>; + riscv,ndev = <1023>; + }; + + uart0: uart@10000000 { + interrupts = < 0x0a 1 >; + interrupt-parent = < &plic0 >; + clock-frequency = <150000000>; + current-speed = <115200>; + reg = < 0x10000000 0x100 >; + compatible = "ns16550"; + reg-shift = < 0 >; + status = "disabled"; + }; + + uart1: uart@10000100 { + interrupts = < 0x0a 1 >; + interrupt-parent = < &plic1 >; + clock-frequency = <150000000>; + current-speed = <115200>; + reg = < 0x10000100 0x100 >; + compatible = "ns16550"; + reg-shift = < 0 >; + status = "disabled"; + }; + }; +}; From c328a38a94962cc64325b525fad8013331291e35 Mon Sep 17 00:00:00 2001 From: Yong Cong Sin Date: Sat, 23 Dec 2023 17:35:24 +0800 Subject: [PATCH 1829/3723] soc: riscv: add support for Renode Virt RISCV32 SoC Add a beef-ed up version of Renode's `riscv_virt` SoC Signed-off-by: Yong Cong Sin --- .../renode_virt/CMakeLists.txt | 6 +++ .../renode_virt/Kconfig.defconfig.series | 48 +++++++++++++++++++ .../renode_virt/Kconfig.series | 9 ++++ .../riscv-privileged/renode_virt/Kconfig.soc | 19 ++++++++ soc/riscv/riscv-privileged/renode_virt/soc.h | 12 +++++ 5 files changed, 94 insertions(+) create mode 100644 soc/riscv/riscv-privileged/renode_virt/CMakeLists.txt create mode 100644 soc/riscv/riscv-privileged/renode_virt/Kconfig.defconfig.series create mode 100644 soc/riscv/riscv-privileged/renode_virt/Kconfig.series create mode 100644 soc/riscv/riscv-privileged/renode_virt/Kconfig.soc create mode 100644 soc/riscv/riscv-privileged/renode_virt/soc.h diff --git a/soc/riscv/riscv-privileged/renode_virt/CMakeLists.txt b/soc/riscv/riscv-privileged/renode_virt/CMakeLists.txt new file mode 100644 index 00000000000..56d36b84ec8 --- /dev/null +++ b/soc/riscv/riscv-privileged/renode_virt/CMakeLists.txt @@ -0,0 +1,6 @@ +# Copyright (c) 2023 Meta +# SPDX-License-Identifier: Apache-2.0 + +zephyr_sources() + +set(SOC_LINKER_SCRIPT ${ZEPHYR_BASE}/include/zephyr/arch/riscv/common/linker.ld CACHE INTERNAL "") diff --git a/soc/riscv/riscv-privileged/renode_virt/Kconfig.defconfig.series b/soc/riscv/riscv-privileged/renode_virt/Kconfig.defconfig.series new file mode 100644 index 00000000000..09adc3d00e8 --- /dev/null +++ b/soc/riscv/riscv-privileged/renode_virt/Kconfig.defconfig.series @@ -0,0 +1,48 @@ +# Copyright (c) 2023 Meta +# SPDX-License-Identifier: Apache-2.0 + +if SOC_SERIES_RISCV32_VIRTUAL_RENODE + +config SOC_SERIES + default "renode_virt" + +config SYS_CLOCK_HW_CYCLES_PER_SEC + default 4000000 + +config RISCV_SOC_INTERRUPT_INIT + default y + +config RISCV_HAS_CPU_IDLE + default y + +config RISCV_HAS_PLIC + default y + +config RISCV_GP + default y + +config 1ST_LEVEL_INTERRUPT_BITS + default 4 + +config NUM_2ND_LEVEL_AGGREGATORS + default 2 + +config 2ND_LEVEL_INTERRUPT_BITS + default 11 + +config 2ND_LVL_ISR_TBL_OFFSET + default 12 + +config 2ND_LVL_INTR_00_OFFSET + default 11 + +config 2ND_LVL_INTR_01_OFFSET + default 4 + +config MAX_IRQ_PER_AGGREGATOR + default 1023 + +config NUM_IRQS + default 2058 + +endif # SOC_SERIES_RISCV32_VIRTUAL_RENODE diff --git a/soc/riscv/riscv-privileged/renode_virt/Kconfig.series b/soc/riscv/riscv-privileged/renode_virt/Kconfig.series new file mode 100644 index 00000000000..22e27cf38b4 --- /dev/null +++ b/soc/riscv/riscv-privileged/renode_virt/Kconfig.series @@ -0,0 +1,9 @@ +# Copyright (c) 2023 Meta +# SPDX-License-Identifier: Apache-2.0 + +config SOC_SERIES_RISCV32_VIRTUAL_RENODE + bool "Renode RISC-V32 Virtual SoC implementation" + select RISCV + select SOC_FAMILY_RISCV_PRIVILEGED + help + Enable support for Renode RISC-V Virtual diff --git a/soc/riscv/riscv-privileged/renode_virt/Kconfig.soc b/soc/riscv/riscv-privileged/renode_virt/Kconfig.soc new file mode 100644 index 00000000000..d123e797229 --- /dev/null +++ b/soc/riscv/riscv-privileged/renode_virt/Kconfig.soc @@ -0,0 +1,19 @@ +# Copyright (c) 2023 Meta +# SPDX-License-Identifier: Apache-2.0 + +choice + prompt "Renode RISCV32 Virtual system implementation" + depends on SOC_SERIES_RISCV32_VIRTUAL_RENODE + +config SOC_RISCV32_VIRTUAL_RENODE + bool "Renode RISCV32 Virtual system implementation" + select ATOMIC_OPERATIONS_BUILTIN + select INCLUDE_RESET_VECTOR + select RISCV_ISA_RV32I + select RISCV_ISA_EXT_M + select RISCV_ISA_EXT_A + select RISCV_ISA_EXT_C + select RISCV_ISA_EXT_ZICSR + select RISCV_ISA_EXT_ZIFENCEI + +endchoice diff --git a/soc/riscv/riscv-privileged/renode_virt/soc.h b/soc/riscv/riscv-privileged/renode_virt/soc.h new file mode 100644 index 00000000000..c82e16f1613 --- /dev/null +++ b/soc/riscv/riscv-privileged/renode_virt/soc.h @@ -0,0 +1,12 @@ +/* + * Copyright (c) 2023 Meta + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#ifndef __RISCV32_RENODE_SOC_H_ +#define __RISCV32_RENODE_SOC_H_ + +#include + +#endif /* __RISCV32_RENODE_SOC_H_ */ From 7fac758bdb33ad893af25cc27126da0a5bee3e9c Mon Sep 17 00:00:00 2001 From: Yong Cong Sin Date: Sat, 23 Dec 2023 17:36:07 +0800 Subject: [PATCH 1830/3723] boards: riscv: add RISCV32 Virtual board made with Renode The RISCV32 Virtual board is a virtual platform made with Renode as an alternative to QEMU. Contrary to QEMU, the peripherals of this platform can be easily configured by editing the `riscv32_virtual.repl` script and the devicetree files accordingly, this allows certain hardware configurations that only exist in proprietary boards/SoCs to be tested in upstream CI. Added another entry for this board to the excluded platform in `kernel.timer.timer` test. Signed-off-by: Yong Cong Sin --- boards/riscv/riscv32_virtual/Kconfig.board | 6 ++ .../riscv/riscv32_virtual/Kconfig.defconfig | 6 ++ boards/riscv/riscv32_virtual/board.cmake | 6 ++ boards/riscv/riscv32_virtual/doc/index.rst | 56 +++++++++++++++++++ .../riscv/riscv32_virtual/riscv32_virtual.dts | 25 +++++++++ .../riscv32_virtual/riscv32_virtual.yaml | 16 ++++++ .../riscv32_virtual/riscv32_virtual_defconfig | 14 +++++ .../support/riscv32_virtual.repl | 33 +++++++++++ .../support/riscv32_virtual.resc | 17 ++++++ 9 files changed, 179 insertions(+) create mode 100644 boards/riscv/riscv32_virtual/Kconfig.board create mode 100644 boards/riscv/riscv32_virtual/Kconfig.defconfig create mode 100644 boards/riscv/riscv32_virtual/board.cmake create mode 100644 boards/riscv/riscv32_virtual/doc/index.rst create mode 100644 boards/riscv/riscv32_virtual/riscv32_virtual.dts create mode 100644 boards/riscv/riscv32_virtual/riscv32_virtual.yaml create mode 100644 boards/riscv/riscv32_virtual/riscv32_virtual_defconfig create mode 100644 boards/riscv/riscv32_virtual/support/riscv32_virtual.repl create mode 100644 boards/riscv/riscv32_virtual/support/riscv32_virtual.resc diff --git a/boards/riscv/riscv32_virtual/Kconfig.board b/boards/riscv/riscv32_virtual/Kconfig.board new file mode 100644 index 00000000000..c8722acb384 --- /dev/null +++ b/boards/riscv/riscv32_virtual/Kconfig.board @@ -0,0 +1,6 @@ +# Copyright (c) 2023 Meta +# SPDX-License-Identifier: Apache-2.0 + +config BOARD_RISCV32_VIRTUAL + bool "riscv32_virtual" + depends on SOC_RISCV32_VIRTUAL_RENODE diff --git a/boards/riscv/riscv32_virtual/Kconfig.defconfig b/boards/riscv/riscv32_virtual/Kconfig.defconfig new file mode 100644 index 00000000000..840b10fd594 --- /dev/null +++ b/boards/riscv/riscv32_virtual/Kconfig.defconfig @@ -0,0 +1,6 @@ +# Copyright (c) 2023 Meta +# SPDX-License-Identifier: Apache-2.0 + +config BOARD + default "riscv32_virtual" + depends on BOARD_RISCV32_VIRTUAL diff --git a/boards/riscv/riscv32_virtual/board.cmake b/boards/riscv/riscv32_virtual/board.cmake new file mode 100644 index 00000000000..cc177a69ce9 --- /dev/null +++ b/boards/riscv/riscv32_virtual/board.cmake @@ -0,0 +1,6 @@ +# Copyright (c) 2023 Meta +# SPDX-License-Identifier: Apache-2.0 + +set(SUPPORTED_EMU_PLATFORMS renode) +set(RENODE_SCRIPT ${CMAKE_CURRENT_LIST_DIR}/support/riscv32_virtual.resc) +set(RENODE_UART sysbus.uart0) diff --git a/boards/riscv/riscv32_virtual/doc/index.rst b/boards/riscv/riscv32_virtual/doc/index.rst new file mode 100644 index 00000000000..a53384f5331 --- /dev/null +++ b/boards/riscv/riscv32_virtual/doc/index.rst @@ -0,0 +1,56 @@ +.. _riscv32-virtual: + +RISCV32 Virtual +############### + +Overview +******** + +The RISCV32 Virtual board is a virtual platform made with Renode as an alternative to QEMU. +Contrary to QEMU, the peripherals of this platform can be easily configured by editing the +``riscv32_virtual.repl`` script and the devicetree files accordingly, this allows certain hardware +configurations that only exist in proprietary boards/SoCs to be tested in upstream CI. + +Programming and debugging +************************* + +Building +======== + +Applications for the ``riscv32_virtual`` board configuration can be built as usual +(see :ref:`build_an_application`): + +.. zephyr-app-commands:: + :board: riscv32_virtual + :goals: build + +Flashing +======== + +While this board is emulated and you can't "flash" it, you can use this +configuration to run basic Zephyr applications and kernel tests in the Renode +emulated environment. For example, with the :zephyr:code-sample:`synchronization` sample: + +.. zephyr-app-commands:: + :zephyr-app: samples/synchronization + :host-os: unix + :board: riscv32_virtual + :goals: run + +This will build an image with the synchronization sample app, boot it using +Renode, and display the following console output: + +.. code-block:: console + + *** Booting Zephyr OS build zephyr-v3.5.0-1511-g56f73bde0fb0 *** + thread_a: Hello World from cpu 0 on riscv32_virtual! + thread_b: Hello World from cpu 0 on riscv32_virtual! + thread_a: Hello World from cpu 0 on riscv32_virtual! + thread_b: Hello World from cpu 0 on riscv32_virtual! + +Exit Renode by pressing :kbd:`CTRL+C`. + +Debugging +========= + +Refer to the detailed overview about :ref:`application_debugging`. diff --git a/boards/riscv/riscv32_virtual/riscv32_virtual.dts b/boards/riscv/riscv32_virtual/riscv32_virtual.dts new file mode 100644 index 00000000000..326b9757518 --- /dev/null +++ b/boards/riscv/riscv32_virtual/riscv32_virtual.dts @@ -0,0 +1,25 @@ +/* + * Copyright (c) 2023 Meta + * + * SPDX-License-Identifier: Apache-2.0 + */ + +/dts-v1/; + +#include + +/ { + model = "Renode RISCV32 Virtual target"; + compatible = "renode,riscv32-virtual"; + + chosen { + zephyr,console = &uart0; + zephyr,shell-uart = &uart0; + zephyr,flash = &flash0; + zephyr,sram = &sram0; + }; +}; + +&uart0 { + status = "okay"; +}; diff --git a/boards/riscv/riscv32_virtual/riscv32_virtual.yaml b/boards/riscv/riscv32_virtual/riscv32_virtual.yaml new file mode 100644 index 00000000000..11cefb035df --- /dev/null +++ b/boards/riscv/riscv32_virtual/riscv32_virtual.yaml @@ -0,0 +1,16 @@ +identifier: riscv32_virtual +name: Renode RISC-V 32-bit Virtual Board +type: mcu +arch: riscv32 +toolchain: + - zephyr +ram: 4096 +flash: 4096 +simulation: renode +simulation_exec: renode +testing: + ignore_tags: + - net + - bluetooth +supported: + - uart diff --git a/boards/riscv/riscv32_virtual/riscv32_virtual_defconfig b/boards/riscv/riscv32_virtual/riscv32_virtual_defconfig new file mode 100644 index 00000000000..a905f99da2e --- /dev/null +++ b/boards/riscv/riscv32_virtual/riscv32_virtual_defconfig @@ -0,0 +1,14 @@ +# Copyright (c) 2023 Meta +# SPDX-License-Identifier: Apache-2.0 + +CONFIG_SOC_SERIES_RISCV32_VIRTUAL_RENODE=y +CONFIG_SOC_RISCV32_VIRTUAL_RENODE=y +CONFIG_BOARD_RISCV32_VIRTUAL=y +CONFIG_CONSOLE=y +CONFIG_SERIAL=y +CONFIG_UART_CONSOLE=y +CONFIG_GPIO=n +CONFIG_XIP=y + +# Workaround for incorrect SYS_CLOCK_HW_CYCLES_PER_SEC +CONFIG_SYS_CLOCK_TICKS_PER_SEC=100 diff --git a/boards/riscv/riscv32_virtual/support/riscv32_virtual.repl b/boards/riscv/riscv32_virtual/support/riscv32_virtual.repl new file mode 100644 index 00000000000..e0df808631b --- /dev/null +++ b/boards/riscv/riscv32_virtual/support/riscv32_virtual.repl @@ -0,0 +1,33 @@ +// Copyright (c) 2023 Meta +// SPDX-License-Identifier: Apache-2.0 + +flash: Memory.MappedMemory @ sysbus 0x80000000 + size: 0x400000 + +ddr: Memory.MappedMemory @ sysbus 0x80400000 + size: 0x400000 + +uart0: UART.NS16550 @ sysbus 0x10000000 + IRQ -> plic0@10 + +uart1: UART.NS16550 @ sysbus 0x10000100 + IRQ -> plic1@10 + +cpu: CPU.RiscV32 @ sysbus + cpuType: "rv32imac_zicsr_zifencei" + privilegeArchitecture: PrivilegeArchitecture.Priv1_10 + timeProvider: clint + +plic0: IRQControllers.PlatformLevelInterruptController @ sysbus 0x0C000000 + 0 -> cpu@11 + numberOfSources: 1023 + numberOfContexts: 1 + +plic1: IRQControllers.PlatformLevelInterruptController @ sysbus 0x08000000 + 0 -> cpu@4 + numberOfSources: 1023 + numberOfContexts: 1 + +clint: IRQControllers.CoreLevelInterruptor @ sysbus 0x02000000 + [0,1] -> cpu@[3,7] + frequency: 4000000 diff --git a/boards/riscv/riscv32_virtual/support/riscv32_virtual.resc b/boards/riscv/riscv32_virtual/support/riscv32_virtual.resc new file mode 100644 index 00000000000..87e327287b6 --- /dev/null +++ b/boards/riscv/riscv32_virtual/support/riscv32_virtual.resc @@ -0,0 +1,17 @@ +:name: RISCV32-Virtual +:description: This script is prepared to run Zephyr on a Renode RISCV32 board. + +$name?="RISCV32-Virtual" + +using sysbus +mach create $name +machine LoadPlatformDescription $ORIGIN/riscv32_virtual.repl + +showAnalyzer uart0 +cpu PerformanceInMips 4 + +macro reset +""" + sysbus LoadELF $bin +""" +runMacro $reset From 310c4539e96d54aeef7c811d50fa5b2029dff8dc Mon Sep 17 00:00:00 2001 From: Yong Cong Sin Date: Thu, 4 Jan 2024 21:51:32 +0800 Subject: [PATCH 1831/3723] drivers: intc: plic: fix compilation warning Change the index variable type to `int` from `size_t` to compile across 32bit and 64bit platforms without generating warnings. Signed-off-by: Yong Cong Sin --- drivers/interrupt_controller/intc_plic.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/interrupt_controller/intc_plic.c b/drivers/interrupt_controller/intc_plic.c index df50e7b9d3c..47ae54060cf 100644 --- a/drivers/interrupt_controller/intc_plic.c +++ b/drivers/interrupt_controller/intc_plic.c @@ -466,7 +466,7 @@ static int cmd_get_stats(const struct shell *sh, size_t argc, char *argv[]) shell_print(sh, " IRQ\t Hits"); shell_print(sh, "=================="); - for (size_t i = 0; i < MIN(config->num_irqs, CONFIG_MAX_IRQ_PER_AGGREGATOR); i++) { + for (int i = 0; i < MIN(config->num_irqs, CONFIG_MAX_IRQ_PER_AGGREGATOR); i++) { if (stat.irq_count[i] > min_hit) { shell_print(sh, "%6d\t%10d", i, stat.irq_count[i]); } From dd7193e49133d1fde2dd38c2ddc5df3b0241496a Mon Sep 17 00:00:00 2001 From: Yong Cong Sin Date: Thu, 4 Jan 2024 21:54:00 +0800 Subject: [PATCH 1832/3723] drivers: intc: plic: simplify the handling of the `irq_count` array Store the compile-time computed length of the `irq_count` into a variable so that we have less to do in runtime. Signed-off-by: Yong Cong Sin --- drivers/interrupt_controller/intc_plic.c | 15 +++++++-------- 1 file changed, 7 insertions(+), 8 deletions(-) diff --git a/drivers/interrupt_controller/intc_plic.c b/drivers/interrupt_controller/intc_plic.c index 47ae54060cf..8702735d87f 100644 --- a/drivers/interrupt_controller/intc_plic.c +++ b/drivers/interrupt_controller/intc_plic.c @@ -79,7 +79,8 @@ struct plic_config { }; struct plic_stats { - uint16_t *irq_count; + uint16_t *const irq_count; + const int irq_count_len; }; struct plic_data { @@ -455,7 +456,6 @@ static int cmd_get_stats(const struct shell *sh, size_t argc, char *argv[]) return ret; } - const struct plic_config *config = dev->config; const struct plic_data *data = dev->data; struct plic_stats stat = data->stats; @@ -466,7 +466,7 @@ static int cmd_get_stats(const struct shell *sh, size_t argc, char *argv[]) shell_print(sh, " IRQ\t Hits"); shell_print(sh, "=================="); - for (int i = 0; i < MIN(config->num_irqs, CONFIG_MAX_IRQ_PER_AGGREGATOR); i++) { + for (int i = 0; i < stat.irq_count_len; i++) { if (stat.irq_count[i] > min_hit) { shell_print(sh, "%6d\t%10d", i, stat.irq_count[i]); } @@ -485,12 +485,10 @@ static int cmd_clear_stats(const struct shell *sh, size_t argc, char *argv[]) return ret; } - const struct plic_config *config = dev->config; const struct plic_data *data = dev->data; struct plic_stats stat = data->stats; - memset(stat.irq_count, 0, - MIN(config->num_irqs, CONFIG_MAX_IRQ_PER_AGGREGATOR) * sizeof(uint16_t)); + memset(stat.irq_count, 0, stat.irq_count_len * sizeof(uint16_t)); shell_print(sh, "Cleared stats of %s.\n", dev->name); @@ -536,15 +534,16 @@ static int cmd_plic(const struct shell *sh, size_t argc, char **argv) SHELL_CMD_ARG_REGISTER(plic, &plic_cmds, "PLIC shell commands", cmd_plic, 2, 0); +#define PLIC_MIN_IRQ_NUM(n) MIN(DT_INST_PROP(n, riscv_ndev), CONFIG_MAX_IRQ_PER_AGGREGATOR) #define PLIC_INTC_IRQ_COUNT_BUF_DEFINE(n) \ - static uint16_t local_irq_count_##n[MIN(DT_INST_PROP(n, riscv_ndev), \ - CONFIG_MAX_IRQ_PER_AGGREGATOR)]; + static uint16_t local_irq_count_##n[PLIC_MIN_IRQ_NUM(n)]; #define PLIC_INTC_DATA_INIT(n) \ PLIC_INTC_IRQ_COUNT_BUF_DEFINE(n); \ static struct plic_data plic_data_##n = { \ .stats = { \ .irq_count = local_irq_count_##n, \ + .irq_count_len = PLIC_MIN_IRQ_NUM(n), \ }, \ }; From 8f6be9661e64987404f2356b536e1918f173d08f Mon Sep 17 00:00:00 2001 From: Yong Cong Sin Date: Thu, 4 Jan 2024 17:36:30 +0800 Subject: [PATCH 1833/3723] tests: build_all: plic: add test for `PLIC_SHELL` build Add a build-only test for the `PLIC_SHELL` configuration. Signed-off-by: Yong Cong Sin --- .../build_all/interrupt_controller/intc_plic/testcase.yaml | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/tests/drivers/build_all/interrupt_controller/intc_plic/testcase.yaml b/tests/drivers/build_all/interrupt_controller/intc_plic/testcase.yaml index ea80ccf8d26..290a889ba89 100644 --- a/tests/drivers/build_all/interrupt_controller/intc_plic/testcase.yaml +++ b/tests/drivers/build_all/interrupt_controller/intc_plic/testcase.yaml @@ -10,6 +10,12 @@ common: - plic tests: drivers.interrupt_controller.intc_plic.build: {} + drivers.interrupt_controller.intc_plic.plic_shell.build: + tags: + - shell + extra_configs: + - CONFIG_SHELL=y + - CONFIG_PLIC_SHELL=y drivers.interrupt_controller.intc_plic.multi_instance.build: extra_args: DTC_OVERLAY_FILE="./app.multi_instance.overlay" From 410684c7b0de20ce0fe0a4eb529147e106852f20 Mon Sep 17 00:00:00 2001 From: "Hudson C. Dalpra" Date: Thu, 30 Nov 2023 16:33:09 +1300 Subject: [PATCH 1834/3723] drivers: w1: add zephyr-gpio driver The zephyr-gpio w1 driver introduced in this commit implements all routines for the w1 api on top of the zephyr gpio driver. W1 bit read, write, and reset operations are executed by bit-banging the selected gpio. Signed-off-by: Hudson C. Dalpra --- drivers/w1/CMakeLists.txt | 1 + drivers/w1/Kconfig | 1 + drivers/w1/Kconfig.zephyr_gpio | 28 ++ drivers/w1/w1_zephyr_gpio.c | 326 ++++++++++++++++++++++ dts/bindings/w1/zephyr,w1-gpio.yaml | 29 ++ tests/drivers/build_all/w1/CMakeLists.txt | 9 + tests/drivers/build_all/w1/app.overlay | 31 ++ tests/drivers/build_all/w1/prj.conf | 7 + tests/drivers/build_all/w1/src/main.c | 10 + tests/drivers/build_all/w1/testcase.yaml | 11 + 10 files changed, 453 insertions(+) create mode 100644 drivers/w1/Kconfig.zephyr_gpio create mode 100644 drivers/w1/w1_zephyr_gpio.c create mode 100644 dts/bindings/w1/zephyr,w1-gpio.yaml create mode 100644 tests/drivers/build_all/w1/CMakeLists.txt create mode 100644 tests/drivers/build_all/w1/app.overlay create mode 100644 tests/drivers/build_all/w1/prj.conf create mode 100644 tests/drivers/build_all/w1/src/main.c create mode 100644 tests/drivers/build_all/w1/testcase.yaml diff --git a/drivers/w1/CMakeLists.txt b/drivers/w1/CMakeLists.txt index 57d010f4e4d..58fa21ab84a 100644 --- a/drivers/w1/CMakeLists.txt +++ b/drivers/w1/CMakeLists.txt @@ -14,6 +14,7 @@ zephyr_library_sources_ifdef(CONFIG_W1_DS2484 w1_ds2484.c) zephyr_library_sources_ifdef(CONFIG_W1_DS2485 w1_ds2485.c) zephyr_library_sources_ifdef(CONFIG_W1_DS2477_85_COMMON w1_ds2477_85_common.c) zephyr_library_sources_ifdef(CONFIG_W1_TEST w1_test.c) +zephyr_library_sources_ifdef(CONFIG_W1_ZEPHYR_GPIO w1_zephyr_gpio.c) zephyr_library_sources_ifdef(CONFIG_W1_ZEPHYR_SERIAL w1_zephyr_serial.c) # network functions: diff --git a/drivers/w1/Kconfig b/drivers/w1/Kconfig index a63a5741981..d33503c2684 100644 --- a/drivers/w1/Kconfig +++ b/drivers/w1/Kconfig @@ -44,6 +44,7 @@ rsource "Kconfig.ds2484" rsource "Kconfig.ds2477_85" rsource "Kconfig.ds2485" rsource "Kconfig.test" +rsource "Kconfig.zephyr_gpio" rsource "Kconfig.zephyr_serial" config W1_NET diff --git a/drivers/w1/Kconfig.zephyr_gpio b/drivers/w1/Kconfig.zephyr_gpio new file mode 100644 index 00000000000..57bccfabd91 --- /dev/null +++ b/drivers/w1/Kconfig.zephyr_gpio @@ -0,0 +1,28 @@ +# Configuration options for the Zephyr GPIO 1-Wire Master driver + +# Copyright (c) 2023 Hudson C. Dalpra +# SPDX-License-Identifier: Apache-2.0 + +config W1_ZEPHYR_GPIO + bool "1-wire GPIO" + default y + depends on DT_HAS_ZEPHYR_W1_GPIO_ENABLED + help + This option enables the Zephyr GPIO 1-Wire master driver. + + The bus reset, and bit read and write operations are executed + via byte read and write operations on top of the Zephyr + GPIO driver interface. + +if W1_ZEPHYR_GPIO + +config W1_ZEPHYR_GPIO_TIME_CRITICAL + bool "Force time critical operations" + default y + help + This option forces the 1-Wire GPIO driver to use time critical + operations for bus reset, and bit read and write operations. + Time critical communications operations are not interrupted while + being generated. + +endif # W1_ZEPHYR_GPIO diff --git a/drivers/w1/w1_zephyr_gpio.c b/drivers/w1/w1_zephyr_gpio.c new file mode 100644 index 00000000000..090df881122 --- /dev/null +++ b/drivers/w1/w1_zephyr_gpio.c @@ -0,0 +1,326 @@ +/* + * Copyright (c) 2023 Hudson C. Dalpra + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#define DT_DRV_COMPAT zephyr_w1_gpio + +/** + * @brief 1-Wire Bus Master driver using Zephyr GPIO interface. + * + * This file contains the implementation of the 1-Wire Bus Master driver using + * the Zephyr GPIO interface. The driver is based on GPIO bit-banging and + * follows the timing specifications for 1-Wire communication. + * + * The driver supports both standard speed and overdrive speed modes. + * + * This driver is heavily based on the w1_zephyr_serial.c driver and the + * technical documentation from Maxim Integrated. + * + * - w1_zephyr_serial.c: drivers/w1/w1_zephyr_serial.c + * - Maxim Integrated 1-Wire Communication Through Software: + * https://www.analog.com/en/technical-articles/1wire-communication-through-software.html + */ + +#include +#include +#include +#include + +#include +LOG_MODULE_REGISTER(w1_gpio, CONFIG_W1_LOG_LEVEL); + +/* + * The time critical sections are used to ensure that the timing + * between communication operations is correct. + */ +#if defined(CONFIG_W1_ZEPHYR_GPIO_TIME_CRITICAL) +#define W1_GPIO_ENTER_CRITICAL() irq_lock() +#define W1_GPIO_EXIT_CRITICAL(key) irq_unlock(key) +#define W1_GPIO_WAIT_US(us) k_busy_wait(us) +#else +#define W1_GPIO_ENTER_CRITICAL() 0u +#define W1_GPIO_EXIT_CRITICAL(key) (void)key +#define W1_GPIO_WAIT_US(us) k_usleep(us) +#endif + +/* + * Standard timing between communication operations: + */ +#define W1_GPIO_TIMING_STD_A 6u +#define W1_GPIO_TIMING_STD_B 64u +#define W1_GPIO_TIMING_STD_C 60u +#define W1_GPIO_TIMING_STD_D 10u +#define W1_GPIO_TIMING_STD_E 9u +#define W1_GPIO_TIMING_STD_F 55u +#define W1_GPIO_TIMING_STD_G 0u +#define W1_GPIO_TIMING_STD_H 480u +#define W1_GPIO_TIMING_STD_I 70u +#define W1_GPIO_TIMING_STD_J 410u + +/* + * Overdrive timing between communication operations: + * + * Not completely correct since the overdrive communication requires + * delays of 2.5us, 7.5us and 8.5us. + * The delays are approximated by flooring the values. + */ +#define W1_GPIO_TIMING_OD_A 1u +#define W1_GPIO_TIMING_OD_B 7u +#define W1_GPIO_TIMING_OD_C 7u +#define W1_GPIO_TIMING_OD_D 2u +#define W1_GPIO_TIMING_OD_E 1u +#define W1_GPIO_TIMING_OD_F 7u +#define W1_GPIO_TIMING_OD_G 2u +#define W1_GPIO_TIMING_OD_H 70u +#define W1_GPIO_TIMING_OD_I 8u +#define W1_GPIO_TIMING_OD_J 40u + +struct w1_gpio_timing { + uint16_t a; + uint16_t b; + uint16_t c; + uint16_t d; + uint16_t e; + uint16_t f; + uint16_t g; + uint16_t h; + uint16_t i; + uint16_t j; +}; + +struct w1_gpio_config { + /** w1 master config, common to all drivers */ + struct w1_master_config master_config; + /** GPIO device used for 1-Wire communication */ + const struct gpio_dt_spec spec; +}; + +struct w1_gpio_data { + /** w1 master data, common to all drivers */ + struct w1_master_data master_data; + /** timing parameters for 1-Wire communication */ + const struct w1_gpio_timing *timing; + /** overdrive speed mode active */ + bool overdrive_active; +}; + +static const struct w1_gpio_timing std = { + .a = W1_GPIO_TIMING_STD_A, + .b = W1_GPIO_TIMING_STD_B, + .c = W1_GPIO_TIMING_STD_C, + .d = W1_GPIO_TIMING_STD_D, + .e = W1_GPIO_TIMING_STD_E, + .f = W1_GPIO_TIMING_STD_F, + .g = W1_GPIO_TIMING_STD_G, + .h = W1_GPIO_TIMING_STD_H, + .i = W1_GPIO_TIMING_STD_I, + .j = W1_GPIO_TIMING_STD_J, +}; + +static const struct w1_gpio_timing od = { + .a = W1_GPIO_TIMING_OD_A, + .b = W1_GPIO_TIMING_OD_B, + .c = W1_GPIO_TIMING_OD_C, + .d = W1_GPIO_TIMING_OD_D, + .e = W1_GPIO_TIMING_OD_E, + .f = W1_GPIO_TIMING_OD_F, + .g = W1_GPIO_TIMING_OD_G, + .h = W1_GPIO_TIMING_OD_H, + .i = W1_GPIO_TIMING_OD_I, + .j = W1_GPIO_TIMING_OD_J, +}; + +static int w1_gpio_reset_bus(const struct device *dev) +{ + const struct w1_gpio_config *cfg = dev->config; + const struct w1_gpio_data *data = dev->data; + + const struct gpio_dt_spec *spec = &cfg->spec; + const struct w1_gpio_timing *timing = data->timing; + + int ret = 0; + unsigned int key = W1_GPIO_ENTER_CRITICAL(); + + W1_GPIO_WAIT_US(timing->g); + ret = gpio_pin_set_dt(spec, 0); + if (ret < 0) { + goto out; + } + + W1_GPIO_WAIT_US(timing->h); + ret = gpio_pin_set_dt(spec, 1); + if (ret < 0) { + goto out; + } + + W1_GPIO_WAIT_US(timing->i); + ret = gpio_pin_get_dt(spec) ^ 0x01; + if (ret < 0) { + goto out; + } + + W1_GPIO_WAIT_US(timing->j); +out: + W1_GPIO_EXIT_CRITICAL(key); + return ret; +} + +static int w1_gpio_read_bit(const struct device *dev) +{ + const struct w1_gpio_config *cfg = dev->config; + const struct w1_gpio_data *data = dev->data; + + const struct gpio_dt_spec *spec = &cfg->spec; + const struct w1_gpio_timing *timing = data->timing; + + int ret = 0; + unsigned int key = W1_GPIO_ENTER_CRITICAL(); + + ret = gpio_pin_set_dt(spec, 0); + if (ret < 0) { + goto out; + } + + W1_GPIO_WAIT_US(timing->a); + ret = gpio_pin_set_dt(spec, 1); + if (ret < 0) { + goto out; + } + + W1_GPIO_WAIT_US(timing->e); + ret = gpio_pin_get_dt(spec) & 0x01; + if (ret < 0) { + goto out; + } + + W1_GPIO_WAIT_US(timing->f); +out: + W1_GPIO_EXIT_CRITICAL(key); + return ret; +} + +static int w1_gpio_write_bit(const struct device *dev, const bool bit) +{ + const struct w1_gpio_config *cfg = dev->config; + const struct w1_gpio_data *data = dev->data; + + const struct gpio_dt_spec *spec = &cfg->spec; + const struct w1_gpio_timing *timing = data->timing; + + int ret = 0; + unsigned int key = W1_GPIO_ENTER_CRITICAL(); + + ret = gpio_pin_set_dt(spec, 0); + if (ret < 0) { + goto out; + } + + W1_GPIO_WAIT_US(bit ? timing->a : timing->c); + ret = gpio_pin_set_dt(spec, 1); + if (ret < 0) { + goto out; + } + + W1_GPIO_WAIT_US(bit ? timing->b : timing->d); +out: + W1_GPIO_EXIT_CRITICAL(key); + return ret; +} + +static int w1_gpio_read_byte(const struct device *dev) +{ + int ret = 0; + int byte = 0x00; + + for (int i = 0; i < 8; i++) { + ret = w1_gpio_read_bit(dev); + if (ret < 0) { + return ret; + } + + byte >>= 1; + if (ret) { + byte |= 0x80; + } + } + + return byte; +} + +static int w1_gpio_write_byte(const struct device *dev, const uint8_t byte) +{ + int ret = 0; + uint8_t write = byte; + + for (int i = 0; i < 8; i++) { + ret = w1_gpio_write_bit(dev, write & 0x01); + if (ret < 0) { + return ret; + } + write >>= 1; + } + + return ret; +} + +static int w1_gpio_configure(const struct device *dev, enum w1_settings_type type, uint32_t value) +{ + struct w1_gpio_data *data = dev->data; + + switch (type) { + case W1_SETTING_SPEED: + data->overdrive_active = (value != 0); + data->timing = data->overdrive_active ? &od : &std; + return 0; + default: + return -ENOTSUP; + } +} + +static int w1_gpio_init(const struct device *dev) +{ + const struct w1_gpio_config *cfg = dev->config; + const struct gpio_dt_spec *spec = &cfg->spec; + struct w1_gpio_data *data = dev->data; + + if (gpio_is_ready_dt(spec)) { + int ret = gpio_pin_configure_dt(spec, GPIO_OUTPUT_INACTIVE | GPIO_OPEN_DRAIN | + GPIO_PULL_UP); + if (ret < 0) { + LOG_ERR("Failed to configure GPIO port %s pin %d", spec->port->name, + spec->pin); + return ret; + } + } else { + LOG_ERR("GPIO port %s is not ready", spec->port->name); + return -ENODEV; + } + + data->timing = &std; + data->overdrive_active = false; + + LOG_DBG("w1-gpio initialized, with %d slave devices", cfg->master_config.slave_count); + return 0; +} + +static const struct w1_driver_api w1_gpio_driver_api = { + .reset_bus = w1_gpio_reset_bus, + .read_bit = w1_gpio_read_bit, + .write_bit = w1_gpio_write_bit, + .read_byte = w1_gpio_read_byte, + .write_byte = w1_gpio_write_byte, + .configure = w1_gpio_configure, +}; + +#define W1_ZEPHYR_GPIO_INIT(inst) \ + static const struct w1_gpio_config w1_gpio_cfg_##inst = { \ + .master_config.slave_count = W1_INST_SLAVE_COUNT(inst), \ + .spec = GPIO_DT_SPEC_INST_GET(inst, gpios)}; \ + static struct w1_gpio_data w1_gpio_data_##inst = {}; \ + DEVICE_DT_INST_DEFINE(inst, &w1_gpio_init, NULL, &w1_gpio_data_##inst, \ + &w1_gpio_cfg_##inst, POST_KERNEL, CONFIG_W1_INIT_PRIORITY, \ + &w1_gpio_driver_api); + +DT_INST_FOREACH_STATUS_OKAY(W1_ZEPHYR_GPIO_INIT) diff --git a/dts/bindings/w1/zephyr,w1-gpio.yaml b/dts/bindings/w1/zephyr,w1-gpio.yaml new file mode 100644 index 00000000000..46f4e684e01 --- /dev/null +++ b/dts/bindings/w1/zephyr,w1-gpio.yaml @@ -0,0 +1,29 @@ +# Copyright (c) 2023 Hudson C. Dalpra +# SPDX-License-Identifier: Apache-2.0 + +description: | + Zephyr W1 GPIO node + + This defines a one-wire driver through GPIO bit-banging. + + For example: + + / { + w1: w1 { + compatible = "zephyr,w1-gpio"; + gpios = <&gpio0 13 (GPIO_ACTIVE_HIGH | GPIO_OPEN_DRAIN | GPIO_PULL_UP)>; + }; + }; + + Above: + - w1 is pin 13 on gpio0. The gpio is active when the pin is high, is + configured as an open-drain, and has a pull-up resistor. + +compatible: "zephyr,w1-gpio" + +include: [w1-master.yaml] + +properties: + gpios: + type: phandle-array + required: true diff --git a/tests/drivers/build_all/w1/CMakeLists.txt b/tests/drivers/build_all/w1/CMakeLists.txt new file mode 100644 index 00000000000..b627b17c503 --- /dev/null +++ b/tests/drivers/build_all/w1/CMakeLists.txt @@ -0,0 +1,9 @@ +# Copyright (c) 2023 Hudson C. Dalpra +# SPDX-License-Identifier: Apache-2.0 + +cmake_minimum_required(VERSION 3.20.0) +find_package(Zephyr REQUIRED HINTS $ENV{ZEPHYR_BASE}) +project(build_all) + +FILE(GLOB app_sources src/*.c) +target_sources(app PRIVATE ${app_sources}) diff --git a/tests/drivers/build_all/w1/app.overlay b/tests/drivers/build_all/w1/app.overlay new file mode 100644 index 00000000000..aa11ce6c168 --- /dev/null +++ b/tests/drivers/build_all/w1/app.overlay @@ -0,0 +1,31 @@ +/* + * Copyright (c) 2023 Hudson C. Dalpra + * + * SPDX-License-Identifier: Apache-2.0 + * + * Application overlay for testing driver builds + * + * Names in this file should be chosen in a way that won't conflict + * with real-world devicetree nodes, to allow these tests to run on + * (and be extended to test) real hardware. + */ + +/ { + test { + #address-cells = <1>; + #size-cells = <1>; + + test_gpio: gpio@deadbeef { + compatible = "vnd,gpio"; + gpio-controller; + reg = <0xdeadbeef 0x1000>; + #gpio-cells = <0x2>; + status = "okay"; + }; + + test_w1_gpio: test_w1_gpio { + compatible = "zephyr,w1-gpio"; + gpios = <&test_gpio 0 0>; + }; + }; +}; diff --git a/tests/drivers/build_all/w1/prj.conf b/tests/drivers/build_all/w1/prj.conf new file mode 100644 index 00000000000..f9de5e17578 --- /dev/null +++ b/tests/drivers/build_all/w1/prj.conf @@ -0,0 +1,7 @@ +# Copyright (c) 2023 Hudson C. Dalpra +# SPDX-License-Identifier: Apache-2.0 + +CONFIG_TEST=y +CONFIG_TEST_USERSPACE=y +CONFIG_GPIO=y +CONFIG_W1=y diff --git a/tests/drivers/build_all/w1/src/main.c b/tests/drivers/build_all/w1/src/main.c new file mode 100644 index 00000000000..98bfd327335 --- /dev/null +++ b/tests/drivers/build_all/w1/src/main.c @@ -0,0 +1,10 @@ +/* + * Copyright (c) 2023 Hudson C. Dalpra + * + * SPDX-License-Identifier: Apache-2.0 + */ + +int main(void) +{ + return 0; +} diff --git a/tests/drivers/build_all/w1/testcase.yaml b/tests/drivers/build_all/w1/testcase.yaml new file mode 100644 index 00000000000..f0e1d11aeb9 --- /dev/null +++ b/tests/drivers/build_all/w1/testcase.yaml @@ -0,0 +1,11 @@ +# Copyright (c) 2023 Hudson C. Dalpra +# SPDX-License-Identifier: Apache-2.0 + +tests: + drivers.w1.build: + build_only: true + tags: + - drivers + - w1 + integration_platforms: + - native_posix From a3573a9e30b9aab694bb50384e4dd5f318b10dee Mon Sep 17 00:00:00 2001 From: Jai Arora Date: Wed, 27 Dec 2023 08:33:14 +0530 Subject: [PATCH 1835/3723] posix: implement clock_getcpuclockid function Implements clock_getcpuclockid function Fixes #59954 Signed-off-by: Jai Arora --- include/zephyr/posix/time.h | 5 +++++ lib/posix/clock.c | 13 +++++++++++++ 2 files changed, 18 insertions(+) diff --git a/include/zephyr/posix/time.h b/include/zephyr/posix/time.h index ea7e68cb079..417923c4377 100644 --- a/include/zephyr/posix/time.h +++ b/include/zephyr/posix/time.h @@ -69,6 +69,10 @@ extern "C" { #define CLOCK_REALTIME 1 #endif +#ifndef CLOCK_PROCESS_CPUTIME_ID +#define CLOCK_PROCESS_CPUTIME_ID 2 +#endif + #ifndef CLOCK_MONOTONIC #define CLOCK_MONOTONIC 4 #endif @@ -84,6 +88,7 @@ static inline int32_t _ts_to_ms(const struct timespec *to) int clock_gettime(clockid_t clock_id, struct timespec *ts); int clock_settime(clockid_t clock_id, const struct timespec *ts); +int clock_getcpuclockid(pid_t pid, clockid_t *clock_id); /* Timer APIs */ int timer_create(clockid_t clockId, struct sigevent *evp, timer_t *timerid); int timer_delete(timer_t timerid); diff --git a/lib/posix/clock.c b/lib/posix/clock.c index 0d085a6d0d0..1a59aa741f9 100644 --- a/lib/posix/clock.c +++ b/lib/posix/clock.c @@ -10,6 +10,7 @@ #include #include #include +#include #include #include @@ -222,3 +223,15 @@ int gettimeofday(struct timeval *tv, void *tz) return res; } + +int clock_getcpuclockid(pid_t pid, clockid_t *clock_id) +{ + /* We don't allow any process ID but our own. */ + if (pid != 0 && pid != getpid()) { + return EPERM; + } + + *clock_id = CLOCK_PROCESS_CPUTIME_ID; + + return 0; +} From a7c1a5f9d6f3a9c2aeff1820c0070362e1aa6605 Mon Sep 17 00:00:00 2001 From: Jai Arora Date: Mon, 1 Jan 2024 13:31:39 +0530 Subject: [PATCH 1836/3723] posix: Adds test case for clock_getcpuclockid function Adds ZTEST for clock_getcpuclockid function Signed-off-by: Jai Arora --- tests/posix/common/src/clock.c | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/tests/posix/common/src/clock.c b/tests/posix/common/src/clock.c index 3677e606c16..21319bf3592 100644 --- a/tests/posix/common/src/clock.c +++ b/tests/posix/common/src/clock.c @@ -213,3 +213,15 @@ ZTEST(posix_apis, test_realtime) CONFIG_TEST_CLOCK_RT_ERROR_MS, lo_wm, cma, hi_wm); zassert_between_inclusive(cma, lo, hi); } + +ZTEST(posix_apis, test_clock_getcpuclockid) +{ + int ret = 0; + clockid_t clock_id; + + ret = clock_getcpuclockid((pid_t)0, &clock_id); + zassert_equal(ret, 0, "POSIX clock_getcpuclock id failed"); + + ret = clock_getcpuclockid((pid_t)2482, &clock_id); + zassert_equal(ret, EPERM, "POSIX clock_getcpuclock id failed"); +} From 5c34726ab11de79d8c5a456153d81d40fa3124eb Mon Sep 17 00:00:00 2001 From: Jai Arora Date: Wed, 27 Dec 2023 08:35:32 +0530 Subject: [PATCH 1837/3723] posix: patch to implement get_pid function patch to implement get_pid function Signed-off-by: Jai Arora --- include/zephyr/posix/posix_types.h | 2 ++ include/zephyr/posix/unistd.h | 1 + lib/posix/pthread.c | 17 +++++++++++++++++ 3 files changed, 20 insertions(+) diff --git a/include/zephyr/posix/posix_types.h b/include/zephyr/posix/posix_types.h index 175943950b7..3420d562679 100644 --- a/include/zephyr/posix/posix_types.h +++ b/include/zephyr/posix/posix_types.h @@ -21,6 +21,8 @@ extern "C" { #endif +typedef int pid_t; + #ifndef __useconds_t_defined typedef unsigned long useconds_t; #endif diff --git a/include/zephyr/posix/unistd.h b/include/zephyr/posix/unistd.h index b55cf702fec..84faf7c1c8f 100644 --- a/include/zephyr/posix/unistd.h +++ b/include/zephyr/posix/unistd.h @@ -51,6 +51,7 @@ extern char *optarg; extern int opterr, optind, optopt; #endif +pid_t getpid(void); unsigned sleep(unsigned int seconds); int usleep(useconds_t useconds); diff --git a/lib/posix/pthread.c b/lib/posix/pthread.c index 131242866a0..2e2c49f2a35 100644 --- a/lib/posix/pthread.c +++ b/lib/posix/pthread.c @@ -15,6 +15,7 @@ #include #include #include +#include #include #include @@ -158,6 +159,22 @@ int pthread_equal(pthread_t pt1, pthread_t pt2) return (pt1 == pt2); } +pid_t getpid(void) +{ + /* + * To maintain compatibility with some other POSIX operating systems, + * a PID of zero is used to indicate that the process exists in another namespace. + * PID zero is also used by the scheduler in some cases. + * PID one is usually reserved for the init process. + * Also note, that negative PIDs may be used by kill() + * to send signals to process groups in some implementations. + * + * At the moment, getpid just returns an arbitrary number >= 2 + */ + + return 42; +} + static inline void __z_pthread_cleanup_init(struct __pthread_cleanup *c, void (*routine)(void *arg), void *arg) { From c8d22cf13ae05e03695330bd34669af3c1336ea7 Mon Sep 17 00:00:00 2001 From: Nikodem Kastelik Date: Thu, 21 Dec 2023 21:07:00 +0100 Subject: [PATCH 1838/3723] manifest: hal_nordic: update revision to have nrfx 3.3.0 release New hal_nordic revision contains nrfx 3.3.0 which adds support for nRF54H20 EngA and nRF54L15 EngA devices. Signed-off-by: Nikodem Kastelik --- west.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/west.yml b/west.yml index d67fa039322..4b29e9b9fd2 100644 --- a/west.yml +++ b/west.yml @@ -183,7 +183,7 @@ manifest: groups: - hal - name: hal_nordic - revision: 3786c55424d4d64c62dd25219de31618cef26fdf + revision: b55cfbbf0221d709560c2e438beef66842ada272 path: modules/hal/nordic groups: - hal From 6a64bf6b4f0398bf14e44028b074dd93526979ae Mon Sep 17 00:00:00 2001 From: Bryan Zhu Date: Tue, 26 Dec 2023 14:35:15 +0800 Subject: [PATCH 1839/3723] drivers: counter: counter_ambiq_timer: Enable interrupt in set_alarm Alarm interrupt is disabled in cancel_alarm, we should re-enable it in set_alarm, at meanwhile, should reset the compare register in cancel_alarm to avoid the contention condition in cancel_alarm & set_alarm in short time. This change fixes the test case failure at zephyr\tests\drivers\counter\counter_basic_api. Signed-off-by: Bryan Zhu --- drivers/counter/counter_ambiq_timer.c | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/drivers/counter/counter_ambiq_timer.c b/drivers/counter/counter_ambiq_timer.c index 94549d65685..67df6c5647f 100644 --- a/drivers/counter/counter_ambiq_timer.c +++ b/drivers/counter/counter_ambiq_timer.c @@ -43,7 +43,6 @@ static int counter_ambiq_init(const struct device *dev) tc.ui32PatternLimit = 0; am_hal_timer_config(0, &tc); - am_hal_timer_interrupt_enable(AM_HAL_TIMER_MASK(0, AM_HAL_TIMER_COMPARE1)); k_spin_unlock(&lock, key); @@ -98,6 +97,10 @@ static int counter_ambiq_set_alarm(const struct device *dev, uint8_t chan_id, k_spinlock_key_t key = k_spin_lock(&lock); + /* Enable interrupt, due to counter_ambiq_cancel_alarm() disables it*/ + am_hal_timer_interrupt_clear(AM_HAL_TIMER_MASK(0, AM_HAL_TIMER_COMPARE1)); + am_hal_timer_interrupt_enable(AM_HAL_TIMER_MASK(0, AM_HAL_TIMER_COMPARE1)); + if ((alarm_cfg->flags & COUNTER_ALARM_CFG_ABSOLUTE) == 0) { am_hal_timer_compare1_set(0, now + alarm_cfg->ticks); } else { @@ -119,6 +122,8 @@ static int counter_ambiq_cancel_alarm(const struct device *dev, uint8_t chan_id) k_spinlock_key_t key = k_spin_lock(&lock); am_hal_timer_interrupt_disable(AM_HAL_TIMER_MASK(0, AM_HAL_TIMER_COMPARE1)); + /* Reset the compare register */ + am_hal_timer_compare1_set(0, 0); k_spin_unlock(&lock, key); return 0; From 6f84f3464733d90437487558aa1fd97e47412d78 Mon Sep 17 00:00:00 2001 From: Bryan Zhu Date: Tue, 26 Dec 2023 14:35:16 +0800 Subject: [PATCH 1840/3723] tests: counter: counter_basic_api: Add support for ambiq_counter device Update counter test to test ambiq_counter devices Signed-off-by: Bryan Zhu --- tests/drivers/counter/counter_basic_api/src/test_counter.c | 3 +++ 1 file changed, 3 insertions(+) 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 f63ee5ce6c4..370b07b248c 100644 --- a/tests/drivers/counter/counter_basic_api/src/test_counter.c +++ b/tests/drivers/counter/counter_basic_api/src/test_counter.c @@ -99,6 +99,9 @@ static const struct device *const devices[] = { #ifdef CONFIG_COUNTER_TIMER_RPI_PICO DEVS_FOR_DT_COMPAT(raspberrypi_pico_timer) #endif +#ifdef CONFIG_COUNTER_AMBIQ + DEVS_FOR_DT_COMPAT(ambiq_counter) +#endif }; static const struct device *const period_devs[] = { From 7213e8e1f52dd1479952636b01bc3b6cdff8e55b Mon Sep 17 00:00:00 2001 From: Bartosz Bilas Date: Tue, 2 Jan 2024 13:23:03 +0100 Subject: [PATCH 1841/3723] drivers: regulator: max20335: allow current limit operations only for BUCKs LDOs don't have such possibility so add the extra checks. Signed-off-by: Bartosz Bilas --- drivers/regulator/regulator_max20335.c | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/drivers/regulator/regulator_max20335.c b/drivers/regulator/regulator_max20335.c index 699edd8162f..b94c0e0bb98 100644 --- a/drivers/regulator/regulator_max20335.c +++ b/drivers/regulator/regulator_max20335.c @@ -224,6 +224,11 @@ static unsigned int regulator_max20335_count_current_limits(const struct device { const struct regulator_max20335_config *config = dev->config; + if (config->source != MAX20335_PMIC_SOURCE_BUCK1 && + config->source != MAX20335_PMIC_SOURCE_BUCK2) { + return -ENOTSUP; + } + return linear_range_values_count(config->desc->ua_range); } @@ -232,6 +237,11 @@ static int regulator_max20335_list_current_limit(const struct device *dev, unsig { const struct regulator_max20335_config *config = dev->config; + if (config->source != MAX20335_PMIC_SOURCE_BUCK1 && + config->source != MAX20335_PMIC_SOURCE_BUCK2) { + return -ENOTSUP; + } + return linear_range_get_value(config->desc->ua_range, idx, current_ua); } @@ -244,6 +254,11 @@ static int regulator_max20335_set_current_limit(const struct device *dev, uint16_t idx; int ret; + if (config->source != MAX20335_PMIC_SOURCE_BUCK1 && + config->source != MAX20335_PMIC_SOURCE_BUCK2) { + return -ENOTSUP; + } + ret = i2c_reg_read_byte_dt(&config->bus, MAX20335_BUCK12_CSET, &val); if (ret < 0) { return ret; From b4dc12b42bd31199ccb5fa726203153e1942ca6e Mon Sep 17 00:00:00 2001 From: Aleksandr Khromykh Date: Tue, 2 Jan 2024 15:41:07 +0100 Subject: [PATCH 1842/3723] tests: Bluetooth: Mesh: optimize proxy beacon test Emitting network beacons in parallel to proxy functionality causes collisions. The commit disables network beacons and allows the test scenario to be more precise. Signed-off-by: Aleksandr Khromykh --- tests/bsim/bluetooth/mesh/src/test_beacon.c | 8 ++++++-- .../priv_beacon/proxy_adv_multi_subnet_coex.sh | 4 ++++ 2 files changed, 10 insertions(+), 2 deletions(-) diff --git a/tests/bsim/bluetooth/mesh/src/test_beacon.c b/tests/bsim/bluetooth/mesh/src/test_beacon.c index 938b5dc141a..2e7e36a9b50 100644 --- a/tests/bsim/bluetooth/mesh/src/test_beacon.c +++ b/tests/bsim/bluetooth/mesh/src/test_beacon.c @@ -2011,6 +2011,8 @@ static const struct bt_mesh_test_cfg solicit_trigger_cfg = { static void test_tx_proxy_adv_solicit_trigger(void) { tx_proxy_adv_common_init(PROXY_ADV_MULTI_SUBNET_COEX_WAIT_TIME, &solicit_trigger_cfg); + /* Disable SNB. */ + bt_mesh_beacon_set(false); ASSERT_OK_MSG(bt_mesh_subnet_add(TEST_NET_IDX2, test_net_key_2), "Failed to add second subnet"); @@ -2028,6 +2030,8 @@ static void test_tx_proxy_adv_solicit_trigger(void) static void test_rx_proxy_adv_multi_subnet_coex(void) { rx_priv_common_init(PROXY_ADV_MULTI_SUBNET_COEX_WAIT_TIME); + /* Disable SNB. */ + bt_mesh_beacon_set(false); pp_netkey_ctx_init(&pp_net1); pp_netkey_ctx_init(&pp_net2); @@ -2071,10 +2075,10 @@ static void test_rx_proxy_adv_multi_subnet_coex(void) /** The first and second subnet gets solicited. Check that * PRIVATE_NET_ID is advertised by these subnet, */ - {.evt_type = BEACON_TYPE_PRIVATE_NET_ID, .net_idx = 0, .evt_cnt = 9, + {.evt_type = BEACON_TYPE_PRIVATE_NET_ID, .net_idx = 0, .evt_cnt = 8, .time = {.after = PROXY_ADV_MULTI_CHECKPOINT_3, .before = PROXY_ADV_MULTI_CHECKPOINT_4}}, - {.evt_type = BEACON_TYPE_PRIVATE_NET_ID, .net_idx = 1, .evt_cnt = 9, + {.evt_type = BEACON_TYPE_PRIVATE_NET_ID, .net_idx = 1, .evt_cnt = 8, .time = {.after = PROXY_ADV_MULTI_CHECKPOINT_3, .before = PROXY_ADV_MULTI_CHECKPOINT_4}}, diff --git a/tests/bsim/bluetooth/mesh/tests_scripts/priv_beacon/proxy_adv_multi_subnet_coex.sh b/tests/bsim/bluetooth/mesh/tests_scripts/priv_beacon/proxy_adv_multi_subnet_coex.sh index aa96ee325d8..845a8ff7da7 100755 --- a/tests/bsim/bluetooth/mesh/tests_scripts/priv_beacon/proxy_adv_multi_subnet_coex.sh +++ b/tests/bsim/bluetooth/mesh/tests_scripts/priv_beacon/proxy_adv_multi_subnet_coex.sh @@ -22,6 +22,10 @@ source $(dirname "${BASH_SOURCE[0]}")/../../_mesh_test.sh # window. The Mesh Protocol specification does not specify exactly the # timing for Proxy ADV messages. +# Note 3: The proxy transmitting device mandates emitting of the secure +# network beacons. This allows to check that proxy goes back to normal +# behavior after device advertises the seure network beacons. + # Test procedure: # 1. (0-20 seconds) A single subnet is active on the TX device with GATT # Proxy enabled. RX device verifies that the single subnet has exclusive From b64915e616de7561a55450d5857d24363a586b27 Mon Sep 17 00:00:00 2001 From: Tomasz Gorochowik Date: Wed, 3 Jan 2024 14:36:30 +0100 Subject: [PATCH 1843/3723] docs: Fix rzt2m starterkit docs formatting Add additional new lines before bullet points. Otherwise they are not rendered as bullets. Signed-off-by: Tomasz Gorochowik --- boards/arm/rzt2m_starterkit/doc/index.rst | 3 +++ 1 file changed, 3 insertions(+) diff --git a/boards/arm/rzt2m_starterkit/doc/index.rst b/boards/arm/rzt2m_starterkit/doc/index.rst index 1fa6a13b6f9..72dc6615f64 100644 --- a/boards/arm/rzt2m_starterkit/doc/index.rst +++ b/boards/arm/rzt2m_starterkit/doc/index.rst @@ -22,6 +22,7 @@ Hardware The board utilizes the SoC of part no. R9A07G075M24GBG, with 2MB of RAM. It has several on-board memory components: + * SDRAM (256MBit), * NOR Flash (256MBit), * Octa Flash (512MBit), @@ -30,6 +31,7 @@ It has several on-board memory components: * I2C EEPROM (32Kbit). The communication interfaces include: + * Debug interfaces (J-Link, MIPI-10, MIPI-20), * Ethernet, * CAN, @@ -62,6 +64,7 @@ Connections and IOs =================== By default, the board is configured for use with: + * UART0 connected to the USB serial port (pins K18, K19), * UART3 connected to the PMOD Header (J25, pins H16, G20), * LEDs defined as `led0`, `led1`, `led2` and `led3`, From fcb9f412596ee785e15990a0c62a825e1fa395e9 Mon Sep 17 00:00:00 2001 From: Bartosz Bilas Date: Mon, 11 Dec 2023 20:44:17 +0100 Subject: [PATCH 1844/3723] boards: xtensa: add Kincony KC868-A32 module suppport Add support for the KC868-A32 ESP32 home automation relay module. Signed-off-by: Bartosz Bilas --- CODEOWNERS | 1 + boards/xtensa/kincony_kc868_a32/Kconfig.board | 10 + .../kincony_kc868_a32/Kconfig.defconfig | 14 ++ .../xtensa/kincony_kc868_a32/Kconfig.sysbuild | 10 + boards/xtensa/kincony_kc868_a32/board.cmake | 11 + .../doc/img/kincony_kc868_a32.jpg | Bin 0 -> 82930 bytes boards/xtensa/kincony_kc868_a32/doc/index.rst | 97 ++++++++ .../kincony_kc868_a32-pinctrl.dtsi | 49 ++++ .../kincony_kc868_a32/kincony_kc868_a32.dts | 214 ++++++++++++++++++ .../kincony_kc868_a32/kincony_kc868_a32.yaml | 19 ++ .../kincony_kc868_a32_defconfig | 14 ++ .../kincony_kc868_a32/support/openocd.cfg | 5 + tests/lib/devicetree/devices/testcase.yaml | 1 + 13 files changed, 445 insertions(+) create mode 100644 boards/xtensa/kincony_kc868_a32/Kconfig.board create mode 100644 boards/xtensa/kincony_kc868_a32/Kconfig.defconfig create mode 100644 boards/xtensa/kincony_kc868_a32/Kconfig.sysbuild create mode 100644 boards/xtensa/kincony_kc868_a32/board.cmake create mode 100644 boards/xtensa/kincony_kc868_a32/doc/img/kincony_kc868_a32.jpg create mode 100644 boards/xtensa/kincony_kc868_a32/doc/index.rst create mode 100644 boards/xtensa/kincony_kc868_a32/kincony_kc868_a32-pinctrl.dtsi create mode 100644 boards/xtensa/kincony_kc868_a32/kincony_kc868_a32.dts create mode 100644 boards/xtensa/kincony_kc868_a32/kincony_kc868_a32.yaml create mode 100644 boards/xtensa/kincony_kc868_a32/kincony_kc868_a32_defconfig create mode 100644 boards/xtensa/kincony_kc868_a32/support/openocd.cfg diff --git a/CODEOWNERS b/CODEOWNERS index 8c2b478fb4a..af2cb6c5d51 100644 --- a/CODEOWNERS +++ b/CODEOWNERS @@ -133,6 +133,7 @@ /boards/shields/inventek_eswifi/ @nandojve /boards/xtensa/odroid_go/ @ydamigos /boards/xtensa/nxp_adsp_imx8/ @iuliana-prodan @dbaluta +/boards/xtensa/kincony_kc868_a32/ @bbilas /boards/arm64/qemu_cortex_a53/ @carlocaione /boards/arm64/bcm958402m2_a72/ @abhishek-brcm /boards/arm64/mimx8mm_evk/ @MrVan @JiafeiPan diff --git a/boards/xtensa/kincony_kc868_a32/Kconfig.board b/boards/xtensa/kincony_kc868_a32/Kconfig.board new file mode 100644 index 00000000000..098f377092b --- /dev/null +++ b/boards/xtensa/kincony_kc868_a32/Kconfig.board @@ -0,0 +1,10 @@ +# Copyright (c) 2023 Bartosz Bilas +# SPDX-License-Identifier: Apache-2.0 + +config BOARD_KINCONY_KC868_A32 + bool "KINCONY KC868-A32 Board" + depends on SOC_SERIES_ESP32 + +choice SOC_PART_NUMBER + default SOC_ESP32_WROOM_32UE_N4 +endchoice diff --git a/boards/xtensa/kincony_kc868_a32/Kconfig.defconfig b/boards/xtensa/kincony_kc868_a32/Kconfig.defconfig new file mode 100644 index 00000000000..229aaaeb4e3 --- /dev/null +++ b/boards/xtensa/kincony_kc868_a32/Kconfig.defconfig @@ -0,0 +1,14 @@ +# Copyright (c) 2023 Bartosz Bilas +# SPDX-License-Identifier: Apache-2.0 + +config BOARD + default "kincony_kc868_a32" + depends on BOARD_KINCONY_KC868_A32 + +config ENTROPY_GENERATOR + default y + +config HEAP_MEM_POOL_SIZE + default 98304 if WIFI + default 40960 if BT + default 4096 diff --git a/boards/xtensa/kincony_kc868_a32/Kconfig.sysbuild b/boards/xtensa/kincony_kc868_a32/Kconfig.sysbuild new file mode 100644 index 00000000000..bcf253836da --- /dev/null +++ b/boards/xtensa/kincony_kc868_a32/Kconfig.sysbuild @@ -0,0 +1,10 @@ +# Copyright (c) Bartosz Bilas +# SPDX-License-Identifier: Apache-2.0 + +choice BOOTLOADER + default BOOTLOADER_MCUBOOT +endchoice + +choice BOOT_SIGNATURE_TYPE + default BOOT_SIGNATURE_TYPE_NONE +endchoice diff --git a/boards/xtensa/kincony_kc868_a32/board.cmake b/boards/xtensa/kincony_kc868_a32/board.cmake new file mode 100644 index 00000000000..bf24ed17150 --- /dev/null +++ b/boards/xtensa/kincony_kc868_a32/board.cmake @@ -0,0 +1,11 @@ +# Copyright (c) Bartosz Bilas +# SPDX-License-Identifier: Apache-2.0 + +if(NOT "${OPENOCD}" MATCHES "^${ESPRESSIF_TOOLCHAIN_PATH}/.*") + set(OPENOCD OPENOCD-NOTFOUND) +endif() + +find_program(OPENOCD openocd PATHS ${ESPRESSIF_TOOLCHAIN_PATH}/openocd-esp32/bin NO_DEFAULT_PATH) + +include(${ZEPHYR_BASE}/boards/common/esp32.board.cmake) +include(${ZEPHYR_BASE}/boards/common/openocd.board.cmake) diff --git a/boards/xtensa/kincony_kc868_a32/doc/img/kincony_kc868_a32.jpg b/boards/xtensa/kincony_kc868_a32/doc/img/kincony_kc868_a32.jpg new file mode 100644 index 0000000000000000000000000000000000000000..9fa5685bb4d42eba716985026c787364295c9a9d GIT binary patch literal 82930 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 Z=fC;i|GhB!|G(eA+LQk@XA*yx{~s7E%K!iX literal 0 HcmV?d00001 diff --git a/boards/xtensa/kincony_kc868_a32/doc/index.rst b/boards/xtensa/kincony_kc868_a32/doc/index.rst new file mode 100644 index 00000000000..dfd4797701b --- /dev/null +++ b/boards/xtensa/kincony_kc868_a32/doc/index.rst @@ -0,0 +1,97 @@ +.. _kincony_kc868_a32: + +KINCONY KC868-A32 +################# + +Overview +******** + +Kincony KC868-A32 is a home automation relay module based on the +Espressif ESP-WROOM-32 module with all its inherent capabilities +(Wi-Fi, Bluetooth, etc.) + +The features include the following: + +- 32 digital optoisolated inputs “dry contact” +- 4 analog inputs 0-5 V +- 32 relays 220 V, 10 A (COM, NO, NC) +- RS485 interface +- I2C connector +- Connector GSM/HMI +- Ethernet LAN8270A +- USB Type-B connector for programming and filling firmware +- RESET and DOWNLOAD buttons +- Powered by 12V DC + +.. figure:: img/kincony_kc868_a32.jpg + :align: center + :alt: KINCONCY-KC868-A32 + + KINCONCY-KC868-A32 + +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 +------------------- + +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 + :goals: build + +The usual ``flash`` target will work with the ``kincony_kc868_a32`` board +configuration. Here is an example for the :ref:`hello_world` +application. + +.. zephyr-app-commands:: + :zephyr-app: samples/hello_world + :board: kincony_kc868_a32 + :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! kincony_kc868_a32 + +Enabling Ethernet +***************** + +Enable Ethernet in KConfig: + +.. code-block:: cfg + + CONFIG_NETWORKING=y + CONFIG_NET_L2_ETHERNET=y + CONFIG_MDIO=y + +References +********** + +.. _KINCONY KC868-A32 User Guide: https://www.kincony.com/arduino-esp32-32-channel-relay-module-kc868-a32.html diff --git a/boards/xtensa/kincony_kc868_a32/kincony_kc868_a32-pinctrl.dtsi b/boards/xtensa/kincony_kc868_a32/kincony_kc868_a32-pinctrl.dtsi new file mode 100644 index 00000000000..e1ee7cb2432 --- /dev/null +++ b/boards/xtensa/kincony_kc868_a32/kincony_kc868_a32-pinctrl.dtsi @@ -0,0 +1,49 @@ +/* + * Copyright (c) Bartosz Bilas + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include +#include +#include + +&pinctrl { + uart0_default: uart0_default { + group1 { + pinmux = ; + output-high; + }; + group2 { + pinmux = ; + bias-pull-up; + }; + }; + + i2c0_default: i2c0_default { + group1 { + pinmux = , + ; + bias-pull-up; + drive-open-drain; + output-high; + }; + }; + + i2c1_default: i2c1_default { + group1 { + pinmux = , + ; + bias-pull-up; + drive-open-drain; + output-high; + }; + }; + + mdio_default: mdio_default { + group1 { + pinmux = , + ; + }; + }; +}; diff --git a/boards/xtensa/kincony_kc868_a32/kincony_kc868_a32.dts b/boards/xtensa/kincony_kc868_a32/kincony_kc868_a32.dts new file mode 100644 index 00000000000..da250ef781a --- /dev/null +++ b/boards/xtensa/kincony_kc868_a32/kincony_kc868_a32.dts @@ -0,0 +1,214 @@ +/* + * Copyright (c) 2023 Bartosz Bilas + * + * SPDX-License-Identifier: Apache-2.0 + */ +/dts-v1/; + +#include +#include "kincony_kc868_a32-pinctrl.dtsi" + +/ { + model = "Kincony KC868-A32"; + compatible = "espressif,esp32"; + + aliases { + uart-0 = &uart0; + watchdog0 = &wdt0; + }; + + chosen { + zephyr,sram = &sram0; + zephyr,console = &uart0; + zephyr,shell-uart = &uart0; + zephyr,flash = &flash0; + zephyr,code-partition = &slot0_partition; + }; +}; + +&cpu0 { + clock-frequency = ; + cpu-power-states = <&light_sleep &deep_sleep>; +}; + +&cpu1 { + clock-frequency = ; +}; + +&gpio0 { + status = "okay"; +}; + +&gpio1 { + status = "okay"; +}; + +&i2c0 { + status = "okay"; + clock-frequency = ; + sda-gpios = <&gpio0 15 GPIO_OPEN_DRAIN>; + scl-gpios = <&gpio0 13 GPIO_OPEN_DRAIN>; + pinctrl-0 = <&i2c0_default>; + pinctrl-names = "default"; + + i2c0_pcf8574@21 { + compatible = "nxp,pcf8574"; + reg = <0x21>; + gpio-controller; + #gpio-cells = <2>; + ngpios = <8>; + }; + + i2c0_pcf8574@22 { + compatible = "nxp,pcf8574"; + reg = <0x22>; + gpio-controller; + #gpio-cells = <2>; + ngpios = <8>; + }; + + i2c0_pcf8574@24 { + compatible = "nxp,pcf8574"; + reg = <0x24>; + gpio-controller; + #gpio-cells = <2>; + ngpios = <8>; + }; + + i2c0_pcf8574@25 { + compatible = "nxp,pcf8574"; + reg = <0x25>; + gpio-controller; + #gpio-cells = <2>; + ngpios = <8>; + }; +}; + +&i2c1 { + status = "okay"; + clock-frequency = ; + sda-gpios = <&gpio0 4 GPIO_OPEN_DRAIN>; + scl-gpios = <&gpio0 5 GPIO_OPEN_DRAIN>; + pinctrl-0 = <&i2c1_default>; + pinctrl-names = "default"; + + i2c1_pcf8574@21 { + compatible = "nxp,pcf8574"; + reg = <0x21>; + gpio-controller; + #gpio-cells = <2>; + ngpios = <8>; + }; + + i2c1_pcf8574@22 { + compatible = "nxp,pcf8574"; + reg = <0x22>; + gpio-controller; + #gpio-cells = <2>; + ngpios = <8>; + }; + + i2c1_pcf8574@24 { + compatible = "nxp,pcf8574"; + reg = <0x24>; + gpio-controller; + #gpio-cells = <2>; + ngpios = <8>; + }; + + i2c1_pcf8574@25 { + compatible = "nxp,pcf8574"; + reg = <0x25>; + gpio-controller; + #gpio-cells = <2>; + ngpios = <8>; + }; +}; + +&mdio { + pinctrl-0 = <&mdio_default>; + pinctrl-names = "default"; + status = "okay"; + + phy: ethernet-phy@0 { + compatible = "ethernet-phy"; + status = "okay"; + reg = <0>; + }; +}; + +ð { + status = "okay"; + phy-handle = <&phy>; + ref-clk-output-gpios = <&gpio0 17 0>; +}; + +&psram0 { + status = "disabled"; +}; + +&timer0 { + status = "okay"; +}; + +&timer1 { + status = "okay"; +}; + +&timer2 { + status = "okay"; +}; + +&timer3 { + status = "okay"; +}; + +&trng0 { + status = "okay"; +}; + +&uart0 { + status = "okay"; + current-speed = <115200>; + pinctrl-0 = <&uart0_default>; + pinctrl-names = "default"; +}; + +&flash0 { + status = "okay"; + partitions { + compatible = "fixed-partitions"; + #address-cells = <1>; + #size-cells = <1>; + + /* Reserve 60kB for the bootloader */ + boot_partition: partition@1000 { + label = "mcuboot"; + reg = <0x00001000 0x0000F000>; + read-only; + }; + + /* Reserve 1024kB for the application in slot 0 */ + slot0_partition: partition@10000 { + label = "image-0"; + reg = <0x00010000 0x00100000>; + }; + + /* Reserve 1024kB for the application in slot 1 */ + slot1_partition: partition@110000 { + label = "image-1"; + reg = <0x00110000 0x00100000>; + }; + + /* Reserve 256kB for the scratch partition */ + scratch_partition: partition@210000 { + label = "image-scratch"; + reg = <0x00210000 0x00040000>; + }; + + storage_partition: partition@250000 { + label = "storage"; + reg = <0x00250000 0x00006000>; + }; + }; +}; diff --git a/boards/xtensa/kincony_kc868_a32/kincony_kc868_a32.yaml b/boards/xtensa/kincony_kc868_a32/kincony_kc868_a32.yaml new file mode 100644 index 00000000000..72577b2572a --- /dev/null +++ b/boards/xtensa/kincony_kc868_a32/kincony_kc868_a32.yaml @@ -0,0 +1,19 @@ +identifier: kincony_kc868_a32 +name: KINCONY-KC868-A32 +type: mcu +arch: xtensa +toolchain: + - zephyr +supported: + - gpio + - i2c + - watchdog + - uart + - nvs + - counter + - entropy +testing: + ignore_tags: + - net + - bluetooth +vendor: kincony diff --git a/boards/xtensa/kincony_kc868_a32/kincony_kc868_a32_defconfig b/boards/xtensa/kincony_kc868_a32/kincony_kc868_a32_defconfig new file mode 100644 index 00000000000..7bb4a23e794 --- /dev/null +++ b/boards/xtensa/kincony_kc868_a32/kincony_kc868_a32_defconfig @@ -0,0 +1,14 @@ +# Copyright (c) Bartosz Bilas +# SPDX-License-Identifier: Apache-2.0 + +CONFIG_BOARD_KINCONY_KC868_A32=y +CONFIG_SOC_SERIES_ESP32=y + +CONFIG_MAIN_STACK_SIZE=2048 + +CONFIG_CONSOLE=y +CONFIG_SERIAL=y +CONFIG_UART_CONSOLE=y + +CONFIG_GPIO=y +CONFIG_I2C=y diff --git a/boards/xtensa/kincony_kc868_a32/support/openocd.cfg b/boards/xtensa/kincony_kc868_a32/support/openocd.cfg new file mode 100644 index 00000000000..338e6e4e6ea --- /dev/null +++ b/boards/xtensa/kincony_kc868_a32/support/openocd.cfg @@ -0,0 +1,5 @@ +set ESP_RTOS none +set ESP32_ONLYCPU 1 + +source [find interface/ftdi/esp32_devkitj_v1.cfg] +source [find target/esp32.cfg] diff --git a/tests/lib/devicetree/devices/testcase.yaml b/tests/lib/devicetree/devices/testcase.yaml index 27be9c7c9e1..47e8d6cf9f9 100644 --- a/tests/lib/devicetree/devices/testcase.yaml +++ b/tests/lib/devicetree/devices/testcase.yaml @@ -18,3 +18,4 @@ tests: - mimxrt595_evk_cm33 - nrf9131ek_nrf9131 - nrf9131ek_nrf9131_ns + - kincony_kc868_a32 From 4d0ef142f3a3391be6e6d7fed0bbef2eda33c5ee Mon Sep 17 00:00:00 2001 From: Piotr Pryga Date: Mon, 14 Aug 2023 11:25:51 +0200 Subject: [PATCH 1845/3723] Bluetooth: services: Add HRS notification changed app callback It is useful for an application to be informed when there is a subscriber waiting for HRS service notification. Extend HRS service API and add required code to service implementation. Signed-off-by: Piotr Pryga --- include/zephyr/bluetooth/services/hrs.h | 40 +++++++++++++++++++++++++ subsys/bluetooth/services/hrs.c | 35 ++++++++++++++++++++++ 2 files changed, 75 insertions(+) diff --git a/include/zephyr/bluetooth/services/hrs.h b/include/zephyr/bluetooth/services/hrs.h index 097998f5caf..f19b2924ce0 100644 --- a/include/zephyr/bluetooth/services/hrs.h +++ b/include/zephyr/bluetooth/services/hrs.h @@ -19,10 +19,50 @@ #include +#include + #ifdef __cplusplus extern "C" { #endif +/** @brief Heart rate service callback structure */ +struct bt_hrs_cb { + /** @brief Heart rate notifications changed + * + * @param enabled Flag that is true if notifications were enabled, false + * if they were disabled. + */ + void (*ntf_changed)(bool enabled); + + /** Internal member to form a list of callbacks */ + sys_snode_t _node; +}; + +/** @brief Heart rate service callback register + * + * This function will register callbacks that will be called in + * certain events related to Heart rate service. + * + * @param cb Pointer to callbacks structure. Must point to memory that remains valid + * until unregistered. + * + * @return 0 on success + * @return -EINVAL in case @p cb is NULL + */ +int bt_hrs_cb_register(struct bt_hrs_cb *cb); + +/** @brief Heart rate service callback unregister + * + * This function will unregister callback from Heart rate service. + * + * @param cb Pointer to callbacks structure + * + * @return 0 on success + * @return -EINVAL in case @p cb is NULL + * @return -ENOENT in case the @p cb was not found in registered callbacks + */ +int bt_hrs_cb_unregister(struct bt_hrs_cb *cb); + /** @brief Notify heart rate measurement. * * This will send a GATT notification to all current subscribers. diff --git a/subsys/bluetooth/services/hrs.c b/subsys/bluetooth/services/hrs.c index 013591516a1..875129ac185 100644 --- a/subsys/bluetooth/services/hrs.c +++ b/subsys/bluetooth/services/hrs.c @@ -14,12 +14,14 @@ #include #include #include +#include #include #include #include #include #include +#include #define LOG_LEVEL CONFIG_BT_HRS_LOG_LEVEL #include @@ -51,14 +53,23 @@ LOG_MODULE_REGISTER(hrs); (BT_GATT_PERM_READ | BT_GATT_PERM_WRITE)) \ static uint8_t hrs_blsc; +static sys_slist_t hrs_cbs = SYS_SLIST_STATIC_INIT(&hrs_cbs); static void hrmc_ccc_cfg_changed(const struct bt_gatt_attr *attr, uint16_t value) { ARG_UNUSED(attr); + struct bt_hrs_cb *listener; + bool notif_enabled = (value == BT_GATT_CCC_NOTIFY); LOG_INF("HRS notifications %s", notif_enabled ? "enabled" : "disabled"); + + SYS_SLIST_FOR_EACH_CONTAINER(&hrs_cbs, listener, _node) { + if (listener->ntf_changed) { + listener->ntf_changed(notif_enabled); + } + } } static ssize_t read_blsc(struct bt_conn *conn, const struct bt_gatt_attr *attr, @@ -91,6 +102,30 @@ static int hrs_init(void) return 0; } +int bt_hrs_cb_register(struct bt_hrs_cb *cb) +{ + CHECKIF(cb == NULL) { + return -EINVAL; + } + + sys_slist_append(&hrs_cbs, &cb->_node); + + return 0; +} + +int bt_hrs_cb_unregister(struct bt_hrs_cb *cb) +{ + CHECKIF(cb == NULL) { + return -EINVAL; + } + + if (!sys_slist_find_and_remove(&hrs_cbs, &cb->_node)) { + return -ENOENT; + } + + return 0; +} + int bt_hrs_notify(uint16_t heartrate) { int rc; From cb8d6235062449b6e834178250b0e7916bfa3915 Mon Sep 17 00:00:00 2001 From: Piotr Pryga Date: Wed, 16 Aug 2023 15:37:23 +0200 Subject: [PATCH 1846/3723] samples: Bluetooth: periph_hr: add use of HRS nofitication changed cb Add example usage of the HRS notification callback to peripheral_hr. Signed-off-by: Piotr Pryga --- samples/bluetooth/peripheral_hr/src/main.c | 26 +++++++++++++++++++++- 1 file changed, 25 insertions(+), 1 deletion(-) diff --git a/samples/bluetooth/peripheral_hr/src/main.c b/samples/bluetooth/peripheral_hr/src/main.c index addee9bf92e..135f41667e2 100644 --- a/samples/bluetooth/peripheral_hr/src/main.c +++ b/samples/bluetooth/peripheral_hr/src/main.c @@ -22,6 +22,8 @@ #include #include +static bool hrf_ntf_enabled; + static const struct bt_data ad[] = { BT_DATA_BYTES(BT_DATA_FLAGS, (BT_LE_AD_GENERAL | BT_LE_AD_NO_BREDR)), BT_DATA_BYTES(BT_DATA_UUID16_ALL, @@ -49,6 +51,25 @@ BT_CONN_CB_DEFINE(conn_callbacks) = { .disconnected = disconnected, }; +static void hrs_ntf_changed(bool enabled) +{ + hrf_ntf_enabled = enabled; + + printk("HRS notification status changed: %s\n", enabled ? "enabled" : "disabled"); +} + +static struct bt_hrs_cb hrs_cb = { + .ntf_changed = hrs_ntf_changed, +}; + +/** @brief Heart rate service callback register + * + * This function will register callbacks that will be called in + * certain events related to Heart rate service. + * + * @param cb Pointer to callbacks structure + */ + static void bt_ready(void) { int err; @@ -100,7 +121,9 @@ static void hrs_notify(void) heartrate = 90U; } - bt_hrs_notify(heartrate); + if (hrf_ntf_enabled) { + bt_hrs_notify(heartrate); + } } int main(void) @@ -117,6 +140,7 @@ int main(void) bt_conn_auth_cb_register(&auth_cb_display); + bt_hrs_cb_register(&hrs_cb); /* Implement notification. At the moment there is no suitable way * of starting delayed work so we do it here */ From 3bbd34d1b636a269d4123fd346779b9ee140a83b Mon Sep 17 00:00:00 2001 From: Dmitrii Golovanov Date: Thu, 21 Dec 2023 22:56:02 +0100 Subject: [PATCH 1847/3723] twister: coverage: Fix device handler coverage collection mode Twister DeviceHandler now checks `--enable-coverage` command line argument instead of `--coverage` when it deals with device output. This resolves potential problem when only `--enable-coverage` argument is given and the coverage report is not needed. In this case the test image which is built for code coverage works slower also producing additional console output, so the additional DeviceHandler timeout still have to be applied and the output with coverage data correctly processed by Harness. Signed-off-by: Dmitrii Golovanov --- scripts/pylib/twister/twisterlib/handlers.py | 4 ++-- scripts/tests/twister/test_handlers.py | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/scripts/pylib/twister/twisterlib/handlers.py b/scripts/pylib/twister/twisterlib/handlers.py index da902cc5ef6..3a13b819649 100755 --- a/scripts/pylib/twister/twisterlib/handlers.py +++ b/scripts/pylib/twister/twisterlib/handlers.py @@ -363,7 +363,7 @@ def __init__(self, instance, type_str): def get_test_timeout(self): timeout = super().get_test_timeout() - if self.options.coverage: + if self.options.enable_coverage: # wait more for gcov data to be dumped on console timeout += 120 return timeout @@ -371,7 +371,7 @@ def get_test_timeout(self): def monitor_serial(self, ser, halt_event, harness): log_out_fp = open(self.log, "wb") - if self.options.coverage: + if self.options.enable_coverage: # Set capture_coverage to True to indicate that right after # test results we should get coverage data, otherwise we exit # from the test. diff --git a/scripts/tests/twister/test_handlers.py b/scripts/tests/twister/test_handlers.py index 931df46e674..d2e4b367a79 100644 --- a/scripts/tests/twister/test_handlers.py +++ b/scripts/tests/twister/test_handlers.py @@ -740,7 +740,7 @@ def test_devicehandler_monitor_serial( type(harness).state=mock.PropertyMock(side_effect=state_iter) handler = DeviceHandler(mocked_instance, 'build') - handler.options = mock.Mock(coverage=not end_by_state) + handler.options = mock.Mock(enable_coverage=not end_by_state) with mock.patch('builtins.open', mock.mock_open(read_data='')): handler.monitor_serial(ser, halt_event, harness) From 8caaea2f0032ed02c37fcfd8850ccb6617407246 Mon Sep 17 00:00:00 2001 From: Marcin Niestroj Date: Mon, 9 Oct 2023 09:07:32 +0200 Subject: [PATCH 1848/3723] boards: arm: lora_e5_mini: new board support This board is similar to 'lora_e5_dev_board', but with smaller form-factor, which makes it better suited as low volume prototype device. Signed-off-by: Marcin Niestroj --- boards/arm/lora_e5_mini/Kconfig.board | 8 + boards/arm/lora_e5_mini/Kconfig.defconfig | 11 + boards/arm/lora_e5_mini/board.cmake | 14 ++ .../arm/lora_e5_mini/doc/img/lora_e5_mini.jpg | Bin 0 -> 35515 bytes .../doc/img/lora_e5_mini_pinout.jpg | Bin 0 -> 50434 bytes boards/arm/lora_e5_mini/doc/index.rst | 226 ++++++++++++++++++ boards/arm/lora_e5_mini/lora_e5_mini.dts | 125 ++++++++++ boards/arm/lora_e5_mini/lora_e5_mini.yaml | 19 ++ .../arm/lora_e5_mini/lora_e5_mini_defconfig | 24 ++ boards/arm/lora_e5_mini/support/openocd.cfg | 7 + 10 files changed, 434 insertions(+) create mode 100644 boards/arm/lora_e5_mini/Kconfig.board create mode 100644 boards/arm/lora_e5_mini/Kconfig.defconfig create mode 100644 boards/arm/lora_e5_mini/board.cmake create mode 100644 boards/arm/lora_e5_mini/doc/img/lora_e5_mini.jpg create mode 100644 boards/arm/lora_e5_mini/doc/img/lora_e5_mini_pinout.jpg create mode 100644 boards/arm/lora_e5_mini/doc/index.rst create mode 100644 boards/arm/lora_e5_mini/lora_e5_mini.dts create mode 100644 boards/arm/lora_e5_mini/lora_e5_mini.yaml create mode 100644 boards/arm/lora_e5_mini/lora_e5_mini_defconfig create mode 100644 boards/arm/lora_e5_mini/support/openocd.cfg diff --git a/boards/arm/lora_e5_mini/Kconfig.board b/boards/arm/lora_e5_mini/Kconfig.board new file mode 100644 index 00000000000..1b4e30a54c4 --- /dev/null +++ b/boards/arm/lora_e5_mini/Kconfig.board @@ -0,0 +1,8 @@ +# LoRa-E5 mini configuration + +# Copyright (c) 2023 Marcin Niestroj +# SPDX-License-Identifier: Apache-2.0 + +config BOARD_LORA_E5_MINI + bool "LoRa E5 mini" + depends on SOC_STM32WLE5XX diff --git a/boards/arm/lora_e5_mini/Kconfig.defconfig b/boards/arm/lora_e5_mini/Kconfig.defconfig new file mode 100644 index 00000000000..ca35c4321a0 --- /dev/null +++ b/boards/arm/lora_e5_mini/Kconfig.defconfig @@ -0,0 +1,11 @@ +# LoRa-E5 mini configuration + +# Copyright (c) 2023 Marcin Niestroj +# SPDX-License-Identifier: Apache-2.0 + +if BOARD_LORA_E5_MINI + +config BOARD + default "lora_e5_mini" + +endif # BOARD_LORA_E5_MINI diff --git a/boards/arm/lora_e5_mini/board.cmake b/boards/arm/lora_e5_mini/board.cmake new file mode 100644 index 00000000000..ac24f811559 --- /dev/null +++ b/boards/arm/lora_e5_mini/board.cmake @@ -0,0 +1,14 @@ +# SPDX-License-Identifier: Apache-2.0 + +board_runner_args(pyocd "--target=stm32wle5jcix") +board_runner_args(pyocd "--flash-opt=-O reset_type=hw") +board_runner_args(pyocd "--flash-opt=-O connect_mode=under-reset") +board_runner_args(jlink "--device=STM32WLE5JC" "--speed=4000" "--reset-after-load") +board_runner_args(stm32cubeprogrammer "--port=swd" "--reset-mode=hw") +board_runner_args(blackmagicprobe "--connect-rst") + +include(${ZEPHYR_BASE}/boards/common/pyocd.board.cmake) +include(${ZEPHYR_BASE}/boards/common/openocd.board.cmake) +include(${ZEPHYR_BASE}/boards/common/stm32cubeprogrammer.board.cmake) +include(${ZEPHYR_BASE}/boards/common/jlink.board.cmake) +include(${ZEPHYR_BASE}/boards/common/blackmagicprobe.board.cmake) diff --git a/boards/arm/lora_e5_mini/doc/img/lora_e5_mini.jpg b/boards/arm/lora_e5_mini/doc/img/lora_e5_mini.jpg new file mode 100644 index 0000000000000000000000000000000000000000..8b22ba96ea6b6368ce250f622eb5a475742d07e4 GIT binary patch literal 35515 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

+CSuEliT4k&qP=5qTJb1PW`EowVQ^=KH?KZAmU z+jO`hurp7Ct=j=`cMqe?(y7XsK5m;rJU?N4uJx(TwRAO@AD{BQnUOw(?ZjehF{0Pi z05`D}!tK_XntB?uc@prn^^`qf!^Ava2~vhN5~@uL4il*0N1BIKviIGI+7?LtjuAx% zae00Tbuf}b>Yi1mKDKwLp}XMVbFMCZj(MvLl&*ZIHBa# zMK}c@hu#zGj+k{ZVhMgrMxp049aXw$g&zmc*Mf|rMS^+gp;nYZ|j#m!;K6`%Du(K z-T#@U%(P)W3-bIXRz!`0tIcUd3l}=~2cVPiI>Y>2f(-XpzQoC38fE|aL%;laoG>L( z6fKK}mvE#-7d$wu`yUNgovAGn%sXL^Nj0Gs+f_MiWM~ z5HxD^!Qf8J_K0{WEc|od57O5tT@^hvv`^h_rq(58lf6Blo2+nev0dQLlqT3Qyb@S$ zTtM6Rr;$+ZL@FO_IW@;R$(xvJlPWhU-6pQpg4nT`5LFQ>wsRCtza5c$+~W{hK238m zd!cc9o|}Yi@A5Y8&Dq`5)LV6IA^3RI<(qdYNZO3v4_0~9bkItR79d}r#WNW7#f?uP z1Oau|Fbm#xIiJ>HEOpqdu|b^i7UP>*jE7f?jl=%!qCT~pJ&a^nR@tel4qK=Q2N7_Q zxs}aWh0wu@ddm208K2pehS*)cPmayeh)qtcVb4X>(PNu#hV74bnt*Ys!(SUgBFyjg zvb9M9F}XDie*gkj{c-1ED(n;)jEol$4wN$%1|}jR(kUN{_KSOlCvfOu^Njf~gMM2G z#&29OlK=;(4+DOO&6~;EHQq$$7_&}&AM#0yYowyad$AV;mgtPQF(qitnW&b{CaTOe zNvpLTm|H_7aG6l0X}P;XEw zD)I^(KN)2wlE6_NEpHeAW7oNs*$VJh{|3B`0$xBY+-MO9m@bq@R-LzmCm(@KM2jpKRsIWM_MNCaF`15z1hds?Tc#i zzc?UY7}ng)__e!Wi#R^i8kBFBjOz#j9;^ttxiHsBUxbP~;MdrvBn(Yt?LgoJu)f2J zC;F-dZ#9H?4(CEUN6Ij@4sazu9szUqZv3A6#!F1IfvMCguktCkSOzs&>J2StGp*h&jHohq*7C;z86(en^Kh=Z1F_Bg9DZ5wZVyRc7S8X@FzYh&j6*JhmEL3~YKj!*1@*u17 zusy9~l$uF1Zy#aM?_xgCo?9wOeMp>9+~O;Rd)}9MXYCTi?p2zsS z@9(|e_4}>6*8S(M`;O;1vuDqqJ$v@-J+o&#+|Avs0*_=Qq$L12ICy{>{0H2v0Wsq4 z7N!6oElm&H0{{RSz=A^n;6MoWBY;Etm8*j=;U8EZgrEMQK>%Skkl8~p2blouAdCa% z&fpK0#^3<}``>a&Y5A9A?96Pe%p9B`H7h#@KN~AQI|ms%J3l8cKPwj~5!$%9v$H)v z3yZB2v!RKd5ro;;&W6R^(4K{jnUw_)eCBR%Xlw;>CNqMVS=b6u9JY2+kXe`rQD|_< zv&!3xLCh_rJRKn_o(ihQo>svdd%*q5R$d#P}0M;mgV`h^e$j1#|!ow0=p|1Xe}&CuAGje~=U!_*YQ#K~%8#Kg3mv!Sgq1jYyC%xnQNVdF67VCOPsXX0ezFk#{}C(E>ChL+gK+2gb()*D?gt7>5bQE@heX^xGXkC&B?la-I1lbxG~50vs38+C}I6KF3mR=<4bm+<^z zju1m}Kc) z5j6wt2-E;*MZXpovZueaOZS(~%^U(#9jF5)HdZEfjz2nJWB;QA7Epc`m@EDs3d?_v z@>kuzx$R$aa4mp=|12%SWdBY7)xdu>@Lvu5R|Egmz<)LH|33}<>u>_G1tT3d@aS>3 z4!0;RCT8$bSy4h-P8>XYfk&&4u)`6&2msjFIy)*$J}1-E(k27`Eg2d++5cPdKS7Yk z`OL4A831Kcaz?`VPlEqL8PyT&5TyAI{&38G!ElH$*yuNm4};yD?ZI;#93u=iws(ZV zA|Q8=OBya$&IZ-@Yg3BY5*Az;GY^#Men&fpQ?U^e$RAtE6lqrk)618WIEJgoL_6__I+ z!oh=MxLW|w5Wvbu2#>&7+{^wqivJNrAr^Q95LM4cnAuVTaKkc`^Hb=m5Pr4>0N~2D z&L*1L7P-FGd`$g%B3cBzV+gS8`iIRbiXRFc-NUx&s3@oS9HOrwuFuI+HYASaxSdX# z+lg^f)QHUctdZcLQd@%T#DbFw9q51?^kkxe@JVsPfIaWT_ub$y+rk7V%J=CZf4RbS zq2Hn-yY;@tlTgtTnD{uVyAx!{J2@JXWEbqOO~AJxBbJ#={W^#6C0Bf2T25K!9%)Ks z{qiWVDEmf%Ciz94HholxK4D2CK>9G;{Q}03P4}%cn zzx_rap#txo)5Hu>DQlsniP6NOzId+nC`p_j z%Cp&TgcqJ?iiBDr=d$;=@i5E2Dohwqc$;IH{_N837W1BU?v?dA%$|Vp`@@@+pc=Tc z>3?sCJOxl?iNIgF~J}CrBS*(e~iLg3&}Xq_x^uJusQ96-imt@ zpv~#9yxh8iT+(W z%?2}3)=IH-2B1cQqOF;r?(`S8(0vE)iF3TlnMCNFKb` zeOi+>?N!+2dST^N;?vbV4Bneiv^YYwUUy;f@{G7#|?#a}V&_+3T;wedS+iApHH&HSH z%JtU-xTn5u1H$PM-ksS1OrXp9${8)W{sm&|8)2nnl+7<44*UXlfK^sE?=rgIWM1ou zDb$noK=-nK_xk~->6D##{bamWGsyuy-~nlu+fjjbxp6pMJ1a`MY&ylDk_qa`nD zEv{X*mD#x9{$zWbFW9#+oyu<#y(ITfT2}wj&?fi7&z$cF+cnLdA^^PfDZ+^bf{h8T z=l%=lIx{Zg48jZgL-Ak*Cf^F7LB@N1$MsG0;mYMTg2`0upDL*nsblYTX~f^3^aw^3 zaHBsjp=r{K^3wyk|MAU$tc3Pgfa~MPEi_|ttf&}iaCJc0oJ3C_={J%l$p;C+gdU|6 zCtC}rfL7S&>jUa&ajXTz{xOOtGy$goM!B%6rXYy2fML@0vGx z&9mW6w1(aq#}k{q0{I?$0)PkQI|duQ^$Pzd+Frxjx2odJjIE&Mvtf!*V2zKTLOxZ! z01zzbyUi`T0KLrY<)(g)ZQb!g!8)!teD@#f_M+PYzyYle$PFOH$OhL#7z8dXaxY$@ z(HQ$HC5yH{0v^^EA$6AkaJDXQiuR)mDKodYsp&qYRCigpkF)lQ0rkQ1JwdSodQGOS zrVD)ma!Pw+RHFq0GL;^uGxDsb+6fYSHe@7HU$rPdwJcSm%y_aqt|;eNjj)x>Mx}*f z;=sQz;Ik99_4^bEAkB0B5P#|q)bT6Lxeh=vi?(mkc|oju=RI>IH8XM){ea(9+a=uq-$96Jq>!NEkpD zMXn%E|Me9hgpCoX(gonXmE*6RJBIL8I&l{Azrp%WK*BL%4+R+4;vMo#WS}-l`AySJ z9~x2OX*e1#_|Dxx^?U>1zD9Yo?iV9$r|bE{oX?vwBVnfd`zJIJnBw3pT_`P=U)n}! zt|B*Q{Ok#5@obJF5J7>?AlT=bB#<;~y{iy=Dwc&mLdScdt!TVIKR0#^|z`!9rz1x;k6Tx0kC!Tdcme`{>-9&x>8crhsRh( zFloAA{@cQ&XM(+*Kd6NUY_x(@oB#|+$%qJW7JT@zUDlK&$FcL@eEV252Dnm;4D6Q{ zhHW$$qlMazDnns}1jf&#@X-dgoZ9WL^e}41SG~&?6wR_cO5Z?|iV2xqth96!E_E%- z=WR-pA(f@eNps@VxIwW*)pQ>n&DamOA0(a~=q+h=b?oBiSvDxlpLM`PRRQqn*+hY^ox&t}`1C7Ej3@uvw;zs90P^BMUE7J- zWXmI4PH;i~&@h>-(S$b&uG4!unW*(0fdWOsHr&?&E>9YCYOJTJX05lY)mMVYlGQFs zvSg)P^J@w}C@aWre+xBpVFDHKXUD*Ij{qPCA~44WU*M`$A0eG*%gH|U?&&Al-4Y@k zXiT@fn`C-$htpjD{mVq=xt+tUntDCc#CkTDH2vxiQCjTc1bjC8ld#r*x1kxU4whF4 zOj*mjMH||p+;ygZL$8N&E-_tRVMVmiy>59D`X|aPAjjtOxu;eR4&k8=$!(>2$1Kx?!CT_ge*Tnr0stX3~p}JbQ1+m&%xIw9!He0Yw>QBtG`U5}#i&%=; zFdSS}3R<6|63*Bws+gey3nOu=m~gDN40Sw+gOLWIyD*FfgXUNG6)nI0)VYh)DSYKE zecjWoUes4w0n*?_0GPPGz>!5rQDWbFF^MYZuSkYHXfjz}%OK0%R?RS4eD#Y4wnGjc z$(B0Yfb+4jbdqN3@F+w-Sv=+ML~D^HA;Nc6(k2#wHw%eDsp{Ie)ZNNDxYQ*tbrLqu z!JYqCB9Yq4FeSnRNTnMYKs)~<0oywavp4gr=k7xPH-N+cPfN<*C!A9-JpCUNhCdAL z1AwP$jz<6-A{-nN3aD6kc-XxJ0vtRd5`c_}g^k08@(7QNm4g$PoQqq8oq|gA6(x;7 zc-p=Pp2Fdf;O~GL%l&fMa>15^F&7WSeN!c#mj=_)Z^;~UFI}eduPzZ>>nWf8Y_z!b z+kV^G!BjQn5@ivuMS_v8+~Q?<3N31>>QuzKnHBobIEB*U)KCnS-*FmDFAen`s<;D$ zBSyu$I&Vu2KDRbVxxqvlcrKr^@wkH zmCJ;ilwLPhuzAT`zH~tnAa@T-Civ>aS&*Q~Z9G$r6Z18|#QQx%ubRAF@gAXxp1hQ5 zO=pLdjqSI6F6-XDT&M~}2I`#b8KASTRcbjir0S|+*JqApU+zoUP@$^JVoOhNtVyC-qIvg%BU&fJl*xUay6Uw z7Aw4Mx>4=ybhCJ|zROsyfY-UtvivsB_#JV9b0)_t)YsG&XF`G71QDKZ<0jXvBdJ%1 z%U>6i<&5kzY=}*|P=~Hwd5h-4qsNv<)9*wzio2N>`Q94bV%I4e*Ryne^P6dvxm@Tx zdq{ru)-;Pj-RJbs^bQE0Ag#aP#o_QqN-%}>6+l-B%n(mul34er%v3m-1Zj5I>g znn-BNbcAchgstPY{;1H6&eay!G_>jF4!FuSE%Cq$|{14HE1L&v$v72jHSmVMCt~sXxNSzQ?A;nZZIjtUlI>dBfy2DshZcSi0r*0lpQ~Y56E=GxFScU~dZ9 z*hcSwh>;|p%j5eT=vvb!`8Z}cc_pTUPsg4}D&GO@H#a7FSsx9LF`67dQvFmuH^iT^ z&KD=2E2jHQA$ghEloq$&%!g@;8(~#&z16HX$$c`WSCka#yh5nyx8bI!$L~iRXCs(7 zB}>{NC6NcQS#Wtl)VFX+dQ5b>;6YdtkBO&sflYP&rP*yGmvQ~T!GwZw*4Bx3ajbLG zv~P4~bJxkGxn*hD*0za9C%xhy1Zn0C`>0yO(sQ#%seLpKsF8F$>9@WGbhPOEr6-p7 zBZv=z<#{}vZv|)>(2nh>!w$X-wZ+dG6G=AHmKO4ceXVw^9;Z3i6mS&_?PxTxU{ceV z6L8hPy)=8~s$$Sd(XB>}q^7vbF?O43G7IjP@fqbA8zx%}w1jvHCw_yJ5lk{t-dL)A z_UocJMs7uly1|c*s3p|M1GuEw5*53~uXuft!Iw)!Xs2F~2(xW(Pd!6=ENjL6Qg-Ia z`uoL$tumh&Vq;xnUpu8e{g(eqcQcA#V8$%-M#y=4cjs^rV`(}oKKhsiGn`ut6T!0; z=Nbh;jpDtBz`^6ly^lBx8mJ?(h#FE$^GOCCOjfZoQe{-;t;g*%UUBVfKi|~}9&W#N ztQOqM*fQA?pyiwAjW@AT2&|*UWezOIEx}!R0e0e=S79P9!hg9>yjKuYV!OQiq|)iN zzy63t`P$>QoM;+3N3?8D zRj~QoB$-c?=c|k*+2(Z#lSKY_J(Ld@%I%czq-av?=`a*YdLHN<{;enIk$8OB3@?bDJ=AzeI`kmgEexcBC4{`$HZx zP|~86iW3!?93{&4#%)w%l9&RE=kSzctc0P|QOc}#pJN8-ka-TTMou~lW$58~LgNMH zQrAt!v1w=uY^Qz}O}}y?RejwbYKE@m9SUvRz(>4MlbUs}j2G09e#ekMj-zT8y2J4S z_sM#T+>sv5?~0hShq`q`aZlHRiWz7KRAVL32(N|;Q=hUSz~44H6n;cx?P{;g(1OC< zV`Z^2!*lKuLn9W|;+)(-e){V3j6CPOVKDyV>AGA4uZ`iXj!{osRhD%fdw@%GnbC~O)&ANju68UL<{<=R7(q*!4*cLz{7AMW3GkcNeJQs^%t(#-;FUP;=Eq z4mH%?f=}j^iDi9j%H~uWk2NEE3hu2K^-V^(ADEBBwcK~0p7xXj^-Uzt>dp5+@b81I z&?BxW%I~&YHUD%|Izm9}LcgSe>(gAgzLP|% zlg}&jM2R@m#)~BORn>QL7PCCuPKGM)R6)QM`^)5DB7w_vK}Ddp7SU%9$KW#?m`$Ncb_OT+o;5WoKxN73G}5!G+s)**#Hi zIgeUleu&KTrp_R88)lc1*#l=O&3~Ww$!xAg*_i@ovwI16CjQAu{pkdHIbVCl=Ni(| zx+a(HPlpx?z0f7!2SPPUP>ZIjKk>LS*Cb%^N~9aoXs!)WNh8-My!^nCmoalZ{4|aj zzpyDmy*JK0IN6F`mhLmx+gL;Uf(RXL!;|CyVriy6JS|;mDoHJoOktb%>wUxpt^^B8 zZ|F?t}Z)#&{ZFf(X8o(_f;itMPh7wFkG&TR4+h==k@Nl+GmJMa;*qFsBk(Q>ru4UTIH5^J7vobYJ#X?qsX^v#F+TSo;Eoe9$ePI2} zDx`?djfMsVp;cYk`1){n66Jxr!+`*R72v zQxKAY6bO-=PXSvh z&a)&dVGU2`o}YSKlqs_BCsCg%JuF8_k^4-c(YHAGVmXczv#kN^3D!`{yY?~Vnkp~D z_gy$r2p++G&aWw&_bnN-DUO2P43pEZyllbI#Dg-Y3su#)L6!mqcUK6 zjLH;yx~OXH_+8~5cO`H2;%jfbX88wh{ocR?27v$&!Au-tx;Bk}?7r&>O()}oE4C+}>roSH6swglzS4y*44nL6|lUd}iwqE<5L zhW(U|+a(Y5lY)j#MX%hZGVSoTUAJv*Y&~P)yL6A=*jETO*BFL;O2})DTWe4nJyb|B zuVOgq}B~k@OhAlGY!?1$mME>DaC_ora#6;mWstK6<5ilS!;B7?t<^&c)IONwaLCj z6{9~2DLn_~PV~LrKL3CRQuZnHNZexL;%chmQ|vZxc$B2-SzC8W`eiqBwzx3hMKS4P zHFyldW;b`w4>~cc7PXp^4lVajI*Z&8wYu@_#WOI??&*g)fB0GSfQu$4Q^)4Z1Hq%9 zcLEyorI-igLY}FNp+?IpNMp60=sk?iF;W0N+-J|{oC*>5=d^ty1P&|n)JLY0j`o7S zF6%Dq=A6@=*wSx)?wIbcTIu|9Q3tL`8s9&h(V9(VW+}V+NY9_qx>5Zo)pTXuh#&st z+*t!Jj@XxJrb@r7q{b??Rr_a?dKa(9;m7I|A^9;|@jViw)Fi=t{aI7uzQHqWz8|UD zkLPOB>I254c%`15d^N}jSj}#F6+BVb4!X>c-{Zkdm7KB-{O@v3q`y0eH5^V1H159x z))i~Fz2;SBAoH)?ikTnk;K{#6(vmdSxqszVC!a~N*V8e@LsK3t+!ecPWA?7!EUV5S z{MV{_o|ir-Ird!G5%VM_IwR0e{MV|%>0O*9-;s=T(I_5berEs4XgE&tm8 zG&>dEN}4TfA(cGBi_Sir0PYh~V%%iqmWYiLRlna{3h`^d6x3E{+yLF{C*F);3kjH0AP9aupC zM=-12A10HD2S+fj*&lY5i3KDLXiJ9eRG#CWbg^N(6N;DLWu=?jzZn<$iIy@BWd&T3FQ~`$<5Y<1I?Zg$=-|^%CDu}@ZSz~*W0`8GrJC8M zxA>k}vP(5oHR*hkLsMLqNZ%0G?|E#B&PQnSm|wMffYLgkGLh9`Ws$Y4NHduHiOZ9*Oe6e2njDAfLqg9%-Hj7W_yl8`)(OhOs&pRAwFZ~4jb)NLq4$JiC!|5Vvj z;yr|ti+v#gEvhnKz8vh&UAnH}a$Rf~Pwi3aRK8yQxsbdWy;OaXJ~Oalr{%luQfJxm zJaRyb+9v9T&BCp3RVeNA7;F z*P*IvR$V$h2d#JQ_hY*Stw#Gz@7ywX3+OaxsIa5WJl~U7>v^@K*L*v^l;tZC87JhA zm9N)g4}1$QM<}Pw=<9zTIF74{(Q3&Q%Wvq`xPFaG4%>ZvAf-{3)V&yorcW{V%>KZ$ z^|$CILF#X!tiPo5ZjSNQpxcy8oair1EM8EL*=x3A&%Jjr1UsI3{i z{FEfBrT*3Xn=Dy*nWOMz0~DQ~oinMSGR0LXmXwA+aT|5fWI(x{T)^T@$JdBvcKXb1 z-TgX>l9j}l=A%s^?{MI$4$P^zESXc9tHS(eUcT3db!`=ROB+%(p5^WTaT^-ae-_En|J zY8{9#(obYMy)fG9*dn#Qg|k+?kRA+Y`?5SV7|yt7#op_dMoAEv7P2iaVLL9r%`CB3 zy}WsE##V88lVrv|KDU&{j)x~b{T~}%TCx3$SiL^n4s!i=Icdf(w$qBNeZR%B2oP&RoB=^9g?3Er%Bmgq3KlG_gx*v ze@Km*oM>yV)ztvo=UhR3Xr1q{{_>%k#)5aCnugXj_|o?JR$69p*mR@qwWy{JU0En? z?AURszrZeazLj+T@IrM%G^3a!5!o?&Oci#1T;djZ^jywY`@bJi} z2ng^fu**yEPj?V75wX~mkg#!Z$=S&$SUE&QUn)C1dS&=LHs|#OC8v>ncFo$a%S!O0 zp=WS+K=-&5TszzrHw#^jhkW?3wf@VQ_iGrWb5{}%9OK7a!#dV(w#>^8NLT(1Bo@~^ zx#xcUeCBWiySQne&C2aK#Jt*1I>`SEPZh5wI!C#_gHrl1t&-W|-gi^9?v!Wh-|QUy z*xCx6pS^#UY8NxA&Qoa|jq#-PHf2%fsxAke!S3{i=_CuHn8bssk;H>h=B(788GXVq zMF@v~2N)!LJ7vjx#dinP7i;X=dfj}ZsjaWcDngjB8hszB_hDl-I=#kgd?j`Hq9UtHydnilSc$=G4ar)R z?N_E+FEf7zJ2Qg%Nd1GGcL$~P;q1w`6!)JmQF$>FO1e+KK^r@^3PZ3=2Q&1}~p$xI22G?4+pG&+{^(iHSbyx29R(LW-Y zC)4`Z)`fA2@{qCH55CfREe|SOw8mr}x{+hZ>J55XGIMG&8YE2VFN8mgJUQJLa301( zh{ojVcv|k>=NK7FsI>Y#!c={Okb*mp@;+OtUU1`Jbn)<-1hp%{B86}sLxTjhI>Fcr zuj5u#BQ?YFuaccG)St>A{KPpc>yV2L*W$j?Uai4sUk%F$nR2d-KPafyNbSwX1_{Jc zs8*6evuklz8o)nfjAtY_K~zS!_Pw}Z?rG+<8=FAsfsvcqQr|&YbLg_0AIW^M1Vv;X zN#^6qmCCV4G^s+?o0crQI?u4xf*Y489}2BBIxu#$Kp_SX3NJoho~B1PRGhO~*kl?X zT#Yhfb@jU?5^Z@Xjr}WIJ9?%hy2eHtJsI|h;}mD@>KSREBI^&c)`V z*1YG9MC25%;e2BgW_$~bTLR)4Tjq6HUCn2bpT4bOnZlB#_wCG~s}K2iw60=Ok#heP z4o~@QIFvv|S(UBx#m5PAZG|5;ek~n7%2Aj!zf#fozLop|o}2a!v}N`nbEebzpy6kc zOLXfFR}5jlOBw%kre%L8iPnNXb5U=!D|QIkr@@ zk>Sc2k0wp5qjY5Z4ox>_c;EGxLr>{ydHTzcFN{m4Np%sE(a47VI?W|Z*QN=?>hlTTkh_h}@Nu6GBC`0Y^@=DutkzUvCs;UsZ&%?)2s$TU6l2$=SU09ORHU zuc8{5e!xI>lx8LFG2-*GHW%YbVS^P_%0l&7jA`107FBN5T<|NH3NNc1{m9hBEz%GvY%El6< zvyHzQdnDmfYoHL}t0yDSZ|}~QYFd~-al~?7(YCuW3OzP|GI+yw1^#JQkurqewBAH4 zyH=&pO5(*Ho>Rhh+C;1XQd}m7&N}U@x?N(z1HTyo4BT5<$!cwBjtV@wzHe2|er(r; z&KfPxQdU&1q9>zB3xfh?qys+KVn6S;q8i;NhIF@pZ5N86#lh5^2*3!VS;C+X*h9e9p?{$RCiCVONt12+GYzaJ7TEp zK^n~=F;xB_O(V0f=}FOrJOhdYqoCncM-b2U;O(otSF}IUa6XHYj%drkn~8hnT}Fh# zktu{-NS@q(I)rdWT0qIbia1fYGk6Pead|aLU{@Z!iTHpsyruS8s-6zwB+V)12^BnG2!u+WSn=}w~{R7I|!>|RaAXexP z7|pVs1!ZGgpf%uJ$dT%Pbn3qW1IR)=MI6(7q>3>^R}d1QJ3%553g3x3D5BjvLf@WC zz+BYNM7=eIaSwIO6>&=d-YN4n-&j}19blq#_;^y#&p1GIFthf+sZnpt^<(qcyc^#l z)7Bke;Rl8f0+;|C0z4u-@;yXk@Izr(_yB%NjEISZMb3t;ghR$IBC3r12p5bYUOI3Z zzK(tVDyOD{&)PaHhL3RsW#lKLBDlLeiK*wPL}TLpO@a|Dr2`UQVQ9m zt1i#6X#U=NyRYTtKCW6awZm$OVKwS>P>EhM9C`|x?rwhbIqUVnBi=b)A8p^+Qr}6! zQrTesp|>laN}qj^8zDZ-S#T>p+zB@!cENkCCqA#CqbJR=tn5SOtgQ8h6oVfZjetn_)B)FhirZZBbKY#22&kaI#E8#>zT z6aRHo@cG4T=Czu&O%{f~{`Co?gW)S5!6g?NdTC>yl@Y&(ZB} zAnRW-VcZIdRecgBQ|IJCcJO`r{p!4}aTvy%Vf~xe73($9?k={I7x$mkeIyiVh@LLA zpnXBZ6vr8RIIxp|27YKu$5-Yto>#8p21YHiEk3Q|B9F#R$LhPO`d`9zc$Zed32Cp7RIN8$)6~s`Vub`eS6x0+q6fqO?BEq zWV2zbq1HuLKIOS$n^&*fp^I915!A80fWyVx^Qo!z=*V>RE!s_w>k}@jSYff|2a_y4 zzBxqfmV9f@!58G75)Vq!P*VI7Sm%p(a@Yx%g0`_`vyCNFCEv=5YhgTE+3RgNl}d?`jjyXrMQGIA*qnUo3F`?;7`m6Wk_8x4=68Z~0Q zdjyF1{1bN@O(FGD|MJkYHKk8Ok|F)`4-ftJ-hJ;*9b9)51f#!?rP}8sdr^2oQ|9jr z9AwrLKQM&(a-^qdaW#v#oUTgi9v>o#P<$|aw-?81U1~9}f*JV}7ai+Gq;u_K$h?{g zdm$y^6uz`|r1#|Gjd``n+EQ3q$vRg$pXFn1c|Jtfo2S&9u~vz3@^Nf!c^*X9gQ%ps zXXr(pl)l7pZET{$SI5HM2h>=jY zdw$Ffmdm0k6S?uVo+ep57@Sw1sI3%?Qk^r5(&wyVu?NfC6{!k=)@sZIM#+&3C(STK zHntHref+~U+5W`Kr5ZQPd!%WvBTZg$8ToVVdAVJQ=_M=+%|~9HImbEhemclxa(+Xj zL(i|I@X`GuEd=o>38z;_jvaaFsfB5pJ|p-a1d}97`?Zm&gvpo1X9XAe_IH4H02^fH z>urGwsZ+}mLy&zX?tlYCjO4ic{h?X;KDEOgu!!VveLq24z~^Uy+gjH7P9)Uz;1PDe zYth+a`@6cF$o>P%Z$}=Idug9043`=34Gx_Q-xE7Y}$TP`_41%rPQHDLw3B|1c7cg?iPI<6%WOW z_ES@2O-+6KAv9+ksEm9}J(2shg;O_KB0P?B!tsD}AKr~9@8ZyGRqX&*q&-PI5u&B8 z_BLGX=+)($a<4$v=Gx{DdF}7YSCh=&D?94a@zHXPE-S89Ox5<@YV?mCSP3+jA8gjO zri~r=$q8ANmA3a3bJvcj8`a^alz%Y%OuIgOOZcFf#advvz50;;ytl1v5&bwPLg3?R z?{sFtNVP61A2VV`vSfT5j_4i0=EaRmLwx9!&SE+Q+1o0vo>{yVN0Se2);Y4g6}w%2 z8T=VfI+fIV9{%3@gJg|A>9ES&OIGGw_rbh93#6+(8U9?Cl;AmKMu(`qtEwE6;bd1P z{~4}Q7xU?ozQE4ZK*RpX%CUR{-H-ZL^SL`|jr@_wH&d4H6?AEtv6E3h1|CLIO+Mju zz*trpF+pDMbNTYBxWd&B@kiSEhP|dClh^uplI&I2GZciT;zzD$@aQZ5Q4(F8x+mcI z8pZA<*{(15W-CZH7cu@s zb5sq9?sc;3hA|X>75*G??k3)oi_7GB?BZeRfawr6p%=W%&!;UyLe4h%u5W#8Yvvtm zB4|cw4Qk)yL1$|cqCOo~%#cMoA+&x!1wX~cIqO2F#b&2|z#Lbz`ndv)B60K-JNJpI41QI4cjp8BX z8Zf9WTonyr=hyJcCj?1l;KF#)xdzl^UcGr_?Ob^wHT%KX5$#Bvybg6*3E!}fS9Pov zhGXX(#Ze|?Jt!td`8W9UGR)=X*!Y*wJ}MrYq@EdOe0(DiPEZVVQJ)1dNgjtgtU5pt+1uw!>MVd z4i1O)nlw5Fg8sU+H;67wx^{-G-s&7;)MgLMw@M4U^`y0j@NJjpnS6tN<^5KYYJrFu=E6p^rxKAvX7Nu}NZjE3L!my7=Mc8b)5l$g&P3;-$2vG1}q> z<<;^03aj}tuW^EB>|Z1|bPB;gw=v52KK%i8{Gsm4g3OwO79E`U zMxj|*GxzdKjGrzN-)vTD?6R(&&e;-QmMaCF_^-$Y7(3Zb_akkRnsnLT@AtL;Nn?vA zbh3CZw~s{DtX`Y!VuY*WB#5Y~Q(F4i9u5z)g?ObP=!h>b?%YQ)(Mz~!xIIf{Lw~&F zIOnbE=i1=qo%gTRS%w5#MlpDJ)K&>%ePtvcBX6!;A5K?w%Gxy3$0_J8-pbTtt1p6) zj-}(5r2UUKNt8ckd^#6OVr$t7g4b^aiViTZ<9|vmb}OF1`&8tnZz3ME`#-wsprl35 z7dV#43lV7w>mzxhjQTZ`H^!gu%)zWV5on6z5SB#yi05Fvz7+2zYHa63PoVAnm_+&> zI*%gv)0Q1Eqbe8Wy(-jWGd1SnRV9~C2M6R)mh+>Ak`6f!INnO7S9|te5`~B3PUL~h zuy?XVblkUzV?6?4gEJN|FjfG+{zHI6L_&T5{y`rC0@Clm7`#^l<6;VSQ6*LmLkGuL zq(?Ypl$^>=uWPzRp2x-Kh#A#Rtl?5|y)+K^POb9hRYJbAe{RpwpAQ3(pMf6+LYZr% zEojCIVsx{Y4fqEcol>ga>SyDBO{XL#w+a%S8sd6~6VhJfG>7CFqO?H4WfIvYxXWSf z`sR_B{0@+Ip87zSp8N5>-!=BL`mzl!t_tBWsA;vQ$PlqhMF_St?oO@WJ~VSp0#Du# z&~n2N8t87i&i!66p`7MT?KjLqu!6&RLQV1r+k)R#AOM@?hF&ujurPUif@iaP{L3s1w9v z;8yUVx9Vb{KQ1AbljTel8k(_^dRSkro_C03xZ^jWrM(Nuz$TYTYnAAPV zSRv?M{SwOkY)Y$y2HxusL*`@A6tn{eXgHv8b2b_Pq2-` zmJwF=(n!;4&WW;(D<j(K}C!A%R@+!JOo z(uB2?A1sq-^}Hw?ER?m%D<=p2ELVl_l}0TZ`6b?Od7daf2Tg=ka}`1Rxs#AZwY!9d z+;|(2ovH&8Khz{y;^$~ye1*!e0e43OFP-&wQo6)0r7`%}(<;WarLEfcOFkk$$OZjT zwQYqnRA;Q@^M|mtuejetM=5&oOsmG=*w!emq_L?VQY6yfD^H5YCMK53UQZQDQXvW! zVNeL{pVy@@U#NffV1q4bdznLl)2RvtJs`6AAfG(>7WGSaU-tu_co~<30iAbdK`Rq& z7#|2-QdYl(zZF%_v95n2MzGj`fHqy~PU(yt?V_e<*W`gariDuN#wbFR+gq&ey&MK?Gc>DJjp_%6(mYoeB+dzpbd z$sDJ0P4AaN2J*RDfrA%p}!ZU}7HgDf!UrL`nr z5c@LNHMNT;f9R0JkGtBcZC?I=z*-*9S_? z&CLhQhwABffNP-3v<}?hW9auXJ4mOR^`4Jf-sc6tNPtw5fAV23q9{o)|soP4ApaVd@BYov9FnIEUZ53yq-_nR15acAU#!A zv>%T%iNu{4W|+z}4J77(gYbTu{aR2vZse6=;F*UoRo~NPSo30MmR$yqbpT~PnCh#g zV$^_$LSBLc21@mkx$T6(+Q_xIMPamfep?TLYMh?)_h*Mh+DE5!GXhNE5+;x3Cv{ae z>ci_sFMMLx8@-af6KiwRMz3;2f12K?rM2l@i)%eaJvG}*e|uBE_w0ZHB1#acKJHq< zg>(8@qyiVk5Il4UIuek$+Eqo3ig;9&D1Gvs?xZN6zByc{{~)SYl^fiD%`(3z)-@q* z)Ts3!kEXstn5Z;+rm1HvL;SCDv( zo16PC>)WFy{7{JI`FBngy*hqOVh$H8gC+xOOcaL}!QHXQC_yPz?Fxjlm}zrjv3;D_ zNcU}A)hO<2-)}`>aS{XPL25Jgoc1L2LOH$p^jtZ4;MYKHBbRcwBcBG8Y;MB@f)jQ8 zazh%X+StH6>Pv}I*y0Vg7_m%H(-loHe_FBCZ3tIXb}qrs9}ML#NZ6vjxA%96MPGa} zNL>xr+(G3(@=w_n?jc%e{R3zZ^Q3i+U$yVBF358Rkm;NYz+trdCkZ+D2bsZo(!b$d84llMU_Mq9Z%Ecp) zt|k-mQk&vhCQhcGB(9h?w7%pwEsFEqu9zNcxx_ z5-SD-o`{H{84yaC6vbu0fN({19)tV(NtU-8>A| z%8tAsC9@y*K|ZrMHND2Z_tENI!$S5pBc#!ZIYfp8ovY9Q5>!xS&p4D?$Sa%PNc^TJ z^swvR50_%JCj9}K2l^NjTH@v*Nndn{{jGM&o#|7$?}gfIbN`ggox7BePTo?< z8=L<}o<3^*myho{BoxLoaFSew$E*)M+&iG2>`u9lArBL@AMAceE_)vIPMQqQP&iq= zX{=$#Ckd5kv5Nz9C7sBAIWK4l8SceJ91!jH;l*ZsC}*Aruk*Cl4vS%;dD_fSkSm?G zU$f@P=OnL0g!!pGgOxTsYEB4O=L=3#3cc`cI!>YcA5=v1@JpZZ|8yx07i=PzWBW)= zEXv;+q+&4;bl;ZD@=)$!;VcflMQN&}hE5pQYHHgw5ktVM0=A8D1Ip*kh5r|GZxtO! ztSpL-DQ0H2V`gS%W@ct)W{jDcnVFel$4oIp3^Ch@8DhvAC)sD;v({bj=l#4LD`fM02RIOLa&lqKl?Ewb4)IbTM;i}@h+FnrslSfdA3 zl+Umw@H;KWlkDdYG&Gse2`rX~!A#M#Tj&m_HQrbR&oRU+;#v$U*_YLvwx(Ng;nA4^ z&L+h+4Y;XzYlzx5K%f1026mCSTUbrWu83lHUv%vuF;qX?=A9}WX`FI4#f9+7+4n|~ zjI21i9Q}3nFhK0o;zpq8j^!zT-aGSU_PAH}&Ei%~U*4kl=jIw~JxsaS0es*3SCw!Z zG4QaNbL20X=827sot>XmCO)0U)C1MsQ_m1zntFi`@-z(|h665_rZ<)JcaQh*ZvgH8 zCQuKbWy!he+7;JAs6ZdIw7u^9S!(4NYL;>uq#{<-EPd3Mx=M^~&T1ki$4Q5trNQ;J zZV+mki#Skqjs!nTgKrqMN|<>@(h!{#rucuu5QWVX|6+3os?J;1EOgG4xu!Lm6cd<~;$RbNpCo;}K@FcyNGaFHSx;%BZ z(ZJ5ms&Tj&z@k=*>;*V%7B>JklXA-rYE!KMuBGm&NZVeN#Y@fh8ti#$5R2RnPe65M zIOX$*32L9rZvgf$8X+gV$v&yK?=M3w+ay?e*UCQi73$ezoD&%V<#+1YqpimO@x=0M z5oV}ozekmNJ3B=$yP9DxB|LdmE4r%HEC*X9WV7r6zVvAW?uA?Q*#`SZ&?}4mW~*{I zp9NS~_pMwuEkSD*xgVf5k``LmHQRTiRf}dm->VPI3jayzSp@{k1S~7o+ATr2kz8dN*TGrf4Vbrfr~Huf?grt>_xLj*fNzz zDP@Un@FYx(bwg%FKmV3>~FE~TliLuL6Mp1#iBdEcPS|qL| z@a93CmiZ=WST}A$BQ*Dtxm0D%fGKM3Nm4~aT_-+C?x|^FcTCPgyk(2E{rc@XGQKhP zv0zJk$%vqu1^lnIy=~VP^@%Q9$zsxL>7BNdn{8%4beJFLGJQI=p6Q;bvL>1GWuzCK zqafF0aX3_Qip>*iyZv9SZM2m@ImpF$8=AO{&w8PL1HPWmJaQ1^EN$@Y({?e@9m^*k z);U!Q&svhQ+6n~Mr%Jp{E&bAq?O-IAo-V@)#b!c7r~`rCE4@EZJ+`5V^VOok{tDl{_w4tqu?{-_NHcqd6u?eYhE$gf@w--HF~DO+(u7Hnu~kp zdSS&-j%lW{sR2~yGdni@rd0)id>uQM1y7hDH}-XngF?jI?}1aX-w_{XZNq`w`w9DX z?a6EURALB+? za$M1czmYY38)?IROn?IhtK_ zm^@Eh%Mf&#hEVL~W&M_A>mcE=m?CF=G5%C%-*6)9 zx*&db82mFEHy2KVJ83}P%zAAXaw}{XqcJG>h7s%mn5p}8f_U^N+lJmv-2sh?wSHO# zrDlIkRdyPVgU~0+d60z2}voi3RD3RU)DlHnp;5;FXJBD~A1 zr6gNOtpU#DIefuZQXKWZczP=iC#Bh%)jI~89LAk;mqIr1@Wg5%Q7TK~m9QJXA6x0d zI9MTW_#s|RfM&T7XY$5@O)Q=z8UOMmkxT0zTE~4 zkLUG?KHW!qq%H#=E?FppGVPUF70ohy+fH|&7rKHf25~P;qjEA?n+^#@9rTQi57~-N z;0`zWONZi++mv0LrY@FDARP0W>t~M{-%bQJdGA}YVD^CT_71yeYS;J6nR>?xHhO*q zb3F06@I}&FMwLbIaQS%bibl1Pb&}e39g-a3S^2@;s8+hi)Y4XL#nTYDst__&XI(`d zMN*Tj15%jROUnHB$iPYi;$1&cD@?UPOxC&tgE2q~5l6aBV7GdK(%6G@jaj=cz*udw zy?2D!R+1Mddv{G{o7$v4u0v*n4yFxmQT-PhIdgK9)qZ#TYThNtz2ZNqyRg<{JkX1y#8tmILjF|3^b&-3 zVL0lJLf{^4MUb~NV=&Ktu6|x?-tG=hN>%hCZeG5si_7z?`3 zbzMS9M|d+fsRgp{yHzTk233jX~!lVw(N5UY;^G%i&U2O zTy@Tb^DYT*kx#tA*+08k=6$92&aGO? z!(zh|CuJ^|_b&-tD$q;S!Z)v<7X9NpWlEZ z2tDX>?YtSSnhOaVJl^A?U^%onPM%=!N39XC3!c%pQu8)B2+~hMMG=gSzsj0st?ly1 z^J_<|mS`Q2qSxCq!?xp6(QTT0m#$jxb)13+UQ255kuT%4k|!hKRDq$T1U6>$9s^zWq$4kyYwt!MZ^5 z$vX_zRnR|>{6f6Cn?5`hj`^Cne{XfhumtFs4sC2ub5Vq7{O8#g`IGLcPwuqh_l z^_FtB`%H?M9h}!M+_P3moYg8AMtUuiVE7)e-)T6TCSkug)eiBF_KAqsdEDy$JkEKh zD1l?;Ny$^*Xf37G*#4=V>6&}yytUm+?gyb~uWxkr-SqrvP&I~%?cEFklPXu#ChpPc!d|U&P^?L_QoUYg%RQ6H zd=Io|O%s`H^k2THb_}sGq=|yH?jFOqqU3?Gj}^Xn#4$}mIvWoa-{Z*nZz^j_TG?XB zYI;TOSQf4ZKoao6n%lPDpRDB{`yRZXx6Xcg)c0;Tc?8f1nDvtqlclfA9VX{X#~u_} zW^FWWjrRWrpc1?BtDtq-*8s{ zJ9J2Lh7EB3w%Ptb_c|Hi5iL;yRM$1{D0cVEm6gL|RKtq_j#Sc9WFNwlM6^dHX(gme z4$p#4wYf61e?S*pY2+IRA|&)`GYqJiGztc+mzjv+tU=+Q!hN9Y^Oo+~4GvdoRUTf5 zzF@S<(2-X3Q&}SnX<=|2Rt*>kO^bA$Dx0RRW1cuB9cWkd`1mY~V~(+KL7k6lE0)wv zu?1ho89+KrBa`W)34aniYs_x3O&=iV|0yoDbP8b^%-b-0yufX5KLUSCDyff&MCU>N zb`U;!e9JSr3c}_k#Tg^wLpPF`brD?iu|AFGCg^qSHT#Xwh;kMApy?b}xA-x-w$%A_ z3;P9qqFQm(WRZIvhajhV?<39UpgSuxI)trotLgCZLXMy{FsJ$(dDmt0b+E8?WWD1t z^kfmT-3P#LK&ogbkQS?f2Y;jRLPvt~m&B=jFdDjAbTx+yAONc4Vpq;!Y9i7E=H<()h8?v zS68AJm0ZfY*j5+`R?tKCOJ3B!kj6h~3&^$=A4Z}D^bjUw7@agJ(A7|-kY7De4-ABBzcq)SPk6<)2=jtx1P%;)>b0jX`wc>{ma)`PBb zvu(_SdZlrXN7RR&3wfZ*i$`yP6n05s|NRfeGyVbcZAZ8dobWlV{!-yhM&ps=KtT^*fGK5l8+Mjv(bhGyBAuQVs`Y{zZt<&K4la+*)|z ztQ~0LeFi<-bg2VqS@;z2&RL?xwG2Ad+0l5S(_)yP;9Z4ZoSImN?|1@m2P$pv)lcw# zskmR3Usu>e)6Z=~MkURfnJ3Pa{c=!&Rpn-UZs7>p%Y{hIl0ZRlRbgMjh{C!M6l=3p7Q`aWww z)`BsoBV-5B!oTP=II_?|MBk789}gPV&YqPn5~e{E@|Tq)F-M_x(vd>EST9lyaENiH zV^yM>oC+Z=F2yBNMFjAb;5BcMfvig%20>0#eOR+Ekf1h$w%x#qqUf%kXO)(+XS;OV zxU+o-ONa$8-t_%w)h&o(r;}xMPXoR-K3b0L6Ed9P2ec;OQkk@ClY~T9QP7BA0(;9> zSsy&fURg1u^Rj-o9aQak6*mdbsN^JvZs2SFtb6uygc;aEgc&$@kF1TD+*bzplc1uq zQ_L)3LxPDO=c*V)Gu7Ca&a>~jkPr=R7(=T%1PoNJU^3dv-H-DU7W3YmU+B=sg(P1M zvc}9XMk!&V`$)gOCZ+&q<=oH=O=|O!DnqlZD@Njb&K_;ln6JvpaVUT4_7HY1DOnE7 z)EW8EolY&_tQgvd-&WYSaBhCdYejR;`l9DU8|+}len+D>-g2*EJv8OKnf*14Y0NvW zZ^FuuwT^9CVoh#7d-c#o>0U*I#=ZNdD!wUenfu13pI`UxHz2unY*nd&vo8*7Aw|xO zrXp)yMbkmfiO`9u0Kf23_Q9GRGih#DF!RSEmcEQg0~GRkp(@pRK^P~kv{m`0+~Dx* zcvfLI~+hGd; z&MoTwo+Rx}wy=>PjqtgLYDGGp<8TQ6x-eDtMw58qq%ypPCR!>>2%ujqbf>bsarxm4Knh$=-tYSjZ~MjX z%`QtCqhhMw?my-hPo%`LfH!ADAXsFle?AB21sdrsk_7?`MwE0BWcm(6d;;?qQv8Dx z&cfP*K)MZMWg0PzD4{BhBLU|lmV40cj`sco(CEMu5$zc!sS%%8lex;|gO=rWCkZ$e4~=Hwhj}bP42E}w+_ct zU-_Dy1tdDaWwZMulTuV|au_l<7xOg9N=XIkw z0>?OMwQy4Zok2ZiFD7A42RFzi=TNSa-gRlyS;H{#CbN)f3Qw?b7BSZ6>mi1Ilx2fU zz6Rsvm~-|U{wsyBsN z+QAHbW&)jzr728G_WUt(?O6^%#^g?iuxj;HeeASNz@TMm3c|(ihxYXU*E4WptdllP zhAe5^v`OpTlb#9GwxC6Nx3L5O1KL^w`C|easD_M8%p{~_ghb>NlvsGlDA+i7HNUH9 z_&-LL1c-q~mgEi*&|z@;AUy%I4a4xchBLnb_+rVQkc&7^_^)HX^b%Y{#eAISN`M{g z7*p=t|CyEQ`TcA8#{z1K(*U+Nq3q0|nH7|r;^i$< zpz{0;kl6D5M!)96`tgOq$mD*o$`)8AdeTf$;YA&w=F^2;-U+K|)!OX~T+04S+62sT z)L9d)aoL{?_o$Q4p{iW3Wp4BNrh*9&oeB@Q4H%%j#85}8N~zRS3GD2Vl35e9YLiCf zP=l-k^mFqer};5cQ1$yUEs65J-Q_JlyfqUgWPoNu5$A6u5}?y^_@q**s<(NINu zoi)3NG?cYn>wu8+lwkNG%-GA-CIEsQ$0&Lp+4ePeG1JUg+ien7wXq$DpqvUy+@abj!yCl;pC+2CK0Uj6d~&u38vP zFs&L^S|=Hh6rSY`m07$l+;D}I06t#w5`BcaGFmK&H2h>kC<&&x%->uOg|CS=^zBwA z@-)dC`7@7TLo9GESe={nL-at9F!EtogIOiq=kxG}_?nt@8L)X}=7ugFeT+GAqZ)62 z1xaY>o7V7jpMClo!#WN{5N6vn1@w**Eq|qTk$fcAlZQGBQ3#5a-bJ|76iXU4_@XD6 zpQR}yY2Q5g_Y2O6xxIv5cmVLMhzH;>$CNzW?32**Suno==dHCfNp7E(DKvA9|JQ|L zL&G|1&-bH^odW^t0m`e4<7GZ&jv4{#E=mNfuJHbyv^Fkh<_aO{Kw#G=j6F^wUeHr5 zL9tzwy%;5iRj8CBnyL?!X?;*B&t^q?>i*62`8JckHeG0}rZ@?bRs?l-SD*vSxcg=p zS?}~0!o8|%!pLg&y4SUS1Ej_~BV1tOnWj$gDQF^W<&mSZ(_W40IlC%u%9piU=wNMf zB(Zj~P8N&<>xFp97X=q`vQwjIw5olLE9V?Wo`G+3M%5P}1LSR+Y(iUYXO8R93?Cka zcTnjkXB-i*`l+<2A!HWcrjXjAm8?{v3U?2n2e>bw6?q!dbwUsFALyYp=ZE=k9{jO0 zQAlWJhzfW)s;5evKioyZm25fnBMjx{KO z8Q0SiEc3I1B9RV36kGyV=#%IPOVG(`Vbhfb2Gpf5O9{Cp_9_X2BUoi8egEe3OVlSyXu z>A!Rk6?KE ztW8+PlRn3js3=N0|8iIt1KQ2KPGVmyJ_@Azp$=0^XGCZpHLogLFg-0De&P$MXx=_$ui-flPq!qdN7>eIn^tJ+wK9Bvl!Hv~wi1|Kg?*e({ zGC0h^UbGUmr5z|M)-;>vOAf^lYVM4fxDvvW(ElX%Dg)0|S8_s1&#BwXkkoc!@J}gG+%!Qjm1w)T1sb3b3*7vFDmJxw#=hQi zmQ^`2hzEq=p03oK9nz#WjSHA96CVk-^gK@dR)*RVPuFt@QC-1DxB#^LPuKllpA1fY z>+ks4e&ut&D#ZGiPy7a`90XMU#UM~n$w0=K4x=!DcrZWUfgBMU-eU@CkBOznK|~Ou zP=3|agKs4E3lZ$v-^crsG(mg_mx{<$;vGm__U=jb4iXjQvMM~<$F^+46l!B;Xs{&k zXR`PdHYY5H#)`;QryNL>#ME4P1ZjK>s@Qn#+KIiES5mV!7e&YQtw5H$~V+Hze zW_bMzzz$RI1b~Izy!+(gcY9wU2IHP(ypdIorPC0;+#g)m)wqiL^!2s7>p7S)x=^oA z?E}dAwwcVgLZVLO+DCLS4HZUzxG7HcAzu_V05icQ6ae5j0WChqz#9_HtwC>k@8&d> z&on_92!BRN=X(QJz^iA$!cWWk)rC(f&`z{scPC@i4zfuDBC8&S7+2^#Wze{K0vG#} z>(T!bj>FF}w6i*mQp@+}JL$Pg8h4u+uMVD5ypWsH~@dU2f% zUPats3W!J%o<3x0-WDfs0RawXTUynw4=(1@85doy0{}3Ixs}bQJS`&(tmP+sqaR_T zH!%@ha;~m&8H(OSJL;brQC<(I|r^ z)-AL8`pCowO1eT>&y|!85DvCjvvb(lVCQ&F0tkNC@2xu>C}gO-F~D_N60k zVewOj{WAFUGp~?dN?TF=soB7*%sv7VrJ~Y8OAjV;5NySwo8eN+42ijej=m5XGwP#7 zMj~#QMw~0C4=(lLBaLS>NNSE8*40;L1$o*N7e_$54t}HA4EmKvwBHwMElNo%h}a`m z#pjmDeqFsd231hMvUez57Eb%yOvx-=Hq`_WgR8I3zXhGJffww4mZsRJZWP)<@@r!_ zLX}Yw6F6l)t zA_fkYxCU)W6vac``^6VhXyD?#A{(@H6U55uqLBaM_LjBz4ks3@G+Mw4sjROZrv_Tc zjVuQ9oA}qESDvmubTCootJ-@YNG5ywo@3QLH3PH3aw`F`hU~&(&VH=k#$<#&!+u z;A(MudU$KYMhbCim|?d(eHX==_+qDS3^I5@E*D|7UNf=*FpGE(s`XQX&_{zGrX11q zy8ihYI>1hg61Vb2>W`Du`9)l5jk0;(eIw)6lVO(Ngy)=1x|r1w@;xhL%zd9`lPBw$ z@91ii0>s2Gj>AEbJ3p`Y#b#vbioIW??FNKyZyEjPwj8l}57pL$+%gSKj<0AYR1@_h zy9Q6+E z*JPVZR&}h$aeL!KK)>Iyvz;8Fe;!>)l>AEl=h- z?AN=Hhfg`lL}7g*F1P4?Bja^!pl{pLzk@1-c1bben9SLu3MOl4^Oje>(HFemE1N;7 z&2cK==1B#|wyAtweLLqdyv97>95M2?53pw=<6~-%+11~~;^3|)E)EqQrFAscKU7mN zGXYR~C!eQvtGj3`QU58mQ+FNFlA>k{HFP(39KoZgf5 z=^^C;y0UlzV~46Ei-&LJ3OiNAf#A^&w&Ha9L_zHgKl5yp&}ZEsYEk8mV;wyMwQX|` zM=`Tj&!=U=V)_LBrE?bTuupU;kJ6}*D>n}u{qP=ykrJk!EAl+IxUaU|!Vg44-5jOGO>I%URUtM@98<3e)x2XW%G~0nIk($mCS%Z*K%I zX$n9Wh|2%0uvZ|LmwtS94ob&q)*--5j6GsY;8zGrCZA;-aroR(_cl}_z~Pv5RD}6C z#$5{JG&|*T1m;`d8Il^2$8=3`&?YxXXocc=s!C3arS^2M5Wb-t^B~9w%}9H&#o@!BaSgJWN_VY|Sl9qNoRub_B{+f~ZMK)$ zK4ARoPn#dUvkdFZP`bl(gVD9B;!Ts4LqC)vUl1Z=U7hHRFQmCZ0)N;`wM*U*QG`ML z>X?y6^UeN>(}X16bLfa{hCbSz(ip+E;QCg%_^a?un*_*D)V*E-|TF6cTu$EbTR=5Lu94BL08$h$M$>QyWPg*<-Ow8U+5HTC16sO zI>{~wZW(HyJ}&%xNpBpmv-0$m9WdO|S7Q#LT*fvBuGYf+60Sf?%lHjI9(@?u#~e~D zKX9GE3`D>LJ7(`5JN?sz-GjNK&7^QEo`{qJvVV~nxEy*Ji4hXn)wIXR5DDmj4}V4= zFvV1>?^shi(5u$T{-Ay9NnGF(rIz!Ig;`7-B{#G&7$rv&_{(I9w2sBs5dC9n)m>iG zY7T2v$^z^^O~e^^knn zs>o>JUb46X2h~+hemU?>tv3oCqPdp7rEB3#Qo=7?RwDuty6A|yoSg_s;-iP#1HVO@ z5t(RPTQz8JIGO3?Ym*p&G$z65`GX)(Xm*CE3kRT23=BJ@bO>7F{ z%HRZ06%)7c(3?1>nkrBDpFyLm6k)LJeKD1kJ7j89RPr1hMA($ymtAgHSYBP#h!CRk zSQ$wjFAzwl%vfTum;$$urW@DsiXoS7LJ*9)Iwr0cn-NIsGmCTKytsz}!bEt|=H?e2 zcOh!^UbzhO?aAS$JGAzlWA!pctb!#&UuV2^QRS6a3pG#GhI&47H-C?l{%)1_J;D<3 zfvfUTnhDL@$jaAxA4YB3uzNhudIbv8WCGkwH``bVNr?&M5kFXRcYQ|&SS<`;MKOm`=C>5_ zfa(#uN~xY=+gBhAUjkCk>sW zP9@cx!*$N3i$>1jFj|T?fmyw!-n|gV+-eux$Rs3 zz_0NfXjb^xP&Ef;u**+)9nEOp@f#3o)BpzGKJ$)OdCsSK9bVMLPIL4YMd5Cks=Z1a zaWye4MVlBmAc91mk6o2U+i{6!y~cs{Hb%#Xu_R#3R2ntAHCZZ0V*!DHGuIlAR&!LG zD*qEN4-Ljl-noGbPsH1}5?$JI<`>c|+J|s$@6WCFnsYs7U9s?REqBq6Fr)EW2Fjr$ zkjb<-QKNY*O1?PQR%e(qo2-b~*ZrGM3O}>}hR3e#L8zVX8wLtD&(A&q-2#7I^R3%! z(C1iaT^sdCCKF+eyrm*Krb5bD>v^_IV{7=h;A5cnK|7qBbn|*${yEWUdSrwB2{d=< z9xZN{h+s;OP*${P*pN_jAr2`$3Vbe9FR>$!{y1hRJ*3SVaeeK3tIWIG;$Rhmx!geO zjbSBf(qUt*SWE=lt0NP)O6jsPawN+(=RBMB zcZ)syrOpk~e9O5m^3!|_4k1bcci2AjW2*bqjnD5hG#Gk~bTMQYZ^|KJ6?tEgQ5f*T zi&cb%Q~>a8Z<bozmvs z88OOuFOcl+R zBwFEBd>StYYNm4RhVRxyb-F>dgQ}bao~uK8pqO0%r5YRVu7euJlN3!QF+67zaz`mU z|C4A;xc6o$XdX11r=P=nvrs%{_32t}mBSFmQVA$>yWALH^%ucY*SL6 zgLLUk!F}!TGlUlVJYD4RQ2e!p4Ofm@wqQ!&PN$|M>6fA!A=>(mvR&W6W+#s3FbUkMZ zcC2(-xvPVKmekLFfTwmVXXnF8Z&k|i{jE;k;K!&1@|`s;b?eZJ+WHBDR5DI7!$rEdY-YSd<};{=9nF0G+0Ij|Dow1*4XGQQgtFx_ zpjjhSJ7{nA{QvGgo3Q!6ZBLMPV_&cRajSZ7m*Y-xZn^P`wmscEMu-oehzV)!C7OITQD_3*C*m@u~} zDHotJJV^);C`gn5O^O6f6bwZg4DvrHQY0awKxklG(j;g=k`OQ)fCT+t zY?2fakk8*lf!qRtWdCLR|9k(t-6{aezYGHf2S<_u{3riJf$zxwh#(071tCfRfd9h^ zzT*J@Qw|_R04YEq^q)XrA@H?L0O|j+1rL@aLIUoK_74O|k)|a5<3qx;%!zCnip*E? z5BrC~KejedFCq}H$%1tMB9ejvz=H+<pYD@a8O z++7re^iv>dyl(OYQHhnoZ$RB*%3pM#`^Hz`E=rQv2~v2I^I={qY)qCo6{U@6YOY!hJHHpbuOOdcmqfF?~6r>b!VPon+~ z#G*(MAth-6qb5mxOp*c*mLdh8a|#C1yfYz15d`vlmorHMSj&NpLEskkF-hpxrGhSy zTOh_p3^ed|5=8-vSc){*f0yBsGy#FQ&Jz$Q1*mP~{ZlP?lO(}WqyP@93VTwFC?CC< zf%ykvUjwp*2IlrpLLht&F{Vi$zUA(}gMbbDOThmjX4P*%12(CT&Mx>kFi)VQsqgnQ z=&#sP#6UxzzX8hcg1pB~fNlepJh09+fsn+#i$L^VfMI`9ks`viO9%!^iVz4YujmqA zVG@o&y%$sSCt{Ky`Nq3R3euo2;IWICiA(#@xjW}-J3yYmBT&Z9QSe<-BtZax9nyB= zuIs{X2l_8tfD{=pN$@|E;I>S|1yM0fdZvFPCIO_#2Y{0Pp@go^E;TS7n27QE8<7-r z{Qc2`@+S$pvhc{Lk+Xr6kz;d7{|faedgG)WMIG~v%31%?O`p#Z>vk2e6+pR}Y% z1L@j$p@4F}69JD8Rz~%Na!AHSoQLy@OD| zM2UbkDd8^&Wb)4bU&Md(|3LxSzW<;pfI2I5$iV6k0s;;V)LHqv^)^svg^3ubvyzBJ zBnZ^>Z=AnmR2il(m1j@D^-20Q;vv z%tQXD&+I)x`(x-p?bjUU1AyKQJKd@TaD$95)ZeRDzFKNH%r%It65Hk?9g_ zk!kbYpLC%Qu#fUWMK=2qK8`{=B1{C>y7mFT_wPAcJWN1p(I`B=ai|xXbH#_0N$)br zeC|6xB-Y{_%m8jbs^Y@$8Qs_e-tzXBcU4!gB-60lhxB^yuiFn}!@d4C?~Ed-eW9+2h{U z2ADp`Fs~C;g+Z*>0Me!Zp}xS#hhWdsn>OZQ7-z$7H5?pR&c4u_pY=kwpjqG0w4zeE zC+6M#R+niuHsz5x24ZSXFG)lPE_RXqE7j=o4AO12hnf#?BPK_mcUE;a=>x1muryW* zj=2#+iZU7zwPZCT>Ma$u8)RPij>exAlJD~=E&x>DUq{Ni#R8Ts$I$Az2a)z-f;R`j zWQ!^7TLaZIWpK7^;KResBJEql7e$y$Ho)PTV~VY6kXj}_hM#H5v9i$8xYdy2U3x4d3KNg%FGL~N5|oGo~)VyX#$dZ zOpghY2|39@(I3i&37(|Iux5mfegP?g_#!V-FbKgL6&IXqe=cK{coqv(Frv+y7zU2( zSk@NlC}v{%J9UN2sG?Y$+$CkVJQFAe7so)6&?k3PHV$0V+;mD<-J@GVt5?YN0HOQ* zIlm&YZ!8zcIQ|t)!C>|NzIY#(fAk@<3yxWFfY+L2gxIAwJ!#adjm&<#bG<&*Q?LKY zDT@4kh9;S_PIj-8CF=Vqa0YDkwdM@MHD&7n%Idsj!i*WH8%KJ1PqR>}YG%VOz04IT z;b8#RH~AD-jdu@#mk9UuA!ueUl}<~gsY4dwtWmQ&kAay%aZC=)AvJYb#csNsjW=%7 z?W|e0q1Wy2T-ELo;LC~gmahgGa)KWDxc1S!>R46IZdz6zj!zERq5aN)5uw^HeXw#B znZ^KNatP17aaQVIIr9PQo=ua<{Oufv3m-SHzy{4&Uao(3w%(pcR`)_dtxYSl{RQt6Ab8=M)g38xvA zIOiOf6xC`jvHmJWZ3(>uFdY$%dR+oW^Wc#&sdXV$nL+X5ifwo6RBDYCz6<<0CAqkA zJ;cKCpXq%WFnlTxbD#1;Wp6)P6r%D$Wgd&p3X^*yv-}C18UcozbL&8b1*qtK?3;t& zA*rt7elTul(*8My1#nErtQMYmvi}@QjSf**?mMXzORe}B=wUTtDrFv7hUeKW2wIdj zQq{)s7&>eOQi%bP^fp)vrBJ}2;mQyk)kfyQa^D4Hl$LU)1a)}c9ioDhQl?W|93d^B zhYef|Xe?3ahc$`xU1Q67(McZM zbdf6KRX2gDemf_EUCZRf@<1ElCDwp?9i z7GXB)Z4@}pp>o&R&4zawBZU()dyGh)l#ScLzi^u0)?Pt*FQ-P`J(b9buk>A&$9Rjk z48}RGIqeSnry>M4Hlv@-4&fs3FG@(;j`7`4{P?w~KVe?7U7PAr)gL<|r2WQv68O zrTGo!rCF<5B9-|H^Rrg++Erx9e;ZA~@c{&1Wmv8~3#^K-iG@zw(ARI+T5UJ@VU>O4 z&31=W5cODWb2!KNQb-w*wmMG6h&c^m?HEK)V`jA-mBmNc7;SrHzIz*fz;B>u>fpwK z)8Ka38wc%^4r$-sh;-M#?)UVT;~!jb{$#Kk^YRhz>FF&}G1z^%T5@6zh+s>|2lyxi z@|6z|Ebbs$R_Z5jyvh8hLw{F71qb%jf4cPlQ9>1TN-S)=BnldwXH@)ehyHH;7TBR* z9-hXjRB|U*awjx9uDsz<;+5-hpRCAtVP3#{L^$PY{$SK+QSV&#lG8rYIsiY;rJv`f z5Qd)TMw0)e0Yx5}4y{PC1SJJ=Djh^nAp*sq@@%J%w0U1vvA)eCD$gDeim8A&RdQ`{ zXi@iiZ+q^#3KJQo@4`zaAx(@F!+$&>sTT1OTw$D|n6G@w0<63+5H|EaEyzl6S#5(dDHX(8X_Kt7> z?D4X7{?#LRo1u0MU2$Q3f2b%?}dxxL! zroOUXlrKY9F0Yf@=0B!(;#BNhVrtlnK%0KK#2|bGk+Z5U$F7IX7=Y+zte-L020(q2 z2y+f)hLpbGs%N-}FFMFA7||zF#iW+ObGm!MgZf}puL&J5(BSEBHhMqPquv`L99|^S zD7`8rrX@60RMRnKp8^*)JO{4&JyEg1lp&M>08>uUqY1sA$Mt^v?Iwo;K) zeOjm8J{G{xaN$MWRsD&{OBF_T@CUw@>~|?5Gvmhs%Oj z+xJz?a6$K@35)S3L~=R+43Kzg+cRR*j1@@mp?RN^0QEC5RAWgWn7NlOhbLsTqOxLW zzp@o6VhL50Ujfus*R`93V8H_vhv2S-;uLrH7S{qT5Q;;K z1b14XXz}93-6c51DNx*9iu-$c|NDJ&=gxoT%&cdxoIP{SWS^atXRq~a+vrRtgY&|KuG-qh_^M3qpy53vz&fBP+19yym`K@egD^!MZ`DXN@1PYy-J ziWGU#R}_U4EicE<#jn$>I+ezfo%>MgN zn`fOzYOz$=kV3zK+b+WcGjegWeQs_8_9ORy06G1qN0(@STebl;(k_0wS^-;!I$X=c z4hy|?nFqhW+y8qW3l<{#nOZXQ7UJ@pOV&0kKcfN7hciXDyNh$EE8Oe~1sf*E83wM= z(+c41PIwLKTiTgJN%Pu2)Y?n%P3>Mjxn81RprcTY3)KePYur6&8!EltV}4{Xze=&g zgM)s!HVAf2H5oU3yno4M+|+QTILUQ3=i0e;dR+JC>gXb0@H@$GH#0*Qta|V#6CkUEQ5Mcv=uXeagnMLRBL?DxF7@6IC`*K4V{U+v$OT@!ckXDHCE%};GHkLAO^jS1em zv`u^}RM~k_Pab>t&Yg8DV)pusmgDvxK>UY}-DBaqt2<3JUu&p9A$fsUri+K&(XVZ5 z>t><9XE6(}T-N%7tJd4`FuN4a?)n?1ss#L5EMIN+C|NCW|Mz%tza6igI`wHs?fkpo zsN0GVmfLM-nLoQPfUUW-<_9vgGc4fV3x0QKYeH#Q!s8nHwZAn$8(}i5U+|_}!T-b^ zlGikY4ajCo_JW`dy-y@|Om-e^n(xGTRij{d|j=t&Q>YtC`-i$_0b@CNtYD zSIq^37diFiEHZ~<65r3*V|7{9}7xuuF*OD`+iiOJs&Qd(pXjG`4g}3DB zGB7gn2r~@c>(8urn6S0XKYjeXRT|e@q2X1U{SP=IsqgvFjJp)NcjuXx|_@ z8S9|^!@mdG>#W{O^Jn>;W*dp% z@wri3?}`nMd&k=bZF|-*{4|9v#o;YtKz^*_&7D488Q4gHN=#oLa#lU30tf20N~crP zG#({!6W@o_H`6p0SPVz%;2O)Kq`WNP0gjMOEsMJ@>`e%G=2&$dj~Z&;Zh;QW24l|N zro4%j|2k$IsZeQoZvuOW49uF~`+Kv=GS&cB()mh8x#Hts2- z01aX)ets6l#d50iRh^Y^q1EoiBHBKXdrVFoA*N6upHhFI)jyjti0U6TR%U7Wgu;xR z|IH&=vg_?7v3a4HVx>ESn^pKrLCL3Gw8L)CM@7Nr@u48>>IV9dUh|2m#iDPQ2YqY3 z=Q(fi{or)i%Rm#9=biEnaC@rs3$MI~b-abpt7uGwZj1WrUFqtnU-m|YaxAb>f8Ap< z{i1A~smj2AyRvSsPT)Yh#V^_{{~S2gl!{bt_q0)!Mo!COGh-P3ATA0g_4Y8c>Dt$N zdjQIdjkiqHZ|*E{nIvW-PAGXYC*nEtchQU{K4v38wDrPfq;KHLy4(TfCmnmV6%TUH zf1wPX=yF!ogJ!Qq@XQu>#r<8gFCV*?#LegZZ~WySnYP28C@EwlY_j;qQs0eKzIYsa zu5|ssl}P{6Iw(Ml{|N%0i5(yT;D0KST%K8-e@l`6@^np9{eP86&oSUR+n5hL#HkrG4;qDp7*zub~Y}mBV4(N*EL51bc}cMvR*L*%Q9aRVLkvkuksNbAncO=OJM2FHdPs#E4It0Y_H~GWPGo zHIyZKa>hTNhR_uFBn39SjdDOY0OcZasiyt`U?mk;yYGjY?~96uOt28o$f}8-n;7gA zApqq?&A3gFHdXDMV)TIV{x_AK#Zhj+9KpzAl5b^dM7v*Zzwl8M%nOXG#eER$k)jI6 zQJ*uK6vQec&encTaK`zNsFZzbVox%Qa-tNBVFG5BgGbNou}X~>N=##9yMN}B+D8DF zTw1^Sm}3s;?H59(gM8iJ1@P7-AKAdvWeS`G+S6jRs0N(n6@bS}FwI+eEn#cLno593 z32QKA~_T9?{0<#MMEvyCK|<;-G*}KlSFrdKb{4p7N^CHU#qpc+H!Kq~A}8 zpx1K+j8))%YSJEiqo$Y@=jR{uitM{Igv%#0XwC#LzX#2OqJnxj8q+W|+^KuSre5s* zM7&*cN`gRC`xxIt|1f@rBO9Do+~(FLIHYt@BoVf`PR*n#7WG@AJAk#!j?mn`{b}IN zVMRKZ60);5M}g5Ig?62CkUFMd>Dk3x&e1sI_Z2SdlniC7^OhIYStKI0q}62Yd2I=Q zOT3a;Qc`Q|XVp;IY5|gVC-N(7A&??T4OqUKiW*hD%cB{F^<)2N-o zOp60L(eP+UZ#xfaR^p@CgXUj&r3kKERl~bR&`O-O6kF< zg%TZ^U>SNc0Ws)X(g$+EnX)$$f%x+fR5z0MWrQslG6_z3_D2S=HnNmecp@>g+tmw| zdH``1K};L33Hhp;8GBXO`V$-cqCj#R7mAFfebF%>h7^@ zqMB)>4-Gq*NE<0y-Xa$ReJ`h_uKmOb3^H@I6~@mYfk8+9 zS5fcC>X<;xu|Z!VOnQ?|w!0(y0LEd6Z>uZ{FDIk&okRgo9Bgp>}UyAhYHs|o+7%8^ot>x zG!;GHOg`^`jF5{_$j!HsYd#`lD#V>N+)l4ydMMp^4(4OSVpnRvIeZ&1$8mIuJSfoR z-rk{>r{L}ef~)4xt$gk_c`)WBU&YSs0`Z8{J<&*-MMp;Z%-iXoN zY{&>g1;2e?f36;yn4a5taUQHTzK`}`U}nr(i@P=~SutDx!iYew73ViY%hzHJ%dqH) z{A|4s$V*13?u#zA13hGJAJl?{154ojQ_hkLxkhL=JD$X&whpcsNH;w$6LL zDiW4C)Y=wKQ*D@cr~764-z*%C1#89=p{_P}ZGBL#uCZh|JP-X#SH4u3F*6B`?bhad z#a!U!emFmBMM4`qvFYXEG}|Z4mmVlE1UFYRPDCJJg6HO$okg4%CKk<`FHCgjB1FYj z6D;zz|JM9S2EtYE_)7=6y@uDcYl$Z}4}_3jI4ptGq$h(JBOG>M?!e^_KV|z}yqBCa zP+g$f2hKx}E|7w9C5jehFFm{~N5q zFn}mG+US2>4663BqW!&Z`mg_E0-snCDGp+!^pdwC!o^hT;@KuI;)MQ`v)u1R%)uzP zFM6F`;Qw&*Ugx*a&<#U61YS!ZZ)9+IKpC6VT7bZ*EMbuy3uWtQCVslIo#u5b%kbz$ z*NV;PJ1)9GJ2&^_{&<|&vK_EM8AL2KM?ezhwlj)85U)k_`Wl7OIxq%Z%%WFI*SqVM z9wZKTzp;{i7PV~TwbNvQ;og&RGWHT`_@fDR%Cd^Sj~?r$>sY{djeSzczF%PrI484+_^(4hu$AMKlz_zA*I(tXC6EScxGVAfZ45GYN z20#D}*F%i}8Ur1LkBxI;GJ30m0n2vN$5@Db6$dZSQI8tVqZaot6t%&ug9TEaea=11 z{QMdmOCWPOX+1s*{SCRi^>bn9hLX>c6q076E%`lY!sG)px!mI&#Ht*z`LX}Pi);8D zR=-xpzcx?>jZ&0cq!#cq;4b^PhIr-FnI;H?grKI7APre=ep#7k*WgN(qSDYjSesdX z!loIx^2OoB*H?G%F=x#Fjx}y*nxZmJ^_k_m91ep*%!0IxYe-^DAf%xJqZ64 zMmvelU3tcjY5?9FCvR(WAp=477rk|vl6okWhEePdrpSI>nE}GZDaAMu6+!rKu+jRd zPSdpFxgw2~0E+gq8-nz70biarUIQ0iqpqwI$T)^-ht{0EK6p+4^j~A@ptW!{gw7%) z07flhvz;qs8Ro4;(=?#m*P4jUOUOzk#tg9GC~Uc6?&LrHddV}3ymJi_)TN+oL{F38 zD_2n)hdD*cRz+KPelr7NP=@?bYdBcfC7eP3vA(WXXWFY3{QGhg%VS+-sP;~{qzJ_Z zqg9@-@db-i*ZFhIz$eCv%;UtTks3^qB>Dioz;$6ExQQbA=^W-2(n%L)WSZ9U3*&(j z48s%Mzv`p{F^vwKdu77$dHxVpm9$c)BWcu*B{RPrwpz;U=(DYvhH(oC11(tsR5R`@ zn(IR*!*LmoV#W6aH4;|nWI{)awnB}WBAlkm_P$-I5X%XfWg+PvR-8SLvF{ZgkQbgT zrnOq|szwT@7M7U?orW)c5}#SC4fWJ7-Y?w~t}-SVVoI@zpGOamU}(QM=sbzrxtd{l zyI5?ym7dD$_`X=#p`DWQ1R9agN&a-m!eJrJ8FfhctRNS&xqI6=fKn@dRe5ZtpbF-K zj5x-m9mIOHZ4XhNv9gZ`2FI}_ZBmH)n7@)-p5e&FAvuY4T6O=}iYLSdWVc!F?C?&e zLV%nRQ$gUErhb@4SwBvp4%+Mor5N@EQG1I^R|B6vqQP^C}fs> zj6?^*A%D&8H;-(5k${9doap5Gk2PGzY) zp-J0S#~id@rCs0l_Z6wg`kB}!yV z>B!=2DYyqrMn(BK9Te?cr-dd#n6j&BgiFy;P${-Z| z4NoO2+v)<_FEDPLMP-9nr(u=v*N~7_TjvU5if7MX29z?l}7)U0##uMf|1}$(xGA z9_L{|u_Qm1;>VP-=p5(^ii7c<8EIc0-S56OA|@14nk%eb0aLoSn$HfankrsGwfZ1= zws@A70%Uz-=Sw9jK*54eVeJ>Xp?uHBnbpaA@O;ww}wJ-x8zRmJ1l*pSwCf#5unuhuJZk5;7k;-8vC%>hVZnMo64)F z`Yjd>P1A9$2f)JVXI0-~5S6_;QBZwEQ+peDK@Hvk-sJ!ku`9&4o8Yy~nyg9d5A+_t z$J*_u3CLp!i`KF&1Of^f3;qVHEO$<@sjK6x%B_xZp%h2L)r)HW5u zNlL#k?Lq(MdGng1?r$pUfiK*aVHx?h@CnQ=0cR}o+!cMpX-W;S(6W@FWSeo%9!B90 zoXs2OI0GWR?8D;L$*8ULk9FO&e(kbLo%`jw^^)F~r)WhY1q9}$E!9nTq=i@VTcJCq z8aWYfR4XGd$9>Sd={EiSq)4x?)xV2)s;2C|nMe+p2H??jT`{+aInEJbMyVKo=To}_ z929xmEm!i3evp%u!hPfbJcQYj;ET30_0DPx9wJHIM}811Q&JB~m4gI^+kY5y^@ZE> zlpV+Oe+ua-qC6>*ahjw!3i|s2h+&7)+(~J}Fzzb80R1f7lZ(WOkXEs*Tl@v4-o{bVq(^D*{wDYuuMi?>G(&go7VSQfEw zWH8w{Gt?5Ta7FiOiYm~(aMv+n+LlW~r4#M!H<^lN>4J?wcp^MKY}3SOs0VUHjxUB@ zRV%Uz1e1KmZS<6)G5q)eW!d(SYjL46Y3sM^s2Zlpxc&>$@3?Gss+|2z0C*3lx*_Wdapqx~U>uS?b0x)y2cgD7b6lq3DERre&5GOo~_JAS;tS zP-dU|M<>|jG&6#m3z2PL#_hh);55OgS(ND>><|za{UfohEwMVe;rWN9MT|;Pmhv6r zXP%VHFBa)%+|jx=T}mPeiuPQ;e)`c8R`Yju>^I^w5u?DD#Sj+UhK?ch!rhjR{VByM zQaMYu4UmsN482{*Kf5KV)hD$i?e%6XQ-fc{mED@Zt=cCv>x8*A7Ds(WU|#cd>rA{? z(S>}g+b?6ac3}8==6oK)Q&|-$v!U0d;-T6|A8rndoeJ)~jR(M}W;L5J$x8>F!vev6 zw>tWy1v^qX^wxWUDN@8@1+d?~{6BRDu69ZqCnFK~ogU^lebvoi3}`n5Wm7&&OINiV zdt=c!&5^0vbp40k#6S?%^%BQ|nrP z20ek7s+QAEo_TpUdXmE;j-n>Q-q$ovma?4LvejkPhwF7-i>t1qcJhxcKcYMC?rYyx z>ZV(+K1e6U%;nFV4K|Bz+uAmWeRJU7vL+JPFy3dh!KRo;TY=@F_}^XFO1+&@kb{}4 z=V^58TOE!@>$7@7hNUr(D|qtK8T{cXQWk@VJ<37?TV!PGmKUUGk~V@vqBu|-^xljK z0QMr}vcpd7MboN&&%=KhjR;_$IQwLOVZ2Q#9nfLshQOc&L?*dey^6FKBa}t6RJ(6U0h$IyU~UKt3t%cMtSzj3`OlMPr&A0Fc=ND^IR5zI12$&_aCgOX9b1g zpQE>d!>ide{>H0C7*jh5kXI1PA=N~NqfGA3(2v%VQ3v70Vc1hUfq>A!#v^1T#+q=5 zd<-2bqb}i*hVx}eOsp~@z@`4 zE)&Vc;f+pYS6(vHqq!;!X5or^FCQ$S$PzcS7MwvPiI#SGgC!%J@YKrL9Cy`fHQ$6Ia;F`0z>p8E^?T(FRe$YbF$@{w@!tJGt@xjGspbJe((?;sDZL z5ia2(ReJfie*Vy-#=yu8NP$2LTMx8a2bV_M*`PFHHSA3CYg_*5IQ zL=ZRNOoY$kA@~~Gg-KJUI2e#eqlpD_D|p-lbzwor3k`sZwK0aDZ}Z;)(KTT^8AgUM z6@LC_ZZ2b)AIKI>ERd5cl*d-hqA9AA8Yjyuv@IEaK7SO-0R?KG$~a7-3&IdQm2&CR zLax!-L|F0>zo{zWC`=iNYE%{CyezL5QQVwj1!f5GL2?UAFFpn+pN(@@1(EMDU+S-H zIEIgFyzY*0NFlq|_nXP8dw28(t0fS)!R<#i)8CbjqD-m))o6iidEhiy1h5C_&&*(I zo1i%Z>2T7`i}m!EEB^ERn=r+aL-&g-&o67>f^YX5`KCnQ{6Ggsi;LJz)pN5iCr(IZ zH2&ni8Ra>Od15$+?~5tsj(c-@4U$!$nTs)4G}$}$1nQE9mdkdjYe}rZ9NoPadb|Hp zrisY-nN*#6gSh3~P%?eYnN;nhaf5>73#!;3NQ=TssM2H?#TK zeAZvMwY1W{4rw4iI+UpRa%73(#;nr#na1FGo4}30+KV~c8u<{GDH=Q9*LX{bTzf^p zSDOqTv$!}M*=!$lLBumLxz_1;!i`C0)Ycc$b!>%~}BRDh$`KCX^=)+rutx&1l;V)b5# zAw)4^(pE&z7c&)k2w8dD4VU`-4wfzu3FAd)ZM@69{9l=3sJ9s z2K{l>FqSn2Ad_KxA!4NMyhd(N1V74npQQYEhS2`v3~o>x{=^BafaG!cWWMIe|D3>^ z7-cnKKz%SRvX#xiUss@jULcL8sk`*WFrt=h84&iLF~47)qHTwwQGP_bC|1XvgHf@Yl+#S8XVC!iRX0y%OId9QC%YGv9xm11r0=snRkK&K=#pw9z#d zMQ}k72$D!qu~bXd@H#rzNcRNE?Pi3I#fN?wuRQq!$H=J2Mg!YiD`&fp49iZ~Kg_zG z=_)(uCdss0FQSN+s`4Oi)0>4-1UOaBCLWzA;}x;6h}T4$Tb%XdAHc{X_md6Ge*L9z zzfqs(m0Y9XMtQ~q{j#5yV7k##Lqiji0(|HXv1XuSBz%qkRPz__;6Db076a{HxbZ_? zk@Djo3k7xV5#McaGwZf!X0)}HByom=l#g{kyQZ4MwlqpQ0HH9_gksHu70jOqTFs7E zD28%H9~!CEwx@5Go8h}IeMAZB`w)z;J#S|JoZvSWitctyMG-ih6WPaJb@omM^y>n8 zGRJU*6r~|(oKulsvsVF$N5@*Ib6kECS+(Zp;hWz{)8J=YEoof5`2{_3xb8h!aYEIF zc?U72HyT@V+Z535k;mkRv3dXh8gKcQxQ9Vz?Nw`|IbK=7@4o#tJcN-_?qWt*+Z8iX z!$z8j=#@JM5+rGF5U~Tz=fC)qex3mQX!LH6*$P_U;*{%O&R`NdpLyv=3h%l_O zGg-P{jn9h%{u`8xR@vlxz1Y)x>ZkxD~#K8XlkimL&RQ^4$UWuM}3Np&_`)gQ!7t zW+D!<onsW8%nHcI3L4ES=k$#a za5E4YLJEWik>t23 zLBT6w0ASqZfyUCeW}cE8`O+NNp!%h8p6J_nOe?N1y^zZU2<0_*dZ1?Sd;4x<23`y* z_t?r0BG8CwQSO&>h{+D;$jeW}gE1x1EsPR1j3hC{j}cXCucOC16NA*qJ73B;r{}wU zTy-AsfD$=TIH@G_CUZaQ#UOsfqLVs?r0xWEuCJobeL&F`@wsr(#U3U>6>JU5a$9BR zdf(7$vpvWJpe+5OUpNQ*Y}{xB!INY(ZT5X&z0k+ToD-kGkOnAMHxhu?kmbzBLGNG2 zE96m|?}|3^7)pnq#{C;(iyxkXHzz^al#P_sc0@%3m?J(`@hU?Aq0__NiMh>uv11rq z5Gq}f)9|#8G+y05_u6sNO~)4{!urXE7KD~wNOsKr+UOq(Yc zOl+X4QmX6O&jLp$Iumtv!xCr5utE?l#%maG@O~pgJe!==l$%CuiLt4B7I+GH7l_AE zx(nW{A(=iT)(Xs^O1CN_w?^UtVpv=K*je0(3DpZR$k}7;r1Jd_71RayJxCPAwPHnp zkuB4!bCUs?I?RK_n9ny(EG51R9t}u!64t9QNj&?#qRYa&#>i+50D4Lz2Uj%#$=Q1~_1=O+d(j*MCDjeWRhq^Gp` z)&?bx!W6agzveu1_oWze0$GB3dIPB9grUo<-Qt>IDHq*-_U>*OQB^!v`3#H|@S0gH zw(f3DH!a!W&{|0XW;p3ZIYxhw6mWI#Q=~K-!fw{5G1ZiN-8g?)Umk@5?La>({pb09^lL;TATYB=^sounibtF^&dIDwXleJTrKU zzQpjH=6VwI>Siat)36d$yy>er>I{&=2Pb`Cc96(UU-!m0RQbEx+rhMy-~kDLxKGu= zOgwavl@7_N6q5EQ7`}{TvawfxDaQ`Ya|lBTE|K9glJ)BLSWG1-!9~X)qNMuDO!Uh+ znaog^5-TvjipV5!)g|^fL0*!yg|nEP{t#T4zK)>gxpntlb!dW`&vY4^&;b`6oB_9s z5J5@H<9q3ry$K&Y(2O0(ke3JHhX6Il+|}pMHIoA0tf0H|;}eS%zC+)IRhA)n@kC`Qg*4B5P@GRlc z(N-505RPWCrU?Z9%u$v@Cx7(!oj)B1A>8v36soiyCn3=R>NP!SQq#k(*{RyRK*q5O0D+5|39*HY^J)Z^H4*0JBk^N_qQ zypLn>oO!*-6DLDT%*O}|Q9>FA9Kp?`i%Z`(FTibw0CW4(Zt~GwAKLSsPCXUI7N5Tx za&tD6k=)OptZ;ugrO%k3jfhIRfzmv_y_sAsw_Y&a|A~#+?t~V48l}S8E7|U1#M%sCABZ-gLI`i`GIkFVY zZPn1o1b2UVOBbJ1C}xhcJJ8aD6ic2haI_~ub?r$yLR5J@%2a#YZXbZjsAPJ&+$oY% z*}^R5cRM)l1^)pMlgwoS@`AbFz}i&&-dMT!paV@>D}n^W0g;Lm(Vm4&I=ln`rn^N@imcq03n8XDB{8-41{AfR|M1;>I~7!oL*!+~W87=2vAOdrF{r^iR%Ff= zI`uEZYWuo54rI|szRFgW`5D#hBw|8^VCGVqPvR)3D>hgYe4OW={oxM6oWk$LBpwx> zx7Zx3k^r=4t9a=j%o09ghy?j=I^`O5H<&j5DFRMYtYGacIYX9wHl(xBHJv{R1~3+- zD~t*e%qY_T+{CAQ8&L~imnViTIn$x1s+T@)>PuPu8t~D14zIlF@j1L}J_fhB*b}tY z*cU}EEnE-$1ob{`&+8MnG@K-S{1-1=K4Wk^rsc1PU3O0=%xtROr?oH(2`U0f$Z2Ng zt|p{7Eqy+j!|hA$^5Nemo*j_MrL|1n80q65dpGUC<~pIS98~0O{3@>Vr@2aV6~O^I zJSohIXCemJncb7*KVk>?@`cM=3gh{XQYYByrSF_cEZHdDKUu25=;@4&!*gGiK3NRl z%PV-L639AM+(rpt=FzvB{g2=3m!;jn2}w6c%yaLQQ{yx~(cbkadWX1!7g!1M&fZLA z^p38!ANfabnGT=P$A1y*UzB=hpUTXh=QwI{xNWKHEp-!YmOD1_Znx&*&7JeVvmC&g zE1jDBpea~6zj7%rGwp9eeQttQQ+wlK+P(uFzVJpn9~-TfRzrbuSxz+rKzioZJn|@0 zJSbXAh184ofFAC2p=RLHx8qNWxe0_XaT~mgy-BCC<8;~hGy-ZwBE`|3a>^(k3H26T znpXNy+W>Jm--oLy%_&&(ehclv1@k|f6Mk}u5g_t8Je-)dtyB^*SDJvX6trwND}mVG z9vH7#?qXVXqh+=r^`CX~-_fyy`_#A$;{A zo7?>5MaCoZYo)PC*Z&3J_z;AMe+Vst!OJ2m{~y4cJB`c#+Gu*LM*lMSF_%G53cmvh z+__%;bHBCAp`xJx3GvE_?qTj8(eHaw2(PiIgBr| zt1-&jR8bPcx==J>gBu{68HZfcV13g9{7CxMz#@F>zacS=SVh&CZ+ud;CS)#p{=EuI z1WuymL-6b(oKWaO(UMB&d+#`&mJFP6QBkFp)~3iU6c_5UrchbHR8jtD&RyEciD^H_ z%KeE1#oL{nk&|^WAguyiAEn-<x!VK9B!)%BbrRplop2JR1rVg?{E z^PM6yF2-s;i9BREd&bR5ECopaN}H9_W=ePG{b`n+&BahF`*uF!FO6~|RH^!S6eS}b zQ@T+UZC~cjGk_&=s%GJNb(Hr?i=dHf7$8?L4!P|d1VQMz=Laq@B)bB~NRxolfwdxT zdz~9UH3D|CU-r>u^OCM&vrJGojs_sD0%#?XK5MyX^pu!#5RA*NX|TKyVdM+?S&5mj zKmNxwv?aV-!MPz|pS5-JJZeKl7Q=Kx^fUp?2)&i@|^?cWgq literal 0 HcmV?d00001 diff --git a/boards/arm/lora_e5_mini/doc/index.rst b/boards/arm/lora_e5_mini/doc/index.rst new file mode 100644 index 00000000000..6e6be186dd7 --- /dev/null +++ b/boards/arm/lora_e5_mini/doc/index.rst @@ -0,0 +1,226 @@ +.. _lora_e5_mini: + +Seeed Studio LoRa-E5 mini +######################### + +Overview +******** + +LoRa-E5 mini is a compacted-sized development board suitable for the rapid +testing and building of small-sized LoRa device, exposing all capabilities of +Seeed Studio LoRa-E5 STM32WLE5JC module. + +.. image:: img/lora_e5_mini.jpg + :align: center + :alt: LoRa-E5 mini + +Hardware +******** + +The boards' LoRa-E5 Module packages a STM32WLE5JC SOC, a 32MHz TCXO, +and a 32.768kHz crystal oscillator in a 28-pin SMD package. +This STM32WLEJC SOC is powered by ARM Cortex-M4 core and integrates Semtech +SX126X LoRa IP to support (G)FSK, BPSK, (G)MSK, and LoRa modulations. + +- LoRa-E5 STM32WLE5JC Module with STM32WLE5JC multiprotocol LPWAN single-core + 32-bit microcontroller (Arm® Cortex®-M4 at 48 MHz) in 28-pin SMD package + featuring: + + - Ultra-low-power MCU + - RF transceiver (150 MHz to 960 MHz frequency range) supporting LoRa®, + (G)FSK, (G)MSK, and BPSK modulations + - 256-Kbyte Flash memory and 64-Kbyte SRAM + - Hardware encryption AES256-bit and a True random number generator + +- 1 user LED +- 2 serial communication (RX/TX) LEDs +- 1 boot/user and 1 reset push-button +- 32.768 kHz LSE crystal oscillator +- 32 MHz HSE oscillator +- Board connectors: + + - USB Type-C connector + - +/- (battery) power input pins (3-5V) + - SMA-K and IPEX antenna connectors + +- Delivered with SMA antenna (per default IPEX connector is disconnected) +- Flexible power-supply options: USB Type C or 3-5V battery soldered to +/- pins +- Suitable for rapid prototyping of end nodes based on LoRaWAN, Sigfox, wM-Bus, + and many other proprietary protocols +- All GPIOs led out from the LoRa-E5 STM32WLE5JC module +- 4x M2 mounting holes + +More information about the board can be found at the `LoRa-E5 mini Wiki`_. + +More information about LoRa-E5 STM32WLE5JC Module can be found here: + +- `LoRa-E5 STM32WLE5JC Module Wiki`_ +- `LoRa-E5 STM32WLE5JC Module datasheet`_ +- `STM32WLE5JC datasheet`_ +- `STM32WLE5JC reference manual`_ +- `STM32WLE5JC on www.st.com`_ + +Supported Features +================== + +The Zephyr LoRa-E5 mini configuration supports the following hardware features: + ++-----------+------------+-------------------------------------+ +| Interface | Controller | Driver/Component | ++===========+============+=====================================+ +| ADC | on-chip | adc | ++-----------+------------+-------------------------------------+ +| AES | on-chip | crypto | ++-----------+------------+-------------------------------------+ +| COUNTER | on-chip | rtc | ++-----------+------------+-------------------------------------+ +| CLOCK | on-chip | reset and clock control | ++-----------+------------+-------------------------------------+ +| FLASH | on-chip | flash | ++-----------+------------+-------------------------------------+ +| GPIO | on-chip | gpio | ++-----------+------------+-------------------------------------+ +| I2C | on-chip | i2c | ++-----------+------------+-------------------------------------+ +| MPU | on-chip | arch/arm | ++-----------+------------+-------------------------------------+ +| NVIC | on-chip | arch/arm | ++-----------+------------+-------------------------------------+ +| PINMUX | on-chip | pinmux | ++-----------+------------+-------------------------------------+ +| RADIO | on-chip | LoRa | ++-----------+------------+-------------------------------------+ +| SPI | on-chip | spi | ++-----------+------------+-------------------------------------+ +| UART | on-chip | serial port-polling; | +| | | serial port-interrupt | ++-----------+------------+-------------------------------------+ +| WATCHDOG | on-chip | independent watchdog | ++-----------+------------+-------------------------------------+ + +Other hardware features are not yet supported on this Zephyr port. + +The default configuration can be found in the defconfig and dts files: + +- :zephyr_file:`boards/arm/lora_e5_mini/lora_e5_mini_defconfig` +- :zephyr_file:`boards/arm/lora_e5_mini/lora_e5_mini.dts` + + +Connections and IOs +=================== + +LoRa-E5 mini has 4 GPIO controllers. These controllers are responsible for pin +muxing, input/output, pull-up, etc. + +Available pins: +--------------- + +.. image:: img/lora_e5_mini_pinout.jpg + :align: center + :alt: LoRa-E5 mini Pinout + +Default Zephyr Peripheral Mapping: +---------------------------------- + +- USART_1 TX : PB6 +- USART_1 RX : PB7 +- I2C_2_SCL : PB15 +- I2C_2_SDA : PA15 +- BOOT_PB : PB13 +- LED_1 : PB5 + +System Clock +------------ + +LoRa-E5 mini board System Clock could be driven by the low-power internal (MSI), +High-speed internal (HSI) or High-speed external (HSE) oscillator, as well as +main PLL clock. By default System clock is driven by the MSI clock at 48MHz. + +Programming and Debugging +************************* + +Applications for the ``lora_e5_mini`` board configuration can be built the +usual way (see :ref:`build_an_application`). + +In the factory the module is flashed with an DFU bootloader, an AT command +firmware, and the read protection level 1 is enabled. +So before you can program a Zephyr application to the module for the first time +you have to reset the read protection to level 0. +In case you use an st-link debugger you can use the STM32CubeProgrammer GUI to +set the RDP option byte to ``AA``, +or use the STM32_Programmer_CLI passing the ``--readunprotect`` command +to perform this read protection regression. +The RDP level 1 to RDP level 0 regression will erase the factory programmed AT +firmware, from which seeed has neither released the source code nor a binary. +Also, note that on the module the ``BOOT0`` pin of the SOC is not accessible, +so the system bootloader will only be executed if configured in the option bytes. + +Flashing +======== + +The LoRa-E5 mini does not include a on-board debug probe. +But the module can be debugged by connecting an external debug probe to the +2.54mm header. +Depending on the external probe used, ``openocd``, the ``stm32cubeprogrammer``, +``pyocd``, ``blackmagic``, or ``jlink`` runner can be used to flash the board. +Additional notes: + +- Pyocd: For STM32WL support Pyocd needs additional target information, which + can be installed by adding "pack" support with the following pyocd command: + +.. code-block:: console + + $ pyocd pack --update + $ pyocd pack --install stm32wl + +Flashing an application to LoRa-E5 mini +--------------------------------------- + +Connect the LoRa-E5 to your host computer using the external debug probe. +Then build and flash an application. Here is an example for the +:ref:`hello_world` application. + +Run a serial host program to connect with your board: +Per default the console on ``usart1`` is available on the USB Type C connector +via the built-in USB to UART converter. + +.. code-block:: console + + $ picocom --baud 115200 /dev/ttyACM0 + +Then build and flash the application. + +.. zephyr-app-commands:: + :zephyr-app: samples/hello_world + :board: lora_e5_mini + :goals: build flash + +Debugging +========= + +You can debug an application in the usual way. Here is an example for the +:zephyr:code-sample:`blinky` application. + +.. zephyr-app-commands:: + :zephyr-app: samples/basic/blinky + :board: lora_e5_mini + :maybe-skip-config: + :goals: debug + +.. _LoRa-E5 mini Wiki: + https://wiki.seeedstudio.com/LoRa_E5_mini/ + +.. _LoRa-E5 STM32WLE5JC Module Wiki: + https://wiki.seeedstudio.com/LoRa-E5_STM32WLE5JC_Module/ + +.. _LoRa-E5 STM32WLE5JC Module datasheet: + https://files.seeedstudio.com/products/317990687/res/LoRa-E5%20module%20datasheet_V1.0.pdf + +.. _STM32WLE5JC on www.st.com: + https://www.st.com/en/microcontrollers-microprocessors/stm32wle5jc.html + +.. _STM32WLE5JC datasheet: + https://www.st.com/resource/en/datasheet/stm32wle5jc.pdf + +.. _STM32WLE5JC reference manual: + https://www.st.com/resource/en/reference_manual/dm00530369-stm32wlex-advanced-armbased-32bit-mcus-with-subghz-radio-solution-stmicroelectronics.pdf diff --git a/boards/arm/lora_e5_mini/lora_e5_mini.dts b/boards/arm/lora_e5_mini/lora_e5_mini.dts new file mode 100644 index 00000000000..e65572c6e35 --- /dev/null +++ b/boards/arm/lora_e5_mini/lora_e5_mini.dts @@ -0,0 +1,125 @@ +/* + * Copyright (c) 2023 Marcin Niestroj + * + * SPDX-License-Identifier: Apache-2.0 + */ + +/dts-v1/; +#include +#include + +/ { + model = "Seeed Studio LoRa-E5 mini"; + compatible = "seeed,lora-e5-mini"; + + chosen { + zephyr,console = &usart1; + zephyr,shell-uart = &usart1; + zephyr,sram = &sram0; + zephyr,flash = &flash0; + zephyr,code-partition = &slot0_partition; + }; + + leds { + compatible = "gpio-leds"; + red_led_1: led_1 { + gpios = <&gpiob 5 GPIO_ACTIVE_LOW>; + label = "User LED1"; + }; + }; + + gpio_keys { + compatible = "gpio-keys"; + boot_button: button_0 { + label = "SW1"; + gpios = <&gpiob 13 (GPIO_ACTIVE_LOW | GPIO_PULL_UP)>; + zephyr,code = ; + }; + }; + + aliases { + led0 = &red_led_1; + sw0 = &boot_button; + lora0 = &lora; + watchdog0 = &iwdg; + }; +}; + +stm32_lp_tick_source: &lptim1 { + status = "okay"; + clocks = <&rcc STM32_CLOCK_BUS_APB1 0x80000000>, + <&rcc STM32_SRC_LSI LPTIM1_SEL(1)>; +}; + +&clk_lsi { + status = "okay"; +}; + +&clk_msi { + status = "okay"; + msi-range = <11>; +}; + +&rcc { + clocks = <&clk_msi>; + clock-frequency = ; + cpu1-prescaler = <1>; + ahb3-prescaler = <1>; + apb1-prescaler = <1>; + apb2-prescaler = <1>; +}; + +&usart1 { + pinctrl-0 = <&usart1_tx_pb6 &usart1_rx_pb7>; + pinctrl-names = "default"; + current-speed = <115200>; + status = "okay"; +}; + +&i2c2 { + pinctrl-0 = <&i2c2_scl_pb15 &i2c2_sda_pa15>; + pinctrl-names = "default"; + status = "okay"; + clock-frequency = ; +}; + +&rtc { + clocks = <&rcc STM32_CLOCK_BUS_APB1 0x00000400>, + <&rcc STM32_SRC_LSI RTC_SEL(2)>; + status = "okay"; +}; + +&iwdg { + status = "okay"; +}; + +&aes { + status = "okay"; +}; + +&flash0 { + partitions { + compatible = "fixed-partitions"; + #address-cells = <1>; + #size-cells = <1>; + + boot_partition: partition@0 { + label = "mcuboot"; + reg = <0x00000000 DT_SIZE_K(48)>; + }; + slot0_partition: partition@c000 { + label = "image-0"; + reg = <0x0000c000 DT_SIZE_K(96)>; + }; + slot1_partition: partition@24000 { + label = "image-1"; + reg = <0x00024000 DT_SIZE_K(96)>; + }; + + /* 16KB (8x2kB pages) of storage at the end of the flash */ + storage_partition: partition@3c000 { + label = "storage"; + reg = <0x0003c000 DT_SIZE_K(16)>; + }; + }; +}; diff --git a/boards/arm/lora_e5_mini/lora_e5_mini.yaml b/boards/arm/lora_e5_mini/lora_e5_mini.yaml new file mode 100644 index 00000000000..144ee2275ad --- /dev/null +++ b/boards/arm/lora_e5_mini/lora_e5_mini.yaml @@ -0,0 +1,19 @@ +identifier: lora_e5_mini +name: Seeedstudio LoRa-E5 mini +type: mcu +arch: arm +toolchain: + - zephyr + - gnuarmemb + - xtools +ram: 64 +flash: 256 +supported: + - counter + - gpio + - i2c + - nvs + - uart + - watchdog + - lora +vendor: seeed diff --git a/boards/arm/lora_e5_mini/lora_e5_mini_defconfig b/boards/arm/lora_e5_mini/lora_e5_mini_defconfig new file mode 100644 index 00000000000..5e6649fe25a --- /dev/null +++ b/boards/arm/lora_e5_mini/lora_e5_mini_defconfig @@ -0,0 +1,24 @@ +CONFIG_SOC_SERIES_STM32WLX=y +CONFIG_SOC_STM32WLE5XX=y + +# enable uart driver +CONFIG_SERIAL=y + +# enable GPIO +CONFIG_GPIO=y + +# Enable Clocks +CONFIG_CLOCK_CONTROL=y + +# console +CONFIG_CONSOLE=y +CONFIG_UART_CONSOLE=y + +# Enable MPU +CONFIG_ARM_MPU=y + +# Enable HW stack protection +CONFIG_HW_STACK_PROTECTION=y + +# enable pin controller +CONFIG_PINCTRL=y diff --git a/boards/arm/lora_e5_mini/support/openocd.cfg b/boards/arm/lora_e5_mini/support/openocd.cfg new file mode 100644 index 00000000000..f4902698c63 --- /dev/null +++ b/boards/arm/lora_e5_mini/support/openocd.cfg @@ -0,0 +1,7 @@ +source [find interface/stlink.cfg] + +transport select hla_swd + +source [find target/stm32wlx.cfg] + +reset_config srst_only From 0b5ffac8af3a05b99da860ce52f6cf69f1d7e199 Mon Sep 17 00:00:00 2001 From: Bartosz Bilas Date: Thu, 4 Jan 2024 09:31:35 +0100 Subject: [PATCH 1849/3723] dts: bindings: max20335: adjust properties order Match it to the order of the regulator.yaml. Signed-off-by: Bartosz Bilas --- dts/bindings/regulator/maxim,max20335-regulator.yaml | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/dts/bindings/regulator/maxim,max20335-regulator.yaml b/dts/bindings/regulator/maxim,max20335-regulator.yaml index 44086e0c4fa..3b73ab525dc 100644 --- a/dts/bindings/regulator/maxim,max20335-regulator.yaml +++ b/dts/bindings/regulator/maxim,max20335-regulator.yaml @@ -40,10 +40,10 @@ child-binding: include: - name: regulator.yaml property-allowlist: - - regulator-always-on - - regulator-boot-on - - regulator-max-microamp - regulator-min-microvolt - regulator-max-microvolt - - regulator-allowed-modes + - regulator-max-microamp + - regulator-always-on + - regulator-boot-on - regulator-initial-mode + - regulator-allowed-modes From 9618b761ec6abf91fecdfa5b453714dbfccd23c0 Mon Sep 17 00:00:00 2001 From: Bartosz Bilas Date: Thu, 4 Jan 2024 09:35:13 +0100 Subject: [PATCH 1850/3723] dts: bindings: max20335: add regulator-init-microvolt/microamp to allowlist This PMIC can handle those features, so let's add them. Signed-off-by: Bartosz Bilas --- dts/bindings/regulator/maxim,max20335-regulator.yaml | 2 ++ 1 file changed, 2 insertions(+) diff --git a/dts/bindings/regulator/maxim,max20335-regulator.yaml b/dts/bindings/regulator/maxim,max20335-regulator.yaml index 3b73ab525dc..d23a1fdf1c1 100644 --- a/dts/bindings/regulator/maxim,max20335-regulator.yaml +++ b/dts/bindings/regulator/maxim,max20335-regulator.yaml @@ -40,8 +40,10 @@ child-binding: include: - name: regulator.yaml property-allowlist: + - regulator-init-microvolt - regulator-min-microvolt - regulator-max-microvolt + - regulator-init-microamp - regulator-max-microamp - regulator-always-on - regulator-boot-on From 3f2d6efc9c8c70efb1f66ed50075295b1a82f8ff Mon Sep 17 00:00:00 2001 From: Yuval Peress Date: Thu, 4 Jan 2024 08:04:12 -0700 Subject: [PATCH 1851/3723] icm42688: Remove unnecessary locks The entire switch statement is already wrapped in a lock which is acquired just before configuring the gpio pin. Signed-off-by: Yuval Peress --- drivers/sensor/icm42688/icm42688_trigger.c | 2 -- 1 file changed, 2 deletions(-) diff --git a/drivers/sensor/icm42688/icm42688_trigger.c b/drivers/sensor/icm42688/icm42688_trigger.c index 32b60f3cd75..3254a252e09 100644 --- a/drivers/sensor/icm42688/icm42688_trigger.c +++ b/drivers/sensor/icm42688/icm42688_trigger.c @@ -99,9 +99,7 @@ int icm42688_trigger_set(const struct device *dev, const struct sensor_trigger * data->data_ready_handler = handler; data->data_ready_trigger = trig; - icm42688_lock(dev); icm42688_spi_read(&cfg->spi, REG_INT_STATUS, &status, 1); - icm42688_unlock(dev); break; default: res = -ENOTSUP; From 5edc45421ad2ba5f177a847157d00df5ae3cc9e2 Mon Sep 17 00:00:00 2001 From: Yuval Peress Date: Thu, 4 Jan 2024 08:04:57 -0700 Subject: [PATCH 1852/3723] icm42688: Capture the spi return value Handle the return value of the spi transaction. Fixes #58582 Signed-off-by: Yuval Peress --- drivers/sensor/icm42688/icm42688_trigger.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/sensor/icm42688/icm42688_trigger.c b/drivers/sensor/icm42688/icm42688_trigger.c index 3254a252e09..72ccd7e9059 100644 --- a/drivers/sensor/icm42688/icm42688_trigger.c +++ b/drivers/sensor/icm42688/icm42688_trigger.c @@ -99,7 +99,7 @@ int icm42688_trigger_set(const struct device *dev, const struct sensor_trigger * data->data_ready_handler = handler; data->data_ready_trigger = trig; - icm42688_spi_read(&cfg->spi, REG_INT_STATUS, &status, 1); + res = icm42688_spi_read(&cfg->spi, REG_INT_STATUS, &status, 1); break; default: res = -ENOTSUP; From b19c164e7b485f409b2c2b69b86bc5f9db8cbac0 Mon Sep 17 00:00:00 2001 From: Sylvio Alves Date: Thu, 4 Jan 2024 14:06:11 -0300 Subject: [PATCH 1853/3723] soc: espressif: add common linker tls entry Adds common thread-local-storage.ld provided by Zephyr. This also fixes a wrong xtensa_core entry that should be riscv_core. Signed-off-by: Sylvio Alves --- soc/riscv/espressif_esp32/esp32c3/default.ld | 12 ++++-------- soc/xtensa/espressif_esp32/esp32/default.ld | 7 +------ soc/xtensa/espressif_esp32/esp32s2/default.ld | 7 +------ soc/xtensa/espressif_esp32/esp32s3/default.ld | 7 +------ 4 files changed, 7 insertions(+), 26 deletions(-) diff --git a/soc/riscv/espressif_esp32/esp32c3/default.ld b/soc/riscv/espressif_esp32/esp32c3/default.ld index 0884e3d7d3a..65984b4fd7b 100644 --- a/soc/riscv/espressif_esp32/esp32c3/default.ld +++ b/soc/riscv/espressif_esp32/esp32c3/default.ld @@ -142,8 +142,8 @@ SECTIONS #include . = ALIGN(4); - *(EXCLUDE_FILE (*libarch__xtensa__core.a:* *libkernel.a:fatal.* *libkernel.a:init.* *libzephyr.a:cbprintf_complete* *libzephyr.a:log_core.* *libzephyr.a:log_backend_uart.* *libdrivers__flash.a:esp32_mp.* *libzephyr.a:log_output.* *libzephyr.a:loader.* *libdrivers__flash.a:flash_esp32.* *libdrivers__serial.a:uart_esp32.* *libzephyr.a:spi_flash_rom_patch.*) .rodata) - *(EXCLUDE_FILE (*libarch__xtensa__core.a:* *libkernel.a:fatal.* *libkernel.a:init.* *libzephyr.a:cbprintf_complete* *libzephyr.a:log_core.* *libzephyr.a:log_backend_uart.* *libdrivers__flash.a:esp32_mp.* *libzephyr.a:log_output.* *libzephyr.a:loader.* *libdrivers__flash.a:flash_esp32.* *libdrivers__serial.a:uart_esp32.* *libzephyr.a:spi_flash_rom_patch.*) .rodata.*) + *(EXCLUDE_FILE (*libarch__riscv__core.a:* *libkernel.a:fatal.* *libkernel.a:init.* *libzephyr.a:cbprintf_complete* *libzephyr.a:log_core.* *libzephyr.a:log_backend_uart.* *libdrivers__flash.a:esp32_mp.* *libzephyr.a:log_output.* *libzephyr.a:loader.* *libdrivers__flash.a:flash_esp32.* *libdrivers__serial.a:uart_esp32.* *libzephyr.a:spi_flash_rom_patch.*) .rodata) + *(EXCLUDE_FILE (*libarch__riscv__core.a:* *libkernel.a:fatal.* *libkernel.a:init.* *libzephyr.a:cbprintf_complete* *libzephyr.a:log_core.* *libzephyr.a:log_backend_uart.* *libdrivers__flash.a:esp32_mp.* *libzephyr.a:log_output.* *libzephyr.a:loader.* *libdrivers__flash.a:flash_esp32.* *libdrivers__serial.a:uart_esp32.* *libzephyr.a:spi_flash_rom_patch.*) .rodata.*) *(.irom1.text) /* catch stray ICACHE_RODATA_ATTR */ *(.gnu.linkonce.r.*) @@ -175,18 +175,12 @@ SECTIONS *(.gnu.linkonce.lit4.*) _lit4_end = ABSOLUTE(.); . = ALIGN(4); - _thread_local_start = ABSOLUTE(.); - *(.tdata) - *(.tdata.*) - *(.tbss) - *(.tbss.*) *(.srodata) *(.srodata.*) *(.rodata) *(.rodata.*) *(.rodata_wlog) *(.rodata_wlog*) - _thread_local_end = ABSOLUTE(.); . = ALIGN(4); } GROUP_DATA_LINK_IN(RODATA_REGION, ROMABLE_REGION) @@ -197,6 +191,7 @@ SECTIONS #include #include #include + #include #include /* Create an explicit section at the end of all the data that shall be mapped into drom. @@ -233,6 +228,7 @@ SECTIONS *(.iram0.literal .iram.literal .iram.text.literal .iram0.text .iram.text) *libesp32.a:panic.*(.literal .text .literal.* .text.*) *librtc.a:(.literal .text .literal.* .text.*) + *libarch__riscv__core.a:(.literal .text .literal.* .text.*) *libsubsys__net__l2__ethernet.a:(.literal .text .literal.* .text.*) *libsubsys__net__lib__config.a:(.literal .text .literal.* .text.*) *libsubsys__net__ip.a:(.literal .text .literal.* .text.*) diff --git a/soc/xtensa/espressif_esp32/esp32/default.ld b/soc/xtensa/espressif_esp32/esp32/default.ld index 20dc3c28ef5..7a78c49f364 100644 --- a/soc/xtensa/espressif_esp32/esp32/default.ld +++ b/soc/xtensa/espressif_esp32/esp32/default.ld @@ -203,14 +203,8 @@ SECTIONS *(.gnu.linkonce.lit4.*) _lit4_end = ABSOLUTE(.); . = ALIGN(4); - _thread_local_start = ABSOLUTE(.); - *(.tdata) - *(.tdata.*) - *(.tbss) - *(.tbss.*) *(.rodata_wlog) *(.rodata_wlog*) - _thread_local_end = ABSOLUTE(.); . = ALIGN(4); } GROUP_DATA_LINK_IN(RODATA_REGION, ROMABLE_REGION) @@ -221,6 +215,7 @@ SECTIONS #include #include #include + #include #include /* Create an explicit section at the end of all the data that shall be mapped into drom. diff --git a/soc/xtensa/espressif_esp32/esp32s2/default.ld b/soc/xtensa/espressif_esp32/esp32s2/default.ld index 15f654d4b99..8a78bb89ac2 100644 --- a/soc/xtensa/espressif_esp32/esp32s2/default.ld +++ b/soc/xtensa/espressif_esp32/esp32s2/default.ld @@ -175,14 +175,8 @@ SECTIONS *(.gnu.linkonce.lit4.*) _lit4_end = ABSOLUTE(.); . = ALIGN(4); - _thread_local_start = ABSOLUTE(.); - *(.tdata) - *(.tdata.*) - *(.tbss) - *(.tbss.*) *(.rodata_wlog) *(.rodata_wlog*) - _thread_local_end = ABSOLUTE(.); . = ALIGN(4); } GROUP_DATA_LINK_IN(RODATA_REGION, ROMABLE_REGION) @@ -192,6 +186,7 @@ SECTIONS #include #include #include + #include #include /* Create an explicit section at the end of all the data that shall be mapped into drom. diff --git a/soc/xtensa/espressif_esp32/esp32s3/default.ld b/soc/xtensa/espressif_esp32/esp32s3/default.ld index 90b6c89ada2..4076ea7c1af 100644 --- a/soc/xtensa/espressif_esp32/esp32s3/default.ld +++ b/soc/xtensa/espressif_esp32/esp32s3/default.ld @@ -211,14 +211,8 @@ SECTIONS *(.gnu.linkonce.lit4.*) _lit4_end = ABSOLUTE(.); . = ALIGN(4); - _thread_local_start = ABSOLUTE(.); - *(.tdata) - *(.tdata.*) - *(.tbss) - *(.tbss.*) *(.rodata_wlog) *(.rodata_wlog*) - _thread_local_end = ABSOLUTE(.); . = ALIGN(4); } GROUP_DATA_LINK_IN(RODATA_REGION, ROMABLE_REGION) @@ -229,6 +223,7 @@ SECTIONS #include #include #include + #include #include /* Create an explicit section at the end of all the data that shall be mapped into drom. From 617b45ab59e984bcf22798b7c460c33572700c6a Mon Sep 17 00:00:00 2001 From: Sylvio Alves Date: Thu, 4 Jan 2024 14:18:59 -0300 Subject: [PATCH 1854/3723] west.yml: update hal_espressif to fix libc calls Make sure some ROM libc calls are weak to allow Zephyr's libc implementation instead. Fixes #66351 Signed-off-by: Sylvio Alves --- west.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/west.yml b/west.yml index 4b29e9b9fd2..692813cc159 100644 --- a/west.yml +++ b/west.yml @@ -152,7 +152,7 @@ manifest: groups: - hal - name: hal_espressif - revision: e98ce93e916eebdc4a0c5bceef864289447e3d63 + revision: a248460c09b6588428f6edaf5ebe312648c7360c path: modules/hal/espressif west-commands: west/west-commands.yml groups: From 57238057f07182057bbc558c0aaf795effc33c41 Mon Sep 17 00:00:00 2001 From: Karol Gugala Date: Sat, 6 Jan 2024 17:14:42 +0100 Subject: [PATCH 1855/3723] boards: efm32gg_sltb009a: uart: switch to new pinctrl API The board uses pinctrl API. This commit updates pin USART pin definition to be compliant with new API. Signed-off-by: Karol Gugala --- .../efm32gg_sltb009a-pinctrl.dtsi | 19 +++++++++++++++++++ .../arm/efm32gg_sltb009a/efm32gg_sltb009a.dts | 5 +++-- 2 files changed, 22 insertions(+), 2 deletions(-) create mode 100644 boards/arm/efm32gg_sltb009a/efm32gg_sltb009a-pinctrl.dtsi diff --git a/boards/arm/efm32gg_sltb009a/efm32gg_sltb009a-pinctrl.dtsi b/boards/arm/efm32gg_sltb009a/efm32gg_sltb009a-pinctrl.dtsi new file mode 100644 index 00000000000..71d20205691 --- /dev/null +++ b/boards/arm/efm32gg_sltb009a/efm32gg_sltb009a-pinctrl.dtsi @@ -0,0 +1,19 @@ +/* + * Copyright (c) 2024 Antmicro + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include + +&pinctrl { + /* configuration for usart0 device, default state - operating as UART */ + usart0_default: usart0_default { + group1 { + psels = , + , + , + ; + }; + }; +}; diff --git a/boards/arm/efm32gg_sltb009a/efm32gg_sltb009a.dts b/boards/arm/efm32gg_sltb009a/efm32gg_sltb009a.dts index 1ff034899db..5dcae30fbee 100644 --- a/boards/arm/efm32gg_sltb009a/efm32gg_sltb009a.dts +++ b/boards/arm/efm32gg_sltb009a/efm32gg_sltb009a.dts @@ -7,6 +7,7 @@ /dts-v1/; #include #include +#include "efm32gg_sltb009a-pinctrl.dtsi" / { model = "Silicon Labs EFM32GG SLTB009A board"; @@ -57,8 +58,8 @@ &usart0 { current-speed = <115200>; - location-rx = ; - location-tx = ; + pinctrl-0 = <&usart0_default>; + pinctrl-names = "default"; status = "okay"; }; From 133d8c781791f87a3a4516e8596d96ed3ea5429a Mon Sep 17 00:00:00 2001 From: Karol Gugala Date: Sat, 6 Jan 2024 17:32:47 +0100 Subject: [PATCH 1856/3723] boards: efm32pg_stk3401a: uart: switch to new pinctrl API The board uses pinctrl API. This commit updates pin USART pin definition to be compliant with new API. Signed-off-by: Karol Gugala --- .../efm32pg_stk3401a-pinctrl.dtsi | 19 +++++++++++++++++++ .../efm32pg_stk3401a_common.dtsi | 5 +++-- 2 files changed, 22 insertions(+), 2 deletions(-) create mode 100644 boards/arm/efm32pg_stk3401a/efm32pg_stk3401a-pinctrl.dtsi diff --git a/boards/arm/efm32pg_stk3401a/efm32pg_stk3401a-pinctrl.dtsi b/boards/arm/efm32pg_stk3401a/efm32pg_stk3401a-pinctrl.dtsi new file mode 100644 index 00000000000..24b51c33612 --- /dev/null +++ b/boards/arm/efm32pg_stk3401a/efm32pg_stk3401a-pinctrl.dtsi @@ -0,0 +1,19 @@ +/* + * Copyright (c) 2024 Antmicro + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include + +&pinctrl { + /* configuration for usart0 device, default state - operating as UART */ + usart0_default: usart0_default { + group1 { + psels = , + , + , + ; + }; + }; +}; diff --git a/boards/arm/efm32pg_stk3401a/efm32pg_stk3401a_common.dtsi b/boards/arm/efm32pg_stk3401a/efm32pg_stk3401a_common.dtsi index cb0209f8e4a..6611bee4956 100644 --- a/boards/arm/efm32pg_stk3401a/efm32pg_stk3401a_common.dtsi +++ b/boards/arm/efm32pg_stk3401a/efm32pg_stk3401a_common.dtsi @@ -5,6 +5,7 @@ */ #include +#include "efm32pg_stk3401a-pinctrl.dtsi" / { model = "Silicon Labs EFM32PG STK3401A board"; @@ -60,8 +61,8 @@ &usart0 { current-speed = <115200>; - location-rx = ; - location-tx = ; + pinctrl-0 = <&usart0_default>; + pinctrl-names = "default"; status = "okay"; }; From 58f5720eb43f2f4b291aa939dafaca55f930ad8a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Manuel=20Arg=C3=BCelles?= Date: Tue, 26 Dec 2023 14:51:54 +0700 Subject: [PATCH 1857/3723] dts: arm: nxp: add FlexCAN support for S32K1xx MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit S32K1xx devices have a maximum of 3 FlexCAN peripherals. Each part may define a different maximum number of instances and message buffers, hence the interrupt lines are defined in the part specific dts. Signed-off-by: Manuel Argüelles --- dts/arm/nxp/nxp_s32k146.dtsi | 17 +++++++++++++++++ dts/arm/nxp/nxp_s32k1xx.dtsi | 22 ++++++++++++++++++++++ soc/arm/nxp_s32/s32k1/Kconfig.series | 1 + west.yml | 2 +- 4 files changed, 41 insertions(+), 1 deletion(-) diff --git a/dts/arm/nxp/nxp_s32k146.dtsi b/dts/arm/nxp/nxp_s32k146.dtsi index be62957cae2..bfbb1558349 100644 --- a/dts/arm/nxp/nxp_s32k146.dtsi +++ b/dts/arm/nxp/nxp_s32k146.dtsi @@ -61,3 +61,20 @@ &lpspi2 { clocks = <&clock NXP_S32_LPSPI2_CLK>; }; + +&flexcan0 { + interrupts = <78 0>, <79 0>, <80 0>, <81 0>, <82 0>; + interrupt-names = "warning", "error", "wake-up", "mb-0-15", "mb-16-31"; +}; + +&flexcan1 { + interrupts = <85 0>, <86 0>, <88 0>, <89 0>; + interrupt-names = "warning", "error", "mb-0-15", "mb-16-31"; + clocks = <&clock NXP_S32_FLEXCAN1_CLK>; +}; + +&flexcan2 { + interrupts = <92 0>, <93 0>, <95 0>; + interrupt-names = "warning", "error", "mb-0-15"; + clocks = <&clock NXP_S32_FLEXCAN2_CLK>; +}; diff --git a/dts/arm/nxp/nxp_s32k1xx.dtsi b/dts/arm/nxp/nxp_s32k1xx.dtsi index dc0763a0e9f..a8c07d14028 100644 --- a/dts/arm/nxp/nxp_s32k1xx.dtsi +++ b/dts/arm/nxp/nxp_s32k1xx.dtsi @@ -44,6 +44,28 @@ status = "disabled"; }; + flexcan0: can@40024000 { + compatible = "nxp,flexcan-fd", "nxp,flexcan"; + reg = <0x40024000 0x1000>; + clocks = <&clock NXP_S32_FLEXCAN0_CLK>; + clk-source = <1>; + status = "disabled"; + }; + + flexcan1: can@40025000 { + compatible = "nxp,flexcan-fd", "nxp,flexcan"; + reg = <0x40025000 0x1000>; + clk-source = <1>; + status = "disabled"; + }; + + flexcan2: can@4002b000 { + compatible = "nxp,flexcan-fd", "nxp,flexcan"; + reg = <0x4002b000 0x1000>; + clk-source = <1>; + status = "disabled"; + }; + lpspi0: spi@4002c000 { compatible = "nxp,imx-lpspi"; reg = <0x4002c000 0x1000>; diff --git a/soc/arm/nxp_s32/s32k1/Kconfig.series b/soc/arm/nxp_s32/s32k1/Kconfig.series index df7070e8e75..12d74205412 100644 --- a/soc/arm/nxp_s32/s32k1/Kconfig.series +++ b/soc/arm/nxp_s32/s32k1/Kconfig.series @@ -17,5 +17,6 @@ config SOC_SERIES_S32K1XX select HAS_MCUX_LPI2C select HAS_MCUX_LPSPI select HAS_MCUX_FTM + select HAS_MCUX_FLEXCAN help Enable support for NXP S32K1XX MCU series. diff --git a/west.yml b/west.yml index 692813cc159..be923f8a989 100644 --- a/west.yml +++ b/west.yml @@ -193,7 +193,7 @@ manifest: groups: - hal - name: hal_nxp - revision: 4605f6715c6a55121da8fcbff060e01c4383c1e9 + revision: 12970d629fc900010dab5cf250be70287bf9e443 path: modules/hal/nxp groups: - hal From fa0b1b5fe82e94cfc71ed553d37fe59145608e72 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Manuel=20Arg=C3=BCelles?= Date: Tue, 26 Dec 2023 14:53:20 +0700 Subject: [PATCH 1858/3723] drivers: can: flexcan: add support for S32K1xx MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Add message buffer allowed values for S32K1xx devices. Except S32K14xW parts which supports 64 MBs, the rest of the parts support a maximum of 32 MBs. Signed-off-by: Manuel Argüelles --- drivers/can/Kconfig.mcux | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/drivers/can/Kconfig.mcux b/drivers/can/Kconfig.mcux index 5983be36c8a..7df67684e8a 100644 --- a/drivers/can/Kconfig.mcux +++ b/drivers/can/Kconfig.mcux @@ -31,8 +31,10 @@ config CAN_MCUX_FLEXCAN_WAIT_TIMEOUT config CAN_MAX_MB int "Maximum number of message buffers for concurrent active instances" default 16 - depends on SOC_SERIES_S32K3XX - range 1 96 + depends on SOC_SERIES_S32K3XX || SOC_SERIES_S32K1XX + range 1 96 if SOC_SERIES_S32K3XX + range 1 32 if SOC_SERIES_S32K1XX && !SOC_S32K142W && !SOC_S32K144W + range 1 64 if SOC_S32K142W || SOC_S32K144W help Defines maximum number of message buffers for concurrent active instances. @@ -43,6 +45,8 @@ config CAN_MAX_FILTER range 1 13 if SOC_SERIES_IMX_RT && CAN_MCUX_FLEXCAN_FD range 1 63 if SOC_SERIES_IMX_RT range 1 96 if SOC_SERIES_S32K3XX + range 1 32 if SOC_SERIES_S32K1XX && !SOC_S32K142W && !SOC_S32K144W + range 1 64 if SOC_S32K142W || SOC_S32K144W help Defines maximum number of concurrent active RX filters From c68564bc93463a8d646be4dacd064a49dcdb5b12 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Manuel=20Arg=C3=BCelles?= Date: Tue, 26 Dec 2023 16:59:43 +0700 Subject: [PATCH 1859/3723] boards: arm: ucans32k1sic: enable FlexCAN MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Enable FlexCAN peripheral driver for ucans32k1sic board. The GPIO-based CAN transceiver driver is used to control the on-board CAN transceivers. Signed-off-by: Manuel Argüelles --- boards/arm/ucans32k1sic/Kconfig.defconfig | 7 ++++ boards/arm/ucans32k1sic/doc/index.rst | 1 + .../ucans32k1sic/ucans32k1sic-pinctrl.dtsi | 14 +++++++ boards/arm/ucans32k1sic/ucans32k1sic.dts | 37 +++++++++++++++++++ boards/arm/ucans32k1sic/ucans32k1sic.yaml | 1 + 5 files changed, 60 insertions(+) diff --git a/boards/arm/ucans32k1sic/Kconfig.defconfig b/boards/arm/ucans32k1sic/Kconfig.defconfig index 88941a6f64a..044df50c0c5 100644 --- a/boards/arm/ucans32k1sic/Kconfig.defconfig +++ b/boards/arm/ucans32k1sic/Kconfig.defconfig @@ -13,4 +13,11 @@ config UART_CONSOLE endif # SERIAL +if CAN + +config GPIO + default y + +endif # CAN + endif # BOARD_UCANS32K1SIC diff --git a/boards/arm/ucans32k1sic/doc/index.rst b/boards/arm/ucans32k1sic/doc/index.rst index efeb6911d7e..adceb43de03 100644 --- a/boards/arm/ucans32k1sic/doc/index.rst +++ b/boards/arm/ucans32k1sic/doc/index.rst @@ -50,6 +50,7 @@ LPUART on-chip serial LPI2C on-chip i2c LPSPI on-chip spi FTM on-chip pwm +FlexCAN on-chip can ============ ========== ================================ The default configuration can be found in the Kconfig file diff --git a/boards/arm/ucans32k1sic/ucans32k1sic-pinctrl.dtsi b/boards/arm/ucans32k1sic/ucans32k1sic-pinctrl.dtsi index b1451d26287..2bb216e63ae 100644 --- a/boards/arm/ucans32k1sic/ucans32k1sic-pinctrl.dtsi +++ b/boards/arm/ucans32k1sic/ucans32k1sic-pinctrl.dtsi @@ -60,4 +60,18 @@ drive-strength = "low"; }; }; + + flexcan0_default: flexcan0_default { + group0 { + pinmux = , ; + drive-strength = "low"; + }; + }; + + flexcan1_default: flexcan1_default { + group0 { + pinmux = , ; + drive-strength = "low"; + }; + }; }; diff --git a/boards/arm/ucans32k1sic/ucans32k1sic.dts b/boards/arm/ucans32k1sic/ucans32k1sic.dts index 23a380b4c44..6996a12d6d0 100644 --- a/boards/arm/ucans32k1sic/ucans32k1sic.dts +++ b/boards/arm/ucans32k1sic/ucans32k1sic.dts @@ -21,6 +21,7 @@ zephyr,console = &lpuart1; zephyr,shell-uart = &lpuart1; zephyr,uart-pipe = &lpuart1; + zephyr,canbus = &flexcan0; }; aliases { @@ -81,6 +82,20 @@ zephyr,code = ; }; }; + + can_phy0: can-phy0 { + compatible = "nxp,tja1463", "nxp,tja1443", "nxp,tja1153", "can-transceiver-gpio"; + enable-gpios = <&gpioa 10 GPIO_ACTIVE_HIGH>; + max-bitrate = <8000000>; + #phy-cells = <0>; + }; + + can_phy1: can-phy1 { + compatible = "nxp,tja1463", "nxp,tja1443", "nxp,tja1153", "can-transceiver-gpio"; + enable-gpios = <&gpioe 2 GPIO_ACTIVE_HIGH>; + max-bitrate = <8000000>; + #phy-cells = <0>; + }; }; &gpioa { @@ -154,3 +169,25 @@ #pwm-cells = <3>; status = "okay"; }; + +&flexcan0 { + pinctrl-0 = <&flexcan0_default>; + pinctrl-names = "default"; + phys = <&can_phy0>; + bus-speed = <125000>; + sample-point = <875>; + bus-speed-data = <1000000>; + sample-point-data = <875>; + status = "okay"; +}; + +&flexcan1 { + pinctrl-0 = <&flexcan1_default>; + pinctrl-names = "default"; + phys = <&can_phy1>; + bus-speed = <125000>; + sample-point = <875>; + bus-speed-data = <1000000>; + sample-point-data = <875>; + status = "okay"; +}; diff --git a/boards/arm/ucans32k1sic/ucans32k1sic.yaml b/boards/arm/ucans32k1sic/ucans32k1sic.yaml index fd0b23a40b9..d4bf0d5065c 100644 --- a/boards/arm/ucans32k1sic/ucans32k1sic.yaml +++ b/boards/arm/ucans32k1sic/ucans32k1sic.yaml @@ -18,3 +18,4 @@ supported: - i2c - spi - pwm + - can From e0c24c8842e53a0e26a84e62974171b04cae9964 Mon Sep 17 00:00:00 2001 From: Fabio Baltieri Date: Mon, 8 Jan 2024 11:32:28 +0000 Subject: [PATCH 1860/3723] doc: input: few minor fixes Few documentation fixes that got caught post merge. Signed-off-by: Fabio Baltieri --- doc/services/input/gpio-kbd.rst | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/doc/services/input/gpio-kbd.rst b/doc/services/input/gpio-kbd.rst index fffabc7ac79..2910405bdd2 100644 --- a/doc/services/input/gpio-kbd.rst +++ b/doc/services/input/gpio-kbd.rst @@ -160,10 +160,10 @@ The same is true for column GPIOs, but only if the matrix is configured for ``col-drive-inactive``, so that is only usable for matrixes with isolation diodes. -16 bit row support +16-bit row support ****************** -The driver uses an 8 bit datatype to store the row state by default, which +The driver uses an 8-bit datatype to store the row state by default, which limits the matrix row size to 8. This can be increased to 16 by enabling the :kconfig:option:`CONFIG_INPUT_KBD_MATRIX_16_BIT_ROW` option. @@ -192,10 +192,10 @@ For example for a 3x3 matrix missing a key: actual-key-mask = <0x07 0x05 0x07>; }; -Would allow, for example, to detect pressing ``Sw0``, ``SW1`` and ``SW3`` at -the same time without triggering anti ghosting. +This would allow, for example, to detect pressing ``Sw1``, ``SW2`` and ``SW4`` +at the same time without triggering anti ghosting. -The actual key mask can be changed in runtime by enabling +The actual key mask can be changed at runtime by enabling :kconfig:option:`CONFIG_INPUT_KBD_ACTUAL_KEY_MASK_DYNAMIC` and the using the :c:func:`input_kbd_matrix_actual_key_mask_set` API. From 34b9b3aacac3d2f64282114d90b67b501f2b4fde Mon Sep 17 00:00:00 2001 From: Jun Lin Date: Tue, 2 Jan 2024 10:45:51 +0800 Subject: [PATCH 1861/3723] dts: npcx: sha: fix the incorrect unit address Fix the incorrect unit address of sha node from 13C to 148 to avoid the build warning. Signed-off-by: Jun Lin --- dts/arm/nuvoton/npcx/npcx4.dtsi | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/dts/arm/nuvoton/npcx/npcx4.dtsi b/dts/arm/nuvoton/npcx/npcx4.dtsi index 5cc63cb658e..004ca5332af 100644 --- a/dts/arm/nuvoton/npcx/npcx4.dtsi +++ b/dts/arm/nuvoton/npcx/npcx4.dtsi @@ -289,7 +289,7 @@ clocks = <&pcc NPCX_CLOCK_BUS_FIU0 NPCX_PWDWN_CTL8 6>; }; - sha0: sha@13c { + sha0: sha@148 { compatible = "nuvoton,npcx-sha"; reg = <0x148 0x4c>; context-buffer-size = <240>; From fa5cb1afa88883f44418bb3c161f9bc376c57608 Mon Sep 17 00:00:00 2001 From: Yong Cong Sin Date: Mon, 11 Dec 2023 16:54:49 +0800 Subject: [PATCH 1862/3723] boards: hifive_unmatched: add renode simulation Changes to this file were missed out from the original PR #65564 that added Renode support for this board, add them here so that it gets ran in CI. Signed-off-by: Yong Cong Sin --- boards/riscv/hifive_unmatched/hifive_unmatched.yaml | 2 ++ 1 file changed, 2 insertions(+) diff --git a/boards/riscv/hifive_unmatched/hifive_unmatched.yaml b/boards/riscv/hifive_unmatched/hifive_unmatched.yaml index 8b62698b61b..39450132d44 100644 --- a/boards/riscv/hifive_unmatched/hifive_unmatched.yaml +++ b/boards/riscv/hifive_unmatched/hifive_unmatched.yaml @@ -5,6 +5,8 @@ arch: riscv64 toolchain: - zephyr ram: 3840 +simulation: renode +simulation_exec: renode testing: ignore_tags: - net From c7ce871a04b03f5f232ff7a89c72b48eecde3098 Mon Sep 17 00:00:00 2001 From: Yong Cong Sin Date: Sat, 23 Dec 2023 17:45:38 +0800 Subject: [PATCH 1863/3723] tests: exclude `renode` from tests requiring unsimulated peripherals Physical boards work on these tests but some of the required peripherals are not simulated by `renode`, executing the tests with renode-simulated board in CI will fail. Exclude `renode` simulation from these tests. Signed-off-by: Yong Cong Sin --- samples/subsys/fs/fs_sample/sample.yaml | 2 ++ tests/drivers/memc/ram/testcase.yaml | 2 ++ tests/subsys/fs/ext2/testcase.yaml | 2 ++ 3 files changed, 6 insertions(+) diff --git a/samples/subsys/fs/fs_sample/sample.yaml b/samples/subsys/fs/fs_sample/sample.yaml index 375bacf4f8f..58c0cf62361 100644 --- a/samples/subsys/fs/fs_sample/sample.yaml +++ b/samples/subsys/fs/fs_sample/sample.yaml @@ -43,6 +43,8 @@ tests: integration_platforms: - frdm_k64f sample.filesystem.ext2: + simulation_exclude: + - renode extra_args: CONF_FILE="prj_ext.conf" platform_allow: hifive_unmatched bl5340_dvk_cpuapp sample.filesystem.fat_fs.stm32h747i_disco_m7_sdmmc: diff --git a/tests/drivers/memc/ram/testcase.yaml b/tests/drivers/memc/ram/testcase.yaml index 0fac2dea9b4..5d9f768b8bb 100644 --- a/tests/drivers/memc/ram/testcase.yaml +++ b/tests/drivers/memc/ram/testcase.yaml @@ -21,6 +21,8 @@ tests: integration_platforms: - sam4s_xplained drivers.memc.sifive_ddr: + simulation_exclude: + - renode tags: - drivers - memc diff --git a/tests/subsys/fs/ext2/testcase.yaml b/tests/subsys/fs/ext2/testcase.yaml index 7466e0984b9..bb4402c9b0e 100644 --- a/tests/subsys/fs/ext2/testcase.yaml +++ b/tests/subsys/fs/ext2/testcase.yaml @@ -19,6 +19,8 @@ tests: - EXTRA_DTC_OVERLAY_FILE="ramdisk_big.overlay" filesystem.ext2.sdcard: + simulation_exclude: + - renode platform_allow: - hifive_unmatched - bl5340_dvk_cpuapp From fe75bb950f45c1740225a21a2638a20080f4e967 Mon Sep 17 00:00:00 2001 From: Chun-Chieh Li Date: Thu, 14 Dec 2023 17:23:19 +0800 Subject: [PATCH 1864/3723] shields: esp_8266: support Nuvoton numaker_pfm_m467 board 1. Support H/W reset pin 2. Support UART flow control (CTS/RTS) Signed-off-by: Chun-Chieh Li --- .../esp_8266/boards/numaker_pfm_m467.overlay | 35 +++++++++++++++++++ 1 file changed, 35 insertions(+) create mode 100644 boards/shields/esp_8266/boards/numaker_pfm_m467.overlay diff --git a/boards/shields/esp_8266/boards/numaker_pfm_m467.overlay b/boards/shields/esp_8266/boards/numaker_pfm_m467.overlay new file mode 100644 index 00000000000..f28bf527c9a --- /dev/null +++ b/boards/shields/esp_8266/boards/numaker_pfm_m467.overlay @@ -0,0 +1,35 @@ +/* + * Copyright (c) 2023 Nuvoton Technology Corporation. + * + * SPDX-License-Identifier: Apache-2.0 + */ + +&pinctrl { + uart2_esp8266: uart2_esp8266 { + group0 { + pinmux = , + , + , + ; + }; + }; +}; + +&uart2 { + status = "okay"; + current-speed = <115200>; + hw-flow-control; + + pinctrl-0 = <&uart2_esp8266>; + pinctrl-names = "default"; + + esp8266: esp8266 { + compatible = "espressif,esp-at"; + reset-gpios = <&gpioc 4 GPIO_ACTIVE_LOW>; + status = "okay"; + }; +}; + +&gpioc { + status = "okay"; +}; From 2ee6c26d15a04bf03fee29f84cf421017272db4b Mon Sep 17 00:00:00 2001 From: Marc Herbert Date: Tue, 26 Dec 2023 23:25:03 +0000 Subject: [PATCH 1865/3723] west: sign.py: rename new `generated/platf.toml` to `rimage_config.toml` CMake-based build systems like Zephyr's use separate build directories; one for each build configuration. Even Zephyr's multi-build system "sysbuild" (which is not relevant here) uses separate subdirectories. So there is only one pre-processed, .toml file generated by build directory and no need to vary its filename based on the platform name or any other configuration parameter. It can and should keep the same filename across build directories as zephyr.elf and all other build artefacts do. Moreover, when building a collection of configurations (as for instance `sof/scripts/xtensa-build-zephyr.py` does), keeping all build directories consistent with each other simplifies installation, checksumming and any other post-processing. "Fixes" recent commit 15336045aff8 ("west: sign.py: generate platf.toml from platf.toml.h with cc -E") Signed-off-by: Marc Herbert --- scripts/west_commands/sign.py | 11 +++++------ 1 file changed, 5 insertions(+), 6 deletions(-) diff --git a/scripts/west_commands/sign.py b/scripts/west_commands/sign.py index 8d961004adb..4f001187b21 100644 --- a/scripts/west_commands/sign.py +++ b/scripts/west_commands/sign.py @@ -442,7 +442,7 @@ def preprocess_toml(self, config_dir, toml_basename, subdir): preproc_cmd += ['-I', str(self.sof_src_dir / 'src')] preproc_cmd += ['-imacros', str(pathlib.Path('zephyr') / 'include' / 'generated' / 'autoconf.h')] - preproc_cmd += ['-o', str(subdir / toml_basename)] + preproc_cmd += ['-o', str(subdir / 'rimage_config.toml')] self.command.inf(quote_sh_list(preproc_cmd)) subprocess.run(preproc_cmd, check=True, cwd=self.build_dir) @@ -573,13 +573,12 @@ def sign(self, command, build_dir, build_conf, formats): command.die(f"Cannot have both {toml_basename + '.h'} and {toml_basename} in {conf_dir}") if (conf_dir / (toml_basename + '.h')).exists(): - toml_subdir = pathlib.Path('zephyr') / 'misc' / 'generated' - self.preprocess_toml(conf_dir, toml_basename, toml_subdir) - toml_dir = b / toml_subdir + generated_subdir = pathlib.Path('zephyr') / 'misc' / 'generated' + self.preprocess_toml(conf_dir, toml_basename, generated_subdir) + extra_ri_args += ['-c', str(b / generated_subdir / 'rimage_config.toml')] else: toml_dir = conf_dir - - extra_ri_args += ['-c', str(toml_dir / toml_basename)] + extra_ri_args += ['-c', str(toml_dir / toml_basename)] # Warning: while not officially supported (yet?), the rimage --option that is last # on the command line currently wins in case of duplicate options. So pay From a27e8f9a197668b77cdb46e3e96350548fef57a9 Mon Sep 17 00:00:00 2001 From: Marc Herbert Date: Tue, 26 Dec 2023 23:40:46 +0000 Subject: [PATCH 1866/3723] west: sign.py: explain why `-P` is passed to cpp Zero-functional change. Also move it to a separate line so it's more convenient to temporarily comment it out. Signed-off-by: Marc Herbert --- scripts/west_commands/sign.py | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/scripts/west_commands/sign.py b/scripts/west_commands/sign.py index 4f001187b21..54006e565c7 100644 --- a/scripts/west_commands/sign.py +++ b/scripts/west_commands/sign.py @@ -438,7 +438,12 @@ def preprocess_toml(self, config_dir, toml_basename, subdir): 'Runs the C pre-processor on config_dir/toml_basename.h' compiler_path = self.cmake_cache.get("CMAKE_C_COMPILER") - preproc_cmd = [compiler_path, '-P', '-E', str(config_dir / (toml_basename + '.h'))] + preproc_cmd = [compiler_path, '-E', str(config_dir / (toml_basename + '.h'))] + # -P removes line markers to keep the .toml output reproducible. To + # trace #includes, temporarily comment out '-P' (-f*-prefix-map + # unfortunately don't seem to make any difference here and they're + # gcc-specific) + preproc_cmd += ['-P'] preproc_cmd += ['-I', str(self.sof_src_dir / 'src')] preproc_cmd += ['-imacros', str(pathlib.Path('zephyr') / 'include' / 'generated' / 'autoconf.h')] From 4aa0e7af683468bb20f2350f962cca295a396e2a Mon Sep 17 00:00:00 2001 From: Marc Herbert Date: Tue, 26 Dec 2023 23:47:02 +0000 Subject: [PATCH 1867/3723] west: sign.py: add "REM" support to pass comments through cpp Generated outputs can be difficult to read, preserving comments helps a lot and they often provide good `git grep` search keywords. Signed-off-by: Marc Herbert --- scripts/west_commands/sign.py | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/scripts/west_commands/sign.py b/scripts/west_commands/sign.py index 54006e565c7..fb1de570974 100644 --- a/scripts/west_commands/sign.py +++ b/scripts/west_commands/sign.py @@ -444,6 +444,16 @@ def preprocess_toml(self, config_dir, toml_basename, subdir): # unfortunately don't seem to make any difference here and they're # gcc-specific) preproc_cmd += ['-P'] + + # "REM" escapes _leading_ '#' characters from cpp and allows + # such comments to be preserved in generated/*.toml files: + # + # REM # my comment... + # + # Note _trailing_ '#' characters and comments are ignored by cpp + # and don't need any REM trick. + preproc_cmd += ['-DREM='] + preproc_cmd += ['-I', str(self.sof_src_dir / 'src')] preproc_cmd += ['-imacros', str(pathlib.Path('zephyr') / 'include' / 'generated' / 'autoconf.h')] From ee337087fa54277f0f60eb2f77fe7f6f277da6aa Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?H=C3=A5vard=20Reierstad?= Date: Tue, 19 Dec 2023 15:10:33 +0100 Subject: [PATCH 1868/3723] bsim: Bluetooth: Mesh: extract common adv logic MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Extracts logic related to waiting for packets from `test_advertiser.c` and `test_beacon.c` to use in a sync mechanism. Introduces a sync mechanism in bsim with the functions `bt_mesh_test_send_over_adv` and `bt_mesh_test_wait_for_packet` Extracts gatt-related logic from `test_advertiser.c` into a separate file so it can be re-used. Signed-off-by: Håvard Reierstad --- tests/bsim/bluetooth/mesh/CMakeLists.txt | 1 + tests/bsim/bluetooth/mesh/src/gatt_common.c | 39 ++++++ tests/bsim/bluetooth/mesh/src/gatt_common.h | 27 ++++ tests/bsim/bluetooth/mesh/src/mesh_test.c | 45 +++++++ tests/bsim/bluetooth/mesh/src/mesh_test.h | 8 ++ .../bsim/bluetooth/mesh/src/test_advertiser.c | 120 ++---------------- tests/bsim/bluetooth/mesh/src/test_beacon.c | 26 +--- 7 files changed, 131 insertions(+), 135 deletions(-) create mode 100644 tests/bsim/bluetooth/mesh/src/gatt_common.c create mode 100644 tests/bsim/bluetooth/mesh/src/gatt_common.h diff --git a/tests/bsim/bluetooth/mesh/CMakeLists.txt b/tests/bsim/bluetooth/mesh/CMakeLists.txt index c6e09abe9c8..1adccdb9413 100644 --- a/tests/bsim/bluetooth/mesh/CMakeLists.txt +++ b/tests/bsim/bluetooth/mesh/CMakeLists.txt @@ -9,6 +9,7 @@ target_sources(app PRIVATE src/main.c src/mesh_test.c src/friendship_common.c + src/gatt_common.c ) if(CONFIG_BT_MESH_V1d1) diff --git a/tests/bsim/bluetooth/mesh/src/gatt_common.c b/tests/bsim/bluetooth/mesh/src/gatt_common.c new file mode 100644 index 00000000000..ff57cebed71 --- /dev/null +++ b/tests/bsim/bluetooth/mesh/src/gatt_common.c @@ -0,0 +1,39 @@ +/* + * Copyright (c) 2023 Nordic Semiconductor + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include "gatt_common.h" +#include +LOG_MODULE_REGISTER(gatt_common); + +void bt_mesh_test_parse_mesh_gatt_preamble(struct net_buf_simple *buf) +{ + ASSERT_EQUAL(0x0201, net_buf_simple_pull_be16(buf)); + /* flags */ + (void)net_buf_simple_pull_u8(buf); + ASSERT_EQUAL(0x0303, net_buf_simple_pull_be16(buf)); +} + +void bt_mesh_test_parse_mesh_pb_gatt_service(struct net_buf_simple *buf) +{ + /* MshPRT Figure 7.1: PB-GATT Advertising Data */ + /* mesh provisioning service */ + ASSERT_EQUAL(0x2718, net_buf_simple_pull_be16(buf)); + ASSERT_EQUAL(0x1516, net_buf_simple_pull_be16(buf)); + /* mesh provisioning service */ + ASSERT_EQUAL(0x2718, net_buf_simple_pull_be16(buf)); +} + +void bt_mesh_test_parse_mesh_proxy_service(struct net_buf_simple *buf) +{ + /* MshPRT Figure 7.2: Advertising with Network ID (Identification Type 0x00) */ + /* mesh proxy service */ + ASSERT_EQUAL(0x2818, net_buf_simple_pull_be16(buf)); + ASSERT_EQUAL(0x0c16, net_buf_simple_pull_be16(buf)); + /* mesh proxy service */ + ASSERT_EQUAL(0x2818, net_buf_simple_pull_be16(buf)); + /* network ID */ + ASSERT_EQUAL(0x00, net_buf_simple_pull_u8(buf)); +} diff --git a/tests/bsim/bluetooth/mesh/src/gatt_common.h b/tests/bsim/bluetooth/mesh/src/gatt_common.h new file mode 100644 index 00000000000..4904325cdb2 --- /dev/null +++ b/tests/bsim/bluetooth/mesh/src/gatt_common.h @@ -0,0 +1,27 @@ +/* + * Copyright (c) 2023 Nordic Semiconductor + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include "mesh_test.h" + +enum bt_mesh_test_gatt_service { + MESH_SERVICE_PROVISIONING, + MESH_SERVICE_PROXY, +}; + +struct bt_mesh_test_gatt { + uint8_t transmits; /* number of frame (pb gatt or proxy beacon) transmits */ + int64_t interval; /* interval of transmitted frames */ + enum bt_mesh_test_gatt_service service; +}; + +struct bt_mesh_test_adv { + uint8_t retr; /* number of retransmits of adv frame */ + int64_t interval; /* interval of transmitted frames */ +}; + +void bt_mesh_test_parse_mesh_gatt_preamble(struct net_buf_simple *buf); +void bt_mesh_test_parse_mesh_pb_gatt_service(struct net_buf_simple *buf); +void bt_mesh_test_parse_mesh_proxy_service(struct net_buf_simple *buf); diff --git a/tests/bsim/bluetooth/mesh/src/mesh_test.c b/tests/bsim/bluetooth/mesh/src/mesh_test.c index 5dce0c8dc9d..2a73d1f4718 100644 --- a/tests/bsim/bluetooth/mesh/src/mesh_test.c +++ b/tests/bsim/bluetooth/mesh/src/mesh_test.c @@ -7,6 +7,7 @@ #include "argparse.h" #include #include "mesh/crypto.h" +#include #define LOG_MODULE_NAME mesh_test @@ -546,6 +547,50 @@ uint16_t bt_mesh_test_own_addr_get(uint16_t start_addr) return start_addr + get_device_nbr(); } +void bt_mesh_test_send_over_adv(void *data, size_t len) +{ + struct bt_mesh_adv *adv = bt_mesh_adv_create(BT_MESH_ADV_DATA, BT_MESH_ADV_TAG_LOCAL, + BT_MESH_TRANSMIT(0, 20), K_NO_WAIT); + net_buf_simple_add_mem(&adv->b, data, len); + bt_mesh_adv_send(adv, NULL, NULL); +} + +int bt_mesh_test_wait_for_packet(bt_le_scan_cb_t scan_cb, struct k_sem *observer_sem, uint16_t wait) +{ + struct bt_le_scan_param scan_param = { + .type = BT_HCI_LE_SCAN_PASSIVE, + .options = BT_LE_SCAN_OPT_NONE, + .interval = BT_MESH_ADV_SCAN_UNIT(1000), + .window = BT_MESH_ADV_SCAN_UNIT(1000) + }; + int err; + int returned_value = 0; + + err = bt_le_scan_start(&scan_param, scan_cb); + if (err && err != -EALREADY) { + LOG_ERR("Starting scan failed (err %d)", err); + return err; + } + + err = k_sem_take(observer_sem, K_SECONDS(wait)); + if (err == -EAGAIN) { + LOG_WRN("Taking sem timed out (err %d)", err); + returned_value = -EAGAIN; + } else if (err) { + LOG_ERR("Taking sem failed (err %d)", err); + return err; + } + + err = bt_le_scan_stop(); + if (err && err != -EALREADY) { + LOG_ERR("Stopping scan failed (err %d)", err); + return err; + } + + return returned_value; +} + + #if defined(CONFIG_BT_MESH_SAR_CFG) void bt_mesh_test_sar_conf_set(struct bt_mesh_sar_tx *tx_set, struct bt_mesh_sar_rx *rx_set) { diff --git a/tests/bsim/bluetooth/mesh/src/mesh_test.h b/tests/bsim/bluetooth/mesh/src/mesh_test.h index 3dcaa5f784a..d3af115c881 100644 --- a/tests/bsim/bluetooth/mesh/src/mesh_test.h +++ b/tests/bsim/bluetooth/mesh/src/mesh_test.h @@ -23,6 +23,7 @@ #include #include +#include #define TEST_MOD_ID 0x8888 #define TEST_MSG_OP_1 BT_MESH_MODEL_OP_1(0x0f) @@ -202,6 +203,13 @@ void bt_mesh_test_ra_cb_setup(void (*cb)(uint8_t *, size_t)); uint16_t bt_mesh_test_own_addr_get(uint16_t start_addr); +void bt_mesh_test_send_over_adv(void *data, size_t len); +/* Wait for a packet (i. e. an advertisement or a GATT frame) sent by a device. + * `scan_cb` is triggered if the packet is received, and must release `observer_sem` when finished. + */ +int bt_mesh_test_wait_for_packet(bt_le_scan_cb_t scan_cb, struct k_sem *observer_sem, + uint16_t wait); + #if defined(CONFIG_BT_MESH_SAR_CFG) void bt_mesh_test_sar_conf_set(struct bt_mesh_sar_tx *tx_set, struct bt_mesh_sar_rx *rx_set); #endif diff --git a/tests/bsim/bluetooth/mesh/src/test_advertiser.c b/tests/bsim/bluetooth/mesh/src/test_advertiser.c index 47851fc72f4..0ddb5fba6ce 100644 --- a/tests/bsim/bluetooth/mesh/src/test_advertiser.c +++ b/tests/bsim/bluetooth/mesh/src/test_advertiser.c @@ -10,6 +10,7 @@ #include "mesh/net.h" #include "mesh/mesh.h" #include "mesh/foundation.h" +#include "gatt_common.h" #define LOG_MODULE_NAME test_adv @@ -18,22 +19,6 @@ LOG_MODULE_REGISTER(LOG_MODULE_NAME, LOG_LEVEL_INF); #define WAIT_TIME 60 /*seconds*/ -enum bt_mesh_gatt_service { - MESH_SERVICE_PROVISIONING, - MESH_SERVICE_PROXY, -}; - -struct bt_mesh_test_adv { - uint8_t retr; /* number of retransmits of adv frame */ - int64_t interval; /* interval of transmitted frames */ -}; - -struct bt_mesh_test_gatt { - uint8_t transmits; /* number of frame (pb gatt or proxy beacon) transmits */ - int64_t interval; /* interval of transmitted frames */ - enum bt_mesh_gatt_service service; -}; - extern const struct bt_mesh_comp comp; static uint8_t test_prov_uuid[16] = { 0x6c, 0x69, 0x6e, 0x67, 0x61, 0xaa }; @@ -183,36 +168,6 @@ static void seq_end_cb(int err, void *cb_data) } } -static void parse_mesh_gatt_preamble(struct net_buf_simple *buf) -{ - ASSERT_EQUAL(0x0201, net_buf_simple_pull_be16(buf)); - /* flags */ - (void)net_buf_simple_pull_u8(buf); - ASSERT_EQUAL(0x0303, net_buf_simple_pull_be16(buf)); -} - -static void parse_mesh_pb_gatt_service(struct net_buf_simple *buf) -{ - /* Figure 7.1: PB-GATT Advertising Data */ - /* mesh provisioning service */ - ASSERT_EQUAL(0x2718, net_buf_simple_pull_be16(buf)); - ASSERT_EQUAL(0x1516, net_buf_simple_pull_be16(buf)); - /* mesh provisioning service */ - ASSERT_EQUAL(0x2718, net_buf_simple_pull_be16(buf)); -} - -static void parse_mesh_proxy_service(struct net_buf_simple *buf) -{ - /* Figure 7.2: Advertising with Network ID (Identification Type 0x00) */ - /* mesh proxy service */ - ASSERT_EQUAL(0x2818, net_buf_simple_pull_be16(buf)); - ASSERT_EQUAL(0x0c16, net_buf_simple_pull_be16(buf)); - /* mesh proxy service */ - ASSERT_EQUAL(0x2818, net_buf_simple_pull_be16(buf)); - /* network ID */ - ASSERT_EQUAL(0x00, net_buf_simple_pull_u8(buf)); -} - static void gatt_scan_cb(const bt_addr_le_t *addr, int8_t rssi, uint8_t adv_type, struct net_buf_simple *buf) { @@ -220,12 +175,12 @@ static void gatt_scan_cb(const bt_addr_le_t *addr, int8_t rssi, return; } - parse_mesh_gatt_preamble(buf); + bt_mesh_test_parse_mesh_gatt_preamble(buf); if (gatt_param.service == MESH_SERVICE_PROVISIONING) { - parse_mesh_pb_gatt_service(buf); + bt_mesh_test_parse_mesh_pb_gatt_service(buf); } else { - parse_mesh_proxy_service(buf); + bt_mesh_test_parse_mesh_proxy_service(buf); } LOG_INF("rx: %s", txt_msg); @@ -236,26 +191,6 @@ static void gatt_scan_cb(const bt_addr_le_t *addr, int8_t rssi, } } -static void rx_gatt_beacons(void) -{ - struct bt_le_scan_param scan_param = { - .type = BT_HCI_LE_SCAN_PASSIVE, - .options = BT_LE_SCAN_OPT_NONE, - .interval = BT_MESH_ADV_SCAN_UNIT(1000), - .window = BT_MESH_ADV_SCAN_UNIT(1000) - }; - int err; - - err = bt_le_scan_start(&scan_param, gatt_scan_cb); - ASSERT_FALSE_MSG(err && err != -EALREADY, "Starting scan failed (err %d)\n", err); - - err = k_sem_take(&observer_sem, K_SECONDS(20)); - ASSERT_OK(err); - - err = bt_le_scan_stop(); - ASSERT_FALSE_MSG(err && err != -EALREADY, "Stopping scan failed (err %d)\n", err); -} - static void xmit_scan_cb(const bt_addr_le_t *addr, int8_t rssi, uint8_t adv_type, struct net_buf_simple *buf) { @@ -282,26 +217,6 @@ static void xmit_scan_cb(const bt_addr_le_t *addr, int8_t rssi, uint8_t adv_type } } -static void rx_xmit_adv(void) -{ - struct bt_le_scan_param scan_param = { - .type = BT_HCI_LE_SCAN_PASSIVE, - .options = BT_LE_SCAN_OPT_NONE, - .interval = BT_MESH_ADV_SCAN_UNIT(1000), - .window = BT_MESH_ADV_SCAN_UNIT(1000) - }; - int err; - - err = bt_le_scan_start(&scan_param, xmit_scan_cb); - ASSERT_FALSE_MSG(err && err != -EALREADY, "Starting scan failed (err %d)\n", err); - - err = k_sem_take(&observer_sem, K_SECONDS(20)); - ASSERT_OK(err); - - err = bt_le_scan_stop(); - ASSERT_FALSE_MSG(err && err != -EALREADY, "Stopping scan failed (err %d)\n", err); -} - static void send_order_start_cb(uint16_t duration, int err, void *user_data) { struct bt_mesh_adv *adv = (struct bt_mesh_adv *)user_data; @@ -355,25 +270,10 @@ static void receive_order_scan_cb(const bt_addr_le_t *addr, int8_t rssi, uint8_t static void receive_order(int expect_adv) { - struct bt_le_scan_param scan_param = { - .type = BT_HCI_LE_SCAN_PASSIVE, - .options = BT_LE_SCAN_OPT_NONE, - .interval = BT_MESH_ADV_SCAN_UNIT(1000), - .window = BT_MESH_ADV_SCAN_UNIT(1000) - }; - int err; - - err = bt_le_scan_start(&scan_param, receive_order_scan_cb); - ASSERT_FALSE_MSG(err && err != -EALREADY, "Starting scan failed (err %d)\n", err); - previous_checker = 0xff; for (int i = 0; i < expect_adv; i++) { - err = k_sem_take(&observer_sem, K_SECONDS(10)); - ASSERT_OK_MSG(err, "Didn't receive adv in time"); + ASSERT_OK(bt_mesh_test_wait_for_packet(receive_order_scan_cb, &observer_sem, 10)); } - - err = bt_le_scan_stop(); - ASSERT_FALSE_MSG(err && err != -EALREADY, "Stopping scan failed (err %d)\n", err); } static void send_adv_buf(struct bt_mesh_adv *adv, uint8_t curr, uint8_t prev) @@ -446,7 +346,7 @@ static void test_rx_xmit(void) xmit_param.interval = 20; bt_init(); - rx_xmit_adv(); + ASSERT_OK(bt_mesh_test_wait_for_packet(xmit_scan_cb, &observer_sem, 20)); PASS(); } @@ -548,7 +448,7 @@ static void test_rx_proxy_mixin(void) bt_init(); /* Scan pb gatt beacons. */ - rx_gatt_beacons(); + ASSERT_OK(bt_mesh_test_wait_for_packet(gatt_scan_cb, &observer_sem, 20)); /* Delay to provision dut */ k_sleep(K_MSEC(1000)); @@ -558,15 +458,15 @@ static void test_rx_proxy_mixin(void) gatt_param.transmits = 5000 / 1000; gatt_param.interval = 1000; gatt_param.service = MESH_SERVICE_PROXY; - rx_gatt_beacons(); + ASSERT_OK(bt_mesh_test_wait_for_packet(gatt_scan_cb, &observer_sem, 20)); /* Scan adv data. */ xmit_param.retr = 5; xmit_param.interval = 20; - rx_xmit_adv(); + ASSERT_OK(bt_mesh_test_wait_for_packet(xmit_scan_cb, &observer_sem, 20)); /* Scan proxy beacons again. */ - rx_gatt_beacons(); + ASSERT_OK(bt_mesh_test_wait_for_packet(gatt_scan_cb, &observer_sem, 20)); PASS(); } diff --git a/tests/bsim/bluetooth/mesh/src/test_beacon.c b/tests/bsim/bluetooth/mesh/src/test_beacon.c index 2e7e36a9b50..69dbad1f24c 100644 --- a/tests/bsim/bluetooth/mesh/src/test_beacon.c +++ b/tests/bsim/bluetooth/mesh/src/test_beacon.c @@ -387,23 +387,9 @@ static void beacon_scan_cb(const bt_addr_le_t *addr, int8_t rssi, uint8_t adv_ty static bool wait_for_beacon(bt_le_scan_cb_t scan_cb, uint16_t wait, bool (*process_cb)(const uint8_t *net_id, void *ctx), void *ctx) { - struct bt_le_scan_param scan_param = { - .type = BT_HCI_LE_SCAN_PASSIVE, - .options = BT_LE_SCAN_OPT_NONE, - .interval = BT_MESH_ADV_SCAN_UNIT(1000), - .window = BT_MESH_ADV_SCAN_UNIT(1000) - }; - bool received = false; - int err; - beacon.process_cb = process_cb; beacon.user_ctx = ctx; - err = bt_le_scan_start(&scan_param, scan_cb); - if (err && err != -EALREADY) { - FAIL("starting scan failed (err %d)", err); - } - /* Listen to beacons ONLY for one beacon interval. * Tests start quite often the waiting for the next beacon after * transmission or receiving the previous one. If start waiting timer @@ -413,17 +399,7 @@ static bool wait_for_beacon(bt_le_scan_cb_t scan_cb, uint16_t wait, * waiting time (BEACON_INTERVAL + 1) to guarantee that beacon comes * before timer expiration. */ - err = k_sem_take(&observer_sem, K_SECONDS(wait)); - if (!err) { - received = true; - } else { - LOG_WRN("Didn't receive beacon in time (err: %d)", err); - } - - err = bt_le_scan_stop(); - if (err && err != -EALREADY) { - FAIL("stopping scan failed (err %d)", err); - } + bool received = !bt_mesh_test_wait_for_packet(scan_cb, &observer_sem, wait); /* Sleep a little to get to the next beacon interval. Otherwise, calling this function * again will catch the old beacon. This happens due to a known bug in legacy advertiser, From 0480367d77c1a4858c4b07287007b8a21a63389a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?H=C3=A5vard=20Reierstad?= Date: Tue, 19 Dec 2023 15:10:33 +0100 Subject: [PATCH 1869/3723] bsim: Bluetooth: Mesh: refactor suspend test MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Renames tx to DUT and rx to Tester to clarify roles in test. Re-uses the same body for suspend/resume and suspend/disable/resume for DUT with a parameter to toggle disabling BT. Re-uses the same Tester config in both existing test-cases as the previous configs were duplicates. Updates the dut suspension status in the message handler. Signed-off-by: Håvard Reierstad --- tests/bsim/bluetooth/mesh/src/test_suspend.c | 183 ++++++++---------- .../suspend/suspend_disable_resume.sh | 8 +- .../tests_scripts/suspend/suspend_resume.sh | 8 +- 3 files changed, 85 insertions(+), 114 deletions(-) diff --git a/tests/bsim/bluetooth/mesh/src/test_suspend.c b/tests/bsim/bluetooth/mesh/src/test_suspend.c index a83ee025909..53d0bfdbf0f 100644 --- a/tests/bsim/bluetooth/mesh/src/test_suspend.c +++ b/tests/bsim/bluetooth/mesh/src/test_suspend.c @@ -16,35 +16,40 @@ LOG_MODULE_REGISTER(test_suspend, LOG_LEVEL_INF); #define WAIT_TIME 60 /* seconds */ #define SUSPEND_DURATION 15 /* seconds */ -#define NUM_PUB 4 /* Times the transmitter will publish per interval. */ +#define NUM_PUB 4 /* Times the DUT will publish per interval. */ #define TEST_MODEL_ID_1 0x2a2a #define TEST_MODEL_ID_2 0x2b2b #define TEST_MESSAGE_OP 0x1f +enum dut_mesh_status { + DUT_SUSPENDED, + DUT_RUNNING, +}; + static int model_1_init(const struct bt_mesh_model *model); static int model_2_init(const struct bt_mesh_model *model); static uint8_t app_key[16] = {0xaa}; static uint8_t net_key[16] = {0xcc}; -static const struct bt_mesh_test_cfg tx_cfg = { +static const struct bt_mesh_test_cfg dut_cfg = { .addr = 0x00a0, .dev_key = {0x01}, }; -static const struct bt_mesh_test_cfg rx_cfg = { +static const struct bt_mesh_test_cfg tester_cfg = { .addr = 0x00b0, .dev_key = {0x02}, }; static struct bt_mesh_prov prov; static struct k_sem publish_sem; -static bool suspended; +static enum dut_mesh_status dut_status; static int model_1_update(const struct bt_mesh_model *model) { model->pub->msg->data[1]++; - LOG_INF("Model 1 publishing..., n: %d", model->pub->msg->data[1]); + LOG_DBG("Model 1 publishing..., n: %d", model->pub->msg->data[1]); k_sem_give(&publish_sem); return 0; } @@ -53,16 +58,32 @@ static int msg_handler(const struct bt_mesh_model *model, struct bt_mesh_msg_ctx struct net_buf_simple *buf) { static uint8_t prev_num; + static int64_t uptime; uint8_t num = net_buf_simple_pull_u8(buf); - LOG_INF("Received msg, n: %d", num); + LOG_DBG("Received msg, n: %d", num); /* Ensure that payload changes. */ ASSERT_TRUE(prev_num != num); prev_num = num; - /* Ensure that no message is received while Mesh is suspended or disabled. */ - ASSERT_FALSE_MSG(suspended, "Received publication while Mesh is suspended."); + /* Ensure that no message is received while Mesh is suspended or disabled. + * A publication may be sent just before DUT is suspended, which is ignored. + */ + if ((dut_status == DUT_SUSPENDED) && !(num == (NUM_PUB + 1))) { + if (SUSPEND_DURATION * 1000ll <= k_uptime_delta(&uptime)) { + dut_status = DUT_RUNNING; + LOG_DBG("Suspend duration passed. Setting status to %d.", dut_status); + } else { + FAIL("Received publication while Mesh is suspended."); + } + } + + if (num == NUM_PUB) { + dut_status = DUT_SUSPENDED; + LOG_DBG("Expected number of pubs received. Setting status to %d.", dut_status); + uptime = k_uptime_get(); + } k_sem_give(&publish_sem); return 0; @@ -83,42 +104,42 @@ static const struct bt_mesh_model_op model_op_1[] = {BT_MESH_MODEL_OP_END}; static const struct bt_mesh_model_op model_op_2[] = {{TEST_MESSAGE_OP, 0, msg_handler}, BT_MESH_MODEL_OP_END}; -static struct bt_mesh_cfg_cli cfg_cli_tx; -static struct bt_mesh_model tx_models[] = { +static struct bt_mesh_cfg_cli cfg_cli_dut; +static struct bt_mesh_model dut_models[] = { BT_MESH_MODEL_CFG_SRV, - BT_MESH_MODEL_CFG_CLI(&cfg_cli_tx), + BT_MESH_MODEL_CFG_CLI(&cfg_cli_dut), BT_MESH_MODEL_CB(TEST_MODEL_ID_1, model_op_1, &model_1_pub, NULL, &model_1_cb), }; -static struct bt_mesh_elem tx_elems[] = { - BT_MESH_ELEM(0, tx_models, BT_MESH_MODEL_NONE), +static struct bt_mesh_elem dut_elems[] = { + BT_MESH_ELEM(0, dut_models, BT_MESH_MODEL_NONE), }; -static const struct bt_mesh_comp tx_comp = { +static const struct bt_mesh_comp dut_comp = { .cid = TEST_VND_COMPANY_ID, .vid = 0xeeee, .pid = 0xaaaa, - .elem = tx_elems, - .elem_count = ARRAY_SIZE(tx_elems), + .elem = dut_elems, + .elem_count = ARRAY_SIZE(dut_elems), }; -static struct bt_mesh_cfg_cli cfg_cli_rx; -static struct bt_mesh_model rx_models[] = { +static struct bt_mesh_cfg_cli cfg_cli_tester; +static struct bt_mesh_model tester_models[] = { BT_MESH_MODEL_CFG_SRV, - BT_MESH_MODEL_CFG_CLI(&cfg_cli_rx), + BT_MESH_MODEL_CFG_CLI(&cfg_cli_tester), BT_MESH_MODEL_CB(TEST_MODEL_ID_2, model_op_2, NULL, NULL, &model_2_cb), }; -static struct bt_mesh_elem rx_elems[] = { - BT_MESH_ELEM(0, rx_models, BT_MESH_MODEL_NONE), +static struct bt_mesh_elem tester_elems[] = { + BT_MESH_ELEM(0, tester_models, BT_MESH_MODEL_NONE), }; -static const struct bt_mesh_comp rx_comp = { +static const struct bt_mesh_comp tester_comp = { .cid = TEST_VND_COMPANY_ID, .vid = 0xbaaa, .pid = 0xb000, - .elem = rx_elems, - .elem_count = ARRAY_SIZE(rx_elems), + .elem = tester_elems, + .elem_count = ARRAY_SIZE(tester_elems), }; static int model_1_init(const struct bt_mesh_model *model) @@ -134,7 +155,7 @@ static int model_2_init(const struct bt_mesh_model *model) return 0; } -static void provision_and_configure(struct bt_mesh_test_cfg cfg, bool rx) +static void provision_and_configure(struct bt_mesh_test_cfg cfg, bool tester) { int err; uint8_t status; @@ -146,8 +167,8 @@ static void provision_and_configure(struct bt_mesh_test_cfg cfg, bool rx) FAIL("AppKey add failed (err %d, status %u)", err, status); } - const struct bt_mesh_test_cfg *pcfg = rx ? &rx_cfg : &tx_cfg; - uint16_t model_id = rx ? TEST_MODEL_ID_2 : TEST_MODEL_ID_1; + const struct bt_mesh_test_cfg *pcfg = tester ? &tester_cfg : &dut_cfg; + uint16_t model_id = tester ? TEST_MODEL_ID_2 : TEST_MODEL_ID_1; err = bt_mesh_cfg_cli_mod_app_bind(0, pcfg->addr, pcfg->addr, 0, model_id, &status); if (err || status) { @@ -156,7 +177,7 @@ static void provision_and_configure(struct bt_mesh_test_cfg cfg, bool rx) } struct bt_mesh_cfg_cli_mod_pub pub_params = { - .addr = rx_cfg.addr, + .addr = tester_cfg.addr, .uuid = NULL, .cred_flag = false, .app_idx = 0, @@ -165,19 +186,18 @@ struct bt_mesh_cfg_cli_mod_pub pub_params = { .transmit = 0, }; -static void test_tx_suspend_resume(void) +static void dut_pub_common(bool disable_bt) { bt_mesh_test_cfg_set(NULL, WAIT_TIME); - bt_mesh_device_setup(&prov, &tx_comp); - provision_and_configure(tx_cfg, 0); + bt_mesh_device_setup(&prov, &dut_comp); + provision_and_configure(dut_cfg, 0); k_sem_init(&publish_sem, 0, 1); - suspended = false; uint8_t status; int err; - err = bt_mesh_cfg_cli_mod_pub_set(0, tx_cfg.addr, tx_cfg.addr, TEST_MODEL_ID_1, &pub_params, - &status); + err = bt_mesh_cfg_cli_mod_pub_set(0, dut_cfg.addr, dut_cfg.addr, TEST_MODEL_ID_1, + &pub_params, &status); if (err || status) { FAIL("Mod pub set failed (err %d, status %u)", err, status); } @@ -187,15 +207,19 @@ static void test_tx_suspend_resume(void) ASSERT_OK_MSG(k_sem_take(&publish_sem, K_SECONDS(30)), "Pub timed out"); } - ASSERT_OK(bt_mesh_suspend()); - suspended = true; - LOG_INF("Mesh suspended."); + ASSERT_OK_MSG(bt_mesh_suspend(), "Failed to suspend Mesh."); + + if (disable_bt) { + ASSERT_OK_MSG(bt_disable(), "Failed to disable Bluetooth."); + } k_sleep(K_SECONDS(SUSPEND_DURATION)); - ASSERT_OK(bt_mesh_resume()); - suspended = false; - LOG_INF("Mesh resumed."); + if (disable_bt) { + ASSERT_OK_MSG(bt_enable(NULL), "Failed to enable Bluetooth."); + } + + ASSERT_OK_MSG(bt_mesh_resume(), "Failed to resume Mesh."); for (int i = 0; i < NUM_PUB; i++) { ASSERT_OK_MSG(k_sem_take(&publish_sem, K_SECONDS(30)), "Pub timed out"); @@ -204,81 +228,27 @@ static void test_tx_suspend_resume(void) /* Allow publishing to finish before suspending. */ k_sleep(K_MSEC(100)); ASSERT_OK(bt_mesh_suspend()); - - PASS(); } -static void test_rx_suspend_resume(void) +static void test_dut_suspend_resume(void) { - bt_mesh_test_cfg_set(NULL, WAIT_TIME); - bt_mesh_device_setup(&prov, &rx_comp); - provision_and_configure(rx_cfg, 1); - k_sem_init(&publish_sem, 0, 1); - - /* Receive messages before and after suspending. A publication may get lost - * when suspending immeditiately after publication, thus the "-1". - */ - for (int i = 0; i < NUM_PUB * 2 - 1; i++) { - ASSERT_OK_MSG(k_sem_take(&publish_sem, K_SECONDS(30)), "Receiver timed out"); - } - + dut_pub_common(false); PASS(); } -static void test_tx_suspend_disable_resume(void) +static void test_dut_suspend_disable_resume(void) { - bt_mesh_test_cfg_set(NULL, WAIT_TIME); - bt_mesh_device_setup(&prov, &tx_comp); - provision_and_configure(tx_cfg, 0); - - k_sem_init(&publish_sem, 0, 1); - suspended = false; - uint8_t status; - int err; - - err = bt_mesh_cfg_cli_mod_pub_set(0, tx_cfg.addr, tx_cfg.addr, TEST_MODEL_ID_1, &pub_params, - &status); - if (err || status) { - FAIL("Mod pub set failed (err %d, status %u)", err, status); - } - - /* Wait until node has published before suspending. */ - for (int i = 0; i < NUM_PUB; i++) { - ASSERT_OK_MSG(k_sem_take(&publish_sem, K_SECONDS(30)), "Pub timed out"); - } - - ASSERT_OK(bt_mesh_suspend()); - suspended = true; - LOG_INF("Mesh suspended."); - - ASSERT_OK(bt_disable()); - LOG_INF("Bluetooth disabled."); - - k_sleep(K_SECONDS(SUSPEND_DURATION)); - - ASSERT_OK(bt_enable(NULL)); - LOG_INF("Bluetooth enabled."); - - ASSERT_OK(bt_mesh_resume()); - suspended = false; - LOG_INF("Mesh resumed."); - - for (int i = 0; i < NUM_PUB; i++) { - ASSERT_OK_MSG(k_sem_take(&publish_sem, K_SECONDS(30)), "Pub timed out"); - } - - /* Allow publishing to finish before suspending. */ - k_sleep(K_MSEC(100)); - ASSERT_OK(bt_mesh_suspend()); + dut_pub_common(true); PASS(); } -static void test_rx_suspend_disable_resume(void) +static void test_tester_pub(void) { bt_mesh_test_cfg_set(NULL, WAIT_TIME); - bt_mesh_device_setup(&prov, &rx_comp); - provision_and_configure(rx_cfg, 1); + bt_mesh_device_setup(&prov, &tester_comp); + provision_and_configure(tester_cfg, 1); k_sem_init(&publish_sem, 0, 1); + dut_status = DUT_RUNNING; /* Receive messages before and after suspending. A publication may get lost * when suspending immeditiately after publication, thus the "-1". @@ -297,11 +267,12 @@ static void test_rx_suspend_disable_resume(void) } static const struct bst_test_instance test_suspend[] = { - TEST_CASE(tx, suspend_resume, "tx suspend resume"), - TEST_CASE(tx, suspend_disable_resume, "tx suspend, disable resume"), + TEST_CASE(dut, suspend_resume, + "Suspend and resume Mesh while publishing periodically"), + TEST_CASE(dut, suspend_disable_resume, + "Suspend and resume Mesh (and disable/enable BT) while publishing periodically"), - TEST_CASE(rx, suspend_resume, "rx suspend resume"), - TEST_CASE(rx, suspend_disable_resume, "rx suspend, disable resume"), + TEST_CASE(tester, pub, "Scan and verify behavior of periodic publishing adv"), BSTEST_END_MARKER}; diff --git a/tests/bsim/bluetooth/mesh/tests_scripts/suspend/suspend_disable_resume.sh b/tests/bsim/bluetooth/mesh/tests_scripts/suspend/suspend_disable_resume.sh index 6390b2e193c..3329cc2d2bd 100755 --- a/tests/bsim/bluetooth/mesh/tests_scripts/suspend/suspend_disable_resume.sh +++ b/tests/bsim/bluetooth/mesh/tests_scripts/suspend/suspend_disable_resume.sh @@ -17,17 +17,17 @@ source $(dirname "${BASH_SOURCE[0]}")/../../_mesh_test.sh # Check that publication resumes. RunTest mesh_suspend_disable_resume \ - suspend_tx_suspend_disable_resume suspend_rx_suspend_disable_resume + suspend_dut_suspend_disable_resume suspend_tester_pub conf=prj_mesh1d1_conf RunTest mesh_suspend_disable_resume_1d1 \ - suspend_tx_suspend_disable_resume suspend_rx_suspend_disable_resume + suspend_dut_suspend_disable_resume suspend_tester_pub overlay=overlay_low_lat_conf RunTest mesh_suspend_disable_resume_low_lat \ - suspend_tx_suspend_disable_resume suspend_rx_suspend_disable_resume + suspend_dut_suspend_disable_resume suspend_tester_pub conf=prj_mesh1d1_conf overlay=overlay_psa_conf RunTest mesh_suspend_disable_resume_psa \ - suspend_tx_suspend_disable_resume suspend_rx_suspend_disable_resume + suspend_dut_suspend_disable_resume suspend_tester_pub diff --git a/tests/bsim/bluetooth/mesh/tests_scripts/suspend/suspend_resume.sh b/tests/bsim/bluetooth/mesh/tests_scripts/suspend/suspend_resume.sh index 5d4da84a165..90e1623b62b 100755 --- a/tests/bsim/bluetooth/mesh/tests_scripts/suspend/suspend_resume.sh +++ b/tests/bsim/bluetooth/mesh/tests_scripts/suspend/suspend_resume.sh @@ -16,17 +16,17 @@ source $(dirname "${BASH_SOURCE[0]}")/../../_mesh_test.sh # 3. Resume Mesh a specified time after suspension. Check that publication resumes. RunTest mesh_suspend_resume \ - suspend_tx_suspend_resume suspend_rx_suspend_resume + suspend_dut_suspend_resume suspend_tester_pub conf=prj_mesh1d1_conf RunTest mesh_suspend_resume_1d1 \ - suspend_tx_suspend_resume suspend_rx_suspend_resume + suspend_dut_suspend_resume suspend_tester_pub overlay=overlay_low_lat_conf RunTest mesh_suspend_resume_low_lat \ - suspend_tx_suspend_resume suspend_rx_suspend_resume + suspend_dut_suspend_resume suspend_tester_pub conf=prj_mesh1d1_conf overlay=overlay_psa_conf RunTest mesh_suspend_resume_psa \ - suspend_tx_suspend_resume suspend_rx_suspend_resume + suspend_dut_suspend_resume suspend_tester_pub From 9285ea3238e468e1294e92bcad56a2b9b34d0d63 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?H=C3=A5vard=20Reierstad?= Date: Mon, 8 Jan 2024 08:20:45 +0100 Subject: [PATCH 1870/3723] Bluetooth: Mesh: fix proxy srv return value MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Previously, `bt_mesh_proxy_gatt_enable` returned the return value from `k_work_schedule`, which could be a positive (non-error) message. Now, it only returns negative error codes (else 0). Signed-off-by: Håvard Reierstad --- subsys/bluetooth/mesh/proxy_srv.c | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/subsys/bluetooth/mesh/proxy_srv.c b/subsys/bluetooth/mesh/proxy_srv.c index 25a44abfded..a903d94ffa9 100644 --- a/subsys/bluetooth/mesh/proxy_srv.c +++ b/subsys/bluetooth/mesh/proxy_srv.c @@ -975,6 +975,8 @@ static void svc_reg_work_handler(struct k_work *work) int bt_mesh_proxy_gatt_enable(void) { + int err; + LOG_DBG(""); if (!bt_mesh_is_provisioned()) { @@ -986,7 +988,13 @@ int bt_mesh_proxy_gatt_enable(void) } svc_reg_attempts = PROXY_SVC_REG_ATTEMPTS; - return k_work_schedule(&svc_reg_work, PROXY_SVC_INIT_TIMEOUT); + err = k_work_schedule(&svc_reg_work, PROXY_SVC_INIT_TIMEOUT); + if (err < 0) { + LOG_ERR("Enabling GATT proxy failed (err %d)", err); + return err; + } + + return 0; } void bt_mesh_proxy_gatt_disconnect(void) From 6c5fc658efc713b04b6c495be3170c46bf4ef832 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?H=C3=A5vard=20Reierstad?= Date: Tue, 19 Dec 2023 15:10:34 +0100 Subject: [PATCH 1871/3723] Bluetooth: Mesh: suspend/resume gatt advs MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Disables pb gatt- and gatt proxy advs when suspending Mesh, and enables them again when resuming Mesh. Adds `bt_mesh_adv_gatt_send` to `bt_mesh_resume` to make sure that GATT advs start after resumption. Signed-off-by: Håvard Reierstad --- subsys/bluetooth/mesh/main.c | 40 +++++++++++++++++++++++++++++++++++- 1 file changed, 39 insertions(+), 1 deletion(-) diff --git a/subsys/bluetooth/mesh/main.c b/subsys/bluetooth/mesh/main.c index 2689a3355c1..1b80233cec1 100644 --- a/subsys/bluetooth/mesh/main.c +++ b/subsys/bluetooth/mesh/main.c @@ -462,6 +462,22 @@ int bt_mesh_suspend(void) bt_mesh_access_suspend(); + if (IS_ENABLED(CONFIG_BT_MESH_PB_GATT)) { + err = bt_mesh_pb_gatt_srv_disable(); + if (err && err != -EALREADY) { + LOG_WRN("Disabling PB-GATT failed (err %d)", err); + return err; + } + } + + if (IS_ENABLED(CONFIG_BT_MESH_GATT_PROXY)) { + err = bt_mesh_proxy_gatt_disable(); + if (err && err != -EALREADY) { + LOG_WRN("Disabling GATT proxy failed (err %d)", err); + return err; + } + } + err = bt_mesh_adv_disable(); if (err) { atomic_clear_bit(bt_mesh.flags, BT_MESH_SUSPENDED); @@ -508,6 +524,22 @@ int bt_mesh_resume(void) return err; } + if (IS_ENABLED(CONFIG_BT_MESH_GATT_PROXY) && bt_mesh_is_provisioned()) { + err = bt_mesh_proxy_gatt_enable(); + if (err) { + LOG_WRN("Re-enabling GATT proxy failed (err %d)", err); + return err; + } + } + + if (IS_ENABLED(CONFIG_BT_MESH_PB_GATT) && !bt_mesh_is_provisioned()) { + err = bt_mesh_pb_gatt_srv_enable(); + if (err) { + LOG_WRN("Re-enabling PB-GATT failed (err %d)", err); + return err; + } + } + err = bt_mesh_scan_enable(); if (err) { LOG_WRN("Re-enabling scanning failed (err %d)", err); @@ -524,7 +556,13 @@ int bt_mesh_resume(void) bt_mesh_model_foreach(model_resume, NULL); - return err; + err = bt_mesh_adv_gatt_send(); + if (err && (err != -ENOTSUP)) { + LOG_WRN("GATT send failed (err %d)", err); + return err; + } + + return 0; } int bt_mesh_init(const struct bt_mesh_prov *prov, From 9c3ca4573a8ebddfc37fcadf2a770b128845b5bd Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?H=C3=A5vard=20Reierstad?= Date: Tue, 19 Dec 2023 15:10:34 +0100 Subject: [PATCH 1872/3723] bsim: Bluetooth: Mesh: Add gatt suspension test MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Adds two test-cases to `test_suspend.c`, both checking that gatt advertisement is stopped when suspending Mesh, and that is started again when Mesh is resumed. The first test-case involves suspending and resuming Mesh, and the second test-case involves suspending Mesh and disabling Bluetooth, then re-enabling Bluetooth and resuming Mesh. Signed-off-by: Håvard Reierstad --- tests/bsim/bluetooth/mesh/CMakeLists.txt | 1 + tests/bsim/bluetooth/mesh/compile.sh | 2 + tests/bsim/bluetooth/mesh/src/main.c | 2 + tests/bsim/bluetooth/mesh/src/test_suspend.c | 192 +++++++++++++++++- .../suspend/gatt_suspend_disable_resume.sh | 38 ++++ .../suspend/gatt_suspend_resume.sh | 38 ++++ 6 files changed, 269 insertions(+), 4 deletions(-) create mode 100755 tests/bsim/bluetooth/mesh/tests_scripts/suspend/gatt_suspend_disable_resume.sh create mode 100755 tests/bsim/bluetooth/mesh/tests_scripts/suspend/gatt_suspend_resume.sh diff --git a/tests/bsim/bluetooth/mesh/CMakeLists.txt b/tests/bsim/bluetooth/mesh/CMakeLists.txt index 1adccdb9413..f57b59c0c64 100644 --- a/tests/bsim/bluetooth/mesh/CMakeLists.txt +++ b/tests/bsim/bluetooth/mesh/CMakeLists.txt @@ -46,6 +46,7 @@ elseif(CONFIG_BT_MESH_GATT_PROXY) target_sources(app PRIVATE src/test_advertiser.c + src/test_suspend.c ) if(CONFIG_BT_MESH_V1d1) diff --git a/tests/bsim/bluetooth/mesh/compile.sh b/tests/bsim/bluetooth/mesh/compile.sh index de9b4bd6af0..4e3027a7681 100755 --- a/tests/bsim/bluetooth/mesh/compile.sh +++ b/tests/bsim/bluetooth/mesh/compile.sh @@ -35,5 +35,7 @@ app=tests/bsim/bluetooth/mesh \ conf_file=prj_mesh1d1.conf conf_overlay="overlay_gatt.conf;overlay_psa.conf" compile app=tests/bsim/bluetooth/mesh \ conf_file=prj_mesh1d1.conf conf_overlay="overlay_low_lat.conf;overlay_psa.conf" compile +app=tests/bsim/bluetooth/mesh \ + conf_file=prj_mesh1d1.conf conf_overlay="overlay_gatt.conf;overlay_low_lat.conf" compile wait_for_background_jobs diff --git a/tests/bsim/bluetooth/mesh/src/main.c b/tests/bsim/bluetooth/mesh/src/main.c index 67544e494d0..4b28d506627 100644 --- a/tests/bsim/bluetooth/mesh/src/main.c +++ b/tests/bsim/bluetooth/mesh/src/main.c @@ -19,6 +19,7 @@ extern struct bst_test_list *test_sar_pst_install(struct bst_test_list *test); #endif /* defined(CONFIG_BT_MESH_V1d1) */ #elif defined(CONFIG_BT_MESH_GATT_PROXY) extern struct bst_test_list *test_adv_install(struct bst_test_list *test); +extern struct bst_test_list *test_suspend_install(struct bst_test_list *test); #if defined(CONFIG_BT_MESH_V1d1) extern struct bst_test_list *test_beacon_install(struct bst_test_list *tests); #endif /* defined(CONFIG_BT_MESH_V1d1) */ @@ -59,6 +60,7 @@ bst_test_install_t test_installers[] = { #endif /* defined(CONFIG_BT_MESH_V1d1) */ #elif defined(CONFIG_BT_MESH_GATT_PROXY) test_adv_install, + test_suspend_install, #if defined(CONFIG_BT_MESH_V1d1) test_beacon_install, #endif /* defined(CONFIG_BT_MESH_V1d1) */ diff --git a/tests/bsim/bluetooth/mesh/src/test_suspend.c b/tests/bsim/bluetooth/mesh/src/test_suspend.c index 53d0bfdbf0f..63ad49d802f 100644 --- a/tests/bsim/bluetooth/mesh/src/test_suspend.c +++ b/tests/bsim/bluetooth/mesh/src/test_suspend.c @@ -6,10 +6,10 @@ */ #include "mesh_test.h" +#include "gatt_common.h" #include #include -#include #include LOG_MODULE_REGISTER(test_suspend, LOG_LEVEL_INF); @@ -42,7 +42,10 @@ static const struct bt_mesh_test_cfg tester_cfg = { .dev_key = {0x02}, }; -static struct bt_mesh_prov prov; +static uint8_t test_prov_uuid[16] = { 0x6c, 0x69, 0x6e, 0x67, 0x61, 0xaa }; +static struct bt_mesh_prov prov = { + .uuid = test_prov_uuid, + }; static struct k_sem publish_sem; static enum dut_mesh_status dut_status; @@ -186,6 +189,91 @@ struct bt_mesh_cfg_cli_mod_pub pub_params = { .transmit = 0, }; +extern const struct bt_mesh_comp comp; +/* For legacy adv, pb-gatt advs are sent with a 1000ms interval. For ext adv, they are sent + * with a 100ms interval. + */ +static struct bt_mesh_test_gatt gatt_param = { +#if defined(CONFIG_BT_EXT_ADV) + /* (total transmit duration) / (transmit interval) */ + .transmits = 1500 / 100, + .interval = 100, +#else + .transmits = 2000 / 1000, + .interval = 1000, +#endif + .service = MESH_SERVICE_PROVISIONING, +}; + +static bool gatt_check_rx_count(uint8_t transmit) +{ + static int cnt; + + LOG_DBG("rx: cnt(%d)", cnt); + cnt++; + + if (cnt >= transmit) { + cnt = 0; + return true; + } + + return false; +} + +static void gatt_scan_cb(const bt_addr_le_t *addr, int8_t rssi, + uint8_t adv_type, struct net_buf_simple *buf) +{ + if (adv_type != BT_GAP_ADV_TYPE_ADV_IND) { + return; + } + + /* Ensure that no message is received while Mesh is suspended or disabled. */ + ASSERT_FALSE_MSG(dut_status == DUT_SUSPENDED, "Received adv while Mesh is suspended."); + + bt_mesh_test_parse_mesh_gatt_preamble(buf); + + if (gatt_param.service == MESH_SERVICE_PROVISIONING) { + LOG_DBG("Parsing pb_gatt adv"); + bt_mesh_test_parse_mesh_pb_gatt_service(buf); + } else { + LOG_DBG("Parsing proxy adv"); + bt_mesh_test_parse_mesh_proxy_service(buf); + } + + if (gatt_check_rx_count(gatt_param.transmits)) { + LOG_DBG("rx completed, stopping scan..."); + k_sem_give(&publish_sem); + } +} + +static void suspend_state_change_cb(const bt_addr_le_t *addr, int8_t rssi, uint8_t adv_type, + struct net_buf_simple *buf) +{ + uint8_t length; + + if (adv_type != BT_GAP_ADV_TYPE_ADV_NONCONN_IND) { + return; + } + + length = net_buf_simple_pull_u8(buf); + ASSERT_EQUAL(buf->len, length); + ASSERT_EQUAL(length, sizeof(uint8_t) + sizeof(enum dut_mesh_status)); + ASSERT_EQUAL(BT_DATA_MESH_MESSAGE, net_buf_simple_pull_u8(buf)); + + enum dut_mesh_status *msg_status = + net_buf_simple_pull_mem(buf, sizeof(enum dut_mesh_status)); + + if ((*msg_status == DUT_RUNNING) || (*msg_status == DUT_SUSPENDED)) { + dut_status = *msg_status; + } else { + FAIL("Received unexpected data"); + } + + LOG_DBG("Received %d from DUT, setting status to %s", + *msg_status, (dut_status == DUT_SUSPENDED) ? "true" : "false"); + k_sem_give(&publish_sem); +} + static void dut_pub_common(bool disable_bt) { bt_mesh_test_cfg_set(NULL, WAIT_TIME); @@ -230,6 +318,49 @@ static void dut_pub_common(bool disable_bt) ASSERT_OK(bt_mesh_suspend()); } +static void dut_gatt_common(bool disable_bt) +{ + bt_mesh_test_cfg_set(NULL, WAIT_TIME); + bt_mesh_device_setup(&prov, &comp); + ASSERT_OK_MSG(bt_mesh_prov_enable(BT_MESH_PROV_GATT), "Failed to enable GATT provisioner"); + dut_status = DUT_RUNNING; + /* Let the Tester observe pb gatt advertisements before provisioning. The node should + * advertise pb gatt service with 100 msec (ext adv) or 1000msec (legacy adv) interval. + */ + k_sleep(K_MSEC(1800)); + + ASSERT_OK(bt_mesh_provision(test_net_key, 0, 0, 0, dut_cfg.addr, dut_cfg.dev_key)); + + /* Let the Tester observe proxy advertisements */ + k_sleep(K_MSEC(6500)); + + /* Send a mesh message to notify Tester that DUT is about to be suspended. */ + dut_status = DUT_SUSPENDED; + bt_mesh_test_send_over_adv(&dut_status, sizeof(enum dut_mesh_status)); + k_sleep(K_MSEC(150)); + + ASSERT_OK_MSG(bt_mesh_suspend(), "Failed to suspend Mesh."); + + if (disable_bt) { + ASSERT_OK_MSG(bt_disable(), "Failed to disable Bluetooth."); + } + + k_sleep(K_SECONDS(SUSPEND_DURATION)); + + if (disable_bt) { + ASSERT_OK_MSG(bt_enable(NULL), "Failed to enable Bluetooth."); + } + + ASSERT_OK_MSG(bt_mesh_resume(), "Failed to resume Mesh."); + + /* Send a mesh message to notify Tester that device is resumed */ + dut_status = DUT_RUNNING; + bt_mesh_test_send_over_adv(&dut_status, sizeof(enum dut_mesh_status)); + + /* Let the Tester observe that proxy advertisement resumes */ + k_sleep(K_MSEC(6000)); +} + static void test_dut_suspend_resume(void) { dut_pub_common(false); @@ -260,6 +391,54 @@ static void test_tester_pub(void) PASS(); } +static void test_dut_gatt_suspend_resume(void) +{ + dut_gatt_common(false); + PASS(); +} + +static void test_dut_gatt_suspend_disable_resume(void) +{ + dut_gatt_common(true); + PASS(); +} + +static void test_tester_gatt(void) +{ + k_sem_init(&publish_sem, 0, 1); + dut_status = DUT_RUNNING; + int err; + + ASSERT_OK_MSG(bt_enable(NULL), "Bluetooth init failed"); + + /* Scan pb gatt beacons. */ + ASSERT_OK(bt_mesh_test_wait_for_packet(gatt_scan_cb, &publish_sem, 10)); + + /* Delay to provision DUT */ + k_sleep(K_MSEC(1000)); + + /* Scan gatt proxy beacons. */ + /* (total transmit duration) / (transmit interval) */ + gatt_param.transmits = 5000 / 1000; + gatt_param.interval = 1000; + gatt_param.service = MESH_SERVICE_PROXY; + ASSERT_OK(bt_mesh_test_wait_for_packet(gatt_scan_cb, &publish_sem, 10)); + + /* Allow DUT to suspend before scanning for gatt proxy beacons */ + ASSERT_OK(bt_mesh_test_wait_for_packet(suspend_state_change_cb, &publish_sem, 20)); + ASSERT_EQUAL(dut_status, DUT_SUSPENDED); + k_sleep(K_MSEC(500)); + err = bt_mesh_test_wait_for_packet(gatt_scan_cb, &publish_sem, 10); + ASSERT_FALSE(err && err != -EAGAIN); + + /* Wait for DUT to resume Mesh and notify Tester, then scan for gatt proxy beacons */ + ASSERT_OK(bt_mesh_test_wait_for_packet(suspend_state_change_cb, &publish_sem, 20)); + ASSERT_EQUAL(dut_status, DUT_RUNNING); + ASSERT_OK(bt_mesh_test_wait_for_packet(gatt_scan_cb, &publish_sem, 10)); + + PASS(); +} + #define TEST_CASE(role, name, description) \ { \ .test_id = "suspend_" #role "_" #name, .test_descr = description, \ @@ -268,11 +447,16 @@ static void test_tester_pub(void) static const struct bst_test_instance test_suspend[] = { TEST_CASE(dut, suspend_resume, - "Suspend and resume Mesh while publishing periodically"), + "Suspend and resume Mesh with periodic pub"), TEST_CASE(dut, suspend_disable_resume, - "Suspend and resume Mesh (and disable/enable BT) while publishing periodically"), + "Suspend and resume Mesh (and disable/enable BT) with periodic pub"), + TEST_CASE(dut, gatt_suspend_resume, + "Suspend and resume Mesh with GATT proxy advs"), + TEST_CASE(dut, gatt_suspend_disable_resume, + "Suspend and resume Mesh (and disable/enable BT) with GATT proxy advs"), TEST_CASE(tester, pub, "Scan and verify behavior of periodic publishing adv"), + TEST_CASE(tester, gatt, "Scan and verify behavior of GATT proxy adv"), BSTEST_END_MARKER}; diff --git a/tests/bsim/bluetooth/mesh/tests_scripts/suspend/gatt_suspend_disable_resume.sh b/tests/bsim/bluetooth/mesh/tests_scripts/suspend/gatt_suspend_disable_resume.sh new file mode 100755 index 00000000000..c723ea38610 --- /dev/null +++ b/tests/bsim/bluetooth/mesh/tests_scripts/suspend/gatt_suspend_disable_resume.sh @@ -0,0 +1,38 @@ +#!/usr/bin/env bash +# Copyright 2023 Nordic Semiconductor +# SPDX-License-Identifier: Apache-2.0 + +source $(dirname "${BASH_SOURCE[0]}")/../../_mesh_test.sh + +# Test that GATT advertisement is stopped when suspending Mesh and disabling +# Bluetooth, and that it is started again when Bluetooth is re-enabled and Mesh is resumed. +# +# Test procedure: +# 0. DUT (Device 0) initializes the Mesh stack, and starts provisioning procedure using +# bt_mesh_prov_enable(BT_MESH_PROV_GATT). +# 1. Tester (Device 1) observes PB-GATT advs, and will fail the test if the expected +# amount of advs is not received. +# 2. DUT is provisioned, and Tester observes GATT proxy advs. +# 3. DUT notifies the Tester that it will be suspended, and Tester observes for advs after a +# brief delay. Receiving an adv while DUT is suspended will cause the test to fail. +# 4. After a delay, the DUT resumes and notifies the Tester, which checks that the +# advertising resumes. + +overlay=overlay_gatt_conf +RunTest mesh_gatt_suspend_disable_resume \ + suspend_dut_gatt_suspend_disable_resume suspend_tester_gatt + +conf=prj_mesh1d1_conf +overlay="overlay_gatt_conf_overlay_low_lat_conf" +RunTest mesh_gatt_suspend_disable_resume_low_lat \ + suspend_dut_gatt_suspend_disable_resume suspend_tester_gatt + +conf=prj_mesh1d1_conf +overlay=overlay_gatt_conf +RunTest mesh_gatt_suspend_disable_resume_1d1 \ + suspend_dut_gatt_suspend_disable_resume suspend_tester_gatt + +conf=prj_mesh1d1_conf +overlay="overlay_gatt_conf_overlay_psa_conf" +RunTest mesh_gatt_suspend_disable_resume_psa \ + suspend_dut_gatt_suspend_disable_resume suspend_tester_gatt diff --git a/tests/bsim/bluetooth/mesh/tests_scripts/suspend/gatt_suspend_resume.sh b/tests/bsim/bluetooth/mesh/tests_scripts/suspend/gatt_suspend_resume.sh new file mode 100755 index 00000000000..dc29ecfeadf --- /dev/null +++ b/tests/bsim/bluetooth/mesh/tests_scripts/suspend/gatt_suspend_resume.sh @@ -0,0 +1,38 @@ +#!/usr/bin/env bash +# Copyright 2023 Nordic Semiconductor +# SPDX-License-Identifier: Apache-2.0 + +source $(dirname "${BASH_SOURCE[0]}")/../../_mesh_test.sh + +# Test that GATT advertisement is stopped when suspending Mesh, and that it is started again +# when Mesh is resumed. +# +# Test procedure: +# 0. DUT (Device 0) initializes the Mesh stack, and starts provisioning procedure using +# bt_mesh_prov_enable(BT_MESH_PROV_GATT). +# 1. Tester (Device 1) observes PB-GATT advs, and will fail the test if the expected +# amount of advs is not received. +# 2. DUT is provisioned, and Tester observes GATT proxy advs. +# 3. DUT notifies the Tester that it will be suspended, and Tester observes for advs after a +# brief delay. Receiving an adv while DUT is suspended will cause the test to fail. +# 4. After a delay, the DUT resumes and notifies the Tester, which checks that the +# advertising resumes. + +overlay=overlay_gatt_conf +RunTest mesh_gatt_suspend_resume \ + suspend_dut_gatt_suspend_resume suspend_tester_gatt + +conf=prj_mesh1d1_conf +overlay="overlay_gatt_conf_overlay_low_lat_conf" +RunTest mesh_gatt_suspend_resume_low_lat \ + suspend_dut_gatt_suspend_resume suspend_tester_gatt + +conf=prj_mesh1d1_conf +overlay=overlay_gatt_conf +RunTest mesh_gatt_suspend_resume_1d1 \ + suspend_dut_gatt_suspend_resume suspend_tester_gatt + +conf=prj_mesh1d1_conf +overlay="overlay_gatt_conf_overlay_psa_conf" +RunTest mesh_gatt_suspend_resume_psa \ + suspend_dut_gatt_suspend_resume suspend_tester_gatt From 3267bdc4b78bd773b59498c686b4914b3b1c0596 Mon Sep 17 00:00:00 2001 From: Flavio Ceolin Date: Fri, 15 Dec 2023 15:09:50 -0800 Subject: [PATCH 1873/3723] fs: fuse: Avoid possible buffer overflow Checks path's size before copying it to local variable. Signed-off-by: Flavio Ceolin --- subsys/fs/fuse_fs_access.c | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/subsys/fs/fuse_fs_access.c b/subsys/fs/fuse_fs_access.c index e39416f91cf..d3df397842f 100644 --- a/subsys/fs/fuse_fs_access.c +++ b/subsys/fs/fuse_fs_access.c @@ -65,8 +65,15 @@ static void release_file_handle(size_t handle) static bool is_mount_point(const char *path) { char dir_path[PATH_MAX]; + size_t len; - sprintf(dir_path, "%s", path); + len = strlen(path); + if (len >= sizeof(dir_path)) { + return false; + } + + memcpy(dir_path, path, len); + dir_path[len] = '\0'; return strcmp(dirname(dir_path), "/") == 0; } From 698f3b1a58903238d945ccc3c3600b51f9e257b2 Mon Sep 17 00:00:00 2001 From: Reto Schneider Date: Mon, 8 Jan 2024 17:21:53 +0100 Subject: [PATCH 1874/3723] doc: Fix sentence Before this commit, the sentence did not make sense. Signed-off-by: Reto Schneider --- doc/kernel/services/other/atomic.rst | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/doc/kernel/services/other/atomic.rst b/doc/kernel/services/other/atomic.rst index 6d739209ae6..3e589a4cad3 100644 --- a/doc/kernel/services/other/atomic.rst +++ b/doc/kernel/services/other/atomic.rst @@ -4,8 +4,8 @@ Atomic Services ############### An :dfn:`atomic variable` is one that can be read and modified -by threads and ISRs in an uninterruptible manner. It 32-bit on -32-bit machines and 64-bit on 64-bit machines. +by threads and ISRs in an uninterruptible manner. It is a 32-bit variable on +32-bit machines and a 64-bit variable on 64-bit machines. .. contents:: :local: From a006ad5399c4aa4613f3573d3ff6e641950c6e19 Mon Sep 17 00:00:00 2001 From: Fabio Baltieri Date: Mon, 8 Jan 2024 12:12:54 +0000 Subject: [PATCH 1875/3723] ci: do_not_merge: check for dev and arch review labels as well Add "Architecture Review" and "dev-review" to the list of labels that block a PR from merging, less chances to merge these before discussion unintentionally. Signed-off-by: Fabio Baltieri --- .github/workflows/do_not_merge.yml | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/.github/workflows/do_not_merge.yml b/.github/workflows/do_not_merge.yml index 14c651a25f1..b6954e288c9 100644 --- a/.github/workflows/do_not_merge.yml +++ b/.github/workflows/do_not_merge.yml @@ -7,12 +7,14 @@ on: jobs: do-not-merge: if: ${{ contains(github.event.*.labels.*.name, 'DNM') || - contains(github.event.*.labels.*.name, 'TSC') }} + contains(github.event.*.labels.*.name, 'TSC') || + contains(github.event.*.labels.*.name, 'Architecture Review') || + contains(github.event.*.labels.*.name, 'dev-review') }} name: Prevent Merging runs-on: ubuntu-22.04 steps: - name: Check for label run: | - echo "Pull request is labeled as 'DNM' or 'TSC'" - echo "This workflow fails so that the pull request cannot be merged" + echo "Pull request is labeled as 'DNM', 'TSC', 'Architecture Review' or 'dev-review'." + echo "This workflow fails so that the pull request cannot be merged." exit 1 From 2ab367d1491c3e2ab6fc6e95c5daed05fc27be78 Mon Sep 17 00:00:00 2001 From: Daniel Leung Date: Tue, 2 Jan 2024 12:12:57 -0800 Subject: [PATCH 1876/3723] x86: ia32/gdbstub: remove dead code There is logically dead code which will never run. So remove. Fixes #66848 Signed-off-by: Daniel Leung --- arch/x86/core/ia32/gdbstub.c | 8 ++------ 1 file changed, 2 insertions(+), 6 deletions(-) diff --git a/arch/x86/core/ia32/gdbstub.c b/arch/x86/core/ia32/gdbstub.c index 41b6a4500ff..692ea78baf4 100644 --- a/arch/x86/core/ia32/gdbstub.c +++ b/arch/x86/core/ia32/gdbstub.c @@ -174,12 +174,8 @@ size_t arch_gdb_reg_readone(struct gdb_ctx *ctx, uint8_t *buf, size_t buflen, * registers instead of stopping in the middle of * "info registers all". */ - if (buflen >= 2) { - memcpy(buf, "xx", 2); - ret = 2; - } else { - ret = 0; - } + memcpy(buf, "xx", 2); + ret = 2; } else { ret = bin2hex((const uint8_t *)&(ctx->registers[regno]), sizeof(ctx->registers[regno]), From 4824e405cfc1b4e2cf027222027b5b6c6df223e7 Mon Sep 17 00:00:00 2001 From: Adrien Ricciardi Date: Wed, 20 Dec 2023 10:29:15 +0200 Subject: [PATCH 1877/3723] drivers: i2c: i2c_dw: Fixed integer overflow in i2c_dw_data_ask(). The controller can implement a reception FIFO as deep as 256 bytes. However, the computation made by the driver code to determine how many bytes can be asked is stored in a signed 8-bit variable called rx_empty. If the reception FIFO depth is greater or equal to 128 bytes and the FIFO is currently empty, the rx_empty value will be 128 (or more), which stands for a negative value as the variable is signed. Thus, the later code checking if the FIFO is full will run while it should not and exit from the i2c_dw_data_ask() function too early. This hangs the controller in an infinite loop of interrupt storm because the interrupt flags are never cleared. Storing the rx_empty empty on a signed 32-bit variable instead of a 8-bit one solves the issue and is compliant with the controller hardware specifications of a maximum FIFO depth of 256 bytes. It has been agreed with upstream maintainers to change the type of the variables tx_empty, rx_empty, cnt, rx_buffer_depth and tx_buffer_depth to plain int because it is most effectively handled by the CPUs. Using 8-bit or 16-bit variables had no meaning here. Signed-off-by: Adrien Ricciardi --- drivers/i2c/i2c_dw.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/drivers/i2c/i2c_dw.c b/drivers/i2c/i2c_dw.c index 3dd006fb5ae..443bee9059c 100644 --- a/drivers/i2c/i2c_dw.c +++ b/drivers/i2c/i2c_dw.c @@ -201,10 +201,10 @@ static inline void i2c_dw_data_ask(const struct device *dev) { struct i2c_dw_dev_config * const dw = dev->data; uint32_t data; - uint8_t tx_empty; - int8_t rx_empty; - uint8_t cnt; - uint8_t rx_buffer_depth, tx_buffer_depth; + int tx_empty; + int rx_empty; + int cnt; + int rx_buffer_depth, tx_buffer_depth; union ic_comp_param_1_register ic_comp_param_1; uint32_t reg_base = get_regs(dev); From 6443c50bd04d4f11900b48fed80726ed0bc969f6 Mon Sep 17 00:00:00 2001 From: Gerard Marull-Paretas Date: Wed, 3 Jan 2024 12:17:30 +0100 Subject: [PATCH 1878/3723] soc: riscv: move privileged code to common folder Add a new riscv/common directory where to store common code between SoCs, e.g. those implementing the privileged spec. Signed-off-by: Gerard Marull-Paretas --- soc/riscv/CMakeLists.txt | 2 ++ soc/riscv/common/CMakeLists.txt | 1 + soc/riscv/common/Kconfig | 4 +++ .../riscv-privileged}/CMakeLists.txt | 0 soc/riscv/common/riscv-privileged/Kconfig | 36 +++++++++++++++++++ .../common => common/riscv-privileged}/idle.c | 0 .../riscv-privileged}/nuclei/nuclei_csr.h | 0 .../riscv-privileged}/soc_common.h | 0 .../riscv-privileged}/soc_common_irq.c | 0 .../riscv-privileged}/soc_irq.S | 0 .../riscv-privileged}/vector.S | 0 soc/riscv/litex-vexriscv/CMakeLists.txt | 4 +-- soc/riscv/litex-vexriscv/soc.h | 2 +- soc/riscv/riscv-privileged/CMakeLists.txt | 1 - soc/riscv/riscv-privileged/Kconfig | 34 ------------------ 15 files changed, 46 insertions(+), 38 deletions(-) create mode 100644 soc/riscv/common/CMakeLists.txt create mode 100644 soc/riscv/common/Kconfig rename soc/riscv/{riscv-privileged/common => common/riscv-privileged}/CMakeLists.txt (100%) create mode 100644 soc/riscv/common/riscv-privileged/Kconfig rename soc/riscv/{riscv-privileged/common => common/riscv-privileged}/idle.c (100%) rename soc/riscv/{riscv-privileged/common => common/riscv-privileged}/nuclei/nuclei_csr.h (100%) rename soc/riscv/{riscv-privileged/common => common/riscv-privileged}/soc_common.h (100%) rename soc/riscv/{riscv-privileged/common => common/riscv-privileged}/soc_common_irq.c (100%) rename soc/riscv/{riscv-privileged/common => common/riscv-privileged}/soc_irq.S (100%) rename soc/riscv/{riscv-privileged/common => common/riscv-privileged}/vector.S (100%) diff --git a/soc/riscv/CMakeLists.txt b/soc/riscv/CMakeLists.txt index b826da926ca..79d115704b2 100644 --- a/soc/riscv/CMakeLists.txt +++ b/soc/riscv/CMakeLists.txt @@ -1,5 +1,7 @@ # SPDX-License-Identifier: Apache-2.0 +add_subdirectory(common) + if(SOC_FAMILY) add_subdirectory(${SOC_FAMILY}) else() diff --git a/soc/riscv/common/CMakeLists.txt b/soc/riscv/common/CMakeLists.txt new file mode 100644 index 00000000000..9102b32a45f --- /dev/null +++ b/soc/riscv/common/CMakeLists.txt @@ -0,0 +1 @@ +add_subdirectory_ifdef(CONFIG_SOC_FAMILY_RISCV_PRIVILEGED riscv-privileged) diff --git a/soc/riscv/common/Kconfig b/soc/riscv/common/Kconfig new file mode 100644 index 00000000000..91f2c5cf80a --- /dev/null +++ b/soc/riscv/common/Kconfig @@ -0,0 +1,4 @@ +# Copyright (c) 2024 Nordic Semiconductor ASA +# SPDX-License-Identifier: Apache-2.0 +# +source "soc/riscv/common/riscv-privileged/Kconfig" diff --git a/soc/riscv/riscv-privileged/common/CMakeLists.txt b/soc/riscv/common/riscv-privileged/CMakeLists.txt similarity index 100% rename from soc/riscv/riscv-privileged/common/CMakeLists.txt rename to soc/riscv/common/riscv-privileged/CMakeLists.txt diff --git a/soc/riscv/common/riscv-privileged/Kconfig b/soc/riscv/common/riscv-privileged/Kconfig new file mode 100644 index 00000000000..6bc12b46c5a --- /dev/null +++ b/soc/riscv/common/riscv-privileged/Kconfig @@ -0,0 +1,36 @@ +# Configuration options for riscv SOCs supporting the riscv privileged +# architecture specification + +# Copyright (c) 2017 Jean-Paul Etienne +# SPDX-License-Identifier: Apache-2.0 + +config SOC_FAMILY_RISCV_PRIVILEGE + bool + select DEPRECATED + +config SOC_FAMILY_RISCV_PRIVILEGED + bool + select ARCH_HAS_RAMFUNC_SUPPORT if XIP + +config SOC_FAMILY + string + default "riscv-privileged" + depends on SOC_FAMILY_RISCV_PRIVILEGED + +config RISCV_HAS_PLIC + bool "Does the SOC provide support for a Platform Level Interrupt Controller (PLIC)" + depends on SOC_FAMILY_RISCV_PRIVILEGED + help + Does the SOC provide support for a Platform Level Interrupt Controller (PLIC). + +config RISCV_HAS_CLIC + bool "Does the SOC provide support for a Core-Local Interrupt Controller (CLIC)" + depends on SOC_FAMILY_RISCV_PRIVILEGED + help + Does the SOC provide support for a Core-Local Interrupt Controller (CLIC). + +config RISCV_VECTORED_MODE + bool "Should the SOC use vectored mode" + depends on SOC_FAMILY_RISCV_PRIVILEGED + help + Should the SOC use vectored mode. diff --git a/soc/riscv/riscv-privileged/common/idle.c b/soc/riscv/common/riscv-privileged/idle.c similarity index 100% rename from soc/riscv/riscv-privileged/common/idle.c rename to soc/riscv/common/riscv-privileged/idle.c diff --git a/soc/riscv/riscv-privileged/common/nuclei/nuclei_csr.h b/soc/riscv/common/riscv-privileged/nuclei/nuclei_csr.h similarity index 100% rename from soc/riscv/riscv-privileged/common/nuclei/nuclei_csr.h rename to soc/riscv/common/riscv-privileged/nuclei/nuclei_csr.h diff --git a/soc/riscv/riscv-privileged/common/soc_common.h b/soc/riscv/common/riscv-privileged/soc_common.h similarity index 100% rename from soc/riscv/riscv-privileged/common/soc_common.h rename to soc/riscv/common/riscv-privileged/soc_common.h diff --git a/soc/riscv/riscv-privileged/common/soc_common_irq.c b/soc/riscv/common/riscv-privileged/soc_common_irq.c similarity index 100% rename from soc/riscv/riscv-privileged/common/soc_common_irq.c rename to soc/riscv/common/riscv-privileged/soc_common_irq.c diff --git a/soc/riscv/riscv-privileged/common/soc_irq.S b/soc/riscv/common/riscv-privileged/soc_irq.S similarity index 100% rename from soc/riscv/riscv-privileged/common/soc_irq.S rename to soc/riscv/common/riscv-privileged/soc_irq.S diff --git a/soc/riscv/riscv-privileged/common/vector.S b/soc/riscv/common/riscv-privileged/vector.S similarity index 100% rename from soc/riscv/riscv-privileged/common/vector.S rename to soc/riscv/common/riscv-privileged/vector.S diff --git a/soc/riscv/litex-vexriscv/CMakeLists.txt b/soc/riscv/litex-vexriscv/CMakeLists.txt index 9d100ea0e2a..98386f6b57a 100644 --- a/soc/riscv/litex-vexriscv/CMakeLists.txt +++ b/soc/riscv/litex-vexriscv/CMakeLists.txt @@ -5,8 +5,8 @@ # zephyr_sources( - ../riscv-privileged/common/soc_irq.S - ../riscv-privileged/common/vector.S + ../common/riscv-privileged/soc_irq.S + ../common/riscv-privileged/vector.S ) set(SOC_LINKER_SCRIPT ${ZEPHYR_BASE}/include/zephyr/arch/riscv/common/linker.ld CACHE INTERNAL "") diff --git a/soc/riscv/litex-vexriscv/soc.h b/soc/riscv/litex-vexriscv/soc.h index b738deec771..b3521b51e8e 100644 --- a/soc/riscv/litex-vexriscv/soc.h +++ b/soc/riscv/litex-vexriscv/soc.h @@ -7,7 +7,7 @@ #ifndef __RISCV32_LITEX_VEXRISCV_SOC_H_ #define __RISCV32_LITEX_VEXRISCV_SOC_H_ -#include "../riscv-privileged/common/soc_common.h" +#include "../common/riscv-privileged/soc_common.h" #include #include diff --git a/soc/riscv/riscv-privileged/CMakeLists.txt b/soc/riscv/riscv-privileged/CMakeLists.txt index c5f97039eb7..226f3bd626f 100644 --- a/soc/riscv/riscv-privileged/CMakeLists.txt +++ b/soc/riscv/riscv-privileged/CMakeLists.txt @@ -1,4 +1,3 @@ # SPDX-License-Identifier: Apache-2.0 -add_subdirectory(common) add_subdirectory(${SOC_SERIES}) diff --git a/soc/riscv/riscv-privileged/Kconfig b/soc/riscv/riscv-privileged/Kconfig index abbeeac242b..b0700dd3440 100644 --- a/soc/riscv/riscv-privileged/Kconfig +++ b/soc/riscv/riscv-privileged/Kconfig @@ -1,38 +1,4 @@ -# Configuration options for riscv SOCs supporting the riscv privileged -# architecture specification - # Copyright (c) 2017 Jean-Paul Etienne # SPDX-License-Identifier: Apache-2.0 -config SOC_FAMILY_RISCV_PRIVILEGE - bool - select DEPRECATED - -config SOC_FAMILY_RISCV_PRIVILEGED - bool - select ARCH_HAS_RAMFUNC_SUPPORT if XIP - -config SOC_FAMILY - string - default "riscv-privileged" - depends on SOC_FAMILY_RISCV_PRIVILEGED - -config RISCV_HAS_PLIC - bool "Does the SOC provide support for a Platform Level Interrupt Controller (PLIC)" - depends on SOC_FAMILY_RISCV_PRIVILEGED - help - Does the SOC provide support for a Platform Level Interrupt Controller (PLIC). - -config RISCV_HAS_CLIC - bool "Does the SOC provide support for a Core-Local Interrupt Controller (CLIC)" - depends on SOC_FAMILY_RISCV_PRIVILEGED - help - Does the SOC provide support for a Core-Local Interrupt Controller (CLIC). - -config RISCV_VECTORED_MODE - bool "Should the SOC use vectored mode" - depends on SOC_FAMILY_RISCV_PRIVILEGED - help - Should the SOC use vectored mode. - source "soc/riscv/riscv-privileged/*/Kconfig.soc" From 9a35ad858c6d32a25e36c6244f9ab709c9b279d0 Mon Sep 17 00:00:00 2001 From: Gerard Marull-Paretas Date: Wed, 3 Jan 2024 12:20:19 +0100 Subject: [PATCH 1879/3723] soc: riscv: gd32vf103: move nuclei CSR header The header is common to all Nuclei based cores (not strictly related to RISCV privileged spec). Since only GD32VF103 uses a Nuclei core, move the file to its SoC folder. Signed-off-by: Gerard Marull-Paretas --- soc/riscv/riscv-privileged/gd32vf103/entry.S | 3 ++- .../nuclei => riscv-privileged/gd32vf103}/nuclei_csr.h | 0 2 files changed, 2 insertions(+), 1 deletion(-) rename soc/riscv/{common/riscv-privileged/nuclei => riscv-privileged/gd32vf103}/nuclei_csr.h (100%) diff --git a/soc/riscv/riscv-privileged/gd32vf103/entry.S b/soc/riscv/riscv-privileged/gd32vf103/entry.S index 5f8af0d691f..41cc6cc686b 100644 --- a/soc/riscv/riscv-privileged/gd32vf103/entry.S +++ b/soc/riscv/riscv-privileged/gd32vf103/entry.S @@ -4,9 +4,10 @@ * SPDX-License-Identifier: Apache-2.0 */ +#include "nuclei_csr.h" + #include #include -#include GTEXT(__nuclei_start) SECTION_FUNC(vectors, __nuclei_start) diff --git a/soc/riscv/common/riscv-privileged/nuclei/nuclei_csr.h b/soc/riscv/riscv-privileged/gd32vf103/nuclei_csr.h similarity index 100% rename from soc/riscv/common/riscv-privileged/nuclei/nuclei_csr.h rename to soc/riscv/riscv-privileged/gd32vf103/nuclei_csr.h From 0106e8d14c34f3dcd75e8858d01d904375076a34 Mon Sep 17 00:00:00 2001 From: Gerard Marull-Paretas Date: Wed, 3 Jan 2024 12:39:36 +0100 Subject: [PATCH 1880/3723] arch: riscv: introduce RISCV_PRIVILEGED Introduce a new arch level Kconfig option to signal the implementation of the RISCV Privileged ISA spec. This replaces SOC_FAMILY_RISCV_PRIVILEGED, because this is not a SoC specific property, nor a SoC family. Note that the SoC family naming scheme will be fixed in upcoming commits. Signed-off-by: Gerard Marull-Paretas --- arch/riscv/Kconfig | 8 +++++++- drivers/interrupt_controller/intc_plic.c | 4 ++-- include/zephyr/arch/riscv/arch.h | 2 +- soc/riscv/common/CMakeLists.txt | 2 +- soc/riscv/common/riscv-privileged/Kconfig | 17 ++++------------- .../riscv-privileged/andes_v5/Kconfig.series | 2 +- .../efinix-sapphire/Kconfig.series | 2 +- .../riscv-privileged/gd32vf103/Kconfig.series | 2 +- soc/riscv/riscv-privileged/miv/Kconfig.series | 2 +- soc/riscv/riscv-privileged/mpfs/Kconfig.series | 2 +- .../riscv-privileged/neorv32/Kconfig.series | 2 +- soc/riscv/riscv-privileged/niosv/Kconfig.series | 2 +- .../riscv-privileged/opentitan/Kconfig.series | 2 +- .../sifive-freedom/Kconfig.series | 2 +- .../starfive_jh71xx/Kconfig.series | 2 +- .../riscv-privileged/telink_b91/Kconfig.series | 2 +- soc/riscv/riscv-privileged/virt/Kconfig.series | 2 +- tests/kernel/gen_isr_table/testcase.yaml | 8 ++++---- 18 files changed, 31 insertions(+), 34 deletions(-) diff --git a/arch/riscv/Kconfig b/arch/riscv/Kconfig index a1cefcbdf43..80249670d09 100644 --- a/arch/riscv/Kconfig +++ b/arch/riscv/Kconfig @@ -47,6 +47,12 @@ config INCLUDE_RESET_VECTOR Include the reset vector stub, which initializes the stack and prepares for running C code. +config RISCV_PRIVILEGED + bool + select ARCH_HAS_RAMFUNC_SUPPORT if XIP + help + Option selected by SoCs implementing the RISC-V privileged ISA. + config RISCV_SOC_HAS_ISR_STACKING bool depends on !USERSPACE @@ -333,7 +339,7 @@ config RISCV_TRAP_HANDLER_ALIGNMENT The minimum alignment is 4 bytes according to the Spec. config GEN_IRQ_VECTOR_TABLE - select RISCV_VECTORED_MODE if SOC_FAMILY_RISCV_PRIVILEGED + select RISCV_VECTORED_MODE if RISCV_PRIVILEGED config ARCH_HAS_SINGLE_THREAD_SUPPORT default y if !SMP diff --git a/drivers/interrupt_controller/intc_plic.c b/drivers/interrupt_controller/intc_plic.c index 8702735d87f..c33e699bb96 100644 --- a/drivers/interrupt_controller/intc_plic.c +++ b/drivers/interrupt_controller/intc_plic.c @@ -228,7 +228,7 @@ static void plic_irq_enable_set_state(uint32_t irq, bool enable) * @brief Enable a riscv PLIC-specific interrupt line * * This routine enables a RISCV PLIC-specific interrupt line. - * riscv_plic_irq_enable is called by SOC_FAMILY_RISCV_PRIVILEGED + * riscv_plic_irq_enable is called by RISCV_PRIVILEGED * arch_irq_enable function to enable external interrupts for * IRQS level == 2, whenever CONFIG_RISCV_HAS_PLIC variable is set. * @@ -243,7 +243,7 @@ void riscv_plic_irq_enable(uint32_t irq) * @brief Disable a riscv PLIC-specific interrupt line * * This routine disables a RISCV PLIC-specific interrupt line. - * riscv_plic_irq_disable is called by SOC_FAMILY_RISCV_PRIVILEGED + * riscv_plic_irq_disable is called by RISCV_PRIVILEGED * arch_irq_disable function to disable external interrupts, for * IRQS level == 2, whenever CONFIG_RISCV_HAS_PLIC variable is set. * diff --git a/include/zephyr/arch/riscv/arch.h b/include/zephyr/arch/riscv/arch.h index 1d173102de7..1b456a48d96 100644 --- a/include/zephyr/arch/riscv/arch.h +++ b/include/zephyr/arch/riscv/arch.h @@ -300,7 +300,7 @@ static inline uint64_t arch_k_cycle_get_64(void) #endif /*_ASMLANGUAGE */ -#if defined(CONFIG_SOC_FAMILY_RISCV_PRIVILEGED) +#if defined(CONFIG_RISCV_PRIVILEGED) #include #endif diff --git a/soc/riscv/common/CMakeLists.txt b/soc/riscv/common/CMakeLists.txt index 9102b32a45f..91ef5c975b9 100644 --- a/soc/riscv/common/CMakeLists.txt +++ b/soc/riscv/common/CMakeLists.txt @@ -1 +1 @@ -add_subdirectory_ifdef(CONFIG_SOC_FAMILY_RISCV_PRIVILEGED riscv-privileged) +add_subdirectory_ifdef(CONFIG_RISCV_PRIVILEGED riscv-privileged) diff --git a/soc/riscv/common/riscv-privileged/Kconfig b/soc/riscv/common/riscv-privileged/Kconfig index 6bc12b46c5a..526dea4bbfb 100644 --- a/soc/riscv/common/riscv-privileged/Kconfig +++ b/soc/riscv/common/riscv-privileged/Kconfig @@ -4,33 +4,24 @@ # Copyright (c) 2017 Jean-Paul Etienne # SPDX-License-Identifier: Apache-2.0 -config SOC_FAMILY_RISCV_PRIVILEGE - bool - select DEPRECATED - -config SOC_FAMILY_RISCV_PRIVILEGED - bool - select ARCH_HAS_RAMFUNC_SUPPORT if XIP - config SOC_FAMILY string - default "riscv-privileged" - depends on SOC_FAMILY_RISCV_PRIVILEGED + default "riscv-privileged" if RISCV_PRIVILEGED config RISCV_HAS_PLIC bool "Does the SOC provide support for a Platform Level Interrupt Controller (PLIC)" - depends on SOC_FAMILY_RISCV_PRIVILEGED + depends on RISCV_PRIVILEGED help Does the SOC provide support for a Platform Level Interrupt Controller (PLIC). config RISCV_HAS_CLIC bool "Does the SOC provide support for a Core-Local Interrupt Controller (CLIC)" - depends on SOC_FAMILY_RISCV_PRIVILEGED + depends on RISCV_PRIVILEGED help Does the SOC provide support for a Core-Local Interrupt Controller (CLIC). config RISCV_VECTORED_MODE bool "Should the SOC use vectored mode" - depends on SOC_FAMILY_RISCV_PRIVILEGED + depends on RISCV_PRIVILEGED help Should the SOC use vectored mode. diff --git a/soc/riscv/riscv-privileged/andes_v5/Kconfig.series b/soc/riscv/riscv-privileged/andes_v5/Kconfig.series index 9a99711b04c..a85c521492b 100644 --- a/soc/riscv/riscv-privileged/andes_v5/Kconfig.series +++ b/soc/riscv/riscv-privileged/andes_v5/Kconfig.series @@ -4,6 +4,6 @@ config SOC_SERIES_RISCV_ANDES_V5 bool "Andes V5 SoC Series Implementation" select RISCV - select SOC_FAMILY_RISCV_PRIVILEGED + select RISCV_PRIVILEGED help Enable support for Andes V5 SoC Series diff --git a/soc/riscv/riscv-privileged/efinix-sapphire/Kconfig.series b/soc/riscv/riscv-privileged/efinix-sapphire/Kconfig.series index 8505cf1318a..421d81a7e33 100644 --- a/soc/riscv/riscv-privileged/efinix-sapphire/Kconfig.series +++ b/soc/riscv/riscv-privileged/efinix-sapphire/Kconfig.series @@ -4,6 +4,6 @@ config SOC_SERIES_EFINIX_SAPPHIRE bool "Efinix Sapphire SOC implementation" select RISCV - select SOC_FAMILY_RISCV_PRIVILEGED + select RISCV_PRIVILEGED help Enable support for Efinix Sapphire SOC implementation diff --git a/soc/riscv/riscv-privileged/gd32vf103/Kconfig.series b/soc/riscv/riscv-privileged/gd32vf103/Kconfig.series index 3922bf19bdd..79bb3690743 100644 --- a/soc/riscv/riscv-privileged/gd32vf103/Kconfig.series +++ b/soc/riscv/riscv-privileged/gd32vf103/Kconfig.series @@ -6,7 +6,7 @@ config SOC_SERIES_GD32VF103 bool "GigaDevice GD32VF103 series SoC implementation" select RISCV - select SOC_FAMILY_RISCV_PRIVILEGED + select RISCV_PRIVILEGED select ATOMIC_OPERATIONS_C select INCLUDE_RESET_VECTOR select BUILD_OUTPUT_HEX diff --git a/soc/riscv/riscv-privileged/miv/Kconfig.series b/soc/riscv/riscv-privileged/miv/Kconfig.series index 00a6f129f9f..017de686a94 100644 --- a/soc/riscv/riscv-privileged/miv/Kconfig.series +++ b/soc/riscv/riscv-privileged/miv/Kconfig.series @@ -6,6 +6,6 @@ config SOC_SERIES_RISCV32_MIV bool "Microchip Mi-V implementation" select RISCV - select SOC_FAMILY_RISCV_PRIVILEGED + select RISCV_PRIVILEGED help Enable support for Microchip Mi-V diff --git a/soc/riscv/riscv-privileged/mpfs/Kconfig.series b/soc/riscv/riscv-privileged/mpfs/Kconfig.series index ca37731f192..3b30cd15365 100644 --- a/soc/riscv/riscv-privileged/mpfs/Kconfig.series +++ b/soc/riscv/riscv-privileged/mpfs/Kconfig.series @@ -6,6 +6,6 @@ config SOC_SERIES_RISCV64_MIV bool "Microchip RV64 implementation" select RISCV - select SOC_FAMILY_RISCV_PRIVILEGED + select RISCV_PRIVILEGED help Enable support for Microchip RISCV 64bit diff --git a/soc/riscv/riscv-privileged/neorv32/Kconfig.series b/soc/riscv/riscv-privileged/neorv32/Kconfig.series index 98c7f34024d..0f8f9ca8fd4 100644 --- a/soc/riscv/riscv-privileged/neorv32/Kconfig.series +++ b/soc/riscv/riscv-privileged/neorv32/Kconfig.series @@ -9,7 +9,7 @@ config SOC_SERIES_NEORV32 select RISCV_ISA_EXT_A select RISCV_ISA_EXT_ZICSR select RISCV_ISA_EXT_ZIFENCEI - select SOC_FAMILY_RISCV_PRIVILEGED + select RISCV_PRIVILEGED help Enable support for the NEORV32 Processor (SoC). diff --git a/soc/riscv/riscv-privileged/niosv/Kconfig.series b/soc/riscv/riscv-privileged/niosv/Kconfig.series index 7de17cf2db0..104f5a48352 100644 --- a/soc/riscv/riscv-privileged/niosv/Kconfig.series +++ b/soc/riscv/riscv-privileged/niosv/Kconfig.series @@ -4,6 +4,6 @@ config SOC_SERIES_NIOSV bool "INTEL FPGA NIOSV" select RISCV - select SOC_FAMILY_RISCV_PRIVILEGED + select RISCV_PRIVILEGED help Enable support for the INTEL FPGA NIOSV. diff --git a/soc/riscv/riscv-privileged/opentitan/Kconfig.series b/soc/riscv/riscv-privileged/opentitan/Kconfig.series index f8bbc2840fe..b516e6d8092 100644 --- a/soc/riscv/riscv-privileged/opentitan/Kconfig.series +++ b/soc/riscv/riscv-privileged/opentitan/Kconfig.series @@ -4,7 +4,7 @@ config SOC_SERIES_RISCV_OPENTITAN bool "OpenTitan implementation" select RISCV - select SOC_FAMILY_RISCV_PRIVILEGED + select RISCV_PRIVILEGED # OpenTitan Ibex core mtvec mode is read-only / forced to vectored mode. select RISCV_VECTORED_MODE select GEN_IRQ_VECTOR_TABLE diff --git a/soc/riscv/riscv-privileged/sifive-freedom/Kconfig.series b/soc/riscv/riscv-privileged/sifive-freedom/Kconfig.series index 523f6a4ffe9..a24b4812c28 100644 --- a/soc/riscv/riscv-privileged/sifive-freedom/Kconfig.series +++ b/soc/riscv/riscv-privileged/sifive-freedom/Kconfig.series @@ -6,6 +6,6 @@ config SOC_SERIES_RISCV_SIFIVE_FREEDOM bool "SiFive Freedom SOC implementation" select RISCV - select SOC_FAMILY_RISCV_PRIVILEGED + select RISCV_PRIVILEGED help Enable support for SiFive Freedom SOC diff --git a/soc/riscv/riscv-privileged/starfive_jh71xx/Kconfig.series b/soc/riscv/riscv-privileged/starfive_jh71xx/Kconfig.series index b360f78b77b..19cedcefe27 100644 --- a/soc/riscv/riscv-privileged/starfive_jh71xx/Kconfig.series +++ b/soc/riscv/riscv-privileged/starfive_jh71xx/Kconfig.series @@ -4,6 +4,6 @@ config SOC_SERIES_STARFIVE_JH71XX bool "Starfive JH71XX series" select RISCV - select SOC_FAMILY_RISCV_PRIVILEGED + select RISCV_PRIVILEGED help Enable support for Starfive JH71XX SoC Series. diff --git a/soc/riscv/riscv-privileged/telink_b91/Kconfig.series b/soc/riscv/riscv-privileged/telink_b91/Kconfig.series index a966dfe447b..cce6011ce68 100644 --- a/soc/riscv/riscv-privileged/telink_b91/Kconfig.series +++ b/soc/riscv/riscv-privileged/telink_b91/Kconfig.series @@ -10,7 +10,7 @@ config SOC_SERIES_RISCV_TELINK_B91 select RISCV_ISA_EXT_C select RISCV_ISA_EXT_ZICSR select RISCV_ISA_EXT_ZIFENCEI - select SOC_FAMILY_RISCV_PRIVILEGED + select RISCV_PRIVILEGED select HAS_TELINK_DRIVERS help Enable support for Telink B91 SoC diff --git a/soc/riscv/riscv-privileged/virt/Kconfig.series b/soc/riscv/riscv-privileged/virt/Kconfig.series index e9846764f6b..44ec681a308 100644 --- a/soc/riscv/riscv-privileged/virt/Kconfig.series +++ b/soc/riscv/riscv-privileged/virt/Kconfig.series @@ -4,4 +4,4 @@ config SOC_SERIES_RISCV_VIRT bool "QEMU RISC-V VirtIO Board" select RISCV - select SOC_FAMILY_RISCV_PRIVILEGED + select RISCV_PRIVILEGED diff --git a/tests/kernel/gen_isr_table/testcase.yaml b/tests/kernel/gen_isr_table/testcase.yaml index 29c4316dafa..292a801080b 100644 --- a/tests/kernel/gen_isr_table/testcase.yaml +++ b/tests/kernel/gen_isr_table/testcase.yaml @@ -53,7 +53,7 @@ tests: platform_exclude: - m2gl025_miv - adp_xc7k_ae350 - filter: CONFIG_SOC_FAMILY_RISCV_PRIVILEGED + filter: CONFIG_RISCV_PRIVILEGED extra_configs: - CONFIG_GEN_IRQ_VECTOR_TABLE=y arch.interrupt.gen_isr_table.riscv_no_direct: @@ -61,18 +61,18 @@ tests: arch_allow: - riscv32 - riscv64 - filter: CONFIG_SOC_FAMILY_RISCV_PRIVILEGED + filter: CONFIG_RISCV_PRIVILEGED extra_configs: - CONFIG_GEN_IRQ_VECTOR_TABLE=n arch.interrupt.gen_isr_table.bit_shift_2nd_level: platform_allow: qemu_riscv32 - filter: CONFIG_SOC_FAMILY_RISCV_PRIVILEGED + filter: CONFIG_RISCV_PRIVILEGED extra_configs: - CONFIG_1ST_LEVEL_INTERRUPT_BITS=7 - CONFIG_2ND_LEVEL_INTERRUPT_BITS=9 arch.interrupt.gen_isr_table.bit_shift_3rd_level: platform_allow: qemu_riscv32 - filter: CONFIG_SOC_FAMILY_RISCV_PRIVILEGED + filter: CONFIG_RISCV_PRIVILEGED extra_configs: - CONFIG_MULTI_LEVEL_INTERRUPTS=y - CONFIG_2ND_LEVEL_INTERRUPTS=y From d8c0cc2e3502da55338c5563feb8b4bebe193d5e Mon Sep 17 00:00:00 2001 From: Gerard Marull-Paretas Date: Wed, 3 Jan 2024 14:02:24 +0100 Subject: [PATCH 1881/3723] soc: riscv: introduce temporary RISCV_PRIVILEGED_STANDALONE So that SoCs can be ported outside of riscv-privileged folder, setting their own family name. This will be removed once all SoCs are ported. Signed-off-by: Gerard Marull-Paretas --- soc/riscv/common/riscv-privileged/Kconfig | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/soc/riscv/common/riscv-privileged/Kconfig b/soc/riscv/common/riscv-privileged/Kconfig index 526dea4bbfb..de064842604 100644 --- a/soc/riscv/common/riscv-privileged/Kconfig +++ b/soc/riscv/common/riscv-privileged/Kconfig @@ -4,9 +4,12 @@ # Copyright (c) 2017 Jean-Paul Etienne # SPDX-License-Identifier: Apache-2.0 +config RISCV_PRIVILEGED_STANDALONE + bool + config SOC_FAMILY string - default "riscv-privileged" if RISCV_PRIVILEGED + default "riscv-privileged" if RISCV_PRIVILEGED && !RISCV_PRIVILEGED_STANDALONE config RISCV_HAS_PLIC bool "Does the SOC provide support for a Platform Level Interrupt Controller (PLIC)" From 72e52a06aa474917443e522963429448d2d780b8 Mon Sep 17 00:00:00 2001 From: Gerard Marull-Paretas Date: Wed, 3 Jan 2024 14:00:12 +0100 Subject: [PATCH 1882/3723] soc: riscv: telink_b91: reorganize SoC folder Reorganize following the hierarchy found in the vendor website [1]: - SoC Family: Telink TLSR - SoC series: TLSR951X - SoC: TLSR9518 Also split out from riscv-privileged folder. Note that B91 was the name of a starter kit [2]. [1]: http://wiki.telink-semi.cn/wiki/chip-series/TLSR951x-Series/ [2]: https://wiki.telink-semi.cn/wiki/Hardware/ B91_Generic_Starter_Kit_Hardware_Guide/ Signed-off-by: Gerard Marull-Paretas --- boards/riscv/tlsr9518adk80d/Kconfig.board | 2 +- .../tlsr9518adk80d/tlsr9518adk80d_defconfig | 4 +- .../riscv-privileged/telink_b91/Kconfig.soc | 40 ------------------- soc/riscv/telink_tlsr/CMakeLists.txt | 4 ++ soc/riscv/telink_tlsr/Kconfig | 15 +++++++ soc/riscv/telink_tlsr/Kconfig.defconfig | 4 ++ soc/riscv/telink_tlsr/Kconfig.soc | 4 ++ .../tlsr951x}/CMakeLists.txt | 0 .../tlsr951x}/Kconfig.defconfig.series | 8 ++-- .../tlsr951x/Kconfig.defconfig.tlsr9518 | 5 +++ .../tlsr951x}/Kconfig.series | 11 +++-- soc/riscv/telink_tlsr/tlsr951x/Kconfig.soc | 23 +++++++++++ .../tlsr951x}/init.ld | 0 .../tlsr951x}/linker.ld | 0 .../tlsr951x}/pinctrl_soc.h | 0 .../telink_b91 => telink_tlsr/tlsr951x}/soc.c | 0 .../telink_b91 => telink_tlsr/tlsr951x}/soc.h | 0 .../tlsr951x}/soc_context.h | 0 .../tlsr951x}/soc_irq.S | 0 .../tlsr951x}/soc_offsets.h | 0 .../tlsr951x}/start.S | 0 21 files changed, 71 insertions(+), 49 deletions(-) delete mode 100644 soc/riscv/riscv-privileged/telink_b91/Kconfig.soc create mode 100644 soc/riscv/telink_tlsr/CMakeLists.txt create mode 100644 soc/riscv/telink_tlsr/Kconfig create mode 100644 soc/riscv/telink_tlsr/Kconfig.defconfig create mode 100644 soc/riscv/telink_tlsr/Kconfig.soc rename soc/riscv/{riscv-privileged/telink_b91 => telink_tlsr/tlsr951x}/CMakeLists.txt (100%) rename soc/riscv/{riscv-privileged/telink_b91 => telink_tlsr/tlsr951x}/Kconfig.defconfig.series (81%) create mode 100644 soc/riscv/telink_tlsr/tlsr951x/Kconfig.defconfig.tlsr9518 rename soc/riscv/{riscv-privileged/telink_b91 => telink_tlsr/tlsr951x}/Kconfig.series (55%) create mode 100644 soc/riscv/telink_tlsr/tlsr951x/Kconfig.soc rename soc/riscv/{riscv-privileged/telink_b91 => telink_tlsr/tlsr951x}/init.ld (100%) rename soc/riscv/{riscv-privileged/telink_b91 => telink_tlsr/tlsr951x}/linker.ld (100%) rename soc/riscv/{riscv-privileged/telink_b91 => telink_tlsr/tlsr951x}/pinctrl_soc.h (100%) rename soc/riscv/{riscv-privileged/telink_b91 => telink_tlsr/tlsr951x}/soc.c (100%) rename soc/riscv/{riscv-privileged/telink_b91 => telink_tlsr/tlsr951x}/soc.h (100%) rename soc/riscv/{riscv-privileged/telink_b91 => telink_tlsr/tlsr951x}/soc_context.h (100%) rename soc/riscv/{riscv-privileged/telink_b91 => telink_tlsr/tlsr951x}/soc_irq.S (100%) rename soc/riscv/{riscv-privileged/telink_b91 => telink_tlsr/tlsr951x}/soc_offsets.h (100%) rename soc/riscv/{riscv-privileged/telink_b91 => telink_tlsr/tlsr951x}/start.S (100%) diff --git a/boards/riscv/tlsr9518adk80d/Kconfig.board b/boards/riscv/tlsr9518adk80d/Kconfig.board index bd36cb0e481..971b34dc13b 100644 --- a/boards/riscv/tlsr9518adk80d/Kconfig.board +++ b/boards/riscv/tlsr9518adk80d/Kconfig.board @@ -3,4 +3,4 @@ config BOARD_TLSR9518ADK80D bool "Telink B91 Platform" - depends on SOC_RISCV_TELINK_B91 + depends on SOC_TELINK_TLSR9518 diff --git a/boards/riscv/tlsr9518adk80d/tlsr9518adk80d_defconfig b/boards/riscv/tlsr9518adk80d/tlsr9518adk80d_defconfig index fe5cfbe8c2e..c4cfdfea718 100644 --- a/boards/riscv/tlsr9518adk80d/tlsr9518adk80d_defconfig +++ b/boards/riscv/tlsr9518adk80d/tlsr9518adk80d_defconfig @@ -1,8 +1,8 @@ # Copyright (c) 2021 Telink Semiconductor # SPDX-License-Identifier: Apache-2.0 -CONFIG_SOC_SERIES_RISCV_TELINK_B91=y -CONFIG_SOC_RISCV_TELINK_B91=y +CONFIG_SOC_SERIES_TELINK_TLSR951X=y +CONFIG_SOC_TELINK_TLSR9518=y CONFIG_BOARD_TLSR9518ADK80D=y CONFIG_GPIO=y CONFIG_SYS_CLOCK_TICKS_PER_SEC=1000 diff --git a/soc/riscv/riscv-privileged/telink_b91/Kconfig.soc b/soc/riscv/riscv-privileged/telink_b91/Kconfig.soc deleted file mode 100644 index 3f4f96c332e..00000000000 --- a/soc/riscv/riscv-privileged/telink_b91/Kconfig.soc +++ /dev/null @@ -1,40 +0,0 @@ -# Copyright (c) 2021 Telink Semiconductor -# SPDX-License-Identifier: Apache-2.0 - -choice -prompt "CPU Architecture of SoC" -depends on SOC_SERIES_RISCV_TELINK_B91 - -config B91_CPU_RISCV32 - bool "RISCV32 CPU Architecture" - select RISCV_ISA_RV32I - select RISCV_ISA_EXT_M - select RISCV_ISA_EXT_A - select RISCV_ISA_EXT_C - select RISCV_ISA_EXT_ZICSR - select RISCV_ISA_EXT_ZIFENCEI - -endchoice - -config TELINK_B91_HWDSP - bool "Support Hardware DSP" - select RISCV_SOC_CONTEXT_SAVE - depends on SOC_SERIES_RISCV_TELINK_B91 - -config TELINK_B91_PFT_ARCH - bool "Support performance throttling" - default y - select RISCV_SOC_CONTEXT_SAVE - depends on SOC_SERIES_RISCV_TELINK_B91 - -choice -prompt "Telink B91 SoC implementation" -depends on SOC_SERIES_RISCV_TELINK_B91 - -config SOC_RISCV_TELINK_B91 - bool "Telink B91 SoC implementation" - select ATOMIC_OPERATIONS_BUILTIN - select CPU_HAS_FPU - select INCLUDE_RESET_VECTOR - -endchoice diff --git a/soc/riscv/telink_tlsr/CMakeLists.txt b/soc/riscv/telink_tlsr/CMakeLists.txt new file mode 100644 index 00000000000..69b2926358e --- /dev/null +++ b/soc/riscv/telink_tlsr/CMakeLists.txt @@ -0,0 +1,4 @@ +# Copyright (c) 2024 Nordic Semiconductor +# SPDX-License-Identifier: Apache-2.0 + +add_subdirectory(${SOC_SERIES}) diff --git a/soc/riscv/telink_tlsr/Kconfig b/soc/riscv/telink_tlsr/Kconfig new file mode 100644 index 00000000000..144751311ba --- /dev/null +++ b/soc/riscv/telink_tlsr/Kconfig @@ -0,0 +1,15 @@ +# Copyright (c) 2024 Nordic Semiconductor ASA +# SPDX-License-Identifier: Apache-2.0 + +config SOC_FAMILY_TELINK_TLSR + bool + +if SOC_FAMILY_TELINK_TLSR + +config SOC_FAMILY + string + default "telink_tlsr" + +source "soc/riscv/telink_tlsr/*/Kconfig.soc" + +endif # SOC_FAMILY_TELINK_TLSR diff --git a/soc/riscv/telink_tlsr/Kconfig.defconfig b/soc/riscv/telink_tlsr/Kconfig.defconfig new file mode 100644 index 00000000000..04a888381fa --- /dev/null +++ b/soc/riscv/telink_tlsr/Kconfig.defconfig @@ -0,0 +1,4 @@ +# Copyright (c) 2024 Nordic Semiconductor ASA +# SPDX-License-Identifier: Apache-2.0 + +source "soc/riscv/telink_tlsr/*/Kconfig.defconfig.series" diff --git a/soc/riscv/telink_tlsr/Kconfig.soc b/soc/riscv/telink_tlsr/Kconfig.soc new file mode 100644 index 00000000000..db09c69d1f4 --- /dev/null +++ b/soc/riscv/telink_tlsr/Kconfig.soc @@ -0,0 +1,4 @@ +# Copyright (c) 2024 Nordic Semiconductor ASA +# SPDX-License-Identifier: Apache-2.0 + +source "soc/riscv/telink_tlsr/*/Kconfig.series" diff --git a/soc/riscv/riscv-privileged/telink_b91/CMakeLists.txt b/soc/riscv/telink_tlsr/tlsr951x/CMakeLists.txt similarity index 100% rename from soc/riscv/riscv-privileged/telink_b91/CMakeLists.txt rename to soc/riscv/telink_tlsr/tlsr951x/CMakeLists.txt diff --git a/soc/riscv/riscv-privileged/telink_b91/Kconfig.defconfig.series b/soc/riscv/telink_tlsr/tlsr951x/Kconfig.defconfig.series similarity index 81% rename from soc/riscv/riscv-privileged/telink_b91/Kconfig.defconfig.series rename to soc/riscv/telink_tlsr/tlsr951x/Kconfig.defconfig.series index 986b6240750..23a78c9f0da 100644 --- a/soc/riscv/riscv-privileged/telink_b91/Kconfig.defconfig.series +++ b/soc/riscv/telink_tlsr/tlsr951x/Kconfig.defconfig.series @@ -1,11 +1,11 @@ # Copyright (c) 2021 Telink Semiconductor # SPDX-License-Identifier: Apache-2.0 -if SOC_SERIES_RISCV_TELINK_B91 +if SOC_SERIES_TELINK_TLSR951X config SOC_SERIES string - default "telink_b91" + default "tlsr951x" config SYS_CLOCK_HW_CYCLES_PER_SEC int @@ -56,4 +56,6 @@ config 2ND_LVL_INTR_00_OFFSET config HAS_FLASH_LOAD_OFFSET default y if BOOTLOADER_MCUBOOT -endif # SOC_SERIES_RISCV_TELINK_B91 +source "soc/riscv/telink_tlsr/tlsr951x/Kconfig.defconfig.tlsr*" + +endif # SOC_SERIES_TELINK_TLSR951X diff --git a/soc/riscv/telink_tlsr/tlsr951x/Kconfig.defconfig.tlsr9518 b/soc/riscv/telink_tlsr/tlsr951x/Kconfig.defconfig.tlsr9518 new file mode 100644 index 00000000000..4ffdebdaf6b --- /dev/null +++ b/soc/riscv/telink_tlsr/tlsr951x/Kconfig.defconfig.tlsr9518 @@ -0,0 +1,5 @@ +# Copyright (c) 2024 Nordic Semiconductor ASA +# SPDX-License-Identifier: Apache-2.0 + +config SOC + default "tlsr9518" if SOC_TELINK_TLSR9518 diff --git a/soc/riscv/riscv-privileged/telink_b91/Kconfig.series b/soc/riscv/telink_tlsr/tlsr951x/Kconfig.series similarity index 55% rename from soc/riscv/riscv-privileged/telink_b91/Kconfig.series rename to soc/riscv/telink_tlsr/tlsr951x/Kconfig.series index cce6011ce68..e074a53e11b 100644 --- a/soc/riscv/riscv-privileged/telink_b91/Kconfig.series +++ b/soc/riscv/telink_tlsr/tlsr951x/Kconfig.series @@ -1,8 +1,8 @@ # Copyright (c) 2021 Telink Semiconductor # SPDX-License-Identifier: Apache-2.0 -config SOC_SERIES_RISCV_TELINK_B91 - bool "Telink B91 SoC Implementation" +config SOC_SERIES_TELINK_TLSR951X + bool "Telink TLSR951X" select RISCV select RISCV_ISA_RV32I select RISCV_ISA_EXT_M @@ -12,5 +12,10 @@ config SOC_SERIES_RISCV_TELINK_B91 select RISCV_ISA_EXT_ZIFENCEI select RISCV_PRIVILEGED select HAS_TELINK_DRIVERS + select ATOMIC_OPERATIONS_BUILTIN + select CPU_HAS_FPU + select INCLUDE_RESET_VECTOR + select SOC_FAMILY_TELINK_TLSR + select RISCV_PRIVILEGED_STANDALONE help - Enable support for Telink B91 SoC + Enable support for Telink TLSR951X diff --git a/soc/riscv/telink_tlsr/tlsr951x/Kconfig.soc b/soc/riscv/telink_tlsr/tlsr951x/Kconfig.soc new file mode 100644 index 00000000000..2abc12cc58c --- /dev/null +++ b/soc/riscv/telink_tlsr/tlsr951x/Kconfig.soc @@ -0,0 +1,23 @@ +# Copyright (c) 2021 Telink Semiconductor +# SPDX-License-Identifier: Apache-2.0 + +if SOC_SERIES_TELINK_TLSR951X + +choice + prompt "Telink TLSR951X SoC implementation" + +config SOC_TELINK_TLSR9518 + bool "Telink TLSR9518" + +endchoice + +config TELINK_B91_HWDSP + bool "Support Hardware DSP" + select RISCV_SOC_CONTEXT_SAVE + +config TELINK_B91_PFT_ARCH + bool "Support performance throttling" + default y + select RISCV_SOC_CONTEXT_SAVE + +endif # SOC_SERIES_TELINK_TLSR951X diff --git a/soc/riscv/riscv-privileged/telink_b91/init.ld b/soc/riscv/telink_tlsr/tlsr951x/init.ld similarity index 100% rename from soc/riscv/riscv-privileged/telink_b91/init.ld rename to soc/riscv/telink_tlsr/tlsr951x/init.ld diff --git a/soc/riscv/riscv-privileged/telink_b91/linker.ld b/soc/riscv/telink_tlsr/tlsr951x/linker.ld similarity index 100% rename from soc/riscv/riscv-privileged/telink_b91/linker.ld rename to soc/riscv/telink_tlsr/tlsr951x/linker.ld diff --git a/soc/riscv/riscv-privileged/telink_b91/pinctrl_soc.h b/soc/riscv/telink_tlsr/tlsr951x/pinctrl_soc.h similarity index 100% rename from soc/riscv/riscv-privileged/telink_b91/pinctrl_soc.h rename to soc/riscv/telink_tlsr/tlsr951x/pinctrl_soc.h diff --git a/soc/riscv/riscv-privileged/telink_b91/soc.c b/soc/riscv/telink_tlsr/tlsr951x/soc.c similarity index 100% rename from soc/riscv/riscv-privileged/telink_b91/soc.c rename to soc/riscv/telink_tlsr/tlsr951x/soc.c diff --git a/soc/riscv/riscv-privileged/telink_b91/soc.h b/soc/riscv/telink_tlsr/tlsr951x/soc.h similarity index 100% rename from soc/riscv/riscv-privileged/telink_b91/soc.h rename to soc/riscv/telink_tlsr/tlsr951x/soc.h diff --git a/soc/riscv/riscv-privileged/telink_b91/soc_context.h b/soc/riscv/telink_tlsr/tlsr951x/soc_context.h similarity index 100% rename from soc/riscv/riscv-privileged/telink_b91/soc_context.h rename to soc/riscv/telink_tlsr/tlsr951x/soc_context.h diff --git a/soc/riscv/riscv-privileged/telink_b91/soc_irq.S b/soc/riscv/telink_tlsr/tlsr951x/soc_irq.S similarity index 100% rename from soc/riscv/riscv-privileged/telink_b91/soc_irq.S rename to soc/riscv/telink_tlsr/tlsr951x/soc_irq.S diff --git a/soc/riscv/riscv-privileged/telink_b91/soc_offsets.h b/soc/riscv/telink_tlsr/tlsr951x/soc_offsets.h similarity index 100% rename from soc/riscv/riscv-privileged/telink_b91/soc_offsets.h rename to soc/riscv/telink_tlsr/tlsr951x/soc_offsets.h diff --git a/soc/riscv/riscv-privileged/telink_b91/start.S b/soc/riscv/telink_tlsr/tlsr951x/start.S similarity index 100% rename from soc/riscv/riscv-privileged/telink_b91/start.S rename to soc/riscv/telink_tlsr/tlsr951x/start.S From 5a98d87335a2db818259dd71f84b4a9e8df052a2 Mon Sep 17 00:00:00 2001 From: Gerard Marull-Paretas Date: Wed, 3 Jan 2024 14:14:00 +0100 Subject: [PATCH 1883/3723] soc: riscv: gd32vf103: reorganize SoC folder Move things out from riscv-privileged, and create the new RISC-V GD32 family. New family folder follows the _ naming convention. Signed-off-by: Gerard Marull-Paretas --- MAINTAINERS.yml | 2 +- soc/riscv/gd_gd32/CMakeLists.txt | 4 ++++ soc/riscv/gd_gd32/Kconfig | 15 +++++++++++++++ soc/riscv/gd_gd32/Kconfig.defconfig | 4 ++++ soc/riscv/gd_gd32/Kconfig.soc | 4 ++++ .../gd32vf103/CMakeLists.txt | 0 .../gd32vf103/Kconfig.defconfig.gd32vf103 | 0 .../gd32vf103/Kconfig.defconfig.series | 2 +- .../gd32vf103/Kconfig.series | 3 ++- .../gd32vf103/Kconfig.soc | 0 .../gd32vf103/entry.S | 0 .../gd32vf103/gd32_regs.h | 0 .../gd32vf103/nuclei_csr.h | 0 .../gd32vf103/pinctrl_soc.h | 0 .../{riscv-privileged => gd_gd32}/gd32vf103/soc.c | 0 .../{riscv-privileged => gd_gd32}/gd32vf103/soc.h | 0 16 files changed, 31 insertions(+), 3 deletions(-) create mode 100644 soc/riscv/gd_gd32/CMakeLists.txt create mode 100644 soc/riscv/gd_gd32/Kconfig create mode 100644 soc/riscv/gd_gd32/Kconfig.defconfig create mode 100644 soc/riscv/gd_gd32/Kconfig.soc rename soc/riscv/{riscv-privileged => gd_gd32}/gd32vf103/CMakeLists.txt (100%) rename soc/riscv/{riscv-privileged => gd_gd32}/gd32vf103/Kconfig.defconfig.gd32vf103 (100%) rename soc/riscv/{riscv-privileged => gd_gd32}/gd32vf103/Kconfig.defconfig.series (72%) rename soc/riscv/{riscv-privileged => gd_gd32}/gd32vf103/Kconfig.series (89%) rename soc/riscv/{riscv-privileged => gd_gd32}/gd32vf103/Kconfig.soc (100%) rename soc/riscv/{riscv-privileged => gd_gd32}/gd32vf103/entry.S (100%) rename soc/riscv/{riscv-privileged => gd_gd32}/gd32vf103/gd32_regs.h (100%) rename soc/riscv/{riscv-privileged => gd_gd32}/gd32vf103/nuclei_csr.h (100%) rename soc/riscv/{riscv-privileged => gd_gd32}/gd32vf103/pinctrl_soc.h (100%) rename soc/riscv/{riscv-privileged => gd_gd32}/gd32vf103/soc.c (100%) rename soc/riscv/{riscv-privileged => gd_gd32}/gd32vf103/soc.h (100%) diff --git a/MAINTAINERS.yml b/MAINTAINERS.yml index 92782837327..56b50ca4c1e 100644 --- a/MAINTAINERS.yml +++ b/MAINTAINERS.yml @@ -2995,7 +2995,7 @@ GD32 Platforms: - dts/*/gigadevice/ - dts/bindings/*/*gd32* - soc/arm/gigadevice/ - - soc/riscv/riscv-privileged/gd32vf103/ + - soc/riscv/gd_gd32/ - scripts/west_commands/*/*gd32* labels: - "platform: GD32" diff --git a/soc/riscv/gd_gd32/CMakeLists.txt b/soc/riscv/gd_gd32/CMakeLists.txt new file mode 100644 index 00000000000..69b2926358e --- /dev/null +++ b/soc/riscv/gd_gd32/CMakeLists.txt @@ -0,0 +1,4 @@ +# Copyright (c) 2024 Nordic Semiconductor +# SPDX-License-Identifier: Apache-2.0 + +add_subdirectory(${SOC_SERIES}) diff --git a/soc/riscv/gd_gd32/Kconfig b/soc/riscv/gd_gd32/Kconfig new file mode 100644 index 00000000000..46f2dd0b1d6 --- /dev/null +++ b/soc/riscv/gd_gd32/Kconfig @@ -0,0 +1,15 @@ +# Copyright (c) 2024 Nordic Semiconductor ASA +# SPDX-License-Identifier: Apache-2.0 + +config SOC_FAMILY_GD32 + bool + +if SOC_FAMILY_GD32 + +config SOC_FAMILY + string + default "gd_gd32" + +source "soc/riscv/gd_gd32/*/Kconfig.soc" + +endif # SOC_FAMILY_GIGADEVICE_GD32 diff --git a/soc/riscv/gd_gd32/Kconfig.defconfig b/soc/riscv/gd_gd32/Kconfig.defconfig new file mode 100644 index 00000000000..2be284db7ea --- /dev/null +++ b/soc/riscv/gd_gd32/Kconfig.defconfig @@ -0,0 +1,4 @@ +# Copyright (c) 2024 Nordic Semiconductor ASA +# SPDX-License-Identifier: Apache-2.0 + +source "soc/riscv/gd_gd32/*/Kconfig.defconfig.series" diff --git a/soc/riscv/gd_gd32/Kconfig.soc b/soc/riscv/gd_gd32/Kconfig.soc new file mode 100644 index 00000000000..09d7d5d627e --- /dev/null +++ b/soc/riscv/gd_gd32/Kconfig.soc @@ -0,0 +1,4 @@ +# Copyright (c) 2024 Nordic Semiconductor ASA +# SPDX-License-Identifier: Apache-2.0 + +source "soc/riscv/gd_gd32/*/Kconfig.series" diff --git a/soc/riscv/riscv-privileged/gd32vf103/CMakeLists.txt b/soc/riscv/gd_gd32/gd32vf103/CMakeLists.txt similarity index 100% rename from soc/riscv/riscv-privileged/gd32vf103/CMakeLists.txt rename to soc/riscv/gd_gd32/gd32vf103/CMakeLists.txt diff --git a/soc/riscv/riscv-privileged/gd32vf103/Kconfig.defconfig.gd32vf103 b/soc/riscv/gd_gd32/gd32vf103/Kconfig.defconfig.gd32vf103 similarity index 100% rename from soc/riscv/riscv-privileged/gd32vf103/Kconfig.defconfig.gd32vf103 rename to soc/riscv/gd_gd32/gd32vf103/Kconfig.defconfig.gd32vf103 diff --git a/soc/riscv/riscv-privileged/gd32vf103/Kconfig.defconfig.series b/soc/riscv/gd_gd32/gd32vf103/Kconfig.defconfig.series similarity index 72% rename from soc/riscv/riscv-privileged/gd32vf103/Kconfig.defconfig.series rename to soc/riscv/gd_gd32/gd32vf103/Kconfig.defconfig.series index 061b53b2514..17ab7a87c39 100644 --- a/soc/riscv/riscv-privileged/gd32vf103/Kconfig.defconfig.series +++ b/soc/riscv/gd_gd32/gd32vf103/Kconfig.defconfig.series @@ -3,7 +3,7 @@ if SOC_SERIES_GD32VF103 -source "soc/riscv/riscv-privileged/gd32vf103/Kconfig.defconfig.gd32vf103*" +source "soc/riscv/gd_gd32/gd32vf103/Kconfig.defconfig.gd32vf103*" config SOC_SERIES default "gd32vf103" diff --git a/soc/riscv/riscv-privileged/gd32vf103/Kconfig.series b/soc/riscv/gd_gd32/gd32vf103/Kconfig.series similarity index 89% rename from soc/riscv/riscv-privileged/gd32vf103/Kconfig.series rename to soc/riscv/gd_gd32/gd32vf103/Kconfig.series index 79bb3690743..b0b86db7c02 100644 --- a/soc/riscv/riscv-privileged/gd32vf103/Kconfig.series +++ b/soc/riscv/gd_gd32/gd32vf103/Kconfig.series @@ -15,6 +15,7 @@ config SOC_SERIES_GD32VF103 select GD32_HAS_IRC_40K select HAS_GD32_HAL select RISCV_HAS_CLIC - + select SOC_FAMILY_GD32 + select RISCV_PRIVILEGED_STANDALONE help Enable support for GigaDevice GD32VF1 series SoC diff --git a/soc/riscv/riscv-privileged/gd32vf103/Kconfig.soc b/soc/riscv/gd_gd32/gd32vf103/Kconfig.soc similarity index 100% rename from soc/riscv/riscv-privileged/gd32vf103/Kconfig.soc rename to soc/riscv/gd_gd32/gd32vf103/Kconfig.soc diff --git a/soc/riscv/riscv-privileged/gd32vf103/entry.S b/soc/riscv/gd_gd32/gd32vf103/entry.S similarity index 100% rename from soc/riscv/riscv-privileged/gd32vf103/entry.S rename to soc/riscv/gd_gd32/gd32vf103/entry.S diff --git a/soc/riscv/riscv-privileged/gd32vf103/gd32_regs.h b/soc/riscv/gd_gd32/gd32vf103/gd32_regs.h similarity index 100% rename from soc/riscv/riscv-privileged/gd32vf103/gd32_regs.h rename to soc/riscv/gd_gd32/gd32vf103/gd32_regs.h diff --git a/soc/riscv/riscv-privileged/gd32vf103/nuclei_csr.h b/soc/riscv/gd_gd32/gd32vf103/nuclei_csr.h similarity index 100% rename from soc/riscv/riscv-privileged/gd32vf103/nuclei_csr.h rename to soc/riscv/gd_gd32/gd32vf103/nuclei_csr.h diff --git a/soc/riscv/riscv-privileged/gd32vf103/pinctrl_soc.h b/soc/riscv/gd_gd32/gd32vf103/pinctrl_soc.h similarity index 100% rename from soc/riscv/riscv-privileged/gd32vf103/pinctrl_soc.h rename to soc/riscv/gd_gd32/gd32vf103/pinctrl_soc.h diff --git a/soc/riscv/riscv-privileged/gd32vf103/soc.c b/soc/riscv/gd_gd32/gd32vf103/soc.c similarity index 100% rename from soc/riscv/riscv-privileged/gd32vf103/soc.c rename to soc/riscv/gd_gd32/gd32vf103/soc.c diff --git a/soc/riscv/riscv-privileged/gd32vf103/soc.h b/soc/riscv/gd_gd32/gd32vf103/soc.h similarity index 100% rename from soc/riscv/riscv-privileged/gd32vf103/soc.h rename to soc/riscv/gd_gd32/gd32vf103/soc.h From 87f3b072922fe3f5f6e55f090e6abd3d155cbf0e Mon Sep 17 00:00:00 2001 From: Gerard Marull-Paretas Date: Wed, 3 Jan 2024 15:15:05 +0100 Subject: [PATCH 1884/3723] soc: riscv: starfive_jh71xx: reorganize SoC folder Move it out from RISC-V privileged folder, and create a standalone family. Signed-off-by: Gerard Marull-Paretas --- soc/riscv/starfive_jh71xx/CMakeLists.txt | 4 ++++ soc/riscv/starfive_jh71xx/Kconfig | 15 +++++++++++++++ soc/riscv/starfive_jh71xx/Kconfig.defconfig | 4 ++++ soc/riscv/starfive_jh71xx/Kconfig.soc | 4 ++++ .../jh71xx}/CMakeLists.txt | 0 .../jh71xx/Kconfig.defconfig.jh7100 | 5 +++++ .../jh71xx}/Kconfig.defconfig.series | 4 +++- .../jh71xx}/Kconfig.series | 1 + .../jh71xx}/Kconfig.soc | 0 .../jh71xx}/soc.h | 0 10 files changed, 36 insertions(+), 1 deletion(-) create mode 100644 soc/riscv/starfive_jh71xx/CMakeLists.txt create mode 100644 soc/riscv/starfive_jh71xx/Kconfig create mode 100644 soc/riscv/starfive_jh71xx/Kconfig.defconfig create mode 100644 soc/riscv/starfive_jh71xx/Kconfig.soc rename soc/riscv/{riscv-privileged/starfive_jh71xx => starfive_jh71xx/jh71xx}/CMakeLists.txt (100%) create mode 100644 soc/riscv/starfive_jh71xx/jh71xx/Kconfig.defconfig.jh7100 rename soc/riscv/{riscv-privileged/starfive_jh71xx => starfive_jh71xx/jh71xx}/Kconfig.defconfig.series (84%) rename soc/riscv/{riscv-privileged/starfive_jh71xx => starfive_jh71xx/jh71xx}/Kconfig.series (88%) rename soc/riscv/{riscv-privileged/starfive_jh71xx => starfive_jh71xx/jh71xx}/Kconfig.soc (100%) rename soc/riscv/{riscv-privileged/starfive_jh71xx => starfive_jh71xx/jh71xx}/soc.h (100%) diff --git a/soc/riscv/starfive_jh71xx/CMakeLists.txt b/soc/riscv/starfive_jh71xx/CMakeLists.txt new file mode 100644 index 00000000000..69b2926358e --- /dev/null +++ b/soc/riscv/starfive_jh71xx/CMakeLists.txt @@ -0,0 +1,4 @@ +# Copyright (c) 2024 Nordic Semiconductor +# SPDX-License-Identifier: Apache-2.0 + +add_subdirectory(${SOC_SERIES}) diff --git a/soc/riscv/starfive_jh71xx/Kconfig b/soc/riscv/starfive_jh71xx/Kconfig new file mode 100644 index 00000000000..65694c07eff --- /dev/null +++ b/soc/riscv/starfive_jh71xx/Kconfig @@ -0,0 +1,15 @@ +# Copyright (c) 2024 Nordic Semiconductor ASA +# SPDX-License-Identifier: Apache-2.0 + +config SOC_FAMILY_STARFIVE_JH71XX + bool + +if SOC_FAMILY_STARFIVE_JH71XX + +config SOC_FAMILY + string + default "starfive_jh71xx" + +source "soc/riscv/starfive_jh71xx/*/Kconfig.soc" + +endif # SOC_FAMILY_STARFIVE_JH71XX diff --git a/soc/riscv/starfive_jh71xx/Kconfig.defconfig b/soc/riscv/starfive_jh71xx/Kconfig.defconfig new file mode 100644 index 00000000000..b399e38b340 --- /dev/null +++ b/soc/riscv/starfive_jh71xx/Kconfig.defconfig @@ -0,0 +1,4 @@ +# Copyright (c) 2024 Nordic Semiconductor ASA +# SPDX-License-Identifier: Apache-2.0 + +source "soc/riscv/starfive_jh71xx/*/Kconfig.defconfig.series" diff --git a/soc/riscv/starfive_jh71xx/Kconfig.soc b/soc/riscv/starfive_jh71xx/Kconfig.soc new file mode 100644 index 00000000000..1ff54faa970 --- /dev/null +++ b/soc/riscv/starfive_jh71xx/Kconfig.soc @@ -0,0 +1,4 @@ +# Copyright (c) 2024 Nordic Semiconductor ASA +# SPDX-License-Identifier: Apache-2.0 + +source "soc/riscv/starfive_jh71xx/*/Kconfig.series" diff --git a/soc/riscv/riscv-privileged/starfive_jh71xx/CMakeLists.txt b/soc/riscv/starfive_jh71xx/jh71xx/CMakeLists.txt similarity index 100% rename from soc/riscv/riscv-privileged/starfive_jh71xx/CMakeLists.txt rename to soc/riscv/starfive_jh71xx/jh71xx/CMakeLists.txt diff --git a/soc/riscv/starfive_jh71xx/jh71xx/Kconfig.defconfig.jh7100 b/soc/riscv/starfive_jh71xx/jh71xx/Kconfig.defconfig.jh7100 new file mode 100644 index 00000000000..6f38d61dd4e --- /dev/null +++ b/soc/riscv/starfive_jh71xx/jh71xx/Kconfig.defconfig.jh7100 @@ -0,0 +1,5 @@ +# Copyright (c) 2024 Nordic Semiconductor ASA +# SPDX-License-Identifier: Apache-2.0 + +config SOC + default "jh7100" if SOC_JH7100 diff --git a/soc/riscv/riscv-privileged/starfive_jh71xx/Kconfig.defconfig.series b/soc/riscv/starfive_jh71xx/jh71xx/Kconfig.defconfig.series similarity index 84% rename from soc/riscv/riscv-privileged/starfive_jh71xx/Kconfig.defconfig.series rename to soc/riscv/starfive_jh71xx/jh71xx/Kconfig.defconfig.series index c488c614b7d..77436b593e1 100644 --- a/soc/riscv/riscv-privileged/starfive_jh71xx/Kconfig.defconfig.series +++ b/soc/riscv/starfive_jh71xx/jh71xx/Kconfig.defconfig.series @@ -4,7 +4,7 @@ if SOC_SERIES_STARFIVE_JH71XX config SOC_SERIES - default "starfive_jh71xx" + default "jh71xx" config SYS_CLOCK_HW_CYCLES_PER_SEC default 6250000 @@ -30,4 +30,6 @@ config 2ND_LVL_INTR_00_OFFSET config NUM_IRQS default 139 +source "soc/riscv/starfive_jh71xx/jh71xx/Kconfig.defconfig.jh71*" + endif diff --git a/soc/riscv/riscv-privileged/starfive_jh71xx/Kconfig.series b/soc/riscv/starfive_jh71xx/jh71xx/Kconfig.series similarity index 88% rename from soc/riscv/riscv-privileged/starfive_jh71xx/Kconfig.series rename to soc/riscv/starfive_jh71xx/jh71xx/Kconfig.series index 19cedcefe27..d70cff1c63d 100644 --- a/soc/riscv/riscv-privileged/starfive_jh71xx/Kconfig.series +++ b/soc/riscv/starfive_jh71xx/jh71xx/Kconfig.series @@ -5,5 +5,6 @@ config SOC_SERIES_STARFIVE_JH71XX bool "Starfive JH71XX series" select RISCV select RISCV_PRIVILEGED + select RISCV_PRIVILEGED_STANDALONE help Enable support for Starfive JH71XX SoC Series. diff --git a/soc/riscv/riscv-privileged/starfive_jh71xx/Kconfig.soc b/soc/riscv/starfive_jh71xx/jh71xx/Kconfig.soc similarity index 100% rename from soc/riscv/riscv-privileged/starfive_jh71xx/Kconfig.soc rename to soc/riscv/starfive_jh71xx/jh71xx/Kconfig.soc diff --git a/soc/riscv/riscv-privileged/starfive_jh71xx/soc.h b/soc/riscv/starfive_jh71xx/jh71xx/soc.h similarity index 100% rename from soc/riscv/riscv-privileged/starfive_jh71xx/soc.h rename to soc/riscv/starfive_jh71xx/jh71xx/soc.h From 8027689392f6ba835906efe56296094bf49e3aa8 Mon Sep 17 00:00:00 2001 From: Gerard Marull-Paretas Date: Wed, 3 Jan 2024 15:25:56 +0100 Subject: [PATCH 1885/3723] soc: riscv: andes_v5: reorganize SoC folder Split out from riscv-privileged folder, and create a new family. Signed-off-by: Gerard Marull-Paretas --- boards/riscv/adp_xc7k_ae350/Kconfig.board | 2 +- .../riscv/adp_xc7k_ae350/adp_xc7k_ae350_defconfig | 4 ++-- drivers/hwinfo/Kconfig | 2 +- soc/riscv/andes_v5/CMakeLists.txt | 4 ++++ soc/riscv/andes_v5/Kconfig | 15 +++++++++++++++ soc/riscv/andes_v5/Kconfig.defconfig | 4 ++++ soc/riscv/andes_v5/Kconfig.soc | 4 ++++ .../andes_v5 => andes_v5/ae350}/CMakeLists.txt | 6 +++--- .../ae350}/Kconfig.defconfig.ae350 | 4 ++-- .../ae350}/Kconfig.defconfig.series | 8 ++++---- soc/riscv/andes_v5/ae350/Kconfig.series | 11 +++++++++++ .../andes_v5 => andes_v5/ae350}/Kconfig.soc | 8 ++++---- .../ae350}/common_linker/execit.ld | 0 .../ae350}/common_linker/init.ld | 0 .../ae350}/common_linker/ram_start_nonzero.ld | 0 .../andes_v5 => andes_v5/ae350}/l2_cache.c | 0 .../andes_v5/ae350/linker.ld | 0 .../andes_v5 => andes_v5/ae350}/pma.c | 0 .../{riscv-privileged => }/andes_v5/ae350/soc.h | 0 .../andes_v5 => andes_v5/ae350}/soc_context.h | 0 .../andes_v5 => andes_v5/ae350}/soc_irq.S | 0 .../andes_v5 => andes_v5/ae350}/soc_offsets.h | 0 .../andes_v5 => andes_v5/ae350}/soc_v5.h | 0 .../andes_v5 => andes_v5/ae350}/start.S | 0 .../riscv-privileged/andes_v5/Kconfig.series | 9 --------- 25 files changed, 55 insertions(+), 26 deletions(-) create mode 100644 soc/riscv/andes_v5/CMakeLists.txt create mode 100644 soc/riscv/andes_v5/Kconfig create mode 100644 soc/riscv/andes_v5/Kconfig.defconfig create mode 100644 soc/riscv/andes_v5/Kconfig.soc rename soc/riscv/{riscv-privileged/andes_v5 => andes_v5/ae350}/CMakeLists.txt (82%) rename soc/riscv/{riscv-privileged/andes_v5 => andes_v5/ae350}/Kconfig.defconfig.ae350 (88%) rename soc/riscv/{riscv-privileged/andes_v5 => andes_v5/ae350}/Kconfig.defconfig.series (83%) create mode 100644 soc/riscv/andes_v5/ae350/Kconfig.series rename soc/riscv/{riscv-privileged/andes_v5 => andes_v5/ae350}/Kconfig.soc (95%) rename soc/riscv/{riscv-privileged/andes_v5 => andes_v5/ae350}/common_linker/execit.ld (100%) rename soc/riscv/{riscv-privileged/andes_v5 => andes_v5/ae350}/common_linker/init.ld (100%) rename soc/riscv/{riscv-privileged/andes_v5 => andes_v5/ae350}/common_linker/ram_start_nonzero.ld (100%) rename soc/riscv/{riscv-privileged/andes_v5 => andes_v5/ae350}/l2_cache.c (100%) rename soc/riscv/{riscv-privileged => }/andes_v5/ae350/linker.ld (100%) rename soc/riscv/{riscv-privileged/andes_v5 => andes_v5/ae350}/pma.c (100%) rename soc/riscv/{riscv-privileged => }/andes_v5/ae350/soc.h (100%) rename soc/riscv/{riscv-privileged/andes_v5 => andes_v5/ae350}/soc_context.h (100%) rename soc/riscv/{riscv-privileged/andes_v5 => andes_v5/ae350}/soc_irq.S (100%) rename soc/riscv/{riscv-privileged/andes_v5 => andes_v5/ae350}/soc_offsets.h (100%) rename soc/riscv/{riscv-privileged/andes_v5 => andes_v5/ae350}/soc_v5.h (100%) rename soc/riscv/{riscv-privileged/andes_v5 => andes_v5/ae350}/start.S (100%) delete mode 100644 soc/riscv/riscv-privileged/andes_v5/Kconfig.series diff --git a/boards/riscv/adp_xc7k_ae350/Kconfig.board b/boards/riscv/adp_xc7k_ae350/Kconfig.board index 085eb9696a8..5b58e01fbfd 100644 --- a/boards/riscv/adp_xc7k_ae350/Kconfig.board +++ b/boards/riscv/adp_xc7k_ae350/Kconfig.board @@ -3,4 +3,4 @@ config BOARD_ADP_XC7K_AE350 bool "Andes ADP-XC7K AE350 Platform" - depends on SOC_RISCV_ANDES_AE350 + depends on SOC_ANDES_AE350 diff --git a/boards/riscv/adp_xc7k_ae350/adp_xc7k_ae350_defconfig b/boards/riscv/adp_xc7k_ae350/adp_xc7k_ae350_defconfig index 3f7f1f727c6..edbe7118c64 100644 --- a/boards/riscv/adp_xc7k_ae350/adp_xc7k_ae350_defconfig +++ b/boards/riscv/adp_xc7k_ae350/adp_xc7k_ae350_defconfig @@ -1,5 +1,5 @@ -CONFIG_SOC_SERIES_RISCV_ANDES_V5=y -CONFIG_SOC_RISCV_ANDES_AE350=y +CONFIG_SOC_SERIES_ANDES_AE350=y +CONFIG_SOC_ANDES_AE350=y CONFIG_BOARD_ADP_XC7K_AE350=y CONFIG_XIP=n CONFIG_CONSOLE=y diff --git a/drivers/hwinfo/Kconfig b/drivers/hwinfo/Kconfig index f293ab60b7f..84afbefd84f 100644 --- a/drivers/hwinfo/Kconfig +++ b/drivers/hwinfo/Kconfig @@ -188,7 +188,7 @@ config HWINFO_GECKO config HWINFO_ANDES bool "Andes system ID" default y - depends on SOC_SERIES_RISCV_ANDES_V5 + depends on SOC_FAMILY_ANDES_V5 help Enable Andes hwinfo driver diff --git a/soc/riscv/andes_v5/CMakeLists.txt b/soc/riscv/andes_v5/CMakeLists.txt new file mode 100644 index 00000000000..69b2926358e --- /dev/null +++ b/soc/riscv/andes_v5/CMakeLists.txt @@ -0,0 +1,4 @@ +# Copyright (c) 2024 Nordic Semiconductor +# SPDX-License-Identifier: Apache-2.0 + +add_subdirectory(${SOC_SERIES}) diff --git a/soc/riscv/andes_v5/Kconfig b/soc/riscv/andes_v5/Kconfig new file mode 100644 index 00000000000..f3c78ab7f81 --- /dev/null +++ b/soc/riscv/andes_v5/Kconfig @@ -0,0 +1,15 @@ +# Copyright (c) 2024 Nordic Semiconductor ASA +# SPDX-License-Identifier: Apache-2.0 + +config SOC_FAMILY_ANDES_V5 + bool + +if SOC_FAMILY_ANDES_V5 + +config SOC_FAMILY + string + default "andes_v5" + +source "soc/riscv/andes_v5/*/Kconfig.soc" + +endif # SOC_FAMILY_ANDES_V5 diff --git a/soc/riscv/andes_v5/Kconfig.defconfig b/soc/riscv/andes_v5/Kconfig.defconfig new file mode 100644 index 00000000000..6213f28d2cb --- /dev/null +++ b/soc/riscv/andes_v5/Kconfig.defconfig @@ -0,0 +1,4 @@ +# Copyright (c) 2024 Nordic Semiconductor ASA +# SPDX-License-Identifier: Apache-2.0 + +source "soc/riscv/andes_v5/*/Kconfig.defconfig.series" diff --git a/soc/riscv/andes_v5/Kconfig.soc b/soc/riscv/andes_v5/Kconfig.soc new file mode 100644 index 00000000000..9efb4781934 --- /dev/null +++ b/soc/riscv/andes_v5/Kconfig.soc @@ -0,0 +1,4 @@ +# Copyright (c) 2024 Nordic Semiconductor ASA +# SPDX-License-Identifier: Apache-2.0 + +source "soc/riscv/andes_v5/*/Kconfig.series" diff --git a/soc/riscv/riscv-privileged/andes_v5/CMakeLists.txt b/soc/riscv/andes_v5/ae350/CMakeLists.txt similarity index 82% rename from soc/riscv/riscv-privileged/andes_v5/CMakeLists.txt rename to soc/riscv/andes_v5/ae350/CMakeLists.txt index 21268312347..b8eac026dfb 100644 --- a/soc/riscv/riscv-privileged/andes_v5/CMakeLists.txt +++ b/soc/riscv/andes_v5/ae350/CMakeLists.txt @@ -1,6 +1,6 @@ # SPDX-License-Identifier: Apache-2.0 -zephyr_include_directories(${CONFIG_SOC}) +zephyr_include_directories(.) zephyr_sources( start.S @@ -24,6 +24,6 @@ if(CONFIG_SOC_ANDES_V5_EXECIT) zephyr_ld_options(-Wl,--mexecit) endif() -if(CONFIG_SOC_RISCV_ANDES_AE350) - set(SOC_LINKER_SCRIPT ${CMAKE_CURRENT_SOURCE_DIR}/ae350/linker.ld CACHE INTERNAL "") +if(CONFIG_SOC_ANDES_AE350) + set(SOC_LINKER_SCRIPT ${CMAKE_CURRENT_SOURCE_DIR}/linker.ld CACHE INTERNAL "") endif() diff --git a/soc/riscv/riscv-privileged/andes_v5/Kconfig.defconfig.ae350 b/soc/riscv/andes_v5/ae350/Kconfig.defconfig.ae350 similarity index 88% rename from soc/riscv/riscv-privileged/andes_v5/Kconfig.defconfig.ae350 rename to soc/riscv/andes_v5/ae350/Kconfig.defconfig.ae350 index 5d652057a38..fee73684b71 100644 --- a/soc/riscv/riscv-privileged/andes_v5/Kconfig.defconfig.ae350 +++ b/soc/riscv/andes_v5/ae350/Kconfig.defconfig.ae350 @@ -1,7 +1,7 @@ # Copyright (c) 2021 Andes Technology Corporation # SPDX-License-Identifier: Apache-2.0 -if SOC_RISCV_ANDES_AE350 +if SOC_ANDES_AE350 config SOC default "ae350" @@ -25,4 +25,4 @@ config MP_MAX_NUM_CPUS default 1 range 1 8 -endif # SOC_RISCV_ANDES_AE350 +endif # SOC_ANDES_AE350 diff --git a/soc/riscv/riscv-privileged/andes_v5/Kconfig.defconfig.series b/soc/riscv/andes_v5/ae350/Kconfig.defconfig.series similarity index 83% rename from soc/riscv/riscv-privileged/andes_v5/Kconfig.defconfig.series rename to soc/riscv/andes_v5/ae350/Kconfig.defconfig.series index c6436807825..7bd679e5f45 100644 --- a/soc/riscv/riscv-privileged/andes_v5/Kconfig.defconfig.series +++ b/soc/riscv/andes_v5/ae350/Kconfig.defconfig.series @@ -1,15 +1,15 @@ # Copyright (c) 2021 Andes Technology Corporation # SPDX-License-Identifier: Apache-2.0 -if SOC_SERIES_RISCV_ANDES_V5 +if SOC_SERIES_ANDES_AE350 # Kconfig picks the first default with a satisfied condition. # SoC defaults should be parsed before SoC Series defaults, because SoCs usually # overrides SoC Series values. -source "soc/riscv/riscv-privileged/andes_v5/Kconfig.defconfig.ae*" +source "soc/riscv/andes_v5/ae350/Kconfig.defconfig.ae*" config SOC_SERIES - default "andes_v5" + default "ae350" config SYS_CLOCK_HW_CYCLES_PER_SEC default 60000000 @@ -45,4 +45,4 @@ config MAX_IRQ_PER_AGGREGATOR config NUM_IRQS default 64 -endif # SOC_SERIES_RISCV_ANDES_V5 +endif # SOC_SERIES_ANDES_AE350 diff --git a/soc/riscv/andes_v5/ae350/Kconfig.series b/soc/riscv/andes_v5/ae350/Kconfig.series new file mode 100644 index 00000000000..4eb9557f92f --- /dev/null +++ b/soc/riscv/andes_v5/ae350/Kconfig.series @@ -0,0 +1,11 @@ +# Copyright (c) 2021 Andes Technology Corporation +# SPDX-License-Identifier: Apache-2.0 + +config SOC_SERIES_ANDES_AE350 + bool "Andes V5 AE350 SoC Series Implementation" + select RISCV + select RISCV_PRIVILEGED + select RISCV_PRIVILEGED_STANDALONE + select SOC_FAMILY_ANDES_V5 + help + Enable support for Andes V5 AE350 SoC Series diff --git a/soc/riscv/riscv-privileged/andes_v5/Kconfig.soc b/soc/riscv/andes_v5/ae350/Kconfig.soc similarity index 95% rename from soc/riscv/riscv-privileged/andes_v5/Kconfig.soc rename to soc/riscv/andes_v5/ae350/Kconfig.soc index 19f215e2c5a..1731cc08f51 100644 --- a/soc/riscv/riscv-privileged/andes_v5/Kconfig.soc +++ b/soc/riscv/andes_v5/ae350/Kconfig.soc @@ -3,9 +3,9 @@ choice prompt "Andes V5 SoC Selection" -depends on SOC_SERIES_RISCV_ANDES_V5 +depends on SOC_SERIES_ANDES_AE350 -config SOC_RISCV_ANDES_AE350 +config SOC_ANDES_AE350 bool "Andes AE350 SoC implementation" select ATOMIC_OPERATIONS_BUILTIN select INCLUDE_RESET_VECTOR @@ -18,7 +18,7 @@ config SOC_RISCV_ANDES_AE350 endchoice -if SOC_SERIES_RISCV_ANDES_V5 +if SOC_SERIES_ANDES_AE350 choice prompt "Base CPU ISA options" @@ -121,4 +121,4 @@ config SOC_ANDES_V5_IOCP between cache and external non-caching master, such as DMA controller. -endif # SOC_SERIES_RISCV_ANDES_V5 +endif # SOC_SERIES_ANDES_AE350 diff --git a/soc/riscv/riscv-privileged/andes_v5/common_linker/execit.ld b/soc/riscv/andes_v5/ae350/common_linker/execit.ld similarity index 100% rename from soc/riscv/riscv-privileged/andes_v5/common_linker/execit.ld rename to soc/riscv/andes_v5/ae350/common_linker/execit.ld diff --git a/soc/riscv/riscv-privileged/andes_v5/common_linker/init.ld b/soc/riscv/andes_v5/ae350/common_linker/init.ld similarity index 100% rename from soc/riscv/riscv-privileged/andes_v5/common_linker/init.ld rename to soc/riscv/andes_v5/ae350/common_linker/init.ld diff --git a/soc/riscv/riscv-privileged/andes_v5/common_linker/ram_start_nonzero.ld b/soc/riscv/andes_v5/ae350/common_linker/ram_start_nonzero.ld similarity index 100% rename from soc/riscv/riscv-privileged/andes_v5/common_linker/ram_start_nonzero.ld rename to soc/riscv/andes_v5/ae350/common_linker/ram_start_nonzero.ld diff --git a/soc/riscv/riscv-privileged/andes_v5/l2_cache.c b/soc/riscv/andes_v5/ae350/l2_cache.c similarity index 100% rename from soc/riscv/riscv-privileged/andes_v5/l2_cache.c rename to soc/riscv/andes_v5/ae350/l2_cache.c diff --git a/soc/riscv/riscv-privileged/andes_v5/ae350/linker.ld b/soc/riscv/andes_v5/ae350/linker.ld similarity index 100% rename from soc/riscv/riscv-privileged/andes_v5/ae350/linker.ld rename to soc/riscv/andes_v5/ae350/linker.ld diff --git a/soc/riscv/riscv-privileged/andes_v5/pma.c b/soc/riscv/andes_v5/ae350/pma.c similarity index 100% rename from soc/riscv/riscv-privileged/andes_v5/pma.c rename to soc/riscv/andes_v5/ae350/pma.c diff --git a/soc/riscv/riscv-privileged/andes_v5/ae350/soc.h b/soc/riscv/andes_v5/ae350/soc.h similarity index 100% rename from soc/riscv/riscv-privileged/andes_v5/ae350/soc.h rename to soc/riscv/andes_v5/ae350/soc.h diff --git a/soc/riscv/riscv-privileged/andes_v5/soc_context.h b/soc/riscv/andes_v5/ae350/soc_context.h similarity index 100% rename from soc/riscv/riscv-privileged/andes_v5/soc_context.h rename to soc/riscv/andes_v5/ae350/soc_context.h diff --git a/soc/riscv/riscv-privileged/andes_v5/soc_irq.S b/soc/riscv/andes_v5/ae350/soc_irq.S similarity index 100% rename from soc/riscv/riscv-privileged/andes_v5/soc_irq.S rename to soc/riscv/andes_v5/ae350/soc_irq.S diff --git a/soc/riscv/riscv-privileged/andes_v5/soc_offsets.h b/soc/riscv/andes_v5/ae350/soc_offsets.h similarity index 100% rename from soc/riscv/riscv-privileged/andes_v5/soc_offsets.h rename to soc/riscv/andes_v5/ae350/soc_offsets.h diff --git a/soc/riscv/riscv-privileged/andes_v5/soc_v5.h b/soc/riscv/andes_v5/ae350/soc_v5.h similarity index 100% rename from soc/riscv/riscv-privileged/andes_v5/soc_v5.h rename to soc/riscv/andes_v5/ae350/soc_v5.h diff --git a/soc/riscv/riscv-privileged/andes_v5/start.S b/soc/riscv/andes_v5/ae350/start.S similarity index 100% rename from soc/riscv/riscv-privileged/andes_v5/start.S rename to soc/riscv/andes_v5/ae350/start.S diff --git a/soc/riscv/riscv-privileged/andes_v5/Kconfig.series b/soc/riscv/riscv-privileged/andes_v5/Kconfig.series deleted file mode 100644 index a85c521492b..00000000000 --- a/soc/riscv/riscv-privileged/andes_v5/Kconfig.series +++ /dev/null @@ -1,9 +0,0 @@ -# Copyright (c) 2021 Andes Technology Corporation -# SPDX-License-Identifier: Apache-2.0 - -config SOC_SERIES_RISCV_ANDES_V5 - bool "Andes V5 SoC Series Implementation" - select RISCV - select RISCV_PRIVILEGED - help - Enable support for Andes V5 SoC Series From 4a0d880350b84d22789a37c942a567c6036e8aca Mon Sep 17 00:00:00 2001 From: Gerard Marull-Paretas Date: Wed, 3 Jan 2024 15:36:49 +0100 Subject: [PATCH 1886/3723] soc: riscv: ite: reorganize SoC folder Follow the vendor structure [1]: - Family: ITE Embedded Controller SoCs - Series: IT8XXX2 - SoCs: IT81202BX, IT81202CX, etc. [1]: https://www.ite.com.tw/en/product/category?cid=1 Signed-off-by: Gerard Marull-Paretas --- MAINTAINERS.yml | 2 +- boards/riscv/it82xx2_evb/it82xx2_evb_defconfig | 2 +- boards/riscv/it8xxx2_evb/it8xxx2_evb_defconfig | 2 +- soc/riscv/{riscv-ite => ite_ec}/CMakeLists.txt | 0 soc/riscv/ite_ec/Kconfig | 17 +++++++++++++++++ .../{riscv-ite => ite_ec}/Kconfig.defconfig | 2 +- soc/riscv/{riscv-ite => ite_ec}/Kconfig.soc | 2 +- .../{riscv-ite => ite_ec}/common/CMakeLists.txt | 0 .../{riscv-ite => ite_ec}/common/check_regs.c | 0 .../common/chip_chipregs.h | 0 .../{riscv-ite => ite_ec}/common/pinctrl_soc.h | 0 soc/riscv/{riscv-ite => ite_ec}/common/policy.c | 0 soc/riscv/{riscv-ite => ite_ec}/common/power.c | 0 .../{riscv-ite => ite_ec}/common/soc_common.h | 0 .../common/soc_common_irq.c | 0 soc/riscv/{riscv-ite => ite_ec}/common/soc_dt.h | 0 .../{riscv-ite => ite_ec}/common/soc_espi.h | 0 .../{riscv-ite => ite_ec}/common/soc_irq.S | 0 soc/riscv/{riscv-ite => ite_ec}/common/vector.S | 0 .../it8xxx2/CMakeLists.txt | 0 .../it8xxx2/Kconfig.defconfig.it81202bx | 0 .../it8xxx2/Kconfig.defconfig.it81202cx | 0 .../it8xxx2/Kconfig.defconfig.it81302bx | 0 .../it8xxx2/Kconfig.defconfig.it81302cx | 0 .../it8xxx2/Kconfig.defconfig.it82002aw | 0 .../it8xxx2/Kconfig.defconfig.it82202ax | 0 .../it8xxx2/Kconfig.defconfig.it82302ax | 0 .../it8xxx2/Kconfig.defconfig.series | 6 +++--- .../it8xxx2/Kconfig.series | 4 ++-- .../{riscv-ite => ite_ec}/it8xxx2/Kconfig.soc | 2 +- .../it8xxx2/__arithmetic.S | 0 soc/riscv/{riscv-ite => ite_ec}/it8xxx2/ilm.c | 0 soc/riscv/{riscv-ite => ite_ec}/it8xxx2/ilm.h | 0 .../{riscv-ite => ite_ec}/it8xxx2/linker.ld | 0 soc/riscv/{riscv-ite => ite_ec}/it8xxx2/soc.c | 0 soc/riscv/{riscv-ite => ite_ec}/it8xxx2/soc.h | 0 soc/riscv/riscv-ite/Kconfig | 14 -------------- .../gpio/gpio_ite_it8xxx2_v2/CMakeLists.txt | 4 ++-- .../gpio_ite_it8xxx2_v2/include/chip_chipregs.h | 2 +- 39 files changed, 31 insertions(+), 28 deletions(-) rename soc/riscv/{riscv-ite => ite_ec}/CMakeLists.txt (100%) create mode 100644 soc/riscv/ite_ec/Kconfig rename soc/riscv/{riscv-ite => ite_ec}/Kconfig.defconfig (63%) rename soc/riscv/{riscv-ite => ite_ec}/Kconfig.soc (68%) rename soc/riscv/{riscv-ite => ite_ec}/common/CMakeLists.txt (100%) rename soc/riscv/{riscv-ite => ite_ec}/common/check_regs.c (100%) rename soc/riscv/{riscv-ite => ite_ec}/common/chip_chipregs.h (100%) rename soc/riscv/{riscv-ite => ite_ec}/common/pinctrl_soc.h (100%) rename soc/riscv/{riscv-ite => ite_ec}/common/policy.c (100%) rename soc/riscv/{riscv-ite => ite_ec}/common/power.c (100%) rename soc/riscv/{riscv-ite => ite_ec}/common/soc_common.h (100%) rename soc/riscv/{riscv-ite => ite_ec}/common/soc_common_irq.c (100%) rename soc/riscv/{riscv-ite => ite_ec}/common/soc_dt.h (100%) rename soc/riscv/{riscv-ite => ite_ec}/common/soc_espi.h (100%) rename soc/riscv/{riscv-ite => ite_ec}/common/soc_irq.S (100%) rename soc/riscv/{riscv-ite => ite_ec}/common/vector.S (100%) rename soc/riscv/{riscv-ite => ite_ec}/it8xxx2/CMakeLists.txt (100%) rename soc/riscv/{riscv-ite => ite_ec}/it8xxx2/Kconfig.defconfig.it81202bx (100%) rename soc/riscv/{riscv-ite => ite_ec}/it8xxx2/Kconfig.defconfig.it81202cx (100%) rename soc/riscv/{riscv-ite => ite_ec}/it8xxx2/Kconfig.defconfig.it81302bx (100%) rename soc/riscv/{riscv-ite => ite_ec}/it8xxx2/Kconfig.defconfig.it81302cx (100%) rename soc/riscv/{riscv-ite => ite_ec}/it8xxx2/Kconfig.defconfig.it82002aw (100%) rename soc/riscv/{riscv-ite => ite_ec}/it8xxx2/Kconfig.defconfig.it82202ax (100%) rename soc/riscv/{riscv-ite => ite_ec}/it8xxx2/Kconfig.defconfig.it82302ax (100%) rename soc/riscv/{riscv-ite => ite_ec}/it8xxx2/Kconfig.defconfig.series (87%) rename soc/riscv/{riscv-ite => ite_ec}/it8xxx2/Kconfig.series (86%) rename soc/riscv/{riscv-ite => ite_ec}/it8xxx2/Kconfig.soc (99%) rename soc/riscv/{riscv-ite => ite_ec}/it8xxx2/__arithmetic.S (100%) rename soc/riscv/{riscv-ite => ite_ec}/it8xxx2/ilm.c (100%) rename soc/riscv/{riscv-ite => ite_ec}/it8xxx2/ilm.h (100%) rename soc/riscv/{riscv-ite => ite_ec}/it8xxx2/linker.ld (100%) rename soc/riscv/{riscv-ite => ite_ec}/it8xxx2/soc.c (100%) rename soc/riscv/{riscv-ite => ite_ec}/it8xxx2/soc.h (100%) delete mode 100644 soc/riscv/riscv-ite/Kconfig diff --git a/MAINTAINERS.yml b/MAINTAINERS.yml index 56b50ca4c1e..1ae22144b50 100644 --- a/MAINTAINERS.yml +++ b/MAINTAINERS.yml @@ -3384,7 +3384,7 @@ ITE Platforms: - drivers/*/*it8xxx2*.c - dts/bindings/*/*ite* - dts/riscv/ite/ - - soc/riscv/riscv-ite/ + - soc/riscv/ite_ec/ labels: - "platform: ITE" diff --git a/boards/riscv/it82xx2_evb/it82xx2_evb_defconfig b/boards/riscv/it82xx2_evb/it82xx2_evb_defconfig index f082e4a7bad..6866e3f633b 100644 --- a/boards/riscv/it82xx2_evb/it82xx2_evb_defconfig +++ b/boards/riscv/it82xx2_evb/it82xx2_evb_defconfig @@ -1,7 +1,7 @@ # Copyright (c) 2023 ITE Corporation. All Rights Reserved. # SPDX-License-Identifier: Apache-2.0 -CONFIG_SOC_SERIES_RISCV32_IT8XXX2=y +CONFIG_SOC_SERIES_ITE_IT8XXX2=y CONFIG_SOC_IT8XXX2=y CONFIG_SOC_IT82202_AX=y CONFIG_BOARD_IT82XX2_EVB=y diff --git a/boards/riscv/it8xxx2_evb/it8xxx2_evb_defconfig b/boards/riscv/it8xxx2_evb/it8xxx2_evb_defconfig index 21967527f8e..38a44d6f8f3 100644 --- a/boards/riscv/it8xxx2_evb/it8xxx2_evb_defconfig +++ b/boards/riscv/it8xxx2_evb/it8xxx2_evb_defconfig @@ -1,7 +1,7 @@ # Copyright (c) 2020 ITE Corporation. All Rights Reserved. # SPDX-License-Identifier: Apache-2.0 -CONFIG_SOC_SERIES_RISCV32_IT8XXX2=y +CONFIG_SOC_SERIES_ITE_IT8XXX2=y CONFIG_SOC_IT8XXX2=y CONFIG_BOARD_IT8XXX2_EVB=y CONFIG_BOOT_DELAY=1 diff --git a/soc/riscv/riscv-ite/CMakeLists.txt b/soc/riscv/ite_ec/CMakeLists.txt similarity index 100% rename from soc/riscv/riscv-ite/CMakeLists.txt rename to soc/riscv/ite_ec/CMakeLists.txt diff --git a/soc/riscv/ite_ec/Kconfig b/soc/riscv/ite_ec/Kconfig new file mode 100644 index 00000000000..54628029a4e --- /dev/null +++ b/soc/riscv/ite_ec/Kconfig @@ -0,0 +1,17 @@ +# Copyright (c) 2020 ITE Corporation. All Rights Reserved. +# SPDX-License-Identifier: Apache-2.0 + +config SOC_FAMILY_ITE_EC + bool + help + ITE Embedded Controller SoC family + +if SOC_FAMILY_ITE_EC + +config SOC_FAMILY + string + default "ite_ec" + +source "soc/riscv/ite_ec/*/Kconfig.soc" + +endif # SOC_FAMILY_ITE_EC diff --git a/soc/riscv/riscv-ite/Kconfig.defconfig b/soc/riscv/ite_ec/Kconfig.defconfig similarity index 63% rename from soc/riscv/riscv-ite/Kconfig.defconfig rename to soc/riscv/ite_ec/Kconfig.defconfig index ae18beac098..8994f47abd9 100644 --- a/soc/riscv/riscv-ite/Kconfig.defconfig +++ b/soc/riscv/ite_ec/Kconfig.defconfig @@ -1,4 +1,4 @@ # Copyright (c) 2020 ITE Corporation. All Rights Reserved. # SPDX-License-Identifier: Apache-2.0 -source "soc/riscv/riscv-ite/*/Kconfig.defconfig.series" +source "soc/riscv/ite_ec/*/Kconfig.defconfig.series" diff --git a/soc/riscv/riscv-ite/Kconfig.soc b/soc/riscv/ite_ec/Kconfig.soc similarity index 68% rename from soc/riscv/riscv-ite/Kconfig.soc rename to soc/riscv/ite_ec/Kconfig.soc index 925edb1543c..13f951c0466 100644 --- a/soc/riscv/riscv-ite/Kconfig.soc +++ b/soc/riscv/ite_ec/Kconfig.soc @@ -1,4 +1,4 @@ # Copyright (c) 2020 ITE Corporation. All Rights Reserved. # SPDX-License-Identifier: Apache-2.0 -source "soc/riscv/riscv-ite/*/Kconfig.series" +source "soc/riscv/ite_ec/*/Kconfig.series" diff --git a/soc/riscv/riscv-ite/common/CMakeLists.txt b/soc/riscv/ite_ec/common/CMakeLists.txt similarity index 100% rename from soc/riscv/riscv-ite/common/CMakeLists.txt rename to soc/riscv/ite_ec/common/CMakeLists.txt diff --git a/soc/riscv/riscv-ite/common/check_regs.c b/soc/riscv/ite_ec/common/check_regs.c similarity index 100% rename from soc/riscv/riscv-ite/common/check_regs.c rename to soc/riscv/ite_ec/common/check_regs.c diff --git a/soc/riscv/riscv-ite/common/chip_chipregs.h b/soc/riscv/ite_ec/common/chip_chipregs.h similarity index 100% rename from soc/riscv/riscv-ite/common/chip_chipregs.h rename to soc/riscv/ite_ec/common/chip_chipregs.h diff --git a/soc/riscv/riscv-ite/common/pinctrl_soc.h b/soc/riscv/ite_ec/common/pinctrl_soc.h similarity index 100% rename from soc/riscv/riscv-ite/common/pinctrl_soc.h rename to soc/riscv/ite_ec/common/pinctrl_soc.h diff --git a/soc/riscv/riscv-ite/common/policy.c b/soc/riscv/ite_ec/common/policy.c similarity index 100% rename from soc/riscv/riscv-ite/common/policy.c rename to soc/riscv/ite_ec/common/policy.c diff --git a/soc/riscv/riscv-ite/common/power.c b/soc/riscv/ite_ec/common/power.c similarity index 100% rename from soc/riscv/riscv-ite/common/power.c rename to soc/riscv/ite_ec/common/power.c diff --git a/soc/riscv/riscv-ite/common/soc_common.h b/soc/riscv/ite_ec/common/soc_common.h similarity index 100% rename from soc/riscv/riscv-ite/common/soc_common.h rename to soc/riscv/ite_ec/common/soc_common.h diff --git a/soc/riscv/riscv-ite/common/soc_common_irq.c b/soc/riscv/ite_ec/common/soc_common_irq.c similarity index 100% rename from soc/riscv/riscv-ite/common/soc_common_irq.c rename to soc/riscv/ite_ec/common/soc_common_irq.c diff --git a/soc/riscv/riscv-ite/common/soc_dt.h b/soc/riscv/ite_ec/common/soc_dt.h similarity index 100% rename from soc/riscv/riscv-ite/common/soc_dt.h rename to soc/riscv/ite_ec/common/soc_dt.h diff --git a/soc/riscv/riscv-ite/common/soc_espi.h b/soc/riscv/ite_ec/common/soc_espi.h similarity index 100% rename from soc/riscv/riscv-ite/common/soc_espi.h rename to soc/riscv/ite_ec/common/soc_espi.h diff --git a/soc/riscv/riscv-ite/common/soc_irq.S b/soc/riscv/ite_ec/common/soc_irq.S similarity index 100% rename from soc/riscv/riscv-ite/common/soc_irq.S rename to soc/riscv/ite_ec/common/soc_irq.S diff --git a/soc/riscv/riscv-ite/common/vector.S b/soc/riscv/ite_ec/common/vector.S similarity index 100% rename from soc/riscv/riscv-ite/common/vector.S rename to soc/riscv/ite_ec/common/vector.S diff --git a/soc/riscv/riscv-ite/it8xxx2/CMakeLists.txt b/soc/riscv/ite_ec/it8xxx2/CMakeLists.txt similarity index 100% rename from soc/riscv/riscv-ite/it8xxx2/CMakeLists.txt rename to soc/riscv/ite_ec/it8xxx2/CMakeLists.txt diff --git a/soc/riscv/riscv-ite/it8xxx2/Kconfig.defconfig.it81202bx b/soc/riscv/ite_ec/it8xxx2/Kconfig.defconfig.it81202bx similarity index 100% rename from soc/riscv/riscv-ite/it8xxx2/Kconfig.defconfig.it81202bx rename to soc/riscv/ite_ec/it8xxx2/Kconfig.defconfig.it81202bx diff --git a/soc/riscv/riscv-ite/it8xxx2/Kconfig.defconfig.it81202cx b/soc/riscv/ite_ec/it8xxx2/Kconfig.defconfig.it81202cx similarity index 100% rename from soc/riscv/riscv-ite/it8xxx2/Kconfig.defconfig.it81202cx rename to soc/riscv/ite_ec/it8xxx2/Kconfig.defconfig.it81202cx diff --git a/soc/riscv/riscv-ite/it8xxx2/Kconfig.defconfig.it81302bx b/soc/riscv/ite_ec/it8xxx2/Kconfig.defconfig.it81302bx similarity index 100% rename from soc/riscv/riscv-ite/it8xxx2/Kconfig.defconfig.it81302bx rename to soc/riscv/ite_ec/it8xxx2/Kconfig.defconfig.it81302bx diff --git a/soc/riscv/riscv-ite/it8xxx2/Kconfig.defconfig.it81302cx b/soc/riscv/ite_ec/it8xxx2/Kconfig.defconfig.it81302cx similarity index 100% rename from soc/riscv/riscv-ite/it8xxx2/Kconfig.defconfig.it81302cx rename to soc/riscv/ite_ec/it8xxx2/Kconfig.defconfig.it81302cx diff --git a/soc/riscv/riscv-ite/it8xxx2/Kconfig.defconfig.it82002aw b/soc/riscv/ite_ec/it8xxx2/Kconfig.defconfig.it82002aw similarity index 100% rename from soc/riscv/riscv-ite/it8xxx2/Kconfig.defconfig.it82002aw rename to soc/riscv/ite_ec/it8xxx2/Kconfig.defconfig.it82002aw diff --git a/soc/riscv/riscv-ite/it8xxx2/Kconfig.defconfig.it82202ax b/soc/riscv/ite_ec/it8xxx2/Kconfig.defconfig.it82202ax similarity index 100% rename from soc/riscv/riscv-ite/it8xxx2/Kconfig.defconfig.it82202ax rename to soc/riscv/ite_ec/it8xxx2/Kconfig.defconfig.it82202ax diff --git a/soc/riscv/riscv-ite/it8xxx2/Kconfig.defconfig.it82302ax b/soc/riscv/ite_ec/it8xxx2/Kconfig.defconfig.it82302ax similarity index 100% rename from soc/riscv/riscv-ite/it8xxx2/Kconfig.defconfig.it82302ax rename to soc/riscv/ite_ec/it8xxx2/Kconfig.defconfig.it82302ax diff --git a/soc/riscv/riscv-ite/it8xxx2/Kconfig.defconfig.series b/soc/riscv/ite_ec/it8xxx2/Kconfig.defconfig.series similarity index 87% rename from soc/riscv/riscv-ite/it8xxx2/Kconfig.defconfig.series rename to soc/riscv/ite_ec/it8xxx2/Kconfig.defconfig.series index 4e6b7c18cca..7c5bc0ee897 100644 --- a/soc/riscv/riscv-ite/it8xxx2/Kconfig.defconfig.series +++ b/soc/riscv/ite_ec/it8xxx2/Kconfig.defconfig.series @@ -1,7 +1,7 @@ # Copyright (c) 2020 ITE Corporation. All Rights Reserved. # SPDX-License-Identifier: Apache-2.0 -if SOC_SERIES_RISCV32_IT8XXX2 +if SOC_SERIES_ITE_IT8XXX2 config SOC_SERIES default "it8xxx2" @@ -57,6 +57,6 @@ config GEN_SW_ISR_TABLE config RISCV_SOC_INTERRUPT_INIT default y -source "soc/riscv/riscv-ite/it8xxx2/Kconfig.defconfig.it8*" +source "soc/riscv/ite_ec/it8xxx2/Kconfig.defconfig.it8*" -endif # SOC_SERIES_RISCV32_IT8XXX2 +endif # SOC_SERIES_ITE_IT8XXX2 diff --git a/soc/riscv/riscv-ite/it8xxx2/Kconfig.series b/soc/riscv/ite_ec/it8xxx2/Kconfig.series similarity index 86% rename from soc/riscv/riscv-ite/it8xxx2/Kconfig.series rename to soc/riscv/ite_ec/it8xxx2/Kconfig.series index ebed0fcd120..265bf855f12 100644 --- a/soc/riscv/riscv-ite/it8xxx2/Kconfig.series +++ b/soc/riscv/ite_ec/it8xxx2/Kconfig.series @@ -1,13 +1,13 @@ # Copyright (c) 2020 ITE Corporation. All Rights Reserved. # SPDX-License-Identifier: Apache-2.0 -config SOC_SERIES_RISCV32_IT8XXX2 +config SOC_SERIES_ITE_IT8XXX2 bool "ITE IT8XXX2 implementation" #depends on RISCV # RV32IAFC is an uncommon configuration which is not supported by # default in most toolchains, causing link-time errors. select CPU_HAS_FPU if "$(ZEPHYR_TOOLCHAIN_VARIANT)" != "zephyr" || RISCV_ISA_EXT_M - select SOC_FAMILY_RISCV_ITE + select SOC_FAMILY_ITE_EC select HAS_PM help Enable support for ITE IT8XXX2 diff --git a/soc/riscv/riscv-ite/it8xxx2/Kconfig.soc b/soc/riscv/ite_ec/it8xxx2/Kconfig.soc similarity index 99% rename from soc/riscv/riscv-ite/it8xxx2/Kconfig.soc rename to soc/riscv/ite_ec/it8xxx2/Kconfig.soc index 38525449f89..800a2a9dafd 100644 --- a/soc/riscv/riscv-ite/it8xxx2/Kconfig.soc +++ b/soc/riscv/ite_ec/it8xxx2/Kconfig.soc @@ -3,7 +3,7 @@ choice prompt "ITE IT8XXX2 system implementation" -depends on SOC_SERIES_RISCV32_IT8XXX2 +depends on SOC_SERIES_ITE_IT8XXX2 config SOC_IT8XXX2 bool "ITE IT8XXX2 system implementation" diff --git a/soc/riscv/riscv-ite/it8xxx2/__arithmetic.S b/soc/riscv/ite_ec/it8xxx2/__arithmetic.S similarity index 100% rename from soc/riscv/riscv-ite/it8xxx2/__arithmetic.S rename to soc/riscv/ite_ec/it8xxx2/__arithmetic.S diff --git a/soc/riscv/riscv-ite/it8xxx2/ilm.c b/soc/riscv/ite_ec/it8xxx2/ilm.c similarity index 100% rename from soc/riscv/riscv-ite/it8xxx2/ilm.c rename to soc/riscv/ite_ec/it8xxx2/ilm.c diff --git a/soc/riscv/riscv-ite/it8xxx2/ilm.h b/soc/riscv/ite_ec/it8xxx2/ilm.h similarity index 100% rename from soc/riscv/riscv-ite/it8xxx2/ilm.h rename to soc/riscv/ite_ec/it8xxx2/ilm.h diff --git a/soc/riscv/riscv-ite/it8xxx2/linker.ld b/soc/riscv/ite_ec/it8xxx2/linker.ld similarity index 100% rename from soc/riscv/riscv-ite/it8xxx2/linker.ld rename to soc/riscv/ite_ec/it8xxx2/linker.ld diff --git a/soc/riscv/riscv-ite/it8xxx2/soc.c b/soc/riscv/ite_ec/it8xxx2/soc.c similarity index 100% rename from soc/riscv/riscv-ite/it8xxx2/soc.c rename to soc/riscv/ite_ec/it8xxx2/soc.c diff --git a/soc/riscv/riscv-ite/it8xxx2/soc.h b/soc/riscv/ite_ec/it8xxx2/soc.h similarity index 100% rename from soc/riscv/riscv-ite/it8xxx2/soc.h rename to soc/riscv/ite_ec/it8xxx2/soc.h diff --git a/soc/riscv/riscv-ite/Kconfig b/soc/riscv/riscv-ite/Kconfig deleted file mode 100644 index f25c53d1ffb..00000000000 --- a/soc/riscv/riscv-ite/Kconfig +++ /dev/null @@ -1,14 +0,0 @@ -# Copyright (c) 2020 ITE Corporation. All Rights Reserved. -# SPDX-License-Identifier: Apache-2.0 - -config SOC_FAMILY_RISCV_ITE - bool - help - omit prompt to signify a "hidden" option - -config SOC_FAMILY - string - default "riscv-ite" - depends on SOC_FAMILY_RISCV_ITE - -source "soc/riscv/riscv-ite/*/Kconfig.soc" diff --git a/tests/drivers/gpio/gpio_ite_it8xxx2_v2/CMakeLists.txt b/tests/drivers/gpio/gpio_ite_it8xxx2_v2/CMakeLists.txt index bf01055ffc3..1079605a2b4 100644 --- a/tests/drivers/gpio/gpio_ite_it8xxx2_v2/CMakeLists.txt +++ b/tests/drivers/gpio/gpio_ite_it8xxx2_v2/CMakeLists.txt @@ -13,8 +13,8 @@ target_include_directories(app PRIVATE zephyr_include_directories( include - ${ZEPHYR_BASE}/soc/riscv/riscv-ite/common - ${ZEPHYR_BASE}/soc/riscv/riscv-ite/it8xxx2 + ${ZEPHYR_BASE}/soc/riscv/ite_ec/common + ${ZEPHYR_BASE}/soc/riscv/ite_ec/it8xxx2 ) target_sources(app diff --git a/tests/drivers/gpio/gpio_ite_it8xxx2_v2/include/chip_chipregs.h b/tests/drivers/gpio/gpio_ite_it8xxx2_v2/include/chip_chipregs.h index 3372a845aa9..d3c1f7c827e 100644 --- a/tests/drivers/gpio/gpio_ite_it8xxx2_v2/include/chip_chipregs.h +++ b/tests/drivers/gpio/gpio_ite_it8xxx2_v2/include/chip_chipregs.h @@ -4,7 +4,7 @@ * SPDX-License-Identifier: Apache-2.0 */ -#include <../soc/riscv/riscv-ite/common/chip_chipregs.h> +#include <../soc/riscv/ite_ec/common/chip_chipregs.h> /* * Macros for emulated hardware registers access. From 7a44806a53e74b7720382298afcd502dd5912782 Mon Sep 17 00:00:00 2001 From: Gerard Marull-Paretas Date: Wed, 3 Jan 2024 15:40:52 +0100 Subject: [PATCH 1887/3723] soc: riscv: s/litex-vexriscv/litex_vexriscv To be consistent with other SoCs in the same folder. Signed-off-by: Gerard Marull-Paretas --- soc/riscv/{litex-vexriscv => litex_vexriscv}/CMakeLists.txt | 0 soc/riscv/{litex-vexriscv => litex_vexriscv}/Kconfig.defconfig | 2 +- soc/riscv/{litex-vexriscv => litex_vexriscv}/Kconfig.soc | 0 soc/riscv/{litex-vexriscv => litex_vexriscv}/soc.h | 0 4 files changed, 1 insertion(+), 1 deletion(-) rename soc/riscv/{litex-vexriscv => litex_vexriscv}/CMakeLists.txt (100%) rename soc/riscv/{litex-vexriscv => litex_vexriscv}/Kconfig.defconfig (92%) rename soc/riscv/{litex-vexriscv => litex_vexriscv}/Kconfig.soc (100%) rename soc/riscv/{litex-vexriscv => litex_vexriscv}/soc.h (100%) diff --git a/soc/riscv/litex-vexriscv/CMakeLists.txt b/soc/riscv/litex_vexriscv/CMakeLists.txt similarity index 100% rename from soc/riscv/litex-vexriscv/CMakeLists.txt rename to soc/riscv/litex_vexriscv/CMakeLists.txt diff --git a/soc/riscv/litex-vexriscv/Kconfig.defconfig b/soc/riscv/litex_vexriscv/Kconfig.defconfig similarity index 92% rename from soc/riscv/litex-vexriscv/Kconfig.defconfig rename to soc/riscv/litex_vexriscv/Kconfig.defconfig index 9447948b567..3efdf200ee7 100644 --- a/soc/riscv/litex-vexriscv/Kconfig.defconfig +++ b/soc/riscv/litex_vexriscv/Kconfig.defconfig @@ -4,7 +4,7 @@ if SOC_RISCV32_LITEX_VEXRISCV config SOC - default "litex-vexriscv" + default "litex_vexriscv" config SYS_CLOCK_HW_CYCLES_PER_SEC default 100000000 diff --git a/soc/riscv/litex-vexriscv/Kconfig.soc b/soc/riscv/litex_vexriscv/Kconfig.soc similarity index 100% rename from soc/riscv/litex-vexriscv/Kconfig.soc rename to soc/riscv/litex_vexriscv/Kconfig.soc diff --git a/soc/riscv/litex-vexriscv/soc.h b/soc/riscv/litex_vexriscv/soc.h similarity index 100% rename from soc/riscv/litex-vexriscv/soc.h rename to soc/riscv/litex_vexriscv/soc.h From b7b19b8b05d23406358d721f325715fccb39f330 Mon Sep 17 00:00:00 2001 From: Gerard Marull-Paretas Date: Wed, 3 Jan 2024 15:50:51 +0100 Subject: [PATCH 1888/3723] soc: riscv: neorv32: reorganize SoC folder Move out of riscv-privileged and convert to a standalone SoC. Note that the family/series structure has been dropped in favor of a single SoC (what NEORV32 seems to be). Signed-off-by: Gerard Marull-Paretas --- boards/riscv/neorv32/Kconfig.board | 2 +- boards/riscv/neorv32/neorv32_defconfig | 2 +- .../neorv32/CMakeLists.txt | 0 .../Kconfig.defconfig} | 6 ++-- .../Kconfig.series => neorv32/Kconfig.soc} | 27 +++++++++++++++- .../{riscv-privileged => }/neorv32/linker.ld | 0 .../{riscv-privileged => }/neorv32/reset.S | 0 .../{riscv-privileged => }/neorv32/soc.c | 0 .../{riscv-privileged => }/neorv32/soc.h | 0 .../{riscv-privileged => }/neorv32/soc_irq.S | 0 .../riscv-privileged/neorv32/Kconfig.soc | 32 ------------------- 11 files changed, 31 insertions(+), 38 deletions(-) rename soc/riscv/{riscv-privileged => }/neorv32/CMakeLists.txt (100%) rename soc/riscv/{riscv-privileged/neorv32/Kconfig.defconfig.series => neorv32/Kconfig.defconfig} (88%) rename soc/riscv/{riscv-privileged/neorv32/Kconfig.series => neorv32/Kconfig.soc} (56%) rename soc/riscv/{riscv-privileged => }/neorv32/linker.ld (100%) rename soc/riscv/{riscv-privileged => }/neorv32/reset.S (100%) rename soc/riscv/{riscv-privileged => }/neorv32/soc.c (100%) rename soc/riscv/{riscv-privileged => }/neorv32/soc.h (100%) rename soc/riscv/{riscv-privileged => }/neorv32/soc_irq.S (100%) delete mode 100644 soc/riscv/riscv-privileged/neorv32/Kconfig.soc diff --git a/boards/riscv/neorv32/Kconfig.board b/boards/riscv/neorv32/Kconfig.board index eee37f4a8c3..6d85ebb2e40 100644 --- a/boards/riscv/neorv32/Kconfig.board +++ b/boards/riscv/neorv32/Kconfig.board @@ -3,4 +3,4 @@ config BOARD_NEORV32 bool "NEORV32 Processor (SoC)" - depends on SOC_SERIES_NEORV32 + depends on SOC_NEORV32 diff --git a/boards/riscv/neorv32/neorv32_defconfig b/boards/riscv/neorv32/neorv32_defconfig index 17e9b8038ce..7dc8a74ffff 100644 --- a/boards/riscv/neorv32/neorv32_defconfig +++ b/boards/riscv/neorv32/neorv32_defconfig @@ -1,7 +1,7 @@ # Copyright (c) 2021 Henrik Brix Andersen # SPDX-License-Identifier: Apache-2.0 -CONFIG_SOC_SERIES_NEORV32=y +CONFIG_SOC_NEORV32=y CONFIG_SOC_NEORV32_ISA_C=y CONFIG_BOARD_NEORV32=y CONFIG_SERIAL=y diff --git a/soc/riscv/riscv-privileged/neorv32/CMakeLists.txt b/soc/riscv/neorv32/CMakeLists.txt similarity index 100% rename from soc/riscv/riscv-privileged/neorv32/CMakeLists.txt rename to soc/riscv/neorv32/CMakeLists.txt diff --git a/soc/riscv/riscv-privileged/neorv32/Kconfig.defconfig.series b/soc/riscv/neorv32/Kconfig.defconfig similarity index 88% rename from soc/riscv/riscv-privileged/neorv32/Kconfig.defconfig.series rename to soc/riscv/neorv32/Kconfig.defconfig index 11bd7ef7d33..86aed551f5d 100644 --- a/soc/riscv/riscv-privileged/neorv32/Kconfig.defconfig.series +++ b/soc/riscv/neorv32/Kconfig.defconfig @@ -1,9 +1,9 @@ # Copyright (c) 2021 Henrik Brix Andersen # SPDX-License-Identifier: Apache-2.0 -if SOC_SERIES_NEORV32 +if SOC_NEORV32 -config SOC_SERIES +config SOC default "neorv32" config SYS_CLOCK_HW_CYCLES_PER_SEC @@ -29,4 +29,4 @@ config ENTROPY_INIT_PRIORITY default 55 depends on ENTROPY_GENERATOR -endif # SOC_SERIES_NEORV32 +endif # SOC_NEORV32 diff --git a/soc/riscv/riscv-privileged/neorv32/Kconfig.series b/soc/riscv/neorv32/Kconfig.soc similarity index 56% rename from soc/riscv/riscv-privileged/neorv32/Kconfig.series rename to soc/riscv/neorv32/Kconfig.soc index 0f8f9ca8fd4..f07bba96574 100644 --- a/soc/riscv/riscv-privileged/neorv32/Kconfig.series +++ b/soc/riscv/neorv32/Kconfig.soc @@ -1,7 +1,7 @@ # Copyright (c) 2021 Henrik Brix Andersen # SPDX-License-Identifier: Apache-2.0 -config SOC_SERIES_NEORV32 +config SOC_NEORV32 bool "NEORV32 Processor" select RISCV select RISCV_ISA_RV32I @@ -10,6 +10,7 @@ config SOC_SERIES_NEORV32 select RISCV_ISA_EXT_ZICSR select RISCV_ISA_EXT_ZIFENCEI select RISCV_PRIVILEGED + select RISCV_PRIVILEGED_STANDALONE help Enable support for the NEORV32 Processor (SoC). @@ -24,3 +25,27 @@ config SOC_SERIES_NEORV32 - E (Embedded, only 16 integer registers) - Zbb (Basic Bit Manipulation) - Zfinx (Floating Point in Integer Registers) + +if SOC_NEORV32 + +config SOC_NEORV32_V1_8_6 + bool "v1.8.6" + # NEORV32 RISC-V ISA A extension implements only LR/SC, not AMO + select ATOMIC_OPERATIONS_C + +config SOC_NEORV32_VERSION + hex + default 0x01080600 if SOC_NEORV32_V1_8_6 + help + The targeted NEORV32 version as BCD-coded number. The format is + identical to that of the NEORV32 Machine implementation ID (mimpid) + register. + +config SOC_NEORV32_ISA_C + bool "RISC-V ISA Extension \"C\"" + select RISCV_ISA_EXT_C + help + Enable this if the NEORV32 CPU implementation supports the RISC-V ISA + "C" extension (Compressed Instructions). + +endif # SOC_NEORV32 diff --git a/soc/riscv/riscv-privileged/neorv32/linker.ld b/soc/riscv/neorv32/linker.ld similarity index 100% rename from soc/riscv/riscv-privileged/neorv32/linker.ld rename to soc/riscv/neorv32/linker.ld diff --git a/soc/riscv/riscv-privileged/neorv32/reset.S b/soc/riscv/neorv32/reset.S similarity index 100% rename from soc/riscv/riscv-privileged/neorv32/reset.S rename to soc/riscv/neorv32/reset.S diff --git a/soc/riscv/riscv-privileged/neorv32/soc.c b/soc/riscv/neorv32/soc.c similarity index 100% rename from soc/riscv/riscv-privileged/neorv32/soc.c rename to soc/riscv/neorv32/soc.c diff --git a/soc/riscv/riscv-privileged/neorv32/soc.h b/soc/riscv/neorv32/soc.h similarity index 100% rename from soc/riscv/riscv-privileged/neorv32/soc.h rename to soc/riscv/neorv32/soc.h diff --git a/soc/riscv/riscv-privileged/neorv32/soc_irq.S b/soc/riscv/neorv32/soc_irq.S similarity index 100% rename from soc/riscv/riscv-privileged/neorv32/soc_irq.S rename to soc/riscv/neorv32/soc_irq.S diff --git a/soc/riscv/riscv-privileged/neorv32/Kconfig.soc b/soc/riscv/riscv-privileged/neorv32/Kconfig.soc deleted file mode 100644 index 93c9da8cc3d..00000000000 --- a/soc/riscv/riscv-privileged/neorv32/Kconfig.soc +++ /dev/null @@ -1,32 +0,0 @@ -# Copyright (c) 2021 Henrik Brix Andersen -# SPDX-License-Identifier: Apache-2.0 - -choice - prompt "NEORV32 Version" - depends on SOC_SERIES_NEORV32 - -config SOC_NEORV32_V1_8_6 - bool "v1.8.6" - # NEORV32 RISC-V ISA A extension implements only LR/SC, not AMO - select ATOMIC_OPERATIONS_C - -endchoice - -if SOC_SERIES_NEORV32 - -config SOC_NEORV32_VERSION - hex - default 0x01080600 if SOC_NEORV32_V1_8_6 - help - The targeted NEORV32 version as BCD-coded number. The format is - identical to that of the NEORV32 Machine implementation ID (mimpid) - register. - -config SOC_NEORV32_ISA_C - bool "RISC-V ISA Extension \"C\"" - select RISCV_ISA_EXT_C - help - Enable this if the NEORV32 CPU implementation supports the RISC-V ISA - "C" extension (Compressed Instructions). - -endif # SOC_SERIES_NEORV32 From 7da6342dff4a3ff62de02e15a8c9959bef7d46a1 Mon Sep 17 00:00:00 2001 From: Gerard Marull-Paretas Date: Wed, 3 Jan 2024 15:57:37 +0100 Subject: [PATCH 1889/3723] soc: riscv: virt: reorganize SoC folder Move out of riscv-privileged, and convert to single SoC (no family/series). Signed-off-by: Gerard Marull-Paretas --- boards/riscv/qemu_riscv32/qemu_riscv32_defconfig | 1 - boards/riscv/qemu_riscv32/qemu_riscv32_smp_defconfig | 1 - boards/riscv/qemu_riscv32e/qemu_riscv32e_defconfig | 1 - boards/riscv/qemu_riscv64/qemu_riscv64_defconfig | 1 - boards/riscv/qemu_riscv64/qemu_riscv64_smp_defconfig | 1 - soc/riscv/riscv-privileged/virt/Kconfig.series | 7 ------- soc/riscv/{riscv-privileged => }/virt/CMakeLists.txt | 0 .../Kconfig.defconfig.series => virt/Kconfig.defconfig} | 4 ++-- soc/riscv/{riscv-privileged => }/virt/Kconfig.soc | 9 +++------ soc/riscv/{riscv-privileged => }/virt/soc.c | 0 soc/riscv/{riscv-privileged => }/virt/soc.h | 0 11 files changed, 5 insertions(+), 20 deletions(-) delete mode 100644 soc/riscv/riscv-privileged/virt/Kconfig.series rename soc/riscv/{riscv-privileged => }/virt/CMakeLists.txt (100%) rename soc/riscv/{riscv-privileged/virt/Kconfig.defconfig.series => virt/Kconfig.defconfig} (91%) rename soc/riscv/{riscv-privileged => }/virt/Kconfig.soc (75%) rename soc/riscv/{riscv-privileged => }/virt/soc.c (100%) rename soc/riscv/{riscv-privileged => }/virt/soc.h (100%) diff --git a/boards/riscv/qemu_riscv32/qemu_riscv32_defconfig b/boards/riscv/qemu_riscv32/qemu_riscv32_defconfig index f50d82dcb76..946e679a6e8 100644 --- a/boards/riscv/qemu_riscv32/qemu_riscv32_defconfig +++ b/boards/riscv/qemu_riscv32/qemu_riscv32_defconfig @@ -1,6 +1,5 @@ # SPDX-License-Identifier: Apache-2.0 -CONFIG_SOC_SERIES_RISCV_VIRT=y CONFIG_SOC_RISCV_VIRT=y CONFIG_BOARD_QEMU_RISCV32=y CONFIG_CONSOLE=y diff --git a/boards/riscv/qemu_riscv32/qemu_riscv32_smp_defconfig b/boards/riscv/qemu_riscv32/qemu_riscv32_smp_defconfig index eef7d03e356..90f87ef6b98 100644 --- a/boards/riscv/qemu_riscv32/qemu_riscv32_smp_defconfig +++ b/boards/riscv/qemu_riscv32/qemu_riscv32_smp_defconfig @@ -1,6 +1,5 @@ # SPDX-License-Identifier: Apache-2.0 -CONFIG_SOC_SERIES_RISCV_VIRT=y CONFIG_SOC_RISCV_VIRT=y CONFIG_BOARD_QEMU_RISCV32_SMP=y CONFIG_CONSOLE=y diff --git a/boards/riscv/qemu_riscv32e/qemu_riscv32e_defconfig b/boards/riscv/qemu_riscv32e/qemu_riscv32e_defconfig index ef4d6273cfb..1f1c46acb10 100644 --- a/boards/riscv/qemu_riscv32e/qemu_riscv32e_defconfig +++ b/boards/riscv/qemu_riscv32e/qemu_riscv32e_defconfig @@ -1,6 +1,5 @@ # SPDX-License-Identifier: Apache-2.0 -CONFIG_SOC_SERIES_RISCV_VIRT=y CONFIG_SOC_RISCV_VIRT=y CONFIG_BOARD_QEMU_RISCV32E=y CONFIG_CONSOLE=y diff --git a/boards/riscv/qemu_riscv64/qemu_riscv64_defconfig b/boards/riscv/qemu_riscv64/qemu_riscv64_defconfig index 6f51da3c592..6bfc46ac907 100644 --- a/boards/riscv/qemu_riscv64/qemu_riscv64_defconfig +++ b/boards/riscv/qemu_riscv64/qemu_riscv64_defconfig @@ -1,6 +1,5 @@ # SPDX-License-Identifier: Apache-2.0 -CONFIG_SOC_SERIES_RISCV_VIRT=y CONFIG_SOC_RISCV_VIRT=y CONFIG_BOARD_QEMU_RISCV64=y CONFIG_PRIVILEGED_STACK_SIZE=2048 diff --git a/boards/riscv/qemu_riscv64/qemu_riscv64_smp_defconfig b/boards/riscv/qemu_riscv64/qemu_riscv64_smp_defconfig index 78b5b74de9a..265d84a1ded 100644 --- a/boards/riscv/qemu_riscv64/qemu_riscv64_smp_defconfig +++ b/boards/riscv/qemu_riscv64/qemu_riscv64_smp_defconfig @@ -1,6 +1,5 @@ # SPDX-License-Identifier: Apache-2.0 -CONFIG_SOC_SERIES_RISCV_VIRT=y CONFIG_SOC_RISCV_VIRT=y CONFIG_BOARD_QEMU_RISCV64_SMP=y CONFIG_PRIVILEGED_STACK_SIZE=2048 diff --git a/soc/riscv/riscv-privileged/virt/Kconfig.series b/soc/riscv/riscv-privileged/virt/Kconfig.series deleted file mode 100644 index 44ec681a308..00000000000 --- a/soc/riscv/riscv-privileged/virt/Kconfig.series +++ /dev/null @@ -1,7 +0,0 @@ -# Copyright (c) 2020 Cobham Gaisler AB -# SPDX-License-Identifier: Apache-2.0 - -config SOC_SERIES_RISCV_VIRT - bool "QEMU RISC-V VirtIO Board" - select RISCV - select RISCV_PRIVILEGED diff --git a/soc/riscv/riscv-privileged/virt/CMakeLists.txt b/soc/riscv/virt/CMakeLists.txt similarity index 100% rename from soc/riscv/riscv-privileged/virt/CMakeLists.txt rename to soc/riscv/virt/CMakeLists.txt diff --git a/soc/riscv/riscv-privileged/virt/Kconfig.defconfig.series b/soc/riscv/virt/Kconfig.defconfig similarity index 91% rename from soc/riscv/riscv-privileged/virt/Kconfig.defconfig.series rename to soc/riscv/virt/Kconfig.defconfig index 231d4519d67..9773586e922 100644 --- a/soc/riscv/riscv-privileged/virt/Kconfig.defconfig.series +++ b/soc/riscv/virt/Kconfig.defconfig @@ -1,9 +1,9 @@ # Copyright (c) 2020 Cobham Gaisler AB # SPDX-License-Identifier: Apache-2.0 -if SOC_SERIES_RISCV_VIRT +if SOC_RISCV_VIRT -config SOC_SERIES +config SOC default "virt" config SYS_CLOCK_HW_CYCLES_PER_SEC diff --git a/soc/riscv/riscv-privileged/virt/Kconfig.soc b/soc/riscv/virt/Kconfig.soc similarity index 75% rename from soc/riscv/riscv-privileged/virt/Kconfig.soc rename to soc/riscv/virt/Kconfig.soc index 35a2853eb50..fb615005b0a 100644 --- a/soc/riscv/riscv-privileged/virt/Kconfig.soc +++ b/soc/riscv/virt/Kconfig.soc @@ -1,10 +1,6 @@ # Copyright (c) 2020 Cobham Gaisler AB # SPDX-License-Identifier: Apache-2.0 -choice - prompt "QEMU RISC-V VirtIO Board" - depends on SOC_SERIES_RISCV_VIRT - config SOC_RISCV_VIRT bool "QEMU RISC-V VirtIO Board" select ATOMIC_OPERATIONS_BUILTIN @@ -12,5 +8,6 @@ config SOC_RISCV_VIRT select RISCV_ISA_EXT_M select RISCV_ISA_EXT_A select RISCV_ISA_EXT_C - -endchoice + select RISCV + select RISCV_PRIVILEGED + select RISCV_PRIVILEGED_STANDALONE diff --git a/soc/riscv/riscv-privileged/virt/soc.c b/soc/riscv/virt/soc.c similarity index 100% rename from soc/riscv/riscv-privileged/virt/soc.c rename to soc/riscv/virt/soc.c diff --git a/soc/riscv/riscv-privileged/virt/soc.h b/soc/riscv/virt/soc.h similarity index 100% rename from soc/riscv/riscv-privileged/virt/soc.h rename to soc/riscv/virt/soc.h From 4c4beabecc3cb4eb80aae32e590a2fe21c84bd6a Mon Sep 17 00:00:00 2001 From: Gerard Marull-Paretas Date: Wed, 3 Jan 2024 16:04:26 +0100 Subject: [PATCH 1890/3723] soc: riscv: efinix-sapphire: reorganize SoC folder Move things out from riscv-privileged, and convert to single SoC. Signed-off-by: Gerard Marull-Paretas --- boards/riscv/titanium_ti60_f225/Kconfig.board | 2 +- .../titanium_ti60_f225/titanium_ti60_f225_defconfig | 2 +- .../CMakeLists.txt | 0 .../Kconfig.defconfig} | 8 ++++---- .../efinix-sapphire => efinix_sapphire}/Kconfig.soc | 11 ++++------- .../efinix-sapphire => efinix_sapphire}/soc.h | 0 .../riscv-privileged/efinix-sapphire/Kconfig.series | 9 --------- 7 files changed, 10 insertions(+), 22 deletions(-) rename soc/riscv/{riscv-privileged/efinix-sapphire => efinix_sapphire}/CMakeLists.txt (100%) rename soc/riscv/{riscv-privileged/efinix-sapphire/Kconfig.defconfig.series => efinix_sapphire/Kconfig.defconfig} (75%) rename soc/riscv/{riscv-privileged/efinix-sapphire => efinix_sapphire}/Kconfig.soc (72%) rename soc/riscv/{riscv-privileged/efinix-sapphire => efinix_sapphire}/soc.h (100%) delete mode 100644 soc/riscv/riscv-privileged/efinix-sapphire/Kconfig.series diff --git a/boards/riscv/titanium_ti60_f225/Kconfig.board b/boards/riscv/titanium_ti60_f225/Kconfig.board index d6ed41ffc79..bac70816b20 100644 --- a/boards/riscv/titanium_ti60_f225/Kconfig.board +++ b/boards/riscv/titanium_ti60_f225/Kconfig.board @@ -3,4 +3,4 @@ config BOARD_TITANIUM_TI60_F225 bool "Board with Efinix Sapphire riscv SoC" - depends on SOC_SERIES_EFINIX_SAPPHIRE + depends on SOC_EFINIX_SAPPHIRE diff --git a/boards/riscv/titanium_ti60_f225/titanium_ti60_f225_defconfig b/boards/riscv/titanium_ti60_f225/titanium_ti60_f225_defconfig index 096980b864e..0608a8e8953 100644 --- a/boards/riscv/titanium_ti60_f225/titanium_ti60_f225_defconfig +++ b/boards/riscv/titanium_ti60_f225/titanium_ti60_f225_defconfig @@ -1,7 +1,7 @@ # Copyright (c) 2023 Efinix Inc. # SPDX-License-Identifier: Apache-2.0 -CONFIG_SOC_SERIES_EFINIX_SAPPHIRE=y +CONFIG_SOC_EFINIX_SAPPHIRE=y CONFIG_BOARD_TITANIUM_TI60_F225=y CONFIG_CONSOLE=y CONFIG_SERIAL=y diff --git a/soc/riscv/riscv-privileged/efinix-sapphire/CMakeLists.txt b/soc/riscv/efinix_sapphire/CMakeLists.txt similarity index 100% rename from soc/riscv/riscv-privileged/efinix-sapphire/CMakeLists.txt rename to soc/riscv/efinix_sapphire/CMakeLists.txt diff --git a/soc/riscv/riscv-privileged/efinix-sapphire/Kconfig.defconfig.series b/soc/riscv/efinix_sapphire/Kconfig.defconfig similarity index 75% rename from soc/riscv/riscv-privileged/efinix-sapphire/Kconfig.defconfig.series rename to soc/riscv/efinix_sapphire/Kconfig.defconfig index e2f31e91a7b..7018c0f11fb 100644 --- a/soc/riscv/riscv-privileged/efinix-sapphire/Kconfig.defconfig.series +++ b/soc/riscv/efinix_sapphire/Kconfig.defconfig @@ -1,10 +1,10 @@ # Copyright (c) 2023 Efinix Inc. # SPDX-License-Identifier: Apache-2.0 -if SOC_SERIES_EFINIX_SAPPHIRE +if SOC_EFINIX_SAPPHIRE -config SOC_SERIES - default "efinix-sapphire" +config SOC + default "efinix_sapphire" config SYS_CLOCK_HW_CYCLES_PER_SEC default 100000000 @@ -28,4 +28,4 @@ config NUM_IRQS config 2ND_LVL_INTR_00_OFFSET default 11 -endif # SOC_SERIES_EFINIX_SAPPHIRE +endif # SOC_EFINIX_SAPPHIRE diff --git a/soc/riscv/riscv-privileged/efinix-sapphire/Kconfig.soc b/soc/riscv/efinix_sapphire/Kconfig.soc similarity index 72% rename from soc/riscv/riscv-privileged/efinix-sapphire/Kconfig.soc rename to soc/riscv/efinix_sapphire/Kconfig.soc index dba8491b8bd..2cc5f3ba361 100644 --- a/soc/riscv/riscv-privileged/efinix-sapphire/Kconfig.soc +++ b/soc/riscv/efinix_sapphire/Kconfig.soc @@ -1,11 +1,7 @@ # Copyright (c) 2023 Efinix Inc. # SPDX-License-Identifier: Apache-2.0 -choice - prompt "Efinix SoC selection" - depends on SOC_SERIES_EFINIX_SAPPHIRE - -config SOC_RISCV32_EFINIX_SAPPHIRE +config SOC_EFINIX_SAPPHIRE bool "Efinix Sapphire VexRiscv system implementation" select ATOMIC_OPERATIONS_BUILTIN select INCLUDE_RESET_VECTOR @@ -14,5 +10,6 @@ config SOC_RISCV32_EFINIX_SAPPHIRE select RISCV_ISA_EXT_A select RISCV_ISA_EXT_ZICSR select RISCV_ISA_EXT_ZIFENCEI - -endchoice + select RISCV + select RISCV_PRIVILEGED + select RISCV_PRIVILEGED_STANDALONE diff --git a/soc/riscv/riscv-privileged/efinix-sapphire/soc.h b/soc/riscv/efinix_sapphire/soc.h similarity index 100% rename from soc/riscv/riscv-privileged/efinix-sapphire/soc.h rename to soc/riscv/efinix_sapphire/soc.h diff --git a/soc/riscv/riscv-privileged/efinix-sapphire/Kconfig.series b/soc/riscv/riscv-privileged/efinix-sapphire/Kconfig.series deleted file mode 100644 index 421d81a7e33..00000000000 --- a/soc/riscv/riscv-privileged/efinix-sapphire/Kconfig.series +++ /dev/null @@ -1,9 +0,0 @@ -# Copyright (c) 2023 Efinix Inc. -# SPDX-License-Identifier: Apache-2.0 - -config SOC_SERIES_EFINIX_SAPPHIRE - bool "Efinix Sapphire SOC implementation" - select RISCV - select RISCV_PRIVILEGED - help - Enable support for Efinix Sapphire SOC implementation From b2b86556a7a381d6f776f1a682ac2b347b20acf9 Mon Sep 17 00:00:00 2001 From: Gerard Marull-Paretas Date: Wed, 3 Jan 2024 16:43:52 +0100 Subject: [PATCH 1891/3723] soc: riscv: miv/mpfs: reorganize SoC folder Merge both series into a new family: microchip_miv [1], moving them out of riscv-privileged. Updated naming to stay closer to what vendor announces on their website. [1]: https://www.microchip.com/en-us/products/fpgas-and-plds/ fpga-and-soc-design-tools/mi-v Signed-off-by: Gerard Marull-Paretas --- boards/riscv/beaglev_fire/Kconfig.board | 2 +- boards/riscv/beaglev_fire/beaglev_fire_defconfig | 4 ++-- boards/riscv/m2gl025_miv/Kconfig.board | 2 +- boards/riscv/m2gl025_miv/m2gl025_miv_defconfig | 4 ++-- boards/riscv/mpfs_icicle/Kconfig.board | 2 +- boards/riscv/mpfs_icicle/mpfs_icicle_defconfig | 4 ++-- soc/riscv/microchip_miv/CMakeLists.txt | 4 ++++ soc/riscv/microchip_miv/Kconfig | 15 +++++++++++++++ soc/riscv/microchip_miv/Kconfig.defconfig | 4 ++++ soc/riscv/microchip_miv/Kconfig.soc | 4 ++++ .../miv/CMakeLists.txt | 0 .../miv/Kconfig.defconfig.series | 4 ++-- .../miv/Kconfig.series | 4 +++- .../miv/Kconfig.soc | 4 ++-- .../{riscv-privileged => microchip_miv}/miv/soc.h | 0 .../polarfire}/CMakeLists.txt | 0 .../polarfire}/Kconfig.defconfig.series | 6 +++--- .../polarfire}/Kconfig.series | 4 +++- .../mpfs => microchip_miv/polarfire}/Kconfig.soc | 6 +++--- .../mpfs => microchip_miv/polarfire}/soc.h | 0 20 files changed, 52 insertions(+), 21 deletions(-) create mode 100644 soc/riscv/microchip_miv/CMakeLists.txt create mode 100644 soc/riscv/microchip_miv/Kconfig create mode 100644 soc/riscv/microchip_miv/Kconfig.defconfig create mode 100644 soc/riscv/microchip_miv/Kconfig.soc rename soc/riscv/{riscv-privileged => microchip_miv}/miv/CMakeLists.txt (100%) rename soc/riscv/{riscv-privileged => microchip_miv}/miv/Kconfig.defconfig.series (88%) rename soc/riscv/{riscv-privileged => microchip_miv}/miv/Kconfig.series (72%) rename soc/riscv/{riscv-privileged => microchip_miv}/miv/Kconfig.soc (88%) rename soc/riscv/{riscv-privileged => microchip_miv}/miv/soc.h (100%) rename soc/riscv/{riscv-privileged/mpfs => microchip_miv/polarfire}/CMakeLists.txt (100%) rename soc/riscv/{riscv-privileged/mpfs => microchip_miv/polarfire}/Kconfig.defconfig.series (88%) rename soc/riscv/{riscv-privileged/mpfs => microchip_miv/polarfire}/Kconfig.series (71%) rename soc/riscv/{riscv-privileged/mpfs => microchip_miv/polarfire}/Kconfig.soc (89%) rename soc/riscv/{riscv-privileged/mpfs => microchip_miv/polarfire}/soc.h (100%) diff --git a/boards/riscv/beaglev_fire/Kconfig.board b/boards/riscv/beaglev_fire/Kconfig.board index 1984bb05c09..55b59d4ac92 100644 --- a/boards/riscv/beaglev_fire/Kconfig.board +++ b/boards/riscv/beaglev_fire/Kconfig.board @@ -3,7 +3,7 @@ config BOARD_BEAGLEV_FIRE bool "Beagleboard BeagleV-Fire" - depends on SOC_MPFS + depends on SOC_POLARFIRE select 64BIT select SCHED_IPI_SUPPORTED select CPU_HAS_FPU_DOUBLE_PRECISION diff --git a/boards/riscv/beaglev_fire/beaglev_fire_defconfig b/boards/riscv/beaglev_fire/beaglev_fire_defconfig index a60ed8c1691..3b264d6c288 100644 --- a/boards/riscv/beaglev_fire/beaglev_fire_defconfig +++ b/boards/riscv/beaglev_fire/beaglev_fire_defconfig @@ -1,8 +1,8 @@ # Copyright (c) 2023 Microchip Technology Inc # SPDX-License-Identifier: Apache-2.0 -CONFIG_SOC_SERIES_RISCV64_MIV=y -CONFIG_SOC_MPFS=y +CONFIG_SOC_SERIES_POLARFIRE=y +CONFIG_SOC_POLARFIRE=y CONFIG_MPFS_HAL=n CONFIG_BASE64=y CONFIG_INCLUDE_RESET_VECTOR=y diff --git a/boards/riscv/m2gl025_miv/Kconfig.board b/boards/riscv/m2gl025_miv/Kconfig.board index 51c2f9d8de3..9f81fad406f 100644 --- a/boards/riscv/m2gl025_miv/Kconfig.board +++ b/boards/riscv/m2gl025_miv/Kconfig.board @@ -2,4 +2,4 @@ config BOARD_M2GL025_MIV bool "Microchip M2GL025 IGLOO2 dev board with Mi-V CPU" - depends on SOC_RISCV32_MIV + depends on SOC_MIV diff --git a/boards/riscv/m2gl025_miv/m2gl025_miv_defconfig b/boards/riscv/m2gl025_miv/m2gl025_miv_defconfig index 8c944a10a74..e33765680d5 100644 --- a/boards/riscv/m2gl025_miv/m2gl025_miv_defconfig +++ b/boards/riscv/m2gl025_miv/m2gl025_miv_defconfig @@ -1,7 +1,7 @@ # SPDX-License-Identifier: Apache-2.0 -CONFIG_SOC_SERIES_RISCV32_MIV=y -CONFIG_SOC_RISCV32_MIV=y +CONFIG_SOC_SERIES_MIV=y +CONFIG_SOC_MIV=y CONFIG_BOARD_M2GL025_MIV=y CONFIG_CONSOLE=y CONFIG_SERIAL=y diff --git a/boards/riscv/mpfs_icicle/Kconfig.board b/boards/riscv/mpfs_icicle/Kconfig.board index 297f4ce4bc7..e772b82d7f5 100644 --- a/boards/riscv/mpfs_icicle/Kconfig.board +++ b/boards/riscv/mpfs_icicle/Kconfig.board @@ -3,7 +3,7 @@ config BOARD_MPFS_ICICLE bool "Microchip PolarFire SoC ICICLE kit" - depends on SOC_MPFS + depends on SOC_POLARFIRE select 64BIT select SCHED_IPI_SUPPORTED select CPU_HAS_FPU_DOUBLE_PRECISION diff --git a/boards/riscv/mpfs_icicle/mpfs_icicle_defconfig b/boards/riscv/mpfs_icicle/mpfs_icicle_defconfig index 5c41649cb3e..00b44f7a6d5 100644 --- a/boards/riscv/mpfs_icicle/mpfs_icicle_defconfig +++ b/boards/riscv/mpfs_icicle/mpfs_icicle_defconfig @@ -1,8 +1,8 @@ # Copyright (c) 2020-2021 Microchip Technology Inc # SPDX-License-Identifier: Apache-2.0 -CONFIG_SOC_SERIES_RISCV64_MIV=y -CONFIG_SOC_MPFS=y +CONFIG_SOC_SERIES_POLARFIRE=y +CONFIG_SOC_POLARFIRE=y CONFIG_MPFS_HAL=n CONFIG_BASE64=y CONFIG_INCLUDE_RESET_VECTOR=y diff --git a/soc/riscv/microchip_miv/CMakeLists.txt b/soc/riscv/microchip_miv/CMakeLists.txt new file mode 100644 index 00000000000..69b2926358e --- /dev/null +++ b/soc/riscv/microchip_miv/CMakeLists.txt @@ -0,0 +1,4 @@ +# Copyright (c) 2024 Nordic Semiconductor +# SPDX-License-Identifier: Apache-2.0 + +add_subdirectory(${SOC_SERIES}) diff --git a/soc/riscv/microchip_miv/Kconfig b/soc/riscv/microchip_miv/Kconfig new file mode 100644 index 00000000000..46616636aa1 --- /dev/null +++ b/soc/riscv/microchip_miv/Kconfig @@ -0,0 +1,15 @@ +# Copyright (c) 2024 Nordic Semiconductor ASA +# SPDX-License-Identifier: Apache-2.0 + +config SOC_FAMILY_MICROCHIP_MIV + bool + +if SOC_FAMILY_MICROCHIP_MIV + +config SOC_FAMILY + string + default "microchip_miv" + +source "soc/riscv/microchip_miv/*/Kconfig.soc" + +endif # SOC_FAMILY_MICROCHIP_MIV diff --git a/soc/riscv/microchip_miv/Kconfig.defconfig b/soc/riscv/microchip_miv/Kconfig.defconfig new file mode 100644 index 00000000000..2fe508bddba --- /dev/null +++ b/soc/riscv/microchip_miv/Kconfig.defconfig @@ -0,0 +1,4 @@ +# Copyright (c) 2024 Nordic Semiconductor ASA +# SPDX-License-Identifier: Apache-2.0 + +source "soc/riscv/microchip_miv/*/Kconfig.defconfig.series" diff --git a/soc/riscv/microchip_miv/Kconfig.soc b/soc/riscv/microchip_miv/Kconfig.soc new file mode 100644 index 00000000000..8677f1ba448 --- /dev/null +++ b/soc/riscv/microchip_miv/Kconfig.soc @@ -0,0 +1,4 @@ +# Copyright (c) 2024 Nordic Semiconductor ASA +# SPDX-License-Identifier: Apache-2.0 + +source "soc/riscv/microchip_miv/*/Kconfig.series" diff --git a/soc/riscv/riscv-privileged/miv/CMakeLists.txt b/soc/riscv/microchip_miv/miv/CMakeLists.txt similarity index 100% rename from soc/riscv/riscv-privileged/miv/CMakeLists.txt rename to soc/riscv/microchip_miv/miv/CMakeLists.txt diff --git a/soc/riscv/riscv-privileged/miv/Kconfig.defconfig.series b/soc/riscv/microchip_miv/miv/Kconfig.defconfig.series similarity index 88% rename from soc/riscv/riscv-privileged/miv/Kconfig.defconfig.series rename to soc/riscv/microchip_miv/miv/Kconfig.defconfig.series index 81b224ed397..ef161321a5b 100644 --- a/soc/riscv/riscv-privileged/miv/Kconfig.defconfig.series +++ b/soc/riscv/microchip_miv/miv/Kconfig.defconfig.series @@ -1,6 +1,6 @@ # SPDX-License-Identifier: Apache-2.0 -if SOC_SERIES_RISCV32_MIV +if SOC_SERIES_MIV config SOC_SERIES default "miv" @@ -32,4 +32,4 @@ config MAX_IRQ_PER_AGGREGATOR config NUM_IRQS default 42 -endif # SOC_SERIES_RISCV32_MIV +endif # SOC_SERIES_MIV diff --git a/soc/riscv/riscv-privileged/miv/Kconfig.series b/soc/riscv/microchip_miv/miv/Kconfig.series similarity index 72% rename from soc/riscv/riscv-privileged/miv/Kconfig.series rename to soc/riscv/microchip_miv/miv/Kconfig.series index 017de686a94..20430e6d0f9 100644 --- a/soc/riscv/riscv-privileged/miv/Kconfig.series +++ b/soc/riscv/microchip_miv/miv/Kconfig.series @@ -3,9 +3,11 @@ # Copyright (c) 2018 Antmicro # SPDX-License-Identifier: Apache-2.0 -config SOC_SERIES_RISCV32_MIV +config SOC_SERIES_MIV bool "Microchip Mi-V implementation" + select SOC_FAMILY_MICROCHIP_MIV select RISCV select RISCV_PRIVILEGED + select RISCV_PRIVILEGED_STANDALONE help Enable support for Microchip Mi-V diff --git a/soc/riscv/riscv-privileged/miv/Kconfig.soc b/soc/riscv/microchip_miv/miv/Kconfig.soc similarity index 88% rename from soc/riscv/riscv-privileged/miv/Kconfig.soc rename to soc/riscv/microchip_miv/miv/Kconfig.soc index 189abb6879c..0a48c2e0524 100644 --- a/soc/riscv/riscv-privileged/miv/Kconfig.soc +++ b/soc/riscv/microchip_miv/miv/Kconfig.soc @@ -5,9 +5,9 @@ choice prompt "Microchip Mi-V system implementation" - depends on SOC_SERIES_RISCV32_MIV + depends on SOC_SERIES_MIV -config SOC_RISCV32_MIV +config SOC_MIV bool "Microchip Mi-V system implementation" select ATOMIC_OPERATIONS_BUILTIN select INCLUDE_RESET_VECTOR diff --git a/soc/riscv/riscv-privileged/miv/soc.h b/soc/riscv/microchip_miv/miv/soc.h similarity index 100% rename from soc/riscv/riscv-privileged/miv/soc.h rename to soc/riscv/microchip_miv/miv/soc.h diff --git a/soc/riscv/riscv-privileged/mpfs/CMakeLists.txt b/soc/riscv/microchip_miv/polarfire/CMakeLists.txt similarity index 100% rename from soc/riscv/riscv-privileged/mpfs/CMakeLists.txt rename to soc/riscv/microchip_miv/polarfire/CMakeLists.txt diff --git a/soc/riscv/riscv-privileged/mpfs/Kconfig.defconfig.series b/soc/riscv/microchip_miv/polarfire/Kconfig.defconfig.series similarity index 88% rename from soc/riscv/riscv-privileged/mpfs/Kconfig.defconfig.series rename to soc/riscv/microchip_miv/polarfire/Kconfig.defconfig.series index 12f9dcaa992..e5c3a2ebce9 100644 --- a/soc/riscv/riscv-privileged/mpfs/Kconfig.defconfig.series +++ b/soc/riscv/microchip_miv/polarfire/Kconfig.defconfig.series @@ -1,10 +1,10 @@ # Copyright (c) 2020-2021 Microchip Technology Inc # SPDX-License-Identifier: Apache-2.0 -if SOC_SERIES_RISCV64_MIV +if SOC_SERIES_POLARFIRE config SOC_SERIES - default "mpfs" + default "polarfire" # MPFS should be configured so that the mtimer clock is 1MHz independent of the CPU clock... @@ -35,4 +35,4 @@ config MAX_IRQ_PER_AGGREGATOR config NUM_IRQS default 186 -endif # SOC_SERIES_RISCV64_MIV +endif # SOC_SERIES_POLARFIRE diff --git a/soc/riscv/riscv-privileged/mpfs/Kconfig.series b/soc/riscv/microchip_miv/polarfire/Kconfig.series similarity index 71% rename from soc/riscv/riscv-privileged/mpfs/Kconfig.series rename to soc/riscv/microchip_miv/polarfire/Kconfig.series index 3b30cd15365..4bbceaee745 100644 --- a/soc/riscv/riscv-privileged/mpfs/Kconfig.series +++ b/soc/riscv/microchip_miv/polarfire/Kconfig.series @@ -3,9 +3,11 @@ # Copyright (c) 2018 Antmicro # SPDX-License-Identifier: Apache-2.0 -config SOC_SERIES_RISCV64_MIV +config SOC_SERIES_POLARFIRE bool "Microchip RV64 implementation" + select SOC_FAMILY_MICROCHIP_MIV select RISCV select RISCV_PRIVILEGED + select RISCV_PRIVILEGED_STANDALONE help Enable support for Microchip RISCV 64bit diff --git a/soc/riscv/riscv-privileged/mpfs/Kconfig.soc b/soc/riscv/microchip_miv/polarfire/Kconfig.soc similarity index 89% rename from soc/riscv/riscv-privileged/mpfs/Kconfig.soc rename to soc/riscv/microchip_miv/polarfire/Kconfig.soc index 7f20dc703c2..101e8b4d029 100644 --- a/soc/riscv/riscv-privileged/mpfs/Kconfig.soc +++ b/soc/riscv/microchip_miv/polarfire/Kconfig.soc @@ -5,9 +5,9 @@ choice prompt "Microchip Polarfire SOC implementation" - depends on SOC_SERIES_RISCV64_MIV + depends on SOC_SERIES_POLARFIRE -config SOC_MPFS +config SOC_POLARFIRE bool "Microchip MPFS system implementation" select ATOMIC_OPERATIONS_BUILTIN select RISCV_GP @@ -25,6 +25,6 @@ config SOC_MPFS endchoice config MPFS_HAL - depends on SOC_MPFS + depends on SOC_POLARFIRE bool "Microchip Polarfire SOC hardware abstracton layer" select HAS_MPFS_HAL diff --git a/soc/riscv/riscv-privileged/mpfs/soc.h b/soc/riscv/microchip_miv/polarfire/soc.h similarity index 100% rename from soc/riscv/riscv-privileged/mpfs/soc.h rename to soc/riscv/microchip_miv/polarfire/soc.h From 38a44e683eaa92c642b5aaa59fe3f10a3ac28941 Mon Sep 17 00:00:00 2001 From: Gerard Marull-Paretas Date: Wed, 3 Jan 2024 17:26:25 +0100 Subject: [PATCH 1892/3723] soc: riscv: sifive-freedom: reorganize SoC folder Reorganized as follows: - Created a new SiFive Freedom family - Created 3 new series: E300/E500/E700 - Created Socs within each series (e.g. E340) Also moved out of riscv-privileged folder. Signed-off-by: Gerard Marull-Paretas --- boards/riscv/hifive1/Kconfig.board | 2 +- boards/riscv/hifive1/hifive1_defconfig | 4 +- boards/riscv/hifive1_revb/Kconfig.board | 2 +- .../riscv/hifive1_revb/hifive1_revb_defconfig | 4 +- boards/riscv/hifive_unleashed/Kconfig.board | 2 +- .../hifive_unleashed_defconfig | 4 +- boards/riscv/hifive_unmatched/Kconfig.board | 2 +- .../hifive_unmatched_defconfig | 4 +- boards/riscv/qemu_riscv32/Kconfig.board | 2 +- .../qemu_riscv32/qemu_riscv32_xip_defconfig | 4 +- .../sparkfun_red_v_things_plus/Kconfig.board | 2 +- .../sparkfun_red_v_things_plus_defconfig | 4 +- .../sifive-freedom/CMakeLists.txt | 8 ---- .../sifive-freedom/Kconfig.series | 11 ----- .../sifive-freedom/Kconfig.soc | 44 ------------------- soc/riscv/sifive_freedom/CMakeLists.txt | 5 +++ soc/riscv/sifive_freedom/Kconfig | 15 +++++++ soc/riscv/sifive_freedom/Kconfig.defconfig | 4 ++ soc/riscv/sifive_freedom/Kconfig.soc | 4 ++ .../sifive_freedom/common/CMakeLists.txt | 3 ++ .../common}/pinctrl_soc.h | 0 soc/riscv/sifive_freedom/e300/CMakeLists.txt | 5 +++ .../e300/Kconfig.defconfig.e340 | 5 +++ .../e300}/Kconfig.defconfig.series | 9 ++-- soc/riscv/sifive_freedom/e300/Kconfig.series | 13 ++++++ soc/riscv/sifive_freedom/e300/Kconfig.soc | 20 +++++++++ .../e300/clock.c} | 2 +- .../e300/prci.h} | 0 .../e300}/soc.h | 27 ++---------- soc/riscv/sifive_freedom/u500/CMakeLists.txt | 5 +++ .../u500/Kconfig.defconfig.series | 38 ++++++++++++++++ .../u500/Kconfig.defconfig.u540 | 5 +++ soc/riscv/sifive_freedom/u500/Kconfig.series | 13 ++++++ soc/riscv/sifive_freedom/u500/Kconfig.soc | 22 ++++++++++ .../u500/clock.c} | 2 +- .../u500/prci.h} | 0 soc/riscv/sifive_freedom/u500/soc.h | 32 ++++++++++++++ soc/riscv/sifive_freedom/u700/CMakeLists.txt | 5 +++ .../u700/Kconfig.defconfig.series | 38 ++++++++++++++++ .../u700/Kconfig.defconfig.u740 | 5 +++ soc/riscv/sifive_freedom/u700/Kconfig.series | 13 ++++++ soc/riscv/sifive_freedom/u700/Kconfig.soc | 22 ++++++++++ .../u700/clock.c} | 2 +- .../u700/prci.h} | 0 soc/riscv/sifive_freedom/u700/soc.h | 26 +++++++++++ 45 files changed, 328 insertions(+), 111 deletions(-) delete mode 100644 soc/riscv/riscv-privileged/sifive-freedom/CMakeLists.txt delete mode 100644 soc/riscv/riscv-privileged/sifive-freedom/Kconfig.series delete mode 100644 soc/riscv/riscv-privileged/sifive-freedom/Kconfig.soc create mode 100644 soc/riscv/sifive_freedom/CMakeLists.txt create mode 100644 soc/riscv/sifive_freedom/Kconfig create mode 100644 soc/riscv/sifive_freedom/Kconfig.defconfig create mode 100644 soc/riscv/sifive_freedom/Kconfig.soc create mode 100644 soc/riscv/sifive_freedom/common/CMakeLists.txt rename soc/riscv/{riscv-privileged/sifive-freedom => sifive_freedom/common}/pinctrl_soc.h (100%) create mode 100644 soc/riscv/sifive_freedom/e300/CMakeLists.txt create mode 100644 soc/riscv/sifive_freedom/e300/Kconfig.defconfig.e340 rename soc/riscv/{riscv-privileged/sifive-freedom => sifive_freedom/e300}/Kconfig.defconfig.series (65%) create mode 100644 soc/riscv/sifive_freedom/e300/Kconfig.series create mode 100644 soc/riscv/sifive_freedom/e300/Kconfig.soc rename soc/riscv/{riscv-privileged/sifive-freedom/fe310_clock.c => sifive_freedom/e300/clock.c} (98%) rename soc/riscv/{riscv-privileged/sifive-freedom/fe310_prci.h => sifive_freedom/e300/prci.h} (100%) rename soc/riscv/{riscv-privileged/sifive-freedom => sifive_freedom/e300}/soc.h (52%) create mode 100644 soc/riscv/sifive_freedom/u500/CMakeLists.txt create mode 100644 soc/riscv/sifive_freedom/u500/Kconfig.defconfig.series create mode 100644 soc/riscv/sifive_freedom/u500/Kconfig.defconfig.u540 create mode 100644 soc/riscv/sifive_freedom/u500/Kconfig.series create mode 100644 soc/riscv/sifive_freedom/u500/Kconfig.soc rename soc/riscv/{riscv-privileged/sifive-freedom/fu540_clock.c => sifive_freedom/u500/clock.c} (97%) rename soc/riscv/{riscv-privileged/sifive-freedom/fu540_prci.h => sifive_freedom/u500/prci.h} (100%) create mode 100644 soc/riscv/sifive_freedom/u500/soc.h create mode 100644 soc/riscv/sifive_freedom/u700/CMakeLists.txt create mode 100644 soc/riscv/sifive_freedom/u700/Kconfig.defconfig.series create mode 100644 soc/riscv/sifive_freedom/u700/Kconfig.defconfig.u740 create mode 100644 soc/riscv/sifive_freedom/u700/Kconfig.series create mode 100644 soc/riscv/sifive_freedom/u700/Kconfig.soc rename soc/riscv/{riscv-privileged/sifive-freedom/fu740_clock.c => sifive_freedom/u700/clock.c} (99%) rename soc/riscv/{riscv-privileged/sifive-freedom/fu740_prci.h => sifive_freedom/u700/prci.h} (100%) create mode 100644 soc/riscv/sifive_freedom/u700/soc.h diff --git a/boards/riscv/hifive1/Kconfig.board b/boards/riscv/hifive1/Kconfig.board index b5b32649441..d2f40472f24 100644 --- a/boards/riscv/hifive1/Kconfig.board +++ b/boards/riscv/hifive1/Kconfig.board @@ -2,4 +2,4 @@ config BOARD_HIFIVE1 bool "HiFive1 target" - depends on SOC_RISCV_SIFIVE_FREEDOM + depends on SOC_SIFIVE_FREEDOM_E340 diff --git a/boards/riscv/hifive1/hifive1_defconfig b/boards/riscv/hifive1/hifive1_defconfig index d37ded2bb25..8e4e8e21c1a 100644 --- a/boards/riscv/hifive1/hifive1_defconfig +++ b/boards/riscv/hifive1/hifive1_defconfig @@ -1,7 +1,7 @@ # SPDX-License-Identifier: Apache-2.0 -CONFIG_SOC_SERIES_RISCV_SIFIVE_FREEDOM=y -CONFIG_SOC_RISCV_SIFIVE_FREEDOM=y +CONFIG_SOC_SERIES_SIFIVE_FREEDOM_E300=y +CONFIG_SOC_SIFIVE_FREEDOM_E340=y CONFIG_BOARD_HIFIVE1=y CONFIG_CONSOLE=y CONFIG_SERIAL=y diff --git a/boards/riscv/hifive1_revb/Kconfig.board b/boards/riscv/hifive1_revb/Kconfig.board index d4c5b99ce72..b0bf1edd156 100644 --- a/boards/riscv/hifive1_revb/Kconfig.board +++ b/boards/riscv/hifive1_revb/Kconfig.board @@ -3,4 +3,4 @@ config BOARD_HIFIVE1_REVB bool "HiFive1 Rev B target" - depends on SOC_RISCV_SIFIVE_FREEDOM + depends on SOC_SIFIVE_FREEDOM_E340 diff --git a/boards/riscv/hifive1_revb/hifive1_revb_defconfig b/boards/riscv/hifive1_revb/hifive1_revb_defconfig index 4f691bd9435..b2119eecae9 100644 --- a/boards/riscv/hifive1_revb/hifive1_revb_defconfig +++ b/boards/riscv/hifive1_revb/hifive1_revb_defconfig @@ -1,5 +1,5 @@ -CONFIG_SOC_SERIES_RISCV_SIFIVE_FREEDOM=y -CONFIG_SOC_RISCV_SIFIVE_FREEDOM=y +CONFIG_SOC_SERIES_SIFIVE_FREEDOM_E300=y +CONFIG_SOC_SIFIVE_FREEDOM_E340=y CONFIG_BOARD_HIFIVE1_REVB=y CONFIG_GPIO=y CONFIG_PINCTRL=y diff --git a/boards/riscv/hifive_unleashed/Kconfig.board b/boards/riscv/hifive_unleashed/Kconfig.board index 4766e0ea792..f6c623e9928 100644 --- a/boards/riscv/hifive_unleashed/Kconfig.board +++ b/boards/riscv/hifive_unleashed/Kconfig.board @@ -3,4 +3,4 @@ config BOARD_HIFIVE_UNLEASHED bool "HiFive Unleashed target" - depends on SOC_RISCV_SIFIVE_FU540 + depends on SOC_SIFIVE_FREEDOM_U540 diff --git a/boards/riscv/hifive_unleashed/hifive_unleashed_defconfig b/boards/riscv/hifive_unleashed/hifive_unleashed_defconfig index 15c9e60d552..51d324d457d 100644 --- a/boards/riscv/hifive_unleashed/hifive_unleashed_defconfig +++ b/boards/riscv/hifive_unleashed/hifive_unleashed_defconfig @@ -1,5 +1,5 @@ -CONFIG_SOC_SERIES_RISCV_SIFIVE_FREEDOM=y -CONFIG_SOC_RISCV_SIFIVE_FU540=y +CONFIG_SOC_SERIES_SIFIVE_FREEDOM_U500=y +CONFIG_SOC_SIFIVE_FREEDOM_U540=y CONFIG_BOARD_HIFIVE_UNLEASHED=y CONFIG_CONSOLE=y CONFIG_GPIO=y diff --git a/boards/riscv/hifive_unmatched/Kconfig.board b/boards/riscv/hifive_unmatched/Kconfig.board index cf6ac1c8392..bb303cc3aac 100644 --- a/boards/riscv/hifive_unmatched/Kconfig.board +++ b/boards/riscv/hifive_unmatched/Kconfig.board @@ -3,4 +3,4 @@ config BOARD_HIFIVE_UNMATCHED bool "HiFive Unmatched target" - depends on SOC_RISCV_SIFIVE_FU740 + depends on SOC_SIFIVE_FREEDOM_U740 diff --git a/boards/riscv/hifive_unmatched/hifive_unmatched_defconfig b/boards/riscv/hifive_unmatched/hifive_unmatched_defconfig index 654fdc1bf2a..be13ed10358 100644 --- a/boards/riscv/hifive_unmatched/hifive_unmatched_defconfig +++ b/boards/riscv/hifive_unmatched/hifive_unmatched_defconfig @@ -1,5 +1,5 @@ -CONFIG_SOC_SERIES_RISCV_SIFIVE_FREEDOM=y -CONFIG_SOC_RISCV_SIFIVE_FU740=y +CONFIG_SOC_SERIES_SIFIVE_FREEDOM_U700=y +CONFIG_SOC_SIFIVE_FREEDOM_U740=y CONFIG_BOARD_HIFIVE_UNMATCHED=y CONFIG_CONSOLE=y CONFIG_SERIAL=y diff --git a/boards/riscv/qemu_riscv32/Kconfig.board b/boards/riscv/qemu_riscv32/Kconfig.board index 989fa13b453..7c94b59455c 100644 --- a/boards/riscv/qemu_riscv32/Kconfig.board +++ b/boards/riscv/qemu_riscv32/Kconfig.board @@ -22,7 +22,7 @@ config BOARD_QEMU_RISCV32_SMP config BOARD_QEMU_RISCV32_XIP bool "QEMU RISCV32 XIP target" - depends on SOC_RISCV_SIFIVE_FREEDOM + depends on SOC_SIFIVE_FREEDOM_E340 select QEMU_TARGET select HAS_COVERAGE_SUPPORT select CPU_HAS_FPU diff --git a/boards/riscv/qemu_riscv32/qemu_riscv32_xip_defconfig b/boards/riscv/qemu_riscv32/qemu_riscv32_xip_defconfig index 2cd0b2cbecb..948fa909a08 100644 --- a/boards/riscv/qemu_riscv32/qemu_riscv32_xip_defconfig +++ b/boards/riscv/qemu_riscv32/qemu_riscv32_xip_defconfig @@ -1,7 +1,7 @@ # SPDX-License-Identifier: Apache-2.0 -CONFIG_SOC_SERIES_RISCV_SIFIVE_FREEDOM=y -CONFIG_SOC_RISCV_SIFIVE_FREEDOM=y +CONFIG_SOC_SERIES_SIFIVE_FREEDOM_E300=y +CONFIG_SOC_SIFIVE_FREEDOM_E340=y CONFIG_BOARD_QEMU_RISCV32_XIP=y CONFIG_CONSOLE=y CONFIG_SERIAL=y diff --git a/boards/riscv/sparkfun_red_v_things_plus/Kconfig.board b/boards/riscv/sparkfun_red_v_things_plus/Kconfig.board index 34f852dc0ec..cc9e7b4f935 100644 --- a/boards/riscv/sparkfun_red_v_things_plus/Kconfig.board +++ b/boards/riscv/sparkfun_red_v_things_plus/Kconfig.board @@ -3,4 +3,4 @@ config BOARD_SPARKFUN_RED_V_THINGS_PLUS bool "SparkFun RED-V Things Plus board" - depends on SOC_RISCV_SIFIVE_FREEDOM + depends on SOC_SIFIVE_FREEDOM_E340 diff --git a/boards/riscv/sparkfun_red_v_things_plus/sparkfun_red_v_things_plus_defconfig b/boards/riscv/sparkfun_red_v_things_plus/sparkfun_red_v_things_plus_defconfig index de3d18bcfde..8cf24ffbe09 100644 --- a/boards/riscv/sparkfun_red_v_things_plus/sparkfun_red_v_things_plus_defconfig +++ b/boards/riscv/sparkfun_red_v_things_plus/sparkfun_red_v_things_plus_defconfig @@ -1,8 +1,8 @@ # Copyright (c) 2022 TOKITA Hiroshi # SPDX-License-Identifier: Apache-2.0 -CONFIG_SOC_SERIES_RISCV_SIFIVE_FREEDOM=y -CONFIG_SOC_RISCV_SIFIVE_FREEDOM=y +CONFIG_SOC_SERIES_SIFIVE_FREEDOM_E300=y +CONFIG_SOC_SIFIVE_FREEDOM_E340=y CONFIG_BOARD_SPARKFUN_RED_V_THINGS_PLUS=y CONFIG_GPIO=y CONFIG_PINCTRL=y diff --git a/soc/riscv/riscv-privileged/sifive-freedom/CMakeLists.txt b/soc/riscv/riscv-privileged/sifive-freedom/CMakeLists.txt deleted file mode 100644 index ff4cc56d739..00000000000 --- a/soc/riscv/riscv-privileged/sifive-freedom/CMakeLists.txt +++ /dev/null @@ -1,8 +0,0 @@ -# SPDX-License-Identifier: Apache-2.0 - -zephyr_sources() -zephyr_sources_ifdef(CONFIG_SOC_RISCV_SIFIVE_FREEDOM fe310_clock.c) -zephyr_sources_ifdef(CONFIG_SOC_RISCV_SIFIVE_FU540 fu540_clock.c) -zephyr_sources_ifdef(CONFIG_SOC_RISCV_SIFIVE_FU740 fu740_clock.c) - -set(SOC_LINKER_SCRIPT ${ZEPHYR_BASE}/include/zephyr/arch/riscv/common/linker.ld CACHE INTERNAL "") diff --git a/soc/riscv/riscv-privileged/sifive-freedom/Kconfig.series b/soc/riscv/riscv-privileged/sifive-freedom/Kconfig.series deleted file mode 100644 index a24b4812c28..00000000000 --- a/soc/riscv/riscv-privileged/sifive-freedom/Kconfig.series +++ /dev/null @@ -1,11 +0,0 @@ -# RISCV_SIFIVE_FREEDOM SOC implementation - -# Copyright (c) 2017 Jean-Paul Etienne -# SPDX-License-Identifier: Apache-2.0 - -config SOC_SERIES_RISCV_SIFIVE_FREEDOM - bool "SiFive Freedom SOC implementation" - select RISCV - select RISCV_PRIVILEGED - help - Enable support for SiFive Freedom SOC diff --git a/soc/riscv/riscv-privileged/sifive-freedom/Kconfig.soc b/soc/riscv/riscv-privileged/sifive-freedom/Kconfig.soc deleted file mode 100644 index 7840f8a09ba..00000000000 --- a/soc/riscv/riscv-privileged/sifive-freedom/Kconfig.soc +++ /dev/null @@ -1,44 +0,0 @@ -# RISCV_SIFIVE_FREEDOM SOC configuration options - -# Copyright (c) 2017 Jean-Paul Etienne -# SPDX-License-Identifier: Apache-2.0 - -choice - prompt "SiFive Freedom SOC implementation" - depends on SOC_SERIES_RISCV_SIFIVE_FREEDOM - -config SOC_RISCV_SIFIVE_FREEDOM - bool "SiFive Freedom SOC implementation" - select ATOMIC_OPERATIONS_C - select INCLUDE_RESET_VECTOR - select RISCV_ISA_RV32I - select RISCV_ISA_EXT_M - select RISCV_ISA_EXT_A - select RISCV_ISA_EXT_ZICSR - select RISCV_ISA_EXT_ZIFENCEI - -config SOC_RISCV_SIFIVE_FU540 - bool "SiFive Freedom U540 SOC implementation" - select ATOMIC_OPERATIONS_C - select INCLUDE_RESET_VECTOR - select 64BIT - select RISCV_ISA_RV64I - select RISCV_ISA_EXT_M - select RISCV_ISA_EXT_A - select RISCV_ISA_EXT_C - select RISCV_ISA_EXT_ZICSR - select RISCV_ISA_EXT_ZIFENCEI - -config SOC_RISCV_SIFIVE_FU740 - bool "SiFive Freedom U740 SOC implementation" - select ATOMIC_OPERATIONS_C - select INCLUDE_RESET_VECTOR - select 64BIT - select RISCV_ISA_RV64I - select RISCV_ISA_EXT_M - select RISCV_ISA_EXT_A - select RISCV_ISA_EXT_C - select RISCV_ISA_EXT_ZICSR - select RISCV_ISA_EXT_ZIFENCEI - -endchoice diff --git a/soc/riscv/sifive_freedom/CMakeLists.txt b/soc/riscv/sifive_freedom/CMakeLists.txt new file mode 100644 index 00000000000..6a5b10545ff --- /dev/null +++ b/soc/riscv/sifive_freedom/CMakeLists.txt @@ -0,0 +1,5 @@ +# Copyright (c) 2024 Nordic Semiconductor +# SPDX-License-Identifier: Apache-2.0 + +add_subdirectory(common) +add_subdirectory(${SOC_SERIES}) diff --git a/soc/riscv/sifive_freedom/Kconfig b/soc/riscv/sifive_freedom/Kconfig new file mode 100644 index 00000000000..0fed11158af --- /dev/null +++ b/soc/riscv/sifive_freedom/Kconfig @@ -0,0 +1,15 @@ +# Copyright (c) 2024 Nordic Semiconductor ASA +# SPDX-License-Identifier: Apache-2.0 + +config SOC_FAMILY_SIFIVE_FREEDOM + bool + +if SOC_FAMILY_SIFIVE_FREEDOM + +config SOC_FAMILY + string + default "sifive_freedom" + +source "soc/riscv/sifive_freedom/*/Kconfig.soc" + +endif # SOC_FAMILY_SIFIVE_FREEDOM diff --git a/soc/riscv/sifive_freedom/Kconfig.defconfig b/soc/riscv/sifive_freedom/Kconfig.defconfig new file mode 100644 index 00000000000..5adf8fc437e --- /dev/null +++ b/soc/riscv/sifive_freedom/Kconfig.defconfig @@ -0,0 +1,4 @@ +# Copyright (c) 2024 Nordic Semiconductor ASA +# SPDX-License-Identifier: Apache-2.0 + +source "soc/riscv/sifive_freedom/*/Kconfig.defconfig.series" diff --git a/soc/riscv/sifive_freedom/Kconfig.soc b/soc/riscv/sifive_freedom/Kconfig.soc new file mode 100644 index 00000000000..54274defd91 --- /dev/null +++ b/soc/riscv/sifive_freedom/Kconfig.soc @@ -0,0 +1,4 @@ +# Copyright (c) 2024 Nordic Semiconductor ASA +# SPDX-License-Identifier: Apache-2.0 + +source "soc/riscv/sifive_freedom/*/Kconfig.series" diff --git a/soc/riscv/sifive_freedom/common/CMakeLists.txt b/soc/riscv/sifive_freedom/common/CMakeLists.txt new file mode 100644 index 00000000000..f75aec6b311 --- /dev/null +++ b/soc/riscv/sifive_freedom/common/CMakeLists.txt @@ -0,0 +1,3 @@ +# SPDX-License-Identifier: Apache-2.0 + +zephyr_include_directories(.) diff --git a/soc/riscv/riscv-privileged/sifive-freedom/pinctrl_soc.h b/soc/riscv/sifive_freedom/common/pinctrl_soc.h similarity index 100% rename from soc/riscv/riscv-privileged/sifive-freedom/pinctrl_soc.h rename to soc/riscv/sifive_freedom/common/pinctrl_soc.h diff --git a/soc/riscv/sifive_freedom/e300/CMakeLists.txt b/soc/riscv/sifive_freedom/e300/CMakeLists.txt new file mode 100644 index 00000000000..baf01a6b047 --- /dev/null +++ b/soc/riscv/sifive_freedom/e300/CMakeLists.txt @@ -0,0 +1,5 @@ +# SPDX-License-Identifier: Apache-2.0 + +zephyr_sources(clock.c) + +set(SOC_LINKER_SCRIPT ${ZEPHYR_BASE}/include/zephyr/arch/riscv/common/linker.ld CACHE INTERNAL "") diff --git a/soc/riscv/sifive_freedom/e300/Kconfig.defconfig.e340 b/soc/riscv/sifive_freedom/e300/Kconfig.defconfig.e340 new file mode 100644 index 00000000000..cb0131f1427 --- /dev/null +++ b/soc/riscv/sifive_freedom/e300/Kconfig.defconfig.e340 @@ -0,0 +1,5 @@ +# Copyright (c) 2017 Jean-Paul Etienne +# SPDX-License-Identifier: Apache-2.0 + +config SOC + default "e340" if SOC_SIFIVE_FREEDOM_E340 diff --git a/soc/riscv/riscv-privileged/sifive-freedom/Kconfig.defconfig.series b/soc/riscv/sifive_freedom/e300/Kconfig.defconfig.series similarity index 65% rename from soc/riscv/riscv-privileged/sifive-freedom/Kconfig.defconfig.series rename to soc/riscv/sifive_freedom/e300/Kconfig.defconfig.series index 0c3cd541773..b2f16e5261d 100644 --- a/soc/riscv/riscv-privileged/sifive-freedom/Kconfig.defconfig.series +++ b/soc/riscv/sifive_freedom/e300/Kconfig.defconfig.series @@ -1,9 +1,10 @@ +# Copyright (c) 2017 Jean-Paul Etienne # SPDX-License-Identifier: Apache-2.0 -if SOC_SERIES_RISCV_SIFIVE_FREEDOM +if SOC_SERIES_SIFIVE_FREEDOM_E300 config SOC_SERIES - default "sifive-freedom" + default "e300" config SYS_CLOCK_HW_CYCLES_PER_SEC default 32768 @@ -32,4 +33,6 @@ config MAX_IRQ_PER_AGGREGATOR config NUM_IRQS default 64 -endif # SOC_SERIES_RISCV_SIFIVE_FREEDOM +source "soc/riscv/sifive_freedom/e300/Kconfig.defconfig.e*" + +endif # SOC_SERIES_SIFIVE_FREEDOM_E300 diff --git a/soc/riscv/sifive_freedom/e300/Kconfig.series b/soc/riscv/sifive_freedom/e300/Kconfig.series new file mode 100644 index 00000000000..066f8909d53 --- /dev/null +++ b/soc/riscv/sifive_freedom/e300/Kconfig.series @@ -0,0 +1,13 @@ +# RISCV_SIFIVE_FREEDOM SOC implementation + +# Copyright (c) 2017 Jean-Paul Etienne +# SPDX-License-Identifier: Apache-2.0 + +config SOC_SERIES_SIFIVE_FREEDOM_E300 + bool "SiFive Freedom E300 SOC implementation" + select RISCV + select RISCV_PRIVILEGED + select RISCV_PRIVILEGED_STANDALONE + select SOC_FAMILY_SIFIVE_FREEDOM + help + Enable support for SiFive Freedom FE300 SOC diff --git a/soc/riscv/sifive_freedom/e300/Kconfig.soc b/soc/riscv/sifive_freedom/e300/Kconfig.soc new file mode 100644 index 00000000000..e53b84c0890 --- /dev/null +++ b/soc/riscv/sifive_freedom/e300/Kconfig.soc @@ -0,0 +1,20 @@ +# RISCV_SIFIVE_FREEDOM SOC configuration options + +# Copyright (c) 2017 Jean-Paul Etienne +# SPDX-License-Identifier: Apache-2.0 + +choice + prompt "SiFive Freedom SOC implementation" + depends on SOC_SERIES_SIFIVE_FREEDOM_E300 + +config SOC_SIFIVE_FREEDOM_E340 + bool "SiFive Freedom SOC implementation" + select ATOMIC_OPERATIONS_C + select INCLUDE_RESET_VECTOR + select RISCV_ISA_RV32I + select RISCV_ISA_EXT_M + select RISCV_ISA_EXT_A + select RISCV_ISA_EXT_ZICSR + select RISCV_ISA_EXT_ZIFENCEI + +endchoice diff --git a/soc/riscv/riscv-privileged/sifive-freedom/fe310_clock.c b/soc/riscv/sifive_freedom/e300/clock.c similarity index 98% rename from soc/riscv/riscv-privileged/sifive-freedom/fe310_clock.c rename to soc/riscv/sifive_freedom/e300/clock.c index 0b642f3e8b2..8fde8121db9 100644 --- a/soc/riscv/riscv-privileged/sifive-freedom/fe310_clock.c +++ b/soc/riscv/sifive_freedom/e300/clock.c @@ -7,7 +7,7 @@ #include #include -#include "fe310_prci.h" +#include "prci.h" #define CORECLK_HZ (DT_PROP(DT_NODELABEL(coreclk), clock_frequency)) BUILD_ASSERT(DT_PROP(DT_NODELABEL(tlclk), clock_div) == 1, diff --git a/soc/riscv/riscv-privileged/sifive-freedom/fe310_prci.h b/soc/riscv/sifive_freedom/e300/prci.h similarity index 100% rename from soc/riscv/riscv-privileged/sifive-freedom/fe310_prci.h rename to soc/riscv/sifive_freedom/e300/prci.h diff --git a/soc/riscv/riscv-privileged/sifive-freedom/soc.h b/soc/riscv/sifive_freedom/e300/soc.h similarity index 52% rename from soc/riscv/riscv-privileged/sifive-freedom/soc.h rename to soc/riscv/sifive_freedom/e300/soc.h index 958891a9d6a..c83f5f322b6 100644 --- a/soc/riscv/riscv-privileged/sifive-freedom/soc.h +++ b/soc/riscv/sifive_freedom/e300/soc.h @@ -8,30 +8,17 @@ * @file SoC configuration macros for the SiFive Freedom processor */ -#ifndef __RISCV_SIFIVE_FREEDOM_SOC_H_ -#define __RISCV_SIFIVE_FREEDOM_SOC_H_ +#ifndef __RISCV_SIFIVE_FREEDOM_FE300_SOC_H_ +#define __RISCV_SIFIVE_FREEDOM_FE300_SOC_H_ #include -#if defined(CONFIG_SOC_RISCV_SIFIVE_FREEDOM) /* PINMUX MAX PINS */ #define SIFIVE_PINMUX_PINS 32 /* Clock controller. */ #define PRCI_BASE_ADDR 0x10008000 -#elif defined(CONFIG_SOC_RISCV_SIFIVE_FU540) || defined(CONFIG_SOC_RISCV_SIFIVE_FU740) - -/* Clock controller. */ -#define PRCI_BASE_ADDR 0x10000000 - -/* PINMUX MAX PINS */ -#define SIFIVE_PINMUX_PINS 16 - -#endif - -#if defined(CONFIG_SOC_RISCV_SIFIVE_FREEDOM) || defined(CONFIG_SOC_RISCV_SIFIVE_FU540) - /* * On FE310 and FU540, peripherals such as SPI, UART, I2C and PWM are clocked * by TLCLK, which is derived from CORECLK. @@ -42,12 +29,4 @@ #define SIFIVE_PERIPHERAL_CLOCK_FREQUENCY \ (SIFIVE_TLCLK_BASE_FREQUENCY / SIFIVE_TLCLK_DIVIDER) -#elif defined(CONFIG_SOC_RISCV_SIFIVE_FU740) - -/* On FU740, peripherals are clocked by PCLK. */ -#define SIFIVE_PERIPHERAL_CLOCK_FREQUENCY \ - DT_PROP(DT_NODELABEL(pclk), clock_frequency) - -#endif - -#endif /* __RISCV_SIFIVE_FREEDOM_SOC_H_ */ +#endif /* __RISCV_SIFIVE_FREEDOM_FE300_SOC_H_ */ diff --git a/soc/riscv/sifive_freedom/u500/CMakeLists.txt b/soc/riscv/sifive_freedom/u500/CMakeLists.txt new file mode 100644 index 00000000000..baf01a6b047 --- /dev/null +++ b/soc/riscv/sifive_freedom/u500/CMakeLists.txt @@ -0,0 +1,5 @@ +# SPDX-License-Identifier: Apache-2.0 + +zephyr_sources(clock.c) + +set(SOC_LINKER_SCRIPT ${ZEPHYR_BASE}/include/zephyr/arch/riscv/common/linker.ld CACHE INTERNAL "") diff --git a/soc/riscv/sifive_freedom/u500/Kconfig.defconfig.series b/soc/riscv/sifive_freedom/u500/Kconfig.defconfig.series new file mode 100644 index 00000000000..d6b94678686 --- /dev/null +++ b/soc/riscv/sifive_freedom/u500/Kconfig.defconfig.series @@ -0,0 +1,38 @@ +# Copyright (c) 2017 Jean-Paul Etienne +# SPDX-License-Identifier: Apache-2.0 + +if SOC_SERIES_SIFIVE_FREEDOM_U500 + +config SOC_SERIES + default "u500" + +config SYS_CLOCK_HW_CYCLES_PER_SEC + default 32768 + +config RISCV_SOC_INTERRUPT_INIT + default y + +config RISCV_HAS_CPU_IDLE + default y + +config RISCV_HAS_PLIC + default y + +config RISCV_GP + default y + +config 2ND_LVL_ISR_TBL_OFFSET + default 12 + +config 2ND_LVL_INTR_00_OFFSET + default 11 + +config MAX_IRQ_PER_AGGREGATOR + default 52 + +config NUM_IRQS + default 64 + +source "soc/riscv/sifive_freedom/u500/Kconfig.defconfig.u*" + +endif # SOC_SERIES_SIFIVE_FREEDOM_U500 diff --git a/soc/riscv/sifive_freedom/u500/Kconfig.defconfig.u540 b/soc/riscv/sifive_freedom/u500/Kconfig.defconfig.u540 new file mode 100644 index 00000000000..f559f5914b3 --- /dev/null +++ b/soc/riscv/sifive_freedom/u500/Kconfig.defconfig.u540 @@ -0,0 +1,5 @@ +# Copyright (c) 2017 Jean-Paul Etienne +# SPDX-License-Identifier: Apache-2.0 + +config SOC + default "u540" if SOC_SIFIVE_FREEDOM_U540 diff --git a/soc/riscv/sifive_freedom/u500/Kconfig.series b/soc/riscv/sifive_freedom/u500/Kconfig.series new file mode 100644 index 00000000000..963a265f383 --- /dev/null +++ b/soc/riscv/sifive_freedom/u500/Kconfig.series @@ -0,0 +1,13 @@ +# RISCV_SIFIVE_FREEDOM SOC implementation + +# Copyright (c) 2017 Jean-Paul Etienne +# SPDX-License-Identifier: Apache-2.0 + +config SOC_SERIES_SIFIVE_FREEDOM_U500 + bool "SiFive Freedom U500 SOC implementation" + select RISCV + select RISCV_PRIVILEGED + select RISCV_PRIVILEGED_STANDALONE + select SOC_FAMILY_SIFIVE_FREEDOM + help + Enable support for SiFive Freedom U500 SOC diff --git a/soc/riscv/sifive_freedom/u500/Kconfig.soc b/soc/riscv/sifive_freedom/u500/Kconfig.soc new file mode 100644 index 00000000000..0a88ccf8cc1 --- /dev/null +++ b/soc/riscv/sifive_freedom/u500/Kconfig.soc @@ -0,0 +1,22 @@ +# RISCV_SIFIVE_FREEDOM SOC configuration options + +# Copyright (c) 2017 Jean-Paul Etienne +# SPDX-License-Identifier: Apache-2.0 + +choice + prompt "SiFive Freedom SOC implementation" + depends on SOC_SERIES_SIFIVE_FREEDOM_U500 + +config SOC_SIFIVE_FREEDOM_U540 + bool "SiFive Freedom U540 SOC implementation" + select ATOMIC_OPERATIONS_C + select INCLUDE_RESET_VECTOR + select 64BIT + select RISCV_ISA_RV64I + select RISCV_ISA_EXT_M + select RISCV_ISA_EXT_A + select RISCV_ISA_EXT_C + select RISCV_ISA_EXT_ZICSR + select RISCV_ISA_EXT_ZIFENCEI + +endchoice diff --git a/soc/riscv/riscv-privileged/sifive-freedom/fu540_clock.c b/soc/riscv/sifive_freedom/u500/clock.c similarity index 97% rename from soc/riscv/riscv-privileged/sifive-freedom/fu540_clock.c rename to soc/riscv/sifive_freedom/u500/clock.c index bc68a502f59..87929892f77 100644 --- a/soc/riscv/riscv-privileged/sifive-freedom/fu540_clock.c +++ b/soc/riscv/sifive_freedom/u500/clock.c @@ -7,7 +7,7 @@ #include #include #include -#include "fu540_prci.h" +#include "prci.h" BUILD_ASSERT(MHZ(1000) == DT_PROP(DT_NODELABEL(coreclk), clock_frequency), "Unsupported CORECLK frequency"); diff --git a/soc/riscv/riscv-privileged/sifive-freedom/fu540_prci.h b/soc/riscv/sifive_freedom/u500/prci.h similarity index 100% rename from soc/riscv/riscv-privileged/sifive-freedom/fu540_prci.h rename to soc/riscv/sifive_freedom/u500/prci.h diff --git a/soc/riscv/sifive_freedom/u500/soc.h b/soc/riscv/sifive_freedom/u500/soc.h new file mode 100644 index 00000000000..ed367950278 --- /dev/null +++ b/soc/riscv/sifive_freedom/u500/soc.h @@ -0,0 +1,32 @@ +/* + * Copyright (c) 2017 Jean-Paul Etienne + * + * SPDX-License-Identifier: Apache-2.0 + */ + +/** + * @file SoC configuration macros for the SiFive Freedom processor + */ + +#ifndef __RISCV_SIFIVE_FREEDOM_U500_SOC_H_ +#define __RISCV_SIFIVE_FREEDOM_U500_SOC_H_ + +#include + +/* Clock controller. */ +#define PRCI_BASE_ADDR 0x10000000 + +/* PINMUX MAX PINS */ +#define SIFIVE_PINMUX_PINS 16 + +/* + * On FE310 and FU540, peripherals such as SPI, UART, I2C and PWM are clocked + * by TLCLK, which is derived from CORECLK. + */ +#define SIFIVE_TLCLK_BASE_FREQUENCY \ + DT_PROP_BY_PHANDLE_IDX(DT_NODELABEL(tlclk), clocks, 0, clock_frequency) +#define SIFIVE_TLCLK_DIVIDER DT_PROP(DT_NODELABEL(tlclk), clock_div) +#define SIFIVE_PERIPHERAL_CLOCK_FREQUENCY \ + (SIFIVE_TLCLK_BASE_FREQUENCY / SIFIVE_TLCLK_DIVIDER) + +#endif /* __RISCV_SIFIVE_FREEDOM_U500_SOC_H_ */ diff --git a/soc/riscv/sifive_freedom/u700/CMakeLists.txt b/soc/riscv/sifive_freedom/u700/CMakeLists.txt new file mode 100644 index 00000000000..baf01a6b047 --- /dev/null +++ b/soc/riscv/sifive_freedom/u700/CMakeLists.txt @@ -0,0 +1,5 @@ +# SPDX-License-Identifier: Apache-2.0 + +zephyr_sources(clock.c) + +set(SOC_LINKER_SCRIPT ${ZEPHYR_BASE}/include/zephyr/arch/riscv/common/linker.ld CACHE INTERNAL "") diff --git a/soc/riscv/sifive_freedom/u700/Kconfig.defconfig.series b/soc/riscv/sifive_freedom/u700/Kconfig.defconfig.series new file mode 100644 index 00000000000..347ac14b551 --- /dev/null +++ b/soc/riscv/sifive_freedom/u700/Kconfig.defconfig.series @@ -0,0 +1,38 @@ +# Copyright (c) 2017 Jean-Paul Etienne +# SPDX-License-Identifier: Apache-2.0 + +if SOC_SERIES_SIFIVE_FREEDOM_U700 + +config SOC_SERIES + default "u700" + +config SYS_CLOCK_HW_CYCLES_PER_SEC + default 32768 + +config RISCV_SOC_INTERRUPT_INIT + default y + +config RISCV_HAS_CPU_IDLE + default y + +config RISCV_HAS_PLIC + default y + +config RISCV_GP + default y + +config 2ND_LVL_ISR_TBL_OFFSET + default 12 + +config 2ND_LVL_INTR_00_OFFSET + default 11 + +config MAX_IRQ_PER_AGGREGATOR + default 52 + +config NUM_IRQS + default 64 + +source "soc/riscv/sifive_freedom/u700/Kconfig.defconfig.u*" + +endif # SOC_SERIES_SIFIVE_FREEDOM_U700 diff --git a/soc/riscv/sifive_freedom/u700/Kconfig.defconfig.u740 b/soc/riscv/sifive_freedom/u700/Kconfig.defconfig.u740 new file mode 100644 index 00000000000..ca935f772eb --- /dev/null +++ b/soc/riscv/sifive_freedom/u700/Kconfig.defconfig.u740 @@ -0,0 +1,5 @@ +# Copyright (c) 2017 Jean-Paul Etienne +# SPDX-License-Identifier: Apache-2.0 + +config SOC + default "u740" if SOC_SIFIVE_FREEDOM_U740 diff --git a/soc/riscv/sifive_freedom/u700/Kconfig.series b/soc/riscv/sifive_freedom/u700/Kconfig.series new file mode 100644 index 00000000000..b4ca38697f8 --- /dev/null +++ b/soc/riscv/sifive_freedom/u700/Kconfig.series @@ -0,0 +1,13 @@ +# RISCV_SIFIVE_FREEDOM SOC implementation + +# Copyright (c) 2017 Jean-Paul Etienne +# SPDX-License-Identifier: Apache-2.0 + +config SOC_SERIES_SIFIVE_FREEDOM_U700 + bool "SiFive Freedom SOC U700 implementation" + select RISCV + select RISCV_PRIVILEGED + select RISCV_PRIVILEGED_STANDALONE + select SOC_FAMILY_SIFIVE_FREEDOM + help + Enable support for SiFive Freedom U700 SOC diff --git a/soc/riscv/sifive_freedom/u700/Kconfig.soc b/soc/riscv/sifive_freedom/u700/Kconfig.soc new file mode 100644 index 00000000000..1eec9b4bb17 --- /dev/null +++ b/soc/riscv/sifive_freedom/u700/Kconfig.soc @@ -0,0 +1,22 @@ +# RISCV_SIFIVE_FREEDOM SOC configuration options + +# Copyright (c) 2017 Jean-Paul Etienne +# SPDX-License-Identifier: Apache-2.0 + +choice + prompt "SiFive Freedom SOC implementation" + depends on SOC_SERIES_SIFIVE_FREEDOM_U700 + +config SOC_SIFIVE_FREEDOM_U740 + bool "SiFive Freedom U740 SOC implementation" + select ATOMIC_OPERATIONS_C + select INCLUDE_RESET_VECTOR + select 64BIT + select RISCV_ISA_RV64I + select RISCV_ISA_EXT_M + select RISCV_ISA_EXT_A + select RISCV_ISA_EXT_C + select RISCV_ISA_EXT_ZICSR + select RISCV_ISA_EXT_ZIFENCEI + +endchoice diff --git a/soc/riscv/riscv-privileged/sifive-freedom/fu740_clock.c b/soc/riscv/sifive_freedom/u700/clock.c similarity index 99% rename from soc/riscv/riscv-privileged/sifive-freedom/fu740_clock.c rename to soc/riscv/sifive_freedom/u700/clock.c index e6bbee93689..5c3fa567343 100644 --- a/soc/riscv/riscv-privileged/sifive-freedom/fu740_clock.c +++ b/soc/riscv/sifive_freedom/u700/clock.c @@ -8,7 +8,7 @@ #include #include -#include "fu740_prci.h" +#include "prci.h" BUILD_ASSERT(MHZ(1000) == DT_PROP(DT_NODELABEL(coreclk), clock_frequency), "Unsupported CORECLK frequency"); diff --git a/soc/riscv/riscv-privileged/sifive-freedom/fu740_prci.h b/soc/riscv/sifive_freedom/u700/prci.h similarity index 100% rename from soc/riscv/riscv-privileged/sifive-freedom/fu740_prci.h rename to soc/riscv/sifive_freedom/u700/prci.h diff --git a/soc/riscv/sifive_freedom/u700/soc.h b/soc/riscv/sifive_freedom/u700/soc.h new file mode 100644 index 00000000000..91aac61afdd --- /dev/null +++ b/soc/riscv/sifive_freedom/u700/soc.h @@ -0,0 +1,26 @@ +/* + * Copyright (c) 2017 Jean-Paul Etienne + * + * SPDX-License-Identifier: Apache-2.0 + */ + +/** + * @file SoC configuration macros for the SiFive Freedom processor + */ + +#ifndef __RISCV_SIFIVE_FREEDOM_U700_SOC_H_ +#define __RISCV_SIFIVE_FREEDOM_U700_SOC_H_ + +#include + +/* Clock controller. */ +#define PRCI_BASE_ADDR 0x10000000 + +/* PINMUX MAX PINS */ +#define SIFIVE_PINMUX_PINS 16 + +/* On FU740, peripherals are clocked by PCLK. */ +#define SIFIVE_PERIPHERAL_CLOCK_FREQUENCY \ + DT_PROP(DT_NODELABEL(pclk), clock_frequency) + +#endif /* __RISCV_SIFIVE_FREEDOM_U700_SOC_H_ */ From b5fb00bdc87588607940d2af053866d04d11d423 Mon Sep 17 00:00:00 2001 From: Gerard Marull-Paretas Date: Wed, 3 Jan 2024 17:30:23 +0100 Subject: [PATCH 1893/3723] soc: riscv: opentitan: reorganize SoC folder Remove from riscv-privileged, and create a standalone SoC. Signed-off-by: Gerard Marull-Paretas --- boards/riscv/opentitan_earlgrey/Kconfig.board | 2 +- .../opentitan_earlgrey_defconfig | 3 +-- .../opentitan/CMakeLists.txt | 0 .../Kconfig.defconfig} | 6 +++--- .../{riscv-privileged => }/opentitan/Kconfig.soc | 14 +++++++------- .../{riscv-privileged => }/opentitan/rom_header.S | 0 .../{riscv-privileged => }/opentitan/rom_header.ld | 0 soc/riscv/{riscv-privileged => }/opentitan/soc.c | 0 soc/riscv/{riscv-privileged => }/opentitan/soc.h | 0 .../riscv-privileged/opentitan/Kconfig.series | 12 ------------ 10 files changed, 12 insertions(+), 25 deletions(-) rename soc/riscv/{riscv-privileged => }/opentitan/CMakeLists.txt (100%) rename soc/riscv/{riscv-privileged/opentitan/Kconfig.defconfig.series => opentitan/Kconfig.defconfig} (83%) rename soc/riscv/{riscv-privileged => }/opentitan/Kconfig.soc (63%) rename soc/riscv/{riscv-privileged => }/opentitan/rom_header.S (100%) rename soc/riscv/{riscv-privileged => }/opentitan/rom_header.ld (100%) rename soc/riscv/{riscv-privileged => }/opentitan/soc.c (100%) rename soc/riscv/{riscv-privileged => }/opentitan/soc.h (100%) delete mode 100644 soc/riscv/riscv-privileged/opentitan/Kconfig.series diff --git a/boards/riscv/opentitan_earlgrey/Kconfig.board b/boards/riscv/opentitan_earlgrey/Kconfig.board index ec7f735b442..544c02b1b2a 100644 --- a/boards/riscv/opentitan_earlgrey/Kconfig.board +++ b/boards/riscv/opentitan_earlgrey/Kconfig.board @@ -3,4 +3,4 @@ config BOARD_OPENTITAN_EARLGREY bool "OpenTitan Earl Grey Target" - depends on SOC_RISCV_OPENTITAN + depends on SOC_OPENTITAN diff --git a/boards/riscv/opentitan_earlgrey/opentitan_earlgrey_defconfig b/boards/riscv/opentitan_earlgrey/opentitan_earlgrey_defconfig index 79299c3892f..886e439b88a 100644 --- a/boards/riscv/opentitan_earlgrey/opentitan_earlgrey_defconfig +++ b/boards/riscv/opentitan_earlgrey/opentitan_earlgrey_defconfig @@ -1,8 +1,7 @@ # Copyright (c) 2023 by Rivos Inc. # SPDX-License-Identifier: Apache-2.0 -CONFIG_SOC_SERIES_RISCV_OPENTITAN=y -CONFIG_SOC_RISCV_OPENTITAN=y +CONFIG_SOC_OPENTITAN=y CONFIG_BOARD_OPENTITAN_EARLGREY=y CONFIG_XIP=y CONFIG_SERIAL=y diff --git a/soc/riscv/riscv-privileged/opentitan/CMakeLists.txt b/soc/riscv/opentitan/CMakeLists.txt similarity index 100% rename from soc/riscv/riscv-privileged/opentitan/CMakeLists.txt rename to soc/riscv/opentitan/CMakeLists.txt diff --git a/soc/riscv/riscv-privileged/opentitan/Kconfig.defconfig.series b/soc/riscv/opentitan/Kconfig.defconfig similarity index 83% rename from soc/riscv/riscv-privileged/opentitan/Kconfig.defconfig.series rename to soc/riscv/opentitan/Kconfig.defconfig index c9e7f8396a0..cc27b7ffd6b 100644 --- a/soc/riscv/riscv-privileged/opentitan/Kconfig.defconfig.series +++ b/soc/riscv/opentitan/Kconfig.defconfig @@ -1,9 +1,9 @@ # Copyright (c) 2023 Rivos Inc. # SPDX-License-Identifier: Apache-2.0 -if SOC_SERIES_RISCV_OPENTITAN +if SOC_OPENTITAN -config SOC_SERIES +config SOC default "opentitan" config SYS_CLOCK_HW_CYCLES_PER_SEC @@ -30,4 +30,4 @@ config 2ND_LVL_INTR_00_OFFSET config NUM_IRQS default 217 -endif # SOC_SERIES_RISCV_OPENTITAN +endif # SOC_OPENTITAN diff --git a/soc/riscv/riscv-privileged/opentitan/Kconfig.soc b/soc/riscv/opentitan/Kconfig.soc similarity index 63% rename from soc/riscv/riscv-privileged/opentitan/Kconfig.soc rename to soc/riscv/opentitan/Kconfig.soc index 098b1844e52..b482afce469 100644 --- a/soc/riscv/riscv-privileged/opentitan/Kconfig.soc +++ b/soc/riscv/opentitan/Kconfig.soc @@ -1,11 +1,7 @@ # Copyright (c) 2023 Rivos Inc. # SPDX-License-Identifier: Apache-2.0 -choice - prompt "OpenTitan implementation" - depends on SOC_SERIES_RISCV_OPENTITAN - -config SOC_RISCV_OPENTITAN +config SOC_OPENTITAN bool "OpenTitan implementation" select ATOMIC_OPERATIONS_C select INCLUDE_RESET_VECTOR @@ -18,5 +14,9 @@ config SOC_RISCV_OPENTITAN select RISCV_ISA_EXT_ZBB select RISCV_ISA_EXT_ZBC select RISCV_ISA_EXT_ZBS - -endchoice + select RISCV + select RISCV_PRIVILEGED + # OpenTitan Ibex core mtvec mode is read-only / forced to vectored mode. + select RISCV_VECTORED_MODE + select GEN_IRQ_VECTOR_TABLE + select RISCV_PRIVILEGED_STANDALONE diff --git a/soc/riscv/riscv-privileged/opentitan/rom_header.S b/soc/riscv/opentitan/rom_header.S similarity index 100% rename from soc/riscv/riscv-privileged/opentitan/rom_header.S rename to soc/riscv/opentitan/rom_header.S diff --git a/soc/riscv/riscv-privileged/opentitan/rom_header.ld b/soc/riscv/opentitan/rom_header.ld similarity index 100% rename from soc/riscv/riscv-privileged/opentitan/rom_header.ld rename to soc/riscv/opentitan/rom_header.ld diff --git a/soc/riscv/riscv-privileged/opentitan/soc.c b/soc/riscv/opentitan/soc.c similarity index 100% rename from soc/riscv/riscv-privileged/opentitan/soc.c rename to soc/riscv/opentitan/soc.c diff --git a/soc/riscv/riscv-privileged/opentitan/soc.h b/soc/riscv/opentitan/soc.h similarity index 100% rename from soc/riscv/riscv-privileged/opentitan/soc.h rename to soc/riscv/opentitan/soc.h diff --git a/soc/riscv/riscv-privileged/opentitan/Kconfig.series b/soc/riscv/riscv-privileged/opentitan/Kconfig.series deleted file mode 100644 index b516e6d8092..00000000000 --- a/soc/riscv/riscv-privileged/opentitan/Kconfig.series +++ /dev/null @@ -1,12 +0,0 @@ -# Copyright (c) 2023 Rivos Inc. -# SPDX-License-Identifier: Apache-2.0 - -config SOC_SERIES_RISCV_OPENTITAN - bool "OpenTitan implementation" - select RISCV - select RISCV_PRIVILEGED - # OpenTitan Ibex core mtvec mode is read-only / forced to vectored mode. - select RISCV_VECTORED_MODE - select GEN_IRQ_VECTOR_TABLE - help - Enable support for OpenTitan From 8729a782f96eaa2d673517048dd1afef0513ffd2 Mon Sep 17 00:00:00 2001 From: Gerard Marull-Paretas Date: Wed, 3 Jan 2024 17:36:53 +0100 Subject: [PATCH 1894/3723] soc: riscv: niosv: reorganize SoC folder Move out of riscv-privileged, create new family for it. Signed-off-by: Gerard Marull-Paretas --- .../CMakeLists.txt | 1 + soc/riscv/intel_niosv/Kconfig | 15 +++++++++++++++ soc/riscv/intel_niosv/Kconfig.defconfig | 4 ++++ soc/riscv/intel_niosv/Kconfig.soc | 4 ++++ .../niosv/CMakeLists.txt | 0 .../niosv/Kconfig.defconfig.series | 2 +- .../niosv/Kconfig.series | 2 ++ .../niosv/Kconfig.soc | 0 .../niosv/linker.ld | 0 .../{riscv-privileged => intel_niosv}/niosv/soc.h | 0 soc/riscv/riscv-privileged/Kconfig | 4 ---- soc/riscv/riscv-privileged/Kconfig.defconfig | 6 ------ soc/riscv/riscv-privileged/Kconfig.soc | 6 ------ 13 files changed, 27 insertions(+), 17 deletions(-) rename soc/riscv/{riscv-privileged => intel_niosv}/CMakeLists.txt (62%) create mode 100644 soc/riscv/intel_niosv/Kconfig create mode 100644 soc/riscv/intel_niosv/Kconfig.defconfig create mode 100644 soc/riscv/intel_niosv/Kconfig.soc rename soc/riscv/{riscv-privileged => intel_niosv}/niosv/CMakeLists.txt (100%) rename soc/riscv/{riscv-privileged => intel_niosv}/niosv/Kconfig.defconfig.series (94%) rename soc/riscv/{riscv-privileged => intel_niosv}/niosv/Kconfig.series (76%) rename soc/riscv/{riscv-privileged => intel_niosv}/niosv/Kconfig.soc (100%) rename soc/riscv/{riscv-privileged => intel_niosv}/niosv/linker.ld (100%) rename soc/riscv/{riscv-privileged => intel_niosv}/niosv/soc.h (100%) delete mode 100644 soc/riscv/riscv-privileged/Kconfig delete mode 100644 soc/riscv/riscv-privileged/Kconfig.defconfig delete mode 100644 soc/riscv/riscv-privileged/Kconfig.soc diff --git a/soc/riscv/riscv-privileged/CMakeLists.txt b/soc/riscv/intel_niosv/CMakeLists.txt similarity index 62% rename from soc/riscv/riscv-privileged/CMakeLists.txt rename to soc/riscv/intel_niosv/CMakeLists.txt index 226f3bd626f..69b2926358e 100644 --- a/soc/riscv/riscv-privileged/CMakeLists.txt +++ b/soc/riscv/intel_niosv/CMakeLists.txt @@ -1,3 +1,4 @@ +# Copyright (c) 2024 Nordic Semiconductor # SPDX-License-Identifier: Apache-2.0 add_subdirectory(${SOC_SERIES}) diff --git a/soc/riscv/intel_niosv/Kconfig b/soc/riscv/intel_niosv/Kconfig new file mode 100644 index 00000000000..b841d19c922 --- /dev/null +++ b/soc/riscv/intel_niosv/Kconfig @@ -0,0 +1,15 @@ +# Copyright (c) 2024 Nordic Semiconductor ASA +# SPDX-License-Identifier: Apache-2.0 + +config SOC_FAMILY_INTEL_NIOSV + bool + +if SOC_FAMILY_INTEL_NIOSV + +config SOC_FAMILY + string + default "intel_niosv" + +source "soc/riscv/intel_niosv/*/Kconfig.soc" + +endif # SOC_FAMILY_INTEL_NIOSV diff --git a/soc/riscv/intel_niosv/Kconfig.defconfig b/soc/riscv/intel_niosv/Kconfig.defconfig new file mode 100644 index 00000000000..2afa0f7e0e6 --- /dev/null +++ b/soc/riscv/intel_niosv/Kconfig.defconfig @@ -0,0 +1,4 @@ +# Copyright (c) 2024 Nordic Semiconductor ASA +# SPDX-License-Identifier: Apache-2.0 + +source "soc/riscv/intel_niosv/*/Kconfig.defconfig.series" diff --git a/soc/riscv/intel_niosv/Kconfig.soc b/soc/riscv/intel_niosv/Kconfig.soc new file mode 100644 index 00000000000..8567429c61f --- /dev/null +++ b/soc/riscv/intel_niosv/Kconfig.soc @@ -0,0 +1,4 @@ +# Copyright (c) 2024 Nordic Semiconductor ASA +# SPDX-License-Identifier: Apache-2.0 + +source "soc/riscv/intel_niosv/*/Kconfig.series" diff --git a/soc/riscv/riscv-privileged/niosv/CMakeLists.txt b/soc/riscv/intel_niosv/niosv/CMakeLists.txt similarity index 100% rename from soc/riscv/riscv-privileged/niosv/CMakeLists.txt rename to soc/riscv/intel_niosv/niosv/CMakeLists.txt diff --git a/soc/riscv/riscv-privileged/niosv/Kconfig.defconfig.series b/soc/riscv/intel_niosv/niosv/Kconfig.defconfig.series similarity index 94% rename from soc/riscv/riscv-privileged/niosv/Kconfig.defconfig.series rename to soc/riscv/intel_niosv/niosv/Kconfig.defconfig.series index 532a67959d2..8e8ea255202 100644 --- a/soc/riscv/riscv-privileged/niosv/Kconfig.defconfig.series +++ b/soc/riscv/intel_niosv/niosv/Kconfig.defconfig.series @@ -21,4 +21,4 @@ config RISCV_GP config RISCV_SOC_INTERRUPT_INIT default y -endif # SOC_SERIES_NIOSV +endif # SOC_NIOSV diff --git a/soc/riscv/riscv-privileged/niosv/Kconfig.series b/soc/riscv/intel_niosv/niosv/Kconfig.series similarity index 76% rename from soc/riscv/riscv-privileged/niosv/Kconfig.series rename to soc/riscv/intel_niosv/niosv/Kconfig.series index 104f5a48352..b8edc073916 100644 --- a/soc/riscv/riscv-privileged/niosv/Kconfig.series +++ b/soc/riscv/intel_niosv/niosv/Kconfig.series @@ -5,5 +5,7 @@ config SOC_SERIES_NIOSV bool "INTEL FPGA NIOSV" select RISCV select RISCV_PRIVILEGED + select RISCV_PRIVILEGED_STANDALONE + select SOC_FAMILY_INTEL_NIOSV help Enable support for the INTEL FPGA NIOSV. diff --git a/soc/riscv/riscv-privileged/niosv/Kconfig.soc b/soc/riscv/intel_niosv/niosv/Kconfig.soc similarity index 100% rename from soc/riscv/riscv-privileged/niosv/Kconfig.soc rename to soc/riscv/intel_niosv/niosv/Kconfig.soc diff --git a/soc/riscv/riscv-privileged/niosv/linker.ld b/soc/riscv/intel_niosv/niosv/linker.ld similarity index 100% rename from soc/riscv/riscv-privileged/niosv/linker.ld rename to soc/riscv/intel_niosv/niosv/linker.ld diff --git a/soc/riscv/riscv-privileged/niosv/soc.h b/soc/riscv/intel_niosv/niosv/soc.h similarity index 100% rename from soc/riscv/riscv-privileged/niosv/soc.h rename to soc/riscv/intel_niosv/niosv/soc.h diff --git a/soc/riscv/riscv-privileged/Kconfig b/soc/riscv/riscv-privileged/Kconfig deleted file mode 100644 index b0700dd3440..00000000000 --- a/soc/riscv/riscv-privileged/Kconfig +++ /dev/null @@ -1,4 +0,0 @@ -# Copyright (c) 2017 Jean-Paul Etienne -# SPDX-License-Identifier: Apache-2.0 - -source "soc/riscv/riscv-privileged/*/Kconfig.soc" diff --git a/soc/riscv/riscv-privileged/Kconfig.defconfig b/soc/riscv/riscv-privileged/Kconfig.defconfig deleted file mode 100644 index 6793d72a385..00000000000 --- a/soc/riscv/riscv-privileged/Kconfig.defconfig +++ /dev/null @@ -1,6 +0,0 @@ -# riscv SOC family supporting the riscv privileged architecture spec - -# Copyright (c) 2017 Jean-Paul Etienne -# SPDX-License-Identifier: Apache-2.0 - -source "soc/riscv/riscv-privileged/*/Kconfig.defconfig.series" diff --git a/soc/riscv/riscv-privileged/Kconfig.soc b/soc/riscv/riscv-privileged/Kconfig.soc deleted file mode 100644 index 14d141223e0..00000000000 --- a/soc/riscv/riscv-privileged/Kconfig.soc +++ /dev/null @@ -1,6 +0,0 @@ -# riscv SOC series supporting the riscv privileged architecture spec - -# Copyright (c) 2017 Jean-Paul Etienne -# SPDX-License-Identifier: Apache-2.0 - -source "soc/riscv/riscv-privileged/*/Kconfig.series" From 724a967c1a170f181e4fccb974fb22127fb0d75a Mon Sep 17 00:00:00 2001 From: Gerard Marull-Paretas Date: Mon, 8 Jan 2024 14:13:06 +0100 Subject: [PATCH 1895/3723] soc: riscv: renove_virt: reorganize SoC folder Move out from riscv-privileged, and convert to a standalone SoC. Signed-off-by: Gerard Marull-Paretas --- boards/riscv/riscv32_virtual/riscv32_virtual_defconfig | 1 - .../{riscv-privileged => }/renode_virt/CMakeLists.txt | 0 .../Kconfig.defconfig} | 6 +++--- soc/riscv/{riscv-privileged => }/renode_virt/Kconfig.soc | 9 +++------ soc/riscv/{riscv-privileged => }/renode_virt/soc.h | 0 soc/riscv/riscv-privileged/renode_virt/Kconfig.series | 9 --------- 6 files changed, 6 insertions(+), 19 deletions(-) rename soc/riscv/{riscv-privileged => }/renode_virt/CMakeLists.txt (100%) rename soc/riscv/{riscv-privileged/renode_virt/Kconfig.defconfig.series => renode_virt/Kconfig.defconfig} (86%) rename soc/riscv/{riscv-privileged => }/renode_virt/Kconfig.soc (75%) rename soc/riscv/{riscv-privileged => }/renode_virt/soc.h (100%) delete mode 100644 soc/riscv/riscv-privileged/renode_virt/Kconfig.series diff --git a/boards/riscv/riscv32_virtual/riscv32_virtual_defconfig b/boards/riscv/riscv32_virtual/riscv32_virtual_defconfig index a905f99da2e..4dcad0a7ea1 100644 --- a/boards/riscv/riscv32_virtual/riscv32_virtual_defconfig +++ b/boards/riscv/riscv32_virtual/riscv32_virtual_defconfig @@ -1,7 +1,6 @@ # Copyright (c) 2023 Meta # SPDX-License-Identifier: Apache-2.0 -CONFIG_SOC_SERIES_RISCV32_VIRTUAL_RENODE=y CONFIG_SOC_RISCV32_VIRTUAL_RENODE=y CONFIG_BOARD_RISCV32_VIRTUAL=y CONFIG_CONSOLE=y diff --git a/soc/riscv/riscv-privileged/renode_virt/CMakeLists.txt b/soc/riscv/renode_virt/CMakeLists.txt similarity index 100% rename from soc/riscv/riscv-privileged/renode_virt/CMakeLists.txt rename to soc/riscv/renode_virt/CMakeLists.txt diff --git a/soc/riscv/riscv-privileged/renode_virt/Kconfig.defconfig.series b/soc/riscv/renode_virt/Kconfig.defconfig similarity index 86% rename from soc/riscv/riscv-privileged/renode_virt/Kconfig.defconfig.series rename to soc/riscv/renode_virt/Kconfig.defconfig index 09adc3d00e8..89e226edbb1 100644 --- a/soc/riscv/riscv-privileged/renode_virt/Kconfig.defconfig.series +++ b/soc/riscv/renode_virt/Kconfig.defconfig @@ -1,9 +1,9 @@ # Copyright (c) 2023 Meta # SPDX-License-Identifier: Apache-2.0 -if SOC_SERIES_RISCV32_VIRTUAL_RENODE +if SOC_RISCV32_VIRTUAL_RENODE -config SOC_SERIES +config SOC default "renode_virt" config SYS_CLOCK_HW_CYCLES_PER_SEC @@ -45,4 +45,4 @@ config MAX_IRQ_PER_AGGREGATOR config NUM_IRQS default 2058 -endif # SOC_SERIES_RISCV32_VIRTUAL_RENODE +endif # SOC_RISCV32_VIRTUAL_RENODE diff --git a/soc/riscv/riscv-privileged/renode_virt/Kconfig.soc b/soc/riscv/renode_virt/Kconfig.soc similarity index 75% rename from soc/riscv/riscv-privileged/renode_virt/Kconfig.soc rename to soc/riscv/renode_virt/Kconfig.soc index d123e797229..3e8af25099f 100644 --- a/soc/riscv/riscv-privileged/renode_virt/Kconfig.soc +++ b/soc/riscv/renode_virt/Kconfig.soc @@ -1,12 +1,11 @@ # Copyright (c) 2023 Meta # SPDX-License-Identifier: Apache-2.0 -choice - prompt "Renode RISCV32 Virtual system implementation" - depends on SOC_SERIES_RISCV32_VIRTUAL_RENODE - config SOC_RISCV32_VIRTUAL_RENODE bool "Renode RISCV32 Virtual system implementation" + select RISCV + select RISCV_PRIVILEGED + select RISCV_PRIVILEGED_STANDALONE select ATOMIC_OPERATIONS_BUILTIN select INCLUDE_RESET_VECTOR select RISCV_ISA_RV32I @@ -15,5 +14,3 @@ config SOC_RISCV32_VIRTUAL_RENODE select RISCV_ISA_EXT_C select RISCV_ISA_EXT_ZICSR select RISCV_ISA_EXT_ZIFENCEI - -endchoice diff --git a/soc/riscv/riscv-privileged/renode_virt/soc.h b/soc/riscv/renode_virt/soc.h similarity index 100% rename from soc/riscv/riscv-privileged/renode_virt/soc.h rename to soc/riscv/renode_virt/soc.h diff --git a/soc/riscv/riscv-privileged/renode_virt/Kconfig.series b/soc/riscv/riscv-privileged/renode_virt/Kconfig.series deleted file mode 100644 index 22e27cf38b4..00000000000 --- a/soc/riscv/riscv-privileged/renode_virt/Kconfig.series +++ /dev/null @@ -1,9 +0,0 @@ -# Copyright (c) 2023 Meta -# SPDX-License-Identifier: Apache-2.0 - -config SOC_SERIES_RISCV32_VIRTUAL_RENODE - bool "Renode RISC-V32 Virtual SoC implementation" - select RISCV - select SOC_FAMILY_RISCV_PRIVILEGED - help - Enable support for Renode RISC-V Virtual From 14ff171411901b994f2761a76af4baf17bcdab7b Mon Sep 17 00:00:00 2001 From: Gerard Marull-Paretas Date: Wed, 3 Jan 2024 17:39:38 +0100 Subject: [PATCH 1896/3723] soc: riscv: drop RISCV_PRIVILEGED_STANDALONE This option is no longer needed, all SoCs have been moved out from soc/riscv/riscv-privileged folder. Signed-off-by: Gerard Marull-Paretas --- soc/riscv/andes_v5/ae350/Kconfig.series | 1 - soc/riscv/common/riscv-privileged/Kconfig | 7 ------- soc/riscv/efinix_sapphire/Kconfig.soc | 1 - soc/riscv/gd_gd32/gd32vf103/Kconfig.series | 1 - soc/riscv/intel_niosv/niosv/Kconfig.series | 1 - soc/riscv/microchip_miv/miv/Kconfig.series | 1 - soc/riscv/microchip_miv/polarfire/Kconfig.series | 1 - soc/riscv/neorv32/Kconfig.soc | 1 - soc/riscv/opentitan/Kconfig.soc | 1 - soc/riscv/renode_virt/Kconfig.soc | 1 - soc/riscv/sifive_freedom/e300/Kconfig.series | 1 - soc/riscv/sifive_freedom/u500/Kconfig.series | 1 - soc/riscv/sifive_freedom/u700/Kconfig.series | 1 - soc/riscv/starfive_jh71xx/jh71xx/Kconfig.series | 1 - soc/riscv/telink_tlsr/tlsr951x/Kconfig.series | 1 - soc/riscv/virt/Kconfig.soc | 1 - 16 files changed, 22 deletions(-) diff --git a/soc/riscv/andes_v5/ae350/Kconfig.series b/soc/riscv/andes_v5/ae350/Kconfig.series index 4eb9557f92f..ebf68f7a3aa 100644 --- a/soc/riscv/andes_v5/ae350/Kconfig.series +++ b/soc/riscv/andes_v5/ae350/Kconfig.series @@ -5,7 +5,6 @@ config SOC_SERIES_ANDES_AE350 bool "Andes V5 AE350 SoC Series Implementation" select RISCV select RISCV_PRIVILEGED - select RISCV_PRIVILEGED_STANDALONE select SOC_FAMILY_ANDES_V5 help Enable support for Andes V5 AE350 SoC Series diff --git a/soc/riscv/common/riscv-privileged/Kconfig b/soc/riscv/common/riscv-privileged/Kconfig index de064842604..a4a8da0bf1f 100644 --- a/soc/riscv/common/riscv-privileged/Kconfig +++ b/soc/riscv/common/riscv-privileged/Kconfig @@ -4,13 +4,6 @@ # Copyright (c) 2017 Jean-Paul Etienne # SPDX-License-Identifier: Apache-2.0 -config RISCV_PRIVILEGED_STANDALONE - bool - -config SOC_FAMILY - string - default "riscv-privileged" if RISCV_PRIVILEGED && !RISCV_PRIVILEGED_STANDALONE - config RISCV_HAS_PLIC bool "Does the SOC provide support for a Platform Level Interrupt Controller (PLIC)" depends on RISCV_PRIVILEGED diff --git a/soc/riscv/efinix_sapphire/Kconfig.soc b/soc/riscv/efinix_sapphire/Kconfig.soc index 2cc5f3ba361..bf57d9cc541 100644 --- a/soc/riscv/efinix_sapphire/Kconfig.soc +++ b/soc/riscv/efinix_sapphire/Kconfig.soc @@ -12,4 +12,3 @@ config SOC_EFINIX_SAPPHIRE select RISCV_ISA_EXT_ZIFENCEI select RISCV select RISCV_PRIVILEGED - select RISCV_PRIVILEGED_STANDALONE diff --git a/soc/riscv/gd_gd32/gd32vf103/Kconfig.series b/soc/riscv/gd_gd32/gd32vf103/Kconfig.series index b0b86db7c02..e50567e0798 100644 --- a/soc/riscv/gd_gd32/gd32vf103/Kconfig.series +++ b/soc/riscv/gd_gd32/gd32vf103/Kconfig.series @@ -16,6 +16,5 @@ config SOC_SERIES_GD32VF103 select HAS_GD32_HAL select RISCV_HAS_CLIC select SOC_FAMILY_GD32 - select RISCV_PRIVILEGED_STANDALONE help Enable support for GigaDevice GD32VF1 series SoC diff --git a/soc/riscv/intel_niosv/niosv/Kconfig.series b/soc/riscv/intel_niosv/niosv/Kconfig.series index b8edc073916..9d7aa492692 100644 --- a/soc/riscv/intel_niosv/niosv/Kconfig.series +++ b/soc/riscv/intel_niosv/niosv/Kconfig.series @@ -5,7 +5,6 @@ config SOC_SERIES_NIOSV bool "INTEL FPGA NIOSV" select RISCV select RISCV_PRIVILEGED - select RISCV_PRIVILEGED_STANDALONE select SOC_FAMILY_INTEL_NIOSV help Enable support for the INTEL FPGA NIOSV. diff --git a/soc/riscv/microchip_miv/miv/Kconfig.series b/soc/riscv/microchip_miv/miv/Kconfig.series index 20430e6d0f9..2989876c0e0 100644 --- a/soc/riscv/microchip_miv/miv/Kconfig.series +++ b/soc/riscv/microchip_miv/miv/Kconfig.series @@ -8,6 +8,5 @@ config SOC_SERIES_MIV select SOC_FAMILY_MICROCHIP_MIV select RISCV select RISCV_PRIVILEGED - select RISCV_PRIVILEGED_STANDALONE help Enable support for Microchip Mi-V diff --git a/soc/riscv/microchip_miv/polarfire/Kconfig.series b/soc/riscv/microchip_miv/polarfire/Kconfig.series index 4bbceaee745..9001efc2858 100644 --- a/soc/riscv/microchip_miv/polarfire/Kconfig.series +++ b/soc/riscv/microchip_miv/polarfire/Kconfig.series @@ -8,6 +8,5 @@ config SOC_SERIES_POLARFIRE select SOC_FAMILY_MICROCHIP_MIV select RISCV select RISCV_PRIVILEGED - select RISCV_PRIVILEGED_STANDALONE help Enable support for Microchip RISCV 64bit diff --git a/soc/riscv/neorv32/Kconfig.soc b/soc/riscv/neorv32/Kconfig.soc index f07bba96574..3155d1b7c31 100644 --- a/soc/riscv/neorv32/Kconfig.soc +++ b/soc/riscv/neorv32/Kconfig.soc @@ -10,7 +10,6 @@ config SOC_NEORV32 select RISCV_ISA_EXT_ZICSR select RISCV_ISA_EXT_ZIFENCEI select RISCV_PRIVILEGED - select RISCV_PRIVILEGED_STANDALONE help Enable support for the NEORV32 Processor (SoC). diff --git a/soc/riscv/opentitan/Kconfig.soc b/soc/riscv/opentitan/Kconfig.soc index b482afce469..8270fde110d 100644 --- a/soc/riscv/opentitan/Kconfig.soc +++ b/soc/riscv/opentitan/Kconfig.soc @@ -19,4 +19,3 @@ config SOC_OPENTITAN # OpenTitan Ibex core mtvec mode is read-only / forced to vectored mode. select RISCV_VECTORED_MODE select GEN_IRQ_VECTOR_TABLE - select RISCV_PRIVILEGED_STANDALONE diff --git a/soc/riscv/renode_virt/Kconfig.soc b/soc/riscv/renode_virt/Kconfig.soc index 3e8af25099f..5aae660880a 100644 --- a/soc/riscv/renode_virt/Kconfig.soc +++ b/soc/riscv/renode_virt/Kconfig.soc @@ -5,7 +5,6 @@ config SOC_RISCV32_VIRTUAL_RENODE bool "Renode RISCV32 Virtual system implementation" select RISCV select RISCV_PRIVILEGED - select RISCV_PRIVILEGED_STANDALONE select ATOMIC_OPERATIONS_BUILTIN select INCLUDE_RESET_VECTOR select RISCV_ISA_RV32I diff --git a/soc/riscv/sifive_freedom/e300/Kconfig.series b/soc/riscv/sifive_freedom/e300/Kconfig.series index 066f8909d53..47ae89e6d4c 100644 --- a/soc/riscv/sifive_freedom/e300/Kconfig.series +++ b/soc/riscv/sifive_freedom/e300/Kconfig.series @@ -7,7 +7,6 @@ config SOC_SERIES_SIFIVE_FREEDOM_E300 bool "SiFive Freedom E300 SOC implementation" select RISCV select RISCV_PRIVILEGED - select RISCV_PRIVILEGED_STANDALONE select SOC_FAMILY_SIFIVE_FREEDOM help Enable support for SiFive Freedom FE300 SOC diff --git a/soc/riscv/sifive_freedom/u500/Kconfig.series b/soc/riscv/sifive_freedom/u500/Kconfig.series index 963a265f383..a576dfbc6f7 100644 --- a/soc/riscv/sifive_freedom/u500/Kconfig.series +++ b/soc/riscv/sifive_freedom/u500/Kconfig.series @@ -7,7 +7,6 @@ config SOC_SERIES_SIFIVE_FREEDOM_U500 bool "SiFive Freedom U500 SOC implementation" select RISCV select RISCV_PRIVILEGED - select RISCV_PRIVILEGED_STANDALONE select SOC_FAMILY_SIFIVE_FREEDOM help Enable support for SiFive Freedom U500 SOC diff --git a/soc/riscv/sifive_freedom/u700/Kconfig.series b/soc/riscv/sifive_freedom/u700/Kconfig.series index b4ca38697f8..613844703c7 100644 --- a/soc/riscv/sifive_freedom/u700/Kconfig.series +++ b/soc/riscv/sifive_freedom/u700/Kconfig.series @@ -7,7 +7,6 @@ config SOC_SERIES_SIFIVE_FREEDOM_U700 bool "SiFive Freedom SOC U700 implementation" select RISCV select RISCV_PRIVILEGED - select RISCV_PRIVILEGED_STANDALONE select SOC_FAMILY_SIFIVE_FREEDOM help Enable support for SiFive Freedom U700 SOC diff --git a/soc/riscv/starfive_jh71xx/jh71xx/Kconfig.series b/soc/riscv/starfive_jh71xx/jh71xx/Kconfig.series index d70cff1c63d..19cedcefe27 100644 --- a/soc/riscv/starfive_jh71xx/jh71xx/Kconfig.series +++ b/soc/riscv/starfive_jh71xx/jh71xx/Kconfig.series @@ -5,6 +5,5 @@ config SOC_SERIES_STARFIVE_JH71XX bool "Starfive JH71XX series" select RISCV select RISCV_PRIVILEGED - select RISCV_PRIVILEGED_STANDALONE help Enable support for Starfive JH71XX SoC Series. diff --git a/soc/riscv/telink_tlsr/tlsr951x/Kconfig.series b/soc/riscv/telink_tlsr/tlsr951x/Kconfig.series index e074a53e11b..5ad3053725e 100644 --- a/soc/riscv/telink_tlsr/tlsr951x/Kconfig.series +++ b/soc/riscv/telink_tlsr/tlsr951x/Kconfig.series @@ -16,6 +16,5 @@ config SOC_SERIES_TELINK_TLSR951X select CPU_HAS_FPU select INCLUDE_RESET_VECTOR select SOC_FAMILY_TELINK_TLSR - select RISCV_PRIVILEGED_STANDALONE help Enable support for Telink TLSR951X diff --git a/soc/riscv/virt/Kconfig.soc b/soc/riscv/virt/Kconfig.soc index fb615005b0a..9a9168f5a8c 100644 --- a/soc/riscv/virt/Kconfig.soc +++ b/soc/riscv/virt/Kconfig.soc @@ -10,4 +10,3 @@ config SOC_RISCV_VIRT select RISCV_ISA_EXT_C select RISCV select RISCV_PRIVILEGED - select RISCV_PRIVILEGED_STANDALONE From 37529505ad79aa5d863777ffa2c63593ea52f0a5 Mon Sep 17 00:00:00 2001 From: Anas Nashif Date: Mon, 18 Dec 2023 14:56:31 -0500 Subject: [PATCH 1897/3723] ztest: remove old file This c file is not being used anymore, so remove it. Signed-off-by: Anas Nashif --- subsys/testsuite/ztest/src/ztest_new.c | 1158 ------------------------ 1 file changed, 1158 deletions(-) delete mode 100644 subsys/testsuite/ztest/src/ztest_new.c diff --git a/subsys/testsuite/ztest/src/ztest_new.c b/subsys/testsuite/ztest/src/ztest_new.c deleted file mode 100644 index d49a1ef9c11..00000000000 --- a/subsys/testsuite/ztest/src/ztest_new.c +++ /dev/null @@ -1,1158 +0,0 @@ -/* - * Copyright (c) 2016 Intel Corporation - * - * SPDX-License-Identifier: Apache-2.0 - */ - -#include - -#include -#ifdef CONFIG_USERSPACE -#include -#endif -#include -#include - -#ifdef KERNEL -static struct k_thread ztest_thread; -#endif -static bool failed_expectation; - -#ifdef CONFIG_ZTEST_SHUFFLE -#include -#include - -#include -#define NUM_ITER_PER_SUITE CONFIG_ZTEST_SHUFFLE_SUITE_REPEAT_COUNT -#define NUM_ITER_PER_TEST CONFIG_ZTEST_SHUFFLE_TEST_REPEAT_COUNT -#else -#define NUM_ITER_PER_SUITE 1 -#define NUM_ITER_PER_TEST 1 -#endif - -/* ZTEST_DMEM and ZTEST_BMEM are used for the application shared memory test */ - -/** - * @brief The current status of the test binary - */ -enum ztest_status { - ZTEST_STATUS_OK, - ZTEST_STATUS_HAS_FAILURE, - ZTEST_STATUS_CRITICAL_ERROR -}; - -/** - * @brief Tracks the current phase that ztest is operating in. - */ -ZTEST_DMEM enum ztest_phase cur_phase = TEST_PHASE_FRAMEWORK; - -static ZTEST_BMEM enum ztest_status test_status = ZTEST_STATUS_OK; - -extern ZTEST_DMEM const struct ztest_arch_api ztest_api; - -static void __ztest_show_suite_summary(void); - -static void end_report(void) -{ - __ztest_show_suite_summary(); - if (test_status) { - TC_END_REPORT(TC_FAIL); - } else { - TC_END_REPORT(TC_PASS); - } -} - -static int cleanup_test(struct ztest_unit_test *test) -{ - int ret = TC_PASS; - int mock_status; - - mock_status = z_cleanup_mock(); - -#ifdef KERNEL - /* we need to remove the ztest_thread information from the timeout_q. - * Because we reuse the same k_thread structure this would - * causes some problems. - */ - if (IS_ENABLED(CONFIG_MULTITHREADING)) { - k_thread_abort(&ztest_thread); - } -#endif - - if (!ret && mock_status == 1) { - PRINT("Test %s failed: Unused mock parameter values\n", test->name); - ret = TC_FAIL; - } else if (!ret && mock_status == 2) { - PRINT("Test %s failed: Unused mock return values\n", test->name); - ret = TC_FAIL; - } else { - ; - } - - return ret; -} - -#ifdef KERNEL - -#if defined(CONFIG_SMP) && (CONFIG_MP_MAX_NUM_CPUS > 1) -#define MAX_NUM_CPUHOLD (CONFIG_MP_MAX_NUM_CPUS - 1) -#define CPUHOLD_STACK_SZ (512 + CONFIG_TEST_EXTRA_STACK_SIZE) -static struct k_thread cpuhold_threads[MAX_NUM_CPUHOLD]; -K_KERNEL_STACK_ARRAY_DEFINE(cpuhold_stacks, MAX_NUM_CPUHOLD, CPUHOLD_STACK_SZ); - -static struct k_sem cpuhold_sem; -volatile int cpuhold_active; - -/* "Holds" a CPU for use with the "1cpu" test cases. Note that we - * can't use tools like the cpumask feature because we have tests that - * may need to control that configuration themselves. We do this at - * the lowest level, but locking interrupts directly and spinning. - */ -static void cpu_hold(void *arg1, void *arg2, void *arg3) -{ - ARG_UNUSED(arg1); - ARG_UNUSED(arg2); - ARG_UNUSED(arg3); - - unsigned int key = arch_irq_lock(); - uint32_t dt, start_ms = k_uptime_get_32(); - - k_sem_give(&cpuhold_sem); - -#if (defined(CONFIG_ARM64) || defined(CONFIG_RISCV)) && defined(CONFIG_FPU_SHARING) - /* - * We'll be spinning with IRQs disabled. The flush-your-FPU request - * IPI will never be serviced during that time. Therefore we flush - * the FPU preemptively here to prevent any other CPU waiting after - * this CPU forever and deadlock the system. - */ - k_float_disable(_current_cpu->arch.fpu_owner); -#endif - - while (cpuhold_active) { - k_busy_wait(1000); - } - - /* Holding the CPU via spinning is expensive, and abusing this - * for long-running test cases tends to overload the CI system - * (qemu runs separate CPUs in different threads, but the CI - * logic views it as one "job") and cause other test failures. - */ - dt = k_uptime_get_32() - start_ms; - zassert_true(dt < CONFIG_ZTEST_CPU_HOLD_TIME_MS, - "1cpu test took too long (%d ms)", dt); - arch_irq_unlock(key); -} -#endif /* CONFIG_SMP && (CONFIG_MP_MAX_NUM_CPUS > 1) */ - -void z_impl_z_test_1cpu_start(void) -{ -#if defined(CONFIG_SMP) && (CONFIG_MP_MAX_NUM_CPUS > 1) - unsigned int num_cpus = arch_num_cpus(); - - cpuhold_active = 1; - char tname[CONFIG_THREAD_MAX_NAME_LEN]; - - k_sem_init(&cpuhold_sem, 0, 999); - - /* Spawn N-1 threads to "hold" the other CPUs, waiting for - * each to signal us that it's locked and spinning. - */ - for (int i = 0; i < num_cpus - 1; i++) { - k_thread_create(&cpuhold_threads[i], cpuhold_stacks[i], CPUHOLD_STACK_SZ, - cpu_hold, NULL, NULL, NULL, K_HIGHEST_THREAD_PRIO, - 0, K_NO_WAIT); - if (IS_ENABLED(CONFIG_THREAD_NAME)) { - snprintk(tname, CONFIG_THREAD_MAX_NAME_LEN, "cpuhold%02d", i); - k_thread_name_set(&cpuhold_threads[i], tname); - } - k_sem_take(&cpuhold_sem, K_FOREVER); - } -#endif -} - -void z_impl_z_test_1cpu_stop(void) -{ -#if defined(CONFIG_SMP) && (CONFIG_MP_MAX_NUM_CPUS > 1) - unsigned int num_cpus = arch_num_cpus(); - - cpuhold_active = 0; - - for (int i = 0; i < num_cpus - 1; i++) { - k_thread_abort(&cpuhold_threads[i]); - } -#endif -} - -#ifdef CONFIG_USERSPACE -void z_vrfy_z_test_1cpu_start(void) { z_impl_z_test_1cpu_start(); } -#include - -void z_vrfy_z_test_1cpu_stop(void) { z_impl_z_test_1cpu_stop(); } -#include -#endif /* CONFIG_USERSPACE */ -#endif - -__maybe_unused static void run_test_rules(bool is_before, struct ztest_unit_test *test, void *data) -{ - for (struct ztest_test_rule *rule = _ztest_test_rule_list_start; - rule < _ztest_test_rule_list_end; ++rule) { - if (is_before && rule->before_each) { - rule->before_each(test, data); - } else if (!is_before && rule->after_each) { - rule->after_each(test, data); - } - } -} - -static void run_test_functions(struct ztest_suite_node *suite, struct ztest_unit_test *test, - void *data) -{ - __ztest_set_test_phase(TEST_PHASE_TEST); - test->test(data); -} - -COND_CODE_1(KERNEL, (ZTEST_BMEM), ()) static enum ztest_result test_result; - -static int get_final_test_result(const struct ztest_unit_test *test, int ret) -{ - enum ztest_expected_result expected_result = -1; - - for (struct ztest_expected_result_entry *expectation = - _ztest_expected_result_entry_list_start; - expectation < _ztest_expected_result_entry_list_end; ++expectation) { - if (strcmp(expectation->test_name, test->name) == 0 && - strcmp(expectation->test_suite_name, test->test_suite_name) == 0) { - expected_result = expectation->expected_result; - break; - } - } - - if (expected_result == ZTEST_EXPECTED_RESULT_FAIL) { - /* Expected a failure: - * - If we got a failure, return TC_PASS - * - Otherwise force a failure - */ - return (ret == TC_FAIL) ? TC_PASS : TC_FAIL; - } - if (expected_result == ZTEST_EXPECTED_RESULT_SKIP) { - /* Expected a skip: - * - If we got a skip, return TC_PASS - * - Otherwise force a failure - */ - return (ret == TC_SKIP) ? TC_PASS : TC_FAIL; - } - /* No expectation was made, no change is needed. */ - return ret; -} - -/** - * @brief Get a friendly name string for a given test phrase. - * - * @param phase an enum ztest_phase value describing the desired test phase - * @returns a string name for `phase` - */ -static inline const char *get_friendly_phase_name(enum ztest_phase phase) -{ - switch (phase) { - case TEST_PHASE_SETUP: - return "setup"; - case TEST_PHASE_BEFORE: - return "before"; - case TEST_PHASE_TEST: - return "test"; - case TEST_PHASE_AFTER: - return "after"; - case TEST_PHASE_TEARDOWN: - return "teardown"; - case TEST_PHASE_FRAMEWORK: - return "framework"; - default: - return "(unknown)"; - } -} - -static bool current_test_failed_assumption; -void ztest_skip_failed_assumption(void) -{ - if (IS_ENABLED(CONFIG_ZTEST_FAIL_ON_ASSUME)) { - current_test_failed_assumption = true; - } - ztest_test_skip(); -} - -#ifndef KERNEL - -/* Static code analysis tool can raise a violation that the standard header - * shall not be used. - * - * setjmp is using in a test code, not in a runtime code, it is acceptable. - * It is a deliberate deviation. - */ -#include /* parasoft-suppress MISRAC2012-RULE_21_4-a MISRAC2012-RULE_21_4-b*/ -#include -#include -#include - -#define FAIL_FAST 0 - -static jmp_buf test_fail; -static jmp_buf test_pass; -static jmp_buf test_skip; -static jmp_buf stack_fail; -static jmp_buf test_suite_fail; - -void ztest_test_fail(void) -{ - switch (cur_phase) { - case TEST_PHASE_SETUP: - PRINT(" at %s function\n", get_friendly_phase_name(cur_phase)); - longjmp(test_suite_fail, 1); - case TEST_PHASE_BEFORE: - case TEST_PHASE_TEST: - PRINT(" at %s function\n", get_friendly_phase_name(cur_phase)); - longjmp(test_fail, 1); - case TEST_PHASE_AFTER: - case TEST_PHASE_TEARDOWN: - case TEST_PHASE_FRAMEWORK: - PRINT(" ERROR: cannot fail in test phase '%s()', bailing\n", - get_friendly_phase_name(cur_phase)); - longjmp(stack_fail, 1); - } -} - -void ztest_test_pass(void) -{ - if (cur_phase == TEST_PHASE_TEST) { - longjmp(test_pass, 1); - } - PRINT(" ERROR: cannot pass in test phase '%s()', bailing\n", - get_friendly_phase_name(cur_phase)); - longjmp(stack_fail, 1); -} - -void ztest_test_skip(void) -{ - switch (cur_phase) { - case TEST_PHASE_SETUP: - case TEST_PHASE_BEFORE: - case TEST_PHASE_TEST: - longjmp(test_skip, 1); - default: - PRINT(" ERROR: cannot skip in test phase '%s()', bailing\n", - get_friendly_phase_name(cur_phase)); - longjmp(stack_fail, 1); - } -} - -void ztest_test_expect_fail(void) -{ - failed_expectation = true; - - switch (cur_phase) { - case TEST_PHASE_SETUP: - PRINT(" at %s function\n", get_friendly_phase_name(cur_phase)); - break; - case TEST_PHASE_BEFORE: - case TEST_PHASE_TEST: - PRINT(" at %s function\n", get_friendly_phase_name(cur_phase)); - break; - case TEST_PHASE_AFTER: - case TEST_PHASE_TEARDOWN: - case TEST_PHASE_FRAMEWORK: - PRINT(" ERROR: cannot fail in test phase '%s()', bailing\n", - get_friendly_phase_name(cur_phase)); - longjmp(stack_fail, 1); - } -} - -static int run_test(struct ztest_suite_node *suite, struct ztest_unit_test *test, void *data) -{ - int ret = TC_PASS; - - TC_START(test->name); - __ztest_set_test_phase(TEST_PHASE_BEFORE); - - if (test_result == ZTEST_RESULT_SUITE_FAIL) { - ret = TC_FAIL; - goto out; - } - - if (setjmp(test_fail)) { - ret = TC_FAIL; - goto out; - } - - if (setjmp(test_pass)) { - ret = TC_PASS; - goto out; - } - - if (setjmp(test_skip)) { - ret = TC_SKIP; - goto out; - } - - run_test_rules(/*is_before=*/true, test, data); - if (suite->before) { - suite->before(data); - } - run_test_functions(suite, test, data); -out: - if (failed_expectation) { - failed_expectation = false; - ret = TC_FAIL; - } - - __ztest_set_test_phase(TEST_PHASE_AFTER); - if (test_result != ZTEST_RESULT_SUITE_FAIL) { - if (suite->after != NULL) { - suite->after(data); - } - run_test_rules(/*is_before=*/false, test, data); - } - __ztest_set_test_phase(TEST_PHASE_FRAMEWORK); - ret |= cleanup_test(test); - - ret = get_final_test_result(test, ret); - Z_TC_END_RESULT(ret, test->name); - if (ret == TC_SKIP && current_test_failed_assumption) { - test_status = 1; - } - - return ret; -} - -#else /* KERNEL */ - -/* Zephyr's probably going to cause all tests to fail if one test fails, so - * skip the rest of tests if one of them fails - */ -#ifdef CONFIG_ZTEST_FAIL_FAST -#define FAIL_FAST 1 -#else -#define FAIL_FAST 0 -#endif - -K_THREAD_STACK_DEFINE(ztest_thread_stack, CONFIG_ZTEST_STACK_SIZE + CONFIG_TEST_EXTRA_STACK_SIZE); - -static void test_finalize(void) -{ - if (IS_ENABLED(CONFIG_MULTITHREADING)) { - k_thread_abort(&ztest_thread); - if (k_is_in_isr()) { - return; - } - - k_thread_abort(k_current_get()); - CODE_UNREACHABLE; - } -} - -void ztest_test_fail(void) -{ - switch (cur_phase) { - case TEST_PHASE_SETUP: - __ztest_set_test_result(ZTEST_RESULT_SUITE_FAIL); - break; - case TEST_PHASE_BEFORE: - case TEST_PHASE_TEST: - __ztest_set_test_result(ZTEST_RESULT_FAIL); - test_finalize(); - break; - default: - PRINT(" ERROR: cannot fail in test phase '%s()', bailing\n", - get_friendly_phase_name(cur_phase)); - test_status = ZTEST_STATUS_CRITICAL_ERROR; - break; - } -} - -void ztest_test_pass(void) -{ - switch (cur_phase) { - case TEST_PHASE_TEST: - __ztest_set_test_result(ZTEST_RESULT_PASS); - test_finalize(); - break; - default: - PRINT(" ERROR: cannot pass in test phase '%s()', bailing\n", - get_friendly_phase_name(cur_phase)); - test_status = ZTEST_STATUS_CRITICAL_ERROR; - if (cur_phase == TEST_PHASE_BEFORE) { - test_finalize(); - } - } -} - -void ztest_test_skip(void) -{ - switch (cur_phase) { - case TEST_PHASE_SETUP: - __ztest_set_test_result(ZTEST_RESULT_SUITE_SKIP); - break; - case TEST_PHASE_BEFORE: - case TEST_PHASE_TEST: - __ztest_set_test_result(ZTEST_RESULT_SKIP); - test_finalize(); - break; - default: - PRINT(" ERROR: cannot skip in test phase '%s()', bailing\n", - get_friendly_phase_name(cur_phase)); - test_status = ZTEST_STATUS_CRITICAL_ERROR; - break; - } -} - -void ztest_test_expect_fail(void) -{ - failed_expectation = true; -} - -void ztest_simple_1cpu_before(void *data) -{ - ARG_UNUSED(data); - z_test_1cpu_start(); -} - -void ztest_simple_1cpu_after(void *data) -{ - ARG_UNUSED(data); - z_test_1cpu_stop(); -} - -static void test_cb(void *a, void *b, void *c) -{ - struct ztest_suite_node *suite = a; - struct ztest_unit_test *test = b; - const bool config_user_mode = FIELD_GET(K_USER, test->thread_options) != 0; - - if (!IS_ENABLED(CONFIG_USERSPACE) || !k_is_user_context()) { - __ztest_set_test_result(ZTEST_RESULT_PENDING); - run_test_rules(/*is_before=*/true, test, /*data=*/c); - if (suite->before) { - suite->before(/*data=*/c); - } - if (IS_ENABLED(CONFIG_USERSPACE) && config_user_mode) { - k_thread_user_mode_enter(test_cb, a, b, c); - } - } - run_test_functions(suite, test, c); - __ztest_set_test_result(ZTEST_RESULT_PASS); -} - -static int run_test(struct ztest_suite_node *suite, struct ztest_unit_test *test, void *data) -{ - int ret = TC_PASS; - -#if CONFIG_ZTEST_TEST_DELAY_MS > 0 - k_busy_wait(CONFIG_ZTEST_TEST_DELAY_MS * USEC_PER_MSEC); -#endif - TC_START(test->name); - - __ztest_set_test_phase(TEST_PHASE_BEFORE); - - /* If the suite's setup function marked us as skipped, don't bother - * running the tests. - */ - if (IS_ENABLED(CONFIG_MULTITHREADING)) { - get_start_time_cyc(); - k_thread_create(&ztest_thread, ztest_thread_stack, - K_THREAD_STACK_SIZEOF(ztest_thread_stack), - test_cb, suite, test, data, - CONFIG_ZTEST_THREAD_PRIORITY, - K_INHERIT_PERMS, K_FOREVER); - - k_thread_access_grant(&ztest_thread, suite, test, suite->stats); - if (test->name != NULL) { - k_thread_name_set(&ztest_thread, test->name); - } - /* Only start the thread if we're not skipping the suite */ - if (test_result != ZTEST_RESULT_SUITE_SKIP && - test_result != ZTEST_RESULT_SUITE_FAIL) { - k_thread_start(&ztest_thread); - k_thread_join(&ztest_thread, K_FOREVER); - } - } else if (test_result != ZTEST_RESULT_SUITE_SKIP && - test_result != ZTEST_RESULT_SUITE_FAIL) { - __ztest_set_test_result(ZTEST_RESULT_PENDING); - get_start_time_cyc(); - run_test_rules(/*is_before=*/true, test, data); - if (suite->before) { - suite->before(data); - } - run_test_functions(suite, test, data); - } - - __ztest_set_test_phase(TEST_PHASE_AFTER); - if (suite->after != NULL) { - suite->after(data); - } - run_test_rules(/*is_before=*/false, test, data); - - get_test_duration_ms(); - if (tc_spend_time > test->stats->duration_worst_ms) { - test->stats->duration_worst_ms = tc_spend_time; - } - - __ztest_set_test_phase(TEST_PHASE_FRAMEWORK); - - /* Flush all logs in case deferred mode and default logging thread are used. */ - while (IS_ENABLED(CONFIG_TEST_LOGGING_FLUSH_AFTER_TEST) && - IS_ENABLED(CONFIG_LOG_PROCESS_THREAD) && log_data_pending()) { - k_msleep(100); - } - - if (test_result == ZTEST_RESULT_FAIL || test_result == ZTEST_RESULT_SUITE_FAIL || - failed_expectation) { - ret = TC_FAIL; - failed_expectation = false; - } else if (test_result == ZTEST_RESULT_SKIP || test_result == ZTEST_RESULT_SUITE_SKIP) { - ret = TC_SKIP; - } - - if (test_result == ZTEST_RESULT_PASS || !FAIL_FAST) { - ret |= cleanup_test(test); - } - - ret = get_final_test_result(test, ret); - Z_TC_END_RESULT(ret, test->name); - if (ret == TC_SKIP && current_test_failed_assumption) { - test_status = 1; - } - - return ret; -} - -#endif /* !KERNEL */ - -static struct ztest_suite_node *ztest_find_test_suite(const char *name) -{ - struct ztest_suite_node *node; - - for (node = _ztest_suite_node_list_start; node < _ztest_suite_node_list_end; ++node) { - if (strcmp(name, node->name) == 0) { - return node; - } - } - - return NULL; -} - -struct ztest_unit_test *z_ztest_get_next_test(const char *suite, struct ztest_unit_test *prev) -{ - struct ztest_unit_test *test = (prev == NULL) ? _ztest_unit_test_list_start : prev + 1; - - for (; test < _ztest_unit_test_list_end; ++test) { - if (strcmp(suite, test->test_suite_name) == 0) { - return test; - } - } - return NULL; -} - -#ifdef CONFIG_ZTEST_SHUFFLE -static void z_ztest_shuffle(void *dest[], intptr_t start, size_t num_items, size_t element_size) -{ - void *tmp; - - /* Initialize dest array */ - for (size_t i = 0; i < num_items; ++i) { - dest[i] = (void *)(start + (i * element_size)); - } - - /* Shuffle dest array */ - for (size_t i = num_items - 1; i > 0; i--) { - int j = sys_rand32_get() % (i + 1); - - if (i != j) { - tmp = dest[j]; - dest[j] = dest[i]; - dest[i] = tmp; - } - } -} -#endif /* CONFIG_ZTEST_SHUFFLE */ - -static int z_ztest_run_test_suite_ptr(struct ztest_suite_node *suite) -{ - struct ztest_unit_test *test = NULL; - void *data = NULL; - int fail = 0; - int tc_result = TC_PASS; - - if (FAIL_FAST && test_status != ZTEST_STATUS_OK) { - return test_status; - } - - if (suite == NULL) { - test_status = ZTEST_STATUS_CRITICAL_ERROR; - return -1; - } - -#ifndef KERNEL - if (setjmp(stack_fail)) { - PRINT("TESTSUITE crashed.\n"); - test_status = ZTEST_STATUS_CRITICAL_ERROR; - end_report(); - exit(1); - } -#else - k_object_access_all_grant(&ztest_thread); -#endif - - TC_SUITE_START(suite->name); - current_test_failed_assumption = false; - __ztest_set_test_result(ZTEST_RESULT_PENDING); - __ztest_set_test_phase(TEST_PHASE_SETUP); -#ifndef KERNEL - if (setjmp(test_suite_fail)) { - __ztest_set_test_result(ZTEST_RESULT_SUITE_FAIL); - } -#endif - if (test_result != ZTEST_RESULT_SUITE_FAIL && suite->setup != NULL) { - data = suite->setup(); - } - - for (int i = 0; i < NUM_ITER_PER_TEST; i++) { - fail = 0; - -#ifdef CONFIG_ZTEST_SHUFFLE - struct ztest_unit_test *tests_to_run[ZTEST_TEST_COUNT]; - - memset(tests_to_run, 0, ZTEST_TEST_COUNT * sizeof(struct ztest_unit_test *)); - z_ztest_shuffle((void **)tests_to_run, (intptr_t)_ztest_unit_test_list_start, - ZTEST_TEST_COUNT, sizeof(struct ztest_unit_test)); - for (size_t j = 0; j < ZTEST_TEST_COUNT; ++j) { - test = tests_to_run[j]; - /* Make sure that the test belongs to this suite */ - if (strcmp(suite->name, test->test_suite_name) != 0) { - continue; - } - if (ztest_api.should_test_run(suite->name, test->name)) { - test->stats->run_count++; - tc_result = run_test(suite, test, data); - if (tc_result == TC_PASS) { - test->stats->pass_count++; - } else if (tc_result == TC_SKIP) { - test->stats->skip_count++; - } else if (tc_result == TC_FAIL) { - test->stats->fail_count++; - } - if (tc_result == TC_FAIL) { - fail++; - } - } - - if ((fail && FAIL_FAST) || test_status == ZTEST_STATUS_CRITICAL_ERROR) { - break; - } - } -#else - while (((test = z_ztest_get_next_test(suite->name, test)) != NULL)) { - if (ztest_api.should_test_run(suite->name, test->name)) { - test->stats->run_count++; - tc_result = run_test(suite, test, data); - if (tc_result == TC_PASS) { - test->stats->pass_count++; - } else if (tc_result == TC_SKIP) { - test->stats->skip_count++; - } else if (tc_result == TC_FAIL) { - test->stats->fail_count++; - } - - if (tc_result == TC_FAIL) { - fail++; - } - } - - if ((fail && FAIL_FAST) || test_status == ZTEST_STATUS_CRITICAL_ERROR) { - break; - } - } -#endif - - if (test_status == ZTEST_STATUS_OK && fail != 0) { - test_status = ZTEST_STATUS_HAS_FAILURE; - } - } - - TC_SUITE_END(suite->name, (fail > 0 ? TC_FAIL : TC_PASS)); - __ztest_set_test_phase(TEST_PHASE_TEARDOWN); - if (suite->teardown != NULL) { - suite->teardown(data); - } - - return fail; -} - -int z_ztest_run_test_suite(const char *name) -{ - return z_ztest_run_test_suite_ptr(ztest_find_test_suite(name)); -} - -#ifdef CONFIG_USERSPACE -K_APPMEM_PARTITION_DEFINE(ztest_mem_partition); -#endif - -static void __ztest_init_unit_test_result_for_suite(struct ztest_suite_node *suite) -{ - struct ztest_unit_test *test = NULL; - - while (((test = z_ztest_get_next_test(suite->name, test)) != NULL)) { - test->stats->run_count = 0; - test->stats->skip_count = 0; - test->stats->fail_count = 0; - test->stats->pass_count = 0; - test->stats->duration_worst_ms = 0; - } -} - -static void flush_log(void) -{ - if (IS_ENABLED(CONFIG_LOG_PROCESS_THREAD)) { - while (log_data_pending()) { - k_sleep(K_MSEC(10)); - } - k_sleep(K_MSEC(10)); - } else { - while (LOG_PROCESS()) { - } - } -} - -/* Show one line summary for a test suite. - */ -static void __ztest_show_suite_summary_oneline(struct ztest_suite_node *suite) -{ - int distinct_pass = 0, distinct_fail = 0, distinct_skip = 0, distinct_total = 0; - int effective_total = 0; - int expanded_pass = 0, expanded_passrate = 0; - int passrate_major = 0, passrate_minor = 0, passrate_tail = 0; - int suite_result = TC_PASS; - - struct ztest_unit_test *test = NULL; - unsigned int suite_duration_worst_ms = 0; - - /** summary of disctinct run */ - while (((test = z_ztest_get_next_test(suite->name, test)) != NULL)) { - distinct_total++; - suite_duration_worst_ms += test->stats->duration_worst_ms; - if (test->stats->skip_count == test->stats->run_count) { - distinct_skip++; - } else if (test->stats->pass_count == test->stats->run_count) { - distinct_pass++; - } else { - distinct_fail++; - } - } - - if (distinct_skip == distinct_total) { - suite_result = TC_SKIP; - passrate_major = passrate_minor = 0; - } else { - suite_result = (distinct_fail > 0) ? TC_FAIL : TC_PASS; - effective_total = distinct_total - distinct_skip; - expanded_pass = distinct_pass * 100000; - expanded_passrate = expanded_pass / effective_total; - passrate_major = expanded_passrate / 1000; - passrate_minor = (expanded_passrate - passrate_major * 1000) / 10; - passrate_tail = expanded_passrate - passrate_major * 1000 - passrate_minor * 10; - if (passrate_tail >= 5) { /* rounding */ - passrate_minor++; - } - } - - TC_SUMMARY_PRINT("SUITE %s - %3d.%02d%% [%s]: pass = %d, fail = %d, " - "skip = %d, total = %d duration = %u.%03u seconds\n", - TC_RESULT_TO_STR(suite_result), - passrate_major, passrate_minor, - suite->name, distinct_pass, distinct_fail, - distinct_skip, distinct_total, - suite_duration_worst_ms / 1000, suite_duration_worst_ms % 1000); - flush_log(); -} - -static void __ztest_show_suite_summary_verbose(struct ztest_suite_node *suite) -{ - struct ztest_unit_test *test = NULL; - int tc_result = TC_PASS; - int flush_frequency = 0; - - if (IS_ENABLED(CONFIG_ZTEST_VERBOSE_SUMMARY) == 0) { - return; - } - - while (((test = z_ztest_get_next_test(suite->name, test)) != NULL)) { - if (test->stats->skip_count == test->stats->run_count) { - tc_result = TC_SKIP; - } else if (test->stats->pass_count == test->stats->run_count) { - tc_result = TC_PASS; - } else if (test->stats->pass_count == 0) { - tc_result = TC_FAIL; - } else { - tc_result = TC_FLAKY; - } - - if (tc_result == TC_FLAKY) { - TC_SUMMARY_PRINT(" - %s - [%s.%s] - (Failed %d of %d attempts)" - " - duration = %u.%03u seconds\n", - TC_RESULT_TO_STR(tc_result), - test->test_suite_name, test->name, - test->stats->run_count - test->stats->pass_count, - test->stats->run_count, - test->stats->duration_worst_ms / 1000, - test->stats->duration_worst_ms % 1000); - } else { - TC_SUMMARY_PRINT(" - %s - [%s.%s] duration = %u.%03u seconds\n", - TC_RESULT_TO_STR(tc_result), - test->test_suite_name, test->name, - test->stats->duration_worst_ms / 1000, - test->stats->duration_worst_ms % 1000); - } - - if (flush_frequency % 3 == 0) { - /** Reduce the flush frequencey a bit to speed up the output */ - flush_log(); - } - flush_frequency++; - } - TC_SUMMARY_PRINT("\n"); - flush_log(); -} - -static void __ztest_show_suite_summary(void) -{ - if (IS_ENABLED(CONFIG_ZTEST_SUMMARY) == 0) { - return; - } - /* Flush the log a lot to ensure that no summary content - * is dropped if it goes through the logging subsystem. - */ - flush_log(); - TC_SUMMARY_PRINT("\n------ TESTSUITE SUMMARY START ------\n\n"); - flush_log(); - for (struct ztest_suite_node *ptr = _ztest_suite_node_list_start; - ptr < _ztest_suite_node_list_end; ++ptr) { - - __ztest_show_suite_summary_oneline(ptr); - __ztest_show_suite_summary_verbose(ptr); - } - TC_SUMMARY_PRINT("------ TESTSUITE SUMMARY END ------\n\n"); - flush_log(); -} - -static int __ztest_run_test_suite(struct ztest_suite_node *ptr, const void *state) -{ - struct ztest_suite_stats *stats = ptr->stats; - int count = 0; - - for (int i = 0; i < NUM_ITER_PER_SUITE; i++) { - if (ztest_api.should_suite_run(state, ptr)) { - int fail = z_ztest_run_test_suite_ptr(ptr); - - count++; - stats->run_count++; - stats->fail_count += (fail != 0) ? 1 : 0; - } else { - stats->skip_count++; - } - } - - return count; -} - -int z_impl_ztest_run_test_suites(const void *state) -{ - int count = 0; - - if (test_status == ZTEST_STATUS_CRITICAL_ERROR) { - return count; - } - -#ifdef CONFIG_ZTEST_SHUFFLE - struct ztest_suite_node *suites_to_run[ZTEST_SUITE_COUNT]; - - memset(suites_to_run, 0, ZTEST_SUITE_COUNT * sizeof(struct ztest_suite_node *)); - z_ztest_shuffle((void **)suites_to_run, (intptr_t)_ztest_suite_node_list_start, - ZTEST_SUITE_COUNT, sizeof(struct ztest_suite_node)); - for (size_t i = 0; i < ZTEST_SUITE_COUNT; ++i) { - __ztest_init_unit_test_result_for_suite(suites_to_run[i]); - } - for (size_t i = 0; i < ZTEST_SUITE_COUNT; ++i) { - count += __ztest_run_test_suite(suites_to_run[i], state); - /* Stop running tests if we have a critical error or if we have a failure and - * FAIL_FAST was set - */ - if (test_status == ZTEST_STATUS_CRITICAL_ERROR || - (test_status == ZTEST_STATUS_HAS_FAILURE && FAIL_FAST)) { - break; - } - } -#else - for (struct ztest_suite_node *ptr = _ztest_suite_node_list_start; - ptr < _ztest_suite_node_list_end; ++ptr) { - __ztest_init_unit_test_result_for_suite(ptr); - count += __ztest_run_test_suite(ptr, state); - /* Stop running tests if we have a critical error or if we have a failure and - * FAIL_FAST was set - */ - if (test_status == ZTEST_STATUS_CRITICAL_ERROR || - (test_status == ZTEST_STATUS_HAS_FAILURE && FAIL_FAST)) { - break; - } - } -#endif - - return count; -} - -void z_impl___ztest_set_test_result(enum ztest_result new_result) -{ - test_result = new_result; -} - -void z_impl___ztest_set_test_phase(enum ztest_phase new_phase) -{ - cur_phase = new_phase; -} - -#ifdef CONFIG_USERSPACE -void z_vrfy___ztest_set_test_result(enum ztest_result new_result) -{ - z_impl___ztest_set_test_result(new_result); -} -#include - -void z_vrfy___ztest_set_test_phase(enum ztest_phase new_phase) -{ - z_impl___ztest_set_test_phase(new_phase); -} -#include -#endif /* CONFIG_USERSPACE */ - -void ztest_verify_all_test_suites_ran(void) -{ - bool all_tests_run = true; - struct ztest_suite_node *suite; - struct ztest_unit_test *test; - - if (IS_ENABLED(CONFIG_ZTEST_VERIFY_RUN_ALL)) { - for (suite = _ztest_suite_node_list_start; suite < _ztest_suite_node_list_end; - ++suite) { - if (suite->stats->run_count < 1) { - PRINT("ERROR: Test suite '%s' did not run.\n", suite->name); - all_tests_run = false; - } - } - - for (test = _ztest_unit_test_list_start; test < _ztest_unit_test_list_end; ++test) { - suite = ztest_find_test_suite(test->test_suite_name); - if (suite == NULL) { - PRINT("ERROR: Test '%s' assigned to test suite '%s' which doesn't " - "exist\n", - test->name, test->test_suite_name); - all_tests_run = false; - } - } - - if (!all_tests_run) { - test_status = ZTEST_STATUS_HAS_FAILURE; - } - } - - for (test = _ztest_unit_test_list_start; test < _ztest_unit_test_list_end; ++test) { - if (test->stats->fail_count + test->stats->pass_count + test->stats->skip_count != - test->stats->run_count) { - PRINT("Bad stats for %s.%s\n", test->test_suite_name, test->name); - test_status = 1; - } - } -} - -void ztest_run_all(const void *state) { ztest_api.run_all(state); } - -void __weak test_main(void) -{ - ztest_run_all(NULL); - - ztest_verify_all_test_suites_ran(); -} - -#ifndef KERNEL -int main(void) -{ - z_init_mock(); - test_main(); - end_report(); -#ifdef CONFIG_ZTEST_NO_YIELD - /* - * Rather than yielding to idle thread, keep the part awake so debugger can - * still access it, since some SOCs cannot be debugged in low power states. - */ - uint32_t key = irq_lock(); - - while (1) { - ; /* Spin */ - } - irq_unlock(key); -#endif - return test_status; -} -#else -int main(void) -{ -#ifdef CONFIG_USERSPACE - /* Partition containing globals tagged with ZTEST_DMEM and ZTEST_BMEM - * macros. Any variables that user code may reference need to be - * placed in this partition if no other memory domain configuration - * is made. - */ - k_mem_domain_add_partition(&k_mem_domain_default, &ztest_mem_partition); -#ifdef Z_MALLOC_PARTITION_EXISTS - /* Allow access to malloc() memory */ - k_mem_domain_add_partition(&k_mem_domain_default, &z_malloc_partition); -#endif -#endif /* CONFIG_USERSPACE */ - - z_init_mock(); - test_main(); - end_report(); - flush_log(); - LOG_PANIC(); - if (IS_ENABLED(CONFIG_ZTEST_RETEST_IF_PASSED)) { - static __noinit struct { - uint32_t magic; - uint32_t boots; - } state; - const uint32_t magic = 0x152ac523; - - if (state.magic != magic) { - state.magic = magic; - state.boots = 0; - } - state.boots += 1; - if (test_status == 0) { - PRINT("Reset board #%u to test again\n", state.boots); - k_msleep(10); - sys_reboot(SYS_REBOOT_COLD); - } else { - PRINT("Failed after %u attempts\n", state.boots); - state.boots = 0; - } - } -#ifdef CONFIG_ZTEST_NO_YIELD - /* - * Rather than yielding to idle thread, keep the part awake so debugger can - * still access it, since some SOCs cannot be debugged in low power states. - */ - uint32_t key = irq_lock(); - - while (1) { - ; /* Spin */ - } - irq_unlock(key); -#endif - return 0; -} -#endif From 6ba0e9c79723e42a3c315380f586854d481d1e91 Mon Sep 17 00:00:00 2001 From: Anas Nashif Date: Wed, 20 Dec 2023 13:05:32 -0500 Subject: [PATCH 1898/3723] tests: sleep: reduce verbosity Reduce verbosity and debug messages on the screen. Signed-off-by: Anas Nashif --- tests/kernel/sleep/src/main.c | 11 ----------- tests/kernel/sleep/src/usleep.c | 1 - 2 files changed, 12 deletions(-) diff --git a/tests/kernel/sleep/src/main.c b/tests/kernel/sleep/src/main.c index 89da43b82ca..9ef991b8647 100644 --- a/tests/kernel/sleep/src/main.c +++ b/tests/kernel/sleep/src/main.c @@ -72,8 +72,6 @@ static void test_objects_init(void) k_sem_init(&test_thread_sem, 0, UINT_MAX); k_sem_init(&helper_thread_sem, 0, UINT_MAX); k_sem_init(&task_sem, 0, UINT_MAX); - - TC_PRINT("Kernel objects initialized\n"); } static void align_to_tick_boundary(void) @@ -111,7 +109,6 @@ static void test_thread(void *p1, void *p2, void *p3) k_sem_take(&test_thread_sem, K_FOREVER); - TC_PRINT("Testing normal expiration of k_sleep()\n"); align_to_tick_boundary(); start_tick = k_uptime_get_32(); @@ -125,7 +122,6 @@ static void test_thread(void *p1, void *p2, void *p3) return; } - TC_PRINT("Testing: test thread sleep + helper thread wakeup test\n"); k_sem_give(&helper_thread_sem); /* Activate helper thread */ align_to_tick_boundary(); @@ -139,7 +135,6 @@ static void test_thread(void *p1, void *p2, void *p3) return; } - TC_PRINT("Testing: test thread sleep + isr offload wakeup test\n"); k_sem_give(&helper_thread_sem); /* Activate helper thread */ align_to_tick_boundary(); @@ -153,7 +148,6 @@ static void test_thread(void *p1, void *p2, void *p3) return; } - TC_PRINT("Testing: test thread sleep + main wakeup test thread\n"); k_sem_give(&task_sem); /* Activate task */ align_to_tick_boundary(); @@ -216,16 +210,12 @@ ZTEST(sleep, test_sleep) 0, 0, NULL, TEST_THREAD_PRIORITY, 0, K_NO_WAIT); - TC_PRINT("Test thread started: id = %p\n", test_thread_id); - helper_thread_id = k_thread_create(&helper_thread_data, helper_thread_stack, THREAD_STACK, helper_thread, 0, 0, NULL, HELPER_THREAD_PRIORITY, 0, K_NO_WAIT); - TC_PRINT("Helper thread started: id = %p\n", helper_thread_id); - /* Activate test_thread */ k_sem_give(&test_thread_sem); @@ -237,7 +227,6 @@ ZTEST(sleep, test_sleep) zassert_false(test_failure, "test failure"); - TC_PRINT("Testing kernel k_sleep()\n"); align_to_tick_boundary(); start_tick = k_uptime_get_32(); k_sleep(K_SECONDS(1)); diff --git a/tests/kernel/sleep/src/usleep.c b/tests/kernel/sleep/src/usleep.c index 67037e593c9..b7c1144505a 100644 --- a/tests/kernel/sleep/src/usleep.c +++ b/tests/kernel/sleep/src/usleep.c @@ -89,7 +89,6 @@ ZTEST_USER(sleep, test_usleep) } } - printk("elapsed_ms = %" PRId64 "\n", elapsed_ms); zassert_true(elapsed_ms >= LOWER_BOUND_MS, "short sleep"); zassert_true(elapsed_ms <= UPPER_BOUND_MS, "overslept"); } From afc319e3fa8547607a5715dda57bba073ce72cf7 Mon Sep 17 00:00:00 2001 From: Anas Nashif Date: Mon, 18 Dec 2023 16:02:18 -0500 Subject: [PATCH 1899/3723] ztest: shell: add shell support - Support for listing both testcases and testsuites - Support for running single suites or single test cases - Support shuffling tests and repeating execution based on command line arguments. For example, build with west build -p -b qemu_cortex_m3 tests/kernel/sleep -t run -- \ -DCONFIG_ZTEST_SHUFFLE=y -DCONFIG_ZTEST_SHELL=y Following commands are available: uart:~$ ztest ztest - Ztest commands Subcommands: run-all :Run all tests shuffle :Shuffle tests list-testsuites :List all test suites list-testcases :List all test cases run-testsuite :Run test suite run-testcase :Run testcase shuffle accepts two arguments --suite_iter and --case_iter which allows repeated exercution of testcases or suites. Signed-off-by: Anas Nashif --- doc/develop/test/ztest.rst | 6 +- subsys/testsuite/ztest/CMakeLists.txt | 2 + subsys/testsuite/ztest/Kconfig | 9 + .../ztest/include/zephyr/ztest_test.h | 30 +- subsys/testsuite/ztest/src/ztest.c | 259 +++++++++++++++--- subsys/testsuite/ztest/src/ztest_defaults.c | 4 +- subsys/testsuite/ztest/src/ztest_posix.c | 6 +- subsys/testsuite/ztest/src/ztest_shell.c | 152 ++++++++++ .../host/keys/bt_keys_get_addr/src/main.c | 4 +- tests/drivers/eeprom/api/src/main.c | 2 +- tests/kernel/threads/thread_apis/src/main.c | 4 +- .../mgmt/mcumgr/cb_notifications/src/main.c | 2 +- .../mgmt/mcumgr/os_mgmt_datetime/src/main.c | 2 +- .../mgmt/mcumgr/os_mgmt_info/src/main.c | 2 +- tests/ztest/error_hook/src/main.c | 2 +- 15 files changed, 427 insertions(+), 59 deletions(-) create mode 100644 subsys/testsuite/ztest/src/ztest_shell.c diff --git a/doc/develop/test/ztest.rst b/doc/develop/test/ztest.rst index f9255ecad2a..c2d7cd0923e 100644 --- a/doc/develop/test/ztest.rst +++ b/doc/develop/test/ztest.rst @@ -197,15 +197,15 @@ function can be written as follows: /* Only suites that use a predicate checking for phase == PWR_PHASE_0 will run. */ state.phase = PWR_PHASE_0; - ztest_run_all(&state); + ztest_run_all(&state, false, 1, 1); /* Only suites that use a predicate checking for phase == PWR_PHASE_1 will run. */ state.phase = PWR_PHASE_1; - ztest_run_all(&state); + ztest_run_all(&state, false, 1, 1); /* Only suites that use a predicate checking for phase == PWR_PHASE_2 will run. */ state.phase = PWR_PHASE_2; - ztest_run_all(&state); + ztest_run_all(&state, false, 1, 1); /* Check that all the suites in this binary ran at least once. */ ztest_verify_all_test_suites_ran(); diff --git a/subsys/testsuite/ztest/CMakeLists.txt b/subsys/testsuite/ztest/CMakeLists.txt index 7817bc2f30b..4d29ac033c3 100644 --- a/subsys/testsuite/ztest/CMakeLists.txt +++ b/subsys/testsuite/ztest/CMakeLists.txt @@ -26,6 +26,8 @@ zephyr_library_sources_ifdef(CONFIG_ZTRESS src/ztress.c) if(CONFIG_ARCH_POSIX) zephyr_library_sources(src/ztest_posix.c) +elseif(CONFIG_ZTEST_SHELL) + zephyr_library_sources(src/ztest_shell.c) else() zephyr_library_sources(src/ztest_defaults.c) endif() diff --git a/subsys/testsuite/ztest/Kconfig b/subsys/testsuite/ztest/Kconfig index 977f882d838..e453d286463 100644 --- a/subsys/testsuite/ztest/Kconfig +++ b/subsys/testsuite/ztest/Kconfig @@ -23,6 +23,15 @@ config ZTEST_TEST_DELAY_MS Add a delay between between tests to manage output on the console on systems that can't handle the rapid output rate. +config ZTEST_SHELL + bool "Ztest with shell support" + select SHELL + select SHELL_THREAD_PRIORITY_OVERRIDE + select GETOPT_LONG + select SHELL_GETOPT + help + Enable shell to manage test execution and selection. + config ZTEST_CPU_HOLD_TIME_MS int "Time in milliseconds to hold other CPUs for 1cpu type tests" default 3000 diff --git a/subsys/testsuite/ztest/include/zephyr/ztest_test.h b/subsys/testsuite/ztest/include/zephyr/ztest_test.h index aac7a7b2ad8..120848f26a7 100644 --- a/subsys/testsuite/ztest/include/zephyr/ztest_test.h +++ b/subsys/testsuite/ztest/include/zephyr/ztest_test.h @@ -232,8 +232,11 @@ extern struct ztest_suite_node _ztest_suite_node_list_end[]; * Default entry point for running or listing registered unit tests. * * @param state The current state of the machine as it relates to the test executable. + * @param shuffle Shuffle tests + * @param suite_iter Test suite repetitions. + * @param case_iter Test case repetitions. */ -void ztest_run_all(const void *state); +void ztest_run_all(const void *state, bool shuffle, int suite_iter, int case_iter); /** * The result of the current running test. It's possible that the setup function sets the result @@ -265,18 +268,25 @@ enum ztest_phase { * Run the registered unit tests which return true from their predicate function. * * @param state The current state of the machine as it relates to the test executable. + * @param shuffle Shuffle tests + * @param suite_iter Test suite repetitions. + * @param case_iter Test case repetitions. * @return The number of tests that ran. */ #ifdef ZTEST_UNITTEST -int z_impl_ztest_run_test_suites(const void *state); -static inline int ztest_run_test_suites(const void *state) +int z_impl_ztest_run_test_suites(const void *state, bool shuffle, + int suite_iter, int case_iter); + +static inline int ztest_run_test_suites(const void *state, bool shuffle, + int suite_iter, int case_iter) { - return z_impl_ztest_run_test_suites(state); + return z_impl_ztest_run_test_suites(state, shuffle, suite_iter, case_iter); } #else -__syscall int ztest_run_test_suites(const void *state); +__syscall int ztest_run_test_suites(const void *state, bool shuffle, + int suite_iter, int case_iter); #endif #ifdef ZTEST_UNITTEST @@ -315,9 +325,12 @@ void ztest_verify_all_test_suites_ran(void); * checks for fast failures and initialization. * * @param name The name of the suite to run. + * @param shuffle Shuffle tests + * @param suite_iter Test suite repetitions. + * @param case_iter Test case repetitions. * @return Negative value if the test suite never ran; otherwise, return the number of failures. */ -int z_ztest_run_test_suite(const char *name); +int z_ztest_run_test_suite(const char *name, bool shuffle, int suite_iter, int case_iter); /** * @brief Returns next test within suite. @@ -534,14 +547,15 @@ void ztest_simple_1cpu_after(void *data); * * @param suite Test suite to run. */ -#define ztest_run_test_suite(suite) z_ztest_run_test_suite(STRINGIFY(suite)) +#define ztest_run_test_suite(suite) z_ztest_run_test_suite(STRINGIFY(suite), \ + int suite_iter, int case_iter) /** * @brief Structure for architecture specific APIs * */ struct ztest_arch_api { - void (*run_all)(const void *state); + void (*run_all)(const void *state, bool shuffle, int suite_iter, int case_iter); bool (*should_suite_run)(const void *state, struct ztest_suite_node *suite); bool (*should_test_run)(const char *suite, const char *test); }; diff --git a/subsys/testsuite/ztest/src/ztest.c b/subsys/testsuite/ztest/src/ztest.c index d49a1ef9c11..5c44829acd4 100644 --- a/subsys/testsuite/ztest/src/ztest.c +++ b/subsys/testsuite/ztest/src/ztest.c @@ -18,11 +18,15 @@ static struct k_thread ztest_thread; #endif static bool failed_expectation; +#ifdef CONFIG_ZTEST_SHELL +#include +#endif + #ifdef CONFIG_ZTEST_SHUFFLE #include #include - #include + #define NUM_ITER_PER_SUITE CONFIG_ZTEST_SHUFFLE_SUITE_REPEAT_COUNT #define NUM_ITER_PER_TEST CONFIG_ZTEST_SHUFFLE_TEST_REPEAT_COUNT #else @@ -651,30 +655,33 @@ struct ztest_unit_test *z_ztest_get_next_test(const char *suite, struct ztest_un return NULL; } -#ifdef CONFIG_ZTEST_SHUFFLE -static void z_ztest_shuffle(void *dest[], intptr_t start, size_t num_items, size_t element_size) +#if CONFIG_ZTEST_SHUFFLE +static void z_ztest_shuffle(bool shuffle, void *dest[], intptr_t start, + size_t num_items, size_t element_size) { - void *tmp; - /* Initialize dest array */ for (size_t i = 0; i < num_items; ++i) { dest[i] = (void *)(start + (i * element_size)); } + void *tmp; /* Shuffle dest array */ - for (size_t i = num_items - 1; i > 0; i--) { - int j = sys_rand32_get() % (i + 1); - - if (i != j) { - tmp = dest[j]; - dest[j] = dest[i]; - dest[i] = tmp; + if (shuffle) { + for (size_t i = num_items - 1; i > 0; i--) { + int j = sys_rand32_get() % (i + 1); + + if (i != j) { + tmp = dest[j]; + dest[j] = dest[i]; + dest[i] = tmp; + } } } } -#endif /* CONFIG_ZTEST_SHUFFLE */ +#endif -static int z_ztest_run_test_suite_ptr(struct ztest_suite_node *suite) +static int z_ztest_run_test_suite_ptr(struct ztest_suite_node *suite, + bool shuffle, int suite_iter, int case_iter) { struct ztest_unit_test *test = NULL; void *data = NULL; @@ -714,14 +721,13 @@ static int z_ztest_run_test_suite_ptr(struct ztest_suite_node *suite) data = suite->setup(); } - for (int i = 0; i < NUM_ITER_PER_TEST; i++) { - fail = 0; - + for (int i = 0; i < case_iter; i++) { #ifdef CONFIG_ZTEST_SHUFFLE struct ztest_unit_test *tests_to_run[ZTEST_TEST_COUNT]; memset(tests_to_run, 0, ZTEST_TEST_COUNT * sizeof(struct ztest_unit_test *)); - z_ztest_shuffle((void **)tests_to_run, (intptr_t)_ztest_unit_test_list_start, + z_ztest_shuffle(shuffle, (void **)tests_to_run, + (intptr_t)_ztest_unit_test_list_start, ZTEST_TEST_COUNT, sizeof(struct ztest_unit_test)); for (size_t j = 0; j < ZTEST_TEST_COUNT; ++j) { test = tests_to_run[j]; @@ -771,7 +777,6 @@ static int z_ztest_run_test_suite_ptr(struct ztest_suite_node *suite) } } #endif - if (test_status == ZTEST_STATUS_OK && fail != 0) { test_status = ZTEST_STATUS_HAS_FAILURE; } @@ -786,9 +791,10 @@ static int z_ztest_run_test_suite_ptr(struct ztest_suite_node *suite) return fail; } -int z_ztest_run_test_suite(const char *name) +int z_ztest_run_test_suite(const char *name, bool shuffle, int suite_iter, int case_iter) { - return z_ztest_run_test_suite_ptr(ztest_find_test_suite(name)); + return z_ztest_run_test_suite_ptr(ztest_find_test_suite(name), + shuffle, suite_iter, case_iter); } #ifdef CONFIG_USERSPACE @@ -942,14 +948,15 @@ static void __ztest_show_suite_summary(void) flush_log(); } -static int __ztest_run_test_suite(struct ztest_suite_node *ptr, const void *state) +static int __ztest_run_test_suite(struct ztest_suite_node *ptr, + const void *state, bool shuffle, int suite_iter, int case_iter) { struct ztest_suite_stats *stats = ptr->stats; int count = 0; - for (int i = 0; i < NUM_ITER_PER_SUITE; i++) { + for (int i = 0; i < suite_iter; i++) { if (ztest_api.should_suite_run(state, ptr)) { - int fail = z_ztest_run_test_suite_ptr(ptr); + int fail = z_ztest_run_test_suite_ptr(ptr, shuffle, suite_iter, case_iter); count++; stats->run_count++; @@ -962,7 +969,7 @@ static int __ztest_run_test_suite(struct ztest_suite_node *ptr, const void *stat return count; } -int z_impl_ztest_run_test_suites(const void *state) +int z_impl_ztest_run_test_suites(const void *state, bool shuffle, int suite_iter, int case_iter) { int count = 0; @@ -974,31 +981,32 @@ int z_impl_ztest_run_test_suites(const void *state) struct ztest_suite_node *suites_to_run[ZTEST_SUITE_COUNT]; memset(suites_to_run, 0, ZTEST_SUITE_COUNT * sizeof(struct ztest_suite_node *)); - z_ztest_shuffle((void **)suites_to_run, (intptr_t)_ztest_suite_node_list_start, + z_ztest_shuffle(shuffle, (void **)suites_to_run, (intptr_t)_ztest_suite_node_list_start, ZTEST_SUITE_COUNT, sizeof(struct ztest_suite_node)); for (size_t i = 0; i < ZTEST_SUITE_COUNT; ++i) { __ztest_init_unit_test_result_for_suite(suites_to_run[i]); } for (size_t i = 0; i < ZTEST_SUITE_COUNT; ++i) { - count += __ztest_run_test_suite(suites_to_run[i], state); + count += __ztest_run_test_suite(suites_to_run[i], + state, shuffle, suite_iter, case_iter); /* Stop running tests if we have a critical error or if we have a failure and * FAIL_FAST was set */ if (test_status == ZTEST_STATUS_CRITICAL_ERROR || - (test_status == ZTEST_STATUS_HAS_FAILURE && FAIL_FAST)) { + (test_status == ZTEST_STATUS_HAS_FAILURE && FAIL_FAST)) { break; } } #else for (struct ztest_suite_node *ptr = _ztest_suite_node_list_start; - ptr < _ztest_suite_node_list_end; ++ptr) { + ptr < _ztest_suite_node_list_end; ++ptr) { __ztest_init_unit_test_result_for_suite(ptr); - count += __ztest_run_test_suite(ptr, state); + count += __ztest_run_test_suite(ptr, state, shuffle, suite_iter, case_iter); /* Stop running tests if we have a critical error or if we have a failure and * FAIL_FAST was set */ if (test_status == ZTEST_STATUS_CRITICAL_ERROR || - (test_status == ZTEST_STATUS_HAS_FAILURE && FAIL_FAST)) { + (test_status == ZTEST_STATUS_HAS_FAILURE && FAIL_FAST)) { break; } } @@ -1070,12 +1078,18 @@ void ztest_verify_all_test_suites_ran(void) } } -void ztest_run_all(const void *state) { ztest_api.run_all(state); } +void ztest_run_all(const void *state, bool shuffle, int suite_iter, int case_iter) +{ + ztest_api.run_all(state, shuffle, suite_iter, case_iter); +} void __weak test_main(void) { - ztest_run_all(NULL); - +#if CONFIG_ZTEST_SHUFFLE + ztest_run_all(NULL, true, NUM_ITER_PER_SUITE, NUM_ITER_PER_TEST); +#else + ztest_run_all(NULL, false, NUM_ITER_PER_SUITE, NUM_ITER_PER_TEST); +#endif ztest_verify_all_test_suites_ran(); } @@ -1100,6 +1114,179 @@ int main(void) return test_status; } #else + +/* Shell */ + +#ifdef CONFIG_ZTEST_SHELL +static int cmd_list_suites(const struct shell *sh, size_t argc, char **argv) +{ + struct ztest_suite_node *suite; + + for (suite = _ztest_suite_node_list_start; suite < _ztest_suite_node_list_end; ++suite) { + shell_print(sh, "%s", suite->name); + } + return 0; +} + +static int cmd_list_cases(const struct shell *sh, size_t argc, char **argv) +{ + struct ztest_suite_node *ptr; + struct ztest_unit_test *test = NULL; + int test_count = 0; + + for (ptr = _ztest_suite_node_list_start; ptr < _ztest_suite_node_list_end; ++ptr) { + test = NULL; + while ((test = z_ztest_get_next_test(ptr->name, test)) != NULL) { + shell_print(sh, "%s::%s", test->test_suite_name, test->name); + test_count++; + } + } + return 0; +} +extern void ztest_set_test_args(char *argv); +extern void ztest_reset_test_args(void); + +static int cmd_runall(const struct shell *sh, size_t argc, char **argv) +{ + ztest_reset_test_args(); + ztest_run_all(NULL, false, 1, 1); + end_report(); + return 0; +} + +#ifdef CONFIG_ZTEST_SHUFFLE +static int cmd_shuffle(const struct shell *sh, size_t argc, char **argv) +{ + + struct getopt_state *state; + int opt; + static struct option long_options[] = {{"suite_iter", required_argument, 0, 's'}, + {"case_iter", required_argument, 0, 'c'}, + {0, 0, 0, 0}}; + int opt_index = 0; + int val; + int opt_num = 0; + + int suite_iter = 1; + int case_iter = 1; + + while ((opt = getopt_long(argc, argv, "s:c:", long_options, &opt_index)) != -1) { + state = getopt_state_get(); + switch (opt) { + case 's': + val = atoi(state->optarg); + if (val < 1) { + shell_fprintf(sh, SHELL_ERROR, + "Invalid number of suite interations\n"); + return -ENOEXEC; + } + suite_iter = val; + opt_num++; + break; + case 'c': + val = atoi(state->optarg); + if (val < 1) { + shell_fprintf(sh, SHELL_ERROR, + "Invalid number of case interations\n"); + return -ENOEXEC; + } + case_iter = val; + opt_num++; + break; + default: + shell_fprintf(sh, SHELL_ERROR, + "Invalid option or option usage: %s\n", argv[opt_index + 1]); + return -ENOEXEC; + } + } + ztest_reset_test_args(); + ztest_run_all(NULL, true, suite_iter, case_iter); + end_report(); + return 0; +} +#endif + +static int cmd_run_suite(const struct shell *sh, size_t argc, char **argv) +{ + int count = 0; + bool shuffle = false; + + ztest_set_test_args(argv[1]); + + for (struct ztest_suite_node *ptr = _ztest_suite_node_list_start; + ptr < _ztest_suite_node_list_end; ++ptr) { + __ztest_init_unit_test_result_for_suite(ptr); + count += __ztest_run_test_suite(ptr, NULL, shuffle, 1, 1); + if (test_status == ZTEST_STATUS_CRITICAL_ERROR || + (test_status == ZTEST_STATUS_HAS_FAILURE && FAIL_FAST)) { + break; + } + } + return 0; +} + +static void testsuite_list_get(size_t idx, struct shell_static_entry *entry); + +SHELL_DYNAMIC_CMD_CREATE(testsuite_names, testsuite_list_get); + +static size_t testsuite_get_all_static(struct ztest_suite_node const **suites) +{ + *suites = _ztest_suite_node_list_start; + return _ztest_suite_node_list_end - _ztest_suite_node_list_start; +} + +static const struct ztest_suite_node *suite_lookup(size_t idx, const char *prefix) +{ + size_t match_idx = 0; + const struct ztest_suite_node *suite; + size_t len = testsuite_get_all_static(&suite); + const struct ztest_suite_node *suite_end = suite + len; + + while (suite < suite_end) { + if ((suite->name != NULL) && (strlen(suite->name) != 0) && + ((prefix == NULL) || + (strncmp(prefix, suite->name, strlen(prefix)) == 0))) { + if (match_idx == idx) { + return suite; + } + ++match_idx; + } + ++suite; + } + + return NULL; +} + +static void testsuite_list_get(size_t idx, struct shell_static_entry *entry) +{ + const struct ztest_suite_node *suite = suite_lookup(idx, ""); + + entry->syntax = (suite != NULL) ? suite->name : NULL; + entry->handler = NULL; + entry->help = NULL; + entry->subcmd = NULL; +} + + SHELL_STATIC_SUBCMD_SET_CREATE( + sub_ztest_cmds, + SHELL_CMD_ARG(run-all, NULL, "Run all tests", cmd_runall, 0, 0), +#ifdef CONFIG_ZTEST_SHUFFLE + SHELL_COND_CMD_ARG(CONFIG_ZTEST_SHUFFLE, shuffle, NULL, + "Shuffle tests", cmd_shuffle, 0, 2), +#endif + SHELL_CMD_ARG(list-testsuites, NULL, + "List all test suites", cmd_list_suites, 0, 0), + SHELL_CMD_ARG(list-testcases, NULL, + "List all test cases", cmd_list_cases, 0, 0), + SHELL_CMD_ARG(run-testsuite, &testsuite_names, + "Run test suite", cmd_run_suite, 2, 0), + SHELL_CMD_ARG(run-testcase, NULL, "Run testcase", cmd_run_suite, 2, 0), + SHELL_SUBCMD_SET_END /* Array terminated. */ + ); + +SHELL_CMD_REGISTER(ztest, &sub_ztest_cmds, "Ztest commands", NULL); +#endif /* CONFIG_ZTEST_SHELL */ + int main(void) { #ifdef CONFIG_USERSPACE @@ -1116,6 +1303,7 @@ int main(void) #endif /* CONFIG_USERSPACE */ z_init_mock(); +#ifndef CONFIG_ZTEST_SHELL test_main(); end_report(); flush_log(); @@ -1152,7 +1340,8 @@ int main(void) ; /* Spin */ } irq_unlock(key); -#endif +#endif /* CONFIG_ZTEST_NO_YIELD */ +#endif /* CONFIG_ZTEST_SHELL */ return 0; } #endif diff --git a/subsys/testsuite/ztest/src/ztest_defaults.c b/subsys/testsuite/ztest/src/ztest_defaults.c index eaf59c8a096..12569d4126a 100644 --- a/subsys/testsuite/ztest/src/ztest_defaults.c +++ b/subsys/testsuite/ztest/src/ztest_defaults.c @@ -27,9 +27,9 @@ const char *ztest_relative_filename(const char *file) * * @param state The current state of the machine as it relates to the test executable. */ -void z_ztest_run_all(const void *state) +void z_ztest_run_all(const void *state, bool shuffle, int suite_iter, int case_iter) { - ztest_run_test_suites(state); + ztest_run_test_suites(state, shuffle, suite_iter, case_iter); } /** diff --git a/subsys/testsuite/ztest/src/ztest_posix.c b/subsys/testsuite/ztest/src/ztest_posix.c index d2c1857c04c..585bbeb9837 100644 --- a/subsys/testsuite/ztest/src/ztest_posix.c +++ b/subsys/testsuite/ztest/src/ztest_posix.c @@ -95,6 +95,8 @@ const char *ztest_get_test_args(void) return test_args; } + + /** * @brief Lists registered unit tests in this binary, one per line * @@ -126,12 +128,12 @@ int z_ztest_list_tests(void) * * @param state The current state of the machine as it relates to the test executable. */ -void z_ztest_run_all(const void *state) +void z_ztest_run_all(const void *state, bool shuffle, int suite_iter, int case_iter) { if (z_ztest_get_list_test()) { z_ztest_list_tests(); } else { - ztest_run_test_suites(state); + ztest_run_test_suites(state, shuffle, suite_iter, case_iter); } } diff --git a/subsys/testsuite/ztest/src/ztest_shell.c b/subsys/testsuite/ztest/src/ztest_shell.c new file mode 100644 index 00000000000..969f0fcd9d4 --- /dev/null +++ b/subsys/testsuite/ztest/src/ztest_shell.c @@ -0,0 +1,152 @@ +/* + * Copyright (c) 2022 Google LLC + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include + + +static const char *test_args; + +/** + * @brief Try to shorten a filename by removing the current directory + * + * This helps to reduce the very long filenames in assertion failures. It + * removes the current directory from the filename and returns the rest. + * This makes assertions a lot more readable, and sometimes they fit on one + * line. + * + * @param file Filename to check + * @returns Shortened filename, or @file if it could not be shortened + */ +const char *ztest_relative_filename(const char *file) +{ + return file; +} + +/** + * Default entry point for running registered unit tests. + * + * @param state The current state of the machine as it relates to the test executable. + */ +void z_ztest_run_all(const void *state, bool shuffle, int suite_iter, int case_iter) +{ + ztest_run_test_suites(state, shuffle, suite_iter, case_iter); +} + +void ztest_reset_test_args(void) +{ + test_args = NULL; +} + +void ztest_set_test_args(char *args) +{ + test_args = strdup(args); +} + +/** + * @brief Helper function to get command line test arguments + * + * @return const char* + */ +char *ztest_get_test_args(void) +{ + if (test_args != NULL) { + return strdup(test_args); + } else { + return NULL; + } +} + + +/** + * @brief Checks if the test_args contains the suite/test name. + * + * @param suite_name + * @param test_name + * @return true + * @return false + */ +static bool z_ztest_testargs_contains(const char *suite_name, const char *test_name) +{ + bool found = false; + char *test_args_local = ztest_get_test_args(); + char *suite_test_pair; + char *last_suite_test_pair; + char *suite_arg; + char *test_arg; + char *last_arg; + + if (test_args_local == NULL) { + return true; + } + suite_test_pair = strtok_r(test_args_local, ",", &last_suite_test_pair); + + while (suite_test_pair && !found) { + suite_arg = strtok_r(suite_test_pair, ":", &last_arg); + test_arg = strtok_r(NULL, ":", &last_arg); + + found = !strcmp(suite_arg, suite_name); + if (test_name && test_arg) { + found &= !strcmp(test_arg, "*") || + !strcmp(test_arg, test_name); + } + + suite_test_pair = strtok_r(NULL, ",", &last_suite_test_pair); + } + return found; +} + +/** + * @brief Determines if the test suite should run based on test cases listed + * in the command line argument. + * + * Overrides implementation in ztest.c + * + * @param state The current state of the machine as it relates to the test + * executable. + * @param suite Pointer to ztest_suite_node + * @return true + * @return false + */ +bool z_ztest_should_suite_run(const void *state, struct ztest_suite_node *suite) +{ + char *test_args_local = ztest_get_test_args(); + bool run_suite = true; + + if (test_args_local != NULL && !z_ztest_testargs_contains(suite->name, NULL)) { + run_suite = false; + suite->stats->run_count++; + } else if (suite->predicate != NULL) { + run_suite = suite->predicate(state); + } + + return run_suite; +} + + + +/** + * @brief Determines if the test case should run based on test cases listed + * in the command line argument. Run all tests for non-posix builds + * + * @param suite - name of test suite + * @param test - name of unit test + * @return true + * @return false + */ +bool z_ztest_should_test_run(const char *suite, const char *test) +{ + bool run_test = false; + + run_test = z_ztest_testargs_contains(suite, test); + + return run_test; +} + +ZTEST_DMEM const struct ztest_arch_api ztest_api = { + .run_all = z_ztest_run_all, + .should_suite_run = z_ztest_should_suite_run, + .should_test_run = z_ztest_should_test_run +}; diff --git a/tests/bluetooth/host/keys/bt_keys_get_addr/src/main.c b/tests/bluetooth/host/keys/bt_keys_get_addr/src/main.c index 06213463181..cebbf1923e9 100644 --- a/tests/bluetooth/host/keys/bt_keys_get_addr/src/main.c +++ b/tests/bluetooth/host/keys/bt_keys_get_addr/src/main.c @@ -181,11 +181,11 @@ void test_main(void) { /* Only startup suite will run. */ all_startup_checks_executed = false; - ztest_run_all(NULL); + ztest_run_all(NULL, false, 1, 1); /* All other suites, except startup suite, will run. */ all_startup_checks_executed = true; - ztest_run_all(NULL); + ztest_run_all(NULL, false, 1, 1); /* Check that all the suites in this binary ran at least once. */ ztest_verify_all_test_suites_ran(); diff --git a/tests/drivers/eeprom/api/src/main.c b/tests/drivers/eeprom/api/src/main.c index e9ddd3ec76f..5a14565cccb 100644 --- a/tests/drivers/eeprom/api/src/main.c +++ b/tests/drivers/eeprom/api/src/main.c @@ -178,7 +178,7 @@ static void run_tests_on_eeprom(const struct device *dev) printk("Running tests on device \"%s\"\n", eeprom->name); k_object_access_grant(eeprom, k_current_get()); - ztest_run_all(NULL); + ztest_run_all(NULL, false, 1, 1); } void test_main(void) diff --git a/tests/kernel/threads/thread_apis/src/main.c b/tests/kernel/threads/thread_apis/src/main.c index b68c4331101..2e4a4b90f45 100644 --- a/tests/kernel/threads/thread_apis/src/main.c +++ b/tests/kernel/threads/thread_apis/src/main.c @@ -43,7 +43,7 @@ static ZTEST_DMEM int tp = 10; */ ZTEST(threads_lifecycle, test_systhreads_main) { - zassert_true(main_prio == CONFIG_MAIN_THREAD_PRIORITY); + zassert_true(main_prio == CONFIG_MAIN_THREAD_PRIORITY, "%d", CONFIG_MAIN_THREAD_PRIORITY); } /** @@ -185,7 +185,7 @@ ZTEST_USER(threads_lifecycle, test_thread_name_user_get_set) zassert_equal(ret, -EINVAL, "not a thread object"); ret = k_thread_name_copy(&z_main_thread, thread_name, sizeof(thread_name)); - zassert_equal(ret, 0, "couldn't get main thread name"); + zassert_equal(ret, 0, "couldn't get main thread name: %s (%d)", thread_name, ret); LOG_DBG("Main thread name is '%s'", thread_name); /* Set and get child thread's name */ diff --git a/tests/subsys/mgmt/mcumgr/cb_notifications/src/main.c b/tests/subsys/mgmt/mcumgr/cb_notifications/src/main.c index 50ac67d43b2..99dee33e380 100644 --- a/tests/subsys/mgmt/mcumgr/cb_notifications/src/main.c +++ b/tests/subsys/mgmt/mcumgr/cb_notifications/src/main.c @@ -248,7 +248,7 @@ static void cleanup_test(void *p) void test_main(void) { while (test_state.test_set < CB_NOTIFICATION_TEST_SET_COUNT) { - ztest_run_all(&test_state); + ztest_run_all(&test_state, false, 1, 1); ++test_state.test_set; } diff --git a/tests/subsys/mgmt/mcumgr/os_mgmt_datetime/src/main.c b/tests/subsys/mgmt/mcumgr/os_mgmt_datetime/src/main.c index c387c3b4812..c3a3c71d2b2 100644 --- a/tests/subsys/mgmt/mcumgr/os_mgmt_datetime/src/main.c +++ b/tests/subsys/mgmt/mcumgr/os_mgmt_datetime/src/main.c @@ -1458,7 +1458,7 @@ static void cleanup_test(void *p) void test_main(void) { while (test_state.test_set < OS_MGMT_DATETIME_TEST_SET_COUNT) { - ztest_run_all(&test_state); + ztest_run_all(&test_state, false, 1, 1); ++test_state.test_set; } diff --git a/tests/subsys/mgmt/mcumgr/os_mgmt_info/src/main.c b/tests/subsys/mgmt/mcumgr/os_mgmt_info/src/main.c index 8ffc2a354b8..d07b8ed6d4d 100644 --- a/tests/subsys/mgmt/mcumgr/os_mgmt_info/src/main.c +++ b/tests/subsys/mgmt/mcumgr/os_mgmt_info/src/main.c @@ -1499,7 +1499,7 @@ static void cleanup_test(void *p) void test_main(void) { while (test_state.test_set < OS_MGMT_TEST_SET_COUNT) { - ztest_run_all(&test_state); + ztest_run_all(&test_state, false, 1, 1); ++test_state.test_set; } diff --git a/tests/ztest/error_hook/src/main.c b/tests/ztest/error_hook/src/main.c index e38b3111cf3..dfa998e0075 100644 --- a/tests/ztest/error_hook/src/main.c +++ b/tests/ztest/error_hook/src/main.c @@ -424,7 +424,7 @@ ZTEST(fail_assume_in_test, test_to_skip) void test_main(void) { - ztest_run_test_suites(NULL); + ztest_run_test_suites(NULL, false, 1, 1); /* Can't run ztest_verify_all_test_suites_ran() since some tests are * skipped by design. */ From 3bfb2e3ab2d5975fe522cdc90ba24246b2d5c92e Mon Sep 17 00:00:00 2001 From: Daniela Andreea Dumitrache Date: Tue, 25 Jul 2023 13:14:18 +0300 Subject: [PATCH 1900/3723] Bluetooth: Audio: Add implementation for PBP and dedicated sample apps. PBP API allows sources to create a Public Broadcast Announcement. PBP API to parse a Public Broadcast Announcement. public_broadcast_source application starts extended advertising and includes a Public Broadcast Announcement. The advertised broadcast audio stream quality will cycle between high and standard quality. public_broadcast_sink application scans for broadcast sources and synchronizes to the first found source which defines a Public Broadcast Announcement including a High Quality Public Broadcast Audio Stream configuration. Add bsim tests for Public Broadcast Profile APIs. Add shell implementation for Public Broadcast Profile APIs. Signed-off-by: Daniela Andreea Dumitrache --- doc/connectivity/bluetooth/api/index.rst | 1 + doc/connectivity/bluetooth/api/shell/pbp.rst | 20 + include/zephyr/bluetooth/audio/pbp.h | 80 ++++ .../public_broadcast_sink/CMakeLists.txt | 11 + .../public_broadcast_sink/Kconfig.sysbuild | 15 + .../public_broadcast_sink/README.rst | 77 ++++ .../overlay-bt_ll_sw_split.conf | 16 + .../bluetooth/public_broadcast_sink/prj.conf | 34 ++ .../public_broadcast_sink/sample.yaml | 27 ++ .../public_broadcast_sink/src/main.c | 436 ++++++++++++++++++ .../public_broadcast_sink/sysbuild.cmake | 24 + .../public_broadcast_source/CMakeLists.txt | 11 + .../public_broadcast_source/Kconfig.sysbuild | 15 + .../public_broadcast_source/README.rst | 77 ++++ .../overlay-bt_ll_sw_split.conf | 24 + .../public_broadcast_source/prj.conf | 26 ++ .../public_broadcast_source/sample.yaml | 27 ++ .../public_broadcast_source/src/main.c | 424 +++++++++++++++++ .../public_broadcast_source/sysbuild.cmake | 24 + samples/bluetooth/tmap_bms/prj.conf | 2 + .../bluetooth/tmap_bms/src/cap_initiator.c | 8 +- subsys/bluetooth/Kconfig.logging | 6 + subsys/bluetooth/audio/CMakeLists.txt | 1 + subsys/bluetooth/audio/Kconfig | 1 + subsys/bluetooth/audio/Kconfig.pbp | 12 + subsys/bluetooth/audio/pbp.c | 81 ++++ subsys/bluetooth/audio/shell/CMakeLists.txt | 4 + subsys/bluetooth/audio/shell/audio.h | 1 + subsys/bluetooth/audio/shell/pbp.c | 88 ++++ tests/bluetooth/shell/audio.conf | 3 + tests/bsim/bluetooth/audio/prj.conf | 3 + tests/bsim/bluetooth/audio/src/common.h | 2 + tests/bsim/bluetooth/audio/src/main.c | 4 + .../src/pbp_public_broadcast_sink_test.c | 432 +++++++++++++++++ .../src/pbp_public_broadcast_source_test.c | 394 ++++++++++++++++ .../bsim/bluetooth/audio/test_scripts/pbp.sh | 28 ++ 36 files changed, 2436 insertions(+), 3 deletions(-) create mode 100644 doc/connectivity/bluetooth/api/shell/pbp.rst create mode 100644 include/zephyr/bluetooth/audio/pbp.h create mode 100644 samples/bluetooth/public_broadcast_sink/CMakeLists.txt create mode 100644 samples/bluetooth/public_broadcast_sink/Kconfig.sysbuild create mode 100644 samples/bluetooth/public_broadcast_sink/README.rst create mode 100644 samples/bluetooth/public_broadcast_sink/overlay-bt_ll_sw_split.conf create mode 100644 samples/bluetooth/public_broadcast_sink/prj.conf create mode 100644 samples/bluetooth/public_broadcast_sink/sample.yaml create mode 100644 samples/bluetooth/public_broadcast_sink/src/main.c create mode 100644 samples/bluetooth/public_broadcast_sink/sysbuild.cmake create mode 100644 samples/bluetooth/public_broadcast_source/CMakeLists.txt create mode 100644 samples/bluetooth/public_broadcast_source/Kconfig.sysbuild create mode 100644 samples/bluetooth/public_broadcast_source/README.rst create mode 100644 samples/bluetooth/public_broadcast_source/overlay-bt_ll_sw_split.conf create mode 100644 samples/bluetooth/public_broadcast_source/prj.conf create mode 100644 samples/bluetooth/public_broadcast_source/sample.yaml create mode 100644 samples/bluetooth/public_broadcast_source/src/main.c create mode 100644 samples/bluetooth/public_broadcast_source/sysbuild.cmake create mode 100644 subsys/bluetooth/audio/Kconfig.pbp create mode 100644 subsys/bluetooth/audio/pbp.c create mode 100644 subsys/bluetooth/audio/shell/pbp.c create mode 100644 tests/bsim/bluetooth/audio/src/pbp_public_broadcast_sink_test.c create mode 100644 tests/bsim/bluetooth/audio/src/pbp_public_broadcast_source_test.c create mode 100755 tests/bsim/bluetooth/audio/test_scripts/pbp.sh diff --git a/doc/connectivity/bluetooth/api/index.rst b/doc/connectivity/bluetooth/api/index.rst index 9152aa7ff10..fa7e357f7d8 100644 --- a/doc/connectivity/bluetooth/api/index.rst +++ b/doc/connectivity/bluetooth/api/index.rst @@ -39,3 +39,4 @@ Bluetooth APIs shell/iso.rst shell/mcp.rst shell/tmap.rst + shell/pbp.rst diff --git a/doc/connectivity/bluetooth/api/shell/pbp.rst b/doc/connectivity/bluetooth/api/shell/pbp.rst new file mode 100644 index 00000000000..ba3e0f459fd --- /dev/null +++ b/doc/connectivity/bluetooth/api/shell/pbp.rst @@ -0,0 +1,20 @@ +Bluetooth: Public Broadcast Profile Shell +######################################### + +This document describes how to run the Public Broadcast Profile functionality. +PBP does not have an associated service. Its purpose is to enable a faster, more +efficient discovery of Broadcast Sources that are transmitting audio with commonly used codec configurations. + +Using the PBP Shell +******************* + +When the Bluetooth stack has been initialized (:code:`bt init`), the Public Broadcast Profile is ready to run. +To set the Public Broadcast Announcement features call :code:`pbp set_features`. + +.. code-block:: console + + + pbp --help + pbp - Bluetooth PBP shell commands + Subcommands: + set_features :Set the Public Broadcast Announcement features diff --git a/include/zephyr/bluetooth/audio/pbp.h b/include/zephyr/bluetooth/audio/pbp.h new file mode 100644 index 00000000000..2ea85564fa7 --- /dev/null +++ b/include/zephyr/bluetooth/audio/pbp.h @@ -0,0 +1,80 @@ +/* + * Copyright 2023 NXP + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#ifndef ZEPHYR_INCLUDE_BLUETOOTH_AUDIO_PBP_ +#define ZEPHYR_INCLUDE_BLUETOOTH_AUDIO_PBP_ + +/** + * @brief Public Broadcast Profile (PBP) + * + * @defgroup bt_pbp Public Broadcast Profile (PBP) + * + * @ingroup bluetooth + * @{ + * + * [Experimental] Users should note that the APIs can change + * as a part of ongoing development. + */ + +#include +#include + +#ifdef __cplusplus +extern "C" { +#endif + +/* PBA Service UUID + Public Broadcast Announcement features + Metadata Length */ +#define BT_PBP_MIN_PBA_SIZE (BT_UUID_SIZE_16 + 1 + 1) + +/** Public Broadcast Announcement features */ +enum bt_pbp_announcement_feature { + /** Broadcast Streams encryption status */ + BT_PBP_ANNOUNCEMENT_FEATURE_ENCRYPTION = BIT(0), + /** Standard Quality Public Broadcast Audio configuration */ + BT_PBP_ANNOUNCEMENT_FEATURE_STANDARD_QUALITY = BIT(1), + /** High Quality Public Broadcast Audio configuration */ + BT_PBP_ANNOUNCEMENT_FEATURE_HIGH_QUALITY = BIT(2), +}; + +/** + * @brief Creates a Public Broadcast Announcement based on the information received + * in the features parameter. + * + * @param meta Metadata to be included in the advertising data + * @param meta_len Size of the metadata fields to be included in the advertising data + * @param features Public Broadcast Announcement features + * @param pba_data_buf Pointer to store the PBA advertising data. Buffer size needs to be + * meta_len + @ref BT_PBP_MIN_PBA_SIZE. + * + * @return 0 on success or an appropriate error code. + */ +int bt_pbp_get_announcement(const uint8_t meta[], size_t meta_len, + enum bt_pbp_announcement_feature features, + struct net_buf_simple *pba_data_buf); + +/** + * @brief Parses the received advertising data corresponding to a Public Broadcast + * Announcement. Returns the advertised Public Broadcast Announcement features and metadata. + * + * @param data Advertising data to be checked + * @param features Public broadcast source features + * @param meta Pointer to copy the metadata present in the advertising data + * + * @return parsed metadata length on success or an appropriate error code + */ +uint8_t bt_pbp_parse_announcement(struct bt_data *data, + enum bt_pbp_announcement_feature *features, + uint8_t *meta); + +#ifdef __cplusplus +} +#endif + +/** + * @} + */ + +#endif /* ZEPHYR_INCLUDE_BLUETOOTH_AUDIO_PBP_ */ diff --git a/samples/bluetooth/public_broadcast_sink/CMakeLists.txt b/samples/bluetooth/public_broadcast_sink/CMakeLists.txt new file mode 100644 index 00000000000..74bed078bdd --- /dev/null +++ b/samples/bluetooth/public_broadcast_sink/CMakeLists.txt @@ -0,0 +1,11 @@ +# SPDX-License-Identifier: Apache-2.0 + +cmake_minimum_required(VERSION 3.20.0) +find_package(Zephyr REQUIRED HINTS $ENV{ZEPHYR_BASE}) +project(pbp_broadcast_sink) + +target_sources(app PRIVATE + src/main.c +) + +zephyr_library_include_directories(${ZEPHYR_BASE}/samples/bluetooth) diff --git a/samples/bluetooth/public_broadcast_sink/Kconfig.sysbuild b/samples/bluetooth/public_broadcast_sink/Kconfig.sysbuild new file mode 100644 index 00000000000..f434010f81d --- /dev/null +++ b/samples/bluetooth/public_broadcast_sink/Kconfig.sysbuild @@ -0,0 +1,15 @@ +# Copyright 2023 Nordic Semiconductor ASA +# SPDX-License-Identifier: Apache-2.0 + +source "share/sysbuild/Kconfig" + +config NET_CORE_BOARD + string + default "nrf5340dk_nrf5340_cpunet" if $(BOARD) = "nrf5340dk_nrf5340_cpuapp" + default "nrf5340_audio_dk_nrf5340_cpunet" if $(BOARD) = "nrf5340_audio_dk_nrf5340_cpuapp" + default "nrf5340bsim_nrf5340_cpunet" if $(BOARD) = "nrf5340bsim_nrf5340_cpuapp" + +config NET_CORE_IMAGE_HCI_IPC + bool "HCI IPC image on network core" + default y + depends on NET_CORE_BOARD != "" diff --git a/samples/bluetooth/public_broadcast_sink/README.rst b/samples/bluetooth/public_broadcast_sink/README.rst new file mode 100644 index 00000000000..5f47bcd05ab --- /dev/null +++ b/samples/bluetooth/public_broadcast_sink/README.rst @@ -0,0 +1,77 @@ +.. zephyr:code-sample:: bluetooth_public_broadcast_sink + :name: Bluetooth: Public Broadcast Sink + :relevant-api: bluetooth + + Bluetooth: Public Broadcast Sink + +Overview +******** + +Application demonstrating the LE Public Broadcast Profile sink functionality. +Starts by scanning for LE Audio broadcast sources and then synchronizes to +the first found source which defines a Public Broadcast Announcement including +a High Quality Public Broadcast Audio Stream configuration. + +This sample can be found under +:zephyr_file:`samples/bluetooth/public_broadcast_sink` in the Zephyr tree. + +Check the :ref:`bluetooth samples section ` for general information. + +Requirements +************ + +* BlueZ running on the host, or +* A board with Bluetooth Low Energy 5.2 support + +Building and Running +******************** + +When building targeting an nrf52 series board with the Zephyr Bluetooth Controller, +use `-DOVERLAY_CONFIG=overlay-bt_ll_sw_split.conf` to enable the required ISO +feature support. + +Building for an nrf5340dk +------------------------- + +You can build both the application core image and an appropriate controller image for the network +core with: + +.. zephyr-app-commands:: + :zephyr-app: samples/bluetooth/public_broadcast_sink/ + :board: nrf5340dk_nrf5340_cpuapp + :goals: build + :west-args: --sysbuild + +If you prefer to only build the application core image, you can do so by doing instead: + +.. zephyr-app-commands:: + :zephyr-app: samples/bluetooth/public_broadcast_sink/ + :board: nrf5340dk_nrf5340_cpuapp + :goals: build + +In that case you can pair this application core image with the +:ref:`hci_ipc sample ` +:zephyr_file:`samples/bluetooth/hci_ipc/nrf5340_cpunet_iso-bt_ll_sw_split.conf` configuration. + +Building for a simulated nrf5340bsim +------------------------------------ + +Similarly to how you would for real HW, you can do: + +.. zephyr-app-commands:: + :zephyr-app: samples/bluetooth/public_broadcast_sink/ + :board: nrf5340bsim_nrf5340_cpuapp + :goals: build + :west-args: --sysbuild + +Note this will produce a Linux executable in `./build/zephyr/zephyr.exe`. +For more information, check :ref:`this board documentation `. + +Building for a simulated nrf52_bsim +----------------------------------- + +.. zephyr-app-commands:: + :zephyr-app: samples/bluetooth/public_broadcast_sink/ + :board: nrf52_bsim + :goals: build + :gen-args: -DOVERLAY_CONFIG=overlay-bt_ll_sw_split.conf diff --git a/samples/bluetooth/public_broadcast_sink/overlay-bt_ll_sw_split.conf b/samples/bluetooth/public_broadcast_sink/overlay-bt_ll_sw_split.conf new file mode 100644 index 00000000000..e336dae38e1 --- /dev/null +++ b/samples/bluetooth/public_broadcast_sink/overlay-bt_ll_sw_split.conf @@ -0,0 +1,16 @@ +# Zephyr Bluetooth Controller +CONFIG_BT_LL_SW_SPLIT=y + +# Enable support for Broadcast ISO Sync +CONFIG_BT_CTLR_SYNC_ISO=y + +# Supports the highest SDU size required by any BAP LC3 presets (155) +CONFIG_BT_CTLR_SYNC_ISO_PDU_LEN_MAX=155 + +# Supports the highest advertising data that is set in a single HCI command in +# Zephyr Bluetooth Controller +CONFIG_BT_CTLR_SCAN_DATA_LEN_MAX=191 + +# Number of supported streams +CONFIG_BT_CTLR_SYNC_ISO_STREAM_MAX=2 +CONFIG_BT_CTLR_ISOAL_SINKS=2 diff --git a/samples/bluetooth/public_broadcast_sink/prj.conf b/samples/bluetooth/public_broadcast_sink/prj.conf new file mode 100644 index 00000000000..0feae717a77 --- /dev/null +++ b/samples/bluetooth/public_broadcast_sink/prj.conf @@ -0,0 +1,34 @@ +CONFIG_BT=y +CONFIG_LOG=y +CONFIG_BT_PAC_SNK=y +CONFIG_BT_PERIPHERAL=y +CONFIG_BT_AUDIO=y +CONFIG_UTF8=y + +CONFIG_BT_SMP=y +CONFIG_BT_KEYS_OVERWRITE_OLDEST=y +CONFIG_BT_L2CAP_TX_BUF_COUNT=20 +CONFIG_BT_HCI_ACL_FLOW_CONTROL=n +CONFIG_BT_AUDIO_CODEC_CAP_MAX_METADATA_SIZE=196 + +# CAP +CONFIG_BT_CAP_ACCEPTOR=y + +# BAP support +CONFIG_BT_BAP_SCAN_DELEGATOR=y +CONFIG_BT_BAP_BROADCAST_SINK=y +CONFIG_BT_BAP_BROADCAST_SNK_SUBGROUP_COUNT=1 +CONFIG_BT_BAP_BROADCAST_SNK_STREAM_COUNT=1 + +# Support an ISO channel per ASE +CONFIG_BT_ISO_MAX_CHAN=2 + +# Sink PAC Location Support +CONFIG_BT_PAC_SNK_LOC=y + +# Generic config +CONFIG_BT_EXT_ADV=y +CONFIG_BT_DEVICE_NAME="PBP Broadcast Sink" + +# PBP Support +CONFIG_BT_PBP=y diff --git a/samples/bluetooth/public_broadcast_sink/sample.yaml b/samples/bluetooth/public_broadcast_sink/sample.yaml new file mode 100644 index 00000000000..8b81f4cc364 --- /dev/null +++ b/samples/bluetooth/public_broadcast_sink/sample.yaml @@ -0,0 +1,27 @@ +sample: + description: Bluetooth Low Energy Audio PBP Broadcast Sink sample + name: Bluetooth Low Energy Audio PBP Broadcast Sink sample +tests: + sample.bluetooth.public_broadcast_sink: + harness: bluetooth + platform_allow: + - qemu_cortex_m3 + - qemu_x86 + - nrf5340dk_nrf5340_cpuapp + - nrf5340bsim_nrf5340_cpuapp + integration_platforms: + - qemu_x86 + - nrf5340dk_nrf5340_cpuapp + tags: bluetooth + sysbuild: true + sample.bluetooth.public_broadcast_sink.bt_ll_sw_split: + harness: bluetooth + platform_allow: + - nrf52_bsim + - nrf52833dk_nrf52820 + - nrf52833dk_nrf52833 + integration_platforms: + - nrf52_bsim + - nrf52833dk_nrf52833 + extra_args: OVERLAY_CONFIG=overlay-bt_ll_sw_split.conf + tags: bluetooth diff --git a/samples/bluetooth/public_broadcast_sink/src/main.c b/samples/bluetooth/public_broadcast_sink/src/main.c new file mode 100644 index 00000000000..1331ffbeded --- /dev/null +++ b/samples/bluetooth/public_broadcast_sink/src/main.c @@ -0,0 +1,436 @@ +/* + * Copyright 2023 NXP + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#define AVAILABLE_SINK_CONTEXT (BT_AUDIO_CONTEXT_TYPE_UNSPECIFIED | \ + BT_AUDIO_CONTEXT_TYPE_CONVERSATIONAL | \ + BT_AUDIO_CONTEXT_TYPE_MEDIA | \ + BT_AUDIO_CONTEXT_TYPE_GAME | \ + BT_AUDIO_CONTEXT_TYPE_INSTRUCTIONAL) + +#define SEM_TIMEOUT K_SECONDS(10) +#define PA_SYNC_SKIP 5 +#define SYNC_RETRY_COUNT 6 /* similar to retries for connections */ +#define INVALID_BROADCAST_ID 0xFFFFFFFF + +static bool pbs_found; +static uint8_t meta[CONFIG_BT_AUDIO_CODEC_CAP_MAX_METADATA_SIZE]; + +static K_SEM_DEFINE(sem_pa_synced, 0U, 1U); +static K_SEM_DEFINE(sem_base_received, 0U, 1U); +static K_SEM_DEFINE(sem_syncable, 0U, 1U); +static K_SEM_DEFINE(sem_pa_sync_lost, 0U, 1U); + +static void broadcast_scan_recv(const struct bt_le_scan_recv_info *info, + struct net_buf_simple *ad); + +static void broadcast_scan_timeout(void); + +static void broadcast_pa_synced(struct bt_le_per_adv_sync *sync, + struct bt_le_per_adv_sync_synced_info *info); + +static void broadcast_pa_recv(struct bt_le_per_adv_sync *sync, + const struct bt_le_per_adv_sync_recv_info *info, + struct net_buf_simple *buf); + +static void broadcast_pa_terminated(struct bt_le_per_adv_sync *sync, + const struct bt_le_per_adv_sync_term_info *info); + +static struct bt_le_scan_cb broadcast_scan_cb = { + .recv = broadcast_scan_recv, + .timeout = broadcast_scan_timeout +}; + +static struct bt_le_per_adv_sync_cb broadcast_sync_cb = { + .synced = broadcast_pa_synced, + .recv = broadcast_pa_recv, + .term = broadcast_pa_terminated, +}; + +static struct bt_bap_broadcast_sink *broadcast_sink; +static uint32_t bcast_id; +static struct bt_le_per_adv_sync *bcast_pa_sync; + +static struct bt_bap_stream streams[CONFIG_BT_BAP_BROADCAST_SNK_STREAM_COUNT]; +struct bt_bap_stream *streams_p[ARRAY_SIZE(streams)]; + +static const struct bt_audio_codec_cap codec = BT_AUDIO_CODEC_CAP_LC3( + BT_AUDIO_CODEC_LC3_FREQ_48KHZ, BT_AUDIO_CODEC_LC3_DURATION_10, + BT_AUDIO_CODEC_LC3_CHAN_COUNT_SUPPORT(1), 40u, 60u, 1u, (BT_AUDIO_CONTEXT_TYPE_MEDIA)); + +/* Create a mask for the maximum BIS we can sync to using the number of streams + * we have. We add an additional 1 since the bis indexes start from 1 and not + * 0. + */ +static const uint32_t bis_index_mask = BIT_MASK(ARRAY_SIZE(streams) + 1U); +static uint32_t bis_index_bitfield; + +static void stream_started_cb(struct bt_bap_stream *stream) +{ + printk("Stream %p started\n", stream); +} + +static void stream_stopped_cb(struct bt_bap_stream *stream, uint8_t reason) +{ + printk("Stream %p stopped with reason 0x%02X\n", stream, reason); +} + +static void stream_recv_cb(struct bt_bap_stream *stream, + const struct bt_iso_recv_info *info, + struct net_buf *buf) +{ + static uint32_t recv_cnt; + + recv_cnt++; + if ((recv_cnt % 20U) == 0U) { + printk("Received %u total ISO packets\n", recv_cnt); + } +} + +static struct bt_bap_stream_ops stream_ops = { + .started = stream_started_cb, + .stopped = stream_stopped_cb, + .recv = stream_recv_cb +}; + +static struct bt_pacs_cap cap = { + .codec_cap = &codec, +}; + +static uint16_t interval_to_sync_timeout(uint16_t interval) +{ + uint32_t interval_ms; + uint16_t timeout; + + /* Ensure that the following calculation does not overflow silently */ + __ASSERT(SYNC_RETRY_COUNT < 10, "SYNC_RETRY_COUNT shall be less than 10"); + + /* Add retries and convert to unit in 10's of ms */ + interval_ms = BT_GAP_PER_ADV_INTERVAL_TO_MS(interval); + timeout = (interval_ms * SYNC_RETRY_COUNT) / 10; + + /* Enforce restraints */ + timeout = CLAMP(timeout, BT_GAP_PER_ADV_MIN_TIMEOUT, BT_GAP_PER_ADV_MAX_TIMEOUT); + + return timeout; +} + +static void sync_broadcast_pa(const struct bt_le_scan_recv_info *info, + uint32_t broadcast_id) +{ + struct bt_le_per_adv_sync_param param; + int err; + + /* Unregister the callbacks to prevent broadcast_scan_recv to be called again */ + bt_le_scan_cb_unregister(&broadcast_scan_cb); + + err = bt_le_scan_stop(); + if (err != 0) { + printk("Could not stop scan: %d", err); + } + + bt_addr_le_copy(¶m.addr, info->addr); + param.options = 0; + param.sid = info->sid; + param.skip = PA_SYNC_SKIP; + param.timeout = interval_to_sync_timeout(info->interval); + err = bt_le_per_adv_sync_create(¶m, &bcast_pa_sync); + + if (err != 0) { + printk("Could not sync to PA: %d", err); + } else { + bcast_id = broadcast_id; + } +} + +static bool scan_check_and_sync_broadcast(struct bt_data *data, void *user_data) +{ + uint32_t *broadcast_id = user_data; + struct bt_uuid_16 adv_uuid; + enum bt_pbp_announcement_feature source_features = 0U; + + memset(meta, 0, ARRAY_SIZE(meta)); + + if (data->type != BT_DATA_SVC_DATA16) { + return true; + } + + if (!bt_uuid_create(&adv_uuid.uuid, data->data, BT_UUID_SIZE_16)) { + return true; + } + + if (!bt_uuid_cmp(&adv_uuid.uuid, BT_UUID_BROADCAST_AUDIO)) { + *broadcast_id = sys_get_le24(data->data + BT_UUID_SIZE_16); + return true; + } + + if (!bt_uuid_cmp(&adv_uuid.uuid, BT_UUID_PBA)) { + bt_pbp_parse_announcement(data, &source_features, meta); + if (!(source_features & BT_PBP_ANNOUNCEMENT_FEATURE_HIGH_QUALITY)) { + /* This is a Standard Quality Public Broadcast Audio stream */ + printk("This is a Standard Quality Public Broadcast Audio stream\n"); + pbs_found = false; + + return true; + } + printk("Found Suitable Public Broadcast Announcement\n"); + pbs_found = true; + + /** + * Continue parsing if Broadcast Audio Announcement Service + * was not found. + */ + if (*broadcast_id == INVALID_BROADCAST_ID) { + return true; + } + + return false; + } + + return true; +} + +static void broadcast_scan_recv(const struct bt_le_scan_recv_info *info, + struct net_buf_simple *ad) +{ + uint32_t broadcast_id; + + pbs_found = false; + + /* We are only interested in non-connectable periodic advertisers */ + if ((info->adv_props & BT_GAP_ADV_PROP_CONNECTABLE) || info->interval == 0) { + return; + } + + broadcast_id = INVALID_BROADCAST_ID; + bt_data_parse(ad, scan_check_and_sync_broadcast, (void *)&broadcast_id); + + if ((broadcast_id != INVALID_BROADCAST_ID) && pbs_found) { + sync_broadcast_pa(info, broadcast_id); + } +} + +static void broadcast_scan_timeout(void) +{ + printk("Broadcast scan timed out\n"); +} + +static bool pa_decode_base(struct bt_data *data, void *user_data) +{ + const struct bt_bap_base *base = bt_bap_base_get_base_from_ad(data); + uint32_t base_bis_index_bitfield = 0U; + int err; + + /* Base is NULL if the data does not contain a valid BASE */ + if (base == NULL) { + return true; + } + + err = bt_bap_base_get_bis_indexes(base, &base_bis_index_bitfield); + if (err != 0) { + return false; + } + + bis_index_bitfield = base_bis_index_bitfield & bis_index_mask; + k_sem_give(&sem_base_received); + + return false; +} + +static void broadcast_pa_recv(struct bt_le_per_adv_sync *sync, + const struct bt_le_per_adv_sync_recv_info *info, + struct net_buf_simple *buf) +{ + bt_data_parse(buf, pa_decode_base, NULL); +} + +static void syncable_cb(struct bt_bap_broadcast_sink *sink, bool encrypted) +{ + k_sem_give(&sem_syncable); +} + +static void base_recv_cb(struct bt_bap_broadcast_sink *sink, const struct bt_bap_base *base, + size_t base_size) +{ + k_sem_give(&sem_base_received); +} + +static struct bt_bap_broadcast_sink_cb broadcast_sink_cbs = { + .syncable = syncable_cb, + .base_recv = base_recv_cb, +}; + +static void broadcast_pa_synced(struct bt_le_per_adv_sync *sync, + struct bt_le_per_adv_sync_synced_info *info) +{ + if (sync == bcast_pa_sync) { + printk("PA sync %p synced for broadcast sink with broadcast ID 0x%06X\n", + sync, bcast_id); + + k_sem_give(&sem_pa_synced); + } +} + +static void broadcast_pa_terminated(struct bt_le_per_adv_sync *sync, + const struct bt_le_per_adv_sync_term_info *info) +{ + if (sync == bcast_pa_sync) { + printk("PA sync %p lost with reason %u\n", sync, info->reason); + bcast_pa_sync = NULL; + + k_sem_give(&sem_pa_sync_lost); + } +} + +static int reset(void) +{ + if (broadcast_sink != NULL) { + int err = bt_bap_broadcast_sink_delete(broadcast_sink); + + if (err) { + printk("Deleting broadcast sink failed (err %d)\n", err); + + return err; + } + + broadcast_sink = NULL; + } + k_sem_reset(&sem_pa_synced); + k_sem_reset(&sem_base_received); + k_sem_reset(&sem_syncable); + k_sem_reset(&sem_pa_sync_lost); + + return 0; +} + +int bap_broadcast_sink_init(void) +{ + int err; + + bt_bap_broadcast_sink_register_cb(&broadcast_sink_cbs); + bt_le_per_adv_sync_cb_register(&broadcast_sync_cb); + + err = bt_pacs_cap_register(BT_AUDIO_DIR_SINK, &cap); + if (err) { + printk("Capability register failed (err %d)\n", err); + + return err; + } + + for (size_t i = 0U; i < ARRAY_SIZE(streams); i++) { + streams[i].ops = &stream_ops; + } + + for (size_t i = 0U; i < ARRAY_SIZE(streams_p); i++) { + streams_p[i] = &streams[i]; + } + + return 0; +} + +int bap_broadcast_sink_run(void) +{ + while (true) { + int err = reset(); + + if (err != 0) { + printk("Resetting failed: %d - Aborting\n", err); + + return err; + } + + /* Register callbacks */ + bt_le_scan_cb_register(&broadcast_scan_cb); + + /* Start scanning */ + err = bt_le_scan_start(BT_LE_SCAN_PASSIVE, NULL); + if (err) { + printk("Scan start failed (err %d)\n", err); + + return err; + } + + /* Wait until a suitable source is found */ + err = k_sem_take(&sem_pa_synced, K_FOREVER); + printk("Broadcast source PA synced, waiting for BASE\n"); + + /* Wait for BASE decode */ + err = k_sem_take(&sem_base_received, SEM_TIMEOUT); + if (err != 0) { + printk("sem_base_received timed out\n"); + + return err; + } + + /* Create broadcast sink */ + printk("BASE received, creating broadcast sink\n"); + err = bt_bap_broadcast_sink_create(bcast_pa_sync, bcast_id, &broadcast_sink); + if (err != 0) { + printk("bt_bap_broadcast_sink_create failed: %d\n", err); + + return err; + } + + k_sem_take(&sem_syncable, SEM_TIMEOUT); + if (err != 0) { + printk("sem_syncable timed out\n"); + + return err; + } + + /* Sync to broadcast source */ + printk("Syncing to broadcast\n"); + err = bt_bap_broadcast_sink_sync(broadcast_sink, bis_index_bitfield, + streams_p, NULL); + if (err != 0) { + printk("Unable to sync to broadcast source: %d\n", err); + + return err; + } + + k_sem_take(&sem_pa_sync_lost, K_FOREVER); + } + + return 0; +} + +int main(void) +{ + int err; + + err = bt_enable(NULL); + if (err != 0) { + printk("Bluetooth init failed (err %d)\n", err); + + return err; + } + printk("Bluetooth initialized\n"); + + printk("Initializing BAP Broadcast Sink\n"); + err = bap_broadcast_sink_init(); + if (err != 0) { + return err; + } + + err = bap_broadcast_sink_run(); + if (err != 0) { + return err; + } + + return 0; +} diff --git a/samples/bluetooth/public_broadcast_sink/sysbuild.cmake b/samples/bluetooth/public_broadcast_sink/sysbuild.cmake new file mode 100644 index 00000000000..2523aac8ea7 --- /dev/null +++ b/samples/bluetooth/public_broadcast_sink/sysbuild.cmake @@ -0,0 +1,24 @@ +# Copyright (c) 2023 Nordic Semiconductor ASA +# SPDX-License-Identifier: Apache-2.0 + +if(SB_CONFIG_NET_CORE_IMAGE_HCI_IPC) + # For builds in the nrf5340, we build the netcore image with the controller + + set(NET_APP hci_ipc) + set(NET_APP_SRC_DIR ${ZEPHYR_BASE}/samples/bluetooth/${NET_APP}) + + ExternalZephyrProject_Add( + APPLICATION ${NET_APP} + SOURCE_DIR ${NET_APP_SRC_DIR} + BOARD ${SB_CONFIG_NET_CORE_BOARD} + ) + + set(${NET_APP}_CONF_FILE + ${NET_APP_SRC_DIR}/nrf5340_cpunet_iso-bt_ll_sw_split.conf + CACHE INTERNAL "" + ) + + native_simulator_set_child_images(${DEFAULT_IMAGE} ${NET_APP}) +endif() + +native_simulator_set_final_executable(${DEFAULT_IMAGE}) diff --git a/samples/bluetooth/public_broadcast_source/CMakeLists.txt b/samples/bluetooth/public_broadcast_source/CMakeLists.txt new file mode 100644 index 00000000000..6331703e2d8 --- /dev/null +++ b/samples/bluetooth/public_broadcast_source/CMakeLists.txt @@ -0,0 +1,11 @@ +# SPDX-License-Identifier: Apache-2.0 + +cmake_minimum_required(VERSION 3.20.0) +find_package(Zephyr REQUIRED HINTS $ENV{ZEPHYR_BASE}) +project(public_broadcast_source) + +target_sources(app PRIVATE + src/main.c +) + +zephyr_library_include_directories(${ZEPHYR_BASE}/samples/bluetooth) diff --git a/samples/bluetooth/public_broadcast_source/Kconfig.sysbuild b/samples/bluetooth/public_broadcast_source/Kconfig.sysbuild new file mode 100644 index 00000000000..f434010f81d --- /dev/null +++ b/samples/bluetooth/public_broadcast_source/Kconfig.sysbuild @@ -0,0 +1,15 @@ +# Copyright 2023 Nordic Semiconductor ASA +# SPDX-License-Identifier: Apache-2.0 + +source "share/sysbuild/Kconfig" + +config NET_CORE_BOARD + string + default "nrf5340dk_nrf5340_cpunet" if $(BOARD) = "nrf5340dk_nrf5340_cpuapp" + default "nrf5340_audio_dk_nrf5340_cpunet" if $(BOARD) = "nrf5340_audio_dk_nrf5340_cpuapp" + default "nrf5340bsim_nrf5340_cpunet" if $(BOARD) = "nrf5340bsim_nrf5340_cpuapp" + +config NET_CORE_IMAGE_HCI_IPC + bool "HCI IPC image on network core" + default y + depends on NET_CORE_BOARD != "" diff --git a/samples/bluetooth/public_broadcast_source/README.rst b/samples/bluetooth/public_broadcast_source/README.rst new file mode 100644 index 00000000000..9111cd3f614 --- /dev/null +++ b/samples/bluetooth/public_broadcast_source/README.rst @@ -0,0 +1,77 @@ +.. zephyr:code-sample:: bluetooth_public_broadcast_source + :name: Bluetooth: Public Broadcast Source + :relevant-api: bluetooth + + Bluetooth: Public Broadcast Source + +Overview +******** + +Application demonstrating the LE Public Broadcast Profile source functionality. +Will start advertising extended advertising and includes a Broadcast Audio Announcement. +The advertised broadcast audio stream quality will cycle between high and standard quality +every 15 seconds. + +This sample can be found under +:zephyr_file:`samples/bluetooth/public_broadcast_source` in the Zephyr tree. + +Check the :ref:`bluetooth samples section ` for general information. + +Requirements +************ + +* BlueZ running on the host, or +* A board with Bluetooth Low Energy 5.2 support + +Building and Running +******************** + +When building targeting an nrf52 series board with the Zephyr Bluetooth Controller, +use `-DOVERLAY_CONFIG=overlay-bt_ll_sw_split.conf` to enable the required ISO +feature support. + +Building for an nrf5340dk +------------------------- + +You can build both the application core image and an appropriate controller image for the network +core with: + +.. zephyr-app-commands:: + :zephyr-app: samples/bluetooth/public_broadcast_source/ + :board: nrf5340dk_nrf5340_cpuapp + :goals: build + :west-args: --sysbuild + +If you prefer to only build the application core image, you can do so by doing instead: + +.. zephyr-app-commands:: + :zephyr-app: samples/bluetooth/public_broadcast_source/ + :board: nrf5340dk_nrf5340_cpuapp + :goals: build + +In that case you can pair this application core image with the +:ref:`hci_ipc sample ` +:zephyr_file:`samples/bluetooth/hci_ipc/nrf5340_cpunet_iso-bt_ll_sw_split.conf` configuration. + +Building for a simulated nrf5340bsim +------------------------------------ + +Similarly to how you would for real HW, you can do: + +.. zephyr-app-commands:: + :zephyr-app: samples/bluetooth/public_broadcast_source/ + :board: nrf5340bsim_nrf5340_cpuapp + :goals: build + :west-args: --sysbuild + +Note this will produce a Linux executable in `./build/zephyr/zephyr.exe`. +For more information, check :ref:`this board documentation `. + +Building for a simulated nrf52_bsim +----------------------------------- + +.. zephyr-app-commands:: + :zephyr-app: samples/bluetooth/public_broadcast_source/ + :board: nrf52_bsim + :goals: build + :gen-args: -DOVERLAY_CONFIG=overlay-bt_ll_sw_split.conf diff --git a/samples/bluetooth/public_broadcast_source/overlay-bt_ll_sw_split.conf b/samples/bluetooth/public_broadcast_source/overlay-bt_ll_sw_split.conf new file mode 100644 index 00000000000..c73ff9c3ea9 --- /dev/null +++ b/samples/bluetooth/public_broadcast_source/overlay-bt_ll_sw_split.conf @@ -0,0 +1,24 @@ +# Zephyr Bluetooth Controller +CONFIG_BT_LL_SW_SPLIT=y + +# Zephyr Controller tested maximum advertising data that can be set in a single HCI command +CONFIG_BT_CTLR_ADV_DATA_LEN_MAX=191 + +# Enable support for Broadcast ISO in Zephyr Bluetooth Controller +CONFIG_BT_CTLR_ADV_ISO=y + +# Sufficient ISO PDU length for any BAP LC3 presets (155) +CONFIG_BT_CTLR_ADV_ISO_PDU_LEN_MAX=155 + +# Number of supported streams +CONFIG_BT_CTLR_ADV_ISO_STREAM_MAX=2 +CONFIG_BT_CTLR_ISOAL_SOURCES=2 + +# FIXME: Host needs CONFIG_BT_ISO_TX_MTU + 4 bytes for sequence number, and optionally +# additional + 4 bytes for timestamp when not using BT_ISO_TIMESTAMP_NONE in bt_iso_chan_send(), +# otherwise Host tries to fragment ISO data. +# When Host is fixed, CONFIG_BT_CTLR_ISO_TX_BUFFER_SIZE can inherit the +# CONFIG_BT_ISO_TX_MTU value. +# +# Supports the highest SDU size required by any BAP LC3 presets (155) +CONFIG_BT_CTLR_ISO_TX_BUFFER_SIZE=163 diff --git a/samples/bluetooth/public_broadcast_source/prj.conf b/samples/bluetooth/public_broadcast_source/prj.conf new file mode 100644 index 00000000000..ca7d3f38261 --- /dev/null +++ b/samples/bluetooth/public_broadcast_source/prj.conf @@ -0,0 +1,26 @@ +CONFIG_MAIN_STACK_SIZE=2048 + +CONFIG_BT=y +CONFIG_LOG=y +CONFIG_BT_AUDIO=y +CONFIG_BT_PERIPHERAL=y + +CONFIG_BT_ISO_MAX_CHAN=2 +CONFIG_BT_BAP_BROADCAST_SRC_STREAM_COUNT=2 +CONFIG_BT_BAP_BROADCAST_SRC_SUBGROUP_COUNT=2 +CONFIG_BT_ISO_TX_BUF_COUNT=4 +CONFIG_BT_HCI_ACL_FLOW_CONTROL=n + +# PBP support +CONFIG_BT_PBP=y + +# CAP support +CONFIG_BT_CAP_INITIATOR=y + +# BAP support +CONFIG_BT_BAP_BROADCAST_SOURCE=y +CONFIG_BT_BAP_BROADCAST_SRC_STREAM_COUNT=1 +CONFIG_BT_BAP_BROADCAST_SRC_SUBGROUP_COUNT=1 + +CONFIG_BT_EXT_ADV=y +CONFIG_BT_DEVICE_NAME="PBS" diff --git a/samples/bluetooth/public_broadcast_source/sample.yaml b/samples/bluetooth/public_broadcast_source/sample.yaml new file mode 100644 index 00000000000..eb2bd5dc79b --- /dev/null +++ b/samples/bluetooth/public_broadcast_source/sample.yaml @@ -0,0 +1,27 @@ +sample: + description: Bluetooth Low Energy Public Broadcast Source sample + name: Bluetooth Low Energy Public Broadcast Source sample +tests: + sample.bluetooth.public_broadcast_source: + harness: bluetooth + platform_allow: + - qemu_cortex_m3 + - qemu_x86 + - nrf5340dk_nrf5340_cpuapp + - nrf5340bsim_nrf5340_cpuapp + integration_platforms: + - qemu_x86 + - nrf5340dk_nrf5340_cpuapp + tags: bluetooth + sysbuild: true + sample.bluetooth.public_broadcast_source.bt_ll_sw_split: + harness: bluetooth + platform_allow: + - nrf52_bsim + - nrf52833dk_nrf52820 + - nrf52833dk_nrf52833 + integration_platforms: + - nrf52_bsim + - nrf52833dk_nrf52833 + extra_args: OVERLAY_CONFIG=overlay-bt_ll_sw_split.conf + tags: bluetooth diff --git a/samples/bluetooth/public_broadcast_source/src/main.c b/samples/bluetooth/public_broadcast_source/src/main.c new file mode 100644 index 00000000000..c719810e243 --- /dev/null +++ b/samples/bluetooth/public_broadcast_source/src/main.c @@ -0,0 +1,424 @@ +/* + * Copyright 2023 NXP + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#define BROADCAST_ENQUEUE_COUNT 2U + +/* PBS ASCII text */ +#define PBS_DEMO 'P', 'B', 'P' + +NET_BUF_POOL_FIXED_DEFINE(tx_pool, + (BROADCAST_ENQUEUE_COUNT * CONFIG_BT_BAP_BROADCAST_SRC_STREAM_COUNT), + BT_ISO_SDU_BUF_SIZE(CONFIG_BT_ISO_TX_MTU), 8, NULL); + +static K_SEM_DEFINE(sem_broadcast_started, 0, 1); +static K_SEM_DEFINE(sem_broadcast_stopped, 0, 1); + +static struct bt_cap_stream broadcast_source_stream; +static struct bt_cap_stream *broadcast_stream; + +static uint8_t bis_codec_data[] = {BT_AUDIO_CODEC_DATA( + BT_AUDIO_CODEC_CONFIG_LC3_FREQ, BT_BYTES_LIST_LE16(BT_AUDIO_CODEC_CONFIG_LC3_FREQ_48KHZ))}; + + +const uint8_t pba_metadata[] = { + BT_AUDIO_CODEC_DATA(BT_AUDIO_METADATA_TYPE_PROGRAM_INFO, PBS_DEMO) +}; + +static uint8_t appearance_addata[] = { + BT_BYTES_LIST_LE16(BT_APPEARANCE_AUDIO_SOURCE_BROADCASTING_DEVICE) +}; + +static const char broadcast_name[] = "PBP Source Demo"; + +static struct bt_bap_lc3_preset broadcast_preset_48_2_1 = + BT_BAP_LC3_UNICAST_PRESET_48_2_1(BT_AUDIO_LOCATION_FRONT_LEFT, + BT_AUDIO_CONTEXT_TYPE_MEDIA); + +struct bt_cap_initiator_broadcast_stream_param stream_params; +struct bt_cap_initiator_broadcast_subgroup_param subgroup_param; +struct bt_cap_initiator_broadcast_create_param create_param; +struct bt_cap_broadcast_source *broadcast_source; +struct bt_le_ext_adv *ext_adv; + +static void broadcast_started_cb(struct bt_bap_stream *stream) +{ + printk("Stream %p started\n", stream); + k_sem_give(&sem_broadcast_started); +} + +static void broadcast_stopped_cb(struct bt_bap_stream *stream, uint8_t reason) +{ + if (reason == BT_HCI_ERR_LOCALHOST_TERM_CONN) { + printk("Stream %p ended\n", stream); + } else { + printk("Stream %p stopped with reason 0x%02X\n", stream, reason); + } + + k_sem_give(&sem_broadcast_stopped); +} + +static void broadcast_sent_cb(struct bt_bap_stream *stream) +{ + static uint8_t mock_data[CONFIG_BT_ISO_TX_MTU]; + static bool mock_data_initialized; + static uint32_t seq_num; + struct net_buf *buf; + int ret; + + if (broadcast_preset_48_2_1.qos.sdu > CONFIG_BT_ISO_TX_MTU) { + printk("Invalid SDU %u for the MTU: %d", broadcast_preset_48_2_1.qos.sdu, + CONFIG_BT_ISO_TX_MTU); + + return; + } + + if (!mock_data_initialized) { + for (size_t i = 0U; i < ARRAY_SIZE(mock_data); i++) { + /* Initialize mock data */ + mock_data[i] = (uint8_t)i; + } + mock_data_initialized = true; + } + + buf = net_buf_alloc(&tx_pool, K_FOREVER); + if (buf == NULL) { + printk("Could not allocate buffer when sending on %p\n", stream); + + return; + } + + net_buf_reserve(buf, BT_ISO_CHAN_SEND_RESERVE); + net_buf_add_mem(buf, mock_data, broadcast_preset_48_2_1.qos.sdu); + ret = bt_bap_stream_send(stream, buf, seq_num++, BT_ISO_TIMESTAMP_NONE); + if (ret < 0) { + /* This will end broadcasting on this stream. */ + net_buf_unref(buf); + + return; + } +} + +static struct bt_bap_stream_ops broadcast_stream_ops = { + .started = broadcast_started_cb, + .stopped = broadcast_stopped_cb, + .sent = broadcast_sent_cb +}; + +static int setup_extended_adv(struct bt_le_ext_adv **adv) +{ + int err; + + /* Create a non-connectable non-scannable advertising set */ + err = bt_le_ext_adv_create(BT_LE_EXT_ADV_NCONN_NAME, NULL, adv); + if (err != 0) { + printk("Unable to create extended advertising set: %d\n", err); + + return err; + } + + /* Set periodic advertising parameters */ + err = bt_le_per_adv_set_param(*adv, BT_LE_PER_ADV_DEFAULT); + if (err) { + printk("Failed to set periodic advertising parameters: %d\n", err); + + return err; + } + + return 0; +} + +static int setup_extended_adv_data(struct bt_cap_broadcast_source *source, + struct bt_le_ext_adv *adv) +{ + /* Broadcast Audio Streaming Endpoint advertising data */ + NET_BUF_SIMPLE_DEFINE(ad_buf, + BT_UUID_SIZE_16 + BT_AUDIO_BROADCAST_ID_SIZE); + NET_BUF_SIMPLE_DEFINE(base_buf, 128); + NET_BUF_SIMPLE_DEFINE(pbp_ad_buf, BT_UUID_SIZE_16 + 1 + ARRAY_SIZE(pba_metadata)); + static enum bt_pbp_announcement_feature pba_params; + struct bt_data ext_ad[4]; + struct bt_data per_ad; + uint32_t broadcast_id; + int err; + + err = bt_cap_initiator_broadcast_get_id(source, &broadcast_id); + if (err != 0) { + printk("Unable to get broadcast ID: %d\n", err); + + return err; + } + + /* Setup extended advertising data */ + ext_ad[0].type = BT_DATA_GAP_APPEARANCE; + ext_ad[0].data_len = 2; + ext_ad[0].data = appearance_addata; + /* Broadcast name AD Type */ + ext_ad[1].type = BT_DATA_BROADCAST_NAME; + ext_ad[1].data_len = ARRAY_SIZE(broadcast_name); + ext_ad[1].data = broadcast_name; + /* Broadcast Audio Announcement */ + net_buf_simple_add_le16(&ad_buf, BT_UUID_BROADCAST_AUDIO_VAL); + net_buf_simple_add_le24(&ad_buf, broadcast_id); + ext_ad[2].type = BT_DATA_SVC_DATA16; + ext_ad[2].data_len = ad_buf.len + sizeof(ext_ad[2].type); + ext_ad[2].data = ad_buf.data; + + /** + * Create a Public Broadcast Announcement + * Cycle between high and standard quality public broadcast audio. + */ + if (pba_params & BT_PBP_ANNOUNCEMENT_FEATURE_HIGH_QUALITY) { + pba_params = 0; + pba_params |= BT_PBP_ANNOUNCEMENT_FEATURE_STANDARD_QUALITY; + printk("Starting stream with standard quality!\n"); + } else { + pba_params = 0; + pba_params |= BT_PBP_ANNOUNCEMENT_FEATURE_HIGH_QUALITY; + printk("Starting stream with high quality!\n"); + } + err = bt_pbp_get_announcement(&pba_metadata[1], ARRAY_SIZE(pba_metadata) - 1, + pba_params, &pbp_ad_buf); + if (err != 0) { + printk("Failed to create public broadcast announcement!: %d\n", err); + + return err; + } + ext_ad[3].type = BT_DATA_SVC_DATA16; + ext_ad[3].data_len = pbp_ad_buf.len; + ext_ad[3].data = pbp_ad_buf.data; + err = bt_le_ext_adv_set_data(adv, ext_ad, ARRAY_SIZE(ext_ad), NULL, 0); + if (err != 0) { + printk("Failed to set extended advertising data: %d\n", err); + + return err; + } + + /* Setup periodic advertising data */ + err = bt_cap_initiator_broadcast_get_base(source, &base_buf); + if (err != 0) { + printk("Failed to get encoded BASE: %d\n", err); + + return err; + } + + per_ad.type = BT_DATA_SVC_DATA16; + per_ad.data_len = base_buf.len; + per_ad.data = base_buf.data; + err = bt_le_per_adv_set_data(adv, &per_ad, 1); + if (err != 0) { + printk("Failed to set periodic advertising data: %d\n", err); + + return err; + } + + return 0; +} + +static int start_extended_adv(struct bt_le_ext_adv *adv) +{ + int err; + + /* Start extended advertising */ + err = bt_le_ext_adv_start(adv, BT_LE_EXT_ADV_START_DEFAULT); + if (err) { + printk("Failed to start extended advertising: %d\n", err); + + return err; + } + + /* Enable Periodic Advertising */ + err = bt_le_per_adv_start(adv); + if (err) { + printk("Failed to enable periodic advertising: %d\n", err); + + return err; + } + + return 0; +} + +static int stop_and_delete_extended_adv(struct bt_le_ext_adv *adv) +{ + int err; + + /* Stop extended advertising */ + err = bt_le_per_adv_stop(adv); + if (err) { + printk("Failed to stop periodic advertising: %d\n", err); + + return err; + } + + err = bt_le_ext_adv_stop(adv); + if (err) { + printk("Failed to stop extended advertising: %d\n", err); + + return err; + } + + err = bt_le_ext_adv_delete(adv); + if (err) { + printk("Failed to delete extended advertising: %d\n", err); + + return err; + } + + return 0; +} + +static int reset(void) +{ + k_sem_reset(&sem_broadcast_started); + k_sem_reset(&sem_broadcast_stopped); + + return 0; +} + +int cap_initiator_init(void) +{ + if (IS_ENABLED(CONFIG_BT_BAP_BROADCAST_SOURCE)) { + broadcast_stream = &broadcast_source_stream; + bt_bap_stream_cb_register(&broadcast_stream->bap_stream, &broadcast_stream_ops); + } + + return 0; +} + +void cap_initiator_setup(void) +{ + int err; + + stream_params.stream = &broadcast_source_stream; + stream_params.data_len = ARRAY_SIZE(bis_codec_data); + stream_params.data = bis_codec_data; + + subgroup_param.stream_count = 1U; + subgroup_param.stream_params = &stream_params; + subgroup_param.codec_cfg = &broadcast_preset_48_2_1.codec_cfg; + + create_param.subgroup_count = 1U; + create_param.subgroup_params = &subgroup_param; + create_param.qos = &broadcast_preset_48_2_1.qos; + create_param.packing = BT_ISO_PACKING_SEQUENTIAL; + create_param.encryption = false; + + while (true) { + err = reset(); + if (err != 0) { + printk("Resetting failed: %d - Aborting\n", err); + + return; + } + + err = setup_extended_adv(&ext_adv); + if (err != 0) { + printk("Unable to setup extended advertiser: %d\n", err); + + return; + } + + err = bt_cap_initiator_broadcast_audio_create(&create_param, &broadcast_source); + if (err != 0) { + printk("Unable to create broadcast source: %d\n", err); + + return; + } + + err = bt_cap_initiator_broadcast_audio_start(broadcast_source, ext_adv); + if (err != 0) { + printk("Unable to start broadcast source: %d\n", err); + + return; + } + + err = setup_extended_adv_data(broadcast_source, ext_adv); + if (err != 0) { + printk("Unable to setup extended advertising data: %d\n", err); + + return; + } + + err = start_extended_adv(ext_adv); + if (err != 0) { + printk("Unable to start extended advertiser: %d\n", err); + + return; + } + k_sem_take(&sem_broadcast_started, K_FOREVER); + + /* Initialize sending */ + for (unsigned int j = 0U; j < BROADCAST_ENQUEUE_COUNT; j++) { + broadcast_sent_cb(&broadcast_stream->bap_stream); + } + + /* Keeping running for a little while */ + k_sleep(K_SECONDS(15)); + + err = bt_cap_initiator_broadcast_audio_stop(broadcast_source); + if (err != 0) { + printk("Failed to stop broadcast source: %d\n", err); + + return; + } + + k_sem_take(&sem_broadcast_stopped, K_FOREVER); + err = bt_cap_initiator_broadcast_audio_delete(broadcast_source); + if (err != 0) { + printk("Failed to stop broadcast source: %d\n", err); + + return; + } + broadcast_source = NULL; + + err = stop_and_delete_extended_adv(ext_adv); + if (err != 0) { + printk("Failed to stop and delete extended advertising: %d\n", err); + + return; + } + } +} + + +int main(void) +{ + int err; + + err = bt_enable(NULL); + if (err != 0) { + printk("Bluetooth enable failed (err %d)\n", err); + + return err; + } + + printk("Bluetooth initialized\n"); + + /* Initialize CAP Initiator */ + err = cap_initiator_init(); + if (err != 0) { + return err; + } + + printk("CAP initialized\n"); + + /* Configure and start broadcast stream */ + cap_initiator_setup(); + + return 0; +} diff --git a/samples/bluetooth/public_broadcast_source/sysbuild.cmake b/samples/bluetooth/public_broadcast_source/sysbuild.cmake new file mode 100644 index 00000000000..d3bf7be5b6c --- /dev/null +++ b/samples/bluetooth/public_broadcast_source/sysbuild.cmake @@ -0,0 +1,24 @@ +# Copyright (c) 2023 Nordic Semiconductor ASA +# SPDX-License-Identifier: Apache-2.0 + +if(NOT("${SB_CONFIG_NET_CORE_BOARD}" STREQUAL "")) + # For builds in the nrf5340, we build the netcore image with the controller + + set(NET_APP hci_ipc) + set(NET_APP_SRC_DIR ${ZEPHYR_BASE}/samples/bluetooth/${NET_APP}) + + ExternalZephyrProject_Add( + APPLICATION ${NET_APP} + SOURCE_DIR ${NET_APP_SRC_DIR} + BOARD ${SB_CONFIG_NET_CORE_BOARD} + ) + + set(${NET_APP}_CONF_FILE + ${NET_APP_SRC_DIR}/nrf5340_cpunet_iso-bt_ll_sw_split.conf + CACHE INTERNAL "" + ) + + native_simulator_set_child_images(${DEFAULT_IMAGE} ${NET_APP}) +endif() + +native_simulator_set_final_executable(${DEFAULT_IMAGE}) diff --git a/samples/bluetooth/tmap_bms/prj.conf b/samples/bluetooth/tmap_bms/prj.conf index ab3641a7a0f..be8acce1880 100644 --- a/samples/bluetooth/tmap_bms/prj.conf +++ b/samples/bluetooth/tmap_bms/prj.conf @@ -1,3 +1,5 @@ +CONFIG_MAIN_STACK_SIZE=2048 + CONFIG_BT=y CONFIG_LOG=y CONFIG_BT_PERIPHERAL=y diff --git a/samples/bluetooth/tmap_bms/src/cap_initiator.c b/samples/bluetooth/tmap_bms/src/cap_initiator.c index af946f8ba94..1e50977eab5 100644 --- a/samples/bluetooth/tmap_bms/src/cap_initiator.c +++ b/samples/bluetooth/tmap_bms/src/cap_initiator.c @@ -16,7 +16,7 @@ #include #define BROADCAST_ENQUEUE_COUNT 2U -#define MOCK_CCID 0xAB + NET_BUF_POOL_FIXED_DEFINE(tx_pool, (BROADCAST_ENQUEUE_COUNT * CONFIG_BT_BAP_BROADCAST_SRC_STREAM_COUNT), BT_ISO_SDU_BUF_SIZE(CONFIG_BT_ISO_TX_MTU), 8, NULL); @@ -32,8 +32,7 @@ static uint8_t bis_codec_data[] = {BT_AUDIO_CODEC_DATA( static const uint8_t new_metadata[] = { BT_AUDIO_CODEC_DATA(BT_AUDIO_METADATA_TYPE_STREAM_CONTEXT, - BT_BYTES_LIST_LE16(BT_AUDIO_CONTEXT_TYPE_MEDIA)), - BT_AUDIO_CODEC_DATA(BT_AUDIO_METADATA_TYPE_CCID_LIST, MOCK_CCID), + BT_BYTES_LIST_LE16(BT_AUDIO_CONTEXT_TYPE_MEDIA)) }; static struct bt_bap_lc3_preset broadcast_preset_48_2_1 = @@ -60,6 +59,7 @@ static void broadcast_started_cb(struct bt_bap_stream *stream) static void broadcast_stopped_cb(struct bt_bap_stream *stream, uint8_t reason) { printk("Stream %p stopped with reason 0x%02X\n", stream, reason); + k_sem_give(&sem_broadcast_stopped); } @@ -151,11 +151,13 @@ static int setup_extended_adv_data(struct bt_cap_broadcast_source *source, ext_ad[0].type = BT_DATA_SVC_DATA16; ext_ad[0].data_len = ARRAY_SIZE(tmap_addata); ext_ad[0].data = tmap_addata; + /* Broadcast Audio Announcement */ net_buf_simple_add_le16(&ad_buf, BT_UUID_BROADCAST_AUDIO_VAL); net_buf_simple_add_le24(&ad_buf, broadcast_id); ext_ad[1].type = BT_DATA_SVC_DATA16; ext_ad[1].data_len = ad_buf.len + sizeof(ext_ad[1].type); ext_ad[1].data = ad_buf.data; + err = bt_le_ext_adv_set_data(adv, ext_ad, ARRAY_SIZE(ext_ad), NULL, 0); if (err != 0) { printk("Failed to set extended advertising data: %d\n", err); diff --git a/subsys/bluetooth/Kconfig.logging b/subsys/bluetooth/Kconfig.logging index 5a7032723fc..c103a42c316 100644 --- a/subsys/bluetooth/Kconfig.logging +++ b/subsys/bluetooth/Kconfig.logging @@ -846,6 +846,12 @@ legacy-debug-sym = BT_DEBUG_VOCS_CLIENT module-str = "Volume Offset Control Service client" source "subsys/bluetooth/common/Kconfig.template.log_config_bt" +# PBP + +module = BT_PBP +module-str = "Public Broadcast Profile" +source "${ZEPHYR_BASE}/subsys/logging/Kconfig.template.log_config" + endmenu # Audio menu "Others" diff --git a/subsys/bluetooth/audio/CMakeLists.txt b/subsys/bluetooth/audio/CMakeLists.txt index 26185111ce9..293498fbd40 100644 --- a/subsys/bluetooth/audio/CMakeLists.txt +++ b/subsys/bluetooth/audio/CMakeLists.txt @@ -67,3 +67,4 @@ if (CONFIG_BT_CAP_INITIATOR OR CONFIG_BT_CAP_COMMANDER) endif() zephyr_library_sources_ifdef(CONFIG_BT_TMAP tmap.c) zephyr_library_sources_ifdef(CONFIG_BT_GMAP gmap_client.c gmap_server.c) +zephyr_library_sources_ifdef(CONFIG_BT_PBP pbp.c) diff --git a/subsys/bluetooth/audio/Kconfig b/subsys/bluetooth/audio/Kconfig index d720b095223..b60475c02e2 100644 --- a/subsys/bluetooth/audio/Kconfig +++ b/subsys/bluetooth/audio/Kconfig @@ -61,6 +61,7 @@ rsource "Kconfig.mctl" rsource "Kconfig.cap" rsource "Kconfig.tmap" rsource "Kconfig.gmap" +rsource "Kconfig.pbp" module = BT_AUDIO module-str = "Bluetooth Audio" diff --git a/subsys/bluetooth/audio/Kconfig.pbp b/subsys/bluetooth/audio/Kconfig.pbp new file mode 100644 index 00000000000..cb24845b202 --- /dev/null +++ b/subsys/bluetooth/audio/Kconfig.pbp @@ -0,0 +1,12 @@ +# Bluetooth Audio - Public Broadcast Profile (PBP) options +# +# Copyright 2023 NXP +# +# SPDX-License-Identifier: Apache-2.0 +# + +config BT_PBP + bool "Public Broadcast Profile [EXPERIMENTAL]" + select EXPERIMENTAL + help + Enabling this will enable PBP. diff --git a/subsys/bluetooth/audio/pbp.c b/subsys/bluetooth/audio/pbp.c new file mode 100644 index 00000000000..9cb589c9095 --- /dev/null +++ b/subsys/bluetooth/audio/pbp.c @@ -0,0 +1,81 @@ +/* + * Copyright 2023 NXP + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include +#include +#include +#include +#include +#include +#include + +LOG_MODULE_REGISTER(bt_pbp, CONFIG_BT_PBP_LOG_LEVEL); + +int bt_pbp_get_announcement(const uint8_t meta[], size_t meta_len, + enum bt_pbp_announcement_feature features, + struct net_buf_simple *pba_data_buf) +{ + CHECKIF(pba_data_buf == NULL) { + LOG_DBG("No buffer provided for advertising data!\n"); + + return -EINVAL; + } + + CHECKIF((meta == NULL && meta_len != 0) || (meta != NULL && meta_len == 0)) { + LOG_DBG("Invalid metadata combination: %p %zu", meta, meta_len); + + return -EINVAL; + } + + CHECKIF(pba_data_buf->size < (meta_len + BT_PBP_MIN_PBA_SIZE)) { + LOG_DBG("Buffer size needs to be at least %d!\n", meta_len + BT_PBP_MIN_PBA_SIZE); + + return -EINVAL; + } + + /* Fill Announcement data */ + net_buf_simple_add_le16(pba_data_buf, BT_UUID_PBA_VAL); + net_buf_simple_add_u8(pba_data_buf, features); + net_buf_simple_add_u8(pba_data_buf, meta_len); + net_buf_simple_add_mem(pba_data_buf, meta, meta_len); + + return 0; +} + +uint8_t bt_pbp_parse_announcement(struct bt_data *data, + enum bt_pbp_announcement_feature *features, + uint8_t *meta) +{ + uint8_t meta_len = 0; + struct bt_uuid_16 adv_uuid; + + CHECKIF(!data || !features || !meta) { + return -EINVAL; + } + + if (data->data_len < BT_PBP_MIN_PBA_SIZE) { + return -EBADMSG; + } + + if (data->type != BT_DATA_SVC_DATA16) { + return -EINVAL; + } + + if (!bt_uuid_create(&adv_uuid.uuid, data->data, BT_UUID_SIZE_16)) { + return -EINVAL; + } + + if (bt_uuid_cmp(&adv_uuid.uuid, BT_UUID_PBA)) { + return -EBADMSG; + } + + /* Copy source features, metadata length and metadata from the Announcement */ + *features = data->data[BT_UUID_SIZE_16]; + meta_len = data->data[BT_UUID_SIZE_16 + sizeof(uint8_t)]; + memcpy(meta, data->data + BT_PBP_MIN_PBA_SIZE, meta_len); + + return meta_len; +} diff --git a/subsys/bluetooth/audio/shell/CMakeLists.txt b/subsys/bluetooth/audio/shell/CMakeLists.txt index 18cb1df9933..9913d92994a 100644 --- a/subsys/bluetooth/audio/shell/CMakeLists.txt +++ b/subsys/bluetooth/audio/shell/CMakeLists.txt @@ -89,3 +89,7 @@ zephyr_library_sources_ifdef( CONFIG_BT_BAP_BROADCAST_ASSISTANT bap_broadcast_assistant.c ) +zephyr_library_sources_ifdef( + CONFIG_BT_PBP + pbp.c + ) diff --git a/subsys/bluetooth/audio/shell/audio.h b/subsys/bluetooth/audio/shell/audio.h index d204dc3dc2d..a674b474d07 100644 --- a/subsys/bluetooth/audio/shell/audio.h +++ b/subsys/bluetooth/audio/shell/audio.h @@ -30,6 +30,7 @@ ssize_t audio_pa_data_add(struct bt_data *data_array, const size_t data_array_si ssize_t csis_ad_data_add(struct bt_data *data, const size_t data_size, const bool discoverable); size_t cap_acceptor_ad_data_add(struct bt_data data[], size_t data_size, bool discoverable); size_t gmap_ad_data_add(struct bt_data data[], size_t data_size); +size_t pbp_ad_data_add(struct bt_data data[], size_t data_size); #if defined(CONFIG_BT_AUDIO) /* Must guard before including audio.h as audio.h uses Kconfigs guarded by diff --git a/subsys/bluetooth/audio/shell/pbp.c b/subsys/bluetooth/audio/shell/pbp.c new file mode 100644 index 00000000000..9519fd19274 --- /dev/null +++ b/subsys/bluetooth/audio/shell/pbp.c @@ -0,0 +1,88 @@ +/** @file + * @brief Bluetooth Public Broadcast Profile shell + */ + +/* + * Copyright 2023 NXP + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include +#include +#include +#include + +#include "shell/bt.h" + +#define PBS_DEMO 'P', 'B', 'P' + +const uint8_t pba_metadata[] = { + BT_AUDIO_CODEC_DATA(BT_AUDIO_METADATA_TYPE_PROGRAM_INFO, PBS_DEMO) +}; + +/* Buffer to hold the Public Broadcast Announcement */ +NET_BUF_SIMPLE_DEFINE_STATIC(pbp_ad_buf, BT_PBP_MIN_PBA_SIZE + ARRAY_SIZE(pba_metadata)); + +enum bt_pbp_announcement_feature pbp_features; +extern const struct shell *ctx_shell; + +static int cmd_pbp_set_features(const struct shell *sh, size_t argc, char **argv) +{ + int err = 0; + enum bt_pbp_announcement_feature features; + + features = shell_strtoul(argv[1], 16, &err); + if (err != 0) { + shell_error(sh, "Could not parse received features: %d", err); + + return -ENOEXEC; + } + + pbp_features = features; + + return err; +} + +size_t pbp_ad_data_add(struct bt_data data[], size_t data_size) +{ + int err; + + err = bt_pbp_get_announcement(pba_metadata, + ARRAY_SIZE(pba_metadata), + pbp_features, + &pbp_ad_buf); + + if (err != 0) { + shell_info(ctx_shell, "Create Public Broadcast Announcement"); + } else { + shell_error(ctx_shell, "Failed to create Public Broadcast Announcement: %d", err); + } + + __ASSERT(data_size > 0, "No space for Public Broadcast Announcement"); + data[0].type = BT_DATA_SVC_DATA16; + data[0].data_len = pbp_ad_buf.len; + data[0].data = pbp_ad_buf.data; + + return 1U; +} + +static int cmd_pbp(const struct shell *sh, size_t argc, char **argv) +{ + if (argc > 1) { + shell_error(sh, "%s unknown parameter: %s", argv[0], argv[1]); + } else { + shell_error(sh, "%s missing subcomand", argv[0]); + } + + return -ENOEXEC; +} + +SHELL_STATIC_SUBCMD_SET_CREATE(pbp_cmds, + SHELL_CMD_ARG(set_features, NULL, + "Set the Public Broadcast Announcement features", + cmd_pbp_set_features, 2, 0), + SHELL_SUBCMD_SET_END +); + +SHELL_CMD_ARG_REGISTER(pbp, &pbp_cmds, "Bluetooth pbp shell commands", cmd_pbp, 1, 1); diff --git a/tests/bluetooth/shell/audio.conf b/tests/bluetooth/shell/audio.conf index 0458bcb82b1..0a38138b6ae 100644 --- a/tests/bluetooth/shell/audio.conf +++ b/tests/bluetooth/shell/audio.conf @@ -162,6 +162,9 @@ CONFIG_BT_CAP_COMMANDER=y # Telephone and Media Audio Profile CONFIG_BT_TMAP=y +# Public Broadcast Profile +CONFIG_BT_PBP=y + CONFIG_BT_PACS_SUPPORTED_CONTEXT_NOTIFIABLE=y CONFIG_BT_PAC_SNK_LOC_NOTIFIABLE=y CONFIG_BT_PAC_SRC_LOC_NOTIFIABLE=y diff --git a/tests/bsim/bluetooth/audio/prj.conf b/tests/bsim/bluetooth/audio/prj.conf index 06114766881..871034f2fcc 100644 --- a/tests/bsim/bluetooth/audio/prj.conf +++ b/tests/bsim/bluetooth/audio/prj.conf @@ -149,6 +149,9 @@ CONFIG_BT_GATT_AUTO_RESUBSCRIBE=n # Gaming Audio Profile CONFIG_BT_GMAP=y +# Public Broadcast Profile +CONFIG_BT_PBP=y + # DEBUGGING CONFIG_LOG=y CONFIG_LOG_FUNC_NAME_PREFIX_ERR=y diff --git a/tests/bsim/bluetooth/audio/src/common.h b/tests/bsim/bluetooth/audio/src/common.h index 0fb3aac451d..2e87bac169e 100644 --- a/tests/bsim/bluetooth/audio/src/common.h +++ b/tests/bsim/bluetooth/audio/src/common.h @@ -87,6 +87,8 @@ static const uint8_t mock_iso_data[] = { #define SYNC_RETRY_COUNT 6 /* similar to retries for connections */ #define PA_SYNC_SKIP 5 +#define PBP_STREAMS_TO_SEND 2 + extern struct bt_le_scan_cb common_scan_cb; extern const struct bt_data ad[AD_SIZE]; extern struct bt_conn *default_conn; diff --git a/tests/bsim/bluetooth/audio/src/main.c b/tests/bsim/bluetooth/audio/src/main.c index 284f29ca88f..50784a4dc4d 100644 --- a/tests/bsim/bluetooth/audio/src/main.c +++ b/tests/bsim/bluetooth/audio/src/main.c @@ -36,6 +36,8 @@ extern struct bst_test_list *test_tmap_client_install(struct bst_test_list *test extern struct bst_test_list *test_tmap_server_install(struct bst_test_list *tests); extern struct bst_test_list *test_pacs_notify_client_install(struct bst_test_list *tests); extern struct bst_test_list *test_pacs_notify_server_install(struct bst_test_list *tests); +extern struct bst_test_list *test_public_broadcast_source_install(struct bst_test_list *tests); +extern struct bst_test_list *test_public_broadcast_sink_install(struct bst_test_list *tests); extern struct bst_test_list *test_csip_notify_client_install(struct bst_test_list *tests); extern struct bst_test_list *test_csip_notify_server_install(struct bst_test_list *tests); extern struct bst_test_list *test_gmap_ugg_install(struct bst_test_list *tests); @@ -72,6 +74,8 @@ bst_test_install_t test_installers[] = { test_tmap_client_install, test_pacs_notify_client_install, test_pacs_notify_server_install, + test_public_broadcast_source_install, + test_public_broadcast_sink_install, test_csip_notify_client_install, test_csip_notify_server_install, test_gmap_ugg_install, diff --git a/tests/bsim/bluetooth/audio/src/pbp_public_broadcast_sink_test.c b/tests/bsim/bluetooth/audio/src/pbp_public_broadcast_sink_test.c new file mode 100644 index 00000000000..6154fae570e --- /dev/null +++ b/tests/bsim/bluetooth/audio/src/pbp_public_broadcast_sink_test.c @@ -0,0 +1,432 @@ +/* + * Copyright 2023 NXP + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#if defined(CONFIG_BT_PBP) + +#include + +#include +#include +#include +#include +#include +#include +#include + +#include "common.h" + +#define SEM_TIMEOUT K_SECONDS(1.5) +#define PA_SYNC_SKIP 5 +#define SYNC_RETRY_COUNT 6 /* similar to retries for connections */ + +extern enum bst_result_t bst_result; + +static bool pbs_found; + +static K_SEM_DEFINE(sem_pa_synced, 0U, 1U); +static K_SEM_DEFINE(sem_base_received, 0U, 1U); +static K_SEM_DEFINE(sem_syncable, 0U, 1U); +static K_SEM_DEFINE(sem_pa_sync_lost, 0U, 1U); +static K_SEM_DEFINE(sem_data_received, 0U, 1U); + +static struct bt_bap_broadcast_sink *broadcast_sink; +static struct bt_le_per_adv_sync *bcast_pa_sync; + +static struct bt_bap_stream streams[CONFIG_BT_BAP_BROADCAST_SNK_STREAM_COUNT]; +static struct bt_bap_stream *streams_p[ARRAY_SIZE(streams)]; + +static const struct bt_audio_codec_cap codec = + BT_AUDIO_CODEC_CAP_LC3(BT_AUDIO_CODEC_LC3_FREQ_16KHZ | BT_AUDIO_CODEC_LC3_FREQ_24KHZ + | BT_AUDIO_CODEC_LC3_FREQ_48KHZ, + BT_AUDIO_CODEC_LC3_DURATION_10, + BT_AUDIO_CODEC_LC3_CHAN_COUNT_SUPPORT(1), 40u, 155u, 1u, + BT_AUDIO_CONTEXT_TYPE_MEDIA +); + +/* Create a mask for the maximum BIS we can sync to using the number of streams + * we have. We add an additional 1 since the bis indexes start from 1 and not + * 0. + */ +static const uint32_t bis_index_mask = BIT_MASK(ARRAY_SIZE(streams) + 1U); +static uint32_t bis_index_bitfield; +static uint32_t broadcast_id = INVALID_BROADCAST_ID; + +static struct bt_pacs_cap cap = { + .codec_cap = &codec, +}; + +static void broadcast_scan_recv(const struct bt_le_scan_recv_info *info, + struct net_buf_simple *ad); + +static struct bt_le_scan_cb broadcast_scan_cb = { + .recv = broadcast_scan_recv +}; + +static void base_recv_cb(struct bt_bap_broadcast_sink *sink, const struct bt_bap_base *base, + size_t base_size) +{ + k_sem_give(&sem_base_received); +} + +static void syncable_cb(struct bt_bap_broadcast_sink *sink, bool encrypted) +{ + k_sem_give(&sem_syncable); +} + +static struct bt_bap_broadcast_sink_cb broadcast_sink_cbs = { + .base_recv = base_recv_cb, + .syncable = syncable_cb, +}; + +static void started_cb(struct bt_bap_stream *stream) +{ + printk("Stream %p started\n", stream); +} + +static void stopped_cb(struct bt_bap_stream *stream, uint8_t reason) +{ + printk("Stream %p stopped with reason 0x%02X\n", stream, reason); +} + +static void recv_cb(struct bt_bap_stream *stream, + const struct bt_iso_recv_info *info, + struct net_buf *buf) +{ + static uint32_t recv_cnt; + + recv_cnt++; + if (recv_cnt >= MIN_SEND_COUNT) { + k_sem_give(&sem_data_received); + } + printk("Receiving ISO packets\n"); +} + +static uint16_t interval_to_sync_timeout(uint16_t interval) +{ + uint32_t interval_ms; + uint16_t timeout; + + /* Ensure that the following calculation does not overflow silently */ + __ASSERT(SYNC_RETRY_COUNT < 10, "SYNC_RETRY_COUNT shall be less than 10"); + + /* Add retries and convert to unit in 10's of ms */ + interval_ms = BT_GAP_PER_ADV_INTERVAL_TO_MS(interval); + timeout = (interval_ms * SYNC_RETRY_COUNT) / 10; + + /* Enforce restraints */ + timeout = CLAMP(timeout, BT_GAP_PER_ADV_MIN_TIMEOUT, + BT_GAP_PER_ADV_MAX_TIMEOUT); + + return timeout; +} + +static bool pa_decode_base(struct bt_data *data, void *user_data) +{ + const struct bt_bap_base *base = bt_bap_base_get_base_from_ad(data); + uint32_t base_bis_index_bitfield = 0U; + int err; + + /* Base is NULL if the data does not contain a valid BASE */ + if (base == NULL) { + return true; + } + + err = bt_bap_base_get_bis_indexes(base, &base_bis_index_bitfield); + if (err != 0) { + return false; + } + + bis_index_bitfield = base_bis_index_bitfield & bis_index_mask; + k_sem_give(&sem_base_received); + + return false; +} + +static void broadcast_pa_recv(struct bt_le_per_adv_sync *sync, + const struct bt_le_per_adv_sync_recv_info *info, + struct net_buf_simple *buf) +{ + bt_data_parse(buf, pa_decode_base, NULL); +} + +static void broadcast_pa_synced(struct bt_le_per_adv_sync *sync, + struct bt_le_per_adv_sync_synced_info *info) +{ + k_sem_give(&sem_pa_synced); +} + +static void broadcast_pa_terminated(struct bt_le_per_adv_sync *sync, + const struct bt_le_per_adv_sync_term_info *info) +{ + if (sync == bcast_pa_sync) { + printk("PA sync %p lost with reason %u\n", sync, info->reason); + bcast_pa_sync = NULL; + + k_sem_give(&sem_pa_sync_lost); + } +} + +static struct bt_bap_stream_ops stream_ops = { + .started = started_cb, + .stopped = stopped_cb, + .recv = recv_cb +}; + +static struct bt_le_per_adv_sync_cb broadcast_sync_cb = { + .synced = broadcast_pa_synced, + .recv = broadcast_pa_recv, + .term = broadcast_pa_terminated, +}; + +static int reset(void) +{ + int err; + + k_sem_reset(&sem_pa_synced); + k_sem_reset(&sem_base_received); + k_sem_reset(&sem_syncable); + k_sem_reset(&sem_pa_sync_lost); + + if (broadcast_sink != NULL) { + err = bt_bap_broadcast_sink_delete(broadcast_sink); + if (err) { + printk("Deleting broadcast sink failed (err %d)\n", err); + + return err; + } + + broadcast_sink = NULL; + } + + return 0; +} + +static int init(void) +{ + int err; + + err = bt_enable(NULL); + if (err) { + FAIL("Bluetooth enable failed (err %d)\n", err); + + return err; + } + + printk("Bluetooth initialized\n"); + + bt_bap_broadcast_sink_register_cb(&broadcast_sink_cbs); + bt_le_per_adv_sync_cb_register(&broadcast_sync_cb); + + err = bt_pacs_cap_register(BT_AUDIO_DIR_SINK, &cap); + if (err) { + printk("Capability register failed (err %d)\n", err); + + return err; + } + + for (size_t i = 0U; i < ARRAY_SIZE(streams); i++) { + streams[i].ops = &stream_ops; + } + + for (size_t i = 0U; i < ARRAY_SIZE(streams_p); i++) { + streams_p[i] = &streams[i]; + } + + return 0; +} + +static void sync_broadcast_pa(const struct bt_le_scan_recv_info *info) +{ + struct bt_le_per_adv_sync_param param; + int err; + + /* Unregister the callbacks to prevent broadcast_scan_recv to be called again */ + bt_le_scan_cb_unregister(&broadcast_scan_cb); + err = bt_le_scan_stop(); + if (err != 0) { + printk("Could not stop scan: %d", err); + } + + bt_addr_le_copy(¶m.addr, info->addr); + param.options = 0; + param.sid = info->sid; + param.skip = PA_SYNC_SKIP; + param.timeout = interval_to_sync_timeout(info->interval); + err = bt_le_per_adv_sync_create(¶m, &bcast_pa_sync); + if (err != 0) { + printk("Could not sync to PA: %d", err); + + } +} + +static bool scan_check_and_sync_broadcast(struct bt_data *data, void *user_data) +{ + struct bt_uuid_16 adv_uuid; + uint8_t source_features = 0U; + uint8_t meta[50]; + + if (data->type != BT_DATA_SVC_DATA16) { + return true; + } + + if (!bt_uuid_create(&adv_uuid.uuid, data->data, BT_UUID_SIZE_16)) { + return true; + } + + if (!bt_uuid_cmp(&adv_uuid.uuid, BT_UUID_BROADCAST_AUDIO)) { + /* Save broadcast_id */ + if (broadcast_id == INVALID_BROADCAST_ID) { + broadcast_id = sys_get_le24(data->data + BT_UUID_SIZE_16); + } + + /* Found Broadcast Audio and Public Broadcast Announcement Services */ + if (pbs_found) { + return false; + } + } + + if (!bt_uuid_cmp(&adv_uuid.uuid, BT_UUID_PBA)) { + bt_pbp_parse_announcement(data, &source_features, meta); + if (!(source_features & BT_PBP_ANNOUNCEMENT_FEATURE_HIGH_QUALITY)) { + /* This is a Standard Quality Public Broadcast Audio stream - do not sync */ + printk("This is a Standard Quality Public Broadcast Audio stream\n"); + pbs_found = false; + + return true; + } + + printk("Found Suitable Public Broadcast Announcement\n"); + pbs_found = true; + + /* Continue parsing if Broadcast Audio Announcement Service was not found */ + if (broadcast_id == INVALID_BROADCAST_ID) { + return true; + } + + return false; + } + + /* Continue parsing */ + return true; +} + +static void broadcast_scan_recv(const struct bt_le_scan_recv_info *info, + struct net_buf_simple *ad) +{ + pbs_found = false; + + /* We are only interested in non-connectable periodic advertisers */ + if ((info->adv_props & BT_GAP_ADV_PROP_CONNECTABLE) || + info->interval == 0) { + return; + } + + bt_data_parse(ad, scan_check_and_sync_broadcast, (void *)&broadcast_id); + + if ((broadcast_id != INVALID_BROADCAST_ID) && pbs_found) { + sync_broadcast_pa(info); + } +} + +static void test_main(void) +{ + int count = 0; + int err; + + init(); + + while (count < PBP_STREAMS_TO_SEND) { + err = reset(); + if (err != 0) { + printk("Resetting failed: %d\n", err); + break; + } + + /* Register callbacks */ + bt_le_scan_cb_register(&broadcast_scan_cb); + + /* Start scanning */ + err = bt_le_scan_start(BT_LE_SCAN_PASSIVE, NULL); + if (err) { + printk("Scan start failed (err %d)\n", err); + break; + } + + /* Wait for PA sync */ + err = k_sem_take(&sem_pa_synced, SEM_TIMEOUT); + if (err != 0) { + printk("sem_pa_synced timed out\n"); + break; + } + + /* Wait for BASE decode */ + err = k_sem_take(&sem_base_received, SEM_TIMEOUT); + if (err != 0) { + printk("sem_base_received timed out\n"); + break; + } + + /* Create broadcast sink */ + err = bt_bap_broadcast_sink_create(bcast_pa_sync, broadcast_id, &broadcast_sink); + if (err != 0) { + printk("Sink not created!\n"); + break; + } + + k_sem_take(&sem_syncable, SEM_TIMEOUT); + if (err != 0) { + printk("sem_syncable timed out\n"); + break; + } + + /* Sync to broadcast source */ + err = bt_bap_broadcast_sink_sync(broadcast_sink, bis_index_bitfield, + streams_p, NULL); + if (err != 0) { + printk("Unable to sync to broadcast source: %d\n", err); + break; + } + + /* Wait for data */ + k_sem_take(&sem_data_received, SEM_TIMEOUT); + + /* Wait for the stream to end */ + k_sem_take(&sem_pa_sync_lost, SEM_TIMEOUT); + + count++; + } + + if (count == PBP_STREAMS_TO_SEND - 1) { + /* Pass if we synced only with the high quality broadcast */ + PASS("Public Broadcast sink passed\n"); + } else { + FAIL("Public Broadcast sink failed\n"); + } +} + +static const struct bst_test_instance test_public_broadcast_sink[] = { + { + .test_id = "public_broadcast_sink", + .test_post_init_f = test_init, + .test_tick_f = test_tick, + .test_main_f = test_main + }, + BSTEST_END_MARKER +}; + +struct bst_test_list *test_public_broadcast_sink_install(struct bst_test_list *tests) +{ + return bst_add_tests(tests, test_public_broadcast_sink); +} + +#else /* !CONFIG_BT_PBP */ + +struct bst_test_list *test_public_broadcast_sink_install(struct bst_test_list *tests) +{ + return tests; +} + +#endif /* CONFIG_BT_PBP */ diff --git a/tests/bsim/bluetooth/audio/src/pbp_public_broadcast_source_test.c b/tests/bsim/bluetooth/audio/src/pbp_public_broadcast_source_test.c new file mode 100644 index 00000000000..4602e4963b2 --- /dev/null +++ b/tests/bsim/bluetooth/audio/src/pbp_public_broadcast_source_test.c @@ -0,0 +1,394 @@ +/* + * Copyright 2023 NXP + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#if defined(CONFIG_BT_PBP) + +#include +#include +#include +#include +#include +#include + +#include "common.h" + +/* When BROADCAST_ENQUEUE_COUNT > 1 we can enqueue enough buffers to ensure that + * the controller is never idle + */ +#define BROADCAST_ENQUEUE_COUNT 2U +#define BUF_NEEDED (BROADCAST_ENQUEUE_COUNT * CONFIG_BT_BAP_BROADCAST_SRC_STREAM_COUNT) +/* PBS ASCII text */ +#define PBS_DEMO 'P', 'B', 'P' +#define SEM_TIMEOUT K_SECONDS(2) + +extern enum bst_result_t bst_result; + +BUILD_ASSERT(CONFIG_BT_ISO_TX_BUF_COUNT >= BUF_NEEDED, + "CONFIG_BT_ISO_TX_BUF_COUNT should be at least " + "BROADCAST_ENQUEUE_COUNT * CONFIG_BT_BAP_BROADCAST_SRC_STREAM_COUNT"); + +NET_BUF_POOL_FIXED_DEFINE(tx_pool, + BUF_NEEDED, + BT_ISO_SDU_BUF_SIZE(CONFIG_BT_ISO_TX_MTU), + CONFIG_BT_CONN_TX_USER_DATA_SIZE, NULL); + +const uint8_t pba_metadata[] = { + BT_AUDIO_CODEC_DATA(BT_AUDIO_METADATA_TYPE_PROGRAM_INFO, PBS_DEMO)}; + +static uint8_t bis_codec_data[] = { + BT_AUDIO_CODEC_DATA(BT_AUDIO_CODEC_CONFIG_LC3_FREQ, + BT_BYTES_LIST_LE16(BT_AUDIO_CODEC_CONFIG_LC3_FREQ_48KHZ))}; + +static struct bt_cap_stream broadcast_source_stream; +static struct bt_cap_stream *broadcast_stream; + +static struct bt_cap_initiator_broadcast_stream_param stream_params; +static struct bt_cap_initiator_broadcast_subgroup_param subgroup_param; +static struct bt_cap_initiator_broadcast_create_param create_param; +static struct bt_cap_broadcast_source *broadcast_source; + +static struct bt_bap_lc3_preset broadcast_preset_48_2_1 = + BT_BAP_LC3_UNICAST_PRESET_48_2_1(BT_AUDIO_LOCATION_FRONT_LEFT, + BT_AUDIO_CONTEXT_TYPE_MEDIA); + +static K_SEM_DEFINE(sem_started, 0U, 1); +static K_SEM_DEFINE(sem_stopped, 0U, 1); + +struct bt_le_ext_adv *adv; + +static void started_cb(struct bt_bap_stream *stream) +{ + printk("Stream %p started\n", stream); + k_sem_give(&sem_started); +} + +static void stopped_cb(struct bt_bap_stream *stream, uint8_t reason) +{ + printk("Stream %p stopped with reason 0x%02X\n", stream, reason); + k_sem_give(&sem_stopped); +} + +static void sent_cb(struct bt_bap_stream *stream) +{ + static uint8_t mock_data[CONFIG_BT_ISO_TX_MTU]; + static bool mock_data_initialized; + static uint32_t seq_num; + struct net_buf *buf; + int ret; + + if (broadcast_preset_48_2_1.qos.sdu > CONFIG_BT_ISO_TX_MTU) { + printk("Invalid SDU %u for the MTU: %d", + broadcast_preset_48_2_1.qos.sdu, CONFIG_BT_ISO_TX_MTU); + return; + } + + if (!mock_data_initialized) { + for (size_t i = 0U; i < ARRAY_SIZE(mock_data); i++) { + /* Initialize mock data */ + mock_data[i] = (uint8_t)i; + } + mock_data_initialized = true; + } + + buf = net_buf_alloc(&tx_pool, K_FOREVER); + if (buf == NULL) { + printk("Could not allocate buffer when sending on %p\n", stream); + return; + } + + net_buf_reserve(buf, BT_ISO_CHAN_SEND_RESERVE); + net_buf_add_mem(buf, mock_data, broadcast_preset_48_2_1.qos.sdu); + ret = bt_bap_stream_send(stream, buf, seq_num++, BT_ISO_TIMESTAMP_NONE); + if (ret < 0) { + /* This will end broadcasting on this stream. */ + net_buf_unref(buf); + return; + } +} + +static int setup_extended_adv_data(struct bt_cap_broadcast_source *source, + struct bt_le_ext_adv *adv) +{ + /* Broadcast Audio Streaming Endpoint advertising data */ + NET_BUF_SIMPLE_DEFINE(ad_buf, BT_UUID_SIZE_16 + BT_AUDIO_BROADCAST_ID_SIZE); + NET_BUF_SIMPLE_DEFINE(pbp_ad_buf, BT_UUID_SIZE_16 + 1 + ARRAY_SIZE(pba_metadata)); + NET_BUF_SIMPLE_DEFINE(base_buf, 128); + static enum bt_pbp_announcement_feature pba_params; + struct bt_data ext_ad[2]; + struct bt_data per_ad; + uint32_t broadcast_id; + int err; + + err = bt_cap_initiator_broadcast_get_id(source, &broadcast_id); + if (err != 0) { + printk("Unable to get broadcast ID: %d\n", err); + + return err; + } + + /* Broadcast Audio Announcements */ + net_buf_simple_add_le16(&ad_buf, BT_UUID_BROADCAST_AUDIO_VAL); + net_buf_simple_add_le24(&ad_buf, broadcast_id); + ext_ad[0].type = BT_DATA_SVC_DATA16; + ext_ad[0].data_len = ad_buf.len + sizeof(ext_ad[0].type); + ext_ad[0].data = ad_buf.data; + + /** + * Create a Public Broadcast Announcement + * Cycle between high and standard quality public broadcast audio. + */ + if (pba_params & BT_PBP_ANNOUNCEMENT_FEATURE_HIGH_QUALITY) { + pba_params = 0; + pba_params |= BT_PBP_ANNOUNCEMENT_FEATURE_STANDARD_QUALITY; + printk("Starting stream with standard quality!\n"); + } else { + pba_params = 0; + pba_params |= BT_PBP_ANNOUNCEMENT_FEATURE_HIGH_QUALITY; + printk("Starting stream with high quality!\n"); + } + + err = bt_pbp_get_announcement(pba_metadata, ARRAY_SIZE(pba_metadata) - 1, + pba_params, &pbp_ad_buf); + if (err != 0) { + printk("Failed to create public broadcast announcement!: %d\n", err); + + return err; + } + ext_ad[1].type = BT_DATA_SVC_DATA16; + ext_ad[1].data_len = pbp_ad_buf.len; + ext_ad[1].data = pbp_ad_buf.data; + + err = bt_le_ext_adv_set_data(adv, ext_ad, ARRAY_SIZE(ext_ad), NULL, 0); + if (err != 0) { + printk("Failed to set extended advertising data: %d\n", err); + + return err; + } + + /* Setup periodic advertising data */ + err = bt_cap_initiator_broadcast_get_base(source, &base_buf); + if (err != 0) { + printk("Failed to get encoded BASE: %d\n", err); + + return err; + } + + per_ad.type = BT_DATA_SVC_DATA16; + per_ad.data_len = base_buf.len; + per_ad.data = base_buf.data; + err = bt_le_per_adv_set_data(adv, &per_ad, 1); + if (err != 0) { + printk("Failed to set periodic advertising data: %d\n", err); + + return err; + } + + return 0; +} + +static int start_extended_adv(struct bt_le_ext_adv *adv) +{ + int err; + + /* Start extended advertising */ + err = bt_le_ext_adv_start(adv, BT_LE_EXT_ADV_START_DEFAULT); + if (err) { + printk("Failed to start extended advertising: %d\n", err); + + return err; + } + + /* Enable Periodic Advertising */ + err = bt_le_per_adv_start(adv); + if (err) { + printk("Failed to enable periodic advertising: %d\n", err); + + return err; + } + + return 0; +} + +static int setup_extended_adv(struct bt_le_ext_adv **adv) +{ + int err; + + /* Create a non-connectable non-scannable advertising set */ + err = bt_le_ext_adv_create(BT_LE_EXT_ADV_NCONN_NAME, NULL, adv); + if (err != 0) { + printk("Unable to create extended advertising set: %d\n", err); + + return err; + } + + /* Set periodic advertising parameters */ + err = bt_le_per_adv_set_param(*adv, BT_LE_PER_ADV_DEFAULT); + if (err) { + printk("Failed to set periodic advertising parameters: %d\n", err); + + return err; + } + + return 0; +} + +static int stop_extended_adv(struct bt_le_ext_adv *adv) +{ + int err; + + err = bt_le_per_adv_stop(adv); + if (err) { + printk("Failed to stop periodic advertising: %d\n", err); + + return err; + } + + err = bt_le_ext_adv_stop(adv); + if (err) { + printk("Failed to stop extended advertising: %d\n", err); + + return err; + } + + err = bt_le_ext_adv_delete(adv); + if (err) { + printk("Failed to delete extended advertising: %d\n", err); + + return err; + } + + return 0; +} + +static struct bt_bap_stream_ops broadcast_stream_ops = { + .started = started_cb, + .stopped = stopped_cb, + .sent = sent_cb +}; + +static void test_main(void) +{ + int err; + int count = 0; + + err = bt_enable(NULL); + if (err) { + FAIL("Bluetooth enable failed (err %d)\n", err); + + return; + } + + broadcast_stream = &broadcast_source_stream; + bt_bap_stream_cb_register(&broadcast_stream->bap_stream, &broadcast_stream_ops); + + stream_params.stream = &broadcast_source_stream; + stream_params.data_len = ARRAY_SIZE(bis_codec_data); + stream_params.data = bis_codec_data; + + subgroup_param.stream_count = 1U; + subgroup_param.stream_params = &stream_params; + subgroup_param.codec_cfg = &broadcast_preset_48_2_1.codec_cfg; + + create_param.subgroup_count = 1U; + create_param.subgroup_params = &subgroup_param; + create_param.qos = &broadcast_preset_48_2_1.qos; + create_param.packing = BT_ISO_PACKING_SEQUENTIAL; + create_param.encryption = false; + + while (count < PBP_STREAMS_TO_SEND) { + k_sem_reset(&sem_started); + k_sem_reset(&sem_stopped); + + err = setup_extended_adv(&adv); + if (err != 0) { + printk("Unable to setup extended advertiser: %d\n", err); + FAIL("Public Broadcast source failed\n"); + } + + err = bt_cap_initiator_broadcast_audio_create(&create_param, &broadcast_source); + if (err != 0) { + printk("Unable to create broadcast source: %d\n", err); + FAIL("Public Broadcast source failed\n"); + } + + err = bt_cap_initiator_broadcast_audio_start(broadcast_source, adv); + if (err != 0) { + printk("Unable to start broadcast source: %d\n", err); + FAIL("Public Broadcast source failed\n"); + } + + err = setup_extended_adv_data(broadcast_source, adv); + if (err != 0) { + printk("Unable to setup extended advertising data: %d\n", err); + FAIL("Public Broadcast source failed\n"); + } + + err = start_extended_adv(adv); + if (err != 0) { + printk("Unable to start extended advertiser: %d\n", err); + FAIL("Public Broadcast source failed\n"); + } + + k_sem_take(&sem_started, SEM_TIMEOUT); + + /* Initialize sending */ + for (unsigned int j = 0U; j < BROADCAST_ENQUEUE_COUNT; j++) { + sent_cb(&broadcast_stream->bap_stream); + } + + /* Keeping running for a little while */ + k_sleep(K_SECONDS(3)); + + err = bt_cap_initiator_broadcast_audio_stop(broadcast_source); + if (err != 0) { + printk("Failed to stop broadcast source: %d\n", err); + FAIL("Public Broadcast source failed\n"); + } + + k_sem_take(&sem_stopped, SEM_TIMEOUT); + err = bt_cap_initiator_broadcast_audio_delete(broadcast_source); + if (err != 0) { + printk("Failed to stop broadcast source: %d\n", err); + FAIL("Public Broadcast source failed\n"); + } + + broadcast_source = NULL; + + err = stop_extended_adv(adv); + if (err != 0) { + printk("Failed to stop and delete extended advertising: %d\n", err); + FAIL("Public Broadcast source failed\n"); + } + + count++; + } + + PASS("Public Broadcast source passed\n"); +} + +static const struct bst_test_instance test_pbp_broadcaster[] = { + { + .test_id = "public_broadcast_source", + .test_post_init_f = test_init, + .test_tick_f = test_tick, + .test_main_f = test_main + }, + BSTEST_END_MARKER +}; + +struct bst_test_list *test_public_broadcast_source_install(struct bst_test_list *tests) +{ + return bst_add_tests(tests, test_pbp_broadcaster); +} + +#else /* CONFIG_BT_PBP */ + +struct bst_test_list *test_public_broadcast_source_install(struct bst_test_list *tests) +{ + return tests; +} + +#endif /* CONFIG_BT_PBP */ diff --git a/tests/bsim/bluetooth/audio/test_scripts/pbp.sh b/tests/bsim/bluetooth/audio/test_scripts/pbp.sh new file mode 100755 index 00000000000..2a028e9f70f --- /dev/null +++ b/tests/bsim/bluetooth/audio/test_scripts/pbp.sh @@ -0,0 +1,28 @@ +#!/usr/bin/env bash +# +# Copyright 2023 NXP +# +# SPDX-License-Identifier: Apache-2.0 + +VERBOSITY_LEVEL=2 +EXECUTE_TIMEOUT=20 + +source ${ZEPHYR_BASE}/tests/bsim/sh_common.source + +cd ${BSIM_OUT_PATH}/bin + +printf "\n\n======== Public Broadcaster test =========\n\n" + +SIMULATION_ID="pbp_broadcaster" + +Execute ./bs_${BOARD}_tests_bsim_bluetooth_audio_prj_conf \ + -v=${VERBOSITY_LEVEL} -s=${SIMULATION_ID} -d=0 -testid=public_broadcast_source -rs=27 -D=2 + +Execute ./bs_${BOARD}_tests_bsim_bluetooth_audio_prj_conf \ + -v=${VERBOSITY_LEVEL} -s=${SIMULATION_ID} -d=1 -testid=public_broadcast_sink -rs=27 -D=2 + +# Simulation time should be larger than the WAIT_TIME in common.h +Execute ./bs_2G4_phy_v1 -v=${VERBOSITY_LEVEL} -s=${SIMULATION_ID} \ + -D=2 -sim_length=70e6 $@ + +wait_for_background_jobs From 3099520921a10e36f7a4f22bd9067bef8c9f9ce2 Mon Sep 17 00:00:00 2001 From: Emil Gydesen Date: Mon, 11 Sep 2023 20:25:41 +0200 Subject: [PATCH 1901/3723] tests: bsim: Bluetooth: BAP Broadcast update to 2 bis Update the bsim test for the BAP broadcast to use 2 bis. This tests a larger part of the code, and also verifies that we can send and receive on 2 BIS without any ISO errors. This requires the ADV interval to be a multiple of ISO interval - 10ms, so the advertising interval has been set to 80ms. Signed-off-by: Emil Gydesen --- tests/bsim/bluetooth/audio/prj.conf | 9 +++++---- .../bsim/bluetooth/audio/src/bap_broadcast_source_test.c | 6 ++++-- 2 files changed, 9 insertions(+), 6 deletions(-) diff --git a/tests/bsim/bluetooth/audio/prj.conf b/tests/bsim/bluetooth/audio/prj.conf index 871034f2fcc..e3510c63b18 100644 --- a/tests/bsim/bluetooth/audio/prj.conf +++ b/tests/bsim/bluetooth/audio/prj.conf @@ -30,10 +30,10 @@ CONFIG_BT_BAP_BROADCAST_SOURCE=y CONFIG_BT_BAP_BROADCAST_SINK=y CONFIG_BT_AUDIO_CODEC_CFG_MAX_METADATA_SIZE=196 CONFIG_BT_AUDIO_CODEC_CAP_MAX_METADATA_SIZE=196 -CONFIG_BT_BAP_BROADCAST_SRC_STREAM_COUNT=1 +CONFIG_BT_BAP_BROADCAST_SRC_STREAM_COUNT=2 CONFIG_BT_BAP_BROADCAST_SRC_SUBGROUP_COUNT=1 CONFIG_BT_BAP_BROADCAST_SNK_SUBGROUP_COUNT=1 -CONFIG_BT_BAP_BROADCAST_SNK_STREAM_COUNT=1 +CONFIG_BT_BAP_BROADCAST_SNK_STREAM_COUNT=2 CONFIG_BT_ISO_TX_BUF_COUNT=4 CONFIG_BT_ISO_MAX_CHAN=4 CONFIG_BT_ISO_TX_MTU=310 @@ -203,8 +203,9 @@ CONFIG_BT_CTLR_ISO_TX_BUFFER_SIZE=251 CONFIG_BT_CTLR_ADV_DATA_LEN_MAX=191 # Controller ISO Broadcast Settings -CONFIG_BT_CTLR_ADV_ISO_STREAM_COUNT=1 -CONFIG_BT_CTLR_SYNC_ISO_STREAM_MAX=1 +CONFIG_BT_CTLR_ADV_ISO_STREAM_COUNT=2 +CONFIG_BT_CTLR_ADV_ISO_STREAM_MAX=2 +CONFIG_BT_CTLR_SYNC_ISO_STREAM_MAX=2 # Controller ISO Unicast Settings CONFIG_BT_CTLR_CENTRAL_ISO=y diff --git a/tests/bsim/bluetooth/audio/src/bap_broadcast_source_test.c b/tests/bsim/bluetooth/audio/src/bap_broadcast_source_test.c index 5410d76defa..1559f8c3010 100644 --- a/tests/bsim/bluetooth/audio/src/bap_broadcast_source_test.c +++ b/tests/bsim/bluetooth/audio/src/bap_broadcast_source_test.c @@ -121,7 +121,7 @@ static int setup_broadcast_source(struct bt_bap_broadcast_source **source) } for (size_t i = 0U; i < ARRAY_SIZE(subgroup_params); i++) { - subgroup_params[i].params_count = 1U; + subgroup_params[i].params_count = ARRAY_SIZE(stream_params); subgroup_params[i].params = &stream_params[i]; subgroup_params[i].codec_cfg = &preset_16_1_1.codec_cfg; } @@ -178,6 +178,8 @@ static int setup_extended_adv(struct bt_bap_broadcast_source *source, struct bt_ /* Broadcast Audio Streaming Endpoint advertising data */ NET_BUF_SIMPLE_DEFINE(ad_buf, BT_UUID_SIZE_16 + BT_AUDIO_BROADCAST_ID_SIZE); + struct bt_le_adv_param adv_param = BT_LE_ADV_PARAM_INIT( + BT_LE_ADV_OPT_EXT_ADV | BT_LE_ADV_OPT_USE_NAME, 0x80, 0x80, NULL); NET_BUF_SIMPLE_DEFINE(base_buf, 128); struct bt_data ext_ad; struct bt_data per_ad; @@ -185,7 +187,7 @@ static int setup_extended_adv(struct bt_bap_broadcast_source *source, struct bt_ int err; /* Create a non-connectable non-scannable advertising set */ - err = bt_le_ext_adv_create(BT_LE_EXT_ADV_NCONN_NAME, NULL, adv); + err = bt_le_ext_adv_create(&adv_param, NULL, adv); if (err != 0) { printk("Unable to create extended advertising set: %d\n", err); return err; From 7bde51bccfd9cf893a8866f8bdd15178f7df1925 Mon Sep 17 00:00:00 2001 From: Thomas Gagneret Date: Tue, 5 Dec 2023 17:41:06 +0100 Subject: [PATCH 1902/3723] scripts: zspdx: Include modules as packages in zephyr.spdx The current zephyr.spdx does not contain the modules included in the build. This commit split the zephyr-sources package into multiple packages, one for each modules found by zephyr_module.py. Signed-off-by: Thomas Gagneret --- CMakeLists.txt | 6 +- doc/develop/west/zephyr-cmds.rst | 2 + scripts/west_commands/zspdx/walker.py | 165 +++++++++++++++++--------- 3 files changed, 116 insertions(+), 57 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index be0dafe0fc1..e3e65cf26eb 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -1622,18 +1622,20 @@ if(CONFIG_BUILD_OUTPUT_BIN AND CONFIG_BUILD_OUTPUT_UF2) endif() if(CONFIG_BUILD_OUTPUT_META) + set(KERNEL_META_PATH ${PROJECT_BINARY_DIR}/${KERNEL_META_NAME} CACHE INTERNAL "") + list(APPEND post_build_commands COMMAND ${PYTHON_EXECUTABLE} ${ZEPHYR_BASE}/scripts/zephyr_module.py ${WEST_ARG} ${ZEPHYR_MODULES_ARG} ${EXTRA_ZEPHYR_MODULES_ARG} - --meta-out ${KERNEL_META_NAME} + --meta-out ${KERNEL_META_PATH} $<$:--meta-state-propagate> ) list(APPEND post_build_byproducts - ${KERNEL_META_NAME} + ${KERNEL_META_PATH} ) endif() diff --git a/doc/develop/west/zephyr-cmds.rst b/doc/develop/west/zephyr-cmds.rst index 056d22e48eb..f6b2322e6a4 100644 --- a/doc/develop/west/zephyr-cmds.rst +++ b/doc/develop/west/zephyr-cmds.rst @@ -89,6 +89,8 @@ To use this command: This step ensures the build directory contains CMake metadata required for SPDX document generation. +#. Enable :file:`CONFIG_BUILD_OUTPUT_META` in your project. + #. Build your application using this pre-created build directory, like so: .. code-block:: bash diff --git a/scripts/west_commands/zspdx/walker.py b/scripts/west_commands/zspdx/walker.py index c809ac40318..0c6469444ed 100644 --- a/scripts/west_commands/zspdx/walker.py +++ b/scripts/west_commands/zspdx/walker.py @@ -3,6 +3,7 @@ # SPDX-License-Identifier: Apache-2.0 import os +import yaml from west import log from west.util import west_topdir, WestNotFound @@ -74,6 +75,11 @@ def makeDocuments(self): log.inf("parsing CMake Cache file") self.getCacheFile() + # check if meta file is generated + if not self.metaFile: + log.err("CONFIG_BUILD_OUTPUT_META must be enabled to generate spdx files; bailing") + return False + # parse codemodel from Walker cfg's build dir log.inf("parsing CMake Codemodel files") self.cm = self.getCodemodel() @@ -108,6 +114,7 @@ def getCacheFile(self): if self.cmakeCache: self.compilerPath = self.cmakeCache.get("CMAKE_C_COMPILER", "") self.sdkPath = self.cmakeCache.get("ZEPHYR_SDK_INSTALL_DIR", "") + self.metaFile = self.cmakeCache.get("KERNEL_META_PATH", "") # determine path from build dir to CMake file-based API index file, then # parse it and return the Codemodel @@ -138,10 +145,35 @@ def getCodemodel(self): # parse it return parseReply(indexFilePath) - # set up Documents before beginning - def setupDocuments(self): - log.dbg("setting up placeholder documents") + def setupAppDocument(self): + # set up app document + cfgApp = DocumentConfig() + cfgApp.name = "app-sources" + cfgApp.namespace = self.cfg.namespacePrefix + "/app" + cfgApp.docRefID = "DocumentRef-app" + self.docApp = Document(cfgApp) + + # also set up app sources package + cfgPackageApp = PackageConfig() + cfgPackageApp.name = "app-sources" + cfgPackageApp.spdxID = "SPDXRef-app-sources" + # relativeBaseDir is app sources dir + cfgPackageApp.relativeBaseDir = self.cm.paths_source + pkgApp = Package(cfgPackageApp, self.docApp) + self.docApp.pkgs[pkgApp.cfg.spdxID] = pkgApp + # create DESCRIBES relationship data + rd = RelationshipData() + rd.ownerType = RelationshipDataElementType.DOCUMENT + rd.ownerDocument = self.docApp + rd.otherType = RelationshipDataElementType.PACKAGEID + rd.otherPackageID = cfgPackageApp.spdxID + rd.rlnType = "DESCRIBES" + + # add it to pending relationships queue + self.pendingRelationships.append(rd) + + def setupBuildDocument(self): # set up build document cfgBuild = DocumentConfig() cfgBuild.name = "build" @@ -163,6 +195,7 @@ def setupDocuments(self): # add it to pending relationships queue self.pendingRelationships.append(rd) + def setupZephyrDocument(self, modules): # set up zephyr document cfgZephyr = DocumentConfig() cfgZephyr.name = "zephyr-sources" @@ -170,19 +203,42 @@ def setupDocuments(self): cfgZephyr.docRefID = "DocumentRef-zephyr" self.docZephyr = Document(cfgZephyr) - # also set up zephyr sources package - cfgPackageZephyr = PackageConfig() - cfgPackageZephyr.name = "zephyr-sources" - cfgPackageZephyr.spdxID = "SPDXRef-zephyr-sources" # relativeBaseDir is Zephyr sources topdir try: - cfgPackageZephyr.relativeBaseDir = west_topdir(self.cm.paths_source) + relativeBaseDir = west_topdir(self.cm.paths_source) except WestNotFound: log.err(f"cannot find west_topdir for CMake Codemodel sources path {self.cm.paths_source}; bailing") return False + + # set up zephyr sources package + cfgPackageZephyr = PackageConfig() + cfgPackageZephyr.name = "zephyr-sources" + cfgPackageZephyr.spdxID = "SPDXRef-zephyr-sources" + cfgPackageZephyr.relativeBaseDir = relativeBaseDir + pkgZephyr = Package(cfgPackageZephyr, self.docZephyr) self.docZephyr.pkgs[pkgZephyr.cfg.spdxID] = pkgZephyr + for module in modules: + module_name = module.get("name", None) + module_path = module.get("path", None) + + if not module_name: + log.err(f"cannot find module name in meta file; bailing") + return False + + # Replace "_" by "-" since it's not allowed in spdx ID + module_name = module_name.replace("_", "-") + + # set up zephyr sources package + cfgPackageZephyrModule = PackageConfig() + cfgPackageZephyrModule.name = module_name + cfgPackageZephyrModule.spdxID = "SPDXRef-" + module_name + "-sources" + cfgPackageZephyrModule.relativeBaseDir = module_path + + pkgZephyrModule = Package(cfgPackageZephyrModule, self.docZephyr) + self.docZephyr.pkgs[pkgZephyrModule.cfg.spdxID] = pkgZephyrModule + # create DESCRIBES relationship data rd = RelationshipData() rd.ownerType = RelationshipDataElementType.DOCUMENT @@ -194,60 +250,52 @@ def setupDocuments(self): # add it to pending relationships queue self.pendingRelationships.append(rd) - # set up app document - cfgApp = DocumentConfig() - cfgApp.name = "app-sources" - cfgApp.namespace = self.cfg.namespacePrefix + "/app" - cfgApp.docRefID = "DocumentRef-app" - self.docApp = Document(cfgApp) - - # also set up app sources package - cfgPackageApp = PackageConfig() - cfgPackageApp.name = "app-sources" - cfgPackageApp.spdxID = "SPDXRef-app-sources" - # relativeBaseDir is app sources dir - cfgPackageApp.relativeBaseDir = self.cm.paths_source - pkgApp = Package(cfgPackageApp, self.docApp) - self.docApp.pkgs[pkgApp.cfg.spdxID] = pkgApp + def setupSDKDocument(self): + # set up SDK document + cfgSDK = DocumentConfig() + cfgSDK.name = "sdk" + cfgSDK.namespace = self.cfg.namespacePrefix + "/sdk" + cfgSDK.docRefID = "DocumentRef-sdk" + self.docSDK = Document(cfgSDK) + + # also set up zephyr sdk package + cfgPackageSDK = PackageConfig() + cfgPackageSDK.name = "sdk" + cfgPackageSDK.spdxID = "SPDXRef-sdk" + # relativeBaseDir is SDK dir + cfgPackageSDK.relativeBaseDir = self.sdkPath + pkgSDK = Package(cfgPackageSDK, self.docSDK) + self.docSDK.pkgs[pkgSDK.cfg.spdxID] = pkgSDK # create DESCRIBES relationship data rd = RelationshipData() rd.ownerType = RelationshipDataElementType.DOCUMENT - rd.ownerDocument = self.docApp + rd.ownerDocument = self.docSDK rd.otherType = RelationshipDataElementType.PACKAGEID - rd.otherPackageID = cfgPackageApp.spdxID + rd.otherPackageID = cfgPackageSDK.spdxID rd.rlnType = "DESCRIBES" # add it to pending relationships queue self.pendingRelationships.append(rd) - if self.cfg.includeSDK: - # set up SDK document - cfgSDK = DocumentConfig() - cfgSDK.name = "sdk" - cfgSDK.namespace = self.cfg.namespacePrefix + "/sdk" - cfgSDK.docRefID = "DocumentRef-sdk" - self.docSDK = Document(cfgSDK) - - # also set up zephyr sdk package - cfgPackageSDK = PackageConfig() - cfgPackageSDK.name = "sdk" - cfgPackageSDK.spdxID = "SPDXRef-sdk" - # relativeBaseDir is SDK dir - cfgPackageSDK.relativeBaseDir = self.sdkPath - pkgSDK = Package(cfgPackageSDK, self.docSDK) - self.docSDK.pkgs[pkgSDK.cfg.spdxID] = pkgSDK - - # create DESCRIBES relationship data - rd = RelationshipData() - rd.ownerType = RelationshipDataElementType.DOCUMENT - rd.ownerDocument = self.docSDK - rd.otherType = RelationshipDataElementType.PACKAGEID - rd.otherPackageID = cfgPackageSDK.spdxID - rd.rlnType = "DESCRIBES" + # set up Documents before beginning + def setupDocuments(self): + log.dbg("setting up placeholder documents") - # add it to pending relationships queue - self.pendingRelationships.append(rd) + self.setupBuildDocument() + + try: + with open(self.metaFile) as file: + content = yaml.load(file.read(), yaml.SafeLoader) + self.setupZephyrDocument(content["modules"]) + except (FileNotFoundError, yaml.YAMLError): + log.err(f"cannot find a valid zephyr_meta.yml required for SPDX generation; bailing") + return False + + self.setupAppDocument() + + if self.cfg.includeSDK: + self.setupSDKDocument() return True @@ -497,6 +545,7 @@ def walkPendingSources(self): # not yet assigned; figure out where it goes pkgBuild = self.findBuildPackage(srcAbspath) + pkgZephyr = self.findZephyrPackage(srcAbspath) if pkgBuild: log.dbg(f" - {srcAbspath}: assigning to build document, package {pkgBuild.cfg.name}") @@ -510,7 +559,7 @@ def walkPendingSources(self): log.dbg(f" - {srcAbspath}: assigning to app document") srcDoc = self.docApp srcPkg = pkgApp - elif os.path.commonpath([srcAbspath, pkgZephyr.cfg.relativeBaseDir]) == pkgZephyr.cfg.relativeBaseDir: + elif pkgZephyr: log.dbg(f" - {srcAbspath}: assigning to zephyr document") srcDoc = self.docZephyr srcPkg = pkgZephyr @@ -533,16 +582,16 @@ def walkPendingSources(self): srcDoc.fileLinks[sf.abspath] = sf self.allFileLinks[sf.abspath] = srcDoc - # figure out which build Package contains the given file, if any + # figure out which Package contains the given file, if any # call with: # 1) absolute path for source filename being searched - def findBuildPackage(self, srcAbspath): + def findPackageFromSrcAbsPath(self, document, srcAbspath): # Multiple target Packages might "contain" the file path, if they # are nested. If so, the one with the longest path would be the # most deeply-nested target directory, so that's the one which # should get the file path. pkgLongestMatch = None - for pkg in self.docBuild.pkgs.values(): + for pkg in document.pkgs.values(): if os.path.commonpath([srcAbspath, pkg.cfg.relativeBaseDir]) == pkg.cfg.relativeBaseDir: # the package does contain this file; is it the deepest? if pkgLongestMatch: @@ -554,6 +603,12 @@ def findBuildPackage(self, srcAbspath): return pkgLongestMatch + def findBuildPackage(self, srcAbspath): + return self.findPackageFromSrcAbsPath(self.docBuild, srcAbspath) + + def findZephyrPackage(self, srcAbspath): + return self.findPackageFromSrcAbsPath(self.docZephyr, srcAbspath) + # walk through pending RelationshipData entries, create corresponding # Relationships, and assign them to the applicable Files / Packages def walkRelationships(self): From 37f427a5c728855767bd77291f58f078ad4d0a4b Mon Sep 17 00:00:00 2001 From: Anas Nashif Date: Wed, 13 Dec 2023 12:53:49 -0500 Subject: [PATCH 1903/3723] arch: introduce arch_smp_init Introduce a new arch interface for intializing smp. Signed-off-by: Anas Nashif --- arch/arc/core/arc_smp.c | 5 ++--- arch/arm/core/cortex_a_r/smp.c | 4 ++-- arch/arm64/core/prep_c.c | 1 + arch/arm64/core/smp.c | 4 ++-- arch/riscv/core/smp.c | 5 ++--- arch/x86/core/intel64/irq.c | 6 +++++- arch/x86/core/prep_c.c | 2 +- include/zephyr/sys/arch_interface.h | 3 +++ 8 files changed, 18 insertions(+), 12 deletions(-) diff --git a/arch/arc/core/arc_smp.c b/arch/arc/core/arc_smp.c index 9fb43c41152..1aa61be53f0 100644 --- a/arch/arc/core/arc_smp.c +++ b/arch/arc/core/arc_smp.c @@ -145,7 +145,7 @@ void arch_sched_ipi(void) } } -static int arc_smp_init(void) +int arch_smp_init(void) { struct arc_connect_bcr bcr; @@ -188,6 +188,5 @@ static int arc_smp_init(void) return 0; } - -SYS_INIT(arc_smp_init, PRE_KERNEL_1, CONFIG_KERNEL_INIT_PRIORITY_DEFAULT); +SYS_INIT(arch_smp_init, PRE_KERNEL_1, CONFIG_KERNEL_INIT_PRIORITY_DEFAULT); #endif diff --git a/arch/arm/core/cortex_a_r/smp.c b/arch/arm/core/cortex_a_r/smp.c index 2aeb36c1735..c17f2fa048f 100644 --- a/arch/arm/core/cortex_a_r/smp.c +++ b/arch/arm/core/cortex_a_r/smp.c @@ -245,7 +245,7 @@ void arch_sched_ipi(void) broadcast_ipi(SGI_SCHED_IPI); } -static int arm_smp_init(void) +int arch_smp_init(void) { cpu_map[0] = MPIDR_TO_CORE(GET_MPIDR()); @@ -259,6 +259,6 @@ static int arm_smp_init(void) return 0; } -SYS_INIT(arm_smp_init, PRE_KERNEL_2, CONFIG_KERNEL_INIT_PRIORITY_DEFAULT); +SYS_INIT(arch_smp_init, PRE_KERNEL_2, CONFIG_KERNEL_INIT_PRIORITY_DEFAULT); #endif diff --git a/arch/arm64/core/prep_c.c b/arch/arm64/core/prep_c.c index 8ec380296aa..e8a7ba95f09 100644 --- a/arch/arm64/core/prep_c.c +++ b/arch/arm64/core/prep_c.c @@ -69,6 +69,7 @@ void z_prep_c(void) CODE_UNREACHABLE; } + #if CONFIG_MP_MAX_NUM_CPUS > 1 extern FUNC_NORETURN void z_arm64_secondary_start(void); void z_arm64_secondary_prep_c(void) diff --git a/arch/arm64/core/smp.c b/arch/arm64/core/smp.c index e67032eb2a4..043e07eb305 100644 --- a/arch/arm64/core/smp.c +++ b/arch/arm64/core/smp.c @@ -279,7 +279,7 @@ void arch_spin_relax(void) } #endif -static int arm64_smp_init(void) +int arch_smp_init(void) { cpu_map[0] = MPIDR_TO_CORE(GET_MPIDR()); @@ -302,6 +302,6 @@ static int arm64_smp_init(void) return 0; } -SYS_INIT(arm64_smp_init, PRE_KERNEL_2, CONFIG_KERNEL_INIT_PRIORITY_DEFAULT); +SYS_INIT(arch_smp_init, PRE_KERNEL_2, CONFIG_KERNEL_INIT_PRIORITY_DEFAULT); #endif diff --git a/arch/riscv/core/smp.c b/arch/riscv/core/smp.c index 6154450e58d..3294f9006f3 100644 --- a/arch/riscv/core/smp.c +++ b/arch/riscv/core/smp.c @@ -151,7 +151,7 @@ void arch_spin_relax(void) } #endif -static int riscv_smp_init(void) +int arch_smp_init(void) { IRQ_CONNECT(RISCV_MACHINE_SOFT_IRQ, 0, ipi_handler, NULL, 0); @@ -159,6 +159,5 @@ static int riscv_smp_init(void) return 0; } - -SYS_INIT(riscv_smp_init, PRE_KERNEL_2, CONFIG_KERNEL_INIT_PRIORITY_DEFAULT); +SYS_INIT(arch_smp_init, PRE_KERNEL_2, CONFIG_KERNEL_INIT_PRIORITY_DEFAULT); #endif /* CONFIG_SMP */ diff --git a/arch/x86/core/intel64/irq.c b/arch/x86/core/intel64/irq.c index a7304271746..09b1961585c 100644 --- a/arch/x86/core/intel64/irq.c +++ b/arch/x86/core/intel64/irq.c @@ -14,6 +14,7 @@ #include #include #include +#include LOG_MODULE_DECLARE(os, CONFIG_KERNEL_LOG_LEVEL); @@ -154,7 +155,7 @@ void arch_irq_offload(irq_offload_routine_t routine, const void *parameter) #if defined(CONFIG_SMP) -void z_x86_ipi_setup(void) +int arch_smp_init(void) { /* * z_sched_ipi() doesn't have the same signature as a typical ISR, so @@ -166,8 +167,11 @@ void z_x86_ipi_setup(void) /* TLB shootdown handling */ x86_irq_funcs[CONFIG_TLB_IPI_VECTOR - IV_IRQS] = z_x86_tlb_ipi; + return 0; } +SYS_INIT(arch_smp_init, PRE_KERNEL_1, CONFIG_KERNEL_INIT_PRIORITY_DEFAULT); + /* * it is not clear exactly how/where/why to abstract this, as it * assumes the use of a local APIC (but there's no other mechanism). diff --git a/arch/x86/core/prep_c.c b/arch/x86/core/prep_c.c index d067e067641..17a4a7f7473 100644 --- a/arch/x86/core/prep_c.c +++ b/arch/x86/core/prep_c.c @@ -74,7 +74,7 @@ FUNC_NORETURN void z_prep_c(void *arg) #endif #if defined(CONFIG_SMP) - z_x86_ipi_setup(); + arch_smp_init(); #endif z_cstart(); diff --git a/include/zephyr/sys/arch_interface.h b/include/zephyr/sys/arch_interface.h index d044f578fae..dd5755c1e23 100644 --- a/include/zephyr/sys/arch_interface.h +++ b/include/zephyr/sys/arch_interface.h @@ -495,6 +495,9 @@ static inline uint32_t arch_proc_id(void); */ void arch_sched_ipi(void); + +int arch_smp_init(void); + #endif /* CONFIG_SMP */ /** From 17080d0215c906082f6b669d0f762241c50739eb Mon Sep 17 00:00:00 2001 From: Anas Nashif Date: Wed, 13 Dec 2023 13:23:56 -0500 Subject: [PATCH 1904/3723] arch: ipi_handler -> sched_ipi_handler unifiy naming for ipi handler call and use the same signature everywhere. Signed-off-by: Anas Nashif --- arch/riscv/core/smp.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/arch/riscv/core/smp.c b/arch/riscv/core/smp.c index 3294f9006f3..4e9cdb55f48 100644 --- a/arch/riscv/core/smp.c +++ b/arch/riscv/core/smp.c @@ -104,7 +104,7 @@ void z_riscv_flush_fpu_ipi(unsigned int cpu) } #endif -static void ipi_handler(const void *unused) +static void sched_ipi_handler(const void *unused) { ARG_UNUSED(unused); @@ -154,7 +154,7 @@ void arch_spin_relax(void) int arch_smp_init(void) { - IRQ_CONNECT(RISCV_MACHINE_SOFT_IRQ, 0, ipi_handler, NULL, 0); + IRQ_CONNECT(RISCV_MACHINE_SOFT_IRQ, 0, sched_ipi_handler, NULL, 0); irq_enable(RISCV_MACHINE_SOFT_IRQ); return 0; From 2f3b7fa9bf02afc76818fdcb53911bb878b4a87b Mon Sep 17 00:00:00 2001 From: Anas Nashif Date: Wed, 13 Dec 2023 14:25:18 -0500 Subject: [PATCH 1905/3723] arch: arc rename arc_smp.c -> smp.c We know this is SMP for arc, no need for the arc_ prefix. Signed-off-by: Anas Nashif --- arch/arc/core/CMakeLists.txt | 2 +- arch/arc/core/{arc_smp.c => smp.c} | 0 2 files changed, 1 insertion(+), 1 deletion(-) rename arch/arc/core/{arc_smp.c => smp.c} (100%) diff --git a/arch/arc/core/CMakeLists.txt b/arch/arc/core/CMakeLists.txt index 3325e27ff88..00c9f775038 100644 --- a/arch/arc/core/CMakeLists.txt +++ b/arch/arc/core/CMakeLists.txt @@ -26,7 +26,7 @@ zephyr_library_sources_ifdef(CONFIG_IRQ_OFFLOAD irq_offload.c) zephyr_library_sources_ifdef(CONFIG_USERSPACE userspace.S) zephyr_library_sources_ifdef(CONFIG_ARC_CONNECT arc_connect.c) -zephyr_library_sources_ifdef(CONFIG_ARC_CONNECT arc_smp.c) +zephyr_library_sources_ifdef(CONFIG_ARC_CONNECT smp.c) zephyr_library_sources_ifdef(CONFIG_THREAD_LOCAL_STORAGE tls.c) diff --git a/arch/arc/core/arc_smp.c b/arch/arc/core/smp.c similarity index 100% rename from arch/arc/core/arc_smp.c rename to arch/arc/core/smp.c From 3f753735845d313db2e0dc564606a97c0412361b Mon Sep 17 00:00:00 2001 From: Anas Nashif Date: Wed, 13 Dec 2023 15:27:41 -0500 Subject: [PATCH 1906/3723] arch: introduce arch_secondary_cpu_init Different architecture are doing this in custom ways and using different naming conventions, unify this interface and make it part of the arch implementation for SMP. Signed-off-by: Anas Nashif --- arch/arc/core/reset.S | 2 +- arch/arc/core/smp.c | 2 +- arch/arm/core/cortex_a_r/reset.S | 2 +- arch/arm/core/cortex_a_r/smp.c | 4 ++-- arch/arm64/core/prep_c.c | 4 ++-- arch/arm64/core/smp.c | 6 +++--- arch/riscv/core/reset.S | 4 ++-- arch/riscv/core/smp.c | 2 +- 8 files changed, 13 insertions(+), 13 deletions(-) diff --git a/arch/arc/core/reset.S b/arch/arc/core/reset.S index 82ea4c4d435..0894875dcac 100644 --- a/arch/arc/core/reset.S +++ b/arch/arc/core/reset.S @@ -174,7 +174,7 @@ _slave_core_wait: jl z_arc_firq_stack_set pop r0 #endif - j z_arc_slave_start + j arch_secondary_cpu_init _master_core_startup: #endif diff --git a/arch/arc/core/smp.c b/arch/arc/core/smp.c index 1aa61be53f0..6bc89883fad 100644 --- a/arch/arc/core/smp.c +++ b/arch/arc/core/smp.c @@ -89,7 +89,7 @@ static void arc_connect_debug_mask_update(int cpu_num) void arc_core_private_intc_init(void); /* the C entry of slave cores */ -void z_arc_slave_start(int cpu_num) +void arch_secondary_cpu_init(int cpu_num) { arch_cpustart_t fn; diff --git a/arch/arm/core/cortex_a_r/reset.S b/arch/arm/core/cortex_a_r/reset.S index 362f4aa214f..0b107fbf596 100644 --- a/arch/arm/core/cortex_a_r/reset.S +++ b/arch/arm/core/cortex_a_r/reset.S @@ -217,7 +217,7 @@ EL1_Reset_Handler: bne 1b /* we can now move on */ - ldr r4, =z_arm_secondary_start + ldr r4, =arch_secondary_cpu_init ldr r5, [r0, #BOOT_PARAM_FIQ_SP_OFFSET] ldr r6, [r0, #BOOT_PARAM_IRQ_SP_OFFSET] ldr r7, [r0, #BOOT_PARAM_ABT_SP_OFFSET] diff --git a/arch/arm/core/cortex_a_r/smp.c b/arch/arm/core/cortex_a_r/smp.c index c17f2fa048f..f581c770310 100644 --- a/arch/arm/core/cortex_a_r/smp.c +++ b/arch/arm/core/cortex_a_r/smp.c @@ -148,7 +148,7 @@ void arch_start_cpu(int cpu_num, k_thread_stack_t *stack, int sz, arch_cpustart_ * \todo Support PSCI */ - /* Wait secondary cores up, see z_arm64_secondary_start */ + /* Wait secondary cores up, see arch_secondary_cpu_init */ while (arm_cpu_boot_params.fn) { wfe(); } @@ -159,7 +159,7 @@ void arch_start_cpu(int cpu_num, k_thread_stack_t *stack, int sz, arch_cpustart_ } /* the C entry of secondary cores */ -void z_arm_secondary_start(void) +void arch_secondary_cpu_init(void) { int cpu_num = arm_cpu_boot_params.cpu_num; arch_cpustart_t fn; diff --git a/arch/arm64/core/prep_c.c b/arch/arm64/core/prep_c.c index e8a7ba95f09..bfd3b7c1eaa 100644 --- a/arch/arm64/core/prep_c.c +++ b/arch/arm64/core/prep_c.c @@ -71,10 +71,10 @@ void z_prep_c(void) #if CONFIG_MP_MAX_NUM_CPUS > 1 -extern FUNC_NORETURN void z_arm64_secondary_start(void); +extern FUNC_NORETURN void arch_secondary_cpu_init(void); void z_arm64_secondary_prep_c(void) { - z_arm64_secondary_start(); + arch_secondary_cpu_init(); CODE_UNREACHABLE; } diff --git a/arch/arm64/core/smp.c b/arch/arm64/core/smp.c index 043e07eb305..d7accdcd713 100644 --- a/arch/arm64/core/smp.c +++ b/arch/arm64/core/smp.c @@ -122,7 +122,7 @@ void arch_start_cpu(int cpu_num, k_thread_stack_t *stack, int sz, k_panic(); } - /* Wait secondary cores up, see z_arm64_secondary_start */ + /* Wait secondary cores up, see arch_secondary_cpu_init */ while (arm64_cpu_boot_params.fn) { wfe(); } @@ -133,9 +133,9 @@ void arch_start_cpu(int cpu_num, k_thread_stack_t *stack, int sz, } /* the C entry of secondary cores */ -void z_arm64_secondary_start(void) +void arch_secondary_cpu_init(int cpu_num) { - int cpu_num = arm64_cpu_boot_params.cpu_num; + cpu_num = arm64_cpu_boot_params.cpu_num; arch_cpustart_t fn; void *arg; diff --git a/arch/riscv/core/reset.S b/arch/riscv/core/reset.S index 73e2bf923a2..e9424e7a8e2 100644 --- a/arch/riscv/core/reset.S +++ b/arch/riscv/core/reset.S @@ -19,7 +19,7 @@ GTEXT(__reset) GTEXT(z_prep_c) GTEXT(riscv_cpu_wake_flag) GTEXT(riscv_cpu_sp) -GTEXT(z_riscv_secondary_cpu_init) +GTEXT(arch_secondary_cpu_init) #if CONFIG_INCLUDE_RESET_VECTOR SECTION_FUNC(reset, __reset) @@ -111,7 +111,7 @@ wait_secondary_wake_flag: la t0, riscv_cpu_boot_flag li t1, 1 sr t1, 0(t0) - j z_riscv_secondary_cpu_init + j arch_secondary_cpu_init #else j loop_unconfigured_cores #endif diff --git a/arch/riscv/core/smp.c b/arch/riscv/core/smp.c index 4e9cdb55f48..2c091165e5f 100644 --- a/arch/riscv/core/smp.c +++ b/arch/riscv/core/smp.c @@ -43,7 +43,7 @@ void arch_start_cpu(int cpu_num, k_thread_stack_t *stack, int sz, } } -void z_riscv_secondary_cpu_init(int hartid) +void arch_secondary_cpu_init(int hartid) { unsigned int i; unsigned int cpu_num = 0; From 7d3b6c6a40959464b6703991ebf984abc7b1de6e Mon Sep 17 00:00:00 2001 From: Anas Nashif Date: Wed, 13 Dec 2023 16:04:15 -0500 Subject: [PATCH 1907/3723] arch: smp: make flush_fpu_ipi a common, optional interfaces The interface to flush fpu is not unique to one architecture, make it a generic, optional interface that can be implemented (and overriden) by a platform. Signed-off-by: Anas Nashif --- arch/arm64/core/fatal.c | 2 +- arch/arm64/core/fpu.c | 10 +++++----- arch/arm64/core/smp.c | 6 +++--- arch/arm64/include/kernel_arch_func.h | 4 ++-- arch/riscv/core/fpu.c | 14 +++++++------- arch/riscv/core/smp.c | 6 +++--- arch/riscv/include/kernel_arch_func.h | 4 ++-- 7 files changed, 23 insertions(+), 23 deletions(-) diff --git a/arch/arm64/core/fatal.c b/arch/arm64/core/fatal.c index 1139a818e1f..dbf0c4cdae1 100644 --- a/arch/arm64/core/fatal.c +++ b/arch/arm64/core/fatal.c @@ -250,7 +250,7 @@ static bool z_arm64_stack_corruption_check(z_arch_esf_t *esf, uint64_t esr, uint * so flush the fpu context to its owner, and then set no fpu trap to avoid * a new nested exception triggered by FPU accessing (var_args). */ - z_arm64_flush_local_fpu(); + arch_flush_local_fpu(); write_cpacr_el1(read_cpacr_el1() | CPACR_EL1_FPEN_NOTRAP); #endif arch_curr_cpu()->arch.corrupted_sp = 0UL; diff --git a/arch/arm64/core/fpu.c b/arch/arm64/core/fpu.c index 74a32b8009c..0133eed2dca 100644 --- a/arch/arm64/core/fpu.c +++ b/arch/arm64/core/fpu.c @@ -64,7 +64,7 @@ static inline void DBG(char *msg, struct k_thread *t) { } * Flush FPU content and disable access. * This is called locally and also from flush_fpu_ipi_handler(). */ -void z_arm64_flush_local_fpu(void) +void arch_flush_local_fpu(void) { __ASSERT(read_daif() & DAIF_IRQ_BIT, "must be called with IRQs disabled"); @@ -107,10 +107,10 @@ static void flush_owned_fpu(struct k_thread *thread) } /* we found it live on CPU i */ if (i == _current_cpu->id) { - z_arm64_flush_local_fpu(); + arch_flush_local_fpu(); } else { /* the FPU context is live on another CPU */ - z_arm64_flush_fpu_ipi(i); + arch_flush_fpu_ipi(i); /* * Wait for it only if this is about the thread @@ -126,7 +126,7 @@ static void flush_owned_fpu(struct k_thread *thread) * two CPUs want to pull each other's FPU context. */ if (thread == _current) { - z_arm64_flush_local_fpu(); + arch_flush_local_fpu(); while (atomic_ptr_get(&_kernel.cpus[i].arch.fpu_owner) == thread) { barrier_dsync_fence_full(); } @@ -334,7 +334,7 @@ int arch_float_disable(struct k_thread *thread) flush_owned_fpu(thread); #else if (thread == atomic_ptr_get(&_current_cpu->arch.fpu_owner)) { - z_arm64_flush_local_fpu(); + arch_flush_local_fpu(); } #endif diff --git a/arch/arm64/core/smp.c b/arch/arm64/core/smp.c index d7accdcd713..20faef06108 100644 --- a/arch/arm64/core/smp.c +++ b/arch/arm64/core/smp.c @@ -242,11 +242,11 @@ void flush_fpu_ipi_handler(const void *unused) ARG_UNUSED(unused); disable_irq(); - z_arm64_flush_local_fpu(); + arch_flush_local_fpu(); /* no need to re-enable IRQs here */ } -void z_arm64_flush_fpu_ipi(unsigned int cpu) +void arch_flush_fpu_ipi(unsigned int cpu) { const uint64_t mpidr = cpu_map[cpu]; uint8_t aff0; @@ -272,7 +272,7 @@ void arch_spin_relax(void) arm_gic_irq_clear_pending(SGI_FPU_IPI); /* * We may not be in IRQ context here hence cannot use - * z_arm64_flush_local_fpu() directly. + * arch_flush_local_fpu() directly. */ arch_float_disable(_current_cpu->arch.fpu_owner); } diff --git a/arch/arm64/include/kernel_arch_func.h b/arch/arm64/include/kernel_arch_func.h index 3b028b10b37..a5c3d59d87a 100644 --- a/arch/arm64/include/kernel_arch_func.h +++ b/arch/arm64/include/kernel_arch_func.h @@ -48,8 +48,8 @@ extern void z_arm64_set_ttbr0(uint64_t ttbr0); extern void z_arm64_mem_cfg_ipi(void); #ifdef CONFIG_FPU_SHARING -void z_arm64_flush_local_fpu(void); -void z_arm64_flush_fpu_ipi(unsigned int cpu); +void arch_flush_local_fpu(void); +void arch_flush_fpu_ipi(unsigned int cpu); #endif #ifdef CONFIG_ARM64_SAFE_EXCEPTION_STACK diff --git a/arch/riscv/core/fpu.c b/arch/riscv/core/fpu.c index 293a5bc613f..da5d07b3146 100644 --- a/arch/riscv/core/fpu.c +++ b/arch/riscv/core/fpu.c @@ -98,7 +98,7 @@ static void z_riscv_fpu_load(void) * * This is called locally and also from flush_fpu_ipi_handler(). */ -void z_riscv_flush_local_fpu(void) +void arch_flush_local_fpu(void) { __ASSERT((csr_read(mstatus) & MSTATUS_IEN) == 0, "must be called with IRQs disabled"); @@ -149,11 +149,11 @@ static void flush_owned_fpu(struct k_thread *thread) /* we found it live on CPU i */ if (i == _current_cpu->id) { z_riscv_fpu_disable(); - z_riscv_flush_local_fpu(); + arch_flush_local_fpu(); break; } /* the FPU context is live on another CPU */ - z_riscv_flush_fpu_ipi(i); + arch_flush_fpu_ipi(i); /* * Wait for it only if this is about the thread @@ -170,7 +170,7 @@ static void flush_owned_fpu(struct k_thread *thread) */ if (thread == _current) { z_riscv_fpu_disable(); - z_riscv_flush_local_fpu(); + arch_flush_local_fpu(); do { arch_nop(); owner = atomic_ptr_get(&_kernel.cpus[i].arch.fpu_owner); @@ -211,7 +211,7 @@ void z_riscv_fpu_trap(z_arch_esf_t *esf) "called despite FPU being accessible"); /* save current owner's content if any */ - z_riscv_flush_local_fpu(); + arch_flush_local_fpu(); if (_current->arch.exception_depth > 0) { /* @@ -271,7 +271,7 @@ static bool fpu_access_allowed(unsigned int exc_update_level) * to come otherwise. */ z_riscv_fpu_disable(); - z_riscv_flush_local_fpu(); + arch_flush_local_fpu(); #ifdef CONFIG_SMP flush_owned_fpu(_current); #endif @@ -329,7 +329,7 @@ int arch_float_disable(struct k_thread *thread) #else if (thread == _current_cpu->arch.fpu_owner) { z_riscv_fpu_disable(); - z_riscv_flush_local_fpu(); + arch_flush_local_fpu(); } #endif diff --git a/arch/riscv/core/smp.c b/arch/riscv/core/smp.c index 2c091165e5f..b49fcf8aa4f 100644 --- a/arch/riscv/core/smp.c +++ b/arch/riscv/core/smp.c @@ -97,7 +97,7 @@ void arch_sched_ipi(void) } #ifdef CONFIG_FPU_SHARING -void z_riscv_flush_fpu_ipi(unsigned int cpu) +void arch_flush_fpu_ipi(unsigned int cpu) { atomic_set_bit(&cpu_pending_ipi[cpu], IPI_FPU_FLUSH); MSIP(_kernel.cpus[cpu].arch.hartid) = 1; @@ -120,7 +120,7 @@ static void sched_ipi_handler(const void *unused) /* disable IRQs */ csr_clear(mstatus, MSTATUS_IEN); /* perform the flush */ - z_riscv_flush_local_fpu(); + arch_flush_local_fpu(); /* * No need to re-enable IRQs here as long as * this remains the last case. @@ -144,7 +144,7 @@ void arch_spin_relax(void) if (atomic_test_and_clear_bit(pending_ipi, IPI_FPU_FLUSH)) { /* * We may not be in IRQ context here hence cannot use - * z_riscv_flush_local_fpu() directly. + * arch_flush_local_fpu() directly. */ arch_float_disable(_current_cpu->arch.fpu_owner); } diff --git a/arch/riscv/include/kernel_arch_func.h b/arch/riscv/include/kernel_arch_func.h index fdd39eb8a68..b639f09c6c6 100644 --- a/arch/riscv/include/kernel_arch_func.h +++ b/arch/riscv/include/kernel_arch_func.h @@ -95,8 +95,8 @@ int z_irq_do_offload(void); #endif #ifdef CONFIG_FPU_SHARING -void z_riscv_flush_local_fpu(void); -void z_riscv_flush_fpu_ipi(unsigned int cpu); +void arch_flush_local_fpu(void); +void arch_flush_fpu_ipi(unsigned int cpu); #endif #ifndef CONFIG_MULTITHREADING From dac942a2451fadf786a5081273afb858fd9b1fa7 Mon Sep 17 00:00:00 2001 From: Anas Nashif Date: Wed, 13 Dec 2023 17:51:31 -0500 Subject: [PATCH 1908/3723] arch: x86_64: split irq.c into multiple files We had too much going in irq.c, split code into multiple files similar to how we do everywher else. Signed-off-by: Anas Nashif --- arch/x86/core/intel64.cmake | 3 +- arch/x86/core/intel64/irq.c | 52 +---------------------------- arch/x86/core/intel64/irq_offload.c | 28 ++++++++++++++++ arch/x86/core/intel64/smp.c | 42 +++++++++++++++++++++++ 4 files changed, 73 insertions(+), 52 deletions(-) create mode 100644 arch/x86/core/intel64/irq_offload.c create mode 100644 arch/x86/core/intel64/smp.c diff --git a/arch/x86/core/intel64.cmake b/arch/x86/core/intel64.cmake index cd37d5c497e..1cb25ebe220 100644 --- a/arch/x86/core/intel64.cmake +++ b/arch/x86/core/intel64.cmake @@ -15,7 +15,8 @@ zephyr_library_sources( intel64/thread.c intel64/fatal.c ) - +zephyr_library_sources_ifdef(CONFIG_SMP intel64/smp.c) +zephyr_library_sources_ifdef(CONFIG_IRQ_OFFLOAD intel64/irq_offload.c) zephyr_library_sources_ifdef(CONFIG_USERSPACE intel64/userspace.S) zephyr_library_sources_ifdef(CONFIG_THREAD_LOCAL_STORAGE intel64/tls.c) zephyr_library_sources_ifdef(CONFIG_DEBUG_COREDUMP intel64/coredump.c) diff --git a/arch/x86/core/intel64/irq.c b/arch/x86/core/intel64/irq.c index 09b1961585c..f8e251b8046 100644 --- a/arch/x86/core/intel64/irq.c +++ b/arch/x86/core/intel64/irq.c @@ -13,19 +13,11 @@ #include #include #include -#include -#include + LOG_MODULE_DECLARE(os, CONFIG_KERNEL_LOG_LEVEL); unsigned char _irq_to_interrupt_vector[CONFIG_MAX_IRQ_LINES]; - -/* - * The low-level interrupt code consults these arrays to dispatch IRQs, so - * so be sure to keep locore.S up to date with any changes. Note the indices: - * use (vector - IV_IRQS), since exception vectors do not appear here. - */ - #define NR_IRQ_VECTORS (IV_NR_VECTORS - IV_IRQS) /* # vectors free for IRQs */ void (*x86_irq_funcs[NR_IRQ_VECTORS])(const void *arg); @@ -139,48 +131,6 @@ int arch_irq_connect_dynamic(unsigned int irq, unsigned int priority, return vector; } -#ifdef CONFIG_IRQ_OFFLOAD -#include - -void arch_irq_offload(irq_offload_routine_t routine, const void *parameter) -{ - x86_irq_funcs[CONFIG_IRQ_OFFLOAD_VECTOR - IV_IRQS] = routine; - x86_irq_args[CONFIG_IRQ_OFFLOAD_VECTOR - IV_IRQS] = parameter; - __asm__ volatile("int %0" : : "i" (CONFIG_IRQ_OFFLOAD_VECTOR) - : "memory"); - x86_irq_funcs[CONFIG_IRQ_OFFLOAD_VECTOR - IV_IRQS] = NULL; -} - -#endif /* CONFIG_IRQ_OFFLOAD */ - -#if defined(CONFIG_SMP) - -int arch_smp_init(void) -{ - /* - * z_sched_ipi() doesn't have the same signature as a typical ISR, so - * we fudge it with a cast. the argument is ignored, no harm done. - */ - - x86_irq_funcs[CONFIG_SCHED_IPI_VECTOR - IV_IRQS] = - (void *) z_sched_ipi; - - /* TLB shootdown handling */ - x86_irq_funcs[CONFIG_TLB_IPI_VECTOR - IV_IRQS] = z_x86_tlb_ipi; - return 0; -} - -SYS_INIT(arch_smp_init, PRE_KERNEL_1, CONFIG_KERNEL_INIT_PRIORITY_DEFAULT); - -/* - * it is not clear exactly how/where/why to abstract this, as it - * assumes the use of a local APIC (but there's no other mechanism). - */ -void arch_sched_ipi(void) -{ - z_loapic_ipi(0, LOAPIC_ICR_IPI_OTHERS, CONFIG_SCHED_IPI_VECTOR); -} -#endif /* The first bit is used to indicate whether the list of reserved interrupts * have been initialized based on content stored in the irq_alloc linker diff --git a/arch/x86/core/intel64/irq_offload.c b/arch/x86/core/intel64/irq_offload.c new file mode 100644 index 00000000000..0146321f7d9 --- /dev/null +++ b/arch/x86/core/intel64/irq_offload.c @@ -0,0 +1,28 @@ +/* + * Copyright (c) 2023 Intel corporation + * + * SPDX-License-Identifier: Apache-2.0 + */ + +/** + * @file IRQ offload - x8664 implementation + */ + +#include +#include +#include + +#define NR_IRQ_VECTORS (IV_NR_VECTORS - IV_IRQS) /* # vectors free for IRQs */ + +extern void (*x86_irq_funcs[NR_IRQ_VECTORS])(const void *arg); +extern const void *x86_irq_args[NR_IRQ_VECTORS]; + + +void arch_irq_offload(irq_offload_routine_t routine, const void *parameter) +{ + x86_irq_funcs[CONFIG_IRQ_OFFLOAD_VECTOR - IV_IRQS] = routine; + x86_irq_args[CONFIG_IRQ_OFFLOAD_VECTOR - IV_IRQS] = parameter; + __asm__ volatile("int %0" : : "i" (CONFIG_IRQ_OFFLOAD_VECTOR) + : "memory"); + x86_irq_funcs[CONFIG_IRQ_OFFLOAD_VECTOR - IV_IRQS] = NULL; +} diff --git a/arch/x86/core/intel64/smp.c b/arch/x86/core/intel64/smp.c new file mode 100644 index 00000000000..a73ba9c8f38 --- /dev/null +++ b/arch/x86/core/intel64/smp.c @@ -0,0 +1,42 @@ +/* + * Copyright (c) 2024 Intel Corporation. + * + * SPDX-License-Identifier: Apache-2.0 + */ +#include +#include +#include +#include +#include + +#define NR_IRQ_VECTORS (IV_NR_VECTORS - IV_IRQS) /* # vectors free for IRQs */ + +extern void (*x86_irq_funcs[NR_IRQ_VECTORS])(const void *arg); +extern const void *x86_irq_args[NR_IRQ_VECTORS]; + + +int arch_smp_init(void) +{ + /* + * z_sched_ipi() doesn't have the same signature as a typical ISR, so + * we fudge it with a cast. the argument is ignored, no harm done. + */ + + x86_irq_funcs[CONFIG_SCHED_IPI_VECTOR - IV_IRQS] = + (void *) z_sched_ipi; + + /* TLB shootdown handling */ + x86_irq_funcs[CONFIG_TLB_IPI_VECTOR - IV_IRQS] = z_x86_tlb_ipi; + return 0; +} + +/* + * it is not clear exactly how/where/why to abstract this, as it + * assumes the use of a local APIC (but there's no other mechanism). + */ +void arch_sched_ipi(void) +{ + z_loapic_ipi(0, LOAPIC_ICR_IPI_OTHERS, CONFIG_SCHED_IPI_VECTOR); +} + +SYS_INIT(arch_smp_init, PRE_KERNEL_1, CONFIG_KERNEL_INIT_PRIORITY_DEFAULT); From 201167bdb1d082a4fe5e89fa4cc59ce60df95589 Mon Sep 17 00:00:00 2001 From: Andriy Gelman Date: Tue, 19 Dec 2023 09:22:44 -0500 Subject: [PATCH 1909/3723] dts: xmc4700_F144x2048: Merge dsram regions and use it as RAM This is in preparation for xmc4xxx mdio/ethernet patch set. In the ethernet drivers, the DMA memory (including descriptor and buffers) must live in dsram1 or dsram2. Currently, in xmc47_relax_kit the RAM is the psram1 region meaning that DMA transfers will not work. Switch to using dsram regions instead. Also, merge dsram1 and dsram2 into a single region since they are contiguous. Signed-off-by: Andriy Gelman --- boards/arm/xmc47_relax_kit/xmc47_relax_kit.dts | 11 +++-------- dts/arm/infineon/xmc4700_F144x2048.dtsi | 9 ++------- 2 files changed, 5 insertions(+), 15 deletions(-) diff --git a/boards/arm/xmc47_relax_kit/xmc47_relax_kit.dts b/boards/arm/xmc47_relax_kit/xmc47_relax_kit.dts index 7f1b8f68a38..3a8cb700432 100644 --- a/boards/arm/xmc47_relax_kit/xmc47_relax_kit.dts +++ b/boards/arm/xmc47_relax_kit/xmc47_relax_kit.dts @@ -48,7 +48,7 @@ }; chosen { - zephyr,sram = &psram1; + zephyr,sram = &dsram_joined; zephyr,flash = &flash0; zephyr,console = &usic0ch0; zephyr,shell-uart = &usic0ch0; @@ -58,14 +58,9 @@ }; -&dsram1 { +&psram1 { compatible = "zephyr,memory-region", "mmio-sram"; - zephyr,memory-region = "DSRAM1"; -}; - -&dsram2 { - compatible = "zephyr,memory-region", "mmio-sram"; - zephyr,memory-region = "DSRAM2"; + zephyr,memory-region = "PSRAM1"; }; &cpu0 { diff --git a/dts/arm/infineon/xmc4700_F144x2048.dtsi b/dts/arm/infineon/xmc4700_F144x2048.dtsi index bd5250050e9..22a9eb30404 100644 --- a/dts/arm/infineon/xmc4700_F144x2048.dtsi +++ b/dts/arm/infineon/xmc4700_F144x2048.dtsi @@ -13,14 +13,9 @@ reg = <0x1ffe8000 DT_SIZE_K(96)>; }; - dsram1: memory@20000000 { + dsram_joined: memory@20000000 { compatible = "mmio-sram"; - reg = <0x20000000 DT_SIZE_K(128)>; - }; - - dsram2: memory@20020000 { - compatible = "mmio-sram"; - reg = <0x20020000 DT_SIZE_K(128)>; + reg = <0x20000000 DT_SIZE_K(256)>; }; }; From d540407fc8ee575944a6df873390c1fedab15a4e Mon Sep 17 00:00:00 2001 From: Andriy Gelman Date: Tue, 19 Dec 2023 09:50:22 -0500 Subject: [PATCH 1910/3723] drivers: mdio: Add xmc4xxx mdio drivers Add mdio drivers for xmc4xxx SoCs. Signed-off-by: Andriy Gelman --- drivers/mdio/CMakeLists.txt | 1 + drivers/mdio/Kconfig | 1 + drivers/mdio/Kconfig.xmc4xxx | 9 + drivers/mdio/mdio_shell.c | 2 + drivers/mdio/mdio_xmc4xxx.c | 185 ++++++++++++++++++ .../infineon/xmc4500_F100x1024-pinctrl.dtsi | 23 +++ .../infineon/xmc4700_F144x2048-pinctrl.dtsi | 23 +++ dts/arm/infineon/xmc4xxx.dtsi | 11 ++ dts/bindings/mdio/infineon,xmc4xxx-mdio.yaml | 31 +++ modules/Kconfig.infineon | 5 + soc/arm/infineon_xmc/4xxx/Kconfig.series | 1 + soc/arm/infineon_xmc/4xxx/soc.c | 3 + 12 files changed, 295 insertions(+) create mode 100644 drivers/mdio/Kconfig.xmc4xxx create mode 100644 drivers/mdio/mdio_xmc4xxx.c create mode 100644 dts/bindings/mdio/infineon,xmc4xxx-mdio.yaml diff --git a/drivers/mdio/CMakeLists.txt b/drivers/mdio/CMakeLists.txt index 03391788187..30c6b9f8306 100644 --- a/drivers/mdio/CMakeLists.txt +++ b/drivers/mdio/CMakeLists.txt @@ -10,3 +10,4 @@ zephyr_library_sources_ifdef(CONFIG_MDIO_NXP_S32_GMAC mdio_nxp_s32_gmac.c) zephyr_library_sources_ifdef(CONFIG_MDIO_ADIN2111 mdio_adin2111.c) zephyr_library_sources_ifdef(CONFIG_MDIO_GPIO mdio_gpio.c) zephyr_library_sources_ifdef(CONFIG_MDIO_NXP_ENET mdio_nxp_enet.c) +zephyr_library_sources_ifdef(CONFIG_MDIO_INFINEON_XMC4XXX mdio_xmc4xxx.c) diff --git a/drivers/mdio/Kconfig b/drivers/mdio/Kconfig index 7e72b50ceb1..2ff20df0b24 100644 --- a/drivers/mdio/Kconfig +++ b/drivers/mdio/Kconfig @@ -31,6 +31,7 @@ source "drivers/mdio/Kconfig.nxp_s32_gmac" source "drivers/mdio/Kconfig.adin2111" source "drivers/mdio/Kconfig.gpio" source "drivers/mdio/Kconfig.nxp_enet" +source "drivers/mdio/Kconfig.xmc4xxx" config MDIO_INIT_PRIORITY int "Init priority" diff --git a/drivers/mdio/Kconfig.xmc4xxx b/drivers/mdio/Kconfig.xmc4xxx new file mode 100644 index 00000000000..75793fa1508 --- /dev/null +++ b/drivers/mdio/Kconfig.xmc4xxx @@ -0,0 +1,9 @@ +# Copyright (c) 2023 SLB +# SPDX-License-Identifier: Apache-2.0 + +config MDIO_INFINEON_XMC4XXX + bool "Infineon XMC4XXX MDIO driver" + default y + depends on DT_HAS_INFINEON_XMC4XXX_MDIO_ENABLED + help + Enable Infineon XMC4XXX MDIO driver. diff --git a/drivers/mdio/mdio_shell.c b/drivers/mdio/mdio_shell.c index 4cde88a009f..376e95244fa 100644 --- a/drivers/mdio/mdio_shell.c +++ b/drivers/mdio/mdio_shell.c @@ -31,6 +31,8 @@ LOG_MODULE_REGISTER(mdio_shell, CONFIG_LOG_DEFAULT_LEVEL); #define DT_DRV_COMPAT zephyr_mdio_gpio #elif DT_HAS_COMPAT_STATUS_OKAY(nxp_enet_mdio) #define DT_DRV_COMPAT nxp_enet_mdio +#elif DT_HAS_COMPAT_STATUS_OKAY(infineon_xmc4xxx_mdio) +#define DT_DRV_COMPAT infineon_xmc4xxx_mdio #else #error "No known devicetree compatible match for MDIO shell" #endif diff --git a/drivers/mdio/mdio_xmc4xxx.c b/drivers/mdio/mdio_xmc4xxx.c new file mode 100644 index 00000000000..02ebfc5096d --- /dev/null +++ b/drivers/mdio/mdio_xmc4xxx.c @@ -0,0 +1,185 @@ +/* + * Copyright (c) 2023 SLB + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#define DT_DRV_COMPAT infineon_xmc4xxx_mdio + +#include + +#include +#include +#include +#include +#include +#include + +#include +#include + +#include +LOG_MODULE_REGISTER(mdio_xmc4xxx, CONFIG_MDIO_LOG_LEVEL); + +#define MDIO_TRANSFER_TIMEOUT_US 250000 + +#define MAX_MDC_FREQUENCY 2500000u /* 400ns period */ +#define MIN_MDC_FREQUENCY 1000000u /* 1us period */ + +struct mdio_xmc4xxx_clock_divider { + uint8_t divider; + uint8_t reg_val; +}; + +static const struct mdio_xmc4xxx_clock_divider mdio_clock_divider[] = { + {.divider = 8, .reg_val = 2}, {.divider = 13, .reg_val = 3}, + {.divider = 21, .reg_val = 0}, {.divider = 31, .reg_val = 1}, + {.divider = 51, .reg_val = 4}, {.divider = 62, .reg_val = 5}, +}; + +struct mdio_xmc4xxx_dev_data { + struct k_mutex mutex; + uint32_t reg_value_gmii_address; +}; + +struct mdio_xmc4xxx_dev_config { + ETH_GLOBAL_TypeDef *const regs; + const struct pinctrl_dev_config *pcfg; + uint8_t mdi_port_ctrl; +}; + +static int mdio_xmc4xxx_transfer(const struct device *dev, uint8_t phy_addr, uint8_t reg_addr, + uint8_t is_write, uint16_t data_write, uint16_t *data_read) +{ + const struct mdio_xmc4xxx_dev_config *const dev_cfg = dev->config; + ETH_GLOBAL_TypeDef *const regs = dev_cfg->regs; + struct mdio_xmc4xxx_dev_data *const dev_data = dev->data; + uint32_t reg; + int ret = 0; + + k_mutex_lock(&dev_data->mutex, K_FOREVER); + + if ((regs->GMII_ADDRESS & ETH_GMII_ADDRESS_MB_Msk) != 0) { + ret = -EBUSY; + goto finish; + } + + reg = dev_data->reg_value_gmii_address; + if (is_write) { + reg |= ETH_GMII_ADDRESS_MW_Msk; + regs->GMII_DATA = data_write; + } + + regs->GMII_ADDRESS = reg | ETH_GMII_ADDRESS_MB_Msk | + FIELD_PREP(ETH_GMII_ADDRESS_PA_Msk, phy_addr) | + FIELD_PREP(ETH_GMII_ADDRESS_MR_Msk, reg_addr); + + if (!WAIT_FOR((regs->GMII_ADDRESS & ETH_GMII_ADDRESS_MB_Msk) == 0, + MDIO_TRANSFER_TIMEOUT_US, k_msleep(5))) { + LOG_WRN("mdio transfer timedout"); + ret = -ETIMEDOUT; + goto finish; + } + + if (!is_write && data_read != NULL) { + *data_read = regs->GMII_DATA; + } + +finish: + k_mutex_unlock(&dev_data->mutex); + + return ret; +} + +static int mdio_xmc4xxx_read(const struct device *dev, uint8_t phy_addr, uint8_t reg_addr, + uint16_t *data) +{ + return mdio_xmc4xxx_transfer(dev, phy_addr, reg_addr, 0, 0, data); +} + +static int mdio_xmc4xxx_write(const struct device *dev, uint8_t phy_addr, + uint8_t reg_addr, uint16_t data) +{ + return mdio_xmc4xxx_transfer(dev, phy_addr, reg_addr, 1, data, NULL); +} + +static void mdio_xmc4xxx_bus_enable(const struct device *dev) +{ + ARG_UNUSED(dev); + /* this will enable the clock for ETH, which generates to MDIO clk */ + XMC_ETH_MAC_Enable(NULL); +} + +static void mdio_xmc4xxx_bus_disable(const struct device *dev) +{ + ARG_UNUSED(dev); + XMC_ETH_MAC_Disable(NULL); +} + +static int mdio_xmc4xxx_set_clock_divider(const struct device *dev) +{ + struct mdio_xmc4xxx_dev_data *dev_data = dev->data; + uint32_t eth_mac_clk = XMC_SCU_CLOCK_GetEthernetClockFrequency(); + + for (int i = 0; i < ARRAY_SIZE(mdio_clock_divider); i++) { + uint8_t divider = mdio_clock_divider[i].divider; + uint8_t reg_val = mdio_clock_divider[i].reg_val; + uint32_t mdc_clk = eth_mac_clk / divider; + + if (mdc_clk > MIN_MDC_FREQUENCY && mdc_clk < MAX_MDC_FREQUENCY) { + LOG_DBG("Using MDC clock divider %d", divider); + LOG_DBG("MDC clock %dHz", mdc_clk); + dev_data->reg_value_gmii_address = + FIELD_PREP(ETH_GMII_ADDRESS_CR_Msk, reg_val); + return 0; + } + } + + return -EINVAL; +} + +static int mdio_xmc4xxx_initialize(const struct device *dev) +{ + const struct mdio_xmc4xxx_dev_config *dev_cfg = dev->config; + struct mdio_xmc4xxx_dev_data *dev_data = dev->data; + XMC_ETH_MAC_PORT_CTRL_t port_ctrl = {0}; + int ret; + + k_mutex_init(&dev_data->mutex); + + ret = pinctrl_apply_state(dev_cfg->pcfg, PINCTRL_STATE_DEFAULT); + if (ret != 0) { + return ret; + } + + ret = mdio_xmc4xxx_set_clock_divider(dev); + if (ret != 0) { + LOG_ERR("Error setting MDIO clock divider"); + return -EINVAL; + } + + port_ctrl.mdio = dev_cfg->mdi_port_ctrl; + ETH0_CON->CON = port_ctrl.raw; + + return ret; +} + +static const struct mdio_driver_api mdio_xmc4xxx_driver_api = { + .read = mdio_xmc4xxx_read, + .write = mdio_xmc4xxx_write, + .bus_enable = mdio_xmc4xxx_bus_enable, + .bus_disable = mdio_xmc4xxx_bus_disable, +}; + +PINCTRL_DT_INST_DEFINE(0); +static const struct mdio_xmc4xxx_dev_config mdio_xmc4xxx_dev_config_0 = { + .regs = (ETH_GLOBAL_TypeDef *)DT_REG_ADDR(DT_INST_PARENT(0)), + .pcfg = PINCTRL_DT_INST_DEV_CONFIG_GET(0), + .mdi_port_ctrl = DT_INST_ENUM_IDX(0, mdi_port_ctrl), +}; + +static struct mdio_xmc4xxx_dev_data mdio_xmc4xxx_dev_data_0; + +DEVICE_DT_INST_DEFINE(0, &mdio_xmc4xxx_initialize, NULL, &mdio_xmc4xxx_dev_data_0, + &mdio_xmc4xxx_dev_config_0, POST_KERNEL, + CONFIG_MDIO_INIT_PRIORITY, &mdio_xmc4xxx_driver_api); diff --git a/dts/arm/infineon/xmc4500_F100x1024-pinctrl.dtsi b/dts/arm/infineon/xmc4500_F100x1024-pinctrl.dtsi index fd05d415d3a..f41623c5e83 100644 --- a/dts/arm/infineon/xmc4500_F100x1024-pinctrl.dtsi +++ b/dts/arm/infineon/xmc4500_F100x1024-pinctrl.dtsi @@ -425,4 +425,27 @@ /omit-if-no-ref/ i2c_scl_dout1_p1_10_u0c0: i2c_scl_dout1_p1_10_u0c0 { pinmux = ; }; + + /omit-if-no-ref/ eth_p0_9_mdo: ebu_p0_9_mdo { + pinmux = ; + hwctrl = "periph1"; + }; + /omit-if-no-ref/ eth_p1_11_mdo: ebu_p1_11_mdo { + pinmux = ; + hwctrl = "periph1"; + }; + /omit-if-no-ref/ eth_p2_0_mdo: ebu_p2_0_mdo { + pinmux = ; + hwctrl = "periph1"; + }; + + /omit-if-no-ref/ eth_p0_9_mdio: eth_p0_9_mdio { + pinmux = ; + }; + /omit-if-no-ref/ eth_p2_0_mdio: eth_p2_0_mdio { + pinmux = ; + }; + /omit-if-no-ref/ eth_p1_11_mdio: eth_p1_11_mdio { + pinmux = ; + }; }; diff --git a/dts/arm/infineon/xmc4700_F144x2048-pinctrl.dtsi b/dts/arm/infineon/xmc4700_F144x2048-pinctrl.dtsi index 75988d493e7..af2fe761a3c 100644 --- a/dts/arm/infineon/xmc4700_F144x2048-pinctrl.dtsi +++ b/dts/arm/infineon/xmc4700_F144x2048-pinctrl.dtsi @@ -985,4 +985,27 @@ /omit-if-no-ref/ i2c_scl_dout1_p3_9_u2c0: i2c_scl_dout1_p3_9_u2c0 { pinmux = ; }; + + /omit-if-no-ref/ eth_p0_9_mdo: eth_p0_9_mdo { + pinmux = ; + hwctrl = "periph1"; + }; + /omit-if-no-ref/ eth_p1_11_mdo: eth_p1_11_mdo { + pinmux = ; + hwctrl = "periph1"; + }; + /omit-if-no-ref/ eth_p2_0_mdo: eth_p2_0_mdo { + pinmux = ; + hwctrl = "periph1"; + }; + + /omit-if-no-ref/ eth_p0_9_mdio: eth_p0_9_mdio { + pinmux = ; + }; + /omit-if-no-ref/ eth_p2_0_mdio: eth_p2_0_mdio { + pinmux = ; + }; + /omit-if-no-ref/ eth_p1_11_mdio: eth_p1_11_mdio { + pinmux = ; + }; }; diff --git a/dts/arm/infineon/xmc4xxx.dtsi b/dts/arm/infineon/xmc4xxx.dtsi index 82845683fc6..7d6831deb63 100644 --- a/dts/arm/infineon/xmc4xxx.dtsi +++ b/dts/arm/infineon/xmc4xxx.dtsi @@ -236,6 +236,17 @@ interrupts = <0 1>; status = "disabled"; }; + + ethernet@5000c000 { + reg = <0x5000C000 0x3FFF>; + + mdio: mdio { + compatible = "infineon,xmc4xxx-mdio"; + status = "disabled"; + #address-cells = <1>; + #size-cells = <0>; + }; + }; }; }; diff --git a/dts/bindings/mdio/infineon,xmc4xxx-mdio.yaml b/dts/bindings/mdio/infineon,xmc4xxx-mdio.yaml new file mode 100644 index 00000000000..b9da5926d6b --- /dev/null +++ b/dts/bindings/mdio/infineon,xmc4xxx-mdio.yaml @@ -0,0 +1,31 @@ +# Copyright (c) 2023 SLB +# SPDX-License-Identifier: Apache-2.0 + +description: Infineon xmc4xxx Family MDIO Driver node + +compatible: "infineon,xmc4xxx-mdio" + +include: + - name: mdio-controller.yaml + - name: pinctrl-device.yaml + +properties: + mdi-port-ctrl: + description: | + The MDIO input is connected to several port/pins via a mux. + This is not handled by pinctrl because the mux is located at the + peripheral and not GPIO. The possible connections are defined by + an enum. + type: string + + enum: + - "P0_9" + - "P2_0" + - "P1_11" + required: true + + pinctrl-0: + required: true + + pinctrl-names: + required: true diff --git a/modules/Kconfig.infineon b/modules/Kconfig.infineon index 4147d138de3..070508ccce4 100644 --- a/modules/Kconfig.infineon +++ b/modules/Kconfig.infineon @@ -55,4 +55,9 @@ config HAS_XMCLIB_WDT help Enable XMCLIB WDT +config HAS_XMCLIB_ETH + bool + help + Enable XMCLIB Ethernet MAC + endif # HAS_XMCLIB diff --git a/soc/arm/infineon_xmc/4xxx/Kconfig.series b/soc/arm/infineon_xmc/4xxx/Kconfig.series index 53312dfaf7b..bfdbcc93091 100644 --- a/soc/arm/infineon_xmc/4xxx/Kconfig.series +++ b/soc/arm/infineon_xmc/4xxx/Kconfig.series @@ -21,5 +21,6 @@ config SOC_SERIES_XMC_4XXX select HAS_XMCLIB_I2C select HAS_XMCLIB_CCU select HAS_XMCLIB_WDT + select HAS_XMCLIB_ETH help Enable support for XMC 4xxx MCU series diff --git a/soc/arm/infineon_xmc/4xxx/soc.c b/soc/arm/infineon_xmc/4xxx/soc.c index 0d4060568a3..44e83a63c6f 100644 --- a/soc/arm/infineon_xmc/4xxx/soc.c +++ b/soc/arm/infineon_xmc/4xxx/soc.c @@ -37,6 +37,9 @@ void z_arm_platform_init(void) #endif #ifdef CONFIG_PWM_XMC4XXX_CCU8 | XMC_SCU_CLOCK_SLEEP_MODE_CONFIG_ENABLE_CCU +#endif +#ifdef CONFIG_ETH_XMC4XXX + | XMC_SCU_CLOCK_SLEEP_MODE_CONFIG_ENABLE_ETH #endif ); From 2837f4f1825b791c30f2e87a3b187c724b05cca1 Mon Sep 17 00:00:00 2001 From: Andriy Gelman Date: Tue, 19 Dec 2023 09:56:37 -0500 Subject: [PATCH 1911/3723] drivers: ethernet: Add xmc4xxx ethernet/PTP drivers Adds ethernet/PTP drivers for xmc4xxx SoCs. Signed-off-by: Andriy Gelman --- drivers/ethernet/CMakeLists.txt | 1 + drivers/ethernet/Kconfig | 1 + drivers/ethernet/Kconfig.xmc4xxx | 56 + drivers/ethernet/eth_xmc4xxx.c | 1162 +++++++++++++++++ .../infineon/xmc4500_F100x1024-pinctrl.dtsi | 125 ++ .../infineon/xmc4700_F144x2048-pinctrl.dtsi | 152 +++ dts/arm/infineon/xmc4xxx.dtsi | 6 + .../ethernet/infineon,xmc4xxx-ethernet.yaml | 118 ++ 8 files changed, 1621 insertions(+) create mode 100644 drivers/ethernet/Kconfig.xmc4xxx create mode 100644 drivers/ethernet/eth_xmc4xxx.c create mode 100644 dts/bindings/ethernet/infineon,xmc4xxx-ethernet.yaml diff --git a/drivers/ethernet/CMakeLists.txt b/drivers/ethernet/CMakeLists.txt index 7b925b3730a..def0c5bf186 100644 --- a/drivers/ethernet/CMakeLists.txt +++ b/drivers/ethernet/CMakeLists.txt @@ -36,6 +36,7 @@ zephyr_library_sources_ifdef(CONFIG_ETH_IVSHMEM eth_ivshmem.c eth_ivshmem_queue zephyr_library_sources_ifdef(CONFIG_ETH_ADIN2111 eth_adin2111.c) zephyr_library_sources_ifdef(CONFIG_ETH_LAN865X eth_lan865x.c oa_tc6.c) zephyr_library_sources_ifdef(CONFIG_ETH_NXP_ENET eth_nxp_enet.c) +zephyr_library_sources_ifdef(CONFIG_ETH_XMC4XXX eth_xmc4xxx.c) if(CONFIG_ETH_NXP_S32_NETC) zephyr_library_sources(eth_nxp_s32_netc.c) diff --git a/drivers/ethernet/Kconfig b/drivers/ethernet/Kconfig index e26c0bafb6d..4bc7b8b9599 100644 --- a/drivers/ethernet/Kconfig +++ b/drivers/ethernet/Kconfig @@ -64,6 +64,7 @@ source "drivers/ethernet/Kconfig.adin2111" source "drivers/ethernet/Kconfig.numaker" source "drivers/ethernet/Kconfig.lan865x" source "drivers/ethernet/Kconfig.nxp_enet" +source "drivers/ethernet/Kconfig.xmc4xxx" source "drivers/ethernet/phy/Kconfig" diff --git a/drivers/ethernet/Kconfig.xmc4xxx b/drivers/ethernet/Kconfig.xmc4xxx new file mode 100644 index 00000000000..258d1462b8f --- /dev/null +++ b/drivers/ethernet/Kconfig.xmc4xxx @@ -0,0 +1,56 @@ +# ETH_XMC4XXX Ethernet driver configuration options + +# Copyright (c) 2023 SLB +# SPDX-License-Identifier: Apache-2.0 + +menuconfig ETH_XMC4XXX + bool "XMC4XXX Ethernet driver" + default y + depends on DT_HAS_INFINEON_XMC4XXX_ETHERNET_ENABLED + help + Enable XMC4XXX Ethernet driver. + +if ETH_XMC4XXX + +config ETH_XMC4XXX_TX_FRAME_POOL_SIZE + int "Number of TX frames in the pool size" + default 4 + help + Number of TX frames which can be buffered in the driver. + +config ETH_XMC4XXX_NUM_TX_DMA_DESCRIPTORS + int "Number of TX DMA descriptors" + default 32 + help + Number of TX DMA descriptors. Each descriptor stores the memory address of a + data fragment and its size. + +config ETH_XMC4XXX_NUM_RX_DMA_DESCRIPTORS + int "Number of RX DMA descriptors" + default 12 + help + Number of RX DMA descriptors. Each descriptor stores the memory address of a + data fragment and its size. The data fragments are pre-allocated from the rx + network buffers (CONFIG_NET_BUF_RX_COUNT). When a frame is received, it is + forwarded to the network stack without copying the data. The buffers + in the descriptors are replaced by new pre-allocated buffers. + +config ETH_XMC4XXX_VLAN_HW_FILTER + bool "Hardware filter VLAN frames" + default y if NET_VLAN_COUNT=1 + depends on NET_VLAN + help + Hardware filter VLAN frames in hardware. Only ethernet frames with + a tag configured using vlan_setup() call will be received. + The filtering can only be done on one vlan tag. If vlan_setup() is + called multiple times, the filtering will be done on the latest + tag. + +config PTP_CLOCK_XMC4XXX + bool "XMC4XXX PTP clock driver support" + default y + depends on PTP_CLOCK + help + Enable XMC4XXX PTP Clock support. + +endif # ETH_XMC4XXX diff --git a/drivers/ethernet/eth_xmc4xxx.c b/drivers/ethernet/eth_xmc4xxx.c new file mode 100644 index 00000000000..ad2cee470f2 --- /dev/null +++ b/drivers/ethernet/eth_xmc4xxx.c @@ -0,0 +1,1162 @@ +/* XMC4XXX Ethernet controller + * + * Copyright (c) 2023 SLB + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#define DT_DRV_COMPAT infineon_xmc4xxx_ethernet + +#include "eth.h" + +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +#include +#include + +#define LOG_LEVEL CONFIG_ETHERNET_LOG_LEVEL +#include +LOG_MODULE_REGISTER(eth_xmc4xxx); + +#define NUM_TX_DMA_DESCRIPTORS CONFIG_ETH_XMC4XXX_NUM_TX_DMA_DESCRIPTORS +#define NUM_RX_DMA_DESCRIPTORS CONFIG_ETH_XMC4XXX_NUM_RX_DMA_DESCRIPTORS + +#define ETH_NODE DT_NODELABEL(eth) +#define PHY_NODE DT_PHANDLE_BY_IDX(ETH_NODE, phy, 0) + +#define INFINEON_OUI_B0 0x00 +#define INFINEON_OUI_B1 0x03 +#define INFINEON_OUI_B2 0x19 + +#define MODULO_INC_TX(val) {(val) = (++(val) < NUM_TX_DMA_DESCRIPTORS) ? (val) : 0; } +#define MODULO_INC_RX(val) {(val) = (++(val) < NUM_RX_DMA_DESCRIPTORS) ? (val) : 0; } + +#define IS_OWNED_BY_DMA_TX(desc) (((desc)->status & ETH_MAC_DMA_TDES0_OWN) != 0) +#define IS_OWNED_BY_DMA_RX(desc) (((desc)->status & ETH_MAC_DMA_RDES0_OWN) != 0) + +#define IS_START_OF_FRAME_RX(desc) (((desc)->status & ETH_MAC_DMA_RDES0_FS) != 0) +#define IS_END_OF_FRAME_RX(desc) (((desc)->status & ETH_MAC_DMA_RDES0_LS) != 0) + +#define IS_TIMESTAMP_AVAILABLE_RX(desc) (((desc)->status & ETH_MAC_DMA_RDES0_TSA) != 0) +#define IS_TIMESTAMP_AVAILABLE_TX(desc) (((desc)->status & ETH_MAC_DMA_TDES0_TTSS) != 0) + +#define TOTAL_FRAME_LENGTH(desc) (FIELD_GET(ETH_MAC_DMA_RDES0_FL, (desc)->status) - 4) + +#define ETH_STATUS_ERROR_TRANSMIT_EVENTS \ + (XMC_ETH_MAC_EVENT_BUS_ERROR | XMC_ETH_MAC_EVENT_TRANSMIT_JABBER_TIMEOUT | \ + XMC_ETH_MAC_EVENT_TRANSMIT_UNDERFLOW | XMC_ETH_MAC_EVENT_TRANSMIT_PROCESS_STOPPED) + +#define ETH_STATUS_ERROR_RECEIVE_EVENTS \ + (XMC_ETH_MAC_EVENT_BUS_ERROR | XMC_ETH_MAC_EVENT_RECEIVE_OVERFLOW) + +#define ETH_STATUS_ALL_EVENTS \ + (ETH_STATUS_ERROR_TRANSMIT_EVENTS | ETH_STATUS_ERROR_RECEIVE_EVENTS | \ + XMC_ETH_MAC_EVENT_RECEIVE | XMC_ETH_MAC_EVENT_TRANSMIT | ETH_INTERRUPT_ENABLE_NIE_Msk | \ + ETH_INTERRUPT_ENABLE_AIE_Msk) + +#define ETH_MAC_DISABLE_MMC_INTERRUPT_MSK 0x03ffffffu +#define ETH_MAC_DISABLE_MMC_IPC_RECEIVE_INTERRUPT_MSK 0x3fff3fffu + +#define ETH_STATUS_CLEARABLE_BITS 0x1e7ffu + +#define ETH_RX_DMA_DESC_SECOND_ADDR_CHAINED_MASK BIT(14) + +#define ETH_RESET_TIMEOUT_USEC 200000u +#define ETH_TIMESTAMP_CONTROL_REG_TIMEOUT_USEC 100000u + +#define ETH_LINK_SPEED_10M 0 +#define ETH_LINK_SPEED_100M 1 + +#define ETH_LINK_DUPLEX_HALF 0 +#define ETH_LINK_DUPLEX_FULL 1 + +#define ETH_PTP_CLOCK_FREQUENCY 50000000 +#define ETH_PTP_RATE_ADJUST_RATIO_MIN 0.9 +#define ETH_PTP_RATE_ADJUST_RATIO_MAX 1.1 + +struct eth_xmc4xxx_data { + struct net_if *iface; + uint8_t mac_addr[6]; + struct k_sem tx_desc_sem; + bool link_up; +#if defined(CONFIG_NET_STATISTICS_ETHERNET) + struct net_stats_eth stats; +#endif + bool tx_frames_flushed; + uint16_t dma_desc_tx_head; + uint16_t dma_desc_rx_tail; + sys_slist_t tx_frame_list; + struct net_buf *rx_frag_list[NUM_RX_DMA_DESCRIPTORS]; +#if defined(CONFIG_PTP_CLOCK_XMC4XXX) + const struct device *ptp_clock; +#endif +}; + +struct eth_xmc4xxx_config { + ETH_GLOBAL_TypeDef *regs; + const struct device *phy_dev; + void (*irq_config_func)(void); + const struct pinctrl_dev_config *pcfg; + const uint8_t phy_connection_type; + XMC_ETH_MAC_PORT_CTRL_t port_ctrl; +}; + +struct eth_xmc4xxx_tx_frame { + sys_snode_t node; + struct net_pkt *pkt; + uint16_t tail_index; + uint16_t head_index; +}; + +K_MEM_SLAB_DEFINE_STATIC(tx_frame_slab, sizeof(struct eth_xmc4xxx_tx_frame), + CONFIG_ETH_XMC4XXX_TX_FRAME_POOL_SIZE, 4); + +static XMC_ETH_MAC_DMA_DESC_t __aligned(4) tx_dma_desc[NUM_TX_DMA_DESCRIPTORS]; +static XMC_ETH_MAC_DMA_DESC_t __aligned(4) rx_dma_desc[NUM_RX_DMA_DESCRIPTORS]; + +static inline struct net_if *get_iface(struct eth_xmc4xxx_data *ctx, uint16_t vlan_tag) +{ +#if defined(CONFIG_NET_VLAN) + struct net_if *iface; + + iface = net_eth_get_vlan_iface(ctx->iface, vlan_tag); + if (!iface) { + return ctx->iface; + } + + return iface; +#else + ARG_UNUSED(vlan_tag); + + return ctx->iface; +#endif +} + +static void eth_xmc4xxx_tx_dma_descriptors_init(const struct device *dev) +{ + const struct eth_xmc4xxx_config *dev_cfg = dev->config; + + memset(tx_dma_desc, 0, sizeof(tx_dma_desc)); + + dev_cfg->regs->TRANSMIT_DESCRIPTOR_LIST_ADDRESS = (uint32_t)&tx_dma_desc[0]; + + /* chain the descriptors */ + for (int i = 0; i < NUM_TX_DMA_DESCRIPTORS - 1; i++) { + XMC_ETH_MAC_DMA_DESC_t *dma_desc = &tx_dma_desc[i]; + + dma_desc->buffer2 = (volatile uint32_t)&tx_dma_desc[i + 1]; + } + + /* TER: transmit end of ring - it is the last descriptor in ring */ + tx_dma_desc[NUM_TX_DMA_DESCRIPTORS - 1].status |= ETH_MAC_DMA_TDES0_TER; + tx_dma_desc[NUM_TX_DMA_DESCRIPTORS - 1].buffer2 = (volatile uint32_t)&tx_dma_desc[0]; +} + +static void eth_xmc4xxx_flush_rx(const struct device *dev) +{ + const struct eth_xmc4xxx_config *dev_cfg = dev->config; + struct eth_xmc4xxx_data *dev_data = dev->data; + + dev_cfg->regs->OPERATION_MODE &= ~ETH_OPERATION_MODE_SR_Msk; + + for (int i = 0; i < NUM_RX_DMA_DESCRIPTORS; i++) { + rx_dma_desc[i].status = ETH_MAC_DMA_RDES0_OWN; + } + + dev_cfg->regs->OPERATION_MODE |= ETH_OPERATION_MODE_SR_Msk; + dev_data->dma_desc_rx_tail = 0; +} + +static void eth_xmc4xxx_flush_tx(const struct device *dev) +{ + const struct eth_xmc4xxx_config *dev_cfg = dev->config; + struct eth_xmc4xxx_data *dev_data = dev->data; + sys_snode_t *node; + + LOG_DBG("Flushing tx frames"); + + if (dev_data->tx_frames_flushed) { + return; + } + + dev_cfg->regs->OPERATION_MODE &= ~ETH_OPERATION_MODE_ST_Msk; + + node = sys_slist_get(&dev_data->tx_frame_list); + while (node) { + struct eth_xmc4xxx_tx_frame *tx_frame = SYS_SLIST_CONTAINER(node, tx_frame, node); + + net_pkt_unref(tx_frame->pkt); + k_mem_slab_free(&tx_frame_slab, (void *)tx_frame); + + node = sys_slist_get(&dev_data->tx_frame_list); +#ifdef CONFIG_NET_STATISTICS_ETHERNET + dev_data->stats.errors.tx++; + dev_data->stats.error_details.tx_aborted_errors++; +#endif + } + + k_sem_reset(&dev_data->tx_desc_sem); + + eth_xmc4xxx_tx_dma_descriptors_init(dev); + dev_cfg->regs->OPERATION_MODE |= ETH_OPERATION_MODE_ST_Msk; + dev_data->dma_desc_tx_head = 0; + dev_data->tx_frames_flushed = true; + + for (int i = 0; i < NUM_TX_DMA_DESCRIPTORS; i++) { + k_sem_give(&dev_data->tx_desc_sem); + } +} + +static inline void eth_xmc4xxx_trigger_dma_tx(ETH_GLOBAL_TypeDef *regs) +{ + regs->STATUS = ETH_STATUS_TPS_Msk; + regs->TRANSMIT_POLL_DEMAND = 0; +} + +static inline void eth_xmc4xxx_trigger_dma_rx(ETH_GLOBAL_TypeDef *regs) +{ + regs->STATUS = ETH_STATUS_RU_Msk; + regs->RECEIVE_POLL_DEMAND = 0U; +} + +static int eth_xmc4xxx_send(const struct device *dev, struct net_pkt *pkt) +{ + struct eth_xmc4xxx_data *dev_data = dev->data; + const struct eth_xmc4xxx_config *dev_cfg = dev->config; + struct net_buf *frag; + uint8_t *frag_data; + uint16_t frag_len; + int ret = 0; + XMC_ETH_MAC_DMA_DESC_t *dma_desc = NULL; + struct eth_xmc4xxx_tx_frame *tx_frame; + int num_frags = 0; + bool first_descriptor = false; + + frag = pkt->frags; + while (frag) { + num_frags++; + frag = frag->frags; + } + + if (num_frags > NUM_TX_DMA_DESCRIPTORS) { +#ifdef CONFIG_NET_STATISTICS_ETHERNET + dev_data->stats.error_details.tx_dma_failed++; +#endif + LOG_DBG("Number of fragments exceeds total descriptors. Dropping packet"); + return -ENOMEM; + } + + /* All available frames buffered inside the driver. Apply back pressure in the driver. */ + while (tx_frame_slab.info.num_used == CONFIG_ETH_XMC4XXX_TX_FRAME_POOL_SIZE) { + eth_xmc4xxx_trigger_dma_tx(dev_cfg->regs); + k_yield(); + } + + ret = k_mem_slab_alloc(&tx_frame_slab, (void **)&tx_frame, K_NO_WAIT); + __ASSERT_NO_MSG(ret == 0); + + net_pkt_ref(pkt); + + dev_data->tx_frames_flushed = false; + + first_descriptor = true; + tx_frame->pkt = pkt; + tx_frame->tail_index = dev_data->dma_desc_tx_head; + + frag = pkt->frags; + while (frag) { + ret = k_sem_take(&dev_data->tx_desc_sem, K_FOREVER); + /* isr may call k_sem_reset() */ + if (ret < 0 || dev_data->tx_frames_flushed) { + k_mem_slab_free(&tx_frame_slab, (void **)&tx_frame); + net_pkt_unref(pkt); +#ifdef CONFIG_NET_STATISTICS_ETHERNET + dev_data->stats.error_details.tx_aborted_errors++; +#endif + LOG_DBG("Dropping frame. Buffered Tx frames were flushed in ISR."); + return -EIO; + } + + unsigned int key = irq_lock(); + /* Critical section for dma_desc_tx_head and tx_dma_desc. Isr may */ + /* reinitialize the descriptors and set dma_desc_tx_head to 0 */ + + dma_desc = &tx_dma_desc[dev_data->dma_desc_tx_head]; + + frag_data = frag->data; + frag_len = frag->len; + + dma_desc->buffer1 = (volatile uint32_t)frag_data; + dma_desc->length = frag_len; + + /* give ownership of descriptor back to dma and set checksum offload */ + /* TCH we are using a circular list */ + dma_desc->status = ETH_MAC_DMA_TDES0_CIC | ETH_MAC_DMA_TDES0_TCH; + + if (!first_descriptor) { + /* Delay giving ownership of first frag to DMA. Prevents race condition */ + /* where second other frags are not ready */ + dma_desc->status |= ETH_MAC_DMA_TDES0_OWN; + } else { + dma_desc->status |= ETH_MAC_DMA_TDES0_FS; + +#if defined(CONFIG_NET_GPTP) + struct net_eth_hdr *hdr = NET_ETH_HDR(pkt); + + if (ntohs(hdr->type) == NET_ETH_PTYPE_PTP) { + dma_desc->status |= ETH_MAC_DMA_TDES0_TTSE; + } +#endif + } + first_descriptor = false; + + tx_frame->head_index = dev_data->dma_desc_tx_head; + + MODULO_INC_TX(dev_data->dma_desc_tx_head); + + irq_unlock(key); + + frag = frag->frags; + } + + if (dev_data->tx_frames_flushed) { + k_mem_slab_free(&tx_frame_slab, (void **)&tx_frame); + net_pkt_unref(pkt); +#ifdef CONFIG_NET_STATISTICS_ETHERNET + dev_data->stats.error_details.tx_aborted_errors++; +#endif + LOG_DBG("Dropping frame. Buffered Tx frames were flushed in ISR."); + return -EIO; + } + + unsigned int key = irq_lock(); + + /* label last dma descriptor as last segment and trigger interrupt on last segment */ + dma_desc->status |= ETH_MAC_DMA_TDES0_IC | ETH_MAC_DMA_TDES0_LS; + + /* Finally give ownership of first frag to DMA. After this point the DMA engine */ + /* may transfer the whole frame from RAM to Ethernet */ + tx_dma_desc[tx_frame->tail_index].status |= ETH_MAC_DMA_TDES0_OWN; + + sys_slist_append(&dev_data->tx_frame_list, &tx_frame->node); + + eth_xmc4xxx_trigger_dma_tx(dev_cfg->regs); + + irq_unlock(key); + + return 0; +} + +static struct net_pkt *eth_xmc4xxx_rx_pkt(const struct device *dev) +{ + struct eth_xmc4xxx_data *dev_data = dev->data; + const struct eth_xmc4xxx_config *dev_cfg = dev->config; + struct net_pkt *pkt = NULL; + struct net_buf *new_frag; + + bool eof_found = false; + uint16_t tail; + XMC_ETH_MAC_DMA_DESC_t *dma_desc; + int num_frags = 0; + uint16_t frame_end_index; + struct net_buf *frag, *last_frag = NULL; + + tail = dev_data->dma_desc_rx_tail; + dma_desc = &rx_dma_desc[tail]; + + if (IS_OWNED_BY_DMA_RX(dma_desc)) { + return NULL; + } + + if (!IS_START_OF_FRAME_RX(dma_desc)) { + /* handle this error - missing SOF packet? */ + eth_xmc4xxx_flush_rx(dev); + return NULL; + } + + while (!IS_OWNED_BY_DMA_RX(dma_desc)) { + eof_found = IS_END_OF_FRAME_RX(dma_desc); + num_frags++; + if (eof_found) { + break; + } + + MODULO_INC_RX(tail); + + if (tail == dev_data->dma_desc_rx_tail) { + /* wrapped */ + break; + } + + dma_desc = &rx_dma_desc[tail]; + } + + if (!eof_found) { + return NULL; + } + + frame_end_index = tail; + + pkt = net_pkt_rx_alloc(K_NO_WAIT); + if (pkt == NULL) { +#ifdef CONFIG_NET_STATISTICS_ETHERNET + dev_data->stats.errors.rx++; + dev_data->stats.error_details.rx_no_buffer_count++; +#endif + LOG_DBG("Net packet allocation error"); + /* continue because we still need to read out the packet */ + } + + tail = dev_data->dma_desc_rx_tail; + dma_desc = &rx_dma_desc[tail]; + for (;;) { + if (pkt != NULL) { + uint16_t frag_len = CONFIG_NET_BUF_DATA_SIZE; + + frag = dev_data->rx_frag_list[tail]; + if (tail == frame_end_index) { + frag_len = TOTAL_FRAME_LENGTH(dma_desc) - + CONFIG_NET_BUF_DATA_SIZE * (num_frags - 1); + + if (IS_TIMESTAMP_AVAILABLE_RX(dma_desc)) { + struct net_ptp_time timestamp = { + .second = dma_desc->time_stamp_seconds, + .nanosecond = dma_desc->time_stamp_nanoseconds}; + + net_pkt_set_timestamp(pkt, ×tamp); + net_pkt_set_priority(pkt, NET_PRIORITY_CA); + } + } + + new_frag = net_pkt_get_frag(pkt, CONFIG_NET_BUF_DATA_SIZE, K_NO_WAIT); + if (new_frag == NULL) { +#ifdef CONFIG_NET_STATISTICS_ETHERNET + dev_data->stats.errors.rx++; + dev_data->stats.error_details.rx_buf_alloc_failed++; +#endif + LOG_DBG("Frag allocation error. Increase CONFIG_NET_BUF_RX_COUNT."); + net_pkt_unref(pkt); + pkt = NULL; + } else { + net_buf_add(frag, frag_len); + if (!last_frag) { + net_pkt_frag_insert(pkt, frag); + } else { + net_buf_frag_insert(last_frag, frag); + } + + last_frag = frag; + frag = new_frag; + dev_data->rx_frag_list[tail] = frag; + } + } + + dma_desc->buffer1 = (uint32_t)dev_data->rx_frag_list[tail]->data; + dma_desc->length = dev_data->rx_frag_list[tail]->size | + ETH_RX_DMA_DESC_SECOND_ADDR_CHAINED_MASK; + dma_desc->status = ETH_MAC_DMA_RDES0_OWN; + + if (tail == frame_end_index) { + break; + } + + MODULO_INC_RX(tail); + dma_desc = &rx_dma_desc[tail]; + } + + + MODULO_INC_RX(tail); + dev_data->dma_desc_rx_tail = tail; + + eth_xmc4xxx_trigger_dma_rx(dev_cfg->regs); + + return pkt; +} + +static void eth_xmc4xxx_handle_rx(const struct device *dev) +{ + struct eth_xmc4xxx_data *dev_data = dev->data; + struct net_pkt *pkt = NULL; + + for (;;) { + uint16_t vlan_tag = NET_VLAN_TAG_UNSPEC; + + pkt = eth_xmc4xxx_rx_pkt(dev); + if (!pkt) { + return; + } +#if defined(CONFIG_NET_VLAN) + struct net_eth_hdr *hdr = NET_ETH_HDR(pkt); + + if (ntohs(hdr->type) == NET_ETH_PTYPE_VLAN) { + struct net_eth_vlan_hdr *hdr_vlan = (struct net_eth_vlan_hdr *)hdr; + + net_pkt_set_vlan_tci(pkt, ntohs(hdr_vlan->vlan.tci)); + vlan_tag = net_pkt_vlan_tag(pkt); + +#if CONFIG_NET_TC_RX_COUNT > 1 + enum net_priority prio; + + prio = net_vlan2priority(net_pkt_vlan_priority(pkt)); + net_pkt_set_priority(pkt, prio); +#endif + } +#endif /* CONFIG_NET_VLAN */ + if (net_recv_data(get_iface(dev_data, vlan_tag), pkt) < 0) { + eth_stats_update_errors_rx(get_iface(dev_data, vlan_tag)); + net_pkt_unref(pkt); + } + } +} + +static void eth_xmc4xxx_handle_tx(const struct device *dev) +{ + struct eth_xmc4xxx_data *dev_data = dev->data; + sys_snode_t *node = sys_slist_peek_head(&dev_data->tx_frame_list); + + while (node) { + struct eth_xmc4xxx_tx_frame *tx_frame = SYS_SLIST_CONTAINER(node, tx_frame, node); + bool owned_by_mcu = true; + uint8_t index; + int num_descriptors; + + if (tx_frame->head_index >= tx_frame->tail_index) { + num_descriptors = tx_frame->head_index - tx_frame->tail_index + 1; + } else { + num_descriptors = tx_frame->head_index + NUM_TX_DMA_DESCRIPTORS - + tx_frame->tail_index + 1; + } + + index = tx_frame->tail_index; + for (int i = 0; i < num_descriptors; i++) { + if (IS_OWNED_BY_DMA_TX(&tx_dma_desc[index])) { + owned_by_mcu = false; + break; + } + + MODULO_INC_TX(index); + } + + if (owned_by_mcu) { +#if defined(CONFIG_NET_GPTP) + XMC_ETH_MAC_DMA_DESC_t *dma_desc = &tx_dma_desc[tx_frame->head_index]; + + if (IS_TIMESTAMP_AVAILABLE_TX(dma_desc)) { + struct net_pkt *pkt = tx_frame->pkt; + + if (atomic_get(&pkt->atomic_ref) > 1) { + struct net_ptp_time timestamp = { + .second = dma_desc->time_stamp_seconds, + .nanosecond = dma_desc->time_stamp_nanoseconds}; + + net_pkt_set_timestamp(pkt, ×tamp); + net_if_add_tx_timestamp(pkt); + } + } +#endif + + for (int i = 0; i < num_descriptors; i++) { + k_sem_give(&dev_data->tx_desc_sem); + } + + sys_slist_get(&dev_data->tx_frame_list); + net_pkt_unref(tx_frame->pkt); + k_mem_slab_free(&tx_frame_slab, (void *)tx_frame); + node = sys_slist_peek_head(&dev_data->tx_frame_list); + } else { + node = NULL; + } + } +} + +static void eth_xmc4xxx_isr(const struct device *dev) +{ + uint32_t lock; + uint32_t status; + const struct eth_xmc4xxx_config *dev_cfg = dev->config; + + lock = irq_lock(); + status = dev_cfg->regs->STATUS; + + if ((status & XMC_ETH_MAC_EVENT_RECEIVE) != 0) { + eth_xmc4xxx_handle_rx(dev); + } + + if ((status & XMC_ETH_MAC_EVENT_TRANSMIT) != 0) { + eth_xmc4xxx_handle_tx(dev); + } + + if ((status & ETH_STATUS_ERROR_TRANSMIT_EVENTS) != 0) { + LOG_ERR("Transmit error event [0x%x]", status); + eth_xmc4xxx_flush_tx(dev); + } + + if ((status & ETH_STATUS_ERROR_RECEIVE_EVENTS) != 0) { + LOG_ERR("Receive error event [0x%x]", status); + eth_xmc4xxx_flush_rx(dev); + } + + dev_cfg->regs->STATUS = status & ETH_STATUS_CLEARABLE_BITS; + + irq_unlock(lock); +} + +static inline void eth_xmc4xxx_enable_tx(ETH_GLOBAL_TypeDef *regs) +{ + regs->OPERATION_MODE |= ETH_OPERATION_MODE_ST_Msk; + regs->MAC_CONFIGURATION |= ETH_MAC_CONFIGURATION_TE_Msk; +} + +static inline void eth_xmc4xxx_enable_rx(ETH_GLOBAL_TypeDef *regs) +{ + regs->OPERATION_MODE |= ETH_OPERATION_MODE_SR_Msk; + regs->MAC_CONFIGURATION |= ETH_MAC_CONFIGURATION_RE_Msk; +} + +static inline void eth_xmc4xxx_set_link(ETH_GLOBAL_TypeDef *regs, struct phy_link_state *state) +{ + uint32_t reg = regs->MAC_CONFIGURATION; + uint32_t val; + + reg &= ~(ETH_MAC_CONFIGURATION_DM_Msk | ETH_MAC_CONFIGURATION_FES_Msk); + + val = PHY_LINK_IS_FULL_DUPLEX(state->speed) ? ETH_LINK_DUPLEX_FULL : + ETH_LINK_DUPLEX_HALF; + reg |= FIELD_PREP(ETH_MAC_CONFIGURATION_DM_Msk, val); + + val = PHY_LINK_IS_SPEED_100M(state->speed) ? ETH_LINK_SPEED_100M : + ETH_LINK_SPEED_10M; + reg |= FIELD_PREP(ETH_MAC_CONFIGURATION_FES_Msk, val); + + regs->MAC_CONFIGURATION = reg; +} + +static void phy_link_state_changed(const struct device *phy_dev, struct phy_link_state *state, + void *user_data) +{ + struct device *dev = user_data; + struct eth_xmc4xxx_data *dev_data = dev->data; + const struct eth_xmc4xxx_config *dev_cfg = dev->config; + bool is_up = state->is_up; + + if (is_up && !dev_data->link_up) { + LOG_INF("Link up"); + dev_data->link_up = true; + net_eth_carrier_on(dev_data->iface); + eth_xmc4xxx_set_link(dev_cfg->regs, state); + } else if (!is_up && dev_data->link_up) { + LOG_INF("Link down"); + dev_data->link_up = false; + net_eth_carrier_off(dev_data->iface); + } +} + +static void eth_xmc4xxx_iface_init(struct net_if *iface) +{ + const struct device *dev = net_if_get_device(iface); + struct eth_xmc4xxx_data *dev_data = dev->data; + const struct eth_xmc4xxx_config *dev_cfg = dev->config; + + dev_data->iface = iface; + + net_if_set_link_addr(iface, dev_data->mac_addr, sizeof(dev_data->mac_addr), + NET_LINK_ETHERNET); + + ethernet_init(iface); + + dev_cfg->irq_config_func(); + + /* Do not start the interface until PHY link is up */ + net_if_carrier_off(iface); + + phy_link_callback_set(dev_cfg->phy_dev, &phy_link_state_changed, (void *)dev); + + dev_cfg->regs->INTERRUPT_ENABLE |= ETH_STATUS_ALL_EVENTS; + + eth_xmc4xxx_enable_tx(dev_cfg->regs); + eth_xmc4xxx_enable_rx(dev_cfg->regs); +} + +#if defined(CONFIG_NET_STATISTICS_ETHERNET) +static struct net_stats_eth *eth_xmc4xxx_stats(const struct device *dev) +{ + struct eth_xmc4xxx_data *dev_data = dev->data; + + return &dev_data->stats; +} +#endif + +static inline void eth_xmc4xxx_free_rx_bufs(const struct device *dev) +{ + struct eth_xmc4xxx_data *dev_data = dev->data; + + for (int i = 0; i < NUM_RX_DMA_DESCRIPTORS; i++) { + if (dev_data->rx_frag_list[i]) { + net_buf_unref(dev_data->rx_frag_list[i]); + dev_data->rx_frag_list[i] = NULL; + } + } +} + +static int eth_xmc4xxx_rx_dma_descriptors_init(const struct device *dev) +{ + struct eth_xmc4xxx_data *dev_data = dev->data; + const struct eth_xmc4xxx_config *dev_cfg = dev->config; + + dev_cfg->regs->RECEIVE_DESCRIPTOR_LIST_ADDRESS = (uint32_t)&rx_dma_desc[0]; + + for (int i = 0; i < NUM_RX_DMA_DESCRIPTORS - 1; i++) { + XMC_ETH_MAC_DMA_DESC_t *dma_desc = &rx_dma_desc[i]; + + dma_desc->buffer2 = (volatile uint32_t)&rx_dma_desc[i + 1]; + } + + rx_dma_desc[NUM_RX_DMA_DESCRIPTORS - 1].status |= ETH_MAC_DMA_TDES0_TER; + rx_dma_desc[NUM_RX_DMA_DESCRIPTORS - 1].buffer2 = (volatile uint32_t)&rx_dma_desc[0]; + + for (int i = 0; i < NUM_RX_DMA_DESCRIPTORS; i++) { + XMC_ETH_MAC_DMA_DESC_t *dma_desc = &rx_dma_desc[i]; + struct net_buf *rx_buf = net_pkt_get_reserve_rx_data(CONFIG_NET_BUF_DATA_SIZE, + K_NO_WAIT); + + if (rx_buf == NULL) { + eth_xmc4xxx_free_rx_bufs(dev); + LOG_ERR("Failed to reserve data net buffers"); + return -ENOBUFS; + } + + dev_data->rx_frag_list[i] = rx_buf; + dma_desc->buffer1 = (uint32_t)rx_buf->data; + dma_desc->length = rx_buf->size | ETH_RX_DMA_DESC_SECOND_ADDR_CHAINED_MASK; + dma_desc->status = ETH_MAC_DMA_RDES0_OWN; + } + + return 0; +} + +static inline int eth_xmc4xxx_reset(const struct device *dev) +{ + const struct eth_xmc4xxx_config *dev_cfg = dev->config; + + dev_cfg->regs->BUS_MODE |= ETH_BUS_MODE_SWR_Msk; + + /* reset may fail if the clocks are not properly setup */ + if (!WAIT_FOR((dev_cfg->regs->BUS_MODE & ETH_BUS_MODE_SWR_Msk) == 0, + ETH_RESET_TIMEOUT_USEC,)) { + return -ETIMEDOUT; + } + + return 0; +} + +static inline void eth_xmc4xxx_set_mac_address(ETH_GLOBAL_TypeDef *regs, uint8_t *const addr) +{ + regs->MAC_ADDRESS0_HIGH = addr[4] | (addr[5] << 8); + regs->MAC_ADDRESS0_LOW = addr[0] | (addr[1] << 8) | (addr[2] << 16) | (addr[3] << 24); +} + +static inline void eth_xmc4xxx_mask_unused_interrupts(ETH_GLOBAL_TypeDef *regs) +{ + /* Disable Mac Management Counter (MMC) interrupt events */ + regs->MMC_TRANSMIT_INTERRUPT_MASK = ETH_MAC_DISABLE_MMC_INTERRUPT_MSK; + regs->MMC_RECEIVE_INTERRUPT_MASK = ETH_MAC_DISABLE_MMC_INTERRUPT_MSK; + + /* IPC - Receive IP checksum checker */ + regs->MMC_IPC_RECEIVE_INTERRUPT_MASK = ETH_MAC_DISABLE_MMC_IPC_RECEIVE_INTERRUPT_MSK; + + /* Disable PMT and timestamp interrupt events */ + regs->INTERRUPT_MASK = ETH_INTERRUPT_MASK_PMTIM_Msk | ETH_INTERRUPT_MASK_TSIM_Msk; +} + +static inline int eth_xmc4xxx_init_timestamp_control_reg(ETH_GLOBAL_TypeDef *regs) +{ +#if defined(CONFIG_NET_GPTP) + regs->TIMESTAMP_CONTROL = ETH_TIMESTAMP_CONTROL_TSENA_Msk | + ETH_TIMESTAMP_CONTROL_TSENALL_Msk; +#endif + +#if defined(CONFIG_PTP_CLOCK_XMC4XXX) + /* use fine control */ + regs->TIMESTAMP_CONTROL |= ETH_TIMESTAMP_CONTROL_TSCFUPDT_Msk | + ETH_TIMESTAMP_CONTROL_TSCTRLSSR_Msk; + + /* make ptp run at 50MHz - implies 20ns increment for each increment of the */ + /* sub_second_register */ + regs->SUB_SECOND_INCREMENT = 20; + + /* f_out = f_cpu * K / 2^32, where K = TIMESTAMP_ADDEND. Target F_out = 50MHz */ + /* Therefore, K = ceil(f_out * 2^32 / f_cpu) */ + + uint32_t f_cpu = XMC_SCU_CLOCK_GetSystemClockFrequency(); + uint32_t K = (BIT64(32) * ETH_PTP_CLOCK_FREQUENCY + f_cpu / 2) / f_cpu; + + regs->TIMESTAMP_ADDEND = K; + + /* Addend register update */ + regs->TIMESTAMP_CONTROL |= ETH_TIMESTAMP_CONTROL_TSADDREG_Msk; + if (!WAIT_FOR((regs->TIMESTAMP_CONTROL & ETH_TIMESTAMP_CONTROL_TSADDREG_Msk) == 0, + ETH_TIMESTAMP_CONTROL_REG_TIMEOUT_USEC,)) { + return -ETIMEDOUT; + } + + regs->TIMESTAMP_CONTROL |= ETH_TIMESTAMP_CONTROL_TSINIT_Msk; + if (!WAIT_FOR((regs->TIMESTAMP_CONTROL & ETH_TIMESTAMP_CONTROL_TSINIT_Msk) == 0, + ETH_TIMESTAMP_CONTROL_REG_TIMEOUT_USEC,)) { + return -ETIMEDOUT; + } +#endif + return 0; +} + +static int eth_xmc4xxx_init(const struct device *dev) +{ + struct eth_xmc4xxx_data *dev_data = dev->data; + const struct eth_xmc4xxx_config *dev_cfg = dev->config; + XMC_ETH_MAC_PORT_CTRL_t port_ctrl; + int ret; + + sys_slist_init(&dev_data->tx_frame_list); + k_sem_init(&dev_data->tx_desc_sem, NUM_TX_DMA_DESCRIPTORS, + NUM_TX_DMA_DESCRIPTORS); + + if (!device_is_ready(dev_cfg->phy_dev)) { + LOG_ERR("Phy device not ready"); + return -ENODEV; + } + + /* get the port control initialized by MDIO driver */ + port_ctrl.raw = ETH0_CON->CON; + port_ctrl.raw |= dev_cfg->port_ctrl.raw; + + XMC_ETH_MAC_Disable(NULL); + ret = pinctrl_apply_state(dev_cfg->pcfg, PINCTRL_STATE_DEFAULT); + if (ret) { + return ret; + } + + XMC_ETH_MAC_SetPortControl(NULL, port_ctrl); + XMC_ETH_MAC_Enable(NULL); + + ret = eth_xmc4xxx_reset(dev); + if (ret != 0) { + LOG_ERR("Error resetting ethernet [%d]", ret); + return ret; + } + + /* Initialize MAC configuration */ + /* enable checksum offload */ + dev_cfg->regs->MAC_CONFIGURATION = ETH_MAC_CONFIGURATION_IPC_Msk; + + /* disable jumbo frames */ + dev_cfg->regs->MAC_CONFIGURATION &= ~ETH_MAC_CONFIGURATION_JE_Msk; + + + /* Initialize Filter registers - disable zero quanta pause*/ + dev_cfg->regs->FLOW_CONTROL = ETH_FLOW_CONTROL_DZPQ_Msk; + + /* rsf - receive store and forward */ + /* tsf - transmit store and forward */ + dev_cfg->regs->OPERATION_MODE = ETH_OPERATION_MODE_RSF_Msk | ETH_OPERATION_MODE_TSF_Msk | + ETH_OPERATION_MODE_OSF_Msk; + + /* Increase enhanced descriptor to 8 WORDS, required when the Advanced */ + /* Time-Stamp feature or Full IPC Offload Engine is enabled */ + dev_cfg->regs->BUS_MODE = ETH_BUS_MODE_ATDS_Msk | ETH_BUS_MODE_AAL_Msk | + ETH_BUS_MODE_FB_Msk | (0x20 << ETH_BUS_MODE_PBL_Pos); + + eth_xmc4xxx_tx_dma_descriptors_init(dev); + ret = eth_xmc4xxx_rx_dma_descriptors_init(dev); + if (ret != 0) { + return ret; + } + + /* Clear interrupts */ + dev_cfg->regs->STATUS = ETH_STATUS_CLEARABLE_BITS; + + eth_xmc4xxx_mask_unused_interrupts(dev_cfg->regs); + +#if !DT_INST_NODE_HAS_PROP(0, local_mac_address) + gen_random_mac(dev_data->mac_addr, INFINEON_OUI_B0, INFINEON_OUI_B1, INFINEON_OUI_B2); +#endif + eth_xmc4xxx_set_mac_address(dev_cfg->regs, dev_data->mac_addr); + + uint32_t reg = dev_cfg->regs->MAC_FRAME_FILTER; + /* enable reception of broadcast frames */ + reg &= ~ETH_MAC_FRAME_FILTER_DBF_Msk; + /* pass all multicast frames */ + reg |= ETH_MAC_FRAME_FILTER_PM_Msk; + dev_cfg->regs->MAC_FRAME_FILTER = reg; + + return eth_xmc4xxx_init_timestamp_control_reg(dev_cfg->regs); +} + +static enum ethernet_hw_caps eth_xmc4xxx_capabilities(const struct device *dev) +{ + ARG_UNUSED(dev); + enum ethernet_hw_caps caps = ETHERNET_LINK_10BASE_T | ETHERNET_LINK_100BASE_T | + ETHERNET_HW_TX_CHKSUM_OFFLOAD | ETHERNET_HW_RX_CHKSUM_OFFLOAD; + +#if defined(CONFIG_PTP_CLOCK_XMC4XXX) + caps |= ETHERNET_PTP; +#endif + +#if defined(CONFIG_NET_VLAN) + caps |= ETHERNET_HW_VLAN; +#endif + + return caps; +} + +static int eth_xmc4xxx_set_config(const struct device *dev, enum ethernet_config_type type, + const struct ethernet_config *config) +{ + struct eth_xmc4xxx_data *dev_data = dev->data; + const struct eth_xmc4xxx_config *dev_cfg = dev->config; + + switch (type) { + case ETHERNET_CONFIG_TYPE_MAC_ADDRESS: + memcpy(dev_data->mac_addr, config->mac_address.addr, sizeof(dev_data->mac_addr)); + LOG_INF("%s MAC set to %02x:%02x:%02x:%02x:%02x:%02x", dev->name, + dev_data->mac_addr[0], dev_data->mac_addr[1], dev_data->mac_addr[2], + dev_data->mac_addr[3], dev_data->mac_addr[4], dev_data->mac_addr[5]); + + eth_xmc4xxx_set_mac_address(dev_cfg->regs, dev_data->mac_addr); + net_if_set_link_addr(dev_data->iface, dev_data->mac_addr, + sizeof(dev_data->mac_addr), NET_LINK_ETHERNET); + return 0; + default: + break; + } + + return -ENOTSUP; +} + +static void eth_xmc4xxx_irq_config(void) +{ + IRQ_CONNECT(DT_INST_IRQN(0), DT_INST_IRQ(0, priority), eth_xmc4xxx_isr, + DEVICE_DT_INST_GET(0), 0); + irq_enable(DT_INST_IRQN(0)); +} + +#if defined(CONFIG_PTP_CLOCK_XMC4XXX) +static const struct device *eth_xmc4xxx_get_ptp_clock(const struct device *dev) +{ + struct eth_xmc4xxx_data *dev_data = dev->data; + + return dev_data->ptp_clock; +} +#endif + + +#if defined(CONFIG_ETH_XMC4XXX_VLAN_HW_FILTER) +int eth_xmc4xxx_vlan_setup(const struct device *dev, struct net_if *iface, uint16_t tag, + bool enable) +{ + ARG_UNUSED(iface); + const struct eth_xmc4xxx_config *dev_cfg = dev->config; + + LOG_INF("Configuring vlan %d", tag); + + if (enable) { + dev_cfg->regs->VLAN_TAG = FIELD_PREP(ETH_VLAN_TAG_VL_Msk, tag) | + ETH_VLAN_TAG_ETV_Msk | + ETH_VLAN_TAG_ESVL_Msk; + dev_cfg->regs->MAC_FRAME_FILTER |= ETH_MAC_FRAME_FILTER_VTFE_Msk; + } else { + dev_cfg->regs->VLAN_TAG = 0; + dev_cfg->regs->MAC_FRAME_FILTER &= ~ETH_MAC_FRAME_FILTER_VTFE_Msk; + } + + return 0; +} +#endif + +static const struct ethernet_api eth_xmc4xxx_api = { + .iface_api.init = eth_xmc4xxx_iface_init, + .send = eth_xmc4xxx_send, + .set_config = eth_xmc4xxx_set_config, + .get_capabilities = eth_xmc4xxx_capabilities, +#if defined(CONFIG_NET_STATISTICS_ETHERNET) + .get_stats = eth_xmc4xxx_stats, +#endif +#if defined(CONFIG_PTP_CLOCK_XMC4XXX) + .get_ptp_clock = eth_xmc4xxx_get_ptp_clock, +#endif +#if defined(CONFIG_ETH_XMC4XXX_VLAN_HW_FILTER) + .vlan_setup = eth_xmc4xxx_vlan_setup, +#endif +}; + +PINCTRL_DT_INST_DEFINE(0); + +static struct eth_xmc4xxx_config eth_xmc4xxx_config = { + .regs = (ETH_GLOBAL_TypeDef *)DT_REG_ADDR(DT_INST_PARENT(0)), + .irq_config_func = eth_xmc4xxx_irq_config, + .phy_dev = DEVICE_DT_GET(DT_INST_PHANDLE(0, phy_handle)), + .pcfg = PINCTRL_DT_INST_DEV_CONFIG_GET(0), + .port_ctrl = { + .rxd0 = DT_INST_ENUM_IDX(0, rxd0_port_ctrl), + .rxd1 = DT_INST_ENUM_IDX(0, rxd1_port_ctrl), + .rxd2 = DT_INST_ENUM_IDX_OR(0, rxd2_port_ctrl, 0), + .rxd3 = DT_INST_ENUM_IDX_OR(0, rxd3_port_ctrl, 0), + .clk_rmii = DT_INST_ENUM_IDX(0, rmii_rx_clk_port_ctrl), + .crs_dv = DT_INST_ENUM_IDX(0, crs_rx_dv_port_ctrl), + .crs = DT_INST_ENUM_IDX_OR(0, crs_port_ctrl, 0), + .rxer = DT_INST_ENUM_IDX(0, rxer_port_ctrl), + .col = DT_INST_ENUM_IDX_OR(0, col_port_ctrl, 0), + .clk_tx = DT_INST_ENUM_IDX_OR(0, tx_clk_port_ctrl, 0), + .mode = DT_INST_ENUM_IDX_OR(0, phy_connection_type, 0), + } +}; + +static struct eth_xmc4xxx_data eth_xmc4xxx_data = { + .mac_addr = DT_INST_PROP_OR(0, local_mac_address, {0}), +}; + +ETH_NET_DEVICE_DT_INST_DEFINE(0, eth_xmc4xxx_init, NULL, ð_xmc4xxx_data, ð_xmc4xxx_config, + CONFIG_ETH_INIT_PRIORITY, ð_xmc4xxx_api, NET_ETH_MTU); + +#if defined(CONFIG_PTP_CLOCK_XMC4XXX) + +struct ptp_context { + const struct device *eth_dev; +}; + +static struct ptp_context ptp_xmc4xxx_context_0; + +static int eth_xmc4xxx_ptp_clock_set(const struct device *dev, struct net_ptp_time *tm) +{ + struct ptp_context *ptp_context = dev->data; + const struct eth_xmc4xxx_config *dev_cfg = ptp_context->eth_dev->config; + + dev_cfg->regs->SYSTEM_TIME_NANOSECONDS_UPDATE = tm->nanosecond; + dev_cfg->regs->SYSTEM_TIME_SECONDS_UPDATE = tm->second; + + dev_cfg->regs->TIMESTAMP_CONTROL |= ETH_TIMESTAMP_CONTROL_TSINIT_Msk; + if (!WAIT_FOR((dev_cfg->regs->TIMESTAMP_CONTROL & ETH_TIMESTAMP_CONTROL_TSINIT_Msk) == 0, + ETH_TIMESTAMP_CONTROL_REG_TIMEOUT_USEC,)) { + return -ETIMEDOUT; + } + + return 0; +} + +static int eth_xmc4xxx_ptp_clock_get(const struct device *dev, struct net_ptp_time *tm) +{ + struct ptp_context *ptp_context = dev->data; + const struct eth_xmc4xxx_config *dev_cfg = ptp_context->eth_dev->config; + + uint32_t nanosecond_0 = dev_cfg->regs->SYSTEM_TIME_NANOSECONDS; + uint32_t second_0 = dev_cfg->regs->SYSTEM_TIME_SECONDS; + + uint32_t nanosecond_1 = dev_cfg->regs->SYSTEM_TIME_NANOSECONDS; + uint32_t second_1 = dev_cfg->regs->SYSTEM_TIME_SECONDS; + + /* check that there is no roll over while we read the timestamp. If roll over happens */ + /* just choose the later value */ + if (second_0 == second_1) { + tm->second = second_0; + tm->nanosecond = nanosecond_0; + } else { + tm->second = second_1; + tm->nanosecond = nanosecond_1; + } + + return 0; +} + +static int eth_xmc4xxx_ptp_clock_adjust(const struct device *dev, int increment) +{ + struct ptp_context *ptp_context = dev->data; + const struct eth_xmc4xxx_config *dev_cfg = ptp_context->eth_dev->config; + uint32_t increment_tmp; + + if ((increment <= -(int)NSEC_PER_SEC) || (increment >= (int)NSEC_PER_SEC)) { + return -EINVAL; + } + + if (increment < 0) { + increment_tmp = -increment; + increment_tmp |= ETH_SYSTEM_TIME_NANOSECONDS_UPDATE_ADDSUB_Msk; + } else { + increment_tmp = increment; + } + + dev_cfg->regs->SYSTEM_TIME_NANOSECONDS_UPDATE = increment_tmp; + dev_cfg->regs->SYSTEM_TIME_SECONDS_UPDATE = 0; + + dev_cfg->regs->TIMESTAMP_CONTROL |= ETH_TIMESTAMP_CONTROL_TSUPDT_Msk; + if (!WAIT_FOR((dev_cfg->regs->TIMESTAMP_CONTROL & ETH_TIMESTAMP_CONTROL_TSUPDT_Msk) == 0, + ETH_TIMESTAMP_CONTROL_REG_TIMEOUT_USEC,)) { + return -ETIMEDOUT; + } + + return 0; +} + +static int eth_xmc4xxx_ptp_clock_rate_adjust(const struct device *dev, double ratio) +{ + struct ptp_context *ptp_context = dev->data; + const struct eth_xmc4xxx_config *dev_cfg = ptp_context->eth_dev->config; + uint64_t K = dev_cfg->regs->TIMESTAMP_ADDEND; + + if (ratio < ETH_PTP_RATE_ADJUST_RATIO_MIN || ratio > ETH_PTP_RATE_ADJUST_RATIO_MAX) { + return -EINVAL; + } + + /* f_out = f_cpu * K / 2^32, where K = TIMESTAMP_ADDEND. Target F_out = 50MHz */ + K = K * ratio + 0.5; + if (K > UINT32_MAX) { + return -EINVAL; + } + dev_cfg->regs->TIMESTAMP_ADDEND = K; + + /* Addend register update */ + dev_cfg->regs->TIMESTAMP_CONTROL |= ETH_TIMESTAMP_CONTROL_TSADDREG_Msk; + if (!WAIT_FOR((dev_cfg->regs->TIMESTAMP_CONTROL & ETH_TIMESTAMP_CONTROL_TSADDREG_Msk) == 0, + ETH_TIMESTAMP_CONTROL_REG_TIMEOUT_USEC,)) { + return -ETIMEDOUT; + } + + return 0; +} + +static const struct ptp_clock_driver_api ptp_api_xmc4xxx = { + .set = eth_xmc4xxx_ptp_clock_set, + .get = eth_xmc4xxx_ptp_clock_get, + .adjust = eth_xmc4xxx_ptp_clock_adjust, + .rate_adjust = eth_xmc4xxx_ptp_clock_rate_adjust, +}; + +static int ptp_clock_xmc4xxx_init(const struct device *port) +{ + const struct device *const eth_dev = DEVICE_DT_INST_GET(0); + struct eth_xmc4xxx_data *dev_data = eth_dev->data; + struct ptp_context *ptp_context = port->data; + + dev_data->ptp_clock = port; + ptp_context->eth_dev = eth_dev; + + return 0; +} + +DEVICE_DEFINE(xmc4xxx_ptp_clock_0, PTP_CLOCK_NAME, ptp_clock_xmc4xxx_init, NULL, + &ptp_xmc4xxx_context_0, NULL, POST_KERNEL, CONFIG_PTP_CLOCK_INIT_PRIORITY, + &ptp_api_xmc4xxx); + +#endif /* CONFIG_PTP_CLOCK_XMC4XXX */ diff --git a/dts/arm/infineon/xmc4500_F100x1024-pinctrl.dtsi b/dts/arm/infineon/xmc4500_F100x1024-pinctrl.dtsi index f41623c5e83..f0d7d31f9eb 100644 --- a/dts/arm/infineon/xmc4500_F100x1024-pinctrl.dtsi +++ b/dts/arm/infineon/xmc4500_F100x1024-pinctrl.dtsi @@ -448,4 +448,129 @@ /omit-if-no-ref/ eth_p1_11_mdio: eth_p1_11_mdio { pinmux = ; }; + + /omit-if-no-ref/ eth_p0_4_tx_en: eth_p0_4_tx_en { + pinmux = ; + }; + /omit-if-no-ref/ eth_p0_5_txd0: eth_p0_5_txd0 { + pinmux = ; + }; + /omit-if-no-ref/ eth_p0_6_txd1: eth_p0_6_txd1 { + pinmux = ; + }; + /omit-if-no-ref/ eth_p0_10_mdc: eth_p0_10_mdc { + pinmux = ; + }; + /omit-if-no-ref/ eth_p1_10_mdc: eth_p1_10_mdc { + pinmux = ; + }; + /omit-if-no-ref/ eth_p1_12_tx_en: eth_p1_12_tx_en { + pinmux = ; + }; + /omit-if-no-ref/ eth_p1_13_txd0: eth_p1_13_txd0 { + pinmux = ; + }; + /omit-if-no-ref/ eth_p1_14_txd1: eth_p1_14_txd1 { + pinmux = ; + }; + /omit-if-no-ref/ eth_p2_5_tx_en: eth_p2_5_tx_en { + pinmux = ; + }; + /omit-if-no-ref/ eth_p2_7_mdc: eth_p2_7_mdc { + pinmux = ; + }; + /omit-if-no-ref/ eth_p2_8_txd0: eth_p2_8_txd0 { + pinmux = ; + }; + /omit-if-no-ref/ eth_p2_9_txd1: eth_p2_9_txd1 { + pinmux = ; + }; + + /omit-if-no-ref/ eth_p2_2_rxd0: eth_p2_2_rxd0 { + pinmux = ; + }; + /omit-if-no-ref/ eth_p0_2_rxd0: eth_p0_2_rxd0 { + pinmux = ; + }; + /omit-if-no-ref/ eth_p14_8_rxd0: eth_p14_8_rxd0 { + pinmux = ; + }; + /omit-if-no-ref/ eth_p5_0_rxd0: eth_p5_0_rxd0 { + pinmux = ; + }; + /omit-if-no-ref/ eth_p2_3_rxd1: eth_p2_3_rxd1 { + pinmux = ; + }; + /omit-if-no-ref/ eth_p0_3_rxd1: eth_p0_3_rxd1 { + pinmux = ; + }; + /omit-if-no-ref/ eth_p14_9_rxd1: eth_p14_9_rxd1 { + pinmux = ; + }; + /omit-if-no-ref/ eth_p5_1_rxd1: eth_p5_1_rxd1 { + pinmux = ; + }; + /omit-if-no-ref/ eth_p5_8_rxd2: eth_p5_8_rxd2 { + pinmux = ; + }; + /omit-if-no-ref/ eth_p6_4_rxd2: eth_p6_4_rxd2 { + pinmux = ; + }; + /omit-if-no-ref/ eth_p5_9_rxd3: eth_p5_9_rxd3 { + pinmux = ; + }; + /omit-if-no-ref/ eth_p6_3_rxd3: eth_p6_3_rxd3 { + pinmux = ; + }; + /omit-if-no-ref/ eth_p2_1_clk_rmii: eth_p2_1_clk_rmii { + pinmux = ; + }; + /omit-if-no-ref/ eth_p0_0_clk_rmii: eth_p0_0_clk_rmii { + pinmux = ; + }; + /omit-if-no-ref/ eth_p15_8_clk_rmii: eth_p15_8_clk_rmii { + pinmux = ; + }; + /omit-if-no-ref/ eth_p6_5_clk_rmii: eth_p6_5_clk_rmii { + pinmux = ; + }; + /omit-if-no-ref/ eth_p2_5_crs_dv: eth_p2_5_crs_dv { + pinmux = ; + }; + /omit-if-no-ref/ eth_p0_1_crs_dv: eth_p0_1_crs_dv { + pinmux = ; + }; + /omit-if-no-ref/ eth_p15_9_crs_dv: eth_p15_9_crs_dv { + pinmux = ; + }; + /omit-if-no-ref/ eth_p5_2_crs_dv: eth_p5_2_crs_dv { + pinmux = ; + }; + /omit-if-no-ref/ eth_p5_11_crs: eth_p5_11_crs { + pinmux = ; + }; + /omit-if-no-ref/ eth_p5_4_crs: eth_p5_4_crs { + pinmux = ; + }; + /omit-if-no-ref/ eth_p2_4_rxer: eth_p2_4_rxer { + pinmux = ; + }; + /omit-if-no-ref/ eth_p0_11_rxer: eth_p0_11_rxer { + pinmux = ; + }; + /omit-if-no-ref/ eth_p5_3_rxer: eth_p5_3_rxer { + pinmux = ; + }; + /omit-if-no-ref/ eth_p2_15_col: eth_p2_15_col { + pinmux = ; + }; + /omit-if-no-ref/ eth_p5_5_col: eth_p5_5_col { + pinmux = ; + }; + /omit-if-no-ref/ eth_p5_10_clk_tx: eth_p5_10_clk_tx { + pinmux = ; + }; + /omit-if-no-ref/ eth_p6_6_clk_tx: eth_p6_6_clk_tx { + pinmux = ; + }; }; diff --git a/dts/arm/infineon/xmc4700_F144x2048-pinctrl.dtsi b/dts/arm/infineon/xmc4700_F144x2048-pinctrl.dtsi index af2fe761a3c..8962aa2731a 100644 --- a/dts/arm/infineon/xmc4700_F144x2048-pinctrl.dtsi +++ b/dts/arm/infineon/xmc4700_F144x2048-pinctrl.dtsi @@ -1008,4 +1008,156 @@ /omit-if-no-ref/ eth_p1_11_mdio: eth_p1_11_mdio { pinmux = ; }; + + /omit-if-no-ref/ eth_p0_4_tx_en: eth_p0_4_tx_en { + pinmux = ; + }; + /omit-if-no-ref/ eth_p0_5_txd0: eth_p0_5_txd0 { + pinmux = ; + }; + /omit-if-no-ref/ eth_p0_6_txd1: eth_p0_6_txd1 { + pinmux = ; + }; + /omit-if-no-ref/ eth_p0_10_mdc: eth_p0_10_mdc { + pinmux = ; + }; + /omit-if-no-ref/ eth_p1_10_mdc: eth_p1_10_mdc { + pinmux = ; + }; + /omit-if-no-ref/ eth_p1_12_tx_en: eth_p1_12_tx_en { + pinmux = ; + }; + /omit-if-no-ref/ eth_p1_13_txd0: eth_p1_13_txd0 { + pinmux = ; + }; + /omit-if-no-ref/ eth_p1_14_txd1: eth_p1_14_txd1 { + pinmux = ; + }; + /omit-if-no-ref/ eth_p2_5_tx_en: eth_p2_5_tx_en { + pinmux = ; + }; + /omit-if-no-ref/ eth_p2_7_mdc: eth_p2_7_mdc { + pinmux = ; + }; + /omit-if-no-ref/ eth_p2_8_txd0: eth_p2_8_txd0 { + pinmux = ; + }; + /omit-if-no-ref/ eth_p2_9_txd1: eth_p2_9_txd1 { + pinmux = ; + }; + /omit-if-no-ref/ eth_p2_11_txer: eth_p2_11_txer { + pinmux = ; + }; + /omit-if-no-ref/ eth_p2_12_txd2: eth_p2_12_txd2 { + pinmux = ; + }; + /omit-if-no-ref/ eth_p2_12_txd0: eth_p2_12_txd0 { + pinmux = ; + }; + /omit-if-no-ref/ eth_p2_13_txd3: eth_p2_13_txd3 { + pinmux = ; + }; + /omit-if-no-ref/ eth_p2_13_txd1: eth_p2_13_txd1 { + pinmux = ; + }; + /omit-if-no-ref/ eth_p5_9_tx_en: eth_p5_9_tx_en { + pinmux = ; + }; + /omit-if-no-ref/ eth_p6_0_txd2: eth_p6_0_txd2 { + pinmux = ; + }; + /omit-if-no-ref/ eth_p6_1_txd3: eth_p6_1_txd3 { + pinmux = ; + }; + /omit-if-no-ref/ eth_p6_2_txer: eth_p6_2_txer { + pinmux = ; + }; + + /omit-if-no-ref/ eth_p2_2_rxd0: eth_p2_2_rxd0 { + pinmux = ; + }; + /omit-if-no-ref/ eth_p0_2_rxd0: eth_p0_2_rxd0 { + pinmux = ; + }; + /omit-if-no-ref/ eth_p14_8_rxd0: eth_p14_8_rxd0 { + pinmux = ; + }; + /omit-if-no-ref/ eth_p5_0_rxd0: eth_p5_0_rxd0 { + pinmux = ; + }; + /omit-if-no-ref/ eth_p2_3_rxd1: eth_p2_3_rxd1 { + pinmux = ; + }; + /omit-if-no-ref/ eth_p0_3_rxd1: eth_p0_3_rxd1 { + pinmux = ; + }; + /omit-if-no-ref/ eth_p14_9_rxd1: eth_p14_9_rxd1 { + pinmux = ; + }; + /omit-if-no-ref/ eth_p5_1_rxd1: eth_p5_1_rxd1 { + pinmux = ; + }; + /omit-if-no-ref/ eth_p5_8_rxd2: eth_p5_8_rxd2 { + pinmux = ; + }; + /omit-if-no-ref/ eth_p6_4_rxd2: eth_p6_4_rxd2 { + pinmux = ; + }; + /omit-if-no-ref/ eth_p5_9_rxd3: eth_p5_9_rxd3 { + pinmux = ; + }; + /omit-if-no-ref/ eth_p6_3_rxd3: eth_p6_3_rxd3 { + pinmux = ; + }; + /omit-if-no-ref/ eth_p2_1_clk_rmii: eth_p2_1_clk_rmii { + pinmux = ; + }; + /omit-if-no-ref/ eth_p0_0_clk_rmii: eth_p0_0_clk_rmii { + pinmux = ; + }; + /omit-if-no-ref/ eth_p15_8_clk_rmii: eth_p15_8_clk_rmii { + pinmux = ; + }; + /omit-if-no-ref/ eth_p6_5_clk_rmii: eth_p6_5_clk_rmii { + pinmux = ; + }; + /omit-if-no-ref/ eth_p2_5_crs_dv: eth_p2_5_crs_dv { + pinmux = ; + }; + /omit-if-no-ref/ eth_p0_1_crs_dv: eth_p0_1_crs_dv { + pinmux = ; + }; + /omit-if-no-ref/ eth_p15_9_crs_dv: eth_p15_9_crs_dv { + pinmux = ; + }; + /omit-if-no-ref/ eth_p5_2_crs_dv: eth_p5_2_crs_dv { + pinmux = ; + }; + /omit-if-no-ref/ eth_p5_11_crs: eth_p5_11_crs { + pinmux = ; + }; + /omit-if-no-ref/ eth_p5_4_crs: eth_p5_4_crs { + pinmux = ; + }; + /omit-if-no-ref/ eth_p2_4_rxer: eth_p2_4_rxer { + pinmux = ; + }; + /omit-if-no-ref/ eth_p0_11_rxer: eth_p0_11_rxer { + pinmux = ; + }; + /omit-if-no-ref/ eth_p5_3_rxer: eth_p5_3_rxer { + pinmux = ; + }; + /omit-if-no-ref/ eth_p2_15_col: eth_p2_15_col { + pinmux = ; + }; + /omit-if-no-ref/ eth_p5_5_col: eth_p5_5_col { + pinmux = ; + }; + /omit-if-no-ref/ eth_p5_10_clk_tx: eth_p5_10_clk_tx { + pinmux = ; + }; + /omit-if-no-ref/ eth_p6_6_clk_tx: eth_p6_6_clk_tx { + pinmux = ; + }; }; diff --git a/dts/arm/infineon/xmc4xxx.dtsi b/dts/arm/infineon/xmc4xxx.dtsi index 7d6831deb63..90049348134 100644 --- a/dts/arm/infineon/xmc4xxx.dtsi +++ b/dts/arm/infineon/xmc4xxx.dtsi @@ -240,6 +240,12 @@ ethernet@5000c000 { reg = <0x5000C000 0x3FFF>; + eth: ethernet { + compatible = "infineon,xmc4xxx-ethernet"; + interrupts = <108 1>; + status = "disabled"; + }; + mdio: mdio { compatible = "infineon,xmc4xxx-mdio"; status = "disabled"; diff --git a/dts/bindings/ethernet/infineon,xmc4xxx-ethernet.yaml b/dts/bindings/ethernet/infineon,xmc4xxx-ethernet.yaml new file mode 100644 index 00000000000..c526fe89055 --- /dev/null +++ b/dts/bindings/ethernet/infineon,xmc4xxx-ethernet.yaml @@ -0,0 +1,118 @@ +# Copyright (c) 2023 SLB +# SPDX-License-Identifier: Apache-2.0 + +description: XMC 4XXX Ethernet + +compatible: "infineon,xmc4xxx-ethernet" + +include: + - name: ethernet-controller.yaml + - name: pinctrl-device.yaml + +properties: + interrupts: + required: true + + pinctrl-0: + required: true + + pinctrl-names: + required: true + + phy-connection-type: + required: true + + rxd0-port-ctrl: + required: true + type: string + description: Receive bit 0 (rxd0) signal GPIO connection. Used for RMII and MII interfaces. + enum: + - "P2_2" + - "P0_2" + - "P14_8" + - "P5_0" + + rxd1-port-ctrl: + required: true + type: string + description: Receive bit 1 (rxd1) signal GPIO connection. Used for RMII and MII interfaces. + enum: + - "P2_3" + - "P0_3" + - "P14_9" + - "P5_1" + + rxd2-port-ctrl: + type: string + description: Receive bit 2 (rxd2) signal GPIO connection. Only used for MII interface. + enum: + - "P5_8" + - "P6_4" + + rxd3-port-ctrl: + type: string + description: Receive bit 2 (rxd2) signal GPIO connection. Only used for MII interface. + enum: + - "P5_9" + - "P6_3" + + rmii-rx-clk-port-ctrl: + required: true + description: | + If the RMII interface is used it connects GPIO to the rmii-clk signal. + Otherwise, if the MII interface is used, then it connects to the Receive clock (rx-clk) + signal. + type: string + enum: + - "P2_1" + - "P0_0" + - "P15_8" + - "P6_5" + + crs-rx-dv-port-ctrl: + required: true + description: | + If the RMII interface is used it connects GPIO to the Carrier Sense Data Valid (crs-dv) + signal. Otherwise, if the MII interface is used, it connects to the + Receive Data Valid (rx-dv) signal. + type: string + enum: + - "P2_5" + - "P0_1" + - "P15_9" + - "P5_2" + + crs-port-ctrl: + description: Carrier Sense (crs) signal GPIO connection. Only used for the MII interface. + type: string + enum: + - "P5_11" + - "unused1" + - "unused2" + - "P5_4" + + rxer-port-ctrl: + required: true + description: Receive Error (rxer) signal GPIO connection. Used for MII and RMII interfaces. + type: string + enum: + - "P2_4" + - "P0_11" + - "unused1" + - "P5_3" + + col-port-ctrl: + description: Collision (col) signal GPIO connection. Only used for MII interface. + type: string + enum: + - "P2_15" + - "unused1" + - "unused2" + - "P5_5" + + tx-clk-port-ctrl: + description: Transmit clock (tx-clk) GPIO connection. Only used for MII interface. + type: string + enum: + - "P5_10" + - "P6_6" From 2391ff77679ed6788127198580679350a3e7cf09 Mon Sep 17 00:00:00 2001 From: Andriy Gelman Date: Tue, 19 Dec 2023 10:12:48 -0500 Subject: [PATCH 1912/3723] boards: xmc45_relax_kit: Add ethernet/mdio to the devicetree Adds ethernet/mdio into to the devicetree. Signed-off-by: Andriy Gelman --- boards/arm/xmc45_relax_kit/Kconfig.defconfig | 11 ++++ boards/arm/xmc45_relax_kit/doc/index.rst | 6 ++ .../xmc45_relax_kit-pinctrl.dtsi | 58 +++++++++++++++++++ .../arm/xmc45_relax_kit/xmc45_relax_kit.dts | 29 ++++++++++ .../arm/xmc45_relax_kit/xmc45_relax_kit.yaml | 1 + samples/net/gptp/boards/xmc45_relax_kit.conf | 2 + 6 files changed, 107 insertions(+) create mode 100644 samples/net/gptp/boards/xmc45_relax_kit.conf diff --git a/boards/arm/xmc45_relax_kit/Kconfig.defconfig b/boards/arm/xmc45_relax_kit/Kconfig.defconfig index e6f0add4859..0296bc64ff7 100644 --- a/boards/arm/xmc45_relax_kit/Kconfig.defconfig +++ b/boards/arm/xmc45_relax_kit/Kconfig.defconfig @@ -8,4 +8,15 @@ if BOARD_XMC45_RELAX_KIT config BOARD default "xmc45_relax_kit" +if NETWORKING + +config NET_L2_ETHERNET + default y +config MDIO + default y +config TEST_RANDOM_GENERATOR + default y + +endif # NETWORKING + endif # BOARD_XMC45_RELAX_KIT diff --git a/boards/arm/xmc45_relax_kit/doc/index.rst b/boards/arm/xmc45_relax_kit/doc/index.rst index 7a54abfe37a..6d75146046e 100644 --- a/boards/arm/xmc45_relax_kit/doc/index.rst +++ b/boards/arm/xmc45_relax_kit/doc/index.rst @@ -57,6 +57,12 @@ The Relax Kit development board configuration supports the following hardware fe +-----------+------------+-----------------------+ | WATCHDOG | on-chip | watchdog | +-----------+------------+-----------------------+ +| MDIO | on-chip | mdio | ++-----------+------------+-----------------------+ +| ETHERNET | on-chip | ethernet | ++-----------+------------+-----------------------+ +| PTP | on-chip | ethernet | ++-----------+------------+-----------------------+ More details about the supported peripherals are available in `XMC4500 TRM`_ Other hardware features are not currently supported by the Zephyr kernel. diff --git a/boards/arm/xmc45_relax_kit/xmc45_relax_kit-pinctrl.dtsi b/boards/arm/xmc45_relax_kit/xmc45_relax_kit-pinctrl.dtsi index 04156e2890c..936733ea02a 100644 --- a/boards/arm/xmc45_relax_kit/xmc45_relax_kit-pinctrl.dtsi +++ b/boards/arm/xmc45_relax_kit/xmc45_relax_kit-pinctrl.dtsi @@ -27,3 +27,61 @@ drive-push-pull; hwctrl = "disabled"; }; + +ð_p2_0_mdo { + drive-strength = "strong-sharp-edge"; + output-low; +}; + +ð_p2_7_mdc { + drive-strength = "strong-medium-edge"; + drive-push-pull; + output-low; + hwctrl = "disabled"; +}; + +ð_p2_5_tx_en { + drive-strength = "strong-medium-edge"; + drive-push-pull; + output-low; + hwctrl = "disabled"; +}; + +ð_p2_8_txd0 { + drive-strength = "strong-medium-edge"; + drive-push-pull; + output-low; + hwctrl = "disabled"; +}; + +ð_p2_9_txd1 { + drive-strength = "strong-medium-edge"; + drive-push-pull; + output-low; + hwctrl = "disabled"; +}; + +ð_p2_4_rxer { + drive-strength = "strong-medium-edge"; + hwctrl = "disabled"; +}; + +ð_p2_2_rxd0{ + drive-strength = "strong-medium-edge"; + hwctrl = "disabled"; +}; + +ð_p2_3_rxd1 { + drive-strength = "strong-medium-edge"; + hwctrl = "disabled"; +}; + +ð_p15_8_clk_rmii { + drive-strength = "strong-medium-edge"; + hwctrl = "disabled"; +}; + +ð_p15_9_crs_dv { + drive-strength = "strong-medium-edge"; + hwctrl = "disabled"; +}; diff --git a/boards/arm/xmc45_relax_kit/xmc45_relax_kit.dts b/boards/arm/xmc45_relax_kit/xmc45_relax_kit.dts index cebeb2deffe..6b1519a4553 100644 --- a/boards/arm/xmc45_relax_kit/xmc45_relax_kit.dts +++ b/boards/arm/xmc45_relax_kit/xmc45_relax_kit.dts @@ -133,3 +133,32 @@ pinctrl-0 = <&pwm_out_p1_0_ccu40_ch3 &pwm_out_p1_1_ccu40_ch2>; pinctrl-names = "default"; }; + +ð { + status = "okay"; + pinctrl-0 = <ð_p2_4_rxer ð_p2_2_rxd0 ð_p2_3_rxd1 + ð_p15_8_clk_rmii ð_p15_9_crs_dv ð_p2_5_tx_en + ð_p2_8_txd0 ð_p2_9_txd1>; + pinctrl-names = "default"; + + rxer-port-ctrl = "P2_4"; + rxd0-port-ctrl = "P2_2"; + rxd1-port-ctrl = "P2_3"; + rmii-rx-clk-port-ctrl = "P15_8"; + crs-rx-dv-port-ctrl = "P15_9"; + + phy-connection-type = "rmii"; + phy-handle = <&phy>; +}; + +&mdio { + status = "okay"; + mdi-port-ctrl = "P2_0"; + pinctrl-0 = <ð_p2_0_mdo ð_p2_7_mdc>; + pinctrl-names = "default"; + + phy: ethernet-phy@0 { + compatible = "ethernet-phy"; + reg = <0>; + }; +}; diff --git a/boards/arm/xmc45_relax_kit/xmc45_relax_kit.yaml b/boards/arm/xmc45_relax_kit/xmc45_relax_kit.yaml index b84e29973a7..031d9dc5a6c 100644 --- a/boards/arm/xmc45_relax_kit/xmc45_relax_kit.yaml +++ b/boards/arm/xmc45_relax_kit/xmc45_relax_kit.yaml @@ -13,6 +13,7 @@ supported: - spi - uart - watchdog + - netif:eth ram: 160 flash: 1024 vendor: infineon diff --git a/samples/net/gptp/boards/xmc45_relax_kit.conf b/samples/net/gptp/boards/xmc45_relax_kit.conf new file mode 100644 index 00000000000..720b511fdb9 --- /dev/null +++ b/samples/net/gptp/boards/xmc45_relax_kit.conf @@ -0,0 +1,2 @@ +CONFIG_NET_TC_TX_COUNT=3 +CONFIG_NET_TC_RX_COUNT=2 From 4c080d4de505781e9b720e27865f73d46061f90a Mon Sep 17 00:00:00 2001 From: Andriy Gelman Date: Tue, 19 Dec 2023 10:15:13 -0500 Subject: [PATCH 1913/3723] boards: xmc47_relax_kit: Add ethernet/mdio to the devicetree Add ethernet/mdio to the devicetree. Signed-off-by: Andriy Gelman --- boards/arm/xmc47_relax_kit/Kconfig.defconfig | 11 ++++ boards/arm/xmc47_relax_kit/doc/index.rst | 6 ++ .../xmc47_relax_kit-pinctrl.dtsi | 58 +++++++++++++++++++ .../arm/xmc47_relax_kit/xmc47_relax_kit.dts | 29 ++++++++++ .../arm/xmc47_relax_kit/xmc47_relax_kit.yaml | 1 + 5 files changed, 105 insertions(+) diff --git a/boards/arm/xmc47_relax_kit/Kconfig.defconfig b/boards/arm/xmc47_relax_kit/Kconfig.defconfig index da18e0230b1..98978ffd540 100644 --- a/boards/arm/xmc47_relax_kit/Kconfig.defconfig +++ b/boards/arm/xmc47_relax_kit/Kconfig.defconfig @@ -7,4 +7,15 @@ if BOARD_XMC47_RELAX_KIT config BOARD default "xmc47_relax_kit" +if NETWORKING + +config NET_L2_ETHERNET + default y +config MDIO + default y +config TEST_RANDOM_GENERATOR + default y + +endif # NETWORKING + endif diff --git a/boards/arm/xmc47_relax_kit/doc/index.rst b/boards/arm/xmc47_relax_kit/doc/index.rst index cbf5eb7a5f3..8fb2ce9997a 100644 --- a/boards/arm/xmc47_relax_kit/doc/index.rst +++ b/boards/arm/xmc47_relax_kit/doc/index.rst @@ -60,6 +60,12 @@ The Relax Kit development board configuration supports the following hardware fe +-----------+------------+-----------------------+ | WATCHDOG | on-chip | watchdog | +-----------+------------+-----------------------+ +| MDIO | on-chip | mdio | ++-----------+------------+-----------------------+ +| ETHERNET | on-chip | ethernet | ++-----------+------------+-----------------------+ +| PTP | on-chip | ethernet | ++-----------+------------+-----------------------+ More details about the supported peripherals are available in `XMC4700 TRM`_ Other hardware features are not currently supported by the Zephyr kernel. diff --git a/boards/arm/xmc47_relax_kit/xmc47_relax_kit-pinctrl.dtsi b/boards/arm/xmc47_relax_kit/xmc47_relax_kit-pinctrl.dtsi index 83d92d7ee51..c81e1222cf8 100644 --- a/boards/arm/xmc47_relax_kit/xmc47_relax_kit-pinctrl.dtsi +++ b/boards/arm/xmc47_relax_kit/xmc47_relax_kit-pinctrl.dtsi @@ -67,3 +67,61 @@ drive-open-drain; hwctrl = "disabled"; }; + +ð_p2_0_mdo { + drive-strength = "strong-sharp-edge"; + output-low; +}; + +ð_p2_7_mdc { + drive-strength = "strong-medium-edge"; + drive-push-pull; + output-low; + hwctrl = "disabled"; +}; + +ð_p2_5_tx_en { + drive-strength = "strong-medium-edge"; + drive-push-pull; + output-low; + hwctrl = "disabled"; +}; + +ð_p2_8_txd0 { + drive-strength = "strong-medium-edge"; + drive-push-pull; + output-low; + hwctrl = "disabled"; +}; + +ð_p2_9_txd1 { + drive-strength = "strong-medium-edge"; + drive-push-pull; + output-low; + hwctrl = "disabled"; +}; + +ð_p2_4_rxer { + drive-strength = "strong-medium-edge"; + hwctrl = "disabled"; +}; + +ð_p2_2_rxd0{ + drive-strength = "strong-medium-edge"; + hwctrl = "disabled"; +}; + +ð_p2_3_rxd1 { + drive-strength = "strong-medium-edge"; + hwctrl = "disabled"; +}; + +ð_p15_8_clk_rmii { + drive-strength = "strong-medium-edge"; + hwctrl = "disabled"; +}; + +ð_p15_9_crs_dv { + drive-strength = "strong-medium-edge"; + hwctrl = "disabled"; +}; diff --git a/boards/arm/xmc47_relax_kit/xmc47_relax_kit.dts b/boards/arm/xmc47_relax_kit/xmc47_relax_kit.dts index 3a8cb700432..a9e0731fa0e 100644 --- a/boards/arm/xmc47_relax_kit/xmc47_relax_kit.dts +++ b/boards/arm/xmc47_relax_kit/xmc47_relax_kit.dts @@ -170,3 +170,32 @@ pinctrl-0 = <&pwm_out_p5_9_ccu80_ch4_high &pwm_out_p5_8_ccu80_ch0_low>; pinctrl-names = "default"; }; + +ð { + status = "okay"; + pinctrl-0 = <ð_p2_4_rxer ð_p2_2_rxd0 ð_p2_3_rxd1 + ð_p15_8_clk_rmii ð_p15_9_crs_dv ð_p2_5_tx_en + ð_p2_8_txd0 ð_p2_9_txd1>; + pinctrl-names = "default"; + + rxer-port-ctrl = "P2_4"; + rxd0-port-ctrl = "P2_2"; + rxd1-port-ctrl = "P2_3"; + rmii-rx-clk-port-ctrl = "P15_8"; + crs-rx-dv-port-ctrl = "P15_9"; + + phy-connection-type = "rmii"; + phy-handle = <&phy>; +}; + +&mdio { + status = "okay"; + mdi-port-ctrl = "P2_0"; + pinctrl-0 = <ð_p2_0_mdo ð_p2_7_mdc>; + pinctrl-names = "default"; + + phy: ethernet-phy@0 { + compatible = "ethernet-phy"; + reg = <0>; + }; +}; diff --git a/boards/arm/xmc47_relax_kit/xmc47_relax_kit.yaml b/boards/arm/xmc47_relax_kit/xmc47_relax_kit.yaml index d88826ab4ef..72fa356ef0c 100644 --- a/boards/arm/xmc47_relax_kit/xmc47_relax_kit.yaml +++ b/boards/arm/xmc47_relax_kit/xmc47_relax_kit.yaml @@ -15,6 +15,7 @@ supported: - arduino_spi - arduino_serial - watchdog + - netif:eth ram: 352 flash: 2048 vendor: infineon From abafe9bbe24c5bb2c377702db1ba3d1d2cd8379a Mon Sep 17 00:00:00 2001 From: Kelly Helmut Lord Date: Thu, 21 Dec 2023 14:00:12 -0500 Subject: [PATCH 1914/3723] drivers: qspi: added operation timeout Added Kconfig assignment of qspi timeout. Per nrfx v3.2 addition of qspi timeout in config struct. Signed-off-by: Kelly Helmut Lord --- drivers/flash/Kconfig.nordic_qspi_nor | 9 +++++++++ drivers/flash/nrf_qspi_nor.c | 1 + 2 files changed, 10 insertions(+) diff --git a/drivers/flash/Kconfig.nordic_qspi_nor b/drivers/flash/Kconfig.nordic_qspi_nor index aac9830835a..ff652f60822 100644 --- a/drivers/flash/Kconfig.nordic_qspi_nor +++ b/drivers/flash/Kconfig.nordic_qspi_nor @@ -50,4 +50,13 @@ config NORDIC_QSPI_NOR_XIP QSPI NOR flash chip is executed until the driver has been setup. This will also disable power management for the QSPI NOR flash chip. +config NORDIC_QSPI_NOR_TIMEOUT_MS + int "Timeout for QSPI operations (ms)" + default 500 + help + The QSPI peripheral operation timeout in milliseconds. + Primarily intended for long running operations such as + a flash sector erase. The 500 ms default allows for + most typical NOR flash chips to erase a sector. + endif # NORDIC_QSPI_NOR diff --git a/drivers/flash/nrf_qspi_nor.c b/drivers/flash/nrf_qspi_nor.c index d6695989857..b9c3af9ca5c 100644 --- a/drivers/flash/nrf_qspi_nor.c +++ b/drivers/flash/nrf_qspi_nor.c @@ -1382,6 +1382,7 @@ static const struct qspi_nor_config qspi_nor_dev_config = { .sck_delay = DT_INST_PROP(0, sck_delay), .spi_mode = INST_0_SPI_MODE, }, + .nrfx_cfg.timeout = CONFIG_NORDIC_QSPI_NOR_TIMEOUT_MS, .size = INST_0_BYTES, .id = DT_INST_PROP(0, jedec_id), From 40215e07a39305125d47f04f6b4a498b71d79c43 Mon Sep 17 00:00:00 2001 From: Jukka Rissanen Date: Fri, 29 Dec 2023 12:05:51 +0200 Subject: [PATCH 1915/3723] net: tcp: Install a last ack timer in passive close If we are in a passive close state, then it is possible that the ack we are waiting is lost or we do not accept the one peer sent to us because of some earlier out of memory issue. So install a timer (using by default the FIN timer value) to close the connection if the last ack is not received on time. Signed-off-by: Jukka Rissanen --- subsys/net/ip/tcp.c | 51 +++++++++++++++++++++++++++++++++++++++++---- 1 file changed, 47 insertions(+), 4 deletions(-) diff --git a/subsys/net/ip/tcp.c b/subsys/net/ip/tcp.c index 23fec86262a..cefb78bc5f7 100644 --- a/subsys/net/ip/tcp.c +++ b/subsys/net/ip/tcp.c @@ -28,6 +28,8 @@ LOG_MODULE_REGISTER(net_tcp, CONFIG_NET_TCP_LOG_LEVEL); #define ACK_TIMEOUT_MS CONFIG_NET_TCP_ACK_TIMEOUT #define ACK_TIMEOUT K_MSEC(ACK_TIMEOUT_MS) +#define LAST_ACK_TIMEOUT_MS tcp_fin_timeout_ms +#define LAST_ACK_TIMEOUT K_MSEC(LAST_ACK_TIMEOUT_MS) #define FIN_TIMEOUT K_MSEC(tcp_fin_timeout_ms) #define ACK_DELAY K_MSEC(100) #define ZWP_MAX_DELAY_MS 120000 @@ -1774,9 +1776,9 @@ static void tcp_resend_data(struct k_work *work) conn->send_data_retries++; if (ret == 0) { if (conn->in_close && conn->send_data_total == 0) { - NET_DBG("TCP connection in active close, " + NET_DBG("TCP connection in %s close, " "not disposing yet (waiting %dms)", - tcp_fin_timeout_ms); + "active", tcp_fin_timeout_ms); k_work_reschedule_for_queue(&tcp_work_q, &conn->fin_timer, FIN_TIMEOUT); @@ -1857,6 +1859,40 @@ static void tcp_fin_timeout(struct k_work *work) (void)tcp_conn_close(conn, -ETIMEDOUT); } +static void tcp_last_ack_timeout(struct k_work *work) +{ + struct k_work_delayable *dwork = k_work_delayable_from_work(work); + struct tcp *conn = CONTAINER_OF(dwork, struct tcp, fin_timer); + + NET_DBG("Did not receive %s in %dms", "last ACK", LAST_ACK_TIMEOUT_MS); + NET_DBG("conn: %p %s", conn, tcp_conn_state(conn, NULL)); + + (void)tcp_conn_close(conn, -ETIMEDOUT); +} + +static void tcp_setup_last_ack_timer(struct tcp *conn) +{ + /* Just in case the last ack is lost, install a timer that will + * close the connection in that case. Use the fin_timer for that + * as the fin handling cannot be done in this passive close state. + * Instead of default tcp_fin_timeout() function, have a separate + * function to catch this last ack case. + */ + k_work_init_delayable(&conn->fin_timer, tcp_last_ack_timeout); + + NET_DBG("TCP connection in %s close, " + "not disposing yet (waiting %dms)", + "passive", LAST_ACK_TIMEOUT_MS); + k_work_reschedule_for_queue(&tcp_work_q, + &conn->fin_timer, + LAST_ACK_TIMEOUT); +} + +static void tcp_cancel_last_ack_timer(struct tcp *conn) +{ + k_work_cancel_delayable(&conn->fin_timer); +} + #if defined(CONFIG_NET_TCP_KEEPALIVE) static void tcp_send_keepalive_probe(struct k_work *work) { @@ -2922,6 +2958,7 @@ static enum net_verdict tcp_in(struct tcp *conn, struct net_pkt *pkt) next = TCP_LAST_ACK; verdict = NET_OK; keep_alive_timer_stop(conn); + tcp_setup_last_ack_timer(conn); break; } else if (th && FL(&fl, ==, FIN, th_seq(th) == conn->ack)) { conn_ack(conn, + 1); @@ -2946,6 +2983,7 @@ static enum net_verdict tcp_in(struct tcp *conn, struct net_pkt *pkt) tcp_out(conn, FIN | ACK); next = TCP_LAST_ACK; keep_alive_timer_stop(conn); + tcp_setup_last_ack_timer(conn); break; } @@ -3126,6 +3164,7 @@ static enum net_verdict tcp_in(struct tcp *conn, struct net_pkt *pkt) case TCP_CLOSE_WAIT: tcp_out(conn, FIN); next = TCP_LAST_ACK; + tcp_setup_last_ack_timer(conn); break; case TCP_LAST_ACK: if (th && FL(&fl, ==, ACK, th_seq(th) == conn->ack)) { @@ -3133,6 +3172,9 @@ static enum net_verdict tcp_in(struct tcp *conn, struct net_pkt *pkt) do_close = true; verdict = NET_OK; close_status = 0; + + /* Remove the last ack timer if we received it in time */ + tcp_cancel_last_ack_timer(conn); } break; case TCP_CLOSED: @@ -3456,8 +3498,9 @@ int net_tcp_put(struct net_context *context) } else { int ret; - NET_DBG("TCP connection in active close, not " - "disposing yet (waiting %dms)", tcp_fin_timeout_ms); + NET_DBG("TCP connection in %s close, " + "not disposing yet (waiting %dms)", + "active", tcp_fin_timeout_ms); k_work_reschedule_for_queue(&tcp_work_q, &conn->fin_timer, FIN_TIMEOUT); From b214207d91951e7a9e06bc84ed6d06f654e2e58d Mon Sep 17 00:00:00 2001 From: Jukka Rissanen Date: Thu, 4 Jan 2024 15:33:10 +0200 Subject: [PATCH 1916/3723] net: tcp: Reschedule FIN timer when entering FIN state The FIN timer was not set when we entered the FIN_WAIT_1 state. This could cause issues if we did not receive proper packets from peer. With this fix, the connection is always terminated even if peer does not respond. Signed-off-by: Robert Lubos Signed-off-by: Jukka Rissanen --- subsys/net/ip/tcp.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/subsys/net/ip/tcp.c b/subsys/net/ip/tcp.c index cefb78bc5f7..c4db136f374 100644 --- a/subsys/net/ip/tcp.c +++ b/subsys/net/ip/tcp.c @@ -3090,6 +3090,10 @@ static enum net_verdict tcp_in(struct tcp *conn, struct net_pkt *pkt) tcp_send_timer_cancel(conn); next = TCP_FIN_WAIT_1; + k_work_reschedule_for_queue(&tcp_work_q, + &conn->fin_timer, + FIN_TIMEOUT); + tcp_out(conn, FIN | ACK); conn_seq(conn, + 1); verdict = NET_OK; From 9b11fbd54cc3a7e6a340c36367c0cc06227f0869 Mon Sep 17 00:00:00 2001 From: Jukka Rissanen Date: Tue, 2 Jan 2024 11:37:13 +0200 Subject: [PATCH 1917/3723] tests: net: tcp: Verify termination at closing state Make sure the connection is closed by the timer if the final ack is lost in closing state. Signed-off-by: Jukka Rissanen --- tests/net/tcp/src/main.c | 133 +++++++++++++++++++++++++++++++++++++++ 1 file changed, 133 insertions(+) diff --git a/tests/net/tcp/src/main.c b/tests/net/tcp/src/main.c index e935cb4d40e..8fe3f2d5245 100644 --- a/tests/net/tcp/src/main.c +++ b/tests/net/tcp/src/main.c @@ -128,6 +128,7 @@ static void handle_syn_resend(void); static void handle_syn_rst_ack(sa_family_t af, struct tcphdr *th); static void handle_client_fin_wait_2_test(sa_family_t af, struct tcphdr *th); static void handle_client_closing_test(sa_family_t af, struct tcphdr *th); +static void handle_client_closing_failure_test(sa_family_t af, struct tcphdr *th); static void handle_data_fin1_test(sa_family_t af, struct tcphdr *th); static void handle_data_during_fin1_test(sa_family_t af, struct tcphdr *th); static void handle_server_recv_out_of_order(struct net_pkt *pkt); @@ -215,6 +216,15 @@ static void test_sem_take(k_timeout_t timeout, int line) } } +static void test_sem_take_failure(k_timeout_t timeout, int line) +{ + sem = true; + + if (k_sem_take(&test_sem, timeout) == 0) { + zassert_true(false, "semaphore succeed out (line %d)", line); + } +} + static uint8_t tcp_options[20] = { 0x02, 0x04, 0x05, 0xb4, /* Max segment */ 0x04, 0x02, /* SACK */ @@ -468,6 +478,9 @@ static int tester_send(const struct device *dev, struct net_pkt *pkt) case 15: handle_syn_invalid_ack(net_pkt_family(pkt), &th); break; + case 16: + handle_client_closing_failure_test(net_pkt_family(pkt), &th); + break; default: zassert_true(false, "Undefined test case"); @@ -1614,6 +1627,126 @@ ZTEST(net_tcp, test_client_closing_ipv6) k_sleep(K_MSEC(CONFIG_NET_TCP_TIME_WAIT_DELAY)); } +/* In this test we check that things work properly if we do not receive + * the final ACK that leads to TIME_WAIT state. + */ +static void handle_client_closing_failure_test(sa_family_t af, struct tcphdr *th) +{ + struct net_pkt *reply; + int ret; + + switch (t_state) { + case T_SYN: + test_verify_flags(th, SYN); + seq = 0U; + ack = ntohl(th->th_seq) + 1U; + reply = prepare_syn_ack_packet(af, htons(MY_PORT), + th->th_sport); + t_state = T_SYN_ACK; + break; + case T_SYN_ACK: + test_verify_flags(th, ACK); + /* connection is success */ + t_state = T_DATA; + test_sem_give(); + return; + case T_DATA: + test_verify_flags(th, PSH | ACK); + seq++; + ack = ack + 1U; + reply = prepare_ack_packet(af, htons(MY_PORT), th->th_sport); + t_state = T_FIN; + test_sem_give(); + break; + case T_FIN: + test_verify_flags(th, FIN | ACK); + t_state = T_FIN_1; + reply = prepare_fin_packet(af, htons(MY_PORT), th->th_sport); + break; + case T_FIN_1: + test_verify_flags(th, FIN | ACK); + t_state = T_CLOSING; + reply = prepare_fin_packet(af, htons(MY_PORT), th->th_sport); + break; + case T_CLOSING: + test_verify_flags(th, FIN | ACK); + /* Simulate the case where we do not receive final ACK */ + reply = NULL; + break; + default: + zassert_true(false, "%s unexpected state", __func__); + return; + } + + if (reply != NULL) { + ret = net_recv_data(net_iface, reply); + if (ret < 0) { + goto fail; + } + } + + return; +fail: + zassert_true(false, "%s failed", __func__); +} + +/* Test case scenario IPv6 + * send SYN, + * expect SYN ACK, + * send ACK, + * send Data, + * expect ACK, + * send FIN, + * expect FIN, + * send ACK, + * expect ACK but fail to receive it + * any failures cause test case to fail. + */ +ZTEST(net_tcp, test_client_closing_failure_ipv6) +{ + struct net_context *ctx; + uint8_t data = 0x41; /* "A" */ + int ret; + + t_state = T_SYN; + test_case_no = 16; + seq = ack = 0; + + ret = net_context_get(AF_INET6, SOCK_STREAM, IPPROTO_TCP, &ctx); + if (ret < 0) { + zassert_true(false, "Failed to get net_context"); + } + + net_context_ref(ctx); + + ret = net_context_connect(ctx, (struct sockaddr *)&peer_addr_v6_s, + sizeof(struct sockaddr_in6), + NULL, + K_MSEC(100), NULL); + if (ret < 0) { + zassert_true(false, "Failed to connect to peer"); + } + + /* Peer will release the semaphore after it receives + * proper ACK to SYN | ACK + */ + test_sem_take(K_MSEC(100), __LINE__); + + ret = net_context_send(ctx, &data, 1, NULL, K_NO_WAIT, NULL); + if (ret < 0) { + zassert_true(false, "Failed to send data to peer"); + } + + /* Peer will release the semaphore after it sends ACK for data */ + test_sem_take(K_MSEC(100), __LINE__); + + net_context_put(ctx); + + /* The lock is not released as we do not receive final ACK. + */ + test_sem_take_failure(K_MSEC(400), __LINE__); +} + static struct net_context *create_server_socket(uint32_t my_seq, uint32_t my_ack) { From 35e1df6bb4e2a438714f1d0a9f1116df94927859 Mon Sep 17 00:00:00 2001 From: Jukka Rissanen Date: Tue, 2 Jan 2024 17:46:30 +0200 Subject: [PATCH 1918/3723] tests: net: tcp: Add support for close callback Add a function callback that is called when the TCP connection is closed. This is only available if doing network tests. Signed-off-by: Jukka Rissanen --- subsys/net/ip/tcp.c | 18 ++++++++++++++++++ subsys/net/ip/tcp_private.h | 13 +++++++++++++ 2 files changed, 31 insertions(+) diff --git a/subsys/net/ip/tcp.c b/subsys/net/ip/tcp.c index c4db136f374..41df924607c 100644 --- a/subsys/net/ip/tcp.c +++ b/subsys/net/ip/tcp.c @@ -714,6 +714,12 @@ static void tcp_conn_release(struct k_work *work) struct tcp *conn = CONTAINER_OF(work, struct tcp, conn_release); struct net_pkt *pkt; +#if defined(CONFIG_NET_TEST) + if (conn->test_closed_cb != NULL) { + conn->test_closed_cb(conn, conn->test_user_data); + } +#endif + k_mutex_lock(&tcp_lock, K_FOREVER); /* Application is no longer there, unref any remaining packets on the @@ -762,6 +768,18 @@ static void tcp_conn_release(struct k_work *work) k_mutex_unlock(&tcp_lock); } +#if defined(CONFIG_NET_TEST) +void tcp_install_close_cb(struct net_context *ctx, + net_tcp_closed_cb_t cb, + void *user_data) +{ + NET_ASSERT(ctx->tcp != NULL); + + ((struct tcp *)ctx->tcp)->test_closed_cb = cb; + ((struct tcp *)ctx->tcp)->test_user_data = user_data; +} +#endif + static int tcp_conn_unref(struct tcp *conn) { int ref_count = atomic_get(&conn->ref_count); diff --git a/subsys/net/ip/tcp_private.h b/subsys/net/ip/tcp_private.h index 5d5d78d916b..1f2eee24989 100644 --- a/subsys/net/ip/tcp_private.h +++ b/subsys/net/ip/tcp_private.h @@ -250,6 +250,9 @@ struct tcp_collision_avoidance_reno { }; #endif +struct tcp; +typedef void (*net_tcp_closed_cb_t)(struct tcp *conn, void *user_data); + struct tcp { /* TCP connection */ sys_snode_t next; struct net_context *context; @@ -263,6 +266,10 @@ struct tcp { /* TCP connection */ struct tcp *accepted_conn; }; net_context_connect_cb_t connect_cb; +#if defined(CONFIG_NET_TEST) + net_tcp_closed_cb_t test_closed_cb; + void *test_user_data; +#endif struct k_mutex lock; struct k_sem connect_sem; /* semaphore for blocking connect */ struct k_sem tx_sem; /* Semaphore indicating if transfers are blocked . */ @@ -345,3 +352,9 @@ struct tcp { /* TCP connection */ _flags(_fl, _op, _mask, sizeof(#_args) > 1 ? _args : true) typedef void (*net_tcp_cb_t)(struct tcp *conn, void *user_data); + +#if defined(CONFIG_NET_TEST) +void tcp_install_close_cb(struct net_context *ctx, + net_tcp_closed_cb_t cb, + void *user_data); +#endif From d94914d3157a1beea83a5fe97ff41c08a8482f48 Mon Sep 17 00:00:00 2001 From: Jukka Rissanen Date: Tue, 2 Jan 2024 17:47:54 +0200 Subject: [PATCH 1919/3723] tests: net: tcp: Shorten the test execution Make the retransmission timer much shorter so that the test is run faster (about 50% faster test run in qemu_x86). Signed-off-by: Jukka Rissanen --- tests/net/tcp/prj.conf | 1 + 1 file changed, 1 insertion(+) diff --git a/tests/net/tcp/prj.conf b/tests/net/tcp/prj.conf index 86f972f043d..2e67a55dd1b 100644 --- a/tests/net/tcp/prj.conf +++ b/tests/net/tcp/prj.conf @@ -29,6 +29,7 @@ CONFIG_NET_IF_UNICAST_IPV4_ADDR_COUNT=3 CONFIG_NET_TCP_CHECKSUM=n CONFIG_NET_TCP_RANDOMIZED_RTO=n CONFIG_NET_TCP_INIT_RETRANSMISSION_TIMEOUT=100 +CONFIG_NET_TCP_RETRY_COUNT=2 CONFIG_NET_IPV6_ND=n CONFIG_NET_IPV6_DAD=n From 59a7915d11a30003587e1ef60bb672713fd277fe Mon Sep 17 00:00:00 2001 From: Jukka Rissanen Date: Tue, 2 Jan 2024 17:51:35 +0200 Subject: [PATCH 1920/3723] tests: net: tcp: Add tests for last FIN handling Make sure the connection is closed by the timer if the final fin is lost. Signed-off-by: Jukka Rissanen --- tests/net/tcp/src/main.c | 145 +++++++++++++++++++++++++++++++++++++++ 1 file changed, 145 insertions(+) diff --git a/tests/net/tcp/src/main.c b/tests/net/tcp/src/main.c index 8fe3f2d5245..547fd4fc133 100644 --- a/tests/net/tcp/src/main.c +++ b/tests/net/tcp/src/main.c @@ -127,6 +127,7 @@ static void handle_server_test(sa_family_t af, struct tcphdr *th); static void handle_syn_resend(void); static void handle_syn_rst_ack(sa_family_t af, struct tcphdr *th); static void handle_client_fin_wait_2_test(sa_family_t af, struct tcphdr *th); +static void handle_client_fin_wait_2_failure_test(sa_family_t af, struct tcphdr *th); static void handle_client_closing_test(sa_family_t af, struct tcphdr *th); static void handle_client_closing_failure_test(sa_family_t af, struct tcphdr *th); static void handle_data_fin1_test(sa_family_t af, struct tcphdr *th); @@ -481,6 +482,9 @@ static int tester_send(const struct device *dev, struct net_pkt *pkt) case 16: handle_client_closing_failure_test(net_pkt_family(pkt), &th); break; + case 17: + handle_client_fin_wait_2_failure_test(net_pkt_family(pkt), &th); + break; default: zassert_true(false, "Undefined test case"); @@ -1243,6 +1247,147 @@ ZTEST(net_tcp, test_client_fin_wait_2_ipv4) k_sleep(K_MSEC(CONFIG_NET_TCP_TIME_WAIT_DELAY)); } +static void handle_client_fin_wait_2_failure_test(sa_family_t af, struct tcphdr *th) +{ + struct net_pkt *reply; + int ret; + +send_next: + switch (t_state) { + case T_SYN: + test_verify_flags(th, SYN); + seq = 0U; + ack = ntohl(th->th_seq) + 1U; + reply = prepare_syn_ack_packet(af, htons(MY_PORT), + th->th_sport); + t_state = T_SYN_ACK; + break; + case T_SYN_ACK: + test_verify_flags(th, ACK); + /* connection is success */ + t_state = T_DATA; + test_sem_give(); + return; + case T_DATA: + test_verify_flags(th, PSH | ACK); + seq++; + ack = ack + 1U; + reply = prepare_ack_packet(af, htons(MY_PORT), th->th_sport); + t_state = T_FIN; + test_sem_give(); + break; + case T_FIN: + test_verify_flags(th, FIN | ACK); + ack = ack + 1U; + t_state = T_FIN_2; + reply = prepare_ack_packet(af, htons(MY_PORT), th->th_sport); + break; + case T_FIN_2: + t_state = T_FIN_ACK; + /* We do not send last FIN that would move the state to TIME_WAIT. + * Make sure that the stack can recover from this by closing the + * connection. + */ + reply = NULL; + break; + case T_FIN_ACK: + reply = NULL; + return; + default: + zassert_true(false, "%s unexpected state", __func__); + return; + } + + if (reply != NULL) { + ret = net_recv_data(net_iface, reply); + if (ret < 0) { + goto fail; + } + } + + if (t_state == T_FIN_2) { + goto send_next; + } + + return; +fail: + zassert_true(false, "%s failed", __func__); +} + +static bool closed; +static K_SEM_DEFINE(wait_data, 0, 1); + +static void connection_closed(struct tcp *conn, void *user_data) +{ + struct k_sem *my_sem = user_data; + + k_sem_give(my_sem); + closed = true; +} + +/* Test case scenario IPv4 + * send SYN, + * expect SYN ACK, + * send ACK, + * send Data, + * expect ACK, + * send FIN, + * expect ACK, + * expect FIN, + * send ACK, + * any failures cause test case to fail. + */ +ZTEST(net_tcp, test_client_fin_wait_2_ipv4_failure) +{ + struct net_context *ctx; + uint8_t data = 0x41; /* "A" */ + int ret; + + t_state = T_SYN; + test_case_no = 17; + seq = ack = 0; + closed = false; + + ret = net_context_get(AF_INET, SOCK_STREAM, IPPROTO_TCP, &ctx); + if (ret < 0) { + zassert_true(false, "Failed to get net_context"); + } + + net_context_ref(ctx); + + ret = net_context_connect(ctx, (struct sockaddr *)&peer_addr_s, + sizeof(struct sockaddr_in), + NULL, + K_MSEC(100), NULL); + if (ret < 0) { + zassert_true(false, "Failed to connect to peer"); + } + + /* Peer will release the semaphore after it receives + * proper ACK to SYN | ACK + */ + test_sem_take(K_MSEC(100), __LINE__); + + ret = net_context_send(ctx, &data, 1, NULL, K_NO_WAIT, NULL); + if (ret < 0) { + zassert_true(false, "Failed to send data to peer"); + } + + /* Peer will release the semaphore after it sends ACK for data */ + test_sem_take(K_MSEC(100), __LINE__); + + k_sem_reset(&wait_data); + k_sem_take(&wait_data, K_NO_WAIT); + + tcp_install_close_cb(ctx, connection_closed, &wait_data); + + net_context_put(ctx); + + /* The lock is released after we have closed the connection. */ + k_sem_take(&wait_data, K_MSEC(10000)); + zassert_equal(closed, true, "Connection was not closed!"); +} + static uint32_t get_rel_seq(struct tcphdr *th) { return ntohl(th->th_seq) - device_initial_seq; From cef8da0ecf06c689f266e5543a0ba2b3ff8eec4a Mon Sep 17 00:00:00 2001 From: Jukka Rissanen Date: Thu, 4 Jan 2024 17:34:23 +0200 Subject: [PATCH 1921/3723] samples: net: dumb_http_server_mt: Sleep after accept error If accept() returns an error, it typically means that the system is running out of resources. In this case sleep some time in order the system to cool down a bit. Signed-off-by: Jukka Rissanen --- samples/net/sockets/dumb_http_server_mt/src/main.c | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) diff --git a/samples/net/sockets/dumb_http_server_mt/src/main.c b/samples/net/sockets/dumb_http_server_mt/src/main.c index baa295b7f50..06f9f0c6e71 100644 --- a/samples/net/sockets/dumb_http_server_mt/src/main.c +++ b/samples/net/sockets/dumb_http_server_mt/src/main.c @@ -20,6 +20,12 @@ LOG_MODULE_REGISTER(net_dumb_http_srv_mt_sample); #define MY_PORT 8080 +/* If accept returns an error, then we are probably running + * out of resource. Sleep a small amount of time in order the + * system to cool down. + */ +#define ACCEPT_ERROR_WAIT 100 /* in ms */ + #if defined(CONFIG_NET_SOCKETS_SOCKOPT_TLS) #define STACK_SIZE 4096 @@ -268,8 +274,9 @@ static int process_tcp(int *sock, int *accepted) client = accept(*sock, (struct sockaddr *)&client_addr, &client_addr_len); if (client < 0) { - LOG_ERR("Error in accept %d, stopping server", -errno); - return -errno; + LOG_DBG("Error in accept %d, ignored", -errno); + k_msleep(ACCEPT_ERROR_WAIT); + return 0; } slot = get_free_slot(accepted); From b18442bc0da6db6c86113be6f015a10450c9d1a7 Mon Sep 17 00:00:00 2001 From: Jukka Rissanen Date: Thu, 4 Jan 2024 17:33:05 +0200 Subject: [PATCH 1922/3723] samples: net: dumb_http_server: Sleep after accept error If accept() returns an error, it typically means that the system is running out of resources. In this case sleep some time in order the system to cool down a bit. Signed-off-by: Jukka Rissanen --- .../dumb_http_server/src/socket_dumb_http.c | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/samples/net/sockets/dumb_http_server/src/socket_dumb_http.c b/samples/net/sockets/dumb_http_server/src/socket_dumb_http.c index 76b94934df8..d9194ca0dd2 100644 --- a/samples/net/sockets/dumb_http_server/src/socket_dumb_http.c +++ b/samples/net/sockets/dumb_http_server/src/socket_dumb_http.c @@ -40,6 +40,21 @@ static const char content[] = { #endif }; +/* If accept returns an error, then we are probably running + * out of resource. Sleep a small amount of time in order the + * system to cool down. + */ +#define ACCEPT_ERROR_WAIT 100 /* in ms */ + +static void sleep_after_error(unsigned int amount) +{ +#if defined(__ZEPHYR__) + k_msleep(amount); +#else + usleep(amount * 1000U); +#endif +} + int main(void) { int serv; @@ -72,6 +87,7 @@ int main(void) &client_addr_len); if (client < 0) { printf("Error in accept: %d - continuing\n", errno); + sleep_after_error(ACCEPT_ERROR_WAIT); continue; } From 1e72643b61edae12109a06f258f633cd8b6a1d9c Mon Sep 17 00:00:00 2001 From: Jamie McCrae Date: Fri, 5 Jan 2024 09:28:52 +0000 Subject: [PATCH 1923/3723] cmake: modules: shields: Process shields in order Changes shield processing order from being on a root-by-root basis to being order they were supplied to cmake Signed-off-by: Jamie McCrae --- cmake/modules/shields.cmake | 66 ++++++++++++++++++++++--------------- 1 file changed, 39 insertions(+), 27 deletions(-) diff --git a/cmake/modules/shields.cmake b/cmake/modules/shields.cmake index 77abc4d603b..ec172512b68 100644 --- a/cmake/modules/shields.cmake +++ b/cmake/modules/shields.cmake @@ -79,41 +79,53 @@ foreach(root ${BOARD_ROOT}) list(REMOVE_ITEM SHIELD-NOTFOUND ${s}) - # Add .overlay to the shield_dts_files output variable. - list(APPEND - shield_dts_files - ${SHIELD_DIR_${s}}/${s}.overlay - ) - - # Add the shield's directory to the SHIELD_DIRS output variable. - list(APPEND - SHIELD_DIRS - ${SHIELD_DIR_${s}} - ) + # Add .overlay to a temporary variable + set(shield_${s}_dts_file ${SHIELD_DIR_${s}}/${s}.overlay) # Search for shield/shield.conf file if(EXISTS ${SHIELD_DIR_${s}}/${s}.conf) - # Add .conf to the shield_conf_files output variable. - list(APPEND - shield_conf_files - ${SHIELD_DIR_${s}}/${s}.conf - ) + # Add .conf to a temporary variable + set(shield_${s}_conf_file ${SHIELD_DIR_${s}}/${s}.conf) endif() - - # Add board-specific .conf and .overlay files to their - # respective output variables. - zephyr_file(CONF_FILES ${SHIELD_DIR_${s}}/boards - DTS shield_dts_files - KCONF shield_conf_files - ) - zephyr_file(CONF_FILES ${SHIELD_DIR_${s}}/boards/${s} - DTS shield_dts_files - KCONF shield_conf_files - ) endforeach() endif() endforeach() +# Process shields in-order +if(DEFINED SHIELD) + foreach(s ${SHIELD_AS_LIST}) + # Add .overlay to the shield_dts_files output variable. + list(APPEND + shield_dts_files + ${shield_${s}_dts_file} + ) + + # Add the shield's directory to the SHIELD_DIRS output variable. + list(APPEND + SHIELD_DIRS + ${SHIELD_DIR_${s}} + ) + + if(DEFINED shield_${s}_conf_file) + list(APPEND + shield_conf_files + ${shield_${s}_conf_file} + ) + endif() + + # Add board-specific .conf and .overlay files to their + # respective output variables. + zephyr_file(CONF_FILES ${SHIELD_DIR_${s}}/boards + DTS shield_dts_files + KCONF shield_conf_files + ) + zephyr_file(CONF_FILES ${SHIELD_DIR_${s}}/boards/${s} + DTS shield_dts_files + KCONF shield_conf_files + ) + endforeach() +endif() + # Prepare shield usage command printing. # This command prints all shields in the system in the following cases: # - User specifies an invalid SHIELD From bde23945fe7cc991c985951ee85706a97c13892b Mon Sep 17 00:00:00 2001 From: Jamie McCrae Date: Fri, 5 Jan 2024 09:30:30 +0000 Subject: [PATCH 1924/3723] doc: release: 3.6: Add note on shield processing change Adds a note that shields are now processed in order Signed-off-by: Jamie McCrae --- doc/releases/release-notes-3.6.rst | 3 +++ 1 file changed, 3 insertions(+) diff --git a/doc/releases/release-notes-3.6.rst b/doc/releases/release-notes-3.6.rst index e191ab73ffa..4a3a0e3eb91 100644 --- a/doc/releases/release-notes-3.6.rst +++ b/doc/releases/release-notes-3.6.rst @@ -141,6 +141,9 @@ Build system and infrastructure * Deprecated :kconfig:option:`CONFIG_BOOTLOADER_SRAM_SIZE`, users of this should transition to having RAM set up properly in their board devicetree files. +* Fixed an issue whereby shields were processed in order of the root they resided in rather than + the order they were supplied to cmake in. + Drivers and Sensors ******************* From a2ad1b64a72201fc50e0b4af0e126b21d8a2bd3c Mon Sep 17 00:00:00 2001 From: Alberto Escolar Piedras Date: Sun, 7 Jan 2024 10:14:26 +0100 Subject: [PATCH 1925/3723] docs boards native_sim: Capitalize consistently peripherals table Capitalize all acronyms and the begining of each entry consistently Signed-off-by: Alberto Escolar Piedras --- boards/posix/native_sim/doc/index.rst | 48 +++++++++++++-------------- 1 file changed, 24 insertions(+), 24 deletions(-) diff --git a/boards/posix/native_sim/doc/index.rst b/boards/posix/native_sim/doc/index.rst index be419705643..1ee897f3579 100644 --- a/boards/posix/native_sim/doc/index.rst +++ b/boards/posix/native_sim/doc/index.rst @@ -654,27 +654,27 @@ host libC (:kconfig:option:`CONFIG_EXTERNAL_LIBC`): .. csv-table:: Drivers/backends vs libC choice :header: Driver class, driver name, driver kconfig, libC choices - adc, ADC emul, :kconfig:option:`CONFIG_ADC_EMUL`, all - bluetooth, :ref:`userchan `, :kconfig:option:`CONFIG_BT_USERCHAN`, host libC - can, can native Linux, :kconfig:option:`CONFIG_CAN_NATIVE_LINUX`, all - console backend, :ref:`POSIX arch console `, :kconfig:option:`CONFIG_POSIX_ARCH_CONSOLE`, all - display, :ref:`display SDL `, :kconfig:option:`CONFIG_SDL_DISPLAY`, all - entropy, :ref:`native posix entropy `, :kconfig:option:`CONFIG_FAKE_ENTROPY_NATIVE_POSIX`, all - eeprom, eeprom simulator, :kconfig:option:`CONFIG_EEPROM_SIMULATOR`, host libC - eeprom, eeprom emulator, :kconfig:option:`CONFIG_EEPROM_EMULATOR`, all - ethernet, :ref:`eth native_posix `, :kconfig:option:`CONFIG_ETH_NATIVE_POSIX`, all - flash, :ref:`flash simulator `, :kconfig:option:`CONFIG_FLASH_SIMULATOR`, all - flash, :ref:`host based flash access `, :kconfig:option:`CONFIG_FUSE_FS_ACCESS`, host libC - gpio, GPIO emulator, :kconfig:option:`CONFIG_GPIO_EMUL`, all - gpio, SDL GPIO emulator, :kconfig:option:`CONFIG_GPIO_EMUL_SDL`, all - i2c, I2C emulator, :kconfig:option:`CONFIG_I2C_EMUL`, all - input, input SDL touch, :kconfig:option:`CONFIG_INPUT_SDL_TOUCH`, all - input, Linux evdev, :kconfig:option:`CONFIG_NATIVE_LINUX_EVDEV`, all - log backend, :ref:`native backend `, :kconfig:option:`CONFIG_LOG_BACKEND_NATIVE_POSIX`, all - rtc, RTC emul, :kconfig:option:`CONFIG_RTC_EMUL`, all - serial, :ref:`uart native posix/PTTY `, :kconfig:option:`CONFIG_UART_NATIVE_POSIX`, all - serial, :ref:`uart native TTY `, :kconfig:option:`CONFIG_UART_NATIVE_TTY`, all - spi, SPI emul, :kconfig:option:`CONFIG_SPI_EMUL`, all - system tick, native_posix timer, :kconfig:option:`CONFIG_NATIVE_POSIX_TIMER`, all - tracing, :ref:`Posix tracing backend `, :kconfig:option:`CONFIG_TRACING_BACKEND_POSIX`, all - usb, :ref:`USB native posix `, :kconfig:option:`CONFIG_USB_NATIVE_POSIX`, host libC + ADC, ADC emul, :kconfig:option:`CONFIG_ADC_EMUL`, All + Bluetooth, :ref:`Userchan `, :kconfig:option:`CONFIG_BT_USERCHAN`, Host libC + CAN, CAN native Linux, :kconfig:option:`CONFIG_CAN_NATIVE_LINUX`, All + Console backend, :ref:`POSIX arch console `, :kconfig:option:`CONFIG_POSIX_ARCH_CONSOLE`, All + Display, :ref:`Display SDL `, :kconfig:option:`CONFIG_SDL_DISPLAY`, All + Entropy, :ref:`Native posix entropy `, :kconfig:option:`CONFIG_FAKE_ENTROPY_NATIVE_POSIX`, All + EEPROM, EEPROM simulator, :kconfig:option:`CONFIG_EEPROM_SIMULATOR`, Host libC + EEPROM, EEPROM emulator, :kconfig:option:`CONFIG_EEPROM_EMULATOR`, All + Ethernet, :ref:`Eth native_posix `, :kconfig:option:`CONFIG_ETH_NATIVE_POSIX`, All + Flash, :ref:`Flash simulator `, :kconfig:option:`CONFIG_FLASH_SIMULATOR`, All + Flash, :ref:`Host based flash access `, :kconfig:option:`CONFIG_FUSE_FS_ACCESS`, Host libC + GPIO, GPIO emulator, :kconfig:option:`CONFIG_GPIO_EMUL`, All + GPIO, SDL GPIO emulator, :kconfig:option:`CONFIG_GPIO_EMUL_SDL`, All + I2C, I2C emulator, :kconfig:option:`CONFIG_I2C_EMUL`, All + Input, Input SDL touch, :kconfig:option:`CONFIG_INPUT_SDL_TOUCH`, All + Input, Linux evdev, :kconfig:option:`CONFIG_NATIVE_LINUX_EVDEV`, All + Logger backend, :ref:`Native backend `, :kconfig:option:`CONFIG_LOG_BACKEND_NATIVE_POSIX`, All + RTC, RTC emul, :kconfig:option:`CONFIG_RTC_EMUL`, All + Serial, :ref:`UART native posix/PTTY `, :kconfig:option:`CONFIG_UART_NATIVE_POSIX`, All + Serial, :ref:`UART native TTY `, :kconfig:option:`CONFIG_UART_NATIVE_TTY`, All + SPI, SPI emul, :kconfig:option:`CONFIG_SPI_EMUL`, All + System tick, Native_posix timer, :kconfig:option:`CONFIG_NATIVE_POSIX_TIMER`, All + Tracing, :ref:`Posix tracing backend `, :kconfig:option:`CONFIG_TRACING_BACKEND_POSIX`, All + USB, :ref:`USB native posix `, :kconfig:option:`CONFIG_USB_NATIVE_POSIX`, Host libC From b89399ff409147080345c60cd82e2f7ca011b629 Mon Sep 17 00:00:00 2001 From: Alberto Escolar Piedras Date: Sun, 7 Jan 2024 10:22:06 +0100 Subject: [PATCH 1926/3723] docs boards native_sim: Add mention about the EEPROM simu Add a small paragraph about the EEPROM simulator, and improve slightly the flash simulator section Signed-off-by: Alberto Escolar Piedras --- boards/posix/native_sim/doc/index.rst | 17 +++++++++++++---- doc/hardware/emulator/index.rst | 4 ++++ 2 files changed, 17 insertions(+), 4 deletions(-) diff --git a/boards/posix/native_sim/doc/index.rst b/boards/posix/native_sim/doc/index.rst index 1ee897f3579..b8f6a305bd4 100644 --- a/boards/posix/native_sim/doc/index.rst +++ b/boards/posix/native_sim/doc/index.rst @@ -433,10 +433,17 @@ The following peripherals are currently provided with this board: .. _nsim_per_flash_simu: -**Flash driver** - A flash driver is provided that accesses all flash data through a binary file - on the host file system. The behavior of the flash device can be configured - through the native_sim board devicetree or Kconfig settings under +**EEPROM simulator** + The EEPROM simulator can also be used in the native targets. In these, you have the added feature + of keeping the EEPROM content on a file on the host filesystem. + By default this is kept in the file :file:`eeprom.bin` in the current working directory, but you + can select the location of this file and its name with the command line parameter ``--eeprom``. + Some more information can be found in :ref:`the emulators page `. + +**Flash simulator** + The flash simulator can also be used in the native targets. In this you have the option to keep + the flash content in a binary file on the host file system or in RAM. The behavior of the flash + device can be configured through the native_sim board devicetree or Kconfig settings under :kconfig:option:`CONFIG_FLASH_SIMULATOR`. By default the binary data is located in the file :file:`flash.bin` in the current @@ -446,6 +453,8 @@ The following peripherals are currently provided with this board: configuration. In case the file does not exists the driver will take care of creating the file, else the existing file is used. + Some more information can be found in :ref:`the emulators page `. + The flash content can be accessed from the host system, as explained in the `Host based flash access`_ section. diff --git a/doc/hardware/emulator/index.rst b/doc/hardware/emulator/index.rst index 0b3a809e4dd..0369876783a 100644 --- a/doc/hardware/emulator/index.rst +++ b/doc/hardware/emulator/index.rst @@ -47,6 +47,8 @@ Available Emulators * Main Kconfig option: :kconfig:option:`CONFIG_EEPROM_EMULATOR` * DT binding: :dtcompatible:`zephyr,emu-eeprom` +.. _emul_eeprom_simu_brief: + **EEPROM simulator** * Emulate an EEPROM on RAM * Main Kconfig option: :kconfig:option:`CONFIG_EEPROM_SIMULATOR` @@ -58,6 +60,8 @@ Available Emulators * :ref:`Documentation ` * Allow emulating external buses like I2C or SPI and peripherals connected to them. +.. _emul_flash_simu_brief: + **Flash simulator** * Emulate a flash on RAM * Main Kconfig option: :kconfig:option:`CONFIG_FLASH_SIMULATOR` From 893b59b4aab6d16b68d612dbc7023efad5e87cbe Mon Sep 17 00:00:00 2001 From: Alberto Escolar Piedras Date: Sun, 7 Jan 2024 11:04:08 +0100 Subject: [PATCH 1927/3723] docs boards native_sim: Mention the input SDL touch driver Add a small paragraph about the input SDL touch driver, clarifying the evdev driver is not the only input one. Signed-off-by: Alberto Escolar Piedras --- boards/posix/native_sim/doc/index.rst | 33 ++++++++++++++++++--------- 1 file changed, 22 insertions(+), 11 deletions(-) diff --git a/boards/posix/native_sim/doc/index.rst b/boards/posix/native_sim/doc/index.rst index b8f6a305bd4..7f422e791fa 100644 --- a/boards/posix/native_sim/doc/index.rst +++ b/boards/posix/native_sim/doc/index.rst @@ -459,21 +459,32 @@ The following peripherals are currently provided with this board: `Host based flash access`_ section. **Input events** - A driver is provided to read input events from a Linux evdev input device and - inject them back into the Zephyr input subsystem. + Two optional native input drivers are available: - The driver is automatically enabled when :kconfig:option:`CONFIG_INPUT` is - enabled and the devicetree contains a node such as: + **evdev driver** + A driver is provided to read input events from a Linux evdev input device and + inject them back into the Zephyr input subsystem. - .. code-block:: dts + The driver is automatically enabled when :kconfig:option:`CONFIG_INPUT` is + enabled and the devicetree contains a node such as: - evdev { - compatible = "zephyr,native-linux-evdev"; - }; + .. code-block:: dts - The application then has to be run with a command line option to specify - which evdev device node has to be used, for example - ``zephyr.exe --evdev=/dev/input/event0``. + evdev { + compatible = "zephyr,native-linux-evdev"; + }; + + The application then has to be run with a command line option to specify + which evdev device node has to be used, for example + ``zephyr.exe --evdev=/dev/input/event0``. + + **Input SDL touch** + This driver emulates a touch panel input using the SDL library. It can be enabled with + :kconfig:option:`CONFIG_INPUT_SDL_TOUCH` and configured with the device tree binding + :dtcompatible:`zephyr,input-sdl-touch`. + + More information on using SDL and the Display driver can be found in + :ref:`its section `. .. _native_ptty_uart: From 1be87446b1f83197969e16c25b677415a93c7501 Mon Sep 17 00:00:00 2001 From: Alberto Escolar Piedras Date: Sun, 7 Jan 2024 11:05:37 +0100 Subject: [PATCH 1928/3723] docs boards native_sim: Mention the SocketCAN driver Add a small paragraph about the native SocketCAN Linux driver. Signed-off-by: Alberto Escolar Piedras --- boards/posix/native_sim/doc/index.rst | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/boards/posix/native_sim/doc/index.rst b/boards/posix/native_sim/doc/index.rst index 7f422e791fa..64579fc4631 100644 --- a/boards/posix/native_sim/doc/index.rst +++ b/boards/posix/native_sim/doc/index.rst @@ -486,6 +486,11 @@ The following peripherals are currently provided with this board: More information on using SDL and the Display driver can be found in :ref:`its section `. +**CAN controller** + It is possible to use a host CAN controller with the native SockerCAN Linux driver. It can be + enabled with :kconfig:option:`CONFIG_CAN_NATIVE_LINUX` and configured with the device tree binding + :dtcompatible:`zephyr,native-linux-can`. + .. _native_ptty_uart: PTTY UART From b007bbb54f1b4a34f4dd9ffec1d27d7171b95afd Mon Sep 17 00:00:00 2001 From: Philip Molloy Date: Mon, 8 Jan 2024 09:19:16 +0100 Subject: [PATCH 1929/3723] boards: arm: doc: fix small typo Replace the accidently typed letter "d" with "r" Signed-off-by: Philip Molloy --- boards/arm/arduino_opta_m4/doc/index.rst | 2 +- boards/arm/atsamc21n_xpro/doc/index.rst | 2 +- boards/arm/atsamd21_xpro/doc/index.rst | 2 +- boards/arm/atsaml21_xpro/doc/index.rst | 2 +- boards/arm/atsamr21_xpro/doc/index.rst | 2 +- boards/arm/atsamr34_xpro/doc/index.rst | 2 +- boards/arm/b_g474e_dpow1/doc/index.rst | 2 +- boards/arm/b_l4s5i_iot01a/doc/index.rst | 2 +- boards/arm/b_u585i_iot02a/doc/index.rst | 2 +- boards/arm/mps2_an385/doc/index.rst | 2 +- boards/arm/mps2_an521/doc/index.rst | 2 +- boards/arm/mps3_an547/doc/index.rst | 2 +- boards/arm/nucleo_c031c6/doc/index.rst | 2 +- boards/arm/nucleo_f030r8/doc/index.rst | 2 +- boards/arm/nucleo_f031k6/doc/index.rst | 2 +- boards/arm/nucleo_f042k6/doc/index.rst | 2 +- boards/arm/nucleo_f070rb/doc/index.rst | 2 +- boards/arm/nucleo_f091rc/doc/index.rst | 2 +- boards/arm/nucleo_f103rb/doc/index.rst | 2 +- boards/arm/nucleo_f334r8/doc/index.rst | 2 +- boards/arm/nucleo_f401re/doc/index.rst | 2 +- boards/arm/nucleo_f410rb/doc/index.rst | 2 +- boards/arm/nucleo_f411re/doc/index.rst | 2 +- boards/arm/nucleo_f413zh/doc/index.rst | 2 +- boards/arm/nucleo_f429zi/doc/index.rst | 2 +- boards/arm/nucleo_f446re/doc/index.rst | 2 +- boards/arm/nucleo_f446ze/doc/index.rst | 2 +- boards/arm/nucleo_f746zg/doc/index.rst | 2 +- boards/arm/nucleo_f756zg/doc/index.rst | 2 +- boards/arm/nucleo_f767zi/doc/index.rst | 2 +- boards/arm/nucleo_g031k8/doc/index.rst | 2 +- boards/arm/nucleo_g070rb/doc/index.rst | 2 +- boards/arm/nucleo_g071rb/doc/index.rst | 2 +- boards/arm/nucleo_g0b1re/doc/index.rst | 2 +- boards/arm/nucleo_g431rb/doc/index.rst | 2 +- boards/arm/nucleo_g474re/doc/index.rst | 2 +- boards/arm/nucleo_h563zi/doc/index.rst | 2 +- boards/arm/nucleo_h723zg/doc/index.rst | 2 +- boards/arm/nucleo_h743zi/doc/index.rst | 2 +- boards/arm/nucleo_h745zi_q/doc/index.rst | 2 +- boards/arm/nucleo_h753zi/doc/index.rst | 2 +- boards/arm/nucleo_h7a3zi_q/doc/index.rst | 2 +- boards/arm/nucleo_l011k4/doc/index.rst | 2 +- boards/arm/nucleo_l031k6/doc/index.rst | 2 +- boards/arm/nucleo_l053r8/doc/index.rst | 2 +- boards/arm/nucleo_l073rz/doc/index.rst | 2 +- boards/arm/nucleo_l152re/doc/index.rst | 2 +- boards/arm/nucleo_l412rb_p/doc/index.rst | 2 +- boards/arm/nucleo_l432kc/doc/index.rst | 2 +- boards/arm/nucleo_l433rc_p/doc/index.rst | 2 +- boards/arm/nucleo_l476rg/doc/index.rst | 2 +- boards/arm/nucleo_l496zg/doc/index.rst | 2 +- boards/arm/nucleo_l4a6zg/doc/index.rst | 2 +- boards/arm/nucleo_l4r5zi/doc/index.rst | 2 +- boards/arm/nucleo_l552ze_q/doc/nucleol552ze_q.rst | 2 +- boards/arm/nucleo_u575zi_q/doc/index.rst | 2 +- boards/arm/nucleo_u5a5zj_q/doc/index.rst | 2 +- boards/arm/pandora_stm32l475/doc/index.rst | 2 +- boards/arm/stm32f072_eval/doc/index.rst | 2 +- boards/arm/stm32f072b_disco/doc/index.rst | 2 +- boards/arm/stm32f0_disco/doc/index.rst | 2 +- boards/arm/stm32f3_disco/doc/index.rst | 2 +- boards/arm/stm32f3_seco_d23/doc/index.rst | 2 +- boards/arm/stm32f411e_disco/doc/index.rst | 2 +- boards/arm/stm32f412g_disco/doc/index.rst | 2 +- boards/arm/stm32f429i_disc1/doc/index.rst | 2 +- boards/arm/stm32f469i_disco/doc/index.rst | 2 +- boards/arm/stm32f4_disco/doc/index.rst | 2 +- boards/arm/stm32f723e_disco/doc/index.rst | 2 +- boards/arm/stm32f746g_disco/doc/index.rst | 2 +- boards/arm/stm32f7508_dk/doc/index.rst | 2 +- boards/arm/stm32f769i_disco/doc/index.rst | 2 +- boards/arm/stm32g071b_disco/doc/index.rst | 2 +- boards/arm/stm32g081b_eval/doc/index.rst | 2 +- boards/arm/stm32h573i_dk/doc/index.rst | 2 +- boards/arm/stm32h735g_disco/doc/index.rst | 2 +- boards/arm/stm32h747i_disco/doc/index.rst | 2 +- boards/arm/stm32h750b_dk/doc/index.rst | 2 +- boards/arm/stm32h7b3i_dk/doc/index.rst | 2 +- boards/arm/stm32l1_disco/doc/index.rst | 2 +- boards/arm/stm32l476g_disco/doc/index.rst | 2 +- boards/arm/stm32l496g_disco/doc/index.rst | 2 +- boards/arm/stm32l4r9i_disco/doc/index.rst | 2 +- boards/arm/stm32l562e_dk/doc/index.rst | 2 +- boards/arm/stm32u5a9j_dk/doc/index.rst | 2 +- boards/arm/stm32vl_disco/doc/index.rst | 2 +- boards/arm/v2m_beetle/doc/index.rst | 2 +- boards/arm/v2m_musca_b1/doc/index.rst | 2 +- boards/arm/v2m_musca_s1/doc/index.rst | 2 +- 89 files changed, 89 insertions(+), 89 deletions(-) diff --git a/boards/arm/arduino_opta_m4/doc/index.rst b/boards/arm/arduino_opta_m4/doc/index.rst index be914c3fa48..90f9497db33 100644 --- a/boards/arm/arduino_opta_m4/doc/index.rst +++ b/boards/arm/arduino_opta_m4/doc/index.rst @@ -71,7 +71,7 @@ Pin Mapping ARDUINO OPTA M4 has access to the 9 GPIO controllers. These controllers are responsible for pin muxing, input/output, pull-up, etc. -For mode details please refer to `ARDUINO-OPTA website`_. +For more details please refer to `ARDUINO-OPTA website`_. Default Zephyr Peripheral Mapping --------------------------------- diff --git a/boards/arm/atsamc21n_xpro/doc/index.rst b/boards/arm/atsamc21n_xpro/doc/index.rst index bb060fe32a4..e7d7d2d5852 100644 --- a/boards/arm/atsamc21n_xpro/doc/index.rst +++ b/boards/arm/atsamc21n_xpro/doc/index.rst @@ -86,7 +86,7 @@ Pin Mapping The SAM C21N Xplained Pro evaluation kit has 4 GPIO controllers. These controllers are responsible for pin muxing, input/output, pull-up, etc. -For mode details please refer to `SAM C21 Family Datasheet`_ and the `SAM C21N +For more details please refer to `SAM C21 Family Datasheet`_ and the `SAM C21N Xplained Pro Schematic`_. Default Zephyr Peripheral Mapping: diff --git a/boards/arm/atsamd21_xpro/doc/index.rst b/boards/arm/atsamd21_xpro/doc/index.rst index 9732c84d6fb..78ed6da63ff 100644 --- a/boards/arm/atsamd21_xpro/doc/index.rst +++ b/boards/arm/atsamd21_xpro/doc/index.rst @@ -87,7 +87,7 @@ Pin Mapping The SAM D21 Xplained Pro evaluation kit has 3 GPIO controllers. These controllers are responsible for pin muxing, input/output, pull-up, etc. -For mode details please refer to `SAM D21 Family Datasheet`_ and the `SAM D21 +For more details please refer to `SAM D21 Family Datasheet`_ and the `SAM D21 Xplained Pro Schematic`_. .. image:: img/ATSAMD21-XPRO-pinout.jpg diff --git a/boards/arm/atsaml21_xpro/doc/index.rst b/boards/arm/atsaml21_xpro/doc/index.rst index 2051b9efa18..5c55f23d587 100644 --- a/boards/arm/atsaml21_xpro/doc/index.rst +++ b/boards/arm/atsaml21_xpro/doc/index.rst @@ -81,7 +81,7 @@ Pin Mapping The SAM L21 Xplained Pro evaluation kit has 2 GPIO controllers. These controllers are responsible for pin muxing, input/output, pull-up, etc. -For mode details please refer to `SAM L21 Family Datasheet`_ and the `SAM L21 +For more details please refer to `SAM L21 Family Datasheet`_ and the `SAM L21 Xplained Pro Schematic`_. .. image:: img/atsaml21-xpro-pinout.jpg diff --git a/boards/arm/atsamr21_xpro/doc/index.rst b/boards/arm/atsamr21_xpro/doc/index.rst index da9cb14a437..60d2c36ea32 100644 --- a/boards/arm/atsamr21_xpro/doc/index.rst +++ b/boards/arm/atsamr21_xpro/doc/index.rst @@ -64,7 +64,7 @@ Pin Mapping The SAM R21 Xplained Pro evaluation kit has 3 GPIO controllers. These controllers are responsible for pin muxing, input/output, pull-up, etc. -For mode details please refer to `SAM R21 Family Datasheet`_ and the `SAM R21 +For more details please refer to `SAM R21 Family Datasheet`_ and the `SAM R21 Xplained Pro Schematic`_. .. image:: img/ATSAMR21-XPRO-pinout.jpg diff --git a/boards/arm/atsamr34_xpro/doc/index.rst b/boards/arm/atsamr34_xpro/doc/index.rst index 051245c5d39..6347b50dedb 100644 --- a/boards/arm/atsamr34_xpro/doc/index.rst +++ b/boards/arm/atsamr34_xpro/doc/index.rst @@ -99,7 +99,7 @@ Pin Mapping The SAM R34 Xplained Pro evaluation kit has 3 GPIO controllers. These controllers are responsible for pin muxing, input/output, pull-up, etc. -For mode details please refer to `SAM R34 Family Datasheet`_ and the `SAM R34 +For more details please refer to `SAM R34 Family Datasheet`_ and the `SAM R34 Xplained Pro Schematic`_. .. image:: img/atsamr34-xpro-pinout.jpg diff --git a/boards/arm/b_g474e_dpow1/doc/index.rst b/boards/arm/b_g474e_dpow1/doc/index.rst index 1959ab6ad68..75d99572fbf 100644 --- a/boards/arm/b_g474e_dpow1/doc/index.rst +++ b/boards/arm/b_g474e_dpow1/doc/index.rst @@ -99,7 +99,7 @@ Default Zephyr Peripheral Mapping: - UCPD CC2 : PB4 - UCPD CC1 : PB6 -For mode details please refer to `B-G474E-DPOW1 Discovery board User Manual`_. +For more details please refer to `B-G474E-DPOW1 Discovery board User Manual`_. Programming and Debugging ************************* diff --git a/boards/arm/b_l4s5i_iot01a/doc/index.rst b/boards/arm/b_l4s5i_iot01a/doc/index.rst index 14d9480707b..d5b11c8b30b 100644 --- a/boards/arm/b_l4s5i_iot01a/doc/index.rst +++ b/boards/arm/b_l4s5i_iot01a/doc/index.rst @@ -144,7 +144,7 @@ Connections and IOs B_L4S5I_IOT01A Discovery kit has 9 GPIO controllers (from A to I). These controllers are responsible for pin muxing, input/output, pull-up, etc. -For mode details please refer to `B L47S5I IOT01A board User Manual`_. +For more details please refer to `B L47S5I IOT01A board User Manual`_. Default Zephyr Peripheral Mapping: ---------------------------------- diff --git a/boards/arm/b_u585i_iot02a/doc/index.rst b/boards/arm/b_u585i_iot02a/doc/index.rst index 3c794b4de79..56906f5ff08 100644 --- a/boards/arm/b_u585i_iot02a/doc/index.rst +++ b/boards/arm/b_u585i_iot02a/doc/index.rst @@ -245,7 +245,7 @@ Connections and IOs B_U585I_IOT02A Discovery kit has 9 GPIO controllers (from A to I). These controllers are responsible for pin muxing, input/output, pull-up, etc. -For mode details please refer to `B U585I IOT02A board User Manual`_. +For more details please refer to `B U585I IOT02A board User Manual`_. Default Zephyr Peripheral Mapping: ---------------------------------- diff --git a/boards/arm/mps2_an385/doc/index.rst b/boards/arm/mps2_an385/doc/index.rst index 1f9d1a59e23..ac27e70e593 100644 --- a/boards/arm/mps2_an385/doc/index.rst +++ b/boards/arm/mps2_an385/doc/index.rst @@ -226,7 +226,7 @@ Peripheral Mapping: - I2C_4_SDA : D40 - I2C_4_SCL : D41 -For mode details please refer to `MPS2 Technical Reference Manual (TRM)`_. +For more details please refer to `MPS2 Technical Reference Manual (TRM)`_. System Clock ============ diff --git a/boards/arm/mps2_an521/doc/index.rst b/boards/arm/mps2_an521/doc/index.rst index 1cd049ec8f9..e8789e72e18 100644 --- a/boards/arm/mps2_an521/doc/index.rst +++ b/boards/arm/mps2_an521/doc/index.rst @@ -331,7 +331,7 @@ Peripheral Mapping: - I2C_4_SDA : D40 - I2C_4_SCL : D41 -For mode details refer to `MPS2+ AN521 Technical Reference Manual (TRM)`_. +For more details refer to `MPS2+ AN521 Technical Reference Manual (TRM)`_. LED ============ diff --git a/boards/arm/mps3_an547/doc/index.rst b/boards/arm/mps3_an547/doc/index.rst index 002c4210f52..b5f383d546a 100644 --- a/boards/arm/mps3_an547/doc/index.rst +++ b/boards/arm/mps3_an547/doc/index.rst @@ -111,7 +111,7 @@ features. The default configuration can be found in the defconfig file: ``boards/arm/mps3_an547/mps3_an547_defconfig``. -For mode details refer to `MPS3 AN547 Technical Reference Manual (TRM)`_. +For more details refer to `MPS3 AN547 Technical Reference Manual (TRM)`_. Serial Port =========== diff --git a/boards/arm/nucleo_c031c6/doc/index.rst b/boards/arm/nucleo_c031c6/doc/index.rst index fcf134f497e..3e28230cba2 100644 --- a/boards/arm/nucleo_c031c6/doc/index.rst +++ b/boards/arm/nucleo_c031c6/doc/index.rst @@ -110,7 +110,7 @@ Default Zephyr Peripheral Mapping: - UART_2 TX/RX : PA2/PA3 (ST-Link Virtual Port Com) - LD4 : PA5 -For mode details please refer to `STM32 Nucleo-64 board User Manual`_. +For more details please refer to `STM32 Nucleo-64 board User Manual`_. Programming and Debugging ************************* diff --git a/boards/arm/nucleo_f030r8/doc/index.rst b/boards/arm/nucleo_f030r8/doc/index.rst index 821470b20c0..a6f104398c7 100644 --- a/boards/arm/nucleo_f030r8/doc/index.rst +++ b/boards/arm/nucleo_f030r8/doc/index.rst @@ -129,7 +129,7 @@ Default Zephyr Peripheral Mapping: - ADC : PA0 -For mode details please refer to `STM32 Nucleo-64 board User Manual`_. +For more details please refer to `STM32 Nucleo-64 board User Manual`_. Programming and Debugging ************************* diff --git a/boards/arm/nucleo_f031k6/doc/index.rst b/boards/arm/nucleo_f031k6/doc/index.rst index b7adddf6509..ccfb1540f26 100644 --- a/boards/arm/nucleo_f031k6/doc/index.rst +++ b/boards/arm/nucleo_f031k6/doc/index.rst @@ -98,7 +98,7 @@ Default Zephyr Peripheral Mapping: - LD2 : PB3 -For mode details please refer to `STM32 Nucleo-32 board User Manual`_. +For more details please refer to `STM32 Nucleo-32 board User Manual`_. Programming and Debugging ************************* diff --git a/boards/arm/nucleo_f042k6/doc/index.rst b/boards/arm/nucleo_f042k6/doc/index.rst index a9676350eb4..66ad80adeed 100644 --- a/boards/arm/nucleo_f042k6/doc/index.rst +++ b/boards/arm/nucleo_f042k6/doc/index.rst @@ -98,7 +98,7 @@ Default Zephyr Peripheral Mapping: - LD2 : PB3 -For mode details please refer to `STM32 Nucleo-32 board User Manual`_. +For more details please refer to `STM32 Nucleo-32 board User Manual`_. Programming and Debugging ************************* diff --git a/boards/arm/nucleo_f070rb/doc/index.rst b/boards/arm/nucleo_f070rb/doc/index.rst index 5d7e214bd1b..50a96e3fed4 100644 --- a/boards/arm/nucleo_f070rb/doc/index.rst +++ b/boards/arm/nucleo_f070rb/doc/index.rst @@ -126,7 +126,7 @@ Default Zephyr Peripheral Mapping: - USER_PB : PC13 - LD1 : PA5 -For mode details please refer to `STM32 Nucleo-64 board User Manual`_. +For more details please refer to `STM32 Nucleo-64 board User Manual`_. Programming and Debugging ************************* diff --git a/boards/arm/nucleo_f091rc/doc/index.rst b/boards/arm/nucleo_f091rc/doc/index.rst index f1f0df58e10..9ff09e28770 100644 --- a/boards/arm/nucleo_f091rc/doc/index.rst +++ b/boards/arm/nucleo_f091rc/doc/index.rst @@ -143,7 +143,7 @@ Default Zephyr Peripheral Mapping: - DAC_OUT1 : PA4 - PWM_2_CH1 : PA5 (might conflict with SPI1) -For mode details please refer to `STM32 Nucleo-64 board User Manual`_. +For more details please refer to `STM32 Nucleo-64 board User Manual`_. Programming and Debugging ************************* diff --git a/boards/arm/nucleo_f103rb/doc/index.rst b/boards/arm/nucleo_f103rb/doc/index.rst index b717c75b58a..8f67b04ad62 100644 --- a/boards/arm/nucleo_f103rb/doc/index.rst +++ b/boards/arm/nucleo_f103rb/doc/index.rst @@ -133,7 +133,7 @@ Default Zephyr Peripheral Mapping: - USER_PB : PC13 - LD1 : PA5 -For mode details please refer to `STM32 Nucleo-64 board User Manual`_. +For more details please refer to `STM32 Nucleo-64 board User Manual`_. Programming and Debugging ************************* diff --git a/boards/arm/nucleo_f334r8/doc/index.rst b/boards/arm/nucleo_f334r8/doc/index.rst index d44ee9e51d7..64824e787eb 100644 --- a/boards/arm/nucleo_f334r8/doc/index.rst +++ b/boards/arm/nucleo_f334r8/doc/index.rst @@ -123,7 +123,7 @@ Default Zephyr Peripheral Mapping: - USER_PB : PC13 - LD2 : PA5 -For mode details please refer to `STM32 Nucleo-64 board User Manual`_. +For more details please refer to `STM32 Nucleo-64 board User Manual`_. Programming and Debugging ************************* diff --git a/boards/arm/nucleo_f401re/doc/index.rst b/boards/arm/nucleo_f401re/doc/index.rst index c844ef9ab9c..aa01b1ad3ad 100644 --- a/boards/arm/nucleo_f401re/doc/index.rst +++ b/boards/arm/nucleo_f401re/doc/index.rst @@ -109,7 +109,7 @@ Available pins: :align: center :alt: Nucleo F401RE Morpho connectors -For mode details please refer to `STM32 Nucleo-64 board User Manual`_. +For more details please refer to `STM32 Nucleo-64 board User Manual`_. Default Zephyr Peripheral Mapping: ---------------------------------- diff --git a/boards/arm/nucleo_f410rb/doc/index.rst b/boards/arm/nucleo_f410rb/doc/index.rst index c5702552ca8..23c979e49aa 100644 --- a/boards/arm/nucleo_f410rb/doc/index.rst +++ b/boards/arm/nucleo_f410rb/doc/index.rst @@ -120,7 +120,7 @@ Available pins: :align: center :alt: Nucleo F410RB Morpho connectors (top right) -For mode details please refer to `STM32 Nucleo-64 board User Manual`_. +For more details please refer to `STM32 Nucleo-64 board User Manual`_. Default Zephyr Peripheral Mapping: ---------------------------------- diff --git a/boards/arm/nucleo_f411re/doc/index.rst b/boards/arm/nucleo_f411re/doc/index.rst index ee7d652d1c5..908dfbf9a2a 100644 --- a/boards/arm/nucleo_f411re/doc/index.rst +++ b/boards/arm/nucleo_f411re/doc/index.rst @@ -107,7 +107,7 @@ Available pins: :align: center :alt: Nucleo F411RE Morpho connectors -For mode details please refer to `STM32 Nucleo-64 board User Manual`_. +For more details please refer to `STM32 Nucleo-64 board User Manual`_. Default Zephyr Peripheral Mapping: ---------------------------------- diff --git a/boards/arm/nucleo_f413zh/doc/index.rst b/boards/arm/nucleo_f413zh/doc/index.rst index b00213ced7e..7979171472e 100644 --- a/boards/arm/nucleo_f413zh/doc/index.rst +++ b/boards/arm/nucleo_f413zh/doc/index.rst @@ -117,7 +117,7 @@ Available pins: :align: center :alt: Nucleo F413ZH Morpho connectors (right) -For mode details please refer to `STM32 Nucleo-144 board User Manual`_. +For more details please refer to `STM32 Nucleo-144 board User Manual`_. Default Zephyr Peripheral Mapping: ---------------------------------- diff --git a/boards/arm/nucleo_f429zi/doc/index.rst b/boards/arm/nucleo_f429zi/doc/index.rst index 3b20f6a7a0c..e65e9194ad4 100644 --- a/boards/arm/nucleo_f429zi/doc/index.rst +++ b/boards/arm/nucleo_f429zi/doc/index.rst @@ -139,7 +139,7 @@ Available pins: :align: center :alt: Nucleo F429ZI Morpho connectors (right) -For mode details please refer to `STM32 Nucleo-144 board User Manual`_. +For more details please refer to `STM32 Nucleo-144 board User Manual`_. Default Zephyr Peripheral Mapping: ---------------------------------- diff --git a/boards/arm/nucleo_f446re/doc/index.rst b/boards/arm/nucleo_f446re/doc/index.rst index a835d963d2b..37d62c04310 100644 --- a/boards/arm/nucleo_f446re/doc/index.rst +++ b/boards/arm/nucleo_f446re/doc/index.rst @@ -118,7 +118,7 @@ Available pins: :align: center :alt: Nucleo F446RE Morpho connectors (top right) -For mode details please refer to `STM32 Nucleo-64 board User Manual`_. +For more details please refer to `STM32 Nucleo-64 board User Manual`_. Default Zephyr Peripheral Mapping: ---------------------------------- diff --git a/boards/arm/nucleo_f446ze/doc/index.rst b/boards/arm/nucleo_f446ze/doc/index.rst index b0a8f431462..697324e84fa 100644 --- a/boards/arm/nucleo_f446ze/doc/index.rst +++ b/boards/arm/nucleo_f446ze/doc/index.rst @@ -129,7 +129,7 @@ Available pins: :align: center :alt: Nucleo F446ZE Morpho connectors (right) -For mode details please refer to `STM32 Nucleo-144 board User Manual`_. +For more details please refer to `STM32 Nucleo-144 board User Manual`_. Default Zephyr Peripheral Mapping: ---------------------------------- diff --git a/boards/arm/nucleo_f746zg/doc/index.rst b/boards/arm/nucleo_f746zg/doc/index.rst index ef9fdf9d20e..8bc083bcc3f 100644 --- a/boards/arm/nucleo_f746zg/doc/index.rst +++ b/boards/arm/nucleo_f746zg/doc/index.rst @@ -128,7 +128,7 @@ Other hardware features are not yet supported on this Zephyr port. The default configuration can be found in the defconfig file: ``boards/arm/nucleo_f746zg/nucleo_f746zg_defconfig`` -For mode details please refer to `STM32 Nucleo-144 board User Manual`_. +For more details please refer to `STM32 Nucleo-144 board User Manual`_. Default Zephyr Peripheral Mapping: ---------------------------------- diff --git a/boards/arm/nucleo_f756zg/doc/index.rst b/boards/arm/nucleo_f756zg/doc/index.rst index 2616a3b6dcc..aa13ddb7f20 100644 --- a/boards/arm/nucleo_f756zg/doc/index.rst +++ b/boards/arm/nucleo_f756zg/doc/index.rst @@ -118,7 +118,7 @@ Other hardware features are not yet supported on this Zephyr port. The default configuration can be found in the defconfig file: ``boards/arm/nucleo_f756zg/nucleo_f756zg_defconfig`` -For mode details please refer to `STM32 Nucleo-144 board User Manual`_. +For more details please refer to `STM32 Nucleo-144 board User Manual`_. Default Zephyr Peripheral Mapping: ---------------------------------- diff --git a/boards/arm/nucleo_f767zi/doc/index.rst b/boards/arm/nucleo_f767zi/doc/index.rst index bed503e2609..7eca2af1eda 100644 --- a/boards/arm/nucleo_f767zi/doc/index.rst +++ b/boards/arm/nucleo_f767zi/doc/index.rst @@ -135,7 +135,7 @@ Other hardware features are not yet supported on this Zephyr port. The default configuration can be found in the defconfig file: ``boards/arm/nucleo_f767zi/nucleo_f767zi_defconfig`` -For mode details please refer to `STM32 Nucleo-144 board User Manual`_. +For more details please refer to `STM32 Nucleo-144 board User Manual`_. Default Zephyr Peripheral Mapping: ---------------------------------- diff --git a/boards/arm/nucleo_g031k8/doc/index.rst b/boards/arm/nucleo_g031k8/doc/index.rst index 6f933b08546..93a10b553ab 100644 --- a/boards/arm/nucleo_g031k8/doc/index.rst +++ b/boards/arm/nucleo_g031k8/doc/index.rst @@ -105,7 +105,7 @@ Default Zephyr Peripheral Mapping: - SPI1 SCK/MISO/MOSI : PB3/PB4/PB5 (Arduino SPI) - LD3 : PC6 -For mode details please refer to `STM32 Nucleo-32 board User Manual`_. +For more details please refer to `STM32 Nucleo-32 board User Manual`_. Programming and Debugging ************************* diff --git a/boards/arm/nucleo_g070rb/doc/index.rst b/boards/arm/nucleo_g070rb/doc/index.rst index 056bb298c4f..8908ed5ce43 100644 --- a/boards/arm/nucleo_g070rb/doc/index.rst +++ b/boards/arm/nucleo_g070rb/doc/index.rst @@ -138,7 +138,7 @@ Default Zephyr Peripheral Mapping: - ADC1 IN1 : PA1 - DAC1_OUT1 : PA4 -For mode details please refer to `STM32 Nucleo-64 board User Manual`_. +For more details please refer to `STM32 Nucleo-64 board User Manual`_. Programming and Debugging ************************* diff --git a/boards/arm/nucleo_g071rb/doc/index.rst b/boards/arm/nucleo_g071rb/doc/index.rst index f6aebe8f12b..424f1ade9f7 100644 --- a/boards/arm/nucleo_g071rb/doc/index.rst +++ b/boards/arm/nucleo_g071rb/doc/index.rst @@ -142,7 +142,7 @@ Default Zephyr Peripheral Mapping: - ADC1 IN1 : PA1 - DAC1_OUT1 : PA4 -For mode details please refer to `STM32 Nucleo-64 board User Manual`_. +For more details please refer to `STM32 Nucleo-64 board User Manual`_. Programming and Debugging ************************* diff --git a/boards/arm/nucleo_g0b1re/doc/index.rst b/boards/arm/nucleo_g0b1re/doc/index.rst index 0ad60852627..7ca35bd7511 100644 --- a/boards/arm/nucleo_g0b1re/doc/index.rst +++ b/boards/arm/nucleo_g0b1re/doc/index.rst @@ -138,7 +138,7 @@ Default Zephyr Peripheral Mapping: - ADC1 IN1 : PA1 - DAC1_OUT1 : PA4 -For mode details please refer to `STM32 Nucleo-64 board User Manual`_. +For more details please refer to `STM32 Nucleo-64 board User Manual`_. Programming and Debugging ************************* diff --git a/boards/arm/nucleo_g431rb/doc/index.rst b/boards/arm/nucleo_g431rb/doc/index.rst index 7d60b8c5426..0359a29b231 100644 --- a/boards/arm/nucleo_g431rb/doc/index.rst +++ b/boards/arm/nucleo_g431rb/doc/index.rst @@ -134,7 +134,7 @@ Connections and IOs Nucleo G431RB Board has 6 GPIO controllers. These controllers are responsible for pin muxing, input/output, pull-up, etc. -For mode details please refer to `STM32G4 Nucleo-64 board User Manual`_. +For more details please refer to `STM32G4 Nucleo-64 board User Manual`_. Default Zephyr Peripheral Mapping: ---------------------------------- diff --git a/boards/arm/nucleo_g474re/doc/index.rst b/boards/arm/nucleo_g474re/doc/index.rst index 437668ed42e..6705e20fd78 100644 --- a/boards/arm/nucleo_g474re/doc/index.rst +++ b/boards/arm/nucleo_g474re/doc/index.rst @@ -140,7 +140,7 @@ Connections and IOs Nucleo G474RE Board has 6 GPIO controllers. These controllers are responsible for pin muxing, input/output, pull-up, etc. -For mode details please refer to `STM32G4 Nucleo-64 board User Manual`_. +For more details please refer to `STM32G4 Nucleo-64 board User Manual`_. Default Zephyr Peripheral Mapping: ---------------------------------- diff --git a/boards/arm/nucleo_h563zi/doc/index.rst b/boards/arm/nucleo_h563zi/doc/index.rst index 9b6f880ac4c..7d1ac5c5b5a 100644 --- a/boards/arm/nucleo_h563zi/doc/index.rst +++ b/boards/arm/nucleo_h563zi/doc/index.rst @@ -206,7 +206,7 @@ Connections and IOs Nucleo H563ZI Board has 9 GPIO controllers. These controllers are responsible for pin muxing, input/output, pull-up, etc. -For mode details please refer to `STM32H5 Nucleo-144 board User Manual`_. +For more details please refer to `STM32H5 Nucleo-144 board User Manual`_. Default Zephyr Peripheral Mapping: ---------------------------------- diff --git a/boards/arm/nucleo_h723zg/doc/index.rst b/boards/arm/nucleo_h723zg/doc/index.rst index 09b71835f67..44a87bb5129 100644 --- a/boards/arm/nucleo_h723zg/doc/index.rst +++ b/boards/arm/nucleo_h723zg/doc/index.rst @@ -121,7 +121,7 @@ Other hardware features are not yet supported on this Zephyr port. The default configuration per core can be found in the defconfig files: ``boards/arm/nucleo_h723zg/nucleo_h723zg_defconfig`` -For mode details please refer to `STM32 Nucleo-144 board User Manual`_. +For more details please refer to `STM32 Nucleo-144 board User Manual`_. Default Zephyr Peripheral Mapping: ---------------------------------- diff --git a/boards/arm/nucleo_h743zi/doc/index.rst b/boards/arm/nucleo_h743zi/doc/index.rst index c401e3ab098..e6cb6e242cd 100644 --- a/boards/arm/nucleo_h743zi/doc/index.rst +++ b/boards/arm/nucleo_h743zi/doc/index.rst @@ -135,7 +135,7 @@ Other hardware features are not yet supported on this Zephyr port. The default configuration can be found in the defconfig file: ``boards/arm/nucleo_h743zi/nucleo_h743zi_defconfig`` -For mode details please refer to `STM32 Nucleo-144 board User Manual`_. +For more details please refer to `STM32 Nucleo-144 board User Manual`_. Default Zephyr Peripheral Mapping: ---------------------------------- diff --git a/boards/arm/nucleo_h745zi_q/doc/index.rst b/boards/arm/nucleo_h745zi_q/doc/index.rst index 60f86f2ab81..36c4b80bc58 100644 --- a/boards/arm/nucleo_h745zi_q/doc/index.rst +++ b/boards/arm/nucleo_h745zi_q/doc/index.rst @@ -122,7 +122,7 @@ The default configuration per core can be found in the defconfig files: ``boards/arm/nucleo_h745zi_q/nucleo_h745zi_q_m7_defconfig`` and ``boards/arm/nucleo_h745zi_q/nucleo_h745zi_q_m4_defconfig`` -For mode details please refer to `STM32 Nucleo-144 board User Manual`_. +For more details please refer to `STM32 Nucleo-144 board User Manual`_. Default Zephyr Peripheral Mapping: ---------------------------------- diff --git a/boards/arm/nucleo_h753zi/doc/index.rst b/boards/arm/nucleo_h753zi/doc/index.rst index 058cbc67c9f..eab88c9952a 100644 --- a/boards/arm/nucleo_h753zi/doc/index.rst +++ b/boards/arm/nucleo_h753zi/doc/index.rst @@ -129,7 +129,7 @@ Other hardware features are not yet supported on this Zephyr port. The default configuration can be found in the defconfig file: ``boards/arm/nucleo_h753zi/nucleo_h753zi_defconfig`` -For mode details please refer to `STM32 Nucleo-144 board User Manual`_. +For more details please refer to `STM32 Nucleo-144 board User Manual`_. Default Zephyr Peripheral Mapping: ---------------------------------- diff --git a/boards/arm/nucleo_h7a3zi_q/doc/index.rst b/boards/arm/nucleo_h7a3zi_q/doc/index.rst index 7b107733510..1144f13e731 100644 --- a/boards/arm/nucleo_h7a3zi_q/doc/index.rst +++ b/boards/arm/nucleo_h7a3zi_q/doc/index.rst @@ -117,7 +117,7 @@ Other hardware features are not yet supported on this Zephyr port. The default configuration can be found in the defconfig file: ``boards/arm/nucleo_h7a3zi_q/nucleo_h7a3zi_q_defconfig`` -For mode details please refer to `STM32 Nucleo-144 board User Manual`_. +For more details please refer to `STM32 Nucleo-144 board User Manual`_. Default Zephyr Peripheral Mapping: ---------------------------------- diff --git a/boards/arm/nucleo_l011k4/doc/index.rst b/boards/arm/nucleo_l011k4/doc/index.rst index 9b815ede4de..04fc12c53f3 100644 --- a/boards/arm/nucleo_l011k4/doc/index.rst +++ b/boards/arm/nucleo_l011k4/doc/index.rst @@ -113,7 +113,7 @@ Default Zephyr Peripheral Mapping: - SPI1 SCK/MISO/MOSI : PA5/PA6/PA7 (Arduino SPI) - LD2 : PB3 -For mode details please refer to `STM32 Nucleo-32 board User Manual`_. +For more details please refer to `STM32 Nucleo-32 board User Manual`_. Programming and Debugging ************************* diff --git a/boards/arm/nucleo_l031k6/doc/index.rst b/boards/arm/nucleo_l031k6/doc/index.rst index eb1f6e25387..da0fcaa271e 100644 --- a/boards/arm/nucleo_l031k6/doc/index.rst +++ b/boards/arm/nucleo_l031k6/doc/index.rst @@ -106,7 +106,7 @@ Default Zephyr Peripheral Mapping: - SPI1 SCK/MISO/MOSI : PA5/PA6/PA7 (Arduino SPI) - LD2 : PB3 -For mode details please refer to `STM32 Nucleo-32 board User Manual`_. +For more details please refer to `STM32 Nucleo-32 board User Manual`_. Programming and Debugging ************************* diff --git a/boards/arm/nucleo_l053r8/doc/index.rst b/boards/arm/nucleo_l053r8/doc/index.rst index 33f84b14e6c..ba448176fca 100644 --- a/boards/arm/nucleo_l053r8/doc/index.rst +++ b/boards/arm/nucleo_l053r8/doc/index.rst @@ -122,7 +122,7 @@ Default Zephyr Peripheral Mapping: - USER_PB : PC13 - LD2 : PA5 -For mode details please refer to `STM32 Nucleo-64 board User Manual`_. +For more details please refer to `STM32 Nucleo-64 board User Manual`_. Programming and Debugging ************************* diff --git a/boards/arm/nucleo_l073rz/doc/index.rst b/boards/arm/nucleo_l073rz/doc/index.rst index de662f5b14f..a828a5b70eb 100644 --- a/boards/arm/nucleo_l073rz/doc/index.rst +++ b/boards/arm/nucleo_l073rz/doc/index.rst @@ -136,7 +136,7 @@ Default Zephyr Peripheral Mapping: - DAC : PA4 - PWM_2_CH1 : PA5 (might conflict with SPI1) -For mode details please refer to `STM32 Nucleo-64 board User Manual`_. +For more details please refer to `STM32 Nucleo-64 board User Manual`_. Programming and Debugging ************************* diff --git a/boards/arm/nucleo_l152re/doc/index.rst b/boards/arm/nucleo_l152re/doc/index.rst index 2595144e730..020beb6583f 100644 --- a/boards/arm/nucleo_l152re/doc/index.rst +++ b/boards/arm/nucleo_l152re/doc/index.rst @@ -130,7 +130,7 @@ Default Zephyr Peripheral Mapping: - DAC : PA4 - PWM_3_CH1 : PA6 -For mode details please refer to `STM32 Nucleo-64 board User Manual`_. +For more details please refer to `STM32 Nucleo-64 board User Manual`_. Programming and Debugging ************************* diff --git a/boards/arm/nucleo_l412rb_p/doc/index.rst b/boards/arm/nucleo_l412rb_p/doc/index.rst index 007ae04379d..3485d01cba1 100644 --- a/boards/arm/nucleo_l412rb_p/doc/index.rst +++ b/boards/arm/nucleo_l412rb_p/doc/index.rst @@ -176,7 +176,7 @@ Available pins: :align: center :alt: Nucleo L412RB-P -For mode details please refer to `ST Nucleo L412RB-P User Manual`_. +For more details please refer to `ST Nucleo L412RB-P User Manual`_. Default Zephyr Peripheral Mapping: ---------------------------------- diff --git a/boards/arm/nucleo_l432kc/doc/index.rst b/boards/arm/nucleo_l432kc/doc/index.rst index 94d6f6f20f0..b054c472f22 100644 --- a/boards/arm/nucleo_l432kc/doc/index.rst +++ b/boards/arm/nucleo_l432kc/doc/index.rst @@ -137,7 +137,7 @@ Available pins: :align: center :alt: Nucleo L432KC Arduino connectors -For mode details please refer to `STM32 Nucleo-32 board User Manual`_. +For more details please refer to `STM32 Nucleo-32 board User Manual`_. Default Zephyr Peripheral Mapping: ---------------------------------- diff --git a/boards/arm/nucleo_l433rc_p/doc/index.rst b/boards/arm/nucleo_l433rc_p/doc/index.rst index da2660417c0..6e86a44cee0 100644 --- a/boards/arm/nucleo_l433rc_p/doc/index.rst +++ b/boards/arm/nucleo_l433rc_p/doc/index.rst @@ -140,7 +140,7 @@ Available pins: :align: center :alt: Nucleo L433RC-P -For mode details please refer to `ST Nucleo L433RC-P User Manual`_. +For more details please refer to `ST Nucleo L433RC-P User Manual`_. Default Zephyr Peripheral Mapping: ---------------------------------- diff --git a/boards/arm/nucleo_l476rg/doc/index.rst b/boards/arm/nucleo_l476rg/doc/index.rst index cfbf949df57..10dff333643 100644 --- a/boards/arm/nucleo_l476rg/doc/index.rst +++ b/boards/arm/nucleo_l476rg/doc/index.rst @@ -145,7 +145,7 @@ Available pins: :align: center :alt: Nucleo L476RG Morpho connectors -For mode details please refer to `STM32 Nucleo-64 board User Manual`_. +For more details please refer to `STM32 Nucleo-64 board User Manual`_. Default Zephyr Peripheral Mapping: ---------------------------------- diff --git a/boards/arm/nucleo_l496zg/doc/index.rst b/boards/arm/nucleo_l496zg/doc/index.rst index 43f6e1fdb4c..49d011b8846 100644 --- a/boards/arm/nucleo_l496zg/doc/index.rst +++ b/boards/arm/nucleo_l496zg/doc/index.rst @@ -142,7 +142,7 @@ Connections and IOs Nucleo L496ZG Board has 8 GPIO controllers. These controllers are responsible for pin muxing, input/output, pull-up, etc. -For mode details please refer to `STM32 Nucleo-144 board User Manual`_. +For more details please refer to `STM32 Nucleo-144 board User Manual`_. Default Zephyr Peripheral Mapping: ---------------------------------- diff --git a/boards/arm/nucleo_l4a6zg/doc/index.rst b/boards/arm/nucleo_l4a6zg/doc/index.rst index 79c7caca7bb..7e61d9f8907 100644 --- a/boards/arm/nucleo_l4a6zg/doc/index.rst +++ b/boards/arm/nucleo_l4a6zg/doc/index.rst @@ -147,7 +147,7 @@ Connections and IOs Nucleo L4A6ZG Board has 8 GPIO controllers. These controllers are responsible for pin muxing, input/output, pull-up, etc. -For mode details please refer to `STM32 Nucleo-144 board User Manual`_. +For more details please refer to `STM32 Nucleo-144 board User Manual`_. Default Zephyr Peripheral Mapping: ---------------------------------- diff --git a/boards/arm/nucleo_l4r5zi/doc/index.rst b/boards/arm/nucleo_l4r5zi/doc/index.rst index 15072f81cdf..b132403ce2a 100644 --- a/boards/arm/nucleo_l4r5zi/doc/index.rst +++ b/boards/arm/nucleo_l4r5zi/doc/index.rst @@ -160,7 +160,7 @@ Available pins: :align: center :alt: Nucleo L4R5ZI Arduino connectors -For mode details please refer to `STM32 Nucleo-144 board User Manual`_. +For more details please refer to `STM32 Nucleo-144 board User Manual`_. Default Zephyr Peripheral Mapping: ---------------------------------- diff --git a/boards/arm/nucleo_l552ze_q/doc/nucleol552ze_q.rst b/boards/arm/nucleo_l552ze_q/doc/nucleol552ze_q.rst index 51675477af4..0d9b7b37ae0 100644 --- a/boards/arm/nucleo_l552ze_q/doc/nucleol552ze_q.rst +++ b/boards/arm/nucleo_l552ze_q/doc/nucleol552ze_q.rst @@ -234,7 +234,7 @@ Available pins: :align: center :alt: Nucleo L552ZE Q Zio right connector -For mode details please refer to `STM32 Nucleo-144 board User Manual`_. +For more details please refer to `STM32 Nucleo-144 board User Manual`_. Default Zephyr Peripheral Mapping: ---------------------------------- diff --git a/boards/arm/nucleo_u575zi_q/doc/index.rst b/boards/arm/nucleo_u575zi_q/doc/index.rst index 0de2c364ecf..d9f4c93d753 100644 --- a/boards/arm/nucleo_u575zi_q/doc/index.rst +++ b/boards/arm/nucleo_u575zi_q/doc/index.rst @@ -185,7 +185,7 @@ Connections and IOs Nucleo U575ZI Q Board has 9 GPIO controllers. These controllers are responsible for pin muxing, input/output, pull-up, etc. -For mode details please refer to `STM32 Nucleo-144 board User Manual`_. +For more details please refer to `STM32 Nucleo-144 board User Manual`_. Default Zephyr Peripheral Mapping: ---------------------------------- diff --git a/boards/arm/nucleo_u5a5zj_q/doc/index.rst b/boards/arm/nucleo_u5a5zj_q/doc/index.rst index f877be5c168..d9732bf430b 100644 --- a/boards/arm/nucleo_u5a5zj_q/doc/index.rst +++ b/boards/arm/nucleo_u5a5zj_q/doc/index.rst @@ -219,7 +219,7 @@ Connections and IOs Nucleo U5A5ZJ Q Board has 10 GPIO controllers. These controllers are responsible for pin muxing, input/output, pull-up, etc. -For mode details please refer to `STM32 Nucleo-144 board User Manual`_. +For more details please refer to `STM32 Nucleo-144 board User Manual`_. Default Zephyr Peripheral Mapping: ---------------------------------- diff --git a/boards/arm/pandora_stm32l475/doc/index.rst b/boards/arm/pandora_stm32l475/doc/index.rst index 62a903faf78..76da038e9ec 100644 --- a/boards/arm/pandora_stm32l475/doc/index.rst +++ b/boards/arm/pandora_stm32l475/doc/index.rst @@ -136,7 +136,7 @@ Connections and IOs STM32L475 Pandora Board has 8 GPIO controllers. These controllers are responsible for pin muxing, input/output, pull-up, etc. -For mode details please refer to `STM32L475 Pandora board User Manual`_. +For more details please refer to `STM32L475 Pandora board User Manual`_. Default Zephyr Peripheral Mapping: ---------------------------------- diff --git a/boards/arm/stm32f072_eval/doc/index.rst b/boards/arm/stm32f072_eval/doc/index.rst index 4872f85785b..49b6577935c 100644 --- a/boards/arm/stm32f072_eval/doc/index.rst +++ b/boards/arm/stm32f072_eval/doc/index.rst @@ -110,7 +110,7 @@ Pin Mapping STM32F072-EVAL Discovery kit has 6 GPIO controllers. These controllers are responsible for pin muxing, input/output, pull-up, etc. -For mode details please refer to STM32F072-EVAL board User Manual. +For more details please refer to STM32F072-EVAL board User Manual. Default Zephyr Peripheral Mapping: ---------------------------------- diff --git a/boards/arm/stm32f072b_disco/doc/index.rst b/boards/arm/stm32f072b_disco/doc/index.rst index 3756926ec4c..a2c51e51cdd 100644 --- a/boards/arm/stm32f072b_disco/doc/index.rst +++ b/boards/arm/stm32f072b_disco/doc/index.rst @@ -108,7 +108,7 @@ Pin Mapping STM32F072B-DISCO Discovery kit has 6 GPIO controllers. These controllers are responsible for pin muxing, input/output, pull-up, etc. -For mode details please refer to `STM32F072B-DISCO board User Manual`_. +For more details please refer to `STM32F072B-DISCO board User Manual`_. Default Zephyr Peripheral Mapping: ---------------------------------- diff --git a/boards/arm/stm32f0_disco/doc/index.rst b/boards/arm/stm32f0_disco/doc/index.rst index e2910793d72..daf0e1f06d3 100644 --- a/boards/arm/stm32f0_disco/doc/index.rst +++ b/boards/arm/stm32f0_disco/doc/index.rst @@ -89,7 +89,7 @@ Default Zephyr Peripheral Mapping: - UART_2_TX : PA2 - UART_2_RX : PA3 -For mode details please refer to `STM32F0DISCOVERY board User Manual`_. +For more details please refer to `STM32F0DISCOVERY board User Manual`_. Programming and Debugging ************************* diff --git a/boards/arm/stm32f3_disco/doc/index.rst b/boards/arm/stm32f3_disco/doc/index.rst index a94083fa2c7..5a0dc214e06 100644 --- a/boards/arm/stm32f3_disco/doc/index.rst +++ b/boards/arm/stm32f3_disco/doc/index.rst @@ -123,7 +123,7 @@ Pin Mapping STM32F3DISCOVERY Discovery kit has 6 GPIO controllers. These controllers are responsible for pin muxing, input/output, pull-up, etc. -For mode details please refer to `STM32F3DISCOVERY board User Manual`_. +For more details please refer to `STM32F3DISCOVERY board User Manual`_. Default Zephyr Peripheral Mapping: ---------------------------------- diff --git a/boards/arm/stm32f3_seco_d23/doc/index.rst b/boards/arm/stm32f3_seco_d23/doc/index.rst index 9b500e372ff..410e2ecea14 100644 --- a/boards/arm/stm32f3_seco_d23/doc/index.rst +++ b/boards/arm/stm32f3_seco_d23/doc/index.rst @@ -96,7 +96,7 @@ Pin Mapping SECO-D23 has 6 GPIO controllers. These controllers are responsible for pin muxing, input/output, pull-up, etc. -For mode details please refer to `SECO JUNO SBC-D23 board User Manual`_. +For more details please refer to `SECO JUNO SBC-D23 board User Manual`_. Default Zephyr Peripheral Mapping: ---------------------------------- diff --git a/boards/arm/stm32f411e_disco/doc/index.rst b/boards/arm/stm32f411e_disco/doc/index.rst index d15dc7728c7..12a057ff1ad 100644 --- a/boards/arm/stm32f411e_disco/doc/index.rst +++ b/boards/arm/stm32f411e_disco/doc/index.rst @@ -96,7 +96,7 @@ Pin Mapping STM32F411E-DISCO Discovery kit has 5 GPIO controllers. These controllers are responsible for pin muxing, input/output, pull-up, etc. -For mode details please refer to `32F411EDISCOVERY board User Manual`_. +For more details please refer to `32F411EDISCOVERY board User Manual`_. Default Zephyr Peripheral Mapping: ---------------------------------- diff --git a/boards/arm/stm32f412g_disco/doc/index.rst b/boards/arm/stm32f412g_disco/doc/index.rst index b79f9b18a0a..8bd0bd588f1 100644 --- a/boards/arm/stm32f412g_disco/doc/index.rst +++ b/boards/arm/stm32f412g_disco/doc/index.rst @@ -113,7 +113,7 @@ Pin Mapping STM32F412G-DISCO Discovery kit has 8 GPIO controllers. These controllers are responsible for pin muxing, input/output, pull-up, etc. -For mode details please refer to `32F412GDISCOVERY board User Manual`_. +For more details please refer to `32F412GDISCOVERY board User Manual`_. Default Zephyr Peripheral Mapping: ---------------------------------- diff --git a/boards/arm/stm32f429i_disc1/doc/index.rst b/boards/arm/stm32f429i_disc1/doc/index.rst index ba2317772a3..9b90abf0dbb 100644 --- a/boards/arm/stm32f429i_disc1/doc/index.rst +++ b/boards/arm/stm32f429i_disc1/doc/index.rst @@ -113,7 +113,7 @@ Pin Mapping The STM32F429I-DISC1 Discovery kit has 8 GPIO controllers. These controllers are responsible for pin muxing, input/output, pull-up, etc. -For mode details please refer to `STM32F429I-DISC1 board User Manual`_. +For more details please refer to `STM32F429I-DISC1 board User Manual`_. Default Zephyr Peripheral Mapping: ---------------------------------- diff --git a/boards/arm/stm32f469i_disco/doc/index.rst b/boards/arm/stm32f469i_disco/doc/index.rst index 7ba1d7c71e3..658f2a7b75e 100644 --- a/boards/arm/stm32f469i_disco/doc/index.rst +++ b/boards/arm/stm32f469i_disco/doc/index.rst @@ -113,7 +113,7 @@ Pin Mapping STM32F469I-DISCO Discovery kit has 9 GPIO controllers. These controllers are responsible for pin muxing, input/output, pull-up, etc. -For mode details please refer to `32F469IDISCOVERY board User Manual`_. +For more details please refer to `32F469IDISCOVERY board User Manual`_. Default Zephyr Peripheral Mapping: ---------------------------------- diff --git a/boards/arm/stm32f4_disco/doc/index.rst b/boards/arm/stm32f4_disco/doc/index.rst index 8ea4ef9893c..15dadab7fbf 100644 --- a/boards/arm/stm32f4_disco/doc/index.rst +++ b/boards/arm/stm32f4_disco/doc/index.rst @@ -114,7 +114,7 @@ Pin Mapping STM32F4DISCOVERY Discovery kit has 8 GPIO controllers. These controllers are responsible for pin muxing, input/output, pull-up, etc. -For mode details please refer to `STM32F4DISCOVERY board User Manual`_. +For more details please refer to `STM32F4DISCOVERY board User Manual`_. Default Zephyr Peripheral Mapping: ---------------------------------- diff --git a/boards/arm/stm32f723e_disco/doc/index.rst b/boards/arm/stm32f723e_disco/doc/index.rst index 5ebcc65c392..c6e34cbbe91 100644 --- a/boards/arm/stm32f723e_disco/doc/index.rst +++ b/boards/arm/stm32f723e_disco/doc/index.rst @@ -99,7 +99,7 @@ Pin Mapping STM32F723E Discovery kit has 7 GPIO controllers. These controllers are responsible for pin muxing, input/output, pull-up, etc. -For mode details please refer to `32F723E-DISCO board User Manual`_. +For more details please refer to `32F723E-DISCO board User Manual`_. Default Zephyr Peripheral Mapping: ---------------------------------- diff --git a/boards/arm/stm32f746g_disco/doc/index.rst b/boards/arm/stm32f746g_disco/doc/index.rst index c9b77967be9..714a627ec4a 100644 --- a/boards/arm/stm32f746g_disco/doc/index.rst +++ b/boards/arm/stm32f746g_disco/doc/index.rst @@ -130,7 +130,7 @@ Pin Mapping STM32F746G Discovery kit has 9 GPIO controllers. These controllers are responsible for pin muxing, input/output, pull-up, etc. -For mode details please refer to `32F746G-DISCO board User Manual`_. +For more details please refer to `32F746G-DISCO board User Manual`_. Default Zephyr Peripheral Mapping: ---------------------------------- diff --git a/boards/arm/stm32f7508_dk/doc/index.rst b/boards/arm/stm32f7508_dk/doc/index.rst index a3f39f37e5e..699285fcd90 100644 --- a/boards/arm/stm32f7508_dk/doc/index.rst +++ b/boards/arm/stm32f7508_dk/doc/index.rst @@ -125,7 +125,7 @@ Pin Mapping STM32F7508-DK Discovery kit has 9 GPIO controllers. These controllers are responsible for pin muxing, input/output, pull-up, etc. -For mode details please refer to `32F7508-DK board User Manual`_. +For more details please refer to `32F7508-DK board User Manual`_. Default Zephyr Peripheral Mapping: ---------------------------------- diff --git a/boards/arm/stm32f769i_disco/doc/index.rst b/boards/arm/stm32f769i_disco/doc/index.rst index d2183087b95..203beb6f48a 100644 --- a/boards/arm/stm32f769i_disco/doc/index.rst +++ b/boards/arm/stm32f769i_disco/doc/index.rst @@ -132,7 +132,7 @@ Pin Mapping STM32F769I Discovery kit has 9 GPIO controllers. These controllers are responsible for pin muxing, input/output, pull-up, etc. -For mode details please refer to `32F769I-DISCO board User Manual`_. +For more details please refer to `32F769I-DISCO board User Manual`_. Default Zephyr Peripheral Mapping: ---------------------------------- diff --git a/boards/arm/stm32g071b_disco/doc/index.rst b/boards/arm/stm32g071b_disco/doc/index.rst index d7071c3d3d2..2c9cbea3176 100644 --- a/boards/arm/stm32g071b_disco/doc/index.rst +++ b/boards/arm/stm32g071b_disco/doc/index.rst @@ -109,7 +109,7 @@ Default Zephyr Peripheral Mapping: - RDCC1 : PB12 (Enable Door Sense on CC1) -For mode details please refer to `STM32G0 Discovery board User Manual`_. +For more details please refer to `STM32G0 Discovery board User Manual`_. Programming and Debugging ************************* diff --git a/boards/arm/stm32g081b_eval/doc/index.rst b/boards/arm/stm32g081b_eval/doc/index.rst index 3e2268446c3..970ec32dd0a 100644 --- a/boards/arm/stm32g081b_eval/doc/index.rst +++ b/boards/arm/stm32g081b_eval/doc/index.rst @@ -147,7 +147,7 @@ Default Zephyr Peripheral Mapping: - LED3 : PD8 - LED4 : PD9 -For mode details please refer to `STM32G0 Evaluation board User Manual`_. +For more details please refer to `STM32G0 Evaluation board User Manual`_. Programming and Debugging ************************* diff --git a/boards/arm/stm32h573i_dk/doc/index.rst b/boards/arm/stm32h573i_dk/doc/index.rst index 515371632db..a41a12f0c82 100644 --- a/boards/arm/stm32h573i_dk/doc/index.rst +++ b/boards/arm/stm32h573i_dk/doc/index.rst @@ -223,7 +223,7 @@ Connections and IOs STM32H573I-DK Discovery Board has 9 GPIO controllers. These controllers are responsible for pin muxing, input/output, pull-up, etc. -For mode details please refer to `STM32H573I-DK Discovery board User Manual`_. +For more details please refer to `STM32H573I-DK Discovery board User Manual`_. Default Zephyr Peripheral Mapping: ---------------------------------- diff --git a/boards/arm/stm32h735g_disco/doc/index.rst b/boards/arm/stm32h735g_disco/doc/index.rst index 210756e1567..473dcfa08c2 100644 --- a/boards/arm/stm32h735g_disco/doc/index.rst +++ b/boards/arm/stm32h735g_disco/doc/index.rst @@ -75,7 +75,7 @@ The default configuration per core can be found in the defconfig file: Pin Mapping =========== -For mode details please refer to `STM32H735G-DISCO website`_. +For more details please refer to `STM32H735G-DISCO website`_. Default Zephyr Peripheral Mapping: ---------------------------------- diff --git a/boards/arm/stm32h747i_disco/doc/index.rst b/boards/arm/stm32h747i_disco/doc/index.rst index d020a3ed94e..2f720ae4628 100644 --- a/boards/arm/stm32h747i_disco/doc/index.rst +++ b/boards/arm/stm32h747i_disco/doc/index.rst @@ -99,7 +99,7 @@ Pin Mapping STM32H747I Discovery kit has 9 GPIO controllers. These controllers are responsible for pin muxing, input/output, pull-up, etc. -For mode details please refer to `STM32H747I-DISCO website`_. +For more details please refer to `STM32H747I-DISCO website`_. Default Zephyr Peripheral Mapping: ---------------------------------- diff --git a/boards/arm/stm32h750b_dk/doc/index.rst b/boards/arm/stm32h750b_dk/doc/index.rst index 5b61e499e8f..6ac1aa15d34 100644 --- a/boards/arm/stm32h750b_dk/doc/index.rst +++ b/boards/arm/stm32h750b_dk/doc/index.rst @@ -65,7 +65,7 @@ The default configuration per core can be found in the defconfig file: Pin Mapping =========== -For mode details please refer to `STM32H750B-DK website`_. +For more details please refer to `STM32H750B-DK website`_. Default Zephyr Peripheral Mapping: ---------------------------------- diff --git a/boards/arm/stm32h7b3i_dk/doc/index.rst b/boards/arm/stm32h7b3i_dk/doc/index.rst index 549594bb3cc..83d18858426 100644 --- a/boards/arm/stm32h7b3i_dk/doc/index.rst +++ b/boards/arm/stm32h7b3i_dk/doc/index.rst @@ -74,7 +74,7 @@ The default configuration per core can be found in the defconfig file: Pin Mapping =========== -For mode details please refer to `STM32H7B3I-DK website`_. +For more details please refer to `STM32H7B3I-DK website`_. Default Zephyr Peripheral Mapping: ---------------------------------- diff --git a/boards/arm/stm32l1_disco/doc/index.rst b/boards/arm/stm32l1_disco/doc/index.rst index 65bb4bc028f..a968cebc792 100644 --- a/boards/arm/stm32l1_disco/doc/index.rst +++ b/boards/arm/stm32l1_disco/doc/index.rst @@ -125,7 +125,7 @@ Default Zephyr Peripheral Mapping: - SPI2_MISO : PB14 - SPI2_MOSI : PB15 -For mode details please refer to `STM32L1DISCOVERY board User Manual`_. +For more details please refer to `STM32L1DISCOVERY board User Manual`_. Programming and Debugging ************************* diff --git a/boards/arm/stm32l476g_disco/doc/index.rst b/boards/arm/stm32l476g_disco/doc/index.rst index bd4b2a5a6d5..65eef57c609 100644 --- a/boards/arm/stm32l476g_disco/doc/index.rst +++ b/boards/arm/stm32l476g_disco/doc/index.rst @@ -135,7 +135,7 @@ Connections and IOs STM32L476G Discovery Board has 8 GPIO controllers. These controllers are responsible for pin muxing, input/output, pull-up, etc. -For mode details please refer to `STM32L476G Discovery board User Manual`_. +For more details please refer to `STM32L476G Discovery board User Manual`_. Default Zephyr Peripheral Mapping: ---------------------------------- diff --git a/boards/arm/stm32l496g_disco/doc/index.rst b/boards/arm/stm32l496g_disco/doc/index.rst index 0bd31e72c38..e8bc81f092b 100644 --- a/boards/arm/stm32l496g_disco/doc/index.rst +++ b/boards/arm/stm32l496g_disco/doc/index.rst @@ -164,7 +164,7 @@ Connections and IOs STM32L496G Discovery Board has 8 GPIO controllers. These controllers are responsible for pin muxing, input/output, pull-up, etc. -For mode details please refer to `STM32L496G Discovery board User Manual`_. +For more details please refer to `STM32L496G Discovery board User Manual`_. Default Zephyr Peripheral Mapping: ---------------------------------- diff --git a/boards/arm/stm32l4r9i_disco/doc/index.rst b/boards/arm/stm32l4r9i_disco/doc/index.rst index a8f7798f840..0f651e2b9ff 100644 --- a/boards/arm/stm32l4r9i_disco/doc/index.rst +++ b/boards/arm/stm32l4r9i_disco/doc/index.rst @@ -71,7 +71,7 @@ The default configuration can be found in the defconfig file: Pin Mapping =========== -For mode details, please refer to `STM32L4R9I-DISCOVERY website`_. +For more details, please refer to `STM32L4R9I-DISCOVERY website`_. System Clock ============ diff --git a/boards/arm/stm32l562e_dk/doc/index.rst b/boards/arm/stm32l562e_dk/doc/index.rst index 5a4f5845617..f3dd058b341 100644 --- a/boards/arm/stm32l562e_dk/doc/index.rst +++ b/boards/arm/stm32l562e_dk/doc/index.rst @@ -251,7 +251,7 @@ Connections and IOs STM32L562E-DK Discovery Board has 8 GPIO controllers. These controllers are responsible for pin muxing, input/output, pull-up, etc. -For mode details please refer to `STM32L562E-DK Discovery board User Manual`_. +For more details please refer to `STM32L562E-DK Discovery board User Manual`_. Default Zephyr Peripheral Mapping: ---------------------------------- diff --git a/boards/arm/stm32u5a9j_dk/doc/index.rst b/boards/arm/stm32u5a9j_dk/doc/index.rst index 6e3e44c5942..23859666df7 100644 --- a/boards/arm/stm32u5a9j_dk/doc/index.rst +++ b/boards/arm/stm32u5a9j_dk/doc/index.rst @@ -92,7 +92,7 @@ The default configuration per core can be found in the defconfig file: Pin Mapping =========== -For mode details please refer to `STM32U5A9J-DK board User Manual`_. +For more details please refer to `STM32U5A9J-DK board User Manual`_. Default Zephyr Peripheral Mapping: ---------------------------------- diff --git a/boards/arm/stm32vl_disco/doc/index.rst b/boards/arm/stm32vl_disco/doc/index.rst index 006c8854bb4..7819200bafb 100644 --- a/boards/arm/stm32vl_disco/doc/index.rst +++ b/boards/arm/stm32vl_disco/doc/index.rst @@ -119,7 +119,7 @@ Default Zephyr Peripheral Mapping: - I2C2_SCL : PB10 - I2C2_SDA : PB11 -For mode details please refer to `STM32VLDISCOVERY board User Manual`_. +For more details please refer to `STM32VLDISCOVERY board User Manual`_. Programming and Debugging ************************* diff --git a/boards/arm/v2m_beetle/doc/index.rst b/boards/arm/v2m_beetle/doc/index.rst index 80e7af563fc..7673e510ebf 100644 --- a/boards/arm/v2m_beetle/doc/index.rst +++ b/boards/arm/v2m_beetle/doc/index.rst @@ -190,7 +190,7 @@ Peripheral Mapping: - I2C_1_SDA : D22 - I2C_1_SCL : D23 -For mode details please refer to `Beetle Technical Reference Manual (TRM)`_. +For more details please refer to `Beetle Technical Reference Manual (TRM)`_. System Clock ============ diff --git a/boards/arm/v2m_musca_b1/doc/index.rst b/boards/arm/v2m_musca_b1/doc/index.rst index f36ae79dbb4..0f0c261460a 100644 --- a/boards/arm/v2m_musca_b1/doc/index.rst +++ b/boards/arm/v2m_musca_b1/doc/index.rst @@ -205,7 +205,7 @@ Peripheral Mapping: - I2C_0_SDA : D14 - I2C_0_SCL : D15 -For mode details please refer to `Musca B1 Technical Reference Manual (TRM)`_. +For more details please refer to `Musca B1 Technical Reference Manual (TRM)`_. RGB LED diff --git a/boards/arm/v2m_musca_s1/doc/index.rst b/boards/arm/v2m_musca_s1/doc/index.rst index 4c8f4fcc0c1..8a1c4b221bd 100644 --- a/boards/arm/v2m_musca_s1/doc/index.rst +++ b/boards/arm/v2m_musca_s1/doc/index.rst @@ -199,7 +199,7 @@ Peripheral Mapping: - I2C_0_SDA : D14 - I2C_0_SCL : D15 -For mode details please refer to `Musca-S1 Technical Reference Manual (TRM)`_. +For more details please refer to `Musca-S1 Technical Reference Manual (TRM)`_. RGB LED From 1ebaa293a12d9dde715e6610c0dd341a824aae2c Mon Sep 17 00:00:00 2001 From: Henrik Brix Andersen Date: Sun, 7 Jan 2024 19:31:03 +0100 Subject: [PATCH 1930/3723] dts: bindings: adc: ti: lmp90xxx: use common io-channel-cells naming Use the common io-channel-cells name "input" instead of "positive" and "negative" to make this binding work with the various ADC DT macros. Signed-off-by: Henrik Brix Andersen --- boards/shields/lmp90100_evb/lmp90100_evb.overlay | 2 +- dts/bindings/adc/ti,lmp90xxx-base.yaml | 5 ++--- .../build_all/adc/boards/native_sim.overlay | 16 ++++++++-------- 3 files changed, 11 insertions(+), 12 deletions(-) diff --git a/boards/shields/lmp90100_evb/lmp90100_evb.overlay b/boards/shields/lmp90100_evb/lmp90100_evb.overlay index 600eefdb127..5b17aa9ff91 100644 --- a/boards/shields/lmp90100_evb/lmp90100_evb.overlay +++ b/boards/shields/lmp90100_evb/lmp90100_evb.overlay @@ -13,7 +13,7 @@ spi-max-frequency = <1000000>; /* Uncomment to use IRQ instead of polling: */ /* drdyb-gpios = <&arduino_header 15 GPIO_ACTIVE_LOW>; */ - #io-channel-cells = <2>; + #io-channel-cells = <1>; lmp90100_gpio: gpio { compatible = "ti,lmp90xxx-gpio"; diff --git a/dts/bindings/adc/ti,lmp90xxx-base.yaml b/dts/bindings/adc/ti,lmp90xxx-base.yaml index 4225c9b0cc3..8c0bb066b80 100644 --- a/dts/bindings/adc/ti,lmp90xxx-base.yaml +++ b/dts/bindings/adc/ti,lmp90xxx-base.yaml @@ -10,8 +10,7 @@ properties: description: Data Ready Bar "#io-channel-cells": - const: 2 + const: 1 io-channel-cells: - - positive - - negative + - input diff --git a/tests/drivers/build_all/adc/boards/native_sim.overlay b/tests/drivers/build_all/adc/boards/native_sim.overlay index 120e05dcfb0..cc7ac9a45e2 100644 --- a/tests/drivers/build_all/adc/boards/native_sim.overlay +++ b/tests/drivers/build_all/adc/boards/native_sim.overlay @@ -140,7 +140,7 @@ reg = <0x1>; spi-max-frequency = <0>; drdyb-gpios = <&test_gpio 0 0>; - #io-channel-cells = <2>; + #io-channel-cells = <1>; }; test_spi_lmp90078: lmp90078@2 { @@ -148,7 +148,7 @@ reg = <0x2>; spi-max-frequency = <0>; drdyb-gpios = <&test_gpio 0 0>; - #io-channel-cells = <2>; + #io-channel-cells = <1>; }; test_spi_lmp90079: lmp90079@3 { @@ -156,7 +156,7 @@ reg = <0x3>; spi-max-frequency = <0>; drdyb-gpios = <&test_gpio 0 0>; - #io-channel-cells = <2>; + #io-channel-cells = <1>; }; test_spi_lmp90080: lmp90080@4 { @@ -164,7 +164,7 @@ reg = <0x4>; spi-max-frequency = <0>; drdyb-gpios = <&test_gpio 0 0>; - #io-channel-cells = <2>; + #io-channel-cells = <1>; }; test_spi_lmp90097: lmp90097@5 { @@ -172,7 +172,7 @@ reg = <0x5>; spi-max-frequency = <0>; drdyb-gpios = <&test_gpio 0 0>; - #io-channel-cells = <2>; + #io-channel-cells = <1>; }; test_spi_lmp90098: lmp90098@6 { @@ -180,7 +180,7 @@ reg = <0x6>; spi-max-frequency = <0>; drdyb-gpios = <&test_gpio 0 0>; - #io-channel-cells = <2>; + #io-channel-cells = <1>; }; test_spi_lmp90099: lmp90099@7 { @@ -188,7 +188,7 @@ reg = <0x7>; spi-max-frequency = <0>; drdyb-gpios = <&test_gpio 0 0>; - #io-channel-cells = <2>; + #io-channel-cells = <1>; }; test_spi_lmp90100: lmp90100@8 { @@ -196,7 +196,7 @@ reg = <0x8>; spi-max-frequency = <0>; drdyb-gpios = <&test_gpio 0 0>; - #io-channel-cells = <2>; + #io-channel-cells = <1>; }; test_spi_ads7052: ads7052@9 { From 527383f9b198792cc20c4e82997a52b001e9e682 Mon Sep 17 00:00:00 2001 From: Henrik Brix Andersen Date: Sun, 7 Jan 2024 19:33:25 +0100 Subject: [PATCH 1931/3723] doc: release: migration-guide: 3.6: mention change in lmp90xxx bindings Mention the change in the ti,lmp90xxx bindings to use the common io-channel-cells name "input" instead of "positive" and "negative". Signed-off-by: Henrik Brix Andersen --- doc/releases/migration-guide-3.6.rst | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/doc/releases/migration-guide-3.6.rst b/doc/releases/migration-guide-3.6.rst index 434bc9368c5..22321e8e9b9 100644 --- a/doc/releases/migration-guide-3.6.rst +++ b/doc/releases/migration-guide-3.6.rst @@ -146,6 +146,19 @@ Device Drivers and Device Tree * The main Kconfig option was renamed from ``CONFIG_CAN_NATIVE_POSIX_LINUX`` to :kconfig:option:`CONFIG_CAN_NATIVE_LINUX`. +* The io-channel cells of the following devicetree bindings were reduced from 2 (``positive`` and + ``negative``) to the common ``input``, making it possible to use the various ADC DT macros with TI + LMP90xxx ADC devices: + + * :dtcompatible:`ti,lmp90077` + * :dtcompatible:`ti,lmp90078` + * :dtcompatible:`ti,lmp90079` + * :dtcompatible:`ti,lmp90080` + * :dtcompatible:`ti,lmp90097` + * :dtcompatible:`ti,lmp90098` + * :dtcompatible:`ti,lmp90099` + * :dtcompatible:`ti,lmp90100` + Power Management ================ From df83fffc7c269fcfb3ede0037ea2a0a106a2ae41 Mon Sep 17 00:00:00 2001 From: Henrik Brix Andersen Date: Sun, 7 Jan 2024 19:34:43 +0100 Subject: [PATCH 1932/3723] boards: shields: lmp90100_evb: include relevant dt-bindings headers Include zephyr/dt-bindings/adc/adc.h and zephyr/dt-bindings/gpio/gpio.h in the shield DTS overlays to simplify using this shield in application overlays. Signed-off-by: Henrik Brix Andersen --- boards/shields/lmp90100_evb/lmp90100_evb.overlay | 3 +++ 1 file changed, 3 insertions(+) diff --git a/boards/shields/lmp90100_evb/lmp90100_evb.overlay b/boards/shields/lmp90100_evb/lmp90100_evb.overlay index 5b17aa9ff91..7271c9c7c3d 100644 --- a/boards/shields/lmp90100_evb/lmp90100_evb.overlay +++ b/boards/shields/lmp90100_evb/lmp90100_evb.overlay @@ -4,6 +4,9 @@ * SPDX-License-Identifier: Apache-2.0 */ +#include +#include + &arduino_spi { status = "okay"; From d856ed73f4c64e0f981a6f7cb5e4b44a0b0576fa Mon Sep 17 00:00:00 2001 From: Henrik Brix Andersen Date: Sun, 7 Jan 2024 19:36:27 +0100 Subject: [PATCH 1933/3723] samples: shields: lmp90100_evb: rtd: convert to devicetree configuration Convert the sample for the lmp90100_evb shield to use devicetree for configuring the ADC channel. Signed-off-by: Henrik Brix Andersen --- samples/shields/lmp90100_evb/rtd/app.overlay | 22 +++++++++- samples/shields/lmp90100_evb/rtd/src/main.c | 44 ++++++++------------ 2 files changed, 38 insertions(+), 28 deletions(-) diff --git a/samples/shields/lmp90100_evb/rtd/app.overlay b/samples/shields/lmp90100_evb/rtd/app.overlay index 7ea69d39c83..27044a27865 100644 --- a/samples/shields/lmp90100_evb/rtd/app.overlay +++ b/samples/shields/lmp90100_evb/rtd/app.overlay @@ -1,9 +1,29 @@ /* - * Copyright (c) 2019 Vestas Wind Systems A/S + * Copyright (c) 2019-2024 Vestas Wind Systems A/S * * SPDX-License-Identifier: Apache-2.0 */ +/ { + zephyr,user { + io-channels = <&lmp90100_lmp90100_evb 0>; + }; +}; + &lmp90100_lmp90100_evb { + #address-cells = <1>; + #size-cells = <0>; + rtd-current = <1000>; + + channel@0 { + reg = <0>; + zephyr,gain = "ADC_GAIN_1"; + zephyr,reference = "ADC_REF_EXTERNAL1"; + zephyr,acquisition-time = ; + zephyr,resolution = <24>; + zephyr,differential; + zephyr,input-positive = <0>; + zephyr,input-negative = <1>; + }; }; diff --git a/samples/shields/lmp90100_evb/rtd/src/main.c b/samples/shields/lmp90100_evb/rtd/src/main.c index 939f2c331ad..040a1d23509 100644 --- a/samples/shields/lmp90100_evb/rtd/src/main.c +++ b/samples/shields/lmp90100_evb/rtd/src/main.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2019 Vestas Wind Systems A/S + * Copyright (c) 2019-2024 Vestas Wind Systems A/S * * SPDX-License-Identifier: Apache-2.0 */ @@ -17,11 +17,8 @@ LOG_MODULE_REGISTER(main); /* Nominal RTD (PT100) resistance in ohms */ #define RTD_NOMINAL_RESISTANCE 100 -/* ADC resolution in bits */ -#define ADC_RESOLUTION 24U - /* ADC maximum value (taking sign bit into consideration) */ -#define ADC_MAX BIT_MASK(ADC_RESOLUTION - 1) +#define ADC_MAX(resolution) BIT_MASK(resolution - 1) /* Bottom resistor value in ohms */ #define BOTTOM_RESISTANCE 2000 @@ -42,46 +39,39 @@ static double rtd_temperature(int nom, double resistance) int main(void) { - const struct device *const lmp90100 = DEVICE_DT_GET_ONE(ti_lmp90100); + const struct adc_dt_spec ch_cfg = ADC_DT_SPEC_GET(DT_PATH(zephyr_user)); + double adc_max = ADC_MAX(ch_cfg.resolution); double resistance; int32_t buffer; int err; - const struct adc_channel_cfg ch_cfg = { - .channel_id = 0, - .differential = 1, - .input_positive = 0, - .input_negative = 1, - .reference = ADC_REF_EXTERNAL1, - .gain = ADC_GAIN_1, - .acquisition_time = ADC_ACQ_TIME(ADC_ACQ_TIME_TICKS, 0) - }; - const struct adc_sequence seq = { - .options = NULL, - .channels = BIT(0), + struct adc_sequence seq = { .buffer = &buffer, .buffer_size = sizeof(buffer), - .resolution = ADC_RESOLUTION, - .oversampling = 0, - .calibrate = 0 }; - if (!device_is_ready(lmp90100)) { + if (!adc_is_ready_dt(&ch_cfg)) { LOG_ERR("LMP90100 device not ready"); return 0; } - err = adc_channel_setup(lmp90100, &ch_cfg); - if (err) { + err = adc_channel_setup_dt(&ch_cfg); + if (err != 0) { LOG_ERR("failed to setup ADC channel (err %d)", err); return 0; } + err = adc_sequence_init_dt(&ch_cfg, &seq); + if (err != 0) { + LOG_ERR("failed to initialize ADC sequence (err %d)", err); + return 0; + } + while (true) { - err = adc_read(lmp90100, &seq); - if (err) { + err = adc_read_dt(&ch_cfg, &seq); + if (err != 0) { LOG_ERR("failed to read ADC (err %d)", err); } else { - resistance = (buffer / (double)ADC_MAX) * BOTTOM_RESISTANCE; + resistance = (buffer / adc_max) * BOTTOM_RESISTANCE; printf("R: %.02f ohm\n", resistance); printf("T: %.02f degC\n", rtd_temperature(RTD_NOMINAL_RESISTANCE, From 754f7ac1fb4a68538842b9de8492b09d4c193674 Mon Sep 17 00:00:00 2001 From: Aaron Ye Date: Mon, 8 Jan 2024 09:46:07 +0800 Subject: [PATCH 1934/3723] MAINTAINERS.yml: Update the Ambiq platform covered files Current setting missed some necessary files which should be covered by Ambiq platforms. Add them in this commit. Signed-off-by: Aaron Ye --- MAINTAINERS.yml | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/MAINTAINERS.yml b/MAINTAINERS.yml index 1ae22144b50..1dffa8e82fc 100644 --- a/MAINTAINERS.yml +++ b/MAINTAINERS.yml @@ -252,8 +252,10 @@ Ambiq Platforms: - soc/arm/ambiq/ - boards/arm/apollo*/ - dts/arm/ambiq/ - - dts/bindings/*/ambiq* - - drivers/*/*_ambiq* + - dts/bindings/*/ambiq,* + - drivers/*/*ambiq* + - drivers/*/*/*ambiq* + - drivers/*/*/*apollo* labels: - "platform: Ambiq" From b4a059df75ab6c84f66c05bf9c2feb89c60d228e Mon Sep 17 00:00:00 2001 From: Pieter De Gendt Date: Mon, 8 Jan 2024 14:40:42 +0100 Subject: [PATCH 1935/3723] drivers: mdio: nxp_enet: Fix "expected statement" clangsa error clangsa reports the error mdio_nxp_enet.c:245:10: error: label at end of compound statement: expected statement Signed-off-by: Pieter De Gendt --- drivers/mdio/mdio_nxp_enet.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/mdio/mdio_nxp_enet.c b/drivers/mdio/mdio_nxp_enet.c index 1a5c54145b4..6b5c128e075 100644 --- a/drivers/mdio/mdio_nxp_enet.c +++ b/drivers/mdio/mdio_nxp_enet.c @@ -243,6 +243,7 @@ void nxp_enet_mdio_callback(const struct device *dev, data->interrupt_up = true; break; default: + break; } } From 7ef2744e2fe06c715244f69ca6b453d62a1685c3 Mon Sep 17 00:00:00 2001 From: Daniel DeGrasse Date: Mon, 8 Jan 2024 17:45:10 +0000 Subject: [PATCH 1936/3723] drivers: i2c: i2c_mcux_lpi2c: fix base address declarations With commit 734adf52c60, the MCUX LPI2C config structure no longer contains a direct base address pointer. The base address must be accessed via DEVICE_MMIO_NAMED_GET. Some declarations in the LPCI2C target mode handler still used the old method of accessing the base address, causing a build failure. Fix these accesses to use the local declaration of the "base" variable. Signed-off-by: Daniel DeGrasse --- drivers/i2c/i2c_mcux_lpi2c.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/drivers/i2c/i2c_mcux_lpi2c.c b/drivers/i2c/i2c_mcux_lpi2c.c index e1706e3af27..099633beeeb 100644 --- a/drivers/i2c/i2c_mcux_lpi2c.c +++ b/drivers/i2c/i2c_mcux_lpi2c.c @@ -338,7 +338,7 @@ static void mcux_lpi2c_slave_irq_handler(const struct device *dev) if (flags & kLPI2C_SlaveRxReadyFlag) { /* RX data is available, read it and issue callback */ - i2c_data = (uint8_t)config->base->SRDR; + i2c_data = (uint8_t)base->SRDR; if (data->first_tx) { data->first_tx = false; if (target_cb->write_requested) { @@ -372,7 +372,7 @@ static void mcux_lpi2c_slave_irq_handler(const struct device *dev) data->read_active = false; } else { /* Send I2C data */ - config->base->STDR = i2c_data; + base->STDR = i2c_data; } } } else if (data->read_active) { @@ -384,7 +384,7 @@ static void mcux_lpi2c_slave_irq_handler(const struct device *dev) data->read_active = false; } else { /* Send I2C data */ - config->base->STDR = i2c_data; + base->STDR = i2c_data; } } } From 0198b7d5f789820db487b6890ea4a0c0000bc07c Mon Sep 17 00:00:00 2001 From: Tristan Honscheid Date: Mon, 8 Jan 2024 12:20:32 -0700 Subject: [PATCH 1937/3723] emul: Add stub `release` impl. for emulated SPI driver `release` is a mandatory method in the `struct spi_driver_api` API but is not implemented in the SPI emulator. This can cause a test calling `spi_release()` to segfault. Add a stub implementation that just returns zero. Signed-off-by: Tristan Honscheid --- drivers/spi/spi_emul.c | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/drivers/spi/spi_emul.c b/drivers/spi/spi_emul.c index 5d60acae802..f92d0c95136 100644 --- a/drivers/spi/spi_emul.c +++ b/drivers/spi/spi_emul.c @@ -81,6 +81,18 @@ static int spi_emul_io(const struct device *dev, const struct spi_config *config return api->io(emul->target, config, tx_bufs, rx_bufs); } +/** + * @brief This is a no-op stub of the SPI API's `release` method to protect drivers under test + * from hitting a segmentation fault when using SPI_LOCK_ON plus spi_release() + */ +static int spi_emul_release(const struct device *dev, const struct spi_config *config) +{ + ARG_UNUSED(dev); + ARG_UNUSED(config); + + return 0; +} + /** * Set up a new emulator and add it to the list * @@ -111,6 +123,7 @@ int spi_emul_register(const struct device *dev, struct spi_emul *emul) static const struct spi_driver_api spi_emul_api = { .transceive = spi_emul_io, + .release = spi_emul_release, }; #define EMUL_LINK_AND_COMMA(node_id) \ From 72c6ffb2d04bf1d9c23e0ef71464b3693d96ba98 Mon Sep 17 00:00:00 2001 From: Anas Nashif Date: Mon, 8 Jan 2024 18:02:45 -0500 Subject: [PATCH 1938/3723] doc: ztest: remove reference to non-existing test custom_output test does not exist anymore. Fixes #67168 Signed-off-by: Anas Nashif --- doc/develop/test/ztest.rst | 3 --- 1 file changed, 3 deletions(-) diff --git a/doc/develop/test/ztest.rst b/doc/develop/test/ztest.rst index c2d7cd0923e..124fd415c23 100644 --- a/doc/develop/test/ztest.rst +++ b/doc/develop/test/ztest.rst @@ -553,9 +553,6 @@ See :ref:`FFF Extensions `. Customizing Test Output *********************** -The way output is presented when running tests can be customized. -An example can be found in :zephyr_file:`tests/ztest/custom_output`. - Customization is enabled by setting :kconfig:option:`CONFIG_ZTEST_TC_UTIL_USER_OVERRIDE` to "y" and adding a file :file:`tc_util_user_override.h` with your overrides. From 3f6373eb364bcb3d91ae3733509c41f9673785c3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andrzej=20G=C5=82=C4=85bek?= Date: Tue, 19 Dec 2023 12:57:39 +0100 Subject: [PATCH 1939/3723] drivers: nrf_qspi_nor: Deactivate QSPI peripheral after initialization MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This is a follow-up to commit ea1be7f242b9348863a27adb17215014f15b318a. After the driver performs its initialization, it needs to deactivate the QSPI peripheral. Otherwise, the peripheral would unnecessarily consume power until some QSPI operation is performed (and only then it will get deactivated), what depending on the application may take a significant amount of time. Signed-off-by: Andrzej Głąbek --- drivers/flash/nrf_qspi_nor.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/drivers/flash/nrf_qspi_nor.c b/drivers/flash/nrf_qspi_nor.c index b9c3af9ca5c..c0e8c397d8e 100644 --- a/drivers/flash/nrf_qspi_nor.c +++ b/drivers/flash/nrf_qspi_nor.c @@ -1090,6 +1090,10 @@ static int qspi_nor_init(const struct device *dev) qspi_clock_div_restore(); + if (!IS_ENABLED(CONFIG_NORDIC_QSPI_NOR_XIP) && nrfx_qspi_init_check()) { + (void)nrfx_qspi_deactivate(); + } + #ifdef CONFIG_PM_DEVICE_RUNTIME int rc2 = pm_device_runtime_enable(dev); From db4344b6591c8a0477d15ebd892a5ccd1d13b1b9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andrzej=20G=C5=82=C4=85bek?= Date: Fri, 5 Jan 2024 10:26:59 +0100 Subject: [PATCH 1940/3723] drivers: spi: nrfx: Deactivate CS from thread context MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit ... so that it is possible to use a GPIO expander pin as the CS line. Communication with the expander may involve an operation that cannot be done from the interrupt context (e.g. an I2C transaction). Signed-off-by: Andrzej Głąbek --- drivers/spi/spi_nrfx_spi.c | 4 ++-- drivers/spi/spi_nrfx_spim.c | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/drivers/spi/spi_nrfx_spi.c b/drivers/spi/spi_nrfx_spi.c index 04d7853d11d..752132fb248 100644 --- a/drivers/spi/spi_nrfx_spi.c +++ b/drivers/spi/spi_nrfx_spi.c @@ -161,8 +161,6 @@ static void finish_transaction(const struct device *dev, int error) struct spi_nrfx_data *dev_data = dev->data; struct spi_context *ctx = &dev_data->ctx; - spi_context_cs_control(ctx, false); - LOG_DBG("Transaction finished with status %d", error); spi_context_complete(ctx, dev, error); @@ -277,6 +275,8 @@ static int transceive(const struct device *dev, /* Clean up the driver state. */ k_sem_reset(&dev_data->ctx.sync); } + + spi_context_cs_control(&dev_data->ctx, false); } spi_context_release(&dev_data->ctx, error); diff --git a/drivers/spi/spi_nrfx_spim.c b/drivers/spi/spi_nrfx_spim.c index 95b737d6cf5..08012b389c5 100644 --- a/drivers/spi/spi_nrfx_spim.c +++ b/drivers/spi/spi_nrfx_spim.c @@ -294,8 +294,6 @@ static void finish_transaction(const struct device *dev, int error) struct spi_nrfx_data *dev_data = dev->data; struct spi_context *ctx = &dev_data->ctx; - spi_context_cs_control(ctx, false); - LOG_DBG("Transaction finished with status %d", error); spi_context_complete(ctx, dev, error); @@ -470,6 +468,8 @@ static int transceive(const struct device *dev, anomaly_58_workaround_clear(dev_data); #endif } + + spi_context_cs_control(&dev_data->ctx, false); } spi_context_release(&dev_data->ctx, error); From 56b6e6eb5878ee3bf405987f4d32cf12260b37a2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andrzej=20G=C5=82=C4=85bek?= Date: Fri, 5 Jan 2024 16:23:28 +0100 Subject: [PATCH 1941/3723] samples: boards: nrfx: Use absolute pin numbers MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This sample makes calls to the nrfx_gpiote driver functions that require absolute pin numbers, not relative to a given GPIO port, so instead of getting the numbers with the `DT_GPIO_PIN` macro, it should use `NRF_DT_GPIOS_TO_PSEL`. Signed-off-by: Andrzej Głąbek --- samples/boards/nrf/nrfx/src/main.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/samples/boards/nrf/nrfx/src/main.c b/samples/boards/nrf/nrfx/src/main.c index 0643b1c0911..49a3896ad0f 100644 --- a/samples/boards/nrf/nrfx/src/main.c +++ b/samples/boards/nrf/nrfx/src/main.c @@ -18,8 +18,8 @@ #include LOG_MODULE_REGISTER(nrfx_sample, LOG_LEVEL_INF); -#define INPUT_PIN DT_GPIO_PIN(DT_ALIAS(sw0), gpios) -#define OUTPUT_PIN DT_GPIO_PIN(DT_ALIAS(led0), gpios) +#define INPUT_PIN NRF_DT_GPIOS_TO_PSEL(DT_ALIAS(sw0), gpios) +#define OUTPUT_PIN NRF_DT_GPIOS_TO_PSEL(DT_ALIAS(led0), gpios) #define GPIOTE_INST NRF_DT_GPIOTE_INST(DT_ALIAS(sw0), gpios) #define GPIOTE_NODE DT_NODELABEL(_CONCAT(gpiote, GPIOTE_INST)) From e8d3bf5ff61435fb94702db597ea4144a2e6fc45 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andrzej=20G=C5=82=C4=85bek?= Date: Fri, 5 Jan 2024 16:38:17 +0100 Subject: [PATCH 1942/3723] samples: boards: nrfx: Do not require (d)ppi node to be enabled MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The sample needs to check in Kconfig whether PPI or DPPI is present on the target platform in order to enable the proper allocator in nrfx. It should not use the `HAS_HW_NRF_*` symbols for this as those take into account also the status of the corresponding DT node, not only its presence. Signed-off-by: Andrzej Głąbek --- samples/boards/nrf/nrfx/Kconfig | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/samples/boards/nrf/nrfx/Kconfig b/samples/boards/nrf/nrfx/Kconfig index 09076c9da49..a46af347ba9 100644 --- a/samples/boards/nrf/nrfx/Kconfig +++ b/samples/boards/nrf/nrfx/Kconfig @@ -2,10 +2,10 @@ # SPDX-License-Identifier: Apache-2.0 config NRFX_DPPI - default HAS_HW_NRF_DPPIC + default $(dt_has_compat,$(DT_COMPAT_NORDIC_NRF_DPPIC)) config NRFX_PPI - default HAS_HW_NRF_PPI + default $(dt_has_compat,$(DT_COMPAT_NORDIC_NRF_PPI)) config NRFX_GPIOTE0 default y if SOC_SERIES_NRF51X || \ From 6d67b95a18e08104bb8a33e676b8f32e133c7a47 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andrzej=20G=C5=82=C4=85bek?= Date: Fri, 5 Jan 2024 17:42:17 +0100 Subject: [PATCH 1943/3723] samples: boards: nrfx: Remove redundant inclusions MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This is a follow-up to commit c7e4d23c5d96421feb824ce2b9172f18b7946398. After all calls to `nrfx_dppi_*` and `nrfx_ppi_*` functions were replaced with corresponding `nrfx_gppi_*` calls, it is no longer needed to include the `nrfx_dppi.h` and `nrfx_ppi.h` headers. Signed-off-by: Andrzej Głąbek --- samples/boards/nrf/nrfx/src/main.c | 5 ----- 1 file changed, 5 deletions(-) diff --git a/samples/boards/nrf/nrfx/src/main.c b/samples/boards/nrf/nrfx/src/main.c index 49a3896ad0f..8b3819f2d8a 100644 --- a/samples/boards/nrf/nrfx/src/main.c +++ b/samples/boards/nrf/nrfx/src/main.c @@ -8,11 +8,6 @@ #include #include -#if defined(DPPI_PRESENT) -#include -#else -#include -#endif #include #include From 8ca40e5ebfb6db02c8c2e7312f1c43436028234e Mon Sep 17 00:00:00 2001 From: Fabio Baltieri Date: Tue, 19 Dec 2023 15:11:37 +0000 Subject: [PATCH 1944/3723] drivers: input: depend on multithreading on drivers using a thread These all require threads support to function, add a "depends on MULTITHREADING" accordingly. Signed-off-by: Fabio Baltieri --- drivers/input/Kconfig.evdev | 1 + drivers/input/Kconfig.it8xxx2 | 1 - drivers/input/Kconfig.kbd_matrix | 1 + drivers/input/Kconfig.npcx | 1 - 4 files changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/input/Kconfig.evdev b/drivers/input/Kconfig.evdev index ed2ac16d812..568797800f3 100644 --- a/drivers/input/Kconfig.evdev +++ b/drivers/input/Kconfig.evdev @@ -6,6 +6,7 @@ config NATIVE_LINUX_EVDEV default y depends on DT_HAS_ZEPHYR_NATIVE_LINUX_EVDEV_ENABLED depends on ARCH_POSIX + depends on MULTITHREADING help Enable reading input from a Linux evdev device, requires specifying an evdev device path in the --evdev command line argument. diff --git a/drivers/input/Kconfig.it8xxx2 b/drivers/input/Kconfig.it8xxx2 index 6e729b27c3a..0c59b342534 100644 --- a/drivers/input/Kconfig.it8xxx2 +++ b/drivers/input/Kconfig.it8xxx2 @@ -6,6 +6,5 @@ config INPUT_ITE_IT8XXX2_KBD default y depends on DT_HAS_ITE_IT8XXX2_KBD_ENABLED select INPUT_KBD_MATRIX - select MULTITHREADING help This option enables the ITE keyboard scan driver. diff --git a/drivers/input/Kconfig.kbd_matrix b/drivers/input/Kconfig.kbd_matrix index 18f17b815a9..4532b270f9c 100644 --- a/drivers/input/Kconfig.kbd_matrix +++ b/drivers/input/Kconfig.kbd_matrix @@ -3,6 +3,7 @@ config INPUT_KBD_MATRIX bool + depends on MULTITHREADING help Enable library used for keyboard matrix drivers. diff --git a/drivers/input/Kconfig.npcx b/drivers/input/Kconfig.npcx index ef380b0ca4b..07c2e301944 100644 --- a/drivers/input/Kconfig.npcx +++ b/drivers/input/Kconfig.npcx @@ -8,7 +8,6 @@ config INPUT_NPCX_KBD default y depends on DT_HAS_NUVOTON_NPCX_KBD_ENABLED select INPUT_KBD_MATRIX - select MULTITHREADING help This option enables the keyboard scan driver for NPCX family of processors. From 91841587d6fd3dd5975a595ee819f429487b1ec1 Mon Sep 17 00:00:00 2001 From: Anas Nashif Date: Tue, 9 Jan 2024 07:20:03 -0500 Subject: [PATCH 1945/3723] ztest: fix ztest_run_test_suite usage and macros Fix usage of ztest_run_test_suite that was missed when introducing shell support. Signed-off-by: Anas Nashif --- .../ztest/include/zephyr/ztest_test.h | 4 +- tests/kernel/timer/timer_behavior/src/main.c | 4 +- tests/ztest/base/src/main_deprecated.c | 46 ------------------- 3 files changed, 4 insertions(+), 50 deletions(-) delete mode 100644 tests/ztest/base/src/main_deprecated.c diff --git a/subsys/testsuite/ztest/include/zephyr/ztest_test.h b/subsys/testsuite/ztest/include/zephyr/ztest_test.h index 120848f26a7..eb6d16cf784 100644 --- a/subsys/testsuite/ztest/include/zephyr/ztest_test.h +++ b/subsys/testsuite/ztest/include/zephyr/ztest_test.h @@ -547,8 +547,8 @@ void ztest_simple_1cpu_after(void *data); * * @param suite Test suite to run. */ -#define ztest_run_test_suite(suite) z_ztest_run_test_suite(STRINGIFY(suite), \ - int suite_iter, int case_iter) +#define ztest_run_test_suite(suite, shuffle, suite_iter, case_iter) \ + z_ztest_run_test_suite(STRINGIFY(suite), shuffle, suite_iter, case_iter) /** * @brief Structure for architecture specific APIs diff --git a/tests/kernel/timer/timer_behavior/src/main.c b/tests/kernel/timer/timer_behavior/src/main.c index f3806198e8a..427b88b75d2 100644 --- a/tests/kernel/timer/timer_behavior/src/main.c +++ b/tests/kernel/timer/timer_behavior/src/main.c @@ -8,8 +8,8 @@ void test_main(void) { - ztest_run_test_suite(timer_jitter_drift); + ztest_run_test_suite(timer_jitter_drift, false, 1, 1); #ifndef CONFIG_TIMER_EXTERNAL_TEST - ztest_run_test_suite(timer_tick_train); + ztest_run_test_suite(timer_tick_train, false, 1, 1); #endif } diff --git a/tests/ztest/base/src/main_deprecated.c b/tests/ztest/base/src/main_deprecated.c deleted file mode 100644 index 0a561cc8066..00000000000 --- a/tests/ztest/base/src/main_deprecated.c +++ /dev/null @@ -1,46 +0,0 @@ -/* - * Copyright (c) 2016 Intel Corporation - * - * SPDX-License-Identifier: Apache-2.0 - */ - -#include - -static void test_empty_test(void) -{ -} - -static void test_assert_tests(void) -{ - zassert_true(1); - zassert_false(0); - zassert_is_null(NULL, NULL); - zassert_not_null("foo", NULL); - zassert_equal(1, 1); - zassert_equal_ptr(NULL, NULL, NULL); -} - -static void test_assert_mem_equal(void) -{ - static const uint32_t expected[4] = { - 0x1234, - 0x5678, - 0x9ABC, - 0xDEF0 - }; - uint32_t actual[4] = {0}; - - memcpy(actual, expected, sizeof(actual)); - zassert_mem_equal(actual, expected, sizeof(expected), NULL); -} - -void test_main(void) -{ - ztest_test_suite(framework_tests, - ztest_unit_test(test_empty_test), - ztest_unit_test(test_assert_tests), - ztest_unit_test(test_assert_mem_equal) - ); - - ztest_run_test_suite(framework_tests); -} From d9c0d6981a1a6901512e503a6bb84de6488b7e93 Mon Sep 17 00:00:00 2001 From: Sateesh Kotapati Date: Thu, 21 Dec 2023 14:57:45 +0530 Subject: [PATCH 1946/3723] gecko: sl_assert, sl_common files updated | Update to GSDK 4.4.0 Added the sl_assert, sl_common, em_core_generic, em_system_generic files and updated related files in gecko/common and gecko/emlib to include the mentioned files. Signed-off-by: Sateesh Kotapati --- west.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/west.yml b/west.yml index be923f8a989..571decadd94 100644 --- a/west.yml +++ b/west.yml @@ -219,7 +219,7 @@ manifest: groups: - hal - name: hal_silabs - revision: 7a6ba7ce989c3c466b4cb450e44858a3bb0a949a + revision: e670e749760e7a77a75c69f2c932b345cc0e212f path: modules/hal/silabs groups: - hal From 240bd8e16ac1f714356843720925387225de8df0 Mon Sep 17 00:00:00 2001 From: Michael Arnold Date: Wed, 15 Nov 2023 16:36:36 +0000 Subject: [PATCH 1947/3723] runners: jlink: Add support for J-Link over IP Add support for J-Link over IP and J-Link remote server. If the "--dev-id" is a valid ip, the transport over ip is selected. Otherwise usb is selected. Signed-off-by: Michael Arnold --- scripts/west_commands/runners/jlink.py | 20 ++++++++++++++------ 1 file changed, 14 insertions(+), 6 deletions(-) diff --git a/scripts/west_commands/runners/jlink.py b/scripts/west_commands/runners/jlink.py index 4fa71720673..17d60787745 100644 --- a/scripts/west_commands/runners/jlink.py +++ b/scripts/west_commands/runners/jlink.py @@ -5,6 +5,7 @@ '''Runner for debugging with J-Link.''' import argparse +import ipaddress import logging import os from pathlib import Path @@ -25,6 +26,13 @@ DEFAULT_JLINK_EXE = 'JLink.exe' if sys.platform == 'win32' else 'JLinkExe' DEFAULT_JLINK_GDB_PORT = 2331 +def is_ip(ip): + try: + ipaddress.ip_address(ip) + except ValueError: + return False + return True + class ToggleAction(argparse.Action): def __call__(self, parser, args, ignored, option): @@ -80,7 +88,8 @@ def capabilities(cls): @classmethod def dev_id_help(cls) -> str: return '''Device identifier. Use it to select the J-Link Serial Number - of the device connected over USB.''' + of the device connected over USB. If the J-Link is connected over ip, + the Device identifier is the ip.''' @classmethod def tool_opt_help(cls) -> str: @@ -226,9 +235,9 @@ def do_run(self, command, **kwargs): 'RTOSPlugin_Zephyr') server_cmd = ([self.gdbserver] + - # only USB connections supported - ['-select', 'usb' + (f'={self.dev_id}' - if self.dev_id else ''), + ['-select', + ('ip' if is_ip(self.dev_id) else 'usb') + + (f'={self.dev_id}' if self.dev_id else ''), '-port', str(self.gdb_port), '-if', self.iface, '-speed', self.speed, @@ -355,8 +364,7 @@ def flash(self, **kwargs): loader_details = "?" + self.loader cmd = ([self.commander] + - # only USB connections supported - (['-USB', f'{self.dev_id}'] if self.dev_id else []) + + (['-IP', f'{self.dev_id}'] if is_ip(self.dev_id) else (['-USB', f'{self.dev_id}'] if self.dev_id else [])) + (['-nogui', '1'] if self.supports_nogui else []) + ['-if', self.iface, '-speed', self.speed, From 7ff715b8485685c45c4a470f98971e793d538a2e Mon Sep 17 00:00:00 2001 From: Jamie McCrae Date: Fri, 15 Dec 2023 13:22:19 +0000 Subject: [PATCH 1948/3723] doc: release: 3.6: Add note on sysbuild shield fix Adds a note that the sysbuild shield fix has been applied Signed-off-by: Jamie McCrae --- doc/releases/release-notes-3.6.rst | 2 ++ 1 file changed, 2 insertions(+) diff --git a/doc/releases/release-notes-3.6.rst b/doc/releases/release-notes-3.6.rst index 4a3a0e3eb91..d213ccba259 100644 --- a/doc/releases/release-notes-3.6.rst +++ b/doc/releases/release-notes-3.6.rst @@ -144,6 +144,8 @@ Build system and infrastructure * Fixed an issue whereby shields were processed in order of the root they resided in rather than the order they were supplied to cmake in. +* Fixed an issue whereby using some shields with sysbuild would cause a cmake Kconfig error. + Drivers and Sensors ******************* From 37560fefeaccf4da690b7259f0b0ca6b6ce4545f Mon Sep 17 00:00:00 2001 From: Anas Nashif Date: Tue, 9 Jan 2024 11:32:57 -0500 Subject: [PATCH 1949/3723] ci: use kitaware ninja with job server support Needed for full functionality of the job server in twister which only works with kitware supplied ninja version. Signed-off-by: Anas Nashif --- .github/workflows/twister.yaml | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/.github/workflows/twister.yaml b/.github/workflows/twister.yaml index 49a30e09cda..983a97f8973 100644 --- a/.github/workflows/twister.yaml +++ b/.github/workflows/twister.yaml @@ -179,6 +179,12 @@ jobs: west update --path-cache /github/cache/zephyrproject 2>&1 1> west.update.log || west update --path-cache /github/cache/zephyrproject 2>&1 1> west.update.log || ( rm -rf ../modules ../bootloader ../tools && west update --path-cache /github/cache/zephyrproject) west forall -c 'git reset --hard HEAD' + # Hotfix until we have kitware ninja in the docker image. + # Needed for full functionality of the job server functionality in twister which only works with + # kitware supplied ninja version. + wget -c https://github.com/Kitware/ninja/releases/download/v1.11.1.g95dee.kitware.jobserver-1/ninja-1.11.1.g95dee.kitware.jobserver-1_x86_64-linux-gnu.tar.gz -O - | tar xz --strip-components=1 + sudo cp ninja /usr/local/bin + - name: Check Environment run: | cmake --version From a9ea0fe4203c7e534f8c4ac20c0695bed5aef11f Mon Sep 17 00:00:00 2001 From: Paszkiet Kamil Date: Mon, 16 Oct 2023 12:39:08 +0200 Subject: [PATCH 1950/3723] scripts: tests: twister_blackbox: Add more tests test_printouts.py add tests to test_printouts.py: -timestamps -broken_parameter -help (dummy check) -force_color (dummy check) Signed-off-by: Paszkiet Kamil --- .../tests/twister_blackbox/test_printouts.py | 117 ++++++++++++++++-- 1 file changed, 110 insertions(+), 7 deletions(-) diff --git a/scripts/tests/twister_blackbox/test_printouts.py b/scripts/tests/twister_blackbox/test_printouts.py index 333bf2a090a..b49ea867fb1 100644 --- a/scripts/tests/twister_blackbox/test_printouts.py +++ b/scripts/tests/twister_blackbox/test_printouts.py @@ -11,6 +11,7 @@ import os import pytest import sys +import re from conftest import TEST_DATA, ZEPHYR_BASE, testsuite_filename_mock from twisterlib.testplan import TestPlan @@ -73,6 +74,12 @@ class TestPrintOuts: ), ] + TESTDATA_4 = [ + ( + os.path.join(TEST_DATA, 'tests', 'dummy'), + ['qemu_x86', 'qemu_x86_64', 'frdm_k64f'] + ) + ] @classmethod def setup_class(cls): @@ -81,12 +88,10 @@ def setup_class(cls): cls.spec = importlib.util.spec_from_loader(cls.loader.name, cls.loader) cls.twister_module = importlib.util.module_from_spec(cls.spec) - @classmethod def teardown_class(cls): pass - @pytest.mark.usefixtures("clear_log") @pytest.mark.parametrize( 'test_path, expected', @@ -100,7 +105,7 @@ def test_list_tags(self, capfd, test_path, expected): args = ['-T', test_path, '--list-tags'] with mock.patch.object(sys, 'argv', [sys.argv[0]] + args), \ - pytest.raises(SystemExit) as sys_exit: + pytest.raises(SystemExit) as sys_exit: self.loader.exec_module(self.twister_module) out, err = capfd.readouterr() @@ -114,7 +119,6 @@ def test_list_tags(self, capfd, test_path, expected): assert str(sys_exit.value) == '0' - @pytest.mark.usefixtures("clear_log") @pytest.mark.parametrize( 'test_path, expected', @@ -128,7 +132,7 @@ def test_list_tests(self, capfd, test_path, expected): args = ['-T', test_path, '--list-tests'] with mock.patch.object(sys, 'argv', [sys.argv[0]] + args), \ - pytest.raises(SystemExit) as sys_exit: + pytest.raises(SystemExit) as sys_exit: self.loader.exec_module(self.twister_module) out, err = capfd.readouterr() @@ -143,7 +147,6 @@ def test_list_tests(self, capfd, test_path, expected): assert str(sys_exit.value) == '0' - @pytest.mark.usefixtures("clear_log") @pytest.mark.parametrize( 'test_path, expected', @@ -157,7 +160,7 @@ def test_tree(self, capfd, test_path, expected): args = ['-T', test_path, '--test-tree'] with mock.patch.object(sys, 'argv', [sys.argv[0]] + args), \ - pytest.raises(SystemExit) as sys_exit: + pytest.raises(SystemExit) as sys_exit: self.loader.exec_module(self.twister_module) out, err = capfd.readouterr() @@ -166,3 +169,103 @@ def test_tree(self, capfd, test_path, expected): assert expected in out assert str(sys_exit.value) == '0' + + @pytest.mark.usefixtures("clear_log") + @pytest.mark.parametrize( + 'test_path, test_platforms', + TESTDATA_4, + ids=['tests'] + ) + def test_timestamps(self, capfd, test_path, test_platforms): + + args = ['-i', '-T', test_path, '--timestamps', '-v'] + \ + [val for pair in zip( + ['-p'] * len(test_platforms), test_platforms + ) for val in pair] + + with mock.patch.object(sys, 'argv', [sys.argv[0]] + args), \ + pytest.raises(SystemExit) as sys_exit: + self.loader.exec_module(self.twister_module) + + info_regex = r'\d{4}-\d{2}-\d{2} \d{2}:\d{2}:\d{2},\d{3} - (?:INFO|DEBUG|ERROR)' + + out, err = capfd.readouterr() + sys.stdout.write(out) + sys.stderr.write(err) + + output = err.split('\n') + + err_lines = [] + for line in output: + if line.strip(): + + match = re.search(info_regex, line) + if match is None: + err_lines.append(line) + + if err_lines: + assert False, f'No timestamp in line {err_lines}' + assert str(sys_exit.value) == '0' + + @pytest.mark.usefixtures("clear_log") + @pytest.mark.parametrize( + 'flag', + ['--abcd', '--1234', '-%', '-1'] + ) + def test_broken_parameter(self, capfd, flag): + + args = [flag] + + with mock.patch.object(sys, 'argv', [sys.argv[0]] + args), \ + pytest.raises(SystemExit) as sys_exit: + self.loader.exec_module(self.twister_module) + + out, err = capfd.readouterr() + sys.stdout.write(out) + sys.stderr.write(err) + + if flag == '-1': + assert str(sys_exit.value) == '1' + else: + assert str(sys_exit.value) == '2' + + @pytest.mark.usefixtures("clear_log") + @pytest.mark.parametrize( + 'flag', + ['--help', '-h'] + ) + def test_help(self, capfd, flag): + args = [flag] + + with mock.patch.object(sys, 'argv', [sys.argv[0]] + args), \ + pytest.raises(SystemExit) as sys_exit: + self.loader.exec_module(self.twister_module) + + out, err = capfd.readouterr() + sys.stdout.write(out) + sys.stderr.write(err) + + assert str(sys_exit.value) == '0' + + @pytest.mark.usefixtures("clear_log") + @pytest.mark.parametrize( + 'test_path, test_platforms', + TESTDATA_4, + ids=['tests'] + ) + def test_force_color(self, capfd, test_path, test_platforms): + + args = ['-i', '-T', test_path, '--force-color'] + \ + [val for pair in zip( + ['-p'] * len(test_platforms), test_platforms + ) for val in pair] + + with mock.patch.object(sys, 'argv', [sys.argv[0]] + args), \ + pytest.raises(SystemExit) as sys_exit: + self.loader.exec_module(self.twister_module) + + out, err = capfd.readouterr() + sys.stdout.write(out) + sys.stderr.write(err) + + assert str(sys_exit.value) == '0' From 25753fef13d047bd03e76bc54fc7c62d7987dc00 Mon Sep 17 00:00:00 2001 From: Manuel Aebischer Date: Thu, 21 Dec 2023 12:33:42 +0100 Subject: [PATCH 1951/3723] drivers: usb_dc_rpi_pico: starting read on transfer EPs This commit partially reverts a change which was introduced in the previous commit 5b9a0e54569c8f128315de7c997f86d24ae178ee. usb_dc_ep_start_read() should also be called on transfer endpoints like it has been before, otherwise the endpoint will not be armed after it has been reconfigured. Signed-off-by: Manuel Aebischer --- drivers/usb/device/usb_dc_rpi_pico.c | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/drivers/usb/device/usb_dc_rpi_pico.c b/drivers/usb/device/usb_dc_rpi_pico.c index 38e88afae39..bb99fa365b2 100644 --- a/drivers/usb/device/usb_dc_rpi_pico.c +++ b/drivers/usb/device/usb_dc_rpi_pico.c @@ -655,9 +655,7 @@ int usb_dc_ep_enable(const uint8_t ep) *ep_state->ep_ctl = val; } - if (USB_EP_DIR_IS_OUT(ep) && ep != USB_CONTROL_EP_OUT && - ep_state->cb != usb_transfer_ep_callback) { - /* Start reading now, except for transfer managed eps */ + if (USB_EP_DIR_IS_OUT(ep) && ep != USB_CONTROL_EP_OUT) { return usb_dc_ep_start_read(ep, DATA_BUFFER_SIZE); } From c9263db28fb3d46b683b79e9c31df09a85cf91f0 Mon Sep 17 00:00:00 2001 From: Henrik Brix Andersen Date: Mon, 8 Jan 2024 14:14:54 +0100 Subject: [PATCH 1952/3723] drivers: can: bosch: mcan: use int0 and int1 as interrupt names Consistently use "int0" and "int1" as interrupt names for CAN controllers based on the Bosch M_CAN IP core. This aligns with the upstream Linux bindings. Signed-off-by: Henrik Brix Andersen --- drivers/can/can_sam.c | 12 ++++++------ drivers/can/can_sam0.c | 6 +++--- drivers/can/can_stm32_fdcan.c | 12 ++++++------ drivers/can/can_stm32h7_fdcan.c | 12 ++++++------ dts/arm/atmel/samc21.dtsi | 4 ++-- dts/arm/atmel/same5x.dtsi | 4 ++-- dts/arm/atmel/same70.dtsi | 4 ++-- dts/arm/nuvoton/m46x.dtsi | 8 ++++---- dts/arm/nxp/nxp_lpc55S0x_common.dtsi | 1 + dts/arm/nxp/nxp_lpc55S1x_common.dtsi | 1 + dts/arm/nxp/nxp_lpc55S3x_common.dtsi | 1 + dts/arm/st/g0/stm32g0b1.dtsi | 2 +- dts/arm/st/g4/stm32g4.dtsi | 2 +- dts/arm/st/g4/stm32g473.dtsi | 2 +- dts/arm/st/g4/stm32g491.dtsi | 2 +- dts/arm/st/h5/stm32h5.dtsi | 2 +- dts/arm/st/h5/stm32h562.dtsi | 2 +- dts/arm/st/h7/stm32h7.dtsi | 4 ++-- dts/arm/st/h7/stm32h723.dtsi | 2 +- dts/arm/st/u5/stm32u5.dtsi | 2 +- 20 files changed, 44 insertions(+), 41 deletions(-) diff --git a/drivers/can/can_sam.c b/drivers/can/can_sam.c index e081e57c794..4be722386ae 100644 --- a/drivers/can/can_sam.c +++ b/drivers/can/can_sam.c @@ -154,14 +154,14 @@ static const struct can_mcan_ops can_sam_ops = { static void config_can_##inst##_irq(void) \ { \ LOG_DBG("Enable CAN##inst## IRQ"); \ - IRQ_CONNECT(DT_INST_IRQ_BY_NAME(inst, line_0, irq), \ - DT_INST_IRQ_BY_NAME(inst, line_0, priority), can_mcan_line_0_isr, \ + IRQ_CONNECT(DT_INST_IRQ_BY_NAME(inst, int0, irq), \ + DT_INST_IRQ_BY_NAME(inst, int0, priority), can_mcan_line_0_isr, \ DEVICE_DT_INST_GET(inst), 0); \ - irq_enable(DT_INST_IRQ_BY_NAME(inst, line_0, irq)); \ - IRQ_CONNECT(DT_INST_IRQ_BY_NAME(inst, line_1, irq), \ - DT_INST_IRQ_BY_NAME(inst, line_1, priority), can_mcan_line_1_isr, \ + irq_enable(DT_INST_IRQ_BY_NAME(inst, int0, irq)); \ + IRQ_CONNECT(DT_INST_IRQ_BY_NAME(inst, int1, irq), \ + DT_INST_IRQ_BY_NAME(inst, int1, priority), can_mcan_line_1_isr, \ DEVICE_DT_INST_GET(inst), 0); \ - irq_enable(DT_INST_IRQ_BY_NAME(inst, line_1, irq)); \ + irq_enable(DT_INST_IRQ_BY_NAME(inst, int1, irq)); \ } #define CAN_SAM_CFG_INST(inst) \ diff --git a/drivers/can/can_sam0.c b/drivers/can/can_sam0.c index 05465de13c1..af584df619a 100644 --- a/drivers/can/can_sam0.c +++ b/drivers/can/can_sam0.c @@ -199,10 +199,10 @@ static const struct can_mcan_ops can_sam0_ops = { static void config_can_##inst##_irq(void) \ { \ LOG_DBG("Enable CAN##inst## IRQ"); \ - IRQ_CONNECT(DT_INST_IRQ_BY_NAME(inst, line_0, irq), \ - DT_INST_IRQ_BY_NAME(inst, line_0, priority), can_sam0_line_x_isr, \ + IRQ_CONNECT(DT_INST_IRQ_BY_NAME(inst, int0, irq), \ + DT_INST_IRQ_BY_NAME(inst, int0, priority), can_sam0_line_x_isr, \ DEVICE_DT_INST_GET(inst), 0); \ - irq_enable(DT_INST_IRQ_BY_NAME(inst, line_0, irq)); \ + irq_enable(DT_INST_IRQ_BY_NAME(inst, int0, irq)); \ } #define CAN_SAM0_CFG_INST(inst) \ diff --git a/drivers/can/can_stm32_fdcan.c b/drivers/can/can_stm32_fdcan.c index e17fce0e1b9..1237ddad7b3 100644 --- a/drivers/can/can_stm32_fdcan.c +++ b/drivers/can/can_stm32_fdcan.c @@ -630,14 +630,14 @@ static const struct can_mcan_ops can_stm32fd_ops = { static void config_can_##inst##_irq(void) \ { \ LOG_DBG("Enable CAN" #inst " IRQ"); \ - IRQ_CONNECT(DT_INST_IRQ_BY_NAME(inst, line_0, irq), \ - DT_INST_IRQ_BY_NAME(inst, line_0, priority), \ + IRQ_CONNECT(DT_INST_IRQ_BY_NAME(inst, int0, irq), \ + DT_INST_IRQ_BY_NAME(inst, int0, priority), \ can_mcan_line_0_isr, DEVICE_DT_INST_GET(inst), 0); \ - irq_enable(DT_INST_IRQ_BY_NAME(inst, line_0, irq)); \ - IRQ_CONNECT(DT_INST_IRQ_BY_NAME(inst, line_1, irq), \ - DT_INST_IRQ_BY_NAME(inst, line_1, priority), \ + irq_enable(DT_INST_IRQ_BY_NAME(inst, int0, irq)); \ + IRQ_CONNECT(DT_INST_IRQ_BY_NAME(inst, int1, irq), \ + DT_INST_IRQ_BY_NAME(inst, int1, priority), \ can_mcan_line_1_isr, DEVICE_DT_INST_GET(inst), 0); \ - irq_enable(DT_INST_IRQ_BY_NAME(inst, line_1, irq)); \ + irq_enable(DT_INST_IRQ_BY_NAME(inst, int1, irq)); \ } #define CAN_STM32FD_CFG_INST(inst) \ diff --git a/drivers/can/can_stm32h7_fdcan.c b/drivers/can/can_stm32h7_fdcan.c index 291bcfe8091..9b75932fd4f 100644 --- a/drivers/can/can_stm32h7_fdcan.c +++ b/drivers/can/can_stm32h7_fdcan.c @@ -233,14 +233,14 @@ static const struct can_mcan_ops can_stm32h7_ops = { static void stm32h7_mcan_irq_config_##n(void) \ { \ LOG_DBG("Enable CAN inst" #n " IRQ"); \ - IRQ_CONNECT(DT_INST_IRQ_BY_NAME(n, line_0, irq), \ - DT_INST_IRQ_BY_NAME(n, line_0, priority), \ + IRQ_CONNECT(DT_INST_IRQ_BY_NAME(n, int0, irq), \ + DT_INST_IRQ_BY_NAME(n, int0, priority), \ can_mcan_line_0_isr, DEVICE_DT_INST_GET(n), 0); \ - irq_enable(DT_INST_IRQ_BY_NAME(n, line_0, irq)); \ - IRQ_CONNECT(DT_INST_IRQ_BY_NAME(n, line_1, irq), \ - DT_INST_IRQ_BY_NAME(n, line_1, priority), \ + irq_enable(DT_INST_IRQ_BY_NAME(n, int0, irq)); \ + IRQ_CONNECT(DT_INST_IRQ_BY_NAME(n, int1, irq), \ + DT_INST_IRQ_BY_NAME(n, int1, priority), \ can_mcan_line_1_isr, DEVICE_DT_INST_GET(n), 0); \ - irq_enable(DT_INST_IRQ_BY_NAME(n, line_1, irq)); \ + irq_enable(DT_INST_IRQ_BY_NAME(n, int1, irq)); \ } DT_INST_FOREACH_STATUS_OKAY(CAN_STM32H7_MCAN_INIT) diff --git a/dts/arm/atmel/samc21.dtsi b/dts/arm/atmel/samc21.dtsi index d3cdfbda777..72b28386a4b 100644 --- a/dts/arm/atmel/samc21.dtsi +++ b/dts/arm/atmel/samc21.dtsi @@ -48,7 +48,7 @@ compatible = "atmel,sam0-can"; reg = <0x42001c00 0x100>; interrupts = <15 0>; - interrupt-names = "LINE_0"; + interrupt-names = "int0"; clocks = <&gclk 26>, <&mclk 0x10 8>; clock-names = "GCLK", "MCLK"; bosch,mram-cfg = <0x0 28 8 3 3 0 1 1>; @@ -62,7 +62,7 @@ compatible = "atmel,sam0-can"; reg = <0x42002000 0x100>; interrupts = <16 0>; - interrupt-names = "LINE_0"; + interrupt-names = "int0"; clocks = <&gclk 27>, <&mclk 0x10 9>; clock-names = "GCLK", "MCLK"; bosch,mram-cfg = <0x0 28 8 3 3 0 1 1>; diff --git a/dts/arm/atmel/same5x.dtsi b/dts/arm/atmel/same5x.dtsi index 616b408e8ed..c4b1762e5b3 100644 --- a/dts/arm/atmel/same5x.dtsi +++ b/dts/arm/atmel/same5x.dtsi @@ -31,7 +31,7 @@ compatible = "atmel,sam0-can"; reg = <0x42000000 0x400>; interrupts = <78 0>, <78 0>; - interrupt-names = "LINE_0", "LINE_1"; + interrupt-names = "int0", "int1"; clocks = <&gclk 27>, <&mclk 0x10 17>; clock-names = "GCLK", "MCLK"; bosch,mram-cfg = <0x0 128 64 64 64 64 32 32>; @@ -45,7 +45,7 @@ compatible = "atmel,sam0-can"; reg = <0x42000400 0x400>; interrupts = <79 0>, <79 0>; - interrupt-names = "LINE_0", "LINE_1"; + interrupt-names = "int0", "int1"; clocks = <&gclk 28>, <&mclk 0x10 18>; clock-names = "GCLK", "MCLK"; bosch,mram-cfg = <0x0 128 64 64 64 64 32 32>; diff --git a/dts/arm/atmel/same70.dtsi b/dts/arm/atmel/same70.dtsi index d15d6baf83e..10f103d1ecd 100644 --- a/dts/arm/atmel/same70.dtsi +++ b/dts/arm/atmel/same70.dtsi @@ -422,7 +422,7 @@ compatible = "atmel,sam-can"; reg = <0x40030000 0x100>; interrupts = <35 0>, <36 0>; - interrupt-names = "LINE_0", "LINE_1"; + interrupt-names = "int0", "int1"; clocks = <&pmc PMC_TYPE_PERIPHERAL 35>; divider = <6>; bosch,mram-cfg = <0x0 28 8 3 3 0 1 1>; @@ -435,7 +435,7 @@ compatible = "atmel,sam-can"; reg = <0x40034000 0x100>; interrupts = <37 0>, <38 0>; - interrupt-names = "LINE_0", "LINE_1"; + interrupt-names = "int0", "int1"; clocks = <&pmc PMC_TYPE_PERIPHERAL 37>; divider = <6>; bosch,mram-cfg = <0x0 28 8 3 3 0 1 1>; diff --git a/dts/arm/nuvoton/m46x.dtsi b/dts/arm/nuvoton/m46x.dtsi index 03e62e817ea..d73a888d21b 100644 --- a/dts/arm/nuvoton/m46x.dtsi +++ b/dts/arm/nuvoton/m46x.dtsi @@ -436,7 +436,7 @@ reg = <0x40020000 0x200>, <0x40020200 0x1800>; reg-names = "m_can", "message_ram"; interrupts = <112 0>, <113 0>; - interrupt-names = "LINE_0", "LINE_1"; + interrupt-names = "int0", "int1"; resets = <&rst NUMAKER_CANFD0_RST>; clocks = <&pcc NUMAKER_CANFD0_MODULE NUMAKER_CLK_CLKSEL0_CANFD0SEL_HCLK @@ -452,7 +452,7 @@ reg = <0x40024000 0x200>, <0x40024200 0x1800>; reg-names = "m_can", "message_ram"; interrupts = <114 0>, <115 0>; - interrupt-names = "LINE_0", "LINE_1"; + interrupt-names = "int0", "int1"; resets = <&rst NUMAKER_CANFD1_RST>; clocks = <&pcc NUMAKER_CANFD1_MODULE NUMAKER_CLK_CLKSEL0_CANFD1SEL_HCLK @@ -468,7 +468,7 @@ reg = <0x40028000 0x200>, <0x40028200 0x1800>; reg-names = "m_can", "message_ram"; interrupts = <120 0>, <121 0>; - interrupt-names = "LINE_0", "LINE_1"; + interrupt-names = "int0", "int1"; resets = <&rst NUMAKER_CANFD2_RST>; clocks = <&pcc NUMAKER_CANFD2_MODULE NUMAKER_CLK_CLKSEL0_CANFD2SEL_HCLK @@ -484,7 +484,7 @@ reg = <0x4002c000 0x200>, <0x4002c200 0x1800>; reg-names = "m_can", "message_ram"; interrupts = <122 0>, <123 0>; - interrupt-names = "LINE_0", "LINE_1"; + interrupt-names = "int0", "int1"; resets = <&rst NUMAKER_CANFD3_RST>; clocks = <&pcc NUMAKER_CANFD3_MODULE NUMAKER_CLK_CLKSEL0_CANFD3SEL_HCLK diff --git a/dts/arm/nxp/nxp_lpc55S0x_common.dtsi b/dts/arm/nxp/nxp_lpc55S0x_common.dtsi index b7a13229e00..c579a917698 100644 --- a/dts/arm/nxp/nxp_lpc55S0x_common.dtsi +++ b/dts/arm/nxp/nxp_lpc55S0x_common.dtsi @@ -220,6 +220,7 @@ compatible = "nxp,lpc-mcan"; reg = <0x9d000 0x1000>; interrupts = <43 0>, <44 0>; + interrupt-names = "int0", "int1"; clocks = <&syscon MCUX_MCAN_CLK>; bosch,mram-cfg = <0x0 15 15 8 8 0 15 15>; sample-point = <875>; diff --git a/dts/arm/nxp/nxp_lpc55S1x_common.dtsi b/dts/arm/nxp/nxp_lpc55S1x_common.dtsi index 8a62b6fe5af..304bf2e68d9 100644 --- a/dts/arm/nxp/nxp_lpc55S1x_common.dtsi +++ b/dts/arm/nxp/nxp_lpc55S1x_common.dtsi @@ -215,6 +215,7 @@ compatible = "nxp,lpc-mcan"; reg = <0x9d000 0x1000>; interrupts = <43 0>, <44 0>; + interrupt-names = "int0", "int1"; clocks = <&syscon MCUX_MCAN_CLK>; bosch,mram-cfg = <0x0 15 15 8 8 0 15 15>; sample-point = <875>; diff --git a/dts/arm/nxp/nxp_lpc55S3x_common.dtsi b/dts/arm/nxp/nxp_lpc55S3x_common.dtsi index 348b5e6083d..18ca28d03e8 100644 --- a/dts/arm/nxp/nxp_lpc55S3x_common.dtsi +++ b/dts/arm/nxp/nxp_lpc55S3x_common.dtsi @@ -325,6 +325,7 @@ compatible = "nxp,lpc-mcan"; reg = <0x4009d000 0x1000>; interrupts = <43 0>, <44 0>; + interrupt-names = "int0", "int1"; clocks = <&syscon MCUX_MCAN_CLK>; bosch,mram-cfg = <0x0 15 15 8 8 0 15 15>; sample-point = <875>; diff --git a/dts/arm/st/g0/stm32g0b1.dtsi b/dts/arm/st/g0/stm32g0b1.dtsi index ead49eb0605..28b55fc70de 100644 --- a/dts/arm/st/g0/stm32g0b1.dtsi +++ b/dts/arm/st/g0/stm32g0b1.dtsi @@ -35,7 +35,7 @@ reg = <0x40006400 0x400>, <0x4000b400 0x350>; reg-names = "m_can", "message_ram"; interrupts = <21 0>, <22 0>; - interrupt-names = "LINE_0", "LINE_1"; + interrupt-names = "int0", "int1"; clocks = <&rcc STM32_CLOCK_BUS_APB1 0x00001000>; bosch,mram-cfg = <0x0 28 8 3 3 0 3 3>; sample-point = <875>; diff --git a/dts/arm/st/g4/stm32g4.dtsi b/dts/arm/st/g4/stm32g4.dtsi index 1b6632f694f..d42ff353a73 100644 --- a/dts/arm/st/g4/stm32g4.dtsi +++ b/dts/arm/st/g4/stm32g4.dtsi @@ -387,7 +387,7 @@ reg = <0x40006400 0x400>, <0x4000a400 0x350>; reg-names = "m_can", "message_ram"; interrupts = <21 0>, <22 0>; - interrupt-names = "LINE_0", "LINE_1"; + interrupt-names = "int0", "int1"; clocks = <&rcc STM32_CLOCK_BUS_APB1 0x02000000>; bosch,mram-cfg = <0x0 28 8 3 3 0 3 3>; sample-point = <875>; diff --git a/dts/arm/st/g4/stm32g473.dtsi b/dts/arm/st/g4/stm32g473.dtsi index 930e1639795..0cdcc317f0a 100644 --- a/dts/arm/st/g4/stm32g473.dtsi +++ b/dts/arm/st/g4/stm32g473.dtsi @@ -100,7 +100,7 @@ reg = <0x40006c00 0x400>, <0x4000a400 0x9f0>; reg-names = "m_can", "message_ram"; interrupts = <88 0>, <89 0>; - interrupt-names = "LINE_0", "LINE_1"; + interrupt-names = "int0", "int1"; clocks = <&rcc STM32_CLOCK_BUS_APB1 0x02000000>; bosch,mram-cfg = <0x6a0 28 8 3 3 0 3 3>; sample-point = <875>; diff --git a/dts/arm/st/g4/stm32g491.dtsi b/dts/arm/st/g4/stm32g491.dtsi index 865d3700d96..1e616accc77 100644 --- a/dts/arm/st/g4/stm32g491.dtsi +++ b/dts/arm/st/g4/stm32g491.dtsi @@ -15,7 +15,7 @@ reg = <0x40006800 0x400>, <0x4000a400 0x6a0>; reg-names = "m_can", "message_ram"; interrupts = <86 0>, <87 0>; - interrupt-names = "LINE_0", "LINE_1"; + interrupt-names = "int0", "int1"; clocks = <&rcc STM32_CLOCK_BUS_APB1 0x02000000>; bosch,mram-cfg = <0x350 28 8 3 3 0 3 3>; sample-point = <875>; diff --git a/dts/arm/st/h5/stm32h5.dtsi b/dts/arm/st/h5/stm32h5.dtsi index 310b3384f60..dff30f083da 100644 --- a/dts/arm/st/h5/stm32h5.dtsi +++ b/dts/arm/st/h5/stm32h5.dtsi @@ -438,7 +438,7 @@ reg = <0x4000a400 0x400>, <0x4000ac00 0x350>; reg-names = "m_can", "message_ram"; interrupts = <39 0>, <40 0>; - interrupt-names = "LINE_0", "LINE_1"; + interrupt-names = "int0", "int1"; clocks = <&rcc STM32_CLOCK_BUS_APB1_2 0x00000200>; bosch,mram-cfg = <0x0 28 8 3 3 0 3 3>; sample-point = <875>; diff --git a/dts/arm/st/h5/stm32h562.dtsi b/dts/arm/st/h5/stm32h562.dtsi index 6d99b0d67e2..1285f10b1eb 100644 --- a/dts/arm/st/h5/stm32h562.dtsi +++ b/dts/arm/st/h5/stm32h562.dtsi @@ -308,7 +308,7 @@ reg = <0x4000a800 0x400>, <0x4000ac00 0x6a0>; reg-names = "m_can", "message_ram"; interrupts = <109 0>, <110 0>; - interrupt-names = "LINE_0", "LINE_1"; + interrupt-names = "int0", "int1"; /* common clock FDCAN 1 & 2 */ clocks = <&rcc STM32_CLOCK_BUS_APB1_2 0x00000200>; bosch,mram-cfg = <0x350 28 8 3 3 0 3 3>; diff --git a/dts/arm/st/h7/stm32h7.dtsi b/dts/arm/st/h7/stm32h7.dtsi index 8b6ae8041bb..64ccfbf7241 100644 --- a/dts/arm/st/h7/stm32h7.dtsi +++ b/dts/arm/st/h7/stm32h7.dtsi @@ -514,7 +514,7 @@ reg-names = "m_can", "message_ram"; clocks = <&rcc STM32_CLOCK_BUS_APB1_2 0x00000100>; interrupts = <19 0>, <21 0>, <63 0>; - interrupt-names = "LINE_0", "LINE_1", "CALIB"; + interrupt-names = "int0", "int1", "calib"; bosch,mram-cfg = <0x0 28 8 3 3 0 3 3>; sample-point = <875>; sample-point-data = <875>; @@ -527,7 +527,7 @@ reg-names = "m_can", "message_ram"; clocks = <&rcc STM32_CLOCK_BUS_APB1_2 0x00000100>; interrupts = <20 0>, <22 0>, <63 0>; - interrupt-names = "LINE_0", "LINE_1", "CALIB"; + interrupt-names = "int0", "int1", "calib"; bosch,mram-cfg = <0x350 28 8 3 3 0 3 3>; sample-point = <875>; sample-point-data = <875>; diff --git a/dts/arm/st/h7/stm32h723.dtsi b/dts/arm/st/h7/stm32h723.dtsi index f1b0836f6e8..1a2b917bc1e 100644 --- a/dts/arm/st/h7/stm32h723.dtsi +++ b/dts/arm/st/h7/stm32h723.dtsi @@ -121,7 +121,7 @@ reg-names = "m_can", "message_ram"; clocks = <&rcc STM32_CLOCK_BUS_APB1_2 0x00000100>; interrupts = <159 0>, <160 0>, <63 0>; - interrupt-names = "LINE_0", "LINE_1", "CALIB"; + interrupt-names = "int0", "int1", "calib"; bosch,mram-cfg = <0x6a0 28 8 3 3 0 3 3>; sample-point = <875>; sample-point-data = <875>; diff --git a/dts/arm/st/u5/stm32u5.dtsi b/dts/arm/st/u5/stm32u5.dtsi index b97e509c831..f721617ef5b 100644 --- a/dts/arm/st/u5/stm32u5.dtsi +++ b/dts/arm/st/u5/stm32u5.dtsi @@ -798,7 +798,7 @@ reg = <0x4000a400 0x400>, <0x4000ac00 0x350>; reg-names = "m_can", "message_ram"; interrupts = <39 0>, <40 0>; - interrupt-names = "LINE_0", "LINE_1"; + interrupt-names = "int0", "int1"; clocks = <&rcc STM32_CLOCK_BUS_APB1_2 0x00000200>; bosch,mram-cfg = <0x0 28 8 3 3 0 3 3>; sample-point = <875>; From 074303cb7a617dd8dd290f2e5d874ea405a74215 Mon Sep 17 00:00:00 2001 From: Henrik Brix Andersen Date: Mon, 8 Jan 2024 14:16:52 +0100 Subject: [PATCH 1953/3723] dts: bindings: can: require interrupt-names for drivers using named IRQs Make the "interrupt-names" property mandatory for drivers using named IRQs. Signed-off-by: Henrik Brix Andersen --- dts/bindings/can/atmel,sam-can.yaml | 3 +++ dts/bindings/can/atmel,sam0-can.yaml | 3 +++ dts/bindings/can/st,stm32-fdcan.yaml | 3 +++ dts/bindings/can/st,stm32h7-fdcan.yaml | 3 +++ 4 files changed, 12 insertions(+) diff --git a/dts/bindings/can/atmel,sam-can.yaml b/dts/bindings/can/atmel,sam-can.yaml index e6930009194..c224604fa0b 100644 --- a/dts/bindings/can/atmel,sam-can.yaml +++ b/dts/bindings/can/atmel,sam-can.yaml @@ -13,6 +13,9 @@ properties: interrupts: required: true + interrupt-names: + required: true + clocks: required: true diff --git a/dts/bindings/can/atmel,sam0-can.yaml b/dts/bindings/can/atmel,sam0-can.yaml index 486620a21b7..7002386c922 100644 --- a/dts/bindings/can/atmel,sam0-can.yaml +++ b/dts/bindings/can/atmel,sam0-can.yaml @@ -13,6 +13,9 @@ properties: interrupts: required: true + interrupt-names: + required: true + clocks: required: true diff --git a/dts/bindings/can/st,stm32-fdcan.yaml b/dts/bindings/can/st,stm32-fdcan.yaml index d950bb4e924..f4cfb310dac 100644 --- a/dts/bindings/can/st,stm32-fdcan.yaml +++ b/dts/bindings/can/st,stm32-fdcan.yaml @@ -11,6 +11,9 @@ properties: interrupts: required: true + interrupt-names: + required: true + clocks: required: true diff --git a/dts/bindings/can/st,stm32h7-fdcan.yaml b/dts/bindings/can/st,stm32h7-fdcan.yaml index 3cee6e29219..1d258ea4abf 100644 --- a/dts/bindings/can/st,stm32h7-fdcan.yaml +++ b/dts/bindings/can/st,stm32h7-fdcan.yaml @@ -13,3 +13,6 @@ properties: interrupts: required: true + + interrupt-names: + required: true From b1cf5f0ffc9758df0a64bb6a4cc42db2315d9c18 Mon Sep 17 00:00:00 2001 From: Henrik Brix Andersen Date: Mon, 8 Jan 2024 14:18:32 +0100 Subject: [PATCH 1954/3723] drivers: can: nxp: mcan: use named IRQs Switch to using named IRQs as index-based access makes no guarantees about devicetree interrupt order. Signed-off-by: Henrik Brix Andersen --- drivers/can/can_mcux_mcan.c | 12 ++++++------ dts/bindings/can/nxp,lpc-mcan.yaml | 3 +++ 2 files changed, 9 insertions(+), 6 deletions(-) diff --git a/drivers/can/can_mcux_mcan.c b/drivers/can/can_mcux_mcan.c index eb382c95292..b4c24e2b19e 100644 --- a/drivers/can/can_mcux_mcan.c +++ b/drivers/can/can_mcux_mcan.c @@ -217,17 +217,17 @@ static const struct can_mcan_ops mcux_mcan_ops = { \ static void mcux_mcan_irq_config_##n(const struct device *dev) \ { \ - IRQ_CONNECT(DT_INST_IRQ_BY_IDX(n, 0, irq), \ - DT_INST_IRQ_BY_IDX(n, 0, priority), \ + IRQ_CONNECT(DT_INST_IRQ_BY_NAME(n, int0, irq), \ + DT_INST_IRQ_BY_NAME(n, int0, priority), \ can_mcan_line_0_isr, \ DEVICE_DT_INST_GET(n), 0); \ - irq_enable(DT_INST_IRQ_BY_IDX(n, 0, irq)); \ + irq_enable(DT_INST_IRQ_BY_NAME(n, int0, irq)); \ \ - IRQ_CONNECT(DT_INST_IRQ_BY_IDX(n, 1, irq), \ - DT_INST_IRQ_BY_IDX(n, 1, priority), \ + IRQ_CONNECT(DT_INST_IRQ_BY_NAME(n, int1, irq), \ + DT_INST_IRQ_BY_NAME(n, int1, priority), \ can_mcan_line_1_isr, \ DEVICE_DT_INST_GET(n), 0); \ - irq_enable(DT_INST_IRQ_BY_IDX(n, 1, irq)); \ + irq_enable(DT_INST_IRQ_BY_NAME(n, int1, irq)); \ } DT_INST_FOREACH_STATUS_OKAY(MCUX_MCAN_INIT) diff --git a/dts/bindings/can/nxp,lpc-mcan.yaml b/dts/bindings/can/nxp,lpc-mcan.yaml index a17b0132e62..48aef003139 100644 --- a/dts/bindings/can/nxp,lpc-mcan.yaml +++ b/dts/bindings/can/nxp,lpc-mcan.yaml @@ -11,5 +11,8 @@ properties: interrupts: required: true + interrupt-names: + required: true + clocks: required: true From e24a3f597590f59ef65ef59e54830e94c7039c73 Mon Sep 17 00:00:00 2001 From: Henrik Brix Andersen Date: Mon, 8 Jan 2024 14:19:58 +0100 Subject: [PATCH 1955/3723] drivers: can: nuvoton: numaker: use named IRQs Switch to using named IRQs as index-based access makes no guarantees about devicetree interrupt order. Signed-off-by: Henrik Brix Andersen --- drivers/can/can_numaker.c | 12 ++++++------ dts/bindings/can/nuvoton,numaker-canfd.yaml | 3 +++ 2 files changed, 9 insertions(+), 6 deletions(-) diff --git a/drivers/can/can_numaker.c b/drivers/can/can_numaker.c index 0bb47d78a04..baaa5f1e11e 100644 --- a/drivers/can/can_numaker.c +++ b/drivers/can/can_numaker.c @@ -249,18 +249,18 @@ static const struct can_mcan_ops can_numaker_ops = { \ static void can_numaker_irq_config_func_##inst(const struct device *dev) \ { \ - IRQ_CONNECT(DT_INST_IRQ_BY_IDX(inst, 0, irq), \ - DT_INST_IRQ_BY_IDX(inst, 0, priority), \ + IRQ_CONNECT(DT_INST_IRQ_BY_NAME(inst, int0, irq), \ + DT_INST_IRQ_BY_NAME(inst, int0, priority), \ can_mcan_line_0_isr, \ DEVICE_DT_INST_GET(inst), \ 0); \ - irq_enable(DT_INST_IRQ_BY_IDX(inst, 0, irq)); \ - IRQ_CONNECT(DT_INST_IRQ_BY_IDX(inst, 1, irq), \ - DT_INST_IRQ_BY_IDX(inst, 1, priority), \ + irq_enable(DT_INST_IRQ_BY_NAME(inst, int0, irq)); \ + IRQ_CONNECT(DT_INST_IRQ_BY_NAME(inst, int1, irq), \ + DT_INST_IRQ_BY_NAME(inst, int1, priority), \ can_mcan_line_1_isr, \ DEVICE_DT_INST_GET(inst), \ 0); \ - irq_enable(DT_INST_IRQ_BY_IDX(inst, 1, irq)); \ + irq_enable(DT_INST_IRQ_BY_NAME(inst, int1, irq)); \ } \ \ static const struct can_numaker_config can_numaker_config_##inst = { \ diff --git a/dts/bindings/can/nuvoton,numaker-canfd.yaml b/dts/bindings/can/nuvoton,numaker-canfd.yaml index e3d28f5ce28..f70e86693c1 100644 --- a/dts/bindings/can/nuvoton,numaker-canfd.yaml +++ b/dts/bindings/can/nuvoton,numaker-canfd.yaml @@ -14,6 +14,9 @@ properties: interrupts: required: true + interrupt-names: + required: true + resets: required: true From 8785438d313fd20310661cc82c8e2327d2891271 Mon Sep 17 00:00:00 2001 From: Henrik Brix Andersen Date: Mon, 8 Jan 2024 14:20:28 +0100 Subject: [PATCH 1956/3723] drivers: can: nuvoton: numaker: fix init function reference Fix the reference to the init function. Signed-off-by: Henrik Brix Andersen --- drivers/can/can_numaker.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/can/can_numaker.c b/drivers/can/can_numaker.c index baaa5f1e11e..c2e7bba3943 100644 --- a/drivers/can/can_numaker.c +++ b/drivers/can/can_numaker.c @@ -288,7 +288,7 @@ static const struct can_mcan_ops can_numaker_ops = { CAN_MCAN_DATA_INITIALIZER(&can_numaker_data_ ## inst); \ \ CAN_DEVICE_DT_INST_DEFINE(inst, \ - &can_numaker_init, \ + can_numaker_init, \ NULL, \ &can_mcan_data_##inst, \ &can_mcan_config_##inst, \ From 1c0b114bf802cc9842f47c1e6514d9a1ab5329c2 Mon Sep 17 00:00:00 2001 From: Daniel DeGrasse Date: Thu, 4 Jan 2024 09:37:04 -0600 Subject: [PATCH 1957/3723] sd: add timeout when taking SD card lock for data operations Previously, if an SD I/O operation was attempted while another thread held the mutex for the SD card, the I/O operation would simply fail. Add a timeout to k_mutex_lock calls within the SD subsystem, so that multithreaded access to the SD card instead blocks until the SD card is available for I/O Fixes #66211 Signed-off-by: Daniel DeGrasse --- subsys/sd/sd_ops.c | 4 ++-- subsys/sd/sdio.c | 18 +++++++++--------- 2 files changed, 11 insertions(+), 11 deletions(-) diff --git a/subsys/sd/sd_ops.c b/subsys/sd/sd_ops.c index a2934fd856c..e77160cea21 100644 --- a/subsys/sd/sd_ops.c +++ b/subsys/sd/sd_ops.c @@ -540,7 +540,7 @@ int card_read_blocks(struct sd_card *card, uint8_t *rbuf, uint32_t start_block, LOG_WRN("SDIO does not support MMC commands"); return -ENOTSUP; } - ret = k_mutex_lock(&card->lock, K_NO_WAIT); + ret = k_mutex_lock(&card->lock, K_MSEC(CONFIG_SD_DATA_TIMEOUT)); if (ret) { LOG_WRN("Could not get SD card mutex"); return -EBUSY; @@ -704,7 +704,7 @@ int card_write_blocks(struct sd_card *card, const uint8_t *wbuf, uint32_t start_ LOG_WRN("SDIO does not support MMC commands"); return -ENOTSUP; } - ret = k_mutex_lock(&card->lock, K_NO_WAIT); + ret = k_mutex_lock(&card->lock, K_MSEC(CONFIG_SD_DATA_TIMEOUT)); if (ret) { LOG_WRN("Could not get SD card mutex"); return -EBUSY; diff --git a/subsys/sd/sdio.c b/subsys/sd/sdio.c index ea507fbf496..64c813b1090 100644 --- a/subsys/sd/sdio.c +++ b/subsys/sd/sdio.c @@ -792,7 +792,7 @@ int sdio_read_byte(struct sdio_func *func, uint32_t reg, uint8_t *val) LOG_WRN("Card does not support SDIO commands"); return -ENOTSUP; } - ret = k_mutex_lock(&func->card->lock, K_NO_WAIT); + ret = k_mutex_lock(&func->card->lock, K_MSEC(CONFIG_SD_DATA_TIMEOUT)); if (ret) { LOG_WRN("Could not get SD card mutex"); return -EBUSY; @@ -822,7 +822,7 @@ int sdio_write_byte(struct sdio_func *func, uint32_t reg, uint8_t write_val) LOG_WRN("Card does not support SDIO commands"); return -ENOTSUP; } - ret = k_mutex_lock(&func->card->lock, K_NO_WAIT); + ret = k_mutex_lock(&func->card->lock, K_MSEC(CONFIG_SD_DATA_TIMEOUT)); if (ret) { LOG_WRN("Could not get SD card mutex"); return -EBUSY; @@ -855,7 +855,7 @@ int sdio_rw_byte(struct sdio_func *func, uint32_t reg, uint8_t write_val, LOG_WRN("Card does not support SDIO commands"); return -ENOTSUP; } - ret = k_mutex_lock(&func->card->lock, K_NO_WAIT); + ret = k_mutex_lock(&func->card->lock, K_MSEC(CONFIG_SD_DATA_TIMEOUT)); if (ret) { LOG_WRN("Could not get SD card mutex"); return -EBUSY; @@ -889,7 +889,7 @@ int sdio_read_fifo(struct sdio_func *func, uint32_t reg, uint8_t *data, LOG_WRN("Card does not support SDIO commands"); return -ENOTSUP; } - ret = k_mutex_lock(&func->card->lock, K_NO_WAIT); + ret = k_mutex_lock(&func->card->lock, K_MSEC(CONFIG_SD_DATA_TIMEOUT)); if (ret) { LOG_WRN("Could not get SD card mutex"); return -EBUSY; @@ -923,7 +923,7 @@ int sdio_write_fifo(struct sdio_func *func, uint32_t reg, uint8_t *data, LOG_WRN("Card does not support SDIO commands"); return -ENOTSUP; } - ret = k_mutex_lock(&func->card->lock, K_NO_WAIT); + ret = k_mutex_lock(&func->card->lock, K_MSEC(CONFIG_SD_DATA_TIMEOUT)); if (ret) { LOG_WRN("Could not get SD card mutex"); return -EBUSY; @@ -957,7 +957,7 @@ int sdio_read_blocks_fifo(struct sdio_func *func, uint32_t reg, uint8_t *data, LOG_WRN("Card does not support SDIO commands"); return -ENOTSUP; } - ret = k_mutex_lock(&func->card->lock, K_NO_WAIT); + ret = k_mutex_lock(&func->card->lock, K_MSEC(CONFIG_SD_DATA_TIMEOUT)); if (ret) { LOG_WRN("Could not get SD card mutex"); return -EBUSY; @@ -991,7 +991,7 @@ int sdio_write_blocks_fifo(struct sdio_func *func, uint32_t reg, uint8_t *data, LOG_WRN("Card does not support SDIO commands"); return -ENOTSUP; } - ret = k_mutex_lock(&func->card->lock, K_NO_WAIT); + ret = k_mutex_lock(&func->card->lock, K_MSEC(CONFIG_SD_DATA_TIMEOUT)); if (ret) { LOG_WRN("Could not get SD card mutex"); return -EBUSY; @@ -1024,7 +1024,7 @@ int sdio_read_addr(struct sdio_func *func, uint32_t reg, uint8_t *data, LOG_WRN("Card does not support SDIO commands"); return -ENOTSUP; } - ret = k_mutex_lock(&func->card->lock, K_NO_WAIT); + ret = k_mutex_lock(&func->card->lock, K_MSEC(CONFIG_SD_DATA_TIMEOUT)); if (ret) { LOG_WRN("Could not get SD card mutex"); return -EBUSY; @@ -1058,7 +1058,7 @@ int sdio_write_addr(struct sdio_func *func, uint32_t reg, uint8_t *data, LOG_WRN("Card does not support SDIO commands"); return -ENOTSUP; } - ret = k_mutex_lock(&func->card->lock, K_NO_WAIT); + ret = k_mutex_lock(&func->card->lock, K_MSEC(CONFIG_SD_DATA_TIMEOUT)); if (ret) { LOG_WRN("Could not get SD card mutex"); return -EBUSY; From 14c68c9438476268e4de25b6a2778883993c955c Mon Sep 17 00:00:00 2001 From: Anisetti Avinash Krishna Date: Wed, 3 Jan 2024 15:35:01 +0530 Subject: [PATCH 1958/3723] drivers: serial: ns16550: Add IOPORT_ENABLED check condition io_map check to enable LPSS DMA initialization is kept under condition IOPORT_ENABLED. Signed-off-by: Anisetti Avinash Krishna --- drivers/serial/uart_ns16550.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/drivers/serial/uart_ns16550.c b/drivers/serial/uart_ns16550.c index 665b44062ac..bf07240c0ce 100644 --- a/drivers/serial/uart_ns16550.c +++ b/drivers/serial/uart_ns16550.c @@ -841,7 +841,10 @@ static int uart_ns16550_init(const struct device *dev) data->async.tx_dma_params.dma_cfg.head_block = &data->async.tx_dma_params.active_dma_block; #if defined(CONFIG_UART_NS16550_INTEL_LPSS_DMA) - if (!dev_cfg->io_map) { +#if UART_NS16550_IOPORT_ENABLED + if (!dev_cfg->io_map) +#endif + { uintptr_t base; base = DEVICE_MMIO_GET(dev) + DMA_INTEL_LPSS_OFFSET; From 45232aeaa27dd03080a7f75fadbc5e6eb8f4a0eb Mon Sep 17 00:00:00 2001 From: Ricardo Rivera-Matos Date: Mon, 11 Dec 2023 11:28:11 -0600 Subject: [PATCH 1959/3723] charger: Adds CHARGER_PROP_INPUT_REGULATION_CURRENT_UA prop Adds support for setting the target threshold for an input current limit regulated by an analog loop. The analog loop responds by throttling the charge current limit as necessary. These are distinct from comparator based overcurrent protection thresholds that isolated the charger from the power source when triggered. Signed-off-by: Ricardo Rivera-Matos --- include/zephyr/drivers/charger.h | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/include/zephyr/drivers/charger.h b/include/zephyr/drivers/charger.h index ec40b299d10..29b93952df7 100644 --- a/include/zephyr/drivers/charger.h +++ b/include/zephyr/drivers/charger.h @@ -56,6 +56,13 @@ enum charger_property { CHARGER_PROP_CHARGE_TERM_CURRENT_UA, /** Configuration of charge voltage regulation target in µV */ CHARGER_PROP_CONSTANT_CHARGE_VOLTAGE_UV, + /** + * Configuration of the input current regulation target in µA + * + * This value is a rising current threshold that is regulated by reducing the charge + * current output + */ + CHARGER_PROP_INPUT_REGULATION_CURRENT_UA, /** Reserved to demark end of common charger properties */ CHARGER_PROP_COMMON_COUNT, /** @@ -200,6 +207,8 @@ union charger_propval { uint32_t charge_term_current_ua; /** CHARGER_PROP_CONSTANT_CHARGE_VOLTAGE_UV */ uint32_t const_charge_voltage_uv; + /** CHARGER_PROP_INPUT_REGULATION_CURRENT_UA */ + uint32_t input_current_regulation_current_ua; }; /** From f7d6c4f439af7c2d095502c902d52c32a5daa943 Mon Sep 17 00:00:00 2001 From: Ricardo Rivera-Matos Date: Mon, 11 Dec 2023 13:11:56 -0600 Subject: [PATCH 1960/3723] charger: Adds CHARGER_PROP_INPUT_REGULATION_VOLTAGE_UV prop Adds support for setting a falling input voltage limit regulated by an analog loop. Under heavy loads the analog loop will throttle the charge current to prevent the power source from crashing. Signed-off-by: Ricardo Rivera-Matos --- include/zephyr/drivers/charger.h | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/include/zephyr/drivers/charger.h b/include/zephyr/drivers/charger.h index 29b93952df7..98c2e33cf5e 100644 --- a/include/zephyr/drivers/charger.h +++ b/include/zephyr/drivers/charger.h @@ -63,6 +63,13 @@ enum charger_property { * current output */ CHARGER_PROP_INPUT_REGULATION_CURRENT_UA, + /** + * Configuration of the input voltage regulation target in µV + * + * This value is a falling voltage threshold that is regulated by reducing the charge + * current output + */ + CHARGER_PROP_INPUT_REGULATION_VOLTAGE_UV, /** Reserved to demark end of common charger properties */ CHARGER_PROP_COMMON_COUNT, /** @@ -209,6 +216,8 @@ union charger_propval { uint32_t const_charge_voltage_uv; /** CHARGER_PROP_INPUT_REGULATION_CURRENT_UA */ uint32_t input_current_regulation_current_ua; + /** CHARGER_PROP_INPUT_REGULATION_VOLTAGE_UV */ + uint32_t input_voltage_regulation_voltage_uv; }; /** From 7d51b7cdc14b56e477e1cbcf2f4f2751f9c6b55b Mon Sep 17 00:00:00 2001 From: Ricardo Rivera-Matos Date: Mon, 11 Dec 2023 17:00:22 -0600 Subject: [PATCH 1961/3723] charger: Adds input current notifier properties Some charger devices (such as BQ25710 and ISL9241) issue notifications to the system via a dedicated line (such as the PROCHOT signal on x86 platforms) to almost instantly throttle the system load to prevent a brownout event. This patch introduces two properties to configure two distinct input current notification events of different severity. Signed-off-by: Ricardo Rivera-Matos --- include/zephyr/drivers/charger.h | 33 ++++++++++++++++++++++++++++++++ 1 file changed, 33 insertions(+) diff --git a/include/zephyr/drivers/charger.h b/include/zephyr/drivers/charger.h index 98c2e33cf5e..cf55fd88402 100644 --- a/include/zephyr/drivers/charger.h +++ b/include/zephyr/drivers/charger.h @@ -70,6 +70,13 @@ enum charger_property { * current output */ CHARGER_PROP_INPUT_REGULATION_VOLTAGE_UV, + /** + * Configuration to issue a notification to the system based on the input current + * level and timing + * + * Value should be of type struct charger_input_current_notifier + */ + CHARGER_PROP_INPUT_CURRENT_NOTIFICATION, /** Reserved to demark end of common charger properties */ CHARGER_PROP_COMMON_COUNT, /** @@ -187,6 +194,30 @@ enum charger_health { CHARGER_HEALTH_NO_BATTERY, }; +/** + * @brief Charger severity levels for system notifications + */ +enum charger_notification_severity { + /** Most severe level, typically triggered instantaneously */ + CHARGER_SEVERITY_PEAK = 0, + /** More severe than the warning level, less severe than peak */ + CHARGER_SEVERITY_CRITICAL, + /** Base severity level */ + CHARGER_SEVERITY_WARNING, +}; + +/** + * @brief The input current thresholds for the charger to notify the system + */ +struct charger_current_notifier { + /** The severity of the notification where CHARGER_SEVERITY_PEAK is the most severe */ + uint8_t severity; + /** The current threshold to be exceeded */ + uint32_t current_ua; + /** The duration of excess current before notifying the system */ + uint32_t duration_us; +}; + /** * @brief container for a charger_property value * @@ -218,6 +249,8 @@ union charger_propval { uint32_t input_current_regulation_current_ua; /** CHARGER_PROP_INPUT_REGULATION_VOLTAGE_UV */ uint32_t input_voltage_regulation_voltage_uv; + /** CHARGER_PROP_INPUT_CURRENT_NOTIFICATION */ + struct charger_current_notifier input_current_notification; }; /** From 49d32447986cd017c97eb65f92bbf251a8b96255 Mon Sep 17 00:00:00 2001 From: Benedikt Schmidt Date: Mon, 18 Dec 2023 10:36:03 +0100 Subject: [PATCH 1962/3723] soc: arm: use sys_cache* for enabling the caches in nxp_s32 Use sys_cache* for enabling the caches in nxp_s32. This automatically considers CONFIG_CACHE_MANAGEMENT and will activate the cases only if this is active. Signed-off-by: Benedikt Schmidt --- soc/arm/nxp_s32/s32k3/soc.c | 10 +++------- 1 file changed, 3 insertions(+), 7 deletions(-) diff --git a/soc/arm/nxp_s32/s32k3/soc.c b/soc/arm/nxp_s32/s32k3/soc.c index 5db4204a89c..be822677189 100644 --- a/soc/arm/nxp_s32/s32k3/soc.c +++ b/soc/arm/nxp_s32/s32k3/soc.c @@ -7,6 +7,7 @@ #include #include #include +#include #include #include @@ -50,13 +51,8 @@ const struct ivt ivt_header __attribute__((section(".ivt_header"))) = { static int soc_init(void) { - SCB_EnableICache(); - - if (IS_ENABLED(CONFIG_DCACHE)) { - if (!(SCB->CCR & SCB_CCR_DC_Msk)) { - SCB_EnableDCache(); - } - } + sys_cache_instr_enable(); + sys_cache_data_enable(); OsIf_Init(NULL); From d992683db5684d689723a4d6aea4d43e7f219867 Mon Sep 17 00:00:00 2001 From: Benedikt Schmidt Date: Mon, 18 Dec 2023 10:41:25 +0100 Subject: [PATCH 1963/3723] soc: arm: replace redundant config option for caches for nxp_imx Replace the redundant cache config options for the nxp_imx and use sys_cache* functions to enable the caches. These will automatically consider CONFIG_CACHE_MANAGEMENT. Signed-off-by: Benedikt Schmidt --- soc/arm/nxp_imx/rt/Kconfig.soc | 12 ------------ soc/arm/nxp_imx/rt/soc_rt10xx.c | 20 +++----------------- soc/arm/nxp_imx/rt/soc_rt11xx.c | 20 +++----------------- 3 files changed, 6 insertions(+), 46 deletions(-) diff --git a/soc/arm/nxp_imx/rt/Kconfig.soc b/soc/arm/nxp_imx/rt/Kconfig.soc index 844fd27e9fb..cbc00915046 100644 --- a/soc/arm/nxp_imx/rt/Kconfig.soc +++ b/soc/arm/nxp_imx/rt/Kconfig.soc @@ -834,16 +834,4 @@ config SECOND_CORE_MCUX generated header specifying the VMA and LMA of each memory section to load -config IMXRT1XXX_CODE_CACHE - bool "Code cache" - default y - help - Enable Code cache at boot for IMXRT1xxx series - -config IMXRT1XXX_DATA_CACHE - bool "Data cache" - default y - help - Enable Data cache at boot for IMXRT1xxx series - endif # SOC_SERIES_IMX_RT diff --git a/soc/arm/nxp_imx/rt/soc_rt10xx.c b/soc/arm/nxp_imx/rt/soc_rt10xx.c index 01075ce3582..dd6e534be23 100644 --- a/soc/arm/nxp_imx/rt/soc_rt10xx.c +++ b/soc/arm/nxp_imx/rt/soc_rt10xx.c @@ -10,6 +10,7 @@ #include #include #include +#include #include #ifdef CONFIG_NXP_IMX_RT_BOOT_HEADER #include @@ -318,23 +319,8 @@ void imxrt_audio_codec_pll_init(uint32_t clock_name, uint32_t clk_src, static int imxrt_init(void) { -#ifndef CONFIG_IMXRT1XXX_CODE_CACHE - /* SystemInit enables code cache, disable it here */ - SCB_DisableICache(); -#else - /* z_arm_init_arch_hw_at_boot() disables code cache if CONFIG_ARCH_CACHE is enabled, - * enable it here. - */ - SCB_EnableICache(); -#endif - - if (IS_ENABLED(CONFIG_IMXRT1XXX_DATA_CACHE)) { - if ((SCB->CCR & SCB_CCR_DC_Msk) == 0) { - SCB_EnableDCache(); - } - } else { - SCB_DisableDCache(); - } + sys_cache_instr_enable(); + sys_cache_data_enable(); /* Initialize system clock */ clock_init(); diff --git a/soc/arm/nxp_imx/rt/soc_rt11xx.c b/soc/arm/nxp_imx/rt/soc_rt11xx.c index 9c38f3e7963..3adedde8d38 100644 --- a/soc/arm/nxp_imx/rt/soc_rt11xx.c +++ b/soc/arm/nxp_imx/rt/soc_rt11xx.c @@ -10,6 +10,7 @@ #include #include #include +#include #include #include #include @@ -673,23 +674,8 @@ static int imxrt_init(void) #if defined(CONFIG_SOC_MIMXRT1176_CM7) || defined(CONFIG_SOC_MIMXRT1166_CM7) -#ifndef CONFIG_IMXRT1XXX_CODE_CACHE - /* SystemInit enables code cache, disable it here */ - SCB_DisableICache(); -#else - /* z_arm_init_arch_hw_at_boot() disables code cache if CONFIG_ARCH_CACHE is enabled, - * enable it here. - */ - SCB_EnableICache(); -#endif - - if (IS_ENABLED(CONFIG_IMXRT1XXX_DATA_CACHE)) { - if ((SCB->CCR & SCB_CCR_DC_Msk) == 0) { - SCB_EnableDCache(); - } - } else { - SCB_DisableDCache(); - } + sys_cache_instr_enable(); + sys_cache_data_enable(); #endif /* Initialize system clock */ From 1f1b430d88dc52bf9bd0e38d3f7bcbaccc3c3f88 Mon Sep 17 00:00:00 2001 From: Benedikt Schmidt Date: Mon, 18 Dec 2023 10:45:47 +0100 Subject: [PATCH 1964/3723] soc: arm: remove redundant cache config options for kv5x Remove the redundant cache config options for kv5x and use the sys_cache* functions to enable the caches. This will automatically consider CONFIG_CACHE_MANAGEMENT. Signed-off-by: Benedikt Schmidt --- soc/arm/nxp_kinetis/kv5x/Kconfig.soc | 8 -------- soc/arm/nxp_kinetis/kv5x/soc.c | 11 +++-------- 2 files changed, 3 insertions(+), 16 deletions(-) diff --git a/soc/arm/nxp_kinetis/kv5x/Kconfig.soc b/soc/arm/nxp_kinetis/kv5x/Kconfig.soc index 3a9a6d3adf2..dd69ca523b0 100644 --- a/soc/arm/nxp_kinetis/kv5x/Kconfig.soc +++ b/soc/arm/nxp_kinetis/kv5x/Kconfig.soc @@ -57,12 +57,4 @@ config SOC_PART_NUMBER_KINETIS_KV5X number selection choice defines the default value for this string. -config KINETIS_KV5X_ENABLE_CODE_CACHE - bool "Code cache" - default y - -config KINETIS_KV5X_ENABLE_DATA_CACHE - bool "Data cache" - default y - endif # SOC_SERIES_KINETIS_KV5X diff --git a/soc/arm/nxp_kinetis/kv5x/soc.c b/soc/arm/nxp_kinetis/kv5x/soc.c index 4c566dadcd0..59b77f1c172 100644 --- a/soc/arm/nxp_kinetis/kv5x/soc.c +++ b/soc/arm/nxp_kinetis/kv5x/soc.c @@ -11,6 +11,7 @@ #include #include #include +#include #include #include @@ -90,14 +91,8 @@ static int kv5x_init(void) /* Initialize system clocks and PLL */ clk_init(); -#ifndef CONFIG_KINETIS_KV5X_ENABLE_CODE_CACHE - /* SystemInit will have enabled the code cache. Disable it here */ - SCB_DisableICache(); -#endif -#ifndef CONFIG_KINETIS_KV5X_ENABLE_DATA_CACHE - /* SystemInit will have enabled the data cache. Disable it here */ - SCB_DisableDCache(); -#endif + sys_cache_instr_enable(); + sys_cache_data_enable(); return 0; } From 2a2919946f96b2624bebe5977e44cbfad1a49d48 Mon Sep 17 00:00:00 2001 From: Benedikt Schmidt Date: Mon, 18 Dec 2023 10:49:10 +0100 Subject: [PATCH 1965/3723] arch: arc: use sys_cache instead of arch-function for enabling the cache Use sys_cache_data_enable instead of arch_dcache_enable to enable the cache. This will ensure that CONFIG_CACHE_MANAGEMENT is considered correctly. Signed-off-by: Benedikt Schmidt --- arch/arc/core/cache.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/arch/arc/core/cache.c b/arch/arc/core/cache.c index 1536c5a173f..8c2aab29fed 100644 --- a/arch/arc/core/cache.c +++ b/arch/arc/core/cache.c @@ -218,8 +218,7 @@ int arch_icache_flush_and_invd_range(void *addr, size_t size) static int init_dcache(void) { - - arch_dcache_enable(); + sys_cache_data_enable(); #if defined(CONFIG_DCACHE_LINE_SIZE_DETECT) init_dcache_line_size(); From 8b4516226b90fc6c0f8985cc0f3eedebc48aa48a Mon Sep 17 00:00:00 2001 From: Benedikt Schmidt Date: Mon, 18 Dec 2023 10:53:02 +0100 Subject: [PATCH 1966/3723] soc: arm: use sys_cache* for enabling the caches on same70 and samv71 Use the sys_cache* functions to enable the caches on same70 and samv71. This will ensure that CONFIG_CACHE_MANAGEMENT is considered correctly. Signed-off-by: Benedikt Schmidt --- soc/arm/atmel_sam/same70/Kconfig.series | 1 + soc/arm/atmel_sam/same70/soc.c | 25 +++++++++++++++---------- soc/arm/atmel_sam/samv71/Kconfig.series | 1 + soc/arm/atmel_sam/samv71/soc.c | 25 +++++++++++++++---------- 4 files changed, 32 insertions(+), 20 deletions(-) diff --git a/soc/arm/atmel_sam/same70/Kconfig.series b/soc/arm/atmel_sam/same70/Kconfig.series index 66ceeb6ca3e..4e7d6aa396e 100644 --- a/soc/arm/atmel_sam/same70/Kconfig.series +++ b/soc/arm/atmel_sam/same70/Kconfig.series @@ -14,6 +14,7 @@ config SOC_SERIES_SAME70 select CPU_HAS_ICACHE select CPU_HAS_DCACHE select SOC_FAMILY_SAM + select INIT_ARCH_HW_AT_BOOT select PLATFORM_SPECIFIC_INIT select ASF select HAS_SWO diff --git a/soc/arm/atmel_sam/same70/soc.c b/soc/arm/atmel_sam/same70/soc.c index 79d7c9fa830..f68e520c724 100644 --- a/soc/arm/atmel_sam/same70/soc.c +++ b/soc/arm/atmel_sam/same70/soc.c @@ -14,6 +14,8 @@ #include #include #include +#include +#include #include #include #include @@ -226,16 +228,19 @@ static ALWAYS_INLINE void clock_init(void) void z_arm_platform_init(void) { - if (IS_ENABLED(CONFIG_CACHE_MANAGEMENT) && IS_ENABLED(CONFIG_ICACHE)) { - SCB_EnableICache(); - } else { - SCB_DisableICache(); - } - if (IS_ENABLED(CONFIG_CACHE_MANAGEMENT) && IS_ENABLED(CONFIG_DCACHE)) { - SCB_EnableDCache(); - } else { - SCB_DisableDCache(); - } + /* + * DTCM is enabled by default at reset, therefore we have to disable + * it first to get the caches into a state where then the + * sys_cache*-functions can enable them, if requested by the + * configuration. + */ + SCB_DisableDCache(); + + /* + * Enable the caches only if configured to do so. + */ + sys_cache_instr_enable(); + sys_cache_data_enable(); /* * Set FWS (Flash Wait State) value before increasing Master Clock diff --git a/soc/arm/atmel_sam/samv71/Kconfig.series b/soc/arm/atmel_sam/samv71/Kconfig.series index 543def9d9a2..cadee35acb5 100644 --- a/soc/arm/atmel_sam/samv71/Kconfig.series +++ b/soc/arm/atmel_sam/samv71/Kconfig.series @@ -14,6 +14,7 @@ config SOC_SERIES_SAMV71 select CPU_HAS_ICACHE select CPU_HAS_DCACHE select SOC_FAMILY_SAM + select INIT_ARCH_HW_AT_BOOT select PLATFORM_SPECIFIC_INIT select ASF select HAS_SWO diff --git a/soc/arm/atmel_sam/samv71/soc.c b/soc/arm/atmel_sam/samv71/soc.c index 7571ce46dc7..f88a3cb440b 100644 --- a/soc/arm/atmel_sam/samv71/soc.c +++ b/soc/arm/atmel_sam/samv71/soc.c @@ -14,6 +14,8 @@ #include #include #include +#include +#include #include #include #include @@ -226,16 +228,19 @@ static ALWAYS_INLINE void clock_init(void) void z_arm_platform_init(void) { - if (IS_ENABLED(CONFIG_CACHE_MANAGEMENT) && IS_ENABLED(CONFIG_ICACHE)) { - SCB_EnableICache(); - } else { - SCB_DisableICache(); - } - if (IS_ENABLED(CONFIG_CACHE_MANAGEMENT) && IS_ENABLED(CONFIG_DCACHE)) { - SCB_EnableDCache(); - } else { - SCB_DisableDCache(); - } + /* + * DTCM is enabled by default at reset, therefore we have to disable + * it first to get the caches into a state where then the + * sys_cache*-functions can enable them, if requested by the + * configuration. + */ + SCB_DisableDCache(); + + /* + * Enable the caches only if configured to do so. + */ + sys_cache_instr_enable(); + sys_cache_data_enable(); /* * Set FWS (Flash Wait State) value before increasing Master Clock From 10c0b86f83639535aaeedf3d90fe46e9dd779b9c Mon Sep 17 00:00:00 2001 From: Benedikt Schmidt Date: Mon, 18 Dec 2023 11:16:12 +0100 Subject: [PATCH 1967/3723] soc: arm: use sys_cache* to enable caches for stm32f7 and stm32h7 Use sys_cache* functions to enable the caches for stm32f7 and stm32h7. This ensures that CONFIG_CACHE_MANAGEMENT is considered correctly. Signed-off-by: Benedikt Schmidt --- soc/arm/st_stm32/stm32f7/soc.c | 10 +++------- soc/arm/st_stm32/stm32h7/soc_m7.c | 10 +++------- 2 files changed, 6 insertions(+), 14 deletions(-) diff --git a/soc/arm/st_stm32/stm32f7/soc.c b/soc/arm/st_stm32/stm32f7/soc.c index 19941c9cee0..4a9cc72a78d 100644 --- a/soc/arm/st_stm32/stm32f7/soc.c +++ b/soc/arm/st_stm32/stm32f7/soc.c @@ -12,6 +12,7 @@ #include #include #include +#include #include #include @@ -30,13 +31,8 @@ static int st_stm32f7_init(void) /* Enable ART Flash cache accelerator */ LL_FLASH_EnableART(); - if (IS_ENABLED(CONFIG_ICACHE)) { - SCB_EnableICache(); - } - - if (IS_ENABLED(CONFIG_DCACHE)) { - SCB_EnableDCache(); - } + sys_cache_instr_enable(); + sys_cache_data_enable(); /* Update CMSIS SystemCoreClock variable (HCLK) */ /* At reset, system core clock is set to 16 MHz from HSI */ diff --git a/soc/arm/st_stm32/stm32h7/soc_m7.c b/soc/arm/st_stm32/stm32h7/soc_m7.c index 7ee62921c41..39c1d917c34 100644 --- a/soc/arm/st_stm32/stm32h7/soc_m7.c +++ b/soc/arm/st_stm32/stm32h7/soc_m7.c @@ -12,6 +12,7 @@ #include #include #include +#include #include #include #include @@ -54,13 +55,8 @@ static int stm32h7_m4_wakeup(void) */ static int stm32h7_init(void) { - if (IS_ENABLED(CONFIG_ICACHE)) { - SCB_EnableICache(); - } - - if (IS_ENABLED(CONFIG_DCACHE)) { - SCB_EnableDCache(); - } + sys_cache_instr_enable(); + sys_cache_data_enable(); /* Update CMSIS SystemCoreClock variable (HCLK) */ /* At reset, system core clock is set to 64 MHz from HSI */ From 70c8df7724e7d597122315927de47105ab99ad47 Mon Sep 17 00:00:00 2001 From: Benedikt Schmidt Date: Wed, 27 Dec 2023 17:09:02 +0100 Subject: [PATCH 1968/3723] arch: arm: core: cortex_m: fix cache disabling in init_arch_hw_at_boot Use the arch-cache functions instead of the sys-cache-functions in z_arm_init_arch_hw_at_boot to ensure that the caches are disabled even when CONFIG_CACHE_MANAGEMENT is disabled. Signed-off-by: Benedikt Schmidt --- arch/arm/core/cortex_m/scb.c | 21 +++++++++++++++++---- 1 file changed, 17 insertions(+), 4 deletions(-) diff --git a/arch/arm/core/cortex_m/scb.c b/arch/arm/core/cortex_m/scb.c index 472c8242465..e3c35073ea3 100644 --- a/arch/arm/core/cortex_m/scb.c +++ b/arch/arm/core/cortex_m/scb.c @@ -21,6 +21,7 @@ #include #include #include +#include #if defined(CONFIG_CPU_HAS_NXP_MPU) #include @@ -120,15 +121,27 @@ void z_arm_init_arch_hw_at_boot(void) * reset it to a known clean state. */ if (SCB->CCR & SCB_CCR_DC_Msk) { - sys_cache_data_disable(); + /* + * Do not use sys_cache_data_disable at this point, but instead + * the architecture specific function. This ensures that the + * cache is disabled although CONFIG_CACHE_MANAGEMENT might be + * disabled. + */ + SCB_DisableDCache(); } else { - sys_cache_data_invd_all(); + SCB_InvalidateDCache(); } #endif /* CONFIG_DCACHE */ #if defined(CONFIG_ICACHE) - /* Reset I-Cache settings. */ - sys_cache_instr_disable(); + /* + * Reset I-Cache settings. + * Do not use sys_cache_data_disable at this point, but instead + * the architecture specific function. This ensures that the + * cache is disabled although CONFIG_CACHE_MANAGEMENT might be + * disabled. + */ + SCB_DisableICache(); #endif /* CONFIG_ICACHE */ #endif /* CONFIG_ARCH_CACHE */ From 83ca2a04a0861f1382fa25d0aad3c18243e64e45 Mon Sep 17 00:00:00 2001 From: Abe Kohandel Date: Mon, 8 Jan 2024 03:09:02 +0000 Subject: [PATCH 1969/3723] drivers: usb_dc_native_posix: do callback for ZLPs A Zero Length Packet can be used by higher layer stack to discover when an endpoint is being processed by the host. An example of this was introduced as part of 0127d000a287 ("usb: device: cdc_acm: Use ZLP to detect initial host read") in the CDC ACM class. Not invoking the callback for ZLPs results in the higher layer stack not being informed when the packet is consumed. This manifests as a CDC ACM USB-IP device that cannot transmit to the host while being able to receive from the host. Signed-off-by: Abe Kohandel --- drivers/usb/device/usb_dc_native_posix.c | 10 ++-------- 1 file changed, 2 insertions(+), 8 deletions(-) diff --git a/drivers/usb/device/usb_dc_native_posix.c b/drivers/usb/device/usb_dc_native_posix.c index 70410db2440..c74dad9b35d 100644 --- a/drivers/usb/device/usb_dc_native_posix.c +++ b/drivers/usb/device/usb_dc_native_posix.c @@ -605,14 +605,8 @@ int handle_usb_data(struct usbip_header *hdr) LOG_HEXDUMP_DBG(ep_ctrl->buf, ep_ctrl->buf_len, ">"); - /* - * Call the callback only if data in usb_dc_ep_write() - * is actually written to the intermediate buffer and sent. - */ - if (ep_ctrl->buf_len != 0) { - ep_ctrl->cb(ep, USB_DC_EP_DATA_IN); - usbip_ctrl.in_ep_ctrl[ep_idx].buf_len = 0; - } + ep_ctrl->cb(ep, USB_DC_EP_DATA_IN); + ep_ctrl->buf_len = 0; } return 0; From eac50e318f4d72833ba80fff8848a8352a9537f3 Mon Sep 17 00:00:00 2001 From: Weiwei Guo Date: Mon, 8 Jan 2024 18:17:22 +0800 Subject: [PATCH 1970/3723] drivers: intc_plic: fix plic PLIC_TRIG_LEVEL define mistake Interrupt trigger type register each bit indicate the configured interrupt type. bit value is 0 indicate level trigger interrupt, 1 indicate edge trigger interrupt. The level trigger defined to ~BIT(0) equal 0xfffffffe not equal 0. Signed-off-by: Weiwei Guo --- drivers/interrupt_controller/intc_plic.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/interrupt_controller/intc_plic.c b/drivers/interrupt_controller/intc_plic.c index c33e699bb96..bdfccced192 100644 --- a/drivers/interrupt_controller/intc_plic.c +++ b/drivers/interrupt_controller/intc_plic.c @@ -43,8 +43,8 @@ * However, it is defined and supported by at least the Andes & Telink datasheet, and supported * in Linux's SiFive PLIC driver */ -#define PLIC_TRIG_LEVEL ((uint32_t)~BIT(0)) -#define PLIC_TRIG_EDGE ((uint32_t)BIT(0)) +#define PLIC_TRIG_LEVEL ((uint32_t)0) +#define PLIC_TRIG_EDGE ((uint32_t)1) #define PLIC_DRV_HAS_COMPAT(compat) \ DT_NODE_HAS_COMPAT(DT_COMPAT_GET_ANY_STATUS_OKAY(DT_DRV_COMPAT), compat) From 5b993b070a1a2cff3a19fa27207c521e5bfae5bb Mon Sep 17 00:00:00 2001 From: Alberto Escolar Piedras Date: Wed, 3 Jan 2024 14:42:23 +0100 Subject: [PATCH 1971/3723] drivers uart nrfx: Fix ISR prototype The ISR prototype used when building without the interrupt driven UART was not matching the signature for interrupt handlers, which results in build warnings. Let's fix it. Signed-off-by: Alberto Escolar Piedras --- drivers/serial/uart_nrfx_uarte.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/drivers/serial/uart_nrfx_uarte.c b/drivers/serial/uart_nrfx_uarte.c index 3a62057a47a..23b4521d625 100644 --- a/drivers/serial/uart_nrfx_uarte.c +++ b/drivers/serial/uart_nrfx_uarte.c @@ -1378,8 +1378,9 @@ static void txstopped_isr(const struct device *dev) user_callback(dev, &evt); } -static void uarte_nrfx_isr_async(const struct device *dev) +static void uarte_nrfx_isr_async(const void *arg) { + const struct device *dev = arg; NRF_UARTE_Type *uarte = get_uarte_instance(dev); struct uarte_nrfx_data *data = dev->data; From 4efd08bfd8670ad32d31f5ba5570a1c373f68448 Mon Sep 17 00:00:00 2001 From: Alberto Escolar Piedras Date: Thu, 21 Dec 2023 15:48:26 +0100 Subject: [PATCH 1972/3723] drivers uart_nrfx: Get peripheral address from HAL Instead of getting the hardcoded address from the DT structure use its symbolic name which will be resolved by the nRF HAL definitions to the same value. This allows the GPIO peripherals' addresses to be redefined for the simulated targets. Signed-off-by: Alberto Escolar Piedras --- drivers/serial/uart_nrfx_uarte.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/serial/uart_nrfx_uarte.c b/drivers/serial/uart_nrfx_uarte.c index 23b4521d625..fd964af237c 100644 --- a/drivers/serial/uart_nrfx_uarte.c +++ b/drivers/serial/uart_nrfx_uarte.c @@ -1984,7 +1984,7 @@ static int uarte_nrfx_pm_action(const struct device *dev, }; \ static const struct uarte_nrfx_config uarte_##idx##z_config = { \ .pcfg = PINCTRL_DT_DEV_CONFIG_GET(UARTE(idx)), \ - .uarte_regs = (NRF_UARTE_Type *)DT_REG_ADDR(UARTE(idx)), \ + .uarte_regs = _CONCAT(NRF_UARTE, idx), \ .flags = \ (IS_ENABLED(CONFIG_UART_##idx##_GPIO_MANAGEMENT) ? \ UARTE_CFG_FLAG_GPIO_MGMT : 0) | \ From efca307d35a83a798cba22a04125f0c720034a5d Mon Sep 17 00:00:00 2001 From: Alberto Escolar Piedras Date: Fri, 22 Dec 2023 10:23:48 +0100 Subject: [PATCH 1973/3723] drivers uart_nrfx: Correct pinctrl reg address for simulation For simulation, we cannot get the UART regiter address for the pinctrl config structure from DT, as that cannot match the one allocated at build time. So let's override it at runtime with the correct address which is stored in the UART config structure. Signed-off-by: Alberto Escolar Piedras --- boards/posix/nrf_bsim/Kconfig.board | 1 + drivers/serial/uart_nrfx_uarte.c | 5 +++++ 2 files changed, 6 insertions(+) diff --git a/boards/posix/nrf_bsim/Kconfig.board b/boards/posix/nrf_bsim/Kconfig.board index 4a701c9acdc..7989d457ffa 100644 --- a/boards/posix/nrf_bsim/Kconfig.board +++ b/boards/posix/nrf_bsim/Kconfig.board @@ -12,6 +12,7 @@ config BOARD_NRF52_BSIM select HAS_NRFX select HAS_NORDIC_DRIVERS select NATIVE_LIBRARY + select PINCTRL_DYNAMIC if PINCTRL help Will produce a console Linux process which can be executed natively. It needs the BabbleSim simulator both in compile time and to execute diff --git a/drivers/serial/uart_nrfx_uarte.c b/drivers/serial/uart_nrfx_uarte.c index fd964af237c..6da4a3559ff 100644 --- a/drivers/serial/uart_nrfx_uarte.c +++ b/drivers/serial/uart_nrfx_uarte.c @@ -1746,6 +1746,11 @@ static int uarte_instance_init(const struct device *dev, data->dev = dev; +#ifdef CONFIG_ARCH_POSIX + /* For simulation the DT provided peripheral address needs to be corrected */ + ((struct pinctrl_dev_config *)cfg->pcfg)->reg = (uintptr_t)cfg->uarte_regs; +#endif + err = pinctrl_apply_state(cfg->pcfg, PINCTRL_STATE_DEFAULT); if (err < 0) { return err; From 83af2d7f3c6bb439c316030eed4d18759a7e3e7e Mon Sep 17 00:00:00 2001 From: Alberto Escolar Piedras Date: Sat, 6 Jan 2024 15:45:24 +0100 Subject: [PATCH 1974/3723] drivers counter nrfx: Fix ISR prototype The ISR prototype is not matching the signature for interrupt handlers, which results in build warnings. Let's fix it. Signed-off-by: Alberto Escolar Piedras --- drivers/counter/counter_nrfx_timer.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/drivers/counter/counter_nrfx_timer.c b/drivers/counter/counter_nrfx_timer.c index caf2c5852e4..024f4d8a725 100644 --- a/drivers/counter/counter_nrfx_timer.c +++ b/drivers/counter/counter_nrfx_timer.c @@ -364,8 +364,10 @@ static void alarm_irq_handle(const struct device *dev, uint32_t id) } } -static void irq_handler(const struct device *dev) +static void irq_handler(const void *arg) { + const struct device *dev = arg; + top_irq_handle(dev); for (uint32_t i = 0; i < counter_get_num_of_channels(dev); i++) { From 9a27906e38343b07cbdf1b4aca5451c5886dbd41 Mon Sep 17 00:00:00 2001 From: Alberto Escolar Piedras Date: Sat, 6 Jan 2024 15:54:13 +0100 Subject: [PATCH 1975/3723] drivers counter_nrfx_timer: Get peripheral address from HAL Instead of getting the hardcoded address from the DT structure use its symbolic name which will be resolved by the nRF HAL definitions to the same value. This allows the TIMER peripherals' addresses to be redefined for the simulated targets. Signed-off-by: Alberto Escolar Piedras --- drivers/counter/counter_nrfx_timer.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/counter/counter_nrfx_timer.c b/drivers/counter/counter_nrfx_timer.c index 024f4d8a725..47537b16d7d 100644 --- a/drivers/counter/counter_nrfx_timer.c +++ b/drivers/counter/counter_nrfx_timer.c @@ -439,7 +439,7 @@ static const struct counter_driver_api counter_nrfx_driver_api = { .channels = CC_TO_ID(DT_INST_PROP(idx, cc_num)), \ }, \ .ch_data = counter##idx##_ch_data, \ - .timer = (NRF_TIMER_Type *)DT_INST_REG_ADDR(idx), \ + .timer = (NRF_TIMER_Type *)_CONCAT(NRF_TIMER, idx), \ LOG_INSTANCE_PTR_INIT(log, LOG_MODULE_NAME, idx) \ }; \ DEVICE_DT_INST_DEFINE(idx, \ From 14bc4aeec86e12838a6f6f09f93e13bb465a5ffb Mon Sep 17 00:00:00 2001 From: Alberto Escolar Piedras Date: Sun, 7 Jan 2024 10:04:26 +0100 Subject: [PATCH 1976/3723] drivers uart_nrfx: Break infinite loops for simulation While waiting for the UART to be ready in ISR mode, for simulation only, add a tiny delay per iteration of the busy wait loops to allow time to pass. This Z_SPIN_DELAY is an empty macro for any other target than simulation. Signed-off-by: Alberto Escolar Piedras --- drivers/serial/uart_nrfx_uarte.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/drivers/serial/uart_nrfx_uarte.c b/drivers/serial/uart_nrfx_uarte.c index 6da4a3559ff..23219f16036 100644 --- a/drivers/serial/uart_nrfx_uarte.c +++ b/drivers/serial/uart_nrfx_uarte.c @@ -1502,6 +1502,7 @@ static void uarte_nrfx_poll_out(const struct device *dev, unsigned char c) } irq_unlock(key); + Z_SPIN_DELAY(2); } } else { key = wait_tx_ready(dev); @@ -1924,6 +1925,7 @@ static int uarte_nrfx_pm_action(const struct device *dev, !nrf_uarte_event_check(uarte, NRF_UARTE_EVENT_ERROR)) { /* Busy wait for event to register */ + Z_SPIN_DELAY(2); } nrf_uarte_event_clear(uarte, NRF_UARTE_EVENT_RXSTARTED); nrf_uarte_event_clear(uarte, NRF_UARTE_EVENT_RXTO); From 572ba26b1fcc46dd943a90e37c1d04168242a4bf Mon Sep 17 00:00:00 2001 From: Alberto Escolar Piedras Date: Thu, 21 Dec 2023 14:07:17 +0100 Subject: [PATCH 1977/3723] boards nrf5*_bsim: Provide more common headers Provide some more common headers some nRF drivers expect. Signed-off-by: Alberto Escolar Piedras --- boards/posix/nrf_bsim/board_soc.h | 1 + boards/posix/nrf_bsim/soc/pinctrl_soc.h | 13 +++++++++++++ boards/posix/nrf_bsim/soc/soc_nrf_common.h | 13 +++++++++++++ 3 files changed, 27 insertions(+) create mode 100644 boards/posix/nrf_bsim/soc/pinctrl_soc.h create mode 100644 boards/posix/nrf_bsim/soc/soc_nrf_common.h diff --git a/boards/posix/nrf_bsim/board_soc.h b/boards/posix/nrf_bsim/board_soc.h index 1b7e7a85c0c..d75a187aa61 100644 --- a/boards/posix/nrf_bsim/board_soc.h +++ b/boards/posix/nrf_bsim/board_soc.h @@ -29,6 +29,7 @@ #include #include #include "cmsis.h" +#include "soc_nrf_common.h" #if defined(CONFIG_BOARD_NRF52_BSIM) #define OFFLOAD_SW_IRQ SWI0_EGU0_IRQn diff --git a/boards/posix/nrf_bsim/soc/pinctrl_soc.h b/boards/posix/nrf_bsim/soc/pinctrl_soc.h new file mode 100644 index 00000000000..08252b57fee --- /dev/null +++ b/boards/posix/nrf_bsim/soc/pinctrl_soc.h @@ -0,0 +1,13 @@ +/* + * Copyright (c) 2024 Nordic Semiconductor ASA + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#ifndef BOARDS_POSIX_NRF_BSIM_SOC_PINCTRL_SOC_H +#define BOARDS_POSIX_NRF_BSIM_SOC_PINCTRL_SOC_H + +/* We reuse the real SOC's header: */ +#include "../soc/arm/nordic_nrf/common/pinctrl_soc.h" + +#endif /* BOARDS_POSIX_NRF_BSIM_SOC_PINCTRL_SOC_H */ diff --git a/boards/posix/nrf_bsim/soc/soc_nrf_common.h b/boards/posix/nrf_bsim/soc/soc_nrf_common.h new file mode 100644 index 00000000000..a77778de653 --- /dev/null +++ b/boards/posix/nrf_bsim/soc/soc_nrf_common.h @@ -0,0 +1,13 @@ +/* + * Copyright (c) 2024 Nordic Semiconductor ASA + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#ifndef BOARDS_POSIX_NRF_BSIM_SOC_SOC_NRF_COMMON_H +#define BOARDS_POSIX_NRF_BSIM_SOC_SOC_NRF_COMMON_H + +/* We reuse the real SOC's header: */ +#include "../soc/arm/nordic_nrf/common/soc_nrf_common.h" + +#endif /* BOARDS_POSIX_NRF_BSIM_SOC_SOC_NRF_COMMON_H */ From 85d3ad11179cdc4bf030659e1d413215f1c6b866 Mon Sep 17 00:00:00 2001 From: Alberto Escolar Piedras Date: Mon, 8 Jan 2024 15:08:26 +0100 Subject: [PATCH 1978/3723] manifest: Update nrf hw models to latest * Update the HW models module to c744f2c762aad79e59bd7e99002f2fcab0a2f288 Including the following: * docs: UART: several minor fixes * UART(E): Add peripherals and connect to (D)PPI Signed-off-by: Alberto Escolar Piedras --- west.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/west.yml b/west.yml index 571decadd94..cdad09e2f98 100644 --- a/west.yml +++ b/west.yml @@ -295,7 +295,7 @@ manifest: groups: - tools - name: nrf_hw_models - revision: 9b985ea6bc237b6ae06f48eb228f2ac7f6e3b96b + revision: c744f2c762aad79e59bd7e99002f2fcab0a2f288 path: modules/bsim_hw_models/nrf_hw_models - name: open-amp revision: da78aea63159771956fe0c9263f2e6985b66e9d5 From f84ef2d6eea0945ab79244dd52db9dd8fc532388 Mon Sep 17 00:00:00 2001 From: Alberto Escolar Piedras Date: Thu, 21 Dec 2023 12:30:32 +0100 Subject: [PATCH 1979/3723] boards nrf5*_bsim: Allow using the UART Now the HW models include the UART(E) models. So let's allow selecting it, but let's not default to it, or enable it by default, as it is only in very rare cases uses will want it, and some may already be using the native ptty instead. Signed-off-by: Alberto Escolar Piedras --- boards/posix/nrf_bsim/nrf52_bsim.dts | 4 ---- boards/posix/nrf_bsim/nrf5340bsim_nrf5340_cpuapp.dts | 8 -------- boards/posix/nrf_bsim/nrf5340bsim_nrf5340_cpunet.dts | 2 -- 3 files changed, 14 deletions(-) diff --git a/boards/posix/nrf_bsim/nrf52_bsim.dts b/boards/posix/nrf_bsim/nrf52_bsim.dts index a408ceb0eee..3ae42f78deb 100644 --- a/boards/posix/nrf_bsim/nrf52_bsim.dts +++ b/boards/posix/nrf_bsim/nrf52_bsim.dts @@ -22,8 +22,6 @@ /delete-property/ spi-1; /delete-property/ spi-2; /delete-property/ spi-3; - /delete-property/ uart-0; - /delete-property/ uart-1; /delete-property/ adc-0; /delete-property/ wdt-0; /delete-property/ pwm-0; @@ -41,8 +39,6 @@ soc { /delete-node/ memory@20000000; /delete-node/ adc@40007000; - /delete-node/ uart@40002000; - /delete-node/ uart@40028000; /delete-node/ i2c@40003000; /delete-node/ i2c@40004000; /delete-node/ pwm@4001c000; diff --git a/boards/posix/nrf_bsim/nrf5340bsim_nrf5340_cpuapp.dts b/boards/posix/nrf_bsim/nrf5340bsim_nrf5340_cpuapp.dts index c5ec3c95af5..72194f3b0e1 100644 --- a/boards/posix/nrf_bsim/nrf5340bsim_nrf5340_cpuapp.dts +++ b/boards/posix/nrf_bsim/nrf5340bsim_nrf5340_cpuapp.dts @@ -18,17 +18,13 @@ /delete-property/ sram-0; /delete-property/ i2c-0; /delete-property/ spi-0; - /delete-property/ uart-0; /delete-property/ i2c-1; /delete-property/ spi-1; - /delete-property/ uart-1; /delete-property/ spi-4; /delete-property/ i2c-2; /delete-property/ spi-2; - /delete-property/ uart-2; /delete-property/ i2c-3; /delete-property/ spi-3; - /delete-property/ uart-3; /delete-property/ wdt-0; /delete-property/ wdt-1; /delete-property/ pwm-0; @@ -61,17 +57,13 @@ /delete-node/ ctrlap@6000; /delete-node/ i2c@8000; /delete-node/ spi@8000; - /delete-node/ uart@8000; /delete-node/ i2c@9000; /delete-node/ spi@9000; - /delete-node/ uart@9000; /delete-node/ spi@a000; /delete-node/ i2c@b000; /delete-node/ spi@b000; - /delete-node/ uart@b000; /delete-node/ i2c@c000; /delete-node/ spi@c000; - /delete-node/ uart@c000; /delete-node/ adc@e000; /delete-node/ watchdog@18000; /delete-node/ watchdog@19000; diff --git a/boards/posix/nrf_bsim/nrf5340bsim_nrf5340_cpunet.dts b/boards/posix/nrf_bsim/nrf5340bsim_nrf5340_cpunet.dts index d9d7b02fc67..93e3ee27163 100644 --- a/boards/posix/nrf_bsim/nrf5340bsim_nrf5340_cpunet.dts +++ b/boards/posix/nrf_bsim/nrf5340bsim_nrf5340_cpunet.dts @@ -21,7 +21,6 @@ /delete-property/ wdt-0; /delete-property/ i2c-0; /delete-property/ spi-0; - /delete-property/ uart-0; /delete-property/ gpio-0; /delete-property/ gpio-1; }; @@ -41,7 +40,6 @@ /delete-node/ watchdog@4100b000; /delete-node/ i2c@41013000; /delete-node/ spi@41013000; - /delete-node/ uart@41013000; /delete-node/ acl@41080000; /delete-node/ vmc@41081000; /delete-node/ gpio@418c0500; From 0bdf94390076d1a205842bc565105c28de4b176c Mon Sep 17 00:00:00 2001 From: Alberto Escolar Piedras Date: Fri, 5 Jan 2024 12:31:01 +0100 Subject: [PATCH 1980/3723] boards nrf*_bsim: Do not use the UART for logging by default Even if the UART is enabled, let's not use it by default, in this platform, as this UART is not meant for user interaction, but to connect other devices (for ex. BT controller). Signed-off-by: Alberto Escolar Piedras --- boards/posix/nrf_bsim/nrf52_bsim_defconfig | 1 + 1 file changed, 1 insertion(+) diff --git a/boards/posix/nrf_bsim/nrf52_bsim_defconfig b/boards/posix/nrf_bsim/nrf52_bsim_defconfig index 42231465cea..953e8c1aa93 100644 --- a/boards/posix/nrf_bsim/nrf52_bsim_defconfig +++ b/boards/posix/nrf_bsim/nrf52_bsim_defconfig @@ -4,3 +4,4 @@ CONFIG_SOC_POSIX=y CONFIG_BOARD_NRF52_BSIM=y CONFIG_CONSOLE=y CONFIG_NO_OPTIMIZATIONS=y +CONFIG_LOG_BACKEND_UART=n From 6fee105b1db9faffa16ac4d331bf56e87cf989f8 Mon Sep 17 00:00:00 2001 From: Alberto Escolar Piedras Date: Thu, 21 Dec 2023 13:09:40 +0100 Subject: [PATCH 1981/3723] boards nrf52_bsim: Provide default UART configuration Provide a good enough UART configuration, but do not select it as backend by default, let apps do that. The UART and its driver are very heavy compared to other backends it may replace, so let's avoid enabling it by default. Signed-off-by: Alberto Escolar Piedras --- boards/posix/nrf_bsim/Kconfig.defconfig | 5 +---- boards/posix/nrf_bsim/nrf52_bsim.dts | 25 +++++++++++++++++++++++++ 2 files changed, 26 insertions(+), 4 deletions(-) diff --git a/boards/posix/nrf_bsim/Kconfig.defconfig b/boards/posix/nrf_bsim/Kconfig.defconfig index e762a3c6c85..d4e48ada7ad 100644 --- a/boards/posix/nrf_bsim/Kconfig.defconfig +++ b/boards/posix/nrf_bsim/Kconfig.defconfig @@ -87,10 +87,7 @@ endif # LOG if CONSOLE config POSIX_ARCH_CONSOLE - default y if !SERIAL - -config UART_CONSOLE - default y if SERIAL + default y endif # CONSOLE diff --git a/boards/posix/nrf_bsim/nrf52_bsim.dts b/boards/posix/nrf_bsim/nrf52_bsim.dts index 3ae42f78deb..8410c80fb74 100644 --- a/boards/posix/nrf_bsim/nrf52_bsim.dts +++ b/boards/posix/nrf_bsim/nrf52_bsim.dts @@ -9,6 +9,8 @@ #include #include +/* We resuse the pinctrl definitions directly from the real board : */ +#include <../boards/arm/nrf52833dk_nrf52833/nrf52833dk_nrf52833-pinctrl.dtsi> / { model = "nrf52 bsim"; @@ -34,6 +36,10 @@ chosen { zephyr,ieee802154 = &ieee802154; zephyr,flash = &flash0; + /* UART used by the BT controller UART HCI driver by default: */ + zephyr,bt-c2h-uart = &uart1; + /* UART used by the BT host UART HCI driver by default: */ + zephyr,bt-uart = &uart1; }; soc { @@ -94,3 +100,22 @@ }; }; }; + +&uart0 { + compatible = "nordic,nrf-uarte"; + status = "okay"; + current-speed = <115200>; + pinctrl-0 = <&uart0_default>; + pinctrl-1 = <&uart0_sleep>; + pinctrl-names = "default", "sleep"; +}; + +&uart1 { + compatible = "nordic,nrf-uarte"; + status = "okay"; + current-speed = <115200>; + pinctrl-0 = <&uart1_default>; + pinctrl-1 = <&uart1_sleep>; + pinctrl-names = "default", "sleep"; + hw-flow-control; +}; From 0aa0bc9af0cc702d40dbd34cb1aa4f3c441e8825 Mon Sep 17 00:00:00 2001 From: Alberto Escolar Piedras Date: Fri, 5 Jan 2024 13:50:57 +0100 Subject: [PATCH 1982/3723] boards nrf*bsim: Move common kconfig selection to common place Reduce a bit the amount of boilerplate by placing common Kconfig selections in common options. Signed-off-by: Alberto Escolar Piedras --- boards/posix/nrf_bsim/Kconfig | 12 +++++++++--- boards/posix/nrf_bsim/Kconfig.board | 19 ------------------- 2 files changed, 9 insertions(+), 22 deletions(-) diff --git a/boards/posix/nrf_bsim/Kconfig b/boards/posix/nrf_bsim/Kconfig index 7d67c44d284..d86478a4f4c 100644 --- a/boards/posix/nrf_bsim/Kconfig +++ b/boards/posix/nrf_bsim/Kconfig @@ -17,19 +17,25 @@ endif # SOC_SERIES_BSIM_NRFXX config SOC_SERIES_BSIM_NRFXX bool - depends on SOC_POSIX + select NATIVE_LIBRARY + select SOC_COMPATIBLE_NRF + select HAS_NRFX + select HAS_NORDIC_DRIVERS + select PINCTRL_DYNAMIC if PINCTRL help Any NRF simulated SOC with BabbleSim, based on the POSIX arch config SOC_SERIES_BSIM_NRF52X bool - depends on SOC_SERIES_BSIM_NRFXX + select SOC_SERIES_BSIM_NRFXX + select SOC_COMPATIBLE_NRF52X help Any NRF52 simulated SOC with BabbleSim, based on the POSIX arch config SOC_SERIES_BSIM_NRF53X bool - depends on SOC_SERIES_BSIM_NRFXX + select SOC_SERIES_BSIM_NRFXX + select SOC_COMPATIBLE_NRF53X help Any NRF53 simulated SOC with BabbleSim, based on the POSIX arch diff --git a/boards/posix/nrf_bsim/Kconfig.board b/boards/posix/nrf_bsim/Kconfig.board index 7989d457ffa..fcfbae4d4e7 100644 --- a/boards/posix/nrf_bsim/Kconfig.board +++ b/boards/posix/nrf_bsim/Kconfig.board @@ -2,49 +2,30 @@ config BOARD_NRF52_BSIM bool "NRF52 simulation model" - select SOC_SERIES_BSIM_NRFXX select SOC_SERIES_BSIM_NRF52X - select SOC_COMPATIBLE_NRF - select SOC_COMPATIBLE_NRF52X select SOC_COMPATIBLE_NRF52833 select NRF_RTC_TIMER select CLOCK_CONTROL - select HAS_NRFX - select HAS_NORDIC_DRIVERS - select NATIVE_LIBRARY - select PINCTRL_DYNAMIC if PINCTRL help Will produce a console Linux process which can be executed natively. It needs the BabbleSim simulator both in compile time and to execute config BOARD_NRF5340BSIM_NRF5340_CPUNET bool "Simulated NRF53 Network core" - select SOC_SERIES_BSIM_NRFXX select SOC_SERIES_BSIM_NRF53X - select SOC_COMPATIBLE_NRF - select SOC_COMPATIBLE_NRF53X select SOC_COMPATIBLE_NRF5340_CPUNET select NRF_RTC_TIMER select CLOCK_CONTROL - select HAS_NRFX - select HAS_NORDIC_DRIVERS - select NATIVE_LIBRARY help Will produce a console Linux process which can be executed natively. It needs the BabbleSim simulator both in compile time and to execute config BOARD_NRF5340BSIM_NRF5340_CPUAPP bool "Simulated NRF53 Application core" - select SOC_SERIES_BSIM_NRFXX select SOC_SERIES_BSIM_NRF53X - select SOC_COMPATIBLE_NRF - select SOC_COMPATIBLE_NRF53X select SOC_COMPATIBLE_NRF5340_CPUAPP select NRF_RTC_TIMER select CLOCK_CONTROL - select HAS_NRFX - select HAS_NORDIC_DRIVERS - select NATIVE_LIBRARY help Will produce a console Linux process which can be executed natively. It needs the BabbleSim simulator both in compile time and to execute From 2f25cd58512ba3d24b28bd5590624cdf68c3711c Mon Sep 17 00:00:00 2001 From: Alberto Escolar Piedras Date: Sat, 6 Jan 2024 14:39:58 +0100 Subject: [PATCH 1983/3723] boards nrf52_bsim docs: UART is now supported Add the UART to the list of supported peripherals Signed-off-by: Alberto Escolar Piedras --- boards/posix/nrf_bsim/doc/nrf52_bsim.rst | 1 + 1 file changed, 1 insertion(+) diff --git a/boards/posix/nrf_bsim/doc/nrf52_bsim.rst b/boards/posix/nrf_bsim/doc/nrf52_bsim.rst index da1212e3367..78c8e5c3279 100644 --- a/boards/posix/nrf_bsim/doc/nrf52_bsim.rst +++ b/boards/posix/nrf_bsim/doc/nrf52_bsim.rst @@ -36,6 +36,7 @@ This board includes models of some of the nRF52 SOC peripherals: * RNG (Random Number Generator) * RTC (Real Time Counter) * TEMP (Temperature sensor) +* UART & UARTE (UART with Easy DMA) * UICR (User Information Configuration Registers) and will use the same drivers as the nrf52 dk targets for these. From 398e4b121af48b14b46b87d45f47a4fd49d46087 Mon Sep 17 00:00:00 2001 From: Alberto Escolar Piedras Date: Fri, 5 Jan 2024 11:24:18 +0100 Subject: [PATCH 1984/3723] tests bsim bt: Add basic connection test with HCI UART controllers Add a basic connection test between two devices, in which the controllers are in separate nrf52_bsim devices connected over UART to the devices running the host+app. Signed-off-by: Alberto Escolar Piedras --- tests/bsim/bluetooth/compile.sh | 3 ++ tests/bsim/bluetooth/hci_uart/compile.sh | 24 ++++++++++ .../tests_scripts/basic_conn_split_uart.sh | 46 +++++++++++++++++++ .../bluetooth/ll/conn/prj_split_uart.conf | 18 ++++++++ 4 files changed, 91 insertions(+) create mode 100755 tests/bsim/bluetooth/hci_uart/compile.sh create mode 100755 tests/bsim/bluetooth/hci_uart/tests_scripts/basic_conn_split_uart.sh create mode 100644 tests/bsim/bluetooth/ll/conn/prj_split_uart.conf diff --git a/tests/bsim/bluetooth/compile.sh b/tests/bsim/bluetooth/compile.sh index b6b709f84d2..c0e3d813d72 100755 --- a/tests/bsim/bluetooth/compile.sh +++ b/tests/bsim/bluetooth/compile.sh @@ -28,5 +28,8 @@ ${ZEPHYR_BASE}/tests/bsim/bluetooth/audio_samples/compile.sh ${ZEPHYR_BASE}/tests/bsim/bluetooth/host/compile.sh ${ZEPHYR_BASE}/tests/bsim/bluetooth/ll/compile.sh ${ZEPHYR_BASE}/tests/bsim/bluetooth/mesh/compile.sh +if [ ${BOARD} == "nrf52_bsim" ]; then + ${ZEPHYR_BASE}/tests/bsim/bluetooth/hci_uart/compile.sh +fi wait_for_background_jobs diff --git a/tests/bsim/bluetooth/hci_uart/compile.sh b/tests/bsim/bluetooth/hci_uart/compile.sh new file mode 100755 index 00000000000..182ed938ea8 --- /dev/null +++ b/tests/bsim/bluetooth/hci_uart/compile.sh @@ -0,0 +1,24 @@ +#!/usr/bin/env bash +# Copyright 2024 Nordic Semiconductor ASA +# SPDX-License-Identifier: Apache-2.0 + +# Compile all the applications needed by the bsim tests in these subfolders + +#set -x #uncomment this line for debugging +set -ue +: "${BSIM_COMPONENTS_PATH:?BSIM_COMPONENTS_PATH must be defined}" +: "${ZEPHYR_BASE:?ZEPHYR_BASE must be set to point to the zephyr root\ + directory}" + +WORK_DIR="${WORK_DIR:-${ZEPHYR_BASE}/bsim_out}" + +BOARD_ROOT="${BOARD_ROOT:-${ZEPHYR_BASE}}" + +mkdir -p ${WORK_DIR} + +source ${ZEPHYR_BASE}/tests/bsim/compile.source + +app=tests/bsim/bluetooth/ll/conn conf_file=prj_split_uart.conf compile +app=samples/bluetooth/hci_uart compile + +wait_for_background_jobs diff --git a/tests/bsim/bluetooth/hci_uart/tests_scripts/basic_conn_split_uart.sh b/tests/bsim/bluetooth/hci_uart/tests_scripts/basic_conn_split_uart.sh new file mode 100755 index 00000000000..765115ad449 --- /dev/null +++ b/tests/bsim/bluetooth/hci_uart/tests_scripts/basic_conn_split_uart.sh @@ -0,0 +1,46 @@ +#!/usr/bin/env bash +# Copyright 2024 Nordic Semiconductor ASA +# SPDX-License-Identifier: Apache-2.0 + +source ${ZEPHYR_BASE}/tests/bsim/sh_common.source + +# Basic connection test: a central connects to a peripheral and expects a +# notification, using the split controller (ULL LLL) +# Both central and peripheral hosts have their controllers in a separate device +# connected over UART. The controller is the HCI UART sample. +simulation_id="basic_conn_split_uart" +verbosity_level=2 +EXECUTE_TIMEOUT=10 + +cd ${BSIM_OUT_PATH}/bin + +UART_DIR=/tmp/bs_${USER}/${simulation_id}/ +UART_PER=${UART_DIR}/peripheral +UART_CEN=${UART_DIR}/central + +# Note the host+app devices are NOT connected to the phy, only the controllers are. + +# Peripheral app + host : +Execute ./bs_${BOARD}_tests_bsim_bluetooth_ll_conn_prj_split_uart_conf \ + -v=${verbosity_level} -s=${simulation_id} -d=10 -nosim -RealEncryption=0 \ + -testid=peripheral -rs=23 -uart1_fifob_rxfile=${UART_PER}.rx -uart1_fifob_txfile=${UART_PER}.tx + +# Peripheral controller: +Execute ./bs_${BOARD}_samples_bluetooth_hci_uart_prj_conf \ + -v=${verbosity_level} -s=${simulation_id} -d=0 -RealEncryption=0 \ + -rs=23 -uart1_fifob_rxfile=${UART_PER}.tx -uart1_fifob_txfile=${UART_PER}.rx \ + +# Central app + host +Execute ./bs_${BOARD}_tests_bsim_bluetooth_ll_conn_prj_split_uart_conf\ + -v=${verbosity_level} -s=${simulation_id} -d=11 -nosim -RealEncryption=0 \ + -testid=central -rs=6 -uart1_fifob_rxfile=${UART_CEN}.rx -uart1_fifob_txfile=${UART_CEN}.tx + +# Central controller: +Execute ./bs_${BOARD}_samples_bluetooth_hci_uart_prj_conf \ + -v=${verbosity_level} -s=${simulation_id} -d=1 -RealEncryption=0 \ + -rs=23 -uart1_fifob_rxfile=${UART_CEN}.tx -uart1_fifob_txfile=${UART_CEN}.rx + +Execute ./bs_2G4_phy_v1 -v=${verbosity_level} -s=${simulation_id} \ + -D=2 -sim_length=20e6 $@ + +wait_for_background_jobs diff --git a/tests/bsim/bluetooth/ll/conn/prj_split_uart.conf b/tests/bsim/bluetooth/ll/conn/prj_split_uart.conf new file mode 100644 index 00000000000..bdc23cac294 --- /dev/null +++ b/tests/bsim/bluetooth/ll/conn/prj_split_uart.conf @@ -0,0 +1,18 @@ +CONFIG_BT=y +CONFIG_LOG=y +CONFIG_BT_CENTRAL=y +CONFIG_BT_PERIPHERAL=y +CONFIG_BT_PRIVACY=y +CONFIG_BT_SMP=y +CONFIG_BT_SIGNING=y +CONFIG_BT_BAS=y +CONFIG_BT_HRS=y +CONFIG_BT_ATT_PREPARE_COUNT=2 +CONFIG_BT_GATT_CLIENT=y +CONFIG_BT_L2CAP_DYNAMIC_CHANNEL=y +CONFIG_BT_DEVICE_NAME="bsim_test_split_uart" +CONFIG_BT_L2CAP_TX_BUF_COUNT=6 + +CONFIG_BT_HCI=y +CONFIG_BT_CTLR=n +CONFIG_BT_H4=y From 009fcd70e5fbdf1d391e16738bc3e5f5217febd7 Mon Sep 17 00:00:00 2001 From: Alberto Escolar Piedras Date: Fri, 5 Jan 2024 16:17:30 +0100 Subject: [PATCH 1985/3723] tests bsim bt: Add basic connection test with HCI UART async controllers Add a basic connection test between two devices, in which the controllers are in separate nrf52_bsim devices connected over UART to the devices running the host+app. The controllers are running the HCI UART async sample. Signed-off-by: Alberto Escolar Piedras --- .../hci_uart_async/boards/nrf52_bsim.overlay | 1 + tests/bsim/bluetooth/hci_uart/compile.sh | 1 + .../basic_conn_split_uart_async.sh | 46 +++++++++++++++++++ 3 files changed, 48 insertions(+) create mode 100644 samples/bluetooth/hci_uart_async/boards/nrf52_bsim.overlay create mode 100755 tests/bsim/bluetooth/hci_uart/tests_scripts/basic_conn_split_uart_async.sh diff --git a/samples/bluetooth/hci_uart_async/boards/nrf52_bsim.overlay b/samples/bluetooth/hci_uart_async/boards/nrf52_bsim.overlay new file mode 100644 index 00000000000..adef7109b3c --- /dev/null +++ b/samples/bluetooth/hci_uart_async/boards/nrf52_bsim.overlay @@ -0,0 +1 @@ +/* Purposely empty. To avoid using the one provided by the application */ diff --git a/tests/bsim/bluetooth/hci_uart/compile.sh b/tests/bsim/bluetooth/hci_uart/compile.sh index 182ed938ea8..9eea0d52c38 100755 --- a/tests/bsim/bluetooth/hci_uart/compile.sh +++ b/tests/bsim/bluetooth/hci_uart/compile.sh @@ -20,5 +20,6 @@ source ${ZEPHYR_BASE}/tests/bsim/compile.source app=tests/bsim/bluetooth/ll/conn conf_file=prj_split_uart.conf compile app=samples/bluetooth/hci_uart compile +app=samples/bluetooth/hci_uart_async compile wait_for_background_jobs diff --git a/tests/bsim/bluetooth/hci_uart/tests_scripts/basic_conn_split_uart_async.sh b/tests/bsim/bluetooth/hci_uart/tests_scripts/basic_conn_split_uart_async.sh new file mode 100755 index 00000000000..ca2d9ea2ec8 --- /dev/null +++ b/tests/bsim/bluetooth/hci_uart/tests_scripts/basic_conn_split_uart_async.sh @@ -0,0 +1,46 @@ +#!/usr/bin/env bash +# Copyright 2024 Nordic Semiconductor ASA +# SPDX-License-Identifier: Apache-2.0 + +source ${ZEPHYR_BASE}/tests/bsim/sh_common.source + +# Basic connection test: a central connects to a peripheral and expects a +# notification, using the split controller (ULL LLL) +# Both central and peripheral hosts have their controllers in a separate device +# connected over UART. The controller is the HCI UART async sample. +simulation_id="basic_conn_split_uart_async" +verbosity_level=2 +EXECUTE_TIMEOUT=10 + +cd ${BSIM_OUT_PATH}/bin + +UART_DIR=/tmp/bs_${USER}/${simulation_id}/ +UART_PER=${UART_DIR}/peripheral +UART_CEN=${UART_DIR}/central + +# Note the host+app devices are NOT connected to the phy, only the controllers are. + +# Peripheral app + host : +Execute ./bs_${BOARD}_tests_bsim_bluetooth_ll_conn_prj_split_uart_conf \ + -v=${verbosity_level} -s=${simulation_id} -d=10 -nosim -RealEncryption=0 \ + -testid=peripheral -rs=23 -uart1_fifob_rxfile=${UART_PER}.rx -uart1_fifob_txfile=${UART_PER}.tx + +# Peripheral controller: +Execute ./bs_${BOARD}_samples_bluetooth_hci_uart_async_prj_conf \ + -v=${verbosity_level} -s=${simulation_id} -d=0 -RealEncryption=0 \ + -rs=23 -uart1_fifob_rxfile=${UART_PER}.tx -uart1_fifob_txfile=${UART_PER}.rx + +# Central app + host +Execute ./bs_${BOARD}_tests_bsim_bluetooth_ll_conn_prj_split_uart_conf\ + -v=${verbosity_level} -s=${simulation_id} -d=11 -nosim -RealEncryption=0 \ + -testid=central -rs=6 -uart1_fifob_rxfile=${UART_CEN}.rx -uart1_fifob_txfile=${UART_CEN}.tx + +# Central controller: +Execute ./bs_${BOARD}_samples_bluetooth_hci_uart_async_prj_conf \ + -v=${verbosity_level} -s=${simulation_id} -d=1 -RealEncryption=0 \ + -rs=23 -uart1_fifob_rxfile=${UART_CEN}.tx -uart1_fifob_txfile=${UART_CEN}.rx + +Execute ./bs_2G4_phy_v1 -v=${verbosity_level} -s=${simulation_id} \ + -D=2 -sim_length=20e6 $@ + +wait_for_background_jobs From bd9836be8c81f00337db226fef2e029b4d844821 Mon Sep 17 00:00:00 2001 From: Alberto Escolar Piedras Date: Sat, 6 Jan 2024 15:12:08 +0100 Subject: [PATCH 1986/3723] subsys logging: Enable native backend if possible Let's always enable the native_posix backend even if the serial is used. Both can be used at the same time, and: a) users expect the logger output in the invoking shell even if they enable the UART b) Since printk is routed to the logger twister actually needs it for tests to pass as for native platforms it looks into the stdout of the process. Signed-off-by: Alberto Escolar Piedras --- subsys/logging/backends/Kconfig.native_posix | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/subsys/logging/backends/Kconfig.native_posix b/subsys/logging/backends/Kconfig.native_posix index bde09c9f244..4c734881974 100644 --- a/subsys/logging/backends/Kconfig.native_posix +++ b/subsys/logging/backends/Kconfig.native_posix @@ -4,7 +4,7 @@ config LOG_BACKEND_NATIVE_POSIX bool "Native backend" depends on ARCH_POSIX - default y if !SERIAL + default y select LOG_OUTPUT help Enable backend in native_posix From 37f26174eaa723a7dc6102fef3d2d15c4055036f Mon Sep 17 00:00:00 2001 From: Alberto Escolar Piedras Date: Sat, 6 Jan 2024 15:20:55 +0100 Subject: [PATCH 1987/3723] tests/drivers uart_async_rx: Fix for integration_platforms The test was actually filtered out in the integration platforms (native_sim) as SERIAL was not enabled in its prj.conf and that is not enabled by default for this target. Let's just enable it. Signed-off-by: Alberto Escolar Piedras --- tests/drivers/uart/uart_async_rx/prj.conf | 1 + 1 file changed, 1 insertion(+) diff --git a/tests/drivers/uart/uart_async_rx/prj.conf b/tests/drivers/uart/uart_async_rx/prj.conf index eb88c509ea7..56dee84a9e5 100644 --- a/tests/drivers/uart/uart_async_rx/prj.conf +++ b/tests/drivers/uart/uart_async_rx/prj.conf @@ -1,3 +1,4 @@ CONFIG_ZTEST=y CONFIG_ZTRESS=y CONFIG_UART_ASYNC_RX_HELPER=y +CONFIG_SERIAL=y From c7d179f895679e9ecca4b4d7b91699791a772058 Mon Sep 17 00:00:00 2001 From: Alberto Escolar Piedras Date: Sat, 6 Jan 2024 15:28:04 +0100 Subject: [PATCH 1988/3723] tests/drivers uart_async_api: Fix build error with host gcc For some reason the host gcc (11 & 12) does not believe rx_buf_size is constant. Let's work around it by using the sizeof() expression it is initialized to instead. This fixes a build error when targetting native targets which use the host gcc: tests/drivers/uart/uart_async_api/src/test_uart_async.c:236:34: error: expression in static assertion is not constant 236 | BUILD_ASSERT(rx_buf_size <= sizeof(tdata.rx_first_buffer), "Invalid buf size"); Signed-off-by: Alberto Escolar Piedras --- tests/drivers/uart/uart_async_api/src/test_uart_async.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) 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 9579e49c759..26c8de39897 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 @@ -233,7 +233,7 @@ ZTEST_USER(uart_async_multi_rx, test_multiple_rx_enable) const uint32_t rx_buf_size = sizeof(tx_buf); int ret; - BUILD_ASSERT(rx_buf_size <= sizeof(tdata.rx_first_buffer), "Invalid buf size"); + BUILD_ASSERT(sizeof(tx_buf) <= sizeof(tdata.rx_first_buffer), "Invalid buf size"); /* Enable RX without a timeout. */ ret = uart_rx_enable(uart_dev, tdata.rx_first_buffer, rx_buf_size, SYS_FOREVER_US); From 892e8ef47a5064875795760f8290d8c895504a05 Mon Sep 17 00:00:00 2001 From: Alberto Escolar Piedras Date: Sat, 6 Jan 2024 15:33:19 +0100 Subject: [PATCH 1989/3723] tests/drivers uart_async_*: Provide overlays for nrf52_bsim For uart_async_api, uart_mix_fifo_poll & uart_pm: These test can be run fine in the simulated nrf52_bsim board, just connecting the UART Tx and Rx in loopback, but we need an overlay just like for the real boards. Let's provide it. Signed-off-by: Alberto Escolar Piedras --- tests/drivers/uart/uart_async_api/boards/nrf52_bsim.overlay | 3 +++ .../drivers/uart/uart_mix_fifo_poll/boards/nrf52_bsim.overlay | 3 +++ tests/drivers/uart/uart_pm/boards/nrf52_bsim.overlay | 3 +++ 3 files changed, 9 insertions(+) create mode 100644 tests/drivers/uart/uart_async_api/boards/nrf52_bsim.overlay create mode 100644 tests/drivers/uart/uart_mix_fifo_poll/boards/nrf52_bsim.overlay create mode 100644 tests/drivers/uart/uart_pm/boards/nrf52_bsim.overlay diff --git a/tests/drivers/uart/uart_async_api/boards/nrf52_bsim.overlay b/tests/drivers/uart/uart_async_api/boards/nrf52_bsim.overlay new file mode 100644 index 00000000000..c7277e73775 --- /dev/null +++ b/tests/drivers/uart/uart_async_api/boards/nrf52_bsim.overlay @@ -0,0 +1,3 @@ +/* SPDX-License-Identifier: Apache-2.0 */ + +#include "nrf52840dk_nrf52840.overlay" diff --git a/tests/drivers/uart/uart_mix_fifo_poll/boards/nrf52_bsim.overlay b/tests/drivers/uart/uart_mix_fifo_poll/boards/nrf52_bsim.overlay new file mode 100644 index 00000000000..c7277e73775 --- /dev/null +++ b/tests/drivers/uart/uart_mix_fifo_poll/boards/nrf52_bsim.overlay @@ -0,0 +1,3 @@ +/* SPDX-License-Identifier: Apache-2.0 */ + +#include "nrf52840dk_nrf52840.overlay" diff --git a/tests/drivers/uart/uart_pm/boards/nrf52_bsim.overlay b/tests/drivers/uart/uart_pm/boards/nrf52_bsim.overlay new file mode 100644 index 00000000000..c7277e73775 --- /dev/null +++ b/tests/drivers/uart/uart_pm/boards/nrf52_bsim.overlay @@ -0,0 +1,3 @@ +/* SPDX-License-Identifier: Apache-2.0 */ + +#include "nrf52840dk_nrf52840.overlay" From 7e07ea0435b7b880b67851d555df597d3e3e4032 Mon Sep 17 00:00:00 2001 From: Jamie McCrae Date: Mon, 8 Jan 2024 15:37:29 +0000 Subject: [PATCH 1990/3723] west.yml: MCUboot synchronization from upstream Update Zephyr fork of MCUboot to revision: b994ba2ce29425587957dcbb6c96d4e1872b5737 Brings following Zephyr relevant fixes: - 4d75fc8e bootutil: Fix compatible sector checking - 35e9931c bootutil: Add debug logging for boot status write - db9a7f58 boot: zephyr: cmake: Fix issue with missing dts entries - 8cee3550 zephyr: kconfig: make MBEDTLS_PROMPTLESS depend on MBEDTLS Signed-off-by: Jamie McCrae --- west.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/west.yml b/west.yml index cdad09e2f98..83b7e41b090 100644 --- a/west.yml +++ b/west.yml @@ -282,7 +282,7 @@ manifest: groups: - crypto - name: mcuboot - revision: e9131ee8b8ab9306d8f6ad410fd1e3d8a820ce10 + revision: b994ba2ce29425587957dcbb6c96d4e1872b5737 path: bootloader/mcuboot - name: mipi-sys-t path: modules/debug/mipi-sys-t From a5b467646ad9f3b1b076dced057f01ccfd97be1d Mon Sep 17 00:00:00 2001 From: Lukasz Madej Date: Fri, 5 Jan 2024 14:22:55 +0100 Subject: [PATCH 1991/3723] drivers: mfd: mfd_ad9952: fix reset magic value Reset magic value equal 0xDAC is invalid. According to device specification [1] a valid value is 0x5AC. Use proper value to make driver aligned with the spec. [1] https://www.analog.com/media/en/technical-documentation/data-sheets/ad5592r.pdf Signed-off-by: Lukasz Madej --- drivers/mfd/mfd_ad5592.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/mfd/mfd_ad5592.c b/drivers/mfd/mfd_ad5592.c index d8f8f60de39..934e2ee097d 100644 --- a/drivers/mfd/mfd_ad5592.c +++ b/drivers/mfd/mfd_ad5592.c @@ -15,7 +15,7 @@ #define AD5592_GPIO_READBACK_EN BIT(10) #define AD5592_LDAC_READBACK_EN BIT(6) #define AD5592_REG_SOFTWARE_RESET 0x0FU -#define AD5592_SOFTWARE_RESET_MAGIC_VAL 0xDAC +#define AD5592_SOFTWARE_RESET_MAGIC_VAL 0x5AC #define AD5592_REV_VAL_MASK 0x3FF #define AD5592_REG_SHIFT_VAL 11 #define AD5592_REG_READBACK_SHIFT_VAL 2 From c69ddc10186f27b8847ca9fd38c2b3878ca47484 Mon Sep 17 00:00:00 2001 From: Lukasz Madej Date: Mon, 8 Jan 2024 15:46:10 +0100 Subject: [PATCH 1992/3723] drivers: mfd: mfd_ad5592: fix typo Fix a typo in `AD5592_REG_VAL_MASK` macro name. Signed-off-by: Lukasz Madej --- drivers/mfd/mfd_ad5592.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/mfd/mfd_ad5592.c b/drivers/mfd/mfd_ad5592.c index 934e2ee097d..82d5aadc268 100644 --- a/drivers/mfd/mfd_ad5592.c +++ b/drivers/mfd/mfd_ad5592.c @@ -16,7 +16,7 @@ #define AD5592_LDAC_READBACK_EN BIT(6) #define AD5592_REG_SOFTWARE_RESET 0x0FU #define AD5592_SOFTWARE_RESET_MAGIC_VAL 0x5AC -#define AD5592_REV_VAL_MASK 0x3FF +#define AD5592_REG_VAL_MASK 0x3FF #define AD5592_REG_SHIFT_VAL 11 #define AD5592_REG_READBACK_SHIFT_VAL 2 @@ -115,7 +115,7 @@ int mfd_ad5592_read_reg(const struct device *dev, uint8_t reg, uint8_t reg_data, int mfd_ad5592_write_reg(const struct device *dev, uint8_t reg, uint16_t val) { - uint16_t msg = sys_cpu_to_be16((reg << AD5592_REG_SHIFT_VAL) | (val & AD5592_REV_VAL_MASK)); + uint16_t msg = sys_cpu_to_be16((reg << AD5592_REG_SHIFT_VAL) | (val & AD5592_REG_VAL_MASK)); return mfd_ad5592_write_raw(dev, msg); } From 1ed51885d3ae36f744154ec114080529a9b25a83 Mon Sep 17 00:00:00 2001 From: Lukasz Madej Date: Mon, 8 Jan 2024 15:59:29 +0100 Subject: [PATCH 1993/3723] drivers: mfd: mfd_ad5592: fix reset magic sending Use proper register mask for software reset register so reset magic value sent to device is not malformed. Co-authored-by: Bartosz Bilas Signed-off-by: Lukasz Madej --- drivers/mfd/mfd_ad5592.c | 15 ++++++++++++++- 1 file changed, 14 insertions(+), 1 deletion(-) diff --git a/drivers/mfd/mfd_ad5592.c b/drivers/mfd/mfd_ad5592.c index 82d5aadc268..2c320fa549e 100644 --- a/drivers/mfd/mfd_ad5592.c +++ b/drivers/mfd/mfd_ad5592.c @@ -17,6 +17,7 @@ #define AD5592_REG_SOFTWARE_RESET 0x0FU #define AD5592_SOFTWARE_RESET_MAGIC_VAL 0x5AC #define AD5592_REG_VAL_MASK 0x3FF +#define AD5592_REG_RESET_VAL_MASK 0x7FF #define AD5592_REG_SHIFT_VAL 11 #define AD5592_REG_READBACK_SHIFT_VAL 2 @@ -115,7 +116,19 @@ int mfd_ad5592_read_reg(const struct device *dev, uint8_t reg, uint8_t reg_data, int mfd_ad5592_write_reg(const struct device *dev, uint8_t reg, uint16_t val) { - uint16_t msg = sys_cpu_to_be16((reg << AD5592_REG_SHIFT_VAL) | (val & AD5592_REG_VAL_MASK)); + uint16_t write_mask; + uint16_t msg; + + switch (reg) { + case AD5592_REG_SOFTWARE_RESET: + write_mask = AD5592_REG_RESET_VAL_MASK; + break; + default: + write_mask = AD5592_REG_VAL_MASK; + break; + } + + msg = sys_cpu_to_be16((reg << AD5592_REG_SHIFT_VAL) | (val & write_mask)); return mfd_ad5592_write_raw(dev, msg); } From 47e4728604d0db68289d67068243176cda94329f Mon Sep 17 00:00:00 2001 From: Maximilian Huber Date: Wed, 27 Dec 2023 21:40:01 +0100 Subject: [PATCH 1994/3723] doc: add note that some versions of displays are not supported MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This adds a hint that for stm32h747i_disco just some display shields are supported. Signed-off-by: Maximilian Huber Co-authored-by: Benjamin Cabé --- boards/arm/stm32h747i_disco/doc/index.rst | 4 ++++ boards/shields/st_b_lcd40_dsi1_mb1166/doc/index.rst | 3 +++ 2 files changed, 7 insertions(+) diff --git a/boards/arm/stm32h747i_disco/doc/index.rst b/boards/arm/stm32h747i_disco/doc/index.rst index 2f720ae4628..6fc553ab42e 100644 --- a/boards/arm/stm32h747i_disco/doc/index.rst +++ b/boards/arm/stm32h747i_disco/doc/index.rst @@ -172,6 +172,10 @@ command, for example: :shield: st_b_lcd40_dsi1_mb1166 :goals: build flash +.. note:: + Currently only the older version MB1166-A03 is supported by Zephyr. + The newer version MB1166-A09 does not get initialized correctly (see :github:`60888`). + Resources sharing ================= diff --git a/boards/shields/st_b_lcd40_dsi1_mb1166/doc/index.rst b/boards/shields/st_b_lcd40_dsi1_mb1166/doc/index.rst index 407f8c6efda..815b65f5750 100644 --- a/boards/shields/st_b_lcd40_dsi1_mb1166/doc/index.rst +++ b/boards/shields/st_b_lcd40_dsi1_mb1166/doc/index.rst @@ -9,6 +9,9 @@ Overview The B-LCD40-DSI1 shield provides a 4-inch WVGA TFT LCD with MIPI DSI interface and capacitive touch screen. +.. note:: + Currently only the older version MB1166-A03 is supported by Zephyr. + The newer version MB1166-A09 does not get initialized correctly (see :github:`60888`). .. figure:: image.jpg :alt: B-LCD40-DSI1 MB1166 Image From e49d174be910760031fb2e8ea1df79ad25c8da7d Mon Sep 17 00:00:00 2001 From: Shane Snover Date: Sun, 31 Dec 2023 14:38:33 -0700 Subject: [PATCH 1995/3723] driver: usb: change function parameter name from class to base_class. Change function parameter name in function usbd_device_set_code_triple from `class` to `base_class` as `class` is a keyword in C++. Signed-off-by: Shane Snover --- include/zephyr/usb/usbd.h | 12 ++++++------ subsys/usb/device_next/usbd_device.c | 6 +++--- 2 files changed, 9 insertions(+), 9 deletions(-) diff --git a/include/zephyr/usb/usbd.h b/include/zephyr/usb/usbd.h index 716ee9821f4..28d27f10723 100644 --- a/include/zephyr/usb/usbd.h +++ b/include/zephyr/usb/usbd.h @@ -703,16 +703,16 @@ int usbd_device_set_pid(struct usbd_contex *const uds_ctx, /** * @brief Set USB device descriptor code triple Base Class, SubClass, and Protocol * - * @param[in] uds_ctx Pointer to USB device support context - * @param[in] class bDeviceClass value - * @param[in] subclass bDeviceSubClass value - * @param[in] protocol bDeviceProtocol value + * @param[in] uds_ctx Pointer to USB device support context + * @param[in] base_class bDeviceClass value + * @param[in] subclass bDeviceSubClass value + * @param[in] protocol bDeviceProtocol value * * @return 0 on success, other values on fail. */ int usbd_device_set_code_triple(struct usbd_contex *const uds_ctx, - const uint8_t class, const uint8_t subclass, - const uint8_t protocol); + const uint8_t base_class, + const uint8_t subclass, const uint8_t protocol); /** * @brief Setup USB device configuration attribute Remote Wakeup diff --git a/subsys/usb/device_next/usbd_device.c b/subsys/usb/device_next/usbd_device.c index 8046ea12013..319c73fce2b 100644 --- a/subsys/usb/device_next/usbd_device.c +++ b/subsys/usb/device_next/usbd_device.c @@ -81,8 +81,8 @@ int usbd_device_set_pid(struct usbd_contex *const uds_ctx, } int usbd_device_set_code_triple(struct usbd_contex *const uds_ctx, - const uint8_t class, const uint8_t subclass, - const uint8_t protocol) + const uint8_t base_class, + const uint8_t subclass, const uint8_t protocol) { struct usb_device_descriptor *desc = uds_ctx->desc; int ret = 0; @@ -94,7 +94,7 @@ int usbd_device_set_code_triple(struct usbd_contex *const uds_ctx, goto set_code_triple_exit; } - desc->bDeviceClass = class; + desc->bDeviceClass = base_class; desc->bDeviceSubClass = subclass; desc->bDeviceProtocol = protocol; From b0dd9a2980cb6952df2b9c0ba40148885daed24a Mon Sep 17 00:00:00 2001 From: Jukka Rissanen Date: Fri, 5 Jan 2024 16:27:32 +0200 Subject: [PATCH 1996/3723] doc: net: ppp: Fix the point-to-point documentation The ppp doc was still referring to gsm-modem sample which is no longer there. Also removed old information that is no longer relevant. Fixes #67171 Signed-off-by: Jukka Rissanen --- doc/connectivity/networking/api/ppp.rst | 10 ++++------ 1 file changed, 4 insertions(+), 6 deletions(-) diff --git a/doc/connectivity/networking/api/ppp.rst b/doc/connectivity/networking/api/ppp.rst index d0028a075aa..74e2da248f7 100644 --- a/doc/connectivity/networking/api/ppp.rst +++ b/doc/connectivity/networking/api/ppp.rst @@ -21,9 +21,8 @@ In Zephyr, each individual PPP link is modelled as a network interface. This is similar to how Linux implements PPP. PPP support must be enabled at compile time by setting option -:kconfig:option:`CONFIG_NET_PPP` and :kconfig:option:`CONFIG_NET_L2_PPP`. -The PPP support in Zephyr 2.0 is still experimental and the implementation -supports only these protocols: +:kconfig:option:`CONFIG_NET_L2_PPP`. +The PPP implementation supports only these protocols: * LCP (Link Control Protocol, `RFC1661 `__) @@ -34,9 +33,8 @@ supports only these protocols: * IPV6CP (IPv6 Control Protocol, `RFC5072 `__) -See also the :zephyr_file:`samples/net/sockets/echo_server/overlay-ppp.conf` -file for configuration option examples. -For using PPP with GSM modem, see :ref:`gsm_modem` for additional information. +For using PPP with a cellular modem, see :zephyr:code-sample:`cellular-modem` sample +for additional information. Testing ******* From 6699d4d4f931f5f686bae65da5f89589395d86ba Mon Sep 17 00:00:00 2001 From: TOKITA Hiroshi Date: Sat, 25 Feb 2023 09:00:59 +0900 Subject: [PATCH 1997/3723] drivers: led_strip: add rpi_pico's PIO based ws2812 driver Add driver that based on RPI-PICO's PIO feature for ws2812. This driver can handle WS2812 or compatible LED strips. The single PIO node can handle up to 4 strips. Any pins that can be configured for PIO can be used for strips. I verified the samples/driver/led_ws2812 sample working with WS2812(144 pcs) led strip using following patches. - samples/drivers/led_ws2812/boards/rpi_pico.overlay ``` / { aliases { led-strip = &ws2812; }; }; &pinctrl { ws2812_pio0_default: ws2812_pio0_default { ws2812 { pinmux = ; }; }; }; &pio0 { status = "okay"; pio-ws2812 { compatible = "worldsemi,ws2812-rpi_pico-pio"; status = "okay"; pinctrl-0 = <&ws2812_pio0_default>; pinctrl-names = "default"; bit-waveform = <3>, <3>, <4>; ws2812: ws2812 { status = "okay"; output-pin = <21>; chain-length = <144>; color-mapping = ; reset-delay = <280>; frequency = <800000>; }; }; }; ``` - samples/drivers/led_ws2812/boards/rpi_pico.conf ``` CONFIG_WS2812_STRIP_RPI_PICO_PIO=y ``` Signed-off-by: TOKITA Hiroshi --- drivers/led_strip/CMakeLists.txt | 1 + drivers/led_strip/Kconfig.ws2812 | 7 + drivers/led_strip/ws2812_rpi_pico_pio.c | 249 ++++++++++++++++++ .../worldsemi,ws2812-rpi_pico-pio.yaml | 68 +++++ 4 files changed, 325 insertions(+) create mode 100644 drivers/led_strip/ws2812_rpi_pico_pio.c create mode 100644 dts/bindings/led_strip/worldsemi,ws2812-rpi_pico-pio.yaml diff --git a/drivers/led_strip/CMakeLists.txt b/drivers/led_strip/CMakeLists.txt index 6c950cac596..aa4e95722a7 100644 --- a/drivers/led_strip/CMakeLists.txt +++ b/drivers/led_strip/CMakeLists.txt @@ -7,4 +7,5 @@ zephyr_library_sources_ifdef(CONFIG_LPD880X_STRIP lpd880x.c) zephyr_library_sources_ifdef(CONFIG_WS2812_STRIP_GPIO ws2812_gpio.c) zephyr_library_sources_ifdef(CONFIG_WS2812_STRIP_SPI ws2812_spi.c) zephyr_library_sources_ifdef(CONFIG_WS2812_STRIP_I2S ws2812_i2s.c) +zephyr_library_sources_ifdef(CONFIG_WS2812_STRIP_RPI_PICO_PIO ws2812_rpi_pico_pio.c) zephyr_library_sources_ifdef(CONFIG_TLC5971_STRIP tlc5971.c) diff --git a/drivers/led_strip/Kconfig.ws2812 b/drivers/led_strip/Kconfig.ws2812 index 7682ba4be87..469b6d3f915 100644 --- a/drivers/led_strip/Kconfig.ws2812 +++ b/drivers/led_strip/Kconfig.ws2812 @@ -46,4 +46,11 @@ config WS2812_STRIP_GPIO Note that this driver is not compatible with the Everlight B1414 controller. +config WS2812_STRIP_RPI_PICO_PIO + bool "Raspberry Pi Pico PIO" + depends on DT_HAS_WORLDSEMI_WS2812_RPI_PICO_PIO_ENABLED + select PICOSDK_USE_PIO + help + Use the PIO feature available on RaspberryPi Pico devices. + endchoice diff --git a/drivers/led_strip/ws2812_rpi_pico_pio.c b/drivers/led_strip/ws2812_rpi_pico_pio.c new file mode 100644 index 00000000000..b2bb2654977 --- /dev/null +++ b/drivers/led_strip/ws2812_rpi_pico_pio.c @@ -0,0 +1,249 @@ +/* + * Copyright (c) 2023 TOKITA Hiroshi + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include +#include +#include +#include +#include + +#include +LOG_MODULE_REGISTER(ws2812_rpi_pico_pio, CONFIG_LED_STRIP_LOG_LEVEL); + +#define DT_DRV_COMPAT worldsemi_ws2812_rpi_pico_pio + +struct ws2812_led_strip_data { + uint32_t sm; +}; + +struct ws2812_led_strip_config { + const struct device *piodev; + uint32_t output_pin; + uint8_t num_colors; + uint32_t frequency; + const uint8_t *const color_mapping; + uint16_t reset_delay; + uint32_t cycles_per_bit; +}; + +struct ws2812_rpi_pico_pio_config { + const struct device *piodev; + const struct pinctrl_dev_config *const pcfg; + struct pio_program program; +}; + +static int ws2812_led_strip_sm_init(const struct device *dev) +{ + const struct ws2812_led_strip_config *config = dev->config; + const float clkdiv = + sys_clock_hw_cycles_per_sec() / (config->cycles_per_bit * config->frequency); + pio_sm_config sm_config = pio_get_default_sm_config(); + PIO pio; + int sm; + + pio = pio_rpi_pico_get_pio(config->piodev); + + sm = pio_claim_unused_sm(pio, false); + if (sm < 0) { + return -EINVAL; + } + + sm_config_set_sideset(&sm_config, 1, false, false); + sm_config_set_sideset_pins(&sm_config, config->output_pin); + sm_config_set_out_shift(&sm_config, false, true, (config->num_colors == 4 ? 32 : 24)); + sm_config_set_fifo_join(&sm_config, PIO_FIFO_JOIN_TX); + sm_config_set_clkdiv(&sm_config, clkdiv); + pio_sm_set_consecutive_pindirs(pio, sm, config->output_pin, 1, true); + pio_sm_init(pio, sm, -1, &sm_config); + pio_sm_set_enabled(pio, sm, true); + + return sm; +} + +/* + * Latch current color values on strip and reset its state machines. + */ +static inline void ws2812_led_strip_reset_delay(uint16_t delay) +{ + k_usleep(delay); +} + +static int ws2812_led_strip_update_rgb(const struct device *dev, struct led_rgb *pixels, + size_t num_pixels) +{ + const struct ws2812_led_strip_config *config = dev->config; + struct ws2812_led_strip_data *data = dev->data; + PIO pio = pio_rpi_pico_get_pio(config->piodev); + + for (size_t i = 0; i < num_pixels; i++) { + uint32_t color = 0; + + for (size_t j = 0; j < config->num_colors; j++) { + switch (config->color_mapping[j]) { + /* White channel is not supported by LED strip API. */ + case LED_COLOR_ID_WHITE: + color |= 0; + break; + case LED_COLOR_ID_RED: + color |= pixels[i].r << (8 * (2 - j)); + break; + case LED_COLOR_ID_GREEN: + color |= pixels[i].g << (8 * (2 - j)); + break; + case LED_COLOR_ID_BLUE: + color |= pixels[i].b << (8 * (2 - j)); + break; + } + } + + pio_sm_put_blocking(pio, data->sm, color << (config->num_colors == 4 ? 0 : 8)); + } + + ws2812_led_strip_reset_delay(config->reset_delay); + + return 0; +} + +static int ws2812_led_strip_update_channels(const struct device *dev, uint8_t *channels, + size_t num_channels) +{ + LOG_DBG("update_channels not implemented"); + return -ENOTSUP; +} + +static const struct led_strip_driver_api ws2812_led_strip_api = { + .update_rgb = ws2812_led_strip_update_rgb, + .update_channels = ws2812_led_strip_update_channels, +}; + +/* + * Retrieve the channel to color mapping (e.g. RGB, BGR, GRB, ...) from the + * "color-mapping" DT property. + */ +static int ws2812_led_strip_init(const struct device *dev) +{ + const struct ws2812_led_strip_config *config = dev->config; + struct ws2812_led_strip_data *data = dev->data; + int sm; + + if (!device_is_ready(config->piodev)) { + LOG_ERR("%s: PIO device not ready", dev->name); + return -ENODEV; + } + + for (uint32_t i = 0; i < config->num_colors; i++) { + switch (config->color_mapping[i]) { + case LED_COLOR_ID_WHITE: + case LED_COLOR_ID_RED: + case LED_COLOR_ID_GREEN: + case LED_COLOR_ID_BLUE: + break; + default: + LOG_ERR("%s: invalid channel to color mapping." + " Check the color-mapping DT property", + dev->name); + return -EINVAL; + } + } + + sm = ws2812_led_strip_sm_init(dev); + if (sm < 0) { + return sm; + } + + data->sm = sm; + + return 0; +} + +static int ws2812_rpi_pico_pio_init(const struct device *dev) +{ + const struct ws2812_rpi_pico_pio_config *config = dev->config; + PIO pio; + + if (!device_is_ready(config->piodev)) { + LOG_ERR("%s: PIO device not ready", dev->name); + return -ENODEV; + } + + pio = pio_rpi_pico_get_pio(config->piodev); + + pio_add_program(pio, &config->program); + + return pinctrl_apply_state(config->pcfg, PINCTRL_STATE_DEFAULT); +} + +#define CYCLES_PER_BIT(node) \ + (DT_PROP_BY_IDX(node, bit_waveform, 0) + DT_PROP_BY_IDX(node, bit_waveform, 1) + \ + DT_PROP_BY_IDX(node, bit_waveform, 2)) + +#define WS2812_CHILD_INIT(node) \ + static const uint8_t ws2812_led_strip_##node##_color_mapping[] = \ + DT_PROP(node, color_mapping); \ + struct ws2812_led_strip_data ws2812_led_strip_##node##_data; \ + \ + static const struct ws2812_led_strip_config ws2812_led_strip_##node##_config = { \ + .piodev = DEVICE_DT_GET(DT_PARENT(DT_PARENT(node))), \ + .output_pin = DT_PROP(node, output_pin), \ + .num_colors = DT_PROP_LEN(node, color_mapping), \ + .color_mapping = ws2812_led_strip_##node##_color_mapping, \ + .reset_delay = DT_PROP(node, reset_delay), \ + .frequency = DT_PROP(node, frequency), \ + .cycles_per_bit = CYCLES_PER_BIT(DT_PARENT(node)), \ + }; \ + \ + DEVICE_DT_DEFINE(node, &ws2812_led_strip_init, NULL, &ws2812_led_strip_##node##_data, \ + &ws2812_led_strip_##node##_config, POST_KERNEL, \ + CONFIG_LED_STRIP_INIT_PRIORITY, &ws2812_led_strip_api); + +#define SET_DELAY(op, inst, i) \ + (op | (((DT_INST_PROP_BY_IDX(inst, bit_waveform, i) - 1) & 0xF) << 8)) + +/* + * This pio program runs [T0+T1+T2] cycles per 1 loop. + * The first `out` instruction outputs 0 by [T2] times to the sideset pin. + * These zeros are padding. Here is the start of actual data transmission. + * The second `jmp` instruction output 1 by [T0] times to the sideset pin. + * This `jmp` instruction jumps to line 3 if the value of register x is true. + * Otherwise, jump to line 4. + * The third `jmp` instruction outputs 1 by [T1] times to the sideset pin. + * After output, return to the first line. + * The fourth `jmp` instruction outputs 0 by [T1] times. + * After output, return to the first line and output 0 by [T2] times. + * + * In the case of configuration, T0=3, T1=3, T2 =4, + * the final output is 1110000000 in case register x is false. + * It represents code 0, defined in the datasheet. + * And outputs 1111110000 in case of x is true. It represents code 1. + */ +#define WS2812_RPI_PICO_PIO_INIT(inst) \ + PINCTRL_DT_INST_DEFINE(inst); \ + \ + DT_INST_FOREACH_CHILD_STATUS_OKAY(inst, WS2812_CHILD_INIT); \ + \ + static const uint16_t rpi_pico_pio_ws2812_instructions_##inst[] = { \ + SET_DELAY(0x6021, inst, 2), /* 0: out x, 1 side 0 [T2 - 1] */ \ + SET_DELAY(0x1023, inst, 0), /* 1: jmp !x, 3 side 1 [T0 - 1] */ \ + SET_DELAY(0x1000, inst, 1), /* 2: jmp 0 side 1 [T1 - 1] */ \ + SET_DELAY(0x0000, inst, 1), /* 3: jmp 0 side 0 [T1 - 1] */ \ + }; \ + \ + static const struct ws2812_rpi_pico_pio_config rpi_pico_pio_ws2812_##inst##_config = { \ + .piodev = DEVICE_DT_GET(DT_INST_PARENT(inst)), \ + .pcfg = PINCTRL_DT_INST_DEV_CONFIG_GET(inst), \ + .program = \ + { \ + .instructions = rpi_pico_pio_ws2812_instructions_##inst, \ + .length = ARRAY_SIZE(rpi_pico_pio_ws2812_instructions_##inst), \ + .origin = -1, \ + }, \ + }; \ + \ + DEVICE_DT_INST_DEFINE(inst, &ws2812_rpi_pico_pio_init, NULL, NULL, \ + &rpi_pico_pio_ws2812_##inst##_config, POST_KERNEL, \ + CONFIG_LED_STRIP_INIT_PRIORITY, NULL); + +DT_INST_FOREACH_STATUS_OKAY(WS2812_RPI_PICO_PIO_INIT) diff --git a/dts/bindings/led_strip/worldsemi,ws2812-rpi_pico-pio.yaml b/dts/bindings/led_strip/worldsemi,ws2812-rpi_pico-pio.yaml new file mode 100644 index 00000000000..d5d41ed38ee --- /dev/null +++ b/dts/bindings/led_strip/worldsemi,ws2812-rpi_pico-pio.yaml @@ -0,0 +1,68 @@ +# Copyright (c) 2023, TOKITA Hiroshi +# SPDX-License-Identifier: Apache-2.0 + +description: | + The pio node configured for ws2812. + +compatible: "worldsemi,ws2812-rpi_pico-pio" + +include: pinctrl-device.yaml + +properties: + bit-waveform: + type: array + description: | + This property defines the waveform for sending 1-bit data. + The program uses the first three elements of the array. + The T0 is equal to T0H in the datasheet. + The T2 is equal to T1L in the datasheet. + The T1 is equal to (T1H-T0H) or (T0L-T1L) in the datasheet. + + Code-0 + +------+ +--- + | | | + | T0 | T1+T2 | + | | | + ---+ +-----------------+ + + Code-1 + +---------------+ +--- + | | | + | T0+T1 | T2 | + | | | + ---+ +--------+ + + + The frequency determines the wave period. + The T0~T2 means ratio in one period. + + For example, T0=3, T1=3, T2=4 and the frequency is 800kHz case, + T0H is + (1 / 800kHz) * (3/10) = 375ns + T0L is + (1 / 800kHz) * ((4+3)/10) = 875ns + +child-binding: + description: | + Worldsemi WS2812 or compatible LED strip driver based on RaspberryPi Pico's PIO + The LED strip node can put up to 4 instances under a single PIO node. + + include: ws2812.yaml + + properties: + output-pin: + type: int + required: true + description: | + Select the output pin. + + Note: This driver does not configure the output pin. + You need to configure the pin with pinctrl that is in the parent node configuration + for use by PIO. + + frequency: + type: int + description: | + Specify the number of times a waveform representing 1 bit is + transmitted per second. It is same meaning as bit-per-seconds. + WS2812 works with 800000. Set the value 400000 if use with WS2811. From 4266a7e17ae8e67e99fa46f93c4670f5c11ef247 Mon Sep 17 00:00:00 2001 From: TOKITA Hiroshi Date: Sun, 26 Feb 2023 20:37:11 +0900 Subject: [PATCH 1998/3723] boards: arm: adafruit_kb2040: add led-strip configuration Adafruit KB2040 has one NeoPixel(WS2812) LED that attaches to GPIO17 pin. Add configuration for it. Signed-off-by: TOKITA Hiroshi --- .../adafruit_kb2040-pinctrl.dtsi | 6 +++++ .../arm/adafruit_kb2040/adafruit_kb2040.dts | 25 +++++++++++++++++++ 2 files changed, 31 insertions(+) diff --git a/boards/arm/adafruit_kb2040/adafruit_kb2040-pinctrl.dtsi b/boards/arm/adafruit_kb2040/adafruit_kb2040-pinctrl.dtsi index cf4eeaf6b95..cf1289acedc 100644 --- a/boards/arm/adafruit_kb2040/adafruit_kb2040-pinctrl.dtsi +++ b/boards/arm/adafruit_kb2040/adafruit_kb2040-pinctrl.dtsi @@ -50,4 +50,10 @@ clocks_default: clocks_default { }; + + ws2812_pio0_default: ws2812_pio0_default { + ws2812 { + pinmux = ; + }; + }; }; diff --git a/boards/arm/adafruit_kb2040/adafruit_kb2040.dts b/boards/arm/adafruit_kb2040/adafruit_kb2040.dts index 1abbb70e988..c17700aa8fa 100644 --- a/boards/arm/adafruit_kb2040/adafruit_kb2040.dts +++ b/boards/arm/adafruit_kb2040/adafruit_kb2040.dts @@ -11,6 +11,7 @@ #include "adafruit_kb2040-pinctrl.dtsi" #include "sparkfun_pro_micro_connector.dtsi" #include +#include / { chosen { @@ -24,6 +25,7 @@ aliases { watchdog0 = &wdt0; + led-strip = &ws2812; }; }; @@ -94,6 +96,29 @@ pinctrl-names = "default"; }; +&pio0 { + status = "okay"; + + pio-ws2812 { + compatible = "worldsemi,ws2812-rpi_pico-pio"; + status = "okay"; + pinctrl-0 = <&ws2812_pio0_default>; + pinctrl-names = "default"; + bit-waveform = <3>, <3>, <4>; + + ws2812: ws2812 { + status = "okay"; + output-pin = <17>; + chain-length = <1>; + color-mapping = ; + reset-delay = <280>; + frequency = <800000>; + }; + }; +}; + zephyr_udc0: &usbd { status = "okay"; }; From 665d216b6fed750c8ec47bc4fe1bebbe8616ab91 Mon Sep 17 00:00:00 2001 From: TOKITA Hiroshi Date: Sun, 26 Feb 2023 22:53:34 +0900 Subject: [PATCH 1999/3723] samples: drivers: led_ws2812: add configure for adafruit_kb2040 Add configuration to use PIO driver for adafruit_kb2040. Signed-off-by: TOKITA Hiroshi --- samples/drivers/led_ws2812/boards/adafruit_kb2040.conf | 1 + 1 file changed, 1 insertion(+) create mode 100644 samples/drivers/led_ws2812/boards/adafruit_kb2040.conf diff --git a/samples/drivers/led_ws2812/boards/adafruit_kb2040.conf b/samples/drivers/led_ws2812/boards/adafruit_kb2040.conf new file mode 100644 index 00000000000..9ccb06fb7bc --- /dev/null +++ b/samples/drivers/led_ws2812/boards/adafruit_kb2040.conf @@ -0,0 +1 @@ +CONFIG_WS2812_STRIP_RPI_PICO_PIO=y From 8831aa60eb7c65fb389e18e2b01ce47ffa00103a Mon Sep 17 00:00:00 2001 From: Piotr Golyzniak Date: Sun, 17 Dec 2023 23:41:07 +0100 Subject: [PATCH 2000/3723] scripts: twister: add copying of bsim exe To make possible to build bsim tests by Twister, it is necessary to copy executables to BabbleSim bin directory. Signed-off-by: Piotr Golyzniak --- doc/develop/test/twister.rst | 15 +++++++- scripts/pylib/twister/twisterlib/harness.py | 37 +++++++++++++++++++ scripts/pylib/twister/twisterlib/runner.py | 12 +++++- scripts/schemas/twister/testsuite-schema.yaml | 6 +++ scripts/tests/twister/test_harness.py | 29 ++++++++++++++- scripts/tests/twister/test_runner.py | 1 + 6 files changed, 97 insertions(+), 3 deletions(-) diff --git a/doc/develop/test/twister.rst b/doc/develop/test/twister.rst index 0866653a636..beaf1284868 100644 --- a/doc/develop/test/twister.rst +++ b/doc/develop/test/twister.rst @@ -419,7 +419,7 @@ harness: Twister to be able to evaluate if a test passes criteria. For example, a keyboard harness is set on tests that require keyboard interaction to reach verdict on whether a test has passed or failed, however, Twister lack this - harness implementation at the momemnt. + harness implementation at the moment. Supported harnesses: @@ -445,6 +445,14 @@ harness: - net - bluetooth + Harness ``bsim`` is implemented in limited way - it helps only to copy the + final executable (``zephyr.exe``) from build directory to BabbleSim's + ``bin`` directory (``${BSIM_OUT_PATH}/bin``). This action is useful to allow + BabbleSim's tests to directly run after. By default, the executable file + name is (with dots and slashes replaced by underscores): + ``bs___``. + This name can be overridden with the ``bsim_exe_name`` option in + ``harness_config`` section. platform_key: Often a test needs to only be built and run once to qualify as passing. @@ -553,6 +561,11 @@ harness_config: robot_test_path: (default empty) Specify a path to a file containing a Robot Framework test suite to be run. + bsim_exe_name: + If provided, the executable filename when copying to BabbleSim's bin + directory, will be ``bs__`` instead of the + default based on the test path and scenario name. + The following is an example yaml file with a few harness_config options. .. code-block:: yaml diff --git a/scripts/pylib/twister/twisterlib/harness.py b/scripts/pylib/twister/twisterlib/harness.py index c1d0b6fd23c..a70601e3de3 100644 --- a/scripts/pylib/twister/twisterlib/harness.py +++ b/scripts/pylib/twister/twisterlib/harness.py @@ -12,6 +12,7 @@ import logging import threading import time +import shutil from twisterlib.error import ConfigurationError from twisterlib.environment import ZEPHYR_BASE, PYTEST_PLUGIN_INSTALLED @@ -83,6 +84,8 @@ def configure(self, instance): if self.record: self.record_pattern = re.compile(self.record.get("regex", "")) + def build(self): + pass def get_testcase_name(self): """ @@ -651,6 +654,40 @@ class Ztest(Test): pass +class Bsim(Harness): + + def build(self): + """ + Copying the application executable to BabbleSim's bin directory enables + running multidevice bsim tests after twister has built them. + """ + + if self.instance is None: + return + + original_exe_path: str = os.path.join(self.instance.build_dir, 'zephyr', 'zephyr.exe') + if not os.path.exists(original_exe_path): + logger.warning('Cannot copy bsim exe - cannot find original executable.') + return + + bsim_out_path: str = os.getenv('BSIM_OUT_PATH', '') + if not bsim_out_path: + logger.warning('Cannot copy bsim exe - BSIM_OUT_PATH not provided.') + return + + new_exe_name: str = self.instance.testsuite.harness_config.get('bsim_exe_name', '') + if new_exe_name: + new_exe_name = f'bs_{self.instance.platform.name}_{new_exe_name}' + else: + new_exe_name = self.instance.name + new_exe_name = new_exe_name.replace(os.path.sep, '_').replace('.', '_') + new_exe_name = f'bs_{new_exe_name}' + + new_exe_path: str = os.path.join(bsim_out_path, 'bin', new_exe_name) + logger.debug(f'Copying executable from {original_exe_path} to {new_exe_path}') + shutil.copy(original_exe_path, new_exe_path) + + class HarnessImporter: @staticmethod diff --git a/scripts/pylib/twister/twisterlib/runner.py b/scripts/pylib/twister/twisterlib/runner.py index 2d948336f50..bfaa5939fe2 100644 --- a/scripts/pylib/twister/twisterlib/runner.py +++ b/scripts/pylib/twister/twisterlib/runner.py @@ -1052,7 +1052,17 @@ def cmake(self, filter_stages=[]): return self.run_cmake(args,filter_stages) def build(self): - return self.run_build(['--build', self.build_dir]) + harness = HarnessImporter.get_harness(self.instance.testsuite.harness.capitalize()) + build_result = self.run_build(['--build', self.build_dir]) + try: + harness.instance = self.instance + harness.build() + except ConfigurationError as error: + self.instance.status = "error" + self.instance.reason = str(error) + logger.error(self.instance.reason) + return + return build_result def run(self): diff --git a/scripts/schemas/twister/testsuite-schema.yaml b/scripts/schemas/twister/testsuite-schema.yaml index 31aacc76edf..cdec09e536c 100644 --- a/scripts/schemas/twister/testsuite-schema.yaml +++ b/scripts/schemas/twister/testsuite-schema.yaml @@ -123,6 +123,9 @@ mapping: "regex": type: str required: true + "bsim_exe_name": + type: str + required: false "min_ram": type: int required: false @@ -346,6 +349,9 @@ mapping: "regex": type: str required: true + "bsim_exe_name": + type: str + required: false "min_ram": type: int required: false diff --git a/scripts/tests/twister/test_harness.py b/scripts/tests/twister/test_harness.py index 247a9426f7b..96941b60b28 100644 --- a/scripts/tests/twister/test_harness.py +++ b/scripts/tests/twister/test_harness.py @@ -14,7 +14,7 @@ ZEPHYR_BASE = os.getenv("ZEPHYR_BASE") sys.path.insert(0, os.path.join(ZEPHYR_BASE, "scripts/pylib/twister")) -from twisterlib.harness import Gtest +from twisterlib.harness import Gtest, Bsim from twisterlib.testinstance import TestInstance GTEST_START_STATE = " RUN " @@ -250,3 +250,30 @@ def test_gtest_repeated_run(gtest): ), ], ) + + +def test_bsim_build(monkeypatch, tmp_path): + mocked_instance = mock.Mock() + build_dir = tmp_path / 'build_dir' + os.makedirs(build_dir) + mocked_instance.build_dir = str(build_dir) + mocked_instance.name = 'platform_name/test/dummy.test' + mocked_instance.testsuite.harness_config = {} + + harness = Bsim() + harness.instance = mocked_instance + + monkeypatch.setenv('BSIM_OUT_PATH', str(tmp_path)) + os.makedirs(os.path.join(tmp_path, 'bin'), exist_ok=True) + zephyr_exe_path = os.path.join(build_dir, 'zephyr', 'zephyr.exe') + os.makedirs(os.path.dirname(zephyr_exe_path), exist_ok=True) + with open(zephyr_exe_path, 'w') as file: + file.write('TEST_EXE') + + harness.build() + + new_exe_path = os.path.join(tmp_path, 'bin', 'bs_platform_name_test_dummy_test') + assert os.path.exists(new_exe_path) + with open(new_exe_path, 'r') as file: + exe_content = file.read() + assert 'TEST_EXE' in exe_content diff --git a/scripts/tests/twister/test_runner.py b/scripts/tests/twister/test_runner.py index 8b98e79a5a3..fcf6ccd2a01 100644 --- a/scripts/tests/twister/test_runner.py +++ b/scripts/tests/twister/test_runner.py @@ -2071,6 +2071,7 @@ def test_projectbuilder_cmake(): def test_projectbuilder_build(mocked_jobserver): instance_mock = mock.Mock() + instance_mock.testsuite.harness = 'test' env_mock = mock.Mock() pb = ProjectBuilder(instance_mock, env_mock, mocked_jobserver) From a27ae686d3b70c742cc1db94703eff65cda2f73a Mon Sep 17 00:00:00 2001 From: Piotr Golyzniak Date: Mon, 18 Dec 2023 16:30:00 +0100 Subject: [PATCH 2001/3723] tests: bsim: add testcase.yaml to bsim bis test For better manageability of tests building, add possibility to build BabbleSim Bluetooth BIS tests by Twister. Signed-off-by: Piotr Golyzniak --- tests/bsim/bluetooth/ll/bis/testcase.yaml | 42 +++++++++++++++++++++++ 1 file changed, 42 insertions(+) create mode 100644 tests/bsim/bluetooth/ll/bis/testcase.yaml diff --git a/tests/bsim/bluetooth/ll/bis/testcase.yaml b/tests/bsim/bluetooth/ll/bis/testcase.yaml new file mode 100644 index 00000000000..ee619560a79 --- /dev/null +++ b/tests/bsim/bluetooth/ll/bis/testcase.yaml @@ -0,0 +1,42 @@ +common: + build_only: true + tags: + - bluetooth + - bsim_multi + +tests: + bluetooth.ll.bis: + sysbuild: true + platform_allow: + - nrf52_bsim + - nrf5340bsim_nrf5340_cpuapp + - nrf5340bsim_nrf5340_cpunet + integration_platforms: + - nrf52_bsim + - nrf5340bsim_nrf5340_cpuapp + - nrf5340bsim_nrf5340_cpunet + harness: bsim + harness_config: + bsim_exe_name: tests_bsim_bluetooth_ll_bis_prj_conf + bluetooth.ll.bis_ticker_expire_info: + extra_args: OVERLAY_CONFIG=overlay-ticker_expire_info.conf + platform_allow: + - nrf52_bsim + - nrf5340bsim_nrf5340_cpunet + integration_platforms: + - nrf52_bsim + - nrf5340bsim_nrf5340_cpunet + harness: bsim + harness_config: + bsim_exe_name: tests_bsim_bluetooth_ll_bis_prj_conf_overlay-ticker_expire_info_conf + bluetooth.ll.bis_vs_dp: + extra_args: CONF_FILE=prj_vs_dp.conf + platform_allow: + - nrf52_bsim + - nrf5340bsim_nrf5340_cpunet + integration_platforms: + - nrf52_bsim + - nrf5340bsim_nrf5340_cpunet + harness: bsim + harness_config: + bsim_exe_name: tests_bsim_bluetooth_ll_bis_prj_vs_dp_conf From 25b0083ee9fb6ea15924017d2aa770cc2132c830 Mon Sep 17 00:00:00 2001 From: Yong Cong Sin Date: Tue, 26 Dec 2023 18:17:17 +0800 Subject: [PATCH 2002/3723] MAINTAINERS: add myself as a POSIX collaborator Add myself as a collaborator in the POSIX subsystem. Signed-off-by: Yong Cong Sin --- MAINTAINERS.yml | 2 ++ 1 file changed, 2 insertions(+) diff --git a/MAINTAINERS.yml b/MAINTAINERS.yml index 1dffa8e82fc..ef82c8e3e7c 100644 --- a/MAINTAINERS.yml +++ b/MAINTAINERS.yml @@ -2730,6 +2730,8 @@ POSIX API layer: status: maintained maintainers: - cfriedt + collaborators: + - ycsin files: - include/zephyr/posix/ - lib/posix/ From abb21d48d9a312c2e0d1bfde170ff9ff7979fd52 Mon Sep 17 00:00:00 2001 From: Yong Cong Sin Date: Tue, 26 Dec 2023 18:15:58 +0800 Subject: [PATCH 2003/3723] posix: semaphore: implement `sem_open()`, `sem_unlink()` & `sem_close()` Implements `sem_open()`, `sem_unlink()` & `sem_close()` functions and added tests for them. Updated existing tests and POSIX docs. Signed-off-by: Yong Cong Sin --- include/zephyr/posix/semaphore.h | 5 + lib/posix/Kconfig.semaphore | 8 + lib/posix/semaphore.c | 242 ++++++++++++++++++++++++++ tests/posix/common/src/semaphore.c | 191 ++++++++++++++++++++ tests/posix/headers/src/semaphore_h.c | 6 +- 5 files changed, 449 insertions(+), 3 deletions(-) diff --git a/include/zephyr/posix/semaphore.h b/include/zephyr/posix/semaphore.h index 943218ee08e..3b0f53b0712 100644 --- a/include/zephyr/posix/semaphore.h +++ b/include/zephyr/posix/semaphore.h @@ -13,6 +13,8 @@ extern "C" { #endif +#define SEM_FAILED ((sem_t *) 0) + int sem_destroy(sem_t *semaphore); int sem_getvalue(sem_t *ZRESTRICT semaphore, int *ZRESTRICT value); int sem_init(sem_t *semaphore, int pshared, unsigned int value); @@ -20,6 +22,9 @@ int sem_post(sem_t *semaphore); int sem_timedwait(sem_t *ZRESTRICT semaphore, struct timespec *ZRESTRICT abstime); int sem_trywait(sem_t *semaphore); int sem_wait(sem_t *semaphore); +sem_t *sem_open(const char *name, int oflags, ...); +int sem_unlink(const char *name); +int sem_close(sem_t *sem); #ifdef __cplusplus } diff --git a/lib/posix/Kconfig.semaphore b/lib/posix/Kconfig.semaphore index d9b9b47a508..aa3468fea76 100644 --- a/lib/posix/Kconfig.semaphore +++ b/lib/posix/Kconfig.semaphore @@ -8,3 +8,11 @@ config SEM_VALUE_MAX range 1 32767 help Maximum semaphore count in POSIX compliant Application. + +config SEM_NAMELEN_MAX + int "Maximum name length" + default 16 + range 2 255 + help + Maximum length of name for a named semaphore. + The max value of 255 corresponds to {NAME_MAX}. diff --git a/lib/posix/semaphore.c b/lib/posix/semaphore.c index 7a1392cd521..804ca08de1f 100644 --- a/lib/posix/semaphore.c +++ b/lib/posix/semaphore.c @@ -1,11 +1,75 @@ /* * Copyright (c) 2018 Intel Corporation + * Copyright (c) 2023 Meta * * SPDX-License-Identifier: Apache-2.0 */ #include +#include +#include +#include #include +#include + +struct nsem_obj { + sys_snode_t snode; + sem_t sem; + unsigned int ref_count; + char *name; +}; + +/* Initialize the list */ +static sys_slist_t nsem_list = SYS_SLIST_STATIC_INIT(&nsem_list); + +static K_MUTEX_DEFINE(nsem_mutex); + +static inline void nsem_list_lock(void) +{ + k_mutex_lock(&nsem_mutex, K_FOREVER); +} + +static inline void nsem_list_unlock(void) +{ + k_mutex_unlock(&nsem_mutex); +} + +static struct nsem_obj *nsem_find(const char *name) +{ + struct nsem_obj *nsem; + + SYS_SLIST_FOR_EACH_CONTAINER(&nsem_list, nsem, snode) { + if ((nsem->name != NULL) && (strcmp(nsem->name, name) == 0)) { + return nsem; + } + } + + return NULL; +} + +/* Clean up a named semaphore object completely (incl its `name` buffer) */ +static void nsem_cleanup(struct nsem_obj *nsem) +{ + if (nsem != NULL) { + if (nsem->name != NULL) { + k_free(nsem->name); + nsem->name = NULL; + } + k_free(nsem); + nsem = NULL; + } +} + +/* Remove a named semaphore if it isn't unsed */ +static void nsem_remove_if_unused(struct nsem_obj *nsem) +{ + if (nsem->ref_count == 0) { + sys_slist_find_and_remove(&nsem_list, (sys_snode_t *) nsem); + + /* Free nsem */ + nsem_cleanup(nsem); + } +} /** * @brief Destroy semaphore. @@ -148,3 +212,181 @@ int sem_wait(sem_t *semaphore) (void)k_sem_take(semaphore, K_FOREVER); return 0; } + +sem_t *sem_open(const char *name, int oflags, ...) +{ + va_list va; + mode_t mode; + unsigned int value; + struct nsem_obj *nsem = NULL; + size_t namelen; + + va_start(va, oflags); + BUILD_ASSERT(sizeof(mode_t) <= sizeof(int)); + mode = va_arg(va, int); + value = va_arg(va, unsigned int); + va_end(va); + + if (value > CONFIG_SEM_VALUE_MAX) { + errno = EINVAL; + return (sem_t *)SEM_FAILED; + } + + if (name == NULL) { + errno = EINVAL; + return (sem_t *)SEM_FAILED; + } + + namelen = strlen(name); + if ((namelen + 1) > CONFIG_SEM_NAMELEN_MAX) { + errno = ENAMETOOLONG; + return (sem_t *)SEM_FAILED; + } + + /* Lock before checking to make sure that the call is atomic */ + nsem_list_lock(); + + /* Check if the named semaphore exists */ + nsem = nsem_find(name); + + if (nsem != NULL) { /* Named semaphore exists */ + if (((oflags & O_CREAT) != 0) && ((oflags & O_EXCL) != 0)) { + errno = EEXIST; + goto error_unlock; + } + + __ASSERT_NO_MSG(nsem->ref_count != UINT_MAX); + nsem->ref_count++; + goto unlock; + } + + /* Named sempahore doesn't exist, try to create new one */ + + if ((oflags & O_CREAT) == 0) { + errno = ENOENT; + goto error_unlock; + } + + nsem = k_calloc(1, sizeof(struct nsem_obj)); + if (nsem == NULL) { + errno = ENOSPC; + goto error_unlock; + } + + /* goto `cleanup_error_unlock` past this point to avoid memory leak */ + + nsem->name = k_calloc(namelen + 1, sizeof(uint8_t)); + if (nsem->name == NULL) { + errno = ENOSPC; + goto cleanup_error_unlock; + } + + strcpy(nsem->name, name); + nsem->ref_count = 1; + + (void)k_sem_init(&nsem->sem, value, CONFIG_SEM_VALUE_MAX); + + sys_slist_append(&nsem_list, (sys_snode_t *)&(nsem->snode)); + + goto unlock; + +cleanup_error_unlock: + nsem_cleanup(nsem); + +error_unlock: + nsem = NULL; + +unlock: + nsem_list_unlock(); + return nsem == NULL ? SEM_FAILED : &nsem->sem; +} + +int sem_unlink(const char *name) +{ + int ret = 0; + struct nsem_obj *nsem; + + if (name == NULL) { + errno = EINVAL; + return -1; + } + + if ((strlen(name) + 1) > CONFIG_SEM_NAMELEN_MAX) { + errno = ENAMETOOLONG; + return -1; + } + + nsem_list_lock(); + + /* Check if queue already exists */ + nsem = nsem_find(name); + if (nsem == NULL) { + ret = -1; + errno = ENOENT; + goto unlock; + } + + k_free(nsem->name); + nsem->name = NULL; + + nsem_remove_if_unused(nsem); + +unlock: + nsem_list_unlock(); + return ret; +} + +int sem_close(sem_t *sem) +{ + struct nsem_obj *nsem = CONTAINER_OF(sem, struct nsem_obj, sem); + + if (sem == NULL) { + errno = EINVAL; + return -1; + } + + __ASSERT_NO_MSG(nsem != NULL); + + nsem_list_lock(); + + __ASSERT_NO_MSG(nsem->ref_count != 0); + nsem->ref_count--; + + /* remove sem if marked for unlink */ + if (nsem->name == NULL) { + nsem_remove_if_unused(nsem); + } + + nsem_list_unlock(); + return 0; +} + +#ifdef CONFIG_ZTEST +/* Used by ztest to get the ref count of a named semaphore */ +unsigned int nsem_get_ref_count(sem_t *sem) +{ + struct nsem_obj *nsem = CONTAINER_OF(sem, struct nsem_obj, sem); + unsigned int ref_count; + + __ASSERT_NO_MSG(sem != NULL); + __ASSERT_NO_MSG(nsem != NULL); + + nsem_list_lock(); + ref_count = nsem->ref_count; + nsem_list_unlock(); + + return ref_count; +} + +/* Used by ztest to get the length of the named semaphore */ +size_t nsem_get_list_len(void) +{ + size_t len; + + nsem_list_lock(); + len = sys_slist_len(&nsem_list); + nsem_list_unlock(); + + return len; +} +#endif diff --git a/tests/posix/common/src/semaphore.c b/tests/posix/common/src/semaphore.c index 921ddbb4a41..1e8810683e1 100644 --- a/tests/posix/common/src/semaphore.c +++ b/tests/posix/common/src/semaphore.c @@ -1,10 +1,12 @@ /* * Copyright (c) 2018 Intel Corporation + * Copyright (c) 2023 Meta * * SPDX-License-Identifier: Apache-2.0 */ #include +#include #include #include @@ -94,3 +96,192 @@ ZTEST(posix_apis, test_semaphore) /* TESTPOINT: Wait and acquire semaphore till thread2 gives */ zassert_equal(sem_wait(&sema), 0, "sem_wait failed"); } + +unsigned int nsem_get_ref_count(sem_t *sem); +size_t nsem_get_list_len(void); +#define N_LOOPS 999 + +static void *nsem_open_func(void *p) +{ + const char *name = (char *)p; + + for (int i = 0; i < N_LOOPS; i++) { + zassert_not_null(sem_open(name, 0, 0, 0), "%s is NULL", name); + k_msleep(1); + } + + /* Unlink after finished opening */ + zassert_ok(sem_unlink(name)); + return NULL; +} + +static void *nsem_close_func(void *p) +{ + sem_t *sem = (sem_t *)p; + + /* Make sure that we have enough ref_count's initially */ + k_msleep(N_LOOPS >> 1); + + for (int i = 0; i < N_LOOPS; i++) { + zassert_ok(sem_close(sem)); + k_msleep(1); + } + + /* Close the last `sem` */ + zassert_ok(sem_close(sem)); + return NULL; +} + +ZTEST(posix_apis, test_named_semaphore) +{ + pthread_t thread1, thread2; + sem_t *sem1, *sem2, *different_sem1; + + /* If `name` is invalid */ + sem1 = sem_open(NULL, 0, 0, 0); + zassert_equal(errno, EINVAL); + zassert_equal_ptr(sem1, SEM_FAILED); + zassert_equal(nsem_get_list_len(), 0); + + /* Attempt to open a named sem that doesn't exist */ + sem1 = sem_open("sem1", 0, 0, 0); + zassert_equal(errno, ENOENT); + zassert_equal_ptr(sem1, SEM_FAILED); + zassert_equal(nsem_get_list_len(), 0); + + /* Name exceeds CONFIG_SEM_NAMELEN_MAX */ + char name_too_long[CONFIG_SEM_NAMELEN_MAX + 2]; + + for (size_t i = 0; i < sizeof(name_too_long) - 1; i++) { + name_too_long[i] = 'a'; + } + name_too_long[sizeof(name_too_long) - 1] = '\0'; + + sem1 = sem_open(name_too_long, 0, 0, 0); + zassert_equal(errno, ENAMETOOLONG, "\"%s\" should be longer than %d", name_too_long, + CONFIG_SEM_NAMELEN_MAX); + zassert_equal_ptr(sem1, SEM_FAILED); + zassert_equal(nsem_get_list_len(), 0); + + /* `value` greater than CONFIG_SEM_VALUE_MAX */ + sem1 = sem_open("sem1", O_CREAT, 0, (CONFIG_SEM_VALUE_MAX + 1)); + zassert_equal(errno, EINVAL); + zassert_equal_ptr(sem1, SEM_FAILED); + zassert_equal(nsem_get_list_len(), 0); + + /* Open named sem */ + sem1 = sem_open("sem1", O_CREAT, 0, 0); + zassert_equal(nsem_get_ref_count(sem1), 1); + zassert_equal(nsem_get_list_len(), 1); + sem2 = sem_open("sem2", O_CREAT, 0, 0); + zassert_equal(nsem_get_ref_count(sem2), 1); + zassert_equal(nsem_get_list_len(), 2); + + /* Open created named sem repeatedly */ + for (size_t i = 1; i < N_LOOPS; i++) { + sem_t *new_sem1, *new_sem2; + + /* oflags are ignored (except when both O_CREAT & O_EXCL are set) */ + new_sem1 = sem_open("sem1", i % 2 == 0 ? O_CREAT : 0, 0, 0); + zassert_not_null(new_sem1); + zassert_equal_ptr(new_sem1, sem1); /* Should point to the same sem */ + new_sem2 = sem_open("sem2", i % 2 == 0 ? O_CREAT : 0, 0, 0); + zassert_not_null(new_sem2); + zassert_equal_ptr(new_sem2, sem2); + + /* ref_count should increment */ + zassert_equal(nsem_get_ref_count(sem1), i + 1); + zassert_equal(nsem_get_ref_count(sem2), i + 1); + + /* Should reuse the same named sem instead of creating another one */ + zassert_equal(nsem_get_list_len(), 2); + } + + /* O_CREAT and O_EXCL are set and the named semaphore already exists */ + zassert_equal_ptr((sem_open("sem1", O_CREAT | O_EXCL, 0, 0)), SEM_FAILED); + zassert_equal(errno, EEXIST); + zassert_equal(nsem_get_list_len(), 2); + + zassert_equal(sem_close(NULL), -1); + zassert_equal(errno, EINVAL); + zassert_equal(nsem_get_list_len(), 2); + + /* Close sem */ + for (size_t i = 0; + /* close until one left, required by the test later */ + i < (N_LOOPS - 1); i++) { + zassert_ok(sem_close(sem1)); + zassert_not_null(sem1); + zassert_equal(nsem_get_ref_count(sem1), N_LOOPS - (i + 1)); + + zassert_ok(sem_close(sem2)); + zassert_not_null(sem2); + zassert_equal(nsem_get_ref_count(sem2), N_LOOPS - (i + 1)); + + zassert_equal(nsem_get_list_len(), 2); + } + + /* If `name` is invalid */ + zassert_equal(sem_unlink(NULL), -1); + zassert_equal(errno, EINVAL); + zassert_equal(nsem_get_list_len(), 2); + + /* Attempt to unlink a named sem that doesn't exist */ + zassert_equal(sem_unlink("sem3"), -1); + zassert_equal(errno, ENOENT); + zassert_equal(nsem_get_list_len(), 2); + + /* Name exceeds CONFIG_SEM_NAMELEN_MAX */ + char long_sem_name[CONFIG_SEM_NAMELEN_MAX + 2]; + + for (int i = 0; i < CONFIG_SEM_NAMELEN_MAX + 1; i++) { + long_sem_name[i] = 'a'; + } + long_sem_name[CONFIG_SEM_NAMELEN_MAX + 1] = '\0'; + + zassert_equal(sem_unlink(long_sem_name), -1); + zassert_equal(errno, ENAMETOOLONG); + zassert_equal(nsem_get_list_len(), 2); + + /* Unlink sem1 when it is still being used */ + zassert_equal(nsem_get_ref_count(sem1), 1); + zassert_ok(sem_unlink("sem1")); + /* sem won't be destroyed */ + zassert_equal(nsem_get_list_len(), 2); + + /* Create another sem with the name of an unlinked sem */ + different_sem1 = sem_open("sem1", O_CREAT, 0, 0); + zassert_not_null(different_sem1); + /* The created sem will be a different instance */ + zassert(different_sem1 != sem1, ""); + zassert_equal(nsem_get_list_len(), 3); + + /* Destruction of sem1 will be postponed until all references to the semaphore have been + * destroyed by calls to sem_close() + */ + zassert_ok(sem_close(sem1)); + zassert_equal(nsem_get_list_len(), 2); + + /* Closing a linked sem won't destroy the sem */ + zassert_ok(sem_close(sem2)); + zassert_equal(nsem_get_ref_count(sem2), 0); + zassert_equal(nsem_get_list_len(), 2); + + /* Instead the sem will be destroyed upon call to sem_unlink() */ + zassert_ok(sem_unlink("sem2")); + zassert_equal(nsem_get_list_len(), 1); + + /* What we have left open here is `different_sem` as "sem1", which has 1 ref_count */ + zassert_equal(nsem_get_ref_count(different_sem1), 1); + + /* Stress test: open & close "sem1" repeatedly */ + zassert_ok(pthread_create(&thread1, NULL, nsem_open_func, "sem1")); + zassert_ok(pthread_create(&thread2, NULL, nsem_close_func, different_sem1)); + + /* Make sure the threads are terminated */ + zassert_ok(pthread_join(thread1, NULL)); + zassert_ok(pthread_join(thread2, NULL)); + + /* All named semaphores should be destroyed here */ + zassert_equal(nsem_get_list_len(), 0); +} diff --git a/tests/posix/headers/src/semaphore_h.c b/tests/posix/headers/src/semaphore_h.c index 0ac1de36f2e..b4c2e151fa1 100644 --- a/tests/posix/headers/src/semaphore_h.c +++ b/tests/posix/headers/src/semaphore_h.c @@ -22,15 +22,15 @@ ZTEST(posix_headers, test_semaphore_h) /* zassert_not_equal(SEM_FAILED, (sem_t *)42); */ /* not implemented */ if (IS_ENABLED(CONFIG_POSIX_API)) { - /* zassert_not_null(sem_close); */ /* not implemented */ + zassert_not_null(sem_close); zassert_not_null(sem_destroy); zassert_not_null(sem_getvalue); zassert_not_null(sem_init); - /* zassert_not_null(sem_open); */ /* not implemented */ + zassert_not_null(sem_open); zassert_not_null(sem_post); zassert_not_null(sem_timedwait); zassert_not_null(sem_trywait); - /* zassert_not_null(sem_unlink); */ /* not implemented */ + zassert_not_null(sem_unlink); zassert_not_null(sem_wait); } } From 9016cec1503c02cc1b43957c9f12f334a783fbe9 Mon Sep 17 00:00:00 2001 From: Yong Cong Sin Date: Tue, 2 Jan 2024 11:34:13 +0800 Subject: [PATCH 2004/3723] doc: posix: mark `sem_open`, `sem_close` & `sem_unlink` as supported The `sem_open()`, `sem_close()` & `sem_unlink()` functions are now implemented, so mark them as supported. Signed-off-by: Yong Cong Sin --- doc/services/portability/posix/option_groups/index.rst | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/doc/services/portability/posix/option_groups/index.rst b/doc/services/portability/posix/option_groups/index.rst index 893754f647d..edbd6899841 100644 --- a/doc/services/portability/posix/option_groups/index.rst +++ b/doc/services/portability/posix/option_groups/index.rst @@ -367,14 +367,14 @@ POSIX_SEMAPHORES :header: API, Supported :widths: 50,10 - sem_close(), + sem_close(),yes sem_destroy(),yes sem_getvalue(),yes sem_init(),yes - sem_open(), + sem_open(),yes sem_post(),yes sem_trywait(),yes - sem_unlink(), + sem_unlink(),yes sem_wait(),yes .. _posix_option_group_spin_locks: From 3bfcf123a787d9b56268a1a72c3d4b9244b72a4d Mon Sep 17 00:00:00 2001 From: Yong Cong Sin Date: Tue, 9 Jan 2024 22:57:44 +0800 Subject: [PATCH 2005/3723] tests: posix: semaphore: refactor `test_semaphore` Localize a few public variables and refactor the test and functions so that they are reusable. Signed-off-by: Yong Cong Sin --- tests/posix/common/src/semaphore.c | 68 +++++++++++++++++------------- 1 file changed, 39 insertions(+), 29 deletions(-) diff --git a/tests/posix/common/src/semaphore.c b/tests/posix/common/src/semaphore.c index 1e8810683e1..e17300d91e8 100644 --- a/tests/posix/common/src/semaphore.c +++ b/tests/posix/common/src/semaphore.c @@ -13,16 +13,15 @@ #include #include -static sem_t sema; -static void *dummy_sem; - static void *child_func(void *p1) { - zassert_equal(sem_post(&sema), 0, "sem_post failed"); + sem_t *sem = (sem_t *)p1; + + zassert_equal(sem_post(sem), 0, "sem_post failed"); return NULL; } -ZTEST(posix_apis, test_semaphore) +static void semaphore_test(sem_t *sem) { pthread_t thread1, thread2; int val, ret; @@ -31,28 +30,23 @@ ZTEST(posix_apis, test_semaphore) /* TESTPOINT: Check if sema value is less than * CONFIG_SEM_VALUE_MAX */ - zassert_equal(sem_init(&sema, 0, (CONFIG_SEM_VALUE_MAX + 1)), -1, + zassert_equal(sem_init(sem, 0, (CONFIG_SEM_VALUE_MAX + 1)), -1, "value larger than %d\n", CONFIG_SEM_VALUE_MAX); zassert_equal(errno, EINVAL); - zassert_equal(sem_init(&sema, 0, 0), 0, "sem_init failed"); - - /* TESTPOINT: Call sem_post with invalid kobject */ - zassert_equal(sem_post(dummy_sem), -1, "sem_post of" - " invalid semaphore object didn't fail"); - zassert_equal(errno, EINVAL); + zassert_equal(sem_init(sem, 0, 0), 0, "sem_init failed"); /* TESTPOINT: Check if semaphore value is as set */ - zassert_equal(sem_getvalue(&sema, &val), 0); + zassert_equal(sem_getvalue(sem, &val), 0); zassert_equal(val, 0); /* TESTPOINT: Check if sema is acquired when it * is not available */ - zassert_equal(sem_trywait(&sema), -1); + zassert_equal(sem_trywait(sem), -1); zassert_equal(errno, EAGAIN); - ret = pthread_create(&thread1, NULL, child_func, NULL); + ret = pthread_create(&thread1, NULL, child_func, sem); zassert_equal(ret, 0, "Thread creation failed"); zassert_equal(clock_gettime(CLOCK_REALTIME, &abstime), 0, @@ -63,38 +57,54 @@ ZTEST(posix_apis, test_semaphore) /* TESPOINT: Wait for 5 seconds and acquire sema given * by thread1 */ - zassert_equal(sem_timedwait(&sema, &abstime), 0); + zassert_equal(sem_timedwait(sem, &abstime), 0); /* TESTPOINT: Semaphore is already acquired, check if * no semaphore is available */ - zassert_equal(sem_timedwait(&sema, &abstime), -1); + zassert_equal(sem_timedwait(sem, &abstime), -1); zassert_equal(errno, ETIMEDOUT); - /* TESTPOINT: sem_destroy with invalid kobject */ - zassert_equal(sem_destroy(dummy_sem), -1, "invalid" - " semaphore is destroyed"); - zassert_equal(errno, EINVAL); - - zassert_equal(sem_destroy(&sema), 0, "semaphore is not destroyed"); + zassert_equal(sem_destroy(sem), 0, "semaphore is not destroyed"); /* TESTPOINT: Initialize sema with 1 */ - zassert_equal(sem_init(&sema, 0, 1), 0, "sem_init failed"); - zassert_equal(sem_getvalue(&sema, &val), 0); + zassert_equal(sem_init(sem, 0, 1), 0, "sem_init failed"); + zassert_equal(sem_getvalue(sem, &val), 0); zassert_equal(val, 1); - zassert_equal(sem_destroy(&sema), -1, "acquired semaphore" + zassert_equal(sem_destroy(sem), -1, "acquired semaphore" " is destroyed"); zassert_equal(errno, EBUSY); /* TESTPOINT: take semaphore which is initialized with 1 */ - zassert_equal(sem_trywait(&sema), 0); + zassert_equal(sem_trywait(sem), 0); - zassert_equal(pthread_create(&thread2, NULL, child_func, NULL), 0, + zassert_equal(pthread_create(&thread2, NULL, child_func, sem), 0, "Thread creation failed"); /* TESTPOINT: Wait and acquire semaphore till thread2 gives */ - zassert_equal(sem_wait(&sema), 0, "sem_wait failed"); + zassert_equal(sem_wait(sem), 0, "sem_wait failed"); + + /* Make sure the threads are terminated */ + zassert_ok(pthread_join(thread1, NULL)); + zassert_ok(pthread_join(thread2, NULL)); +} + +ZTEST(posix_apis, test_semaphore) +{ + sem_t sema; + + /* TESTPOINT: Call sem_post with invalid kobject */ + zassert_equal(sem_post(NULL), -1, "sem_post of" + " invalid semaphore object didn't fail"); + zassert_equal(errno, EINVAL); + + /* TESTPOINT: sem_destroy with invalid kobject */ + zassert_equal(sem_destroy(NULL), -1, "invalid" + " semaphore is destroyed"); + zassert_equal(errno, EINVAL); + + semaphore_test(&sema); } unsigned int nsem_get_ref_count(sem_t *sem); From b8662b97f2378f2cc204ffd985938866e4e264de Mon Sep 17 00:00:00 2001 From: Yong Cong Sin Date: Tue, 9 Jan 2024 22:59:45 +0800 Subject: [PATCH 2006/3723] tests: posix: semaphore: run normal semaphore test with named semaphore Run the normal semaphore test with a named semaphore. Signed-off-by: Yong Cong Sin --- tests/posix/common/src/semaphore.c | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) diff --git a/tests/posix/common/src/semaphore.c b/tests/posix/common/src/semaphore.c index e17300d91e8..fdaba371964 100644 --- a/tests/posix/common/src/semaphore.c +++ b/tests/posix/common/src/semaphore.c @@ -294,4 +294,21 @@ ZTEST(posix_apis, test_named_semaphore) /* All named semaphores should be destroyed here */ zassert_equal(nsem_get_list_len(), 0); + + /* Create a new named sem to be used in the normal semaphore test */ + sem1 = sem_open("nsem", O_CREAT, 0, 0); + zassert_equal(nsem_get_list_len(), 1); + zassert_equal(nsem_get_ref_count(sem1), 1); + + /* Run the semaphore test with the created named semaphore */ + semaphore_test(sem1); + + /* List length and ref_count shouldn't change after the test */ + zassert_equal(nsem_get_list_len(), 1); + zassert_equal(nsem_get_ref_count(sem1), 1); + + /* Unless it is unlinked and closed */ + sem_unlink("nsem"); + sem_close(sem1); + zassert_equal(nsem_get_list_len(), 0); } From cf74f225240ce33282bcb7aea3b9db0fe9f63e69 Mon Sep 17 00:00:00 2001 From: Nicolas Pitre Date: Tue, 9 Jan 2024 12:42:19 -0500 Subject: [PATCH 2007/3723] posix: semaphore: optimize named semaphore implementation a bit - Regroup refcount decrement and semaphore destruction by making the linked state into a counted reference for it. This allows for simplifying the code and cleanly adding a few assertions in a common location. - Remove redundant initialization to NULL on memory about to be freed and local pointer in nsem_cleanup(). Signed-off-by: Nicolas Pitre --- lib/posix/semaphore.c | 36 +++++++++++++----------------- tests/posix/common/src/semaphore.c | 2 +- 2 files changed, 16 insertions(+), 22 deletions(-) diff --git a/lib/posix/semaphore.c b/lib/posix/semaphore.c index 804ca08de1f..07ec11add4e 100644 --- a/lib/posix/semaphore.c +++ b/lib/posix/semaphore.c @@ -15,7 +15,7 @@ struct nsem_obj { sys_snode_t snode; sem_t sem; - unsigned int ref_count; + int ref_count; char *name; }; @@ -53,17 +53,20 @@ static void nsem_cleanup(struct nsem_obj *nsem) if (nsem != NULL) { if (nsem->name != NULL) { k_free(nsem->name); - nsem->name = NULL; } k_free(nsem); - nsem = NULL; } } /* Remove a named semaphore if it isn't unsed */ -static void nsem_remove_if_unused(struct nsem_obj *nsem) +static void nsem_unref(struct nsem_obj *nsem) { + nsem->ref_count -= 1; + __ASSERT(nsem->ref_count >= 0, "ref_count may not be negative"); + if (nsem->ref_count == 0) { + __ASSERT(nsem->name == NULL, "ref_count is 0 but sem is not unlinked"); + sys_slist_find_and_remove(&nsem_list, (sys_snode_t *) nsem); /* Free nsem */ @@ -255,7 +258,7 @@ sem_t *sem_open(const char *name, int oflags, ...) goto error_unlock; } - __ASSERT_NO_MSG(nsem->ref_count != UINT_MAX); + __ASSERT_NO_MSG(nsem->ref_count != INT_MAX); nsem->ref_count++; goto unlock; } @@ -282,7 +285,9 @@ sem_t *sem_open(const char *name, int oflags, ...) } strcpy(nsem->name, name); - nsem->ref_count = 1; + + /* 1 for this open instance, +1 for the linked name */ + nsem->ref_count = 2; (void)k_sem_init(&nsem->sem, value, CONFIG_SEM_VALUE_MAX); @@ -328,8 +333,7 @@ int sem_unlink(const char *name) k_free(nsem->name); nsem->name = NULL; - - nsem_remove_if_unused(nsem); + nsem_unref(nsem); unlock: nsem_list_unlock(); @@ -345,28 +349,18 @@ int sem_close(sem_t *sem) return -1; } - __ASSERT_NO_MSG(nsem != NULL); - nsem_list_lock(); - - __ASSERT_NO_MSG(nsem->ref_count != 0); - nsem->ref_count--; - - /* remove sem if marked for unlink */ - if (nsem->name == NULL) { - nsem_remove_if_unused(nsem); - } - + nsem_unref(nsem); nsem_list_unlock(); return 0; } #ifdef CONFIG_ZTEST /* Used by ztest to get the ref count of a named semaphore */ -unsigned int nsem_get_ref_count(sem_t *sem) +int nsem_get_ref_count(sem_t *sem) { struct nsem_obj *nsem = CONTAINER_OF(sem, struct nsem_obj, sem); - unsigned int ref_count; + int ref_count; __ASSERT_NO_MSG(sem != NULL); __ASSERT_NO_MSG(nsem != NULL); diff --git a/tests/posix/common/src/semaphore.c b/tests/posix/common/src/semaphore.c index fdaba371964..14eb54915ac 100644 --- a/tests/posix/common/src/semaphore.c +++ b/tests/posix/common/src/semaphore.c @@ -107,7 +107,7 @@ ZTEST(posix_apis, test_semaphore) semaphore_test(&sema); } -unsigned int nsem_get_ref_count(sem_t *sem); +int nsem_get_ref_count(sem_t *sem); size_t nsem_get_list_len(void); #define N_LOOPS 999 From e5b3231354bbd1d29702f694fc669d370df872aa Mon Sep 17 00:00:00 2001 From: Nicolas Pitre Date: Tue, 9 Jan 2024 12:55:48 -0500 Subject: [PATCH 2008/3723] tests: posix: semaphore: assorted adjustments - Adjust refcount checks with regards to previous commit. - Remove redundant zassert_not_null() on local pointers after a sem_close(). There is no implicit reference passing in C. Signed-off-by: Nicolas Pitre --- tests/posix/common/src/semaphore.c | 33 +++++++++++++++--------------- 1 file changed, 16 insertions(+), 17 deletions(-) diff --git a/tests/posix/common/src/semaphore.c b/tests/posix/common/src/semaphore.c index 14eb54915ac..fda34cfc23d 100644 --- a/tests/posix/common/src/semaphore.c +++ b/tests/posix/common/src/semaphore.c @@ -181,14 +181,14 @@ ZTEST(posix_apis, test_named_semaphore) /* Open named sem */ sem1 = sem_open("sem1", O_CREAT, 0, 0); - zassert_equal(nsem_get_ref_count(sem1), 1); + zassert_equal(nsem_get_ref_count(sem1), 2); zassert_equal(nsem_get_list_len(), 1); sem2 = sem_open("sem2", O_CREAT, 0, 0); - zassert_equal(nsem_get_ref_count(sem2), 1); + zassert_equal(nsem_get_ref_count(sem2), 2); zassert_equal(nsem_get_list_len(), 2); /* Open created named sem repeatedly */ - for (size_t i = 1; i < N_LOOPS; i++) { + for (size_t i = 1; i <= N_LOOPS; i++) { sem_t *new_sem1, *new_sem2; /* oflags are ignored (except when both O_CREAT & O_EXCL are set) */ @@ -200,8 +200,8 @@ ZTEST(posix_apis, test_named_semaphore) zassert_equal_ptr(new_sem2, sem2); /* ref_count should increment */ - zassert_equal(nsem_get_ref_count(sem1), i + 1); - zassert_equal(nsem_get_ref_count(sem2), i + 1); + zassert_equal(nsem_get_ref_count(sem1), 2 + i); + zassert_equal(nsem_get_ref_count(sem2), 2 + i); /* Should reuse the same named sem instead of creating another one */ zassert_equal(nsem_get_list_len(), 2); @@ -217,16 +217,14 @@ ZTEST(posix_apis, test_named_semaphore) zassert_equal(nsem_get_list_len(), 2); /* Close sem */ - for (size_t i = 0; + for (size_t i = N_LOOPS; /* close until one left, required by the test later */ - i < (N_LOOPS - 1); i++) { + i >= 1; i--) { zassert_ok(sem_close(sem1)); - zassert_not_null(sem1); - zassert_equal(nsem_get_ref_count(sem1), N_LOOPS - (i + 1)); + zassert_equal(nsem_get_ref_count(sem1), 2 + i - 1); zassert_ok(sem_close(sem2)); - zassert_not_null(sem2); - zassert_equal(nsem_get_ref_count(sem2), N_LOOPS - (i + 1)); + zassert_equal(nsem_get_ref_count(sem2), 2 + i - 1); zassert_equal(nsem_get_list_len(), 2); } @@ -254,9 +252,10 @@ ZTEST(posix_apis, test_named_semaphore) zassert_equal(nsem_get_list_len(), 2); /* Unlink sem1 when it is still being used */ - zassert_equal(nsem_get_ref_count(sem1), 1); + zassert_equal(nsem_get_ref_count(sem1), 2); zassert_ok(sem_unlink("sem1")); /* sem won't be destroyed */ + zassert_equal(nsem_get_ref_count(sem1), 1); zassert_equal(nsem_get_list_len(), 2); /* Create another sem with the name of an unlinked sem */ @@ -274,15 +273,15 @@ ZTEST(posix_apis, test_named_semaphore) /* Closing a linked sem won't destroy the sem */ zassert_ok(sem_close(sem2)); - zassert_equal(nsem_get_ref_count(sem2), 0); + zassert_equal(nsem_get_ref_count(sem2), 1); zassert_equal(nsem_get_list_len(), 2); /* Instead the sem will be destroyed upon call to sem_unlink() */ zassert_ok(sem_unlink("sem2")); zassert_equal(nsem_get_list_len(), 1); - /* What we have left open here is `different_sem` as "sem1", which has 1 ref_count */ - zassert_equal(nsem_get_ref_count(different_sem1), 1); + /* What we have left open here is `different_sem` as "sem1", which has a ref_count of 2 */ + zassert_equal(nsem_get_ref_count(different_sem1), 2); /* Stress test: open & close "sem1" repeatedly */ zassert_ok(pthread_create(&thread1, NULL, nsem_open_func, "sem1")); @@ -298,14 +297,14 @@ ZTEST(posix_apis, test_named_semaphore) /* Create a new named sem to be used in the normal semaphore test */ sem1 = sem_open("nsem", O_CREAT, 0, 0); zassert_equal(nsem_get_list_len(), 1); - zassert_equal(nsem_get_ref_count(sem1), 1); + zassert_equal(nsem_get_ref_count(sem1), 2); /* Run the semaphore test with the created named semaphore */ semaphore_test(sem1); /* List length and ref_count shouldn't change after the test */ zassert_equal(nsem_get_list_len(), 1); - zassert_equal(nsem_get_ref_count(sem1), 1); + zassert_equal(nsem_get_ref_count(sem1), 2); /* Unless it is unlinked and closed */ sem_unlink("nsem"); From bd8cee8683bf56cb74869457db20f9c4ae81466f Mon Sep 17 00:00:00 2001 From: Fabio Baltieri Date: Sat, 16 Dec 2023 21:13:57 +0000 Subject: [PATCH 2009/3723] drivers: input: add an analog-axis driver Add an input driver to read data from an analog device, such as a thumbstick, connected to an ADC channel, and report it as an input device. Signed-off-by: Fabio Baltieri --- doc/services/input/index.rst | 5 + drivers/input/CMakeLists.txt | 2 + drivers/input/Kconfig | 1 + drivers/input/Kconfig.analog_axis | 43 +++ drivers/input/input_analog_axis.c | 271 ++++++++++++++++++ drivers/input/input_analog_axis_settings.c | 111 +++++++ dts/bindings/input/analog-axis.yaml | 90 ++++++ include/zephyr/input/input_analog_axis.h | 97 +++++++ .../zephyr/input/input_analog_axis_settings.h | 33 +++ tests/drivers/build_all/input/app.overlay | 30 ++ tests/drivers/build_all/input/testcase.yaml | 5 + 11 files changed, 688 insertions(+) create mode 100644 drivers/input/Kconfig.analog_axis create mode 100644 drivers/input/input_analog_axis.c create mode 100644 drivers/input/input_analog_axis_settings.c create mode 100644 dts/bindings/input/analog-axis.yaml create mode 100644 include/zephyr/input/input_analog_axis.h create mode 100644 include/zephyr/input/input_analog_axis_settings.h diff --git a/doc/services/input/index.rst b/doc/services/input/index.rst index 1ec83803689..01d7d92b088 100644 --- a/doc/services/input/index.rst +++ b/doc/services/input/index.rst @@ -96,3 +96,8 @@ Input Event Definitions *********************** .. doxygengroup:: input_events + +Analog Axis API Reference +************************* + +.. doxygengroup:: input_analog_axis diff --git a/drivers/input/CMakeLists.txt b/drivers/input/CMakeLists.txt index 012bb08b283..9aeb9198b31 100644 --- a/drivers/input/CMakeLists.txt +++ b/drivers/input/CMakeLists.txt @@ -4,6 +4,8 @@ zephyr_library() zephyr_library_property(ALLOW_EMPTY TRUE) # zephyr-keep-sorted-start +zephyr_library_sources_ifdef(CONFIG_INPUT_ANALOG_AXIS input_analog_axis.c) +zephyr_library_sources_ifdef(CONFIG_INPUT_ANALOG_AXIS_SETTINGS input_analog_axis_settings.c) zephyr_library_sources_ifdef(CONFIG_INPUT_CAP1203 input_cap1203.c) zephyr_library_sources_ifdef(CONFIG_INPUT_CST816S input_cst816s.c) zephyr_library_sources_ifdef(CONFIG_INPUT_ESP32_TOUCH_SENSOR input_esp32_touch_sensor.c) diff --git a/drivers/input/Kconfig b/drivers/input/Kconfig index 8aa5471e571..41c93241f2a 100644 --- a/drivers/input/Kconfig +++ b/drivers/input/Kconfig @@ -6,6 +6,7 @@ if INPUT menu "Input drivers" # zephyr-keep-sorted-start +source "drivers/input/Kconfig.analog_axis" source "drivers/input/Kconfig.cap1203" source "drivers/input/Kconfig.cst816s" source "drivers/input/Kconfig.esp32" diff --git a/drivers/input/Kconfig.analog_axis b/drivers/input/Kconfig.analog_axis new file mode 100644 index 00000000000..472b611acea --- /dev/null +++ b/drivers/input/Kconfig.analog_axis @@ -0,0 +1,43 @@ +# Copyright 2023 Google LLC +# SPDX-License-Identifier: Apache-2.0 + +config INPUT_ANALOG_AXIS + bool "ADC based analog axis input driver" + default y + depends on DT_HAS_ANALOG_AXIS_ENABLED + depends on ADC + depends on MULTITHREADING + help + ADC based analog axis input driver + +if INPUT_ANALOG_AXIS + +config INPUT_ANALOG_AXIS_THREAD_STACK_SIZE + int "Stack size for the analog axis thread" + default 762 + help + Size of the stack used for the analog axis thread. + +config INPUT_ANALOG_AXIS_THREAD_PRIORITY + int "Priority for the analog axis thread" + default 0 + help + Priority level of the analog axis thread. + +config INPUT_ANALOG_AXIS_SETTINGS + bool "Analog axis settings support" + default y + depends on SETTINGS + help + Settings support for the analog axis driver, exposes a + analog_axis_calibration_save() function to save the calibration into + settings and load them automatically on startup. + +config INPUT_ANALOG_AXIS_SETTINGS_MAX_AXES + int "Maximum number of axes supported in the settings." + default 8 + help + Maximum number of axes that can have calibration value saved in + settings. + +endif diff --git a/drivers/input/input_analog_axis.c b/drivers/input/input_analog_axis.c new file mode 100644 index 00000000000..ace693ddf58 --- /dev/null +++ b/drivers/input/input_analog_axis.c @@ -0,0 +1,271 @@ +/* + * Copyright 2023 Google LLC + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#define DT_DRV_COMPAT analog_axis + +#include +#include +#include +#include +#include +#include +#include +#include + +LOG_MODULE_REGISTER(analog_axis, CONFIG_INPUT_LOG_LEVEL); + +struct analog_axis_channel_config { + struct adc_dt_spec adc; + int16_t out_min; + int16_t out_max; + uint16_t axis; + bool invert; +}; + +struct analog_axis_channel_data { + int last_out; +}; + +struct analog_axis_config { + uint32_t poll_period_ms; + const struct analog_axis_channel_config *channel_cfg; + struct analog_axis_channel_data *channel_data; + struct analog_axis_calibration *calibration; + const uint8_t num_channels; +}; + +struct analog_axis_data { + struct k_mutex cal_lock; + analog_axis_raw_data_t raw_data_cb; + struct k_timer timer; + struct k_thread thread; + + K_KERNEL_STACK_MEMBER(thread_stack, + CONFIG_INPUT_ANALOG_AXIS_THREAD_STACK_SIZE); +}; + +int analog_axis_num_axes(const struct device *dev) +{ + const struct analog_axis_config *cfg = dev->config; + + return cfg->num_channels; +} + +int analog_axis_calibration_get(const struct device *dev, + int channel, + struct analog_axis_calibration *out_cal) +{ + const struct analog_axis_config *cfg = dev->config; + struct analog_axis_data *data = dev->data; + struct analog_axis_calibration *cal = &cfg->calibration[channel]; + + if (channel >= cfg->num_channels) { + return -EINVAL; + } + + k_mutex_lock(&data->cal_lock, K_FOREVER); + memcpy(out_cal, cal, sizeof(struct analog_axis_calibration)); + k_mutex_unlock(&data->cal_lock); + + return 0; +} + +void analog_axis_set_raw_data_cb(const struct device *dev, analog_axis_raw_data_t cb) +{ + struct analog_axis_data *data = dev->data; + + k_mutex_lock(&data->cal_lock, K_FOREVER); + data->raw_data_cb = cb; + k_mutex_unlock(&data->cal_lock); +} + +int analog_axis_calibration_set(const struct device *dev, + int channel, + struct analog_axis_calibration *new_cal) +{ + const struct analog_axis_config *cfg = dev->config; + struct analog_axis_data *data = dev->data; + struct analog_axis_calibration *cal = &cfg->calibration[channel]; + + if (channel >= cfg->num_channels) { + return -EINVAL; + } + + k_mutex_lock(&data->cal_lock, K_FOREVER); + memcpy(cal, new_cal, sizeof(struct analog_axis_calibration)); + k_mutex_unlock(&data->cal_lock); + + return 0; +} + +static void analog_axis_loop(const struct device *dev) +{ + const struct analog_axis_config *cfg = dev->config; + struct analog_axis_data *data = dev->data; + int16_t bufs[cfg->num_channels]; + int32_t out; + struct adc_sequence sequence = { + .buffer = bufs, + .buffer_size = sizeof(bufs), + }; + const struct analog_axis_channel_config *axis_cfg_0 = &cfg->channel_cfg[0]; + int err; + int i; + + adc_sequence_init_dt(&axis_cfg_0->adc, &sequence); + + for (i = 0; i < cfg->num_channels; i++) { + const struct analog_axis_channel_config *axis_cfg = &cfg->channel_cfg[i]; + + sequence.channels |= BIT(axis_cfg->adc.channel_id); + } + + err = adc_read(axis_cfg_0->adc.dev, &sequence); + if (err < 0) { + LOG_ERR("Could not read (%d)", err); + return; + } + + k_mutex_lock(&data->cal_lock, K_FOREVER); + + for (i = 0; i < cfg->num_channels; i++) { + const struct analog_axis_channel_config *axis_cfg = &cfg->channel_cfg[i]; + struct analog_axis_channel_data *axis_data = &cfg->channel_data[i]; + struct analog_axis_calibration *cal = &cfg->calibration[i]; + int16_t in_range = cal->in_max - cal->in_min; + int16_t out_range = axis_cfg->out_max - axis_cfg->out_min; + int32_t raw_val = bufs[i]; + + if (axis_cfg->invert) { + raw_val *= -1; + } + + if (data->raw_data_cb != NULL) { + data->raw_data_cb(dev, i, raw_val); + } + + LOG_DBG("%s: ch %d: raw_val: %d", dev->name, i, raw_val); + + out = CLAMP((raw_val - cal->in_min) * out_range / in_range + axis_cfg->out_min, + axis_cfg->out_min, axis_cfg->out_max); + + if (cal->out_deadzone > 0) { + int16_t center = DIV_ROUND_CLOSEST( + axis_cfg->out_max + axis_cfg->out_min, 2); + if (abs(out - center) < cal->out_deadzone) { + out = center; + } + } + + if (axis_data->last_out != out) { + input_report_abs(dev, axis_cfg->axis, out, true, K_FOREVER); + } + axis_data->last_out = out; + } + + k_mutex_unlock(&data->cal_lock); +} + +static void analog_axis_thread(void *arg1, void *arg2, void *arg3) +{ + const struct device *dev = arg1; + const struct analog_axis_config *cfg = dev->config; + struct analog_axis_data *data = dev->data; + int err; + int i; + + for (i = 0; i < cfg->num_channels; i++) { + const struct analog_axis_channel_config *axis_cfg = &cfg->channel_cfg[i]; + + if (!adc_is_ready_dt(&axis_cfg->adc)) { + LOG_ERR("ADC controller device not ready"); + return; + } + + err = adc_channel_setup_dt(&axis_cfg->adc); + if (err < 0) { + LOG_ERR("Could not setup channel #%d (%d)", i, err); + return; + } + } + + k_timer_init(&data->timer, NULL, NULL); + k_timer_start(&data->timer, + K_MSEC(cfg->poll_period_ms), K_MSEC(cfg->poll_period_ms)); + + while (true) { + analog_axis_loop(dev); + k_timer_status_sync(&data->timer); + } +} + +static int analog_axis_init(const struct device *dev) +{ + struct analog_axis_data *data = dev->data; + k_tid_t tid; + + k_mutex_init(&data->cal_lock); + + tid = k_thread_create(&data->thread, data->thread_stack, + K_KERNEL_STACK_SIZEOF(data->thread_stack), + analog_axis_thread, (void *)dev, NULL, NULL, + CONFIG_INPUT_ANALOG_AXIS_THREAD_PRIORITY, + 0, K_NO_WAIT); + if (!tid) { + LOG_ERR("thread creation failed"); + return -ENODEV; + } + + k_thread_name_set(&data->thread, dev->name); + + return 0; +} + +#define ANALOG_AXIS_CHANNEL_CFG_DEF(node_id) \ + { \ + .adc = ADC_DT_SPEC_GET(node_id), \ + .out_min = (int16_t)DT_PROP(node_id, out_min), \ + .out_max = (int16_t)DT_PROP(node_id, out_max), \ + .axis = DT_PROP(node_id, zephyr_axis), \ + .invert = DT_PROP(node_id, invert), \ + } + +#define ANALOG_AXIS_CHANNEL_CAL_DEF(node_id) \ + { \ + .in_min = (int16_t)DT_PROP(node_id, in_min), \ + .in_max = (int16_t)DT_PROP(node_id, in_max), \ + .out_deadzone = DT_PROP(node_id, out_deadzone), \ + } + +#define ANALOG_AXIS_INIT(inst) \ + static const struct analog_axis_channel_config analog_axis_channel_cfg_##inst[] = { \ + DT_INST_FOREACH_CHILD_STATUS_OKAY_SEP(inst, ANALOG_AXIS_CHANNEL_CFG_DEF, (,)) \ + }; \ + \ + static struct analog_axis_channel_data \ + analog_axis_channel_data_##inst[ARRAY_SIZE(analog_axis_channel_cfg_##inst)]; \ + \ + static struct analog_axis_calibration \ + analog_axis_calibration##inst[ARRAY_SIZE(analog_axis_channel_cfg_##inst)] = { \ + DT_INST_FOREACH_CHILD_STATUS_OKAY_SEP( \ + inst, ANALOG_AXIS_CHANNEL_CAL_DEF, (,)) \ + }; \ + \ + static const struct analog_axis_config analog_axis_cfg_##inst = { \ + .poll_period_ms = DT_INST_PROP(inst, poll_period_ms), \ + .channel_cfg = analog_axis_channel_cfg_##inst, \ + .channel_data = analog_axis_channel_data_##inst, \ + .calibration = analog_axis_calibration##inst, \ + .num_channels = ARRAY_SIZE(analog_axis_channel_cfg_##inst), \ + }; \ + \ + static struct analog_axis_data analog_axis_data_##inst; \ + \ + DEVICE_DT_INST_DEFINE(inst, analog_axis_init, NULL, \ + &analog_axis_data_##inst, &analog_axis_cfg_##inst, \ + POST_KERNEL, CONFIG_INPUT_INIT_PRIORITY, NULL); + +DT_INST_FOREACH_STATUS_OKAY(ANALOG_AXIS_INIT) diff --git a/drivers/input/input_analog_axis_settings.c b/drivers/input/input_analog_axis_settings.c new file mode 100644 index 00000000000..3d29af8b96f --- /dev/null +++ b/drivers/input/input_analog_axis_settings.c @@ -0,0 +1,111 @@ +/* + * Copyright 2023 Google LLC + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include +#include +#include +#include +#include +#include +#include + +LOG_MODULE_REGISTER(analog_axis_settings, CONFIG_INPUT_LOG_LEVEL); + +#define ANALOG_AXIS_SETTINGS_PATH_MAX 32 + +#define MAX_AXES CONFIG_INPUT_ANALOG_AXIS_SETTINGS_MAX_AXES + +static void analog_axis_calibration_log(const struct device *dev) +{ + struct analog_axis_calibration cal; + int i; + + for (i = 0; i < analog_axis_num_axes(dev); i++) { + analog_axis_calibration_get(dev, i, &cal); + + LOG_INF("%s: ch: %d min: %d max: %d deadzone: %d", + dev->name, i, cal.in_min, cal.in_max, cal.out_deadzone); + } +} + +static int analog_axis_calibration_load(const char *key, size_t len_rd, + settings_read_cb read_cb, void *cb_arg) +{ + const struct device *dev; + struct analog_axis_calibration cal[MAX_AXES]; + int axes; + char dev_name[ANALOG_AXIS_SETTINGS_PATH_MAX]; + const char *next; + int nlen; + ssize_t len; + + nlen = settings_name_next(key, &next); + if (nlen + 1 > sizeof(dev_name)) { + LOG_ERR("Setting name too long: %d", nlen); + return -EINVAL; + } + + memcpy(dev_name, key, nlen); + dev_name[nlen] = '\0'; + + dev = device_get_binding(dev_name); + if (dev == NULL) { + LOG_ERR("Cannot restore: device %s not available", dev_name); + return -ENODEV; + } + + len = read_cb(cb_arg, cal, sizeof(cal)); + if (len < 0) { + LOG_ERR("Data restore error: %d", len); + } + + axes = analog_axis_num_axes(dev); + if (len != sizeof(struct analog_axis_calibration) * axes) { + LOG_ERR("Invalid settings data length: %d, expected %d", + len, sizeof(struct analog_axis_calibration) * axes); + return -EIO; + } + + for (int i = 0; i < axes; i++) { + analog_axis_calibration_set(dev, i, &cal[i]); + } + + analog_axis_calibration_log(dev); + + return 0; +} + +SETTINGS_STATIC_HANDLER_DEFINE(analog_axis, "aa-cal", NULL, + analog_axis_calibration_load, NULL, NULL); + +int analog_axis_calibration_save(const struct device *dev) +{ + struct analog_axis_calibration cal[MAX_AXES]; + int axes; + char path[ANALOG_AXIS_SETTINGS_PATH_MAX]; + int ret; + + analog_axis_calibration_log(dev); + + ret = snprintk(path, sizeof(path), "aa-cal/%s", dev->name); + if (ret < 0) { + return -EINVAL; + } + + axes = analog_axis_num_axes(dev); + for (int i = 0; i < axes; i++) { + analog_axis_calibration_get(dev, i, &cal[i]); + } + + ret = settings_save_one(path, &cal[0], + sizeof(struct analog_axis_calibration) * axes); + if (ret < 0) { + LOG_ERR("Settings save errord: %d", ret); + return ret; + } + + return 0; +} diff --git a/dts/bindings/input/analog-axis.yaml b/dts/bindings/input/analog-axis.yaml new file mode 100644 index 00000000000..ded94e86c0f --- /dev/null +++ b/dts/bindings/input/analog-axis.yaml @@ -0,0 +1,90 @@ +# Copyright 2023 Google LLC +# SPDX-License-Identifier: Apache-2.0 + +description: | + ADC based analog axis input device + + Implement an input device generating absolute axis events by periodically + reading from some ADC channels. + + Example configuration: + + #include + + analog_axis { + compatible = "analog-axis"; + poll-period-ms = <15>; + axis-x { + io-channels = <&adc 0>; + out-deadzone = <8>; + in-min = <100>; + in-max = <800>; + zephyr,axis = ; + }; + }; + +compatible: "analog-axis" + +include: base.yaml + +properties: + poll-period-ms: + type: int + default: 15 + description: | + How often to get new ADC samples for the various configured axes in + milliseconds. Defaults to 15ms if unspecified. + +child-binding: + properties: + io-channels: + type: phandle-array + required: true + description: | + ADC IO channel to use. + + out-min: + type: int + default: 0 + description: | + Minimum value to output on input events. Defaults to 0 if unspecified. + + out-max: + type: int + default: 255 + description: | + Maximum value to output on input events. Defaults to 255 if + unspecified. + + out-deadzone: + type: int + default: 0 + description: | + Deadzone for the output center value. If specified output values + between the center of the range plus or minus this value will be + reported as center. Defaults to 0, no deadzone. + + in-min: + type: int + required: true + description: | + Input value that corresponds to the minimum output value. + + in-max: + type: int + required: true + description: | + Input value that corresponds to the maximum output value. + + zephyr,axis: + type: int + required: true + description: | + The input code for the axis to report for the device, typically any of + INPUT_ABS_*. + + invert: + type: boolean + description: | + If set, invert the raw ADC value before processing it. Useful for + differential channels. diff --git a/include/zephyr/input/input_analog_axis.h b/include/zephyr/input/input_analog_axis.h new file mode 100644 index 00000000000..14492156d9c --- /dev/null +++ b/include/zephyr/input/input_analog_axis.h @@ -0,0 +1,97 @@ +/* + * Copyright 2023 Google LLC + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#ifndef ZEPHYR_INCLUDE_INPUT_ANALOG_AXIS_H_ +#define ZEPHYR_INCLUDE_INPUT_ANALOG_AXIS_H_ + +#include +#include + +/** + * @brief Analog axis API + * @defgroup input_analog_axis Analog axis API + * @ingroup io_interfaces + * @{ + */ + +/** + * @brief Analog axis calibration data structure. + * + * Holds the calibration data for a single analog axis. Initial values are set + * from the devicetree and can be changed by the applicatoin in runtime using + * @ref analog_axis_calibration_set and @ref analog_axis_calibration_get. + */ +struct analog_axis_calibration { + /** Input value that corresponds to the minimum output value. */ + int16_t in_min; + /** Input value that corresponds to the maximum output value. */ + int16_t in_max; + /** Output value deadzone relative to the output range. */ + uint16_t out_deadzone; +}; + +/** + * @brief Analog axis raw data callback. + * + * @param dev Analog axis device. + * @param channel Channel number. + * @param raw_val Raw value for the channel. + */ +typedef void (*analog_axis_raw_data_t)(const struct device *dev, + int channel, int16_t raw_val); + +/** + * @brief Set a raw data callback. + * + * Set a callback to receive raw data for the specified analog axis device. + * This is meant to be use in the application to acquire the data to use for + * calibration. Set cb to NULL to disable the callback. + * + * @param dev Analog axis device. + * @param cb An analog_axis_raw_data_t callback to use, NULL disable. + */ +void analog_axis_set_raw_data_cb(const struct device *dev, analog_axis_raw_data_t cb); + +/** + * @brief Get the number of defined axes. + * + * @retval n The number of defined axes for dev. + */ +int analog_axis_num_axes(const struct device *dev); + +/** + * @brief Get the axis calibration data. + * + * @param dev Analog axis device. + * @param channel Channel number. + * @param cal Pointer to an analog_axis_calibration structure that is going to + * get set with the current calibration data. + * + * @retval 0 If successful. + * @retval -EINVAL If the specified channel is not valid. + */ +int analog_axis_calibration_get(const struct device *dev, + int channel, + struct analog_axis_calibration *cal); + +/** + * @brief Set the axis calibration data. + * + * @param dev Analog axis device. + * @param channel Channel number. + * @param cal Pointer to an analog_axis_calibration structure with the new + * calibration data + * + * @retval 0 If successful. + * @retval -EINVAL If the specified channel is not valid. + */ +int analog_axis_calibration_set(const struct device *dev, + int channel, + struct analog_axis_calibration *cal); + +/** @} */ + +#endif /* ZEPHYR_INCLUDE_INPUT_ANALOG_AXIS_H_ */ diff --git a/include/zephyr/input/input_analog_axis_settings.h b/include/zephyr/input/input_analog_axis_settings.h new file mode 100644 index 00000000000..da8ad0ddfa3 --- /dev/null +++ b/include/zephyr/input/input_analog_axis_settings.h @@ -0,0 +1,33 @@ +/* + * Copyright 2023 Google LLC + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#ifndef ZEPHYR_INCLUDE_INPUT_ANALOG_AXIS_SETTINGS_H_ +#define ZEPHYR_INCLUDE_INPUT_ANALOG_AXIS_SETTINGS_H_ + +#include +#include + +/** + * @addtogroup input_analog_axis + * @{ + */ + +/** + * @brief Save the calibration data. + * + * Save the calibration data permanently on the specifided device, requires the + * the @ref settings subsystem to be configured and initialized. + * + * @param dev Analog axis device. + * + * @retval 0 If successful. + * @retval -errno In case of any other error. + */ +int analog_axis_calibration_save(const struct device *dev); + +/** @} */ + +#endif /* ZEPHYR_INCLUDE_INPUT_ANALOG_AXIS_SETTINGS_H_ */ diff --git a/tests/drivers/build_all/input/app.overlay b/tests/drivers/build_all/input/app.overlay index 0a005414667..66edd90f8bd 100644 --- a/tests/drivers/build_all/input/app.overlay +++ b/tests/drivers/build_all/input/app.overlay @@ -9,6 +9,22 @@ #address-cells = <1>; #size-cells = <1>; + test_adc: adc@adc0adc0 { + compatible = "vnd,adc"; + reg = <0xadc0adc0 0x1000>; + #io-channel-cells = <1>; + #address-cells = <1>; + #size-cells = <0>; + status = "okay"; + + channel@0 { + reg = <0>; + zephyr,gain = "ADC_GAIN_1"; + zephyr,reference = "ADC_REF_VDD_1"; + zephyr,acquisition-time = ; + }; + }; + test_gpio: gpio@0 { compatible = "vnd,gpio"; gpio-controller; @@ -71,6 +87,20 @@ idle-timeout-ms = <200>; }; + analog_axis { + compatible = "analog-axis"; + axis-x { + io-channels = <&test_adc 0>; + out-min = <(-127)>; + out-max = <127>; + out-deadzone = <8>; + in-min = <(-100)>; + in-max = <100>; + zephyr,axis = <0>; + invert; + }; + }; + longpress: longpress { input = <&longpress>; compatible = "zephyr,input-longpress"; diff --git a/tests/drivers/build_all/input/testcase.yaml b/tests/drivers/build_all/input/testcase.yaml index eb915db1673..2c3883ab062 100644 --- a/tests/drivers/build_all/input/testcase.yaml +++ b/tests/drivers/build_all/input/testcase.yaml @@ -19,3 +19,8 @@ tests: drivers.input.kbd_16_bit: extra_configs: - CONFIG_INPUT_KBD_MATRIX_16_BIT_ROW=y + + drivers.input.analog_axis: + extra_configs: + - CONFIG_ADC=y + - CONFIG_SETTINGS=y From 067f32731e64198cf59b34b3b74c5c6aadc7c82d Mon Sep 17 00:00:00 2001 From: Gerard Marull-Paretas Date: Tue, 2 Jan 2024 12:11:01 +0100 Subject: [PATCH 2010/3723] modules: hal_gigadevice: use CONFIG_${ARCH} to select components Instead of using custom SoC definitions. The selected components (e.g. CMSIS), depend on the architecture selected by the SoC Kconfig options. Signed-off-by: Gerard Marull-Paretas --- modules/hal_gigadevice/CMakeLists.txt | 4 ++-- modules/hal_gigadevice/Kconfig | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/modules/hal_gigadevice/CMakeLists.txt b/modules/hal_gigadevice/CMakeLists.txt index 7a4096bc4d2..3b887f654a9 100644 --- a/modules/hal_gigadevice/CMakeLists.txt +++ b/modules/hal_gigadevice/CMakeLists.txt @@ -6,9 +6,9 @@ if(CONFIG_HAS_GD32_HAL) string(TOUPPER ${CONFIG_SOC} gd32_soc_uc) set(gd32_soc_dir ${ZEPHYR_HAL_GIGADEVICE_MODULE_DIR}/${CONFIG_SOC_SERIES}) -if(CONFIG_SOC_FAMILY_GD32_ARM) +if(CONFIG_ARM) set(gd32_soc_sys_dir ${gd32_soc_dir}/cmsis/gd/${CONFIG_SOC_SERIES}) -elseif(CONFIG_SOC_SERIES_GD32VF103) +elseif(CONFIG_RISCV) set(gd32_soc_sys_dir ${gd32_soc_dir}/riscv) zephyr_include_directories(${gd32_soc_dir}/riscv/drivers) endif() diff --git a/modules/hal_gigadevice/Kconfig b/modules/hal_gigadevice/Kconfig index 66132779eb1..84f6532b251 100644 --- a/modules/hal_gigadevice/Kconfig +++ b/modules/hal_gigadevice/Kconfig @@ -16,7 +16,7 @@ config GD32_HAS_AFIO_PINMUX config HAS_GD32_HAL bool - select HAS_CMSIS_CORE if SOC_FAMILY_GD32_ARM + select HAS_CMSIS_CORE if ARM if HAS_GD32_HAL From 81dbe94a16ae1e73050f07dd7c67bccd1f5f9d68 Mon Sep 17 00:00:00 2001 From: Gerard Marull-Paretas Date: Mon, 8 Jan 2024 10:02:36 +0100 Subject: [PATCH 2011/3723] boards: gd32*: reduce board image file size Some GD32 board pictures exceed the maximum allowed limit (100K), so reduce them. Automated using `cwebp path/to/board.jpg -o path/to/board.webp` Signed-off-by: Gerard Marull-Paretas --- .../gd32e507z_eval/doc/img/gd32e507z_eval.jpg | Bin 169999 -> 0 bytes .../gd32e507z_eval/doc/img/gd32e507z_eval.webp | Bin 0 -> 56794 bytes boards/arm/gd32e507z_eval/doc/index.rst | 2 +- .../gd32f350r_eval/doc/img/gd32f350r_eval.jpg | Bin 103110 -> 0 bytes .../gd32f350r_eval/doc/img/gd32f350r_eval.webp | Bin 0 -> 76978 bytes boards/arm/gd32f350r_eval/doc/index.rst | 2 +- .../doc/img/gd32f407v_start.jpg | Bin 127346 -> 0 bytes .../doc/img/gd32f407v_start.webp | Bin 0 -> 42974 bytes boards/arm/gd32f407v_start/doc/index.rst | 2 +- .../gd32f450i_eval/doc/img/gd32f450i_eval.jpg | Bin 102487 -> 0 bytes .../gd32f450i_eval/doc/img/gd32f450i_eval.webp | Bin 0 -> 65868 bytes boards/arm/gd32f450i_eval/doc/index.rst | 2 +- .../doc/img/gd32f450v_start.jpg | Bin 114900 -> 0 bytes .../doc/img/gd32f450v_start.webp | Bin 0 -> 37702 bytes boards/arm/gd32f450v_start/doc/index.rst | 2 +- .../gd32f450z_eval/doc/img/gd32f450z_eval.jpg | Bin 104488 -> 0 bytes .../gd32f450z_eval/doc/img/gd32f450z_eval.webp | Bin 0 -> 79346 bytes boards/arm/gd32f450z_eval/doc/index.rst | 2 +- 18 files changed, 6 insertions(+), 6 deletions(-) delete mode 100644 boards/arm/gd32e507z_eval/doc/img/gd32e507z_eval.jpg create mode 100644 boards/arm/gd32e507z_eval/doc/img/gd32e507z_eval.webp delete mode 100644 boards/arm/gd32f350r_eval/doc/img/gd32f350r_eval.jpg create mode 100644 boards/arm/gd32f350r_eval/doc/img/gd32f350r_eval.webp delete mode 100644 boards/arm/gd32f407v_start/doc/img/gd32f407v_start.jpg create mode 100644 boards/arm/gd32f407v_start/doc/img/gd32f407v_start.webp delete mode 100644 boards/arm/gd32f450i_eval/doc/img/gd32f450i_eval.jpg create mode 100644 boards/arm/gd32f450i_eval/doc/img/gd32f450i_eval.webp delete mode 100644 boards/arm/gd32f450v_start/doc/img/gd32f450v_start.jpg create mode 100644 boards/arm/gd32f450v_start/doc/img/gd32f450v_start.webp delete mode 100644 boards/arm/gd32f450z_eval/doc/img/gd32f450z_eval.jpg create mode 100644 boards/arm/gd32f450z_eval/doc/img/gd32f450z_eval.webp diff --git a/boards/arm/gd32e507z_eval/doc/img/gd32e507z_eval.jpg b/boards/arm/gd32e507z_eval/doc/img/gd32e507z_eval.jpg deleted file mode 100644 index f09658eb7b8633ef41a3f4f8d9e24006edd0a491..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 169999 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

G`2BBg^_OH!i@W-IXmj#j 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 RGJHV6;J^<-{{Z=a|Jf5wzzP5W diff --git a/boards/arm/gd32e507z_eval/doc/img/gd32e507z_eval.webp b/boards/arm/gd32e507z_eval/doc/img/gd32e507z_eval.webp new file mode 100644 index 0000000000000000000000000000000000000000..bad1bd26a4f21c6a02af47b24bb781e09dc9aca5 GIT binary patch literal 56794 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


%=j3n@flF+AOrZEsY*2f!7@9x_+Hp|5i$g_qY} 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
2+s2~7DNpp_9qdeD`Lj|O6+5L&UT_HO3x3c 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 diff --git a/boards/arm/gd32f407v_start/doc/img/gd32f407v_start.webp b/boards/arm/gd32f407v_start/doc/img/gd32f407v_start.webp new file mode 100644 index 0000000000000000000000000000000000000000..1badefd1e38826b37ebfaedaf00d48e47386918d GIT binary patch literal 42974 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 ffPomT?p1(DbN~PV000000000000000000002f(N^ literal 0 HcmV?d00001 diff --git a/boards/arm/gd32f407v_start/doc/index.rst b/boards/arm/gd32f407v_start/doc/index.rst index fd24ffb5d64..cd67921e59e 100644 --- a/boards/arm/gd32f407v_start/doc/index.rst +++ b/boards/arm/gd32f407v_start/doc/index.rst @@ -13,7 +13,7 @@ The GD32F407VE features a single-core ARM Cortex-M4 MCU which can run up to 168 MHz with flash accesses zero wait states, 3072kiB of Flash, 192kiB of SRAM and 82 GPIOs. -.. image:: img/gd32f407v_start.jpg +.. image:: img/gd32f407v_start.webp :align: center :alt: gd32f407v_start diff --git a/boards/arm/gd32f450i_eval/doc/img/gd32f450i_eval.jpg b/boards/arm/gd32f450i_eval/doc/img/gd32f450i_eval.jpg deleted file mode 100644 index 032905d9842a827a98ef92e7f4cdaca7ec66c703..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 102487 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%0ANnH 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 bz`d&-<7WhdLwJ2Q$C+ZVfc7$-|0e%`yj4S! literal 0 HcmV?d00001 diff --git a/boards/arm/gd32f450i_eval/doc/index.rst b/boards/arm/gd32f450i_eval/doc/index.rst index 56017e4aef5..59e9d258975 100644 --- a/boards/arm/gd32f450i_eval/doc/index.rst +++ b/boards/arm/gd32f450i_eval/doc/index.rst @@ -13,7 +13,7 @@ The GD32F450IK features a single-core ARM Cortex-M4F MCU which can run up to 200 MHz with flash accesses zero wait states, 3072kiB of Flash, 256kiB of SRAM and 140 GPIOs. -.. image:: img/gd32f450i_eval.jpg +.. image:: img/gd32f450i_eval.webp :align: center :alt: gd32f450i_eval diff --git a/boards/arm/gd32f450v_start/doc/img/gd32f450v_start.jpg b/boards/arm/gd32f450v_start/doc/img/gd32f450v_start.jpg deleted file mode 100644 index f2b3f48fbcab2cb8b623adad43c5270b2e845648..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 114900 zcmeFYbzD{5_BXmVASEplN^Ak8k?ux7L>lSdG;CsTxAZ9p1=@!Jjnc98i8zJ>Phv1~&A(jfu$@4xyB ze?kXX{<0obToJ33fExwxUK2uG-rsRzIY>R$W#cPp=;qzdKc;Ns-q;RLgK`N8^YRFD@%{%J3_xPwUr}~|-lhD(10be*^_O?oQ8NC)<{$>%VgaC2 z04FyOH~QPZA|3;kF#g~T5EFqI>sl9#fcOu_1~JJWOax*`)L(WW*I9_h{T&GfC`XI_ z%O5C+(f`PqK#cJRbAlKv`Y+#ZfJ5N?!9*a&{nJ+v)FB1s*M3TZI4TGXIi;5J3M2#>o6D zmdBtEH~z>aK^@G0=x~EN*M6#kIy{+wtx6{l^MaTQl)Hi0SuKy@w(M)$jn+6&3)d>3VVh%O5-tU;FjHSh-L$Q#3M=lFqWBieuf%5A-Uwe98Fn?bG zfEOso`=hT2%JKim13@{_AGszdC;lT31?A-bkW>7TM}u@%koMuJ2PZ+yK(RN96C8{*N37xCG<6*7zOGpWPzm z`ugvk1H6F-?m*WWAqA6+{%1G3-pw%ofp7o8*Lo1Nzii$C_0j&|r;OkYuweiGx%%h6 zc|ABd%GD$w17KrfVqxCE#=^qF!NJDGBgMzNc@vM4N`|aPzDZ0C>FZZ<(2o4So-c39Te0&P-dsO$h|BuU6GeC?DdX$0= zp##u}A?U=At8d_(0FWEkyFBD~uC9XtHxrB-m{{02xHmzC3UHPo=;&w|=r?X)fD;Gt zz20mvh;NYGrDlpn=S<4|JSrWVUb^(lZT0Uv3_NCtKpb2$atg{j_a87aF|+XU z@e2qF3Clc^m6Lz0@I*uNnU=PWt{%+X!qUpx#un+~>gMj@>Gk4eP;khr*P+od?_%TP z-zOw~%*f2j&iRy^SN6HQqOz*GruJ*gx7N1yj?S*Zp&!E|qhsR}bMp&}OUtO0)wSKd z{a*)%N5?0p*Kt9>N&UNANA>@Rix`Xx4Fdxm1M5022%7tK;KUd=?r~v~NU33&I^Uw> zevVBl9hF}C1&5wTedo3r;yW%G1Ml4Z-RsbPNA~|Nu)zOMk^L*Mf5$Ze;Gu(0H8DCd zAORemvQ$iuz6Dfo(s=$VSmn!nIjank0Hz-Q}$yn#9X-(LJP5{fnP-?wh z+ODPjnWF4mT0bM zNn;oCd`;*3B<*XOhw4~|Q<+{TYFEH6-_S97d*WgGg8p566?N|FBNjJGr2=XvfB+8N`^1`+99n)EEYIK5;=oahOqHQeM|5h1DXdl`5(@>stv98VX~ zHe`?a;a&mf&%8D(b3{wNZqWC3ASijvC@1F52La-<+2*V`iR&1yE z^m<2y$}1W=#r!%}#n-o^x(Wj2**JZ1+E>;33q!iI`afA0Cy8<`5E2=`d86Mey}n5- zy;l&dp7~Y|Qy7+bK#P0+BvQw%EM6tWyedGXi`H-dtuW+xNL^`+N_Rz5%f+iq;R;}T zPu=RIlHUHSh;|+;!qpI%#AkX`$dXUY;C*SF#<JfB)QQ*Bno} z;$^z#XJUJgFVLgILTZuutp>-uM|>Xe)E-A0vKclJCafC@_O8_He6L=(F%L$IHHNmn z`8EcSpRsI0qIn`n23F>N~kr z++BwOOitkTJ{3KAhX^1M%ak4WVXW62o*dzSr@wMVJm=)j&}jRq+}!FAUy`+;_=mI$ zjDbpmoO~a~q0OQSUpd{65ptpTElA`FuzHX`Tv3HywW~X5X`&yPG=t1cTJxn;XnSQR3 zs)K+WF4x`dP6!DtuU<%$f%9@0zM-nba=x%-sHh$qY`>YE#N~)Y)A?c@luTDxULPoY z=6{fP1+;9ET>&a1j>VRh3GDYn?A1H!1d?BTO?5uj)}G6s>@0NjIWhJ!tcA1rsfxH3 zx>;IwlPC$cvP+fS9CEVfkj;SCaB;po6&GCJ4&7^_HCEPx9&vZsJ8!$j1esyCk!Gtf!muzjxq zig1evc(x6Qd8aeWzdg;8SwV7sF*RNQAjq@Q5h%n z(Vd)G+9!R5_$n9Hr&@k2oh-Iz5@iq6aTqDuy-sSqangtNc&GxH(e3aHJbtYwp4tb@ zvI4T6+Mzz|g$Bos-WPNOj!EyLDW7pV2V%1kI`|^hhZ@?Pj2`S__Bq< z!*p0U6@Wlx6+U^Xos`HBm}A+rBHW#grHbJRfr^osP}a!887IVnV>ub}E-2P#DB91= z7r`?LxXi!NHSjKtu|Bfg(;&!kr;ul()7iO&!7nc;>eC={IucubX81+3@gdYep>cNk z>_e)zQ_J3_L2Lc#>tMmKJ7IES3%&ZE-cT)2u10gppJV@snl_T6%4hI;&Ed`v=+POu zZABFpA-|-tNhhx5dN@)x8OZQnkUs4lUYgMjomQkDb&YOT_3H}ek{b%9DT< ze>A%c$!AVII;V->Me?J6x!tR+RIF1dG-qJwP)0tktq!S16{Fmjwa3@C_|Kb1#q53X2Hjl zkA&f|-`?!2knlkI1n_<^yx;1YP>vCcdv0nnIQQX27Xk;BBaQv*!gi@5Xu5s|*2~ah zIsFpgNk;80oU?ZLJutkPM%)wAY{W`&H^_ug5S7*vX}eI)9MnB6@4_J<<*@fC`{@m? zKrcUv{0FG--zVzTGw!~oV!3TH-N|qTq^&rspDK|`e{xI zI?|=?7CB<N!I4ObzI?z#x@-2(>R7A&s9VC%*$Z%%icZsvOBksOV?*A^S9!$x}rj+ zG)WJlkoc`V0^FXX7(5tOjLxDiK%~)dKepyG^U0y~f@A{{{e+R)*3By*Fk`f+aASH} z!1BIh%5z*9^r5@ncSf2XL(6!k=*z?0A$Q`SWNd^(STt>=9ECTsk}LHb0;484Tk4Ue z+FyQJIkh+uAZHWTEUKreoVv3**}T67?1lj7;ZtF-rb6pc{;+o&2zcS@nw;pD2(FSL zVd-ngKKHnSpFg~${f^aC=IFMYv3C6C#h)%3sM*W2Nj6Uz{-L_wd?1{7iYJmL2W zUrM=19SQAU`s!)W~Di;Kt~;i&7aR+&s;4 zAFZ>dg{$AB25a|A;ig7wRQrcEBZ8oup*0OpM8H&p2!!r-_84~O+i%- zb#tGo88~nJS}b)(hSaHzGb$ke*X=J4TlFR0iYKpZKv*m&4GzT*+*_^yq5{Wa@z%Vy zfhp1F_xM+IDWcxu98jS@S>Y2@dF}43cl@R5TY($#3ks*^h)kLWl_dkC*n+z{Mf2fm z;op=fyUgdxgb%4udqt>uQLpf-aGC{`(5DrZtt?3)Y?IYrmTQzmRCY=Id@HhI$I0#A zK*@R(Z%jefB`KB29H#v~qX3S7va92Lntidf%J>-D|y zamv#+>thIP(RI3guc+?n6`<U30^vOcmxhnu|ZKQTHF4v7d2#zB79@CxD zAl11bNUA$U_=whyVY?c5-ZtaeKD2spm>u)Uv&io|aaawDP~WU_itm~CkEtCMtm+)I zg6JE!ur3z!R;z}vBWc{hE8o^L z23$A%{-x|yU}nwRd*JvsweGD@hbROlZEHQ-mQBIVU?Zy_&Jk9 zyx(-R7T|77GGp9f1J5L@ItrtWuoVg%+SYDKN?$jWSNy;N4`ft zXuoZ*XnkaxORVcws%}P)9=0Fpd?^d)WPW@hNvwh)pjs|K%obIp>HOACWVq!GZ4>B5=m?Cs~LO%#e;|NjjVP7_V z$d-4cds;9WBMb=-p^)H`=vdgv-3`^lu$&P%v?z$j_hsSGS$fBbvBR^0L!~*tbu(A5 zlSY>N5hVk)4)I9(Xd$iI_vP}S3=)3A-Urjw(1UY{JJGCmpNiQnQs<}5B7jsKfVvq5 zMdegV+==&I;g+&Pd{T2LfSti*Wy7$S|ZBmVtU zvr=Nw2aSNMu7xm;5S!r}^m-Up@k}e=(n;5WV-QAV8jKIOnO$pwocAII@E@YvVNw{g zC%nGzmW;dteEp1uhit^P$D0s{yU-y^xl(aLq6-nRIeG0)qY0r-Zz2<(Sc%e{EJPE|>5{bi%@~hwnT8dP z@tlMzA0O^v3e%*;a+00SuUaNf!zl~z3~Jd0$lVT@d)(*QpJQ7#)YIp#SG(V*L#uMx zw4}Mc&}d`ju|=mZQQB2_3%$utTwSboxp1RK<27S=hvWMbosNasV&lH&gdandts&N# z8G;{fe0)n4YCs&7T8^itpqMB!2+5{Mj?qQ1r zC+94IO`(KA35j>riqOAq-^HFj^(p6M|KfdThb{XVydd3dPTUB~!9yag!NtoNlSDd} z<|VAA2*E$B@czUty{txyA!X8Y(K#Y^P{*npRrEb=~_bku^V9TRF_ux{9?1sQ`FC;`C(zY_xKk6VlHQCta#tuB^LiT6l-F>;F~;d z3GwvfIb`IlL%(ukLz8gEC;p_1bm4Baq+L^H61dP_(<`g>2$p%V%rFe*Ff>h1`|2+S z2k4D6Op>}8qC?EqL~HrJ{+KDYL;Vc4Mf!RVouz)1M5Z_yANy_y#;d+YvDDj zdzhN;=%h&{gCZ8Yu1PLWf35i6I>GaE$!H^!3UGnKmQQL;%r6c6T<7L61=Yg5)Run2 zfWubVv3{iSZGA3Cx=BkswcBpY1=fPb_;Ezn+M;AnNlY`x7$sm8vn5%K<`F#Tmb;K8 zO{Yu2EGb1FX4SywB%Vy~sKyi0*Jr3U8lbNy`zIkpOK!5&_|V<$3YEdT=}%QXsQl9GJf0F?w-qd$P1c| z<4DwIE*6!~_!psbRw@6_7|yQ(h_UyYSs_cCM~CeVW_iaNm$%P=y_B2o>N+JN$L;N-G*-%z%OeKHVw%V!>Oy~5gViyufB*TE}2Hk?+0*XwdA}rj9A!n zKDDe(VON8{lS3p)X`~^gF|BMrD^c%bRB>}OyJNMBzi+iD-*4q+<1ge^aM6;(@LP4e z*z(!~&h6y2^fUbL1#3Q=sK!g!)NOT`(CHy*dsW5IM?sswe+3W-Q!NxXaNUcqx)oCM zQunj$p#qgMSNQDIda7SaUUQr-)ob=1U(YG*%}amW;0;5EY739c&O@skk426Sg;v8X zv!oDIp8dBt2;9=KBvR06pWxpkC3uJJv2LWYi${IfBWzAnb4hGez}k6958EVbejXM1 zo`2&!qe(`ME~*W0lcupL9K!-3$Cb8!zDmN~g$)e#z{`C;L<{@zLFM;p#Ds@@xkeF( z{r*po^elmrtz32HR?D<~?`d{_?x}>#cmBGh^Y;FA&gxfl1z^E0iC0P#+Jv`$ZKkd2 zAE=E{%qh8>OLtO61#^B_;9Zj^P(6{A*$r%=FP6x*dG&hP=N^9<8s>&`fA^7JLq0X1 zg*blnu?Iq}6HAFX7<~NOBxqtwt^m7>5ucQC!8YeQN7`WIsg_sO>nmW6((L<$KRj&C z-ESj&rm@c2M8C3H{V|z3-DhS1`ZXn)aP@dpCcE(%9nKm{MI0!^_ndGtEX+Vsh{mL| z175!{nX?Z5rA}D%`^9AMkJHhnEb&zJWlxG8MVh)BPnpooz1Li0hv(~JbMlF34(6}g z5xQzRen(66HXV!Z3xkDrgE|}^yIqMaMLfBp39+ayUDFT~UQ;@6T4h)b)5^%!7$&AA ze%||ZhuRgF@5la|oEdgQ{Azj|jEil9!`x^FUG%J;2!P(ksrlD(-jrC#;k%A!{^j^d z$l0#`z3EWj@;FShxYCzSgb>`__A5Z|<&B>23UW5DoJ2=s&gCXXwOS2QC9i;Xd7e))+U9n5}gy)*X~+0m*%GqqH6 zd-e+WT9U+&Fj)lbYc50{`Fds<2dk%@*e=kE_SBpE*Ny!!u);j!eDVP;quEkz{5>9R zp%>OUtI$)=eTL4}g!rX}iy2#Q|DfGY1j(A`{7dt=h-a_?;>fs{r;yQO3Hp|S2(C8a zE5LYF|LcdUKvwHGCYa8GDuDaJpCz@B6-uq-O7f_~@GX@^Y>7O5)2d=(#9X?*y8!N; zdsR-XbrPKIv<4cGVyvl2*9QdJBF`t>4o;8G?bu!NqkbNOtKwx)PmbV^y2vEa{bSes z)kDHE@>dXaA?^d(Fa1V-TdepRUuSm$NJ)BJ_$55*$T6BI#QY8(V4m~uVKHv*QP*jP z;YoClt|3GYi(V+JmlEkz)tn|SJ>xB0W+pJkrJvF%Rm!2d0%nclD_p(&L{o*~6c;w> zJa=_#QtzU0Y#8z+??#2BZ(e#0lUK)4!oRbd$6BVuPCLH}#+jO#f*cQD=otE23(1Aa zKM&AE2_E#Sy4G>)d*YMFqPVK32%eZMI5s+uR&WvbiUu!x!{E?Y`tjsca7MxLgKfpz z(>*Z)DVFdBbvcyJ)@m4R&7TGSrAF6^&FqXkrVUvyzTHi6VJnn)&>3DIANFEjHu*)H z@NPs?mf{@_s|c^bAI`atV-@F%reW)C*IMRB_tG#WZ+L(0#tefpDgUI>cbD8-?_EqIe97hVY6?B z=Xk`nbKd`0c07Syu9^`27<>8(_%?`!^ecHF7ms8Sl0##9_o~wf69+4dX8K}1cc{;- zpZ@viZjqZn(-f*ZAT8d5;YE|9*lt8xii@7#Q_(Ogyvy=|gvfl!e!q<>k_U49!3#NA zR^3=BeC2`eQg{VDp@K1=TD+~&KHav{CzEiD@0)D0p7LCc)JsPkTCTNhiuhasVwYVw zi;Wai1XlouHBmf&o5F*4%HJryzIuFD3O{8g^RSh@FkkNxz1`~vUtsY^^e6s$u#3nu zIj5`}t3l}d{qao^;x$<>HY`=)U0V}QnDUgAm+#oy2R_SLlcp%C2K7Rnm+eog{A>MF ztaNO{y*+)cS4tJ_7;K;H;Z{0%iXk##tH<)lyc0669{RV_<-5)Bv4E96Ny?vx&?C~K z5SRhg03lzR=O+a#qsTq8Y*b(?knWy-U`gI`o)@!Zl7AThuM{a$py?m@H9EmFL@_e~^4d2%?4oKJ_h} zBH>ML2pgWS*E6-e$F-RQ3ZyStw(rSFQdce%d3%lc=7bLOS-Ui7O>VgJBumlpuPllu zY#{Xoh^V7)L`C7k)g_kR_KS&#PJ{Y-1r)6B6L{_THR;tnj2>Canixp75{<~9En*JfRcEseciPZB zc5BmK0(U^8GL0v-G=$!_<{52XGuYlc#UEc!O{pCT?&gA@l{HGimWfo9k}uyE@V)q& z(fl;fO86FyF_Ns)PiXzF6mp`eA*I@u6sJC{DPuddQ+dpD%s5)`E^Mf zXAgAx*;kXzDqP*(8*zqf&=lBFKB&=!YS}q8nm1YZytkkfaXTF{WAMbOj;4o0v0pQ$ zR0W?ju87yW9A)Xcms|`L$thUS@8s>EA3krCwR7a)4%y`BG4JePO@;-XuesQCKTNm- zAd>~2JT`yVu<}J>FeXbiR1Y3hk$D>4JhSbTHy96Z0r-K1^^;NhJo-uN39-$*Z;brC zyb&-hhFr583|K&>wkz_U;@uF&pw|)p=mu_u&==C>LCq$$kKlp+^<`)hM0U)pcI4Db zC+vggHtyu=%9i2kl5{_LIE{2ASFrm$ZaZ9V*$I-{KUv8{F@j%!NgXT(vRL~mdPJ$* zyz}WC$Q%8<=A8D6G`!D=Od0YMmUgzjmpz~O<5p>es4QOi6+p9RRl@zy5nI2W9#Cp`5o>5m2#Tcu@BNc~H>H4_CJ_Si>PPeS}mJP&h@!&wXgOu_JMl3o*#2#M(RzKYGYCW3*@uoIwlAK9Ab-oBu z(0}MhUh;h)AduIy!7JIQBF?~rWB6pGdeDsL5w*W7w_PT`YrI9=?NhUGqQ&c#mAmsa zetqubMo9-;qT`DMKVf%ddzL-V)JyeCxt%MZu7%3VW<51|ge~5WKE5SbyXvK#ZGyf_ z^;g<7Y8lwp*}ykD8JDog%NI=Hft+Zf&-c))sQr}>hE`FWczDhR6))rGiS!scaV=)= zu`#grBRB=OXKGU+78=d2P`i_cHAf(x$z+VJCNgoUc1(VqN;he>Z@ z!xdr6P-ekqK*LzQMDCT?L2W|3i|1RPg=|@J+jYK%9(75E5I+(del*-YsV`q>l@s!a zb*C9_$+DgLEH9(uh0{L|`&=dYK>&XvKWO1cgwXqLQ^$*k4T9lJ%1wHX7FFb22kutc<^C5ayyk zuESH;Sw&v{S|>Yoc{T8!gsCP}u#AgB`U5ON{6;!x=%gLI&qU9cVv*Ux%En;`=c%d6VfW@#9TED4Z&eiBJ$@KT>KUQ^Fhi zqw@i; z^3Zz;bTN$Sh%x%nt;>%e4AB-kbtdM?nB5Pv1Vsg?#r8x{tLh3L4Z7JbEe1u^r{tX= z{axDb=oAM=HB>HHo{;n#8xOfcZH5=H+57BNPNtG3%-2WfY4B3O66C?GZ8e13wq4H&=UAiH-VQZxj^0!R6Fq>G9~G zvYMRvyvb)MZK!_JQz_%o;x6$?0y1EFcT2EUuRenDbCPdP95sKPVyppeJeFXae3Ms} zqm>;&7K~duTy!qejB#yRk%_&7fgmB*p_iatCcpzqysg$vn3#_434=!Gam!~t_8JUL z#|!1b5I5R8W(brQEZh{i6q7Y`D{KH;tdZwDj9TDoZ9iw_nAZyCl;c)d%c{j&03wv^ zY(w=2W>5*yTYTFbR%(25%MqkuwGj1h9;31TPTW2p(;F*UkMM2W|SZARR!&$BHi zqjet3iv@$;NW>^Fu*!=M-zcPD(C5wz5hK4L=Y_zO7=Ms*zh22112NGWhreve-NGoe zC3u9Ydg34B^u65DM)m#SYm9HHIx(XIR93m|ddVk+Zd8q9U%BUWen!g)t~U4cLNuqQ zWpjhbLR<3M2fYF<8YWWFS9_qw=n7MzIc9aPHD6yD!HV4NfjHe_mEw;7@==9lkr@BZ5uv<#CGTHk&BcLMP2gkAC`LEZ)%X|7_WA zC_V=F$SixpmL0U|leOcG`bK7GK9lX#vVGKQL&Q%GHVanT^UjYq+aW+1$+%Y&%Tg4~fTbP#?WR$O; z>!q8Uw>-U*L~*~NvWojQA|Yn4vVD3PVY zt3TyaNbS5X%g3OQpY!L?P*la4cR<#c29{8XQ-ayX2vC_I`yGZ?CfvzBcqh_rF|$%8zB%!F?!Ogv zp5G(-Z0FQ_n~eXnO`g>4`VGb;7l*!=u&n@strVQw8{}Sysm7g2orB(I!W{lfA1^ie z3cs1xGN`p;DC^S6N~)BgpK5v(7H?>PIg(#exOj!UEceqKEGsc+Lkk_h{3fyg!%s79 zEF^6v!Z-JMRQaj8$*I;$qdU<;&w5v&OwBsGFXDt2QwipxHb)Xgxwxuy($q{I8ELJ& zE2f|qjp?V~`+**@7*XhmOn9IA{xk;hXfiW;i&+E<*sU;F*w?#P*-w_WVJG7fj9 zAUU4(eY~?5Mn6wUgL$QdE58T!Ca20DYlG)cu(zL*^OvsA!8xc?=Jp5(oG(Ybaesa@ z%@W#wG;&M9)^j-7dB(%5myYxO2qMeeNZI1mTd|Y=A-&Qt9K;qfjL$6 zL^LBl%z3#`_B-mOxY*pN4podkrg#{QQiL;*RXYQw@zIPsa}>!6s3 za%JhO80vaOl9(R>Tn3I2E;d#P4`ZB|=@h8~xqotp-L^+SsMm-5%LvbZ(Z&ke$kVQ4 zE$Q(gI3l?R(yPI*^JgC8Jk}GisU*rHcLqo>Jz=NXd8^<#qV?m%;){2Z&CZcepB7~LON-QC?e+<7=05mpbmz;m(>Ik_KlbF+gQ>_|@s7gG;*2PFO979Lq3 zVc_Xa7aK(n&(42?&@BS(X8*mw!+W*s^Ydhwk9X=sGE(=RD zPIgO9J_~kUb3q<vOHKhUUQTmUZaSzrOjynl0XGHb!3J(>W%1C~$-;^b zdYvy}DOCkAI&KcmKbNZZrY@GCt{B}@8wXd9KT=H_xP^v`>2>C~`1!#zph7%Cyh1_( z0s?}6G_))bNN~MeoBDl1{kQYNG6)M(7e|DqqochT-M~hDH?KLDAiFug zsVO@zFOMm^nWc~ryE%^_%-meSjF;Qe^zZ&iM@tuXQ-p<-6*%9Zr{HY=K57qT`ke*l zzxCX$Ev`cZ&)&0h3bJ$aY5slo{;wm~bPqxQA6`E)e}(e!e@6NH-aj6%ztzEK_8R_c z3lN9?xBNE)|INUEGw|OG{5J#t&A|WvGVt#Y5f%>Mn~pp95#eectwcda##mKdMNZ+V zEJzsw={_IqVQ?e{Ncw_1xFFQ!rJ*2u1&Xx{vVJH*=F>d@-4up&l2TQD`WMsWKm9%& z`HPJ-#C~n-KWY4LWccRbhXs(q0tIy>VNM7a5SxIQ-`&OO8oviIDfq$$vZNpdAZ9~= z4uW{>T5k3izGhUCTK&eqIaH(wO?4SCwrjQ})aoDD>>n6rjevtXyr2$)IotuXkEZh% zHowL`*BEZ^3i|fDTyu!UYcgRKK7K?3UF zed+&2|2x0?tAf4Ez+N^04D9g;a0K9h>F@r)^&EgYVEK1$k(NByoIWsgJZX^7Hgk2g z536E$%NWuCfbbEH^?Ycm&f1!i_&@nO4!GZ-+wlJ}=aImqlut7Q( z{!JWQJX~z-n}j#<@CgVA32<%_5fc#*gP7nq#SH9t-3tQ)ivR~32bBIFmaDHI#SBdc z;*1Uf*;Rj2%&5VDu>Qd>11~}17056{$HoDfT6h0uX+gjnf0aKBw5vaKCn9u^mkK%B z0dKZ_cD5gWC?uS>`e3tuE$;6Q|D%O0`04NY@vlE1sds#1Ww53Z$RZ>I`rt{t4 zb{+wr!*xrGAE8uEVcIjkSSs{lsAAD`6*rr0RFeBb{J~Q0aYK>>L6X4G&Zc*7y4M;* z`z3ADR|(cp)=W3M-gY7Hm;>Xx+N-1wUMX}Sq7wt?g7|3JXmDA9~NX9oc^BiS=Vd%;sf)YZ=;ulP| zthDa*Hc*Ml&m9^0<-{*7wu>aSQ-42TP3oYraxo0(QEaX`}6NRkp4GS-fOE9iDTwVbJ-KkS*`5&C8(Yj{#q7}v1 z{ru&N>UMvT8+>v`s`c!v5Tw-n%7$eIKlH1vJ#6*AHAr1*{awzvHPFv}_2;a>h={pc zyW>M6&xR(2pQmaEq6GQ(_uY2=EF(uF8kW{Qe@&x?m&@#^x@3RQrWGgEr!bwhf2vPS zIvU^cN$Ej3#I|@&SA@^;D_Ujc^sgRR`O!qL$FLq+Xb53Zdrdg9EV&eFT|5XHO=8x& z3GAV$&$p|B?PM0UVILuH4s zQEzZkV=g@FRboyM;ddie?`XI_S3g;`+CTM`nhePhvCJo{NfR|i<((=CdsOu{jOxBx z=NGS0MaRR5^Yb2`^A9>OM7VvG9}WI)b`jEXdTVWYOgCz0J!#)&y2f@USx*-n=n3DD zAVgb+W5<05EB}oM$JCK}Sx!N6nTA`jg#RPArIl4ZQ|6U6t{@qn0qsg}9-k5YRiBb( zqR$ljYf1YJV~%~l$c|lO`P*H(33HZD`L=%cy=Gu0<9i)ASuj=+ysKCXlN5AQZ8XkD zjn?&QPyIOF3Vs)Eap&_bw=@Cx6_6u#lK0JK`egpRa+F7DD`J*eq{NsTf)nr_6`6(8 zfHfY9N_zUM+>vY0lc#fXC9UqI+`fMF7rSaJ_yoIfYmAN^XlzJxWLXkT4Q#+$9%=BlYE< zDr`MvPt|-7_Zse(>a1NK(o8 zW=a*iS$hFzXwVR}nJ9&Ym^P&!_N-4pXxFQ%ICrkkmE*Ij!4Y-1%iIX-;_0lFsR3~V z)n^djX!AICH2XDyMD{29)xn)LU-ro8HgW;`yWqv25puzdF2Z~N?iVMKca{q!O+C0UuJO~CJDG6r<6v=Dg0R@@$a8+-&CS8V zEQAMsy%l7v;4n3>hfc%*Av8Z}`C2+HWVxJo2erL5Rqr}?FnVg*sC6U%S9_fpRp|v2 zWlG|^#7SgBaFT4k&&C;w^7exXTqAceWz#2Yw;sR4Rj1IU(BFST1YKm{M3?XJ+1@$I zIThMX??&!!rfCyG!BapMSi`7QWzU1RsA7||^9f2?mSs==pZ;u>@C={LyT2_eQHLNG z3)V;P^aC$&)p)h23du54=@$%_tCikl9$@C;e!L-Jg=%{7`Lez=V#F>|fvO+wRqc7R zePeSp*mO|Qd0nL2XzXyOY1A~&+2~8xvcCAqga8=7L-_qWUy@-JQ0NjF>GvnvEJ?Xf zJ?{2aoy^|kGuj`UW;Eq|Ht@FkBzI}mBysL(S;o5f@pgA7)rG>o)ps4)(X_zx)TYN?=b11AuY8Y#5Kp@vg@HRnYJK`jtw}!fA2VFW0Bp{$Buw|{ zZrrXH6=})z8I>{H^tGu+kU%Lrm`MrICw^^(%6w2bh(5mP#&2rXS<_HH6IozK0R@QKa&*Q9L1 z!jkVxr*vIk;UF=ywM7!++w@k+T|H;CdAJz>Y-j+hFg^ql0BwF#LYMu)*;#_Wh)UST zs88M31o+rkNt#YnQyKo`(xS@EzHCbO;MMz_^(T74jtVq|<^z26#47+r049(fYLwpt z34nyk5VTd###I}>X`R{Ko?{+`a>+`M(-HO6RD}1SD67`B?BHG~Oz%Ql+x;Ofgi8Pg8aC$(;QlS}U6@y?bDW}LV_et7HB$i= z*Y+CY(VAFXd3jHHAroa>?dO=p)^?r3<)w&-1Lm>%y=PI;Q&kC1l1ilmAW%{w6I^t8 zUg@nT>NVI%yBgdF0cJ9!R=JLq6>pSUq<-Yh_qpl~4tY*gyss`?&-D56sOK|FTv_Gx z<4IwuSENKYFes$DAf{a!Qd&U>$wa+Gq$)&`jFV>Ak)J@ZRb#F%PN%{yC3~4%;C`*c zx^bTlikdxSxUQ2q-@1C4X_?3bk2C1TLssEl;t}f?(i(U=QFO|IvTb&;G3t~BXUT)V zvi6GeCM$DCQ$puCSWbr?r0-iS%W7vACUq+cElL6y!9WC~g0|vweltmml7Sxp&wHs9 zEVjd%Jmva*HdmvBjj2T)_rBHw$?llGs9|dC1nVKH$(*NRb)`mTc#zkCbVPJExoKW@ zEHj;rErB~k+1h|2H^ay*gS8Lt*2Wi(NFvvLzrcT_DF1Zzh-}mH4r`UOmkdmcGMM!y zdtIiD6%&yu2Jmfis?(=|`O>%Mhl3MCtop9VgV(dEA*-lnX5}x;y(I6`2VH9ll%tV^ z2k+}Q%PUEYbxQ1RpHJoclE!Wf_EDC%rxrG-xF)gpGpU+lGT8})AX1+^*v*p1MKCNE zrN?Djq&EDR61FO268bX?%)vCJ zR7nLsVZnrsrwTmU-(1>$P^z3fZOEV+lUi1ddVDt#e5cDPzVKP9R5cBz&`$C+U;7N6 zddHfOU1n9Nd*HyvuMHENl}jiYSipQno1!ngtUyy1C5fl{NJ2s-S=8%`x0BZ(nlRP) zLXOO$x)+51ob^!Ae|}OdQ&`F*pUInxA{qQaby%;d_>l3nVTe2X9c4=Na}+T zJU+_4PhSDOC;b91Y+wV6{&FZ3DJuN-}U9AOfE@MU<+pNCDj+s z^9Bb$<)LnBS+7Ota!!)c@S9pI)-Y61snGCepYfP<96U}eCD8`ajHMCAweC*shpK(p zm=kw+_#GvTjn0I+9Ej2-@m4g}ELqD?Q;AjzvR|zf2m2jUP&zrwDE|Fn$8L2b=Uto{ zj`yA^PYsCB@HmO;>rP&L`z9v1A>0d%uaumtCJ`Mwb~$7$CJ}>@0bi*|eG0rvz7uxy zH^w!EHkJ)1!A3=lO7(g_IkYO#*=68;WUe!8zwe5W3TAl5WU(+CTYp4&5RIO#Y!TP` zGfenVSZ`INis5O=b|zZMoE!ylFvF-D+sL z3p<;9^KeUx=!P1m?1{H0^4+&O<}8y>?$57CdP&uqwd*z`>rka zZrwtYqOwto!*1$Uf8kGdP96JqmI@H`$lMEMG8Y-#m%y*5uDu20iz%@}f- z=8ix4A_<9#?(B{>ST$1Ko$+<8h1av{tfw4&DHc0SUh)ezcfW1OEcKF!r}Ukbmw3(4 zgIt59E8t0+-SqN7*4lEbGkTKdO#Wgczcv*KrF{n5h8@$0@+(d>T)<2gN4V>@#uHMA zbP&MVg2z)XoM*QGt!!1N^Kf5qIBve(S-G`~9bU-Sm-SGXx2o}Ow!TN1f937!D5+o~ zUEnKVdh>P)yJj|%j&w6biaKmdkz{zkpe4e!C{&z}Zw18@zDX@KRs{WQD^kMBmDKyL z(9fk@_ioo0r&Y17{o4=|Y(XN7V4_m>OtnF{bWi}7Q~)P|MyX~}Y@d1g>(0uUtPq`& zDRm?=VLWc9h2J=p>9mSQOvk|$l_Od^eiCF_-e)&d0gq|*i?}p>VO=OHYLk zB`E+3w7?g55Dd3O&Lwg&%OBcBIG@C|E`~?2)yDd4fAkvP{klKoR=;-h$ahz#A_B>7LXl-X; z%OGIIjVeni_q?56&?@sliOXz+*`p?9vm?l?GkJN`E7%=;fgFpkQ8kmMmbS&ZYZ+l* zGDiPuXEl0+t16yjTy&GHZCKBU#wcjQSa_j61#d*LN=zboVF*PFLn`B%2>3pV?#$Q3{SE5#qNa9TC z^E1)Q<%5&uU&5xg2R>(e-s`i9{SvuMDD9+$uJP05rj(kp7Ok__>!Ahe6?qZD%x~y4 z=w?=L^U*gtxW8q(=S=+Oezw%yw(YLl-fa4&fBNz#eg6@gnsNtq?$PRT!vmuP)JNCe z=+>Mkq+MeM<8{IO-JMTEIXG%6XepJed_K#Lu#ppSqfUo8T;8=&qBLg^rz=N8-FZSk zB+&`T3Boi`r}p9;mp%s#@mqWRKbD@&SQ~8F>AY&Vv%oKY5R&BU`ex*(utCu~H@qxG z%d!f*nmjLgi{H6dtTJ~x z+O1AxrGtf!;Y9O>POb2f)idl#KB4%Vuj^h>TGtgeBZQ^xKBZ$k@?;eH)a_j?WAmXK z^?y!$U;HSALMc|<-Q8V_ySux)J5+Ej?oiw%0fM`GaZ=nZxNHCU{+`Tx*_qwD zcQTvoWOL8G=X~UX%pjB$B6xH6$sfy|qgrO#q@T}lFi7EC?*`Ny&~{>b`I0|dvnLuj zdTU$%McV?wZD&Mru-!;`?dycZI(ZmUqNuHIr3Z^Lj^|U((66l2j~Ok09(1yb$B^ah zv4n3+{h2y91e*_1w(jKvMV(id+eoG`KFH`3fCMZ=gLNNfmO|pjzOnbh6dk(r)QC?= zt~)W4%Vu*`K*&xuJ?)7O`zN=9tF^B!Nyu^~8P&23*0mmwOD5JAEOCr(|FE)=Mj2$# zyYLCDe#xHb17#f-29pWasF|T~2pHW(*IFRZcPx{K5vOz73nYhI(9|~6n5bn>)+Uyv zFv1~H6>bO(ILn?`P+*%;Iwhnn*6fE}dW9X%TRxjuuRudOJf0%-8n6bmr+(_#HEEpg zAQ=k29=XP$vedl&QCB(mYIIz`1}m`vEOJhsM}QRnM?9MMQogN7~p}XaDC98_Q zZ?z-if?~aMWILu#>N~cVglvEBdHD#&O#^V4@}!Uuol|Lftd8L`cxmsT&rp?#$)$#p z^-RtF@m_nmA~DeVyT$R~l(~!I_(;^j^yU0b{tWdy-)c%Q>vX3`N3bgm)pE{^i%HKL zUZmowz<%swyUp4&4*dy_1C+j}^892c7)9CUIN2lAp;RNZS<+pQ{7~naJ@~OHAt3(p z^gy>KePY7o{pOj8^qqbwK*L<{KixjH4<80f@b3R7TIul4*i4C9lBjzKCrWSCzDMeShXc`Wo^vwIJ!{H zcGdfq9-l`xy*$MhDx#UtwY+}@f5#t-6ocb%Q({Dd4vQnt@NNP!9SaopzU~go9U>b! z3%(c5^K&S?e|$zh54unZ6i^d3CWQVkT}4RiMWdZ(OHD zgReG8GNz7aMLI!=y7`WJ^@{S^PXVCG$o8DG)Z1K$@))wV;)I&vhBO`f(GHp5k4Msa z_7Kn2rXbP{#?H5oi^{Y>`lGI@+rQhV7Q}02J=|< z88(GTmcP%3L3fueM#_#DS2FgUN35DPH>u(bNZBe4{WtT4FdBxo~NSrm?h&6r_^ok2A9Hp(yY zU-9ZI3@i!+T5Sq5XS1`xp*Ld8kNr&yt+1iP!^W{AU{mJneSwx4_|aiLe1sMj5D=h; zk5CmgnE%e;5nwPdvBW>2W8;uh;8JpMa&hBPvGYjqQPa?U<&{*EhSneup(Vf%@UVB* zVAlbRe=tlqje$B8e^r(~&-qj-90zJ=5xv%m0*JHPR0RIP?A})u+`U|ID=ayFPl%tm zk;$o_svC`Z3VjV()buBe9^2aXxEM}c$KU}?Lz+q=n+lZE!nD(XKC${3WTT4#?@~3} z?}|lIw)Wf_oT7g!OsPFM&7p)NIjTsNtkXK1*1LAcCc%3Q@NN`a3;}XLjq-M$l~Y~r zpeeddrL%H%QheqlNNIL_0Fx*GG)(Pt_uV=8~ME9btZi-jg)73FezHW$4A6Ss9 zwH&TKe+*=Ln`4^-O{GmqP&m@&H1^4n(fap;)+8l84loC=Oma03#8}o`V+Xql2i=-W zRS{%4$HGWjvdr(Id~J4g9^HM7<=aPc>zj(?aVZUWSc{!p7Ukj_06RMorJGOk&2!Y4 zFqWmB-4@E&^sn#Leq~Wnq6wJJFYN-}R?8{oY5Q{vD~pE@;wv|OZS_1eY>nXH!JpSf z?ue?Of?M0Qz4z2;Mk4U2O`nms#A?DN?c;Dlwi}T6nq#okMi*-;8Dc+xw1}(u1wldF zg$Z1JL(YXqQ*Ss)_RjKr%)=2ml|Sh}-$rE`7DFq3&4$sxvK&=McKX)orLZWK5Bw<#LpKef9;@tqZl;TJ?{!*)w2e=zaUBWu8=2hkLOQc{26N z5SsNj@jM_@IixEKij_^Mymd-&1ZL6#M{=S^DW;uUStyY|myjo~kw~YeNv3%UaEl?E zTIn>U$;-!_9vA&41?eX5z^~ew7|oJe15%c|bh9_Tg=}*v-FBZR+7fLv>TlQ?e!yZM z@K$44ZdDQdL@8baff;D#8RUMA}ue;){VFQ<>dKSX#zbd_D1nWNtU3o*s zHt+Wybjq=u>1biNK3@koImB{L5F~3GfDLxJHupa4XV~h;(eed(=efpasHV*OZr4(uB`;$`Nt-rAHUlk{!b?fR4;8S7| zIAtDf1H3Ep?ce*}yxC619(+fDqW@sNhp(V+7biwW(TA1h^oo34HeJ=yO~1&WEOCrE|3nX=2M<|!F^PEVBY zQ0_Ku*_(hEUFhsm61Ef=UN%LF*&Wl_SxuX_O~jeLWluW={u8?ZdYDs8kIBpr&*M_W zGGiI?aJ6x@qIR>93>I|y5Hiu$6^>aNnyl<eJQKr5ZXwew^m1K9ySo%d1@F?qu*vrNei!@3!;qC{D|42R;403X` zyY|uA`?D)*nA9Wj!OYi6N+Phn3a)>#tT9yV{8hyfIX0a` zGI9}gPtrBp!|QJGxmO88d9d3>SsG*Cay^$B6|z0D#H*#ZXI79Q^$#W?7@h&Wi>u@oK40Ks+P`_b z^Jm87P+fVjsnnI4F9D&2Hll8b)@tXXr%)91Yx=YvsXE2V)eK(u6JlPB`K!kMM~*q| z_#qZvxu+*S2`RyfefCLlS?^KzE2N`hneD(({OBic-N!M}H`gQ9I*AL+x^Z#3wjVek z>f~*S^BwCwO@+@bA2bhCe-UTka5gs#ejWU*N$-yFm&-ysp4^k-sjYJCu$`4oEIi4| zoh}0MciaYCzijNiP^C{dDp{IpRJKRSd~#C#D#{bPq-bK(ng%yE=;*jX<8({kF_yra ziyr<2*AI&}!5i^m5M6bm2uh@$c;e{+J)f=>glLfjp4bgoUP%<9XG3@mScx|Tr9gw# z1-2=e1mtG7sF}y9F;7zY*PoSdY(_7592_UNb_~@!xoXX$mvQH?%)vuY!JBty?{m|# zWLes_g!xji$Zb>%t}^9FS>BiL@>qi?R%+V)Ig+|A&NS&FX3}-oWc#xPJJhdvXUXs^ zQ*)HZJvoeC)v;>SlO=oOKeyzyIRsvLzW&{XS2RvabHypJc_i+~2xZ57%mSb}bRhb4 zf6gLqwVzt-E44)z9hN0+#QHr{xbr9B>*L2}mUMn0Hsc+nG4 zO7@A6r4%$^cZscSMuKQU^X=pB&>We6FcB#i=eGNm!`B>*ZM?e9C3C2-%v(T18a&3J z-)d@>-=)z6Z_36#BT0B9a&QrXhygl-)C)2(;=%?D$lhI6pnBkrvAbiiz<6I?b~*+b z(VtGQDZ90a8Zc1LBIDz_Rvy)lQnDsISV_;<5FI|@k!4-zKukG8()@*{hTKPj)_LF% zUImy!Ej(uJFVz=A;%)3JZk?Qe`zI7o96BKXB-DQ1z8Uh~X=qPv9Q{LnAEBoo{bY>J z(j5jizXKPA@yUT;`$J_y_e_t=J>Q-P>9!eNuV%wsvjC6gERa$%ks#^do?0D#ERq_6 zNQNmP*T0|KGN5d19Q72MUQMgD+u9PqPU%Ot|Bz*@3cdgQBFOhD zT#(We?xS_<@CF|TIc*6)nnP)qOAS2-pf=4?c*>2R}b*+n`|E|#V8#o9Wvy+ zEl!7Z?Hi-+z(PN+@JI4uqR9Oe)Vrnq+Ko6DXu(;~9t_yU3{%~?OBy~)OdUdkB{$kpV!khp0Ma+to)hjXuu9Z2&SSTl|edajVE5}&dnsJ z@R7ntj}U8Aa3Jgq5)y21sa)4U{bD=c2iu1){#CZn$JqJetY_Zz^ev%X8ULuW9?OaQ zX;{|Zgk{n2@k%VX{i5~`2Y+CxK#t~{60DE`vnCRtux-?S?jH>Hu)CuIAxz~k6Q06R zTH4PFz{!R+5#9~#s~Ik5|oFy$rllAyFlKb&yEo>+C%?Oq+W0OyK}@7bSL5>YI3P@P4E(qu!cbL<#6PU5nO zUhRn3;fMbEsRa9@r)P6uEGAP5oUisT6_b63*EiJ>5JxpP()+MzHnS}cM!ZtqTwcDt zI6Z2Jk-y43q5TFU!$@2wryL@{ZY9t=#Axs^Wr6{#0uw>s*JrMqu+?Dskiny7V!5Cf zx04h#OhpyZX*cLod!P>RT~~xVg#-=4O{I4LP^id#WaAD%gL6ALc%;E#VKD44 z@siv!;F$iTBjDNB`_}8$wNAv{G1O)6k3KsHcFG!Y%DkrT_uvhkDPGcAEdoQrUh<~p z2O}N$1Yj?NHIf|^R)VpZu$iEoW2)ZL$Lyq@Q0utc9D(8Xgh9l$6Mo6&+j1{>@wSmS zRw;q$R)%k}YKlS~tsF5oYq+8t>!__CtMg}WStm?}3SUi{-W^E5W0By^h6CXX{42u} z7TLFwfNE*$7;ST-_vOc;9*+4+PT6Q-9gud?%&0)j87+!sP5944`Lx zq8b-f+mR-|aXQ$ACBnL7O>bYPac)}=BrDR*pc^8a`XwODxbLN%>oqXRuY8@!k=lx1 z(I&wzU2h~|NzQtxbTjY9v98^*tlhVK_2_unSm^m54Dc;52G{iIoLxztBMUd3tm ztC{4iwwAi~2zD!%*>|A$OM9a$2^DNB>3YAOWN{%d2awBY_|)*a;ONot_n5^BB2V7( z9mzU<<2@nvNalRgdTHZ@7PPc#ua2S4r-JHS+x)&B*#1EK;=T`9O4VMI9^;_0@I#Pr zjxV$DZ*D~+39^5@yuaVwVQ}$0?#)6>l>G-2=V{y~*R5*IL@}`Ft1tIWuhu#)&O*!6 zB!OIaI)8n~ZKqR+@%Y88Eheo%{VB_oPQTti8z6h+UnFYjJncA=%U zY^tu|2DUO9v1EBw*;JV;egrL@>+?gC*=cniFN)`^EK~6^y0v1(t8F~JXH>)ql}}oh zFf2y*(s;u1SI_bDXb(F-AMR{61buh^P>(Z)M-yqiOpkI1dS1PXvHdQf95k=xZ2?r$ z7si|8d}1oE@~!?nx{|N6p3dvm9CiO_y&65e6B|!Lrwci_d{MlPjh7f(!SZ7eF+G83 z=$*(_P--4vrvOk8iTbWlMyYDpm1vRa0phSdMj}OP-Bn-K7ITuC8O%N=<1uUOauC3W zpi!vnX_J`o*zq<3gQQ26&xS{O6pv3d^>%@u8b{T2ZGta6AXVplmp5se!Ec})W6Y?Z zvu6`^VE3smJ3WQr%i>d$m14||_I?X_V)86UQ)_9B%YB3Jk7_EcIDPp8uTX1Kt3!j{KH zeKk%8+jB~Pv88LKGvc9WM!B!a#ho>ZTWdBix@DhtK1-OT?!ps-uAcT1UbKe6l12aQ zvWM{_Sa0;U%}0%97%H%arJw1*(t|cMK;7~~O%DEWZ)HUeGP}#0ezX{=zSa`9 zUQQmVWY)I@-^+Vm-hWOs0RDqPop3E30o-vi5r6QIrJ`aQBmlKP3yuRz(`CTmxW>rT zgK|7f+9aOycGZ?=yXrgTR=Lf-xyGSESe_=r+p7EdwM%9{`g~?iO~?rVnZR5KCCKs-7$%CM+QqOwoYD5pzv-1gN5BXkf(sxj{MyS_dl4n z>ZdX?qV%OnPg+`w7ol+$nzCL%taW!U@TJJk{k!rF>5N=!Lzp|NKb_ZYvQX5VG+CA< zzZ(D0?KYZpVu~(Ro*q$bLWK`oDtu$r4<|?!2KV1@ezs*8&)7alU7F|Tr<;VXOc#(< z6M}B~8Peuf5LsG=pNXa`3ob#zI+6F!*pR=k0bC`&3je`)>WGyNp6OL<5=gB%XOC_Y zdx|^c=s*&DiLfKjM&5dYo0p9PpMy2a3wa)RME0r@1j4F^D=Xue`M=cT#()wDsv&0{hn9G!0%QsEADk%rcpSD01aT^ zC&Mp9rh+f^4}#C6W=T}q$bm|g!9)qVHiI)LW2R!ZVG;vr%^2~E+BXyH9x3{;;s*p+YlD4ql zwzM;`t}f@>rGKNY^^gvV8Sdt-p_?(CoL)n1cX1;U}o|fKzg< z_1uDP(`|=N1}hc#BKuW6OTwO{;65PSpT^TwUk4?NZ_x66I&n3*$M7==uIPg^?`dfo zepyTA^2HD+V{v)iYZpo3(4Brg;K5t@HiymEnC~1fQ^!Ih<%4E-uaJ2(@$>oKyrvH& zBZ~q^1jSFL?OOID3%6z^LsAIRQw!PsT>xKfr9umuT49Rm_k+}fO|ymXGloBG{LUhz zRXGI-L+RxHvR_Mu2ArN$VlDEM46btI9+x40UmBI^`MwtPWwn|z@b-v$PMWr`#**a| z!R69*L7m~lF8#?jNt!I=2=X<}kL4Z6)DukO zO?@w7H9&;+CPkV;M5PGI;n#LRkbCqDS==#x>sXi+wNo0f@Z&JCRCA-iAo7H)%%Sg_ z*Jk^1_*cBxgc;yk#6nDQgqNr0pA`c4zo-EeslV~A`pP|9IsEgrpvYsG?wlc^A z4T~X?K>G8?9AlxB(=^qOzjk)n>qaM9TdS$z8%Kb`!a}+d3sD?}$pT!XyH^AY>_r-F z5DT7D;ttmm$6^f49MXyDG3f{*VO)P&$a1BHjMrx>NPk5+D3XF(f2$bbiSnSxR(LAH4yehm+Ny>duBxmatp*~EOZV*ct*jDKOs(ye$_&K32Ao8c^d7x|~uJw1&6)lRhmskz@6V30z@e z`Jt@T2S#JvEbaCNc)_yLG~^QpNH>bN5S9q>gf)LpPPDPB8of>*g(`=+ zhWp-jtmEo0i^hyRvrpbC$)HjlDR{P%Z0thc14|oPRq3=D;-*i24Ia=%t zIqM)z9)rhrMMEvAcSWh}MuaFrU2(OQR!gg3$ybAhH|b|bXOXyMTq;W^$q^JqqL%#* z7o5dhypQUJ=Ki^0c)p=UzS;W>kC9z4x&S?KOU0w7sbThNKJk51QujcM7kw7R=TK=fT2h?-#f+D~IEPU^`y-nO<8& z_FreB5%n+3*e0Lq=rgvI&N=Gj{oMXFRN1YW>SG)I!KBbG$bP& zr}$N>fwCyxDr&;uE_!9NeAQU;RZ#4XDPyE#Pf#3z1d0)c#LTV$=jQ(QhSds@!}y;aNGwf zP%jQ>qnJGzrx7q_uyjCSyo2%D41A{O^_@S*$A+(d@OF$u2#5V*?9)+q^fdEiVlLX_ zR_TW3E-#P%!7P}T`^t`u6D(N`6Q>Wd^8jf;aHj2^>kdKQ^b$0Qd1!?xp}NT7j9Arg z^zA!ZT3KsG51x8ns)?Cro+JaqXYQ;m_tH;;VSumRRv~iVK2hc}f7jMV=U!gsjAt2i z8zKturEPzJf8;TLo_=-&e1#>qLolNG0z#r8(2?r*+-~7Mz&26MfIt(gkmhcGH_Tz6XADin#?2z7#$92 zepJK-QY!s0X?IDKW{DP0>Zr}jw^GTCtv zq@R=5kbg6BkgYBSd4j`e<-y= zKgx+lYDb>-a4-OK2BsNAYH3W;Xq+JLF$%;&4I@8IRAdg63gfuzTh!40l!MMe@DC;u z2mV(yK~b;XWh`bdtx`1Lra?|0&*n{YQ#ty4PMXr5D#Hl#j9y+C5IgQzU9|m7XL5W% zEQfiL6P?=@d4jh+`wyn>OoA}IMIb~#o<+M^R9t%^S#%G&;0c;z?D(WimWz>HqAA2? zH~hg=0juiDy>iUPpIKunJ#80pXe<23lD#OfxFFtE3azW8-Mq9Qb42*XBWiGyd7mVS zrH7&IXSr%O7_LVrAkyddo?Q732m6u9f9^DpANI1DvTlXkZI1!OPML&nvpw( zf&A)I0>#}KrGrtCa=NnB+S0N$76SoHpI;8_wy)6VL*Q?=q5poWdgL?5&I|O$T3~TQ z-x2GVvCpm_^Ap-vH|Jt7euz`DR#p@k+$wQQX_ETk6P>t;- z5P+f2!X9YGfZhBTgGm6ugG=qo8jJ#cfezU3aYKdwpqaQ-cX&A!T)C`T_l)WH)@on3pZVJn(fBF*Qi?n&Ei+{AHyTAXkH-FQXF^Ki z=l9=9=G|DLQN`VOqEVS+8tE@T^|wtZT8QO;?vMzuA3j3a)c+ST`2z+lIvgfB1v>|p z_}7n=oaz$hYVO!nT;Kl(5rUdcihWo}%~C4UWJn$7A=_bC)_n}Gt5x(IQQxh&TClcJ zh)W9sceJmK$Ca3*byZt+n8%GzmT4f0W}s!Cc=$o3z-42<-2OjDVPgIxufC7y;vX?e z8E`R@zyDdf_x07O@GZXP%#0pG&8Y;PwrduN#Yhw07@^GK3W;`(3f^S+E>Tt(!u&32ajOlfiY;ZXWR#bZ8*fr? zXFOlgf>^v8h!`8xoezaJt*oTltV*2+3r$5yIcYbNXs|}kYG1x^*f@*p-D+x~YN}Oe z2m&cCylt&0>&{1U2PrY+4Kx9S`nLtY&Kg=6!8jfBU~R58lyZx5<^WB*>ETr>gJ$FP zbpo3i(>aC;D;ydk>@m|F?Lu7yD?Z!ac9Qk96h?>^ub_bt3A=`TX5L75g__zcquLcn z_>SzF;IP6E7*TdpdKrqb4%Wv>-QkX@_SPq2jcg8OFU;=Crjcrn`^(&X>9(gGb#T@tp_>am zw+KPtim6?RiKb4qk%}p?kqkoGX#Se~lbfJcmpFAJ48Z}f8*=R8pR=P_4H1m8>N*;08`f5B5HGdQtuw-!x98O2M(f{OMkVjBGf{3l^F0MLR zzZO7jnpog=aX?Wah{JqA z=E1nlg=|N$h5VLQdqg&FTemT?LU^J6gKhB8%5YeDB1+{IZ2;lkrX-NsI1$i>Qxb&j zq&@t+mBL$FHX{LfD7{qE9(na!UjrYhd`=fVkKpSIv+x}`3V5cSkqiWb(Y>bXS}WXi zwXU8?TYSFOj9LPL5LXX*+*hq8Q8CHgBol?2nhsw4a4=kHsW7(nz4pja(51GuLm(p< zY#^)Yz>og2dpCTsUgBe%B^MLZLlIRCps3g?lv{drEWETPTnUM4k!%E>Z$QQ{sIRES zKL!zy6}hfLdlv3RM^-Y3|7QQ5 zn@Na?bu_7hBDEe2TZM3#&%zh_0qi3WdGKC&_k0hxdS7RgfcQvr3hX2h%oU}&O-*(V9D(`a~=jIlYmZKMk0AvTQel{^`W#pZSaSY*DEgO;9s5#}MN zi5=elHV%n25`&h5$=)n%jqFWAl++5SCE<1^QB*&_SkscdGrt{s4FP{KDs{*`QqBMh zG2j}3)Kk{>KjgQ{FWF5De8mDhpRp{dq{U-^o3_Uf^O^8JvJecF* zM2DDSq4XXfam#6hC=XC?cw}5k&5|Q`K$Jq|&{%m#wi=tIVMT!i;W+#(GCmlWCt5~g zNjbAtr#B`+_TZkx;#E^1gPUtAVi7VvN=`5L{H*90OAx&d&PU^Nk9FC9rRLjbhwQ?yk8d&8_ z(1aF5+KynZf1P9*F1l;!X)x2@I+3mO(a+GW8+Oe$eQ;)I$%k;+z} z>oh1P&B9*sEr$0e&Hzz{w-%}8_{tT*p775)uLCX(+gPD$>6Vs4eFp<}0}aMwX}wfn z)h__H3*+T%w1La{@pVg)K6APvP4bu(P@Xznu_;-(^uPB1+xh=%%>IWAhQ@lRJvtmL z{0I0?P;+nS>jTtc869eHjYZD>Q5>F<^Q$^Gj+!~3kBUn|!@Y2pnp^7o_W!~@?0;eZ z+$CP7Sife$;ccGv@%<>n+Lko1JjDIC8e#O8OJj%=@WEY5hud7NlsSpQ16ZQmH?MT{ zsJWLQCkE`+EO*%r#c&84G%xr;KEgtR%n5`h3_ZC<*2c42>6D4o?!~nF6^rS4Q@HfU z=g#2x$mh&si$^b0I>@F{$Yh_G&DMyQ?EJBnwZvN8{#MTWpF{#)1FV@f(;s>PQRehk z^Ndp3UqazxZE%THz|wW7VbRiRzegYH5ttn@M|o!~F*WX~7%*nmV#eBe3f&A?{E3xO zx;kp1<`^xG^2w_V%!T<$*4%2KXrZpKi4`Cz?g%3Vi*dT%(6D3wwcQ{3Kar$kPSF-C zSNe-d3pQnrRab3&3$PA3xE53g)iZ%#*_hY1auVFwd0UA_@pFLnJ5AL^@N)o<0 zyopXtO*S>{&`1g{ zqA6Ish?}8-1Zw-(KikH$h!wTK)TTrX^kk=cIIN^f!lVk7F+mB>1xHy8s??Hq4Lrkx z8~yr*R2~uvS=DG9YpX1XY;uho-Z(?dbxk!Ocy+7Y!Z&p^f26fVU-bvS*kbyrflz3m`eGFft@x&Ui*-s5QKI<$U5-VkpuJ!55m1!Q)i*XvZH! z#VZN5*4WVo*iMSBuwzgAd4;}nQ->{SR*x@8(%79iIpZC8(N>SRN?pTjEg7&2;Q06= zE%CJ=!iXb{&Sh5`oQE&p6<0=LQ{#BlFD#^S+6;4$>3SRE>trZ0?rYSzi>kX~l;hJ4 zx<_8}($ZWs#;hJ$_C_JYtg=+Po9c9O8kSykJ6;-Z{o{;7IDa2;mG#m%6*dfG-tY9H ziNKV9u~)HMYBnw2#uTZOh85{XEF>{8LYP=^8#_U~R~MnfPh6a;|zBH%> z5`>rHMQ7>7U>cqO&Uc5g+XwQAFmyeE zz2>G@Ta4k>wQ6NKh!&YfHW4sir3r%^bCp~6y&}UWegHEw1dGJEujPu)*XP6=9`SmPUQyBSrVxDQc{jcz2bKl}8Nb zu9qx}wD_V46DHsNAT-P+ncIu4=1o>qDthP}$FZ3pEV$v+@p8>z8Rl&E(n=Ry$E`U? zGE*Q!wCKT+%J5OoC(VN*$e=Szl#ui}pA2Y^PpTZSC^({Zl4ov#k?!#$sR@HvZlYyH zQ&-Z9fi8RO+yUDVy9yK!9YsX+-!te%%31Tr{mG%Z1_lt@A$~p*y%so;7dhOIH9G)%3Nl#ag73SgoCD}-zPjrqW=deFn@TdU8Z-{En{ORI z@64}S30vJ;fGBS~nf}D{S5N4+Aifut@bXsi4MMbDm7VI~ zAUNFGpF&pTS!&V0{9Wxzt1R7s?^=~Ta>qi~1rv3P&M@?vKT7>rahatXxOOc`8L zb@x#}ms18wFH}QHKzMMAXS+4IEa0M*-G*XWmAq{D5oZ+7IDKM05OhrHy-~SoXB)7t zr)8!bH8(GG-!fr|kpbJQcB_O(IY^aBpX=MD&QY-#$GVJdx5a*u>n?!34#a-NPY=kt zy)=|~tgqPI1B=Q9St2?50iMfQ=EU@t>EE>KEzw*t^uyPNK^#1+C?dL0RBRhH1Km#N zQb@OYU$3XbP&7eH^w}fvmGhXJ`LK|Fcw%&X!sXJ%6UNUlMx*=;zf4D0gdx^t>Vy(S zRT?nE#^~J2ybN){m-ZM)-Ar7U=nvU}b3NR*i+2v_C%&$*z$1^OUCr~$#3 zgCG`x0DiIQDs~RimVCLWaI=2HF6T2FO5uX}WNwK7$aC zt%XGz7yO3b0T~=2d;WTgE{38^zfYVjAo50WDyru3oY?wkjf^OiJ3xt_O*K4{6u18H zAIv-)&d5?g$!wGP4XfCwNZR&Yb>tlisV)L-sfU&oJTSd}Cwq2% zkNF2fKJuOe?QeX-6zzG1E>t{vM&;kLpgm<>H?CaiOerWyo;+sXzL?hkgYk01dWOy~ z0miu~F=?QnMD32#PU5@sx@-^nA8t>p{VmToo2K+m34=z=#oLM7&>1d2Uc2i(lYFnS z-u;p!+;j6XTn|p%o;sEJ*K*0-bzL{CcMhV8=ca<**9(C(Qt?SGWc&%t5!jOGM_Y`g z_=rJ9_xI+|jTFDgVSks+I{@cY{vS-H;}Y}+c&dFe{=o?J#LEX|PcErY zFBpNa_(OWgs({Jc^3+yH#=6SON8gzA^Cdi&DHCF&5rP-rdFX~4T&$=z4_cK~tp-JIL28NkDBnK(@*wAWg6bUp zj}*9;wEBEd|ABp?BT(CEBB;``GR=6h4yCq z;X0_1%CUUXDJX5Thv1bdQid+jJ9+6)CCfbniQ{ojCfDMKi#Kg*Z1b#=_O;%>kan-< zIwdX07Jp{dbU$|HHlm`;g~Nv`L-0!;>24w+W{6(bdemsU%l1XJ3h9H3-}hN8IOGtw z7k5>BFV_6_$o1e`&T&pR&h>Xwt?bv;w}N3nr|li!22Zy(4&)$T?u=fpQ;EBTfhfHo z6T)r2xW$<2femjG|4-156) zeXWffJ1pTG0Cwg2@Q|PhXE9~>+_$1umLzX1F|6+qhUKm#Ox|bIH3G#;a3Uhj=Cs~y z48!ivi};=^OK@Z#RLWk{78^|RpYsEW?CV(!Eh+0{?9v6YlKdm;3n9sMoTzS%?(BQa zH=f1A-tqqG1(vQxY&rC;9WC~R_T%>@tZ4O3Z)q{mL~-*!m^W7=Zn)Cy4R6z$QbTw2 z`%=>25B~X?=%KRxt*vt;PuovFH^eLbQ?Sk25|Q(i^Yh2Id24>jW!q$>`?oo)Ecl9P zd!I44>!D@MIjoTVgBcrmm^VJt|!Yh54ZDVK~g3-HZ!J4h*8^J_jE41e8t zqb+=kQ4PkOK8PxofIfNwq9+M@KLBb2C@ZJBxf%mW?*1sXa05a|x;jX!yl995bvSf5 z?V+O0netQyQ`B|=P+Wa?i$Qbe5AGi{x$->yYf#Zd8BIw#$!<}cK<;Zt{MGussFVYctyu_0?X`}V{=^u}?Obad@$s$*z06(o7qIKCp~ zALbpg0=PoGiZVZMCdQlEYfYo6g0?aF9-NpL?AP~65auhf2t?-Zx?8}RZUbs8(O z>fa>wt}_(jwYABSOZ6(-ip4%%n9SVJJCKpx^;Q0@^}!+k08*p+sUhiNO4pC@lH955p+ z4nC?SzE9o+=5qp=Snt&P>EZtXlT+D-7=JgkWCwio#Y+-!TlNgu{K@=k;UVEy2{{8s zwqBs-rsB;6Tq@e_wU0P{&>ylls5oG_^R8PnG@5kelb)VlEySK1skoK?(0P<5M}1NDroOXkCscnq!Bm=TTfr0(; zQGE#`K%-CW;)%)B#AhejioEgXHa<1Om#!@%AL@@M3XLQQ=^6JK4Yxy9d^R#UOAvf7 zMtA=BsA4wBaWTg-MqHEbtNsrp#QB_uk@}$Z6?bmWuSAO7bGaM+)W5QS4G0DTt~hvFzvw$oJGndx_uk8p9G;%X>vET)fy$#516 z?>j6XwSl+cS2r9uNqu|gdLpzEY1E-XIIH)%Q*S&Ih}tG#+B-R~TDLzk+eyG_@ZQm( zkKtC4qU8qC`(w=p_4MrfR5BIm7H4!_}8 zzVS`u5-v+yzPvA8KT51GY^7g2wQV|Cwv}_R_taO=#+vccWc6!_&Wg($=2<1`zUt>n z8D+YV%tQ46`lI3Z(*DW(JdN)1_SZXOApMkK25w0?X!)22;X*iLSd+O_Vx$vFk(m*K zhHPrvx~%^IbxXcCsg*I3xYRqVSo-MsE?2vhhK+on9>{;&tIKq5T#~}bt(;(yj_TsE z`GkBf7q^UCM+Eych)L9O)9BTM%KBpSpfu!;VIY7u_V4vna^7(tIE?WU(W4T1YFB0U z@c%1I;Z&=mpgXX>FW7ZKe>uSj^9Fx6JG-M|H;oK7|bFg~;G(EF+mRA}-g z=36WW(ciDUR~3jLj$yHRi>LyGJr!Ia};e|HfG+05faClyuYM7wyQt;+Aq9O^2;v|lv>LB zm|S`?eV?O2)+AB&GmEJK)FDCW!Tf7_U)ev0k^cZ^$+wqkitbHMBg~1U zoP`w!xQaP$l{hyksDY(_N|bYheiiEvCCBa;@A7frkei2*ZPidVJLUcractUSmMrQ5 zWqf0=PL<~J+p-htlPY$Hh#9L$6PxD(0((#?!x zDetFgE_ja>jzuu)V-#_}jt)Vnt@s*x^DN$J=K#uc`$xmuUzTm{Z<1d)Qpy?*O17^2 zIW@(29QM~T2A`YEwRnkLhWIV`RmHq)>l~8~Q(QV~lL`mXC*AXURqdUJ6H?F$-Zc zkT>;nS0;9FVYU;=r8AW+q>PeYPNs z{X&w}Zqmxq8KaULZA~a+Q}STOg}6|oE~P) zp8d~C<2O_BTMk=t)mlq-?QP&2vr$jZ;r{^0OI#_lmBgflIM|P}mF~sVP`eUlTXOxc zXrL?0fnV;Qa?b9ZrP73|ilZwf~Vk|3a#I<Vt_0^xgMo|{Y+|CdwTd%w zA?#{2kMf4?&@yU_TY$i4#+fWGWtKKj*;U9=Yx1&by5YL8T&6Kzq66&Oqj=kB$CHR( z+gtPRBEO3u$){2QoOpdBTw91-TbSUPb?Rn|OkRX3)K6$*eulV(u;lRNxUh~G;DX~% zGG)(eZMVoC+C-l28+RjRX9B0A_H z*14R;<#pGqZ;g5>ht+@iA!HH^5Zy_*KpC4B=c- z?kiTrw@V-~fKD}UTpG`Z+(~0-Wspy+)zmO|9q0JcKR2B+wslL59}2l{$E%M<0AI4N zZzAFm*(4JfaM5Zk+CzB$u&yIz!Og(CyNq+?xs)J{vA-`F$@bS2nsYxW@L3V!Cn!Av z@1GrEw(GexIE*>sToBuZdl>FO1+Yh|Pqch0Xe8ki8<}7c#VcGW<+ev_tx0Fan-_zI z$;;+VtcZ&{^yrN+3qcpb2ROMF)iHgR6Zc^uAeOp<~$UjG6K6CV_w;#Ah0&}?6b9)kPPe4+E?LIen(60 zB`;*Wj}Rt3vT>Yb_j@x}t<02KAXP}D1J)x^KWHBxDe>|MZf=B9XC9*v4l{y4z}tUy zd8ePp=NiJ58Q7D7lhdx=`iACyQ$sYeg%R4bXbSp9PcT;(;)GipYdKLd9h;YZO0CnG z-K*@W9ZXDtGuVis8{>Sjt*d>7MFoxYTu>Q#&n#UR3#Av^)s0?p0I+$rysH^jJ+j1R zxf%3K+VPJ1xw{fut%o*5RXwQ~s*}_DHE=o6$NahWX9F887~hH7EQ6@?g`m;8%Ngj( zat$Z!x8dZU_h;^-^SGZ4xk;jx??uI|>272Lu%o-{6>S%sDGw$b{!Wwy9y^b9S#c=1 z#2$xckC0bdo})D+slkY!W5~oEMi-Imqr6b8j~gxmcsdnHPh| z;m>{u+Z87(ieAY!Fp-WCB4qtyt}URsXN1aUnrYY#@CVc|w303TyGGJ-)r9MU{{W-! zscq6|Co`qasddI+sYj$N6_)N-l6x7Do2#jXiGP80pwLaBnytqsxl9= zr3+t_RuJ0CqtS5~A=r+a_B{fyArW{jkRr|bhsGxjc~-bxOml)b#@!|Vb|*>uCFZaq?YdD z{{Wn2*S@uvNdEv-SIP^SE)4QCP>ufprB{*1ysra<_vzZC=0PR9h=?mLGwS;ZtVMwS zZEUNzMdU4T#pg=xal@jN{?V(2?U#*4uhs9X*MeEO!-iZl>jN6JcU6<}xr330J9W(+ zg>dYCl%M@WN&7AMc`iS8-*q3ICD%A|bX(#)cDoW5Zr4$^I#-ibhSx zMaOU(Q07})XfDW)=)iKP2N`;^96yXnz!WU9PbVcLCr*qnc=~*)zTey%9QQuYu^6{bO+p6hx9F;&DQ2|NP*}$v&ZX16M%1sf7 zyidAk$HKUkj8ns|>BO4mk@>6H3%ME3tJAz!6iBZXmhFTKByt{Sr=JC|M`s%9*4@=S=D5@&zG_WOeo$v54hhc`r1K@28s>{3=Kc zPE~E)qV4*)6rY#ng`kFKenrX`2PmK%W5+eZXW(|Q!DTJ89Ki=IU$xh!^?74&#-D;+ zGUf)2PGsw;b|b?z#G>L?a^2~*iCXFv(IW*XByZNZzYn%+i-{n%N#Hk(GSV!8m(?fq zYTM;7Iv_|{S9?wjtY-#_~mpc=n*Mi7~GBXTU-WF%jdL4GtEsy2M5G>RgVz62rebnua+>oF%+M$--nXx z_bvBP@?*$t`SF{8H;Y)+@U6P}Y;M0IeqKIs>B?PNqU|2vXWfdjig-=7mb%ju1C#~g zY<;xkj3=8&4Lz3>wYQNaW+GXiNnI*7t`Qdt5eNmdWh0YPj@Q{w#-ic#aUVB)2x0wY zBYll=8@sD{Z0&s6OwobqR1$R!`}V8*%L8@Fdtew{Y19aB)%Vob95QI_<)8d&+Tk@p zKfHGzX!^mYEx{+VC9|W4@kB7^*scaE{GY^6{vzA>*Jp)s7XJXmTYnnt@O#tyS2q6u z#<$=%&Hn(4xBfJNK26+p-%#qI4$L#it{a_Sq!-1^?`p8EE8eB6BP>ga#e zx7}PBr?)UN&SZaG_O(3HTbg;~sWI(PuDZ3~$%lSZRj)_G;(l1lR16#Qu&D zn-P)J{d6y^Z)|jD4I9jLr@UgOf?JzdV^suAmSt@BbndG@8zjQv;nkTGU>vbDpRnJD zlJEB|_fhhXeOz4JNiQ_tWXQ{y8XW4@59v|IlxbK~541NI$;^TTxNup2^6{Eq$k9%hHvlY<+8L+3Z1%)ZPaz~tB7E@5=jebkZ-ZhKJaU;SR@lVTFlyRi24CW zp^psuzg=;5;&Hqn%%v56&t-e5135r@$8~wSNaEaM(Sx?# zD(Uzi4g9BY_V|)K6M>$)RoCU-4xBb69*KsvKg(Pqr!i1ARO2HD-PWz!&bjcxY#@mqJ=es8o~OTR;W9~UEEkp$XpVR;WAMS)(p=g# zexrvgIT$G_W9TPRtlOzS7rQ~1$#NaSAi z3#UI_TpKz7vpn+|l&F+h9RU0-LR~LRthlO6WlFejNNoJ2ZZ0r{VY5RMteEPa;Gk9e-2g4m*}dkieqyGSC)xYj;KeqK8OS8&VLH3*qlHI{qiHbV- z5w#6K;$6idr2bJyG{ELtFK{Rn5$+jAJNt?G`Q{c76gTQo3UK+@U- zmvM|>KHGZTd#dFPy|Y|fn6>&w(!y5KF}B#=p4v!JQ!c3C@=GS2TVwUSe3Aacee2}9 z{nLHa-!f5k5#*chN1KPnk7k42j{dZKr{=B8#hF0|*El2$0!Kn>_InO$Bx6*;W;&e} z4iq<49XfA{ll&oajX2*-nF^%j44j?3b6WoZD$H0H>H!B=t=;|2AMmWi9R%f5eLW9P z{{TJp#B48a-tlw|0puq~Q=E4W?}Z-f>GK=iN@qTgn0cGv`*H24u4ahEcJPgI#yc}( zq^skR)O7~3ouPr$Q(xTrEnk||vG>)#?!Ov@{{Yln{{U_37Q2@Tp3n`xJ(cH#X?f!Y zM^DYnf6gbrY>uGjiOFL|`-n;{-d@Zo-Ereqhu4jxVh?fNzE2tLVwt12>=s^~s`IWy zesP@hH1C{aKMkvup?P|>X~x;ke*NigrL~S*fs8v3(dqE1+*!q$m6kw8K?kVEc72r5 zM*@i1gFbS_i0P7g^c5xA!lLEI8cc3~z6Zm}AM7{YzDuv&H{D0(8Tp|c8ok^fO=mwbz14IiSGW%P z?HPAM593k8dYse)b(Xb5YKqI>jMCp++_-6C{zi(q8B>Q=@I4J%iF&GS@u10c2mArA1D5F{Pi*=YUXk(!FRfVfQUL<_4 z=w-46a4-8W;(wTr_8aeCCC~1SALqEBi+1x_cJK8MaqB=0v5&fsziJDdFIv4CdmN6v zKCJiqzP{?#2|b)>?xD6e>E)i`+2-N+8g1hB^=b9Jz8L!IQ#^Cpb02so)v6JIF_YKF zJ|?a#?KphHii3c==w{BucViV7JBWp!K;{8z4jaF|vH3)Qp^x{fNbhBN;e9@9%a2a4 z($)R^YUcj{iCkP+TP(#bV~bB|d`@WadtFi5Bn*q%?Qfi)eJplXrTDW;6l@ue?%uZ5 ziFl+sy_P@vtFy(T&;8&30IIKTuOC*45J1W3)2Yj~}T205KozH{QNWuiYBY&+)Ckbe3GyfZi*>uP>+xjlF7b z@Nv`=eJ(SAbPtbrjTe3yB4LO=kxxOAecs<4sDZ*}*R513UGX3)<^}OJ!)5K__I^xTclM6|0M#`m$~CjJUc8{G(eE`Iwah_e{M&N}Yu)2d z9n^*`HvIC$ZKpbM@6UBWE}&4e45SxIHGfu;G|-4UD66pd4N~)R=rgx zzi%4CfTO?)_WZ?f16(!thvU^GxtX z6cVneWoYCK`fx!W<6Jr|aE~^zHri56AsbLUCfX_KZwa~6C_qJlbC@!g&TW!p?7a>0F)gw zK=3ZOkGJ1me)bSDhtt`%QrSJj_|kDpD{F0LXtSo>RpEYW>~T#DP){tp){Fq78iN(_ z+tod3_;#5iyGXf(Tz75!et!P|IC%LzzD>qHU?yo|RJEF4MLS2j>Be-C;%Tifn@!n* zR*#i_(`>P}_}0U&oOjeQ@aZOabSZv+5TCqnzP}pb&nYb_wq0bLoa5$)UMFnGPf;kR zW}ZDUunu+lr1a0mzEEFZaeLc)dt2!dRvADFpbffHEw>Zm$%CXbOr=Ti$Qv4#_VTD!Qh<2+ghNEzd43SqE1gQo}GR%Yt#iGRc@Uo3UL6w1hrh5Y zNVsGiu484{n6W48sVq2*Jm?$hAoz-FE*%#tAv`BN?0KoVsV%f(66LU@sSHkX2;3ad znj2(_O*(Qvzh7_7-m};F`?O)(Hj?9R>~Hu|nVQ<=t@vcQdpQG)s0SYW15qW@ygNkU zhrd=UhRM)9vbV%$hm?x9hRS1T>1=J~mqxdha0gT0wQ@|7Tl#qB4GH>402%S=Un)3s zu47sFl%rVsJ1tKw-SjVLSy)F2ZrNW~HFLvxyoY=k-x&ak;z@gZ8%4;MlMGBs>SgQp zRCg}SC%d+WK*x26@{x92R6BRs}HiWeRJC%U7&ft<0L80T3BsV6luJ-ur7 z<+yClk;r3*MoE=}mB8ECowHYVP{edY7-gGQ&(rR895RMkjPt8t6lLuD^GIG)mPK3#dqgd@LvEUxBa9#?*9->*^9zEa=Mym4_kHtC;N6(LAf6<@*K;d^EZE*M}xG5wSkt~Cj#|M@h9Xu*9CT&h!1Ti+O zrtC3{)wRXEoXA=?!Nxw29sWs`hE%QyuG)ve$jInw;{XCxiNNc%aH!;nO&eH59T{>6 z&?-o{ZIo6qxyvL=ftr@i_651Olh#JBGU4{iX>PX=;aA6;wb?*4u`9PjQcD%QaZLWZ zq5xaof99M{-VNuL(nOE;ikw#vwos8Nxq@qPY3QRNSQ0enuE#z*Rm{=?5SjUt78svY zfW?p4Os@E;tmLqoW?m~K-Jq_rMAN$rcDL-2vBf`{@X4Z+%_B=jQX*I+4*H1!_8WuW zkz7J)AezxjX+@GvLQVewIoGNC2ifJfhDckL0vOR!R$j^2slnWB-%HMoh9+4@E=Ei; zj1GprQdr!K!9Nm}TYj4@NqPB3OQG~5(WGtDJ~eT}t{BFTg08j~NTX_J& zX#*=sD=A6u?IJTuxYRuwjlZfXSDP%7a}13$H*J`VXJJr75hZj;#J71Y3F+j&xKIm4 z32~oh^=L0F+95QZx8=4LJv+G@>D=Rb;ysj84p&rdsXbiv@2D?ffZRzB4}ggBaCT9? zJBD-hRJRh^d9}ncXpz%AsXeQbX|HXdHx11RjZ6`9^qWozA6+f+j!0!Ua3jXVmB^Vp zNKW`Q#BQI5N>&-3ID%yJSV&L-+3&`7%@GB^I5bf_EYj#!)=$G2sHI<3&@lSzf1keJ z&-M9--AOIAh1`*qG8P=YIzR-R>ff(QcQ8)ql4)Y9I%w8kuS|V)@|%bes71u3BRxKi zOAPB86>zx5hV5qr44jRseju@P-B>EA>62IUT%Y3hOEa<}JWQ>X86bi-+N~}ieq=Jh%#GqZK1o!JgSPa?>Z^c&FQa3D z?yeE5rIw-0EOGcCz@|x6WQ>e5u*fyawuNosTZlBGE&%k)U6lhvlDHiS{{Zt% z8^IgK!%Hh5!5wj49v|~=pE?_PZSxFCp%4-VpV8a8m1l%74Xds@vG;9XC@pRx62UJM zlsX=SVQKHJIkHWj$2GH}rm?+`nQtdt91-mm#1`G9ous#rYLtwOjp{j!dMXKQboX%u+$#*DIC+anA6ni4V`1r4qbwj1d!kpt3!=q$di#5-k%cyUt z_HnSzowL%d`SQCyxz^**_GC=9mdNS0Dhaq{zntGk!{9L{Gu*j2@4(5$OFtL2Xs%_&N7$`W-Gh9I3U97W+WXx=sbRlz{wkuFs!NPf|ZyXRT z?I~FG9ShnzHubx+P}#MNkQaB0m|H8Yb!Sf4E7?2!l@IQp?_VQ(*Y6Z+=l3o5R|%3w z5va0&cHbq13e1b%ra`~Lu%>*VY62lG9CX4ETs zuT=1i|L)l_iK{f--TZxYPrKjPXUVfZO2VhRdr@w@zvQ0Ocf3w<$3YOF!pX zKU?dk{Dy_@!;M-8q|x7|tzU}Uh&Yd&KopUNk$KCcx3;5u%gN`BkEDjwg6e#7e&JIz zb53LQY^fMceye4Ft)nzGV^@AF+4DW0FpO_m)TeIaSkK#CM_hHTwbXoT1n)zjI&*_w zw|0EKK2E*78Xl1F6<+1tkyNi>7@27PV)W8u=Fxe(hyuZQ!sOynq#I8*%{_TPH2oOF`Z zx2uoQ?(#S7ul9u>3cddTv%mIhgO?|JI6{CjPhfNuREAUFcCB+hk8mXX1uMk*m(MNx zv5!oY#}%KSwREk9YU7z3s&b&X&NkBv<&XN*@CYU{@~$nA0oB8Eli-!iOL;j{%FL`2 zZ5J`=Pm79%X(5vd$eGTAfFaCNd@?9ov@>(k+}q<%{UlOzas5r{f?LhYmRW%85tX=1 z$MH24(SkyPXl@*c&qZEThvT(oYg>hyJ7tZSp~-k9)<^YCNgQh_*XL2F3%{oHkz??y z>}4dJCCp%tSZN5ve@Sa`{Lrp5{{VVR_*9bGS;GX6>ojSKWOWiF3^K6DBCk@$&Kqdj z7uCy5XKLXc{{YCM{>ZKOsDE_-0DAc)jP!O@KU)e77Mr+s!JY7J_ax{5cjwthmgms< z%Z*M?Wy2hOqM@_lvkQCaID8^DCm9%0S3TJqQrU60QzA^#ld6-Sc^x zwF!@1I)3e{IHSI}L{NZwPgj<5p94}OUQTuE)#;A<&ZqdD>E`q4+H%_U^G^0k*S`NW!=m!x$xv%xCO3y#C7*w)>Cb7QVHs|^?P z+}-lB>aunb@VgRQ_Pj^3olxCKl5rqomN^#?MWJ)H*%{O^_1DVL!^W$>KAV=Kt906@ zf>s7;Ql*V|Gz)+GzHu3eB-9Qbz zXy9acgF%j19`n%AB?-?%MTS5faynL>&u0hQU6mxSwur|{!uM8BT^*{6lg~yg{{TV~ z*!rXV=UTVsa|`3O&1Gim;=6n++vMrL&FNc;<4nz^M-!Bid%9GA6+u~$iLKbqRy z=raJCr7Wyl)+fI;#S>C7Fi3qIdK7v*Y(A=wgvU3V$u*Q39Q4YCY#(OT`9FwXE!pPl zL{C-`;3(PJ%p;v-<|?tmzQ<$nt1cCPa4s%V;uY1Mmou+t+$!IaBc4T4k{h9@V@@^$ z!~2@Kky~FiV+51AD!9+{7Wz^89I%yDe!TDSr;x^q=KPGj1UF9S8y~NF^|4Ko6lZ$% zvU5tCYTWL2pf<@lG#e!!>@-zaDI4TgN7-1(QBR-IG`eAq<1q|`wKteJ9d-S}t&^4^ z!sAG{I?b7F~lIXjrzyf-*dLwx?+`H_GoTT3wX6^QdVsCU-q$9`RmDS z{8!1TwgOo5{{Wb@;V&X)9I@EWz z&a>LcPKje}O4a8Va>s8Da9(M2DEjK&;R>`bcWmhB`jv+{cLufj>>6{7^F>IjBD*2O zfODt$i(f;`p9crcd4Lap(W&E(W#5T6qFG9o+o_MC_lm&AnkG-$_xmY(jxsw9y0q0GPDWLnB(k+6zGvE(;+fHht&p zt|bdxHQV{LtkSySpDKFQw+xeT=F=(|-bP+&bt4$u{5z^igu20rB2Y)sUYR}T zf95QfVuLxrXKnugqCIMCJf%k!I18ndI)ALb>KN~%_w}oG+its1+bVV&VxK~V@zg%b zWl@}WVu9R_`tKd!Rx#JD0KcQXCaretP;9qpXWTwDYQ@>|omz1z>-s~l&g(@_c*R)B zZ8xTdJuUzxFj-+<5oMXi9^IKlG!;@n9FYauT1!DP)?T_x|L#*CDo-u zdN#q>=hg4qdJ+!Hd7mZX6X0i9Vcn<4x~x{#Z0 zb8-~4o{RHi+wra~b!tl@K{Diy@TRPdyMr#I}>&+Pp44kmn^dOLEO8GeAYRa!KE&2K@~P;hkiD zP?rPrPebMD^KHE>k*1c&S;8szj=u^rX%54Quw22~BOT5=y@z_wTE}*+{gijp;q9dX zLGkOgY0=wk@1C`&_IIP)ao%e=(%9)kQ9UWV4}~g3d5z1+^Ls^`d=K-rY^;oo7jW>1 z&tK6S51)ZS1;{cVRYEpfuR)FaAB9ZwT_j=>Ik`TjMtAVqxb@VprU>|q%ISiQ-^N zy2=P3b>6MnSTdMcf(}95e3DzrHAN(`tB(=PT18|r#H*v13usnc=L8Pw<2p5V?BvOI z&q&THE*X2TlP$D;sLmNk0D>#>b%RLpnGBLVr!42jn!@)|uB}nXol&uj*AC&9g^Up1 z+kjl;lh0C3Ah%O&=`ol|9yOLZ&UW9{H6_KQCMjM$5*}eXzCHf{%ttM`I%89uM1=3) zPf93~02_%vV_8$vsa}omp}i8twK3DRFQrxR)kM6zeJv)t4cXJSuIf{(D1U`vSOe9( z1!JeSf!ijV0|N$^ScUx_F>;b!cMtP@D#$2}MvjpqD)sISxcdHhHE#;2iQ|wtla?IG zjaxQ)`o^SRIe59IK6aHDkSB2-2fn^i@aJP1&BP`Fhj&W5mh$Zy2W2`V@6()p^>M?5 zyq9b;F&kuf*APqVgjF%hRwO!xO5;BYisn~tebuBbA6+qe6<(R&q4?FbprD=@-Y{A{ zc@2*f?5j&i@u4G^7#j?@IQx8)T{@OXog9JeaZ5T{P07=(-z$Y&<2`#r-J0XNt)#ax zK{9$xCs(8DFil0oZp-<+Ng8R1a_mR|0Z?&EMkWafQjd*sk=$`heR3o*w4AjOCZ=PI z_v|Z&aT|FSYio<^Z3GMv>6d05#+n$c?k1m}V$mNgoQ+?tx2k&6!)(mVv4_cAY<}MV z0Ol<6h|==gMq_tB0kQh%<2!K{^(PNLzmu0Dhenz_sqgKINhgJ6bjFw3y@i zB-C~sLIHDWEGe!sPj^klFAw3c3u{p2^yHFB@g|RM{5k;*tatX< zQNR5%?rJExdKM=y9)~JHImyWPnlnQPj!hai@c!U@{{R|+DCblScg2K;3)vc77i`9{RV0MaxKJ*B>d05ZEI-d(AS+ zu1jN6tgNlD$5HGizEJS_!B}PDGO5yfbgAx76MLj`3dRPIanm(74xQQ{_$cf2Sahx< z9Jl7=yizt5bf_hI{3;1$PvsYuF=kDPkI^XX{3_MDv;l%)0{Y&;RyMI`l?}5Z=fG+5 zOL7oMV{|%6#(P4o8s~{J@pmjalGu(=@BCZ?#U$J*9YP-O4kuxUR#lnH7BJR z2i$90aG3;tam(gvV!uoEH$9$%Z*55jo3u;GS!0t{L#t5v*cA&zTn%w9=y7#u#ANWpirIS%M2W_(_f6=T@#N>_i0~&r$W7;k1?fSdaoW3Z{80PZZ z%$p}3r+?C*r;E$W<^Wjm=Jj-Ck6z~5j5fE?#i9W7nW1C|OA)8r(=@y~;^I4rMDF^c z1P%P2+Rx6486ZZEBbdfLL+q!P8+hW8#vPS#TE0+O+{ewgmx#kA*{BS#<*#g^^M>zlMx*NKR`*P0l6Vw|i^;O* z+0(q#U%P+3e3DCUy60C-3#U0cs?{zm;_Ytf(ea!QrS@-JURgqG^Etmaxb+XT)Z9u4 zJmy%MFcpc?Gv3(lt8OOn`MkzPj#U8Z$nRYDR9DupEyT?}jWRI^qZub|rnoN>!=m0? z+n!X1Jg-PIzj)f3Q)wGV&(M#jPOvp+8EyJ?_SMX6iyA7c#ek{(o@ zjP`Tg;Cj`}>~gb0k(9sru%jPn z$I5iiDS9#0;X%t1nPw@-Q@bvo@8g=CnCs6gmb{hQNXPdy0A@twGw| z7!>-$dR~g!qI2k1s_bh8NF2Q<(68xbf4_BQ8AB5$8_kz(L#{sxx-sX{xIV5rC>~zF zIaKt`B+J6rOp*~Bw_qGAu^XNCPg|z-aDpueiyI?q&ams6`AftCYiPKP*ckU!#8)LU zj-yG&ds)F4_jIeCAp+)5LatXh$*Z|;rCB+UOruhSk~RzM*p2$tv=77Ql`U*x*75%6 z9OJ{g-&RO%3Uk8~={HS2Bj7%|i}!E$uaQ4`zkPMCC9fd`teMB`nh3x$l*0lt4Jsmt z<57iG7y_OtqgkSFSsii>SfcEL`rH6JhOt9g?E6JJG0;~Jj!0GG zp2{w8BiHN!zrvT79+C!-bCZv*qW#*US0dEDgFfuE&TP{_V?t@+U!<*}dH#&Pbh zD=pGuLuEbH#j&0j9;Rd)f!&%}ZG7BX%H>A5vioPl#;#?!lQ5}N zi9|TkEqshxBTp9r9myq$7f+NIk|W>G+lAo9mj3Y<5y5j0f0oW30O*Frgdkb zCpaDz@~ZLynWN$}Q&c|Q$6*3xA%*2H!4BN zU`ZHXTRt7wq~&nWIflm86?fOCtP0uBPOXeo5H*xm#hjyqK40nX2lPJLi}!E$uaYm` zk0%qJGQ7y_-G7u;Whax4XD`1^aOpVAY@Aev6Kf+|VC+skl#_g& zGRJl#^v!O%q$}J#*{_q$#8DvPa@|4asK2GF@7lSs6D`z@goF)RHan64{aeBDezRi01H zX(XJSZK!EoHFt3%$dEWe6||ar2N`3xzaP=Bm6F&gdy&K@(ig9GYVHZ;l;M|1$7P24 zf%j}`_Ff*(9H6eYPN6fsUc)`ql8_`0rETP`7~GMZ z*9^9T-b?E#re&J^Ta-lX5(me>rA7O;``5`A?>_@ZxQ}Z_EamMU?!l}a=Q{v0Xy`o- z4~VVz_65(~TpXq!UlWKg)sy&Aq;ctU*EN?ce!2*%6-PinncMlGWseQ0HmJ^$SbC)6 zt~;|*LR(dc)#+L?WtwiSq%UyqIHh!8@vsF*?;p(Zzx&o-xoTN#(g4l*#)K~Z{87(N z{MGYV#|&x6a(M~>Cr`4tH~oe$>eStPAfEGzf*u0yt|rXM4BWSG(K*Q2cvs0+xq>I+(OyUA3LjXJxoo|BYSQhVcZt=F z&8mzfN5gprem_-RF=r_HbcTH6ZSmp!?_cIFUMVG8zcy&VjfbTjbR7GAqONam-sLTh zg@Os>=FH90U^dHsfZJ+Yx4ZuU2(oAL9-+$-{*JHn-rk+w+FP4qOl07O7-T)_M{yr9 zO>*Gk#v6%>>t-xOT1jux+?|2xwO&hf9buFP((?xj{t@Ho`}^zVVp#tGjh-PmOm*(7 z)w{Qu04hUC+&9z@@T=(fcy^y+RzF#nJJ%C4#dDIfYIz4_rk;n}pT?~3Ev46G9}kE_ zYC!a-l0BPth&r>}YlgwZV`aC74Hr(TrDl9LZ&&p;+kDav{SEhzBsu>8IsVD4Y8gE@ zt|21lQrf;T-PxmrXFksA-AXru3g}O}x~z{zivB#SYj{&C6|;kobzTYgjz{k4T!hm6Rj^@b^2Of=>?~p5(f(&pq|&X&`YFkEWR zqxjUEJBLcJ+=s(c13rFyNu zBk>h&HveoJ0Rue>l$1Yh|jTp|Xc;}^E z+Svm0)m0Z}@b!*bj-OVi=7+rjzl_Sl!#)u*HNvZv#2d&B@cg_|v|6XCk;V z-d@Euy`YjilB{)4w_(qZcHTLq{ge24BY9+4kUy;Lf$Ew>^O$w8)T5d*!^Bnek;oYh zyJ3;K?N2oBu)wFcERGQq-c21R?Z{!=LGKmKozf_?jdIGdu6#1bt#J1tgQen-GweSA z*FY%09jjlR!J}3+bJrR0>r56!c3)U40$1PV-^*b3-h_)qdxk2cmOeVF(s+TihVJDd zkO?DT0%23HHkj7hg|^(dH*7B>O)Kyy1o3OpT<4gvmsMlqvWl>Sh#-|OWD9OPAjWf$*&fX8Pjf0X$52?I zkJgpXMHFmItu4x+d9Cf`(F7U#C-k=OKTx5r`Y2!YV=mbHtFy$EpW1)pL_Zsi9CaPD z_}BSmPT!#a0LFnFVLiuR@u#?g;%Q@1+Ivfu5B*cu<5601=+@>J^*DqB1drBFzLr>= zNfUs|>T(FAQtbrsHmiGt_2F+3_>TH+8O9;xaY#me6JSWc=OaEI&gylAOg5->xhGRO zKY6CV;WpDndm`q0NpKeRM|e5Fkav6!u`X?&RA;!1GM@D#xQ`Db6}y475FZl`&Q1rr zdMl_GUsz{x@2`|I%>1}hib~AKyJf95ml~UV1{l@usV=Ui5Wyd;#;-iaers|Yvy2{< z!IT~R#xDN=)D^zQm-bKLxF>|h-KN#QQ|;?lcG`pD2kEf! z?==?>OTlHzx#xD1A+{rbjd0!)CG(Fqh=V3El1^&g-aFN`Xo>vdYF+X6?O!HrjG||P zK@pQiop_16zN)qJb|IrakhG24?BIMV?Unm8zP&r+J?C@Z_K6(0A>M;@qqO9oTjD7EGVEqFGx|is9prKcm+l zZ;=(*p`Iq!Z*ZQxE#f~B-&b50i0QQAqCDk&Nte1r_IQr!Ypx?KLMVJWGXz zlHrH)%Pm;*rSTpPJbU^YORHAb5k2D!q;*m|i14p8npxaF_YcfEr0P@;(Eyy_RMVFd zOEN|!V3^d(F{|sZm3%%qc`{AJrd59fg{!a1FvS!GRCPLo9Iky|ets2qVQk?p4jMgO z7>???P93*p}O}G@&tR)ON}0cFrq>$29O>!D6f< zpGjHB-$*{esQdP%{ge245#=~tc<4`Ypgig`mDQ^~pB}v``6HcVm(4YVAEJBf&aY*T z+S^{9Y^{Nx4S^=2x{nPEtEx9f%DVW9N$>7qvVogQNjs6K`v4Wg=4@qW4veprIYYjC z#tjJ(vW$A^BAz>Yl$F=0A37m@=F(i)TZE9q#teE#>j1xfLaHJQy8#R8KnW*f-`2Pg zNXD$FKd-%foWSh~_W0DdjOWgz;%?xLkN3%|IkiQi-A6U9CeSgX9cl~fOGqN;NEl1` zMWqLQU4e{uRh8*|Hk-q6Pejy4m;SKF^s4sb&06_!(ZbtFpQ~y-z9)xoSb4Oaq3!I~_{5&614X=_h@_8) zK-V%VVPv1tqSA1y4@)zXEc3eQUHxeffbIgVcy+GvLb%j=x$kd}mNj;0XNk4j+(+xe z-Xr*T)A0NB5OGL`NMBNQ{{T3i&k@~I<|p&HC-fvQYuLco4VKINt#GP%owv|2V|icn zSa%-&p6+aSderv_pH@2O7|uPtDa0~sE7!7d^?3bN@{;Oi(+qr4W^d}PdA+=aXU-K# z9j}3@udc}u#y7y+`zq{NmRWf(*psQ-+3&6y7oJ1Si-*M0r!-{-f!D&L5nRJ5b<}|+ z2T<`8zp{T1BoWJ!f^Aq0jP^}sCMj>-07cR^#Z7XPHej{os$gSI+P>->KH}m_T^AhK zMfCasR-W9qII!}UyKR#-#eX970d?d++N zZXq+gjvrb8x)=?Ljp%0bSrC8G;X?g*A3H>LmI)L=#3Zv9AhvPSv-a;%K{Tdm0b*FT zuB=Wo-`A~hcz;=c3i&Apocdi``!atD;OyFel^G@&+bzsdx3dPV8Z8Cw?p9u0jfH$< zW2d)1@mxEINpouicJmh&klURpkac0RyBzh!JZ^$WoN07nkVORH*Ad*ri-;n;c1MTU zvo84dFf>c>z8d! zPszR(G5YX-_NruxD=rHZqtZM~9sZ?Q*ZWlV_A1Wu9M5qk@=ATD@cF2P%ohGlRj`|!p*nj(nplv73^#1^!)%riH*E?0jeAk-h<34kA{=BS4GyDg2S}lt`gpftb z=EJ8`t_Q7rF^R4@;Qi2#U&btcV%kwOPjc)w~>_TLF;MG z53{XL!}+|2Vi_M9!4-e!^F+}NQmVzirqhh)-CQ#8@5EXNWsX@pN}DOho}J$Mw7H(* zCgjM{Vk>+rFj9Sz>7i!`dp{c$JheMLLp&Eex7)alRU@ zE-j#eCFUuLNYt*N$a-(S)Cn&RTq5&gWYkYgXRT-&v*KeqecAE(*`Zu1KSjskTr*kp zR@Tx<*Z!>k02=ulZ7^eb8o{Ft*~82}-Ko9x)~B6Um}5fPbBx!U$z#u#8nnRriBY*d zDX%T;rIyY;Jo#8-m#bmYjm4_O&ui7yI%1%k%_g4K;h8Puf-=S3ePO4s*H#e= zURvHtVu7VByN1)hXU2`~{Bc5@(->5gyAnOZyuqZE~t0Jy_Bqe+@H}4r0@|yN<&Betf zC)?Rtcv22lh6|`ZttBL=PDyo_tf&wgsc&erA`!px}x$0#N>RBsPpp)1QZ%$Oroj5=c& z*l*XqqSGX-k%6K%VT^^-tENfElVMweK4wX%f#{q3GyE%xOBusM!e+*ywnTOEHXS(A z6{&B2v-~NCeG0jPJO_BlT%EI0aarY;hECD)jK=LuU=fd0(6NVz%XMpa5Mvy3qVrWx zU-*i+wuae9410c3$IV`La!WS6dq&k44o)Q{quVjj2cD^AVlsZbRh;P4aVTwOXMl^; z(~{bl9CZZuRCc^V-SHfzP;Kslf$ZPA9yHu>eo<<>SqG)vHE!yPJ5HHu7Jl{3pU z>e~%OX#?8TkDMwf5;F?K+M{UOODXZs)@a;Y#>*pia?&$<`kwq(%AOr{D)Q#yl7`;| zWm2wZJXtPck(B8Rr#f?t{AnzO+)%sB=Oz3lYJBlaX{|_RbyK-*I3IbdDej`?&2wQ7 zq&~D*j1JF*Let$zc{Eb<1d@UJC3}Z~r9Q*>c@y^k00ZP?brK^CGO)-s{z&ROPHy?e-a<@XrksTa%-~hmkzuc;MCQ^BgW{i)*NEO7-PR8y^a2UZzB{PL!Yps0o6Q>0=nee|*Uu7wf=bahd*? zCYlJ0m}F&E!Nvj9YAXw#R%DS;BoMJ1?DeVmY2or7 zQid|TfmQl;SH-v3cke|*X+AWb&$g#GGhCpW(n73~ySB3A?jIpo3}YL0_Enxd`a8cc zk0n7Voei%&+Ov;sMzf-jq1aX~zW?d`5YOIg9e4LttH{do70WVutaH?Pb53TrNg2~i9CaNjR_+lxj)0T> z$o72I{jb2#`GuU}6l9vd;`bjYF8D_PONL80Z6B1x4)!$sGHxmPdxObtS}U2PUSu!& zJ#uUEq4{6LY_7cGL_`xA6S8soRmb=r7Arp-;lG-h#?oii&)M}FlKbUH%d4Ij$I7$Y zSz10*9m7cLQC?WaC*!hAVvcPfWk1euwrV~ndGhkHyKRTjUdhf0$?>B?uA)d& zDQ6^+tm(_v!SFPkolE1lhmBfH(L`aFguT&hk?9mB-tN@|;`Z@g8)=_t#shjSTW)vX z6=B9Kc|1De@@XKJIpI1&4cBeHHN&r((}&;7e|*by63pQSrQfc1%~>0GgfQ~`6l0>V zaQ6-J=OA;x-^90gp;> z^M>%lby~c-md06buCB+K**9pxx2(gj)lJ3zSMa_w$8XiW3_{TI5PQE0x4w=UEml>? zieZLdeL&Yb?eA^dRkh?hNfG=Q+-;`zt^W2dcBiaXl%m(dm{NE(+JbaS+j{S9G z8g}Vl%U6hL(b?BoTpbi6`4{R?+!Ap0whM0l;gWo;Whj8WW{a6!uUXqzrKWe);; zYLA`+?w~(+zKy&Q-79cRZ*g?5B&G3M`?b#63_cB&3!(nuy%WoYf)y=Kxgfw9ii zw>J8@Y*=>CsmLWx$J#!BTE?Qs!kI}Shg{M~mq^jE(xqRiuUOZtYp=|P7^IH=H5gL< ziyr`UQ^7wFhs^x(r^L}KDmjq3Q=X$F(?&RqS}v{D7KYp+tdXg0lz&Nv)qQZ1NyRRj z_6d1yjenh8G3U5=RqP9AKM%`1(sOQ-bPj!B04GmVP+7^r=Duh*v@u-A3dy%{IL}%# z#}cfQDw!A!&u96A$6>Dp&mQ2Ycsw8Y4&iL`K$+sLqt)-odN)69$eSMzU_VgV+l-IWxvs;^> zwu+qI&w`?iZByF$7=9h&Vh5Vq<^MpP6d}>QutIkyMsA(6J$4EXn8&$o< z#}JKe=1oybs?3Z%;9|Mf&R#s@CN^KZRP(fn6cCKaTodJbG>YmOrMQ<`cKuh0bkXnmYw$rF<)z?45y}nPbqmKD`Z`@%GC_e?-n$=P~eoWm!kn&8|z+%~wl zjJMogM?;iw$4cb)laHuZ7x_HNFPWziH&;`hj~l3NUVW|h16)ErIb<7#&FGuVWM_3o zI4pMV+oekfou?bHw}g4O5^H{3gZ`|XVY+7`zEW|?*`$nBX*IBxk?@kE~b99yeuw$g!V@kvvOjnYjt*%OO4Z1oW?y{0oO8 zy`-11D*Z1;o{*FMU$(QF<4z1>A2-Co+Zi9~!`4m-0iCn3ax}vS4W%Chiey@Ii z))j9&w%qq_6w-uf_t)9(?yDwS+uM7Y#D?Y$U*@nzowWDwR%>a_y@FdEcbeb@R#L5z zoNa@OhxP~0_EGXLlQrncllN*^eU+iJ89mOWe*XZOB)^j8p2`rWdw}6_sQnOqdT=e8 z=F%Bsitcrg4pX_J;?*Jd;`7$Ii8s z0VHJX*xsz~AmQRKNfM|I#~O~2)cBgc;q7dZOvQBGhQmkL9~!q)I!!A{i6cf~ryexn zF|Tk~jGBvy&2r0Vv-!LbGqV;r%X_NOaQj1T9CqS4S&s6z>3b`Ns2!EHQGk3+ML5qk zd7Q}E^|ZE;_75i2vYPcxdZ!iYnpcuG)}sNEMnjJcjW9)!>g&vM{{Vd*LTn!IIg|L- zF@QRJ&UMu3Zk{qWGhgGtd*fg}>Jq^s%Ngj%*%iGXAg{iomSrs&{M!g{VTStD(`0%rSX`ehEpfw=ehCYyfO*(n-+ZjUOC7?S zhuow?hc_8(`K|=HX@;#xntQj#ebpt`5#jK)jBkq*=YN?P_4H$RKV@BB%HD&_mJ57+ z5?Gf%+4xeyZt`)srFQeLJ-Ni1O8pWrI@P6&g>^-%0SO@iVnTv?;2dY!SJ!h&pOO6J zUR%NRjln>LkFaBJZCTy3eAPQxc`leKXE4wm9O zOL-dLPJiiGllN{Y&oS2Wwx?l%R$&`j`Mfp5y{|9-08sfMg5D*#;#WEIc$oH74zAy- zKZO{gYu}WYqw~!ijRm@U0 z{eFBhd9&RaB;~Ae`oz}`;Sq5An|b4&GECrO0Q>9Z7ZQa~+S)u3+ydL>lmT2ho((4U z4N#RooXb=!u}{xfbP&+tYvk?Pj86^R@p`%HOI6nocr{$dt({Qqvg#+{R?!S<^K?7Y zaG@S0u-)7@W%auqsC(<>6wu4dx{;HIMEU&KILY_sL+}+Hg}-9X1=E0fpBC|@?E*+7 zXU3q-!$$6V@IvC8I)M64r}uQFF{+kfj!`57PKI+56O=g4YFlahPJK*u0C&}g5w&bh z1<%ADqwK7Wv*fpE8M((;K!*pWYlLuhLj{mjk&vHRobF9WXA8$}Iw_H~fn0JGh)68i z3cC%IosDrTX}1Y*9X*{jY~FtbDcWAdE4h=xHR0heqHLfWOVKs_}2}$j&M}^Lk5xP z_v@c-{{Ra4Srko_p6&p{sO+g9eSi9Y1Q5v68)2kIGRLwG-wMZ^?bJuk=~wVbaIkTf zRr=x0aR<65nk+7Jt#E%einnDwqY8}I8bG)U1V7q;ClR!PgmPcKumMxHEci|YtJ zCZ@c%ZqpIYw_%AOlf77XP$hCl)F^hMCvVPUr`J=3bx7F>k5qI{9u#tHLx%VWURpBAu)%XI`nTrXJw=)>G; zVv;w9h%VB=(VbbV^pKHpcOsc_&;{tGq`ARgIg?WAJLww_#*dK&Vv2>-Gm%R&JMy$? zWmq)~_0Bu#B{wpg1m6ZOTAjLJ)~7xD4+`E#EyW^sem*UI}CA%rZqNZy#vdKOrqNSo_R>`2S63) zC{JOsBnPE@qnx(07ZHYj*7+o2xYhf4zcy|QJ2#uYwaGz6W=XvG#Sfd5I6=A9nuCc) ztle=4{W)gavdxSSugGm~(6o6BjHeG9cQT&iS!J~2P0=peR;H~*OIe5Chz9~Gm(k$@431hFO zJA(A^t{rj1?BtJ&zY%Mj%g;4rDITK6GURr$Fu1M;c)Ui%V~%N@LK<}qvL@=j1&v+# zle8-DYi(;X#gdx6B(1pp996WIxw?|t>h9txZdV?O2P|{|7VQ$X9vPfqcAKfMliEq% z`F9_()x~Ct;Tu%Ud-4xLDUi!jql22uyqG7pD%$Axftw8?6%#2!1VcaNy$zki0M9{P=@yq+s#YOQf9 z#tX%Fr1}ss(>>nd-%F@rurfWhYcjD|%X05y?wTwT0sfXgqH62VHTA65Vri|~U(SwR zoOX|MX*l*(wDZX%(tb;h37pB0T~BbX`tPouPM%)>04Dn{kIWjEIImK@L0+J*QoTW5 zps!F@sa~aemFf!hEB-aO`)gtL*H5;(eYNV>X59w)uG9$L@n7Ol{{ZFJ_>4c)ukk2< zsbAuee^P;4WKud{bgbk3V_iPl=zpwhzvEu7+g`8RUa#9;uiIXy+g`8RUa#9;uiIX& zdbR4;t6r@J<$}YZJLAj$!~iJ}0RRF50s;a80{{a70RaF20RRypF+ovbaeqEYJ-LlnusRS+Zt`%9%}r0mT^- ztSTPv&*T39$So*-I>QS{SpNY0$SB+nRpZQ1TFy`6 zB)T8#`I&Tou3*jt!JGL4iY?Va4%iH=?@&;N0sSOn(j}AiERV{qSL!7IZ=o+d5eSgU zcCyC~7F;Tw80S!E^AlpuAS}3kq{!nk_FLclQTTZ7Mq-GobT+tp?gD^z2j8iv?zgxD zG#TnyC#FS(H`KFRBAC{$1oIYgYVQ$di8fnuTYAI_&cPJRhqBXLrJfN{JeBzOQrdPI zpX$SzhmhG#bfc0?G0ev(Eb0oJnQ~~$7DTt9Z&Alsz-*2R}mVbTdw{#hVZgMwjYl7%0s#4M=r!vFi^o4JyHEQKJ&TP!{OG@t6eE zWyb9@g!8Fr-shZn5Nn|Xw9(WcZz&;RiFJ_w0C5t~I3lfoADLh&L3AQ|w3VvHP^p{Y zdGQX=N?Zjt@W)3RfVCF1M36bnUkOGDiUGoka=QZ;xO-B<3_!r4+gDji3tP?NW+n&d z#$SSG3El*NmX$VZ!_(pl6uf33xqg_!d|CJ7@ZrjhbVSKG8KU1ne`M)OVfUi2OJAts z;D0-i$Q@9lrh$v_Na7P+eCR>;w}qgu{f1`aA*Os$4KMSRo+Ol6hT zKlT!+(=NrO^w|%k{Gajsu`BLoN2;KMiOCXTm-)kA6583Tsb(JzfO2#_tg!eWki>MU8!{{ZJQt9LT9NWZWAOpub%K=q`RF4rX4_8J^#p_)_E98d$gk)GMfHE%lk6ccTS~^~8 zBn5y3)mfu3`-5yn(?aL4LbDe;4s#6w1hazJ*}LX85Gm%{Ke(IQC{_w*)VXpKRBFR< zZ$hVV2lUD=jbvp0hyY#y+TjN7w_VhQyAAAx6oeT7FmaYW)Nbl+_^L|qD&RXhc$wOw zP0F*+>N4UBqfPXgaXNl~58i$+A^1_Y+~T|u_9=K7=TA|{<$Fz=NvnWBbbn*|+$97P zjHWq?Q!r_1Ply*eA7uK(-8c1cl)HK=cS|g4ud)81Fd29z3S~AHZcwHRhTc-}cPn&C ztoz(OXq2hvuTHqPlMxD`Xi<_~B4^w*>2NI$z3Y(q( z059SDIm<7mX3ARtr*6*-TjdhvZ!{iWVP3o%8C0~D@om7!6sH8V^h>G40D;G^;%A(t z3ZA6H#WNdQYu=Qcp69`=XRLj+hVnPFF|CA!6X2X4P3opFCu2t48xU(ph$_ zML3Hqvo7s3r<25O5rr!IyMCpsXm4qA^$58ccR$JR@WFh)h^ccN+i6dA>Q#Az0A?B_ zpt}yQ5~_3v^vZe!H1nL!S9BrstT1iA(G5k14a^6RF%@2MeWuSW9`(aDGPp3I@wHr3 zTV!K$%qIeHI}IaS%);x;45T|0>&(1XPzqKYg{lC!X$&||Uh^-je%=D;+d-{@IatSD zXHegImGJ_u>olrH`An>CE`5)pPEkfx^y6bgJaS6KB+}MJf10 zyO?PVnj67O&M2QzYaP7Mny8RAW#}&ogFQns;0Z}V#m0^D26NnIC|#97PwES%1`NlYL;{UBD^uSILxwic6ATaXjf-Bk zusY@sT4X5gSyepEYwsMjdc_z<#Eiw>qQ%>O{{SELI-9&q_b*+`$eDH4qocGN0VT?`>bF9o^7c!0{J9%zNf24Pf{nVG|( zGqj-fU8eLKHD;#XUb6sd3o5Xj8m~Evg-Crx8gr);bR5dez)`TG{+UI%<*DpZOFl^4 z2#!MToBjd``SR%7~^jdLC`2W_?p*4krnz%IoJ$uh2+<^wKf z1`b15@h@El#7=m5_bm9;N;b$A@S30Wi0_&xm+z@K}`5`qx#;u@VxYgY_9Iz|qc)$;K{{Sp|2FtNM zFcCs4S|lZhBLi0RY_sj;EM&aGqY>1og&Z+I>gVzQ02{aC+8WF(^)rRc+2(6CD~^DO znxz|8lDL>ep`b*z6>90G;tl4UFcReII?Y`xfVn8zU=6AydsKUwp0{Gyr>~%AEi^WkZ zqgVK}bqg-yt!zE|jAm*hj8*!Cccpu}T~uUnST5G9B)k-`a=zE~8sXW8mtSHHDx1#b znE2uzt{9DZu|Z<%m8LV5*mPMaW1{dFN}ammy_&S&Gijc9r^)+iR^r?M*8H&w6P(ZW z9iybuvcdNSl`P>lSQO*=AuSjuq5Lx^X0_{jTJhQNYMcS-Qw!60%u}7Ew-M`g?=>cLXOOH;v^5a zP}0K#X^;RI@CF^T55?1IwUj6sPFt?iV6{x%UvRAbhzEcQNzLpG15t3iw@_}+ICJ?zF<@&y*rrN`L)3M7jG5r7+6s)7|sw;1jN??J22E7Yqn zpkF-AL!RS4y%Q8c)~?4<;ZG0}SD&22k)gtj&7oFQ7R)QJ5K4JKOaQl&FWVNOcBnw5 z<7B`faTGe3Xr*&GAFE{ofmLWv1;O;8mod!;CP0kZ&^Hm zaEp-d%3uI@$S7;T3qq>UC>jV{l!dL#qY!sQr56);+(o)4*1)NJKVb)ePLW3hD;RSIQ|w>gvxD=yS;0#tqXx$zobI zj7a;B{2cx`{{X)^gpYFRE+9u-qsM>^6@!}by)5&}~4>27@Vj{A)z6pyO zuJ)H9bQN!iI(LKzRM#~3LkNb%FjSVz;8}|qcD9M9ce%!Qn-ugakd{g{FBvW{TISbU zFm9!}V`p$h8|YMP^&7U3TT8D?oS8hq!Bj&j;o2WCyaVnidkX&myKDxB+z%S!&S5$M zfCbBlbw3so4aRk36Jp)r6{kq1%aAUEIBQl;dm%A@6 z2}vVObS41;_)wF@UH1)R`;>xe=#5nzwREjR7i-&8rLz~D#nxQXpwahZ z%+5<|7g2pz*$sxZ2+uOhmJ6ytBL%<`+oguguoP-t8Z%hj`I|&TGO`dFFwyZX72FiO zhhmKCF?n)%*QeA@Cfd3S(KNE1R8ALbcE zKWs%F=Mbx}-AW9e69dFD<;NJ}H0t51YpxGVZfv=V8QtJYv(%u(VZcvK3umhH900xD zhRV{<4b^|l8nr!KqxK)73Fle4oUE(rcR%<1GC%QYwC>?A6Q3|o;TSA^%i;WD{{ZSQ zPfS_=0OXHw^NI9zT)#o5#MA!(F1s2y9xTGeN_5ATqO+PR@bMc%?a~LSPM>nUdWO|J zRHBX`rnuMt3ArR(+hz^r2dW zP+>+8+Y;wxwq@%}0Y)g9-0lin?y^fE90hL{s)T={M%1{xQES_49tu83tQui$Z_m(^@zV0g-7S*>RT=y%MhJP`}m z#N)CLm46V}6lvWo>9fc~Dv%#p3X3ULVH%nm1va-j3`Rk>!-;QYzi9lSB1ME0oLAAT zo@E9UOdNWSPa$`3*TL{YHm(QUaB2!_!LJ7-R-j9BN_j9e;>mZa5BDxj)*}3u^3J>c zk(rKS<#+DNoj`)P$n2H^$^zW7-GUkcNLpaG6$(+(z{UOM?ww8y+co&l@H<5ZQzF51 zN@wXH^IM5;Ii3+ZGdRxW^{>vSEDsPS4L1&3(&LV1^(;3qW9AJ;-~&FU8lVLaJx?$m z+B6*baq^O&34elG+aKIHOZjsw@XX-N@$nse#}nT88b%M>EUM4)ea9^9Wge~*CR<;8 zB$K3Nttu_BQ%qH$HBWz?6N&=*1bU8aLkPVgBMtqAT6OQLGpod`Kf%P`<0B8PBS;+ZQKWZcN=W|#d&iaZJgqs<=%Sz>NE%)%qOdoz4n~?2T!DI* z2|(KtN0h7cAN@15vb{OIYNj!<#o_b34+@yE6d8@OxEW#n8H{1kB)zReGQyp;YPzGpF}CD3l@35u!W3k|D0!+!Oc z;gnut09SId%$KrB$z2#wdMiZc*u91C{xb~SRzjPNMHTr46m+0Xzl+W!DZc9*>ByDd-* z#-dVN=B&Bqq94;99s{az6$nM-aK#OWBsQ*Y8j7$H5fX5Z?3B7>fTg}v6$(Hd0)X`> z=Gg9GZlUgDYd&Ud&BpJ%{{Zj+WB%+*ZsrZ!Rm}4~rsXeR^Zp|}&CZ^b#}iJaIWRZ5 zNaebiy#Amb{mv)7OMomK?G#7kK%~;+jwROC1!JYO`^;Il3uN0$Uy~6OKwx3|m#jdp zFXC&=O6Sz9J0@M*yr4=J*jx+}$CXABc$tv!nJ{3(!kRb?;Q%oY8^D*M6k1)NschaTdn)*iMk!wXC|UQ(Lj3N$Rmps=tta@?HY zzXU0yoa(kk!lV{ShpsSZh=kFkYSCFjfsv zeBV;klc2y3Qa9Y^s9SniDFJ0e=jyO%&==cMpgTZYc!_&9G04!hE*A{bOC~SF(ySbd zoFiOrc#oNlZc&x|L4fCoa1GaUJnnXUK;bFWDYzM0EJr&g9Q2yj;>+kWQJ(FV^1Q>) zKZ?B}4HwL1Wuev-z^&v?Ww^I<8i-^|S!fSu!VwNM&0f5W(y zL@=rp=(NX^xr{^!`UPg!?g6W7CYB}#4(k^iF$K6Z2uFyK#U(>mYw<5LNBB|3?mqom z2Gcxq)MdL>4kz$M+-m}4Wd!gC!*a9%U~+|DnX7A-JUV>E_&72m)bT9Q?{r#D8GL(I zb0p~?u)Rjj=%}nGTDQ%0DmXp0SU+<-Q4A`BMi%emnE1{v!Yt|6%(7!d z6kNiwq1>~{%vl_RUP?vOVsJ=H5xy%}yw>2RW3kscp`f?%q`72~r|MLdJQ15BHnQ*( zuLj>q*F+R4vH=WXmvCZgu4#f3va7;Z1=wWc`4JJ|FR(Pm>H^)7WOe`zhyMU2P8M!8 zjk)Lm+}yKuVA87zLCfZ%-#M4(@rv$o{mwNpSd=evxXjM(disZiagb{ewqfcj?_}C% zsNvi@B@h=K%hGeW)0}lnB-V>+p0g0b(+#%PmHqaPj1l*2@By;(SpZ`k8@` zcWQ%xsJLatcz#y7+YK!i*{;*Azibc_S<<`(x%_j~^2f?v<})+mx|aAQ$H|`)8nlj& zGb?VT7h3!@b1N3H&P$#uSnxvX!u^;hvOAhAtW4;91xqF*Tne;eQt@{m`NoSWS{@kj zE}^T+w1A-CXH!gn8aqw=02ogY@BZcQyY3lLFqFzd3#~;3a4fadveBZJjx8K&B6{0L zK|GAc9txBt!NSMcD~V#Y*GDlOk!FEza@MuBXJ#F+_eO%s$#Wk=1--frH~e?iCXQwz`4BAlR2IqJ3qN*diKP0sB+wGP=8Wyq@t5&;W!HNX~M013)6fjZM z&DZxe&gCyP)XmHLWtS{H{unsHD~@1T+}7TDocQw%4*X6YfO?^vQyAb=<|~twuo_MhUk(Qf;X&i- zTBvvcafXaq)!b-Zb1+f|6#!s>B>;7s@Pa`GLX_P#^%fM3(`c&A-a^YL*SKLYa}h zJZjFN9fl@q3TqcMw=&9BVeSW;M8`1tW%@{48>x!u-bhq2osigW@k?HJO;q3|=Me}P zmRXUTZGI*&2zNeaFL{ZL*W=!Q77#5GeM4pfVbt!ELzP3V$S$WA>D!I!sc2r+F0pTc znM9#bty{1xH;0Ot)UAA~yyM1ufmypOXh5O%KdT@_oB&!n3-H}yG_V#UMH(+Lx;az7 zz#8(tX96!D%a_Thq8S2v1i1B`l84JLU5dXkh{pJQqC75f#C|Zwnf7Cy>KTjAsd(Bp zS}`;|oJ-fZReIdZU}n3V_pHn5Z!ELHmD%$yu$jE(2YKdmpTe@(gZ@(sxy^AGB*3jW z@dtBzeZerS*dmD>78K@jg5wQJvOnx$H=13?V6G2R%b`)tsHMEzyGc}dBL|7Q_yu$X zTTx`;AEcX^WNFZ_85wErJ;QJ#6f^=G*5Xb@6)fYdQ`~MG602k%qRS;SC}rz)tkh$~ z2q2S=KT*o$s1sXgv^WfLaB5jWtz^}5F0Qc>jbJ*ivp9_VIGE3HU{yyJea2I(xD+cO zJm*9)jft+ce{zlui(o9R{X;5hXx~sRAVd+p+eh0f5#|@ead->WUT&_v^8r?{lOVue zE#%n0j)z!zv5m%%$-Y>&R-ifysqxdS|gz z3McGVU!66!zD<3NaqDm&E2~;o98O60NUHopn&%T(tHN?r?B-cPs8tT#CDEad&rj*Moa;cXugpaQBwt z?(fIF^Zjv?nM|@LJDJ(ZO!mrp*6&gHUGqt8b|Bvr*4v6(xZX1wnAIi=HzCBE{f7n# z=7-hac-9GJ+%*#WaG>xTH2n_u5g2-w1TEFpc8NVjE6wJ{=x2414veBx>;ZbM=C}8V zIz}6W#2Ado`Odj|Hs`t$OLwnK{R1_5SKJRz0cXD8!8VkJX10_+%Tdc;W`2!mKUj(% z4%>hU$J7OQ(;eq6GoIAyRZGMr{R3`rWP7?6Z$!6!RA+Ih*-d&>-Q(zDhsAaj5W`nF zm49;K4}Y7z>-6Rip*d^PswH@dyK~~W)IBiE$&|oJ{J~wRGb>7%2;DP#^;*YHMx<#O2BKCk-8$=svBp#W^)`^tU~Fx1^jQe1>SPCEN1+U`p; zuX&5sy#qTQb&$W5aq8p7t9Ei&vJOjx$n?C5pX{;mO4H9;^1H;6K^e}=5ir#764C}T8p($XJtnnC(QQ{+fE;4R!ZLk-g> z0=R)S@;fet;QX;9;%4}f-DTh0J@MLUd=aEO9{*W0X^u+prv;%E3C+}^#2LOSNm>-6 z>HZeIGbmbR@*2C7y+-xy`18Stz0sE~h&ESj=?9ShC|uj4{D*2CT;i6_F=4^ts<&5^=w2aSlkRGoz_Hv=-{y6>t!_;StS(AM`nsvwB*2i%*{A%OrWyNqia^g~ zvKa%*x@he@Hc@7r1*LfpPZWi-4$d4*Ej7ma9F%8lO&#JKef^xrm+9?^wp!)2JkPm7 zg2Ma;hyG#_Z>Ys0C9AFq%Np$f{P|PbItmN9_<&$US7V)_(-opGj83g%H)?U6&~yFL zT#XyH&vdy6sX9A$D5o+Vu>oEqU-)jz?&8g}65L{_xmAKWYHAs+hFxjxer%CfTk4NL zH{Tgi*kMs^sKh$|x>@PWLH<>yy3IwbxeZ=wmG2?j zk}O7X-_2Po#J}(wy+v_S?fCsTI!MS)q{I^7k_mZ~kytFh7-MLs$~n3=?{JNfhy2i} z4_p+hz6fCvqI6I#3VLfRp|VE3K9|#TS{)@Pi&CYS!ek-SR%70JH-R2iB2%eTIQScJ zLpL1-Dp8vquhd8s+j3|LTKG;e+j`yEwcgl)nh^Cu_#DSa&#=n^yq$?}zp!auA;IB4 z@B1>Ycu*5bze_!^CaMNxEkDWw^pO+L{IZ`DnnUn&5}6?x7~tw0$4Eoi$e-4TYo27r zZZFcn8ka0K%GDg3YV#-AuFwj6+Vl2-#GfVR%N(BhP4FQv2!J72yNq%SPfV}N#($<`UzcA9#cz1 zF%`*b6pZzGNol>QHRN6!cl7>O!jm>S$C8F^`6XN;TSF^1E9FOY4a>Gegzq`te*oy4 z&jUG)`;HO3Zt@i)jwux);zT3%u69Jin(~Q?F085-qPdejErIWgOXBxQ4t&;OmDLw{ zxb9UW4)BZiBBP0iaG*-7%zL}C8|J}E=J{t(F<0!F%LO~RpY>Oa$mTS~dUm_Yb~K!C zgRfEIQ^y~gI{uQ|x}P@C-Sw~<%80KuJJz74Khr4L=3>LF!yaYWdu^+q?pYIcAk%yzNcmrPL?9Pl=#JiLac+jm~i4s0&OkQ9nfF8(Px<-{7DkSscFe(Iu=JqFN!#SsF@P|Pj_-$wPcclx?_twEy7H_te-(QK?h8C@$FWK(~#Y?uOB3`~#r zYRC?Ff-w`lqc4?{TbyI7`M=pEk|$TVPRq%GS;jb%leX65{7X*gI`{4%h{LMa8fPT6 z;HjraTwb_e^*UthvigNLse&x&Y}}$OIk!Bh^;s^AZ2Kmrr_|aACH*W8pgMh zcpnASU+jlr4W<$T+I*ld!ZYMBSg_EjDE?O+jb7}g`M9R?sOrj4fh1Vcx4aBo-CDdG z<;~)MVM4E-bz+V5LLDkf07*k&>O=(_)TF0vG0faeGAX?SB@fu`P|%@NjL;c z@kL&-R&gvfy{+6VQn`eLD*m6gN8>Gaplg)t3&HjT=pu2Q0wgCc1TRY z^I3$1nA(K`SWd3~gR7h^W}hR2&t!iu`+W+v23`g(rDa zppX)`1G=-vOh)TlLYH(&*KXdd4~W|}cDb*vuv!#cm3IzEIbZDXu<#*jQ5NGrrno7g z##7-sJrubx3NxCY7Kf^*wCJK|BpSNgc}NvLBO}Ga;_XwrXIP>!_;Sow+*};3@awbb zKX;x+mz0}0`ZB+}^mx@UaEUJ=GN+3MQiHo?prF$9<~BTaIdtP~lEnrM@`=I2aJTB35Vo8W%YD2ON!FPH3zgzZoiWAMap1nniu#OW#THqZ(4LO(jz(yNP1|g5T^d)nrG<}$`EvLpy zC?AgHr0GehSECKTIb<)fPHXXu1KabGX%*C~xIn((2aHKKGR3m8^_N>CHLwmG@2b;4 z4fLNDbgupx(@iZssu-Op`4~QsDCTE6GQD&zUZi5QO#RA0m)*R6%l97T&x@QLrpiMK*Q`8Fo$6AM?oce?$h5h%)k zSamnb7W2g5^hWwdbn7LItIff?pg}+cmbfGVYb2aCs6qf%ffCAJi_hvUjq-1aIY+fX zX^%WT$5C;;QXRvx;!5akdxaC#RREg@5vr0qog3$OJdD%=XPsNL5d*0AE&jzMQ5(S4 z8n3a49Q!Vtzz>u`jzL!lXtquTN$kDJM2B=krVC>i)|9F8%FNB1H1nK-!YOMAVy=HW^Hy2 z{C>!kt){q&-Td0V?D?*FbTs@pIK#x&6y6j8H-1Wej!!q-xi|GLI-R7j@y&pcY0TgV z$)pa}=|)8o+g5gWc6r6-Fvb;Z_=d**JT4wCDUe%FB!PLgG0-(o**ZHzR=mA~p_#U? z*r@bebOuGrdL{^)lPiSF;T?#{vE`)L93||^$V1o{?MiaPI=|QcoO!{0=IAueg}5Kr zq)A({%H{YCm!3Kkt`T%THOGZw(!uS?16?!FGf)7V?#ZJJ+qB*x-W!RC?u)JEaM*Yh z?^826y;GEj2e@5h!*|2qrRV`k3ujaOx#_qC2wb(Yx zI;8GrteSa>5i=}SvN;tws{AG4Sw3+auxoNWzC-^ z-K;eoc@%%FE@)HO=Zp1Zo1<3Stq>mnzYQ3cH*C=S>V!;frMpDh2HqBSiJ)6CE%-@C z7zuWbZ%!Fw7(7HIe$(t_Yz|CvP$*N_+Gg^hO5|gD;+9UlK(~;0NYx|6A zc$}{JLF#eq5RUOT1J(TL#Lf~ zIs-eLa&>Q_aeBlCSiMk~7W8dF@2oj9tJdf-tew{7TkbX)@9D*{K1KeoriI7g0`e=^UJ=gCPUxQ=^j`+XN%xZKqhG_opt(mq z>?F|&0>b{mxmR0JP?TM+Ro$wKkjwC~?KCw)AI7w4;Kle%1ojeWA5+dN!=n5ktAGJP z{}PBMV_}o@Y&j`c9u4WKP{7X19{DQZ?;jTq$m*%1D1G9IVWmw`&&Lrhv78x%TinTE zCj8UJ{&OPOfE&1|@Qr!jr?MZC22*9j&seAWiTU~I9GP`QepTTM$2T({ols66TRf|- zr%i3VE1F5&bpQ|74jr+klORZ$7|tFZ6g@2#RqI8MQZSz3JHxa0bJ_D0-KHaaFS*Un z8|jKoBO|Bypeq(;3!V*%+|cx{uoYY{6UX0%Yx;PtSauI4Ui+#^f_yeGec}c32G&`Z zxD+}b=lx|^<$B6%jTWQkKwGrv}Z2F6>_##$hvuJY1^#Z63iwTQiHB&&0?Mb{W;hNx%YDS*^R;8DXq0 ztjoYOk8QVcgs z*R)5LE@Ciw+@{v=0mgllbDz0>?Y@f_W~3bAscANoJ4dHB-w%4V_EA{5g3Erz|PP#OCD!;$WlLLW(Ag z%(xHm8S&;48#z<#K-ZL7YA?OzD#OW+reo_5&gEn5O~|#3SFQg5-hrr)X=(S6U1YUQ z+>!Orru9$}2Eryjgpc@l4%%e~`uC`;Jb1|8ewxkq?GZglNR(vsyIe%ls(c_z0`K>Y zeGrAo9zZWwX1QSl!^kma{OZlG)y2Rk@;1QUB$OJL{Vrk0gc| zN6rT-KYY3fbe(-9miP$my<~mYU6NE?H$C)7`dfh+-eS zV`$2hTMCq+l1L;|a|?NKLVqPoAzMm{#^6$(Y4vI@Inf)eKPBAxq~76TiC;pIx>JM9 zHH#2U@O26wC~B&XAF^(hD<4kxb{fUu+%&_!!I!32ll+wv*_0ioS!aLRF>uUT*0xo= zRC8vv%~50f3?rl$^$(-GpWJIWHKmi!=^$=t`Nt9tGmjeok~YDVe?}wgOyxAB=Gs8n z*H?7_$)6zKA>lv3&y3e>27U;yJZgJRkCm~E&8ZCZ?OFGo{M0(^;0T`=akR`MK|%V| zr%*KVLv)xy@%ZbC_IOSh4~Rk`fz=J;zxvQTa&maC);5qH&S9PDL6Qvy=6jx986~2f zyl^fb+3?UMnm#6%95FFMdpjiBsS2UQK}UBY%U3rn;#8)k&FrMe0?46SqBfRdw%nZr zt=4Caok}#cd8TIAHhw!Zm8xVO>W&@6*QQXI6q}dY$^JBjFIVKC7$1b_wueQcCl@BaX)z#C;T z%cX0{>!gk)^m`gbO|vkWCgZW_kdOy#l_QmFqDUS)$uK1;^#%=jaL0#E)`o`n-Iu&Y zoFbkU-l(Np_>8_kO5}UVJ5@$Hq@ncoF)89K)?R;om8ZC4${8;n&3gDTr}W|HfFD0< zDiktjNmfMv6Q~m@eECNd*-s}xd}iS}#1M;b4I|!2s}Rj1o$+wJ!wS*hao$42W=T4= z>*lNU6v-ch4EK@l(s>Xp*6J@!Yj6fDU2dp~^O33HuOn*J76;`&alSS*Mdtm6>N zJ!_4hMs^Th5x>qgiF~8xo{(|Q7iJsbO)P(74Tq*a!A9VO=MM{$XXi|YzffV)EGl#hw_fh@kjI%WS1R=(DJIV_FecOdc_T4;oRfF4TG++j0dp@LgOVq|PIW`$9Q#H?iCTZ$? z%TKlaFgi?}?H|%nsHp24AJlT!u2N5*N8<0BcKZ(8Vvr+*&-0=|kF;}66!?cx)Yu+c zG8omXIi@Gu(;0#svN$!x#@$>y-mNY+BRsHt!^05u3bGmM$KB#^XTgF9PmP`n{G(8q zTZmvF4rGI)_z$qpftzm+u7m8|aM^Ag-|tnrtrs_UO~fX)eX*Ob=_+=5E!IFab6E83Z}NOW%0 zp&6Z9#dK6?uBfBO@a9>0hBihT_DM6B;ci2%pvXu)H$je;5lZ8PgnD?VRbuo^r|>9y z$)nubSSW;H)97wNBS%drU8`tNv;N>S;#xoa*c!lL#6wZ{aJb@EX)IzLNp5F7m1q^E zZFY@f+ORGc@e@`he-N1EsO%?uC`!AN!quI+Olce~3RK?Qx)|Cs8`L83(+%wWaN6Frj2Irr207WxJ zA#;lhW5RmEO;vu*4J(g~UtAV5R8(trWT+QT(lSI-jcW?_49oh!_R|znJ}oxu zryS*gZj_xIZ&7TqqZ~)ib29*Kx0CaFb236Uy@B>l)w<0F$SjwCxiHtnx z03U0m7#VuJLwWrk$1R0OTH zM|55m*e>a=dqzh^WhL^4)LCdQ9e&Wp7sij3M$n85xSf(0BxyL|bv~3B#vXewn}v%A z3>`ZM#!S*zuS?WWxD*>W+R3rq1 z=E~14VPWp565o<6>#fbbB^flIRC%v1q)$lgNrw#Xhb`0YofAG4>Hl}_i2YTKu52Q5 zYd)yL!HI+12DQ&XA^MjKz1+xReK8wM-4J}c5D3h{(9vMwUWxE2tZ+$lSvG{jBap5d2` zi^9t{tX7Rbr^>IFmU??|Gb{-zy+m|G!2a+sSVCc#JBV7U5rZ2ev2q8K_EGF(qJ}Wo z_?bi|(1Q&6ZiUPNCZk6a1)+1*jw6)D!(aCZDgDBxv#RBW|P1p*1 ze0tRH^Yc2jp3{CVRn&LSB?>uv_nP`5a zQb-##bXEHHNX}oTTS<53B4%4+SJ|kk;T)gQuD}(&N<|Ami38E;;f^wjxIHQj3`YGq z(QmMeVPUA@U=1}jFy(8MEVsh(LexJXE&~M5`Btes3$zAFR1^O9b|99sswDpwTE3kr*9N1nh z{r4t=>y}#Qos}M}$hjn!?^B4onscx#aeqLj-7$NOUyP> zEw~E%^MZGrZ|nD~oJM<7`iJ6R3^0qbc~Bvt#BTevqp)cT?mS3rg1RtusY>(*8#6`F zm+430vRShE3Gb;nQK4)y6bZ#Vu1==>$ZE%lDWTB(+Izq>Q_zNkl7@b3H-C*Jh3Zz(M%33%3pI@8&rBQ^HrH7IE}7E`t75XBcxgy9}lkXt2Q zhg5~@Ix+1|@C_^c1#aO7ALpSo>E5}a%4bW4sv!1YU(P7KfyPyi7)ouc&}yqENIc_Z zsxEaCpY-TPIRuZ^9Ip&9flQmb!G0*7n&ZZA#)=Ee@}zPVeA+Q^C`;Bx_UWTzE%Vv2 z=d+$LW4*S&J?L6)=!f>Hq9}0PzOd90j|W|oqJ`Bpj7b=HaCDMPH7{8s!!UgHke7fl zd_|nT;$z+1J1@}rc(nJ-p~s9T)2u=#-pAGWU4JEaHpYMh7HJo0A9N5Yw7xLC)7kHb zsxqP{mo)V8$QwpJyoNgDW}N#hiks{>Cxp=UY;|Z&cr4#DhScZ~EJcV~;xXi-Za~X` zy=$n#@yTR>u#z*QpX=W=ZsqHAgt`*bYM|}0vJQ^WHA0|Rr^%pXW2>k133o&KH)F(1 zogE864FlY7Bt)S(-4+Q&vl+upZZ6aSlksnjyS;KG)Q}C95nMBk>ESGY@59v*7Xq)c zgLNIG7vVy6B)be8jffN(?!2x5$9>pOa$N$?~u&#VLyS-8QiATUU?y;E01&kV)35azCyAe%90 zS+y91N{+snAdtm>j4k=e%$hFNslO0__dG~g&yWUCHvg zDw8g@S$fO;WA{Da9ogNghCgke`BmB9>V^fosjWTzIF@8WMJYc@o+d5S<1KJ&ETsJe z&!QJiMcP>(7k7?kGQ}C(;X8BGiZPLs{_WOJXFo z9JX0kty{89|JFp5;b`eMC!Q0i$I+maw%c-G`IYmS9p*Qy8JJrxiSFM4ITt z9zo4S*X^78UU2Gs^;nhYf4mw%*3!=@CR``xD~M*Dke4iJc9J1an!XuF!hCR`IE=rq z-kmlt`8!s4O^g|dp?dDj;Cq9ofgIAem6fd-t#TH&e$_2E?fhp7?WQqUSCeP2cr30i z95c$+-#;4pmqt%CCPC zBb>vwgL}PL@A4_OKlOR)UgnBxI^CsBuuF%*HMcV=k!Q>{QDy%DIPRKx%T{53|7Af| z1J89o2^v*0R?l=f>IQFI^>G|!5!|pnCQU-0^;Z?eMivNZWOQjyr8GNl{|hun_4-!E zoVe8rH?r}kzcSBlLiTzA#EHMByePe_{wsqAv2$-jJGTD!(N7nHVJ=ulBz0DkGrjJ+ zqhP<#m!O{=Xgj#7sYJVjFudNMEgM<5dqWr6QW|~Z zmR&3;`xRTo<=eOUxV|^|&_vrOad5){MG_F@g-!uBWI^kv9m%oaMyHCK4eQr;8>jJT zG)PmGC?{8KP3~ zxe>I{7wKIm3Tm1MK$pScudZp5Z=`$FIVf{F6O?q8tjS2@%KU@(<^z z5R$F-?)j+;}oL`71mMaDT=&TY8`8jUmf zt`Z2V7t0D$BRV3bnYd^Q19MSrKSdDMNW1b@s(M>D-A?O1%qMezvZ;r|?d?LtuW76Kq!wuAnEGv@&D?=3N$oc6WLAV`Sm44<Jlt_A%y8;OWn&{ZhazgN5l2V*rQBgs0LJFa@+u#rWfI*2HX zLc&1ru#!Up$ZloG?mjdjWqV4%LISnCNn+5qq5z)~!yr0$2Qp*4WwInOav(gxBIDTN z?n^?jtC@5mq!={-A&rq)L(;*pA?&VY|)%_>m#5jwzB58$smQK-G3PXLA>9EDFE7bnq(Fv zGN{o zf;z72rmgo8YAOr64o@2*QVK*M>llGN@b*s;V?z{0DdeMqR1kqqD)`1}qYoPb@Zb(+hT z89<<7bMJ-HNg4aYp(ovf73Kl}z+`VZp}Ka9kptkZDab?tL1Mi9Vr_g@zxfl3oLuq7RQbiw+3zja{kP_w`G>TuZ(c-QMQ{KqM&P z{+k%T9;H83nIdKYW&y;hN=KmX=k7H!yorHPC1N8<@UM+dKowB{=XRxAq+#0xq@KEJ za_1rjF?8r@8x=3jtJrmpsU2vzV#II7L(6he~QiD1YbEjchnjd~2iI1aX#jSO;b z9;3taCC*Etn0Cty74&S4qYaVqO0#JAHjgep59o*)Mp6X;o-~bFo}6H$kFw&)AL^rp z?#ABZO=1T0!$@*N$-O3!^76zljY9az;0(?={AfRBrC~NrUCtvUXFJ3l^c;>Xw$hLWFW$E)G6|dNrx~(lp!S{|DGHT$}IwbdI%A865u+G^@*&{+2f3 z5xxqSI!&r9;S+>#A%rK-#XBvP&l0zZW+0Ec&X00%e}rb;{{4+=snaeBu`o82#3xEy zT=Wco`Eb83t0I77Y0Sx6urGQ2Mjp>?4HEqyf>2{_(+`z6`FhGh2G12ynU5Kqc_Oqk zicQ}29Ua0pkLeb%=lL2BXn2HF)qc`C;mpJkZZ4?hn&qemb7%gZav)mNBIL^0uGfST zN^RC{6W_=}@5AZgp5iM?#oP~O1otEF>3p#Xg?8hO3kP>^;UB3ik~_b2FmdryujW&t z%N$unA|3`$Syj&QDd0*S8i>g*&bbzyFTfN2b+a#IH~?11suA50Z5+i!aHr{ZCUe33 zpit<7hnHZenNL(QoLz0)VZJqM68k$?N+NWlTI=R(~}!ozmLkgtt#=s_)^XOtZ~9E)5cDR{vbW{UQ|hrred z4Z;13cw>vJcJxReS$bFr^AJr%kY$5WZp!#bN9?veNNoNtLn>GudY@Ng2 zk~*nSZcRSErlAhp(wVoduaSM)A4+dcw}9iV%WHdW{a7Wc9s9$YfAz{`_9Xmhg4}M{KIUd>d`D~V>E^R? z@lPy$8@fEtX3APS1Ji^F_7E*3EM+FZK0jk<{%Hxe#+iRc1Y)jHY1*H}GLqficdkr&PsI6y$%D3Lt}O9wpRC0KcF^seMygufmjNTu&wc^W z>mSTgAJ-uWYo@}y*Q`4H?u2xWlbD-+BpZ{lai7U=x_YWt`$XhR*DUfY18?18D6y^U z@9ys2DgSzCdUcOVPkhP9q^xQl+k5wcyCco@IVF^t(YWIJV>kxSg)W|FzOtXiPKQK0 z0p$<0uIGHH(_1yq{{gHfVHNfs|0cy46o?nI1-$SAV|&R=1(h~kM3GU^wXN% z;L@sEJir+R@1iY(wfSZ8*H`94*Zg;yyTO-Fh!51x>4ZjOZWD$A|4er9AAN8CI1yjX zPq^5x^;-3z!L{wfJb4RUBWH5qCl-ON-wHg8hPo z=KE9id_s*1K;bwFEMhyG* zIu5E{m@F`PjD6^OfWj^^DLXqbbHPpc(WFM96KN5+;46ZS%>v#1Z>>Ut6i%zId(oR7 zt2Lf$a?q&Z`L{x;7Xv7h5?&AqvWfdhMgICG7Kwa$0uKR`m&P|SqM)x^oq3*-wmuDS zFC{AXT`rrCCPGy>s_qUfl#ciJp*l4bIAv5dG(59t2WKNRS?UZmBofQ-Qm)~^o3G^` z@ey~LV_uVFg$`c(KR3Sg4Xo`b^mRbA6YaeWUID(mI#B0fQfLAoZPxGp=L}07f4@|# zwwuLQT?v5<5VUQ|p7{OwdYfXV9_ip45c%yz_??t&gR_1B&NqMUkNhm}iO_I&i6fCu zYd1>6$QgDxc2WZ#E^6h$lRuSo$8OD%&&4kHL4ewt zXLuFn?NZ zoeFdEA)4xjV)c%u)Kov-4-OQ|zr)i5N*FD6;c-2u+0JzN@@TG~>&-@ODiFOALgop4 zZhTHPmid?anuA-)A(TG)I6Ym!CfUyAOVZ{6}mVC>&fp79pDG~MBoc~u@yn}4nR1WNCv za0}49bkNnKDTc8@0n!a)8{Lt*)0U8ZbNSy1ITG%e%E0TX=IgvuyhQd&C)KjAvUyfW z4XG%hcH^B-iGnx}83sShyG^|8PRuJJM;uZTLEBlJNM<1C7iA zfN(J|c6qds+=UJVf7o}+J0X;Oy}3z|L6s905hY;BIbMKfR<2dkbf_w47b>Fq_Chz^ zxIK|#bB-N`=iKIxrflcmzHN*zjs3p@qZA$ISp>;F>>MBFq%Lk zk1lI{#{2h%iT3&Er2lYA-ec5Z-4GP?vwd1?VJL$E3fL#al-D;cdxmLCM#jDH$OOhtzA%fJzTq820ZCQC>gPV zSev`W<`Ezn#j(kN$TL?EzX9a2BV#wa8&zsOUm(28uz~U%1f}0@^(6! z?KRXVPLxxE{@4G#Zw$Q1;Zi;{Nt7rqonk8j2O1CuKW=&^9P=QpjQk5lOWZ~CV(St} zDY23gmw{RnY`No|Y4IgN(jyOL$vk^_jvOt(j8J#nfd~ue3Bo%HK;82+%C(a=o485q<1#Th5sjHP(D*Zh(x{XCwbkYW=o6>^ag@LejIg;G9IbbW z>Sp~w@Z3Ke@_%{akd9pX#8V;O6Pqsy9HCWg@%nPD@R15f@{5_* z@YlZ%cVll`;VH-a{{XR^7GJT28aRoSujpg&sr?4f?rYJ_(%|{bpSPEZDk%aFfc>R= z#MNrETniWf!TQ(aDbV)SXz?@izP|$QzQ63NDNz1@8de|sTR%Ec3B>yg%Grj|F!^al6__7?WOoaIn{f2kIp5UXJ#~1rA9_a*)g! z2M&t-2?>l7Wp9bZ-1ND5YLB@&OpzQ-_0#r}C;=1hbP&H27kbDmwr%>fclvXahyH5! zbk!~LZJPFOIQxqh`gs)m#s*Vi^vJOVafN`=OZr9;*is~r^LW@pb}2`qQv;JAQH-!5 zYTn5W2QhTDXSEw*D39M`fP1%(mGRUznRj*s^ToJ)q8kqqDKG~~hkk|{JNYOWSdfg@ zzY7FX-F--ZTB-8t%9r|*O}D#V5Ir~Bbukqh#Kl45Idwx12AB$3K z$ijwZjZ;}irP5U+y1RW@c#6(2^0xV@TD{D7fpy9v+e>Xd-eyPThijhI;dM5{^G@z$G*3&v zOym^6FxW~@YaMy^@iR3k_tyUzZTSgzVZz-CPyWC!F{s--$fvu@Ehw{BuKYVs2XzD0 zF;A30@rgvYkY(>?6TTJwm^%V^O8qA8!OW^OQCRGjqz?}NEmXdQ_AOb$aL=GW<<}%2|;_A@v zG~ma8ajub>9?K`Ri`V-31TFkimHRZw-0Q%6ZwYv{NdaNC%__r>HRDNG+mD2V2UPWM zayQzH6w*AkyGXbz;VMBYED1&15c1QQi3qbk{Ps-yQ13=wpsQ)!M9A6N-b!HNOl@%i zY`VB&F+j$c+E;5T8Yz97^Xtl<-V_Dck<$$DWLw?YGNDILu{z+h%`33<8JoW zBJ>{i{{YoMD!=9B=`A+Z_Uq&$6HbXcZ{mLj+i5cOGP~5DsW876t0xExkPVGuN^GZ` zpCB?rEPx%5*_V>9;eDUOo!NDVvtg16WAN#=I!-;xNPVoDlUvKuN_Q^K=TJmjZ^BQE z0N4wki9UJ55#FI4mi7R{k0*@Fpze5V$94p3+3HyxIme4SlKQ%kV8(lZC-EoCW0!#? z{d0w!Cc}D+vT0+q?Yws5(f~TP8e|ym&of~8!{5j4oc%$tarbQe-lJ1&T21m{r2CBf zXK-V~f!t@+`ye|Y6T1(_$Ha~vH}Gp6Ad&_^WV?lZg>5XNl}I1Mui{blz2 zo$ycPW%soEBszo+UTN!63F**B;$k7w|p_7m@eNA7yDX>aXs?R5DbbJdb(FP3g}l60R#Z5=IO zup0p!c#an@5)V=2gw7wCVJZjS1M9YMoOZz5qhBtq&ZqUxaJKvmy2;FgppZ`F`g7}n zv%`e$)rY;4N#uo{Ps|-;y5+vuU0E?DmOO!(0qF?jI&#=&z&|WYu?Q(8jTAWG4DJl% z0cer?hsu-JRD zOi$o{BtLQS$d0XHXPx*pwfJV)c6VemxM>4=kYQ!H9*?&hAFhf zXUQHeLO5Zj5gNV8T#|VwM&7><`VjOHou`{8v6*s%Dg;P3Nc$A}}c3EUI|&JH!=>4i?_Ben__vlyqb=gs^W+4(fR%Iukv zYz~qixgFz9WO3po>QMF(@=@)-N%CE@G>?<>JhZ+1tmxJ|laICtu#PsJaF@mqBmGal z0M6OHW`1Mm&)6b(*hkO6e$hOdTSrSG?AL!dIC#)?I6HvA_8&-HFSQAW&1dGYS;y2G z>VFXJg#Q3+M_&4}XU){%K_Mn=`X}lRhKdjLUu__iySnat0Ca3?@qJ z>>eOJ*nE$|Y`#9f0B@E*0QkKRWC1hb?;la&DQJ`3=Sq<4ocK()}4UOABC6kUoCARdmDQIaF?0bgl$Gk3DNIt{XI%^|VpC!Us9Yv&x zs|x1UGl&Myxxu>ul6}UkZf&E}ZezgX6|I|PFrHaLH}*g^ya;~20pig0c6845VC}eU z7)w#uq2I;wLs02F_Z(;2w9J#Fi2k;rkQuWEy^ig~hD}cL1EyUV@@CnSVv7AvI=czBGQ!<}OHm#n za8{1Cepvc}(B$C6g}k?Yw%XnpZPD28+dJ6zloE-=?1QpVgse@=9~I|#B~0{T>~J9! z%jn{PeGrp}+d19j@_a{ld8tk$kz1l0!S4?b;?_p}SZKS5mI=<~x4f`23Ph%S9fS?< zfK#^8L4M8W{sRlyG{}9QCsNy9FSz6E_&r0Vt?%Qp9?3lu%O+{WW1Z`s+2JJi*~VXR zFO$>X!)>x{KJt6V+40Qy=E}Ds4&ESbkg|TEGm=-e(HdjLtCPMEtw3d`E7Tux5ZScJ z?dQcd-cNY@J}tKQ4_30RuK-{c%VA(oNEv&H@Mez0aHmC*L;90Z6I%r5r?*id)qz=l z$KcX9`#vedJuLvdp}F5A{9ih}M)4=G-U4k9GeFqn`sa8HWZ1&iADheU_=edyTs9fE zq>olecgr81H!ke7PH^}bn`dy(a(%au_iHE3H<#JN7#& z!cMGu4D0^@C7k__Phxa<(?k8bo-Yn{^>t<%xBz_m?efw)z5f7Mihp1?@ZNUC@;xT) z_B;AMF1C{FuLFkDy=s7T3Q0{{S$S7jW@B#Pt6Fe^2f$ z)|0N^PV@a&{kxa)YjqhOP1xwq_hkP75Sv}KwP^P?5{_SFH+J?%yJSbaKH5dAQNijE z7-tWbUvunP!?DU_z3ets5E1pet^WWXG5`j4FGH?>-;nkf!mIxPTX!D0{{SE}{{Rqv z^ZnHv2i5N0qS^AxhkUc?vIM#L}hB?TR zDKzW;O#c9UfYv{g#qs|DNB%FlCLhD2{NX5nynFIY_yPX$ZtK<8{{TMvp1z`4_reK` zFGm0$$j|Ek00sSH?6wRuo}XZ#@(sASNdB!?zC5uiPY`3g^f5~HY z5B&Yvy-yF<)_(H(@n!Ino?)-*D?6GwndkU|3Ea9}NA}ySv>`1X9&*Ux;5k9Cu&}VO zu&}VOu&}VOu&}VOu!h9HmHcn#e>rccAFB_pL-=39{#Ww9mHe;ee+~>-u(7}cpZ~-F zDG&hx00RL40s;a80|5X70RRCJ03k6!QDJd`5Rsv=!O`&HAW-o@|Jncu0RaF3KM?-_ z^81gjE>Mi=R*(>o=xo;WSqN}@BZ_#cMspFM6iuRZ%aNc9shb4g=(NO>+2zSo+5tWV zbYHyGx~P-7Wj-4`{{Zy{6h!KxKg;^gER3+yqyGN@I>m@kYRx7bv~}hj%{?ojZPfH1MIMRPud!kFQ?>?vdKm9;%lhRgcf4n48hQxsr#NOQ% z#SoVo@(m}=pBbs#BA^nt;NAi{!Xk#i>Cwd}cNA+;2hDdP3zM`P`T1|ou{|_dI79LO z0OcGT{ID2RH}45OmsC|i+3q%01=4Hh3fZQN%BLXe>lEOiQ9l`}fD|qQ!k&jPnu1t})XJI7RUGNgO+tYu+lAW7H3r*NGQ{{UEVx94u>^ySXVd?6n(=Po2P zC=eT`Y<9-XWwWUeq7hALn~lVs8RJ3WRK+rawlxpxa5aqlqu9ro9|GYu&sm7OAt6n? zxZOCh3<+YC{NVZ!a8(UeA8_tKwTWz7r(jAQ&5*a{bNiU4#^Po4&E4x?W30YE*C?SjO=Y1PMmrNtz>(GAEh zO_!i&dg`X_$Z1VTtOc`{VY}cY*rkG_aNZ;Yomu|?jP2z7m^GEx~{{RMS z2|u*{S|>qrh^aj{FWRla0gzg(09FAg09PMKfoq~PP&jTh0B`lRL$LOvuQJPtw+;-j zc7xeLa9xy*C^v;P&Np@I^Zx*OWxASxTmdmy%4*5+?p>e)Z1(^kxNULlfPDV|-*_bv zl5(&Us}fL)LJe8mVXs)FY9NAwN4Z8chW`K)h$}KqQ|N#N+3I3E)ZwumQH_^S z#PFvdl{?uY4%EX7E%KAmX^xy|yAL!=O?pFLPCciFqx~qCe;AmB$p!%up^Bl+hReyw z@NZZKuB}^+miMlv2h^#c9iUTUd-%f;oE*MUZw&)O20>L<33dqh4-DNJs5yZ#()otW z+V0Z$H|$5)rWw@QoFZz4wdR*CloW!4ih+GIdu@Dz1S!1|gWN0Ft4JGVpez(n!gzF2 zBU%7Px|kVKRqP-A_{ZBGLZ%5#V1uw3d#2UsHWq~tSzE`U{)S!EEz{|l{g@L3lPC9Q z?8iV*YI+?HkUv=-$+T^Ro>dK4tL(e_n$sAUfVedjuy*8lrQ@hKEO{H?u`5`rgYLi< zQZRD>NL`2aEyC0$46n4Z*o5^$-sj3jJfb=g2f)TN;AvrB`O3Czf#1A|6s)!I6px zS9-$;A>((8;iih9@e+mW0*T+HZK#`IMEJye66m8<+avqLqtdztPk|qiOcK!bG%hY+ zByX?x{{RLQSu>IdU-`&J5lV9P(y46WFlS0BQ=}K(g|in^J^OHuhyhGra)!83wr^T| z@({&9X8;2p^3-`iUAS}KF$skV+o7chF2~2J(KS`q-XGZn)0L7S@6Yj+Plf)m+-A@9 z%&mhKl7;(|=UCMY1$EMRL#U6O%FM{>0byxJ^OPWm9fBgrX-V!o z<7C002BBanOR9sWiRE_cO4!GT%e{CbXLo$QLK$g$75Y=B-5WWWg0OS7vpW#RN{{U7J4v^)- zlt8ttt}8YDUEvu7e)~!ioGDX=D7hIlz&Qh6ox;T=VWdXY1*J+?dEqFo27dj&E*|uW zi=oy*D3Uw;vSa`5^De7(6F4!TB~$1iCr8xS6*V-c#7?*@m1i!BD;Kh4ZuDd!j6j>Of4r_` zcf3Stv(fGXk^BiHaRi&M-bc$5LB5!RpfrLHUew+!L2*#(pAVnB zXKid+fFKb85yujNX$GEeZwzGcQ1VFr_xW*Bg)OaL^Nau%LvAeA3JwT*ik(M3Go>?+ zl*@<&Xr{2ZuUdN7&_>TN3pRox*TPnv!8+B~ z#`&G$+CZ?OETQI3XA|q;#3^if=6i=)wQ<1h58hoG3sNGSD-x*NhLa+C;ghx*O655wFxM^h9k(r@g; z)V&AHCADCdJDeu9^Xb8;vevgZa`Na^=i>vCErJC6xTdh;N3EuGO^2tm7Z`jJ;Vh{1 zjkg42a25$j5JJ1|H8P5RPx{zf-ju(*2r8!9-}RT^YrOsC0O5K@#>`MY0hUomd>z=0 z@jqD!-(~yd5vV^XaU(>j+{Hz9Nc#T(xv zr!!Ivx;9zppS68*MWnV(##b7no7X2+pVqG%7$CE36`tD)1sD z3`Z9~A<(vx0J|+jx``H!63VSZ;}{he?8TIcy8Y);R)h8N^M$#>Lux1?6VftgGm_|K zBLYgN0T!p4h{}OWb%1bz*Fo;2(^%KAAQ?V8Tfz@R)8Q&2So& z!EUU;s+iO&t9xj%NS5xGSpb1He+!B6{>Cw=6RaU)uZK_G1RX3liU+^8ZN&p?)9V{j zd>Ei`gTMumz^lK7<#*n^#E##PhurrxnZhUotnffG6u1x4=_d~AeC2flAkq5&09mNd zH_+>Oc}61HXTQJlV6wH_^^>S>bL|k&Hdr$xx5!Wxbs+6kx|B|sDh`+-1qT33VL_@= zh!K1+<%O?=QUHMe08zVs3}S@{F?}3nP!393zZ+cw%le5p=u4EyYr#p$V72p}a+h9y3U5`F-U^HZ$6{w{n@Jo)nzy|i$w2m!T zNW*Xh!9(5jTV4$gHp&JY?tyP)3@ITPLIv6)PCyRN(PG+=mIHx4=^7G}9|3sL`n{2E zv`bMd`ODUa6suZ@E}Ttb#h?^HglJLh+YQ0KOePm#6L5B+P-;?lUS7G zYJ3PCC^~mG-MuOIQ9sr16tUI?`Kg758Iz%{!lGMFI4U*M@0?*un^!wPWm70wQ8HY0FuT5<34z|Y znn_1Sk+H(ohL?KAXWmgq+0zz*4}W+op>RW9d|u;LgiB{!VB^(Czc_WXI$b{Tt!?k0k&JZYC?uRbLJwM{E&-KM41fqDN$w1Oo6J<3IeV53 z)gk;X1EYVQCgC~Uu1Nl7MT60!Jwiu#3aJWRxCqcy6$p_;HYN)bt9*cNLXe1Dll>yr zsZD)Ljh_VEt?I~i7i^o#jfA{JgS2tI8^F?=j9?3f`iS!y>p&Wi@`b(}oeB+Q8`;@= zt>K}0a=L>su~SVIW1T*ZL0uEmRG4N10>C2X71RJ>!nYnk&!;bK?;_`6V3D;q5?AHJ z*XY79sC||Pm@vqbPfFQs-kO-unC(`Ipb&U0Fi16!0w4?1v{MqX8GA!)m=adBxQ_9R z0q#qML0oUb6D2iVj9Ci7(&S-|i$5QjO>7`F)#fV(sRQM5O>vC-!mUMi;TJL@&t@PPs1zBJ zMHJD6mI`c>BH5|HHV*83u4$A10Bb7Gma*5M6XC>xZRz#%fYa5yz`#CN!7=+_+M}Tz zU<^^Ncu`#_Seam39uy|Z$t7U2b<}hms|1EyCAO;IvfVq~`{@d6?Zb*5u9hGw3Z%FK zMyrKN#V9*7nEwD)I4r-0z3p;Dh=wKlhMuJE7%PTP0+xUA$3Qf202;o#v_7%D10l97 zU0zoJh)M%rcueCs`ZfJH79M$g{{YqeIG+uYl8a-O5qvQ??c(Bn0_13D9^(O z`N8S3U2BtjFbKFUB_D9pf5!5vTPP(#+iQT!k3qJ{DjwAj*K<|4E~Fubt-o8lv)T^m zGUOwzBYtsWHSKIj?p1zfSr(xSXQ8Y$OVywO0k+^%q;8tWLsh6bn`lyQCO?opvw30y zIfYk62h6ZAus{H5tUAXXHmN^ml<#HZ*a(!y>lR!1>{u?`cnZpMyvQ^i52ZJTc!&w< zjPq*#CIxV$#FsW7E_a8!J9AG0baxV`$N`h-QMGJY{&M9sqMR%t5Hi{(3S?1iK@0nG zyo007tQs0`oWyNxq)i$sKQ1U@Z~i9}87G*(t>YR@_<4g`D~mUPg4g2X^ai(z9HHOK zEC9#Bk71*s*?u!}weRG(W1!l4T%60K4(r#f_gI}PKYF^#UAN-k!TU7CQA0pu)Xf3h z8+xVyNaQqAEuk1_O{_HGmRF_@oI9dzW)_y2pQ=XP&9UY&bjex(@f$&)oHNfP-ArLE zDUQnNyubGmC5N8(5~(VVkQEPo%l9Hk?^PP#{&LCtvJr(xTak5~a6m-Gs4Ln-nBU9k zqP85f)F??=_(3PKz(o|$ypf=s&>k5U~;0n46D|uV=@cwX*L9=Lg3KQ~U z0pg!{7m76w+^Z>Ob7xaw+0EpZwOZp2jgPW_)(W&}Q}r$wDRH!JT_k#TE1tRk08_bT ze4=DwIjEuMw@v!TTeJjI-BnLRh!s|xvOSg%YT^n{h*_ixPX-LKX zLKT$iZ@JuIY1;UVQ~}^cZu9u+@P`M)0LWX&`+7^c^vr9(LO1osTRd-6K7q@?p9T7< zF-tm4c&i7@Eavd@!6up-GuW=qf&_q|fJ6W^2O)@_uKvwoRt9v$jiiwC7J@cUoNm>6 zB%fb?=CrR865v3Cr1$F>fxc1${_s>RU7tC-S)rE{0h`E8 zYss3Zwt}B=h~}W!&zf~RjEJRbP_zdtxYT2DxB`JD z{xXMMs6WQ2_)Xxe3h(oRy8fEPJZ?Na`*8_?C^@`!J5yd{KtZ-i%80gr`~Lup5D*F@ zBK>2yqSBuyxM=z(?T7#XRejGwSQSx0MOdIhV;q6~andoNTSnY_!EBQ|aRXpg412QC z0VV4g3spp-Pqj+f8xm_w-fOcZj3>u1bm=x1+eLuw+9gx~^@nM0VAG)U6YVZJBBWS?kdE$cidX5?%_S%7zJ}n{V{sG z8YvEF9HCvX1>$nWKp{SIh@?UK1O6}rCv8g-2yCz6nx~BbI?!}b66-*lpfoTFYK7*q zw2T~pZY^kHgBb`N1UgIp%;YsEFI998-Xe`6-K;_u1cIw{HTd}IqJSw)223KQ8*KP6 z)xJF*oqZmBVhEW88H{%Cd%!^C1czq(HJ2Yy-wwM{pKIq0?O>LuN+?&<>x0ciUj%1I zf|GYiOQZ6_9d+s7;37{Da2sL0(*#8Q$~pLplqssyFmN{dxC*umIlmkofjV&&q7KiD zsFpXC#YdZ)`N)-rhm0|T0Yw3RnkPX47?M$OfJ~^c6HG7UI1LaJKmqlWY|A9EIT(|Z zShIal5cb>^T_T1eo2D+vX6sr9GsL=p>=`f}mMX#~_x^EcrVlvdP$DOpd!HORnqqz2 z=wc@huXm^8>knb>{{XxocMpZfX0j?BX4C?ZKD@!S5s-Eo7vwPpZtXmgmv)B0UM}tZ}f`=G*xo9@~L~2WAtXQvOMhdYz}m`og?P zF0w|JPQVmci}TH9)nQ;|bfCLWxs7&E83GYjo3SgE`LfFP`4AVuVyd2m11Ajhx}nt> ztH6)RmHxHv#tGK8y$@K#3Z{)*bPtNa-cS_x_>b8RNDUi7J-HMv-z364HJ1XZy6wY^ zX|?h5o0K`@5Q1ym5~0AD2rEf}PU$us$~-LqZGu0Wf2=E2sV&3-Uk>u@Z6tVn0ipGI zf*yB)uxM;Sq6p-eYg{9)kFTFNdV$dZsJ-Q-`PLd@)Wu=3{2lnsv5oi7yg?8rfBrC9 zLgv0-f1C!z2e^U|$8O2`xFAFKn17T8G^3I6guKqtXv<;u@mq*=6Mqq0KfqFB_W&zP7GkkoGOZF|P(q z{bZ%2lw2(7X5lfJFb%jF{=G-SSW+7b;9$1g5fxQAtw6|B0IDOfU+W19S0zM&RvN2q zfdMcg^XZ~io0bF-SQNW%*Qu;@AuM%~ogM2S`U~qAM-Fe8U>1w~u)cSNBXpgsdNQYE z!A-UmorHA8YE`x*ec`W+ib(6JXgnzwXkT(Fx2)Z-{{T3~)AsNEn4+ga&A|~$(gDLI zS5dYuj+GeD!=i*5NACXs#uTAe1+=2G0`NZY_K&1{6Q|xZw0@6*5k(LwLC0e(Ujehp z9|^S9P#T0Kr!8%3<$IHG%-I||NC?uT#IG=GO**0y1&$H*r5(OcV1f`PD~v_3KBW}^ z>?~(=ugQX?wa2&kT+SRaUH<@ip;hIC!I}9bg8Coa#OnB9EF%_{kZ(yx@5#nBVe^Q%i5&@T2s=OSaGHF zHf`@5K`r2c(eq2M-NtHg8lw{LXr~CLfFJ&kBDdg$zgX@xMS5v($L!4=9k$^G+Zrwe zS66im4&xtPf6i3#*>F(rtJF>%z{9dEx=Ua(c$m#d?%|p(Z`|e>XvGI{I5$}Rubk9R zVC&$`LPbYuf1G16eO*>^1W&djWuzbF;*8csB1iG6yF4?!wTBUF3P3i6;e?bTDwmve zd{ZM;;||vU0H5=QqH1z`j4jf*2GIlOm|_S!y>J1kbT2M)oAdFSRNKrcqfXD@y*<=s%1#GQoQe)qhy8;)%PNY0yM>gT z8p3FrXfvl6u6yusMN3Kzn_xl`Uvo|KTPO$s}O z^%IFLfV(uH!>d;Y@Zg;j_ph4p<{L^!Z`|oLNNX4^7>i#{mFeiiUcI3@H)d*jBoH zTicB=O$v~v)7(GSH0=vTI_r4{?==Jn$(AXG(9Rjnx!I(V3YT%AM*yKW7)PKQjWw2z ziC+`uq$*ZKN* zaW_!KfXIq22b(DhS|=jMysVj)t8(oCh9v=Hm=x)dUDZT9?)GhN@_o+hHzluT08?yL zC^egzbDT3fa%2m5UWNwXkt^whD^B(?GQsSrFgAm;gdbRpu9terNIFF0@rV`mG+B%E z_(>cyrSfuNW!Yn_p`sdVk))$R`pZIZhtdB47i$j-iZaP#F#L*9X=?+IP$H1!-D28s z^a53^1@b$0KmdgWrPRtie=;J`C<1F};0OM*fl&&IAn{x#6TRcU(xV$3Okh^)A)6tI z4Gw{o^xPmqL#(IXMQSgXF3FFdIUe>p)=&y0`0ff2*#zf#uE6xTfkKNkU;QzOL0)`g zMG9B#yk*>GtH%JFEUT2jN2=TrgF@b;uknNccvH+^MyP|Q?-2l^HFt?;UNjt6q;Hr6 zU`_1r)-e7+Vu%)o`vsUr+MtU9D}hU(Abd{BEE-r+3seF$+=byzV9{NTs<{ZX8eTbC zWjFB0(ULl|7y$HE2j$BFR^kW8L>km>!?}dDDziabb#aJ;q7Rcwh+Uu|gAwSgB7qoz zK`mvvQy$G$v1)({p@PLc`Y*sd3Rp)9KBB`q2{gk^lNIC_k7J{HJZ@or23iFTC-5W8 zG*AyjQ8Ez#CFtRyg*d{R#7Cas(S4?_SB!&NX+j7fL_s!SFZsh1L9GCv=LX1(9>5Gi z*qC1wvduQLRepc~35(}cNWdlwq{L?F!l5#zz*#8_P?{#oF#{?O4=`uYLl7RvTJ8rR zZGxjr9tYzRCJt{PyBYKU0KXVDK3O(aU=Uq=%t#UYWgvrBd&9KDE8#hpVK%fjI-m23 zsB1OuJkVRG1rb#L06D5G9oB8PhV{FOv;)oJI&(syhl=X<9~h4)tffeHk62tUzwH(y zWJYWn{09F31$YDcYx>5JsrYWpHXTbcps;(6)QXw%Vs}XG-f%+v3N?)SKVPgmQ(Xno zlk3K5SL_4k52Z?rm=IFBVk968rJqf=a+?bCBT&A=z=z~2oqK(=?qx+_pq0V}kIg

-02`e5G1IA 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 diff --git a/boards/arm/gd32f450v_start/doc/img/gd32f450v_start.webp b/boards/arm/gd32f450v_start/doc/img/gd32f450v_start.webp new file mode 100644 index 0000000000000000000000000000000000000000..f76c58206b30c0cfe5758d21d64e546fc9d7be56 GIT binary patch literal 37702 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

UYGU%0l2=ihE(9pGWHj$!EbY-?mNO@ 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 diff --git a/boards/arm/gd32f450z_eval/doc/img/gd32f450z_eval.webp b/boards/arm/gd32f450z_eval/doc/img/gd32f450z_eval.webp new file mode 100644 index 0000000000000000000000000000000000000000..be33bd01263e67ecaee133789ce9c4ffce6895d0 GIT binary patch literal 79346 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 Y00000X!C&!qyzd3qc-3G000000LZp_Pyhe` literal 0 HcmV?d00001 diff --git a/boards/arm/gd32f450z_eval/doc/index.rst b/boards/arm/gd32f450z_eval/doc/index.rst index 179886cd0db..0e31f262db3 100644 --- a/boards/arm/gd32f450z_eval/doc/index.rst +++ b/boards/arm/gd32f450z_eval/doc/index.rst @@ -13,7 +13,7 @@ The GD32F450ZK features a single-core ARM Cortex-M4F MCU which can run up to 200 MHz with flash accesses zero wait states, 3072kiB of Flash, 256kiB of SRAM and 114 GPIOs. -.. image:: img/gd32f450z_eval.jpg +.. image:: img/gd32f450z_eval.webp :align: center :alt: gd32f450z_eval From ba52701630a27d11c6ea7d6623fd24facd0d7d3d Mon Sep 17 00:00:00 2001 From: Gerard Marull-Paretas Date: Tue, 2 Jan 2024 12:36:28 +0100 Subject: [PATCH 2012/3723] drivers: counter: gd32: depend on !SOC_SERIES_GD32VF103 Because SOC_FAMILY_GD32_ARM is going to be dropped soon. Signed-off-by: Gerard Marull-Paretas --- drivers/counter/Kconfig.gd32 | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/counter/Kconfig.gd32 b/drivers/counter/Kconfig.gd32 index eb5d5897af2..fcb8913434e 100644 --- a/drivers/counter/Kconfig.gd32 +++ b/drivers/counter/Kconfig.gd32 @@ -6,7 +6,7 @@ config COUNTER_TIMER_GD32 bool "GD32 timer counter driver" default y - depends on DT_HAS_GD_GD32_TIMER_ENABLED && SOC_FAMILY_GD32_ARM + depends on DT_HAS_GD_GD32_TIMER_ENABLED && !SOC_SERIES_GD32VF103 select USE_GD32_TIMER help Enable counter timer driver for GD32 series devices. From d4838ed57e651f5b329f6674d5d0865e0665ada8 Mon Sep 17 00:00:00 2001 From: Gerard Marull-Paretas Date: Tue, 2 Jan 2024 13:53:46 +0100 Subject: [PATCH 2013/3723] boards: gd32f450i_eval: remove unused Kconfig Board no longer has init code. Signed-off-by: Gerard Marull-Paretas --- boards/arm/gd32f450i_eval/Kconfig | 8 -------- 1 file changed, 8 deletions(-) delete mode 100644 boards/arm/gd32f450i_eval/Kconfig diff --git a/boards/arm/gd32f450i_eval/Kconfig b/boards/arm/gd32f450i_eval/Kconfig deleted file mode 100644 index ec5800eae97..00000000000 --- a/boards/arm/gd32f450i_eval/Kconfig +++ /dev/null @@ -1,8 +0,0 @@ -# Copyright (c) 2021 Teslabs Engineering S.L. -# SPDX-License-Identifier: Apache-2.0 - -config BOARD_INIT_PRIORITY - int "Board initialization priority" - default 50 - help - Board initialization priority. From 5b3dd2288eb3dc7255683cb38fdbb467530300fb Mon Sep 17 00:00:00 2001 From: Gerard Marull-Paretas Date: Tue, 2 Jan 2024 17:53:44 +0100 Subject: [PATCH 2014/3723] boards: gd32f403z_eval: remove redundant Kconfig Board does not have any init code, so BOARD_INIT_PRIORITY is redundant. Signed-off-by: Gerard Marull-Paretas --- boards/arm/gd32f403z_eval/Kconfig | 8 -------- 1 file changed, 8 deletions(-) delete mode 100644 boards/arm/gd32f403z_eval/Kconfig diff --git a/boards/arm/gd32f403z_eval/Kconfig b/boards/arm/gd32f403z_eval/Kconfig deleted file mode 100644 index 5630f4bbf05..00000000000 --- a/boards/arm/gd32f403z_eval/Kconfig +++ /dev/null @@ -1,8 +0,0 @@ -# Copyright (c) 2021 ATL-Electronics -# SPDX-License-Identifier: Apache-2.0 - -config BOARD_INIT_PRIORITY - int "Board initialization priority" - default 50 - help - Board initialization priority. From f74c14537ada144fe8e11205c61e33e1f4c8afa3 Mon Sep 17 00:00:00 2001 From: Ali Hozhabri Date: Fri, 5 Jan 2024 17:59:33 +0100 Subject: [PATCH 2015/3723] dts: bindings: bluetooth: Include zephyr,bt-hci-spi.yaml Include zephyr,bt-hci-spi.yaml in both ST HCI SPI yaml files. Signed-off-by: Ali Hozhabri --- dts/bindings/bluetooth/st,hci-spi-v1.yaml | 2 ++ dts/bindings/bluetooth/st,hci-spi-v2.yaml | 2 ++ 2 files changed, 4 insertions(+) diff --git a/dts/bindings/bluetooth/st,hci-spi-v1.yaml b/dts/bindings/bluetooth/st,hci-spi-v1.yaml index d61b936c5b6..3784c88ded0 100644 --- a/dts/bindings/bluetooth/st,hci-spi-v1.yaml +++ b/dts/bindings/bluetooth/st,hci-spi-v1.yaml @@ -4,3 +4,5 @@ description: STMicroelectronics SPI protocol V1 compatible with BlueNRG-MS devices compatible: "st,hci-spi-v1" + +include: zephyr,bt-hci-spi.yaml diff --git a/dts/bindings/bluetooth/st,hci-spi-v2.yaml b/dts/bindings/bluetooth/st,hci-spi-v2.yaml index 58e91e496e2..36b25eae768 100644 --- a/dts/bindings/bluetooth/st,hci-spi-v2.yaml +++ b/dts/bindings/bluetooth/st,hci-spi-v2.yaml @@ -4,3 +4,5 @@ description: STMicroelectronics SPI protocol V2 compatible with BlueNRG-1 and successor devices compatible: "st,hci-spi-v2" + +include: zephyr,bt-hci-spi.yaml From 98d6dbf787e7a71f8fe182f1581e5f9d97025a0d Mon Sep 17 00:00:00 2001 From: Ali Hozhabri Date: Fri, 5 Jan 2024 18:08:16 +0100 Subject: [PATCH 2016/3723] drivers: bluetooth: hci: Add Bluetooth driver for ST HCI SPI protocol Copy ST specific SPI protocol code from spi.c to a vendor specific file. Signed-off-by: Ali Hozhabri --- drivers/bluetooth/hci/hci_spi_st.c | 594 +++++++++++++++++++++++++++++ 1 file changed, 594 insertions(+) create mode 100644 drivers/bluetooth/hci/hci_spi_st.c diff --git a/drivers/bluetooth/hci/hci_spi_st.c b/drivers/bluetooth/hci/hci_spi_st.c new file mode 100644 index 00000000000..605e36e56a6 --- /dev/null +++ b/drivers/bluetooth/hci/hci_spi_st.c @@ -0,0 +1,594 @@ +/* hci_spi_st.c - STMicroelectronics HCI SPI Bluetooth driver */ + +/* + * Copyright (c) 2017 Linaro Ltd. + * Copyright (c) 2024 STMicroelectronics + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#if defined(CONFIG_DT_HAS_ST_HCI_SPI_V1_ENABLED) +#define DT_DRV_COMPAT st_hci_spi_v1 + +#elif defined(CONFIG_DT_HAS_ST_HCI_SPI_V2_ENABLED) +#define DT_DRV_COMPAT st_hci_spi_v2 + +#endif /* CONFIG_DT_HAS_ST_HCI_SPI_V1_ENABLED */ + +#include +#include +#include +#include +#include + +#include +#include + +#define LOG_LEVEL CONFIG_BT_HCI_DRIVER_LOG_LEVEL +#include +LOG_MODULE_REGISTER(bt_driver); + +#define HCI_CMD 0x01 +#define HCI_ACL 0x02 +#define HCI_SCO 0x03 +#define HCI_EVT 0x04 + +/* Special Values */ +#define SPI_WRITE 0x0A +#define SPI_READ 0x0B +#define READY_NOW 0x02 + +#define EVT_BLUE_INITIALIZED 0x01 + +/* Offsets */ +#define STATUS_HEADER_READY 0 +#define STATUS_HEADER_TOREAD 3 +#define STATUS_HEADER_TOWRITE 1 + +#define PACKET_TYPE 0 +#define EVT_HEADER_TYPE 0 +#define EVT_HEADER_EVENT 1 +#define EVT_HEADER_SIZE 2 +#define EVT_LE_META_SUBEVENT 3 +#define EVT_VENDOR_CODE_LSB 3 +#define EVT_VENDOR_CODE_MSB 4 + +#define CMD_OGF 1 +#define CMD_OCF 2 + +#define SPI_MAX_MSG_LEN 255 + +/* Single byte header denoting the buffer type */ +#define H4_HDR_SIZE 1 + +/* Maximum L2CAP MTU that can fit in a single packet */ +#define MAX_MTU (SPI_MAX_MSG_LEN - H4_HDR_SIZE - BT_L2CAP_HDR_SIZE - BT_HCI_ACL_HDR_SIZE) + +#if CONFIG_BT_L2CAP_TX_MTU > MAX_MTU +#warning CONFIG_BT_L2CAP_TX_MTU is too large and can result in packets that cannot \ + be transmitted across this HCI link +#endif /* CONFIG_BT_L2CAP_TX_MTU > MAX_MTU */ + +static uint8_t rxmsg[SPI_MAX_MSG_LEN]; +static uint8_t txmsg[SPI_MAX_MSG_LEN]; + +static const struct gpio_dt_spec irq_gpio = GPIO_DT_SPEC_INST_GET(0, irq_gpios); +static const struct gpio_dt_spec rst_gpio = GPIO_DT_SPEC_INST_GET(0, reset_gpios); + +static struct gpio_callback gpio_cb; + +static K_SEM_DEFINE(sem_initialised, 0, 1); +static K_SEM_DEFINE(sem_request, 0, 1); +static K_SEM_DEFINE(sem_busy, 1, 1); + +static K_KERNEL_STACK_DEFINE(spi_rx_stack, CONFIG_BT_DRV_RX_STACK_SIZE); +static struct k_thread spi_rx_thread_data; + +#if defined(CONFIG_BT_BLUENRG_ACI) +#define BLUENRG_ACI_WRITE_CONFIG_DATA BT_OP(BT_OGF_VS, 0x000C) +#define BLUENRG_CONFIG_PUBADDR_OFFSET 0x00 +#define BLUENRG_CONFIG_PUBADDR_LEN 0x06 +#define BLUENRG_CONFIG_LL_ONLY_OFFSET 0x2C +#define BLUENRG_CONFIG_LL_ONLY_LEN 0x01 + +static int bt_spi_send_aci_config(uint8_t offset, const uint8_t *value, size_t value_len); +#endif /* CONFIG_BT_BLUENRG_ACI */ + +static const struct spi_dt_spec bus = SPI_DT_SPEC_INST_GET( + 0, SPI_OP_MODE_MASTER | SPI_TRANSFER_MSB | SPI_WORD_SET(8), 0); + +static struct spi_buf spi_tx_buf; +static struct spi_buf spi_rx_buf; +static const struct spi_buf_set spi_tx = { + .buffers = &spi_tx_buf, + .count = 1 +}; +static const struct spi_buf_set spi_rx = { + .buffers = &spi_rx_buf, + .count = 1 +}; + +static inline int bt_spi_transceive(void *tx, uint32_t tx_len, + void *rx, uint32_t rx_len) +{ + spi_tx_buf.buf = tx; + spi_tx_buf.len = (size_t)tx_len; + spi_rx_buf.buf = rx; + spi_rx_buf.len = (size_t)rx_len; + return spi_transceive_dt(&bus, &spi_tx, &spi_rx); +} + +static inline uint16_t bt_spi_get_cmd(uint8_t *msg) +{ + return (msg[CMD_OCF] << 8) | msg[CMD_OGF]; +} + +static inline uint16_t bt_spi_get_evt(uint8_t *msg) +{ + return (msg[EVT_VENDOR_CODE_MSB] << 8) | msg[EVT_VENDOR_CODE_LSB]; +} + +static void bt_spi_isr(const struct device *unused1, + struct gpio_callback *unused2, + uint32_t unused3) +{ + LOG_DBG(""); + + k_sem_give(&sem_request); +} + +static bool bt_spi_handle_vendor_evt(uint8_t *msg) +{ + bool handled = false; + + switch (bt_spi_get_evt(msg)) { + case EVT_BLUE_INITIALIZED: { + k_sem_give(&sem_initialised); +#if defined(CONFIG_BT_BLUENRG_ACI) + /* force BlueNRG to be on controller mode */ + uint8_t data = 1; + + bt_spi_send_aci_config(BLUENRG_CONFIG_LL_ONLY_OFFSET, &data, 1); +#endif + handled = true; + } + default: + break; + } + return handled; +} + +#define IS_IRQ_HIGH gpio_pin_get_dt(&irq_gpio) + +#if DT_HAS_COMPAT_STATUS_OKAY(st_hci_spi_v1) + +/* Define a limit when reading IRQ high */ +#define IRQ_HIGH_MAX_READ 15 + +/* On BlueNRG-MS, host is expected to read */ +/* as long as IRQ pin is high */ +#define READ_CONDITION IS_IRQ_HIGH + +static void assert_cs(void) +{ + gpio_pin_set_dt(&bus.config.cs.gpio, 0); + gpio_pin_set_dt(&bus.config.cs.gpio, 1); +} + +static void release_cs(bool data_transaction) +{ + ARG_UNUSED(data_transaction); + gpio_pin_set_dt(&bus.config.cs.gpio, 0); +} + +static int bt_spi_get_header(uint8_t op, uint16_t *size) +{ + uint8_t header_master[5] = {op, 0, 0, 0, 0}; + uint8_t header_slave[5]; + uint8_t size_offset, attempts; + int ret; + + if (op == SPI_READ) { + if (!IS_IRQ_HIGH) { + *size = 0; + return 0; + } + size_offset = STATUS_HEADER_TOREAD; + } else if (op == SPI_WRITE) { + size_offset = STATUS_HEADER_TOWRITE; + } else { + return -EINVAL; + } + attempts = IRQ_HIGH_MAX_READ; + do { + if (op == SPI_READ) { + /* Keep checking that IRQ is still high, if we need to read */ + if (!IS_IRQ_HIGH) { + *size = 0; + return 0; + } + } + assert_cs(); + ret = bt_spi_transceive(header_master, 5, header_slave, 5); + if (ret) { + /* SPI transaction failed */ + break; + } + + *size = (header_slave[STATUS_HEADER_READY] == READY_NOW) ? + header_slave[size_offset] : 0; + attempts--; + } while ((*size == 0) && attempts); + + return ret; +} + +#elif DT_HAS_COMPAT_STATUS_OKAY(st_hci_spi_v2) + +#define READ_CONDITION false + +static void assert_cs(uint16_t delay) +{ + gpio_pin_set_dt(&bus.config.cs.gpio, 0); + if (delay) { + k_sleep(K_USEC(delay)); + } + gpio_pin_set_dt(&bus.config.cs.gpio, 1); + gpio_pin_interrupt_configure_dt(&irq_gpio, GPIO_INT_DISABLE); +} + +static void release_cs(bool data_transaction) +{ + /* Consume possible event signals */ + while (k_sem_take(&sem_request, K_NO_WAIT) == 0) { + } + if (data_transaction) { + /* Wait for IRQ to become low only when data phase has been performed */ + while (IS_IRQ_HIGH) { + } + } + gpio_pin_interrupt_configure_dt(&irq_gpio, GPIO_INT_EDGE_TO_ACTIVE); + gpio_pin_set_dt(&bus.config.cs.gpio, 0); +} + +static int bt_spi_get_header(uint8_t op, uint16_t *size) +{ + uint8_t header_master[5] = {op, 0, 0, 0, 0}; + uint8_t header_slave[5]; + uint16_t cs_delay; + uint8_t size_offset; + int ret; + + if (op == SPI_READ) { + if (!IS_IRQ_HIGH) { + *size = 0; + return 0; + } + cs_delay = 0; + size_offset = STATUS_HEADER_TOREAD; + } else if (op == SPI_WRITE) { + /* To make sure we have a minimum delay from previous release cs */ + cs_delay = 100; + size_offset = STATUS_HEADER_TOWRITE; + } else { + return -EINVAL; + } + + assert_cs(cs_delay); + /* Wait up to a maximum time of 100 ms */ + if (!WAIT_FOR(IS_IRQ_HIGH, 100000, k_usleep(100))) { + LOG_ERR("IRQ pin did not raise"); + return -EIO; + } + + ret = bt_spi_transceive(header_master, 5, header_slave, 5); + *size = header_slave[size_offset] | (header_slave[size_offset + 1] << 8); + return ret; +} +#endif /* DT_HAS_COMPAT_STATUS_OKAY(st_hci_spi_v1) */ + +#if defined(CONFIG_BT_BLUENRG_ACI) +static int bt_spi_send_aci_config(uint8_t offset, const uint8_t *value, size_t value_len) +{ + struct net_buf *buf; + uint8_t *cmd_data; + size_t data_len = 2 + value_len; + + buf = bt_hci_cmd_create(BLUENRG_ACI_WRITE_CONFIG_DATA, data_len); + if (!buf) { + return -ENOBUFS; + } + + cmd_data = net_buf_add(buf, data_len); + cmd_data[0] = offset; + cmd_data[1] = value_len; + memcpy(&cmd_data[2], value, value_len); + + return bt_hci_cmd_send(BLUENRG_ACI_WRITE_CONFIG_DATA, buf); +} + +static int bt_spi_bluenrg_setup(const struct bt_hci_setup_params *params) +{ + int ret; + const bt_addr_t *addr = ¶ms->public_addr; + + if (!bt_addr_eq(addr, BT_ADDR_NONE) && !bt_addr_eq(addr, BT_ADDR_ANY)) { + ret = bt_spi_send_aci_config( + BLUENRG_CONFIG_PUBADDR_OFFSET, + addr->val, sizeof(addr->val)); + + if (ret != 0) { + LOG_ERR("Failed to set BlueNRG public address (%d)", ret); + return ret; + } + } + + return 0; +} +#endif /* CONFIG_BT_BLUENRG_ACI */ + +static struct net_buf *bt_spi_rx_buf_construct(uint8_t *msg) +{ + bool discardable = false; + k_timeout_t timeout = K_FOREVER; + struct bt_hci_acl_hdr acl_hdr; + struct net_buf *buf; + int len; + + switch (msg[PACKET_TYPE]) { + case HCI_EVT: + switch (msg[EVT_HEADER_EVENT]) { + case BT_HCI_EVT_VENDOR: + /* Run event through interface handler */ + if (bt_spi_handle_vendor_evt(msg)) { + return NULL; + } + /* Event has not yet been handled */ + __fallthrough; + default: + if (msg[EVT_HEADER_EVENT] == BT_HCI_EVT_LE_META_EVENT && + (msg[EVT_LE_META_SUBEVENT] == BT_HCI_EVT_LE_ADVERTISING_REPORT)) { + discardable = true; + timeout = K_NO_WAIT; + } + buf = bt_buf_get_evt(msg[EVT_HEADER_EVENT], + discardable, timeout); + if (!buf) { + LOG_DBG("Discard adv report due to insufficient buf"); + return NULL; + } + } + + len = sizeof(struct bt_hci_evt_hdr) + msg[EVT_HEADER_SIZE]; + if (len > net_buf_tailroom(buf)) { + LOG_ERR("Event too long: %d", len); + net_buf_unref(buf); + return NULL; + } + net_buf_add_mem(buf, &msg[1], len); + break; + case HCI_ACL: + buf = bt_buf_get_rx(BT_BUF_ACL_IN, K_FOREVER); + memcpy(&acl_hdr, &msg[1], sizeof(acl_hdr)); + len = sizeof(acl_hdr) + sys_le16_to_cpu(acl_hdr.len); + if (len > net_buf_tailroom(buf)) { + LOG_ERR("ACL too long: %d", len); + net_buf_unref(buf); + return NULL; + } + net_buf_add_mem(buf, &msg[1], len); + break; + default: + LOG_ERR("Unknown BT buf type %d", msg[0]); + return NULL; + } + + return buf; +} + +static void bt_spi_rx_thread(void *p1, void *p2, void *p3) +{ + ARG_UNUSED(p1); + ARG_UNUSED(p2); + ARG_UNUSED(p3); + + struct net_buf *buf; + uint16_t size = 0U; + int ret; + + (void)memset(&txmsg, 0xFF, SPI_MAX_MSG_LEN); + while (true) { + + /* Wait for interrupt pin to be active */ + k_sem_take(&sem_request, K_FOREVER); + + LOG_DBG(""); + + do { + /* Wait for SPI bus to be available */ + k_sem_take(&sem_busy, K_FOREVER); + ret = bt_spi_get_header(SPI_READ, &size); + + /* Read data */ + if (ret == 0 && size != 0) { + ret = bt_spi_transceive(&txmsg, size, &rxmsg, size); + } + + release_cs(size > 0); + + k_sem_give(&sem_busy); + + if (ret || size == 0) { + if (ret) { + LOG_ERR("Error %d", ret); + } + continue; + } + + LOG_HEXDUMP_DBG(rxmsg, size, "SPI RX"); + + /* Construct net_buf from SPI data */ + buf = bt_spi_rx_buf_construct(rxmsg); + if (buf) { + /* Handle the received HCI data */ + bt_recv(buf); + } + } while (READ_CONDITION); + } +} + +static int bt_spi_send(struct net_buf *buf) +{ + uint16_t size; + uint8_t rx_first[1]; + int ret; + + LOG_DBG(""); + + /* Buffer needs an additional byte for type */ + if (buf->len >= SPI_MAX_MSG_LEN) { + LOG_ERR("Message too long (%d)", buf->len); + return -EINVAL; + } + + switch (bt_buf_get_type(buf)) { + case BT_BUF_ACL_OUT: + net_buf_push_u8(buf, HCI_ACL); + break; + case BT_BUF_CMD: + net_buf_push_u8(buf, HCI_CMD); + break; + default: + LOG_ERR("Unsupported type"); + return -EINVAL; + } + + /* Wait for SPI bus to be available */ + k_sem_take(&sem_busy, K_FOREVER); + + ret = bt_spi_get_header(SPI_WRITE, &size); + size = MIN(buf->len, size); + + if (size < buf->len) { + LOG_WRN("Unable to write full data, skipping"); + size = 0; + ret = -ECANCELED; + } + + if (!ret) { + /* Transmit the message */ + ret = bt_spi_transceive(buf->data, size, + rx_first, 1); + } + + release_cs(size > 0); + + k_sem_give(&sem_busy); + + if (ret) { + LOG_ERR("Error %d", ret); + return ret; + } + + LOG_HEXDUMP_DBG(buf->data, buf->len, "SPI TX"); + +#if (DT_HAS_COMPAT_STATUS_OKAY(st_hci_spi_v1) || DT_HAS_COMPAT_STATUS_OKAY(st_hci_spi_v2)) + /* + * Since a RESET has been requested, the chip will now restart. + * Unfortunately the BlueNRG will reply with "reset received" but + * since it does not send back a NOP, we have no way to tell when the + * RESET has actually taken place. Instead, we use the vendor command + * EVT_BLUE_INITIALIZED as an indication that it is safe to proceed. + */ + if (bt_spi_get_cmd(buf->data) == BT_HCI_OP_RESET) { + k_sem_take(&sem_initialised, K_FOREVER); + } +#endif /* DT_HAS_COMPAT_STATUS_OKAY(st_hci_spi_v1) || DT_HAS_COMPAT_STATUS_OKAY(st_hci_spi_v2) */ + net_buf_unref(buf); + + return ret; +} + +static int bt_spi_open(void) +{ + int err; + + /* Configure RST pin and hold BLE in Reset */ + err = gpio_pin_configure_dt(&rst_gpio, GPIO_OUTPUT_ACTIVE); + if (err) { + return err; + } + + /* Configure IRQ pin and the IRQ call-back/handler */ + err = gpio_pin_configure_dt(&irq_gpio, GPIO_INPUT); + if (err) { + return err; + } + + gpio_init_callback(&gpio_cb, bt_spi_isr, BIT(irq_gpio.pin)); + err = gpio_add_callback(irq_gpio.port, &gpio_cb); + if (err) { + return err; + } + + /* Enable the interrupt line */ + err = gpio_pin_interrupt_configure_dt(&irq_gpio, GPIO_INT_EDGE_TO_ACTIVE); + if (err) { + return err; + } + + /* Take BLE out of reset */ + k_sleep(K_MSEC(DT_INST_PROP_OR(0, reset_assert_duration_ms, 0))); + gpio_pin_set_dt(&rst_gpio, 0); + + /* Start RX thread */ + k_thread_create(&spi_rx_thread_data, spi_rx_stack, + K_KERNEL_STACK_SIZEOF(spi_rx_stack), + bt_spi_rx_thread, NULL, NULL, NULL, + K_PRIO_COOP(CONFIG_BT_DRIVER_RX_HIGH_PRIO), + 0, K_NO_WAIT); + + /* Device will let us know when it's ready */ + k_sem_take(&sem_initialised, K_FOREVER); + + return 0; +} + +static const struct bt_hci_driver drv = { + .name = DEVICE_DT_NAME(DT_DRV_INST(0)), + .bus = BT_HCI_DRIVER_BUS_SPI, +#if defined(CONFIG_BT_BLUENRG_ACI) + .quirks = BT_QUIRK_NO_RESET, + .setup = bt_spi_bluenrg_setup, +#endif /* CONFIG_BT_BLUENRG_ACI */ + .open = bt_spi_open, + .send = bt_spi_send, +}; + +static int bt_spi_init(void) +{ + + if (!spi_is_ready_dt(&bus)) { + LOG_ERR("SPI device not ready"); + return -ENODEV; + } + + if (!gpio_is_ready_dt(&irq_gpio)) { + LOG_ERR("IRQ GPIO device not ready"); + return -ENODEV; + } + + if (!gpio_is_ready_dt(&rst_gpio)) { + LOG_ERR("Reset GPIO device not ready"); + return -ENODEV; + } + + bt_hci_driver_register(&drv); + + + LOG_DBG("BT SPI initialized"); + + return 0; +} + +SYS_INIT(bt_spi_init, POST_KERNEL, CONFIG_BT_SPI_INIT_PRIORITY); From 8b8be3c7aa6e03c0c895ac4f9d928fb789bb3390 Mon Sep 17 00:00:00 2001 From: Ali Hozhabri Date: Fri, 5 Jan 2024 18:11:05 +0100 Subject: [PATCH 2017/3723] drivers: bluetooth: hci: Remove ST vendor code from spi.c Remove ST vendor code from spi.c. Update CMakeLists to select ST vendor file for ST BlueNRG devices. Signed-off-by: Ali Hozhabri --- drivers/bluetooth/hci/CMakeLists.txt | 8 +- drivers/bluetooth/hci/spi.c | 283 ++++----------------------- 2 files changed, 40 insertions(+), 251 deletions(-) diff --git a/drivers/bluetooth/hci/CMakeLists.txt b/drivers/bluetooth/hci/CMakeLists.txt index e20706c494f..adda6ea0e2a 100644 --- a/drivers/bluetooth/hci/CMakeLists.txt +++ b/drivers/bluetooth/hci/CMakeLists.txt @@ -19,7 +19,13 @@ zephyr_library_sources_ifdef(CONFIG_BT_ESP32 hci_esp32.c) zephyr_library_sources_ifdef(CONFIG_BT_H4 h4.c) zephyr_library_sources_ifdef(CONFIG_BT_H5 h5.c) zephyr_library_sources_ifdef(CONFIG_BT_HCI_IPC ipc.c) -zephyr_library_sources_ifdef(CONFIG_BT_SPI spi.c) +if(CONFIG_BT_SPI) + if ((CONFIG_DT_HAS_ST_HCI_SPI_V1_ENABLED) OR (CONFIG_DT_HAS_ST_HCI_SPI_V2_ENABLED)) + zephyr_library_sources(hci_spi_st.c) + else() + zephyr_library_sources(spi.c) + endif() +endif() zephyr_library_sources_ifdef(CONFIG_BT_STM32_IPM ipm_stm32wb.c) zephyr_library_sources_ifdef(CONFIG_BT_STM32WBA hci_stm32wba.c) zephyr_library_sources_ifdef(CONFIG_BT_USERCHAN userchan.c) diff --git a/drivers/bluetooth/hci/spi.c b/drivers/bluetooth/hci/spi.c index afad8fcf2ba..5c2695435e4 100644 --- a/drivers/bluetooth/hci/spi.c +++ b/drivers/bluetooth/hci/spi.c @@ -86,16 +86,6 @@ static K_SEM_DEFINE(sem_busy, 1, 1); static K_KERNEL_STACK_DEFINE(spi_rx_stack, CONFIG_BT_DRV_RX_STACK_SIZE); static struct k_thread spi_rx_thread_data; -#if defined(CONFIG_BT_BLUENRG_ACI) -#define BLUENRG_ACI_WRITE_CONFIG_DATA BT_OP(BT_OGF_VS, 0x000C) -#define BLUENRG_CONFIG_PUBADDR_OFFSET 0x00 -#define BLUENRG_CONFIG_PUBADDR_LEN 0x06 -#define BLUENRG_CONFIG_LL_ONLY_OFFSET 0x2C -#define BLUENRG_CONFIG_LL_ONLY_LEN 0x01 - -static int bt_spi_send_aci_config(uint8_t offset, const uint8_t *value, size_t value_len); -#endif /* CONFIG_BT_BLUENRG_ACI */ - static const struct spi_dt_spec bus = SPI_DT_SPEC_INST_GET( 0, SPI_OP_MODE_MASTER | SPI_TRANSFER_MSB | SPI_WORD_SET(8), 0); @@ -146,12 +136,6 @@ static bool bt_spi_handle_vendor_evt(uint8_t *msg) switch (bt_spi_get_evt(msg)) { case EVT_BLUE_INITIALIZED: { k_sem_give(&sem_initialised); -#if defined(CONFIG_BT_BLUENRG_ACI) - /* force BlueNRG to be on controller mode */ - uint8_t data = 1; - - bt_spi_send_aci_config(BLUENRG_CONFIG_LL_ONLY_OFFSET, &data, 1); -#endif handled = true; } default: @@ -160,144 +144,6 @@ static bool bt_spi_handle_vendor_evt(uint8_t *msg) return handled; } -#define IS_IRQ_HIGH gpio_pin_get_dt(&irq_gpio) - -#if DT_HAS_COMPAT_STATUS_OKAY(st_hci_spi_v1) -/* Define a limit when reading IRQ high */ -/* It can be required to be increased for */ -/* some particular cases. */ -#define IRQ_HIGH_MAX_READ 3 -/* On BlueNRG-MS, host is expected to read */ -/* as long as IRQ pin is high */ -#define READ_CONDITION IS_IRQ_HIGH -/* We cannot retry write data without reading again the header */ -#define WRITE_DATA_CONDITION(...) true - -static void assert_cs(void) -{ - gpio_pin_set_dt(&bus.config.cs.gpio, 0); - gpio_pin_set_dt(&bus.config.cs.gpio, 1); -} - -static void release_cs(bool data_transaction) -{ - ARG_UNUSED(data_transaction); - gpio_pin_set_dt(&bus.config.cs.gpio, 0); -} - -static int bt_spi_get_header(uint8_t op, uint16_t *size) -{ - uint8_t header_master[5] = {op, 0, 0, 0, 0}; - uint8_t header_slave[5]; - uint8_t size_offset, attempts; - int ret; - - if (op == SPI_READ) { - if (!IS_IRQ_HIGH) { - *size = 0; - return 0; - } - size_offset = STATUS_HEADER_TOREAD; - } else if (op == SPI_WRITE) { - size_offset = STATUS_HEADER_TOWRITE; - } else { - return -EINVAL; - } - attempts = IRQ_HIGH_MAX_READ; - do { - if (op == SPI_READ) { - /* Keep checking that IRQ is still high, if we need to read */ - if (!IS_IRQ_HIGH) { - *size = 0; - return 0; - } - } - assert_cs(); - ret = bt_spi_transceive(header_master, 5, header_slave, 5); - if (ret) { - /* SPI transaction failed */ - break; - } - - *size = (header_slave[STATUS_HEADER_READY] == READY_NOW) ? - header_slave[size_offset] : 0; - attempts--; - } while ((*size == 0) && attempts); - - return ret; -} - -#elif DT_HAS_COMPAT_STATUS_OKAY(st_hci_spi_v2) - -#define READ_CONDITION false -/* We cannot retry writing data without reading the header again */ -#define WRITE_DATA_CONDITION(...) true - -static void assert_cs(uint16_t delay) -{ - gpio_pin_set_dt(&bus.config.cs.gpio, 0); - if (delay) { - k_sleep(K_USEC(delay)); - } - gpio_pin_set_dt(&bus.config.cs.gpio, 1); - gpio_pin_interrupt_configure_dt(&irq_gpio, GPIO_INT_DISABLE); -} - -static void release_cs(bool data_transaction) -{ - /* Consume possible event signals */ - while (k_sem_take(&sem_request, K_NO_WAIT) == 0) { - } - if (data_transaction) { - /* Wait for IRQ to become low only when data phase has been performed */ - while (IS_IRQ_HIGH) { - } - } - gpio_pin_interrupt_configure_dt(&irq_gpio, GPIO_INT_EDGE_TO_ACTIVE); - gpio_pin_set_dt(&bus.config.cs.gpio, 0); -} - -static int bt_spi_get_header(uint8_t op, uint16_t *size) -{ - uint8_t header_master[5] = {op, 0, 0, 0, 0}; - uint8_t header_slave[5]; - uint16_t cs_delay; - uint8_t size_offset; - int ret; - - if (op == SPI_READ) { - if (!IS_IRQ_HIGH) { - *size = 0; - return 0; - } - cs_delay = 0; - size_offset = STATUS_HEADER_TOREAD; - } else if (op == SPI_WRITE) { - /* To make sure we have a minimum delay from previous release cs */ - cs_delay = 100; - size_offset = STATUS_HEADER_TOWRITE; - } else { - return -EINVAL; - } - - assert_cs(cs_delay); - /* Wait up to a maximum time of 100 ms */ - if (!WAIT_FOR(IS_IRQ_HIGH, 100000, k_usleep(100))) { - LOG_ERR("IRQ pin did not raise"); - return -EIO; - } - - ret = bt_spi_transceive(header_master, 5, header_slave, 5); - *size = header_slave[size_offset] | (header_slave[size_offset + 1] << 8); - return ret; -} -/* Other Boards */ -#else - -#define release_cs(...) -#define READ_CONDITION false -#define WRITE_DATA_CONDITION(ret, rx_first) (rx_first != 0U || ret) - static int bt_spi_get_header(uint8_t op, uint16_t *size) { uint8_t header_master[5] = {op, 0, 0, 0, 0}; @@ -334,47 +180,6 @@ static int bt_spi_get_header(uint8_t op, uint16_t *size) return ret; } -#endif /* DT_HAS_COMPAT_STATUS_OKAY(st_hci_spi_v1) */ - -#if defined(CONFIG_BT_BLUENRG_ACI) -static int bt_spi_send_aci_config(uint8_t offset, const uint8_t *value, size_t value_len) -{ - struct net_buf *buf; - uint8_t *cmd_data; - size_t data_len = 2 + value_len; - - buf = bt_hci_cmd_create(BLUENRG_ACI_WRITE_CONFIG_DATA, data_len); - if (!buf) { - return -ENOBUFS; - } - - cmd_data = net_buf_add(buf, data_len); - cmd_data[0] = offset; - cmd_data[1] = value_len; - memcpy(&cmd_data[2], value, value_len); - - return bt_hci_cmd_send(BLUENRG_ACI_WRITE_CONFIG_DATA, buf); -} - -static int bt_spi_bluenrg_setup(const struct bt_hci_setup_params *params) -{ - int ret; - const bt_addr_t *addr = ¶ms->public_addr; - - if (!bt_addr_eq(addr, BT_ADDR_NONE) && !bt_addr_eq(addr, BT_ADDR_ANY)) { - ret = bt_spi_send_aci_config( - BLUENRG_CONFIG_PUBADDR_OFFSET, - addr->val, sizeof(addr->val)); - - if (ret != 0) { - LOG_ERR("Failed to set BlueNRG public address (%d)", ret); - return ret; - } - } - - return 0; -} -#endif /* CONFIG_BT_BLUENRG_ACI */ static struct net_buf *bt_spi_rx_buf_construct(uint8_t *msg) { @@ -453,48 +258,44 @@ static void bt_spi_rx_thread(void *p1, void *p2, void *p3) LOG_DBG(""); - do { - /* Wait for SPI bus to be available */ - k_sem_take(&sem_busy, K_FOREVER); - ret = bt_spi_get_header(SPI_READ, &size); - - /* Delay here is rounded up to next tick */ - k_sleep(K_USEC(DATA_DELAY_US)); - /* Read data */ - if (ret == 0 && size != 0) { - do { - ret = bt_spi_transceive(&txmsg, size, - &rxmsg, size); - if (rxmsg[0] == 0U) { - /* Consider increasing controller-data-delay-us - * if this message is extremely common. - */ - LOG_DBG("Controller not ready for SPI transaction " - "of %d bytes", size); - } - } while (rxmsg[0] == 0U && ret == 0); - } + /* Wait for SPI bus to be available */ + k_sem_take(&sem_busy, K_FOREVER); + ret = bt_spi_get_header(SPI_READ, &size); - release_cs(size > 0); + /* Delay here is rounded up to next tick */ + k_sleep(K_USEC(DATA_DELAY_US)); + /* Read data */ + if (ret == 0 && size != 0) { + do { + ret = bt_spi_transceive(&txmsg, size, + &rxmsg, size); + if (rxmsg[0] == 0U) { + /* Consider increasing controller-data-delay-us + * if this message is extremely common. + */ + LOG_DBG("Controller not ready for SPI transaction " + "of %d bytes", size); + } + } while (rxmsg[0] == 0U && ret == 0); + } - k_sem_give(&sem_busy); + k_sem_give(&sem_busy); - if (ret || size == 0) { - if (ret) { - LOG_ERR("Error %d", ret); - } - continue; + if (ret || size == 0) { + if (ret) { + LOG_ERR("Error %d", ret); } + continue; + } - LOG_HEXDUMP_DBG(rxmsg, size, "SPI RX"); + LOG_HEXDUMP_DBG(rxmsg, size, "SPI RX"); - /* Construct net_buf from SPI data */ - buf = bt_spi_rx_buf_construct(rxmsg); - if (buf) { - /* Handle the received HCI data */ - bt_recv(buf); - } - } while (READ_CONDITION); + /* Construct net_buf from SPI data */ + buf = bt_spi_rx_buf_construct(rxmsg); + if (buf) { + /* Handle the received HCI data */ + bt_recv(buf); + } } } @@ -544,7 +345,7 @@ static int bt_spi_send(struct net_buf *buf) while (true) { ret = bt_spi_transceive(buf->data, size, rx_first, 1); - if (WRITE_DATA_CONDITION(ret, rx_first[0])) { + if (rx_first[0] != 0U || ret) { break; } /* Consider increasing controller-data-delay-us @@ -554,8 +355,6 @@ static int bt_spi_send(struct net_buf *buf) } } - release_cs(size > 0); - k_sem_give(&sem_busy); if (ret) { @@ -565,18 +364,6 @@ static int bt_spi_send(struct net_buf *buf) LOG_HEXDUMP_DBG(buf->data, buf->len, "SPI TX"); -#if (DT_HAS_COMPAT_STATUS_OKAY(st_hci_spi_v1) || DT_HAS_COMPAT_STATUS_OKAY(st_hci_spi_v2)) - /* - * Since a RESET has been requested, the chip will now restart. - * Unfortunately the BlueNRG will reply with "reset received" but - * since it does not send back a NOP, we have no way to tell when the - * RESET has actually taken place. Instead, we use the vendor command - * EVT_BLUE_INITIALIZED as an indication that it is safe to proceed. - */ - if (bt_spi_get_cmd(buf->data) == BT_HCI_OP_RESET) { - k_sem_take(&sem_initialised, K_FOREVER); - } -#endif /* DT_HAS_COMPAT_STATUS_OKAY(st_hci_spi_v1) || DT_HAS_COMPAT_STATUS_OKAY(st_hci_spi_v2) */ out: net_buf_unref(buf); @@ -631,10 +418,6 @@ static int bt_spi_open(void) static const struct bt_hci_driver drv = { .name = DEVICE_DT_NAME(DT_DRV_INST(0)), .bus = BT_HCI_DRIVER_BUS_SPI, -#if defined(CONFIG_BT_BLUENRG_ACI) - .quirks = BT_QUIRK_NO_RESET, - .setup = bt_spi_bluenrg_setup, -#endif /* CONFIG_BT_BLUENRG_ACI */ .open = bt_spi_open, .send = bt_spi_send, }; From af76d061f8a032471eb0303f9653b51344e66f5f Mon Sep 17 00:00:00 2001 From: Ali Hozhabri Date: Fri, 5 Jan 2024 18:19:20 +0100 Subject: [PATCH 2018/3723] boards: arm: Update dts files for ST BlueNRG-based boards Update dts files to use ST vendor specific HCI SPI Bluetooth driver. Remove unnecessary GPIO bias for output pins. Signed-off-by: Ali Hozhabri --- boards/arm/b_l4s5i_iot01a/b_l4s5i_iot01a.dts | 9 ++++----- boards/arm/disco_l475_iot1/disco_l475_iot1.dts | 9 ++++----- boards/arm/sensortile_box/sensortile_box.dts | 9 ++++----- boards/arm/sensortile_box_pro/sensortile_box_pro.dts | 2 +- boards/arm/stm32l562e_dk/stm32l562e_dk_common.dtsi | 9 ++++----- boards/shields/x_nucleo_idb05a1/x_nucleo_idb05a1.overlay | 9 ++++----- 6 files changed, 21 insertions(+), 26 deletions(-) diff --git a/boards/arm/b_l4s5i_iot01a/b_l4s5i_iot01a.dts b/boards/arm/b_l4s5i_iot01a/b_l4s5i_iot01a.dts index fe6322cc26b..c5116181432 100644 --- a/boards/arm/b_l4s5i_iot01a/b_l4s5i_iot01a.dts +++ b/boards/arm/b_l4s5i_iot01a/b_l4s5i_iot01a.dts @@ -148,16 +148,15 @@ pinctrl-names = "default"; status = "okay"; - cs-gpios = <&gpiod 13 (GPIO_ACTIVE_LOW | GPIO_PULL_UP)>, + cs-gpios = <&gpiod 13 GPIO_ACTIVE_LOW>, <&gpioe 0 GPIO_ACTIVE_LOW>; spbtle-rf@0 { - compatible = "zephyr,bt-hci-spi", "st,hci-spi-v1"; + compatible = "st,hci-spi-v1"; reg = <0>; - reset-gpios = <&gpioa 8 (GPIO_ACTIVE_LOW | GPIO_PULL_UP)>; + reset-gpios = <&gpioa 8 GPIO_ACTIVE_LOW>; irq-gpios = <&gpioe 6 (GPIO_ACTIVE_HIGH | GPIO_PULL_DOWN)>; - spi-max-frequency = <2000000>; - controller-data-delay-us = <0>; /* No need for extra delay for BlueNRG-MS */ + spi-max-frequency = ; spi-hold-cs; }; diff --git a/boards/arm/disco_l475_iot1/disco_l475_iot1.dts b/boards/arm/disco_l475_iot1/disco_l475_iot1.dts index 85e0dcea3c2..9ae6399e62e 100644 --- a/boards/arm/disco_l475_iot1/disco_l475_iot1.dts +++ b/boards/arm/disco_l475_iot1/disco_l475_iot1.dts @@ -187,16 +187,15 @@ pinctrl-0 = <&spi3_sck_pc10 &spi3_miso_pc11 &spi3_mosi_pc12>; pinctrl-names = "default"; - cs-gpios = <&gpiod 13 (GPIO_ACTIVE_LOW | GPIO_PULL_UP)>, + cs-gpios = <&gpiod 13 GPIO_ACTIVE_LOW>, <&gpioe 0 GPIO_ACTIVE_LOW>; spbtle-rf@0 { - compatible = "zephyr,bt-hci-spi", "st,hci-spi-v1"; + compatible = "st,hci-spi-v1"; reg = <0>; - reset-gpios = <&gpioa 8 (GPIO_ACTIVE_LOW | GPIO_PULL_UP)>; + reset-gpios = <&gpioa 8 GPIO_ACTIVE_LOW>; irq-gpios = <&gpioe 6 (GPIO_ACTIVE_HIGH | GPIO_PULL_DOWN)>; - spi-max-frequency = <2000000>; - controller-data-delay-us = <0>; /* No need for extra delay for BlueNRG-MS */ + spi-max-frequency = ; spi-hold-cs; }; diff --git a/boards/arm/sensortile_box/sensortile_box.dts b/boards/arm/sensortile_box/sensortile_box.dts index b8622020840..4c5a9654b3d 100644 --- a/boards/arm/sensortile_box/sensortile_box.dts +++ b/boards/arm/sensortile_box/sensortile_box.dts @@ -165,16 +165,15 @@ pinctrl-0 = <&spi2_sck_pd1 &spi2_miso_pd3 &spi2_mosi_pc3>; pinctrl-names = "default"; status = "okay"; - cs-gpios = <&gpiod 0 (GPIO_ACTIVE_LOW | GPIO_PULL_UP)>; + cs-gpios = <&gpiod 0 GPIO_ACTIVE_LOW>; spbtle_1s_sensortile_box: spbtle-1s@0 { - compatible = "zephyr,bt-hci-spi", "st,hci-spi-v2"; + compatible = "st,hci-spi-v2"; reg = <0>; - reset-gpios = <&gpioa 8 (GPIO_ACTIVE_LOW | GPIO_PULL_UP)>; + reset-gpios = <&gpioa 8 GPIO_ACTIVE_LOW>; irq-gpios = <&gpiod 4 (GPIO_ACTIVE_HIGH | GPIO_PULL_DOWN)>; - spi-max-frequency = <1000000>; + spi-max-frequency = ; spi-cpha; spi-hold-cs; - controller-data-delay-us = <0>; reset-assert-duration-ms = <6>; }; }; diff --git a/boards/arm/sensortile_box_pro/sensortile_box_pro.dts b/boards/arm/sensortile_box_pro/sensortile_box_pro.dts index 0a5be03e4a9..8c159eb831f 100644 --- a/boards/arm/sensortile_box_pro/sensortile_box_pro.dts +++ b/boards/arm/sensortile_box_pro/sensortile_box_pro.dts @@ -164,7 +164,7 @@ stm32_lp_tick_source: &lptim1 { status = "okay"; bluenrg-lp@0 { - compatible = "zephyr,bt-hci-spi", "st,hci-spi-v2"; + compatible = "st,hci-spi-v2"; reg = <0>; irq-gpios = <&gpiod 1 (GPIO_ACTIVE_HIGH | GPIO_PULL_DOWN)>; reset-gpios = <&gpiod 4 GPIO_ACTIVE_LOW>; diff --git a/boards/arm/stm32l562e_dk/stm32l562e_dk_common.dtsi b/boards/arm/stm32l562e_dk/stm32l562e_dk_common.dtsi index 97263620f2e..7c91d04cbb5 100644 --- a/boards/arm/stm32l562e_dk/stm32l562e_dk_common.dtsi +++ b/boards/arm/stm32l562e_dk/stm32l562e_dk_common.dtsi @@ -111,16 +111,15 @@ stm32_lp_tick_source: &lptim1 { &spi1 { pinctrl-0 = <&spi1_sck_pg2 &spi1_miso_pg3 &spi1_mosi_pg4>; pinctrl-names = "default"; - cs-gpios = <&gpiog 5 (GPIO_ACTIVE_LOW | GPIO_PULL_UP)>; + cs-gpios = <&gpiog 5 GPIO_ACTIVE_LOW>; status = "okay"; spbtle-rf@0 { - compatible = "zephyr,bt-hci-spi", "st,hci-spi-v1"; + compatible = "st,hci-spi-v1"; reg = <0>; irq-gpios = <&gpiog 6 (GPIO_ACTIVE_HIGH | GPIO_PULL_DOWN)>; - reset-gpios = <&gpiog 8 (GPIO_ACTIVE_LOW | GPIO_PULL_UP)>; - spi-max-frequency = <2000000>; - controller-data-delay-us = <0>; /* No need for extra delay for BlueNRG-MS */ + reset-gpios = <&gpiog 8 GPIO_ACTIVE_LOW>; + spi-max-frequency = ; spi-hold-cs; }; }; diff --git a/boards/shields/x_nucleo_idb05a1/x_nucleo_idb05a1.overlay b/boards/shields/x_nucleo_idb05a1/x_nucleo_idb05a1.overlay index dbb23935f03..e6dff3c9c9f 100644 --- a/boards/shields/x_nucleo_idb05a1/x_nucleo_idb05a1.overlay +++ b/boards/shields/x_nucleo_idb05a1/x_nucleo_idb05a1.overlay @@ -5,15 +5,14 @@ */ &arduino_spi { - cs-gpios = <&arduino_header 1 (GPIO_ACTIVE_LOW | GPIO_PULL_UP)>; /* A1 */ + cs-gpios = <&arduino_header 1 GPIO_ACTIVE_LOW>; /* A1 */ spbtle_rf_x_nucleo_idb05a1: spbtle-rf@0 { - compatible = "zephyr,bt-hci-spi", "st,hci-spi-v1"; + compatible = "st,hci-spi-v1"; reg = <0>; - reset-gpios = <&arduino_header 13 (GPIO_ACTIVE_LOW | GPIO_PULL_UP)>; /* D7 */ + reset-gpios = <&arduino_header 13 GPIO_ACTIVE_LOW>; /* D7 */ irq-gpios = <&arduino_header 0 (GPIO_ACTIVE_HIGH | GPIO_PULL_DOWN)>; /* A0 */ - spi-max-frequency = <2000000>; - controller-data-delay-us = <0>; /* No need for extra delay for BlueNRG-MS */ + spi-max-frequency = ; spi-hold-cs; }; }; From a87a42dec7ca83f7f6e66a9b773c42f0b6b10bf8 Mon Sep 17 00:00:00 2001 From: Ali Hozhabri Date: Mon, 8 Jan 2024 14:38:20 +0100 Subject: [PATCH 2019/3723] drivers: bluetooth: hci: Add support for ST Proprietary extended event Add support for handling ST Proprietary extended event. Signed-off-by: Ali Hozhabri --- drivers/bluetooth/hci/hci_spi_st.c | 20 ++++++++++++++++++++ 1 file changed, 20 insertions(+) diff --git a/drivers/bluetooth/hci/hci_spi_st.c b/drivers/bluetooth/hci/hci_spi_st.c index 605e36e56a6..bd1e4d447ef 100644 --- a/drivers/bluetooth/hci/hci_spi_st.c +++ b/drivers/bluetooth/hci/hci_spi_st.c @@ -32,6 +32,8 @@ LOG_MODULE_REGISTER(bt_driver); #define HCI_ACL 0x02 #define HCI_SCO 0x03 #define HCI_EVT 0x04 +/* ST Proprietary extended event */ +#define HCI_EXT_EVT 0x82 /* Special Values */ #define SPI_WRITE 0x0A @@ -108,6 +110,11 @@ static const struct spi_buf_set spi_rx = { .count = 1 }; +struct bt_hci_ext_evt_hdr { + uint8_t evt; + uint16_t len; +} __packed; + static inline int bt_spi_transceive(void *tx, uint32_t tx_len, void *rx, uint32_t rx_len) { @@ -336,6 +343,19 @@ static struct net_buf *bt_spi_rx_buf_construct(uint8_t *msg) int len; switch (msg[PACKET_TYPE]) { +#if DT_HAS_COMPAT_STATUS_OKAY(st_hci_spi_v2) + case HCI_EXT_EVT: + struct bt_hci_ext_evt_hdr *evt = (struct bt_hci_ext_evt_hdr *) (msg + 1); + struct bt_hci_evt_hdr *evt2 = (struct bt_hci_evt_hdr *) (msg + 1); + + if (evt->len > 0xff) { + return NULL; + } + /* Use memmove instead of memcpy due to buffer overlapping */ + memmove(msg + (1 + sizeof(*evt2)), msg + (1 + sizeof(*evt)), evt2->len); + /* Manage event as regular HCI_EVT */ + __fallthrough; +#endif /* DT_HAS_COMPAT_STATUS_OKAY(st_hci_spi_v2) */ case HCI_EVT: switch (msg[EVT_HEADER_EVENT]) { case BT_HCI_EVT_VENDOR: From 2b91d62c0ef7be59c5de18018b66fc31adc26464 Mon Sep 17 00:00:00 2001 From: James Zipperer Date: Fri, 5 Jan 2024 12:53:55 -0800 Subject: [PATCH 2020/3723] modules: hal_nxp: usb: enable sof notifications When building with CONFIG_USB_DEVICE_AUDIO, enable start of frame notifications from the mcux sdk usb middleware Signed-off-by: James Zipperer --- modules/hal_nxp/usb/usb_device_config.h | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/modules/hal_nxp/usb/usb_device_config.h b/modules/hal_nxp/usb/usb_device_config.h index 31a62ffbfeb..09af4fe7be6 100644 --- a/modules/hal_nxp/usb/usb_device_config.h +++ b/modules/hal_nxp/usb/usb_device_config.h @@ -52,4 +52,9 @@ BUILD_ASSERT(NUM_INSTS <= 1, "Only one USB device supported"); /* Number of endpoints supported */ #define USB_DEVICE_CONFIG_ENDPOINTS (DT_INST_PROP(0, num_bidir_endpoints)) +/* Start of Frame (SOF) Notifications are required by the zephyr usb audio driver */ +#ifdef CONFIG_USB_DEVICE_AUDIO +#define USB_DEVICE_CONFIG_SOF_NOTIFICATIONS (1U) +#endif /* CONFIG_USB_DEVICE_AUDIO */ + #endif /* __USB_DEVICE_CONFIG_H__ */ From 21c9c4abfe5c858b1c5d6c45a2c919d81b12a02b Mon Sep 17 00:00:00 2001 From: James Zipperer Date: Fri, 5 Jan 2024 13:13:24 -0800 Subject: [PATCH 2021/3723] drivers: usb: device: add start of frame notifications to nxp mcux driver When usb middleware sends a start of frame notification to this driver, call status_cb with USB_DC_SOF. Signed-off-by: James Zipperer --- drivers/usb/device/usb_dc_mcux.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/drivers/usb/device/usb_dc_mcux.c b/drivers/usb/device/usb_dc_mcux.c index 0667486b628..dc0868ffd5d 100644 --- a/drivers/usb/device/usb_dc_mcux.c +++ b/drivers/usb/device/usb_dc_mcux.c @@ -910,6 +910,9 @@ static void usb_mcux_thread_main(void *arg1, void *arg2, void *arg3) case kUSB_DeviceNotifyResume: dev_state.status_cb(USB_DC_RESUME, NULL); break; + case kUSB_DeviceNotifySOF: + dev_state.status_cb(USB_DC_SOF, NULL); + break; default: ep_abs_idx = EP_ABS_IDX(msg.code); From 975208209b589517d84eb08f9565a0f286907277 Mon Sep 17 00:00:00 2001 From: James Zipperer Date: Fri, 5 Jan 2024 13:35:44 -0800 Subject: [PATCH 2022/3723] usb: device: audio options for polling-interval and sample-rate-hz These descriptor values can now be configured via the device tree Signed-off-by: James Zipperer --- dts/bindings/usb/usb-audio-hp.yaml | 6 +++++ dts/bindings/usb/usb-audio-hs.yaml | 12 ++++++++++ dts/bindings/usb/usb-audio-mic.yaml | 6 +++++ subsys/usb/device/class/audio/audio.c | 8 ++++--- .../device/class/audio/usb_audio_internal.h | 23 +++++++++++++++---- 5 files changed, 48 insertions(+), 7 deletions(-) diff --git a/dts/bindings/usb/usb-audio-hp.yaml b/dts/bindings/usb/usb-audio-hp.yaml index 91968126c1e..a7b1f857d5f 100644 --- a/dts/bindings/usb/usb-audio-hp.yaml +++ b/dts/bindings/usb/usb-audio-hp.yaml @@ -18,6 +18,12 @@ properties: - 16 - 24 - 32 + sample-rate-hz: + type: int + default: 48000 + polling-interval: + type: int + default: 1 # channel configuration options channel-l: type: boolean diff --git a/dts/bindings/usb/usb-audio-hs.yaml b/dts/bindings/usb/usb-audio-hs.yaml index ce0245cc136..e876746ebe3 100644 --- a/dts/bindings/usb/usb-audio-hs.yaml +++ b/dts/bindings/usb/usb-audio-hs.yaml @@ -30,6 +30,12 @@ properties: - "Asynchronous" - "Adaptive" - "Synchronous" + mic-sample-rate-hz: + type: int + default: 48000 + mic-polling-interval: + type: int + default: 1 hp-resolution: type: int default: 16 @@ -38,6 +44,12 @@ properties: - 16 - 24 - 32 + hp-sample-rate-hz: + type: int + default: 48000 + hp-polling-interval: + type: int + default: 1 # microphone channel configuration options mic-channel-l: type: boolean diff --git a/dts/bindings/usb/usb-audio-mic.yaml b/dts/bindings/usb/usb-audio-mic.yaml index 032021fd363..c8571084682 100644 --- a/dts/bindings/usb/usb-audio-mic.yaml +++ b/dts/bindings/usb/usb-audio-mic.yaml @@ -30,6 +30,12 @@ properties: - "Asynchronous" - "Adaptive" - "Synchronous" + sample-rate-hz: + type: int + default: 48000 + polling-interval: + type: int + default: 1 # channel configuration options channel-l: type: boolean diff --git a/subsys/usb/device/class/audio/audio.c b/subsys/usb/device/class/audio/audio.c index 338163940e3..15a4fdbef07 100644 --- a/subsys/usb/device/class/audio/audio.c +++ b/subsys/usb/device/class/audio/audio.c @@ -87,7 +87,7 @@ struct dev##_descriptor_##i dev##_desc_##i = { \ .as_interface_alt_0 = INIT_STD_IF(USB_AUDIO_AUDIOSTREAMING, 1, 0, 0), \ .as_interface_alt_1 = INIT_STD_IF(USB_AUDIO_AUDIOSTREAMING, 1, 1, 1), \ .as_cs_interface = INIT_AS_GENERAL(link), \ - .format = INIT_AS_FORMAT_I(CH_CNT(dev, i), GET_RES(dev, i)), \ + .format = INIT_AS_FORMAT_I(CH_CNT(dev, i), GET_RES(dev, i), GET_RATE(dev, i)), \ .std_ep = INIT_STD_AS_AD_EP(dev, i, addr), \ .cs_ep = INIT_CS_AS_AD_EP, \ }; \ @@ -133,7 +133,8 @@ struct dev##_descriptor_##i dev##_desc_##i = { \ 1, 1, 1), \ .as_cs_interface_0 = INIT_AS_GENERAL(id+2), \ .format_0 = INIT_AS_FORMAT_I(CH_CNT(dev##_MIC, i), \ - GET_RES(dev##_MIC, i)), \ + GET_RES(dev##_MIC, i), \ + GET_RATE(dev##_MIC, i)), \ .std_ep_0 = INIT_STD_AS_AD_EP(dev##_MIC, i, \ AUTO_EP_IN), \ .cs_ep_0 = INIT_CS_AS_AD_EP, \ @@ -143,7 +144,8 @@ struct dev##_descriptor_##i dev##_desc_##i = { \ 2, 1, 1), \ .as_cs_interface_1 = INIT_AS_GENERAL(id+3), \ .format_1 = INIT_AS_FORMAT_I(CH_CNT(dev##_HP, i), \ - GET_RES(dev##_HP, i)), \ + GET_RES(dev##_HP, i), \ + GET_RATE(dev##_HP, i)), \ .std_ep_1 = INIT_STD_AS_AD_EP(dev##_HP, i, \ AUTO_EP_OUT), \ .cs_ep_1 = INIT_CS_AS_AD_EP, \ diff --git a/subsys/usb/device/class/audio/usb_audio_internal.h b/subsys/usb/device/class/audio/usb_audio_internal.h index 7a70ae94178..43c73fd8533 100644 --- a/subsys/usb/device/class/audio/usb_audio_internal.h +++ b/subsys/usb/device/class/audio/usb_audio_internal.h @@ -165,6 +165,18 @@ #define GET_VOLUME_MIC(i, prop) DT_PROP_OR(DT_INST(i, COMPAT_MIC), prop, 0) #define GET_VOLUME(dev, i, prop) GET_VOLUME_##dev(i, prop) +#define GET_RATE_HP(i) DT_PROP(DT_INST(i, COMPAT_HP), sample_rate_hz) +#define GET_RATE_MIC(i) DT_PROP(DT_INST(i, COMPAT_MIC), sample_rate_hz) +#define GET_RATE_HS_HP(i) DT_PROP(DT_INST(i, COMPAT_HS), hp_sample_rate_hz) +#define GET_RATE_HS_MIC(i) DT_PROP(DT_INST(i, COMPAT_HS), mic_sample_rate_hz) +#define GET_RATE(dev, i) GET_RATE_##dev(i) + +#define GET_INTERVAL_HP(i) DT_PROP(DT_INST(i, COMPAT_HP), polling_interval) +#define GET_INTERVAL_MIC(i) DT_PROP(DT_INST(i, COMPAT_MIC), polling_interval) +#define GET_INTERVAL_HS_HP(i) DT_PROP(DT_INST(i, COMPAT_HS), hp_polling_interval) +#define GET_INTERVAL_HS_MIC(i) DT_PROP(DT_INST(i, COMPAT_HS), mic_polling_interval) +#define GET_INTERVAL(dev, i) GET_INTERVAL_##dev(i) + #define SYNC_TYPE_HP(i) 3 #define SYNC_TYPE_MIC(i) DT_ENUM_IDX(DT_INST(i, COMPAT_MIC), sync_type) #define SYNC_TYPE_HS_HP(i) 3 @@ -172,7 +184,7 @@ #define SYNC_TYPE(dev, i) (SYNC_TYPE_##dev(i) << 2) #define EP_SIZE(dev, i) \ - ((GET_RES(dev, i)/8) * CH_CNT(dev, i) * 48) + (DIV_ROUND_UP((GET_RES(dev, i)/8 * CH_CNT(dev, i) * GET_RATE(dev, i)), 1000)) /* *_ID() macros are used to give proper Id to each entity describing * the device. Entities Id must start from 1 that's why 1 is added. @@ -477,11 +489,14 @@ struct dev##_descriptor_##i { \ .wFormatTag = sys_cpu_to_le16(0x0001), \ } +#define SAMPLE_RATE(rate) \ + {(((rate) >> 0) & 0xff), (((rate) >> 8) & 0xff), (((rate) >> 16) & 0xff)} + /** Class-Specific AS Format Type Descriptor 4.5.3 audio10.pdf * For more information refer to 2.2.5 Type I Format Type Descriptor * from frmts10.pdf */ -#define INIT_AS_FORMAT_I(ch_cnt, res) \ +#define INIT_AS_FORMAT_I(ch_cnt, res, rate) \ { \ .bLength = sizeof(struct format_type_i_descriptor), \ .bDescriptorType = USB_DESC_CS_INTERFACE, \ @@ -491,7 +506,7 @@ struct dev##_descriptor_##i { \ .bSubframeSize = res/8, \ .bBitResolution = res, \ .bSamFreqType = 1, \ - .tSamFreq = {0x80, 0xBB, 0x00}, \ + .tSamFreq = SAMPLE_RATE(rate), \ } #define INIT_STD_AS_AD_EP(dev, i, addr) \ @@ -501,7 +516,7 @@ struct dev##_descriptor_##i { \ .bEndpointAddress = addr, \ .bmAttributes = (USB_DC_EP_ISOCHRONOUS | SYNC_TYPE(dev, i)), \ .wMaxPacketSize = sys_cpu_to_le16(EP_SIZE(dev, i)), \ - .bInterval = 0x01, \ + .bInterval = GET_INTERVAL(dev, i), \ .bRefresh = 0x00, \ .bSynchAddress = 0x00, \ } From 273165c3bb9c8bc7af02350511cb94f4f64bb135 Mon Sep 17 00:00:00 2001 From: James Zipperer Date: Fri, 5 Jan 2024 13:37:34 -0800 Subject: [PATCH 2023/3723] usb: device: audio: fix compiler warning for usb audio microphone audio_receive_cb is only used by headphones and headset, it is unused in microphone-only configurations. Gate compilation based on the device tree. Signed-off-by: James Zipperer --- subsys/usb/device/class/audio/audio.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/subsys/usb/device/class/audio/audio.c b/subsys/usb/device/class/audio/audio.c index 15a4fdbef07..d293b834cab 100644 --- a/subsys/usb/device/class/audio/audio.c +++ b/subsys/usb/device/class/audio/audio.c @@ -919,6 +919,7 @@ size_t usb_audio_get_in_frame_size(const struct device *dev) return audio_dev_data->in_frame_size; } +#if (HEADPHONES_DEVICE_COUNT > 0 || HEADSET_DEVICE_COUNT > 0) static void audio_receive_cb(uint8_t ep, enum usb_dc_ep_cb_status_code status) { struct usb_audio_dev_data *audio_dev_data; @@ -970,6 +971,7 @@ static void audio_receive_cb(uint8_t ep, enum usb_dc_ep_cb_status_code status) buffer, ret_bytes); } } +#endif /* #if (HEADPHONES_DEVICE_COUNT > 0 || HEADSET_DEVICE_COUNT > 0) */ void usb_audio_register(const struct device *dev, const struct usb_audio_ops *ops) From b8188e54a421cdc08861ca06933efee3224d3816 Mon Sep 17 00:00:00 2001 From: Gerson Fernando Budke Date: Mon, 16 Oct 2023 20:15:31 +0200 Subject: [PATCH 2024/3723] kernel: Implement k_sleep for Single Thread The current z_tick_sleep return directly when building kernel for Single Thread model. This reorganize the code to use k_busy_wait() to be time coherent since subsystems may depend on it. In the case of a K_FOREVER timeout is selected the Single Thread the implementation will invoke k_cpu_idle() and the system will wait for an interrupt saving power. Signed-off-by: Gerson Fernando Budke --- kernel/sched.c | 15 ++++++++++++--- 1 file changed, 12 insertions(+), 3 deletions(-) diff --git a/kernel/sched.c b/kernel/sched.c index 2e15b665960..bb009238d5d 100644 --- a/kernel/sched.c +++ b/kernel/sched.c @@ -1527,26 +1527,28 @@ static inline void z_vrfy_k_yield(void) static int32_t z_tick_sleep(k_ticks_t ticks) { -#ifdef CONFIG_MULTITHREADING uint32_t expected_wakeup_ticks; __ASSERT(!arch_is_in_isr(), ""); LOG_DBG("thread %p for %lu ticks", _current, (unsigned long)ticks); +#ifdef CONFIG_MULTITHREADING /* wait of 0 ms is treated as a 'yield' */ if (ticks == 0) { k_yield(); return 0; } +#endif - k_timeout_t timeout = Z_TIMEOUT_TICKS(ticks); if (Z_TICK_ABS(ticks) <= 0) { expected_wakeup_ticks = ticks + sys_clock_tick_get_32(); } else { expected_wakeup_ticks = Z_TICK_ABS(ticks); } +#ifdef CONFIG_MULTITHREADING + k_timeout_t timeout = Z_TIMEOUT_TICKS(ticks); k_spinlock_key_t key = k_spin_lock(&sched_spinlock); #if defined(CONFIG_TIMESLICING) && defined(CONFIG_SWAP_NONATOMIC) @@ -1564,6 +1566,9 @@ static int32_t z_tick_sleep(k_ticks_t ticks) if (ticks > 0) { return ticks; } +#else + /* busy wait to be time coherent since subsystems may depend on it */ + z_impl_k_busy_wait(k_ticks_to_us_ceil32(expected_wakeup_ticks)); #endif return 0; @@ -1579,8 +1584,12 @@ int32_t z_impl_k_sleep(k_timeout_t timeout) /* in case of K_FOREVER, we suspend */ if (K_TIMEOUT_EQ(timeout, K_FOREVER)) { +#ifdef CONFIG_MULTITHREADING k_thread_suspend(_current); - +#else + /* In Single Thread, just wait for an interrupt saving power */ + k_cpu_idle(); +#endif SYS_PORT_TRACING_FUNC_EXIT(k_thread, sleep, timeout, (int32_t) K_TICKS_FOREVER); return (int32_t) K_TICKS_FOREVER; From 23b3e5741ea39543f29efaadaa53c21c072ad514 Mon Sep 17 00:00:00 2001 From: Lukasz Mrugala Date: Thu, 21 Dec 2023 13:38:37 +0000 Subject: [PATCH 2025/3723] scripts: tests: Removal of straggling folders Current blacbox tests leave two folders, OUT_DIR and TEST_DIR after they are finished. Unit tests create two further folders, mock_testsuite and demo_board_2. This change deletes them appropriately. Additionally, the created twister-out* folders in blackbox tests are moved to a temp directory and removed after every test. Signed-off-by: Lukasz Mrugala --- scripts/tests/twister/test_harness.py | 6 +- scripts/tests/twister/test_testplan.py | 4 +- scripts/tests/twister_blackbox/conftest.py | 26 ++++++ .../twister_blackbox/test_hardwaremap.py | 15 ++-- .../tests/twister_blackbox/test_printouts.py | 24 +++--- scripts/tests/twister_blackbox/test_qemu.py | 6 +- scripts/tests/twister_blackbox/test_report.py | 85 +++++++++---------- 7 files changed, 90 insertions(+), 76 deletions(-) diff --git a/scripts/tests/twister/test_harness.py b/scripts/tests/twister/test_harness.py index 96941b60b28..f0697efc43d 100644 --- a/scripts/tests/twister/test_harness.py +++ b/scripts/tests/twister/test_harness.py @@ -35,7 +35,7 @@ def process_logs(harness, logs): @pytest.fixture -def gtest(): +def gtest(tmp_path): mock_platform = mock.Mock() mock_platform.name = "mock_platform" mock_testsuite = mock.Mock() @@ -44,8 +44,10 @@ def gtest(): mock_testsuite.id = "id" mock_testsuite.testcases = [] mock_testsuite.harness_config = {} + outdir = tmp_path / 'gtest_out' + outdir.mkdir() - instance = TestInstance(testsuite=mock_testsuite, platform=mock_platform, outdir="") + instance = TestInstance(testsuite=mock_testsuite, platform=mock_platform, outdir=outdir) harness = Gtest() harness.configure(instance) diff --git a/scripts/tests/twister/test_testplan.py b/scripts/tests/twister/test_testplan.py index ed61759750f..473085467d2 100644 --- a/scripts/tests/twister/test_testplan.py +++ b/scripts/tests/twister/test_testplan.py @@ -244,14 +244,14 @@ def test_apply_filters_part3(class_testplan, all_testsuites_dict, platforms_list filtered_instances = list(filter(lambda item: item.status == "filtered", class_testplan.instances.values())) assert not filtered_instances -def test_add_instances_short(test_data, class_env, all_testsuites_dict, platforms_list): +def test_add_instances_short(tmp_path, class_env, all_testsuites_dict, platforms_list): """ Testing add_instances() function of TestPlan class in Twister Test 1: instances dictionary keys have expected values (Platform Name + Testcase Name) Test 2: Values of 'instances' dictionary in Testsuite class are an instance of 'TestInstance' class Test 3: Values of 'instances' dictionary have expected values. """ - class_env.outdir = test_data + class_env.outdir = tmp_path plan = TestPlan(class_env) plan.platforms = platforms_list platform = plan.get_platform("demo_board_2") diff --git a/scripts/tests/twister_blackbox/conftest.py b/scripts/tests/twister_blackbox/conftest.py index f07980a19bc..95fd0b3338a 100644 --- a/scripts/tests/twister_blackbox/conftest.py +++ b/scripts/tests/twister_blackbox/conftest.py @@ -6,6 +6,7 @@ '''Common fixtures for use in testing the twister tool.''' import logging +import shutil import mock import os import pytest @@ -43,3 +44,28 @@ def clear_log(): handlers = getattr(logger, 'handlers', []) for handler in handlers: logger.removeHandler(handler) + +# This fixture provides blackbox tests with an `out_path` parameter +# It should be used as the `-O` (`--out_dir`) parameter in blackbox tests +# APPRECIATED: method of using this out_path wholly outside of test code +@pytest.fixture(name='out_path', autouse=True) +def provide_out(tmp_path, request): + # As this fixture is autouse, one can use the pytest.mark.noclearout decorator + # in order to be sure that this fixture's code will not fire. + # Most of the time, just omitting the `out_path` parameter is sufficient. + if 'noclearout' in request.keywords: + yield + return + + # Before + out_container_path = tmp_path / 'blackbox-out-container' + out_container_path.mkdir() + out_path = os.path.join(out_container_path, "blackbox-out") + + # Test + yield out_path + + # After + # We're operating in temp, so it is not strictly necessary + # but the files can get large quickly as we do not need them after the test. + shutil.rmtree(out_container_path) diff --git a/scripts/tests/twister_blackbox/test_hardwaremap.py b/scripts/tests/twister_blackbox/test_hardwaremap.py index c5dbd990377..c1efd5be495 100644 --- a/scripts/tests/twister_blackbox/test_hardwaremap.py +++ b/scripts/tests/twister_blackbox/test_hardwaremap.py @@ -105,15 +105,14 @@ def setup_class(cls): def teardown_class(cls): pass - @pytest.mark.usefixtures("clear_log") @pytest.mark.parametrize( ('manufacturer', 'product', 'serial', 'runner'), TESTDATA_1, ) - def test_generate(self, capfd, manufacturer, product, serial, runner): + def test_generate(self, capfd, out_path, manufacturer, product, serial, runner): file_name = "test-map.yaml" path = os.path.join(ZEPHYR_BASE, file_name) - args = ['--generate-hardware-map', file_name] + args = ['--outdir', out_path, '--generate-hardware-map', file_name] if os.path.exists(path): os.remove(path) @@ -165,15 +164,14 @@ def mocked_comports(): for handler in handlers: logger.removeHandler(handler) - @pytest.mark.usefixtures("clear_log") @pytest.mark.parametrize( ('manufacturer', 'product', 'serial', 'runner'), TESTDATA_2, ) - def test_few_generate(self, capfd, manufacturer, product, serial, runner): + def test_few_generate(self, capfd, out_path, manufacturer, product, serial, runner): file_name = "test-map.yaml" path = os.path.join(ZEPHYR_BASE, file_name) - args = ['--generate-hardware-map', file_name] + args = ['--outdir', out_path, '--generate-hardware-map', file_name] if os.path.exists(path): os.remove(path) @@ -247,15 +245,14 @@ def mocked_comports(): assert str(sys_exit.value) == '0' - @pytest.mark.usefixtures("clear_log") @pytest.mark.parametrize( ('manufacturer', 'product', 'serial', 'location'), TESTDATA_3, ) - def test_texas_exeption(self, capfd, manufacturer, product, serial, location): + def test_texas_exeption(self, capfd, out_path, manufacturer, product, serial, location): file_name = "test-map.yaml" path = os.path.join(ZEPHYR_BASE, file_name) - args = ['--generate-hardware-map', file_name] + args = ['--outdir', out_path, '--generate-hardware-map', file_name] if os.path.exists(path): os.remove(path) diff --git a/scripts/tests/twister_blackbox/test_printouts.py b/scripts/tests/twister_blackbox/test_printouts.py index b49ea867fb1..845cea92161 100644 --- a/scripts/tests/twister_blackbox/test_printouts.py +++ b/scripts/tests/twister_blackbox/test_printouts.py @@ -92,7 +92,6 @@ def setup_class(cls): def teardown_class(cls): pass - @pytest.mark.usefixtures("clear_log") @pytest.mark.parametrize( 'test_path, expected', TESTDATA_1, @@ -101,8 +100,8 @@ def teardown_class(cls): 'tests/dummy/device', ] ) - def test_list_tags(self, capfd, test_path, expected): - args = ['-T', test_path, '--list-tags'] + def test_list_tags(self, capfd, out_path, test_path, expected): + args = ['--outdir', out_path, '-T', test_path, '--list-tags'] with mock.patch.object(sys, 'argv', [sys.argv[0]] + args), \ pytest.raises(SystemExit) as sys_exit: @@ -119,7 +118,6 @@ def test_list_tags(self, capfd, test_path, expected): assert str(sys_exit.value) == '0' - @pytest.mark.usefixtures("clear_log") @pytest.mark.parametrize( 'test_path, expected', TESTDATA_2, @@ -128,8 +126,8 @@ def test_list_tags(self, capfd, test_path, expected): 'tests/dummy/device', ] ) - def test_list_tests(self, capfd, test_path, expected): - args = ['-T', test_path, '--list-tests'] + def test_list_tests(self, capfd, out_path, test_path, expected): + args = ['--outdir', out_path, '-T', test_path, '--list-tests'] with mock.patch.object(sys, 'argv', [sys.argv[0]] + args), \ pytest.raises(SystemExit) as sys_exit: @@ -147,7 +145,6 @@ def test_list_tests(self, capfd, test_path, expected): assert str(sys_exit.value) == '0' - @pytest.mark.usefixtures("clear_log") @pytest.mark.parametrize( 'test_path, expected', TESTDATA_3, @@ -156,8 +153,8 @@ def test_list_tests(self, capfd, test_path, expected): 'tests/dummy/device', ] ) - def test_tree(self, capfd, test_path, expected): - args = ['-T', test_path, '--test-tree'] + def test_tree(self, capfd, out_path, test_path, expected): + args = ['--outdir', out_path, '-T', test_path, '--test-tree'] with mock.patch.object(sys, 'argv', [sys.argv[0]] + args), \ pytest.raises(SystemExit) as sys_exit: @@ -176,9 +173,9 @@ def test_tree(self, capfd, test_path, expected): TESTDATA_4, ids=['tests'] ) - def test_timestamps(self, capfd, test_path, test_platforms): + def test_timestamps(self, capfd, out_path, test_path, test_platforms): - args = ['-i', '-T', test_path, '--timestamps', '-v'] + \ + args = ['-i', '--outdir', out_path, '-T', test_path, '--timestamps', '-v'] + \ [val for pair in zip( ['-p'] * len(test_platforms), test_platforms ) for val in pair] @@ -247,15 +244,14 @@ def test_help(self, capfd, flag): assert str(sys_exit.value) == '0' - @pytest.mark.usefixtures("clear_log") @pytest.mark.parametrize( 'test_path, test_platforms', TESTDATA_4, ids=['tests'] ) - def test_force_color(self, capfd, test_path, test_platforms): + def test_force_color(self, capfd, out_path, test_path, test_platforms): - args = ['-i', '-T', test_path, '--force-color'] + \ + args = ['-i', '--outdir', out_path, '-T', test_path, '--force-color'] + \ [val for pair in zip( ['-p'] * len(test_platforms), test_platforms ) for val in pair] diff --git a/scripts/tests/twister_blackbox/test_qemu.py b/scripts/tests/twister_blackbox/test_qemu.py index a7f7d1c33ef..087249ccb50 100644 --- a/scripts/tests/twister_blackbox/test_qemu.py +++ b/scripts/tests/twister_blackbox/test_qemu.py @@ -74,8 +74,6 @@ def setup_class(cls): def teardown_class(cls): pass - - @pytest.mark.usefixtures("clear_log") @pytest.mark.parametrize( 'test_path, test_platforms, expected', TESTDATA_1, @@ -84,8 +82,8 @@ def teardown_class(cls): 'tests/dummy/device', ] ) - def test_emulation_only(self, capfd, test_path, test_platforms, expected): - args = ['-i', '-T', test_path, '--emulation-only'] + \ + def test_emulation_only(self, capfd, out_path, test_path, test_platforms, expected): + args = ['-i', '--outdir', out_path, '-T', test_path, '--emulation-only'] + \ [val for pair in zip( ['-p'] * len(test_platforms), test_platforms ) for val in pair] diff --git a/scripts/tests/twister_blackbox/test_report.py b/scripts/tests/twister_blackbox/test_report.py index aa5a541ff3d..1a076f97b19 100644 --- a/scripts/tests/twister_blackbox/test_report.py +++ b/scripts/tests/twister_blackbox/test_report.py @@ -110,7 +110,6 @@ def setup_class(cls): def teardown_class(cls): pass - @pytest.mark.usefixtures("clear_log") @pytest.mark.parametrize( 'test_path, test_platforms, file_name', TESTDATA_1, @@ -118,14 +117,11 @@ def teardown_class(cls): 'platform_reports' ] ) - def test_platform_reports(self, capfd, test_path, test_platforms, file_name): - args = ['-i', '-T', test_path, '--platform-reports'] + \ + def test_platform_reports(self, capfd, out_path, test_path, test_platforms, file_name): + args = ['-i', '--outdir', out_path, '-T', test_path, '--platform-reports'] + \ [val for pair in zip( ['-p'] * len(test_platforms), test_platforms ) for val in pair] - twister_path = os.path.join(ZEPHYR_BASE, "twister-out") - if os.path.exists(twister_path): - shutil.rmtree(twister_path) with mock.patch.object(sys, 'argv', [sys.argv[0]] + args), \ pytest.raises(SystemExit) as sys_exit: @@ -136,7 +132,7 @@ def test_platform_reports(self, capfd, test_path, test_platforms, file_name): sys.stderr.write(err) for f_name in file_name: - path = os.path.join(twister_path, f_name) + path = os.path.join(out_path, f_name) assert os.path.exists(path), 'file not found' if path.endswith(".json"): @@ -158,12 +154,11 @@ def test_platform_reports(self, capfd, test_path, test_platforms, file_name): pytest.fail(f"Unsupported file type: '{path}'") for f_platform in test_platforms: - platform_path = os.path.join(twister_path, f_platform) + platform_path = os.path.join(out_path, f_platform) assert os.path.exists(platform_path), f'file not found {f_platform}' assert str(sys_exit.value) == '0' - @pytest.mark.usefixtures("clear_log") @pytest.mark.parametrize( 'test_path, test_platforms, file_name', TESTDATA_2, @@ -171,16 +166,12 @@ def test_platform_reports(self, capfd, test_path, test_platforms, file_name): 'report_suffix', ] ) - def test_report_suffix(self, capfd, test_path, test_platforms, file_name): - args = ['-i', '-T', test_path, '--platform-reports', '--report-suffix=TEST'] + \ + def test_report_suffix(self, capfd, out_path, test_path, test_platforms, file_name): + args = ['-i', '--outdir', out_path, '-T', test_path, '--platform-reports', '--report-suffix=TEST'] + \ [val for pair in zip( ['-p'] * len(test_platforms), test_platforms ) for val in pair] - twister_path = os.path.join(ZEPHYR_BASE, "twister-out") - if os.path.exists(twister_path): - shutil.rmtree(twister_path) - with mock.patch.object(sys, 'argv', [sys.argv[0]] + args), \ pytest.raises(SystemExit) as sys_exit: self.loader.exec_module(self.twister_module) @@ -190,12 +181,11 @@ def test_report_suffix(self, capfd, test_path, test_platforms, file_name): sys.stderr.write(err) for f_name in file_name: - path = os.path.join(twister_path, f_name) + path = os.path.join(out_path, f_name) assert os.path.exists(path), f'file not found {f_name}' assert str(sys_exit.value) == '0' - @pytest.mark.usefixtures("clear_log") @pytest.mark.parametrize( 'test_path, test_platforms, report_arg, file_name', TESTDATA_3, @@ -205,8 +195,8 @@ def test_report_suffix(self, capfd, test_path, test_platforms, file_name): 'report-name + platform-reports + report-suffix' ] ) - def test_report_name(self, capfd, test_path, test_platforms, report_arg, file_name): - args = ['-i', '-T', test_path] + \ + def test_report_name(self, capfd, out_path, test_path, test_platforms, report_arg, file_name): + args = ['-i', '--outdir', out_path, '-T', test_path] + \ [val for pair in zip( ['-p'] * len(test_platforms), test_platforms ) for val in pair] + \ @@ -214,10 +204,6 @@ def test_report_name(self, capfd, test_path, test_platforms, report_arg, file_na report_arg ) for val in pair] - twister_path = os.path.join(ZEPHYR_BASE, "twister-out") - if os.path.exists(twister_path): - shutil.rmtree(twister_path) - with mock.patch.object(sys, 'argv', [sys.argv[0]] + args), \ pytest.raises(SystemExit) as sys_exit: self.loader.exec_module(self.twister_module) @@ -227,12 +213,11 @@ def test_report_name(self, capfd, test_path, test_platforms, report_arg, file_na sys.stderr.write(err) for f_name in file_name: - path = os.path.join(twister_path, f_name) + path = os.path.join(out_path, f_name) assert os.path.exists(path), f'file not found {f_name}' assert str(sys_exit.value) == '0' - @pytest.mark.usefixtures("clear_log") @pytest.mark.parametrize( 'test_path, test_platforms, file_name, dir_name', TESTDATA_4, @@ -240,8 +225,8 @@ def test_report_name(self, capfd, test_path, test_platforms, report_arg, file_na 'report_dir', ] ) - def test_report_dir(self, capfd, test_path, test_platforms, file_name, dir_name): - args = ['-i', '-T', test_path, "--report-dir", dir_name] + \ + def test_report_dir(self, capfd, out_path, test_path, test_platforms, file_name, dir_name): + args = ['-i', '--outdir', out_path, '-T', test_path, "--report-dir", dir_name] + \ [val for pair in zip( ['-p'] * len(test_platforms), test_platforms ) for val in pair] @@ -250,21 +235,26 @@ def test_report_dir(self, capfd, test_path, test_platforms, file_name, dir_name) if os.path.exists(twister_path): shutil.rmtree(twister_path) - with mock.patch.object(sys, 'argv', [sys.argv[0]] + args), \ - pytest.raises(SystemExit) as sys_exit: - self.loader.exec_module(self.twister_module) + try: + with mock.patch.object(sys, 'argv', [sys.argv[0]] + args), \ + pytest.raises(SystemExit) as sys_exit: + self.loader.exec_module(self.twister_module) - out, err = capfd.readouterr() - sys.stdout.write(out) - sys.stderr.write(err) + out, err = capfd.readouterr() + sys.stdout.write(out) + sys.stderr.write(err) - for f_name in file_name: - path = os.path.join(twister_path, f_name) - assert os.path.exists(path), f'file not found {f_name}' + for f_name in file_name: + path = os.path.join(twister_path, f_name) + assert os.path.exists(path), f'file not found {f_name}' - assert str(sys_exit.value) == '0' + assert str(sys_exit.value) == '0' + finally: + twister_path = os.path.join(ZEPHYR_BASE, dir_name) + if os.path.exists(twister_path): + shutil.rmtree(twister_path) - @pytest.mark.usefixtures("clear_log") + @pytest.mark.noclearout @pytest.mark.parametrize( 'test_path, test_platforms, file_name, dir_name', TESTDATA_5, @@ -290,12 +280,17 @@ def test_outdir(self, capfd, test_path, test_platforms, file_name, dir_name): sys.stdout.write(out) sys.stderr.write(err) - for f_name in file_name: - path = os.path.join(twister_path, f_name) - assert os.path.exists(path), 'file not found {f_name}' + try: + for f_name in file_name: + path = os.path.join(twister_path, f_name) + assert os.path.exists(path), 'file not found {f_name}' - for f_platform in test_platforms: - platform_path = os.path.join(twister_path, f_platform) - assert os.path.exists(platform_path), f'file not found {f_platform}' + for f_platform in test_platforms: + platform_path = os.path.join(twister_path, f_platform) + assert os.path.exists(platform_path), f'file not found {f_platform}' - assert str(sys_exit.value) == '0' + assert str(sys_exit.value) == '0' + finally: + twister_path = os.path.join(ZEPHYR_BASE, dir_name) + if os.path.exists(twister_path): + shutil.rmtree(twister_path) From 78790a85aa86c7cd8ed7c9e8b1084306e68b85d7 Mon Sep 17 00:00:00 2001 From: Daniel Leung Date: Tue, 9 Jan 2024 16:58:18 -0800 Subject: [PATCH 2026/3723] tests: net: lwm2m_engine: workaround stack overflow on qemu_x86 When running on qemu_x86, the test test_socket_state failed on stack overflow. Setting CONFIG_TEST_EXTRA_STACK_SIZE to 1024 seems to fix the issue. So add a board specific config for qemu_x86 so this test would pass. Signed-off-by: Daniel Leung --- tests/net/lib/lwm2m/lwm2m_engine/boards/qemu_x86.conf | 1 + 1 file changed, 1 insertion(+) create mode 100644 tests/net/lib/lwm2m/lwm2m_engine/boards/qemu_x86.conf diff --git a/tests/net/lib/lwm2m/lwm2m_engine/boards/qemu_x86.conf b/tests/net/lib/lwm2m/lwm2m_engine/boards/qemu_x86.conf new file mode 100644 index 00000000000..c735e1a8a2d --- /dev/null +++ b/tests/net/lib/lwm2m/lwm2m_engine/boards/qemu_x86.conf @@ -0,0 +1 @@ +CONFIG_TEST_EXTRA_STACK_SIZE=1024 From d33f8c7f27e41b5a44c7032b95462765eaf674d8 Mon Sep 17 00:00:00 2001 From: David Leach Date: Tue, 9 Jan 2024 16:03:03 -0600 Subject: [PATCH 2027/3723] drivers: i2c: i2c_mcux_lpi2c: fix unused variable warning With commit 1d7476af, it fixed a build error with config structure no longer having a base address field but left the local variable defined. This resulted in a build warning of an unused variable 'config' in two places. Signed-off-by: David Leach --- drivers/i2c/i2c_mcux_lpi2c.c | 2 -- 1 file changed, 2 deletions(-) diff --git a/drivers/i2c/i2c_mcux_lpi2c.c b/drivers/i2c/i2c_mcux_lpi2c.c index 099633beeeb..16660359312 100644 --- a/drivers/i2c/i2c_mcux_lpi2c.c +++ b/drivers/i2c/i2c_mcux_lpi2c.c @@ -310,7 +310,6 @@ static int mcux_lpi2c_recover_bus(const struct device *dev) #ifdef CONFIG_I2C_TARGET static void mcux_lpi2c_slave_irq_handler(const struct device *dev) { - const struct mcux_lpi2c_config *config = dev->config; struct mcux_lpi2c_data *data = dev->data; LPI2C_Type *base = (LPI2C_Type *)DEVICE_MMIO_NAMED_GET(dev, reg_base); const struct i2c_target_callbacks *target_cb = data->target_cfg->callbacks; @@ -454,7 +453,6 @@ static int mcux_lpi2c_target_register(const struct device *dev, static int mcux_lpi2c_target_unregister(const struct device *dev, struct i2c_target_config *target_config) { - const struct mcux_lpi2c_config *config = dev->config; struct mcux_lpi2c_data *data = dev->data; LPI2C_Type *base = (LPI2C_Type *)DEVICE_MMIO_NAMED_GET(dev, reg_base); From 4e7269669ba0f6d19767fd600531ce5ef9ab807c Mon Sep 17 00:00:00 2001 From: Anas Nashif Date: Wed, 10 Jan 2024 09:49:26 -0500 Subject: [PATCH 2028/3723] twister: hotfix for unimplemented harnesses Harness is freeform right now in the yaml file and if the harness is not implemented in class, things fail. While we cleanup and enforce implementations, this should serve as a quick fix dealing with such unimplemented harnesses. Signed-off-by: Anas Nashif --- scripts/pylib/twister/twisterlib/harness.py | 14 +++++++++----- scripts/pylib/twister/twisterlib/runner.py | 5 +++-- 2 files changed, 12 insertions(+), 7 deletions(-) diff --git a/scripts/pylib/twister/twisterlib/harness.py b/scripts/pylib/twister/twisterlib/harness.py index a70601e3de3..bfdcb107ec8 100644 --- a/scripts/pylib/twister/twisterlib/harness.py +++ b/scripts/pylib/twister/twisterlib/harness.py @@ -693,8 +693,12 @@ class HarnessImporter: @staticmethod def get_harness(harness_name): thismodule = sys.modules[__name__] - if harness_name: - harness_class = getattr(thismodule, harness_name) - else: - harness_class = getattr(thismodule, 'Test') - return harness_class() + try: + if harness_name: + harness_class = getattr(thismodule, harness_name) + else: + harness_class = getattr(thismodule, 'Test') + return harness_class() + except AttributeError as e: + logger.debug(f"harness {harness_name} not implemented: {e}") + return None diff --git a/scripts/pylib/twister/twisterlib/runner.py b/scripts/pylib/twister/twisterlib/runner.py index bfaa5939fe2..9ef53b386c9 100644 --- a/scripts/pylib/twister/twisterlib/runner.py +++ b/scripts/pylib/twister/twisterlib/runner.py @@ -1055,8 +1055,9 @@ def build(self): harness = HarnessImporter.get_harness(self.instance.testsuite.harness.capitalize()) build_result = self.run_build(['--build', self.build_dir]) try: - harness.instance = self.instance - harness.build() + if harness: + harness.instance = self.instance + harness.build() except ConfigurationError as error: self.instance.status = "error" self.instance.reason = str(error) From 9c1a45cc0051118a441a3450768abd3e3c53def6 Mon Sep 17 00:00:00 2001 From: Jonathan Hamberg Date: Thu, 4 Jan 2024 10:36:24 -0800 Subject: [PATCH 2029/3723] posix: Fix name collision with __bswap __bswap_ in zephyr/sys/byteorder.h conflicts with __bswap_ in host's byteswap.h. byteswap.h from host compiler used in posix_native_64 boards causes a compilation issue. This commit renames __bswap_ to BSWAP_ to prevent collision. Before this commit a compilation error can be created by adding #include to samples/net/sockets/echo/src/socket_echo.c This does not change external API to byteorder.h, but does change internal implementation which some other source files depend on. Replaced manual byteswap operations in devmem_service.c with APIs from byteorder.h which automatically converts to CPU endianess when necessary. Fixes #44324 Signed-off-by: Jonathan Hamberg --- drivers/fpga/fpga_zynqmp.c | 2 +- drivers/input/input_gt911.c | 8 ++-- include/zephyr/sys/byteorder.h | 51 +++++++++++----------- subsys/net/ip/utils.c | 4 +- subsys/shell/modules/devmem_service.c | 20 +++------ tests/drivers/smbus/smbus_emul/src/smbus.c | 2 +- tests/lib/cpp/cxx/src/main.cpp | 1 - 7 files changed, 39 insertions(+), 49 deletions(-) diff --git a/drivers/fpga/fpga_zynqmp.c b/drivers/fpga/fpga_zynqmp.c index 8da54462fae..8181edf5c75 100644 --- a/drivers/fpga/fpga_zynqmp.c +++ b/drivers/fpga/fpga_zynqmp.c @@ -293,7 +293,7 @@ static int zynqmp_fpga_load(const struct device *dev, uint32_t *image_ptr, } for (int i = 0; i < (img_size / 4); i++) { - *(BITSTREAM + i) = __bswap_32(*(addr + i)); + *(BITSTREAM + i) = BSWAP_32(*(addr + i)); } init_pcap(dev); diff --git a/drivers/input/input_gt911.c b/drivers/input/input_gt911.c index c7f2d5c90b3..01699c06377 100644 --- a/drivers/input/input_gt911.c +++ b/drivers/input/input_gt911.c @@ -17,9 +17,9 @@ LOG_MODULE_REGISTER(gt911, CONFIG_INPUT_LOG_LEVEL); /* GT911 used registers */ -#define DEVICE_ID __bswap_16(0x8140U) -#define REG_STATUS __bswap_16(0x814EU) -#define REG_FIRST_POINT __bswap_16(0x814FU) +#define DEVICE_ID BSWAP_16(0x8140U) +#define REG_STATUS BSWAP_16(0x814EU) +#define REG_FIRST_POINT BSWAP_16(0x814FU) /* REG_TD_STATUS: Touch points. */ #define TOUCH_POINTS_MSK 0x0FU @@ -28,7 +28,7 @@ LOG_MODULE_REGISTER(gt911, CONFIG_INPUT_LOG_LEVEL); #define TOUCH_STATUS_MSK (1 << 7U) /* The GT911's config */ -#define GT911_CONFIG_REG __bswap_16(0x8047U) +#define GT911_CONFIG_REG BSWAP_16(0x8047U) #define REG_CONFIG_VERSION GT911_CONFIG_REG #define REG_CONFIG_SIZE (186U) #define GT911_PRODUCT_ID (0x00313139U) diff --git a/include/zephyr/sys/byteorder.h b/include/zephyr/sys/byteorder.h index 978255fd02d..d1f839f5188 100644 --- a/include/zephyr/sys/byteorder.h +++ b/include/zephyr/sys/byteorder.h @@ -16,22 +16,21 @@ #include #include -/* Internal helpers only used by the sys_* APIs further below */ -#define __bswap_16(x) ((uint16_t) ((((x) >> 8) & 0xff) | (((x) & 0xff) << 8))) -#define __bswap_24(x) ((uint32_t) ((((x) >> 16) & 0xff) | \ +#define BSWAP_16(x) ((uint16_t) ((((x) >> 8) & 0xff) | (((x) & 0xff) << 8))) +#define BSWAP_24(x) ((uint32_t) ((((x) >> 16) & 0xff) | \ (((x)) & 0xff00) | \ (((x) & 0xff) << 16))) -#define __bswap_32(x) ((uint32_t) ((((x) >> 24) & 0xff) | \ +#define BSWAP_32(x) ((uint32_t) ((((x) >> 24) & 0xff) | \ (((x) >> 8) & 0xff00) | \ (((x) & 0xff00) << 8) | \ (((x) & 0xff) << 24))) -#define __bswap_48(x) ((uint64_t) ((((x) >> 40) & 0xff) | \ +#define BSWAP_48(x) ((uint64_t) ((((x) >> 40) & 0xff) | \ (((x) >> 24) & 0xff00) | \ (((x) >> 8) & 0xff0000) | \ (((x) & 0xff0000) << 8) | \ (((x) & 0xff00) << 24) | \ (((x) & 0xff) << 40))) -#define __bswap_64(x) ((uint64_t) ((((x) >> 56) & 0xff) | \ +#define BSWAP_64(x) ((uint64_t) ((((x) >> 56) & 0xff) | \ (((x) >> 40) & 0xff00) | \ (((x) >> 24) & 0xff0000) | \ (((x) >> 8) & 0xff000000) | \ @@ -222,16 +221,16 @@ #define sys_cpu_to_le48(val) (val) #define sys_le64_to_cpu(val) (val) #define sys_cpu_to_le64(val) (val) -#define sys_be16_to_cpu(val) __bswap_16(val) -#define sys_cpu_to_be16(val) __bswap_16(val) -#define sys_be24_to_cpu(val) __bswap_24(val) -#define sys_cpu_to_be24(val) __bswap_24(val) -#define sys_be32_to_cpu(val) __bswap_32(val) -#define sys_cpu_to_be32(val) __bswap_32(val) -#define sys_be48_to_cpu(val) __bswap_48(val) -#define sys_cpu_to_be48(val) __bswap_48(val) -#define sys_be64_to_cpu(val) __bswap_64(val) -#define sys_cpu_to_be64(val) __bswap_64(val) +#define sys_be16_to_cpu(val) BSWAP_16(val) +#define sys_cpu_to_be16(val) BSWAP_16(val) +#define sys_be24_to_cpu(val) BSWAP_24(val) +#define sys_cpu_to_be24(val) BSWAP_24(val) +#define sys_be32_to_cpu(val) BSWAP_32(val) +#define sys_cpu_to_be32(val) BSWAP_32(val) +#define sys_be48_to_cpu(val) BSWAP_48(val) +#define sys_cpu_to_be48(val) BSWAP_48(val) +#define sys_be64_to_cpu(val) BSWAP_64(val) +#define sys_cpu_to_be64(val) BSWAP_64(val) #define sys_uint16_to_array(val) { \ ((val) & 0xff), \ @@ -254,16 +253,16 @@ (((val) >> 56) & 0xff)} #else -#define sys_le16_to_cpu(val) __bswap_16(val) -#define sys_cpu_to_le16(val) __bswap_16(val) -#define sys_le24_to_cpu(val) __bswap_24(val) -#define sys_cpu_to_le24(val) __bswap_24(val) -#define sys_le32_to_cpu(val) __bswap_32(val) -#define sys_cpu_to_le32(val) __bswap_32(val) -#define sys_le48_to_cpu(val) __bswap_48(val) -#define sys_cpu_to_le48(val) __bswap_48(val) -#define sys_le64_to_cpu(val) __bswap_64(val) -#define sys_cpu_to_le64(val) __bswap_64(val) +#define sys_le16_to_cpu(val) BSWAP_16(val) +#define sys_cpu_to_le16(val) BSWAP_16(val) +#define sys_le24_to_cpu(val) BSWAP_24(val) +#define sys_cpu_to_le24(val) BSWAP_24(val) +#define sys_le32_to_cpu(val) BSWAP_32(val) +#define sys_cpu_to_le32(val) BSWAP_32(val) +#define sys_le48_to_cpu(val) BSWAP_48(val) +#define sys_cpu_to_le48(val) BSWAP_48(val) +#define sys_le64_to_cpu(val) BSWAP_64(val) +#define sys_cpu_to_le64(val) BSWAP_64(val) #define sys_be16_to_cpu(val) (val) #define sys_cpu_to_be16(val) (val) #define sys_be24_to_cpu(val) (val) diff --git a/subsys/net/ip/utils.c b/subsys/net/ip/utils.c index a1b3facd905..a52c96a16b6 100644 --- a/subsys/net/ip/utils.c +++ b/subsys/net/ip/utils.c @@ -539,7 +539,7 @@ uint16_t calc_chksum(uint16_t sum_in, const uint8_t *data, size_t len) * and the offset of starting */ if (odd_start == CHECKSUM_BIG_ENDIAN) { - sum = __bswap_16(sum_in); + sum = BSWAP_16(sum_in); } else { sum = sum_in; } @@ -591,7 +591,7 @@ uint16_t calc_chksum(uint16_t sum_in, const uint8_t *data, size_t len) * and the offset of starting */ if (odd_start == CHECKSUM_BIG_ENDIAN) { - return __bswap_16((uint16_t)sum); + return BSWAP_16((uint16_t)sum); } else { return sum; } diff --git a/subsys/shell/modules/devmem_service.c b/subsys/shell/modules/devmem_service.c index 3c0a42ff321..60c51d07fae 100644 --- a/subsys/shell/modules/devmem_service.c +++ b/subsys/shell/modules/devmem_service.c @@ -63,21 +63,13 @@ static int memory_dump(const struct shell *sh, mem_addr_t phys_addr, size_t size hex_data[data_offset] = value; break; case 16: - value = sys_read16(addr + data_offset); - if (IS_ENABLED(CONFIG_BIG_ENDIAN)) { - value = __bswap_16(value); - } - + value = sys_le16_to_cpu(sys_read16(addr + data_offset)); hex_data[data_offset] = (uint8_t)value; value >>= 8; hex_data[data_offset + 1] = (uint8_t)value; break; case 32: - value = sys_read32(addr + data_offset); - if (IS_ENABLED(CONFIG_BIG_ENDIAN)) { - value = __bswap_32(value); - } - + value = sys_le32_to_cpu(sys_read32(addr + data_offset)); hex_data[data_offset] = (uint8_t)value; value >>= 8; hex_data[data_offset + 1] = (uint8_t)value; @@ -192,16 +184,16 @@ static void bypass_cb(const struct shell *sh, uint8_t *recv, size_t len) if (!littleendian) { while (sum > 4) { - *data = __bswap_32(*data); + *data = BSWAP_32(*data); data++; sum = sum - 4; } if (sum % 4 == 0) { - *data = __bswap_32(*data); + *data = BSWAP_32(*data); } else if (sum % 4 == 2) { - *data = __bswap_16(*data); + *data = BSWAP_16(*data); } else if (sum % 4 == 3) { - *data = __bswap_24(*data); + *data = BSWAP_24(*data); } } return; diff --git a/tests/drivers/smbus/smbus_emul/src/smbus.c b/tests/drivers/smbus/smbus_emul/src/smbus.c index d42a22d1a23..9a96722684d 100644 --- a/tests/drivers/smbus/smbus_emul/src/smbus.c +++ b/tests/drivers/smbus/smbus_emul/src/smbus.c @@ -181,7 +181,7 @@ ZTEST(test_smbus_emul, test_proc_call) zassert_ok(ret, "SMBus Proc Call failed"); /* Our emulated Proc Call swaps bytes */ - zassert_equal(snd_word, __bswap_16(rcv_word), "Data mismatch"); + zassert_equal(snd_word, BSWAP_16(rcv_word), "Data mismatch"); } ZTEST(test_smbus_emul, test_block) diff --git a/tests/lib/cpp/cxx/src/main.cpp b/tests/lib/cpp/cxx/src/main.cpp index 43bc14f65ac..dd377c015b8 100644 --- a/tests/lib/cpp/cxx/src/main.cpp +++ b/tests/lib/cpp/cxx/src/main.cpp @@ -17,7 +17,6 @@ #include #include #include -/* #include conflicts with __bswapXX on native_posix */ #include #include From a147c8814b55d242a41770ab706387bd7ca93bf5 Mon Sep 17 00:00:00 2001 From: Jonathan Rico Date: Tue, 9 Jan 2024 16:12:11 +0100 Subject: [PATCH 2030/3723] MAINTAINERS: Add myself as Bluetooth host co-maintainer As discussed in the Bluetooth host weekly meeting. Signed-off-by: Jonathan Rico --- MAINTAINERS.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/MAINTAINERS.yml b/MAINTAINERS.yml index ef82c8e3e7c..f4c36391723 100644 --- a/MAINTAINERS.yml +++ b/MAINTAINERS.yml @@ -353,10 +353,10 @@ Bluetooth controller: Bluetooth Host: status: maintained maintainers: + - jori-nordic - jhedberg collaborators: - hermabe - - jori-nordic - alwa-nordic - Vudentz - Thalley From 4d7b7c89a6b7daa3dd5761e6eb7f577cca4b0559 Mon Sep 17 00:00:00 2001 From: Jonathan Rico Date: Tue, 9 Jan 2024 16:13:57 +0100 Subject: [PATCH 2031/3723] MAINTAINERS: Remove inactive collaborators from Bluetooth host They have been inactive for more than a few months. Signed-off-by: Jonathan Rico --- MAINTAINERS.yml | 3 --- 1 file changed, 3 deletions(-) diff --git a/MAINTAINERS.yml b/MAINTAINERS.yml index f4c36391723..fe0a7c2e3b5 100644 --- a/MAINTAINERS.yml +++ b/MAINTAINERS.yml @@ -358,12 +358,9 @@ Bluetooth Host: collaborators: - hermabe - alwa-nordic - - Vudentz - Thalley - - asbjornsabo - sjanc - theob-pro - - kruithofa files: - drivers/bluetooth/ - subsys/bluetooth/host/ From 1b490592375b32f24eb8148647b600eecd6ba0a9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?H=C3=A5vard=20Reierstad?= Date: Wed, 10 Jan 2024 10:37:34 +0100 Subject: [PATCH 2032/3723] MAINTAINERS: Add HaavardRei as BT Mesh collaborator MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Add myself as a Bluetooth Mesh collaborator Signed-off-by: Håvard Reierstad --- MAINTAINERS.yml | 1 + 1 file changed, 1 insertion(+) diff --git a/MAINTAINERS.yml b/MAINTAINERS.yml index fe0a7c2e3b5..9cee672506f 100644 --- a/MAINTAINERS.yml +++ b/MAINTAINERS.yml @@ -382,6 +382,7 @@ Bluetooth Mesh: - alxelax - Andrewpini - akredalen + - HaavardRei files: - subsys/bluetooth/mesh/ - include/zephyr/bluetooth/mesh/ From 283d813c8853821e319583438353313425f72967 Mon Sep 17 00:00:00 2001 From: Christopher Friedt Date: Thu, 21 Dec 2023 21:56:12 -0500 Subject: [PATCH 2033/3723] doc: posix: option groups: abbreviate POSIX_C_LANG_SUPPORT In order to reduce verbosity on the primary Option Groups page, simply add a note that the POSIX_C_LANG_SUPPORT is considered supported with newlib, picolibc, or any other libc conforming to the ISO C standard. Add a link to the language support page that details C, C++, .. Signed-off-by: Christopher Friedt --- doc/services/portability/posix/aep/index.rst | 9 +- .../portability/posix/option_groups/index.rst | 119 ++---------------- .../portability/posix/overview/index.rst | 6 +- 3 files changed, 17 insertions(+), 117 deletions(-) diff --git a/doc/services/portability/posix/aep/index.rst b/doc/services/portability/posix/aep/index.rst index 30b3e517cd5..431da449fe4 100644 --- a/doc/services/portability/posix/aep/index.rst +++ b/doc/services/portability/posix/aep/index.rst @@ -26,7 +26,7 @@ Minimal Realtime System Profile (PSE51) :widths: 50, 10, 50 POSIX_C_LANG_JUMP,, - POSIX_C_LANG_SUPPORT, yes, :ref:`†` + POSIX_C_LANG_SUPPORT, yes, :ref:`POSIX_C_LANG_SUPPORT ` POSIX_DEVICE_IO,, :ref:`†` POSIX_FILE_LOCKING,, POSIX_SIGNALS,, :ref:`†` @@ -57,9 +57,6 @@ Minimal Realtime System Profile (PSE51) _POSIX_TIMEOUTS, 200809L, :kconfig:option:`CONFIG_PTHREAD_IPC` _POSIX_TIMERS, 200809L, :kconfig:option:`CONFIG_POSIX_CLOCK` -.. note:: - For PSE51 support, 44 of 75 symbols are currently implemented. - .. _posix_aep_pse52: Realtime Controller System Profile (PSE52) @@ -79,7 +76,7 @@ Realtime Controller System Profile (PSE52) POSIX_C_LANG_JUMP,, POSIX_C_LANG_MATH, yes, - POSIX_C_LANG_SUPPORT, yes, :ref:`†` + POSIX_C_LANG_SUPPORT, yes, :ref:`POSIX_C_LANG_SUPPORT ` POSIX_DEVICE_IO,, :ref:`†` POSIX_FD_MGMT,, POSIX_FILE_LOCKING,, @@ -136,7 +133,7 @@ Dedicated Realtime System Profile (PSE53) POSIX_C_LANG_JUMP,, POSIX_C_LANG_MATH, yes, - POSIX_C_LANG_SUPPORT, yes, :ref:`†` + POSIX_C_LANG_SUPPORT, yes, :ref:`POSIX_C_LANG_SUPPORT ` POSIX_DEVICE_IO,, :ref:`†` POSIX_FD_MGMT,, POSIX_FILE_LOCKING,, diff --git a/doc/services/portability/posix/option_groups/index.rst b/doc/services/portability/posix/option_groups/index.rst index edbd6899841..135b74a2142 100644 --- a/doc/services/portability/posix/option_groups/index.rst +++ b/doc/services/portability/posix/option_groups/index.rst @@ -107,118 +107,17 @@ This table lists service support status in Zephyr: POSIX_C_LANG_SUPPORT ==================== -The POSIX_C_LANG_SUPPORT option group contains the general ISO C -Library. +The POSIX_C_LANG_SUPPORT option group contains the general ISO C Library. -.. csv-table:: POSIX_C_LANG_SUPPORT - :header: API, Supported - :widths: 50,10 +.. note:: + When using Newlib, Picolibc, or other C libraries conforming to the ISO C Standard, the entire + ``POSIX_C_LANG_SUPPORT`` Option Group is considered supported. + +Please refer to `Subprofiling Considerations`_ for details on the ``POSIX_C_LANG_SUPPORT`` Option +Group. - abs(),yes - asctime(), - asctime_r(), - atof(), - atoi(),yes - atol(), - atoll(), - bsearch(),yes - calloc(),yes - ctime(), - ctime_r(), - difftime(), - div(), - feclearexcept(), - fegetenv(), - fegetexceptflag(), - fegetround(), - feholdexcept(), - feraiseexcept(), - fesetenv(), - fesetexceptflag(), - fesetround(), - fetestexcept(), - feupdateenv(), - free(),yes - gmtime(),yes - gmtime_r(),yes - imaxabs(), - imaxdiv(), - isalnum(),yes - isalpha(),yes - isblank(), - iscntrl(),yes - isdigit(),yes - isgraph(),yes - islower(), - isprint(),yes - ispunct(), - isspace(),yes - isupper(),yes - isxdigit(),yes - labs(),yes - ldiv(), - llabs(),yes - lldiv(), - localeconv(), - localtime(),yes - localtime_r(), - malloc(),yes - memchr(),yes - memcmp(),yes - memcpy(),yes - memmove(),yes - memset(),yes - mktime(),yes - qsort(),yes - rand(),yes - rand_r(),yes - realloc(),yes - setlocale(), - snprintf(),yes - sprintf(),yes - srand(),yes - sscanf(), - strcat(),yes - strchr(),yes - strcmp(),yes - strcoll(), - strcpy(),yes - strcspn(),yes - strerror(),yes - strerror_r(),yes - strftime(), - strlen(),yes - strncat(),yes - strncmp(),yes - strncpy(),yes - strpbrk(), - strrchr(),yes - strspn(),yes - strstr(),yes - strtod(), - strtof(), - strtoimax(), - strtok(),yes - strtok_r(),yes - strtol(),yes - strtold(), - strtoll(),yes - strtoul(),yes - strtoull(),yes - strtoumax(), - strxfrm(), - time(),yes - tolower(),yes - toupper(),yes - tzname(), - tzset(), - va_arg(),yes - va_copy(),yes - va_end(),yes - va_start(),yes - vsnprintf(),yes - vsprintf(),yes - vsscanf(), +For more information on developing Zephyr applications in the C programming language, please refer +to :ref:`details`. .. _posix_option_group_single_process: diff --git a/doc/services/portability/posix/overview/index.rst b/doc/services/portability/posix/overview/index.rst index 56810e49ac1..384e7c142c0 100644 --- a/doc/services/portability/posix/overview/index.rst +++ b/doc/services/portability/posix/overview/index.rst @@ -59,7 +59,9 @@ as part of `IEEE 1003.13-2003`_ (also known as POSIX.13-2003). POSIX.13-2003 AEP were formalized in 2003 via "Units of Functionality" but the specification is now inactive (for reference only). Nevertheless, the intent is still captured as part of POSIX-1.2017 -via :ref:`Options` and :ref:`Option Groups`, in Appendix E. +via :ref:`Options` and :ref:`Option Groups`. + +For more information, please see `IEEE 1003.1-2017, Section E, Subprofiling Considerations`_. .. _posix_apps: @@ -133,3 +135,5 @@ Alternatively, users may enable one of the Kconfig options below as a shortcut t .. _IEEE Computer Society: https://www.computer.org/ .. _IEEE 1003.1-2017: https://standards.ieee.org/ieee/1003.1/7101/ .. _IEEE 1003.13-2003: https://standards.ieee.org/ieee/1003.13/3322/ +.. _IEEE 1003.1-2017, Section E, Subprofiling Considerations: + https://pubs.opengroup.org/onlinepubs/9699919799/xrat/V4_subprofiles.html From ce42bf38207a6052d92e8dcec89228aa71230660 Mon Sep 17 00:00:00 2001 From: Christopher Friedt Date: Thu, 4 Jan 2024 13:33:49 -0500 Subject: [PATCH 2034/3723] doc: posix: option groups: add C_LANG_JUMP and C_LANG_MATH Add POSIX_C_LANG_JUMP and POSIX_C_LANG_MATH option groups with links to specification details on opengroup.org . Signed-off-by: Christopher Friedt --- doc/services/portability/posix/aep/index.rst | 10 +++--- .../portability/posix/option_groups/index.rst | 36 +++++++++++++++++++ 2 files changed, 41 insertions(+), 5 deletions(-) diff --git a/doc/services/portability/posix/aep/index.rst b/doc/services/portability/posix/aep/index.rst index 431da449fe4..55a841dd565 100644 --- a/doc/services/portability/posix/aep/index.rst +++ b/doc/services/portability/posix/aep/index.rst @@ -25,7 +25,7 @@ Minimal Realtime System Profile (PSE51) :header: Symbol, Support, Remarks :widths: 50, 10, 50 - POSIX_C_LANG_JUMP,, + POSIX_C_LANG_JUMP, yes, :ref:`POSIX_C_LANG_JUMP ` POSIX_C_LANG_SUPPORT, yes, :ref:`POSIX_C_LANG_SUPPORT ` POSIX_DEVICE_IO,, :ref:`†` POSIX_FILE_LOCKING,, @@ -74,8 +74,8 @@ Realtime Controller System Profile (PSE52) :header: Symbol, Support, Remarks :widths: 50, 10, 50 - POSIX_C_LANG_JUMP,, - POSIX_C_LANG_MATH, yes, + POSIX_C_LANG_JUMP, yes, :ref:`POSIX_C_LANG_JUMP ` + POSIX_C_LANG_MATH, yes, :ref:`POSIX_C_LANG_MATH ` POSIX_C_LANG_SUPPORT, yes, :ref:`POSIX_C_LANG_SUPPORT ` POSIX_DEVICE_IO,, :ref:`†` POSIX_FD_MGMT,, @@ -131,8 +131,8 @@ Dedicated Realtime System Profile (PSE53) :header: Symbol, Support, Remarks :widths: 50, 10, 50 - POSIX_C_LANG_JUMP,, - POSIX_C_LANG_MATH, yes, + POSIX_C_LANG_JUMP, yes, :ref:`POSIX_C_LANG_JUMP ` + POSIX_C_LANG_MATH, yes, :ref:`POSIX_C_LANG_MATH ` POSIX_C_LANG_SUPPORT, yes, :ref:`POSIX_C_LANG_SUPPORT ` POSIX_DEVICE_IO,, :ref:`†` POSIX_FD_MGMT,, diff --git a/doc/services/portability/posix/option_groups/index.rst b/doc/services/portability/posix/option_groups/index.rst index 135b74a2142..806ee1adcb4 100644 --- a/doc/services/portability/posix/option_groups/index.rst +++ b/doc/services/portability/posix/option_groups/index.rst @@ -102,6 +102,38 @@ This table lists service support status in Zephyr: pthread_getconcurrency(),yes pthread_setconcurrency(),yes +.. _posix_option_group_c_lang_jump: + +POSIX_C_LANG_JUMP +================= + +The ``POSIX_C_LANG_JUMP`` Option Group is included in the ISO C standard. + +.. note:: + When using Newlib, Picolibc, or other C libraries conforming to the ISO C Standard, the + ``POSIX_C_LANG_JUMP`` Option Group is considered supported. + +.. csv-table:: POSIX_C_LANG_JUMP + :header: API, Supported + :widths: 50,10 + + setjmp(), yes + longjmp(), yes + +.. _posix_option_group_c_lang_math: + +POSIX_C_LANG_MATH +================= + +The ``POSIX_C_LANG_MATH`` Option Group is included in the ISO C standard. + +.. note:: + When using Newlib, Picolibc, or other C libraries conforming to the ISO C Standard, the + ``POSIX_C_LANG_MATH`` Option Group is considered supported. + +Please refer to `Subprofiling Considerations`_ for details on the ``POSIX_C_LANG_MATH`` Option +Group. + .. _posix_option_group_c_lang_support: POSIX_C_LANG_SUPPORT @@ -450,3 +482,7 @@ _XOPEN_STREAMS isastream(), putmsg(), putpmsg(), + + +.. _Subprofiling Considerations: + https://pubs.opengroup.org/onlinepubs/9699919799/xrat/V4_subprofiles.html From 5bbec7a45d7f7c821410239c5a80d7aab6309fac Mon Sep 17 00:00:00 2001 From: Christopher Friedt Date: Thu, 4 Jan 2024 13:51:55 -0500 Subject: [PATCH 2035/3723] docs: posix: option groups: add _POSIX_THREAD_SAFE_FUNCTIONS The _POSIX_THREAD_SAFE_FUNCTIONS option was mentioned in aep/index.rst but not expanded. Signed-off-by: Christopher Friedt --- .../portability/posix/conformance/index.rst | 2 +- .../portability/posix/option_groups/index.rst | 29 +++++++++++++++++++ 2 files changed, 30 insertions(+), 1 deletion(-) diff --git a/doc/services/portability/posix/conformance/index.rst b/doc/services/portability/posix/conformance/index.rst index 7d28efcf9ac..683799e7ab6 100644 --- a/doc/services/portability/posix/conformance/index.rst +++ b/doc/services/portability/posix/conformance/index.rst @@ -61,7 +61,7 @@ POSIX System Interfaces _POSIX_REALTIME_SIGNALS, -1, :ref:`†` :ref:`_POSIX_SEMAPHORES`, 200809L, :kconfig:option:`CONFIG_PTHREAD_IPC` :ref:`_POSIX_SPIN_LOCKS`, 200809L, :kconfig:option:`CONFIG_PTHREAD_SPINLOCK` - _POSIX_THREAD_SAFE_FUNCTIONS, 200809L, + :ref:`_POSIX_THREAD_SAFE_FUNCTIONS`, -1, :ref:`_POSIX_THREADS`, -1, :kconfig:option:`CONFIG_PTHREAD_IPC` :ref:`_POSIX_TIMEOUTS`, 200809L, :kconfig:option:`CONFIG_PTHREAD_IPC` :ref:`_POSIX_TIMERS`, 200809L, :kconfig:option:`CONFIG_POSIX_CLOCK` diff --git a/doc/services/portability/posix/option_groups/index.rst b/doc/services/portability/posix/option_groups/index.rst index 806ee1adcb4..47fc9ebd0f9 100644 --- a/doc/services/portability/posix/option_groups/index.rst +++ b/doc/services/portability/posix/option_groups/index.rst @@ -448,6 +448,35 @@ _POSIX_THREAD_PRIORITY_SCHEDULING pthread_setschedparam(),yes pthread_setschedprio(),yes +.. _posix_thread_safe_functions: + +_POSIX_THREAD_SAFE_FUNCTIONS +++++++++++++++++++++++++++++ + +.. csv-table:: _POSIX_THREAD_SAFE_FUNCTIONS + :header: API, Supported + :widths: 50,10 + + asctime_r(), + ctime_r(), + flockfile(), + ftrylockfile(), + funlockfile(), + getc_unlocked(), yes + getchar_unlocked(), yes + getgrgid_r(), + getgrnam_r(), + getpwnam_r(), + getpwuid_r(), + gmtime_r(), yes + localtime_r(), + putc_unlocked(), yes + putchar_unlocked(), yes + rand_r(), yes + readdir_r(), + strerror_r(), yes + strtok_r(), yes + .. _posix_option_timeouts: _POSIX_TIMEOUTS From b85b7a34907cc8505df8f70d81446900149bf093 Mon Sep 17 00:00:00 2001 From: Christopher Friedt Date: Thu, 4 Jan 2024 13:40:47 -0500 Subject: [PATCH 2036/3723] doc: posix: overview: clarification on conformant implementations Any C library with conformant implementations of POSIX features, options, or option groups can be used in place of the versions provided with Zephyr's POSIX implementation as long as there is no source licensing compatibility or linking clause violation. Implementations of such features, options, or option groups can be used in whole or in part, as long as there is no conflict with the rest of Zephyr or the application. Signed-off-by: Christopher Friedt --- doc/services/portability/posix/conformance/index.rst | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/doc/services/portability/posix/conformance/index.rst b/doc/services/portability/posix/conformance/index.rst index 683799e7ab6..53f3113ca68 100644 --- a/doc/services/portability/posix/conformance/index.rst +++ b/doc/services/portability/posix/conformance/index.rst @@ -14,6 +14,13 @@ As per `IEEE 1003.1-2017`, this section details Zephyr's POSIX conformance. Zephyr's current design, some features requiring multi-process capabilities may exhibit undefined behaviour, which we denote with the † (obelus) symbol. +.. _posix_libc_provided: + +.. note:: + Features listed in various POSIX Options or Option Groups may be provided in whole or in part + by a conformant C library implementation. This includes (but is not limited to) POSIX + Extensions to the ISO C Standard (`CX`_). + .. _posix_system_interfaces: POSIX System Interfaces @@ -143,3 +150,5 @@ XSI System Interfaces :ref:`_POSIX_THREAD_ATTR_STACKADDR`, 200809L, :kconfig:option:`CONFIG_PTHREAD` :ref:`_POSIX_THREAD_ATTR_STACKSIZE`, 200809L, :kconfig:option:`CONFIG_PTHREAD` _POSIX_THREAD_PROCESS_SHARED, -1, + +.. _CX: https://pubs.opengroup.org/onlinepubs/9699919799/basedefs/V1_chap01.html From c65b1bb241189b88d14952d80ca6e2117b307edf Mon Sep 17 00:00:00 2001 From: Pisit Sawangvonganan Date: Sat, 23 Dec 2023 17:07:41 +0700 Subject: [PATCH 2037/3723] drivers: flash: spi_nor: ensure paired calling of acquire/release_device Adjusted the code to guarantee resource release irrespective of operation success or failure. Fixes #67336 Signed-off-by: Pisit Sawangvonganan --- drivers/flash/spi_nor.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/drivers/flash/spi_nor.c b/drivers/flash/spi_nor.c index 1658fce1039..06518175e45 100644 --- a/drivers/flash/spi_nor.c +++ b/drivers/flash/spi_nor.c @@ -659,6 +659,7 @@ static int mxicy_configure(const struct device *dev, const uint8_t *jedec_id) ret = mxicy_rdcr(dev); if (ret < 0) { + release_device(dev); return ret; } current_cr = ret; @@ -1231,6 +1232,7 @@ static int spi_nor_configure(const struct device *dev) rc = exit_dpd(dev); if (rc < 0) { LOG_ERR("Failed to exit DPD (%d)", rc); + release_device(dev); return -ENODEV; } @@ -1280,12 +1282,12 @@ static int spi_nor_configure(const struct device *dev) rc = spi_nor_wrsr(dev, rc & ~cfg->has_lock); } + release_device(dev); + if (rc != 0) { LOG_ERR("BP clear failed: %d\n", rc); return -ENODEV; } - - release_device(dev); } #ifdef CONFIG_SPI_NOR_SFDP_MINIMAL From e5974b2aac2cc1dd5447d02b41be2625f4a22206 Mon Sep 17 00:00:00 2001 From: Fabio Baltieri Date: Thu, 4 Jan 2024 14:12:41 +0000 Subject: [PATCH 2038/3723] input: gpio_keys: implement polling mode support Some MCU have limitations with GPIO interrupts. Add a polling mode to the gpio-keys driver to support those cases. This required a bit of a refactoring of the driver data structure to add a instance wide data, and move the pin specific pointer in the config structure. For polling, reuse the button 0 delayed work so we minimize the resource waste, the two work handler functions are only referenced when used so at least those are discarded automatically if no instance needs them. Fix a bug in the PM structure instantiation as well. Signed-off-by: Fabio Baltieri --- drivers/input/input_gpio_keys.c | 110 ++++++++++++++++++---- dts/bindings/input/gpio-keys.yaml | 8 ++ tests/drivers/build_all/input/app.overlay | 10 ++ 3 files changed, 108 insertions(+), 20 deletions(-) diff --git a/drivers/input/input_gpio_keys.c b/drivers/input/input_gpio_keys.c index e9df3cb907d..cd277c19fdc 100644 --- a/drivers/input/input_gpio_keys.c +++ b/drivers/input/input_gpio_keys.c @@ -13,6 +13,7 @@ #include #include #include +#include LOG_MODULE_REGISTER(gpio_keys, CONFIG_INPUT_LOG_LEVEL); @@ -27,35 +28,43 @@ struct gpio_keys_pin_config { /** Zephyr code from devicetree */ uint32_t zephyr_code; }; + +struct gpio_keys_pin_data { + const struct device *dev; + struct gpio_keys_callback cb_data; + struct k_work_delayable work; + int8_t pin_state; +}; + struct gpio_keys_config { /** Debounce interval in milliseconds from devicetree */ uint32_t debounce_interval_ms; const int num_keys; const struct gpio_keys_pin_config *pin_cfg; + struct gpio_keys_pin_data *pin_data; + k_work_handler_t handler; + bool polling_mode; }; -struct gpio_keys_pin_data { - const struct device *dev; - struct gpio_keys_callback cb_data; - struct k_work_delayable work; - int8_t pin_state; +struct gpio_keys_data { +#ifdef CONFIG_PM_DEVICE + atomic_t suspended; +#endif }; /** * Handle debounced gpio pin state. */ -static void gpio_keys_change_deferred(struct k_work *work) +static void gpio_keys_poll_pin(const struct device *dev, int key_index) { - struct k_work_delayable *dwork = k_work_delayable_from_work(work); - struct gpio_keys_pin_data *pin_data = CONTAINER_OF(dwork, struct gpio_keys_pin_data, work); - const struct device *dev = pin_data->dev; - int key_index = pin_data - (struct gpio_keys_pin_data *)dev->data; const struct gpio_keys_config *cfg = dev->config; const struct gpio_keys_pin_config *pin_cfg = &cfg->pin_cfg[key_index]; + struct gpio_keys_pin_data *pin_data = &cfg->pin_data[key_index]; + int new_pressed; - const int new_pressed = gpio_pin_get(pin_cfg->spec.port, pin_cfg->spec.pin); + new_pressed = gpio_pin_get(pin_cfg->spec.port, pin_cfg->spec.pin); - LOG_DBG("gpio_change_deferred %s pin_state=%d, new_pressed=%d, key_index=%d", dev->name, + LOG_DBG("%s: pin_state=%d, new_pressed=%d, key_index=%d", dev->name, pin_data->cb_data.pin_state, new_pressed, key_index); /* If gpio changed, report the event */ @@ -67,6 +76,39 @@ static void gpio_keys_change_deferred(struct k_work *work) } } +static __maybe_unused void gpio_keys_poll_pins(struct k_work *work) +{ + struct k_work_delayable *dwork = k_work_delayable_from_work(work); + struct gpio_keys_pin_data *pin_data = CONTAINER_OF(dwork, struct gpio_keys_pin_data, work); + const struct device *dev = pin_data->dev; + const struct gpio_keys_config *cfg = dev->config; + +#ifdef CONFIG_PM_DEVICE + struct gpio_keys_data *data = dev->data; + + if (atomic_get(&data->suspended) == 1) { + return; + } +#endif + + for (int i = 0; i < cfg->num_keys; i++) { + gpio_keys_poll_pin(dev, i); + } + + k_work_reschedule(dwork, K_MSEC(cfg->debounce_interval_ms)); +} + +static __maybe_unused void gpio_keys_change_deferred(struct k_work *work) +{ + struct k_work_delayable *dwork = k_work_delayable_from_work(work); + struct gpio_keys_pin_data *pin_data = CONTAINER_OF(dwork, struct gpio_keys_pin_data, work); + const struct device *dev = pin_data->dev; + const struct gpio_keys_config *cfg = dev->config; + int key_index = pin_data - (struct gpio_keys_pin_data *)cfg->pin_data; + + gpio_keys_poll_pin(dev, key_index); +} + static void gpio_keys_interrupt(const struct device *dev, struct gpio_callback *cbdata, uint32_t pins) { @@ -97,7 +139,7 @@ static int gpio_keys_interrupt_configure(const struct gpio_dt_spec *gpio_spec, cb->pin_state = -1; - LOG_DBG("%s [0x%p, %d]", __func__, gpio_spec->port, gpio_spec->pin); + LOG_DBG("port=%s, pin=%d", gpio_spec->port->name, gpio_spec->pin); ret = gpio_pin_interrupt_configure_dt(gpio_spec, GPIO_INT_EDGE_BOTH); if (ret < 0) { @@ -110,8 +152,8 @@ static int gpio_keys_interrupt_configure(const struct gpio_dt_spec *gpio_spec, static int gpio_keys_init(const struct device *dev) { - struct gpio_keys_pin_data *pin_data = dev->data; const struct gpio_keys_config *cfg = dev->config; + struct gpio_keys_pin_data *pin_data = cfg->pin_data; int ret; for (int i = 0; i < cfg->num_keys; i++) { @@ -129,7 +171,11 @@ static int gpio_keys_init(const struct device *dev) } pin_data[i].dev = dev; - k_work_init_delayable(&pin_data[i].work, gpio_keys_change_deferred); + k_work_init_delayable(&pin_data[i].work, cfg->handler); + + if (cfg->polling_mode) { + continue; + } ret = gpio_keys_interrupt_configure(&cfg->pin_cfg[i].spec, &pin_data[i].cb_data, @@ -140,6 +186,11 @@ static int gpio_keys_init(const struct device *dev) } } + if (cfg->polling_mode) { + /* use pin 0 work to poll all the pins periodically */ + k_work_reschedule(&pin_data[0].work, K_MSEC(cfg->debounce_interval_ms)); + } + ret = pm_device_runtime_enable(dev); if (ret < 0) { LOG_ERR("Failed to enable runtime power management"); @@ -154,6 +205,8 @@ static int gpio_keys_pm_action(const struct device *dev, enum pm_device_action action) { const struct gpio_keys_config *cfg = dev->config; + struct gpio_keys_data *data = dev->data; + struct gpio_keys_pin_data *pin_data = cfg->pin_data; gpio_flags_t gpio_flags; gpio_flags_t int_flags; int ret; @@ -162,10 +215,12 @@ static int gpio_keys_pm_action(const struct device *dev, case PM_DEVICE_ACTION_SUSPEND: gpio_flags = GPIO_DISCONNECTED; int_flags = GPIO_INT_DISABLE; + atomic_set(&data->suspended, 1); break; case PM_DEVICE_ACTION_RESUME: gpio_flags = GPIO_INPUT; int_flags = GPIO_INT_EDGE_BOTH; + atomic_set(&data->suspended, 0); break; default: return -ENOTSUP; @@ -180,6 +235,10 @@ static int gpio_keys_pm_action(const struct device *dev, return ret; } + if (cfg->polling_mode) { + continue; + } + ret = gpio_pin_interrupt_configure_dt(gpio, int_flags); if (ret < 0) { LOG_ERR("interrupt configuration failed: %d", ret); @@ -187,6 +246,11 @@ static int gpio_keys_pm_action(const struct device *dev, } } + if (action == PM_DEVICE_ACTION_RESUME && cfg->polling_mode) { + k_work_reschedule(&pin_data[0].work, + K_MSEC(cfg->debounce_interval_ms)); + } + return 0; } #endif @@ -207,19 +271,25 @@ static int gpio_keys_pm_action(const struct device *dev, static const struct gpio_keys_pin_config gpio_keys_pin_config_##i[] = { \ DT_INST_FOREACH_CHILD_STATUS_OKAY_SEP(i, GPIO_KEYS_CFG_DEF, (,))}; \ \ + static struct gpio_keys_pin_data \ + gpio_keys_pin_data_##i[ARRAY_SIZE(gpio_keys_pin_config_##i)]; \ + \ static const struct gpio_keys_config gpio_keys_config_##i = { \ .debounce_interval_ms = DT_INST_PROP(i, debounce_interval_ms), \ .num_keys = ARRAY_SIZE(gpio_keys_pin_config_##i), \ .pin_cfg = gpio_keys_pin_config_##i, \ + .pin_data = gpio_keys_pin_data_##i, \ + .handler = COND_CODE_1(DT_INST_PROP(i, polling_mode), \ + (gpio_keys_poll_pins), (gpio_keys_change_deferred)), \ + .polling_mode = DT_INST_PROP(i, polling_mode), \ }; \ \ - static struct gpio_keys_pin_data \ - gpio_keys_pin_data_##i[ARRAY_SIZE(gpio_keys_pin_config_##i)]; \ + static struct gpio_keys_data gpio_keys_data_##i; \ \ - PM_DEVICE_DT_INST_DEFINE(n, gpio_keys_pm_action); \ + PM_DEVICE_DT_INST_DEFINE(i, gpio_keys_pm_action); \ \ - DEVICE_DT_INST_DEFINE(i, &gpio_keys_init, PM_DEVICE_DT_INST_GET(n), \ - gpio_keys_pin_data_##i, &gpio_keys_config_##i, \ + DEVICE_DT_INST_DEFINE(i, &gpio_keys_init, PM_DEVICE_DT_INST_GET(i), \ + &gpio_keys_data_##i, &gpio_keys_config_##i, \ POST_KERNEL, CONFIG_INPUT_INIT_PRIORITY, NULL); DT_INST_FOREACH_STATUS_OKAY(GPIO_KEYS_INIT) diff --git a/dts/bindings/input/gpio-keys.yaml b/dts/bindings/input/gpio-keys.yaml index 9b3581a1c13..f2776bbda9d 100644 --- a/dts/bindings/input/gpio-keys.yaml +++ b/dts/bindings/input/gpio-keys.yaml @@ -35,15 +35,23 @@ properties: Debouncing interval time in milliseconds. If not specified defaults to 30. + polling-mode: + type: boolean + description: | + Do not use interrupts for the key GPIOs, poll the pin periodically at the + specified debounce-interval-ms instead. + child-binding: description: GPIO KEYS child node properties: gpios: type: phandle-array required: true + label: type: string description: Descriptive name of the key + zephyr,code: type: int description: Key code to emit. diff --git a/tests/drivers/build_all/input/app.overlay b/tests/drivers/build_all/input/app.overlay index 66edd90f8bd..d1baa128237 100644 --- a/tests/drivers/build_all/input/app.overlay +++ b/tests/drivers/build_all/input/app.overlay @@ -42,6 +42,16 @@ }; }; + gpio-keys-polled { + compatible = "gpio-keys"; + debounce-interval-ms = <30>; + button_0 { + gpios = <&test_gpio 0 0>; + zephyr,code = <0>; + }; + polling-mode; + }; + evdev { compatible = "zephyr,native-linux-evdev"; }; From 38aa4d5169e3fe60ef32b0de473831046516891d Mon Sep 17 00:00:00 2001 From: Simon Walz Date: Mon, 8 Jan 2024 13:42:28 +0100 Subject: [PATCH 2039/3723] net: lwm2m: add gateway callback to handle prefixed messages Adding a callback for handling lwm2m messages with prefixed paths defined by the gateway object. If CONFIG_LWM2M_GATEWAY_OBJ_SUPPORT is set, each path is checked for the prefix stored in the object instances of the gateway object 25. If prefixes match the msg is passed to the gw_msg_cb. Signed-off-by: Simon Walz --- subsys/net/lib/lwm2m/lwm2m_message_handling.c | 12 ++++- subsys/net/lib/lwm2m/lwm2m_message_handling.h | 2 + subsys/net/lib/lwm2m/lwm2m_obj_gateway.c | 52 +++++++++++++++++++ subsys/net/lib/lwm2m/lwm2m_obj_gateway.h | 40 ++++++++++++++ 4 files changed, 105 insertions(+), 1 deletion(-) diff --git a/subsys/net/lib/lwm2m/lwm2m_message_handling.c b/subsys/net/lib/lwm2m/lwm2m_message_handling.c index 677879304f8..480c64372e8 100644 --- a/subsys/net/lib/lwm2m/lwm2m_message_handling.c +++ b/subsys/net/lib/lwm2m/lwm2m_message_handling.c @@ -46,6 +46,7 @@ LOG_MODULE_REGISTER(LOG_MODULE_NAME); #include "lwm2m_object.h" #include "lwm2m_obj_access_control.h" #include "lwm2m_obj_server.h" +#include "lwm2m_obj_gateway.h" #include "lwm2m_rw_link_format.h" #include "lwm2m_rw_oma_tlv.h" #include "lwm2m_rw_plain_text.h" @@ -479,7 +480,7 @@ void lwm2m_engine_context_init(struct lwm2m_ctx *client_ctx) } /* utility functions */ -static int coap_options_to_path(struct coap_option *opt, int options_count, +int coap_options_to_path(struct coap_option *opt, int options_count, struct lwm2m_obj_path *path) { uint16_t len, @@ -2268,6 +2269,15 @@ static int handle_request(struct coap_packet *request, struct lwm2m_message *msg msg->token = token; } + if (IS_ENABLED(CONFIG_LWM2M_GATEWAY_OBJ_SUPPORT)) { + r = lwm2m_gw_handle_req(msg); + if (r == 0) { + return 0; + } else if (r != -ENOENT) { + goto error; + } + } + /* parse the URL path into components */ r = coap_find_options(msg->in.in_cpkt, COAP_OPTION_URI_PATH, options, ARRAY_SIZE(options)); if (r < 0) { diff --git a/subsys/net/lib/lwm2m/lwm2m_message_handling.h b/subsys/net/lib/lwm2m/lwm2m_message_handling.h index c41fbbac0ee..3ac014b5db8 100644 --- a/subsys/net/lib/lwm2m/lwm2m_message_handling.h +++ b/subsys/net/lib/lwm2m/lwm2m_message_handling.h @@ -39,6 +39,8 @@ #define NUM_OUTPUT_BLOCK_CONTEXT CONFIG_LWM2M_NUM_OUTPUT_BLOCK_CONTEXT #endif +int coap_options_to_path(struct coap_option *opt, int options_count, + struct lwm2m_obj_path *path); /* LwM2M message functions */ struct lwm2m_message *lwm2m_get_message(struct lwm2m_ctx *client_ctx); struct lwm2m_message *find_msg(struct coap_pending *pending, struct coap_reply *reply); diff --git a/subsys/net/lib/lwm2m/lwm2m_obj_gateway.c b/subsys/net/lib/lwm2m/lwm2m_obj_gateway.c index 711fd5fe127..5bb12f80f47 100644 --- a/subsys/net/lib/lwm2m/lwm2m_obj_gateway.c +++ b/subsys/net/lib/lwm2m/lwm2m_obj_gateway.c @@ -59,6 +59,7 @@ static struct lwm2m_engine_obj_field fields[] = { static struct lwm2m_engine_obj_inst inst[MAX_INSTANCE_COUNT]; static struct lwm2m_engine_res res[MAX_INSTANCE_COUNT][GATEWAY_MAX_ID]; static struct lwm2m_engine_res_inst res_inst[MAX_INSTANCE_COUNT][RESOURCE_INSTANCE_COUNT]; +lwm2m_engine_gateway_msg_cb gateway_msg_cb[MAX_INSTANCE_COUNT]; static int prefix_validation_cb(uint16_t obj_inst_id, uint16_t res_id, uint16_t res_inst_id, uint8_t *data, uint16_t data_len, bool last_block, @@ -146,6 +147,57 @@ static struct lwm2m_engine_obj_inst *lwm2m_gw_create(uint16_t obj_inst_id) return &inst[index]; } +int lwm2m_gw_handle_req(struct lwm2m_message *msg) +{ + struct coap_option options[4]; + int ret; + + ret = coap_find_options(msg->in.in_cpkt, COAP_OPTION_URI_PATH, options, + ARRAY_SIZE(options)); + if (ret < 0) { + return ret; + } + + for (int index = 0; index < MAX_INSTANCE_COUNT; index++) { + /* Skip uninitialized objects */ + if (!inst[index].obj) { + continue; + } + + char *prefix = device_table[index].prefix; + size_t prefix_len = strlen(prefix); + + if (prefix_len != options[0].len) { + continue; + } + if (strncmp(options[0].value, prefix, prefix_len) != 0) { + continue; + } + + if (gateway_msg_cb[index] == NULL) { + return -ENOENT; + } + /* Delete prefix from path*/ + ret = coap_options_to_path(&options[1], ret - 1, &msg->path); + if (ret < 0) { + return ret; + } + return gateway_msg_cb[index](msg); + } + return -ENOENT; +} + +int lwm2m_register_gw_callback(uint16_t obj_inst_id, lwm2m_engine_gateway_msg_cb cb) +{ + for (int index = 0; index < MAX_INSTANCE_COUNT; index++) { + if (inst[index].obj_inst_id == obj_inst_id) { + gateway_msg_cb[index] = cb; + return 0; + } + } + return -ENOENT; +} + static int lwm2m_gw_init(void) { int ret = 0; diff --git a/subsys/net/lib/lwm2m/lwm2m_obj_gateway.h b/subsys/net/lib/lwm2m/lwm2m_obj_gateway.h index 597e3de19bc..0f7a82af249 100644 --- a/subsys/net/lib/lwm2m/lwm2m_obj_gateway.h +++ b/subsys/net/lib/lwm2m/lwm2m_obj_gateway.h @@ -9,6 +9,8 @@ #ifndef __LWM2M_OBJ_GATEWAY__ #define __LWM2M_OBJ_GATEWAY__ +#include + /* LwM2M Gateway resource IDs */ /* clang-format off */ #define LWM2M_GATEWAY_DEVICE_RID 0 @@ -17,4 +19,42 @@ #define LWM2M_GATEWAY_IOT_DEVICE_OBJECTS_RID 3 /* clang-format on */ +/** + * @brief A callback which handles the prefixed messages from the server. + * + * The callback gets triggered each time the prefix in front of a received lwm2m + * msg path matches the prefix set in the LWM2M_GATEWAY_PREFIX_RID buffer. + * + * It must handle the content of the coap message completely. + * In case of success the LwM2M engine will then send the formatted coap message, + * otherwise a coap response code is sent. + * + * Example of returning CoAP response: + * @code{.c} + * lwm2m_init_message(msg); + * // Write CoAP packet to msg->out.out_cpkt + * return 0; + * @endcode + * + * + * @return 0 if msg contains a valid CoAP response. + * @return negative error code otherwise. + */ +typedef int (*lwm2m_engine_gateway_msg_cb)(struct lwm2m_message *msg); +/** + * @brief Register a callback which handles the prefixed messages from the server. + * + * @return 0 on success + * @return -ENOENT if no object instance with obj_inst_id was found + */ +int lwm2m_register_gw_callback(uint16_t obj_inst_id, lwm2m_engine_gateway_msg_cb cb); +/** + * @brief Check if given message is handled by Gateway callback. + * + * @return 0 if msg was handled by Gateawy and contains a valid response. Negative error code + * otherwise. + * @return -ENOENT if this msg was not handled by Gateway object. + */ +int lwm2m_gw_handle_req(struct lwm2m_message *msg); + #endif /* __LWM2M_OBJ_GATEWAY__ */ From 10e66dc9fcf79534865ddc0253e3eb63e7d7fe9b Mon Sep 17 00:00:00 2001 From: Dawid Niedzwiecki Date: Mon, 8 Jan 2024 14:00:17 +0100 Subject: [PATCH 2040/3723] boards: google_dragonclaw: limit frequency of an unused clock I2S is unused on the dragonclow board. Increase the R division factor (used for I2S), to reduce the clock frequency, which saves some power. Signed-off-by: Dawid Niedzwiecki --- boards/arm/google_dragonclaw/google_dragonclaw.dts | 1 + 1 file changed, 1 insertion(+) diff --git a/boards/arm/google_dragonclaw/google_dragonclaw.dts b/boards/arm/google_dragonclaw/google_dragonclaw.dts index 2f17124747d..579adf4026f 100644 --- a/boards/arm/google_dragonclaw/google_dragonclaw.dts +++ b/boards/arm/google_dragonclaw/google_dragonclaw.dts @@ -37,6 +37,7 @@ mul-n = <192>; /* 16MHz * 192/8 = 384MHz VCO clock */ div-p = <4>; /* 96MHz PLL general clock output */ div-q = <8>; /* 48MHz PLL output for USB, SDIO, RNG */ + div-r = <7>; /* I2S - lowest possible frequency to save power */ clocks = <&clk_hsi>; status = "okay"; }; From c1a1e4524df56c440f3c686c27a82255e9c89150 Mon Sep 17 00:00:00 2001 From: Bartosz Bilas Date: Thu, 4 Jan 2024 19:55:03 +0100 Subject: [PATCH 2041/3723] drivers: regulator: max20335: add support for ship mode Allows the user to disable PMIC. Signed-off-by: Bartosz Bilas --- drivers/regulator/Kconfig.max20335 | 17 +++++++++-- drivers/regulator/regulator_max20335.c | 40 +++++++++++++++++++++++++- 2 files changed, 53 insertions(+), 4 deletions(-) diff --git a/drivers/regulator/Kconfig.max20335 b/drivers/regulator/Kconfig.max20335 index a9b739e1f2c..a92743afdb5 100644 --- a/drivers/regulator/Kconfig.max20335 +++ b/drivers/regulator/Kconfig.max20335 @@ -10,9 +10,20 @@ config REGULATOR_MAX20335 help Enable the Maxim MAX20335 PMIC regulator driver +if REGULATOR_MAX20335 + +config REGULATOR_MAXIM_MAX20335_COMMON_INIT_PRIORITY + int "MAX20335 regulator driver init priority (common part)" + default 86 + help + Init priority for the Maxim MAX20335 regulator driver + (common part). It must be greater than I2C and MFD init priority. + config REGULATOR_MAXIM_MAX20335_INIT_PRIORITY int "MAX20335 regulator driver init priority" - default 86 - depends on REGULATOR_MAX20335 + default 87 help - Init priority for the Maxim MAX20335 regulator driver. + Init priority for the Maxim MAX20335 regulator driver. It must be + greater than REGULATOR_MAXIM_MAX20335_COMMON_INIT_PRIORITY + +endif diff --git a/drivers/regulator/regulator_max20335.c b/drivers/regulator/regulator_max20335.c index b94c0e0bb98..328e5179156 100644 --- a/drivers/regulator/regulator_max20335.c +++ b/drivers/regulator/regulator_max20335.c @@ -16,6 +16,7 @@ #define MAX20335_BUCK2_CFG 0x0FU #define MAX20335_BUCK2_VSET 0x10U #define MAX20335_BUCK12_CSET 0x11U +#define MAX20335_PWR_CMD 0x1FU #define MAX20335_BUCK1_CSET_MASK 0xF0U #define MAX20335_BUCK2_CSET_MASK 0x0FU #define MAX20335_BUCK2_CSET_SHIFT 4 @@ -32,6 +33,8 @@ #define MAX20335_LDO_EN BIT(1) #define MAX20335_LDO_EN_MASK GENMASK(2, 1) +#define MAX20335_OFF_MODE 0xB2U + enum max20335_pmic_sources { MAX20335_PMIC_SOURCE_BUCK1, MAX20335_PMIC_SOURCE_BUCK2, @@ -49,6 +52,10 @@ struct regulator_max20335_desc { const struct linear_range *ua_range; }; +struct regulator_max20335_common_config { + struct i2c_dt_spec bus; +}; + struct regulator_max20335_config { struct regulator_common_config common; struct i2c_dt_spec bus; @@ -283,6 +290,13 @@ static int regulator_max20335_set_current_limit(const struct device *dev, return i2c_reg_write_byte_dt(&config->bus, MAX20335_BUCK12_CSET, val); } +static int regulator_max20335_power_off(const struct device *dev) +{ + const struct regulator_max20335_common_config *common_config = dev->config; + + return i2c_reg_write_byte_dt(&common_config->bus, MAX20335_PWR_CMD, MAX20335_OFF_MODE); +} + static int regulator_max20335_init(const struct device *dev) { const struct regulator_max20335_config *config = dev->config; @@ -296,6 +310,21 @@ static int regulator_max20335_init(const struct device *dev) return regulator_common_init(dev, false); } +static int regulator_max20335_common_init(const struct device *dev) +{ + const struct regulator_max20335_common_config *common_config = dev->config; + + if (!i2c_is_ready_dt(&common_config->bus)) { + return -ENODEV; + } + + return 0; +} + +static const struct regulator_parent_driver_api parent_api = { + .ship_mode = regulator_max20335_power_off, +}; + static const struct regulator_driver_api api = { .enable = regulator_max20335_enable, .disable = regulator_max20335_disable, @@ -332,10 +361,19 @@ static const struct regulator_driver_api api = { ()) #define REGULATOR_MAX20335_DEFINE_ALL(inst) \ + static const struct regulator_max20335_common_config common_config_##inst = { \ + .bus = I2C_DT_SPEC_GET(DT_INST_PARENT(inst)), \ + }; \ + \ + DEVICE_DT_INST_DEFINE(inst, regulator_max20335_common_init, \ + NULL, NULL, &common_config_##inst, POST_KERNEL, \ + CONFIG_REGULATOR_MAXIM_MAX20335_COMMON_INIT_PRIORITY, \ + &parent_api); \ + \ REGULATOR_MAX20335_DEFINE_COND(inst, buck1, MAX20335_PMIC_SOURCE_BUCK1) \ REGULATOR_MAX20335_DEFINE_COND(inst, buck2, MAX20335_PMIC_SOURCE_BUCK2) \ REGULATOR_MAX20335_DEFINE_COND(inst, ldo1, MAX20335_PMIC_SOURCE_LDO1) \ REGULATOR_MAX20335_DEFINE_COND(inst, ldo2, MAX20335_PMIC_SOURCE_LDO2) \ REGULATOR_MAX20335_DEFINE_COND(inst, ldo3, MAX20335_PMIC_SOURCE_LDO3) -DT_INST_FOREACH_STATUS_OKAY(REGULATOR_MAX20335_DEFINE_ALL); +DT_INST_FOREACH_STATUS_OKAY(REGULATOR_MAX20335_DEFINE_ALL) From 29a4e04143785d396c5c559075446408eabcd0dc Mon Sep 17 00:00:00 2001 From: Anas Nashif Date: Mon, 8 Jan 2024 11:37:47 -0500 Subject: [PATCH 2042/3723] ci: update elasticsearch index with merged PR data A simple workflow that runs when a PR is merged and updates the elasticsearch index with merged PR info. The dashboard for displaying the information can be found here: https://kibana.zephyrproject.io/ Signed-off-by: Anas Nashif --- .github/workflows/stats_merged_prs.yml | 24 ++++ scripts/ci/stats/merged_prs.py | 157 +++++++++++++++++++++++++ 2 files changed, 181 insertions(+) create mode 100644 .github/workflows/stats_merged_prs.yml create mode 100755 scripts/ci/stats/merged_prs.py diff --git a/.github/workflows/stats_merged_prs.yml b/.github/workflows/stats_merged_prs.yml new file mode 100644 index 00000000000..a3d5efc7fd0 --- /dev/null +++ b/.github/workflows/stats_merged_prs.yml @@ -0,0 +1,24 @@ +name: Merged PR stats + +on: + pull_request_target: + branches: + - main + - v*-branch + types: [closed] +jobs: + record_merged: + if: github.event.pull_request.merged == true && github.repository == 'zephyrproject-rtos/zephyr' + runs-on: ubuntu-22.04 + steps: + - name: checkout + uses: actions/checkout@v3 + - name: PR event + env: + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + ELASTICSEARCH_KEY: ${{ secrets.ELASTICSEARCH_KEY }} + ELASTICSEARCH_SERVER: "https://elasticsearch.zephyrproject.io:443" + PR_STAT_INDEX: "pr-test-7" + run: | + pip3 install pygithub elasticsearch + python3 ./scripts/ci/stats/merged_prs.py --pull-request ${{ github.event.pull_request.number }} --repo ${{ github.repository }} diff --git a/scripts/ci/stats/merged_prs.py b/scripts/ci/stats/merged_prs.py new file mode 100755 index 00000000000..7a9ffa41981 --- /dev/null +++ b/scripts/ci/stats/merged_prs.py @@ -0,0 +1,157 @@ +#!/usr/bin/env python3 +# Copyright (c) 2024 Intel Corp. +# SPDX-License-Identifier: Apache-2.0 + +# Script that operates on a merged PR and sends data to elasticsearch for +# further insepctions using the PR dashboard at +# https://kibana.zephyrproject.io/ + +import sys +import os +from github import Github +import argparse +from elasticsearch import Elasticsearch +from elasticsearch.helpers import bulk +from datetime import timedelta + + +date_format = '%Y-%m-%d %H:%M:%S' + +def parse_args() -> argparse.Namespace: + parser = argparse.ArgumentParser( + formatter_class=argparse.RawDescriptionHelpFormatter, allow_abbrev=False) + + parser.add_argument('--pull-request', required=True, help='pull request number', type=int) + parser.add_argument('--repo', required=True, help='github repo') + + return parser.parse_args() + +def gendata(data, index): + for t in data: + yield { + "_index": index, + "_source": t + } + +def main(): + args = parse_args() + token = os.environ.get('GITHUB_TOKEN') + if not token: + sys.exit('Github token not set in environment, please set the ' + 'GITHUB_TOKEN environment variable and retry.') + + gh = Github(token) + json_list = [] + gh_repo = gh.get_repo(args.repo) + + if args.pull_request: + pr = gh_repo.get_pull(args.pull_request) + + reviews = pr.get_reviews() + print(f'#{pr.number}: {pr.title} - {pr.comments} Comments, reviews: {reviews.totalCount}, {len(pr.assignees)} Assignees (Updated {pr.updated_at})') + assignee_reviews = 0 + reviewers = set() + prj = {} + for r in reviews: + if r.user and r.state == 'APPROVED': + reviewers.add(r.user.login) + if pr.assignees and r.user: + for assignee in pr.assignees: + if r.user.login == assignee.login: + assignee_reviews = assignee_reviews + 1 + # was reviewed at least by one assignee + prj['reviewed_by_assignee'] = "yes" + + # This is all data we get easily though the Github API and serves as the basis + # for displaying some trends and metrics. + # Data can be extended in the future if we find more information that + # is useful through the API + + prj['nr'] = pr.number + prj['url'] = pr.url + prj['title'] = pr.title + prj['comments'] = pr.comments + prj['reviews'] = reviews.totalCount + prj['assignees'] = len(pr.assignees) + prj['updated'] = pr.updated_at.strftime("%Y-%m-%d %H:%M:%S") + prj['created'] = pr.created_at.strftime("%Y-%m-%d %H:%M:%S") + prj['closed'] = pr.closed_at.strftime("%Y-%m-%d %H:%M:%S") + prj['merged_by'] = pr.merged_by.login + prj['submitted_by'] = pr.user.login + prj['changed_files'] = pr.changed_files + prj['additions'] = pr.additions + prj['deletions'] = pr.deletions + prj['commits'] = pr.commits + # The branch we are targeting. main vs release branches. + prj['base'] = pr.base.ref + + ll = [] + for l in pr.labels: + ll.append(l.name) + prj['labels'] = ll + + # take first assignee, otherwise we have no assignees and this rule is not applicable + if pr.assignee: + prj['assignee'] = pr.assignee.login + else: + prj['assignee'] = "none" + prj['reviewed_by_assignee'] = "na" + prj['review_rule'] = "na" + + # go through all assignees and check if anyone has approved and reset assignee to the one who approved + for assignee in pr.assignees: + if assignee.login in reviewers: + prj['assignee'] = assignee.login + elif assignee.login == pr.user.login: + prj['reviewed_by_assignee'] = "yes" + + + # list assignees for later checks + assignees = [a.login for a in pr.assignees] + + # Deal with exceptions when assignee approval is not needed. + if 'Trivial' in ll or 'Hotfix' in ll: + prj['review_rule'] = "yes" + elif pr.merged_by.login in assignees: + prj['review_rule'] = "yes" + else: + prj['review_rule'] = "no" + + prj['assignee_reviews'] = assignee_reviews + + delta = pr.closed_at - pr.created_at + deltah = delta.total_seconds() / 3600 + prj['hours_open'] = deltah + + dates = (pr.created_at + timedelta(idx + 1) for idx in range((pr.closed_at - pr.created_at).days)) + + # Get number of business days per the guidelines, we need at least 2. + res = sum(1 for day in dates if day.weekday() < 5) + + if res < 2 and not ('Trivial' in ll or 'Hotfix' in ll): + prj['time_rule'] = False + elif deltah < 4 and 'Trivial' in ll: + prj['time_rule'] = False + else: + prj['time_rule'] = True + prj['reviewers'] = list(reviewers) + + json_list.append(prj) + + + # Send data over to elasticsearch. + es = Elasticsearch( + [os.environ['ELASTICSEARCH_SERVER']], + api_key=os.environ['ELASTICSEARCH_KEY'], + verify_certs=False + ) + + try: + index = os.environ['PR_STAT_INDEX'] + bulk(es, gendata(json_list, index)) + except KeyError as e: + print(f"Error: {e} not set.") + print(json_list) + +if __name__ == "__main__": + main() From 97f8b8b6eec733a5d0f0cb144c78956ff7f3a988 Mon Sep 17 00:00:00 2001 From: Keith Packard Date: Mon, 27 Nov 2023 16:57:56 -0800 Subject: [PATCH 2043/3723] scripts/footprint: Avoid fpdiff failure when data changes lots Bounds check the array access in case the input data changes so that the number of entries in the 'children' array is not the same. The tool output with this change isn't terribly useful, but at least it doesn't crash. Signed-off-by: Keith Packard --- scripts/footprint/fpdiff.py | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/scripts/footprint/fpdiff.py b/scripts/footprint/fpdiff.py index fe9c40bc40d..c76bf4a5806 100755 --- a/scripts/footprint/fpdiff.py +++ b/scripts/footprint/fpdiff.py @@ -15,7 +15,7 @@ # ./scripts/footprint/fpdiff.py ram1.json ram2.json from anytree.importer import DictImporter -from anytree import PreOrderIter +from anytree import PreOrderIter, AnyNode from anytree.search import find import colorama @@ -46,7 +46,10 @@ def main(): for idx, ch in enumerate(data1['symbols']['children']): root1 = importer.import_(ch) - root2 = importer.import_(data2['symbols']['children'][idx]) + if idx >= len(data2['symbols']['children']): + root2 = AnyNode(identifier=None) + else: + root2 = importer.import_(data2['symbols']['children'][idx]) print(f"{root1.name}\n+++++++++++++++++++++") for node in PreOrderIter(root1): From cdc686eecc00d448d724f8e5e5853f88c8ac4e04 Mon Sep 17 00:00:00 2001 From: Keith Packard Date: Sun, 19 Nov 2023 00:33:23 -0800 Subject: [PATCH 2044/3723] compiler/gcc: _FORTIFY_SOURCE=1 doesn't mean compile-time only checks _FORTIFY_SOURCE=1 differs from _FORTIFY_SOURCE=2 only in the bounds checking mode that it uses. With _FORTIFY_SOURCE=1, bounds checks are 'loose', allowing access to the whole underlying object, not just the subset referenced in the expression (e.g, the bounds of a struct member is the whole struct, not just the member). With _FORTIFY_SOURCE=2, bounds checks are strict, meaning that the bounds of an expression are limited to the referenced value. Both of these perform their checks at runtime, calling _chk_fail if the bounds check fails. That's done in the __*_chk functions included in the C library. These are always called when _FORTIFY_SOURCE > 0, unless the compiler replaces the call with inline code. GCC already does all of the compile-time bounds checking for string and mem functions when not using -ffreestanding, so there's nothing we need to add for that to work. That means the security_fortify_compile_time property should be empty. Signed-off-by: Keith Packard --- cmake/compiler/gcc/compiler_flags.cmake | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/cmake/compiler/gcc/compiler_flags.cmake b/cmake/compiler/gcc/compiler_flags.cmake index 5b1dbde49c6..a118fbe570c 100644 --- a/cmake/compiler/gcc/compiler_flags.cmake +++ b/cmake/compiler/gcc/compiler_flags.cmake @@ -169,9 +169,11 @@ endif() if(NOT CONFIG_NO_OPTIMIZATIONS) # _FORTIFY_SOURCE: Detect common-case buffer overflows for certain functions - # _FORTIFY_SOURCE=1 : Compile-time checks (requires -O1 at least) - # _FORTIFY_SOURCE=2 : Additional lightweight run-time checks - set_compiler_property(PROPERTY security_fortify_compile_time _FORTIFY_SOURCE=1) + # _FORTIFY_SOURCE=1 : Loose checking (use wide bounds checks) + # _FORTIFY_SOURCE=2 : Tight checking (use narrow bounds checks) + # GCC always does compile-time bounds checking for string/mem functions, so + # there's no additional value to set here + set_compiler_property(PROPERTY security_fortify_compile_time) set_compiler_property(PROPERTY security_fortify_run_time _FORTIFY_SOURCE=2) endif() From 2a4794e98a713f68c27686965c51798140de4760 Mon Sep 17 00:00:00 2001 From: Jeeva Kandasamy Date: Thu, 21 Dec 2023 23:05:07 +0530 Subject: [PATCH 2045/3723] drivers: pwm: fix esp32-s3 ledc pwm low frequency ESP32 - S2,S3 and C3 variants have only 14 bits counter. where as the plain ESP32 variant has 20 bits counter. application failed to set low frequency(1Hz) in S2, S3 and C3 variants. to get very low frequencies on these variants, frequency needs to be tuned with 18 bits clock divider. so select the slow clock source (1MHz) with highest counter resolution. this can be handled on the func'pwm_led_esp32_timer_set' with 'prescaler'. Signed-off-by: Jeeva Kandasamy --- drivers/pwm/pwm_led_esp32.c | 20 +++++++++++++++++--- 1 file changed, 17 insertions(+), 3 deletions(-) diff --git a/drivers/pwm/pwm_led_esp32.c b/drivers/pwm/pwm_led_esp32.c index de89bf694a8..7e53877f69e 100644 --- a/drivers/pwm/pwm_led_esp32.c +++ b/drivers/pwm/pwm_led_esp32.c @@ -169,7 +169,17 @@ static int pwm_led_esp32_timer_config(struct pwm_ledc_esp32_channel_config *chan return 0; } - return -EINVAL; + /** + * ESP32 - S2,S3 and C3 variants have only 14 bits counter. + * where as the plain ESP32 variant has 20 bits counter. + * application failed to set low frequency(1Hz) in S2, S3 and C3 variants. + * to get very low frequencies on these variants, + * frequency needs to be tuned with 18 bits clock divider. + * so select the slow clock source (1MHz) with highest counter resolution. + * this can be handled on the func 'pwm_led_esp32_timer_set' with 'prescaler'. + */ + channel->resolution = SOC_LEDC_TIMER_BIT_WIDE_NUM; + return 0; } static int pwm_led_esp32_timer_set(const struct device *dev, @@ -193,11 +203,12 @@ static int pwm_led_esp32_timer_set(const struct device *dev, prescaler = ((uint64_t) REF_CLK_FREQ << 8) / channel->freq / precision; break; default: - LOG_ERR("Invalid clock source"); + LOG_ERR("Invalid clock source (%d)", channel->clock_src); return -EINVAL; } if (prescaler < 0x100 || prescaler > 0x3FFFF) { + LOG_ERR("Prescaler out of range: %#X", prescaler); return -EINVAL; } @@ -251,7 +262,10 @@ static int pwm_led_esp32_set_cycles(const struct device *dev, uint32_t channel_i } /* Update PWM frequency according to period_cycles */ - pwm_led_esp32_get_cycles_per_sec(dev, channel_idx, &clk_freq); + ret = pwm_led_esp32_get_cycles_per_sec(dev, channel_idx, &clk_freq); + if (ret < 0) { + return ret; + } channel->freq = (uint32_t) (clk_freq/period_cycles); if (!channel->freq) { From e8f223dbe83b85ad4606e13c9ca480d341e658c4 Mon Sep 17 00:00:00 2001 From: Bartosz Bilas Date: Tue, 9 Jan 2024 21:07:18 +0100 Subject: [PATCH 2046/3723] drivers: charger: bq24190: fix api and init functions references There is no need to use & as a function reference, so remove it. Signed-off-by: Bartosz Bilas --- drivers/charger/charger_bq24190.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/drivers/charger/charger_bq24190.c b/drivers/charger/charger_bq24190.c index 0661bd92796..9b313136fef 100644 --- a/drivers/charger/charger_bq24190.c +++ b/drivers/charger/charger_bq24190.c @@ -471,8 +471,8 @@ static int bq24190_init(const struct device *dev) } static const struct charger_driver_api bq24190_driver_api = { - .get_property = &bq24190_get_prop, - .set_property = &bq24190_set_prop, + .get_property = bq24190_get_prop, + .set_property = bq24190_set_prop, }; #define BQ24190_INIT(inst) \ @@ -486,7 +486,7 @@ static const struct charger_driver_api bq24190_driver_api = { .vreg_uv = DT_INST_PROP(inst, constant_charge_voltage_max_microvolt), \ }; \ \ - DEVICE_DT_INST_DEFINE(inst, &bq24190_init, NULL, &bq24190_data_##inst, \ + DEVICE_DT_INST_DEFINE(inst, bq24190_init, NULL, &bq24190_data_##inst, \ &bq24190_config_##inst, POST_KERNEL, CONFIG_CHARGER_INIT_PRIORITY, \ &bq24190_driver_api); From a15c24ad7586bb6fc2d70b0019093e0dea31c2ac Mon Sep 17 00:00:00 2001 From: Andrzej Kuros Date: Tue, 9 Jan 2024 09:25:03 +0100 Subject: [PATCH 2047/3723] manifest: update hal_nordic revision MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This commit updates revision of hal_nordic to bring the latest changes in the nRF IEEE 802.15.4 driver. Signed-off-by: Andrzej Kuroś --- west.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/west.yml b/west.yml index 83b7e41b090..21fbd973bb1 100644 --- a/west.yml +++ b/west.yml @@ -183,7 +183,7 @@ manifest: groups: - hal - name: hal_nordic - revision: b55cfbbf0221d709560c2e438beef66842ada272 + revision: 64bd075a06f6a16d6ea9101cda82b41465a35211 path: modules/hal/nordic groups: - hal From c4ce2359736a930f881ea448237557c8ed1e68ed Mon Sep 17 00:00:00 2001 From: Andrzej Kuros Date: Tue, 9 Jan 2024 09:30:55 +0100 Subject: [PATCH 2048/3723] modules: hal_nordic: remove NRF_802154_ENERGY_DETECTED_VERSION MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The macro `NRF_802154_ENERGY_DETECTED_VERSION` is no longer required because transition of nrf 802154 API is done. Signed-off-by: Andrzej Kuroś --- modules/hal_nordic/nrf_802154/CMakeLists.txt | 2 -- 1 file changed, 2 deletions(-) diff --git a/modules/hal_nordic/nrf_802154/CMakeLists.txt b/modules/hal_nordic/nrf_802154/CMakeLists.txt index 763f9625be8..30c4c237a04 100644 --- a/modules/hal_nordic/nrf_802154/CMakeLists.txt +++ b/modules/hal_nordic/nrf_802154/CMakeLists.txt @@ -93,8 +93,6 @@ else() target_compile_definitions(zephyr-802154-interface INTERFACE NRF_802154_CARRIER_FUNCTIONS_ENABLED=0) endif() -target_compile_definitions(zephyr-802154-interface INTERFACE NRF_802154_ENERGY_DETECTED_VERSION=1) - if (CONFIG_NRF_802154_ASSERT_ZEPHYR OR CONFIG_NRF_802154_ASSERT_ZEPHYR_MINIMAL) target_include_directories(zephyr-802154-interface INTERFACE include) target_compile_definitions(zephyr-802154-interface INTERFACE NRF_802154_PLATFORM_ASSERT_INCLUDE=\"nrf_802154_assert_zephyr.h\") From 3e8dbaf75fd0c239e00e33eb5970843341dad0f0 Mon Sep 17 00:00:00 2001 From: Kapil Bhatt Date: Tue, 9 Jan 2024 12:13:38 +0530 Subject: [PATCH 2049/3723] net: wifi_utils: Fix max channels allow for scan Fix the maximum channels allow for scan command input. Signed-off-by: Kapil Bhatt --- subsys/net/l2/wifi/wifi_utils.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/subsys/net/l2/wifi/wifi_utils.c b/subsys/net/l2/wifi/wifi_utils.c index 52d25d90566..79c858c5dd7 100644 --- a/subsys/net/l2/wifi/wifi_utils.c +++ b/subsys/net/l2/wifi/wifi_utils.c @@ -368,7 +368,7 @@ int wifi_utils_parse_scan_chan(char *scan_chan_str, memset(chan_str, 0, sizeof(chan_str)); if (chan_start) { - if ((chan_idx + (chan_val - chan_start)) >= max_channels) { + if ((chan_idx + (chan_val - chan_start)) > max_channels) { NET_ERR("Too many channels specified (%d)", max_channels); return -EINVAL; } From 773ebe9c41903ce458eb2609c3c5668ef3976466 Mon Sep 17 00:00:00 2001 From: Kapil Bhatt Date: Tue, 9 Jan 2024 12:34:26 +0530 Subject: [PATCH 2050/3723] net: wifi_shell: Update scan argument shell Update the example of scan -c argument. Default value for max channels is set to 3, So, update the example according to that. Add closing bracket in -s. Signed-off-by: Kapil Bhatt --- subsys/net/l2/wifi/wifi_shell.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/subsys/net/l2/wifi/wifi_shell.c b/subsys/net/l2/wifi/wifi_shell.c index c7899635105..74a88103f48 100644 --- a/subsys/net/l2/wifi/wifi_shell.c +++ b/subsys/net/l2/wifi/wifi_shell.c @@ -1674,9 +1674,9 @@ SHELL_STATIC_SUBCMD_SET_CREATE(wifi_commands, "[-b, --bands ] : Bands to be scanned where 2: 2.4 GHz, 5: 5 GHz, 6: 6 GHz\n" "[-a, --dwell_time_active ] : Active scan dwell time (in ms) on a channel. Range 5 ms to 1000 ms\n" "[-p, --dwell_time_passive ] : Passive scan dwell time (in ms) on a channel. Range 10 ms to 1000 ms\n" - "[-s, --ssid : SSID to scan for. Can be provided multiple times\n" + "[-s, --ssid] : SSID to scan for. Can be provided multiple times\n" "[-m, --max_bss ] : Maximum BSSes to scan for. Range 1 - 65535\n" - "[-c, --chans ] : Channels to be scanned. The channels must be specified in the form band1:chan1,chan2_band2:chan3,..etc. band1, band2 must be valid band values and chan1, chan2, chan3 must be specified as a list of comma separated values where each value is either a single channel or a channel range specified as chan_start-chan_end. Each band channel set has to be separated by a _. For example, a valid channel specification can be 2:1,6-11,14_5:36,149-165,44\n" + "[-c, --chans ] : Channels to be scanned. The channels must be specified in the form band1:chan1,chan2_band2:chan3,..etc. band1, band2 must be valid band values and chan1, chan2, chan3 must be specified as a list of comma separated values where each value is either a single channel or a channel range specified as chan_start-chan_end. Each band channel set has to be separated by a _. For example, a valid channel specification can be 2:1,6_5:36\n" "[-h, --help] : Print out the help for the scan command.\n", cmd_wifi_scan, 1, 8), From e3deb44bc432b08e9d3da95e9accac077a37c4eb Mon Sep 17 00:00:00 2001 From: Mateusz Holenko Date: Fri, 22 Dec 2023 16:02:06 +0100 Subject: [PATCH 2051/3723] boards: arduino_portenta_h7: enable mailbox MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The mailbox peripheral is actively accesses by stm32_hsem functions, so it should be marked as enabled in DTS. Signed-off-by: Mateusz Hołenko --- .../arm/arduino_portenta_h7/arduino_portenta_h7-common.dtsi | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/boards/arm/arduino_portenta_h7/arduino_portenta_h7-common.dtsi b/boards/arm/arduino_portenta_h7/arduino_portenta_h7-common.dtsi index 653812e3e6a..87a22fac74e 100644 --- a/boards/arm/arduino_portenta_h7/arduino_portenta_h7-common.dtsi +++ b/boards/arm/arduino_portenta_h7/arduino_portenta_h7-common.dtsi @@ -116,3 +116,7 @@ zephyr_udc0: &usbotg_fs { pinctrl-names = "default"; status = "disabled"; }; + +&mailbox { + status = "okay"; +}; From b3d8fc5e824f568a4ce570957efafb02d5e1f8cc Mon Sep 17 00:00:00 2001 From: Gerard Marull-Paretas Date: Tue, 9 Jan 2024 09:45:11 +0100 Subject: [PATCH 2052/3723] soc: arm: gigadevice: s/gigadevice/gd_gd32 Gigadevice was inconsistent with the convention established by other SoC families, that is, use _. For example, ST STM32 uses st_stm32. Note that GD32VF103, under soc/riscv, has already been adjusted. Signed-off-by: Gerard Marull-Paretas --- MAINTAINERS.yml | 3 +-- soc/arm/{gigadevice => gd_gd32}/CMakeLists.txt | 0 soc/arm/{gigadevice => gd_gd32}/Kconfig | 4 ++-- soc/arm/{gigadevice => gd_gd32}/Kconfig.defconfig | 2 +- soc/arm/{gigadevice => gd_gd32}/Kconfig.soc | 2 +- soc/arm/{gigadevice => gd_gd32}/common/CMakeLists.txt | 0 soc/arm/{gigadevice => gd_gd32}/common/pinctrl_soc.h | 0 soc/arm/{gigadevice => gd_gd32}/gd32a50x/CMakeLists.txt | 0 .../gd32a50x/Kconfig.defconfig.gd32a503 | 0 .../{gigadevice => gd_gd32}/gd32a50x/Kconfig.defconfig.series | 2 +- soc/arm/{gigadevice => gd_gd32}/gd32a50x/Kconfig.series | 0 soc/arm/{gigadevice => gd_gd32}/gd32a50x/Kconfig.soc | 0 soc/arm/{gigadevice => gd_gd32}/gd32a50x/gd32_regs.h | 0 soc/arm/{gigadevice => gd_gd32}/gd32a50x/soc.c | 0 soc/arm/{gigadevice => gd_gd32}/gd32a50x/soc.h | 0 soc/arm/{gigadevice => gd_gd32}/gd32e10x/CMakeLists.txt | 0 .../gd32e10x/Kconfig.defconfig.gd32e103 | 0 .../{gigadevice => gd_gd32}/gd32e10x/Kconfig.defconfig.series | 2 +- soc/arm/{gigadevice => gd_gd32}/gd32e10x/Kconfig.series | 0 soc/arm/{gigadevice => gd_gd32}/gd32e10x/Kconfig.soc | 0 soc/arm/{gigadevice => gd_gd32}/gd32e10x/gd32_regs.h | 0 soc/arm/{gigadevice => gd_gd32}/gd32e10x/soc.c | 0 soc/arm/{gigadevice => gd_gd32}/gd32e10x/soc.h | 0 soc/arm/{gigadevice => gd_gd32}/gd32e50x/CMakeLists.txt | 0 .../gd32e50x/Kconfig.defconfig.gd32e507 | 0 .../{gigadevice => gd_gd32}/gd32e50x/Kconfig.defconfig.series | 2 +- soc/arm/{gigadevice => gd_gd32}/gd32e50x/Kconfig.series | 0 soc/arm/{gigadevice => gd_gd32}/gd32e50x/Kconfig.soc | 0 soc/arm/{gigadevice => gd_gd32}/gd32e50x/gd32_regs.h | 0 soc/arm/{gigadevice => gd_gd32}/gd32e50x/soc.c | 0 soc/arm/{gigadevice => gd_gd32}/gd32e50x/soc.h | 0 soc/arm/{gigadevice => gd_gd32}/gd32f3x0/CMakeLists.txt | 0 .../gd32f3x0/Kconfig.defconfig.gd32f350 | 0 .../{gigadevice => gd_gd32}/gd32f3x0/Kconfig.defconfig.series | 2 +- soc/arm/{gigadevice => gd_gd32}/gd32f3x0/Kconfig.series | 0 soc/arm/{gigadevice => gd_gd32}/gd32f3x0/Kconfig.soc | 0 soc/arm/{gigadevice => gd_gd32}/gd32f3x0/gd32_regs.h | 0 soc/arm/{gigadevice => gd_gd32}/gd32f3x0/soc.c | 0 soc/arm/{gigadevice => gd_gd32}/gd32f3x0/soc.h | 0 soc/arm/{gigadevice => gd_gd32}/gd32f403/CMakeLists.txt | 0 .../gd32f403/Kconfig.defconfig.gd32f403 | 0 .../{gigadevice => gd_gd32}/gd32f403/Kconfig.defconfig.series | 2 +- soc/arm/{gigadevice => gd_gd32}/gd32f403/Kconfig.series | 0 soc/arm/{gigadevice => gd_gd32}/gd32f403/Kconfig.soc | 0 soc/arm/{gigadevice => gd_gd32}/gd32f403/gd32_regs.h | 0 soc/arm/{gigadevice => gd_gd32}/gd32f403/soc.c | 0 soc/arm/{gigadevice => gd_gd32}/gd32f403/soc.h | 0 soc/arm/{gigadevice => gd_gd32}/gd32f4xx/CMakeLists.txt | 0 .../gd32f4xx/Kconfig.defconfig.gd32f405 | 0 .../gd32f4xx/Kconfig.defconfig.gd32f407 | 0 .../gd32f4xx/Kconfig.defconfig.gd32f450 | 0 .../gd32f4xx/Kconfig.defconfig.gd32f470 | 0 .../{gigadevice => gd_gd32}/gd32f4xx/Kconfig.defconfig.series | 2 +- soc/arm/{gigadevice => gd_gd32}/gd32f4xx/Kconfig.series | 0 soc/arm/{gigadevice => gd_gd32}/gd32f4xx/Kconfig.soc | 0 soc/arm/{gigadevice => gd_gd32}/gd32f4xx/gd32_regs.h | 0 soc/arm/{gigadevice => gd_gd32}/gd32f4xx/soc.c | 0 soc/arm/{gigadevice => gd_gd32}/gd32f4xx/soc.h | 0 soc/arm/{gigadevice => gd_gd32}/gd32l23x/CMakeLists.txt | 0 .../gd32l23x/Kconfig.defconfig.gd32l233 | 0 .../{gigadevice => gd_gd32}/gd32l23x/Kconfig.defconfig.series | 2 +- soc/arm/{gigadevice => gd_gd32}/gd32l23x/Kconfig.series | 0 soc/arm/{gigadevice => gd_gd32}/gd32l23x/Kconfig.soc | 0 soc/arm/{gigadevice => gd_gd32}/gd32l23x/gd32_regs.h | 0 soc/arm/{gigadevice => gd_gd32}/gd32l23x/soc.c | 0 soc/arm/{gigadevice => gd_gd32}/gd32l23x/soc.h | 0 66 files changed, 12 insertions(+), 13 deletions(-) rename soc/arm/{gigadevice => gd_gd32}/CMakeLists.txt (100%) rename soc/arm/{gigadevice => gd_gd32}/Kconfig (85%) rename soc/arm/{gigadevice => gd_gd32}/Kconfig.defconfig (79%) rename soc/arm/{gigadevice => gd_gd32}/Kconfig.soc (63%) rename soc/arm/{gigadevice => gd_gd32}/common/CMakeLists.txt (100%) rename soc/arm/{gigadevice => gd_gd32}/common/pinctrl_soc.h (100%) rename soc/arm/{gigadevice => gd_gd32}/gd32a50x/CMakeLists.txt (100%) rename soc/arm/{gigadevice => gd_gd32}/gd32a50x/Kconfig.defconfig.gd32a503 (100%) rename soc/arm/{gigadevice => gd_gd32}/gd32a50x/Kconfig.defconfig.series (75%) rename soc/arm/{gigadevice => gd_gd32}/gd32a50x/Kconfig.series (100%) rename soc/arm/{gigadevice => gd_gd32}/gd32a50x/Kconfig.soc (100%) rename soc/arm/{gigadevice => gd_gd32}/gd32a50x/gd32_regs.h (100%) rename soc/arm/{gigadevice => gd_gd32}/gd32a50x/soc.c (100%) rename soc/arm/{gigadevice => gd_gd32}/gd32a50x/soc.h (100%) rename soc/arm/{gigadevice => gd_gd32}/gd32e10x/CMakeLists.txt (100%) rename soc/arm/{gigadevice => gd_gd32}/gd32e10x/Kconfig.defconfig.gd32e103 (100%) rename soc/arm/{gigadevice => gd_gd32}/gd32e10x/Kconfig.defconfig.series (75%) rename soc/arm/{gigadevice => gd_gd32}/gd32e10x/Kconfig.series (100%) rename soc/arm/{gigadevice => gd_gd32}/gd32e10x/Kconfig.soc (100%) rename soc/arm/{gigadevice => gd_gd32}/gd32e10x/gd32_regs.h (100%) rename soc/arm/{gigadevice => gd_gd32}/gd32e10x/soc.c (100%) rename soc/arm/{gigadevice => gd_gd32}/gd32e10x/soc.h (100%) rename soc/arm/{gigadevice => gd_gd32}/gd32e50x/CMakeLists.txt (100%) rename soc/arm/{gigadevice => gd_gd32}/gd32e50x/Kconfig.defconfig.gd32e507 (100%) rename soc/arm/{gigadevice => gd_gd32}/gd32e50x/Kconfig.defconfig.series (74%) rename soc/arm/{gigadevice => gd_gd32}/gd32e50x/Kconfig.series (100%) rename soc/arm/{gigadevice => gd_gd32}/gd32e50x/Kconfig.soc (100%) rename soc/arm/{gigadevice => gd_gd32}/gd32e50x/gd32_regs.h (100%) rename soc/arm/{gigadevice => gd_gd32}/gd32e50x/soc.c (100%) rename soc/arm/{gigadevice => gd_gd32}/gd32e50x/soc.h (100%) rename soc/arm/{gigadevice => gd_gd32}/gd32f3x0/CMakeLists.txt (100%) rename soc/arm/{gigadevice => gd_gd32}/gd32f3x0/Kconfig.defconfig.gd32f350 (100%) rename soc/arm/{gigadevice => gd_gd32}/gd32f3x0/Kconfig.defconfig.series (73%) rename soc/arm/{gigadevice => gd_gd32}/gd32f3x0/Kconfig.series (100%) rename soc/arm/{gigadevice => gd_gd32}/gd32f3x0/Kconfig.soc (100%) rename soc/arm/{gigadevice => gd_gd32}/gd32f3x0/gd32_regs.h (100%) rename soc/arm/{gigadevice => gd_gd32}/gd32f3x0/soc.c (100%) rename soc/arm/{gigadevice => gd_gd32}/gd32f3x0/soc.h (100%) rename soc/arm/{gigadevice => gd_gd32}/gd32f403/CMakeLists.txt (100%) rename soc/arm/{gigadevice => gd_gd32}/gd32f403/Kconfig.defconfig.gd32f403 (100%) rename soc/arm/{gigadevice => gd_gd32}/gd32f403/Kconfig.defconfig.series (72%) rename soc/arm/{gigadevice => gd_gd32}/gd32f403/Kconfig.series (100%) rename soc/arm/{gigadevice => gd_gd32}/gd32f403/Kconfig.soc (100%) rename soc/arm/{gigadevice => gd_gd32}/gd32f403/gd32_regs.h (100%) rename soc/arm/{gigadevice => gd_gd32}/gd32f403/soc.c (100%) rename soc/arm/{gigadevice => gd_gd32}/gd32f403/soc.h (100%) rename soc/arm/{gigadevice => gd_gd32}/gd32f4xx/CMakeLists.txt (100%) rename soc/arm/{gigadevice => gd_gd32}/gd32f4xx/Kconfig.defconfig.gd32f405 (100%) rename soc/arm/{gigadevice => gd_gd32}/gd32f4xx/Kconfig.defconfig.gd32f407 (100%) rename soc/arm/{gigadevice => gd_gd32}/gd32f4xx/Kconfig.defconfig.gd32f450 (100%) rename soc/arm/{gigadevice => gd_gd32}/gd32f4xx/Kconfig.defconfig.gd32f470 (100%) rename soc/arm/{gigadevice => gd_gd32}/gd32f4xx/Kconfig.defconfig.series (74%) rename soc/arm/{gigadevice => gd_gd32}/gd32f4xx/Kconfig.series (100%) rename soc/arm/{gigadevice => gd_gd32}/gd32f4xx/Kconfig.soc (100%) rename soc/arm/{gigadevice => gd_gd32}/gd32f4xx/gd32_regs.h (100%) rename soc/arm/{gigadevice => gd_gd32}/gd32f4xx/soc.c (100%) rename soc/arm/{gigadevice => gd_gd32}/gd32f4xx/soc.h (100%) rename soc/arm/{gigadevice => gd_gd32}/gd32l23x/CMakeLists.txt (100%) rename soc/arm/{gigadevice => gd_gd32}/gd32l23x/Kconfig.defconfig.gd32l233 (100%) rename soc/arm/{gigadevice => gd_gd32}/gd32l23x/Kconfig.defconfig.series (73%) rename soc/arm/{gigadevice => gd_gd32}/gd32l23x/Kconfig.series (100%) rename soc/arm/{gigadevice => gd_gd32}/gd32l23x/Kconfig.soc (100%) rename soc/arm/{gigadevice => gd_gd32}/gd32l23x/gd32_regs.h (100%) rename soc/arm/{gigadevice => gd_gd32}/gd32l23x/soc.c (100%) rename soc/arm/{gigadevice => gd_gd32}/gd32l23x/soc.h (100%) diff --git a/MAINTAINERS.yml b/MAINTAINERS.yml index 9cee672506f..cab33e30ca8 100644 --- a/MAINTAINERS.yml +++ b/MAINTAINERS.yml @@ -2996,8 +2996,7 @@ GD32 Platforms: - drivers/*/*gd32* - dts/*/gigadevice/ - dts/bindings/*/*gd32* - - soc/arm/gigadevice/ - - soc/riscv/gd_gd32/ + - soc/*/gd_gd32/ - scripts/west_commands/*/*gd32* labels: - "platform: GD32" diff --git a/soc/arm/gigadevice/CMakeLists.txt b/soc/arm/gd_gd32/CMakeLists.txt similarity index 100% rename from soc/arm/gigadevice/CMakeLists.txt rename to soc/arm/gd_gd32/CMakeLists.txt diff --git a/soc/arm/gigadevice/Kconfig b/soc/arm/gd_gd32/Kconfig similarity index 85% rename from soc/arm/gigadevice/Kconfig rename to soc/arm/gd_gd32/Kconfig index 1facd4ceeda..69f21b210d0 100644 --- a/soc/arm/gigadevice/Kconfig +++ b/soc/arm/gd_gd32/Kconfig @@ -9,7 +9,7 @@ config SOC_FAMILY_GD32 config SOC_FAMILY string - default "gigadevice" + default "gd_gd32" depends on SOC_FAMILY_GD32 config SOC_FAMILY_GD32_ARM @@ -18,6 +18,6 @@ config SOC_FAMILY_GD32_ARM if SOC_FAMILY_GD32_ARM -source "soc/arm/gigadevice/*/Kconfig.soc" +source "soc/arm/gd_gd32/*/Kconfig.soc" endif # SOC_FAMILY_GD32_ARM diff --git a/soc/arm/gigadevice/Kconfig.defconfig b/soc/arm/gd_gd32/Kconfig.defconfig similarity index 79% rename from soc/arm/gigadevice/Kconfig.defconfig rename to soc/arm/gd_gd32/Kconfig.defconfig index 1aa25966163..b6fae5d43ec 100644 --- a/soc/arm/gigadevice/Kconfig.defconfig +++ b/soc/arm/gd_gd32/Kconfig.defconfig @@ -3,7 +3,7 @@ if SOC_FAMILY_GD32 -source "soc/arm/gigadevice/*/Kconfig.defconfig.series" +source "soc/arm/gd_gd32/*/Kconfig.defconfig.series" config PINCTRL default y diff --git a/soc/arm/gigadevice/Kconfig.soc b/soc/arm/gd_gd32/Kconfig.soc similarity index 63% rename from soc/arm/gigadevice/Kconfig.soc rename to soc/arm/gd_gd32/Kconfig.soc index 897238ff3fb..20a2f4c8cb4 100644 --- a/soc/arm/gigadevice/Kconfig.soc +++ b/soc/arm/gd_gd32/Kconfig.soc @@ -1,4 +1,4 @@ # Copyright (c) 2021, ATL Electronics # SPDX-License-Identifier: Apache-2.0 -source "soc/arm/gigadevice/*/Kconfig.series" +source "soc/arm/gd_gd32/*/Kconfig.series" diff --git a/soc/arm/gigadevice/common/CMakeLists.txt b/soc/arm/gd_gd32/common/CMakeLists.txt similarity index 100% rename from soc/arm/gigadevice/common/CMakeLists.txt rename to soc/arm/gd_gd32/common/CMakeLists.txt diff --git a/soc/arm/gigadevice/common/pinctrl_soc.h b/soc/arm/gd_gd32/common/pinctrl_soc.h similarity index 100% rename from soc/arm/gigadevice/common/pinctrl_soc.h rename to soc/arm/gd_gd32/common/pinctrl_soc.h diff --git a/soc/arm/gigadevice/gd32a50x/CMakeLists.txt b/soc/arm/gd_gd32/gd32a50x/CMakeLists.txt similarity index 100% rename from soc/arm/gigadevice/gd32a50x/CMakeLists.txt rename to soc/arm/gd_gd32/gd32a50x/CMakeLists.txt diff --git a/soc/arm/gigadevice/gd32a50x/Kconfig.defconfig.gd32a503 b/soc/arm/gd_gd32/gd32a50x/Kconfig.defconfig.gd32a503 similarity index 100% rename from soc/arm/gigadevice/gd32a50x/Kconfig.defconfig.gd32a503 rename to soc/arm/gd_gd32/gd32a50x/Kconfig.defconfig.gd32a503 diff --git a/soc/arm/gigadevice/gd32a50x/Kconfig.defconfig.series b/soc/arm/gd_gd32/gd32a50x/Kconfig.defconfig.series similarity index 75% rename from soc/arm/gigadevice/gd32a50x/Kconfig.defconfig.series rename to soc/arm/gd_gd32/gd32a50x/Kconfig.defconfig.series index d9e48ae18c2..0b250325c45 100644 --- a/soc/arm/gigadevice/gd32a50x/Kconfig.defconfig.series +++ b/soc/arm/gd_gd32/gd32a50x/Kconfig.defconfig.series @@ -3,7 +3,7 @@ if SOC_SERIES_GD32A50X -source "soc/arm/gigadevice/gd32a50x/Kconfig.defconfig.gd32*" +source "soc/arm/gd_gd32/gd32a50x/Kconfig.defconfig.gd32*" config SOC_SERIES default "gd32a50x" diff --git a/soc/arm/gigadevice/gd32a50x/Kconfig.series b/soc/arm/gd_gd32/gd32a50x/Kconfig.series similarity index 100% rename from soc/arm/gigadevice/gd32a50x/Kconfig.series rename to soc/arm/gd_gd32/gd32a50x/Kconfig.series diff --git a/soc/arm/gigadevice/gd32a50x/Kconfig.soc b/soc/arm/gd_gd32/gd32a50x/Kconfig.soc similarity index 100% rename from soc/arm/gigadevice/gd32a50x/Kconfig.soc rename to soc/arm/gd_gd32/gd32a50x/Kconfig.soc diff --git a/soc/arm/gigadevice/gd32a50x/gd32_regs.h b/soc/arm/gd_gd32/gd32a50x/gd32_regs.h similarity index 100% rename from soc/arm/gigadevice/gd32a50x/gd32_regs.h rename to soc/arm/gd_gd32/gd32a50x/gd32_regs.h diff --git a/soc/arm/gigadevice/gd32a50x/soc.c b/soc/arm/gd_gd32/gd32a50x/soc.c similarity index 100% rename from soc/arm/gigadevice/gd32a50x/soc.c rename to soc/arm/gd_gd32/gd32a50x/soc.c diff --git a/soc/arm/gigadevice/gd32a50x/soc.h b/soc/arm/gd_gd32/gd32a50x/soc.h similarity index 100% rename from soc/arm/gigadevice/gd32a50x/soc.h rename to soc/arm/gd_gd32/gd32a50x/soc.h diff --git a/soc/arm/gigadevice/gd32e10x/CMakeLists.txt b/soc/arm/gd_gd32/gd32e10x/CMakeLists.txt similarity index 100% rename from soc/arm/gigadevice/gd32e10x/CMakeLists.txt rename to soc/arm/gd_gd32/gd32e10x/CMakeLists.txt diff --git a/soc/arm/gigadevice/gd32e10x/Kconfig.defconfig.gd32e103 b/soc/arm/gd_gd32/gd32e10x/Kconfig.defconfig.gd32e103 similarity index 100% rename from soc/arm/gigadevice/gd32e10x/Kconfig.defconfig.gd32e103 rename to soc/arm/gd_gd32/gd32e10x/Kconfig.defconfig.gd32e103 diff --git a/soc/arm/gigadevice/gd32e10x/Kconfig.defconfig.series b/soc/arm/gd_gd32/gd32e10x/Kconfig.defconfig.series similarity index 75% rename from soc/arm/gigadevice/gd32e10x/Kconfig.defconfig.series rename to soc/arm/gd_gd32/gd32e10x/Kconfig.defconfig.series index 5a17c08d864..f16328e1e70 100644 --- a/soc/arm/gigadevice/gd32e10x/Kconfig.defconfig.series +++ b/soc/arm/gd_gd32/gd32e10x/Kconfig.defconfig.series @@ -3,7 +3,7 @@ if SOC_SERIES_GD32E10X -source "soc/arm/gigadevice/gd32e10x/Kconfig.defconfig.gd32*" +source "soc/arm/gd_gd32/gd32e10x/Kconfig.defconfig.gd32*" config SOC_SERIES default "gd32e10x" diff --git a/soc/arm/gigadevice/gd32e10x/Kconfig.series b/soc/arm/gd_gd32/gd32e10x/Kconfig.series similarity index 100% rename from soc/arm/gigadevice/gd32e10x/Kconfig.series rename to soc/arm/gd_gd32/gd32e10x/Kconfig.series diff --git a/soc/arm/gigadevice/gd32e10x/Kconfig.soc b/soc/arm/gd_gd32/gd32e10x/Kconfig.soc similarity index 100% rename from soc/arm/gigadevice/gd32e10x/Kconfig.soc rename to soc/arm/gd_gd32/gd32e10x/Kconfig.soc diff --git a/soc/arm/gigadevice/gd32e10x/gd32_regs.h b/soc/arm/gd_gd32/gd32e10x/gd32_regs.h similarity index 100% rename from soc/arm/gigadevice/gd32e10x/gd32_regs.h rename to soc/arm/gd_gd32/gd32e10x/gd32_regs.h diff --git a/soc/arm/gigadevice/gd32e10x/soc.c b/soc/arm/gd_gd32/gd32e10x/soc.c similarity index 100% rename from soc/arm/gigadevice/gd32e10x/soc.c rename to soc/arm/gd_gd32/gd32e10x/soc.c diff --git a/soc/arm/gigadevice/gd32e10x/soc.h b/soc/arm/gd_gd32/gd32e10x/soc.h similarity index 100% rename from soc/arm/gigadevice/gd32e10x/soc.h rename to soc/arm/gd_gd32/gd32e10x/soc.h diff --git a/soc/arm/gigadevice/gd32e50x/CMakeLists.txt b/soc/arm/gd_gd32/gd32e50x/CMakeLists.txt similarity index 100% rename from soc/arm/gigadevice/gd32e50x/CMakeLists.txt rename to soc/arm/gd_gd32/gd32e50x/CMakeLists.txt diff --git a/soc/arm/gigadevice/gd32e50x/Kconfig.defconfig.gd32e507 b/soc/arm/gd_gd32/gd32e50x/Kconfig.defconfig.gd32e507 similarity index 100% rename from soc/arm/gigadevice/gd32e50x/Kconfig.defconfig.gd32e507 rename to soc/arm/gd_gd32/gd32e50x/Kconfig.defconfig.gd32e507 diff --git a/soc/arm/gigadevice/gd32e50x/Kconfig.defconfig.series b/soc/arm/gd_gd32/gd32e50x/Kconfig.defconfig.series similarity index 74% rename from soc/arm/gigadevice/gd32e50x/Kconfig.defconfig.series rename to soc/arm/gd_gd32/gd32e50x/Kconfig.defconfig.series index 3a05359fd4a..f771aea44d9 100644 --- a/soc/arm/gigadevice/gd32e50x/Kconfig.defconfig.series +++ b/soc/arm/gd_gd32/gd32e50x/Kconfig.defconfig.series @@ -3,7 +3,7 @@ if SOC_SERIES_GD32E50X -source "soc/arm/gigadevice/gd32e50x/Kconfig.defconfig.gd32*" +source "soc/arm/gd_gd32/gd32e50x/Kconfig.defconfig.gd32*" config SOC_SERIES default "gd32e50x" diff --git a/soc/arm/gigadevice/gd32e50x/Kconfig.series b/soc/arm/gd_gd32/gd32e50x/Kconfig.series similarity index 100% rename from soc/arm/gigadevice/gd32e50x/Kconfig.series rename to soc/arm/gd_gd32/gd32e50x/Kconfig.series diff --git a/soc/arm/gigadevice/gd32e50x/Kconfig.soc b/soc/arm/gd_gd32/gd32e50x/Kconfig.soc similarity index 100% rename from soc/arm/gigadevice/gd32e50x/Kconfig.soc rename to soc/arm/gd_gd32/gd32e50x/Kconfig.soc diff --git a/soc/arm/gigadevice/gd32e50x/gd32_regs.h b/soc/arm/gd_gd32/gd32e50x/gd32_regs.h similarity index 100% rename from soc/arm/gigadevice/gd32e50x/gd32_regs.h rename to soc/arm/gd_gd32/gd32e50x/gd32_regs.h diff --git a/soc/arm/gigadevice/gd32e50x/soc.c b/soc/arm/gd_gd32/gd32e50x/soc.c similarity index 100% rename from soc/arm/gigadevice/gd32e50x/soc.c rename to soc/arm/gd_gd32/gd32e50x/soc.c diff --git a/soc/arm/gigadevice/gd32e50x/soc.h b/soc/arm/gd_gd32/gd32e50x/soc.h similarity index 100% rename from soc/arm/gigadevice/gd32e50x/soc.h rename to soc/arm/gd_gd32/gd32e50x/soc.h diff --git a/soc/arm/gigadevice/gd32f3x0/CMakeLists.txt b/soc/arm/gd_gd32/gd32f3x0/CMakeLists.txt similarity index 100% rename from soc/arm/gigadevice/gd32f3x0/CMakeLists.txt rename to soc/arm/gd_gd32/gd32f3x0/CMakeLists.txt diff --git a/soc/arm/gigadevice/gd32f3x0/Kconfig.defconfig.gd32f350 b/soc/arm/gd_gd32/gd32f3x0/Kconfig.defconfig.gd32f350 similarity index 100% rename from soc/arm/gigadevice/gd32f3x0/Kconfig.defconfig.gd32f350 rename to soc/arm/gd_gd32/gd32f3x0/Kconfig.defconfig.gd32f350 diff --git a/soc/arm/gigadevice/gd32f3x0/Kconfig.defconfig.series b/soc/arm/gd_gd32/gd32f3x0/Kconfig.defconfig.series similarity index 73% rename from soc/arm/gigadevice/gd32f3x0/Kconfig.defconfig.series rename to soc/arm/gd_gd32/gd32f3x0/Kconfig.defconfig.series index dc9607f1149..4852255d255 100644 --- a/soc/arm/gigadevice/gd32f3x0/Kconfig.defconfig.series +++ b/soc/arm/gd_gd32/gd32f3x0/Kconfig.defconfig.series @@ -3,7 +3,7 @@ if SOC_SERIES_GD32F3X0 -source "soc/arm/gigadevice/gd32f3x0/Kconfig.defconfig.gd32*" +source "soc/arm/gd_gd32/gd32f3x0/Kconfig.defconfig.gd32*" config SOC_SERIES default "gd32f3x0" diff --git a/soc/arm/gigadevice/gd32f3x0/Kconfig.series b/soc/arm/gd_gd32/gd32f3x0/Kconfig.series similarity index 100% rename from soc/arm/gigadevice/gd32f3x0/Kconfig.series rename to soc/arm/gd_gd32/gd32f3x0/Kconfig.series diff --git a/soc/arm/gigadevice/gd32f3x0/Kconfig.soc b/soc/arm/gd_gd32/gd32f3x0/Kconfig.soc similarity index 100% rename from soc/arm/gigadevice/gd32f3x0/Kconfig.soc rename to soc/arm/gd_gd32/gd32f3x0/Kconfig.soc diff --git a/soc/arm/gigadevice/gd32f3x0/gd32_regs.h b/soc/arm/gd_gd32/gd32f3x0/gd32_regs.h similarity index 100% rename from soc/arm/gigadevice/gd32f3x0/gd32_regs.h rename to soc/arm/gd_gd32/gd32f3x0/gd32_regs.h diff --git a/soc/arm/gigadevice/gd32f3x0/soc.c b/soc/arm/gd_gd32/gd32f3x0/soc.c similarity index 100% rename from soc/arm/gigadevice/gd32f3x0/soc.c rename to soc/arm/gd_gd32/gd32f3x0/soc.c diff --git a/soc/arm/gigadevice/gd32f3x0/soc.h b/soc/arm/gd_gd32/gd32f3x0/soc.h similarity index 100% rename from soc/arm/gigadevice/gd32f3x0/soc.h rename to soc/arm/gd_gd32/gd32f3x0/soc.h diff --git a/soc/arm/gigadevice/gd32f403/CMakeLists.txt b/soc/arm/gd_gd32/gd32f403/CMakeLists.txt similarity index 100% rename from soc/arm/gigadevice/gd32f403/CMakeLists.txt rename to soc/arm/gd_gd32/gd32f403/CMakeLists.txt diff --git a/soc/arm/gigadevice/gd32f403/Kconfig.defconfig.gd32f403 b/soc/arm/gd_gd32/gd32f403/Kconfig.defconfig.gd32f403 similarity index 100% rename from soc/arm/gigadevice/gd32f403/Kconfig.defconfig.gd32f403 rename to soc/arm/gd_gd32/gd32f403/Kconfig.defconfig.gd32f403 diff --git a/soc/arm/gigadevice/gd32f403/Kconfig.defconfig.series b/soc/arm/gd_gd32/gd32f403/Kconfig.defconfig.series similarity index 72% rename from soc/arm/gigadevice/gd32f403/Kconfig.defconfig.series rename to soc/arm/gd_gd32/gd32f403/Kconfig.defconfig.series index dbec480c299..8923e1582a3 100644 --- a/soc/arm/gigadevice/gd32f403/Kconfig.defconfig.series +++ b/soc/arm/gd_gd32/gd32f403/Kconfig.defconfig.series @@ -3,7 +3,7 @@ if SOC_SERIES_GD32F403 -source "soc/arm/gigadevice/gd32f403/Kconfig.defconfig.gd32f403" +source "soc/arm/gd_gd32/gd32f403/Kconfig.defconfig.gd32f403" config SOC_SERIES default "gd32f403" diff --git a/soc/arm/gigadevice/gd32f403/Kconfig.series b/soc/arm/gd_gd32/gd32f403/Kconfig.series similarity index 100% rename from soc/arm/gigadevice/gd32f403/Kconfig.series rename to soc/arm/gd_gd32/gd32f403/Kconfig.series diff --git a/soc/arm/gigadevice/gd32f403/Kconfig.soc b/soc/arm/gd_gd32/gd32f403/Kconfig.soc similarity index 100% rename from soc/arm/gigadevice/gd32f403/Kconfig.soc rename to soc/arm/gd_gd32/gd32f403/Kconfig.soc diff --git a/soc/arm/gigadevice/gd32f403/gd32_regs.h b/soc/arm/gd_gd32/gd32f403/gd32_regs.h similarity index 100% rename from soc/arm/gigadevice/gd32f403/gd32_regs.h rename to soc/arm/gd_gd32/gd32f403/gd32_regs.h diff --git a/soc/arm/gigadevice/gd32f403/soc.c b/soc/arm/gd_gd32/gd32f403/soc.c similarity index 100% rename from soc/arm/gigadevice/gd32f403/soc.c rename to soc/arm/gd_gd32/gd32f403/soc.c diff --git a/soc/arm/gigadevice/gd32f403/soc.h b/soc/arm/gd_gd32/gd32f403/soc.h similarity index 100% rename from soc/arm/gigadevice/gd32f403/soc.h rename to soc/arm/gd_gd32/gd32f403/soc.h diff --git a/soc/arm/gigadevice/gd32f4xx/CMakeLists.txt b/soc/arm/gd_gd32/gd32f4xx/CMakeLists.txt similarity index 100% rename from soc/arm/gigadevice/gd32f4xx/CMakeLists.txt rename to soc/arm/gd_gd32/gd32f4xx/CMakeLists.txt diff --git a/soc/arm/gigadevice/gd32f4xx/Kconfig.defconfig.gd32f405 b/soc/arm/gd_gd32/gd32f4xx/Kconfig.defconfig.gd32f405 similarity index 100% rename from soc/arm/gigadevice/gd32f4xx/Kconfig.defconfig.gd32f405 rename to soc/arm/gd_gd32/gd32f4xx/Kconfig.defconfig.gd32f405 diff --git a/soc/arm/gigadevice/gd32f4xx/Kconfig.defconfig.gd32f407 b/soc/arm/gd_gd32/gd32f4xx/Kconfig.defconfig.gd32f407 similarity index 100% rename from soc/arm/gigadevice/gd32f4xx/Kconfig.defconfig.gd32f407 rename to soc/arm/gd_gd32/gd32f4xx/Kconfig.defconfig.gd32f407 diff --git a/soc/arm/gigadevice/gd32f4xx/Kconfig.defconfig.gd32f450 b/soc/arm/gd_gd32/gd32f4xx/Kconfig.defconfig.gd32f450 similarity index 100% rename from soc/arm/gigadevice/gd32f4xx/Kconfig.defconfig.gd32f450 rename to soc/arm/gd_gd32/gd32f4xx/Kconfig.defconfig.gd32f450 diff --git a/soc/arm/gigadevice/gd32f4xx/Kconfig.defconfig.gd32f470 b/soc/arm/gd_gd32/gd32f4xx/Kconfig.defconfig.gd32f470 similarity index 100% rename from soc/arm/gigadevice/gd32f4xx/Kconfig.defconfig.gd32f470 rename to soc/arm/gd_gd32/gd32f4xx/Kconfig.defconfig.gd32f470 diff --git a/soc/arm/gigadevice/gd32f4xx/Kconfig.defconfig.series b/soc/arm/gd_gd32/gd32f4xx/Kconfig.defconfig.series similarity index 74% rename from soc/arm/gigadevice/gd32f4xx/Kconfig.defconfig.series rename to soc/arm/gd_gd32/gd32f4xx/Kconfig.defconfig.series index f5ef03cd276..a4ccaed4e80 100644 --- a/soc/arm/gigadevice/gd32f4xx/Kconfig.defconfig.series +++ b/soc/arm/gd_gd32/gd32f4xx/Kconfig.defconfig.series @@ -3,7 +3,7 @@ if SOC_SERIES_GD32F4XX -source "soc/arm/gigadevice/gd32f4xx/Kconfig.defconfig.gd32*" +source "soc/arm/gd_gd32/gd32f4xx/Kconfig.defconfig.gd32*" config SOC_SERIES default "gd32f4xx" diff --git a/soc/arm/gigadevice/gd32f4xx/Kconfig.series b/soc/arm/gd_gd32/gd32f4xx/Kconfig.series similarity index 100% rename from soc/arm/gigadevice/gd32f4xx/Kconfig.series rename to soc/arm/gd_gd32/gd32f4xx/Kconfig.series diff --git a/soc/arm/gigadevice/gd32f4xx/Kconfig.soc b/soc/arm/gd_gd32/gd32f4xx/Kconfig.soc similarity index 100% rename from soc/arm/gigadevice/gd32f4xx/Kconfig.soc rename to soc/arm/gd_gd32/gd32f4xx/Kconfig.soc diff --git a/soc/arm/gigadevice/gd32f4xx/gd32_regs.h b/soc/arm/gd_gd32/gd32f4xx/gd32_regs.h similarity index 100% rename from soc/arm/gigadevice/gd32f4xx/gd32_regs.h rename to soc/arm/gd_gd32/gd32f4xx/gd32_regs.h diff --git a/soc/arm/gigadevice/gd32f4xx/soc.c b/soc/arm/gd_gd32/gd32f4xx/soc.c similarity index 100% rename from soc/arm/gigadevice/gd32f4xx/soc.c rename to soc/arm/gd_gd32/gd32f4xx/soc.c diff --git a/soc/arm/gigadevice/gd32f4xx/soc.h b/soc/arm/gd_gd32/gd32f4xx/soc.h similarity index 100% rename from soc/arm/gigadevice/gd32f4xx/soc.h rename to soc/arm/gd_gd32/gd32f4xx/soc.h diff --git a/soc/arm/gigadevice/gd32l23x/CMakeLists.txt b/soc/arm/gd_gd32/gd32l23x/CMakeLists.txt similarity index 100% rename from soc/arm/gigadevice/gd32l23x/CMakeLists.txt rename to soc/arm/gd_gd32/gd32l23x/CMakeLists.txt diff --git a/soc/arm/gigadevice/gd32l23x/Kconfig.defconfig.gd32l233 b/soc/arm/gd_gd32/gd32l23x/Kconfig.defconfig.gd32l233 similarity index 100% rename from soc/arm/gigadevice/gd32l23x/Kconfig.defconfig.gd32l233 rename to soc/arm/gd_gd32/gd32l23x/Kconfig.defconfig.gd32l233 diff --git a/soc/arm/gigadevice/gd32l23x/Kconfig.defconfig.series b/soc/arm/gd_gd32/gd32l23x/Kconfig.defconfig.series similarity index 73% rename from soc/arm/gigadevice/gd32l23x/Kconfig.defconfig.series rename to soc/arm/gd_gd32/gd32l23x/Kconfig.defconfig.series index da16d8f287c..36a6476dbfb 100644 --- a/soc/arm/gigadevice/gd32l23x/Kconfig.defconfig.series +++ b/soc/arm/gd_gd32/gd32l23x/Kconfig.defconfig.series @@ -3,7 +3,7 @@ if SOC_SERIES_GD32L23X -source "soc/arm/gigadevice/gd32l23x/Kconfig.defconfig.gd32*" +source "soc/arm/gd_gd32/gd32l23x/Kconfig.defconfig.gd32*" config SOC_SERIES default "gd32l23x" diff --git a/soc/arm/gigadevice/gd32l23x/Kconfig.series b/soc/arm/gd_gd32/gd32l23x/Kconfig.series similarity index 100% rename from soc/arm/gigadevice/gd32l23x/Kconfig.series rename to soc/arm/gd_gd32/gd32l23x/Kconfig.series diff --git a/soc/arm/gigadevice/gd32l23x/Kconfig.soc b/soc/arm/gd_gd32/gd32l23x/Kconfig.soc similarity index 100% rename from soc/arm/gigadevice/gd32l23x/Kconfig.soc rename to soc/arm/gd_gd32/gd32l23x/Kconfig.soc diff --git a/soc/arm/gigadevice/gd32l23x/gd32_regs.h b/soc/arm/gd_gd32/gd32l23x/gd32_regs.h similarity index 100% rename from soc/arm/gigadevice/gd32l23x/gd32_regs.h rename to soc/arm/gd_gd32/gd32l23x/gd32_regs.h diff --git a/soc/arm/gigadevice/gd32l23x/soc.c b/soc/arm/gd_gd32/gd32l23x/soc.c similarity index 100% rename from soc/arm/gigadevice/gd32l23x/soc.c rename to soc/arm/gd_gd32/gd32l23x/soc.c diff --git a/soc/arm/gigadevice/gd32l23x/soc.h b/soc/arm/gd_gd32/gd32l23x/soc.h similarity index 100% rename from soc/arm/gigadevice/gd32l23x/soc.h rename to soc/arm/gd_gd32/gd32l23x/soc.h From 0f73e8fd3e2f9594dd223b93b891808891e83929 Mon Sep 17 00:00:00 2001 From: Gerard Marull-Paretas Date: Tue, 9 Jan 2024 09:50:44 +0100 Subject: [PATCH 2053/3723] dts: arm/riscv: gigadevice: s/gigadevice/gd To stay consistent with other vendors, use vendor prefix (gd). Signed-off-by: Gerard Marull-Paretas --- CODEOWNERS | 2 +- MAINTAINERS.yml | 2 +- boards/arm/gd32a503v_eval/gd32a503v_eval.dts | 2 +- boards/arm/gd32e103v_eval/gd32e103v_eval.dts | 2 +- boards/arm/gd32e507v_start/gd32e507v_start.dts | 2 +- boards/arm/gd32e507z_eval/gd32e507z_eval.dts | 2 +- boards/arm/gd32f350r_eval/gd32f350r_eval.dts | 2 +- boards/arm/gd32f403z_eval/gd32f403z_eval.dts | 2 +- boards/arm/gd32f407v_start/gd32f407v_start.dts | 2 +- boards/arm/gd32f450i_eval/gd32f450i_eval.dts | 2 +- boards/arm/gd32f450v_start/gd32f450v_start.dts | 2 +- boards/arm/gd32f450z_eval/gd32f450z_eval.dts | 2 +- boards/arm/gd32f470i_eval/gd32f470i_eval.dts | 2 +- boards/arm/gd32l233r_eval/gd32l233r_eval.dts | 2 +- boards/riscv/gd32vf103c_starter/gd32vf103c_starter.dts | 2 +- boards/riscv/gd32vf103v_eval/gd32vf103v_eval.dts | 2 +- boards/riscv/longan_nano/longan_nano.dts | 2 +- boards/riscv/longan_nano/longan_nano_lite.dts | 2 +- dts/arm/{gigadevice => gd}/gd32a50x/gd32a503vdt3.dtsi | 2 +- dts/arm/{gigadevice => gd}/gd32a50x/gd32a50x.dtsi | 0 dts/arm/{gigadevice => gd}/gd32e10x/gd32e103vbt6.dtsi | 2 +- dts/arm/{gigadevice => gd}/gd32e10x/gd32e10x.dtsi | 0 dts/arm/{gigadevice => gd}/gd32e50x/gd32e507xe.dtsi | 2 +- dts/arm/{gigadevice => gd}/gd32e50x/gd32e50x.dtsi | 0 dts/arm/{gigadevice => gd}/gd32f3x0/gd32f350.dtsi | 2 +- dts/arm/{gigadevice => gd}/gd32f3x0/gd32f350g6.dtsi | 2 +- dts/arm/{gigadevice => gd}/gd32f3x0/gd32f350rb.dtsi | 2 +- dts/arm/{gigadevice => gd}/gd32f3x0/gd32f3x0.dtsi | 0 dts/arm/{gigadevice => gd}/gd32f403/gd32f403.dtsi | 0 dts/arm/{gigadevice => gd}/gd32f403/gd32f403zet6.dtsi | 2 +- dts/arm/{gigadevice => gd}/gd32f4xx/gd32f405.dtsi | 2 +- dts/arm/{gigadevice => gd}/gd32f4xx/gd32f405vg.dtsi | 2 +- dts/arm/{gigadevice => gd}/gd32f4xx/gd32f407.dtsi | 2 +- dts/arm/{gigadevice => gd}/gd32f4xx/gd32f407xe.dtsi | 2 +- dts/arm/{gigadevice => gd}/gd32f4xx/gd32f407xg.dtsi | 2 +- dts/arm/{gigadevice => gd}/gd32f4xx/gd32f407xk.dtsi | 2 +- dts/arm/{gigadevice => gd}/gd32f4xx/gd32f450.dtsi | 2 +- dts/arm/{gigadevice => gd}/gd32f4xx/gd32f450xk.dtsi | 2 +- dts/arm/{gigadevice => gd}/gd32f4xx/gd32f470.dtsi | 2 +- dts/arm/{gigadevice => gd}/gd32f4xx/gd32f470ik.dtsi | 2 +- dts/arm/{gigadevice => gd}/gd32f4xx/gd32f4xx.dtsi | 0 dts/arm/{gigadevice => gd}/gd32l23x/gd32l233rc.dtsi | 2 +- dts/arm/{gigadevice => gd}/gd32l23x/gd32l23x.dtsi | 0 dts/riscv/{gigadevice => gd}/gd32vf103.dtsi | 0 dts/riscv/{gigadevice => gd}/gd32vf103X8.dtsi | 2 +- dts/riscv/{gigadevice => gd}/gd32vf103Xb.dtsi | 2 +- 46 files changed, 38 insertions(+), 38 deletions(-) rename dts/arm/{gigadevice => gd}/gd32a50x/gd32a503vdt3.dtsi (83%) rename dts/arm/{gigadevice => gd}/gd32a50x/gd32a50x.dtsi (100%) rename dts/arm/{gigadevice => gd}/gd32e10x/gd32e103vbt6.dtsi (83%) rename dts/arm/{gigadevice => gd}/gd32e10x/gd32e10x.dtsi (100%) rename dts/arm/{gigadevice => gd}/gd32e50x/gd32e507xe.dtsi (98%) rename dts/arm/{gigadevice => gd}/gd32e50x/gd32e50x.dtsi (100%) rename dts/arm/{gigadevice => gd}/gd32f3x0/gd32f350.dtsi (88%) rename dts/arm/{gigadevice => gd}/gd32f3x0/gd32f350g6.dtsi (81%) rename dts/arm/{gigadevice => gd}/gd32f3x0/gd32f350rb.dtsi (81%) rename dts/arm/{gigadevice => gd}/gd32f3x0/gd32f3x0.dtsi (100%) rename dts/arm/{gigadevice => gd}/gd32f403/gd32f403.dtsi (100%) rename dts/arm/{gigadevice => gd}/gd32f403/gd32f403zet6.dtsi (81%) rename dts/arm/{gigadevice => gd}/gd32f4xx/gd32f405.dtsi (74%) rename dts/arm/{gigadevice => gd}/gd32f4xx/gd32f405vg.dtsi (85%) rename dts/arm/{gigadevice => gd}/gd32f4xx/gd32f407.dtsi (77%) rename dts/arm/{gigadevice => gd}/gd32f4xx/gd32f407xe.dtsi (80%) rename dts/arm/{gigadevice => gd}/gd32f4xx/gd32f407xg.dtsi (80%) rename dts/arm/{gigadevice => gd}/gd32f4xx/gd32f407xk.dtsi (80%) rename dts/arm/{gigadevice => gd}/gd32f4xx/gd32f450.dtsi (95%) rename dts/arm/{gigadevice => gd}/gd32f4xx/gd32f450xk.dtsi (78%) rename dts/arm/{gigadevice => gd}/gd32f4xx/gd32f470.dtsi (74%) rename dts/arm/{gigadevice => gd}/gd32f4xx/gd32f470ik.dtsi (76%) rename dts/arm/{gigadevice => gd}/gd32f4xx/gd32f4xx.dtsi (100%) rename dts/arm/{gigadevice => gd}/gd32l23x/gd32l233rc.dtsi (95%) rename dts/arm/{gigadevice => gd}/gd32l23x/gd32l23x.dtsi (100%) rename dts/riscv/{gigadevice => gd}/gd32vf103.dtsi (100%) rename dts/riscv/{gigadevice => gd}/gd32vf103X8.dtsi (86%) rename dts/riscv/{gigadevice => gd}/gd32vf103Xb.dtsi (86%) diff --git a/CODEOWNERS b/CODEOWNERS index af2cb6c5d51..46b71efa32b 100644 --- a/CODEOWNERS +++ b/CODEOWNERS @@ -419,7 +419,7 @@ /dts/arm/atmel/ @galak /dts/arm/broadcom/ @sbranden /dts/arm/cypress/ @ifyall @npal-cy -/dts/arm/gigadevice/ @nandojve +/dts/arm/gd/ @nandojve /dts/arm/infineon/xmc4* @parthitce @ifyall @npal-cy /dts/arm/infineon/psoc6/ @ifyall @npal-cy /dts/arm64/armv8-r.dtsi @povergoing diff --git a/MAINTAINERS.yml b/MAINTAINERS.yml index cab33e30ca8..a2098e0452e 100644 --- a/MAINTAINERS.yml +++ b/MAINTAINERS.yml @@ -2994,7 +2994,7 @@ GD32 Platforms: - boards/riscv/gd32*/ - boards/riscv/longan_nano/ - drivers/*/*gd32* - - dts/*/gigadevice/ + - dts/*/gd/ - dts/bindings/*/*gd32* - soc/*/gd_gd32/ - scripts/west_commands/*/*gd32* diff --git a/boards/arm/gd32a503v_eval/gd32a503v_eval.dts b/boards/arm/gd32a503v_eval/gd32a503v_eval.dts index f5f79267c16..dc6e0325452 100644 --- a/boards/arm/gd32a503v_eval/gd32a503v_eval.dts +++ b/boards/arm/gd32a503v_eval/gd32a503v_eval.dts @@ -5,7 +5,7 @@ /dts-v1/; -#include +#include #include "gd32a503v_eval-pinctrl.dtsi" / { diff --git a/boards/arm/gd32e103v_eval/gd32e103v_eval.dts b/boards/arm/gd32e103v_eval/gd32e103v_eval.dts index 1811736fb04..c4aa7403591 100644 --- a/boards/arm/gd32e103v_eval/gd32e103v_eval.dts +++ b/boards/arm/gd32e103v_eval/gd32e103v_eval.dts @@ -5,7 +5,7 @@ /dts-v1/; -#include +#include #include "gd32e103v_eval-pinctrl.dtsi" #include diff --git a/boards/arm/gd32e507v_start/gd32e507v_start.dts b/boards/arm/gd32e507v_start/gd32e507v_start.dts index 4da44f66ff5..5c287ed51fe 100644 --- a/boards/arm/gd32e507v_start/gd32e507v_start.dts +++ b/boards/arm/gd32e507v_start/gd32e507v_start.dts @@ -5,7 +5,7 @@ /dts-v1/; -#include +#include #include "gd32e507v_start-pinctrl.dtsi" #include diff --git a/boards/arm/gd32e507z_eval/gd32e507z_eval.dts b/boards/arm/gd32e507z_eval/gd32e507z_eval.dts index 6f7140ca17f..9f9be821e41 100644 --- a/boards/arm/gd32e507z_eval/gd32e507z_eval.dts +++ b/boards/arm/gd32e507z_eval/gd32e507z_eval.dts @@ -5,7 +5,7 @@ /dts-v1/; -#include +#include #include "gd32e507z_eval-pinctrl.dtsi" #include diff --git a/boards/arm/gd32f350r_eval/gd32f350r_eval.dts b/boards/arm/gd32f350r_eval/gd32f350r_eval.dts index c3f721c4beb..84133e75e4e 100644 --- a/boards/arm/gd32f350r_eval/gd32f350r_eval.dts +++ b/boards/arm/gd32f350r_eval/gd32f350r_eval.dts @@ -5,7 +5,7 @@ /dts-v1/; -#include +#include #include "gd32f350r_eval-pinctrl.dtsi" / { diff --git a/boards/arm/gd32f403z_eval/gd32f403z_eval.dts b/boards/arm/gd32f403z_eval/gd32f403z_eval.dts index f2ff8bd1efc..fe96f6832a0 100644 --- a/boards/arm/gd32f403z_eval/gd32f403z_eval.dts +++ b/boards/arm/gd32f403z_eval/gd32f403z_eval.dts @@ -5,7 +5,7 @@ /dts-v1/; -#include +#include #include "gd32f403z_eval-pinctrl.dtsi" #include diff --git a/boards/arm/gd32f407v_start/gd32f407v_start.dts b/boards/arm/gd32f407v_start/gd32f407v_start.dts index f8df275d830..1b36e5cfdbd 100644 --- a/boards/arm/gd32f407v_start/gd32f407v_start.dts +++ b/boards/arm/gd32f407v_start/gd32f407v_start.dts @@ -5,7 +5,7 @@ /dts-v1/; -#include +#include #include "gd32f407v_start-pinctrl.dtsi" #include diff --git a/boards/arm/gd32f450i_eval/gd32f450i_eval.dts b/boards/arm/gd32f450i_eval/gd32f450i_eval.dts index 01dd5ff86de..4e2f87c4015 100644 --- a/boards/arm/gd32f450i_eval/gd32f450i_eval.dts +++ b/boards/arm/gd32f450i_eval/gd32f450i_eval.dts @@ -5,7 +5,7 @@ /dts-v1/; -#include +#include #include "gd32f450i_eval-pinctrl.dtsi" #include diff --git a/boards/arm/gd32f450v_start/gd32f450v_start.dts b/boards/arm/gd32f450v_start/gd32f450v_start.dts index 803ff1a9709..20500889670 100644 --- a/boards/arm/gd32f450v_start/gd32f450v_start.dts +++ b/boards/arm/gd32f450v_start/gd32f450v_start.dts @@ -5,7 +5,7 @@ /dts-v1/; -#include +#include #include "gd32f450v_start-pinctrl.dtsi" #include diff --git a/boards/arm/gd32f450z_eval/gd32f450z_eval.dts b/boards/arm/gd32f450z_eval/gd32f450z_eval.dts index b40cbb54c79..c636a5647c7 100644 --- a/boards/arm/gd32f450z_eval/gd32f450z_eval.dts +++ b/boards/arm/gd32f450z_eval/gd32f450z_eval.dts @@ -5,7 +5,7 @@ /dts-v1/; -#include +#include #include "gd32f450z_eval-pinctrl.dtsi" #include diff --git a/boards/arm/gd32f470i_eval/gd32f470i_eval.dts b/boards/arm/gd32f470i_eval/gd32f470i_eval.dts index 792533b63ac..306d190b3d4 100644 --- a/boards/arm/gd32f470i_eval/gd32f470i_eval.dts +++ b/boards/arm/gd32f470i_eval/gd32f470i_eval.dts @@ -5,7 +5,7 @@ /dts-v1/; -#include +#include #include "gd32f470i_eval-pinctrl.dtsi" #include diff --git a/boards/arm/gd32l233r_eval/gd32l233r_eval.dts b/boards/arm/gd32l233r_eval/gd32l233r_eval.dts index 31348d14920..5ee22563bd0 100644 --- a/boards/arm/gd32l233r_eval/gd32l233r_eval.dts +++ b/boards/arm/gd32l233r_eval/gd32l233r_eval.dts @@ -5,7 +5,7 @@ /dts-v1/; -#include +#include #include "gd32l233r_eval-pinctrl.dtsi" #include diff --git a/boards/riscv/gd32vf103c_starter/gd32vf103c_starter.dts b/boards/riscv/gd32vf103c_starter/gd32vf103c_starter.dts index 160d6b14d4d..8939bb4cddb 100644 --- a/boards/riscv/gd32vf103c_starter/gd32vf103c_starter.dts +++ b/boards/riscv/gd32vf103c_starter/gd32vf103c_starter.dts @@ -5,7 +5,7 @@ /dts-v1/; -#include +#include #include "gd32vf103c_starter-pinctrl.dtsi" #include diff --git a/boards/riscv/gd32vf103v_eval/gd32vf103v_eval.dts b/boards/riscv/gd32vf103v_eval/gd32vf103v_eval.dts index 3cb3b024cea..cea9c00b7e9 100644 --- a/boards/riscv/gd32vf103v_eval/gd32vf103v_eval.dts +++ b/boards/riscv/gd32vf103v_eval/gd32vf103v_eval.dts @@ -5,7 +5,7 @@ /dts-v1/; -#include +#include #include "gd32vf103v_eval-pinctrl.dtsi" #include diff --git a/boards/riscv/longan_nano/longan_nano.dts b/boards/riscv/longan_nano/longan_nano.dts index e86c1992be1..dd59e6cfe5f 100644 --- a/boards/riscv/longan_nano/longan_nano.dts +++ b/boards/riscv/longan_nano/longan_nano.dts @@ -5,7 +5,7 @@ */ /dts-v1/; -#include +#include #include "longan_nano-pinctrl.dtsi" #include "longan_nano-common.dtsi" diff --git a/boards/riscv/longan_nano/longan_nano_lite.dts b/boards/riscv/longan_nano/longan_nano_lite.dts index 976992c3173..a36827b1bcd 100644 --- a/boards/riscv/longan_nano/longan_nano_lite.dts +++ b/boards/riscv/longan_nano/longan_nano_lite.dts @@ -5,7 +5,7 @@ */ /dts-v1/; -#include +#include #include "longan_nano-pinctrl.dtsi" #include "longan_nano-common.dtsi" diff --git a/dts/arm/gigadevice/gd32a50x/gd32a503vdt3.dtsi b/dts/arm/gd/gd32a50x/gd32a503vdt3.dtsi similarity index 83% rename from dts/arm/gigadevice/gd32a50x/gd32a503vdt3.dtsi rename to dts/arm/gd/gd32a50x/gd32a503vdt3.dtsi index 674016f5e98..98fad6847f0 100644 --- a/dts/arm/gigadevice/gd32a50x/gd32a503vdt3.dtsi +++ b/dts/arm/gd/gd32a50x/gd32a503vdt3.dtsi @@ -5,7 +5,7 @@ */ #include -#include +#include &flash0 { reg = <0x08000000 DT_SIZE_K(384)>; diff --git a/dts/arm/gigadevice/gd32a50x/gd32a50x.dtsi b/dts/arm/gd/gd32a50x/gd32a50x.dtsi similarity index 100% rename from dts/arm/gigadevice/gd32a50x/gd32a50x.dtsi rename to dts/arm/gd/gd32a50x/gd32a50x.dtsi diff --git a/dts/arm/gigadevice/gd32e10x/gd32e103vbt6.dtsi b/dts/arm/gd/gd32e10x/gd32e103vbt6.dtsi similarity index 83% rename from dts/arm/gigadevice/gd32e10x/gd32e103vbt6.dtsi rename to dts/arm/gd/gd32e10x/gd32e103vbt6.dtsi index 2229355de43..7f403134076 100644 --- a/dts/arm/gigadevice/gd32e10x/gd32e103vbt6.dtsi +++ b/dts/arm/gd/gd32e10x/gd32e103vbt6.dtsi @@ -5,7 +5,7 @@ */ #include -#include +#include &flash0 { reg = <0x08000000 DT_SIZE_K(128)>; diff --git a/dts/arm/gigadevice/gd32e10x/gd32e10x.dtsi b/dts/arm/gd/gd32e10x/gd32e10x.dtsi similarity index 100% rename from dts/arm/gigadevice/gd32e10x/gd32e10x.dtsi rename to dts/arm/gd/gd32e10x/gd32e10x.dtsi diff --git a/dts/arm/gigadevice/gd32e50x/gd32e507xe.dtsi b/dts/arm/gd/gd32e50x/gd32e507xe.dtsi similarity index 98% rename from dts/arm/gigadevice/gd32e50x/gd32e507xe.dtsi rename to dts/arm/gd/gd32e50x/gd32e507xe.dtsi index 37665e54445..c897ad60f8f 100644 --- a/dts/arm/gigadevice/gd32e50x/gd32e507xe.dtsi +++ b/dts/arm/gd/gd32e50x/gd32e507xe.dtsi @@ -5,7 +5,7 @@ */ #include -#include +#include / { soc { diff --git a/dts/arm/gigadevice/gd32e50x/gd32e50x.dtsi b/dts/arm/gd/gd32e50x/gd32e50x.dtsi similarity index 100% rename from dts/arm/gigadevice/gd32e50x/gd32e50x.dtsi rename to dts/arm/gd/gd32e50x/gd32e50x.dtsi diff --git a/dts/arm/gigadevice/gd32f3x0/gd32f350.dtsi b/dts/arm/gd/gd32f3x0/gd32f350.dtsi similarity index 88% rename from dts/arm/gigadevice/gd32f3x0/gd32f350.dtsi rename to dts/arm/gd/gd32f3x0/gd32f350.dtsi index 43dbe4b3a5d..e9c5af1ab9f 100644 --- a/dts/arm/gigadevice/gd32f3x0/gd32f350.dtsi +++ b/dts/arm/gd/gd32f3x0/gd32f350.dtsi @@ -5,7 +5,7 @@ */ #include -#include +#include / { soc { diff --git a/dts/arm/gigadevice/gd32f3x0/gd32f350g6.dtsi b/dts/arm/gd/gd32f3x0/gd32f350g6.dtsi similarity index 81% rename from dts/arm/gigadevice/gd32f3x0/gd32f350g6.dtsi rename to dts/arm/gd/gd32f3x0/gd32f350g6.dtsi index ae878fac1ff..5304ebae045 100644 --- a/dts/arm/gigadevice/gd32f3x0/gd32f350g6.dtsi +++ b/dts/arm/gd/gd32f3x0/gd32f350g6.dtsi @@ -5,7 +5,7 @@ */ #include -#include +#include &flash0 { reg = <0x08000000 DT_SIZE_K(32)>; diff --git a/dts/arm/gigadevice/gd32f3x0/gd32f350rb.dtsi b/dts/arm/gd/gd32f3x0/gd32f350rb.dtsi similarity index 81% rename from dts/arm/gigadevice/gd32f3x0/gd32f350rb.dtsi rename to dts/arm/gd/gd32f3x0/gd32f350rb.dtsi index fda4a635993..054a3848c05 100644 --- a/dts/arm/gigadevice/gd32f3x0/gd32f350rb.dtsi +++ b/dts/arm/gd/gd32f3x0/gd32f350rb.dtsi @@ -5,7 +5,7 @@ */ #include -#include +#include &flash0 { reg = <0x08000000 DT_SIZE_K(128)>; diff --git a/dts/arm/gigadevice/gd32f3x0/gd32f3x0.dtsi b/dts/arm/gd/gd32f3x0/gd32f3x0.dtsi similarity index 100% rename from dts/arm/gigadevice/gd32f3x0/gd32f3x0.dtsi rename to dts/arm/gd/gd32f3x0/gd32f3x0.dtsi diff --git a/dts/arm/gigadevice/gd32f403/gd32f403.dtsi b/dts/arm/gd/gd32f403/gd32f403.dtsi similarity index 100% rename from dts/arm/gigadevice/gd32f403/gd32f403.dtsi rename to dts/arm/gd/gd32f403/gd32f403.dtsi diff --git a/dts/arm/gigadevice/gd32f403/gd32f403zet6.dtsi b/dts/arm/gd/gd32f403/gd32f403zet6.dtsi similarity index 81% rename from dts/arm/gigadevice/gd32f403/gd32f403zet6.dtsi rename to dts/arm/gd/gd32f403/gd32f403zet6.dtsi index e93f69691a8..bfe5145e9fb 100644 --- a/dts/arm/gigadevice/gd32f403/gd32f403zet6.dtsi +++ b/dts/arm/gd/gd32f403/gd32f403zet6.dtsi @@ -5,7 +5,7 @@ */ #include -#include +#include &flash0 { reg = <0x08000000 DT_SIZE_K(512)>; diff --git a/dts/arm/gigadevice/gd32f4xx/gd32f405.dtsi b/dts/arm/gd/gd32f4xx/gd32f405.dtsi similarity index 74% rename from dts/arm/gigadevice/gd32f4xx/gd32f405.dtsi rename to dts/arm/gd/gd32f4xx/gd32f405.dtsi index dd31946ff76..0d1b1fdef3f 100644 --- a/dts/arm/gigadevice/gd32f4xx/gd32f405.dtsi +++ b/dts/arm/gd/gd32f4xx/gd32f405.dtsi @@ -4,7 +4,7 @@ * SPDX-License-Identifier: Apache-2.0 */ -#include +#include &cpu0 { clock-frequency = <168000000>; diff --git a/dts/arm/gigadevice/gd32f4xx/gd32f405vg.dtsi b/dts/arm/gd/gd32f4xx/gd32f405vg.dtsi similarity index 85% rename from dts/arm/gigadevice/gd32f4xx/gd32f405vg.dtsi rename to dts/arm/gd/gd32f4xx/gd32f405vg.dtsi index ef9a82f8b44..0197c8c4d9e 100644 --- a/dts/arm/gigadevice/gd32f4xx/gd32f405vg.dtsi +++ b/dts/arm/gd/gd32f4xx/gd32f405vg.dtsi @@ -5,7 +5,7 @@ */ #include -#include +#include / { soc { diff --git a/dts/arm/gigadevice/gd32f4xx/gd32f407.dtsi b/dts/arm/gd/gd32f4xx/gd32f407.dtsi similarity index 77% rename from dts/arm/gigadevice/gd32f4xx/gd32f407.dtsi rename to dts/arm/gd/gd32f4xx/gd32f407.dtsi index dc4d74b1a28..bfc8d85c01b 100644 --- a/dts/arm/gigadevice/gd32f4xx/gd32f407.dtsi +++ b/dts/arm/gd/gd32f4xx/gd32f407.dtsi @@ -4,7 +4,7 @@ * SPDX-License-Identifier: Apache-2.0 */ -#include +#include &cpu0 { clock-frequency = <168000000>; diff --git a/dts/arm/gigadevice/gd32f4xx/gd32f407xe.dtsi b/dts/arm/gd/gd32f4xx/gd32f407xe.dtsi similarity index 80% rename from dts/arm/gigadevice/gd32f4xx/gd32f407xe.dtsi rename to dts/arm/gd/gd32f4xx/gd32f407xe.dtsi index eb3549aa29b..48a8deff114 100644 --- a/dts/arm/gigadevice/gd32f4xx/gd32f407xe.dtsi +++ b/dts/arm/gd/gd32f4xx/gd32f407xe.dtsi @@ -5,7 +5,7 @@ */ #include -#include +#include &flash0 { reg = <0x08000000 DT_SIZE_K(512)>; diff --git a/dts/arm/gigadevice/gd32f4xx/gd32f407xg.dtsi b/dts/arm/gd/gd32f4xx/gd32f407xg.dtsi similarity index 80% rename from dts/arm/gigadevice/gd32f4xx/gd32f407xg.dtsi rename to dts/arm/gd/gd32f4xx/gd32f407xg.dtsi index 66e3b3a0af6..7bef0eb8d97 100644 --- a/dts/arm/gigadevice/gd32f4xx/gd32f407xg.dtsi +++ b/dts/arm/gd/gd32f4xx/gd32f407xg.dtsi @@ -5,7 +5,7 @@ */ #include -#include +#include &flash0 { reg = <0x08000000 DT_SIZE_K(1024)>; diff --git a/dts/arm/gigadevice/gd32f4xx/gd32f407xk.dtsi b/dts/arm/gd/gd32f4xx/gd32f407xk.dtsi similarity index 80% rename from dts/arm/gigadevice/gd32f4xx/gd32f407xk.dtsi rename to dts/arm/gd/gd32f4xx/gd32f407xk.dtsi index e85fddb5609..d48f6d75830 100644 --- a/dts/arm/gigadevice/gd32f4xx/gd32f407xk.dtsi +++ b/dts/arm/gd/gd32f4xx/gd32f407xk.dtsi @@ -5,7 +5,7 @@ */ #include -#include +#include &flash0 { reg = <0x08000000 DT_SIZE_K(3072)>; diff --git a/dts/arm/gigadevice/gd32f4xx/gd32f450.dtsi b/dts/arm/gd/gd32f4xx/gd32f450.dtsi similarity index 95% rename from dts/arm/gigadevice/gd32f4xx/gd32f450.dtsi rename to dts/arm/gd/gd32f4xx/gd32f450.dtsi index c6d5b0e6b0b..b1aea0ba5a5 100644 --- a/dts/arm/gigadevice/gd32f4xx/gd32f450.dtsi +++ b/dts/arm/gd/gd32f4xx/gd32f450.dtsi @@ -5,7 +5,7 @@ */ #include -#include +#include / { soc { diff --git a/dts/arm/gigadevice/gd32f4xx/gd32f450xk.dtsi b/dts/arm/gd/gd32f4xx/gd32f450xk.dtsi similarity index 78% rename from dts/arm/gigadevice/gd32f4xx/gd32f450xk.dtsi rename to dts/arm/gd/gd32f4xx/gd32f450xk.dtsi index 98c0c6e4e8d..c1f76b49382 100644 --- a/dts/arm/gigadevice/gd32f4xx/gd32f450xk.dtsi +++ b/dts/arm/gd/gd32f4xx/gd32f450xk.dtsi @@ -5,7 +5,7 @@ */ #include -#include +#include &flash0 { reg = <0x08000000 DT_SIZE_K(3072)>; diff --git a/dts/arm/gigadevice/gd32f4xx/gd32f470.dtsi b/dts/arm/gd/gd32f4xx/gd32f470.dtsi similarity index 74% rename from dts/arm/gigadevice/gd32f4xx/gd32f470.dtsi rename to dts/arm/gd/gd32f4xx/gd32f470.dtsi index a77a11763e4..1900a34abad 100644 --- a/dts/arm/gigadevice/gd32f4xx/gd32f470.dtsi +++ b/dts/arm/gd/gd32f4xx/gd32f470.dtsi @@ -4,7 +4,7 @@ * SPDX-License-Identifier: Apache-2.0 */ -#include +#include &cpu0 { clock-frequency = ; diff --git a/dts/arm/gigadevice/gd32f4xx/gd32f470ik.dtsi b/dts/arm/gd/gd32f4xx/gd32f470ik.dtsi similarity index 76% rename from dts/arm/gigadevice/gd32f4xx/gd32f470ik.dtsi rename to dts/arm/gd/gd32f4xx/gd32f470ik.dtsi index dcd74a8b35a..9f074ec7529 100644 --- a/dts/arm/gigadevice/gd32f4xx/gd32f470ik.dtsi +++ b/dts/arm/gd/gd32f4xx/gd32f470ik.dtsi @@ -5,7 +5,7 @@ */ #include -#include +#include &flash0 { reg = <0x08000000 DT_SIZE_K(3072)>; diff --git a/dts/arm/gigadevice/gd32f4xx/gd32f4xx.dtsi b/dts/arm/gd/gd32f4xx/gd32f4xx.dtsi similarity index 100% rename from dts/arm/gigadevice/gd32f4xx/gd32f4xx.dtsi rename to dts/arm/gd/gd32f4xx/gd32f4xx.dtsi diff --git a/dts/arm/gigadevice/gd32l23x/gd32l233rc.dtsi b/dts/arm/gd/gd32l23x/gd32l233rc.dtsi similarity index 95% rename from dts/arm/gigadevice/gd32l23x/gd32l233rc.dtsi rename to dts/arm/gd/gd32l23x/gd32l233rc.dtsi index 8539b3928a4..d8c2f80ee65 100644 --- a/dts/arm/gigadevice/gd32l23x/gd32l233rc.dtsi +++ b/dts/arm/gd/gd32l23x/gd32l233rc.dtsi @@ -5,7 +5,7 @@ */ #include -#include +#include / { soc { diff --git a/dts/arm/gigadevice/gd32l23x/gd32l23x.dtsi b/dts/arm/gd/gd32l23x/gd32l23x.dtsi similarity index 100% rename from dts/arm/gigadevice/gd32l23x/gd32l23x.dtsi rename to dts/arm/gd/gd32l23x/gd32l23x.dtsi diff --git a/dts/riscv/gigadevice/gd32vf103.dtsi b/dts/riscv/gd/gd32vf103.dtsi similarity index 100% rename from dts/riscv/gigadevice/gd32vf103.dtsi rename to dts/riscv/gd/gd32vf103.dtsi diff --git a/dts/riscv/gigadevice/gd32vf103X8.dtsi b/dts/riscv/gd/gd32vf103X8.dtsi similarity index 86% rename from dts/riscv/gigadevice/gd32vf103X8.dtsi rename to dts/riscv/gd/gd32vf103X8.dtsi index e92e4b73f7b..4c6c4fd695b 100644 --- a/dts/riscv/gigadevice/gd32vf103X8.dtsi +++ b/dts/riscv/gd/gd32vf103X8.dtsi @@ -5,7 +5,7 @@ */ #include -#include +#include &sram0 { reg = <0x20000000 DT_SIZE_K(20)>; diff --git a/dts/riscv/gigadevice/gd32vf103Xb.dtsi b/dts/riscv/gd/gd32vf103Xb.dtsi similarity index 86% rename from dts/riscv/gigadevice/gd32vf103Xb.dtsi rename to dts/riscv/gd/gd32vf103Xb.dtsi index aa3cbda7a85..a88aa2f0fe9 100644 --- a/dts/riscv/gigadevice/gd32vf103Xb.dtsi +++ b/dts/riscv/gd/gd32vf103Xb.dtsi @@ -5,7 +5,7 @@ */ #include -#include +#include &sram0 { reg = <0x20000000 DT_SIZE_K(32)>; From bc69500b0e101087d5c9f7261c2e729882aee88a Mon Sep 17 00:00:00 2001 From: Henrik Brix Andersen Date: Tue, 9 Jan 2024 11:23:17 +0100 Subject: [PATCH 2054/3723] drivers: can: stm32h7: fdcan: add support for domain clock and divider Add support for specifying the domain/kernel clock along with a common clock divider for the STM32H7 CAN controller driver via devicetree. Previously, the driver only supported using the PLL1_Q clock for domain/kernel clock, but now the driver defaults to the HSE clock, which is the chip default. Update existing boards to continue to use the PLL1_Q clock. Signed-off-by: Henrik Brix Andersen --- .../arduino_giga_r1/arduino_giga_r1_m7.dts | 2 + .../arduino_portenta_h7-common.dtsi | 2 + boards/arm/nucleo_h743zi/nucleo_h743zi.dts | 2 + boards/arm/stm32h7b3i_dk/stm32h7b3i_dk.dts | 2 + drivers/can/can_stm32h7_fdcan.c | 55 ++++++++++++++----- dts/bindings/can/st,stm32h7-fdcan.yaml | 26 +++++++++ 6 files changed, 75 insertions(+), 14 deletions(-) diff --git a/boards/arm/arduino_giga_r1/arduino_giga_r1_m7.dts b/boards/arm/arduino_giga_r1/arduino_giga_r1_m7.dts index ef3544ef958..9cc042ff0d3 100644 --- a/boards/arm/arduino_giga_r1/arduino_giga_r1_m7.dts +++ b/boards/arm/arduino_giga_r1/arduino_giga_r1_m7.dts @@ -139,6 +139,8 @@ status = "okay"; pinctrl-0 = <&fdcan2_tx_pb13 &fdcan2_rx_pb5>; pinctrl-names = "default"; + clocks = <&rcc STM32_CLOCK_BUS_APB1_2 0x00000100>, + <&rcc STM32_SRC_PLL1_Q FDCAN_SEL(1)>; bus-speed = <125000>; bus-speed-data = <1000000>; }; diff --git a/boards/arm/arduino_portenta_h7/arduino_portenta_h7-common.dtsi b/boards/arm/arduino_portenta_h7/arduino_portenta_h7-common.dtsi index 87a22fac74e..87d85f27263 100644 --- a/boards/arm/arduino_portenta_h7/arduino_portenta_h7-common.dtsi +++ b/boards/arm/arduino_portenta_h7/arduino_portenta_h7-common.dtsi @@ -105,6 +105,8 @@ &fdcan1 { pinctrl-0 = <&fdcan1_rx_pb8 &fdcan1_tx_ph13>; pinctrl-names = "default"; + clocks = <&rcc STM32_CLOCK_BUS_APB1_2 0x00000100>, + <&rcc STM32_SRC_PLL1_Q FDCAN_SEL(1)>; }; &rtc { diff --git a/boards/arm/nucleo_h743zi/nucleo_h743zi.dts b/boards/arm/nucleo_h743zi/nucleo_h743zi.dts index f93964479e2..ad88d87f059 100644 --- a/boards/arm/nucleo_h743zi/nucleo_h743zi.dts +++ b/boards/arm/nucleo_h743zi/nucleo_h743zi.dts @@ -170,6 +170,8 @@ zephyr_udc0: &usbotg_fs { &fdcan1 { pinctrl-0 = <&fdcan1_rx_pd0 &fdcan1_tx_pd1>; pinctrl-names = "default"; + clocks = <&rcc STM32_CLOCK_BUS_APB1_2 0x00000100>, + <&rcc STM32_SRC_PLL1_Q FDCAN_SEL(1)>; bus-speed = <125000>; bus-speed-data = <1000000>; status = "okay"; diff --git a/boards/arm/stm32h7b3i_dk/stm32h7b3i_dk.dts b/boards/arm/stm32h7b3i_dk/stm32h7b3i_dk.dts index 35470174123..b8b781b3fa1 100644 --- a/boards/arm/stm32h7b3i_dk/stm32h7b3i_dk.dts +++ b/boards/arm/stm32h7b3i_dk/stm32h7b3i_dk.dts @@ -152,6 +152,8 @@ &fdcan1 { pinctrl-0 = <&fdcan1_rx_pa11 &fdcan1_tx_pa12>; pinctrl-names = "default"; + clocks = <&rcc STM32_CLOCK_BUS_APB1_2 0x00000100>, + <&rcc STM32_SRC_PLL1_Q FDCAN_SEL(1)>; phys = <&transceiver0>; bus-speed = <125000>; bus-speed-data = <1000000>; diff --git a/drivers/can/can_stm32h7_fdcan.c b/drivers/can/can_stm32h7_fdcan.c index 9b75932fd4f..977da154dc0 100644 --- a/drivers/can/can_stm32h7_fdcan.c +++ b/drivers/can/can_stm32h7_fdcan.c @@ -14,18 +14,29 @@ #include #include #include +#include LOG_MODULE_REGISTER(can_stm32h7, CONFIG_CAN_LOG_LEVEL); #define DT_DRV_COMPAT st_stm32h7_fdcan +/* This symbol takes the value 1 if one of the device instances */ +/* is configured in dts with a domain clock */ +#if STM32_DT_INST_DEV_DOMAIN_CLOCK_SUPPORT +#define STM32H7_FDCAN_DOMAIN_CLOCK_SUPPORT 1 +#else +#define STM32H7_FDCAN_DOMAIN_CLOCK_SUPPORT 0 +#endif + struct can_stm32h7_config { mm_reg_t base; mem_addr_t mrba; mem_addr_t mram; void (*config_irq)(void); const struct pinctrl_dev_config *pcfg; - struct stm32_pclken pclken; + size_t pclk_len; + const struct stm32_pclken *pclken; + uint8_t clock_divider; }; static int can_stm32h7_read_reg(const struct device *dev, uint16_t reg, uint32_t *val) @@ -72,6 +83,7 @@ static int can_stm32h7_clear_mram(const struct device *dev, uint16_t offset, siz static int can_stm32h7_get_core_clock(const struct device *dev, uint32_t *rate) { const uint32_t rate_tmp = LL_RCC_GetFDCANClockFreq(LL_RCC_FDCAN_CLKSOURCE); + uint32_t cdiv; ARG_UNUSED(dev); @@ -80,9 +92,12 @@ static int can_stm32h7_get_core_clock(const struct device *dev, uint32_t *rate) return -EIO; } - *rate = rate_tmp; - - LOG_DBG("rate=%d", *rate); + cdiv = FIELD_GET(FDCANCCU_CCFG_CDIV, FDCAN_CCU->CCFG); + if (cdiv == 0U) { + *rate = rate_tmp; + } else { + *rate = rate_tmp / (cdiv << 1U); + } return 0; } @@ -94,22 +109,32 @@ static int can_stm32h7_clock_enable(const struct device *dev) const struct device *const clk = DEVICE_DT_GET(STM32_CLOCK_CONTROL_NODE); int ret; - LL_RCC_SetFDCANClockSource(LL_RCC_FDCAN_CLKSOURCE_PLL1Q); - if (!device_is_ready(clk)) { LOG_ERR("clock control device not ready"); return -ENODEV; } - ret = clock_control_on(clk, (clock_control_subsys_t)&stm32h7_cfg->pclken); + if (IS_ENABLED(STM32H7_FDCAN_DOMAIN_CLOCK_SUPPORT) && (stm32h7_cfg->pclk_len > 1)) { + ret = clock_control_configure(clk, + (clock_control_subsys_t)&stm32h7_cfg->pclken[1], + NULL); + if (ret < 0) { + LOG_ERR("Could not select can_stm32fd domain clock"); + return ret; + } + } + + ret = clock_control_on(clk, (clock_control_subsys_t)&stm32h7_cfg->pclken[0]); if (ret != 0) { LOG_ERR("failure enabling clock"); return ret; } - if (!LL_RCC_PLL1Q_IsEnabled()) { - LOG_ERR("PLL1Q clock must be enabled!"); - return -EIO; + if (stm32h7_cfg->clock_divider != 0U) { + can_mcan_enable_configuration_change(dev); + + FDCAN_CCU->CCFG = FDCANCCU_CCFG_BCC | + FIELD_PREP(FDCANCCU_CCFG_CDIV, stm32h7_cfg->clock_divider >> 1U); } return 0; @@ -204,16 +229,18 @@ static const struct can_mcan_ops can_stm32h7_ops = { PINCTRL_DT_INST_DEFINE(n); \ CAN_MCAN_DT_INST_CALLBACKS_DEFINE(n, can_stm32h7_cbs_##n); \ \ + static const struct stm32_pclken can_stm32h7_pclken_##n[] = \ + STM32_DT_INST_CLOCKS(n); \ + \ static const struct can_stm32h7_config can_stm32h7_cfg_##n = { \ .base = CAN_MCAN_DT_INST_MCAN_ADDR(n), \ .mrba = CAN_MCAN_DT_INST_MRBA(n), \ .mram = CAN_MCAN_DT_INST_MRAM_ADDR(n), \ .config_irq = stm32h7_mcan_irq_config_##n, \ .pcfg = PINCTRL_DT_INST_DEV_CONFIG_GET(n), \ - .pclken = { \ - .enr = DT_INST_CLOCKS_CELL(n, bits), \ - .bus = DT_INST_CLOCKS_CELL(n, bus), \ - }, \ + .pclken = can_stm32h7_pclken_##n, \ + .pclk_len = DT_INST_NUM_CLOCKS(n), \ + .clock_divider = DT_INST_PROP_OR(n, clk_divider, 0) \ }; \ \ static const struct can_mcan_config can_mcan_cfg_##n = \ diff --git a/dts/bindings/can/st,stm32h7-fdcan.yaml b/dts/bindings/can/st,stm32h7-fdcan.yaml index 1d258ea4abf..14f6fad61c5 100644 --- a/dts/bindings/can/st,stm32h7-fdcan.yaml +++ b/dts/bindings/can/st,stm32h7-fdcan.yaml @@ -16,3 +16,29 @@ properties: interrupt-names: required: true + + clk-divider: + type: int + enum: + - 1 + - 2 + - 4 + - 6 + - 8 + - 10 + - 12 + - 14 + - 16 + - 18 + - 20 + - 22 + - 24 + - 26 + - 28 + - 30 + description: | + Divides the kernel clock giving the time quanta clock that is fed to the FDCAN core + (FDCAN_CCU->CCFG CDIV register bits). Note that the divisor is common to all + 'st,stm32h7-fdcan' instances. + + Divide by 1 is the peripherals reset value and remains set unless this property is configured. From 1fa11bd038e51e90f10314d0c507d5ad527ded94 Mon Sep 17 00:00:00 2001 From: Henrik Brix Andersen Date: Tue, 9 Jan 2024 11:26:24 +0100 Subject: [PATCH 2055/3723] doc: release: migration guide: 3.6: add note on stm32h7 CAN domain clk Add a note describing the new default for the STM32H7 FDCAN CAN controller domain/kernel clock and how to override it. Signed-off-by: Henrik Brix Andersen --- doc/releases/migration-guide-3.6.rst | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/doc/releases/migration-guide-3.6.rst b/doc/releases/migration-guide-3.6.rst index 22321e8e9b9..1156cc91e77 100644 --- a/doc/releases/migration-guide-3.6.rst +++ b/doc/releases/migration-guide-3.6.rst @@ -159,6 +159,18 @@ Device Drivers and Device Tree * :dtcompatible:`ti,lmp90099` * :dtcompatible:`ti,lmp90100` +* The :dtcompatible:`st,stm32h7-fdcan` CAN controller driver now supports configuring the + domain/kernel clock via devicetree. Previously, the driver only supported using the PLL1_Q clock + for kernel clock, but now it defaults to the HSE clock, which is the chip default. Boards that + use the PLL1_Q clock for FDCAN will need to override the ``clocks`` property as follows: + + .. code-block:: devicetree + + &fdcan1 { + clocks = <&rcc STM32_CLOCK_BUS_APB1_2 0x00000100>, + <&rcc STM32_SRC_PLL1_Q FDCAN_SEL(1)>; + }; + Power Management ================ From d7873e25fdd88c8740ef7ba9ef1ca5c3ef1bce5c Mon Sep 17 00:00:00 2001 From: Henrik Brix Andersen Date: Fri, 28 Jul 2023 21:12:47 +0200 Subject: [PATCH 2056/3723] boards: arm: stm32h735g_disco: enable CAN suppport Enable support for FDCAN1, FDCAN2, and FDCAN3 on the stm32h735g_disco board. Signed-off-by: Henrik Brix Andersen --- boards/arm/stm32h735g_disco/doc/index.rst | 11 +++- .../arm/stm32h735g_disco/stm32h735g_disco.dts | 54 +++++++++++++++++++ .../stm32h735g_disco/stm32h735g_disco.yaml | 1 + 3 files changed, 65 insertions(+), 1 deletion(-) diff --git a/boards/arm/stm32h735g_disco/doc/index.rst b/boards/arm/stm32h735g_disco/doc/index.rst index 473dcfa08c2..e4bf324650b 100644 --- a/boards/arm/stm32h735g_disco/doc/index.rst +++ b/boards/arm/stm32h735g_disco/doc/index.rst @@ -65,7 +65,15 @@ The current Zephyr stm32h735g_disco board configuration supports the following h +-----------+------------+-------------------------------------+ | ADC | on-chip | ADC Controller | +-----------+------------+-------------------------------------+ - +| FDCAN1 | on-chip | CAN-FD Controller | ++-----------+------------+-------------------------------------+ +| FDCAN2 | on-chip | CAN-FD Controller | ++-----------+------------+-------------------------------------+ +| FDCAN2 | on-chip | CAN-FD Controller (disabled by | +| | | default. Solder bridges SB29 and | +| | | SB30 need to be closed for FDCAN3 | +| | | to work) | ++-----------+------------+-------------------------------------+ Other hardware features are not yet supported on Zephyr porting. @@ -84,6 +92,7 @@ Default Zephyr Peripheral Mapping: - UART_7 TX/RX : PF7/PF6 (Arduino Serial) - LD1 : PC2 - LD2 : PC3 +- FDCAN1 : CAN System Clock ============ diff --git a/boards/arm/stm32h735g_disco/stm32h735g_disco.dts b/boards/arm/stm32h735g_disco/stm32h735g_disco.dts index 29eef0e5326..8443c222abd 100644 --- a/boards/arm/stm32h735g_disco/stm32h735g_disco.dts +++ b/boards/arm/stm32h735g_disco/stm32h735g_disco.dts @@ -19,6 +19,7 @@ zephyr,shell-uart = &usart3; zephyr,sram = &sram0; zephyr,flash = &flash0; + zephyr,canbus = &fdcan1; }; leds { @@ -77,6 +78,16 @@ status = "okay"; }; +&pll2 { + div-m = <5>; + mul-n = <80>; + div-p = <5>; + div-q = <5>; + div-r = <5>; + clocks = <&clk_hse>; + status = "okay"; +}; + &rcc { clocks = <&pll>; clock-frequency = ; @@ -189,3 +200,46 @@ &vbat { status = "okay"; }; + +&fdcan1 { + pinctrl-0 = <&fdcan1_rx_ph14 &fdcan1_tx_ph13>; + pinctrl-names = "default"; + clocks = <&rcc STM32_CLOCK_BUS_APB1_2 0x00000100>, + <&rcc STM32_SRC_PLL2_Q FDCAN_SEL(2)>; + status = "okay"; + bus-speed = <125000>; + bus-speed-data = <1000000>; + + can-transceiver { + max-bitrate = <8000000>; + }; +}; + +&fdcan2 { + pinctrl-0 = <&fdcan2_rx_pb5 &fdcan2_tx_pb6>; + pinctrl-names = "default"; + clocks = <&rcc STM32_CLOCK_BUS_APB1_2 0x00000100>, + <&rcc STM32_SRC_PLL2_Q FDCAN_SEL(2)>; + status = "okay"; + bus-speed = <125000>; + bus-speed-data = <1000000>; + + can-transceiver { + max-bitrate = <8000000>; + }; +}; + +&fdcan3 { + pinctrl-0 = <&fdcan3_rx_pf6 &fdcan3_tx_pf7>; + pinctrl-names = "default"; + clocks = <&rcc STM32_CLOCK_BUS_APB1_2 0x00000100>, + <&rcc STM32_SRC_PLL2_Q FDCAN_SEL(2)>; + /* Solder bridges SB29 and SB30 need to be closed for this to work */ + status = "disabled"; + bus-speed = <125000>; + bus-speed-data = <1000000>; + + can-transceiver { + max-bitrate = <8000000>; + }; +}; diff --git a/boards/arm/stm32h735g_disco/stm32h735g_disco.yaml b/boards/arm/stm32h735g_disco/stm32h735g_disco.yaml index a679deb18d4..c0983f46f4f 100644 --- a/boards/arm/stm32h735g_disco/stm32h735g_disco.yaml +++ b/boards/arm/stm32h735g_disco/stm32h735g_disco.yaml @@ -15,4 +15,5 @@ supported: - memc - adc - counter + - can vendor: st From 6127535b1d5a08df2ad4ab2df9c14fb8304fe226 Mon Sep 17 00:00:00 2001 From: Laurentiu Mihalcea Date: Thu, 21 Dec 2023 14:36:46 +0200 Subject: [PATCH 2057/3723] drivers: dai: sai: Introduce the rx_sync_mode/tx_sync_mode properties In preparation for supporting all synchronization modes, this commit introduces the rx_sync_mode/tx_sync_mode DTS properties. Using these, the user will be able to specify which synchronization mode the SAI should use. At the moment, the driver does nothing with the values from said properties but still checks if their values are sane (i.e: it checks if the directions are both in SYNC mode which is forbidden). By default, if "rx_sync_mode" or "tx_sync_mode" is not specified, the direction will be set to ASYNC mode. As such, below one may find a couple of valid examples depicting this idea: tx_sync_mode = <0>; rx_sync_mode = <0>; is the same as not specifying any of the properties, tx_sync_mode = <1>; rx_sync_mode = <0>; is the same as: tx_sync_mode = <1>; Signed-off-by: Laurentiu Mihalcea --- drivers/dai/nxp/sai/sai.c | 6 ++++++ drivers/dai/nxp/sai/sai.h | 16 ++++++++++++++++ dts/bindings/dai/nxp,dai-sai.yaml | 26 ++++++++++++++++++++++++++ 3 files changed, 48 insertions(+) diff --git a/drivers/dai/nxp/sai/sai.c b/drivers/dai/nxp/sai/sai.c index 000c754f8b6..dea2e668eef 100644 --- a/drivers/dai/nxp/sai/sai.c +++ b/drivers/dai/nxp/sai/sai.c @@ -711,6 +711,10 @@ BUILD_ASSERT(IS_ENABLED(CONFIG_SAI_HAS_MCLK_CONFIG_OPTION) || \ !DT_INST_PROP(inst, mclk_is_output), \ "SAI doesn't support MCLK config but mclk_is_output is specified");\ \ +BUILD_ASSERT(SAI_TX_SYNC_MODE(inst) != SAI_RX_SYNC_MODE(inst) || \ + SAI_TX_SYNC_MODE(inst) != kSAI_ModeSync, \ + "transmitter and receiver can't be both SYNC with each other"); \ + \ static const struct dai_properties sai_tx_props_##inst = { \ .fifo_address = SAI_TX_FIFO_BASE(inst), \ .fifo_depth = SAI_FIFO_DEPTH(inst) * CONFIG_SAI_FIFO_WORD_SIZE, \ @@ -743,6 +747,8 @@ static struct sai_config sai_config_##inst = { \ .tx_props = &sai_tx_props_##inst, \ .rx_props = &sai_rx_props_##inst, \ .irq_config = irq_config_##inst, \ + .tx_sync_mode = SAI_TX_SYNC_MODE(inst), \ + .rx_sync_mode = SAI_RX_SYNC_MODE(inst), \ }; \ \ static struct sai_data sai_data_##inst = { \ diff --git a/drivers/dai/nxp/sai/sai.h b/drivers/dai/nxp/sai/sai.h index 33200d5a8fe..92e5e8e1b00 100644 --- a/drivers/dai/nxp/sai/sai.h +++ b/drivers/dai/nxp/sai/sai.h @@ -125,6 +125,18 @@ LOG_MODULE_REGISTER(nxp_dai_sai); #define SAI_RX_DMA_MUX(inst)\ FSL_FEATURE_SAI_RX_DMA_MUXn(UINT_TO_I2S(DT_INST_REG_ADDR(inst))) +/* used to retrieve the synchronization mode of the transmitter. If this + * property is not specified, ASYNC mode will be used. + */ +#define SAI_TX_SYNC_MODE(inst)\ + DT_INST_PROP_OR(inst, tx_sync_mode, kSAI_ModeAsync) + +/* used to retrieve the synchronization mode of the receiver. If this property + * is not specified, ASYNC mode will be used. + */ +#define SAI_RX_SYNC_MODE(inst)\ + DT_INST_PROP_OR(inst, rx_sync_mode, kSAI_ModeAsync) + /* utility macros */ /* invert a clock's polarity. This works because a clock's polarity is expressed @@ -211,6 +223,10 @@ struct sai_config { const struct dai_properties *tx_props; const struct dai_properties *rx_props; uint32_t dai_index; + /* RX synchronization mode - may be SYNC or ASYNC */ + sai_sync_mode_t rx_sync_mode; + /* TX synchronization mode - may be SYNC or ASYNC */ + sai_sync_mode_t tx_sync_mode; void (*irq_config)(void); }; diff --git a/dts/bindings/dai/nxp,dai-sai.yaml b/dts/bindings/dai/nxp,dai-sai.yaml index 901382f90bb..ae9cd201880 100644 --- a/dts/bindings/dai/nxp,dai-sai.yaml +++ b/dts/bindings/dai/nxp,dai-sai.yaml @@ -58,3 +58,29 @@ properties: associated with the DAI whose index Linux passes to SOF through an IPC. If this property is not specified, the DAI index will be considered 0. + tx-sync-mode: + type: int + enum: + - 0 + - 1 + description: | + Use this property to specify which synchronization mode to use + for the transmitter. At the moment, the only supported modes are: + 1) The transmitter is ASYNC (0) + 2) The transmitter is in SYNC with the receiver (1) + If this property is not specified, the transmitter will be set to ASYNC. + If one side is SYNC then the other MUST be ASYNC. Failing to meet this + condition will result in a failed BUILD_ASSERT(). + rx-sync-mode: + type: int + enum: + - 0 + - 1 + description: | + Use this property to specify which synchronization mode to use + for the receiver. At the moment, the only supported modes are: + 1) The receiver is ASYNC (0) + 2) The receiver is in SYNC with the transmitter (1) + If this property is not specified, the receiver will be set to ASYNC. + If one side is SYNC then the other MUST be ASYNC. Failing to meet this + condition will result in a failed BUILD_ASSERT(). From 0db2d17b480f8f4ab7b90485f9cea3bce39b469f Mon Sep 17 00:00:00 2001 From: Laurentiu Mihalcea Date: Thu, 21 Dec 2023 15:02:35 +0200 Subject: [PATCH 2058/3723] drivers: dai: sai: Add support for all SYNC modes With the introduction of the "rx_sync_mode" and "tx_sync_mode" properties, the user may choose which synchronization mode the SAI should use. To support this, the code had to be changed a bit such that the software reset and the disable operations work on all synchronization modes. What this commit does, is it changes the software reset and disable sequences such that they work with any of the supported synchronization modes. Also, the syncMode field of sai_transceiver_t structure is set to the value passed from the DTS during sai_config_set(). Signed-off-by: Laurentiu Mihalcea --- drivers/dai/nxp/sai/sai.c | 191 ++++++++++++++++++++++++++------------ drivers/dai/nxp/sai/sai.h | 16 ++++ 2 files changed, 147 insertions(+), 60 deletions(-) diff --git a/drivers/dai/nxp/sai/sai.c b/drivers/dai/nxp/sai/sai.c index dea2e668eef..6719bd703df 100644 --- a/drivers/dai/nxp/sai/sai.c +++ b/drivers/dai/nxp/sai/sai.c @@ -308,11 +308,9 @@ static int sai_config_set(const struct device *dev, LOG_DBG("RX watermark: %d", sai_cfg->rx_fifo_watermark); LOG_DBG("TX watermark: %d", sai_cfg->tx_fifo_watermark); - /* TODO: for now, the only supported operation mode is RX sync with TX. - * Is there a need to support other modes? - */ - tx_config->syncMode = kSAI_ModeAsync; - rx_config->syncMode = kSAI_ModeSync; + /* set the synchronization mode based on data passed from the DTS */ + tx_config->syncMode = sai_cfg->tx_sync_mode; + rx_config->syncMode = sai_cfg->rx_sync_mode; /* commit configuration */ SAI_RxSetConfig(UINT_TO_I2S(data->regmap), rx_config); @@ -383,8 +381,33 @@ static int sai_config_set(const struct device *dev, * rid of the busy waiting, the STOP operation may have to be split into * 2 operations: TRIG_STOP and TRIG_POST_STOP. */ -static int sai_tx_rx_disable(struct sai_data *data, enum dai_dir dir) +static bool sai_dir_disable(struct sai_data *data, enum dai_dir dir) +{ + /* VERY IMPORTANT: DO NOT use SAI_TxEnable/SAI_RxEnable + * here as they do not disable the ASYNC direction. + * Since the software logic assures that the ASYNC direction + * is not disabled before the SYNC direction, we can force + * the disablement of the given direction. + */ + sai_tx_rx_force_disable(dir, data->regmap); + + /* please note the difference between the transmitter/receiver's + * hardware states and their software states. The software + * states can be obtained by reading data->tx/rx_enabled, while + * the hardware states can be obtained by reading TCSR/RCSR. The + * hardware state can actually differ from the software state. + * Here, we're interested in reading the hardware state which + * indicates if the transmitter/receiver was actually disabled + * or not. + */ + return WAIT_FOR(!SAI_TX_RX_IS_HW_ENABLED(dir, data->regmap), + SAI_TX_RX_HW_DISABLE_TIMEOUT, k_busy_wait(1)); +} + +static int sai_tx_rx_disable(struct sai_data *data, + const struct sai_config *cfg, enum dai_dir dir) { + enum dai_dir sync_dir, async_dir; bool ret; /* sai_disable() should never be called from ISR context @@ -395,44 +418,42 @@ static int sai_tx_rx_disable(struct sai_data *data, enum dai_dir dir) return -EINVAL; } - if ((dir == DAI_DIR_TX && !data->rx_enabled) || dir == DAI_DIR_RX) { - /* VERY IMPORTANT: DO NOT use SAI_TxEnable/SAI_RxEnable - * here as they do not disable the ASYNC direction. - * Since the software logic assures that the ASYNC direction - * is not disabled before the SYNC direction, we can force - * the disablement of the given direction. - */ - sai_tx_rx_force_disable(dir, data->regmap); - - /* please note the difference between the transmitter/receiver's - * hardware states and their software states. The software - * states can be obtained by reading data->tx/rx_enabled, while - * the hardware states can be obtained by reading TCSR/RCSR. The - * hadrware state can actually differ from the software state. - * Here, we're interested in reading the hardware state which - * indicates if the transmitter/receiver was actually disabled - * or not. - */ - ret = WAIT_FOR(!SAI_TX_RX_IS_HW_ENABLED(dir, data->regmap), - SAI_TX_RX_HW_DISABLE_TIMEOUT, k_busy_wait(1)); + if (cfg->tx_sync_mode == kSAI_ModeAsync && + cfg->rx_sync_mode == kSAI_ModeAsync) { + ret = sai_dir_disable(data, dir); if (!ret) { LOG_ERR("timed out while waiting for dir %d disable", dir); return -ETIMEDOUT; } - } - - /* if TX wasn't explicitly enabled (via sai_trigger_start(TX)) - * then that means it was enabled by a sai_trigger_start(RX). As - * such, data->tx_enabled will be false. - */ - if (dir == DAI_DIR_RX && !data->tx_enabled) { - sai_tx_rx_force_disable(DAI_DIR_TX, data->regmap); - - ret = WAIT_FOR(!SAI_TX_RX_IS_HW_ENABLED(DAI_DIR_TX, data->regmap), - SAI_TX_RX_HW_DISABLE_TIMEOUT, k_busy_wait(1)); - if (!ret) { - LOG_ERR("timed out while waiting for dir TX disable"); - return -ETIMEDOUT; + } else { + sync_dir = SAI_TX_RX_GET_SYNC_DIR(cfg); + async_dir = SAI_TX_RX_GET_ASYNC_DIR(cfg); + + if (dir == sync_dir) { + ret = sai_dir_disable(data, sync_dir); + if (!ret) { + LOG_ERR("timed out while waiting for dir %d disable", + sync_dir); + return -ETIMEDOUT; + } + + if (!SAI_TX_RX_DIR_IS_SW_ENABLED(async_dir, data)) { + ret = sai_dir_disable(data, async_dir); + if (!ret) { + LOG_ERR("timed out while waiting for dir %d disable", + async_dir); + return -ETIMEDOUT; + } + } + } else { + if (!SAI_TX_RX_DIR_IS_SW_ENABLED(sync_dir, data)) { + ret = sai_dir_disable(data, async_dir); + if (!ret) { + LOG_ERR("timed out while waiting for dir %d disable", + async_dir); + return -ETIMEDOUT; + } + } } } @@ -443,9 +464,11 @@ static int sai_trigger_pause(const struct device *dev, enum dai_dir dir) { struct sai_data *data; + const struct sai_config *cfg; int ret; data = dev->data; + cfg = dev->config; if (dir != DAI_DIR_RX && dir != DAI_DIR_TX) { LOG_ERR("invalid direction: %d", dir); @@ -462,7 +485,7 @@ static int sai_trigger_pause(const struct device *dev, LOG_DBG("pause on direction %d", dir); - ret = sai_tx_rx_disable(data, dir); + ret = sai_tx_rx_disable(data, cfg, dir); if (ret < 0) { return ret; } @@ -477,10 +500,12 @@ static int sai_trigger_stop(const struct device *dev, enum dai_dir dir) { struct sai_data *data; + const struct sai_config *cfg; int ret; uint32_t old_state; data = dev->data; + cfg = dev->config; old_state = sai_get_state(dir, data); if (dir != DAI_DIR_RX && dir != DAI_DIR_TX) { @@ -506,7 +531,7 @@ static int sai_trigger_stop(const struct device *dev, goto out_dline_disable; } - ret = sai_tx_rx_disable(data, dir); + ret = sai_tx_rx_disable(data, cfg, dir); if (ret < 0) { return ret; } @@ -528,14 +553,77 @@ static int sai_trigger_stop(const struct device *dev, return 0; } +/* notes: + * 1) The "rx_sync_mode" and "tx_sync_mode" properties force the user to pick from + * SYNC and ASYNC for each direction. As such, there are 4 possible combinations + * that need to be covered here: + * a) TX ASYNC, RX ASYNC + * b) TX SYNC, RX ASYNC + * c) TX ASYNC, RX SYNC + * d) TX SYNC, RX SYNC + * + * Combination d) is not valid and is covered by a BUILD_ASSERT(). As such, there are 3 valid + * combinations that need to be supported. Since the main branch of the IF statement covers + * combination a), there's only combinations b) and c) to be covered here. + * + * 2) We can distinguish between 3 types of directions: + * a) The target direction. This is the direction on which we want to perform the + * software reset. + * b) The SYNC direction. This is, well, the direction that's in SYNC with the other + * direction. + * c) The ASYNC direction. + * + * Of course, the target direction may differ from the SYNC or ASYNC directions, but it + * can't differ from both of them at the same time (i.e: TARGET != SYNC AND TARGET != ASYNC). + * + * If the target direction is the same as the SYNC direction then we can safely perform the + * software reset on the target direction as there's nothing depending on it. We also want + * to do a software reset on the ASYNC direction. We can only do this if the ASYNC direction + * wasn't software enabled (i.e: through an explicit trigger_start() call). + * + * If the target direction is the same as the ASYNC direction then we can only perform a + * software reset on it only if the SYNC direction wasn't software enabled (i.e: through an + * explicit trigger_start() call). + */ +static void sai_tx_rx_sw_reset(struct sai_data *data, + const struct sai_config *cfg, enum dai_dir dir) +{ + enum dai_dir sync_dir, async_dir; + + if (cfg->tx_sync_mode == kSAI_ModeAsync && + cfg->rx_sync_mode == kSAI_ModeAsync) { + /* both directions are ASYNC w.r.t each other. As such, do + * software reset only on the targeted direction. + */ + SAI_TX_RX_SW_RESET(dir, data->regmap); + } else { + sync_dir = SAI_TX_RX_GET_SYNC_DIR(cfg); + async_dir = SAI_TX_RX_GET_ASYNC_DIR(cfg); + + if (dir == sync_dir) { + SAI_TX_RX_SW_RESET(sync_dir, data->regmap); + + if (!SAI_TX_RX_DIR_IS_SW_ENABLED(async_dir, data)) { + SAI_TX_RX_SW_RESET(async_dir, data->regmap); + } + } else { + if (!SAI_TX_RX_DIR_IS_SW_ENABLED(sync_dir, data)) { + SAI_TX_RX_SW_RESET(async_dir, data->regmap); + } + } + } +} + static int sai_trigger_start(const struct device *dev, enum dai_dir dir) { struct sai_data *data; + const struct sai_config *cfg; uint32_t old_state; int ret; data = dev->data; + cfg = dev->config; old_state = sai_get_state(dir, data); /* TX and RX should be triggered independently */ @@ -563,24 +651,7 @@ static int sai_trigger_start(const struct device *dev, LOG_DBG("start on direction %d", dir); - if (dir == DAI_DIR_RX) { - /* this is fine because TX is async so it won't be - * affected by an RX software reset. - */ - SAI_TX_RX_SW_RESET(dir, data->regmap); - - /* do a TX software reset only if not already enabled */ - if (!data->tx_enabled) { - SAI_TX_RX_SW_RESET(DAI_DIR_TX, data->regmap); - } - } else { - /* a software reset should be issued for TX - * only if RX was not already enabled. - */ - if (!data->rx_enabled) { - SAI_TX_RX_SW_RESET(dir, data->regmap); - } - } + sai_tx_rx_sw_reset(data, cfg, dir); /* enable error interrupt */ SAI_TX_RX_ENABLE_DISABLE_IRQ(dir, data->regmap, diff --git a/drivers/dai/nxp/sai/sai.h b/drivers/dai/nxp/sai/sai.h index 92e5e8e1b00..f3f4441a6cb 100644 --- a/drivers/dai/nxp/sai/sai.h +++ b/drivers/dai/nxp/sai/sai.h @@ -190,6 +190,22 @@ LOG_MODULE_REGISTER(nxp_dai_sai); ((dir) == DAI_DIR_RX ? ((UINT_TO_I2S(regmap))->RCSR & (which)) : \ ((UINT_TO_I2S(regmap))->TCSR & (which))) +/* used to retrieve the SYNC direction. Use this macro when you know for sure + * you have 1 SYNC direction with 1 ASYNC direction. + */ +#define SAI_TX_RX_GET_SYNC_DIR(cfg)\ + ((cfg)->tx_sync_mode == kSAI_ModeSync ? DAI_DIR_TX : DAI_DIR_RX) + +/* used to retrieve the ASYNC direction. Use this macro when you know for sure + * you have 1 SYNC direction with 1 ASYNC direction. + */ +#define SAI_TX_RX_GET_ASYNC_DIR(cfg)\ + ((cfg)->tx_sync_mode == kSAI_ModeAsync ? DAI_DIR_TX : DAI_DIR_RX) + +/* used to check if transmitter/receiver is SW enabled */ +#define SAI_TX_RX_DIR_IS_SW_ENABLED(dir, data)\ + ((dir) == DAI_DIR_TX ? data->tx_enabled : data->rx_enabled) + struct sai_clock_data { uint32_t *clocks; uint32_t clock_num; From 265554b8733348cad7bfbb5d6adf0ce6f104445b Mon Sep 17 00:00:00 2001 From: Laurentiu Mihalcea Date: Thu, 21 Dec 2023 15:29:56 +0200 Subject: [PATCH 2059/3723] drivers: dai: sai: Add fix for i.MX93 SAI errata 051421 ERRATA 051421 states that if the SAI is FSYNC/BCLK master, one of the directions is SYNC with the other, and the ASYNC direction has the BYP bit toggled, the SYNC direction's BCLK won't be generated properly. This commit fixes this issue by enabling BCI for the SYNC direction. What this does is it makes the SYNC direction use the BCLK from the ASYNC direction's pad, which, if the BYP bit is toggled, will be the undivided MCLK. Without this fix, the SYNC direction will use the ASYNC direction's BCLK obtained by dividing the MCLK via the following formula: MCLK / ((DIV + 1) * 2). This is wrong because the ASYNC direction will use an undivided MCLK while the SYNC direction will use a divided MCLK. Signed-off-by: Laurentiu Mihalcea --- drivers/dai/nxp/sai/Kconfig.sai | 11 +++++ drivers/dai/nxp/sai/sai.c | 73 +++++++++++++++++++++++++++++++++ 2 files changed, 84 insertions(+) diff --git a/drivers/dai/nxp/sai/Kconfig.sai b/drivers/dai/nxp/sai/Kconfig.sai index e123c955f6b..04c1ff7a430 100644 --- a/drivers/dai/nxp/sai/Kconfig.sai +++ b/drivers/dai/nxp/sai/Kconfig.sai @@ -27,4 +27,15 @@ config SAI_FIFO_WORD_SIZE Use this to set the size (in bytes) of a SAI FIFO word. +config SAI_IMX93_ERRATA_051421 + bool "Set if your SAI IP version is affected by i.MX93's ERRATA 051421" + default n + help + Select this if your SAI ip version is affected by + i.MX93's ERRATA 051421. The errata states that if + the SAI is FSYNC/BCLK master, one of the directions + is SYNC with the other, and the ASYNC direction has + the BYP bit toggled, the SYNC direction's BCLK won't + be generated properly. + endif # DAI_NXP_SAI diff --git a/drivers/dai/nxp/sai/sai.c b/drivers/dai/nxp/sai/sai.c index 6719bd703df..a19bda1218a 100644 --- a/drivers/dai/nxp/sai/sai.c +++ b/drivers/dai/nxp/sai/sai.c @@ -142,6 +142,73 @@ static const struct dai_properties CODE_UNREACHABLE; } +#ifdef CONFIG_SAI_IMX93_ERRATA_051421 +/* notes: + * 1) TX and RX operate in the same mode: master/slave. As such, + * there's no need to check the mode for both directions. + * + * 2) Only one of the directions can operate in SYNC mode at a + * time. + * + * 3) What this piece of code does is it makes the SYNC direction + * use the ASYNC direction's BCLK that comes from its input pad. + * Logically speaking, this would look like: + * + * +--------+ +--------+ + * | TX | | RX | + * | module | | module | + * +--------+ +--------+ + * | ^ | + * | | | + * TX_BCLK | |____________| RX_BCLK + * | | + * V V + * +---------+ +---------+ + * | TX BCLK | | RX BCLK | + * | pad | | pad | + * +---------+ +---------+ + * | | + * | TX_BCLK | RX_BCLK + * V V + * + * Without BCI enabled, the TX module would use an RX_BCLK + * that's divided instead of the one that's obtained from + * bypassing the MCLK (i.e: TX_BCLK would have the value of + * MCLK / ((RX_DIV + 1) * 2)). If BCI is 1, then TX_BCLK will + * be the same as the RX_BCLK that's obtained from bypassing + * the MCLK on RX's side. + * + * 4) The check for BCLK == MCLK is there to see if the ASYNC + * direction will have the BYP bit toggled. + * + * IMPORTANT1: in the above diagram and information, RX is SYNC + * with TX. The same applies if RX is SYNC with TX. Also, this + * applies to i.MX93. For other SoCs, things may be different + * so use this information with caution. + * + * IMPORTANT2: for this to work, you also need to enable the + * pad's input path. For i.MX93, this can be achieved by setting + * the pad's SION bit. + */ +static void sai_config_set_err_051421(I2S_Type *base, + const struct sai_config *cfg, + const struct sai_bespoke_config *bespoke, + sai_transceiver_t *rx_config, + sai_transceiver_t *tx_config) +{ + if (tx_config->masterSlave == kSAI_Master && + bespoke->mclk_rate == bespoke->bclk_rate) { + if (cfg->tx_sync_mode == kSAI_ModeSync) { + base->TCR2 |= I2S_TCR2_BCI(1); + } + + if (cfg->rx_sync_mode == kSAI_ModeSync) { + base->RCR2 |= I2S_RCR2_BCI(1); + } + } +} +#endif /* CONFIG_SAI_IMX93_ERRATA_051421 */ + static int sai_config_set(const struct device *dev, const struct dai_config *cfg, const void *bespoke_data) @@ -341,6 +408,12 @@ static int sai_config_set(const struct device *dev, } #endif /* CONFIG_SAI_HAS_MCLK_CONFIG_OPTION */ +#ifdef CONFIG_SAI_IMX93_ERRATA_051421 + sai_config_set_err_051421(UINT_TO_I2S(data->regmap), + sai_cfg, bespoke, + rx_config, tx_config); +#endif /* CONFIG_SAI_IMX93_ERRATA_051421 */ + /* this is needed so that rates different from FSYNC_RATE * will not be allowed. * From 09e1ed039a9ceb846f8ceb327b736da7afff5527 Mon Sep 17 00:00:00 2001 From: Chaitanya Tata Date: Tue, 26 Dec 2023 21:27:32 +0530 Subject: [PATCH 2060/3723] wifi: Fix duplication Use a common set of events and then add specific ones as per the configuration. Signed-off-by: Chaitanya Tata --- subsys/net/l2/wifi/wifi_shell.c | 20 +++++++++----------- 1 file changed, 9 insertions(+), 11 deletions(-) diff --git a/subsys/net/l2/wifi/wifi_shell.c b/subsys/net/l2/wifi/wifi_shell.c index 74a88103f48..a7df832408c 100644 --- a/subsys/net/l2/wifi/wifi_shell.c +++ b/subsys/net/l2/wifi/wifi_shell.c @@ -30,19 +30,17 @@ LOG_MODULE_REGISTER(net_wifi_shell, LOG_LEVEL_INF); #define WIFI_SHELL_MODULE "wifi" +#define WIFI_SHELL_MGMT_EVENTS_COMMON (NET_EVENT_WIFI_SCAN_DONE |\ + NET_EVENT_WIFI_CONNECT_RESULT |\ + NET_EVENT_WIFI_DISCONNECT_RESULT | \ + NET_EVENT_WIFI_TWT |\ + NET_EVENT_WIFI_RAW_SCAN_RESULT) + #ifdef CONFIG_WIFI_MGMT_RAW_SCAN_RESULTS_ONLY -#define WIFI_SHELL_MGMT_EVENTS (NET_EVENT_WIFI_RAW_SCAN_RESULT | \ - NET_EVENT_WIFI_SCAN_DONE | \ - NET_EVENT_WIFI_CONNECT_RESULT | \ - NET_EVENT_WIFI_DISCONNECT_RESULT | \ - NET_EVENT_WIFI_TWT) +#define WIFI_SHELL_MGMT_EVENTS (WIFI_SHELL_MGMT_EVENTS_COMMON) #else -#define WIFI_SHELL_MGMT_EVENTS (NET_EVENT_WIFI_SCAN_RESULT | \ - NET_EVENT_WIFI_SCAN_DONE | \ - NET_EVENT_WIFI_CONNECT_RESULT | \ - NET_EVENT_WIFI_DISCONNECT_RESULT | \ - NET_EVENT_WIFI_TWT | \ - NET_EVENT_WIFI_RAW_SCAN_RESULT) +#define WIFI_SHELL_MGMT_EVENTS (WIFI_SHELL_MGMT_EVENTS_COMMON |\ + NET_EVENT_WIFI_SCAN_RESULT) #endif /* CONFIG_WIFI_MGMT_RAW_SCAN_RESULTS_ONLY */ static struct { From 2703955aeeed6cbfe3c6f1394e23f2ff23149dd2 Mon Sep 17 00:00:00 2001 From: Chaitanya Tata Date: Mon, 25 Dec 2023 20:09:45 +0530 Subject: [PATCH 2061/3723] wifi: ap: Add status events These events communicate the status of AP mode operations (enable or disable) with few pre-defined enumerations. Signed-off-by: Chaitanya Tata --- include/zephyr/net/wifi_mgmt.h | 47 +++++++++++++++++++++++++++++++++ subsys/net/l2/wifi/wifi_mgmt.c | 24 +++++++++++++++++ subsys/net/l2/wifi/wifi_shell.c | 41 +++++++++++++++++++++++++--- 3 files changed, 108 insertions(+), 4 deletions(-) diff --git a/include/zephyr/net/wifi_mgmt.h b/include/zephyr/net/wifi_mgmt.h index babf67722c1..0897bdd5715 100644 --- a/include/zephyr/net/wifi_mgmt.h +++ b/include/zephyr/net/wifi_mgmt.h @@ -180,6 +180,10 @@ enum net_event_wifi_cmd { NET_EVENT_WIFI_CMD_RAW_SCAN_RESULT, /** Disconnect complete */ NET_EVENT_WIFI_CMD_DISCONNECT_COMPLETE, + /** AP mode enable result */ + NET_EVENT_WIFI_CMD_AP_ENABLE_RESULT, + /** AP mode disable result */ + NET_EVENT_WIFI_CMD_AP_DISABLE_RESULT, }; #define NET_EVENT_WIFI_SCAN_RESULT \ @@ -209,6 +213,12 @@ enum net_event_wifi_cmd { #define NET_EVENT_WIFI_DISCONNECT_COMPLETE \ (_NET_WIFI_EVENT | NET_EVENT_WIFI_CMD_DISCONNECT_COMPLETE) +#define NET_EVENT_WIFI_AP_ENABLE_RESULT \ + (_NET_WIFI_EVENT | NET_EVENT_WIFI_CMD_AP_ENABLE_RESULT) + +#define NET_EVENT_WIFI_AP_DISABLE_RESULT \ + (_NET_WIFI_EVENT | NET_EVENT_WIFI_CMD_AP_DISABLE_RESULT) + /** * @brief Wi-Fi structure to uniquely identify a band-channel pair */ @@ -351,12 +361,35 @@ enum wifi_disconn_reason { WIFI_REASON_DISCONN_INACTIVITY, }; +/** Wi-Fi AP mode result codes. To be overlaid on top of \ref wifi_status + * in the AP mode enable or disable result event for detailed status. + */ +enum wifi_ap_status { + /** AP mode enable or disable successful */ + WIFI_STATUS_AP_SUCCESS = 0, + /** AP mode enable or disable failed - generic failure */ + WIFI_STATUS_AP_FAIL, + /** AP mode enable failed - channel not supported */ + WIFI_STATUS_AP_CHANNEL_NOT_SUPPORTED, + /** AP mode enable failed - channel not allowed */ + WIFI_STATUS_AP_CHANNEL_NOT_ALLOWED, + /** AP mode enable failed - SSID not allowed */ + WIFI_STATUS_AP_SSID_NOT_ALLOWED, + /** AP mode enable failed - authentication type not supported */ + WIFI_STATUS_AP_AUTH_TYPE_NOT_SUPPORTED, + /** AP mode enable failed - operation not supported */ + WIFI_STATUS_AP_OP_NOT_SUPPORTED, + /** AP mode enable failed - operation not permitted */ + WIFI_STATUS_AP_OP_NOT_PERMITTED, +}; + /** Generic Wi-Fi status for commands and events */ struct wifi_status { union { int status; enum wifi_conn_status conn_status; enum wifi_disconn_reason disconn_reason; + enum wifi_ap_status ap_status; }; }; @@ -802,6 +835,20 @@ void wifi_mgmt_raise_raw_scan_result_event(struct net_if *iface, */ void wifi_mgmt_raise_disconnect_complete_event(struct net_if *iface, int status); +/** Wi-Fi management AP mode enable result event + * + * @param iface Network interface + * @param status AP mode enable result status + */ +void wifi_mgmt_raise_ap_enable_result_event(struct net_if *iface, enum wifi_ap_status status); + +/** Wi-Fi management AP mode disable result event + * + * @param iface Network interface + * @param status AP mode disable result status + */ +void wifi_mgmt_raise_ap_disable_result_event(struct net_if *iface, enum wifi_ap_status status); + /** * @} */ diff --git a/subsys/net/l2/wifi/wifi_mgmt.c b/subsys/net/l2/wifi/wifi_mgmt.c index 1a866d4c47c..21a426d794d 100644 --- a/subsys/net/l2/wifi/wifi_mgmt.c +++ b/subsys/net/l2/wifi/wifi_mgmt.c @@ -707,3 +707,27 @@ void wifi_mgmt_raise_disconnect_complete_event(struct net_if *iface, iface, &cnx_status, sizeof(struct wifi_status)); } + +void wifi_mgmt_raise_ap_enable_result_event(struct net_if *iface, + enum wifi_ap_status status) +{ + struct wifi_status cnx_status = { + .status = status, + }; + + net_mgmt_event_notify_with_info(NET_EVENT_WIFI_AP_ENABLE_RESULT, + iface, &cnx_status, + sizeof(enum wifi_ap_status)); +} + +void wifi_mgmt_raise_ap_disable_result_event(struct net_if *iface, + enum wifi_ap_status status) +{ + struct wifi_status cnx_status = { + .status = status, + }; + + net_mgmt_event_notify_with_info(NET_EVENT_WIFI_AP_DISABLE_RESULT, + iface, &cnx_status, + sizeof(enum wifi_ap_status)); +} diff --git a/subsys/net/l2/wifi/wifi_shell.c b/subsys/net/l2/wifi/wifi_shell.c index a7df832408c..cacff802f3e 100644 --- a/subsys/net/l2/wifi/wifi_shell.c +++ b/subsys/net/l2/wifi/wifi_shell.c @@ -34,7 +34,9 @@ LOG_MODULE_REGISTER(net_wifi_shell, LOG_LEVEL_INF); NET_EVENT_WIFI_CONNECT_RESULT |\ NET_EVENT_WIFI_DISCONNECT_RESULT | \ NET_EVENT_WIFI_TWT |\ - NET_EVENT_WIFI_RAW_SCAN_RESULT) + NET_EVENT_WIFI_RAW_SCAN_RESULT |\ + NET_EVENT_WIFI_AP_ENABLE_RESULT |\ + NET_EVENT_WIFI_AP_DISABLE_RESULT) #ifdef CONFIG_WIFI_MGMT_RAW_SCAN_RESULTS_ONLY #define WIFI_SHELL_MGMT_EVENTS (WIFI_SHELL_MGMT_EVENTS_COMMON) @@ -301,6 +303,32 @@ static void handle_wifi_twt_event(struct net_mgmt_event_callback *cb) } } +static void handle_wifi_ap_enable_result(struct net_mgmt_event_callback *cb) +{ + const struct wifi_status *status = + (const struct wifi_status *)cb->info; + + if (status->status) { + print(context.sh, SHELL_WARNING, + "AP enable request failed (%d)\n", status->status); + } else { + print(context.sh, SHELL_NORMAL, "AP enabled\n"); + } +} + +static void handle_wifi_ap_disable_result(struct net_mgmt_event_callback *cb) +{ + const struct wifi_status *status = + (const struct wifi_status *)cb->info; + + if (status->status) { + print(context.sh, SHELL_WARNING, + "AP disable request failed (%d)\n", status->status); + } else { + print(context.sh, SHELL_NORMAL, "AP disabled\n"); + } +} + static void wifi_mgmt_event_handler(struct net_mgmt_event_callback *cb, uint32_t mgmt_event, struct net_if *iface) { @@ -325,6 +353,12 @@ static void wifi_mgmt_event_handler(struct net_mgmt_event_callback *cb, handle_wifi_raw_scan_result(cb); break; #endif /* CONFIG_WIFI_MGMT_RAW_SCAN_RESULTS */ + case NET_EVENT_WIFI_AP_ENABLE_RESULT: + handle_wifi_ap_enable_result(cb); + break; + case NET_EVENT_WIFI_AP_DISABLE_RESULT: + handle_wifi_ap_disable_result(cb); + break; default: break; } @@ -1113,7 +1147,7 @@ static int cmd_wifi_ap_enable(const struct shell *sh, size_t argc, return -ENOEXEC; } - shell_fprintf(sh, SHELL_NORMAL, "AP mode enabled\n"); + shell_fprintf(sh, SHELL_NORMAL, "AP mode enable requested\n"); return 0; } @@ -1130,8 +1164,7 @@ static int cmd_wifi_ap_disable(const struct shell *sh, size_t argc, return -ENOEXEC; } - shell_fprintf(sh, SHELL_NORMAL, "AP mode disabled\n"); - + shell_fprintf(sh, SHELL_NORMAL, "AP mode disable requested\n"); return 0; } From 725c13bafb06b67c194b51a610e3eca7eaa631c3 Mon Sep 17 00:00:00 2001 From: Chaitanya Tata Date: Tue, 26 Dec 2023 21:17:51 +0530 Subject: [PATCH 2062/3723] wifi: ap: Add client side events These are helpful to track clients being added and deleted. Applications can actions based on these events. Signed-off-by: Chaitanya Tata --- include/zephyr/net/wifi_mgmt.h | 38 +++++++++++++++++++++++++++++++++ subsys/net/l2/wifi/wifi_mgmt.c | 16 ++++++++++++++ subsys/net/l2/wifi/wifi_shell.c | 32 ++++++++++++++++++++++++++- 3 files changed, 85 insertions(+), 1 deletion(-) diff --git a/include/zephyr/net/wifi_mgmt.h b/include/zephyr/net/wifi_mgmt.h index 0897bdd5715..78800f451e7 100644 --- a/include/zephyr/net/wifi_mgmt.h +++ b/include/zephyr/net/wifi_mgmt.h @@ -184,6 +184,10 @@ enum net_event_wifi_cmd { NET_EVENT_WIFI_CMD_AP_ENABLE_RESULT, /** AP mode disable result */ NET_EVENT_WIFI_CMD_AP_DISABLE_RESULT, + /** STA connected to AP */ + NET_EVENT_WIFI_CMD_AP_STA_CONNECTED, + /** STA disconnected from AP */ + NET_EVENT_WIFI_CMD_AP_STA_DISCONNECTED, }; #define NET_EVENT_WIFI_SCAN_RESULT \ @@ -219,6 +223,12 @@ enum net_event_wifi_cmd { #define NET_EVENT_WIFI_AP_DISABLE_RESULT \ (_NET_WIFI_EVENT | NET_EVENT_WIFI_CMD_AP_DISABLE_RESULT) +#define NET_EVENT_WIFI_AP_STA_CONNECTED \ + (_NET_WIFI_EVENT | NET_EVENT_WIFI_CMD_AP_STA_CONNECTED) + +#define NET_EVENT_WIFI_AP_STA_DISCONNECTED \ + (_NET_WIFI_EVENT | NET_EVENT_WIFI_CMD_AP_STA_DISCONNECTED) + /** * @brief Wi-Fi structure to uniquely identify a band-channel pair */ @@ -568,6 +578,18 @@ struct wifi_raw_scan_result { }; #endif /* CONFIG_WIFI_MGMT_RAW_SCAN_RESULTS */ +/** AP mode - connected STA details */ +struct wifi_ap_sta_info { + /** Link mode, see enum wifi_link_mode */ + enum wifi_link_mode link_mode; + /** MAC address */ + uint8_t mac[WIFI_MAC_ADDR_LEN]; + /** MAC address length */ + uint8_t mac_length; + /** is TWT capable ? */ + bool twt_capable; +}; + /* for use in max info size calculations */ union wifi_mgmt_events { struct wifi_scan_result scan_result; @@ -577,6 +599,7 @@ union wifi_mgmt_events { struct wifi_raw_scan_result raw_scan_result; #endif /* CONFIG_WIFI_MGMT_RAW_SCAN_RESULTS */ struct wifi_twt_params twt_params; + struct wifi_ap_sta_info ap_sta_info; }; /** Wi-Fi mode setup */ @@ -849,6 +872,21 @@ void wifi_mgmt_raise_ap_enable_result_event(struct net_if *iface, enum wifi_ap_s */ void wifi_mgmt_raise_ap_disable_result_event(struct net_if *iface, enum wifi_ap_status status); +/** Wi-Fi management AP mode STA connected event + * + * @param iface Network interface + * @param sta_info STA information + */ +void wifi_mgmt_raise_ap_sta_connected_event(struct net_if *iface, + struct wifi_ap_sta_info *sta_info); + +/** Wi-Fi management AP mode STA disconnected event + * @param iface Network interface + * @param sta_info STA information + */ +void wifi_mgmt_raise_ap_sta_disconnected_event(struct net_if *iface, + struct wifi_ap_sta_info *sta_info); + /** * @} */ diff --git a/subsys/net/l2/wifi/wifi_mgmt.c b/subsys/net/l2/wifi/wifi_mgmt.c index 21a426d794d..6e0cb761dbf 100644 --- a/subsys/net/l2/wifi/wifi_mgmt.c +++ b/subsys/net/l2/wifi/wifi_mgmt.c @@ -731,3 +731,19 @@ void wifi_mgmt_raise_ap_disable_result_event(struct net_if *iface, iface, &cnx_status, sizeof(enum wifi_ap_status)); } + +void wifi_mgmt_raise_ap_sta_connected_event(struct net_if *iface, + struct wifi_ap_sta_info *sta_info) +{ + net_mgmt_event_notify_with_info(NET_EVENT_WIFI_AP_STA_CONNECTED, + iface, sta_info, + sizeof(struct wifi_ap_sta_info)); +} + +void wifi_mgmt_raise_ap_sta_disconnected_event(struct net_if *iface, + struct wifi_ap_sta_info *sta_info) +{ + net_mgmt_event_notify_with_info(NET_EVENT_WIFI_AP_STA_DISCONNECTED, + iface, sta_info, + sizeof(struct wifi_ap_sta_info)); +} diff --git a/subsys/net/l2/wifi/wifi_shell.c b/subsys/net/l2/wifi/wifi_shell.c index cacff802f3e..a559471d843 100644 --- a/subsys/net/l2/wifi/wifi_shell.c +++ b/subsys/net/l2/wifi/wifi_shell.c @@ -36,7 +36,9 @@ LOG_MODULE_REGISTER(net_wifi_shell, LOG_LEVEL_INF); NET_EVENT_WIFI_TWT |\ NET_EVENT_WIFI_RAW_SCAN_RESULT |\ NET_EVENT_WIFI_AP_ENABLE_RESULT |\ - NET_EVENT_WIFI_AP_DISABLE_RESULT) + NET_EVENT_WIFI_AP_DISABLE_RESULT |\ + NET_EVENT_WIFI_AP_STA_CONNECTED |\ + NET_EVENT_WIFI_AP_STA_DISCONNECTED) #ifdef CONFIG_WIFI_MGMT_RAW_SCAN_RESULTS_ONLY #define WIFI_SHELL_MGMT_EVENTS (WIFI_SHELL_MGMT_EVENTS_COMMON) @@ -329,6 +331,28 @@ static void handle_wifi_ap_disable_result(struct net_mgmt_event_callback *cb) } } +static void handle_wifi_ap_sta_connected(struct net_mgmt_event_callback *cb) +{ + const struct wifi_ap_sta_info *sta_info = + (const struct wifi_ap_sta_info *)cb->info; + uint8_t mac_string_buf[sizeof("xx:xx:xx:xx:xx:xx")]; + + print(context.sh, SHELL_NORMAL, "Station connected: %s\n", + net_sprint_ll_addr_buf(sta_info->mac, WIFI_MAC_ADDR_LEN, + mac_string_buf, sizeof(mac_string_buf))); +} + +static void handle_wifi_ap_sta_disconnected(struct net_mgmt_event_callback *cb) +{ + const struct wifi_ap_sta_info *sta_info = + (const struct wifi_ap_sta_info *)cb->info; + uint8_t mac_string_buf[sizeof("xx:xx:xx:xx:xx:xx")]; + + print(context.sh, SHELL_NORMAL, "Station disconnected: %s\n", + net_sprint_ll_addr_buf(sta_info->mac, WIFI_MAC_ADDR_LEN, + mac_string_buf, sizeof(mac_string_buf))); +} + static void wifi_mgmt_event_handler(struct net_mgmt_event_callback *cb, uint32_t mgmt_event, struct net_if *iface) { @@ -359,6 +383,12 @@ static void wifi_mgmt_event_handler(struct net_mgmt_event_callback *cb, case NET_EVENT_WIFI_AP_DISABLE_RESULT: handle_wifi_ap_disable_result(cb); break; + case NET_EVENT_WIFI_AP_STA_CONNECTED: + handle_wifi_ap_sta_connected(cb); + break; + case NET_EVENT_WIFI_AP_STA_DISCONNECTED: + handle_wifi_ap_sta_disconnected(cb); + break; default: break; } From 918e08fda8f3a6ba894bbc7ad21eb35b797b4cb4 Mon Sep 17 00:00:00 2001 From: Chaitanya Tata Date: Wed, 27 Dec 2023 00:06:45 +0530 Subject: [PATCH 2063/3723] wifi: shell: Add a shell command to list stations In AP mode maintain the database of connected stations based on the Wi-Fi management events and dump the list. Signed-off-by: Chaitanya Tata --- subsys/net/l2/wifi/Kconfig | 8 +++ subsys/net/l2/wifi/wifi_shell.c | 90 +++++++++++++++++++++++++++++++++ 2 files changed, 98 insertions(+) diff --git a/subsys/net/l2/wifi/Kconfig b/subsys/net/l2/wifi/Kconfig index 134448aa57f..2816be56d74 100644 --- a/subsys/net/l2/wifi/Kconfig +++ b/subsys/net/l2/wifi/Kconfig @@ -64,6 +64,14 @@ config WIFI_MGMT_SCAN_CHAN_MAX_MANUAL There are approximately 100 channels allocated across the three supported bands. The default of 3 allows the 3 most common channels (2.4GHz: 1, 6, 11) to be specified. +config WIFI_SHELL_MAX_AP_STA + int "Maximum number of APs and STAs that can be managed in Wi-Fi shell" + range 1 5 + default 1 + help + This option defines the maximum number of APs and STAs that can be managed + in Wi-Fi shell. + config WIFI_NM bool "Wi-Fi Network manager support" help diff --git a/subsys/net/l2/wifi/wifi_shell.c b/subsys/net/l2/wifi/wifi_shell.c index a559471d843..2654f0337bf 100644 --- a/subsys/net/l2/wifi/wifi_shell.c +++ b/subsys/net/l2/wifi/wifi_shell.c @@ -25,6 +25,7 @@ LOG_MODULE_REGISTER(net_wifi_shell, LOG_LEVEL_INF); #include #include #include +#include #include "net_private.h" @@ -65,6 +66,13 @@ static uint32_t scan_result; static struct net_mgmt_event_callback wifi_shell_mgmt_cb; +static K_MUTEX_DEFINE(wifi_ap_sta_list_lock); +struct wifi_ap_sta_node { + bool valid; + struct wifi_ap_sta_info sta_info; +}; +static struct wifi_ap_sta_node sta_list[CONFIG_WIFI_SHELL_MAX_AP_STA]; + #define print(sh, level, fmt, ...) \ do { \ if (sh) { \ @@ -329,6 +337,10 @@ static void handle_wifi_ap_disable_result(struct net_mgmt_event_callback *cb) } else { print(context.sh, SHELL_NORMAL, "AP disabled\n"); } + + k_mutex_lock(&wifi_ap_sta_list_lock, K_FOREVER); + memset(&sta_list, 0, sizeof(sta_list)); + k_mutex_unlock(&wifi_ap_sta_list_lock); } static void handle_wifi_ap_sta_connected(struct net_mgmt_event_callback *cb) @@ -336,10 +348,25 @@ static void handle_wifi_ap_sta_connected(struct net_mgmt_event_callback *cb) const struct wifi_ap_sta_info *sta_info = (const struct wifi_ap_sta_info *)cb->info; uint8_t mac_string_buf[sizeof("xx:xx:xx:xx:xx:xx")]; + int i; print(context.sh, SHELL_NORMAL, "Station connected: %s\n", net_sprint_ll_addr_buf(sta_info->mac, WIFI_MAC_ADDR_LEN, mac_string_buf, sizeof(mac_string_buf))); + + k_mutex_lock(&wifi_ap_sta_list_lock, K_FOREVER); + for (i = 0; i < CONFIG_WIFI_SHELL_MAX_AP_STA; i++) { + if (!sta_list[i].valid) { + sta_list[i].sta_info = *sta_info; + sta_list[i].valid = true; + break; + } + } + if (i == CONFIG_WIFI_SHELL_MAX_AP_STA) { + print(context.sh, SHELL_WARNING, "No space to store station info: " + "Increase CONFIG_WIFI_SHELL_MAX_AP_STA\n"); + } + k_mutex_unlock(&wifi_ap_sta_list_lock); } static void handle_wifi_ap_sta_disconnected(struct net_mgmt_event_callback *cb) @@ -351,6 +378,20 @@ static void handle_wifi_ap_sta_disconnected(struct net_mgmt_event_callback *cb) print(context.sh, SHELL_NORMAL, "Station disconnected: %s\n", net_sprint_ll_addr_buf(sta_info->mac, WIFI_MAC_ADDR_LEN, mac_string_buf, sizeof(mac_string_buf))); + + k_mutex_lock(&wifi_ap_sta_list_lock, K_FOREVER); + for (int i = 0; i < CONFIG_WIFI_SHELL_MAX_AP_STA; i++) { + if (!sta_list[i].valid) { + continue; + } + + if (!memcmp(sta_list[i].sta_info.mac, sta_info->mac, + WIFI_MAC_ADDR_LEN)) { + sta_list[i].valid = false; + break; + } + } + k_mutex_unlock(&wifi_ap_sta_list_lock); } static void wifi_mgmt_event_handler(struct net_mgmt_event_callback *cb, @@ -1170,6 +1211,8 @@ static int cmd_wifi_ap_enable(const struct shell *sh, size_t argc, context.sh = sh; + k_mutex_init(&wifi_ap_sta_list_lock); + ret = net_mgmt(NET_REQUEST_WIFI_AP_ENABLE, iface, &cnx_params, sizeof(struct wifi_connect_req_params)); if (ret) { @@ -1198,6 +1241,49 @@ static int cmd_wifi_ap_disable(const struct shell *sh, size_t argc, return 0; } +static int cmd_wifi_ap_stations(const struct shell *sh, size_t argc, + char *argv[]) +{ + size_t id = 1; + + ARG_UNUSED(argv); + ARG_UNUSED(argc); + + shell_fprintf(sh, SHELL_NORMAL, "AP stations:\n"); + shell_fprintf(sh, SHELL_NORMAL, "============\n"); + + k_mutex_lock(&wifi_ap_sta_list_lock, K_FOREVER); + for (int i = 0; i < CONFIG_WIFI_SHELL_MAX_AP_STA; i++) { + struct wifi_ap_sta_info *sta; + uint8_t mac_string_buf[sizeof("xx:xx:xx:xx:xx:xx")]; + + if (!sta_list[i].valid) { + continue; + } + + sta = &sta_list[i].sta_info; + + shell_fprintf(sh, SHELL_NORMAL, "Station %zu:\n", id++); + shell_fprintf(sh, SHELL_NORMAL, "==========\n"); + shell_fprintf(sh, SHELL_NORMAL, "MAC: %s\n", + net_sprint_ll_addr_buf(sta->mac, + WIFI_MAC_ADDR_LEN, + mac_string_buf, + sizeof(mac_string_buf))); + shell_fprintf(sh, SHELL_NORMAL, "Link mode: %s\n", + wifi_link_mode_txt(sta->link_mode)); + shell_fprintf(sh, SHELL_NORMAL, "TWT: %s\n", + sta->twt_capable ? "Supported" : "Not supported"); + } + + if (id == 1) { + shell_fprintf(sh, SHELL_NORMAL, "No stations connected\n"); + } + k_mutex_unlock(&wifi_ap_sta_list_lock); + + return 0; +} + static int cmd_wifi_reg_domain(const struct shell *sh, size_t argc, char *argv[]) @@ -1676,6 +1762,10 @@ SHELL_STATIC_SUBCMD_SET_CREATE(wifi_cmd_ap, ": 0:Disable, 1:Optional, 2:Required.\n", cmd_wifi_ap_enable, 2, 4), + SHELL_CMD_ARG(stations, NULL, + "List stations connected to the AP", + cmd_wifi_ap_stations, + 1, 0), SHELL_SUBCMD_SET_END ); From aac9b661858d45a7f84488e993404d4afd857131 Mon Sep 17 00:00:00 2001 From: Bryan Zhu Date: Tue, 9 Jan 2024 08:48:21 +0800 Subject: [PATCH 2064/3723] west.yml: hal_ambiq: Update stimer HAL Update stimer HAL from latested AmbiqSuite. Signed-off-by: Bryan Zhu --- west.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/west.yml b/west.yml index 21fbd973bb1..613e06b27bb 100644 --- a/west.yml +++ b/west.yml @@ -142,7 +142,7 @@ manifest: groups: - hal - name: hal_ambiq - revision: 323048f916faa84cebcf6dfd73e606d8cf64107a + revision: ff4ca358d730536addf336c40c3faa4ebf1df00a path: modules/hal/ambiq groups: - hal From 0b74aa08316959ed82683a05aebc6de82ace9248 Mon Sep 17 00:00:00 2001 From: Jacob Siverskog Date: Thu, 4 Jan 2024 17:29:22 +0100 Subject: [PATCH 2065/3723] manifest: bump hal_nxp revision this revision contains an usb fix that allows tests/subsys/usb/device/usb.device to pass on lpcxpresso55s69_cpu0. see https://github.com/zephyrproject-rtos/hal_nxp/pull/315 for more information. Signed-off-by: Jacob Siverskog --- west.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/west.yml b/west.yml index 613e06b27bb..e8feaa2938a 100644 --- a/west.yml +++ b/west.yml @@ -193,7 +193,7 @@ manifest: groups: - hal - name: hal_nxp - revision: 12970d629fc900010dab5cf250be70287bf9e443 + revision: 9b2693c7659f37f84bcf2604995c88f7fa5206be path: modules/hal/nxp groups: - hal From a897b8a09c88c735db664d697a593e6adaca7ae2 Mon Sep 17 00:00:00 2001 From: Jun Lin Date: Mon, 8 Jan 2024 10:07:01 +0800 Subject: [PATCH 2066/3723] drivers: spi: npcx: add driver for the SPI peripheral This commit adds the driver support for the NPCX SPI peripheral. Signed-off-by: Jun Lin --- drivers/spi/CMakeLists.txt | 1 + drivers/spi/Kconfig | 2 + drivers/spi/Kconfig.npcx | 17 + drivers/spi/spi_npcx_spip.c | 446 ++++++++++++++++++ dts/arm/nuvoton/npcx/npcx.dtsi | 11 + dts/arm/nuvoton/npcx/npcx4/npcx4-pinctrl.dtsi | 8 + dts/arm/nuvoton/npcx/npcx7/npcx7-pinctrl.dtsi | 8 + dts/arm/nuvoton/npcx/npcx9/npcx9-pinctrl.dtsi | 8 + dts/bindings/spi/nuvoton,npcx-spip.yaml | 12 + soc/arm/nuvoton_npcx/common/reg/reg_def.h | 21 + soc/arm/nuvoton_npcx/common/registers.c | 4 + 11 files changed, 538 insertions(+) create mode 100644 drivers/spi/Kconfig.npcx create mode 100644 drivers/spi/spi_npcx_spip.c create mode 100644 dts/bindings/spi/nuvoton,npcx-spip.yaml diff --git a/drivers/spi/CMakeLists.txt b/drivers/spi/CMakeLists.txt index 956b6d3397a..eccdc7325de 100644 --- a/drivers/spi/CMakeLists.txt +++ b/drivers/spi/CMakeLists.txt @@ -50,3 +50,4 @@ zephyr_library_sources_ifdef(CONFIG_SPI_ASYNC spi_signal.c) zephyr_library_sources_ifdef(CONFIG_USERSPACE spi_handlers.c) zephyr_library_sources_ifdef(CONFIG_SPI_INFINEON_CAT1 spi_ifx_cat1.c) zephyr_library_sources_ifdef(CONFIG_SPI_SEDI spi_sedi.c) +zephyr_library_sources_ifdef(CONFIG_SPI_NPCX_SPIP spi_npcx_spip.c) diff --git a/drivers/spi/Kconfig b/drivers/spi/Kconfig index 24982cae90e..8618b284b44 100644 --- a/drivers/spi/Kconfig +++ b/drivers/spi/Kconfig @@ -137,4 +137,6 @@ source "drivers/spi/Kconfig.ifx_cat1" source "drivers/spi/Kconfig.sedi" +source "drivers/spi/Kconfig.npcx" + endif # SPI diff --git a/drivers/spi/Kconfig.npcx b/drivers/spi/Kconfig.npcx new file mode 100644 index 00000000000..196e85cf02d --- /dev/null +++ b/drivers/spi/Kconfig.npcx @@ -0,0 +1,17 @@ +# Nuvoton NPCX SPI Driver configuration options + +# Copyright (c) 2024 Nuvoton Technology Corporation. +# SPDX-License-Identifier: Apache-2.0 + +menuconfig SPI_NPCX_SPIP + bool "Nuvoton NPCX embedded controller (EC) SPI driver" + default y + depends on DT_HAS_NUVOTON_NPCX_SPIP_ENABLED + help + Enable the SPI peripherals on NPCX MCU. + +config SPI_NPCX_SPIP_INTERRUPT + bool "NPCX SPIP Interrupt Support" + depends on SPI_NPCX_SPIP + help + Enable Interrupt support for the SPI Driver of NPCX chip. diff --git a/drivers/spi/spi_npcx_spip.c b/drivers/spi/spi_npcx_spip.c new file mode 100644 index 00000000000..f82d090d693 --- /dev/null +++ b/drivers/spi/spi_npcx_spip.c @@ -0,0 +1,446 @@ +/* + * Copyright (c) 2024 Nuvoton Technology Corporation. + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#define DT_DRV_COMPAT nuvoton_npcx_spip + +#include +#include +#include +#include + +#include +LOG_MODULE_REGISTER(spi_npcx_spip, CONFIG_SPI_LOG_LEVEL); + +#include "spi_context.h" + +/* Transfer this NOP value when tx buf is null */ +#define SPI_NPCX_SPIP_TX_NOP 0x00 +#define SPI_NPCX_SPIP_WAIT_STATUS_TIMEOUT_US 1000 + +/* The max allowed prescaler divider */ +#define SPI_NPCX_MAX_PRESCALER_DIV INT8_MAX + +struct spi_npcx_spip_data { + struct spi_context ctx; + uint32_t src_clock_freq; + uint8_t bytes_per_frame; +}; + +struct spi_npcx_spip_cfg { + struct spip_reg *reg_base; + struct npcx_clk_cfg clk_cfg; +#ifdef CONFIG_SPI_NPCX_SPIP_INTERRUPT + /* routine for configuring SPIP ISR */ + void (*irq_cfg_func)(const struct device *dev); +#endif + const struct pinctrl_dev_config *pcfg; +}; + +static int spi_npcx_spip_configure(const struct device *dev, const struct spi_config *spi_cfg) +{ + uint8_t prescaler_divider; + const struct spi_npcx_spip_cfg *const config = dev->config; + struct spi_npcx_spip_data *const data = dev->data; + struct spip_reg *const reg_base = config->reg_base; + spi_operation_t operation = spi_cfg->operation; + uint8_t frame_size; + + if (spi_context_configured(&data->ctx, spi_cfg)) { + /* This configuration is already in use */ + return 0; + } + + if (operation & SPI_HALF_DUPLEX) { + LOG_ERR("Half duplex mode is not supported"); + return -ENOTSUP; + } + + if (SPI_OP_MODE_GET(operation) != SPI_OP_MODE_MASTER) { + LOG_ERR("Only SPI controller mode is supported"); + return -ENOTSUP; + } + + if (operation & SPI_MODE_LOOP) { + LOG_ERR("Loopback mode is not supported"); + return -ENOTSUP; + } + + /* + * If the GPIO CS configuration is not present, return error because the hardware CS is + * not supported. + */ + if (!spi_cs_is_gpio(spi_cfg)) { + LOG_ERR("Only GPIO CS is supported"); + return -ENOTSUP; + } + + /* Get the frame length */ + frame_size = SPI_WORD_SIZE_GET(operation); + if (frame_size == 8) { + data->bytes_per_frame = 1; + reg_base->SPIP_CTL1 &= ~BIT(NPCX_SPIP_CTL1_MOD); + } else if (frame_size == 16) { + reg_base->SPIP_CTL1 |= BIT(NPCX_SPIP_CTL1_MOD); + data->bytes_per_frame = 2; + } else { + LOG_ERR("Only support word sizes either 8 or 16 bits"); + return -ENOTSUP; + } + + if (IS_ENABLED(CONFIG_SPI_EXTENDED_MODES) && + (operation & SPI_LINES_MASK) != SPI_LINES_SINGLE) { + LOG_ERR("Only single line mode is supported"); + return -ENOTSUP; + } + + /* Set the endianness */ + if (operation & SPI_TRANSFER_LSB) { + LOG_ERR("Shift out with LSB is not supported"); + return -ENOTSUP; + } + + /* + * Set CPOL and CPHA. + * The following is how to map npcx spip control register to CPOL and CPHA + * CPOL CPHA | SCIDL SCM + * ----------------------------- + * 0 0 | 0 0 + * 0 1 | 0 1 + * 1 0 | 1 1 + * 1 1 | 1 0 + */ + if (operation & SPI_MODE_CPOL) { + reg_base->SPIP_CTL1 |= BIT(NPCX_SPIP_CTL1_SCIDL); + } else { + reg_base->SPIP_CTL1 &= ~BIT(NPCX_SPIP_CTL1_SCIDL); + } + if (((operation & SPI_MODE_CPOL) == SPI_MODE_CPOL) != + ((operation & SPI_MODE_CPHA) == SPI_MODE_CPHA)) { + reg_base->SPIP_CTL1 |= BIT(NPCX_SPIP_CTL1_SCM); + } else { + reg_base->SPIP_CTL1 &= ~BIT(NPCX_SPIP_CTL1_SCM); + } + + /* Set the SPI frequency */ + prescaler_divider = data->src_clock_freq / 2 / spi_cfg->frequency; + if (prescaler_divider >= 1) { + prescaler_divider -= 1; + } + if (prescaler_divider >= SPI_NPCX_MAX_PRESCALER_DIV) { + LOG_ERR("SPI divider %d exceeds the max allowed value %d.", prescaler_divider, + SPI_NPCX_MAX_PRESCALER_DIV); + return -ENOTSUP; + } + SET_FIELD(reg_base->SPIP_CTL1, NPCX_SPIP_CTL1_SCDV, prescaler_divider); + + data->ctx.config = spi_cfg; + + return 0; +} + +static void spi_npcx_spip_process_tx_buf(struct spi_npcx_spip_data *const data, uint16_t *tx_frame) +{ + /* Get the tx_frame from tx_buf only when tx_buf != NULL */ + if (spi_context_tx_buf_on(&data->ctx)) { + if (data->bytes_per_frame == 1) { + *tx_frame = UNALIGNED_GET((uint8_t *)(data->ctx.tx_buf)); + } else { + *tx_frame = UNALIGNED_GET((uint16_t *)(data->ctx.tx_buf)); + } + } + /* + * The update is ignored if TX is off (tx_len == 0). + * Note: if tx_buf == NULL && tx_len != 0, the update still counts. + */ + spi_context_update_tx(&data->ctx, data->bytes_per_frame, 1); +} + +static void spi_npcx_spip_process_rx_buf(struct spi_npcx_spip_data *const data, uint16_t rx_frame) +{ + if (spi_context_rx_buf_on(&data->ctx)) { + if (data->bytes_per_frame == 1) { + UNALIGNED_PUT(rx_frame, (uint8_t *)data->ctx.rx_buf); + } else { + UNALIGNED_PUT(rx_frame, (uint16_t *)data->ctx.rx_buf); + } + } + spi_context_update_rx(&data->ctx, data->bytes_per_frame, 1); +} + +#ifndef CONFIG_SPI_NPCX_SPIP_INTERRUPT +static int spi_npcx_spip_xfer_frame(const struct device *dev) +{ + const struct spi_npcx_spip_cfg *const config = dev->config; + struct spip_reg *const reg_base = config->reg_base; + struct spi_npcx_spip_data *const data = dev->data; + uint16_t tx_frame = SPI_NPCX_SPIP_TX_NOP; + uint16_t rx_frame; + + spi_npcx_spip_process_tx_buf(data, &tx_frame); + + if (WAIT_FOR(!IS_BIT_SET(reg_base->SPIP_STAT, NPCX_SPIP_STAT_BSY), + SPI_NPCX_SPIP_WAIT_STATUS_TIMEOUT_US, NULL) == false) { + LOG_ERR("Check Status BSY Timeout"); + return -ETIMEDOUT; + } + + reg_base->SPIP_DATA = tx_frame; + + if (WAIT_FOR(IS_BIT_SET(reg_base->SPIP_STAT, NPCX_SPIP_STAT_RBF), + SPI_NPCX_SPIP_WAIT_STATUS_TIMEOUT_US, NULL) == false) { + LOG_ERR("Check Status RBF Timeout"); + return -ETIMEDOUT; + } + + rx_frame = reg_base->SPIP_DATA; + spi_npcx_spip_process_rx_buf(data, rx_frame); + + return 0; +} +#endif + +static bool spi_npcx_spip_transfer_ongoing(struct spi_npcx_spip_data *data) +{ + return spi_context_tx_on(&data->ctx) || spi_context_rx_on(&data->ctx); +} + +#ifdef CONFIG_SPI_NPCX_SPIP_INTERRUPT +static void spi_npcx_spip_isr(const struct device *dev) +{ + const struct spi_npcx_spip_cfg *const config = dev->config; + struct spip_reg *const reg_base = config->reg_base; + struct spi_npcx_spip_data *const data = dev->data; + struct spi_context *ctx = &data->ctx; + uint16_t tx_frame = SPI_NPCX_SPIP_TX_NOP; + uint16_t rx_frame; + uint8_t status; + + status = reg_base->SPIP_STAT; + + if (!IS_BIT_SET(status, NPCX_SPIP_STAT_BSY) && !IS_BIT_SET(status, NPCX_SPIP_STAT_RBF)) { + reg_base->SPIP_CTL1 &= ~BIT(NPCX_SPIP_CTL1_EIW); + + spi_npcx_spip_process_tx_buf(data, &tx_frame); + reg_base->SPIP_DATA = tx_frame; + } else if (IS_BIT_SET(status, NPCX_SPIP_STAT_RBF)) { + rx_frame = reg_base->SPIP_DATA; + + spi_npcx_spip_process_rx_buf(data, rx_frame); + + if (!spi_npcx_spip_transfer_ongoing(data)) { + reg_base->SPIP_CTL1 &= ~BIT(NPCX_SPIP_CTL1_EIR); + /* + * The CS might not de-assert if SPI_HOLD_ON_CS is configured. + * In this case, CS de-assertion reles on the caller to explicitly call + * spi_release() API. + */ + spi_context_cs_control(ctx, false); + + spi_context_complete(ctx, dev, 0); + + } else { + spi_npcx_spip_process_tx_buf(data, &tx_frame); + reg_base->SPIP_DATA = tx_frame; + } + } +} +#endif + +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) +{ + const struct spi_npcx_spip_cfg *const config = dev->config; + struct spip_reg *const reg_base = config->reg_base; + struct spi_npcx_spip_data *const data = dev->data; + struct spi_context *ctx = &data->ctx; + int rc; + + if (!tx_bufs && !rx_bufs) { + return 0; + } + +#ifndef CONFIG_SPI_NPCX_SPIP_INTERRUPT + if (asynchronous) { + return -ENOTSUP; + } +#endif + + /* Lock the SPI Context */ + spi_context_lock(ctx, asynchronous, cb, userdata, spi_cfg); + + rc = spi_npcx_spip_configure(dev, spi_cfg); + if (rc < 0) { + spi_context_release(ctx, rc); + return rc; + } + + spi_context_buffers_setup(ctx, tx_bufs, rx_bufs, data->bytes_per_frame); + if (!spi_npcx_spip_transfer_ongoing(data)) { + spi_context_release(ctx, 0); + return 0; + } + + /* Enable SPIP module */ + reg_base->SPIP_CTL1 |= BIT(NPCX_SPIP_CTL1_SPIEN); + + /* Cleaning junk data in the buffer */ + while (IS_BIT_SET(reg_base->SPIP_STAT, NPCX_SPIP_STAT_RBF)) { + uint8_t unused __attribute__((unused)); + + unused = reg_base->SPIP_DATA; + } + + /* Assert the CS line */ + spi_context_cs_control(ctx, true); + +#ifdef CONFIG_SPI_NPCX_SPIP_INTERRUPT + reg_base->SPIP_CTL1 |= BIT(NPCX_SPIP_CTL1_EIR) | BIT(NPCX_SPIP_CTL1_EIW); + rc = spi_context_wait_for_completion(&data->ctx); +#else + do { + rc = spi_npcx_spip_xfer_frame(dev); + if (rc < 0) { + break; + } + } while (spi_npcx_spip_transfer_ongoing(data)); + + /* + * The CS might not de-assert if SPI_HOLD_ON_CS is configured. + * In this case, CS de-assertion reles on the caller to explicitly call spi_release() API. + */ + spi_context_cs_control(ctx, false); + +#endif + spi_context_release(ctx, rc); + + return rc; +} + +static int spi_npcx_spip_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) +{ + return transceive(dev, spi_cfg, tx_bufs, rx_bufs, false, NULL, NULL); +} + +#ifdef CONFIG_SPI_ASYNC +static int spi_npcx_spip_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 + +static int spi_npcx_spip_release(const struct device *dev, const struct spi_config *spi_cfg) +{ + struct spi_npcx_spip_data *const data = dev->data; + struct spi_context *ctx = &data->ctx; + + if (!spi_context_configured(ctx, spi_cfg)) { + return -EINVAL; + } + + spi_context_unlock_unconditionally(ctx); + + return 0; +} + +static int spi_npcx_spip_init(const struct device *dev) +{ + int ret; + struct spi_npcx_spip_data *const data = dev->data; + const struct spi_npcx_spip_cfg *const config = dev->config; + struct spip_reg *const reg_base = config->reg_base; + const struct device *const clk_dev = DEVICE_DT_GET(NPCX_CLK_CTRL_NODE); + + if (!device_is_ready(clk_dev)) { + LOG_ERR("clock control device not ready"); + return -ENODEV; + } + + ret = clock_control_on(clk_dev, (clock_control_subsys_t)&config->clk_cfg); + if (ret < 0) { + LOG_ERR("Turn on SPIP clock fail %d", ret); + return ret; + } + + ret = clock_control_get_rate(clk_dev, (clock_control_subsys_t)&config->clk_cfg, + &data->src_clock_freq); + if (ret < 0) { + LOG_ERR("Get SPIP clock source rate error %d", ret); + return ret; + } + + ret = spi_context_cs_configure_all(&data->ctx); + if (ret < 0) { + return ret; + } + + ret = pinctrl_apply_state(config->pcfg, PINCTRL_STATE_DEFAULT); + if (ret < 0) { + return ret; + } + + /* Make sure the context is unlocked */ + spi_context_unlock_unconditionally(&data->ctx); + +#ifdef CONFIG_SPI_NPCX_SPIP_INTERRUPT + config->irq_cfg_func(dev); +#endif + + /* Enable SPIP module */ + reg_base->SPIP_CTL1 |= BIT(NPCX_SPIP_CTL1_SPIEN); + + return 0; +} + +static struct spi_driver_api spi_npcx_spip_api = { + .transceive = spi_npcx_spip_transceive, + .release = spi_npcx_spip_release, +#ifdef CONFIG_SPI_ASYNC + .transceive_async = spi_npcx_spip_transceive_async, +#endif +}; + +#ifdef CONFIG_SPI_NPCX_SPIP_INTERRUPT +#define NPCX_SPIP_IRQ_HANDLER(n) \ + static void spi_npcx_spip_irq_cfg_func_##n(const struct device *dev) \ + { \ + IRQ_CONNECT(DT_INST_IRQN(n), DT_INST_IRQ(n, priority), spi_npcx_spip_isr, \ + DEVICE_DT_INST_GET(n), 0); \ + irq_enable(DT_INST_IRQN(n)); \ + } + +#define NPCX_SPIP_IRQ_HANDLER_FUNC(n) .irq_cfg_func = spi_npcx_spip_irq_cfg_func_##n, +#else +#define NPCX_SPIP_IRQ_HANDLER_FUNC(n) +#define NPCX_SPIP_IRQ_HANDLER(n) +#endif + +#define NPCX_SPI_INIT(n) \ + PINCTRL_DT_INST_DEFINE(n); \ + NPCX_SPIP_IRQ_HANDLER(n) \ + \ + static struct spi_npcx_spip_data spi_npcx_spip_data_##n = { \ + SPI_CONTEXT_INIT_LOCK(spi_npcx_spip_data_##n, ctx), \ + SPI_CONTEXT_INIT_SYNC(spi_npcx_spip_data_##n, ctx), \ + SPI_CONTEXT_CS_GPIOS_INITIALIZE(DT_DRV_INST(n), ctx)}; \ + \ + static struct spi_npcx_spip_cfg spi_npcx_spip_cfg_##n = { \ + .reg_base = (struct spip_reg *)DT_INST_REG_ADDR(n), \ + .clk_cfg = NPCX_DT_CLK_CFG_ITEM(n), \ + .pcfg = PINCTRL_DT_INST_DEV_CONFIG_GET(n), \ + NPCX_SPIP_IRQ_HANDLER_FUNC(n)}; \ + \ + DEVICE_DT_INST_DEFINE(n, spi_npcx_spip_init, NULL, &spi_npcx_spip_data_##n, \ + &spi_npcx_spip_cfg_##n, POST_KERNEL, CONFIG_SPI_INIT_PRIORITY, \ + &spi_npcx_spip_api); + +DT_INST_FOREACH_STATUS_OKAY(NPCX_SPI_INIT) diff --git a/dts/arm/nuvoton/npcx/npcx.dtsi b/dts/arm/nuvoton/npcx/npcx.dtsi index 28a491de16f..6c9a82f0145 100644 --- a/dts/arm/nuvoton/npcx/npcx.dtsi +++ b/dts/arm/nuvoton/npcx/npcx.dtsi @@ -546,6 +546,17 @@ &wui_io25 &wui_io24 &wui_io23 &wui_io22>; status = "disabled"; }; + + spip0: spi@400d2000 { + compatible = "nuvoton,npcx-spip"; + reg = <0x400d2000 0x1000>; + #address-cells = <1>; + #size-cells = <0>; + interrupts = <57 3>; + clocks = <&pcc NPCX_CLOCK_BUS_APB2 NPCX_PWDWN_CTL4 7>; + status = "disabled"; + + }; }; soc-if { diff --git a/dts/arm/nuvoton/npcx/npcx4/npcx4-pinctrl.dtsi b/dts/arm/nuvoton/npcx/npcx4/npcx4-pinctrl.dtsi index c795a41736b..af45fa59ddb 100644 --- a/dts/arm/nuvoton/npcx/npcx4/npcx4-pinctrl.dtsi +++ b/dts/arm/nuvoton/npcx/npcx4/npcx4-pinctrl.dtsi @@ -555,4 +555,12 @@ /omit-if-no-ref/ uart4_sout_gp35: periph-uart4-sout { pinmux = <&alte_cr_sout4_sl>; }; + + /omit-if-no-ref/ spip_sclk_mosi_miso_gp95_gpa1_gpa3_gpa5_sl: periph-spip-sl { + pinmux = <&alt0_spip_sl>; + }; + + /omit-if-no-ref/ spip_sclk_mosi_miso_gp95_gpa1_gpa3_gpa5_no_spip_inv: periph-no-spip-inv { + pinmux = <&alt0_gpio_no_spip>; + }; }; diff --git a/dts/arm/nuvoton/npcx/npcx7/npcx7-pinctrl.dtsi b/dts/arm/nuvoton/npcx/npcx7/npcx7-pinctrl.dtsi index e9acb4a0978..2b219c48ede 100644 --- a/dts/arm/nuvoton/npcx/npcx7/npcx7-pinctrl.dtsi +++ b/dts/arm/nuvoton/npcx/npcx7/npcx7-pinctrl.dtsi @@ -404,4 +404,12 @@ /omit-if-no-ref/ uart2_sin_sout_gp75_86: periph-uart2 { pinmux = <&alta_uart2_sl>; }; + + /omit-if-no-ref/ spip_sclk_mosi_miso_gp95_gpa1_gpa3_gpa5_sl: periph-spip-sl { + pinmux = <&alt0_spip_sl>; + }; + + /omit-if-no-ref/ spip_sclk_mosi_miso_gp95_gpa1_gpa3_gpa5_no_spip_inv: periph-no-spip-inv { + pinmux = <&alt0_gpio_no_spip>; + }; }; diff --git a/dts/arm/nuvoton/npcx/npcx9/npcx9-pinctrl.dtsi b/dts/arm/nuvoton/npcx/npcx9/npcx9-pinctrl.dtsi index 2fe2b1f75c9..2ba0b78fdda 100644 --- a/dts/arm/nuvoton/npcx/npcx9/npcx9-pinctrl.dtsi +++ b/dts/arm/nuvoton/npcx/npcx9/npcx9-pinctrl.dtsi @@ -462,4 +462,12 @@ /omit-if-no-ref/ uart4_sout_gp35: periph-uart4-sout { pinmux = <&alte_cr_sout4_sl>; }; + + /omit-if-no-ref/ spip_sclk_mosi_miso_gp95_gpa1_gpa3_gpa5_sl: periph-spip-sl { + pinmux = <&alt0_spip_sl>; + }; + + /omit-if-no-ref/ spip_sclk_mosi_miso_gp95_gpa1_gpa3_gpa5_no_spip_inv: periph-no-spip-inv { + pinmux = <&alt0_gpio_no_spip>; + }; }; diff --git a/dts/bindings/spi/nuvoton,npcx-spip.yaml b/dts/bindings/spi/nuvoton,npcx-spip.yaml new file mode 100644 index 00000000000..da771b4ba82 --- /dev/null +++ b/dts/bindings/spi/nuvoton,npcx-spip.yaml @@ -0,0 +1,12 @@ +# Copyright (c) 2024 Nuvoton Technology Corporation. +# SPDX-License-Identifier: Apache-2.0 + +description: Nuvoton, NPCX SPI controller. + +compatible: "nuvoton,npcx-spip" + +include: [spi-controller.yaml, pinctrl-device.yaml] + +properties: + reg: + required: true diff --git a/soc/arm/nuvoton_npcx/common/reg/reg_def.h b/soc/arm/nuvoton_npcx/common/reg/reg_def.h index 76cab3a6624..a4a23e543e6 100644 --- a/soc/arm/nuvoton_npcx/common/reg/reg_def.h +++ b/soc/arm/nuvoton_npcx/common/reg/reg_def.h @@ -1725,4 +1725,25 @@ struct shi_reg { #define IBF_IBHF_EN_MASK (BIT(NPCX_EVENABLE_IBFEN) | BIT(NPCX_EVENABLE_IBHFEN)) +/* SPIP (SPI Peripheral Interface) registers */ +struct spip_reg { + /* 0x000: SPIP Data In/Out */ + volatile uint16_t SPIP_DATA; + /* 0x002: SPIP Control 1 */ + volatile uint16_t SPIP_CTL1; + /* 0x004: SPIP Status */ + volatile uint8_t SPIP_STAT; + volatile uint8_t reserved1; +}; + +#define NPCX_SPIP_CTL1_SPIEN 0 +#define NPCX_SPIP_CTL1_MOD 2 +#define NPCX_SPIP_CTL1_EIR 5 +#define NPCX_SPIP_CTL1_EIW 6 +#define NPCX_SPIP_CTL1_SCM 7 +#define NPCX_SPIP_CTL1_SCIDL 8 +#define NPCX_SPIP_CTL1_SCDV FIELD(9, 7) +#define NPCX_SPIP_STAT_BSY 0 +#define NPCX_SPIP_STAT_RBF 1 + #endif /* _NUVOTON_NPCX_REG_DEF_H */ diff --git a/soc/arm/nuvoton_npcx/common/registers.c b/soc/arm/nuvoton_npcx/common/registers.c index d2e64d290ca..8c4ed132b46 100644 --- a/soc/arm/nuvoton_npcx/common/registers.c +++ b/soc/arm/nuvoton_npcx/common/registers.c @@ -185,3 +185,7 @@ NPCX_REG_SIZE_CHECK(kbs_reg, 0x010); NPCX_REG_OFFSET_CHECK(kbs_reg, KBSIN, 0x004); NPCX_REG_OFFSET_CHECK(kbs_reg, KBSOUT0, 0x006); NPCX_REG_OFFSET_CHECK(kbs_reg, KBS_BUF_INDX, 0x00a); + +/* SPIP register structure check */ +NPCX_REG_SIZE_CHECK(spip_reg, 0x006); +NPCX_REG_OFFSET_CHECK(spip_reg, SPIP_CTL1, 0x002); From 833495675a233c93d22d548dd992962297ebd0bc Mon Sep 17 00:00:00 2001 From: Jun Lin Date: Mon, 8 Jan 2024 10:13:37 +0800 Subject: [PATCH 2067/3723] test: spi_loopback: add npcx evbs to the spi_loopback test suite This commits adds the npcx4/npcx9/npcx7 evaluation boards to the spi_loopback test suite. Signed-off-by: Jun Lin --- .../spi/spi_loopback/boards/npcx4m8f_evb.conf | 3 +++ .../spi_loopback/boards/npcx4m8f_evb.overlay | 21 +++++++++++++++++++ .../spi_loopback/boards/npcx7m6fb_evb.conf | 3 +++ .../spi_loopback/boards/npcx7m6fb_evb.overlay | 21 +++++++++++++++++++ .../spi/spi_loopback/boards/npcx9m6f_evb.conf | 3 +++ .../spi_loopback/boards/npcx9m6f_evb.overlay | 21 +++++++++++++++++++ 6 files changed, 72 insertions(+) create mode 100644 tests/drivers/spi/spi_loopback/boards/npcx4m8f_evb.conf create mode 100644 tests/drivers/spi/spi_loopback/boards/npcx4m8f_evb.overlay create mode 100644 tests/drivers/spi/spi_loopback/boards/npcx7m6fb_evb.conf create mode 100644 tests/drivers/spi/spi_loopback/boards/npcx7m6fb_evb.overlay create mode 100644 tests/drivers/spi/spi_loopback/boards/npcx9m6f_evb.conf create mode 100644 tests/drivers/spi/spi_loopback/boards/npcx9m6f_evb.overlay diff --git a/tests/drivers/spi/spi_loopback/boards/npcx4m8f_evb.conf b/tests/drivers/spi/spi_loopback/boards/npcx4m8f_evb.conf new file mode 100644 index 00000000000..e853c1fdc01 --- /dev/null +++ b/tests/drivers/spi/spi_loopback/boards/npcx4m8f_evb.conf @@ -0,0 +1,3 @@ +CONFIG_GPIO=y +CONFIG_SPI_ASYNC=y +CONFIG_SPI_NPCX_SPIP_INTERRUPT=y diff --git a/tests/drivers/spi/spi_loopback/boards/npcx4m8f_evb.overlay b/tests/drivers/spi/spi_loopback/boards/npcx4m8f_evb.overlay new file mode 100644 index 00000000000..284b8041c98 --- /dev/null +++ b/tests/drivers/spi/spi_loopback/boards/npcx4m8f_evb.overlay @@ -0,0 +1,21 @@ +/* SPDX-License-Identifier: Apache-2.0 */ + +&spip0 { + status = "okay"; + pinctrl-0 = <&spip_sclk_mosi_miso_gp95_gpa1_gpa3_gpa5_sl + &spip_sclk_mosi_miso_gp95_gpa1_gpa3_gpa5_no_spip_inv>; + pinctrl-names = "default"; + + cs-gpios = <&gpioa 5 GPIO_ACTIVE_LOW>; + + 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 = <15000000>; + }; +}; diff --git a/tests/drivers/spi/spi_loopback/boards/npcx7m6fb_evb.conf b/tests/drivers/spi/spi_loopback/boards/npcx7m6fb_evb.conf new file mode 100644 index 00000000000..e853c1fdc01 --- /dev/null +++ b/tests/drivers/spi/spi_loopback/boards/npcx7m6fb_evb.conf @@ -0,0 +1,3 @@ +CONFIG_GPIO=y +CONFIG_SPI_ASYNC=y +CONFIG_SPI_NPCX_SPIP_INTERRUPT=y diff --git a/tests/drivers/spi/spi_loopback/boards/npcx7m6fb_evb.overlay b/tests/drivers/spi/spi_loopback/boards/npcx7m6fb_evb.overlay new file mode 100644 index 00000000000..284b8041c98 --- /dev/null +++ b/tests/drivers/spi/spi_loopback/boards/npcx7m6fb_evb.overlay @@ -0,0 +1,21 @@ +/* SPDX-License-Identifier: Apache-2.0 */ + +&spip0 { + status = "okay"; + pinctrl-0 = <&spip_sclk_mosi_miso_gp95_gpa1_gpa3_gpa5_sl + &spip_sclk_mosi_miso_gp95_gpa1_gpa3_gpa5_no_spip_inv>; + pinctrl-names = "default"; + + cs-gpios = <&gpioa 5 GPIO_ACTIVE_LOW>; + + 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 = <15000000>; + }; +}; diff --git a/tests/drivers/spi/spi_loopback/boards/npcx9m6f_evb.conf b/tests/drivers/spi/spi_loopback/boards/npcx9m6f_evb.conf new file mode 100644 index 00000000000..e853c1fdc01 --- /dev/null +++ b/tests/drivers/spi/spi_loopback/boards/npcx9m6f_evb.conf @@ -0,0 +1,3 @@ +CONFIG_GPIO=y +CONFIG_SPI_ASYNC=y +CONFIG_SPI_NPCX_SPIP_INTERRUPT=y diff --git a/tests/drivers/spi/spi_loopback/boards/npcx9m6f_evb.overlay b/tests/drivers/spi/spi_loopback/boards/npcx9m6f_evb.overlay new file mode 100644 index 00000000000..284b8041c98 --- /dev/null +++ b/tests/drivers/spi/spi_loopback/boards/npcx9m6f_evb.overlay @@ -0,0 +1,21 @@ +/* SPDX-License-Identifier: Apache-2.0 */ + +&spip0 { + status = "okay"; + pinctrl-0 = <&spip_sclk_mosi_miso_gp95_gpa1_gpa3_gpa5_sl + &spip_sclk_mosi_miso_gp95_gpa1_gpa3_gpa5_no_spip_inv>; + pinctrl-names = "default"; + + cs-gpios = <&gpioa 5 GPIO_ACTIVE_LOW>; + + 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 = <15000000>; + }; +}; From bc90724de41c32cf45eab9048636100801db3758 Mon Sep 17 00:00:00 2001 From: Mykola Kvach Date: Tue, 9 Jan 2024 10:00:59 +0200 Subject: [PATCH 2068/3723] drivers: serial: uart_rcar: fix reading of SCFRDR register Fix the read size of the SCFRDR register, which has an 8-bit size for both Gen3 and Gen4 boards. Signed-off-by: Mykola Kvach --- drivers/serial/uart_rcar.c | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/drivers/serial/uart_rcar.c b/drivers/serial/uart_rcar.c index b8011244a46..081d2d48959 100644 --- a/drivers/serial/uart_rcar.c +++ b/drivers/serial/uart_rcar.c @@ -104,6 +104,11 @@ struct uart_rcar_data { #define SCLSR_TO BIT(2) /* Timeout */ #define SCLSR_ORER BIT(0) /* Overrun Error */ +static uint8_t uart_rcar_read_8(const struct device *dev, uint32_t offs) +{ + return sys_read8(DEVICE_MMIO_GET(dev) + offs); +} + static void uart_rcar_write_8(const struct device *dev, uint32_t offs, uint8_t value) { @@ -146,7 +151,7 @@ static int uart_rcar_poll_in(const struct device *dev, unsigned char *p_char) goto unlock; } - *p_char = uart_rcar_read_16(dev, SCFRDR); + *p_char = uart_rcar_read_8(dev, SCFRDR); reg_val = uart_rcar_read_16(dev, SCFSR); reg_val &= ~SCFSR_RDF; @@ -347,7 +352,7 @@ static int uart_rcar_fifo_read(const struct device *dev, uint8_t *rx_data, while (((size - num_rx) > 0) && (uart_rcar_read_16(dev, SCFSR) & SCFSR_RDF)) { /* Receive current byte */ - rx_data[num_rx++] = uart_rcar_read_16(dev, SCFRDR); + rx_data[num_rx++] = uart_rcar_read_8(dev, SCFRDR); reg_val = uart_rcar_read_16(dev, SCFSR); reg_val &= ~(SCFSR_RDF); From 76997374c3d01c110e277a71dffef957d0d61c42 Mon Sep 17 00:00:00 2001 From: Lucas Tamborrino Date: Tue, 9 Jan 2024 10:54:18 -0300 Subject: [PATCH 2069/3723] tests: pwm: esp32: add internal loopback Add internal loopback for testing purposes and change wroom for wrover, which is default board for testing. Signed-off-by: Lucas Tamborrino --- ...32_devkitc_wroom.overlay => esp32_devkitc_wrover.overlay} | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) rename tests/drivers/pwm/pwm_loopback/boards/{esp32_devkitc_wroom.overlay => esp32_devkitc_wrover.overlay} (92%) diff --git a/tests/drivers/pwm/pwm_loopback/boards/esp32_devkitc_wroom.overlay b/tests/drivers/pwm/pwm_loopback/boards/esp32_devkitc_wrover.overlay similarity index 92% rename from tests/drivers/pwm/pwm_loopback/boards/esp32_devkitc_wroom.overlay rename to tests/drivers/pwm/pwm_loopback/boards/esp32_devkitc_wrover.overlay index b0d4e1e0381..f089abb8959 100644 --- a/tests/drivers/pwm/pwm_loopback/boards/esp32_devkitc_wroom.overlay +++ b/tests/drivers/pwm/pwm_loopback/boards/esp32_devkitc_wrover.overlay @@ -19,10 +19,11 @@ mcpwm0_default: mcpwm0_default { group1 { pinmux = ; - output-enable; + input-enable; }; group2 { - pinmux = ; + pinmux = ; + output-enable; }; }; }; From 2ca4ed205fee589d4cb9fbc4591760c27884ca54 Mon Sep 17 00:00:00 2001 From: Lucas Tamborrino Date: Tue, 9 Jan 2024 10:55:24 -0300 Subject: [PATCH 2070/3723] tests: pwm: esp32s3: add internal loopback Add internal loopback for testing purposes Signed-off-by: Lucas Tamborrino --- .../drivers/pwm/pwm_loopback/boards/esp32s3_devkitm.overlay | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/tests/drivers/pwm/pwm_loopback/boards/esp32s3_devkitm.overlay b/tests/drivers/pwm/pwm_loopback/boards/esp32s3_devkitm.overlay index 64e50d19693..00d99271cef 100644 --- a/tests/drivers/pwm/pwm_loopback/boards/esp32s3_devkitm.overlay +++ b/tests/drivers/pwm/pwm_loopback/boards/esp32s3_devkitm.overlay @@ -19,10 +19,11 @@ mcpwm0_default: mcpwm0_default { group1 { pinmux = ; - output-enable; + input-enable; }; group2 { - pinmux = ; + pinmux = ; + output-enable; }; }; }; From 9f4a7ba0f57b4606174b410b63f9d94f6f33b1f9 Mon Sep 17 00:00:00 2001 From: Gerard Marull-Paretas Date: Tue, 9 Jan 2024 15:23:54 +0100 Subject: [PATCH 2071/3723] doc: extensions: zephyr-domain: fix object descriptions Zephyr's domain code-sample object description was incorrectly yielded, making Sphinx inventory (objects.inv) unusable on other projects that need to use the domain via Intersphinx. Ref. https://www.sphinx-doc.org/en/master/extdev/domainapi.html Signed-off-by: Gerard Marull-Paretas --- doc/_extensions/zephyr/domain.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/doc/_extensions/zephyr/domain.py b/doc/_extensions/zephyr/domain.py index 8c395142818..beb94eb4d2f 100644 --- a/doc/_extensions/zephyr/domain.py +++ b/doc/_extensions/zephyr/domain.py @@ -249,7 +249,7 @@ class ZephyrDomain(Domain): directives = {"code-sample": CodeSampleDirective} object_types: Dict[str, ObjType] = { - "code-sample": ObjType("code sample", "code-sample"), + "code-sample": ObjType("code-sample", "code-sample"), } initial_data: Dict[str, Any] = {"code-samples": {}} @@ -267,9 +267,9 @@ def merge_domaindata(self, docnames: List[str], otherdata: Dict) -> None: def get_objects(self): for _, code_sample in self.data["code-samples"].items(): yield ( + code_sample["id"], code_sample["name"], - code_sample["name"], - "code sample", + "code-sample", code_sample["docname"], code_sample["id"], 1, From 9e5e8e8c40f3b667f67a9edc6e21f9a5e9926786 Mon Sep 17 00:00:00 2001 From: Gerard Marull-Paretas Date: Tue, 9 Jan 2024 15:34:14 +0100 Subject: [PATCH 2072/3723] doc: extensions: zephyr-domain: make Breathe inserts optional So that external users of the domain only interested in e.g. referencing roles, can skip tweaks made to Breathe's directives. Signed-off-by: Gerard Marull-Paretas --- doc/_extensions/zephyr/domain.py | 8 +++++++- doc/conf.py | 4 ++++ 2 files changed, 11 insertions(+), 1 deletion(-) diff --git a/doc/_extensions/zephyr/domain.py b/doc/_extensions/zephyr/domain.py index beb94eb4d2f..66327f9c7ad 100644 --- a/doc/_extensions/zephyr/domain.py +++ b/doc/_extensions/zephyr/domain.py @@ -308,10 +308,16 @@ class CustomDoxygenGroupDirective(DoxygenGroupDirective): def run(self) -> List[Node]: nodes = super().run() - return [RelatedCodeSamplesNode(id=self.arguments[0]), *nodes] + + if self.config.zephyr_breathe_insert_related_samples: + return [RelatedCodeSamplesNode(id=self.arguments[0]), *nodes] + else: + return nodes def setup(app): + app.add_config_value("zephyr_breathe_insert_related_samples", False, "env") + app.add_domain(ZephyrDomain) app.add_transform(ConvertCodeSampleNode) diff --git a/doc/conf.py b/doc/conf.py index f8bfb06e199..808df88917f 100644 --- a/doc/conf.py +++ b/doc/conf.py @@ -310,6 +310,10 @@ "build/dts/api/compatibles/**/*", ] +# -- Options for zephyr.domain -------------------------------------------- + +zephyr_breathe_insert_related_samples = True + # -- Options for sphinx.ext.graphviz -------------------------------------- graphviz_dot = os.environ.get("DOT_EXECUTABLE", "dot") From 19da13313d566fb09f06734d9b6beea5fe9b1791 Mon Sep 17 00:00:00 2001 From: Jonathan Rico Date: Tue, 9 Jan 2024 14:15:15 +0100 Subject: [PATCH 2073/3723] Bluetooth: L2CAP: remove usage of `bt_l2cap_send_cb` by BR/EDR Isolates BR/EDR's l2cap use from LE (most of l2cap.c). Why? Because I'm refactoring l2cap.c and don't want to accidentally break BR/EDR support, as there are very few tests in CI. This way, once `bt_l2cap_chan_send` hands control to l2cap_br.c, it will not call back into l2cap.c, it will instead be a parallel layer going directly to conn.c. Signed-off-by: Jonathan Rico --- subsys/bluetooth/host/l2cap_br.c | 21 ++++++++++++++++++--- 1 file changed, 18 insertions(+), 3 deletions(-) diff --git a/subsys/bluetooth/host/l2cap_br.c b/subsys/bluetooth/host/l2cap_br.c index e9a10ff8d72..2976731f568 100644 --- a/subsys/bluetooth/host/l2cap_br.c +++ b/subsys/bluetooth/host/l2cap_br.c @@ -236,6 +236,20 @@ static uint8_t l2cap_br_get_ident(void) return ident; } +static int l2cap_br_send_cb(struct bt_conn *conn, uint16_t cid, struct net_buf *buf, + bt_conn_tx_cb_t cb, void *user_data) +{ + struct bt_l2cap_hdr *hdr; + + LOG_DBG("conn %p cid %u len %zu", conn, cid, buf->len); + + hdr = net_buf_push(buf, sizeof(*hdr)); + hdr->len = sys_cpu_to_le16(buf->len - sizeof(*hdr)); + hdr->cid = sys_cpu_to_le16(cid); + + return bt_conn_send_cb(conn, buf, cb, user_data); +} + /* Send the buffer and release it in case of failure. * Any other cleanup in failure to send should be handled by the disconnected * handler. @@ -243,7 +257,7 @@ static uint8_t l2cap_br_get_ident(void) static inline void l2cap_send(struct bt_conn *conn, uint16_t cid, struct net_buf *buf) { - if (bt_l2cap_send(conn, cid, buf)) { + if (l2cap_br_send_cb(conn, cid, buf, NULL, NULL)) { net_buf_unref(buf); } } @@ -252,7 +266,8 @@ static void l2cap_br_chan_send_req(struct bt_l2cap_br_chan *chan, struct net_buf *buf, k_timeout_t timeout) { - if (bt_l2cap_send(chan->chan.conn, BT_L2CAP_CID_BR_SIG, buf)) { + if (l2cap_br_send_cb(chan->chan.conn, BT_L2CAP_CID_BR_SIG, buf, + NULL, NULL)) { net_buf_unref(buf); return; } @@ -1362,7 +1377,7 @@ int bt_l2cap_br_chan_send_cb(struct bt_l2cap_chan *chan, struct net_buf *buf, bt return -EMSGSIZE; } - return bt_l2cap_send_cb(br_chan->chan.conn, br_chan->tx.cid, buf, cb, user_data); + return l2cap_br_send_cb(br_chan->chan.conn, br_chan->tx.cid, buf, cb, user_data); } int bt_l2cap_br_chan_send(struct bt_l2cap_chan *chan, struct net_buf *buf) From 1e6ff5ff05de2380cd5208a2abc1874f7c8b14a0 Mon Sep 17 00:00:00 2001 From: Jonathan Rico Date: Tue, 9 Jan 2024 15:43:33 +0100 Subject: [PATCH 2074/3723] Bluetooth: L2CAP: separate BR/EDR and LE internal headers Extract BR/EDR definitions from `l2cap_internal.c` into its own headers: one for the interface with l2cap.c and one for the rest of the BR/EDR stack. Signed-off-by: Jonathan Rico --- subsys/bluetooth/host/avdtp.c | 2 +- subsys/bluetooth/host/hfp_hf.c | 2 +- subsys/bluetooth/host/l2cap_br.c | 2 +- subsys/bluetooth/host/l2cap_br_interface.h | 39 +++++ subsys/bluetooth/host/l2cap_br_internal.h | 177 +++++++++++++++++++++ subsys/bluetooth/host/l2cap_internal.h | 129 +-------------- subsys/bluetooth/host/rfcomm.c | 2 +- subsys/bluetooth/host/sdp.c | 2 +- 8 files changed, 222 insertions(+), 133 deletions(-) create mode 100644 subsys/bluetooth/host/l2cap_br_interface.h create mode 100644 subsys/bluetooth/host/l2cap_br_internal.h diff --git a/subsys/bluetooth/host/avdtp.c b/subsys/bluetooth/host/avdtp.c index 62409937514..9f9b63dfe4f 100644 --- a/subsys/bluetooth/host/avdtp.c +++ b/subsys/bluetooth/host/avdtp.c @@ -20,7 +20,7 @@ #include "hci_core.h" #include "conn_internal.h" -#include "l2cap_internal.h" +#include "l2cap_br_internal.h" #include "avdtp_internal.h" #define LOG_LEVEL CONFIG_BT_AVDTP_LOG_LEVEL diff --git a/subsys/bluetooth/host/hfp_hf.c b/subsys/bluetooth/host/hfp_hf.c index 9ad49278111..e6cc10c8f7c 100644 --- a/subsys/bluetooth/host/hfp_hf.c +++ b/subsys/bluetooth/host/hfp_hf.c @@ -21,7 +21,7 @@ #include "hci_core.h" #include "conn_internal.h" -#include "l2cap_internal.h" +#include "l2cap_br_internal.h" #include "rfcomm_internal.h" #include "at.h" #include "hfp_internal.h" diff --git a/subsys/bluetooth/host/l2cap_br.c b/subsys/bluetooth/host/l2cap_br.c index 2976731f568..aaef1e3d1f1 100644 --- a/subsys/bluetooth/host/l2cap_br.c +++ b/subsys/bluetooth/host/l2cap_br.c @@ -21,7 +21,7 @@ #include "hci_core.h" #include "conn_internal.h" -#include "l2cap_internal.h" +#include "l2cap_br_internal.h" #include "avdtp_internal.h" #include "a2dp_internal.h" #include "rfcomm_internal.h" diff --git a/subsys/bluetooth/host/l2cap_br_interface.h b/subsys/bluetooth/host/l2cap_br_interface.h new file mode 100644 index 00000000000..0bfb7076e37 --- /dev/null +++ b/subsys/bluetooth/host/l2cap_br_interface.h @@ -0,0 +1,39 @@ +/* l2cap_br.c - L2CAP BREDR internal interface + * + * This is the only interface between l2cap.c and l2cap_br.c. + * + * Copyright (c) 2024 Nordic Semiconductor ASA + * + * SPDX-License-Identifier: Apache-2.0 + */ + +/* Initialize BR/EDR L2CAP signal layer */ +void bt_l2cap_br_init(void); + +/* Notify BR/EDR L2CAP channels about established new ACL connection */ +void bt_l2cap_br_connected(struct bt_conn *conn); + +/* Lookup BR/EDR L2CAP channel by Receiver CID */ +struct bt_l2cap_chan *bt_l2cap_br_lookup_rx_cid(struct bt_conn *conn, + uint16_t cid); + +/* Disconnects dynamic channel */ +int bt_l2cap_br_chan_disconnect(struct bt_l2cap_chan *chan); + +/* Make connection to peer psm server */ +int bt_l2cap_br_chan_connect(struct bt_conn *conn, struct bt_l2cap_chan *chan, + uint16_t psm); + +/* Send packet data to connected peer */ +int bt_l2cap_br_chan_send(struct bt_l2cap_chan *chan, struct net_buf *buf); +int bt_l2cap_br_chan_send_cb(struct bt_l2cap_chan *chan, struct net_buf *buf, bt_conn_tx_cb_t cb, + void *user_data); + +/* + * Handle security level changed on link passing HCI status of performed + * security procedure. + */ +void l2cap_br_encrypt_change(struct bt_conn *conn, uint8_t hci_status); + +/* Handle received data */ +void bt_l2cap_br_recv(struct bt_conn *conn, struct net_buf *buf); diff --git a/subsys/bluetooth/host/l2cap_br_internal.h b/subsys/bluetooth/host/l2cap_br_internal.h new file mode 100644 index 00000000000..0057bc5548c --- /dev/null +++ b/subsys/bluetooth/host/l2cap_br_internal.h @@ -0,0 +1,177 @@ +/** @file + * @brief Internal APIs for Bluetooth L2CAP BR/EDR handling. + */ + +/* + * Copyright (c) 2015-2016 Intel Corporation + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include +#include +#include "l2cap_br_interface.h" + +#define BT_L2CAP_CID_BR_SIG 0x0001 +#define BT_L2CAP_CID_BR_SMP 0x0007 +#define BT_L2CAP_PSM_RFCOMM 0x0003 + +struct bt_l2cap_hdr { + uint16_t len; + uint16_t cid; +} __packed; + +struct bt_l2cap_sig_hdr { + uint8_t code; + uint8_t ident; + uint16_t len; +} __packed; + +#define BT_L2CAP_REJ_NOT_UNDERSTOOD 0x0000 +#define BT_L2CAP_REJ_MTU_EXCEEDED 0x0001 +#define BT_L2CAP_REJ_INVALID_CID 0x0002 + +#define BT_L2CAP_CMD_REJECT 0x01 +struct bt_l2cap_cmd_reject { + uint16_t reason; + uint8_t data[0]; +} __packed; + +struct bt_l2cap_cmd_reject_cid_data { + uint16_t scid; + uint16_t dcid; +} __packed; + +#define BT_L2CAP_CONN_REQ 0x02 +struct bt_l2cap_conn_req { + uint16_t psm; + uint16_t scid; +} __packed; + +/* command statuses in response */ +#define BT_L2CAP_CS_NO_INFO 0x0000 +#define BT_L2CAP_CS_AUTHEN_PEND 0x0001 + +/* valid results in conn response on BR/EDR */ +#define BT_L2CAP_BR_SUCCESS 0x0000 +#define BT_L2CAP_BR_PENDING 0x0001 +#define BT_L2CAP_BR_ERR_PSM_NOT_SUPP 0x0002 +#define BT_L2CAP_BR_ERR_SEC_BLOCK 0x0003 +#define BT_L2CAP_BR_ERR_NO_RESOURCES 0x0004 +#define BT_L2CAP_BR_ERR_INVALID_SCID 0x0006 +#define BT_L2CAP_BR_ERR_SCID_IN_USE 0x0007 + +#define BT_L2CAP_CONN_RSP 0x03 +struct bt_l2cap_conn_rsp { + uint16_t dcid; + uint16_t scid; + uint16_t result; + uint16_t status; +} __packed; + +#define BT_L2CAP_CONF_SUCCESS 0x0000 +#define BT_L2CAP_CONF_UNACCEPT 0x0001 +#define BT_L2CAP_CONF_REJECT 0x0002 + +#define BT_L2CAP_CONF_REQ 0x04 +struct bt_l2cap_conf_req { + uint16_t dcid; + uint16_t flags; + uint8_t data[0]; +} __packed; + +#define BT_L2CAP_CONF_RSP 0x05 +struct bt_l2cap_conf_rsp { + uint16_t scid; + uint16_t flags; + uint16_t result; + uint8_t data[0]; +} __packed; + +/* Option type used by MTU config request data */ +#define BT_L2CAP_CONF_OPT_MTU 0x01 +/* Options bits selecting most significant bit (hint) in type field */ +#define BT_L2CAP_CONF_HINT 0x80 +#define BT_L2CAP_CONF_MASK 0x7f + +struct bt_l2cap_conf_opt { + uint8_t type; + uint8_t len; + uint8_t data[0]; +} __packed; + +#define BT_L2CAP_DISCONN_REQ 0x06 +struct bt_l2cap_disconn_req { + uint16_t dcid; + uint16_t scid; +} __packed; + +#define BT_L2CAP_DISCONN_RSP 0x07 +struct bt_l2cap_disconn_rsp { + uint16_t dcid; + uint16_t scid; +} __packed; + +#define BT_L2CAP_INFO_FEAT_MASK 0x0002 +#define BT_L2CAP_INFO_FIXED_CHAN 0x0003 + +#define BT_L2CAP_INFO_REQ 0x0a +struct bt_l2cap_info_req { + uint16_t type; +} __packed; + +/* info result */ +#define BT_L2CAP_INFO_SUCCESS 0x0000 +#define BT_L2CAP_INFO_NOTSUPP 0x0001 + +#define BT_L2CAP_INFO_RSP 0x0b +struct bt_l2cap_info_rsp { + uint16_t type; + uint16_t result; + uint8_t data[0]; +} __packed; + +/* Need a name different than bt_l2cap_fixed_chan for a different section */ +struct bt_l2cap_br_fixed_chan { + uint16_t cid; + int (*accept)(struct bt_conn *conn, struct bt_l2cap_chan **chan); +}; + +#define BT_L2CAP_BR_CHANNEL_DEFINE(_name, _cid, _accept) \ + const STRUCT_SECTION_ITERABLE(bt_l2cap_br_fixed_chan, _name) = { \ + .cid = _cid, \ + .accept = _accept, \ + } + +#define BR_CHAN(_ch) CONTAINER_OF(_ch, struct bt_l2cap_br_chan, chan) + +/* Add channel to the connection */ +void bt_l2cap_chan_add(struct bt_conn *conn, struct bt_l2cap_chan *chan, + bt_l2cap_chan_destroy_t destroy); + +/* Remove channel from the connection */ +void bt_l2cap_chan_remove(struct bt_conn *conn, struct bt_l2cap_chan *chan); + +/* Delete channel */ +void bt_l2cap_chan_del(struct bt_l2cap_chan *chan); + +const char *bt_l2cap_chan_state_str(bt_l2cap_chan_state_t state); + +#if defined(CONFIG_BT_L2CAP_LOG_LEVEL_DBG) +void bt_l2cap_chan_set_state_debug(struct bt_l2cap_chan *chan, + bt_l2cap_chan_state_t state, + const char *func, int line); +#define bt_l2cap_chan_set_state(_chan, _state) \ + bt_l2cap_chan_set_state_debug(_chan, _state, __func__, __LINE__) +#else +void bt_l2cap_chan_set_state(struct bt_l2cap_chan *chan, + bt_l2cap_chan_state_t state); +#endif /* CONFIG_BT_L2CAP_LOG_LEVEL_DBG */ + +/* Prepare an L2CAP PDU to be sent over a connection */ +struct net_buf *bt_l2cap_create_pdu_timeout(struct net_buf_pool *pool, + size_t reserve, + k_timeout_t timeout); + +#define bt_l2cap_create_pdu(_pool, _reserve) \ + bt_l2cap_create_pdu_timeout(_pool, _reserve, K_FOREVER) diff --git a/subsys/bluetooth/host/l2cap_internal.h b/subsys/bluetooth/host/l2cap_internal.h index a6ecac9a016..43ade8b90d7 100644 --- a/subsys/bluetooth/host/l2cap_internal.h +++ b/subsys/bluetooth/host/l2cap_internal.h @@ -10,6 +10,7 @@ #include #include +#include "l2cap_br_interface.h" enum l2cap_conn_list_action { BT_L2CAP_CHAN_LOOKUP, @@ -50,64 +51,6 @@ struct bt_l2cap_cmd_reject_cid_data { uint16_t dcid; } __packed; -#define BT_L2CAP_CONN_REQ 0x02 -struct bt_l2cap_conn_req { - uint16_t psm; - uint16_t scid; -} __packed; - -/* command statuses in response */ -#define BT_L2CAP_CS_NO_INFO 0x0000 -#define BT_L2CAP_CS_AUTHEN_PEND 0x0001 - -/* valid results in conn response on BR/EDR */ -#define BT_L2CAP_BR_SUCCESS 0x0000 -#define BT_L2CAP_BR_PENDING 0x0001 -#define BT_L2CAP_BR_ERR_PSM_NOT_SUPP 0x0002 -#define BT_L2CAP_BR_ERR_SEC_BLOCK 0x0003 -#define BT_L2CAP_BR_ERR_NO_RESOURCES 0x0004 -#define BT_L2CAP_BR_ERR_INVALID_SCID 0x0006 -#define BT_L2CAP_BR_ERR_SCID_IN_USE 0x0007 - -#define BT_L2CAP_CONN_RSP 0x03 -struct bt_l2cap_conn_rsp { - uint16_t dcid; - uint16_t scid; - uint16_t result; - uint16_t status; -} __packed; - -#define BT_L2CAP_CONF_SUCCESS 0x0000 -#define BT_L2CAP_CONF_UNACCEPT 0x0001 -#define BT_L2CAP_CONF_REJECT 0x0002 - -#define BT_L2CAP_CONF_REQ 0x04 -struct bt_l2cap_conf_req { - uint16_t dcid; - uint16_t flags; - uint8_t data[0]; -} __packed; - -#define BT_L2CAP_CONF_RSP 0x05 -struct bt_l2cap_conf_rsp { - uint16_t scid; - uint16_t flags; - uint16_t result; - uint8_t data[0]; -} __packed; - -/* Option type used by MTU config request data */ -#define BT_L2CAP_CONF_OPT_MTU 0x01 -/* Options bits selecting most significant bit (hint) in type field */ -#define BT_L2CAP_CONF_HINT 0x80 -#define BT_L2CAP_CONF_MASK 0x7f - -struct bt_l2cap_conf_opt { - uint8_t type; - uint8_t len; - uint8_t data[0]; -} __packed; - #define BT_L2CAP_DISCONN_REQ 0x06 struct bt_l2cap_disconn_req { uint16_t dcid; @@ -120,25 +63,6 @@ struct bt_l2cap_disconn_rsp { uint16_t scid; } __packed; -#define BT_L2CAP_INFO_FEAT_MASK 0x0002 -#define BT_L2CAP_INFO_FIXED_CHAN 0x0003 - -#define BT_L2CAP_INFO_REQ 0x0a -struct bt_l2cap_info_req { - uint16_t type; -} __packed; - -/* info result */ -#define BT_L2CAP_INFO_SUCCESS 0x0000 -#define BT_L2CAP_INFO_NOTSUPP 0x0001 - -#define BT_L2CAP_INFO_RSP 0x0b -struct bt_l2cap_info_rsp { - uint16_t type; - uint16_t result; - uint8_t data[0]; -} __packed; - #define BT_L2CAP_CONN_PARAM_REQ 0x12 struct bt_l2cap_conn_param_req { uint16_t min_interval; @@ -243,20 +167,6 @@ struct bt_l2cap_fixed_chan { .destroy = _destroy, \ } -/* Need a name different than bt_l2cap_fixed_chan for a different section */ -struct bt_l2cap_br_fixed_chan { - uint16_t cid; - int (*accept)(struct bt_conn *conn, struct bt_l2cap_chan **chan); -}; - -#define BT_L2CAP_BR_CHANNEL_DEFINE(_name, _cid, _accept) \ - const STRUCT_SECTION_ITERABLE(bt_l2cap_br_fixed_chan, _name) = { \ - .cid = _cid, \ - .accept = _accept, \ - } - -#define BR_CHAN(_ch) CONTAINER_OF(_ch, struct bt_l2cap_br_chan, chan) - /* Notify L2CAP channels of a new connection */ void bt_l2cap_connected(struct bt_conn *conn); @@ -300,9 +210,6 @@ struct net_buf *bt_l2cap_create_pdu_timeout(struct net_buf_pool *pool, #define bt_l2cap_create_pdu(_pool, _reserve) \ bt_l2cap_create_pdu_timeout(_pool, _reserve, K_FOREVER) -/* Prepare a L2CAP Response PDU to be sent over a connection */ -struct net_buf *bt_l2cap_create_rsp(struct net_buf *buf, size_t reserve); - /* Send L2CAP PDU over a connection * * Buffer ownership is transferred to stack in case of success. @@ -334,40 +241,6 @@ struct bt_l2cap_chan *bt_l2cap_le_lookup_tx_cid(struct bt_conn *conn, struct bt_l2cap_chan *bt_l2cap_le_lookup_rx_cid(struct bt_conn *conn, uint16_t cid); -/* Initialize BR/EDR L2CAP signal layer */ -void bt_l2cap_br_init(void); - -/* Register fixed channel */ -void bt_l2cap_br_fixed_chan_register(struct bt_l2cap_fixed_chan *chan); - -/* Notify BR/EDR L2CAP channels about established new ACL connection */ -void bt_l2cap_br_connected(struct bt_conn *conn); - -/* Lookup BR/EDR L2CAP channel by Receiver CID */ -struct bt_l2cap_chan *bt_l2cap_br_lookup_rx_cid(struct bt_conn *conn, - uint16_t cid); - -/* Disconnects dynamic channel */ -int bt_l2cap_br_chan_disconnect(struct bt_l2cap_chan *chan); - -/* Make connection to peer psm server */ -int bt_l2cap_br_chan_connect(struct bt_conn *conn, struct bt_l2cap_chan *chan, - uint16_t psm); - -/* Send packet data to connected peer */ -int bt_l2cap_br_chan_send(struct bt_l2cap_chan *chan, struct net_buf *buf); -int bt_l2cap_br_chan_send_cb(struct bt_l2cap_chan *chan, struct net_buf *buf, bt_conn_tx_cb_t cb, - void *user_data); - -/* - * Handle security level changed on link passing HCI status of performed - * security procedure. - */ -void l2cap_br_encrypt_change(struct bt_conn *conn, uint8_t hci_status); - -/* Handle received data */ -void bt_l2cap_br_recv(struct bt_conn *conn, struct net_buf *buf); - struct bt_l2cap_ecred_cb { void (*ecred_conn_rsp)(struct bt_conn *conn, uint16_t result, uint8_t attempted, uint8_t succeeded, uint16_t psm); diff --git a/subsys/bluetooth/host/rfcomm.c b/subsys/bluetooth/host/rfcomm.c index 21b0e45e13a..16e771c659d 100644 --- a/subsys/bluetooth/host/rfcomm.c +++ b/subsys/bluetooth/host/rfcomm.c @@ -24,7 +24,7 @@ #include "hci_core.h" #include "conn_internal.h" -#include "l2cap_internal.h" +#include "l2cap_br_internal.h" #include "rfcomm_internal.h" #define LOG_LEVEL CONFIG_BT_RFCOMM_LOG_LEVEL diff --git a/subsys/bluetooth/host/sdp.c b/subsys/bluetooth/host/sdp.c index d663ee5123f..a0346c84bd7 100644 --- a/subsys/bluetooth/host/sdp.c +++ b/subsys/bluetooth/host/sdp.c @@ -21,7 +21,7 @@ #include "hci_core.h" #include "conn_internal.h" -#include "l2cap_internal.h" +#include "l2cap_br_internal.h" #include "sdp_internal.h" #define LOG_LEVEL CONFIG_BT_SDP_LOG_LEVEL From 9852e8e15bc8536aa1a49cc2697c1e8f802e331f Mon Sep 17 00:00:00 2001 From: Peter Mitsis Date: Tue, 9 Jan 2024 10:45:34 -0500 Subject: [PATCH 2075/3723] tests: Add thread suspend-resume SMP stress test Adds a test to stress k_thread_suspend() and k_thread_resume() on an SMP system. The test should take about 30 seconds. Signed-off-by: Peter Mitsis --- tests/kernel/smp_suspend/CMakeLists.txt | 12 ++++ tests/kernel/smp_suspend/prj.conf | 2 + tests/kernel/smp_suspend/src/main.c | 85 +++++++++++++++++++++++++ tests/kernel/smp_suspend/testcase.yaml | 6 ++ 4 files changed, 105 insertions(+) create mode 100644 tests/kernel/smp_suspend/CMakeLists.txt create mode 100644 tests/kernel/smp_suspend/prj.conf create mode 100644 tests/kernel/smp_suspend/src/main.c create mode 100644 tests/kernel/smp_suspend/testcase.yaml diff --git a/tests/kernel/smp_suspend/CMakeLists.txt b/tests/kernel/smp_suspend/CMakeLists.txt new file mode 100644 index 00000000000..f32de519289 --- /dev/null +++ b/tests/kernel/smp_suspend/CMakeLists.txt @@ -0,0 +1,12 @@ +# SPDX-License-Identifier: Apache-2.0 + +cmake_minimum_required(VERSION 3.20.0) +find_package(Zephyr REQUIRED HINTS $ENV{ZEPHYR_BASE}) +project(smp) + +target_sources(app PRIVATE src/main.c) + +target_include_directories(app PRIVATE + ${ZEPHYR_BASE}/kernel/include + ${ZEPHYR_BASE}/arch/${ARCH}/include + ) diff --git a/tests/kernel/smp_suspend/prj.conf b/tests/kernel/smp_suspend/prj.conf new file mode 100644 index 00000000000..26542e0a35c --- /dev/null +++ b/tests/kernel/smp_suspend/prj.conf @@ -0,0 +1,2 @@ +CONFIG_ZTEST=y +CONFIG_SMP=y diff --git a/tests/kernel/smp_suspend/src/main.c b/tests/kernel/smp_suspend/src/main.c new file mode 100644 index 00000000000..8ddc2854e9d --- /dev/null +++ b/tests/kernel/smp_suspend/src/main.c @@ -0,0 +1,85 @@ +/* + * Copyright (c) 2024 Intel Corporation. + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include +#include +#include + +#if CONFIG_MP_MAX_NUM_CPUS < 2 +#error "SMP test requires at least two CPUs!" +#endif + +#define STACK_SIZE 1024 + +#define NUM_THREADS 6 + +K_THREAD_STACK_ARRAY_DEFINE(thread_stack, NUM_THREADS, STACK_SIZE); +struct k_thread thread[NUM_THREADS]; + +volatile uint64_t thread_counter[NUM_THREADS]; + +static void thread_entry(void *p1, void *p2, void *p3) +{ + struct k_thread *resume_thread = p1; + unsigned int self_index = (unsigned int)(uintptr_t)p2; + + while (1) { + if (resume_thread != NULL) { + k_thread_resume(resume_thread); + } + + thread_counter[self_index]++; + + if (self_index != 0) { + k_thread_suspend(k_current_get()); + } + } +} + +ZTEST(smp_suspend_resume, test_smp_thread_suspend_resume_stress) +{ + unsigned int i; + uint64_t counter[NUM_THREADS] = {}; + + /* Create the threads */ + + printk("Starting ...\n"); + + for (i = 0; i < NUM_THREADS; i++) { + + k_thread_create(&thread[i], thread_stack[i], + STACK_SIZE, thread_entry, + i < (NUM_THREADS - 1) ? &thread[i + 1] : NULL, + (void *)(uintptr_t)i, NULL, + 10 - i, 0, K_FOREVER); + + k_thread_suspend(&thread[i]); + + k_thread_start(&thread[i]); + } + + /* + * All newly created test threads are currently in the suspend state. + * Start the first thread. + */ + + k_thread_resume(&thread[0]); + + for (unsigned int iteration = 0; iteration < 30; iteration++) { + k_sleep(K_MSEC(1000)); + + for (i = 0; i < NUM_THREADS; i++) { + zassert_false(counter[i] == thread_counter[i], + " -- Thread %u appears to be hung: %llu\n", + i, thread_counter[i]); + + counter[i] = thread_counter[i]; + + } + } +} + +ZTEST_SUITE(smp_suspend_resume, NULL, NULL, NULL, NULL, NULL); diff --git a/tests/kernel/smp_suspend/testcase.yaml b/tests/kernel/smp_suspend/testcase.yaml new file mode 100644 index 00000000000..542d6b25850 --- /dev/null +++ b/tests/kernel/smp_suspend/testcase.yaml @@ -0,0 +1,6 @@ +tests: + kernel.smp_suspend: + tags: + - kernel + - smp + filter: (CONFIG_MP_MAX_NUM_CPUS > 1) From c3a6274bf5e47a384ab2036c00450f69f5ee215e Mon Sep 17 00:00:00 2001 From: Tomasz Leman Date: Wed, 13 Dec 2023 20:39:16 +0100 Subject: [PATCH 2076/3723] intel_adsp: ace: power: Prevent HST domain power gating This patch introduces power management for the HOST (HST) domain within the Intel ADSP ACE IP. It adds macros to access the node identifier and device pointer for the HST power domain and integrates power management calls into the system initialization and power state transition functions. The patch ensures that power gating of the HST domain is prevented when the primary core of the audio DSP is active. Preventing power gating is crucial for maintaining the functionality of the HST domain while the primary DSP core is performing critical tasks. Signed-off-by: Tomasz Leman --- .../ace/include/intel_ace15_mtpm/adsp_power.h | 9 +++++++++ .../ace/include/intel_ace20_lnl/adsp_power.h | 10 ++++++++++ soc/xtensa/intel_adsp/ace/multiprocessing.c | 6 ++++++ soc/xtensa/intel_adsp/ace/power.c | 16 ++++++++++++++++ 4 files changed, 41 insertions(+) diff --git a/soc/xtensa/intel_adsp/ace/include/intel_ace15_mtpm/adsp_power.h b/soc/xtensa/intel_adsp/ace/include/intel_ace15_mtpm/adsp_power.h index 6efcde4a491..594fc414bbc 100644 --- a/soc/xtensa/intel_adsp/ace/include/intel_ace15_mtpm/adsp_power.h +++ b/soc/xtensa/intel_adsp/ace/include/intel_ace15_mtpm/adsp_power.h @@ -88,5 +88,14 @@ static ALWAYS_INLINE bool soc_cpu_is_powered(int cpu_num) return (ACE_PWRSTS->dsphpxpgs & BIT(cpu_num)) == BIT(cpu_num); } +/** + * @brief Retrieve node identifier for Intel ADSP HOST power domain. + */ +#define INTEL_ADSP_HST_DOMAIN_DTNODE DT_NODELABEL(hst_domain) + +/** + * @brief Intel ADSP HOST power domain pointer. + */ +#define INTEL_ADSP_HST_DOMAIN_DEV DEVICE_DT_GET(INTEL_ADSP_HST_DOMAIN_DTNODE) #endif /* ZEPHYR_SOC_INTEL_ADSP_POWER_H_ */ diff --git a/soc/xtensa/intel_adsp/ace/include/intel_ace20_lnl/adsp_power.h b/soc/xtensa/intel_adsp/ace/include/intel_ace20_lnl/adsp_power.h index 60631945da3..5d12c79fdcb 100644 --- a/soc/xtensa/intel_adsp/ace/include/intel_ace20_lnl/adsp_power.h +++ b/soc/xtensa/intel_adsp/ace/include/intel_ace20_lnl/adsp_power.h @@ -88,4 +88,14 @@ static ALWAYS_INLINE bool soc_cpu_is_powered(int cpu_num) return (ACE_PWRSTS->dsphpxpgs & BIT(cpu_num)) == BIT(cpu_num); } +/** + * @brief Retrieve node identifier for Intel ADSP HOST power domain. + */ +#define INTEL_ADSP_HST_DOMAIN_DTNODE DT_NODELABEL(hst_domain) + +/** + * @brief Intel ADSP HOST power domain pointer. + */ +#define INTEL_ADSP_HST_DOMAIN_DEV DEVICE_DT_GET(INTEL_ADSP_HST_DOMAIN_DTNODE) + #endif /* ZEPHYR_SOC_INTEL_ADSP_POWER_H_ */ diff --git a/soc/xtensa/intel_adsp/ace/multiprocessing.c b/soc/xtensa/intel_adsp/ace/multiprocessing.c index 750dc06d74e..08a0aab16c4 100644 --- a/soc/xtensa/intel_adsp/ace/multiprocessing.c +++ b/soc/xtensa/intel_adsp/ace/multiprocessing.c @@ -9,6 +9,7 @@ #include #include #include +#include #include #include @@ -79,6 +80,11 @@ void soc_mp_init(void) IDC[i].agents[0].ipc.ctl = BIT(0); /* IPCTBIE */ } + int ret = pm_device_runtime_get(INTEL_ADSP_HST_DOMAIN_DEV); + + ARG_UNUSED(ret); + __ASSERT_NO_MSG(ret == 0); + /* Set the core 0 active */ soc_cpus_active[0] = true; } diff --git a/soc/xtensa/intel_adsp/ace/power.c b/soc/xtensa/intel_adsp/ace/power.c index cee8047d4a2..7c50923abdd 100644 --- a/soc/xtensa/intel_adsp/ace/power.c +++ b/soc/xtensa/intel_adsp/ace/power.c @@ -5,6 +5,7 @@ */ #include #include +#include #include #include #include @@ -234,6 +235,9 @@ void pm_state_set(enum pm_state state, uint8_t substate_id) { ARG_UNUSED(substate_id); uint32_t cpu = arch_proc_id(); + int ret = 0; + + ARG_UNUSED(ret); /* save interrupt state and turn off all interrupts */ core_desc[cpu].intenable = XTENSA_RSR("INTENABLE"); @@ -296,6 +300,8 @@ void pm_state_set(enum pm_state state, uint8_t substate_id) hpsram_mask = (1 << ebb_banks) - 1; #endif /* CONFIG_ADSP_POWER_DOWN_HPSRAM */ /* do power down - this function won't return */ + ret = pm_device_runtime_put(INTEL_ADSP_HST_DOMAIN_DEV); + __ASSERT_NO_MSG(ret == 0); power_down(true, uncache_to_cache(&hpsram_mask), true); } else { @@ -311,6 +317,9 @@ void pm_state_set(enum pm_state state, uint8_t substate_id) battr |= (DSPBR_BATTR_LPSCTL_RESTORE_BOOT & LPSCTL_BATTR_MASK); DSPCS.bootctl[cpu].battr = battr; } + + ret = pm_device_runtime_put(INTEL_ADSP_HST_DOMAIN_DEV); + __ASSERT_NO_MSG(ret == 0); power_gate_entry(cpu); } else { __ASSERT(false, "invalid argument - unsupported power state"); @@ -323,6 +332,13 @@ void pm_state_exit_post_ops(enum pm_state state, uint8_t substate_id) ARG_UNUSED(substate_id); uint32_t cpu = arch_proc_id(); + if (cpu == 0) { + int ret = pm_device_runtime_get(INTEL_ADSP_HST_DOMAIN_DEV); + + ARG_UNUSED(ret); + __ASSERT_NO_MSG(ret == 0); + } + if (state == PM_STATE_SOFT_OFF) { /* restore clock gating state */ DSPCS.bootctl[cpu].bctl |= From 1c0c900cbbc395e9c8d646c419e7ab90d6900a7e Mon Sep 17 00:00:00 2001 From: Tomasz Leman Date: Wed, 13 Dec 2023 22:21:55 +0100 Subject: [PATCH 2077/3723] intel_adsp: ace15: Enhance HST domain power-down sequence This patch enhances the power-down sequence for the HOST (HST) domain within the Intel ADSP ACE 1.5 architecture. It introduces a check to ensure that a specific condition, represented by a magic key value, is met before disabling the HST domain. This additional verification step ensures that the HST domain is only powered down when it is safe to do so, thereby maintaining the stability and reliability of the system. Signed-off-by: Tomasz Leman --- drivers/power_domain/power_domain_intel_adsp.c | 15 +++++++++++++++ .../ace/include/intel_ace15_mtpm/adsp_power.h | 4 ++++ soc/xtensa/intel_adsp/ace/multiprocessing.c | 9 +++++++++ 3 files changed, 28 insertions(+) diff --git a/drivers/power_domain/power_domain_intel_adsp.c b/drivers/power_domain/power_domain_intel_adsp.c index 47828d6c744..9fa66e5ab96 100644 --- a/drivers/power_domain/power_domain_intel_adsp.c +++ b/drivers/power_domain/power_domain_intel_adsp.c @@ -9,6 +9,10 @@ #include #include +#if CONFIG_ACE_VERSION_1_5 +#include +#endif /* CONFIG_ACE_VERSION_1_5 */ + #include LOG_MODULE_REGISTER(power_domain_intel_adsp, LOG_LEVEL_INF); @@ -31,6 +35,17 @@ static int pd_intel_adsp_set_power_enable(struct pg_bits *bits, bool power_enabl return -1; } } else { +#if CONFIG_ACE_VERSION_1_5 + extern uint32_t g_key_read_holder; + + if (bits->SPA_bit == INTEL_ADSP_HST_DOMAIN_BIT) { + volatile uint32_t *key_read_ptr = z_soc_uncached_ptr(&g_key_read_holder); + uint32_t key_value = *key_read_ptr; + + if (key_value != INTEL_ADSP_ACE15_MAGIC_KEY) + return -1; + } +#endif sys_write16(sys_read16((mem_addr_t)&ACE_DfPMCCU.dfpwrctl) & ~(SPA_bit_mask), (mem_addr_t)&ACE_DfPMCCU.dfpwrctl); } diff --git a/soc/xtensa/intel_adsp/ace/include/intel_ace15_mtpm/adsp_power.h b/soc/xtensa/intel_adsp/ace/include/intel_ace15_mtpm/adsp_power.h index 594fc414bbc..4da0e07508c 100644 --- a/soc/xtensa/intel_adsp/ace/include/intel_ace15_mtpm/adsp_power.h +++ b/soc/xtensa/intel_adsp/ace/include/intel_ace15_mtpm/adsp_power.h @@ -98,4 +98,8 @@ static ALWAYS_INLINE bool soc_cpu_is_powered(int cpu_num) */ #define INTEL_ADSP_HST_DOMAIN_DEV DEVICE_DT_GET(INTEL_ADSP_HST_DOMAIN_DTNODE) +#define INTEL_ADSP_HST_DOMAIN_BIT DT_PROP(INTEL_ADSP_HST_DOMAIN_DTNODE, bit_position) + +#define INTEL_ADSP_ACE15_MAGIC_KEY 0xFFFACE15 + #endif /* ZEPHYR_SOC_INTEL_ADSP_POWER_H_ */ diff --git a/soc/xtensa/intel_adsp/ace/multiprocessing.c b/soc/xtensa/intel_adsp/ace/multiprocessing.c index 08a0aab16c4..fbdc146c6c7 100644 --- a/soc/xtensa/intel_adsp/ace/multiprocessing.c +++ b/soc/xtensa/intel_adsp/ace/multiprocessing.c @@ -26,6 +26,11 @@ #define ACE_INTC_IRQ DT_IRQN(DT_NODELABEL(ace_intc)) +#if CONFIG_ACE_VERSION_1_5 +__aligned(CONFIG_DCACHE_LINE_SIZE) uint32_t g_key_read_holder; +__aligned(CONFIG_DCACHE_LINE_SIZE) unsigned int alignment_dummy[0]; +#endif /* CONFIG_ACE_VERSION_1_5 */ + static void ipc_isr(void *arg) { uint32_t cpu_id = arch_proc_id(); @@ -87,6 +92,10 @@ void soc_mp_init(void) /* Set the core 0 active */ soc_cpus_active[0] = true; +#if CONFIG_ACE_VERSION_1_5 + g_key_read_holder = INTEL_ADSP_ACE15_MAGIC_KEY; + sys_cache_data_flush_range(&g_key_read_holder, sizeof(g_key_read_holder)); +#endif /* CONFIG_ACE_VERSION_1_5 */ } #ifdef CONFIG_ADSP_IMR_CONTEXT_SAVE From 8356ec21e5c98ddf9b9e91203ff3962e992e73e6 Mon Sep 17 00:00:00 2001 From: Flavio Ceolin Date: Tue, 9 Jan 2024 21:58:09 -0800 Subject: [PATCH 2078/3723] xtensa: mmu: Fix mmu initialization The constant used to calculate TLB entries for the way six was wrong and causing an integer overflow. Consequently only the first 512MB where being unmapped from the TLB. Signed-off-by: Flavio Ceolin --- arch/xtensa/core/mmu.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/arch/xtensa/core/mmu.c b/arch/xtensa/core/mmu.c index 45d8619654b..294a66dbc22 100644 --- a/arch/xtensa/core/mmu.c +++ b/arch/xtensa/core/mmu.c @@ -165,8 +165,8 @@ void xtensa_init_paging(uint32_t *l1_page) * initialization entries. Now we're flying free with our own * page table. */ - for (int i = 0; i < 8; i++) { - uint32_t ixtlb = (i * 0x2000000000) | XCHAL_SPANNING_WAY; + for (uint32_t i = 0; i < 8; i++) { + uint32_t ixtlb = (i * 0x20000000) | XCHAL_SPANNING_WAY; if (ixtlb != iitlb_pc) { __asm__ volatile("iitlb %0" :: "r"(ixtlb)); From 3557bfeb60eadb4a60d2b9623626cd533b641fe3 Mon Sep 17 00:00:00 2001 From: Ettore Chimenti Date: Thu, 4 Jan 2024 12:36:08 +0100 Subject: [PATCH 2079/3723] boards: stm32f3_seco_d23: update name and refs Due to board name change (JUNO -> SBC-3.5-PX30), it is necessary to update board names, links and references in files and documentation. Signed-off-by: Ettore Chimenti --- boards/arm/stm32f3_seco_d23/Kconfig.board | 4 +- boards/arm/stm32f3_seco_d23/Kconfig.defconfig | 2 +- boards/arm/stm32f3_seco_d23/doc/index.rst | 44 +++++++++---------- .../arm/stm32f3_seco_d23/stm32f3_seco_d23.dts | 2 +- .../stm32f3_seco_d23/stm32f3_seco_d23.yaml | 2 +- .../stm32f3_seco_d23_defconfig | 2 +- .../arm/stm32f3_seco_d23/support/openocd.cfg | 2 +- 7 files changed, 29 insertions(+), 29 deletions(-) diff --git a/boards/arm/stm32f3_seco_d23/Kconfig.board b/boards/arm/stm32f3_seco_d23/Kconfig.board index d745a9ce8d0..94536f8f05e 100644 --- a/boards/arm/stm32f3_seco_d23/Kconfig.board +++ b/boards/arm/stm32f3_seco_d23/Kconfig.board @@ -1,8 +1,8 @@ -# SECO SBC-D23 board configuration +# SECO SBC-3.5-PX30 board configuration # Copyright (c) 2022, SECO Spa # SPDX-License-Identifier: Apache-2.0 config BOARD_STM32F3_SECO_D23 - bool "SECO JUNO SBC-D23 (STM32F302VC) Board" + bool "SECO SBC-3.5-PX30 (STM32F302VC) Board" depends on SOC_STM32F302XC diff --git a/boards/arm/stm32f3_seco_d23/Kconfig.defconfig b/boards/arm/stm32f3_seco_d23/Kconfig.defconfig index f83d9615416..4af3bbc0022 100644 --- a/boards/arm/stm32f3_seco_d23/Kconfig.defconfig +++ b/boards/arm/stm32f3_seco_d23/Kconfig.defconfig @@ -1,4 +1,4 @@ -# SECO SBC-D23 board configuration +# SECO SBC-3.5-PX30 board configuration # Copyright (c) 2022, SECO Spa # SPDX-License-Identifier: Apache-2.0 diff --git a/boards/arm/stm32f3_seco_d23/doc/index.rst b/boards/arm/stm32f3_seco_d23/doc/index.rst index 410e2ecea14..90981205b5b 100644 --- a/boards/arm/stm32f3_seco_d23/doc/index.rst +++ b/boards/arm/stm32f3_seco_d23/doc/index.rst @@ -1,12 +1,12 @@ .. _stm32f3_seco_d23_board: -SECO JUNO SBC-D23 (STM32F302) -############################# +SECO SBC-3.5-PX30 (JUNO - D23) (STM32F302) +########################################## Overview ******** -JUNO (SBC-D23) is a Single Board Computer based on embedded Rockchip PX30 +SBC-3.5-PX30 (JUNO - D23) is a Single Board Computer based on embedded Rockchip PX30 Processor, featuring Quad-Core ARM Cortex-A35 processor. The processor integrates a Mali-G31 GPU with High performance dedicated 2D processor, supporting OpenGL ES 1.1 / 2.0 / 3.2, Vulkan 1.0, OpenCL 2.0 and Open VG 1.1. @@ -18,20 +18,20 @@ HDMI are supported. The RMII interface and Micrel KSZ8091 Ethernet Transceiver allow the implementation of a Fast Ethernet interface. The networking capabilities can be extended by WiFi+BT M.2 module and external modem module. The audio functionalities are managed by the AudioCodec embedded in the RK-809 -PMIC. The JUNO board is completed by a series of connectors with various +PMIC. SBC-3.5-PX30 board is completed by a series of connectors with various interfaces (UART, SPI, I2C) managed by the microcontroller STM32F302VCT6. .. image:: img/stm32f3_seco_d23.jpg :align: center - :alt: SECO JUNO + :alt: SECO SBC-3.5-PX30 More information about the board can be found at the -`SECO JUNO SBC-D23 website`_. +`SECO SBC-3.5-PX30 website`_. Hardware ******** -SECO JUNO SBC-D23 provides the following hardware components: +SECO SBC-3.5-PX30 provides the following hardware components: - STM32F302VCT6 - ARM |reg| 32-bit Cortex |reg| -M4 CPU with FPU @@ -93,10 +93,10 @@ Other hardware features are not yet supported on Zephyr porting. Pin Mapping =========== -SECO-D23 has 6 GPIO controllers. These controllers are +SBC-3.5-PX30 has 6 GPIO controllers. These controllers are responsible for pin muxing, input/output, pull-up, etc. -For more details please refer to `SECO JUNO SBC-D23 board User Manual`_. +For more details please refer to `SECO SBC-3.5-PX30 board User Manual`_. Default Zephyr Peripheral Mapping: ---------------------------------- @@ -142,14 +142,14 @@ Default Zephyr Peripheral Mapping: System Clock ============ -SECO SBC-D23 System Clock could be driven by internal or external +SECO SBC-3.5-PX30 System Clock could be driven by internal or external oscillator, as well as main PLL clock. By default System clock is driven by PLL clock at 72 MHz, driven by an external oscillator at 8 MHz. Serial Port =========== -SECO SBC-D23 has up to 4 U(S)ARTs. The Zephyr console output +SECO SBC-3.5-PX30 has up to 4 U(S)ARTs. The Zephyr console output is assigned to UART1. Default settings are 115200 8N1. In debug configuration UART1 is connected to the flashing connector CN56. @@ -161,22 +161,22 @@ UART1 (in alternate config) and UART5 are connected to CN32. I2C === -SECO SBC-D23 has up to 2 I2Cs. Both are present in connector CN33. +SECO SBC-3.5-PX30 has up to 2 I2Cs. Both are present in connector CN33. I2C2 is available only on boards where DEBUG serial is not connected. USB === -SECO SBC-D23 has a USB 2.0 full-speed device interface available through +SECO SBC-3.5-PX30 has a USB 2.0 full-speed device interface available through its connector CN31. CAN === -SECO SBC-D23 has an onboard CAN transceiver (TJA1051T), and it is +SECO SBC-3.5-PX30 has an onboard CAN transceiver (TJA1051T), and it is connected to both CN29 and CN30. PD0 is connected to EC_CAN_STBY. SPI === -SECO SBC-D23 has two SPI lines: SPI1 is an internal SPI line connected to the +SECO SBC-3.5-PX30 has two SPI lines: SPI1 is an internal SPI line connected to the main processor (Rockchip PX30) and SPI2 is connected to CN39. Programming and Debugging @@ -189,10 +189,10 @@ Applications for the ``stm32f3_seco_d23`` board configuration can be built and flashed in the usual way (see :ref:`build_an_application` and :ref:`application_run` for more details). -Flashing an application to SECO SBC-D23 -------------------------------------------- +Flashing an application to SECO SBC-3.5-PX30 +-------------------------------------------- -First, connect the SECO SBC-D23 to your host computer using +First, connect the SECO SBC-3.5-PX30 to your host computer using CN56 connector to an ST-Link. The pinout is (1-8): - VDD @@ -219,7 +219,7 @@ Run a serial host program to connect with your board. $ minicom -D /dev/ -Replace with the port where the SBC-D23 board can be +Replace with the port where the SBC-3.5-PX30 board can be found. You should see the following message on the console: @@ -229,10 +229,10 @@ You should see the following message on the console: Hello World! stm32f3_seco_d23 -.. _SECO JUNO SBC-D23 website: - https://edge.seco.com/juno.html +.. _SECO SBC-3.5-PX30 website: + https://edge.seco.com/sbc-3-5-px30.html -.. _SECO JUNO SBC-D23 board User Manual: +.. _SECO SBC-3.5-PX30 board User Manual: https://www.seco.com/Manuals/SBC-D23_Manual.pdf .. _STM32F302VC on www.st.com: diff --git a/boards/arm/stm32f3_seco_d23/stm32f3_seco_d23.dts b/boards/arm/stm32f3_seco_d23/stm32f3_seco_d23.dts index dd100b28865..79577593ddb 100644 --- a/boards/arm/stm32f3_seco_d23/stm32f3_seco_d23.dts +++ b/boards/arm/stm32f3_seco_d23/stm32f3_seco_d23.dts @@ -9,7 +9,7 @@ #include / { - model = "SECO JUNO SBC-D23 board (STM32F302VCT6)"; + model = "SECO SBC-3.5-PX30 board (STM32F302VCT6)"; compatible = "seco,stm32f3-d23"; chosen { diff --git a/boards/arm/stm32f3_seco_d23/stm32f3_seco_d23.yaml b/boards/arm/stm32f3_seco_d23/stm32f3_seco_d23.yaml index 8ca0b339122..469523eadc2 100644 --- a/boards/arm/stm32f3_seco_d23/stm32f3_seco_d23.yaml +++ b/boards/arm/stm32f3_seco_d23/stm32f3_seco_d23.yaml @@ -1,5 +1,5 @@ identifier: stm32f3_seco_d23 -name: SECO JUNO SBC-D23 (STM32F302) +name: SECO SBC-3.5-PX30 (STM32F302) type: mcu arch: arm toolchain: diff --git a/boards/arm/stm32f3_seco_d23/stm32f3_seco_d23_defconfig b/boards/arm/stm32f3_seco_d23/stm32f3_seco_d23_defconfig index c8038a6da72..344746567ad 100644 --- a/boards/arm/stm32f3_seco_d23/stm32f3_seco_d23_defconfig +++ b/boards/arm/stm32f3_seco_d23/stm32f3_seco_d23_defconfig @@ -1,5 +1,5 @@ # SPDX-License-Identifier: Apache-2.0 -# SECO SBC-D23 board defconfig +# SECO SBC-3.5-PX30 board defconfig # # Copyright (c) 2022, SECO Spa diff --git a/boards/arm/stm32f3_seco_d23/support/openocd.cfg b/boards/arm/stm32f3_seco_d23/support/openocd.cfg index 69be74a0766..8d66962a35f 100644 --- a/boards/arm/stm32f3_seco_d23/support/openocd.cfg +++ b/boards/arm/stm32f3_seco_d23/support/openocd.cfg @@ -1,4 +1,4 @@ -# SECO JUNO SBC-D23 board with a single STM32F302VCT6 chip +# SECO SBC-3.5-PX30 board with a single STM32F302VCT6 chip # Flashing is possible by connecting the board to an ST-Link via SWD # https://edge.seco.com/juno.html From fcef0607ca66cb28e558cb961ff31d8084280c9e Mon Sep 17 00:00:00 2001 From: Henrik Brix Andersen Date: Wed, 10 Jan 2024 12:55:14 +0100 Subject: [PATCH 2080/3723] boards: arm: nucleo_g0b1re: list FDCAN1 as supported in the docs List FDCAN1 as supported in the board documentation. Fixes: #67087 Signed-off-by: Henrik Brix Andersen --- boards/arm/nucleo_g0b1re/doc/index.rst | 3 +++ 1 file changed, 3 insertions(+) diff --git a/boards/arm/nucleo_g0b1re/doc/index.rst b/boards/arm/nucleo_g0b1re/doc/index.rst index 7ca35bd7511..00a3c94b110 100644 --- a/boards/arm/nucleo_g0b1re/doc/index.rst +++ b/boards/arm/nucleo_g0b1re/doc/index.rst @@ -108,6 +108,8 @@ The Zephyr nucleo_g0b1re board configuration supports the following hardware fea +-----------+------------+-------------------------------------+ | die-temp | on-chip | die temperature sensor | +-----------+------------+-------------------------------------+ +| FDCAN1 | on-chip | CAN controller | ++-----------+------------+-------------------------------------+ Other hardware features are not yet supported in this Zephyr port. @@ -137,6 +139,7 @@ Default Zephyr Peripheral Mapping: - ADC1 IN0 : PA0 - ADC1 IN1 : PA1 - DAC1_OUT1 : PA4 +- FDCAN1 RX/TX: PA11/PA12 For more details please refer to `STM32 Nucleo-64 board User Manual`_. From 735c9e23ec80cd0c6beaafb21d01f9223fdb5bd9 Mon Sep 17 00:00:00 2001 From: Henrik Brix Andersen Date: Wed, 10 Jan 2024 12:56:36 +0100 Subject: [PATCH 2081/3723] boards: arm: nucleo_g474re: list FDCAN1 as supported in the docs List FDCAN1 as supported in the board documentation. Fixes: #67087 Signed-off-by: Henrik Brix Andersen --- boards/arm/nucleo_g474re/doc/index.rst | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/boards/arm/nucleo_g474re/doc/index.rst b/boards/arm/nucleo_g474re/doc/index.rst index 6705e20fd78..87fca388905 100644 --- a/boards/arm/nucleo_g474re/doc/index.rst +++ b/boards/arm/nucleo_g474re/doc/index.rst @@ -127,6 +127,8 @@ The Zephyr nucleo_g474re board configuration supports the following hardware fea +-----------+------------+-------------------------------------+ | die-temp | on-chip | die temperature sensor | +-----------+------------+-------------------------------------+ +| FDCAN1 | on-chip | CAN controller | ++-----------+------------+-------------------------------------+ Other hardware features are not yet supported on this Zephyr port. @@ -171,6 +173,8 @@ Default Zephyr Peripheral Mapping: - LD2 : PA5 - ADC1_IN1 : PA0 - DAC1_OUT1 : PA4 +- FDCAN1_RX: PA11 +- FDCAN1_TX: PA12 System Clock ------------ From 73da1e80f4c7ca102f17bb2cab9e444a1e8a1303 Mon Sep 17 00:00:00 2001 From: Yong Cong Sin Date: Tue, 26 Dec 2023 18:31:52 +0800 Subject: [PATCH 2082/3723] posix: signal: implement `sigprocmask()` Implement `sigprocmask()` by simply redirecting call to the `pthread_sigmask()` as they are identical. Signed-off-by: Yong Cong Sin --- include/zephyr/posix/signal.h | 1 + lib/posix/signal.c | 18 ++++++++++++++++++ tests/posix/headers/src/signal_h.c | 2 +- 3 files changed, 20 insertions(+), 1 deletion(-) diff --git a/include/zephyr/posix/signal.h b/include/zephyr/posix/signal.h index 327ca20edc0..d22ac34c48d 100644 --- a/include/zephyr/posix/signal.h +++ b/include/zephyr/posix/signal.h @@ -99,6 +99,7 @@ int sigfillset(sigset_t *set); int sigaddset(sigset_t *set, int signo); int sigdelset(sigset_t *set, int signo); int sigismember(const sigset_t *set, int signo); +int sigprocmask(int how, const sigset_t *ZRESTRICT set, sigset_t *ZRESTRICT oset); int pthread_sigmask(int how, const sigset_t *ZRESTRICT set, sigset_t *ZRESTRICT oset); #endif /* CONFIG_POSIX_SIGNAL */ diff --git a/lib/posix/signal.c b/lib/posix/signal.c index d2153238ff8..f14ef7fe614 100644 --- a/lib/posix/signal.c +++ b/lib/posix/signal.c @@ -100,3 +100,21 @@ char *strsignal(int signum) return buf; } + +int sigprocmask(int how, const sigset_t *ZRESTRICT set, sigset_t *ZRESTRICT oset) +{ + if (!IS_ENABLED(CONFIG_MULTITHREADING)) { + return pthread_sigmask(how, set, oset); + } + + /* + * Until Zephyr supports processes and specifically querying the number of active threads in + * a process For more information, see + * https://pubs.opengroup.org/onlinepubs/9699919799/functions/pthread_sigmask.html + */ + __ASSERT(false, "In multi-threaded environments, please use pthread_sigmask() instead of " + "%s()", __func__); + + errno = ENOSYS; + return -1; +} diff --git a/tests/posix/headers/src/signal_h.c b/tests/posix/headers/src/signal_h.c index 58c17dd623e..9d0be5778d7 100644 --- a/tests/posix/headers/src/signal_h.c +++ b/tests/posix/headers/src/signal_h.c @@ -164,6 +164,7 @@ ZTEST(posix_headers, test_signal_h) zassert_not_null(sigdelset); zassert_not_null(sigismember); zassert_not_null(strsignal); + zassert_not_null(sigprocmask); zassert_not_null(pthread_sigmask); #endif /* CONFIG_POSIX_SIGNAL */ @@ -182,7 +183,6 @@ ZTEST(posix_headers, test_signal_h) /* zassert_not_null(signal); */ /* not implemented */ /* zassert_not_null(sigpause); */ /* not implemented */ /* zassert_not_null(sigpending); */ /* not implemented */ - /* zassert_not_null(sigprocmask); */ /* not implemented */ /* zassert_not_null(sigqueue); */ /* not implemented */ /* zassert_not_null(sigrelse); */ /* not implemented */ /* zassert_not_null(sigset); */ /* not implemented */ From b42e362fa8ac092366b8368ecac16e4fb3ef8824 Mon Sep 17 00:00:00 2001 From: Yong Cong Sin Date: Thu, 4 Jan 2024 11:21:33 +0800 Subject: [PATCH 2083/3723] tests: posix: pthread: add test for `sigprocmask()` Refactor the existing `pthread_sigmask` test function to get its function-under-test via arg and test `sigprocmask` with that. Signed-off-by: Yong Cong Sin --- tests/posix/common/src/signal.c | 51 +++++++++++++++++++++------------ 1 file changed, 33 insertions(+), 18 deletions(-) diff --git a/tests/posix/common/src/signal.c b/tests/posix/common/src/signal.c index 5fc7cd16e48..92017ad4cde 100644 --- a/tests/posix/common/src/signal.c +++ b/tests/posix/common/src/signal.c @@ -219,7 +219,8 @@ ZTEST(posix_apis, test_signal_strsignal) #endif } -static void *test_pthread_sigmask_entry(void *arg) +typedef int (*sigmask_fn)(int how, const sigset_t *set, sigset_t *oset); +static void *test_sigmask_entry(void *arg) { /* for clarity */ #define SIG_GETMASK SIG_SETMASK @@ -230,68 +231,67 @@ static void *test_pthread_sigmask_entry(void *arg) }; static sigset_t set[2]; const int invalid_how = 0x9a2ba9e; - - ARG_UNUSED(arg); + sigmask_fn sigmask = arg; /* invalid how results in EINVAL */ - zassert_equal(pthread_sigmask(invalid_how, NULL, NULL), EINVAL); - zassert_equal(pthread_sigmask(invalid_how, &set[NEW], &set[OLD]), EINVAL); + zassert_equal(sigmask(invalid_how, NULL, NULL), EINVAL); + zassert_equal(sigmask(invalid_how, &set[NEW], &set[OLD]), EINVAL); /* verify setting / getting masks */ zassert_ok(sigemptyset(&set[NEW])); - zassert_ok(pthread_sigmask(SIG_SETMASK, &set[NEW], NULL)); + zassert_ok(sigmask(SIG_SETMASK, &set[NEW], NULL)); zassert_ok(sigfillset(&set[OLD])); - zassert_ok(pthread_sigmask(SIG_GETMASK, NULL, &set[OLD])); + zassert_ok(sigmask(SIG_GETMASK, NULL, &set[OLD])); zassert_mem_equal(&set[OLD], &set[NEW], sizeof(set[OLD])); zassert_ok(sigfillset(&set[NEW])); - zassert_ok(pthread_sigmask(SIG_SETMASK, &set[NEW], NULL)); + zassert_ok(sigmask(SIG_SETMASK, &set[NEW], NULL)); zassert_ok(sigemptyset(&set[OLD])); - zassert_ok(pthread_sigmask(SIG_GETMASK, NULL, &set[OLD])); + zassert_ok(sigmask(SIG_GETMASK, NULL, &set[OLD])); zassert_mem_equal(&set[OLD], &set[NEW], sizeof(set[OLD])); /* start with an empty mask */ zassert_ok(sigemptyset(&set[NEW])); - zassert_ok(pthread_sigmask(SIG_SETMASK, &set[NEW], NULL)); + zassert_ok(sigmask(SIG_SETMASK, &set[NEW], NULL)); /* verify SIG_BLOCK: expect (SIGUSR1 | SIGUSR2 | SIGHUP) */ zassert_ok(sigemptyset(&set[NEW])); zassert_ok(sigaddset(&set[NEW], SIGUSR1)); - zassert_ok(pthread_sigmask(SIG_BLOCK, &set[NEW], NULL)); + zassert_ok(sigmask(SIG_BLOCK, &set[NEW], NULL)); zassert_ok(sigemptyset(&set[NEW])); zassert_ok(sigaddset(&set[NEW], SIGUSR2)); zassert_ok(sigaddset(&set[NEW], SIGHUP)); - zassert_ok(pthread_sigmask(SIG_BLOCK, &set[NEW], NULL)); + zassert_ok(sigmask(SIG_BLOCK, &set[NEW], NULL)); zassert_ok(sigemptyset(&set[OLD])); zassert_ok(sigaddset(&set[OLD], SIGUSR1)); zassert_ok(sigaddset(&set[OLD], SIGUSR2)); zassert_ok(sigaddset(&set[OLD], SIGHUP)); - zassert_ok(pthread_sigmask(SIG_GETMASK, NULL, &set[NEW])); + zassert_ok(sigmask(SIG_GETMASK, NULL, &set[NEW])); zassert_mem_equal(&set[NEW], &set[OLD], sizeof(set[NEW])); /* start with full mask */ zassert_ok(sigfillset(&set[NEW])); - zassert_ok(pthread_sigmask(SIG_SETMASK, &set[NEW], NULL)); + zassert_ok(sigmask(SIG_SETMASK, &set[NEW], NULL)); /* verify SIG_UNBLOCK: expect ~(SIGUSR1 | SIGUSR2 | SIGHUP) */ zassert_ok(sigemptyset(&set[NEW])); zassert_ok(sigaddset(&set[NEW], SIGUSR1)); - zassert_ok(pthread_sigmask(SIG_UNBLOCK, &set[NEW], NULL)); + zassert_ok(sigmask(SIG_UNBLOCK, &set[NEW], NULL)); zassert_ok(sigemptyset(&set[NEW])); zassert_ok(sigaddset(&set[NEW], SIGUSR2)); zassert_ok(sigaddset(&set[NEW], SIGHUP)); - zassert_ok(pthread_sigmask(SIG_UNBLOCK, &set[NEW], NULL)); + zassert_ok(sigmask(SIG_UNBLOCK, &set[NEW], NULL)); zassert_ok(sigfillset(&set[OLD])); zassert_ok(sigdelset(&set[OLD], SIGUSR1)); zassert_ok(sigdelset(&set[OLD], SIGUSR2)); zassert_ok(sigdelset(&set[OLD], SIGHUP)); - zassert_ok(pthread_sigmask(SIG_GETMASK, NULL, &set[NEW])); + zassert_ok(sigmask(SIG_GETMASK, NULL, &set[NEW])); zassert_mem_equal(&set[NEW], &set[OLD], sizeof(set[NEW])); return NULL; @@ -301,6 +301,21 @@ ZTEST(posix_apis, test_pthread_sigmask) { pthread_t th; - zassert_ok(pthread_create(&th, NULL, test_pthread_sigmask_entry, NULL)); + zassert_ok(pthread_create(&th, NULL, test_sigmask_entry, pthread_sigmask)); zassert_ok(pthread_join(th, NULL)); } + +ZTEST(posix_apis, test_sigprocmask) +{ + if (IS_ENABLED(CONFIG_MULTITHREADING)) { + if (!IS_ENABLED(CONFIG_ASSERT)) { + zassert_not_ok(sigprocmask(SIG_SETMASK, NULL, NULL)); + zassert_equal(errno, ENOSYS); + } + } else { + pthread_t th; + + zassert_ok(pthread_create(&th, NULL, test_sigmask_entry, sigprocmask)); + zassert_ok(pthread_join(th, NULL)); + } +} From f82b64504cf5c1a1ccd23a52c0d439c75b16a9f4 Mon Sep 17 00:00:00 2001 From: Yong Cong Sin Date: Tue, 2 Jan 2024 10:36:57 +0800 Subject: [PATCH 2084/3723] doc: posix: signal: mark `sigprocmask` as supported `sigprocmask()` is now implemented, mark it so. Signed-off-by: Yong Cong Sin --- doc/services/portability/posix/option_groups/index.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/doc/services/portability/posix/option_groups/index.rst b/doc/services/portability/posix/option_groups/index.rst index 47fc9ebd0f9..e884712ae89 100644 --- a/doc/services/portability/posix/option_groups/index.rst +++ b/doc/services/portability/posix/option_groups/index.rst @@ -197,7 +197,7 @@ required for error and event handling. sigismember(),yes signal(), sigpending(), - sigprocmask(), + sigprocmask(),yes igsuspend(), sigwait(), strsignal(),yes From 768ed260101ff30221f7b95dca00dc7ba93097e5 Mon Sep 17 00:00:00 2001 From: Yong Cong Sin Date: Thu, 4 Jan 2024 11:24:48 +0800 Subject: [PATCH 2085/3723] doc: posix: signal: fix `sigsuspend` typo The `sigsuspend` is currently `igsuspend`, fix that. Signed-off-by: Yong Cong Sin --- doc/services/portability/posix/option_groups/index.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/doc/services/portability/posix/option_groups/index.rst b/doc/services/portability/posix/option_groups/index.rst index e884712ae89..2a1eefdc0a1 100644 --- a/doc/services/portability/posix/option_groups/index.rst +++ b/doc/services/portability/posix/option_groups/index.rst @@ -198,7 +198,7 @@ required for error and event handling. signal(), sigpending(), sigprocmask(),yes - igsuspend(), + sigsuspend(), sigwait(), strsignal(),yes From 06b57926a2a6ea39e7485a6e69c4264f578c939b Mon Sep 17 00:00:00 2001 From: Brian Juel Folkmann Date: Fri, 5 Jan 2024 09:10:31 +0100 Subject: [PATCH 2086/3723] drivers: adc: stm32: Fix race condition with internal channels When using one of the internal channels (die_temp, vbat, vref) the channels are enabled in the individual drivers and disabled again whenever an adc conversion is complete. This creates a race condition if the ADC is used from multiple threads. This commit moves the disabling of the channels to the individual drivers. Signed-off-by: Brian Juel Folkmann --- drivers/adc/adc_stm32.c | 4 ---- drivers/sensor/stm32_temp/stm32_temp.c | 9 ++++++++- drivers/sensor/stm32_vbat/stm32_vbat.c | 8 +++++++- drivers/sensor/stm32_vref/stm32_vref.c | 10 +++++++++- 4 files changed, 24 insertions(+), 7 deletions(-) diff --git a/drivers/adc/adc_stm32.c b/drivers/adc/adc_stm32.c index f456c78acb6..abc5a7514b6 100644 --- a/drivers/adc/adc_stm32.c +++ b/drivers/adc/adc_stm32.c @@ -1087,10 +1087,6 @@ static void adc_context_on_complete(struct adc_context *ctx, int status) /* Reset acquisition time used for the sequence */ data->acq_time_index = -1; - /* Reset internal channels */ - LL_ADC_SetCommonPathInternalCh(__LL_ADC_COMMON_INSTANCE(adc), - LL_ADC_PATH_INTERNAL_NONE); - #if defined(CONFIG_SOC_SERIES_STM32H7X) || defined(CONFIG_SOC_SERIES_STM32U5X) /* Reset channel preselection register */ LL_ADC_SetChannelPreselection(adc, 0); diff --git a/drivers/sensor/stm32_temp/stm32_temp.c b/drivers/sensor/stm32_temp/stm32_temp.c index 7ad72490e91..5e594b0fe0c 100644 --- a/drivers/sensor/stm32_temp/stm32_temp.c +++ b/drivers/sensor/stm32_temp/stm32_temp.c @@ -67,6 +67,7 @@ static int stm32_temp_sample_fetch(const struct device *dev, enum sensor_channel struct stm32_temp_data *data = dev->data; struct adc_sequence *sp = &data->adc_seq; int rc; + uint32_t path; if (chan != SENSOR_CHAN_ALL && chan != SENSOR_CHAN_DIE_TEMP) { return -ENOTSUP; @@ -80,8 +81,10 @@ static int stm32_temp_sample_fetch(const struct device *dev, enum sensor_channel goto unlock; } + path = LL_ADC_GetCommonPathInternalCh(__LL_ADC_COMMON_INSTANCE(data->adc_base)); LL_ADC_SetCommonPathInternalCh(__LL_ADC_COMMON_INSTANCE(data->adc_base), - LL_ADC_PATH_INTERNAL_TEMPSENSOR); + LL_ADC_PATH_INTERNAL_TEMPSENSOR | path); + k_usleep(LL_ADC_DELAY_TEMPSENSOR_STAB_US); rc = adc_read(data->adc, sp); @@ -89,6 +92,10 @@ static int stm32_temp_sample_fetch(const struct device *dev, enum sensor_channel data->raw = data->sample_buffer; } + path = LL_ADC_GetCommonPathInternalCh(__LL_ADC_COMMON_INSTANCE(data->adc_base)); + LL_ADC_SetCommonPathInternalCh(__LL_ADC_COMMON_INSTANCE(data->adc_base), + path &= ~LL_ADC_PATH_INTERNAL_TEMPSENSOR); + unlock: k_mutex_unlock(&data->mutex); diff --git a/drivers/sensor/stm32_vbat/stm32_vbat.c b/drivers/sensor/stm32_vbat/stm32_vbat.c index 10c035baacf..8379670fab3 100644 --- a/drivers/sensor/stm32_vbat/stm32_vbat.c +++ b/drivers/sensor/stm32_vbat/stm32_vbat.c @@ -38,6 +38,7 @@ static int stm32_vbat_sample_fetch(const struct device *dev, enum sensor_channel struct stm32_vbat_data *data = dev->data; struct adc_sequence *sp = &data->adc_seq; int rc; + uint32_t path; if (chan != SENSOR_CHAN_ALL && chan != SENSOR_CHAN_VOLTAGE) { return -ENOTSUP; @@ -52,14 +53,19 @@ static int stm32_vbat_sample_fetch(const struct device *dev, enum sensor_channel goto unlock; } + path = LL_ADC_GetCommonPathInternalCh(__LL_ADC_COMMON_INSTANCE(data->adc_base)); LL_ADC_SetCommonPathInternalCh(__LL_ADC_COMMON_INSTANCE(data->adc_base), - LL_ADC_PATH_INTERNAL_VBAT); + LL_ADC_PATH_INTERNAL_VBAT | path); rc = adc_read(data->adc, sp); if (rc == 0) { data->raw = data->sample_buffer; } + path = LL_ADC_GetCommonPathInternalCh(__LL_ADC_COMMON_INSTANCE(data->adc_base)); + LL_ADC_SetCommonPathInternalCh(__LL_ADC_COMMON_INSTANCE(data->adc_base), + path &= ~LL_ADC_PATH_INTERNAL_VBAT); + unlock: k_mutex_unlock(&data->mutex); diff --git a/drivers/sensor/stm32_vref/stm32_vref.c b/drivers/sensor/stm32_vref/stm32_vref.c index 4dcb8324076..3532d2aeddd 100644 --- a/drivers/sensor/stm32_vref/stm32_vref.c +++ b/drivers/sensor/stm32_vref/stm32_vref.c @@ -38,6 +38,7 @@ static int stm32_vref_sample_fetch(const struct device *dev, enum sensor_channel struct stm32_vref_data *data = dev->data; struct adc_sequence *sp = &data->adc_seq; int rc; + uint32_t path; if (chan != SENSOR_CHAN_ALL && chan != SENSOR_CHAN_VOLTAGE) { return -ENOTSUP; @@ -51,8 +52,10 @@ static int stm32_vref_sample_fetch(const struct device *dev, enum sensor_channel goto unlock; } + path = LL_ADC_GetCommonPathInternalCh(__LL_ADC_COMMON_INSTANCE(data->adc_base)); LL_ADC_SetCommonPathInternalCh(__LL_ADC_COMMON_INSTANCE(data->adc_base), - LL_ADC_PATH_INTERNAL_VREFINT); + LL_ADC_PATH_INTERNAL_VREFINT | path); + #ifdef LL_ADC_DELAY_VREFINT_STAB_US k_usleep(LL_ADC_DELAY_VREFINT_STAB_US); #endif @@ -62,6 +65,11 @@ static int stm32_vref_sample_fetch(const struct device *dev, enum sensor_channel data->raw = data->sample_buffer; } + path = LL_ADC_GetCommonPathInternalCh(__LL_ADC_COMMON_INSTANCE(data->adc_base)); + LL_ADC_SetCommonPathInternalCh(__LL_ADC_COMMON_INSTANCE(data->adc_base), + path &= ~LL_ADC_PATH_INTERNAL_VREFINT); + + unlock: k_mutex_unlock(&data->mutex); From 3debfc8c8d4d224d92be35786fd9774f6030580a Mon Sep 17 00:00:00 2001 From: Bjarki Arge Andreasen Date: Tue, 9 Jan 2024 15:13:57 +0100 Subject: [PATCH 2087/3723] modem: cmux: Simplify resync mechanism Some modems don't start sending resync flags as described in 3G TS 27.010 V2.0.0 5.2.5, which results in the CMUX being stuck in resync mode for said modems. This patch simplifies the resync mechanism to simply drop invalid frames, and wait for atleast two consequtive frame flags (stop+start). Signed-off-by: Bjarki Arge Andreasen --- include/zephyr/modem/cmux.h | 5 +--- subsys/modem/modem_cmux.c | 46 +++++++------------------------------ 2 files changed, 9 insertions(+), 42 deletions(-) diff --git a/include/zephyr/modem/cmux.h b/include/zephyr/modem/cmux.h index 4562cb544d9..58959d6136b 100644 --- a/include/zephyr/modem/cmux.h +++ b/include/zephyr/modem/cmux.h @@ -63,10 +63,7 @@ enum modem_cmux_state { enum modem_cmux_receive_state { MODEM_CMUX_RECEIVE_STATE_SOF = 0, - MODEM_CMUX_RECEIVE_STATE_RESYNC_0, - MODEM_CMUX_RECEIVE_STATE_RESYNC_1, - MODEM_CMUX_RECEIVE_STATE_RESYNC_2, - MODEM_CMUX_RECEIVE_STATE_RESYNC_3, + MODEM_CMUX_RECEIVE_STATE_RESYNC, MODEM_CMUX_RECEIVE_STATE_ADDRESS, MODEM_CMUX_RECEIVE_STATE_ADDRESS_CONT, MODEM_CMUX_RECEIVE_STATE_CONTROL, diff --git a/subsys/modem/modem_cmux.c b/subsys/modem/modem_cmux.c index 258f969c498..472d1a7149a 100644 --- a/subsys/modem/modem_cmux.c +++ b/subsys/modem/modem_cmux.c @@ -642,13 +642,6 @@ static void modem_cmux_on_frame(struct modem_cmux *cmux) modem_cmux_on_dlci_frame(cmux); } -static void modem_cmux_transmit_resync(struct modem_cmux *cmux) -{ - static const uint8_t resync[3] = {0xF9, 0xF9, 0xF9}; - - modem_pipe_transmit(cmux->pipe, resync, sizeof(resync)); -} - static void modem_cmux_process_received_byte(struct modem_cmux *cmux, uint8_t byte) { uint8_t fcs; @@ -656,46 +649,23 @@ static void modem_cmux_process_received_byte(struct modem_cmux *cmux, uint8_t by switch (cmux->receive_state) { case MODEM_CMUX_RECEIVE_STATE_SOF: if (byte == 0xF9) { - cmux->receive_state = MODEM_CMUX_RECEIVE_STATE_ADDRESS; + cmux->receive_state = MODEM_CMUX_RECEIVE_STATE_RESYNC; break; } - modem_cmux_transmit_resync(cmux); - cmux->receive_state = MODEM_CMUX_RECEIVE_STATE_RESYNC_0; - break; - - case MODEM_CMUX_RECEIVE_STATE_RESYNC_0: - if (byte == 0xF9) { - cmux->receive_state = MODEM_CMUX_RECEIVE_STATE_RESYNC_1; - } - - break; - - case MODEM_CMUX_RECEIVE_STATE_RESYNC_1: - if (byte == 0xF9) { - cmux->receive_state = MODEM_CMUX_RECEIVE_STATE_RESYNC_2; - } else { - modem_cmux_transmit_resync(cmux); - cmux->receive_state = MODEM_CMUX_RECEIVE_STATE_RESYNC_0; - } - break; - case MODEM_CMUX_RECEIVE_STATE_RESYNC_2: - if (byte == 0xF9) { - cmux->receive_state = MODEM_CMUX_RECEIVE_STATE_RESYNC_3; - } else { - modem_cmux_transmit_resync(cmux); - cmux->receive_state = MODEM_CMUX_RECEIVE_STATE_RESYNC_0; - } - - break; - - case MODEM_CMUX_RECEIVE_STATE_RESYNC_3: + case MODEM_CMUX_RECEIVE_STATE_RESYNC: + /* + * Allow any number of consequtive flags (0xF9). + * 0xF9 could also be a valid address field for DLCI 62. + */ if (byte == 0xF9) { break; } + __fallthrough; + case MODEM_CMUX_RECEIVE_STATE_ADDRESS: /* Initialize */ cmux->receive_buf_len = 0; From 7d7f7aaf03fd0728d298dce22c20cb3098c3d0aa Mon Sep 17 00:00:00 2001 From: Bjarki Arge Andreasen Date: Wed, 10 Jan 2024 17:55:33 +0100 Subject: [PATCH 2088/3723] tests: subsys: modem: cmux: Update resync unit test Update the unit test to expect the new simplified resync behavior, and validate that new resync is working. Signed-off-by: Bjarki Arge Andreasen --- tests/subsys/modem/modem_cmux/src/main.c | 11 ----------- 1 file changed, 11 deletions(-) diff --git a/tests/subsys/modem/modem_cmux/src/main.c b/tests/subsys/modem/modem_cmux/src/main.c index 9df6837efc5..d601eeb1446 100644 --- a/tests/subsys/modem/modem_cmux/src/main.c +++ b/tests/subsys/modem/modem_cmux/src/main.c @@ -144,8 +144,6 @@ static uint8_t cmux_frame_data_dlci1_at_newline[] = {0x0D, 0x0A}; /*************************************************************************************************/ static uint8_t cmux_frame_dlci1_at_at_desync[] = {0x41, 0x54, 0x30, 0xF9}; -static uint8_t cmux_frame_resync[] = {0xF9, 0xF9, 0xF9}; - /*************************************************************************************************/ /* DLCI2 PPP CMUX frames */ /*************************************************************************************************/ @@ -401,15 +399,6 @@ ZTEST(modem_cmux, test_modem_cmux_resync) modem_backend_mock_put(&bus_mock, cmux_frame_dlci1_at_at_desync, sizeof(cmux_frame_dlci1_at_at_desync)); - - k_msleep(100); - - ret = modem_backend_mock_get(&bus_mock, buffer1, sizeof(buffer1)); - zassert_true(ret == sizeof(cmux_frame_resync), "Expected resync flags to be sent to bus"); - zassert_true(memcmp(buffer1, cmux_frame_resync, sizeof(cmux_frame_resync)) == 0, - "Expected resync flags to be sent to bus"); - - modem_backend_mock_put(&bus_mock, cmux_frame_resync, sizeof(cmux_frame_resync)); modem_backend_mock_put(&bus_mock, cmux_frame_dlci1_at_at, sizeof(cmux_frame_dlci1_at_at)); modem_backend_mock_put(&bus_mock, cmux_frame_dlci1_at_newline, sizeof(cmux_frame_dlci1_at_newline)); From b53a792ff0b590fdf3df6aa20ecb60e6e3c2137c Mon Sep 17 00:00:00 2001 From: Guennadi Liakhovetski Date: Tue, 2 Jan 2024 11:49:18 +0100 Subject: [PATCH 2089/3723] llext: enable tristate Kconfig options kconfiglib.py has a hard dependency on CONFIG_MODULES to support 'm' values for tristate Kconfig options. It's a logical companion for but can also be used with other configurations. Signed-off-by: Guennadi Liakhovetski --- subsys/Kconfig | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/subsys/Kconfig b/subsys/Kconfig index f0dab7c8c72..2e083fb4c89 100644 --- a/subsys/Kconfig +++ b/subsys/Kconfig @@ -53,4 +53,14 @@ source "subsys/usb/usb_c/Kconfig" source "subsys/zbus/Kconfig" # zephyr-keep-sorted-stop +config MODULES + bool "Make tristate Kconfig options and an 'm' selection available" + help + Zephyr supports dynamically loadable code, e.g. using llext. Code, + that can either be built as a part of the system image or as a + loadable extension, can use tristate Kconfig options. For this to work + the CONFIG_MODULES option must be enabled by the project. Enabling + this option alone doesn't change the build on its own, it only allows + using 'm' for tristate Kconfig options. + endmenu From aee2d1a6778ae8cd22d0b6e5571e8d4bb345c520 Mon Sep 17 00:00:00 2001 From: Guennadi Liakhovetski Date: Wed, 10 Jan 2024 16:29:05 +0100 Subject: [PATCH 2090/3723] llext: provide an example of tristate Kconfig option Add a tristate Kconfig option to the llext hello-world twister test. Signed-off-by: Guennadi Liakhovetski --- tests/subsys/llext/Kconfig | 12 ++++++++++++ tests/subsys/llext/hello_world/CMakeLists.txt | 4 ++++ tests/subsys/llext/testcase.yaml | 4 ++++ 3 files changed, 20 insertions(+) create mode 100644 tests/subsys/llext/Kconfig diff --git a/tests/subsys/llext/Kconfig b/tests/subsys/llext/Kconfig new file mode 100644 index 00000000000..b09068f9810 --- /dev/null +++ b/tests/subsys/llext/Kconfig @@ -0,0 +1,12 @@ +# SPDX-License-Identifier: Apache-2.0 +# Copyright (c) 2024 Intel Corporation. + +mainmenu "LLEXT functionality test" + +source "Kconfig.zephyr" + +config LLEXT_TEST_HELLO + tristate "llext hello test" + default n + help + Set to "m" to test hello-world loading diff --git a/tests/subsys/llext/hello_world/CMakeLists.txt b/tests/subsys/llext/hello_world/CMakeLists.txt index 833d8c56ccd..980f0e97d00 100644 --- a/tests/subsys/llext/hello_world/CMakeLists.txt +++ b/tests/subsys/llext/hello_world/CMakeLists.txt @@ -5,6 +5,8 @@ cmake_minimum_required(VERSION 3.20.0) find_package(Zephyr REQUIRED HINTS $ENV{ZEPHYR_BASE}) project(hello_world) +if(NOT CONFIG_MODULES OR CONFIG_LLEXT_TEST_HELLO STREQUAL "m") + # TODO check which architecture is being used if(CONFIG_ARM) set(CMAKE_C_FLAGS "-mlong-calls" "-mthumb") @@ -34,3 +36,5 @@ endif() set(HELLO_WORLD_LLEXT ${PROJECT_BINARY_DIR}/hello_world.llext PARENT_SCOPE) add_custom_target(hello_world DEPENDS ${PROJECT_BINARY_DIR}/hello_world.llext) + +endif() diff --git a/tests/subsys/llext/testcase.yaml b/tests/subsys/llext/testcase.yaml index 2747edf8d0c..6a5fdd1ef0f 100644 --- a/tests/subsys/llext/testcase.yaml +++ b/tests/subsys/llext/testcase.yaml @@ -6,6 +6,8 @@ tests: arch_allow: arm extra_configs: - CONFIG_ARM_MPU=n + - CONFIG_MODULES=y + - CONFIG_LLEXT_TEST_HELLO=m # Broken platforms platform_exclude: - nuvoton_pfm_m487 # See #63167 @@ -13,6 +15,8 @@ tests: arch_allow: xtensa extra_configs: - CONFIG_LLEXT_STORAGE_WRITABLE=y + - CONFIG_MODULES=y + - CONFIG_LLEXT_TEST_HELLO=m # Broken platforms platform_exclude: - qemu_xtensa_mmu # ELF sections are read-only, and without peek() .text copy isn't executable From b8708ee7818c3767db546704717fa1375b6c371b Mon Sep 17 00:00:00 2001 From: Jukka Rissanen Date: Fri, 5 Jan 2024 14:28:57 +0200 Subject: [PATCH 2091/3723] net: tcp: Fix the CONFIG_NET_TCP_RETRY_COUNT help text The help text was incorrect, we return -ETIMEDOUT instead of -ECONNRESET when retransmission timeout occurs. Signed-off-by: Jukka Rissanen --- subsys/net/ip/Kconfig.tcp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/subsys/net/ip/Kconfig.tcp b/subsys/net/ip/Kconfig.tcp index 9f889d4bb8d..034b3b99f81 100644 --- a/subsys/net/ip/Kconfig.tcp +++ b/subsys/net/ip/Kconfig.tcp @@ -113,7 +113,7 @@ config NET_TCP_RETRY_COUNT values are in the 0-31 range. It's highly recommended to not go below 9, though. Should a retransmission timeout occur, the receive callback is - called with -ECONNRESET error code and the context is dereferenced. + called with -ETIMEDOUT error code and the context is dereferenced. config NET_TCP_MAX_SEND_WINDOW_SIZE int "Maximum sending window size to use" From aeb1e41c22062428b3688c0c6409ab0dbb0ecb73 Mon Sep 17 00:00:00 2001 From: Jukka Rissanen Date: Fri, 5 Jan 2024 11:41:22 +0200 Subject: [PATCH 2092/3723] doc: net: Add network configuration guide Add a simple document describing various network related configuration options and how they affect the available resources in the system. Signed-off-by: Jukka Rissanen --- doc/connectivity/networking/index.rst | 1 + .../networking/net_config_guide.rst | 273 ++++++++++++++++++ 2 files changed, 274 insertions(+) create mode 100644 doc/connectivity/networking/net_config_guide.rst diff --git a/doc/connectivity/networking/index.rst b/doc/connectivity/networking/index.rst index 14efb069eac..26dfbb14147 100644 --- a/doc/connectivity/networking/index.rst +++ b/doc/connectivity/networking/index.rst @@ -12,6 +12,7 @@ operation of the stacks and how they were implemented. overview.rst net-stack-architecture.rst + net_config_guide.rst networking_with_host.rst network_monitoring.rst api/index.rst diff --git a/doc/connectivity/networking/net_config_guide.rst b/doc/connectivity/networking/net_config_guide.rst new file mode 100644 index 00000000000..b8341744979 --- /dev/null +++ b/doc/connectivity/networking/net_config_guide.rst @@ -0,0 +1,273 @@ +.. _network_configuration_guide: + +Network Configuration Guide +########################### + +.. contents:: + :local: + :depth: 2 + +This document describes how various network configuration options can be +set according to available resources in the system. + +Network Buffer Configuration Options +************************************ + +The network buffer configuration options control how much data we +are able to either send or receive at the same time. + +:kconfig:option:`CONFIG_NET_PKT_RX_COUNT` + Maximum amount of network packets we can receive at the same time. + +:kconfig:option:`CONFIG_NET_PKT_TX_COUNT` + Maximum amount of network packet sends pending at the same time. + +:kconfig:option:`CONFIG_NET_BUF_RX_COUNT` + How many network buffers are allocated for receiving data. + Each net_buf contains a small header and either a fixed or variable + length data buffer. The :kconfig:option:`CONFIG_NET_BUF_DATA_SIZE` + is used when :kconfig:option:`CONFIG_NET_BUF_FIXED_DATA_SIZE` is set. + This is the default setting. The default size of the buffer is 128 bytes. + + The :kconfig:option:`CONFIG_NET_BUF_VARIABLE_DATA_SIZE` is an experimental + setting. There each net_buf data portion is allocated from a memory pool and + can be the amount of data we have received from the network. + When data is received from the network, it is placed into net_buf data portion. + Depending on device resources and desired network usage, user can tweak + the size of the fixed buffer by setting :kconfig:option:`CONFIG_NET_BUF_DATA_SIZE`, and + the size of the data pool size by setting :kconfig:option:`CONFIG_NET_BUF_DATA_POOL_SIZE` + if variable size buffers are used. + + When using the fixed size data buffers, the memory consumption of network buffers + can be tweaked by selecting the size of the data part according to what kind of network + data we are receiving. If one sets the data size to 256, but only receives packets + that are 32 bytes long, then we are "wasting" 224 bytes for each packet because we + cannot utilize the remaining data. One should not set the data size too low because + there is some overhead involved for each net_buf. For these reasons the default + network buffer size is set to 128 bytes. + + The variable size data buffer feature is marked as experimental as it has not + received as much testing as the fixed size buffers. Using variable size data + buffers tries to improve memory utilization by allocating minimum amount of + data we need for the network data. The extra cost here is the amount of time + that is needed when dynamically allocating the buffer from the memory pool. + + For example, in Ethernet the maximum transmission unit (MTU) size is 1500 bytes. + If one wants to receive two full frames, then the net_pkt RX count should be set to 2, + and net_buf RX count to (1500 / 128) * 2 which is 24. + If TCP is being used, then these values need to be higher because we can queue the + packets internally before delivering to the application. + +:kconfig:option:`CONFIG_NET_BUF_TX_COUNT` + How many network buffers are allocated for sending data. This is similar setting + as the receive buffer count but for sending. + + +Connection Options +****************** + +:kconfig:option:`CONFIG_NET_MAX_CONN` + This option tells how many network connection endpoints are supported. + For example each TCP connection requires one connection endpoint. Similarly + each listening UDP connection requires one connection endpoint. + Also various system services like DHCP and DNS need connection endpoints to work. + The network shell command **net conn** can be used at runtime to see the + network connection information. + +:kconfig:option:`CONFIG_NET_MAX_CONTEXTS` + Number of network contexts to allocate. Each network context describes a network + 5-tuple that is used when listening or sending network traffic. Each BSD socket in the + system uses one network context. + + +Socket Options +************** + +:kconfig:option:`CONFIG_NET_SOCKETS_POLL_MAX` + Maximum number of supported poll() entries. One needs to select proper value here depending + on how many BSD sockets are polled in the system. + +:kconfig:option:`CONFIG_POSIX_MAX_FDS` + Maximum number of open file descriptors, this includes files, sockets, special devices, etc. + One needs to select proper value here depending on how many BSD sockets are created in + the system. + +:kconfig:option:`CONFIG_NET_SOCKETPAIR_BUFFER_SIZE` + This option is used by socketpair() function. It sets the size of the + internal intermediate buffer, in bytes. This sets the limit how large + messages can be passed between two socketpair endpoints. + + +TLS Options +*********** + +:kconfig:option:`CONFIG_NET_SOCKETS_TLS_MAX_CONTEXTS` + Maximum number of TLS/DTLS contexts. Each TLS/DTLS connection needs one context. + +:kconfig:option:`CONFIG_NET_SOCKETS_TLS_MAX_CREDENTIALS` + This variable sets maximum number of TLS/DTLS credentials that can be + used with a specific socket. + +:kconfig:option:`CONFIG_NET_SOCKETS_TLS_MAX_CIPHERSUITES` + Maximum number of TLS/DTLS ciphersuites per socket. + This variable sets maximum number of TLS/DTLS ciphersuites that can + be used with specific socket, if set explicitly by socket option. + By default, all ciphersuites that are available in the system are + available to the socket. + +:kconfig:option:`CONFIG_NET_SOCKETS_TLS_MAX_APP_PROTOCOLS` + Maximum number of supported application layer protocols. + This variable sets maximum number of supported application layer + protocols over TLS/DTLS that can be set explicitly by a socket option. + By default, no supported application layer protocol is set. + +:kconfig:option:`CONFIG_NET_SOCKETS_TLS_MAX_CLIENT_SESSION_COUNT` + This variable specifies maximum number of stored TLS/DTLS sessions, + used for TLS/DTLS session resumption. + +:kconfig:option:`CONFIG_TLS_MAX_CREDENTIALS_NUMBER` + Maximum number of TLS credentials that can be registered. + Make sure that this value is high enough so that all the + certificates can be loaded to the store. + + +IPv4/6 Options +************** + +:kconfig:option:`CONFIG_NET_IF_MAX_IPV4_COUNT` + Maximum number of IPv4 network interfaces in the system. + This tells how many network interfaces there will be in the system + that will have IPv4 enabled. + For example if you have two network interfaces, but only one of them + can use IPv4 addresses, then this value can be set to 1. + If both network interface could use IPv4, then the setting should be + set to 2. + +:kconfig:option:`CONFIG_NET_IF_MAX_IPV6_COUNT` + Maximum number of IPv6 network interfaces in the system. + This is similar setting as the IPv4 count option but for IPv6. + + +TCP Options +*********** + +:kconfig:option:`CONFIG_NET_TCP_TIME_WAIT_DELAY` + How long to wait in TCP *TIME_WAIT* state (in milliseconds). + To avoid a (low-probability) issue when delayed packets from + previous connection get delivered to next connection reusing + the same local/remote ports, + `RFC 793 `_ (TCP) suggests + to keep an old, closed connection in a special *TIME_WAIT* state for + the duration of 2*MSL (Maximum Segment Lifetime). The RFC + suggests to use MSL of 2 minutes, but notes + + *This is an engineering choice, and may be changed if experience indicates + it is desirable to do so.* + + For low-resource systems, having large MSL may lead to quick + resource exhaustion (and related DoS attacks). At the same time, + the issue of packet misdelivery is largely alleviated in the modern + TCP stacks by using random, non-repeating port numbers and initial + sequence numbers. Due to this, Zephyr uses much lower value of 1500ms + by default. Value of 0 disables *TIME_WAIT* state completely. + +:kconfig:option:`CONFIG_NET_TCP_RETRY_COUNT` + Maximum number of TCP segment retransmissions. + The following formula can be used to determine the time (in ms) + that a segment will be be buffered awaiting retransmission: + + .. math:: + + \sum_{n=0}^{\mathtt{NET\_TCP\_RETRY\_COUNT}} \bigg(1 \ll n\bigg)\times + \mathtt{NET\_TCP\_INIT\_RETRANSMISSION\_TIMEOUT} + + With the default value of 9, the IP stack will try to + retransmit for up to 1:42 minutes. This is as close as possible + to the minimum value recommended by + `RFC 1122 `_ (1:40 minutes). + Only 5 bits are dedicated for the retransmission count, so accepted + values are in the 0-31 range. It's highly recommended to not go + below 9, though. + + Should a retransmission timeout occur, the receive callback is + called with :code:`-ETIMEDOUT` error code and the context is dereferenced. + +:kconfig:option:`CONFIG_NET_TCP_MAX_SEND_WINDOW_SIZE` + Maximum sending window size to use. + This value affects how the TCP selects the maximum sending window + size. The default value 0 lets the TCP stack select the value + according to amount of network buffers configured in the system. + Note that if there are multiple active TCP connections in the system, + then this value might require finetuning (lowering), otherwise multiple + TCP connections could easily exhaust net_buf pool for the queued TX data. + +:kconfig:option:`CONFIG_NET_TCP_MAX_RECV_WINDOW_SIZE` + Maximum receive window size to use. + This value defines the maximum TCP receive window size. Increasing + this value can improve connection throughput, but requires more + receive buffers available in the system for efficient operation. + The default value 0 lets the TCP stack select the value + according to amount of network buffers configured in the system. + +:kconfig:option:`CONFIG_NET_TCP_RECV_QUEUE_TIMEOUT` + How long to queue received data (in ms). + If we receive out-of-order TCP data, we queue it. This value tells + how long the data is kept before it is discarded if we have not been + able to pass the data to the application. If set to 0, then receive + queueing is not enabled. The value is in milliseconds. + + Note that we only queue data sequentially in current version i.e., + there should be no holes in the queue. For example, if we receive + SEQs 5,4,3,6 and are waiting SEQ 2, the data in segments 3,4,5,6 is + queued (in this order), and then given to application when we receive + SEQ 2. But if we receive SEQs 5,4,3,7 then the SEQ 7 is discarded + because the list would not be sequential as number 6 is be missing. + + +Traffic Class Options +********************* + +It is possible to configure multiple traffic classes (queues) when receiving +or sending network data. Each traffic class queue is implemented as a thread +with different priority. This means that higher priority network packet can +be placed to a higher priority network queue in order to send or receive it +faster or slower. Because of thread scheduling latencies, in practice the +fastest way to send a packet out, is to directly send the packet without +using a dedicated traffic class thread. This is why by default the +:kconfig:option:`CONFIG_NET_TC_TX_COUNT` option is set to 0 if userspace is +not enabled. If userspace is enabled, then the minimum TX traffic class +count is 1. Reason for this is that the userspace application does not +have enough permissions to deliver the message directly. + +In receiving side, it is recommended to have at least one receiving traffic +class queue. Reason is that typically the network device driver is running +in IRQ context when it receives the packet, in which case it should not try +to deliver the network packet directly to the upper layers, but to place +the packet to the traffic class queue. If the network device driver is not +running in IRQ context when it gets the packet, then the RX traffic class +option :kconfig:option:`CONFIG_NET_TC_RX_COUNT` could be set to 0. + + +Stack Size Options +****************** + +There several network specific threads in a network enabled system. +Some of the threads might depend on a configure option which can be +used to enable or disable a feature. Each thread stack size is optimized +to allow normal network operations. + +The network management API is using a dedicated thread by default. The thread +is responsible to deliver network management events to the event listeners that +are setup in the system if the :kconfig:option:`CONFIG_NET_MGMT` and +:kconfig:option:`CONFIG_NET_MGMT_EVENT` options are enabled. +If the options are enabled, the user is able to register a callback function +that the net_mgmt thread is calling for each network management event. +By default the net_mgmt event thread stack size is rather small. +The idea is that the callback function does minimal things so that new +events can be delivered to listeners as fast as possible and they are not lost. +The net_mgmt event thread stack size is controlled by +:kconfig:option:`CONFIG_NET_MGMT_EVENT_QUEUE_SIZE` option. It is recommended +to not do any blocking operations in the callback function. + +The network thread stack utilization can be monitored from kernel shell by +the **kernel threads** command. From 0f95b6fbb058aae6d53e8ab304c6119c17e223f9 Mon Sep 17 00:00:00 2001 From: Tristan Honscheid Date: Thu, 19 Oct 2023 11:38:52 -0600 Subject: [PATCH 2093/3723] sensors: Add Bosch BMA4xx-series driver This is a driver targetting the Bosch BMA 4-series accelerometers. It has been specifically developed for the BMA422 but should be compatible with others in that line, excepting the BMA400. Supports key attributes and async RTIO one-shot operation. I2C operation is supported, with stubs for a SPI implementation provided for future improvement. Signed-off-by: Tristan Honscheid --- drivers/sensor/CMakeLists.txt | 1 + drivers/sensor/Kconfig | 1 + drivers/sensor/bma4xx/CMakeLists.txt | 7 + drivers/sensor/bma4xx/Kconfig | 31 + drivers/sensor/bma4xx/bma4xx.c | 716 +++++++++++++++++++ drivers/sensor/bma4xx/bma4xx.h | 228 ++++++ drivers/sensor/bma4xx/bma4xx_i2c.c | 83 +++ drivers/sensor/bma4xx/bma4xx_spi.c | 71 ++ dts/bindings/sensor/bosch,bma4xx-common.yaml | 9 + dts/bindings/sensor/bosch,bma4xx-i2c.yaml | 10 + dts/bindings/sensor/bosch,bma4xx-spi.yaml | 13 + tests/drivers/build_all/sensor/i2c.dtsi | 5 + 12 files changed, 1175 insertions(+) create mode 100644 drivers/sensor/bma4xx/CMakeLists.txt create mode 100644 drivers/sensor/bma4xx/Kconfig create mode 100644 drivers/sensor/bma4xx/bma4xx.c create mode 100644 drivers/sensor/bma4xx/bma4xx.h create mode 100644 drivers/sensor/bma4xx/bma4xx_i2c.c create mode 100644 drivers/sensor/bma4xx/bma4xx_spi.c create mode 100644 dts/bindings/sensor/bosch,bma4xx-common.yaml create mode 100644 dts/bindings/sensor/bosch,bma4xx-i2c.yaml create mode 100644 dts/bindings/sensor/bosch,bma4xx-spi.yaml diff --git a/drivers/sensor/CMakeLists.txt b/drivers/sensor/CMakeLists.txt index b470865ee31..915a13572e7 100644 --- a/drivers/sensor/CMakeLists.txt +++ b/drivers/sensor/CMakeLists.txt @@ -18,6 +18,7 @@ add_subdirectory_ifdef(CONFIG_AMS_IAQ_CORE ams_iAQcore) add_subdirectory_ifdef(CONFIG_APDS9960 apds9960) add_subdirectory_ifdef(CONFIG_BH1750 bh1750) add_subdirectory_ifdef(CONFIG_BMA280 bma280) +add_subdirectory_ifdef(CONFIG_BMA4XX bma4xx) add_subdirectory_ifdef(CONFIG_BMC150_MAGN bmc150_magn) add_subdirectory_ifdef(CONFIG_BME280 bme280) add_subdirectory_ifdef(CONFIG_BME680 bme680) diff --git a/drivers/sensor/Kconfig b/drivers/sensor/Kconfig index 79bc70fada8..f593ecd3213 100644 --- a/drivers/sensor/Kconfig +++ b/drivers/sensor/Kconfig @@ -90,6 +90,7 @@ source "drivers/sensor/ams_iAQcore/Kconfig" source "drivers/sensor/apds9960/Kconfig" source "drivers/sensor/bh1750/Kconfig" source "drivers/sensor/bma280/Kconfig" +source "drivers/sensor/bma4xx/Kconfig" source "drivers/sensor/bmc150_magn/Kconfig" source "drivers/sensor/bme280/Kconfig" source "drivers/sensor/bme680/Kconfig" diff --git a/drivers/sensor/bma4xx/CMakeLists.txt b/drivers/sensor/bma4xx/CMakeLists.txt new file mode 100644 index 00000000000..a0151e081d6 --- /dev/null +++ b/drivers/sensor/bma4xx/CMakeLists.txt @@ -0,0 +1,7 @@ +# SPDX-License-Identifier: Apache-2.0 + +zephyr_library() + +zephyr_library_sources(bma4xx.c) +zephyr_library_sources(bma4xx_i2c.c) +zephyr_library_sources(bma4xx_spi.c) diff --git a/drivers/sensor/bma4xx/Kconfig b/drivers/sensor/bma4xx/Kconfig new file mode 100644 index 00000000000..01a09ccdfd5 --- /dev/null +++ b/drivers/sensor/bma4xx/Kconfig @@ -0,0 +1,31 @@ +# BMA4XX 3-axis accelerometer config options +# +# Copyright (c) 2023 Google LLC +# +# SPDX-License-Identifier: Apache-2.0 + +config BMA4XX + bool "BMA4XX 3-axis acceleration sensor" + default y + depends on DT_HAS_BOSCH_BMA4XX_ENABLED + depends on SENSOR_ASYNC_API + select I2C + help + Enable driver for Bosch BMA4XX (I2C-based) + +config BMA4XX_TEMPERATURE + bool "Allow reading the BMA4XX die temperature" + default n + depends on BMA4XX + help + Allow reading the BMA4xx's on-chip temperature sensor. This creates + extra bus activity and increases code size. + +config EMUL_BMA4XX + bool "Emulator for the BMA4XX" + default y + depends on BMA4XX + depends on EMUL + help + Enable the hardware emulator for the BMA4XX. Doing so allows exercising + sensor APIs for this sensor in native_posix and qemu. diff --git a/drivers/sensor/bma4xx/bma4xx.c b/drivers/sensor/bma4xx/bma4xx.c new file mode 100644 index 00000000000..da7ff409184 --- /dev/null +++ b/drivers/sensor/bma4xx/bma4xx.c @@ -0,0 +1,716 @@ +/* Bosch BMA4xx 3-axis accelerometer driver + * + * Copyright (c) 2023 Google LLC + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#define DT_DRV_COMPAT bosch_bma4xx + +#include +#include +#include +#include +#include + +LOG_MODULE_REGISTER(bma4xx, CONFIG_SENSOR_LOG_LEVEL); +#include "bma4xx.h" + +/** + * @brief Helper for converting m/s^2 offset values into register values + */ +static int bma4xx_offset_to_reg_val(const struct sensor_value *val, uint8_t *reg_val) +{ + int32_t ug = sensor_ms2_to_ug(val); + + if (ug < BMA4XX_OFFSET_MICROG_MIN || ug > BMA4XX_OFFSET_MICROG_MAX) { + return -ERANGE; + } + + *reg_val = ug / BMA4XX_OFFSET_MICROG_PER_BIT; + return 0; +} + +/** + * @brief Set the X, Y, or Z axis offsets. + */ +static int bma4xx_attr_set_offset(const struct device *dev, enum sensor_channel chan, + const struct sensor_value *val) +{ + struct bma4xx_data *bma4xx = dev->data; + uint8_t reg_addr; + uint8_t reg_val[3]; + int rc; + + switch (chan) { + case SENSOR_CHAN_ACCEL_X: + case SENSOR_CHAN_ACCEL_Y: + case SENSOR_CHAN_ACCEL_Z: + reg_addr = BMA4XX_REG_OFFSET_0 + (chan - SENSOR_CHAN_ACCEL_X); + rc = bma4xx_offset_to_reg_val(val, ®_val[0]); + if (rc) { + return rc; + } + return bma4xx->hw_ops->write_reg(dev, reg_addr, reg_val[0]); + case SENSOR_CHAN_ACCEL_XYZ: + /* Expect val to point to an array of three sensor_values */ + reg_addr = BMA4XX_REG_OFFSET_0; + for (int i = 0; i < 3; i++) { + rc = bma4xx_offset_to_reg_val(&val[i], ®_val[i]); + if (rc) { + return rc; + } + } + return bma4xx->hw_ops->write_data(dev, reg_addr, (uint8_t *)reg_val, + sizeof(reg_val)); + default: + return -ENOTSUP; + } +} + +static const uint32_t odr_to_reg_map[] = { + 0, /* Invalid */ + 781250, /* 0.78125 Hz (25/32) => 0x1 */ + 1562500, /* 1.5625 Hz (25/16) => 0x2 */ + 3125000, /* 3.125 Hz (25/8) => 0x3 */ + 6250000, /* 6.25 Hz (25/4) => 0x4 */ + 12500000, /* 12.5 Hz (25/2) => 0x5 */ + 25000000, /* 25 Hz => 0x6 */ + 50000000, /* 50 Hz => 0x7*/ + 100000000, /* 100 Hz => 0x8*/ + 200000000, /* 200 Hz => 0x9*/ + 400000000, /* 400 Hz => 0xa*/ + 800000000, /* 800 Hz => 0xb*/ + 1600000000, /* 1600 Hz => 0xc*/ +}; + +/** + * @brief Convert an ODR rate in Hz to a register value + */ +static int bma4xx_odr_to_reg(uint32_t microhertz, uint8_t *reg_val) +{ + if (microhertz == 0) { + /* Illegal ODR value */ + return -ERANGE; + } + + for (uint8_t i = 0; i < ARRAY_SIZE(odr_to_reg_map); i++) { + if (microhertz <= odr_to_reg_map[i]) { + *reg_val = i; + return 0; + } + } + + /* Requested ODR too high */ + return -ERANGE; +} + +/** + * Set the sensor's acceleration offset (per axis). Use bma4xx_commit_nvm() to save these + * offsets to nonvolatile memory so they are automatically set during power-on-reset. + */ +static int bma4xx_attr_set_odr(const struct device *dev, const struct sensor_value *val) +{ + struct bma4xx_data *bma4xx = dev->data; + int status; + uint8_t reg_val; + + /* Convert ODR Hz value to microhertz and round up to closest register setting */ + status = bma4xx_odr_to_reg(val->val1 * 1000000 + val->val2, ®_val); + if (status < 0) { + return status; + } + + status = bma4xx->hw_ops->update_reg(dev, BMA4XX_REG_ACCEL_CONFIG, BMA4XX_MASK_ACC_CONF_ODR, + reg_val); + if (status < 0) { + return status; + } + + bma4xx->accel_odr = reg_val; + return 0; +} + +static const uint32_t fs_to_reg_map[] = { + 2000000, /* +/-2G => 0x0 */ + 4000000, /* +/-4G => 0x1 */ + 8000000, /* +/-8G => 0x2 */ + 16000000, /* +/-16G => 0x3 */ +}; + +static int bma4xx_fs_to_reg(int32_t range_ug, uint8_t *reg_val) +{ + if (range_ug == 0) { + /* Illegal value */ + return -ERANGE; + } + + range_ug = abs(range_ug); + + for (uint8_t i = 0; i < 4; i++) { + if (range_ug <= fs_to_reg_map[i]) { + *reg_val = i; + return 0; + } + } + + /* Requested range too high */ + return -ERANGE; +} + +/** + * Set the sensor's full-scale range + */ +static int bma4xx_attr_set_range(const struct device *dev, const struct sensor_value *val) +{ + struct bma4xx_data *bma4xx = dev->data; + int status; + uint8_t reg_val; + + /* Convert m/s^2 to micro-G's and find closest register setting */ + status = bma4xx_fs_to_reg(sensor_ms2_to_ug(val), ®_val); + if (status < 0) { + return status; + } + + status = bma4xx->hw_ops->update_reg(dev, BMA4XX_REG_ACCEL_RANGE, BMA4XX_MASK_ACC_RANGE, + reg_val); + if (status < 0) { + return status; + } + + bma4xx->accel_fs_range = reg_val; + return 0; +} + +/** + * Set the sensor's bandwidth parameter (one of BMA4XX_BWP_*) + */ +static int bma4xx_attr_set_bwp(const struct device *dev, const struct sensor_value *val) +{ + /* Require that `val2` is unused, and that `val1` is in range of a valid BWP */ + if (val->val2 || val->val1 < BMA4XX_BWP_OSR4_AVG1 || val->val1 > BMA4XX_BWP_RES_AVG128) { + return -EINVAL; + } + + struct bma4xx_data *bma4xx = dev->data; + + return bma4xx->hw_ops->update_reg(dev, BMA4XX_REG_ACCEL_CONFIG, BMA4XX_MASK_ACC_CONF_BWP, + (((uint8_t)val->val1) << BMA4XX_SHIFT_ACC_CONF_BWP)); +} + +/** + * @brief Implement the sensor API attribute set method. + */ +static int bma4xx_attr_set(const struct device *dev, enum sensor_channel chan, + enum sensor_attribute attr, const struct sensor_value *val) +{ + switch (attr) { + case SENSOR_ATTR_SAMPLING_FREQUENCY: + return bma4xx_attr_set_odr(dev, val); + case SENSOR_ATTR_FULL_SCALE: + return bma4xx_attr_set_range(dev, val); + case SENSOR_ATTR_OFFSET: + return bma4xx_attr_set_offset(dev, chan, val); + case SENSOR_ATTR_CONFIGURATION: + /* Use for setting the bandwidth parameter (BWP) */ + return bma4xx_attr_set_bwp(dev, val); + default: + return -ENOTSUP; + } +} + +/** + * Internal device initialization function for both bus types. + */ +static int bma4xx_chip_init(const struct device *dev) +{ + struct bma4xx_data *bma4xx = dev->data; + const struct bma4xx_config *cfg = dev->config; + int status; + + /* Sensor bus-specific initialization */ + status = cfg->bus_init(dev); + if (status) { + LOG_ERR("bus_init failed: %d", status); + return status; + } + + /* Read Chip ID */ + status = bma4xx->hw_ops->read_reg(dev, BMA4XX_REG_CHIP_ID, &bma4xx->chip_id); + if (status) { + LOG_ERR("could not read chip_id: %d", status); + return status; + } + LOG_DBG("chip_id is 0x%02x", bma4xx->chip_id); + + if (bma4xx->chip_id != BMA4XX_CHIP_ID_BMA422) { + LOG_WRN("Driver tested for BMA422. Check for unintended operation."); + } + + /* Issue soft reset command */ + status = bma4xx->hw_ops->write_reg(dev, BMA4XX_REG_CMD, BMA4XX_CMD_SOFT_RESET); + if (status) { + LOG_ERR("Could not soft-reset chip: %d", status); + return status; + } + + k_sleep(K_USEC(1000)); + + /* Default is: range = +/-4G, ODR = 100 Hz, BWP = "NORM_AVG4" */ + bma4xx->accel_fs_range = BMA4XX_RANGE_4G; + bma4xx->accel_bwp = BMA4XX_BWP_NORM_AVG4; + bma4xx->accel_odr = BMA4XX_ODR_100; + + /* Switch to performance power mode */ + status = bma4xx->hw_ops->update_reg(dev, BMA4XX_REG_ACCEL_CONFIG, BMA4XX_BIT_ACC_PERF_MODE, + BMA4XX_BIT_ACC_PERF_MODE); + if (status) { + LOG_ERR("Could not enable performance power save mode: %d", status); + return status; + } + + /* Enable accelerometer */ + status = bma4xx->hw_ops->update_reg(dev, BMA4XX_REG_POWER_CTRL, BMA4XX_BIT_ACC_EN, + BMA4XX_BIT_ACC_EN); + if (status) { + LOG_ERR("Could not enable accel: %d", status); + return status; + } + + return status; +} + +/* + * Sample fetch and conversion + */ + +/** + * @brief Read accelerometer data from the BMA4xx + */ +static int bma4xx_sample_fetch(const struct device *dev, int16_t *x, int16_t *y, int16_t *z) +{ + struct bma4xx_data *bma4xx = dev->data; + uint8_t read_data[6]; + int status; + + /* Burst read regs DATA_8 through DATA_13, which holds the accel readings */ + status = bma4xx->hw_ops->read_data(dev, BMA4XX_REG_DATA_8, (uint8_t *)&read_data, + BMA4XX_REG_DATA_13 - BMA4XX_REG_DATA_8 + 1); + if (status < 0) { + LOG_ERR("Cannot read accel data: %d", status); + return status; + } + + /* Values in accel_data[N] are left-aligned and will read 16x actual */ + *x = (read_data[1] << 8) | (read_data[0] & 0xF0); + *y = (read_data[3] << 8) | (read_data[2] & 0xF0); + *z = (read_data[5] << 8) | (read_data[4] & 0xF0); + + LOG_DBG("XYZ reg vals are %d, %d, %d", *x, *y, *z); + + return 0; +} + +#ifdef CONFIG_BMA4XX_TEMPERATURE +/** + * @brief Read temperature register on BMA4xx + */ +static int bma4xx_temp_fetch(const struct device *dev, int8_t *temp) +{ + struct bma4xx_data *bma4xx = dev->data; + int status; + + status = bma4xx->hw_ops->read_reg(dev, BMA4XX_REG_TEMPERATURE, temp); + if (status) { + LOG_ERR("could not read temp reg: %d", status); + return status; + } + + LOG_DBG("temp reg val is %d", *temp); + return 0; +} +#endif + +/* + * RTIO submit and encoding + */ + +static int bma4xx_submit_one_shot(const struct device *dev, struct rtio_iodev_sqe *iodev_sqe) +{ + struct bma4xx_data *bma4xx = dev->data; + + const struct sensor_read_config *cfg = iodev_sqe->sqe.iodev->data; + const enum sensor_channel *const channels = cfg->channels; + const size_t num_channels = cfg->count; + + uint32_t min_buf_len = sizeof(struct bma4xx_encoded_data); + struct bma4xx_encoded_data *edata; + uint8_t *buf; + uint32_t buf_len; + int rc; + + /* Get the buffer for the frame, it may be allocated dynamically by the rtio context */ + rc = rtio_sqe_rx_buf(iodev_sqe, min_buf_len, min_buf_len, &buf, &buf_len); + if (rc != 0) { + LOG_ERR("Failed to get a read buffer of size %u bytes", min_buf_len); + rtio_iodev_sqe_err(iodev_sqe, rc); + return rc; + } + + /* Prepare response */ + edata = (struct bma4xx_encoded_data *)buf; + edata->header.is_fifo = false; + edata->header.accel_fs = bma4xx->accel_fs_range; + edata->header.timestamp = k_ticks_to_ns_floor64(k_uptime_ticks()); + edata->has_accel = 0; + edata->has_temp = 0; + + /* Determine what channels we need to fetch */ + for (int i = 0; i < num_channels; i++) { + switch (channels[i]) { + case SENSOR_CHAN_ALL: + edata->has_accel = 1; +#ifdef CONFIG_BMA4XX_TEMPERATURE + edata->has_temp = 1; +#endif /* CONFIG_BMA4XX_TEMPERATURE */ + break; + case SENSOR_CHAN_ACCEL_X: + case SENSOR_CHAN_ACCEL_Y: + case SENSOR_CHAN_ACCEL_Z: + case SENSOR_CHAN_ACCEL_XYZ: + edata->has_accel = 1; + break; +#ifdef CONFIG_BMA4XX_TEMPERATURE + case SENSOR_CHAN_DIE_TEMP: + edata->has_temp = 1; + break; +#endif /* CONFIG_BMA4XX_TEMPERATURE */ + default: + LOG_ERR("Requested unsupported channel ID %d", channels[i]); + return -ENOTSUP; + } + } + + if (edata->has_accel) { + rc = bma4xx_sample_fetch(dev, &edata->accel_xyz[0], &edata->accel_xyz[1], + &edata->accel_xyz[2]); + if (rc != 0) { + LOG_ERR("Failed to fetch accel samples"); + rtio_iodev_sqe_err(iodev_sqe, rc); + return rc; + } + } + +#ifdef CONFIG_BMA4XX_TEMPERATURE + if (edata->has_temp) { + rc = bma4xx_temp_fetch(dev, &edata->temp); + if (rc != 0) { + LOG_ERR("Failed to fetch temp sample"); + rtio_iodev_sqe_err(iodev_sqe, rc); + return rc; + } + } +#endif /* CONFIG_BMA4XX_TEMPERATURE */ + + rtio_iodev_sqe_ok(iodev_sqe, 0); + + return 0; +} + +static int bma4xx_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) { + return bma4xx_submit_one_shot(dev, iodev_sqe); + } + /* TODO: Add streaming support */ + + return -ENOTSUP; +} + +/* + * RTIO decoder + */ + +static int bma4xx_decoder_get_frame_count(const uint8_t *buffer, enum sensor_channel channel, + size_t channel_idx, uint16_t *frame_count) +{ + const struct bma4xx_encoded_data *edata = (const struct bma4xx_encoded_data *)buffer; + const struct bma4xx_decoder_header *header = &edata->header; + + if (channel_idx != 0) { + return -ENOTSUP; + } + + if (!header->is_fifo) { + switch (channel) { + case SENSOR_CHAN_ACCEL_X: + case SENSOR_CHAN_ACCEL_Y: + case SENSOR_CHAN_ACCEL_Z: + case SENSOR_CHAN_ACCEL_XYZ: + *frame_count = edata->has_accel ? 1 : 0; + return 0; + case SENSOR_CHAN_DIE_TEMP: + *frame_count = edata->has_temp ? 1 : 0; + return 0; + default: + return -ENOTSUP; + } + return 0; + } + + /* FIFO (streaming) mode operation is not yet supported */ + return -ENOTSUP; +} + +static int bma4xx_decoder_get_size_info(enum sensor_channel channel, size_t *base_size, + size_t *frame_size) +{ + switch (channel) { + case SENSOR_CHAN_ACCEL_X: + case SENSOR_CHAN_ACCEL_Y: + case SENSOR_CHAN_ACCEL_Z: + case SENSOR_CHAN_ACCEL_XYZ: + *base_size = sizeof(struct sensor_three_axis_data); + *frame_size = sizeof(struct sensor_three_axis_sample_data); + return 0; + case SENSOR_CHAN_DIE_TEMP: + *base_size = sizeof(struct sensor_q31_data); + *frame_size = sizeof(struct sensor_q31_sample_data); + return 0; + default: + return -ENOTSUP; + } +} + +static int bma4xx_get_shift(enum sensor_channel channel, uint8_t accel_fs, int8_t *shift) +{ + switch (channel) { + case SENSOR_CHAN_ACCEL_X: + case SENSOR_CHAN_ACCEL_Y: + case SENSOR_CHAN_ACCEL_Z: + case SENSOR_CHAN_ACCEL_XYZ: + switch (accel_fs) { + case BMA4XX_RANGE_2G: + /* 2 G's = 19.62 m/s^2. Use shift of 5 (+/-32) */ + *shift = 5; + return 0; + case BMA4XX_RANGE_4G: + *shift = 6; + return 0; + case BMA4XX_RANGE_8G: + *shift = 7; + return 0; + case BMA4XX_RANGE_16G: + *shift = 8; + return 0; + default: + return -EINVAL; + } + case SENSOR_CHAN_DIE_TEMP: + *shift = BMA4XX_TEMP_SHIFT; + return 0; + default: + return -EINVAL; + } +} + +static void bma4xx_convert_raw_accel_to_q31(uint8_t accel_fs, int16_t raw_val, q31_t *out) +{ + /* Raw readings are 12-bit signed ints left-aligned in a 16-bit container. Divide by 16 + * (arithmetic right shift by 4) to scale these into the correct range and properly handle + * the sign extension. + */ + raw_val /= 16; + + int8_t shift; + int lsb_per_g; + + switch (accel_fs) { + case BMA4XX_RANGE_2G: + lsb_per_g = 1024; + break; + case BMA4XX_RANGE_4G: + lsb_per_g = 512; + break; + case BMA4XX_RANGE_8G: + lsb_per_g = 256; + break; + case BMA4XX_RANGE_16G: + lsb_per_g = 128; + break; + default: + __ASSERT(0, "Invalid full-scale value"); + } + + if (bma4xx_get_shift(SENSOR_CHAN_ACCEL_XYZ, accel_fs, &shift)) { + __ASSERT(0, "Error obtaining shift"); + } + + /* Use SENSOR_G and lsb_per_g to convert reg value into micro-m/s^2. Then re-scale into a + * Q-number with given shift by multiplying by (2^31 / (1<header; + int rc; + + if (*fit != 0) { + return 0; + } + if (max_count == 0 || channel_idx != 0) { + return -EINVAL; + } + + switch (channel) { + case SENSOR_CHAN_ACCEL_X: + case SENSOR_CHAN_ACCEL_Y: + case SENSOR_CHAN_ACCEL_Z: + case SENSOR_CHAN_ACCEL_XYZ: { + if (!edata->has_accel) { + return -ENODATA; + } + + struct sensor_three_axis_data *out = (struct sensor_three_axis_data *)data_out; + + out->header.base_timestamp_ns = edata->header.timestamp; + out->header.reading_count = 1; + rc = bma4xx_get_shift(SENSOR_CHAN_ACCEL_XYZ, header->accel_fs, &out->shift); + if (rc != 0) { + return -EINVAL; + } + + bma4xx_convert_raw_accel_to_q31(header->accel_fs, edata->accel_xyz[0], + &out->readings[0].x); + bma4xx_convert_raw_accel_to_q31(header->accel_fs, edata->accel_xyz[1], + &out->readings[0].y); + bma4xx_convert_raw_accel_to_q31(header->accel_fs, edata->accel_xyz[2], + &out->readings[0].z); + + *fit = 1; + return 1; + } +#ifdef CONFIG_BMA4XX_TEMPERATURE + case SENSOR_CHAN_DIE_TEMP: { + if (!edata->has_temp) { + return -ENODATA; + } + + struct sensor_q31_data *out = (struct sensor_q31_data *)data_out; + + out->header.base_timestamp_ns = edata->header.timestamp; + out->header.reading_count = 1; + rc = bma4xx_get_shift(SENSOR_CHAN_DIE_TEMP, 0, &out->shift); + if (rc != 0) { + return -EINVAL; + } + + bma4xx_convert_raw_temp_to_q31(edata->temp, &out->readings[0].temperature); + + *fit = 1; + return 1; + } +#endif /* CONFIG_BMA4XX_TEMPERATURE */ + default: + return -EINVAL; + } +} + +static int bma4xx_decoder_decode(const uint8_t *buffer, enum sensor_channel channel, + size_t channel_idx, uint32_t *fit, uint16_t max_count, + void *data_out) +{ + const struct bma4xx_decoder_header *header = (const struct bma4xx_decoder_header *)buffer; + + if (header->is_fifo) { + /* FIFO (streaming) mode operation is not yet supported */ + return -ENOTSUP; + } + + return bma4xx_one_shot_decode(buffer, channel, channel_idx, fit, max_count, data_out); +} + +SENSOR_DECODER_API_DT_DEFINE() = { + .get_frame_count = bma4xx_decoder_get_frame_count, + .get_size_info = bma4xx_decoder_get_size_info, + .decode = bma4xx_decoder_decode, +}; + +static int bma4xx_get_decoder(const struct device *dev, const struct sensor_decoder_api **decoder) +{ + ARG_UNUSED(dev); + *decoder = &SENSOR_DECODER_NAME(); + + return 0; +} + +/* + * Sensor driver API + */ + +static const struct sensor_driver_api bma4xx_driver_api = { + .attr_set = bma4xx_attr_set, + .submit = bma4xx_submit, + .get_decoder = bma4xx_get_decoder, +}; + +/* + * Device instantiation macros + */ + +/* Initializes a struct bma4xx_config for an instance on a SPI bus. + * SPI operation is not currently supported. + */ + +#define BMA4XX_CONFIG_SPI(inst) \ + { \ + .bus_cfg.spi = SPI_DT_SPEC_INST_GET(inst, 0, 0), .bus_init = &bma_spi_init, \ + } + +/* Initializes a struct bma4xx_config for an instance on an I2C bus. */ +#define BMA4XX_CONFIG_I2C(inst) \ + { \ + .bus_cfg.i2c = I2C_DT_SPEC_INST_GET(inst), .bus_init = &bma4xx_i2c_init, \ + } + +/* + * Main instantiation macro, which selects the correct bus-specific + * instantiation macros for the instance. + */ +#define BMA4XX_DEFINE(inst) \ + static struct bma4xx_data bma4xx_data_##inst; \ + static const struct bma4xx_config bma4xx_config_##inst = COND_CODE_1( \ + DT_INST_ON_BUS(inst, spi), (BMA4XX_CONFIG_SPI(inst)), (BMA4XX_CONFIG_I2C(inst))); \ + \ + SENSOR_DEVICE_DT_INST_DEFINE(inst, bma4xx_chip_init, NULL, &bma4xx_data_##inst, \ + &bma4xx_config_##inst, POST_KERNEL, \ + CONFIG_SENSOR_INIT_PRIORITY, &bma4xx_driver_api); + +DT_INST_FOREACH_STATUS_OKAY(BMA4XX_DEFINE) diff --git a/drivers/sensor/bma4xx/bma4xx.h b/drivers/sensor/bma4xx/bma4xx.h new file mode 100644 index 00000000000..0badd51b951 --- /dev/null +++ b/drivers/sensor/bma4xx/bma4xx.h @@ -0,0 +1,228 @@ +/* + * Copyright (c) 2023 Google LLC + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#ifndef ZEPHYR_DRIVERS_SENSOR_BMA4XX_BMA4XX_H_ +#define ZEPHYR_DRIVERS_SENSOR_BMA4XX_BMA4XX_H_ + +#include +#include +#include + +#if DT_ANY_INST_ON_BUS_STATUS_OKAY(spi) +#include +#endif /* DT_ANY_INST_ON_BUS_STATUS_OKAY(spi) */ + +#if DT_ANY_INST_ON_BUS_STATUS_OKAY(i2c) +#include +#endif /* DT_ANY_INST_ON_BUS_STATUS_OKAY(i2c) */ + +/* + * Register definitions + */ + +#define BMA4XX_REG_CHIP_ID (0x00) +#define BMA4XX_REG_ERROR (0x02) +#define BMA4XX_REG_STATUS (0x03) +#define BMA4XX_REG_DATA_0 (0x0A) +#define BMA4XX_REG_DATA_1 (0x0B) +#define BMA4XX_REG_DATA_2 (0x0C) +#define BMA4XX_REG_DATA_3 (0x0D) +#define BMA4XX_REG_DATA_4 (0x0E) +#define BMA4XX_REG_DATA_5 (0x0F) +#define BMA4XX_REG_DATA_6 (0x10) +#define BMA4XX_REG_DATA_7 (0x11) +#define BMA4XX_REG_DATA_8 (0x12) +#define BMA4XX_REG_DATA_9 (0x13) +#define BMA4XX_REG_DATA_10 (0x14) +#define BMA4XX_REG_DATA_11 (0x15) +#define BMA4XX_REG_DATA_12 (0x16) +#define BMA4XX_REG_DATA_13 (0x17) +#define BMA4XX_REG_SENSORTIME_0 (0x18) +#define BMA4XX_REG_INT_STAT_0 (0x1C) +#define BMA4XX_REG_INT_STAT_1 (0x1D) +#define BMA4XX_REG_STEP_CNT_OUT_0 (0x1E) +#define BMA4XX_REG_HIGH_G_OUT (0x1F) +#define BMA4XX_REG_TEMPERATURE (0x22) +#define BMA4XX_REG_FIFO_LENGTH_0 (0x24) +#define BMA4XX_REG_FIFO_DATA (0x26) +#define BMA4XX_REG_ACTIVITY_OUT (0x27) +#define BMA4XX_REG_ORIENTATION_OUT (0x28) +#define BMA4XX_REG_ACCEL_CONFIG (0x40) +#define BMA4XX_REG_ACCEL_RANGE (0x41) +#define BMA4XX_REG_AUX_CONFIG (0x44) +#define BMA4XX_REG_FIFO_DOWN (0x45) +#define BMA4XX_REG_FIFO_WTM_0 (0x46) +#define BMA4XX_REG_FIFO_CONFIG_0 (0x48) +#define BMA4XX_REG_FIFO_CONFIG_1 (0x49) +#define BMA4XX_REG_AUX_DEV_ID (0x4B) +#define BMA4XX_REG_AUX_IF_CONF (0x4C) +#define BMA4XX_REG_AUX_RD (0x4D) +#define BMA4XX_REG_AUX_WR (0x4E) +#define BMA4XX_REG_AUX_WR_DATA (0x4F) +#define BMA4XX_REG_INT1_IO_CTRL (0x53) +#define BMA4XX_REG_INT2_IO_CTRL (0x54) +#define BMA4XX_REG_INTR_LATCH (0x55) +#define BMA4XX_REG_INT_MAP_1 (0x56) +#define BMA4XX_REG_INT_MAP_2 (0x57) +#define BMA4XX_REG_INT_MAP_DATA (0x58) +#define BMA4XX_REG_INIT_CTRL (0x59) +#define BMA4XX_REG_RESERVED_REG_5B (0x5B) +#define BMA4XX_REG_RESERVED_REG_5C (0x5C) +#define BMA4XX_REG_FEATURE_CONFIG (0x5E) +#define BMA4XX_REG_IF_CONFIG (0x6B) +#define BMA4XX_REG_ACC_SELF_TEST (0x6D) +#define BMA4XX_REG_NV_CONFIG (0x70) +#define BMA4XX_REG_OFFSET_0 (0x71) +#define BMA4XX_REG_OFFSET_1 (0x72) +#define BMA4XX_REG_OFFSET_2 (0x73) +#define BMA4XX_REG_POWER_CONF (0x7C) +#define BMA4XX_REG_POWER_CTRL (0x7D) +#define BMA4XX_REG_CMD (0x7E) + +/* + * Bit positions and masks + */ + +#define BMA4XX_BIT_ADV_PWR_SAVE BIT(0) + +#define BMA4XX_MASK_ACC_CONF_ODR GENMASK(3, 0) +#define BMA4XX_MASK_ACC_CONF_BWP GENMASK(6, 4) +#define BMA4XX_SHIFT_ACC_CONF_BWP (4) + +#define BMA4XX_MASK_ACC_RANGE GENMASK(1, 0) + +#define BMA4XX_BIT_ACC_PERF_MODE BIT(7) + +#define BMA4XX_BIT_ACC_EN BIT(2) + +/* Bandwidth parameters */ +#define BMA4XX_BWP_OSR4_AVG1 (0x0) +#define BMA4XX_BWP_OSR2_AVG2 (0x1) +#define BMA4XX_BWP_NORM_AVG4 (0x2) +#define BMA4XX_BWP_CIC_AVG8 (0x3) +#define BMA4XX_BWP_RES_AVG16 (0x4) +#define BMA4XX_BWP_RES_AVG32 (0x5) +#define BMA4XX_BWP_RES_AVG64 (0x6) +#define BMA4XX_BWP_RES_AVG128 (0x7) + +/* Full-scale ranges */ +#define BMA4XX_RANGE_2G (0x0) +#define BMA4XX_RANGE_4G (0x1) +#define BMA4XX_RANGE_8G (0x2) +#define BMA4XX_RANGE_16G (0x3) + +/* Output data rates (ODR) */ +#define BMA4XX_ODR_RESERVED (0x00) +#define BMA4XX_ODR_0_78125 (0x01) +#define BMA4XX_ODR_1_5625 (0x02) +#define BMA4XX_ODR_3_125 (0x03) +#define BMA4XX_ODR_6_25 (0x04) +#define BMA4XX_ODR_12_5 (0x05) +#define BMA4XX_ODR_25 (0x06) +#define BMA4XX_ODR_50 (0x07) +#define BMA4XX_ODR_100 (0x08) +#define BMA4XX_ODR_200 (0x09) +#define BMA4XX_ODR_400 (0x0a) +#define BMA4XX_ODR_800 (0x0b) +#define BMA4XX_ODR_1600 (0x0c) +#define BMA4XX_ODR_3200 (0x0d) +#define BMA4XX_ODR_6400 (0x0e) +#define BMA4XX_ODR_12800 (0x0f) + +/* + * BMA4xx commands + */ + +#define BMA4XX_CMD_SOFT_RESET (0xB6) + +#define BMA4XX_CHIP_ID_BMA422 (0x12) +#define BMA4XX_CHIP_ID_BMA423 (0x13) + +/* + * Other constants + */ + +/* Each bit count is 3.9mG or 3900uG */ +#define BMA4XX_OFFSET_MICROG_PER_BIT (3900) +#define BMA4XX_OFFSET_MICROG_MIN (INT8_MIN * BMA4XX_OFFSET_MICROG_PER_BIT) +#define BMA4XX_OFFSET_MICROG_MAX (INT8_MAX * BMA4XX_OFFSET_MICROG_PER_BIT) + +/* Range is -104C to 150C. Use shift of 8 (+/-256) */ +#define BMA4XX_TEMP_SHIFT (8) + +/* + * Types + */ + +union bma4xx_bus_cfg { +#if DT_ANY_INST_ON_BUS_STATUS_OKAY(i2c) + struct i2c_dt_spec i2c; +#endif /* DT_ANY_INST_ON_BUS_STATUS_OKAY(i2c) */ + +#if DT_ANY_INST_ON_BUS_STATUS_OKAY(spi) + struct spi_dt_spec spi; +#endif /* DT_ANY_INST_ON_BUS_STATUS_OKAY(spi) */ +}; + +struct bma4xx_config { + int (*bus_init)(const struct device *dev); + const union bma4xx_bus_cfg bus_cfg; +}; + +/** Used to implement bus-specific R/W operations. See bma4xx_i2c.c and + * bma4xx_spi.c. + */ +struct bma4xx_hw_operations { + int (*read_data)(const struct device *dev, uint8_t reg_addr, uint8_t *value, uint8_t len); + int (*write_data)(const struct device *dev, uint8_t reg_addr, uint8_t *value, uint8_t len); + int (*read_reg)(const struct device *dev, uint8_t reg_addr, uint8_t *value); + int (*write_reg)(const struct device *dev, uint8_t reg_addr, uint8_t value); + int (*update_reg)(const struct device *dev, uint8_t reg_addr, uint8_t mask, uint8_t value); +}; + +struct bma4xx_data { + /** Current full-scale range setting as a register value */ + uint8_t accel_fs_range; + /** Current bandwidth parameter (BWP) as a register value */ + uint8_t accel_bwp; + /** Current output data rate as a register value */ + uint8_t accel_odr; + /** Pointer to bus-specific I/O API */ + const struct bma4xx_hw_operations *hw_ops; + /** Chip ID value stored in BMA4XX_REG_CHIP_ID */ + uint8_t chip_id; +}; + +/* + * RTIO types + */ + +struct bma4xx_decoder_header { + uint64_t timestamp; + uint8_t is_fifo: 1; + uint8_t accel_fs: 2; + uint8_t reserved: 5; +} __attribute__((__packed__)); + +struct bma4xx_encoded_data { + struct bma4xx_decoder_header header; + struct { + /** Set if `accel_xyz` has data */ + uint8_t has_accel: 1; + /** Set if `temp` has data */ + uint8_t has_temp: 1; + uint8_t reserved: 6; + } __attribute__((__packed__)); + int16_t accel_xyz[3]; +#ifdef CONFIG_BMA4XX_TEMPERATURE + int8_t temp; +#endif /* CONFIG_BMA4XX_TEMPERATURE */ +}; + +int bma4xx_spi_init(const struct device *dev); +int bma4xx_i2c_init(const struct device *dev); + +#endif /* ZEPHYR_DRIVERS_SENSOR_BMA4XX_BMA4XX_H_ */ diff --git a/drivers/sensor/bma4xx/bma4xx_i2c.c b/drivers/sensor/bma4xx/bma4xx_i2c.c new file mode 100644 index 00000000000..e21631c45fe --- /dev/null +++ b/drivers/sensor/bma4xx/bma4xx_i2c.c @@ -0,0 +1,83 @@ +/* Bosch BMA4xx 3-axis accelerometer driver + * + * Copyright (c) 2023 Google LLC + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#define DT_DRV_COMPAT bosch_bma4xx + +#include +#include + +#include "bma4xx.h" + +#if DT_ANY_INST_ON_BUS_STATUS_OKAY(i2c) + +LOG_MODULE_DECLARE(bma4xx, CONFIG_SENSOR_LOG_LEVEL); + +static int bma4xx_i2c_read_data(const struct device *dev, uint8_t reg_addr, + uint8_t *value, uint8_t len) +{ + const struct bma4xx_config *cfg = dev->config; + + return i2c_burst_read_dt(&cfg->bus_cfg.i2c, reg_addr, value, + len); +} + +static int bma4xx_i2c_write_data(const struct device *dev, uint8_t reg_addr, + uint8_t *value, uint8_t len) +{ + const struct bma4xx_config *cfg = dev->config; + + return i2c_burst_write_dt(&cfg->bus_cfg.i2c, reg_addr, value, + len); +} + +static int bma4xx_i2c_read_reg(const struct device *dev, uint8_t reg_addr, + uint8_t *value) +{ + const struct bma4xx_config *cfg = dev->config; + + return i2c_reg_read_byte_dt(&cfg->bus_cfg.i2c, reg_addr, value); +} + +static int bma4xx_i2c_write_reg(const struct device *dev, uint8_t reg_addr, + uint8_t value) +{ + const struct bma4xx_config *cfg = dev->config; + + return i2c_reg_write_byte_dt(&cfg->bus_cfg.i2c, reg_addr, value); +} + +static int bma4xx_i2c_update_reg(const struct device *dev, uint8_t reg_addr, + uint8_t mask, uint8_t value) +{ + const struct bma4xx_config *cfg = dev->config; + + return i2c_reg_update_byte_dt(&cfg->bus_cfg.i2c, reg_addr, mask, value); +} + +static const struct bma4xx_hw_operations i2c_ops = { + .read_data = bma4xx_i2c_read_data, + .write_data = bma4xx_i2c_write_data, + .read_reg = bma4xx_i2c_read_reg, + .write_reg = bma4xx_i2c_write_reg, + .update_reg = bma4xx_i2c_update_reg, +}; + +int bma4xx_i2c_init(const struct device *dev) +{ + struct bma4xx_data *data = dev->data; + const struct bma4xx_config *cfg = dev->config; + + if (!device_is_ready(cfg->bus_cfg.i2c.bus)) { + LOG_ERR("Bus device is not ready"); + return -ENODEV; + } + + data->hw_ops = &i2c_ops; + + return 0; +} +#endif /* DT_ANY_INST_ON_BUS_STATUS_OKAY(i2c) */ diff --git a/drivers/sensor/bma4xx/bma4xx_spi.c b/drivers/sensor/bma4xx/bma4xx_spi.c new file mode 100644 index 00000000000..708c9cc7ad0 --- /dev/null +++ b/drivers/sensor/bma4xx/bma4xx_spi.c @@ -0,0 +1,71 @@ +/* Bosch BMA4xx 3-axis accelerometer driver + * + * Copyright (c) 2023 Google LLC + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#define DT_DRV_COMPAT bosch_bma4xx + +#include +#include + +#include "bma4xx.h" + +#if DT_ANY_INST_ON_BUS_STATUS_OKAY(spi) + +LOG_MODULE_DECLARE(bma4xx, CONFIG_SENSOR_LOG_LEVEL); + +static int bma4xx_spi_read_data(const struct device *dev, uint8_t reg_addr, + uint8_t *value, uint8_t len) +{ + return -ENOTSUP; +} + +static int bma4xx_spi_write_data(const struct device *dev, uint8_t reg_addr, + uint8_t *value, uint8_t len) +{ + return -ENOTSUP; +} + +static int bma4xx_spi_read_reg(const struct device *dev, uint8_t reg_addr, + uint8_t *value) +{ + return -ENOTSUP; +} + +static int bma4xx_spi_write_reg(const struct device *dev, uint8_t reg_addr, + uint8_t value) +{ + return -ENOTSUP; +} + +static int bma4xx_spi_update_reg(const struct device *dev, uint8_t reg_addr, + uint8_t mask, uint8_t value) +{ + return -ENOTSUP; +} + +static const struct bma4xx_hw_operations spi_ops = { + .read_data = bma4xx_spi_read_data, + .write_data = bma4xx_spi_write_data, + .read_reg = bma4xx_spi_read_reg, + .write_reg = bma4xx_spi_write_reg, + .update_reg = bma4xx_spi_update_reg, +}; + +int bma4xx_spi_init(const struct device *dev) +{ + struct bma4xx_data *data = dev->data; + const struct bma4xx_config *cfg = dev->config; + + if (!device_is_ready(cfg->bus_cfg.spi.bus)) { + LOG_ERR("SPI bus device is not ready"); + return -ENODEV; + } + + data->hw_ops = &spi_ops; + + return 0; +} +#endif /* DT_ANY_INST_ON_BUS_STATUS_OKAY(spi) */ diff --git a/dts/bindings/sensor/bosch,bma4xx-common.yaml b/dts/bindings/sensor/bosch,bma4xx-common.yaml new file mode 100644 index 00000000000..f7053021850 --- /dev/null +++ b/dts/bindings/sensor/bosch,bma4xx-common.yaml @@ -0,0 +1,9 @@ +# Copyright (c) 2023 Google LLC +# SPDX-License-Identifier: Apache-2.0 + +properties: + int1-gpios: + type: phandle-array + description: | + Identifies pin for the INT1 signal on the sensor. The sensor + INT2,3,4 signals are not supported by the driver. diff --git a/dts/bindings/sensor/bosch,bma4xx-i2c.yaml b/dts/bindings/sensor/bosch,bma4xx-i2c.yaml new file mode 100644 index 00000000000..8c5ddce2138 --- /dev/null +++ b/dts/bindings/sensor/bosch,bma4xx-i2c.yaml @@ -0,0 +1,10 @@ +# Copyright (c) 2023 Google LLC +# SPDX-License-Identifier: Apache-2.0 + +description: | + Bosch BMA4xx 3-axis acceleration sensors in I2C mode. See more info at: + https://www.bosch-sensortec.com/products/motion-sensors/accelerometers/ + +compatible: "bosch,bma4xx" + +include: [sensor-device.yaml, i2c-device.yaml, "bosch,bma4xx-common.yaml"] diff --git a/dts/bindings/sensor/bosch,bma4xx-spi.yaml b/dts/bindings/sensor/bosch,bma4xx-spi.yaml new file mode 100644 index 00000000000..dfadc8c686e --- /dev/null +++ b/dts/bindings/sensor/bosch,bma4xx-spi.yaml @@ -0,0 +1,13 @@ +# Copyright (c) 2023 Google LLC +# SPDX-License-Identifier: Apache-2.0 + +description: | + Bosch BMA4xx 3-axis acceleration sensors in SPI mode. See more info at: + https://www.bosch-sensortec.com/products/motion-sensors/accelerometers/ + + SPI mode is currently NOT supported in the driver but is specified in the + bindings for ease of future expansion. + +compatible: "bosch,bma4xx" + +include: [sensor-device.yaml, spi-device.yaml, "bosch,bma4xx-common.yaml"] diff --git a/tests/drivers/build_all/sensor/i2c.dtsi b/tests/drivers/build_all/sensor/i2c.dtsi index 9387a24cc85..aa5f6f3212b 100644 --- a/tests/drivers/build_all/sensor/i2c.dtsi +++ b/tests/drivers/build_all/sensor/i2c.dtsi @@ -879,3 +879,8 @@ test_i2c_lis2du12: lis2du12@7c { accel-range = ; accel-odr = ; }; + +test_i2c_bma4xx: bma4xx@7d { + compatible = "bosch,bma4xx"; + reg = <0x7d>; +}; From 516af3cb8432fd8fde2b10b8f7e78486d51b69d4 Mon Sep 17 00:00:00 2001 From: Bjarki Arge Andreasen Date: Wed, 22 Nov 2023 06:59:44 +0100 Subject: [PATCH 2094/3723] modem: pipe: Add TRANSMIT_IDLE event Add transmit idle event to modem_pipe_event enum. This will allow modules to await transmit idle before trying to transmit more data, instead of blindly calling modem_pipe_transmit in a loop until all data has been accepted. This will reduce the time spent trying to transmit data while the backend is blocked. Similarly to the RECEIVE_READY event, backends will call modem_pipe_notify_transmit_idle() to indicate that transmit is idle, and the TRANSMIT_IDLE event will be reinvoked when the modem pipe is attached to synchronize the state of the pipe with the user of it. Additionally, the TRANSMIT_IDLE event is also invoked when the modem is opened to further help synchronization with the user of the pipe. Signed-off-by: Bjarki Arge Andreasen --- include/zephyr/modem/pipe.h | 13 ++++++++++++- subsys/modem/modem_pipe.c | 21 +++++++++++++++++++++ 2 files changed, 33 insertions(+), 1 deletion(-) diff --git a/include/zephyr/modem/pipe.h b/include/zephyr/modem/pipe.h index abf8d74918e..a741a94a34c 100644 --- a/include/zephyr/modem/pipe.h +++ b/include/zephyr/modem/pipe.h @@ -25,6 +25,7 @@ extern "C" { enum modem_pipe_event { MODEM_PIPE_EVENT_OPENED = 0, MODEM_PIPE_EVENT_RECEIVE_READY, + MODEM_PIPE_EVENT_TRANSMIT_IDLE, MODEM_PIPE_EVENT_CLOSED, }; @@ -73,7 +74,8 @@ struct modem_pipe { enum modem_pipe_state state; struct k_mutex lock; struct k_condvar condvar; - bool receive_ready_pending; + uint8_t receive_ready_pending : 1; + uint8_t transmit_idle_pending : 1; }; /** @@ -213,6 +215,15 @@ void modem_pipe_notify_closed(struct modem_pipe *pipe); */ void modem_pipe_notify_receive_ready(struct modem_pipe *pipe); +/** + * @brief Notify user of pipe that pipe has no more data to transmit + * + * @param pipe Pipe instance + * + * @note Invoked from instance which initialized the pipe instance + */ +void modem_pipe_notify_transmit_idle(struct modem_pipe *pipe); + /** * @endcond */ diff --git a/subsys/modem/modem_pipe.c b/subsys/modem/modem_pipe.c index 01bdac50d3a..b0088fdefed 100644 --- a/subsys/modem/modem_pipe.c +++ b/subsys/modem/modem_pipe.c @@ -21,6 +21,7 @@ void modem_pipe_init(struct modem_pipe *pipe, void *data, struct modem_pipe_api pipe->user_data = NULL; pipe->state = MODEM_PIPE_STATE_CLOSED; pipe->receive_ready_pending = false; + pipe->transmit_idle_pending = true; k_mutex_init(&pipe->lock); k_condvar_init(&pipe->condvar); @@ -82,6 +83,10 @@ void modem_pipe_attach(struct modem_pipe *pipe, modem_pipe_api_callback callback pipe->callback(pipe, MODEM_PIPE_EVENT_RECEIVE_READY, pipe->user_data); } + if (pipe->transmit_idle_pending && (pipe->callback != NULL)) { + pipe->callback(pipe, MODEM_PIPE_EVENT_TRANSMIT_IDLE, pipe->user_data); + } + k_mutex_unlock(&pipe->lock); } @@ -97,6 +102,7 @@ int modem_pipe_transmit(struct modem_pipe *pipe, const uint8_t *buf, size_t size } ret = pipe->api->transmit(pipe->data, buf, size); + pipe->transmit_idle_pending = false; k_mutex_unlock(&pipe->lock); return ret; } @@ -179,6 +185,7 @@ void modem_pipe_notify_opened(struct modem_pipe *pipe) if (pipe->callback != NULL) { pipe->callback(pipe, MODEM_PIPE_EVENT_OPENED, pipe->user_data); + pipe->callback(pipe, MODEM_PIPE_EVENT_TRANSMIT_IDLE, pipe->user_data); } k_condvar_signal(&pipe->condvar); @@ -190,6 +197,7 @@ void modem_pipe_notify_closed(struct modem_pipe *pipe) k_mutex_lock(&pipe->lock, K_FOREVER); pipe->state = MODEM_PIPE_STATE_CLOSED; pipe->receive_ready_pending = false; + pipe->transmit_idle_pending = true; if (pipe->callback != NULL) { pipe->callback(pipe, MODEM_PIPE_EVENT_CLOSED, pipe->user_data); @@ -211,3 +219,16 @@ void modem_pipe_notify_receive_ready(struct modem_pipe *pipe) k_mutex_unlock(&pipe->lock); } + +void modem_pipe_notify_transmit_idle(struct modem_pipe *pipe) +{ + k_mutex_lock(&pipe->lock, K_FOREVER); + + pipe->transmit_idle_pending = true; + + if (pipe->callback != NULL) { + pipe->callback(pipe, MODEM_PIPE_EVENT_TRANSMIT_IDLE, pipe->user_data); + } + + k_mutex_unlock(&pipe->lock); +} From 8c6a9ee594acdf300636dd30f86fd05fe16fb03f Mon Sep 17 00:00:00 2001 From: Bjarki Arge Andreasen Date: Wed, 22 Nov 2023 07:30:12 +0100 Subject: [PATCH 2095/3723] modem: backend: uart: Implement transmit idle event Make async and interrupt driven UART backends notify transmit idle when transmit is idle. Signed-off-by: Bjarki Arge Andreasen --- include/zephyr/modem/backend/uart.h | 1 + subsys/modem/backends/modem_backend_uart.c | 9 +++++++++ subsys/modem/backends/modem_backend_uart_async.c | 2 ++ subsys/modem/backends/modem_backend_uart_isr.c | 1 + 4 files changed, 13 insertions(+) diff --git a/include/zephyr/modem/backend/uart.h b/include/zephyr/modem/backend/uart.h index 0ddef4df734..5f9f99370a0 100644 --- a/include/zephyr/modem/backend/uart.h +++ b/include/zephyr/modem/backend/uart.h @@ -43,6 +43,7 @@ struct modem_backend_uart { const struct device *uart; struct modem_pipe pipe; struct k_work receive_ready_work; + struct k_work transmit_idle_work; union { struct modem_backend_uart_isr isr; diff --git a/subsys/modem/backends/modem_backend_uart.c b/subsys/modem/backends/modem_backend_uart.c index b4b0b81c291..a8348b0b8a0 100644 --- a/subsys/modem/backends/modem_backend_uart.c +++ b/subsys/modem/backends/modem_backend_uart.c @@ -22,6 +22,14 @@ static void modem_backend_uart_receive_ready_handler(struct k_work *item) modem_pipe_notify_receive_ready(&backend->pipe); } +static void modem_backend_uart_transmit_idle_handler(struct k_work *item) +{ + struct modem_backend_uart *backend = + CONTAINER_OF(item, struct modem_backend_uart, transmit_idle_work); + + modem_pipe_notify_transmit_idle(&backend->pipe); +} + struct modem_pipe *modem_backend_uart_init(struct modem_backend_uart *backend, const struct modem_backend_uart_config *config) { @@ -35,6 +43,7 @@ struct modem_pipe *modem_backend_uart_init(struct modem_backend_uart *backend, memset(backend, 0x00, sizeof(*backend)); backend->uart = config->uart; k_work_init(&backend->receive_ready_work, modem_backend_uart_receive_ready_handler); + k_work_init(&backend->transmit_idle_work, modem_backend_uart_transmit_idle_handler); #ifdef CONFIG_MODEM_BACKEND_UART_ASYNC if (modem_backend_uart_async_is_supported(backend)) { diff --git a/subsys/modem/backends/modem_backend_uart_async.c b/subsys/modem/backends/modem_backend_uart_async.c index bd18edbd2f5..47148a77f77 100644 --- a/subsys/modem/backends/modem_backend_uart_async.c +++ b/subsys/modem/backends/modem_backend_uart_async.c @@ -44,6 +44,7 @@ static void modem_backend_uart_async_event_handler(const struct device *dev, case UART_TX_DONE: atomic_clear_bit(&backend->async.state, MODEM_BACKEND_UART_ASYNC_STATE_TRANSMITTING_BIT); + k_work_submit(&backend->transmit_idle_work); break; @@ -51,6 +52,7 @@ static void modem_backend_uart_async_event_handler(const struct device *dev, LOG_WRN("Transmit aborted"); atomic_clear_bit(&backend->async.state, MODEM_BACKEND_UART_ASYNC_STATE_TRANSMITTING_BIT); + k_work_submit(&backend->transmit_idle_work); break; diff --git a/subsys/modem/backends/modem_backend_uart_isr.c b/subsys/modem/backends/modem_backend_uart_isr.c index 7c88cb4673c..8a7075e3519 100644 --- a/subsys/modem/backends/modem_backend_uart_isr.c +++ b/subsys/modem/backends/modem_backend_uart_isr.c @@ -56,6 +56,7 @@ static void modem_backend_uart_isr_irq_handler_transmit_ready(struct modem_backe if (ring_buf_is_empty(&backend->isr.transmit_rb) == true) { uart_irq_tx_disable(backend->uart); + k_work_submit(&backend->transmit_idle_work); return; } From 4d99c69e4aa818c1407789e4e21dfa9102cb533b Mon Sep 17 00:00:00 2001 From: Bjarki Arge Andreasen Date: Wed, 22 Nov 2023 07:33:38 +0100 Subject: [PATCH 2096/3723] modem: backend: tty: Implement transmit idle event Implement transmit idle notification for TTY backend. Since TTY has an "infinite" transmit buffer, we invoke transmit idle immediately after writing the data to the TTY file. The test suite for the TTY backend has been updated to match the new behavior. Signed-off-by: Bjarki Arge Andreasen --- subsys/modem/backends/modem_backend_tty.c | 5 ++++- tests/subsys/modem/backends/tty/src/main.c | 18 +++++++++++++++++- 2 files changed, 21 insertions(+), 2 deletions(-) diff --git a/subsys/modem/backends/modem_backend_tty.c b/subsys/modem/backends/modem_backend_tty.c index b8864fc3d91..8375183be48 100644 --- a/subsys/modem/backends/modem_backend_tty.c +++ b/subsys/modem/backends/modem_backend_tty.c @@ -73,8 +73,11 @@ static int modem_backend_tty_open(void *data) static int modem_backend_tty_transmit(void *data, const uint8_t *buf, size_t size) { struct modem_backend_tty *backend = (struct modem_backend_tty *)data; + int ret; - return write(backend->tty_fd, buf, size); + ret = write(backend->tty_fd, buf, size); + modem_pipe_notify_transmit_idle(&backend->pipe); + return ret; } static int modem_backend_tty_receive(void *data, uint8_t *buf, size_t size) diff --git a/tests/subsys/modem/backends/tty/src/main.c b/tests/subsys/modem/backends/tty/src/main.c index 49a1841486a..96ebdb2763d 100644 --- a/tests/subsys/modem/backends/tty/src/main.c +++ b/tests/subsys/modem/backends/tty/src/main.c @@ -22,7 +22,8 @@ #define TEST_MODEM_BACKEND_TTY_PIPE_EVENT_OPENED_BIT (0) #define TEST_MODEM_BACKEND_TTY_PIPE_EVENT_RRDY_BIT (1) -#define TEST_MODEM_BACKEND_TTY_PIPE_EVENT_CLOSED_BIT (2) +#define TEST_MODEM_BACKEND_TTY_PIPE_EVENT_TIDLE_BIT (2) +#define TEST_MODEM_BACKEND_TTY_PIPE_EVENT_CLOSED_BIT (3) #define TEST_MODEM_BACKEND_TTY_OP_DELAY (K_MSEC(1000)) @@ -72,6 +73,10 @@ static void modem_pipe_callback_handler(struct modem_pipe *pipe, enum modem_pipe atomic_set_bit(&tty_pipe_events, TEST_MODEM_BACKEND_TTY_PIPE_EVENT_RRDY_BIT); break; + case MODEM_PIPE_EVENT_TRANSMIT_IDLE: + atomic_set_bit(&tty_pipe_events, TEST_MODEM_BACKEND_TTY_PIPE_EVENT_TIDLE_BIT); + break; + case MODEM_PIPE_EVENT_CLOSED: atomic_set_bit(&tty_pipe_events, TEST_MODEM_BACKEND_TTY_PIPE_EVENT_CLOSED_BIT); break; @@ -122,9 +127,13 @@ static void test_modem_backend_tty_teardown(void *f) /*************************************************************************************************/ ZTEST(modem_backend_tty_suite, test_close_open) { + bool result; + zassert_ok(modem_pipe_close(tty_pipe), "Failed to close pipe"); zassert_ok(modem_pipe_close(tty_pipe), "Pipe should already be closed"); zassert_ok(modem_pipe_open(tty_pipe), "Failed to open pipe"); + result = atomic_test_bit(&tty_pipe_events, TEST_MODEM_BACKEND_TTY_PIPE_EVENT_TIDLE_BIT); + zassert_true(result, "Transmit idle event should be set"); zassert_ok(modem_pipe_open(tty_pipe), "Pipe should already be open"); } @@ -172,12 +181,19 @@ ZTEST(modem_backend_tty_suite, test_transmit) { int ret; char msg[] = "Test me buddy 2"; + bool result; + + result = atomic_test_bit(&tty_pipe_events, TEST_MODEM_BACKEND_TTY_PIPE_EVENT_TIDLE_BIT); + zassert_false(result, "Transmit idle event should not be set"); ret = modem_pipe_transmit(tty_pipe, msg, sizeof(msg)); zassert_true(ret == sizeof(msg), "Failed to transmit using pipe"); k_sleep(TEST_MODEM_BACKEND_TTY_OP_DELAY); + result = atomic_test_bit(&tty_pipe_events, TEST_MODEM_BACKEND_TTY_PIPE_EVENT_TIDLE_BIT); + zassert_true(result, "Transmit idle event should be set"); + ret = read(primary_fd, buffer1, sizeof(buffer1)); zassert_true(ret == sizeof(msg), "Read incorrect number of bytes"); ret = memcmp(msg, buffer1, sizeof(msg)); From 9176e5c5681d3cafc6087c29d52017fe134ccde8 Mon Sep 17 00:00:00 2001 From: Bjarki Arge Andreasen Date: Thu, 23 Nov 2023 11:15:09 +0100 Subject: [PATCH 2097/3723] modem: pipe: Add test suite Add test suite for the modem_pipe module. Signed-off-by: Bjarki Arge Andreasen --- tests/subsys/modem/modem_pipe/CMakeLists.txt | 8 + tests/subsys/modem/modem_pipe/prj.conf | 8 + tests/subsys/modem/modem_pipe/src/main.c | 401 +++++++++++++++++++ tests/subsys/modem/modem_pipe/testcase.yaml | 8 + 4 files changed, 425 insertions(+) create mode 100644 tests/subsys/modem/modem_pipe/CMakeLists.txt create mode 100644 tests/subsys/modem/modem_pipe/prj.conf create mode 100644 tests/subsys/modem/modem_pipe/src/main.c create mode 100644 tests/subsys/modem/modem_pipe/testcase.yaml diff --git a/tests/subsys/modem/modem_pipe/CMakeLists.txt b/tests/subsys/modem/modem_pipe/CMakeLists.txt new file mode 100644 index 00000000000..9d160a67720 --- /dev/null +++ b/tests/subsys/modem/modem_pipe/CMakeLists.txt @@ -0,0 +1,8 @@ +# Copyright (c) 2023 Trackunit Corporation +# SPDX-License-Identifier: Apache-2.0 + +cmake_minimum_required(VERSION 3.20.0) +find_package(Zephyr REQUIRED HINTS $ENV{ZEPHYR_BASE}) +project(modem_pipe_test) + +target_sources(app PRIVATE src/main.c) diff --git a/tests/subsys/modem/modem_pipe/prj.conf b/tests/subsys/modem/modem_pipe/prj.conf new file mode 100644 index 00000000000..ab3228738b9 --- /dev/null +++ b/tests/subsys/modem/modem_pipe/prj.conf @@ -0,0 +1,8 @@ +# Copyright (c) 2023 Trackunit Corporation +# SPDX-License-Identifier: Apache-2.0 + +CONFIG_NO_OPTIMIZATIONS=y +CONFIG_MODEM_MODULES=y +CONFIG_MODEM_PIPE=y +CONFIG_EVENTS=y +CONFIG_ZTEST=y diff --git a/tests/subsys/modem/modem_pipe/src/main.c b/tests/subsys/modem/modem_pipe/src/main.c new file mode 100644 index 00000000000..07cc93decfe --- /dev/null +++ b/tests/subsys/modem/modem_pipe/src/main.c @@ -0,0 +1,401 @@ +/* + * Copyright (c) 2023 Trackunit Corporation + * + * SPDX-License-Identifier: Apache-2.0 + */ + +/*************************************************************************************************/ +/* Dependencies */ +/*************************************************************************************************/ +#include +#include +#include +#include +#include + +#define TEST_MODEM_PIPE_EVENT_OPENED_BIT 0 +#define TEST_MODEM_PIPE_EVENT_TRANSMIT_IDLE_BIT 1 +#define TEST_MODEM_PIPE_EVENT_RECEIVE_READY_BIT 2 +#define TEST_MODEM_PIPE_EVENT_CLOSED_BIT 3 +#define TEST_MODEM_PIPE_NOTIFY_TIMEOUT K_MSEC(10) +#define TEST_MODEM_PIPE_WAIT_TIMEOUT K_MSEC(20) + +/*************************************************************************************************/ +/* Fake modem_pipe backend */ +/*************************************************************************************************/ +struct modem_backend_fake { + struct modem_pipe pipe; + + struct k_work_delayable opened_dwork; + struct k_work_delayable transmit_idle_dwork; + struct k_work_delayable closed_dwork; + + const uint8_t *transmit_buffer; + size_t transmit_buffer_size; + + uint8_t *receive_buffer; + size_t receive_buffer_size; + + uint8_t synchronous : 1; + uint8_t open_called : 1; + uint8_t transmit_called : 1; + uint8_t receive_called : 1; + uint8_t close_called : 1; +}; + +static void modem_backend_fake_opened_handler(struct k_work *item) +{ + struct k_work_delayable *dwork = k_work_delayable_from_work(item); + struct modem_backend_fake *backend = + CONTAINER_OF(dwork, struct modem_backend_fake, opened_dwork); + + modem_pipe_notify_opened(&backend->pipe); +} + +static int modem_backend_fake_open(void *data) +{ + struct modem_backend_fake *backend = data; + + backend->open_called = true; + + if (backend->synchronous) { + modem_pipe_notify_opened(&backend->pipe); + } else { + k_work_schedule(&backend->opened_dwork, TEST_MODEM_PIPE_NOTIFY_TIMEOUT); + } + + return 0; +} + +static void modem_backend_fake_transmit_idle_handler(struct k_work *item) +{ + struct k_work_delayable *dwork = k_work_delayable_from_work(item); + struct modem_backend_fake *backend = + CONTAINER_OF(dwork, struct modem_backend_fake, transmit_idle_dwork); + + modem_pipe_notify_transmit_idle(&backend->pipe); +} + +static int modem_backend_fake_transmit(void *data, const uint8_t *buf, size_t size) +{ + struct modem_backend_fake *backend = data; + + backend->transmit_called = true; + backend->transmit_buffer = buf; + backend->transmit_buffer_size = size; + + if (backend->synchronous) { + modem_pipe_notify_transmit_idle(&backend->pipe); + } else { + k_work_schedule(&backend->transmit_idle_dwork, TEST_MODEM_PIPE_NOTIFY_TIMEOUT); + } + + return size; +} + +static int modem_backend_fake_receive(void *data, uint8_t *buf, size_t size) +{ + struct modem_backend_fake *backend = data; + + backend->receive_called = true; + backend->receive_buffer = buf; + backend->receive_buffer_size = size; + return size; +} + +static void modem_backend_fake_closed_handler(struct k_work *item) +{ + struct k_work_delayable *dwork = k_work_delayable_from_work(item); + struct modem_backend_fake *backend = + CONTAINER_OF(dwork, struct modem_backend_fake, closed_dwork); + + modem_pipe_notify_closed(&backend->pipe); +} + +static int modem_backend_fake_close(void *data) +{ + struct modem_backend_fake *backend = data; + + backend->close_called = true; + + if (backend->synchronous) { + modem_pipe_notify_closed(&backend->pipe); + } else { + k_work_schedule(&backend->closed_dwork, TEST_MODEM_PIPE_NOTIFY_TIMEOUT); + } + + return 0; +} + +static struct modem_pipe_api modem_backend_fake_api = { + .open = modem_backend_fake_open, + .transmit = modem_backend_fake_transmit, + .receive = modem_backend_fake_receive, + .close = modem_backend_fake_close, +}; + +static struct modem_pipe *modem_backend_fake_init(struct modem_backend_fake *backend) +{ + k_work_init_delayable(&backend->opened_dwork, + modem_backend_fake_opened_handler); + k_work_init_delayable(&backend->transmit_idle_dwork, + modem_backend_fake_transmit_idle_handler); + k_work_init_delayable(&backend->closed_dwork, + modem_backend_fake_closed_handler); + + modem_pipe_init(&backend->pipe, backend, &modem_backend_fake_api); + return &backend->pipe; +} + +static void modem_backend_fake_reset(struct modem_backend_fake *backend) +{ + backend->transmit_buffer = NULL; + backend->transmit_buffer_size = 0; + backend->receive_buffer = NULL; + backend->transmit_buffer_size = 0; + backend->open_called = false; + backend->transmit_called = false; + backend->receive_called = false; + backend->close_called = false; +} + +static void modem_backend_fake_set_sync(struct modem_backend_fake *backend, bool sync) +{ + backend->synchronous = sync; +} + +/*************************************************************************************************/ +/* Instances */ +/*************************************************************************************************/ +static struct modem_backend_fake test_backend; +static struct modem_pipe *test_pipe; +static uint32_t test_user_data; +static atomic_t test_state; +static uint8_t test_buffer[4]; +static size_t test_buffer_size = sizeof(test_buffer); + +/*************************************************************************************************/ +/* Callbacks */ +/*************************************************************************************************/ +static void modem_pipe_fake_handler(struct modem_pipe *pipe, enum modem_pipe_event event, + void *user_data) +{ + __ASSERT(pipe == test_pipe, "Incorrect pipe provided with callback"); + __ASSERT(user_data == (void *)&test_user_data, "Incorrect user data ptr"); + + switch (event) { + case MODEM_PIPE_EVENT_OPENED: + atomic_set_bit(&test_state, TEST_MODEM_PIPE_EVENT_OPENED_BIT); + break; + + case MODEM_PIPE_EVENT_RECEIVE_READY: + atomic_set_bit(&test_state, TEST_MODEM_PIPE_EVENT_RECEIVE_READY_BIT); + break; + + case MODEM_PIPE_EVENT_TRANSMIT_IDLE: + atomic_set_bit(&test_state, TEST_MODEM_PIPE_EVENT_TRANSMIT_IDLE_BIT); + break; + + case MODEM_PIPE_EVENT_CLOSED: + atomic_set_bit(&test_state, TEST_MODEM_PIPE_EVENT_CLOSED_BIT); + break; + } +} + +static void test_reset(void) +{ + modem_backend_fake_reset(&test_backend); + atomic_set(&test_state, 0); +} + +static void *modem_backend_fake_setup(void) +{ + test_pipe = modem_backend_fake_init(&test_backend); + return NULL; +} + +static void modem_backend_fake_before(void *f) +{ + modem_backend_fake_set_sync(&test_backend, false); + modem_pipe_attach(test_pipe, modem_pipe_fake_handler, &test_user_data); + test_reset(); +} + +static void modem_backend_fake_after(void *f) +{ + __ASSERT(modem_pipe_close(test_pipe) == 0, "Failed to close pipe"); + modem_pipe_release(test_pipe); +} + +/* Opening pipe shall raise events OPENED and TRANSMIT_IDLE */ +static void test_pipe_open(void) +{ + zassert_ok(modem_pipe_open(test_pipe), "Failed to open pipe"); + zassert_true(test_backend.open_called, "open was not called"); + zassert_equal(atomic_get(&test_state), + BIT(TEST_MODEM_PIPE_EVENT_OPENED_BIT) | + BIT(TEST_MODEM_PIPE_EVENT_TRANSMIT_IDLE_BIT), + "Unexpected state %u", atomic_get(&test_state)); +} + +/* Re-opening pipe shall have no effect */ +static void test_pipe_reopen(void) +{ + zassert_ok(modem_pipe_open(test_pipe), "Failed to re-open pipe"); + zassert_false(test_backend.open_called, "open was called"); + zassert_equal(atomic_get(&test_state), 0, + "Unexpected state %u", atomic_get(&test_state)); +} + +/* Closing pipe shall raise event CLOSED */ +static void test_pipe_close(void) +{ + zassert_ok(modem_pipe_close(test_pipe), "Failed to close pipe"); + zassert_true(test_backend.close_called, "close was not called"); + zassert_equal(atomic_get(&test_state), BIT(TEST_MODEM_PIPE_EVENT_CLOSED_BIT), + "Unexpected state %u", atomic_get(&test_state)); +} + +/* Re-closing pipe shall have no effect */ +static void test_pipe_reclose(void) +{ + zassert_ok(modem_pipe_close(test_pipe), "Failed to re-close pipe"); + zassert_false(test_backend.close_called, "close was called"); + zassert_equal(atomic_get(&test_state), 0, + "Unexpected state %u", atomic_get(&test_state)); +} + +static void test_pipe_async_transmit(void) +{ + zassert_equal(modem_pipe_transmit(test_pipe, test_buffer, test_buffer_size), + test_buffer_size, "Failed to transmit"); + zassert_true(test_backend.transmit_called, "transmit was not called"); + zassert_equal(test_backend.transmit_buffer, test_buffer, "Incorrect buffer"); + zassert_equal(test_backend.transmit_buffer_size, test_buffer_size, + "Incorrect buffer size"); + zassert_equal(atomic_get(&test_state), 0, "Unexpected state %u", + atomic_get(&test_state)); + k_sleep(TEST_MODEM_PIPE_WAIT_TIMEOUT); + zassert_equal(atomic_get(&test_state), BIT(TEST_MODEM_PIPE_EVENT_TRANSMIT_IDLE_BIT), + "Unexpected state %u", atomic_get(&test_state)); +} + +static void test_pipe_sync_transmit(void) +{ + zassert_equal(modem_pipe_transmit(test_pipe, test_buffer, test_buffer_size), + test_buffer_size, "Failed to transmit"); + zassert_true(test_backend.transmit_called, "transmit was not called"); + zassert_equal(test_backend.transmit_buffer, test_buffer, "Incorrect buffer"); + zassert_equal(test_backend.transmit_buffer_size, test_buffer_size, + "Incorrect buffer size"); + zassert_equal(atomic_get(&test_state), BIT(TEST_MODEM_PIPE_EVENT_TRANSMIT_IDLE_BIT), + "Unexpected state %u", atomic_get(&test_state)); +} + +static void test_pipe_attach_receive_not_ready_transmit_idle(void) +{ + modem_pipe_attach(test_pipe, modem_pipe_fake_handler, &test_user_data); + zassert_equal(atomic_get(&test_state), BIT(TEST_MODEM_PIPE_EVENT_TRANSMIT_IDLE_BIT), + "Unexpected state %u", atomic_get(&test_state)); +} + +static void test_pipe_attach_receive_ready_transmit_idle(void) +{ + modem_pipe_attach(test_pipe, modem_pipe_fake_handler, &test_user_data); + zassert_equal(atomic_get(&test_state), + BIT(TEST_MODEM_PIPE_EVENT_TRANSMIT_IDLE_BIT) | + BIT(TEST_MODEM_PIPE_EVENT_RECEIVE_READY_BIT), + "Unexpected state %u", atomic_get(&test_state)); +} + +static void test_pipe_receive(void) +{ + zassert_equal(modem_pipe_receive(test_pipe, test_buffer, test_buffer_size), + test_buffer_size, "Failed to receive"); + zassert_true(test_backend.receive_called, "receive was not called"); + zassert_equal(test_backend.receive_buffer, test_buffer, "Incorrect buffer"); + zassert_equal(test_backend.receive_buffer_size, test_buffer_size, + "Incorrect buffer size"); + zassert_equal(atomic_get(&test_state), 0, "Unexpected state %u", + atomic_get(&test_state)); +} + +static void test_pipe_notify_receive_ready(void) +{ + modem_pipe_notify_receive_ready(test_pipe); + zassert_equal(atomic_get(&test_state), BIT(TEST_MODEM_PIPE_EVENT_RECEIVE_READY_BIT), + "Unexpected state %u", atomic_get(&test_state)); +} + +ZTEST(modem_pipe, test_async_open_close) +{ + test_pipe_open(); + test_reset(); + test_pipe_reopen(); + test_reset(); + test_pipe_close(); + test_reset(); + test_pipe_reclose(); +} + +ZTEST(modem_pipe, test_sync_open_close) +{ + modem_backend_fake_set_sync(&test_backend, true); + test_pipe_open(); + test_reset(); + test_pipe_reopen(); + test_reset(); + test_pipe_close(); + test_reset(); + test_pipe_reclose(); +} + +ZTEST(modem_pipe, test_async_transmit) +{ + test_pipe_open(); + test_reset(); + test_pipe_async_transmit(); +} + +ZTEST(modem_pipe, test_sync_transmit) +{ + modem_backend_fake_set_sync(&test_backend, true); + test_pipe_open(); + test_reset(); + test_pipe_sync_transmit(); +} + +ZTEST(modem_pipe, test_attach) +{ + test_pipe_open(); + + /* + * Attaching pipe shall reinvoke TRANSMIT IDLE, but not RECEIVE READY as + * receive is not ready. + */ + test_reset(); + test_pipe_attach_receive_not_ready_transmit_idle(); + + /* + * Notify receive ready and expect receive ready to be re-invoked every + * time the pipe is attached to. + */ + test_reset(); + test_pipe_notify_receive_ready(); + test_reset(); + test_pipe_attach_receive_ready_transmit_idle(); + test_reset(); + test_pipe_attach_receive_ready_transmit_idle(); + + /* + * Receiving data from the pipe shall clear the receive ready state, stopping + * the invocation of receive ready on attach. + */ + test_reset(); + test_pipe_receive(); + test_reset(); + test_pipe_attach_receive_not_ready_transmit_idle(); +} + +ZTEST_SUITE(modem_pipe, NULL, modem_backend_fake_setup, modem_backend_fake_before, + modem_backend_fake_after, NULL); diff --git a/tests/subsys/modem/modem_pipe/testcase.yaml b/tests/subsys/modem/modem_pipe/testcase.yaml new file mode 100644 index 00000000000..39a8c8e6c2c --- /dev/null +++ b/tests/subsys/modem/modem_pipe/testcase.yaml @@ -0,0 +1,8 @@ +# Copyright (c) 2023 Trackunit Corporation +# SPDX-License-Identifier: Apache-2.0 + +tests: + modem.modem_pipe: + tags: modem_pipe + harness: ztest + platform_allow: native_sim From 1270bce4d84b6146aae7ffbe07579aa4a85ebf27 Mon Sep 17 00:00:00 2001 From: Pisit Sawangvonganan Date: Tue, 2 Jan 2024 22:53:57 +0700 Subject: [PATCH 2098/3723] modem: modem_cmux: optimize modem_cmux_transmit_frame to save ROM This optimization aggregates frame headers before adding to the ring buffer and computes the FCS of the frame header in one operation. This approach improves execution efficiency and reduces memory footprint. This code adjustment aligns with the changes proposed in https://github.com/zephyrproject-rtos/zephyr/pull/67062. Signed-off-by: Pisit Sawangvonganan --- subsys/modem/modem_cmux.c | 46 +++++++++++++++++++-------------------- 1 file changed, 22 insertions(+), 24 deletions(-) diff --git a/subsys/modem/modem_cmux.c b/subsys/modem/modem_cmux.c index 472d1a7149a..dc7c3915566 100644 --- a/subsys/modem/modem_cmux.c +++ b/subsys/modem/modem_cmux.c @@ -205,57 +205,55 @@ static void modem_cmux_bus_callback(struct modem_pipe *pipe, enum modem_pipe_eve static uint16_t modem_cmux_transmit_frame(struct modem_cmux *cmux, const struct modem_cmux_frame *frame) { - uint8_t byte; + uint8_t buf[MODEM_CMUX_FRAME_SIZE_MAX]; uint8_t fcs; uint16_t space; uint16_t data_len; + uint16_t buf_idx; space = ring_buf_space_get(&cmux->transmit_rb) - MODEM_CMUX_FRAME_SIZE_MAX; data_len = (space < frame->data_len) ? space : frame->data_len; /* SOF */ - byte = 0xF9; - ring_buf_put(&cmux->transmit_rb, &byte, 1); + buf[0] = 0xF9; /* DLCI Address (Max 63) */ - byte = 0x01 | (frame->cr << 1) | (frame->dlci_address << 2); - fcs = crc8(&byte, 1, MODEM_CMUX_FCS_POLYNOMIAL, MODEM_CMUX_FCS_INIT_VALUE, true); - ring_buf_put(&cmux->transmit_rb, &byte, 1); + buf[1] = 0x01 | (frame->cr << 1) | (frame->dlci_address << 2); /* Frame type and poll/final */ - byte = frame->type | (frame->pf << 4); - fcs = crc8(&byte, 1, MODEM_CMUX_FCS_POLYNOMIAL, fcs, true); - ring_buf_put(&cmux->transmit_rb, &byte, 1); + buf[2] = frame->type | (frame->pf << 4); /* Data length */ if (data_len > 127) { - byte = data_len << 1; - fcs = crc8(&byte, 1, MODEM_CMUX_FCS_POLYNOMIAL, fcs, true); - ring_buf_put(&cmux->transmit_rb, &byte, 1); - byte = data_len >> 7; - ring_buf_put(&cmux->transmit_rb, &byte, 1); + buf[3] = data_len << 1; + buf[4] = data_len >> 7; + buf_idx = 5; } else { - byte = 0x01 | (data_len << 1); - ring_buf_put(&cmux->transmit_rb, &byte, 1); + buf[3] = 0x01 | (data_len << 1); + buf_idx = 4; } + /* Compute FCS for the header (exclude SOF) */ + fcs = crc8(&buf[1], (buf_idx - 1), MODEM_CMUX_FCS_POLYNOMIAL, MODEM_CMUX_FCS_INIT_VALUE, + true); + /* FCS final */ if (frame->type == MODEM_CMUX_FRAME_TYPE_UIH) { - fcs = 0xFF - crc8(&byte, 1, MODEM_CMUX_FCS_POLYNOMIAL, fcs, true); + fcs = 0xFF - fcs; } else { - fcs = crc8(&byte, 1, MODEM_CMUX_FCS_POLYNOMIAL, fcs, true); fcs = 0xFF - crc8(frame->data, data_len, MODEM_CMUX_FCS_POLYNOMIAL, fcs, true); } + /* Frame header */ + ring_buf_put(&cmux->transmit_rb, buf, buf_idx); + /* Data */ ring_buf_put(&cmux->transmit_rb, frame->data, data_len); - /* FCS */ - ring_buf_put(&cmux->transmit_rb, &fcs, 1); - - /* EOF */ - byte = 0xF9; - ring_buf_put(&cmux->transmit_rb, &byte, 1); + /* FCS and EOF will be put on the same call */ + buf[0] = fcs; + buf[1] = 0xF9; + ring_buf_put(&cmux->transmit_rb, buf, 2); k_work_schedule(&cmux->transmit_work, K_NO_WAIT); return data_len; } From 9310b34b44fd8b4895e84e2b753320616e7e30b3 Mon Sep 17 00:00:00 2001 From: Emil Gydesen Date: Thu, 4 Jan 2024 14:29:28 +0100 Subject: [PATCH 2099/3723] tests: bsim: Bluetooth: BAP: Refactor bap_test_stream Refactor the bap_test_stream struct and rename to audio_test_stream so that it can be used by CAP as well. Signed-off-by: Emil Gydesen --- .../audio/src/bap_broadcast_sink_test.c | 6 +- .../audio/src/bap_broadcast_source_test.c | 20 +++--- .../audio/src/bap_unicast_client_test.c | 49 ++++++++------ .../audio/src/bap_unicast_server_test.c | 40 ++++++------ .../audio/src/cap_initiator_broadcast_test.c | 65 ++++++++++++------- tests/bsim/bluetooth/audio/src/common.h | 32 ++++++++- 6 files changed, 132 insertions(+), 80 deletions(-) diff --git a/tests/bsim/bluetooth/audio/src/bap_broadcast_sink_test.c b/tests/bsim/bluetooth/audio/src/bap_broadcast_sink_test.c index 1f7c91288c8..df9203a2b98 100644 --- a/tests/bsim/bluetooth/audio/src/bap_broadcast_sink_test.c +++ b/tests/bsim/bluetooth/audio/src/bap_broadcast_sink_test.c @@ -31,7 +31,7 @@ static struct bt_le_scan_recv_info broadcaster_info; static bt_addr_le_t broadcaster_addr; static struct bt_le_per_adv_sync *pa_sync; static uint32_t broadcaster_broadcast_id; -static struct bap_test_stream broadcast_sink_streams[CONFIG_BT_BAP_BROADCAST_SNK_STREAM_COUNT]; +static struct audio_test_stream broadcast_sink_streams[CONFIG_BT_BAP_BROADCAST_SNK_STREAM_COUNT]; static struct bt_bap_stream *streams[ARRAY_SIZE(broadcast_sink_streams)]; static uint32_t requested_bis_sync; static struct bt_le_ext_adv *ext_adv; @@ -274,7 +274,7 @@ static void recv_cb(struct bt_bap_stream *stream, const struct bt_iso_recv_info *info, struct net_buf *buf) { - struct bap_test_stream *test_stream = CONTAINER_OF(stream, struct bap_test_stream, stream); + struct audio_test_stream *test_stream = audio_test_stream_from_bap_stream(stream); if ((test_stream->rx_cnt % 100U) == 0U) { printk("Incoming audio on stream %p len %u and ts %u\n", stream, buf->len, @@ -363,7 +363,7 @@ static int init(void) UNSET_FLAG(pa_synced); for (size_t i = 0U; i < ARRAY_SIZE(streams); i++) { - streams[i] = &broadcast_sink_streams[i].stream; + streams[i] = bap_stream_from_audio_test_stream(&broadcast_sink_streams[i]); bt_bap_stream_cb_register(streams[i], &stream_ops); } diff --git a/tests/bsim/bluetooth/audio/src/bap_broadcast_source_test.c b/tests/bsim/bluetooth/audio/src/bap_broadcast_source_test.c index 1559f8c3010..29c77219a7c 100644 --- a/tests/bsim/bluetooth/audio/src/bap_broadcast_source_test.c +++ b/tests/bsim/bluetooth/audio/src/bap_broadcast_source_test.c @@ -28,7 +28,7 @@ NET_BUF_POOL_FIXED_DEFINE(tx_pool, CONFIG_BT_CONN_TX_USER_DATA_SIZE, NULL); extern enum bst_result_t bst_result; -static struct bap_test_stream broadcast_source_streams[CONFIG_BT_BAP_BROADCAST_SRC_STREAM_COUNT]; +static struct audio_test_stream broadcast_source_streams[CONFIG_BT_BAP_BROADCAST_SRC_STREAM_COUNT]; static struct bt_bap_lc3_preset preset_16_2_1 = BT_BAP_LC3_BROADCAST_PRESET_16_2_1( BT_AUDIO_LOCATION_FRONT_LEFT, BT_AUDIO_CONTEXT_TYPE_UNSPECIFIED); static struct bt_bap_lc3_preset preset_16_1_1 = BT_BAP_LC3_BROADCAST_PRESET_16_1_1( @@ -51,7 +51,7 @@ static void stopped_cb(struct bt_bap_stream *stream, uint8_t reason) static void stream_sent_cb(struct bt_bap_stream *stream) { - struct bap_test_stream *test_stream = CONTAINER_OF(stream, struct bap_test_stream, stream); + struct audio_test_stream *test_stream = audio_test_stream_from_bap_stream(stream); struct net_buf *buf; int ret; @@ -111,7 +111,8 @@ static int setup_broadcast_source(struct bt_bap_broadcast_source **source) sizeof(broadcast_source_streams)); for (size_t i = 0; i < ARRAY_SIZE(stream_params); i++) { - stream_params[i].stream = &broadcast_source_streams[i].stream; + stream_params[i].stream = + bap_stream_from_audio_test_stream(&broadcast_source_streams[i]); bt_bap_stream_cb_register(stream_params[i].stream, &stream_ops); #if CONFIG_BT_AUDIO_CODEC_CFG_MAX_DATA_SIZE > 0 @@ -141,7 +142,7 @@ static int setup_broadcast_source(struct bt_bap_broadcast_source **source) } for (size_t i = 0U; i < ARRAY_SIZE(broadcast_source_streams); i++) { - struct bap_test_stream *test_stream = &broadcast_source_streams[i]; + struct audio_test_stream *test_stream = &broadcast_source_streams[i]; test_stream->tx_sdu_size = preset_16_1_1.qos.sdu; } @@ -258,7 +259,8 @@ static void test_broadcast_source_reconfig(struct bt_bap_broadcast_source *sourc int err; for (size_t i = 0; i < ARRAY_SIZE(stream_params); i++) { - stream_params[i].stream = &broadcast_source_streams[i].stream; + stream_params[i].stream = + bap_stream_from_audio_test_stream(&broadcast_source_streams[i]); stream_params[i].data_len = ARRAY_SIZE(bis_codec_data); stream_params[i].data = bis_codec_data; } @@ -283,7 +285,7 @@ static void test_broadcast_source_reconfig(struct bt_bap_broadcast_source *sourc } for (size_t i = 0U; i < ARRAY_SIZE(broadcast_source_streams); i++) { - struct bap_test_stream *test_stream = &broadcast_source_streams[i]; + struct audio_test_stream *test_stream = &broadcast_source_streams[i]; test_stream->tx_sdu_size = preset_16_1_1.qos.sdu; } @@ -433,12 +435,10 @@ static void test_main(void) printk("Sending data\n"); for (size_t i = 0U; i < ARRAY_SIZE(broadcast_source_streams); i++) { for (unsigned int j = 0U; j < BROADCAST_ENQUEUE_COUNT; j++) { - struct bap_test_stream *test_stream = - CONTAINER_OF(&broadcast_source_streams[i].stream, - struct bap_test_stream, stream); + struct audio_test_stream *test_stream = &broadcast_source_streams[i]; test_stream->tx_active = true; - stream_sent_cb(&broadcast_source_streams[i].stream); + stream_sent_cb(&test_stream->stream.bap_stream); } } diff --git a/tests/bsim/bluetooth/audio/src/bap_unicast_client_test.c b/tests/bsim/bluetooth/audio/src/bap_unicast_client_test.c index 6f2a4b3ab15..81ca44af0e1 100644 --- a/tests/bsim/bluetooth/audio/src/bap_unicast_client_test.c +++ b/tests/bsim/bluetooth/audio/src/bap_unicast_client_test.c @@ -24,12 +24,12 @@ NET_BUF_POOL_FIXED_DEFINE(tx_pool, TOTAL_BUF_NEEDED, BT_ISO_SDU_BUF_SIZE(CONFIG_ extern enum bst_result_t bst_result; static volatile size_t sent_count; -static struct bap_test_stream g_streams[CONFIG_BT_BAP_UNICAST_CLIENT_ASE_SNK_COUNT]; +static struct audio_test_stream test_streams[CONFIG_BT_BAP_UNICAST_CLIENT_ASE_SNK_COUNT]; static struct bt_bap_ep *g_sinks[CONFIG_BT_BAP_UNICAST_CLIENT_ASE_SNK_COUNT]; static struct bt_bap_ep *g_sources[CONFIG_BT_BAP_UNICAST_CLIENT_ASE_SRC_COUNT]; -static struct bt_bap_unicast_group_stream_pair_param pair_params[ARRAY_SIZE(g_streams)]; -static struct bt_bap_unicast_group_stream_param stream_params[ARRAY_SIZE(g_streams)]; +static struct bt_bap_unicast_group_stream_pair_param pair_params[ARRAY_SIZE(test_streams)]; +static struct bt_bap_unicast_group_stream_param stream_params[ARRAY_SIZE(test_streams)]; /* Mandatory support preset by both client and server */ static struct bt_bap_lc3_preset preset_16_2_1 = BT_BAP_LC3_UNICAST_PRESET_16_2_1( @@ -63,7 +63,7 @@ static void stream_configured(struct bt_bap_stream *stream, static void stream_qos_set(struct bt_bap_stream *stream) { - struct bap_test_stream *test_stream = CONTAINER_OF(stream, struct bap_test_stream, stream); + struct audio_test_stream *test_stream = audio_test_stream_from_bap_stream(stream); printk("QoS set stream %p\n", stream); @@ -95,7 +95,7 @@ static void stream_metadata_updated(struct bt_bap_stream *stream) static void stream_disabled(struct bt_bap_stream *stream) { - struct bap_test_stream *test_stream = CONTAINER_OF(stream, struct bap_test_stream, stream); + struct audio_test_stream *test_stream = audio_test_stream_from_bap_stream(stream); test_stream->tx_active = false; @@ -119,7 +119,7 @@ static void stream_released(struct bt_bap_stream *stream) static void stream_recv_cb(struct bt_bap_stream *stream, const struct bt_iso_recv_info *info, struct net_buf *buf) { - struct bap_test_stream *test_stream = CONTAINER_OF(stream, struct bap_test_stream, stream); + struct audio_test_stream *test_stream = audio_test_stream_from_bap_stream(stream); printk("Incoming audio on stream %p len %u and ts %u\n", stream, buf->len, info->ts); @@ -152,7 +152,7 @@ static void stream_recv_cb(struct bt_bap_stream *stream, const struct bt_iso_rec static void stream_sent_cb(struct bt_bap_stream *stream) { - struct bap_test_stream *test_stream = CONTAINER_OF(stream, struct bap_test_stream, stream); + struct audio_test_stream *test_stream = audio_test_stream_from_bap_stream(stream); struct net_buf *buf; int ret; @@ -489,8 +489,11 @@ static void init(void) return; } - for (size_t i = 0; i < ARRAY_SIZE(g_streams); i++) { - g_streams[i].stream.ops = &stream_ops; + for (size_t i = 0; i < ARRAY_SIZE(test_streams); i++) { + struct bt_bap_stream *bap_stream = + bap_stream_from_audio_test_stream(&test_streams[i]); + + bap_stream->ops = &stream_ops; } bt_le_scan_cb_register(&bap_scan_cb); @@ -674,7 +677,7 @@ static int enable_stream(struct bt_bap_stream *stream) static void enable_streams(size_t stream_cnt) { for (size_t i = 0U; i < stream_cnt; i++) { - struct bt_bap_stream *stream = &g_streams[i].stream; + struct bt_bap_stream *stream = bap_stream_from_audio_test_stream(&test_streams[i]); int err; err = enable_stream(stream); @@ -713,7 +716,7 @@ static int metadata_update_stream(struct bt_bap_stream *stream) static void metadata_update_streams(size_t stream_cnt) { for (size_t i = 0U; i < stream_cnt; i++) { - struct bt_bap_stream *stream = &g_streams[i].stream; + struct bt_bap_stream *stream = bap_stream_from_audio_test_stream(&test_streams[i]); int err; err = metadata_update_stream(stream); @@ -788,8 +791,8 @@ static void transceive_streams(void) sink_stream = pair_params[0].tx_param == NULL ? NULL : pair_params[0].tx_param->stream; if (sink_stream != NULL) { - struct bap_test_stream *test_stream = - CONTAINER_OF(sink_stream, struct bap_test_stream, stream); + struct audio_test_stream *test_stream = + audio_test_stream_from_bap_stream(sink_stream); test_stream->tx_active = true; for (unsigned int i = 0U; i < ENQUEUE_COUNT; i++) { @@ -803,8 +806,8 @@ static void transceive_streams(void) } if (source_stream != NULL) { - const struct bap_test_stream *test_stream = - CONTAINER_OF(source_stream, struct bap_test_stream, stream); + const struct audio_test_stream *test_stream = + audio_test_stream_from_bap_stream(source_stream); /* Keep receiving until we reach the minimum expected */ while (test_stream->rx_cnt < MIN_SEND_COUNT) { @@ -822,7 +825,8 @@ static void disable_streams(size_t stream_cnt) UNSET_FLAG(flag_stream_disabled); do { - err = bt_bap_stream_disable(&g_streams[i].stream); + err = bt_bap_stream_disable( + bap_stream_from_audio_test_stream(&test_streams[i])); if (err == -EBUSY) { k_sleep(BAP_STREAM_RETRY_WAIT); } else if (err != 0) { @@ -845,7 +849,8 @@ static void release_streams(size_t stream_cnt) UNSET_FLAG(flag_stream_released); do { - err = bt_bap_stream_release(&g_streams[i].stream); + err = bt_bap_stream_release( + bap_stream_from_audio_test_stream(&test_streams[i])); if (err == -EBUSY) { k_sleep(BAP_STREAM_RETRY_WAIT); } else if (err != 0) { @@ -869,12 +874,13 @@ static size_t create_unicast_group(struct bt_bap_unicast_group **unicast_group) memset(stream_params, 0, sizeof(stream_params)); memset(pair_params, 0, sizeof(pair_params)); - for (size_t i = 0U; i < MIN(ARRAY_SIZE(g_sinks), ARRAY_SIZE(g_streams)); i++) { + for (size_t i = 0U; i < MIN(ARRAY_SIZE(g_sinks), ARRAY_SIZE(test_streams)); i++) { if (g_sinks[i] == NULL) { break; } - stream_params[stream_cnt].stream = &g_streams[stream_cnt].stream; + stream_params[stream_cnt].stream = + bap_stream_from_audio_test_stream(&test_streams[stream_cnt]); stream_params[stream_cnt].qos = &preset_16_2_1.qos; pair_params[i].tx_param = &stream_params[stream_cnt]; @@ -883,12 +889,13 @@ static size_t create_unicast_group(struct bt_bap_unicast_group **unicast_group) break; } - for (size_t i = 0U; i < MIN(ARRAY_SIZE(g_sources), ARRAY_SIZE(g_streams)); i++) { + for (size_t i = 0U; i < MIN(ARRAY_SIZE(g_sources), ARRAY_SIZE(test_streams)); i++) { if (g_sources[i] == NULL) { break; } - stream_params[stream_cnt].stream = &g_streams[stream_cnt].stream; + stream_params[stream_cnt].stream = + bap_stream_from_audio_test_stream(&test_streams[stream_cnt]); stream_params[stream_cnt].qos = &preset_16_2_1.qos; pair_params[i].rx_param = &stream_params[stream_cnt]; diff --git a/tests/bsim/bluetooth/audio/src/bap_unicast_server_test.c b/tests/bsim/bluetooth/audio/src/bap_unicast_server_test.c index abe62c4dd52..6dce1dea3fa 100644 --- a/tests/bsim/bluetooth/audio/src/bap_unicast_server_test.c +++ b/tests/bsim/bluetooth/audio/src/bap_unicast_server_test.c @@ -48,7 +48,8 @@ static const struct bt_audio_codec_cap lc3_codec_cap = { }, }; -static struct bap_test_stream streams[CONFIG_BT_ASCS_ASE_SNK_COUNT + CONFIG_BT_ASCS_ASE_SRC_COUNT]; +static struct audio_test_stream + test_streams[CONFIG_BT_ASCS_ASE_SNK_COUNT + CONFIG_BT_ASCS_ASE_SRC_COUNT]; static const struct bt_audio_codec_qos_pref qos_pref = BT_AUDIO_CODEC_QOS_PREF(true, BT_GAP_LE_PHY_2M, 0x02, 10, 40000, 40000, 40000, 40000); @@ -80,8 +81,8 @@ static void print_ase_info(struct bt_bap_ep *ep, void *user_data) static struct bt_bap_stream *stream_alloc(void) { - for (size_t i = 0; i < ARRAY_SIZE(streams); i++) { - struct bt_bap_stream *stream = &streams[i].stream; + for (size_t i = 0; i < ARRAY_SIZE(test_streams); i++) { + struct bt_bap_stream *stream = bap_stream_from_audio_test_stream(&test_streams[i]); if (!stream->conn) { return stream; @@ -101,7 +102,7 @@ static int lc3_config(struct bt_conn *conn, const struct bt_bap_ep *ep, enum bt_ *stream = stream_alloc(); if (*stream == NULL) { - printk("No streams available\n"); + printk("No test_streams available\n"); *rsp = BT_BAP_ASCS_RSP(BT_BAP_ASCS_RSP_CODE_NO_MEM, BT_BAP_ASCS_REASON_NONE); return -ENOMEM; } @@ -133,7 +134,7 @@ static int lc3_reconfig(struct bt_bap_stream *stream, enum bt_audio_dir dir, static int lc3_qos(struct bt_bap_stream *stream, const struct bt_audio_codec_qos *qos, struct bt_bap_ascs_rsp *rsp) { - struct bap_test_stream *test_stream = CONTAINER_OF(stream, struct bap_test_stream, stream); + struct audio_test_stream *test_stream = audio_test_stream_from_bap_stream(stream); printk("QoS: stream %p qos %p\n", stream, qos); @@ -182,7 +183,7 @@ static int lc3_metadata(struct bt_bap_stream *stream, const uint8_t meta[], size static int lc3_disable(struct bt_bap_stream *stream, struct bt_bap_ascs_rsp *rsp) { - struct bap_test_stream *test_stream = CONTAINER_OF(stream, struct bap_test_stream, stream); + struct audio_test_stream *test_stream = audio_test_stream_from_bap_stream(stream); printk("Disable: stream %p\n", stream); @@ -251,7 +252,7 @@ static void stream_started_cb(struct bt_bap_stream *stream) static void stream_recv_cb(struct bt_bap_stream *stream, const struct bt_iso_recv_info *info, struct net_buf *buf) { - struct bap_test_stream *test_stream = CONTAINER_OF(stream, struct bap_test_stream, stream); + struct audio_test_stream *test_stream = audio_test_stream_from_bap_stream(stream); printk("Incoming audio on stream %p len %u and ts %u\n", stream, buf->len, info->ts); @@ -284,7 +285,7 @@ static void stream_recv_cb(struct bt_bap_stream *stream, const struct bt_iso_rec static void stream_sent_cb(struct bt_bap_stream *stream) { - struct bap_test_stream *test_stream = CONTAINER_OF(stream, struct bap_test_stream, stream); + struct audio_test_stream *test_stream = audio_test_stream_from_bap_stream(stream); struct net_buf *buf; int ret; @@ -323,15 +324,15 @@ static struct bt_bap_stream_ops stream_ops = { .sent = stream_sent_cb, }; -static void transceive_streams(void) +static void transceive_test_streams(void) { struct bt_bap_stream *source_stream = NULL; struct bt_bap_stream *sink_stream = NULL; struct bt_bap_ep_info info; int err; - for (size_t i = 0U; i < ARRAY_SIZE(streams); i++) { - struct bt_bap_stream *stream = &streams[i].stream; + for (size_t i = 0U; i < ARRAY_SIZE(test_streams); i++) { + struct bt_bap_stream *stream = bap_stream_from_audio_test_stream(&test_streams[i]); if (stream->ep == NULL) { break; @@ -345,7 +346,7 @@ static void transceive_streams(void) return; } - /* Ensure that all configured streams are in the streaming state before + /* Ensure that all configured test_streams are in the streaming state before * starting TX and RX */ if (info.state == BT_BAP_EP_STATE_STREAMING) { @@ -363,8 +364,8 @@ static void transceive_streams(void) } if (source_stream != NULL) { - struct bap_test_stream *test_stream = - CONTAINER_OF(source_stream, struct bap_test_stream, stream); + struct audio_test_stream *test_stream = + audio_test_stream_from_bap_stream(source_stream); test_stream->tx_active = true; for (unsigned int i = 0U; i < ENQUEUE_COUNT; i++) { @@ -378,8 +379,8 @@ static void transceive_streams(void) } if (sink_stream != NULL) { - const struct bap_test_stream *test_stream = - CONTAINER_OF(sink_stream, struct bap_test_stream, stream); + const struct audio_test_stream *test_stream = + audio_test_stream_from_bap_stream(sink_stream); /* Keep receiving until we reach the minimum expected */ while (test_stream->rx_cnt < MIN_SEND_COUNT) { @@ -481,8 +482,9 @@ static void init(void) set_location(); set_available_contexts(); - for (size_t i = 0; i < ARRAY_SIZE(streams); i++) { - bt_bap_stream_cb_register(&streams[i].stream, &stream_ops); + for (size_t i = 0; i < ARRAY_SIZE(test_streams); i++) { + bt_bap_stream_cb_register(bap_stream_from_audio_test_stream(&test_streams[i]), + &stream_ops); } /* Create a non-connectable non-scannable advertising set */ @@ -518,7 +520,7 @@ static void test_main(void) WAIT_FOR_FLAG(flag_stream_started); - transceive_streams(); + transceive_test_streams(); WAIT_FOR_UNSET_FLAG(flag_connected); PASS("Unicast server passed\n"); } diff --git a/tests/bsim/bluetooth/audio/src/cap_initiator_broadcast_test.c b/tests/bsim/bluetooth/audio/src/cap_initiator_broadcast_test.c index b5c98ba1a9c..37bcfe0e2a3 100644 --- a/tests/bsim/bluetooth/audio/src/cap_initiator_broadcast_test.c +++ b/tests/bsim/bluetooth/audio/src/cap_initiator_broadcast_test.c @@ -26,7 +26,7 @@ NET_BUF_POOL_FIXED_DEFINE(tx_pool, TOTAL_BUF_NEEDED, BT_ISO_SDU_BUF_SIZE(CONFIG_ CONFIG_BT_CONN_TX_USER_DATA_SIZE, NULL); extern enum bst_result_t bst_result; -static struct bt_cap_stream broadcast_source_streams[BROADCAST_STREMT_CNT]; +static struct audio_test_stream broadcast_source_streams[BROADCAST_STREMT_CNT]; static struct bt_cap_stream *broadcast_streams[ARRAY_SIZE(broadcast_source_streams)]; static struct bt_bap_lc3_preset broadcast_preset_16_2_1 = BT_BAP_LC3_BROADCAST_PRESET_16_2_1( BT_AUDIO_LOCATION_FRONT_LEFT, BT_AUDIO_CONTEXT_TYPE_MEDIA); @@ -34,8 +34,6 @@ static struct bt_bap_lc3_preset broadcast_preset_16_2_1 = BT_BAP_LC3_BROADCAST_P static K_SEM_DEFINE(sem_broadcast_started, 0U, ARRAY_SIZE(broadcast_streams)); static K_SEM_DEFINE(sem_broadcast_stopped, 0U, ARRAY_SIZE(broadcast_streams)); -CREATE_FLAG(flag_broadcast_stopping); - static void broadcast_started_cb(struct bt_bap_stream *stream) { printk("Stream %p started\n", stream); @@ -50,30 +48,24 @@ static void broadcast_stopped_cb(struct bt_bap_stream *stream, uint8_t reason) static void broadcast_sent_cb(struct bt_bap_stream *bap_stream) { - struct bt_cap_stream *cap_stream = - CONTAINER_OF(bap_stream, struct bt_cap_stream, bap_stream); - static uint8_t mock_data[CONFIG_BT_ISO_TX_MTU]; - static bool mock_data_initialized; - static uint32_t seq_num; + struct audio_test_stream *test_stream = audio_test_stream_from_bap_stream(bap_stream); + struct bt_cap_stream *cap_stream = cap_stream_from_audio_test_stream(test_stream); struct net_buf *buf; int ret; - if (broadcast_preset_16_2_1.qos.sdu > CONFIG_BT_ISO_TX_MTU) { - FAIL("Invalid SDU %u for the MTU: %d", broadcast_preset_16_2_1.qos.sdu, - CONFIG_BT_ISO_TX_MTU); + if (!test_stream->tx_active) { return; } - if (TEST_FLAG(flag_broadcast_stopping)) { - return; + if ((test_stream->tx_cnt % 100U) == 0U) { + printk("[%zu]: Stream %p sent with seq_num %u\n", test_stream->tx_cnt, cap_stream, + test_stream->seq_num); } - if (!mock_data_initialized) { - for (size_t i = 0U; i < ARRAY_SIZE(mock_data); i++) { - /* Initialize mock data */ - mock_data[i] = (uint8_t)i; - } - mock_data_initialized = true; + if (test_stream->tx_sdu_size > CONFIG_BT_ISO_TX_MTU) { + FAIL("Invalid SDU %u for the MTU: %d", test_stream->tx_sdu_size, + CONFIG_BT_ISO_TX_MTU); + return; } buf = net_buf_alloc(&tx_pool, K_FOREVER); @@ -83,14 +75,21 @@ static void broadcast_sent_cb(struct bt_bap_stream *bap_stream) } net_buf_reserve(buf, BT_ISO_CHAN_SEND_RESERVE); - net_buf_add_mem(buf, mock_data, broadcast_preset_16_2_1.qos.sdu); - ret = bt_cap_stream_send(cap_stream, buf, seq_num++, BT_ISO_TIMESTAMP_NONE); + net_buf_add_mem(buf, mock_iso_data, test_stream->tx_sdu_size); + ret = bt_cap_stream_send(cap_stream, buf, test_stream->seq_num++, BT_ISO_TIMESTAMP_NONE); if (ret < 0) { /* This will end broadcasting on this stream. */ - printk("Unable to broadcast data on %p: %d\n", bap_stream, ret); net_buf_unref(buf); + + /* Only fail if tx is active (may fail if we are disabling the stream) */ + if (test_stream->tx_active) { + FAIL("Unable to broadcast data on %p: %d\n", cap_stream, ret); + } + return; } + + test_stream->tx_cnt++; } static struct bt_bap_stream_ops broadcast_stream_ops = { @@ -112,7 +111,8 @@ static void init(void) (void)memset(broadcast_source_streams, 0, sizeof(broadcast_source_streams)); for (size_t i = 0; i < ARRAY_SIZE(broadcast_streams); i++) { - broadcast_streams[i] = &broadcast_source_streams[i]; + broadcast_streams[i] = + cap_stream_from_audio_test_stream(&broadcast_source_streams[i]); bt_cap_stream_ops_register(broadcast_streams[i], &broadcast_stream_ops); } } @@ -239,7 +239,8 @@ static void test_broadcast_audio_create_inval(void) int err; for (size_t i = 0U; i < ARRAY_SIZE(broadcast_streams); i++) { - stream_params[i].stream = &broadcast_source_streams[i]; + stream_params[i].stream = + cap_stream_from_audio_test_stream(&broadcast_source_streams[i]); stream_params[i].data_len = ARRAY_SIZE(bis_codec_data); stream_params[i].data = bis_codec_data; } @@ -294,7 +295,8 @@ static void test_broadcast_audio_create(struct bt_cap_broadcast_source **broadca int err; for (size_t i = 0; i < ARRAY_SIZE(broadcast_streams); i++) { - stream_params[i].stream = &broadcast_source_streams[i]; + stream_params[i].stream = + cap_stream_from_audio_test_stream(&broadcast_source_streams[i]); stream_params[i].data_len = ARRAY_SIZE(bis_codec_data); stream_params[i].data = bis_codec_data; } @@ -318,6 +320,12 @@ static void test_broadcast_audio_create(struct bt_cap_broadcast_source **broadca return; } + for (size_t i = 0U; i < ARRAY_SIZE(broadcast_source_streams); i++) { + struct audio_test_stream *test_stream = &broadcast_source_streams[i]; + + test_stream->tx_sdu_size = create_param.qos->sdu; + } + printk("Broadcast source created with %zu broadcast_streams\n", ARRAY_SIZE(broadcast_streams)); } @@ -474,6 +482,10 @@ static void test_broadcast_audio_stop(struct bt_cap_broadcast_source *broadcast_ printk("Stopping broadcast metadata\n"); + for (size_t i = 0U; i < ARRAY_SIZE(broadcast_source_streams); i++) { + broadcast_source_streams[i].tx_active = false; + } + err = bt_cap_initiator_broadcast_audio_stop(broadcast_source); if (err != 0) { FAIL("Failed to stop broadcast source: %d\n", err); @@ -563,6 +575,9 @@ static void test_main_cap_initiator_broadcast(void) /* Initialize sending */ for (size_t i = 0U; i < ARRAY_SIZE(broadcast_streams); i++) { for (unsigned int j = 0U; j < BROADCAST_ENQUEUE_COUNT; j++) { + struct audio_test_stream *test_stream = &broadcast_source_streams[i]; + + test_stream->tx_active = true; broadcast_sent_cb(&broadcast_streams[i]->bap_stream); } } diff --git a/tests/bsim/bluetooth/audio/src/common.h b/tests/bsim/bluetooth/audio/src/common.h index 2e87bac169e..cbb3d2af2fa 100644 --- a/tests/bsim/bluetooth/audio/src/common.h +++ b/tests/bsim/bluetooth/audio/src/common.h @@ -23,6 +23,7 @@ #include #include +#include #include #include #include @@ -109,8 +110,8 @@ void backchannel_sync_wait_any(void); void backchannel_sync_clear(uint dev); void backchannel_sync_clear_all(void); -struct bap_test_stream { - struct bt_bap_stream stream; +struct audio_test_stream { + struct bt_cap_stream stream; uint16_t seq_num; bool tx_active; @@ -121,4 +122,31 @@ struct bap_test_stream { size_t rx_cnt; }; +static inline struct audio_test_stream * +audio_test_stream_from_cap_stream(struct bt_cap_stream *cap_stream) +{ + return CONTAINER_OF(cap_stream, struct audio_test_stream, stream); +} + +static inline struct audio_test_stream * +audio_test_stream_from_bap_stream(struct bt_bap_stream *bap_stream) +{ + struct bt_cap_stream *cap_stream = + CONTAINER_OF(bap_stream, struct bt_cap_stream, bap_stream); + + return audio_test_stream_from_cap_stream(cap_stream); +} + +static inline struct bt_cap_stream * +cap_stream_from_audio_test_stream(struct audio_test_stream *test_stream) +{ + return &test_stream->stream; +} + +static inline struct bt_bap_stream * +bap_stream_from_audio_test_stream(struct audio_test_stream *test_stream) +{ + return &cap_stream_from_audio_test_stream(test_stream)->bap_stream; +} + #endif /* ZEPHYR_TEST_BSIM_BT_AUDIO_TEST_ */ From 79af154ae7d54f703aaf3660868f1de88c613840 Mon Sep 17 00:00:00 2001 From: Emil Gydesen Date: Thu, 4 Jan 2024 15:19:10 +0100 Subject: [PATCH 2100/3723] tests: bsim: Bluetooth: CAP broadcast AC testing Add testing of the Audio Configurations from the BAP spec using the CAP API. Signed-off-by: Emil Gydesen --- subsys/bluetooth/audio/shell/cap_initiator.c | 4 +- .../audio/src/bap_broadcast_sink_test.c | 6 +- .../audio/src/bap_unicast_client_test.c | 7 +- .../audio/src/bap_unicast_server_test.c | 7 +- .../bluetooth/audio/src/cap_acceptor_test.c | 68 ++++- .../audio/src/cap_initiator_broadcast_test.c | 274 ++++++++++++++++-- .../audio/src/cap_initiator_unicast_test.c | 2 +- tests/bsim/bluetooth/audio/src/common.h | 17 ++ .../bsim/bluetooth/audio/test_scripts/_cap.sh | 3 + .../audio/test_scripts/cap_broadcast_ac_12.sh | 69 +++++ .../audio/test_scripts/cap_broadcast_ac_13.sh | 68 +++++ .../audio/test_scripts/cap_broadcast_ac_14.sh | 69 +++++ 12 files changed, 558 insertions(+), 36 deletions(-) create mode 100755 tests/bsim/bluetooth/audio/test_scripts/cap_broadcast_ac_12.sh create mode 100755 tests/bsim/bluetooth/audio/test_scripts/cap_broadcast_ac_13.sh create mode 100755 tests/bsim/bluetooth/audio/test_scripts/cap_broadcast_ac_14.sh diff --git a/subsys/bluetooth/audio/shell/cap_initiator.c b/subsys/bluetooth/audio/shell/cap_initiator.c index 0d002b30df3..070fd614036 100644 --- a/subsys/bluetooth/audio/shell/cap_initiator.c +++ b/subsys/bluetooth/audio/shell/cap_initiator.c @@ -1134,9 +1134,9 @@ static int cmd_cap_ac_13(const struct shell *sh, size_t argc, char **argv) static int cmd_cap_ac_14(const struct shell *sh, size_t argc, char **argv) { const struct bap_broadcast_ac_param param = { - .name = "AC_13", + .name = "AC_14", .stream_cnt = 2U, - .chan_cnt = 1U, + .chan_cnt = 2U, }; return cap_ac_broadcast(sh, argc, argv, ¶m); diff --git a/tests/bsim/bluetooth/audio/src/bap_broadcast_sink_test.c b/tests/bsim/bluetooth/audio/src/bap_broadcast_sink_test.c index df9203a2b98..a0ca2539866 100644 --- a/tests/bsim/bluetooth/audio/src/bap_broadcast_sink_test.c +++ b/tests/bsim/bluetooth/audio/src/bap_broadcast_sink_test.c @@ -277,8 +277,8 @@ static void recv_cb(struct bt_bap_stream *stream, struct audio_test_stream *test_stream = audio_test_stream_from_bap_stream(stream); if ((test_stream->rx_cnt % 100U) == 0U) { - printk("Incoming audio on stream %p len %u and ts %u\n", stream, buf->len, - info->ts); + printk("[%zu]: Incoming audio on stream %p len %u and ts %u\n", test_stream->rx_cnt, + stream, buf->len, info->ts); } if (test_stream->rx_cnt > 0U && info->ts == test_stream->last_info.ts) { @@ -313,7 +313,7 @@ static void recv_cb(struct bt_bap_stream *stream, SET_FLAG(flag_received); } } else { - FAIL("Unexpected data received"); + FAIL("Unexpected data received\n"); } } diff --git a/tests/bsim/bluetooth/audio/src/bap_unicast_client_test.c b/tests/bsim/bluetooth/audio/src/bap_unicast_client_test.c index 81ca44af0e1..0fe3156afe8 100644 --- a/tests/bsim/bluetooth/audio/src/bap_unicast_client_test.c +++ b/tests/bsim/bluetooth/audio/src/bap_unicast_client_test.c @@ -121,7 +121,10 @@ static void stream_recv_cb(struct bt_bap_stream *stream, const struct bt_iso_rec { struct audio_test_stream *test_stream = audio_test_stream_from_bap_stream(stream); - printk("Incoming audio on stream %p len %u and ts %u\n", stream, buf->len, info->ts); + if ((test_stream->rx_cnt % 100U) == 0U) { + printk("[%zu]: Incoming audio on stream %p len %u and ts %u\n", test_stream->rx_cnt, + stream, buf->len, info->ts); + } if (test_stream->rx_cnt > 0U && info->ts == test_stream->last_info.ts) { FAIL("Duplicated timestamp received: %u\n", test_stream->last_info.ts); @@ -146,7 +149,7 @@ static void stream_recv_cb(struct bt_bap_stream *stream, const struct bt_iso_rec if (memcmp(buf->data, mock_iso_data, buf->len) == 0) { test_stream->rx_cnt++; } else { - FAIL("Unexpected data received"); + FAIL("Unexpected data received\n"); } } diff --git a/tests/bsim/bluetooth/audio/src/bap_unicast_server_test.c b/tests/bsim/bluetooth/audio/src/bap_unicast_server_test.c index 6dce1dea3fa..6d6f899d0e3 100644 --- a/tests/bsim/bluetooth/audio/src/bap_unicast_server_test.c +++ b/tests/bsim/bluetooth/audio/src/bap_unicast_server_test.c @@ -254,7 +254,10 @@ static void stream_recv_cb(struct bt_bap_stream *stream, const struct bt_iso_rec { struct audio_test_stream *test_stream = audio_test_stream_from_bap_stream(stream); - printk("Incoming audio on stream %p len %u and ts %u\n", stream, buf->len, info->ts); + if ((test_stream->rx_cnt % 100U) == 0U) { + printk("[%zu]: Incoming audio on stream %p len %u and ts %u\n", test_stream->rx_cnt, + stream, buf->len, info->ts); + } if (test_stream->rx_cnt > 0U && info->ts == test_stream->last_info.ts) { FAIL("Duplicated timestamp received: %u\n", test_stream->last_info.ts); @@ -279,7 +282,7 @@ static void stream_recv_cb(struct bt_bap_stream *stream, const struct bt_iso_rec if (memcmp(buf->data, mock_iso_data, buf->len) == 0) { test_stream->rx_cnt++; } else { - FAIL("Unexpected data received"); + FAIL("Unexpected data received\n"); } } diff --git a/tests/bsim/bluetooth/audio/src/cap_acceptor_test.c b/tests/bsim/bluetooth/audio/src/cap_acceptor_test.c index 56bb02cb6d2..ccb9eaed8c4 100644 --- a/tests/bsim/bluetooth/audio/src/cap_acceptor_test.c +++ b/tests/bsim/bluetooth/audio/src/cap_acceptor_test.c @@ -33,7 +33,7 @@ static struct bt_le_scan_recv_info broadcaster_info; static bt_addr_le_t broadcaster_addr; static struct bt_le_per_adv_sync *pa_sync; static uint32_t broadcaster_broadcast_id; -static struct bt_cap_stream broadcast_sink_streams[CONFIG_BT_BAP_BROADCAST_SNK_STREAM_COUNT]; +static struct audio_test_stream broadcast_sink_streams[CONFIG_BT_BAP_BROADCAST_SNK_STREAM_COUNT]; static const struct bt_audio_codec_cap codec_cap = BT_AUDIO_CODEC_CAP_LC3( BT_AUDIO_CODEC_LC3_FREQ_ANY, BT_AUDIO_CODEC_LC3_DURATION_ANY, @@ -260,7 +260,47 @@ static void stopped_cb(struct bt_bap_stream *stream, uint8_t reason) static void recv_cb(struct bt_bap_stream *stream, const struct bt_iso_recv_info *info, struct net_buf *buf) { - SET_FLAG(flag_received); + struct audio_test_stream *test_stream = audio_test_stream_from_bap_stream(stream); + + if ((test_stream->rx_cnt % 100U) == 0U) { + printk("[%zu]: Incoming audio on stream %p len %u and ts %u\n", test_stream->rx_cnt, + stream, buf->len, info->ts); + } + + if (test_stream->rx_cnt > 0U && info->ts == test_stream->last_info.ts) { + FAIL("Duplicated timestamp received: %u\n", test_stream->last_info.ts); + return; + } + + if (test_stream->rx_cnt > 0U && info->seq_num == test_stream->last_info.seq_num) { + FAIL("Duplicated PSN received: %u\n", test_stream->last_info.seq_num); + return; + } + + if (info->flags & BT_ISO_FLAGS_ERROR) { + /* Fail the test if we have not received what we expected */ + if (!TEST_FLAG(flag_received)) { + FAIL("ISO receive error\n"); + } + + return; + } + + if (info->flags & BT_ISO_FLAGS_LOST) { + FAIL("ISO receive lost\n"); + return; + } + + if (memcmp(buf->data, mock_iso_data, buf->len) == 0) { + test_stream->rx_cnt++; + + if (test_stream->rx_cnt >= MIN_SEND_COUNT) { + /* We set the flag is just one stream has received the expected */ + SET_FLAG(flag_received); + } + } else { + FAIL("Unexpected data received\n"); + } } static struct bt_bap_stream_ops broadcast_stream_ops = { @@ -604,8 +644,9 @@ static void init(void) UNSET_FLAG(flag_pa_synced); for (size_t i = 0U; i < ARRAY_SIZE(broadcast_sink_streams); i++) { - bt_cap_stream_ops_register(&broadcast_sink_streams[i], - &broadcast_stream_ops); + bt_cap_stream_ops_register( + cap_stream_from_audio_test_stream(&broadcast_sink_streams[i]), + &broadcast_stream_ops); } } @@ -678,6 +719,7 @@ static int pa_sync_create(void) static void test_cap_acceptor_broadcast(void) { static struct bt_bap_stream *bap_streams[ARRAY_SIZE(broadcast_sink_streams)]; + size_t stream_count; int err; init(); @@ -724,10 +766,17 @@ static void test_cap_acceptor_broadcast(void) WAIT_FOR_FLAG(flag_syncable); for (size_t i = 0U; i < ARRAY_SIZE(broadcast_sink_streams); i++) { - bap_streams[i] = &broadcast_sink_streams[i].bap_stream; + bap_streams[i] = bap_stream_from_audio_test_stream(&broadcast_sink_streams[i]); } printk("Syncing the sink\n"); + stream_count = 0; + for (int i = 1; i < BT_ISO_MAX_GROUP_ISO_COUNT; i++) { + if ((bis_index_bitfield & BIT(i)) != 0) { + stream_count++; + } + } + err = bt_bap_broadcast_sink_sync(g_broadcast_sink, bis_index_bitfield, bap_streams, NULL); if (err != 0) { FAIL("Unable to sync the sink: %d\n", err); @@ -735,13 +784,14 @@ static void test_cap_acceptor_broadcast(void) } /* Wait for all to be started */ - printk("Waiting for broadcast_sink_streams to be started\n"); - for (size_t i = 0U; i < ARRAY_SIZE(broadcast_sink_streams); i++) { + printk("Waiting for %zu streams to be started\n", stream_count); + for (size_t i = 0U; i < stream_count; i++) { k_sem_take(&sem_broadcast_started, K_FOREVER); } printk("Waiting for data\n"); WAIT_FOR_FLAG(flag_received); + backchannel_sync_send_all(); /* let other devices know we have received what we wanted */ /* The order of PA sync lost and BIG Sync lost is irrelevant * and depend on timeout parameters. We just wait for PA first, but @@ -750,8 +800,8 @@ static void test_cap_acceptor_broadcast(void) printk("Waiting for PA disconnected\n"); WAIT_FOR_FLAG(flag_pa_sync_lost); - printk("Waiting for streams to be stopped\n"); - for (size_t i = 0U; i < ARRAY_SIZE(broadcast_sink_streams); i++) { + printk("Waiting for %zu streams to be stopped\n", stream_count); + for (size_t i = 0U; i < stream_count; i++) { k_sem_take(&sem_broadcast_stopped, K_FOREVER); } diff --git a/tests/bsim/bluetooth/audio/src/cap_initiator_broadcast_test.c b/tests/bsim/bluetooth/audio/src/cap_initiator_broadcast_test.c index 37bcfe0e2a3..001b0d0ddd9 100644 --- a/tests/bsim/bluetooth/audio/src/cap_initiator_broadcast_test.c +++ b/tests/bsim/bluetooth/audio/src/cap_initiator_broadcast_test.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2022-2023 Nordic Semiconductor ASA + * Copyright (c) 2022-2024 Nordic Semiconductor ASA * * SPDX-License-Identifier: Apache-2.0 */ @@ -12,11 +12,15 @@ #include #include #include +#include "bap_common.h" #include "common.h" #define BROADCAST_STREMT_CNT CONFIG_BT_BAP_BROADCAST_SRC_STREAM_COUNT #define BROADCAST_ENQUEUE_COUNT 2U #define TOTAL_BUF_NEEDED (BROADCAST_ENQUEUE_COUNT * BROADCAST_STREMT_CNT) +#define CAP_AC_MAX_STREAM 2 +#define LOCATION (BT_AUDIO_LOCATION_FRONT_LEFT | BT_AUDIO_LOCATION_FRONT_RIGHT) +#define CONTEXT (BT_AUDIO_CONTEXT_TYPE_MEDIA) BUILD_ASSERT(CONFIG_BT_ISO_TX_BUF_COUNT >= TOTAL_BUF_NEEDED, "CONFIG_BT_ISO_TX_BUF_COUNT should be at least " @@ -25,15 +29,60 @@ BUILD_ASSERT(CONFIG_BT_ISO_TX_BUF_COUNT >= TOTAL_BUF_NEEDED, NET_BUF_POOL_FIXED_DEFINE(tx_pool, TOTAL_BUF_NEEDED, BT_ISO_SDU_BUF_SIZE(CONFIG_BT_ISO_TX_MTU), CONFIG_BT_CONN_TX_USER_DATA_SIZE, NULL); +struct cap_initiator_ac_param { + char *name; + size_t stream_cnt; + size_t chan_cnt; + const struct named_lc3_preset *named_preset; +}; +static const struct named_lc3_preset *named_preset; + extern enum bst_result_t bst_result; static struct audio_test_stream broadcast_source_streams[BROADCAST_STREMT_CNT]; static struct bt_cap_stream *broadcast_streams[ARRAY_SIZE(broadcast_source_streams)]; -static struct bt_bap_lc3_preset broadcast_preset_16_2_1 = BT_BAP_LC3_BROADCAST_PRESET_16_2_1( - BT_AUDIO_LOCATION_FRONT_LEFT, BT_AUDIO_CONTEXT_TYPE_MEDIA); +static struct bt_bap_lc3_preset broadcast_preset_16_2_1 = + BT_BAP_LC3_BROADCAST_PRESET_16_2_1(LOCATION, CONTEXT); +static size_t stream_count; static K_SEM_DEFINE(sem_broadcast_started, 0U, ARRAY_SIZE(broadcast_streams)); static K_SEM_DEFINE(sem_broadcast_stopped, 0U, ARRAY_SIZE(broadcast_streams)); +static const struct named_lc3_preset lc3_broadcast_presets[] = { + {"8_1_1", BT_BAP_LC3_BROADCAST_PRESET_8_1_1(LOCATION, CONTEXT)}, + {"8_2_1", BT_BAP_LC3_BROADCAST_PRESET_8_2_1(LOCATION, CONTEXT)}, + {"16_1_1", BT_BAP_LC3_BROADCAST_PRESET_16_1_1(LOCATION, CONTEXT)}, + {"16_2_1", BT_BAP_LC3_BROADCAST_PRESET_16_2_1(LOCATION, CONTEXT)}, + {"24_1_1", BT_BAP_LC3_BROADCAST_PRESET_24_1_1(LOCATION, CONTEXT)}, + {"24_2_1", BT_BAP_LC3_BROADCAST_PRESET_24_2_1(LOCATION, CONTEXT)}, + {"32_1_1", BT_BAP_LC3_BROADCAST_PRESET_32_1_1(LOCATION, CONTEXT)}, + {"32_2_1", BT_BAP_LC3_BROADCAST_PRESET_32_2_1(LOCATION, CONTEXT)}, + {"441_1_1", BT_BAP_LC3_BROADCAST_PRESET_441_1_1(LOCATION, CONTEXT)}, + {"441_2_1", BT_BAP_LC3_BROADCAST_PRESET_441_2_1(LOCATION, CONTEXT)}, + {"48_1_1", BT_BAP_LC3_BROADCAST_PRESET_48_1_1(LOCATION, CONTEXT)}, + {"48_2_1", BT_BAP_LC3_BROADCAST_PRESET_48_2_1(LOCATION, CONTEXT)}, + {"48_3_1", BT_BAP_LC3_BROADCAST_PRESET_48_3_1(LOCATION, CONTEXT)}, + {"48_4_1", BT_BAP_LC3_BROADCAST_PRESET_48_4_1(LOCATION, CONTEXT)}, + {"48_5_1", BT_BAP_LC3_BROADCAST_PRESET_48_5_1(LOCATION, CONTEXT)}, + {"48_6_1", BT_BAP_LC3_BROADCAST_PRESET_48_6_1(LOCATION, CONTEXT)}, + /* High-reliability presets */ + {"8_1_2", BT_BAP_LC3_BROADCAST_PRESET_8_1_2(LOCATION, CONTEXT)}, + {"8_2_2", BT_BAP_LC3_BROADCAST_PRESET_8_2_2(LOCATION, CONTEXT)}, + {"16_1_2", BT_BAP_LC3_BROADCAST_PRESET_16_1_2(LOCATION, CONTEXT)}, + {"16_2_2", BT_BAP_LC3_BROADCAST_PRESET_16_2_2(LOCATION, CONTEXT)}, + {"24_1_2", BT_BAP_LC3_BROADCAST_PRESET_24_1_2(LOCATION, CONTEXT)}, + {"24_2_2", BT_BAP_LC3_BROADCAST_PRESET_24_2_2(LOCATION, CONTEXT)}, + {"32_1_2", BT_BAP_LC3_BROADCAST_PRESET_32_1_2(LOCATION, CONTEXT)}, + {"32_2_2", BT_BAP_LC3_BROADCAST_PRESET_32_2_2(LOCATION, CONTEXT)}, + {"441_1_2", BT_BAP_LC3_BROADCAST_PRESET_441_1_2(LOCATION, CONTEXT)}, + {"441_2_2", BT_BAP_LC3_BROADCAST_PRESET_441_2_2(LOCATION, CONTEXT)}, + {"48_1_2", BT_BAP_LC3_BROADCAST_PRESET_48_1_2(LOCATION, CONTEXT)}, + {"48_2_2", BT_BAP_LC3_BROADCAST_PRESET_48_2_2(LOCATION, CONTEXT)}, + {"48_3_2", BT_BAP_LC3_BROADCAST_PRESET_48_3_2(LOCATION, CONTEXT)}, + {"48_4_2", BT_BAP_LC3_BROADCAST_PRESET_48_4_2(LOCATION, CONTEXT)}, + {"48_5_2", BT_BAP_LC3_BROADCAST_PRESET_48_5_2(LOCATION, CONTEXT)}, + {"48_6_2", BT_BAP_LC3_BROADCAST_PRESET_48_6_2(LOCATION, CONTEXT)}, +}; + static void broadcast_started_cb(struct bt_bap_stream *stream) { printk("Stream %p started\n", stream); @@ -328,6 +377,8 @@ static void test_broadcast_audio_create(struct bt_cap_broadcast_source **broadca printk("Broadcast source created with %zu broadcast_streams\n", ARRAY_SIZE(broadcast_streams)); + + stream_count = ARRAY_SIZE(broadcast_streams); } static void test_broadcast_audio_start_inval(struct bt_cap_broadcast_source *broadcast_source, @@ -456,7 +507,7 @@ static void test_broadcast_audio_stop_inval(void) static void test_broadcast_audio_tx_sync(void) { - for (size_t i = 0U; i < ARRAY_SIZE(broadcast_streams); i++) { + for (size_t i = 0U; i < stream_count; i++) { struct bt_cap_stream *cap_stream = broadcast_streams[i]; struct bt_iso_tx_info info; int err; @@ -480,7 +531,7 @@ static void test_broadcast_audio_stop(struct bt_cap_broadcast_source *broadcast_ { int err; - printk("Stopping broadcast metadata\n"); + printk("Stopping broadcast source\n"); for (size_t i = 0U; i < ARRAY_SIZE(broadcast_source_streams); i++) { broadcast_source_streams[i].tx_active = false; @@ -494,11 +545,11 @@ static void test_broadcast_audio_stop(struct bt_cap_broadcast_source *broadcast_ /* Wait for all to be stopped */ printk("Waiting for broadcast_streams to be stopped\n"); - for (size_t i = 0U; i < ARRAY_SIZE(broadcast_streams); i++) { + for (size_t i = 0U; i < stream_count; i++) { k_sem_take(&sem_broadcast_stopped, K_FOREVER); } - printk("Broadcast metadata stopped\n"); + printk("Broadcast source stopped\n"); /* Verify that it cannot be stopped twice */ err = bt_cap_initiator_broadcast_audio_stop(broadcast_source); @@ -526,7 +577,7 @@ static void test_broadcast_audio_delete(struct bt_cap_broadcast_source *broadcas { int err; - printk("Stopping broadcast metadata\n"); + printk("Deleting broadcast source\n"); err = bt_cap_initiator_broadcast_audio_delete(broadcast_source); if (err != 0) { @@ -534,7 +585,7 @@ static void test_broadcast_audio_delete(struct bt_cap_broadcast_source *broadcas return; } - printk("Broadcast metadata stopped\n"); + printk("Broadcast source deleted\n"); /* Verify that it cannot be deleted twice */ err = bt_cap_initiator_broadcast_audio_delete(broadcast_source); @@ -568,22 +619,23 @@ static void test_main_cap_initiator_broadcast(void) /* Wait for all to be started */ printk("Waiting for broadcast_streams to be started\n"); - for (size_t i = 0U; i < ARRAY_SIZE(broadcast_streams); i++) { + for (size_t i = 0U; i < stream_count; i++) { k_sem_take(&sem_broadcast_started, K_FOREVER); } /* Initialize sending */ - for (size_t i = 0U; i < ARRAY_SIZE(broadcast_streams); i++) { - for (unsigned int j = 0U; j < BROADCAST_ENQUEUE_COUNT; j++) { - struct audio_test_stream *test_stream = &broadcast_source_streams[i]; + for (size_t i = 0U; i < stream_count; i++) { + struct audio_test_stream *test_stream = &broadcast_source_streams[i]; + + test_stream->tx_active = true; - test_stream->tx_active = true; - broadcast_sent_cb(&broadcast_streams[i]->bap_stream); + for (unsigned int j = 0U; j < BROADCAST_ENQUEUE_COUNT; j++) { + broadcast_sent_cb(bap_stream_from_audio_test_stream(test_stream)); } } - /* Keeping running for a little while */ - k_sleep(K_SECONDS(5)); + /* Wait for other devices to have received what they wanted */ + backchannel_sync_wait_any(); test_broadcast_audio_update_inval(broadcast_source); test_broadcast_audio_update(broadcast_source); @@ -606,6 +658,171 @@ static void test_main_cap_initiator_broadcast(void) PASS("CAP initiator broadcast passed\n"); } +static int test_cap_initiator_ac(const struct cap_initiator_ac_param *param) +{ + struct bt_cap_initiator_broadcast_stream_param stream_params[CAP_AC_MAX_STREAM] = {0}; + uint8_t stereo_data[] = { + BT_AUDIO_CODEC_DATA(BT_AUDIO_CODEC_CONFIG_LC3_CHAN_ALLOC, + BT_AUDIO_LOCATION_FRONT_RIGHT | BT_AUDIO_LOCATION_FRONT_LEFT)}; + uint8_t right_data[] = {BT_AUDIO_CODEC_DATA(BT_AUDIO_CODEC_CONFIG_LC3_CHAN_ALLOC, + BT_AUDIO_LOCATION_FRONT_RIGHT)}; + uint8_t left_data[] = {BT_AUDIO_CODEC_DATA(BT_AUDIO_CODEC_CONFIG_LC3_CHAN_ALLOC, + BT_AUDIO_LOCATION_FRONT_LEFT)}; + struct bt_cap_initiator_broadcast_subgroup_param subgroup_param = {0}; + struct bt_cap_initiator_broadcast_create_param create_param = {0}; + struct bt_cap_broadcast_source *broadcast_source; + struct bt_audio_codec_cfg codec_cfg; + struct bt_audio_codec_qos qos; + struct bt_le_ext_adv *adv; + int err; + + for (size_t i = 0U; i < param->stream_cnt; i++) { + stream_params[i].stream = + cap_stream_from_audio_test_stream(&broadcast_source_streams[i]); + + if (param->stream_cnt == 1U) { + stream_params[i].data_len = ARRAY_SIZE(stereo_data); + stream_params[i].data = stereo_data; + } else if (i == 0U) { + stream_params[i].data_len = ARRAY_SIZE(left_data); + stream_params[i].data = left_data; + } else if (i == 1U) { + stream_params[i].data_len = ARRAY_SIZE(right_data); + stream_params[i].data = right_data; + } + } + + memcpy(&codec_cfg, &named_preset->preset.codec_cfg, sizeof(codec_cfg)); + memcpy(&qos, &named_preset->preset.qos, sizeof(qos)); + qos.sdu *= param->chan_cnt; + + subgroup_param.stream_count = param->stream_cnt; + subgroup_param.stream_params = stream_params; + subgroup_param.codec_cfg = &codec_cfg; + create_param.subgroup_count = 1U; + create_param.subgroup_params = &subgroup_param; + create_param.qos = &qos; + + init(); + setup_extended_adv(&adv); + + err = bt_cap_initiator_broadcast_audio_create(&create_param, &broadcast_source); + if (err != 0) { + FAIL("Failed to create broadcast source: %d\n", err); + return -ENOEXEC; + } + + stream_count = param->stream_cnt; + for (size_t i = 0U; i < stream_count; i++) { + struct audio_test_stream *test_stream = &broadcast_source_streams[i]; + + test_stream->tx_sdu_size = create_param.qos->sdu; + } + + test_broadcast_audio_start(broadcast_source, adv); + setup_extended_adv_data(broadcast_source, adv); + start_extended_adv(adv); + + /* Wait for all to be started */ + printk("Waiting for broadcast_streams to be started\n"); + for (size_t i = 0U; i < stream_count; i++) { + k_sem_take(&sem_broadcast_started, K_FOREVER); + } + + /* Initialize sending */ + for (size_t i = 0U; i < stream_count; i++) { + struct audio_test_stream *test_stream = &broadcast_source_streams[i]; + + test_stream->tx_active = true; + + for (unsigned int j = 0U; j < BROADCAST_ENQUEUE_COUNT; j++) { + broadcast_sent_cb(bap_stream_from_audio_test_stream(test_stream)); + } + } + + /* Wait for other devices to have received what they wanted */ + backchannel_sync_wait_any(); + + test_broadcast_audio_stop(broadcast_source); + + test_broadcast_audio_delete(broadcast_source); + broadcast_source = NULL; + + stop_and_delete_extended_adv(adv); + adv = NULL; + + PASS("CAP initiator broadcast passed\n"); + + return 0; +} + +static void test_cap_initiator_ac_12(void) +{ + const struct cap_initiator_ac_param param = { + .name = "ac_12", + .stream_cnt = 1U, + .chan_cnt = 1U, + .named_preset = named_preset, + }; + + test_cap_initiator_ac(¶m); +} + +#if BROADCAST_STREMT_CNT >= CAP_AC_MAX_STREAM +static void test_cap_initiator_ac_13(void) +{ + const struct cap_initiator_ac_param param = { + .name = "ac_13", + .stream_cnt = 2U, + .chan_cnt = 1U, + .named_preset = named_preset, + }; + + test_cap_initiator_ac(¶m); +} +#endif /* BROADCAST_STREMT_CNT >= CAP_AC_MAX_STREAM */ + +static void test_cap_initiator_ac_14(void) +{ + const struct cap_initiator_ac_param param = { + .name = "ac_14", + .stream_cnt = 1U, + .chan_cnt = 2U, + .named_preset = named_preset, + }; + + test_cap_initiator_ac(¶m); +} + +static const struct named_lc3_preset *cap_get_named_preset(const char *preset_arg) +{ + for (size_t i = 0U; i < ARRAY_SIZE(lc3_broadcast_presets); i++) { + if (strcmp(preset_arg, lc3_broadcast_presets[i].name) == 0) { + return &lc3_broadcast_presets[i]; + } + } + + return NULL; +} + +static void test_args(int argc, char *argv[]) +{ + for (size_t argn = 0; argn < argc; argn++) { + const char *arg = argv[argn]; + + if (strcmp(arg, "preset") == 0) { + const char *preset_arg = argv[++argn]; + + named_preset = cap_get_named_preset(preset_arg); + if (named_preset == NULL) { + FAIL("Failed to get preset from %s\n", preset_arg); + } + } else { + FAIL("Invalid arg: %s\n", arg); + } + } +} + static const struct bst_test_instance test_cap_initiator_broadcast[] = { { .test_id = "cap_initiator_broadcast", @@ -613,6 +830,29 @@ static const struct bst_test_instance test_cap_initiator_broadcast[] = { .test_tick_f = test_tick, .test_main_f = test_main_cap_initiator_broadcast, }, + { + .test_id = "cap_initiator_ac_12", + .test_post_init_f = test_init, + .test_tick_f = test_tick, + .test_main_f = test_cap_initiator_ac_12, + .test_args_f = test_args, + }, +#if BROADCAST_STREMT_CNT >= CAP_AC_MAX_STREAM + { + .test_id = "cap_initiator_ac_13", + .test_post_init_f = test_init, + .test_tick_f = test_tick, + .test_main_f = test_cap_initiator_ac_13, + .test_args_f = test_args, + }, +#endif /* BROADCAST_STREMT_CNT >= CAP_AC_MAX_STREAM */ + { + .test_id = "cap_initiator_ac_14", + .test_post_init_f = test_init, + .test_tick_f = test_tick, + .test_main_f = test_cap_initiator_ac_14, + .test_args_f = test_args, + }, BSTEST_END_MARKER, }; diff --git a/tests/bsim/bluetooth/audio/src/cap_initiator_unicast_test.c b/tests/bsim/bluetooth/audio/src/cap_initiator_unicast_test.c index b555af8b99b..37c175d8d55 100644 --- a/tests/bsim/bluetooth/audio/src/cap_initiator_unicast_test.c +++ b/tests/bsim/bluetooth/audio/src/cap_initiator_unicast_test.c @@ -918,7 +918,7 @@ static void test_cap_initiator_unicast_timeout(void) PASS("CAP initiator unicast timeout passed\n"); } -const struct named_lc3_preset *cap_get_named_preset(const char *preset_arg) +static const struct named_lc3_preset *cap_get_named_preset(const char *preset_arg) { for (size_t i = 0U; i < ARRAY_SIZE(lc3_unicast_presets); i++) { if (strcmp(preset_arg, lc3_unicast_presets[i].name) == 0) { diff --git a/tests/bsim/bluetooth/audio/src/common.h b/tests/bsim/bluetooth/audio/src/common.h index cbb3d2af2fa..d39cfcd656b 100644 --- a/tests/bsim/bluetooth/audio/src/common.h +++ b/tests/bsim/bluetooth/audio/src/common.h @@ -48,6 +48,23 @@ static const uint8_t mock_iso_data[] = { 0xd3, 0xd4, 0xd5, 0xd6, 0xd7, 0xd8, 0xd9, 0xda, 0xdb, 0xdc, 0xdd, 0xde, 0xdf, 0xe0, 0xe1, 0xe2, 0xe3, 0xe4, 0xe5, 0xe6, 0xe7, 0xe8, 0xe9, 0xea, 0xeb, 0xec, 0xed, 0xee, 0xef, 0xf0, 0xf1, 0xf2, 0xf3, 0xf4, 0xf5, 0xf6, 0xf7, 0xf8, 0xf9, 0xfa, 0xfb, 0xfc, 0xfd, 0xfe, 0xff, + 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, + 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, + 0x1f, 0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27, 0x28, 0x29, 0x2a, 0x2b, 0x2c, 0x2d, + 0x2e, 0x2f, 0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, 0x38, 0x39, 0x3a, 0x3b, 0x3c, + 0x3d, 0x3e, 0x3f, 0x40, 0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47, 0x48, 0x49, 0x4a, 0x4b, + 0x4c, 0x4d, 0x4e, 0x4f, 0x50, 0x51, 0x52, 0x53, 0x54, 0x55, 0x56, 0x57, 0x58, 0x59, 0x5a, + 0x5b, 0x5c, 0x5d, 0x5e, 0x5f, 0x60, 0x61, 0x62, 0x63, 0x64, 0x65, 0x66, 0x67, 0x68, 0x69, + 0x6a, 0x6b, 0x6c, 0x6d, 0x6e, 0x6f, 0x70, 0x71, 0x72, 0x73, 0x74, 0x75, 0x76, 0x77, 0x78, + 0x79, 0x7a, 0x7b, 0x7c, 0x7d, 0x7e, 0x7f, 0x80, 0x81, 0x82, 0x83, 0x84, 0x85, 0x86, 0x87, + 0x88, 0x89, 0x8a, 0x8b, 0x8c, 0x8d, 0x8e, 0x8f, 0x90, 0x91, 0x92, 0x93, 0x94, 0x95, 0x96, + 0x97, 0x98, 0x99, 0x9a, 0x9b, 0x9c, 0x9d, 0x9e, 0x9f, 0xa0, 0xa1, 0xa2, 0xa3, 0xa4, 0xa5, + 0xa6, 0xa7, 0xa8, 0xa9, 0xaa, 0xab, 0xac, 0xad, 0xae, 0xaf, 0xb0, 0xb1, 0xb2, 0xb3, 0xb4, + 0xb5, 0xb6, 0xb7, 0xb8, 0xb9, 0xba, 0xbb, 0xbc, 0xbd, 0xbe, 0xbf, 0xc0, 0xc1, 0xc2, 0xc3, + 0xc4, 0xc5, 0xc6, 0xc7, 0xc8, 0xc9, 0xca, 0xcb, 0xcc, 0xcd, 0xce, 0xcf, 0xd0, 0xd1, 0xd2, + 0xd3, 0xd4, 0xd5, 0xd6, 0xd7, 0xd8, 0xd9, 0xda, 0xdb, 0xdc, 0xdd, 0xde, 0xdf, 0xe0, 0xe1, + 0xe2, 0xe3, 0xe4, 0xe5, 0xe6, 0xe7, 0xe8, 0xe9, 0xea, 0xeb, 0xec, 0xed, 0xee, 0xef, 0xf0, + 0xf1, 0xf2, 0xf3, 0xf4, 0xf5, 0xf6, 0xf7, 0xf8, 0xf9, 0xfa, 0xfb, 0xfc, 0xfd, 0xfe, 0xff, }; #define MIN_SEND_COUNT 100 diff --git a/tests/bsim/bluetooth/audio/test_scripts/_cap.sh b/tests/bsim/bluetooth/audio/test_scripts/_cap.sh index 2afa116b889..c4e3ddec197 100755 --- a/tests/bsim/bluetooth/audio/test_scripts/_cap.sh +++ b/tests/bsim/bluetooth/audio/test_scripts/_cap.sh @@ -13,6 +13,9 @@ $dir_path/cap_unicast_inval.sh $dir_path/cap_unicast.sh $dir_path/cap_broadcast.sh +$dir_path/cap_broadcast_ac_12.sh +$dir_path/cap_broadcast_ac_13.sh +$dir_path/cap_broadcast_ac_14.sh $dir_path/cap_unicast_ac_1.sh $dir_path/cap_unicast_ac_2.sh diff --git a/tests/bsim/bluetooth/audio/test_scripts/cap_broadcast_ac_12.sh b/tests/bsim/bluetooth/audio/test_scripts/cap_broadcast_ac_12.sh new file mode 100755 index 00000000000..ecfd5391da4 --- /dev/null +++ b/tests/bsim/bluetooth/audio/test_scripts/cap_broadcast_ac_12.sh @@ -0,0 +1,69 @@ +#!/usr/bin/env bash +# +# Copyright (c) 2024 Nordic Semiconductor ASA +# +# SPDX-License-Identifier: Apache-2.0 + +SIMULATION_ID="cap_unicast_ac_12" +VERBOSITY_LEVEL=2 +EXECUTE_TIMEOUT=60 + +source ${ZEPHYR_BASE}/tests/bsim/sh_common.source + +cd ${BSIM_OUT_PATH}/bin + +function Execute_AC_12() { + printf "\n\n======== Running CAP AC_12 with %s =========\n\n" $1 + + Execute ./bs_${BOARD}_tests_bsim_bluetooth_audio_prj_conf \ + -v=${VERBOSITY_LEVEL} -s=${SIMULATION_ID} -d=0 -testid=cap_initiator_ac_12 \ + -RealEncryption=1 -rs=23 -D=2 -argstest preset $1 + + Execute ./bs_${BOARD}_tests_bsim_bluetooth_audio_prj_conf \ + -v=${VERBOSITY_LEVEL} -s=${SIMULATION_ID} -d=1 -testid=cap_acceptor_broadcast \ + -RealEncryption=1 -rs=46 -D=2 + + # Simulation time should be larger than the WAIT_TIME in common.h + Execute ./bs_2G4_phy_v1 -v=${VERBOSITY_LEVEL} -s=${SIMULATION_ID} \ + -D=2 -sim_length=60e6 ${@:2} + + wait_for_background_jobs +} + +set -e # Exit on error + +# Low latency tests +Execute_AC_12 8_1_1 +Execute_AC_12 8_2_1 +Execute_AC_12 16_1_1 +Execute_AC_12 16_2_1 +Execute_AC_12 24_1_1 +Execute_AC_12 24_2_1 +Execute_AC_12 32_1_1 +Execute_AC_12 32_2_1 +# Execute_AC_12 441_1_1 # BT_ISO_FLAGS_ERROR +Execute_AC_12 441_2_1 +# Execute_AC_12 48_1_1 # BT_ISO_FLAGS_ERROR +Execute_AC_12 48_2_1 +# Execute_AC_12 48_3_1 # BT_ISO_FLAGS_ERROR +Execute_AC_12 48_4_1 +# Execute_AC_12 48_5_1 # BT_ISO_FLAGS_ERROR +Execute_AC_12 48_6_1 + +# High reliability +# Execute_AC_12 8_1_2 # BT_ISO_FLAGS_ERROR +# Execute_AC_12 8_2_2 # BT_ISO_FLAGS_ERROR +# Execute_AC_12 16_1_2 # BT_ISO_FLAGS_ERROR +# Execute_AC_12 16_2_2 # BT_ISO_FLAGS_ERROR +# Execute_AC_12 24_1_2 # BT_ISO_FLAGS_ERROR +# Execute_AC_12 24_2_2 # BT_ISO_FLAGS_ERROR +# Execute_AC_12 32_1_2 # BT_ISO_FLAGS_ERROR +# Execute_AC_12 32_2_2 # BT_ISO_FLAGS_ERROR +# Execute_AC_12 441_1_2 # BT_ISO_FLAGS_ERROR +# Execute_AC_12 441_2_2 # BT_ISO_FLAGS_ERROR +# Execute_AC_12 48_1_2 # BT_ISO_FLAGS_ERROR +# Execute_AC_12 48_2_2 # BT_ISO_FLAGS_ERROR +# Execute_AC_12 48_3_2 # BT_ISO_FLAGS_ERROR +# Execute_AC_12 48_4_2 # BT_ISO_FLAGS_ERROR +# Execute_AC_12 48_5_2 # BT_ISO_FLAGS_ERROR +# Execute_AC_12 48_6_2 # BT_ISO_FLAGS_ERROR diff --git a/tests/bsim/bluetooth/audio/test_scripts/cap_broadcast_ac_13.sh b/tests/bsim/bluetooth/audio/test_scripts/cap_broadcast_ac_13.sh new file mode 100755 index 00000000000..dd1859cbda4 --- /dev/null +++ b/tests/bsim/bluetooth/audio/test_scripts/cap_broadcast_ac_13.sh @@ -0,0 +1,68 @@ +#!/usr/bin/env bash +# +# Copyright (c) 2024 Nordic Semiconductor ASA +# +# SPDX-License-Identifier: Apache-2.0 + +SIMULATION_ID="cap_unicast_ac_13" +VERBOSITY_LEVEL=2 +EXECUTE_TIMEOUT=60 + +source ${ZEPHYR_BASE}/tests/bsim/sh_common.source + +cd ${BSIM_OUT_PATH}/bin + +function Execute_AC_13() { + printf "\n\n======== Running CAP AC_13 with %s =========\n\n" $1 + + Execute ./bs_${BOARD}_tests_bsim_bluetooth_audio_prj_conf \ + -v=${VERBOSITY_LEVEL} -s=${SIMULATION_ID} -d=0 -testid=cap_initiator_ac_13 \ + -RealEncryption=1 -rs=23 -D=2 -argstest preset $1 + + Execute ./bs_${BOARD}_tests_bsim_bluetooth_audio_prj_conf \ + -v=${VERBOSITY_LEVEL} -s=${SIMULATION_ID} -d=1 -testid=cap_acceptor_broadcast \ + -RealEncryption=1 -rs=46 -D=2 + + # Simulation time should be larger than the WAIT_TIME in common.h + Execute ./bs_2G4_phy_v1 -v=${VERBOSITY_LEVEL} -s=${SIMULATION_ID} \ + -D=2 -sim_length=60e6 ${@:2} + + wait_for_background_jobs +} + +set -e # Exit on error + +# Execute_AC_13 8_1_1 # BT_ISO_FLAGS_ERROR +Execute_AC_13 8_2_1 +# Execute_AC_13 16_1_1 # BT_ISO_FLAGS_ERROR +Execute_AC_13 16_2_1 +# Execute_AC_13 24_1_1 # BT_ISO_FLAGS_ERROR +Execute_AC_13 24_2_1 +# Execute_AC_13 32_1_1 # BT_ISO_FLAGS_ERROR +Execute_AC_13 32_2_1 +# Execute_AC_13 441_1_1 # BT_ISO_FLAGS_ERROR +# Execute_AC_13 441_2_1 # BT_ISO_FLAGS_ERROR +# Execute_AC_13 48_1_1 # BT_ISO_FLAGS_ERROR +# Execute_AC_13 48_2_1 # BT_ISO_FLAGS_ERROR +# Execute_AC_13 48_3_1 # BT_ISO_FLAGS_ERROR +# Execute_AC_13 48_4_1 # BT_ISO_FLAGS_ERROR +# Execute_AC_13 48_5_1 # BT_ISO_FLAGS_ERROR +# Execute_AC_13 48_6_1 # BT_ISO_FLAGS_ERROR + +# High reliability +# Execute_AC_13 8_1_2 # BT_ISO_FLAGS_ERROR +# Execute_AC_13 8_2_2 # BT_ISO_FLAGS_ERROR +# Execute_AC_13 16_1_2 # BT_ISO_FLAGS_ERROR +# Execute_AC_13 16_2_2 # BT_ISO_FLAGS_ERROR +# Execute_AC_13 24_1_2 # BT_ISO_FLAGS_ERROR +# Execute_AC_13 24_2_2 # BT_ISO_FLAGS_ERROR +# Execute_AC_13 32_1_2 # BT_ISO_FLAGS_ERROR +# Execute_AC_13 32_2_2 # BT_ISO_FLAGS_ERROR +# Execute_AC_13 441_1_2 # BT_ISO_FLAGS_ERROR +# Execute_AC_13 441_2_2 # BT_ISO_FLAGS_ERROR +# Execute_AC_13 48_1_2 # BT_ISO_FLAGS_ERROR +# Execute_AC_13 48_2_2 # BT_ISO_FLAGS_ERROR +# Execute_AC_13 48_3_2 # BT_ISO_FLAGS_ERROR +# Execute_AC_13 48_4_2 # BT_ISO_FLAGS_ERROR +# Execute_AC_13 48_5_2 # BT_ISO_FLAGS_ERROR +# Execute_AC_13 48_6_2 # BT_ISO_FLAGS_ERROR diff --git a/tests/bsim/bluetooth/audio/test_scripts/cap_broadcast_ac_14.sh b/tests/bsim/bluetooth/audio/test_scripts/cap_broadcast_ac_14.sh new file mode 100755 index 00000000000..2b0735cd911 --- /dev/null +++ b/tests/bsim/bluetooth/audio/test_scripts/cap_broadcast_ac_14.sh @@ -0,0 +1,69 @@ +#!/usr/bin/env bash +# +# Copyright (c) 2024 Nordic Semiconductor ASA +# +# SPDX-License-Identifier: Apache-2.0 + +SIMULATION_ID="cap_unicast_ac_14" +VERBOSITY_LEVEL=2 +EXECUTE_TIMEOUT=60 + +source ${ZEPHYR_BASE}/tests/bsim/sh_common.source + +cd ${BSIM_OUT_PATH}/bin + +function Execute_AC_14() { + printf "\n\n======== Running CAP AC_14 with %s =========\n\n" $1 + + Execute ./bs_${BOARD}_tests_bsim_bluetooth_audio_prj_conf \ + -v=${VERBOSITY_LEVEL} -s=${SIMULATION_ID} -d=0 -testid=cap_initiator_ac_14 \ + -RealEncryption=1 -rs=23 -D=2 -argstest preset $1 + + Execute ./bs_${BOARD}_tests_bsim_bluetooth_audio_prj_conf \ + -v=${VERBOSITY_LEVEL} -s=${SIMULATION_ID} -d=1 -testid=cap_acceptor_broadcast \ + -RealEncryption=1 -rs=46 -D=2 + + # Simulation time should be larger than the WAIT_TIME in common.h + Execute ./bs_2G4_phy_v1 -v=${VERBOSITY_LEVEL} -s=${SIMULATION_ID} \ + -D=2 -sim_length=60e6 ${@:2} + + wait_for_background_jobs +} + +set -e # Exit on error + +# Low latency tests +Execute_AC_14 8_1_1 +Execute_AC_14 8_2_1 +Execute_AC_14 16_1_1 +Execute_AC_14 16_2_1 +Execute_AC_14 24_1_1 +Execute_AC_14 24_2_1 +Execute_AC_14 32_1_1 +Execute_AC_14 32_2_1 +# Execute_AC_14 441_1_1 # BT_ISO_FLAGS_ERROR +# Execute_AC_14 441_2_1 # Failed to create BIG: -22 +# Execute_AC_14 48_1_1 # BT_ISO_FLAGS_ERROR +Execute_AC_14 48_2_1 +# Execute_AC_14 48_3_1 # BT_ISO_FLAGS_ERROR +Execute_AC_14 48_4_1 +# Execute_AC_14 48_5_1 # BT_ISO_FLAGS_ERROR +# Execute_AC_14 48_6_1 # Failed to create BIG: -22 + +# High reliability +# Execute_AC_14 8_1_2 # BT_ISO_FLAGS_ERROR +# Execute_AC_14 8_2_2 # BT_ISO_FLAGS_ERROR +# Execute_AC_14 16_1_2 # BT_ISO_FLAGS_ERROR +# Execute_AC_14 16_2_2 # BT_ISO_FLAGS_ERROR +# Execute_AC_14 24_1_2 # BT_ISO_FLAGS_ERROR +# Execute_AC_14 24_2_2 # BT_ISO_FLAGS_ERROR +# Execute_AC_14 32_1_2 # BT_ISO_FLAGS_ERROR +# Execute_AC_14 32_2_2 # BT_ISO_FLAGS_ERROR +# Execute_AC_14 441_1_2 # BT_ISO_FLAGS_ERROR +# Execute_AC_14 441_2_2 # BT_ISO_FLAGS_ERROR +# Execute_AC_14 48_1_2 # BT_ISO_FLAGS_ERROR +# Execute_AC_14 48_2_2 # BT_ISO_FLAGS_ERROR +# Execute_AC_14 48_3_2 # BT_ISO_FLAGS_ERROR +# Execute_AC_14 48_4_2 # BT_ISO_FLAGS_ERROR +# Execute_AC_14 48_5_2 # BT_ISO_FLAGS_ERROR +# Execute_AC_14 48_6_2 # BT_ISO_FLAGS_ERROR From baf8c47473d56f7cd82c2a53ffaadd44275f8b05 Mon Sep 17 00:00:00 2001 From: Emil Gydesen Date: Fri, 5 Jan 2024 12:47:22 +0100 Subject: [PATCH 2101/3723] tests: bsim: Bluetooth: GMAP broadcast AC testing Add testing of all GMAP broadcast audio configuration with GMAP broadcast presets. Signed-off-by: Emil Gydesen --- .../bsim/bluetooth/audio/src/gmap_ugg_test.c | 548 +++++++++++++++--- .../test_scripts/gmap_broadcast_ac_12.sh | 39 ++ .../test_scripts/gmap_broadcast_ac_13.sh | 39 ++ .../test_scripts/gmap_broadcast_ac_14.sh | 39 ++ 4 files changed, 574 insertions(+), 91 deletions(-) create mode 100755 tests/bsim/bluetooth/audio/test_scripts/gmap_broadcast_ac_12.sh create mode 100755 tests/bsim/bluetooth/audio/test_scripts/gmap_broadcast_ac_13.sh create mode 100755 tests/bsim/bluetooth/audio/test_scripts/gmap_broadcast_ac_14.sh diff --git a/tests/bsim/bluetooth/audio/src/gmap_ugg_test.c b/tests/bsim/bluetooth/audio/src/gmap_ugg_test.c index adfce597271..8763f663fad 100644 --- a/tests/bsim/bluetooth/audio/src/gmap_ugg_test.c +++ b/tests/bsim/bluetooth/audio/src/gmap_ugg_test.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2023 Nordic Semiconductor ASA + * Copyright (c) 2023-2024 Nordic Semiconductor ASA * * SPDX-License-Identifier: Apache-2.0 */ @@ -23,18 +23,20 @@ #define CONTEXT (BT_AUDIO_CONTEXT_TYPE_UNSPECIFIED | BT_AUDIO_CONTEXT_TYPE_GAME) #define LOCATION (BT_AUDIO_LOCATION_FRONT_LEFT | BT_AUDIO_LOCATION_FRONT_RIGHT) -#define GMAP_AC_MAX_CONN 2U -#define GMAP_AC_MAX_SNK (2U * GMAP_AC_MAX_CONN) -#define GMAP_AC_MAX_SRC (2U * GMAP_AC_MAX_CONN) -#define GMAP_AC_MAX_PAIR MAX(GMAP_AC_MAX_SNK, GMAP_AC_MAX_SRC) -#define GMAP_AC_MAX_STREAM (GMAP_AC_MAX_SNK + GMAP_AC_MAX_SRC) +#define GMAP_BROADCAST_AC_MAX_STREAM 2 +#define GMAP_UNICAST_AC_MAX_CONN 2U +#define GMAP_UNICAST_AC_MAX_SNK (2U * GMAP_UNICAST_AC_MAX_CONN) +#define GMAP_UNICAST_AC_MAX_SRC (2U * GMAP_UNICAST_AC_MAX_CONN) +#define GMAP_UNICAST_AC_MAX_PAIR MAX(GMAP_UNICAST_AC_MAX_SNK, GMAP_UNICAST_AC_MAX_SRC) +#define GMAP_UNICAST_AC_MAX_STREAM (GMAP_UNICAST_AC_MAX_SNK + GMAP_UNICAST_AC_MAX_SRC) -#define MAX_CIS_COUNT 2U +#define MAX_ISO_CHAN_COUNT 2U #define ISO_ENQUEUE_COUNT 2U -#define TOTAL_BUF_NEEDED (ISO_ENQUEUE_COUNT * MAX_CIS_COUNT) +#define TOTAL_BUF_NEEDED (ISO_ENQUEUE_COUNT * MAX_ISO_CHAN_COUNT) -BUILD_ASSERT(CONFIG_BT_ISO_TX_BUF_COUNT >= TOTAL_BUF_NEEDED, - "CONFIG_BT_ISO_TX_BUF_COUNT should be at least ISO_ENQUEUE_COUNT * MAX_CIS_COUNT"); +BUILD_ASSERT( + CONFIG_BT_ISO_TX_BUF_COUNT >= TOTAL_BUF_NEEDED, + "CONFIG_BT_ISO_TX_BUF_COUNT should be at least ISO_ENQUEUE_COUNT * MAX_ISO_CHAN_COUNT"); NET_BUF_POOL_FIXED_DEFINE(tx_pool, TOTAL_BUF_NEEDED, BT_ISO_SDU_BUF_SIZE(CONFIG_BT_ISO_TX_MTU), CONFIG_BT_CONN_TX_USER_DATA_SIZE, NULL); @@ -42,16 +44,23 @@ NET_BUF_POOL_FIXED_DEFINE(tx_pool, TOTAL_BUF_NEEDED, BT_ISO_SDU_BUF_SIZE(CONFIG_ extern enum bst_result_t bst_result; static const struct named_lc3_preset *snk_named_preset; static const struct named_lc3_preset *src_named_preset; +static const struct named_lc3_preset *broadcast_named_preset; -struct gmap_ac_param { +struct gmap_unicast_ac_param { char *name; size_t conn_cnt; - size_t snk_cnt[GMAP_AC_MAX_CONN]; - size_t src_cnt[GMAP_AC_MAX_CONN]; + size_t snk_cnt[GMAP_UNICAST_AC_MAX_CONN]; + size_t src_cnt[GMAP_UNICAST_AC_MAX_CONN]; size_t snk_chan_cnt; const struct named_lc3_preset *snk_named_preset; const struct named_lc3_preset *src_named_preset; }; +struct gmap_broadcast_ac_param { + char *name; + size_t stream_cnt; + size_t chan_cnt; + const struct named_lc3_preset *named_preset; +}; static struct named_lc3_preset gmap_unicast_snk_presets[] = { {"32_1_gr", BT_GMAP_LC3_PRESET_32_1_GR(LOCATION, CONTEXT)}, @@ -80,14 +89,19 @@ static struct named_lc3_preset gmap_broadcast_presets[] = { struct named_lc3_preset named_preset; -static struct unicast_stream unicast_streams[GMAP_AC_MAX_STREAM]; -static struct bt_bap_ep *sink_eps[GMAP_AC_MAX_CONN][CONFIG_BT_BAP_UNICAST_CLIENT_ASE_SNK_COUNT]; -static struct bt_bap_ep *source_eps[GMAP_AC_MAX_CONN][CONFIG_BT_BAP_UNICAST_CLIENT_ASE_SRC_COUNT]; -static struct bt_conn *connected_conns[GMAP_AC_MAX_CONN]; +static struct audio_test_stream broadcast_streams[CONFIG_BT_BAP_BROADCAST_SRC_STREAM_COUNT]; +static struct unicast_stream unicast_streams[GMAP_UNICAST_AC_MAX_STREAM]; +static struct bt_bap_ep + *sink_eps[GMAP_UNICAST_AC_MAX_CONN][CONFIG_BT_BAP_UNICAST_CLIENT_ASE_SNK_COUNT]; +static struct bt_bap_ep + *source_eps[GMAP_UNICAST_AC_MAX_CONN][CONFIG_BT_BAP_UNICAST_CLIENT_ASE_SRC_COUNT]; +static struct bt_conn *connected_conns[GMAP_UNICAST_AC_MAX_CONN]; static size_t connected_conn_cnt; -static K_SEM_DEFINE(sem_stream_started, 0U, ARRAY_SIZE(unicast_streams)); -static K_SEM_DEFINE(sem_stream_stopped, 0U, ARRAY_SIZE(unicast_streams)); +static K_SEM_DEFINE(sem_stream_started, 0U, + MAX(ARRAY_SIZE(unicast_streams), ARRAY_SIZE(broadcast_streams))); +static K_SEM_DEFINE(sem_stream_stopped, 0U, + MAX(ARRAY_SIZE(unicast_streams), ARRAY_SIZE(broadcast_streams))); CREATE_FLAG(flag_cas_discovered); CREATE_FLAG(flag_started); @@ -96,7 +110,6 @@ CREATE_FLAG(flag_stopped); CREATE_FLAG(flag_mtu_exchanged); CREATE_FLAG(flag_sink_discovered); CREATE_FLAG(flag_source_discovered); -CREATE_FLAG(flag_stream_stopping); CREATE_FLAG(flag_gmap_discovered); const struct named_lc3_preset *gmap_get_named_preset(bool is_unicast, enum bt_audio_dir dir, @@ -128,47 +141,50 @@ const struct named_lc3_preset *gmap_get_named_preset(bool is_unicast, enum bt_au return NULL; } -static void stream_sent_cb(struct bt_bap_stream *stream) +static void stream_sent_cb(struct bt_bap_stream *bap_stream) { - static uint8_t mock_data[CONFIG_BT_ISO_TX_MTU]; - static bool mock_data_initialized; - static uint32_t seq_num; + struct audio_test_stream *test_stream = audio_test_stream_from_bap_stream(bap_stream); + struct bt_cap_stream *cap_stream = cap_stream_from_audio_test_stream(test_stream); struct net_buf *buf; int ret; - if (named_preset.preset.qos.sdu > CONFIG_BT_ISO_TX_MTU) { - FAIL("Invalid SDU %u for the MTU: %d\n", named_preset.preset.qos.sdu, - CONFIG_BT_ISO_TX_MTU); + if (!test_stream->tx_active) { return; } - if (TEST_FLAG(flag_stream_stopping)) { - return; + if ((test_stream->tx_cnt % 100U) == 0U) { + printk("[%zu]: Stream %p sent with seq_num %u\n", test_stream->tx_cnt, cap_stream, + test_stream->seq_num); } - if (!mock_data_initialized) { - for (size_t i = 0U; i < ARRAY_SIZE(mock_data); i++) { - /* Initialize mock data */ - mock_data[i] = (uint8_t)i; - } - mock_data_initialized = true; + if (test_stream->tx_sdu_size > CONFIG_BT_ISO_TX_MTU) { + FAIL("Invalid SDU %u for the MTU: %d", test_stream->tx_sdu_size, + CONFIG_BT_ISO_TX_MTU); + return; } buf = net_buf_alloc(&tx_pool, K_FOREVER); if (buf == NULL) { - printk("Could not allocate buffer when sending on %p\n", stream); + printk("Could not allocate buffer when sending on %p\n", bap_stream); return; } net_buf_reserve(buf, BT_ISO_CHAN_SEND_RESERVE); - net_buf_add_mem(buf, mock_data, named_preset.preset.qos.sdu); - ret = bt_bap_stream_send(stream, buf, seq_num++, BT_ISO_TIMESTAMP_NONE); + net_buf_add_mem(buf, mock_iso_data, test_stream->tx_sdu_size); + ret = bt_cap_stream_send(cap_stream, buf, test_stream->seq_num++, BT_ISO_TIMESTAMP_NONE); if (ret < 0) { - /* This will end send on this stream. */ - printk("Unable to send data on %p: %d\n", stream, ret); + /* This will end broadcasting on this stream. */ net_buf_unref(buf); + + /* Only fail if tx is active (may fail if we are disabling the stream) */ + if (test_stream->tx_active) { + FAIL("Unable to broadcast data on %p: %d\n", cap_stream, ret); + } + return; } + + test_stream->tx_cnt++; } static void stream_configured_cb(struct bt_bap_stream *stream, @@ -439,6 +455,11 @@ static void init(void) bt_cap_stream_ops_register(&unicast_streams[i].stream, &stream_ops); } + for (size_t i = 0; i < ARRAY_SIZE(broadcast_streams); i++) { + bt_cap_stream_ops_register(cap_stream_from_audio_test_stream(&broadcast_streams[i]), + &stream_ops); + } + err = bt_gmap_register(role, features); if (err != 0) { FAIL("Failed to register GMAS (err %d)\n", err); @@ -574,14 +595,18 @@ static void discover_cas(struct bt_conn *conn) WAIT_FOR_FLAG(flag_cas_discovered); } -static int gmap_ac_create_unicast_group(const struct gmap_ac_param *param, - struct unicast_stream *snk_uni_streams[], size_t snk_cnt, - struct unicast_stream *src_uni_streams[], size_t src_cnt, - struct bt_bap_unicast_group **unicast_group) +static int gmap_unicast_ac_create_unicast_group(const struct gmap_unicast_ac_param *param, + struct unicast_stream *snk_uni_streams[], + size_t snk_cnt, + struct unicast_stream *src_uni_streams[], + size_t src_cnt, + struct bt_bap_unicast_group **unicast_group) { - struct bt_bap_unicast_group_stream_param snk_group_stream_params[GMAP_AC_MAX_SNK] = {0}; - struct bt_bap_unicast_group_stream_param src_group_stream_params[GMAP_AC_MAX_SRC] = {0}; - struct bt_bap_unicast_group_stream_pair_param pair_params[GMAP_AC_MAX_PAIR] = {0}; + struct bt_bap_unicast_group_stream_param + snk_group_stream_params[GMAP_UNICAST_AC_MAX_SNK] = {0}; + struct bt_bap_unicast_group_stream_param + src_group_stream_params[GMAP_UNICAST_AC_MAX_SRC] = {0}; + struct bt_bap_unicast_group_stream_pair_param pair_params[GMAP_UNICAST_AC_MAX_PAIR] = {0}; struct bt_bap_unicast_group_param group_param = {0}; size_t snk_stream_cnt = 0U; size_t src_stream_cnt = 0U; @@ -628,19 +653,20 @@ static int gmap_ac_create_unicast_group(const struct gmap_ac_param *param, return bt_bap_unicast_group_create(&group_param, unicast_group); } -static int gmap_ac_cap_unicast_start(const struct gmap_ac_param *param, +static int gmap_ac_cap_unicast_start(const struct gmap_unicast_ac_param *param, struct unicast_stream *snk_uni_streams[], size_t snk_cnt, struct unicast_stream *src_uni_streams[], size_t src_cnt, struct bt_bap_unicast_group *unicast_group) { - struct bt_cap_unicast_audio_start_stream_param stream_params[GMAP_AC_MAX_STREAM] = {0}; - struct bt_audio_codec_cfg *snk_codec_cfgs[GMAP_AC_MAX_SNK] = {0}; - struct bt_audio_codec_cfg *src_codec_cfgs[GMAP_AC_MAX_SRC] = {0}; - struct bt_cap_stream *snk_cap_streams[GMAP_AC_MAX_SNK] = {0}; - struct bt_cap_stream *src_cap_streams[GMAP_AC_MAX_SRC] = {0}; + struct bt_cap_unicast_audio_start_stream_param stream_params[GMAP_UNICAST_AC_MAX_STREAM] = { + 0}; + struct bt_audio_codec_cfg *snk_codec_cfgs[GMAP_UNICAST_AC_MAX_SNK] = {0}; + struct bt_audio_codec_cfg *src_codec_cfgs[GMAP_UNICAST_AC_MAX_SRC] = {0}; + struct bt_cap_stream *snk_cap_streams[GMAP_UNICAST_AC_MAX_SNK] = {0}; + struct bt_cap_stream *src_cap_streams[GMAP_UNICAST_AC_MAX_SRC] = {0}; struct bt_cap_unicast_audio_start_param start_param = {0}; - struct bt_bap_ep *snk_eps[GMAP_AC_MAX_SNK] = {0}; - struct bt_bap_ep *src_eps[GMAP_AC_MAX_SRC] = {0}; + struct bt_bap_ep *snk_eps[GMAP_UNICAST_AC_MAX_SNK] = {0}; + struct bt_bap_ep *src_eps[GMAP_UNICAST_AC_MAX_SRC] = {0}; size_t snk_stream_cnt = 0U; size_t src_stream_cnt = 0U; size_t stream_cnt = 0U; @@ -745,17 +771,17 @@ static int gmap_ac_cap_unicast_start(const struct gmap_ac_param *param, return bt_cap_initiator_unicast_audio_start(&start_param, unicast_group); } -static int gmap_ac_unicast(const struct gmap_ac_param *param, +static int gmap_ac_unicast(const struct gmap_unicast_ac_param *param, struct bt_bap_unicast_group **unicast_group) { /* Allocate params large enough for any params, but only use what is required */ - struct unicast_stream *snk_uni_streams[GMAP_AC_MAX_SNK]; - struct unicast_stream *src_uni_streams[GMAP_AC_MAX_SRC]; + struct unicast_stream *snk_uni_streams[GMAP_UNICAST_AC_MAX_SNK]; + struct unicast_stream *src_uni_streams[GMAP_UNICAST_AC_MAX_SRC]; size_t snk_cnt = 0; size_t src_cnt = 0; int err; - if (param->conn_cnt > GMAP_AC_MAX_CONN) { + if (param->conn_cnt > GMAP_UNICAST_AC_MAX_CONN) { FAIL("Invalid conn_cnt: %zu\n", param->conn_cnt); return -EINVAL; @@ -763,13 +789,13 @@ static int gmap_ac_unicast(const struct gmap_ac_param *param, for (size_t i = 0; i < param->conn_cnt; i++) { /* Verify conn values */ - if (param->snk_cnt[i] > GMAP_AC_MAX_SNK) { + if (param->snk_cnt[i] > GMAP_UNICAST_AC_MAX_SNK) { FAIL("Invalid conn_snk_cnt[%zu]: %zu\n", i, param->snk_cnt[i]); return -EINVAL; } - if (param->src_cnt[i] > GMAP_AC_MAX_SRC) { + if (param->src_cnt[i] > GMAP_UNICAST_AC_MAX_SRC) { FAIL("Invalid conn_src_cnt[%zu]: %zu\n", i, param->src_cnt[i]); return -EINVAL; @@ -806,8 +832,8 @@ static int gmap_ac_unicast(const struct gmap_ac_param *param, copy_unicast_stream_preset(src_uni_streams[i], param->src_named_preset); } - err = gmap_ac_create_unicast_group(param, snk_uni_streams, snk_cnt, src_uni_streams, - src_cnt, unicast_group); + err = gmap_unicast_ac_create_unicast_group(param, snk_uni_streams, snk_cnt, src_uni_streams, + src_cnt, unicast_group); if (err != 0) { FAIL("Failed to create group: %d\n", err); @@ -856,7 +882,7 @@ static void unicast_group_delete(struct bt_bap_unicast_group *unicast_group) } } -static void test_ugg(const struct gmap_ac_param *param) +static void test_gmap_ugg_unicast_ac(const struct gmap_unicast_ac_param *param) { struct bt_bap_unicast_group *unicast_group; @@ -864,7 +890,7 @@ static void test_ugg(const struct gmap_ac_param *param) param->snk_named_preset != NULL ? param->snk_named_preset->name : "None", param->src_named_preset != NULL ? param->src_named_preset->name : "None"); - if (param->conn_cnt > GMAP_AC_MAX_CONN) { + if (param->conn_cnt > GMAP_UNICAST_AC_MAX_CONN) { FAIL("Invalid conn_cnt: %zu\n", param->conn_cnt); return; } @@ -926,9 +952,270 @@ static void test_ugg(const struct gmap_ac_param *param) param->src_named_preset != NULL ? param->src_named_preset->name : "None"); } +static void setup_extended_adv(struct bt_le_ext_adv **adv) +{ + int err; + + /* Create a non-connectable non-scannable advertising set */ + err = bt_le_ext_adv_create(BT_LE_EXT_ADV_NCONN_NAME, NULL, adv); + if (err != 0) { + FAIL("Unable to create extended advertising set: %d\n", err); + return; + } + + /* Set periodic advertising parameters */ + err = bt_le_per_adv_set_param(*adv, BT_LE_PER_ADV_DEFAULT); + if (err) { + FAIL("Failed to set periodic advertising parameters: %d\n", err); + return; + } +} + +static void setup_extended_adv_data(struct bt_cap_broadcast_source *source, + struct bt_le_ext_adv *adv) +{ + /* Broadcast Audio Streaming Endpoint advertising data */ + NET_BUF_SIMPLE_DEFINE(ad_buf, BT_UUID_SIZE_16 + BT_AUDIO_BROADCAST_ID_SIZE); + NET_BUF_SIMPLE_DEFINE(base_buf, 128); + struct bt_data ext_ad; + struct bt_data per_ad; + uint32_t broadcast_id; + int err; + + err = bt_cap_initiator_broadcast_get_id(source, &broadcast_id); + if (err != 0) { + FAIL("Unable to get broadcast ID: %d\n", err); + return; + } + + /* Setup extended advertising data */ + net_buf_simple_add_le16(&ad_buf, BT_UUID_BROADCAST_AUDIO_VAL); + net_buf_simple_add_le24(&ad_buf, broadcast_id); + ext_ad.type = BT_DATA_SVC_DATA16; + ext_ad.data_len = ad_buf.len; + ext_ad.data = ad_buf.data; + err = bt_le_ext_adv_set_data(adv, &ext_ad, 1, NULL, 0); + if (err != 0) { + FAIL("Failed to set extended advertising data: %d\n", err); + return; + } + + /* Setup periodic advertising data */ + err = bt_cap_initiator_broadcast_get_base(source, &base_buf); + if (err != 0) { + FAIL("Failed to get encoded BASE: %d\n", err); + return; + } + + per_ad.type = BT_DATA_SVC_DATA16; + per_ad.data_len = base_buf.len; + per_ad.data = base_buf.data; + err = bt_le_per_adv_set_data(adv, &per_ad, 1); + if (err != 0) { + FAIL("Failed to set periodic advertising data: %d\n", err); + return; + } +} + +static void start_extended_adv(struct bt_le_ext_adv *adv) +{ + int err; + + /* Start extended advertising */ + err = bt_le_ext_adv_start(adv, BT_LE_EXT_ADV_START_DEFAULT); + if (err) { + FAIL("Failed to start extended advertising: %d\n", err); + return; + } + + /* Enable Periodic Advertising */ + err = bt_le_per_adv_start(adv); + if (err) { + FAIL("Failed to enable periodic advertising: %d\n", err); + return; + } +} + +static void stop_and_delete_extended_adv(struct bt_le_ext_adv *adv) +{ + int err; + + /* Stop extended advertising */ + err = bt_le_per_adv_stop(adv); + if (err) { + FAIL("Failed to stop periodic advertising: %d\n", err); + return; + } + + err = bt_le_ext_adv_stop(adv); + if (err) { + FAIL("Failed to stop extended advertising: %d\n", err); + return; + } + + err = bt_le_ext_adv_delete(adv); + if (err) { + FAIL("Failed to delete extended advertising: %d\n", err); + return; + } +} + +static void broadcast_audio_start(struct bt_cap_broadcast_source *broadcast_source, + struct bt_le_ext_adv *adv) +{ + int err; + + err = bt_cap_initiator_broadcast_audio_start(broadcast_source, adv); + if (err != 0) { + FAIL("Unable to start broadcast source: %d\n", err); + return; + } + + printk("Broadcast source created\n"); +} + +static void broadcast_audio_stop(struct bt_cap_broadcast_source *broadcast_source, + size_t stream_count) +{ + int err; + + printk("Stopping broadcast source\n"); + + for (size_t i = 0U; i < ARRAY_SIZE(broadcast_streams); i++) { + broadcast_streams[i].tx_active = false; + } + + err = bt_cap_initiator_broadcast_audio_stop(broadcast_source); + if (err != 0) { + FAIL("Failed to stop broadcast source: %d\n", err); + return; + } + + /* Wait for all to be stopped */ + printk("Waiting for broadcast_streams to be stopped\n"); + for (size_t i = 0U; i < stream_count; i++) { + k_sem_take(&sem_stream_stopped, K_FOREVER); + } + + printk("Broadcast source stopped\n"); +} + +static void broadcast_audio_delete(struct bt_cap_broadcast_source *broadcast_source) +{ + int err; + + printk("Deleting broadcast source\n"); + + err = bt_cap_initiator_broadcast_audio_delete(broadcast_source); + if (err != 0) { + FAIL("Failed to stop broadcast source: %d\n", err); + return; + } + + printk("Broadcast source deleted\n"); +} + +static int test_gmap_ugg_broadcast_ac(const struct gmap_broadcast_ac_param *param) +{ + uint8_t stereo_data[] = { + BT_AUDIO_CODEC_DATA(BT_AUDIO_CODEC_CONFIG_LC3_CHAN_ALLOC, + BT_AUDIO_LOCATION_FRONT_RIGHT | BT_AUDIO_LOCATION_FRONT_LEFT)}; + uint8_t right_data[] = {BT_AUDIO_CODEC_DATA(BT_AUDIO_CODEC_CONFIG_LC3_CHAN_ALLOC, + BT_AUDIO_LOCATION_FRONT_RIGHT)}; + uint8_t left_data[] = {BT_AUDIO_CODEC_DATA(BT_AUDIO_CODEC_CONFIG_LC3_CHAN_ALLOC, + BT_AUDIO_LOCATION_FRONT_LEFT)}; + struct bt_cap_initiator_broadcast_subgroup_param subgroup_param = {0}; + struct bt_cap_initiator_broadcast_create_param create_param = {0}; + struct bt_cap_initiator_broadcast_stream_param + stream_params[GMAP_BROADCAST_AC_MAX_STREAM] = {0}; + struct bt_cap_broadcast_source *broadcast_source; + struct bt_audio_codec_cfg codec_cfg; + struct bt_audio_codec_qos qos; + struct bt_le_ext_adv *adv; + int err; + + for (size_t i = 0U; i < param->stream_cnt; i++) { + stream_params[i].stream = cap_stream_from_audio_test_stream(&broadcast_streams[i]); + + if (param->stream_cnt == 1U) { + stream_params[i].data_len = ARRAY_SIZE(stereo_data); + stream_params[i].data = stereo_data; + } else if (i == 0U) { + stream_params[i].data_len = ARRAY_SIZE(left_data); + stream_params[i].data = left_data; + } else if (i == 1U) { + stream_params[i].data_len = ARRAY_SIZE(right_data); + stream_params[i].data = right_data; + } + } + + memcpy(&codec_cfg, &broadcast_named_preset->preset.codec_cfg, sizeof(codec_cfg)); + memcpy(&qos, &broadcast_named_preset->preset.qos, sizeof(qos)); + qos.sdu *= param->chan_cnt; + + subgroup_param.stream_count = param->stream_cnt; + subgroup_param.stream_params = stream_params; + subgroup_param.codec_cfg = &codec_cfg; + create_param.subgroup_count = 1U; + create_param.subgroup_params = &subgroup_param; + create_param.qos = &qos; + + init(); + setup_extended_adv(&adv); + + err = bt_cap_initiator_broadcast_audio_create(&create_param, &broadcast_source); + if (err != 0) { + FAIL("Failed to create broadcast source: %d\n", err); + return -ENOEXEC; + } + + for (size_t i = 0U; i < param->stream_cnt; i++) { + struct audio_test_stream *test_stream = &broadcast_streams[i]; + + test_stream->tx_sdu_size = create_param.qos->sdu; + } + + broadcast_audio_start(broadcast_source, adv); + setup_extended_adv_data(broadcast_source, adv); + start_extended_adv(adv); + + /* Wait for all to be started */ + printk("Waiting for broadcast_streams to be started\n"); + for (size_t i = 0U; i < param->stream_cnt; i++) { + k_sem_take(&sem_stream_started, K_FOREVER); + } + + /* Initialize sending */ + printk("Starting sending\n"); + for (size_t i = 0U; i < param->stream_cnt; i++) { + struct audio_test_stream *test_stream = &broadcast_streams[i]; + + test_stream->tx_active = true; + + for (unsigned int j = 0U; j < ISO_ENQUEUE_COUNT; j++) { + stream_sent_cb(bap_stream_from_audio_test_stream(test_stream)); + } + } + + /* Wait for other devices to have received what they wanted */ + backchannel_sync_wait_any(); + + broadcast_audio_stop(broadcast_source, param->stream_cnt); + + broadcast_audio_delete(broadcast_source); + broadcast_source = NULL; + + stop_and_delete_extended_adv(adv); + adv = NULL; + + PASS("CAP initiator broadcast passed\n"); + + return 0; +} + static void test_gmap_ac_1(void) { - const struct gmap_ac_param param = { + const struct gmap_unicast_ac_param param = { .name = "ac_1", .conn_cnt = 1U, .snk_cnt = {1U}, @@ -938,12 +1225,12 @@ static void test_gmap_ac_1(void) .src_named_preset = NULL, }; - test_ugg(¶m); + test_gmap_ugg_unicast_ac(¶m); } static void test_gmap_ac_2(void) { - const struct gmap_ac_param param = { + const struct gmap_unicast_ac_param param = { .name = "ac_2", .conn_cnt = 1U, .snk_cnt = {0U}, @@ -953,12 +1240,12 @@ static void test_gmap_ac_2(void) .src_named_preset = src_named_preset, }; - test_ugg(¶m); + test_gmap_ugg_unicast_ac(¶m); } static void test_gmap_ac_3(void) { - const struct gmap_ac_param param = { + const struct gmap_unicast_ac_param param = { .name = "ac_3", .conn_cnt = 1U, .snk_cnt = {1U}, @@ -968,12 +1255,12 @@ static void test_gmap_ac_3(void) .src_named_preset = src_named_preset, }; - test_ugg(¶m); + test_gmap_ugg_unicast_ac(¶m); } static void test_gmap_ac_4(void) { - const struct gmap_ac_param param = { + const struct gmap_unicast_ac_param param = { .name = "ac_4", .conn_cnt = 1U, .snk_cnt = {1U}, @@ -983,12 +1270,12 @@ static void test_gmap_ac_4(void) .src_named_preset = NULL, }; - test_ugg(¶m); + test_gmap_ugg_unicast_ac(¶m); } static void test_gmap_ac_5(void) { - const struct gmap_ac_param param = { + const struct gmap_unicast_ac_param param = { .name = "ac_5", .conn_cnt = 1U, .snk_cnt = {1U}, @@ -998,12 +1285,12 @@ static void test_gmap_ac_5(void) .src_named_preset = src_named_preset, }; - test_ugg(¶m); + test_gmap_ugg_unicast_ac(¶m); } static void test_gmap_ac_6_i(void) { - const struct gmap_ac_param param = { + const struct gmap_unicast_ac_param param = { .name = "ac_6_i", .conn_cnt = 1U, .snk_cnt = {2U}, @@ -1013,12 +1300,12 @@ static void test_gmap_ac_6_i(void) .src_named_preset = NULL, }; - test_ugg(¶m); + test_gmap_ugg_unicast_ac(¶m); } static void test_gmap_ac_6_ii(void) { - const struct gmap_ac_param param = { + const struct gmap_unicast_ac_param param = { .name = "ac_6_ii", .conn_cnt = 2U, .snk_cnt = {1U, 1U}, @@ -1028,12 +1315,12 @@ static void test_gmap_ac_6_ii(void) .src_named_preset = NULL, }; - test_ugg(¶m); + test_gmap_ugg_unicast_ac(¶m); } static void test_gmap_ac_7_ii(void) { - const struct gmap_ac_param param = { + const struct gmap_unicast_ac_param param = { .name = "ac_7_ii", .conn_cnt = 2U, .snk_cnt = {1U, 0U}, @@ -1043,12 +1330,12 @@ static void test_gmap_ac_7_ii(void) .src_named_preset = src_named_preset, }; - test_ugg(¶m); + test_gmap_ugg_unicast_ac(¶m); } static void test_gmap_ac_8_i(void) { - const struct gmap_ac_param param = { + const struct gmap_unicast_ac_param param = { .name = "ac_8_i", .conn_cnt = 1U, .snk_cnt = {2U}, @@ -1058,12 +1345,12 @@ static void test_gmap_ac_8_i(void) .src_named_preset = src_named_preset, }; - test_ugg(¶m); + test_gmap_ugg_unicast_ac(¶m); } static void test_gmap_ac_8_ii(void) { - const struct gmap_ac_param param = { + const struct gmap_unicast_ac_param param = { .name = "ac_8_ii", .conn_cnt = 2U, .snk_cnt = {1U, 1U}, @@ -1073,12 +1360,12 @@ static void test_gmap_ac_8_ii(void) .src_named_preset = src_named_preset, }; - test_ugg(¶m); + test_gmap_ugg_unicast_ac(¶m); } static void test_gmap_ac_11_i(void) { - const struct gmap_ac_param param = { + const struct gmap_unicast_ac_param param = { .name = "ac_11_i", .conn_cnt = 1U, .snk_cnt = {2U}, @@ -1088,12 +1375,12 @@ static void test_gmap_ac_11_i(void) .src_named_preset = src_named_preset, }; - test_ugg(¶m); + test_gmap_ugg_unicast_ac(¶m); } static void test_gmap_ac_11_ii(void) { - const struct gmap_ac_param param = { + const struct gmap_unicast_ac_param param = { .name = "ac_11_ii", .conn_cnt = 2U, .snk_cnt = {1U, 1U}, @@ -1103,7 +1390,45 @@ static void test_gmap_ac_11_ii(void) .src_named_preset = src_named_preset, }; - test_ugg(¶m); + test_gmap_ugg_unicast_ac(¶m); +} + +static void test_gmap_ac_12(void) +{ + const struct gmap_broadcast_ac_param param = { + .name = "ac_12", + .stream_cnt = 1U, + .chan_cnt = 1U, + .named_preset = broadcast_named_preset, + }; + + test_gmap_ugg_broadcast_ac(¶m); +} + +#if CONFIG_BT_BAP_BROADCAST_SRC_STREAM_COUNT >= GMAP_BROADCAST_AC_MAX_STREAM +static void test_gmap_ac_13(void) +{ + const struct gmap_broadcast_ac_param param = { + .name = "ac_13", + .stream_cnt = 2U, + .chan_cnt = 1U, + .named_preset = broadcast_named_preset, + }; + + test_gmap_ugg_broadcast_ac(¶m); +} +#endif /* CONFIG_BT_BAP_BROADCAST_SRC_STREAM_COUNT >= GMAP_BROADCAST_AC_MAX_STREAM */ + +static void test_gmap_ac_14(void) +{ + const struct gmap_broadcast_ac_param param = { + .name = "ac_14", + .stream_cnt = 1U, + .chan_cnt = 2U, + .named_preset = broadcast_named_preset, + }; + + test_gmap_ugg_broadcast_ac(¶m); } static void test_args(int argc, char *argv[]) @@ -1112,11 +1437,29 @@ static void test_args(int argc, char *argv[]) const char *arg = argv[argn]; if (strcmp(arg, "sink_preset") == 0) { + const char *preset_arg = argv[++argn]; + snk_named_preset = - gmap_get_named_preset(true, BT_AUDIO_DIR_SINK, argv[++argn]); + gmap_get_named_preset(true, BT_AUDIO_DIR_SINK, preset_arg); + if (snk_named_preset == NULL) { + FAIL("Failed to get sink preset from %s\n", preset_arg); + } } else if (strcmp(arg, "source_preset") == 0) { + const char *preset_arg = argv[++argn]; + src_named_preset = - gmap_get_named_preset(true, BT_AUDIO_DIR_SOURCE, argv[++argn]); + gmap_get_named_preset(true, BT_AUDIO_DIR_SOURCE, preset_arg); + if (src_named_preset == NULL) { + FAIL("Failed to get source preset from %s\n", preset_arg); + } + } else if (strcmp(arg, "broadcast_preset") == 0) { + const char *preset_arg = argv[++argn]; + + broadcast_named_preset = gmap_get_named_preset( + false, BT_AUDIO_DIR_SINK /* unused */, preset_arg); + if (broadcast_named_preset == NULL) { + FAIL("Failed to get broadcast preset from %s\n", preset_arg); + } } else { FAIL("Invalid arg: %s\n", arg); } @@ -1208,6 +1551,29 @@ static const struct bst_test_instance test_gmap_ugg[] = { .test_main_f = test_gmap_ac_11_ii, .test_args_f = test_args, }, + { + .test_id = "gmap_ugg_ac_12", + .test_post_init_f = test_init, + .test_tick_f = test_tick, + .test_main_f = test_gmap_ac_12, + .test_args_f = test_args, + }, +#if CONFIG_BT_BAP_BROADCAST_SRC_STREAM_COUNT >= GMAP_BROADCAST_AC_MAX_STREAM + { + .test_id = "gmap_ugg_ac_13", + .test_post_init_f = test_init, + .test_tick_f = test_tick, + .test_main_f = test_gmap_ac_13, + .test_args_f = test_args, + }, +#endif /* CONFIG_BT_BAP_BROADCAST_SRC_STREAM_COUNT >= GMAP_BROADCAST_AC_MAX_STREAM */ + { + .test_id = "gmap_ugg_ac_14", + .test_post_init_f = test_init, + .test_tick_f = test_tick, + .test_main_f = test_gmap_ac_14, + .test_args_f = test_args, + }, BSTEST_END_MARKER, }; diff --git a/tests/bsim/bluetooth/audio/test_scripts/gmap_broadcast_ac_12.sh b/tests/bsim/bluetooth/audio/test_scripts/gmap_broadcast_ac_12.sh new file mode 100755 index 00000000000..2038ef4a163 --- /dev/null +++ b/tests/bsim/bluetooth/audio/test_scripts/gmap_broadcast_ac_12.sh @@ -0,0 +1,39 @@ +#!/usr/bin/env bash +# +# Copyright (c) 2024 Nordic Semiconductor ASA +# +# SPDX-License-Identifier: Apache-2.0 + +SIMULATION_ID="gmap_unicast_ac_12" +VERBOSITY_LEVEL=2 +EXECUTE_TIMEOUT=60 + +source ${ZEPHYR_BASE}/tests/bsim/sh_common.source + +cd ${BSIM_OUT_PATH}/bin + +function Execute_AC_12() { + printf "\n\n======== Running GMAP AC_12 with %s =========\n\n" $1 + + Execute ./bs_${BOARD}_tests_bsim_bluetooth_audio_prj_conf \ + -v=${VERBOSITY_LEVEL} -s=${SIMULATION_ID} -d=0 -testid=gmap_ugg_ac_12 \ + -RealEncryption=1 -rs=23 -D=2 -argstest broadcast_preset $1 + + Execute ./bs_${BOARD}_tests_bsim_bluetooth_audio_prj_conf \ + -v=${VERBOSITY_LEVEL} -s=${SIMULATION_ID} -d=1 -testid=cap_acceptor_broadcast \ + -RealEncryption=1 -rs=46 -D=2 + + # Simulation time should be larger than the WAIT_TIME in common.h + Execute ./bs_2G4_phy_v1 -v=${VERBOSITY_LEVEL} -s=${SIMULATION_ID} \ + -D=2 -sim_length=60e6 ${@:2} + + wait_for_background_jobs +} + +set -e # Exit on error + +# Low latency tests +Execute_AC_12 48_1_g +Execute_AC_12 48_2_g +Execute_AC_12 48_3_g +Execute_AC_12 48_4_g diff --git a/tests/bsim/bluetooth/audio/test_scripts/gmap_broadcast_ac_13.sh b/tests/bsim/bluetooth/audio/test_scripts/gmap_broadcast_ac_13.sh new file mode 100755 index 00000000000..a6bfcac4903 --- /dev/null +++ b/tests/bsim/bluetooth/audio/test_scripts/gmap_broadcast_ac_13.sh @@ -0,0 +1,39 @@ +#!/usr/bin/env bash +# +# Copyright (c) 2024 Nordic Semiconductor ASA +# +# SPDX-License-Identifier: Apache-2.0 + +SIMULATION_ID="gmap_unicast_ac_13" +VERBOSITY_LEVEL=2 +EXECUTE_TIMEOUT=60 + +source ${ZEPHYR_BASE}/tests/bsim/sh_common.source + +cd ${BSIM_OUT_PATH}/bin + +function Execute_AC_13() { + printf "\n\n======== Running GMAP AC_13 with %s =========\n\n" $1 + + Execute ./bs_${BOARD}_tests_bsim_bluetooth_audio_prj_conf \ + -v=${VERBOSITY_LEVEL} -s=${SIMULATION_ID} -d=0 -testid=gmap_ugg_ac_13 \ + -RealEncryption=1 -rs=23 -D=2 -argstest broadcast_preset $1 + + Execute ./bs_${BOARD}_tests_bsim_bluetooth_audio_prj_conf \ + -v=${VERBOSITY_LEVEL} -s=${SIMULATION_ID} -d=1 -testid=cap_acceptor_broadcast \ + -RealEncryption=1 -rs=46 -D=2 + + # Simulation time should be larger than the WAIT_TIME in common.h + Execute ./bs_2G4_phy_v1 -v=${VERBOSITY_LEVEL} -s=${SIMULATION_ID} \ + -D=2 -sim_length=60e6 ${@:2} + + wait_for_background_jobs +} + +set -e # Exit on error + +# Low latency tests +# Execute_AC_13 48_1_g # BT_ISO_FLAGS_ERROR +Execute_AC_13 48_2_g +# Execute_AC_13 48_3_g # BT_ISO_FLAGS_ERROR +Execute_AC_13 48_4_g diff --git a/tests/bsim/bluetooth/audio/test_scripts/gmap_broadcast_ac_14.sh b/tests/bsim/bluetooth/audio/test_scripts/gmap_broadcast_ac_14.sh new file mode 100755 index 00000000000..b73c67f42fe --- /dev/null +++ b/tests/bsim/bluetooth/audio/test_scripts/gmap_broadcast_ac_14.sh @@ -0,0 +1,39 @@ +#!/usr/bin/env bash +# +# Copyright (c) 2024 Nordic Semiconductor ASA +# +# SPDX-License-Identifier: Apache-2.0 + +SIMULATION_ID="gmap_unicast_ac_14" +VERBOSITY_LEVEL=2 +EXECUTE_TIMEOUT=60 + +source ${ZEPHYR_BASE}/tests/bsim/sh_common.source + +cd ${BSIM_OUT_PATH}/bin + +function Execute_AC_14() { + printf "\n\n======== Running GMAP AC_14 with %s =========\n\n" $1 + + Execute ./bs_${BOARD}_tests_bsim_bluetooth_audio_prj_conf \ + -v=${VERBOSITY_LEVEL} -s=${SIMULATION_ID} -d=0 -testid=gmap_ugg_ac_14 \ + -RealEncryption=1 -rs=23 -D=2 -argstest broadcast_preset $1 + + Execute ./bs_${BOARD}_tests_bsim_bluetooth_audio_prj_conf \ + -v=${VERBOSITY_LEVEL} -s=${SIMULATION_ID} -d=1 -testid=cap_acceptor_broadcast \ + -RealEncryption=1 -rs=46 -D=2 + + # Simulation time should be larger than the WAIT_TIME in common.h + Execute ./bs_2G4_phy_v1 -v=${VERBOSITY_LEVEL} -s=${SIMULATION_ID} \ + -D=2 -sim_length=60e6 ${@:2} + + wait_for_background_jobs +} + +set -e # Exit on error + +# Low latency tests +Execute_AC_14 48_1_g +Execute_AC_14 48_2_g +Execute_AC_14 48_3_g +Execute_AC_14 48_4_g From d8c362253dab3304e54704be029a7518f8f19adc Mon Sep 17 00:00:00 2001 From: Kapil Bhatt Date: Thu, 11 Jan 2024 15:29:23 +0530 Subject: [PATCH 2102/3723] net: wifi_shell: Add example of scan option Add an example of the scan's -c parameter to help with understanding. Signed-off-by: Kapil Bhatt --- subsys/net/l2/wifi/wifi_shell.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/subsys/net/l2/wifi/wifi_shell.c b/subsys/net/l2/wifi/wifi_shell.c index 2654f0337bf..c8c3e18903e 100644 --- a/subsys/net/l2/wifi/wifi_shell.c +++ b/subsys/net/l2/wifi/wifi_shell.c @@ -1827,7 +1827,7 @@ SHELL_STATIC_SUBCMD_SET_CREATE(wifi_commands, "[-p, --dwell_time_passive ] : Passive scan dwell time (in ms) on a channel. Range 10 ms to 1000 ms\n" "[-s, --ssid] : SSID to scan for. Can be provided multiple times\n" "[-m, --max_bss ] : Maximum BSSes to scan for. Range 1 - 65535\n" - "[-c, --chans ] : Channels to be scanned. The channels must be specified in the form band1:chan1,chan2_band2:chan3,..etc. band1, band2 must be valid band values and chan1, chan2, chan3 must be specified as a list of comma separated values where each value is either a single channel or a channel range specified as chan_start-chan_end. Each band channel set has to be separated by a _. For example, a valid channel specification can be 2:1,6_5:36\n" + "[-c, --chans ] : Channels to be scanned. The channels must be specified in the form band1:chan1,chan2_band2:chan3,..etc. band1, band2 must be valid band values and chan1, chan2, chan3 must be specified as a list of comma separated values where each value is either a single channel or a channel range specified as chan_start-chan_end. Each band channel set has to be separated by a _. For example, a valid channel specification can be 2:1,6_5:36 or 2:1,6-11,14_5:36,163-177,52\n" "[-h, --help] : Print out the help for the scan command.\n", cmd_wifi_scan, 1, 8), From 55fe95a5f64be22e07bea434df24f0e470ff6920 Mon Sep 17 00:00:00 2001 From: Daniel DeGrasse Date: Wed, 10 Jan 2024 14:33:44 +0000 Subject: [PATCH 2103/3723] soc: arm: nxp_imx: enable CONFIG_CACHE_MANAGEMENT for RT1xxx M7 cores Since d992683db5 (soc: arm: replace redundant config option for caches for nxp_imx), RT1xxx series will not have cache enabled at boot unless CONFIG_CACHE_MANAGEMENT=y. Since this will improve performance, enable CONFIG_CACHE_MANAGEMENT by default. Signed-off-by: Daniel DeGrasse --- soc/arm/nxp_imx/rt/Kconfig.defconfig.series | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/soc/arm/nxp_imx/rt/Kconfig.defconfig.series b/soc/arm/nxp_imx/rt/Kconfig.defconfig.series index f8467559d37..61f537a402d 100644 --- a/soc/arm/nxp_imx/rt/Kconfig.defconfig.series +++ b/soc/arm/nxp_imx/rt/Kconfig.defconfig.series @@ -136,6 +136,11 @@ config TEST_EXTRA_STACK_SIZE default 1024 endif # MBEDTLS +# Enable cache management features when using M7 core, since these parts +# have L1 instruction and data caches that should be enabled at boot +config CACHE_MANAGEMENT + default y if CPU_CORTEX_M7 + source "soc/arm/nxp_imx/rt/Kconfig.defconfig.mimxrt*" endif # SOC_SERIES_IMX_RT From d2c6fcfd32cadcf395c56b70338f6ca473c732ff Mon Sep 17 00:00:00 2001 From: Henrik Brix Andersen Date: Thu, 4 Jan 2024 14:58:01 +0100 Subject: [PATCH 2104/3723] boards: shields: mikroe_adc_click: fix lpcxpresso55s16 overlay Remove the correct nodelabel in the overlay for the lpcxpresso55s16 board. Fixes: 07b642d94f4428fb77d1f7d55db2dc268bea531b Signed-off-by: Henrik Brix Andersen --- boards/shields/mikroe_adc_click/boards/lpcxpresso55s16.overlay | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/boards/shields/mikroe_adc_click/boards/lpcxpresso55s16.overlay b/boards/shields/mikroe_adc_click/boards/lpcxpresso55s16.overlay index 7238a5cfb8e..5cb35984f93 100644 --- a/boards/shields/mikroe_adc_click/boards/lpcxpresso55s16.overlay +++ b/boards/shields/mikroe_adc_click/boards/lpcxpresso55s16.overlay @@ -4,7 +4,7 @@ * SPDX-License-Identifier: Apache-2.0 */ -/delete-node/ &mcp3204; +/delete-node/ &mcp3204_mikroe_adc_click; &mikrobus_spi { status = "okay"; From 1798a7b5a28585ad34bfed944c0ef3d55fa7621c Mon Sep 17 00:00:00 2001 From: Henrik Brix Andersen Date: Thu, 4 Jan 2024 15:04:03 +0100 Subject: [PATCH 2105/3723] boards: shields: mikroe_adc_click: include zephyr/dt-bindings/adc/adc.h Include zephyr/dt-bindings/adc/adc.h in the shield DTS overlays to simplify using this shield in application overlays. Signed-off-by: Henrik Brix Andersen --- boards/shields/mikroe_adc_click/boards/lpcxpresso55s16.overlay | 2 ++ boards/shields/mikroe_adc_click/mikroe_adc_click.overlay | 2 ++ 2 files changed, 4 insertions(+) diff --git a/boards/shields/mikroe_adc_click/boards/lpcxpresso55s16.overlay b/boards/shields/mikroe_adc_click/boards/lpcxpresso55s16.overlay index 5cb35984f93..62f633b1a33 100644 --- a/boards/shields/mikroe_adc_click/boards/lpcxpresso55s16.overlay +++ b/boards/shields/mikroe_adc_click/boards/lpcxpresso55s16.overlay @@ -4,6 +4,8 @@ * SPDX-License-Identifier: Apache-2.0 */ +#include + /delete-node/ &mcp3204_mikroe_adc_click; &mikrobus_spi { diff --git a/boards/shields/mikroe_adc_click/mikroe_adc_click.overlay b/boards/shields/mikroe_adc_click/mikroe_adc_click.overlay index e5604daee7e..6686e9e7812 100644 --- a/boards/shields/mikroe_adc_click/mikroe_adc_click.overlay +++ b/boards/shields/mikroe_adc_click/mikroe_adc_click.overlay @@ -4,6 +4,8 @@ * SPDX-License-Identifier: Apache-2.0 */ +#include + &mikrobus_spi { status = "okay"; From 8291cc322d79113b1443fce587f50d229a83fe94 Mon Sep 17 00:00:00 2001 From: Henrik Brix Andersen Date: Thu, 4 Jan 2024 15:05:42 +0100 Subject: [PATCH 2106/3723] dts: bindings: adc: microchip: mcp320x: use common io-channel-cells name Use the common io-channel-cells name "input" instead of "channel" to make this binding work with the various ADC DT macros. Signed-off-by: Henrik Brix Andersen --- dts/bindings/adc/microchip,mcp320x-base.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/dts/bindings/adc/microchip,mcp320x-base.yaml b/dts/bindings/adc/microchip,mcp320x-base.yaml index c5d80c9a637..9bee60f1320 100644 --- a/dts/bindings/adc/microchip,mcp320x-base.yaml +++ b/dts/bindings/adc/microchip,mcp320x-base.yaml @@ -7,4 +7,4 @@ properties: const: 1 io-channel-cells: - - channel + - input From 53217b980ca91f83b409b027ffdf5c20fcceeff4 Mon Sep 17 00:00:00 2001 From: Henrik Brix Andersen Date: Sat, 6 Jan 2024 21:48:58 +0100 Subject: [PATCH 2107/3723] doc: release: migration-guide: 3.6: mention change in mcp320x bindings Mention the change in the microchip,mcp320x bindings to use the common io-channel-cells name "input" instead of "channel". Signed-off-by: Henrik Brix Andersen --- doc/releases/migration-guide-3.6.rst | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/doc/releases/migration-guide-3.6.rst b/doc/releases/migration-guide-3.6.rst index 1156cc91e77..38e819d840d 100644 --- a/doc/releases/migration-guide-3.6.rst +++ b/doc/releases/migration-guide-3.6.rst @@ -159,6 +159,10 @@ Device Drivers and Device Tree * :dtcompatible:`ti,lmp90099` * :dtcompatible:`ti,lmp90100` +* The io-channel cells of the :dtcompatible:`microchip,mcp3204` and + :dtcompatible:`microchip,mcp3208` devicetree bindings were renamed from ``channel`` to the common + ``input``, making it possible to use the various ADC DT macros with Microchip MCP320x ADC devices. + * The :dtcompatible:`st,stm32h7-fdcan` CAN controller driver now supports configuring the domain/kernel clock via devicetree. Previously, the driver only supported using the PLL1_Q clock for kernel clock, but now it defaults to the HSE clock, which is the chip default. Boards that From 1b0ea02ffb16d3ff5c440672b574fb374ab4457e Mon Sep 17 00:00:00 2001 From: Henrik Brix Andersen Date: Thu, 4 Jan 2024 14:59:16 +0100 Subject: [PATCH 2108/3723] boards: shields: mikroe_adc_click: use board with mikroBUS as example Use a board with a mikroBUS as example in the shield documentation and update the example application since the board_shell sample was removed in commit 7c85f4b2f5bea25a3c34a8f81ef6590639629434. Fixes: #67134 Signed-off-by: Henrik Brix Andersen --- boards/shields/mikroe_adc_click/doc/index.rst | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/boards/shields/mikroe_adc_click/doc/index.rst b/boards/shields/mikroe_adc_click/doc/index.rst index 41656ab2e36..8157863d7d4 100644 --- a/boards/shields/mikroe_adc_click/doc/index.rst +++ b/boards/shields/mikroe_adc_click/doc/index.rst @@ -35,8 +35,8 @@ Set ``-DSHIELD=mikro_adc_click`` when you invoke ``west build``. For example: .. zephyr-app-commands:: - :zephyr-app: test/boards/board_shell - :board: frdm_k64f + :zephyr-app: + :board: lpcxpresso55s16 :shield: mikroe_adc_click :goals: build From b7854c08bede5efc659863b2f585518431a67c4c Mon Sep 17 00:00:00 2001 From: Henrik Brix Andersen Date: Thu, 4 Jan 2024 15:13:29 +0100 Subject: [PATCH 2109/3723] tests: drivers: build_all: adc: add build test for the mcp320x driver Add build-only test of the mcp320x ADC driver. Signed-off-by: Henrik Brix Andersen --- tests/drivers/build_all/adc/testcase.yaml | 3 +++ 1 file changed, 3 insertions(+) diff --git a/tests/drivers/build_all/adc/testcase.yaml b/tests/drivers/build_all/adc/testcase.yaml index 3b8995e1769..0d2df1769ea 100644 --- a/tests/drivers/build_all/adc/testcase.yaml +++ b/tests/drivers/build_all/adc/testcase.yaml @@ -20,6 +20,9 @@ tests: platform_allow: frdm_k22f drivers.adc.mcux.lpadc.build: platform_allow: lpcxpresso55s28 + drivers.adc.mcp320x.build: + platform_allow: lpcxpresso55s16 + extra_args: SHIELD=mikroe_adc_click drivers.adc.npcx.build: platform_allow: npcx7m6fb_evb drivers.adc.nrf.build: From 7557756b86c0dd666c50e1fc40c0a31d491e7b98 Mon Sep 17 00:00:00 2001 From: Jordan Yates Date: Sat, 11 Nov 2023 11:41:45 +1000 Subject: [PATCH 2110/3723] scripts: twister: testplan: search for requested snippets Search for the snippets requested by the test, not for snippets found in the snippet roots. Signed-off-by: Jordan Yates --- scripts/pylib/twister/twisterlib/testplan.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/scripts/pylib/twister/twisterlib/testplan.py b/scripts/pylib/twister/twisterlib/testplan.py index 3202d5d483a..e813f031ee8 100755 --- a/scripts/pylib/twister/twisterlib/testplan.py +++ b/scripts/pylib/twister/twisterlib/testplan.py @@ -820,7 +820,7 @@ def apply_filters(self, **kwargs): if not missing_snippet: # Look for required snippets and check that they are applicable for these # platforms/boards - for this_snippet in found_snippets: + for this_snippet in snippet_args['snippets']: matched_snippet_board = False # If the "appends" key is present with at least one entry then this From 30c660162f5fe70606bd122b61818ace47e6d908 Mon Sep 17 00:00:00 2001 From: Alberto Escolar Piedras Date: Thu, 11 Jan 2024 13:30:30 +0100 Subject: [PATCH 2111/3723] tests/kernel/context: Fix for nrf5340bsim_nrf5340_cpunet This test assumes nothing else is running in the background but when the logger is on, this board will by default start the RTC sync mechanism, which will awake the CPU every now and then. Let's disable this mechanism to avoid disturbing the test. Signed-off-by: Alberto Escolar Piedras --- tests/kernel/context/boards/nrf5340bsim_nrf5340_cpunet.conf | 1 + 1 file changed, 1 insertion(+) create mode 100644 tests/kernel/context/boards/nrf5340bsim_nrf5340_cpunet.conf diff --git a/tests/kernel/context/boards/nrf5340bsim_nrf5340_cpunet.conf b/tests/kernel/context/boards/nrf5340bsim_nrf5340_cpunet.conf new file mode 100644 index 00000000000..e09415f38f7 --- /dev/null +++ b/tests/kernel/context/boards/nrf5340bsim_nrf5340_cpunet.conf @@ -0,0 +1 @@ +CONFIG_NRF53_SYNC_RTC=n From c2f0a7a5a37dab5f5a42550e5a2b66dca987905e Mon Sep 17 00:00:00 2001 From: David Leach Date: Tue, 9 Jan 2024 12:54:49 -0600 Subject: [PATCH 2112/3723] maintainers: Split up NXP maintainer group Split the NXP maintainer group into NXP S32, NXP Xtensa, and NXP. Signed-off-by: David Leach --- MAINTAINERS.yml | 50 ++++++++++++++++++++++++++++++++++++------------- 1 file changed, 37 insertions(+), 13 deletions(-) diff --git a/MAINTAINERS.yml b/MAINTAINERS.yml index a2098e0452e..6a9c1eef3b7 100644 --- a/MAINTAINERS.yml +++ b/MAINTAINERS.yml @@ -3168,6 +3168,28 @@ Intel Platforms (Agilex): labels: - "platform: Intel SoC FPGA Agilex" +NXP Platforms (S32): + status: maintained + maintainers: + - manuargue + collaborators: + - PetervdPerk-NXP + - bperseghetti + - Dat-NguyenDuy + files: + - boards/arm/s32*/ + - boards/arm/mr_canhubk3/ + - boards/arm/ucans32k1sic/ + - soc/arm/nxp_s32/ + - drivers/*/*nxp_s32* + - dts/bindings/*/nxp,s32* + - samples/boards/nxp_s32/ + - include/zephyr/dt-bindings/*/nxp-s32* + - include/zephyr/dt-bindings/*/nxp_s32* + - include/zephyr/drivers/*/*nxp_s32* + labels: + - "platform: NXP S32" + NXP Platforms: status: maintained maintainers: @@ -3179,21 +3201,14 @@ NXP Platforms: - yvanderv - EmilioCBen - decsny - - manuargue - - PetervdPerk-NXP - - bperseghetti - - dbaluta - - iuliana-prodan - - Dat-NguyenDuy files: - boards/arm/mimx*/ - boards/arm/frdm_k*/ - boards/arm/lpcxpress*/ - boards/arm/twr_*/ - - boards/arm/s32*/ - - boards/arm/mr_canhubk3/ - - boards/arm/vmu_rt*/ - - soc/arm/nxp_*/ + - soc/arm/nxp_imx/ + - soc/arm/nxp_kinetis/ + - soc/arm/nxp_lpc/ - drivers/*/*imx* - drivers/*/*lpc*.c - drivers/*/*mcux*.c @@ -3202,14 +3217,23 @@ NXP Platforms: - drivers/*/*nxp* - dts/arm/nxp/ - dts/bindings/*/nxp* - - soc/xtensa/nxp_adsp/ - - boards/xtensa/nxp_adsp_*/ - samples/boards/nxp*/ - include/zephyr/dt-bindings/*/nxp* - - include/zephyr/drivers/*/*nxp* labels: - "platform: NXP" +NXP Platforms (Xtensa): + status: maintained + maintainers: + - dbaluta + collaborators: + - iuliana-prodan + files: + - soc/xtensa/nxp_adsp/ + - boards/xtensa/nxp_adsp_*/ + labels: + - "platform: NXP ADSP" + Microchip MEC Platforms: status: maintained maintainers: From f32e68651133960f257f7505ac7fac7f46986252 Mon Sep 17 00:00:00 2001 From: Maciej Baczmanski Date: Wed, 10 Jan 2024 13:03:21 +0100 Subject: [PATCH 2113/3723] net: openthread: implement `otPlatResetToBootloader` This commit implements `otPlatResetToBootloader` in two ways: - trigger reset to bootloader using boot mode retention API - trigger reset to bootloader by triggering GPIO pin (applicable for nRF52840 Dongle) Signed-off-by: Maciej Baczmanski --- dts/bindings/options/openthread,config.yaml | 7 +++ modules/openthread/CMakeLists.txt | 1 + modules/openthread/Kconfig.features | 23 ++++++- modules/openthread/platform/misc.c | 66 +++++++++++++++++++++ 4 files changed, 95 insertions(+), 2 deletions(-) diff --git a/dts/bindings/options/openthread,config.yaml b/dts/bindings/options/openthread,config.yaml index 054107fab44..6366c289c80 100644 --- a/dts/bindings/options/openthread,config.yaml +++ b/dts/bindings/options/openthread,config.yaml @@ -10,6 +10,7 @@ description: | compatible = "openthread,config"; diag-gpios = <&gpio0 0 GPIO_ACTIVE_HIGH>, <&gpio1 0 GPIO_ACTIVE_LOW>; + bootloader-gpios = <&gpio0 1 GPIO_ACTIVE_HIGH>; }; }; @@ -21,3 +22,9 @@ properties: description: | This enables access to diagnostic GPIO pins. Each field consists of GPIO pin's configuration: controller's phandle, pin number and configuration flags. + + bootloader-gpios: + type: phandle-array + description: | + This enables resetting to bootloader by triggering given GPIO pin. Property represents + chosen GPIO pin's configuration: controller's phandle, pin number and configuration flags. diff --git a/modules/openthread/CMakeLists.txt b/modules/openthread/CMakeLists.txt index c9ccf074649..5b64d3be2f5 100644 --- a/modules/openthread/CMakeLists.txt +++ b/modules/openthread/CMakeLists.txt @@ -99,6 +99,7 @@ kconfig_to_ot_option(CONFIG_OPENTHREAD_NETDATA_PUBLISHER OT_NETDATA_PUBLISHER "E kconfig_to_ot_option(CONFIG_OPENTHREAD_OPERATIONAL_DATASET_AUTO_INIT OT_OPERATIONAL_DATASET_AUTO_INIT "Enable operational dataset auto init") kconfig_to_ot_option(CONFIG_OPENTHREAD_OTNS OT_OTNS "Enable OTNS support") kconfig_to_ot_option(CONFIG_OPENTHREAD_PING_SENDER OT_PING_SENDER "Enable ping sender support") +kconfig_to_ot_option(CONFIG_OPENTHREAD_PLATFORM_BOOTLOADER_MODE OT_PLATFORM_BOOTLOADER_MODE "Enable platform bootloader mode support") kconfig_to_ot_option(CONFIG_OPENTHREAD_PLATFORM_KEY_REF OT_PLATFORM_KEY_REF "Enable platform key reference support") kconfig_to_ot_option(CONFIG_OPENTHREAD_PLATFORM_NETIF OT_PLATFORM_NETIF "Enable platform netif support") kconfig_to_ot_option(CONFIG_OPENTHREAD_PLATFORM_UDP OT_PLATFORM_UDP "Enable platform UDP support") diff --git a/modules/openthread/Kconfig.features b/modules/openthread/Kconfig.features index 952a7853b43..ba3990a348d 100644 --- a/modules/openthread/Kconfig.features +++ b/modules/openthread/Kconfig.features @@ -17,7 +17,7 @@ config OPENTHREAD_THREAD_VERSION_1_3 bool "Version 1.3" config OPENTHREAD_THREAD_VERSION_1_3_1 bool "Version 1.3.1" -endchoice +endchoice # OPENTHREAD_STACK_VERSION config OPENTHREAD_THREAD_VERSION string @@ -255,6 +255,25 @@ config OPENTHREAD_PLATFORM_KEY_REF Enable usage of cryptographic key references instead of literal keys. This requires a crypto backend library that supports key references. +choice OPENTHREAD_PLATFORM_BOOTLOADER_MODE_CHOICE + prompt "Platform bootloader mode configuration" + optional + +config OPENTHREAD_PLATFORM_BOOTLOADER_MODE_RETENTION + bool "Bootloader mode support with boot mode retention API" + depends on RETENTION_BOOT_MODE && REBOOT + select OPENTHREAD_PLATFORM_BOOTLOADER_MODE + +config OPENTHREAD_PLATFORM_BOOTLOADER_MODE_GPIO + bool "Bootloader mode support with GPIO pin trigger" + select OPENTHREAD_PLATFORM_BOOTLOADER_MODE +endchoice # OPENTHREAD_PLATFORM_BOOTLOADER_MODE + +config OPENTHREAD_PLATFORM_BOOTLOADER_MODE + bool + help + Platform bootloader mode support + config OPENTHREAD_PLATFORM_NETIF bool "Platform netif support" @@ -276,7 +295,7 @@ config OPENTHREAD_POWER_SUPPLY_EXTERNAL_STABLE config OPENTHREAD_POWER_SUPPLY_EXTERNAL_UNSTABLE bool "OT_POWER_SUPPLY_EXTERNAL_UNSTABLE" -endchoice +endchoice # OPENTHREAD_POWER_SUPPLY_CHOICE config OPENTHREAD_POWER_SUPPLY string diff --git a/modules/openthread/platform/misc.c b/modules/openthread/platform/misc.c index 7f57dddb9e3..11fdc42ec34 100644 --- a/modules/openthread/platform/misc.c +++ b/modules/openthread/platform/misc.c @@ -9,6 +9,24 @@ #include #include +#if defined(CONFIG_OPENTHREAD_PLATFORM_BOOTLOADER_MODE_RETENTION) + +#include + +#elif defined(CONFIG_OPENTHREAD_PLATFORM_BOOTLOADER_MODE_GPIO) + +BUILD_ASSERT(DT_HAS_COMPAT_STATUS_OKAY(openthread_config), + "`openthread,config` compatible node not found"); +BUILD_ASSERT(DT_NODE_HAS_PROP(DT_COMPAT_GET_ANY_STATUS_OKAY(openthread_config), bootloader_gpios), + "`bootloader-gpios` property missing from `openthread,config` compatible node"); + +#include + +static const struct gpio_dt_spec bootloader_gpio = + GPIO_DT_SPEC_GET(DT_COMPAT_GET_ANY_STATUS_OKAY(openthread_config), + bootloader_gpios); +#endif + #include "platform-zephyr.h" void otPlatReset(otInstance *aInstance) @@ -19,6 +37,54 @@ void otPlatReset(otInstance *aInstance) sys_reboot(SYS_REBOOT_WARM); } +#if defined(CONFIG_OPENTHREAD_PLATFORM_BOOTLOADER_MODE) +otError otPlatResetToBootloader(otInstance *aInstance) +{ + OT_UNUSED_VARIABLE(aInstance); + +#if defined(CONFIG_OPENTHREAD_PLATFORM_BOOTLOADER_MODE_RETENTION) + if (bootmode_set(BOOT_MODE_TYPE_BOOTLOADER)) { + return OT_ERROR_NOT_CAPABLE; + } + sys_reboot(SYS_REBOOT_WARM); + +#elif defined(CONFIG_OPENTHREAD_PLATFORM_BOOTLOADER_MODE_GPIO) + /* + * To enable resetting to bootloader by triggering gpio pin, + * select `CONFIG_OPENTHREAD_PLATFORM_BOOTLOADER_MODE_GPIO=y`, + * and in Devicetree create `openthread` node in `/options/` path with + * `compatible = "openthread,config"` property and `bootloader-gpios` property, + * which should represent GPIO pin's configuration, + * containing controller phandle, pin number and pin flags. e.g: + * + * options { + * openthread { + * compatible = "openthread,config"; + * bootloader-gpios = <&gpio0 0 GPIO_ACTIVE_HIGH>; + * }; + * }; + * + * Note: in below implementation, chosen GPIO pin is configured as output + * and initialized to active state (logical value ‘1’). + * Configuring pin flags in `bootloader-gpios` allows to choose + * if pin should be active in high or in low state. + */ + + if (!gpio_is_ready_dt(&bootloader_gpio)) { + return OT_ERROR_NOT_CAPABLE; + } + gpio_pin_configure_dt(&bootloader_gpio, GPIO_OUTPUT_ACTIVE); + +#endif + + /* + * Return OT_ERROR_NOT_CAPABLE if resetting has been unsuccessful (invalid configuration or + * triggering reset had no effect) + */ + return OT_ERROR_NOT_CAPABLE; +} +#endif /* defined(CONFIG_OPENTHREAD_PLATFORM_BOOTLOADER_MODE) */ + otPlatResetReason otPlatGetResetReason(otInstance *aInstance) { ARG_UNUSED(aInstance); From 2ce295b71e396f5305d39d819ada2fb179128748 Mon Sep 17 00:00:00 2001 From: Chaitanya Tata Date: Wed, 10 Jan 2024 23:12:39 +0530 Subject: [PATCH 2114/3723] wifi: shell: Fix missing case sensitivity This was missed in earlier that tried to fix all string comparisons to use case insensitive comparison. Signed-off-by: Chaitanya Tata --- subsys/net/l2/wifi/wifi_shell.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/subsys/net/l2/wifi/wifi_shell.c b/subsys/net/l2/wifi/wifi_shell.c index c8c3e18903e..44f72ca13fe 100644 --- a/subsys/net/l2/wifi/wifi_shell.c +++ b/subsys/net/l2/wifi/wifi_shell.c @@ -600,9 +600,9 @@ static int wifi_scan_args_to_params(const struct shell *sh, state = getopt_state_get(); switch (opt) { case 't': - if (!strcmp(optarg, "passive")) { + if (!strncasecmp(optarg, "passive", 7)) { params->scan_type = WIFI_SCAN_TYPE_PASSIVE; - } else if (!strcmp(optarg, "active")) { + } else if (!strncasecmp(optarg, "active", 6)) { params->scan_type = WIFI_SCAN_TYPE_ACTIVE; } else { shell_fprintf(sh, SHELL_ERROR, "Invalid scan type %s\n", optarg); From c8c91c7ba51cc025b5f4098e4f8e0741379e0177 Mon Sep 17 00:00:00 2001 From: Sateesh Kotapati Date: Wed, 10 Jan 2024 11:04:16 +0530 Subject: [PATCH 2115/3723] gecko: emlib files updated | Update to GSDK 4.4.0 Updated the files present in gecko/emlib folder and gecko/common folder in Silabs HAL. Signed-off-by: Sateesh Kotapati --- west.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/west.yml b/west.yml index e8feaa2938a..64433b970d2 100644 --- a/west.yml +++ b/west.yml @@ -219,7 +219,7 @@ manifest: groups: - hal - name: hal_silabs - revision: e670e749760e7a77a75c69f2c932b345cc0e212f + revision: 4cfb0e3e363678dd96e19a5ea4eede771d0e3b1d path: modules/hal/silabs groups: - hal From 0018204091d104bda853ef870aaff8a1bc0e201c Mon Sep 17 00:00:00 2001 From: Przemyslaw Bida Date: Wed, 10 Jan 2024 15:34:16 +0100 Subject: [PATCH 2116/3723] net: openthread: Add new key and algorithm in PSA. This commit adds new types of keys and algorithm to crypto_psa backend of openthread. Added options: - `OT_CRYPTO_KEY_TYPE_ECDSA` - `OT_CRYPTO_KEY_ALG_ECDSA` - `OT_CRYPTO_KEY_USAGE_VERIFY_HASH` Signed-off-by: Przemyslaw Bida --- modules/openthread/platform/crypto_psa.c | 15 ++++++++++++--- 1 file changed, 12 insertions(+), 3 deletions(-) diff --git a/modules/openthread/platform/crypto_psa.c b/modules/openthread/platform/crypto_psa.c index e5b234ce030..0dcf3803fde 100644 --- a/modules/openthread/platform/crypto_psa.c +++ b/modules/openthread/platform/crypto_psa.c @@ -41,6 +41,8 @@ static psa_key_type_t toPsaKeyType(otCryptoKeyType aType) return PSA_KEY_TYPE_AES; case OT_CRYPTO_KEY_TYPE_HMAC: return PSA_KEY_TYPE_HMAC; + case OT_CRYPTO_KEY_TYPE_ECDSA: + return PSA_KEY_TYPE_ECC_KEY_PAIR(PSA_ECC_FAMILY_SECP_R1); default: return PSA_KEY_TYPE_NONE; } @@ -53,6 +55,8 @@ static psa_algorithm_t toPsaAlgorithm(otCryptoKeyAlgorithm aAlgorithm) return PSA_ALG_ECB_NO_PADDING; case OT_CRYPTO_KEY_ALG_HMAC_SHA_256: return PSA_ALG_HMAC(PSA_ALG_SHA_256); + case OT_CRYPTO_KEY_ALG_ECDSA: + return PSA_ALG_DETERMINISTIC_ECDSA(PSA_ALG_SHA_256); default: /* * There is currently no constant like PSA_ALG_NONE, but 0 is used @@ -82,6 +86,10 @@ static psa_key_usage_t toPsaKeyUsage(int aUsage) usage |= PSA_KEY_USAGE_SIGN_HASH; } + if (aUsage & OT_CRYPTO_KEY_USAGE_VERIFY_HASH) { + usage |= PSA_KEY_USAGE_VERIFY_HASH; + } + return usage; } @@ -89,9 +97,10 @@ static bool checkKeyUsage(int aUsage) { /* Check if only supported flags have been passed */ int supported_flags = OT_CRYPTO_KEY_USAGE_EXPORT | - OT_CRYPTO_KEY_USAGE_ENCRYPT | - OT_CRYPTO_KEY_USAGE_DECRYPT | - OT_CRYPTO_KEY_USAGE_SIGN_HASH; + OT_CRYPTO_KEY_USAGE_ENCRYPT | + OT_CRYPTO_KEY_USAGE_DECRYPT | + OT_CRYPTO_KEY_USAGE_SIGN_HASH | + OT_CRYPTO_KEY_USAGE_VERIFY_HASH; return (aUsage & ~supported_flags) == 0; } From 0e87de0a10934e62418eb29232efed7f24821c63 Mon Sep 17 00:00:00 2001 From: Anisetti Avinash Krishna Date: Wed, 10 Jan 2024 21:30:15 +0530 Subject: [PATCH 2117/3723] dts: x86: intel: alder_lake: Added UARTs DMA instances Added UARTs DMA instances to enable Async operations on ADL platform Signed-off-by: Anisetti Avinash Krishna --- boards/x86/intel_adl/Kconfig.defconfig | 12 ++++++++++++ boards/x86/intel_adl/intel_adl_crb.dts | 4 ---- dts/x86/intel/alder_lake.dtsi | 16 ++++++++++++++++ 3 files changed, 28 insertions(+), 4 deletions(-) diff --git a/boards/x86/intel_adl/Kconfig.defconfig b/boards/x86/intel_adl/Kconfig.defconfig index 597f6c566f4..6211c525030 100644 --- a/boards/x86/intel_adl/Kconfig.defconfig +++ b/boards/x86/intel_adl/Kconfig.defconfig @@ -46,4 +46,16 @@ config SHELL_STACK_SIZE endif # SHELL endif # ACPI +if DMA +config DMA_64BIT + default y +config DMA_DW_HW_LLI + default n +config DMA_DW_CHANNEL_COUNT + default 2 +endif + +config UART_NS16550_INTEL_LPSS_DMA + default y + endif # BOARD_INTEL_ADL_CRB || BOARD_INTEL_ADL_RVP || BOARD_UP_SQUARED_PRO_7000 diff --git a/boards/x86/intel_adl/intel_adl_crb.dts b/boards/x86/intel_adl/intel_adl_crb.dts index 7a5f8b9d6e0..e78b92aff4d 100644 --- a/boards/x86/intel_adl/intel_adl_crb.dts +++ b/boards/x86/intel_adl/intel_adl_crb.dts @@ -23,7 +23,3 @@ &uart0 { status = "okay"; }; - -&uart1 { - status = "okay"; -}; diff --git a/dts/x86/intel/alder_lake.dtsi b/dts/x86/intel/alder_lake.dtsi index 3bc21994ffe..973e95db153 100644 --- a/dts/x86/intel/alder_lake.dtsi +++ b/dts/x86/intel/alder_lake.dtsi @@ -78,6 +78,12 @@ status = "disabled"; }; + uart1_dma: uart1_dma { + compatible = "intel,lpss"; + #dma-cells = <1>; + status = "disabled"; + }; + uart1: uart1 { compatible = "ns16550"; vendor-id = <0x8086>; @@ -87,6 +93,14 @@ reg-shift = <2>; interrupts = ; interrupt-parent = <&intc>; + dmas = <&uart1_dma 0>, <&uart1_dma 1>; + dma-names = "tx", "rx"; + status = "disabled"; + }; + + uart2_dma: uart2_dma { + compatible = "intel,lpss"; + #dma-cells = <1>; status = "disabled"; }; @@ -99,6 +113,8 @@ reg-shift = <2>; interrupts = ; interrupt-parent = <&intc>; + dmas = <&uart2_dma 0>, <&uart2_dma 1>; + dma-names = "tx", "rx"; status = "disabled"; }; From 62c8b066c0b42a581213d9e31619d5db921fbaf9 Mon Sep 17 00:00:00 2001 From: Anisetti Avinash Krishna Date: Wed, 10 Jan 2024 21:32:23 +0530 Subject: [PATCH 2118/3723] tests: drivers: uart: uart_async_api: Enable test for adl_crb Enable uart_async_api test for ADL_CRB Signed-off-by: Anisetti Avinash Krishna --- .../uart/uart_async_api/boards/intel_adl_crb.conf | 1 + .../uart_async_api/boards/intel_adl_crb.overlay | 13 +++++++++++++ 2 files changed, 14 insertions(+) create mode 100644 tests/drivers/uart/uart_async_api/boards/intel_adl_crb.conf create mode 100644 tests/drivers/uart/uart_async_api/boards/intel_adl_crb.overlay diff --git a/tests/drivers/uart/uart_async_api/boards/intel_adl_crb.conf b/tests/drivers/uart/uart_async_api/boards/intel_adl_crb.conf new file mode 100644 index 00000000000..86df0aff3e6 --- /dev/null +++ b/tests/drivers/uart/uart_async_api/boards/intel_adl_crb.conf @@ -0,0 +1 @@ +CONFIG_UART_INTERRUPT_DRIVEN=y diff --git a/tests/drivers/uart/uart_async_api/boards/intel_adl_crb.overlay b/tests/drivers/uart/uart_async_api/boards/intel_adl_crb.overlay new file mode 100644 index 00000000000..b78b7d61070 --- /dev/null +++ b/tests/drivers/uart/uart_async_api/boards/intel_adl_crb.overlay @@ -0,0 +1,13 @@ +/* + * Copyright (c) 2024 Intel Corporation + * + * SPDX-License-Identifier: Apache-2.0 + */ + +dut: &uart2 { + status = "okay"; +}; + +&uart2_dma { + status = "okay"; +}; From 3053484dcb646066fe738050d9d5e4c314f1235f Mon Sep 17 00:00:00 2001 From: Ajay Parida Date: Thu, 11 Jan 2024 12:36:15 +0530 Subject: [PATCH 2119/3723] net: mgmt: Update app of TWT teardown status Update user/app status of TWT teardown sessions. Signed-off-by: Ajay Parida --- include/zephyr/net/wifi.h | 8 ++++++++ include/zephyr/net/wifi_mgmt.h | 2 ++ subsys/net/l2/wifi/wifi_shell.c | 9 +++++++-- 3 files changed, 17 insertions(+), 2 deletions(-) diff --git a/include/zephyr/net/wifi.h b/include/zephyr/net/wifi.h index be12a0961f6..0f19d7c4c18 100644 --- a/include/zephyr/net/wifi.h +++ b/include/zephyr/net/wifi.h @@ -345,6 +345,14 @@ enum wifi_twt_fail_reason { WIFI_TWT_FAIL_FLOW_ALREADY_EXISTS, }; +/** Wi-Fi Target Wake Time (TWT) teradown status. */ +enum wifi_twt_teardown_status { + /** TWT teardown success */ + WIFI_TWT_TEARDOWN_SUCCESS = 0, + /** TWT teardown failure */ + WIFI_TWT_TEARDOWN_FAILED, +}; + /** @cond INTERNAL_HIDDEN */ static const char * const wifi_twt_err_code_tbl[] = { [WIFI_TWT_FAIL_UNSPECIFIED] = "Unspecified", diff --git a/include/zephyr/net/wifi_mgmt.h b/include/zephyr/net/wifi_mgmt.h index 78800f451e7..8fb35647c36 100644 --- a/include/zephyr/net/wifi_mgmt.h +++ b/include/zephyr/net/wifi_mgmt.h @@ -470,6 +470,8 @@ struct wifi_twt_params { enum wifi_twt_setup_cmd setup_cmd; /** TWT setup response status, see enum wifi_twt_setup_resp_status */ enum wifi_twt_setup_resp_status resp_status; + /** TWT teardown cmd status, see enum wifi_twt_teardown_status */ + enum wifi_twt_teardown_status teardown_status; /** Dialog token, used to map requests to responses */ uint8_t dialog_token; /** Flow ID, used to map setup with teardown */ diff --git a/subsys/net/l2/wifi/wifi_shell.c b/subsys/net/l2/wifi/wifi_shell.c index 44f72ca13fe..b05e5cd27b8 100644 --- a/subsys/net/l2/wifi/wifi_shell.c +++ b/subsys/net/l2/wifi/wifi_shell.c @@ -290,8 +290,13 @@ static void handle_wifi_twt_event(struct net_mgmt_event_callback *cb) (const struct wifi_twt_params *)cb->info; if (resp->operation == WIFI_TWT_TEARDOWN) { - print(context.sh, SHELL_NORMAL, "TWT teardown received for flow ID %d\n", - resp->flow_id); + if (resp->teardown_status == WIFI_TWT_TEARDOWN_SUCCESS) { + print(context.sh, SHELL_NORMAL, "TWT teardown received for flow ID %d\n", + resp->flow_id); + } else { + print(context.sh, SHELL_NORMAL, "TWT teardown failed for flow ID %d\n", + resp->flow_id); + } return; } From 0d7d39d441724bb99829c1c06071c5309db04627 Mon Sep 17 00:00:00 2001 From: Anas Nashif Date: Wed, 10 Jan 2024 14:10:13 -0500 Subject: [PATCH 2120/3723] scripts: set_maintainer: do not re-add self-removed reviewers If a collaborator removes themselves from the reviewer list, do not attempt to re-add them on changes to the PR. Fixes #67214 Signed-off-by: Anas Nashif --- scripts/set_assignees.py | 21 ++++++++++++++------- 1 file changed, 14 insertions(+), 7 deletions(-) diff --git a/scripts/set_assignees.py b/scripts/set_assignees.py index 269bde82f54..ced5900fad6 100755 --- a/scripts/set_assignees.py +++ b/scripts/set_assignees.py @@ -78,7 +78,7 @@ def process_pr(gh, maintainer_file, number): # one liner PRs should be trivial if pr.commits == 1 and (pr.additions <= 1 and pr.deletions <= 1) and not manifest_change: - labels = {'trivial'} + labels = {'Trivial'} if len(fn) > 500: log(f"Too many files changed ({len(fn)}), skipping....") @@ -181,14 +181,21 @@ def process_pr(gh, maintainer_file, number): existing_reviewers |= set(r.get_page(page)) page += 1 - for c in collab: + # check for reviewers that remove themselves from list of reviewer and + # do not attempt to add them again based on MAINTAINERS file. + self_removal = [] + for event in pr.get_issue_events(): + if event.event == 'review_request_removed' and event.actor == event.requested_reviewer: + self_removal.append(event.actor) + + for collaborator in collab: try: - u = gh.get_user(c) - if pr.user != u and gh_repo.has_in_collaborators(u): - if u not in existing_reviewers: - reviewers.append(c) + gh_user = gh.get_user(collaborator) + if pr.user != gh_user and gh_repo.has_in_collaborators(gh_user): + if gh_user not in existing_reviewers and gh_user not in self_removal: + reviewers.append(collaborator) except UnknownObjectException as e: - log(f"Can't get user '{c}', account does not exist anymore? ({e})") + log(f"Can't get user '{collaborator}', account does not exist anymore? ({e})") if len(existing_reviewers) < 15: reviewer_vacancy = 15 - len(existing_reviewers) From 206e1d5b0eb55f6faa36323be56079bf2e594cc6 Mon Sep 17 00:00:00 2001 From: Daniel Leung Date: Mon, 9 Oct 2023 12:50:39 -0700 Subject: [PATCH 2121/3723] sys: atomic: move doxygen doc to atomic.h This moves the doxygen doc from atomic_builtin.h to atomic.h, as the doc should not have been inside a particular implementation. Also add an alias @atomic_api to replace the repetitive wordings in the doc. Signed-off-by: Daniel Leung --- doc/zephyr.doxyfile.in | 1 + include/zephyr/sys/atomic.h | 251 ++++++++++++++++++++++++++-- include/zephyr/sys/atomic_builtin.h | 239 -------------------------- 3 files changed, 240 insertions(+), 251 deletions(-) diff --git a/doc/zephyr.doxyfile.in b/doc/zephyr.doxyfile.in index 1f8a6af46c4..493e56dd198 100644 --- a/doc/zephyr.doxyfile.in +++ b/doc/zephyr.doxyfile.in @@ -286,6 +286,7 @@ ALIASES = "rst=\verbatim embed:rst:leading-asterisk" \ "isr_ok=\htmlonly isr-ok \endhtmlonly \xmlonly embed:rst:inline :ref:`api_term_isr-ok` \endxmlonly" \ "pre_kernel_ok=\htmlonly pre-kernel-ok \endhtmlonly \xmlonly embed:rst:inline :ref:`api_term_pre-kernel-ok` \endxmlonly" \ "async=\htmlonly async \endhtmlonly \xmlonly embed:rst:inline :ref:`api_term_async` \endxmlonly" \ + "atomic_api=As for all atomic APIs, includes a full/sequentially-consistent memory barrier (where applicable)." \ "supervisor=\htmlonly supervisor \endhtmlonly \xmlonly embed:rst:inline :ref:`api_term_supervisor` \endxmlonly" # Set the OPTIMIZE_OUTPUT_FOR_C tag to YES if your project consists of C sources diff --git a/include/zephyr/sys/atomic.h b/include/zephyr/sys/atomic.h index 266f6b1391b..3982e428038 100644 --- a/include/zephyr/sys/atomic.h +++ b/include/zephyr/sys/atomic.h @@ -117,8 +117,7 @@ extern "C" { * This routine tests whether bit number @a bit of @a target is set or not. * The target may be a single atomic variable or an array of them. * - * @note As for all atomic APIs, includes a - * full/sequentially-consistent memory barrier (where applicable). + * @note @atomic_api * * @param target Address of atomic variable or array. * @param bit Bit number (starting from 0). @@ -138,8 +137,7 @@ static inline bool atomic_test_bit(const atomic_t *target, int bit) * Atomically clear bit number @a bit of @a target and return its old value. * The target may be a single atomic variable or an array of them. * - * @note As for all atomic APIs, includes a - * full/sequentially-consistent memory barrier (where applicable). + * @note @atomic_api * * @param target Address of atomic variable or array. * @param bit Bit number (starting from 0). @@ -162,8 +160,7 @@ static inline bool atomic_test_and_clear_bit(atomic_t *target, int bit) * Atomically set bit number @a bit of @a target and return its old value. * The target may be a single atomic variable or an array of them. * - * @note As for all atomic APIs, includes a - * full/sequentially-consistent memory barrier (where applicable). + * @note @atomic_api * * @param target Address of atomic variable or array. * @param bit Bit number (starting from 0). @@ -186,8 +183,7 @@ static inline bool atomic_test_and_set_bit(atomic_t *target, int bit) * Atomically clear bit number @a bit of @a target. * The target may be a single atomic variable or an array of them. * - * @note As for all atomic APIs, includes a - * full/sequentially-consistent memory barrier (where applicable). + * @note @atomic_api * * @param target Address of atomic variable or array. * @param bit Bit number (starting from 0). @@ -205,8 +201,7 @@ static inline void atomic_clear_bit(atomic_t *target, int bit) * Atomically set bit number @a bit of @a target. * The target may be a single atomic variable or an array of them. * - * @note As for all atomic APIs, includes a - * full/sequentially-consistent memory barrier (where applicable). + * @note @atomic_api * * @param target Address of atomic variable or array. * @param bit Bit number (starting from 0). @@ -224,8 +219,7 @@ static inline void atomic_set_bit(atomic_t *target, int bit) * Atomically set bit number @a bit of @a target to value @a val. * The target may be a single atomic variable or an array of them. * - * @note As for all atomic APIs, includes a - * full/sequentially-consistent memory barrier (where applicable). + * @note @atomic_api * * @param target Address of atomic variable or array. * @param bit Bit number (starting from 0). @@ -242,6 +236,239 @@ static inline void atomic_set_bit_to(atomic_t *target, int bit, bool val) } } +/** + * @brief Atomic compare-and-set. + * + * This routine performs an atomic compare-and-set on @a target. If the current + * value of @a target equals @a old_value, @a target is set to @a new_value. + * If the current value of @a target does not equal @a old_value, @a target + * is left unchanged. + * + * @note @atomic_api + * + * @param target Address of atomic variable. + * @param old_value Original value to compare against. + * @param new_value New value to store. + * @return true if @a new_value is written, false otherwise. + */ +bool atomic_cas(atomic_t *target, atomic_val_t old_value, atomic_val_t new_value); + +/** + * @brief Atomic compare-and-set with pointer values + * + * This routine performs an atomic compare-and-set on @a target. If the current + * value of @a target equals @a old_value, @a target is set to @a new_value. + * If the current value of @a target does not equal @a old_value, @a target + * is left unchanged. + * + * @note @atomic_api + * + * @param target Address of atomic variable. + * @param old_value Original value to compare against. + * @param new_value New value to store. + * @return true if @a new_value is written, false otherwise. + */ +bool atomic_ptr_cas(atomic_ptr_t *target, atomic_ptr_val_t old_value, + atomic_ptr_val_t new_value); + +/** + * @brief Atomic addition. + * + * This routine performs an atomic addition on @a target. + * + * @note @atomic_api + * + * @param target Address of atomic variable. + * @param value Value to add. + * + * @return Previous value of @a target. + */ +atomic_val_t atomic_add(atomic_t *target, atomic_val_t value); + +/** + * @brief Atomic subtraction. + * + * This routine performs an atomic subtraction on @a target. + * + * @note @atomic_api + * + * @param target Address of atomic variable. + * @param value Value to subtract. + * + * @return Previous value of @a target. + */ +atomic_val_t atomic_sub(atomic_t *target, atomic_val_t value); + +/** + * @brief Atomic increment. + * + * This routine performs an atomic increment by 1 on @a target. + * + * @note @atomic_api + * + * @param target Address of atomic variable. + * + * @return Previous value of @a target. + */ +atomic_val_t atomic_inc(atomic_t *target); + +/** + * @brief Atomic decrement. + * + * This routine performs an atomic decrement by 1 on @a target. + * + * @note @atomic_api + * + * @param target Address of atomic variable. + * + * @return Previous value of @a target. + */ +atomic_val_t atomic_dec(atomic_t *target); + +/** + * @brief Atomic get. + * + * This routine performs an atomic read on @a target. + * + * @note @atomic_api + * + * @param target Address of atomic variable. + * + * @return Value of @a target. + */ +atomic_val_t atomic_get(const atomic_t *target); + +/** + * @brief Atomic get a pointer value + * + * This routine performs an atomic read on @a target. + * + * @note @atomic_api + * + * @param target Address of pointer variable. + * + * @return Value of @a target. + */ +atomic_ptr_val_t atomic_ptr_get(const atomic_ptr_t *target); + +/** + * @brief Atomic get-and-set. + * + * This routine atomically sets @a target to @a value and returns + * the previous value of @a target. + * + * @note @atomic_api + * + * @param target Address of atomic variable. + * @param value Value to write to @a target. + * + * @return Previous value of @a target. + */ +atomic_val_t atomic_set(atomic_t *target, atomic_val_t value); + +/** + * @brief Atomic get-and-set for pointer values + * + * This routine atomically sets @a target to @a value and returns + * the previous value of @a target. + * + * @note @atomic_api + * + * @param target Address of atomic variable. + * @param value Value to write to @a target. + * + * @return Previous value of @a target. + */ +atomic_ptr_val_t atomic_ptr_set(atomic_ptr_t *target, atomic_ptr_val_t value); + +/** + * @brief Atomic clear. + * + * This routine atomically sets @a target to zero and returns its previous + * value. (Hence, it is equivalent to atomic_set(target, 0).) + * + * @note @atomic_api + * + * @param target Address of atomic variable. + * + * @return Previous value of @a target. + */ +atomic_val_t atomic_clear(atomic_t *target); + +/** + * @brief Atomic clear of a pointer value + * + * This routine atomically sets @a target to zero and returns its previous + * value. (Hence, it is equivalent to atomic_set(target, 0).) + * + * @note @atomic_api + * + * @param target Address of atomic variable. + * + * @return Previous value of @a target. + */ +atomic_ptr_val_t atomic_ptr_clear(atomic_ptr_t *target); + +/** + * @brief Atomic bitwise inclusive OR. + * + * This routine atomically sets @a target to the bitwise inclusive OR of + * @a target and @a value. + * + * @note @atomic_api + * + * @param target Address of atomic variable. + * @param value Value to OR. + * + * @return Previous value of @a target. + */ +atomic_val_t atomic_or(atomic_t *target, atomic_val_t value); + +/** + * @brief Atomic bitwise exclusive OR (XOR). + * + * @note @atomic_api + * + * This routine atomically sets @a target to the bitwise exclusive OR (XOR) of + * @a target and @a value. + * + * @param target Address of atomic variable. + * @param value Value to XOR + * + * @return Previous value of @a target. + */ +atomic_val_t atomic_xor(atomic_t *target, atomic_val_t value); + +/** + * @brief Atomic bitwise AND. + * + * This routine atomically sets @a target to the bitwise AND of @a target + * and @a value. + * + * @note @atomic_api + * + * @param target Address of atomic variable. + * @param value Value to AND. + * + * @return Previous value of @a target. + */ +atomic_val_t atomic_and(atomic_t *target, atomic_val_t value); + +/** + * @brief Atomic bitwise NAND. + * + * This routine atomically sets @a target to the bitwise NAND of @a target + * and @a value. (This operation is equivalent to target = ~(target & value).) + * + * @note @atomic_api + * + * @param target Address of atomic variable. + * @param value Value to NAND. + * + * @return Previous value of @a target. + */ +atomic_val_t atomic_nand(atomic_t *target, atomic_val_t value); + /** * @} */ diff --git a/include/zephyr/sys/atomic_builtin.h b/include/zephyr/sys/atomic_builtin.h index 972200c4fc6..5b81a76f050 100644 --- a/include/zephyr/sys/atomic_builtin.h +++ b/include/zephyr/sys/atomic_builtin.h @@ -19,28 +19,6 @@ extern "C" { /* Included from */ -/** - * @addtogroup atomic_apis Atomic Services APIs - * @ingroup kernel_apis - * @{ - */ - -/** - * @brief Atomic compare-and-set. - * - * This routine performs an atomic compare-and-set on @a target. If the current - * value of @a target equals @a old_value, @a target is set to @a new_value. - * If the current value of @a target does not equal @a old_value, @a target - * is left unchanged. - * - * @note As for all atomic APIs, includes a - * full/sequentially-consistent memory barrier (where applicable). - * - * @param target Address of atomic variable. - * @param old_value Original value to compare against. - * @param new_value New value to store. - * @return true if @a new_value is written, false otherwise. - */ static inline bool atomic_cas(atomic_t *target, atomic_val_t old_value, atomic_val_t new_value) { @@ -49,22 +27,6 @@ static inline bool atomic_cas(atomic_t *target, atomic_val_t old_value, __ATOMIC_SEQ_CST); } -/** - * @brief Atomic compare-and-set with pointer values - * - * This routine performs an atomic compare-and-set on @a target. If the current - * value of @a target equals @a old_value, @a target is set to @a new_value. - * If the current value of @a target does not equal @a old_value, @a target - * is left unchanged. - * - * @note As for all atomic APIs, includes a - * full/sequentially-consistent memory barrier (where applicable). - * - * @param target Address of atomic variable. - * @param old_value Original value to compare against. - * @param new_value New value to store. - * @return true if @a new_value is written, false otherwise. - */ static inline bool atomic_ptr_cas(atomic_ptr_t *target, atomic_ptr_val_t old_value, atomic_ptr_val_t new_value) { @@ -73,131 +35,36 @@ static inline bool atomic_ptr_cas(atomic_ptr_t *target, atomic_ptr_val_t old_val __ATOMIC_SEQ_CST); } -/** - * - * @brief Atomic addition. - * - * This routine performs an atomic addition on @a target. - * - * @note As for all atomic APIs, includes a - * full/sequentially-consistent memory barrier (where applicable). - * - * @param target Address of atomic variable. - * @param value Value to add. - * - * @return Previous value of @a target. - */ static inline atomic_val_t atomic_add(atomic_t *target, atomic_val_t value) { return __atomic_fetch_add(target, value, __ATOMIC_SEQ_CST); } -/** - * - * @brief Atomic subtraction. - * - * This routine performs an atomic subtraction on @a target. - * - * @note As for all atomic APIs, includes a - * full/sequentially-consistent memory barrier (where applicable). - * - * @param target Address of atomic variable. - * @param value Value to subtract. - * - * @return Previous value of @a target. - */ static inline atomic_val_t atomic_sub(atomic_t *target, atomic_val_t value) { return __atomic_fetch_sub(target, value, __ATOMIC_SEQ_CST); } -/** - * - * @brief Atomic increment. - * - * This routine performs an atomic increment by 1 on @a target. - * - * @note As for all atomic APIs, includes a - * full/sequentially-consistent memory barrier (where applicable). - * - * @param target Address of atomic variable. - * - * @return Previous value of @a target. - */ static inline atomic_val_t atomic_inc(atomic_t *target) { return atomic_add(target, 1); } -/** - * - * @brief Atomic decrement. - * - * This routine performs an atomic decrement by 1 on @a target. - * - * @note As for all atomic APIs, includes a - * full/sequentially-consistent memory barrier (where applicable). - * - * @param target Address of atomic variable. - * - * @return Previous value of @a target. - */ static inline atomic_val_t atomic_dec(atomic_t *target) { return atomic_sub(target, 1); } -/** - * - * @brief Atomic get. - * - * This routine performs an atomic read on @a target. - * - * @note As for all atomic APIs, includes a - * full/sequentially-consistent memory barrier (where applicable). - * - * @param target Address of atomic variable. - * - * @return Value of @a target. - */ static inline atomic_val_t atomic_get(const atomic_t *target) { return __atomic_load_n(target, __ATOMIC_SEQ_CST); } -/** - * - * @brief Atomic get a pointer value - * - * This routine performs an atomic read on @a target. - * - * @note As for all atomic APIs, includes a - * full/sequentially-consistent memory barrier (where applicable). - * - * @param target Address of pointer variable. - * - * @return Value of @a target. - */ static inline atomic_ptr_val_t atomic_ptr_get(const atomic_ptr_t *target) { return __atomic_load_n(target, __ATOMIC_SEQ_CST); } -/** - * - * @brief Atomic get-and-set. - * - * This routine atomically sets @a target to @a value and returns - * the previous value of @a target. - * - * @note As for all atomic APIs, includes a - * full/sequentially-consistent memory barrier (where applicable). - * - * @param target Address of atomic variable. - * @param value Value to write to @a target. - * - * @return Previous value of @a target. - */ static inline atomic_val_t atomic_set(atomic_t *target, atomic_val_t value) { /* This builtin, as described by Intel, is not a traditional @@ -207,147 +74,41 @@ static inline atomic_val_t atomic_set(atomic_t *target, atomic_val_t value) return __atomic_exchange_n(target, value, __ATOMIC_SEQ_CST); } -/** - * - * @brief Atomic get-and-set for pointer values - * - * This routine atomically sets @a target to @a value and returns - * the previous value of @a target. - * - * @note As for all atomic APIs, includes a - * full/sequentially-consistent memory barrier (where applicable). - * - * @param target Address of atomic variable. - * @param value Value to write to @a target. - * - * @return Previous value of @a target. - */ static inline atomic_ptr_val_t atomic_ptr_set(atomic_ptr_t *target, atomic_ptr_val_t value) { return __atomic_exchange_n(target, value, __ATOMIC_SEQ_CST); } -/** - * - * @brief Atomic clear. - * - * This routine atomically sets @a target to zero and returns its previous - * value. (Hence, it is equivalent to atomic_set(target, 0).) - * - * @note As for all atomic APIs, includes a - * full/sequentially-consistent memory barrier (where applicable). - * - * @param target Address of atomic variable. - * - * @return Previous value of @a target. - */ static inline atomic_val_t atomic_clear(atomic_t *target) { return atomic_set(target, 0); } -/** - * - * @brief Atomic clear of a pointer value - * - * This routine atomically sets @a target to zero and returns its previous - * value. (Hence, it is equivalent to atomic_set(target, 0).) - * - * @note As for all atomic APIs, includes a - * full/sequentially-consistent memory barrier (where applicable). - * - * @param target Address of atomic variable. - * - * @return Previous value of @a target. - */ static inline atomic_ptr_val_t atomic_ptr_clear(atomic_ptr_t *target) { return atomic_ptr_set(target, NULL); } -/** - * - * @brief Atomic bitwise inclusive OR. - * - * This routine atomically sets @a target to the bitwise inclusive OR of - * @a target and @a value. - * - * @note As for all atomic APIs, includes a - * full/sequentially-consistent memory barrier (where applicable). - * - * @param target Address of atomic variable. - * @param value Value to OR. - * - * @return Previous value of @a target. - */ static inline atomic_val_t atomic_or(atomic_t *target, atomic_val_t value) { return __atomic_fetch_or(target, value, __ATOMIC_SEQ_CST); } -/** - * - * @brief Atomic bitwise exclusive OR (XOR). - * - * @note As for all atomic APIs, includes a - * full/sequentially-consistent memory barrier (where applicable). - * - * This routine atomically sets @a target to the bitwise exclusive OR (XOR) of - * @a target and @a value. - * - * @param target Address of atomic variable. - * @param value Value to XOR - * - * @return Previous value of @a target. - */ static inline atomic_val_t atomic_xor(atomic_t *target, atomic_val_t value) { return __atomic_fetch_xor(target, value, __ATOMIC_SEQ_CST); } -/** - * - * @brief Atomic bitwise AND. - * - * This routine atomically sets @a target to the bitwise AND of @a target - * and @a value. - * - * @note As for all atomic APIs, includes a - * full/sequentially-consistent memory barrier (where applicable). - * - * @param target Address of atomic variable. - * @param value Value to AND. - * - * @return Previous value of @a target. - */ static inline atomic_val_t atomic_and(atomic_t *target, atomic_val_t value) { return __atomic_fetch_and(target, value, __ATOMIC_SEQ_CST); } -/** - * - * @brief Atomic bitwise NAND. - * - * This routine atomically sets @a target to the bitwise NAND of @a target - * and @a value. (This operation is equivalent to target = ~(target & value).) - * - * @note As for all atomic APIs, includes a - * full/sequentially-consistent memory barrier (where applicable). - * - * @param target Address of atomic variable. - * @param value Value to NAND. - * - * @return Previous value of @a target. - */ static inline atomic_val_t atomic_nand(atomic_t *target, atomic_val_t value) { return __atomic_fetch_nand(target, value, __ATOMIC_SEQ_CST); } -/** @} */ - - #ifdef __cplusplus } #endif From 94291a0c759e3bfbf419428caee1d7f288dc238c Mon Sep 17 00:00:00 2001 From: Daniel Leung Date: Mon, 9 Oct 2023 13:33:17 -0700 Subject: [PATCH 2122/3723] cache: make arch cache interface parsable by doxygen This adds the defined(__DOXYGEN__) to arch/cache.h so the doxygen doc there can be seen. Signed-off-by: Daniel Leung --- include/zephyr/arch/cache.h | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/include/zephyr/arch/cache.h b/include/zephyr/arch/cache.h index 8cbef3d2b9d..f2943bdd7f9 100644 --- a/include/zephyr/arch/cache.h +++ b/include/zephyr/arch/cache.h @@ -25,7 +25,7 @@ #include #endif -#if defined(CONFIG_DCACHE) +#if defined(CONFIG_DCACHE) || defined(__DOXYGEN__) /** * @brief Enable the d-cache @@ -157,7 +157,7 @@ int arch_dcache_flush_and_invd_range(void *addr, size_t size); #define cache_data_flush_and_invd_range(addr, size) \ arch_dcache_flush_and_invd_range(addr, size) -#if defined(CONFIG_DCACHE_LINE_SIZE_DETECT) +#if defined(CONFIG_DCACHE_LINE_SIZE_DETECT) || defined(__DOXYGEN__) /** * @@ -176,11 +176,11 @@ size_t arch_dcache_line_size_get(void); #define cache_data_line_size_get arch_dcache_line_size_get -#endif /* CONFIG_DCACHE_LINE_SIZE_DETECT */ +#endif /* CONFIG_DCACHE_LINE_SIZE_DETECT || __DOXYGEN__ */ -#endif /* CONFIG_DCACHE */ +#endif /* CONFIG_DCACHE || __DOXYGEN__ */ -#if defined(CONFIG_ICACHE) +#if defined(CONFIG_ICACHE) || defined(__DOXYGEN__) /** * @brief Enable the i-cache @@ -311,7 +311,7 @@ int arch_icache_flush_and_invd_range(void *addr, size_t size); #define cache_instr_flush_and_invd_range(addr, size) \ arch_icache_flush_and_invd_range(addr, size) -#if defined(CONFIG_ICACHE_LINE_SIZE_DETECT) +#if defined(CONFIG_ICACHE_LINE_SIZE_DETECT) || defined(__DOXYGEN__) /** * @@ -331,9 +331,9 @@ size_t arch_icache_line_size_get(void); #define cache_instr_line_size_get arch_icache_line_size_get -#endif /* CONFIG_ICACHE_LINE_SIZE_DETECT */ +#endif /* CONFIG_ICACHE_LINE_SIZE_DETECT || __DOXYGEN__ */ -#endif /* CONFIG_ICACHE */ +#endif /* CONFIG_ICACHE || __DOXYGEN__ */ /** * @} From bd3c76c88d4fff6b4b42d38525de33b099410277 Mon Sep 17 00:00:00 2001 From: Daniel Leung Date: Mon, 9 Oct 2023 11:52:32 -0700 Subject: [PATCH 2123/3723] doc: force include interface header files first Force include interface header files first before other files under include. This is due to doxygen always using the first found item during linking. Because of this, without forcing the interface definitions first, almost all of these would link to the same named items, for example, under ARC header files instead. Hence the need to manually shuffle the items so linking would actually link to the correct items. Note that this only works with functions and macros that are actually defined in the interface file. A simple doc section with @def would not work as this is not an actual definition. Signed-off-by: Daniel Leung --- doc/zephyr.doxyfile.in | 3 +++ 1 file changed, 3 insertions(+) diff --git a/doc/zephyr.doxyfile.in b/doc/zephyr.doxyfile.in index 493e56dd198..2332b2f5932 100644 --- a/doc/zephyr.doxyfile.in +++ b/doc/zephyr.doxyfile.in @@ -924,6 +924,9 @@ WARN_LOGFILE = INPUT = @ZEPHYR_BASE@/doc/_doxygen/mainpage.md \ @ZEPHYR_BASE@/doc/_doxygen/groups.dox \ @ZEPHYR_BASE@/kernel/include/kernel_arch_interface.h \ + @ZEPHYR_BASE@/include/zephyr/arch/cache.h \ + @ZEPHYR_BASE@/include/zephyr/sys/arch_interface.h \ + @ZEPHYR_BASE@/include/zephyr/sys/atomic.h \ @ZEPHYR_BASE@/include/ \ @ZEPHYR_BASE@/lib/libc/minimal/include/ \ @ZEPHYR_BASE@/subsys/testsuite/include/ \ From a64eec6aaeecf0ad8c53cd1b9d10e7d6ae7abf8f Mon Sep 17 00:00:00 2001 From: Daniel Leung Date: Mon, 9 Oct 2023 11:04:23 -0700 Subject: [PATCH 2124/3723] xtensa: remove XTENSA_ERR_NORET It is not being used anywhere, so remove. Signed-off-by: Daniel Leung --- include/zephyr/arch/xtensa/arch.h | 2 -- 1 file changed, 2 deletions(-) diff --git a/include/zephyr/arch/xtensa/arch.h b/include/zephyr/arch/xtensa/arch.h index 4601a675949..68ede62f1f5 100644 --- a/include/zephyr/arch/xtensa/arch.h +++ b/include/zephyr/arch/xtensa/arch.h @@ -100,8 +100,6 @@ extern void z_irq_priority_set(uint32_t irq, uint32_t prio, uint32_t flags); Z_ISR_DECLARE(irq_p, flags_p, isr_p, isr_param_p); \ } -#define XTENSA_ERR_NORET - extern uint32_t sys_clock_cycle_get_32(void); static inline uint32_t arch_k_cycle_get_32(void) From 035c8d8ceb4b4dc13f7ae072f62da1c1cf1f27db Mon Sep 17 00:00:00 2001 From: Daniel Leung Date: Mon, 9 Oct 2023 11:10:40 -0700 Subject: [PATCH 2125/3723] xtensa: remove sys_define_gpr_with_alias() This is not being used in Xtensa anywhere, so remove. Signed-off-by: Daniel Leung --- include/zephyr/arch/xtensa/arch.h | 3 --- 1 file changed, 3 deletions(-) diff --git a/include/zephyr/arch/xtensa/arch.h b/include/zephyr/arch/xtensa/arch.h index 68ede62f1f5..745288da171 100644 --- a/include/zephyr/arch/xtensa/arch.h +++ b/include/zephyr/arch/xtensa/arch.h @@ -46,9 +46,6 @@ * @} */ -/* Xtensa GPRs are often designated by two different names */ -#define sys_define_gpr_with_alias(name1, name2) union { uint32_t name1, name2; } - #include #ifdef __cplusplus From 0ee1e28a2f5f118b09a1689e78500218eb1f64cc Mon Sep 17 00:00:00 2001 From: Daniel Leung Date: Mon, 9 Oct 2023 12:31:56 -0700 Subject: [PATCH 2126/3723] xtensa: polish doxygen and add to missing doc This polishes doxygen to, hopefully, make it better looking on the API doc. Also adds missing doc to various functions and macros. Signed-off-by: Daniel Leung --- include/zephyr/arch/xtensa/arch.h | 108 ++++++++++++++++----- include/zephyr/arch/xtensa/arch_inlines.h | 29 ++++++ include/zephyr/arch/xtensa/atomic_xtensa.h | 39 +++++++- include/zephyr/arch/xtensa/cache.h | 22 ++++- include/zephyr/arch/xtensa/gdbstub.h | 40 ++++---- include/zephyr/arch/xtensa/irq.h | 3 + 6 files changed, 196 insertions(+), 45 deletions(-) diff --git a/include/zephyr/arch/xtensa/arch.h b/include/zephyr/arch/xtensa/arch.h index 745288da171..26325a984e1 100644 --- a/include/zephyr/arch/xtensa/arch.h +++ b/include/zephyr/arch/xtensa/arch.h @@ -7,7 +7,7 @@ * @file * @brief Xtensa specific kernel interface header * This header contains the Xtensa specific kernel interface. It is included - * by the generic kernel interface header (include/arch/cpu.h) + * by the generic kernel interface header (include/zephyr/arch/cpu.h) */ #ifndef ZEPHYR_INCLUDE_ARCH_XTENSA_ARCH_H_ @@ -33,6 +33,8 @@ #include #include +#include + #include /** @@ -61,7 +63,23 @@ struct arch_mem_domain { sys_snode_t node; }; +/** + * @brief Generate hardware exception. + * + * This generates hardware exception which is used by ARCH_EXCEPT(). + * + * @param reason_p Reason for exception. + */ extern void xtensa_arch_except(int reason_p); + +/** + * @brief Generate kernel oops. + * + * This generates kernel oops which is used by arch_syscall_oops(). + * + * @param reason_p Reason for exception. + * @param ssf Stack pointer. + */ extern void xtensa_arch_kernel_oops(int reason_p, void *ssf); #ifdef CONFIG_USERSPACE @@ -79,9 +97,9 @@ extern void xtensa_arch_kernel_oops(int reason_p, void *ssf); #else #define ARCH_EXCEPT(reason_p) do { \ - xtensa_arch_except(reason_p); \ - CODE_UNREACHABLE; \ -} while (false) + xtensa_arch_except(reason_p); \ + CODE_UNREACHABLE; \ + } while (false) #endif @@ -93,44 +111,47 @@ __syscall void xtensa_user_fault(unsigned int reason); extern void z_irq_priority_set(uint32_t irq, uint32_t prio, uint32_t flags); #define ARCH_IRQ_CONNECT(irq_p, priority_p, isr_p, isr_param_p, flags_p) \ -{ \ - Z_ISR_DECLARE(irq_p, flags_p, isr_p, isr_param_p); \ -} - -extern uint32_t sys_clock_cycle_get_32(void); + { \ + Z_ISR_DECLARE(irq_p, flags_p, isr_p, isr_param_p); \ + } +/** Implementation of @ref arch_k_cycle_get_32. */ static inline uint32_t arch_k_cycle_get_32(void) { return sys_clock_cycle_get_32(); } -extern uint64_t sys_clock_cycle_get_64(void); - +/** Implementation of @ref arch_k_cycle_get_64. */ static inline uint64_t arch_k_cycle_get_64(void) { return sys_clock_cycle_get_64(); } +/** Implementation of @ref arch_nop. */ static ALWAYS_INLINE void arch_nop(void) { __asm__ volatile("nop"); } +/** + * @brief Lock VECBASE if supported by hardware. + * + * The bit 0 of VECBASE acts as a lock bit on hardware supporting + * this feature. When this bit is set, VECBASE cannot be changed + * until it is cleared by hardware reset. When the hardware does not + * support this bit, it is hardwired to 0. + */ static ALWAYS_INLINE void xtensa_vecbase_lock(void) { int vecbase; __asm__ volatile("rsr.vecbase %0" : "=r" (vecbase)); - - /* In some targets the bit 0 of VECBASE works as lock bit. - * When this bit set, VECBASE can't be changed until it is cleared by - * reset. When the target does not have it, it is hardwired to 0. - **/ __asm__ volatile("wsr.vecbase %0; rsync" : : "r" (vecbase | 1)); } -#if defined(CONFIG_XTENSA_RPO_CACHE) -#if defined(CONFIG_ARCH_HAS_COHERENCE) +#if defined(CONFIG_XTENSA_RPO_CACHE) || defined(__DOXYGEN__) +#if defined(CONFIG_ARCH_HAS_COHERENCE) || defined(__DOXYGEN__) +/** Implementation of @ref arch_mem_coherent. */ static inline bool arch_mem_coherent(void *ptr) { size_t addr = (size_t) ptr; @@ -139,6 +160,19 @@ static inline bool arch_mem_coherent(void *ptr) } #endif +/** + * @brief Test if a pointer is in cached region. + * + * Some hardware may map the same physical memory twice + * so that it can be seen in both (incoherent) cached mappings + * and a coherent "shared" area. This tests if a particular + * pointer is within the cached, coherent area. + * + * @param ptr Pointer + * + * @retval True if pointer is in cached region. + * @retval False if pointer is not in cached region. + */ static inline bool arch_xtensa_is_ptr_cached(void *ptr) { size_t addr = (size_t) ptr; @@ -146,6 +180,19 @@ static inline bool arch_xtensa_is_ptr_cached(void *ptr) return (addr >> 29) == CONFIG_XTENSA_CACHED_REGION; } +/** + * @brief Test if a pointer is in un-cached region. + * + * Some hardware may map the same physical memory twice + * so that it can be seen in both (incoherent) cached mappings + * and a coherent "shared" area. This tests if a particular + * pointer is within the un-cached, incoherent area. + * + * @param ptr Pointer + * + * @retval True if pointer is not in cached region. + * @retval False if pointer is in cached region. + */ static inline bool arch_xtensa_is_ptr_uncached(void *ptr) { size_t addr = (size_t) ptr; @@ -173,6 +220,7 @@ static ALWAYS_INLINE uint32_t z_xtrpoflip(uint32_t addr, uint32_t rto, uint32_t return (addr & ~(7U << 29)) | rto; } } + /** * @brief Return cached pointer to a RAM address * @@ -271,10 +319,14 @@ static inline void *arch_xtensa_uncached_ptr(void __sparse_cache *ptr) addr += addrincr; \ } while (0) -#define ARCH_XTENSA_SET_RPO_TLB() do { \ - register uint32_t addr = 0, addrincr = 0x20000000; \ - FOR_EACH(_SET_ONE_TLB, (;), 0, 1, 2, 3, 4, 5, 6, 7); \ -} while (0) +/** + * @brief Setup RPO TLB registers. + */ +#define ARCH_XTENSA_SET_RPO_TLB() \ + do { \ + register uint32_t addr = 0, addrincr = 0x20000000; \ + FOR_EACH(_SET_ONE_TLB, (;), 0, 1, 2, 3, 4, 5, 6, 7); \ + } while (0) #else /* CONFIG_XTENSA_RPO_CACHE */ @@ -304,7 +356,17 @@ static inline void *arch_xtensa_uncached_ptr(void *ptr) #endif /* CONFIG_XTENSA_RPO_CACHE */ -#ifdef CONFIG_XTENSA_MMU +#if defined(CONFIG_XTENSA_MMU) || defined(__DOXYGEN__) +/** + * @brief Peform additional steps after MMU initialization. + * + * This performs additional steps related to memory management + * after the main MMU initialization code. This needs to defined + * in the SoC layer. Default is do no nothing. + * + * @param is_core0 True if this is called while executing on + * CPU core #0. + */ extern void arch_xtensa_mmu_post_init(bool is_core0); #endif diff --git a/include/zephyr/arch/xtensa/arch_inlines.h b/include/zephyr/arch/xtensa/arch_inlines.h index d5fcc55af47..4e7b5200276 100644 --- a/include/zephyr/arch/xtensa/arch_inlines.h +++ b/include/zephyr/arch/xtensa/arch_inlines.h @@ -13,26 +13,53 @@ #include #include +/** + * @brief Read a special register. + * + * @param sr Name of special register. + * + * @return Value of special register. + */ #define XTENSA_RSR(sr) \ ({uint32_t v; \ __asm__ volatile ("rsr." sr " %0" : "=a"(v)); \ v; }) +/** + * @brief Write to a special register. + * + * @param sr Name of special register. + * @param v Value to be written to special register. + */ #define XTENSA_WSR(sr, v) \ do { \ __asm__ volatile ("wsr." sr " %0" : : "r"(v)); \ } while (false) +/** + * @brief Read a user register. + * + * @param ur Name of user register. + * + * @return Value of user register. + */ #define XTENSA_RUR(ur) \ ({uint32_t v; \ __asm__ volatile ("rur." ur " %0" : "=a"(v)); \ v; }) +/** + * @brief Write to a user register. + * + * @param ur Name of user register. + * @param v Value to be written to user register. + */ #define XTENSA_WUR(ur, v) \ do { \ __asm__ volatile ("wur." ur " %0" : : "r"(v)); \ } while (false) +/** Implementation of @ref arch_curr_cpu. */ static ALWAYS_INLINE _cpu_t *arch_curr_cpu(void) { _cpu_t *cpu; @@ -42,6 +69,7 @@ static ALWAYS_INLINE _cpu_t *arch_curr_cpu(void) return cpu; } +/** Implementation of @ref arch_proc_id. */ static ALWAYS_INLINE uint32_t arch_proc_id(void) { uint32_t prid; @@ -54,6 +82,7 @@ static ALWAYS_INLINE uint32_t arch_proc_id(void) extern unsigned int soc_num_cpus; #endif +/** Implementation of @ref arch_num_cpus. */ static ALWAYS_INLINE unsigned int arch_num_cpus(void) { #ifdef CONFIG_SOC_HAS_RUNTIME_NUM_CPUS diff --git a/include/zephyr/arch/xtensa/atomic_xtensa.h b/include/zephyr/arch/xtensa/atomic_xtensa.h index c518f4df4ed..a8f5d0f78e9 100644 --- a/include/zephyr/arch/xtensa/atomic_xtensa.h +++ b/include/zephyr/arch/xtensa/atomic_xtensa.h @@ -1,11 +1,12 @@ -/** +/* * Copyright (c) 2021 Intel Corporation * SPDX-License-Identifier: Apache-2.0 */ + #ifndef ZEPHYR_INCLUDE_ATOMIC_XTENSA_H_ #define ZEPHYR_INCLUDE_ATOMIC_XTENSA_H_ -/* Included from */ +/* Included from */ /* Recent GCC versions actually do have working atomics support on * Xtensa (and so should work with CONFIG_ATOMIC_OPERATIONS_BUILTIN), @@ -13,6 +14,7 @@ * inline implementation here that is more or less identical */ +/** Implementation of @ref atomic_get. */ static ALWAYS_INLINE atomic_val_t atomic_get(const atomic_t *target) { atomic_val_t ret; @@ -28,6 +30,23 @@ static ALWAYS_INLINE atomic_val_t atomic_get(const atomic_t *target) return ret; } +/** + * @brief Xtensa specific atomic compare-and-set (CAS). + * + * @param addr Address of atomic variable. + * @param oldval Original value to compare against. + * @param newval New value to store. + * + * This utilizes SCOMPARE1 register and s32c1i instruction to + * perform compare-and-set atomic operation. This will + * unconditionally read from the atomic variable at @p addr + * before the comparison. This value is returned from + * the function. + * + * @return The value at the memory location before CAS. + * + * @see atomic_cas. + */ static ALWAYS_INLINE atomic_val_t xtensa_cas(atomic_t *addr, atomic_val_t oldval, atomic_val_t newval) @@ -38,12 +57,14 @@ atomic_val_t xtensa_cas(atomic_t *addr, atomic_val_t oldval, return newval; /* got swapped with the old memory by s32c1i */ } +/** Implementation of @ref atomic_cas. */ static ALWAYS_INLINE bool atomic_cas(atomic_t *target, atomic_val_t oldval, atomic_val_t newval) { return oldval == xtensa_cas(target, oldval, newval); } +/** Implementation of @ref atomic_ptr_cas. */ static ALWAYS_INLINE bool atomic_ptr_cas(atomic_ptr_t *target, void *oldval, void *newval) { @@ -57,7 +78,6 @@ bool atomic_ptr_cas(atomic_ptr_t *target, void *oldval, void *newval) * specified expression. Evaluates to the old value which was * atomically replaced. */ - #define Z__GEN_ATOMXCHG(expr) ({ \ atomic_val_t res, cur; \ do { \ @@ -66,75 +86,88 @@ bool atomic_ptr_cas(atomic_ptr_t *target, void *oldval, void *newval) } while (res != cur); \ res; }) +/** Implementation of @ref atomic_set. */ static ALWAYS_INLINE atomic_val_t atomic_set(atomic_t *target, atomic_val_t value) { return Z__GEN_ATOMXCHG(value); } +/** Implementation of @ref atomic_add. */ static ALWAYS_INLINE atomic_val_t atomic_add(atomic_t *target, atomic_val_t value) { return Z__GEN_ATOMXCHG(cur + value); } +/** Implementation of @ref atomic_sub. */ static ALWAYS_INLINE atomic_val_t atomic_sub(atomic_t *target, atomic_val_t value) { return Z__GEN_ATOMXCHG(cur - value); } +/** Implementation of @ref atomic_inc. */ static ALWAYS_INLINE atomic_val_t atomic_inc(atomic_t *target) { return Z__GEN_ATOMXCHG(cur + 1); } +/** Implementation of @ref atomic_dec. */ static ALWAYS_INLINE atomic_val_t atomic_dec(atomic_t *target) { return Z__GEN_ATOMXCHG(cur - 1); } +/** Implementation of @ref atomic_or. */ static ALWAYS_INLINE atomic_val_t atomic_or(atomic_t *target, atomic_val_t value) { return Z__GEN_ATOMXCHG(cur | value); } +/** Implementation of @ref atomic_xor. */ static ALWAYS_INLINE atomic_val_t atomic_xor(atomic_t *target, atomic_val_t value) { return Z__GEN_ATOMXCHG(cur ^ value); } +/** Implementation of @ref atomic_and. */ static ALWAYS_INLINE atomic_val_t atomic_and(atomic_t *target, atomic_val_t value) { return Z__GEN_ATOMXCHG(cur & value); } +/** Implementation of @ref atomic_nand. */ static ALWAYS_INLINE atomic_val_t atomic_nand(atomic_t *target, atomic_val_t value) { return Z__GEN_ATOMXCHG(~(cur & value)); } +/** Implementation of @ref atomic_ptr_get. */ static ALWAYS_INLINE void *atomic_ptr_get(const atomic_ptr_t *target) { return (void *) atomic_get((atomic_t *)target); } +/** Implementation of @ref atomic_ptr_set. */ static ALWAYS_INLINE void *atomic_ptr_set(atomic_ptr_t *target, void *value) { return (void *) atomic_set((atomic_t *) target, (atomic_val_t) value); } +/** Implementation of @ref atomic_clear. */ static ALWAYS_INLINE atomic_val_t atomic_clear(atomic_t *target) { return atomic_set(target, 0); } +/** Implementation of @ref atomic_ptr_clear. */ static ALWAYS_INLINE void *atomic_ptr_clear(atomic_ptr_t *target) { return (void *) atomic_set((atomic_t *) target, 0); diff --git a/include/zephyr/arch/xtensa/cache.h b/include/zephyr/arch/xtensa/cache.h index 8a190d0d371..6fb64ef30d5 100644 --- a/include/zephyr/arch/xtensa/cache.h +++ b/include/zephyr/arch/xtensa/cache.h @@ -22,7 +22,9 @@ BUILD_ASSERT(Z_IS_POW2(XCHAL_DCACHE_LINESIZE)); BUILD_ASSERT(Z_IS_POW2(Z_DCACHE_MAX)); #endif -#if defined(CONFIG_DCACHE) +#if defined(CONFIG_DCACHE) || defined(__DOXYGEN__) + +/** Implementation of @ref arch_dcache_flush_range. */ static ALWAYS_INLINE int arch_dcache_flush_range(void *addr, size_t bytes) { #if XCHAL_DCACHE_SIZE @@ -38,6 +40,7 @@ static ALWAYS_INLINE int arch_dcache_flush_range(void *addr, size_t bytes) return 0; } +/** Implementation of @ref arch_dcache_flush_and_invd_range. */ static ALWAYS_INLINE int arch_dcache_flush_and_invd_range(void *addr, size_t bytes) { #if XCHAL_DCACHE_SIZE @@ -53,6 +56,7 @@ static ALWAYS_INLINE int arch_dcache_flush_and_invd_range(void *addr, size_t byt return 0; } +/** Implementation of @ref arch_dcache_invd_range. */ static ALWAYS_INLINE int arch_dcache_invd_range(void *addr, size_t bytes) { #if XCHAL_DCACHE_SIZE @@ -68,6 +72,7 @@ static ALWAYS_INLINE int arch_dcache_invd_range(void *addr, size_t bytes) return 0; } +/** Implementation of @ref arch_dcache_invd_all. */ static ALWAYS_INLINE int arch_dcache_invd_all(void) { #if XCHAL_DCACHE_SIZE @@ -81,6 +86,7 @@ static ALWAYS_INLINE int arch_dcache_invd_all(void) return 0; } +/** Implementation of @ref arch_dcache_flush_all. */ static ALWAYS_INLINE int arch_dcache_flush_all(void) { #if XCHAL_DCACHE_SIZE @@ -94,6 +100,7 @@ static ALWAYS_INLINE int arch_dcache_flush_all(void) return 0; } +/** Implementation of @ref arch_dcache_flush_and_invd_all. */ static ALWAYS_INLINE int arch_dcache_flush_and_invd_all(void) { #if XCHAL_DCACHE_SIZE @@ -107,11 +114,13 @@ static ALWAYS_INLINE int arch_dcache_flush_and_invd_all(void) return 0; } +/** Implementation of @ref arch_dcache_enable. */ static ALWAYS_INLINE void arch_dcache_enable(void) { /* nothing */ } +/** Implementation of @ref arch_dcache_disable. */ static ALWAYS_INLINE void arch_dcache_disable(void) { /* nothing */ @@ -119,18 +128,21 @@ static ALWAYS_INLINE void arch_dcache_disable(void) #endif /* CONFIG_DCACHE */ -#if defined(CONFIG_ICACHE) +#if defined(CONFIG_ICACHE) || defined(__DOXYGEN__) +/** Implementation of @ref arch_icache_line_size_get. */ static ALWAYS_INLINE size_t arch_icache_line_size_get(void) { return -ENOTSUP; } +/** Implementation of @ref arch_icache_flush_all. */ static ALWAYS_INLINE int arch_icache_flush_all(void) { return -ENOTSUP; } +/** Implementation of @ref arch_icache_invd_all. */ static ALWAYS_INLINE int arch_icache_invd_all(void) { #if XCHAL_ICACHE_SIZE @@ -139,16 +151,19 @@ static ALWAYS_INLINE int arch_icache_invd_all(void) return 0; } +/** Implementation of @ref arch_icache_flush_and_invd_all. */ static ALWAYS_INLINE int arch_icache_flush_and_invd_all(void) { return -ENOTSUP; } +/** Implementation of @ref arch_icache_flush_range. */ static ALWAYS_INLINE int arch_icache_flush_range(void *addr, size_t size) { return -ENOTSUP; } +/** Implementation of @ref arch_icache_invd_range. */ static ALWAYS_INLINE int arch_icache_invd_range(void *addr, size_t size) { #if XCHAL_ICACHE_SIZE @@ -157,16 +172,19 @@ static ALWAYS_INLINE int arch_icache_invd_range(void *addr, size_t size) return 0; } +/** Implementation of @ref arch_icache_flush_and_invd_range. */ static ALWAYS_INLINE int arch_icache_flush_and_invd_range(void *addr, size_t size) { return -ENOTSUP; } +/** Implementation of @ref arch_icache_enable. */ static ALWAYS_INLINE void arch_icache_enable(void) { /* nothing */ } +/** Implementation of @ref arch_icache_disable. */ static ALWAYS_INLINE void arch_icache_disable(void) { /* nothing */ diff --git a/include/zephyr/arch/xtensa/gdbstub.h b/include/zephyr/arch/xtensa/gdbstub.h index 627bb79e678..89aabb02905 100644 --- a/include/zephyr/arch/xtensa/gdbstub.h +++ b/include/zephyr/arch/xtensa/gdbstub.h @@ -17,8 +17,8 @@ #define XTREG_GRP_SPECIAL 0x0200 #define XTREG_GRP_USER 0x0300 -/* - * Register description fot GDB stub. +/** + * @brief Register description for GDB stub. * * Values are based on gdb/gdb/xtensa-config.c in the Xtensa overlay, * where registers are defined using XTREG() macro: @@ -35,32 +35,35 @@ * gpkt_offset : ofs */ struct xtensa_register { - /* Register value */ + /** Register value */ uint32_t val; - /* GDB register index (for p/P packets) */ + /** GDB register index (for p/P packets) */ uint8_t idx; - /* Size of register */ + /** Size of register */ uint8_t byte_size; - /* Xtensa register number */ + /** Xtensa register number */ uint16_t regno; - /* Offset of this register in GDB G-packet. + /** + * Offset of this register in GDB G-packet. * -1 if register is not in G-packet. */ int16_t gpkt_offset; - /* Offset of saved register in stack frame. + /** + * Offset of saved register in stack frame. * 0 if not saved in stack frame. */ int8_t stack_offset; - /* Sequence number */ + /** Sequence number */ uint8_t seqno; - /* Set 1 to if register should not be written + /** + * Set to 1 if register should not be written * to during debugging. */ uint8_t is_read_only:1; @@ -78,26 +81,29 @@ struct xtensa_register { */ #include +/** + * @brief Architecture specific GDB context. + */ struct gdb_ctx { - /* Exception reason */ + /** Exception reason */ unsigned int exception; - /* Register descriptions */ + /** Register descriptions */ struct xtensa_register *regs; - /* Number of registers */ + /** Number of registers */ uint8_t num_regs; - /* Sequence number */ + /** Sequence number */ uint8_t seqno; - /* Index in register descriptions of A0 register */ + /** Index in register descriptions of A0 register */ uint8_t a0_idx; - /* Index in register descriptions of AR0 register */ + /** Index in register descriptions of AR0 register */ uint8_t ar_idx; - /* Index in register descriptions of WINDOWBASE register */ + /** Index in register descriptions of WINDOWBASE register */ uint8_t wb_idx; }; diff --git a/include/zephyr/arch/xtensa/irq.h b/include/zephyr/arch/xtensa/irq.h index 22d4800f8b9..938ab7b2303 100644 --- a/include/zephyr/arch/xtensa/irq.h +++ b/include/zephyr/arch/xtensa/irq.h @@ -130,6 +130,7 @@ static ALWAYS_INLINE void xtensa_irq_disable(uint32_t irq) z_xt_ints_off(1 << irq); } +/** Implementation of @ref arch_irq_lock. */ static ALWAYS_INLINE unsigned int arch_irq_lock(void) { unsigned int key; @@ -139,12 +140,14 @@ static ALWAYS_INLINE unsigned int arch_irq_lock(void) return key; } +/** Implementation of @ref arch_irq_unlock. */ static ALWAYS_INLINE void arch_irq_unlock(unsigned int key) { __asm__ volatile("wsr.ps %0; rsync" :: "r"(key) : "memory"); } +/** Implementation of @ref arch_irq_unlocked. */ static ALWAYS_INLINE bool arch_irq_unlocked(unsigned int key) { return (key & 0xf) == 0; /* INTLEVEL field */ From fe4ea0f326a4da4941cd01660fd068fc88a33d4c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Krzysztof=20Chru=C5=9Bci=C5=84ski?= Date: Tue, 21 Nov 2023 12:27:02 +0100 Subject: [PATCH 2127/3723] sys: util: Rework CONCAT to support variable length arguments MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Rework CONCAT to accept multiple arugments which are concatenated together. Number of arguments is limited to 8. Signed-off-by: Krzysztof Chruściński --- include/zephyr/sys/util.h | 13 +++++++++---- include/zephyr/sys/util_internal.h | 9 +++++++++ 2 files changed, 18 insertions(+), 4 deletions(-) diff --git a/include/zephyr/sys/util.h b/include/zephyr/sys/util.h index 97bfd3aa714..71ed1f7f45d 100644 --- a/include/zephyr/sys/util.h +++ b/include/zephyr/sys/util.h @@ -269,13 +269,18 @@ extern "C" { }) /** - * @brief Concatenate two tokens into one + * @brief Concatenate input arguments * - * Concatenate two tokens, @p x and @p y, into a combined token during the preprocessor pass. - * This can be used to, for ex., build an identifier out of two parts, + * Concatenate provided tokens into a combined token during the preprocessor pass. + * This can be used to, for ex., build an identifier out of multiple parts, * where one of those parts may be, for ex, a number, another macro, or a macro argument. + * + * @param ... Tokens to concatencate + * + * @return Concatenated token. */ -#define CONCAT(x, y) _DO_CONCAT(x, y) +#define CONCAT(...) \ + UTIL_CAT(_CONCAT_, NUM_VA_ARGS_LESS_1(__VA_ARGS__))(__VA_ARGS__) /** * @brief Value of @p x rounded up to the next multiple of @p align. diff --git a/include/zephyr/sys/util_internal.h b/include/zephyr/sys/util_internal.h index 2cde08332e2..d3adca60640 100644 --- a/include/zephyr/sys/util_internal.h +++ b/include/zephyr/sys/util_internal.h @@ -116,6 +116,15 @@ #define UTIL_EXPAND(...) __VA_ARGS__ #define UTIL_REPEAT(...) UTIL_LISTIFY(__VA_ARGS__) +#define _CONCAT_0(arg, ...) arg +#define _CONCAT_1(arg, ...) UTIL_CAT(arg, _CONCAT_0(__VA_ARGS__)) +#define _CONCAT_2(arg, ...) UTIL_CAT(arg, _CONCAT_1(__VA_ARGS__)) +#define _CONCAT_3(arg, ...) UTIL_CAT(arg, _CONCAT_2(__VA_ARGS__)) +#define _CONCAT_4(arg, ...) UTIL_CAT(arg, _CONCAT_3(__VA_ARGS__)) +#define _CONCAT_5(arg, ...) UTIL_CAT(arg, _CONCAT_4(__VA_ARGS__)) +#define _CONCAT_6(arg, ...) UTIL_CAT(arg, _CONCAT_5(__VA_ARGS__)) +#define _CONCAT_7(arg, ...) UTIL_CAT(arg, _CONCAT_6(__VA_ARGS__)) + /* Implementation details for NUM_VA_ARGS_LESS_1 */ #define NUM_VA_ARGS_LESS_1_IMPL( \ _ignored, \ From 04edca7a9f70b000dbb9345ef49d5aa7f0d692bd Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Krzysztof=20Chru=C5=9Bci=C5=84ski?= Date: Tue, 21 Nov 2023 12:27:32 +0100 Subject: [PATCH 2128/3723] tests: unit: util: Add test for CONCAT macro MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Add test for CONCAT. Signed-off-by: Krzysztof Chruściński --- tests/unit/util/main.c | 36 ++++++++++++++++++++++++++++++++++++ 1 file changed, 36 insertions(+) diff --git a/tests/unit/util/main.c b/tests/unit/util/main.c index fc8af19d34a..4486d89272a 100644 --- a/tests/unit/util/main.c +++ b/tests/unit/util/main.c @@ -717,4 +717,40 @@ ZTEST(util, test_mem_xor_128) zassert_mem_equal(expected_result, dst, 16); } +ZTEST(util, test_CONCAT) +{ +#define _CAT_PART1 1 +#define CAT_PART1 _CAT_PART1 +#define _CAT_PART2 2 +#define CAT_PART2 _CAT_PART2 +#define _CAT_PART3 3 +#define CAT_PART3 _CAT_PART3 +#define _CAT_PART4 4 +#define CAT_PART4 _CAT_PART4 +#define _CAT_PART5 5 +#define CAT_PART5 _CAT_PART5 +#define _CAT_PART6 6 +#define CAT_PART6 _CAT_PART6 +#define _CAT_PART7 7 +#define CAT_PART7 _CAT_PART7 +#define _CAT_PART8 8 +#define CAT_PART8 _CAT_PART8 + + zassert_equal(CONCAT(CAT_PART1), 1); + zassert_equal(CONCAT(CAT_PART1, CAT_PART2), 12); + zassert_equal(CONCAT(CAT_PART1, CAT_PART2, CAT_PART3), 123); + zassert_equal(CONCAT(CAT_PART1, CAT_PART2, CAT_PART3, CAT_PART4), 1234); + zassert_equal(CONCAT(CAT_PART1, CAT_PART2, CAT_PART3, CAT_PART4, CAT_PART5), 12345); + zassert_equal(CONCAT(CAT_PART1, CAT_PART2, CAT_PART3, CAT_PART4, CAT_PART5, CAT_PART6), + 123456); + zassert_equal(CONCAT(CAT_PART1, CAT_PART2, CAT_PART3, CAT_PART4, + CAT_PART5, CAT_PART6, CAT_PART7), + 1234567); + zassert_equal(CONCAT(CAT_PART1, CAT_PART2, CAT_PART3, CAT_PART4, + CAT_PART5, CAT_PART6, CAT_PART7, CAT_PART8), + 12345678); + + zassert_equal(CONCAT(CAT_PART1, CONCAT(CAT_PART2, CAT_PART3)), 123); +} + ZTEST_SUITE(util, NULL, NULL, NULL, NULL, NULL); From 5fb6e267f629dedb8382da6bcad8018b1bb8930a Mon Sep 17 00:00:00 2001 From: Gerard Marull-Paretas Date: Wed, 10 Jan 2024 12:54:55 +0100 Subject: [PATCH 2129/3723] arch: riscv: idle: trace idle and call wfi While going to idle may require SoC specific implementations, provide a more sensible default implementation. Signed-off-by: Gerard Marull-Paretas --- arch/riscv/core/cpu_idle.c | 16 +++++----------- 1 file changed, 5 insertions(+), 11 deletions(-) diff --git a/arch/riscv/core/cpu_idle.c b/arch/riscv/core/cpu_idle.c index 0c7f5f3dac7..0d8e4fedeb2 100644 --- a/arch/riscv/core/cpu_idle.c +++ b/arch/riscv/core/cpu_idle.c @@ -5,24 +5,18 @@ */ #include - -/* - * In RISC-V there is no conventional way to handle CPU power save. - * Each RISC-V SOC handles it in its own way. - * Hence, by default, arch_cpu_idle and arch_cpu_atomic_idle functions just - * unlock interrupts and return to the caller, without issuing any CPU power - * saving instruction. - * - * Nonetheless, define the default arch_cpu_idle and arch_cpu_atomic_idle - * functions as weak functions, so that they can be replaced at the SOC-level. - */ +#include void __weak arch_cpu_idle(void) { + sys_trace_idle(); irq_unlock(MSTATUS_IEN); + __asm__ volatile("wfi"); } void __weak arch_cpu_atomic_idle(unsigned int key) { + sys_trace_idle(); irq_unlock(key); + __asm__ volatile("wfi"); } From 1dbcef9d3c98dc84148572d91600a4a87e69cc93 Mon Sep 17 00:00:00 2001 From: Gerard Marull-Paretas Date: Wed, 10 Jan 2024 12:56:27 +0100 Subject: [PATCH 2130/3723] soc: riscv: espressif_esp32: use arch idle It is equivalent to the provided custom implementation. Signed-off-by: Gerard Marull-Paretas --- .../espressif_esp32/esp32c3/CMakeLists.txt | 1 - soc/riscv/espressif_esp32/esp32c3/idle.c | 27 ------------------- 2 files changed, 28 deletions(-) delete mode 100644 soc/riscv/espressif_esp32/esp32c3/idle.c diff --git a/soc/riscv/espressif_esp32/esp32c3/CMakeLists.txt b/soc/riscv/espressif_esp32/esp32c3/CMakeLists.txt index e97f71751ef..d6772eacbfc 100644 --- a/soc/riscv/espressif_esp32/esp32c3/CMakeLists.txt +++ b/soc/riscv/espressif_esp32/esp32c3/CMakeLists.txt @@ -1,7 +1,6 @@ # SPDX-License-Identifier: Apache-2.0 zephyr_sources( - idle.c vectors.S soc_irq.S soc_irq.c diff --git a/soc/riscv/espressif_esp32/esp32c3/idle.c b/soc/riscv/espressif_esp32/esp32c3/idle.c deleted file mode 100644 index 1bfb2832187..00000000000 --- a/soc/riscv/espressif_esp32/esp32c3/idle.c +++ /dev/null @@ -1,27 +0,0 @@ -/* - * Copyright (c) 2021 Espressif Systems (Shanghai) Co., Ltd. - * - * SPDX-License-Identifier: Apache-2.0 - */ - -#include -#include -#include - -/** - * @brief Power save idle routine - * - * This function will be called by the kernel idle loop or possibly within - * an implementation of _pm_save_idle in the kernel when the - * '_pm_save_flag' variable is non-zero. - */ -void arch_cpu_idle(void) -{ - /* curiously it arrives here with the interrupts masked - * so umask it before wait for an event - */ - arch_irq_unlock(MSTATUS_IEN); - - /* Wait for interrupt */ - __asm__ volatile("wfi"); -} From 7631e0ddfaa9ff2f286fb11983cbab2db510f900 Mon Sep 17 00:00:00 2001 From: Gerard Marull-Paretas Date: Wed, 10 Jan 2024 12:57:35 +0100 Subject: [PATCH 2131/3723] soc: riscv: riscv-privileged: remove redundant idle implementation Default RISC-V arch level implementation is equivalent. Signed-off-by: Gerard Marull-Paretas --- .../common/riscv-privileged/CMakeLists.txt | 2 - soc/riscv/common/riscv-privileged/idle.c | 53 ------------------- 2 files changed, 55 deletions(-) delete mode 100644 soc/riscv/common/riscv-privileged/idle.c diff --git a/soc/riscv/common/riscv-privileged/CMakeLists.txt b/soc/riscv/common/riscv-privileged/CMakeLists.txt index d1ec3daceb5..80be64cf2a9 100644 --- a/soc/riscv/common/riscv-privileged/CMakeLists.txt +++ b/soc/riscv/common/riscv-privileged/CMakeLists.txt @@ -7,5 +7,3 @@ zephyr_sources( soc_common_irq.c vector.S ) - -zephyr_sources_ifdef(CONFIG_RISCV_HAS_CPU_IDLE idle.c) diff --git a/soc/riscv/common/riscv-privileged/idle.c b/soc/riscv/common/riscv-privileged/idle.c deleted file mode 100644 index e61ce72b280..00000000000 --- a/soc/riscv/common/riscv-privileged/idle.c +++ /dev/null @@ -1,53 +0,0 @@ -/* - * Copyright (c) 2017 Jean-Paul Etienne - * Contributors: 2018 Antmicro - * - * SPDX-License-Identifier: Apache-2.0 - */ - -#include -#include -#include - -#include - -static ALWAYS_INLINE void riscv_idle(unsigned int key) -{ - sys_trace_idle(); - /* unlock interrupts */ - irq_unlock(key); - - /* Wait for interrupt */ - __asm__ volatile("wfi"); -} - -/** - * @brief Power save idle routine - * - * This function will be called by the kernel idle loop or possibly within - * an implementation of _pm_save_idle in the kernel when the - * '_pm_save_flag' variable is non-zero. - */ -void arch_cpu_idle(void) -{ - riscv_idle(MSTATUS_IEN); -} - -/** - * @brief Atomically re-enable interrupts and enter low power mode - * - * INTERNAL - * The requirements for arch_cpu_atomic_idle() are as follows: - * 1) The enablement of interrupts and entering a low-power mode needs to be - * atomic, i.e. there should be no period of time where interrupts are - * enabled before the processor enters a low-power mode. See the comments - * in k_lifo_get(), for example, of the race condition that - * occurs if this requirement is not met. - * - * 2) After waking up from the low-power mode, the interrupt lockout state - * must be restored as indicated in the 'imask' input parameter. - */ -void arch_cpu_atomic_idle(unsigned int key) -{ - riscv_idle(key); -} From f885763b507a29431c5b6dbdb44a410ec88c76bf Mon Sep 17 00:00:00 2001 From: Gerard Marull-Paretas Date: Wed, 10 Jan 2024 13:05:28 +0100 Subject: [PATCH 2132/3723] arch: riscv: drop RISCV_HAS_CPU_IDLE Because it was exclusively used by the "common" RISC-V privileged code to build CPU idle routines that are now handled by arch level code. Also, all platforms defaulted to "y", making it pointless in practice. Signed-off-by: Gerard Marull-Paretas --- arch/riscv/Kconfig | 5 ----- soc/riscv/andes_v5/ae350/Kconfig.defconfig.series | 3 --- soc/riscv/efinix_sapphire/Kconfig.defconfig | 4 ---- soc/riscv/gd_gd32/gd32vf103/Kconfig.defconfig.gd32vf103 | 3 --- soc/riscv/intel_niosv/niosv/Kconfig.defconfig.series | 3 --- soc/riscv/ite_ec/it8xxx2/Kconfig.defconfig.series | 3 --- soc/riscv/litex_vexriscv/Kconfig.defconfig | 3 --- soc/riscv/microchip_miv/miv/Kconfig.defconfig.series | 3 --- soc/riscv/microchip_miv/polarfire/Kconfig.defconfig.series | 3 --- soc/riscv/neorv32/Kconfig.defconfig | 3 --- soc/riscv/opentitan/Kconfig.defconfig | 3 --- soc/riscv/renode_virt/Kconfig.defconfig | 3 --- soc/riscv/sifive_freedom/e300/Kconfig.defconfig.series | 3 --- soc/riscv/sifive_freedom/u500/Kconfig.defconfig.series | 3 --- soc/riscv/sifive_freedom/u700/Kconfig.defconfig.series | 3 --- soc/riscv/starfive_jh71xx/jh71xx/Kconfig.defconfig.series | 3 --- soc/riscv/telink_tlsr/tlsr951x/Kconfig.defconfig.series | 4 ---- soc/riscv/virt/Kconfig.defconfig | 3 --- tests/kernel/context/src/main.c | 7 +++---- 19 files changed, 3 insertions(+), 62 deletions(-) diff --git a/arch/riscv/Kconfig b/arch/riscv/Kconfig index 80249670d09..60d33b18071 100644 --- a/arch/riscv/Kconfig +++ b/arch/riscv/Kconfig @@ -174,11 +174,6 @@ config RISCV_GENERIC_TOOLCHAIN Allow SOCs that have custom extended riscv ISA to still compile with generic riscv32 toolchain. -config RISCV_HAS_CPU_IDLE - bool "Does SOC has CPU IDLE instruction" - help - Does SOC has CPU IDLE instruction - config GEN_ISR_TABLES default y diff --git a/soc/riscv/andes_v5/ae350/Kconfig.defconfig.series b/soc/riscv/andes_v5/ae350/Kconfig.defconfig.series index 7bd679e5f45..699e54e66b8 100644 --- a/soc/riscv/andes_v5/ae350/Kconfig.defconfig.series +++ b/soc/riscv/andes_v5/ae350/Kconfig.defconfig.series @@ -24,9 +24,6 @@ config RISCV_GENERIC_TOOLCHAIN config RISCV_SOC_INTERRUPT_INIT default y -config RISCV_HAS_CPU_IDLE - default y - config RISCV_HAS_PLIC default y diff --git a/soc/riscv/efinix_sapphire/Kconfig.defconfig b/soc/riscv/efinix_sapphire/Kconfig.defconfig index 7018c0f11fb..08e2c851a21 100644 --- a/soc/riscv/efinix_sapphire/Kconfig.defconfig +++ b/soc/riscv/efinix_sapphire/Kconfig.defconfig @@ -9,10 +9,6 @@ config SOC config SYS_CLOCK_HW_CYCLES_PER_SEC default 100000000 -config RISCV_HAS_CPU_IDLE - bool - default y - config RISCV_SOC_INTERRUPT_INIT bool default y diff --git a/soc/riscv/gd_gd32/gd32vf103/Kconfig.defconfig.gd32vf103 b/soc/riscv/gd_gd32/gd32vf103/Kconfig.defconfig.gd32vf103 index 1e93f2703b2..4d65e4c43cd 100644 --- a/soc/riscv/gd_gd32/gd32vf103/Kconfig.defconfig.gd32vf103 +++ b/soc/riscv/gd_gd32/gd32vf103/Kconfig.defconfig.gd32vf103 @@ -20,9 +20,6 @@ config RISCV_SOC_MCAUSE_EXCEPTION_MASK config RISCV_SOC_INTERRUPT_INIT default y -config RISCV_HAS_CPU_IDLE - default y - config RISCV_GP default y diff --git a/soc/riscv/intel_niosv/niosv/Kconfig.defconfig.series b/soc/riscv/intel_niosv/niosv/Kconfig.defconfig.series index 8e8ea255202..15e98314c89 100644 --- a/soc/riscv/intel_niosv/niosv/Kconfig.defconfig.series +++ b/soc/riscv/intel_niosv/niosv/Kconfig.defconfig.series @@ -12,9 +12,6 @@ config SYS_CLOCK_HW_CYCLES_PER_SEC config NUM_IRQS # Platform interrupts IRQs index start from index 16 default 32 -config RISCV_HAS_CPU_IDLE - default y - config RISCV_GP default y diff --git a/soc/riscv/ite_ec/it8xxx2/Kconfig.defconfig.series b/soc/riscv/ite_ec/it8xxx2/Kconfig.defconfig.series index 7c5bc0ee897..0ed7358b631 100644 --- a/soc/riscv/ite_ec/it8xxx2/Kconfig.defconfig.series +++ b/soc/riscv/ite_ec/it8xxx2/Kconfig.defconfig.series @@ -22,9 +22,6 @@ config UART_NS16550_WA_ISR_REENABLE_INTERRUPT default y depends on UART_NS16550 -config RISCV_HAS_CPU_IDLE - default y - config FLASH_INIT_PRIORITY default 0 diff --git a/soc/riscv/litex_vexriscv/Kconfig.defconfig b/soc/riscv/litex_vexriscv/Kconfig.defconfig index 3efdf200ee7..f3e4c7cc79c 100644 --- a/soc/riscv/litex_vexriscv/Kconfig.defconfig +++ b/soc/riscv/litex_vexriscv/Kconfig.defconfig @@ -9,9 +9,6 @@ config SOC config SYS_CLOCK_HW_CYCLES_PER_SEC default 100000000 -config RISCV_HAS_CPU_IDLE - bool - config RISCV_HAS_PLIC bool diff --git a/soc/riscv/microchip_miv/miv/Kconfig.defconfig.series b/soc/riscv/microchip_miv/miv/Kconfig.defconfig.series index ef161321a5b..fc5aaa7c186 100644 --- a/soc/riscv/microchip_miv/miv/Kconfig.defconfig.series +++ b/soc/riscv/microchip_miv/miv/Kconfig.defconfig.series @@ -11,9 +11,6 @@ config SYS_CLOCK_HW_CYCLES_PER_SEC config RISCV_SOC_INTERRUPT_INIT default y -config RISCV_HAS_CPU_IDLE - default y - config RISCV_HAS_PLIC default y diff --git a/soc/riscv/microchip_miv/polarfire/Kconfig.defconfig.series b/soc/riscv/microchip_miv/polarfire/Kconfig.defconfig.series index e5c3a2ebce9..4399972dd9d 100644 --- a/soc/riscv/microchip_miv/polarfire/Kconfig.defconfig.series +++ b/soc/riscv/microchip_miv/polarfire/Kconfig.defconfig.series @@ -14,9 +14,6 @@ config SYS_CLOCK_HW_CYCLES_PER_SEC config RISCV_SOC_INTERRUPT_INIT default y -config RISCV_HAS_CPU_IDLE - default y - config RISCV_HAS_PLIC default y diff --git a/soc/riscv/neorv32/Kconfig.defconfig b/soc/riscv/neorv32/Kconfig.defconfig index 86aed551f5d..bc37ea74727 100644 --- a/soc/riscv/neorv32/Kconfig.defconfig +++ b/soc/riscv/neorv32/Kconfig.defconfig @@ -12,9 +12,6 @@ config SYS_CLOCK_HW_CYCLES_PER_SEC config NUM_IRQS default 32 -config RISCV_HAS_CPU_IDLE - default y - config RISCV_GP default y diff --git a/soc/riscv/opentitan/Kconfig.defconfig b/soc/riscv/opentitan/Kconfig.defconfig index cc27b7ffd6b..4ec6bffc4e7 100644 --- a/soc/riscv/opentitan/Kconfig.defconfig +++ b/soc/riscv/opentitan/Kconfig.defconfig @@ -12,9 +12,6 @@ config SYS_CLOCK_HW_CYCLES_PER_SEC config RISCV_SOC_INTERRUPT_INIT default y -config RISCV_HAS_CPU_IDLE - default y - config RISCV_HAS_PLIC default y diff --git a/soc/riscv/renode_virt/Kconfig.defconfig b/soc/riscv/renode_virt/Kconfig.defconfig index 89e226edbb1..5d2cd649b0b 100644 --- a/soc/riscv/renode_virt/Kconfig.defconfig +++ b/soc/riscv/renode_virt/Kconfig.defconfig @@ -12,9 +12,6 @@ config SYS_CLOCK_HW_CYCLES_PER_SEC config RISCV_SOC_INTERRUPT_INIT default y -config RISCV_HAS_CPU_IDLE - default y - config RISCV_HAS_PLIC default y diff --git a/soc/riscv/sifive_freedom/e300/Kconfig.defconfig.series b/soc/riscv/sifive_freedom/e300/Kconfig.defconfig.series index b2f16e5261d..661fe4ba1eb 100644 --- a/soc/riscv/sifive_freedom/e300/Kconfig.defconfig.series +++ b/soc/riscv/sifive_freedom/e300/Kconfig.defconfig.series @@ -12,9 +12,6 @@ config SYS_CLOCK_HW_CYCLES_PER_SEC config RISCV_SOC_INTERRUPT_INIT default y -config RISCV_HAS_CPU_IDLE - default y - config RISCV_HAS_PLIC default y diff --git a/soc/riscv/sifive_freedom/u500/Kconfig.defconfig.series b/soc/riscv/sifive_freedom/u500/Kconfig.defconfig.series index d6b94678686..3db750cb1a6 100644 --- a/soc/riscv/sifive_freedom/u500/Kconfig.defconfig.series +++ b/soc/riscv/sifive_freedom/u500/Kconfig.defconfig.series @@ -12,9 +12,6 @@ config SYS_CLOCK_HW_CYCLES_PER_SEC config RISCV_SOC_INTERRUPT_INIT default y -config RISCV_HAS_CPU_IDLE - default y - config RISCV_HAS_PLIC default y diff --git a/soc/riscv/sifive_freedom/u700/Kconfig.defconfig.series b/soc/riscv/sifive_freedom/u700/Kconfig.defconfig.series index 347ac14b551..83165d58870 100644 --- a/soc/riscv/sifive_freedom/u700/Kconfig.defconfig.series +++ b/soc/riscv/sifive_freedom/u700/Kconfig.defconfig.series @@ -12,9 +12,6 @@ config SYS_CLOCK_HW_CYCLES_PER_SEC config RISCV_SOC_INTERRUPT_INIT default y -config RISCV_HAS_CPU_IDLE - default y - config RISCV_HAS_PLIC default y diff --git a/soc/riscv/starfive_jh71xx/jh71xx/Kconfig.defconfig.series b/soc/riscv/starfive_jh71xx/jh71xx/Kconfig.defconfig.series index 77436b593e1..2dc45e1f347 100644 --- a/soc/riscv/starfive_jh71xx/jh71xx/Kconfig.defconfig.series +++ b/soc/riscv/starfive_jh71xx/jh71xx/Kconfig.defconfig.series @@ -12,9 +12,6 @@ config SYS_CLOCK_HW_CYCLES_PER_SEC config RISCV_SOC_INTERRUPT_INIT default y -config RISCV_HAS_CPU_IDLE - default y - config RISCV_HAS_PLIC default y diff --git a/soc/riscv/telink_tlsr/tlsr951x/Kconfig.defconfig.series b/soc/riscv/telink_tlsr/tlsr951x/Kconfig.defconfig.series index 23a78c9f0da..5b62959858e 100644 --- a/soc/riscv/telink_tlsr/tlsr951x/Kconfig.defconfig.series +++ b/soc/riscv/telink_tlsr/tlsr951x/Kconfig.defconfig.series @@ -15,10 +15,6 @@ config RISCV_SOC_INTERRUPT_INIT bool default y -config RISCV_HAS_CPU_IDLE - bool - default y - config RISCV_HAS_PLIC bool default y diff --git a/soc/riscv/virt/Kconfig.defconfig b/soc/riscv/virt/Kconfig.defconfig index 9773586e922..e0982bc185b 100644 --- a/soc/riscv/virt/Kconfig.defconfig +++ b/soc/riscv/virt/Kconfig.defconfig @@ -12,9 +12,6 @@ config SYS_CLOCK_HW_CYCLES_PER_SEC config RISCV_SOC_INTERRUPT_INIT default y -config RISCV_HAS_CPU_IDLE - default y - config RISCV_HAS_PLIC default y diff --git a/tests/kernel/context/src/main.c b/tests/kernel/context/src/main.c index 2e3ad1a36c9..a138e012280 100644 --- a/tests/kernel/context/src/main.c +++ b/tests/kernel/context/src/main.c @@ -72,11 +72,10 @@ extern const int32_t z_sys_timer_irq_for_test; #endif -/* Cortex-M1, Nios II, and RISCV without CONFIG_RISCV_HAS_CPU_IDLE - * do have a power saving instruction, so k_cpu_idle() returns immediately +/* Cortex-M1 and Nios II do have a power saving instruction, so k_cpu_idle() + * returns immediately */ -#if !defined(CONFIG_CPU_CORTEX_M1) && !defined(CONFIG_NIOS2) && \ - (!defined(CONFIG_RISCV) || defined(CONFIG_RISCV_HAS_CPU_IDLE)) +#if !defined(CONFIG_CPU_CORTEX_M1) && !defined(CONFIG_NIOS2) #define HAS_POWERSAVE_INSTRUCTION #endif From 5bda339058cf62e3b30a282ab0f468bd1b60ee79 Mon Sep 17 00:00:00 2001 From: Mahesh Mahadevan Date: Thu, 11 Jan 2024 17:00:42 +0000 Subject: [PATCH 2133/3723] Revert "drivers: usb: device: add start of frame notifications to nxp mcux driver" This reverts commit 21c9c4abfe5c858b1c5d6c45a2c919d81b12a02b. Signed-off-by: Mahesh Mahadevan --- drivers/usb/device/usb_dc_mcux.c | 3 --- 1 file changed, 3 deletions(-) diff --git a/drivers/usb/device/usb_dc_mcux.c b/drivers/usb/device/usb_dc_mcux.c index dc0868ffd5d..0667486b628 100644 --- a/drivers/usb/device/usb_dc_mcux.c +++ b/drivers/usb/device/usb_dc_mcux.c @@ -910,9 +910,6 @@ static void usb_mcux_thread_main(void *arg1, void *arg2, void *arg3) case kUSB_DeviceNotifyResume: dev_state.status_cb(USB_DC_RESUME, NULL); break; - case kUSB_DeviceNotifySOF: - dev_state.status_cb(USB_DC_SOF, NULL); - break; default: ep_abs_idx = EP_ABS_IDX(msg.code); From 0a26da9b084d510766d8e5a3d9461c83900b34f6 Mon Sep 17 00:00:00 2001 From: Mahesh Mahadevan Date: Thu, 11 Jan 2024 21:17:37 +0000 Subject: [PATCH 2134/3723] Revert "modules: hal_nxp: usb: enable sof notifications" This reverts commit 2b91d62c0ef7be59c5de18018b66fc31adc26464. Signed-off-by: Mahesh Mahadevan --- modules/hal_nxp/usb/usb_device_config.h | 5 ----- 1 file changed, 5 deletions(-) diff --git a/modules/hal_nxp/usb/usb_device_config.h b/modules/hal_nxp/usb/usb_device_config.h index 09af4fe7be6..31a62ffbfeb 100644 --- a/modules/hal_nxp/usb/usb_device_config.h +++ b/modules/hal_nxp/usb/usb_device_config.h @@ -52,9 +52,4 @@ BUILD_ASSERT(NUM_INSTS <= 1, "Only one USB device supported"); /* Number of endpoints supported */ #define USB_DEVICE_CONFIG_ENDPOINTS (DT_INST_PROP(0, num_bidir_endpoints)) -/* Start of Frame (SOF) Notifications are required by the zephyr usb audio driver */ -#ifdef CONFIG_USB_DEVICE_AUDIO -#define USB_DEVICE_CONFIG_SOF_NOTIFICATIONS (1U) -#endif /* CONFIG_USB_DEVICE_AUDIO */ - #endif /* __USB_DEVICE_CONFIG_H__ */ From 56de0a347e6965b0c5612cfd31725d75535532b4 Mon Sep 17 00:00:00 2001 From: Ajay Parida Date: Mon, 8 Jan 2024 16:57:32 +0530 Subject: [PATCH 2135/3723] net: mgmt: Provide Regulatory channel info Updated to provide regulatory channel information along with country code. Signed-off-by: Ajay Parida --- include/zephyr/net/wifi_mgmt.h | 20 ++++++++++++++++++++ subsys/net/l2/wifi/wifi_shell.c | 19 +++++++++++++++++-- 2 files changed, 37 insertions(+), 2 deletions(-) diff --git a/include/zephyr/net/wifi_mgmt.h b/include/zephyr/net/wifi_mgmt.h index 8fb35647c36..0c64cab3c01 100644 --- a/include/zephyr/net/wifi_mgmt.h +++ b/include/zephyr/net/wifi_mgmt.h @@ -548,6 +548,22 @@ enum wifi_mgmt_op { WIFI_MGMT_SET = 1, }; +#define MAX_REG_CHAN_NUM 42 + +/** Per-channel regulatory attributes */ +struct wifi_reg_chan_info { + /** Center frequency in MHz */ + unsigned short center_frequency; + /** Maximum transmission power (in dBm) */ + unsigned short max_power:8; + /** Is channel supported or not */ + unsigned short supported:1; + /** Passive transmissions only */ + unsigned short passive_only:1; + /** Is a DFS channel */ + unsigned short dfs:1; +} __packed; + /** Regulatory domain information or configuration */ struct wifi_reg_domain { /* Regulatory domain operation */ @@ -556,6 +572,10 @@ struct wifi_reg_domain { bool force; /** Country code: ISO/IEC 3166-1 alpha-2 */ uint8_t country_code[WIFI_COUNTRY_CODE_LEN]; + /** Number of channels supported */ + unsigned int num_channels; + /** Channels information */ + struct wifi_reg_chan_info *chan_info; }; /** Wi-Fi TWT sleep states */ diff --git a/subsys/net/l2/wifi/wifi_shell.c b/subsys/net/l2/wifi/wifi_shell.c index b05e5cd27b8..718144618d6 100644 --- a/subsys/net/l2/wifi/wifi_shell.c +++ b/subsys/net/l2/wifi/wifi_shell.c @@ -65,6 +65,7 @@ static struct { static uint32_t scan_result; static struct net_mgmt_event_callback wifi_shell_mgmt_cb; +static struct wifi_reg_chan_info chan_info[MAX_REG_CHAN_NUM]; static K_MUTEX_DEFINE(wifi_ap_sta_list_lock); struct wifi_ap_sta_node { @@ -135,7 +136,6 @@ static void handle_wifi_scan_result(struct net_mgmt_event_callback *cb) wifi_mfp_txt(entry->mfp)); } -#ifdef CONFIG_WIFI_MGMT_RAW_SCAN_RESULTS static int wifi_freq_to_channel(int frequency) { int channel = 0; @@ -157,6 +157,7 @@ static int wifi_freq_to_channel(int frequency) return channel; } +#ifdef CONFIG_WIFI_MGMT_RAW_SCAN_RESULTS static enum wifi_frequency_bands wifi_freq_to_band(int frequency) { enum wifi_frequency_bands band = WIFI_FREQ_BAND_2_4_GHZ; @@ -1295,9 +1296,10 @@ static int cmd_wifi_reg_domain(const struct shell *sh, size_t argc, { struct net_if *iface = net_if_get_first_wifi(); struct wifi_reg_domain regd = {0}; - int ret; + int ret, chan_idx = 0; if (argc == 1) { + (®d)->chan_info = &chan_info[0]; regd.oper = WIFI_MGMT_GET; } else if (argc >= 2 && argc <= 3) { regd.oper = WIFI_MGMT_SET; @@ -1342,6 +1344,19 @@ static int cmd_wifi_reg_domain(const struct shell *sh, size_t argc, if (regd.oper == WIFI_MGMT_GET) { shell_fprintf(sh, SHELL_NORMAL, "Wi-Fi Regulatory domain is: %c%c\n", regd.country_code[0], regd.country_code[1]); + shell_fprintf(sh, SHELL_NORMAL, + "\t

\t\t" + "\t\t\n"); + for (chan_idx = 0; chan_idx < regd.num_channels; chan_idx++) { + shell_fprintf(sh, SHELL_NORMAL, + " %d\t\t\t\%d\t\t\t\%s\t\t\t%d\t\t\t%s\t\t\t\t%s\n", + wifi_freq_to_channel(chan_info[chan_idx].center_frequency), + chan_info[chan_idx].center_frequency, + chan_info[chan_idx].supported ? "y" : "n", + chan_info[chan_idx].max_power, + chan_info[chan_idx].passive_only ? "y" : "n", + chan_info[chan_idx].dfs ? "y" : "n"); + } } else { shell_fprintf(sh, SHELL_NORMAL, "Wi-Fi Regulatory domain set to: %c%c\n", regd.country_code[0], regd.country_code[1]); From a9afc5a7b8d58885eb57749360998746c144821f Mon Sep 17 00:00:00 2001 From: Yuval Peress Date: Thu, 4 Jan 2024 02:08:59 -0700 Subject: [PATCH 2136/3723] emul: Add support for non-bus emulators Adds a stub API for a non bus emulators. The stub is used to keep the rest of the emulation consistent. Signed-off-by: Yuval Peress --- include/zephyr/drivers/emul.h | 22 ++++++++++++++++------ subsys/emul/emul.c | 2 ++ 2 files changed, 18 insertions(+), 6 deletions(-) diff --git a/include/zephyr/drivers/emul.h b/include/zephyr/drivers/emul.h index 7c306de9889..6dfb281e465 100644 --- a/include/zephyr/drivers/emul.h +++ b/include/zephyr/drivers/emul.h @@ -36,6 +36,7 @@ enum emul_bus_type { EMUL_BUS_TYPE_I2C, EMUL_BUS_TYPE_ESPI, EMUL_BUS_TYPE_SPI, + EMUL_BUS_TYPE_NONE, }; /** @@ -62,6 +63,14 @@ struct emul_list_for_bus { */ typedef int (*emul_init_t)(const struct emul *emul, const struct device *parent); +/** + * Emulator API stub when an emulator is not actually placed on a bus. + */ +struct no_bus_emul { + void *api; + uint16_t addr; +}; + /** An emulator instance - represents the *target* emulated device/peripheral that is * interacted with through an emulated bus. Instances of emulated bus nodes (e.g. i2c_emul) * and emulators (i.e. struct emul) are exactly 1..1 @@ -82,6 +91,7 @@ struct emul { struct i2c_emul *i2c; struct espi_emul *espi; struct spi_emul *spi; + struct no_bus_emul *none; } bus; /** Address of the API structure exposed by the emulator instance */ const void *backend_api; @@ -101,10 +111,10 @@ struct emul { #define Z_EMUL_REG_BUS_IDENTIFIER(_dev_node_id) (_CONCAT(_CONCAT(__emulreg_, _dev_node_id), _bus)) /* Conditionally places text based on what bus _dev_node_id is on. */ -#define Z_EMUL_BUS(_dev_node_id, _i2c, _espi, _spi) \ +#define Z_EMUL_BUS(_dev_node_id, _i2c, _espi, _spi, _none) \ COND_CODE_1(DT_ON_BUS(_dev_node_id, i2c), (_i2c), \ (COND_CODE_1(DT_ON_BUS(_dev_node_id, espi), (_espi), \ - (COND_CODE_1(DT_ON_BUS(_dev_node_id, spi), (_spi), (-EINVAL)))))) + (COND_CODE_1(DT_ON_BUS(_dev_node_id, spi), (_spi), (_none)))))) /** * @brief Define a new emulator * @@ -120,10 +130,10 @@ struct emul { * @param _backend_api emulator-specific backend api */ #define EMUL_DT_DEFINE(node_id, init_fn, data_ptr, cfg_ptr, bus_api, _backend_api) \ - static struct Z_EMUL_BUS(node_id, i2c_emul, espi_emul, spi_emul) \ + static struct Z_EMUL_BUS(node_id, i2c_emul, espi_emul, spi_emul, no_bus_emul) \ Z_EMUL_REG_BUS_IDENTIFIER(node_id) = { \ .api = bus_api, \ - .Z_EMUL_BUS(node_id, addr, chipsel, chipsel) = DT_REG_ADDR(node_id), \ + .Z_EMUL_BUS(node_id, addr, chipsel, chipsel, addr) = DT_REG_ADDR(node_id), \ }; \ const STRUCT_SECTION_ITERABLE(emul, EMUL_DT_NAME_GET(node_id)) \ __used = { \ @@ -132,8 +142,8 @@ struct emul { .cfg = (cfg_ptr), \ .data = (data_ptr), \ .bus_type = Z_EMUL_BUS(node_id, EMUL_BUS_TYPE_I2C, EMUL_BUS_TYPE_ESPI, \ - EMUL_BUS_TYPE_SPI), \ - .bus = {.Z_EMUL_BUS(node_id, i2c, espi, spi) = \ + EMUL_BUS_TYPE_SPI, EMUL_BUS_TYPE_NONE), \ + .bus = {.Z_EMUL_BUS(node_id, i2c, espi, spi, none) = \ &(Z_EMUL_REG_BUS_IDENTIFIER(node_id))}, \ .backend_api = (_backend_api), \ }; diff --git a/subsys/emul/emul.c b/subsys/emul/emul.c index 96adb888dd2..a3f534febb3 100644 --- a/subsys/emul/emul.c +++ b/subsys/emul/emul.c @@ -55,6 +55,8 @@ int emul_init_for_bus(const struct device *dev) case EMUL_BUS_TYPE_SPI: emul->bus.spi->target = emul; break; + case EMUL_BUS_TYPE_NONE: + break; } int rc = emul->init(emul, dev); From af5ea66c9999251b9a2af03b99e227d48284b6ca Mon Sep 17 00:00:00 2001 From: Yuval Peress Date: Fri, 5 Jan 2024 12:17:08 -0700 Subject: [PATCH 2137/3723] bbram: emul: Add backend API Add a backend API which allows us to set and get data Signed-off-by: Yuval Peress --- include/zephyr/drivers/emul_bbram.h | 96 +++++++++++++++++++++++++++++ 1 file changed, 96 insertions(+) create mode 100644 include/zephyr/drivers/emul_bbram.h diff --git a/include/zephyr/drivers/emul_bbram.h b/include/zephyr/drivers/emul_bbram.h new file mode 100644 index 00000000000..441f101c934 --- /dev/null +++ b/include/zephyr/drivers/emul_bbram.h @@ -0,0 +1,96 @@ +/* + * Copyright 2024 Google LLC + * SPDX-License-Identifier: Apache-2.0 + */ + +#ifndef INCLUDE_ZEPHYR_DRIVERS_EMUL_BBRAM_H_ +#define INCLUDE_ZEPHYR_DRIVERS_EMUL_BBRAM_H_ + +#include + +#include + +/** + * @brief BBRAM emulator backend API + * @defgroup bbram_emulator_backend BBRAM emulator backend API + * @ingroup io_interfaces + * @{ + */ + +/** + * @cond INTERNAL_HIDDEN + * + * These are for internal use only, so skip these in public documentation. + */ + +__subsystem struct emul_bbram_backend_api { + /** Sets the data */ + int (*set_data)(const struct emul *target, size_t offset, size_t count, + const uint8_t *data); + /** Checks the data */ + int (*get_data)(const struct emul *target, size_t offset, size_t count, uint8_t *data); +}; + +/** + * @endcond + */ + +/** + * @brief Set the expected data in the bbram region + * + * @param target Pointer to the emulator instance to operate on + * @param offset Offset within the memory to set + * @param count Number of bytes to write + * @param data The data to write + * @return 0 if successful + * @return -ENOTSUP if no backend API or if the set_data function isn't implemented + * @return -ERANGE if the destination address is out of range. + */ +static inline int emul_bbram_backend_set_data(const struct emul *target, size_t offset, + size_t count, const uint8_t *data) +{ + if (target == NULL || target->backend_api == NULL) { + return -ENOTSUP; + } + + struct emul_bbram_backend_api *api = (struct emul_bbram_backend_api *)target->backend_api; + + if (api->set_data == NULL) { + return -ENOTSUP; + } + + return api->set_data(target, offset, count, data); +} + +/** + * @brief Get the expected data in the bbram region + * + * @param target Pointer to the emulator instance to operate on + * @param offset Offset within the memory to get + * @param count Number of bytes to read + * @param data The data buffer to hold the result + * @return 0 if successful + * @return -ENOTSUP if no backend API or if the get_data function isn't implemented + * @return -ERANGE if the address is out of range. + */ +static inline int emul_bbram_backend_get_data(const struct emul *target, size_t offset, + size_t count, uint8_t *data) +{ + if (target == NULL || target->backend_api == NULL) { + return -ENOTSUP; + } + + struct emul_bbram_backend_api *api = (struct emul_bbram_backend_api *)target->backend_api; + + if (api->get_data == NULL) { + return -ENOTSUP; + } + + return api->get_data(target, offset, count, data); +} + +/** + * @} + */ + +#endif /* INCLUDE_ZEPHYR_DRIVERS_EMUL_BBRAM_H_ */ From 59675bf682dde86c4b68f539062b1c7ba21f0fbd Mon Sep 17 00:00:00 2001 From: Yuval Peress Date: Fri, 5 Jan 2024 12:17:58 -0700 Subject: [PATCH 2138/3723] bbram: it8xxx2: Add emulator implementation Add an emulator that supports reading and writing to the it8xxx2 bbram. Signed-off-by: Yuval Peress --- drivers/bbram/CMakeLists.txt | 2 + drivers/bbram/Kconfig.it8xxx2 | 8 ++++ drivers/bbram/bbram_it8xxx2.c | 42 +++++++++++++-------- drivers/bbram/bbram_it8xxx2_emul.c | 60 ++++++++++++++++++++++++++++++ drivers/bbram/it8xxx2.h | 36 ++++++++++++++++++ 5 files changed, 132 insertions(+), 16 deletions(-) create mode 100644 drivers/bbram/bbram_it8xxx2_emul.c create mode 100644 drivers/bbram/it8xxx2.h diff --git a/drivers/bbram/CMakeLists.txt b/drivers/bbram/CMakeLists.txt index 538384e9d14..2365cf4c8c5 100644 --- a/drivers/bbram/CMakeLists.txt +++ b/drivers/bbram/CMakeLists.txt @@ -8,6 +8,8 @@ zephyr_library_sources_ifdef(CONFIG_BBRAM_SHELL bbram_shell.c) zephyr_library_sources_ifdef(CONFIG_USERSPACE bbram_handlers.c) zephyr_library_sources_ifdef(CONFIG_BBRAM_NPCX bbram_npcx.c) zephyr_library_sources_ifdef(CONFIG_BBRAM_IT8XXX2 bbram_it8xxx2.c) +zephyr_library_sources_ifdef(CONFIG_BBRAM_IT8XXX2_EMUL bbram_it8xxx2_emul.c) +zephyr_library_include_directories_ifdef(CONFIG_BBRAM_IT8XXX2 .) zephyr_library_sources_ifdef(CONFIG_BBRAM_EMUL bbram_emul.c) zephyr_library_sources_ifdef(CONFIG_BBRAM_MICROCHIP_MCP7940N bbram_microchip_mcp7940n.c) zephyr_library_sources_ifdef(CONFIG_BBRAM_XEC bbram_xec.c) diff --git a/drivers/bbram/Kconfig.it8xxx2 b/drivers/bbram/Kconfig.it8xxx2 index a3af7e9537b..64ed29f1a52 100644 --- a/drivers/bbram/Kconfig.it8xxx2 +++ b/drivers/bbram/Kconfig.it8xxx2 @@ -8,3 +8,11 @@ config BBRAM_IT8XXX2 help This option enables the BBRAM driver for RISCV_ITE family of processors. + +config BBRAM_IT8XXX2_EMUL + bool "Emulator for the ITE IT81202 BBRAM driver" + default y + depends on BBRAM_IT8XXX2 + depends on EMUL + help + Enable the emulator for the ITE IT81202 BBRAM. diff --git a/drivers/bbram/bbram_it8xxx2.c b/drivers/bbram/bbram_it8xxx2.c index cae7715e702..cecf555ee8d 100644 --- a/drivers/bbram/bbram_it8xxx2.c +++ b/drivers/bbram/bbram_it8xxx2.c @@ -12,30 +12,34 @@ #include #include +#ifndef CONFIG_BBRAM_IT8XXX2_EMUL #include +#else +/* Emulation register values */ +enum bram_indices { + BRAM_IDX_VALID_FLAGS0, + BRAM_IDX_VALID_FLAGS1, + BRAM_IDX_VALID_FLAGS2, + BRAM_IDX_VALID_FLAGS3, +}; +#endif + +#include "it8xxx2.h" -LOG_MODULE_REGISTER(bbram, CONFIG_BBRAM_LOG_LEVEL); +LOG_MODULE_REGISTER(it8xxx2_bbram, CONFIG_BBRAM_LOG_LEVEL); -#define BRAM_VALID_MAGIC 0x4252414D /* "BRAM" */ +#define BRAM_VALID_MAGIC 0x4252414D /* "BRAM" */ #define BRAM_VALID_MAGIC_FIELD0 (BRAM_VALID_MAGIC & 0xff) #define BRAM_VALID_MAGIC_FIELD1 ((BRAM_VALID_MAGIC >> 8) & 0xff) #define BRAM_VALID_MAGIC_FIELD2 ((BRAM_VALID_MAGIC >> 16) & 0xff) #define BRAM_VALID_MAGIC_FIELD3 ((BRAM_VALID_MAGIC >> 24) & 0xff) -/** Device config */ -struct bbram_it8xxx2_config { - /** BBRAM base address */ - uintptr_t base_addr; - /** BBRAM size (Unit:bytes) */ - int size; -}; - static int bbram_it8xxx2_read(const struct device *dev, size_t offset, size_t size, uint8_t *data) { const struct bbram_it8xxx2_config *config = dev->config; if (size < 1 || offset + size > config->size) { - return -EFAULT; + return -EINVAL; } bytecpy(data, ((uint8_t *)config->base_addr + offset), size); @@ -48,16 +52,25 @@ static int bbram_it8xxx2_write(const struct device *dev, size_t offset, size_t s const struct bbram_it8xxx2_config *config = dev->config; if (size < 1 || offset + size > config->size) { - return -EFAULT; + return -EINVAL; } bytecpy(((uint8_t *)config->base_addr + offset), data, size); return 0; } +static int bbram_it8xxx2_size(const struct device *dev, size_t *size) +{ + const struct bbram_it8xxx2_config *config = dev->config; + + *size = config->size; + return 0; +} + static const struct bbram_driver_api bbram_it8xxx2_driver_api = { .read = bbram_it8xxx2_read, .write = bbram_it8xxx2_write, + .get_size = bbram_it8xxx2_size, }; static int bbram_it8xxx2_init(const struct device *dev) @@ -91,10 +104,7 @@ static int bbram_it8xxx2_init(const struct device *dev) } #define BBRAM_INIT(inst) \ - static const struct bbram_it8xxx2_config bbram_cfg_##inst = { \ - .base_addr = DT_INST_REG_ADDR(inst), \ - .size = DT_INST_REG_SIZE(inst), \ - }; \ + BBRAM_IT8XXX2_DECL_CONFIG(inst); \ DEVICE_DT_INST_DEFINE(inst, bbram_it8xxx2_init, NULL, NULL, &bbram_cfg_##inst, \ PRE_KERNEL_1, CONFIG_BBRAM_INIT_PRIORITY, \ &bbram_it8xxx2_driver_api); diff --git a/drivers/bbram/bbram_it8xxx2_emul.c b/drivers/bbram/bbram_it8xxx2_emul.c new file mode 100644 index 00000000000..901a09835f1 --- /dev/null +++ b/drivers/bbram/bbram_it8xxx2_emul.c @@ -0,0 +1,60 @@ +/* + * Copyright (c) 2024 Google Inc + * SPDX-License-Identifier: Apache-2.0 + */ + +#include +#include +#include + +#include "it8xxx2.h" + +#define DT_DRV_COMPAT ite_it8xxx2_bbram + +struct bbram_it8xxx2_emul_config { + const struct device *dev; +}; + +#define GET_CONFIG(target) \ + ((const struct bbram_it8xxx2_config \ + *)(((const struct bbram_it8xxx2_emul_config *)((target)->cfg))->dev->config)) + +static int it8xxx2_emul_backend_set_data(const struct emul *target, size_t offset, size_t count, + const uint8_t *buffer) +{ + const struct bbram_it8xxx2_config *config = GET_CONFIG(target); + + if (offset + count > config->size) { + return -ERANGE; + } + + bytecpy(((uint8_t *)config->base_addr + offset), buffer, count); + return 0; +} + +static int it8xxx2_emul_backend_get_data(const struct emul *target, size_t offset, size_t count, + uint8_t *buffer) +{ + const struct bbram_it8xxx2_config *config = GET_CONFIG(target); + + if (offset + count > config->size) { + return -ERANGE; + } + + bytecpy(buffer, ((uint8_t *)config->base_addr + offset), count); + return 0; +} + +static const struct emul_bbram_backend_api it8xxx2_emul_backend_api = { + .set_data = it8xxx2_emul_backend_set_data, + .get_data = it8xxx2_emul_backend_get_data, +}; + +#define BBRAM_EMUL_INIT(inst) \ + static struct bbram_it8xxx2_emul_config bbram_it8xxx2_emul_config_##inst = { \ + .dev = DEVICE_DT_INST_GET(inst), \ + }; \ + EMUL_DT_INST_DEFINE(inst, NULL, NULL, &bbram_it8xxx2_emul_config_##inst, NULL, \ + &it8xxx2_emul_backend_api) + +DT_INST_FOREACH_STATUS_OKAY(BBRAM_EMUL_INIT); diff --git a/drivers/bbram/it8xxx2.h b/drivers/bbram/it8xxx2.h new file mode 100644 index 00000000000..d5e905d4f72 --- /dev/null +++ b/drivers/bbram/it8xxx2.h @@ -0,0 +1,36 @@ +/* + * Copyright (c) 2024 Google Inc + * SPDX-License-Identifier: Apache-2.0 + */ + +#ifndef INCLUDE_ZEPHYR_DRIVERS_BBRAM_IT8XXX2_H_ +#define INCLUDE_ZEPHYR_DRIVERS_BBRAM_IT8XXX2_H_ + +#include + +#include + +/** Device config */ +struct bbram_it8xxx2_config { + /** BBRAM base address */ + uintptr_t base_addr; + /** BBRAM size (Unit:bytes) */ + int size; +}; + +#ifdef CONFIG_BBRAM_IT8XXX2_EMUL +#define BBRAM_IT8XXX2_DECL_CONFIG(inst) \ + static uint8_t bbram_it8xxx2_emul_buffer_##inst[DT_INST_REG_SIZE(inst)]; \ + static const struct bbram_it8xxx2_config bbram_cfg_##inst = { \ + .base_addr = (uintptr_t)bbram_it8xxx2_emul_buffer_##inst, \ + .size = DT_INST_REG_SIZE(inst), \ + } +#else +#define BBRAM_IT8XXX2_DECL_CONFIG(inst) \ + static const struct bbram_it8xxx2_config bbram_cfg_##inst = { \ + .base_addr = DT_INST_REG_ADDR(inst), \ + .size = DT_INST_REG_SIZE(inst), \ + } +#endif + +#endif /* INCLUDE_ZEPHYR_DRIVERS_BBRAM_IT8XXX2_H_ */ From 69dfb2fee3c20129e0afa597c6d91a5fc7dba24c Mon Sep 17 00:00:00 2001 From: Yuval Peress Date: Fri, 5 Jan 2024 12:18:42 -0700 Subject: [PATCH 2139/3723] bbram: mcp7940c: Add emulator Add an emulator for the mcp7940c BBRAM that supports reading and writing. Signed-off-by: Yuval Peress --- drivers/bbram/CMakeLists.txt | 1 + drivers/bbram/Kconfig.microchip | 9 ++ drivers/bbram/bbram_microchip_mcp7940n.c | 4 +- drivers/bbram/bbram_microchip_mcp7940n_emul.c | 150 ++++++++++++++++++ 4 files changed, 162 insertions(+), 2 deletions(-) create mode 100644 drivers/bbram/bbram_microchip_mcp7940n_emul.c diff --git a/drivers/bbram/CMakeLists.txt b/drivers/bbram/CMakeLists.txt index 2365cf4c8c5..14ed29b9b79 100644 --- a/drivers/bbram/CMakeLists.txt +++ b/drivers/bbram/CMakeLists.txt @@ -12,5 +12,6 @@ zephyr_library_sources_ifdef(CONFIG_BBRAM_IT8XXX2_EMUL bbram_it8xxx2_emul.c) zephyr_library_include_directories_ifdef(CONFIG_BBRAM_IT8XXX2 .) zephyr_library_sources_ifdef(CONFIG_BBRAM_EMUL bbram_emul.c) zephyr_library_sources_ifdef(CONFIG_BBRAM_MICROCHIP_MCP7940N bbram_microchip_mcp7940n.c) +zephyr_library_sources_ifdef(CONFIG_BBRAM_MICROCHIP_MCP7940N_EMUL bbram_microchip_mcp7940n_emul.c) zephyr_library_sources_ifdef(CONFIG_BBRAM_XEC bbram_xec.c) zephyr_library_sources_ifdef(CONFIG_BBRAM_STM32 bbram_stm32.c) diff --git a/drivers/bbram/Kconfig.microchip b/drivers/bbram/Kconfig.microchip index 015b2bcb124..35fd828e6a5 100644 --- a/drivers/bbram/Kconfig.microchip +++ b/drivers/bbram/Kconfig.microchip @@ -8,3 +8,12 @@ config BBRAM_MICROCHIP_MCP7940N select I2C help Enable driver for Microchip MCP7940N SRAM based battery-backed RAM. + +config BBRAM_MICROCHIP_MCP7940N_EMUL + bool "Emulator for the Microchip MCP7940N SRAM BBRAM driver" + default y + depends on BBRAM_MICROCHIP_MCP7940N + depends on EMUL + help + Enable the emulator for the Microchip MCP7940N SRAM based + battery-backed RAM. diff --git a/drivers/bbram/bbram_microchip_mcp7940n.c b/drivers/bbram/bbram_microchip_mcp7940n.c index c3b538c842f..ff5b7850576 100644 --- a/drivers/bbram/bbram_microchip_mcp7940n.c +++ b/drivers/bbram/bbram_microchip_mcp7940n.c @@ -153,7 +153,7 @@ static int microchip_mcp7940n_bbram_read(const struct device *dev, size_t offset size_t i = 0; int32_t rc = 0; - if ((offset + size) > MICROCHIP_MCP7940N_SRAM_SIZE) { + if (size == 0 || (offset + size) > MICROCHIP_MCP7940N_SRAM_SIZE) { return -EINVAL; } @@ -186,7 +186,7 @@ static int microchip_mcp7940n_bbram_write(const struct device *dev, size_t offse size_t i = 0; int32_t rc = 0; - if ((offset + size) > MICROCHIP_MCP7940N_SRAM_SIZE) { + if (size == 0 || (offset + size) > MICROCHIP_MCP7940N_SRAM_SIZE) { return -EINVAL; } diff --git a/drivers/bbram/bbram_microchip_mcp7940n_emul.c b/drivers/bbram/bbram_microchip_mcp7940n_emul.c new file mode 100644 index 00000000000..56a84825948 --- /dev/null +++ b/drivers/bbram/bbram_microchip_mcp7940n_emul.c @@ -0,0 +1,150 @@ +/* + * Copyright 2024 Google LLC + * SPDX-License-Identifier: Apache-2.0 + */ + +#define DT_DRV_COMPAT microchip_mcp7940n + +#include +#include +#include +#include +#include +#include + +LOG_MODULE_DECLARE(bbram_microchip_mcp7940n, CONFIG_BBRAM_LOG_LEVEL); + +#define MICROCHIP_MCP7940N_SRAM_OFFSET 0x20 +#define MICROCHIP_MCP7940N_SRAM_SIZE 64 +#define MICROCHIP_MCP7940N_RTCWKDAY_REGISTER_ADDRESS 0x03 +#define MICROCHIP_MCP7940N_RTCWKDAY_VBATEN_BIT BIT(3) +#define MICROCHIP_MCP7940N_RTCWKDAY_PWRFAIL_BIT BIT(4) + +struct mcp7940n_emul_cfg { +}; + +struct mcp7940n_emul_data { + uint8_t rtcwkday; + uint8_t data[MICROCHIP_MCP7940N_SRAM_SIZE]; +}; + +static int mcp7940n_emul_init(const struct emul *target, const struct device *parent) +{ + ARG_UNUSED(target); + ARG_UNUSED(parent); + return 0; +} + +static int mcp7940n_emul_transfer_i2c(const struct emul *target, struct i2c_msg *msgs, int num_msgs, + int addr) +{ + struct mcp7940n_emul_data *data = target->data; + + i2c_dump_msgs_rw(target->dev, msgs, num_msgs, addr, false); + + if (num_msgs < 1) { + LOG_ERR("Invalid number of messages: %d", num_msgs); + return -EIO; + } + if (FIELD_GET(I2C_MSG_READ, msgs->flags)) { + LOG_ERR("Unexpected read"); + return -EIO; + } + if (msgs->len < 1) { + LOG_ERR("Unexpected msg0 length %d", msgs->len); + return -EIO; + } + + uint8_t regn = msgs->buf[0]; + bool is_read = FIELD_GET(I2C_MSG_READ, msgs->flags) == 1; + bool is_stop = FIELD_GET(I2C_MSG_STOP, msgs->flags) == 1; + + if (!is_stop && !is_read) { + /* First message was a write with the register number, check next message */ + msgs++; + is_read = FIELD_GET(I2C_MSG_READ, msgs->flags) == 1; + is_stop = FIELD_GET(I2C_MSG_STOP, msgs->flags) == 1; + } + + if (is_read) { + /* Read data */ + if (regn == MICROCHIP_MCP7940N_RTCWKDAY_REGISTER_ADDRESS) { + msgs->buf[0] = data->rtcwkday; + return 0; + } + if (regn >= MICROCHIP_MCP7940N_SRAM_OFFSET && + regn + msgs->len <= + MICROCHIP_MCP7940N_SRAM_OFFSET + MICROCHIP_MCP7940N_SRAM_SIZE) { + for (int i = 0; i < msgs->len; ++i) { + msgs->buf[i] = + data->data[regn + i - MICROCHIP_MCP7940N_SRAM_OFFSET]; + } + return 0; + } + } else { + /* Write data */ + if (regn == MICROCHIP_MCP7940N_RTCWKDAY_REGISTER_ADDRESS) { + data->rtcwkday = msgs->buf[1]; + return 0; + } + if (regn >= MICROCHIP_MCP7940N_SRAM_OFFSET && + regn + msgs->len - 1 <= + MICROCHIP_MCP7940N_SRAM_OFFSET + MICROCHIP_MCP7940N_SRAM_SIZE) { + for (int i = 0; i < msgs->len; ++i) { + data->data[regn + i - MICROCHIP_MCP7940N_SRAM_OFFSET] = + msgs->buf[1 + i]; + } + return 0; + } + } + + return -EIO; +} + +static const struct i2c_emul_api mcp7940n_emul_api_i2c = { + .transfer = mcp7940n_emul_transfer_i2c, +}; + +static int mcp7940n_emul_backend_set_data(const struct emul *target, size_t offset, size_t count, + const uint8_t *buffer) +{ + struct mcp7940n_emul_data *data = target->data; + + if (offset + count > MICROCHIP_MCP7940N_SRAM_SIZE) { + return -ERANGE; + } + + for (size_t i = 0; i < count; ++i) { + data->data[offset + i] = buffer[i]; + } + return 0; +} + +static int mcp7940n_emul_backend_get_data(const struct emul *target, size_t offset, size_t count, + uint8_t *buffer) +{ + struct mcp7940n_emul_data *data = target->data; + + if (offset + count > MICROCHIP_MCP7940N_SRAM_SIZE) { + return -ERANGE; + } + + for (size_t i = 0; i < count; ++i) { + buffer[i] = data->data[offset + i]; + } + return 0; +} + +static const struct emul_bbram_backend_api mcp7940n_emul_backend_api = { + .set_data = mcp7940n_emul_backend_set_data, + .get_data = mcp7940n_emul_backend_get_data, +}; + +#define MCP7940N_EMUL(inst) \ + static const struct mcp7940n_emul_cfg mcp7940n_emul_cfg_##inst; \ + static struct mcp7940n_emul_data mcp7940n_emul_data_##inst; \ + EMUL_DT_INST_DEFINE(inst, mcp7940n_emul_init, &mcp7940n_emul_data_##inst, \ + &mcp7940n_emul_cfg_##inst, &mcp7940n_emul_api_i2c, \ + &mcp7940n_emul_backend_api) + +DT_INST_FOREACH_STATUS_OKAY(MCP7940N_EMUL) From 2772843cf149e47749797bd0e5ae34f563e68ab3 Mon Sep 17 00:00:00 2001 From: Yuval Peress Date: Fri, 5 Jan 2024 12:19:08 -0700 Subject: [PATCH 2140/3723] bbram: npcx: Add emulator Add an emulator for the NPCX BBRAM which supports reading and writing Signed-off-by: Yuval Peress --- drivers/bbram/CMakeLists.txt | 2 ++ drivers/bbram/Kconfig.npcx | 8 +++++ drivers/bbram/bbram_npcx.c | 32 +++++------------- drivers/bbram/bbram_npcx_emul.c | 60 +++++++++++++++++++++++++++++++++ drivers/bbram/npcx.h | 41 ++++++++++++++++++++++ 5 files changed, 120 insertions(+), 23 deletions(-) create mode 100644 drivers/bbram/bbram_npcx_emul.c create mode 100644 drivers/bbram/npcx.h diff --git a/drivers/bbram/CMakeLists.txt b/drivers/bbram/CMakeLists.txt index 14ed29b9b79..9027ab548b3 100644 --- a/drivers/bbram/CMakeLists.txt +++ b/drivers/bbram/CMakeLists.txt @@ -7,6 +7,8 @@ zephyr_library_sources_ifdef(CONFIG_BBRAM_SHELL bbram_shell.c) zephyr_library_sources_ifdef(CONFIG_USERSPACE bbram_handlers.c) zephyr_library_sources_ifdef(CONFIG_BBRAM_NPCX bbram_npcx.c) +zephyr_library_sources_ifdef(CONFIG_BBRAM_NPCX_EMUL bbram_npcx_emul.c) +zephyr_library_include_directories_ifdef(CONFIG_BBRAM_NPCX .) zephyr_library_sources_ifdef(CONFIG_BBRAM_IT8XXX2 bbram_it8xxx2.c) zephyr_library_sources_ifdef(CONFIG_BBRAM_IT8XXX2_EMUL bbram_it8xxx2_emul.c) zephyr_library_include_directories_ifdef(CONFIG_BBRAM_IT8XXX2 .) diff --git a/drivers/bbram/Kconfig.npcx b/drivers/bbram/Kconfig.npcx index 4b5cc135b72..e529022213e 100644 --- a/drivers/bbram/Kconfig.npcx +++ b/drivers/bbram/Kconfig.npcx @@ -7,3 +7,11 @@ config BBRAM_NPCX depends on DT_HAS_NUVOTON_NPCX_BBRAM_ENABLED help This option enables the BBRAM driver for NPCX family of processors. + +config BBRAM_NPCX_EMUL + bool "Emulator for the NPCX BBRAM driver" + default y + depends on BBRAM_NPCX + depends on EMUL + help + Enable the emulator for the NPCX BBRAM. diff --git a/drivers/bbram/bbram_npcx.c b/drivers/bbram/bbram_npcx.c index b9b02f90eb3..ba9500ae6f1 100644 --- a/drivers/bbram/bbram_npcx.c +++ b/drivers/bbram/bbram_npcx.c @@ -11,17 +11,9 @@ #include #include -LOG_MODULE_REGISTER(bbram, CONFIG_BBRAM_LOG_LEVEL); - -/** Device config */ -struct bbram_npcx_config { - /** BBRAM base address */ - uintptr_t base_addr; - /** BBRAM size (Unit:bytes) */ - int size; - /** Status register base address */ - uintptr_t status_reg_addr; -}; +LOG_MODULE_REGISTER(npcx_bbram, CONFIG_BBRAM_LOG_LEVEL); + +#include "npcx.h" #define NPCX_STATUS_IBBR BIT(7) #define NPCX_STATUS_VSBY BIT(1) @@ -35,7 +27,7 @@ static int get_bit_and_reset(const struct device *dev, int mask) int result = DRV_STATUS(dev) & mask; /* Clear the bit(s) */ - DRV_STATUS(dev) = mask; + DRV_STATUS(dev) &= ~mask; return result; } @@ -69,7 +61,7 @@ static int bbram_npcx_read(const struct device *dev, size_t offset, size_t size, const struct bbram_npcx_config *config = dev->config; if (size < 1 || offset + size > config->size || bbram_npcx_check_invalid(dev)) { - return -EFAULT; + return -EINVAL; } @@ -83,7 +75,7 @@ static int bbram_npcx_write(const struct device *dev, size_t offset, size_t size const struct bbram_npcx_config *config = dev->config; if (size < 1 || offset + size > config->size || bbram_npcx_check_invalid(dev)) { - return -EFAULT; + return -EINVAL; } bytecpy(((uint8_t *)config->base_addr + offset), data, size); @@ -100,14 +92,8 @@ static const struct bbram_driver_api bbram_npcx_driver_api = { }; #define BBRAM_INIT(inst) \ - static struct { \ - } bbram_data_##inst; \ - static const struct bbram_npcx_config bbram_cfg_##inst = { \ - .base_addr = DT_INST_REG_ADDR_BY_NAME(inst, memory), \ - .size = DT_INST_REG_SIZE_BY_NAME(inst, memory), \ - .status_reg_addr = DT_INST_REG_ADDR_BY_NAME(inst, status), \ - }; \ - DEVICE_DT_INST_DEFINE(inst, NULL, NULL, &bbram_data_##inst, &bbram_cfg_##inst, \ - PRE_KERNEL_1, CONFIG_BBRAM_INIT_PRIORITY, &bbram_npcx_driver_api); + BBRAM_NPCX_DECL_CONFIG(inst); \ + DEVICE_DT_INST_DEFINE(inst, NULL, NULL, NULL, &bbram_cfg_##inst, PRE_KERNEL_1, \ + CONFIG_BBRAM_INIT_PRIORITY, &bbram_npcx_driver_api); DT_INST_FOREACH_STATUS_OKAY(BBRAM_INIT); diff --git a/drivers/bbram/bbram_npcx_emul.c b/drivers/bbram/bbram_npcx_emul.c new file mode 100644 index 00000000000..799e158eefd --- /dev/null +++ b/drivers/bbram/bbram_npcx_emul.c @@ -0,0 +1,60 @@ +/* + * Copyright (c) 2024 Google Inc + * SPDX-License-Identifier: Apache-2.0 + */ + +#include +#include +#include + +#include "npcx.h" + +#define DT_DRV_COMPAT nuvoton_npcx_bbram + +struct bbram_npcx_emul_config { + const struct device *dev; +}; + +#define GET_CONFIG(target) \ + ((const struct bbram_npcx_config \ + *)(((const struct bbram_npcx_emul_config *)((target)->cfg))->dev->config)) + +static int npcx_emul_backend_set_data(const struct emul *target, size_t offset, size_t count, + const uint8_t *buffer) +{ + const struct bbram_npcx_config *config = GET_CONFIG(target); + + if (offset + count > config->size) { + return -ERANGE; + } + + bytecpy(((uint8_t *)config->base_addr + offset), buffer, count); + return 0; +} + +static int npcx_emul_backend_get_data(const struct emul *target, size_t offset, size_t count, + uint8_t *buffer) +{ + const struct bbram_npcx_config *config = GET_CONFIG(target); + + if (offset + count > config->size) { + return -ERANGE; + } + + bytecpy(buffer, ((uint8_t *)config->base_addr + offset), count); + return 0; +} + +static const struct emul_bbram_backend_api npcx_emul_backend_api = { + .set_data = npcx_emul_backend_set_data, + .get_data = npcx_emul_backend_get_data, +}; + +#define BBRAM_EMUL_INIT(inst) \ + static struct bbram_npcx_emul_config bbram_npcx_emul_config_##inst = { \ + .dev = DEVICE_DT_INST_GET(inst), \ + }; \ + EMUL_DT_INST_DEFINE(inst, NULL, NULL, &bbram_npcx_emul_config_##inst, NULL, \ + &npcx_emul_backend_api) + +DT_INST_FOREACH_STATUS_OKAY(BBRAM_EMUL_INIT); diff --git a/drivers/bbram/npcx.h b/drivers/bbram/npcx.h new file mode 100644 index 00000000000..b177a94f32a --- /dev/null +++ b/drivers/bbram/npcx.h @@ -0,0 +1,41 @@ +/* + * Copyright (c) 2024 Google Inc + * SPDX-License-Identifier: Apache-2.0 + */ + +#ifndef INCLUDE_ZEPHYR_DRIVERS_BBRAM_NPCX_H_ +#define INCLUDE_ZEPHYR_DRIVERS_BBRAM_NPCX_H_ + +#include + +#include + +/** Device config */ +struct bbram_npcx_config { + /** BBRAM base address */ + uintptr_t base_addr; + /** BBRAM size (Unit:bytes) */ + int size; + /** Status register base address */ + uintptr_t status_reg_addr; +}; + +#ifdef CONFIG_BBRAM_NPCX_EMUL +#define BBRAM_NPCX_DECL_CONFIG(inst) \ + static uint8_t bbram_npcx_emul_buffer_##inst[DT_INST_REG_SIZE_BY_NAME(inst, memory)]; \ + static uint8_t bbram_npcx_emul_status_##inst; \ + static const struct bbram_npcx_config bbram_cfg_##inst = { \ + .base_addr = (uintptr_t)bbram_npcx_emul_buffer_##inst, \ + .size = DT_INST_REG_SIZE_BY_NAME(inst, memory), \ + .status_reg_addr = (uintptr_t)&bbram_npcx_emul_status_##inst, \ + } +#else +#define BBRAM_NPCX_DECL_CONFIG(inst) \ + static const struct bbram_npcx_config bbram_cfg_##inst = { \ + .base_addr = DT_INST_REG_ADDR_BY_NAME(inst, memory), \ + .size = DT_INST_REG_SIZE_BY_NAME(inst, memory), \ + .status_reg_addr = DT_INST_REG_ADDR_BY_NAME(inst, status), \ + } +#endif + +#endif /* INCLUDE_ZEPHYR_DRIVERS_BBRAM_NPCX_H_ */ From 4efa11ebf760b4b52823c0203ff9bdbc59e5e7e2 Mon Sep 17 00:00:00 2001 From: Yuval Peress Date: Thu, 4 Jan 2024 02:13:23 -0700 Subject: [PATCH 2141/3723] bbram: Add tests Add emulation testing for it8xxx2, npcx, and mcp7940n. The test is made to be generic and uses the backend API in order to verify both read and write functionality. Additional tests are made for the API's limits when reading/writing out of bounds. Fixes #65018 Signed-off-by: Yuval Peress --- tests/drivers/bbram/generic/CMakeLists.txt | 16 ++++++ .../bbram/generic/boards/native_sim.overlay | 28 +++++++++ tests/drivers/bbram/generic/include/fixture.h | 21 +++++++ tests/drivers/bbram/generic/prj.conf | 6 ++ tests/drivers/bbram/generic/src/fixture.c | 25 ++++++++ tests/drivers/bbram/generic/src/read.c | 57 +++++++++++++++++++ tests/drivers/bbram/generic/src/write.c | 57 +++++++++++++++++++ tests/drivers/bbram/generic/testcase.yaml | 10 ++++ 8 files changed, 220 insertions(+) create mode 100644 tests/drivers/bbram/generic/CMakeLists.txt create mode 100644 tests/drivers/bbram/generic/boards/native_sim.overlay create mode 100644 tests/drivers/bbram/generic/include/fixture.h create mode 100644 tests/drivers/bbram/generic/prj.conf create mode 100644 tests/drivers/bbram/generic/src/fixture.c create mode 100644 tests/drivers/bbram/generic/src/read.c create mode 100644 tests/drivers/bbram/generic/src/write.c create mode 100644 tests/drivers/bbram/generic/testcase.yaml diff --git a/tests/drivers/bbram/generic/CMakeLists.txt b/tests/drivers/bbram/generic/CMakeLists.txt new file mode 100644 index 00000000000..7a531bf960c --- /dev/null +++ b/tests/drivers/bbram/generic/CMakeLists.txt @@ -0,0 +1,16 @@ +# Copyright 2024 Google LLC +# SPDX-License-Identifier: Apache-2.0 + +cmake_minimum_required(VERSION 3.20.0) + +find_package(Zephyr REQUIRED HINTS $ENV{ZEPHYR_BASE}) +project(bbram) + +target_sources(app + PRIVATE + include/fixture.h + src/fixture.c + src/read.c + src/write.c +) +target_include_directories(app PRIVATE include) diff --git a/tests/drivers/bbram/generic/boards/native_sim.overlay b/tests/drivers/bbram/generic/boards/native_sim.overlay new file mode 100644 index 00000000000..2f97bbb0ef0 --- /dev/null +++ b/tests/drivers/bbram/generic/boards/native_sim.overlay @@ -0,0 +1,28 @@ +/* + * Copyright 2021 Google LLC + * + * SPDX-License-Identifier: Apache-2.0 + */ + +&i2c0 { + mcp7940n: mcp7940n@0 { + compatible = "microchip,mcp7940n"; + reg = <0x0>; + }; +}; + +/ { + ite8xxx2: ite8xxx2@0 { + #address-cells = <1>; + #size-cells = <1>; + compatible = "ite,it8xxx2-bbram"; + status = "okay"; + reg = <0x0 0x40>; + }; + npcx: npcx@40 { + compatible = "nuvoton,npcx-bbram"; + reg = <0x40 0x40 + 0x80 0x1>; + reg-names = "memory", "status"; + }; +}; diff --git a/tests/drivers/bbram/generic/include/fixture.h b/tests/drivers/bbram/generic/include/fixture.h new file mode 100644 index 00000000000..a804d44270c --- /dev/null +++ b/tests/drivers/bbram/generic/include/fixture.h @@ -0,0 +1,21 @@ +/* + * Copyright 2024 Google LLC + * SPDX-License-Identifier: Apache-2.0 + */ + +#ifndef TESTS_DRIVERS_BBRAM_GENERIC_INCLUDE_FIXTURE_H_ +#define TESTS_DRIVERS_BBRAM_GENERIC_INCLUDE_FIXTURE_H_ + +#define BBRAM_TEST_IMPL(name, inst) \ + ZTEST(generic, test_##name##_##inst) \ + { \ + const struct device *dev = DEVICE_DT_GET(inst); \ + run_test_##name(dev, get_and_check_emul(dev)); \ + } + +#define BBRAM_FOR_EACH(fn) \ + fn(DT_NODELABEL(mcp7940n)) fn(DT_NODELABEL(ite8xxx2)) fn(DT_NODELABEL(npcx)) + +const struct emul *get_and_check_emul(const struct device *dev); + +#endif /* TESTS_DRIVERS_BBRAM_GENERIC_INCLUDE_FIXTURE_H_ */ diff --git a/tests/drivers/bbram/generic/prj.conf b/tests/drivers/bbram/generic/prj.conf new file mode 100644 index 00000000000..02cf2049d79 --- /dev/null +++ b/tests/drivers/bbram/generic/prj.conf @@ -0,0 +1,6 @@ +# Copyright 2021 Google LLC +# SPDX-License-Identifier: Apache-2.0 + +CONFIG_ZTEST=y +CONFIG_EMUL=y +CONFIG_BBRAM=y diff --git a/tests/drivers/bbram/generic/src/fixture.c b/tests/drivers/bbram/generic/src/fixture.c new file mode 100644 index 00000000000..e479864140e --- /dev/null +++ b/tests/drivers/bbram/generic/src/fixture.c @@ -0,0 +1,25 @@ +/* + * Copyright 2021 Google LLC + * SPDX-License-Identifier: Apache-2.0 + */ + +#include +#include +#include + +#include "fixture.h" + +ZTEST_SUITE(generic, NULL, NULL, NULL, NULL, NULL); + +const struct emul *get_and_check_emul(const struct device *dev) +{ + zassert_not_null(dev, "Cannot get device pointer. Is this driver properly instantiated?"); + + const struct emul *emul = emul_get_binding(dev->name); + + /* Skip this sensor if there is no emulator or backend loaded. */ + if (emul == NULL || emul->backend_api == NULL) { + ztest_test_skip(); + } + return emul; +} diff --git a/tests/drivers/bbram/generic/src/read.c b/tests/drivers/bbram/generic/src/read.c new file mode 100644 index 00000000000..e17b57296a0 --- /dev/null +++ b/tests/drivers/bbram/generic/src/read.c @@ -0,0 +1,57 @@ +/* + * Copyright 2024 Google LLC + * SPDX-License-Identifier: Apache-2.0 + */ + +#include +#include +#include +#include +#include + +#include "fixture.h" + +static void run_test_read_invalid_size(const struct device *dev, const struct emul *emulator) +{ + uint8_t data = 0; + size_t bbram_size = 0; + int rc; + + ARG_UNUSED(emulator); + + rc = bbram_read(dev, 0, 0, &data); + zassert_equal(-EINVAL, rc, "got %d", rc); + + rc = bbram_get_size(dev, &bbram_size); + zassert_ok(rc, "got %d", rc); + + rc = bbram_read(dev, 0, bbram_size + 1, &data); + zassert_equal(-EINVAL, rc, "got %d", rc); +} + +static void run_test_read_bytes(const struct device *dev, const struct emul *emulator) +{ + uint8_t data = 0; + uint8_t expected_data = 0; + size_t bbram_size = 0; + int rc; + + rc = bbram_get_size(dev, &bbram_size); + zassert_ok(rc, "got %d", rc); + + for (size_t i = 0; i < bbram_size; ++i) { + expected_data = i % BIT(8); + rc = emul_bbram_backend_set_data(emulator, i, 1, &expected_data); + zassert_ok(rc, "Failed to set expected data at offset %zu", i); + + rc = bbram_read(dev, i, 1, &data); + zassert_ok(rc, "Failed to read byte at offset %zu", i); + zassert_equal(expected_data, data, "Expected %u, but got %u", expected_data, data); + } +} + +#define DECLARE_ZTEST_PER_DEVICE(inst) \ + BBRAM_TEST_IMPL(read_invalid_size, inst) \ + BBRAM_TEST_IMPL(read_bytes, inst) + +BBRAM_FOR_EACH(DECLARE_ZTEST_PER_DEVICE) diff --git a/tests/drivers/bbram/generic/src/write.c b/tests/drivers/bbram/generic/src/write.c new file mode 100644 index 00000000000..83d06a6f344 --- /dev/null +++ b/tests/drivers/bbram/generic/src/write.c @@ -0,0 +1,57 @@ +/* + * Copyright 2024 Google LLC + * SPDX-License-Identifier: Apache-2.0 + */ + +#include +#include +#include +#include +#include + +#include "fixture.h" + +static void run_test_write_invalid_size(const struct device *dev, const struct emul *emulator) +{ + uint8_t data = 0; + size_t bbram_size = 0; + int rc; + + ARG_UNUSED(emulator); + + rc = bbram_write(dev, 0, 0, &data); + zassert_equal(-EINVAL, rc, "got %d", rc); + + rc = bbram_get_size(dev, &bbram_size); + zassert_ok(rc, "got %d", rc); + + rc = bbram_write(dev, 0, bbram_size + 1, &data); + zassert_equal(-EINVAL, rc, "got %d", rc); +} + +static void run_test_write_bytes(const struct device *dev, const struct emul *emulator) +{ + uint8_t data = 0; + uint8_t expected_data = 0; + size_t bbram_size = 0; + int rc; + + rc = bbram_get_size(dev, &bbram_size); + zassert_ok(rc, "got %d", rc); + + for (size_t i = 0; i < bbram_size; ++i) { + expected_data = i % BIT(8); + rc = bbram_write(dev, i, 1, &expected_data); + zassert_ok(rc, "Failed to set expected data at offset %zu", i); + + rc = emul_bbram_backend_get_data(emulator, i, 1, &data); + zassert_ok(rc, "Failed to get byte at offset %zu", i); + zassert_equal(expected_data, data, "Expected %u, but got %u", expected_data, data); + } +} + +#define DECLARE_ZTEST_PER_DEVICE(inst) \ + BBRAM_TEST_IMPL(write_invalid_size, inst) \ + BBRAM_TEST_IMPL(write_bytes, inst) + +BBRAM_FOR_EACH(DECLARE_ZTEST_PER_DEVICE) diff --git a/tests/drivers/bbram/generic/testcase.yaml b/tests/drivers/bbram/generic/testcase.yaml new file mode 100644 index 00000000000..0a0ff045462 --- /dev/null +++ b/tests/drivers/bbram/generic/testcase.yaml @@ -0,0 +1,10 @@ +# Copyright 2024 Google LLC +# SPDX-License-Identifier: Apache-2.0 + +tests: + drivers.bbram.generic: + tags: + - drivers + - bbram + platform_allow: + - native_sim From b7a1ff7b181d4508b529073c1c7fc4e35ed46208 Mon Sep 17 00:00:00 2001 From: Martin Kiepfer Date: Fri, 29 Dec 2023 19:44:28 +0100 Subject: [PATCH 2142/3723] devicetree: led: Add timing definitions for WS2812C RGBs Timing parameters for WS2812C variant of digital RGB. Signed-off-by: Martin Kiepfer --- .../dt-bindings/led/worldsemi_ws2812c.h | 20 +++++++++++++++++++ 1 file changed, 20 insertions(+) create mode 100644 include/zephyr/dt-bindings/led/worldsemi_ws2812c.h diff --git a/include/zephyr/dt-bindings/led/worldsemi_ws2812c.h b/include/zephyr/dt-bindings/led/worldsemi_ws2812c.h new file mode 100644 index 00000000000..e723227a022 --- /dev/null +++ b/include/zephyr/dt-bindings/led/worldsemi_ws2812c.h @@ -0,0 +1,20 @@ +/* + * Copyright (c) 2023 Martin Kiepfer + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#ifndef ZEPHYR_DT_LED_WS2812C_H_ +#define ZEPHYR_DT_LED_WS2812C_H_ + +/* + * At 7 MHz: 1 bit in 142.86 ns + * 1090 ns -> 7.6 bits + * 300 ns -> 2.1 bits + * 790 ns -> 5.5 bits + */ +#define WS2812C_SPI_FREQ (7000000U) +#define WS2812C_ZERO_FRAME (0xC0U) +#define WS2812C_ONE_FRAME (0xFCU) + +#endif From 51e5ecf829151ee0e8d563b730473c9dbae27b9d Mon Sep 17 00:00:00 2001 From: Martin Kiepfer Date: Tue, 2 Jan 2024 18:35:40 +0100 Subject: [PATCH 2143/3723] board: m5stack_stamps3: Add support for M5Stack StampS3 development board Adding support for M5Stack StampS3 development board, featuring an ESP32 MCU Signed-off-by: Martin Kiepfer --- boards/xtensa/m5stack_stamps3/Kconfig.board | 12 ++ .../xtensa/m5stack_stamps3/Kconfig.defconfig | 27 +++ boards/xtensa/m5stack_stamps3/board.cmake | 9 + .../doc/img/m5stack_stamps3.webp | Bin 0 -> 54796 bytes .../doc/img/m5stack_stamps3_header.webp | Bin 0 -> 53484 bytes boards/xtensa/m5stack_stamps3/doc/index.rst | 199 ++++++++++++++++++ .../m5stack_stamps3-pinctrl.dtsi | 84 ++++++++ .../m5stack_stamps3/m5stack_stamps3.dts | 195 +++++++++++++++++ .../m5stack_stamps3/m5stack_stamps3.yaml | 20 ++ .../m5stack_stamps3_connectors.dtsi | 48 +++++ .../m5stack_stamps3/m5stack_stamps3_defconfig | 14 ++ dts/bindings/gpio/m5stack,stamps3-header.yaml | 33 +++ 12 files changed, 641 insertions(+) create mode 100644 boards/xtensa/m5stack_stamps3/Kconfig.board create mode 100644 boards/xtensa/m5stack_stamps3/Kconfig.defconfig create mode 100644 boards/xtensa/m5stack_stamps3/board.cmake create mode 100644 boards/xtensa/m5stack_stamps3/doc/img/m5stack_stamps3.webp create mode 100644 boards/xtensa/m5stack_stamps3/doc/img/m5stack_stamps3_header.webp create mode 100644 boards/xtensa/m5stack_stamps3/doc/index.rst create mode 100644 boards/xtensa/m5stack_stamps3/m5stack_stamps3-pinctrl.dtsi create mode 100644 boards/xtensa/m5stack_stamps3/m5stack_stamps3.dts create mode 100644 boards/xtensa/m5stack_stamps3/m5stack_stamps3.yaml create mode 100644 boards/xtensa/m5stack_stamps3/m5stack_stamps3_connectors.dtsi create mode 100644 boards/xtensa/m5stack_stamps3/m5stack_stamps3_defconfig create mode 100644 dts/bindings/gpio/m5stack,stamps3-header.yaml diff --git a/boards/xtensa/m5stack_stamps3/Kconfig.board b/boards/xtensa/m5stack_stamps3/Kconfig.board new file mode 100644 index 00000000000..1f22500830e --- /dev/null +++ b/boards/xtensa/m5stack_stamps3/Kconfig.board @@ -0,0 +1,12 @@ +# M5Stack StampS3 board configuration + +# Copyright (c) 2023 Martin Kiepfer +# SPDX-License-Identifier: Apache-2.0 + +config BOARD_M5STACK_STAMPS3 + bool "M5Stack StampS3 Development Board" + depends on SOC_SERIES_ESP32S3 + +choice SOC_PART_NUMBER + default SOC_ESP32S3_FN8 +endchoice diff --git a/boards/xtensa/m5stack_stamps3/Kconfig.defconfig b/boards/xtensa/m5stack_stamps3/Kconfig.defconfig new file mode 100644 index 00000000000..f451db3e231 --- /dev/null +++ b/boards/xtensa/m5stack_stamps3/Kconfig.defconfig @@ -0,0 +1,27 @@ +# M5Stack StampS3 board configuration +# Copyright (c) 2023 Martin Kiepfer +# SPDX-License-Identifier: Apache-2.0 + +if BOARD_M5STACK_STAMPS3 + +config BOARD + default "m5stack_stamps3" + depends on BOARD_M5STACK_STAMPS3 + +config ENTROPY_GENERATOR + default y + +config HEAP_MEM_POOL_ADD_SIZE_BOARD + int + default 98304 if WIFI + default 65536 if BT + default 4096 + +config KERNEL_MEM_POOL + default y + +choice BT_HCI_BUS_TYPE + default BT_ESP32 if BT +endchoice + +endif # BOARD_M5STACK_STAMPS3 diff --git a/boards/xtensa/m5stack_stamps3/board.cmake b/boards/xtensa/m5stack_stamps3/board.cmake new file mode 100644 index 00000000000..2f04d1fe886 --- /dev/null +++ b/boards/xtensa/m5stack_stamps3/board.cmake @@ -0,0 +1,9 @@ +# SPDX-License-Identifier: Apache-2.0 + +if(NOT "${OPENOCD}" MATCHES "^${ESPRESSIF_TOOLCHAIN_PATH}/.*") + set(OPENOCD OPENOCD-NOTFOUND) +endif() +find_program(OPENOCD openocd PATHS ${ESPRESSIF_TOOLCHAIN_PATH}/openocd-esp32/bin NO_DEFAULT_PATH) + +include(${ZEPHYR_BASE}/boards/common/esp32.board.cmake) +include(${ZEPHYR_BASE}/boards/common/openocd.board.cmake) diff --git a/boards/xtensa/m5stack_stamps3/doc/img/m5stack_stamps3.webp b/boards/xtensa/m5stack_stamps3/doc/img/m5stack_stamps3.webp new file mode 100644 index 0000000000000000000000000000000000000000..3d24c0322e3b44257c3b4f2329d8c93578710e0b GIT binary patch literal 54796 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Ņ!VpwJE62B!rE%)Vs@YN&yLgoolhgGBnfDLX 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 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_stamps3 + +Debugging +--------- + +M5Stack StampS3 exports a JTAG-interface via Pins 19 (MTCK), 21 (MTDO), 23 +(MTDI), 25 (MTMS). + +.. note:: + + Please note that additional JTAG equipment is needed to utilize JTAG. Refer to + the ESP32S3 datasheet and the M5Stack StampS3 documentation for details. + +Related Documents +***************** + +- `M5Stack StampS3 schematic `_ +- `M5Stack StampS3 `_ +- `ESP32 Datasheet `_ (PDF) +- `ESP32 Hardware Reference `_ diff --git a/boards/xtensa/m5stack_stamps3/m5stack_stamps3-pinctrl.dtsi b/boards/xtensa/m5stack_stamps3/m5stack_stamps3-pinctrl.dtsi new file mode 100644 index 00000000000..c10190db129 --- /dev/null +++ b/boards/xtensa/m5stack_stamps3/m5stack_stamps3-pinctrl.dtsi @@ -0,0 +1,84 @@ +/* + * Copyright (c) 2023 Martin Kiepfer + * + * SPDX-License-Identifier: Apache-2.0 + */ + + #include + #include + #include + +&pinctrl { + uart0_default: uart0_default { + group1 { + pinmux = ; + output-high; + }; + group2 { + pinmux = ; + bias-pull-up; + }; + }; + + i2c0_default: i2c0_default { + group1 { + pinmux = , + ; + bias-pull-up; + drive-open-drain; + output-high; + }; + }; + + i2c1_default: i2c1_default { + group1 { + pinmux = , + ; + bias-pull-up; + drive-open-drain; + output-high; + }; + }; + + spim2_default: spim2_default { + group1 { + pinmux = , + ; + }; + group2 { + pinmux = ; + output-low; + }; + + }; + + spim3_default: spim3_default { + group1 { + pinmux = ; + output-low; + }; + + }; + + ledc0_default: ledc0_default { + group1 { + pinmux = ; /* lcd backlight */ + output-enable; + }; + group2 { + pinmux = ; /* beeper */ + output-enable; + }; + }; + + mcpwm0_default: mcpwm0_default { + group1 { + pinmux = ; /* lcd backlight */ + output-enable; + }; + group2 { + pinmux = ; + output-enable; + }; + }; +}; diff --git a/boards/xtensa/m5stack_stamps3/m5stack_stamps3.dts b/boards/xtensa/m5stack_stamps3/m5stack_stamps3.dts new file mode 100644 index 00000000000..b4087e31bd9 --- /dev/null +++ b/boards/xtensa/m5stack_stamps3/m5stack_stamps3.dts @@ -0,0 +1,195 @@ +/* + * Copyright (c) 2023 Martin Kiepfer + * + * SPDX-License-Identifier: Apache-2.0 + */ +/dts-v1/; + +#include +#include "m5stack_stamps3-pinctrl.dtsi" +#include "m5stack_stamps3_connectors.dtsi" +#include +#include +#include +#include + +/ { + model = "M5Stack StampS3"; + compatible = "m5stack,stamps3"; + + chosen { + zephyr,sram = &sram0; + zephyr,console = &usb_serial; + zephyr,shell-uart = &usb_serial; + zephyr,flash = &flash0; + zephyr,code-partition = &slot0_partition; + }; + + aliases { + sw0 = &user_button_0; + watchdog0 = &wdt0; + //pwm-0 = &ledc0; + i2c-0 = &i2c0; + led-strip = &status_rgb_led; + }; + + gpio_keys { + compatible = "gpio-keys"; + + /* This is the button that's underneath the LCD display */ + user_button_0: button_0 { + label = "User button 0"; + gpios = <&gpio0 0 GPIO_ACTIVE_LOW>; + zephyr,code = ; + }; + }; +}; + +&cpu0 { + clock-frequency = ; +}; + +&cpu1 { + clock-frequency = ; +}; + +&usb_serial { + status = "okay"; +}; + +&uart0 { + status = "okay"; + current-speed = <115200>; + pinctrl-0 = <&uart0_default>; + pinctrl-names = "default"; +}; + +&i2c0 { + status = "okay"; + clock-frequency = ; + pinctrl-0 = <&i2c0_default>; + pinctrl-names = "default"; +}; + +&i2c1 { + status = "okay"; + clock-frequency = ; + pinctrl-0 = <&i2c1_default>; + pinctrl-names = "default"; +}; + +&trng0 { + status = "okay"; +}; + +&mcpwm0 { + status = "okay"; + pinctrl-0 = <&mcpwm0_default>; + pinctrl-names = "default"; + prescale = <255>; + prescale-timer0 = <100>; + prescale-timer1 = <100>; +}; + +&ledc0 { + pinctrl-0 = <&ledc0_default>; + pinctrl-names = "default"; + status = "disabled"; + #address-cells = <1>; + #size-cells = <0>; + channel0@0 { + reg = <0x0>; + timer = <0>; + }; + channel0@1 { + reg = <0x1>; + timer = <0>; + }; +}; + + +&spi2 { + #address-cells = <1>; + #size-cells = <0>; + status = "okay"; + pinctrl-0 = <&spim2_default>; + pinctrl-names = "default"; +}; + +&spi3 { + #address-cells = <1>; + #size-cells = <0>; + status = "okay"; + line-idle-low; + pinctrl-0 = <&spim3_default>; + pinctrl-names = "default"; + + status_rgb_led: ws2812@0 { + compatible = "worldsemi,ws2812-spi"; + reg = <0x0>; + spi-max-frequency = ; + + chain-length = <1>; + color-mapping = , + , + ; + spi-one-frame = ; + spi-zero-frame = ; + reset-delay = <250>; + }; +}; + +&gpio0 { + status = "okay"; +}; + +&gpio1 { + status = "okay"; +}; + +&wdt0 { + status = "okay"; +}; + +&timer0 { + status = "okay"; +}; + +&timer1 { + status = "okay"; +}; + +&flash0 { + status = "okay"; + partitions { + compatible = "fixed-partitions"; + #address-cells = <1>; + #size-cells = <1>; + + boot_partition: partition@0 { + label = "mcuboot"; + reg = <0x00000000 0x0000F000>; + read-only; + }; + + slot0_partition: partition@10000 { + label = "image-0"; + reg = <0x00010000 0x00100000>; + }; + + slot1_partition: partition@110000 { + label = "image-1"; + reg = <0x00110000 0x00100000>; + }; + + scratch_partition: partition@210000 { + label = "image-scratch"; + reg = <0x00210000 0x00040000>; + }; + + storage_partition: partition@250000 { + label = "storage"; + reg = <0x00250000 0x00006000>; + }; + }; +}; diff --git a/boards/xtensa/m5stack_stamps3/m5stack_stamps3.yaml b/boards/xtensa/m5stack_stamps3/m5stack_stamps3.yaml new file mode 100644 index 00000000000..f5275cabe05 --- /dev/null +++ b/boards/xtensa/m5stack_stamps3/m5stack_stamps3.yaml @@ -0,0 +1,20 @@ +identifier: m5stack_stamps3 +name: M5Stack StampS3 +type: mcu +arch: xtensa +toolchain: + - zephyr +supported: + - gpio + - i2c + - spi + - watchdog + - uart + - pwm + - pinmux + - nvs +testing: + ignore_tags: + - net + - bluetooth +vendor: m5stack diff --git a/boards/xtensa/m5stack_stamps3/m5stack_stamps3_connectors.dtsi b/boards/xtensa/m5stack_stamps3/m5stack_stamps3_connectors.dtsi new file mode 100644 index 00000000000..393b741440a --- /dev/null +++ b/boards/xtensa/m5stack_stamps3/m5stack_stamps3_connectors.dtsi @@ -0,0 +1,48 @@ +/* + * Copyright (c) 2023 Martin Kiepfer + * SPDX-License-Identifier: Apache-2.0 + */ + +/ { + m5stack_stamps3_header: m5stack_stamps3_header { + compatible = "m5stack,stamps3-header"; + #gpio-cells = <2>; + gpio-map-mask = <0xffffffff 0xffffffc0>; + gpio-map-pass-thru = <0 0x3f>; + gpio-map = + <0 0 &gpio0 1 0>, /* GPIO/AIN */ + <1 0 &gpio0 2 0>, /* GPIO/AIN */ + <2 0 &gpio0 3 0>, /* GPIO/AIN/CLKOUT1-3 */ + <3 0 &gpio0 4 0>, /* GPIO/AIN */ + <4 0 &gpio0 5 0>, /* GPIO/AIN/SPI2-MOSI */ + <5 0 &gpio0 6 0>, /* GPIO/AIN/SPI2-CLK */ + <6 0 &gpio0 7 0>, /* GPIO/AIN/SPI2-CS */ + <7 0 &gpio0 8 0>, /* GPIO/AIN */ + <8 0 &gpio0 9 0>, /* GPIO/AIN/CLKOUT1-4 */ + <9 0 &gpio0 10 0>, /* GPIO/AIN */ + /* 10 GND */ + <11 0 &gpio0 11 0>, /* GPIO/AIN/SDA1 */ + /* 11 5V */ + <12 0 &gpio0 12 0>, /* GPIO/AIN/SCL1 */ + <14 0 &gpio0 13 0>, /* GPIO/AIN/SDA0 */ + <15 0 &gpio0 14 0>, /* GPIO/AIN */ + <16 0 &gpio0 15 0>, /* GPIO/AIN/SCL0 */ + /* 17 GND */ + <18 0 &gpio1 7 0>, /* GPIO/CLKOUT0-0 */ + <19 0 &gpio0 0 0>, /* GPIO */ + <20 0 &gpio1 8 0>, /* GPIO/CLKOUT0-1 */ + /* 21 EN */ + <22 0 &gpio1 9 0>, /* GPIO/CLKOUT1-0 */ + <23 0 &gpio1 12 0>, /* GPIO/CLKOUT1-1/RXD0 */ + <24 0 &gpio1 10 0>, /* GPIO */ + <25 0 &gpio1 11 0>, /* GPIO/CLKOUT1.2/TXD0 */ + <26 0 &gpio1 14 0>; /* GPIO */ + /* 27 3V3 */ + }; +}; + +m5stack_stamps3_uart0: &uart0 {}; +m5stack_stamps3_i2c0: &i2c0 {}; +m5stack_stamps3_i2c1: &i2c1 {}; +m5stack_stamps3_clkout0: &mcpwm0 {}; +m5stack_stamps3_spilcd: &spi2 {}; diff --git a/boards/xtensa/m5stack_stamps3/m5stack_stamps3_defconfig b/boards/xtensa/m5stack_stamps3/m5stack_stamps3_defconfig new file mode 100644 index 00000000000..34f489623bc --- /dev/null +++ b/boards/xtensa/m5stack_stamps3/m5stack_stamps3_defconfig @@ -0,0 +1,14 @@ +# SPDX-License-Identifier: Apache-2.0 + +CONFIG_BOARD_M5STACK_STAMPS3=y +CONFIG_SOC_SERIES_ESP32S3=y + +CONFIG_MAIN_STACK_SIZE=2048 + +CONFIG_GPIO=y + +CONFIG_CONSOLE=y +CONFIG_PWM=y +CONFIG_SERIAL=y +CONFIG_UART_CONSOLE=y +CONFIG_CLOCK_CONTROL=y diff --git a/dts/bindings/gpio/m5stack,stamps3-header.yaml b/dts/bindings/gpio/m5stack,stamps3-header.yaml new file mode 100644 index 00000000000..a04fb9997ba --- /dev/null +++ b/dts/bindings/gpio/m5stack,stamps3-header.yaml @@ -0,0 +1,33 @@ +# Copyright (c) 2023 Martin Kiepfer +# SPDX-License-Identifier: Apache-2.0 + +description: | + GPIO pins exposed on M5Stack StampS3 module headers. + + This binding provides a nexus mapping for 28 pins as depicted below. + + 0 GPIO + 1 GPIO + 2 GPIO/CLKOUT0 + 3 GPIO + 4 GPIO/SPILCD + 5 GPIO/SPILCD + 6 GPIO/SPILCD 27 3V3 + 7 GPIO 26 GPIO + 8 GPIO/CLKOUT0 25 GPIO/CLKOUT/TXD + 9 GPIO 24 GPIO + 10 GND 23 GPIO/CLKOUT/RXD + 11 GPIO/SDA1 22 GPIO/CLKOUT + 12 5V 21 EN + 13 GPIO/SCL1 20 GPIO/CLKOUT + 14 GPIO/SDA0 19 GPIO + 15 GPIO 18 GPIO/CLKOUT + 16 GPIO/SCL0 17 GND + + Note: Please note that the StampS3 is not pin compatible to the + other Stamp variantes like StampC3 or Stamp-Pico. + + +compatible: "m5stack,stamps3-header" + +include: [gpio-nexus.yaml, base.yaml] From 6b84d29c0c5a1c5fb5d1ad48b95f9f5b3cab22e9 Mon Sep 17 00:00:00 2001 From: Andrej Butok Date: Fri, 15 Dec 2023 14:17:41 +0100 Subject: [PATCH 2144/3723] cmake: mcuboot: set align to 1 for overwrite only mode Set align to 1 for CONFIG_MCUBOOT_IMGTOOL_OVERWRITE_ONLY, used by non-swap update modes. Fix imgtool error message for device with write size > 32B. Signed-off-by: Andrej Butok --- cmake/mcuboot.cmake | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cmake/mcuboot.cmake b/cmake/mcuboot.cmake index 2347ae3108c..6dd0717f515 100644 --- a/cmake/mcuboot.cmake +++ b/cmake/mcuboot.cmake @@ -98,7 +98,7 @@ function(zephyr_mcuboot_tasks) # Use overwrite-only instead of swap upgrades. if(CONFIG_MCUBOOT_IMGTOOL_OVERWRITE_ONLY) - set(imgtool_extra --overwrite-only ${imgtool_extra}) + set(imgtool_extra --overwrite-only --align 1 ${imgtool_extra}) endif() set(imgtool_args -- ${imgtool_extra}) From 11d52f71e573106f84e79129f0f140fa97681d7e Mon Sep 17 00:00:00 2001 From: Derek Snell Date: Tue, 5 Dec 2023 12:03:55 -0500 Subject: [PATCH 2145/3723] soc: arm: nxp: increase NUM_IRQS for RT5xx series This enables the PVT Sensor IRQ. Signed-off-by: Derek Snell --- soc/arm/nxp_imx/rt5xx/Kconfig.defconfig.series | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/soc/arm/nxp_imx/rt5xx/Kconfig.defconfig.series b/soc/arm/nxp_imx/rt5xx/Kconfig.defconfig.series index 31b6a2c70db..b277f621d0a 100644 --- a/soc/arm/nxp_imx/rt5xx/Kconfig.defconfig.series +++ b/soc/arm/nxp_imx/rt5xx/Kconfig.defconfig.series @@ -1,6 +1,6 @@ # i.MX RT5XX series configuration options -# Copyright (c) 2022-2023, NXP +# Copyright (c) 2022-2024, NXP # SPDX-License-Identifier: Apache-2.0 if SOC_SERIES_IMX_RT5XX @@ -11,8 +11,10 @@ config SOC_SERIES config ROM_START_OFFSET default 0x1200 if NXP_IMX_RT5XX_BOOT_HEADER +# The PVT Sensor uses IRQ #75. For more details, see +# https://www.nxp.com/design/design-center/software/embedded-software/application-software-packs/application-software-pack-dynamic-voltage-scaling-using-pvt-sensor:APP-SW-PACK-DVS-PVT-SENSOR config NUM_IRQS - default 74 + default 76 config ZTEST_NO_YIELD default y if (PM && ZTEST) From 8d8d3a53c0a2e106e8abeb3680b1f5300f9246d4 Mon Sep 17 00:00:00 2001 From: Derek Snell Date: Tue, 5 Dec 2023 14:18:06 -0500 Subject: [PATCH 2146/3723] boards: arm: mimxrt595_evk_cm33: add power profiles Power profiles enable the app to dynamically switch modes and support DVFS. These profiles leverage the PCA9420 PMIC to change the VDDCORE voltage, and optimize power consumption. Two runtime profiles are provided for the application: * main_clk sourced from FRO192M, VDDCORE at 0.9 V * main_clk sourced from FRO96M, VDDCORE at 0.8 V Both profiles use the FRO, and the FRO is retrimmed with the target frequency when switching profiles. Signed-off-by: Derek Snell --- boards/arm/mimxrt595_evk/CMakeLists.txt | 1 + boards/arm/mimxrt595_evk/board.c | 191 +++++++++++++++++- boards/arm/mimxrt595_evk/board.h | 10 + .../arm/mimxrt595_evk/mimxrt595_evk_cm33.dts | 7 +- 4 files changed, 206 insertions(+), 3 deletions(-) create mode 100644 boards/arm/mimxrt595_evk/board.h diff --git a/boards/arm/mimxrt595_evk/CMakeLists.txt b/boards/arm/mimxrt595_evk/CMakeLists.txt index 51294dec288..002c6976545 100644 --- a/boards/arm/mimxrt595_evk/CMakeLists.txt +++ b/boards/arm/mimxrt595_evk/CMakeLists.txt @@ -6,6 +6,7 @@ zephyr_library() zephyr_library_sources(board.c) +zephyr_library_include_directories(.) if(CONFIG_NXP_IMX_RT5XX_BOOT_HEADER) if(NOT DEFINED CONFIG_BOARD_MIMXRT595_EVK) diff --git a/boards/arm/mimxrt595_evk/board.c b/boards/arm/mimxrt595_evk/board.c index fce50f4c23d..dd2cb36354c 100644 --- a/boards/arm/mimxrt595_evk/board.c +++ b/boards/arm/mimxrt595_evk/board.c @@ -6,19 +6,45 @@ #include #include "fsl_power.h" #include +#include "board.h" + +#ifdef CONFIG_FLASH_MCUX_FLEXSPI_XIP +#include "flash_clock_setup.h" +#endif + +/* OTP fuse index. */ +#define FRO_192MHZ_SC_TRIM 0x2C +#define FRO_192MHZ_RD_TRIM 0x2B +#define FRO_96MHZ_SC_TRIM 0x2E +#define FRO_96MHZ_RD_TRIM 0x2D + +#define OTP_FUSE_READ_API ((void (*)(uint32_t addr, uint32_t *data))0x1300805D) + +#define PMIC_MODE_BOOT 0U +#define PMIC_MODE_DEEP_SLEEP 1U +#define PMIC_MODE_FRO192M_900MV 2U +#define PMIC_MODE_FRO96M_800MV 3U + +#define PMIC_SETTLING_TIME 2000U /* in micro-seconds */ + +static uint32_t sc_trim_192, rd_trim_192, sc_trim_96, rd_trim_96; #if CONFIG_REGULATOR #include +#define NODE_PCA9420 DT_NODELABEL(pca9420) #define NODE_SW1 DT_NODELABEL(pca9420_sw1) #define NODE_SW2 DT_NODELABEL(pca9420_sw2) #define NODE_LDO1 DT_NODELABEL(pca9420_ldo1) #define NODE_LDO2 DT_NODELABEL(pca9420_ldo2) +static const struct device *pca9420 = DEVICE_DT_GET(NODE_PCA9420); static const struct device *sw1 = DEVICE_DT_GET(NODE_SW1); static const struct device *sw2 = DEVICE_DT_GET(NODE_SW2); static const struct device *ldo1 = DEVICE_DT_GET(NODE_LDO1); static const struct device *ldo2 = DEVICE_DT_GET(NODE_LDO2); +static int current_power_profile; + #define MEGA (1000000U) /* Core frequency levels number. */ @@ -93,7 +119,148 @@ static int board_config_pmic(void) return ret; } -#endif + +static int board_pmic_change_mode(uint8_t pmic_mode) +{ + int ret; + + if (pmic_mode >= 4) { + return -ERANGE; + } + + ret = regulator_parent_dvs_state_set(pca9420, pmic_mode); + if (ret != -EPERM) { + return ret; + } + + POWER_SetPmicMode(pmic_mode, kCfg_Run); + k_busy_wait(PMIC_SETTLING_TIME); + + return 0; +} + +/* Changes power-related config to preset profiles, like clocks and VDDCORE voltage */ +__ramfunc int32_t power_manager_set_profile(uint32_t power_profile) +{ + bool voltage_changed = false; + int32_t current_uv, future_uv; + int ret; + + if (power_profile == current_power_profile) { + return 0; + } + + /* Confirm valid power_profile, and read the new VDDCORE voltage */ + switch (power_profile) { + case POWER_PROFILE_AFTER_BOOT: + future_uv = DT_PROP(NODE_SW1, nxp_mode0_microvolt); + break; + + case POWER_PROFILE_FRO192M_900MV: + future_uv = DT_PROP(NODE_SW1, nxp_mode2_microvolt); + break; + + case POWER_PROFILE_FRO96M_800MV: + future_uv = DT_PROP(NODE_SW1, nxp_mode3_microvolt); + break; + + default: + return -EINVAL; + } + + if (current_power_profile == POWER_PROFILE_AFTER_BOOT) { + /* One-Time optimization after boot */ + + POWER_DisableLVD(); + + CLOCK_AttachClk(kFRO_DIV1_to_MAIN_CLK); + /* Set SYSCPUAHBCLKDIV divider to value 1 */ + CLOCK_SetClkDiv(kCLOCK_DivSysCpuAhbClk, 1U); + + /* Other clock optimizations */ + #ifdef CONFIG_FLASH_MCUX_FLEXSPI_XIP + flexspi_setup_clock(FLEXSPI0, 0U, 1U); /* main_clk div by 1 */ + #endif + /* Disable the PFDs of SYSPLL */ + CLKCTL0->SYSPLL0PFD |= CLKCTL0_SYSPLL0PFD_PFD0_CLKGATE_MASK | + CLKCTL0_SYSPLL0PFD_PFD1_CLKGATE_MASK | + CLKCTL0_SYSPLL0PFD_PFD2_CLKGATE_MASK; + + POWER_EnablePD(kPDRUNCFG_PD_SYSPLL_LDO); + POWER_EnablePD(kPDRUNCFG_PD_SYSPLL_ANA); + POWER_EnablePD(kPDRUNCFG_PD_AUDPLL_LDO); + POWER_EnablePD(kPDRUNCFG_PD_AUDPLL_ANA); + POWER_EnablePD(kPDRUNCFG_PD_SYSXTAL); + + /* Configure MCU that PMIC supplies will be powered in all + * PMIC modes + */ + PMC->PMICCFG = 0xFF; + + } + + /* Get current and future PMIC voltages to determine DVFS sequence */ + ret = regulator_get_voltage(sw1, ¤t_uv); + if (ret) { + return ret; + } + + if (power_profile == POWER_PROFILE_FRO192M_900MV) { + /* check if voltage or frequency change is first */ + if (future_uv > current_uv) { + /* Increase voltage first before frequencies */ + ret = board_pmic_change_mode(PMIC_MODE_FRO192M_900MV); + if (ret) { + return ret; + } + + voltage_changed = true; + } + + /* Trim FRO to 192MHz */ + CLKCTL0->FRO_SCTRIM = sc_trim_192; + CLKCTL0->FRO_RDTRIM = rd_trim_192; + /* Reset the EXP_COUNT. */ + CLKCTL0->FRO_CONTROL &= ~CLKCTL0_FRO_CONTROL_EXP_COUNT_MASK; + + CLOCK_AttachClk(kFRO_DIV1_to_MAIN_CLK); + /* Set SYSCPUAHBCLKDIV divider to value 1 */ + CLOCK_SetClkDiv(kCLOCK_DivSysCpuAhbClk, 1U); + + if (voltage_changed == false) { + ret = board_pmic_change_mode(PMIC_MODE_FRO192M_900MV); + if (ret) { + return ret; + } + } + + } else if (power_profile == POWER_PROFILE_FRO96M_800MV) { + /* This PMIC mode is the lowest voltage used for DVFS, + * Reduce frequency first, and then reduce voltage + */ + + /* Trim the FRO to 96MHz */ + CLKCTL0->FRO_SCTRIM = sc_trim_96; + CLKCTL0->FRO_RDTRIM = rd_trim_96; + /* Reset the EXP_COUNT. */ + CLKCTL0->FRO_CONTROL &= ~CLKCTL0_FRO_CONTROL_EXP_COUNT_MASK; + + CLOCK_AttachClk(kFRO_DIV1_to_MAIN_CLK); + /* Set SYSCPUAHBCLKDIV divider to value 1 */ + CLOCK_SetClkDiv(kCLOCK_DivSysCpuAhbClk, 1U); + + ret = board_pmic_change_mode(PMIC_MODE_FRO96M_800MV); + if (ret) { + return ret; + } + } + + current_power_profile = power_profile; + + return 0; +} + +#endif /* CONFIG_REGULATOR */ static int mimxrt595_evk_init(void) { @@ -153,6 +320,28 @@ static int mimxrt595_evk_init(void) */ OCOTP0->OTP_SHADOW[97] = 0x164000; #endif /* CONFIG_REBOOT */ + + /* Read 192M FRO clock Trim settings from fuses. + * NOTE: Reading OTP fuses requires a VDDCORE voltage of at least 1.0V + */ + OTP_FUSE_READ_API(FRO_192MHZ_SC_TRIM, &sc_trim_192); + OTP_FUSE_READ_API(FRO_192MHZ_RD_TRIM, &rd_trim_192); + + /* Read 96M FRO clock Trim settings from fuses. */ + OTP_FUSE_READ_API(FRO_96MHZ_SC_TRIM, &sc_trim_96); + OTP_FUSE_READ_API(FRO_96MHZ_RD_TRIM, &rd_trim_96); + + /* Check if the 96MHz fuses have been programmed. + * Production devices have 96M trim values programmed in OTP fuses. + * However, older EVKs may have pre-production silicon. + */ + if ((rd_trim_96 == 0) && (sc_trim_96 == 0)) { + /* If not programmed then use software to calculate the trim values */ + CLOCK_FroTuneToFreq(96000000u); + rd_trim_96 = CLKCTL0->FRO_RDTRIM; + sc_trim_96 = sc_trim_192; + } + return 0; } diff --git a/boards/arm/mimxrt595_evk/board.h b/boards/arm/mimxrt595_evk/board.h new file mode 100644 index 00000000000..f30095651f9 --- /dev/null +++ b/boards/arm/mimxrt595_evk/board.h @@ -0,0 +1,10 @@ +/* + * Copyright 2023 NXP + * SPDX-License-Identifier: Apache-2.0 + */ + +#define POWER_PROFILE_FRO192M_900MV 0xFF +#define POWER_PROFILE_FRO96M_800MV 0x1 +#define POWER_PROFILE_AFTER_BOOT 0x0 + +__ramfunc int32_t power_manager_set_profile(uint32_t power_profile); diff --git a/boards/arm/mimxrt595_evk/mimxrt595_evk_cm33.dts b/boards/arm/mimxrt595_evk/mimxrt595_evk_cm33.dts index b91a45f5008..a00a5ca844e 100644 --- a/boards/arm/mimxrt595_evk/mimxrt595_evk_cm33.dts +++ b/boards/arm/mimxrt595_evk/mimxrt595_evk_cm33.dts @@ -238,7 +238,8 @@ arduino_serial: &flexcomm12 { regulator-boot-on; nxp,mode0-microvolt = <1100000>; nxp,mode1-microvolt = <600000>; - nxp,mode2-microvolt = <0>; + nxp,mode2-microvolt = <900000>; + nxp,mode3-microvolt = <800000>; }; pca9420_sw2: BUCK2 { @@ -246,7 +247,7 @@ arduino_serial: &flexcomm12 { nxp,mode0-microvolt = <1800000>; nxp,mode1-microvolt = <1800000>; nxp,mode2-microvolt = <1800000>; - + nxp,mode3-microvolt = <1800000>; }; pca9420_ldo1: LDO1 { @@ -254,6 +255,7 @@ arduino_serial: &flexcomm12 { nxp,mode0-microvolt = <1800000>; nxp,mode1-microvolt = <1800000>; nxp,mode2-microvolt = <1800000>; + nxp,mode3-microvolt = <1800000>; }; pca9420_ldo2: LDO2 { @@ -261,6 +263,7 @@ arduino_serial: &flexcomm12 { nxp,mode0-microvolt = <3300000>; nxp,mode1-microvolt = <3300000>; nxp,mode2-microvolt = <3300000>; + nxp,mode3-microvolt = <3300000>; }; }; }; From 2b30259e9f043a0d6683a75b378cfd6c23211b05 Mon Sep 17 00:00:00 2001 From: Vinayak Kariappa Chettimada Date: Tue, 14 Feb 2023 13:16:37 +0530 Subject: [PATCH 2147/3723] Bluetooth: Controller: Fix ull_prepare_dequeue for skipped events Fix ull_prepare_dequeue to not skip events when preempt does not match the event in the head of the prepare queue. The head of the prepare queue does not match when ull_prepare_dequeue has put the head of the queue to the last of the queue when it is calling lll_resume interface. This happens when there is already an active event which needs a preempt timeout to be setup and there is another non-resume event in the pipeline which now becomes the head. The fix ensure to restore the order of the events if a preempt timeout was to be setup. Currently ull_prepare_dequeue loops through all events before stopping at the original way the queue was. This is not efficient and is a scope for improvement in future. This reverts commit 91781306e95c ("Revert "Bluetooth: Controller: Fix ull_prepare_dequeue for skipped events""). Signed-off-by: Vinayak Kariappa Chettimada --- subsys/bluetooth/controller/ll_sw/ull.c | 48 +++++++++++++++---------- 1 file changed, 30 insertions(+), 18 deletions(-) diff --git a/subsys/bluetooth/controller/ll_sw/ull.c b/subsys/bluetooth/controller/ll_sw/ull.c index 3130978df4e..1a44dfc0b12 100644 --- a/subsys/bluetooth/controller/ll_sw/ull.c +++ b/subsys/bluetooth/controller/ll_sw/ull.c @@ -2065,6 +2065,8 @@ void *ull_prepare_dequeue_iter(uint8_t *idx) void ull_prepare_dequeue(uint8_t caller_id) { + void *param_normal_head = NULL; + void *param_normal_next = NULL; void *param_resume_head = NULL; void *param_resume_next = NULL; struct lll_event *next; @@ -2105,31 +2107,41 @@ void ull_prepare_dequeue(uint8_t caller_id) /* The prepare element was not a resume event, it would * use the radio or was enqueued back into prepare * pipeline with a preempt timeout being set. + * + * Remember the first encountered and the next element + * in the prepare pipeline so that we do not infinitely + * loop through the resume events in prepare pipeline. */ if (!is_resume) { - break; - } - - /* Remember the first encountered resume and the next - * resume element in the prepare pipeline so that we do - * not infinitely loop through the resume events in - * prepare pipeline. - */ - if (!param_resume_head) { - param_resume_head = param; - } else if (!param_resume_next) { - param_resume_next = param; + if (!param_normal_head) { + param_normal_head = param; + } else if (!param_normal_next) { + param_normal_next = param; + } + } else { + if (!param_resume_head) { + param_resume_head = param; + } else if (!param_resume_next) { + param_resume_next = param; + } } /* Stop traversing the prepare pipeline when we reach - * back to the first or next resume event where we + * back to the first or next event where we * initially started processing the prepare pipeline. */ - if (next->is_resume && - ((next->prepare_param.param == - param_resume_head) || - (next->prepare_param.param == - param_resume_next))) { + if (!next->is_aborted && + ((!next->is_resume && + ((next->prepare_param.param == + param_normal_head) || + (next->prepare_param.param == + param_normal_next))) || + (next->is_resume && + !param_normal_next && + ((next->prepare_param.param == + param_resume_head) || + (next->prepare_param.param == + param_resume_next))))) { break; } } From 7f99677aa6b5f622dad0d89faf9df3b178f3b47e Mon Sep 17 00:00:00 2001 From: Vinayak Kariappa Chettimada Date: Thu, 30 Nov 2023 11:49:04 +0100 Subject: [PATCH 2148/3723] Bluetooth: Controller: Add support for DYNAMIC_INTERRUPTS MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Add support for DYNAMIC_INTERRUPTS and ARM specific DYNAMIC_DIRECT_INTERRUPTS. Co-authored-by: Radosław Koppel Signed-off-by: Vinayak Kariappa Chettimada --- .../bluetooth/controller/Kconfig.ll_sw_split | 11 ++++ .../controller/ll_sw/nordic/lll/lll.c | 64 +++++++++++++++++++ 2 files changed, 75 insertions(+) diff --git a/subsys/bluetooth/controller/Kconfig.ll_sw_split b/subsys/bluetooth/controller/Kconfig.ll_sw_split index 0e2685f29ca..ad292a87f0c 100644 --- a/subsys/bluetooth/controller/Kconfig.ll_sw_split +++ b/subsys/bluetooth/controller/Kconfig.ll_sw_split @@ -560,6 +560,17 @@ config BT_CTLR_ZLI shall not use Zero Latency IRQ themselves when this option is selected, else will impact controller stability. +config BT_CTLR_DYNAMIC_INTERRUPTS + bool "Use Dynamic Interrupts allocation only" + depends on DYNAMIC_INTERRUPTS + help + Allocate all Controller required interrupts dynamically. This makes + sure that interrupts are properly connected when the Controller is + initialized and not only during the system startup. Thanks to that + application is able to enable Controller and its ISR at runtime, and + permit use of SoC's peripheral for custom use when Bluetooth is not + enabled. + config BT_CTLR_OPTIMIZE_FOR_SPEED prompt "Optimize for Speed" if !(SOC_SERIES_NRF51X && BT_CTLR_LE_ENC) bool diff --git a/subsys/bluetooth/controller/ll_sw/nordic/lll/lll.c b/subsys/bluetooth/controller/ll_sw/nordic/lll/lll.c index 473282eb618..30fca6d1e2e 100644 --- a/subsys/bluetooth/controller/ll_sw/nordic/lll/lll.c +++ b/subsys/bluetooth/controller/ll_sw/nordic/lll/lll.c @@ -86,7 +86,12 @@ static void ticker_op_job_disable(uint32_t status, void *op_context); #endif #endif /* CONFIG_BT_CTLR_LOW_LAT */ +#if defined(CONFIG_BT_CTLR_DYNAMIC_INTERRUPTS) && \ + defined(CONFIG_DYNAMIC_DIRECT_INTERRUPTS) +static void radio_nrf5_isr(const void *arg) +#else /* !CONFIG_BT_CTLR_DYNAMIC_INTERRUPTS */ ISR_DIRECT_DECLARE(radio_nrf5_isr) +#endif /* !CONFIG_BT_CTLR_DYNAMIC_INTERRUPTS */ { DEBUG_RADIO_ISR(1); @@ -99,7 +104,11 @@ ISR_DIRECT_DECLARE(radio_nrf5_isr) lll_prof_exit_radio(); DEBUG_RADIO_ISR(0); + +#if !defined(CONFIG_BT_CTLR_DYNAMIC_INTERRUPTS) || \ + !defined(CONFIG_DYNAMIC_DIRECT_INTERRUPTS) return 1; +#endif /* !CONFIG_DYNAMIC_DIRECT_INTERRUPTS */ } static void rtc0_nrf5_isr(const void *arg) @@ -187,6 +196,27 @@ int lll_init(void) hal_swi_init(); /* Connect ISRs */ +#if defined(CONFIG_BT_CTLR_DYNAMIC_INTERRUPTS) +#if defined(CONFIG_DYNAMIC_DIRECT_INTERRUPTS) + ARM_IRQ_DIRECT_DYNAMIC_CONNECT(RADIO_IRQn, CONFIG_BT_CTLR_LLL_PRIO, + IRQ_CONNECT_FLAGS, no_reschedule); + irq_connect_dynamic(RADIO_IRQn, CONFIG_BT_CTLR_LLL_PRIO, + radio_nrf5_isr, NULL, IRQ_CONNECT_FLAGS); +#else /* !CONFIG_DYNAMIC_DIRECT_INTERRUPTS */ + IRQ_DIRECT_CONNECT(RADIO_IRQn, CONFIG_BT_CTLR_LLL_PRIO, + radio_nrf5_isr, IRQ_CONNECT_FLAGS); +#endif /* !CONFIG_DYNAMIC_DIRECT_INTERRUPTS */ + irq_connect_dynamic(RTC0_IRQn, CONFIG_BT_CTLR_ULL_HIGH_PRIO, + rtc0_nrf5_isr, NULL, 0U); + irq_connect_dynamic(HAL_SWI_RADIO_IRQ, CONFIG_BT_CTLR_LLL_PRIO, + swi_lll_nrf5_isr, NULL, IRQ_CONNECT_FLAGS); +#if defined(CONFIG_BT_CTLR_LOW_LAT) || \ + (CONFIG_BT_CTLR_ULL_HIGH_PRIO != CONFIG_BT_CTLR_ULL_LOW_PRIO) + irq_connect_dynamic(HAL_SWI_JOB_IRQ, CONFIG_BT_CTLR_ULL_LOW_PRIO, + swi_ull_low_nrf5_isr, NULL, 0U); +#endif + +#else /* !CONFIG_BT_CTLR_DYNAMIC_INTERRUPTS */ IRQ_DIRECT_CONNECT(RADIO_IRQn, CONFIG_BT_CTLR_LLL_PRIO, radio_nrf5_isr, IRQ_CONNECT_FLAGS); IRQ_CONNECT(RTC0_IRQn, CONFIG_BT_CTLR_ULL_HIGH_PRIO, @@ -198,6 +228,7 @@ int lll_init(void) IRQ_CONNECT(HAL_SWI_JOB_IRQ, CONFIG_BT_CTLR_ULL_LOW_PRIO, swi_ull_low_nrf5_isr, NULL, 0); #endif +#endif /* !CONFIG_BT_CTLR_DYNAMIC_INTERRUPTS */ /* Enable IRQs */ irq_enable(RADIO_IRQn); @@ -232,6 +263,39 @@ int lll_deinit(void) irq_disable(HAL_SWI_JOB_IRQ); } + /* Disconnect dynamic ISRs used */ +#if defined(CONFIG_BT_CTLR_DYNAMIC_INTERRUPTS) +#if defined(CONFIG_SHARED_INTERRUPTS) +#if defined(CONFIG_DYNAMIC_DIRECT_INTERRUPTS) + irq_disconnect_dynamic(RADIO_IRQn, CONFIG_BT_CTLR_LLL_PRIO, + radio_nrf5_isr, NULL, IRQ_CONNECT_FLAGS); +#endif /* CONFIG_DYNAMIC_DIRECT_INTERRUPTS */ + irq_disconnect_dynamic(RTC0_IRQn, CONFIG_BT_CTLR_ULL_HIGH_PRIO, + rtc0_nrf5_isr, NULL, 0U); + irq_disconnect_dynamic(HAL_SWI_RADIO_IRQ, CONFIG_BT_CTLR_LLL_PRIO, + swi_lll_nrf5_isr, NULL, IRQ_CONNECT_FLAGS); +#if defined(CONFIG_BT_CTLR_LOW_LAT) || \ + (CONFIG_BT_CTLR_ULL_HIGH_PRIO != CONFIG_BT_CTLR_ULL_LOW_PRIO) + irq_disconnect_dynamic(HAL_SWI_JOB_IRQ, CONFIG_BT_CTLR_ULL_LOW_PRIO, + swi_ull_low_nrf5_isr, NULL, 0U); +#endif +#else /* !CONFIG_SHARED_INTERRUPTS */ +#if defined(CONFIG_DYNAMIC_DIRECT_INTERRUPTS) + irq_connect_dynamic(RADIO_IRQn, CONFIG_BT_CTLR_LLL_PRIO, NULL, NULL, + IRQ_CONNECT_FLAGS); +#endif /* CONFIG_DYNAMIC_DIRECT_INTERRUPTS */ + irq_connect_dynamic(RTC0_IRQn, CONFIG_BT_CTLR_ULL_HIGH_PRIO, NULL, NULL, + 0U); + irq_connect_dynamic(HAL_SWI_RADIO_IRQ, CONFIG_BT_CTLR_LLL_PRIO, NULL, + NULL, IRQ_CONNECT_FLAGS); +#if defined(CONFIG_BT_CTLR_LOW_LAT) || \ + (CONFIG_BT_CTLR_ULL_HIGH_PRIO != CONFIG_BT_CTLR_ULL_LOW_PRIO) + irq_connect_dynamic(HAL_SWI_JOB_IRQ, CONFIG_BT_CTLR_ULL_LOW_PRIO, NULL, + NULL, 0U); +#endif +#endif /* !CONFIG_SHARED_INTERRUPTS */ +#endif /* CONFIG_BT_CTLR_DYNAMIC_INTERRUPTS */ + return 0; } From 76f547e7633266c51a6e9c147da1658afa9e5b88 Mon Sep 17 00:00:00 2001 From: Daniel DeGrasse Date: Wed, 10 Jan 2024 12:17:53 -0600 Subject: [PATCH 2149/3723] net: l2: wifi: wifi_utils: Resolve build warning with strncpy function ARM GCC version 12.2.0 (Zephyr SDK 0.16.4) generates the following build warning from the strncpy call in "wifi_utils_parse_scan_bands": warning: '__builtin_strncpy' output truncated before terminating nul copying as many bytes from a string as its length To resolve this warning, pass the maximum length of the temporary parse_str buffer to strncpy. This also has the benefit of correctly null terminating parse_str, since we already verify the scan_bands_str is properly null terminated with the strlen() check in this function. We can therefore remove the line adding a null terminator to parse_str as well. Signed-off-by: Daniel DeGrasse --- subsys/net/l2/wifi/wifi_utils.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/subsys/net/l2/wifi/wifi_utils.c b/subsys/net/l2/wifi/wifi_utils.c index 79c858c5dd7..177e0d8ee02 100644 --- a/subsys/net/l2/wifi/wifi_utils.c +++ b/subsys/net/l2/wifi/wifi_utils.c @@ -241,8 +241,7 @@ int wifi_utils_parse_scan_bands(char *scan_bands_str, uint8_t *band_map) return -EINVAL; } - strncpy(parse_str, scan_bands_str, len); - parse_str[len] = '\0'; + strncpy(parse_str, scan_bands_str, sizeof(parse_str)); band_str = strtok_r(parse_str, ",", &ctx); From 765519ea92df3fccc54f190065a4d91f2e8d47f4 Mon Sep 17 00:00:00 2001 From: Armando Visconti Date: Wed, 10 Jan 2024 10:12:51 +0100 Subject: [PATCH 2150/3723] drivers/sensor: fix some ST drivers dependency to HAL_ST module In order to avoid build failures as described in issue #67242, make all ST drivers using HAL_ST module dependent to HAL_STMEMSC and HAS_STLIB libs, which need to be configured in all samples referring to them. Signed-off-by: Armando Visconti --- MAINTAINERS.yml | 2 +- drivers/sensor/hts221/Kconfig | 1 + drivers/sensor/i3g4250d/Kconfig | 1 + drivers/sensor/iis2dh/Kconfig | 1 + drivers/sensor/iis2dlpc/Kconfig | 1 + drivers/sensor/iis2iclx/Kconfig | 1 + drivers/sensor/iis2mdc/Kconfig | 1 + drivers/sensor/iis3dhhc/Kconfig | 1 + drivers/sensor/ism330dhcx/Kconfig | 1 + drivers/sensor/lis2ds12/Kconfig | 1 + drivers/sensor/lis2du12/Kconfig | 1 + drivers/sensor/lis2dw12/Kconfig | 1 + drivers/sensor/lis2mdl/Kconfig | 1 + drivers/sensor/lps22hh/Kconfig | 1 + drivers/sensor/lps2xdf/Kconfig | 1 + drivers/sensor/lsm6dso/Kconfig | 1 + drivers/sensor/lsm6dso16is/Kconfig | 1 + drivers/sensor/lsm6dsv16x/Kconfig | 1 + drivers/sensor/stts751/Kconfig | 1 + drivers/sensor/vl53l0x/Kconfig | 1 + drivers/sensor/vl53l1x/Kconfig | 1 + modules/Kconfig | 1 - modules/{Kconfig.st => hal_st/Kconfig} | 6 ++++-- west.yml | 2 +- 24 files changed, 26 insertions(+), 5 deletions(-) rename modules/{Kconfig.st => hal_st/Kconfig} (94%) diff --git a/MAINTAINERS.yml b/MAINTAINERS.yml index 6a9c1eef3b7..d8768d52863 100644 --- a/MAINTAINERS.yml +++ b/MAINTAINERS.yml @@ -4066,7 +4066,7 @@ West: collaborators: - erwango files: - - modules/Kconfig.st + - modules/hal_st/Kconfig labels: - "area: Sensors" diff --git a/drivers/sensor/hts221/Kconfig b/drivers/sensor/hts221/Kconfig index 5c3ff69273a..bb2ce7d848a 100644 --- a/drivers/sensor/hts221/Kconfig +++ b/drivers/sensor/hts221/Kconfig @@ -5,6 +5,7 @@ menuconfig HTS221 bool "HTS221 temperature and humidity sensor" default y depends on DT_HAS_ST_HTS221_ENABLED + depends on ZEPHYR_HAL_ST_MODULE select I2C if $(dt_compat_on_bus,$(DT_COMPAT_ST_HTS221),i2c) select SPI if $(dt_compat_on_bus,$(DT_COMPAT_ST_HTS221),spi) select HAS_STMEMSC diff --git a/drivers/sensor/i3g4250d/Kconfig b/drivers/sensor/i3g4250d/Kconfig index 4a9d5b80fd6..6f9dd720a95 100644 --- a/drivers/sensor/i3g4250d/Kconfig +++ b/drivers/sensor/i3g4250d/Kconfig @@ -7,6 +7,7 @@ config I3G4250D bool "I3G4250D three-axis digital output gyroscope" default y depends on DT_HAS_ST_I3G4250D_ENABLED + depends on ZEPHYR_HAL_ST_MODULE select SPI select HAS_STMEMSC select USE_STDC_I3G4250D diff --git a/drivers/sensor/iis2dh/Kconfig b/drivers/sensor/iis2dh/Kconfig index 5067b283ead..8e072265b0d 100644 --- a/drivers/sensor/iis2dh/Kconfig +++ b/drivers/sensor/iis2dh/Kconfig @@ -7,6 +7,7 @@ menuconfig IIS2DH bool "IIS2DH I2C/SPI accelerometer sensor driver" default y depends on DT_HAS_ST_IIS2DH_ENABLED + depends on ZEPHYR_HAL_ST_MODULE select I2C if $(dt_compat_on_bus,$(DT_COMPAT_ST_IIS2DH),i2c) select SPI if $(dt_compat_on_bus,$(DT_COMPAT_ST_IIS2DH),spi) select HAS_STMEMSC diff --git a/drivers/sensor/iis2dlpc/Kconfig b/drivers/sensor/iis2dlpc/Kconfig index 6e241af0279..2a7daeb4cc6 100644 --- a/drivers/sensor/iis2dlpc/Kconfig +++ b/drivers/sensor/iis2dlpc/Kconfig @@ -7,6 +7,7 @@ menuconfig IIS2DLPC bool "IIS2DLPC I2C/SPI accelerometer sensor driver" default y depends on DT_HAS_ST_IIS2DLPC_ENABLED + depends on ZEPHYR_HAL_ST_MODULE select I2C if $(dt_compat_on_bus,$(DT_COMPAT_ST_IIS2DLPC),i2c) select SPI if $(dt_compat_on_bus,$(DT_COMPAT_ST_IIS2DLPC),spi) select HAS_STMEMSC diff --git a/drivers/sensor/iis2iclx/Kconfig b/drivers/sensor/iis2iclx/Kconfig index 030fc0bbd96..8266a60b2f9 100644 --- a/drivers/sensor/iis2iclx/Kconfig +++ b/drivers/sensor/iis2iclx/Kconfig @@ -7,6 +7,7 @@ menuconfig IIS2ICLX bool "IIS2ICLX I2C/SPI accelerometer Chip" default y depends on DT_HAS_ST_IIS2ICLX_ENABLED + depends on ZEPHYR_HAL_ST_MODULE select I2C if $(dt_compat_on_bus,$(DT_COMPAT_ST_IIS2ICLX),i2c) select SPI if $(dt_compat_on_bus,$(DT_COMPAT_ST_IIS2ICLX),spi) select HAS_STMEMSC diff --git a/drivers/sensor/iis2mdc/Kconfig b/drivers/sensor/iis2mdc/Kconfig index 2215c778c28..1f4817a0a69 100644 --- a/drivers/sensor/iis2mdc/Kconfig +++ b/drivers/sensor/iis2mdc/Kconfig @@ -5,6 +5,7 @@ menuconfig IIS2MDC bool "IIS2MDC Magnetometer" default y depends on DT_HAS_ST_IIS2MDC_ENABLED + depends on ZEPHYR_HAL_ST_MODULE select I2C if $(dt_compat_on_bus,$(DT_COMPAT_ST_IIS2MDC),i2c) select SPI if $(dt_compat_on_bus,$(DT_COMPAT_ST_IIS2MDC),spi) select HAS_STMEMSC diff --git a/drivers/sensor/iis3dhhc/Kconfig b/drivers/sensor/iis3dhhc/Kconfig index ecd112aa928..f48e35d81f6 100644 --- a/drivers/sensor/iis3dhhc/Kconfig +++ b/drivers/sensor/iis3dhhc/Kconfig @@ -7,6 +7,7 @@ menuconfig IIS3DHHC bool "IIS3DHHC accelerometer sensor" default y depends on DT_HAS_ST_IIS3DHHC_ENABLED + depends on ZEPHYR_HAL_ST_MODULE select SPI select HAS_STMEMSC select USE_STDC_IIS3DHHC diff --git a/drivers/sensor/ism330dhcx/Kconfig b/drivers/sensor/ism330dhcx/Kconfig index 75eb6d9fec9..f5a6b7d891b 100644 --- a/drivers/sensor/ism330dhcx/Kconfig +++ b/drivers/sensor/ism330dhcx/Kconfig @@ -7,6 +7,7 @@ menuconfig ISM330DHCX bool "ISM330DHCX I2C/SPI accelerometer and gyroscope Chip" default y depends on DT_HAS_ST_ISM330DHCX_ENABLED + depends on ZEPHYR_HAL_ST_MODULE select I2C if $(dt_compat_on_bus,$(DT_COMPAT_ST_ISM330DHCX),i2c) select SPI if $(dt_compat_on_bus,$(DT_COMPAT_ST_ISM330DHCX),spi) select HAS_STMEMSC diff --git a/drivers/sensor/lis2ds12/Kconfig b/drivers/sensor/lis2ds12/Kconfig index 14b063bd8ec..cc8331bdf5e 100644 --- a/drivers/sensor/lis2ds12/Kconfig +++ b/drivers/sensor/lis2ds12/Kconfig @@ -7,6 +7,7 @@ menuconfig LIS2DS12 bool "LIS2DS12 I2C/SPI accelerometer sensor driver" default y depends on DT_HAS_ST_LIS2DS12_ENABLED + depends on ZEPHYR_HAL_ST_MODULE select I2C if $(dt_compat_on_bus,$(DT_COMPAT_ST_LIS2DS12),i2c) select SPI if $(dt_compat_on_bus,$(DT_COMPAT_ST_LIS2DS12),spi) select HAS_STMEMSC diff --git a/drivers/sensor/lis2du12/Kconfig b/drivers/sensor/lis2du12/Kconfig index 24802d5fa6f..4c00b940ef1 100644 --- a/drivers/sensor/lis2du12/Kconfig +++ b/drivers/sensor/lis2du12/Kconfig @@ -7,6 +7,7 @@ menuconfig LIS2DU12 bool "LIS2DU12 I2C/SPI smartxl Chip" default y depends on DT_HAS_ST_LIS2DU12_ENABLED + depends on ZEPHYR_HAL_ST_MODULE select I2C if $(dt_compat_on_bus,$(DT_COMPAT_ST_LIS2DU12),i2c) select SPI if $(dt_compat_on_bus,$(DT_COMPAT_ST_LIS2DU12),spi) select HAS_STMEMSC diff --git a/drivers/sensor/lis2dw12/Kconfig b/drivers/sensor/lis2dw12/Kconfig index 9e34bfaea84..2241505902f 100644 --- a/drivers/sensor/lis2dw12/Kconfig +++ b/drivers/sensor/lis2dw12/Kconfig @@ -7,6 +7,7 @@ menuconfig LIS2DW12 bool "LIS2DW12 I2C/SPI accelerometer sensor driver" default y depends on DT_HAS_ST_LIS2DW12_ENABLED + depends on ZEPHYR_HAL_ST_MODULE select I2C if $(dt_compat_on_bus,$(DT_COMPAT_ST_LIS2DW12),i2c) select SPI if $(dt_compat_on_bus,$(DT_COMPAT_ST_LIS2DW12),spi) select HAS_STMEMSC diff --git a/drivers/sensor/lis2mdl/Kconfig b/drivers/sensor/lis2mdl/Kconfig index 6970a60555d..637b883b26e 100644 --- a/drivers/sensor/lis2mdl/Kconfig +++ b/drivers/sensor/lis2mdl/Kconfig @@ -5,6 +5,7 @@ menuconfig LIS2MDL bool "LIS2MDL Magnetometer" default y depends on DT_HAS_ST_LIS2MDL_ENABLED + depends on ZEPHYR_HAL_ST_MODULE select I2C if $(dt_compat_on_bus,$(DT_COMPAT_ST_LIS2MDL),i2c) select SPI if $(dt_compat_on_bus,$(DT_COMPAT_ST_LIS2MDL),spi) select HAS_STMEMSC diff --git a/drivers/sensor/lps22hh/Kconfig b/drivers/sensor/lps22hh/Kconfig index ad23e07068e..2fa57a6c485 100644 --- a/drivers/sensor/lps22hh/Kconfig +++ b/drivers/sensor/lps22hh/Kconfig @@ -7,6 +7,7 @@ menuconfig LPS22HH bool "LPS22HH pressure and temperature" default y depends on DT_HAS_ST_LPS22HH_ENABLED + depends on ZEPHYR_HAL_ST_MODULE select I2C if $(dt_compat_on_bus,$(DT_COMPAT_ST_LPS22HH),i2c) select I3C if $(dt_compat_on_bus,$(DT_COMPAT_ST_LPS22HH),i3c) select SPI if $(dt_compat_on_bus,$(DT_COMPAT_ST_LPS22HH),spi) diff --git a/drivers/sensor/lps2xdf/Kconfig b/drivers/sensor/lps2xdf/Kconfig index 9ea7b94200e..754f8c3b451 100644 --- a/drivers/sensor/lps2xdf/Kconfig +++ b/drivers/sensor/lps2xdf/Kconfig @@ -8,6 +8,7 @@ menuconfig LPS2XDF bool "LPS2xDF pressure and temperature" default y depends on DT_HAS_ST_LPS22DF_ENABLED || DT_HAS_ST_LPS28DFW_ENABLED + depends on ZEPHYR_HAL_ST_MODULE select I2C if $(dt_compat_on_bus,$(DT_COMPAT_ST_LPS22DF),i2c) ||\ $(dt_compat_on_bus,$(DT_COMPAT_ST_LPS28DFW),i2c) select I2C if $(dt_compat_on_bus,$(DT_COMPAT_ST_LPS22DF),i3c) ||\ diff --git a/drivers/sensor/lsm6dso/Kconfig b/drivers/sensor/lsm6dso/Kconfig index f1948a9769e..272deb6be95 100644 --- a/drivers/sensor/lsm6dso/Kconfig +++ b/drivers/sensor/lsm6dso/Kconfig @@ -7,6 +7,7 @@ menuconfig LSM6DSO bool "LSM6DSO I2C/SPI accelerometer and gyroscope Chip" default y depends on DT_HAS_ST_LSM6DSO_ENABLED + depends on ZEPHYR_HAL_ST_MODULE select I2C if $(dt_compat_on_bus,$(DT_COMPAT_ST_LSM6DSO),i2c) select SPI if $(dt_compat_on_bus,$(DT_COMPAT_ST_LSM6DSO),spi) select HAS_STMEMSC diff --git a/drivers/sensor/lsm6dso16is/Kconfig b/drivers/sensor/lsm6dso16is/Kconfig index eac3312d784..7994d6a782f 100644 --- a/drivers/sensor/lsm6dso16is/Kconfig +++ b/drivers/sensor/lsm6dso16is/Kconfig @@ -7,6 +7,7 @@ menuconfig LSM6DSO16IS bool "LSM6DSO16IS I2C/SPI accelerometer and gyroscope Chip" default y depends on DT_HAS_ST_LSM6DSO16IS_ENABLED + depends on ZEPHYR_HAL_ST_MODULE select I2C if $(dt_compat_on_bus,$(DT_COMPAT_ST_LSM6DSO16IS),i2c) select SPI if $(dt_compat_on_bus,$(DT_COMPAT_ST_LSM6DSO16IS),spi) select HAS_STMEMSC diff --git a/drivers/sensor/lsm6dsv16x/Kconfig b/drivers/sensor/lsm6dsv16x/Kconfig index eb894ac2e99..79463a0f4e8 100644 --- a/drivers/sensor/lsm6dsv16x/Kconfig +++ b/drivers/sensor/lsm6dsv16x/Kconfig @@ -7,6 +7,7 @@ menuconfig LSM6DSV16X bool "LSM6DSV16X I2C/SPI accelerometer and gyroscope Chip" default y depends on DT_HAS_ST_LSM6DSV16X_ENABLED + depends on ZEPHYR_HAL_ST_MODULE select I2C if $(dt_compat_on_bus,$(DT_COMPAT_ST_LSM6DSV16X),i2c) select SPI if $(dt_compat_on_bus,$(DT_COMPAT_ST_LSM6DSV16X),spi) select HAS_STMEMSC diff --git a/drivers/sensor/stts751/Kconfig b/drivers/sensor/stts751/Kconfig index d048e117e10..d4bb8eeb700 100644 --- a/drivers/sensor/stts751/Kconfig +++ b/drivers/sensor/stts751/Kconfig @@ -7,6 +7,7 @@ menuconfig STTS751 bool "STTS751 temperature sensor" default y depends on DT_HAS_ST_STTS751_ENABLED + depends on ZEPHYR_HAL_ST_MODULE select I2C select HAS_STMEMSC select USE_STDC_STTS751 diff --git a/drivers/sensor/vl53l0x/Kconfig b/drivers/sensor/vl53l0x/Kconfig index 936ef923c87..246962a2571 100644 --- a/drivers/sensor/vl53l0x/Kconfig +++ b/drivers/sensor/vl53l0x/Kconfig @@ -7,6 +7,7 @@ menuconfig VL53L0X bool "VL53L0X time of flight sensor" default y depends on DT_HAS_ST_VL53L0X_ENABLED + depends on ZEPHYR_HAL_ST_MODULE select I2C select HAS_STLIB help diff --git a/drivers/sensor/vl53l1x/Kconfig b/drivers/sensor/vl53l1x/Kconfig index 0865ff79549..99a69ae7276 100644 --- a/drivers/sensor/vl53l1x/Kconfig +++ b/drivers/sensor/vl53l1x/Kconfig @@ -7,6 +7,7 @@ menuconfig VL53L1X bool "VL53L1X time of flight sensor" default y depends on DT_HAS_ST_VL53L1X_ENABLED + depends on ZEPHYR_HAL_ST_MODULE select I2C select HAS_STLIB help diff --git a/modules/Kconfig b/modules/Kconfig index 0c1b240efec..94a3ccdf590 100644 --- a/modules/Kconfig +++ b/modules/Kconfig @@ -31,7 +31,6 @@ source "modules/Kconfig.nxp_s32" source "modules/Kconfig.silabs" source "modules/Kconfig.simplelink" source "modules/Kconfig.sof" -source "modules/Kconfig.st" source "modules/Kconfig.stm32" source "modules/Kconfig.syst" source "modules/Kconfig.telink" diff --git a/modules/Kconfig.st b/modules/hal_st/Kconfig similarity index 94% rename from modules/Kconfig.st rename to modules/hal_st/Kconfig index d853b742512..020dbdc5d35 100644 --- a/modules/Kconfig.st +++ b/modules/hal_st/Kconfig @@ -1,6 +1,8 @@ -# STLIB config +# Copyright (c) 2024 STMicroelectronics +# SPDX-License-Identifier: Apache-2.0 -# Copyright (c) 2017 STMicroelectronics +config ZEPHYR_HAL_ST_MODULE + bool config HAS_STLIB bool diff --git a/west.yml b/west.yml index 64433b970d2..290e7777917 100644 --- a/west.yml +++ b/west.yml @@ -224,7 +224,7 @@ manifest: groups: - hal - name: hal_st - revision: fb8e79d1a261fd02aadff7c142729f1954163cf3 + revision: 0643d20ae85b32c658ad11036f7c964a860ddefe path: modules/hal/st groups: - hal From 0cd776e7dd92f44d65eff44997235c9b33b81831 Mon Sep 17 00:00:00 2001 From: Henrik Brix Andersen Date: Thu, 11 Jan 2024 21:35:09 +0100 Subject: [PATCH 2151/3723] drivers: adc: shell: sort the list of compatibles Sort the list of supported ADC compatibles alphabetically. Signed-off-by: Henrik Brix Andersen --- drivers/adc/adc_shell.c | 34 ++++++++++++++++++---------------- 1 file changed, 18 insertions(+), 16 deletions(-) diff --git a/drivers/adc/adc_shell.c b/drivers/adc/adc_shell.c index 81b0d0d3d2f..9db0d9cf33b 100644 --- a/drivers/adc/adc_shell.c +++ b/drivers/adc/adc_shell.c @@ -74,37 +74,39 @@ static struct adc_hdl { struct adc_channel_cfg channel_config; uint8_t resolution; } adc_list[] = { + /* zephyr-keep-sorted-start */ + DT_FOREACH_STATUS_OKAY(adi_ad5592_adc, ADC_HDL_LIST_ENTRY) + DT_FOREACH_STATUS_OKAY(atmel_sam0_adc, ADC_HDL_LIST_ENTRY) + DT_FOREACH_STATUS_OKAY(atmel_sam_adc, ADC_HDL_LIST_ENTRY) DT_FOREACH_STATUS_OKAY(atmel_sam_afec, ADC_HDL_LIST_ENTRY) DT_FOREACH_STATUS_OKAY(espressif_esp32_adc, ADC_HDL_LIST_ENTRY) - DT_FOREACH_STATUS_OKAY(atmel_sam_adc, ADC_HDL_LIST_ENTRY) - DT_FOREACH_STATUS_OKAY(atmel_sam0_adc, ADC_HDL_LIST_ENTRY) DT_FOREACH_STATUS_OKAY(ite_it8xxx2_adc, ADC_HDL_LIST_ENTRY) + DT_FOREACH_STATUS_OKAY(maxim_max11102, ADC_HDL_LIST_ENTRY) + DT_FOREACH_STATUS_OKAY(maxim_max11103, ADC_HDL_LIST_ENTRY) + DT_FOREACH_STATUS_OKAY(maxim_max11105, ADC_HDL_LIST_ENTRY) + DT_FOREACH_STATUS_OKAY(maxim_max11106, ADC_HDL_LIST_ENTRY) + DT_FOREACH_STATUS_OKAY(maxim_max11110, ADC_HDL_LIST_ENTRY) + DT_FOREACH_STATUS_OKAY(maxim_max11111, ADC_HDL_LIST_ENTRY) + DT_FOREACH_STATUS_OKAY(maxim_max11115, ADC_HDL_LIST_ENTRY) + DT_FOREACH_STATUS_OKAY(maxim_max11116, ADC_HDL_LIST_ENTRY) + DT_FOREACH_STATUS_OKAY(maxim_max11117, ADC_HDL_LIST_ENTRY) DT_FOREACH_STATUS_OKAY(microchip_xec_adc, ADC_HDL_LIST_ENTRY) DT_FOREACH_STATUS_OKAY(nordic_nrf_adc, ADC_HDL_LIST_ENTRY) DT_FOREACH_STATUS_OKAY(nordic_nrf_saadc, ADC_HDL_LIST_ENTRY) - DT_FOREACH_STATUS_OKAY(nxp_mcux_12b1msps_sar, ADC_HDL_LIST_ENTRY) + DT_FOREACH_STATUS_OKAY(nuvoton_npcx_adc, ADC_HDL_LIST_ENTRY) DT_FOREACH_STATUS_OKAY(nxp_kinetis_adc12, ADC_HDL_LIST_ENTRY) DT_FOREACH_STATUS_OKAY(nxp_kinetis_adc16, ADC_HDL_LIST_ENTRY) + DT_FOREACH_STATUS_OKAY(nxp_mcux_12b1msps_sar, ADC_HDL_LIST_ENTRY) + DT_FOREACH_STATUS_OKAY(nxp_s32_adc_sar, ADC_HDL_LIST_ENTRY) DT_FOREACH_STATUS_OKAY(nxp_vf610_adc, ADC_HDL_LIST_ENTRY) + DT_FOREACH_STATUS_OKAY(raspberrypi_pico_adc, ADC_HDL_LIST_ENTRY) DT_FOREACH_STATUS_OKAY(st_stm32_adc, ADC_HDL_LIST_ENTRY) - DT_FOREACH_STATUS_OKAY(nuvoton_npcx_adc, ADC_HDL_LIST_ENTRY) DT_FOREACH_STATUS_OKAY(ti_ads1112, ADC_HDL_LIST_ENTRY) DT_FOREACH_STATUS_OKAY(ti_ads1119, ADC_HDL_LIST_ENTRY) DT_FOREACH_STATUS_OKAY(ti_ads114s08, ADC_HDL_LIST_ENTRY) DT_FOREACH_STATUS_OKAY(ti_cc32xx_adc, ADC_HDL_LIST_ENTRY) - DT_FOREACH_STATUS_OKAY(raspberrypi_pico_adc, ADC_HDL_LIST_ENTRY) DT_FOREACH_STATUS_OKAY(zephyr_adc_emul, ADC_HDL_LIST_ENTRY) - DT_FOREACH_STATUS_OKAY(nxp_s32_adc_sar, ADC_HDL_LIST_ENTRY) - DT_FOREACH_STATUS_OKAY(maxim_max11102, ADC_HDL_LIST_ENTRY) - DT_FOREACH_STATUS_OKAY(maxim_max11103, ADC_HDL_LIST_ENTRY) - DT_FOREACH_STATUS_OKAY(maxim_max11105, ADC_HDL_LIST_ENTRY) - DT_FOREACH_STATUS_OKAY(maxim_max11106, ADC_HDL_LIST_ENTRY) - DT_FOREACH_STATUS_OKAY(maxim_max11110, ADC_HDL_LIST_ENTRY) - DT_FOREACH_STATUS_OKAY(maxim_max11111, ADC_HDL_LIST_ENTRY) - DT_FOREACH_STATUS_OKAY(maxim_max11115, ADC_HDL_LIST_ENTRY) - DT_FOREACH_STATUS_OKAY(maxim_max11116, ADC_HDL_LIST_ENTRY) - DT_FOREACH_STATUS_OKAY(maxim_max11117, ADC_HDL_LIST_ENTRY) - DT_FOREACH_STATUS_OKAY(adi_ad5592_adc, ADC_HDL_LIST_ENTRY) + /* zephyr-keep-sorted-stop */ }; static struct adc_hdl *get_adc(const char *device_label) From 24b68fa67f44b72ca7b20ce6052d1d5ef1695537 Mon Sep 17 00:00:00 2001 From: Henrik Brix Andersen Date: Thu, 11 Jan 2024 21:45:13 +0100 Subject: [PATCH 2152/3723] drivers: adc: shell: update list of compatibles Update the list of ADC compatibles based on the compatibles from dts/bindings/adc/*.yaml. Signed-off-by: Henrik Brix Andersen --- drivers/adc/adc_shell.c | 34 ++++++++++++++++++++++++++++++++++ 1 file changed, 34 insertions(+) diff --git a/drivers/adc/adc_shell.c b/drivers/adc/adc_shell.c index 9db0d9cf33b..bc002d76972 100644 --- a/drivers/adc/adc_shell.c +++ b/drivers/adc/adc_shell.c @@ -80,7 +80,11 @@ static struct adc_hdl { DT_FOREACH_STATUS_OKAY(atmel_sam_adc, ADC_HDL_LIST_ENTRY) DT_FOREACH_STATUS_OKAY(atmel_sam_afec, ADC_HDL_LIST_ENTRY) DT_FOREACH_STATUS_OKAY(espressif_esp32_adc, ADC_HDL_LIST_ENTRY) + DT_FOREACH_STATUS_OKAY(gd_gd32_adc, ADC_HDL_LIST_ENTRY) + DT_FOREACH_STATUS_OKAY(infineon_cat1_adc, ADC_HDL_LIST_ENTRY) + DT_FOREACH_STATUS_OKAY(infineon_xmc4xxx_adc, ADC_HDL_LIST_ENTRY) DT_FOREACH_STATUS_OKAY(ite_it8xxx2_adc, ADC_HDL_LIST_ENTRY) + DT_FOREACH_STATUS_OKAY(lltc_ltc2451, ADC_HDL_LIST_ENTRY) DT_FOREACH_STATUS_OKAY(maxim_max11102, ADC_HDL_LIST_ENTRY) DT_FOREACH_STATUS_OKAY(maxim_max11103, ADC_HDL_LIST_ENTRY) DT_FOREACH_STATUS_OKAY(maxim_max11105, ADC_HDL_LIST_ENTRY) @@ -90,21 +94,51 @@ static struct adc_hdl { DT_FOREACH_STATUS_OKAY(maxim_max11115, ADC_HDL_LIST_ENTRY) DT_FOREACH_STATUS_OKAY(maxim_max11116, ADC_HDL_LIST_ENTRY) DT_FOREACH_STATUS_OKAY(maxim_max11117, ADC_HDL_LIST_ENTRY) + DT_FOREACH_STATUS_OKAY(maxim_max11253, ADC_HDL_LIST_ENTRY) + DT_FOREACH_STATUS_OKAY(maxim_max11254, ADC_HDL_LIST_ENTRY) + DT_FOREACH_STATUS_OKAY(microchip_mcp3204, ADC_HDL_LIST_ENTRY) + DT_FOREACH_STATUS_OKAY(microchip_mcp3208, ADC_HDL_LIST_ENTRY) DT_FOREACH_STATUS_OKAY(microchip_xec_adc, ADC_HDL_LIST_ENTRY) DT_FOREACH_STATUS_OKAY(nordic_nrf_adc, ADC_HDL_LIST_ENTRY) DT_FOREACH_STATUS_OKAY(nordic_nrf_saadc, ADC_HDL_LIST_ENTRY) DT_FOREACH_STATUS_OKAY(nuvoton_npcx_adc, ADC_HDL_LIST_ENTRY) + DT_FOREACH_STATUS_OKAY(nuvoton_numaker_adc, ADC_HDL_LIST_ENTRY) DT_FOREACH_STATUS_OKAY(nxp_kinetis_adc12, ADC_HDL_LIST_ENTRY) DT_FOREACH_STATUS_OKAY(nxp_kinetis_adc16, ADC_HDL_LIST_ENTRY) + DT_FOREACH_STATUS_OKAY(nxp_lpc_lpadc, ADC_HDL_LIST_ENTRY) DT_FOREACH_STATUS_OKAY(nxp_mcux_12b1msps_sar, ADC_HDL_LIST_ENTRY) DT_FOREACH_STATUS_OKAY(nxp_s32_adc_sar, ADC_HDL_LIST_ENTRY) DT_FOREACH_STATUS_OKAY(nxp_vf610_adc, ADC_HDL_LIST_ENTRY) DT_FOREACH_STATUS_OKAY(raspberrypi_pico_adc, ADC_HDL_LIST_ENTRY) + DT_FOREACH_STATUS_OKAY(renesas_smartbond_adc, ADC_HDL_LIST_ENTRY) + DT_FOREACH_STATUS_OKAY(renesas_smartbond_sdadc, ADC_HDL_LIST_ENTRY) + DT_FOREACH_STATUS_OKAY(silabs_gecko_adc, ADC_HDL_LIST_ENTRY) + DT_FOREACH_STATUS_OKAY(silabs_gecko_iadc, ADC_HDL_LIST_ENTRY) DT_FOREACH_STATUS_OKAY(st_stm32_adc, ADC_HDL_LIST_ENTRY) + DT_FOREACH_STATUS_OKAY(st_stm32f1_adc, ADC_HDL_LIST_ENTRY) + DT_FOREACH_STATUS_OKAY(st_stm32f4_adc, ADC_HDL_LIST_ENTRY) + DT_FOREACH_STATUS_OKAY(telink_b91_adc, ADC_HDL_LIST_ENTRY) + DT_FOREACH_STATUS_OKAY(ti_ads1013, ADC_HDL_LIST_ENTRY) + DT_FOREACH_STATUS_OKAY(ti_ads1014, ADC_HDL_LIST_ENTRY) + DT_FOREACH_STATUS_OKAY(ti_ads1015, ADC_HDL_LIST_ENTRY) DT_FOREACH_STATUS_OKAY(ti_ads1112, ADC_HDL_LIST_ENTRY) + DT_FOREACH_STATUS_OKAY(ti_ads1113, ADC_HDL_LIST_ENTRY) + DT_FOREACH_STATUS_OKAY(ti_ads1114, ADC_HDL_LIST_ENTRY) + DT_FOREACH_STATUS_OKAY(ti_ads1115, ADC_HDL_LIST_ENTRY) DT_FOREACH_STATUS_OKAY(ti_ads1119, ADC_HDL_LIST_ENTRY) DT_FOREACH_STATUS_OKAY(ti_ads114s08, ADC_HDL_LIST_ENTRY) + DT_FOREACH_STATUS_OKAY(ti_ads7052, ADC_HDL_LIST_ENTRY) + DT_FOREACH_STATUS_OKAY(ti_cc13xx_cc26xx_adc, ADC_HDL_LIST_ENTRY) DT_FOREACH_STATUS_OKAY(ti_cc32xx_adc, ADC_HDL_LIST_ENTRY) + DT_FOREACH_STATUS_OKAY(ti_lmp90077, ADC_HDL_LIST_ENTRY) + DT_FOREACH_STATUS_OKAY(ti_lmp90078, ADC_HDL_LIST_ENTRY) + DT_FOREACH_STATUS_OKAY(ti_lmp90079, ADC_HDL_LIST_ENTRY) + DT_FOREACH_STATUS_OKAY(ti_lmp90080, ADC_HDL_LIST_ENTRY) + DT_FOREACH_STATUS_OKAY(ti_lmp90097, ADC_HDL_LIST_ENTRY) + DT_FOREACH_STATUS_OKAY(ti_lmp90098, ADC_HDL_LIST_ENTRY) + DT_FOREACH_STATUS_OKAY(ti_lmp90099, ADC_HDL_LIST_ENTRY) + DT_FOREACH_STATUS_OKAY(ti_lmp90100, ADC_HDL_LIST_ENTRY) + DT_FOREACH_STATUS_OKAY(ti_tla2021, ADC_HDL_LIST_ENTRY) DT_FOREACH_STATUS_OKAY(zephyr_adc_emul, ADC_HDL_LIST_ENTRY) /* zephyr-keep-sorted-stop */ }; From 0b72debabcf4d3eda4f1a1ce1bc65b54dc8b265a Mon Sep 17 00:00:00 2001 From: Mahesh Mahadevan Date: Mon, 6 Nov 2023 16:22:40 +0000 Subject: [PATCH 2153/3723] dts: counter: Add binding for 1KHz counter in NXP LPC RTC A 1KHz counter is also available inside the NXP LPC RTC block. Add a binding to support that counter. Signed-off-by: Mahesh Mahadevan --- dts/bindings/counter/nxp,lpc-rtc-highres.yaml | 8 ++++++++ 1 file changed, 8 insertions(+) create mode 100644 dts/bindings/counter/nxp,lpc-rtc-highres.yaml diff --git a/dts/bindings/counter/nxp,lpc-rtc-highres.yaml b/dts/bindings/counter/nxp,lpc-rtc-highres.yaml new file mode 100644 index 00000000000..633ca5557a3 --- /dev/null +++ b/dts/bindings/counter/nxp,lpc-rtc-highres.yaml @@ -0,0 +1,8 @@ +# Copyright 2023, NXP +# SPDX-License-Identifier: Apache-2.0 + +description: Driver that uses the NXP LPC RTC High resolution counter + +compatible: "nxp,lpc-rtc-highres" + +include: base.yaml From 08705f51f2df32dbf240e0c5b5d83744d8900e38 Mon Sep 17 00:00:00 2001 From: Mahesh Mahadevan Date: Fri, 3 Nov 2023 22:13:47 -0500 Subject: [PATCH 2154/3723] drivers: mcux_lpc_rtc: Add support for 1KHz counter Add support for the 1KHz counter. Update the RTC driver to allow the 1Hz and high resolution counters to exist together. Signed-off-by: Mahesh Mahadevan --- drivers/counter/Kconfig.mcux_lpc_rtc | 19 +- drivers/counter/counter_mcux_lpc_rtc.c | 310 +++++++++++++++++++++---- 2 files changed, 283 insertions(+), 46 deletions(-) diff --git a/drivers/counter/Kconfig.mcux_lpc_rtc b/drivers/counter/Kconfig.mcux_lpc_rtc index bd012db822c..49f063116d5 100644 --- a/drivers/counter/Kconfig.mcux_lpc_rtc +++ b/drivers/counter/Kconfig.mcux_lpc_rtc @@ -1,9 +1,24 @@ -# Copyright (c) 2021, NXP +# Copyright (c) 2021-23, NXP # SPDX-License-Identifier: Apache-2.0 config COUNTER_MCUX_LPC_RTC bool "MCUX LPC RTC driver" default y + depends on DT_HAS_NXP_LPC_RTC_ENABLED || \ + DT_HAS_NXP_LPC_RTC_HIGHRES_ENABLED + help + Enable the LPC rtc driver. + +config COUNTER_MCUX_LPC_RTC_1HZ + bool "MCUX LPC RTC 1Hz counter driver" + default y depends on DT_HAS_NXP_LPC_RTC_ENABLED help - Enable support for LPC rtc driver. + Enable support for LPC 1Hz counter. + +config COUNTER_MCUX_LPC_RTC_HIGHRES + bool "MCUX LPC RTC High Resolution counter driver" + default y + depends on DT_HAS_NXP_LPC_RTC_HIGHRES_ENABLED + help + Enable support for LPC rtc high resolution counter. diff --git a/drivers/counter/counter_mcux_lpc_rtc.c b/drivers/counter/counter_mcux_lpc_rtc.c index 2bb8d920fea..433fef0683c 100644 --- a/drivers/counter/counter_mcux_lpc_rtc.c +++ b/drivers/counter/counter_mcux_lpc_rtc.c @@ -1,11 +1,9 @@ /* - * Copyright 2021-22, NXP + * Copyright 2021-23, NXP * * SPDX-License-Identifier: Apache-2.0 */ -#define DT_DRV_COMPAT nxp_lpc_rtc - #include #include #include @@ -16,17 +14,72 @@ LOG_MODULE_REGISTER(mcux_rtc, CONFIG_COUNTER_LOG_LEVEL); struct mcux_lpc_rtc_data { counter_alarm_callback_t alarm_callback; + counter_top_callback_t top_callback; void *alarm_user_data; + void *top_user_data; + uint32_t value; }; struct mcux_lpc_rtc_config { struct counter_config_info info; RTC_Type *base; + const struct device *rtc_dev; void (*irq_config_func)(const struct device *dev); /* Device defined as wake-up source */ bool wakeup_source; }; +#if CONFIG_COUNTER_MCUX_LPC_RTC_HIGHRES +static int mcux_lpc_rtc_highres_start(const struct device *dev); +#endif + +static void mcux_lpc_rtc_isr(const struct device *dev) +{ + const struct counter_config_info *info = dev->config; + const struct mcux_lpc_rtc_config *config = + CONTAINER_OF(info, struct mcux_lpc_rtc_config, info); + struct mcux_lpc_rtc_data *data = dev->data; + counter_alarm_callback_t cb; + uint32_t current = RTC_GetSecondsTimerCount(config->base); + + LOG_DBG("Current time is %d ticks", current); + + if ((RTC_GetStatusFlags(config->base) & RTC_CTRL_ALARM1HZ_MASK) && + (data->alarm_callback)) { + cb = data->alarm_callback; + data->alarm_callback = NULL; + cb(dev, 0, current, data->alarm_user_data); + } + + if (data->top_callback) { + data->top_callback(dev, data->top_user_data); + } + + /* + * Clear any conditions to ack the IRQ + * + * callback may have already reset the alarm flag if a new + * alarm value was programmed to the TAR + */ + if (RTC_GetStatusFlags(config->base) & RTC_CTRL_ALARM1HZ_MASK) { + RTC_ClearStatusFlags(config->base, kRTC_AlarmFlag); + } + + /* Check if the Wake counter interrupt was set */ + if (RTC_GetStatusFlags(config->base) & RTC_CTRL_WAKE1KHZ_MASK) { + RTC_ClearStatusFlags(config->base, kRTC_WakeupFlag); +#if CONFIG_COUNTER_MCUX_LPC_RTC_HIGHRES + if (config->base->CTRL & RTC_CTRL_RTC1KHZ_EN_MASK) { + mcux_lpc_rtc_highres_start(dev); + } +#endif + } +} + +#if CONFIG_COUNTER_MCUX_LPC_RTC_1HZ + +#define DT_DRV_COMPAT nxp_lpc_rtc + static int mcux_lpc_rtc_start(const struct device *dev) { const struct counter_config_info *info = dev->config; @@ -145,41 +198,6 @@ static uint32_t mcux_lpc_rtc_get_top_value(const struct device *dev) return info->max_top_value; } -static void mcux_lpc_rtc_isr(const struct device *dev) -{ - const struct counter_config_info *info = dev->config; - const struct mcux_lpc_rtc_config *config = - CONTAINER_OF(info, struct mcux_lpc_rtc_config, info); - struct mcux_lpc_rtc_data *data = dev->data; - counter_alarm_callback_t cb; - uint32_t current = mcux_lpc_rtc_read(dev); - uint32_t enable = (config->base->CTRL & RTC_CTRL_RTC_EN_MASK); - - - LOG_DBG("Current time is %d ticks", current); - - if ((RTC_GetStatusFlags(config->base) & RTC_CTRL_ALARM1HZ_MASK) && - (data->alarm_callback)) { - cb = data->alarm_callback; - data->alarm_callback = NULL; - cb(dev, 0, current, data->alarm_user_data); - } - - /* - * Clear any conditions to ack the IRQ - * - * callback may have already reset the alarm flag if a new - * alarm value was programmed to the TAR - */ - RTC_EnableTimer(config->base, false); - if (RTC_GetStatusFlags(config->base) & RTC_CTRL_ALARM1HZ_MASK) { - RTC_ClearStatusFlags(config->base, kRTC_AlarmFlag); - } - if (enable) { - RTC_EnableTimer(config->base, true); - } -} - static int mcux_lpc_rtc_init(const struct device *dev) { const struct counter_config_info *info = dev->config; @@ -212,11 +230,12 @@ static const struct counter_driver_api mcux_rtc_driver_api = { .get_top_value = mcux_lpc_rtc_get_top_value, }; -#define COUNTER_LPC_RTC_DEVICE(id) \ - static void mcux_lpc_rtc_irq_config_##id(const struct device *dev); \ - static const struct mcux_lpc_rtc_config mcux_lpc_rtc_config_##id = { \ - .base = (RTC_Type *)DT_INST_REG_ADDR(id), \ - .irq_config_func = mcux_lpc_rtc_irq_config_##id, \ +#define COUNTER_LPC_RTC_DEVICE(id) \ + static void mcux_lpc_rtc_irq_config_##id(const struct device *dev); \ + static const struct mcux_lpc_rtc_config mcux_lpc_rtc_config_##id = { \ + .base = (RTC_Type *)DT_INST_REG_ADDR(id), \ + .irq_config_func = mcux_lpc_rtc_irq_config_##id, \ + .rtc_dev = DEVICE_DT_GET_OR_NULL(DT_INST_CHILD(id, rtc_highres)), \ .info = { \ .max_top_value = UINT32_MAX, \ .freq = 1, \ @@ -227,7 +246,7 @@ static const struct counter_driver_api mcux_rtc_driver_api = { }; \ static struct mcux_lpc_rtc_data mcux_lpc_rtc_data_##id; \ DEVICE_DT_INST_DEFINE(id, &mcux_lpc_rtc_init, NULL, \ - &mcux_lpc_rtc_data_##id, &mcux_lpc_rtc_config_##id.info, \ + &mcux_lpc_rtc_data_##id, &mcux_lpc_rtc_config_##id.info, \ POST_KERNEL, CONFIG_COUNTER_INIT_PRIORITY, \ &mcux_rtc_driver_api); \ static void mcux_lpc_rtc_irq_config_##id(const struct device *dev) \ @@ -242,3 +261,206 @@ static const struct counter_driver_api mcux_rtc_driver_api = { } DT_INST_FOREACH_STATUS_OKAY(COUNTER_LPC_RTC_DEVICE) +#endif + +#if CONFIG_COUNTER_MCUX_LPC_RTC_HIGHRES + +#undef DT_DRV_COMPAT +#define DT_DRV_COMPAT nxp_lpc_rtc_highres + +static int mcux_lpc_rtc_highres_start(const struct device *dev) +{ + const struct counter_config_info *info = dev->config; + const struct mcux_lpc_rtc_config *config = + CONTAINER_OF(info, struct mcux_lpc_rtc_config, info); + struct mcux_lpc_rtc_data *data = dev->data; + + if (config->rtc_dev) { + /* We have another RTC driver enabled, check if RTC is enabled */ + if ((config->base->CTRL & RTC_CTRL_RTC_EN_MASK) == 0) { + /* RTC is not enabled and we do not turn it on as it will effect + * the RTC counter value thereby affecting the RTC counter drivers + */ + LOG_ERR("RTC Wake counter cannot be started as RTC is not enabled."); + return -EINVAL; + } + } else { + if ((config->base->CTRL & RTC_CTRL_RTC_EN_MASK) == 0) { + RTC_EnableTimer(config->base, true); + } + } + + if (data->value == 0) { + /* Start from the max value */ + RTC_SetWakeupCount(config->base, counter_get_top_value(dev)); + } else { + RTC_SetWakeupCount(config->base, data->value); + } + + return 0; +} + +static int mcux_lpc_rtc_highres_stop(const struct device *dev) +{ + const struct counter_config_info *info = dev->config; + const struct mcux_lpc_rtc_config *config = + CONTAINER_OF(info, struct mcux_lpc_rtc_config, info); + + config->base->CTRL &= ~RTC_CTRL_RTC1KHZ_EN_MASK; + + if (config->rtc_dev == NULL) { + /* Disable RTC as no other driver is using it */ + RTC_EnableTimer(config->base, false); + } + + return 0; +} + +static uint32_t mcux_lpc_rtc_highres_read(const struct device *dev) +{ + const struct counter_config_info *info = dev->config; + const struct mcux_lpc_rtc_config *config = + CONTAINER_OF(info, struct mcux_lpc_rtc_config, info); + + uint32_t ticks = RTC_GetWakeupCount(config->base); + + return ticks; +} + +static int mcux_lpc_rtc_highres_set_alarm(const struct device *dev, uint8_t chan_id, + const struct counter_alarm_cfg *alarm_cfg) +{ + return -ENOTSUP; +} + +static int mcux_lpc_rtc_highres_cancel_alarm(const struct device *dev, uint8_t chan_id) +{ + return -ENOTSUP; +} + + +static int mcux_lpc_rtc_highres_get_value(const struct device *dev, uint32_t *ticks) +{ + *ticks = mcux_lpc_rtc_highres_read(dev); + return 0; +} + +static int mcux_lpc_rtc_highres_set_top_value(const struct device *dev, + const struct counter_top_cfg *cfg) +{ + const struct counter_config_info *info = dev->config; + const struct mcux_lpc_rtc_config *config = + CONTAINER_OF(info, struct mcux_lpc_rtc_config, info); + struct mcux_lpc_rtc_data *data = dev->data; + + if (cfg->flags & COUNTER_TOP_CFG_DONT_RESET) { + return -ENOTSUP; + } + + data->value = cfg->ticks; + data->top_callback = cfg->callback; + data->top_user_data = cfg->user_data; + + if (config->base->CTRL & RTC_CTRL_RTC1KHZ_EN_MASK) { + return mcux_lpc_rtc_highres_start(dev); + } + + return 0; +} + +static uint32_t mcux_lpc_rtc_highres_get_pending_int(const struct device *dev) +{ + const struct counter_config_info *info = dev->config; + const struct mcux_lpc_rtc_config *config = + CONTAINER_OF(info, struct mcux_lpc_rtc_config, info); + + return RTC_GetStatusFlags(config->base) & RTC_CTRL_WAKE1KHZ_MASK; +} + +static uint32_t mcux_lpc_rtc_highres_get_top_value(const struct device *dev) +{ + struct mcux_lpc_rtc_data *data = dev->data; + const struct counter_config_info *info = dev->config; + + if (data->value == 0) { + return info->max_top_value; + } else { + return data->value; + } +} + +static int mcux_lpc_rtc_highres_init(const struct device *dev) +{ + const struct counter_config_info *info = dev->config; + const struct mcux_lpc_rtc_config *config = + CONTAINER_OF(info, struct mcux_lpc_rtc_config, info); + + /* Initialize the RTC if this is only driver using it */ + if (config->rtc_dev == NULL) { + RTC_Init(config->base); + + /* Issue a software reset to set the registers to init state */ + RTC_Reset(config->base); + + config->irq_config_func(dev); + } + + if (config->wakeup_source) { + /* Enable the bit to wakeup from Deep Power Down mode */ + RTC_EnableWakeUpTimerInterruptFromDPD(config->base, true); + } + + return 0; +} + +static const struct counter_driver_api mcux_rtc_highres_driver_api = { + .start = mcux_lpc_rtc_highres_start, + .stop = mcux_lpc_rtc_highres_stop, + .get_value = mcux_lpc_rtc_highres_get_value, + .set_alarm = mcux_lpc_rtc_highres_set_alarm, + .cancel_alarm = mcux_lpc_rtc_highres_cancel_alarm, + .set_top_value = mcux_lpc_rtc_highres_set_top_value, + .get_pending_int = mcux_lpc_rtc_highres_get_pending_int, + .get_top_value = mcux_lpc_rtc_highres_get_top_value, +}; + +#define COUNTER_LPC_RTC_HIGHRES_IRQ_INIT(n) \ + do { \ + IRQ_CONNECT(DT_IRQN(DT_INST_PARENT(n)), \ + DT_IRQ(DT_INST_PARENT(n), priority), \ + mcux_lpc_rtc_isr, \ + DEVICE_DT_INST_GET(n), 0); \ + irq_enable(DT_IRQN(DT_INST_PARENT(n))); \ + if (DT_INST_PROP(n, wakeup_source)) { \ + EnableDeepSleepIRQ(DT_IRQN(DT_INST_PARENT(n))); \ + } \ + } while (false) + +#define COUNTER_LPC_RTC_HIGHRES_DEVICE(id) \ + static void mcux_lpc_rtc_highres_irq_config_##id(const struct device *dev); \ + static const struct mcux_lpc_rtc_config mcux_lpc_rtc_highres_config_##id = { \ + .base = (RTC_Type *)DT_REG_ADDR(DT_INST_PARENT(id)), \ + .rtc_dev = DEVICE_DT_GET_OR_NULL(DT_INST_PARENT(id)), \ + .irq_config_func = mcux_lpc_rtc_highres_irq_config_##id, \ + .info = { \ + .max_top_value = UINT16_MAX, \ + .freq = 1000, \ + .channels = 0, \ + }, \ + .wakeup_source = DT_INST_PROP(id, wakeup_source) \ + }; \ + static struct mcux_lpc_rtc_data mcux_lpc_rtc_highres_data_##id; \ + DEVICE_DT_INST_DEFINE(id, &mcux_lpc_rtc_highres_init, NULL, \ + &mcux_lpc_rtc_highres_data_##id, \ + &mcux_lpc_rtc_highres_config_##id.info, \ + POST_KERNEL, CONFIG_COUNTER_INIT_PRIORITY, \ + &mcux_rtc_highres_driver_api); \ + static void mcux_lpc_rtc_highres_irq_config_##id(const struct device *dev) \ + { \ + COND_CODE_1(IS_ENABLED(DT_HAS_COMPAT_STATUS_OKAY(nxp_lpc_rtc)), \ + (), (COUNTER_LPC_RTC_HIGHRES_IRQ_INIT(id));) \ + } + +DT_INST_FOREACH_STATUS_OKAY(COUNTER_LPC_RTC_HIGHRES_DEVICE) + +#endif From 008b5027a69897a34734765bca86e9ec2784ea72 Mon Sep 17 00:00:00 2001 From: Mahesh Mahadevan Date: Mon, 6 Nov 2023 10:05:24 -0600 Subject: [PATCH 2155/3723] dts: nxp: Add support for 1Kz RTC counter A 1KHz counter is present in the LPC RTC. Add support for this counter to get better resolution for certain applications. Signed-off-by: Mahesh Mahadevan --- dts/arm/nxp/nxp_rt5xx_common.dtsi | 4 ++++ dts/arm/nxp/nxp_rt6xx_common.dtsi | 4 ++++ 2 files changed, 8 insertions(+) diff --git a/dts/arm/nxp/nxp_rt5xx_common.dtsi b/dts/arm/nxp/nxp_rt5xx_common.dtsi index 42f3951ab20..f63e27b5d6a 100644 --- a/dts/arm/nxp/nxp_rt5xx_common.dtsi +++ b/dts/arm/nxp/nxp_rt5xx_common.dtsi @@ -400,6 +400,10 @@ reg = <0x30000 0x1000>; interrupts = <32 0>; status = "disabled"; + rtc_highres: rtc_highres { + compatible = "nxp,lpc-rtc-highres"; + status = "disabled"; + }; }; trng: random@138000 { diff --git a/dts/arm/nxp/nxp_rt6xx_common.dtsi b/dts/arm/nxp/nxp_rt6xx_common.dtsi index 97a664845ec..62e8865b731 100644 --- a/dts/arm/nxp/nxp_rt6xx_common.dtsi +++ b/dts/arm/nxp/nxp_rt6xx_common.dtsi @@ -311,6 +311,10 @@ reg = <0x30000 0x1000>; interrupts = <32 0>; status = "disabled"; + rtc_highres: rtc_highres { + compatible = "nxp,lpc-rtc-highres"; + status = "disabled"; + }; }; trng: random@138000 { From 37158ebf15c8c299a1bc349bee206916842609f5 Mon Sep 17 00:00:00 2001 From: Mahesh Mahadevan Date: Mon, 6 Nov 2023 12:24:27 -0600 Subject: [PATCH 2156/3723] tests: counter: Add LPC RTC 1KHZ counter Add counter test support for the RTC 1KHz counter Signed-off-by: Mahesh Mahadevan --- .../boards/mimxrt685_evk_cm33_rtc_1khz.overlay | 7 +++++++ .../drivers/counter/counter_basic_api/src/test_counter.c | 5 ++++- tests/drivers/counter/counter_basic_api/testcase.yaml | 9 +++++++++ 3 files changed, 20 insertions(+), 1 deletion(-) create mode 100644 tests/drivers/counter/counter_basic_api/boards/mimxrt685_evk_cm33_rtc_1khz.overlay diff --git a/tests/drivers/counter/counter_basic_api/boards/mimxrt685_evk_cm33_rtc_1khz.overlay b/tests/drivers/counter/counter_basic_api/boards/mimxrt685_evk_cm33_rtc_1khz.overlay new file mode 100644 index 00000000000..3ee5af716e7 --- /dev/null +++ b/tests/drivers/counter/counter_basic_api/boards/mimxrt685_evk_cm33_rtc_1khz.overlay @@ -0,0 +1,7 @@ +&rtc { + status = "disabled"; +}; + +&rtc_highres { + status = "okay"; +}; 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 370b07b248c..642465c6078 100644 --- a/tests/drivers/counter/counter_basic_api/src/test_counter.c +++ b/tests/drivers/counter/counter_basic_api/src/test_counter.c @@ -69,9 +69,12 @@ static const struct device *const devices[] = { #ifdef CONFIG_COUNTER_NXP_MRT DEVS_FOR_DT_COMPAT(nxp_mrt_channel) #endif -#ifdef CONFIG_COUNTER_MCUX_LPC_RTC +#ifdef CONFIG_COUNTER_MCUX_LPC_RTC_1HZ DEVS_FOR_DT_COMPAT(nxp_lpc_rtc) #endif +#ifdef CONFIG_COUNTER_MCUX_LPC_RTC_HIGHRES + DEVS_FOR_DT_COMPAT(nxp_lpc_rtc_highres) +#endif #ifdef CONFIG_COUNTER_GECKO_RTCC DEVS_FOR_DT_COMPAT(silabs_gecko_rtcc) #endif diff --git a/tests/drivers/counter/counter_basic_api/testcase.yaml b/tests/drivers/counter/counter_basic_api/testcase.yaml index 2173d417c06..f6210c0bc74 100644 --- a/tests/drivers/counter/counter_basic_api/testcase.yaml +++ b/tests/drivers/counter/counter_basic_api/testcase.yaml @@ -27,3 +27,12 @@ tests: timeout: 600 extra_configs: - CONFIG_COUNTER_RTC_STM32_SUBSECONDS=y + drivers.counter.basic_api.rtc_1khz: + tags: + - drivers + - counter + depends_on: counter + platform_allow: mimxrt685_evk_cm33 + timeout: 400 + extra_args: + DTC_OVERLAY_FILE="boards/mimxrt685_evk_cm33_rtc_1khz.overlay" From 12f4f4dc86791d9446b58b399d5b41cf8ee3cb86 Mon Sep 17 00:00:00 2001 From: Wojciech Sipak Date: Tue, 12 Dec 2023 15:32:59 +0100 Subject: [PATCH 2157/3723] samples: hello_world_user: fail in compilation if userspace is not enabled The sample depends on CONFIG_USERSPACE. Signed-off-by: Wojciech Sipak --- samples/userspace/hello_world_user/src/main.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/samples/userspace/hello_world_user/src/main.c b/samples/userspace/hello_world_user/src/main.c index 0a2b724117e..3223d4a1a27 100644 --- a/samples/userspace/hello_world_user/src/main.c +++ b/samples/userspace/hello_world_user/src/main.c @@ -8,6 +8,10 @@ #include #define USER_STACKSIZE 2048 +#ifndef CONFIG_USERSPACE +#error This sample requires CONFIG_USERSPACE. +#endif + struct k_thread user_thread; K_THREAD_STACK_DEFINE(user_stack, USER_STACKSIZE); From e9b56bd1ecdb544f0c3facd9f292125059e27c8e Mon Sep 17 00:00:00 2001 From: Nick Ward Date: Fri, 29 Dec 2023 22:01:32 +1100 Subject: [PATCH 2158/3723] drivers: sensor: bq274xx: remove float use Remove float usage in calculation of SENSOR_CHAN_GAUGE_TEMP Signed-off-by: Nick Ward --- drivers/sensor/bq274xx/bq274xx.c | 15 ++++++++++----- 1 file changed, 10 insertions(+), 5 deletions(-) diff --git a/drivers/sensor/bq274xx/bq274xx.c b/drivers/sensor/bq274xx/bq274xx.c index 27810204798..13275638df5 100644 --- a/drivers/sensor/bq274xx/bq274xx.c +++ b/drivers/sensor/bq274xx/bq274xx.c @@ -62,6 +62,9 @@ LOG_MODULE_REGISTER(bq274xx, CONFIG_SENSOR_LOG_LEVEL); #define BQ274XX_SUBCLASS_82 82 #define BQ274XX_SUBCLASS_105 105 +/* For temperature conversion */ +#define KELVIN_OFFSET 273.15 + static const struct bq274xx_regs bq27421_regs = { .dm_design_capacity = 10, .dm_design_energy = 12, @@ -485,7 +488,7 @@ static int bq274xx_channel_get(const struct device *dev, enum sensor_channel cha struct sensor_value *val) { struct bq274xx_data *data = dev->data; - float int_temp; + int32_t int_temp; switch (chan) { case SENSOR_CHAN_GAUGE_VOLTAGE: @@ -509,10 +512,12 @@ static int bq274xx_channel_get(const struct device *dev, enum sensor_channel cha break; case SENSOR_CHAN_GAUGE_TEMP: - int_temp = (data->internal_temperature * 0.1f); - int_temp = int_temp - 273.15f; - val->val1 = (int32_t)int_temp; - val->val2 = (int_temp - (int32_t)int_temp) * 1000000; + /* Convert units from 0.1K to 0.01K */ + int_temp = data->internal_temperature * 10; + /* Convert to 0.01C */ + int_temp -= (int32_t)(100.0 * KELVIN_OFFSET); + val->val1 = int_temp / 100; + val->val2 = (int_temp % 100) * 10000; break; case SENSOR_CHAN_GAUGE_STATE_OF_CHARGE: From 7f41696a93fe4c0527d765efe7811b0821b6f60d Mon Sep 17 00:00:00 2001 From: Nick Ward Date: Fri, 29 Dec 2023 22:15:58 +1100 Subject: [PATCH 2159/3723] dts: binding: sensor: bq274xx: improve desc. Improve descriptions of taper-current and terminate-voltage. Also fixes units of taper-current. Signed-off-by: Nick Ward --- dts/bindings/sensor/ti,bq274xx.yaml | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/dts/bindings/sensor/ti,bq274xx.yaml b/dts/bindings/sensor/ti,bq274xx.yaml index f50aba228c1..e92f0d09208 100644 --- a/dts/bindings/sensor/ti,bq274xx.yaml +++ b/dts/bindings/sensor/ti,bq274xx.yaml @@ -24,12 +24,16 @@ properties: taper-current: type: int required: true - description: Battery Taper current in mAh + description: | + Current in mA slightly higher than the taper current threshold at which + point the charger cuts off charging. terminate-voltage: type: int required: true - description: Battery Terminate Voltage in mV + description: | + Minimum operating voltage of your system. This is the target where the + gauge typically reports 0% capacity. In mV. chemistry-id: type: int From 6d53c2aed295a243152ec0c7c640e76e09bdf66b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Manuel=20Arg=C3=BCelles?= Date: Thu, 11 Jan 2024 10:10:56 +0700 Subject: [PATCH 2160/3723] soc: arm: nxp_s32: s32k3: select CONFIG_CACHE_MANAGEMENT MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Commit 447a492 switched to `sys_cache*` to enable caches at SoC init. To preserve the old behavior of enabling caches at init, is missing to select `CONFIG_CACHE_MANAGEMENT`. Signed-off-by: Manuel Argüelles --- soc/arm/nxp_s32/s32k3/Kconfig.defconfig.series | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/soc/arm/nxp_s32/s32k3/Kconfig.defconfig.series b/soc/arm/nxp_s32/s32k3/Kconfig.defconfig.series index 04d54fdc666..2307571611a 100644 --- a/soc/arm/nxp_s32/s32k3/Kconfig.defconfig.series +++ b/soc/arm/nxp_s32/s32k3/Kconfig.defconfig.series @@ -1,6 +1,6 @@ # NXP S32K3XX MCU series -# Copyright 2023 NXP +# Copyright 2023-2024 NXP # SPDX-License-Identifier: Apache-2.0 if SOC_SERIES_S32K3XX @@ -32,6 +32,9 @@ config NET_UDP_CHECKSUM endif # NET_L2_ETHERNET +config CACHE_MANAGEMENT + default y + source "soc/arm/nxp_s32/s32k3/Kconfig.defconfig.s32k*" endif # SOC_SERIES_S32K3XX From e46265669fa6d18383ba81c8cdb59d3bd65ae384 Mon Sep 17 00:00:00 2001 From: Stephan Linz Date: Mon, 1 Jan 2024 13:28:55 +0100 Subject: [PATCH 2161/3723] samples: drivers: display: fix mono buffer size Rounding errors due to the division of non-integrally divisible buffer sizes lead to the loss of one byte. This can be avoided with the DIV_ROUND_UP() macro. Signed-off-by: Stephan Linz --- samples/drivers/display/src/main.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/samples/drivers/display/src/main.c b/samples/drivers/display/src/main.c index 5e74e7a018d..e05be9ace68 100644 --- a/samples/drivers/display/src/main.c +++ b/samples/drivers/display/src/main.c @@ -234,7 +234,8 @@ int main(void) case PIXEL_FORMAT_MONO01: case PIXEL_FORMAT_MONO10: fill_buffer_fnc = fill_buffer_mono; - buf_size /= 8; + buf_size = DIV_ROUND_UP(DIV_ROUND_UP( + buf_size, NUM_BITS(uint8_t)), sizeof(uint8_t)); break; default: LOG_ERR("Unsupported pixel format. Aborting sample."); From 2fdea6b2b97a4dead9d4b9f13d2a495f2a685fea Mon Sep 17 00:00:00 2001 From: Stephan Linz Date: Mon, 1 Jan 2024 14:01:07 +0100 Subject: [PATCH 2162/3723] samples: drivers: display: distinguish mono pixel format In exceptional cases, monochrome displays can deviate from the general interpretation (PIXEL_FORMAT_MONO01) of a logical 1 as pixel on (white) and 0 as pixel off (black) and instead set the capability to PIXEL_FORMAT_MONO10. This small but significant difference has been ignored so far, resulting in an inverse display for those displays. In order to be technically correct here, the buffers for a "white" background should be set to 0 instead of 1 and for "black" to 1 instead of 0. Signed-off-by: Stephan Linz --- samples/drivers/display/src/main.c | 36 +++++++++++++++++++++++++----- 1 file changed, 30 insertions(+), 6 deletions(-) diff --git a/samples/drivers/display/src/main.c b/samples/drivers/display/src/main.c index e05be9ace68..642558e2af9 100644 --- a/samples/drivers/display/src/main.c +++ b/samples/drivers/display/src/main.c @@ -140,23 +140,36 @@ static void fill_buffer_bgr565(enum corner corner, uint8_t grey, uint8_t *buf, } } -static void fill_buffer_mono(enum corner corner, uint8_t grey, uint8_t *buf, - size_t buf_size) +static void fill_buffer_mono(enum corner corner, uint8_t grey, + uint8_t black, uint8_t white, + uint8_t *buf, size_t buf_size) { uint16_t color; switch (corner) { case BOTTOM_LEFT: - color = (grey & 0x01u) ? 0xFFu : 0x00u; + color = (grey & 0x01u) ? white : black; break; default: - color = 0; + color = black; break; } memset(buf, color, buf_size); } +static inline void fill_buffer_mono01(enum corner corner, uint8_t grey, + uint8_t *buf, size_t buf_size) +{ + fill_buffer_mono(corner, grey, 0x00u, 0xFFu, buf, buf_size); +} + +static inline void fill_buffer_mono10(enum corner corner, uint8_t grey, + uint8_t *buf, size_t buf_size) +{ + fill_buffer_mono(corner, grey, 0xFFu, 0x00u, buf, buf_size); +} + int main(void) { size_t x; @@ -166,6 +179,7 @@ int main(void) size_t h_step; size_t scale; size_t grey_count; + uint8_t bg_color; uint8_t *buf; int32_t grey_scale_sleep; const struct device *display_dev; @@ -216,24 +230,34 @@ int main(void) switch (capabilities.current_pixel_format) { case PIXEL_FORMAT_ARGB_8888: + bg_color = 0xFFu; fill_buffer_fnc = fill_buffer_argb8888; buf_size *= 4; break; case PIXEL_FORMAT_RGB_888: + bg_color = 0xFFu; fill_buffer_fnc = fill_buffer_rgb888; buf_size *= 3; break; case PIXEL_FORMAT_RGB_565: + bg_color = 0xFFu; fill_buffer_fnc = fill_buffer_rgb565; buf_size *= 2; break; case PIXEL_FORMAT_BGR_565: + bg_color = 0xFFu; fill_buffer_fnc = fill_buffer_bgr565; buf_size *= 2; break; case PIXEL_FORMAT_MONO01: + bg_color = 0xFFu; + fill_buffer_fnc = fill_buffer_mono01; + buf_size = DIV_ROUND_UP(DIV_ROUND_UP( + buf_size, NUM_BITS(uint8_t)), sizeof(uint8_t)); + break; case PIXEL_FORMAT_MONO10: - fill_buffer_fnc = fill_buffer_mono; + bg_color = 0x00u; + fill_buffer_fnc = fill_buffer_mono10; buf_size = DIV_ROUND_UP(DIV_ROUND_UP( buf_size, NUM_BITS(uint8_t)), sizeof(uint8_t)); break; @@ -257,7 +281,7 @@ int main(void) #endif } - (void)memset(buf, 0xFFu, buf_size); + (void)memset(buf, bg_color, buf_size); buf_desc.buf_size = buf_size; buf_desc.pitch = capabilities.x_resolution; From 162a8f00c13ac0dfc8d9df0bccb269a0b67fc317 Mon Sep 17 00:00:00 2001 From: Stephan Linz Date: Mon, 1 Jan 2024 14:43:05 +0100 Subject: [PATCH 2163/3723] samples: drivers: display: support small displays With extremely small displays (much smaller than 64x24), the calculation of the blocks in the four corners fails. These might then be too large and no longer fit into the available area of the small displays. Signed-off-by: Stephan Linz --- samples/drivers/display/src/main.c | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) diff --git a/samples/drivers/display/src/main.c b/samples/drivers/display/src/main.c index 642558e2af9..a9267b51c74 100644 --- a/samples/drivers/display/src/main.c +++ b/samples/drivers/display/src/main.c @@ -210,8 +210,17 @@ int main(void) rect_h = 1; } - h_step = rect_h; - scale = (capabilities.x_resolution / 8) / rect_h; + if ((capabilities.x_resolution < 3 * rect_w) || + (capabilities.y_resolution < 3 * rect_h) || + (capabilities.x_resolution < 8 * rect_h)) { + rect_w = capabilities.x_resolution * 40 / 100; + rect_h = capabilities.y_resolution * 40 / 100; + h_step = capabilities.y_resolution * 20 / 100; + scale = 1; + } else { + h_step = rect_h; + scale = (capabilities.x_resolution / 8) / rect_h; + } rect_w *= scale; rect_h *= scale; From 3e1a82226d995b21233a6e9002bb5dbf50286fe0 Mon Sep 17 00:00:00 2001 From: Jonathan Rico Date: Thu, 4 Jan 2024 18:10:56 +0100 Subject: [PATCH 2164/3723] tests: Bluetooth: use unique IDs for l2cap bsim tests If $BASH_SOURCE is the empty string, then those two tests end up with the same simulation ID. That's not a good time. Signed-off-by: Jonathan Rico --- .../host/l2cap/credits/tests_scripts/l2cap_credits.sh | 4 ++-- .../credits_seg_recv/tests_scripts/l2cap_credits_seg_recv.sh | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/tests/bsim/bluetooth/host/l2cap/credits/tests_scripts/l2cap_credits.sh b/tests/bsim/bluetooth/host/l2cap/credits/tests_scripts/l2cap_credits.sh index b357f016964..fb2588cfd87 100755 --- a/tests/bsim/bluetooth/host/l2cap/credits/tests_scripts/l2cap_credits.sh +++ b/tests/bsim/bluetooth/host/l2cap/credits/tests_scripts/l2cap_credits.sh @@ -9,7 +9,7 @@ EXECUTE_TIMEOUT=20 cd ${BSIM_OUT_PATH}/bin -simulation_id=$(basename $BASH_SOURCE) +simulation_id=bluetooth_host_l2cap_credits_prj_conf bsim_exe=./bs_nrf52_bsim_tests_bsim_bluetooth_host_l2cap_credits_prj_conf Execute "${bsim_exe}" -v=${verbosity_level} -s=${simulation_id} -d=0 -testid=central -rs=420 @@ -19,7 +19,7 @@ Execute ./bs_2G4_phy_v1 -v=${verbosity_level} -s=${simulation_id} -D=2 -sim_leng wait_for_background_jobs -simulation_id=$(basename $BASH_SOURCE)_ecred +simulation_id=bluetooth_host_l2cap_credits_prj_ecred_conf bsim_exe=./bs_nrf52_bsim_tests_bsim_bluetooth_host_l2cap_credits_prj_ecred_conf Execute "${bsim_exe}" -v=${verbosity_level} -s=${simulation_id} -d=0 -testid=central -rs=420 diff --git a/tests/bsim/bluetooth/host/l2cap/credits_seg_recv/tests_scripts/l2cap_credits_seg_recv.sh b/tests/bsim/bluetooth/host/l2cap/credits_seg_recv/tests_scripts/l2cap_credits_seg_recv.sh index 664c57e9a18..4dfa15cbdb2 100755 --- a/tests/bsim/bluetooth/host/l2cap/credits_seg_recv/tests_scripts/l2cap_credits_seg_recv.sh +++ b/tests/bsim/bluetooth/host/l2cap/credits_seg_recv/tests_scripts/l2cap_credits_seg_recv.sh @@ -19,7 +19,7 @@ Execute ./bs_2G4_phy_v1 -v=${verbosity_level} -s=${simulation_id} -D=2 -sim_leng wait_for_background_jobs -simulation_id=$(basename $BASH_SOURCE)_ecred +simulation_id=bluetooth_host_l2cap_credits_seg_recv_prj_ecred_conf bsim_exe=./bs_nrf52_bsim_tests_bsim_bluetooth_host_l2cap_credits_seg_recv_prj_ecred_conf Execute "${bsim_exe}" -v=${verbosity_level} -s=${simulation_id} -d=0 -testid=central -rs=420 From 13671813feab6668c928d252860a5815ecb43fa5 Mon Sep 17 00:00:00 2001 From: Charles Dias Date: Sat, 16 Dec 2023 07:58:53 -0300 Subject: [PATCH 2165/3723] boards: arm: Add support for FK7B0M1-VBT6 board Adds the device trees, Kconfig, and documentation files. The following features have been confirmed working on hardware: * LED * Button * UART Signed-off-by: Charles Dias --- boards/arm/fk7b0m1_vbt6/Kconfig.board | 8 + boards/arm/fk7b0m1_vbt6/Kconfig.defconfig | 11 ++ boards/arm/fk7b0m1_vbt6/board.cmake | 9 + .../fk7b0m1_vbt6/doc/img/fk7b0m1_vbt6.webp | Bin 0 -> 88846 bytes .../doc/img/fk7b0m1_vbt6_pins.webp | Bin 0 -> 88370 bytes boards/arm/fk7b0m1_vbt6/doc/index.rst | 179 ++++++++++++++++++ boards/arm/fk7b0m1_vbt6/fk7b0m1_vbt6.dts | 97 ++++++++++ boards/arm/fk7b0m1_vbt6/fk7b0m1_vbt6.yaml | 14 ++ .../arm/fk7b0m1_vbt6/fk7b0m1_vbt6_defconfig | 27 +++ boards/arm/fk7b0m1_vbt6/support/openocd.cfg | 25 +++ 10 files changed, 370 insertions(+) create mode 100644 boards/arm/fk7b0m1_vbt6/Kconfig.board create mode 100644 boards/arm/fk7b0m1_vbt6/Kconfig.defconfig create mode 100644 boards/arm/fk7b0m1_vbt6/board.cmake create mode 100644 boards/arm/fk7b0m1_vbt6/doc/img/fk7b0m1_vbt6.webp create mode 100644 boards/arm/fk7b0m1_vbt6/doc/img/fk7b0m1_vbt6_pins.webp create mode 100644 boards/arm/fk7b0m1_vbt6/doc/index.rst create mode 100644 boards/arm/fk7b0m1_vbt6/fk7b0m1_vbt6.dts create mode 100644 boards/arm/fk7b0m1_vbt6/fk7b0m1_vbt6.yaml create mode 100644 boards/arm/fk7b0m1_vbt6/fk7b0m1_vbt6_defconfig create mode 100644 boards/arm/fk7b0m1_vbt6/support/openocd.cfg diff --git a/boards/arm/fk7b0m1_vbt6/Kconfig.board b/boards/arm/fk7b0m1_vbt6/Kconfig.board new file mode 100644 index 00000000000..0b46551e95e --- /dev/null +++ b/boards/arm/fk7b0m1_vbt6/Kconfig.board @@ -0,0 +1,8 @@ +# STM32H7B0VBT FK7B0M1_VBT6 board + +# Copyright (c) 2023 Charles Dias +# SPDX-License-Identifier: Apache-2.0 + +config BOARD_FK7B0M1_VBT6 + bool "FANKE FK7B0M1-VBT6 board" + depends on SOC_STM32H7B0XX diff --git a/boards/arm/fk7b0m1_vbt6/Kconfig.defconfig b/boards/arm/fk7b0m1_vbt6/Kconfig.defconfig new file mode 100644 index 00000000000..39de99eb5f8 --- /dev/null +++ b/boards/arm/fk7b0m1_vbt6/Kconfig.defconfig @@ -0,0 +1,11 @@ +# STM32H7B0VBT board configuration + +# Copyright (c) Charles Dias +# SPDX-License-Identifier: Apache-2.0 + +if BOARD_FK7B0M1_VBT6 + +config BOARD + default "fk7b0m1_vbt6" + +endif # BOARD_FK7B0M1_VBT6 diff --git a/boards/arm/fk7b0m1_vbt6/board.cmake b/boards/arm/fk7b0m1_vbt6/board.cmake new file mode 100644 index 00000000000..f709513c711 --- /dev/null +++ b/boards/arm/fk7b0m1_vbt6/board.cmake @@ -0,0 +1,9 @@ +# SPDX-License-Identifier: Apache-2.0 + +board_runner_args(openocd --target-handle=_CHIPNAME.cpu0) +board_runner_args(stm32cubeprogrammer "--port=swd" "--reset-mode=hw") +board_runner_args(jlink "--device=STM32H7B0VB" "--speed=4000") + +include(${ZEPHYR_BASE}/boards/common/openocd.board.cmake) +include(${ZEPHYR_BASE}/boards/common/stm32cubeprogrammer.board.cmake) +include(${ZEPHYR_BASE}/boards/common/jlink.board.cmake) diff --git a/boards/arm/fk7b0m1_vbt6/doc/img/fk7b0m1_vbt6.webp b/boards/arm/fk7b0m1_vbt6/doc/img/fk7b0m1_vbt6.webp new file mode 100644 index 0000000000000000000000000000000000000000..68faf96b85951cc2b11fdb58a66cc5cb96e43463 GIT binary patch literal 88846 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 NHKu{W%f4gD008yqFbV(w literal 0 HcmV?d00001 diff --git a/boards/arm/fk7b0m1_vbt6/doc/img/fk7b0m1_vbt6_pins.webp b/boards/arm/fk7b0m1_vbt6/doc/img/fk7b0m1_vbt6_pins.webp new file mode 100644 index 0000000000000000000000000000000000000000..5a67a58fcbd3a611aadc830839eefdc657dde4e4 GIT binary patch literal 88370 zcmV)NK)1hANk&F0Spfi7MM6+kP&iB;SpfhqU_nL@O-O7TNs=T;)!4?K%72Hy-t!=$ z{}V7LALnI31rZaPQZ+lyt|?myUj}0Tk#ZT8iqo3wX5P8j*p%6zqNCi9T7yxVSWCL= zs?r>>%V`A#F3tdY;xXsu0`ozVF)~x-qNF2F>V2iZ6Q|Co6bGteO|PW2i2S zpQhE@@Ol{OY^)Wmv!v1uQlr%Fd|Fa|9<|xRME9ijT*ltHVBWO zY;!cTpq0J~)C@RaAGsNdS}`7x9e-3ZECj`zQbom*=WGv93xjfKK}8npz;iO(XR6%5 z@6rKGO%nrUUKDp_%n2|#cEe{EbX9G0q&bIL@4a`!M)I0SY^YG7LS2Hc)&HTqN`4rc z=A&tfqA4mF)m{U2W!v7!&4m~iVTR?!z57jfw~rv?IP)vy2>d&}_be{M;_eS2gcyYQ z7=~d|p=E8`vsStIfnCnFWdIJr`Hv!pb{~7!AA;de0?*t32>?%$M8b-(;4}>kCGRqp zK#Y$fMvS~=$&#g;z)-3I$sqs&1WAB!Vq|NC_F$C0Qv(QM^-*M4&m_YcN~tB>9$o`T z5Cj1NAOO;`$7RII*!QD9qQ-RqhztWjsamTS)a9!RQrb&EfEF%t{cz-lDs! zO*LuwPLivPjQeqam4S(%uiDGI4Q6HYPC)(Q&33%+Rp~wcVcA})29gN`J6a?Ej;Evc z%NhWZ>u@HKkv9-y9Tm78+c7rS>&@r^uwX?CP5>efnsu~y?#8w<1dv=`&#Yk$$pWHQ ztpeN(BtQ$UlLSc+1W2{<(s^|Mv(l&XJwJOFNA=X&CL&a4t(U2A~hxlT+ZXa_(A;wA`MT6ORioceF0^izNL2VW|H zm_)1oaj2j_B$;bn;O=kF)voNt1{8X#zO{CHb_iBoiJjVbym}mQZX;y~4@Enh*{GIk zDW=eXaZEJ8Q$4@bVPbiVFgt`h&@9p79xw-j`V_{BZuBK;NdG_mvdTv9wBrf8)Jqu0 z*w(|%?q%zCMs;U7+%1F=?38&IcnNTls=z-ZPEh(o2~o0EjYeRE?K}NIw^|PaymYOP zm-ukv`u^{;mQK{497UJf{93kIn=cm7Kw&pMj`riJ9gWgA<#JoT*vB7Lt5$@D{NmOn zi@px3yMb#xy|h^3;q-=%0Hl$>0o)eL66*g<=MgkaRUXLehiO(*O(m7jgk(8jsv|nM zeenE)*W+4QOKSp79TL1;%H#ctlQ1^xg<3*Lh^eNMqJ(5&GgXY2usgdQyjw%rO9zCS zvjIR5tU##M^X_r<^qaLCn?CkCit!7z)@2e3WP!0teN(V)rZ*M`G&U+5tr-9aP^nI% zj&{^Wg=!dc)skG2Ko%Ir$pRJ{AnES`+C>&W)3P@9E3T)oKEP*ZmgDLyZuWGB{5+Me#ftj%#!5Z001hVT)d17XC0e{hrNxB z&91gJ*IWSmaxoPeKsm9~)6lbhQ_gCS7j$YIO1CeTLJY@cse!Q$V^e^YsI{(IwE)?n z)_Q>3!*z|l=g@F4WqVry)<#(`%W%N#c<`>d^EA?*pcaG>wbnJ)TmVo@8Qku+*jNtt zy(kpN#j-dSW(U-Nmk0%j-&=Fv7$s|eIBE%DC8nxXYhM6w_N=S6J%GB|iUYK?7&9D< zlRbDB(~;pWR5o|KWjp3&0aiXGe6ZRX>SYZzRjHSyR&f2{wK~8EV3>dZ1ytay!bL|> zuA`SnC�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 F+z|}^RO|o% literal 0 HcmV?d00001 diff --git a/boards/arm/fk7b0m1_vbt6/doc/index.rst b/boards/arm/fk7b0m1_vbt6/doc/index.rst new file mode 100644 index 00000000000..2af182bc041 --- /dev/null +++ b/boards/arm/fk7b0m1_vbt6/doc/index.rst @@ -0,0 +1,179 @@ +.. _fk7b0m1_vbt6: + +FANKE FK7B0M1-VBT6 +################## + +Overview +******** + +The FK7B0M1-VBT6 core board by FANKE Technology Co., Ltd. is an advanced microcontroller +platform based on the STMicroelectronics Arm® Cortex®-M7 core STM32H7B0VBT6 microcontroller. +This board is an ideal solution for developers looking to create high-performance +applications, especially in the field of Human-Machine Interface (HMI), leveraging its +robust capabilities and support for sophisticated display and touch technologies. + +The FK7B0M1-VBT6 is designed as a reference design for user application development before +transitioning to the final product, significantly simplifying the development process. +Its wide range of hardware features, including advanced display and touch capabilities, +make it exceptionally suitable for HMI applications, allowing for comprehensive evaluation +and testing of peripherals and functionalities. + +.. figure:: img/fk7b0m1_vbt6.webp + :width: 600px + :align: center + :alt: FK7B0M1-VBT6 + + FK7B0M1-VBT6 (Credit: FANKE Technology Co., Ltd) + +Hardware +******** + +FK7B0M1-VBT6 provides the following hardware components: + +- STM32H7B6VB in LQFP100 package +- ARM 32-bit Cortex-M7 CPU with FPU +- 280 MHz max CPU frequency +- VDD from 1.62 V to 3.6 V +- 128 KB Flash +- ~1.4 MB SRAM max (1.18 Mbytes user SRAM + 64 Kbytes ITCM RAM + 128 Kbytes DTCM RAM + 4 Kbytes SRAM in Backup domain) +- Main clock: External 25MHz crystal oscillator. +- RTC: 32.768kHz crystal oscillator. +- 32-bit timers(2) +- 16-bit timers(12) +- 1 reset button, 1 user button, and 1 BOOT button +- 1 user LED +- External 64-Mbit QSPI (W25Q64) NOR Flash memory. +- External 64-Mbit SPI (W25Q64) NOR Flash memory. +- USB OTG Full Speed and High Speed(1) +- 1 micro SD card +- 1 RGB LCD interface +- SWD and serial port accessibility through a pin header +- Bring out 39 IO ports + +More information about STM32H7B0VB can be found here: + +- `STM32H7B0VB on www.st.com`_ + +Supported Features +================== + +The Zephyr nucleo_h723zg board configuration supports the following hardware +features: + ++-------------+------------+-------------------------------------+ +| Interface | Controller | Driver/Component | ++=============+============+=====================================+ +| NVIC | on-chip | nested vector interrupt controller | ++-------------+------------+-------------------------------------+ +| UART | on-chip | serial port | ++-------------+------------+-------------------------------------+ +| PINMUX | on-chip | pinmux | ++-------------+------------+-------------------------------------+ +| GPIO | on-chip | gpio | ++-------------+------------+-------------------------------------+ +| RNG | on-chip | True Random number generator | ++-------------+------------+-------------------------------------+ +| Backup SRAM | on-chip | Backup SRAM | ++-------------+------------+-------------------------------------+ + +Other hardware features are not yet supported on this Zephyr port. + +The default configuration per core can be found in the defconfig files: +``boards/arm/fk7b0m1-vbt6/fk7b0m1_vbt6_defconfig`` + +Connections and IOs +=================== + +Available pins: +--------------- + +Nucleo FK7B0M1-VBT6 board has 6 GPIO controllers. These controllers are responsible for pin muxing, +input/output, pull-up, etc. + +.. figure:: img/fk7b0m1_vbt6_pins.webp + :width: 600px + :align: center + :alt: FK7B0M1-VBT6 + + FK7B0M1-VBT6 (Credit: FANKE Technology Co., Ltd) + +LED +--- + +- User LED (blue) = PC1 + +Push buttons +------------------------- + +- BOOT = SW1 = BOOT0 +- RESET = SW2 = NRST +- User button = SW3 = PC13 + +UART +----- + +- TX device = USART1 PA9 +- RX device = USART1 PA10 + +USB +--- + +- USB D- = PA11 +- USB D+ = PA12 + +System Clock +============ + +The FK7B0M1-VBT6 System Clock could be driven by an internal or external oscillator, +as well as by the main PLL clock. By default the system clock is driven by the PLL clock at 280MHz, +driven by an 25MHz external crystal oscillator. + +Serial Port +=========== + +The Zephyr console output is assigned to UART1. The default communication settings are 115200 8N1. + +Programming and Debugging +************************* + +The FK7B0M1-VBT6 board does not include an on-board debugger. As a result, it requires +an external debugger, such as ST-Link, for programming and debugging purposes. + +The board provides header pins for the Serial Wire Debug (SWD) interface. + +Flashing +======== + +To begin, connect the ST-Link Debug Programmer to the FK7B0M1-VBT6 board using the SWD +interface. Next, connect the ST-Link to your host computer via a USB port. +Once this setup is complete, you can proceed to build and flash your application to the board + +Here is an example for the :ref:`hello_world` application. + +.. zephyr-app-commands:: + :zephyr-app: samples/hello_world + :board: fk7b0m1_vbt6 + :goals: build flash + +Run a serial host program to connect with your board: + +.. code-block:: console + + $ minicom -D /dev/ttyACM0 -b 115200 + +Then, press the RESET button, you should see the following message: + +.. code-block:: console + + Hello World! fk7b0m1_vbt6 + +Debugging +========= + +This current Zephyr port does not support debugging. + +References +********** + +.. target-notes:: +.. _STM32H7B0VB on www.st.com: https://www.st.com/en/microcontrollers/stm32h7b0vb.html diff --git a/boards/arm/fk7b0m1_vbt6/fk7b0m1_vbt6.dts b/boards/arm/fk7b0m1_vbt6/fk7b0m1_vbt6.dts new file mode 100644 index 00000000000..536c7b6e780 --- /dev/null +++ b/boards/arm/fk7b0m1_vbt6/fk7b0m1_vbt6.dts @@ -0,0 +1,97 @@ +/* + * Copyright (c) 2023 Charles Dias + * + * SPDX-License-Identifier: Apache-2.0 + */ + +/dts-v1/; +#include +#include +#include +#include + +/ { + model = "FANKE FK7B0M1-VBT6 board"; + compatible = "fanke,fk7b0m1-vbt6"; + + chosen { + zephyr,console = &usart1; + zephyr,shell-uart = &usart1; + zephyr,sram = &sram0; + zephyr,flash = &flash0; + }; + + leds { + compatible = "gpio-leds"; + user_led: led_0 { + gpios = <&gpioc 1 GPIO_ACTIVE_HIGH>; + label = "User LED"; + }; + }; + + gpio_keys { + compatible = "gpio-keys"; + user_button: button_0 { + label = "User PB"; + gpios = <&gpioc 13 (GPIO_PULL_UP | GPIO_ACTIVE_HIGH)>; + zephyr,code = ; + }; + }; + + aliases { + led0 = &user_led; + sw0 = &user_button; + }; +}; + +&clk_hsi48 { + status = "okay"; +}; + +&clk_hse { + clock-frequency = ; + status = "okay"; +}; + +/* PLL1P is used for system clock (280 MHz) */ +&pll { + div-m = <5>; + mul-n = <112>; + div-p = <2>; + div-q = <2>; + div-r = <2>; + clocks = <&clk_hse>; + status = "okay"; +}; + +&rcc { + clocks = <&pll>; + clock-frequency = ; + d1cpre = <1>; + hpre = <1>; + d1ppre = <2>; + d2ppre1 = <2>; + d2ppre2 = <2>; + d3ppre = <2>; +}; + +&usart1 { + pinctrl-0 = <&usart1_tx_pa9 &usart1_rx_pa10>; + pinctrl-names = "default"; + current-speed = <115200>; + status = "okay"; +}; + +&backup_sram { + status = "okay"; +}; + +zephyr_udc0: &usbotg_hs { + pinctrl-0 = <&usb_otg_hs_dm_pa11 &usb_otg_hs_dp_pa12>; + pinctrl-names = "default"; + status = "okay"; +}; + +&rng { + status = "okay"; +}; diff --git a/boards/arm/fk7b0m1_vbt6/fk7b0m1_vbt6.yaml b/boards/arm/fk7b0m1_vbt6/fk7b0m1_vbt6.yaml new file mode 100644 index 00000000000..f847d49f450 --- /dev/null +++ b/boards/arm/fk7b0m1_vbt6/fk7b0m1_vbt6.yaml @@ -0,0 +1,14 @@ +identifier: fk7b0m1_vbt6 +name: FANKE FK7B0M1-VBT6 board +type: mcu +arch: arm +toolchain: + - zephyr + - gnuarmemb + - xtools +ram: 1376 +flash: 128 +supported: + - uart + - gpio +vendor: fanke diff --git a/boards/arm/fk7b0m1_vbt6/fk7b0m1_vbt6_defconfig b/boards/arm/fk7b0m1_vbt6/fk7b0m1_vbt6_defconfig new file mode 100644 index 00000000000..72587a3a897 --- /dev/null +++ b/boards/arm/fk7b0m1_vbt6/fk7b0m1_vbt6_defconfig @@ -0,0 +1,27 @@ +# Copyright (c) Charles Dias +# SPDX-License-Identifier: Apache-2.0 + +CONFIG_SOC_SERIES_STM32H7X=y +CONFIG_SOC_STM32H7B0XX=y + +# Enable MPU +CONFIG_ARM_MPU=y + +# Enable HW stack protection +CONFIG_HW_STACK_PROTECTION=y + +# Enable UART +CONFIG_SERIAL=y + +# Console +CONFIG_CONSOLE=y +CONFIG_UART_CONSOLE=y + +# Enable Pinctrl +CONFIG_PINCTRL=y + +# Enable GPIO +CONFIG_GPIO=y + +# Enable clocks +CONFIG_CLOCK_CONTROL=y diff --git a/boards/arm/fk7b0m1_vbt6/support/openocd.cfg b/boards/arm/fk7b0m1_vbt6/support/openocd.cfg new file mode 100644 index 00000000000..ce4f15c9979 --- /dev/null +++ b/boards/arm/fk7b0m1_vbt6/support/openocd.cfg @@ -0,0 +1,25 @@ +# Copyright (c) Charles Dias +# SPDX-License-Identifier: Apache-2.0 + +source [find interface/stlink-dap.cfg] +transport select "dapdirect_swd" + +set WORKAREASIZE 0x8000 + +set CHIPNAME STM32H7B0VB +set BOARDNAME FK7B0M1-VBT6 + +source [find target/stm32h7x.cfg] + +# Enable debug when in low power modes +set ENABLE_LOW_POWER 1 + +# Stop Watchdog counters when halt +set STOP_WATCHDOG 1 + +# Reset configuration +# use hardware reset, connect under reset +# connect_assert_srst needed if low power mode application running (WFI...) +reset_config srst_only srst_nogate connect_assert_srst +set CONNECT_UNDER_RESET 1 +set CORE_RESET 0 From 8b968146769c9daf98117ef96a89ec687af880fb Mon Sep 17 00:00:00 2001 From: Charles Dias Date: Sat, 16 Dec 2023 08:01:36 -0300 Subject: [PATCH 2166/3723] dts: bindings: Add vendor prefix fanke Add vendor prefix fanke FANKE Technology Co., Ltd. Signed-off-by: Charles Dias --- 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 231fa50da0f..d75fd09e0bf 100644 --- a/dts/bindings/vendor-prefixes.txt +++ b/dts/bindings/vendor-prefixes.txt @@ -208,6 +208,7 @@ excito Excito ezchip EZchip Semiconductor facebook Facebook (deprecated, use meta) fairphone Fairphone B.V. +fanke FANKE Technology Co., Ltd. faraday Faraday Technology Corporation fastrax Fastrax Oy fcs Fairchild Semiconductor From c860542cf1991df8aaaf0931e92bdadc21f1d06e Mon Sep 17 00:00:00 2001 From: Toon Stegen Date: Mon, 16 Oct 2023 12:31:50 +0300 Subject: [PATCH 2167/3723] boards: suppress dtc warning for SPI bridge on ST Get rid of warnings Signed-off-by: Toon Stegen --- boards/arm/b_u585i_iot02a/pre_dt_board.cmake | 3 +++ 1 file changed, 3 insertions(+) create mode 100644 boards/arm/b_u585i_iot02a/pre_dt_board.cmake diff --git a/boards/arm/b_u585i_iot02a/pre_dt_board.cmake b/boards/arm/b_u585i_iot02a/pre_dt_board.cmake new file mode 100644 index 00000000000..812d18cdf6c --- /dev/null +++ b/boards/arm/b_u585i_iot02a/pre_dt_board.cmake @@ -0,0 +1,3 @@ + +# SPI is implemented via octospi so node name isn't spi@... +list(APPEND EXTRA_DTC_FLAGS "-Wno-spi_bus_bridge") From 36b7a3e701fb36135f97b60d893640a99cd0b7d6 Mon Sep 17 00:00:00 2001 From: Damian Krolik Date: Thu, 11 Jan 2024 16:59:23 +0100 Subject: [PATCH 2168/3723] net: openthread: Remove PSA crypto backend workarounds Remove two workarounds in OpenThread's PSA crypto backend that were required when Zephyr used pre-1.5 TF-M version: 1. psa_open_key() is no longer needed to reference a persistent key 2. psa_cipher_encrypt() can be used to simplify AES encryption Signed-off-by: Damian Krolik --- modules/openthread/platform/crypto_psa.c | 68 +++--------------------- 1 file changed, 7 insertions(+), 61 deletions(-) diff --git a/modules/openthread/platform/crypto_psa.c b/modules/openthread/platform/crypto_psa.c index 0dcf3803fde..55018254154 100644 --- a/modules/openthread/platform/crypto_psa.c +++ b/modules/openthread/platform/crypto_psa.c @@ -111,31 +111,6 @@ static bool checkContext(otCryptoContext *aContext, size_t aMinSize) return aContext != NULL && aContext->mContext != NULL && aContext->mContextSize >= aMinSize; } -static void ensureKeyIsLoaded(otCryptoKeyRef aKeyRef) -{ - /* - * The workaround below will no longer be need after updating TF-M version used in Zephyr - * to 1.5.0 (see upstream commit 42e77b561fcfe19819ff1e63cb7c0b672ee8ba41). - * In the recent versions of TF-M the concept of key handles and psa_open_key()/ - * psa_close_key() APIs have been being deprecated, but the version currently used in Zephyr - * is in the middle of that transition. Consequently, psa_destroy_key() and lots of other - * functions will fail when a key ID that they take as a parameter is not loaded from the - * persistent storage. That may occur when a given persistent key is created via - * psa_generate_key() or psa_import_key(), and then the device reboots. - * - * Use psa_open_key() when the key has not been loaded yet to work around the issue. - */ - psa_key_attributes_t attributes = PSA_KEY_ATTRIBUTES_INIT; - psa_status_t status = psa_get_key_attributes(aKeyRef, &attributes); - psa_key_id_t key_handle; - - if (status == PSA_ERROR_INVALID_HANDLE) { - psa_open_key(aKeyRef, &key_handle); - } - - psa_reset_key_attributes(&attributes); -} - void otPlatCryptoInit(void) { psa_crypto_init(); @@ -195,15 +170,11 @@ otError otPlatCryptoExportKey(otCryptoKeyRef aKeyRef, return OT_ERROR_INVALID_ARGS; } - ensureKeyIsLoaded(aKeyRef); - return psaToOtError(psa_export_key(aKeyRef, aBuffer, aBufferLen, aKeyLen)); } otError otPlatCryptoDestroyKey(otCryptoKeyRef aKeyRef) { - ensureKeyIsLoaded(aKeyRef); - return psaToOtError(psa_destroy_key(aKeyRef)); } @@ -212,7 +183,6 @@ bool otPlatCryptoHasKey(otCryptoKeyRef aKeyRef) psa_key_attributes_t attributes = PSA_KEY_ATTRIBUTES_INIT; psa_status_t status; - ensureKeyIsLoaded(aKeyRef); status = psa_get_key_attributes(aKeyRef, &attributes); psa_reset_key_attributes(&attributes); @@ -255,7 +225,6 @@ otError otPlatCryptoHmacSha256Start(otCryptoContext *aContext, const otCryptoKey return OT_ERROR_INVALID_ARGS; } - ensureKeyIsLoaded(aKey->mKeyRef); operation = aContext->mContext; status = psa_mac_sign_setup(operation, aKey->mKeyRef, PSA_ALG_HMAC(PSA_ALG_SHA_256)); @@ -323,7 +292,6 @@ otError otPlatCryptoAesEncrypt(otCryptoContext *aContext, const uint8_t *aInput, { const size_t block_size = PSA_BLOCK_CIPHER_BLOCK_LENGTH(PSA_KEY_TYPE_AES); psa_status_t status = PSA_SUCCESS; - psa_cipher_operation_t operation = PSA_CIPHER_OPERATION_INIT; psa_key_id_t *key_ref; size_t cipher_length; @@ -331,37 +299,15 @@ otError otPlatCryptoAesEncrypt(otCryptoContext *aContext, const uint8_t *aInput, return OT_ERROR_INVALID_ARGS; } - /* - * The code below can be simplified after updating TF-M version used in Zephyr to 1.5.0 - * (see upstream commit: 045ec4abfc73152a0116684ba9127d0a97cc8d34), using - * psa_cipher_encrypt() function which will replace the setup-update-finish sequence below. - */ key_ref = aContext->mContext; - ensureKeyIsLoaded(*key_ref); - status = psa_cipher_encrypt_setup(&operation, *key_ref, PSA_ALG_ECB_NO_PADDING); - - if (status != PSA_SUCCESS) { - goto out; - } - - status = psa_cipher_update(&operation, - aInput, - block_size, - aOutput, - block_size, - &cipher_length); + status = psa_cipher_encrypt(*key_ref, + PSA_ALG_ECB_NO_PADDING, + aInput, + block_size, + aOutput, + block_size, + &cipher_length); - if (status != PSA_SUCCESS) { - goto out; - } - - status = psa_cipher_finish(&operation, - aOutput + cipher_length, - block_size - cipher_length, - &cipher_length); - -out: - psa_cipher_abort(&operation); return psaToOtError(status); } From 992c04c471edc0ea63a4f572cf72b2195ef6a99b Mon Sep 17 00:00:00 2001 From: Alberto Escolar Piedras Date: Thu, 11 Jan 2024 13:52:24 +0100 Subject: [PATCH 2169/3723] manifest: Update nrf hw models to latest * Update the HW models module to a08acc7d3a853f890df2bf82167c02ab2153ffe7 Including the following: * a08acc7 UART(E): Duty cycle warnings due to Rx while Rx Off * aa1f38d UART(E): FIFO backend Minor bugfix * 8b0819f UART(E): Add Loopback backend * bc648f2 UART(E): Update RTS pin level as soon as the conf is changed * b39e448 UART(E): Detect receiver opening mid frame Signed-off-by: Alberto Escolar Piedras --- west.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/west.yml b/west.yml index 290e7777917..87e766c9e66 100644 --- a/west.yml +++ b/west.yml @@ -295,7 +295,7 @@ manifest: groups: - tools - name: nrf_hw_models - revision: c744f2c762aad79e59bd7e99002f2fcab0a2f288 + revision: a08acc7d3a853f890df2bf82167c02ab2153ffe7 path: modules/bsim_hw_models/nrf_hw_models - name: open-amp revision: da78aea63159771956fe0c9263f2e6985b66e9d5 From 51f9af86e4a673db580cc6a033be20e26523db7a Mon Sep 17 00:00:00 2001 From: Alberto Escolar Piedras Date: Tue, 9 Jan 2024 13:38:18 +0100 Subject: [PATCH 2170/3723] tests/drivers uart_pm: Fix for too fast targets On the async configurations, the first part of the test (test_uart_pm_in_idle) can interfere with the second part of the test, if the device has a fast enough CPU. This is due to the first part of the test ending as soon as it queues the last byte for transmission. If the device is fast enough (and the simulated nrf52 is), the 2nd part of the test will start executing enabling the UART Rx, which can result in either the Rx being enabled mid frame, which can result in a frame error or even before the Tx HW started pushing the byte in the line (resulting in that byte being received). Neither of these cases are handled by the 2nd test, which sees a spurious error or received byte and fails. Let's just add a small delay at the end of the first test to allow the Tx of the last byte to be done. Signed-off-by: Alberto Escolar Piedras --- tests/drivers/uart/uart_pm/src/main.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/tests/drivers/uart/uart_pm/src/main.c b/tests/drivers/uart/uart_pm/src/main.c index 043e225254e..7f3782ee615 100644 --- a/tests/drivers/uart/uart_pm/src/main.c +++ b/tests/drivers/uart/uart_pm/src/main.c @@ -169,6 +169,9 @@ ZTEST(uart_pm, test_uart_pm_in_idle) action_run(dev, PM_DEVICE_ACTION_RESUME, 0); communication_verify(dev, true); + + /* Let's give enough time for the last byte to be transmitted out */ + k_busy_wait(500); } ZTEST(uart_pm, test_uart_pm_poll_tx) From 7ef23e15735690e3cf29048946817ba5c3f81e81 Mon Sep 17 00:00:00 2001 From: Alberto Escolar Piedras Date: Wed, 10 Jan 2024 13:58:50 +0100 Subject: [PATCH 2171/3723] tests uart/uart_pm: Fix kconfig warning The option CONFIG_NATIVE_UART_0_ON_STDINOUT is only usable for the native_sim/posix(_64) targets, but this test is only allowed for the nrf52840dk_nrf52840. Building with this option set causes a kconfig warning. Let's just remove it. Signed-off-by: Alberto Escolar Piedras --- tests/drivers/uart/uart_pm/prj.conf | 1 - 1 file changed, 1 deletion(-) diff --git a/tests/drivers/uart/uart_pm/prj.conf b/tests/drivers/uart/uart_pm/prj.conf index 81baa4cf552..949c1497802 100644 --- a/tests/drivers/uart/uart_pm/prj.conf +++ b/tests/drivers/uart/uart_pm/prj.conf @@ -1,5 +1,4 @@ CONFIG_ZTEST=y CONFIG_SERIAL=y -CONFIG_NATIVE_UART_0_ON_STDINOUT=y CONFIG_PM=y CONFIG_PM_DEVICE=y From f82f6cdeae6abc0cedd9ad604b923bf1103ea684 Mon Sep 17 00:00:00 2001 From: Alberto Escolar Piedras Date: Thu, 11 Jan 2024 10:58:39 +0100 Subject: [PATCH 2172/3723] tests uart/uart_async_api: Improve filter These tests were filtering by CONFIG_UART_CONSOLE, but that does not seem a strick requirement. It seems the requirement would just be CONFIG_SERIAL, but that is implicit if CONFIG_SERIAL_SUPPORT_ASYNC, which is required for all these tests, so let's just remove CONFIG_UART_CONSOLE. (The simulated nrf5x boards do not set CONFIG_UART_CONSOLE by default, as by default the console is routed to the process stdout instead) Signed-off-by: Alberto Escolar Piedras --- tests/drivers/uart/uart_async_api/testcase.yaml | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/tests/drivers/uart/uart_async_api/testcase.yaml b/tests/drivers/uart/uart_async_api/testcase.yaml index e9914d48d99..b2b1f80f316 100644 --- a/tests/drivers/uart/uart_async_api/testcase.yaml +++ b/tests/drivers/uart/uart_async_api/testcase.yaml @@ -8,13 +8,13 @@ common: - uart tests: drivers.uart.async_api: - filter: CONFIG_UART_CONSOLE and CONFIG_SERIAL_SUPPORT_ASYNC and not CONFIG_UART_MCUX_LPUART + filter: CONFIG_SERIAL_SUPPORT_ASYNC and not CONFIG_UART_MCUX_LPUART harness: ztest harness_config: fixture: gpio_loopback depends_on: gpio drivers.uart.wide: - filter: CONFIG_UART_CONSOLE and CONFIG_SERIAL_SUPPORT_ASYNC and not CONFIG_UART_MCUX_LPUART + filter: CONFIG_SERIAL_SUPPORT_ASYNC and not CONFIG_UART_MCUX_LPUART harness: ztest harness_config: fixture: gpio_loopback @@ -26,7 +26,7 @@ tests: integration_platforms: - nucleo_h743zi drivers.uart.async_api.nrf_uart: - filter: CONFIG_UART_CONSOLE and CONFIG_SERIAL_SUPPORT_ASYNC + filter: CONFIG_SERIAL_SUPPORT_ASYNC harness: ztest platform_allow: nrf52840dk_nrf52840 harness_config: @@ -36,7 +36,7 @@ tests: integration_platforms: - nrf52840dk_nrf52840 drivers.uart.async_api.rtt: - filter: CONFIG_UART_CONSOLE and CONFIG_SERIAL_SUPPORT_ASYNC and CONFIG_HAS_SEGGER_RTT + filter: CONFIG_SERIAL_SUPPORT_ASYNC and CONFIG_HAS_SEGGER_RTT and not CONFIG_UART_MCUX_LPUART and not CONFIG_UART_MCUX_FLEXCOMM extra_args: DTC_OVERLAY_FILE=boards/segger_rtt.overlay extra_configs: @@ -49,11 +49,11 @@ tests: integration_platforms: - qemu_cortex_m0 drivers.uart.async_api.lpuart: - filter: CONFIG_UART_CONSOLE and CONFIG_SERIAL_SUPPORT_ASYNC and CONFIG_UART_MCUX_LPUART + filter: CONFIG_SERIAL_SUPPORT_ASYNC and CONFIG_UART_MCUX_LPUART harness: ztest depends_on: dma drivers.uart.async_api.sam0: - filter: CONFIG_UART_CONSOLE and CONFIG_SERIAL_SUPPORT_ASYNC and CONFIG_SOC_FAMILY_SAM0 + filter: CONFIG_SERIAL_SUPPORT_ASYNC and CONFIG_SOC_FAMILY_SAM0 platform_allow: - atsamc21n_xpro - atsamd21_xpro From cf54f9acf9466d398ad32a2e470218a871748027 Mon Sep 17 00:00:00 2001 From: Alberto Escolar Piedras Date: Thu, 11 Jan 2024 11:03:51 +0100 Subject: [PATCH 2173/3723] boards nrf52_bsim: Allow running uart tests in this board Let's allow the uart tests to run in this board Signed-off-by: Alberto Escolar Piedras --- boards/posix/nrf_bsim/nrf52_bsim.yaml | 1 - 1 file changed, 1 deletion(-) diff --git a/boards/posix/nrf_bsim/nrf52_bsim.yaml b/boards/posix/nrf_bsim/nrf52_bsim.yaml index 5b29b974009..ce8cd935a7b 100644 --- a/boards/posix/nrf_bsim/nrf52_bsim.yaml +++ b/boards/posix/nrf_bsim/nrf52_bsim.yaml @@ -10,6 +10,5 @@ toolchain: testing: ignore_tags: - modem - - uart supported: - gpio From cee40d1d494791f19910361328131dc8089ada12 Mon Sep 17 00:00:00 2001 From: Alberto Escolar Piedras Date: Thu, 11 Jan 2024 11:04:31 +0100 Subject: [PATCH 2174/3723] tests/drivers/uart/uart*: Allow on nrf52_bsim Add the nrf52_bsim to the platform_allow list for tests which had such a filter. Note that for this test to pass, you need to connect the uart in loopback, passing the command line option `-uart0_loopback` to zephyr.exe Note this tests do not run right now by default in CI as the fixture is preventing it. They can be run with: twister -T tests/drivers/uart/ -v -p nrf52_bsim \ --fixture gpio_loopback -- -uart0_loopback Signed-off-by: Alberto Escolar Piedras --- tests/drivers/uart/uart_mix_fifo_poll/testcase.yaml | 1 + tests/drivers/uart/uart_pm/testcase.yaml | 4 +++- 2 files changed, 4 insertions(+), 1 deletion(-) diff --git a/tests/drivers/uart/uart_mix_fifo_poll/testcase.yaml b/tests/drivers/uart/uart_mix_fifo_poll/testcase.yaml index 65848e6603e..cd754d607c8 100644 --- a/tests/drivers/uart/uart_mix_fifo_poll/testcase.yaml +++ b/tests/drivers/uart/uart_mix_fifo_poll/testcase.yaml @@ -8,6 +8,7 @@ common: - nrf52840dk_nrf52840 - nrf9160dk_nrf9160 - nrf5340dk_nrf5340_cpuapp + - nrf52_bsim integration_platforms: - nrf52840dk_nrf52840 harness_config: diff --git a/tests/drivers/uart/uart_pm/testcase.yaml b/tests/drivers/uart/uart_pm/testcase.yaml index efb76ecf2c1..c8cb96fae2c 100644 --- a/tests/drivers/uart/uart_pm/testcase.yaml +++ b/tests/drivers/uart/uart_pm/testcase.yaml @@ -3,7 +3,9 @@ common: - drivers - uart harness: ztest - platform_allow: nrf52840dk_nrf52840 + platform_allow: + - nrf52840dk_nrf52840 + - nrf52_bsim harness_config: fixture: gpio_loopback depends_on: gpio From 27b1f4eb7f9d887d8fda81cbdc52f651223e75e9 Mon Sep 17 00:00:00 2001 From: Pavel Vasilyev Date: Fri, 12 Jan 2024 11:30:23 +0100 Subject: [PATCH 2175/3723] Bluetooth: Mesh: Fix dereferencing before null pointer check Don't dereference pointer until it is checked on NULL. Fixes: #66805 Coverity-CID: 338098 Signed-off-by: Pavel Vasilyev --- subsys/bluetooth/mesh/delayable_msg.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/subsys/bluetooth/mesh/delayable_msg.c b/subsys/bluetooth/mesh/delayable_msg.c index 5fa43205d63..a1a247bb9c9 100644 --- a/subsys/bluetooth/mesh/delayable_msg.c +++ b/subsys/bluetooth/mesh/delayable_msg.c @@ -167,13 +167,15 @@ static bool push_msg_from_delayable_msgs(void) sys_snode_t *node; struct delayable_msg_chunk *chunk; struct delayable_msg_ctx *msg = peek_pending_msg(); - uint16_t len = msg->len; + uint16_t len; int err; if (!msg) { return false; } + len = msg->len; + NET_BUF_SIMPLE_DEFINE(buf, BT_MESH_TX_SDU_MAX); SYS_SLIST_FOR_EACH_NODE(&msg->chunks, node) { From 3848fb82b80623612405ca788f150d71c84d1793 Mon Sep 17 00:00:00 2001 From: Yves Vandervennet Date: Thu, 21 Dec 2023 14:08:27 -0600 Subject: [PATCH 2176/3723] boards: mimxrt1050_evk: enable linkserver support - adds the definitions in the board.cmake file - updates documentation Signed-off-by: Yves Vandervennet --- boards/arm/mimxrt1050_evk/board.cmake | 2 ++ boards/arm/mimxrt1050_evk/doc/index.rst | 23 +++++++++++++++++++---- 2 files changed, 21 insertions(+), 4 deletions(-) diff --git a/boards/arm/mimxrt1050_evk/board.cmake b/boards/arm/mimxrt1050_evk/board.cmake index e7a3230af94..265ce1cd5f8 100644 --- a/boards/arm/mimxrt1050_evk/board.cmake +++ b/boards/arm/mimxrt1050_evk/board.cmake @@ -10,6 +10,8 @@ if(${CONFIG_BOARD_MIMXRT1050_EVK_QSPI}) board_runner_args(pyocd "--target=mimxrt1050_quadspi") else() board_runner_args(pyocd "--target=mimxrt1050_hyperflash") + board_runner_args(linkserver "--device=MIMXRT1052xxxxB:EVKB-IMXRT1050") + include(${ZEPHYR_BASE}/boards/common/linkserver.board.cmake) endif() include(${ZEPHYR_BASE}/boards/common/jlink.board.cmake) diff --git a/boards/arm/mimxrt1050_evk/doc/index.rst b/boards/arm/mimxrt1050_evk/doc/index.rst index 15ce2678736..de225ae56f3 100644 --- a/boards/arm/mimxrt1050_evk/doc/index.rst +++ b/boards/arm/mimxrt1050_evk/doc/index.rst @@ -322,8 +322,23 @@ however the :ref:`pyocd-debug-host-tools` do not yet support programming the external flashes on this board so you must reconfigure the board for one of the following debug probes instead. -Option 1: :ref:`opensda-jlink-onboard-debug-probe` (Recommended) ----------------------------------------------------------------- +Using LinkServer +---------------- + +Install the :ref:`linkserver-debug-host-tools` and make sure they are in your +search path. LinkServer works with the default CMSIS-DAP firmware included in +the on-board debugger. + +Linkserver is the default runner. You may also se the ``-r linkserver`` option +with West to use the LinkServer runner. + +.. code-block:: console + + west flash + west debug + +JLink (on-board): :ref:`opensda-jlink-onboard-debug-probe` +---------------------------------------------------------- Install the :ref:`jlink-debug-host-tools` and make sure they are in your search path. @@ -337,8 +352,8 @@ Follow the instructions in `Enable QSPI flash support in SEGGER JLink`_ in order to support your EVK if you have modified it to boot from QSPI NOR flash as specified by NXP AN12108. -Option 2: :ref:`jlink-external-debug-probe` -------------------------------------------- +External JLink :ref:`jlink-external-debug-probe` +------------------------------------------------ Install the :ref:`jlink-debug-host-tools` and make sure they are in your search path. From e021ccfc745221c685ea338f6ac2dd282e060434 Mon Sep 17 00:00:00 2001 From: Rander Wang Date: Wed, 3 Jan 2024 15:49:34 +0800 Subject: [PATCH 2177/3723] drivers: dma: intel-adsp-hda: add delay to stop host dma According to hardware spec, host dma needs some delay to completely stop. In the bug the host dma is disabled in different path in a few microseonds. The first setting disabled the host dma and called pm_device_runtime_put to power off it. The second setting found the host dma was still alive and calle pm_device_runtime_put again. This results to pm->usage checking failed. BugLink: https://github.com/thesofproject/sof/issues/8686 Signed-off-by: Rander Wang --- drivers/dma/dma_intel_adsp_hda.c | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/drivers/dma/dma_intel_adsp_hda.c b/drivers/dma/dma_intel_adsp_hda.c index 7a131db2216..7717013fddc 100644 --- a/drivers/dma/dma_intel_adsp_hda.c +++ b/drivers/dma/dma_intel_adsp_hda.c @@ -326,6 +326,14 @@ int intel_adsp_hda_dma_stop(const struct device *dev, uint32_t channel) intel_adsp_hda_disable(cfg->base, cfg->regblock_size, channel); + /* host dma needs some cycles to completely stop */ + if (cfg->direction == HOST_TO_MEMORY || cfg->direction == MEMORY_TO_HOST) { + if (!WAIT_FOR(!(*DGCS(cfg->base, cfg->regblock_size, channel) & DGCS_GBUSY), 1000, + k_busy_wait(1))) { + return -EBUSY; + } + } + return pm_device_runtime_put(dev); } From fc959fce475005b0e82ae1cfa91567190c4ff776 Mon Sep 17 00:00:00 2001 From: Ajay Parida Date: Thu, 27 Apr 2023 15:40:36 +0530 Subject: [PATCH 2178/3723] net: shell: Early wake up for TWT power save Provision of configurable parameter for generating unblock event ahead of TWT slot. Host application depending upon latencies can configure this to wakeup rpu ahead of the TWT slot. Signed-off-by: Ajay Parida --- include/zephyr/net/wifi_mgmt.h | 9 +++++++++ subsys/net/l2/wifi/wifi_shell.c | 15 ++++++++++++--- 2 files changed, 21 insertions(+), 3 deletions(-) diff --git a/include/zephyr/net/wifi_mgmt.h b/include/zephyr/net/wifi_mgmt.h index 0c64cab3c01..db15fa7b1ab 100644 --- a/include/zephyr/net/wifi_mgmt.h +++ b/include/zephyr/net/wifi_mgmt.h @@ -491,6 +491,12 @@ struct wifi_twt_params { bool announce; /** Wake up time */ uint32_t twt_wake_interval; + /* Wake ahead notification is sent earlier than + * TWT Service period (SP) start based on this duration. + * This should give applications ample time to + * prepare the data before TWT SP starts. + */ + uint32_t twt_wake_ahead_duration; } setup; /** Teardown specific parameters */ struct { @@ -507,6 +513,7 @@ struct wifi_twt_params { #define WIFI_MAX_TWT_INTERVAL_US (LONG_MAX - 1) /* 256 (u8) * 1TU */ #define WIFI_MAX_TWT_WAKE_INTERVAL_US 262144 +#define WIFI_MAX_TWT_WAKE_AHEAD_DURATION_US (LONG_MAX - 1) /** Wi-Fi TWT flow information */ struct wifi_twt_flow_info { @@ -528,6 +535,8 @@ struct wifi_twt_flow_info { bool announce; /** Wake up time */ uint32_t twt_wake_interval; + /* wake ahead duration */ + uint32_t twt_wake_ahead_duration; }; /** Wi-Fi power save configuration */ diff --git a/subsys/net/l2/wifi/wifi_shell.c b/subsys/net/l2/wifi/wifi_shell.c index 718144618d6..4c61ad4e4ae 100644 --- a/subsys/net/l2/wifi/wifi_shell.c +++ b/subsys/net/l2/wifi/wifi_shell.c @@ -887,6 +887,9 @@ static int cmd_wifi_ps(const struct shell *sh, size_t argc, char *argv[]) config.twt_flows[i].trigger, config.twt_flows[i].twt_wake_interval, config.twt_flows[i].twt_interval); + shell_fprintf(context.sh, SHELL_NORMAL, + "TWT Wake ahead duration : %d us\n", + config.twt_flows[i].twt_wake_ahead_duration); } } return 0; @@ -1045,7 +1048,7 @@ static int cmd_wifi_twt_setup(const struct shell *sh, size_t argc, context.sh = sh; - if (argc != 11) { + if (argc != 12) { shell_fprintf(sh, SHELL_WARNING, "Invalid number of arguments\n"); shell_help(sh); return -ENOEXEC; @@ -1105,6 +1108,11 @@ static int cmd_wifi_twt_setup(const struct shell *sh, size_t argc, } params.setup.twt_interval = (uint64_t)value; + if (!parse_number(sh, &value, argv[idx++], 0, WIFI_MAX_TWT_WAKE_AHEAD_DURATION_US)) { + return -EINVAL; + } + params.setup.twt_wake_ahead_duration = (uint32_t)value; + if (net_mgmt(NET_REQUEST_WIFI_TWT, iface, ¶ms, sizeof(params))) { shell_fprintf(sh, SHELL_WARNING, "%s with %s failed. reason : %s\n", wifi_twt_operation_txt(params.operation), @@ -1798,9 +1806,10 @@ SHELL_STATIC_SUBCMD_SET_CREATE(wifi_twt_ops, "\n" "\n" " " - " .\n", + " .\n" + ": 0us-2^31us>\n", cmd_wifi_twt_setup, - 11, 0), + 12, 0), SHELL_CMD_ARG(teardown, NULL, " Teardown a TWT flow:\n" "\n" "\n" From a21076bbf3b7e69e311026088827a0a4ec0cdd20 Mon Sep 17 00:00:00 2001 From: Andrej Butok Date: Thu, 7 Dec 2023 10:04:42 +0100 Subject: [PATCH 2179/3723] doc: pyocd: Add CMSIS DAP Onboard Debug Probe support Add the CMSIS DAP Onboard Debug Probes to the list of supported probes by pyOCD. Signed-off-by: Andrej Butok --- doc/develop/flash_debug/host-tools.rst | 2 ++ 1 file changed, 2 insertions(+) diff --git a/doc/develop/flash_debug/host-tools.rst b/doc/develop/flash_debug/host-tools.rst index cf349d5d29d..785bd6c7aef 100644 --- a/doc/develop/flash_debug/host-tools.rst +++ b/doc/develop/flash_debug/host-tools.rst @@ -321,6 +321,8 @@ Started Guide. pyOCD includes support for Zephyr RTOS-awareness. These debug host tools are compatible with the following debug probes: +- :ref:`lpclink2-cmsis-onboard-debug-probe` +- :ref:`mcu-link-cmsis-onboard-debug-probe` - :ref:`opensda-daplink-onboard-debug-probe` - :ref:`stlink-v21-onboard-debug-probe` From 38ed830f9128d17bcd5950aabd93f1fd7e2ab601 Mon Sep 17 00:00:00 2001 From: Martin Kiepfer Date: Sun, 31 Dec 2023 16:16:46 +0100 Subject: [PATCH 2180/3723] boards: m5stack_atoms3_lite: add support for M5Stack AtomS3 Lite Add support for M5Stack AtomS3 Lite development board. The AtomS3 Lite is a smaller version of the AtomS3 that features only a StatusLED and no LCD display. Signed-off-by: Martin Kiepfer --- .../xtensa/m5stack_atoms3_lite/Kconfig.board | 12 ++ .../m5stack_atoms3_lite/Kconfig.defconfig | 26 +++ .../m5stack_atoms3_lite/Kconfig.sysbuild | 10 ++ boards/xtensa/m5stack_atoms3_lite/board.cmake | 9 + .../doc/img/m5stack_atoms3_lite.webp | Bin 0 -> 21166 bytes .../xtensa/m5stack_atoms3_lite/doc/index.rst | 134 +++++++++++++++ .../m5stack_atoms3_lite/grove_connectors.dtsi | 18 ++ .../m5stack_atoms3_lite-pinctrl.dtsi | 49 ++++++ .../m5stack_atoms3_lite.dts | 155 ++++++++++++++++++ .../m5stack_atoms3_lite.yaml | 23 +++ .../m5stack_atoms3_lite_defconfig | 12 ++ dts/bindings/gpio/m5stack,atom-header.yaml | 17 ++ 12 files changed, 465 insertions(+) create mode 100644 boards/xtensa/m5stack_atoms3_lite/Kconfig.board create mode 100644 boards/xtensa/m5stack_atoms3_lite/Kconfig.defconfig create mode 100644 boards/xtensa/m5stack_atoms3_lite/Kconfig.sysbuild create mode 100644 boards/xtensa/m5stack_atoms3_lite/board.cmake create mode 100644 boards/xtensa/m5stack_atoms3_lite/doc/img/m5stack_atoms3_lite.webp create mode 100644 boards/xtensa/m5stack_atoms3_lite/doc/index.rst create mode 100644 boards/xtensa/m5stack_atoms3_lite/grove_connectors.dtsi create mode 100644 boards/xtensa/m5stack_atoms3_lite/m5stack_atoms3_lite-pinctrl.dtsi create mode 100644 boards/xtensa/m5stack_atoms3_lite/m5stack_atoms3_lite.dts create mode 100644 boards/xtensa/m5stack_atoms3_lite/m5stack_atoms3_lite.yaml create mode 100644 boards/xtensa/m5stack_atoms3_lite/m5stack_atoms3_lite_defconfig create mode 100644 dts/bindings/gpio/m5stack,atom-header.yaml diff --git a/boards/xtensa/m5stack_atoms3_lite/Kconfig.board b/boards/xtensa/m5stack_atoms3_lite/Kconfig.board new file mode 100644 index 00000000000..2c77718895e --- /dev/null +++ b/boards/xtensa/m5stack_atoms3_lite/Kconfig.board @@ -0,0 +1,12 @@ +# M5Stack AtomS3 Lite board configuration +# Copyright (c) 2023 Martin Kiepfer +# SPDX-License-Identifier: Apache-2.0 + +# M5Stack AtomS3 Lite +config BOARD_M5STACK_ATOMS3_LITE + bool "M5Stack AtomS3 Lite Development Board" + depends on SOC_SERIES_ESP32S3 + +choice SOC_PART_NUMBER + default SOC_ESP32S3_FN8 +endchoice diff --git a/boards/xtensa/m5stack_atoms3_lite/Kconfig.defconfig b/boards/xtensa/m5stack_atoms3_lite/Kconfig.defconfig new file mode 100644 index 00000000000..8f982cec80b --- /dev/null +++ b/boards/xtensa/m5stack_atoms3_lite/Kconfig.defconfig @@ -0,0 +1,26 @@ +# M5Stack AtomS3 Lite board configuration +# Copyright (c) 2023 Martin Kiepfer +# SPDX-License-Identifier: Apache-2.0 + +if BOARD_M5STACK_ATOMS3_LITE + +config BOARD + default "m5stack_atoms3_lite" + depends on BOARD_M5STACK_ATOMS3_LITE + +config ENTROPY_GENERATOR + default y + +config HEAP_MEM_POOL_ADD_SIZE_BOARD + int + default 98304 if WIFI + default 65536 if BT + default 4096 + +config KERNEL_MEM_POOL + default y + +choice BT_HCI_BUS_TYPE + default BT_ESP32 if BT +endchoice +endif # BOARD_M5STACK_ATOMS3_LITE diff --git a/boards/xtensa/m5stack_atoms3_lite/Kconfig.sysbuild b/boards/xtensa/m5stack_atoms3_lite/Kconfig.sysbuild new file mode 100644 index 00000000000..3a2d17ac5cf --- /dev/null +++ b/boards/xtensa/m5stack_atoms3_lite/Kconfig.sysbuild @@ -0,0 +1,10 @@ +# Copyright (c) 2023 Espressif Systems (Shanghai) Co., Ltd. +# SPDX-License-Identifier: Apache-2.0 + +choice BOOTLOADER + default BOOTLOADER_MCUBOOT +endchoice + +choice BOOT_SIGNATURE_TYPE + default BOOT_SIGNATURE_TYPE_NONE +endchoice diff --git a/boards/xtensa/m5stack_atoms3_lite/board.cmake b/boards/xtensa/m5stack_atoms3_lite/board.cmake new file mode 100644 index 00000000000..2f04d1fe886 --- /dev/null +++ b/boards/xtensa/m5stack_atoms3_lite/board.cmake @@ -0,0 +1,9 @@ +# SPDX-License-Identifier: Apache-2.0 + +if(NOT "${OPENOCD}" MATCHES "^${ESPRESSIF_TOOLCHAIN_PATH}/.*") + set(OPENOCD OPENOCD-NOTFOUND) +endif() +find_program(OPENOCD openocd PATHS ${ESPRESSIF_TOOLCHAIN_PATH}/openocd-esp32/bin NO_DEFAULT_PATH) + +include(${ZEPHYR_BASE}/boards/common/esp32.board.cmake) +include(${ZEPHYR_BASE}/boards/common/openocd.board.cmake) diff --git a/boards/xtensa/m5stack_atoms3_lite/doc/img/m5stack_atoms3_lite.webp b/boards/xtensa/m5stack_atoms3_lite/doc/img/m5stack_atoms3_lite.webp new file mode 100644 index 0000000000000000000000000000000000000000..c538a14dc0e65235a9a82f0586d47350fa210881 GIT binary patch literal 21166 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 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 + +Debugging +--------- + +M5Stack AtomS3 Lite debugging is not supported due to pinout limitations. + +Related Documents +***************** + +- `M5Stack AtomS3 Lite schematic `_ +- `ESP32S3 Datasheet `_ diff --git a/boards/xtensa/m5stack_atoms3_lite/grove_connectors.dtsi b/boards/xtensa/m5stack_atoms3_lite/grove_connectors.dtsi new file mode 100644 index 00000000000..db98d8885dd --- /dev/null +++ b/boards/xtensa/m5stack_atoms3_lite/grove_connectors.dtsi @@ -0,0 +1,18 @@ +/* + * Copyright (c) 2023 Benjamin Cabé + * Copyright (c) 2023 Martin Kiepfer + * SPDX-License-Identifier: Apache-2.0 + */ + +/ { + grove_header: grove_header { + compatible = "grove-header"; + #gpio-cells = <2>; + gpio-map-mask = <0xffffffff 0xffffffc0>; + gpio-map-pass-thru = <0 0x3f>; + gpio-map = <0 0 &gpio0 1 0>, + <1 0 &gpio0 2 0>; + }; +}; + +grove_i2c1: &i2c1 {}; diff --git a/boards/xtensa/m5stack_atoms3_lite/m5stack_atoms3_lite-pinctrl.dtsi b/boards/xtensa/m5stack_atoms3_lite/m5stack_atoms3_lite-pinctrl.dtsi new file mode 100644 index 00000000000..051456e687c --- /dev/null +++ b/boards/xtensa/m5stack_atoms3_lite/m5stack_atoms3_lite-pinctrl.dtsi @@ -0,0 +1,49 @@ +/* + * Copyright (c) 2023 Benjamin Cabé + * Copyright (c) 2023 Martin Kiepfer + * + * SPDX-License-Identifier: Apache-2.0 + */ +#include +#include +#include + +&pinctrl { + uart0_default: uart0_default { + group1 { + pinmux = ; + output-high; + }; + group2 { + pinmux = ; + bias-pull-up; + }; + }; + + i2c0_default: i2c0_default { + group1 { + pinmux = , + ; + bias-pull-up; + drive-open-drain; + output-high; + }; + }; + + i2c1_default: i2c1_default { + group1 { + pinmux = , + ; + bias-pull-up; + drive-open-drain; + output-high; + }; + }; + + spim3_ws2812_led: spim3_ws2812_led { + group1 { + pinmux = ; + output-low; + }; + }; +}; diff --git a/boards/xtensa/m5stack_atoms3_lite/m5stack_atoms3_lite.dts b/boards/xtensa/m5stack_atoms3_lite/m5stack_atoms3_lite.dts new file mode 100644 index 00000000000..51b65cfba0c --- /dev/null +++ b/boards/xtensa/m5stack_atoms3_lite/m5stack_atoms3_lite.dts @@ -0,0 +1,155 @@ +/* + * Copyright (c) 2023 Benjamin Cabé + * Copyright (c) 2023 Martin Kiepfer + * + * SPDX-License-Identifier: Apache-2.0 + */ +/dts-v1/; + +#include +#include "m5stack_atoms3_lite-pinctrl.dtsi" +#include +#include +#include + +/ { + model = "M5Stack AtomS3 Lite"; + compatible = "m5stack,atoms3_lite"; + + chosen { + zephyr,sram = &sram0; + zephyr,console = &usb_serial; + zephyr,shell-uart = &usb_serial; + zephyr,flash = &flash0; + zephyr,code-partition = &slot0_partition; + }; + + aliases { + sw0 = &user_button_0; + watchdog0 = &wdt0; + i2c-0 = &i2c0; + led-strip = &status_rgb_led; + }; + + buttons { + compatible = "gpio-keys"; + debounce-interval-ms = <100>; + user_button_0: button_0 { + label = "User button 0"; + gpios = <&gpio1 9 (GPIO_PULL_UP | GPIO_ACTIVE_LOW)>; + zephyr,code = ; + }; + }; +}; + +&cpu0 { + clock-frequency = ; +}; + +&cpu1 { + clock-frequency = ; +}; + +&usb_serial { + status = "okay"; +}; +&uart0 { + status = "okay"; + current-speed = <115200>; + pinctrl-0 = <&uart0_default>; + pinctrl-names = "default"; +}; + +&i2c0 { + status = "okay"; + clock-frequency = ; + pinctrl-0 = <&i2c0_default>; + pinctrl-names = "default"; +}; + +&i2c1 { + status = "okay"; + clock-frequency = ; + pinctrl-0 = <&i2c1_default>; + pinctrl-names = "default"; +}; + +&trng0 { + status = "okay"; +}; + +&spi3 { + #address-cells = <1>; + #size-cells = <0>; + status = "okay"; + line-idle-low; + pinctrl-0 = <&spim3_ws2812_led>; + pinctrl-names = "default"; + + status_rgb_led: ws2812@0 { + compatible = "worldsemi,ws2812-spi"; + reg = <0>; + spi-max-frequency = ; + + chain-length = <1>; + color-mapping = , + , + ; + spi-one-frame = ; + spi-zero-frame = ; + }; +}; +&gpio0 { + status = "okay"; +}; + +&gpio1 { + status = "okay"; +}; + +&wdt0 { + status = "okay"; +}; + +&timer0 { + status = "okay"; +}; + +&timer1 { + status = "okay"; +}; + +&flash0 { + status = "okay"; + partitions { + compatible = "fixed-partitions"; + #address-cells = <1>; + #size-cells = <1>; + + boot_partition: partition@0 { + label = "mcuboot"; + reg = <0x00000000 0x0000F000>; + read-only; + }; + + slot0_partition: partition@10000 { + label = "image-0"; + reg = <0x00010000 0x00100000>; + }; + + slot1_partition: partition@110000 { + label = "image-1"; + reg = <0x00110000 0x00100000>; + }; + + scratch_partition: partition@210000 { + label = "image-scratch"; + reg = <0x00210000 0x00040000>; + }; + + storage_partition: partition@250000 { + label = "storage"; + reg = <0x00250000 0x00006000>; + }; + }; +}; diff --git a/boards/xtensa/m5stack_atoms3_lite/m5stack_atoms3_lite.yaml b/boards/xtensa/m5stack_atoms3_lite/m5stack_atoms3_lite.yaml new file mode 100644 index 00000000000..82426e35fe6 --- /dev/null +++ b/boards/xtensa/m5stack_atoms3_lite/m5stack_atoms3_lite.yaml @@ -0,0 +1,23 @@ +identifier: m5stack_atoms3_lite +name: M5Stack AtomS3-Lite +type: mcu +arch: xtensa +toolchain: + - zephyr +supported: + - gpio + - uart + - i2c + - spi + - counter + - watchdog + - entropy + - pwm + - pinmux + - nvs + - dma +testing: + ignore_tags: + - net + - bluetooth +vendor: m5stack diff --git a/boards/xtensa/m5stack_atoms3_lite/m5stack_atoms3_lite_defconfig b/boards/xtensa/m5stack_atoms3_lite/m5stack_atoms3_lite_defconfig new file mode 100644 index 00000000000..18468290e06 --- /dev/null +++ b/boards/xtensa/m5stack_atoms3_lite/m5stack_atoms3_lite_defconfig @@ -0,0 +1,12 @@ +# SPDX-License-Identifier: Apache-2.0 + +CONFIG_BOARD_M5STACK_ATOMS3_LITE=y +CONFIG_SOC_SERIES_ESP32S3=y + +CONFIG_MAIN_STACK_SIZE=2048 + +CONFIG_CONSOLE=y +CONFIG_SERIAL=y +CONFIG_UART_CONSOLE=y +CONFIG_GPIO=y +CONFIG_CLOCK_CONTROL=y diff --git a/dts/bindings/gpio/m5stack,atom-header.yaml b/dts/bindings/gpio/m5stack,atom-header.yaml new file mode 100644 index 00000000000..ddb0c38f82c --- /dev/null +++ b/dts/bindings/gpio/m5stack,atom-header.yaml @@ -0,0 +1,17 @@ +# Copyright (c) 2023 Martin Kiepfer +# SPDX-License-Identifier: Apache-2.0 + +description: | + Pin-header exposed on M5Stack Atom devices. + + This binding provides a nexus mapping for 9 pins as depicted below. + + x 3.3V + 0 GPIO 1 SCL + 2 GPIO/MOSI 3 GPIO/DAC0/SDA + 4 GPIO/CLK 5 5V + 6 GPIO/ADC0/MISO 7 GND + +compatible: "m5stack,atom-header" + +include: [gpio-nexus.yaml, base.yaml] From 11fc1823153895c86414d81af985fa6c87698f79 Mon Sep 17 00:00:00 2001 From: Lucas Tamborrino Date: Wed, 20 Dec 2023 12:24:13 -0300 Subject: [PATCH 2181/3723] soc: esp32: refactor esp32_net SOC_ESP32_NET is now SOC_ESP32_APPCPU, following espressif's naming convention in the same manner as ESP32S3 app cpu. SOC_ESP32_APPCU is now a subset of SOC_SERIES_ESP32. This commit also changes the necessary files, samples and tests for bisect purposes. Signed-off-by: Lucas Tamborrino --- .../xtensa/esp32_devkitc_wroom/Kconfig.board | 4 + .../esp32_devkitc_wroom/Kconfig.defconfig | 24 +- .../xtensa/esp32_devkitc_wroom/doc/index.rst | 6 + .../esp32_devkitc_wroom_appcpu.dts} | 10 +- .../esp32_devkitc_wroom_appcpu.yaml} | 13 +- .../esp32_devkitc_wroom_appcpu_defconfig | 9 + .../xtensa/esp32_devkitc_wrover/Kconfig.board | 4 + .../esp32_devkitc_wrover/Kconfig.defconfig | 23 +- .../xtensa/esp32_devkitc_wrover/doc/index.rst | 6 + .../esp32_devkitc_wrover_appcpu.dts | 31 ++ .../esp32_devkitc_wrover_appcpu.yaml | 27 ++ .../esp32_devkitc_wrover_appcpu_defconfig | 9 + boards/xtensa/esp32_net/Kconfig.board | 12 - boards/xtensa/esp32_net/Kconfig.defconfig | 21 - boards/xtensa/esp32_net/board.cmake | 9 - boards/xtensa/esp32_net/doc/index.rst | 169 --------- boards/xtensa/esp32_net/esp32_net_defconfig | 15 - boards/xtensa/esp32_net/support/openocd.cfg | 5 - drivers/clock_control/clock_control_esp32.c | 5 +- drivers/hwinfo/hwinfo_esp32.c | 2 +- drivers/ipm/ipm_esp32.c | 8 +- .../{esp32_net.dtsi => esp32_appcpu.dtsi} | 0 samples/basic/hash_map/sample.yaml | 2 - samples/drivers/ipm/ipm_esp32/CMakeLists.txt | 18 +- .../ipm_esp32/boards/esp32_devkitc_wroom.conf | 1 + .../boards/esp32_devkitc_wrover.conf | 1 + .../ipm/ipm_esp32/ipm_esp32_net/prj.conf | 3 - .../CMakeLists.txt | 2 +- .../esp32_devkitc_wroom_appcpu.overlay} | 0 .../esp32_devkitc_wrover_appcpu.overlay | 3 + .../ipm/ipm_esp32/ipm_esp_appcpu/prj.conf | 2 + .../src/main.c | 0 samples/drivers/ipm/ipm_esp32/prj.conf | 1 - .../subsys/ipc/rpmsg_service/CMakeLists.txt | 4 +- .../boards/esp32_devkitc_wrover.conf | 2 +- .../ipc/rpmsg_service/remote/CMakeLists.txt | 3 +- ...ay => esp32_devkitc_wrover_appcpu.overlay} | 0 .../remote/boards/esp32_net.conf | 1 - .../espressif_esp32/esp32/CMakeLists.txt | 50 ++- .../espressif_esp32/esp32/Kconfig.series | 14 + soc/xtensa/espressif_esp32/esp32/Kconfig.soc | 20 +- soc/xtensa/espressif_esp32/esp32/default.ld | 6 +- .../linker.ld => esp32/default_appcpu.ld} | 2 +- soc/xtensa/espressif_esp32/esp32/esp32-mp.c | 8 +- soc/xtensa/espressif_esp32/esp32/soc.c | 45 +-- .../{esp32_net/soc.c => esp32/soc_appcpu.c} | 20 +- .../espressif_esp32/esp32_net/CMakeLists.txt | 23 -- .../esp32_net/Kconfig.defconfig.series | 21 - .../espressif_esp32/esp32_net/Kconfig.series | 12 - .../espressif_esp32/esp32_net/Kconfig.soc | 78 ---- .../esp32_net/include/_soc_inthandlers.h | 359 ------------------ .../esp32_net/include/gdbstub/soc.h | 21 - .../espressif_esp32/esp32_net/newlib_fix.c | 22 -- soc/xtensa/espressif_esp32/esp32_net/soc.h | 69 ---- .../fs_mgmt_hash_supported/testcase.yaml | 3 - west.yml | 2 +- 56 files changed, 287 insertions(+), 943 deletions(-) rename boards/xtensa/{esp32_net/esp32_net.dts => esp32_devkitc_wroom/esp32_devkitc_wroom_appcpu.dts} (52%) rename boards/xtensa/{esp32_net/esp32_net.yaml => esp32_devkitc_wroom/esp32_devkitc_wroom_appcpu.yaml} (57%) create mode 100644 boards/xtensa/esp32_devkitc_wroom/esp32_devkitc_wroom_appcpu_defconfig create mode 100644 boards/xtensa/esp32_devkitc_wrover/esp32_devkitc_wrover_appcpu.dts create mode 100644 boards/xtensa/esp32_devkitc_wrover/esp32_devkitc_wrover_appcpu.yaml create mode 100644 boards/xtensa/esp32_devkitc_wrover/esp32_devkitc_wrover_appcpu_defconfig delete mode 100644 boards/xtensa/esp32_net/Kconfig.board delete mode 100644 boards/xtensa/esp32_net/Kconfig.defconfig delete mode 100644 boards/xtensa/esp32_net/board.cmake delete mode 100644 boards/xtensa/esp32_net/doc/index.rst delete mode 100644 boards/xtensa/esp32_net/esp32_net_defconfig delete mode 100644 boards/xtensa/esp32_net/support/openocd.cfg rename dts/xtensa/espressif/esp32/{esp32_net.dtsi => esp32_appcpu.dtsi} (100%) create mode 100644 samples/drivers/ipm/ipm_esp32/boards/esp32_devkitc_wroom.conf create mode 100644 samples/drivers/ipm/ipm_esp32/boards/esp32_devkitc_wrover.conf delete mode 100644 samples/drivers/ipm/ipm_esp32/ipm_esp32_net/prj.conf rename samples/drivers/ipm/ipm_esp32/{ipm_esp32_net => ipm_esp_appcpu}/CMakeLists.txt (86%) rename samples/drivers/ipm/ipm_esp32/{ipm_esp32_net/boards/esp32_net.overlay => ipm_esp_appcpu/boards/esp32_devkitc_wroom_appcpu.overlay} (100%) create mode 100644 samples/drivers/ipm/ipm_esp32/ipm_esp_appcpu/boards/esp32_devkitc_wrover_appcpu.overlay create mode 100644 samples/drivers/ipm/ipm_esp32/ipm_esp_appcpu/prj.conf rename samples/drivers/ipm/ipm_esp32/{ipm_esp32_net => ipm_esp_appcpu}/src/main.c (100%) rename samples/subsys/ipc/rpmsg_service/remote/boards/{esp32_net.overlay => esp32_devkitc_wrover_appcpu.overlay} (100%) delete mode 100644 samples/subsys/ipc/rpmsg_service/remote/boards/esp32_net.conf rename soc/xtensa/espressif_esp32/{esp32_net/linker.ld => esp32/default_appcpu.ld} (99%) rename soc/xtensa/espressif_esp32/{esp32_net/soc.c => esp32/soc_appcpu.c} (93%) delete mode 100644 soc/xtensa/espressif_esp32/esp32_net/CMakeLists.txt delete mode 100644 soc/xtensa/espressif_esp32/esp32_net/Kconfig.defconfig.series delete mode 100644 soc/xtensa/espressif_esp32/esp32_net/Kconfig.series delete mode 100644 soc/xtensa/espressif_esp32/esp32_net/Kconfig.soc delete mode 100644 soc/xtensa/espressif_esp32/esp32_net/include/_soc_inthandlers.h delete mode 100644 soc/xtensa/espressif_esp32/esp32_net/include/gdbstub/soc.h delete mode 100644 soc/xtensa/espressif_esp32/esp32_net/newlib_fix.c delete mode 100644 soc/xtensa/espressif_esp32/esp32_net/soc.h diff --git a/boards/xtensa/esp32_devkitc_wroom/Kconfig.board b/boards/xtensa/esp32_devkitc_wroom/Kconfig.board index 5c3fa887b57..a295f3bfc50 100644 --- a/boards/xtensa/esp32_devkitc_wroom/Kconfig.board +++ b/boards/xtensa/esp32_devkitc_wroom/Kconfig.board @@ -5,6 +5,10 @@ config BOARD_ESP32_DEVKITC_WROOM bool "ESP32-DEVKITC-WROOM Development Board" depends on SOC_SERIES_ESP32 +config BOARD_ESP32_DEVKITC_WROOM_APPCPU + bool "ESP32 Board configuration for APPCPU (core 1)." + depends on SOC_SERIES_ESP32 && SOC_ESP32_APPCPU + choice SOC_PART_NUMBER default SOC_ESP32_WROOM_32UE_N4 endchoice diff --git a/boards/xtensa/esp32_devkitc_wroom/Kconfig.defconfig b/boards/xtensa/esp32_devkitc_wroom/Kconfig.defconfig index a168ca5f31d..0a1d0506fa9 100644 --- a/boards/xtensa/esp32_devkitc_wroom/Kconfig.defconfig +++ b/boards/xtensa/esp32_devkitc_wroom/Kconfig.defconfig @@ -3,12 +3,10 @@ # Copyright (c) 2017 Intel Corporation # SPDX-License-Identifier: Apache-2.0 +if BOARD_ESP32_DEVKITC_WROOM + config BOARD default "esp32_devkitc_wroom" - depends on BOARD_ESP32_DEVKITC_WROOM - -config ENTROPY_GENERATOR - default y config HEAP_MEM_POOL_ADD_SIZE_BOARD int @@ -19,3 +17,21 @@ config HEAP_MEM_POOL_ADD_SIZE_BOARD choice BT_HCI_BUS_TYPE default BT_ESP32 if BT endchoice + +endif # BOARD_ESP32_DEVKITC_WROOM + +if BOARD_ESP32_DEVKITC_WROOM_APPCPU + +config BOARD + default "esp32_devkitc_wroom_appcpu" + +config HEAP_MEM_POOL_ADD_SIZE_BOARD + default 4096 + +config KERNEL_BIN_NAME + default "esp32_net_firmware" + +endif # BOARD_ESP32_DEVKITC_WROOM_APPCPU + +config ENTROPY_GENERATOR + default y diff --git a/boards/xtensa/esp32_devkitc_wroom/doc/index.rst b/boards/xtensa/esp32_devkitc_wroom/doc/index.rst index b8856c7b3cb..ceeb7d38ba9 100644 --- a/boards/xtensa/esp32_devkitc_wroom/doc/index.rst +++ b/boards/xtensa/esp32_devkitc_wroom/doc/index.rst @@ -47,6 +47,12 @@ The features include the following: ESP32-DevKitC-WROOM-32D DK +Asymmetric Multiprocessing (AMP) +******************************** + +ESP32-DEVKITC-WROOM 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 :ref:`ipc_samples` folder as code reference. + Supported Features ================== diff --git a/boards/xtensa/esp32_net/esp32_net.dts b/boards/xtensa/esp32_devkitc_wroom/esp32_devkitc_wroom_appcpu.dts similarity index 52% rename from boards/xtensa/esp32_net/esp32_net.dts rename to boards/xtensa/esp32_devkitc_wroom/esp32_devkitc_wroom_appcpu.dts index 7479d342fb6..c58f39cd444 100644 --- a/boards/xtensa/esp32_net/esp32_net.dts +++ b/boards/xtensa/esp32_devkitc_wroom/esp32_devkitc_wroom_appcpu.dts @@ -1,18 +1,20 @@ /* - * Copyright (c) 2022 Espressif Systems (Shanghai) Co., Ltd. + * Copyright (c) 2023 Espressif Systems (Shanghai) Co., Ltd. * * SPDX-License-Identifier: Apache-2.0 */ /dts-v1/; -#include +#include / { - model = "esp32_net"; - compatible = "espressif,esp32_net"; + model = "esp32_wroom_appcpu"; + compatible = "espressif,esp32_appcpu"; chosen { zephyr,sram = &sram0; + zephyr,ipc_shm = &shm0; + zephyr,ipc = &ipm0; }; }; diff --git a/boards/xtensa/esp32_net/esp32_net.yaml b/boards/xtensa/esp32_devkitc_wroom/esp32_devkitc_wroom_appcpu.yaml similarity index 57% rename from boards/xtensa/esp32_net/esp32_net.yaml rename to boards/xtensa/esp32_devkitc_wroom/esp32_devkitc_wroom_appcpu.yaml index 14739928f62..02f9916ef90 100644 --- a/boards/xtensa/esp32_net/esp32_net.yaml +++ b/boards/xtensa/esp32_devkitc_wroom/esp32_devkitc_wroom_appcpu.yaml @@ -1,12 +1,10 @@ -identifier: esp32_net -name: ESP32_NET +identifier: esp32_devkitc_wroom_appcpu +name: ESP32 DEVKITC WROOM APPCPU type: mcu arch: xtensa toolchain: - zephyr supported: - - gpio - - i2c - uart testing: ignore_tags: @@ -19,4 +17,11 @@ testing: - logging - kernel - pm + - gpio + - crypto + - eeprom + - heap + - cmsis_rtos + - jwt + - zdsp vendor: espressif diff --git a/boards/xtensa/esp32_devkitc_wroom/esp32_devkitc_wroom_appcpu_defconfig b/boards/xtensa/esp32_devkitc_wroom/esp32_devkitc_wroom_appcpu_defconfig new file mode 100644 index 00000000000..81406ae4c49 --- /dev/null +++ b/boards/xtensa/esp32_devkitc_wroom/esp32_devkitc_wroom_appcpu_defconfig @@ -0,0 +1,9 @@ +# SPDX-License-Identifier: Apache-2.0 + +CONFIG_SOC_SERIES_ESP32=y +CONFIG_SOC_ESP32_APPCPU=y +CONFIG_BOARD_ESP32_DEVKITC_WROOM_APPCPU=y + +CONFIG_MAIN_STACK_SIZE=2048 +CONFIG_CLOCK_CONTROL=y +CONFIG_MINIMAL_LIBC=y diff --git a/boards/xtensa/esp32_devkitc_wrover/Kconfig.board b/boards/xtensa/esp32_devkitc_wrover/Kconfig.board index b345a9dff44..20e59ac10fe 100644 --- a/boards/xtensa/esp32_devkitc_wrover/Kconfig.board +++ b/boards/xtensa/esp32_devkitc_wrover/Kconfig.board @@ -5,6 +5,10 @@ config BOARD_ESP32_DEVKITC_WROVER bool "ESP32-DEVKITC-WROVER-E Development board" depends on SOC_SERIES_ESP32 +config BOARD_ESP32_DEVKITC_WROVER_APPCPU + bool "ESP32 Board configuration for APPCPU (core 1)." + depends on SOC_SERIES_ESP32 && SOC_ESP32_APPCPU + choice SOC_PART_NUMBER default SOC_ESP32_WROVER_E_N4R8 endchoice diff --git a/boards/xtensa/esp32_devkitc_wrover/Kconfig.defconfig b/boards/xtensa/esp32_devkitc_wrover/Kconfig.defconfig index 9e07262b1d4..b98f19fce17 100644 --- a/boards/xtensa/esp32_devkitc_wrover/Kconfig.defconfig +++ b/boards/xtensa/esp32_devkitc_wrover/Kconfig.defconfig @@ -1,12 +1,10 @@ # Copyright (c) 2023 Espressif Systems (Shanghai) Co., Ltd. # SPDX-License-Identifier: Apache-2.0 +if BOARD_ESP32_DEVKITC_WROVER + config BOARD default "esp32_devkitc_wrover" - depends on BOARD_ESP32_DEVKITC_WROVER - -config ENTROPY_GENERATOR - default y config HEAP_MEM_POOL_ADD_SIZE_BOARD int @@ -17,3 +15,20 @@ config HEAP_MEM_POOL_ADD_SIZE_BOARD choice BT_HCI_BUS_TYPE default BT_ESP32 if BT endchoice + +endif # BOARD_ESP32_DEVKITC_WROVER + +if BOARD_ESP32_DEVKITC_WROVER_APPCPU + +config BOARD + default "esp32_devkitc_wrover_appcpu" + +config HEAP_MEM_POOL_ADD_SIZE_BOARD + default 4096 + +config KERNEL_BIN_NAME + default "esp32_net_firmware" +endif + +config ENTROPY_GENERATOR + default y diff --git a/boards/xtensa/esp32_devkitc_wrover/doc/index.rst b/boards/xtensa/esp32_devkitc_wrover/doc/index.rst index e7615f13335..ec59ab5c640 100644 --- a/boards/xtensa/esp32_devkitc_wrover/doc/index.rst +++ b/boards/xtensa/esp32_devkitc_wrover/doc/index.rst @@ -47,6 +47,12 @@ The features include the following: ESP32-DevKitC-WROVER-IE +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 :ref:`ipc_samples` folder as code reference. + Supported Features ================== diff --git a/boards/xtensa/esp32_devkitc_wrover/esp32_devkitc_wrover_appcpu.dts b/boards/xtensa/esp32_devkitc_wrover/esp32_devkitc_wrover_appcpu.dts new file mode 100644 index 00000000000..2b6f0626356 --- /dev/null +++ b/boards/xtensa/esp32_devkitc_wrover/esp32_devkitc_wrover_appcpu.dts @@ -0,0 +1,31 @@ +/* + * Copyright (c) 2023 Espressif Systems (Shanghai) Co., Ltd. + * + * SPDX-License-Identifier: Apache-2.0 + */ +/dts-v1/; + +#include + +/ { + model = "esp32_wrover_appcpu"; + compatible = "espressif,esp32_appcpu"; + + chosen { + zephyr,sram = &sram0; + zephyr,ipc_shm = &shm0; + zephyr,ipc = &ipm0; + }; +}; + +&cpu0 { + clock-frequency = ; +}; + +&cpu1 { + clock-frequency = ; +}; + +&trng0 { + status = "okay"; +}; diff --git a/boards/xtensa/esp32_devkitc_wrover/esp32_devkitc_wrover_appcpu.yaml b/boards/xtensa/esp32_devkitc_wrover/esp32_devkitc_wrover_appcpu.yaml new file mode 100644 index 00000000000..03fe6a111a6 --- /dev/null +++ b/boards/xtensa/esp32_devkitc_wrover/esp32_devkitc_wrover_appcpu.yaml @@ -0,0 +1,27 @@ +identifier: esp32_devkitc_wrover_appcpu +name: ESP32 DEVKITC WROVER APPCPU +type: mcu +arch: xtensa +toolchain: + - zephyr +supported: + - uart +testing: + ignore_tags: + - net + - bluetooth + - flash + - cpp + - posix + - watchdog + - logging + - kernel + - pm + - gpio + - crypto + - eeprom + - heap + - cmsis_rtos + - jwt + - zdsp +vendor: espressif diff --git a/boards/xtensa/esp32_devkitc_wrover/esp32_devkitc_wrover_appcpu_defconfig b/boards/xtensa/esp32_devkitc_wrover/esp32_devkitc_wrover_appcpu_defconfig new file mode 100644 index 00000000000..5363f493882 --- /dev/null +++ b/boards/xtensa/esp32_devkitc_wrover/esp32_devkitc_wrover_appcpu_defconfig @@ -0,0 +1,9 @@ +# SPDX-License-Identifier: Apache-2.0 + +CONFIG_SOC_SERIES_ESP32=y +CONFIG_SOC_ESP32_APPCPU=y +CONFIG_BOARD_ESP32_DEVKITC_WROVER_APPCPU=y + +CONFIG_MAIN_STACK_SIZE=2048 +CONFIG_CLOCK_CONTROL=y +CONFIG_MINIMAL_LIBC=y diff --git a/boards/xtensa/esp32_net/Kconfig.board b/boards/xtensa/esp32_net/Kconfig.board deleted file mode 100644 index 946a59dce7f..00000000000 --- a/boards/xtensa/esp32_net/Kconfig.board +++ /dev/null @@ -1,12 +0,0 @@ -# ESP32 board configuration - -# Copyright (c) 2022 Espressif Systems (Shanghai) Co., Ltd. -# SPDX-License-Identifier: Apache-2.0 - -config BOARD_ESP32_NET - bool "ESP32 Board configuration for APP_CPU" - depends on SOC_SERIES_ESP32_NET - -choice SOC_PART_NUMBER - default SOC_ESP32_NET -endchoice diff --git a/boards/xtensa/esp32_net/Kconfig.defconfig b/boards/xtensa/esp32_net/Kconfig.defconfig deleted file mode 100644 index 7770e94a0ae..00000000000 --- a/boards/xtensa/esp32_net/Kconfig.defconfig +++ /dev/null @@ -1,21 +0,0 @@ -# ESP32_NET board configuration - -# Copyright (c) 2022 Espressif Systems (Shanghai) Co., Ltd. -# SPDX-License-Identifier: Apache-2.0 - -config BOARD - default "esp32_net" - depends on BOARD_ESP32_NET - -config ENTROPY_GENERATOR - default y - -config HEAP_MEM_POOL_ADD_SIZE_BOARD - int - default 98304 if WIFI - default 40960 if BT - default 4096 - -choice BT_HCI_BUS_TYPE - default BT_ESP32 if BT -endchoice diff --git a/boards/xtensa/esp32_net/board.cmake b/boards/xtensa/esp32_net/board.cmake deleted file mode 100644 index 2f04d1fe886..00000000000 --- a/boards/xtensa/esp32_net/board.cmake +++ /dev/null @@ -1,9 +0,0 @@ -# SPDX-License-Identifier: Apache-2.0 - -if(NOT "${OPENOCD}" MATCHES "^${ESPRESSIF_TOOLCHAIN_PATH}/.*") - set(OPENOCD OPENOCD-NOTFOUND) -endif() -find_program(OPENOCD openocd PATHS ${ESPRESSIF_TOOLCHAIN_PATH}/openocd-esp32/bin NO_DEFAULT_PATH) - -include(${ZEPHYR_BASE}/boards/common/esp32.board.cmake) -include(${ZEPHYR_BASE}/boards/common/openocd.board.cmake) diff --git a/boards/xtensa/esp32_net/doc/index.rst b/boards/xtensa/esp32_net/doc/index.rst deleted file mode 100644 index 5321727aa7d..00000000000 --- a/boards/xtensa/esp32_net/doc/index.rst +++ /dev/null @@ -1,169 +0,0 @@ -.. _esp32_net: - -ESP32-NET -######### - -Overview -******** - -ESP32_NET is a board configuration to allow zephyr application building -targeted to ESP32 APP_CPU only, please refer ESP32 board to a more complete -list of features. - -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 -------------------- - -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: esp32_devkitc_wroom - :goals: build - -The usual ``flash`` target will work with the ``esp32_devkitc_wroom`` board -configuration. Here is an example for the :ref:`hello_world` -application. - -.. zephyr-app-commands:: - :zephyr-app: samples/hello_world - :board: esp32_devkitc_wroom - :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! esp32_devkitc_wroom - -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 :ref:`hello_world` application. - -.. zephyr-app-commands:: - :zephyr-app: samples/hello_world - :board: esp32_devkitc_wroom - :goals: build flash - :gen-args: -DOPENOCD= -DOPENOCD_DEFAULT_PATH= - -You can debug an application in the usual way. Here is an example for the :ref:`hello_world` application. - -.. zephyr-app-commands:: - :zephyr-app: samples/hello_world - :board: esp32_devkitc_wroom - :goals: debug - -Using JTAG -====================== - -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 -require no external hardware and are debuggable as-is. The JTAG -signals, however, must be jumpered closed to connect the internal -controller (the default is to leave them disconnected). The jumper -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. - -On the ESP-WROOM-32 DevKitC board, the JTAG pins are not run to a -standard connector (e.g. ARM 20-pin) and need to be manually connected -to the external programmer (e.g. a Flyswatter2): - -+------------+-----------+ -| ESP32 pin | JTAG pin | -+============+===========+ -| 3V3 | VTRef | -+------------+-----------+ -| EN | nTRST | -+------------+-----------+ -| IO14 | TMS | -+------------+-----------+ -| IO12 | TDI | -+------------+-----------+ -| GND | GND | -+------------+-----------+ -| IO13 | TCK | -+------------+-----------+ -| IO15 | TDO | -+------------+-----------+ - -Once the device is connected, you should be able to connect with (for -a DevKitC board, replace with esp32-wrover.cfg for WROVER): - -.. code-block:: console - - cd ~/esp/openocd-esp32 - src/openocd -f interface/ftdi/flyswatter2.cfg -c 'set ESP32_ONLYCPU 1' -c 'set ESP32_RTOS none' -f board/esp-wroom-32.cfg -s tcl - -The ESP32_ONLYCPU setting is critical: without it OpenOCD will present -only the "APP_CPU" via the gdbserver, and not the "PRO_CPU" on which -Zephyr is running. It's currently unexplored as to whether the CPU -can be switched at runtime or if breakpoints can be set for -either/both. - -Now you can connect to openocd with gdb and point it to the OpenOCD -gdbserver running (by default) on localhost port 3333. Note that you -must use the gdb distributed with the ESP-32 SDK. Builds off of the -FSF mainline get inexplicable protocol errors when connecting. - -.. code-block:: console - - ~/esp/xtensa-esp32-elf/bin/xtensa-esp32-elf-gdb outdir/esp32/zephyr.elf - (gdb) target remote localhost:3333 - -Further documentation can be obtained from the SoC vendor in `JTAG debugging -for ESP32`_. - -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 -********** - -.. _`ESP32 Technical Reference Manual`: https://espressif.com/sites/default/files/documentation/esp32_technical_reference_manual_en.pdf -.. _`JTAG debugging for ESP32`: http://esp-idf.readthedocs.io/en/latest/api-guides/jtag-debugging/index.html -.. _`Hardware Reference`: https://esp-idf.readthedocs.io/en/latest/hw-reference/index.html -.. _`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 -.. _`OpenOCD ESP32`: https://github.com/espressif/openocd-esp32/releases diff --git a/boards/xtensa/esp32_net/esp32_net_defconfig b/boards/xtensa/esp32_net/esp32_net_defconfig deleted file mode 100644 index 94fed73bc45..00000000000 --- a/boards/xtensa/esp32_net/esp32_net_defconfig +++ /dev/null @@ -1,15 +0,0 @@ -# SPDX-License-Identifier: Apache-2.0 - -CONFIG_BOARD_ESP32_NET=y -CONFIG_SOC_SERIES_ESP32_NET=y - -CONFIG_MAIN_STACK_SIZE=2048 - -CONFIG_CONSOLE=n -CONFIG_SERIAL=n -CONFIG_UART_CONSOLE=n - -CONFIG_GPIO=n -CONFIG_GPIO_ESP32=n - -CONFIG_I2C=n diff --git a/boards/xtensa/esp32_net/support/openocd.cfg b/boards/xtensa/esp32_net/support/openocd.cfg deleted file mode 100644 index 338e6e4e6ea..00000000000 --- a/boards/xtensa/esp32_net/support/openocd.cfg +++ /dev/null @@ -1,5 +0,0 @@ -set ESP_RTOS none -set ESP32_ONLYCPU 1 - -source [find interface/ftdi/esp32_devkitj_v1.cfg] -source [find target/esp32.cfg] diff --git a/drivers/clock_control/clock_control_esp32.c b/drivers/clock_control/clock_control_esp32.c index 52fb330d4b4..4b8b01f521e 100644 --- a/drivers/clock_control/clock_control_esp32.c +++ b/drivers/clock_control/clock_control_esp32.c @@ -9,7 +9,7 @@ #define CPU_RESET_REASON RTC_SW_CPU_RESET -#if defined(CONFIG_SOC_SERIES_ESP32) || defined(CONFIG_SOC_SERIES_ESP32_NET) +#if defined(CONFIG_SOC_SERIES_ESP32) #define DT_CPU_COMPAT cdns_tensilica_xtensa_lx6 #undef CPU_RESET_REASON #define CPU_RESET_REASON SW_CPU_RESET @@ -56,7 +56,6 @@ struct esp32_clock_config { static uint8_t const xtal_freq[] = { #if defined(CONFIG_SOC_SERIES_ESP32) || \ - defined(CONFIG_SOC_SERIES_ESP32_NET) || \ defined(CONFIG_SOC_SERIES_ESP32S3) [ESP32_CLK_XTAL_24M] = 24, [ESP32_CLK_XTAL_26M] = 26, @@ -126,7 +125,7 @@ static int clock_control_esp32_get_rate(const struct device *dev, return 0; } -#if defined(CONFIG_SOC_SERIES_ESP32) || defined(CONFIG_SOC_SERIES_ESP32_NET) +#if defined(CONFIG_SOC_SERIES_ESP32) static void esp32_clock_perip_init(void) { uint32_t common_perip_clk; diff --git a/drivers/hwinfo/hwinfo_esp32.c b/drivers/hwinfo/hwinfo_esp32.c index df4d6732112..131c3fac0c5 100644 --- a/drivers/hwinfo/hwinfo_esp32.c +++ b/drivers/hwinfo/hwinfo_esp32.c @@ -15,7 +15,7 @@ ssize_t z_impl_hwinfo_get_device_id(uint8_t *buffer, size_t length) { -#if !defined(CONFIG_SOC_SERIES_ESP32) && !defined(CONFIG_SOC_SERIES_ESP32_NET) +#if !defined(CONFIG_SOC_SERIES_ESP32) uint32_t rdata1 = sys_read32(EFUSE_RD_MAC_SPI_SYS_0_REG); uint32_t rdata2 = sys_read32(EFUSE_RD_MAC_SPI_SYS_1_REG); #else diff --git a/drivers/ipm/ipm_esp32.c b/drivers/ipm/ipm_esp32.c index cbe6e42d90f..4fc504610a6 100644 --- a/drivers/ipm/ipm_esp32.c +++ b/drivers/ipm/ipm_esp32.c @@ -54,13 +54,13 @@ IRAM_ATTR static void esp32_ipm_isr(const struct device *dev) /* clear interrupt flag */ if (core_id == 0) { -#if defined(CONFIG_SOC_SERIES_ESP32) || defined(CONFIG_SOC_SERIES_ESP32_NET) +#if defined(CONFIG_SOC_SERIES_ESP32) DPORT_WRITE_PERI_REG(DPORT_CPU_INTR_FROM_CPU_0_REG, 0); #elif defined(CONFIG_SOC_SERIES_ESP32S3) WRITE_PERI_REG(SYSTEM_CPU_INTR_FROM_CPU_0_REG, 0); #endif } else { -#if defined(CONFIG_SOC_SERIES_ESP32) || defined(CONFIG_SOC_SERIES_ESP32_NET) +#if defined(CONFIG_SOC_SERIES_ESP32) DPORT_WRITE_PERI_REG(DPORT_CPU_INTR_FROM_CPU_1_REG, 0); #elif defined(CONFIG_SOC_SERIES_ESP32S3) WRITE_PERI_REG(SYSTEM_CPU_INTR_FROM_CPU_1_REG, 0); @@ -138,7 +138,7 @@ static int esp32_ipm_send(const struct device *dev, int wait, uint32_t id, memcpy(dev_data->shm.app_cpu_shm, data, size); atomic_set(&dev_data->control->lock, ESP32_IPM_LOCK_FREE_VAL); LOG_DBG("Generating interrupt on remote CPU 1 from CPU 0"); -#if defined(CONFIG_SOC_SERIES_ESP32) || defined(CONFIG_SOC_SERIES_ESP32_NET) +#if defined(CONFIG_SOC_SERIES_ESP32) DPORT_WRITE_PERI_REG(DPORT_CPU_INTR_FROM_CPU_1_REG, DPORT_CPU_INTR_FROM_CPU_1); #elif defined(CONFIG_SOC_SERIES_ESP32S3) WRITE_PERI_REG(SYSTEM_CPU_INTR_FROM_CPU_1_REG, SYSTEM_CPU_INTR_FROM_CPU_1); @@ -148,7 +148,7 @@ static int esp32_ipm_send(const struct device *dev, int wait, uint32_t id, memcpy(dev_data->shm.pro_cpu_shm, data, size); atomic_set(&dev_data->control->lock, ESP32_IPM_LOCK_FREE_VAL); LOG_DBG("Generating interrupt on remote CPU 0 from CPU 1"); -#if defined(CONFIG_SOC_SERIES_ESP32) || defined(CONFIG_SOC_SERIES_ESP32_NET) +#if defined(CONFIG_SOC_SERIES_ESP32) DPORT_WRITE_PERI_REG(DPORT_CPU_INTR_FROM_CPU_0_REG, DPORT_CPU_INTR_FROM_CPU_0); #elif defined(CONFIG_SOC_SERIES_ESP32S3) WRITE_PERI_REG(SYSTEM_CPU_INTR_FROM_CPU_0_REG, SYSTEM_CPU_INTR_FROM_CPU_0); diff --git a/dts/xtensa/espressif/esp32/esp32_net.dtsi b/dts/xtensa/espressif/esp32/esp32_appcpu.dtsi similarity index 100% rename from dts/xtensa/espressif/esp32/esp32_net.dtsi rename to dts/xtensa/espressif/esp32/esp32_appcpu.dtsi diff --git a/samples/basic/hash_map/sample.yaml b/samples/basic/hash_map/sample.yaml index 40dec267473..9e1ee6558ca 100644 --- a/samples/basic/hash_map/sample.yaml +++ b/samples/basic/hash_map/sample.yaml @@ -16,8 +16,6 @@ common: type: one_line regex: - .*success - platform_exclude: - - esp32_net tests: diff --git a/samples/drivers/ipm/ipm_esp32/CMakeLists.txt b/samples/drivers/ipm/ipm_esp32/CMakeLists.txt index 458f0c9f256..2f764b68c81 100644 --- a/samples/drivers/ipm/ipm_esp32/CMakeLists.txt +++ b/samples/drivers/ipm/ipm_esp32/CMakeLists.txt @@ -2,7 +2,15 @@ cmake_minimum_required(VERSION 3.20.0) -set(REMOTE_ZEPHYR_DIR ${CMAKE_CURRENT_BINARY_DIR}/ipm_esp32_net-prefix/src/ipm_esp32_net-build/zephyr) +set(REMOTE_ZEPHYR_DIR ${CMAKE_CURRENT_BINARY_DIR}/ipm_esp32_appcpu-prefix/src/ipm_esp32_appcpu-build/zephyr) + +if("${BOARD}" STREQUAL "esp32_devkitc_wrover") + set(BOARD_REMOTE "esp32_devkitc_wrover_appcpu") +elseif("${BOARD}" STREQUAL "esp32_devkitc_wroom") + set(BOARD_REMOTE "esp32_devkitc_wroom_appcpu") +else() + message(FATAL_ERROR "${BOARD} was not supported for this sample") +endif() find_package(Zephyr REQUIRED HINTS $ENV{ZEPHYR_BASE}) project(ipm_esp32) @@ -13,12 +21,12 @@ target_sources(app PRIVATE src/main.c ${REMOTE_ZEPHYR_DIR}/esp32_net_firmware.c) include(ExternalProject) ExternalProject_Add( - ipm_esp32_net - SOURCE_DIR ${APPLICATION_SOURCE_DIR}/ipm_esp32_net + ipm_esp32_appcpu + SOURCE_DIR ${APPLICATION_SOURCE_DIR}/ipm_esp_appcpu INSTALL_COMMAND "" - CMAKE_CACHE_ARGS -DBOARD:STRING=esp32_net + CMAKE_CACHE_ARGS -DBOARD:STRING=${BOARD_REMOTE} BUILD_BYPRODUCTS "${REMOTE_ZEPHYR_DIR}/${KERNEL_BIN_NAME}" BUILD_ALWAYS True ) -add_dependencies(app ipm_esp32_net) +add_dependencies(app ipm_esp32_appcpu) diff --git a/samples/drivers/ipm/ipm_esp32/boards/esp32_devkitc_wroom.conf b/samples/drivers/ipm/ipm_esp32/boards/esp32_devkitc_wroom.conf new file mode 100644 index 00000000000..0bef3d481fd --- /dev/null +++ b/samples/drivers/ipm/ipm_esp32/boards/esp32_devkitc_wroom.conf @@ -0,0 +1 @@ +CONFIG_SOC_ESP32_PROCPU=y diff --git a/samples/drivers/ipm/ipm_esp32/boards/esp32_devkitc_wrover.conf b/samples/drivers/ipm/ipm_esp32/boards/esp32_devkitc_wrover.conf new file mode 100644 index 00000000000..0bef3d481fd --- /dev/null +++ b/samples/drivers/ipm/ipm_esp32/boards/esp32_devkitc_wrover.conf @@ -0,0 +1 @@ +CONFIG_SOC_ESP32_PROCPU=y diff --git a/samples/drivers/ipm/ipm_esp32/ipm_esp32_net/prj.conf b/samples/drivers/ipm/ipm_esp32/ipm_esp32_net/prj.conf deleted file mode 100644 index 82a82514edf..00000000000 --- a/samples/drivers/ipm/ipm_esp32/ipm_esp32_net/prj.conf +++ /dev/null @@ -1,3 +0,0 @@ -CONFIG_HEAP_MEM_POOL_SIZE=256 -CONFIG_IPM=y -CONFIG_KERNEL_BIN_NAME="esp32_net_firmware" diff --git a/samples/drivers/ipm/ipm_esp32/ipm_esp32_net/CMakeLists.txt b/samples/drivers/ipm/ipm_esp32/ipm_esp_appcpu/CMakeLists.txt similarity index 86% rename from samples/drivers/ipm/ipm_esp32/ipm_esp32_net/CMakeLists.txt rename to samples/drivers/ipm/ipm_esp32/ipm_esp_appcpu/CMakeLists.txt index 0292180dbf3..44114da8450 100644 --- a/samples/drivers/ipm/ipm_esp32/ipm_esp32_net/CMakeLists.txt +++ b/samples/drivers/ipm/ipm_esp32/ipm_esp_appcpu/CMakeLists.txt @@ -3,6 +3,6 @@ cmake_minimum_required(VERSION 3.20.0) find_package(Zephyr REQUIRED HINTS $ENV{ZEPHYR_BASE}) -project(ipm_esp32_net) +project(ipm_esp32_appcpu) target_sources(app PRIVATE src/main.c) diff --git a/samples/drivers/ipm/ipm_esp32/ipm_esp32_net/boards/esp32_net.overlay b/samples/drivers/ipm/ipm_esp32/ipm_esp_appcpu/boards/esp32_devkitc_wroom_appcpu.overlay similarity index 100% rename from samples/drivers/ipm/ipm_esp32/ipm_esp32_net/boards/esp32_net.overlay rename to samples/drivers/ipm/ipm_esp32/ipm_esp_appcpu/boards/esp32_devkitc_wroom_appcpu.overlay diff --git a/samples/drivers/ipm/ipm_esp32/ipm_esp_appcpu/boards/esp32_devkitc_wrover_appcpu.overlay b/samples/drivers/ipm/ipm_esp32/ipm_esp_appcpu/boards/esp32_devkitc_wrover_appcpu.overlay new file mode 100644 index 00000000000..80f7950333f --- /dev/null +++ b/samples/drivers/ipm/ipm_esp32/ipm_esp_appcpu/boards/esp32_devkitc_wrover_appcpu.overlay @@ -0,0 +1,3 @@ +&ipm0 { + status = "okay"; +}; diff --git a/samples/drivers/ipm/ipm_esp32/ipm_esp_appcpu/prj.conf b/samples/drivers/ipm/ipm_esp32/ipm_esp_appcpu/prj.conf new file mode 100644 index 00000000000..05a3de09ec1 --- /dev/null +++ b/samples/drivers/ipm/ipm_esp32/ipm_esp_appcpu/prj.conf @@ -0,0 +1,2 @@ +CONFIG_HEAP_MEM_POOL_SIZE=256 +CONFIG_IPM=y diff --git a/samples/drivers/ipm/ipm_esp32/ipm_esp32_net/src/main.c b/samples/drivers/ipm/ipm_esp32/ipm_esp_appcpu/src/main.c similarity index 100% rename from samples/drivers/ipm/ipm_esp32/ipm_esp32_net/src/main.c rename to samples/drivers/ipm/ipm_esp32/ipm_esp_appcpu/src/main.c diff --git a/samples/drivers/ipm/ipm_esp32/prj.conf b/samples/drivers/ipm/ipm_esp32/prj.conf index dfabff594df..553edc1f28b 100644 --- a/samples/drivers/ipm/ipm_esp32/prj.conf +++ b/samples/drivers/ipm/ipm_esp32/prj.conf @@ -1,3 +1,2 @@ -CONFIG_ESP32_NETWORK_CORE=y CONFIG_IPM=y CONFIG_LOG=y diff --git a/samples/subsys/ipc/rpmsg_service/CMakeLists.txt b/samples/subsys/ipc/rpmsg_service/CMakeLists.txt index 7411ab59dae..b7350d8b8b5 100644 --- a/samples/subsys/ipc/rpmsg_service/CMakeLists.txt +++ b/samples/subsys/ipc/rpmsg_service/CMakeLists.txt @@ -18,8 +18,10 @@ elseif("${BOARD}" STREQUAL "mps2_an521") set(BOARD_REMOTE "mps2_an521_remote") elseif("${BOARD}" STREQUAL "v2m_musca_b1") set(BOARD_REMOTE "v2m_musca_b1_ns") +elseif("${BOARD}" STREQUAL "esp32_devkitc_wroom") + set(BOARD_REMOTE "esp32_devkitc_wroom_appcpu") elseif("${BOARD}" STREQUAL "esp32_devkitc_wrover") - set(BOARD_REMOTE "esp32_net") + set(BOARD_REMOTE "esp32_devkitc_wrover_appcpu") elseif("${BOARD}" STREQUAL "esp32s3_devkitm") set(BOARD_REMOTE "esp32s3_devkitm_appcpu") else() diff --git a/samples/subsys/ipc/rpmsg_service/boards/esp32_devkitc_wrover.conf b/samples/subsys/ipc/rpmsg_service/boards/esp32_devkitc_wrover.conf index 5cb30cb75c0..0bef3d481fd 100644 --- a/samples/subsys/ipc/rpmsg_service/boards/esp32_devkitc_wrover.conf +++ b/samples/subsys/ipc/rpmsg_service/boards/esp32_devkitc_wrover.conf @@ -1 +1 @@ -CONFIG_ESP32_NETWORK_CORE=y +CONFIG_SOC_ESP32_PROCPU=y diff --git a/samples/subsys/ipc/rpmsg_service/remote/CMakeLists.txt b/samples/subsys/ipc/rpmsg_service/remote/CMakeLists.txt index 76fc92e6307..2ed6c70c01f 100644 --- a/samples/subsys/ipc/rpmsg_service/remote/CMakeLists.txt +++ b/samples/subsys/ipc/rpmsg_service/remote/CMakeLists.txt @@ -10,7 +10,8 @@ if("${BOARD}" STREQUAL "nrf5340dk_nrf5340_cpunet" OR "${BOARD}" STREQUAL "lpcxpresso54114_m0" OR "${BOARD}" STREQUAL "mps2_an521_remote" OR "${BOARD}" STREQUAL "v2m_musca_b1_ns" - OR "${BOARD}" STREQUAL "esp32_net" + OR "${BOARD}" STREQUAL "esp32_devkitc_wroom_appcpu" + OR "${BOARD}" STREQUAL "esp32_devkitc_wrover_appcpu" OR "${BOARD}" STREQUAL "esp32s3_devkitm_appcpu") message(STATUS "${BOARD} compile as slave in this sample") else() diff --git a/samples/subsys/ipc/rpmsg_service/remote/boards/esp32_net.overlay b/samples/subsys/ipc/rpmsg_service/remote/boards/esp32_devkitc_wrover_appcpu.overlay similarity index 100% rename from samples/subsys/ipc/rpmsg_service/remote/boards/esp32_net.overlay rename to samples/subsys/ipc/rpmsg_service/remote/boards/esp32_devkitc_wrover_appcpu.overlay diff --git a/samples/subsys/ipc/rpmsg_service/remote/boards/esp32_net.conf b/samples/subsys/ipc/rpmsg_service/remote/boards/esp32_net.conf deleted file mode 100644 index eee0f29606c..00000000000 --- a/samples/subsys/ipc/rpmsg_service/remote/boards/esp32_net.conf +++ /dev/null @@ -1 +0,0 @@ -CONFIG_KERNEL_BIN_NAME="esp32_net_firmware" diff --git a/soc/xtensa/espressif_esp32/esp32/CMakeLists.txt b/soc/xtensa/espressif_esp32/esp32/CMakeLists.txt index f850e56a9b1..c71c016a706 100644 --- a/soc/xtensa/espressif_esp32/esp32/CMakeLists.txt +++ b/soc/xtensa/espressif_esp32/esp32/CMakeLists.txt @@ -1,10 +1,14 @@ # SPDX-License-Identifier: Apache-2.0 -zephyr_sources( - soc.c - esp32-mp.c - loader.c - ) +if (CONFIG_SOC_ESP32_APPCPU) + zephyr_sources(soc_appcpu.c) +else() + zephyr_sources( + soc.c + loader.c + esp32-mp.c + ) +endif() zephyr_library_sources_ifdef(CONFIG_NEWLIB_LIBC newlib_fix.c) @@ -13,14 +17,6 @@ zephyr_library_sources_ifdef(CONFIG_GDBSTUB gdbstub.c) zephyr_library_sources_ifdef(CONFIG_PM power.c) zephyr_library_sources_ifdef(CONFIG_POWEROFF poweroff.c) -# get code-partition slot0 address -dt_nodelabel(dts_partition_path NODELABEL "slot0_partition") -dt_reg_addr(img_0_off PATH ${dts_partition_path}) - -# get code-partition boot address -dt_nodelabel(dts_partition_path NODELABEL "boot_partition") -dt_reg_addr(boot_off PATH ${dts_partition_path}) - # get flash size to use in esptool as string math(EXPR esptoolpy_flashsize "${CONFIG_FLASH_SIZE} / 0x100000") @@ -92,12 +88,36 @@ if(CONFIG_MCUBOOT OR CONFIG_BOOTLOADER_ESP_IDF) endif() -board_finalize_runner_args(esp32 "--esp-boot-address=${boot_off}") +## When building for APPCPU +if (CONFIG_SOC_ESP32_APPCPU) -board_finalize_runner_args(esp32 "--esp-app-address=${img_0_off}") + if(CONFIG_BUILD_OUTPUT_BIN) + set_property(GLOBAL APPEND PROPERTY extra_post_build_commands + COMMAND ${PYTHON_EXECUTABLE} ${ESP_IDF_PATH}/tools/esp_bin2c_array.py + ARGS -i ${CMAKE_BINARY_DIR}/zephyr/${CONFIG_KERNEL_BIN_NAME}.bin + -o ${CMAKE_BINARY_DIR}/zephyr/${CONFIG_KERNEL_BIN_NAME}.c + -a "esp32_appcpu_fw_array") + endif() + +else() + set_property(TARGET bintools PROPERTY disassembly_flag_inline_source) + + # get code-partition slot0 address + dt_nodelabel(dts_partition_path NODELABEL "slot0_partition") + dt_reg_addr(img_0_off PATH ${dts_partition_path}) + + # get code-partition boot address + dt_nodelabel(dts_partition_path NODELABEL "boot_partition") + dt_reg_addr(boot_off PATH ${dts_partition_path}) + + board_finalize_runner_args(esp32 "--esp-boot-address=${boot_off}") + board_finalize_runner_args(esp32 "--esp-app-address=${img_0_off}") +endif() if(CONFIG_MCUBOOT) set(SOC_LINKER_SCRIPT ${CMAKE_CURRENT_SOURCE_DIR}/mcuboot.ld CACHE INTERNAL "") +elseif(CONFIG_SOC_ESP32_APPCPU) + set(SOC_LINKER_SCRIPT ${CMAKE_CURRENT_SOURCE_DIR}/default_appcpu.ld CACHE INTERNAL "") else() set(SOC_LINKER_SCRIPT ${CMAKE_CURRENT_SOURCE_DIR}/default.ld CACHE INTERNAL "") endif() diff --git a/soc/xtensa/espressif_esp32/esp32/Kconfig.series b/soc/xtensa/espressif_esp32/esp32/Kconfig.series index 2189f7b2dd9..858386e4fd0 100644 --- a/soc/xtensa/espressif_esp32/esp32/Kconfig.series +++ b/soc/xtensa/espressif_esp32/esp32/Kconfig.series @@ -17,3 +17,17 @@ config SOC_SERIES_ESP32 select HAS_POWEROFF help Enable support for Espressif ESP32 + +config SOC_ESP32_PROCPU + bool "Application runs in ESP32 PROCPU (core 0)" + depends on SOC_SERIES_ESP32 + help + When this SOC is enabled, it will run application on PROCPU (core 0). It will automatically + enable AMP support by building, flashing and loading APPCPU (core 1) image if exists. + +config SOC_ESP32_APPCPU + bool "Application runs in ESP32 APPCPU (core 1)" + depends on SOC_SERIES_ESP32 + help + When this SOC is enabled, it will run application on APPCPU (core 1). It is expected that + there is another image running on PROCPU (core 0) to trigger the AMP support. diff --git a/soc/xtensa/espressif_esp32/esp32/Kconfig.soc b/soc/xtensa/espressif_esp32/esp32/Kconfig.soc index 7371c49ed94..6b530767703 100644 --- a/soc/xtensa/espressif_esp32/esp32/Kconfig.soc +++ b/soc/xtensa/espressif_esp32/esp32/Kconfig.soc @@ -13,7 +13,6 @@ config SOC_TOOLCHAIN_NAME choice SOC_PART_NUMBER prompt "ESP32 SOC/SIP Selection" - depends on SOC_SERIES_ESP32 # SoC with/without embedded flash config SOC_ESP32_D0WD_V3 @@ -56,15 +55,26 @@ choice SOC_PART_NUMBER endchoice # SOC_PART_NUMBER +config ESP32_APPCPU_IRAM + hex "ESP32 APPCPU IRAM size" + depends on SOC_ESP32_PROCPU || SOC_ESP32_APPCPU + default 0x20000 + help + Defines APPCPU IRAM area in bytes. + +config ESP32_APPCPU_DRAM + hex "ESP32 APPCPU DRAM size" + depends on SOC_ESP32_PROCPU || SOC_ESP32_APPCPU + default 0x10000 + help + Defines APPCPU DRAM area in bytes. + config ESP_SYSTEM_RTC_EXT_XTAL bool config ESP_SYSTEM_RTC_EXT_OSC bool -config ESP32_NETWORK_CORE - bool "Uses the ESP32 APP_CPU as Network dedicated core" - config ESP32_BT_RESERVE_DRAM hex "Bluetooth controller reserved RAM region" default 0xdb5c if BT @@ -73,7 +83,7 @@ config ESP32_BT_RESERVE_DRAM config ESP_HEAP_MEM_POOL_REGION_1_SIZE int "Internal DRAM region 1 mempool size" default 0 if MCUBOOT - default 1024 if ESP32_NETWORK_CORE + default 1024 if SOC_ESP32_PROCPU default 49152 help ESP32 has two banks of size 192K and 128K which can be used diff --git a/soc/xtensa/espressif_esp32/esp32/default.ld b/soc/xtensa/espressif_esp32/esp32/default.ld index 7a78c49f364..d0eb9b46f4a 100644 --- a/soc/xtensa/espressif_esp32/esp32/default.ld +++ b/soc/xtensa/espressif_esp32/esp32/default.ld @@ -18,7 +18,7 @@ #include #define RAMABLE_REGION dram0_0_seg -#ifndef CONFIG_ESP32_NETWORK_CORE +#ifndef CONFIG_SOC_ESP32_PROCPU #define RAMABLE_REGION_1 dram0_1_seg #else #define RAMABLE_REGION_1 dram0_0_seg @@ -57,7 +57,7 @@ MEMORY metadata (RX): org = 0x20, len = 0x20 ROM (RX): org = 0x40, len = FLASH_SIZE - 0x40 - #ifdef CONFIG_ESP32_NETWORK_CORE + #ifdef CONFIG_SOC_ESP32_PROCPU iram0_0_seg(RX): org = 0x40080000, len = 0x08000 #else iram0_0_seg(RX): org = 0x40080000, len = IRAM_SEG_LEN @@ -78,7 +78,7 @@ MEMORY */ dram0_0_seg(RW): org = 0x3FFB0000 + CONFIG_ESP32_BT_RESERVE_DRAM, len = 0x2c200 - CONFIG_ESP32_BT_RESERVE_DRAM - #ifdef CONFIG_ESP32_NETWORK_CORE + #ifdef CONFIG_SOC_ESP32_PROCPU dram0_shm0_seg(RW): org = 0x3FFE5230, len = 2K /* shared RAM reserved for IPM */ dram0_sem0_seg(RW): org = 0x3FFE5A30, len = 8 /* shared data reserved for IPM data header */ dram0_1_seg(RW): org = 0x3FFE5A38, len = 0K /* for AMP builds dram0_1 is reserved for network core */ diff --git a/soc/xtensa/espressif_esp32/esp32_net/linker.ld b/soc/xtensa/espressif_esp32/esp32/default_appcpu.ld similarity index 99% rename from soc/xtensa/espressif_esp32/esp32_net/linker.ld rename to soc/xtensa/espressif_esp32/esp32/default_appcpu.ld index 69a4c48ef78..a28399f57c4 100644 --- a/soc/xtensa/espressif_esp32/esp32_net/linker.ld +++ b/soc/xtensa/espressif_esp32/esp32/default_appcpu.ld @@ -1,7 +1,7 @@ /* * Copyright (c) 2016 Cadence Design Systems, Inc. * Copyright (c) 2017 Intel Corporation - * Copyright (c) 2020 Espressif Systems (Shanghai) Co., Ltd. + * Copyright (c) 2023 Espressif Systems (Shanghai) Co., Ltd. * SPDX-License-Identifier: Apache-2.0 */ diff --git a/soc/xtensa/espressif_esp32/esp32/esp32-mp.c b/soc/xtensa/espressif_esp32/esp32/esp32-mp.c index db166677f2d..7922e6f18cd 100644 --- a/soc/xtensa/espressif_esp32/esp32/esp32-mp.c +++ b/soc/xtensa/espressif_esp32/esp32/esp32-mp.c @@ -5,9 +5,9 @@ */ /* Include esp-idf headers first to avoid redefining BIT() macro */ -#include "soc/dport_reg.h" -#include "soc/gpio_periph.h" -#include "soc/rtc_periph.h" +#include +#include +#include #include #include @@ -62,7 +62,7 @@ static struct k_spinlock loglock; */ void smp_log(const char *msg) { -#ifndef CONFIG_ESP32_NETWORK_CORE +#ifndef CONFIG_SOC_ESP32_PROCPU k_spinlock_key_t key = k_spin_lock(&loglock); while (*msg) { diff --git a/soc/xtensa/espressif_esp32/esp32/soc.c b/soc/xtensa/espressif_esp32/esp32/soc.c index 7834406f37b..16df3aca645 100644 --- a/soc/xtensa/espressif_esp32/esp32/soc.c +++ b/soc/xtensa/espressif_esp32/esp32/soc.c @@ -5,7 +5,7 @@ */ /* Include esp-idf headers first to avoid redefining BIT() macro */ -#include "soc.h" +#include #include #include #include @@ -31,9 +31,9 @@ #include "esp_app_format.h" #include "hal/wdt_hal.h" -#ifndef CONFIG_SOC_SERIES_ESP32_NET +#ifndef CONFIG_SOC_ESP32_PROCPU #include "esp_clk_internal.h" -#endif /* CONFIG_SOC_SERIES_ESP32_NET */ +#endif /* CONFIG_SOC_ESP32_PROCPU */ #ifdef CONFIG_MCUBOOT #include "bootloader_init.h" @@ -43,47 +43,44 @@ extern void z_cstart(void); extern void esp_reset_reason_init(void); -#ifdef CONFIG_ESP32_NETWORK_CORE -extern const unsigned char esp32_net_fw_array[]; -extern const int esp_32_net_fw_array_size; +#ifdef CONFIG_SOC_ESP32_PROCPU +extern const unsigned char esp32_appcpu_fw_array[]; -void __attribute__((section(".iram1"))) start_esp32_net_cpu(void) +void IRAM_ATTR esp_start_appcpu(void) { - esp_image_header_t *header = (esp_image_header_t *)&esp32_net_fw_array[0]; + esp_image_header_t *header = (esp_image_header_t *)&esp32_appcpu_fw_array[0]; esp_image_segment_header_t *segment = - (esp_image_segment_header_t *)&esp32_net_fw_array[sizeof(esp_image_header_t)]; + (esp_image_segment_header_t *)&esp32_appcpu_fw_array[sizeof(esp_image_header_t)]; uint8_t *segment_payload; uint32_t entry_addr = header->entry_addr; uint32_t idx = sizeof(esp_image_header_t) + sizeof(esp_image_segment_header_t); for (int i = 0; i < header->segment_count; i++) { - segment_payload = (uint8_t *)&esp32_net_fw_array[idx]; + segment_payload = (uint8_t *)&esp32_appcpu_fw_array[idx]; if (segment->load_addr >= SOC_IRAM_LOW && segment->load_addr < SOC_IRAM_HIGH) { /* IRAM segment only accepts 4 byte access, avoid memcpy usage here */ volatile uint32_t *src = (volatile uint32_t *)segment_payload; - volatile uint32_t *dst = - (volatile uint32_t *)segment->load_addr; + volatile uint32_t *dst = (volatile uint32_t *)segment->load_addr; - for (int j = 0; j < segment->data_len/4 ; j++) { + for (int j = 0; j < segment->data_len / 4; j++) { dst[j] = src[j]; } } else if (segment->load_addr >= SOC_DRAM_LOW && - segment->load_addr < SOC_DRAM_HIGH) { + segment->load_addr < SOC_DRAM_HIGH) { - memcpy((void *)segment->load_addr, - (const void *)segment_payload, - segment->data_len); + memcpy((void *)segment->load_addr, (const void *)segment_payload, + segment->data_len); } idx += segment->data_len; - segment = (esp_image_segment_header_t *)&esp32_net_fw_array[idx]; + segment = (esp_image_segment_header_t *)&esp32_appcpu_fw_array[idx]; idx += sizeof(esp_image_segment_header_t); } esp_appcpu_start((void *)entry_addr); } -#endif /* CONFIG_ESP32_NETWORK_CORE */ +#endif /* CONFIG_SOC_ESP32_PROCPU */ /* * This is written in C rather than assembly since, during the port bring up, @@ -138,7 +135,7 @@ void __attribute__((section(".iram1"))) __esp_platform_start(void) wdt_hal_disable(&rtc_wdt_ctx); wdt_hal_write_protect_enable(&rtc_wdt_ctx); -#ifndef CONFIG_SOC_SERIES_ESP32_NET +#ifndef CONFIG_SOC_ESP32_PROCPU /* Configures the CPU clock, RTC slow and fast clocks, and performs * RTC slow clock calibration. */ @@ -147,11 +144,9 @@ void __attribute__((section(".iram1"))) __esp_platform_start(void) esp_timer_early_init(); -#if CONFIG_ESP32_NETWORK_CORE - /* start the esp32 network core before - * start zephyr - */ - start_esp32_net_cpu(); +#if CONFIG_SOC_ESP32_PROCPU + /* start the ESP32 APP CPU */ + esp_start_appcpu(); #endif #if CONFIG_ESP_SPIRAM diff --git a/soc/xtensa/espressif_esp32/esp32_net/soc.c b/soc/xtensa/espressif_esp32/esp32/soc_appcpu.c similarity index 93% rename from soc/xtensa/espressif_esp32/esp32_net/soc.c rename to soc/xtensa/espressif_esp32/esp32/soc_appcpu.c index ac53ccb7e74..a8ff116a58a 100644 --- a/soc/xtensa/espressif_esp32/esp32_net/soc.c +++ b/soc/xtensa/espressif_esp32/esp32/soc_appcpu.c @@ -5,7 +5,7 @@ */ /* Include esp-idf headers first to avoid redefining BIT() macro */ -#include "soc.h" +#include #include #include #include @@ -19,15 +19,15 @@ #include #include -#include "esp_private/system_internal.h" -#include "esp32/rom/cache.h" -#include "hal/soc_ll.h" -#include "soc/cpu.h" -#include "soc/gpio_periph.h" -#include "esp_spi_flash.h" -#include "esp_err.h" -#include "esp32/spiram.h" -#include "esp_app_format.h" +#include +#include +#include +#include +#include +#include +#include +#include +#include #include extern void z_cstart(void); diff --git a/soc/xtensa/espressif_esp32/esp32_net/CMakeLists.txt b/soc/xtensa/espressif_esp32/esp32_net/CMakeLists.txt deleted file mode 100644 index 2997e2e9990..00000000000 --- a/soc/xtensa/espressif_esp32/esp32_net/CMakeLists.txt +++ /dev/null @@ -1,23 +0,0 @@ -# SPDX-License-Identifier: Apache-2.0 - -zephyr_sources( - soc.c - ) - -zephyr_library_sources_ifdef(CONFIG_NEWLIB_LIBC newlib_fix.c) - -if(CONFIG_BUILD_OUTPUT_BIN) - set_property(GLOBAL APPEND PROPERTY extra_post_build_commands - COMMAND ${PYTHON_EXECUTABLE} ${ESP_IDF_PATH}/components/esptool_py/esptool/esptool.py - ARGS --chip esp32 elf2image --flash_mode dio --flash_freq 40m - -o ${CMAKE_BINARY_DIR}/zephyr/${CONFIG_KERNEL_BIN_NAME}.bin - ${CMAKE_BINARY_DIR}/zephyr/${CONFIG_KERNEL_BIN_NAME}.elf) - - set_property(GLOBAL APPEND PROPERTY extra_post_build_commands - COMMAND ${PYTHON_EXECUTABLE} ${ESP_IDF_PATH}/tools/esp_bin2c_array.py - ARGS -i ${CMAKE_BINARY_DIR}/zephyr/${CONFIG_KERNEL_BIN_NAME}.bin - -o ${CMAKE_BINARY_DIR}/zephyr/${CONFIG_KERNEL_BIN_NAME}.c - -a "esp32_net_fw_array") -endif() - -set(SOC_LINKER_SCRIPT ${CMAKE_CURRENT_SOURCE_DIR}/linker.ld CACHE INTERNAL "") diff --git a/soc/xtensa/espressif_esp32/esp32_net/Kconfig.defconfig.series b/soc/xtensa/espressif_esp32/esp32_net/Kconfig.defconfig.series deleted file mode 100644 index 8193bbb6149..00000000000 --- a/soc/xtensa/espressif_esp32/esp32_net/Kconfig.defconfig.series +++ /dev/null @@ -1,21 +0,0 @@ -# Copyright (c) 2023 Espressif Systems (Shanghai) Co., Ltd. -# SPDX-License-Identifier: Apache-2.0 - -if SOC_SERIES_ESP32_NET - -config SOC_SERIES - default "esp32_net" - -config MINIMAL_LIBC_OPTIMIZE_STRING_FOR_SIZE - default n - -config SYS_CLOCK_HW_CYCLES_PER_SEC - default $(dt_node_int_prop_int,/cpus/cpu@0,clock-frequency) - -config XTENSA_CCOUNT_HZ - default SYS_CLOCK_HW_CYCLES_PER_SEC - -config ESPTOOLPY_FLASHFREQ_80M - default y - -endif # SOC_ESP32_NET diff --git a/soc/xtensa/espressif_esp32/esp32_net/Kconfig.series b/soc/xtensa/espressif_esp32/esp32_net/Kconfig.series deleted file mode 100644 index 55f794f96e0..00000000000 --- a/soc/xtensa/espressif_esp32/esp32_net/Kconfig.series +++ /dev/null @@ -1,12 +0,0 @@ -# Copyright (c) 2023 Espressif Systems (Shanghai) Co., Ltd. -# SPDX-License-Identifier: Apache-2.0 - -config SOC_SERIES_ESP32_NET - bool "ESP32-NET Series" - select XTENSA - select SOC_FAMILY_ESP32 - select CLOCK_CONTROL - select DYNAMIC_INTERRUPTS - select HAS_ESPRESSIF_HAL - help - Enable support for Espressif ESP32_NET diff --git a/soc/xtensa/espressif_esp32/esp32_net/Kconfig.soc b/soc/xtensa/espressif_esp32/esp32_net/Kconfig.soc deleted file mode 100644 index 975b777b790..00000000000 --- a/soc/xtensa/espressif_esp32/esp32_net/Kconfig.soc +++ /dev/null @@ -1,78 +0,0 @@ -# Copyright (c) 2022 Espressif Systems (Shanghai) Co., Ltd. -# SPDX-License-Identifier: Apache-2.0 - -if SOC_SERIES_ESP32_NET - -config IDF_TARGET_ESP32 - bool "ESP32 as target board" - default y - -config SOC_TOOLCHAIN_NAME - string - default "espressif_esp32" - -choice SOC_PART_NUMBER - prompt "ESP32-NET SOC Selection" - depends on SOC_SERIES_ESP32_NET - - # SoC with/without embedded flash - config SOC_ESP32_NET - bool "ESP32_NET" - -endchoice # SOC_PART_NUMBER - -config ESP32_BT_RESERVE_DRAM - hex "Bluetooth controller reserved RAM region" - default 0xdb5c if BT - default 0 - -choice ESP32_UNIVERSAL_MAC_ADDRESSES - bool "Number of universally administered (by IEEE) MAC address" - default ESP32_UNIVERSAL_MAC_ADDRESSES_FOUR - help - Configure the number of universally administered (by IEEE) MAC addresses. - During initialization, MAC addresses for each network interface are generated or - derived from a single base MAC address. If the number of universal MAC addresses is four, - all four interfaces (WiFi station, WiFi softap, Bluetooth and Ethernet) receive a universally - administered MAC address. These are generated sequentially by adding 0, 1, 2 and 3 (respectively) - to the final octet of the base MAC address. If the number of universal MAC addresses is two, - only two interfaces (WiFi station and Bluetooth) receive a universally administered MAC address. - These are generated sequentially by adding 0 and 1 (respectively) to the base MAC address. - The remaining two interfaces (WiFi softap and Ethernet) receive local MAC addresses. - These are derived from the universal WiFi station and Bluetooth MAC addresses, respectively. - When using the default (Espressif-assigned) base MAC address, either setting can be used. - When using a custom universal MAC address range, the correct setting will depend on the - allocation of MAC addresses in this range (either 2 or 4 per device.) - -config ESP32_UNIVERSAL_MAC_ADDRESSES_TWO - bool "Two" - select ESP_MAC_ADDR_UNIVERSE_WIFI_STA - select ESP_MAC_ADDR_UNIVERSE_BT - -config ESP32_UNIVERSAL_MAC_ADDRESSES_FOUR - bool "Four" - select ESP_MAC_ADDR_UNIVERSE_WIFI_STA - select ESP_MAC_ADDR_UNIVERSE_WIFI_AP - select ESP_MAC_ADDR_UNIVERSE_BT - select ESP_MAC_ADDR_UNIVERSE_ETH - -endchoice # ESP32_UNIVERSAL_MAC_ADDRESSES - -config ESP_MAC_ADDR_UNIVERSE_WIFI_AP - bool - -config ESP_MAC_ADDR_UNIVERSE_WIFI_STA - bool - -config ESP_MAC_ADDR_UNIVERSE_BT - bool - -config ESP_MAC_ADDR_UNIVERSE_ETH - bool - -config ESP32_UNIVERSAL_MAC_ADDRESSES - int - default 2 if ESP32_UNIVERSAL_MAC_ADDRESSES_TWO - default 4 if ESP32_UNIVERSAL_MAC_ADDRESSES_FOUR - -endif # SOC_ESP32_NET diff --git a/soc/xtensa/espressif_esp32/esp32_net/include/_soc_inthandlers.h b/soc/xtensa/espressif_esp32/esp32_net/include/_soc_inthandlers.h deleted file mode 100644 index 63d6eef4c81..00000000000 --- a/soc/xtensa/espressif_esp32/esp32_net/include/_soc_inthandlers.h +++ /dev/null @@ -1,359 +0,0 @@ -/* - * Copyright (c) 2022 Espressif Systems (Shanghai) Co., Ltd. - * - * SPDX-License-Identifier: Apache-2.0 - */ - -#include -#include -#include - -#if !defined(XCHAL_INT0_LEVEL) || XCHAL_INT0_LEVEL != 1 -#error core-isa.h interrupt level does not match dispatcher! -#endif -#if !defined(XCHAL_INT1_LEVEL) || XCHAL_INT1_LEVEL != 1 -#error core-isa.h interrupt level does not match dispatcher! -#endif -#if !defined(XCHAL_INT2_LEVEL) || XCHAL_INT2_LEVEL != 1 -#error core-isa.h interrupt level does not match dispatcher! -#endif -#if !defined(XCHAL_INT3_LEVEL) || XCHAL_INT3_LEVEL != 1 -#error core-isa.h interrupt level does not match dispatcher! -#endif -#if !defined(XCHAL_INT4_LEVEL) || XCHAL_INT4_LEVEL != 1 -#error core-isa.h interrupt level does not match dispatcher! -#endif -#if !defined(XCHAL_INT5_LEVEL) || XCHAL_INT5_LEVEL != 1 -#error core-isa.h interrupt level does not match dispatcher! -#endif -#if !defined(XCHAL_INT6_LEVEL) || XCHAL_INT6_LEVEL != 1 -#error core-isa.h interrupt level does not match dispatcher! -#endif -#if !defined(XCHAL_INT7_LEVEL) || XCHAL_INT7_LEVEL != 1 -#error core-isa.h interrupt level does not match dispatcher! -#endif -#if !defined(XCHAL_INT8_LEVEL) || XCHAL_INT8_LEVEL != 1 -#error core-isa.h interrupt level does not match dispatcher! -#endif -#if !defined(XCHAL_INT9_LEVEL) || XCHAL_INT9_LEVEL != 1 -#error core-isa.h interrupt level does not match dispatcher! -#endif -#if !defined(XCHAL_INT10_LEVEL) || XCHAL_INT10_LEVEL != 1 -#error core-isa.h interrupt level does not match dispatcher! -#endif -#if !defined(XCHAL_INT12_LEVEL) || XCHAL_INT12_LEVEL != 1 -#error core-isa.h interrupt level does not match dispatcher! -#endif -#if !defined(XCHAL_INT13_LEVEL) || XCHAL_INT13_LEVEL != 1 -#error core-isa.h interrupt level does not match dispatcher! -#endif -#if !defined(XCHAL_INT17_LEVEL) || XCHAL_INT17_LEVEL != 1 -#error core-isa.h interrupt level does not match dispatcher! -#endif -#if !defined(XCHAL_INT18_LEVEL) || XCHAL_INT18_LEVEL != 1 -#error core-isa.h interrupt level does not match dispatcher! -#endif -#if !defined(XCHAL_INT11_LEVEL) || XCHAL_INT11_LEVEL != 3 -#error core-isa.h interrupt level does not match dispatcher! -#endif -#if !defined(XCHAL_INT15_LEVEL) || XCHAL_INT15_LEVEL != 3 -#error core-isa.h interrupt level does not match dispatcher! -#endif -#if !defined(XCHAL_INT22_LEVEL) || XCHAL_INT22_LEVEL != 3 -#error core-isa.h interrupt level does not match dispatcher! -#endif -#if !defined(XCHAL_INT23_LEVEL) || XCHAL_INT23_LEVEL != 3 -#error core-isa.h interrupt level does not match dispatcher! -#endif -#if !defined(XCHAL_INT27_LEVEL) || XCHAL_INT27_LEVEL != 3 -#error core-isa.h interrupt level does not match dispatcher! -#endif -#if !defined(XCHAL_INT29_LEVEL) || XCHAL_INT29_LEVEL != 3 -#error core-isa.h interrupt level does not match dispatcher! -#endif -#if !defined(XCHAL_INT14_LEVEL) || XCHAL_INT14_LEVEL != 7 -#error core-isa.h interrupt level does not match dispatcher! -#endif -#if !defined(XCHAL_INT16_LEVEL) || XCHAL_INT16_LEVEL != 5 -#error core-isa.h interrupt level does not match dispatcher! -#endif -#if !defined(XCHAL_INT26_LEVEL) || XCHAL_INT26_LEVEL != 5 -#error core-isa.h interrupt level does not match dispatcher! -#endif -#if !defined(XCHAL_INT31_LEVEL) || XCHAL_INT31_LEVEL != 5 -#error core-isa.h interrupt level does not match dispatcher! -#endif -#if !defined(XCHAL_INT19_LEVEL) || XCHAL_INT19_LEVEL != 2 -#error core-isa.h interrupt level does not match dispatcher! -#endif -#if !defined(XCHAL_INT20_LEVEL) || XCHAL_INT20_LEVEL != 2 -#error core-isa.h interrupt level does not match dispatcher! -#endif -#if !defined(XCHAL_INT21_LEVEL) || XCHAL_INT21_LEVEL != 2 -#error core-isa.h interrupt level does not match dispatcher! -#endif -#if !defined(XCHAL_INT24_LEVEL) || XCHAL_INT24_LEVEL != 4 -#error core-isa.h interrupt level does not match dispatcher! -#endif -#if !defined(XCHAL_INT25_LEVEL) || XCHAL_INT25_LEVEL != 4 -#error core-isa.h interrupt level does not match dispatcher! -#endif -#if !defined(XCHAL_INT28_LEVEL) || XCHAL_INT28_LEVEL != 4 -#error core-isa.h interrupt level does not match dispatcher! -#endif -#if !defined(XCHAL_INT30_LEVEL) || XCHAL_INT30_LEVEL != 4 -#error core-isa.h interrupt level does not match dispatcher! -#endif - -static inline int _xtensa_handle_one_int1(unsigned int mask) -{ - int irq; - - if (mask & 0x7f) { - if (mask & 0x7) { - if (mask & BIT(0)) { - mask = BIT(0); - irq = 0; - goto handle_irq; - } - if (mask & BIT(1)) { - mask = BIT(1); - irq = 1; - goto handle_irq; - } - if (mask & BIT(2)) { - mask = BIT(2); - irq = 2; - goto handle_irq; - } - } else { - if (mask & 0x18) { - if (mask & BIT(3)) { - mask = BIT(3); - irq = 3; - goto handle_irq; - } - if (mask & BIT(4)) { - mask = BIT(4); - irq = 4; - goto handle_irq; - } - } else { - if (mask & BIT(5)) { - mask = BIT(5); - irq = 5; - goto handle_irq; - } - if (mask & BIT(6)) { - mask = BIT(6); - irq = 6; - goto handle_irq; - } - } - } - } else { - if (mask & 0x780) { - if (mask & 0x180) { - if (mask & BIT(7)) { - mask = BIT(7); - irq = 7; - goto handle_irq; - } - if (mask & BIT(8)) { - mask = BIT(8); - irq = 8; - goto handle_irq; - } - } else { - if (mask & BIT(9)) { - mask = BIT(9); - irq = 9; - goto handle_irq; - } - if (mask & BIT(10)) { - mask = BIT(10); - irq = 10; - goto handle_irq; - } - } - } else { - if (mask & 0x3000) { - if (mask & BIT(12)) { - mask = BIT(12); - irq = 12; - goto handle_irq; - } - if (mask & BIT(13)) { - mask = BIT(13); - irq = 13; - goto handle_irq; - } - } else { - if (mask & BIT(17)) { - mask = BIT(17); - irq = 17; - goto handle_irq; - } - if (mask & BIT(18)) { - mask = BIT(18); - irq = 18; - goto handle_irq; - } - } - } - } - return 0; -handle_irq: - _sw_isr_table[irq].isr(_sw_isr_table[irq].arg); - return mask; -} - -static inline int _xtensa_handle_one_int3(unsigned int mask) -{ - int irq; - - if (mask & 0x408800) { - if (mask & BIT(11)) { - mask = BIT(11); - irq = 11; - goto handle_irq; - } - if (mask & BIT(15)) { - mask = BIT(15); - irq = 15; - goto handle_irq; - } - if (mask & BIT(22)) { - mask = BIT(22); - irq = 22; - goto handle_irq; - } - } else { - if (mask & BIT(23)) { - mask = BIT(23); - irq = 23; - goto handle_irq; - } - if (mask & BIT(27)) { - mask = BIT(27); - irq = 27; - goto handle_irq; - } - if (mask & BIT(29)) { - mask = BIT(29); - irq = 29; - goto handle_irq; - } - } - return 0; -handle_irq: - _sw_isr_table[irq].isr(_sw_isr_table[irq].arg); - return mask; -} - -static inline int _xtensa_handle_one_int7(unsigned int mask) -{ - int irq; - - if (mask & BIT(14)) { - mask = BIT(14); - irq = 14; - goto handle_irq; - } - return 0; -handle_irq: - _sw_isr_table[irq].isr(_sw_isr_table[irq].arg); - return mask; -} - -static inline int _xtensa_handle_one_int5(unsigned int mask) -{ - int irq; - - if (mask & BIT(16)) { - mask = BIT(16); - irq = 16; - goto handle_irq; - } - if (mask & BIT(26)) { - mask = BIT(26); - irq = 26; - goto handle_irq; - } - if (mask & BIT(31)) { - mask = BIT(31); - irq = 31; - goto handle_irq; - } - return 0; -handle_irq: - _sw_isr_table[irq].isr(_sw_isr_table[irq].arg); - return mask; -} - -static inline int _xtensa_handle_one_int2(unsigned int mask) -{ - int irq; - - if (mask & BIT(19)) { - mask = BIT(19); - irq = 19; - goto handle_irq; - } - if (mask & BIT(20)) { - mask = BIT(20); - irq = 20; - goto handle_irq; - } - if (mask & BIT(21)) { - mask = BIT(21); - irq = 21; - goto handle_irq; - } - return 0; -handle_irq: - _sw_isr_table[irq].isr(_sw_isr_table[irq].arg); - return mask; -} - -static inline int _xtensa_handle_one_int4(unsigned int mask) -{ - int irq; - - if (mask & 0x3000000) { - if (mask & BIT(24)) { - mask = BIT(24); - irq = 24; - goto handle_irq; - } - if (mask & BIT(25)) { - mask = BIT(25); - irq = 25; - goto handle_irq; - } - } else { - if (mask & BIT(28)) { - mask = BIT(28); - irq = 28; - goto handle_irq; - } - if (mask & BIT(30)) { - mask = BIT(30); - irq = 30; - goto handle_irq; - } - } - return 0; -handle_irq: - _sw_isr_table[irq].isr(_sw_isr_table[irq].arg); - return mask; -} - -static inline int _xtensa_handle_one_int0(unsigned int mask) -{ - return 0; -} -static inline int _xtensa_handle_one_int6(unsigned int mask) -{ - return 0; -} diff --git a/soc/xtensa/espressif_esp32/esp32_net/include/gdbstub/soc.h b/soc/xtensa/espressif_esp32/esp32_net/include/gdbstub/soc.h deleted file mode 100644 index 03e0c5df0b2..00000000000 --- a/soc/xtensa/espressif_esp32/esp32_net/include/gdbstub/soc.h +++ /dev/null @@ -1,21 +0,0 @@ -/* - * Copyright (c) 2021 Intel Corporation. - * - * SPDX-License-Identifier: Apache-2.0 - */ - -#include - -#ifndef SOC_XTENSA_ESP32_GDBSTUB_H_ -#define SOC_XTENSA_ESP32_GDBSTUB_H_ - -#ifndef ZEPHYR_INCLUDE_ARCH_XTENSA_GDBSTUB_SYS_H_ -#error "Must be included after arch/xtensa/gdbstub.h" -#endif /* ZEPHYR_INCLUDE_ARCH_XTENSA_GDBSTUB_SYS_H_ */ - -#define SOC_GDB_GPKT_BIN_SIZE 420 -#define SOC_GDB_GPKT_HEX_SIZE (SOC_GDB_GPKT_BIN_SIZE * 2) - -#define SOC_GDB_REGNO_A1 0x0001 - -#endif /* SOC_XTENSA_ESP32_GDBSTUB_H_ */ diff --git a/soc/xtensa/espressif_esp32/esp32_net/newlib_fix.c b/soc/xtensa/espressif_esp32/esp32_net/newlib_fix.c deleted file mode 100644 index b0a0efcc4e6..00000000000 --- a/soc/xtensa/espressif_esp32/esp32_net/newlib_fix.c +++ /dev/null @@ -1,22 +0,0 @@ -/* - * Copyright (c) 2019, Intel Corporation. - * - * SPDX-License-Identifier: Apache-2.0 - */ - -#include -#include -#include -#include -#include - -#include - -int __weak _gettimeofday_r(struct _reent *r, struct timeval *__tp, void *__tzp) -{ - ARG_UNUSED(r); - ARG_UNUSED(__tp); - ARG_UNUSED(__tzp); - - return -1; -} diff --git a/soc/xtensa/espressif_esp32/esp32_net/soc.h b/soc/xtensa/espressif_esp32/esp32_net/soc.h deleted file mode 100644 index 7bd495bffb8..00000000000 --- a/soc/xtensa/espressif_esp32/esp32_net/soc.h +++ /dev/null @@ -1,69 +0,0 @@ -/* - * Copyright (c) 2022 Espressif Systems (Shanghai) Co., Ltd. - * - * SPDX-License-Identifier: Apache-2.0 - */ - -#ifndef __SOC_H__ -#define __SOC_H__ -#include -#include -#include -#include -#include - -#include -#include -#include - -#include -#include - -void __esp_platform_start(void); - -static inline void esp32_set_mask32(uint32_t v, uint32_t mem_addr) -{ - sys_write32(sys_read32(mem_addr) | v, mem_addr); -} - -static inline void esp32_clear_mask32(uint32_t v, uint32_t mem_addr) -{ - sys_write32(sys_read32(mem_addr) & ~v, mem_addr); -} - -static inline uint32_t esp_core_id(void) -{ - uint32_t id; - - __asm__ volatile ( - "rsr.prid %0\n" - "extui %0,%0,13,1" : "=r" (id)); - return id; -} - -extern void esp_rom_intr_matrix_set(int cpu_no, uint32_t model_num, uint32_t intr_num); - -extern int esp_rom_gpio_matrix_in(uint32_t gpio, uint32_t signal_index, - bool inverted); -extern int esp_rom_gpio_matrix_out(uint32_t gpio, uint32_t signal_index, - bool out_inverted, - bool out_enabled_inverted); - -extern void esp_rom_uart_attach(void); -extern void esp_rom_uart_tx_wait_idle(uint8_t uart_no); -extern int esp_rom_uart_tx_one_char(uint8_t chr); -extern int esp_rom_uart_rx_one_char(uint8_t *chr); - -extern void esp_rom_Cache_Flush(int cpu); -extern void esp_rom_Cache_Read_Enable(int cpu); -extern void esp_rom_ets_set_appcpu_boot_addr(void *addr); - -/* ROM functions which read/write internal i2c control bus for PLL, APLL */ -extern uint8_t esp_rom_i2c_readReg(uint8_t block, uint8_t host_id, uint8_t reg_add); -extern void esp_rom_i2c_writeReg(uint8_t block, uint8_t host_id, uint8_t reg_add, uint8_t data); - -/* ROM information related to SPI Flash chip timing and device */ -extern esp_rom_spiflash_chip_t g_rom_flashchip; -extern uint8_t g_rom_spiflash_dummy_len_plus[]; - -#endif /* __SOC_H__ */ diff --git a/tests/subsys/mgmt/mcumgr/fs_mgmt_hash_supported/testcase.yaml b/tests/subsys/mgmt/mcumgr/fs_mgmt_hash_supported/testcase.yaml index 81f679d3c28..5d8994f8541 100644 --- a/tests/subsys/mgmt/mcumgr/fs_mgmt_hash_supported/testcase.yaml +++ b/tests/subsys/mgmt/mcumgr/fs_mgmt_hash_supported/testcase.yaml @@ -17,7 +17,6 @@ tests: platform_exclude: - arduino_giga_r1_m4 - arduino_portenta_h7_m4 - - esp32_net - lpcxpresso51u68 - nucleo_h745zi_q_m4 - stm32h747i_disco_m4 @@ -27,7 +26,6 @@ tests: platform_exclude: - arduino_giga_r1_m4 - arduino_portenta_h7_m4 - - esp32_net - lpcxpresso51u68 - nucleo_h745zi_q_m4 - stm32h747i_disco_m4 @@ -37,7 +35,6 @@ tests: platform_exclude: - arduino_giga_r1_m4 - arduino_portenta_h7_m4 - - esp32_net - lpcxpresso51u68 - nucleo_h745zi_q_m4 - stm32h747i_disco_m4 diff --git a/west.yml b/west.yml index 87e766c9e66..afd89e8f802 100644 --- a/west.yml +++ b/west.yml @@ -152,7 +152,7 @@ manifest: groups: - hal - name: hal_espressif - revision: a248460c09b6588428f6edaf5ebe312648c7360c + revision: 19d2fe44ba988781f83eb70645c3757f96fcdf1c path: modules/hal/espressif west-commands: west/west-commands.yml groups: From 9f77808678627368b84564e23e4dc63b70f30e4a Mon Sep 17 00:00:00 2001 From: Lucas Tamborrino Date: Thu, 21 Dec 2023 09:37:43 -0300 Subject: [PATCH 2182/3723] boards: xtensa: esp32_app_cpu: change bin name Change bin name to esp32_appcpu_firmware instead of esp32_net_firmware to keep naming coherence. Signed-off-by: Lucas Tamborrino --- boards/xtensa/esp32_devkitc_wroom/Kconfig.defconfig | 2 +- boards/xtensa/esp32_devkitc_wrover/Kconfig.defconfig | 2 +- boards/xtensa/esp32s3_devkitm/Kconfig.defconfig | 2 +- samples/drivers/ipm/ipm_esp32/CMakeLists.txt | 4 ++-- samples/subsys/ipc/rpmsg_service/CMakeLists.txt | 4 ++-- 5 files changed, 7 insertions(+), 7 deletions(-) diff --git a/boards/xtensa/esp32_devkitc_wroom/Kconfig.defconfig b/boards/xtensa/esp32_devkitc_wroom/Kconfig.defconfig index 0a1d0506fa9..58146fb1202 100644 --- a/boards/xtensa/esp32_devkitc_wroom/Kconfig.defconfig +++ b/boards/xtensa/esp32_devkitc_wroom/Kconfig.defconfig @@ -29,7 +29,7 @@ config HEAP_MEM_POOL_ADD_SIZE_BOARD default 4096 config KERNEL_BIN_NAME - default "esp32_net_firmware" + default "esp32_appcpu_firmware" endif # BOARD_ESP32_DEVKITC_WROOM_APPCPU diff --git a/boards/xtensa/esp32_devkitc_wrover/Kconfig.defconfig b/boards/xtensa/esp32_devkitc_wrover/Kconfig.defconfig index b98f19fce17..ec1ce4ff87e 100644 --- a/boards/xtensa/esp32_devkitc_wrover/Kconfig.defconfig +++ b/boards/xtensa/esp32_devkitc_wrover/Kconfig.defconfig @@ -27,7 +27,7 @@ config HEAP_MEM_POOL_ADD_SIZE_BOARD default 4096 config KERNEL_BIN_NAME - default "esp32_net_firmware" + default "esp32_appcpu_firmware" endif config ENTROPY_GENERATOR diff --git a/boards/xtensa/esp32s3_devkitm/Kconfig.defconfig b/boards/xtensa/esp32s3_devkitm/Kconfig.defconfig index 87c980194e2..0fdbe2af120 100644 --- a/boards/xtensa/esp32s3_devkitm/Kconfig.defconfig +++ b/boards/xtensa/esp32s3_devkitm/Kconfig.defconfig @@ -29,7 +29,7 @@ config HEAP_MEM_POOL_ADD_SIZE_BOARD def_int 4096 config KERNEL_BIN_NAME - default "esp32_net_firmware" + default "esp32_appcpu_firmware" endif config ENTROPY_GENERATOR diff --git a/samples/drivers/ipm/ipm_esp32/CMakeLists.txt b/samples/drivers/ipm/ipm_esp32/CMakeLists.txt index 2f764b68c81..e44076764dd 100644 --- a/samples/drivers/ipm/ipm_esp32/CMakeLists.txt +++ b/samples/drivers/ipm/ipm_esp32/CMakeLists.txt @@ -15,8 +15,8 @@ endif() find_package(Zephyr REQUIRED HINTS $ENV{ZEPHYR_BASE}) project(ipm_esp32) -set_source_files_properties(${REMOTE_ZEPHYR_DIR}/esp32_net_firmware.c PROPERTIES GENERATED TRUE) -target_sources(app PRIVATE src/main.c ${REMOTE_ZEPHYR_DIR}/esp32_net_firmware.c) +set_source_files_properties(${REMOTE_ZEPHYR_DIR}/esp32_appcpu_firmware.c PROPERTIES GENERATED TRUE) +target_sources(app PRIVATE src/main.c ${REMOTE_ZEPHYR_DIR}/esp32_appcpu_firmware.c) include(ExternalProject) diff --git a/samples/subsys/ipc/rpmsg_service/CMakeLists.txt b/samples/subsys/ipc/rpmsg_service/CMakeLists.txt index b7350d8b8b5..ffe26a47a81 100644 --- a/samples/subsys/ipc/rpmsg_service/CMakeLists.txt +++ b/samples/subsys/ipc/rpmsg_service/CMakeLists.txt @@ -38,8 +38,8 @@ enable_language(C ASM) target_sources(app PRIVATE src/main.c) if("${BOARD}" STREQUAL "esp32_devkitc_wrover" OR "${BOARD}" STREQUAL "esp32s3_devkitm") - set_source_files_properties(${REMOTE_ZEPHYR_DIR}/esp32_net_firmware.c PROPERTIES GENERATED TRUE) - target_sources(app PRIVATE src/main.c ${REMOTE_ZEPHYR_DIR}/esp32_net_firmware.c) + set_source_files_properties(${REMOTE_ZEPHYR_DIR}/esp32_appcpu_firmware.c PROPERTIES GENERATED TRUE) + target_sources(app PRIVATE src/main.c ${REMOTE_ZEPHYR_DIR}/esp32_appcpu_firmware.c) endif() include(ExternalProject) From 4a7ba2fa946fd2afe6480145ae4106adf99ed90f Mon Sep 17 00:00:00 2001 From: Lucas Tamborrino Date: Mon, 8 Jan 2024 10:52:36 -0300 Subject: [PATCH 2183/3723] samples: drivers: ipm: esp32: Add ESP32S3 support Add support for ESP32S3 in the IPM sample. Signed-off-by: Lucas Tamborrino --- samples/drivers/ipm/ipm_esp32/CMakeLists.txt | 2 ++ samples/drivers/ipm/ipm_esp32/boards/esp32s3_devkitm.conf | 1 + samples/drivers/ipm/ipm_esp32/boards/esp32s3_devkitm.overlay | 3 +++ .../ipm_esp_appcpu/boards/esp32s3_dekvitm_appcpu.overlay | 3 +++ 4 files changed, 9 insertions(+) create mode 100644 samples/drivers/ipm/ipm_esp32/boards/esp32s3_devkitm.conf create mode 100644 samples/drivers/ipm/ipm_esp32/boards/esp32s3_devkitm.overlay create mode 100644 samples/drivers/ipm/ipm_esp32/ipm_esp_appcpu/boards/esp32s3_dekvitm_appcpu.overlay diff --git a/samples/drivers/ipm/ipm_esp32/CMakeLists.txt b/samples/drivers/ipm/ipm_esp32/CMakeLists.txt index e44076764dd..83869676324 100644 --- a/samples/drivers/ipm/ipm_esp32/CMakeLists.txt +++ b/samples/drivers/ipm/ipm_esp32/CMakeLists.txt @@ -8,6 +8,8 @@ if("${BOARD}" STREQUAL "esp32_devkitc_wrover") set(BOARD_REMOTE "esp32_devkitc_wrover_appcpu") elseif("${BOARD}" STREQUAL "esp32_devkitc_wroom") set(BOARD_REMOTE "esp32_devkitc_wroom_appcpu") +elseif("${BOARD}" STREQUAL "esp32s3_devkitm") + set(BOARD_REMOTE "esp32s3_devkitm_appcpu") else() message(FATAL_ERROR "${BOARD} was not supported for this sample") endif() diff --git a/samples/drivers/ipm/ipm_esp32/boards/esp32s3_devkitm.conf b/samples/drivers/ipm/ipm_esp32/boards/esp32s3_devkitm.conf new file mode 100644 index 00000000000..a8ee714a955 --- /dev/null +++ b/samples/drivers/ipm/ipm_esp32/boards/esp32s3_devkitm.conf @@ -0,0 +1 @@ +CONFIG_SOC_ESP32S3_PROCPU=y diff --git a/samples/drivers/ipm/ipm_esp32/boards/esp32s3_devkitm.overlay b/samples/drivers/ipm/ipm_esp32/boards/esp32s3_devkitm.overlay new file mode 100644 index 00000000000..80f7950333f --- /dev/null +++ b/samples/drivers/ipm/ipm_esp32/boards/esp32s3_devkitm.overlay @@ -0,0 +1,3 @@ +&ipm0 { + status = "okay"; +}; diff --git a/samples/drivers/ipm/ipm_esp32/ipm_esp_appcpu/boards/esp32s3_dekvitm_appcpu.overlay b/samples/drivers/ipm/ipm_esp32/ipm_esp_appcpu/boards/esp32s3_dekvitm_appcpu.overlay new file mode 100644 index 00000000000..80f7950333f --- /dev/null +++ b/samples/drivers/ipm/ipm_esp32/ipm_esp_appcpu/boards/esp32s3_dekvitm_appcpu.overlay @@ -0,0 +1,3 @@ +&ipm0 { + status = "okay"; +}; From 43e34e95d4adab76d9919eb1d3871edd8b65dc8e Mon Sep 17 00:00:00 2001 From: Declan Snyder Date: Thu, 11 Jan 2024 15:56:06 -0600 Subject: [PATCH 2184/3723] MAINTAINERS: Add decsny as ETH/MDIO collaborator Add myself (decsny) as ethernet/mdio collaborator. I have taken an interest in ethernet and am currently maintaining and writing some ethernet/mdio drivers for NXP, and would like to use the collaborator role to monitor the zephyr activity of the ethernet/mdio subsystems. Signed-off-by: Declan Snyder --- MAINTAINERS.yml | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/MAINTAINERS.yml b/MAINTAINERS.yml index d8768d52863..b8a32451a9d 100644 --- a/MAINTAINERS.yml +++ b/MAINTAINERS.yml @@ -1164,6 +1164,8 @@ Release Notes: "Drivers: Ethernet": status: odd fixes + collaborators: + - decsny files: - drivers/ethernet/ - include/zephyr/dt-bindings/ethernet/ @@ -1389,6 +1391,8 @@ Release Notes: "Drivers: MDIO": status: odd fixes + collaborators: + - decsny files: - doc/hardware/peripherals/mdio.rst - drivers/mdio/ From fc694f39c43ec099a942bea3bc4bf8115f3b4555 Mon Sep 17 00:00:00 2001 From: Henrik Brix Andersen Date: Thu, 11 Jan 2024 21:53:33 +0100 Subject: [PATCH 2185/3723] dts: bindings: adc: nxp,vf610-adc: move binding to correct folder Move the nxp,vf610-adc.yaml binding file to the correct folder. Signed-off-by: Henrik Brix Andersen --- dts/bindings/{iio => }/adc/nxp,vf610-adc.yaml | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename dts/bindings/{iio => }/adc/nxp,vf610-adc.yaml (100%) diff --git a/dts/bindings/iio/adc/nxp,vf610-adc.yaml b/dts/bindings/adc/nxp,vf610-adc.yaml similarity index 100% rename from dts/bindings/iio/adc/nxp,vf610-adc.yaml rename to dts/bindings/adc/nxp,vf610-adc.yaml From 6a815d47e21c44fbe695df0cb3fc9dbbad4ffacf Mon Sep 17 00:00:00 2001 From: Pisit Sawangvonganan Date: Sat, 13 Jan 2024 00:31:27 +0700 Subject: [PATCH 2186/3723] drivers: gpio: correct spelling Employ a code spell checking tool to scan and correct spelling errors in all files within the drivers/gpio directory. Signed-off-by: Pisit Sawangvonganan --- drivers/gpio/gpio_bd8lb600fs.c | 2 +- drivers/gpio/gpio_efinix_sapphire.c | 6 +++--- drivers/gpio/gpio_tle9104.c | 2 +- 3 files changed, 5 insertions(+), 5 deletions(-) diff --git a/drivers/gpio/gpio_bd8lb600fs.c b/drivers/gpio/gpio_bd8lb600fs.c index 30ae851d90b..04eed39170b 100644 --- a/drivers/gpio/gpio_bd8lb600fs.c +++ b/drivers/gpio/gpio_bd8lb600fs.c @@ -86,7 +86,7 @@ static int bd8lb600fs_pin_configure(const struct device *dev, gpio_pin_t pin, gp } if (pin > 7) { - LOG_ERR("invalid pin nummber %i", pin); + LOG_ERR("invalid pin number %i", pin); return -EINVAL; } diff --git a/drivers/gpio/gpio_efinix_sapphire.c b/drivers/gpio/gpio_efinix_sapphire.c index 9456406a63c..50123731a5f 100644 --- a/drivers/gpio/gpio_efinix_sapphire.c +++ b/drivers/gpio/gpio_efinix_sapphire.c @@ -34,14 +34,14 @@ LOG_MODULE_REGISTER(gpio_efinix_sapphire); #define BSP_GPIO_INTERRUPT_HIGH_ENABLE 0x28 #define BSP_GPIO_INTERRUPT_LOW_ENABLE 0x2c -/* efinix sapphire specefic gpio config struct */ +/* efinix sapphire specific gpio config struct */ struct gpio_efinix_sapphire_cfg { uint32_t base_addr; int n_gpios; struct gpio_driver_config common; }; -/* efinix sapphire specefic gpio data struct */ +/* efinix sapphire specific gpio data struct */ struct gpio_efinix_sapphire_data { struct gpio_driver_data common; const struct device *dev; @@ -79,7 +79,7 @@ static inline void cfg_output_bit(const struct gpio_efinix_sapphire_cfg *config, } } -/* To use the controller bare minimun as IO, Peripheral has to configure, */ +/* To use the controller bare minimum as IO, Peripheral has to configure, */ /* the Output enable register, b0 : Input, b1 : Output */ static int gpio_efinix_sapphire_config(const struct device *dev, gpio_pin_t pin, gpio_flags_t flags) diff --git a/drivers/gpio/gpio_tle9104.c b/drivers/gpio/gpio_tle9104.c index 072828dec88..1d4c1545e86 100644 --- a/drivers/gpio/gpio_tle9104.c +++ b/drivers/gpio/gpio_tle9104.c @@ -249,7 +249,7 @@ static int tle9104_pin_configure(const struct device *dev, gpio_pin_t pin, gpio_ } if (pin >= TLE9104_GPIO_COUNT) { - LOG_ERR("invalid pin nummber %i", pin); + LOG_ERR("invalid pin number %i", pin); return -EINVAL; } From 6a50bbdb3a24636be7033207a0b35f36086039e9 Mon Sep 17 00:00:00 2001 From: Pisit Sawangvonganan Date: Sat, 13 Jan 2024 00:41:50 +0700 Subject: [PATCH 2187/3723] drivers: spi: correct spelling Employ a code spell checking tool to scan and correct spelling errors in all files within the drivers/spi directory. Signed-off-by: Pisit Sawangvonganan --- drivers/spi/Kconfig.mcux_lpspi | 2 +- drivers/spi/Kconfig.sam | 2 +- drivers/spi/spi_b91.c | 2 +- drivers/spi/spi_opentitan.c | 2 +- drivers/spi/spi_xec_qmspi_ldma.c | 8 ++++---- 5 files changed, 8 insertions(+), 8 deletions(-) diff --git a/drivers/spi/Kconfig.mcux_lpspi b/drivers/spi/Kconfig.mcux_lpspi index 8f5a0a3bbd1..bad4191fbdc 100644 --- a/drivers/spi/Kconfig.mcux_lpspi +++ b/drivers/spi/Kconfig.mcux_lpspi @@ -22,7 +22,7 @@ config SPI_MCUX_LPSPI_DMA if SPI_RTIO config SPI_MCUX_RTIO_SQ_SIZE - int "number of avialable submission queue entries" + int "number of available submission queue entries" default 8 # sensible default that covers most common spi transactions help when rtio is use with spi each driver holds a context with which blocking diff --git a/drivers/spi/Kconfig.sam b/drivers/spi/Kconfig.sam index 6423390a024..1a7e0b5916b 100644 --- a/drivers/spi/Kconfig.sam +++ b/drivers/spi/Kconfig.sam @@ -22,7 +22,7 @@ config SPI_SAM_DMA if SPI_RTIO config SPI_SAM_RTIO_SQ_SIZE - int "Number of avialable submission queue entries" + int "Number of available submission queue entries" default 8 # Sensible default that covers most common spi transactions help When RTIO is use with SPI each driver holds a context with which blocking diff --git a/drivers/spi/spi_b91.c b/drivers/spi/spi_b91.c index ed250eaa62b..f3f1202df29 100644 --- a/drivers/spi/spi_b91.c +++ b/drivers/spi/spi_b91.c @@ -228,7 +228,7 @@ static void spi_b91_txrx(const struct device *dev, uint32_t len) BM_SET(reg_spi_fifo_state(cfg->peripheral_id), FLD_SPI_RXF_CLR); } - /* wait fot SPI is ready */ + /* wait for SPI is ready */ while (spi_is_busy(cfg->peripheral_id)) { }; diff --git a/drivers/spi/spi_opentitan.c b/drivers/spi/spi_opentitan.c index e8d7b8dc926..c3ed64c4a2e 100644 --- a/drivers/spi/spi_opentitan.c +++ b/drivers/spi/spi_opentitan.c @@ -169,7 +169,7 @@ static void spi_opentitan_xfer(const struct device *dev, const bool gpio_cs_cont } /* Keep CS asserted if another Tx segment remains or if two more Rx - * segements remain (because we will handle one Rx segment after the + * segments remain (because we will handle one Rx segment after the * forthcoming transaction). */ if (ctx->tx_count > 0 || ctx->rx_count > 1) { diff --git a/drivers/spi/spi_xec_qmspi_ldma.c b/drivers/spi/spi_xec_qmspi_ldma.c index ab48e49c095..a95a28fc176 100644 --- a/drivers/spi/spi_xec_qmspi_ldma.c +++ b/drivers/spi/spi_xec_qmspi_ldma.c @@ -215,7 +215,7 @@ static int qmspi_set_frequency(struct spi_qmspi_data *qdata, struct qmspi_regs * * SPI signalling mode: CPOL and CPHA * CPOL = 0 is clock idles low, 1 is clock idle high * CPHA = 0 Transmitter changes data on trailing of preceding clock cycle. - * Receiver samples data on leading edge of clock cyle. + * Receiver samples data on leading edge of clock cycle. * 1 Transmitter changes data on leading edge of current clock cycle. * Receiver samples data on the trailing edge of clock cycle. * SPI Mode nomenclature: @@ -475,7 +475,7 @@ static inline int qmspi_xfr_cm_init(const struct device *dev, * RX data discard for certain SPI command protocols using dual/quad I/O. * 1. Get largest contiguous data size from SPI context. * 2. If the SPI TX context has a non-zero length configure Local-DMA TX - * channel 1 for contigous data size. If TX context has valid buffer + * channel 1 for contiguous data size. If TX context has valid buffer * configure channel to use context buffer with address increment. * If the TX buffer pointer is NULL interpret byte length as the number * of clocks to generate with output line(s) tri-stated. NOTE: The controller @@ -487,7 +487,7 @@ static inline int qmspi_xfr_cm_init(const struct device *dev, * For example, if I/O lines is 4 (quad) meaning 4 bits per clock and the * user wants 7 clocks then the number of bit units is 4 * 7 = 28. * 3. If instead, the SPI RX context has a non-zero length configure Local-DMA - * RX channel 1 for the contigous data size. If RX context has a valid + * RX channel 1 for the contiguous data size. If RX context has a valid * buffer configure channel to use buffer with address increment else * configure channel for driver data temporary buffer without address * increment. @@ -696,7 +696,7 @@ static int qmspi_xfr_start_async(const struct device *dev, const struct spi_buf_ return 0; } -/* Wrapper to start asynchronous (interrupts enabled) SPI transction */ +/* Wrapper to start asynchronous (interrupts enabled) SPI transaction */ static int qmspi_xfr_async(const struct device *dev, const struct spi_config *config, const struct spi_buf_set *tx_bufs, From b4567fa5519f1a943ed34cff41241cdffbcd5521 Mon Sep 17 00:00:00 2001 From: Pisit Sawangvonganan Date: Sat, 13 Jan 2024 00:34:18 +0700 Subject: [PATCH 2188/3723] drivers: serial: correct spelling Employ a code spell checking tool to scan and correct spelling errors in all files within the drivers/serial directory. Signed-off-by: Pisit Sawangvonganan --- drivers/serial/Kconfig.emul | 2 +- drivers/serial/uart_cdns.h | 2 +- drivers/serial/uart_esp32.c | 4 ++-- drivers/serial/uart_hostlink.c | 2 +- drivers/serial/uart_ql_usbserialport_s3b.h | 4 ++-- drivers/serial/uart_rzt2m.c | 2 +- drivers/serial/uart_sedi.c | 2 +- drivers/serial/uart_stm32.c | 4 ++-- 8 files changed, 11 insertions(+), 11 deletions(-) diff --git a/drivers/serial/Kconfig.emul b/drivers/serial/Kconfig.emul index b5362eb79ee..e61130a13c7 100644 --- a/drivers/serial/Kconfig.emul +++ b/drivers/serial/Kconfig.emul @@ -20,7 +20,7 @@ config UART_EMUL_WORK_Q_STACK_SIZE default 2048 config UART_EMUL_WORK_Q_PRIORITY - int "UART emulator work queue tread priority" + int "UART emulator work queue thread priority" default 1 endif # UART_EMUL diff --git a/drivers/serial/uart_cdns.h b/drivers/serial/uart_cdns.h index 70c8e5d6220..d9e1769df5f 100644 --- a/drivers/serial/uart_cdns.h +++ b/drivers/serial/uart_cdns.h @@ -122,7 +122,7 @@ struct uart_cdns_regs { volatile uint32_t flow_ctrl_delay; /* Flow Control Delay Register */ volatile uint32_t rpwr; /* IR Minimum Received Pulse Register */ volatile uint32_t tpwr; /* IR TRansmitted Pulse Width Register */ - volatile uint32_t tx_fifo_trigger_level; /* Transmiter FIFO trigger level */ + volatile uint32_t tx_fifo_trigger_level; /* Transmitter FIFO trigger level */ volatile uint32_t rbrs; /* RX FIFO Byte Status Register */ }; diff --git a/drivers/serial/uart_esp32.c b/drivers/serial/uart_esp32.c index 8a7a2f336af..be5d2487e13 100644 --- a/drivers/serial/uart_esp32.c +++ b/drivers/serial/uart_esp32.c @@ -603,7 +603,7 @@ static int uart_esp32_async_tx_abort(const struct device *dev) err = dma_stop(config->dma_dev, config->tx_dma_channel); if (err) { - LOG_ERR("Error stoping Tx DMA (%d)", err); + LOG_ERR("Error stopping Tx DMA (%d)", err); goto unlock; } @@ -838,7 +838,7 @@ static int uart_esp32_async_rx_disable(const struct device *dev) err = dma_stop(config->dma_dev, config->rx_dma_channel); if (err) { - LOG_ERR("Error stoping Rx DMA (%d)", err); + LOG_ERR("Error stopping Rx DMA (%d)", err); goto unlock; } diff --git a/drivers/serial/uart_hostlink.c b/drivers/serial/uart_hostlink.c index a129c67d30f..396422b6e19 100644 --- a/drivers/serial/uart_hostlink.c +++ b/drivers/serial/uart_hostlink.c @@ -254,7 +254,7 @@ static void hl_static_send(size_t payload_used) * It is responsibility of debugger to set this back to HL_NOADDRESS * after receiving the packet. * Please note that we don't wait here because some implementations - * use hl_blockedPeek() function as a signal that we send a messege. + * use hl_blockedPeek() function as a signal that we send a message. */ hl_write32(&__HOSTLINK__.hdr.target2host_addr, buf_addr); diff --git a/drivers/serial/uart_ql_usbserialport_s3b.h b/drivers/serial/uart_ql_usbserialport_s3b.h index c4397ff6d85..47899d2ebb8 100644 --- a/drivers/serial/uart_ql_usbserialport_s3b.h +++ b/drivers/serial/uart_ql_usbserialport_s3b.h @@ -34,8 +34,8 @@ #define USBSERIAL_TX_FIFO_16_TO_31 (0x0B) /* 1011 Room for 16 to 31 */ #define USBSERIAL_TX_FIFO_8_TO_15 (0x0C) /* 1100 Room for 8 to 15 */ #define USBSERIAL_TX_FIFO_4_TO_7 (0x0D) /* 1101 Room for 4 to 7 */ -#define USBSERIAL_TX_FIFO_GE_2 (0x0E) /* 1110 Room for atleast 2 */ -#define USBSERIAL_TX_FIFO_GE_1 (0x0F) /* 1111 Room for atleast 1 */ +#define USBSERIAL_TX_FIFO_GE_2 (0x0E) /* 1110 Room for at least 2 */ +#define USBSERIAL_TX_FIFO_GE_1 (0x0F) /* 1111 Room for at least 1 */ struct fpga_usbserial_regs { uint32_t device_id; diff --git a/drivers/serial/uart_rzt2m.c b/drivers/serial/uart_rzt2m.c index e4ebe251f21..0e40ff78712 100644 --- a/drivers/serial/uart_rzt2m.c +++ b/drivers/serial/uart_rzt2m.c @@ -376,7 +376,7 @@ static int rzt2m_uart_init(const struct device *dev) config->irq_config_func(dev); #endif /* CONFIG_UART_INTERRUPT_DRIVEN */ - /* Start trasmitter and receiver. */ + /* Start transmitter and receiver. */ *CCR0(config->base) |= (CCR0_MASK_TE | CCR0_MASK_RE); while (!(*CCR0(config->base) & CCR0_MASK_RE)) { } diff --git a/drivers/serial/uart_sedi.c b/drivers/serial/uart_sedi.c index 6bbecb407cf..74fcc4a5040 100644 --- a/drivers/serial/uart_sedi.c +++ b/drivers/serial/uart_sedi.c @@ -92,7 +92,7 @@ struct uart_sedi_config_info { /* Specifies the baudrate for the uart instance. */ uint32_t baud_rate; - /* Specifies the port line contorl settings */ + /* Specifies the port line control settings */ sedi_uart_lc_t line_ctrl; struct k_mutex *mutex; diff --git a/drivers/serial/uart_stm32.c b/drivers/serial/uart_stm32.c index 638343528fe..c785c1e4f89 100644 --- a/drivers/serial/uart_stm32.c +++ b/drivers/serial/uart_stm32.c @@ -567,7 +567,7 @@ static int uart_stm32_configure(const struct device *dev, LL_USART_Disable(config->usart); - /* Set basic parmeters, such as data-/stop-bit, parity, and baudrate */ + /* Set basic parameters, such as data-/stop-bit, parity, and baudrate */ uart_stm32_parameters_set(dev, cfg); LL_USART_Enable(config->usart); @@ -1913,7 +1913,7 @@ static int uart_stm32_registers_configure(const struct device *dev) LL_USART_SetTransferDirection(config->usart, LL_USART_DIRECTION_TX_RX); - /* Set basic parmeters, such as data-/stop-bit, parity, and baudrate */ + /* Set basic parameters, such as data-/stop-bit, parity, and baudrate */ uart_stm32_parameters_set(dev, uart_cfg); /* Enable the single wire / half-duplex mode */ From 0a50cb9179123700f873b62bbaf836fc8d0bf713 Mon Sep 17 00:00:00 2001 From: Anas Nashif Date: Wed, 10 Jan 2024 21:46:18 -0500 Subject: [PATCH 2189/3723] ci: pr stats: define elasticsearch index as a repo variable Add flexibility to change and modify index using a variable. Signed-off-by: Anas Nashif --- .github/workflows/stats_merged_prs.yml | 2 +- scripts/ci/stats/merged_prs.py | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/stats_merged_prs.yml b/.github/workflows/stats_merged_prs.yml index a3d5efc7fd0..db1b6f37e5d 100644 --- a/.github/workflows/stats_merged_prs.yml +++ b/.github/workflows/stats_merged_prs.yml @@ -18,7 +18,7 @@ jobs: GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} ELASTICSEARCH_KEY: ${{ secrets.ELASTICSEARCH_KEY }} ELASTICSEARCH_SERVER: "https://elasticsearch.zephyrproject.io:443" - PR_STAT_INDEX: "pr-test-7" + PR_STAT_ES_INDEX: ${{ vars.PR_STAT_ES_INDEX }} run: | pip3 install pygithub elasticsearch python3 ./scripts/ci/stats/merged_prs.py --pull-request ${{ github.event.pull_request.number }} --repo ${{ github.repository }} diff --git a/scripts/ci/stats/merged_prs.py b/scripts/ci/stats/merged_prs.py index 7a9ffa41981..87c84990de9 100755 --- a/scripts/ci/stats/merged_prs.py +++ b/scripts/ci/stats/merged_prs.py @@ -147,7 +147,7 @@ def main(): ) try: - index = os.environ['PR_STAT_INDEX'] + index = os.environ['PR_STAT_ES_INDEX'] bulk(es, gendata(json_list, index)) except KeyError as e: print(f"Error: {e} not set.") From 7fedc81666f34d5948a05adcacc6f644fb85332f Mon Sep 17 00:00:00 2001 From: Anas Nashif Date: Wed, 10 Jan 2024 21:22:14 -0500 Subject: [PATCH 2190/3723] ci: merged_pr stats: fix a bug an minor tweaks We are not setting the review rule value correctly and default to 'no' for all prs, even if they were correctly reviewed by assignees. Minor other cleanups. Signed-off-by: Anas Nashif --- scripts/ci/stats/merged_prs.py | 225 +++++++++++++++++---------------- 1 file changed, 118 insertions(+), 107 deletions(-) diff --git a/scripts/ci/stats/merged_prs.py b/scripts/ci/stats/merged_prs.py index 87c84990de9..eb0a15c026d 100755 --- a/scripts/ci/stats/merged_prs.py +++ b/scripts/ci/stats/merged_prs.py @@ -13,6 +13,7 @@ from elasticsearch import Elasticsearch from elasticsearch.helpers import bulk from datetime import timedelta +import pprint date_format = '%Y-%m-%d %H:%M:%S' @@ -21,8 +22,11 @@ def parse_args() -> argparse.Namespace: parser = argparse.ArgumentParser( formatter_class=argparse.RawDescriptionHelpFormatter, allow_abbrev=False) - parser.add_argument('--pull-request', required=True, help='pull request number', type=int) - parser.add_argument('--repo', required=True, help='github repo') + parser.add_argument('--pull-request', help='pull request number', type=int) + parser.add_argument('--range', help='execute based on a date range, for example 2023-01-01..2023-01-05') + parser.add_argument('--repo', help='github repo', default='zephyrproject-rtos/zephyr') + parser.add_argument('--es-index', help='Elasticsearch index') + parser.add_argument('-y','--dry-run', action="store_true", help='dry run, do not upload data') return parser.parse_args() @@ -33,6 +37,90 @@ def gendata(data, index): "_source": t } +def process_pr(pr): + reviews = pr.get_reviews() + print(f'#{pr.number}: {pr.title} - {pr.comments} Comments, reviews: {reviews.totalCount}, {len(pr.assignees)} Assignees (Updated {pr.updated_at})') + assignee_reviews = 0 + prj = {} + + assignees = [] + labels = [] + for label in pr.labels: + labels.append(label.name) + + reviewers = set() + for review in reviews: + # get list of all approved reviews + if review.user and review.state == 'APPROVED': + reviewers.add(review.user.login) + + for assignee in pr.assignees: + # list assignees for later checks + assignees.append(assignee.login) + if assignee.login in reviewers: + assignee_reviews += 1 + + if assignee_reviews > 0 or pr.merged_by.login in assignees: + # in case of assignee reviews or if PR was merged by an assignee + prj['review_rule'] = "yes" + elif not pr.assignees or \ + (pr.user.login in assignees and len(assignees) == 1) or \ + ('Trivial' in labels or 'Hotfix' in labels): + # in case where no assignees set or if submitter is the only assignee + # or in case of trivial or hotfixes + prj['review_rule'] = "na" + else: + # everything else + prj['review_rule'] = "no" + + + # calculate time the PR was in review, hours and business days. + delta = pr.closed_at - pr.created_at + deltah = delta.total_seconds() / 3600 + prj['hours_open'] = deltah + + dates = (pr.created_at + timedelta(idx + 1) for idx in range((pr.closed_at - pr.created_at).days)) + + # Get number of business days per the guidelines, we need at least 2. + business_days = sum(1 for day in dates if day.weekday() < 5) + prj['business_days_open'] = business_days + + # less than 2 business days ... + if business_days < 2 and not ('Trivial' in labels or 'Hotfix' in labels) or \ + deltah < 4 and 'Trivial' in labels: + prj['time_rule'] = "no" + else: + prj['time_rule'] = "yes" + + # This is all data we get easily though the Github API and serves as the basis + # for displaying some trends and metrics. + # Data can be extended in the future if we find more information that + # is useful through the API + + prj['nr'] = pr.number + prj['url'] = pr.url + prj['title'] = pr.title + prj['comments'] = pr.comments + prj['reviews'] = reviews.totalCount + prj['assignees'] = assignees + prj['updated'] = pr.updated_at.strftime("%Y-%m-%d %H:%M:%S") + prj['created'] = pr.created_at.strftime("%Y-%m-%d %H:%M:%S") + prj['closed'] = pr.closed_at.strftime("%Y-%m-%d %H:%M:%S") + prj['merged_by'] = pr.merged_by.login + prj['submitted_by'] = pr.user.login + prj['changed_files'] = pr.changed_files + prj['additions'] = pr.additions + prj['deletions'] = pr.deletions + prj['commits'] = pr.commits + # The branch we are targeting. main vs release branches. + prj['base'] = pr.base.ref + + # list all reviewers + prj['reviewers'] = list(reviewers) + prj['labels'] = labels + + return prj + def main(): args = parse_args() token = os.environ.get('GITHUB_TOKEN') @@ -46,112 +134,35 @@ def main(): if args.pull_request: pr = gh_repo.get_pull(args.pull_request) - - reviews = pr.get_reviews() - print(f'#{pr.number}: {pr.title} - {pr.comments} Comments, reviews: {reviews.totalCount}, {len(pr.assignees)} Assignees (Updated {pr.updated_at})') - assignee_reviews = 0 - reviewers = set() - prj = {} - for r in reviews: - if r.user and r.state == 'APPROVED': - reviewers.add(r.user.login) - if pr.assignees and r.user: - for assignee in pr.assignees: - if r.user.login == assignee.login: - assignee_reviews = assignee_reviews + 1 - # was reviewed at least by one assignee - prj['reviewed_by_assignee'] = "yes" - - # This is all data we get easily though the Github API and serves as the basis - # for displaying some trends and metrics. - # Data can be extended in the future if we find more information that - # is useful through the API - - prj['nr'] = pr.number - prj['url'] = pr.url - prj['title'] = pr.title - prj['comments'] = pr.comments - prj['reviews'] = reviews.totalCount - prj['assignees'] = len(pr.assignees) - prj['updated'] = pr.updated_at.strftime("%Y-%m-%d %H:%M:%S") - prj['created'] = pr.created_at.strftime("%Y-%m-%d %H:%M:%S") - prj['closed'] = pr.closed_at.strftime("%Y-%m-%d %H:%M:%S") - prj['merged_by'] = pr.merged_by.login - prj['submitted_by'] = pr.user.login - prj['changed_files'] = pr.changed_files - prj['additions'] = pr.additions - prj['deletions'] = pr.deletions - prj['commits'] = pr.commits - # The branch we are targeting. main vs release branches. - prj['base'] = pr.base.ref - - ll = [] - for l in pr.labels: - ll.append(l.name) - prj['labels'] = ll - - # take first assignee, otherwise we have no assignees and this rule is not applicable - if pr.assignee: - prj['assignee'] = pr.assignee.login - else: - prj['assignee'] = "none" - prj['reviewed_by_assignee'] = "na" - prj['review_rule'] = "na" - - # go through all assignees and check if anyone has approved and reset assignee to the one who approved - for assignee in pr.assignees: - if assignee.login in reviewers: - prj['assignee'] = assignee.login - elif assignee.login == pr.user.login: - prj['reviewed_by_assignee'] = "yes" - - - # list assignees for later checks - assignees = [a.login for a in pr.assignees] - - # Deal with exceptions when assignee approval is not needed. - if 'Trivial' in ll or 'Hotfix' in ll: - prj['review_rule'] = "yes" - elif pr.merged_by.login in assignees: - prj['review_rule'] = "yes" - else: - prj['review_rule'] = "no" - - prj['assignee_reviews'] = assignee_reviews - - delta = pr.closed_at - pr.created_at - deltah = delta.total_seconds() / 3600 - prj['hours_open'] = deltah - - dates = (pr.created_at + timedelta(idx + 1) for idx in range((pr.closed_at - pr.created_at).days)) - - # Get number of business days per the guidelines, we need at least 2. - res = sum(1 for day in dates if day.weekday() < 5) - - if res < 2 and not ('Trivial' in ll or 'Hotfix' in ll): - prj['time_rule'] = False - elif deltah < 4 and 'Trivial' in ll: - prj['time_rule'] = False - else: - prj['time_rule'] = True - prj['reviewers'] = list(reviewers) - + prj = process_pr(pr) json_list.append(prj) - - - # Send data over to elasticsearch. - es = Elasticsearch( - [os.environ['ELASTICSEARCH_SERVER']], - api_key=os.environ['ELASTICSEARCH_KEY'], - verify_certs=False - ) - - try: - index = os.environ['PR_STAT_ES_INDEX'] - bulk(es, gendata(json_list, index)) - except KeyError as e: - print(f"Error: {e} not set.") - print(json_list) + elif args.range: + query = f'repo:{args.repo} merged:{args.range} is:pr is:closed sort:updated-desc base:main' + prs = gh.search_issues(query=f'{query}') + for _pr in prs: + pr = gh_repo.get_pull(_pr.number) + prj = process_pr(pr) + json_list.append(prj) + + if json_list and not args.dry_run: + # Send data over to elasticsearch. + es = Elasticsearch( + [os.environ['ELASTICSEARCH_SERVER']], + api_key=os.environ['ELASTICSEARCH_KEY'], + verify_certs=False + ) + + try: + if args.es_index: + index = args.es_index + else: + index = os.environ['PR_STAT_ES_INDEX'] + bulk(es, gendata(json_list, index)) + except KeyError as e: + print(f"Error: {e} not set.") + print(json_list) + if args.dry_run: + pprint.pprint(json_list) if __name__ == "__main__": main() From 5fc96ff9d70f7828b5eada42de04c521cd0904e1 Mon Sep 17 00:00:00 2001 From: Daniel Leung Date: Fri, 12 Jan 2024 11:40:20 -0800 Subject: [PATCH 2191/3723] sys: atomic_c: skip syscall tracing This skips syscall tracing on atomic_c.h, as the compiler does not like "({ ... tracing code ... })" and complains: error: expected identifier or '(' before '{' token Even though there is already a '(' before '{'. Signed-off-by: Daniel Leung --- include/zephyr/sys/atomic_c.h | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+) diff --git a/include/zephyr/sys/atomic_c.h b/include/zephyr/sys/atomic_c.h index 0ea6e6dfa34..f1e23caf362 100644 --- a/include/zephyr/sys/atomic_c.h +++ b/include/zephyr/sys/atomic_c.h @@ -72,7 +72,26 @@ __syscall atomic_val_t atomic_nand(atomic_t *target, atomic_val_t value); #endif #ifdef CONFIG_ATOMIC_OPERATIONS_C + +#ifndef DISABLE_SYSCALL_TRACING +/* Skip defining macros of atomic_*() for syscall tracing. + * Compiler does not like "({ ... tracing code ... })" and complains + * + * error: expected identifier or '(' before '{' token + * + * ... even though there is a '(' before '{'. + */ +#define DISABLE_SYSCALL_TRACING +#define _REMOVE_DISABLE_SYSCALL_TRACING +#endif + #include + +#ifdef _REMOVE_DISABLE_SYSCALL_TRACING +#undef DISABLE_SYSCALL_TRACING +#undef _REMOVE_DISABLE_SYSCALL_TRACING +#endif + #endif #endif /* ZEPHYR_INCLUDE_SYS_ATOMIC_C_H_ */ From 0a8d03b95f8473c8e21687adc5b26e87e4ea6c5d Mon Sep 17 00:00:00 2001 From: Daniel Mangum Date: Sat, 13 Jan 2024 12:29:06 -0500 Subject: [PATCH 2192/3723] docs: posix: fix typo in description Fixes a minor typo in description of the POSIX architecture. Signed-off-by: Daniel Mangum --- boards/posix/doc/arch_soc.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/boards/posix/doc/arch_soc.rst b/boards/posix/doc/arch_soc.rst index 3e548139f4b..fcc6734d2a6 100644 --- a/boards/posix/doc/arch_soc.rst +++ b/boards/posix/doc/arch_soc.rst @@ -237,7 +237,7 @@ section. instruction executes is just some of it; Emulating peripherals accurately is another side. -This native port compiles your code directly for the host architectture +This native port compiles your code directly for the host architecture (typically x86), with no instrumentation or monitoring code. Your code executes directly in the host CPU. That is, your code executes just as fast as it possibly can. From bff6054cb850a50f118b22c7d95b02a158292b38 Mon Sep 17 00:00:00 2001 From: Manuel Schappacher Date: Wed, 20 Dec 2023 15:19:03 +0100 Subject: [PATCH 2193/3723] net: gptp: Always use GM PRIO root system id for announce messages A problem occurred while running PTP on a multi-port target (RENESAS RZT2M) with two ports enabled. Announce messages on the switched devices master port always contained local clock information instead information from received on the slave port from the better GM clock. Depending on the BMCA config this turned into having more than one GM in the system. Sending always the locally stored GM information helped to overcome this issue. Signed-off-by: Manuel Schappacher --- subsys/net/l2/ethernet/gptp/gptp_messages.c | 18 +++--------------- 1 file changed, 3 insertions(+), 15 deletions(-) diff --git a/subsys/net/l2/ethernet/gptp/gptp_messages.c b/subsys/net/l2/ethernet/gptp/gptp_messages.c index 780c1dedb6f..d56b679ab7a 100644 --- a/subsys/net/l2/ethernet/gptp/gptp_messages.c +++ b/subsys/net/l2/ethernet/gptp/gptp_messages.c @@ -489,6 +489,7 @@ struct net_pkt *gptp_prepare_announce(int port) struct net_if *iface; struct net_pkt *pkt; struct gptp_hdr *hdr; + struct gptp_priority_vector *gm_prio; NET_ASSERT((port >= GPTP_PORT_START) && (port <= GPTP_PORT_END)); global_ds = GPTP_GLOBAL_DS(); @@ -538,25 +539,12 @@ struct net_pkt *gptp_prepare_announce(int port) ann->cur_utc_offset = htons(global_ds->current_utc_offset); ann->time_source = global_ds->time_source; + gm_prio = &global_ds->gm_priority; switch (GPTP_PORT_BMCA_DATA(port)->info_is) { case GPTP_INFO_IS_MINE: - ann->root_system_id.grand_master_prio1 = default_ds->priority1; - ann->root_system_id.grand_master_prio2 = default_ds->priority2; - - ann->root_system_id.clk_quality.clock_accuracy = - default_ds->clk_quality.clock_accuracy; - ann->root_system_id.clk_quality.clock_class = default_ds->clk_quality.clock_class; - ann->root_system_id.clk_quality.offset_scaled_log_var = - htons(default_ds->clk_quality.offset_scaled_log_var); - - memcpy(&ann->root_system_id.grand_master_id, - default_ds->clk_id, - GPTP_CLOCK_ID_LEN); - break; case GPTP_INFO_IS_RECEIVED: memcpy(&ann->root_system_id, - &GPTP_PORT_BMCA_DATA(port)-> - master_priority.root_system_id, + &gm_prio->root_system_id, sizeof(struct gptp_root_system_identity)); break; default: From b184fc3a62edd5c54aef38e836a452e2bdf01a2f Mon Sep 17 00:00:00 2001 From: Dmitrii Golovanov Date: Wed, 27 Dec 2023 21:56:15 +0100 Subject: [PATCH 2194/3723] posix: sched: Add CONFIG_POSIX_PRIORITY_SCHEDULING Add `CONFIG_POSIX_PRIORITY_SCHEDULING` Kconfig option to select APIs from PSE53 `_POSIX_PRIORITY_SCHEDULING` option group. Signed-off-by: Dmitrii Golovanov --- doc/services/portability/posix/aep/index.rst | 2 +- doc/services/portability/posix/conformance/index.rst | 2 +- lib/posix/CMakeLists.txt | 2 +- lib/posix/Kconfig | 1 + lib/posix/Kconfig.sched | 11 +++++++++++ tests/posix/common/prj.conf | 1 + 6 files changed, 16 insertions(+), 3 deletions(-) create mode 100644 lib/posix/Kconfig.sched diff --git a/doc/services/portability/posix/aep/index.rst b/doc/services/portability/posix/aep/index.rst index 55a841dd565..5e28fa10397 100644 --- a/doc/services/portability/posix/aep/index.rst +++ b/doc/services/portability/posix/aep/index.rst @@ -52,7 +52,7 @@ Minimal Realtime System Profile (PSE51) _POSIX_THREAD_CPUTIME, -1, _POSIX_THREAD_PRIO_INHERIT, 200809L, :kconfig:option:`CONFIG_PTHREAD_MUTEX` _POSIX_THREAD_PRIO_PROTECT, -1, - _POSIX_THREAD_PRIORITY_SCHEDULING, -1, + _POSIX_THREAD_PRIORITY_SCHEDULING, -1, :kconfig:option:`CONFIG_POSIX_PRIORITY_SCHEDULING` (will fail with ``ENOSYS``:ref:`†`) _POSIX_THREAD_SPORADIC_SERVER, -1, _POSIX_TIMEOUTS, 200809L, :kconfig:option:`CONFIG_PTHREAD_IPC` _POSIX_TIMERS, 200809L, :kconfig:option:`CONFIG_POSIX_CLOCK` diff --git a/doc/services/portability/posix/conformance/index.rst b/doc/services/portability/posix/conformance/index.rst index 53f3113ca68..0c38955337e 100644 --- a/doc/services/portability/posix/conformance/index.rst +++ b/doc/services/portability/posix/conformance/index.rst @@ -87,7 +87,7 @@ POSIX System Interfaces :ref:`_POSIX_MESSAGE_PASSING`, 200809L, :kconfig:option:`CONFIG_POSIX_MQUEUE` _POSIX_MONOTONIC_CLOCK, 200809L, :kconfig:option:`CONFIG_POSIX_CLOCK` _POSIX_PRIORITIZED_IO, -1, - :ref:`_POSIX_PRIORITY_SCHEDULING`, -1, :kconfig:option:`CONFIG_PTHREAD` + :ref:`_POSIX_PRIORITY_SCHEDULING`, -1, :kconfig:option:`CONFIG_POSIX_PRIORITY_SCHEDULING` (will fail with ``ENOSYS``:ref:`†`) _POSIX_RAW_SOCKETS, 200809L, :kconfig:option:`CONFIG_NET_SOCKETS` _POSIX_SHARED_MEMORY_OBJECTS, -1, _POSIX_SPAWN, -1, diff --git a/lib/posix/CMakeLists.txt b/lib/posix/CMakeLists.txt index e73c78d40e4..21d25580aac 100644 --- a/lib/posix/CMakeLists.txt +++ b/lib/posix/CMakeLists.txt @@ -54,7 +54,7 @@ zephyr_library_sources_ifdef(CONFIG_PTHREAD_KEY key.c) zephyr_library_sources_ifdef(CONFIG_PTHREAD_MUTEX mutex.c) zephyr_library_sources_ifdef(CONFIG_PTHREAD pthread.c) zephyr_library_sources_ifdef(CONFIG_PTHREAD_IPC rwlock.c) -zephyr_library_sources_ifdef(CONFIG_PTHREAD_IPC sched.c) +zephyr_library_sources_ifdef(CONFIG_POSIX_PRIORITY_SCHEDULING sched.c) zephyr_library_sources_ifdef(CONFIG_PTHREAD_IPC semaphore.c) zephyr_library_sources_ifdef(CONFIG_PTHREAD_SPINLOCK spinlock.c) diff --git a/lib/posix/Kconfig b/lib/posix/Kconfig index 3fd01313474..3202c13b7dd 100644 --- a/lib/posix/Kconfig +++ b/lib/posix/Kconfig @@ -49,6 +49,7 @@ source "lib/posix/Kconfig.limits" source "lib/posix/Kconfig.mqueue" source "lib/posix/Kconfig.mutex" source "lib/posix/Kconfig.pthread" +source "lib/posix/Kconfig.sched" source "lib/posix/Kconfig.semaphore" source "lib/posix/Kconfig.signal" source "lib/posix/Kconfig.spinlock" diff --git a/lib/posix/Kconfig.sched b/lib/posix/Kconfig.sched new file mode 100644 index 00000000000..62e7541c8e1 --- /dev/null +++ b/lib/posix/Kconfig.sched @@ -0,0 +1,11 @@ +# Copyright (c) 2023 Intel Corporation +# +# SPDX-License-Identifier: Apache-2.0 + +config POSIX_PRIORITY_SCHEDULING + bool "_POSIX_PRIORITY_SCHEDULING API support" + default y if PTHREAD + default y if POSIX_API + depends on PTHREAD + help + This enables POSIX scheduling APIs (_POSIX_PRIORITY_SCHEDULING). diff --git a/tests/posix/common/prj.conf b/tests/posix/common/prj.conf index 6c0b9153b6a..67dab816dc7 100644 --- a/tests/posix/common/prj.conf +++ b/tests/posix/common/prj.conf @@ -4,6 +4,7 @@ CONFIG_MAX_PTHREAD_COUNT=10 CONFIG_ZTEST=y CONFIG_SEM_VALUE_MAX=32767 CONFIG_POSIX_MQUEUE=y +CONFIG_POSIX_PRIORITY_SCHEDULING=y CONFIG_HEAP_MEM_POOL_SIZE=4096 CONFIG_MAX_THREAD_BYTES=4 CONFIG_THREAD_NAME=y From 68d1a524172c24594cddc1381504b5134542a8b1 Mon Sep 17 00:00:00 2001 From: Dmitrii Golovanov Date: Wed, 3 Jan 2024 19:59:08 +0100 Subject: [PATCH 2195/3723] posix: sched: Implement get APIs for scheduling parameters Initial implementation of `sched_getparam()` and `sched_getscheduler()` POSIX APIs as a part of PSE53 `_POSIX_PRIORITY_SCHEDULING` option group. Both functions are actually placeholders and just return `ENOSYS` since Zephyr does not yet support processes or process scheduling. Signed-off-by: Dmitrii Golovanov --- arch/posix/include/posix_cheats.h | 2 ++ include/zephyr/posix/sched.h | 7 ++++++- lib/posix/sched.c | 31 ++++++++++++++++++++++++++++++- tests/posix/common/src/pthread.c | 19 ++++++++++++++++++- tests/posix/headers/src/sched_h.c | 4 ++-- 5 files changed, 58 insertions(+), 5 deletions(-) diff --git a/arch/posix/include/posix_cheats.h b/arch/posix/include/posix_cheats.h index 88a68b9fd49..770dab9aac6 100644 --- a/arch/posix/include/posix_cheats.h +++ b/arch/posix/include/posix_cheats.h @@ -151,6 +151,8 @@ extern "C" int _posix_zephyr_main(void); #define sched_yield(...) zap_sched_yield(__VA_ARGS__) #define sched_get_priority_min(...) zap_sched_get_priority_min(__VA_ARGS__) #define sched_get_priority_max(...) zap_sched_get_priority_max(__VA_ARGS__) +#define sched_getparam(...) zap_sched_getparam(__VA_ARGS__) +#define sched_getscheduler(...) zap_sched_getscheduler(__VA_ARGS__) /* Sleep */ #define sleep(...) zap_sleep(__VA_ARGS__) diff --git a/include/zephyr/posix/sched.h b/include/zephyr/posix/sched.h index 10cfc666c66..b7431fc3342 100644 --- a/include/zephyr/posix/sched.h +++ b/include/zephyr/posix/sched.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2018 Intel Corporation + * Copyright (c) 2018-2023 Intel Corporation * * SPDX-License-Identifier: Apache-2.0 */ @@ -8,6 +8,8 @@ #include +#include "posix_types.h" + #ifdef __cplusplus extern "C" { #endif @@ -46,6 +48,9 @@ static inline int sched_yield(void) int sched_get_priority_min(int policy); int sched_get_priority_max(int policy); +int sched_getparam(pid_t pid, struct sched_param *param); +int sched_getscheduler(pid_t pid); + #ifdef __cplusplus } #endif diff --git a/lib/posix/sched.c b/lib/posix/sched.c index 4f71badded9..d5fa1d81ad4 100644 --- a/lib/posix/sched.c +++ b/lib/posix/sched.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2018 Intel Corporation + * Copyright (c) 2018-2023 Intel Corporation * * SPDX-License-Identifier: Apache-2.0 */ @@ -41,3 +41,32 @@ int sched_get_priority_max(int policy) errno = EINVAL; return -1; } + +/** + * @brief Get scheduling parameters + * + * See IEEE 1003.1 + */ +int sched_getparam(pid_t pid, struct sched_param *param) +{ + ARG_UNUSED(pid); + ARG_UNUSED(param); + + errno = ENOSYS; + + return -1; +} + +/** + * @brief Get scheduling policy + * + * See IEEE 1003.1 + */ +int sched_getscheduler(pid_t pid) +{ + ARG_UNUSED(pid); + + errno = ENOSYS; + + return -1; +} diff --git a/tests/posix/common/src/pthread.c b/tests/posix/common/src/pthread.c index 7cf2405c2b4..6210da0a020 100644 --- a/tests/posix/common/src/pthread.c +++ b/tests/posix/common/src/pthread.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2018 Intel Corporation + * Copyright (c) 2018-2023 Intel Corporation * * SPDX-License-Identifier: Apache-2.0 */ @@ -644,6 +644,23 @@ ZTEST(posix_apis, test_pthread_descriptor_leak) } } +ZTEST(posix_apis, test_sched_getparam) +{ + struct sched_param param; + int rc = sched_getparam(0, ¶m); + int err = errno; + + zassert_true((rc == -1 && err == ENOSYS)); +} + +ZTEST(posix_apis, test_sched_getscheduler) +{ + int rc = sched_getscheduler(0); + int err = errno; + + zassert_true((rc == -1 && err == ENOSYS)); +} + ZTEST(posix_apis, test_sched_policy) { /* diff --git a/tests/posix/headers/src/sched_h.c b/tests/posix/headers/src/sched_h.c index fb4f2de2688..fba7d17704c 100644 --- a/tests/posix/headers/src/sched_h.c +++ b/tests/posix/headers/src/sched_h.c @@ -30,8 +30,8 @@ ZTEST(posix_headers, test_sched_h) zassert_not_null(sched_get_priority_max); zassert_not_null(sched_get_priority_min); - /* zassert_not_null(sched_getparam); */ /* not implemented */ - /* zassert_not_null(sched_getscheduler); */ /* not implemented */ + zassert_not_null(sched_getparam); + zassert_not_null(sched_getscheduler); /* zassert_not_null(sched_rr_get_interval); */ /* not implemented */ From b819b51fe7d0a52443b1d6e6d5840233b3999451 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Krzysztof=20Chru=C5=9Bci=C5=84ski?= Date: Tue, 2 Jan 2024 10:30:40 +0100 Subject: [PATCH 2196/3723] logging: Add support for runtime filtering in frontend MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit So far frontend supported only compile time filtering. Adding support for runtime filtering. From runtime filtering perspective frontend is treated similar to any other backend but since it is a singleton it has fixed ID. Signed-off-by: Krzysztof Chruściński --- include/zephyr/logging/log_core.h | 7 ++++ include/zephyr/logging/log_ctrl.h | 22 +++++++++- subsys/logging/log_core.c | 7 +++- subsys/logging/log_mgmt.c | 70 +++++++++++++++++++++++-------- subsys/logging/log_msg.c | 31 +++++++++++--- 5 files changed, 113 insertions(+), 24 deletions(-) diff --git a/include/zephyr/logging/log_core.h b/include/zephyr/logging/log_core.h index b18fe00c09e..7321b569f34 100644 --- a/include/zephyr/logging/log_core.h +++ b/include/zephyr/logging/log_core.h @@ -378,6 +378,13 @@ static inline char z_log_minimal_level_to_char(int level) /** @brief Number of slots in one word. */ #define LOG_FILTERS_NUM_OF_SLOTS (32 / LOG_FILTER_SLOT_SIZE) +/** @brief Maximum number of backends supported when runtime filtering is enabled. */ +#define LOG_FILTERS_MAX_BACKENDS \ + (LOG_FILTERS_NUM_OF_SLOTS - (1 + IS_ENABLED(CONFIG_LOG_FRONTEND))) + +/** @brief Slot reserved for the frontend. Last slot is used. */ +#define LOG_FRONTEND_SLOT_ID (LOG_FILTERS_NUM_OF_SLOTS - 1) + /** @brief Slot mask. */ #define LOG_FILTER_SLOT_MASK (BIT(LOG_FILTER_SLOT_SIZE) - 1U) diff --git a/include/zephyr/logging/log_ctrl.h b/include/zephyr/logging/log_ctrl.h index 6b8a5ec0414..9e5e3e3c077 100644 --- a/include/zephyr/logging/log_ctrl.h +++ b/include/zephyr/logging/log_ctrl.h @@ -156,7 +156,7 @@ uint32_t log_filter_get(struct log_backend const *const backend, /** * @brief Set filter on given source for the provided backend. * - * @param backend Backend instance. NULL for all backends. + * @param backend Backend instance. NULL for all backends (and frontend). * @param domain_id ID of the domain. * @param source_id Source (module or instance) ID. * @param level Severity level. @@ -168,6 +168,26 @@ __syscall uint32_t log_filter_set(struct log_backend const *const backend, uint32_t domain_id, int16_t source_id, uint32_t level); +/** + * @brief Get source filter for the frontend. + * + * @param source_id Source (module or instance) ID. + * @param runtime True for runtime filter or false for compiled in. + * + * @return Severity level. + */ +uint32_t log_frontend_filter_get(int16_t source_id, bool runtime); + +/** + * @brief Set filter on given source for the frontend. + * + * @param source_id Source (module or instance) ID. + * @param level Severity level. + * + * @return Actual level set which may be limited by compiled level. + */ +__syscall uint32_t log_frontend_filter_set(int16_t source_id, uint32_t level); + /** * * @brief Enable backend with initial maximum filtering level. diff --git a/subsys/logging/log_core.c b/subsys/logging/log_core.c index 3539556ac25..3a2e397a603 100644 --- a/subsys/logging/log_core.c +++ b/subsys/logging/log_core.c @@ -241,6 +241,11 @@ void log_core_init(void) if (IS_ENABLED(CONFIG_LOG_FRONTEND)) { log_frontend_init(); + + for (uint16_t s = 0; s < log_src_cnt_get(0); s++) { + log_frontend_filter_set(s, CONFIG_LOG_MAX_LEVEL); + } + if (IS_ENABLED(CONFIG_LOG_FRONTEND_ONLY)) { return; } @@ -292,7 +297,7 @@ static uint32_t z_log_init(bool blocking, bool can_sleep) return 0; } - __ASSERT_NO_MSG(log_backend_count_get() < LOG_FILTERS_NUM_OF_SLOTS); + __ASSERT_NO_MSG(log_backend_count_get() < LOG_FILTERS_MAX_BACKENDS); if (atomic_inc(&initialized) != 0) { return 0; diff --git a/subsys/logging/log_mgmt.c b/subsys/logging/log_mgmt.c index 6336e4a8385..190c452a2d6 100644 --- a/subsys/logging/log_mgmt.c +++ b/subsys/logging/log_mgmt.c @@ -412,9 +412,23 @@ static void set_runtime_filter(uint8_t backend_id, uint8_t domain_id, } } -uint32_t z_impl_log_filter_set(struct log_backend const *const backend, - uint32_t domain_id, int16_t source_id, - uint32_t level) +static uint32_t filter_get(uint8_t id, uint32_t domain_id, int16_t source_id, bool runtime) +{ + __ASSERT_NO_MSG(source_id < log_src_cnt_get(domain_id)); + + if (IS_ENABLED(CONFIG_LOG_RUNTIME_FILTERING) && runtime) { + if (source_id < 0) { + return LOG_LEVEL_DBG; + } + + return LOG_FILTER_SLOT_GET(get_dynamic_filter(domain_id, source_id), id); + } + + return log_compiled_level_get(domain_id, source_id); +} + + +uint32_t filter_set(int id, uint32_t domain_id, int16_t source_id, uint32_t level) { if (!IS_ENABLED(CONFIG_LOG_RUNTIME_FILTERING)) { return log_compiled_level_get(domain_id, source_id); @@ -423,12 +437,20 @@ uint32_t z_impl_log_filter_set(struct log_backend const *const backend, __ASSERT_NO_MSG(source_id < log_src_cnt_get(domain_id)); - if (backend == NULL) { + if (id < 0) { uint32_t max = 0U; + size_t backend_cnt; + + if (IS_ENABLED(CONFIG_LOG_FRONTEND)) { + max = filter_set(LOG_FRONTEND_SLOT_ID, domain_id, source_id, level); + if (IS_ENABLED(CONFIG_LOG_FRONTEND_ONLY)) { + return max; + } + } - STRUCT_SECTION_FOREACH(log_backend, iter_backend) { - uint32_t current = log_filter_set(iter_backend, - domain_id, source_id, level); + STRUCT_SECTION_COUNT(log_backend, &backend_cnt); + for (size_t i = 0; i < backend_cnt; i++) { + uint32_t current = filter_set(i, domain_id, source_id, level); max = MAX(current, max); } @@ -436,13 +458,27 @@ uint32_t z_impl_log_filter_set(struct log_backend const *const backend, return max; } - level = MIN(level, MAX(log_filter_get(backend, domain_id, source_id, false), + level = MIN(level, MAX(filter_get(id, domain_id, source_id, false), CONFIG_LOG_OVERRIDE_LEVEL)); - set_runtime_filter(log_backend_id_get(backend), domain_id, source_id, level); + set_runtime_filter(id, domain_id, source_id, level); return level; } +uint32_t z_impl_log_filter_set(struct log_backend const *const backend, + uint32_t domain_id, int16_t source_id, + uint32_t level) +{ + int id = (backend == NULL) ? -1 : log_backend_id_get(backend); + + return filter_set(id, domain_id, source_id, level); +} + +uint32_t z_impl_log_frontend_filter_set(int16_t source_id, uint32_t level) +{ + return filter_set(LOG_FRONTEND_SLOT_ID, Z_LOG_LOCAL_DOMAIN_ID, source_id, level); +} + #ifdef CONFIG_USERSPACE uint32_t z_vrfy_log_filter_set(struct log_backend const *const backend, uint32_t domain_id, @@ -541,18 +577,18 @@ void log_backend_disable(struct log_backend const *const backend) uint32_t log_filter_get(struct log_backend const *const backend, uint32_t domain_id, int16_t source_id, bool runtime) { - __ASSERT_NO_MSG(source_id < log_src_cnt_get(domain_id)); + int id = (backend == NULL) ? -1 : log_backend_id_get(backend); - if (IS_ENABLED(CONFIG_LOG_RUNTIME_FILTERING) && runtime) { - if (source_id < 0) { - return LOG_LEVEL_DBG; - } + return filter_get(id, domain_id, source_id, runtime); +} - return LOG_FILTER_SLOT_GET(get_dynamic_filter(domain_id, source_id), - log_backend_id_get(backend)); +uint32_t log_frontend_filter_get(int16_t source_id, bool runtime) +{ + if (!IS_ENABLED(CONFIG_LOG_FRONTEND)) { + return LOG_LEVEL_NONE; } - return log_compiled_level_get(domain_id, source_id); + return filter_get(LOG_FRONTEND_SLOT_ID, Z_LOG_LOCAL_DOMAIN_ID, source_id, runtime); } void z_log_links_initiate(void) diff --git a/subsys/logging/log_msg.c b/subsys/logging/log_msg.c index da9dffdc62e..f69c96dd7b0 100644 --- a/subsys/logging/log_msg.c +++ b/subsys/logging/log_msg.c @@ -51,6 +51,27 @@ void z_log_msg_finalize(struct log_msg *msg, const void *source, z_log_msg_commit(msg); } +static bool frontend_runtime_filtering(const void *source, uint32_t level) +{ + if (!IS_ENABLED(CONFIG_LOG_RUNTIME_FILTERING)) { + return true; + } + + /* If only frontend is used and log got here it means that it was accepted. */ + if (IS_ENABLED(CONFIG_LOG_FRONTEND_ONLY)) { + return true; + } + + if (level == LOG_LEVEL_NONE) { + return true; + } + + struct log_source_dynamic_data *dynamic = (struct log_source_dynamic_data *)source; + uint32_t f_level = LOG_FILTER_SLOT_GET(&dynamic->filters, LOG_FRONTEND_SLOT_ID); + + return level <= f_level; +} + /** @brief Create a log message using simplified method. * * Simple log message has 0-2 32 bit word arguments so creating cbprintf package @@ -102,7 +123,7 @@ static void z_log_msg_simple_create(const void *source, uint32_t level, uint32_t void z_impl_z_log_msg_simple_create_0(const void *source, uint32_t level, const char *fmt) { - if (IS_ENABLED(CONFIG_LOG_FRONTEND)) { + if (IS_ENABLED(CONFIG_LOG_FRONTEND) && frontend_runtime_filtering(source, level)) { if (IS_ENABLED(CONFIG_LOG_FRONTEND_OPT_API)) { log_frontend_simple_0(source, level, fmt); } else { @@ -141,7 +162,7 @@ void z_impl_z_log_msg_simple_create_0(const void *source, uint32_t level, const void z_impl_z_log_msg_simple_create_1(const void *source, uint32_t level, const char *fmt, uint32_t arg) { - if (IS_ENABLED(CONFIG_LOG_FRONTEND)) { + if (IS_ENABLED(CONFIG_LOG_FRONTEND) && frontend_runtime_filtering(source, level)) { if (IS_ENABLED(CONFIG_LOG_FRONTEND_OPT_API)) { log_frontend_simple_1(source, level, fmt, arg); } else { @@ -181,7 +202,7 @@ void z_impl_z_log_msg_simple_create_1(const void *source, uint32_t level, void z_impl_z_log_msg_simple_create_2(const void *source, uint32_t level, const char *fmt, uint32_t arg0, uint32_t arg1) { - if (IS_ENABLED(CONFIG_LOG_FRONTEND)) { + if (IS_ENABLED(CONFIG_LOG_FRONTEND) && frontend_runtime_filtering(source, level)) { if (IS_ENABLED(CONFIG_LOG_FRONTEND_OPT_API)) { log_frontend_simple_2(source, level, fmt, arg0, arg1); } else { @@ -223,7 +244,7 @@ void z_impl_z_log_msg_static_create(const void *source, const struct log_msg_desc desc, uint8_t *package, const void *data) { - if (IS_ENABLED(CONFIG_LOG_FRONTEND)) { + if (IS_ENABLED(CONFIG_LOG_FRONTEND) && frontend_runtime_filtering(source, desc.level)) { log_frontend_msg(source, desc, package, data); } @@ -324,7 +345,7 @@ void z_log_msg_runtime_vcreate(uint8_t domain_id, const void *source, __ASSERT_NO_MSG(plen >= 0); } - if (IS_ENABLED(CONFIG_LOG_FRONTEND)) { + if (IS_ENABLED(CONFIG_LOG_FRONTEND) && frontend_runtime_filtering(source, desc.level)) { log_frontend_msg(source, desc, pkg, data); } From c9e2975a967ce04e3d0ff7449a1e332079b8c054 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Krzysztof=20Chru=C5=9Bci=C5=84ski?= Date: Tue, 2 Jan 2024 10:33:07 +0100 Subject: [PATCH 2197/3723] logging: log_cmds: Add support for frontend runtime filtering MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Add support for controlling runtime filtering for frontend. Signed-off-by: Krzysztof Chruściński --- subsys/logging/log_cmds.c | 63 ++++++++++++++++++++++++++++++++------- 1 file changed, 52 insertions(+), 11 deletions(-) diff --git a/subsys/logging/log_cmds.c b/subsys/logging/log_cmds.c index 372d28ee0aa..79e4457184f 100644 --- a/subsys/logging/log_cmds.c +++ b/subsys/logging/log_cmds.c @@ -11,6 +11,9 @@ #include #include +#define FRONTEND_NAME frontend +#define FRONTEND_STR STRINGIFY(frontend) + typedef int (*log_backend_cmd_t)(const struct shell *sh, const struct log_backend *backend, size_t argc, @@ -76,6 +79,14 @@ static int shell_backend_cmd_execute(const struct shell *sh, * be found at -1 (log backend command). */ char const *name = argv[-1]; + size_t slen = sizeof(FRONTEND_STR); + + if (IS_ENABLED(CONFIG_LOG_FRONTEND) && + strncmp(name, FRONTEND_STR, slen) == 0) { + func(sh, NULL, argc, argv); + return 0; + } + const struct log_backend *backend = backend_find(name); if (backend != NULL) { @@ -84,6 +95,7 @@ static int shell_backend_cmd_execute(const struct shell *sh, shell_error(sh, "Invalid backend: %s", name); return -ENOEXEC; } + return 0; } @@ -96,7 +108,7 @@ static int log_status(const struct shell *sh, uint32_t dynamic_lvl; uint32_t compiled_lvl; - if (!log_backend_is_active(backend)) { + if (backend && !log_backend_is_active(backend)) { shell_warn(sh, "Logs are halted!"); } @@ -106,10 +118,13 @@ static int log_status(const struct shell *sh, "----------------------------------------------------------\r\n"); for (int16_t i = 0U; i < modules_cnt; i++) { - dynamic_lvl = log_filter_get(backend, Z_LOG_LOCAL_DOMAIN_ID, - i, true); - compiled_lvl = log_filter_get(backend, Z_LOG_LOCAL_DOMAIN_ID, - i, false); + if (IS_ENABLED(CONFIG_LOG_FRONTEND) && !backend) { + dynamic_lvl = log_frontend_filter_get(i, true); + compiled_lvl = log_frontend_filter_get(i, false); + } else { + dynamic_lvl = log_filter_get(backend, Z_LOG_LOCAL_DOMAIN_ID, i, true); + compiled_lvl = log_filter_get(backend, Z_LOG_LOCAL_DOMAIN_ID, i, false); + } shell_fprintf(sh, SHELL_NORMAL, "%-40s | %-7s | %s\r\n", log_source_name_get(Z_LOG_LOCAL_DOMAIN_ID, i), @@ -163,16 +178,20 @@ static void filters_set(const struct shell *sh, bool all = argc ? false : true; int cnt = all ? log_src_cnt_get(Z_LOG_LOCAL_DOMAIN_ID) : argc; - if (!backend->cb->active) { + if (backend && !backend->cb->active) { shell_warn(sh, "Backend not active."); } for (i = 0; i < cnt; i++) { id = all ? i : module_id_get(argv[i]); if (id >= 0) { - uint32_t set_lvl = log_filter_set(backend, - Z_LOG_LOCAL_DOMAIN_ID, - id, level); + uint32_t set_lvl; + + if (IS_ENABLED(CONFIG_LOG_FRONTEND) && !backend) { + set_lvl = log_frontend_filter_set(id, level); + } else { + set_lvl = log_filter_set(backend, Z_LOG_LOCAL_DOMAIN_ID, id, level); + } if (set_lvl != level) { const char *name; @@ -290,7 +309,13 @@ static int log_halt(const struct shell *sh, size_t argc, char **argv) { - log_backend_deactivate(backend); + if (backend || !IS_ENABLED(CONFIG_LOG_FRONTEND)) { + log_backend_deactivate(backend); + return 0; + } + + shell_warn(sh, "Not supported for frontend"); + return 0; } @@ -316,7 +341,13 @@ static int log_go(const struct shell *sh, size_t argc, char **argv) { - log_backend_activate(backend, backend->cb->ctx); + if (backend || !IS_ENABLED(CONFIG_LOG_FRONTEND)) { + log_backend_activate(backend, backend->cb->ctx); + return 0; + } + + shell_warn(sh, "Not supported for frontend"); + return 0; } @@ -351,6 +382,11 @@ static int cmd_log_backends_list(const struct shell *sh, backend->cb->id); } + + if (IS_ENABLED(CONFIG_LOG_FRONTEND)) { + shell_print(sh, "%s", FRONTEND_STR); + } + return 0; } @@ -409,12 +445,15 @@ static void backend_name_get(size_t idx, struct shell_static_entry *entry) STRUCT_SECTION_COUNT(log_backend, §ion_count); + if (idx < section_count) { struct log_backend *backend = NULL; STRUCT_SECTION_GET(log_backend, idx, &backend); __ASSERT_NO_MSG(backend != NULL); entry->syntax = backend->name; + } else if (IS_ENABLED(CONFIG_LOG_FRONTEND) && (idx == section_count)) { + entry->syntax = FRONTEND_STR; } } @@ -438,6 +477,8 @@ SHELL_STATIC_SUBCMD_SET_CREATE( cmd_log_self_status), SHELL_COND_CMD(CONFIG_LOG_MODE_DEFERRED, mem, NULL, "Logger memory usage", cmd_log_mem), + SHELL_COND_CMD(CONFIG_LOG_FRONTEND, FRONTEND_NAME, &sub_log_backend, + "Frontend control", NULL), SHELL_SUBCMD_SET_END); SHELL_CMD_REGISTER(log, &sub_log_stat, "Commands for controlling logger", From dc99da6a4f6abc9b9c8a9f9218e54b30779faa74 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Krzysztof=20Chru=C5=9Bci=C5=84ski?= Date: Tue, 2 Jan 2024 10:35:56 +0100 Subject: [PATCH 2198/3723] tests: logging: log_api: Extend to cover frontend runtime filtering MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Extend test to cover runtime filtering for frontend. Signed-off-by: Krzysztof Chruściński --- tests/subsys/logging/log_api/src/main.c | 123 ++++++++++++--------- tests/subsys/logging/log_api/testcase.yaml | 26 +++++ 2 files changed, 97 insertions(+), 52 deletions(-) diff --git a/tests/subsys/logging/log_api/src/main.c b/tests/subsys/logging/log_api/src/main.c index 4026ab5ca91..7771dd8b766 100644 --- a/tests/subsys/logging/log_api/src/main.c +++ b/tests/subsys/logging/log_api/src/main.c @@ -219,6 +219,11 @@ ZTEST(test_log_api, test_log_various_messages) #undef TEST_MSG_1 } +static bool frontend_only(void) +{ + return NO_BACKENDS || IS_ENABLED(CONFIG_LOG_FRONTEND_ONLY); +} + /* * Test is using 2 backends and runtime filtering is enabled. After first call * filtering for backend2 is reduced to warning. It is expected that next INFO @@ -226,7 +231,9 @@ ZTEST(test_log_api, test_log_various_messages) */ ZTEST(test_log_api, test_log_backend_runtime_filtering) { - log_timestamp_t exp_timestamp = TIMESTAMP_INIT_VAL; + uint16_t s_id = LOG_CURRENT_MODULE_ID(); + uint8_t d_id = Z_LOG_LOCAL_DOMAIN_ID; + log_timestamp_t exp_ts = TIMESTAMP_INIT_VAL; if (!IS_ENABLED(CONFIG_LOG_RUNTIME_FILTERING)) { ztest_test_skip(); @@ -245,72 +252,85 @@ ZTEST(test_log_api, test_log_backend_runtime_filtering) snprintk(str, sizeof(str), "test"); } - mock_log_frontend_record(LOG_CURRENT_MODULE_ID(), LOG_LEVEL_DBG, str); - mock_log_backend_record(&backend1, LOG_CURRENT_MODULE_ID(), - Z_LOG_LOCAL_DOMAIN_ID, LOG_LEVEL_DBG, - exp_timestamp, str); - mock_log_backend_record(&backend2, LOG_CURRENT_MODULE_ID(), - Z_LOG_LOCAL_DOMAIN_ID, LOG_LEVEL_DBG, - exp_timestamp, str); - exp_timestamp++; + mock_log_frontend_record(s_id, LOG_LEVEL_DBG, str); + if (!frontend_only()) { + mock_log_backend_record(&backend1, s_id, d_id, LOG_LEVEL_DBG, exp_ts, str); + mock_log_backend_record(&backend2, s_id, d_id, LOG_LEVEL_DBG, exp_ts, str); + } + exp_ts++; } mock_log_frontend_record(LOG_CURRENT_MODULE_ID(), LOG_LEVEL_INF, "test"); - mock_log_backend_record(&backend1, LOG_CURRENT_MODULE_ID(), - Z_LOG_LOCAL_DOMAIN_ID, LOG_LEVEL_INF, - exp_timestamp, "test"); - mock_log_backend_record(&backend2, LOG_CURRENT_MODULE_ID(), - Z_LOG_LOCAL_DOMAIN_ID, LOG_LEVEL_INF, - exp_timestamp, "test"); - exp_timestamp++; + if (!frontend_only()) { + mock_log_backend_record(&backend1, s_id, d_id, LOG_LEVEL_INF, exp_ts, "test"); + mock_log_backend_record(&backend2, s_id, d_id, LOG_LEVEL_INF, exp_ts, "test"); + } + exp_ts++; LOG_DBG("test"); LOG_INF("test"); process_and_validate(true, false); + uint32_t exp_level1 = dbg_enabled() ? LOG_LEVEL_DBG : LOG_LEVEL_INF; + uint32_t exp_level2 = LOG_LEVEL_WRN; - log_filter_set(&backend2, - Z_LOG_LOCAL_DOMAIN_ID, - LOG_CURRENT_MODULE_ID(), - LOG_LEVEL_WRN); + uint32_t b_level; + uint32_t f_level; + + /* Validate levels before changing for backend2 and frontend */ + if (!frontend_only()) { + b_level = log_filter_get(&backend1, d_id, s_id, true); + zassert_equal(b_level, exp_level1); + + b_level = log_filter_get(&backend2, d_id, s_id, true); + zassert_equal(b_level, exp_level1); + } + + if (IS_ENABLED(CONFIG_LOG_FRONTEND)) { + f_level = log_frontend_filter_get(s_id, true); + zassert_equal(f_level, exp_level1); + + log_frontend_filter_set(s_id, LOG_LEVEL_WRN); + + f_level = log_frontend_filter_get(s_id, true); + zassert_equal(f_level, exp_level2); + } + + if (!frontend_only()) { + log_filter_set(&backend2, d_id, s_id, LOG_LEVEL_WRN); + + b_level = log_filter_get(&backend1, d_id, s_id, true); + zassert_equal(b_level, exp_level1); + + b_level = log_filter_get(&backend2, d_id, s_id, true); + zassert_equal(b_level, exp_level2); + } uint8_t data[] = {1, 2, 4, 5, 6, 8}; - /* INF logs expected only on backend1 */ - mock_log_frontend_record(LOG_CURRENT_MODULE_ID(), LOG_LEVEL_INF, "test"); - mock_log_backend_record(&backend1, LOG_CURRENT_MODULE_ID(), - Z_LOG_LOCAL_DOMAIN_ID, LOG_LEVEL_INF, - exp_timestamp++, "test"); + if (!frontend_only()) { + /* INF logs expected only on backend1 */ + mock_log_backend_record(&backend1, s_id, d_id, LOG_LEVEL_INF, exp_ts++, "test"); - mock_log_frontend_generic_record(LOG_CURRENT_MODULE_ID(), Z_LOG_LOCAL_DOMAIN_ID, - LOG_LEVEL_INF, "hexdump", data, sizeof(data)); - mock_log_backend_generic_record(&backend1, LOG_CURRENT_MODULE_ID(), - Z_LOG_LOCAL_DOMAIN_ID, - LOG_LEVEL_INF, - exp_timestamp++, "hexdump", - data, sizeof(data)); + mock_log_backend_generic_record(&backend1, s_id, d_id, LOG_LEVEL_INF, + exp_ts++, "hexdump", data, sizeof(data)); + } - mock_log_frontend_record(LOG_CURRENT_MODULE_ID(), LOG_LEVEL_WRN, "test2"); - mock_log_backend_record(&backend1, LOG_CURRENT_MODULE_ID(), - Z_LOG_LOCAL_DOMAIN_ID, LOG_LEVEL_WRN, - exp_timestamp, "test2"); - mock_log_backend_record(&backend2, LOG_CURRENT_MODULE_ID(), - Z_LOG_LOCAL_DOMAIN_ID, LOG_LEVEL_WRN, - exp_timestamp++, "test2"); + /* WRN message expected on backends and frontend */ + mock_log_frontend_record(s_id, LOG_LEVEL_WRN, "test2"); + if (!frontend_only()) { + mock_log_backend_record(&backend1, s_id, d_id, LOG_LEVEL_WRN, exp_ts, "test2"); + mock_log_backend_record(&backend2, s_id, d_id, LOG_LEVEL_WRN, exp_ts++, "test2"); + } - mock_log_frontend_generic_record(LOG_CURRENT_MODULE_ID(), Z_LOG_LOCAL_DOMAIN_ID, - LOG_LEVEL_WRN, "hexdump", data, sizeof(data)); - mock_log_backend_generic_record(&backend1, LOG_CURRENT_MODULE_ID(), - Z_LOG_LOCAL_DOMAIN_ID, - LOG_LEVEL_WRN, - exp_timestamp, "hexdump", - data, sizeof(data)); - mock_log_backend_generic_record(&backend2, LOG_CURRENT_MODULE_ID(), - Z_LOG_LOCAL_DOMAIN_ID, - LOG_LEVEL_WRN, - exp_timestamp++, "hexdump", - data, sizeof(data)); + mock_log_frontend_generic_record(s_id, d_id, LOG_LEVEL_WRN, "hexdump", data, sizeof(data)); + if (!frontend_only()) { + mock_log_backend_generic_record(&backend1, s_id, d_id, LOG_LEVEL_WRN, + exp_ts, "hexdump", data, sizeof(data)); + mock_log_backend_generic_record(&backend2, s_id, d_id, LOG_LEVEL_WRN, + exp_ts++, "hexdump", data, sizeof(data)); + } LOG_INF("test"); LOG_HEXDUMP_INF(data, sizeof(data), "hexdump"); @@ -318,7 +338,6 @@ ZTEST(test_log_api, test_log_backend_runtime_filtering) LOG_HEXDUMP_WRN(data, sizeof(data), "hexdump"); process_and_validate(true, false); - } static size_t get_max_hexdump(void) diff --git a/tests/subsys/logging/log_api/testcase.yaml b/tests/subsys/logging/log_api/testcase.yaml index 6e6698c294d..b30b61163fd 100644 --- a/tests/subsys/logging/log_api/testcase.yaml +++ b/tests/subsys/logging/log_api/testcase.yaml @@ -94,11 +94,24 @@ tests: - CONFIG_LOG_MODE_DEFERRED=y - CONFIG_SAMPLE_MODULE_LOG_LEVEL_DBG=y + logging.frontend.dbg.rt_filtering: + extra_configs: + - CONFIG_LOG_FRONTEND=y + - CONFIG_LOG_MODE_DEFERRED=y + - CONFIG_SAMPLE_MODULE_LOG_LEVEL_DBG=y + - CONFIG_LOG_RUNTIME_FILTERING=y + logging.frontend: extra_configs: - CONFIG_LOG_FRONTEND=y - CONFIG_LOG_MODE_DEFERRED=y + logging.frontend.rt_filtering: + extra_configs: + - CONFIG_LOG_FRONTEND=y + - CONFIG_LOG_MODE_DEFERRED=y + - CONFIG_LOG_RUNTIME_FILTERING=y + logging.frontend.immediate: extra_configs: - CONFIG_LOG_FRONTEND=y @@ -135,6 +148,12 @@ tests: - CONFIG_LOG_FRONTEND=y - CONFIG_LOG_FRONTEND_ONLY=y + logging.frontend.only.rt_filtering: + extra_configs: + - CONFIG_LOG_FRONTEND=y + - CONFIG_LOG_FRONTEND_ONLY=y + - CONFIG_LOG_RUNTIME_FILTERING=y + logging.frontend.no_backends: extra_configs: - CONFIG_LOG_FRONTEND=y @@ -246,6 +265,13 @@ tests: - CONFIG_LOG_FRONTEND_ONLY=y - CONFIG_CPP=y + logging.frontend.only_cpp.rt_filtering: + extra_configs: + - CONFIG_LOG_FRONTEND=y + - CONFIG_LOG_FRONTEND_ONLY=y + - CONFIG_CPP=y + - CONFIG_LOG_RUNTIME_FILTERING=y + logging.frontend.no_backends_cpp: extra_configs: - CONFIG_LOG_FRONTEND=y From 5062cef1f08c6128ab34da69b60344965b9ad18a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Krzysztof=20Chru=C5=9Bci=C5=84ski?= Date: Tue, 2 Jan 2024 12:40:23 +0100 Subject: [PATCH 2199/3723] samples: logging: dictionary: Add support for runtime filtering MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Extend sample with configuration which has shell on one UART and UART dictionary based frontend on another. Shell commands can be used to control runtime filtering of logging messages for the frontend and shell backend. Signed-off-by: Krzysztof Chruściński --- samples/subsys/logging/dictionary/README.rst | 7 +++++++ .../boards/nrf5340dk_nrf5340_cpuapp.overlay | 16 ++++++++++++++++ samples/subsys/logging/dictionary/sample.yaml | 16 ++++++++++++++++ samples/subsys/logging/dictionary/src/main.c | 16 +++++++++++++++- 4 files changed, 54 insertions(+), 1 deletion(-) create mode 100644 samples/subsys/logging/dictionary/boards/nrf5340dk_nrf5340_cpuapp.overlay diff --git a/samples/subsys/logging/dictionary/README.rst b/samples/subsys/logging/dictionary/README.rst index 2253ff18320..1d54e228664 100644 --- a/samples/subsys/logging/dictionary/README.rst +++ b/samples/subsys/logging/dictionary/README.rst @@ -11,6 +11,13 @@ This is a sample app which utilizes :ref:`dictionary-based logging #include #include +#include -LOG_MODULE_REGISTER(hello_world, 4); +LOG_MODULE_REGISTER(hello_world, LOG_LEVEL_DBG); static const char *hexdump_msg = "HEXDUMP! HEXDUMP@ HEXDUMP#"; @@ -72,3 +73,16 @@ int main(void) #endif return 0; } + +static int rt_demo_cmd(const struct shell *sh, size_t argc, char **argv) +{ + ARG_UNUSED(sh); + LOG_ERR("demo %s", argc > 1 ? argv[1] : ""); + LOG_WRN("demo %s", argc > 1 ? argv[1] : ""); + LOG_INF("demo %s", argc > 1 ? argv[1] : ""); + LOG_DBG("demo %s", argc > 1 ? argv[1] : ""); + + return 0; +} + +SHELL_CMD_REGISTER(log_rt_demo, NULL, "Command can be used to test runtime filtering", rt_demo_cmd); From f1ef55ec5aa096236c78db1d6515cf06b16a4973 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Krzysztof=20Chru=C5=9Bci=C5=84ski?= Date: Tue, 2 Jan 2024 12:44:27 +0100 Subject: [PATCH 2200/3723] samples: shell: shell_module: Enable logging commands MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Enabling commands for the sample. They were disabled by c0c89527391 but should be enabled in the sample. Signed-off-by: Krzysztof Chruściński --- samples/subsys/shell/shell_module/prj.conf | 1 + 1 file changed, 1 insertion(+) diff --git a/samples/subsys/shell/shell_module/prj.conf b/samples/subsys/shell/shell_module/prj.conf index c11e1133d25..41d51f8e22a 100644 --- a/samples/subsys/shell/shell_module/prj.conf +++ b/samples/subsys/shell/shell_module/prj.conf @@ -1,6 +1,7 @@ CONFIG_PRINTK=y CONFIG_SHELL=y CONFIG_LOG=y +CONFIG_LOG_CMDS=y CONFIG_INIT_STACKS=y CONFIG_THREAD_STACK_INFO=y CONFIG_KERNEL_SHELL=y From fcbfe74df1a52a92c9f10d8aedb0f9199d92dbbf Mon Sep 17 00:00:00 2001 From: Gerard Marull-Paretas Date: Wed, 10 Jan 2024 15:38:15 +0100 Subject: [PATCH 2201/3723] arch: riscv: define some RISC-V exception codes As defined in Table 3.6 of "The RISC-V Instruction Set Manual, Volume II: Privileged Architecture". Delete all spread definitions of the same, weirdly prefixed with "SOC". Signed-off-by: Gerard Marull-Paretas --- arch/riscv/core/isr.S | 9 +++++---- include/zephyr/arch/riscv/irq.h | 15 ++++++++++++--- soc/riscv/common/riscv-privileged/soc_common.h | 4 ---- soc/riscv/espressif_esp32/esp32c3/soc.h | 5 +---- soc/riscv/ite_ec/common/soc_common.h | 3 --- soc/riscv/openisa_rv32m1/soc_ri5cy.h | 2 -- soc/riscv/openisa_rv32m1/soc_zero_riscy.h | 3 --- 7 files changed, 18 insertions(+), 23 deletions(-) diff --git a/arch/riscv/core/isr.S b/arch/riscv/core/isr.S index c36679ae6db..a4db1ff053b 100644 --- a/arch/riscv/core/isr.S +++ b/arch/riscv/core/isr.S @@ -14,6 +14,7 @@ #include #include #include +#include #include #include "asm_macros.inc" @@ -298,18 +299,18 @@ no_fp: /* increment _current->arch.exception_depth */ and t0, t0, t2 /* - * If mcause == SOC_MCAUSE_ECALL_EXP, handle system call from + * If mcause == RISCV_EXC_ECALLM, handle system call from * kernel thread. */ - li t1, SOC_MCAUSE_ECALL_EXP + li t1, RISCV_EXC_ECALLM beq t0, t1, is_kernel_syscall #ifdef CONFIG_USERSPACE /* - * If mcause == SOC_MCAUSE_USER_ECALL_EXP, handle system call + * If mcause == RISCV_EXC_ECALLU, handle system call * for user mode thread. */ - li t1, SOC_MCAUSE_USER_ECALL_EXP + li t1, RISCV_EXC_ECALLU beq t0, t1, is_user_syscall #endif /* CONFIG_USERSPACE */ diff --git a/include/zephyr/arch/riscv/irq.h b/include/zephyr/arch/riscv/irq.h index 77c0d4057aa..2e3e813872e 100644 --- a/include/zephyr/arch/riscv/irq.h +++ b/include/zephyr/arch/riscv/irq.h @@ -14,16 +14,25 @@ #ifndef ZEPHYR_INCLUDE_ARCH_RISCV_IRQ_H_ #define ZEPHYR_INCLUDE_ARCH_RISCV_IRQ_H_ -#ifndef _ASMLANGUAGE - #ifdef __cplusplus extern "C" { #endif +#ifndef _ASMLANGUAGE #include #include #include #include +#endif /* !_ASMLANGUAGE */ + +/* Exceptions 0-15 (MCAUSE interrupt=0) */ + +/* Environment Call from U-mode */ +#define RISCV_EXC_ECALLU 8 +/** Environment Call from M-mode */ +#define RISCV_EXC_ECALLM 11 + +#ifndef _ASMLANGUAGE extern void arch_irq_enable(unsigned int irq); extern void arch_irq_disable(unsigned int irq); @@ -102,10 +111,10 @@ static inline void arch_isr_direct_footer(int swap) } \ static inline int name##_body(void) +#endif /* _ASMLANGUAGE */ #ifdef __cplusplus } #endif -#endif /* _ASMLANGUAGE */ #endif /* ZEPHYR_INCLUDE_ARCH_RISCV_IRQ_H_ */ diff --git a/soc/riscv/common/riscv-privileged/soc_common.h b/soc/riscv/common/riscv-privileged/soc_common.h index 79f458924c6..27eed85c684 100644 --- a/soc/riscv/common/riscv-privileged/soc_common.h +++ b/soc/riscv/common/riscv-privileged/soc_common.h @@ -16,10 +16,6 @@ #define RISCV_MACHINE_SOFT_IRQ 3 /* Machine Software Interrupt */ #define RISCV_MACHINE_EXT_IRQ 11 /* Machine External Interrupt */ -/* ECALL Exception numbers */ -#define SOC_MCAUSE_ECALL_EXP 11 /* Machine ECALL instruction */ -#define SOC_MCAUSE_USER_ECALL_EXP 8 /* User ECALL instruction */ - /* SOC-specific MCAUSE bitfields */ #ifdef CONFIG_64BIT /* Interrupt Mask */ diff --git a/soc/riscv/espressif_esp32/esp32c3/soc.h b/soc/riscv/espressif_esp32/esp32c3/soc.h index a3709819abc..4d8904c5b2a 100644 --- a/soc/riscv/espressif_esp32/esp32c3/soc.h +++ b/soc/riscv/espressif_esp32/esp32c3/soc.h @@ -21,12 +21,9 @@ #define RISCV_MACHINE_TIMER_IRQ 7 /* Machine Timer Interrupt */ #define RISCV_MACHINE_EXT_IRQ 11 /* Machine External Interrupt */ -/* ECALL Exception numbers */ -#define SOC_MCAUSE_ECALL_EXP 11 /* Machine ECALL instruction */ -#define SOC_MCAUSE_USER_ECALL_EXP 8 /* User ECALL instruction */ - /* Interrupt Mask */ #define SOC_MCAUSE_IRQ_MASK (1 << 31) + /* Exception code Mask */ #define SOC_MCAUSE_EXP_MASK 0x7FFFFFFF diff --git a/soc/riscv/ite_ec/common/soc_common.h b/soc/riscv/ite_ec/common/soc_common.h index 5b981783164..0504118199a 100644 --- a/soc/riscv/ite_ec/common/soc_common.h +++ b/soc/riscv/ite_ec/common/soc_common.h @@ -22,9 +22,6 @@ /* Exception code Mask */ #define SOC_MCAUSE_EXP_MASK 0x7FFFFFFF -/* Exception code of environment call from M-mode */ -#define SOC_MCAUSE_ECALL_EXP 11 - #ifndef _ASMLANGUAGE #ifdef CONFIG_HAS_ITE_INTC diff --git a/soc/riscv/openisa_rv32m1/soc_ri5cy.h b/soc/riscv/openisa_rv32m1/soc_ri5cy.h index 27ebcbe6f35..12a001defba 100644 --- a/soc/riscv/openisa_rv32m1/soc_ri5cy.h +++ b/soc/riscv/openisa_rv32m1/soc_ri5cy.h @@ -55,6 +55,4 @@ */ #define SOC_MCAUSE_EXP_MASK 0x1F -/* The ecall exception number. This is a standard value. */ -#define SOC_MCAUSE_ECALL_EXP 11 #endif /* SOC_RISCV32_OPENISA_RV32M1_SOC_RI5CY_H_ */ diff --git a/soc/riscv/openisa_rv32m1/soc_zero_riscy.h b/soc/riscv/openisa_rv32m1/soc_zero_riscy.h index d5fa48297f7..4453b3665f6 100644 --- a/soc/riscv/openisa_rv32m1/soc_zero_riscy.h +++ b/soc/riscv/openisa_rv32m1/soc_zero_riscy.h @@ -43,7 +43,4 @@ */ #define SOC_MCAUSE_EXP_MASK 0x1F -/* The ecall exception number. This is a standard value. */ -#define SOC_MCAUSE_ECALL_EXP 11 - #endif /* SOC_RISCV32_OPENISA_RV32M1_SOC_ZERO_RISCY_H_ */ From a364420b30f96df97cc7a50b4674eaee6ce2e918 Mon Sep 17 00:00:00 2001 From: Gerard Marull-Paretas Date: Wed, 10 Jan 2024 13:39:29 +0100 Subject: [PATCH 2202/3723] soc: riscv: cleanup usage/definition of MCAUSE IRQ flag The MCAUSE register has the "Interrupt" flag defined defined at XLEN-1 position (31 for 32-bit, 63 for 64-bit). This is not an SoC specific option, and there's no need to expose it publicly. Signed-off-by: Gerard Marull-Paretas --- include/zephyr/arch/riscv/irq.h | 6 ++++++ soc/riscv/common/riscv-privileged/soc_common.h | 9 --------- soc/riscv/common/riscv-privileged/soc_irq.S | 4 ++-- soc/riscv/espressif_esp32/esp32c3/soc.h | 3 --- soc/riscv/ite_ec/common/soc_common.h | 3 --- 5 files changed, 8 insertions(+), 17 deletions(-) diff --git a/include/zephyr/arch/riscv/irq.h b/include/zephyr/arch/riscv/irq.h index 2e3e813872e..f0b1f88642d 100644 --- a/include/zephyr/arch/riscv/irq.h +++ b/include/zephyr/arch/riscv/irq.h @@ -32,6 +32,12 @@ extern "C" { /** Environment Call from M-mode */ #define RISCV_EXC_ECALLM 11 +#ifdef CONFIG_64BIT +#define RISCV_MCAUSE_IRQ_BIT (1 << 63) +#else +#define RISCV_MCAUSE_IRQ_BIT (1 << 31) +#endif + #ifndef _ASMLANGUAGE extern void arch_irq_enable(unsigned int irq); diff --git a/soc/riscv/common/riscv-privileged/soc_common.h b/soc/riscv/common/riscv-privileged/soc_common.h index 27eed85c684..8b993c8a946 100644 --- a/soc/riscv/common/riscv-privileged/soc_common.h +++ b/soc/riscv/common/riscv-privileged/soc_common.h @@ -16,15 +16,6 @@ #define RISCV_MACHINE_SOFT_IRQ 3 /* Machine Software Interrupt */ #define RISCV_MACHINE_EXT_IRQ 11 /* Machine External Interrupt */ -/* SOC-specific MCAUSE bitfields */ -#ifdef CONFIG_64BIT -/* Interrupt Mask */ -#define SOC_MCAUSE_IRQ_MASK (1 << 63) -#else -/* Interrupt Mask */ -#define SOC_MCAUSE_IRQ_MASK (1 << 31) -#endif - /* Exception code Mask */ #define SOC_MCAUSE_EXP_MASK CONFIG_RISCV_SOC_MCAUSE_EXCEPTION_MASK diff --git a/soc/riscv/common/riscv-privileged/soc_irq.S b/soc/riscv/common/riscv-privileged/soc_irq.S index 73fc24431d5..377edbf600d 100644 --- a/soc/riscv/common/riscv-privileged/soc_irq.S +++ b/soc/riscv/common/riscv-privileged/soc_irq.S @@ -12,7 +12,7 @@ #include #include #include -#include +#include /* * __soc_handle_irq is defined as .weak to allow re-implementation by @@ -48,7 +48,7 @@ WTEXT(__soc_is_irq) SECTION_FUNC(exception.other, __soc_is_irq) /* Read mcause and check if interrupt bit is set */ csrr t0, mcause - li t1, SOC_MCAUSE_IRQ_MASK + li t1, RISCV_MCAUSE_IRQ_BIT and t0, t0, t1 /* If interrupt bit is not set, return with 0 */ diff --git a/soc/riscv/espressif_esp32/esp32c3/soc.h b/soc/riscv/espressif_esp32/esp32c3/soc.h index 4d8904c5b2a..6f6c9263da2 100644 --- a/soc/riscv/espressif_esp32/esp32c3/soc.h +++ b/soc/riscv/espressif_esp32/esp32c3/soc.h @@ -21,9 +21,6 @@ #define RISCV_MACHINE_TIMER_IRQ 7 /* Machine Timer Interrupt */ #define RISCV_MACHINE_EXT_IRQ 11 /* Machine External Interrupt */ -/* Interrupt Mask */ -#define SOC_MCAUSE_IRQ_MASK (1 << 31) - /* Exception code Mask */ #define SOC_MCAUSE_EXP_MASK 0x7FFFFFFF diff --git a/soc/riscv/ite_ec/common/soc_common.h b/soc/riscv/ite_ec/common/soc_common.h index 0504118199a..b50f16df0fb 100644 --- a/soc/riscv/ite_ec/common/soc_common.h +++ b/soc/riscv/ite_ec/common/soc_common.h @@ -16,9 +16,6 @@ /* SOC-specific MCAUSE bitfields */ -/* Interrupt Mask. 1 (interrupt) or 0 (exception) */ -#define SOC_MCAUSE_IRQ_MASK BIT(31) - /* Exception code Mask */ #define SOC_MCAUSE_EXP_MASK 0x7FFFFFFF From 6edb0624d8549339ed08dfeb19fe471be556d3ff Mon Sep 17 00:00:00 2001 From: Gerard Marull-Paretas Date: Wed, 10 Jan 2024 15:50:18 +0100 Subject: [PATCH 2203/3723] soc: riscv: gd32vf103: simplify MCAUSE exception mask handling The exception mask needs to cover MCAUSE bits 11:0, there's no need to overengineer this setting using DT properties. Ref. https://doc.nucleisys.com/nuclei_spec/isa/core_csr.html#mcause Signed-off-by: Gerard Marull-Paretas --- dts/bindings/cpu/nuclei,bumblebee.yaml | 6 ------ dts/riscv/gd/gd32vf103.dtsi | 1 - soc/riscv/gd_gd32/gd32vf103/Kconfig.defconfig.gd32vf103 | 2 +- 3 files changed, 1 insertion(+), 8 deletions(-) diff --git a/dts/bindings/cpu/nuclei,bumblebee.yaml b/dts/bindings/cpu/nuclei,bumblebee.yaml index 8c9dfc7d35d..96eebcd0fb8 100644 --- a/dts/bindings/cpu/nuclei,bumblebee.yaml +++ b/dts/bindings/cpu/nuclei,bumblebee.yaml @@ -6,9 +6,3 @@ description: Nuclei Bumblebee RISC-V Core compatible: "nuclei,bumblebee" include: riscv,cpus.yaml - -properties: - mcause-exception-mask: - type: int - required: true - description: Specify the bits to use for exception code in mcause register. diff --git a/dts/riscv/gd/gd32vf103.dtsi b/dts/riscv/gd/gd32vf103.dtsi index c9f37db5180..b52aee61fbc 100644 --- a/dts/riscv/gd/gd32vf103.dtsi +++ b/dts/riscv/gd/gd32vf103.dtsi @@ -23,7 +23,6 @@ cpu: cpu@0 { clock-frequency = ; - mcause-exception-mask = <0x7ff>; compatible = "nuclei,bumblebee"; riscv,isa = "rv32imac_zicsr_zifencei"; reg = <0>; diff --git a/soc/riscv/gd_gd32/gd32vf103/Kconfig.defconfig.gd32vf103 b/soc/riscv/gd_gd32/gd32vf103/Kconfig.defconfig.gd32vf103 index 4d65e4c43cd..ade07b45635 100644 --- a/soc/riscv/gd_gd32/gd32vf103/Kconfig.defconfig.gd32vf103 +++ b/soc/riscv/gd_gd32/gd32vf103/Kconfig.defconfig.gd32vf103 @@ -15,7 +15,7 @@ config SYS_CLOCK_HW_CYCLES_PER_SEC default 27000000 config RISCV_SOC_MCAUSE_EXCEPTION_MASK - default $(dt_node_int_prop_hex,/cpus/cpu@0,mcause-exception-mask) + default 0xFFF config RISCV_SOC_INTERRUPT_INIT default y From ee6097795855c8752d2060f8cb5a5cad0d7b7dd3 Mon Sep 17 00:00:00 2001 From: Gerard Marull-Paretas Date: Wed, 10 Jan 2024 15:53:24 +0100 Subject: [PATCH 2204/3723] arch: riscv: remove SOC from RISCV_SOC_MCAUSE_EXCEPTION_MASK Just to stay consistent with other RISC-V related settings. Signed-off-by: Gerard Marull-Paretas --- arch/riscv/Kconfig | 2 +- soc/riscv/common/riscv-privileged/soc_common.h | 2 +- soc/riscv/gd_gd32/gd32vf103/Kconfig.defconfig.gd32vf103 | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/arch/riscv/Kconfig b/arch/riscv/Kconfig index 60d33b18071..1c5defbacaf 100644 --- a/arch/riscv/Kconfig +++ b/arch/riscv/Kconfig @@ -159,7 +159,7 @@ config RISCV_SOC_INTERRUPT_INIT Enable SOC-based interrupt initialization (call soc_interrupt_init, within _IntLibInit when enabled) -config RISCV_SOC_MCAUSE_EXCEPTION_MASK +config RISCV_MCAUSE_EXCEPTION_MASK hex default 0x7FFFFFFFFFFFFFFF if 64BIT default 0x7FFFFFFF diff --git a/soc/riscv/common/riscv-privileged/soc_common.h b/soc/riscv/common/riscv-privileged/soc_common.h index 8b993c8a946..6e75d4acf06 100644 --- a/soc/riscv/common/riscv-privileged/soc_common.h +++ b/soc/riscv/common/riscv-privileged/soc_common.h @@ -17,7 +17,7 @@ #define RISCV_MACHINE_EXT_IRQ 11 /* Machine External Interrupt */ /* Exception code Mask */ -#define SOC_MCAUSE_EXP_MASK CONFIG_RISCV_SOC_MCAUSE_EXCEPTION_MASK +#define SOC_MCAUSE_EXP_MASK CONFIG_RISCV_MCAUSE_EXCEPTION_MASK #ifndef _ASMLANGUAGE diff --git a/soc/riscv/gd_gd32/gd32vf103/Kconfig.defconfig.gd32vf103 b/soc/riscv/gd_gd32/gd32vf103/Kconfig.defconfig.gd32vf103 index ade07b45635..0da92e80e36 100644 --- a/soc/riscv/gd_gd32/gd32vf103/Kconfig.defconfig.gd32vf103 +++ b/soc/riscv/gd_gd32/gd32vf103/Kconfig.defconfig.gd32vf103 @@ -14,7 +14,7 @@ config SYS_CLOCK_HW_CYCLES_PER_SEC # The CPU frequency is set to the maximum value of 108MHz by default. default 27000000 -config RISCV_SOC_MCAUSE_EXCEPTION_MASK +config RISCV_MCAUSE_EXCEPTION_MASK default 0xFFF config RISCV_SOC_INTERRUPT_INIT From 452a2f67cdac4d076a481f584d0f7d658e806cde Mon Sep 17 00:00:00 2001 From: Gerard Marull-Paretas Date: Wed, 10 Jan 2024 16:11:51 +0100 Subject: [PATCH 2205/3723] arch: riscv: use CONFIG_RISCV_MCAUSE_EXCEPTION_MASK Instead of custom SOC_MCAUSE_EXP_MASK definition. Note that SoCs selecting RISCV_PRIVILEGED already used such config indirectly (see changes in soc_common.h). Signed-off-by: Gerard Marull-Paretas --- arch/riscv/core/fatal.c | 2 +- arch/riscv/core/irq_manage.c | 2 +- arch/riscv/core/isr.S | 4 ++-- include/zephyr/arch/riscv/irq.h | 2 +- soc/riscv/common/riscv-privileged/soc_common.h | 3 --- soc/riscv/espressif_esp32/esp32c3/soc.h | 3 --- soc/riscv/ite_ec/common/soc_common.h | 5 ----- soc/riscv/openisa_rv32m1/Kconfig.defconfig | 3 +++ soc/riscv/openisa_rv32m1/soc_ri5cy.h | 15 --------------- soc/riscv/openisa_rv32m1/soc_zero_riscy.h | 15 --------------- 10 files changed, 8 insertions(+), 46 deletions(-) diff --git a/arch/riscv/core/fatal.c b/arch/riscv/core/fatal.c index 0cbcf27d5fd..36457a23de7 100644 --- a/arch/riscv/core/fatal.c +++ b/arch/riscv/core/fatal.c @@ -168,7 +168,7 @@ void _Fault(z_arch_esf_t *esf) __asm__ volatile("csrr %0, mtval" : "=r" (mtval)); #endif - mcause &= SOC_MCAUSE_EXP_MASK; + mcause &= CONFIG_RISCV_MCAUSE_EXCEPTION_MASK; LOG_ERR(""); LOG_ERR(" mcause: %ld, %s", mcause, cause_str(mcause)); #ifndef CONFIG_SOC_OPENISA_RV32M1_RISCV32 diff --git a/arch/riscv/core/irq_manage.c b/arch/riscv/core/irq_manage.c index e0ef1374bf1..6ed5781c731 100644 --- a/arch/riscv/core/irq_manage.c +++ b/arch/riscv/core/irq_manage.c @@ -20,7 +20,7 @@ FUNC_NORETURN void z_irq_spurious(const void *unused) mcause = csr_read(mcause); - mcause &= SOC_MCAUSE_EXP_MASK; + mcause &= CONFIG_RISCV_MCAUSE_EXCEPTION_MASK; LOG_ERR("Spurious interrupt detected! IRQ: %ld", mcause); #if defined(CONFIG_RISCV_HAS_PLIC) diff --git a/arch/riscv/core/isr.S b/arch/riscv/core/isr.S index a4db1ff053b..558d2a41fbe 100644 --- a/arch/riscv/core/isr.S +++ b/arch/riscv/core/isr.S @@ -295,7 +295,7 @@ no_fp: /* increment _current->arch.exception_depth */ * to report the exception. */ csrr t0, mcause - li t2, SOC_MCAUSE_EXP_MASK + li t2, CONFIG_RISCV_MCAUSE_EXCEPTION_MASK and t0, t0, t2 /* @@ -528,7 +528,7 @@ on_irq_stack: /* Get IRQ causing interrupt */ csrr a0, mcause - li t0, SOC_MCAUSE_EXP_MASK + li t0, CONFIG_RISCV_MCAUSE_EXCEPTION_MASK and a0, a0, t0 /* diff --git a/include/zephyr/arch/riscv/irq.h b/include/zephyr/arch/riscv/irq.h index f0b1f88642d..d4dfd54d92a 100644 --- a/include/zephyr/arch/riscv/irq.h +++ b/include/zephyr/arch/riscv/irq.h @@ -91,7 +91,7 @@ static inline void arch_isr_direct_footer(int swap) /* Get the IRQ number */ __asm__ volatile("csrr %0, mcause" : "=r" (mcause)); - mcause &= SOC_MCAUSE_EXP_MASK; + mcause &= CONFIG_RISCV_MCAUSE_EXCEPTION_MASK; /* Clear the pending IRQ */ __soc_handle_irq(mcause); diff --git a/soc/riscv/common/riscv-privileged/soc_common.h b/soc/riscv/common/riscv-privileged/soc_common.h index 6e75d4acf06..01a6b783850 100644 --- a/soc/riscv/common/riscv-privileged/soc_common.h +++ b/soc/riscv/common/riscv-privileged/soc_common.h @@ -16,9 +16,6 @@ #define RISCV_MACHINE_SOFT_IRQ 3 /* Machine Software Interrupt */ #define RISCV_MACHINE_EXT_IRQ 11 /* Machine External Interrupt */ -/* Exception code Mask */ -#define SOC_MCAUSE_EXP_MASK CONFIG_RISCV_MCAUSE_EXCEPTION_MASK - #ifndef _ASMLANGUAGE #include diff --git a/soc/riscv/espressif_esp32/esp32c3/soc.h b/soc/riscv/espressif_esp32/esp32c3/soc.h index 6f6c9263da2..8076f2ae045 100644 --- a/soc/riscv/espressif_esp32/esp32c3/soc.h +++ b/soc/riscv/espressif_esp32/esp32c3/soc.h @@ -21,9 +21,6 @@ #define RISCV_MACHINE_TIMER_IRQ 7 /* Machine Timer Interrupt */ #define RISCV_MACHINE_EXT_IRQ 11 /* Machine External Interrupt */ -/* Exception code Mask */ -#define SOC_MCAUSE_EXP_MASK 0x7FFFFFFF - #ifndef _ASMLANGUAGE void __esp_platform_start(void); diff --git a/soc/riscv/ite_ec/common/soc_common.h b/soc/riscv/ite_ec/common/soc_common.h index b50f16df0fb..b7e0cdd5e55 100644 --- a/soc/riscv/ite_ec/common/soc_common.h +++ b/soc/riscv/ite_ec/common/soc_common.h @@ -14,11 +14,6 @@ #include "chip_chipregs.h" -/* SOC-specific MCAUSE bitfields */ - -/* Exception code Mask */ -#define SOC_MCAUSE_EXP_MASK 0x7FFFFFFF - #ifndef _ASMLANGUAGE #ifdef CONFIG_HAS_ITE_INTC diff --git a/soc/riscv/openisa_rv32m1/Kconfig.defconfig b/soc/riscv/openisa_rv32m1/Kconfig.defconfig index 3976c9940c5..52d652a061e 100644 --- a/soc/riscv/openisa_rv32m1/Kconfig.defconfig +++ b/soc/riscv/openisa_rv32m1/Kconfig.defconfig @@ -33,6 +33,9 @@ config RISCV_SOC_OFFSETS config RISCV_SOC_INTERRUPT_INIT default y +config RISCV_MCAUSE_EXCEPTION_MASK + default 0x1F + # We need to disable the watchdog out of reset, as it's enabled by # default. Use the WDOG_INIT hook for doing that. config WDOG_INIT diff --git a/soc/riscv/openisa_rv32m1/soc_ri5cy.h b/soc/riscv/openisa_rv32m1/soc_ri5cy.h index 12a001defba..d9158935e08 100644 --- a/soc/riscv/openisa_rv32m1/soc_ri5cy.h +++ b/soc/riscv/openisa_rv32m1/soc_ri5cy.h @@ -40,19 +40,4 @@ #define RI5CY_PRIVLV 0xC10 #define RI5CY_MHARTID 0xF14 -/* - * Map from SoC-specific configuration to generic Zephyr macros. - * - * These are expected by the code in arch/, and must be provided for - * the kernel to work (or even build at all). - * - * Some of these may also apply to ZERO-RISCY; needs investigation. - */ - -/* - * Exception code mask. Use of the bottom five bits is a subset of - * what the standard allocates (which is XLEN-1 bits). - */ -#define SOC_MCAUSE_EXP_MASK 0x1F - #endif /* SOC_RISCV32_OPENISA_RV32M1_SOC_RI5CY_H_ */ diff --git a/soc/riscv/openisa_rv32m1/soc_zero_riscy.h b/soc/riscv/openisa_rv32m1/soc_zero_riscy.h index 4453b3665f6..43cd144823a 100644 --- a/soc/riscv/openisa_rv32m1/soc_zero_riscy.h +++ b/soc/riscv/openisa_rv32m1/soc_zero_riscy.h @@ -28,19 +28,4 @@ #define ZERO_RISCY_PCMR 0x7A1U #define ZERO_RISCY_MHARTID 0xF14U -/* - * Map from SoC-specific configuration to generic Zephyr macros. - * - * These are expected by the code in arch/, and must be provided for - * the kernel to work (or even build at all). - * - * Some of these may also apply to ZERO-RISCY; needs investigation. - */ - -/* - * Exception code mask. Use of the bottom five bits is a subset of - * what the standard allocates (which is XLEN-1 bits). - */ -#define SOC_MCAUSE_EXP_MASK 0x1F - #endif /* SOC_RISCV32_OPENISA_RV32M1_SOC_ZERO_RISCY_H_ */ From c725c91d951874726392b60c4fd8137ca9d6b920 Mon Sep 17 00:00:00 2001 From: Gerard Marull-Paretas Date: Wed, 10 Jan 2024 16:25:05 +0100 Subject: [PATCH 2206/3723] arch: riscv: define RISC_IRQ_MSOFT/MEXT Instead of relying on spread definitions within SoC files. Signed-off-by: Gerard Marull-Paretas --- arch/riscv/core/irq_manage.c | 2 +- arch/riscv/core/smp.c | 7 ++++--- drivers/interrupt_controller/intc_swerv_pic.c | 5 +++-- drivers/interrupt_controller/intc_vexriscv_litex.c | 5 +++-- drivers/mbox/mbox_andes_plic_sw.c | 4 ++-- include/zephyr/arch/riscv/irq.h | 7 +++++++ soc/riscv/common/riscv-privileged/soc_common.h | 4 ---- soc/riscv/espressif_esp32/esp32c3/soc.h | 5 ----- 8 files changed, 20 insertions(+), 19 deletions(-) diff --git a/arch/riscv/core/irq_manage.c b/arch/riscv/core/irq_manage.c index 6ed5781c731..f3e0cc09ab1 100644 --- a/arch/riscv/core/irq_manage.c +++ b/arch/riscv/core/irq_manage.c @@ -24,7 +24,7 @@ FUNC_NORETURN void z_irq_spurious(const void *unused) LOG_ERR("Spurious interrupt detected! IRQ: %ld", mcause); #if defined(CONFIG_RISCV_HAS_PLIC) - if (mcause == RISCV_MACHINE_EXT_IRQ) { + if (mcause == RISCV_IRQ_MEXT) { unsigned int save_irq = riscv_plic_get_irq(); const struct device *save_dev = riscv_plic_get_dev(); diff --git a/arch/riscv/core/smp.c b/arch/riscv/core/smp.c index b49fcf8aa4f..ddaae4e9db0 100644 --- a/arch/riscv/core/smp.c +++ b/arch/riscv/core/smp.c @@ -9,6 +9,7 @@ #include #include #include +#include #include volatile struct { @@ -67,7 +68,7 @@ void arch_secondary_cpu_init(int hartid) z_riscv_pmp_init(); #endif #ifdef CONFIG_SMP - irq_enable(RISCV_MACHINE_SOFT_IRQ); + irq_enable(RISCV_IRQ_MSOFT); #endif riscv_cpu_init[cpu_num].fn(riscv_cpu_init[cpu_num].arg); } @@ -154,8 +155,8 @@ void arch_spin_relax(void) int arch_smp_init(void) { - IRQ_CONNECT(RISCV_MACHINE_SOFT_IRQ, 0, sched_ipi_handler, NULL, 0); - irq_enable(RISCV_MACHINE_SOFT_IRQ); + IRQ_CONNECT(RISCV_IRQ_MSOFT, 0, sched_ipi_handler, NULL, 0); + irq_enable(RISCV_IRQ_MSOFT); return 0; } diff --git a/drivers/interrupt_controller/intc_swerv_pic.c b/drivers/interrupt_controller/intc_swerv_pic.c index 5c52ab49614..96eb248d27c 100644 --- a/drivers/interrupt_controller/intc_swerv_pic.c +++ b/drivers/interrupt_controller/intc_swerv_pic.c @@ -15,6 +15,7 @@ #include #include #include +#include #define SWERV_PIC_MAX_NUM CONFIG_NUM_IRQS #define SWERV_PIC_MAX_ID (SWERV_PIC_MAX_NUM + RISCV_MAX_GENERIC_IRQ) @@ -176,14 +177,14 @@ static int swerv_pic_init(const struct device *dev) __asm__ swerv_pic_writecsr(meicurpl, 0); /* Setup IRQ handler for SweRV PIC driver */ - IRQ_CONNECT(RISCV_MACHINE_EXT_IRQ, + IRQ_CONNECT(RISCV_IRQ_MEXT, 0, swerv_pic_irq_handler, NULL, 0); /* Enable IRQ for SweRV PIC driver */ - irq_enable(RISCV_MACHINE_EXT_IRQ); + irq_enable(RISCV_IRQ_MEXT); return 0; } diff --git a/drivers/interrupt_controller/intc_vexriscv_litex.c b/drivers/interrupt_controller/intc_vexriscv_litex.c index efec4d2478e..2d5d2233ab2 100644 --- a/drivers/interrupt_controller/intc_vexriscv_litex.c +++ b/drivers/interrupt_controller/intc_vexriscv_litex.c @@ -11,6 +11,7 @@ #include #include #include +#include #define IRQ_MASK DT_INST_REG_ADDR_BY_NAME(0, irq_mask) #define IRQ_PENDING DT_INST_REG_ADDR_BY_NAME(0, irq_pending) @@ -122,9 +123,9 @@ int arch_irq_is_enabled(unsigned int irq) static int vexriscv_litex_irq_init(const struct device *dev) { __asm__ volatile ("csrrs x0, mie, %0" - :: "r"(1 << RISCV_MACHINE_EXT_IRQ)); + :: "r"(1 << RISCV_IRQ_MEXT)); vexriscv_litex_irq_setie(1); - IRQ_CONNECT(RISCV_MACHINE_EXT_IRQ, 0, vexriscv_litex_irq_handler, + IRQ_CONNECT(RISCV_IRQ_MEXT, 0, vexriscv_litex_irq_handler, NULL, 0); return 0; diff --git a/drivers/mbox/mbox_andes_plic_sw.c b/drivers/mbox/mbox_andes_plic_sw.c index bc01da73a30..e2c287ae216 100644 --- a/drivers/mbox/mbox_andes_plic_sw.c +++ b/drivers/mbox/mbox_andes_plic_sw.c @@ -199,11 +199,11 @@ static void andes_plic_sw_irq_handler(const struct device *dev) static int mbox_andes_init(const struct device *dev) { /* Setup IRQ handler for PLIC SW driver */ - IRQ_CONNECT(RISCV_MACHINE_SOFT_IRQ, 1, + IRQ_CONNECT(RISCV_IRQ_MSOFT, 1, andes_plic_sw_irq_handler, DEVICE_DT_INST_GET(0), 0); #ifndef CONFIG_SMP - irq_enable(RISCV_MACHINE_SOFT_IRQ); + irq_enable(RISCV_IRQ_MSOFT); #endif return 0; } diff --git a/include/zephyr/arch/riscv/irq.h b/include/zephyr/arch/riscv/irq.h index d4dfd54d92a..84d3a4949a9 100644 --- a/include/zephyr/arch/riscv/irq.h +++ b/include/zephyr/arch/riscv/irq.h @@ -32,6 +32,13 @@ extern "C" { /** Environment Call from M-mode */ #define RISCV_EXC_ECALLM 11 +/* IRQs 0-15 (MCAUSE interrupt=1) */ + +/** Machine Software Interrupt */ +#define RISCV_IRQ_MSOFT 3 +/** Machine External Interrupt */ +#define RISCV_IRQ_MEXT 11 + #ifdef CONFIG_64BIT #define RISCV_MCAUSE_IRQ_BIT (1 << 63) #else diff --git a/soc/riscv/common/riscv-privileged/soc_common.h b/soc/riscv/common/riscv-privileged/soc_common.h index 01a6b783850..bf9600ab880 100644 --- a/soc/riscv/common/riscv-privileged/soc_common.h +++ b/soc/riscv/common/riscv-privileged/soc_common.h @@ -12,10 +12,6 @@ #ifndef __SOC_COMMON_H_ #define __SOC_COMMON_H_ -/* IRQ numbers */ -#define RISCV_MACHINE_SOFT_IRQ 3 /* Machine Software Interrupt */ -#define RISCV_MACHINE_EXT_IRQ 11 /* Machine External Interrupt */ - #ifndef _ASMLANGUAGE #include diff --git a/soc/riscv/espressif_esp32/esp32c3/soc.h b/soc/riscv/espressif_esp32/esp32c3/soc.h index 8076f2ae045..68fb6fdb1ce 100644 --- a/soc/riscv/espressif_esp32/esp32c3/soc.h +++ b/soc/riscv/espressif_esp32/esp32c3/soc.h @@ -16,11 +16,6 @@ #include "esp32c3/clk.h" #endif -/* IRQ numbers */ -#define RISCV_MACHINE_SOFT_IRQ 3 /* Machine Software Interrupt */ -#define RISCV_MACHINE_TIMER_IRQ 7 /* Machine Timer Interrupt */ -#define RISCV_MACHINE_EXT_IRQ 11 /* Machine External Interrupt */ - #ifndef _ASMLANGUAGE void __esp_platform_start(void); From 0addc80d102175f40acb40c8a80101a6ff5d4913 Mon Sep 17 00:00:00 2001 From: Gerard Marull-Paretas Date: Wed, 10 Jan 2024 16:33:19 +0100 Subject: [PATCH 2207/3723] arch: riscv: define local soc_interrupt_init prototypes Instead of relying on messy soc.h files which are included via a fragile chain of includes. Signed-off-by: Gerard Marull-Paretas --- arch/riscv/core/prep_c.c | 4 ++++ arch/riscv/core/smp.c | 4 ++++ soc/riscv/common/riscv-privileged/soc_common.h | 4 ---- soc/riscv/ite_ec/it8xxx2/soc.h | 4 ---- soc/riscv/openisa_rv32m1/soc.h | 2 -- 5 files changed, 8 insertions(+), 10 deletions(-) diff --git a/arch/riscv/core/prep_c.c b/arch/riscv/core/prep_c.c index 37835402fba..b0fdd3a0569 100644 --- a/arch/riscv/core/prep_c.c +++ b/arch/riscv/core/prep_c.c @@ -20,6 +20,10 @@ #include #include +#if defined(CONFIG_RISCV_SOC_INTERRUPT_INIT) +void soc_interrupt_init(void); +#endif + /** * * @brief Prepare to and run C code diff --git a/arch/riscv/core/smp.c b/arch/riscv/core/smp.c index ddaae4e9db0..941213ab49a 100644 --- a/arch/riscv/core/smp.c +++ b/arch/riscv/core/smp.c @@ -23,6 +23,10 @@ volatile void *riscv_cpu_sp; extern void __start(void); +#if defined(CONFIG_RISCV_SOC_INTERRUPT_INIT) +void soc_interrupt_init(void); +#endif + void arch_start_cpu(int cpu_num, k_thread_stack_t *stack, int sz, arch_cpustart_t fn, void *arg) { diff --git a/soc/riscv/common/riscv-privileged/soc_common.h b/soc/riscv/common/riscv-privileged/soc_common.h index bf9600ab880..f8f1c13cb59 100644 --- a/soc/riscv/common/riscv-privileged/soc_common.h +++ b/soc/riscv/common/riscv-privileged/soc_common.h @@ -17,10 +17,6 @@ #include #include -#if defined(CONFIG_RISCV_SOC_INTERRUPT_INIT) -void soc_interrupt_init(void); -#endif - #endif /* !_ASMLANGUAGE */ #endif /* __SOC_COMMON_H_ */ diff --git a/soc/riscv/ite_ec/it8xxx2/soc.h b/soc/riscv/ite_ec/it8xxx2/soc.h index bc790768369..ea9d30d11fc 100644 --- a/soc/riscv/ite_ec/it8xxx2/soc.h +++ b/soc/riscv/ite_ec/it8xxx2/soc.h @@ -25,8 +25,4 @@ COND_CODE_1(DT_NODE_EXISTS(DT_INST(1, ite_it8xxx2_usbpd)), (2), (1)) */ #define SOC_USBPD_ITE_ACTIVE_PORT_COUNT DT_NUM_INST_STATUS_OKAY(ite_it8xxx2_usbpd) -#ifndef _ASMLANGUAGE -void soc_interrupt_init(void); -#endif - #endif /* __RISCV_ITE_SOC_H_ */ diff --git a/soc/riscv/openisa_rv32m1/soc.h b/soc/riscv/openisa_rv32m1/soc.h index 1b2643d0b66..75011d36283 100644 --- a/soc/riscv/openisa_rv32m1/soc.h +++ b/soc/riscv/openisa_rv32m1/soc.h @@ -94,8 +94,6 @@ static inline uint32_t rv32m1_intmux_line(unsigned int irq) return ((irq >> 8) & 0xff) - 1; } -void soc_interrupt_init(void); - #endif /* !_ASMLANGUAGE */ #if defined(CONFIG_SOC_OPENISA_RV32M1_RI5CY) From 6252e8576c94a4ad7549d4c6180a3e0d3c8eb3a8 Mon Sep 17 00:00:00 2001 From: Gerard Marull-Paretas Date: Thu, 11 Jan 2024 10:42:51 +0100 Subject: [PATCH 2208/3723] arch: riscv: irq_manage: add missing PLIC header Module uses RISC-V PLIC interrupt controller API without including the necessary headers. Signed-off-by: Gerard Marull-Paretas --- arch/riscv/core/irq_manage.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/arch/riscv/core/irq_manage.c b/arch/riscv/core/irq_manage.c index f3e0cc09ab1..f95b099a4da 100644 --- a/arch/riscv/core/irq_manage.c +++ b/arch/riscv/core/irq_manage.c @@ -10,6 +10,10 @@ #include #include +#ifdef CONFIG_RISCV_HAS_PLIC +#include +#endif + LOG_MODULE_DECLARE(os, CONFIG_KERNEL_LOG_LEVEL); FUNC_NORETURN void z_irq_spurious(const void *unused) From 36069b6c9aeb4971955fd2850457b6cdc42e9039 Mon Sep 17 00:00:00 2001 From: Gerard Marull-Paretas Date: Thu, 11 Jan 2024 11:31:24 +0100 Subject: [PATCH 2209/3723] drivers: gpio: sifive: add missing PLIC header Driver is using the PLIC API without including the right header. Signed-off-by: Gerard Marull-Paretas --- drivers/gpio/gpio_sifive.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/gpio/gpio_sifive.c b/drivers/gpio/gpio_sifive.c index 77703f25707..a412fdd1528 100644 --- a/drivers/gpio/gpio_sifive.c +++ b/drivers/gpio/gpio_sifive.c @@ -18,7 +18,7 @@ #include #include #include - +#include #include typedef void (*sifive_cfg_func_t)(void); From 992f25b0c929cad7c1e26ef7cec72ae7823e396d Mon Sep 17 00:00:00 2001 From: Gerard Marull-Paretas Date: Thu, 11 Jan 2024 13:35:47 +0100 Subject: [PATCH 2210/3723] drivers: gpio: b91: add missing PLIC header Driver is using the RISC-V PLIC interrupt controller without including the necessary headers. Signed-off-by: Gerard Marull-Paretas --- drivers/gpio/gpio_b91.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/gpio/gpio_b91.c b/drivers/gpio/gpio_b91.c index bc73f9db9f5..4c4c14dc909 100644 --- a/drivers/gpio/gpio_b91.c +++ b/drivers/gpio/gpio_b91.c @@ -10,6 +10,7 @@ #include #include #include +#include /* Driver dts compatibility: telink,b91_gpio */ From 87bb281a9f8692c8755edb58353085f6b7b4c3be Mon Sep 17 00:00:00 2001 From: Gerard Marull-Paretas Date: Thu, 11 Jan 2024 20:00:37 +0100 Subject: [PATCH 2211/3723] drivers: ieee802154: b91: add missing PLIC include Driver was using RISC-V PLIC API without including the necessary headers. Signed-off-by: Gerard Marull-Paretas --- drivers/ieee802154/ieee802154_b91.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/drivers/ieee802154/ieee802154_b91.c b/drivers/ieee802154/ieee802154_b91.c index e19356a272a..e44c99888dd 100644 --- a/drivers/ieee802154/ieee802154_b91.c +++ b/drivers/ieee802154/ieee802154_b91.c @@ -26,6 +26,8 @@ LOG_MODULE_REGISTER(LOG_MODULE_NAME); #include #endif +#include + #include "ieee802154_b91.h" From 3ed16b38e555a5b17469578b69e479e8434cd257 Mon Sep 17 00:00:00 2001 From: Gerard Marull-Paretas Date: Fri, 12 Jan 2024 12:30:17 +0100 Subject: [PATCH 2212/3723] drivers: serial: b91: add missing RISC-V PLIC header Driver was using PLIC without including necessary headers. Signed-off-by: Gerard Marull-Paretas --- drivers/serial/uart_b91.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/serial/uart_b91.c b/drivers/serial/uart_b91.c index cb2d7ebd190..e2502f4fd9b 100644 --- a/drivers/serial/uart_b91.c +++ b/drivers/serial/uart_b91.c @@ -11,6 +11,7 @@ #include #include #include +#include /* Driver dts compatibility: telink,b91_uart */ From 6876f9eea1acce965be5ba8f7f786ee232e49029 Mon Sep 17 00:00:00 2001 From: Gerard Marull-Paretas Date: Wed, 10 Jan 2024 16:38:50 +0100 Subject: [PATCH 2213/3723] soc: riscv: riscv-privileged: drop soc_common.h The header file is no longer needed. Signed-off-by: Gerard Marull-Paretas --- soc/riscv/andes_v5/ae350/soc.h | 2 -- .../common/riscv-privileged/soc_common.h | 22 ------------------- soc/riscv/efinix_sapphire/soc.h | 1 - soc/riscv/gd_gd32/gd32vf103/soc.h | 2 -- soc/riscv/intel_niosv/niosv/soc.h | 1 - soc/riscv/litex_vexriscv/soc.h | 1 - soc/riscv/microchip_miv/miv/soc.h | 2 -- soc/riscv/microchip_miv/polarfire/soc.h | 1 - soc/riscv/neorv32/soc.h | 2 -- soc/riscv/opentitan/soc.h | 1 - soc/riscv/renode_virt/soc.h | 2 -- soc/riscv/sifive_freedom/e300/soc.h | 2 -- soc/riscv/sifive_freedom/u500/soc.h | 2 -- soc/riscv/sifive_freedom/u700/soc.h | 2 -- soc/riscv/starfive_jh71xx/jh71xx/soc.h | 2 -- soc/riscv/telink_tlsr/tlsr951x/soc.h | 2 -- soc/riscv/virt/soc.h | 2 -- 17 files changed, 49 deletions(-) delete mode 100644 soc/riscv/common/riscv-privileged/soc_common.h diff --git a/soc/riscv/andes_v5/ae350/soc.h b/soc/riscv/andes_v5/ae350/soc.h index 95ea7486fd3..fd3a9e63c0d 100644 --- a/soc/riscv/andes_v5/ae350/soc.h +++ b/soc/riscv/andes_v5/ae350/soc.h @@ -11,8 +11,6 @@ #ifndef __RISCV_ANDES_AE350_SOC_H_ #define __RISCV_ANDES_AE350_SOC_H_ -#include - /* Include CSRs available for Andes V5 SoCs */ #include "soc_v5.h" diff --git a/soc/riscv/common/riscv-privileged/soc_common.h b/soc/riscv/common/riscv-privileged/soc_common.h deleted file mode 100644 index f8f1c13cb59..00000000000 --- a/soc/riscv/common/riscv-privileged/soc_common.h +++ /dev/null @@ -1,22 +0,0 @@ -/* - * Copyright (c) 2017 Jean-Paul Etienne - * - * SPDX-License-Identifier: Apache-2.0 - */ - -/** - * @file configuration macros for riscv SOCs supporting the riscv - * privileged architecture specification - */ - -#ifndef __SOC_COMMON_H_ -#define __SOC_COMMON_H_ - -#ifndef _ASMLANGUAGE - -#include -#include - -#endif /* !_ASMLANGUAGE */ - -#endif /* __SOC_COMMON_H_ */ diff --git a/soc/riscv/efinix_sapphire/soc.h b/soc/riscv/efinix_sapphire/soc.h index 1d566e2f293..5530af16729 100644 --- a/soc/riscv/efinix_sapphire/soc.h +++ b/soc/riscv/efinix_sapphire/soc.h @@ -7,7 +7,6 @@ #ifndef __RISCV32_EFINIX_SAPPHIRE_SOC_H_ #define __RISCV32_EFINIX_SAPPHIRE_SOC_H_ -#include "soc_common.h" #include #include diff --git a/soc/riscv/gd_gd32/gd32vf103/soc.h b/soc/riscv/gd_gd32/gd32vf103/soc.h index 14cdd6b733c..ad2add6fa80 100644 --- a/soc/riscv/gd_gd32/gd32vf103/soc.h +++ b/soc/riscv/gd_gd32/gd32vf103/soc.h @@ -11,6 +11,4 @@ #ifndef RISCV_GD32VF103_SOC_H_ #define RISCV_GD32VF103_SOC_H_ -#include - #endif /* RISCV_GD32VF103_SOC_H */ diff --git a/soc/riscv/intel_niosv/niosv/soc.h b/soc/riscv/intel_niosv/niosv/soc.h index 8c10fec4540..87458c91dff 100644 --- a/soc/riscv/intel_niosv/niosv/soc.h +++ b/soc/riscv/intel_niosv/niosv/soc.h @@ -7,7 +7,6 @@ #ifndef RISCV_INTEL_FPGA_NIOSV_H #define RISCV_INTEL_FPGA_NIOSV_H -#include #include #endif /* RISCV_INTEL_FPGA_NIOSV_H */ diff --git a/soc/riscv/litex_vexriscv/soc.h b/soc/riscv/litex_vexriscv/soc.h index b3521b51e8e..4334be4ec1c 100644 --- a/soc/riscv/litex_vexriscv/soc.h +++ b/soc/riscv/litex_vexriscv/soc.h @@ -7,7 +7,6 @@ #ifndef __RISCV32_LITEX_VEXRISCV_SOC_H_ #define __RISCV32_LITEX_VEXRISCV_SOC_H_ -#include "../common/riscv-privileged/soc_common.h" #include #include diff --git a/soc/riscv/microchip_miv/miv/soc.h b/soc/riscv/microchip_miv/miv/soc.h index 1608c9e6773..c5827ceed21 100644 --- a/soc/riscv/microchip_miv/miv/soc.h +++ b/soc/riscv/microchip_miv/miv/soc.h @@ -4,8 +4,6 @@ #ifndef __RISCV32_MIV_SOC_H_ #define __RISCV32_MIV_SOC_H_ -#include - /* UART Configuration */ #define MIV_UART_0_LINECFG 0x1 diff --git a/soc/riscv/microchip_miv/polarfire/soc.h b/soc/riscv/microchip_miv/polarfire/soc.h index d6a7d2d2e37..f12bea7d533 100644 --- a/soc/riscv/microchip_miv/polarfire/soc.h +++ b/soc/riscv/microchip_miv/polarfire/soc.h @@ -6,7 +6,6 @@ #ifndef __RISCV64_MPFS_SOC_H_ #define __RISCV64_MPFS_SOC_H_ -#include #include diff --git a/soc/riscv/neorv32/soc.h b/soc/riscv/neorv32/soc.h index a1e721923a4..a97daa0fc15 100644 --- a/soc/riscv/neorv32/soc.h +++ b/soc/riscv/neorv32/soc.h @@ -7,8 +7,6 @@ #ifndef RISCV_NEORV32_SOC_H #define RISCV_NEORV32_SOC_H -#include - /* System information (SYSINFO) register offsets */ #define NEORV32_SYSINFO_CLK 0x00U #define NEORV32_SYSINFO_CPU 0x04U diff --git a/soc/riscv/opentitan/soc.h b/soc/riscv/opentitan/soc.h index 13bb5c43b54..c7f75beb877 100644 --- a/soc/riscv/opentitan/soc.h +++ b/soc/riscv/opentitan/soc.h @@ -7,7 +7,6 @@ #ifndef __RISCV_OPENTITAN_SOC_H_ #define __RISCV_OPENTITAN_SOC_H_ -#include #include /* OpenTitan power management regs. */ diff --git a/soc/riscv/renode_virt/soc.h b/soc/riscv/renode_virt/soc.h index c82e16f1613..3edef49c88c 100644 --- a/soc/riscv/renode_virt/soc.h +++ b/soc/riscv/renode_virt/soc.h @@ -7,6 +7,4 @@ #ifndef __RISCV32_RENODE_SOC_H_ #define __RISCV32_RENODE_SOC_H_ -#include - #endif /* __RISCV32_RENODE_SOC_H_ */ diff --git a/soc/riscv/sifive_freedom/e300/soc.h b/soc/riscv/sifive_freedom/e300/soc.h index c83f5f322b6..3c29efb2a71 100644 --- a/soc/riscv/sifive_freedom/e300/soc.h +++ b/soc/riscv/sifive_freedom/e300/soc.h @@ -11,8 +11,6 @@ #ifndef __RISCV_SIFIVE_FREEDOM_FE300_SOC_H_ #define __RISCV_SIFIVE_FREEDOM_FE300_SOC_H_ -#include - /* PINMUX MAX PINS */ #define SIFIVE_PINMUX_PINS 32 diff --git a/soc/riscv/sifive_freedom/u500/soc.h b/soc/riscv/sifive_freedom/u500/soc.h index ed367950278..1e18850787b 100644 --- a/soc/riscv/sifive_freedom/u500/soc.h +++ b/soc/riscv/sifive_freedom/u500/soc.h @@ -11,8 +11,6 @@ #ifndef __RISCV_SIFIVE_FREEDOM_U500_SOC_H_ #define __RISCV_SIFIVE_FREEDOM_U500_SOC_H_ -#include - /* Clock controller. */ #define PRCI_BASE_ADDR 0x10000000 diff --git a/soc/riscv/sifive_freedom/u700/soc.h b/soc/riscv/sifive_freedom/u700/soc.h index 91aac61afdd..2f15ba3b1cb 100644 --- a/soc/riscv/sifive_freedom/u700/soc.h +++ b/soc/riscv/sifive_freedom/u700/soc.h @@ -11,8 +11,6 @@ #ifndef __RISCV_SIFIVE_FREEDOM_U700_SOC_H_ #define __RISCV_SIFIVE_FREEDOM_U700_SOC_H_ -#include - /* Clock controller. */ #define PRCI_BASE_ADDR 0x10000000 diff --git a/soc/riscv/starfive_jh71xx/jh71xx/soc.h b/soc/riscv/starfive_jh71xx/jh71xx/soc.h index 796f07201d9..df3559c96e3 100644 --- a/soc/riscv/starfive_jh71xx/jh71xx/soc.h +++ b/soc/riscv/starfive_jh71xx/jh71xx/soc.h @@ -7,6 +7,4 @@ #ifndef __RISCV_VIRT_SOC_H_ #define __RISCV_VIRT_SOC_H_ -#include - #endif diff --git a/soc/riscv/telink_tlsr/tlsr951x/soc.h b/soc/riscv/telink_tlsr/tlsr951x/soc.h index a46b4c620c7..6acfd63dd02 100644 --- a/soc/riscv/telink_tlsr/tlsr951x/soc.h +++ b/soc/riscv/telink_tlsr/tlsr951x/soc.h @@ -7,6 +7,4 @@ #ifndef RISCV_TELINK_B91_SOC_H #define RISCV_TELINK_B91_SOC_H -#include - #endif /* RISCV_TELINK_B91_SOC_H */ diff --git a/soc/riscv/virt/soc.h b/soc/riscv/virt/soc.h index 8fd5e2108ce..d821c4653e6 100644 --- a/soc/riscv/virt/soc.h +++ b/soc/riscv/virt/soc.h @@ -7,8 +7,6 @@ #ifndef __RISCV_VIRT_SOC_H_ #define __RISCV_VIRT_SOC_H_ -#include - #define SIFIVE_SYSCON_TEST 0x00100000 #define RISCV_MSIP_BASE 0x02000000 From 972a4d9f6f82c811281fd53ef27a028bf2880955 Mon Sep 17 00:00:00 2001 From: Alberto Escolar Piedras Date: Thu, 11 Jan 2024 14:27:01 +0100 Subject: [PATCH 2214/3723] tests/kernel/context: Improve to resist parallel threads interrupting This test assumes that nothing will wake the CPU apart from the timer set by the test. But that is not necessarily the case. Some other platform thread started at boot may be waking the CPU every now and then. Let's allow for some spurious wakes while we are testing k_cpu_idle, while at the same time ensuring we are not just busy waiting all the way. Signed-off-by: Alberto Escolar Piedras --- tests/kernel/context/Kconfig | 14 ++++++++++++++ tests/kernel/context/src/main.c | 18 +++++++++++++----- 2 files changed, 27 insertions(+), 5 deletions(-) create mode 100644 tests/kernel/context/Kconfig diff --git a/tests/kernel/context/Kconfig b/tests/kernel/context/Kconfig new file mode 100644 index 00000000000..4f29151a471 --- /dev/null +++ b/tests/kernel/context/Kconfig @@ -0,0 +1,14 @@ +# Copyright (c) 2024 Nordic Semiconductor ASA +# SPDX-License-Identifier: Apache-2.0 + +config MAX_IDLE_WAKES + int "Maximum number of spurious wakes during k_cpu_idle() test" + default 1 if NRF53_SYNC_RTC + default 0 + help + The platform may have some component running in the background while the k_cpu_idle test is + running causing the CPU to awake. With this option we allow for a maximum number of wakes + for each 10ms idle test, which by default should be 0. + +# Include Zephyr's Kconfig +source "Kconfig" diff --git a/tests/kernel/context/src/main.c b/tests/kernel/context/src/main.c index a138e012280..ff0e0196c90 100644 --- a/tests/kernel/context/src/main.c +++ b/tests/kernel/context/src/main.c @@ -212,9 +212,12 @@ void irq_enable_wrapper(int irq) #if defined(CONFIG_TICKLESS_KERNEL) static struct k_timer idle_timer; +static volatile bool idle_timer_done; + static void idle_timer_expiry_function(struct k_timer *timer_id) { k_timer_stop(&idle_timer); + idle_timer_done = true; } static void _test_kernel_cpu_idle(int atomic) @@ -223,6 +226,7 @@ static void _test_kernel_cpu_idle(int atomic) unsigned int i, key; uint32_t dur = k_ms_to_ticks_ceil32(10); uint32_t slop = 1 + k_ms_to_ticks_ceil32(1); + int idle_loops; /* Set up a time to trigger events to exit idle mode */ k_timer_init(&idle_timer, idle_timer_expiry_function, NULL); @@ -230,13 +234,17 @@ static void _test_kernel_cpu_idle(int atomic) for (i = 0; i < 5; i++) { k_usleep(1); t0 = k_uptime_ticks(); + idle_loops = 0; + idle_timer_done = false; k_timer_start(&idle_timer, K_TICKS(dur), K_NO_WAIT); key = irq_lock(); - if (atomic) { - k_cpu_atomic_idle(key); - } else { - k_cpu_idle(); - } + do { + if (atomic) { + k_cpu_atomic_idle(key); + } else { + k_cpu_idle(); + } + } while ((idle_loops++ < CONFIG_MAX_IDLE_WAKES) && (idle_timer_done == false)); dt = k_uptime_ticks() - t0; zassert_true(abs((int32_t) (dt - dur)) <= slop, "Inaccurate wakeup, idled for %d ticks, expected %d", From b9bf596b34e0e4199a40ebf9d1880717f1c652bc Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Krzysztof=20Chru=C5=9Bci=C5=84ski?= Date: Fri, 12 Jan 2024 08:10:30 +0100 Subject: [PATCH 2215/3723] logging: Fix LOG_FMT_SECTION_STRIP Kconfig dependency MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Strings stripping was disallowed when LOG_OUTPUT was used. However, there is a dictionary log_output module which could work with stripped strings. Dependency is changed to LOG_DICTIONARY_SUPPORT. Signed-off-by: Krzysztof Chruściński --- subsys/logging/Kconfig.misc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/subsys/logging/Kconfig.misc b/subsys/logging/Kconfig.misc index 4b2d9fa143c..d333e19ce53 100644 --- a/subsys/logging/Kconfig.misc +++ b/subsys/logging/Kconfig.misc @@ -66,7 +66,7 @@ config LOG_FMT_SECTION config LOG_FMT_SECTION_STRIP bool "Strip log strings from binary" - depends on !LOG_OUTPUT + depends on LOG_DICTIONARY_SUPPORT depends on LOG_FMT_SECTION depends on LINKER_DEVNULL_SUPPORT imply LINKER_DEVNULL_MEMORY From 5bafa25e13697e2181c62a669477aed92e890fbb Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Krzysztof=20Chru=C5=9Bci=C5=84ski?= Date: Fri, 12 Jan 2024 08:13:45 +0100 Subject: [PATCH 2216/3723] logging: Use strings stripping for dictionary backends MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Enabled by default strings stripping for dictionary based backends. Signed-off-by: Krzysztof Chruściński --- subsys/logging/Kconfig.template.log_format_config | 2 ++ 1 file changed, 2 insertions(+) diff --git a/subsys/logging/Kconfig.template.log_format_config b/subsys/logging/Kconfig.template.log_format_config index 10150faafca..0b2dbe0d403 100644 --- a/subsys/logging/Kconfig.template.log_format_config +++ b/subsys/logging/Kconfig.template.log_format_config @@ -19,6 +19,8 @@ config LOG_BACKEND_$(backend)_OUTPUT_SYST config LOG_BACKEND_$(backend)_OUTPUT_DICTIONARY bool "Dictionary" select LOG_DICTIONARY_SUPPORT + imply LOG_FMT_SECTION + imply LOG_FMT_SECTION_STRIP help Backend is in dictionary-based logging output mode. From 7b42e36c68f3ecc476bb35b3066d5c5d8a639953 Mon Sep 17 00:00:00 2001 From: Damian Krolik Date: Fri, 12 Jan 2024 09:58:52 +0100 Subject: [PATCH 2217/3723] net: openthread: Print the actual assert location When OpenThread application is built with CONFIG_ASSERT and CONFIG_ASSERT_NO_MSG_INFO, OT_ASSERT() prints a location that points to the otPlatAssertFail() function instead of the code that actually failed an assertion. This is confusing and CONFIG_ASSERT_NO_MSG_INFO sometimes cannot be disabled because of flash size limitations. Make otPlatAssertFail() always print the actual assert location. Signed-off-by: Damian Krolik --- modules/openthread/platform/misc.c | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/modules/openthread/platform/misc.c b/modules/openthread/platform/misc.c index 11fdc42ec34..5f9043dfa27 100644 --- a/modules/openthread/platform/misc.c +++ b/modules/openthread/platform/misc.c @@ -99,5 +99,10 @@ void otPlatWakeHost(void) void otPlatAssertFail(const char *aFilename, int aLineNumber) { - __ASSERT(false, "OpenThread ASSERT @ %s:%d", aFilename, aLineNumber); + /* + * The code below is used instead of __ASSERT(false) to print the actual assert + * location instead of __FILE__:__LINE__, which would point to this function. + */ + __ASSERT_PRINT("OpenThread ASSERT @ %s:%d\n", aFilename, aLineNumber); + __ASSERT_POST_ACTION(); } From 75c2aeb8bd02ed26142714377bfa6e1d8bef03b7 Mon Sep 17 00:00:00 2001 From: Jonathan Rico Date: Thu, 11 Jan 2024 10:47:22 +0100 Subject: [PATCH 2218/3723] Bluetooth: L2CAP: stop stealing buffers from SDU pool It seems like a nice idea at first, but leads to hard-to-debug situations for the application. The previous behavior can be implemented by the app by defining `alloc_seg` and allocating from the same pool as `buf`. Signed-off-by: Jonathan Rico --- doc/releases/migration-guide-3.6.rst | 4 ++++ include/zephyr/bluetooth/l2cap.h | 7 ++++--- subsys/bluetooth/host/l2cap.c | 17 ++++++++--------- 3 files changed, 16 insertions(+), 12 deletions(-) diff --git a/doc/releases/migration-guide-3.6.rst b/doc/releases/migration-guide-3.6.rst index 38e819d840d..8dc1b1f1ff2 100644 --- a/doc/releases/migration-guide-3.6.rst +++ b/doc/releases/migration-guide-3.6.rst @@ -241,6 +241,10 @@ Bluetooth Any pointer to a UUID must be prefixed with `const`, otherwise there will be a compilation warning. For example change ``struct bt_uuid *uuid = BT_UUID_DECLARE_16(xx)`` to ``const struct bt_uuid *uuid = BT_UUID_DECLARE_16(xx)``. (:github:`66136`) +* The :c:func:`bt_l2cap_chan_send` API no longer allocates buffers from the same pool as its `buf` + parameter when segmenting SDUs into PDUs. In order to reproduce the previous behavior, the + application should register the `alloc_seg` channel callback and allocate from the same pool as + `buf`. * Mesh diff --git a/include/zephyr/bluetooth/l2cap.h b/include/zephyr/bluetooth/l2cap.h index 3386c38bdb3..f688595f604 100644 --- a/include/zephyr/bluetooth/l2cap.h +++ b/include/zephyr/bluetooth/l2cap.h @@ -587,9 +587,10 @@ int bt_l2cap_chan_disconnect(struct bt_l2cap_chan *chan); * If the application is reserving the bytes it should use the * BT_L2CAP_BUF_SIZE() helper to correctly size the buffers for the for the * outgoing buffer pool. - * When segmenting an L2CAP SDU into L2CAP PDUs the stack will first attempt - * to allocate buffers from the original buffer pool of the L2CAP SDU before - * using the stacks own buffer pool. + * When segmenting an L2CAP SDU into L2CAP PDUs the stack will first attempt to + * allocate buffers from the channel's `alloc_seg` callback and will fallback + * on the stack's global buffer pool (sized + * @kconfig{CONFIG_BT_L2CAP_TX_BUF_COUNT}). * * @note Buffer ownership is transferred to the stack in case of success, in * case of an error the caller retains the ownership of the buffer. diff --git a/subsys/bluetooth/host/l2cap.c b/subsys/bluetooth/host/l2cap.c index 44a013f14b9..e511d44d12b 100644 --- a/subsys/bluetooth/host/l2cap.c +++ b/subsys/bluetooth/host/l2cap.c @@ -1818,25 +1818,24 @@ static void le_disconn_rsp(struct bt_l2cap *l2cap, uint8_t ident, static inline struct net_buf *l2cap_alloc_seg(struct net_buf *buf, struct bt_l2cap_le_chan *ch) { - struct net_buf_pool *pool = net_buf_pool_get(buf->pool_id); - struct net_buf *seg; + struct net_buf *seg = NULL; - /* Use the dedicated segment callback if registered */ + /* Use the user-defined allocator */ if (ch->chan.ops->alloc_seg) { seg = ch->chan.ops->alloc_seg(&ch->chan); __ASSERT_NO_MSG(seg); - } else { - /* Try to use original pool if possible */ - seg = net_buf_alloc(pool, K_NO_WAIT); + } + + /* Fallback to using global connection tx pool */ + if (!seg) { + seg = bt_l2cap_create_pdu_timeout(NULL, 0, K_NO_WAIT); } if (seg) { net_buf_reserve(seg, BT_L2CAP_CHAN_SEND_RESERVE); - return seg; } - /* Fallback to using global connection tx pool */ - return bt_l2cap_create_pdu_timeout(NULL, 0, K_NO_WAIT); + return seg; } static struct net_buf *l2cap_chan_create_seg(struct bt_l2cap_le_chan *ch, From ca12fd13c6d34df02c3ad801f23b319911e4725b Mon Sep 17 00:00:00 2001 From: Guennadi Liakhovetski Date: Fri, 12 Jan 2024 14:14:46 +0100 Subject: [PATCH 2219/3723] xtensa: intel_adsp: fix a cache handling error .bss and .data are uncached in Zephyr builds for intel_adsp. No need to try to manipulate cache of objects in those sections. Signed-off-by: Guennadi Liakhovetski --- drivers/power_domain/power_domain_intel_adsp.c | 2 +- soc/xtensa/intel_adsp/ace/multiprocessing.c | 8 +++++--- 2 files changed, 6 insertions(+), 4 deletions(-) diff --git a/drivers/power_domain/power_domain_intel_adsp.c b/drivers/power_domain/power_domain_intel_adsp.c index 9fa66e5ab96..fa65257a214 100644 --- a/drivers/power_domain/power_domain_intel_adsp.c +++ b/drivers/power_domain/power_domain_intel_adsp.c @@ -39,7 +39,7 @@ static int pd_intel_adsp_set_power_enable(struct pg_bits *bits, bool power_enabl extern uint32_t g_key_read_holder; if (bits->SPA_bit == INTEL_ADSP_HST_DOMAIN_BIT) { - volatile uint32_t *key_read_ptr = z_soc_uncached_ptr(&g_key_read_holder); + volatile uint32_t *key_read_ptr = &g_key_read_holder; uint32_t key_value = *key_read_ptr; if (key_value != INTEL_ADSP_ACE15_MAGIC_KEY) diff --git a/soc/xtensa/intel_adsp/ace/multiprocessing.c b/soc/xtensa/intel_adsp/ace/multiprocessing.c index fbdc146c6c7..96c9d1ac3a1 100644 --- a/soc/xtensa/intel_adsp/ace/multiprocessing.c +++ b/soc/xtensa/intel_adsp/ace/multiprocessing.c @@ -8,6 +8,7 @@ #include #include #include +#include #include #include @@ -27,8 +28,8 @@ #define ACE_INTC_IRQ DT_IRQN(DT_NODELABEL(ace_intc)) #if CONFIG_ACE_VERSION_1_5 -__aligned(CONFIG_DCACHE_LINE_SIZE) uint32_t g_key_read_holder; -__aligned(CONFIG_DCACHE_LINE_SIZE) unsigned int alignment_dummy[0]; +/* .bss is uncached, we further check it below */ +uint32_t g_key_read_holder; #endif /* CONFIG_ACE_VERSION_1_5 */ static void ipc_isr(void *arg) @@ -93,8 +94,9 @@ void soc_mp_init(void) /* Set the core 0 active */ soc_cpus_active[0] = true; #if CONFIG_ACE_VERSION_1_5 + __ASSERT(!arch_xtensa_is_ptr_cached(&g_key_read_holder), + "g_key_read_holder must be uncached"); g_key_read_holder = INTEL_ADSP_ACE15_MAGIC_KEY; - sys_cache_data_flush_range(&g_key_read_holder, sizeof(g_key_read_holder)); #endif /* CONFIG_ACE_VERSION_1_5 */ } From 70c7ac704d1206e0e0e53d1d7d22f50f3ce4c975 Mon Sep 17 00:00:00 2001 From: Pisit Sawangvonganan Date: Sat, 13 Jan 2024 00:55:44 +0700 Subject: [PATCH 2220/3723] drivers: i2c: correct spelling Employ a code spell checking tool to scan and correct spelling errors in all files within the drivers/i2c directory. Signed-off-by: Pisit Sawangvonganan --- drivers/i2c/Kconfig.dw | 4 ++-- drivers/i2c/i2c_dw.c | 4 ++-- drivers/i2c/i2c_ifx_xmc4.c | 4 ++-- drivers/i2c/i2c_ite_enhance.c | 2 +- drivers/i2c/i2c_ll_stm32_v1.c | 2 +- drivers/i2c/i2c_npcx_controller.c | 2 +- drivers/i2c/i2c_npcx_controller.h | 2 +- 7 files changed, 10 insertions(+), 10 deletions(-) diff --git a/drivers/i2c/Kconfig.dw b/drivers/i2c/Kconfig.dw index c84215f4571..796cfb643d1 100644 --- a/drivers/i2c/Kconfig.dw +++ b/drivers/i2c/Kconfig.dw @@ -18,6 +18,6 @@ config I2C_DW_LPSS_DMA select DMA select DMA_INTEL_LPSS help - This option enables I2C DMA feature to be used for asynchrounous - data transfers. All Tx operaton are done using dma channel 0 and + This option enables I2C DMA feature to be used for asynchronous + data transfers. All Tx operations are done using dma channel 0 and all Rx operations are done using dma channel 1. diff --git a/drivers/i2c/i2c_dw.c b/drivers/i2c/i2c_dw.c index 443bee9059c..b198aa15c1b 100644 --- a/drivers/i2c/i2c_dw.c +++ b/drivers/i2c/i2c_dw.c @@ -187,7 +187,7 @@ int32_t i2c_dw_idma_tx_transfer(const struct device *dev, } if (dma_start(rom->dma_dev, DMA_INTEL_LPSS_TX_CHAN)) { - LOG_DBG("Error trnasfer"); + LOG_DBG("Error transfer"); return -EIO; } i2c_dw_enable_idma(dev, true); @@ -909,7 +909,7 @@ static int i2c_dw_set_slave_mode(const struct device *dev, uint8_t addr) write_tx_tl(0, reg_base); write_rx_tl(0, reg_base); - LOG_DBG("I2C: Host registed as Slave Device"); + LOG_DBG("I2C: Host registered as Slave Device"); return 0; } diff --git a/drivers/i2c/i2c_ifx_xmc4.c b/drivers/i2c/i2c_ifx_xmc4.c index 43714cce618..82994eae077 100644 --- a/drivers/i2c/i2c_ifx_xmc4.c +++ b/drivers/i2c/i2c_ifx_xmc4.c @@ -194,7 +194,7 @@ static int ifx_xmc4_i2c_transfer(const struct device *dev, struct i2c_msg *msg, XMC_I2C_CH_ClearStatusFlag(config->i2c, 0xFFFFFFFF); if ((msg_index == 0) || (msg[msg_index].flags & I2C_MSG_RESTART)) { - /* Send START conditon */ + /* Send START condition */ cmd_type = ((msg[msg_index].flags & I2C_MSG_RW_MASK) == I2C_MSG_READ) ? XMC_I2C_CH_CMD_READ : XMC_I2C_CH_CMD_WRITE; @@ -272,7 +272,7 @@ static int ifx_xmc4_i2c_transfer(const struct device *dev, struct i2c_msg *msg, } } - /* Send STOP conditon */ + /* Send STOP condition */ if (msg[msg_index].flags & I2C_MSG_STOP) { XMC_I2C_CH_MasterStop(config->i2c); } diff --git a/drivers/i2c/i2c_ite_enhance.c b/drivers/i2c/i2c_ite_enhance.c index 1d26ade56c1..c1fbf6cc86c 100644 --- a/drivers/i2c/i2c_ite_enhance.c +++ b/drivers/i2c/i2c_ite_enhance.c @@ -1011,7 +1011,7 @@ static void target_i2c_isr_dma(const struct device *dev, &rdata, &len); if (len > CONFIG_I2C_TARGET_IT8XXX2_MAX_BUF_SIZE) { - LOG_ERR("The bufffer size exceeds " + LOG_ERR("The buffer size exceeds " "I2C_TARGET_IT8XXX2_MAX_BUF_SIZE: len=%d", len); } else { diff --git a/drivers/i2c/i2c_ll_stm32_v1.c b/drivers/i2c/i2c_ll_stm32_v1.c index 4730cc15598..ff63ee39913 100644 --- a/drivers/i2c/i2c_ll_stm32_v1.c +++ b/drivers/i2c/i2c_ll_stm32_v1.c @@ -899,7 +899,7 @@ static int32_t stm32_i2c_msg_read(const struct device *dev, struct i2c_msg *msg, } } /* ADDR must be cleared before NACK generation. Either in 2 byte reception - * byte 1 will be NACK'ed and slave wont sent the last byte + * byte 1 will be NACK'ed and slave won't sent the last byte */ LL_I2C_ClearFlag_ADDR(i2c); if (len == 1U) { diff --git a/drivers/i2c/i2c_npcx_controller.c b/drivers/i2c/i2c_npcx_controller.c index 9cd4a02970b..5dbdbc65aa9 100644 --- a/drivers/i2c/i2c_npcx_controller.c +++ b/drivers/i2c/i2c_npcx_controller.c @@ -801,7 +801,7 @@ static void i2c_ctrl_target_isr(const struct device *dev, uint8_t status) /* Clear NMATCH Bit */ inst->SMBST = BIT(NPCX_SMBST_NMATCH); - /* Distinguish tje direction of i2c target mode by reading XMIT bit */ + /* Distinguish the direction of i2c target mode by reading XMIT bit */ if (IS_BIT_SET(inst->SMBST, NPCX_SMBST_XMIT)) { /* Start transmitting data in i2c target mode */ data->oper_state = NPCX_I2C_WRITE_FIFO; diff --git a/drivers/i2c/i2c_npcx_controller.h b/drivers/i2c/i2c_npcx_controller.h index 08338244043..6155f1a1499 100644 --- a/drivers/i2c/i2c_npcx_controller.h +++ b/drivers/i2c/i2c_npcx_controller.h @@ -70,7 +70,7 @@ int npcx_i2c_ctrl_transfer(const struct device *i2c_dev, struct i2c_msg *msgs, uint8_t num_msgs, uint16_t addr, uint8_t port); /** - * @brief Toggle the SCL to generate maxmium 9 clocks until the target release + * @brief Toggle the SCL to generate maximum 9 clocks until the target release * the SDA line and send a STOP condition. * * @param i2c_dev Pointer to the device structure for i2c controller instance. From 00cfab6cfc0e981228198f58070ab6f21cb9f5bf Mon Sep 17 00:00:00 2001 From: Nick Ward Date: Sat, 13 Jan 2024 15:31:28 +1100 Subject: [PATCH 2221/3723] mgmt: mcumgr: use delayed workqueue for reset Same behaviour, less code, smaller code size. Signed-off-by: Nick Ward --- subsys/mgmt/mcumgr/grp/os_mgmt/src/os_mgmt.c | 17 ++++++----------- 1 file changed, 6 insertions(+), 11 deletions(-) diff --git a/subsys/mgmt/mcumgr/grp/os_mgmt/src/os_mgmt.c b/subsys/mgmt/mcumgr/grp/os_mgmt/src/os_mgmt.c index 13de45f02a9..7eef7f398f7 100644 --- a/subsys/mgmt/mcumgr/grp/os_mgmt/src/os_mgmt.c +++ b/subsys/mgmt/mcumgr/grp/os_mgmt/src/os_mgmt.c @@ -59,10 +59,8 @@ LOG_MODULE_REGISTER(mcumgr_os_grp, CONFIG_MCUMGR_GRP_OS_LOG_LEVEL); #ifdef CONFIG_REBOOT static void os_mgmt_reset_work_handler(struct k_work *work); -static void os_mgmt_reset_cb(struct k_timer *timer); -K_WORK_DEFINE(os_mgmt_reset_work, os_mgmt_reset_work_handler); -static K_TIMER_DEFINE(os_mgmt_reset_timer, os_mgmt_reset_cb, NULL); +K_WORK_DELAYABLE_DEFINE(os_mgmt_reset_work, os_mgmt_reset_work_handler); #endif /* This is passed to zcbor_map_start/end_endcode as a number of @@ -358,13 +356,9 @@ static int os_mgmt_taskstat_read(struct smp_streamer *ctxt) */ static void os_mgmt_reset_work_handler(struct k_work *work) { - sys_reboot(SYS_REBOOT_WARM); -} + ARG_UNUSED(work); -static void os_mgmt_reset_cb(struct k_timer *timer) -{ - /* Reboot the system from the system workqueue thread. */ - k_work_submit(&os_mgmt_reset_work); + sys_reboot(SYS_REBOOT_WARM); } static int os_mgmt_reset(struct smp_streamer *ctxt) @@ -404,8 +398,9 @@ static int os_mgmt_reset(struct smp_streamer *ctxt) } #endif - k_timer_start(&os_mgmt_reset_timer, K_MSEC(CONFIG_MCUMGR_GRP_OS_RESET_MS), - K_NO_WAIT); + /* Reboot the system from the system workqueue thread. */ + k_work_schedule(&os_mgmt_reset_work, K_MSEC(CONFIG_MCUMGR_GRP_OS_RESET_MS)); + return 0; } #endif From 8042e73915c46e14891991810006537a46e1f5ac Mon Sep 17 00:00:00 2001 From: Marc Herbert Date: Fri, 12 Jan 2024 21:45:25 +0000 Subject: [PATCH 2222/3723] dai: intel: dmic: demote spurious LOG_ERR in dai_nhlt_get_clock_div() Fix the log level of two LOG_ERR() statements which should have always been LOG_INF(). As confirmed by the author Adrian in #60172 Fixes commit 3fbaed4de9b2 ("dai: intel: ace: dmic: Refactor of dai_nhlt_dmic_dai_params_get function") Signed-off-by: Marc Herbert --- drivers/dai/intel/dmic/dmic_nhlt.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/dai/intel/dmic/dmic_nhlt.c b/drivers/dai/intel/dmic/dmic_nhlt.c index 17a8f385a02..3d803da33b9 100644 --- a/drivers/dai/intel/dmic/dmic_nhlt.c +++ b/drivers/dai/intel/dmic/dmic_nhlt.c @@ -139,12 +139,12 @@ static int dai_nhlt_get_clock_div(const struct dai_intel_dmic *dmic, const int p val = dai_dmic_read(dmic, dmic_base[pdm] + FIR_CHANNEL_REGS_SIZE * dmic->dai_config_params.dai_index + FIR_CONFIG); - LOG_ERR("pdm = %d, FIR_CONFIG = 0x%08X", pdm, val); + LOG_INF("pdm = %d, FIR_CONFIG = 0x%08X", pdm, val); p_mfir = FIELD_GET(FIR_CONFIG_FIR_DECIMATION, val) + 1; rate_div = p_clkdiv * p_mcic * p_mfir; - LOG_ERR("dai_index = %d, rate_div = %d, p_clkdiv = %d, p_mcic = %d, p_mfir = %d", + LOG_INF("dai_index = %d, rate_div = %d, p_clkdiv = %d, p_mcic = %d, p_mfir = %d", dmic->dai_config_params.dai_index, rate_div, p_clkdiv, p_mcic, p_mfir); if (!rate_div) { From ca8ee0e029802afc44fbd85594dfcb5ed240bcff Mon Sep 17 00:00:00 2001 From: Aaron Ye Date: Thu, 11 Jan 2024 11:37:52 +0800 Subject: [PATCH 2223/3723] boards: arm: apollo4p_blue_kxr_evb: Move the bt-spi instance to soc dts Since the pins of bt-spi instance are wired internally in the chip, it will make sense to move the definition to soc dts so no need for every board using the chip to redefine the same. Signed-off-by: Aaron Ye --- .../apollo4p_blue_kxr_evb.dts | 11 ----------- dts/arm/ambiq/ambiq_apollo4p_blue.dtsi | 14 +++++++++++++- 2 files changed, 13 insertions(+), 12 deletions(-) diff --git a/boards/arm/apollo4p_blue_kxr_evb/apollo4p_blue_kxr_evb.dts b/boards/arm/apollo4p_blue_kxr_evb/apollo4p_blue_kxr_evb.dts index cb4014a4f08..f9aa3c11c31 100644 --- a/boards/arm/apollo4p_blue_kxr_evb/apollo4p_blue_kxr_evb.dts +++ b/boards/arm/apollo4p_blue_kxr_evb/apollo4p_blue_kxr_evb.dts @@ -87,20 +87,9 @@ }; &iom4 { - compatible = "ambiq,spi"; pinctrl-0 = <&spi4_default>; pinctrl-names = "default"; - cs-gpios = <&gpio32_63 22 (GPIO_ACTIVE_LOW | GPIO_PULL_UP)>; - clock-frequency = ; status = "okay"; - - bt-hci@0 { - compatible = "ambiq,bt-hci-spi"; - reg = <0>; - irq-gpios = <&gpio32_63 21 GPIO_ACTIVE_HIGH>; - reset-gpios = <&gpio32_63 23 GPIO_ACTIVE_LOW>; - clkreq-gpios = <&gpio32_63 20 GPIO_ACTIVE_HIGH>; - }; }; &mspi0 { diff --git a/dts/arm/ambiq/ambiq_apollo4p_blue.dtsi b/dts/arm/ambiq/ambiq_apollo4p_blue.dtsi index 5df5c7d4b47..dfc2f59de3d 100644 --- a/dts/arm/ambiq/ambiq_apollo4p_blue.dtsi +++ b/dts/arm/ambiq/ambiq_apollo4p_blue.dtsi @@ -160,13 +160,25 @@ ambiq,pwrcfg = <&pwrcfg 0x4 0x10>; }; - iom4: iom@40054000 { + iom4: spi@40054000 { + /* IOM4 works as SPI and is wired internally for BLE HCI. */ + compatible = "ambiq,spi"; reg = <0x40054000 0x1000>; #address-cells = <1>; #size-cells = <0>; interrupts = <10 0>; + cs-gpios = <&gpio32_63 22 (GPIO_ACTIVE_LOW | GPIO_PULL_UP)>; + clock-frequency = ; status = "disabled"; ambiq,pwrcfg = <&pwrcfg 0x4 0x20>; + + bt-hci@0 { + compatible = "ambiq,bt-hci-spi"; + reg = <0>; + irq-gpios = <&gpio32_63 21 GPIO_ACTIVE_HIGH>; + reset-gpios = <&gpio32_63 23 GPIO_ACTIVE_LOW>; + clkreq-gpios = <&gpio32_63 20 GPIO_ACTIVE_HIGH>; + }; }; iom5: iom@40055000 { From d4b0273ab0c46a3319beef3440a2769a6d5b3f19 Mon Sep 17 00:00:00 2001 From: Marc Herbert Date: Wed, 27 Dec 2023 23:31:11 +0000 Subject: [PATCH 2224/3723] cmake: sparse.template: add COMMAND_ERROR_IS_FATAL There are some situations like #67035 where sparse aborts and returns an error code before the compiler has generated the .obj file; without any clear indication that the .obj is missing (in normal situations sparse prints warnings and _does_ creates the .obj file) Also, builds are parallel by default and sparse runs tend to be massive walls of text which all conspires to make it totally impossible to find the relevant error message. Instead, we get an link-time error. The only clear indication is the exit code. So catch it and abort the build ASAP thanks to COMMAND_ERROR_IS_FATAL. More generally speaking, the default behavior of execute_process() to ignore errors is crazy. How frequently does a build system run commands that do NOT matter? Signed-off-by: Marc Herbert --- cmake/sca/sparse/sparse.template | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/cmake/sca/sparse/sparse.template b/cmake/sca/sparse/sparse.template index 8fde837aa26..b54d3e9ed14 100644 --- a/cmake/sca/sparse/sparse.template +++ b/cmake/sca/sparse/sparse.template @@ -16,4 +16,6 @@ endforeach() foreach(i RANGE ${end_of_options} ${CMAKE_ARGC}) list(APPEND ARGS ${CMAKE_ARGV${i}}) endforeach() -execute_process(COMMAND @CMAKE_COMMAND@ -E env REAL_CC=@CMAKE_C_COMPILER@ @SPARSE_COMPILER@ ${ARGS}) +execute_process(COMMAND @CMAKE_COMMAND@ -E env REAL_CC=@CMAKE_C_COMPILER@ @SPARSE_COMPILER@ ${ARGS} + COMMAND_ERROR_IS_FATAL ANY +) From bccec3cccd444896c1343dc3629e1e204a527008 Mon Sep 17 00:00:00 2001 From: Fabian Pflug Date: Thu, 11 Jan 2024 17:36:12 +0100 Subject: [PATCH 2225/3723] doc: twister: fix spelling errors Fis spelling errors in twister doc Signed-off-by: Fabian Pflug --- doc/develop/test/twister.rst | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/doc/develop/test/twister.rst b/doc/develop/test/twister.rst index beaf1284868..be24732e1ba 100644 --- a/doc/develop/test/twister.rst +++ b/doc/develop/test/twister.rst @@ -347,7 +347,7 @@ build_only: (default False) This option is often used to test drivers and the fact that they are correctly enabled in Zephyr and that the code builds, for example sensor drivers. Such - test shall not be used to verify the functionality of the dritver. + test shall not be used to verify the functionality of the driver. build_on_all: (default False) If true, attempt to build test on all available platforms. This is mostly @@ -473,7 +473,7 @@ platform_key: Adding platform (board) attributes to include things such as soc name, soc family, and perhaps sets of IP blocks implementing each peripheral interface would enable other interesting uses. For example, this could enable - building and running SPI tests once for eacn unique IP block. + building and running SPI tests once for each unique IP block. harness_config: Extra harness configuration options to be used to select a board and/or @@ -498,7 +498,7 @@ harness_config: record: (optional) regex: (required) - The regular experssion with named subgroups to match data fields + The regular expression with named subgroups to match data fields at the test's output lines where the test provides some custom data for further analysis. These records will be written into the build directory 'recording.csv' file as well as 'recording' property @@ -1124,7 +1124,7 @@ using an external J-Link probe. The ``probe_id`` keyword overrides the Quarantine ++++++++++ -Twister allows user to provide onfiguration files defining a list of tests or +Twister allows user to provide configuration files defining a list of tests or platforms to be put under quarantine. Such tests will be skipped and marked accordingly in the output reports. This feature is especially useful when running larger test suits, where a failure of one test can affect the execution @@ -1177,7 +1177,7 @@ Additionally you can quarantine entire architectures or a specific simulator for Test Configuration ****************** -A test configuration can be used to customize various apects of twister +A test configuration can be used to customize various aspects of twister and the default enabled options and features. This allows tweaking the filtering capabilities depending on the environment and makes it possible to adapt and improve coverage when targeting different sets of platforms. @@ -1187,7 +1187,7 @@ assign a specific test to one or more levels. Using command line options of twister it is then possible to select a level and just execute the tests included in this level. -Additionally, the test configuration allows defining level +Additionally, the test configuration allows defining level dependencies and additional inclusion of tests into a specific level if the test itself does not have this information already. @@ -1204,7 +1204,7 @@ locally. As of now, those options are available: CI) - Option to specify your own list of default platforms overriding what upstream defines. -- Ability to override `build_onl_all` options used in some testcases. +- Ability to override `build_on_all` options used in some testcases. This will treat tests or sample as any other just build for default platforms you specify in the configuration file or on the command line. - Ignore some logic in twister to expand platform coverage in cases where @@ -1269,7 +1269,7 @@ Combined configuration To mix the Platform and level configuration, you can take an example as below: -And example platforms plus level configuration: +An example platforms plus level configuration: .. code-block:: yaml @@ -1298,7 +1298,7 @@ And example platforms plus level configuration: A plan to be used verifying regression. -To run with above test_config.yaml file, only default_paltforms with given test level +To run with above test_config.yaml file, only default_platforms with given test level test cases will run. .. tabs:: From 460b6ef122f76a634e967b2e13315dd9099cc14e Mon Sep 17 00:00:00 2001 From: Grzegorz Swiderski Date: Fri, 12 Jan 2024 06:06:36 +0100 Subject: [PATCH 2226/3723] code_relocation: Add NOKEEP option When using the code and data relocation feature, every relocated symbol would be marked with `KEEP()` in the generated linker script. Therefore, if any input files contained unused code, then it wouldn't be discarded by the linker, even when invoked with `--gc-sections`. This can cause unexpected bloat, or other link-time issues stemming from some symbols being discarded and others not. On the other hand, this behavior has been present since the feature's introduction, so it should remain default for the users who rely on it. This patch introduces support for `zephyr_code_relocate(... NOKEEP)`. This will suppress the generation of `KEEP()` statements for all symbols in a particular library or set of files. Much like `NOCOPY`, the `NOKEEP` flag is passed to `gen_relocate_app.py` in string form. The script is now equipped to handle multiple such flags when passed from CMake as a semicolon-separated list, like so: "SRAM2:NOCOPY;NOKEEP:/path/to/file1.c;/path/to/file2.c" Documentation and tests are updated here as well. Signed-off-by: Grzegorz Swiderski --- cmake/modules/extensions.cmake | 20 ++++--- doc/kernel/code-relocation.rst | 16 ++++++ scripts/build/gen_relocate_app.py | 55 ++++++++++++------- .../code_relocation/CMakeLists.txt | 5 +- 4 files changed, 67 insertions(+), 29 deletions(-) diff --git a/cmake/modules/extensions.cmake b/cmake/modules/extensions.cmake index 5a216fc1a79..e2904066e7a 100644 --- a/cmake/modules/extensions.cmake +++ b/cmake/modules/extensions.cmake @@ -1330,9 +1330,11 @@ endmacro() # The following optional arguments are supported: # - NOCOPY: this flag indicates that the file data does not need to be copied # at boot time (For example, for flash XIP). +# - NOKEEP: suppress the generation of KEEP() statements in the linker script, +# to allow any unused code in the given files/library to be discarded. # - PHDR [program_header]: add program header. Used on Xtensa platforms. function(zephyr_code_relocate) - set(options NOCOPY) + set(options NOCOPY NOKEEP) set(single_args LIBRARY LOCATION PHDR) set(multi_args FILES) cmake_parse_arguments(CODE_REL "${options}" "${single_args}" @@ -1392,21 +1394,25 @@ function(zephyr_code_relocate) endif() endif() if(NOT CODE_REL_NOCOPY) - set(copy_flag COPY) + set(flag_list COPY) else() - set(copy_flag NOCOPY) + set(flag_list NOCOPY) + endif() + if(CODE_REL_NOKEEP) + list(APPEND flag_list NOKEEP) endif() if(CODE_REL_PHDR) set(CODE_REL_LOCATION "${CODE_REL_LOCATION}\ :${CODE_REL_PHDR}") endif() - # We use the "|" character to separate code relocation directives instead - # of using CMake lists. This way, the ";" character can be reserved for - # generator expression file lists. + # We use the "|" character to separate code relocation directives, instead of + # using set_property(APPEND) to produce a ";"-separated CMake list. This way, + # each directive can embed multiple CMake lists, representing flags and files, + # the latter of which can come from generator expressions. get_property(code_rel_str TARGET code_data_relocation_target PROPERTY COMPILE_DEFINITIONS) set_property(TARGET code_data_relocation_target PROPERTY COMPILE_DEFINITIONS - "${code_rel_str}|${CODE_REL_LOCATION}:${copy_flag}:${file_list}") + "${code_rel_str}|${CODE_REL_LOCATION}:${flag_list}:${file_list}") endfunction() # Usage: diff --git a/doc/kernel/code-relocation.rst b/doc/kernel/code-relocation.rst index a9da18e98cd..599cdedccbd 100644 --- a/doc/kernel/code-relocation.rst +++ b/doc/kernel/code-relocation.rst @@ -97,6 +97,22 @@ This section shows additional configuration options that can be set in zephyr_code_relocate(FILES ${sources} LOCATION SRAM) zephyr_code_relocate(FILES $ LOCATION SRAM) +NOKEEP flag +=========== + +By default, all relocated functions and variables will be marked with ``KEEP()`` +when generating ``linker_relocate.ld``. Therefore, if any input file happens to +contain unused symbols, then they will not be discarded by the linker, even when +it is invoked with ``--gc-sections``. If you'd like to override this behavior, +you can pass ``NOKEEP`` to your ``zephyr_code_relocate()`` call. + + .. code-block:: none + + zephyr_code_relocate(FILES src/file1.c LOCATION SRAM2_TEXT NOKEEP) + +The example above will help ensure that any unused code found in the .text +sections of ``file1.c`` will not stick to SRAM2. + NOCOPY flag =========== diff --git a/scripts/build/gen_relocate_app.py b/scripts/build/gen_relocate_app.py index 1d7783cd38a..f1bcccf1df6 100644 --- a/scripts/build/gen_relocate_app.py +++ b/scripts/build/gen_relocate_app.py @@ -33,6 +33,8 @@ ignored. - COPY/NOCOPY defines whether the script should generate the relocation code in code_relocation.c or not +- NOKEEP will suppress the default behavior of marking every relocated symbol + with KEEP() in the generated linker script. Multiple regions can be appended together like SRAM2_DATA_BSS this will place data and bss inside SRAM2. @@ -94,12 +96,17 @@ def for_section_named(cls, name: str): class OutputSection(NamedTuple): obj_file_name: str section_name: str + keep: bool = True PRINT_TEMPLATE = """ KEEP(*{obj_file_name}({section_name})) """ +PRINT_TEMPLATE_NOKEEP = """ + *{obj_file_name}({section_name}) +""" + SECTION_LOAD_MEMORY_SEQ = """ __{0}_{1}_rom_start = LOADADDR(.{0}_{1}_reloc); """ @@ -274,10 +281,16 @@ def assign_to_correct_mem_region( if align_size: mpu_align[memory_region] = int(align_size) + keep_sections = '|NOKEEP' not in memory_region + memory_region = memory_region.replace('|NOKEEP', '') + output_sections = {} for used_kind in use_section_kinds: # Pass through section kinds that go into this memory region - output_sections[used_kind] = full_list_of_sections[used_kind] + output_sections[used_kind] = [ + section._replace(keep=keep_sections) + for section in full_list_of_sections[used_kind] + ] return {MemoryRegion(memory_region): output_sections} @@ -308,10 +321,12 @@ def section_kinds_from_memory_region(memory_region: str) -> 'Tuple[set[SectionKi def print_linker_sections(list_sections: 'list[OutputSection]'): - return ''.join(PRINT_TEMPLATE.format(obj_file_name=section.obj_file_name, - section_name=section.section_name) - for section in sorted(list_sections)) - + out = '' + for section in sorted(list_sections): + template = PRINT_TEMPLATE if section.keep else PRINT_TEMPLATE_NOKEEP + out += template.format(obj_file_name=section.obj_file_name, + section_name=section.section_name) + return out def add_phdr(memory_type, phdrs): return f'{memory_type} {phdrs[memory_type] if memory_type in phdrs else ""}' @@ -485,20 +500,23 @@ def get_obj_filename(searchpath, filename): return fullname -# Extracts all possible components for the input strin: -# [\ :program_header]:: -# Returns a 4-tuple with them: (mem_region, program_header, flag, file_name) +# Extracts all possible components for the input string: +# [\ :program_header]:[;...]:[;...] +# Returns a 4-tuple with them: (mem_region, program_header, flags, files) # If no `program_header` is defined, returns an empty string def parse_input_string(line): - line = line.replace(' :', ':') + # Be careful when splitting by : to avoid breaking absolute paths on Windows + mem_region, rest = line.split(':', 1) - flag_sep = ':NOCOPY:' if ':NOCOPY' in line else ':COPY:' - mem_region_phdr, copy_flag, file_name = line.partition(flag_sep) - copy_flag = copy_flag.replace(':', '') + phdr = '' + if mem_region.endswith(' '): + mem_region = mem_region.rstrip() + phdr, rest = rest.split(':', 1) - mem_region, _, phdr = mem_region_phdr.partition(':') + # Split lists by semicolons, in part to support generator expressions + flag_list, file_list = (lst.split(';') for lst in rest.split(':', 1)) - return mem_region, phdr, copy_flag, file_name + return mem_region, phdr, flag_list, file_list # Create a dict with key as memory type and files as a list of values. @@ -515,17 +533,15 @@ def create_dict_wrt_mem(): if ':' not in line: continue - mem_region, phdr, copy_flag, file_list = parse_input_string(line) + mem_region, phdr, flag_list, file_list = parse_input_string(line) # Handle any program header if phdr != '': phdrs[mem_region] = f':{phdr}' - # Split file names by semicolons, to support generator expressions - file_glob_list = file_list.split(';') file_name_list = [] # Use glob matching on each file in the list - for file_glob in file_glob_list: + for file_glob in file_list: glob_results = glob.glob(file_glob) if not glob_results: warnings.warn("File: "+file_glob+" Not found") @@ -534,14 +550,13 @@ def create_dict_wrt_mem(): warnings.warn("Regex in file lists is deprecated, please use file(GLOB) instead") file_name_list.extend(glob_results) if len(file_name_list) == 0: - warnings.warn("No files in string: "+file_list+" found") continue if mem_region == '': continue if args.verbose: print("Memory region ", mem_region, " Selected for files:", file_name_list) - mem_region = "|".join((mem_region, copy_flag)) + mem_region = "|".join((mem_region, *flag_list)) if mem_region in rel_dict: rel_dict[mem_region].extend(file_name_list) diff --git a/tests/application_development/code_relocation/CMakeLists.txt b/tests/application_development/code_relocation/CMakeLists.txt index 132c905895e..60350a6e2a5 100644 --- a/tests/application_development/code_relocation/CMakeLists.txt +++ b/tests/application_development/code_relocation/CMakeLists.txt @@ -37,8 +37,9 @@ zephyr_code_relocate(FILES src/test_file3.c LOCATION SRAM2_TEXT) zephyr_code_relocate(FILES src/test_file3.c LOCATION RAM_DATA) zephyr_code_relocate(FILES src/test_file3.c LOCATION SRAM2_BSS) - -zephyr_code_relocate(FILES ${ZEPHYR_BASE}/kernel/sem.c ${RAM_PHDR} LOCATION RAM) +# Test NOKEEP support. Placing both KEEP and NOKEEP symbols in the same location +# (this and test_file2.c in RAM) should work fine. +zephyr_code_relocate(FILES ${ZEPHYR_BASE}/kernel/sem.c ${RAM_PHDR} LOCATION RAM NOKEEP) if (CONFIG_RELOCATE_TO_ITCM) zephyr_code_relocate(FILES ${ZEPHYR_BASE}/lib/libc/minimal/source/string/string.c From 0b7fb57d093a51c47d8e13947102f901d45cdd65 Mon Sep 17 00:00:00 2001 From: Grzegorz Swiderski Date: Sat, 13 Jan 2024 13:02:56 +0100 Subject: [PATCH 2227/3723] cmake: code_relocation: Re-run when relocation_dict.txt changes Fix an issue where updating a `zephyr_code_relocate()` call in CMake didn't trigger regeneration of `code_relocation.c` and linker scripts. The generation command was missing a dependency on the aforementioned input text file, where the outcome of each call is cached. Signed-off-by: Grzegorz Swiderski --- cmake/linker/ld/target_relocation.cmake | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cmake/linker/ld/target_relocation.cmake b/cmake/linker/ld/target_relocation.cmake index c290a330484..a90941d04af 100644 --- a/cmake/linker/ld/target_relocation.cmake +++ b/cmake/linker/ld/target_relocation.cmake @@ -32,7 +32,7 @@ macro(toolchain_ld_relocation) -b ${MEM_RELOCATION_SRAM_BSS_LD} -c ${MEM_RELOCATION_CODE} --default_ram_region ${MEM_REGION_DEFAULT_RAM} - DEPENDS app kernel ${ZEPHYR_LIBS_PROPERTY} + DEPENDS app kernel ${ZEPHYR_LIBS_PROPERTY} ${DICT_FILE} ) add_library(code_relocation_source_lib STATIC ${MEM_RELOCATION_CODE}) From 2dee952a959c93f14929f281c6167439eef7015f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tomasz=20Mo=C5=84?= Date: Fri, 1 Dec 2023 11:05:46 +0100 Subject: [PATCH 2228/3723] modules: hal_nordic: nrfx: update API version to 3.3.0 MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Update i2s nrfx driver to pass buffer size alongside buffer pointers. No functional changes. Signed-off-by: Tomasz Moń --- drivers/i2s/i2s_nrfx.c | 10 ++++++++-- modules/hal_nordic/nrfx/nrfx_config_common.h | 2 +- 2 files changed, 9 insertions(+), 3 deletions(-) diff --git a/drivers/i2s/i2s_nrfx.c b/drivers/i2s/i2s_nrfx.c index e1b3684c4f7..aced4db9693 100644 --- a/drivers/i2s/i2s_nrfx.c +++ b/drivers/i2s/i2s_nrfx.c @@ -226,6 +226,10 @@ static void free_rx_buffer(struct i2s_nrfx_drv_data *drv_data, void *buffer) static bool supply_next_buffers(struct i2s_nrfx_drv_data *drv_data, nrfx_i2s_buffers_t *next) { + uint32_t block_size = (drv_data->active_dir == I2S_DIR_TX) + ? drv_data->tx.cfg.block_size + : drv_data->rx.cfg.block_size; + drv_data->last_tx_buffer = next->p_tx_buffer; if (drv_data->active_dir != I2S_DIR_TX) { /* -> RX active */ @@ -236,6 +240,8 @@ static bool supply_next_buffers(struct i2s_nrfx_drv_data *drv_data, } } + next->buffer_size = block_size / sizeof(uint32_t); + LOG_DBG("Next buffers: %p/%p", next->p_tx_buffer, next->p_rx_buffer); nrfx_i2s_next_buffers_set(drv_data->p_i2s, next); return true; @@ -661,10 +667,10 @@ static int start_transfer(struct i2s_nrfx_drv_data *drv_data) : drv_data->rx.cfg.block_size; nrfx_err_t err; + initial_buffers.buffer_size = block_size / sizeof(uint32_t); drv_data->last_tx_buffer = initial_buffers.p_tx_buffer; - err = nrfx_i2s_start(drv_data->p_i2s, &initial_buffers, - block_size / sizeof(uint32_t), 0); + err = nrfx_i2s_start(drv_data->p_i2s, &initial_buffers, 0); if (err == NRFX_SUCCESS) { return 0; } diff --git a/modules/hal_nordic/nrfx/nrfx_config_common.h b/modules/hal_nordic/nrfx/nrfx_config_common.h index 28a3a15b0de..88a1a8b95e8 100644 --- a/modules/hal_nordic/nrfx/nrfx_config_common.h +++ b/modules/hal_nordic/nrfx/nrfx_config_common.h @@ -18,7 +18,7 @@ /** @brief Symbol specifying minor version of the nrfx API to be used. */ #ifndef NRFX_CONFIG_API_VER_MINOR -#define NRFX_CONFIG_API_VER_MINOR 2 +#define NRFX_CONFIG_API_VER_MINOR 3 #endif /** @brief Symbol specifying micro version of the nrfx API to be used. */ From 07d9e521b8172b17030a06e2b1bb4c97bdcb594a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tomasz=20Mo=C5=84?= Date: Fri, 10 Nov 2023 08:49:39 +0100 Subject: [PATCH 2229/3723] drivers: i2s_nrfx: Support less than block size writes MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Calling I2S write with less bytes than I2S TX memory block size makes it possible to synchronize the time when next block is used against some other, possibly externally sourced, signal. Example use case includes USB Audio where audio sink and/or source has to be synchronized against USB SOF. In Asynchronous synchronization type the rate matching is achieved by varying the number of samples sent/received by 1 sample (e.g. for 48 kHz audio, 47 or 49 samples are transmitted during frame instead of 48). Signed-off-by: Tomasz Moń --- drivers/i2s/i2s_nrfx.c | 81 +++++++++++++++++++++++++++--------------- 1 file changed, 53 insertions(+), 28 deletions(-) diff --git a/drivers/i2s/i2s_nrfx.c b/drivers/i2s/i2s_nrfx.c index aced4db9693..318376406c8 100644 --- a/drivers/i2s/i2s_nrfx.c +++ b/drivers/i2s/i2s_nrfx.c @@ -20,6 +20,11 @@ struct stream_cfg { nrfx_i2s_config_t nrfx_cfg; }; +struct i2s_buf { + void *mem_block; + size_t size; +}; + struct i2s_nrfx_drv_data { struct onoff_manager *clk_mgr; struct onoff_client clk_cli; @@ -189,9 +194,14 @@ static void find_suitable_clock(const struct i2s_nrfx_drv_cfg *drv_cfg, static bool get_next_tx_buffer(struct i2s_nrfx_drv_data *drv_data, nrfx_i2s_buffers_t *buffers) { + struct i2s_buf buf; int ret = k_msgq_get(&drv_data->tx_queue, - &buffers->p_tx_buffer, + &buf, K_NO_WAIT); + if (ret == 0) { + buffers->p_tx_buffer = buf.mem_block; + buffers->buffer_size = buf.size / sizeof(uint32_t); + } return (ret == 0); } @@ -226,21 +236,22 @@ static void free_rx_buffer(struct i2s_nrfx_drv_data *drv_data, void *buffer) static bool supply_next_buffers(struct i2s_nrfx_drv_data *drv_data, nrfx_i2s_buffers_t *next) { - uint32_t block_size = (drv_data->active_dir == I2S_DIR_TX) - ? drv_data->tx.cfg.block_size - : drv_data->rx.cfg.block_size; - - drv_data->last_tx_buffer = next->p_tx_buffer; - if (drv_data->active_dir != I2S_DIR_TX) { /* -> RX active */ if (!get_next_rx_buffer(drv_data, next)) { drv_data->state = I2S_STATE_ERROR; nrfx_i2s_stop(drv_data->p_i2s); return false; } + /* Set buffer size if there is no TX buffer (which effectively + * controls how many bytes will be received). + */ + if (drv_data->active_dir == I2S_DIR_RX) { + next->buffer_size = + drv_data->rx.cfg.block_size / sizeof(uint32_t); + } } - next->buffer_size = block_size / sizeof(uint32_t); + drv_data->last_tx_buffer = next->p_tx_buffer; LOG_DBG("Next buffers: %p/%p", next->p_tx_buffer, next->p_rx_buffer); nrfx_i2s_next_buffers_set(drv_data->p_i2s, next); @@ -300,8 +311,12 @@ static void data_handler(const struct device *dev, if (drv_data->discard_rx) { free_rx_buffer(drv_data, released->p_rx_buffer); } else { + struct i2s_buf buf = { + .mem_block = released->p_rx_buffer, + .size = released->buffer_size * sizeof(uint32_t) + }; int ret = k_msgq_put(&drv_data->rx_queue, - &released->p_rx_buffer, + &buf, K_NO_WAIT); if (ret < 0) { LOG_ERR("No room in RX queue"); @@ -351,6 +366,7 @@ static void data_handler(const struct device *dev, * before this buffer would be started again). */ next.p_tx_buffer = drv_data->last_tx_buffer; + next.buffer_size = 1; } else if (get_next_tx_buffer(drv_data, &next)) { /* Next TX buffer successfully retrieved from * the queue, nothing more to do here. @@ -367,6 +383,7 @@ static void data_handler(const struct device *dev, * will be stopped earlier. */ next.p_tx_buffer = drv_data->last_tx_buffer; + next.buffer_size = 1; } else { /* Next TX buffer cannot be supplied now. * Defer it to when the user writes more data. @@ -383,21 +400,21 @@ static void data_handler(const struct device *dev, static void purge_queue(const struct device *dev, enum i2s_dir dir) { struct i2s_nrfx_drv_data *drv_data = dev->data; - void *mem_block; + struct i2s_buf buf; if (dir == I2S_DIR_TX || dir == I2S_DIR_BOTH) { while (k_msgq_get(&drv_data->tx_queue, - &mem_block, + &buf, K_NO_WAIT) == 0) { - free_tx_buffer(drv_data, mem_block); + free_tx_buffer(drv_data, buf.mem_block); } } if (dir == I2S_DIR_RX || dir == I2S_DIR_BOTH) { while (k_msgq_get(&drv_data->rx_queue, - &mem_block, + &buf, K_NO_WAIT) == 0) { - free_rx_buffer(drv_data, mem_block); + free_rx_buffer(drv_data, buf.mem_block); } } } @@ -560,6 +577,7 @@ static int i2s_nrfx_read(const struct device *dev, void **mem_block, size_t *size) { struct i2s_nrfx_drv_data *drv_data = dev->data; + struct i2s_buf buf; int ret; if (!drv_data->rx_configured) { @@ -568,7 +586,7 @@ static int i2s_nrfx_read(const struct device *dev, } ret = k_msgq_get(&drv_data->rx_queue, - mem_block, + &buf, (drv_data->state == I2S_STATE_ERROR) ? K_NO_WAIT : SYS_TIMEOUT_MS(drv_data->rx.cfg.timeout)); @@ -576,10 +594,11 @@ static int i2s_nrfx_read(const struct device *dev, return -EIO; } - LOG_DBG("Released RX %p", *mem_block); + LOG_DBG("Released RX %p", buf.mem_block); if (ret == 0) { - *size = drv_data->rx.cfg.block_size; + *mem_block = buf.mem_block; + *size = buf.size; } return ret; @@ -589,6 +608,7 @@ static int i2s_nrfx_write(const struct device *dev, void *mem_block, size_t size) { struct i2s_nrfx_drv_data *drv_data = dev->data; + struct i2s_buf buf = { .mem_block = mem_block, .size = size }; int ret; if (!drv_data->tx_configured) { @@ -602,14 +622,14 @@ static int i2s_nrfx_write(const struct device *dev, return -EIO; } - if (size != drv_data->tx.cfg.block_size) { - LOG_ERR("This device can only write blocks of %u bytes", + if (size > drv_data->tx.cfg.block_size || size < sizeof(uint32_t)) { + LOG_ERR("This device can only write blocks up to %u bytes", drv_data->tx.cfg.block_size); return -EIO; } ret = k_msgq_put(&drv_data->tx_queue, - &mem_block, + &buf, SYS_TIMEOUT_MS(drv_data->tx.cfg.timeout)); if (ret < 0) { return ret; @@ -662,12 +682,17 @@ static int start_transfer(struct i2s_nrfx_drv_data *drv_data) /* Failed to allocate next RX buffer */ ret = -ENOMEM; } else { - uint32_t block_size = (drv_data->active_dir == I2S_DIR_TX) - ? drv_data->tx.cfg.block_size - : drv_data->rx.cfg.block_size; nrfx_err_t err; - initial_buffers.buffer_size = block_size / sizeof(uint32_t); + /* It is necessary to set buffer size here only for I2S_DIR_RX, + * because only then the get_next_tx_buffer() call in the if + * condition above gets short-circuited. + */ + if (drv_data->active_dir == I2S_DIR_RX) { + initial_buffers.buffer_size = + drv_data->rx.cfg.block_size / sizeof(uint32_t); + } + drv_data->last_tx_buffer = initial_buffers.p_tx_buffer; err = nrfx_i2s_start(drv_data->p_i2s, &initial_buffers, 0); @@ -904,8 +929,8 @@ static const struct i2s_driver_api i2s_nrf_drv_api = { #define I2S_CLK_SRC(idx) DT_STRING_TOKEN(I2S(idx), clock_source) #define I2S_NRFX_DEVICE(idx) \ - static void *tx_msgs##idx[CONFIG_I2S_NRFX_TX_BLOCK_COUNT]; \ - static void *rx_msgs##idx[CONFIG_I2S_NRFX_RX_BLOCK_COUNT]; \ + static struct i2s_buf tx_msgs##idx[CONFIG_I2S_NRFX_TX_BLOCK_COUNT]; \ + static struct i2s_buf rx_msgs##idx[CONFIG_I2S_NRFX_RX_BLOCK_COUNT]; \ static void data_handler##idx(nrfx_i2s_buffers_t const *p_released, \ uint32_t status) \ { \ @@ -941,10 +966,10 @@ static const struct i2s_driver_api i2s_nrf_drv_api = { return err; \ } \ k_msgq_init(&i2s_nrfx_data##idx.tx_queue, \ - (char *)tx_msgs##idx, sizeof(void *), \ + (char *)tx_msgs##idx, sizeof(struct i2s_buf), \ ARRAY_SIZE(tx_msgs##idx)); \ k_msgq_init(&i2s_nrfx_data##idx.rx_queue, \ - (char *)rx_msgs##idx, sizeof(void *), \ + (char *)rx_msgs##idx, sizeof(struct i2s_buf), \ ARRAY_SIZE(rx_msgs##idx)); \ init_clock_manager(dev); \ return 0; \ From ec43b64c165d1045695c856d2d33331469047d1e Mon Sep 17 00:00:00 2001 From: Emil Gydesen Date: Thu, 21 Dec 2023 14:39:51 +0100 Subject: [PATCH 2230/3723] Bluetooth: host: Add documentation for OPT_EXT_ADV and bt_le_adv_start The bt_le_adv_start function can (currently) not be used together with BT_LE_ADV_OPT_EXT_ADV, and it will return an -EINVAL error if attempted, but this behavior is not documented, and several people have asked about why it does not work. Signed-off-by: Emil Gydesen --- include/zephyr/bluetooth/bluetooth.h | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/include/zephyr/bluetooth/bluetooth.h b/include/zephyr/bluetooth/bluetooth.h index c93cf4a5f25..0cfad9b1f6b 100644 --- a/include/zephyr/bluetooth/bluetooth.h +++ b/include/zephyr/bluetooth/bluetooth.h @@ -628,6 +628,8 @@ enum { * * @note Enabling this option requires extended advertising support in * the peer devices scanning for advertisement packets. + * + * @note This cannot be used with bt_le_adv_start(). */ BT_LE_ADV_OPT_EXT_ADV = BIT(10), @@ -1055,6 +1057,9 @@ struct bt_le_per_adv_param { * response data parameters are ignored. If the mode is high duty cycle * the timeout will be @ref BT_GAP_ADV_HIGH_DUTY_CYCLE_MAX_TIMEOUT. * + * This function cannot be used with @ref BT_LE_ADV_OPT_EXT_ADV in the @p param.options. + * For extended advertising, the bt_le_ext_adv_* functions must be used. + * * @param param Advertising parameters. * @param ad Data to be used in advertisement packets. * @param ad_len Number of elements in ad From d02f86a754829ff12b6a5134f01e656b879b1402 Mon Sep 17 00:00:00 2001 From: Guillaume Galeazzi Date: Tue, 9 Jan 2024 12:36:36 +0100 Subject: [PATCH 2231/3723] boards: arm: stm32u5a9j-dk: fix switch gpio config The user switch on the board require a pull down on mcu side and is active high. Signed-off-by: Guillaume Galeazzi --- boards/arm/stm32u5a9j_dk/stm32u5a9j_dk.dts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/boards/arm/stm32u5a9j_dk/stm32u5a9j_dk.dts b/boards/arm/stm32u5a9j_dk/stm32u5a9j_dk.dts index f236354c6f2..6f80a4061a4 100644 --- a/boards/arm/stm32u5a9j_dk/stm32u5a9j_dk.dts +++ b/boards/arm/stm32u5a9j_dk/stm32u5a9j_dk.dts @@ -37,7 +37,7 @@ compatible = "gpio-keys"; user_button: button_0 { label = "User"; - gpios = <&gpioc 13 GPIO_ACTIVE_LOW>; + gpios = <&gpioc 13 (GPIO_ACTIVE_HIGH | GPIO_PULL_DOWN)>; zephyr,code = ; }; }; From 85995e5688fb7455510009092c585a93dcb19d3e Mon Sep 17 00:00:00 2001 From: Ali Hozhabri Date: Tue, 9 Jan 2024 15:00:25 +0100 Subject: [PATCH 2232/3723] boards: shields: Add support for X-NUCLEO-BNRG2A1 shield Add support for X-NUCLEO-BNRG2A1 which is a BLE expansion board based on the BLUENRG-M2SP. Signed-off-by: Ali Hozhabri --- .../x_nucleo_bnrg2a1/Kconfig.defconfig | 24 +++++ .../shields/x_nucleo_bnrg2a1/Kconfig.shield | 5 + .../doc/img/x-nucleo-bnrg2a1.webp | Bin 0 -> 35014 bytes boards/shields/x_nucleo_bnrg2a1/doc/index.rst | 91 ++++++++++++++++++ .../x_nucleo_bnrg2a1/x_nucleo_bnrg2a1.overlay | 20 ++++ 5 files changed, 140 insertions(+) create mode 100644 boards/shields/x_nucleo_bnrg2a1/Kconfig.defconfig create mode 100644 boards/shields/x_nucleo_bnrg2a1/Kconfig.shield create mode 100644 boards/shields/x_nucleo_bnrg2a1/doc/img/x-nucleo-bnrg2a1.webp create mode 100644 boards/shields/x_nucleo_bnrg2a1/doc/index.rst create mode 100644 boards/shields/x_nucleo_bnrg2a1/x_nucleo_bnrg2a1.overlay diff --git a/boards/shields/x_nucleo_bnrg2a1/Kconfig.defconfig b/boards/shields/x_nucleo_bnrg2a1/Kconfig.defconfig new file mode 100644 index 00000000000..88f16f95dc5 --- /dev/null +++ b/boards/shields/x_nucleo_bnrg2a1/Kconfig.defconfig @@ -0,0 +1,24 @@ +# Copyright (c) 2024 STMicroelectronics +# SPDX-License-Identifier: Apache-2.0 + +if SHIELD_X_NUCLEO_BNRG2A1 + +if BT + +config SPI + default y + +choice BT_HCI_BUS_TYPE + default BT_SPI +endchoice + +config BT_BLUENRG_ACI + default y + +# Disable Flow control +config BT_HCI_ACL_FLOW_CONTROL + default n + +endif # BT + +endif # SHIELD_X_NUCLEO_BNRG2A1 diff --git a/boards/shields/x_nucleo_bnrg2a1/Kconfig.shield b/boards/shields/x_nucleo_bnrg2a1/Kconfig.shield new file mode 100644 index 00000000000..67efc1dffa5 --- /dev/null +++ b/boards/shields/x_nucleo_bnrg2a1/Kconfig.shield @@ -0,0 +1,5 @@ +# Copyright (c) 2024 STMicroelectronics +# SPDX-License-Identifier: Apache-2.0 + +config SHIELD_X_NUCLEO_BNRG2A1 + def_bool $(shields_list_contains,x_nucleo_bnrg2a1) diff --git a/boards/shields/x_nucleo_bnrg2a1/doc/img/x-nucleo-bnrg2a1.webp b/boards/shields/x_nucleo_bnrg2a1/doc/img/x-nucleo-bnrg2a1.webp new file mode 100644 index 0000000000000000000000000000000000000000..82304ace3452ea3f5c5d61d62e3663f9a48bdc83 GIT binary patch literal 35014 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 /* A1 */ + + bluenrg-2@0 { + compatible = "st,hci-spi-v2"; + reg = <0>; + reset-gpios = <&arduino_header 13 GPIO_ACTIVE_LOW>; /* D7 */ + irq-gpios = <&arduino_header 0 (GPIO_ACTIVE_HIGH | GPIO_PULL_DOWN)>; /* A0 */ + spi-cpha; /* CPHA=1 */ + spi-hold-cs; + spi-max-frequency = ; + reset-assert-duration-ms = <6>; + }; +}; From 7c9f2872e17d168cf28c6e77dd5fcb71b892c33d Mon Sep 17 00:00:00 2001 From: Bjarki Arge Andreasen Date: Thu, 11 Jan 2024 13:12:00 +0100 Subject: [PATCH 2233/3723] modem: chat: Start waiting for response after request is sent This PR makes the modem_chat wait until a chat script chat request has been sent before accepting responses to said request. This helps ensure that an unsolicitet response is not mistaken for a response to a request, which is especially problematic if the chat script chat is using an any match. For example, start chat script sending AT+CGMI, expecting the modem name as a response followed by OK > start script, waiting for response immediately > start sending "AT+CGMI" > receive "+CEREG 1,0" while sending > script accepts "+CEREG 1,0" as the response to "AT+CGMI" > "AT+CGMI" sent > receive "QUECTEL BG95" > receive "OK" script handler got "+CEREG 1,0" instead of "QUECTEL BG95" After this PR: > start script > start sending AT+CGMI > receive "+CEREG 1,0" while sending > "AT+CGMI" sent > start waiting for response > receive "QUECTEL BG95" > script accepts "QUECTEL BG95" as response to "AT+CGMI" > receive "OK" Signed-off-by: Bjarki Arge Andreasen --- subsys/modem/modem_chat.c | 30 ++++++++++++++++++++++++------ 1 file changed, 24 insertions(+), 6 deletions(-) diff --git a/subsys/modem/modem_chat.c b/subsys/modem/modem_chat.c index 7cf7692c514..f3857bcfbc3 100644 --- a/subsys/modem/modem_chat.c +++ b/subsys/modem/modem_chat.c @@ -95,8 +95,10 @@ static void modem_chat_script_stop(struct modem_chat *chat, enum modem_chat_scri chat->matches[MODEM_CHAT_MATCHES_INDEX_RESPONSE] = NULL; chat->matches_size[MODEM_CHAT_MATCHES_INDEX_RESPONSE] = 0; - /* Cancel timeout work */ + /* Cancel work */ k_work_cancel_delayable(&chat->script_timeout_work); + k_work_cancel_delayable(&chat->script_send_work); + k_work_cancel_delayable(&chat->script_send_timeout_work); /* Clear script running state */ atomic_clear_bit(&chat->script_state, MODEM_CHAT_SCRIPT_STATE_RUNNING_BIT); @@ -118,6 +120,21 @@ static void modem_chat_script_send(struct modem_chat *chat) k_work_schedule(&chat->script_send_work, K_NO_WAIT); } +static void modem_chat_script_set_response_matches(struct modem_chat *chat) +{ + const struct modem_chat_script_chat *script_chat = + &chat->script->script_chats[chat->script_chat_it]; + + chat->matches[MODEM_CHAT_MATCHES_INDEX_RESPONSE] = script_chat->response_matches; + chat->matches_size[MODEM_CHAT_MATCHES_INDEX_RESPONSE] = script_chat->response_matches_size; +} + +static void modem_chat_script_clear_response_matches(struct modem_chat *chat) +{ + chat->matches[MODEM_CHAT_MATCHES_INDEX_RESPONSE] = NULL; + chat->matches_size[MODEM_CHAT_MATCHES_INDEX_RESPONSE] = 0; +} + static void modem_chat_script_next(struct modem_chat *chat, bool initial) { const struct modem_chat_script_chat *script_chat; @@ -142,14 +159,13 @@ static void modem_chat_script_next(struct modem_chat *chat, bool initial) script_chat = &chat->script->script_chats[chat->script_chat_it]; - /* Set response command handlers */ - chat->matches[MODEM_CHAT_MATCHES_INDEX_RESPONSE] = script_chat->response_matches; - chat->matches_size[MODEM_CHAT_MATCHES_INDEX_RESPONSE] = script_chat->response_matches_size; - - /* Check if work must be sent */ + /* Check if request must be sent */ if (script_chat->request_size > 0) { LOG_DBG("sending: %.*s", script_chat->request_size, script_chat->request); + modem_chat_script_clear_response_matches(chat); modem_chat_script_send(chat); + } else { + modem_chat_script_set_response_matches(chat); } } @@ -322,6 +338,8 @@ static void modem_chat_script_send_handler(struct k_work *item) } else { k_work_schedule(&chat->script_send_timeout_work, K_MSEC(timeout)); } + } else { + modem_chat_script_set_response_matches(chat); } } From 325bc953a89d79ca71b6f8b59ea320bbf78fa656 Mon Sep 17 00:00:00 2001 From: Bjarki Arge Andreasen Date: Fri, 12 Jan 2024 11:31:14 +0100 Subject: [PATCH 2234/3723] tests: modem: pipe: mock: Implement TRANSMIT_IDLE event Implements TRANSMIT_IDLE event notification for mock modem_pipe. Signed-off-by: Bjarki Arge Andreasen --- tests/subsys/modem/mock/modem_backend_mock.c | 24 ++++++++++++++------ tests/subsys/modem/mock/modem_backend_mock.h | 10 ++------ 2 files changed, 19 insertions(+), 15 deletions(-) diff --git a/tests/subsys/modem/mock/modem_backend_mock.c b/tests/subsys/modem/mock/modem_backend_mock.c index 0a12fc43674..5b7b47c0eb4 100644 --- a/tests/subsys/modem/mock/modem_backend_mock.c +++ b/tests/subsys/modem/mock/modem_backend_mock.c @@ -47,7 +47,8 @@ static int modem_backend_mock_transmit(void *data, const uint8_t *buf, size_t si struct modem_backend_mock *t_mock = mock->bridge; ret = ring_buf_put(&t_mock->rx_rb, buf, size); - k_work_submit(&t_mock->received_work_item.work); + k_work_submit(&t_mock->receive_ready_work); + k_work_submit(&mock->transmit_idle_work); return ret; } @@ -59,6 +60,7 @@ static int modem_backend_mock_transmit(void *data, const uint8_t *buf, size_t si mock->transaction = NULL; } + k_work_submit(&mock->transmit_idle_work); return ret; } @@ -85,14 +87,22 @@ struct modem_pipe_api modem_backend_mock_api = { .close = modem_backend_mock_close, }; -static void modem_backend_mock_received_handler(struct k_work *item) +static void modem_backend_mock_receive_ready_handler(struct k_work *item) { - struct modem_backend_mock_work *mock_work_item = (struct modem_backend_mock_work *)item; - struct modem_backend_mock *mock = mock_work_item->mock; + struct modem_backend_mock *mock = + CONTAINER_OF(item, struct modem_backend_mock, receive_ready_work); modem_pipe_notify_receive_ready(&mock->pipe); } +static void modem_backend_mock_transmit_idle_handler(struct k_work *item) +{ + struct modem_backend_mock *mock = + CONTAINER_OF(item, struct modem_backend_mock, transmit_idle_work); + + modem_pipe_notify_transmit_idle(&mock->pipe); +} + struct modem_pipe *modem_backend_mock_init(struct modem_backend_mock *mock, const struct modem_backend_mock_config *config) { @@ -100,8 +110,8 @@ struct modem_pipe *modem_backend_mock_init(struct modem_backend_mock *mock, ring_buf_init(&mock->rx_rb, config->rx_buf_size, config->rx_buf); ring_buf_init(&mock->tx_rb, config->tx_buf_size, config->tx_buf); - mock->received_work_item.mock = mock; - k_work_init(&mock->received_work_item.work, modem_backend_mock_received_handler); + k_work_init(&mock->receive_ready_work, modem_backend_mock_receive_ready_handler); + k_work_init(&mock->transmit_idle_work, modem_backend_mock_transmit_idle_handler); mock->limit = config->limit; modem_pipe_init(&mock->pipe, mock, &modem_backend_mock_api); return &mock->pipe; @@ -130,7 +140,7 @@ void modem_backend_mock_put(struct modem_backend_mock *mock, const uint8_t *buf, __ASSERT(ring_buf_put(&mock->rx_rb, buf, size) == size, "Mock buffer capacity exceeded"); - k_work_submit(&mock->received_work_item.work); + k_work_submit(&mock->receive_ready_work); } void modem_backend_mock_prime(struct modem_backend_mock *mock, diff --git a/tests/subsys/modem/mock/modem_backend_mock.h b/tests/subsys/modem/mock/modem_backend_mock.h index 7d9ad11bf41..56a5b585cb1 100644 --- a/tests/subsys/modem/mock/modem_backend_mock.h +++ b/tests/subsys/modem/mock/modem_backend_mock.h @@ -11,13 +11,6 @@ #ifndef ZEPHYR_DRIVERS_MODEM_MODEM_PIPE_MOCK #define ZEPHYR_DRIVERS_MODEM_MODEM_PIPE_MOCK -struct modem_backend_mock; - -struct modem_backend_mock_work { - struct k_work work; - struct modem_backend_mock *mock; -}; - struct modem_backend_mock_transaction { /* Get data which will trigger put */ const uint8_t *get; @@ -34,7 +27,8 @@ struct modem_backend_mock { struct ring_buf rx_rb; struct ring_buf tx_rb; - struct modem_backend_mock_work received_work_item; + struct k_work receive_ready_work; + struct k_work transmit_idle_work; const struct modem_backend_mock_transaction *transaction; size_t transaction_match_cnt; From 998e839d6743c3ae2633e653415a2ae56bb7fb34 Mon Sep 17 00:00:00 2001 From: Mirko Covizzi Date: Fri, 12 Jan 2024 17:21:22 +0100 Subject: [PATCH 2235/3723] net: sockets: prevent null pointer dereference According to the POSIX specification, null pointer is a valid value for the `address` argument of the `accept` function. This commit adds a check to prevent a null pointer dereference inside `z_impl_zsock_accept`. Signed-off-by: Mirko Covizzi --- subsys/net/lib/sockets/sockets.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/subsys/net/lib/sockets/sockets.c b/subsys/net/lib/sockets/sockets.c index 53ff23a9081..a1f4610b504 100644 --- a/subsys/net/lib/sockets/sockets.c +++ b/subsys/net/lib/sockets/sockets.c @@ -684,7 +684,9 @@ int z_impl_zsock_accept(int sock, struct sockaddr *addr, socklen_t *addrlen) new_sock = VTABLE_CALL(accept, sock, addr, addrlen); - (void)sock_obj_core_alloc_find(sock, new_sock, addr->sa_family, SOCK_STREAM); + if (addr) { + (void)sock_obj_core_alloc_find(sock, new_sock, addr->sa_family, SOCK_STREAM); + } return new_sock; } From 6f6fc4e25c3175d5a2587b0e6f3d858b4c336e99 Mon Sep 17 00:00:00 2001 From: Xuyang Shen Date: Tue, 9 Jan 2024 16:30:33 +0000 Subject: [PATCH 2236/3723] drivers: sensors: icm42688: fix bug in Kconfigfile Fix Bug in Kconfig file of icm42688 driver Signed-off-by: Xuyang Shen --- drivers/sensor/icm42688/Kconfig | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/drivers/sensor/icm42688/Kconfig b/drivers/sensor/icm42688/Kconfig index 08779dc72d9..aea3cc6480f 100644 --- a/drivers/sensor/icm42688/Kconfig +++ b/drivers/sensor/icm42688/Kconfig @@ -4,7 +4,7 @@ # # SPDX-License-Identifier: Apache-2.0 -config ICM42688 +menuconfig ICM42688 bool "ICM42688 Six-Axis Motion Tracking Device" default y depends on DT_HAS_INVENSENSE_ICM42688_ENABLED @@ -12,10 +12,11 @@ config ICM42688 help Enable driver for ICM42688 SPI-based six-axis motion tracking device. +if ICM42688 + config EMUL_ICM42688 bool "Emulator for the ICM42688" default y - depends on ICM42688 depends on EMUL help Enable the hardware emulator for the ICM42688. Doing so allows exercising @@ -23,14 +24,12 @@ config EMUL_ICM42688 config ICM42688_DECODER bool "ICM42688 decoder logic" - default y if ICM42688 + default y select SENSOR_ASYNC_API help Compile the ICM42688 decoder API which allows decoding raw data returned from the sensor. -if ICM42688 - choice prompt "Trigger mode" default ICM42688_TRIGGER_NONE if ICM42688_STREAM From d2be3c05dca6c702c150609b777d96d376738448 Mon Sep 17 00:00:00 2001 From: Flavio Ceolin Date: Sun, 14 Jan 2024 21:18:46 -0800 Subject: [PATCH 2237/3723] tracing: sysview: Fix API name s/k_thread_usermode_enter/k_thread_user_mode_enter/ Signed-off-by: Flavio Ceolin --- subsys/tracing/sysview/SYSVIEW_Zephyr.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/subsys/tracing/sysview/SYSVIEW_Zephyr.txt b/subsys/tracing/sysview/SYSVIEW_Zephyr.txt index 758023d19f7..9006b9bb513 100644 --- a/subsys/tracing/sysview/SYSVIEW_Zephyr.txt +++ b/subsys/tracing/sysview/SYSVIEW_Zephyr.txt @@ -110,7 +110,7 @@ TaskState 0xBF 1=dummy, 2=Waiting, 4=New, 8=Terminated, 16=Suspended, 32=Termina 103 k_thread_resume 104 k_thread_join 105 k_thread_yield -106 k_thread_usermode_enter +106 k_thread_user_mode_enter 107 k_thread_foreach 108 k_thread_foreach_unlocked 155 k_thread_name_set thread=%I From 728f0ec7bed5f8f210b88132bfa2fc0c4f28204c Mon Sep 17 00:00:00 2001 From: Andrzej Kuros Date: Mon, 15 Jan 2024 11:35:28 +0100 Subject: [PATCH 2238/3723] dts: nrf5340: add missing `easydma-maxcnt-bits` for nrf5340_cpunet MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The required property `easydma-maxcnt-bits` was missing for nrf5340_cpunet. Signed-off-by: Andrzej Kuroś --- dts/arm/nordic/nrf5340_cpunet.dtsi | 1 + 1 file changed, 1 insertion(+) diff --git a/dts/arm/nordic/nrf5340_cpunet.dtsi b/dts/arm/nordic/nrf5340_cpunet.dtsi index 6c1e66e73aa..d930cf603c0 100644 --- a/dts/arm/nordic/nrf5340_cpunet.dtsi +++ b/dts/arm/nordic/nrf5340_cpunet.dtsi @@ -193,6 +193,7 @@ reg = <0x41013000 0x1000>; clock-frequency = ; interrupts = <19 NRF_DEFAULT_IRQ_PRIORITY>; + easydma-maxcnt-bits = <16>; status = "disabled"; }; From 234b322dc306a1c936161e4107370dcf5c9cb59e Mon Sep 17 00:00:00 2001 From: Emil Gydesen Date: Tue, 2 Jan 2024 14:55:00 +0100 Subject: [PATCH 2239/3723] Bluetooth: Audio: Fix len check in ltv_set_val The length check in ltv_set_val did not consider the size of the length or type fields. Signed-off-by: Emil Gydesen --- subsys/bluetooth/audio/codec.c | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/subsys/bluetooth/audio/codec.c b/subsys/bluetooth/audio/codec.c index 38b1ef7d22b..2bf3faf2565 100644 --- a/subsys/bluetooth/audio/codec.c +++ b/subsys/bluetooth/audio/codec.c @@ -142,6 +142,8 @@ static bool parse_cb(struct bt_data *data, void *user_data) static int ltv_set_val(struct net_buf_simple *buf, uint8_t type, const uint8_t *data, size_t data_len) { + size_t new_buf_len; + for (uint16_t i = 0U; i < buf->len;) { uint8_t *len = &buf->data[i++]; const uint8_t data_type = buf->data[i++]; @@ -207,11 +209,12 @@ static int ltv_set_val(struct net_buf_simple *buf, uint8_t type, const uint8_t * } /* If we reach here, we did not find the data in the buffer, so we simply add it */ - if ((buf->len + data_len) <= buf->size) { - net_buf_simple_add_u8(buf, data_len + sizeof(type)); - net_buf_simple_add_u8(buf, type); + new_buf_len = buf->len + 1 /* len */ + sizeof(type) + data_len; + if (new_buf_len <= buf->size) { + net_buf_simple_add_u8(buf, data_len + sizeof(type)); /* len */ + net_buf_simple_add_u8(buf, type); /* type */ if (data_len > 0) { - net_buf_simple_add_mem(buf, data, data_len); + net_buf_simple_add_mem(buf, data, data_len); /* value */ } } else { LOG_DBG("Cannot fit data_len %zu in codec_cfg with len %u and size %u", data_len, From a72da864e043b1762fde5c851428a862c6769f4a Mon Sep 17 00:00:00 2001 From: Emil Gydesen Date: Tue, 2 Jan 2024 14:17:55 +0100 Subject: [PATCH 2240/3723] Bluetooth: BAP: Restrict application ASCS response codes Some of the ASCS response codes should not be used by the unicast server, as those will be checked and validated by the stack. They are kept in the enum, as the enum is also used by the unicast client. Besides updating the documentation, this commit also adds a function to validate the response codes as well as the combination of response codes and reason/metadata values, and log a warning if the application does not adhere to the documented behavior. A warning is used instead of an error/assert/modification of the response codes, as there may be unforseen reasons why an application provide a non-approved response code, and since it may be spec-valid, we should not fully prevent it. Signed-off-by: Emil Gydesen --- include/zephyr/bluetooth/audio/bap.h | 21 ++++++---- subsys/bluetooth/audio/ascs.c | 59 ++++++++++++++++++++++++++++ 2 files changed, 72 insertions(+), 8 deletions(-) diff --git a/include/zephyr/bluetooth/audio/bap.h b/include/zephyr/bluetooth/audio/bap.h index 588c44d5efe..5fad95df0b5 100644 --- a/include/zephyr/bluetooth/audio/bap.h +++ b/include/zephyr/bluetooth/audio/bap.h @@ -183,7 +183,19 @@ enum bt_bap_ascs_reason { /** @brief Structure storing values of fields of ASE Control Point notification. */ struct bt_bap_ascs_rsp { - /** @brief Value of the Response Code field. */ + /** + * @brief Value of the Response Code field. + * + * The following response codes are accepted: + * - @ref BT_BAP_ASCS_RSP_CODE_SUCCESS + * - @ref BT_BAP_ASCS_RSP_CODE_CAP_UNSUPPORTED + * - @ref BT_BAP_ASCS_RSP_CODE_CONF_UNSUPPORTED + * - @ref BT_BAP_ASCS_RSP_CODE_CONF_REJECTED + * - @ref BT_BAP_ASCS_RSP_CODE_METADATA_UNSUPPORTED + * - @ref BT_BAP_ASCS_RSP_CODE_METADATA_REJECTED + * - @ref BT_BAP_ASCS_RSP_CODE_NO_MEM + * - @ref BT_BAP_ASCS_RSP_CODE_UNSPECIFIED + */ enum bt_bap_ascs_rsp_code code; /** @@ -198,16 +210,10 @@ struct bt_bap_ascs_rsp { * If the Response Code is one of the following: * - @ref BT_BAP_ASCS_RSP_CODE_CONF_UNSUPPORTED * - @ref BT_BAP_ASCS_RSP_CODE_CONF_REJECTED - * - @ref BT_BAP_ASCS_RSP_CODE_CONF_INVALID * all values from @ref bt_bap_ascs_reason can be used. * * If the Response Code is one of the following: * - @ref BT_BAP_ASCS_RSP_CODE_SUCCESS - * - @ref BT_BAP_ASCS_RSP_CODE_NOT_SUPPORTED - * - @ref BT_BAP_ASCS_RSP_CODE_INVALID_LENGTH - * - @ref BT_BAP_ASCS_RSP_CODE_INVALID_ASE - * - @ref BT_BAP_ASCS_RSP_CODE_INVALID_ASE_STATE - * - @ref BT_BAP_ASCS_RSP_CODE_INVALID_DIR * - @ref BT_BAP_ASCS_RSP_CODE_CAP_UNSUPPORTED * - @ref BT_BAP_ASCS_RSP_CODE_NO_MEM * - @ref BT_BAP_ASCS_RSP_CODE_UNSPECIFIED @@ -221,7 +227,6 @@ struct bt_bap_ascs_rsp { * If the Response Code is one of the following: * - @ref BT_BAP_ASCS_RSP_CODE_METADATA_UNSUPPORTED * - @ref BT_BAP_ASCS_RSP_CODE_METADATA_REJECTED - * - @ref BT_BAP_ASCS_RSP_CODE_METADATA_INVALID * the value of the Metadata Type shall be used. */ enum bt_audio_metadata_type metadata_type; diff --git a/subsys/bluetooth/audio/ascs.c b/subsys/bluetooth/audio/ascs.c index 4118d059586..d19a790bcf1 100644 --- a/subsys/bluetooth/audio/ascs.c +++ b/subsys/bluetooth/audio/ascs.c @@ -101,6 +101,52 @@ NET_BUF_SIMPLE_DEFINE_STATIC(ase_buf, ASE_BUF_SIZE); static int control_point_notify(struct bt_conn *conn, const void *data, uint16_t len); static int ascs_ep_get_status(struct bt_bap_ep *ep, struct net_buf_simple *buf); +static void ascs_app_rsp_warn_valid(const struct bt_bap_ascs_rsp *rsp) +{ + /* Validate application error code */ + switch (rsp->code) { + case BT_BAP_ASCS_RSP_CODE_SUCCESS: + case BT_BAP_ASCS_RSP_CODE_CAP_UNSUPPORTED: + case BT_BAP_ASCS_RSP_CODE_NO_MEM: + case BT_BAP_ASCS_RSP_CODE_UNSPECIFIED: + case BT_BAP_ASCS_RSP_CODE_CONF_UNSUPPORTED: + case BT_BAP_ASCS_RSP_CODE_CONF_REJECTED: + case BT_BAP_ASCS_RSP_CODE_METADATA_UNSUPPORTED: + case BT_BAP_ASCS_RSP_CODE_METADATA_REJECTED: + break; + default: + LOG_WRN("Invalid application error code: %u", rsp->code); + return; + } + + /* Validate application error code and reason combinations */ + switch (rsp->code) { + case BT_BAP_ASCS_RSP_CODE_SUCCESS: + case BT_BAP_ASCS_RSP_CODE_CAP_UNSUPPORTED: + case BT_BAP_ASCS_RSP_CODE_NO_MEM: + case BT_BAP_ASCS_RSP_CODE_UNSPECIFIED: + if (rsp->reason != BT_BAP_ASCS_REASON_NONE) { + LOG_WRN("Invalid reason %u for code %u", rsp->reason, rsp->code); + } + break; + case BT_BAP_ASCS_RSP_CODE_CONF_UNSUPPORTED: + case BT_BAP_ASCS_RSP_CODE_CONF_REJECTED: + if (!IN_RANGE(rsp->reason, BT_BAP_ASCS_REASON_NONE, BT_BAP_ASCS_REASON_CIS)) { + LOG_WRN("Invalid reason %u for code %u", rsp->reason, rsp->code); + } + break; + case BT_BAP_ASCS_RSP_CODE_METADATA_UNSUPPORTED: + case BT_BAP_ASCS_RSP_CODE_METADATA_REJECTED: + if (!BT_AUDIO_METADATA_TYPE_IS_KNOWN(rsp->metadata_type)) { + LOG_WRN("Invalid metadata type %u for code %u", rsp->metadata_type, + rsp->code); + } + break; + default: + break; + } +} + static bool is_valid_ase_id(uint8_t ase_id) { return IN_RANGE(ase_id, 1, ASE_COUNT); @@ -1504,6 +1550,7 @@ static int ase_config(struct bt_ascs_ase *ase, const struct bt_ascs_config *cfg) sys_le16_to_cpu(cfg->codec.vid), (uint8_t *)cfg->cc, cfg->cc_len, &rsp); if (err) { + ascs_app_rsp_warn_valid(&rsp); (void)memcpy(&ase->ep.codec_cfg, &codec_cfg, sizeof(codec_cfg)); ascs_cp_rsp_add(ASE_ID(ase), rsp.code, rsp.reason); return err; @@ -1522,6 +1569,8 @@ static int ase_config(struct bt_ascs_ase *ase, const struct bt_ascs_config *cfg) } if (err) { + ascs_app_rsp_warn_valid(&rsp); + if (rsp.code == BT_BAP_ASCS_RSP_CODE_SUCCESS) { rsp = BT_BAP_ASCS_RSP(BT_BAP_ASCS_RSP_CODE_UNSPECIFIED, BT_BAP_ASCS_REASON_NONE); @@ -1551,6 +1600,8 @@ static int ase_config(struct bt_ascs_ase *ase, const struct bt_ascs_config *cfg) } if (err || stream == NULL) { + ascs_app_rsp_warn_valid(&rsp); + if (rsp.code == BT_BAP_ASCS_RSP_CODE_SUCCESS) { rsp = BT_BAP_ASCS_RSP(BT_BAP_ASCS_RSP_CODE_UNSPECIFIED, BT_BAP_ASCS_REASON_NONE); @@ -2181,6 +2232,8 @@ static void ase_metadata(struct bt_ascs_ase *ase, struct bt_ascs_metadata *meta) } if (err) { + ascs_app_rsp_warn_valid(&rsp); + if (rsp.code == BT_BAP_ASCS_RSP_CODE_SUCCESS) { rsp = BT_BAP_ASCS_RSP(BT_BAP_ASCS_RSP_CODE_UNSPECIFIED, BT_BAP_ASCS_REASON_NONE); @@ -2236,6 +2289,8 @@ static int ase_enable(struct bt_ascs_ase *ase, struct bt_ascs_metadata *meta) } if (err) { + ascs_app_rsp_warn_valid(&rsp); + if (rsp.code == BT_BAP_ASCS_RSP_CODE_SUCCESS) { rsp = BT_BAP_ASCS_RSP(BT_BAP_ASCS_RSP_CODE_UNSPECIFIED, BT_BAP_ASCS_REASON_NONE); @@ -2382,6 +2437,8 @@ static void ase_start(struct bt_ascs_ase *ase) } if (err) { + ascs_app_rsp_warn_valid(&rsp); + if (rsp.code == BT_BAP_ASCS_RSP_CODE_SUCCESS) { rsp = BT_BAP_ASCS_RSP(BT_BAP_ASCS_RSP_CODE_UNSPECIFIED, BT_BAP_ASCS_REASON_NONE); @@ -2584,6 +2641,8 @@ static void ase_stop(struct bt_ascs_ase *ase) } if (err) { + ascs_app_rsp_warn_valid(&rsp); + if (rsp.code == BT_BAP_ASCS_RSP_CODE_SUCCESS) { rsp = BT_BAP_ASCS_RSP(BT_BAP_ASCS_RSP_CODE_UNSPECIFIED, BT_BAP_ASCS_REASON_NONE); From 93b6a06bd1246cc00b6dce3defb68c78a143c8cd Mon Sep 17 00:00:00 2001 From: Joel Guittet Date: Tue, 2 Jan 2024 22:08:37 +0100 Subject: [PATCH 2241/3723] samples: add Wio Terminal overlay to blinky pwm Add overlay to the blinky pwm sample to run the application on the Wio Terminal. The USER LED on PA15 is used to setup the PWM LED. Signed-off-by: Joel Guittet --- .../blinky_pwm/boards/wio_terminal.overlay | 36 +++++++++++++++++++ 1 file changed, 36 insertions(+) create mode 100644 samples/basic/blinky_pwm/boards/wio_terminal.overlay diff --git a/samples/basic/blinky_pwm/boards/wio_terminal.overlay b/samples/basic/blinky_pwm/boards/wio_terminal.overlay new file mode 100644 index 00000000000..cf60fe058b7 --- /dev/null +++ b/samples/basic/blinky_pwm/boards/wio_terminal.overlay @@ -0,0 +1,36 @@ +/* + * Copyright (c) 2024 Joel Guittet + * SPDX-License-Identifier: Apache-2.0 + */ + +/{ + aliases { + pwm-led0 = &pwm_led0; + }; + + pwmleds { + compatible = "pwm-leds"; + pwm_led0: pwm_led_0 { + pwms = <&tcc1 3 PWM_MSEC(500)>; + label = "Blue PWM LED"; + }; + }; +}; + +&tcc1 { + status = "okay"; + compatible = "atmel,sam0-tcc-pwm"; + prescaler = <4>; + #pwm-cells = <2>; + + pinctrl-0 = <&pwm_default>; + pinctrl-names = "default"; +}; + +&pinctrl { + pwm_default: pwm_default { + group1 { + pinmux = ; + }; + }; +}; From 13b0052cfaea0166fb3929922ad69b31ba07ddbe Mon Sep 17 00:00:00 2001 From: Piotr Narajowski Date: Wed, 10 Jan 2024 16:43:19 +0100 Subject: [PATCH 2242/3723] Bluetooth: MPL: Add notification to track change This adds notifications to do_first_track only when changing group. Before the change was made, client was never notified about track change when changing group in Media Player. Signed-off-by: Piotr Narajowski --- subsys/bluetooth/audio/mpl.c | 36 ++++++++++++++++++++---------------- 1 file changed, 20 insertions(+), 16 deletions(-) diff --git a/subsys/bluetooth/audio/mpl.c b/subsys/bluetooth/audio/mpl.c index e97357508e8..94e15071d2c 100644 --- a/subsys/bluetooth/audio/mpl.c +++ b/subsys/bluetooth/audio/mpl.c @@ -1046,14 +1046,22 @@ static void do_next_track(struct mpl_mediaplayer *pl) } } -static void do_first_track(struct mpl_mediaplayer *pl) +static void do_first_track(struct mpl_mediaplayer *pl, bool group_change) { + bool track_changed = false; + #ifdef CONFIG_BT_MPL_OBJECTS LOG_DBG_OBJ_ID("Track ID before: ", pl->group->track->id); #endif /* CONFIG_BT_MPL_OBJECTS */ - if (pl->group->track->prev != NULL) { + /* Set first track */ + while (pl->group->track->prev != NULL) { pl->group->track = pl->group->track->prev; + track_changed = true; + } + + /* Notify about new track */ + if (group_change || track_changed) { media_player.track_pos = 0; do_track_change_notifications(&media_player); } else { @@ -1062,10 +1070,6 @@ static void do_first_track(struct mpl_mediaplayer *pl) set_track_position(0); } - while (pl->group->track->prev != NULL) { - pl->group->track = pl->group->track->prev; - } - #ifdef CONFIG_BT_MPL_OBJECTS LOG_DBG_OBJ_ID("Track ID after: ", pl->group->track->id); #endif /* CONFIG_BT_MPL_OBJECTS */ @@ -1306,7 +1310,7 @@ static void do_full_prev_group(struct mpl_mediaplayer *pl) do_prev_group(pl); /* Whether there is a group change or not, we always go to the first track */ - do_first_track(pl); + do_first_track(pl, true); } static void do_full_next_group(struct mpl_mediaplayer *pl) @@ -1315,7 +1319,7 @@ static void do_full_next_group(struct mpl_mediaplayer *pl) do_next_group(pl); /* Whether there is a group change or not, we always go to the first track */ - do_first_track(pl); + do_first_track(pl, true); } static void do_full_first_group(struct mpl_mediaplayer *pl) @@ -1324,7 +1328,7 @@ static void do_full_first_group(struct mpl_mediaplayer *pl) do_first_group(pl); /* Whether there is a group change or not, we always go to the first track */ - do_first_track(pl); + do_first_track(pl, true); } static void do_full_last_group(struct mpl_mediaplayer *pl) @@ -1333,7 +1337,7 @@ static void do_full_last_group(struct mpl_mediaplayer *pl) do_last_group(pl); /* Whether there is a group change or not, we always go to the first track */ - do_first_track(pl); + do_first_track(pl, true); } static void do_full_goto_group(struct mpl_mediaplayer *pl, int32_t groupnum) @@ -1342,7 +1346,7 @@ static void do_full_goto_group(struct mpl_mediaplayer *pl, int32_t groupnum) do_goto_group(pl, groupnum); /* Whether there is a group change or not, we always go to the first track */ - do_first_track(pl); + do_first_track(pl, true); } static void mpl_set_state(uint8_t state) @@ -1405,7 +1409,7 @@ static uint8_t inactive_state_command_handler(const struct mpl_cmd *command) mpl_set_state(MEDIA_PROXY_STATE_PAUSED); break; case MEDIA_PROXY_OP_FIRST_TRACK: - do_first_track(&media_player); + do_first_track(&media_player, false); mpl_set_state(MEDIA_PROXY_STATE_PAUSED); break; case MEDIA_PROXY_OP_LAST_TRACK: @@ -1537,7 +1541,7 @@ static uint8_t playing_state_command_handler(const struct mpl_cmd *command) do_next_track(&media_player); break; case MEDIA_PROXY_OP_FIRST_TRACK: - do_first_track(&media_player); + do_first_track(&media_player, false); break; case MEDIA_PROXY_OP_LAST_TRACK: do_last_track(&media_player); @@ -1684,7 +1688,7 @@ static uint8_t paused_state_command_handler(const struct mpl_cmd *command) /* does not change */ break; case MEDIA_PROXY_OP_FIRST_TRACK: - do_first_track(&media_player); + do_first_track(&media_player, false); break; case MEDIA_PROXY_OP_LAST_TRACK: do_last_track(&media_player); @@ -1830,7 +1834,7 @@ static uint8_t seeking_state_command_handler(const struct mpl_cmd *command) mpl_set_state(MEDIA_PROXY_STATE_PAUSED); break; case MEDIA_PROXY_OP_FIRST_TRACK: - do_first_track(&media_player); + do_first_track(&media_player, false); media_player.seeking_speed_factor = MEDIA_PROXY_SEEKING_SPEED_FACTOR_ZERO; mpl_set_state(MEDIA_PROXY_STATE_PAUSED); break; @@ -2159,7 +2163,7 @@ static void set_current_group_id(uint64_t id) do_group_change_notifications(&media_player); /* And change to first track in group */ - do_first_track(&media_player); + do_first_track(&media_player, false); } return; } From e2b271fbc4531ed8e051688ce08d267560a23cb7 Mon Sep 17 00:00:00 2001 From: Emil Gydesen Date: Mon, 15 Jan 2024 14:07:59 +0100 Subject: [PATCH 2243/3723] Bluetooth: ASCS: Add additional dbg info in state changes Add additional debug information in some ASCS debug statements, so it is easier to follow the state when there is a potentional state change. Signed-off-by: Emil Gydesen --- subsys/bluetooth/audio/ascs.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/subsys/bluetooth/audio/ascs.c b/subsys/bluetooth/audio/ascs.c index d19a790bcf1..d3ba31cf7a2 100644 --- a/subsys/bluetooth/audio/ascs.c +++ b/subsys/bluetooth/audio/ascs.c @@ -517,7 +517,7 @@ static void state_transition_work_handler(struct k_work *work) } } - LOG_DBG("ase %p id 0x%02x %s -> %s", ase, ase->ep.status.id, + LOG_DBG("ase %p ep %p id 0x%02x %s -> %s", ase, &ase->ep, ase->ep.status.id, bt_bap_ep_state_str(old_state), bt_bap_ep_state_str(new_state)); if (old_state == new_state) { @@ -1004,7 +1004,8 @@ static void ascs_ep_iso_disconnected(struct bt_bap_ep *ep, uint8_t reason) return; } - LOG_DBG("stream %p ep %p reason 0x%02x", stream, stream->ep, reason); + LOG_DBG("stream %p ep %p state %s reason 0x%02x", stream, stream->ep, + bt_bap_ep_state_str(ep->status.state), reason); /* Cancel ASE disconnect work if pending */ (void)k_work_cancel_delayable(&ase->disconnect_work); From 400cdcaca4f6adee8423cd74ad02fee55bff54ff Mon Sep 17 00:00:00 2001 From: Emil Gydesen Date: Wed, 3 Jan 2024 15:25:50 +0100 Subject: [PATCH 2244/3723] Bluetooth: BAP: Fix invalid GATT error codes in scan delegator There was a few places where the scan delegator returned an errno value instead of a valid GATT error codes when rejecting write request. These have been modified to send BT_ATT_ERR_WRITE_REQ_REJECTED to the client instead. Signed-off-by: Emil Gydesen --- subsys/bluetooth/audio/bap_scan_delegator.c | 22 ++++++++++----------- 1 file changed, 10 insertions(+), 12 deletions(-) diff --git a/subsys/bluetooth/audio/bap_scan_delegator.c b/subsys/bluetooth/audio/bap_scan_delegator.c index 296a8f47f65..03ebe87275f 100644 --- a/subsys/bluetooth/audio/bap_scan_delegator.c +++ b/subsys/bluetooth/audio/bap_scan_delegator.c @@ -585,10 +585,10 @@ static int scan_delegator_add_source(struct bt_conn *conn, if (err != 0) { (void)memset(state, 0, sizeof(*state)); - LOG_DBG("PA sync %u from %p was reject with reason %d", - pa_sync, conn, err); + LOG_DBG("PA sync %u from %p was rejected with reason %d", pa_sync, conn, + err); - return err; + return BT_GATT_ERR(BT_ATT_ERR_WRITE_REQ_REJECTED); } } @@ -774,10 +774,10 @@ static int scan_delegator_mod_src(struct bt_conn *conn, (void)memcpy(state, &backup_state, sizeof(backup_state)); - LOG_DBG("PA sync %u from %p was reject with reason %d", - pa_sync, conn, err); + LOG_DBG("PA sync %u from %p was rejected with reason %d", pa_sync, conn, + err); - return err; + return BT_GATT_ERR(BT_ATT_ERR_WRITE_REQ_REJECTED); } } else if (pa_sync == BT_BAP_BASS_PA_REQ_NO_SYNC && (state->pa_sync_state == BT_BAP_PA_STATE_INFO_REQ || @@ -786,10 +786,9 @@ static int scan_delegator_mod_src(struct bt_conn *conn, const int err = pa_sync_term_request(conn, &internal_state->state); if (err != 0) { - LOG_DBG("PA sync term from %p was reject with reason %d", - conn, err); + LOG_DBG("PA sync term from %p was rejected with reason %d", conn, err); - return err; + return BT_GATT_ERR(BT_ATT_ERR_WRITE_REQ_REJECTED); } state_changed = true; @@ -879,10 +878,9 @@ static int scan_delegator_rem_src(struct bt_conn *conn, /* Terminate PA sync */ err = pa_sync_term_request(conn, &internal_state->state); if (err != 0) { - LOG_DBG("PA sync term from %p was reject with reason %d", - conn, err); + LOG_DBG("PA sync term from %p was rejected with reason %d", conn, err); - return err; + return BT_GATT_ERR(BT_ATT_ERR_WRITE_REQ_REJECTED); } } From 92af172159d5b0e0c32e31b0f1aac3bf03341314 Mon Sep 17 00:00:00 2001 From: Paulo Santos Date: Tue, 9 Jan 2024 13:58:06 -0300 Subject: [PATCH 2245/3723] drivers: adc: iadc_gecko: fix sample bits reading The current driver initializes the IADC with the default configuration (IADC_INITSINGLE_DEFAULT), which aligns the data to the right. To correctly read the 12-bit sample, it should be masked from the right instead. Signed-off-by: Paulo Santos --- drivers/adc/iadc_gecko.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/adc/iadc_gecko.c b/drivers/adc/iadc_gecko.c index 1317a4e4729..d9dc542a5bf 100644 --- a/drivers/adc/iadc_gecko.c +++ b/drivers/adc/iadc_gecko.c @@ -20,7 +20,7 @@ LOG_MODULE_REGISTER(iadc_gecko, CONFIG_ADC_LOG_LEVEL); /* Number of channels available. */ #define GECKO_CHANNEL_COUNT 16 #define GECKO_INTERNAL_REFERENCE_mV 1210 -#define GECKO_DATA_RES12BIT(DATA) ((DATA & 0xFFF0) >> 4); +#define GECKO_DATA_RES12BIT(DATA) ((DATA) & 0x0FFF) struct adc_gecko_channel_config { IADC_CfgAnalogGain_t gain; From 5382f827d6053a9ec222b68fc0205f6e9220ece9 Mon Sep 17 00:00:00 2001 From: Alberto Escolar Piedras Date: Thu, 28 Dec 2023 11:50:48 +0100 Subject: [PATCH 2246/3723] drivers can_native_linux: Avoid using ssize ssize is a POSIX.1-2001 extension, which may or may not be provided by the C library, or may be defined to a different size in the host and embedded C library. Two internal functions were returning ssize, but one of them was a trampoline into the same host API, which is already provided by the native simulator so let's just use that instead. The other is only carrying data that fits into an int and is anyhow being cast in/to ints, so let's just avoid the trouble by defining it as returning int. Signed-off-by: Alberto Escolar Piedras --- drivers/can/can_native_linux.c | 3 ++- drivers/can/can_native_linux_adapt.c | 9 ++------- drivers/can/can_native_linux_adapt.h | 4 +--- 3 files changed, 5 insertions(+), 11 deletions(-) diff --git a/drivers/can/can_native_linux.c b/drivers/can/can_native_linux.c index bd93415c134..3f73117ae66 100644 --- a/drivers/can/can_native_linux.c +++ b/drivers/can/can_native_linux.c @@ -18,6 +18,7 @@ #include #include "can_native_linux_adapt.h" +#include "nsi_host_trampolines.h" LOG_MODULE_REGISTER(can_native_linux, CONFIG_CAN_LOG_LEVEL); @@ -179,7 +180,7 @@ static int can_native_linux_send(const struct device *dev, const struct can_fram data->tx_callback = callback; data->tx_user_data = user_data; - ret = linux_socketcan_write_data(data->dev_fd, &sframe, mtu); + ret = nsi_host_write(data->dev_fd, &sframe, mtu); if (ret < 0) { LOG_ERR("Cannot send CAN data len %d (%d)", sframe.len, -errno); } diff --git a/drivers/can/can_native_linux_adapt.c b/drivers/can/can_native_linux_adapt.c index c588591e080..1ec6f399e07 100644 --- a/drivers/can/can_native_linux_adapt.c +++ b/drivers/can/can_native_linux_adapt.c @@ -113,7 +113,7 @@ int linux_socketcan_poll_data(int fd) return -EAGAIN; } -ssize_t linux_socketcan_read_data(int fd, void *buf, size_t buf_len, bool *msg_confirm) +int linux_socketcan_read_data(int fd, void *buf, size_t buf_len, bool *msg_confirm) { struct canfd_frame *frame = (struct canfd_frame *)buf; struct msghdr msg = {0}; @@ -125,7 +125,7 @@ ssize_t linux_socketcan_read_data(int fd, void *buf, size_t buf_len, bool *msg_c msg.msg_iov = &iov; msg.msg_iovlen = 1; - int ret = recvmsg(fd, &msg, MSG_WAITALL); + int ret = (int)recvmsg(fd, &msg, MSG_WAITALL); if (msg_confirm != NULL) { *msg_confirm = (msg.msg_flags & MSG_CONFIRM) != 0; @@ -145,11 +145,6 @@ ssize_t linux_socketcan_read_data(int fd, void *buf, size_t buf_len, bool *msg_c return ret; } -ssize_t linux_socketcan_write_data(int fd, void *buf, size_t buf_len) -{ - return write(fd, buf, buf_len); -} - int linux_socketcan_set_mode_fd(int fd, bool mode_fd) { int opt = mode_fd ? 1 : 0; diff --git a/drivers/can/can_native_linux_adapt.h b/drivers/can/can_native_linux_adapt.h index 5156e0a0b0a..8d19b34a198 100644 --- a/drivers/can/can_native_linux_adapt.h +++ b/drivers/can/can_native_linux_adapt.h @@ -17,9 +17,7 @@ int linux_socketcan_iface_close(int fd); int linux_socketcan_poll_data(int fd); -ssize_t linux_socketcan_read_data(int fd, void *buf, size_t buf_len, bool *msg_confirm); - -ssize_t linux_socketcan_write_data(int fd, void *buf, size_t buf_len); +int linux_socketcan_read_data(int fd, void *buf, size_t buf_len, bool *msg_confirm); int linux_socketcan_set_mode_fd(int fd, bool mode_fd); From 5c06d60cceee12bf46ecd3e26c05cd1c6f3cf3fb Mon Sep 17 00:00:00 2001 From: Alberto Escolar Piedras Date: Thu, 28 Dec 2023 16:58:45 +0100 Subject: [PATCH 2247/3723] drivers eth_native_linux: Avoid using ssize ssize is a POSIX.1-2001 extension, which may or may not be provided by the C library, or may be defined to a different size in the host and embedded C library. Two internal functions were returning ssize. As these functions were just trampolines into the same host API, which are already provided by the native simulator let's just use those. Signed-off-by: Alberto Escolar Piedras --- drivers/ethernet/eth_native_posix.c | 5 +++-- drivers/ethernet/eth_native_posix_adapt.c | 10 ---------- drivers/ethernet/eth_native_posix_priv.h | 2 -- 3 files changed, 3 insertions(+), 14 deletions(-) diff --git a/drivers/ethernet/eth_native_posix.c b/drivers/ethernet/eth_native_posix.c index 4c0a9b0a7f1..9f1b7b2bcda 100644 --- a/drivers/ethernet/eth_native_posix.c +++ b/drivers/ethernet/eth_native_posix.c @@ -35,6 +35,7 @@ LOG_MODULE_REGISTER(LOG_MODULE_NAME); #include #include "eth_native_posix_priv.h" +#include "nsi_host_trampolines.h" #include "eth.h" #define NET_BUF_TIMEOUT K_MSEC(100) @@ -193,7 +194,7 @@ static int eth_send(const struct device *dev, struct net_pkt *pkt) LOG_DBG("Send pkt %p len %d", pkt, count); - ret = eth_write_data(ctx->dev_fd, ctx->send, count); + ret = nsi_host_write(ctx->dev_fd, ctx->send, count); if (ret < 0) { LOG_DBG("Cannot send pkt %p (%d)", pkt, ret); } @@ -321,7 +322,7 @@ static int read_data(struct eth_context *ctx, int fd) int status; int count; - count = eth_read_data(fd, ctx->recv, sizeof(ctx->recv)); + count = nsi_host_read(fd, ctx->recv, sizeof(ctx->recv)); if (count <= 0) { return 0; } diff --git a/drivers/ethernet/eth_native_posix_adapt.c b/drivers/ethernet/eth_native_posix_adapt.c index 7e3864910dc..81ae9bdcf8f 100644 --- a/drivers/ethernet/eth_native_posix_adapt.c +++ b/drivers/ethernet/eth_native_posix_adapt.c @@ -116,16 +116,6 @@ int eth_wait_data(int fd) return -EAGAIN; } -ssize_t eth_read_data(int fd, void *buf, size_t buf_len) -{ - return read(fd, buf, buf_len); -} - -ssize_t eth_write_data(int fd, void *buf, size_t buf_len) -{ - return write(fd, buf, buf_len); -} - int eth_clock_gettime(uint64_t *second, uint32_t *nanosecond) { struct timespec tp; diff --git a/drivers/ethernet/eth_native_posix_priv.h b/drivers/ethernet/eth_native_posix_priv.h index 7ce8c19f67a..f1d56f8df17 100644 --- a/drivers/ethernet/eth_native_posix_priv.h +++ b/drivers/ethernet/eth_native_posix_priv.h @@ -14,8 +14,6 @@ int eth_iface_create(const char *dev_name, const char *if_name, bool tun_only); int eth_iface_remove(int fd); int eth_wait_data(int fd); -ssize_t eth_read_data(int fd, void *buf, size_t buf_len); -ssize_t eth_write_data(int fd, void *buf, size_t buf_len); int eth_clock_gettime(uint64_t *second, uint32_t *nanosecond); int eth_promisc_mode(const char *if_name, bool enable); From 9f096e98160a22fb22257aa6c4c19d5705c13872 Mon Sep 17 00:00:00 2001 From: Yuval Peress Date: Thu, 11 Jan 2024 12:21:37 -0700 Subject: [PATCH 2248/3723] bma4xx: Optimize calculation Reduce some of the arithmetic required to decode a sample. Math is documented in bma4xx_convert_raw_accel_to_q31. This improved the accuracy from roughly 0.865mm/s2 to 0.001mm/s2 when stationary and using a range of 4g. Signed-off-by: Yuval Peress --- drivers/sensor/bma4xx/bma4xx.c | 77 ++++++++++++++-------------------- 1 file changed, 31 insertions(+), 46 deletions(-) diff --git a/drivers/sensor/bma4xx/bma4xx.c b/drivers/sensor/bma4xx/bma4xx.c index da7ff409184..9d8656d67aa 100644 --- a/drivers/sensor/bma4xx/bma4xx.c +++ b/drivers/sensor/bma4xx/bma4xx.c @@ -302,10 +302,12 @@ static int bma4xx_sample_fetch(const struct device *dev, int16_t *x, int16_t *y, return status; } + LOG_DBG("Raw values [0x%02x, 0x%02x, 0x%02x, 0x%02x, 0x%02x, 0x%02x]", read_data[0], + read_data[1], read_data[2], read_data[3], read_data[4], read_data[5]); /* Values in accel_data[N] are left-aligned and will read 16x actual */ - *x = (read_data[1] << 8) | (read_data[0] & 0xF0); - *y = (read_data[3] << 8) | (read_data[2] & 0xF0); - *z = (read_data[5] << 8) | (read_data[4] & 0xF0); + *x = ((int16_t)read_data[1] << 4) | FIELD_GET(GENMASK(7, 4), read_data[0]); + *y = ((int16_t)read_data[3] << 4) | FIELD_GET(GENMASK(7, 4), read_data[2]); + *z = ((int16_t)read_data[5] << 4) | FIELD_GET(GENMASK(7, 4), read_data[4]); LOG_DBG("XYZ reg vals are %d, %d, %d", *x, *y, *z); @@ -517,46 +519,32 @@ static int bma4xx_get_shift(enum sensor_channel channel, uint8_t accel_fs, int8_ } } -static void bma4xx_convert_raw_accel_to_q31(uint8_t accel_fs, int16_t raw_val, q31_t *out) +static void bma4xx_convert_raw_accel_to_q31(int16_t raw_val, q31_t *out) { - /* Raw readings are 12-bit signed ints left-aligned in a 16-bit container. Divide by 16 - * (arithmetic right shift by 4) to scale these into the correct range and properly handle - * the sign extension. + /* The full calculation is (assuming floating math): + * value_ms2 = raw_value * range * 9.8065 / BIT(11) + * We can treat 'range * 9.8065' as a scale, the scale is calculated by first getting 1g + * represented as a q31 value with the same shift as our result: + * 1g = (9.8065 * BIT(31)) >> shift + * Next, we need to multiply it by our range in g, which for this driver is one of + * [2, 4, 8, 16] and maps to a left shift of [1, 2, 3, 4]: + * 1g <<= log2(range) + * Note we used a right shift by 'shift' and left shift by log2(range). 'shift' is + * [5, 6, 7, 8] for range values [2, 4, 8, 16] since it's the final shift in m/s2. It is + * calculated via: + * shift = ceil(log2(range * 9.8065)) + * This means that we can shorten the above 1g alterations to: + * 1g = (1g >> ceil(log2(range * 9.8065))) << log2(range) + * For the range values [2, 4, 8, 16], the following is true: + * (x >> ceil(log2(range * 9.8065))) << log2(range) + * = x >> 4 + * Since the range cancels out in the right and left shift, we've now reduced the following: + * range * 9.8065 = 9.8065 * BIT(31 - 4) + * All that's left is to divide by the bma4xx's maximum range BIT(11). */ - raw_val /= 16; - - int8_t shift; - int lsb_per_g; - - switch (accel_fs) { - case BMA4XX_RANGE_2G: - lsb_per_g = 1024; - break; - case BMA4XX_RANGE_4G: - lsb_per_g = 512; - break; - case BMA4XX_RANGE_8G: - lsb_per_g = 256; - break; - case BMA4XX_RANGE_16G: - lsb_per_g = 128; - break; - default: - __ASSERT(0, "Invalid full-scale value"); - } - - if (bma4xx_get_shift(SENSOR_CHAN_ACCEL_XYZ, accel_fs, &shift)) { - __ASSERT(0, "Error obtaining shift"); - } + const int64_t scale = (int64_t)(9.8065 * BIT64(31 - 4)); - /* Use SENSOR_G and lsb_per_g to convert reg value into micro-m/s^2. Then re-scale into a - * Q-number with given shift by multiplying by (2^31 / (1<> 11, INT32_MIN, INT32_MAX); } #ifdef CONFIG_BMA4XX_TEMPERATURE @@ -607,12 +595,9 @@ static int bma4xx_one_shot_decode(const uint8_t *buffer, enum sensor_channel cha return -EINVAL; } - bma4xx_convert_raw_accel_to_q31(header->accel_fs, edata->accel_xyz[0], - &out->readings[0].x); - bma4xx_convert_raw_accel_to_q31(header->accel_fs, edata->accel_xyz[1], - &out->readings[0].y); - bma4xx_convert_raw_accel_to_q31(header->accel_fs, edata->accel_xyz[2], - &out->readings[0].z); + bma4xx_convert_raw_accel_to_q31(edata->accel_xyz[0], &out->readings[0].x); + bma4xx_convert_raw_accel_to_q31(edata->accel_xyz[1], &out->readings[0].y); + bma4xx_convert_raw_accel_to_q31(edata->accel_xyz[2], &out->readings[0].z); *fit = 1; return 1; From 11f7fa278200330fa4615e32489eefd174232c3f Mon Sep 17 00:00:00 2001 From: Jukka Rissanen Date: Fri, 24 Nov 2023 16:08:21 +0200 Subject: [PATCH 2249/3723] drivers: eth: phy: Remove syscall from phy API No point marking the phy API to be callable from usermode, the device cannot be accessed from usermode anyway so this is pointless. User can call the phy API from supervisor mode thread just fine. Signed-off-by: Jukka Rissanen --- doc/releases/migration-guide-3.6.rst | 5 ++++ include/zephyr/net/phy.h | 40 ++++++++-------------------- 2 files changed, 16 insertions(+), 29 deletions(-) diff --git a/doc/releases/migration-guide-3.6.rst b/doc/releases/migration-guide-3.6.rst index 8dc1b1f1ff2..26d18afa773 100644 --- a/doc/releases/migration-guide-3.6.rst +++ b/doc/releases/migration-guide-3.6.rst @@ -303,6 +303,11 @@ Networking The IPv6 hop limit value is also changed so that unicast and multicast packets can have a different one. (:github:`65886`) +* The Ethernet phy APIs defined in ```` are removed from syscall list. + The APIs were marked as callable from usermode but in practice this does not work as the device + cannot be accessed from usermode thread. This means that the API calls will need to made + from supervisor mode thread. + Other Subsystems ================ diff --git a/include/zephyr/net/phy.h b/include/zephyr/net/phy.h index 40de7137276..38c6d1f5bbe 100644 --- a/include/zephyr/net/phy.h +++ b/include/zephyr/net/phy.h @@ -110,11 +110,8 @@ __subsystem struct ethphy_driver_api { * @retval -EIO If communication with PHY failed. * @retval -ENOTSUP If not supported. */ -__syscall int phy_configure_link(const struct device *dev, - enum phy_link_speed speeds); - -static inline int z_impl_phy_configure_link(const struct device *dev, - enum phy_link_speed speeds) +static inline int phy_configure_link(const struct device *dev, + enum phy_link_speed speeds) { const struct ethphy_driver_api *api = (const struct ethphy_driver_api *)dev->api; @@ -135,11 +132,8 @@ static inline int z_impl_phy_configure_link(const struct device *dev, * @retval 0 If successful. * @retval -EIO If communication with PHY failed. */ -__syscall int phy_get_link_state(const struct device *dev, - struct phy_link_state *state); - -static inline int z_impl_phy_get_link_state(const struct device *dev, - struct phy_link_state *state) +static inline int phy_get_link_state(const struct device *dev, + struct phy_link_state *state) { const struct ethphy_driver_api *api = (const struct ethphy_driver_api *)dev->api; @@ -161,13 +155,9 @@ static inline int z_impl_phy_get_link_state(const struct device *dev, * @retval 0 If successful. * @retval -ENOTSUP If not supported. */ -__syscall int phy_link_callback_set(const struct device *dev, - phy_callback_t callback, - void *user_data); - -static inline int z_impl_phy_link_callback_set(const struct device *dev, - phy_callback_t callback, - void *user_data) +static inline int phy_link_callback_set(const struct device *dev, + phy_callback_t callback, + void *user_data) { const struct ethphy_driver_api *api = (const struct ethphy_driver_api *)dev->api; @@ -187,11 +177,8 @@ static inline int z_impl_phy_link_callback_set(const struct device *dev, * @retval 0 If successful. * @retval -EIO If communication with PHY failed. */ -__syscall int phy_read(const struct device *dev, uint16_t reg_addr, - uint32_t *value); - -static inline int z_impl_phy_read(const struct device *dev, uint16_t reg_addr, - uint32_t *value) +static inline int phy_read(const struct device *dev, uint16_t reg_addr, + uint32_t *value) { const struct ethphy_driver_api *api = (const struct ethphy_driver_api *)dev->api; @@ -211,11 +198,8 @@ static inline int z_impl_phy_read(const struct device *dev, uint16_t reg_addr, * @retval 0 If successful. * @retval -EIO If communication with PHY failed. */ -__syscall int phy_write(const struct device *dev, uint16_t reg_addr, - uint32_t value); - -static inline int z_impl_phy_write(const struct device *dev, uint16_t reg_addr, - uint32_t value) +static inline int phy_write(const struct device *dev, uint16_t reg_addr, + uint32_t value) { const struct ethphy_driver_api *api = (const struct ethphy_driver_api *)dev->api; @@ -232,6 +216,4 @@ static inline int z_impl_phy_write(const struct device *dev, uint16_t reg_addr, * @} */ -#include - #endif /* ZEPHYR_INCLUDE_DRIVERS_PHY_H_ */ From 38690800b8ea8fea1066252f9cd074f15297f8b1 Mon Sep 17 00:00:00 2001 From: Anas Nashif Date: Mon, 15 Jan 2024 13:10:43 -0500 Subject: [PATCH 2250/3723] MAINTAINERS: remove inactive collaborator from area Remove inactive collaborator from Intel ADAP area. Signed-off-by: Anas Nashif --- MAINTAINERS.yml | 1 - 1 file changed, 1 deletion(-) diff --git a/MAINTAINERS.yml b/MAINTAINERS.yml index b8a32451a9d..6147f245e46 100644 --- a/MAINTAINERS.yml +++ b/MAINTAINERS.yml @@ -3124,7 +3124,6 @@ Intel Platforms (Xtensa): - marc-hb - kv2019i - ceolin - - aborisovich - tmleman - softwarecki - jxstelter From c2b16d7403d363f8d31231d963b17c8d83ece5a2 Mon Sep 17 00:00:00 2001 From: Anas Nashif Date: Mon, 15 Jan 2024 17:08:48 -0500 Subject: [PATCH 2251/3723] ci: pr stats: count hours open since moving out of draft if a PR was made ready for review from draft, calculate based on when it was moved out of draft. Signed-off-by: Anas Nashif --- scripts/ci/stats/merged_prs.py | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) diff --git a/scripts/ci/stats/merged_prs.py b/scripts/ci/stats/merged_prs.py index eb0a15c026d..9daaa560c2d 100755 --- a/scripts/ci/stats/merged_prs.py +++ b/scripts/ci/stats/merged_prs.py @@ -74,12 +74,19 @@ def process_pr(pr): prj['review_rule'] = "no" + created = pr.created_at + # if a PR was made ready for review from draft, calculate based on when it + # was moved out of draft. + for event in pr.get_issue_events(): + if event.event == 'ready_for_review': + created = event.created_at + # calculate time the PR was in review, hours and business days. - delta = pr.closed_at - pr.created_at + delta = pr.closed_at - created deltah = delta.total_seconds() / 3600 prj['hours_open'] = deltah - dates = (pr.created_at + timedelta(idx + 1) for idx in range((pr.closed_at - pr.created_at).days)) + dates = (created + timedelta(idx + 1) for idx in range((pr.closed_at - created).days)) # Get number of business days per the guidelines, we need at least 2. business_days = sum(1 for day in dates if day.weekday() < 5) From a6dab1a85eb26bb15c063cfbb2f6972cb3b80e55 Mon Sep 17 00:00:00 2001 From: Christopher Friedt Date: Sat, 13 Jan 2024 15:28:02 -0500 Subject: [PATCH 2252/3723] posix: pthread: additional null checks on parameters Instead of relying on a fault occurring when NULL parameters are passed in, explicitly check and return EINVAL. Signed-off-by: Christopher Friedt --- lib/posix/pthread.c | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/lib/posix/pthread.c b/lib/posix/pthread.c index 2e2c49f2a35..14760908031 100644 --- a/lib/posix/pthread.c +++ b/lib/posix/pthread.c @@ -260,15 +260,14 @@ static int32_t posix_to_zephyr_priority(uint32_t priority, int policy) int pthread_attr_setschedparam(pthread_attr_t *_attr, const struct sched_param *schedparam) { struct posix_thread_attr *attr = (struct posix_thread_attr *)_attr; - int priority = schedparam->sched_priority; - if (attr == NULL || !attr->initialized || - !is_posix_policy_prio_valid(priority, attr->schedpolicy)) { + if (attr == NULL || !attr->initialized || schedparam == NULL || + !is_posix_policy_prio_valid(schedparam->sched_priority, attr->schedpolicy)) { LOG_ERR("Invalid pthread_attr_t or sched_param"); return EINVAL; } - attr->priority = priority; + attr->priority = schedparam->sched_priority; return 0; } @@ -884,7 +883,7 @@ int pthread_attr_getdetachstate(const pthread_attr_t *_attr, int *detachstate) { const struct posix_thread_attr *attr = (const struct posix_thread_attr *)_attr; - if ((attr == NULL) || (attr->initialized == false)) { + if ((attr == NULL) || (attr->initialized == false) || (detachstate == NULL)) { return EINVAL; } @@ -920,7 +919,7 @@ int pthread_attr_getschedpolicy(const pthread_attr_t *_attr, int *policy) { const struct posix_thread_attr *attr = (const struct posix_thread_attr *)_attr; - if ((attr == NULL) || (attr->initialized == 0U)) { + if ((attr == NULL) || (attr->initialized == 0U) || (policy == NULL)) { return EINVAL; } @@ -954,7 +953,7 @@ int pthread_attr_getstacksize(const pthread_attr_t *_attr, size_t *stacksize) { const struct posix_thread_attr *attr = (const struct posix_thread_attr *)_attr; - if ((attr == NULL) || (attr->initialized == false)) { + if ((attr == NULL) || (attr->initialized == false) || (stacksize == NULL)) { return EINVAL; } @@ -992,7 +991,8 @@ int pthread_attr_getstack(const pthread_attr_t *_attr, void **stackaddr, size_t { const struct posix_thread_attr *attr = (const struct posix_thread_attr *)_attr; - if ((attr == NULL) || (attr->initialized == false)) { + if ((attr == NULL) || (attr->initialized == false) || (stackaddr == NULL) || + (stacksize == NULL)) { return EINVAL; } @@ -1036,7 +1036,7 @@ int pthread_attr_getschedparam(const pthread_attr_t *_attr, struct sched_param * { struct posix_thread_attr *attr = (struct posix_thread_attr *)_attr; - if ((attr == NULL) || (attr->initialized == false)) { + if ((attr == NULL) || (attr->initialized == false) || (schedparam == NULL)) { return EINVAL; } From 414868aacea58fbfebf371a51f0835be75ac768f Mon Sep 17 00:00:00 2001 From: Christopher Friedt Date: Sat, 13 Jan 2024 15:05:38 -0500 Subject: [PATCH 2253/3723] tests: posix: common: move condattr test to cond.c Move posix_apis.test_pthread_condattr to cond.c . Create a separate cond ZTEST_SUITE(). Signed-off-by: Christopher Friedt --- tests/posix/common/src/cond.c | 34 +++++++++++++++++++++++++++----- tests/posix/common/src/pthread.c | 22 --------------------- 2 files changed, 29 insertions(+), 27 deletions(-) diff --git a/tests/posix/common/src/cond.c b/tests/posix/common/src/cond.c index 76794f43a4e..b648ac0abd0 100644 --- a/tests/posix/common/src/cond.c +++ b/tests/posix/common/src/cond.c @@ -13,7 +13,7 @@ * * @details Exactly CONFIG_MAX_PTHREAD_COND_COUNT can be in use at once. */ -ZTEST(posix_apis, test_cond_resource_exhausted) +ZTEST(cond, test_cond_resource_exhausted) { size_t i; pthread_cond_t m[CONFIG_MAX_PTHREAD_COND_COUNT + 1]; @@ -37,12 +37,36 @@ ZTEST(posix_apis, test_cond_resource_exhausted) * * @details Demonstrate that condition variables may be used over and over again. */ -ZTEST(posix_apis, test_cond_resource_leak) +ZTEST(cond, test_cond_resource_leak) { - pthread_cond_t m; + pthread_cond_t cond; for (size_t i = 0; i < 2 * CONFIG_MAX_PTHREAD_COND_COUNT; ++i) { - zassert_ok(pthread_cond_init(&m, NULL), "failed to init cond %zu", i); - zassert_ok(pthread_cond_destroy(&m), "failed to destroy cond %zu", i); + zassert_ok(pthread_cond_init(&cond, NULL), "failed to init cond %zu", i); + zassert_ok(pthread_cond_destroy(&cond), "failed to destroy cond %zu", i); } } + +ZTEST(cond, test_pthread_condattr) +{ + clockid_t clock_id; + pthread_condattr_t att = {0}; + + zassert_ok(pthread_condattr_init(&att)); + + zassert_ok(pthread_condattr_getclock(&att, &clock_id), "pthread_condattr_getclock failed"); + zassert_equal(clock_id, CLOCK_MONOTONIC, "clock attribute not set correctly"); + + zassert_ok(pthread_condattr_setclock(&att, CLOCK_REALTIME), + "pthread_condattr_setclock failed"); + + zassert_ok(pthread_condattr_getclock(&att, &clock_id), "pthread_condattr_setclock failed"); + zassert_equal(clock_id, CLOCK_REALTIME, "clock attribute not set correctly"); + + zassert_equal(pthread_condattr_setclock(&att, 42), -EINVAL, + "pthread_condattr_setclock did not return EINVAL"); + + zassert_ok(pthread_condattr_destroy(&att)); +} + +ZTEST_SUITE(cond, NULL, NULL, NULL, NULL, NULL); diff --git a/tests/posix/common/src/pthread.c b/tests/posix/common/src/pthread.c index 6210da0a020..de46f824cca 100644 --- a/tests/posix/common/src/pthread.c +++ b/tests/posix/common/src/pthread.c @@ -231,28 +231,6 @@ void *thread_top_term(void *p1) return NULL; } -ZTEST(posix_apis, test_pthread_condattr) -{ - clockid_t clock_id; - pthread_condattr_t att; - - zassert_ok(pthread_condattr_init(&att), "pthread_condattr_init failed"); - - zassert_ok(pthread_condattr_getclock(&att, &clock_id), "pthread_condattr_getclock failed"); - zassert_equal(clock_id, CLOCK_MONOTONIC, "clock attribute not set correctly"); - - zassert_ok(pthread_condattr_setclock(&att, CLOCK_REALTIME), - "pthread_condattr_setclock failed"); - - zassert_ok(pthread_condattr_getclock(&att, &clock_id), "pthread_condattr_setclock failed"); - zassert_equal(clock_id, CLOCK_REALTIME, "clock attribute not set correctly"); - - zassert_equal(pthread_condattr_setclock(&att, 42), - -EINVAL, "pthread_condattr_setclock did not return EINVAL"); - - zassert_ok(pthread_condattr_destroy(&att), "pthread_condattr_destroy failed"); -} - ZTEST(posix_apis, test_pthread_execution) { int i, ret, min_prio, max_prio; From a2a3140a7424c8140be7144e992640708394cba6 Mon Sep 17 00:00:00 2001 From: Christopher Friedt Date: Sat, 13 Jan 2024 15:42:21 -0500 Subject: [PATCH 2254/3723] tests: posix: common: move barrier test to barrier.c Move the one barrier test to its own file and create a ZTEST_SUITE() for barrier. Signed-off-by: Christopher Friedt --- tests/posix/common/src/barrier.c | 41 ++++++++++++++++++++++++++++++++ tests/posix/common/src/pthread.c | 28 ---------------------- 2 files changed, 41 insertions(+), 28 deletions(-) create mode 100644 tests/posix/common/src/barrier.c diff --git a/tests/posix/common/src/barrier.c b/tests/posix/common/src/barrier.c new file mode 100644 index 00000000000..f168f8368dc --- /dev/null +++ b/tests/posix/common/src/barrier.c @@ -0,0 +1,41 @@ +/* + * Copyright (c) 2023, Harshil Bhatt + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include +#include + +#include +#include + +ZTEST(barrier, test_barrier) +{ + int ret, pshared; + pthread_barrierattr_t attr; + + ret = pthread_barrierattr_init(&attr); + zassert_equal(ret, 0, "pthread_barrierattr_init failed"); + + ret = pthread_barrierattr_getpshared(&attr, &pshared); + zassert_equal(ret, 0, "pthread_barrierattr_getpshared failed"); + zassert_equal(pshared, PTHREAD_PROCESS_PRIVATE, "pshared attribute not set correctly"); + + ret = pthread_barrierattr_setpshared(&attr, PTHREAD_PROCESS_PRIVATE); + zassert_equal(ret, 0, "pthread_barrierattr_setpshared failed"); + + ret = pthread_barrierattr_setpshared(&attr, PTHREAD_PROCESS_PUBLIC); + zassert_equal(ret, 0, "pthread_barrierattr_setpshared failed"); + + ret = pthread_barrierattr_getpshared(&attr, &pshared); + zassert_equal(pshared, PTHREAD_PROCESS_PUBLIC, "pshared attribute not retrieved correctly"); + + ret = pthread_barrierattr_setpshared(&attr, 42); + zassert_equal(ret, -EINVAL, "pthread_barrierattr_setpshared did not return EINVAL"); + + ret = pthread_barrierattr_destroy(&attr); + zassert_equal(ret, 0, "pthread_barrierattr_destroy failed"); +} + +ZTEST_SUITE(barrier, NULL, NULL, NULL, NULL, NULL); diff --git a/tests/posix/common/src/pthread.c b/tests/posix/common/src/pthread.c index de46f824cca..0ceadbd1449 100644 --- a/tests/posix/common/src/pthread.c +++ b/tests/posix/common/src/pthread.c @@ -777,34 +777,6 @@ ZTEST(posix_apis, test_sched_policy) } } -ZTEST(posix_apis, test_barrier) -{ - int ret, pshared; - pthread_barrierattr_t attr; - - ret = pthread_barrierattr_init(&attr); - zassert_equal(ret, 0, "pthread_barrierattr_init failed"); - - ret = pthread_barrierattr_getpshared(&attr, &pshared); - zassert_equal(ret, 0, "pthread_barrierattr_getpshared failed"); - zassert_equal(pshared, PTHREAD_PROCESS_PRIVATE, "pshared attribute not set correctly"); - - ret = pthread_barrierattr_setpshared(&attr, PTHREAD_PROCESS_PRIVATE); - zassert_equal(ret, 0, "pthread_barrierattr_setpshared failed"); - - ret = pthread_barrierattr_setpshared(&attr, PTHREAD_PROCESS_PUBLIC); - zassert_equal(ret, 0, "pthread_barrierattr_setpshared failed"); - - ret = pthread_barrierattr_getpshared(&attr, &pshared); - zassert_equal(pshared, PTHREAD_PROCESS_PUBLIC, "pshared attribute not retrieved correctly"); - - ret = pthread_barrierattr_setpshared(&attr, 42); - zassert_equal(ret, -EINVAL, "pthread_barrierattr_setpshared did not return EINVAL"); - - ret = pthread_barrierattr_destroy(&attr); - zassert_equal(ret, 0, "pthread_barrierattr_destroy failed"); -} - ZTEST(posix_apis, test_pthread_equal) { zassert_true(pthread_equal(pthread_self(), pthread_self())); From 9074feabf6f827f6b37a69d77a5e13093799a905 Mon Sep 17 00:00:00 2001 From: Christopher Friedt Date: Sat, 13 Jan 2024 15:26:01 -0500 Subject: [PATCH 2255/3723] tests: posix: separate suite for pthread_t and pthread_attr_t In order to make state more manageable among the other posix api tests, create a separate ZTEST_SUITE() called pthread and another ZTEST_SUITE() called pthread_attr. The tests in the pthread suite mainly operate on the pthread_t type, while tests in the pthread_attr suite mainly operate on the pthread_attr_t type. The pthread_attr testsuite is moved to a separate file (pthread_attr.c). Having separate test suites allows us to narrow the scope of the tests and have a better degree of control over the state. Some effort went in to highlighting undefined behaviour at the API level. This was quite intentional, as we will need to be be able to test / verify that we do in fact have deterministic outcomes when users attempt operations that result in undefined behaviour (e.g. assert). Signed-off-by: Christopher Friedt --- tests/posix/common/src/pthread.c | 562 +---------------------- tests/posix/common/src/pthread_attr.c | 636 ++++++++++++++++++++++++++ 2 files changed, 656 insertions(+), 542 deletions(-) create mode 100644 tests/posix/common/src/pthread_attr.c diff --git a/tests/posix/common/src/pthread.c b/tests/posix/common/src/pthread.c index 0ceadbd1449..02cff3d1e79 100644 --- a/tests/posix/common/src/pthread.c +++ b/tests/posix/common/src/pthread.c @@ -13,23 +13,14 @@ #define N_THR_E 3 #define N_THR_T 4 #define BOUNCES 64 -#define STACKS (MAX(1024, PTHREAD_STACK_MIN) + CONFIG_TEST_EXTRA_STACK_SIZE) -#define THREAD_PRIORITY 3 #define ONE_SECOND 1 -/* arbitrary number that is also a legal stack size */ -#define OKAY_STACK_SIZE (STACKS + 1) - /* Macros to test invalid states */ #define PTHREAD_CANCEL_INVALID -1 #define SCHED_INVALID -1 #define PRIO_INVALID -1 #define PTHREAD_INVALID -1 -K_THREAD_STACK_ARRAY_DEFINE(stack_e, N_THR_E, STACKS); -K_THREAD_STACK_ARRAY_DEFINE(stack_t, N_THR_T, STACKS); -K_THREAD_STACK_ARRAY_DEFINE(stack_1, 1, 32); - void *thread_top_exec(void *p1); void *thread_top_term(void *p1); @@ -49,8 +40,6 @@ static int barrier_failed; static int barrier_done[N_THR_E]; static int barrier_return[N_THR_E]; -static uint32_t param; - /* First phase bounces execution between two threads using a condition * variable, continuously testing that no other thread is mucking with * the protected state. This ends with all threads going back to @@ -214,13 +203,8 @@ void *thread_top_term(void *p1) } if (id >= 2) { - if (IS_ENABLED(CONFIG_DYNAMIC_THREAD)) { - zassert_false(pthread_detach(self), "failed to set detach state"); - } - ret = pthread_detach(self); - if (id == 2) { - zassert_equal(ret, EINVAL, "re-detached thread!"); - } + zassert_ok(pthread_detach(self), "failed to set detach state"); + zassert_equal(pthread_detach(self), EINVAL, "re-detached thread!"); } printk("Cancelling thread %d\n", id); @@ -231,16 +215,11 @@ void *thread_top_term(void *p1) return NULL; } -ZTEST(posix_apis, test_pthread_execution) +ZTEST(pthread, test_pthread_execution) { - int i, ret, min_prio, max_prio; - int dstate, policy; - pthread_attr_t attr[N_THR_E] = {}; - struct sched_param schedparam, getschedparam; + int i, ret; pthread_t newthread[N_THR_E]; - int schedpolicy = SCHED_FIFO; - void *retval, *stackaddr; - size_t stacksize; + void *retval; int serial_threads = 0; static const char thr_name[] = "thread name"; char thr_name_buf[CONFIG_THREAD_MAX_NAME_LEN]; @@ -252,51 +231,6 @@ ZTEST(posix_apis, test_pthread_execution) zassert_ok(pthread_barrier_init(&barrier, NULL, N_THR_E)); sem_init(&main_sem, 0, 1); - schedparam.sched_priority = CONFIG_NUM_COOP_PRIORITIES - 1; - min_prio = sched_get_priority_min(schedpolicy); - max_prio = sched_get_priority_max(schedpolicy); - - ret = (min_prio < 0 || max_prio < 0 || - schedparam.sched_priority < min_prio || - schedparam.sched_priority > max_prio); - - /* TESTPOINT: Check if scheduling priority is valid */ - zassert_false(ret, - "Scheduling priority outside valid priority range"); - - /* TESTPOINTS: Try setting attributes before init */ - ret = pthread_attr_setschedparam(&attr[0], &schedparam); - zassert_equal(ret, EINVAL, "uninitialized attr set!"); - - ret = pthread_attr_setdetachstate(&attr[0], PTHREAD_CREATE_JOINABLE); - zassert_equal(ret, EINVAL, "uninitialized attr set!"); - - ret = pthread_attr_setschedpolicy(&attr[0], schedpolicy); - zassert_equal(ret, EINVAL, "uninitialized attr set!"); - - /* TESTPOINT: Try setting attribute with empty stack */ - ret = pthread_attr_setstack(&attr[0], 0, STACKS); - zassert_equal(ret, EACCES, "empty stack set!"); - - /* TESTPOINTS: Try getting attributes before init */ - ret = pthread_attr_getschedparam(&attr[0], &getschedparam); - zassert_equal(ret, EINVAL, "uninitialized attr retrieved!"); - - ret = pthread_attr_getdetachstate(&attr[0], &dstate); - zassert_equal(ret, EINVAL, "uninitialized attr retrieved!"); - - ret = pthread_attr_getschedpolicy(&attr[0], &policy); - zassert_equal(ret, EINVAL, "uninitialized attr retrieved!"); - - ret = pthread_attr_getstack(&attr[0], &stackaddr, &stacksize); - zassert_equal(ret, EINVAL, "uninitialized attr retrieved!"); - - ret = pthread_attr_getstacksize(&attr[0], &stacksize); - zassert_equal(ret, EINVAL, "uninitialized attr retrieved!"); - - /* TESTPOINT: Try destroying attr before init */ - ret = pthread_attr_destroy(&attr[0]); - zassert_equal(ret, EINVAL, "uninitialized attr destroyed!"); /* TESTPOINT: Try getting name of NULL thread (aka uninitialized * thread var). @@ -304,60 +238,16 @@ ZTEST(posix_apis, test_pthread_execution) ret = pthread_getname_np(PTHREAD_INVALID, thr_name_buf, sizeof(thr_name_buf)); zassert_equal(ret, ESRCH, "uninitialized getname!"); + for (i = 0; i < N_THR_E; i++) { + ret = pthread_create(&newthread[i], NULL, thread_top_exec, INT_TO_POINTER(i)); + } + /* TESTPOINT: Try setting name of NULL thread (aka uninitialized * thread var). */ ret = pthread_setname_np(PTHREAD_INVALID, thr_name); zassert_equal(ret, ESRCH, "uninitialized setname!"); - /* TESTPOINT: Try creating thread before attr init */ - ret = pthread_create(&newthread[0], &attr[0], - thread_top_exec, NULL); - zassert_equal(ret, EINVAL, "thread created before attr init!"); - - for (i = 0; i < N_THR_E; i++) { - ret = pthread_attr_init(&attr[i]); - if (ret != 0) { - zassert_false(pthread_attr_destroy(&attr[i]), - "Unable to destroy pthread object attrib"); - zassert_false(pthread_attr_init(&attr[i]), - "Unable to create pthread object attrib"); - } - - /* TESTPOINTS: Retrieve set stack attributes and compare */ - pthread_attr_setstack(&attr[i], &stack_e[i][0], STACKS); - stackaddr = NULL; - pthread_attr_getstack(&attr[i], &stackaddr, &stacksize); - zassert_equal_ptr(&stack_e[i][0], stackaddr, - "stack attribute addresses do not match!"); - zassert_equal(STACKS, stacksize, "stack sizes do not match!"); - - pthread_attr_getstacksize(&attr[i], &stacksize); - zassert_equal(STACKS, stacksize, "stack sizes do not match!"); - - pthread_attr_setschedpolicy(&attr[i], schedpolicy); - pthread_attr_getschedpolicy(&attr[i], &policy); - zassert_equal(schedpolicy, policy, - "scheduling policies do not match!"); - - pthread_attr_setschedparam(&attr[i], &schedparam); - pthread_attr_getschedparam(&attr[i], &getschedparam); - zassert_equal(schedparam.sched_priority, - getschedparam.sched_priority, - "scheduling priorities do not match!"); - - if (IS_ENABLED(CONFIG_DYNAMIC_THREAD)) { - ret = pthread_create(&newthread[i], NULL, thread_top_exec, - INT_TO_POINTER(i)); - } else { - ret = pthread_create(&newthread[i], &attr[i], thread_top_exec, - INT_TO_POINTER(i)); - } - - /* TESTPOINT: Check if thread is created successfully */ - zassert_false(ret, "Number of threads exceed max limit"); - } - /* TESTPOINT: Try getting thread name with no buffer */ ret = pthread_getname_np(newthread[0], NULL, sizeof(thr_name_buf)); zassert_equal(ret, EINVAL, "uninitialized getname!"); @@ -416,119 +306,22 @@ ZTEST(posix_apis, test_pthread_execution) printk("Barrier test OK\n"); } -ZTEST(posix_apis, test_pthread_errors_errno) -{ - pthread_attr_t attr; - struct sched_param param; - void *stackaddr; - size_t stacksize; - int policy, detach; - static pthread_once_t key; - - /* TESTPOINT: invoke pthread APIs with NULL */ - zassert_equal(pthread_attr_destroy(NULL), EINVAL, - "pthread destroy NULL error"); - zassert_equal(pthread_attr_getschedparam(NULL, ¶m), EINVAL, - "get scheduling param error"); - zassert_equal(pthread_attr_getstack(NULL, &stackaddr, &stacksize), - EINVAL, "get stack attributes error"); - zassert_equal(pthread_attr_getstacksize(NULL, &stacksize), - EINVAL, "get stack size error"); - zassert_equal(pthread_attr_setschedpolicy(NULL, 2), - EINVAL, "set scheduling policy error"); - zassert_equal(pthread_attr_getschedpolicy(NULL, &policy), - EINVAL, "get scheduling policy error"); - zassert_equal(pthread_attr_setdetachstate(NULL, 0), - EINVAL, "pthread set detach state with NULL error"); - zassert_equal(pthread_attr_getdetachstate(NULL, &detach), - EINVAL, "get detach state error"); - zassert_equal(pthread_detach(PTHREAD_INVALID), ESRCH, "detach with NULL error"); - zassert_equal(pthread_attr_init(NULL), ENOMEM, - "init with NULL error"); - zassert_equal(pthread_attr_setschedparam(NULL, ¶m), EINVAL, - "set sched param with NULL error"); - zassert_equal(pthread_cancel(PTHREAD_INVALID), ESRCH, - "cancel NULL error"); - zassert_equal(pthread_join(PTHREAD_INVALID, NULL), ESRCH, - "join with NULL has error"); - zassert_equal(pthread_once(&key, NULL), EINVAL, - "pthread dynamic package initialization error"); - zassert_equal(pthread_getschedparam(PTHREAD_INVALID, &policy, ¶m), ESRCH, - "get schedparam with NULL error"); - zassert_equal(pthread_setschedparam(PTHREAD_INVALID, policy, ¶m), ESRCH, - "set schedparam with NULL error"); - - attr = (pthread_attr_t){0}; - zassert_equal(pthread_attr_getdetachstate(&attr, &detach), - EINVAL, "get detach state error"); - - /* Initialise thread attribute to ensure won't be return with init error */ - zassert_false(pthread_attr_init(&attr), - "Unable to create pthread object attr"); - zassert_false(pthread_attr_setschedpolicy(&attr, SCHED_FIFO), - "set scheduling policy error"); - zassert_false(pthread_attr_setschedpolicy(&attr, SCHED_RR), "set scheduling policy error"); - zassert_false(pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_JOINABLE), - "set detach state error"); - zassert_false(pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED), - "set detach state error"); - zassert_equal(pthread_attr_setdetachstate(&attr, 3), - EINVAL, "set detach state error"); - zassert_false(pthread_attr_getdetachstate(&attr, &detach), - "get detach state error"); -} - -ZTEST(posix_apis, test_pthread_termination) +ZTEST(pthread, test_pthread_termination) { int32_t i, ret; - int oldstate, policy; - pthread_attr_t attr[N_THR_T]; - struct sched_param schedparam; - pthread_t newthread[N_THR_T]; + int oldstate; + pthread_t newthread[N_THR_T] = {0}; void *retval; - /* Creating 4 threads with lowest application priority */ + /* Creating 4 threads */ for (i = 0; i < N_THR_T; i++) { - ret = pthread_attr_init(&attr[i]); - if (ret != 0) { - zassert_false(pthread_attr_destroy(&attr[i]), - "Unable to destroy pthread object attrib"); - zassert_false(pthread_attr_init(&attr[i]), - "Unable to create pthread object attrib"); - } - - if (i == 2) { - pthread_attr_setdetachstate(&attr[i], - PTHREAD_CREATE_DETACHED); - } - - schedparam.sched_priority = 2; - pthread_attr_setschedparam(&attr[i], &schedparam); - pthread_attr_setstack(&attr[i], &stack_t[i][0], STACKS); - if (IS_ENABLED(CONFIG_DYNAMIC_THREAD)) { - ret = pthread_create(&newthread[i], NULL, thread_top_term, - INT_TO_POINTER(i)); - } else { - ret = pthread_create(&newthread[i], &attr[i], thread_top_term, - INT_TO_POINTER(i)); - } - - zassert_false(ret, "Not enough space to create new thread"); + zassert_ok(pthread_create(&newthread[i], NULL, thread_top_term, INT_TO_POINTER(i))); } /* TESTPOINT: Try setting invalid cancel state to current thread */ ret = pthread_setcancelstate(PTHREAD_CANCEL_INVALID, &oldstate); zassert_equal(ret, EINVAL, "invalid cancel state set!"); - /* TESTPOINT: Try setting invalid policy */ - ret = pthread_setschedparam(newthread[0], SCHED_INVALID, &schedparam); - zassert_equal(ret, EINVAL, "invalid policy set!"); - - /* TESTPOINT: Try setting invalid priority */ - schedparam.sched_priority = PRIO_INVALID; - ret = pthread_setschedparam(newthread[0], SCHED_RR, &schedparam); - zassert_equal(ret, EINVAL, "invalid priority set!"); - for (i = 0; i < N_THR_T; i++) { pthread_join(newthread[i], &retval); } @@ -540,32 +333,6 @@ ZTEST(posix_apis, test_pthread_termination) /* TESTPOINT: Try canceling a terminated thread */ ret = pthread_cancel(newthread[N_THR_T/2]); zassert_equal(ret, ESRCH, "cancelled a terminated thread!"); - - /* TESTPOINT: Try getting scheduling info from terminated thread */ - ret = pthread_getschedparam(newthread[N_THR_T/2], &policy, &schedparam); - zassert_equal(ret, ESRCH, "got attr from terminated thread!"); -} - -ZTEST(posix_apis, test_pthread_attr_stacksize) -{ - size_t act_size; - pthread_attr_t attr; - const size_t exp_size = OKAY_STACK_SIZE; - - /* TESTPOINT: specify a custom stack size via pthread_attr_t */ - zassert_equal(0, pthread_attr_init(&attr), "pthread_attr_init() failed"); - - if (PTHREAD_STACK_MIN > 0) { - zassert_equal(EINVAL, pthread_attr_setstacksize(&attr, 0), - "pthread_attr_setstacksize() did not fail"); - } - - zassert_equal(0, pthread_attr_setstacksize(&attr, exp_size), - "pthread_attr_setstacksize() failed"); - zassert_equal(0, pthread_attr_getstacksize(&attr, &act_size), - "pthread_attr_getstacksize() failed"); - zassert_equal(exp_size, act_size, "wrong size: act: %zu exp: %zu", - exp_size, act_size); } static void *create_thread1(void *p1) @@ -574,50 +341,14 @@ static void *create_thread1(void *p1) return NULL; } -ZTEST(posix_apis, test_pthread_create_negative) -{ - int ret; - pthread_t pthread1; - pthread_attr_t attr1; - - /* create pthread without attr initialized */ - if (!IS_ENABLED(CONFIG_DYNAMIC_THREAD)) { - ret = pthread_create(&pthread1, NULL, create_thread1, (void *)1); - zassert_equal(ret, EAGAIN, "create thread with NULL successful"); - } - - /* initialized attr without set stack to create thread */ - ret = pthread_attr_init(&attr1); - zassert_false(ret, "attr1 initialized failed"); - - attr1 = (pthread_attr_t){0}; - ret = pthread_create(&pthread1, &attr1, create_thread1, (void *)1); - zassert_equal(ret, EINVAL, "create successful with NULL attr"); - - /* set stack size 0 to create thread */ - pthread_attr_setstack(&attr1, &stack_1, 0); - ret = pthread_create(&pthread1, &attr1, create_thread1, (void *)1); - zassert_equal(ret, EINVAL, "create thread with 0 size"); -} - -ZTEST(posix_apis, test_pthread_descriptor_leak) +ZTEST(pthread, test_pthread_descriptor_leak) { pthread_t pthread1; - pthread_attr_t attr; - - zassert_ok(pthread_attr_init(&attr)); - zassert_ok(pthread_attr_setstack(&attr, &stack_e[0][0], STACKS)); /* If we are leaking descriptors, then this loop will never complete */ for (size_t i = 0; i < CONFIG_MAX_PTHREAD_COUNT * 2; ++i) { - zassert_ok(pthread_create(&pthread1, &attr, create_thread1, NULL), + zassert_ok(pthread_create(&pthread1, NULL, create_thread1, NULL), "unable to create thread %zu", i); - /* - * k_msleep() should not be necessary, but it is added as a workaround - * for #56163 and #58116, which identified race conditions on some - * platforms. - */ - k_msleep(100); zassert_ok(pthread_join(pthread1, NULL), "unable to join thread %zu", i); } } @@ -639,210 +370,13 @@ ZTEST(posix_apis, test_sched_getscheduler) zassert_true((rc == -1 && err == ENOSYS)); } -ZTEST(posix_apis, test_sched_policy) -{ - /* - * TODO: - * 1. assert that _POSIX_PRIORITY_SCHEDULING is defined - * 2. if _POSIX_SPORADIC_SERVER or _POSIX_THREAD_SPORADIC_SERVER are defined, - * also check SCHED_SPORADIC - * 3. SCHED_OTHER is mandatory (but may be equivalent to SCHED_FIFO or SCHED_RR, - * and is implementation defined) - */ - - int pmin; - int pmax; - pthread_t th; - pthread_attr_t attr; - struct sched_param param; - static const int policies[] = { - SCHED_FIFO, - SCHED_RR, - SCHED_OTHER, - SCHED_INVALID, - }; - static const char *const policy_names[] = { - "SCHED_FIFO", - "SCHED_RR", - "SCHED_OTHER", - "SCHED_INVALID", - }; - static const bool policy_enabled[] = { - IS_ENABLED(CONFIG_COOP_ENABLED), - IS_ENABLED(CONFIG_PREEMPT_ENABLED), - IS_ENABLED(CONFIG_PREEMPT_ENABLED), - false, - }; - static int nprio[] = { - CONFIG_NUM_COOP_PRIORITIES, - CONFIG_NUM_PREEMPT_PRIORITIES, - CONFIG_NUM_PREEMPT_PRIORITIES, - 42, - }; - const char *const prios[] = {"pmin", "pmax"}; - - BUILD_ASSERT(!(SCHED_INVALID == SCHED_FIFO || SCHED_INVALID == SCHED_RR || - SCHED_INVALID == SCHED_OTHER), - "SCHED_INVALID is itself invalid"); - - for (int policy = 0; policy < ARRAY_SIZE(policies); ++policy) { - if (!policy_enabled[policy]) { - /* test degenerate cases */ - errno = 0; - zassert_equal(-1, sched_get_priority_min(policies[policy]), - "expected sched_get_priority_min(%s) to fail", - policy_names[policy]); - zassert_equal(EINVAL, errno, "sched_get_priority_min(%s) did not set errno", - policy_names[policy]); - - errno = 0; - zassert_equal(-1, sched_get_priority_max(policies[policy]), - "expected sched_get_priority_max(%s) to fail", - policy_names[policy]); - zassert_equal(EINVAL, errno, "sched_get_priority_max(%s) did not set errno", - policy_names[policy]); - continue; - } - - /* get pmin and pmax for policies[policy] */ - for (int i = 0; i < ARRAY_SIZE(prios); ++i) { - errno = 0; - if (i == 0) { - pmin = sched_get_priority_min(policies[policy]); - param.sched_priority = pmin; - } else { - pmax = sched_get_priority_max(policies[policy]); - param.sched_priority = pmax; - } - - zassert_not_equal(-1, param.sched_priority, - "sched_get_priority_%s(%s) failed: %d", - i == 0 ? "min" : "max", policy_names[policy], errno); - zassert_ok(errno, "sched_get_priority_%s(%s) set errno to %s", - i == 0 ? "min" : "max", policy_names[policy], errno); - } - - /* - * IEEE 1003.1-2008 Section 2.8.4 - * conforming implementations should provide a range of at least 32 priorities - * - * Note: we relax this requirement - */ - zassert_true(pmax > pmin, "pmax (%d) <= pmin (%d)", pmax, pmin, - "%s min/max inconsistency: pmin: %d pmax: %d", policy_names[policy], - pmin, pmax); - - /* - * Getting into the weeds a bit (i.e. whitebox testing), Zephyr - * cooperative threads use [-CONFIG_NUM_COOP_PRIORITIES,-1] and - * preemptive threads use [0, CONFIG_NUM_PREEMPT_PRIORITIES - 1], - * where the more negative thread has the higher priority. Since we - * cannot map those directly (a return value of -1 indicates error), - * we simply map those to the positive space. - */ - zassert_equal(pmin, 0, "unexpected pmin for %s", policy_names[policy]); - zassert_equal(pmax, nprio[policy] - 1, "unexpected pmax for %s", - policy_names[policy]); /* test happy paths */ - - for (int i = 0; i < ARRAY_SIZE(prios); ++i) { - /* create threads with min and max priority levels */ - zassert_ok(pthread_attr_init(&attr), - "pthread_attr_init() failed for %s (%d) of %s", prios[i], - param.sched_priority, policy_names[policy]); - - zassert_ok(pthread_attr_setschedpolicy(&attr, policies[policy]), - "pthread_attr_setschedpolicy() failed for %s (%d) of %s", - prios[i], param.sched_priority, policy_names[policy]); - - zassert_ok(pthread_attr_setschedparam(&attr, ¶m), - "pthread_attr_setschedparam() failed for %s (%d) of %s", - prios[i], param.sched_priority, policy_names[policy]); - - zassert_ok(pthread_attr_setstack(&attr, &stack_e[0][0], STACKS), - "pthread_attr_setstack() failed for %s (%d) of %s", prios[i], - param.sched_priority, policy_names[policy]); - - zassert_ok(pthread_create(&th, &attr, create_thread1, NULL), - "pthread_create() failed for %s (%d) of %s", prios[i], - param.sched_priority, policy_names[policy]); - - zassert_ok(pthread_join(th, NULL), - "pthread_join() failed for %s (%d) of %s", prios[i], - param.sched_priority, policy_names[policy]); - - zassert_ok(pthread_attr_destroy(&attr), - "pthread_attr_destroy() failed for %s (%d) of %s", prios[i], - param.sched_priority, policy_names[policy]); - } - } -} - -ZTEST(posix_apis, test_pthread_equal) +ZTEST(pthread, test_pthread_equal) { zassert_true(pthread_equal(pthread_self(), pthread_self())); zassert_false(pthread_equal(pthread_self(), (pthread_t)4242)); } -/* A 32-bit value to use between threads for validation */ -#define BIOS_FOOD 0xB105F00D - -static void *fun(void *arg) -{ - *((uint32_t *)arg) = BIOS_FOOD; - return NULL; -} - -ZTEST(posix_apis, test_pthread_dynamic_stacks) -{ - pthread_t th; - - if (!IS_ENABLED(CONFIG_DYNAMIC_THREAD)) { - ztest_test_skip(); - } - - zassert_ok(pthread_create(&th, NULL, fun, ¶m)); - zassert_ok(pthread_join(th, NULL)); - zassert_equal(BIOS_FOOD, param); -} - -static void *non_null_retval(void *arg) -{ - ARG_UNUSED(arg); - - return (void *)BIOS_FOOD; -} - -ZTEST(posix_apis, test_pthread_return_val) -{ - pthread_t pth; - void *ret = NULL; - - zassert_ok(pthread_create(&pth, NULL, non_null_retval, NULL)); - zassert_ok(pthread_join(pth, &ret)); - zassert_equal(ret, (void *)BIOS_FOOD); -} - -static void *detached(void *arg) -{ - ARG_UNUSED(arg); - - return NULL; -} - -ZTEST(posix_apis, test_pthread_join_detached) -{ - pthread_t pth; - - zassert_ok(pthread_create(&pth, NULL, detached, NULL)); - zassert_ok(pthread_detach(pth)); - /* note, this was required to be EINVAL previously but is now undefined behaviour */ - zassert_not_equal(0, pthread_join(pth, NULL)); - - /* need to allow this thread to be clean-up by the recycler */ - k_msleep(500); -} - -ZTEST(posix_apis, test_pthread_set_get_concurrency) +ZTEST(pthread, test_pthread_set_get_concurrency) { /* EINVAL if the value specified by new_level is negative */ zassert_equal(EINVAL, pthread_setconcurrency(-42)); @@ -887,7 +421,7 @@ static void *test_pthread_cleanup_entry(void *arg) return NULL; } -ZTEST(posix_apis, test_pthread_cleanup) +ZTEST(pthread, test_pthread_cleanup) { pthread_t th; @@ -895,60 +429,4 @@ ZTEST(posix_apis, test_pthread_cleanup) zassert_ok(pthread_join(th, NULL)); } -ZTEST(posix_apis, test_pthread_attr_getguardsize) -{ - size_t size_after; - pthread_attr_t attr; - const size_t size_before = OKAY_STACK_SIZE; - - attr = (pthread_attr_t){0}; - zassert_equal(pthread_attr_getguardsize(&attr, &size_after), EINVAL); - zassert_ok(pthread_attr_init(&attr)); - zassert_equal(pthread_attr_getguardsize(NULL, NULL), EINVAL); - zassert_equal(pthread_attr_getguardsize(NULL, &size_after), EINVAL); - zassert_equal(pthread_attr_getguardsize(&attr, NULL), EINVAL); - size_after = size_before; - zassert_ok(pthread_attr_getguardsize(&attr, &size_after)); - zassert_not_equal(size_before, size_after); - zassert_equal(size_after, CONFIG_POSIX_PTHREAD_ATTR_GUARDSIZE_DEFAULT); - zassert_ok(pthread_attr_destroy(&attr)); -} - -ZTEST(posix_apis, test_pthread_attr_setguardsize) -{ - size_t size_after; - size_t size_before; - pthread_attr_t attr; - size_t sizes[] = {0, BIT_MASK(CONFIG_POSIX_PTHREAD_ATTR_GUARDSIZE_BITS / 2), - BIT_MASK(CONFIG_POSIX_PTHREAD_ATTR_GUARDSIZE_BITS)}; - - attr = (pthread_attr_t){0}; - zassert_equal(pthread_attr_setguardsize(&attr, 0), EINVAL); - zassert_ok(pthread_attr_init(&attr)); - zassert_ok(pthread_attr_getguardsize(&attr, &size_before)); - zassert_equal(size_before, CONFIG_POSIX_PTHREAD_ATTR_GUARDSIZE_DEFAULT); - zassert_equal(pthread_attr_setguardsize(NULL, SIZE_MAX), EINVAL); - zassert_equal(pthread_attr_setguardsize(NULL, 0), EINVAL); - zassert_equal(pthread_attr_setguardsize(&attr, SIZE_MAX), EINVAL); - for (size_t i = 0; i < ARRAY_SIZE(sizes); ++i) { - size_after = ~sizes[i]; - size_before = sizes[i]; - zassert_ok(pthread_attr_setguardsize(&attr, size_before)); - zassert_ok(pthread_attr_getguardsize(&attr, &size_after)); - zassert_equal(size_before, size_after); - } - zassert_ok(pthread_attr_destroy(&attr)); -} - -ZTEST(posix_apis, test_pthread_attr_large_stacksize) -{ - size_t actual_size; - const size_t expect_size = BIT(CONFIG_POSIX_PTHREAD_ATTR_STACKSIZE_BITS); - pthread_attr_t attr; - - zassert_ok(pthread_attr_init(&attr)); - zassert_ok(pthread_attr_setstacksize(&attr, expect_size)); - zassert_ok(pthread_attr_getstacksize(&attr, &actual_size)); - zassert_equal(actual_size, expect_size); - zassert_ok(pthread_attr_destroy(&attr)); -} +ZTEST_SUITE(pthread, NULL, NULL, NULL, NULL, NULL); diff --git a/tests/posix/common/src/pthread_attr.c b/tests/posix/common/src/pthread_attr.c new file mode 100644 index 00000000000..f2a9b2da22f --- /dev/null +++ b/tests/posix/common/src/pthread_attr.c @@ -0,0 +1,636 @@ +/* + * Copyright (c) 2024, Meta + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include + +#include +#include + +#define BIOS_FOOD 0xB105F00D +#define SCHED_INVALID 4242 +#define INVALID_DETACHSTATE 7373 + +static bool attr_valid; +static pthread_attr_t attr; +static const pthread_attr_t uninit_attr; +static bool detached_thread_has_finished; + +/* TODO: this should be optional */ +#define STATIC_THREAD_STACK_SIZE (MAX(1024, PTHREAD_STACK_MIN + CONFIG_TEST_EXTRA_STACK_SIZE)) +static K_THREAD_STACK_DEFINE(static_thread_stack, STATIC_THREAD_STACK_SIZE); + +static void *thread_entry(void *arg) +{ + bool joinable = (bool)POINTER_TO_UINT(arg); + + if (!joinable) { + detached_thread_has_finished = true; + } + + return NULL; +} + +static void create_thread_common(const pthread_attr_t *attrp, bool expect_success, bool joinable) +{ + pthread_t th; + + if (!joinable) { + detached_thread_has_finished = false; + } + + if (expect_success) { + zassert_ok(pthread_create(&th, attrp, thread_entry, UINT_TO_POINTER(joinable))); + } else { + zassert_not_ok(pthread_create(&th, attrp, thread_entry, UINT_TO_POINTER(joinable))); + return; + } + + if (joinable) { + zassert_ok(pthread_join(th, NULL), "failed to join joinable thread"); + return; + } + + /* should not be able to join detached thread */ + zassert_not_ok(pthread_join(th, NULL)); + + for (size_t i = 0; i < 10; ++i) { + k_msleep(2 * CONFIG_PTHREAD_RECYCLER_DELAY_MS); + if (detached_thread_has_finished) { + break; + } + } + + zassert_true(detached_thread_has_finished, "detached thread did not seem to finish"); +} + +static inline void can_create_thread(const pthread_attr_t *attrp) +{ + create_thread_common(attrp, true, true); +} + +static inline void cannot_create_thread(const pthread_attr_t *attrp) +{ + create_thread_common(attrp, false, true); +} + +ZTEST(pthread_attr, test_null_attr) +{ + /* + * This test can only succeed when it is possible to call pthread_create() with a NULL + * pthread_attr_t* (I.e. when we have the ability to allocate thread stacks dynamically). + */ + create_thread_common(NULL, IS_ENABLED(CONFIG_DYNAMIC_THREAD) ? true : false, true); +} + +ZTEST(pthread_attr, test_pthread_attr_static_corner_cases) +{ + pthread_attr_t attr1; + + Z_TEST_SKIP_IFDEF(CONFIG_DYNAMIC_THREAD); + + /* + * These tests are specifically for when dynamic thread stacks are disabled, so passing + * a NULL pthread_attr_t* should fail. + */ + cannot_create_thread(NULL); + + /* + * Additionally, without calling pthread_attr_setstack(), thread creation should fail. + */ + zassert_ok(pthread_attr_init(&attr1)); + cannot_create_thread(&attr1); +} + +ZTEST(pthread_attr, test_pthread_attr_init_destroy) +{ + /* attr has already been initialized in before() */ + + if (false) { + /* undefined behaviour */ + zassert_ok(pthread_attr_init(&attr)); + } + + /* cannot destroy an uninitialized attr */ + zassert_equal(pthread_attr_destroy((pthread_attr_t *)&uninit_attr), EINVAL); + + can_create_thread(&attr); + + /* can destroy an initialized attr */ + zassert_ok(pthread_attr_destroy(&attr), "failed to destroy an initialized attr"); + attr_valid = false; + + cannot_create_thread(&attr); + + if (false) { + /* undefined behaviour */ + zassert_ok(pthread_attr_destroy(&attr)); + } + + /* can re-initialize a destroyed attr */ + zassert_ok(pthread_attr_init(&attr)); + /* TODO: pthread_attr_init() should be sufficient to initialize a thread by itself */ + zassert_ok(pthread_attr_setstack(&attr, &static_thread_stack, STATIC_THREAD_STACK_SIZE)); + attr_valid = true; + + can_create_thread(&attr); + + /* note: attr is still valid and is destroyed in after() */ +} + +ZTEST(pthread_attr, test_pthread_attr_getguardsize) +{ + size_t guardsize; + + /* degenerate cases */ + { + if (false) { + /* undefined behaviour */ + zassert_equal(pthread_attr_getguardsize(NULL, NULL), EINVAL); + zassert_equal(pthread_attr_getguardsize(NULL, &guardsize), EINVAL); + zassert_equal(pthread_attr_getguardsize(&uninit_attr, &guardsize), EINVAL); + } + zassert_equal(pthread_attr_getguardsize(&attr, NULL), EINVAL); + } + + guardsize = BIOS_FOOD; + zassert_ok(pthread_attr_getguardsize(&attr, &guardsize)); + zassert_not_equal(guardsize, BIOS_FOOD); +} + +ZTEST(pthread_attr, test_pthread_attr_setguardsize) +{ + size_t guardsize = CONFIG_POSIX_PTHREAD_ATTR_GUARDSIZE_DEFAULT; + size_t sizes[] = {0, BIT_MASK(CONFIG_POSIX_PTHREAD_ATTR_GUARDSIZE_BITS / 2), + BIT_MASK(CONFIG_POSIX_PTHREAD_ATTR_GUARDSIZE_BITS)}; + + /* valid value */ + zassert_ok(pthread_attr_getguardsize(&attr, &guardsize)); + + /* degenerate cases */ + { + if (false) { + /* undefined behaviour */ + zassert_equal(pthread_attr_setguardsize(NULL, SIZE_MAX), EINVAL); + zassert_equal(pthread_attr_setguardsize(NULL, guardsize), EINVAL); + zassert_equal(pthread_attr_setguardsize((pthread_attr_t *)&uninit_attr, + guardsize), + EINVAL); + } + zassert_equal(pthread_attr_setguardsize(&attr, SIZE_MAX), EINVAL); + } + + ARRAY_FOR_EACH(sizes, i) { + zassert_ok(pthread_attr_setguardsize(&attr, sizes[i])); + guardsize = ~sizes[i]; + zassert_ok(pthread_attr_getguardsize(&attr, &guardsize)); + zassert_equal(guardsize, sizes[i]); + } +} + +ZTEST(pthread_attr, test_pthread_attr_getschedparam) +{ + struct sched_param param = { + .sched_priority = BIOS_FOOD, + }; + + /* degenerate cases */ + { + if (false) { + /* undefined behaviour */ + zassert_equal(pthread_attr_getschedparam(NULL, NULL), EINVAL); + zassert_equal(pthread_attr_getschedparam(NULL, ¶m), EINVAL); + zassert_equal(pthread_attr_getschedparam(&uninit_attr, ¶m), EINVAL); + } + zassert_equal(pthread_attr_getschedparam(&attr, NULL), EINVAL); + } + + /* only check to see that the function succeeds and sets param */ + zassert_ok(pthread_attr_getschedparam(&attr, ¶m)); + zassert_not_equal(BIOS_FOOD, param.sched_priority); +} + +ZTEST(pthread_attr, test_pthread_attr_setschedparam) +{ + struct sched_param param = {0}; + + /* degenerate cases */ + { + if (false) { + /* undefined behaviour */ + zassert_equal(pthread_attr_setschedparam(NULL, NULL), EINVAL); + zassert_equal(pthread_attr_setschedparam(NULL, ¶m), EINVAL); + zassert_equal( + pthread_attr_setschedparam((pthread_attr_t *)&uninit_attr, ¶m), + EINVAL); + } + zassert_equal(pthread_attr_setschedparam(&attr, NULL), EINVAL); + } + + zassert_ok(pthread_attr_setschedparam(&attr, ¶m)); + + can_create_thread(&attr); +} + +ZTEST(pthread_attr, test_pthread_attr_getschedpolicy) +{ + int policy = BIOS_FOOD; + + /* degenerate cases */ + { + if (false) { + /* undefined behaviour */ + zassert_equal(pthread_attr_getschedpolicy(NULL, NULL), EINVAL); + zassert_equal(pthread_attr_getschedpolicy(NULL, &policy), EINVAL); + zassert_equal(pthread_attr_getschedpolicy(&uninit_attr, &policy), EINVAL); + } + zassert_equal(pthread_attr_getschedpolicy(&attr, NULL), EINVAL); + } + + /* only check to see that the function succeeds and sets policy */ + zassert_ok(pthread_attr_getschedpolicy(&attr, &policy)); + zassert_not_equal(BIOS_FOOD, policy); +} + +ZTEST(pthread_attr, test_pthread_attr_setschedpolicy) +{ + int policy = SCHED_OTHER; + + /* degenerate cases */ + { + if (false) { + /* undefined behaviour */ + zassert_equal(pthread_attr_setschedpolicy(NULL, SCHED_INVALID), EINVAL); + zassert_equal(pthread_attr_setschedpolicy(NULL, policy), EINVAL); + zassert_equal( + pthread_attr_setschedpolicy((pthread_attr_t *)&uninit_attr, policy), + EINVAL); + } + zassert_equal(pthread_attr_setschedpolicy(&attr, SCHED_INVALID), EINVAL); + } + + zassert_ok(pthread_attr_setschedpolicy(&attr, SCHED_OTHER)); + /* read back the same policy we just wrote */ + policy = SCHED_INVALID; + zassert_ok(pthread_attr_getschedpolicy(&attr, &policy)); + zassert_equal(policy, SCHED_OTHER); + + can_create_thread(&attr); +} + +ZTEST(pthread_attr, test_pthread_attr_getstack) +{ + void *stackaddr = (void *)BIOS_FOOD; + size_t stacksize = BIOS_FOOD; + + /* degenerate cases */ + { + if (false) { + /* undefined behaviour */ + zassert_equal(pthread_attr_getstack(NULL, NULL, NULL), EINVAL); + zassert_equal(pthread_attr_getstack(NULL, NULL, &stacksize), EINVAL); + zassert_equal(pthread_attr_getstack(NULL, &stackaddr, NULL), EINVAL); + zassert_equal(pthread_attr_getstack(NULL, &stackaddr, &stacksize), EINVAL); + zassert_equal(pthread_attr_getstack(&uninit_attr, &stackaddr, &stacksize), + EINVAL); + } + zassert_equal(pthread_attr_getstack(&attr, NULL, NULL), EINVAL); + zassert_equal(pthread_attr_getstack(&attr, NULL, &stacksize), EINVAL); + zassert_equal(pthread_attr_getstack(&attr, &stackaddr, NULL), EINVAL); + } + + zassert_ok(pthread_attr_getstack(&attr, &stackaddr, &stacksize)); + zassert_not_equal(stackaddr, (void *)BIOS_FOOD); + zassert_not_equal(stacksize, BIOS_FOOD); +} + +ZTEST(pthread_attr, test_pthread_attr_setstack) +{ + void *stackaddr; + size_t stacksize; + void *new_stackaddr; + size_t new_stacksize; + + /* valid values */ + zassert_ok(pthread_attr_getstack(&attr, &stackaddr, &stacksize)); + + /* degenerate cases */ + { + if (false) { + /* undefined behaviour */ + zassert_equal(pthread_attr_setstack(NULL, NULL, 0), EACCES); + zassert_equal(pthread_attr_setstack(NULL, NULL, stacksize), EINVAL); + zassert_equal(pthread_attr_setstack(NULL, stackaddr, 0), EINVAL); + zassert_equal(pthread_attr_setstack(NULL, stackaddr, stacksize), EINVAL); + zassert_equal(pthread_attr_setstack((pthread_attr_t *)&uninit_attr, + stackaddr, stacksize), + EINVAL); + } + zassert_equal(pthread_attr_setstack(&attr, NULL, 0), EACCES); + zassert_equal(pthread_attr_setstack(&attr, NULL, stacksize), EACCES); + zassert_equal(pthread_attr_setstack(&attr, stackaddr, 0), EINVAL); + } + + /* ensure we can create and join a thread with the default attrs */ + can_create_thread(&attr); + + /* set stack / addr to the current values of stack / addr */ + zassert_ok(pthread_attr_setstack(&attr, stackaddr, stacksize)); + can_create_thread(&attr); + + /* qemu_x86 seems to be unable to set thread stacks to be anything less than 4096 */ + if (!IS_ENABLED(CONFIG_X86)) { + /* + * check we can set a smaller stacksize + * should not require dynamic reallocation + * size may get rounded up to some alignment internally + */ + zassert_ok(pthread_attr_setstack(&attr, stackaddr, stacksize - 1)); + /* ensure we read back the same values as we specified */ + zassert_ok(pthread_attr_getstack(&attr, &new_stackaddr, &new_stacksize)); + zassert_equal(new_stackaddr, stackaddr); + zassert_equal(new_stacksize, stacksize - 1); + can_create_thread(&attr); + } + + if (IS_ENABLED(DYNAMIC_THREAD_ALLOC)) { + /* ensure we can set a dynamic stack */ + k_thread_stack_t *stack; + + stack = k_thread_stack_alloc(2 * stacksize, 0); + zassert_not_null(stack); + + zassert_ok(pthread_attr_setstack(&attr, (void *)stack, 2 * stacksize)); + /* ensure we read back the same values as we specified */ + zassert_ok(pthread_attr_getstack(&attr, &new_stackaddr, &new_stacksize)); + zassert_equal(new_stackaddr, (void *)stack); + zassert_equal(new_stacksize, 2 * stacksize); + can_create_thread(&attr); + } +} + +ZTEST(pthread_attr, test_pthread_attr_getstacksize) +{ + size_t stacksize = BIOS_FOOD; + + /* degenerate cases */ + { + if (false) { + /* undefined behaviour */ + zassert_equal(pthread_attr_getstacksize(NULL, NULL), EINVAL); + zassert_equal(pthread_attr_getstacksize(NULL, &stacksize), EINVAL); + zassert_equal(pthread_attr_getstacksize(&uninit_attr, &stacksize), EINVAL); + } + zassert_equal(pthread_attr_getstacksize(&attr, NULL), EINVAL); + } + + zassert_ok(pthread_attr_getstacksize(&attr, &stacksize)); + zassert_not_equal(stacksize, BIOS_FOOD); +} + +ZTEST(pthread_attr, test_pthread_attr_setstacksize) +{ + size_t stacksize; + size_t new_stacksize; + + /* valid size */ + zassert_ok(pthread_attr_getstacksize(&attr, &stacksize)); + + /* degenerate cases */ + { + if (false) { + /* undefined behaviour */ + zassert_equal(pthread_attr_setstacksize(NULL, 0), EINVAL); + zassert_equal(pthread_attr_setstacksize(NULL, stacksize), EINVAL); + zassert_equal(pthread_attr_setstacksize((pthread_attr_t *)&uninit_attr, + stacksize), + EINVAL); + } + zassert_equal(pthread_attr_setstacksize(&attr, 0), EINVAL); + } + + /* ensure we can spin up a thread with the default stack size */ + can_create_thread(&attr); + + /* set stack / addr to the current values of stack / addr */ + zassert_ok(pthread_attr_setstacksize(&attr, stacksize)); + /* ensure we can read back the values we just set */ + zassert_ok(pthread_attr_getstacksize(&attr, &new_stacksize)); + zassert_equal(new_stacksize, stacksize); + can_create_thread(&attr); + + /* qemu_x86 seems to be unable to set thread stacks to be anything less than 4096 */ + if (!IS_ENABLED(CONFIG_X86)) { + zassert_ok(pthread_attr_setstacksize(&attr, stacksize - 1)); + /* ensure we can read back the values we just set */ + zassert_ok(pthread_attr_getstacksize(&attr, &new_stacksize)); + zassert_equal(new_stacksize, stacksize - 1); + can_create_thread(&attr); + } + + if (IS_ENABLED(CONFIG_DYNAMIC_THREAD_ALLOC)) { + zassert_ok(pthread_attr_setstacksize(&attr, 2 * stacksize)); + /* ensure we read back the same values as we specified */ + zassert_ok(pthread_attr_getstacksize(&attr, &new_stacksize)); + zassert_equal(new_stacksize, 2 * stacksize); + can_create_thread(&attr); + } +} + +ZTEST(pthread_attr, test_pthread_attr_large_stacksize) +{ + size_t actual_size; + const size_t expect_size = BIT(CONFIG_POSIX_PTHREAD_ATTR_STACKSIZE_BITS); + + zassert_ok(pthread_attr_setstacksize(&attr, expect_size)); + zassert_ok(pthread_attr_getstacksize(&attr, &actual_size)); + zassert_equal(actual_size, expect_size); +} + +ZTEST(pthread_attr, test_pthread_attr_getdetachstate) +{ + int detachstate; + + /* degenerate cases */ + { + if (false) { + /* undefined behaviour */ + zassert_equal(pthread_attr_getdetachstate(NULL, NULL), EINVAL); + zassert_equal(pthread_attr_getdetachstate(NULL, &detachstate), EINVAL); + zassert_equal(pthread_attr_getdetachstate(&uninit_attr, &detachstate), + EINVAL); + } + zassert_equal(pthread_attr_getdetachstate(&attr, NULL), EINVAL); + } + + /* default detachstate is joinable */ + zassert_ok(pthread_attr_getdetachstate(&attr, &detachstate)); + zassert_equal(detachstate, PTHREAD_CREATE_JOINABLE); + can_create_thread(&attr); +} + +ZTEST(pthread_attr, test_pthread_attr_setdetachstate) +{ + int detachstate = PTHREAD_CREATE_JOINABLE; + + /* degenerate cases */ + { + if (false) { + /* undefined behaviour */ + zassert_equal(pthread_attr_setdetachstate(NULL, INVALID_DETACHSTATE), + EINVAL); + zassert_equal(pthread_attr_setdetachstate(NULL, detachstate), EINVAL); + zassert_equal(pthread_attr_setdetachstate((pthread_attr_t *)&uninit_attr, + detachstate), + EINVAL); + } + zassert_equal(pthread_attr_setdetachstate(&attr, INVALID_DETACHSTATE), EINVAL); + } + + /* read back detachstate just written */ + zassert_ok(pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED)); + zassert_ok(pthread_attr_getdetachstate(&attr, &detachstate)); + zassert_equal(detachstate, PTHREAD_CREATE_DETACHED); + create_thread_common(&attr, true, false); +} + +ZTEST(pthread_attr, test_pthread_attr_policy_and_priority_limits) +{ + int pmin = -1; + int pmax = -1; + struct sched_param param; + static const int policies[] = { + SCHED_FIFO, + SCHED_RR, + SCHED_OTHER, + SCHED_INVALID, + }; + static const char *const policy_names[] = { + "SCHED_FIFO", + "SCHED_RR", + "SCHED_OTHER", + "SCHED_INVALID", + }; + static const bool policy_enabled[] = { + CONFIG_NUM_COOP_PRIORITIES > 0, + CONFIG_NUM_PREEMPT_PRIORITIES > 0, + CONFIG_NUM_PREEMPT_PRIORITIES > 0, + false, + }; + static int nprio[] = { + CONFIG_NUM_COOP_PRIORITIES, + CONFIG_NUM_PREEMPT_PRIORITIES, + CONFIG_NUM_PREEMPT_PRIORITIES, + 42, + }; + const char *const prios[] = {"pmin", "pmax"}; + + BUILD_ASSERT(!(SCHED_INVALID == SCHED_FIFO || SCHED_INVALID == SCHED_RR || + SCHED_INVALID == SCHED_OTHER), + "SCHED_INVALID is itself invalid"); + + ARRAY_FOR_EACH(policies, policy) { + /* get pmin and pmax for policies[policy] */ + ARRAY_FOR_EACH(prios, i) { + errno = 0; + if (i == 0) { + pmin = sched_get_priority_min(policies[policy]); + param.sched_priority = pmin; + } else { + pmax = sched_get_priority_max(policies[policy]); + param.sched_priority = pmax; + } + + if (policy == 3) { + /* invalid policy */ + zassert_equal(-1, param.sched_priority); + zassert_equal(errno, EINVAL); + continue; + } + + zassert_not_equal(-1, param.sched_priority, + "sched_get_priority_%s(%s) failed: %d", + i == 0 ? "min" : "max", policy_names[policy], errno); + zassert_ok(errno, "sched_get_priority_%s(%s) set errno to %s", + i == 0 ? "min" : "max", policy_names[policy], errno); + } + + if (policy != 3) { + /* this will not work for SCHED_INVALID */ + + /* + * IEEE 1003.1-2008 Section 2.8.4 + * conforming implementations should provide a range of at least 32 + * priorities + * + * Note: we relax this requirement + */ + zassert_true(pmax > pmin, "pmax (%d) <= pmin (%d)", pmax, pmin, + "%s min/max inconsistency: pmin: %d pmax: %d", + policy_names[policy], pmin, pmax); + + /* + * Getting into the weeds a bit (i.e. whitebox testing), Zephyr + * cooperative threads use [-CONFIG_NUM_COOP_PRIORITIES,-1] and + * preemptive threads use [0, CONFIG_NUM_PREEMPT_PRIORITIES - 1], + * where the more negative thread has the higher priority. Since we + * cannot map those directly (a return value of -1 indicates error), + * we simply map those to the positive space. + */ + zassert_equal(pmin, 0, "unexpected pmin for %s", policy_names[policy]); + zassert_equal(pmax, nprio[policy] - 1, "unexpected pmax for %s", + policy_names[policy]); /* test happy paths */ + } + + /* create threads with min and max priority levels for each policy */ + ARRAY_FOR_EACH(prios, i) { + param.sched_priority = (i == 0) ? pmin : pmax; + + if (!policy_enabled[policy]) { + zassert_not_ok( + pthread_attr_setschedpolicy(&attr, policies[policy])); + zassert_not_ok( + pthread_attr_setschedparam(&attr, ¶m), + "pthread_attr_setschedparam() failed for %s (%d) of %s", + prios[i], param.sched_priority, policy_names[policy]); + continue; + } + + /* set policy */ + zassert_ok(pthread_attr_setschedpolicy(&attr, policies[policy]), + "pthread_attr_setschedpolicy() failed for %s (%d) of %s", + prios[i], param.sched_priority, policy_names[policy]); + + /* set priority */ + zassert_ok(pthread_attr_setschedparam(&attr, ¶m), + "pthread_attr_setschedparam() failed for %s (%d) of %s", + prios[i], param.sched_priority, policy_names[policy]); + + can_create_thread(&attr); + } + } +} + +static void before(void *arg) +{ + ARG_UNUSED(arg); + + zassert_ok(pthread_attr_init(&attr)); + /* TODO: pthread_attr_init() should be sufficient to initialize a thread by itself */ + zassert_ok(pthread_attr_setstack(&attr, &static_thread_stack, STATIC_THREAD_STACK_SIZE)); + attr_valid = true; +} + +static void after(void *arg) +{ + ARG_UNUSED(arg); + + if (attr_valid) { + (void)pthread_attr_destroy(&attr); + attr_valid = false; + } +} + +ZTEST_SUITE(pthread_attr, NULL, NULL, before, after, NULL); From 68f8c8ff29d0c72d77acb1db7dc66ad669731965 Mon Sep 17 00:00:00 2001 From: Emil Gydesen Date: Fri, 12 Jan 2024 11:32:30 +0100 Subject: [PATCH 2256/3723] Bluetooth: Audio: Fix off-by-one error in codec.c:ltv_set_val The function did not move data correctly when increasing or decreasing the size of a value that was not the last value in the LTV array. Added a few tests to verify the fix, using the CCID list as the main way of verifying it. Signed-off-by: Emil Gydesen --- subsys/bluetooth/audio/codec.c | 4 +- tests/bluetooth/audio/codec/src/main.c | 111 ++++++++++++++++++++++++- 2 files changed, 112 insertions(+), 3 deletions(-) diff --git a/subsys/bluetooth/audio/codec.c b/subsys/bluetooth/audio/codec.c index 2bf3faf2565..3f5f2b56629 100644 --- a/subsys/bluetooth/audio/codec.c +++ b/subsys/bluetooth/audio/codec.c @@ -164,8 +164,8 @@ static int ltv_set_val(struct net_buf_simple *buf, uint8_t type, const uint8_t * if (value + value_len == buf->data + buf->len) { data_len_to_move = 0U; } else { - old_next_data_start = value + value_len + 1; - new_next_data_start = value + data_len + 1; + old_next_data_start = value + value_len; + new_next_data_start = value + data_len; data_len_to_move = buf->len - (old_next_data_start - buf->data); } diff --git a/tests/bluetooth/audio/codec/src/main.c b/tests/bluetooth/audio/codec/src/main.c index 386ef40e7f7..3b909e4582f 100644 --- a/tests/bluetooth/audio/codec/src/main.c +++ b/tests/bluetooth/audio/codec/src/main.c @@ -57,6 +57,26 @@ ZTEST(audio_codec_test_suite, test_bt_audio_codec_cfg_get_freq) zassert_equal(ret, 0x03, "unexpected return value %d", ret); } +ZTEST(audio_codec_test_suite, test_bt_audio_codec_cfg_set_val_new) +{ + struct bt_bap_lc3_preset preset = BT_BAP_LC3_UNICAST_PRESET_16_2_1( + BT_AUDIO_LOCATION_FRONT_LEFT, BT_AUDIO_CONTEXT_TYPE_UNSPECIFIED); + const uint8_t frame_blocks = 0x02; + int ret; + + /* Frame blocks are not part of the preset, so we can use that to test adding a new type to + * the config + */ + ret = bt_audio_codec_cfg_get_frame_blocks_per_sdu(&preset.codec_cfg, false); + zassert_equal(ret, -ENODATA, "Unexpected return value %d", ret); + + ret = bt_audio_codec_cfg_set_frame_blocks_per_sdu(&preset.codec_cfg, frame_blocks); + zassert_true(ret > 0, "Unexpected return value %d", ret); + + ret = bt_audio_codec_cfg_get_frame_blocks_per_sdu(&preset.codec_cfg, false); + zassert_equal(ret, frame_blocks, "Unexpected return value %d", ret); +} + ZTEST(audio_codec_test_suite, test_bt_audio_codec_cfg_set_freq) { struct bt_bap_lc3_preset preset = BT_BAP_LC3_UNICAST_PRESET_16_2_1( @@ -371,7 +391,7 @@ ZTEST(audio_codec_test_suite, test_bt_audio_codec_cfg_meta_get_ccid_list) zassert_mem_equal(expected_data, ccid_list, ARRAY_SIZE(expected_data)); } -ZTEST(audio_codec_test_suite, test_bt_audio_codec_cfg_meta_set_ccid_list) +ZTEST(audio_codec_test_suite, test_bt_audio_codec_cfg_meta_set_ccid_list_shorter) { const uint8_t expected_data[] = {0x05, 0x10, 0x15}; const uint8_t new_expected_data[] = {0x25, 0x30}; @@ -394,6 +414,95 @@ ZTEST(audio_codec_test_suite, test_bt_audio_codec_cfg_meta_set_ccid_list) zassert_mem_equal(new_expected_data, ccid_list, ARRAY_SIZE(new_expected_data)); } +ZTEST(audio_codec_test_suite, test_bt_audio_codec_cfg_meta_set_ccid_list_longer) +{ + const uint8_t expected_data[] = {0x05, 0x10, 0x15}; + const uint8_t new_expected_data[] = {0x25, 0x30, 0x35, 0x40}; + struct bt_audio_codec_cfg codec_cfg = BT_AUDIO_CODEC_CFG( + BT_HCI_CODING_FORMAT_LC3, 0x0000, 0x0000, {}, + {BT_AUDIO_CODEC_DATA(BT_AUDIO_METADATA_TYPE_CCID_LIST, 0x05, 0x10, 0x15)}); + const uint8_t *ccid_list; + int ret; + + ret = bt_audio_codec_cfg_meta_get_ccid_list(&codec_cfg, &ccid_list); + zassert_equal(ret, ARRAY_SIZE(expected_data), "Unexpected return value %d", ret); + zassert_mem_equal(expected_data, ccid_list, ARRAY_SIZE(expected_data)); + + ret = bt_audio_codec_cfg_meta_set_ccid_list(&codec_cfg, new_expected_data, + ARRAY_SIZE(new_expected_data)); + zassert_true(ret > 0, "Unexpected return value %d", ret); + + ret = bt_audio_codec_cfg_meta_get_ccid_list(&codec_cfg, &ccid_list); + zassert_equal(ret, ARRAY_SIZE(new_expected_data), "Unexpected return value %d", ret); + zassert_mem_equal(new_expected_data, ccid_list, ARRAY_SIZE(new_expected_data)); +} + +/* Providing multiple BT_AUDIO_CODEC_DATA to BT_AUDIO_CODEC_CFG without packing it in a macro + * cause compile issue, so define a macro to denote 2 types of data for the ccid_list_first tests + */ +#define DOUBLE_CFG_DATA \ + { \ + BT_AUDIO_CODEC_DATA(BT_AUDIO_METADATA_TYPE_CCID_LIST, 0x05, 0x10, 0x15), \ + BT_AUDIO_CODEC_DATA(BT_AUDIO_METADATA_TYPE_PARENTAL_RATING, \ + BT_AUDIO_PARENTAL_RATING_AGE_10_OR_ABOVE) \ + } + +ZTEST(audio_codec_test_suite, test_bt_audio_codec_cfg_meta_set_ccid_list_first_shorter) +{ + const uint8_t expected_data[] = {0x05, 0x10, 0x15}; + const uint8_t new_expected_data[] = {0x25, 0x30}; + struct bt_audio_codec_cfg codec_cfg = + BT_AUDIO_CODEC_CFG(BT_HCI_CODING_FORMAT_LC3, 0x0000, 0x0000, {}, DOUBLE_CFG_DATA); + const uint8_t *ccid_list; + int ret; + + ret = bt_audio_codec_cfg_meta_get_ccid_list(&codec_cfg, &ccid_list); + zassert_equal(ret, ARRAY_SIZE(expected_data), "Unexpected return value %d", ret); + zassert_mem_equal(expected_data, ccid_list, ARRAY_SIZE(expected_data)); + + ret = bt_audio_codec_cfg_meta_get_parental_rating(&codec_cfg); + zassert_equal(ret, 0x07, "Unexpected return value %d", ret); + + ret = bt_audio_codec_cfg_meta_set_ccid_list(&codec_cfg, new_expected_data, + ARRAY_SIZE(new_expected_data)); + zassert_true(ret > 0, "Unexpected return value %d", ret); + + ret = bt_audio_codec_cfg_meta_get_ccid_list(&codec_cfg, &ccid_list); + zassert_equal(ret, ARRAY_SIZE(new_expected_data), "Unexpected return value %d", ret); + zassert_mem_equal(new_expected_data, ccid_list, ARRAY_SIZE(new_expected_data)); + + ret = bt_audio_codec_cfg_meta_get_parental_rating(&codec_cfg); + zassert_equal(ret, 0x07, "Unexpected return value %d", ret); +} + +ZTEST(audio_codec_test_suite, test_bt_audio_codec_cfg_meta_set_ccid_list_first_longer) +{ + const uint8_t expected_data[] = {0x05, 0x10, 0x15}; + const uint8_t new_expected_data[] = {0x25, 0x30, 0x35, 0x40}; + struct bt_audio_codec_cfg codec_cfg = + BT_AUDIO_CODEC_CFG(BT_HCI_CODING_FORMAT_LC3, 0x0000, 0x0000, {}, DOUBLE_CFG_DATA); + const uint8_t *ccid_list; + int ret; + + ret = bt_audio_codec_cfg_meta_get_ccid_list(&codec_cfg, &ccid_list); + zassert_equal(ret, ARRAY_SIZE(expected_data), "Unexpected return value %d", ret); + zassert_mem_equal(expected_data, ccid_list, ARRAY_SIZE(expected_data)); + + ret = bt_audio_codec_cfg_meta_get_parental_rating(&codec_cfg); + zassert_equal(ret, 0x07, "Unexpected return value %d", ret); + + ret = bt_audio_codec_cfg_meta_set_ccid_list(&codec_cfg, new_expected_data, + ARRAY_SIZE(new_expected_data)); + zassert_true(ret > 0, "Unexpected return value %d", ret); + + ret = bt_audio_codec_cfg_meta_get_ccid_list(&codec_cfg, &ccid_list); + zassert_equal(ret, ARRAY_SIZE(new_expected_data), "Unexpected return value %d", ret); + zassert_mem_equal(new_expected_data, ccid_list, ARRAY_SIZE(new_expected_data)); + + ret = bt_audio_codec_cfg_meta_get_parental_rating(&codec_cfg); + zassert_equal(ret, 0x07, "Unexpected return value %d", ret); +} + ZTEST(audio_codec_test_suite, test_bt_audio_codec_cfg_meta_get_parental_rating) { const struct bt_audio_codec_cfg codec_cfg = From cb2e3a86b4f8526995f149bdec888974a453a318 Mon Sep 17 00:00:00 2001 From: Benedikt Schmidt Date: Tue, 9 Jan 2024 13:49:31 +0100 Subject: [PATCH 2257/3723] drivers: gpio: ignore communication faults of TLE9104 during startup Ignore communication faults of the TLE9104 which are reported before the communication watchdog is configured. Fixes #67370 Signed-off-by: Benedikt Schmidt --- drivers/gpio/gpio_tle9104.c | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) diff --git a/drivers/gpio/gpio_tle9104.c b/drivers/gpio/gpio_tle9104.c index 1d4c1545e86..3494cdb2533 100644 --- a/drivers/gpio/gpio_tle9104.c +++ b/drivers/gpio/gpio_tle9104.c @@ -75,6 +75,8 @@ struct tle9104_data { /* each bit defines if the output channel is configured, see state */ uint8_t configured; struct k_mutex lock; + /* communication watchdog is getting ignored */ + bool cwd_ignore; }; static void tle9104_set_cfg_cwdtime(uint8_t *destination, uint8_t value) @@ -116,6 +118,7 @@ static int tle9104_transceive_frame(const struct device *dev, bool write, enum tle9104_register *read_reg, uint8_t *read_data) { const struct tle9104_config *config = dev->config; + struct tle9104_data *data = dev->data; uint16_t write_frame; uint16_t read_frame; int result; @@ -160,8 +163,10 @@ static int tle9104_transceive_frame(const struct device *dev, bool write, return -EIO; } - if ((TLE9104_SPIFRAME_FAULTCOMMUNICATION_BIT & read_frame) != 0) { - LOG_WRN("communication fault reported by TLE9104"); + if (!data->cwd_ignore) { + if ((TLE9104_SPIFRAME_FAULTCOMMUNICATION_BIT & read_frame) != 0) { + LOG_WRN("%s: communication fault reported by TLE9104", dev->name); + } } *read_reg = FIELD_GET(GENMASK(TLE9104_FRAME_FAULTGLOBAL_POS - 1, TLE9104_FRAME_ADDRESS_POS), @@ -385,6 +390,8 @@ static int tle9104_init(const struct device *dev) LOG_DBG("initialize TLE9104 instance %s", dev->name); + data->cwd_ignore = true; + result = k_mutex_init(&data->lock); if (result != 0) { LOG_ERR("unable to initialize mutex"); @@ -498,6 +505,8 @@ static int tle9104_init(const struct device *dev) return result; } + data->cwd_ignore = false; + return 0; } From 43490289ff35464cfa68de17c65360280fcf16ea Mon Sep 17 00:00:00 2001 From: Greter Raffael Date: Tue, 28 Nov 2023 10:16:41 +0000 Subject: [PATCH 2258/3723] soc: gd32vf103: Remove redundant code from entry.S A lot of the entry.S is again implemented in common/vector.S. I removed everything redundant and changed the jump to the common symbol __start at the end. Signed-off-by: Greter Raffael --- soc/riscv/gd_gd32/gd32vf103/entry.S | 33 ++++------------------------- 1 file changed, 4 insertions(+), 29 deletions(-) diff --git a/soc/riscv/gd_gd32/gd32vf103/entry.S b/soc/riscv/gd_gd32/gd32vf103/entry.S index 41cc6cc686b..cc9f942f63e 100644 --- a/soc/riscv/gd_gd32/gd32vf103/entry.S +++ b/soc/riscv/gd_gd32/gd32vf103/entry.S @@ -16,46 +16,21 @@ SECTION_FUNC(vectors, __nuclei_start) /* Jump to logical address first to ensure correct operation of RAM region */ la a0, __nuclei_start li a1, 1 - slli a1, a1, 29 + slli a1, a1, 29 # 0x2000 0000 bleu a1, a0, _start0800 - srli a1, a1, 2 + srli a1, a1, 2 # 0x0800 0000 bleu a1, a0, _start0800 la a0, _start0800 add a0, a0, a1 jr a0 _start0800: - -#if defined(CONFIG_RISCV_GP) - /* Initialize global pointer */ - .option push - .option norelax - la gp, __global_pointer$ - .option pop -#endif - - .option norvc; - /* Set the the NMI base to share with mtvec by setting CSR_MMISC_CTL */ li t0, 0x200 csrs CSR_MMISC_CTL, t0 - /* Initial the CSR MTVEC for the Trap ane NMI base addr */ - la t0, trap_entry - csrw mtvec, t0 - - /* Direct Mode: All exceptions set pc to BASE. */ - csrc mtvec, 0x3 - /* Disable performance counter */ csrsi mcountinhibit, 0x5 - /* Jump to __reset */ - tail __reset - -1: - j 1b - -.align 6 -trap_entry: - tail _isr_wrapper + /* Jump to common start */ + tail __start From 8460ed093e14113bf3a8a7900c82555bc05b7b6d Mon Sep 17 00:00:00 2001 From: Greter Raffael Date: Tue, 28 Nov 2023 10:18:42 +0000 Subject: [PATCH 2259/3723] soc: gd32vf103: Link soc-specific before common code For a proper initialisation, the soc-specific `__nuclei_start` has to be executed before the common `__start`. To ensure that `__nuclei_start` is linked first, I added the linker section init. Signed-off-by: Greter Raffael --- soc/riscv/gd_gd32/gd32vf103/CMakeLists.txt | 2 ++ soc/riscv/gd_gd32/gd32vf103/entry.S | 2 +- soc/riscv/gd_gd32/gd32vf103/init.ld | 7 +++++++ 3 files changed, 10 insertions(+), 1 deletion(-) create mode 100644 soc/riscv/gd_gd32/gd32vf103/init.ld diff --git a/soc/riscv/gd_gd32/gd32vf103/CMakeLists.txt b/soc/riscv/gd_gd32/gd32vf103/CMakeLists.txt index be61e4a64df..9fa5868a2a6 100644 --- a/soc/riscv/gd_gd32/gd32vf103/CMakeLists.txt +++ b/soc/riscv/gd_gd32/gd32vf103/CMakeLists.txt @@ -4,4 +4,6 @@ zephyr_sources(entry.S) zephyr_sources(soc.c) +zephyr_linker_sources(ROM_START SORT_KEY 0x0 init.ld) + set(SOC_LINKER_SCRIPT ${ZEPHYR_BASE}/include/zephyr/arch/riscv/common/linker.ld CACHE INTERNAL "") diff --git a/soc/riscv/gd_gd32/gd32vf103/entry.S b/soc/riscv/gd_gd32/gd32vf103/entry.S index cc9f942f63e..10e29a4ba3e 100644 --- a/soc/riscv/gd_gd32/gd32vf103/entry.S +++ b/soc/riscv/gd_gd32/gd32vf103/entry.S @@ -10,7 +10,7 @@ #include GTEXT(__nuclei_start) -SECTION_FUNC(vectors, __nuclei_start) +SECTION_FUNC(init, __nuclei_start) /* Disable Global Interrupt */ csrc mstatus, MSTATUS_MIE /* Jump to logical address first to ensure correct operation of RAM region */ diff --git a/soc/riscv/gd_gd32/gd32vf103/init.ld b/soc/riscv/gd_gd32/gd32vf103/init.ld new file mode 100644 index 00000000000..0feb828931b --- /dev/null +++ b/soc/riscv/gd_gd32/gd32vf103/init.ld @@ -0,0 +1,7 @@ +/* + * Copyright (c) 2023 Andes Technology Corporation + * + * SPDX-License-Identifier: Apache-2.0 + */ + +KEEP(*(.init.*)) From 87916d7af39616705192f8a5d2f01177f316f35f Mon Sep 17 00:00:00 2001 From: Greter Raffael Date: Tue, 28 Nov 2023 12:33:55 +0000 Subject: [PATCH 2260/3723] soc: gd32vf103: Correct vector table alignment For a CLIC the vector table has to be aligned by 512 bytes, if there are between 65 and 128 interrupts, which is the case for the gd32vf103. `isr_wrapper` has to be aligned to 64 bytes, s.t. the lower 6 bits of mtvec are 0. Signed-off-by: Greter Raffael --- soc/riscv/gd_gd32/gd32vf103/Kconfig.defconfig.gd32vf103 | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/soc/riscv/gd_gd32/gd32vf103/Kconfig.defconfig.gd32vf103 b/soc/riscv/gd_gd32/gd32vf103/Kconfig.defconfig.gd32vf103 index 0da92e80e36..63f0799b38e 100644 --- a/soc/riscv/gd_gd32/gd32vf103/Kconfig.defconfig.gd32vf103 +++ b/soc/riscv/gd_gd32/gd32vf103/Kconfig.defconfig.gd32vf103 @@ -42,4 +42,10 @@ config RESET config CLOCK_CONTROL default y +config ARCH_IRQ_VECTOR_TABLE_ALIGN + default 512 if NUCLEI_ECLIC + +config RISCV_TRAP_HANDLER_ALIGNMENT + default 64 if NUCLEI_ECLIC && !RISCV_VECTORED_MODE + endif # GD32VF103 From eff5d028728ccc8291f9d83a724517288e940435 Mon Sep 17 00:00:00 2001 From: Jukka Rissanen Date: Thu, 16 Nov 2023 17:06:12 +0200 Subject: [PATCH 2261/3723] net: sockets: Create a socket service API The socket service provides a similar functionality as what initd provides in Linux. It listens user registered sockets for any activity and then launches a k_work for it. This way each application does not need to create a thread to listen a blocking socket. Signed-off-by: Jukka Rissanen --- .../linker/common-rom/common-rom-net.ld | 4 + include/zephyr/net/socket_service.h | 246 +++++++++++++++ subsys/net/lib/sockets/CMakeLists.txt | 1 + subsys/net/lib/sockets/Kconfig | 25 ++ subsys/net/lib/sockets/sockets_service.c | 291 ++++++++++++++++++ 5 files changed, 567 insertions(+) create mode 100644 include/zephyr/net/socket_service.h create mode 100644 subsys/net/lib/sockets/sockets_service.c diff --git a/include/zephyr/linker/common-rom/common-rom-net.ld b/include/zephyr/linker/common-rom/common-rom-net.ld index 909d11c6d57..8b386ee8ce8 100644 --- a/include/zephyr/linker/common-rom/common-rom-net.ld +++ b/include/zephyr/linker/common-rom/common-rom-net.ld @@ -25,3 +25,7 @@ #if defined(CONFIG_NET_MGMT_EVENT) ITERABLE_SECTION_ROM(net_mgmt_event_static_handler, 4) #endif + +#if defined(CONFIG_NET_SOCKETS_SERVICE) + ITERABLE_SECTION_RAM(net_socket_service_desc, 4) +#endif diff --git a/include/zephyr/net/socket_service.h b/include/zephyr/net/socket_service.h new file mode 100644 index 00000000000..16da94d238b --- /dev/null +++ b/include/zephyr/net/socket_service.h @@ -0,0 +1,246 @@ +/** + * @file + * @brief BSD Socket service API + * + * API can be used to install a k_work that is called + * if there is data received to a socket. + */ + +/* + * Copyright (c) 2023 Nordic Semiconductor ASA + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#ifndef ZEPHYR_INCLUDE_NET_SOCKET_SERVICE_H_ +#define ZEPHYR_INCLUDE_NET_SOCKET_SERVICE_H_ + +/** + * @brief BSD socket service API + * @defgroup bsd_socket_service BSD socket service API + * @ingroup networking + * @{ + */ + +#include +#include +#include + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * This struct contains information which socket triggered + * calls to the callback function. + */ +struct net_socket_service_event { + /** k_work that is done when there is desired activity in file descriptor. */ + struct k_work work; + /** Callback to be called for desired socket activity */ + k_work_handler_t callback; + /** Socket information that triggered this event. */ + struct zsock_pollfd event; + /** User data */ + void *user_data; + /** Service back pointer */ + struct net_socket_service_desc *svc; +}; + +/** + * Main structure holding socket service configuration information. + * The k_work item is created so that when there is data coming + * to those fds, the k_work callback is then called. + * The workqueue can be set NULL in which case system workqueue is used. + * The service descriptor should be created at built time, and then used + * as a parameter to register the sockets to be monitored. + * User should create needed sockets and then setup the poll struct and + * then register the sockets to be monitored at runtime. + */ +struct net_socket_service_desc { +#if CONFIG_NET_SOCKETS_LOG_LEVEL >= LOG_LEVEL_DBG + /** + * Owner name. This can be used in debugging to see who has + * registered this service. + */ + const char *owner; +#endif + /** Workqueue where the work is submitted. */ + struct k_work_q *work_q; + /** Pointer to the list of services that we are listening */ + struct net_socket_service_event *pev; + /** Length of the pollable socket array for this service. */ + int pev_len; + /** Where are my pollfd entries in the global list */ + int *idx; +}; + +#define __z_net_socket_svc_get_name(_svc_id) __z_net_socket_service_##_svc_id +#define __z_net_socket_svc_get_idx(_svc_id) __z_net_socket_service_idx##_svc_id +#define __z_net_socket_svc_get_owner __FILE__ ":" STRINGIFY(__LINE__) + +extern void net_socket_service_callback(struct k_work *work); + +#if CONFIG_NET_SOCKETS_LOG_LEVEL >= LOG_LEVEL_DBG +#define NET_SOCKET_SERVICE_OWNER .owner = __z_net_socket_svc_get_owner, +#else +#define NET_SOCKET_SERVICE_OWNER +#endif + +#define NET_SOCKET_SERVICE_CALLBACK_MODE(_flag) \ + IF_ENABLED(_flag, \ + (.work = Z_WORK_INITIALIZER(net_socket_service_callback),)) + +#define __z_net_socket_service_define(_name, _work_q, _cb, _count, _async, ...) \ + static int __z_net_socket_svc_get_idx(_name); \ + static struct net_socket_service_event \ + __z_net_socket_svc_get_name(_name)[_count] = { \ + [0 ... ((_count) - 1)] = { \ + .event.fd = -1, /* Invalid socket */ \ + NET_SOCKET_SERVICE_CALLBACK_MODE(_async) \ + .callback = _cb, \ + } \ + }; \ + COND_CODE_0(NUM_VA_ARGS_LESS_1(__VA_ARGS__), (), __VA_ARGS__) \ + const STRUCT_SECTION_ITERABLE(net_socket_service_desc, _name) = { \ + NET_SOCKET_SERVICE_OWNER \ + .work_q = (_work_q), \ + .pev = __z_net_socket_svc_get_name(_name), \ + .pev_len = (_count), \ + .idx = &__z_net_socket_svc_get_idx(_name), \ + } + +/** + * @brief Statically define a network socket service. + * The user callback is called asynchronously for this service meaning that + * the service API will not wait until the user callback returns before continuing + * with next socket service. + * + * The socket service can be accessed outside the module where it is defined using: + * + * @code extern struct net_socket_service_desc ; @endcode + * + * @note This macro cannot be used together with a static keyword. + * If such a use-case is desired, use NET_SOCKET_SERVICE_ASYNC_DEFINE_STATIC + * instead. + * + * @param name Name of the service. + * @param work_q Pointer to workqueue where the work is done. Can be null in which case + * system workqueue is used. + * @param cb Callback function that is called for socket activity. + * @param count How many pollable sockets is needed for this service. + */ +#define NET_SOCKET_SERVICE_ASYNC_DEFINE(name, work_q, cb, count) \ + __z_net_socket_service_define(name, work_q, cb, count, 1) + +/** + * @brief Statically define a network socket service in a private (static) scope. + * The user callback is called asynchronously for this service meaning that + * the service API will not wait until the user callback returns before continuing + * with next socket service. + * + * @param name Name of the service. + * @param work_q Pointer to workqueue where the work is done. Can be null in which case + * system workqueue is used. + * @param cb Callback function that is called for socket activity. + * @param count How many pollable sockets is needed for this service. + */ +#define NET_SOCKET_SERVICE_ASYNC_DEFINE_STATIC(name, work_q, cb, count) \ + __z_net_socket_service_define(name, work_q, cb, count, 1, static) + +/** + * @brief Statically define a network socket service. + * The user callback is called synchronously for this service meaning that + * the service API will wait until the user callback returns before continuing + * with next socket service. + * + * The socket service can be accessed outside the module where it is defined using: + * + * @code extern struct net_socket_service_desc ; @endcode + * + * @note This macro cannot be used together with a static keyword. + * If such a use-case is desired, use NET_SOCKET_SERVICE_SYNC_DEFINE_STATIC + * instead. + * + * @param name Name of the service. + * @param work_q Pointer to workqueue where the work is done. Can be null in which case + * system workqueue is used. + * @param cb Callback function that is called for socket activity. + * @param count How many pollable sockets is needed for this service. + */ +#define NET_SOCKET_SERVICE_SYNC_DEFINE(name, work_q, cb, count) \ + __z_net_socket_service_define(name, work_q, cb, count, 0) + +/** + * @brief Statically define a network socket service in a private (static) scope. + * The user callback is called synchronously for this service meaning that + * the service API will wait until the user callback returns before continuing + * with next socket service. + * + * @param name Name of the service. + * @param work_q Pointer to workqueue where the work is done. Can be null in which case + * system workqueue is used. + * @param cb Callback function that is called for socket activity. + * @param count How many pollable sockets is needed for this service. + */ +#define NET_SOCKET_SERVICE_SYNC_DEFINE_STATIC(name, work_q, cb, count) \ + __z_net_socket_service_define(name, work_q, cb, count, 0, static) + +/** + * @brief Register pollable sockets. + * + * @param service Pointer to a service description. + * @param fds Socket array to poll. + * @param len Length of the socket array. + * @param user_data User specific data. + * + * @retval 0 No error + * @retval -ENOENT Service is not found. + * @retval -ENINVAL Invalid parameter. + */ +__syscall int net_socket_service_register(const struct net_socket_service_desc *service, + struct zsock_pollfd *fds, int len, void *user_data); + +/** + * @brief Unregister pollable sockets. + * + * @param service Pointer to a service description. + * + * @retval 0 No error + * @retval -ENOENT Service is not found. + * @retval -ENINVAL Invalid parameter. + */ +static inline int net_socket_service_unregister(const struct net_socket_service_desc *service) +{ + return net_socket_service_register(service, NULL, 0, NULL); +} + +/** + * @typedef net_socket_service_cb_t + * @brief Callback used while iterating over socket services. + * + * @param svc Pointer to current socket service. + * @param user_data A valid pointer to user data or NULL + */ +typedef void (*net_socket_service_cb_t)(const struct net_socket_service_desc *svc, + void *user_data); + +/** + * @brief Go through all the socket services and call callback for each service. + * + * @param cb User-supplied callback function to call + * @param user_data User specified data + */ +void net_socket_service_foreach(net_socket_service_cb_t cb, void *user_data); + +#ifdef __cplusplus +} +#endif + +#include + +/** + * @} + */ + +#endif /* ZEPHYR_INCLUDE_NET_SOCKET_SERVICE_H_ */ diff --git a/subsys/net/lib/sockets/CMakeLists.txt b/subsys/net/lib/sockets/CMakeLists.txt index 7ffd6dc476b..253cb4a182f 100644 --- a/subsys/net/lib/sockets/CMakeLists.txt +++ b/subsys/net/lib/sockets/CMakeLists.txt @@ -26,6 +26,7 @@ zephyr_library_sources_ifdef(CONFIG_NET_SOCKETS_SOCKOPT_TLS sockets_tls.c zephyr_library_sources_ifdef(CONFIG_NET_SOCKETS_OFFLOAD socket_offload.c) zephyr_library_sources_ifdef(CONFIG_NET_SOCKETS_OFFLOAD_DISPATCHER socket_dispatcher.c) zephyr_library_sources_ifdef(CONFIG_NET_SOCKETS_OBJ_CORE socket_obj_core.c) +zephyr_library_sources_ifdef(CONFIG_NET_SOCKETS_SERVICE sockets_service.c) if(CONFIG_NET_SOCKETS_NET_MGMT) zephyr_library_sources(sockets_net_mgmt.c) diff --git a/subsys/net/lib/sockets/Kconfig b/subsys/net/lib/sockets/Kconfig index b2da30c1e48..40d86b9498f 100644 --- a/subsys/net/lib/sockets/Kconfig +++ b/subsys/net/lib/sockets/Kconfig @@ -73,6 +73,31 @@ config NET_SOCKET_MAX_SEND_WAIT The maximum time a socket is waiting for a blocked connection before returning an ENOBUFS error. +config NET_SOCKETS_SERVICE + bool "Socket service support [EXPERIMENTAL]" + select EXPERIMENTAL + select EVENTFD + help + The socket service can monitor multiple sockets and save memory + by only having one thread listening socket data. If data is received + in the monitored socket, a user supplied work is called. + Note that you need to set CONFIG_NET_SOCKETS_POLL_MAX high enough + so that enough sockets entries can be serviced. This depends on + system needs as multiple services can be activated at the same time + depending on network configuration. + +config NET_SOCKETS_SERVICE_STACK_SIZE + int "Stack size for the thread handling socket services" + default 1200 + depends on NET_SOCKETS_SERVICE + help + Set the internal stack size for the thread that polls sockets. + +config NET_SOCKETS_SERVICE_INIT_PRIO + int "Startup priority for the network socket service" + default 95 + depends on NET_SOCKETS_SERVICE + config NET_SOCKETS_SOCKOPT_TLS bool "TCP TLS socket option support [EXPERIMENTAL]" imply TLS_CREDENTIALS diff --git a/subsys/net/lib/sockets/sockets_service.c b/subsys/net/lib/sockets/sockets_service.c new file mode 100644 index 00000000000..d253ece629c --- /dev/null +++ b/subsys/net/lib/sockets/sockets_service.c @@ -0,0 +1,291 @@ +/* + * Copyright (c) 2023 Nordic Semiconductor ASA + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include +LOG_MODULE_REGISTER(net_sock_svc, CONFIG_NET_SOCKETS_LOG_LEVEL); + +#include +#include +#include + +static int init_socket_service(void); +static bool init_done; + +static K_MUTEX_DEFINE(lock); +static K_CONDVAR_DEFINE(wait_start); + +STRUCT_SECTION_START_EXTERN(net_socket_service_desc); +STRUCT_SECTION_END_EXTERN(net_socket_service_desc); + +static struct service { + /* The +1 is for triggering events from register function */ + struct zsock_pollfd events[1 + CONFIG_NET_SOCKETS_POLL_MAX]; + int count; +} ctx; + +#define get_idx(svc) (*(svc->idx)) + +void net_socket_service_foreach(net_socket_service_cb_t cb, void *user_data) +{ + STRUCT_SECTION_FOREACH(net_socket_service_desc, svc) { + cb(svc, user_data); + } +} + +static void cleanup_svc_events(const struct net_socket_service_desc *svc) +{ + for (int i = 0; i < svc->pev_len; i++) { + ctx.events[get_idx(svc) + i].fd = -1; + svc->pev[i].event.fd = -1; + svc->pev[i].event.events = 0; + } +} + +int z_impl_net_socket_service_register(const struct net_socket_service_desc *svc, + struct zsock_pollfd *fds, int len, + void *user_data) +{ + int i, ret = -ENOENT; + + k_mutex_lock(&lock, K_FOREVER); + + if (!init_done) { + (void)k_condvar_wait(&wait_start, &lock, K_FOREVER); + } + + if (STRUCT_SECTION_START(net_socket_service_desc) > svc || + STRUCT_SECTION_END(net_socket_service_desc) <= svc) { + goto out; + } + + if (fds == NULL) { + cleanup_svc_events(svc); + } else { + if (len > svc->pev_len) { + NET_DBG("Too many file descriptors, " + "max is %d for service %p", + svc->pev_len, svc); + ret = -ENOMEM; + goto out; + } + + for (i = 0; i < len; i++) { + svc->pev[i].event = fds[i]; + svc->pev[i].user_data = user_data; + } + + for (i = 0; i < svc->pev_len; i++) { + ctx.events[get_idx(svc) + i] = svc->pev[i].event; + } + } + + /* Tell the thread to re-read the variables */ + eventfd_write(ctx.events[0].fd, 1); + ret = 0; + +out: + k_mutex_unlock(&lock); + + return ret; +} + +static struct net_socket_service_desc *find_svc_and_event( + struct zsock_pollfd *pev, + struct net_socket_service_event **event) +{ + STRUCT_SECTION_FOREACH(net_socket_service_desc, svc) { + for (int i = 0; i < svc->pev_len; i++) { + if (svc->pev[i].event.fd == pev->fd) { + *event = &svc->pev[i]; + return svc; + } + } + } + + return NULL; +} + +/* We do not set the user callback to our work struct because we need to + * hook into the flow and restore the global poll array so that the next poll + * round will not notice it and call the callback again while we are + * servicing the callback. + */ +void net_socket_service_callback(struct k_work *work) +{ + struct net_socket_service_event *pev = + CONTAINER_OF(work, struct net_socket_service_event, work); + struct net_socket_service_desc *svc = pev->svc; + struct net_socket_service_event ev = *pev; + + ev.callback(&ev.work); + + /* Copy back the socket fd to the global array because we marked + * it as -1 when triggering the work. + */ + for (int i = 0; i < svc->pev_len; i++) { + ctx.events[get_idx(svc) + i] = svc->pev[i].event; + } +} + +static int call_work(struct zsock_pollfd *pev, struct k_work_q *work_q, + struct k_work *work) +{ + int ret = 0; + + /* Mark the global fd non pollable so that we do not + * call the callback second time. + */ + pev->fd = -1; + + if (work->handler == NULL) { + /* Synchronous call */ + net_socket_service_callback(work); + } else { + if (work_q != NULL) { + ret = k_work_submit_to_queue(work_q, work); + } else { + ret = k_work_submit(work); + } + + k_yield(); + } + + return ret; + +} + +static int trigger_work(struct zsock_pollfd *pev) +{ + struct net_socket_service_event *event; + struct net_socket_service_desc *svc; + + svc = find_svc_and_event(pev, &event); + if (svc == NULL) { + return -ENOENT; + } + + event->svc = svc; + + /* Copy the triggered event to our event so that we know what + * was actually causing the event. + */ + event->event = *pev; + + return call_work(pev, svc->work_q, &event->work); +} + +static void socket_service_thread(void) +{ + int ret, i, fd, count = 0; + eventfd_t value; + + STRUCT_SECTION_COUNT(net_socket_service_desc, &ret); + if (ret == 0) { + NET_INFO("No socket services found, service disabled."); + goto fail; + } + + /* Create contiguous poll event array to enable socket polling */ + STRUCT_SECTION_FOREACH(net_socket_service_desc, svc) { + get_idx(svc) = count + 1; + count += svc->pev_len; + } + + if ((count + 1) > ARRAY_SIZE(ctx.events)) { + NET_WARN("You have %d services to monitor but " + "%d poll entries configured.", + count + 1, ARRAY_SIZE(ctx.events)); + NET_WARN("Consider increasing value of %s to %d", + "CONFIG_NET_SOCKETS_POLL_MAX", count + 1); + } + + NET_DBG("Monitoring %d socket entries", count); + + ctx.count = count + 1; + + /* Create an eventfd that can be used to trigger events during polling */ + fd = eventfd(0, 0); + if (fd < 0) { + fd = -errno; + NET_ERR("eventfd failed (%d)", fd); + goto out; + } + + init_done = true; + k_condvar_broadcast(&wait_start); + + ctx.events[0].fd = fd; + ctx.events[0].events = ZSOCK_POLLIN; + +restart: + i = 1; + + k_mutex_lock(&lock, K_FOREVER); + + /* Copy individual events to the big array */ + STRUCT_SECTION_FOREACH(net_socket_service_desc, svc) { + for (int j = 0; j < svc->pev_len; j++) { + ctx.events[get_idx(svc) + j] = svc->pev[j].event; + } + } + + k_mutex_unlock(&lock); + + while (true) { + ret = zsock_poll(ctx.events, count + 1, -1); + if (ret < 0) { + ret = -errno; + NET_ERR("poll failed (%d)", ret); + goto out; + } + + if (ret == 0) { + /* should not happen because timeout is -1 */ + break; + } + + if (ret > 0 && ctx.events[0].revents) { + eventfd_read(ctx.events[0].fd, &value); + NET_DBG("Received restart event."); + goto restart; + } + + for (i = 1; i < (count + 1); i++) { + if (ctx.events[i].fd < 0) { + continue; + } + + if (ctx.events[i].revents > 0) { + ret = trigger_work(&ctx.events[i]); + if (ret < 0) { + NET_DBG("Triggering work failed (%d)", ret); + } + } + } + } + +out: + NET_DBG("Socket service thread stopped"); + init_done = false; + + return; + +fail: + k_condvar_broadcast(&wait_start); +} + +K_THREAD_DEFINE(socket_service_monitor, CONFIG_NET_SOCKETS_SERVICE_STACK_SIZE, + socket_service_thread, NULL, NULL, NULL, + K_LOWEST_APPLICATION_THREAD_PRIO, 0, 0); + +static int init_socket_service(void) +{ + k_thread_name_set(socket_service_monitor, "net_socket_service"); + + return 0; +} + +SYS_INIT(init_socket_service, APPLICATION, CONFIG_NET_SOCKETS_SERVICE_INIT_PRIO); From 6ea6326e79fae28ca813174291559fcf3f92c114 Mon Sep 17 00:00:00 2001 From: Jukka Rissanen Date: Wed, 20 Dec 2023 20:13:27 +0200 Subject: [PATCH 2262/3723] tests: net: socket: service: Add tests for socket service API Simple tests that verify that the socket service API works as expected. Signed-off-by: Jukka Rissanen --- tests/net/socket/service/CMakeLists.txt | 9 ++ tests/net/socket/service/prj.conf | 31 ++++ tests/net/socket/service/src/main.c | 199 ++++++++++++++++++++++++ tests/net/socket/service/testcase.yaml | 17 ++ 4 files changed, 256 insertions(+) create mode 100644 tests/net/socket/service/CMakeLists.txt create mode 100644 tests/net/socket/service/prj.conf create mode 100644 tests/net/socket/service/src/main.c create mode 100644 tests/net/socket/service/testcase.yaml diff --git a/tests/net/socket/service/CMakeLists.txt b/tests/net/socket/service/CMakeLists.txt new file mode 100644 index 00000000000..1f85d6ad372 --- /dev/null +++ b/tests/net/socket/service/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(socket_poll) + +target_include_directories(app PRIVATE ${ZEPHYR_BASE}/subsys/net/ip) +FILE(GLOB app_sources src/*.c) +target_sources(app PRIVATE ${app_sources}) diff --git a/tests/net/socket/service/prj.conf b/tests/net/socket/service/prj.conf new file mode 100644 index 00000000000..5e51a0f6a53 --- /dev/null +++ b/tests/net/socket/service/prj.conf @@ -0,0 +1,31 @@ +# Networking config +CONFIG_NETWORKING=y +CONFIG_NET_IPV4=y +CONFIG_NET_IPV6=y +CONFIG_NET_UDP=y +CONFIG_NET_TCP=y +CONFIG_NET_SOCKETS=y +CONFIG_POSIX_MAX_FDS=10 +CONFIG_NET_PKT_TX_COUNT=8 +CONFIG_NET_PKT_RX_COUNT=8 +CONFIG_NET_MAX_CONN=5 +CONFIG_NET_SOCKETS_SERVICE=y +CONFIG_NET_SOCKETS_POLL_MAX=20 + +# We need to set POSIX_API and use picolibc for eventfd to work +CONFIG_POSIX_API=y +CONFIG_PICOLIBC=y + +# Network driver config +CONFIG_TEST_RANDOM_GENERATOR=y + +CONFIG_MAIN_STACK_SIZE=2048 +CONFIG_ZTEST_STACK_SIZE=1280 + +CONFIG_ZTEST=y + +CONFIG_NET_TEST=y +CONFIG_NET_DRIVERS=y +CONFIG_NET_LOOPBACK=y +CONFIG_NET_TCP_MAX_RECV_WINDOW_SIZE=128 +CONFIG_NET_TCP_TIME_WAIT_DELAY=50 diff --git a/tests/net/socket/service/src/main.c b/tests/net/socket/service/src/main.c new file mode 100644 index 00000000000..1eb10fff6f3 --- /dev/null +++ b/tests/net/socket/service/src/main.c @@ -0,0 +1,199 @@ +/* + * Copyright (c) 2023 Nordic Semiconductor + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include +LOG_MODULE_REGISTER(net_test, CONFIG_NET_SOCKETS_LOG_LEVEL); + +#include +#include + +#include + +#include "../../socket_helpers.h" + +#define BUF_AND_SIZE(buf) buf, sizeof(buf) - 1 +#define STRLEN(buf) (sizeof(buf) - 1) + +#define TEST_STR_SMALL "test" + +#define MY_IPV6_ADDR "::1" + +#define ANY_PORT 0 +#define SERVER_PORT 4242 +#define CLIENT_PORT 9898 + +#define TCP_TEARDOWN_TIMEOUT K_SECONDS(3) + +K_SEM_DEFINE(wait_data, 0, UINT_MAX); +K_SEM_DEFINE(wait_data_tcp, 0, UINT_MAX); +#define WAIT_TIME 500 + +static void server_handler(struct k_work *work) +{ + struct net_socket_service_event *pev = + CONTAINER_OF(work, struct net_socket_service_event, work); + + ARG_UNUSED(pev); + + k_sem_give(&wait_data); +} + +static void tcp_server_handler(struct k_work *work) +{ + struct net_socket_service_event *pev = + CONTAINER_OF(work, struct net_socket_service_event, work); + + ARG_UNUSED(pev); + + k_sem_give(&wait_data_tcp); + + k_yield(); + + Z_SPIN_DELAY(100); +} + +NET_SOCKET_SERVICE_ASYNC_DEFINE(udp_service_async, NULL, server_handler, 2); +NET_SOCKET_SERVICE_ASYNC_DEFINE(tcp_service_small_async, NULL, tcp_server_handler, 1); +NET_SOCKET_SERVICE_ASYNC_DEFINE_STATIC(tcp_service_async, NULL, tcp_server_handler, 2); + +NET_SOCKET_SERVICE_SYNC_DEFINE(udp_service_sync, NULL, server_handler, 2); +NET_SOCKET_SERVICE_SYNC_DEFINE(tcp_service_small_sync, NULL, tcp_server_handler, 1); +NET_SOCKET_SERVICE_SYNC_DEFINE_STATIC(tcp_service_sync, NULL, tcp_server_handler, 2); + + +void run_test_service(const struct net_socket_service_desc *udp_service, + const struct net_socket_service_desc *tcp_service_small, + const struct net_socket_service_desc *tcp_service) +{ + int ret; + int c_sock_udp; + int s_sock_udp; + int c_sock_tcp; + int s_sock_tcp; + int new_sock; + struct sockaddr_in6 c_addr; + struct sockaddr_in6 s_addr; + ssize_t len; + char buf[10]; + struct zsock_pollfd sock[2] = { + [0] = { .fd = -1 }, + [1] = { .fd = -1 }, + }; + + prepare_sock_udp_v6(MY_IPV6_ADDR, CLIENT_PORT, &c_sock_udp, &c_addr); + prepare_sock_udp_v6(MY_IPV6_ADDR, SERVER_PORT, &s_sock_udp, &s_addr); + prepare_sock_tcp_v6(MY_IPV6_ADDR, CLIENT_PORT, &c_sock_tcp, &c_addr); + prepare_sock_tcp_v6(MY_IPV6_ADDR, SERVER_PORT, &s_sock_tcp, &s_addr); + + sock[0].fd = s_sock_udp; + sock[0].events = ZSOCK_POLLIN; + + ret = net_socket_service_register(udp_service, sock, ARRAY_SIZE(sock), NULL); + zassert_equal(ret, 0, "Cannot register udp service (%d)", ret); + + sock[0].fd = s_sock_tcp; + sock[0].events = ZSOCK_POLLIN; + + ret = net_socket_service_register(tcp_service_small, sock, ARRAY_SIZE(sock) + 1, NULL); + zassert_equal(ret, -ENOMEM, "Could register tcp service (%d)", ret); + + ret = net_socket_service_register(tcp_service, sock, ARRAY_SIZE(sock), NULL); + zassert_equal(ret, 0, "Cannot register tcp service (%d)", ret); + + ret = bind(s_sock_udp, (struct sockaddr *)&s_addr, sizeof(s_addr)); + zassert_equal(ret, 0, "bind failed"); + + ret = connect(c_sock_udp, (struct sockaddr *)&s_addr, sizeof(s_addr)); + zassert_equal(ret, 0, "connect failed"); + + /* Send pkt for s_sock_udp and poll with timeout of 10 */ + len = send(c_sock_udp, BUF_AND_SIZE(TEST_STR_SMALL), 0); + zassert_equal(len, STRLEN(TEST_STR_SMALL), "invalid send len"); + + if (k_sem_take(&wait_data, K_MSEC(WAIT_TIME))) { + zassert_true(0, "Timeout while waiting callback"); + } + + /* Recv pkt from s_sock_udp and ensure no poll events happen */ + len = recv(s_sock_udp, BUF_AND_SIZE(buf), 0); + zassert_equal(len, STRLEN(TEST_STR_SMALL), "invalid recv len"); + + ret = bind(s_sock_tcp, (struct sockaddr *)&s_addr, sizeof(s_addr)); + zassert_equal(ret, 0, "bind failed (%d)", -errno); + ret = listen(s_sock_tcp, 0); + zassert_equal(ret, 0, ""); + + ret = connect(c_sock_tcp, (const struct sockaddr *)&s_addr, + sizeof(s_addr)); + zassert_equal(ret, 0, ""); + + /* Let the network stack run */ + k_msleep(10); + + len = send(c_sock_tcp, BUF_AND_SIZE(TEST_STR_SMALL), 0); + zassert_equal(len, STRLEN(TEST_STR_SMALL), "invalid send len"); + + if (k_sem_take(&wait_data_tcp, K_MSEC(WAIT_TIME))) { + zassert_true(0, "Timeout while waiting callback"); + } + + new_sock = accept(s_sock_tcp, NULL, NULL); + zassert_true(new_sock >= 0, ""); + + sock[1].fd = new_sock; + sock[1].events = ZSOCK_POLLIN; + + ret = net_socket_service_register(tcp_service, sock, ARRAY_SIZE(sock), NULL); + zassert_equal(ret, 0, "Cannot register tcp service (%d)", ret); + + if (k_sem_take(&wait_data_tcp, K_MSEC(WAIT_TIME))) { + zassert_true(0, "Timeout while waiting callback"); + } + + len = recv(new_sock, BUF_AND_SIZE(buf), 0); + zassert_equal(len, STRLEN(TEST_STR_SMALL), "invalid recv len"); + + ret = net_socket_service_unregister(tcp_service); + zassert_equal(ret, 0, "Cannot unregister tcp service (%d)", ret); + + ret = net_socket_service_unregister(udp_service); + zassert_equal(ret, 0, "Cannot unregister tcp service (%d)", ret); + + ret = net_socket_service_unregister(tcp_service_small); + zassert_equal(ret, 0, "Cannot unregister tcp service (%d)", ret); + + ret = close(new_sock); + zassert_equal(ret, 0, "close failed"); + + ret = close(c_sock_tcp); + zassert_equal(ret, 0, "close failed"); + + ret = close(s_sock_tcp); + zassert_equal(ret, 0, "close failed"); + + ret = close(c_sock_udp); + zassert_equal(ret, 0, "close failed"); + + ret = close(s_sock_udp); + zassert_equal(ret, 0, "close failed"); + + /* Let the stack close the TCP sockets properly */ + k_msleep(100); +} + +ZTEST(net_socket_service, test_service_sync) +{ + run_test_service(&udp_service_sync, &tcp_service_small_sync, + &tcp_service_sync); +} + +ZTEST(net_socket_service, test_service_async) +{ + run_test_service(&udp_service_async, &tcp_service_small_async, + &tcp_service_async); +} + +ZTEST_SUITE(net_socket_service, NULL, NULL, NULL, NULL, NULL); diff --git a/tests/net/socket/service/testcase.yaml b/tests/net/socket/service/testcase.yaml new file mode 100644 index 00000000000..74046d08274 --- /dev/null +++ b/tests/net/socket/service/testcase.yaml @@ -0,0 +1,17 @@ +common: + depends_on: netif + # FIXME: This test fails very frequently on mps2_an385 due to the system + # timer stability issues, so keep it disabled until the root cause + # is fixed (GitHub issue zephyrproject-rtos/zephyr#48608). + # eventfd API does not work with native_posix so exclude it here + platform_exclude: + - mps2_an385 + - native_posix + - native_posix_64 +tests: + net.socket.service: + min_ram: 21 + tags: + - net + - socket + - poll From f4373709e7be98d117f28b8bf82fb8d9e62f941d Mon Sep 17 00:00:00 2001 From: Jukka Rissanen Date: Thu, 21 Dec 2023 16:56:39 +0200 Subject: [PATCH 2263/3723] samples: net: sockets: Add echo-service sample The echo-service sample demostrates how to use the socket service API. Signed-off-by: Jukka Rissanen --- .../net/sockets/echo_service/CMakeLists.txt | 11 + samples/net/sockets/echo_service/README.rst | 51 ++++ .../sockets/echo_service/overlay-e1000.conf | 6 + samples/net/sockets/echo_service/prj.conf | 38 +++ samples/net/sockets/echo_service/sample.yaml | 16 ++ samples/net/sockets/echo_service/src/main.c | 255 ++++++++++++++++++ 6 files changed, 377 insertions(+) create mode 100644 samples/net/sockets/echo_service/CMakeLists.txt create mode 100644 samples/net/sockets/echo_service/README.rst create mode 100644 samples/net/sockets/echo_service/overlay-e1000.conf create mode 100644 samples/net/sockets/echo_service/prj.conf create mode 100644 samples/net/sockets/echo_service/sample.yaml create mode 100644 samples/net/sockets/echo_service/src/main.c diff --git a/samples/net/sockets/echo_service/CMakeLists.txt b/samples/net/sockets/echo_service/CMakeLists.txt new file mode 100644 index 00000000000..fda31959a7d --- /dev/null +++ b/samples/net/sockets/echo_service/CMakeLists.txt @@ -0,0 +1,11 @@ +# SPDX-License-Identifier: Apache-2.0 + +cmake_minimum_required(VERSION 3.20.0) + +find_package(Zephyr REQUIRED HINTS $ENV{ZEPHYR_BASE}) +project(sockets_service_echo) + +FILE(GLOB app_sources src/*.c) +target_sources(app PRIVATE ${app_sources}) + +include(${ZEPHYR_BASE}/samples/net/common/common.cmake) diff --git a/samples/net/sockets/echo_service/README.rst b/samples/net/sockets/echo_service/README.rst new file mode 100644 index 00000000000..3e1d7625d70 --- /dev/null +++ b/samples/net/sockets/echo_service/README.rst @@ -0,0 +1,51 @@ +.. zephyr:code-sample:: sockets-service-echo + :name: Echo server (service) + :relevant-api: bsd_sockets + + Implements a simple IPv4/IPv6 TCP echo server using BSD sockets and socket service API. + +Overview +******** + +The sockets/echo_service sample application for Zephyr implements a TCP echo +server supporting both IPv4 and IPv6 and using a BSD Sockets compatible API. + +The purpose of this sample is to show how to use socket service API. +The socket service is a concept where many blocking sockets can be listened by +one thread, and which can then trigger a callback if there is activity in the set +of sockets. This saves memory as only one thread needs to be created in the +system. + +The application supports IPv4 and IPv6, and both UDP and TCP are also supported. +The source code for this sample application can be found at: +:zephyr_file:`samples/net/sockets/echo_service`. + +Requirements +************ + +- :ref:`networking_with_host` +- or, a board with hardware networking + +Building and Running +******************** + +Build the Zephyr version of the sockets/echo_service application like this: + +.. zephyr-app-commands:: + :zephyr-app: samples/net/sockets/echo_service + :board: + :goals: build + :compact: + +After the sample starts, it expects connections at 192.0.2.1, or 2001:db8::1 +and port 4242. +The easiest way to connect is: + +.. code-block:: console + + $ telnet 192.0.2.1 4242 + +After a connection is made, the application will echo back any line sent +to it. The application implements a single-threaded server using blocking +sockets, and currently is only implemented to serve only one client connection +at time. After the current client disconnects, the next connection can proceed. diff --git a/samples/net/sockets/echo_service/overlay-e1000.conf b/samples/net/sockets/echo_service/overlay-e1000.conf new file mode 100644 index 00000000000..adcf29f904d --- /dev/null +++ b/samples/net/sockets/echo_service/overlay-e1000.conf @@ -0,0 +1,6 @@ +# Overlay for experimental TCP as qemu_x86 with E1000 + +CONFIG_PCIE=y + +CONFIG_NET_L2_ETHERNET=y +CONFIG_NET_QEMU_ETHERNET=y diff --git a/samples/net/sockets/echo_service/prj.conf b/samples/net/sockets/echo_service/prj.conf new file mode 100644 index 00000000000..c39159ea7e4 --- /dev/null +++ b/samples/net/sockets/echo_service/prj.conf @@ -0,0 +1,38 @@ +# General config +# The async method used in the sample needs more stack for the workqueue +CONFIG_SYSTEM_WORKQUEUE_STACK_SIZE=1500 +CONFIG_POSIX_API=y + +# Networking config +CONFIG_NETWORKING=y +CONFIG_NET_IPV4=y +CONFIG_NET_IPV6=y +CONFIG_NET_TCP=y +CONFIG_NET_SOCKETS=y +CONFIG_NET_SOCKETS_POSIX_NAMES=y +CONFIG_NET_IPV4_MAPPING_TO_IPV6=y +CONFIG_POSIX_MAX_FDS=10 +CONFIG_NET_MAX_CONN=5 +CONFIG_NET_SOCKETS_SERVICE=y +CONFIG_NET_SOCKETS_POLL_MAX=20 + +# Network driver config +CONFIG_TEST_RANDOM_GENERATOR=y + +# Network address config +CONFIG_NET_CONFIG_SETTINGS=y +CONFIG_NET_CONFIG_NEED_IPV4=y +CONFIG_NET_CONFIG_NEED_IPV6=y +CONFIG_NET_CONFIG_MY_IPV4_ADDR="192.0.2.1" +CONFIG_NET_CONFIG_PEER_IPV4_ADDR="192.0.2.2" +CONFIG_NET_CONFIG_MY_IPV6_ADDR="2001:db8::1" +CONFIG_NET_CONFIG_PEER_IPV6_ADDR="2001:db8::2" + +# Network buffers +CONFIG_NET_PKT_RX_COUNT=16 +CONFIG_NET_PKT_TX_COUNT=16 +CONFIG_NET_BUF_RX_COUNT=64 +CONFIG_NET_BUF_TX_COUNT=64 +CONFIG_NET_CONTEXT_NET_PKT_POOL=y + +CONFIG_NET_SHELL=y diff --git a/samples/net/sockets/echo_service/sample.yaml b/samples/net/sockets/echo_service/sample.yaml new file mode 100644 index 00000000000..aee10686c0f --- /dev/null +++ b/samples/net/sockets/echo_service/sample.yaml @@ -0,0 +1,16 @@ +sample: + description: echo server using socket service API + name: socket_service_echo +common: + harness: net + depends_on: netif + filter: CONFIG_FULL_LIBC_SUPPORTED and not CONFIG_NATIVE_LIBC + # eventfd does not work properly with native_posix so exclude it here + platform_exclude: + - native_posix + - native_posix_64 +tests: + sample.net.sockets.service.echo: + tags: + - net + - socket diff --git a/samples/net/sockets/echo_service/src/main.c b/samples/net/sockets/echo_service/src/main.c new file mode 100644 index 00000000000..dbdde28cf30 --- /dev/null +++ b/samples/net/sockets/echo_service/src/main.c @@ -0,0 +1,255 @@ +/* + * Copyright (c) 2023 Nordic Semiconductor + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include +LOG_MODULE_REGISTER(net_echo_server_svc_sample, LOG_LEVEL_DBG); + +#include +#include +#include + +#include +#include +#include +#include +#include +#include + +#define MY_PORT 4242 + +static char addr_str[INET6_ADDRSTRLEN]; + +static struct pollfd sockfd_udp[1] = { + [0] = { .fd = -1 }, /* UDP socket */ +}; +static struct pollfd sockfd_tcp[1] = { + [0] = { .fd = -1 }, /* TCP socket */ +}; + +#define MAX_SERVICES 1 + +static void receive_data(bool is_udp, struct net_socket_service_event *pev, + char *buf, size_t buflen); + +static void tcp_service_handler(struct k_work *work) +{ + struct net_socket_service_event *pev = + CONTAINER_OF(work, struct net_socket_service_event, work); + static char buf[1500]; + + /* Note that in this application we receive / send data from + * system work queue. In proper application the socket reading and data + * sending should be done so that the system work queue is not blocked. + * It is possible to create a socket service that uses own work queue. + */ + receive_data(false, pev, buf, sizeof(buf)); +} + +static void udp_service_handler(struct k_work *work) +{ + struct net_socket_service_event *pev = + CONTAINER_OF(work, struct net_socket_service_event, work); + static char buf[1500]; + + receive_data(true, pev, buf, sizeof(buf)); +} + +/* In this example we create two services, one with async behavior and one with + * sync one. The async is for TCP and sync is for UDP (this is just an arbitrary + * choice). + * This is an artificial example, both UDP and TCP sockets could be served by the + * same service. + */ +NET_SOCKET_SERVICE_SYNC_DEFINE_STATIC(service_udp, NULL, udp_service_handler, MAX_SERVICES); +NET_SOCKET_SERVICE_ASYNC_DEFINE_STATIC(service_tcp, NULL, tcp_service_handler, MAX_SERVICES); + +static void receive_data(bool is_udp, struct net_socket_service_event *pev, + char *buf, size_t buflen) +{ + struct pollfd *pfd = &pev->event; + int client = pfd->fd; + struct sockaddr_in6 addr; + socklen_t addrlen = sizeof(addr); + int len, out_len; + char *p; + + len = recvfrom(client, buf, buflen, 0, + (struct sockaddr *)&addr, &addrlen); + if (len <= 0) { + if (len < 0) { + LOG_ERR("recv: %d", -errno); + } + + /* If the TCP socket is closed, mark it as non pollable */ + if (!is_udp && sockfd_tcp[0].fd == client) { + sockfd_tcp[0].fd = -1; + + /* Update the handler so that client connection is + * not monitored any more. + */ + (void)net_socket_service_register(&service_tcp, sockfd_tcp, + ARRAY_SIZE(sockfd_tcp), NULL); + close(client); + + LOG_INF("Connection from %s closed", addr_str); + } + + return; + } + + p = buf; + do { + out_len = sendto(client, p, len, 0, + (struct sockaddr *)&addr, addrlen); + if (out_len < 0) { + LOG_ERR("sendto: %d", -errno); + break; + } + + p += out_len; + len -= out_len; + } while (len); +} + +static int setup_tcp_socket(struct sockaddr_in6 *addr) +{ + socklen_t optlen = sizeof(int); + int ret, sock, opt; + + sock = socket(AF_INET6, SOCK_STREAM, IPPROTO_TCP); + if (sock < 0) { + LOG_ERR("socket: %d", -errno); + return -errno; + } + + ret = getsockopt(sock, IPPROTO_IPV6, IPV6_V6ONLY, &opt, &optlen); + if (ret == 0 && opt) { + LOG_INF("IPV6_V6ONLY option is on, turning it off."); + + opt = 0; + ret = setsockopt(sock, IPPROTO_IPV6, IPV6_V6ONLY, &opt, optlen); + if (ret < 0) { + LOG_WRN("Cannot turn off IPV6_V6ONLY option"); + } else { + LOG_INF("Sharing same socket between IPv6 and IPv4"); + } + } + + if (bind(sock, (struct sockaddr *)addr, sizeof(*addr)) < 0) { + LOG_ERR("bind: %d", -errno); + return -errno; + } + + if (listen(sock, 5) < 0) { + LOG_ERR("listen: %d", -errno); + return -errno; + } + + return sock; +} + +static int setup_udp_socket(struct sockaddr_in6 *addr) +{ + socklen_t optlen = sizeof(int); + int ret, sock, opt; + + sock = socket(AF_INET6, SOCK_DGRAM, IPPROTO_UDP); + if (sock < 0) { + LOG_ERR("socket: %d", -errno); + return -errno; + } + + ret = getsockopt(sock, IPPROTO_IPV6, IPV6_V6ONLY, &opt, &optlen); + if (ret == 0 && opt) { + LOG_INF("IPV6_V6ONLY option is on, turning it off."); + + opt = 0; + ret = setsockopt(sock, IPPROTO_IPV6, IPV6_V6ONLY, &opt, optlen); + if (ret < 0) { + LOG_WRN("Cannot turn off IPV6_V6ONLY option"); + } else { + LOG_INF("Sharing same socket between IPv6 and IPv4"); + } + } + + if (bind(sock, (struct sockaddr *)addr, sizeof(*addr)) < 0) { + LOG_ERR("bind: %d", -errno); + return -errno; + } + + return sock; +} + +int main(void) +{ + int tcp_sock, udp_sock, ret; + struct sockaddr_in6 addr = { + .sin6_family = AF_INET6, + .sin6_addr = IN6ADDR_ANY_INIT, + .sin6_port = htons(MY_PORT), + }; + static int counter; + + tcp_sock = setup_tcp_socket(&addr); + if (tcp_sock < 0) { + return tcp_sock; + } + + udp_sock = setup_udp_socket(&addr); + if (udp_sock < 0) { + return udp_sock; + } + + sockfd_udp[0].fd = udp_sock; + sockfd_udp[0].events = POLLIN; + + /* Register UDP socket to service handler */ + ret = net_socket_service_register(&service_udp, sockfd_udp, + ARRAY_SIZE(sockfd_udp), NULL); + if (ret < 0) { + LOG_ERR("Cannot register socket service handler (%d)", ret); + } + + LOG_INF("Single-threaded TCP/UDP echo server waits " + "for a connection on port %d", MY_PORT); + + while (1) { + struct sockaddr_in6 client_addr; + socklen_t client_addr_len = sizeof(client_addr); + int client; + + client = accept(tcp_sock, (struct sockaddr *)&client_addr, + &client_addr_len); + if (client < 0) { + LOG_ERR("accept: %d", -errno); + continue; + } + + inet_ntop(client_addr.sin6_family, &client_addr.sin6_addr, + addr_str, sizeof(addr_str)); + LOG_INF("Connection #%d from %s (%d)", counter++, addr_str, client); + + sockfd_tcp[0].fd = client; + sockfd_tcp[0].events = POLLIN; + + /* Register all the sockets to service handler */ + ret = net_socket_service_register(&service_tcp, sockfd_tcp, + ARRAY_SIZE(sockfd_tcp), NULL); + if (ret < 0) { + LOG_ERR("Cannot register socket service handler (%d)", + ret); + break; + } + } + + (void)net_socket_service_unregister(&service_tcp); + (void)net_socket_service_unregister(&service_udp); + + close(tcp_sock); + close(udp_sock); + + return 0; +} From f5e95852ced37a4effd8f74fec19ea408dde1ac6 Mon Sep 17 00:00:00 2001 From: Jukka Rissanen Date: Tue, 9 Jan 2024 12:28:52 +0200 Subject: [PATCH 2264/3723] net: shell: Add sockets services prints The socket services users to "net sockets" command. Signed-off-by: Jukka Rissanen --- subsys/net/lib/shell/sockets.c | 92 +++++++++++++++++++++++++++++++++- 1 file changed, 91 insertions(+), 1 deletion(-) diff --git a/subsys/net/lib/shell/sockets.c b/subsys/net/lib/shell/sockets.c index 8be67fc5faf..62d41b5cdf2 100644 --- a/subsys/net/lib/shell/sockets.c +++ b/subsys/net/lib/shell/sockets.c @@ -9,6 +9,7 @@ LOG_MODULE_DECLARE(net_shell); #include "net_shell_private.h" #include +#include #if defined(CONFIG_NET_SOCKETS_OBJ_CORE) struct socket_info { @@ -78,6 +79,57 @@ int walk_sockets(struct k_obj_core *obj_core, void *user_data) } #endif /* CONFIG_NET_SOCKETS_OBJ_CORE */ +#if defined(CONFIG_NET_SOCKETS_SERVICE) + +#if CONFIG_NET_SOCKETS_LOG_LEVEL >= LOG_LEVEL_DBG +#define MAX_OWNER_LEN 32 +#else +#define MAX_OWNER_LEN sizeof("") +#endif + +static void walk_socket_services(const struct net_socket_service_desc *svc, + void *user_data) +{ + struct net_shell_user_data *data = user_data; + const struct shell *sh = data->sh; + int *count = data->user_data; + int len = 0; + static char pev_output[sizeof("xxx,") * CONFIG_NET_SOCKETS_POLL_MAX]; + static char owner[MAX_OWNER_LEN + 1]; + + NET_ASSERT(svc->pev != NULL); + + for (int i = 0; i < svc->pev_len; i++) { + len += snprintk(pev_output + len, sizeof(pev_output) - len, + "%d,", svc->pev[i].event.fd); + } + + if (len > 0) { + pev_output[len - 1] = '\0'; + } + +#if CONFIG_NET_SOCKETS_LOG_LEVEL >= LOG_LEVEL_DBG + len = strlen(svc->owner); + + int offset = len > sizeof(owner) ? + len -= (sizeof(owner) - 3) : 0; + + snprintk(owner, sizeof(owner), "%s%s", + offset == 0 ? "" : "...", + svc->owner + offset + 1); +#else + snprintk(owner, sizeof(owner), ""); +#endif + + PR("%32s %-6s %-5d %s\n", + owner, + svc->pev->work.handler == NULL ? "SYNC" : "ASYNC", + svc->pev_len, pev_output); + + (*count)++; +} +#endif /* CONFIG_NET_SOCKETS_SERVICE */ + static int cmd_net_sockets(const struct shell *sh, size_t argc, char *argv[]) { #if defined(CONFIG_NET_SOCKETS_OBJ_CORE) @@ -113,7 +165,39 @@ static int cmd_net_sockets(const struct shell *sh, size_t argc, char *argv[]) count.closed == 1 ? "" : "s"); } } -#else + +#if defined(CONFIG_NET_SOCKETS_SERVICE) + PR("\n"); +#endif +#endif + +#if defined(CONFIG_NET_SOCKETS_SERVICE) + struct net_shell_user_data svc_user_data; + int svc_count = 0; + + svc_user_data.sh = sh; + svc_user_data.user_data = &svc_count; + + PR("Services:\n"); + PR("%32s %-6s %-5s %s\n", + "Owner", "Mode", "Count", "FDs"); + PR("\n"); + + net_socket_service_foreach(walk_socket_services, (void *)&svc_user_data); + + if (svc_count == 0) { + PR("No socket services found.\n"); + } else { + PR("\n%d socket service%s found.\n", svc_count, + svc_count == 1 ? "" : "s"); + } + +#if !defined(CONFIG_NET_SOCKETS_OBJ_CORE) + PR("\n"); +#endif +#endif + +#if !defined(CONFIG_NET_SOCKETS_OBJ_CORE) ARG_UNUSED(argc); ARG_UNUSED(argv); @@ -121,6 +205,12 @@ static int cmd_net_sockets(const struct shell *sh, size_t argc, char *argv[]) "CONFIG_OBJ_CORE and CONFIG_NET_SOCKETS_OBJ_CORE", "socket information"); #endif +#if !defined(CONFIG_NET_SOCKETS_SERVICE) + ARG_UNUSED(argc); + ARG_UNUSED(argv); + + PR_INFO("Socket service not supported.\n"); +#endif return 0; } From eb22110365fe09b85a6c6ce06d4c4eafed60a5d2 Mon Sep 17 00:00:00 2001 From: Jukka Rissanen Date: Wed, 3 Jan 2024 16:25:19 +0200 Subject: [PATCH 2265/3723] tests: net: socket: Add correct path to socket.h for POSIX_API If CONFIG_POSIX_API is enabled, then the socket.h is found under zephyr/posix/sys/socket.h etc. This allows one to compile the socket test applications without error prints. Signed-off-by: Jukka Rissanen --- tests/net/socket/socket_helpers.h | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/tests/net/socket/socket_helpers.h b/tests/net/socket/socket_helpers.h index 1d4d33f4bca..9cecccc20b6 100644 --- a/tests/net/socket/socket_helpers.h +++ b/tests/net/socket/socket_helpers.h @@ -6,7 +6,13 @@ #include +#if defined(CONFIG_POSIX_API) +#include +#include +#include +#else #include +#endif #define clear_buf(buf) memset(buf, 0, sizeof(buf)) From 60331612160a5f728dcb74c4c79b26dc86029aa8 Mon Sep 17 00:00:00 2001 From: Jukka Rissanen Date: Fri, 12 Jan 2024 17:35:37 +0200 Subject: [PATCH 2266/3723] net: shell: Avoid gcc warning print with string catenation gcc prints this warning message 'strncat' specified bound 1 equals source length [-Wstringop-overflow=] 58 | strncat(fd, "C", 1); There was no error in the code but avoid the warning by not using strncat(). Signed-off-by: Jukka Rissanen --- subsys/net/lib/shell/sockets.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/subsys/net/lib/shell/sockets.c b/subsys/net/lib/shell/sockets.c index 62d41b5cdf2..012c572d777 100644 --- a/subsys/net/lib/shell/sockets.c +++ b/subsys/net/lib/shell/sockets.c @@ -55,7 +55,8 @@ int walk_sockets(struct k_obj_core *obj_core, void *user_data) * actual lifetime as calculated in close() */ lifetime = obj->create_time; - strncat(fd, "C", 1); + fd[0] = 'C'; + fd[1] = '\0'; count->closed++; } else { lifetime = k_ticks_to_ms_ceil32(sys_clock_tick_get() - From be563239c8e09636dfad9f7737149260cf39fabd Mon Sep 17 00:00:00 2001 From: Yuval Peress Date: Thu, 16 Nov 2023 01:29:04 -0700 Subject: [PATCH 2267/3723] sensor: testing: Update sensor emul backend Update the backend for sensor emulators to include a function for setting the offset as well as a function to query an attribute's metadata such as bounds and increment size. Additionally, add backend support for setting the _xyz channel values. Make the appropriate test changes to accomodate. Signed-off-by: Yuval Peress --- drivers/sensor/akm09918c/akm09918c_emul.c | 7 +- drivers/sensor/amd_sb_tsi/sb_tsi_emul.c | 4 +- drivers/sensor/bmi160/emul_bmi160.c | 407 +++++++++++++++--- drivers/sensor/bmi160/emul_bmi160.h | 98 +++++ drivers/sensor/f75303/f75303_emul.c | 4 +- drivers/sensor/icm42688/icm42688_emul.c | 4 +- include/zephyr/drivers/emul.h | 12 + include/zephyr/drivers/emul_sensor.h | 74 +++- .../zephyr/drivers/sensor_attribute_types.h | 43 ++ .../build_all/sensor/src/generic_test.c | 2 +- 10 files changed, 581 insertions(+), 74 deletions(-) create mode 100644 drivers/sensor/bmi160/emul_bmi160.h create mode 100644 include/zephyr/drivers/sensor_attribute_types.h diff --git a/drivers/sensor/akm09918c/akm09918c_emul.c b/drivers/sensor/akm09918c/akm09918c_emul.c index 02dc28b35db..adb237e1256 100644 --- a/drivers/sensor/akm09918c/akm09918c_emul.c +++ b/drivers/sensor/akm09918c/akm09918c_emul.c @@ -134,7 +134,7 @@ static int akm09918c_emul_init(const struct emul *target, const struct device *p } static int akm09918c_emul_backend_set_channel(const struct emul *target, enum sensor_channel ch, - q31_t value, int8_t shift) + const q31_t *value, int8_t shift) { if (!target || !target->data) { return -EINVAL; @@ -162,8 +162,9 @@ static int akm09918c_emul_backend_set_channel(const struct emul *target, enum se data->reg[AKM09918C_REG_ST1] |= AKM09918C_ST1_DRDY; /* Convert fixed-point Gauss values into microgauss and then into its bit representation */ - int32_t microgauss = (shift < 0 ? ((int64_t)value >> -shift) : ((int64_t)value << shift)) * - 1000000 / ((int64_t)INT32_MAX + 1); + int32_t microgauss = + (shift < 0 ? ((int64_t)*value >> -shift) : ((int64_t)*value << shift)) * 1000000 / + ((int64_t)INT32_MAX + 1); int16_t reg_val = CLAMP(microgauss, AKM09918C_MAGN_MIN_MICRO_GAUSS, AKM09918C_MAGN_MAX_MICRO_GAUSS) / diff --git a/drivers/sensor/amd_sb_tsi/sb_tsi_emul.c b/drivers/sensor/amd_sb_tsi/sb_tsi_emul.c index fee197f1d90..1c12942c876 100644 --- a/drivers/sensor/amd_sb_tsi/sb_tsi_emul.c +++ b/drivers/sensor/amd_sb_tsi/sb_tsi_emul.c @@ -100,7 +100,7 @@ static int sb_tsi_emul_init(const struct emul *target, const struct device *pare } static int sb_tsi_emul_set_channel(const struct emul *target, enum sensor_channel chan, - q31_t value, int8_t shift) + const q31_t *value, int8_t shift) { struct sb_tsi_emul_data *data = target->data; int64_t scaled_value; @@ -111,7 +111,7 @@ static int sb_tsi_emul_set_channel(const struct emul *target, enum sensor_channe return -ENOTSUP; } - scaled_value = (int64_t)value << shift; + scaled_value = (int64_t)*value << shift; millicelsius = scaled_value * 1000 / ((int64_t)INT32_MAX + 1); reg_value = CLAMP(millicelsius / 125, 0, 0x7ff); diff --git a/drivers/sensor/bmi160/emul_bmi160.c b/drivers/sensor/bmi160/emul_bmi160.c index 3870346cd30..50530eae9dd 100644 --- a/drivers/sensor/bmi160/emul_bmi160.c +++ b/drivers/sensor/bmi160/emul_bmi160.c @@ -17,10 +17,12 @@ LOG_MODULE_REGISTER(bosch_bmi160); #include #include #include +#include #include #include #include #include +#include /** Run-time data used by the emulator */ struct bmi160_emul_data { @@ -42,25 +44,18 @@ struct bmi160_emul_cfg { }; /* Names for the PMU components */ -static const char *const pmu_name[] = { "acc", "gyr", "mag", "INV" }; +static const char *const pmu_name[] = {"acc", "gyr", "mag", "INV"}; -static void sample_read(union bmi160_sample *buf) +int emul_bmi160_get_reg_value(const struct emul *target, int reg_number, uint8_t *out, size_t count) { - /* - * Use hard-coded scales to get values just above 0, 1, 2 and - * 3, 4, 5. Values are stored in little endianness. - * gyr[x] = 0x0b01 // 3 * 1000000 / BMI160_GYR_SCALE(2000) + 1 - * gyr[y] = 0x0eac // 4 * 1000000 / BMI160_GYR_SCALE(2000) + 1 - * gyr[z] = 0x1257 // 5 * 1000000 / BMI160_GYR_SCALE(2000) + 1 - * acc[x] = 0x0001 // 0 * 1000000 / BMI160_ACC_SCALE(2) + 1 - * acc[y] = 0x0689 // 1 * 1000000 / BMI160_ACC_SCALE(2) + 1 - * acc[z] = 0x0d11 // 2 * 1000000 / BMI160_ACC_SCALE(2) + 1 - */ - static uint8_t raw_data[] = { 0x01, 0x0b, 0xac, 0x0e, 0x57, 0x12, - 0x01, 0x00, 0x89, 0x06, 0x11, 0x0d }; - - LOG_INF("Sample read"); - memcpy(buf->raw, raw_data, ARRAY_SIZE(raw_data)); + const struct bmi160_emul_cfg *cfg = target->cfg; + + if (reg_number < 0 || reg_number + count > BMI160_REG_COUNT) { + return -EINVAL; + } + + memcpy(out, cfg->reg + reg_number, count); + return 0; } static void reg_write(const struct emul *target, int regn, int val) @@ -68,25 +63,25 @@ static void reg_write(const struct emul *target, int regn, int val) struct bmi160_emul_data *data = target->data; const struct bmi160_emul_cfg *cfg = target->cfg; - LOG_INF("write %x = %x", regn, val); + LOG_DBG("write %x = %x", regn, val); cfg->reg[regn] = val; switch (regn) { case BMI160_REG_ACC_CONF: - LOG_INF(" * acc conf"); + LOG_DBG(" * acc conf"); break; case BMI160_REG_ACC_RANGE: - LOG_INF(" * acc range"); + LOG_DBG(" * acc range"); break; case BMI160_REG_GYR_CONF: - LOG_INF(" * gyr conf"); + LOG_DBG(" * gyr conf"); break; case BMI160_REG_GYR_RANGE: - LOG_INF(" * gyr range"); + LOG_DBG(" * gyr range"); break; case BMI160_REG_CMD: switch (val) { case BMI160_CMD_SOFT_RESET: - LOG_INF(" * soft reset"); + LOG_DBG(" * soft reset"); break; default: if ((val & BMI160_CMD_PMU_BIT) == BMI160_CMD_PMU_BIT) { @@ -108,16 +103,16 @@ static void reg_write(const struct emul *target, int regn, int val) } data->pmu_status &= 3 << shift; data->pmu_status |= pmu_val << shift; - LOG_INF(" * pmu %s = %x, new status %x", pmu_name[which], pmu_val, + LOG_DBG(" * pmu %s = %x, new status %x", pmu_name[which], pmu_val, data->pmu_status); } else { - LOG_INF("Unknown command %x", val); + LOG_DBG("Unknown command %x", val); } break; } break; default: - LOG_INF("Unknown write %x", regn); + LOG_DBG("Unknown write %x", regn); } } @@ -127,39 +122,39 @@ static int reg_read(const struct emul *target, int regn) const struct bmi160_emul_cfg *cfg = target->cfg; int val; - LOG_INF("read %x =", regn); + LOG_DBG("read %x =", regn); val = cfg->reg[regn]; switch (regn) { case BMI160_REG_CHIPID: - LOG_INF(" * get chipid"); + LOG_DBG(" * get chipid"); break; case BMI160_REG_PMU_STATUS: - LOG_INF(" * get pmu"); + LOG_DBG(" * get pmu"); val = data->pmu_status; break; case BMI160_REG_STATUS: - LOG_INF(" * status"); + LOG_DBG(" * status"); val |= BMI160_DATA_READY_BIT_MASK; break; case BMI160_REG_ACC_CONF: - LOG_INF(" * acc conf"); + LOG_DBG(" * acc conf"); break; case BMI160_REG_GYR_CONF: - LOG_INF(" * gyr conf"); + LOG_DBG(" * gyr conf"); break; case BMI160_SPI_START: - LOG_INF(" * Bus start"); + LOG_DBG(" * Bus start"); break; case BMI160_REG_ACC_RANGE: - LOG_INF(" * acc range"); + LOG_DBG(" * acc range"); break; case BMI160_REG_GYR_RANGE: - LOG_INF(" * gyr range"); + LOG_DBG(" * gyr range"); break; default: - LOG_INF("Unknown read %x", regn); + LOG_DBG("Unknown read %x", regn); } - LOG_INF(" = %x", val); + LOG_DBG(" = %x", val); return val; } @@ -206,23 +201,26 @@ static int bmi160_emul_io_spi(const struct emul *target, const struct spi_config break; case BMI160_SAMPLE_SIZE: if (regn & BMI160_REG_READ) { - sample_read(rxd->buf); + for (int i = 0; i < BMI160_SAMPLE_SIZE; ++i) { + ((uint8_t *)rxd->buf)[i] = reg_read( + target, (regn & BMI160_REG_MASK) + i); + } } else { - LOG_INF("Unknown sample write"); + LOG_DBG("Unknown sample write"); } break; default: - LOG_INF("Unknown A txd->len %d", txd->len); + LOG_DBG("Unknown A txd->len %d", txd->len); break; } break; default: - LOG_INF("Unknown tx->len %d", tx->len); + LOG_DBG("Unknown tx->len %d", tx->len); break; } break; default: - LOG_INF("Unknown tx_bufs->count %d", count); + LOG_DBG("Unknown tx_bufs->count %d", count); break; } @@ -235,7 +233,6 @@ static int bmi160_emul_transfer_i2c(const struct emul *target, struct i2c_msg *m int addr) { struct bmi160_emul_data *data; - unsigned int val; data = target->data; @@ -257,17 +254,8 @@ static int bmi160_emul_transfer_i2c(const struct emul *target, struct i2c_msg *m /* Now process the 'read' part of the message */ msgs++; if (msgs->flags & I2C_MSG_READ) { - switch (msgs->len) { - case 1: - val = reg_read(target, data->cur_reg); - msgs->buf[0] = val; - break; - case BMI160_SAMPLE_SIZE: - sample_read((void *)msgs->buf); - break; - default: - LOG_ERR("Unexpected msg1 length %d", msgs->len); - return -EIO; + for (int i = 0; i < msgs->len; ++i) { + msgs->buf[i] = reg_read(target, data->cur_reg + i); } } else { if (msgs->len != 1) { @@ -299,6 +287,304 @@ static struct i2c_emul_api bmi160_emul_api_i2c = { }; #endif +static int bmi160_emul_backend_set_channel(const struct emul *target, enum sensor_channel ch, + const q31_t *value, int8_t shift) +{ + const struct bmi160_emul_cfg *cfg = target->cfg; + int64_t intermediate = *value; + q31_t scale; + int8_t scale_shift = 0; + int reg_lsb; + + switch (ch) { + case SENSOR_CHAN_ACCEL_X: + case SENSOR_CHAN_ACCEL_Y: + case SENSOR_CHAN_ACCEL_Z: + reg_lsb = BMI160_REG_DATA_ACC_X + (ch - SENSOR_CHAN_ACCEL_X) * 2; + scale = 0x4e7404ea; + + switch (FIELD_GET(GENMASK(3, 0), cfg->reg[BMI160_REG_ACC_RANGE])) { + case BMI160_ACC_RANGE_4G: + scale_shift = 6; + break; + case BMI160_ACC_RANGE_8G: + scale_shift = 7; + break; + case BMI160_ACC_RANGE_16G: + scale_shift = 8; + break; + default: + scale_shift = 5; + break; + } + break; + case SENSOR_CHAN_GYRO_X: + case SENSOR_CHAN_GYRO_Y: + case SENSOR_CHAN_GYRO_Z: + reg_lsb = BMI160_REG_DATA_GYR_X + (ch - SENSOR_CHAN_GYRO_X) * 2; + scale = 0x45d02bea; + + switch (FIELD_GET(GENMASK(2, 0), cfg->reg[BMI160_REG_GYR_RANGE])) { + case BMI160_GYR_RANGE_2000DPS: + scale_shift = 6; + break; + case BMI160_GYR_RANGE_1000DPS: + scale_shift = 5; + break; + case BMI160_GYR_RANGE_500DPS: + scale_shift = 4; + break; + case BMI160_GYR_RANGE_250DPS: + scale_shift = 3; + break; + case BMI160_GYR_RANGE_125DPS: + scale_shift = 2; + break; + default: + return -EINVAL; + } + break; + case SENSOR_CHAN_DIE_TEMP: + reg_lsb = BMI160_REG_TEMPERATURE0; + scale = 0x8000; + scale_shift = 7; + break; + default: + return -EINVAL; + } + + if (shift < scale_shift) { + /* Original value doesn't have enough int bits, fix it */ + intermediate >>= scale_shift - shift; + } else if (shift > 0 && shift > scale_shift) { + /* Original value might be out-of-bounds, fix it (we're going to lose precision) */ + intermediate <<= shift - scale_shift; + } + + if (ch == SENSOR_CHAN_DIE_TEMP) { + /* Need to subtract 23C */ + intermediate -= INT64_C(23) << (31 - scale_shift); + } + + intermediate = + CLAMP(DIV_ROUND_CLOSEST(intermediate * INT16_MAX, scale), INT16_MIN, INT16_MAX); + + cfg->reg[reg_lsb] = FIELD_GET(GENMASK64(7, 0), intermediate); + cfg->reg[reg_lsb + 1] = FIELD_GET(GENMASK64(15, 8), intermediate); + return 0; +} + +static int bmi160_emul_backend_get_sample_range(const struct emul *target, enum sensor_channel ch, + q31_t *lower, q31_t *upper, q31_t *epsilon, + int8_t *shift) +{ + const struct bmi160_emul_cfg *cfg = target->cfg; + + switch (ch) { + case SENSOR_CHAN_ACCEL_X: + case SENSOR_CHAN_ACCEL_Y: + case SENSOR_CHAN_ACCEL_Z: + case SENSOR_CHAN_ACCEL_XYZ: { + uint8_t acc_range = cfg->reg[BMI160_REG_ACC_RANGE]; + + switch (acc_range) { + case BMI160_ACC_RANGE_2G: + *shift = 5; + break; + case BMI160_ACC_RANGE_4G: + *shift = 6; + break; + case BMI160_ACC_RANGE_8G: + *shift = 7; + break; + case BMI160_ACC_RANGE_16G: + *shift = 8; + break; + default: + return -EINVAL; + } + int64_t intermediate = ((int64_t)(2 * 9.80665 * INT32_MAX)) >> 5; + + *upper = intermediate; + *lower = -(*upper); + *epsilon = intermediate * 2 / (1 << (16 - *shift)); + return 0; + } + case SENSOR_CHAN_GYRO_X: + case SENSOR_CHAN_GYRO_Y: + case SENSOR_CHAN_GYRO_Z: + case SENSOR_CHAN_GYRO_XYZ: { + uint8_t gyro_range = cfg->reg[BMI160_REG_GYR_RANGE]; + + switch (gyro_range) { + case BMI160_GYR_RANGE_125DPS: + *shift = 2; + break; + case BMI160_GYR_RANGE_250DPS: + *shift = 3; + break; + case BMI160_GYR_RANGE_500DPS: + *shift = 4; + break; + case BMI160_GYR_RANGE_1000DPS: + *shift = 5; + break; + case BMI160_GYR_RANGE_2000DPS: + *shift = 6; + break; + default: + return -EINVAL; + } + + int64_t intermediate = (int64_t)(125 * 3.141592654 * INT32_MAX / 180) >> 2; + + *upper = intermediate; + *lower = -(*upper); + *epsilon = intermediate * 2 / (1 << (16 - *shift)); + return 0; + } + default: + return -EINVAL; + } + +} + +static int bmi160_emul_backend_set_offset(const struct emul *target, enum sensor_channel ch, + const q31_t *values, int8_t shift) +{ + if (ch != SENSOR_CHAN_ACCEL_XYZ && ch != SENSOR_CHAN_GYRO_XYZ) { + return -EINVAL; + } + + const struct bmi160_emul_cfg *cfg = target->cfg; + q31_t scale; + int8_t scale_shift = 0; + + if (values[0] == 0 && values[1] == 0 && values[2] == 0) { + if (ch == SENSOR_CHAN_ACCEL_XYZ) { + cfg->reg[BMI160_REG_OFFSET_EN] &= ~BIT(BMI160_ACC_OFS_EN_POS); + } else { + cfg->reg[BMI160_REG_OFFSET_EN] &= ~BIT(BMI160_GYR_OFS_EN_POS); + } + } else { + if (ch == SENSOR_CHAN_ACCEL_XYZ) { + cfg->reg[BMI160_REG_OFFSET_EN] |= BIT(BMI160_ACC_OFS_EN_POS); + } else { + cfg->reg[BMI160_REG_OFFSET_EN] |= BIT(BMI160_GYR_OFS_EN_POS); + } + } + + if (ch == SENSOR_CHAN_ACCEL_XYZ) { + /* + * bits = (values[i]mps2 / 9.80665g/mps2) / 0.0039g + * = values[i] / 0.038245935mps2/bit + * 0.038245935 in Q31 format is 0x4e53e28 with shift 0 + */ + scale = 0x4e53e28; + } else { + /* + * bits = (values[i]rad/s * 180 / pi) / 0.061deg/s + * = values[i] / 0.001064651rad/s + */ + scale = 0x22e2f0; + } + + for (int i = 0; i < 3; ++i) { + int64_t intermediate = values[i]; + + if (shift > scale_shift) { + /* Input uses a bigger scale, we need to increase its value to match */ + intermediate <<= (shift - scale_shift); + } else if (shift < scale_shift) { + /* Scale uses a bigger shift, we need to decrease its value to match */ + scale >>= (scale_shift - shift); + } + + int64_t reg_value = intermediate / scale; + + __ASSERT_NO_MSG(ch != SENSOR_CHAN_ACCEL_XYZ || + (reg_value >= INT8_MIN && reg_value <= INT8_MAX)); + __ASSERT_NO_MSG(ch != SENSOR_CHAN_GYRO_XYZ || + (reg_value >= -0x1ff - 1 && reg_value <= 0x1ff)); + if (ch == SENSOR_CHAN_ACCEL_XYZ) { + cfg->reg[BMI160_REG_OFFSET_ACC_X + i] = reg_value & 0xff; + } else { + cfg->reg[BMI160_REG_OFFSET_GYR_X + i] = reg_value & 0xff; + cfg->reg[BMI160_REG_OFFSET_EN] = + (cfg->reg[BMI160_REG_OFFSET_EN] & ~GENMASK(i * 2 + 1, i * 2)) | + (reg_value & GENMASK(9, 8)); + } + } + + return 0; +} + +static int bmi160_emul_backend_set_attribute(const struct emul *target, enum sensor_channel ch, + enum sensor_attribute attribute, const void *value) +{ + if (attribute == SENSOR_ATTR_OFFSET && + (ch == SENSOR_CHAN_ACCEL_XYZ || ch == SENSOR_CHAN_GYRO_XYZ)) { + const struct sensor_three_axis_attribute *attribute_value = value; + + return bmi160_emul_backend_set_offset(target, ch, attribute_value->values, + attribute_value->shift); + } + return -EINVAL; +} + +static int bmi160_emul_backend_get_attribute_metadata(const struct emul *target, + enum sensor_channel ch, + enum sensor_attribute attribute, q31_t *min, + q31_t *max, q31_t *increment, int8_t *shift) +{ + ARG_UNUSED(target); + switch (ch) { + case SENSOR_CHAN_ACCEL_X: + case SENSOR_CHAN_ACCEL_Y: + case SENSOR_CHAN_ACCEL_Z: + case SENSOR_CHAN_ACCEL_XYZ: + if (attribute == SENSOR_ATTR_OFFSET) { + /* Offset uses 3.9mg per bit in an 8 bit register: + * 0.0039g * 9.8065m/s2: yields the increment in SI units + * * INT8_MIN (or MAX) : yields the minimum (or maximum) values + * * INT32_MAX >> 3 : converts to q31 format within range [-8, 8] + */ + *min = (q31_t)((int64_t)(0.0039 * 9.8065 * INT8_MIN * INT32_MAX) >> 3); + *max = (q31_t)((int64_t)(0.0039 * 9.8065 * INT8_MAX * INT32_MAX) >> 3); + *increment = (q31_t)((int64_t)(0.0039 * 9.8065 * INT32_MAX) >> 3); + *shift = 3; + return 0; + } + return -EINVAL; + case SENSOR_CHAN_GYRO_X: + case SENSOR_CHAN_GYRO_Y: + case SENSOR_CHAN_GYRO_Z: + case SENSOR_CHAN_GYRO_XYZ: + if (attribute == SENSOR_ATTR_OFFSET) { + /* Offset uses 0.061deg/s per bit in an 10 bit register: + * 0.061deg/s * pi / 180: yields the increment in SI units + * * INT10_MIN (or MAX) : yields the minimum (or maximum) values + * * INT32_MAX : converts to q31 format within range [-1, 1] + */ + *min = (q31_t)(0.061 * 3.141593 / 180.0 * -512 * INT32_MAX); + *max = (q31_t)(0.061 * 3.141593 / 180.0 * 511 * INT32_MAX); + *increment = (q31_t)(0.061 * 3.141593 / 180.0 * INT32_MAX); + *shift = 0; + return 0; + } + return -EINVAL; + default: + return -EINVAL; + } +} + +static const struct emul_sensor_backend_api backend_api = { + .set_channel = bmi160_emul_backend_set_channel, + .get_sample_range = bmi160_emul_backend_get_sample_range, + .set_attribute = bmi160_emul_backend_set_attribute, + .get_attribute_metadata = bmi160_emul_backend_get_attribute_metadata, +}; + static int emul_bosch_bmi160_init(const struct emul *target, const struct device *parent) { const struct bmi160_emul_cfg *cfg = target->cfg; @@ -320,22 +606,19 @@ static int emul_bosch_bmi160_init(const struct emul *target, const struct device #define BMI160_EMUL_DEFINE(n, bus_api) \ EMUL_DT_INST_DEFINE(n, emul_bosch_bmi160_init, &bmi160_emul_data_##n, \ - &bmi160_emul_cfg_##n, &bus_api, NULL) + &bmi160_emul_cfg_##n, &bus_api, &backend_api) /* Instantiation macros used when a device is on a SPI bus */ #define BMI160_EMUL_SPI(n) \ BMI160_EMUL_DATA(n) \ - static const struct bmi160_emul_cfg bmi160_emul_cfg_##n = { \ - .reg = bmi160_emul_reg_##n, \ - .chipsel = \ - DT_INST_REG_ADDR(n) }; \ + static const struct bmi160_emul_cfg bmi160_emul_cfg_##n = { \ + .reg = bmi160_emul_reg_##n, .chipsel = DT_INST_REG_ADDR(n)}; \ BMI160_EMUL_DEFINE(n, bmi160_emul_api_spi) #define BMI160_EMUL_I2C(n) \ BMI160_EMUL_DATA(n) \ - static const struct bmi160_emul_cfg bmi160_emul_cfg_##n = { \ - .reg = bmi160_emul_reg_##n, \ - .addr = DT_INST_REG_ADDR(n) }; \ + static const struct bmi160_emul_cfg bmi160_emul_cfg_##n = {.reg = bmi160_emul_reg_##n, \ + .addr = DT_INST_REG_ADDR(n)}; \ BMI160_EMUL_DEFINE(n, bmi160_emul_api_i2c) /* diff --git a/drivers/sensor/bmi160/emul_bmi160.h b/drivers/sensor/bmi160/emul_bmi160.h new file mode 100644 index 00000000000..e16b089c461 --- /dev/null +++ b/drivers/sensor/bmi160/emul_bmi160.h @@ -0,0 +1,98 @@ +/* + * Copyright 2020 Google LLC + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#ifndef ZEPHYR_DRIVERS_SENSOR_BMI160_EMUL_BMI160_H_ +#define ZEPHYR_DRIVERS_SENSOR_BMI160_EMUL_BMI160_H_ + +#include +#include + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * @brief Check if I2C messages are touching a given register (R or W) + * + * @param[in] msgs The I2C messages in question + * @param[in] num_msgs The number of messages in the @p msgs array + * @param[in] reg The register to check for + * @return True if @p reg is either read or written to + * @return False otherwise + */ +__maybe_unused static bool emul_bmi160_i2c_is_touching_reg(struct i2c_msg *msgs, int num_msgs, + uint32_t reg) +{ + if (num_msgs != 2) { + return false; + } + if (msgs[0].len != 1) { + return false; + } + if (i2c_is_read_op(msgs)) { + return false; + } + + uint8_t start_reg = msgs[0].buf[0]; + uint8_t read_len = msgs[1].len; + + return (start_reg <= reg) && (reg < start_reg + read_len); +} + +/** + * @brief Check if I2C messages are reading a specific register. + * + * @param[in] msgs The I2C messages in question + * @param[in] num_msgs The number of messages in the @p msgs array + * @param[in] reg The register to check for + * @return True if @p reg is read + * @return False otherwise + */ +__maybe_unused static bool emul_bmi160_i2c_is_reading_reg(struct i2c_msg *msgs, int num_msgs, + uint32_t reg) +{ + if (!emul_bmi160_i2c_is_touching_reg(msgs, num_msgs, reg)) { + return false; + } + return i2c_is_read_op(&msgs[1]); +} + +/** + * @brief Check if I2C messages are writing to a specific register. + * + * @param[in] msgs The I2C messages in question + * @param[in] num_msgs The number of messages in the @p msgs array + * @param[in] reg The register to check for + * @return True if @p reg is written + * @return False otherwise + */ +__maybe_unused static bool emul_bmi160_i2c_is_writing_reg(struct i2c_msg *msgs, int num_msgs, + uint32_t reg) +{ + if (!emul_bmi160_i2c_is_touching_reg(msgs, num_msgs, reg)) { + return false; + } + return !i2c_is_read_op(&msgs[1]); +} + +/** + * @brief Get the internal register value of the emulator + * + * @param[in] target The emulator in question + * @param[in] reg_number The register number to start reading at + * @param[out] out Buffer to store the values into + * @param[in] count The number of registers to read + * @return 0 on success + * @return < 0 on error + */ +int emul_bmi160_get_reg_value(const struct emul *target, int reg_number, uint8_t *out, + size_t count); + +#ifdef __cplusplus +} +#endif + +#endif /* ZEPHYR_DRIVERS_SENSOR_BMI160_EMUL_BMI160_H_ */ diff --git a/drivers/sensor/f75303/f75303_emul.c b/drivers/sensor/f75303/f75303_emul.c index 3e33a7b6f7b..5bab9cd4294 100644 --- a/drivers/sensor/f75303/f75303_emul.c +++ b/drivers/sensor/f75303/f75303_emul.c @@ -104,7 +104,7 @@ static int f75303_emul_init(const struct emul *target, const struct device *pare } static int f75303_emul_set_channel(const struct emul *target, enum sensor_channel chan, - q31_t value, int8_t shift) + const q31_t *value, int8_t shift) { struct f75303_emul_data *data = target->data; int64_t scaled_value; @@ -129,7 +129,7 @@ static int f75303_emul_set_channel(const struct emul *target, enum sensor_channe return -ENOTSUP; } - scaled_value = (int64_t)value << shift; + scaled_value = (int64_t)*value << shift; millicelsius = scaled_value * 1000 / ((int64_t)INT32_MAX + 1); reg_value = CLAMP(millicelsius / 125, 0, 0x7ff); diff --git a/drivers/sensor/icm42688/icm42688_emul.c b/drivers/sensor/icm42688/icm42688_emul.c index e01b90742e3..732af64289b 100644 --- a/drivers/sensor/icm42688/icm42688_emul.c +++ b/drivers/sensor/icm42688/icm42688_emul.c @@ -329,7 +329,7 @@ static int icm42688_emul_backend_get_sample_range(const struct emul *target, enu } static int icm42688_emul_backend_set_channel(const struct emul *target, enum sensor_channel ch, - q31_t value, int8_t shift) + const q31_t *value, int8_t shift) { if (!target || !target->data) { return -EINVAL; @@ -341,7 +341,7 @@ static int icm42688_emul_backend_set_channel(const struct emul *target, enum sen uint8_t reg_addr; int32_t reg_val; int64_t value_unshifted = - shift < 0 ? ((int64_t)value >> -shift) : ((int64_t)value << shift); + shift < 0 ? ((int64_t)*value >> -shift) : ((int64_t)*value << shift); switch (ch) { case SENSOR_CHAN_DIE_TEMP: diff --git a/include/zephyr/drivers/emul.h b/include/zephyr/drivers/emul.h index 6dfb281e465..01297666dac 100644 --- a/include/zephyr/drivers/emul.h +++ b/include/zephyr/drivers/emul.h @@ -174,6 +174,18 @@ struct emul { */ #define EMUL_DT_GET(node_id) (&EMUL_DT_NAME_GET(node_id)) +/** + * @brief Utility macro to obtain an optional reference to an emulator + * + * If the node identifier referes to a node with status `okay`, this returns `EMUL_DT_GET(node_id)`. + * Otherwise, it returns `NULL`. + * + * @param node_id A devicetree node identifier + * @return a @ref emul reference for the node identifier, which may be `NULL`. + */ +#define EMUL_DT_GET_OR_NULL(node_id) \ + COND_CODE_1(DT_NODE_HAS_STATUS(node_id, okay), (EMUL_DT_GET(node_id)), (NULL)) + /** * @brief Set up a list of emulators * diff --git a/include/zephyr/drivers/emul_sensor.h b/include/zephyr/drivers/emul_sensor.h index 44a497ee401..30345cc6a0b 100644 --- a/include/zephyr/drivers/emul_sensor.h +++ b/include/zephyr/drivers/emul_sensor.h @@ -5,6 +5,7 @@ #include #include +#include #include @@ -26,11 +27,18 @@ */ __subsystem struct emul_sensor_backend_api { /** Sets a given fractional value for a given sensor channel. */ - int (*set_channel)(const struct emul *target, enum sensor_channel ch, q31_t value, + int (*set_channel)(const struct emul *target, enum sensor_channel ch, const q31_t *value, int8_t shift); /** Retrieve a range of sensor values to use with test. */ int (*get_sample_range)(const struct emul *target, enum sensor_channel ch, q31_t *lower, q31_t *upper, q31_t *epsilon, int8_t *shift); + /** Set the attribute value(s) of a given chanel. */ + int (*set_attribute)(const struct emul *target, enum sensor_channel ch, + enum sensor_attribute attribute, const void *value); + /** Get metadata about an attribute. */ + int (*get_attribute_metadata)(const struct emul *target, enum sensor_channel ch, + enum sensor_attribute attribute, q31_t *min, q31_t *max, + q31_t *increment, int8_t *shift); }; /** * @endcond @@ -61,7 +69,7 @@ static inline bool emul_sensor_backend_is_supported(const struct emul *target) * @return -ERANGE if provided value is not in the sensor's supported range */ static inline int emul_sensor_backend_set_channel(const struct emul *target, enum sensor_channel ch, - q31_t value, int8_t shift) + const q31_t *value, int8_t shift) { if (!target || !target->backend_api) { return -ENOTSUP; @@ -108,6 +116,68 @@ static inline int emul_sensor_backend_get_sample_range(const struct emul *target return -ENOTSUP; } +/** + * @brief Set the emulator's attribute values + * + * @param[in] target Pointer to emulator instance to operate on + * @param[in] ch The channel to request info for. If \p ch is unsupported, return `-ENOTSUP` + * @param[in] attribute The attribute to set + * @param[in] value the value to use (cast according to the channel/attribute pair) + * @return 0 is successful + * @return < 0 on error + */ +static inline int emul_sensor_backend_set_attribute(const struct emul *target, + enum sensor_channel ch, + enum sensor_attribute attribute, + const void *value) +{ + if (!target || !target->backend_api) { + return -ENOTSUP; + } + + struct emul_sensor_backend_api *api = (struct emul_sensor_backend_api *)target->backend_api; + + if (api->set_attribute == NULL) { + return -ENOTSUP; + } + return api->set_attribute(target, ch, attribute, value); +} + +/** + * @brief Get metadata about an attribute. + * + * Information provided by this function includes the minimum/maximum values of the attribute as + * well as the increment (value per LSB) which can be used as an epsilon when comparing results. + * + * @param[in] target Pointer to emulator instance to operate on + * @param[in] ch The channel to request info for. If \p ch is unsupported, return '-ENOTSUP' + * @param[in] attribute The attribute to request info for. If \p attribute is unsupported, return + * '-ENOTSUP' + * @param[out] min The minimum value the attribute can be set to + * @param[out] max The maximum value the attribute can be set to + * @param[out] increment The value that the attribute increses by for every LSB + * @param[out] shift The shift for \p min, \p max, and \p increment + * @return 0 on SUCCESS + * @return < 0 on error + */ +static inline int emul_sensor_backend_get_attribute_metadata(const struct emul *target, + enum sensor_channel ch, + enum sensor_attribute attribute, + q31_t *min, q31_t *max, + q31_t *increment, int8_t *shift) +{ + if (!target || !target->backend_api) { + return -ENOTSUP; + } + + struct emul_sensor_backend_api *api = (struct emul_sensor_backend_api *)target->backend_api; + + if (api->get_attribute_metadata == NULL) { + return -ENOTSUP; + } + return api->get_attribute_metadata(target, ch, attribute, min, max, increment, shift); +} + /** * @} */ diff --git a/include/zephyr/drivers/sensor_attribute_types.h b/include/zephyr/drivers/sensor_attribute_types.h new file mode 100644 index 00000000000..8ccb9dba110 --- /dev/null +++ b/include/zephyr/drivers/sensor_attribute_types.h @@ -0,0 +1,43 @@ +/* + * Copyright (c) 2023 Google LLC + * SPDX-License-Identifier: Apache-2.0 + */ + +#ifndef ZEPHYR_INCLUDE_DRIVERS_SENSOR_ATTRIBUTE_TYPES_H +#define ZEPHYR_INCLUDE_DRIVERS_SENSOR_ATTRIBUTE_TYPES_H + +#include +#include + +#include + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * Used by the following channel/attribute pairs: + * - SENSOR_CHAN_ACCEL_XYZ + * - SENSOR_ATTR_OFFSET + * - SENSOR_CHAN_GYRO_XYZ + * - SENSOR_ATTR_OFFSET + * - SENSOR_CHAN_MAGN_XYZ + * - SENSOR_ATTR_OFFSET + */ +struct sensor_three_axis_attribute { + int8_t shift; + union { + struct { + q31_t x; + q31_t y; + q31_t z; + }; + q31_t values[3]; + }; +}; + +#ifdef __cplusplus +} +#endif + +#endif /* ZEPHYR_INCLUDE_DRIVERS_SENSOR_ATTRIBUTE_TYPES_H */ diff --git a/tests/drivers/build_all/sensor/src/generic_test.c b/tests/drivers/build_all/sensor/src/generic_test.c index 9a1dc537535..2d5e0c1df86 100644 --- a/tests/drivers/build_all/sensor/src/generic_test.c +++ b/tests/drivers/build_all/sensor/src/generic_test.c @@ -158,7 +158,7 @@ static void run_generic_test(const struct device *dev) enum sensor_channel ch = iodev_all_channels[i]; rv = emul_sensor_backend_set_channel( - emul, ch, channel_table[ch].expected_values[iteration], + emul, ch, &channel_table[ch].expected_values[iteration], channel_table[ch].expected_value_shift); zassert_ok( rv, From 9898b2fc3ff18445c47e7261dd840133b05c0af8 Mon Sep 17 00:00:00 2001 From: Yuval Peress Date: Thu, 16 Nov 2023 01:30:27 -0700 Subject: [PATCH 2268/3723] bmi160: Make changes to align driver to datasheet The logic in the driver was not aligned to the datasheet. Also, temperature reading was not being done in fetch, but in channel_get. There was also some extra conversions from SI->register->SI when setting the range, this was causing the register value calculation to produce an incorrect scale in some cases. Tests were added to cover these cases. Signed-off-by: Yuval Peress --- drivers/sensor/bmi160/bmi160.c | 95 +++++++++++++----------- drivers/sensor/bmi160/bmi160.h | 9 +++ tests/drivers/sensor/accel/src/main.c | 101 +++++++++++++++++++++----- 3 files changed, 147 insertions(+), 58 deletions(-) diff --git a/drivers/sensor/bmi160/bmi160.c b/drivers/sensor/bmi160/bmi160.c index d79259c8ba2..3446e5c3fb5 100644 --- a/drivers/sensor/bmi160/bmi160.c +++ b/drivers/sensor/bmi160/bmi160.c @@ -251,7 +251,7 @@ struct { * SENSOR_ATTR_SAMPLING_FREQUENCY attribute. */ } bmi160_odr_map[] = { - {0, 0 }, {0, 780}, {1, 562}, {3, 120}, {6, 250}, + {0, 0 }, {0, 781}, {1, 562}, {3, 125}, {6, 250}, {12, 500}, {25, 0 }, {50, 0 }, {100, 0 }, {200, 0 }, {400, 0 }, {800, 0 }, {1600, 0 }, {3200, 0 }, }; @@ -281,21 +281,12 @@ static int bmi160_freq_to_odr_val(uint16_t freq_int, uint16_t freq_milli) static int bmi160_acc_odr_set(const struct device *dev, uint16_t freq_int, uint16_t freq_milli) { - struct bmi160_data *data = dev->data; int odr = bmi160_freq_to_odr_val(freq_int, freq_milli); if (odr < 0) { return odr; } - /* some odr values cannot be set in certain power modes */ - if ((data->pmu_sts.acc == BMI160_PMU_NORMAL && - odr < BMI160_ODR_25_2) || - (data->pmu_sts.acc == BMI160_PMU_LOW_POWER && - odr < BMI160_ODR_25_32) || odr > BMI160_ODR_1600) { - return -ENOTSUP; - } - return bmi160_reg_field_update(dev, BMI160_REG_ACC_CONF, BMI160_ACC_CONF_ODR_POS, BMI160_ACC_CONF_ODR_MASK, @@ -381,10 +372,11 @@ static int bmi160_do_calibration(const struct device *dev, uint8_t foc_conf) } #if defined(CONFIG_BMI160_ACCEL_RANGE_RUNTIME) -static int bmi160_acc_range_set(const struct device *dev, int32_t range) +static int bmi160_acc_range_set(const struct device *dev, const struct sensor_value *val) { + int32_t range_g = sensor_ms2_to_g(val); struct bmi160_data *data = dev->data; - int32_t reg_val = bmi160_range_to_reg_val(range, + int32_t reg_val = bmi160_range_to_reg_val(range_g, bmi160_acc_range_map, BMI160_ACC_RANGE_MAP_SIZE); @@ -392,12 +384,26 @@ static int bmi160_acc_range_set(const struct device *dev, int32_t range) return reg_val; } + switch (reg_val & 0xff) { + case BMI160_ACC_RANGE_2G: + range_g = 2; + break; + case BMI160_ACC_RANGE_4G: + range_g = 4; + break; + case BMI160_ACC_RANGE_8G: + range_g = 8; + break; + case BMI160_ACC_RANGE_16G: + range_g = 16; + break; + } + if (bmi160_byte_write(dev, BMI160_REG_ACC_RANGE, reg_val & 0xff) < 0) { return -EIO; } - data->scale.acc = BMI160_ACC_SCALE(range); - + data->scale.acc = BMI160_ACC_SCALE(range_g); return 0; } #endif @@ -418,8 +424,7 @@ static int bmi160_acc_ofs_set(const struct device *dev, BMI160_REG_OFFSET_ACC_Z }; int i; - int32_t ofs_u; - int8_t reg_val; + int32_t reg_val; /* we need the offsets for all axis */ if (chan != SENSOR_CHAN_ACCEL_XYZ) { @@ -428,8 +433,8 @@ static int bmi160_acc_ofs_set(const struct device *dev, for (i = 0; i < BMI160_AXES; i++, ofs++) { /* convert offset to micro m/s^2 */ - ofs_u = ofs->val1 * 1000000ULL + ofs->val2; - reg_val = ofs_u / BMI160_ACC_OFS_LSB; + reg_val = + CLAMP(sensor_value_to_micro(ofs) / BMI160_ACC_OFS_LSB, INT8_MIN, INT8_MAX); if (bmi160_byte_write(dev, reg_addr[i], reg_val) < 0) { return -EIO; @@ -502,7 +507,7 @@ static int bmi160_acc_config(const struct device *dev, switch (attr) { #if defined(CONFIG_BMI160_ACCEL_RANGE_RUNTIME) case SENSOR_ATTR_FULL_SCALE: - return bmi160_acc_range_set(dev, sensor_ms2_to_g(val)); + return bmi160_acc_range_set(dev, val); #endif #if defined(CONFIG_BMI160_ACCEL_ODR_RUNTIME) case SENSOR_ATTR_SAMPLING_FREQUENCY: @@ -548,8 +553,9 @@ static int bmi160_gyr_odr_set(const struct device *dev, uint16_t freq_int, #endif #if defined(CONFIG_BMI160_GYRO_RANGE_RUNTIME) -static int bmi160_gyr_range_set(const struct device *dev, uint16_t range) +static int bmi160_gyr_range_set(const struct device *dev, const struct sensor_value *val) { + uint16_t range = sensor_rad_to_degrees(val); struct bmi160_data *data = dev->data; int32_t reg_val = bmi160_range_to_reg_val(range, bmi160_gyr_range_map, @@ -558,6 +564,23 @@ static int bmi160_gyr_range_set(const struct device *dev, uint16_t range) if (reg_val < 0) { return reg_val; } + switch (reg_val) { + case BMI160_GYR_RANGE_125DPS: + range = 125; + break; + case BMI160_GYR_RANGE_250DPS: + range = 250; + break; + case BMI160_GYR_RANGE_500DPS: + range = 500; + break; + case BMI160_GYR_RANGE_1000DPS: + range = 1000; + break; + case BMI160_GYR_RANGE_2000DPS: + range = 2000; + break; + } if (bmi160_byte_write(dev, BMI160_REG_GYR_RANGE, reg_val) < 0) { return -EIO; @@ -600,15 +623,7 @@ static int bmi160_gyr_ofs_set(const struct device *dev, /* convert offset to micro rad/s */ ofs_u = ofs->val1 * 1000000ULL + ofs->val2; - val = ofs_u / BMI160_GYR_OFS_LSB; - - /* - * The gyro offset is a 10 bit two-complement value. Make sure - * the passed value is within limits. - */ - if (val < -512 || val > 512) { - return -EINVAL; - } + val = CLAMP(ofs_u / BMI160_GYR_OFS_LSB, -512, 511); /* write the LSB */ if (bmi160_byte_write(dev, ofs_desc[i].lsb_addr, @@ -661,7 +676,7 @@ static int bmi160_gyr_config(const struct device *dev, switch (attr) { #if defined(CONFIG_BMI160_GYRO_RANGE_RUNTIME) case SENSOR_ATTR_FULL_SCALE: - return bmi160_gyr_range_set(dev, sensor_rad_to_degrees(val)); + return bmi160_gyr_range_set(dev, val); #endif #if defined(CONFIG_BMI160_GYRO_ODR_RUNTIME) case SENSOR_ATTR_SAMPLING_FREQUENCY: @@ -725,6 +740,14 @@ static int bmi160_sample_fetch(const struct device *dev, goto out; } + if (chan == SENSOR_CHAN_DIE_TEMP) { + /* Die temperature is only valid when at least one measurement is active */ + if (data->pmu_sts.raw == 0U) { + return -EINVAL; + } + return bmi160_word_read(dev, BMI160_REG_TEMPERATURE0, &data->sample.temperature); + } + __ASSERT_NO_MSG(chan == SENSOR_CHAN_ALL); status = 0; @@ -826,20 +849,10 @@ static inline void bmi160_acc_channel_get(const struct device *dev, static int bmi160_temp_channel_get(const struct device *dev, struct sensor_value *val) { - uint16_t temp_raw = 0U; - int32_t temp_micro = 0; struct bmi160_data *data = dev->data; - if (data->pmu_sts.raw == 0U) { - return -EINVAL; - } - - if (bmi160_word_read(dev, BMI160_REG_TEMPERATURE0, &temp_raw) < 0) { - return -EIO; - } - /* the scale is 1/2^9/LSB = 1953 micro degrees */ - temp_micro = BMI160_TEMP_OFFSET * 1000000ULL + temp_raw * 1953ULL; + int32_t temp_micro = BMI160_TEMP_OFFSET * 1000000ULL + data->sample.temperature * 1953ULL; val->val1 = temp_micro / 1000000ULL; val->val2 = temp_micro % 1000000ULL; diff --git a/drivers/sensor/bmi160/bmi160.h b/drivers/sensor/bmi160/bmi160.h index 1399d88b76c..9b44f479fbb 100644 --- a/drivers/sensor/bmi160/bmi160.h +++ b/drivers/sensor/bmi160/bmi160.h @@ -17,6 +17,10 @@ #include #include +#ifdef __cplusplus +extern "C" { +#endif + /* registers */ #define BMI160_REG_CHIPID 0x00 #define BMI160_REG_ERR 0x02 @@ -467,6 +471,7 @@ union bmi160_pmu_status { /* Each sample has X, Y and Z */ union bmi160_sample { uint8_t raw[BMI160_BUF_SIZE]; + uint16_t temperature; struct { #if !defined(CONFIG_BMI160_GYRO_PMU_SUSPEND) uint16_t gyr[BMI160_AXES]; @@ -541,4 +546,8 @@ int bmi160_acc_slope_config(const struct device *dev, int32_t bmi160_acc_reg_val_to_range(uint8_t reg_val); int32_t bmi160_gyr_reg_val_to_range(uint8_t reg_val); +#ifdef __cplusplus +} +#endif + #endif /* ZEPHYR_DRIVERS_SENSOR_BMI160_BMI160_H_ */ diff --git a/tests/drivers/sensor/accel/src/main.c b/tests/drivers/sensor/accel/src/main.c index 0ba03f4b6bf..f1c680b6ba2 100644 --- a/tests/drivers/sensor/accel/src/main.c +++ b/tests/drivers/sensor/accel/src/main.c @@ -11,35 +11,66 @@ * @} */ -#include +#include +#include #include +#include struct sensor_accel_fixture { const struct device *accel_spi; const struct device *accel_i2c; + const struct emul *accel_emul_spi; + const struct emul *accel_emul_i2c; }; static enum sensor_channel channel[] = { - SENSOR_CHAN_ACCEL_X, - SENSOR_CHAN_ACCEL_Y, - SENSOR_CHAN_ACCEL_Z, - SENSOR_CHAN_GYRO_X, - SENSOR_CHAN_GYRO_Y, - SENSOR_CHAN_GYRO_Z, + SENSOR_CHAN_ACCEL_X, SENSOR_CHAN_ACCEL_Y, SENSOR_CHAN_ACCEL_Z, + SENSOR_CHAN_GYRO_X, SENSOR_CHAN_GYRO_Y, SENSOR_CHAN_GYRO_Z, }; -static void test_sensor_accel_basic(const struct device *dev) +static int32_t compute_epsilon_micro(q31_t value, int8_t shift) { - zassert_equal(sensor_sample_fetch(dev), 0, "fail to fetch sample"); + int64_t intermediate = value; + + if (shift > 0) { + intermediate <<= shift; + } else if (shift < 0) { + intermediate >>= -shift; + } + + intermediate = intermediate * INT64_C(1000000) / INT32_MAX; + return CLAMP(intermediate, INT32_MIN, INT32_MAX); +} + +static void test_sensor_accel_basic(const struct device *dev, const struct emul *emulator) +{ + q31_t accel_ranges[3]; + q31_t gyro_ranges[3]; + int8_t accel_shift; + int8_t gyro_shift; + + zassert_ok(sensor_sample_fetch(dev), "fail to fetch sample"); + zassert_ok(emul_sensor_backend_get_sample_range(emulator, SENSOR_CHAN_ACCEL_XYZ, + &accel_ranges[0], &accel_ranges[1], + &accel_ranges[2], &accel_shift)); + zassert_ok(emul_sensor_backend_get_sample_range(emulator, SENSOR_CHAN_GYRO_XYZ, + &gyro_ranges[0], &gyro_ranges[1], + &gyro_ranges[2], &gyro_shift)); + + int32_t accel_epsilon = compute_epsilon_micro(accel_ranges[2], accel_shift); + int32_t gyro_epsilon = compute_epsilon_micro(gyro_ranges[2], gyro_shift); for (int i = 0; i < ARRAY_SIZE(channel); i++) { struct sensor_value val; + int64_t micro_val; + int32_t epsilon = (i < 3) ? accel_epsilon : gyro_epsilon; + + zassert_ok(sensor_channel_get(dev, channel[i], &val), "fail to get channel"); - zassert_ok(sensor_channel_get(dev, channel[i], &val), - "fail to get channel"); - zassert_equal(i, val.val1, "expected %d, got %d", i, val.val1); - zassert_true(val.val2 < 1000, "error %d is too large", - val.val2); + micro_val = sensor_value_to_micro(&val); + zassert_within(i * INT64_C(1000000), micro_val, epsilon, + "%d. expected %" PRIi64 " to be within %d of %" PRIi64, i, + i * INT64_C(1000000), epsilon, micro_val); } } @@ -55,10 +86,9 @@ static void run_tests_on_accel(const struct device *accel) ZTEST_USER_F(sensor_accel, test_sensor_accel_basic_spi) { run_tests_on_accel(fixture->accel_spi); - test_sensor_accel_basic(fixture->accel_spi); + test_sensor_accel_basic(fixture->accel_spi, fixture->accel_emul_spi); } - ZTEST_USER_F(sensor_accel, test_sensor_accel_basic_i2c) { if (fixture->accel_i2c == NULL) { @@ -66,7 +96,39 @@ ZTEST_USER_F(sensor_accel, test_sensor_accel_basic_i2c) } run_tests_on_accel(fixture->accel_i2c); - test_sensor_accel_basic(fixture->accel_i2c); + test_sensor_accel_basic(fixture->accel_i2c, fixture->accel_emul_i2c); +} + +static void sensor_accel_setup_emulator(const struct device *dev, const struct emul *accel_emul) +{ + if (accel_emul == NULL) { + return; + } + + static struct { + enum sensor_channel channel; + q31_t value; + } values[] = { + {SENSOR_CHAN_ACCEL_X, 0}, {SENSOR_CHAN_ACCEL_Y, 1 << 28}, + {SENSOR_CHAN_ACCEL_Z, 2 << 28}, {SENSOR_CHAN_GYRO_X, 3 << 28}, + {SENSOR_CHAN_GYRO_Y, 4 << 28}, {SENSOR_CHAN_GYRO_Z, 5 << 28}, + }; + static struct sensor_value scale; + + /* 4g */ + scale.val1 = 39; + scale.val2 = 226600; + zassert_ok(sensor_attr_set(dev, SENSOR_CHAN_ACCEL_XYZ, SENSOR_ATTR_FULL_SCALE, &scale)); + + /* 125 deg/s */ + scale.val1 = 2; + scale.val2 = 181661; + zassert_ok(sensor_attr_set(dev, SENSOR_CHAN_GYRO_XYZ, SENSOR_ATTR_FULL_SCALE, &scale)); + + for (int i = 0; i < ARRAY_SIZE(values); ++i) { + zassert_ok(emul_sensor_backend_set_channel(accel_emul, values[i].channel, + &values[i].value, 3)); + } } static void *sensor_accel_setup(void) @@ -74,8 +136,13 @@ static void *sensor_accel_setup(void) static struct sensor_accel_fixture fixture = { .accel_spi = DEVICE_DT_GET(DT_ALIAS(accel_0)), .accel_i2c = DEVICE_DT_GET_OR_NULL(DT_ALIAS(accel_1)), + .accel_emul_spi = EMUL_DT_GET(DT_ALIAS(accel_0)), + .accel_emul_i2c = EMUL_DT_GET_OR_NULL(DT_ALIAS(accel_1)), }; + sensor_accel_setup_emulator(fixture.accel_spi, fixture.accel_emul_spi); + sensor_accel_setup_emulator(fixture.accel_i2c, fixture.accel_emul_i2c); + return &fixture; } From fd07f8ce6942108892195400f9bed6218151b7cc Mon Sep 17 00:00:00 2001 From: Yuval Peress Date: Fri, 17 Nov 2023 09:35:35 -0700 Subject: [PATCH 2269/3723] bmi160: Implement attr_get Add support for getting the following attribute values: - SENSOR_ATTR_OFFSET - SENSOR_ATTR_SAMPLING_FREQUENCY - SENSOR_ATTR_FULL_SCALE Signed-off-by: Yuval Peress --- drivers/sensor/bmi160/bmi160.c | 123 +++++++++++++++++++++++++++++++++ 1 file changed, 123 insertions(+) diff --git a/drivers/sensor/bmi160/bmi160.c b/drivers/sensor/bmi160/bmi160.c index 3446e5c3fb5..90ce8d8b58e 100644 --- a/drivers/sensor/bmi160/bmi160.c +++ b/drivers/sensor/bmi160/bmi160.c @@ -724,6 +724,128 @@ static int bmi160_attr_set(const struct device *dev, enum sensor_channel chan, return 0; } +static int bmi160_attr_get(const struct device *dev, enum sensor_channel chan, + enum sensor_attribute attr, struct sensor_value *val) +{ + int rc; + + if (attr == SENSOR_ATTR_OFFSET) { + if (chan != SENSOR_CHAN_ACCEL_XYZ && chan != SENSOR_CHAN_GYRO_XYZ) { + return -EINVAL; + } + + int8_t data[7]; + + rc = bmi160_read(dev, BMI160_REG_OFFSET_ACC_X, data, 7); + if (rc != 0) { + return rc; + } + + if ((chan == SENSOR_CHAN_ACCEL_XYZ && + FIELD_GET(BIT(BMI160_ACC_OFS_EN_POS), data[6]) == 0) || + (chan == SENSOR_CHAN_GYRO_XYZ && + FIELD_GET(BIT(BMI160_GYR_OFS_EN_POS), data[6]) == 0)) { + for (int i = 0; i < 3; ++i) { + val[i].val1 = 0; + val[i].val2 = 0; + } + } else { + for (int i = 0; i < 3; ++i) { + if (chan == SENSOR_CHAN_ACCEL_XYZ) { + int32_t ug = data[i] * INT32_C(3900); + + sensor_ug_to_ms2(ug, &val[i]); + } else { + int32_t udeg = + (FIELD_GET(GENMASK((2 * i) + 1, 2 * i), data[6]) + << 8) | + data[3 + i]; + + udeg |= 0 - (udeg & 0x200); + udeg *= 61000; + sensor_10udegrees_to_rad(udeg / 10, &val[i]); + } + } + } + return 0; + } + if (attr == SENSOR_ATTR_SAMPLING_FREQUENCY) { + if (chan == SENSOR_CHAN_ACCEL_XYZ) { + int64_t rate_uhz; + uint8_t acc_odr; + + if (IS_ENABLED(CONFIG_BMI160_ACCEL_ODR_RUNTIME)) { + /* Read the register */ + rc = bmi160_byte_read(dev, BMI160_REG_ACC_CONF, &acc_odr); + if (rc != 0) { + return rc; + } + acc_odr = FIELD_GET(BMI160_ACC_CONF_ODR_MASK, acc_odr); + } else { + acc_odr = BMI160_DEFAULT_ODR_ACC; + } + + rate_uhz = INT64_C(100000000) * BIT(acc_odr) / 256; + val->val1 = rate_uhz / 1000000; + val->val2 = rate_uhz - val->val1 * 1000000; + return 0; + } else if (chan == SENSOR_CHAN_GYRO_XYZ) { + int64_t rate_uhz; + uint8_t gyr_ord; + + if (IS_ENABLED(CONFIG_BMI160_GYRO_ODR_RUNTIME)) { + /* Read the register */ + rc = bmi160_byte_read(dev, BMI160_REG_GYR_CONF, &gyr_ord); + if (rc != 0) { + return rc; + } + gyr_ord = FIELD_GET(BMI160_GYR_CONF_ODR_MASK, gyr_ord); + } else { + gyr_ord = BMI160_DEFAULT_ODR_GYR; + } + + rate_uhz = INT64_C(100000000) * BIT(gyr_ord) / 256; + val->val1 = rate_uhz / 1000000; + val->val2 = rate_uhz - val->val1 * 1000000; + return 0; + + } + return -EINVAL; + + } + if (attr == SENSOR_ATTR_FULL_SCALE) { + if (chan == SENSOR_CHAN_ACCEL_XYZ) { + uint8_t acc_range; + + if (IS_ENABLED(CONFIG_BMI160_ACCEL_RANGE_RUNTIME)) { + rc = bmi160_byte_read(dev, BMI160_REG_ACC_RANGE, &acc_range); + if (rc != 0) { + return rc; + } + } else { + acc_range = BMI160_DEFAULT_RANGE_ACC; + } + sensor_g_to_ms2(bmi160_acc_reg_val_to_range(acc_range), val); + return 0; + } else if (chan == SENSOR_CHAN_GYRO_XYZ) { + uint8_t gyr_range; + + if (IS_ENABLED(CONFIG_BMI160_GYRO_RANGE_RUNTIME)) { + rc = bmi160_byte_read(dev, BMI160_REG_GYR_RANGE, &gyr_range); + if (rc != 0) { + return rc; + } + } else { + gyr_range = BMI160_DEFAULT_RANGE_GYR; + } + sensor_degrees_to_rad(bmi160_gyr_reg_val_to_range(gyr_range), val); + return 0; + } + return -EINVAL; + } + return -EINVAL; +} + static int bmi160_sample_fetch(const struct device *dev, enum sensor_channel chan) { @@ -893,6 +1015,7 @@ static int bmi160_channel_get(const struct device *dev, static const struct sensor_driver_api bmi160_api = { .attr_set = bmi160_attr_set, + .attr_get = bmi160_attr_get, #ifdef CONFIG_BMI160_TRIGGER .trigger_set = bmi160_trigger_set, #endif From b58b03196b22f649c741484c1a3e42a882712a64 Mon Sep 17 00:00:00 2001 From: Yuval Peress Date: Fri, 17 Nov 2023 09:38:54 -0700 Subject: [PATCH 2270/3723] bus: emul: Update i2c/spi emulators with mock transport Adding a hook for tests to inject a mock transport and migrating the accel test to test bmi160 specific things. The old version of the test which checks for read values is now covered by the generic test in the sensor build_all target. Signed-off-by: Yuval Peress --- drivers/i2c/i2c_emul.c | 12 +- drivers/sensor/bmi160/emul_bmi160.c | 81 +++++----- drivers/spi/spi_emul.c | 8 + include/zephyr/drivers/i2c.h | 12 ++ include/zephyr/drivers/i2c_emul.h | 7 + include/zephyr/drivers/spi_emul.h | 6 + tests/drivers/sensor/accel/CMakeLists.txt | 11 +- tests/drivers/sensor/accel/include/checks.h | 36 +++++ tests/drivers/sensor/accel/include/fixture.h | 20 +++ tests/drivers/sensor/accel/src/fixture.c | 69 +++++++++ tests/drivers/sensor/accel/src/i2c.c | 52 +++++++ tests/drivers/sensor/accel/src/main.c | 149 ------------------- tests/drivers/sensor/accel/src/spi.c | 52 +++++++ 13 files changed, 314 insertions(+), 201 deletions(-) create mode 100644 tests/drivers/sensor/accel/include/checks.h create mode 100644 tests/drivers/sensor/accel/include/fixture.h create mode 100644 tests/drivers/sensor/accel/src/fixture.c create mode 100644 tests/drivers/sensor/accel/src/i2c.c delete mode 100644 tests/drivers/sensor/accel/src/main.c create mode 100644 tests/drivers/sensor/accel/src/spi.c diff --git a/drivers/i2c/i2c_emul.c b/drivers/i2c/i2c_emul.c index 4324f6792c6..63488da8cfd 100644 --- a/drivers/i2c/i2c_emul.c +++ b/drivers/i2c/i2c_emul.c @@ -90,12 +90,14 @@ static int i2c_emul_transfer(const struct device *dev, struct i2c_msg *msgs, uin __ASSERT_NO_MSG(emul->api); __ASSERT_NO_MSG(emul->api->transfer); - ret = api->transfer(emul->target, msgs, num_msgs, addr); - if (ret) { - return ret; + if (emul->mock_api != NULL && emul->mock_api->transfer != NULL) { + ret = emul->mock_api->transfer(emul->target, msgs, num_msgs, addr); + if (ret != -ENOSYS) { + return ret; + } } - return 0; + return api->transfer(emul->target, msgs, num_msgs, addr); } /** @@ -125,7 +127,7 @@ int i2c_emul_register(const struct device *dev, struct i2c_emul *emul) sys_slist_append(&data->emuls, &emul->node); - LOG_INF("Register emulator '%s' at I2C addr %02x\n", name, emul->addr); + LOG_INF("Register emulator '%s' at I2C addr %02x", name, emul->addr); return 0; } diff --git a/drivers/sensor/bmi160/emul_bmi160.c b/drivers/sensor/bmi160/emul_bmi160.c index 50530eae9dd..3ed71790fbe 100644 --- a/drivers/sensor/bmi160/emul_bmi160.c +++ b/drivers/sensor/bmi160/emul_bmi160.c @@ -176,52 +176,44 @@ static int bmi160_emul_io_spi(const struct emul *target, const struct spi_config __ASSERT_NO_MSG(!tx_bufs || !rx_bufs || tx_bufs->count == rx_bufs->count); count = tx_bufs ? tx_bufs->count : rx_bufs->count; - switch (count) { - case 2: - tx = tx_bufs->buffers; - txd = &tx_bufs->buffers[1]; - rxd = rx_bufs ? &rx_bufs->buffers[1] : NULL; - switch (tx->len) { - case 1: - regn = *(uint8_t *)tx->buf; - if ((regn & BMI160_REG_READ) && rxd == NULL) { - LOG_ERR("Cannot read without rxd"); - return -EPERM; - } - switch (txd->len) { - case 1: - if (regn & BMI160_REG_READ) { - regn &= BMI160_REG_MASK; - val = reg_read(target, regn); - *(uint8_t *)rxd->buf = val; - } else { - val = *(uint8_t *)txd->buf; - reg_write(target, regn, val); - } - break; - case BMI160_SAMPLE_SIZE: - if (regn & BMI160_REG_READ) { - for (int i = 0; i < BMI160_SAMPLE_SIZE; ++i) { - ((uint8_t *)rxd->buf)[i] = reg_read( - target, (regn & BMI160_REG_MASK) + i); - } - } else { - LOG_DBG("Unknown sample write"); - } - break; - default: - LOG_DBG("Unknown A txd->len %d", txd->len); - break; + if (count != 2) { + LOG_DBG("Unknown tx_bufs->count %d", count); + return -EIO; + } + tx = tx_bufs->buffers; + txd = &tx_bufs->buffers[1]; + rxd = rx_bufs ? &rx_bufs->buffers[1] : NULL; + + if (tx->len != 1) { + LOG_DBG("Unknown tx->len %d", tx->len); + return -EIO; + } + + regn = *(uint8_t *)tx->buf; + if ((regn & BMI160_REG_READ) && rxd == NULL) { + LOG_ERR("Cannot read without rxd"); + return -EPERM; + } + + if (txd->len == 1) { + if (regn & BMI160_REG_READ) { + regn &= BMI160_REG_MASK; + val = reg_read(target, regn); + *(uint8_t *)rxd->buf = val; + } else { + val = *(uint8_t *)txd->buf; + reg_write(target, regn, val); + } + } else { + if (regn & BMI160_REG_READ) { + regn &= BMI160_REG_MASK; + for (int i = 0; i < txd->len; ++i) { + ((uint8_t *)rxd->buf)[i] = reg_read(target, regn + i); } - break; - default: - LOG_DBG("Unknown tx->len %d", tx->len); - break; + } else { + LOG_ERR("Unknown sample write"); + return -EIO; } - break; - default: - LOG_DBG("Unknown tx_bufs->count %d", count); - break; } return 0; @@ -446,7 +438,6 @@ static int bmi160_emul_backend_get_sample_range(const struct emul *target, enum default: return -EINVAL; } - } static int bmi160_emul_backend_set_offset(const struct emul *target, enum sensor_channel ch, diff --git a/drivers/spi/spi_emul.c b/drivers/spi/spi_emul.c index f92d0c95136..d8e89b1ae7f 100644 --- a/drivers/spi/spi_emul.c +++ b/drivers/spi/spi_emul.c @@ -68,6 +68,7 @@ static int spi_emul_io(const struct device *dev, const struct spi_config *config { struct spi_emul *emul; const struct spi_emul_api *api; + int ret; emul = spi_emul_find(dev, config->slave); if (!emul) { @@ -78,6 +79,13 @@ static int spi_emul_io(const struct device *dev, const struct spi_config *config __ASSERT_NO_MSG(emul->api); __ASSERT_NO_MSG(emul->api->io); + if (emul->mock_api != NULL && emul->mock_api->io != NULL) { + ret = emul->mock_api->io(emul->target, config, tx_bufs, rx_bufs); + if (ret != -ENOSYS) { + return ret; + } + } + return api->io(emul->target, config, tx_bufs, rx_bufs); } diff --git a/include/zephyr/drivers/i2c.h b/include/zephyr/drivers/i2c.h index ea0036eb3de..70cc0840db7 100644 --- a/include/zephyr/drivers/i2c.h +++ b/include/zephyr/drivers/i2c.h @@ -468,6 +468,18 @@ static inline bool i2c_is_ready_dt(const struct i2c_dt_spec *spec) return device_is_ready(spec->bus); } +/** + * @brief Check if the current message is a read operation + * + * @param msg The message to check + * @return true if the I2C message is sa read operation + * @return false if the I2C message is a write operation + */ +static inline bool i2c_is_read_op(struct i2c_msg *msg) +{ + return (msg->flags & I2C_MSG_READ) == I2C_MSG_READ; +} + /** * @brief Dump out an I2C message * diff --git a/include/zephyr/drivers/i2c_emul.h b/include/zephyr/drivers/i2c_emul.h index dcbdd1c5496..4c0b86b18f5 100644 --- a/include/zephyr/drivers/i2c_emul.h +++ b/include/zephyr/drivers/i2c_emul.h @@ -15,6 +15,7 @@ #include #include +#include #include #include @@ -42,6 +43,12 @@ struct i2c_emul { /* API provided for this device */ const struct i2c_emul_api *api; + /** + * A mock API that if not NULL will take precedence over the actual API. If set, a return + * value of -ENOSYS will revert back to the default api. + */ + struct i2c_emul_api *mock_api; + /* I2C address of the emulated device */ uint16_t addr; }; diff --git a/include/zephyr/drivers/spi_emul.h b/include/zephyr/drivers/spi_emul.h index fe189efb82b..9f7eb958089 100644 --- a/include/zephyr/drivers/spi_emul.h +++ b/include/zephyr/drivers/spi_emul.h @@ -43,6 +43,12 @@ struct spi_emul { /* API provided for this device */ const struct spi_emul_api *api; + /** + * A mock API that if not NULL will take precedence over the actual API. If set, a return + * value of -ENOSYS will revert back to the default api. + */ + struct spi_emul_api *mock_api; + /* SPI chip-select of the emulated device */ uint16_t chipsel; }; diff --git a/tests/drivers/sensor/accel/CMakeLists.txt b/tests/drivers/sensor/accel/CMakeLists.txt index 4b3d245c53f..932e8399b03 100644 --- a/tests/drivers/sensor/accel/CMakeLists.txt +++ b/tests/drivers/sensor/accel/CMakeLists.txt @@ -4,5 +4,12 @@ cmake_minimum_required(VERSION 3.20.0) find_package(Zephyr REQUIRED HINTS $ENV{ZEPHYR_BASE}) project(device) -FILE(GLOB app_sources src/*.c) -target_sources(app PRIVATE ${app_sources}) +target_include_directories(app PRIVATE include) +target_sources(app + PRIVATE + include/checks.h + include/fixture.h + src/fixture.c + src/i2c.c + src/spi.c +) diff --git a/tests/drivers/sensor/accel/include/checks.h b/tests/drivers/sensor/accel/include/checks.h new file mode 100644 index 00000000000..b2a4400360a --- /dev/null +++ b/tests/drivers/sensor/accel/include/checks.h @@ -0,0 +1,36 @@ +/* + * Copyright 2023 Google LLC + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#ifndef TEST_DRIVERS_SENSOR_ACCEL_INCLUDE_CHECKS_H_ +#define TEST_DRIVERS_SENSOR_ACCEL_INCLUDE_CHECKS_H_ + +#include +#include + +#include "bmi160.h" + +static inline bool bmi160_i2c_is_touching_reg(struct i2c_msg *msgs, int num_msgs, int reg) +{ + __ASSERT_NO_MSG(num_msgs == 2); + __ASSERT_NO_MSG(msgs[0].len == 1); + + uint8_t start_reg = msgs[0].buf[0]; + + return (start_reg <= reg) && (reg < start_reg + msgs[1].len); +} + +static inline bool bmi160_spi_is_touching_reg(const struct spi_buf_set *tx_bufs, + const struct spi_buf_set *rx_bufs, int reg) +{ + __ASSERT_NO_MSG(tx_bufs->count == 2); + const struct spi_buf *tx = &tx_bufs->buffers[0]; + const struct spi_buf *tx_data = &tx_bufs->buffers[1]; + uint32_t start_reg = ((uint8_t *)(tx->buf))[0] & BMI160_REG_MASK; + + return (start_reg <= reg) && (reg < start_reg + tx_data->len); +} + +#endif /* TEST_DRIVERS_SENSOR_ACCEL_INCLUDE_CHECKS_H_ */ diff --git a/tests/drivers/sensor/accel/include/fixture.h b/tests/drivers/sensor/accel/include/fixture.h new file mode 100644 index 00000000000..45c8b558fe3 --- /dev/null +++ b/tests/drivers/sensor/accel/include/fixture.h @@ -0,0 +1,20 @@ +/* + * Copyright 2023 Google LLC + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#ifndef TEST_DRIVERS_SENSOR_ACCEL_INCLUDE_FIXTURE_H_ +#define TEST_DRIVERS_SENSOR_ACCEL_INCLUDE_FIXTURE_H_ + +#include +#include + +struct bmi160_fixture { + const struct device *dev_spi; + const struct device *dev_i2c; + const struct emul *emul_spi; + const struct emul *emul_i2c; +}; + +#endif /* TEST_DRIVERS_SENSOR_ACCEL_INCLUDE_FIXTURE_H_ */ diff --git a/tests/drivers/sensor/accel/src/fixture.c b/tests/drivers/sensor/accel/src/fixture.c new file mode 100644 index 00000000000..bf938a0971a --- /dev/null +++ b/tests/drivers/sensor/accel/src/fixture.c @@ -0,0 +1,69 @@ +/* + * Copyright 2023 Google LLC + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include "fixture.h" + +#include +#include +#include + +static void sensor_bmi160_setup_emulator(const struct device *dev, const struct emul *emulator) +{ + static struct { + enum sensor_channel channel; + q31_t value; + } values[] = { + {SENSOR_CHAN_ACCEL_X, 0}, {SENSOR_CHAN_ACCEL_Y, 1 << 28}, + {SENSOR_CHAN_ACCEL_Z, 2 << 28}, {SENSOR_CHAN_GYRO_X, 3 << 28}, + {SENSOR_CHAN_GYRO_Y, 4 << 28}, {SENSOR_CHAN_GYRO_Z, 5 << 28}, + }; + static struct sensor_value scale; + + /* 4g */ + scale.val1 = 39; + scale.val2 = 226600; + zassert_ok(sensor_attr_set(dev, SENSOR_CHAN_ACCEL_XYZ, SENSOR_ATTR_FULL_SCALE, &scale)); + + /* 125 deg/s */ + scale.val1 = 2; + scale.val2 = 181661; + zassert_ok(sensor_attr_set(dev, SENSOR_CHAN_GYRO_XYZ, SENSOR_ATTR_FULL_SCALE, &scale)); + + for (size_t i = 0; i < ARRAY_SIZE(values); ++i) { + zassert_ok(emul_sensor_backend_set_channel(emulator, values[i].channel, + &values[i].value, 3)); + } +} + +static void *bmi160_setup(void) +{ + static struct bmi160_fixture fixture = { + .dev_spi = DEVICE_DT_GET(DT_ALIAS(accel_0)), + .dev_i2c = DEVICE_DT_GET(DT_ALIAS(accel_1)), + .emul_spi = EMUL_DT_GET(DT_ALIAS(accel_0)), + .emul_i2c = EMUL_DT_GET(DT_ALIAS(accel_1)), + }; + + sensor_bmi160_setup_emulator(fixture.dev_i2c, fixture.emul_i2c); + sensor_bmi160_setup_emulator(fixture.dev_spi, fixture.emul_spi); + + return &fixture; +} + +static void bmi160_before(void *f) +{ + struct bmi160_fixture *fixture = (struct bmi160_fixture *)f; + + zassert_true(device_is_ready(fixture->dev_spi), "'%s' device is not ready", + fixture->dev_spi->name); + zassert_true(device_is_ready(fixture->dev_i2c), "'%s' device is not ready", + fixture->dev_i2c->name); + + k_object_access_grant(fixture->dev_spi, k_current_get()); + k_object_access_grant(fixture->dev_i2c, k_current_get()); +} + +ZTEST_SUITE(bmi160, NULL, bmi160_setup, bmi160_before, NULL, NULL); \ No newline at end of file diff --git a/tests/drivers/sensor/accel/src/i2c.c b/tests/drivers/sensor/accel/src/i2c.c new file mode 100644 index 00000000000..b293e6e13a5 --- /dev/null +++ b/tests/drivers/sensor/accel/src/i2c.c @@ -0,0 +1,52 @@ +/* + * Copyright 2023 Google LLC + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include +#include +#include +#include +#include + +#include "bmi160.h" +#include "checks.h" +#include "fixture.h" + +static int mock_i2c_transfer_fail_reg_number = -1; + +static int mock_i2c_transfer(const struct emul *target, struct i2c_msg *msgs, int num_msgs, + int addr) +{ + ARG_UNUSED(target); + ARG_UNUSED(addr); + if (mock_i2c_transfer_fail_reg_number >= 0 && i2c_is_read_op(&msgs[1]) && + bmi160_i2c_is_touching_reg(msgs, num_msgs, mock_i2c_transfer_fail_reg_number)) { + return -EIO; + } + return -ENOSYS; +} + +ZTEST_USER_F(bmi160, test_bmi160_i2c_get_offset_fail_to_read_offset_acc) +{ + struct i2c_emul_api mock_bus_api; + struct sensor_value value; + + fixture->emul_i2c->bus.i2c->mock_api = &mock_bus_api; + mock_bus_api.transfer = mock_i2c_transfer; + + enum sensor_channel channels[] = {SENSOR_CHAN_ACCEL_XYZ, SENSOR_CHAN_GYRO_XYZ}; + int fail_registers[] = {BMI160_REG_OFFSET_ACC_X, BMI160_REG_OFFSET_ACC_Y, + BMI160_REG_OFFSET_ACC_Z, BMI160_REG_OFFSET_GYR_X, + BMI160_REG_OFFSET_GYR_Y, BMI160_REG_OFFSET_GYR_Z, + BMI160_REG_OFFSET_EN}; + + for (int fail_reg_idx = 0; fail_reg_idx < ARRAY_SIZE(fail_registers); ++fail_reg_idx) { + mock_i2c_transfer_fail_reg_number = fail_registers[fail_reg_idx]; + for (int chan_idx = 0; chan_idx < ARRAY_SIZE(channels); ++chan_idx) { + zassert_equal(-EIO, sensor_attr_get(fixture->dev_i2c, channels[chan_idx], + SENSOR_ATTR_OFFSET, &value)); + } + } +} diff --git a/tests/drivers/sensor/accel/src/main.c b/tests/drivers/sensor/accel/src/main.c deleted file mode 100644 index f1c680b6ba2..00000000000 --- a/tests/drivers/sensor/accel/src/main.c +++ /dev/null @@ -1,149 +0,0 @@ -/* - * Copyright 2020 Google LLC - * - * SPDX-License-Identifier: Apache-2.0 - */ - -/** - * @defgroup driver_sensor_subsys_tests sensor_subsys - * @ingroup all_tests - * @{ - * @} - */ - -#include -#include -#include -#include - -struct sensor_accel_fixture { - const struct device *accel_spi; - const struct device *accel_i2c; - const struct emul *accel_emul_spi; - const struct emul *accel_emul_i2c; -}; - -static enum sensor_channel channel[] = { - SENSOR_CHAN_ACCEL_X, SENSOR_CHAN_ACCEL_Y, SENSOR_CHAN_ACCEL_Z, - SENSOR_CHAN_GYRO_X, SENSOR_CHAN_GYRO_Y, SENSOR_CHAN_GYRO_Z, -}; - -static int32_t compute_epsilon_micro(q31_t value, int8_t shift) -{ - int64_t intermediate = value; - - if (shift > 0) { - intermediate <<= shift; - } else if (shift < 0) { - intermediate >>= -shift; - } - - intermediate = intermediate * INT64_C(1000000) / INT32_MAX; - return CLAMP(intermediate, INT32_MIN, INT32_MAX); -} - -static void test_sensor_accel_basic(const struct device *dev, const struct emul *emulator) -{ - q31_t accel_ranges[3]; - q31_t gyro_ranges[3]; - int8_t accel_shift; - int8_t gyro_shift; - - zassert_ok(sensor_sample_fetch(dev), "fail to fetch sample"); - zassert_ok(emul_sensor_backend_get_sample_range(emulator, SENSOR_CHAN_ACCEL_XYZ, - &accel_ranges[0], &accel_ranges[1], - &accel_ranges[2], &accel_shift)); - zassert_ok(emul_sensor_backend_get_sample_range(emulator, SENSOR_CHAN_GYRO_XYZ, - &gyro_ranges[0], &gyro_ranges[1], - &gyro_ranges[2], &gyro_shift)); - - int32_t accel_epsilon = compute_epsilon_micro(accel_ranges[2], accel_shift); - int32_t gyro_epsilon = compute_epsilon_micro(gyro_ranges[2], gyro_shift); - - for (int i = 0; i < ARRAY_SIZE(channel); i++) { - struct sensor_value val; - int64_t micro_val; - int32_t epsilon = (i < 3) ? accel_epsilon : gyro_epsilon; - - zassert_ok(sensor_channel_get(dev, channel[i], &val), "fail to get channel"); - - micro_val = sensor_value_to_micro(&val); - zassert_within(i * INT64_C(1000000), micro_val, epsilon, - "%d. expected %" PRIi64 " to be within %d of %" PRIi64, i, - i * INT64_C(1000000), epsilon, micro_val); - } -} - -/* Run all of our tests on an accelerometer device with the given label */ -static void run_tests_on_accel(const struct device *accel) -{ - zassert_true(device_is_ready(accel), "Accelerometer device is not ready"); - - PRINT("Running tests on '%s'\n", accel->name); - k_object_access_grant(accel, k_current_get()); -} - -ZTEST_USER_F(sensor_accel, test_sensor_accel_basic_spi) -{ - run_tests_on_accel(fixture->accel_spi); - test_sensor_accel_basic(fixture->accel_spi, fixture->accel_emul_spi); -} - -ZTEST_USER_F(sensor_accel, test_sensor_accel_basic_i2c) -{ - if (fixture->accel_i2c == NULL) { - ztest_test_skip(); - } - - run_tests_on_accel(fixture->accel_i2c); - test_sensor_accel_basic(fixture->accel_i2c, fixture->accel_emul_i2c); -} - -static void sensor_accel_setup_emulator(const struct device *dev, const struct emul *accel_emul) -{ - if (accel_emul == NULL) { - return; - } - - static struct { - enum sensor_channel channel; - q31_t value; - } values[] = { - {SENSOR_CHAN_ACCEL_X, 0}, {SENSOR_CHAN_ACCEL_Y, 1 << 28}, - {SENSOR_CHAN_ACCEL_Z, 2 << 28}, {SENSOR_CHAN_GYRO_X, 3 << 28}, - {SENSOR_CHAN_GYRO_Y, 4 << 28}, {SENSOR_CHAN_GYRO_Z, 5 << 28}, - }; - static struct sensor_value scale; - - /* 4g */ - scale.val1 = 39; - scale.val2 = 226600; - zassert_ok(sensor_attr_set(dev, SENSOR_CHAN_ACCEL_XYZ, SENSOR_ATTR_FULL_SCALE, &scale)); - - /* 125 deg/s */ - scale.val1 = 2; - scale.val2 = 181661; - zassert_ok(sensor_attr_set(dev, SENSOR_CHAN_GYRO_XYZ, SENSOR_ATTR_FULL_SCALE, &scale)); - - for (int i = 0; i < ARRAY_SIZE(values); ++i) { - zassert_ok(emul_sensor_backend_set_channel(accel_emul, values[i].channel, - &values[i].value, 3)); - } -} - -static void *sensor_accel_setup(void) -{ - static struct sensor_accel_fixture fixture = { - .accel_spi = DEVICE_DT_GET(DT_ALIAS(accel_0)), - .accel_i2c = DEVICE_DT_GET_OR_NULL(DT_ALIAS(accel_1)), - .accel_emul_spi = EMUL_DT_GET(DT_ALIAS(accel_0)), - .accel_emul_i2c = EMUL_DT_GET_OR_NULL(DT_ALIAS(accel_1)), - }; - - sensor_accel_setup_emulator(fixture.accel_spi, fixture.accel_emul_spi); - sensor_accel_setup_emulator(fixture.accel_i2c, fixture.accel_emul_i2c); - - return &fixture; -} - -ZTEST_SUITE(sensor_accel, NULL, sensor_accel_setup, NULL, NULL, NULL); diff --git a/tests/drivers/sensor/accel/src/spi.c b/tests/drivers/sensor/accel/src/spi.c new file mode 100644 index 00000000000..5fc6261b3fc --- /dev/null +++ b/tests/drivers/sensor/accel/src/spi.c @@ -0,0 +1,52 @@ +/* + * Copyright 2023 Google LLC + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include +#include +#include +#include +#include + +#include "bmi160.h" +#include "checks.h" +#include "fixture.h" + +static int mock_spi_io_fail_reg_number = -1; + +static int mock_spi_io(const struct emul *target, const struct spi_config *config, + const struct spi_buf_set *tx_bufs, const struct spi_buf_set *rx_bufs) +{ + ARG_UNUSED(target); + ARG_UNUSED(config); + if (mock_spi_io_fail_reg_number >= 0 && + bmi160_spi_is_touching_reg(tx_bufs, rx_bufs, mock_spi_io_fail_reg_number)) { + return -EIO; + } + return -ENOSYS; +} + +ZTEST_USER_F(bmi160, test_bmi160_spi_get_offset_fail_to_read_offset_acc) +{ + struct spi_emul_api mock_bus_api; + struct sensor_value value; + + fixture->emul_spi->bus.spi->mock_api = &mock_bus_api; + mock_bus_api.io = mock_spi_io; + + enum sensor_channel channels[] = {SENSOR_CHAN_ACCEL_XYZ, SENSOR_CHAN_GYRO_XYZ}; + int fail_registers[] = {BMI160_REG_OFFSET_ACC_X, BMI160_REG_OFFSET_ACC_Y, + BMI160_REG_OFFSET_ACC_Z, BMI160_REG_OFFSET_GYR_X, + BMI160_REG_OFFSET_GYR_Y, BMI160_REG_OFFSET_GYR_Z, + BMI160_REG_OFFSET_EN}; + + for (int fail_reg_idx = 0; fail_reg_idx < ARRAY_SIZE(fail_registers); ++fail_reg_idx) { + mock_spi_io_fail_reg_number = fail_registers[fail_reg_idx]; + for (int chan_idx = 0; chan_idx < ARRAY_SIZE(channels); ++chan_idx) { + zassert_equal(-EIO, sensor_attr_get(fixture->dev_spi, channels[chan_idx], + SENSOR_ATTR_OFFSET, &value)); + } + } +} From 2d09f1f566d8b8cecceff65a608bc72fe2255e1d Mon Sep 17 00:00:00 2001 From: Yuval Peress Date: Fri, 17 Nov 2023 13:54:46 -0700 Subject: [PATCH 2271/3723] test: bmi160: rename test directory Rename the test directory to more accuratly reflect what's being tested. Signed-off-by: Yuval Peress --- tests/drivers/sensor/{accel => bmi160}/CMakeLists.txt | 0 tests/drivers/sensor/{accel => bmi160}/boards/native_sim.conf | 0 .../drivers/sensor/{accel => bmi160}/boards/native_sim.overlay | 0 tests/drivers/sensor/{accel => bmi160}/include/checks.h | 0 tests/drivers/sensor/{accel => bmi160}/include/fixture.h | 0 tests/drivers/sensor/{accel => bmi160}/prj.conf | 0 tests/drivers/sensor/{accel => bmi160}/src/fixture.c | 2 +- tests/drivers/sensor/{accel => bmi160}/src/i2c.c | 0 tests/drivers/sensor/{accel => bmi160}/src/spi.c | 0 tests/drivers/sensor/{accel => bmi160}/testcase.yaml | 0 10 files changed, 1 insertion(+), 1 deletion(-) rename tests/drivers/sensor/{accel => bmi160}/CMakeLists.txt (100%) rename tests/drivers/sensor/{accel => bmi160}/boards/native_sim.conf (100%) rename tests/drivers/sensor/{accel => bmi160}/boards/native_sim.overlay (100%) rename tests/drivers/sensor/{accel => bmi160}/include/checks.h (100%) rename tests/drivers/sensor/{accel => bmi160}/include/fixture.h (100%) rename tests/drivers/sensor/{accel => bmi160}/prj.conf (100%) rename tests/drivers/sensor/{accel => bmi160}/src/fixture.c (99%) rename tests/drivers/sensor/{accel => bmi160}/src/i2c.c (100%) rename tests/drivers/sensor/{accel => bmi160}/src/spi.c (100%) rename tests/drivers/sensor/{accel => bmi160}/testcase.yaml (100%) diff --git a/tests/drivers/sensor/accel/CMakeLists.txt b/tests/drivers/sensor/bmi160/CMakeLists.txt similarity index 100% rename from tests/drivers/sensor/accel/CMakeLists.txt rename to tests/drivers/sensor/bmi160/CMakeLists.txt diff --git a/tests/drivers/sensor/accel/boards/native_sim.conf b/tests/drivers/sensor/bmi160/boards/native_sim.conf similarity index 100% rename from tests/drivers/sensor/accel/boards/native_sim.conf rename to tests/drivers/sensor/bmi160/boards/native_sim.conf diff --git a/tests/drivers/sensor/accel/boards/native_sim.overlay b/tests/drivers/sensor/bmi160/boards/native_sim.overlay similarity index 100% rename from tests/drivers/sensor/accel/boards/native_sim.overlay rename to tests/drivers/sensor/bmi160/boards/native_sim.overlay diff --git a/tests/drivers/sensor/accel/include/checks.h b/tests/drivers/sensor/bmi160/include/checks.h similarity index 100% rename from tests/drivers/sensor/accel/include/checks.h rename to tests/drivers/sensor/bmi160/include/checks.h diff --git a/tests/drivers/sensor/accel/include/fixture.h b/tests/drivers/sensor/bmi160/include/fixture.h similarity index 100% rename from tests/drivers/sensor/accel/include/fixture.h rename to tests/drivers/sensor/bmi160/include/fixture.h diff --git a/tests/drivers/sensor/accel/prj.conf b/tests/drivers/sensor/bmi160/prj.conf similarity index 100% rename from tests/drivers/sensor/accel/prj.conf rename to tests/drivers/sensor/bmi160/prj.conf diff --git a/tests/drivers/sensor/accel/src/fixture.c b/tests/drivers/sensor/bmi160/src/fixture.c similarity index 99% rename from tests/drivers/sensor/accel/src/fixture.c rename to tests/drivers/sensor/bmi160/src/fixture.c index bf938a0971a..a97be2cb784 100644 --- a/tests/drivers/sensor/accel/src/fixture.c +++ b/tests/drivers/sensor/bmi160/src/fixture.c @@ -66,4 +66,4 @@ static void bmi160_before(void *f) k_object_access_grant(fixture->dev_i2c, k_current_get()); } -ZTEST_SUITE(bmi160, NULL, bmi160_setup, bmi160_before, NULL, NULL); \ No newline at end of file +ZTEST_SUITE(bmi160, NULL, bmi160_setup, bmi160_before, NULL, NULL); diff --git a/tests/drivers/sensor/accel/src/i2c.c b/tests/drivers/sensor/bmi160/src/i2c.c similarity index 100% rename from tests/drivers/sensor/accel/src/i2c.c rename to tests/drivers/sensor/bmi160/src/i2c.c diff --git a/tests/drivers/sensor/accel/src/spi.c b/tests/drivers/sensor/bmi160/src/spi.c similarity index 100% rename from tests/drivers/sensor/accel/src/spi.c rename to tests/drivers/sensor/bmi160/src/spi.c diff --git a/tests/drivers/sensor/accel/testcase.yaml b/tests/drivers/sensor/bmi160/testcase.yaml similarity index 100% rename from tests/drivers/sensor/accel/testcase.yaml rename to tests/drivers/sensor/bmi160/testcase.yaml From c743e727566cb7454583c1e657ff98ed2b36dbe1 Mon Sep 17 00:00:00 2001 From: Yuval Peress Date: Tue, 28 Nov 2023 00:02:10 -0700 Subject: [PATCH 2272/3723] bmi160: Fix gyro range map The range map was sorted wrong since the function bmi160_range_to_reg_val() that uses it checks for the user value less than the range component of the bmi160_range struct. This means that no matter what range is set, the value will always end up 2000dps. Signed-off-by: Yuval Peress --- drivers/sensor/bmi160/bmi160.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/drivers/sensor/bmi160/bmi160.c b/drivers/sensor/bmi160/bmi160.c index 90ce8d8b58e..ea251e548d9 100644 --- a/drivers/sensor/bmi160/bmi160.c +++ b/drivers/sensor/bmi160/bmi160.c @@ -303,11 +303,11 @@ static const struct bmi160_range bmi160_acc_range_map[] = { #define BMI160_ACC_RANGE_MAP_SIZE ARRAY_SIZE(bmi160_acc_range_map) static const struct bmi160_range bmi160_gyr_range_map[] = { - {2000, BMI160_GYR_RANGE_2000DPS}, - {1000, BMI160_GYR_RANGE_1000DPS}, - {500, BMI160_GYR_RANGE_500DPS}, - {250, BMI160_GYR_RANGE_250DPS}, {125, BMI160_GYR_RANGE_125DPS}, + {250, BMI160_GYR_RANGE_250DPS}, + {500, BMI160_GYR_RANGE_500DPS}, + {1000, BMI160_GYR_RANGE_1000DPS}, + {2000, BMI160_GYR_RANGE_2000DPS}, }; #define BMI160_GYR_RANGE_MAP_SIZE ARRAY_SIZE(bmi160_gyr_range_map) From 9381e86cbe0d7dd00de4c74d060f7b8d7661c7ee Mon Sep 17 00:00:00 2001 From: Yuval Peress Date: Tue, 28 Nov 2023 00:07:40 -0700 Subject: [PATCH 2273/3723] bmi160: fix value calculation As an example, when the gyro range is set to 250 deg/sec the scale was set to 133 where it really should be 133.160058662. This leads to a 0.12% error in the value returned. By separating the numerator and denominator, we're able to drastically reduce the error. Signed-off-by: Yuval Peress --- drivers/sensor/bmi160/bmi160.c | 32 ++++++++++++++------------------ drivers/sensor/bmi160/bmi160.h | 14 +++++++++----- 2 files changed, 23 insertions(+), 23 deletions(-) diff --git a/drivers/sensor/bmi160/bmi160.c b/drivers/sensor/bmi160/bmi160.c index ea251e548d9..8f19cedac78 100644 --- a/drivers/sensor/bmi160/bmi160.c +++ b/drivers/sensor/bmi160/bmi160.c @@ -403,7 +403,7 @@ static int bmi160_acc_range_set(const struct device *dev, const struct sensor_va return -EIO; } - data->scale.acc = BMI160_ACC_SCALE(range_g); + data->scale.acc_numerator = BMI160_ACC_SCALE_NUMERATOR(range_g); return 0; } #endif @@ -586,7 +586,7 @@ static int bmi160_gyr_range_set(const struct device *dev, const struct sensor_va return -EIO; } - data->scale.gyr = BMI160_GYR_SCALE(range); + data->scale.gyr_numerator = BMI160_GYR_SCALE_NUMERATOR(range); return 0; } @@ -899,24 +899,18 @@ static int bmi160_sample_fetch(const struct device *dev, return ret; } -static void bmi160_to_fixed_point(int16_t raw_val, uint16_t scale, - struct sensor_value *val) +static void bmi160_to_fixed_point(int16_t raw_val, int64_t scale_numerator, + uint32_t scale_denominator, struct sensor_value *val) { - int32_t converted_val; + int64_t converted_val = (int64_t)raw_val * scale_numerator / scale_denominator; - /* - * maximum converted value we can get is: max(raw_val) * max(scale) - * max(raw_val) = +/- 2^15 - * max(scale) = 4785 - * max(converted_val) = 156794880 which is less than 2^31 - */ - converted_val = raw_val * scale; val->val1 = converted_val / 1000000; val->val2 = converted_val % 1000000; } static void bmi160_channel_convert(enum sensor_channel chan, - uint16_t scale, + int64_t scale_numerator, + uint32_t scale_denominator, uint16_t *raw_xyz, struct sensor_value *val) { @@ -942,7 +936,7 @@ static void bmi160_channel_convert(enum sensor_channel chan, } for (i = ofs_start; i <= ofs_stop ; i++, val++) { - bmi160_to_fixed_point(raw_xyz[i], scale, val); + bmi160_to_fixed_point(raw_xyz[i], scale_numerator, scale_denominator, val); } } @@ -953,7 +947,8 @@ static inline void bmi160_gyr_channel_get(const struct device *dev, { struct bmi160_data *data = dev->data; - bmi160_channel_convert(chan, data->scale.gyr, data->sample.gyr, val); + bmi160_channel_convert(chan, data->scale.gyr_numerator, BMI160_GYR_SCALE_DENOMINATOR, + data->sample.gyr, val); } #endif @@ -964,7 +959,8 @@ static inline void bmi160_acc_channel_get(const struct device *dev, { struct bmi160_data *data = dev->data; - bmi160_channel_convert(chan, data->scale.acc, data->sample.acc, val); + bmi160_channel_convert(chan, data->scale.acc_numerator, BMI160_ACC_SCALE_DENOMINATOR, + data->sample.acc, val); } #endif @@ -1130,7 +1126,7 @@ int bmi160_init(const struct device *dev) acc_range = bmi160_acc_reg_val_to_range(BMI160_DEFAULT_RANGE_ACC); - data->scale.acc = BMI160_ACC_SCALE(acc_range); + data->scale.acc_numerator = BMI160_ACC_SCALE_NUMERATOR(acc_range); /* set gyro default range */ if (bmi160_byte_write(dev, BMI160_REG_GYR_RANGE, @@ -1141,7 +1137,7 @@ int bmi160_init(const struct device *dev) gyr_range = bmi160_gyr_reg_val_to_range(BMI160_DEFAULT_RANGE_GYR); - data->scale.gyr = BMI160_GYR_SCALE(gyr_range); + data->scale.gyr_numerator = BMI160_GYR_SCALE_NUMERATOR(gyr_range); if (bmi160_reg_field_update(dev, BMI160_REG_ACC_CONF, BMI160_ACC_CONF_ODR_POS, diff --git a/drivers/sensor/bmi160/bmi160.h b/drivers/sensor/bmi160/bmi160.h index 9b44f479fbb..a0beb7f05bc 100644 --- a/drivers/sensor/bmi160/bmi160.h +++ b/drivers/sensor/bmi160/bmi160.h @@ -300,9 +300,11 @@ enum bmi160_odr { #define BMI160_GYR_RANGE_250DPS 3 #define BMI160_GYR_RANGE_125DPS 4 -#define BMI160_ACC_SCALE(range_g) ((2 * range_g * SENSOR_G) / 65536LL) -#define BMI160_GYR_SCALE(range_dps)\ - ((2 * range_dps * SENSOR_PI) / 180LL / 65536LL) +#define BMI160_ACC_SCALE_NUMERATOR(range_g) (2 * (range_g) * SENSOR_G) +#define BMI160_ACC_SCALE_DENOMINATOR UINT16_MAX + +#define BMI160_GYR_SCALE_NUMERATOR(range_dps) (2 * (range_dps) * SENSOR_PI) +#define BMI160_GYR_SCALE_DENOMINATOR (UINT32_C(180) * UINT16_MAX) /* default settings, based on menuconfig options */ @@ -483,8 +485,10 @@ union bmi160_sample { }; struct bmi160_scale { - uint16_t acc; /* micro m/s^2/lsb */ - uint16_t gyr; /* micro radians/s/lsb */ + /* numerator / denominator => micro m/s^2/lsb */ + int32_t acc_numerator; + /* numerator / denominator => micro radians/s/lsb */ + int64_t gyr_numerator; }; struct bmi160_data { From 640a4586c0c25601f735cad27ad6e53cc74d49ab Mon Sep 17 00:00:00 2001 From: Flavio Ceolin Date: Sat, 13 Jan 2024 22:26:10 -0800 Subject: [PATCH 2274/3723] pm: device_runtime: Fix domain mgmt in async put The asynchronous put is not checking if the device was successfully suspended before suspending its domain and it is not checking if the domain was claimed. This patch adds these two checks. Signed-off-by: Flavio Ceolin --- subsys/pm/device_runtime.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/subsys/pm/device_runtime.c b/subsys/pm/device_runtime.c index b3546b6608f..f7d9b7a8369 100644 --- a/subsys/pm/device_runtime.c +++ b/subsys/pm/device_runtime.c @@ -121,7 +121,8 @@ static void runtime_suspend_work(struct k_work *work) * On async put, we have to suspend the domain when the device * finishes its operation */ - if (PM_DOMAIN(pm) != NULL) { + if ((ret == 0) && + atomic_test_bit(&pm->flags, PM_DEVICE_FLAG_PD_CLAIMED)) { (void)pm_device_runtime_put(PM_DOMAIN(pm)); } From a897005b989a4d8aec27089b5b2aab7535e60270 Mon Sep 17 00:00:00 2001 From: Jaro Van Landschoot Date: Mon, 15 Jan 2024 09:23:10 +0100 Subject: [PATCH 2275/3723] drivers: serial: sam u(s)art: correct interpretation of RXRDY flag The receiver ready flag of the (channel) status register for the sam controller was not being interpreted correctly for both the uart and usart implementation, according to the uart api. Tested and confirmed using the sam4sa16ca. Signed-off-by: Jaro Van Landschoot --- drivers/serial/uart_sam.c | 2 +- drivers/serial/usart_sam.c | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/serial/uart_sam.c b/drivers/serial/uart_sam.c index 0173c15b6bc..2c54f6e550a 100644 --- a/drivers/serial/uart_sam.c +++ b/drivers/serial/uart_sam.c @@ -49,7 +49,7 @@ static int uart_sam_poll_in(const struct device *dev, unsigned char *c) Uart * const uart = cfg->regs; if (!(uart->UART_SR & UART_SR_RXRDY)) { - return -EBUSY; + return -1; } /* got a character */ diff --git a/drivers/serial/usart_sam.c b/drivers/serial/usart_sam.c index ac87c41bdbf..2b050e74205 100644 --- a/drivers/serial/usart_sam.c +++ b/drivers/serial/usart_sam.c @@ -50,7 +50,7 @@ static int usart_sam_poll_in(const struct device *dev, unsigned char *c) Usart * const usart = config->regs; if (!(usart->US_CSR & US_CSR_RXRDY)) { - return -EBUSY; + return -1; } /* got a character */ From a59e01d297fd07735413f362bf8db24133a39f02 Mon Sep 17 00:00:00 2001 From: Erwan Gouriou Date: Mon, 18 Dec 2023 12:03:43 +0100 Subject: [PATCH 2276/3723] scripts: kconfigfunctions: Add dt_node_ph_array_prop_int/hex Add dt_node_ph_array_prop_int/hex function to query value of cells from a phandle-array property of a node at a given index of the array. Based on dt_node_array_prop_int/hex. Signed-off-by: Erwan Gouriou --- scripts/kconfig/kconfigfunctions.py | 57 +++++++++++++++++++++++++++++ 1 file changed, 57 insertions(+) diff --git a/scripts/kconfig/kconfigfunctions.py b/scripts/kconfig/kconfigfunctions.py index 621ec3cb3a8..4a74c6ff88c 100644 --- a/scripts/kconfig/kconfigfunctions.py +++ b/scripts/kconfig/kconfigfunctions.py @@ -245,6 +245,33 @@ def _node_array_prop(node, prop, index=0, unit=None): return 0 return node.props[prop].val[int(index)] >> _dt_units_to_scale(unit) +def _node_ph_array_prop(node, prop, index, cell, unit=None): + """ + This function takes a 'node', a property name ('prop'), index ('index') and + a cell ('cell') and it will look to see if that node has a property + called 'prop' and if that 'prop' is an phandle-array type. + Then it will check if that phandle array has a cell matching the given index + and then return the value of the cell named 'cell' in this array index. + If not found it will return 0. + + The function will divide the value based on 'unit': + None No division + 'k' or 'K' divide by 1024 (1 << 10) + 'm' or 'M' divide by 1,048,576 (1 << 20) + 'g' or 'G' divide by 1,073,741,824 (1 << 30) + """ + if not node: + return 0 + + if prop not in node.props: + return 0 + if node.props[prop].type != "phandle-array": + return 0 + if int(index) >= len(node.props[prop].val): + return 0 + if cell not in node.props[prop].val[int(index)].data.keys(): + return 0 + return node.props[prop].val[int(index)].data[cell] >> _dt_units_to_scale(unit) def _dt_chosen_reg_addr(kconf, chosen, index=0, unit=None): """ @@ -559,6 +586,34 @@ def dt_node_array_prop(kconf, name, path, prop, index, unit=None): return hex(_node_array_prop(node, prop, index, unit)) +def dt_node_ph_array_prop(kconf, name, path, prop, index, cell, unit=None): + """ + This function takes a 'path', property name ('prop'), index ('index') and + a cell ('cell') and looks for an EDT node at that path. + If it finds an EDT node, it will look to see if that node has a property + called 'prop' and if that 'prop' is an phandle-array type. + Then it will check if that phandle array has a cell matching the given index + and ten return the value of the cell named 'cell' in this array index as + either a string int or string hex value. If not found we return 0. + + The function will divide the value based on 'unit': + None No division + 'k' or 'K' divide by 1024 (1 << 10) + 'm' or 'M' divide by 1,048,576 (1 << 20) + 'g' or 'G' divide by 1,073,741,824 (1 << 30) + """ + if doc_mode or edt is None: + return "0" + + try: + node = edt.get_node(path) + except edtlib.EDTError: + return "0" + if name == "dt_node_ph_array_prop_int": + return str(_node_ph_array_prop(node, prop, index, cell, unit)) + if name == "dt_node_ph_array_prop_hex": + return hex(_node_ph_array_prop(node, prop, index, cell, unit)) + def dt_node_str_prop_equals(kconf, _, path, prop, val): """ This function takes a 'path' and property name ('prop') looks for an EDT @@ -799,6 +854,8 @@ def shields_list_contains(kconf, _, shield): "dt_node_int_prop_hex": (dt_node_int_prop, 2, 3), "dt_node_array_prop_int": (dt_node_array_prop, 3, 4), "dt_node_array_prop_hex": (dt_node_array_prop, 3, 4), + "dt_node_ph_array_prop_int": (dt_node_ph_array_prop, 4, 5), + "dt_node_ph_array_prop_hex": (dt_node_ph_array_prop, 4, 5), "dt_node_str_prop_equals": (dt_node_str_prop_equals, 3, 3), "dt_nodelabel_has_compat": (dt_nodelabel_has_compat, 2, 2), "dt_node_has_compat": (dt_node_has_compat, 2, 2), From b677ed0b69e2fdece53ee6a325310db9d6c4e437 Mon Sep 17 00:00:00 2001 From: Erwan Gouriou Date: Wed, 20 Dec 2023 17:15:20 +0100 Subject: [PATCH 2277/3723] include: dt-bindings: stm32_clocks: Rework definitions Rework clock definitions in order to be able to make global assumptions on some specific clocks values such as STM32_SRC_LSE and STM32_SRC_LSI. As such, introduce stm32_common_clocks.h Complete that change by reworking values definition by doing a manual enum (as enum is not possible in dt-bindings header files). Signed-off-by: Erwan Gouriou --- .../dt-bindings/clock/stm32_common_clocks.h | 18 +++++++ .../zephyr/dt-bindings/clock/stm32c0_clock.h | 17 +++---- .../zephyr/dt-bindings/clock/stm32f0_clock.h | 21 ++++---- .../zephyr/dt-bindings/clock/stm32f1_clock.h | 16 +++--- .../zephyr/dt-bindings/clock/stm32f3_clock.h | 20 ++++---- .../zephyr/dt-bindings/clock/stm32f4_clock.h | 24 +++++---- .../zephyr/dt-bindings/clock/stm32f7_clock.h | 24 ++++----- .../zephyr/dt-bindings/clock/stm32g0_clock.h | 27 +++++----- .../zephyr/dt-bindings/clock/stm32g4_clock.h | 28 +++++------ .../zephyr/dt-bindings/clock/stm32h5_clock.h | 42 ++++++++-------- .../zephyr/dt-bindings/clock/stm32h7_clock.h | 49 ++++++++++--------- .../zephyr/dt-bindings/clock/stm32l0_clock.h | 20 ++++---- .../zephyr/dt-bindings/clock/stm32l1_clock.h | 14 +++--- .../zephyr/dt-bindings/clock/stm32l4_clock.h | 25 +++++----- .../zephyr/dt-bindings/clock/stm32u5_clock.h | 45 ++++++++--------- .../zephyr/dt-bindings/clock/stm32wb_clock.h | 27 +++++----- .../zephyr/dt-bindings/clock/stm32wba_clock.h | 22 ++++----- .../zephyr/dt-bindings/clock/stm32wl_clock.h | 24 ++++----- 18 files changed, 234 insertions(+), 229 deletions(-) create mode 100644 include/zephyr/dt-bindings/clock/stm32_common_clocks.h diff --git a/include/zephyr/dt-bindings/clock/stm32_common_clocks.h b/include/zephyr/dt-bindings/clock/stm32_common_clocks.h new file mode 100644 index 00000000000..030ec2d939b --- /dev/null +++ b/include/zephyr/dt-bindings/clock/stm32_common_clocks.h @@ -0,0 +1,18 @@ +/* + * Copyright (c) 2023 STMicroelectronics + * + * SPDX-License-Identifier: Apache-2.0 + */ +#ifndef ZEPHYR_INCLUDE_DT_BINDINGS_CLOCK_STM32_COMMON_CLOCKS_H_ +#define ZEPHYR_INCLUDE_DT_BINDINGS_CLOCK_STM32_COMMON_CLOCKS_H_ + +/** System clock */ +#define STM32_SRC_SYSCLK 0x001 +/** Fixed clocks */ +#define STM32_SRC_LSE 0x002 +#define STM32_SRC_LSI 0x003 + +/** Dummy: Add a specifier when no selection is possible */ +#define NO_SEL 0xFF + +#endif /* ZEPHYR_INCLUDE_DT_BINDINGS_CLOCK_STM32_COMMON_CLOCKS_H_ */ diff --git a/include/zephyr/dt-bindings/clock/stm32c0_clock.h b/include/zephyr/dt-bindings/clock/stm32c0_clock.h index b48aa7d2ef1..224bd1517d5 100644 --- a/include/zephyr/dt-bindings/clock/stm32c0_clock.h +++ b/include/zephyr/dt-bindings/clock/stm32c0_clock.h @@ -6,6 +6,8 @@ #ifndef ZEPHYR_INCLUDE_DT_BINDINGS_CLOCK_STM32C0_CLOCK_H_ #define ZEPHYR_INCLUDE_DT_BINDINGS_CLOCK_STM32C0_CLOCK_H_ +#include "stm32_common_clocks.h" + /** Bus clocks */ #define STM32_CLOCK_BUS_IOP 0x034 #define STM32_CLOCK_BUS_AHB1 0x038 @@ -18,15 +20,14 @@ /** Domain clocks */ /* RM0490, §5.4.21/22 Clock configuration register (RCC_CCIPRx) */ -/** Fixed clocks */ -#define STM32_SRC_HSI48 0x001 -#define STM32_SRC_HSE 0x002 -#define STM32_SRC_LSE 0x003 -#define STM32_SRC_LSI 0x004 /** System clock */ -#define STM32_SRC_SYSCLK 0x005 +/* defined in stm32_common_clocks.h */ +/** Fixed clocks */ +/* Low speed clocks defined in stm32_common_clocks.h */ +#define STM32_SRC_HSI48 (STM32_SRC_LSI + 1) +#define STM32_SRC_HSE (STM32_SRC_HSI48 + 1) /** Peripheral bus clock */ -#define STM32_SRC_PCLK 0x006 +#define STM32_SRC_PCLK (STM32_SRC_HSE + 1) #define STM32_CLOCK_REG_MASK 0xFFU #define STM32_CLOCK_REG_SHIFT 0U @@ -70,7 +71,5 @@ #define ADC_SEL(val) STM32_CLOCK(val, 3, 30, CCIPR_REG) /** CSR1 devices */ #define RTC_SEL(val) STM32_CLOCK(val, 3, 8, CSR1_REG) -/** Dummy: Add a specificier when no selection is possible */ -#define NO_SEL 0xFF #endif /* ZEPHYR_INCLUDE_DT_BINDINGS_CLOCK_STM32C0_CLOCK_H_ */ diff --git a/include/zephyr/dt-bindings/clock/stm32f0_clock.h b/include/zephyr/dt-bindings/clock/stm32f0_clock.h index 309c31877e3..11645735830 100644 --- a/include/zephyr/dt-bindings/clock/stm32f0_clock.h +++ b/include/zephyr/dt-bindings/clock/stm32f0_clock.h @@ -6,6 +6,8 @@ #ifndef ZEPHYR_INCLUDE_DT_BINDINGS_CLOCK_STM32F0_CLOCK_H_ #define ZEPHYR_INCLUDE_DT_BINDINGS_CLOCK_STM32F0_CLOCK_H_ +#include "stm32_common_clocks.h" + /** Bus gatting clocks */ #define STM32_CLOCK_BUS_AHB1 0x014 #define STM32_CLOCK_BUS_APB2 0x018 @@ -16,18 +18,17 @@ /** Domain clocks */ -/** Fixed clocks */ -#define STM32_SRC_HSI 0x001 -#define STM32_SRC_LSE 0x002 -#define STM32_SRC_LSI 0x003 -#define STM32_SRC_HSI14 0x004 -#define STM32_SRC_HSI48 0x005 /** System clock */ -#define STM32_SRC_SYSCLK 0x006 +/* defined in stm32_common_clocks.h */ +/** Fixed clocks */ +/* Low speed clocks defined in stm32_common_clocks.h */ +#define STM32_SRC_HSI (STM32_SRC_LSI + 1) +#define STM32_SRC_HSI14 (STM32_SRC_HSI + 1) +#define STM32_SRC_HSI48 (STM32_SRC_HSI14 + 1) /** Bus clock */ -#define STM32_SRC_PCLK 0x007 +#define STM32_SRC_PCLK (STM32_SRC_HSI48 + 1) /** PLL clock */ -#define STM32_SRC_PLLCLK 0x008 +#define STM32_SRC_PLLCLK (STM32_SRC_PCLK + 1) #define STM32_CLOCK_REG_MASK 0xFFU #define STM32_CLOCK_REG_SHIFT 0U @@ -73,7 +74,5 @@ #define USART3_SEL(val) STM32_CLOCK(val, 3, 18, CFGR3_REG) /** BDCR devices */ #define RTC_SEL(val) STM32_CLOCK(val, 3, 8, BDCR_REG) -/** Dummy: Add a specificier when no selection is possible */ -#define NO_SEL 0xFF #endif /* ZEPHYR_INCLUDE_DT_BINDINGS_CLOCK_STM32F0_CLOCK_H_ */ diff --git a/include/zephyr/dt-bindings/clock/stm32f1_clock.h b/include/zephyr/dt-bindings/clock/stm32f1_clock.h index e65be1c72e3..571014dd2f0 100644 --- a/include/zephyr/dt-bindings/clock/stm32f1_clock.h +++ b/include/zephyr/dt-bindings/clock/stm32f1_clock.h @@ -6,6 +6,8 @@ #ifndef ZEPHYR_INCLUDE_DT_BINDINGS_CLOCK_STM32F1_CLOCK_H_ #define ZEPHYR_INCLUDE_DT_BINDINGS_CLOCK_STM32F1_CLOCK_H_ +#include "stm32_common_clocks.h" + /** Domain clocks */ /** Bus clocks */ @@ -16,13 +18,13 @@ #define STM32_PERIPH_BUS_MIN STM32_CLOCK_BUS_AHB1 #define STM32_PERIPH_BUS_MAX STM32_CLOCK_BUS_APB1 -/** Fixed clocks */ -#define STM32_SRC_HSI 0x001 -#define STM32_SRC_HSE 0x002 -#define STM32_SRC_LSE 0x003 -#define STM32_SRC_LSI 0x004 /** System clock */ -#define STM32_SRC_SYSCLK 0x005 +/* defined in stm32_common_clocks.h */ + +/** Fixed clocks */ +/* Low speed clocks defined in stm32_common_clocks.h */ +#define STM32_SRC_HSI (STM32_SRC_LSI + 1) +#define STM32_SRC_HSE (STM32_SRC_HSI + 1) #define STM32_CLOCK_REG_MASK 0xFFU @@ -65,7 +67,5 @@ #define I2S3_SEL(val) STM32_CLOCK(val, 1, 18, CFGR2_REG) /** BDCR devices */ #define RTC_SEL(val) STM32_CLOCK(val, 3, 8, BDCR_REG) -/** Dummy: Add a specificier when no selection is possible */ -#define NO_SEL 0xFF #endif /* ZEPHYR_INCLUDE_DT_BINDINGS_CLOCK_STM32F1_CLOCK_H_ */ diff --git a/include/zephyr/dt-bindings/clock/stm32f3_clock.h b/include/zephyr/dt-bindings/clock/stm32f3_clock.h index 90614f385b9..377eb4fdaad 100644 --- a/include/zephyr/dt-bindings/clock/stm32f3_clock.h +++ b/include/zephyr/dt-bindings/clock/stm32f3_clock.h @@ -6,6 +6,8 @@ #ifndef ZEPHYR_INCLUDE_DT_BINDINGS_CLOCK_STM32F3_CLOCK_H_ #define ZEPHYR_INCLUDE_DT_BINDINGS_CLOCK_STM32F3_CLOCK_H_ +#include "stm32_common_clocks.h" + /** Bus gatting clocks */ #define STM32_CLOCK_BUS_AHB1 0x014 #define STM32_CLOCK_BUS_APB2 0x018 @@ -17,17 +19,17 @@ /** Domain clocks */ /* RM0316, §9.4.13 Clock configuration register (RCC_CFGR3) */ -/** Fixed clocks */ -#define STM32_SRC_HSI 0x001 -#define STM32_SRC_LSE 0x002 -#define STM32_SRC_LSI 0x007 -/* #define STM32_SRC_HSI48 0x003 */ /** System clock */ -#define STM32_SRC_SYSCLK 0x004 +/* Defined in stm32_common_clocks.h */ + +/** Fixed clocks */ +/* Low speed clocks defined in stm32_common_clocks.h */ +#define STM32_SRC_HSI (STM32_SRC_LSI + 1) +/* #define STM32_SRC_HSI48 TDB */ /** Bus clock */ -#define STM32_SRC_PCLK 0x005 +#define STM32_SRC_PCLK (STM32_SRC_HSI + 1) /** PLL clock */ -#define STM32_SRC_PLLCLK 0x006 +#define STM32_SRC_PLLCLK (STM32_SRC_PCLK + 1) #define STM32_CLOCK_REG_MASK 0xFFU #define STM32_CLOCK_REG_SHIFT 0U @@ -86,7 +88,5 @@ #define TIM3_4_SEL(val) STM32_CLOCK(val, 1, 25, CFGR3_REG) /** BDCR devices */ #define RTC_SEL(val) STM32_CLOCK(val, 3, 8, BDCR_REG) -/** Dummy: Add a specificier when no selection is possible */ -#define NO_SEL 0xFF #endif /* ZEPHYR_INCLUDE_DT_BINDINGS_CLOCK_STM32F3_CLOCK_H_ */ diff --git a/include/zephyr/dt-bindings/clock/stm32f4_clock.h b/include/zephyr/dt-bindings/clock/stm32f4_clock.h index e0edf742d79..93355865fdd 100644 --- a/include/zephyr/dt-bindings/clock/stm32f4_clock.h +++ b/include/zephyr/dt-bindings/clock/stm32f4_clock.h @@ -6,6 +6,8 @@ #ifndef ZEPHYR_INCLUDE_DT_BINDINGS_CLOCK_STM32F4_CLOCK_H_ #define ZEPHYR_INCLUDE_DT_BINDINGS_CLOCK_STM32F4_CLOCK_H_ +#include "stm32_common_clocks.h" + /** Domain clocks */ /** Bus clocks */ @@ -22,19 +24,18 @@ /** Domain clocks */ /* RM0386, 0390, 0402, 0430 § Dedicated Clock configuration register (RCC_DCKCFGRx) */ -/** PLL clock outputs */ -#define STM32_SRC_PLL_P 0x001 -#define STM32_SRC_PLL_Q 0x002 -#define STM32_SRC_PLL_R 0x003 -/** Fixed clocks */ -#define STM32_SRC_LSE 0x004 -#define STM32_SRC_LSI 0x005 /** System clock */ -#define STM32_SRC_SYSCLK 0x006 +/* defined in stm32_common_clocks.h */ +/** Fixed clocks */ +/* Low speed clocks defined in stm32_common_clocks.h */ +/** PLL clock outputs */ +#define STM32_SRC_PLL_P (STM32_SRC_LSI + 1) +#define STM32_SRC_PLL_Q (STM32_SRC_PLL_P + 1) +#define STM32_SRC_PLL_R (STM32_SRC_PLL_Q + 1) /** I2S sources */ -#define STM32_SRC_PLLI2S_R 0x007 +#define STM32_SRC_PLLI2S_R (STM32_SRC_PLL_R + 1) /* I2S_CKIN not supported yet */ -/* #define STM32_SRC_I2S_CKIN 0x008 */ +/* #define STM32_SRC_I2S_CKIN TBD */ #define STM32_CLOCK_REG_MASK 0xFFU @@ -76,7 +77,4 @@ /** BDCR devices */ #define RTC_SEL(val) STM32_CLOCK(val, 3, 8, BDCR_REG) -/** Dummy: Add a specificier when no selection is possible */ -#define NO_SEL 0xFF - #endif /* ZEPHYR_INCLUDE_DT_BINDINGS_CLOCK_STM32F4_CLOCK_H_ */ diff --git a/include/zephyr/dt-bindings/clock/stm32f7_clock.h b/include/zephyr/dt-bindings/clock/stm32f7_clock.h index fd404f1001c..92d3b7e1221 100644 --- a/include/zephyr/dt-bindings/clock/stm32f7_clock.h +++ b/include/zephyr/dt-bindings/clock/stm32f7_clock.h @@ -6,6 +6,8 @@ #ifndef ZEPHYR_INCLUDE_DT_BINDINGS_CLOCK_STM32F7_CLOCK_H_ #define ZEPHYR_INCLUDE_DT_BINDINGS_CLOCK_STM32F7_CLOCK_H_ +#include "stm32_common_clocks.h" + /** Domain clocks */ /** Bus clocks */ @@ -22,18 +24,18 @@ /** Domain clocks */ /* RM0386, 0390, 0402, 0430 § Dedicated Clock configuration register (RCC_DCKCFGRx) */ -/** PLL clock outputs */ -#define STM32_SRC_PLL_P 0x001 -#define STM32_SRC_PLL_Q 0x002 -#define STM32_SRC_PLL_R 0x003 -/** Fixed clocks */ -#define STM32_SRC_LSE 0x004 -#define STM32_SRC_LSI 0x005 -#define STM32_SRC_HSI 0x008 /** System clock */ -#define STM32_SRC_SYSCLK 0x006 +/* defined in stm32_common_clocks.h */ + +/** Fixed clocks */ +/* Low speed clocks defined in stm32_common_clocks.h */ +#define STM32_SRC_HSI (STM32_SRC_LSI + 1) +/** PLL clock outputs */ +#define STM32_SRC_PLL_P (STM32_SRC_HSI + 1) +#define STM32_SRC_PLL_Q (STM32_SRC_PLL_P + 1) +#define STM32_SRC_PLL_R (STM32_SRC_PLL_Q + 1) /** Peripheral bus clock */ -#define STM32_SRC_PCLK 0x007 +#define STM32_SRC_PCLK (STM32_SRC_PLL_R + 1) #define STM32_CLOCK_REG_MASK 0xFFU @@ -100,7 +102,5 @@ #define SDMMC1_SEL(val) STM32_CLOCK(val, 1, 28, DCKCFGR2_REG) #define SDMMC2_SEL(val) STM32_CLOCK(val, 1, 29, DCKCFGR2_REG) #define DSI_SEL(val) STM32_CLOCK(val, 1, 30, DCKCFGR2_REG) -/** Dummy: Add a specificier when no selection is possible */ -#define NO_SEL 0xFF #endif /* ZEPHYR_INCLUDE_DT_BINDINGS_CLOCK_STM32F7_CLOCK_H_ */ diff --git a/include/zephyr/dt-bindings/clock/stm32g0_clock.h b/include/zephyr/dt-bindings/clock/stm32g0_clock.h index 3752a06b9a0..86d93e83d14 100644 --- a/include/zephyr/dt-bindings/clock/stm32g0_clock.h +++ b/include/zephyr/dt-bindings/clock/stm32g0_clock.h @@ -6,6 +6,8 @@ #ifndef ZEPHYR_INCLUDE_DT_BINDINGS_CLOCK_STM32G0_CLOCK_H_ #define ZEPHYR_INCLUDE_DT_BINDINGS_CLOCK_STM32G0_CLOCK_H_ +#include "stm32_common_clocks.h" + /** Bus clocks */ #define STM32_CLOCK_BUS_IOP 0x034 #define STM32_CLOCK_BUS_AHB1 0x038 @@ -18,21 +20,20 @@ /** Domain clocks */ /* RM0444, §5.4.21/22 Clock configuration register (RCC_CCIPRx) */ -/** Fixed clocks */ -#define STM32_SRC_HSI 0x001 -#define STM32_SRC_HSI48 0x002 -#define STM32_SRC_MSI 0x003 -#define STM32_SRC_HSE 0x004 -#define STM32_SRC_LSE 0x005 -#define STM32_SRC_LSI 0x006 /** System clock */ -#define STM32_SRC_SYSCLK 0x007 +/* defined in stm32_common_clocks.h */ +/** Fixed clocks */ +/* Low speed clocks defined in stm32_common_clocks.h */ +#define STM32_SRC_HSI (STM32_SRC_LSI + 1) +#define STM32_SRC_HSI48 (STM32_SRC_HSI + 1) +#define STM32_SRC_MSI (STM32_SRC_HSI48 + 1) +#define STM32_SRC_HSE (STM32_SRC_MSI + 1) /** Peripheral bus clock */ -#define STM32_SRC_PCLK 0x008 +#define STM32_SRC_PCLK (STM32_SRC_HSE + 1) /** PLL clock outputs */ -#define STM32_SRC_PLL_P 0x009 -#define STM32_SRC_PLL_Q 0x00a -#define STM32_SRC_PLL_R 0x00b +#define STM32_SRC_PLL_P (STM32_SRC_PCLK + 1) +#define STM32_SRC_PLL_Q (STM32_SRC_PLL_P + 1) +#define STM32_SRC_PLL_R (STM32_SRC_PLL_Q + 1) #define STM32_CLOCK_REG_MASK 0xFFU #define STM32_CLOCK_REG_SHIFT 0U @@ -92,7 +93,5 @@ #define USB_SEL(val) STM32_CLOCK(val, 3, 12, CCIPR2_REG) /** BDCR devices */ #define RTC_SEL(val) STM32_CLOCK(val, 3, 8, BDCR_REG) -/** Dummy: Add a specificier when no selection is possible */ -#define NO_SEL 0xFF #endif /* ZEPHYR_INCLUDE_DT_BINDINGS_CLOCK_STM32G0_CLOCK_H_ */ diff --git a/include/zephyr/dt-bindings/clock/stm32g4_clock.h b/include/zephyr/dt-bindings/clock/stm32g4_clock.h index d2720fa0b7f..0cc0b1be2dc 100644 --- a/include/zephyr/dt-bindings/clock/stm32g4_clock.h +++ b/include/zephyr/dt-bindings/clock/stm32g4_clock.h @@ -6,6 +6,8 @@ #ifndef ZEPHYR_INCLUDE_DT_BINDINGS_CLOCK_STM32G4_CLOCK_H_ #define ZEPHYR_INCLUDE_DT_BINDINGS_CLOCK_STM32G4_CLOCK_H_ +#include "stm32_common_clocks.h" + /** Bus clocks */ #define STM32_CLOCK_BUS_AHB1 0x048 #define STM32_CLOCK_BUS_AHB2 0x04c @@ -20,21 +22,21 @@ /** Domain clocks */ /* RM0440, § Clock configuration register (RCC_CCIPRx) */ -/** Fixed clocks */ -#define STM32_SRC_HSI 0x001 -#define STM32_SRC_HSI48 0x002 -#define STM32_SRC_HSE 0x003 -#define STM32_SRC_LSE 0x004 -#define STM32_SRC_LSI 0x005 -#define STM32_SRC_MSI 0x006 /** System clock */ -#define STM32_SRC_SYSCLK 0x007 +/* defined in stm32_common_clocks.h */ + +/** Fixed clocks */ +/* Low speed clocks defined in stm32_common_clocks.h */ +#define STM32_SRC_HSI (STM32_SRC_LSI + 1) +#define STM32_SRC_HSI48 (STM32_SRC_HSI + 1) +#define STM32_SRC_HSE (STM32_SRC_HSI48 + 1) +#define STM32_SRC_MSI (STM32_SRC_HSE + 1) /** Bus clock */ -#define STM32_SRC_PCLK 0x008 +#define STM32_SRC_PCLK (STM32_SRC_MSI + 1) /** PLL clock outputs */ -#define STM32_SRC_PLL_P 0x009 -#define STM32_SRC_PLL_Q 0x00a -#define STM32_SRC_PLL_R 0x00b +#define STM32_SRC_PLL_P (STM32_SRC_PCLK + 1) +#define STM32_SRC_PLL_Q (STM32_SRC_PLL_P + 1) +#define STM32_SRC_PLL_R (STM32_SRC_PLL_Q + 1) /* TODO: PLLSAI clocks */ #define STM32_CLOCK_REG_MASK 0xFFU @@ -95,7 +97,5 @@ #define QSPI_SEL(val) STM32_CLOCK(val, 3, 20, CCIPR2_REG) /** BDCR devices */ #define RTC_SEL(val) STM32_CLOCK(val, 3, 8, BDCR_REG) -/** Dummy: Add a specificier when no selection is possible */ -#define NO_SEL 0xFF #endif /* ZEPHYR_INCLUDE_DT_BINDINGS_CLOCK_STM32G4_CLOCK_H_ */ diff --git a/include/zephyr/dt-bindings/clock/stm32h5_clock.h b/include/zephyr/dt-bindings/clock/stm32h5_clock.h index c5172c4e6b6..070f3b3aad4 100644 --- a/include/zephyr/dt-bindings/clock/stm32h5_clock.h +++ b/include/zephyr/dt-bindings/clock/stm32h5_clock.h @@ -6,33 +6,33 @@ #ifndef ZEPHYR_INCLUDE_DT_BINDINGS_CLOCK_STM32H5_CLOCK_H_ #define ZEPHYR_INCLUDE_DT_BINDINGS_CLOCK_STM32H5_CLOCK_H_ +#include "stm32_common_clocks.h" + /** Domain clocks */ /* RM0481/0492, Table 47 Kernel clock distribution summary */ -/** PLL outputs */ -#define STM32_SRC_PLL1_P 0x001 -#define STM32_SRC_PLL1_Q 0x002 -#define STM32_SRC_PLL1_R 0x003 -#define STM32_SRC_PLL2_P 0x004 -#define STM32_SRC_PLL2_Q 0x005 -#define STM32_SRC_PLL2_R 0x006 -#define STM32_SRC_PLL3_P 0x007 -#define STM32_SRC_PLL3_Q 0x008 -#define STM32_SRC_PLL3_R 0x009 +/** System clock */ +/* defined in stm32_common_clocks.h */ /** Fixed clocks */ -#define STM32_SRC_HSE 0x00A -#define STM32_SRC_LSE 0x00B -#define STM32_SRC_LSI 0x00C -#define STM32_SRC_CSI 0x00D -#define STM32_SRC_HSI 0x00E -#define STM32_SRC_HSI48 0x00F - -/** Core clock */ -#define STM32_SRC_SYSCLK 0x011 - +/* Low speed clocks defined in stm32_common_clocks.h */ +#define STM32_SRC_HSE (STM32_SRC_LSI + 1) +#define STM32_SRC_CSI (STM32_SRC_HSE + 1) +#define STM32_SRC_HSI (STM32_SRC_CSI + 1) +#define STM32_SRC_HSI48 (STM32_SRC_HSI + 1) +/** PLL outputs */ +#define STM32_SRC_PLL1_P (STM32_SRC_HSI48 + 1) +#define STM32_SRC_PLL1_Q (STM32_SRC_PLL1_P + 1) +#define STM32_SRC_PLL1_R (STM32_SRC_PLL1_Q + 1) +#define STM32_SRC_PLL2_P (STM32_SRC_PLL1_R + 1) +#define STM32_SRC_PLL2_Q (STM32_SRC_PLL2_P + 1) +#define STM32_SRC_PLL2_R (STM32_SRC_PLL2_Q + 1) +#define STM32_SRC_PLL3_P (STM32_SRC_PLL2_R + 1) +#define STM32_SRC_PLL3_Q (STM32_SRC_PLL3_P + 1) +#define STM32_SRC_PLL3_R (STM32_SRC_PLL3_Q + 1) /** Clock muxes */ -#define STM32_SRC_CKPER 0x012 +#define STM32_SRC_CKPER (STM32_SRC_PLL3_R + 1) + /** Bus clocks */ #define STM32_CLOCK_BUS_AHB1 0x088 diff --git a/include/zephyr/dt-bindings/clock/stm32h7_clock.h b/include/zephyr/dt-bindings/clock/stm32h7_clock.h index d3507bc2fdb..02ed14f2a7b 100644 --- a/include/zephyr/dt-bindings/clock/stm32h7_clock.h +++ b/include/zephyr/dt-bindings/clock/stm32h7_clock.h @@ -6,34 +6,37 @@ #ifndef ZEPHYR_INCLUDE_DT_BINDINGS_CLOCK_STM32H7_CLOCK_H_ #define ZEPHYR_INCLUDE_DT_BINDINGS_CLOCK_STM32H7_CLOCK_H_ +#include "stm32_common_clocks.h" + /** Domain clocks */ /* RM0468, Table 56 Kernel clock dictribution summary */ +/** System clock */ +/* defined in stm32_common_clocks.h */ + +/** Fixed clocks */ +/* Low speed clocks defined in stm32_common_clocks.h */ +#define STM32_SRC_HSE (STM32_SRC_LSI + 1) +#define STM32_SRC_HSI48 (STM32_SRC_HSE + 1) +#define STM32_SRC_HSI_KER (STM32_SRC_HSI48 + 1) /* HSI + HSIKERON */ +#define STM32_SRC_CSI_KER (STM32_SRC_HSI_KER + 1) /* CSI + CSIKERON */ /** PLL outputs */ -#define STM32_SRC_PLL1_P 0x001 -#define STM32_SRC_PLL1_Q 0x002 -#define STM32_SRC_PLL1_R 0x003 -#define STM32_SRC_PLL2_P 0x004 -#define STM32_SRC_PLL2_Q 0x005 -#define STM32_SRC_PLL2_R 0x006 -#define STM32_SRC_PLL3_P 0x007 -#define STM32_SRC_PLL3_Q 0x008 -#define STM32_SRC_PLL3_R 0x009 -/** Oscillators */ -#define STM32_SRC_HSE 0x00A -#define STM32_SRC_LSE 0x00B -#define STM32_SRC_LSI 0x00C -#define STM32_SRC_HSI48 0x00D -#define STM32_SRC_HSI_KER 0x00E /* HSI + HSIKERON */ -#define STM32_SRC_CSI_KER 0x00F /* CSI + CSIKERON */ -/** Core clock */ -#define STM32_SRC_SYSCLK 0x010 -/** Others: Not yet supported */ -/* #define STM32_SRC_I2SCKIN 0x011 */ -/* #define STM32_SRC_SPDIFRX 0x012 */ +#define STM32_SRC_PLL1_P (STM32_SRC_CSI_KER + 1) +#define STM32_SRC_PLL1_Q (STM32_SRC_PLL1_P + 1) +#define STM32_SRC_PLL1_R (STM32_SRC_PLL1_Q + 1) +#define STM32_SRC_PLL2_P (STM32_SRC_PLL1_R + 1) +#define STM32_SRC_PLL2_Q (STM32_SRC_PLL2_P + 1) +#define STM32_SRC_PLL2_R (STM32_SRC_PLL2_Q + 1) +#define STM32_SRC_PLL3_P (STM32_SRC_PLL2_R + 1) +#define STM32_SRC_PLL3_Q (STM32_SRC_PLL3_P + 1) +#define STM32_SRC_PLL3_R (STM32_SRC_PLL3_Q + 1) /** Clock muxes */ -#define STM32_SRC_CKPER 0x013 +#define STM32_SRC_CKPER (STM32_SRC_PLL3_R + 1) +/** Others: Not yet supported */ +/* #define STM32_SRC_I2SCKIN TBD */ +/* #define STM32_SRC_SPDIFRX TBD */ + /** Bus clocks */ #define STM32_CLOCK_BUS_AHB3 0x0D4 @@ -129,7 +132,5 @@ #define SPI6_SEL(val) STM32_CLOCK(val, 7, 28, D3CCIPR_REG) /** BDCR devices */ #define RTC_SEL(val) STM32_CLOCK(val, 3, 8, BDCR_REG) -/** Dummy: Add a specifier when no selection is possible, value may not occur in used RCC regs */ -#define NO_SEL 0xFF #endif /* ZEPHYR_INCLUDE_DT_BINDINGS_CLOCK_STM32H7_CLOCK_H_ */ diff --git a/include/zephyr/dt-bindings/clock/stm32l0_clock.h b/include/zephyr/dt-bindings/clock/stm32l0_clock.h index a6e5565a2b5..5c4d80a2b34 100644 --- a/include/zephyr/dt-bindings/clock/stm32l0_clock.h +++ b/include/zephyr/dt-bindings/clock/stm32l0_clock.h @@ -6,6 +6,8 @@ #ifndef ZEPHYR_INCLUDE_DT_BINDINGS_CLOCK_STM32L0_CLOCK_H_ #define ZEPHYR_INCLUDE_DT_BINDINGS_CLOCK_STM32L0_CLOCK_H_ +#include "stm32_common_clocks.h" + /** Bus gatting clocks */ #define STM32_CLOCK_BUS_IOP 0x02c #define STM32_CLOCK_BUS_AHB1 0x030 @@ -18,16 +20,16 @@ /** Domain clocks */ /* RM0367, §7.3.20 Clock configuration register (RCC_CCIPR) */ -/** Fixed clocks */ -#define STM32_SRC_HSE 0x001 -#define STM32_SRC_LSE 0x002 -#define STM32_SRC_LSI 0x003 -#define STM32_SRC_HSI 0x004 -#define STM32_SRC_HSI48 0x005 /** System clock */ -#define STM32_SRC_SYSCLK 0x006 +/* defined in stm32_common_clocks.h */ + +/** Fixed clocks */ +/* Low speed clocks defined in stm32_common_clocks.h */ +#define STM32_SRC_HSE (STM32_SRC_LSI + 1) +#define STM32_SRC_HSI (STM32_SRC_HSE + 1) +#define STM32_SRC_HSI48 (STM32_SRC_HSI + 1) /** Bus clock */ -#define STM32_SRC_PCLK 0x007 +#define STM32_SRC_PCLK (STM32_SRC_HSI48 + 1) #define STM32_CLOCK_REG_MASK 0xFFU #define STM32_CLOCK_REG_SHIFT 0U @@ -74,7 +76,5 @@ #define HSI48_SEL(val) STM32_CLOCK(val, 1, 26, CCIPR_REG) /** CSR devices */ #define RTC_SEL(val) STM32_CLOCK(val, 3, 16, CSR_REG) -/** Dummy: Add a specificier when no selection is possible */ -#define NO_SEL 0xFF #endif /* ZEPHYR_INCLUDE_DT_BINDINGS_CLOCK_STM32L0_CLOCK_H_ */ diff --git a/include/zephyr/dt-bindings/clock/stm32l1_clock.h b/include/zephyr/dt-bindings/clock/stm32l1_clock.h index ae580af85b4..1dd1fbb90c2 100644 --- a/include/zephyr/dt-bindings/clock/stm32l1_clock.h +++ b/include/zephyr/dt-bindings/clock/stm32l1_clock.h @@ -6,6 +6,8 @@ #ifndef ZEPHYR_INCLUDE_DT_BINDINGS_CLOCK_STM32L1_CLOCK_H_ #define ZEPHYR_INCLUDE_DT_BINDINGS_CLOCK_STM32L1_CLOCK_H_ +#include "stm32_common_clocks.h" + /** Bus gatting clocks */ #define STM32_CLOCK_BUS_AHB1 0x01c #define STM32_CLOCK_BUS_APB2 0x020 @@ -17,12 +19,11 @@ /** Domain clocks */ /* RM0038.pdf, §6.3.14 Control/status register (RCC_CSR) */ -/** Fixed clocks */ -#define STM32_SRC_HSE 0x001 -#define STM32_SRC_LSE 0x002 -#define STM32_SRC_LSI 0x003 /** System clock */ -#define STM32_SRC_SYSCLK 0x004 +/* defined in stm32_common_clocks.h */ +/** Fixed clocks */ +/* Low speed clocks defined in stm32_common_clocks.h */ +#define STM32_SRC_HSE (STM32_SRC_LSI + 1) #define STM32_CLOCK_REG_MASK 0xFFU #define STM32_CLOCK_REG_SHIFT 0U @@ -57,7 +58,4 @@ #define RTC_SEL(val) STM32_CLOCK(val, 3, 16, CSR_REG) -/** Dummy: Add a specificier when no selection is possible */ -#define NO_SEL 0xFF - #endif /* ZEPHYR_INCLUDE_DT_BINDINGS_CLOCK_STM32L1_CLOCK_H_ */ diff --git a/include/zephyr/dt-bindings/clock/stm32l4_clock.h b/include/zephyr/dt-bindings/clock/stm32l4_clock.h index 3a042bc34e9..8249a1bf171 100644 --- a/include/zephyr/dt-bindings/clock/stm32l4_clock.h +++ b/include/zephyr/dt-bindings/clock/stm32l4_clock.h @@ -6,6 +6,8 @@ #ifndef ZEPHYR_INCLUDE_DT_BINDINGS_CLOCK_STM32L4_CLOCK_H_ #define ZEPHYR_INCLUDE_DT_BINDINGS_CLOCK_STM32L4_CLOCK_H_ +#include "stm32_common_clocks.h" + /** Bus clocks */ #define STM32_CLOCK_BUS_AHB1 0x048 #define STM32_CLOCK_BUS_AHB2 0x04c @@ -20,20 +22,19 @@ /** Domain clocks */ /* RM0351/RM0432/RM0438, § Clock configuration register (RCC_CCIPRx) */ -/** Fixed clocks */ -#define STM32_SRC_HSI 0x001 -#define STM32_SRC_HSI48 0x002 -#define STM32_SRC_LSE 0x003 -#define STM32_SRC_LSI 0x004 -#define STM32_SRC_MSI 0x005 /** System clock */ -#define STM32_SRC_SYSCLK 0x006 +/* defined in stm32_common_clocks.h */ +/** Fixed clocks */ +/* Low speed clocks defined in stm32_common_clocks.h */ +#define STM32_SRC_HSI (STM32_SRC_LSI + 1) +#define STM32_SRC_HSI48 (STM32_SRC_HSI + 1) +#define STM32_SRC_MSI (STM32_SRC_HSI48 + 1) /** Bus clock */ -#define STM32_SRC_PCLK 0x007 +#define STM32_SRC_PCLK (STM32_SRC_MSI + 1) /** PLL clock outputs */ -#define STM32_SRC_PLL_P 0x008 -#define STM32_SRC_PLL_Q 0x009 -#define STM32_SRC_PLL_R 0x00a +#define STM32_SRC_PLL_P (STM32_SRC_PCLK + 1) +#define STM32_SRC_PLL_Q (STM32_SRC_PLL_P + 1) +#define STM32_SRC_PLL_R (STM32_SRC_PLL_Q + 1) /* TODO: PLLSAI clocks */ #define STM32_CLOCK_REG_MASK 0xFFU @@ -101,7 +102,5 @@ #define OSPI_SEL(val) STM32_CLOCK(val, 3, 20, CCIPR2_REG) /** BDCR devices */ #define RTC_SEL(val) STM32_CLOCK(val, 3, 8, BDCR_REG) -/** Dummy: Add a specificier when no selection is possible */ -#define NO_SEL 0xFF #endif /* ZEPHYR_INCLUDE_DT_BINDINGS_CLOCK_STM32L4_CLOCK_H_ */ diff --git a/include/zephyr/dt-bindings/clock/stm32u5_clock.h b/include/zephyr/dt-bindings/clock/stm32u5_clock.h index ca4b774d802..6f240fb37b3 100644 --- a/include/zephyr/dt-bindings/clock/stm32u5_clock.h +++ b/include/zephyr/dt-bindings/clock/stm32u5_clock.h @@ -7,32 +7,32 @@ #ifndef ZEPHYR_INCLUDE_DT_BINDINGS_CLOCK_STM32U5_CLOCK_H_ #define ZEPHYR_INCLUDE_DT_BINDINGS_CLOCK_STM32U5_CLOCK_H_ +#include "stm32_common_clocks.h" + /** Domain clocks */ /* RM0468, Table 56 Kernel clock distribution summary */ -/** PLL outputs */ -#define STM32_SRC_PLL1_P 0x001 -#define STM32_SRC_PLL1_Q 0x002 -#define STM32_SRC_PLL1_R 0x003 -#define STM32_SRC_PLL2_P 0x004 -#define STM32_SRC_PLL2_Q 0x005 -#define STM32_SRC_PLL2_R 0x006 -#define STM32_SRC_PLL3_P 0x007 -#define STM32_SRC_PLL3_Q 0x008 -#define STM32_SRC_PLL3_R 0x009 +/** System clock */ +/* defined in stm32_common_clocks.h */ /** Fixed clocks */ -#define STM32_SRC_HSE 0x00A -#define STM32_SRC_LSE 0x00B -#define STM32_SRC_LSI 0x00C -#define STM32_SRC_HSI16 0x00D -#define STM32_SRC_HSI48 0x00E -#define STM32_SRC_MSIS 0x00F -#define STM32_SRC_MSIK 0x010 -/** Core clock */ -#define STM32_SRC_SYSCLK 0x011 +#define STM32_SRC_HSE (STM32_SRC_LSI + 1) +#define STM32_SRC_HSI16 (STM32_SRC_HSE + 1) +#define STM32_SRC_HSI48 (STM32_SRC_HSI16 + 1) +#define STM32_SRC_MSIS (STM32_SRC_HSI48 + 1) +#define STM32_SRC_MSIK (STM32_SRC_MSIS + 1) +/** PLL outputs */ +#define STM32_SRC_PLL1_P (STM32_SRC_MSIK + 1) +#define STM32_SRC_PLL1_Q (STM32_SRC_PLL1_P + 1) +#define STM32_SRC_PLL1_R (STM32_SRC_PLL1_Q + 1) +#define STM32_SRC_PLL2_P (STM32_SRC_PLL1_R + 1) +#define STM32_SRC_PLL2_Q (STM32_SRC_PLL2_P + 1) +#define STM32_SRC_PLL2_R (STM32_SRC_PLL2_Q + 1) +#define STM32_SRC_PLL3_P (STM32_SRC_PLL2_R + 1) +#define STM32_SRC_PLL3_Q (STM32_SRC_PLL3_P + 1) +#define STM32_SRC_PLL3_R (STM32_SRC_PLL3_Q + 1) /** Clock muxes */ -/* #define STM32_SRC_ICLK 0x012 */ +/* #define STM32_SRC_ICLK TBD */ /** Bus clocks */ #define STM32_CLOCK_BUS_AHB1 0x088 @@ -126,10 +126,5 @@ #define ADF1_SEL(val) STM32_CLOCK(val, 7, 16, CCIPR3_REG) /** BDCR devices */ #define RTC_SEL(val) STM32_CLOCK(val, 3, 8, BDCR_REG) -/** - * Dummy: Add a specifier when no selection is possible, value may not occur - * in used RCC regs - */ -#define NO_SEL 0xFF #endif /* ZEPHYR_INCLUDE_DT_BINDINGS_CLOCK_STM32U5_CLOCK_H_ */ diff --git a/include/zephyr/dt-bindings/clock/stm32wb_clock.h b/include/zephyr/dt-bindings/clock/stm32wb_clock.h index f339f2ac19f..d90b640d2dc 100644 --- a/include/zephyr/dt-bindings/clock/stm32wb_clock.h +++ b/include/zephyr/dt-bindings/clock/stm32wb_clock.h @@ -6,6 +6,8 @@ #ifndef ZEPHYR_INCLUDE_DT_BINDINGS_CLOCK_STM32WB_CLOCK_H_ #define ZEPHYR_INCLUDE_DT_BINDINGS_CLOCK_STM32WB_CLOCK_H_ +#include "stm32_common_clocks.h" + /** Bus clocks */ #define STM32_CLOCK_BUS_AHB1 0x048 #define STM32_CLOCK_BUS_AHB2 0x04c @@ -20,21 +22,20 @@ /** Domain clocks */ /* RM0434, § Clock configuration register (RCC_CCIPRx) */ -/** Fixed clocks */ -#define STM32_SRC_HSI 0x001 -#define STM32_SRC_HSI48 0x002 -#define STM32_SRC_LSE 0x003 -#define STM32_SRC_LSI 0x004 -#define STM32_SRC_MSI 0x005 -#define STM32_SRC_HSE 0x006 /** System clock */ -#define STM32_SRC_SYSCLK 0x007 +/* defined in stm32_common_clocks.h */ +/** Fixed clocks */ +/* Low speed clocks defined in stm32_common_clocks.h */ +#define STM32_SRC_HSI (STM32_SRC_LSI + 1) +#define STM32_SRC_HSI48 (STM32_SRC_HSI + 1) +#define STM32_SRC_MSI (STM32_SRC_HSI48 + 1) +#define STM32_SRC_HSE (STM32_SRC_MSI + 1) /** Bus clock */ -#define STM32_SRC_PCLK 0x008 +#define STM32_SRC_PCLK (STM32_SRC_HSE + 1) /** PLL clock outputs */ -#define STM32_SRC_PLL_P 0x009 -#define STM32_SRC_PLL_Q 0x00a -#define STM32_SRC_PLL_R 0x00b +#define STM32_SRC_PLL_P (STM32_SRC_PCLK + 1) +#define STM32_SRC_PLL_Q (STM32_SRC_PLL_P + 1) +#define STM32_SRC_PLL_R (STM32_SRC_PLL_Q + 1) /* TODO: PLLSAI clocks */ #define STM32_CLOCK_REG_MASK 0xFFU @@ -90,7 +91,5 @@ #define RTC_SEL(val) STM32_CLOCK(val, 3, 8, BDCR_REG) /** CSR devices */ #define RFWKP_SEL(val) STM32_CLOCK(val, 3, 14, CSR_REG) -/** Dummy: Add a specificier when no selection is possible */ -#define NO_SEL 0xFF #endif /* ZEPHYR_INCLUDE_DT_BINDINGS_CLOCK_STM32WB_CLOCK_H_ */ diff --git a/include/zephyr/dt-bindings/clock/stm32wba_clock.h b/include/zephyr/dt-bindings/clock/stm32wba_clock.h index 50ec4703e3f..4dc686e8943 100644 --- a/include/zephyr/dt-bindings/clock/stm32wba_clock.h +++ b/include/zephyr/dt-bindings/clock/stm32wba_clock.h @@ -6,22 +6,22 @@ #ifndef ZEPHYR_INCLUDE_DT_BINDINGS_CLOCK_STM32WBA_CLOCK_H_ #define ZEPHYR_INCLUDE_DT_BINDINGS_CLOCK_STM32WBA_CLOCK_H_ +#include "stm32_common_clocks.h" + /** Peripheral clock sources */ /* RM0493, Figure 30, clock tree */ -/** PLL outputs */ -#define STM32_SRC_PLL1_P 0x001 -#define STM32_SRC_PLL1_Q 0x002 -#define STM32_SRC_PLL1_R 0x003 +/** System clock */ +/* defined in stm32_common_clocks.h */ /** Fixed clocks */ -#define STM32_SRC_HSE 0x004 -#define STM32_SRC_LSE 0x005 -#define STM32_SRC_LSI 0x006 -#define STM32_SRC_HSI16 0x007 -/** Core clock */ -#define STM32_SRC_SYSCLK 0x08 - +/* Low speed clocks defined in stm32_common_clocks.h */ +#define STM32_SRC_HSE (STM32_SRC_LSI + 1) +#define STM32_SRC_HSI16 (STM32_SRC_HSE + 1) +/** PLL outputs */ +#define STM32_SRC_PLL1_P (STM32_SRC_HSI16 + 1) +#define STM32_SRC_PLL1_Q (STM32_SRC_PLL1_P + 1) +#define STM32_SRC_PLL1_R (STM32_SRC_PLL1_Q + 1) #define STM32_SRC_CLOCK_MIN STM32_SRC_PLL1_P #define STM32_SRC_CLOCK_MAX STM32_SRC_SYSCLK diff --git a/include/zephyr/dt-bindings/clock/stm32wl_clock.h b/include/zephyr/dt-bindings/clock/stm32wl_clock.h index 7bff72937c1..081490d37e1 100644 --- a/include/zephyr/dt-bindings/clock/stm32wl_clock.h +++ b/include/zephyr/dt-bindings/clock/stm32wl_clock.h @@ -6,6 +6,8 @@ #ifndef ZEPHYR_INCLUDE_DT_BINDINGS_CLOCK_STM32WL_CLOCK_H_ #define ZEPHYR_INCLUDE_DT_BINDINGS_CLOCK_STM32WL_CLOCK_H_ +#include "stm32_common_clocks.h" + /** Bus clocks */ #define STM32_CLOCK_BUS_AHB1 0x048 #define STM32_CLOCK_BUS_AHB2 0x04c @@ -21,19 +23,19 @@ /** Domain clocks */ /* RM0461, §6.4.29 Clock configuration register (RCC_CFGR3) */ -/** Fixed clocks */ -#define STM32_SRC_HSI 0x001 -#define STM32_SRC_LSE 0x002 -#define STM32_SRC_LSI 0x003 -/* #define STM32_SRC_HSI48 0x004 */ + /** System clock */ -#define STM32_SRC_SYSCLK 0x005 +/* defined in stm32_common_clocks.h */ +/** Fixed clocks */ +/* Low speed clocks defined in stm32_common_clocks.h */ +#define STM32_SRC_HSI (STM32_SRC_LSI + 1) +/* #define STM32_SRC_HSI48 TBD */ /** Bus clock */ -#define STM32_SRC_PCLK 0x006 +#define STM32_SRC_PCLK (STM32_SRC_HSI + 1) /** PLL clock outputs */ -#define STM32_SRC_PLL_P 0x007 -#define STM32_SRC_PLL_Q 0x008 -#define STM32_SRC_PLL_R 0x009 +#define STM32_SRC_PLL_P (STM32_SRC_PCLK + 1) +#define STM32_SRC_PLL_Q (STM32_SRC_PLL_P + 1) +#define STM32_SRC_PLL_R (STM32_SRC_PLL_Q + 1) #define STM32_CLOCK_REG_MASK 0xFFU #define STM32_CLOCK_REG_SHIFT 0U @@ -85,7 +87,5 @@ #define RNG_SEL(val) STM32_CLOCK(val, 3, 30, CCIPR_REG) /** BDCR devices */ #define RTC_SEL(val) STM32_CLOCK(val, 3, 8, BDCR_REG) -/** Dummy: Add a specificier when no selection is possible */ -#define NO_SEL 0xFF #endif /* ZEPHYR_INCLUDE_DT_BINDINGS_CLOCK_STM32WL_CLOCK_H_ */ From 7a2e74604f8bc1ba3ab913858034b057ca3a3d61 Mon Sep 17 00:00:00 2001 From: Erwan Gouriou Date: Wed, 20 Dec 2023 17:17:56 +0100 Subject: [PATCH 2278/3723] soc: stm32: common: Define STM32_LPTIM_CLOCK from device tree inputs Now that: 1 - LS Clocks sources values are identical accross series 2 - We're able to extract this value from device tree define STM32_LPTIM_CLOCK choice symbol from device tree Signed-off-by: Erwan Gouriou --- soc/arm/st_stm32/common/Kconfig.defconfig.series | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/soc/arm/st_stm32/common/Kconfig.defconfig.series b/soc/arm/st_stm32/common/Kconfig.defconfig.series index c1d0237e1ee..5b586516d83 100644 --- a/soc/arm/st_stm32/common/Kconfig.defconfig.series +++ b/soc/arm/st_stm32/common/Kconfig.defconfig.series @@ -45,6 +45,11 @@ config SYS_CLOCK_TICKS_PER_SEC default 250 if "$(dt_node_int_prop_int,$(DT_STM32_LPTIM_PATH),$(DT_ST_PRESCALER))" = 128 depends on STM32_LPTIM_TIMER && STM32_LPTIM_CLOCK_LSI +choice STM32_LPTIM_CLOCK + default STM32_LPTIM_CLOCK_LSE if "$(dt_node_ph_array_prop_int,$(DT_STM32_LPTIM_PATH),clocks,1,bus)" = 2 + default STM32_LPTIM_CLOCK_LSI if "$(dt_node_ph_array_prop_int,$(DT_STM32_LPTIM_PATH),clocks,1,bus)" = 3 +endchoice + config CLOCK_CONTROL_STM32_CUBE default y depends on CLOCK_CONTROL From 19cc4779e5526f7c9696625d18545288b03e65e5 Mon Sep 17 00:00:00 2001 From: Erwan Gouriou Date: Wed, 20 Dec 2023 17:21:09 +0100 Subject: [PATCH 2279/3723] boards: stm32: Remove manual definition of CONFIG_STM32_LPTIM_CLOCK_LSE CONFIG_STM32_LPTIM_CLOCK_LSE definition is now defined directly from device tree, remove from boards definition. Solving systematic warning about CONFIG_STM32_LPTIM_CLOCK_LSE being selected with unsatisfied dependencies. Signed-off-by: Erwan Gouriou --- boards/arm/b_u585i_iot02a/b_u585i_iot02a_defconfig | 3 --- boards/arm/b_u585i_iot02a/b_u585i_iot02a_ns_defconfig | 3 --- boards/arm/disco_l475_iot1/disco_l475_iot1_defconfig | 3 --- boards/arm/nucleo_g431rb/nucleo_g431rb_defconfig | 3 --- boards/arm/nucleo_wb55rg/nucleo_wb55rg_defconfig | 3 --- boards/arm/nucleo_wba52cg/nucleo_wba52cg_defconfig | 3 --- boards/arm/nucleo_wba55cg/nucleo_wba55cg_defconfig | 3 --- boards/arm/sensortile_box_pro/sensortile_box_pro_defconfig | 3 --- boards/arm/stm32l562e_dk/stm32l562e_dk_defconfig | 3 --- boards/arm/stm32l562e_dk/stm32l562e_dk_ns_defconfig | 3 --- boards/arm/weact_stm32g431_core/weact_stm32g431_core_defconfig | 3 --- 11 files changed, 33 deletions(-) diff --git a/boards/arm/b_u585i_iot02a/b_u585i_iot02a_defconfig b/boards/arm/b_u585i_iot02a/b_u585i_iot02a_defconfig index d84deca3fe0..c034f717771 100644 --- a/boards/arm/b_u585i_iot02a/b_u585i_iot02a_defconfig +++ b/boards/arm/b_u585i_iot02a/b_u585i_iot02a_defconfig @@ -18,6 +18,3 @@ CONFIG_UART_CONSOLE=y # enable pin controller CONFIG_PINCTRL=y - -# LSE defined as LPTIM clock source by the DTS -CONFIG_STM32_LPTIM_CLOCK_LSE=y diff --git a/boards/arm/b_u585i_iot02a/b_u585i_iot02a_ns_defconfig b/boards/arm/b_u585i_iot02a/b_u585i_iot02a_ns_defconfig index 473e6e2fbb0..4b6f6ba7f5c 100644 --- a/boards/arm/b_u585i_iot02a/b_u585i_iot02a_ns_defconfig +++ b/boards/arm/b_u585i_iot02a/b_u585i_iot02a_ns_defconfig @@ -22,6 +22,3 @@ CONFIG_PINCTRL=y CONFIG_ARM_TRUSTZONE_M=y CONFIG_RUNTIME_NMI=y CONFIG_TRUSTED_EXECUTION_NONSECURE=y - -# LSE defined as LPTIM clock source by the DTS -CONFIG_STM32_LPTIM_CLOCK_LSE=y diff --git a/boards/arm/disco_l475_iot1/disco_l475_iot1_defconfig b/boards/arm/disco_l475_iot1/disco_l475_iot1_defconfig index 072929abda8..a25b1eff645 100644 --- a/boards/arm/disco_l475_iot1/disco_l475_iot1_defconfig +++ b/boards/arm/disco_l475_iot1/disco_l475_iot1_defconfig @@ -26,6 +26,3 @@ CONFIG_HW_STACK_PROTECTION=y # enable pin controller CONFIG_PINCTRL=y - -# LSE defined as LPTIM clock source by the DTS -CONFIG_STM32_LPTIM_CLOCK_LSE=y diff --git a/boards/arm/nucleo_g431rb/nucleo_g431rb_defconfig b/boards/arm/nucleo_g431rb/nucleo_g431rb_defconfig index 25dcaf3dfb7..92c2363d2d8 100644 --- a/boards/arm/nucleo_g431rb/nucleo_g431rb_defconfig +++ b/boards/arm/nucleo_g431rb/nucleo_g431rb_defconfig @@ -24,6 +24,3 @@ CONFIG_HW_STACK_PROTECTION=y # enable pin controller CONFIG_PINCTRL=y - -# LSE defined as LPTIM clock source by the DTS -CONFIG_STM32_LPTIM_CLOCK_LSE=y diff --git a/boards/arm/nucleo_wb55rg/nucleo_wb55rg_defconfig b/boards/arm/nucleo_wb55rg/nucleo_wb55rg_defconfig index 88f9da2ff18..9fdd732848e 100644 --- a/boards/arm/nucleo_wb55rg/nucleo_wb55rg_defconfig +++ b/boards/arm/nucleo_wb55rg/nucleo_wb55rg_defconfig @@ -22,6 +22,3 @@ CONFIG_HW_STACK_PROTECTION=y # enable pin controller CONFIG_PINCTRL=y - -# LSE defined as LPTIM clock source by the DTS -CONFIG_STM32_LPTIM_CLOCK_LSE=y diff --git a/boards/arm/nucleo_wba52cg/nucleo_wba52cg_defconfig b/boards/arm/nucleo_wba52cg/nucleo_wba52cg_defconfig index ffadf13e845..9b917b0fc69 100644 --- a/boards/arm/nucleo_wba52cg/nucleo_wba52cg_defconfig +++ b/boards/arm/nucleo_wba52cg/nucleo_wba52cg_defconfig @@ -24,6 +24,3 @@ CONFIG_HW_STACK_PROTECTION=y # enable pin controller CONFIG_PINCTRL=y - -# LSE defined as LPTIM clock source by the DTS -CONFIG_STM32_LPTIM_CLOCK_LSE=y diff --git a/boards/arm/nucleo_wba55cg/nucleo_wba55cg_defconfig b/boards/arm/nucleo_wba55cg/nucleo_wba55cg_defconfig index 270c9c297f1..2c523d88019 100644 --- a/boards/arm/nucleo_wba55cg/nucleo_wba55cg_defconfig +++ b/boards/arm/nucleo_wba55cg/nucleo_wba55cg_defconfig @@ -26,8 +26,5 @@ CONFIG_HW_STACK_PROTECTION=y # enable pin controller CONFIG_PINCTRL=y -# LSE defined as LPTIM clock source by the DTS -CONFIG_STM32_LPTIM_CLOCK_LSE=y - # Enable the internal SMPS regulator CONFIG_POWER_SUPPLY_DIRECT_SMPS=y diff --git a/boards/arm/sensortile_box_pro/sensortile_box_pro_defconfig b/boards/arm/sensortile_box_pro/sensortile_box_pro_defconfig index a75aad1dad5..7a91dc1c195 100644 --- a/boards/arm/sensortile_box_pro/sensortile_box_pro_defconfig +++ b/boards/arm/sensortile_box_pro/sensortile_box_pro_defconfig @@ -32,6 +32,3 @@ CONFIG_USB_DEVICE_INITIALIZE_AT_BOOT=n # enable pin controller CONFIG_PINCTRL=y - -# LSE defined as LPTIM clock source by the DTS -CONFIG_STM32_LPTIM_CLOCK_LSE=y diff --git a/boards/arm/stm32l562e_dk/stm32l562e_dk_defconfig b/boards/arm/stm32l562e_dk/stm32l562e_dk_defconfig index c5537972912..6646832e7ef 100644 --- a/boards/arm/stm32l562e_dk/stm32l562e_dk_defconfig +++ b/boards/arm/stm32l562e_dk/stm32l562e_dk_defconfig @@ -24,6 +24,3 @@ CONFIG_HW_STACK_PROTECTION=y # enable pin controller CONFIG_PINCTRL=y - -# LSE defined as LPTIM clock source by the DTS -CONFIG_STM32_LPTIM_CLOCK_LSE=y diff --git a/boards/arm/stm32l562e_dk/stm32l562e_dk_ns_defconfig b/boards/arm/stm32l562e_dk/stm32l562e_dk_ns_defconfig index 289f8d82131..c28424d306a 100644 --- a/boards/arm/stm32l562e_dk/stm32l562e_dk_ns_defconfig +++ b/boards/arm/stm32l562e_dk/stm32l562e_dk_ns_defconfig @@ -25,6 +25,3 @@ CONFIG_TRUSTED_EXECUTION_NONSECURE=y # enable pin controller CONFIG_PINCTRL=y - -# LSE defined as LPTIM clock source by the DTS -CONFIG_STM32_LPTIM_CLOCK_LSE=y diff --git a/boards/arm/weact_stm32g431_core/weact_stm32g431_core_defconfig b/boards/arm/weact_stm32g431_core/weact_stm32g431_core_defconfig index aa9e67db821..0c9d0e2a185 100644 --- a/boards/arm/weact_stm32g431_core/weact_stm32g431_core_defconfig +++ b/boards/arm/weact_stm32g431_core/weact_stm32g431_core_defconfig @@ -10,9 +10,6 @@ CONFIG_SOC_STM32G431XX=y CONFIG_CLOCK_CONTROL=y CONFIG_PINCTRL=y -# LSE defined as LPTIM clock source by the DTS -CONFIG_STM32_LPTIM_CLOCK_LSE=y - CONFIG_ARM_MPU=y CONFIG_HW_STACK_PROTECTION=y From 0a2876de263caeeff6bacfa7a94a5e3b18d533dd Mon Sep 17 00:00:00 2001 From: Erwan Gouriou Date: Wed, 20 Dec 2023 17:24:12 +0100 Subject: [PATCH 2280/3723] drivers: timer: stm32: Clean up related to STM32_LPTIM_CLOCK Now that STM32_LPTIM_CLOCK choice symbol is defined from device tree, remove the prompt which was defining it as a user selectable entry. Remove the warning related to possible symbol misalignment with device tree setting. Signed-off-by: Erwan Gouriou --- drivers/timer/Kconfig.stm32_lptim | 2 +- drivers/timer/stm32_lptim_timer.c | 16 ---------------- 2 files changed, 1 insertion(+), 17 deletions(-) diff --git a/drivers/timer/Kconfig.stm32_lptim b/drivers/timer/Kconfig.stm32_lptim index d1e0d5cb81a..dc64ec5bda3 100644 --- a/drivers/timer/Kconfig.stm32_lptim +++ b/drivers/timer/Kconfig.stm32_lptim @@ -35,7 +35,7 @@ config STM32_LPTIM_CLOCK_LSE endchoice config STM32_LPTIM_CLOCK - int "LPTIM clock value" + int default 32768 if STM32_LPTIM_CLOCK_LSE default 32000 if STM32_LPTIM_CLOCK_LSI diff --git a/drivers/timer/stm32_lptim_timer.c b/drivers/timer/stm32_lptim_timer.c index 0a95c84af58..16e8b62c3d3 100644 --- a/drivers/timer/stm32_lptim_timer.c +++ b/drivers/timer/stm32_lptim_timer.c @@ -66,22 +66,6 @@ static uint32_t lptim_clock_freq = CONFIG_STM32_LPTIM_CLOCK; /* The prescaler given by the DTS and to apply to the lptim_clock_freq */ static uint32_t lptim_clock_presc = DT_PROP(DT_DRV_INST(0), st_prescaler); -#if (CONFIG_STM32_LPTIM_CLOCK_LSI) - -/* Kconfig defines the clock source as LSI : check coherency with DTS */ -#if (DT_INST_CLOCKS_CELL_BY_IDX(0, 1, bus) != STM32_SRC_LSI) -#warning CONFIG_STM32_LPTIM_CLOCK_LSI requires STM32_SRC_LSI defined as LPTIM domain clock -#endif /* STM32_SRC_LSI */ - -#elif (CONFIG_STM32_LPTIM_CLOCK_LSE) - -/* Kconfig defines the clock source as LSE : check coherency with DTS */ -#if (DT_INST_CLOCKS_CELL_BY_IDX(0, 1, bus) != STM32_SRC_LSE) -#warning CONFIG_STM32_LPTIM_CLOCK_LSE requires STM32_SRC_LSE defined as LPTIM domain clock -#endif /* STM32_SRC_LSE */ - -#endif /* CONFIG_STM32_LPTIM_CLOCK_LSI */ - /* Minimum nb of clock cycles to have to set autoreload register correctly */ #define LPTIM_GUARD_VALUE 2 From 4e7d64b1b45247de1e1d71a4402f5637b0fd0afe Mon Sep 17 00:00:00 2001 From: Aleksandr Khromykh Date: Tue, 9 Jan 2024 15:22:29 +0100 Subject: [PATCH 2281/3723] Bluetooth: Mesh: enable access responses randomization Enable by default the access layer responses random delays. Commit also adapts all mesh models, samples and babblesim tests to use random delay functionality correctly. Signed-off-by: Aleksandr Khromykh --- subsys/bluetooth/mesh/Kconfig | 15 +++++++++++++-- subsys/bluetooth/mesh/access.c | 10 ++++++++-- tests/bsim/bluetooth/mesh/src/test_access.c | 11 ++++++++--- tests/bsim/bluetooth/mesh/src/test_persistence.c | 6 ------ tests/bsim/bluetooth/mesh/src/test_provision.c | 10 ---------- .../access/access_transmit_delayable.sh | 2 +- .../priv_beacon/proxy_adv_multi_subnet_coex.sh | 2 +- 7 files changed, 31 insertions(+), 25 deletions(-) diff --git a/subsys/bluetooth/mesh/Kconfig b/subsys/bluetooth/mesh/Kconfig index 3ac9954d4de..50d7ca3fb83 100644 --- a/subsys/bluetooth/mesh/Kconfig +++ b/subsys/bluetooth/mesh/Kconfig @@ -639,6 +639,7 @@ config BT_MESH_LABEL_NO_RECOVER menuconfig BT_MESH_ACCESS_DELAYABLE_MSG bool "Access layer tx delayable message" + default y help Enable following of the message transmitting recommendations, the Access layer specification. The recommendations are optional. @@ -647,6 +648,16 @@ menuconfig BT_MESH_ACCESS_DELAYABLE_MSG if BT_MESH_ACCESS_DELAYABLE_MSG +config BT_MESH_ACCESS_DELAYABLE_MSG_CTX_ENABLED + bool "The delayable message in the notification message context" + default y + help + Controls whether the delayable message feature is enabled by default in + the message context of the opcode notifications. This allows the server part of any + model to not bother about additional context configuration to enable the delayable message. + Note that if this is disabled then all foundation models stop using the delayable message + functionality. + config BT_MESH_ACCESS_DELAYABLE_MSG_COUNT int "Number of simultaneously delayed messages" default 4 @@ -657,14 +668,14 @@ config BT_MESH_ACCESS_DELAYABLE_MSG_COUNT config BT_MESH_ACCESS_DELAYABLE_MSG_CHUNK_SIZE int "Maximum delayable message storage chunk" - default 20 + default 10 help Size of memory that Access layer uses to split model message to. It allocates a sufficient number of these chunks from the pool to store the full model payload. config BT_MESH_ACCESS_DELAYABLE_MSG_CHUNK_COUNT int "Maximum number of available chunks" - default 20 + default 40 help The maximum number of available chunks the Access layer allocates to store model payload. It is recommended to keep chunk size equal to the reasonable small value to prevent diff --git a/subsys/bluetooth/mesh/access.c b/subsys/bluetooth/mesh/access.c index c3ef6a40554..23fbb8e82c2 100644 --- a/subsys/bluetooth/mesh/access.c +++ b/subsys/bluetooth/mesh/access.c @@ -922,7 +922,7 @@ static void mod_publish(struct k_work *work) return; } - LOG_DBG("%u", k_uptime_get_32()); + LOG_DBG("timestamp: %u", k_uptime_get_32()); if (pub->count) { pub->count--; @@ -1504,6 +1504,10 @@ static int element_model_recv(struct bt_mesh_msg_ctx *ctx, struct net_buf_simple return ACCESS_STATUS_MESSAGE_NOT_UNDERSTOOD; } + if (IS_ENABLED(CONFIG_BT_MESH_ACCESS_DELAYABLE_MSG_CTX_ENABLED)) { + ctx->rnd_delay = true; + } + net_buf_simple_save(buf, &state); err = op->func(model, ctx, buf); net_buf_simple_restore(buf, &state); @@ -1578,7 +1582,9 @@ int bt_mesh_model_send(const struct bt_mesh_model *model, struct bt_mesh_msg_ctx } #if defined CONFIG_BT_MESH_ACCESS_DELAYABLE_MSG - if (ctx->rnd_delay) { + /* No sense to use delayable message for unicast loopback. */ + if (ctx->rnd_delay && + !(bt_mesh_has_addr(ctx->addr) && BT_MESH_ADDR_IS_UNICAST(ctx->addr))) { return bt_mesh_delayable_msg_manage(ctx, msg, bt_mesh_model_elem(model)->rt->addr, cb, cb_data); } diff --git a/tests/bsim/bluetooth/mesh/src/test_access.c b/tests/bsim/bluetooth/mesh/src/test_access.c index 5cb7d2e28e1..6967aa6d71c 100644 --- a/tests/bsim/bluetooth/mesh/src/test_access.c +++ b/tests/bsim/bluetooth/mesh/src/test_access.c @@ -102,11 +102,15 @@ static bool publish_allow; static int model1_update(const struct bt_mesh_model *model) { - model->pub->msg->data[1]++; + if (!publish_allow) { + return -1; + } + model->pub->msg->data[1]++; LOG_DBG("New pub: n: %d t: %d", model->pub->msg->data[1], k_uptime_get_32()); + k_sem_give(&publish_sem); - return publish_allow ? k_sem_give(&publish_sem), 0 : -1; + return 0; } static int test_msgf_handler(const struct bt_mesh_model *model, @@ -604,7 +608,8 @@ static void recv_delayable_check(int32_t interval, uint8_t count) LOG_DBG("Recv time: %d delta: %d boundaries: %d/%d", (int32_t)timestamp, time_delta, lower_boundary, upper_boundary); - ASSERT_IN_RANGE(time_delta, lower_boundary, upper_boundary + RX_JITTER_MAX); + ASSERT_IN_RANGE(time_delta, lower_boundary - RX_JITTER_MAX, + upper_boundary + RX_JITTER_MAX); } } diff --git a/tests/bsim/bluetooth/mesh/src/test_persistence.c b/tests/bsim/bluetooth/mesh/src/test_persistence.c index ec7d838d26a..4bf1f9faa93 100644 --- a/tests/bsim/bluetooth/mesh/src/test_persistence.c +++ b/tests/bsim/bluetooth/mesh/src/test_persistence.c @@ -455,12 +455,6 @@ static void provisioner_setup(void) FAIL("Failed to add test_netkey (err: %d, status: %d)", err, status); } - err = bt_mesh_cfg_cli_net_transmit_set(test_netkey_idx, TEST_PROV_ADDR, - BT_MESH_TRANSMIT(3, 50), &status); - if (err || status != BT_MESH_TRANSMIT(3, 50)) { - FAIL("Net transmit set failed (err %d, transmit %x)", err, status); - } - provisioner_ready = true; } diff --git a/tests/bsim/bluetooth/mesh/src/test_provision.c b/tests/bsim/bluetooth/mesh/src/test_provision.c index 3f566947efa..9a83f874e11 100644 --- a/tests/bsim/bluetooth/mesh/src/test_provision.c +++ b/tests/bsim/bluetooth/mesh/src/test_provision.c @@ -1211,7 +1211,6 @@ static void test_provisioner_pb_remote_client_nppi_robustness(void) uint16_t pb_remote_server_addr; uint8_t status; struct bt_mesh_cdb_node *node; - int err; provisioner_pb_remote_client_setup(); @@ -1225,15 +1224,6 @@ static void test_provisioner_pb_remote_client_nppi_robustness(void) .ttl = 3, }; - /* Set Network Transmit Count state on the remote client greater than on the remote server - * to increase probability of reception responses. - */ - err = bt_mesh_cfg_cli_net_transmit_set(0, current_dev_addr, BT_MESH_TRANSMIT(3, 50), - &status); - if (err || status != BT_MESH_TRANSMIT(3, 50)) { - FAIL("Net transmit set failed (err %d, transmit %x)", err, status); - } - ASSERT_OK(provision_remote(&srv, 2, &srv.addr)); /* Check device key by adding appkey. */ diff --git a/tests/bsim/bluetooth/mesh/tests_scripts/access/access_transmit_delayable.sh b/tests/bsim/bluetooth/mesh/tests_scripts/access/access_transmit_delayable.sh index 1622ac49f06..0e966288db0 100755 --- a/tests/bsim/bluetooth/mesh/tests_scripts/access/access_transmit_delayable.sh +++ b/tests/bsim/bluetooth/mesh/tests_scripts/access/access_transmit_delayable.sh @@ -14,4 +14,4 @@ RunTest mesh_access_pub_transmit_delayable_retr_1d1 \ conf=prj_mesh1d1_conf overlay=overlay_psa_conf RunTest mesh_access_pub_transmit_delayable_retr_psa \ - access_tx_period_delayable access_rx_period_delayable + access_tx_transmit_delayable access_rx_transmit_delayable diff --git a/tests/bsim/bluetooth/mesh/tests_scripts/priv_beacon/proxy_adv_multi_subnet_coex.sh b/tests/bsim/bluetooth/mesh/tests_scripts/priv_beacon/proxy_adv_multi_subnet_coex.sh index 845a8ff7da7..42863a13458 100755 --- a/tests/bsim/bluetooth/mesh/tests_scripts/priv_beacon/proxy_adv_multi_subnet_coex.sh +++ b/tests/bsim/bluetooth/mesh/tests_scripts/priv_beacon/proxy_adv_multi_subnet_coex.sh @@ -24,7 +24,7 @@ source $(dirname "${BASH_SOURCE[0]}")/../../_mesh_test.sh # Note 3: The proxy transmitting device mandates emitting of the secure # network beacons. This allows to check that proxy goes back to normal -# behavior after device advertises the seure network beacons. +# behavior after the device advertises the secure network beacons. # Test procedure: # 1. (0-20 seconds) A single subnet is active on the TX device with GATT From 6e8c8a1435e083c6c6855b3badc0bff5fd720fa4 Mon Sep 17 00:00:00 2001 From: Henrik Brix Andersen Date: Thu, 11 Jan 2024 22:08:23 +0100 Subject: [PATCH 2282/3723] dts: bindings: sensor: move nRF comparator bindings to correct folder Move the nRF comparator devicetree bindings from ADC to sensors, where the rest of the comparator bindings are placed. Signed-off-by: Henrik Brix Andersen --- dts/bindings/{adc => sensor}/nordic,nrf-comp.yaml | 0 dts/bindings/{adc => sensor}/nordic,nrf-lpcomp.yaml | 0 2 files changed, 0 insertions(+), 0 deletions(-) rename dts/bindings/{adc => sensor}/nordic,nrf-comp.yaml (100%) rename dts/bindings/{adc => sensor}/nordic,nrf-lpcomp.yaml (100%) diff --git a/dts/bindings/adc/nordic,nrf-comp.yaml b/dts/bindings/sensor/nordic,nrf-comp.yaml similarity index 100% rename from dts/bindings/adc/nordic,nrf-comp.yaml rename to dts/bindings/sensor/nordic,nrf-comp.yaml diff --git a/dts/bindings/adc/nordic,nrf-lpcomp.yaml b/dts/bindings/sensor/nordic,nrf-lpcomp.yaml similarity index 100% rename from dts/bindings/adc/nordic,nrf-lpcomp.yaml rename to dts/bindings/sensor/nordic,nrf-lpcomp.yaml From 38c39af4df154f64b655993970dfc045a2e7b08d Mon Sep 17 00:00:00 2001 From: Jonathan Rico Date: Thu, 11 Jan 2024 17:37:11 +0100 Subject: [PATCH 2283/3723] Bluetooth: L2CAP: Prepend SDU header immediately Previously it was not always possible to prepend the header. It was not possible if the application neglected to reserve the space for headers. This is bad because it forces a buffer segment allocation even if the buffer had enough room for the headers. E.g. a payload of 10 bytes in a netbuf of 30 bytes would have been segmented. We now explicitly reject the buffer if it does not have the headroom. This allows us to do a nice thing; simplify L2CAP segmentation. We convert the SDU from the application into a PDU payload, by prepending the SDU header, i.e. the SDU length in the original buffer. This PDU payload is ready to be chunked into PDUs without having to keep track of where in the SDU we are. This has the effect of removing a bunch of logic in the segmentation machine. Signed-off-by: Jonathan Rico Signed-off-by: Aleksander Wasaznik --- doc/releases/migration-guide-3.6.rst | 3 + include/zephyr/bluetooth/l2cap.h | 12 ++-- subsys/bluetooth/host/l2cap.c | 55 +++++++++++++------ .../bluetooth/host/l2cap/credits/src/main.c | 3 +- .../host/l2cap/credits_seg_recv/src/main.c | 3 +- .../host/l2cap/general/src/main_l2cap_ecred.c | 6 +- 6 files changed, 52 insertions(+), 30 deletions(-) diff --git a/doc/releases/migration-guide-3.6.rst b/doc/releases/migration-guide-3.6.rst index 26d18afa773..e77c1a5d1cd 100644 --- a/doc/releases/migration-guide-3.6.rst +++ b/doc/releases/migration-guide-3.6.rst @@ -245,6 +245,9 @@ Bluetooth parameter when segmenting SDUs into PDUs. In order to reproduce the previous behavior, the application should register the `alloc_seg` channel callback and allocate from the same pool as `buf`. +* The :c:func:`bt_l2cap_chan_send` API now requires the application to reserve + enough bytes for the L2CAP headers. Call ``net_buf_reserve(buf, + BT_L2CAP_SDU_CHAN_SEND_RESERVE);`` at buffer allocation time to do so. * Mesh diff --git a/include/zephyr/bluetooth/l2cap.h b/include/zephyr/bluetooth/l2cap.h index f688595f604..7177d388015 100644 --- a/include/zephyr/bluetooth/l2cap.h +++ b/include/zephyr/bluetooth/l2cap.h @@ -579,14 +579,12 @@ int bt_l2cap_chan_disconnect(struct bt_l2cap_chan *chan); * size the buffers for the for the outgoing buffer pool. * * When sending L2CAP data over an LE connection the application is sending - * L2CAP SDUs. The application can optionally reserve + * L2CAP SDUs. The application shall reserve * @ref BT_L2CAP_SDU_CHAN_SEND_RESERVE bytes in the buffer before sending. - * By reserving bytes in the buffer the stack can use this buffer as a segment - * directly, otherwise it will have to allocate a new segment for the first - * segment. - * If the application is reserving the bytes it should use the - * BT_L2CAP_BUF_SIZE() helper to correctly size the buffers for the for the - * outgoing buffer pool. + * + * The application can use the BT_L2CAP_SDU_BUF_SIZE() helper to correctly size + * the buffer to account for the reserved headroom. + * * When segmenting an L2CAP SDU into L2CAP PDUs the stack will first attempt to * allocate buffers from the channel's `alloc_seg` callback and will fallback * on the stack's global buffer pool (sized diff --git a/subsys/bluetooth/host/l2cap.c b/subsys/bluetooth/host/l2cap.c index e511d44d12b..833948730f5 100644 --- a/subsys/bluetooth/host/l2cap.c +++ b/subsys/bluetooth/host/l2cap.c @@ -2067,29 +2067,11 @@ static int l2cap_chan_le_send_sdu(struct bt_l2cap_le_chan *ch, total_len = net_buf_frags_len(*buf) + sent; - if (total_len > ch->tx.mtu) { - return -EMSGSIZE; - } - frag = *buf; if (!frag->len && frag->frags) { frag = frag->frags; } - if (!sent) { - /* Add SDU length for the first segment */ - ret = l2cap_chan_le_send(ch, frag, BT_L2CAP_SDU_HDR_SIZE); - if (ret < 0) { - if (ret == -EAGAIN) { - /* Store sent data into user_data */ - l2cap_tx_meta_data(frag)->sent = sent; - } - *buf = frag; - return ret; - } - sent = ret; - } - /* Send remaining segments */ for (ret = 0; sent < total_len; sent += ret) { /* Proceed to next fragment */ @@ -3139,6 +3121,7 @@ int bt_l2cap_chan_send(struct bt_l2cap_chan *chan, struct net_buf *buf) struct bt_l2cap_le_chan *le_chan = BT_L2CAP_LE_CHAN(chan); struct l2cap_tx_meta_data *data; void *old_user_data = l2cap_tx_meta_data(buf); + uint16_t sdu_len; int err; if (!buf) { @@ -3160,12 +3143,48 @@ int bt_l2cap_chan_send(struct bt_l2cap_chan *chan, struct net_buf *buf) return bt_l2cap_br_chan_send_cb(chan, buf, NULL, NULL); } + sdu_len = net_buf_frags_len(buf); + + if (sdu_len > le_chan->tx.mtu) { + return -EMSGSIZE; + } + + if (net_buf_headroom(buf) < BT_L2CAP_SDU_CHAN_SEND_RESERVE) { + /* Call `net_buf_reserve(buf, BT_L2CAP_SDU_CHAN_SEND_RESERVE)` + * when allocating buffers intended for bt_l2cap_chan_send(). + */ + LOG_DBG("Not enough headroom in buf %p", buf); + return -EINVAL; + } + data = alloc_tx_meta_data(); if (!data) { LOG_WRN("Unable to allocate TX context"); return -ENOBUFS; } + /* Prepend SDU "header". + * + * L2CAP LE CoC SDUs are segmented into PDUs and sent over so-called + * K-frames that each have their own L2CAP header (ie channel, PDU + * length). + * + * The SDU header is right before the data that will be segmented and is + * only present in the first segment/PDU. Here's an example: + * + * Sent data payload of 50 bytes over channel 0x4040 with MPS of 30 bytes: + * First PDU / segment / K-frame: + * | L2CAP K-frame header | K-frame payload | + * | PDU length | Channel ID | SDU header | SDU payload | + * | 30 | 0x4040 | 50 | 28 bytes of data | + * + * Second and last PDU / segment / K-frame: + * | L2CAP K-frame header | K-frame payload | + * | PDU length | Channel ID | rest of SDU payload | + * | 22 | 0x4040 | 22 bytes of data | + */ + net_buf_push_le16(buf, sdu_len); + data->sent = 0; data->cid = le_chan->tx.cid; data->cb = NULL; diff --git a/tests/bsim/bluetooth/host/l2cap/credits/src/main.c b/tests/bsim/bluetooth/host/l2cap/credits/src/main.c index 48d1ac7902c..dcc3d5a2373 100644 --- a/tests/bsim/bluetooth/host/l2cap/credits/src/main.c +++ b/tests/bsim/bluetooth/host/l2cap/credits/src/main.c @@ -23,7 +23,8 @@ CREATE_FLAG(flag_l2cap_connected); #define L2CAP_MTU (2 * SDU_LEN) /* Only one SDU transmitted or received at a time */ -NET_BUF_POOL_DEFINE(sdu_pool, 1, L2CAP_MTU, CONFIG_BT_CONN_TX_USER_DATA_SIZE, NULL); +NET_BUF_POOL_DEFINE(sdu_pool, 1, BT_L2CAP_SDU_BUF_SIZE(L2CAP_MTU), + CONFIG_BT_CONN_TX_USER_DATA_SIZE, NULL); static uint8_t tx_data[SDU_LEN]; static uint16_t rx_cnt; diff --git a/tests/bsim/bluetooth/host/l2cap/credits_seg_recv/src/main.c b/tests/bsim/bluetooth/host/l2cap/credits_seg_recv/src/main.c index 8e927002da1..77dd72dde02 100644 --- a/tests/bsim/bluetooth/host/l2cap/credits_seg_recv/src/main.c +++ b/tests/bsim/bluetooth/host/l2cap/credits_seg_recv/src/main.c @@ -21,7 +21,8 @@ CREATE_FLAG(flag_l2cap_connected); #define L2CAP_MTU (2 * SDU_LEN) /* Only one SDU transmitted or received at a time */ -NET_BUF_POOL_DEFINE(sdu_pool, 1, L2CAP_MTU, CONFIG_BT_CONN_TX_USER_DATA_SIZE, NULL); +NET_BUF_POOL_DEFINE(sdu_pool, 1, BT_L2CAP_SDU_BUF_SIZE(L2CAP_MTU), + CONFIG_BT_CONN_TX_USER_DATA_SIZE, NULL); static uint8_t tx_data[SDU_LEN]; static uint16_t rx_cnt; diff --git a/tests/bsim/bluetooth/host/l2cap/general/src/main_l2cap_ecred.c b/tests/bsim/bluetooth/host/l2cap/general/src/main_l2cap_ecred.c index ecb4fa320ae..f28ce93c693 100644 --- a/tests/bsim/bluetooth/host/l2cap/general/src/main_l2cap_ecred.c +++ b/tests/bsim/bluetooth/host/l2cap/general/src/main_l2cap_ecred.c @@ -33,9 +33,9 @@ static const struct bt_data ad[] = { #define SHORT_MSG_CHAN_IDX 1 NET_BUF_POOL_FIXED_DEFINE(rx_data_pool, L2CAP_CHANNELS, BT_L2CAP_BUF_SIZE(DATA_BUF_SIZE), 8, NULL); -NET_BUF_POOL_FIXED_DEFINE(tx_data_pool_0, 1, BT_L2CAP_BUF_SIZE(DATA_MTU), +NET_BUF_POOL_FIXED_DEFINE(tx_data_pool_0, 1, BT_L2CAP_SDU_BUF_SIZE(DATA_MTU), CONFIG_BT_CONN_TX_USER_DATA_SIZE, NULL); -NET_BUF_POOL_FIXED_DEFINE(tx_data_pool_1, 1, BT_L2CAP_BUF_SIZE(DATA_MTU), +NET_BUF_POOL_FIXED_DEFINE(tx_data_pool_1, 1, BT_L2CAP_SDU_BUF_SIZE(DATA_MTU), CONFIG_BT_CONN_TX_USER_DATA_SIZE, NULL); static struct bt_l2cap_server servers[SERVERS]; @@ -379,7 +379,7 @@ static void send_sdu(int iteration, int chan_idx, int bytes) } channels[chan_idx].buf = buf; - net_buf_reserve(buf, BT_L2CAP_CHAN_SEND_RESERVE); + net_buf_reserve(buf, BT_L2CAP_SDU_CHAN_SEND_RESERVE); net_buf_add_mem(buf, channels[chan_idx].payload, bytes); LOG_DBG("bt_l2cap_chan_sending ch: %i bytes: %i iteration: %i", chan_idx, bytes, iteration); From cd2ac64e8b9e8224cf88be21edab53f3722b8f37 Mon Sep 17 00:00:00 2001 From: Alberto Escolar Piedras Date: Fri, 12 Jan 2024 15:12:18 +0100 Subject: [PATCH 2284/3723] boards nrf_bsim: Optimize irq handler Speed up the interrupt handler when the MCU is woken due to a phony interrupt (while busy waiting). Signed-off-by: Alberto Escolar Piedras --- boards/posix/nrf_bsim/irq_handler.c | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) diff --git a/boards/posix/nrf_bsim/irq_handler.c b/boards/posix/nrf_bsim/irq_handler.c index 24c00a4f79c..5e2a79d7645 100644 --- a/boards/posix/nrf_bsim/irq_handler.c +++ b/boards/posix/nrf_bsim/irq_handler.c @@ -95,13 +95,20 @@ void posix_irq_handler(void) return; } + irq_nbr = hw_irq_ctrl_get_highest_prio_irq(cpu_n); + + if (irq_nbr == -1) { + /* This is a phony interrupt during a busy wait, no need for more */ + return; + } + if (_kernel.cpus[0].nested == 0) { may_swap = 0; } _kernel.cpus[0].nested++; - while ((irq_nbr = hw_irq_ctrl_get_highest_prio_irq(cpu_n)) != -1) { + do { int last_current_running_prio = hw_irq_ctrl_get_cur_prio(cpu_n); int last_running_irq = currently_running_irq; @@ -115,7 +122,7 @@ void posix_irq_handler(void) hw_irq_ctrl_reeval_level_irq(cpu_n, irq_nbr); hw_irq_ctrl_set_cur_prio(cpu_n, last_current_running_prio); - } + } while ((irq_nbr = hw_irq_ctrl_get_highest_prio_irq(cpu_n)) != -1); _kernel.cpus[0].nested--; From a18cae9838b56575f3e4e0980cbf530bd1224dd6 Mon Sep 17 00:00:00 2001 From: Alberto Escolar Piedras Date: Fri, 12 Jan 2024 16:18:20 +0100 Subject: [PATCH 2285/3723] boards native_sim: Optimize irq handler Speed up the interrupt handler when the MCU is woken due to a phony interrupt (while busy waiting). Signed-off-by: Alberto Escolar Piedras --- boards/posix/native_sim/irq_handler.c | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) diff --git a/boards/posix/native_sim/irq_handler.c b/boards/posix/native_sim/irq_handler.c index 3ad8058eb5b..899a4b7139c 100644 --- a/boards/posix/native_sim/irq_handler.c +++ b/boards/posix/native_sim/irq_handler.c @@ -77,13 +77,20 @@ void posix_irq_handler(void) return; } + irq_nbr = hw_irq_ctrl_get_highest_prio_irq(); + + if (irq_nbr == -1) { + /* This is a phony interrupt during a busy wait, no need for more */ + return; + } + if (_kernel.cpus[0].nested == 0) { may_swap = 0; } _kernel.cpus[0].nested++; - while ((irq_nbr = hw_irq_ctrl_get_highest_prio_irq()) != -1) { + do { int last_current_running_prio = hw_irq_ctrl_get_cur_prio(); int last_running_irq = currently_running_irq; @@ -95,7 +102,7 @@ void posix_irq_handler(void) currently_running_irq = last_running_irq; hw_irq_ctrl_set_cur_prio(last_current_running_prio); - } + } while ((irq_nbr = hw_irq_ctrl_get_highest_prio_irq()) != -1); _kernel.cpus[0].nested--; From 1fc6550a254f20ae9e6ad5bb092e5b6b28cff433 Mon Sep 17 00:00:00 2001 From: Alberto Escolar Piedras Date: Fri, 12 Jan 2024 15:50:35 +0100 Subject: [PATCH 2286/3723] native_simulator: Get latest from upstream Align with native_simulator's upstream main 880eea00abf0191f3d986559876359a5422c9618 Which includes: * 880eea0 HW scheduler: Minor optimization * 37c0d86 Minor: Comment fix: Remove out of date reference Signed-off-by: Alberto Escolar Piedras --- .../common/src/include/nsi_hw_scheduler.h | 6 +++++- scripts/native_simulator/common/src/main.c | 2 +- .../common/src/nsi_hw_scheduler.c | 20 ++++++------------- 3 files changed, 12 insertions(+), 16 deletions(-) diff --git a/scripts/native_simulator/common/src/include/nsi_hw_scheduler.h b/scripts/native_simulator/common/src/include/nsi_hw_scheduler.h index e5b4c64f3b8..edff33da8e1 100644 --- a/scripts/native_simulator/common/src/include/nsi_hw_scheduler.h +++ b/scripts/native_simulator/common/src/include/nsi_hw_scheduler.h @@ -16,7 +16,11 @@ extern "C" { #define NSI_NEVER UINT64_MAX /* API intended for the native simulator specific embedded drivers: */ -uint64_t nsi_hws_get_time(void); +static inline uint64_t nsi_hws_get_time(void) +{ + extern uint64_t nsi_simu_time; + return nsi_simu_time; +} /* Internal APIs to the native_simulator and its HW models: */ void nsi_hws_init(void); diff --git a/scripts/native_simulator/common/src/main.c b/scripts/native_simulator/common/src/main.c index b9d97c91748..9b5c566fae0 100644 --- a/scripts/native_simulator/common/src/main.c +++ b/scripts/native_simulator/common/src/main.c @@ -50,7 +50,7 @@ NSI_FUNC_NORETURN void nsi_exit(int exit_code) } /** - * Run all early native_posix initialization steps, including command + * Run all early native simulator initialization steps, including command * line parsing and CPU start, until we are ready to let the HW models * run via hwm_one_event() */ diff --git a/scripts/native_simulator/common/src/nsi_hw_scheduler.c b/scripts/native_simulator/common/src/nsi_hw_scheduler.c index 60cf06167c4..230befcd6f9 100644 --- a/scripts/native_simulator/common/src/nsi_hw_scheduler.c +++ b/scripts/native_simulator/common/src/nsi_hw_scheduler.c @@ -21,7 +21,7 @@ #include "nsi_hw_scheduler.h" #include "nsi_hws_models_if.h" -static uint64_t simu_time; /* The actual time as known by the HW models */ +uint64_t nsi_simu_time; /* The actual time as known by the HW models */ static uint64_t end_of_time = NSI_NEVER; /* When will this device stop */ extern struct nsi_hw_event_st __nsi_hw_events_start[]; @@ -74,21 +74,21 @@ static void nsi_hws_set_sig_handler(void) static void nsi_hws_sleep_until_next_event(void) { - if (next_timer_time >= simu_time) { /* LCOV_EXCL_BR_LINE */ - simu_time = next_timer_time; + if (next_timer_time >= nsi_simu_time) { /* LCOV_EXCL_BR_LINE */ + nsi_simu_time = next_timer_time; } else { /* LCOV_EXCL_START */ nsi_print_warning("next_timer_time corrupted (%"PRIu64"<= %" PRIu64", timer idx=%i)\n", (uint64_t)next_timer_time, - (uint64_t)simu_time, + (uint64_t)nsi_simu_time, next_timer_index); /* LCOV_EXCL_STOP */ } - if (signaled_end || (simu_time > end_of_time)) { + if (signaled_end || (nsi_simu_time > end_of_time)) { nsi_print_trace("\nStopped at %.3Lfs\n", - ((long double)simu_time)/1.0e6L); + ((long double)nsi_simu_time)/1.0e6L); nsi_exit(0); } } @@ -141,14 +141,6 @@ void nsi_hws_set_end_of_time(uint64_t new_end_of_time) end_of_time = new_end_of_time; } -/** - * Return the current simulated time as known by the device - */ -uint64_t nsi_hws_get_time(void) -{ - return simu_time; -} - /** * Function to initialize the HW scheduler * From 4204ca9bcb3f675a0e63f647931ffe2c4b515729 Mon Sep 17 00:00:00 2001 From: Guennadi Liakhovetski Date: Mon, 15 Jan 2024 15:21:36 +0100 Subject: [PATCH 2287/3723] ace: fix DSP panic during startup pm_device_runtime_get() must be called after pd_intel_adsp_init() is called for each device, because the latter calls pm_device_runtime_enable(), which sets the device runtime PM use count to 0. The current wrong calling order causes a DSP panic because of an unbalanced pm_device_runtime_put(). Fix this by delaying pm_device_runtime_get() until the POST_KERNEL initialisation step. Fixes commit c3a6274bf5e4 ("intel_adsp: ace: power: Prevent HST domain power gating") Signed-off-by: Guennadi Liakhovetski --- soc/xtensa/intel_adsp/ace/multiprocessing.c | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/soc/xtensa/intel_adsp/ace/multiprocessing.c b/soc/xtensa/intel_adsp/ace/multiprocessing.c index 96c9d1ac3a1..d3a4bef4094 100644 --- a/soc/xtensa/intel_adsp/ace/multiprocessing.c +++ b/soc/xtensa/intel_adsp/ace/multiprocessing.c @@ -86,11 +86,6 @@ void soc_mp_init(void) IDC[i].agents[0].ipc.ctl = BIT(0); /* IPCTBIE */ } - int ret = pm_device_runtime_get(INTEL_ADSP_HST_DOMAIN_DEV); - - ARG_UNUSED(ret); - __ASSERT_NO_MSG(ret == 0); - /* Set the core 0 active */ soc_cpus_active[0] = true; #if CONFIG_ACE_VERSION_1_5 @@ -100,6 +95,12 @@ void soc_mp_init(void) #endif /* CONFIG_ACE_VERSION_1_5 */ } +static int host_runtime_get(void) +{ + return pm_device_runtime_get(INTEL_ADSP_HST_DOMAIN_DEV); +} +SYS_INIT(host_runtime_get, POST_KERNEL, 99); + #ifdef CONFIG_ADSP_IMR_CONTEXT_SAVE /* * Called after exiting D3 state when context restore is enabled. From 342e10b0b80504c3b119e36994be2ea0659e9326 Mon Sep 17 00:00:00 2001 From: Emil Lindqvist Date: Thu, 4 Jan 2024 10:21:07 +0100 Subject: [PATCH 2288/3723] modem_cellular: add RSRP & RSRQ to U-blox SARA-R5 modem This commit implements parsing of the CESQ extended signal quality AT command, extracting RSRP and RSRQ which is relevant for LTE connections. It's used in the U-blox SARA-R5 modem instance. Furthermore, the IMEI, IMSI is extracted in the same modem. Signed-off-by: Emil Lindqvist --- drivers/modem/modem_cellular.c | 78 +++++++++++++++++++++++++++++++--- 1 file changed, 72 insertions(+), 6 deletions(-) diff --git a/drivers/modem/modem_cellular.c b/drivers/modem/modem_cellular.c index 16530edde6c..d1f3a69c94e 100644 --- a/drivers/modem/modem_cellular.c +++ b/drivers/modem/modem_cellular.c @@ -33,6 +33,16 @@ LOG_MODULE_REGISTER(modem_cellular, CONFIG_MODEM_LOG_LEVEL); #define MODEM_CELLULAR_DATA_MANUFACTURER_LEN (64) #define MODEM_CELLULAR_DATA_FW_VERSION_LEN (64) +/* Magic constants */ +#define CSQ_RSSI_UNKNOWN (99) +#define CESQ_RSRP_UNKNOWN (255) +#define CESQ_RSRQ_UNKNOWN (255) + +/* Magic numbers to units conversions */ +#define CSQ_RSSI_TO_DB(v) (-113 + (2 * (rssi))) +#define CESQ_RSRP_TO_DB(v) (-140 + (v)) +#define CESQ_RSRQ_TO_DB(v) (-20 + ((v) / 2)) + enum modem_cellular_state { MODEM_CELLULAR_STATE_IDLE = 0, MODEM_CELLULAR_STATE_RESET_PULSE, @@ -95,6 +105,8 @@ struct modem_cellular_data { uint8_t registration_status_gprs; uint8_t registration_status_lte; uint8_t rssi; + uint8_t rsrp; + uint8_t rsrq; uint8_t imei[MODEM_CELLULAR_DATA_IMEI_LEN]; uint8_t model_id[MODEM_CELLULAR_DATA_MODEL_ID_LEN]; uint8_t imsi[MODEM_CELLULAR_DATA_IMSI_LEN]; @@ -340,6 +352,19 @@ static void modem_cellular_chat_on_csq(struct modem_chat *chat, char **argv, uin data->rssi = (uint8_t)atoi(argv[1]); } +static void modem_cellular_chat_on_cesq(struct modem_chat *chat, char **argv, uint16_t argc, + void *user_data) +{ + struct modem_cellular_data *data = (struct modem_cellular_data *)user_data; + + if (argc != 7) { + return; + } + + data->rsrq = (uint8_t)atoi(argv[5]); + data->rsrp = (uint8_t)atoi(argv[6]); +} + static void modem_cellular_chat_on_imsi(struct modem_chat *chat, char **argv, uint16_t argc, void *user_data) { @@ -398,6 +423,7 @@ MODEM_CHAT_MATCHES_DEFINE(allow_match, MODEM_CHAT_MATCH_DEFINE(imei_match, "", "", modem_cellular_chat_on_imei); MODEM_CHAT_MATCH_DEFINE(cgmm_match, "", "", modem_cellular_chat_on_cgmm); MODEM_CHAT_MATCH_DEFINE(csq_match, "+CSQ: ", ",", modem_cellular_chat_on_csq); +MODEM_CHAT_MATCH_DEFINE(cesq_match, "+CESQ: ", ",", modem_cellular_chat_on_cesq); MODEM_CHAT_MATCH_DEFINE(cimi_match, "", "", modem_cellular_chat_on_imsi); MODEM_CHAT_MATCH_DEFINE(cgmi_match, "", "", modem_cellular_chat_on_cgmi); MODEM_CHAT_MATCH_DEFINE(cgmr_match, "", "", modem_cellular_chat_on_cgmr); @@ -1253,11 +1279,44 @@ static inline int modem_cellular_csq_parse_rssi(uint8_t rssi, int16_t *value) * - ber is an integer from 0 to 7 that describes the error rate, it can also * be 99 for an unknown error rate */ - if (rssi == 99) { + if (rssi == CSQ_RSSI_UNKNOWN) { + return -EINVAL; + } + + *value = (int16_t)CSQ_RSSI_TO_DB(rssi); + return 0; +} + +MODEM_CHAT_SCRIPT_CMDS_DEFINE(get_signal_cesq_chat_script_cmds, + MODEM_CHAT_SCRIPT_CMD_RESP("AT+CESQ", cesq_match), + MODEM_CHAT_SCRIPT_CMD_RESP("", ok_match)); + +MODEM_CHAT_SCRIPT_DEFINE(get_signal_cesq_chat_script, get_signal_cesq_chat_script_cmds, + abort_matches, modem_cellular_chat_callback_handler, 2); + +/* AT+CESQ returns a response +CESQ: ,,,,, where: + * - rsrq is a integer from 0 to 34 whose values describes the Reference Signal Receive + * Quality between -20 dB for 0 and -3 dB for 34 (0.5 dB steps), or unknown for 255 + * - rsrp is an integer from 0 to 97 that describes the Reference Signal Receive Power + * between -140 dBm for 0 and -44 dBm for 97 (1 dBm steps), or unknown for 255 + */ +static inline int modem_cellular_cesq_parse_rsrp(uint8_t rsrp, int16_t *value) +{ + if (rsrp == CESQ_RSRP_UNKNOWN) { + return -EINVAL; + } + + *value = (int16_t)CESQ_RSRP_TO_DB(rsrp); + return 0; +} + +static inline int modem_cellular_cesq_parse_rsrq(uint8_t rsrq, int16_t *value) +{ + if (rsrq == CESQ_RSRQ_UNKNOWN) { return -EINVAL; } - *value = (int16_t)(-113 + (2 * rssi)); + *value = (int16_t)CESQ_RSRQ_TO_DB(rsrq); return 0; } @@ -1281,8 +1340,7 @@ static int modem_cellular_get_signal(const struct device *dev, case CELLULAR_SIGNAL_RSRP: case CELLULAR_SIGNAL_RSRQ: - /* TODO: Run CESQ script */ - ret = -ENOTSUP; + ret = modem_chat_run_script(&data->chat, &get_signal_cesq_chat_script); break; default: @@ -1302,9 +1360,11 @@ static int modem_cellular_get_signal(const struct device *dev, break; case CELLULAR_SIGNAL_RSRP: + ret = modem_cellular_cesq_parse_rsrp(data->rsrp, value); + break; + case CELLULAR_SIGNAL_RSRQ: - /* TODO: Validate and set values */ - ret = -ENODATA; + ret = modem_cellular_cesq_parse_rsrq(data->rsrq, value); break; default: @@ -1744,6 +1804,12 @@ MODEM_CHAT_SCRIPT_CMDS_DEFINE(u_blox_sara_r5_init_chat_script_cmds, MODEM_CHAT_SCRIPT_CMD_RESP("", ok_match), MODEM_CHAT_SCRIPT_CMD_RESP("AT+CGMM", cgmm_match), MODEM_CHAT_SCRIPT_CMD_RESP("", ok_match), + MODEM_CHAT_SCRIPT_CMD_RESP("AT+CGMI", cgmi_match), + MODEM_CHAT_SCRIPT_CMD_RESP("", ok_match), + MODEM_CHAT_SCRIPT_CMD_RESP("AT+CGMR", cgmr_match), + MODEM_CHAT_SCRIPT_CMD_RESP("", ok_match), + MODEM_CHAT_SCRIPT_CMD_RESP("AT+CIMI", cimi_match), + MODEM_CHAT_SCRIPT_CMD_RESP("", ok_match), MODEM_CHAT_SCRIPT_CMD_RESP("AT+CMUX=0,0,5,127", ok_match)); MODEM_CHAT_SCRIPT_DEFINE(u_blox_sara_r5_init_chat_script, u_blox_sara_r5_init_chat_script_cmds, From 879e3a42b0ef8d63dbd98e5410e8f58dc9a21a4a Mon Sep 17 00:00:00 2001 From: Amrith Venkat Kesavamoorthi Date: Mon, 23 Jan 2023 12:29:37 +0100 Subject: [PATCH 2289/3723] drivers: gpio: PCF857x: Modify PCF8574 driver Modify existing PCF8574 driver as PCF857x for: PCF8574 - 8 channel I/O expander PCF8575 - 16 channel I/O expander Signed-off-by: Amrith Venkat Kesavamoorthi --- .../kincony_kc868_a32/kincony_kc868_a32.dts | 16 +- doc/releases/migration-guide-3.6.rst | 29 +++ drivers/gpio/CMakeLists.txt | 2 +- drivers/gpio/Kconfig | 2 +- drivers/gpio/Kconfig.pcf8574 | 19 -- drivers/gpio/Kconfig.pcf857x | 21 ++ .../gpio/{gpio_pcf8574.c => gpio_pcf857x.c} | 187 +++++++++--------- .../{nxp,pcf8574.yaml => nxp,pcf857x.yaml} | 10 +- tests/drivers/build_all/gpio/app.overlay | 11 +- 9 files changed, 176 insertions(+), 121 deletions(-) delete mode 100644 drivers/gpio/Kconfig.pcf8574 create mode 100644 drivers/gpio/Kconfig.pcf857x rename drivers/gpio/{gpio_pcf8574.c => gpio_pcf857x.c} (59%) rename dts/bindings/gpio/{nxp,pcf8574.yaml => nxp,pcf857x.yaml} (64%) diff --git a/boards/xtensa/kincony_kc868_a32/kincony_kc868_a32.dts b/boards/xtensa/kincony_kc868_a32/kincony_kc868_a32.dts index da250ef781a..2690ae75b24 100644 --- a/boards/xtensa/kincony_kc868_a32/kincony_kc868_a32.dts +++ b/boards/xtensa/kincony_kc868_a32/kincony_kc868_a32.dts @@ -52,7 +52,7 @@ pinctrl-names = "default"; i2c0_pcf8574@21 { - compatible = "nxp,pcf8574"; + compatible = "nxp,pcf857x"; reg = <0x21>; gpio-controller; #gpio-cells = <2>; @@ -60,7 +60,7 @@ }; i2c0_pcf8574@22 { - compatible = "nxp,pcf8574"; + compatible = "nxp,pcf857x"; reg = <0x22>; gpio-controller; #gpio-cells = <2>; @@ -68,7 +68,7 @@ }; i2c0_pcf8574@24 { - compatible = "nxp,pcf8574"; + compatible = "nxp,pcf857x"; reg = <0x24>; gpio-controller; #gpio-cells = <2>; @@ -76,7 +76,7 @@ }; i2c0_pcf8574@25 { - compatible = "nxp,pcf8574"; + compatible = "nxp,pcf857x"; reg = <0x25>; gpio-controller; #gpio-cells = <2>; @@ -93,7 +93,7 @@ pinctrl-names = "default"; i2c1_pcf8574@21 { - compatible = "nxp,pcf8574"; + compatible = "nxp,pcf857x"; reg = <0x21>; gpio-controller; #gpio-cells = <2>; @@ -101,7 +101,7 @@ }; i2c1_pcf8574@22 { - compatible = "nxp,pcf8574"; + compatible = "nxp,pcf857x"; reg = <0x22>; gpio-controller; #gpio-cells = <2>; @@ -109,7 +109,7 @@ }; i2c1_pcf8574@24 { - compatible = "nxp,pcf8574"; + compatible = "nxp,pcf857x"; reg = <0x24>; gpio-controller; #gpio-cells = <2>; @@ -117,7 +117,7 @@ }; i2c1_pcf8574@25 { - compatible = "nxp,pcf8574"; + compatible = "nxp,pcf857x"; reg = <0x25>; gpio-controller; #gpio-cells = <2>; diff --git a/doc/releases/migration-guide-3.6.rst b/doc/releases/migration-guide-3.6.rst index e77c1a5d1cd..d763e9f5f45 100644 --- a/doc/releases/migration-guide-3.6.rst +++ b/doc/releases/migration-guide-3.6.rst @@ -56,6 +56,35 @@ enable all optional modules, and then run ``west update`` again. Device Drivers and Device Tree ============================== +* The :dtcompatible:`nxp,pcf8574` driver has been renamed to + :dtcompatible:`nxp,pcf857x`. (:github:`67054`) to support pcf8574 and pcf8575. + The Kconfig option has been renamed from :kconfig:option:`CONFIG_GPIO_PCF8574` to + :kconfig:option:`CONFIG_GPIO_PCF857X`. + The Device Tree can be configured as follows: + + .. code-block:: devicetree + + &i2c { + status = "okay"; + pcf8574: pcf857x@20 { + compatible = "nxp,pcf857x"; + status = "okay"; + reg = <0x20>; + gpio-controller; + #gpio-cells = <2>; + ngpios = <8>; + }; + + pcf8575: pcf857x@21 { + compatible = "nxp,pcf857x"; + status = "okay"; + reg = <0x21>; + gpio-controller; + #gpio-cells = <2>; + ngpios = <16>; + }; + }; + * The :dtcompatible:`st,lsm6dsv16x` sensor driver has been changed to support configuration of both int1 and int2 pins. The DT attribute ``irq-gpios`` has been removed and substituted by two new attributes, ``int1-gpios`` and ``int2-gpios``. diff --git a/drivers/gpio/CMakeLists.txt b/drivers/gpio/CMakeLists.txt index 34bdaebae27..56018e7744f 100644 --- a/drivers/gpio/CMakeLists.txt +++ b/drivers/gpio/CMakeLists.txt @@ -56,7 +56,7 @@ zephyr_library_sources_ifdef(CONFIG_GPIO_SNPS_CREG gpio_creg_gpio.c) zephyr_library_sources_ifdef(CONFIG_GPIO_STMPE1600 gpio_stmpe1600.c) zephyr_library_sources_ifdef(CONFIG_GPIO_XEC_V2 gpio_mchp_xec_v2.c) zephyr_library_sources_ifdef(CONFIG_GPIO_PCA953X gpio_pca953x.c) -zephyr_library_sources_ifdef(CONFIG_GPIO_PCF8574 gpio_pcf8574.c) +zephyr_library_sources_ifdef(CONFIG_GPIO_PCF857X gpio_pcf857x.c) zephyr_library_sources_ifdef(CONFIG_GPIO_FXL6408 gpio_fxl6408.c) zephyr_library_sources_ifdef(CONFIG_GPIO_ANDES_ATCGPIO100 gpio_andes_atcgpio100.c) zephyr_library_sources_ifdef(CONFIG_GPIO_NEORV32 gpio_neorv32.c) diff --git a/drivers/gpio/Kconfig b/drivers/gpio/Kconfig index 960c7eb540e..6b6928f3971 100644 --- a/drivers/gpio/Kconfig +++ b/drivers/gpio/Kconfig @@ -179,7 +179,7 @@ source "drivers/gpio/Kconfig.stmpe1600" source "drivers/gpio/Kconfig.pca953x" -source "drivers/gpio/Kconfig.pcf8574" +source "drivers/gpio/Kconfig.pcf857x" source "drivers/gpio/Kconfig.fxl6408" diff --git a/drivers/gpio/Kconfig.pcf8574 b/drivers/gpio/Kconfig.pcf8574 deleted file mode 100644 index 0c35008aa64..00000000000 --- a/drivers/gpio/Kconfig.pcf8574 +++ /dev/null @@ -1,19 +0,0 @@ -# PCF8574 GPIO configuration options - -# Copyright (c) 2022 Ithinx -# SPDX-License-Identifier: Apache-2.0 - -menuconfig GPIO_PCF8574 - bool "PCF8574 I2C GPIO chip" - default y - depends on DT_HAS_NXP_PCF8574_ENABLED - select I2C - help - Enable driver for PCF8574 I2C GPIO chip. - -config GPIO_PCF8574_INIT_PRIORITY - int "Init priority" - default 70 - depends on GPIO_PCF8574 - help - Device driver initialization priority. diff --git a/drivers/gpio/Kconfig.pcf857x b/drivers/gpio/Kconfig.pcf857x new file mode 100644 index 00000000000..2617d8a76a1 --- /dev/null +++ b/drivers/gpio/Kconfig.pcf857x @@ -0,0 +1,21 @@ +# PCF857x GPIO configuration options + +# Copyright (c) 2022 Ithinx +# Copyright (c) 2023 Mr Beam Lasers GmbH +# Copyright (c) 2023 Amrith Venkat Kesavamoorthi +# SPDX-License-Identifier: Apache-2.0 + +menuconfig GPIO_PCF857X + bool "PCF857X I2C GPIO chip" + default y + depends on DT_HAS_NXP_PCF857X_ENABLED + select I2C + help + Enable driver for PCF857X I2C GPIO chip. + +config GPIO_PCF857X_INIT_PRIORITY + int "Init priority" + default 70 + depends on GPIO_PCF857X + help + Device driver initialization priority. diff --git a/drivers/gpio/gpio_pcf8574.c b/drivers/gpio/gpio_pcf857x.c similarity index 59% rename from drivers/gpio/gpio_pcf8574.c rename to drivers/gpio/gpio_pcf857x.c index 80a0d8b7d06..c30e1a5d36d 100644 --- a/drivers/gpio/gpio_pcf8574.c +++ b/drivers/gpio/gpio_pcf857x.c @@ -1,10 +1,16 @@ /** - * Copyright (c) 2022 Ithinx GmbH + * Copyright (c) + * 2022 Ithinx GmbH + * 2023 Amrith Venkat Kesavamoorthi + * 2023 Mr Beam Lasers GmbH. * * SPDX-License-Identifier: Apache-2.0 + * + * @see https://www.nxp.com/docs/en/data-sheet/PCF8575.pdf + * @see https://www.nxp.com/docs/en/data-sheet/PCF8574_PCF8574A.pdf */ -#define DT_DRV_COMPAT nxp_pcf8574 +#define DT_DRV_COMPAT nxp_pcf857x #include @@ -12,28 +18,31 @@ #include #include #include -LOG_MODULE_REGISTER(pcf8574, CONFIG_GPIO_LOG_LEVEL); +#include + +LOG_MODULE_REGISTER(pcf857x, CONFIG_GPIO_LOG_LEVEL); -struct pcf8574_pins_cfg { - uint8_t configured_as_outputs; /* 0 for input, 1 for output */ - uint8_t outputs_state; +struct pcf857x_pins_cfg { + uint16_t configured_as_outputs; /* 0 for input, 1 for output */ + uint16_t outputs_state; }; -/** Runtime driver data of the pcf8574*/ -struct pcf8574_drv_data { +/** Runtime driver data of the pcf857x*/ +struct pcf857x_drv_data { /* gpio_driver_data needs to be first */ struct gpio_driver_data common; - struct pcf8574_pins_cfg pins_cfg; + struct pcf857x_pins_cfg pins_cfg; sys_slist_t callbacks; struct k_sem lock; struct k_work work; const struct device *dev; struct gpio_callback int_gpio_cb; - uint8_t input_port_last; + uint16_t input_port_last; + int num_bytes; }; /** Configuration data*/ -struct pcf8574_drv_cfg { +struct pcf857x_drv_cfg { /* gpio_driver_config needs to be first */ struct gpio_driver_config common; struct i2c_dt_spec i2c; @@ -41,52 +50,53 @@ struct pcf8574_drv_cfg { }; /** - * @brief Reads the value of the pins from pcf8574 respectively from a connected device. + * @brief Reads the value of the pins from pcf857x respectively from a connected device. * * @param dev Pointer to the device structure of the driver instance. - * @param value Pointer to the input value. It contains the received Byte. + * @param value Pointer to the input value. It contains the received Bytes(receives 2 Bytes for P0 + * and P1). * * @retval 0 If successful. * @retval Negative value for error code. */ -static int pcf8574_process_input(const struct device *dev, gpio_port_value_t *value) +static int pcf857x_process_input(const struct device *dev, gpio_port_value_t *value) { - const struct pcf8574_drv_cfg *drv_cfg = dev->config; - struct pcf8574_drv_data *drv_data = dev->data; + const struct pcf857x_drv_cfg *drv_cfg = dev->config; + struct pcf857x_drv_data *drv_data = dev->data; int rc = 0; - uint8_t rx_buf; + uint8_t rx_buf[2] = {0}; - rc = i2c_read_dt(&drv_cfg->i2c, &rx_buf, sizeof(rx_buf)); + rc = i2c_read_dt(&drv_cfg->i2c, rx_buf, drv_data->num_bytes); if (rc != 0) { LOG_ERR("%s: failed to read from device: %d", dev->name, rc); return -EIO; } if (value) { - *value = rx_buf; + *value = sys_get_le16(rx_buf); /*format P17-P10..P07-P00 (bit15-bit8..bit7-bit0)*/ } - drv_data->input_port_last = rx_buf; + drv_data->input_port_last = sys_get_le16(rx_buf); return rc; } /** Register the read-task as work*/ -static void pcf8574_work_handler(struct k_work *work) +static void pcf857x_work_handler(struct k_work *work) { - struct pcf8574_drv_data *drv_data = CONTAINER_OF(work, struct pcf8574_drv_data, work); + struct pcf857x_drv_data *drv_data = CONTAINER_OF(work, struct pcf857x_drv_data, work); k_sem_take(&drv_data->lock, K_FOREVER); uint32_t changed_pins; - uint8_t input_port_last_temp = drv_data->input_port_last; - int rc = pcf8574_process_input(drv_data->dev, &changed_pins); + uint16_t input_port_last_temp = drv_data->input_port_last; + int rc = pcf857x_process_input(drv_data->dev, &changed_pins); if (rc) { LOG_ERR("Failed to read interrupt sources: %d", rc); } k_sem_give(&drv_data->lock); - if (input_port_last_temp != (uint8_t)changed_pins && !rc) { + if (input_port_last_temp != (uint16_t)changed_pins && !rc) { /** Find changed bits*/ changed_pins ^= input_port_last_temp; @@ -94,15 +104,15 @@ static void pcf8574_work_handler(struct k_work *work) } } -/** Callback for interrupt through some level changes on pcf8574 pins*/ -static void pcf8574_int_gpio_handler(const struct device *dev, struct gpio_callback *gpio_cb, +/** Callback for interrupt through some level changes on pcf857x pins*/ +static void pcf857x_int_gpio_handler(const struct device *dev, struct gpio_callback *gpio_cb, uint32_t pins) { ARG_UNUSED(dev); ARG_UNUSED(pins); - struct pcf8574_drv_data *drv_data = - CONTAINER_OF(gpio_cb, struct pcf8574_drv_data, int_gpio_cb); + struct pcf857x_drv_data *drv_data = + CONTAINER_OF(gpio_cb, struct pcf857x_drv_data, int_gpio_cb); k_work_submit(&drv_data->work); } @@ -116,16 +126,16 @@ static void pcf8574_int_gpio_handler(const struct device *dev, struct gpio_callb * @retval 0 If successful. * @retval Negative value for error code. */ -static int pcf8574_port_get_raw(const struct device *dev, gpio_port_value_t *value) +static int pcf857x_port_get_raw(const struct device *dev, gpio_port_value_t *value) { - struct pcf8574_drv_data *drv_data = dev->data; + struct pcf857x_drv_data *drv_data = dev->data; int rc; if (k_is_in_isr()) { return -EWOULDBLOCK; } - if ((~drv_data->pins_cfg.configured_as_outputs & (uint8_t)*value) != (uint8_t)*value) { + if ((~drv_data->pins_cfg.configured_as_outputs & (uint16_t)*value) != (uint16_t)*value) { LOG_ERR("Pin(s) is/are configured as output which should be input."); return -EOPNOTSUPP; } @@ -136,7 +146,7 @@ static int pcf8574_port_get_raw(const struct device *dev, gpio_port_value_t *val * Reading of the input port also clears the generated interrupt, * thus the configured callbacks must be fired also here if needed. */ - rc = pcf8574_process_input(dev, value); + rc = pcf857x_process_input(dev, value); k_sem_give(&drv_data->lock); @@ -148,19 +158,20 @@ static int pcf8574_port_get_raw(const struct device *dev, gpio_port_value_t *val * * @param dev A pointer to the device structure * @param mask A mask of bits to set some bits to LOW or HIGH - * @param value The value which is written via i2c to the pfc8574's output pins + * @param value The value which is written via i2c to the pcf857x's output pins * @param toggle A way to toggle some bits with xor * * @retval 0 If successful. * @retval Negative value for error code. */ -static int pcf8574_port_set_raw(const struct device *dev, uint8_t mask, uint8_t value, - uint8_t toggle) +static int pcf857x_port_set_raw(const struct device *dev, uint16_t mask, uint16_t value, + uint16_t toggle) { - const struct pcf8574_drv_cfg *drv_cfg = dev->config; - struct pcf8574_drv_data *drv_data = dev->data; + const struct pcf857x_drv_cfg *drv_cfg = dev->config; + struct pcf857x_drv_data *drv_data = dev->data; int rc = 0; - uint8_t tx_buf; + uint16_t tx_buf; + uint8_t tx_buf_p[2]; if (k_is_in_isr()) { return -EWOULDBLOCK; @@ -174,14 +185,13 @@ static int pcf8574_port_set_raw(const struct device *dev, uint8_t mask, uint8_t tx_buf = (drv_data->pins_cfg.outputs_state & ~mask); tx_buf |= (value & mask); tx_buf ^= toggle; + sys_put_le16(tx_buf, tx_buf_p); - rc = i2c_write_dt(&drv_cfg->i2c, &tx_buf, sizeof(tx_buf)); - + rc = i2c_write_dt(&drv_cfg->i2c, tx_buf_p, drv_data->num_bytes); if (rc != 0) { LOG_ERR("%s: failed to write output port: %d", dev->name, rc); return -EIO; } - k_sem_take(&drv_data->lock, K_FOREVER); drv_data->pins_cfg.outputs_state = tx_buf; k_sem_give(&drv_data->lock); @@ -190,9 +200,9 @@ static int pcf8574_port_set_raw(const struct device *dev, uint8_t mask, uint8_t } /** - * @brief This function fills a dummy because the pfc8574 has no pins to configure. + * @brief This function fills a dummy because the pcf857x has no pins to configure. * You can use it to set some pins permanent to HIGH or LOW until reset. It uses the port_set_raw - * function to set the pins of pcf8574 directly. + * function to set the pins of pcf857x directly. * * @param dev Pointer to the device structure for the driver instance. * @param pin The bit in the io register which is set to high @@ -201,12 +211,12 @@ static int pcf8574_port_set_raw(const struct device *dev, uint8_t mask, uint8_t * @retval 0 If successful. * @retval Negative value for error. */ -static int pcf8574_pin_configure(const struct device *dev, gpio_pin_t pin, gpio_flags_t flags) +static int pcf857x_pin_configure(const struct device *dev, gpio_pin_t pin, gpio_flags_t flags) { - struct pcf8574_drv_data *drv_data = dev->data; + struct pcf857x_drv_data *drv_data = dev->data; int ret = 0; - uint8_t temp_pins = drv_data->pins_cfg.outputs_state; - uint8_t temp_outputs = drv_data->pins_cfg.configured_as_outputs; + uint16_t temp_pins = drv_data->pins_cfg.outputs_state; + uint16_t temp_outputs = drv_data->pins_cfg.configured_as_outputs; if (flags & (GPIO_PULL_UP | GPIO_PULL_DOWN | GPIO_DISCONNECTED | GPIO_SINGLE_ENDED)) { return -ENOTSUP; @@ -225,7 +235,7 @@ static int pcf8574_pin_configure(const struct device *dev, gpio_pin_t pin, gpio_ temp_pins &= ~(1 << pin); } - ret = pcf8574_port_set_raw(dev, drv_data->pins_cfg.configured_as_outputs, temp_pins, 0); + ret = pcf857x_port_set_raw(dev, drv_data->pins_cfg.configured_as_outputs, temp_pins, 0); if (ret == 0) { k_sem_take(&drv_data->lock, K_FOREVER); @@ -238,7 +248,7 @@ static int pcf8574_pin_configure(const struct device *dev, gpio_pin_t pin, gpio_ } /** - * @brief Sets a value to the pins of pcf8574 + * @brief Sets a value to the pins of pcf857x * * @param dev Pointer to the device structure for the driver instance. * @param mask The bit mask which bits should be set @@ -247,24 +257,24 @@ static int pcf8574_pin_configure(const struct device *dev, gpio_pin_t pin, gpio_ * @retval 0 If successful. * @retval Negative value for error. */ -static int pcf8574_port_set_masked_raw(const struct device *dev, gpio_port_pins_t mask, +static int pcf857x_port_set_masked_raw(const struct device *dev, gpio_port_pins_t mask, gpio_port_value_t value) { - return pcf8574_port_set_raw(dev, (uint8_t)mask, (uint8_t)value, 0); + return pcf857x_port_set_raw(dev, (uint16_t)mask, (uint16_t)value, 0); } /** - * @brief Sets some output pins of the pcf8574 + * @brief Sets some output pins of the pcf857x * * @param dev Pointer to the device structure for the driver instance. - * @param pins The pin(s) which will be set in a range from 0 to 7 + * @param pins The pin(s) which will be set in a range from P17-P10..P07-P00 * * @retval 0 If successful. * @retval Negative value for error. */ -static int pcf8574_port_set_bits_raw(const struct device *dev, gpio_port_pins_t pins) +static int pcf857x_port_set_bits_raw(const struct device *dev, gpio_port_pins_t pins) { - return pcf8574_port_set_raw(dev, (uint8_t)pins, (uint8_t)pins, 0); + return pcf857x_port_set_raw(dev, (uint16_t)pins, (uint16_t)pins, 0); } /** @@ -276,9 +286,9 @@ static int pcf8574_port_set_bits_raw(const struct device *dev, gpio_port_pins_t * @retval 0 If successful. * @retval Negative value for error. */ -static int pcf8574_port_clear_bits_raw(const struct device *dev, gpio_port_pins_t pins) +static int pcf857x_port_clear_bits_raw(const struct device *dev, gpio_port_pins_t pins) { - return pcf8574_port_set_raw(dev, (uint8_t)pins, 0, 0); + return pcf857x_port_set_raw(dev, (uint16_t)pins, 0, 0); } /** @@ -290,16 +300,16 @@ static int pcf8574_port_clear_bits_raw(const struct device *dev, gpio_port_pins_ * @retval 0 If successful. * @retval Negative value for error. */ -static int pcf8574_port_toggle_bits(const struct device *dev, gpio_port_pins_t pins) +static int pcf857x_port_toggle_bits(const struct device *dev, gpio_port_pins_t pins) { - return pcf8574_port_set_raw(dev, 0, 0, (uint8_t)pins); + return pcf857x_port_set_raw(dev, 0, 0, (uint16_t)pins); } -/* Each pin gives an interrupt at pcf8574. In this function the configuration is checked. */ -static int pcf8574_pin_interrupt_configure(const struct device *dev, gpio_pin_t pin, +/* Each pin gives an interrupt at pcf857x. In this function the configuration is checked. */ +static int pcf857x_pin_interrupt_configure(const struct device *dev, gpio_pin_t pin, enum gpio_int_mode mode, enum gpio_int_trig trig) { - const struct pcf8574_drv_cfg *drv_cfg = dev->config; + const struct pcf857x_drv_cfg *drv_cfg = dev->config; if (!drv_cfg->gpio_int.port) { return -ENOTSUP; @@ -314,19 +324,19 @@ static int pcf8574_pin_interrupt_configure(const struct device *dev, gpio_pin_t } /** Register the callback in the callback list */ -static int pcf8574_manage_callback(const struct device *dev, struct gpio_callback *callback, +static int pcf857x_manage_callback(const struct device *dev, struct gpio_callback *callback, bool set) { - struct pcf8574_drv_data *drv_data = dev->data; + struct pcf857x_drv_data *drv_data = dev->data; return gpio_manage_callback(&drv_data->callbacks, callback, set); } -/** Initialize the pcf8574 */ -static int pcf8574_init(const struct device *dev) +/** Initialize the pcf857x */ +static int pcf857x_init(const struct device *dev) { - const struct pcf8574_drv_cfg *drv_cfg = dev->config; - struct pcf8574_drv_data *drv_data = dev->data; + const struct pcf857x_drv_cfg *drv_cfg = dev->config; + struct pcf857x_drv_data *drv_data = dev->data; int rc; if (!device_is_ready(drv_cfg->i2c.bus)) { @@ -353,7 +363,7 @@ static int pcf8574_init(const struct device *dev) return -EIO; } - gpio_init_callback(&drv_data->int_gpio_cb, pcf8574_int_gpio_handler, + gpio_init_callback(&drv_data->int_gpio_cb, pcf857x_int_gpio_handler, BIT(drv_cfg->gpio_int.pin)); rc = gpio_add_callback(drv_cfg->gpio_int.port, &drv_data->int_gpio_cb); if (rc != 0) { @@ -365,20 +375,20 @@ static int pcf8574_init(const struct device *dev) return 0; } -/** Realizes the functions of gpio.h for pcf8574*/ -static const struct gpio_driver_api pcf8574_drv_api = { - .pin_configure = pcf8574_pin_configure, - .port_get_raw = pcf8574_port_get_raw, - .port_set_masked_raw = pcf8574_port_set_masked_raw, - .port_set_bits_raw = pcf8574_port_set_bits_raw, - .port_clear_bits_raw = pcf8574_port_clear_bits_raw, - .port_toggle_bits = pcf8574_port_toggle_bits, - .pin_interrupt_configure = pcf8574_pin_interrupt_configure, - .manage_callback = pcf8574_manage_callback, +/** Realizes the functions of gpio.h for pcf857x*/ +static const struct gpio_driver_api pcf857x_drv_api = { + .pin_configure = pcf857x_pin_configure, + .port_get_raw = pcf857x_port_get_raw, + .port_set_masked_raw = pcf857x_port_set_masked_raw, + .port_set_bits_raw = pcf857x_port_set_bits_raw, + .port_clear_bits_raw = pcf857x_port_clear_bits_raw, + .port_toggle_bits = pcf857x_port_toggle_bits, + .pin_interrupt_configure = pcf857x_pin_interrupt_configure, + .manage_callback = pcf857x_manage_callback, }; -#define GPIO_PCF8574_INST(idx) \ - static const struct pcf8574_drv_cfg pcf8574_cfg##idx = { \ +#define GPIO_PCF857X_INST(idx) \ + static const struct pcf857x_drv_cfg pcf857x_cfg##idx = { \ .common = \ { \ .port_pin_mask = GPIO_PORT_PIN_MASK_FROM_DT_INST(idx), \ @@ -386,12 +396,13 @@ static const struct gpio_driver_api pcf8574_drv_api = { .gpio_int = GPIO_DT_SPEC_INST_GET_OR(idx, int_gpios, {0}), \ .i2c = I2C_DT_SPEC_INST_GET(idx), \ }; \ - static struct pcf8574_drv_data pcf8574_data##idx = { \ - .lock = Z_SEM_INITIALIZER(pcf8574_data##idx.lock, 1, 1), \ - .work = Z_WORK_INITIALIZER(pcf8574_work_handler), \ + static struct pcf857x_drv_data pcf857x_data##idx = { \ + .lock = Z_SEM_INITIALIZER(pcf857x_data##idx.lock, 1, 1), \ + .work = Z_WORK_INITIALIZER(pcf857x_work_handler), \ .dev = DEVICE_DT_INST_GET(idx), \ + .num_bytes = DT_INST_ENUM_IDX(idx, ngpios) + 1, \ }; \ - DEVICE_DT_INST_DEFINE(idx, pcf8574_init, NULL, &pcf8574_data##idx, &pcf8574_cfg##idx, \ - POST_KERNEL, CONFIG_GPIO_PCF8574_INIT_PRIORITY, &pcf8574_drv_api); + DEVICE_DT_INST_DEFINE(idx, pcf857x_init, NULL, &pcf857x_data##idx, &pcf857x_cfg##idx, \ + POST_KERNEL, CONFIG_GPIO_PCF857X_INIT_PRIORITY, &pcf857x_drv_api); -DT_INST_FOREACH_STATUS_OKAY(GPIO_PCF8574_INST); +DT_INST_FOREACH_STATUS_OKAY(GPIO_PCF857X_INST); diff --git a/dts/bindings/gpio/nxp,pcf8574.yaml b/dts/bindings/gpio/nxp,pcf857x.yaml similarity index 64% rename from dts/bindings/gpio/nxp,pcf8574.yaml rename to dts/bindings/gpio/nxp,pcf857x.yaml index 96cb2409c16..868ba520571 100644 --- a/dts/bindings/gpio/nxp,pcf8574.yaml +++ b/dts/bindings/gpio/nxp,pcf857x.yaml @@ -1,16 +1,20 @@ # Copyright (c) 2022 ithinx GmbH +# 2023 Amrith Venkat Kesavamoorthi +# 2023 Mr Beam Lasers GmbH. # SPDX-License-Identifier: Apache-2.0 -description: PCF8574 8-bit I2C-based I/O expander +description: PCF857x 8/16-bit I2C-based I/O expander -compatible: "nxp,pcf8574" +compatible: "nxp,pcf857x" include: [i2c-device.yaml, gpio-controller.yaml] properties: ngpios: required: true - const: 8 + enum: + - 8 + - 16 int-gpios: type: phandle-array diff --git a/tests/drivers/build_all/gpio/app.overlay b/tests/drivers/build_all/gpio/app.overlay index 375b3ab25dc..c6dabd6532c 100644 --- a/tests/drivers/build_all/gpio/app.overlay +++ b/tests/drivers/build_all/gpio/app.overlay @@ -68,8 +68,17 @@ interrupt-gpios = <&test_gpio 0 0>; }; + test_i2c_pcf8575: pcf8575@21 { + compatible = "nxp,pcf857x"; + reg = <0x21>; + gpio-controller; + #gpio-cells = <2>; + ngpios = <16>; + int-gpios = <&test_gpio 0 0>; + }; + test_i2c_pcf8574: pcf8574@27 { - compatible = "nxp,pcf8574"; + compatible = "nxp,pcf857x"; reg = <0x27>; gpio-controller; #gpio-cells = <2>; From af126d010afe433a3feed5335cc52511c5c69c12 Mon Sep 17 00:00:00 2001 From: Erwan Gouriou Date: Thu, 19 Oct 2023 09:36:27 +0200 Subject: [PATCH 2290/3723] include: pinctrl.h: Make PINCTRL_SKIP_SLEEP available with CONFIG_PM In some cases, PINCTRL_STATE_SLEEP may be required even when CONFIG_PM_DEVICE is not defined. One example is the possibility/need to put JTAG pins to analog when CONIG_PM=y and CONFIG_DEBUG=n. Signed-off-by: Erwan Gouriou --- doc/hardware/pinctrl/index.rst | 11 ++++++----- include/zephyr/drivers/pinctrl.h | 4 ++-- 2 files changed, 8 insertions(+), 7 deletions(-) diff --git a/doc/hardware/pinctrl/index.rst b/doc/hardware/pinctrl/index.rst index c67f46a0cb1..98edfeacf58 100644 --- a/doc/hardware/pinctrl/index.rst +++ b/doc/hardware/pinctrl/index.rst @@ -145,9 +145,10 @@ In most situations, the states defined in Devicetree will be the ones used in the compiled firmware. However, there are some cases where certain states will be conditionally used depending on a compilation flag. A typical case is the ``sleep`` state. This state is only used in practice if -:kconfig:option:`CONFIG_PM_DEVICE` is enabled. If a firmware variant without device -power management is needed, one should in theory remove the ``sleep`` state from -Devicetree to not waste ROM space storing such unused state. +:kconfig:option:`CONFIG_PM` or :kconfig:option:`CONFIG_PM_DEVICE` is enabled. +If a firmware variant without these power management configurations is needed, +one should in theory remove the ``sleep`` state from Devicetree to not waste ROM +space storing such unused state. States can be skipped by the ``pinctrl`` Devicetree macros if a definition named ``PINCTRL_SKIP_{STATE_NAME}`` expanding to ``1`` is present when pin control @@ -157,8 +158,8 @@ management: .. code-block:: c - #ifndef CONFIG_PM_DEVICE - /** If device power management is not enabled, "sleep" state will be ignored. */ + #if !defined(CONFIG_PM) && !defined(CONFIG_PM_DEVICE) + /** Out of power management configurations, ignore "sleep" state. */ #define PINCTRL_SKIP_SLEEP 1 #endif diff --git a/include/zephyr/drivers/pinctrl.h b/include/zephyr/drivers/pinctrl.h index b0fd60e891b..e03456c76c3 100644 --- a/include/zephyr/drivers/pinctrl.h +++ b/include/zephyr/drivers/pinctrl.h @@ -76,8 +76,8 @@ struct pinctrl_dev_config { /** @cond INTERNAL_HIDDEN */ -#ifndef CONFIG_PM_DEVICE -/** If device power management is not enabled, "sleep" state will be ignored. */ +#if !defined(CONFIG_PM) && !defined(CONFIG_PM_DEVICE) +/** Out of power management configurations, ignore "sleep" state. */ #define PINCTRL_SKIP_SLEEP 1 #endif From c82789c5ff8fffae650a8c99ae5da2535138b8c5 Mon Sep 17 00:00:00 2001 From: Laurentiu Mihalcea Date: Mon, 15 Jan 2024 23:42:36 +0200 Subject: [PATCH 2291/3723] drivers: serial: uart_mcux_lpuart: Switch to using DT_INST_IRQN_BY_IDX After #63289, multi-level interrupts are now encoded using macro magic. This means that using the generic DT_INST_IRQ_BY_IDX() to fetch the INTID is no longer an option as the queried INTID will be the one specified through the node's `interrupts` properties. To fix this, switch to using DT_INST_IRQN_BY_IDX() which will return the correctly encoded INTID. Signed-off-by: Laurentiu Mihalcea --- drivers/serial/uart_mcux_lpuart.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/serial/uart_mcux_lpuart.c b/drivers/serial/uart_mcux_lpuart.c index e46d8d73607..3c2f318f90e 100644 --- a/drivers/serial/uart_mcux_lpuart.c +++ b/drivers/serial/uart_mcux_lpuart.c @@ -1116,7 +1116,7 @@ static const struct uart_driver_api mcux_lpuart_driver_api = { #ifdef CONFIG_UART_MCUX_LPUART_ISR_SUPPORT #define MCUX_LPUART_IRQ_INSTALL(n, i) \ do { \ - IRQ_CONNECT(DT_INST_IRQ_BY_IDX(n, i, irq), \ + IRQ_CONNECT(DT_INST_IRQN_BY_IDX(n, i), \ DT_INST_IRQ_BY_IDX(n, i, priority), \ mcux_lpuart_isr, DEVICE_DT_INST_GET(n), 0); \ \ From d161d05e3390c373d532887e9e36eaa5e4663c19 Mon Sep 17 00:00:00 2001 From: Tomas Galbicka Date: Thu, 21 Dec 2023 14:15:22 +0000 Subject: [PATCH 2292/3723] samples: mbox: Add support for NXP RT boards This commit adds mbox sample support for these NXP boards: - MIMXRT1160-EVK - MIMXRT1170-EVK - MIMXRT1170-EVKB Signed-off-by: Tomas Galbicka --- samples/drivers/mbox/CMakeLists.txt | 11 +++++ samples/drivers/mbox/Kconfig | 11 +++++ samples/drivers/mbox/Kconfig.sysbuild | 4 ++ .../mbox/boards/mimxrt1160_evk_cm7.conf | 3 ++ .../mbox/boards/mimxrt1160_evk_cm7.overlay | 29 +++++++++++ .../mbox/boards/mimxrt1170_evk_cm7.conf | 3 ++ .../mbox/boards/mimxrt1170_evk_cm7.overlay | 29 +++++++++++ .../mbox/boards/mimxrt1170_evkb_cm7.conf | 3 ++ .../mbox/boards/mimxrt1170_evkb_cm7.overlay | 29 +++++++++++ samples/drivers/mbox/remote/CMakeLists.txt | 4 ++ .../remote/boards/mimxrt1160_evk_cm4.conf | 4 ++ .../remote/boards/mimxrt1160_evk_cm4.overlay | 48 ++++++++++++++++++ .../remote/boards/mimxrt1170_evk_cm4.conf | 4 ++ .../remote/boards/mimxrt1170_evk_cm4.overlay | 48 ++++++++++++++++++ .../remote/boards/mimxrt1170_evkb_cm4.conf | 4 ++ .../remote/boards/mimxrt1170_evkb_cm4.overlay | 49 +++++++++++++++++++ samples/drivers/mbox/sample.yaml | 13 ++++- samples/drivers/mbox/sysbuild.cmake | 12 +++++ 18 files changed, 307 insertions(+), 1 deletion(-) create mode 100644 samples/drivers/mbox/Kconfig create mode 100644 samples/drivers/mbox/boards/mimxrt1160_evk_cm7.conf create mode 100644 samples/drivers/mbox/boards/mimxrt1160_evk_cm7.overlay create mode 100644 samples/drivers/mbox/boards/mimxrt1170_evk_cm7.conf create mode 100644 samples/drivers/mbox/boards/mimxrt1170_evk_cm7.overlay create mode 100644 samples/drivers/mbox/boards/mimxrt1170_evkb_cm7.conf create mode 100644 samples/drivers/mbox/boards/mimxrt1170_evkb_cm7.overlay create mode 100644 samples/drivers/mbox/remote/boards/mimxrt1160_evk_cm4.conf create mode 100644 samples/drivers/mbox/remote/boards/mimxrt1160_evk_cm4.overlay create mode 100644 samples/drivers/mbox/remote/boards/mimxrt1170_evk_cm4.conf create mode 100644 samples/drivers/mbox/remote/boards/mimxrt1170_evk_cm4.overlay create mode 100644 samples/drivers/mbox/remote/boards/mimxrt1170_evkb_cm4.conf create mode 100644 samples/drivers/mbox/remote/boards/mimxrt1170_evkb_cm4.overlay diff --git a/samples/drivers/mbox/CMakeLists.txt b/samples/drivers/mbox/CMakeLists.txt index e65d44f0048..4344f4f3ce9 100644 --- a/samples/drivers/mbox/CMakeLists.txt +++ b/samples/drivers/mbox/CMakeLists.txt @@ -1,5 +1,6 @@ # # Copyright (c) 2021 Carlo Caione +# Copyright 2023 NXP # # SPDX-License-Identifier: Apache-2.0 # @@ -8,9 +9,14 @@ cmake_minimum_required(VERSION 3.20.0) find_package(Zephyr REQUIRED HINTS $ENV{ZEPHYR_BASE}) +set(REMOTE_ZEPHYR_DIR ${CMAKE_CURRENT_BINARY_DIR}/../remote/zephyr) + if(("${BOARD}" STREQUAL "nrf5340dk_nrf5340_cpuapp") OR ("${BOARD}" STREQUAL "nrf5340bsim_nrf5340_cpuapp") OR ("${BOARD}" STREQUAL "adp_xc7k_ae350") OR + ("${BOARD}" STREQUAL "mimxrt1170_evkb_cm7") OR + ("${BOARD}" STREQUAL "mimxrt1170_evk_cm7") OR + ("${BOARD}" STREQUAL "mimxrt1160_evk_cm7") OR ("${BOARD}" STREQUAL "mimxrt595_evk_cm33")) message(STATUS "${BOARD} compile as Main in this sample") else() @@ -21,4 +27,9 @@ project(mbox_ipc) enable_language(C ASM) +if(CONFIG_INCLUDE_REMOTE_DIR) + target_include_directories(zephyr_interface + INTERFACE ${REMOTE_ZEPHYR_DIR}/include/public) +endif() + target_sources(app PRIVATE src/main.c) diff --git a/samples/drivers/mbox/Kconfig b/samples/drivers/mbox/Kconfig new file mode 100644 index 00000000000..3837c49b6e9 --- /dev/null +++ b/samples/drivers/mbox/Kconfig @@ -0,0 +1,11 @@ +# Copyright 2023 NXP +# +# SPDX-License-Identifier: Apache-2.0 + +source "Kconfig.zephyr" + +config INCLUDE_REMOTE_DIR + bool "Include remote core header directory" + help + Include remote build header files. Can be used if primary image + needs to be aware of size or base address of secondary image diff --git a/samples/drivers/mbox/Kconfig.sysbuild b/samples/drivers/mbox/Kconfig.sysbuild index 46ffe3e12ae..f472576df82 100644 --- a/samples/drivers/mbox/Kconfig.sysbuild +++ b/samples/drivers/mbox/Kconfig.sysbuild @@ -1,4 +1,5 @@ # Copyright 2023 Nordic Semiconductor ASA +# Copyright 2023 NXP # # SPDX-License-Identifier: Apache-2.0 @@ -10,3 +11,6 @@ string default "nrf5340bsim_nrf5340_cpunet" if $(BOARD) = "nrf5340bsim_nrf5340_cpuapp" default "adp_xc7k_ae350" if $(BOARD) = "adp_xc7k_ae350" default "nrf5340dk_nrf5340_cpunet" if $(BOARD) = "mimxrt595_evk_cm33" + default "mimxrt1170_evkb_cm4" if $(BOARD) = "mimxrt1170_evkb_cm7" + default "mimxrt1170_evk_cm4" if $(BOARD) = "mimxrt1170_evk_cm7" + default "mimxrt1160_evk_cm4" if $(BOARD) = "mimxrt1160_evk_cm7" diff --git a/samples/drivers/mbox/boards/mimxrt1160_evk_cm7.conf b/samples/drivers/mbox/boards/mimxrt1160_evk_cm7.conf new file mode 100644 index 00000000000..583b4950360 --- /dev/null +++ b/samples/drivers/mbox/boards/mimxrt1160_evk_cm7.conf @@ -0,0 +1,3 @@ +CONFIG_MBOX_NXP_IMX_MU=y +CONFIG_INCLUDE_REMOTE_DIR=y +CONFIG_SECOND_CORE_MCUX=y diff --git a/samples/drivers/mbox/boards/mimxrt1160_evk_cm7.overlay b/samples/drivers/mbox/boards/mimxrt1160_evk_cm7.overlay new file mode 100644 index 00000000000..942f67ba6a9 --- /dev/null +++ b/samples/drivers/mbox/boards/mimxrt1160_evk_cm7.overlay @@ -0,0 +1,29 @@ +/* + * Copyright 2023 NXP + * + * SPDX-License-Identifier: Apache-2.0 + */ + +/ { + chosen { + /* Delete ipc chosen property where old IPM mailbox driver bellow is + * configured. + */ + /delete-property/ zephyr,ipc; + }; + + soc { + /* Delete IPM Driver node nxp,imx-mu */ + /delete-node/ mailbox@40c48000; + + /* Attach MBOX driver to MU Unit */ + mbox:mbox@40c48000 { + compatible = "nxp,mbox-imx-mu"; + reg = <0x40c48000 0x4000>; + interrupts = <118 0>; + rx-channels = <4>; + #mbox-cells = <1>; + status = "okay"; + }; + }; +}; diff --git a/samples/drivers/mbox/boards/mimxrt1170_evk_cm7.conf b/samples/drivers/mbox/boards/mimxrt1170_evk_cm7.conf new file mode 100644 index 00000000000..583b4950360 --- /dev/null +++ b/samples/drivers/mbox/boards/mimxrt1170_evk_cm7.conf @@ -0,0 +1,3 @@ +CONFIG_MBOX_NXP_IMX_MU=y +CONFIG_INCLUDE_REMOTE_DIR=y +CONFIG_SECOND_CORE_MCUX=y diff --git a/samples/drivers/mbox/boards/mimxrt1170_evk_cm7.overlay b/samples/drivers/mbox/boards/mimxrt1170_evk_cm7.overlay new file mode 100644 index 00000000000..942f67ba6a9 --- /dev/null +++ b/samples/drivers/mbox/boards/mimxrt1170_evk_cm7.overlay @@ -0,0 +1,29 @@ +/* + * Copyright 2023 NXP + * + * SPDX-License-Identifier: Apache-2.0 + */ + +/ { + chosen { + /* Delete ipc chosen property where old IPM mailbox driver bellow is + * configured. + */ + /delete-property/ zephyr,ipc; + }; + + soc { + /* Delete IPM Driver node nxp,imx-mu */ + /delete-node/ mailbox@40c48000; + + /* Attach MBOX driver to MU Unit */ + mbox:mbox@40c48000 { + compatible = "nxp,mbox-imx-mu"; + reg = <0x40c48000 0x4000>; + interrupts = <118 0>; + rx-channels = <4>; + #mbox-cells = <1>; + status = "okay"; + }; + }; +}; diff --git a/samples/drivers/mbox/boards/mimxrt1170_evkb_cm7.conf b/samples/drivers/mbox/boards/mimxrt1170_evkb_cm7.conf new file mode 100644 index 00000000000..0dfb100ed70 --- /dev/null +++ b/samples/drivers/mbox/boards/mimxrt1170_evkb_cm7.conf @@ -0,0 +1,3 @@ +CONFIG_MBOX_NXP_IMX_MU=y +CONFIG_SECOND_CORE_MCUX=y +CONFIG_INCLUDE_REMOTE_DIR=y diff --git a/samples/drivers/mbox/boards/mimxrt1170_evkb_cm7.overlay b/samples/drivers/mbox/boards/mimxrt1170_evkb_cm7.overlay new file mode 100644 index 00000000000..942f67ba6a9 --- /dev/null +++ b/samples/drivers/mbox/boards/mimxrt1170_evkb_cm7.overlay @@ -0,0 +1,29 @@ +/* + * Copyright 2023 NXP + * + * SPDX-License-Identifier: Apache-2.0 + */ + +/ { + chosen { + /* Delete ipc chosen property where old IPM mailbox driver bellow is + * configured. + */ + /delete-property/ zephyr,ipc; + }; + + soc { + /* Delete IPM Driver node nxp,imx-mu */ + /delete-node/ mailbox@40c48000; + + /* Attach MBOX driver to MU Unit */ + mbox:mbox@40c48000 { + compatible = "nxp,mbox-imx-mu"; + reg = <0x40c48000 0x4000>; + interrupts = <118 0>; + rx-channels = <4>; + #mbox-cells = <1>; + status = "okay"; + }; + }; +}; diff --git a/samples/drivers/mbox/remote/CMakeLists.txt b/samples/drivers/mbox/remote/CMakeLists.txt index 3aee2d96482..e7db9b8cadf 100644 --- a/samples/drivers/mbox/remote/CMakeLists.txt +++ b/samples/drivers/mbox/remote/CMakeLists.txt @@ -1,5 +1,6 @@ # # Copyright (c) 2021 Carlo Caione +# Copyright 2023 NXP # # SPDX-License-Identifier: Apache-2.0 # @@ -10,6 +11,9 @@ find_package(Zephyr REQUIRED HINTS $ENV{ZEPHYR_BASE}) if(("${BOARD}" STREQUAL "nrf5340dk_nrf5340_cpunet") OR ("${BOARD}" STREQUAL "nrf5340bsim_nrf5340_cpunet") OR + ("${BOARD}" STREQUAL "mimxrt1170_evkb_cm4") OR + ("${BOARD}" STREQUAL "mimxrt1170_evk_cm4") OR + ("${BOARD}" STREQUAL "mimxrt1160_evk_cm4") OR ("${BOARD}" STREQUAL "adp_xc7k_ae350")) message(STATUS "${BOARD} compile as remote in this sample") else() diff --git a/samples/drivers/mbox/remote/boards/mimxrt1160_evk_cm4.conf b/samples/drivers/mbox/remote/boards/mimxrt1160_evk_cm4.conf new file mode 100644 index 00000000000..0d36a72aec6 --- /dev/null +++ b/samples/drivers/mbox/remote/boards/mimxrt1160_evk_cm4.conf @@ -0,0 +1,4 @@ +CONFIG_MBOX_NXP_IMX_MU=y +CONFIG_BUILD_OUTPUT_INFO_HEADER=y +CONFIG_BUILD_OUTPUT_HEX=y +CONFIG_SECOND_CORE_MCUX=y diff --git a/samples/drivers/mbox/remote/boards/mimxrt1160_evk_cm4.overlay b/samples/drivers/mbox/remote/boards/mimxrt1160_evk_cm4.overlay new file mode 100644 index 00000000000..cc05e9b96c1 --- /dev/null +++ b/samples/drivers/mbox/remote/boards/mimxrt1160_evk_cm4.overlay @@ -0,0 +1,48 @@ +/* + * Copyright 2023 NXP + * + * SPDX-License-Identifier: Apache-2.0 + */ + +/ { + chosen { + zephyr,flash = &ocram; + zephyr,console = &lpuart1; + zephyr,shell-uart = &lpuart1; + + /* Delete ipc chosen property where old IPM mailbox driver bellow is + * configured. + */ + /delete-property/ zephyr,ipc; + }; + + soc { + /delete-node/ gpt@400f0000; + + /* Replace GPT2 with another GPT kernel timer */ + gpt2_hw_timer:gpt@400f0000 { + compatible = "nxp,gpt-hw-timer"; + reg = <0x400f0000 0x4000>; + interrupts = <120 0>; + status = "okay"; + }; + + /* Delete IPM Driver node nxp,imx-mu */ + /delete-node/ mailbox@40c4c000; + + /* Attach MBOX driver to MU Unit */ + mbox:mbox@40c4c000 { + compatible = "nxp,mbox-imx-mu"; + reg = <0x40c4c000 0x4000>; + interrupts = <118 0>; + rx-channels = <4>; + #mbox-cells = <1>; + status = "okay"; + }; + }; +}; + +/* Disable primary GPT timer */ +&gpt_hw_timer { + status = "disabled"; +}; diff --git a/samples/drivers/mbox/remote/boards/mimxrt1170_evk_cm4.conf b/samples/drivers/mbox/remote/boards/mimxrt1170_evk_cm4.conf new file mode 100644 index 00000000000..0d36a72aec6 --- /dev/null +++ b/samples/drivers/mbox/remote/boards/mimxrt1170_evk_cm4.conf @@ -0,0 +1,4 @@ +CONFIG_MBOX_NXP_IMX_MU=y +CONFIG_BUILD_OUTPUT_INFO_HEADER=y +CONFIG_BUILD_OUTPUT_HEX=y +CONFIG_SECOND_CORE_MCUX=y diff --git a/samples/drivers/mbox/remote/boards/mimxrt1170_evk_cm4.overlay b/samples/drivers/mbox/remote/boards/mimxrt1170_evk_cm4.overlay new file mode 100644 index 00000000000..cc05e9b96c1 --- /dev/null +++ b/samples/drivers/mbox/remote/boards/mimxrt1170_evk_cm4.overlay @@ -0,0 +1,48 @@ +/* + * Copyright 2023 NXP + * + * SPDX-License-Identifier: Apache-2.0 + */ + +/ { + chosen { + zephyr,flash = &ocram; + zephyr,console = &lpuart1; + zephyr,shell-uart = &lpuart1; + + /* Delete ipc chosen property where old IPM mailbox driver bellow is + * configured. + */ + /delete-property/ zephyr,ipc; + }; + + soc { + /delete-node/ gpt@400f0000; + + /* Replace GPT2 with another GPT kernel timer */ + gpt2_hw_timer:gpt@400f0000 { + compatible = "nxp,gpt-hw-timer"; + reg = <0x400f0000 0x4000>; + interrupts = <120 0>; + status = "okay"; + }; + + /* Delete IPM Driver node nxp,imx-mu */ + /delete-node/ mailbox@40c4c000; + + /* Attach MBOX driver to MU Unit */ + mbox:mbox@40c4c000 { + compatible = "nxp,mbox-imx-mu"; + reg = <0x40c4c000 0x4000>; + interrupts = <118 0>; + rx-channels = <4>; + #mbox-cells = <1>; + status = "okay"; + }; + }; +}; + +/* Disable primary GPT timer */ +&gpt_hw_timer { + status = "disabled"; +}; diff --git a/samples/drivers/mbox/remote/boards/mimxrt1170_evkb_cm4.conf b/samples/drivers/mbox/remote/boards/mimxrt1170_evkb_cm4.conf new file mode 100644 index 00000000000..0d36a72aec6 --- /dev/null +++ b/samples/drivers/mbox/remote/boards/mimxrt1170_evkb_cm4.conf @@ -0,0 +1,4 @@ +CONFIG_MBOX_NXP_IMX_MU=y +CONFIG_BUILD_OUTPUT_INFO_HEADER=y +CONFIG_BUILD_OUTPUT_HEX=y +CONFIG_SECOND_CORE_MCUX=y diff --git a/samples/drivers/mbox/remote/boards/mimxrt1170_evkb_cm4.overlay b/samples/drivers/mbox/remote/boards/mimxrt1170_evkb_cm4.overlay new file mode 100644 index 00000000000..392141712a9 --- /dev/null +++ b/samples/drivers/mbox/remote/boards/mimxrt1170_evkb_cm4.overlay @@ -0,0 +1,49 @@ +/* + * Copyright 2023 NXP + * + * SPDX-License-Identifier: Apache-2.0 + */ + +/ { + chosen { + zephyr,flash = &ocram; + zephyr,console = &lpuart1; + zephyr,shell-uart = &lpuart1; + + /* Delete ipc chosen property where old IPM mailbox driver bellow is + * configured. + */ + /delete-property/ zephyr,ipc; + }; + + soc { + /delete-node/ gpt@400f0000; + + /* Replace GPT2 with another GPT kernel timer */ + gpt2_hw_timer:gpt@400f0000 { + compatible = "nxp,gpt-hw-timer"; + reg = <0x400f0000 0x4000>; + interrupts = <120 0>; + status = "okay"; + }; + + /* Delete IPM Driver node nxp,imx-mu */ + /delete-node/ mailbox@40c4c000; + + /* Attach MBOX driver to MU Unit */ + mbox:mbox@40c4c000 { + compatible = "nxp,mbox-imx-mu"; + reg = <0x40c4c000 0x4000>; + interrupts = <118 0>; + rx-channels = <4>; + #mbox-cells = <1>; + status = "okay"; + }; + }; + +}; + +/* Disable primary GPT timer */ +&gpt_hw_timer { + status = "disabled"; +}; diff --git a/samples/drivers/mbox/sample.yaml b/samples/drivers/mbox/sample.yaml index f7aa8953ea1..e8015cf7c25 100644 --- a/samples/drivers/mbox/sample.yaml +++ b/samples/drivers/mbox/sample.yaml @@ -9,9 +9,20 @@ tests: - nrf5340dk_nrf5340_cpuapp - adp_xc7k_ae350 - mimxrt595_evk_cm33 + - mimxrt1170_evkb_cm7 + - mimxrt1170_evk_cm7 + - mimxrt1160_evk_cm7 integration_platforms: - nrf5340dk_nrf5340_cpuapp - harness: remote + harness: console + harness_config: + type: multi_line + ordered: false + regex: + - "Ping \\(on channel 0\\)" + - "Pong \\(on channel 0\\)" + - "Ping \\(on channel 1\\)" + - "Pong \\(on channel 1\\)" sample.drivers.mbox.simu: platform_allow: - nrf5340bsim_nrf5340_cpuapp diff --git a/samples/drivers/mbox/sysbuild.cmake b/samples/drivers/mbox/sysbuild.cmake index a8dfb8ebdf4..7a5d32d4c74 100644 --- a/samples/drivers/mbox/sysbuild.cmake +++ b/samples/drivers/mbox/sysbuild.cmake @@ -1,4 +1,5 @@ # Copyright (c) 2023 Nordic Semiconductor ASA +# Copyright 2023 NXP # SPDX-License-Identifier: Apache-2.0 if("${SB_CONFIG_REMOTE_BOARD}" STREQUAL "") @@ -18,3 +19,14 @@ ExternalZephyrProject_Add( native_simulator_set_child_images(${DEFAULT_IMAGE} ${REMOTE_APP}) native_simulator_set_final_executable(${DEFAULT_IMAGE}) + +if ("${BOARD}" STREQUAL "mimxrt1170_evkb_cm7" OR + "${BOARD}" STREQUAL "mimxrt1170_evk_cm7" OR + "${BOARD}" STREQUAL "mimxrt1160_evk_cm7" + ) + # For these NXP boards the main core application is dependent on + # 'zephyr_image_info.h' generated by remote application. + + # Let's build the remote application first + add_dependencies(${DEFAULT_IMAGE} ${REMOTE_APP}) +endif() From 54d177a3e70f3903c7ed8548832be71b56977ff8 Mon Sep 17 00:00:00 2001 From: Anas Nashif Date: Mon, 15 Jan 2024 20:40:34 +0000 Subject: [PATCH 2293/3723] tests: uart: do not filter if we know which platforms to use No need for filtering in one of the tests, since we have platform_allow. Signed-off-by: Anas Nashif --- tests/drivers/uart/uart_async_rx/testcase.yaml | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/tests/drivers/uart/uart_async_rx/testcase.yaml b/tests/drivers/uart/uart_async_rx/testcase.yaml index 23a1b154975..d0c85fce0a2 100644 --- a/tests/drivers/uart/uart_async_rx/testcase.yaml +++ b/tests/drivers/uart/uart_async_rx/testcase.yaml @@ -5,10 +5,12 @@ tests: integration_platforms: - native_sim drivers.uart.async_rx.ztress: - filter: CONFIG_SERIAL tags: drivers uart - platform_allow: > - qemu_cortex_m3 qemu_x86 qemu_x86_64 qemu_riscv32 + platform_allow: + - qemu_cortex_m3 + - qemu_x86 + - qemu_x86_64 + - qemu_riscv32 integration_platforms: - qemu_x86 extra_configs: From ead02284f0c49c83d14b3d430a4e9a2c7c4dcc40 Mon Sep 17 00:00:00 2001 From: Anas Nashif Date: Mon, 15 Jan 2024 22:26:17 +0000 Subject: [PATCH 2294/3723] tests: uart: filter by CONFIG_SERIAL_HAS_DRIVER filtering by CONFIG_SERIAL always matches, we need a different filter and be able to enable the driver if supported. Signed-off-by: Anas Nashif --- tests/drivers/uart/uart_async_rx/testcase.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/drivers/uart/uart_async_rx/testcase.yaml b/tests/drivers/uart/uart_async_rx/testcase.yaml index d0c85fce0a2..c6470b34a1a 100644 --- a/tests/drivers/uart/uart_async_rx/testcase.yaml +++ b/tests/drivers/uart/uart_async_rx/testcase.yaml @@ -1,6 +1,6 @@ tests: drivers.uart.async_rx: - filter: CONFIG_SERIAL + filter: CONFIG_SERIAL_HAS_DRIVER tags: drivers uart integration_platforms: - native_sim From f9c116ec73b5e688f251c0229422e23ab5214070 Mon Sep 17 00:00:00 2001 From: Emil Gydesen Date: Wed, 3 Jan 2024 15:06:43 +0100 Subject: [PATCH 2295/3723] Bluetooth: CAP: Shell: Fix channel allocation The channel allocation was incorrect when setting up multiple streams to a single device, in which case we should apply individual bits to each stream. Signed-off-by: Emil Gydesen --- subsys/bluetooth/audio/shell/cap_initiator.c | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/subsys/bluetooth/audio/shell/cap_initiator.c b/subsys/bluetooth/audio/shell/cap_initiator.c index 070fd614036..64cff4672c5 100644 --- a/subsys/bluetooth/audio/shell/cap_initiator.c +++ b/subsys/bluetooth/audio/shell/cap_initiator.c @@ -572,7 +572,10 @@ static int cap_ac_unicast_start(const struct bap_unicast_ac_param *param, snk_stream_cnt++; stream_cnt++; - if (param->conn_cnt > 1) { + /* If we have more than 1 connection or stream in one direction, we set the + * location bit accordingly + */ + if (param->conn_cnt > 1U || param->snk_cnt[i] > 1U) { const int err = bt_audio_codec_cfg_set_chan_allocation( stream_param->codec_cfg, (enum bt_audio_location)BIT(i)); @@ -599,7 +602,10 @@ static int cap_ac_unicast_start(const struct bap_unicast_ac_param *param, src_stream_cnt++; stream_cnt++; - if (param->conn_cnt > 1) { + /* If we have more than 1 connection or stream in one direction, we set the + * location bit accordingly + */ + if (param->conn_cnt > 1U || param->src_cnt[i] > 1U) { const int err = bt_audio_codec_cfg_set_chan_allocation( stream_param->codec_cfg, (enum bt_audio_location)BIT(i)); From fd3e3345394986225079921e008d63215335989d Mon Sep 17 00:00:00 2001 From: Emil Gydesen Date: Wed, 3 Jan 2024 15:07:25 +0100 Subject: [PATCH 2296/3723] tests: Bluetooth: Audio: Fix channel allocation The channel allocation was incorrect when setting up multiple streams to a single device, in which case we should apply individual bits to each stream. Signed-off-by: Emil Gydesen --- .../audio/src/cap_initiator_unicast_test.c | 10 ++++++-- .../bsim/bluetooth/audio/src/gmap_ugg_test.c | 24 +++++++++++++++---- 2 files changed, 28 insertions(+), 6 deletions(-) diff --git a/tests/bsim/bluetooth/audio/src/cap_initiator_unicast_test.c b/tests/bsim/bluetooth/audio/src/cap_initiator_unicast_test.c index 37c175d8d55..fd079122a53 100644 --- a/tests/bsim/bluetooth/audio/src/cap_initiator_unicast_test.c +++ b/tests/bsim/bluetooth/audio/src/cap_initiator_unicast_test.c @@ -1083,7 +1083,10 @@ static int cap_initiator_ac_cap_unicast_start(const struct cap_initiator_ac_para snk_stream_cnt++; stream_cnt++; - if (param->conn_cnt > 1) { + /* If we have more than 1 connection or stream in one direction, we set the + * location bit accordingly + */ + if (param->conn_cnt > 1U || param->snk_cnt[i] > 1U) { const int err = bt_audio_codec_cfg_set_chan_allocation( stream_param->codec_cfg, (enum bt_audio_location)BIT(i)); @@ -1106,7 +1109,10 @@ static int cap_initiator_ac_cap_unicast_start(const struct cap_initiator_ac_para src_stream_cnt++; stream_cnt++; - if (param->conn_cnt > 1) { + /* If we have more than 1 connection or stream in one direction, we set the + * location bit accordingly + */ + if (param->conn_cnt > 1U || param->src_cnt[i] > 1U) { const int err = bt_audio_codec_cfg_set_chan_allocation( stream_param->codec_cfg, (enum bt_audio_location)BIT(i)); diff --git a/tests/bsim/bluetooth/audio/src/gmap_ugg_test.c b/tests/bsim/bluetooth/audio/src/gmap_ugg_test.c index 8763f663fad..3f9f0e1dbac 100644 --- a/tests/bsim/bluetooth/audio/src/gmap_ugg_test.c +++ b/tests/bsim/bluetooth/audio/src/gmap_ugg_test.c @@ -739,9 +739,17 @@ static int gmap_ac_cap_unicast_start(const struct gmap_unicast_ac_param *param, snk_stream_cnt++; stream_cnt++; - if (param->conn_cnt > 1) { - bt_audio_codec_cfg_set_chan_allocation( + /* If we have more than 1 connection or stream in one direction, we set the + * location bit accordingly + */ + if (param->conn_cnt > 1U || param->snk_cnt[i] > 1U) { + const int err = bt_audio_codec_cfg_set_chan_allocation( stream_param->codec_cfg, (enum bt_audio_location)BIT(i)); + + if (err < 0) { + FAIL("Failed to set channel allocation: %d\n", err); + return err; + } } } @@ -757,9 +765,17 @@ static int gmap_ac_cap_unicast_start(const struct gmap_unicast_ac_param *param, src_stream_cnt++; stream_cnt++; - if (param->conn_cnt > 1) { - bt_audio_codec_cfg_set_chan_allocation( + /* If we have more than 1 connection or stream in one direction, we set the + * location bit accordingly + */ + if (param->conn_cnt > 1U || param->src_cnt[i] > 1U) { + const int err = bt_audio_codec_cfg_set_chan_allocation( stream_param->codec_cfg, (enum bt_audio_location)BIT(i)); + + if (err < 0) { + FAIL("Failed to set channel allocation: %d\n", err); + return err; + } } } } From 64adf0b06565b7d9b054de52c2b660a3e7dfcfed Mon Sep 17 00:00:00 2001 From: Emil Gydesen Date: Wed, 3 Jan 2024 11:55:18 +0100 Subject: [PATCH 2297/3723] Bluetooth: BAP: Add log of err in bt_bap_stream_detach We can't really do anything about it if it fails, so we simply log the value. Signed-off-by: Emil Gydesen --- subsys/bluetooth/audio/bap_stream.c | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/subsys/bluetooth/audio/bap_stream.c b/subsys/bluetooth/audio/bap_stream.c index ec614ce7243..ab27b32d237 100644 --- a/subsys/bluetooth/audio/bap_stream.c +++ b/subsys/bluetooth/audio/bap_stream.c @@ -406,7 +406,11 @@ void bt_bap_stream_detach(struct bt_bap_stream *stream) stream->ep = NULL; if (!is_broadcast) { - bt_bap_stream_disconnect(stream); + const int err = bt_bap_stream_disconnect(stream); + + if (err != 0) { + LOG_DBG("Failed to disconnect stream %p: %d", stream, err); + } } } From 9fc630d303d54b02e90b1769faaee96aa6a27bcf Mon Sep 17 00:00:00 2001 From: Emil Gydesen Date: Wed, 3 Jan 2024 11:51:31 +0100 Subject: [PATCH 2298/3723] Bluetooth: CSIP: Use bt_crypto_aes_cmac instead of own Instead of reimplementing the aes_cmac function, CSIP will now use the bt_crypto_aes_cmac function. Signed-off-by: Emil Gydesen --- subsys/bluetooth/audio/csip_crypto.c | 36 ++++------------------------ 1 file changed, 5 insertions(+), 31 deletions(-) diff --git a/subsys/bluetooth/audio/csip_crypto.c b/subsys/bluetooth/audio/csip_crypto.c index d880ca36ce1..3240e6d053e 100644 --- a/subsys/bluetooth/audio/csip_crypto.c +++ b/subsys/bluetooth/audio/csip_crypto.c @@ -11,14 +11,11 @@ */ #include "csip_crypto.h" #include -#include -#include -#include -#include -#include #include #include +#include "crypto/bt_crypto.h" + #include "common/bt_str.h" #include @@ -29,29 +26,6 @@ LOG_MODULE_REGISTER(bt_csip_crypto, CONFIG_BT_CSIP_SET_MEMBER_CRYPTO_LOG_LEVEL); #define BT_CSIP_PADDED_RAND_SIZE (BT_CSIP_CRYPTO_PADDING_SIZE + BT_CSIP_CRYPTO_PRAND_SIZE) #define BT_CSIP_R_MASK BIT_MASK(24) /* r is 24 bit / 3 octet */ -static int aes_cmac(const uint8_t key[BT_CSIP_CRYPTO_KEY_SIZE], - const uint8_t *in, size_t in_len, uint8_t *out) -{ - struct tc_aes_key_sched_struct sched; - struct tc_cmac_struct state; - - /* TODO: Copy of the aes_cmac from smp.c: Can we merge them? */ - - if (tc_cmac_setup(&state, key, &sched) == TC_CRYPTO_FAIL) { - return -EIO; - } - - if (tc_cmac_update(&state, in, in_len) == TC_CRYPTO_FAIL) { - return -EIO; - } - - if (tc_cmac_final(out, &state) == TC_CRYPTO_FAIL) { - return -EIO; - } - - return 0; -} - int bt_csip_sih(const uint8_t sirk[BT_CSIP_SET_SIRK_SIZE], uint8_t r[BT_CSIP_CRYPTO_PRAND_SIZE], uint8_t out[BT_CSIP_CRYPTO_HASH_SIZE]) { @@ -130,7 +104,7 @@ static int k1(const uint8_t *n, size_t n_size, LOG_DBG("BE: salt %s", bt_hex(salt, BT_CSIP_CRYPTO_SALT_SIZE)); LOG_DBG("BE: p %s", bt_hex(p, p_size)); - err = aes_cmac(salt, n, n_size, t); + err = bt_crypto_aes_cmac(salt, n, n_size, t); LOG_DBG("BE: t %s", bt_hex(t, sizeof(t))); @@ -138,7 +112,7 @@ static int k1(const uint8_t *n, size_t n_size, return err; } - err = aes_cmac(t, p, p_size, out); + err = bt_crypto_aes_cmac(t, p, p_size, out); LOG_DBG("BE: out %s", bt_hex(out, 16)); @@ -167,7 +141,7 @@ static int s1(const uint8_t *m, size_t m_size, memset(zero, 0, sizeof(zero)); - err = aes_cmac(zero, m, m_size, out); + err = bt_crypto_aes_cmac(zero, m, m_size, out); LOG_DBG("BE: out %s", bt_hex(out, 16)); From bf37784dea5e07ea3fcd31c201fbca357387d700 Mon Sep 17 00:00:00 2001 From: Emil Gydesen Date: Wed, 3 Jan 2024 11:33:08 +0100 Subject: [PATCH 2299/3723] Bluetooth: PACS: Fix logical dead paths In pac_notify and pac_notify_loc coverity found logical dead paths since if both sink and source notify was disabled, the functions would still be compiled, but would never get past the default case. This is not a real issue as the functions were never called in that case, but to make coverity happy, and to prevent any future issues where the functions may be called incorrectly, the static functions are now fully guarded. Signed-off-by: Emil Gydesen --- subsys/bluetooth/audio/pacs.c | 37 +++++++++++++++++++---------------- 1 file changed, 20 insertions(+), 17 deletions(-) diff --git a/subsys/bluetooth/audio/pacs.c b/subsys/bluetooth/audio/pacs.c index 1dfd7aa4710..e6cb7ae71bc 100644 --- a/subsys/bluetooth/audio/pacs.c +++ b/subsys/bluetooth/audio/pacs.c @@ -86,9 +86,6 @@ static atomic_t notify_rdy; static K_SEM_DEFINE(read_buf_sem, 1, 1); NET_BUF_SIMPLE_DEFINE_STATIC(read_buf, BT_ATT_MAX_ATTRIBUTE_LEN); -#if defined(CONFIG_BT_PAC_SNK_LOC_NOTIFIABLE) || defined(CONFIG_BT_PAC_SRC_LOC_NOTIFIABLE) -static int pac_notify_loc(struct bt_conn *conn, enum bt_audio_dir dir); -#endif /* CONFIG_BT_PAC_SNK_LOC_NOTIFIABLE || CONFIG_BT_PAC_SRC_LOC_NOTIFIABLE*/ static int pacs_gatt_notify(struct bt_conn *conn, const struct bt_uuid *uuid, const struct bt_gatt_attr *attr, @@ -634,6 +631,7 @@ BT_GATT_SERVICE_DEFINE(pacs_svc, BT_PAC_SUPPORTED_CONTEXT(supported_context_read) ); +#if defined(CONFIG_BT_PAC_SNK_LOC_NOTIFIABLE) || defined(CONFIG_BT_PAC_SRC_LOC_NOTIFIABLE) static int pac_notify_loc(struct bt_conn *conn, enum bt_audio_dir dir) { uint32_t location_le; @@ -641,21 +639,17 @@ static int pac_notify_loc(struct bt_conn *conn, enum bt_audio_dir dir) const struct bt_uuid *uuid; switch (dir) { - case BT_AUDIO_DIR_SINK: #if defined(CONFIG_BT_PAC_SNK_LOC_NOTIFIABLE) + case BT_AUDIO_DIR_SINK: location_le = sys_cpu_to_le32(pacs_snk_location); uuid = pacs_snk_loc_uuid; break; -#else - return -ENOTSUP; #endif /* CONFIG_BT_PAC_SNK_LOC_NOTIFIABLE */ - case BT_AUDIO_DIR_SOURCE: #if defined(CONFIG_BT_PAC_SRC_LOC_NOTIFIABLE) + case BT_AUDIO_DIR_SOURCE: location_le = sys_cpu_to_le32(pacs_src_location); uuid = pacs_src_loc_uuid; break; -#else - return -ENOTSUP; #endif /* CONFIG_BT_PAC_SRC_LOC_NOTIFIABLE */ default: return -EINVAL; @@ -669,7 +663,9 @@ static int pac_notify_loc(struct bt_conn *conn, enum bt_audio_dir dir) return 0; } +#endif /* CONFIG_BT_PAC_SNK_LOC_NOTIFIABLE || CONFIG_BT_PAC_SRC_LOC_NOTIFIABLE */ +#if defined(CONFIG_BT_PAC_SNK_NOTIFIABLE) || defined(CONFIG_BT_PAC_SRC_NOTIFIABLE) static int pac_notify(struct bt_conn *conn, enum bt_audio_dir dir) { int err = 0; @@ -716,6 +712,7 @@ static int pac_notify(struct bt_conn *conn, enum bt_audio_dir dir) return 0; } } +#endif /* CONFIG_BT_PAC_SNK_NOTIFIABLE || CONFIG_BT_PAC_SRC_NOTIFIABLE */ static int available_contexts_notify(struct bt_conn *conn) { @@ -822,39 +819,45 @@ static void notify_cb(struct bt_conn *conn, void *data) return; } - if (IS_ENABLED(CONFIG_BT_PAC_SNK_NOTIFIABLE) && - atomic_test_bit(client->flags, FLAG_SINK_PAC_CHANGED)) { +#if defined(CONFIG_BT_PAC_SNK_NOTIFIABLE) + if (atomic_test_bit(client->flags, FLAG_SINK_PAC_CHANGED)) { LOG_DBG("Notifying Sink PAC"); err = pac_notify(conn, BT_AUDIO_DIR_SINK); if (!err) { atomic_clear_bit(client->flags, FLAG_SINK_PAC_CHANGED); } } +#endif /* CONFIG_BT_PAC_SNK_NOTIFIABLE */ - if (IS_ENABLED(CONFIG_BT_PAC_SNK_LOC_NOTIFIABLE) && - atomic_test_bit(client->flags, FLAG_SINK_AUDIO_LOCATIONS_CHANGED)) { +#if defined(CONFIG_BT_PAC_SNK_LOC_NOTIFIABLE) + if (atomic_test_bit(client->flags, FLAG_SINK_AUDIO_LOCATIONS_CHANGED)) { LOG_DBG("Notifying Sink Audio Location"); err = pac_notify_loc(conn, BT_AUDIO_DIR_SINK); if (!err) { atomic_clear_bit(client->flags, FLAG_SINK_AUDIO_LOCATIONS_CHANGED); } } - if (IS_ENABLED(CONFIG_BT_PAC_SRC_NOTIFIABLE) && - atomic_test_bit(client->flags, FLAG_SOURCE_PAC_CHANGED)) { +#endif /* CONFIG_BT_PAC_SNK_LOC_NOTIFIABLE */ + +#if defined(CONFIG_BT_PAC_SRC_NOTIFIABLE) + if (atomic_test_bit(client->flags, FLAG_SOURCE_PAC_CHANGED)) { LOG_DBG("Notifying Source PAC"); err = pac_notify(conn, BT_AUDIO_DIR_SOURCE); if (!err) { atomic_clear_bit(client->flags, FLAG_SOURCE_PAC_CHANGED); } } - if (IS_ENABLED(CONFIG_BT_PAC_SRC_LOC_NOTIFIABLE) && - atomic_test_and_clear_bit(client->flags, FLAG_SOURCE_AUDIO_LOCATIONS_CHANGED)) { +#endif /* CONFIG_BT_PAC_SRC_NOTIFIABLE */ + +#if defined(CONFIG_BT_PAC_SRC_LOC_NOTIFIABLE) + if (atomic_test_and_clear_bit(client->flags, FLAG_SOURCE_AUDIO_LOCATIONS_CHANGED)) { LOG_DBG("Notifying Source Audio Location"); err = pac_notify_loc(conn, BT_AUDIO_DIR_SOURCE); if (!err) { atomic_clear_bit(client->flags, FLAG_SOURCE_AUDIO_LOCATIONS_CHANGED); } } +#endif /* CONFIG_BT_PAC_SRC_LOC_NOTIFIABLE */ if (atomic_test_bit(client->flags, FLAG_AVAILABLE_AUDIO_CONTEXT_CHANGED)) { LOG_DBG("Notifying Available Contexts"); From f4cbf403e8238109fd5b00add8e5dee4114aeb61 Mon Sep 17 00:00:00 2001 From: Emil Gydesen Date: Wed, 3 Jan 2024 09:58:07 +0100 Subject: [PATCH 2300/3723] Bluetooth: BAP: Fix uninitialized variable in source_reconfig The stream_in_subgroup variable in bt_bap_broadcast_source_reconfig may have been uninitialized. Signed-off-by: Emil Gydesen --- subsys/bluetooth/audio/bap_broadcast_source.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/subsys/bluetooth/audio/bap_broadcast_source.c b/subsys/bluetooth/audio/bap_broadcast_source.c index 26b79b04666..1cd83155994 100644 --- a/subsys/bluetooth/audio/bap_broadcast_source.c +++ b/subsys/bluetooth/audio/bap_broadcast_source.c @@ -788,7 +788,7 @@ int bt_bap_broadcast_source_reconfig(struct bt_bap_broadcast_source *source, for (size_t i = 0U; i < subgroup_param->params_count; i++) { struct bt_bap_stream *subgroup_stream; struct bt_bap_stream *param_stream; - bool stream_in_subgroup; + bool stream_in_subgroup = false; param_stream = subgroup_param->params[i].stream; From a5b868d94ae3ad7ccc0b7b21a2d018442e0364f5 Mon Sep 17 00:00:00 2001 From: Konrad Derda Date: Thu, 21 Dec 2023 15:48:24 +0100 Subject: [PATCH 2301/3723] net: buf: add function to match buffer's content with a given data This commit adds a new function the net_buf's API that allow an user to match the net_buf's content with a data without copying it to a temporary buffer. Signed-off-by: Konrad Derda --- include/zephyr/net/buf.h | 16 ++++++++++++++++ subsys/net/buf.c | 36 ++++++++++++++++++++++++++++++++++++ 2 files changed, 52 insertions(+) diff --git a/include/zephyr/net/buf.h b/include/zephyr/net/buf.h index 94b0b9a7533..6e7f8b5b2a8 100644 --- a/include/zephyr/net/buf.h +++ b/include/zephyr/net/buf.h @@ -2414,6 +2414,22 @@ size_t net_buf_append_bytes(struct net_buf *buf, size_t len, const void *value, k_timeout_t timeout, net_buf_allocator_cb allocate_cb, void *user_data); +/** + * @brief Match data with a net_buf's content + * + * @details Compare data with a content of a net_buf. Provide information about + * the number of bytes matching between both. If needed, traverse + * through multiple buffer fragments. + * + * @param buf Network buffer + * @param offset Starting offset to compare from + * @param data Data buffer for comparison + * @param len Number of bytes to compare + * + * @return The number of bytes compared before the first difference. + */ +size_t net_buf_data_match(const struct net_buf *buf, size_t offset, const void *data, size_t len); + /** * @brief Skip N number of bytes in a net_buf * diff --git a/subsys/net/buf.c b/subsys/net/buf.c index 4862a65f226..0ea9c0d387c 100644 --- a/subsys/net/buf.c +++ b/subsys/net/buf.c @@ -694,3 +694,39 @@ size_t net_buf_append_bytes(struct net_buf *buf, size_t len, /* Unreachable */ return 0; } + +size_t net_buf_data_match(const struct net_buf *buf, size_t offset, const void *data, size_t len) +{ + const uint8_t *dptr = data; + const uint8_t *bptr; + size_t compared = 0; + size_t to_compare; + + if (!buf || !data) { + return compared; + } + + /* find the right fragment to start comparison */ + while (buf && offset >= buf->len) { + offset -= buf->len; + buf = buf->frags; + } + + while (buf && len > 0) { + bptr = buf->data + offset; + to_compare = MIN(len, buf->len - offset); + + for (size_t i = 0; i < to_compare; ++i) { + if (dptr[compared] != bptr[i]) { + return compared; + } + compared++; + } + + len -= to_compare; + buf = buf->frags; + offset = 0; + } + + return compared; +} From 982fc416f8df34977a720a372564b3b673e1fd1e Mon Sep 17 00:00:00 2001 From: Konrad Derda Date: Thu, 21 Dec 2023 15:52:03 +0100 Subject: [PATCH 2302/3723] tests: net: buf: add tests for data matching Add new test case for veryfing matching between net_bufs' contents and a given data buffer. Signed-off-by: Konrad Derda --- tests/net/buf/src/main.c | 75 +++++++++++++++++++++++++++++++++++++++- 1 file changed, 74 insertions(+), 1 deletion(-) diff --git a/tests/net/buf/src/main.c b/tests/net/buf/src/main.c index a96c6fe83e2..c5975804fbf 100644 --- a/tests/net/buf/src/main.c +++ b/tests/net/buf/src/main.c @@ -20,6 +20,7 @@ #define USER_DATA_HEAP 4 #define USER_DATA_FIXED 0 #define USER_DATA_VAR 63 +#define FIXED_BUFFER_SIZE 128 struct bt_data { void *hci_sync; @@ -68,7 +69,7 @@ static void fixed_destroy(struct net_buf *buf); static void var_destroy(struct net_buf *buf); NET_BUF_POOL_HEAP_DEFINE(bufs_pool, 10, USER_DATA_HEAP, buf_destroy); -NET_BUF_POOL_FIXED_DEFINE(fixed_pool, 10, 128, USER_DATA_FIXED, fixed_destroy); +NET_BUF_POOL_FIXED_DEFINE(fixed_pool, 10, FIXED_BUFFER_SIZE, USER_DATA_FIXED, fixed_destroy); NET_BUF_POOL_VAR_DEFINE(var_pool, 10, 1024, USER_DATA_VAR, var_destroy); static void buf_destroy(struct net_buf *buf) @@ -724,4 +725,76 @@ ZTEST(net_buf_tests, test_net_buf_user_data) net_buf_unref(buf); } +ZTEST(net_buf_tests, test_net_buf_comparison) +{ + struct net_buf *buf; + size_t written; + size_t offset; + size_t to_compare; + size_t res; + uint8_t data[FIXED_BUFFER_SIZE * 2]; + + /* Fill data buffer */ + for (int i = 0; i < sizeof(data); ++i) { + data[i] = (uint8_t)i; + } + + /* Allocate a single net_buf */ + buf = net_buf_alloc(&fixed_pool, K_NO_WAIT); + zassert_not_null(buf, "Failed to get buffer"); + + written = net_buf_append_bytes(buf, buf->size, data, K_NO_WAIT, NULL, NULL); + zassert_equal(written, buf->size, "Failed to fill the buffer"); + zassert_equal(buf->frags, NULL, "Additional buffer allocated"); + + /* Compare the whole buffer */ + res = net_buf_data_match(buf, 0, data, buf->size); + zassert_equal(res, buf->size, "Whole net_buf comparison failed"); + + /* Compare from the offset */ + offset = buf->size / 2; + to_compare = written - offset; + + res = net_buf_data_match(buf, offset, &data[offset], to_compare); + zassert_equal(res, to_compare, "Comparison with offset failed"); + + /* Write more data (it allocates more buffers) */ + written = net_buf_append_bytes(buf, sizeof(data) - written, &data[buf->size], K_NO_WAIT, + NULL, NULL); + zassert_true(buf->frags, "Failed to allocate an additional net_buf"); + + /* Compare whole data with buffers' content */ + res = net_buf_data_match(buf, 0, data, sizeof(data)); + zassert_equal(res, sizeof(data), "Failed to compare data with multiple buffers"); + + /* Compare data with offset at the edge between two fragments */ + offset = buf->size - (buf->size / 2); + res = net_buf_data_match(buf, offset, &data[offset], buf->size); + zassert_equal(res, buf->size, "Failed to compare bytes within two buffers with offset"); + + /* Compare data with partial matching - change the data in the middle */ + data[sizeof(data) / 2] += 1; + res = net_buf_data_match(buf, 0, data, sizeof(data)); + zassert_equal(res, sizeof(data) / 2, "Partial matching failed"); + + /* No buffer - expect 0 matching bytes */ + res = net_buf_data_match(NULL, 0, data, sizeof(data)); + zassert_equal(res, 0, "Matching without a buffer must fail"); + + /* No data - expect 0 matching bytes */ + res = net_buf_data_match(buf, 0, NULL, sizeof(data)); + zassert_equal(res, 0, "Matching without data must fail"); + + /* Too high offset - expect 0 matching bytes */ + res = net_buf_data_match(buf, FIXED_BUFFER_SIZE * 2, data, sizeof(data)); + zassert_equal(res, 0, "Matching with too high offset must fail"); + + /* Try to match more bytes than are in buffers - expect only partial match */ + offset = (FIXED_BUFFER_SIZE * 2) - 8; + res = net_buf_data_match(buf, offset, &data[offset], 16); + zassert_equal(res, 8, "Reaching out of bounds must return a partial match"); + + net_buf_unref(buf); +} + ZTEST_SUITE(net_buf_tests, NULL, NULL, NULL, NULL, NULL); From 49e8e11a77bda474da7b4f2e64169f2f04bef3b3 Mon Sep 17 00:00:00 2001 From: Fabio Baltieri Date: Tue, 16 Jan 2024 11:52:11 +0000 Subject: [PATCH 2303/3723] scripts: set_maintainer: fix author == maintainer fallback logic The "Submitter is same as Assignee" is comparing strings to and always failing the condition, fix it by dropping the ".name". Tested with ./scripts/set_assignees.py -v -y -P 67526 (now falls back to the other maintainer as it should). Signed-off-by: Fabio Baltieri --- scripts/set_assignees.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/scripts/set_assignees.py b/scripts/set_assignees.py index ced5900fad6..17199ec52e6 100755 --- a/scripts/set_assignees.py +++ b/scripts/set_assignees.py @@ -146,7 +146,7 @@ def process_pr(gh, maintainer_file, number): log("Submitter is same as Assignee, trying to find another assignee...") aff = list(area_counter.keys())[0] for area in all_areas: - if area.name == aff: + if area == aff: if len(area.maintainers) > 1: assignee = area.maintainers[1] else: From dc9d5d932120f22175857a80421c1c2df572af33 Mon Sep 17 00:00:00 2001 From: Chaitanya Tata Date: Tue, 16 Jan 2024 18:36:19 +0530 Subject: [PATCH 2304/3723] wifi: shell: Fix typo in comparison The length should be 3 for WMM not 4. Signed-off-by: Chaitanya Tata --- subsys/net/l2/wifi/wifi_shell.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/subsys/net/l2/wifi/wifi_shell.c b/subsys/net/l2/wifi/wifi_shell.c index 4c61ad4e4ae..ebb47dd76cd 100644 --- a/subsys/net/l2/wifi/wifi_shell.c +++ b/subsys/net/l2/wifi/wifi_shell.c @@ -928,7 +928,7 @@ static int cmd_wifi_ps_mode(const struct shell *sh, size_t argc, char *argv[]) if (!strncasecmp(argv[1], "legacy", 6)) { params.mode = WIFI_PS_MODE_LEGACY; - } else if (!strncasecmp(argv[1], "WMM", 4)) { + } else if (!strncasecmp(argv[1], "WMM", 3)) { params.mode = WIFI_PS_MODE_WMM; } else { shell_fprintf(sh, SHELL_WARNING, "Invalid PS mode\n"); From 06fa287d459be699fe34061e3fb3bed2dbf8c733 Mon Sep 17 00:00:00 2001 From: Bi Jian Date: Fri, 29 Sep 2023 11:11:34 +0800 Subject: [PATCH 2305/3723] Bluetooth: Audio: Update audio location definitions The meaning of bit0 in the audio location bitmap will change to mono audio, so we update the audio location macro and releated test cases. Refer to BT SIG ES-22266. Signed-off-by: Bi Jian --- include/zephyr/bluetooth/audio/audio.h | 2 +- subsys/bluetooth/audio/pacs.c | 4 +- subsys/bluetooth/audio/shell/bap.c | 58 +++++++++---------- subsys/bluetooth/audio/vocs.c | 3 +- subsys/bluetooth/audio/vocs_client.c | 2 +- .../bluetooth/audio/src/vcp_vol_ctlr_test.c | 8 --- .../bluetooth/audio/src/vcp_vol_rend_test.c | 8 --- 7 files changed, 32 insertions(+), 53 deletions(-) diff --git a/include/zephyr/bluetooth/audio/audio.h b/include/zephyr/bluetooth/audio/audio.h index 17bac991f18..bb9c8d7eade 100644 --- a/include/zephyr/bluetooth/audio/audio.h +++ b/include/zephyr/bluetooth/audio/audio.h @@ -245,7 +245,7 @@ enum bt_audio_metadata_type { * These values are defined by the Generic Audio Assigned Numbers, bluetooth.com */ enum bt_audio_location { - BT_AUDIO_LOCATION_PROHIBITED = 0, + BT_AUDIO_LOCATION_MONO_AUDIO = 0, BT_AUDIO_LOCATION_FRONT_LEFT = BIT(0), BT_AUDIO_LOCATION_FRONT_RIGHT = BIT(1), BT_AUDIO_LOCATION_FRONT_CENTER = BIT(2), diff --git a/subsys/bluetooth/audio/pacs.c b/subsys/bluetooth/audio/pacs.c index e6cb7ae71bc..6f32774d9f9 100644 --- a/subsys/bluetooth/audio/pacs.c +++ b/subsys/bluetooth/audio/pacs.c @@ -405,7 +405,7 @@ static ssize_t snk_loc_write(struct bt_conn *conn, } location = (enum bt_audio_location)sys_get_le32(data); - if (location > BT_AUDIO_LOCATION_MASK || location == 0) { + if (location > BT_AUDIO_LOCATION_MASK) { LOG_DBG("Invalid location value: 0x%08X", location); return BT_GATT_ERR(BT_ATT_ERR_WRITE_REQ_REJECTED); } @@ -510,7 +510,7 @@ static ssize_t src_loc_write(struct bt_conn *conn, } location = (enum bt_audio_location)sys_get_le32(data); - if (location > BT_AUDIO_LOCATION_MASK || location == 0) { + if (location > BT_AUDIO_LOCATION_MASK) { LOG_DBG("Invalid location value: 0x%08X", location); return BT_GATT_ERR(BT_ATT_ERR_WRITE_REQ_REJECTED); } diff --git a/subsys/bluetooth/audio/shell/bap.c b/subsys/bluetooth/audio/shell/bap.c index 7ad179969cf..2fd5cdce0fb 100644 --- a/subsys/bluetooth/audio/shell/bap.c +++ b/subsys/bluetooth/audio/shell/bap.c @@ -993,7 +993,7 @@ static int cmd_discover(const struct shell *sh, size_t argc, char *argv[]) static int cmd_config(const struct shell *sh, size_t argc, char *argv[]) { - enum bt_audio_location location = BT_AUDIO_LOCATION_PROHIBITED; + enum bt_audio_location location = BT_AUDIO_LOCATION_MONO_AUDIO; const struct named_lc3_preset *named_preset; struct shell_stream *uni_stream; struct bt_bap_stream *bap_stream; @@ -1076,8 +1076,7 @@ static int cmd_config(const struct shell *sh, size_t argc, char *argv[]) return -ENOEXEC; } - if (loc_bits == BT_AUDIO_LOCATION_PROHIBITED || - loc_bits > BT_AUDIO_LOCATION_ANY) { + if (loc_bits > BT_AUDIO_LOCATION_ANY) { shell_error(sh, "Invalid loc_bits: %lu", loc_bits); return -ENOEXEC; @@ -1109,39 +1108,37 @@ static int cmd_config(const struct shell *sh, size_t argc, char *argv[]) copy_unicast_stream_preset(uni_stream, named_preset); /* If location has been modifed, we update the location in the codec configuration */ - if (location != BT_AUDIO_LOCATION_PROHIBITED) { - struct bt_audio_codec_cfg *codec_cfg = &uni_stream->codec_cfg; - - for (size_t i = 0U; i < codec_cfg->data_len;) { - const uint8_t len = codec_cfg->data[i++]; - uint8_t *value; - uint8_t data_len; - uint8_t type; - - if (len == 0 || len > codec_cfg->data_len - i) { - /* Invalid len field */ - return false; - } + struct bt_audio_codec_cfg *codec_cfg = &uni_stream->codec_cfg; - type = codec_cfg->data[i++]; - value = &codec_cfg->data[i]; + for (size_t i = 0U; i < codec_cfg->data_len;) { + const uint8_t len = codec_cfg->data[i++]; + uint8_t *value; + uint8_t data_len; + uint8_t type; - if (type == BT_AUDIO_CODEC_CONFIG_LC3_CHAN_ALLOC) { - const uint32_t loc_32 = location; + if (len == 0 || len > codec_cfg->data_len - i) { + /* Invalid len field */ + return false; + } - sys_put_le32(loc_32, value); + type = codec_cfg->data[i++]; + value = &codec_cfg->data[i]; - shell_print(sh, "Setting location to 0x%08X", location); - break; - } + if (type == BT_AUDIO_CODEC_CONFIG_LC3_CHAN_ALLOC) { + const uint32_t loc_32 = location; - data_len = len - sizeof(type); + sys_put_le32(loc_32, value); - /* Since we are incrementing i by the value_len, we don't need to increment - * it further in the `for` statement - */ - i += data_len; + shell_print(sh, "Setting location to 0x%08X", location); + break; } + + data_len = len - sizeof(type); + + /* Since we are incrementing i by the value_len, we don't need to increment + * it further in the `for` statement + */ + i += data_len; } if (bap_stream->ep == ep) { @@ -2347,8 +2344,7 @@ static int cmd_set_loc(const struct shell *sh, size_t argc, char *argv[]) return -ENOEXEC; } - if (loc_val == BT_AUDIO_LOCATION_PROHIBITED || - loc_val > BT_AUDIO_LOCATION_ANY) { + if (loc_val > BT_AUDIO_LOCATION_ANY) { shell_error(sh, "Invalid location: %lu", loc_val); return -ENOEXEC; diff --git a/subsys/bluetooth/audio/vocs.c b/subsys/bluetooth/audio/vocs.c index 6a03ceb3b70..fe958d5fe33 100644 --- a/subsys/bluetooth/audio/vocs.c +++ b/subsys/bluetooth/audio/vocs.c @@ -134,8 +134,7 @@ static ssize_t write_location(struct bt_conn *conn, const struct bt_gatt_attr *a } new_location = sys_get_le32(buf); - if (new_location == BT_AUDIO_LOCATION_PROHIBITED || - (new_location & BT_AUDIO_LOCATION_RFU) > 0) { + if ((new_location & BT_AUDIO_LOCATION_RFU) > 0) { LOG_DBG("Invalid location %u", new_location); return BT_GATT_ERR(BT_ATT_ERR_VALUE_NOT_ALLOWED); diff --git a/subsys/bluetooth/audio/vocs_client.c b/subsys/bluetooth/audio/vocs_client.c index 2d919baa050..4f88d647ad8 100644 --- a/subsys/bluetooth/audio/vocs_client.c +++ b/subsys/bluetooth/audio/vocs_client.c @@ -470,7 +470,7 @@ int bt_vocs_client_location_set(struct bt_vocs_client *inst, uint32_t location) return -EINVAL; } - CHECKIF(location == BT_AUDIO_LOCATION_PROHIBITED || location > BT_AUDIO_LOCATION_ANY) { + CHECKIF(location > BT_AUDIO_LOCATION_ANY) { LOG_DBG("Invalid location 0x%08X", location); return -EINVAL; } diff --git a/tests/bsim/bluetooth/audio/src/vcp_vol_ctlr_test.c b/tests/bsim/bluetooth/audio/src/vcp_vol_ctlr_test.c index 77feaa4bfb5..8be4a3e34c5 100644 --- a/tests/bsim/bluetooth/audio/src/vcp_vol_ctlr_test.c +++ b/tests/bsim/bluetooth/audio/src/vcp_vol_ctlr_test.c @@ -659,14 +659,6 @@ static void test_vocs_location_set(void) return; } - invalid_location = BT_AUDIO_LOCATION_PROHIBITED; - - err = bt_vocs_location_set(vcp_included.vocs[0], invalid_location); - if (err == 0) { - FAIL("bt_vocs_location_set with location 0x%08X did not fail", invalid_location); - return; - } - invalid_location = BT_AUDIO_LOCATION_ANY + 1; err = bt_vocs_location_set(vcp_included.vocs[0], invalid_location); diff --git a/tests/bsim/bluetooth/audio/src/vcp_vol_rend_test.c b/tests/bsim/bluetooth/audio/src/vcp_vol_rend_test.c index e2790931676..d4918ab0553 100644 --- a/tests/bsim/bluetooth/audio/src/vcp_vol_rend_test.c +++ b/tests/bsim/bluetooth/audio/src/vcp_vol_rend_test.c @@ -621,14 +621,6 @@ static void test_vocs_location_set(void) return; } - invalid_location = BT_AUDIO_LOCATION_PROHIBITED; - - err = bt_vocs_location_set(vcp_included.vocs[0], invalid_location); - if (err == 0) { - FAIL("bt_vocs_location_set with location 0x%08X did not fail", invalid_location); - return; - } - invalid_location = BT_AUDIO_LOCATION_ANY + 1; err = bt_vocs_location_set(vcp_included.vocs[0], invalid_location); From 685c88308d780835b4a47c6b354eaeb6d23b6869 Mon Sep 17 00:00:00 2001 From: Alberto Escolar Piedras Date: Fri, 12 Jan 2024 15:06:51 +0100 Subject: [PATCH 2306/3723] tests/drivers uart_mix_fifo_poll: Speed up for nrf52_bsim Increase the UART speed to 1Mbps for the simulated nrf52 to reduce the amount of time spent busy waiting, and therefore the real time duration of the test. Signed-off-by: Alberto Escolar Piedras --- .../uart/uart_mix_fifo_poll/boards/nrf52_bsim.overlay | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/tests/drivers/uart/uart_mix_fifo_poll/boards/nrf52_bsim.overlay b/tests/drivers/uart/uart_mix_fifo_poll/boards/nrf52_bsim.overlay index c7277e73775..7799b63b73d 100644 --- a/tests/drivers/uart/uart_mix_fifo_poll/boards/nrf52_bsim.overlay +++ b/tests/drivers/uart/uart_mix_fifo_poll/boards/nrf52_bsim.overlay @@ -1,3 +1,8 @@ /* SPDX-License-Identifier: Apache-2.0 */ #include "nrf52840dk_nrf52840.overlay" + + +dut: &uart0 { + current-speed = <1000000>; +}; From a6ea4490a9cc438086ad124bcf72e491bf5aa093 Mon Sep 17 00:00:00 2001 From: Alberto Escolar Piedras Date: Fri, 12 Jan 2024 15:08:20 +0100 Subject: [PATCH 2307/3723] drivers serial nrfx: Speed up for simulation MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Increase the busy wait time granularity while runing in simulation for poll mode. In this mode, the driver spends a *lot* of time waiting for the UART to be done. The smallest frame time is ~10µs @ 1Mbps, so busywaiting in very small increments is very wastefull as we keep shuting down and turning on the simulated MCU. Let's increase the busy wait time increments of the driver to 3 micros, which should not change much the behaviour. Signed-off-by: Alberto Escolar Piedras --- drivers/serial/uart_nrfx_uarte.c | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/drivers/serial/uart_nrfx_uarte.c b/drivers/serial/uart_nrfx_uarte.c index 23219f16036..099a4f55937 100644 --- a/drivers/serial/uart_nrfx_uarte.c +++ b/drivers/serial/uart_nrfx_uarte.c @@ -484,7 +484,11 @@ static int wait_tx_ready(const struct device *dev) /* wait arbitrary time before back off. */ bool res; +#if defined(CONFIG_ARCH_POSIX) + NRFX_WAIT_FOR(is_tx_ready(dev), 33, 3, res); +#else NRFX_WAIT_FOR(is_tx_ready(dev), 100, 1, res); +#endif if (res) { key = irq_lock(); @@ -1502,7 +1506,7 @@ static void uarte_nrfx_poll_out(const struct device *dev, unsigned char c) } irq_unlock(key); - Z_SPIN_DELAY(2); + Z_SPIN_DELAY(3); } } else { key = wait_tx_ready(dev); From e6140f54226a545b05600fa6fa26ac7654a5f0d8 Mon Sep 17 00:00:00 2001 From: Alberto Escolar Piedras Date: Mon, 15 Jan 2024 13:58:01 +0100 Subject: [PATCH 2308/3723] tests/drivers uart_mix_fifo_poll: Allow configuring test length This test is quite heavy and long in simulation, but its length is meant to find unlikely issues which may be triggered only very rarely. Let's provide a kconfig value to chose how long the test is, and set it to a lower value when running in simulation (in CI) to save time. Signed-off-by: Alberto Escolar Piedras --- tests/drivers/uart/uart_mix_fifo_poll/Kconfig | 15 +++++++++++++++ tests/drivers/uart/uart_mix_fifo_poll/src/main.c | 3 ++- 2 files changed, 17 insertions(+), 1 deletion(-) create mode 100644 tests/drivers/uart/uart_mix_fifo_poll/Kconfig diff --git a/tests/drivers/uart/uart_mix_fifo_poll/Kconfig b/tests/drivers/uart/uart_mix_fifo_poll/Kconfig new file mode 100644 index 00000000000..d5d41cd19fd --- /dev/null +++ b/tests/drivers/uart/uart_mix_fifo_poll/Kconfig @@ -0,0 +1,15 @@ +# Copyright (c) 2024 Nordic Semiconductor ASA +# SPDX-License-Identifier: Apache-2.0 + +config STRESS_TEST_REPS + int "Number of loops in the stress test" + # For the simulated devices, which are run by default in CI, we set it to less to not spend too + # much CI time + default 500 if SOC_SERIES_BSIM_NRFXX + default 10000 + help + For how many loops will the stress test run. The higher this number the longer the + test and therefore the higher likelihood an unlikely race/event will be triggered. + +# Include Zephyr's Kconfig +source "Kconfig" diff --git a/tests/drivers/uart/uart_mix_fifo_poll/src/main.c b/tests/drivers/uart/uart_mix_fifo_poll/src/main.c index a080945a067..aaf97ea8488 100644 --- a/tests/drivers/uart/uart_mix_fifo_poll/src/main.c +++ b/tests/drivers/uart/uart_mix_fifo_poll/src/main.c @@ -264,6 +264,7 @@ static void int_async_thread_func(void *p_data, void *base, void *range) int idx = data->cnt & 0xF; size_t len = (idx < BUF_SIZE / 2) ? 5 : 1; /* Try various lengths */ + len = MIN(len, data->max - data->cnt); data->cnt += len; err = uart_tx(uart_dev, &int_async_data.buf[idx], @@ -317,7 +318,7 @@ static void init_test_data(struct test_data *data, const uint8_t *buf, int repea ZTEST(uart_mix_fifo_poll, test_mixed_uart_access) { - int repeat = 10000; + int repeat = CONFIG_STRESS_TEST_REPS; int err; int num_of_contexts = ARRAY_SIZE(test_data); From 7d590a9d3d575df8134b990e254d13c692561bcb Mon Sep 17 00:00:00 2001 From: Alberto Escolar Piedras Date: Mon, 15 Jan 2024 14:07:21 +0100 Subject: [PATCH 2309/3723] boards nrf*_bsim: Add tag to filter slow tests Add a tag to filter slow bsim tests in CI (or tests which do not provide much extra coverage and are not worth running all the time in CI) Signed-off-by: Alberto Escolar Piedras --- boards/posix/nrf_bsim/nrf52_bsim.yaml | 1 + boards/posix/nrf_bsim/nrf5340bsim_nrf5340_cpuapp.yaml | 1 + boards/posix/nrf_bsim/nrf5340bsim_nrf5340_cpunet.yaml | 1 + 3 files changed, 3 insertions(+) diff --git a/boards/posix/nrf_bsim/nrf52_bsim.yaml b/boards/posix/nrf_bsim/nrf52_bsim.yaml index ce8cd935a7b..17aba03864e 100644 --- a/boards/posix/nrf_bsim/nrf52_bsim.yaml +++ b/boards/posix/nrf_bsim/nrf52_bsim.yaml @@ -10,5 +10,6 @@ toolchain: testing: ignore_tags: - modem + - bsim_skip_CI supported: - gpio diff --git a/boards/posix/nrf_bsim/nrf5340bsim_nrf5340_cpuapp.yaml b/boards/posix/nrf_bsim/nrf5340bsim_nrf5340_cpuapp.yaml index 822368df0d3..448d4f330c3 100644 --- a/boards/posix/nrf_bsim/nrf5340bsim_nrf5340_cpuapp.yaml +++ b/boards/posix/nrf_bsim/nrf5340bsim_nrf5340_cpuapp.yaml @@ -12,3 +12,4 @@ testing: - gpio - modem - uart + - bsim_skip_CI diff --git a/boards/posix/nrf_bsim/nrf5340bsim_nrf5340_cpunet.yaml b/boards/posix/nrf_bsim/nrf5340bsim_nrf5340_cpunet.yaml index 4e305c095d3..4cd71ff3566 100644 --- a/boards/posix/nrf_bsim/nrf5340bsim_nrf5340_cpunet.yaml +++ b/boards/posix/nrf_bsim/nrf5340bsim_nrf5340_cpunet.yaml @@ -12,3 +12,4 @@ testing: - gpio - modem - uart + - bsim_skip_CI From 9af74504dd376512ba772ca496a0b1ee4dc5285f Mon Sep 17 00:00:00 2001 From: Alberto Escolar Piedras Date: Mon, 15 Jan 2024 14:08:16 +0100 Subject: [PATCH 2310/3723] tests/drivers uart_mix_fifo_poll: Filter out repetitive tests Do not run in CI all tests, as they have very similar configuration and provide little extra coverage to justify the extra CI time. Signed-off-by: Alberto Escolar Piedras --- tests/drivers/uart/uart_mix_fifo_poll/testcase.yaml | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/tests/drivers/uart/uart_mix_fifo_poll/testcase.yaml b/tests/drivers/uart/uart_mix_fifo_poll/testcase.yaml index cd754d607c8..1d1f97fbcc7 100644 --- a/tests/drivers/uart/uart_mix_fifo_poll/testcase.yaml +++ b/tests/drivers/uart/uart_mix_fifo_poll/testcase.yaml @@ -47,6 +47,7 @@ tests: - CONFIG_NRFX_TIMER2=y - CONFIG_UART_0_ENHANCED_POLL_OUT=n - CONFIG_UART_ASYNC_TX_CACHE_SIZE=2 + tags: bsim_skip_CI # We skip a few tests to save CI time, as they give little extra coverage drivers.uart.uart_mix_poll_async_api_low_power: extra_configs: @@ -58,18 +59,21 @@ tests: - CONFIG_UART_0_NRF_HW_ASYNC_TIMER=2 - CONFIG_NRFX_TIMER2=y - CONFIG_UART_0_ENHANCED_POLL_OUT=n + tags: bsim_skip_CI drivers.uart.uart_mix_poll_with_ppi: extra_configs: - CONFIG_UART_INTERRUPT_DRIVEN=n - CONFIG_UART_ASYNC_API=n - CONFIG_UART_0_ENHANCED_POLL_OUT=y + tags: bsim_skip_CI drivers.uart.uart_mix_poll_fifo_with_ppi: extra_configs: - CONFIG_UART_INTERRUPT_DRIVEN=y - CONFIG_UART_0_INTERRUPT_DRIVEN=y - CONFIG_UART_0_ENHANCED_POLL_OUT=y + tags: bsim_skip_CI drivers.uart.uart_mix_poll_async_api_with_ppi: extra_configs: @@ -80,6 +84,7 @@ tests: - CONFIG_UART_0_NRF_HW_ASYNC_TIMER=2 - CONFIG_NRFX_TIMER2=y - CONFIG_UART_0_ENHANCED_POLL_OUT=y + tags: bsim_skip_CI drivers.uart.uart_mix_poll_async_api_with_ppi_low_power: extra_configs: From 53c121381f1a26153002e133ab4dd656cec0e592 Mon Sep 17 00:00:00 2001 From: Alberto Escolar Piedras Date: Thu, 11 Jan 2024 11:34:40 +0100 Subject: [PATCH 2311/3723] CI bsim workflow: Add UART tests to the bsim workflow Add new workflow steps to the babblesim workflow to run also the UART tests on the nrf52_bsim. This commit: * Enables the single device tests (which we may move to the normal twister workflow once we fix the requirement for a fixture) * Adds as a placeholder the infra for multidevice tests. Signed-off-by: Alberto Escolar Piedras --- .github/workflows/bsim-tests.yaml | 28 ++++++++++++++++++++++++++++ tests/bsim/drivers/uart/compile.sh | 26 ++++++++++++++++++++++++++ 2 files changed, 54 insertions(+) create mode 100755 tests/bsim/drivers/uart/compile.sh diff --git a/.github/workflows/bsim-tests.yaml b/.github/workflows/bsim-tests.yaml index 75a65577975..c6abce73913 100644 --- a/.github/workflows/bsim-tests.yaml +++ b/.github/workflows/bsim-tests.yaml @@ -20,6 +20,8 @@ on: - "include/zephyr/net/openthread.h" - "drivers/ieee802154/**" - "include/zephyr/net/ieee802154*" + - "drivers/serial/*nrfx*" + - "tests/drivers/uart/**" concurrency: group: ${{ github.workflow }}-${{ github.event_name }}-${{ github.head_ref || github.ref }} @@ -44,6 +46,7 @@ jobs: bsim_bt_53_test_results_file: ./bsim_bt/53_bsim_results.xml bsim_bt_53split_test_results_file: ./bsim_bt/53_bsim_split_results.xml bsim_net_52_test_results_file: ./bsim_net/52_bsim_results.xml + bsim_uart_test_results_file: ./bsim_uart/uart_bsim_results.xml steps: - name: Apply container owner mismatch workaround run: | @@ -116,10 +119,20 @@ jobs: drivers/ieee802154/** include/zephyr/net/ieee802154* + - name: Check if UART files changed + uses: tj-actions/changed-files@v41 + id: check-uart-files + with: + files: | + tests/bsim/drivers/uart/** + drivers/serial/*nrfx* + tests/drivers/uart/** + - name: Update BabbleSim to manifest revision if: > steps.check-bluetooth-files.outputs.any_changed == 'true' || steps.check-networking-files.outputs.any_changed == 'true' + || steps.check-uart-files.outputs.any_changed == 'true' || steps.check-common-files.outputs.any_changed == 'true' run: | export BSIM_VERSION=$( west list bsim -f {revision} ) @@ -163,6 +176,18 @@ jobs: RESULTS_FILE=${ZEPHYR_BASE}/${bsim_net_52_test_results_file} \ SEARCH_PATH=tests/bsim/net/ tests/bsim/run_parallel.sh + - name: Run UART Tests with BSIM + if: steps.check-uart-files.outputs.any_changed == 'true' || steps.check-common-files.outputs.any_changed == 'true' + run: | + echo "UART: Single device tests" + ./scripts/twister -T tests/drivers/uart/ --force-color --inline-logs -v -M -p nrf52_bsim \ + --fixture gpio_loopback -- -uart0_loopback + echo "UART: Multi device tests" + export ZEPHYR_BASE=${PWD} + WORK_DIR=${ZEPHYR_BASE}/bsim_uart nice tests/bsim/drivers/uart/compile.sh + RESULTS_FILE=${ZEPHYR_BASE}/${bsim_uart_test_results_file} \ + SEARCH_PATH=tests/bsim/drivers/uart/ tests/bsim/run_parallel.sh + - name: Upload Test Results if: always() uses: actions/upload-artifact@v3 @@ -173,6 +198,9 @@ jobs: ./bsim_bt/53_bsim_results.xml ./bsim_bt/53_bsim_split_results.xml ./bsim_net/52_bsim_results.xml + ./bsim_uart/uart_bsim_results.xml + ./twister-out/twister.xml + ./twister-out/twister.json ${{ github.event_path }} if-no-files-found: warn diff --git a/tests/bsim/drivers/uart/compile.sh b/tests/bsim/drivers/uart/compile.sh new file mode 100755 index 00000000000..5bd35772bb5 --- /dev/null +++ b/tests/bsim/drivers/uart/compile.sh @@ -0,0 +1,26 @@ +#!/usr/bin/env bash +# Copyright 2023 Nordic Semiconductor ASA +# SPDX-License-Identifier: Apache-2.0 + +# Compile all the applications needed by all bsim UART tests + +#set -x #uncomment this line for debugging +set -ue + +: "${BSIM_OUT_PATH:?BSIM_OUT_PATH must be defined}" +: "${BSIM_COMPONENTS_PATH:?BSIM_COMPONENTS_PATH must be defined}" +: "${ZEPHYR_BASE:?ZEPHYR_BASE must be set to point to the zephyr root\ + directory}" + +WORK_DIR="${WORK_DIR:-${ZEPHYR_BASE}/bsim_out}" +BOARD="${BOARD:-nrf52_bsim}" +BOARD_ROOT="${BOARD_ROOT:-${ZEPHYR_BASE}}" + +mkdir -p ${WORK_DIR} + +source ${ZEPHYR_BASE}/tests/bsim/sh_common.source + +# Placeholder, nothing yet +# Add apps needed for multidevice UART tests here + +wait_for_background_jobs From 1fafa94a35c1bf9b16981f55fbf2962ac777f875 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Martin=20J=C3=A4ger?= Date: Sat, 13 Jan 2024 09:33:17 +0100 Subject: [PATCH 2312/3723] dts: bindings: rtc: pcf8563: remove unused wakeup-source MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The wakeup-source is not used by the driver. Most probably this was inadvertently left when copying the binding from pcf8523 driver. Signed-off-by: Martin Jäger --- dts/bindings/rtc/nxp,pcf8563.yaml | 3 --- 1 file changed, 3 deletions(-) diff --git a/dts/bindings/rtc/nxp,pcf8563.yaml b/dts/bindings/rtc/nxp,pcf8563.yaml index 95ca4a793a4..d354c71af00 100644 --- a/dts/bindings/rtc/nxp,pcf8563.yaml +++ b/dts/bindings/rtc/nxp,pcf8563.yaml @@ -8,9 +8,6 @@ compatible: "nxp,pcf8563" include: - name: rtc-device.yaml - name: i2c-device.yaml - - name: pm.yaml - property-allowlist: - - wakeup-source properties: int1-gpios: From 2effad3b11bb48724d9fa6e039665b18cf70abf3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Martin=20J=C3=A4ger?= Date: Sat, 13 Jan 2024 09:38:01 +0100 Subject: [PATCH 2313/3723] drivers: rtc: pcf8563: fix ifdef for alarm_set_callback MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The callback should only be available when CONFIG_RTC_ALARM is defined. Signed-off-by: Martin Jäger --- drivers/rtc/rtc_pcf8563.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/rtc/rtc_pcf8563.c b/drivers/rtc/rtc_pcf8563.c index 4b16707dee8..515adaf5584 100644 --- a/drivers/rtc/rtc_pcf8563.c +++ b/drivers/rtc/rtc_pcf8563.c @@ -427,10 +427,10 @@ static const struct rtc_driver_api pcf8563_driver_api = { .alarm_set_time = pcf8563_alarm_set_time, .alarm_get_time = pcf8563_alarm_get_time, .alarm_is_pending = pcf8563_alarm_is_pending, -#endif #ifdef PCF8563_INT1_GPIOS_IN_USE .alarm_set_callback = pcf8563_alarm_set_callback, #endif +#endif }; From e1d495be811d000f2840c045e6964a4f72c39a64 Mon Sep 17 00:00:00 2001 From: Chekhov Ma Date: Tue, 9 Jan 2024 14:52:51 +0800 Subject: [PATCH 2314/3723] driver: add new gpio driver "gpio_mcux_rgpio" Add RGPIO gpio driver. This driver is used for i.MX93 and i.MX8ULP. GPIO pinctrl, read/write and interrupt is supported. Runtime mmio configuration is enabled, so no need for region definition in mimx9/mmu_region.c Signed-off-by: Chekhov Ma --- drivers/gpio/CMakeLists.txt | 1 + drivers/gpio/Kconfig | 2 + drivers/gpio/Kconfig.mcux_rgpio | 12 + drivers/gpio/gpio_mcux_rgpio.c | 308 ++++++++++++++++++++++++++ dts/bindings/gpio/nxp,imx-rgpio.yaml | 32 +++ soc/arm64/nxp_imx/mimx9/pinctrl_soc.h | 3 +- 6 files changed, 356 insertions(+), 2 deletions(-) create mode 100644 drivers/gpio/Kconfig.mcux_rgpio create mode 100644 drivers/gpio/gpio_mcux_rgpio.c create mode 100644 dts/bindings/gpio/nxp,imx-rgpio.yaml diff --git a/drivers/gpio/CMakeLists.txt b/drivers/gpio/CMakeLists.txt index 56018e7744f..f3f00d79db6 100644 --- a/drivers/gpio/CMakeLists.txt +++ b/drivers/gpio/CMakeLists.txt @@ -26,6 +26,7 @@ zephyr_library_sources_ifdef(CONFIG_GPIO_MCP230XX gpio_mcp230xx.c) zephyr_library_sources_ifdef(CONFIG_GPIO_BD8LB600FS gpio_bd8lb600fs.c) zephyr_library_sources_ifdef(CONFIG_GPIO_MCUX gpio_mcux.c) zephyr_library_sources_ifdef(CONFIG_GPIO_MCUX_IGPIO gpio_mcux_igpio.c) +zephyr_library_sources_ifdef(CONFIG_GPIO_MCUX_RGPIO gpio_mcux_rgpio.c) zephyr_library_sources_ifdef(CONFIG_GPIO_MCUX_LPC gpio_mcux_lpc.c) zephyr_library_sources_ifdef(CONFIG_GPIO_MMIO32 gpio_mmio32.c) zephyr_library_sources_ifdef(CONFIG_GPIO_XEC gpio_mchp_xec.c) diff --git a/drivers/gpio/Kconfig b/drivers/gpio/Kconfig index 6b6928f3971..a6c2417144d 100644 --- a/drivers/gpio/Kconfig +++ b/drivers/gpio/Kconfig @@ -105,6 +105,8 @@ source "drivers/gpio/Kconfig.mcux" source "drivers/gpio/Kconfig.mcux_igpio" +source "drivers/gpio/Kconfig.mcux_rgpio" + source "drivers/gpio/Kconfig.mcux_lpc" source "drivers/gpio/Kconfig.mmio32" diff --git a/drivers/gpio/Kconfig.mcux_rgpio b/drivers/gpio/Kconfig.mcux_rgpio new file mode 100644 index 00000000000..6446137542a --- /dev/null +++ b/drivers/gpio/Kconfig.mcux_rgpio @@ -0,0 +1,12 @@ +# MCUX RGPIO configuration options + +# Copyright 2023, NXP +# SPDX-License-Identifier: Apache-2.0 + +config GPIO_MCUX_RGPIO + bool "MCUX RGPIO driver" + default y + depends on DT_HAS_NXP_IMX_RGPIO_ENABLED + select PINCTRL + help + Enable the MCUX RGPIO driver. diff --git a/drivers/gpio/gpio_mcux_rgpio.c b/drivers/gpio/gpio_mcux_rgpio.c new file mode 100644 index 00000000000..16ad02c6ae8 --- /dev/null +++ b/drivers/gpio/gpio_mcux_rgpio.c @@ -0,0 +1,308 @@ +/* + * Copyright 2023, NXP + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#define DT_DRV_COMPAT nxp_imx_rgpio + +#include +#include +#include +#include +#include +#include +#include + +#include + +struct gpio_pin_gaps { + uint8_t start; + uint8_t len; +}; + +/* Required by DEVICE_MMIO_NAMED_* macros */ +#define DEV_CFG(_dev) \ + ((const struct mcux_rgpio_config *)(_dev)->config) +#define DEV_DATA(_dev) ((struct mcux_rgpio_data *)(_dev)->data) + +struct mcux_rgpio_config { + /* gpio_driver_config needs to be first */ + struct gpio_driver_config common; + + DEVICE_MMIO_NAMED_ROM(reg_base); + + const struct pinctrl_soc_pinmux *pin_muxes; + const struct gpio_pin_gaps *pin_gaps; + uint8_t mux_count; + uint8_t gap_count; +}; + +struct mcux_rgpio_data { + /* gpio_driver_data needs to be first */ + struct gpio_driver_data general; + + DEVICE_MMIO_NAMED_RAM(reg_base); + + /* port ISR callback routine address */ + sys_slist_t callbacks; +}; + +static int mcux_rgpio_configure(const struct device *dev, + gpio_pin_t pin, gpio_flags_t flags) +{ + RGPIO_Type *base = (RGPIO_Type *)DEVICE_MMIO_NAMED_GET(dev, reg_base); + const struct mcux_rgpio_config *config = dev->config; + + struct pinctrl_soc_pin pin_cfg; + int cfg_idx = pin, i; + + /* Some SOCs have non-contiguous gpio pin layouts, account for this */ + for (i = 0; i < config->gap_count; i++) { + if (pin >= config->pin_gaps[i].start) { + if (pin < (config->pin_gaps[i].start + + config->pin_gaps[i].len)) { + /* Pin is not connected to a mux */ + return -ENOTSUP; + } + cfg_idx -= config->pin_gaps[i].len; + } + } + + /* Init pin configuration struct, and use pinctrl api to apply settings */ + if (cfg_idx >= config->mux_count) { + /* Pin is not connected to a mux */ + return -ENOTSUP; + } + + /* Set appropriate bits in pin configuration register */ + volatile uint32_t *gpio_cfg_reg = (volatile uint32_t *) + ((size_t)config->pin_muxes[cfg_idx].config_register); + uint32_t reg = *gpio_cfg_reg; + + /* TODO: Default flags, work for i.MX 9352 */ + if ((flags & GPIO_SINGLE_ENDED) != 0) { + /* Set ODE bit */ + reg |= (0x1 << MCUX_IMX_DRIVE_OPEN_DRAIN_SHIFT); + } else { + reg &= ~(0x1 << MCUX_IMX_DRIVE_OPEN_DRAIN_SHIFT); + } + if (((flags & GPIO_PULL_UP) != 0) || ((flags & GPIO_PULL_DOWN) != 0)) { + /* i.MX93 has no pull enable bit */ + if (((flags & GPIO_PULL_UP) != 0)) { + reg |= (0x1 << MCUX_IMX_BIAS_PULL_UP_SHIFT); + reg &= ~(0x1 << MCUX_IMX_BIAS_PULL_DOWN_SHIFT); + } else { + reg |= (0x1 << MCUX_IMX_BIAS_PULL_DOWN_SHIFT); + reg &= ~(0x1 << MCUX_IMX_BIAS_PULL_UP_SHIFT); + } + } else { + /* Set pin to highz */ + reg &= ~((0x1 << MCUX_IMX_BIAS_PULL_DOWN_SHIFT) | + (0x1 << MCUX_IMX_BIAS_PULL_UP_SHIFT)); + } + + memcpy(&pin_cfg.pinmux, &config->pin_muxes[cfg_idx], sizeof(pin_cfg)); + /* cfg register will be set by pinctrl_configure_pins */ + pin_cfg.pin_ctrl_flags = reg; + pinctrl_configure_pins(&pin_cfg, 1, PINCTRL_REG_NONE); + + if (((flags & GPIO_INPUT) != 0) && ((flags & GPIO_OUTPUT) != 0)) { + return -ENOTSUP; + } + + if (flags & GPIO_OUTPUT_INIT_HIGH) { + RGPIO_WritePinOutput(base, pin, 1); + } + + if (flags & GPIO_OUTPUT_INIT_LOW) { + RGPIO_WritePinOutput(base, pin, 0); + } + + WRITE_BIT(base->PDDR, pin, flags & GPIO_OUTPUT); + + return 0; +} + +static int mcux_rgpio_port_get_raw(const struct device *dev, uint32_t *value) +{ + RGPIO_Type *base = (RGPIO_Type *)DEVICE_MMIO_NAMED_GET(dev, reg_base); + + *value = base->PDIR; + + return 0; +} + +static int mcux_rgpio_port_set_masked_raw(const struct device *dev, + uint32_t mask, + uint32_t value) +{ + RGPIO_Type *base = (RGPIO_Type *)DEVICE_MMIO_NAMED_GET(dev, reg_base); + + base->PDOR = (base->PDOR & ~mask) | (mask & value); + + return 0; +} + +static int mcux_rgpio_port_set_bits_raw(const struct device *dev, + uint32_t mask) +{ + RGPIO_Type *base = (RGPIO_Type *)DEVICE_MMIO_NAMED_GET(dev, reg_base); + + RGPIO_PortSet(base, mask); + + return 0; +} + +static int mcux_rgpio_port_clear_bits_raw(const struct device *dev, + uint32_t mask) +{ + RGPIO_Type *base = (RGPIO_Type *)DEVICE_MMIO_NAMED_GET(dev, reg_base); + + RGPIO_PortClear(base, mask); + + return 0; +} + +static int mcux_rgpio_port_toggle_bits(const struct device *dev, + uint32_t mask) +{ + RGPIO_Type *base = (RGPIO_Type *)DEVICE_MMIO_NAMED_GET(dev, reg_base); + + RGPIO_PortToggle(base, mask); + + return 0; +} + +static int mcux_rgpio_pin_interrupt_configure(const struct device *dev, + gpio_pin_t pin, + enum gpio_int_mode mode, + enum gpio_int_trig trig) +{ + RGPIO_Type *base = (RGPIO_Type *)DEVICE_MMIO_NAMED_GET(dev, reg_base); + unsigned int key; + uint8_t irqs, irqc; + + irqs = 0; /* only irq0 is used for irq */ + + if (mode == GPIO_INT_MODE_DISABLED) { + irqc = kRGPIO_InterruptOrDMADisabled; + } else if ((mode == GPIO_INT_MODE_EDGE) && + (trig == GPIO_INT_TRIG_LOW)) { + irqc = kRGPIO_InterruptFallingEdge; + } else if ((mode == GPIO_INT_MODE_EDGE) && + (trig == GPIO_INT_TRIG_HIGH)) { + irqc = kRGPIO_InterruptRisingEdge; + } else if ((mode == GPIO_INT_MODE_EDGE) && + (trig == GPIO_INT_TRIG_BOTH)) { + irqc = kRGPIO_InterruptEitherEdge; + } else if ((mode == GPIO_INT_MODE_LEVEL) && + (trig == GPIO_INT_TRIG_LOW)) { + irqc = kRGPIO_InterruptLogicZero; + } else if ((mode == GPIO_INT_MODE_LEVEL) && + (trig == GPIO_INT_TRIG_HIGH)) { + irqc = kRGPIO_InterruptLogicOne; + } else { + return -EINVAL; /* should never end up here */ + } + + key = irq_lock(); + RGPIO_SetPinInterruptConfig(base, pin, irqs, irqc); + irq_unlock(key); + + return 0; +} + +static int mcux_rgpio_manage_callback(const struct device *dev, + struct gpio_callback *callback, + bool set) +{ + struct mcux_rgpio_data *data = dev->data; + + return gpio_manage_callback(&data->callbacks, callback, set); +} + +static void mcux_rgpio_port_isr(const struct device *dev) +{ + RGPIO_Type *base = (RGPIO_Type *)DEVICE_MMIO_NAMED_GET(dev, reg_base); + struct mcux_rgpio_data *data = dev->data; + uint32_t int_flags; + + int_flags = base->ISFR[0]; /* Notice: only irq0 is used for now */ + base->ISFR[0] = int_flags; + + gpio_fire_callbacks(&data->callbacks, dev, int_flags); +} + +static const struct gpio_driver_api mcux_rgpio_driver_api = { + .pin_configure = mcux_rgpio_configure, + .port_get_raw = mcux_rgpio_port_get_raw, + .port_set_masked_raw = mcux_rgpio_port_set_masked_raw, + .port_set_bits_raw = mcux_rgpio_port_set_bits_raw, + .port_clear_bits_raw = mcux_rgpio_port_clear_bits_raw, + .port_toggle_bits = mcux_rgpio_port_toggle_bits, + .pin_interrupt_configure = mcux_rgpio_pin_interrupt_configure, + .manage_callback = mcux_rgpio_manage_callback, +}; + +/* These macros will declare an array of pinctrl_soc_pinmux types */ +#define PINMUX_INIT(node, prop, idx) MCUX_IMX_PINMUX(DT_PROP_BY_IDX(node, prop, idx)), +#define MCUX_RGPIO_PIN_DECLARE(n) \ + const struct pinctrl_soc_pinmux mcux_rgpio_pinmux_##n[] = { \ + DT_FOREACH_PROP_ELEM(DT_DRV_INST(n), pinmux, PINMUX_INIT) \ + }; \ + const uint8_t mcux_rgpio_pin_gaps_##n[] = \ + DT_INST_PROP_OR(n, gpio_reserved_ranges, {}); +#define MCUX_RGPIO_PIN_INIT(n) \ + .pin_muxes = mcux_rgpio_pinmux_##n, \ + .pin_gaps = (const struct gpio_pin_gaps *)mcux_rgpio_pin_gaps_##n, \ + .mux_count = DT_PROP_LEN(DT_DRV_INST(n), pinmux), \ + .gap_count = (ARRAY_SIZE(mcux_rgpio_pin_gaps_##n) / 2) + +#define MCUX_RGPIO_IRQ_INIT(n, i) \ + do { \ + IRQ_CONNECT(DT_INST_IRQ_BY_IDX(n, i, irq), \ + DT_INST_IRQ_BY_IDX(n, i, priority), \ + mcux_rgpio_port_isr, \ + DEVICE_DT_INST_GET(n), 0); \ + \ + irq_enable(DT_INST_IRQ_BY_IDX(n, i, irq)); \ + } while (false) + +#define MCUX_RGPIO_INIT(n) \ + MCUX_RGPIO_PIN_DECLARE(n) \ + static int mcux_rgpio_##n##_init(const struct device *dev); \ + \ + static const struct mcux_rgpio_config mcux_rgpio_##n##_config = {\ + .common = { \ + .port_pin_mask = GPIO_PORT_PIN_MASK_FROM_DT_INST(n),\ + }, \ + DEVICE_MMIO_NAMED_ROM_INIT(reg_base, DT_DRV_INST(n)), \ + MCUX_RGPIO_PIN_INIT(n) \ + }; \ + \ + static struct mcux_rgpio_data mcux_rgpio_##n##_data; \ + \ + DEVICE_DT_INST_DEFINE(n, \ + mcux_rgpio_##n##_init, \ + NULL, \ + &mcux_rgpio_##n##_data, \ + &mcux_rgpio_##n##_config, \ + POST_KERNEL, \ + CONFIG_GPIO_INIT_PRIORITY, \ + &mcux_rgpio_driver_api); \ + \ + static int mcux_rgpio_##n##_init(const struct device *dev) \ + { \ + DEVICE_MMIO_NAMED_MAP(dev, reg_base, \ + K_MEM_CACHE_NONE | K_MEM_DIRECT_MAP); \ + IF_ENABLED(DT_INST_IRQ_HAS_IDX(n, 0), \ + (MCUX_RGPIO_IRQ_INIT(n, 0);)) \ + \ + IF_ENABLED(DT_INST_IRQ_HAS_IDX(n, 1), \ + (MCUX_RGPIO_IRQ_INIT(n, 1);)) \ + \ + return 0; \ + } + +DT_INST_FOREACH_STATUS_OKAY(MCUX_RGPIO_INIT) diff --git a/dts/bindings/gpio/nxp,imx-rgpio.yaml b/dts/bindings/gpio/nxp,imx-rgpio.yaml new file mode 100644 index 00000000000..eaa4e08374e --- /dev/null +++ b/dts/bindings/gpio/nxp,imx-rgpio.yaml @@ -0,0 +1,32 @@ +# Copyright 2024, NXP +# SPDX-License-Identifier: Apache-2.0 + +description: i.MX RGPIO node + +compatible: "nxp,imx-rgpio" + +include: [gpio-controller.yaml, base.yaml] + +properties: + reg: + required: true + + rdc: + type: int + description: Set the RDC permission for this peripheral + + pinmux: + type: phandles + description: | + IMX pin selection peripheral does not follow specific + pattern for which GPIO port uses which pinmux. Use this property to specify + pinctrl nodes to use for the gpio port when CONFIG_PINCTRL=y. Note that + the order of the nodes matters. The first node for gpio1 will be used + as the pinmux for gpio0, port 0. + + "#gpio-cells": + const: 2 + +gpio-cells: + - pin + - flags diff --git a/soc/arm64/nxp_imx/mimx9/pinctrl_soc.h b/soc/arm64/nxp_imx/mimx9/pinctrl_soc.h index c3c66d532ec..bd9496ec582 100644 --- a/soc/arm64/nxp_imx/mimx9/pinctrl_soc.h +++ b/soc/arm64/nxp_imx/mimx9/pinctrl_soc.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2022, NXP + * Copyright (c) 2022-2023, NXP * * SPDX-License-Identifier: Apache-2.0 */ @@ -19,7 +19,6 @@ extern "C" { #define MCUX_IMX_DRIVE_OPEN_DRAIN_SHIFT IOMUXC1_SW_PAD_CTL_PAD_OD_SHIFT #define MCUX_IMX_BIAS_PULL_DOWN_SHIFT IOMUXC1_SW_PAD_CTL_PAD_PD_SHIFT #define MCUX_IMX_BIAS_PULL_UP_SHIFT IOMUXC1_SW_PAD_CTL_PAD_PU_SHIFT -#define MCUX_IMX_BIAS_PULL_ENABLE_SHIFT IOMUXC1_SW_PAD_CTL_PAD_PE_SHIFT #define MCUX_IMX_SLEW_RATE_SHIFT IOMUXC1_SW_PAD_CTL_PAD_FSEL1_SHIFT #define MCUX_IMX_DRIVE_STRENGTH_SHIFT IOMUXC1_SW_PAD_CTL_PAD_DSE_SHIFT #define MCUX_IMX_INPUT_ENABLE_SHIFT 23 /* Shift to a bit not used by IOMUXC_SW_PAD_CTL */ From 4e59679ce527afcc0c0bf3af149f536aee30d08d Mon Sep 17 00:00:00 2001 From: Chekhov Ma Date: Fri, 12 Jan 2024 14:41:18 +0800 Subject: [PATCH 2315/3723] soc: imx93: enable rgpio driver Add HAS_MCUX_RGPIO to Kconfig.soc Add gpio1 ~ gpio4 dts node and pinctrl node in nxp_mimx93_a55.dtsi Signed-off-by: Chekhov Ma --- .../arm64/mimx93_evk/mimx93_evk_a55_defconfig | 1 + dts/arm64/nxp/nxp_mimx93_a55.dtsi | 161 ++++++++++++++++++ 2 files changed, 162 insertions(+) diff --git a/boards/arm64/mimx93_evk/mimx93_evk_a55_defconfig b/boards/arm64/mimx93_evk/mimx93_evk_a55_defconfig index 53cb74f825c..fb60fdfd9bb 100644 --- a/boards/arm64/mimx93_evk/mimx93_evk_a55_defconfig +++ b/boards/arm64/mimx93_evk/mimx93_evk_a55_defconfig @@ -22,6 +22,7 @@ CONFIG_BOARD_MIMX93_EVK_A55=y # Zephyr Kernel Configuration CONFIG_XIP=n +CONFIG_KERNEL_DIRECT_MAP=y # Serial Drivers CONFIG_SERIAL=y diff --git a/dts/arm64/nxp/nxp_mimx93_a55.dtsi b/dts/arm64/nxp/nxp_mimx93_a55.dtsi index bfedef48381..4592209c902 100644 --- a/dts/arm64/nxp/nxp_mimx93_a55.dtsi +++ b/dts/arm64/nxp/nxp_mimx93_a55.dtsi @@ -8,6 +8,7 @@ #include #include #include +#include #include #include @@ -76,6 +77,46 @@ #clock-cells = <3>; }; + gpio1: gpio@47400000 { + compatible = "nxp,imx-rgpio"; + reg = <0x47400000 DT_SIZE_K(64)>; + interrupt-parent = <&gic>; + interrupts = , + ; + gpio-controller; + #gpio-cells = <2>; + }; + + gpio2: gpio@43810000 { + compatible = "nxp,imx-rgpio"; + reg = <0x43810000 DT_SIZE_K(64)>; + interrupt-parent = <&gic>; + interrupts = , + ; + gpio-controller; + #gpio-cells = <2>; + }; + + gpio3: gpio@43820000 { + compatible = "nxp,imx-rgpio"; + reg = <0x43820000 DT_SIZE_K(64)>; + interrupt-parent = <&gic>; + interrupts = , + ; + gpio-controller; + #gpio-cells = <2>; + }; + + gpio4: gpio@43830000 { + compatible = "nxp,imx-rgpio"; + reg = <0x43830000 DT_SIZE_K(64)>; + interrupt-parent = <&gic>; + interrupts = , + ; + gpio-controller; + #gpio-cells = <2>; + }; + lpuart1: serial@44380000 { compatible = "nxp,imx-lpuart", "nxp,kinetis-lpuart"; reg = <0x44380000 DT_SIZE_K(64)>; @@ -280,3 +321,123 @@ #size-cells = <0>; }; }; + +&gpio1{ + pinmux = <&iomuxc1_i2c1_scl_gpio_io_gpio1_io00>, + <&iomuxc1_i2c1_sda_gpio_io_gpio1_io01>, + <&iomuxc1_i2c2_scl_gpio_io_gpio1_io02>, + <&iomuxc1_i2c2_sda_gpio_io_gpio1_io03>, + <&iomuxc1_uart1_rxd_gpio_io_gpio1_io04>, + <&iomuxc1_uart1_txd_gpio_io_gpio1_io05>, + <&iomuxc1_uart2_rxd_gpio_io_gpio1_io06>, + <&iomuxc1_uart2_txd_gpio_io_gpio1_io07>, + <&iomuxc1_pdm_clk_gpio_io_gpio1_io08>, + <&iomuxc1_pdm_bit_stream0_gpio_io_gpio1_io09>, + <&iomuxc1_pdm_bit_stream1_gpio_io_gpio1_io10>, + <&iomuxc1_sai1_txfs_gpio_io_gpio1_io11>, + <&iomuxc1_sai1_txc_gpio_io_gpio1_io12>, + <&iomuxc1_sai1_txd0_gpio_io_gpio1_io13>, + <&iomuxc1_sai1_rxd0_gpio_io_gpio1_io14>, + <&iomuxc1_wdog_any_gpio_io_gpio1_io15>; +}; + +&gpio2{ + pinmux = <&iomuxc1_gpio_io00_gpio_io_gpio2_io00>, + <&iomuxc1_gpio_io01_gpio_io_gpio2_io01>, + <&iomuxc1_gpio_io02_gpio_io_gpio2_io02>, + <&iomuxc1_gpio_io03_gpio_io_gpio2_io03>, + <&iomuxc1_gpio_io04_gpio_io_gpio2_io04>, + <&iomuxc1_gpio_io05_gpio_io_gpio2_io05>, + <&iomuxc1_gpio_io06_gpio_io_gpio2_io06>, + <&iomuxc1_gpio_io07_gpio_io_gpio2_io07>, + <&iomuxc1_gpio_io08_gpio_io_gpio2_io08>, + <&iomuxc1_gpio_io09_gpio_io_gpio2_io09>, + <&iomuxc1_gpio_io10_gpio_io_gpio2_io10>, + <&iomuxc1_gpio_io11_gpio_io_gpio2_io11>, + <&iomuxc1_gpio_io12_gpio_io_gpio2_io12>, + <&iomuxc1_gpio_io13_gpio_io_gpio2_io13>, + <&iomuxc1_gpio_io14_gpio_io_gpio2_io14>, + <&iomuxc1_gpio_io15_gpio_io_gpio2_io15>, + <&iomuxc1_gpio_io16_gpio_io_gpio2_io16>, + <&iomuxc1_gpio_io17_gpio_io_gpio2_io17>, + <&iomuxc1_gpio_io18_gpio_io_gpio2_io18>, + <&iomuxc1_gpio_io19_gpio_io_gpio2_io19>, + <&iomuxc1_gpio_io20_gpio_io_gpio2_io20>, + <&iomuxc1_gpio_io21_gpio_io_gpio2_io21>, + <&iomuxc1_gpio_io22_gpio_io_gpio2_io22>, + <&iomuxc1_gpio_io23_gpio_io_gpio2_io23>, + <&iomuxc1_gpio_io24_gpio_io_gpio2_io24>, + <&iomuxc1_gpio_io25_gpio_io_gpio2_io25>, + <&iomuxc1_gpio_io26_gpio_io_gpio2_io26>, + <&iomuxc1_gpio_io27_gpio_io_gpio2_io27>, + <&iomuxc1_gpio_io28_gpio_io_gpio2_io28>, + <&iomuxc1_gpio_io29_gpio_io_gpio2_io29>; +}; + +&gpio3{ + pinmux = <&iomuxc1_sd2_cd_b_gpio_io_gpio3_io00>, + <&iomuxc1_sd2_clk_gpio_io_gpio3_io01>, + <&iomuxc1_sd2_cmd_gpio_io_gpio3_io02>, + <&iomuxc1_sd2_data0_gpio_io_gpio3_io03>, + <&iomuxc1_sd2_data1_gpio_io_gpio3_io04>, + <&iomuxc1_sd2_data2_gpio_io_gpio3_io05>, + <&iomuxc1_sd2_data3_gpio_io_gpio3_io06>, + <&iomuxc1_sd2_reset_b_gpio_io_gpio3_io07>, + <&iomuxc1_sd1_clk_gpio_io_gpio3_io08>, + <&iomuxc1_sd1_cmd_gpio_io_gpio3_io09>, + <&iomuxc1_sd1_data0_gpio_io_gpio3_io10>, + <&iomuxc1_sd1_data1_gpio_io_gpio3_io11>, + <&iomuxc1_sd1_data2_gpio_io_gpio3_io12>, + <&iomuxc1_sd1_data3_gpio_io_gpio3_io13>, + <&iomuxc1_sd1_data4_gpio_io_gpio3_io14>, + <&iomuxc1_sd1_data5_gpio_io_gpio3_io15>, + <&iomuxc1_sd1_data6_gpio_io_gpio3_io16>, + <&iomuxc1_sd1_data7_gpio_io_gpio3_io17>, + <&iomuxc1_sd1_strobe_gpio_io_gpio3_io18>, + <&iomuxc1_sd2_vselect_gpio_io_gpio3_io19>, + <&iomuxc1_sd3_clk_gpio_io_gpio3_io20>, + <&iomuxc1_sd3_cmd_gpio_io_gpio3_io21>, + <&iomuxc1_sd3_data0_gpio_io_gpio3_io22>, + <&iomuxc1_sd3_data1_gpio_io_gpio3_io23>, + <&iomuxc1_sd3_data2_gpio_io_gpio3_io24>, + <&iomuxc1_sd3_data3_gpio_io_gpio3_io25>, + <&iomuxc1_ccm_clko1_gpio_io_gpio3_io26>, + <&iomuxc1_ccm_clko2_gpio_io_gpio3_io27>, + <&iomuxc1_dap_tdi_gpio_io_gpio3_io28>, + <&iomuxc1_dap_tms_swdio_gpio_io_gpio3_io29>, + <&iomuxc1_dap_tclk_swclk_gpio_io_gpio3_io30>, + <&iomuxc1_dap_tdo_traceswo_gpio_io_gpio3_io31>; +}; + +&gpio4{ + pinmux = <&iomuxc1_enet1_mdc_gpio_io_gpio4_io00>, + <&iomuxc1_enet1_mdio_gpio_io_gpio4_io01>, + <&iomuxc1_enet1_td3_gpio_io_gpio4_io02>, + <&iomuxc1_enet1_td2_gpio_io_gpio4_io03>, + <&iomuxc1_enet1_td1_gpio_io_gpio4_io04>, + <&iomuxc1_enet1_td0_gpio_io_gpio4_io05>, + <&iomuxc1_enet1_tx_ctl_gpio_io_gpio4_io06>, + <&iomuxc1_enet1_txc_gpio_io_gpio4_io07>, + <&iomuxc1_enet1_rx_ctl_gpio_io_gpio4_io08>, + <&iomuxc1_enet1_rxc_gpio_io_gpio4_io09>, + <&iomuxc1_enet1_rd0_gpio_io_gpio4_io10>, + <&iomuxc1_enet1_rd1_gpio_io_gpio4_io11>, + <&iomuxc1_enet1_rd2_gpio_io_gpio4_io12>, + <&iomuxc1_enet1_rd3_gpio_io_gpio4_io13>, + <&iomuxc1_enet2_mdc_gpio_io_gpio4_io14>, + <&iomuxc1_enet2_mdio_gpio_io_gpio4_io15>, + <&iomuxc1_enet2_td3_gpio_io_gpio4_io16>, + <&iomuxc1_enet2_td2_gpio_io_gpio4_io17>, + <&iomuxc1_enet2_td1_gpio_io_gpio4_io18>, + <&iomuxc1_enet2_td0_gpio_io_gpio4_io19>, + <&iomuxc1_enet2_tx_ctl_gpio_io_gpio4_io20>, + <&iomuxc1_enet2_txc_gpio_io_gpio4_io21>, + <&iomuxc1_enet2_rx_ctl_gpio_io_gpio4_io22>, + <&iomuxc1_enet2_rxc_gpio_io_gpio4_io23>, + <&iomuxc1_enet2_rd0_gpio_io_gpio4_io24>, + <&iomuxc1_enet2_rd1_gpio_io_gpio4_io25>, + <&iomuxc1_enet2_rd2_gpio_io_gpio4_io26>, + <&iomuxc1_enet2_rd3_gpio_io_gpio4_io27>, + <&iomuxc1_ccm_clko3_gpio_io_gpio4_io28>, + <&iomuxc1_ccm_clko4_gpio_io_gpio4_io29>; +}; From 969792bc183e07433c44d802c2e22aeef311bd3e Mon Sep 17 00:00:00 2001 From: Chekhov Ma Date: Tue, 9 Jan 2024 15:32:04 +0800 Subject: [PATCH 2316/3723] board: mimx93_evk_a55: enable rgpio Add RGPIO 1,2,3,4 to mimx93_evk_a55 board dts Signed-off-by: Chekhov Ma --- boards/arm64/mimx93_evk/mimx93_evk_a55.dts | 16 ++++++++++++++++ boards/arm64/mimx93_evk/mimx93_evk_a55.yaml | 1 + 2 files changed, 17 insertions(+) diff --git a/boards/arm64/mimx93_evk/mimx93_evk_a55.dts b/boards/arm64/mimx93_evk/mimx93_evk_a55.dts index 2fb9d0e9c12..e81a77509ba 100644 --- a/boards/arm64/mimx93_evk/mimx93_evk_a55.dts +++ b/boards/arm64/mimx93_evk/mimx93_evk_a55.dts @@ -67,3 +67,19 @@ pinctrl-0 = <&spi3_default>; pinctrl-names = "default"; }; + +&gpio1{ + status = "okay"; +}; + +&gpio2{ + status = "okay"; +}; + +&gpio3{ + status = "okay"; +}; + +&gpio4{ + status = "okay"; +}; diff --git a/boards/arm64/mimx93_evk/mimx93_evk_a55.yaml b/boards/arm64/mimx93_evk/mimx93_evk_a55.yaml index a57ec92ea4f..d4fc0bc7ae6 100644 --- a/boards/arm64/mimx93_evk/mimx93_evk_a55.yaml +++ b/boards/arm64/mimx93_evk/mimx93_evk_a55.yaml @@ -7,6 +7,7 @@ toolchain: - cross-compile ram: 1024 supported: + - gpio - uart - i2c - spi From 97fabefa34918e3f20f63e1c8c622ad11d6411f8 Mon Sep 17 00:00:00 2001 From: Chekhov Ma Date: Fri, 8 Dec 2023 13:13:32 +0800 Subject: [PATCH 2317/3723] board: mimx93_evk_a55: add led and button definitions and alias Tested with zephyr example project "samples/basic/blinky" and "samples/ basic/button". These examples can run out-of-the-box. No modification needed. for "samples/basic/blinky", the red LED inside RGB LED on board will blink every 2 seconds. for "samples/basic/button", the red LED inside RGB LED on board will turn on once BTN1 on board is pressed down. An log will be present in uart console as well. Signed-off-by: Chekhov Ma --- boards/arm64/mimx93_evk/mimx93_evk_a55.dts | 35 ++++++++++++++++++++++ 1 file changed, 35 insertions(+) diff --git a/boards/arm64/mimx93_evk/mimx93_evk_a55.dts b/boards/arm64/mimx93_evk/mimx93_evk_a55.dts index e81a77509ba..421ad5e3c71 100644 --- a/boards/arm64/mimx93_evk/mimx93_evk_a55.dts +++ b/boards/arm64/mimx93_evk/mimx93_evk_a55.dts @@ -28,6 +28,41 @@ sram0: memory@c0000000 { reg = <0xc0000000 DT_SIZE_M(1)>; }; + + aliases { + led0 = &led_r; + sw0 = &btn_1; + }; + + leds { + compatible = "gpio-leds"; + led_r: led_r { + label = "LED_R"; + gpios = <&gpio2 13 GPIO_ACTIVE_HIGH>; + }; + led_g: led_g { + label = "LED_G"; + gpios = <&gpio2 4 GPIO_ACTIVE_HIGH>; + }; + led_b: led_b { + label = "LED_B"; + gpios = <&gpio2 12 GPIO_ACTIVE_HIGH>; + }; + }; + + keys { + compatible = "gpio-keys"; + + btn_1: btn_1{ + label = "BTN1"; + gpios = <&gpio2 23 GPIO_ACTIVE_LOW>; + }; + + btn_2: btn_2{ + label = "BTN2"; + gpios = <&gpio2 24 GPIO_ACTIVE_LOW>; + }; + }; }; &lpuart1 { From c78f583ed7228ff6dd0a17a8e5fcf81dd2b63df6 Mon Sep 17 00:00:00 2001 From: Chekhov Ma Date: Fri, 12 Jan 2024 14:49:37 +0800 Subject: [PATCH 2318/3723] tests: drivers: gpio_basic_api add board mimx93_evk_a55 Add mimx93_evk_a55.overlay to tests: drivers: gpio_basic_api Signed-off-by: Chekhov Ma --- .../gpio_basic_api/boards/mimx93_evk_a55.overlay | 13 +++++++++++++ 1 file changed, 13 insertions(+) create mode 100644 tests/drivers/gpio/gpio_basic_api/boards/mimx93_evk_a55.overlay diff --git a/tests/drivers/gpio/gpio_basic_api/boards/mimx93_evk_a55.overlay b/tests/drivers/gpio/gpio_basic_api/boards/mimx93_evk_a55.overlay new file mode 100644 index 00000000000..d28f7d93da7 --- /dev/null +++ b/tests/drivers/gpio/gpio_basic_api/boards/mimx93_evk_a55.overlay @@ -0,0 +1,13 @@ +/* + * Copyright 2024, NXP + * + * SPDX-License-Identifier: Apache-2.0 + */ + +/{ + resources { + compatible = "test-gpio-basic-api"; + out-gpios = <&gpio2 13 0>; + in-gpios = <&gpio2 14 0>; + }; +}; From 9eb0a554f90eba5e23d58027a4fa4691746c2950 Mon Sep 17 00:00:00 2001 From: Cong Nguyen Huu Date: Fri, 12 Jan 2024 17:54:05 +0700 Subject: [PATCH 2319/3723] drivers: nxp_s32_canxl: add support RX FIFO Driver supports both CAN classic and CAN FD frames when using RX FIFO mode Signed-off-by: Cong Nguyen Huu --- drivers/can/Kconfig.nxp_s32 | 14 ++- drivers/can/can_nxp_s32_canxl.c | 199 +++++++++++++++++++++++++++---- dts/arm/nxp/nxp_s32z27x_r52.dtsi | 22 ++-- 3 files changed, 201 insertions(+), 34 deletions(-) diff --git a/drivers/can/Kconfig.nxp_s32 b/drivers/can/Kconfig.nxp_s32 index 53c1ffc2b8b..09727d719ef 100644 --- a/drivers/can/Kconfig.nxp_s32 +++ b/drivers/can/Kconfig.nxp_s32 @@ -1,4 +1,4 @@ -# Copyright 2022-2023 NXP +# Copyright 2022-2024 NXP # SPDX-License-Identifier: Apache-2.0 config CAN_NXP_S32_CANXL @@ -10,17 +10,23 @@ config CAN_NXP_S32_CANXL Enable support for NXP S32 CANXL driver. if CAN_NXP_S32_CANXL +config CAN_NXP_S32_RX_FIFO + bool "NXP S32 CANXL uses RX FIFO" + default y + help + If this is enabled, NXP S32 CANXL uses RX FIFO. + Otherwise NXP S32 CANXL uses RX Message Descriptor. + config CAN_NXP_S32_MAX_RX int "Maximum number of RX descriptors" - depends on CAN_NXP_S32_CANXL default 16 - range 1 128 + range 1 32 if CAN_NXP_S32_RX_FIFO + range 1 128 if !CAN_NXP_S32_RX_FIFO help Maximum number of RX descriptors. config CAN_NXP_S32_MAX_TX int "Maximum number of TX descriptors" - depends on CAN_NXP_S32_CANXL default 16 range 1 128 help diff --git a/drivers/can/can_nxp_s32_canxl.c b/drivers/can/can_nxp_s32_canxl.c index 211e901055f..59b2b24aa98 100644 --- a/drivers/can/can_nxp_s32_canxl.c +++ b/drivers/can/can_nxp_s32_canxl.c @@ -1,5 +1,5 @@ /* - * Copyright 2022-2023 NXP + * Copyright 2022-2024 NXP * * SPDX-License-Identifier: Apache-2.0 */ @@ -23,8 +23,14 @@ * Convert from RX message buffer index to allocated filter ID and * vice versa. */ +#ifdef CONFIG_CAN_NXP_S32_RX_FIFO +#define RX_MBIDX_TO_ALLOC_IDX(x) (x) +#define ALLOC_IDX_TO_RXMB_IDX(x) (x) +#else #define RX_MBIDX_TO_ALLOC_IDX(x) (x - CONFIG_CAN_NXP_S32_MAX_TX) #define ALLOC_IDX_TO_RXMB_IDX(x) (x + CONFIG_CAN_NXP_S32_MAX_TX) +#endif + /* * Convert from TX message buffer index to allocated TX ID and vice @@ -37,6 +43,13 @@ #define CAN_NXP_S32_MAX_BITRATE 8000000 #define CAN_NXP_S32_DATA_LENGTH 64 +#ifdef CONFIG_CAN_NXP_S32_RX_FIFO +/* RX FIFO depth is fixed to the maximum value */ +#define CAN_NXP_S32_RX_FIFO_DEPTH 32 +/* RX FIFO water mark equal 1 that allows the interrupt is generated after 1 message received */ +#define CAN_NXP_S32_RX_FIFO_WATERMARK 1 +#endif + LOG_MODULE_REGISTER(nxp_s32_canxl, CONFIG_CAN_LOG_LEVEL); #define SP_AND_TIMING_NOT_SET(inst) \ @@ -66,6 +79,10 @@ struct can_nxp_s32_config { CANXL_SIC_Type *base_sic; CANXL_GRP_CONTROL_Type *base_grp_ctrl; CANXL_DSC_CONTROL_Type *base_dsc_ctrl; +#ifdef CONFIG_CAN_NXP_S32_RX_FIFO + CANXL_RXFIFO_Type * base_rx_fifo; + CANXL_RXFIFO_CONTROL_Type *base_rx_fifo_ctrl; +#endif uint8 instance; const struct device *clock_dev; clock_control_subsys_t clock_subsys; @@ -98,7 +115,9 @@ struct can_nxp_s32_tx_callback { struct can_nxp_s32_rx_callback { struct can_filter filter; +#ifndef CONFIG_CAN_NXP_S32_RX_FIFO Canexcel_Ip_DataInfoType rx_info; +#endif can_rx_callback_t function; void *arg; }; @@ -109,7 +128,9 @@ struct can_nxp_s32_data { ATOMIC_DEFINE(rx_allocs, CONFIG_CAN_NXP_S32_MAX_RX); struct k_mutex rx_mutex; struct can_nxp_s32_rx_callback rx_cbs[CONFIG_CAN_NXP_S32_MAX_RX]; +#ifndef CONFIG_CAN_NXP_S32_RX_FIFO Canexcel_RxFdMsg *rx_msg; +#endif ATOMIC_DEFINE(tx_allocs, CONFIG_CAN_NXP_S32_MAX_TX); struct k_sem tx_allocs_sem; @@ -117,6 +138,11 @@ struct can_nxp_s32_data { struct can_nxp_s32_tx_callback tx_cbs[CONFIG_CAN_NXP_S32_MAX_TX]; Canexcel_TxFdMsgType *tx_msg; +#ifdef CONFIG_CAN_NXP_S32_RX_FIFO + Canexcel_Ip_RxFifoFilterID_ADDR * rx_fifo_filter; + Canexcel_RxFdMsg *rx_fifo; +#endif + struct can_timing timing; #ifdef CONFIG_CAN_FD_MODE struct can_timing timing_data; @@ -140,6 +166,50 @@ static int can_nxp_s32_get_capabilities(const struct device *dev, can_mode_t *ca return 0; } +#ifdef CONFIG_CAN_NXP_S32_RX_FIFO +static void can_nxp_s32_config_rx_fifo_filter(const struct device *dev, int filter_id) +{ + const struct can_nxp_s32_config *config = dev->config; + struct can_nxp_s32_data *data = dev->data; + + /* Lock the RxFIFO by System by reading register */ + (void)config->base_rx_fifo_ctrl->RXFSYSLOCK; + + CanXL_ConfigIDFilter(config->base_rx_fifo, + &data->rx_fifo_filter[filter_id], filter_id); + + if ((config->base_rx_fifo_ctrl->RXFCSTA & CANXL_RXFIFO_CONTROL_RXFCSTA_SYSLOCK_MASK) + == CANXL_RXFIFO_CONTROL_RXFCSTA_SYSLOCK_MASK) { + /* Clear the sys lock to enable transfers */ + config->base_rx_fifo_ctrl->RXFSYSLOCK = + CANXL_RXFIFO_CONTROL_RXFSYSLOCK_SYSLOCK_MASK; + } +} + +/* Get the RxFiFO filter matched with the received RxFIFO message queue */ +static inline int can_nxp_s32_get_rx_fifo_filter(struct can_nxp_s32_data *data) +{ + int alloc = -ENOSPC; + uint32_t mask; + + for (int filter_id = 0; filter_id < CONFIG_CAN_NXP_S32_MAX_RX; filter_id++) { + mask = data->rx_fifo_filter[filter_id].idAddrFilterL; + + if (mask == 0) { + continue; + } + + if ((data->rx_fifo[0].Header.Id & mask) == + (data->rx_fifo_filter[filter_id].idAddrFilterH & mask)) { + alloc = filter_id; + break; + } + } + + return alloc; +} +#endif + static int can_nxp_s32_start(const struct device *dev) { const struct can_nxp_s32_config *config = dev->config; @@ -404,9 +474,20 @@ static void can_nxp_s32_remove_rx_filter(const struct device *dev, int filter_id k_mutex_lock(&data->rx_mutex, K_FOREVER); if (atomic_test_and_clear_bit(data->rx_allocs, filter_id)) { +#ifdef CONFIG_CAN_NXP_S32_RX_FIFO + data->rx_fifo_filter[mb_indx].idAddrFilterL = 0; + data->rx_fifo_filter[mb_indx].idAddrFilterH = 0; + + Canexcel_Ip_EnterFreezeMode(config->instance); + + can_nxp_s32_config_rx_fifo_filter(dev, mb_indx); + + Canexcel_Ip_ExitFreezeMode(config->instance); +#else if (can_nxp_s32_abort_msg(config, mb_indx)) { LOG_ERR("Can't abort message !"); }; +#endif data->rx_cbs[filter_id].function = NULL; data->rx_cbs[filter_id].arg = NULL; @@ -458,24 +539,39 @@ static int can_nxp_s32_add_rx_filter(const struct device *dev, data->rx_cbs[alloc].arg = user_data; data->rx_cbs[alloc].filter = *filter; - data->rx_cbs[alloc].rx_info = (Canexcel_Ip_DataInfoType) { - .frame = !!(filter->flags & CAN_FILTER_FDF) ? - CANEXCEL_FD_FRAME : CANEXCEL_CLASIC_FRAME, - .idType = !!(filter->flags & CAN_FILTER_IDE) ? - CANEXCEL_MSG_ID_EXT : CANEXCEL_MSG_ID_STD, - .dataLength = CAN_NXP_S32_DATA_LENGTH, - }; - /* Set Rx Mb individual mask for */ mb_indx = ALLOC_IDX_TO_RXMB_IDX(alloc); if (!!(filter->flags & CAN_FILTER_IDE)) { - mask = (filter->mask & CANXL_IP_ID_EXT_MASK); + mask = filter->mask & CANXL_IP_ID_EXT_MASK; } else { - mask = ((filter->mask << CANXL_IP_ID_STD_SHIFT) & CANXL_IP_ID_STD_MASK); + mask = (filter->mask << CANXL_IP_ID_STD_SHIFT) & CANXL_IP_ID_STD_MASK; } Canexcel_Ip_EnterFreezeMode(config->instance); +#ifdef CONFIG_CAN_NXP_S32_RX_FIFO + uint32_t filter_id; + + if (!!(filter->flags & CAN_FILTER_IDE)) { + filter_id = filter->id & CANXL_IP_ID_EXT_MASK; + } else { + filter_id = (filter->id << CANXL_IP_ID_STD_SHIFT) & CANXL_IP_ID_STD_MASK; + } + + data->rx_fifo_filter[mb_indx].filterType = CANEXCEL_IP_RX_FIFO_MASK_FILTER; + data->rx_fifo_filter[mb_indx].idAddrFilterL = mask; + data->rx_fifo_filter[mb_indx].idAddrFilterH = filter_id; + + can_nxp_s32_config_rx_fifo_filter(dev, mb_indx); +#else + data->rx_cbs[alloc].rx_info = (Canexcel_Ip_DataInfoType) { + .frame = !!(filter->flags & CAN_FILTER_FDF) ? + CANEXCEL_FD_FRAME : CANEXCEL_CLASIC_FRAME, + .idType = !!(filter->flags & CAN_FILTER_IDE) ? + CANEXCEL_MSG_ID_EXT : CANEXCEL_MSG_ID_STD, + .dataLength = CAN_NXP_S32_DATA_LENGTH, + }; + Canexcel_Ip_SetRxIndividualMask(config->instance, mb_indx, data->rx_cbs[alloc].rx_info.frame, mask); @@ -483,6 +579,7 @@ static int can_nxp_s32_add_rx_filter(const struct device *dev, &data->rx_cbs[alloc].rx_info); Canexcel_Ip_ReceiveFD(config->instance, mb_indx, &data->rx_msg[alloc], FALSE); +#endif Canexcel_Ip_ExitFreezeMode(config->instance); @@ -775,7 +872,6 @@ static void can_nxp_s32_ctrl_callback(const struct device *dev, struct can_frame frame = {0}; can_tx_callback_t tx_func; can_rx_callback_t rx_func; - Canexcel_Ip_StatusType status; int alloc; if (eventType == CANEXCEL_EVENT_TX_COMPLETE) { @@ -786,6 +882,33 @@ static void can_nxp_s32_ctrl_callback(const struct device *dev, tx_func(dev, 0, data->tx_cbs[alloc].arg); k_sem_give(&data->tx_allocs_sem); } +#ifdef CONFIG_CAN_NXP_S32_RX_FIFO + } else if (eventType == CANEXCEL_EVENT_RXFIFO_COMPLETE) { + alloc = can_nxp_s32_get_rx_fifo_filter(data); + + if (alloc != -ENOSPC) { + rx_func = data->rx_cbs[alloc].function; + if (atomic_test_bit(data->rx_allocs, alloc)) { + nxp_s32_msg_data_to_zcan_frame(data->rx_fifo[0], &frame); + + LOG_DBG("%s: Received %d bytes Rx FiFo %d, " + "Rx Id: 0x%x, " + "Id type: %s %s %s %s", + dev->name, can_dlc_to_bytes(frame.dlc), + alloc, frame.id, + !!(frame.flags & CAN_FRAME_IDE) ? + "extended" : "standard", + !!(frame.flags & CAN_FRAME_RTR) ? "RTR" : "", + !!(frame.flags & CAN_FRAME_FDF) ? "FD frame" : "", + !!(frame.flags & CAN_FRAME_BRS) ? "BRS" : ""); + + rx_func(dev, &frame, data->rx_cbs[alloc].arg); + } + } + + /* Pop 1 (= RXFSYSPOP + 1) received RxFIFO message queue */ + config->base_rx_fifo_ctrl->RXFSYSPOP = 0; +#else } else if (eventType == CANEXCEL_EVENT_RX_COMPLETE) { alloc = RX_MBIDX_TO_ALLOC_IDX(buffidx); rx_func = data->rx_cbs[alloc].function; @@ -805,12 +928,12 @@ static void can_nxp_s32_ctrl_callback(const struct device *dev, rx_func(dev, &frame, data->rx_cbs[alloc].arg); - status = Canexcel_Ip_ReceiveFD(config->instance, buffidx, - &data->rx_msg[alloc], FALSE); - if (status != CANEXCEL_STATUS_SUCCESS) { + if (Canexcel_Ip_ReceiveFD(config->instance, buffidx, + &data->rx_msg[alloc], FALSE) != CANEXCEL_STATUS_SUCCESS) { LOG_ERR("MB %d is not ready for receiving next message", buffidx); } } +#endif } } @@ -925,6 +1048,13 @@ static int can_nxp_s32_init(const struct device *dev) CanXL_SetErrIntCmd(config->base_sic, CANXL_INT_ERR, TRUE); CanXL_SetErrIntCmd(config->base_sic, CANXL_INT_BUSOFF, TRUE); CanXL_SetErrIntCmd(config->base_sic, CANXL_INT_PASIVE_ERR, TRUE); +#ifdef CONFIG_CAN_NXP_S32_RX_FIFO + CanXL_SetErrIntCmd(config->base_sic, CANXL_INT_RXFIFO_OVER, TRUE); + + /* Configure number of ID acceptance filters*/ + config->base_rx_fifo->AFCFG = + CANXL_RXFIFO_AFCFG_ACPTID(CONFIG_CAN_NXP_S32_MAX_RX - 1); +#endif config->irq_config_func(); @@ -1063,23 +1193,45 @@ static const struct can_driver_api can_nxp_s32_driver_api = { CAN_NXP_S32_ERR_CALLBACK(n) \ CAN_NXP_S32_IRQ_CONFIG(n) \ PINCTRL_DT_INST_DEFINE(n); \ + \ + __nocache Canexcel_Ip_StateType can_nxp_s32_state##n; \ + __nocache Canexcel_TxFdMsgType tx_msg##n[CONFIG_CAN_NXP_S32_MAX_TX]; \ + IF_DISABLED(CONFIG_CAN_NXP_S32_RX_FIFO, \ + (__nocache Canexcel_RxFdMsg rx_msg_##n[CONFIG_CAN_NXP_S32_MAX_RX];)) \ + IF_ENABLED(CONFIG_CAN_NXP_S32_RX_FIFO, \ + (__nocache Canexcel_RxFdMsg rx_fifo_##n[CAN_NXP_S32_RX_FIFO_DEPTH]; \ + static Canexcel_Ip_RxFifoFilterID_ADDR \ + rx_fifo_filter##n[CONFIG_CAN_NXP_S32_MAX_RX];)) \ Canexcel_Ip_ConfigType can_nxp_s32_default_config##n = { \ - .rx_mbdesc = (uint8)CONFIG_CAN_NXP_S32_MAX_RX, \ + .rx_mbdesc = (uint8)IS_ENABLED(CONFIG_CAN_NXP_S32_RX_FIFO) ? \ + 0 : CONFIG_CAN_NXP_S32_MAX_RX, \ .tx_mbdesc = (uint8)CONFIG_CAN_NXP_S32_MAX_TX, \ .CanxlMode = CANEXCEL_LISTEN_ONLY_MODE, \ .fd_enable = (boolean)CAN_NXP_S32_FD_MODE, \ .bitRateSwitch = (boolean)CAN_NXP_S32_BRS, \ .ctrlOptions = (uint32)CAN_NXP_S32_CTRL_OPTIONS, \ .Callback = nxp_s32_can_##n##_ctrl_callback, \ - .ErrorCallback = nxp_s32_can_##n##_err_callback \ + .ErrorCallback = nxp_s32_can_##n##_err_callback, \ + IF_ENABLED(CONFIG_CAN_NXP_S32_RX_FIFO, \ + (.is_rx_fifo_needed = (boolean)TRUE, \ + .pRxFifoConfig = { \ + .Rx_Fifo_Depth = CAN_NXP_S32_RX_FIFO_DEPTH, \ + .Rx_Fifo_Watermark = CAN_NXP_S32_RX_FIFO_WATERMARK, \ + .Rx_Fifo_Msg_Size = CAN_NXP_S32_DATA_LENGTH, \ + .Rx_Fifo_KeepLast = (boolean)FALSE, \ + .isPolling = (boolean)FALSE, \ + .MsgBuffersPtr = (uint32 *)rx_fifo_##n, \ + },)) \ }; \ - __nocache Canexcel_Ip_StateType can_nxp_s32_state##n; \ - __nocache Canexcel_TxFdMsgType tx_msg##n[CONFIG_CAN_NXP_S32_MAX_TX]; \ - __nocache Canexcel_RxFdMsg rx_msg_##n[CONFIG_CAN_NXP_S32_MAX_RX]; \ static struct can_nxp_s32_data can_nxp_s32_data_##n = { \ .can_state = (Canexcel_Ip_StateType *)&can_nxp_s32_state##n, \ .tx_msg = tx_msg##n, \ - .rx_msg = rx_msg_##n, \ + IF_DISABLED(CONFIG_CAN_NXP_S32_RX_FIFO, \ + (.rx_msg = rx_msg_##n,)) \ + IF_ENABLED(CONFIG_CAN_NXP_S32_RX_FIFO, \ + (.rx_fifo = rx_fifo_##n, \ + .rx_fifo_filter = \ + (Canexcel_Ip_RxFifoFilterID_ADDR *)&rx_fifo_filter##n,))\ }; \ static struct can_nxp_s32_config can_nxp_s32_config_##n = { \ .base_sic = (CANXL_SIC_Type *)DT_INST_REG_ADDR_BY_NAME(n, sic), \ @@ -1087,6 +1239,11 @@ static const struct can_driver_api can_nxp_s32_driver_api = { DT_INST_REG_ADDR_BY_NAME(n, grp_ctrl), \ .base_dsc_ctrl = (CANXL_DSC_CONTROL_Type *) \ DT_INST_REG_ADDR_BY_NAME(n, dsc_ctrl), \ + IF_ENABLED(CONFIG_CAN_NXP_S32_RX_FIFO, \ + (.base_rx_fifo = (CANXL_RXFIFO_Type *) \ + DT_INST_REG_ADDR_BY_NAME(n, rx_fifo), \ + .base_rx_fifo_ctrl = (CANXL_RXFIFO_CONTROL_Type *) \ + DT_INST_REG_ADDR_BY_NAME(n, rx_fifo_ctrl),)) \ .instance = CAN_NXP_S32_HW_INSTANCE(n), \ .clock_dev = DEVICE_DT_GET(DT_INST_CLOCKS_CTLR(n)), \ .clock_subsys = (clock_control_subsys_t) \ diff --git a/dts/arm/nxp/nxp_s32z27x_r52.dtsi b/dts/arm/nxp/nxp_s32z27x_r52.dtsi index 4f92c8ca71a..920f519da0f 100644 --- a/dts/arm/nxp/nxp_s32z27x_r52.dtsi +++ b/dts/arm/nxp/nxp_s32z27x_r52.dtsi @@ -1,5 +1,5 @@ /* - * Copyright 2022-2023 NXP + * Copyright 2022-2024 NXP * * SPDX-License-Identifier: Apache-2.0 */ @@ -693,10 +693,12 @@ can0: can@4741b000 { compatible = "nxp,s32-canxl"; - reg = <0x4741b000 0x4000>, - <0x47426000 0x4000>, - <0x47424000 0x4000>; - reg-names = "sic", "grp_ctrl", "dsc_ctrl"; + reg = <0x4741b000 0x1000>, + <0x47426000 0x1000>, + <0x47424000 0x1000>, + <0x47423000 0x1000>, + <0x47425000 0x1000>; + reg-names = "sic", "grp_ctrl", "dsc_ctrl", "rx_fifo", "rx_fifo_ctrl"; status = "disabled"; interrupts = , ; @@ -706,10 +708,12 @@ can1: can@4751b000 { compatible = "nxp,s32-canxl"; - reg = <0x4751b000 0x4000>, - <0x47526000 0x4000>, - <0x47524000 0x4000>; - reg-names = "sic", "grp_ctrl", "dsc_ctrl"; + reg = <0x4751b000 0x1000>, + <0x47526000 0x1000>, + <0x47524000 0x1000>, + <0x47523000 0x1000>, + <0x47525000 0x1000>; + reg-names = "sic", "grp_ctrl", "dsc_ctrl", "rx_fifo", "rx_fifo_ctrl"; status = "disabled"; interrupts = , ; From 923201abc546293aa6710b57b0c451471bbc3b6a Mon Sep 17 00:00:00 2001 From: Ian Morris Date: Fri, 15 Dec 2023 13:47:33 -0800 Subject: [PATCH 2320/3723] drivers: pinctrl: ra: fix write-protect register access The write protect register (PWPR) found on RA Microcontrollers is an 8-bit register at an odd address. It was being accessed using a pointer to a uint32_t which causes a fault on some devices in the series. Signed-off-by: Ian Morris --- drivers/pinctrl/pinctrl_ra.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/drivers/pinctrl/pinctrl_ra.c b/drivers/pinctrl/pinctrl_ra.c index 54aa881748c..89f8a41d519 100644 --- a/drivers/pinctrl/pinctrl_ra.c +++ b/drivers/pinctrl/pinctrl_ra.c @@ -28,14 +28,14 @@ static inline void pinctrl_ra_write_PmnFPS(size_t port, size_t pin, uint32_t val sys_write32(value, DT_INST_REG_ADDR_BY_NAME(0, pfs) + (port * PIN_NUM + pin) * 4); } -static inline uint32_t pinctrl_ra_read_PMISC_PWPR(size_t port, size_t pin) +static inline uint8_t pinctrl_ra_read_PMISC_PWPR(size_t port, size_t pin) { - return sys_read32(DT_INST_REG_ADDR_BY_NAME(0, pmisc_pwpr)); + return sys_read8(DT_INST_REG_ADDR_BY_NAME(0, pmisc_pwpr)); } -static inline void pinctrl_ra_write_PMISC_PWPR(uint32_t value) +static inline void pinctrl_ra_write_PMISC_PWPR(uint8_t value) { - sys_write32(value, DT_INST_REG_ADDR_BY_NAME(0, pmisc_pwpr)); + sys_write8(value, DT_INST_REG_ADDR_BY_NAME(0, pmisc_pwpr)); } static void pinctrl_ra_configure_pfs(const pinctrl_soc_pin_t *pinc) From a0ac2faf9bde45b176f1e8b315ffb1b8a9096166 Mon Sep 17 00:00:00 2001 From: Anas Nashif Date: Tue, 16 Jan 2024 12:46:57 +0000 Subject: [PATCH 2321/3723] intel_adsp: ace: enable power domain Enable power domain drivers for this soc series as it is now needed in the boot process. Signed-off-by: Anas Nashif --- soc/xtensa/intel_adsp/ace/Kconfig.defconfig.series | 3 +++ 1 file changed, 3 insertions(+) diff --git a/soc/xtensa/intel_adsp/ace/Kconfig.defconfig.series b/soc/xtensa/intel_adsp/ace/Kconfig.defconfig.series index 198f0b35f70..5057e5cb16a 100644 --- a/soc/xtensa/intel_adsp/ace/Kconfig.defconfig.series +++ b/soc/xtensa/intel_adsp/ace/Kconfig.defconfig.series @@ -14,6 +14,9 @@ config SOC_TOOLCHAIN_NAME config SMP default y +config POWER_DOMAIN + default y + # MTL leaves the upper mapping in the same spot as cAVS, but moves the # lower one inexplicably. config XTENSA_UNCACHED_REGION From 897553af179e1a84e4d31dc8bc62a5e598256a78 Mon Sep 17 00:00:00 2001 From: Tom Burdick Date: Fri, 12 Jan 2024 13:18:00 -0600 Subject: [PATCH 2322/3723] logging: Remove hda log backend The HDA log backend has been buggy for some time, and the fixes are well understood. The issue with HDA log as it is implemented today means there are concurrency and ISR issues where it can deadlock. The fixes are effectively dropping the usage of ipc to communicate status, using polling on the hda stream, and having a formatter per call context (cores + isr) when log mode immediate is enabled to fix log mangling. However it was found this had a lot of unintentional side effects that made it difficult to make progress on when it came to changes of the host side python tooling. Meanwhile the feature has sat unused for nearly a year. Remove it, and it can always be revisited in the future if something like it happens to be needed. Signed-off-by: Tom Burdick --- subsys/logging/Kconfig.formatting | 2 +- subsys/logging/backends/CMakeLists.txt | 5 - subsys/logging/backends/Kconfig | 1 - subsys/logging/backends/Kconfig.adsp_hda | 52 --- .../logging/backends/log_backend_adsp_hda.c | 379 ------------------ .../boards/intel_adsp/hda_log/CMakeLists.txt | 7 - tests/boards/intel_adsp/hda_log/prj.conf | 12 - tests/boards/intel_adsp/hda_log/src/logger.c | 61 --- tests/boards/intel_adsp/hda_log/src/tests.h | 21 - tests/boards/intel_adsp/hda_log/testcase.yaml | 21 - 10 files changed, 1 insertion(+), 560 deletions(-) delete mode 100644 subsys/logging/backends/Kconfig.adsp_hda delete mode 100644 subsys/logging/backends/log_backend_adsp_hda.c delete mode 100644 tests/boards/intel_adsp/hda_log/CMakeLists.txt delete mode 100644 tests/boards/intel_adsp/hda_log/prj.conf delete mode 100644 tests/boards/intel_adsp/hda_log/src/logger.c delete mode 100644 tests/boards/intel_adsp/hda_log/src/tests.h delete mode 100644 tests/boards/intel_adsp/hda_log/testcase.yaml diff --git a/subsys/logging/Kconfig.formatting b/subsys/logging/Kconfig.formatting index 44b9244e296..478a7af9a11 100644 --- a/subsys/logging/Kconfig.formatting +++ b/subsys/logging/Kconfig.formatting @@ -166,7 +166,7 @@ config LOG_BACKEND_FORMAT_TIMESTAMP bool "Timestamp formatting in the backend" depends on LOG_BACKEND_UART || LOG_BACKEND_NATIVE_POSIX || LOG_BACKEND_RTT \ || LOG_BACKEND_SWO || LOG_BACKEND_XTENSA_SIM || LOG_BACKEND_FS \ - || LOG_BACKEND_ADSP || LOG_BACKEND_ADSP_HDA || LOG_BACKEND_ADSP_MTRACE + || LOG_BACKEND_ADSP || LOG_BACKEND_ADSP_MTRACE default y help When enabled timestamp is formatted to hh:mm:ss:ms,us. diff --git a/subsys/logging/backends/CMakeLists.txt b/subsys/logging/backends/CMakeLists.txt index d8bdbe92860..5c631ca524f 100644 --- a/subsys/logging/backends/CMakeLists.txt +++ b/subsys/logging/backends/CMakeLists.txt @@ -5,11 +5,6 @@ zephyr_sources_ifdef( log_backend_adsp.c ) -zephyr_sources_ifdef( - CONFIG_LOG_BACKEND_ADSP_HDA - log_backend_adsp_hda.c -) - zephyr_sources_ifdef( CONFIG_LOG_BACKEND_ADSP_MTRACE log_backend_adsp_mtrace.c diff --git a/subsys/logging/backends/Kconfig b/subsys/logging/backends/Kconfig index 356291b5686..545847d103f 100644 --- a/subsys/logging/backends/Kconfig +++ b/subsys/logging/backends/Kconfig @@ -4,7 +4,6 @@ menu "Backends" rsource "Kconfig.adsp" -rsource "Kconfig.adsp_hda" rsource "Kconfig.adsp_mtrace" rsource "Kconfig.ble" rsource "Kconfig.efi_console" diff --git a/subsys/logging/backends/Kconfig.adsp_hda b/subsys/logging/backends/Kconfig.adsp_hda deleted file mode 100644 index e384f43222e..00000000000 --- a/subsys/logging/backends/Kconfig.adsp_hda +++ /dev/null @@ -1,52 +0,0 @@ -# Copyright (c) 2021 Nordic Semiconductor ASA -# SPDX-License-Identifier: Apache-2.0 - -config LOG_BACKEND_ADSP_HDA - bool "Intel ADSP HDA backend" - depends on SOC_FAMILY_INTEL_ADSP && DMA && DMA_INTEL_ADSP_HDA_HOST_OUT - select LOG_OUTPUT - help - Provide a logging backend which writes to a buffer and - periodically flushes to hardware using ringbuffer like - semantics provided by DMA_INTEL_ADSP_HDA. - -if LOG_BACKEND_ADSP_HDA - -backend = ADSP_HDA -backend-str = adsp_hda -source "subsys/logging/Kconfig.template.log_format_config" - -config LOG_BACKEND_ADSP_HDA_SIZE - int "Size of ring buffer" - range 128 8192 - default 4096 - help - Sets the ring buffer size cAVS HDA uses for logging. Effectively - determines how many log messages may be written to in a period of time. - The period of time is decided by how often to inform the hardware of - writes to the buffer. - -config LOG_BACKEND_ADSP_HDA_FLUSH_TIME - int "Time in milliseconds to periodically flush writes to hardware" - range 1 10000 - default 500 - help - The Intel ADSP HDA backend periodically writes out its buffer contents - to hardware by informing the DMA hardware the contents of the ring - buffer. - -config LOG_BACKEND_ADSP_HDA_CAVSTOOL - bool "Log backend is to be used with cavstool" - help - Use cavstool understood IPC messages to inform setup and logging of - HDA messages. - -config LOG_BACKEND_ADSP_HDA_PADDING - bool "Log backend should pad the buffer with \0 characters when flushing" - help - HDA requires transfers be 128 byte aligned such that a partial message may - never make it across unless padded with \0 characters to the next 128 byte - aligned address. This may or may not work depending on the log format - being used but should certainly work with text based logging. - -endif # LOG_BACKEND_ADSP_HDA diff --git a/subsys/logging/backends/log_backend_adsp_hda.c b/subsys/logging/backends/log_backend_adsp_hda.c deleted file mode 100644 index 8e9506c1daa..00000000000 --- a/subsys/logging/backends/log_backend_adsp_hda.c +++ /dev/null @@ -1,379 +0,0 @@ -/* - * Copyright (c) 2022 Intel Corporation - * - * SPDX-License-Identifier: Apache-2.0 - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -static uint32_t log_format_current = CONFIG_LOG_BACKEND_ADSP_HDA_OUTPUT_DEFAULT; -static const struct device *const hda_log_dev = - DEVICE_DT_GET(DT_NODELABEL(hda_host_in)); -static uint32_t hda_log_chan; - -/* - * HDA requires 128 byte aligned data and 128 byte aligned transfers. - */ -#define ALIGNMENT DMA_BUF_ADDR_ALIGNMENT(DT_NODELABEL(hda_host_in)) -static __aligned(ALIGNMENT) uint8_t hda_log_buf[CONFIG_LOG_BACKEND_ADSP_HDA_SIZE]; -static volatile uint32_t hda_log_buffered; -static struct k_timer hda_log_timer; -static adsp_hda_log_hook_t hook; -static uint32_t write_idx; -static struct k_spinlock hda_log_lock; - -/* atomic bit flags for state */ -#define HDA_LOG_DMA_READY 0 -#define HDA_LOG_PANIC_MODE 1 -static atomic_t hda_log_flags; - - -/** - * Flush the buffered log to the HDA stream - * - * If @kconfig{CONFIG_LOG_BACKEND_ADSP_HDA_PADDING} is enabled - * the buffer is extended with '\0' characters to align the buffer - * to 128 bytes. - */ -static uint32_t hda_log_flush(void) -{ - if (hda_log_buffered == 0) { - return 0; - } - - uint32_t nearest128 = hda_log_buffered & ~((128) - 1); - -#ifdef CONFIG_LOG_BACKEND_ADSP_HDA_PADDING - if (nearest128 != hda_log_buffered) { - uint32_t next128 = nearest128 + 128; - uint32_t padding = next128 - hda_log_buffered; - - for (int i = 0; i < padding; i++) { - hda_log_buf[write_idx] = '\0'; - hda_log_buffered++; - write_idx++; - } - nearest128 = hda_log_buffered & ~((128) - 1); - } - __ASSERT(hda_log_buffered == nearest128, - "Expected flush length to be 128 byte aligned"); -#endif - -#if !(IS_ENABLED(CONFIG_KERNEL_COHERENCE)) - sys_cache_data_flush_range(hda_log_buf, CONFIG_LOG_BACKEND_ADSP_HDA_SIZE); -#endif - dma_reload(hda_log_dev, hda_log_chan, 0, 0, nearest128); - - hda_log_buffered = hda_log_buffered - nearest128; - - return nearest128; -} - -static int hda_log_out(uint8_t *data, size_t length, void *ctx) -{ - int ret; - bool do_log_flush; - struct dma_status status; - - k_spinlock_key_t key = k_spin_lock(&hda_log_lock); - - /* Defaults when DMA not yet initialized */ - uint32_t dma_free = sizeof(hda_log_buf); - uint32_t write_pos = 0; - - if (atomic_test_bit(&hda_log_flags, HDA_LOG_DMA_READY)) { - ret = dma_get_status(hda_log_dev, hda_log_chan, &status); - if (ret != 0) { - ret = length; - goto out; - } - - /* The hardware tells us what space we have available, and where to - * start writing. If the buffer is full we have no space. - */ - if (status.free <= 0) { - ret = length; - goto out; - } - - dma_free = status.free; - write_pos = status.write_position; - } - - /* Account for buffered writes since last dma_reload - * - * No underflow should be possible here, status.free is the apparent - * free space in the buffer from the DMA's read/write positions. - * When dma_reload is called status.free may be reduced by - * the nearest 128 divisible value of hda_log_buffered, - * where hda_log_buffered is then subtracted by the same amount. - * After which status.free should only increase in value. - * - * Assert this trueth though, just in case. - */ - __ASSERT_NO_MSG(dma_free > hda_log_buffered); - uint32_t available = dma_free - hda_log_buffered; - - /* If there isn't enough space for the message there's an overflow */ - if (available < length) { - ret = 0; - goto out; - } - - /* Copy over the message to the buffer */ - write_idx = write_pos + hda_log_buffered; - - if (write_idx > sizeof(hda_log_buf)) { - write_idx -= sizeof(hda_log_buf); - } - - size_t copy_len = (write_idx + length) < sizeof(hda_log_buf) ? length - : sizeof(hda_log_buf) - write_idx; - - memcpy(&hda_log_buf[write_idx], data, copy_len); - write_idx += copy_len; - - /* There may be a wrapped copy */ - size_t wrap_copy_len = length - copy_len; - - if (wrap_copy_len != 0) { - memcpy(&hda_log_buf[0], &data[copy_len], wrap_copy_len); - write_idx = wrap_copy_len; - } - - ret = length; - hda_log_buffered += length; - - uint32_t written = 0; - -out: - /* If DMA_READY changes from unset to set during this call, that is - * perfectly acceptable. The default values for write_pos and dma_free - * are the correct values if that occurs. - */ - do_log_flush = ((hda_log_buffered > sizeof(hda_log_buf)/2) || - atomic_test_bit(&hda_log_flags, HDA_LOG_PANIC_MODE)) - && atomic_test_bit(&hda_log_flags, HDA_LOG_DMA_READY); - - /* Flush if there's a hook set AND dma is ready */ - if (do_log_flush && hook != NULL) { - written = hda_log_flush(); - } - - k_spin_unlock(&hda_log_lock, key); - - /* The hook may have log calls and needs to be done outside of the spin - * lock to avoid recursion on the spin lock (deadlocks) in cases of - * direct logging. - */ - if (hook != NULL && written > 0) { - hook(written); - } - - return ret; -} -/** - * 128 bytes is the smallest transferrable size for HDA so use that - * and encompass almost all log lines in the formatter before flushing - * and memcpy'ing to the HDA buffer. - */ -#define LOG_BUF_SIZE 128 -static uint8_t log_buf[LOG_BUF_SIZE]; -LOG_OUTPUT_DEFINE(log_output_adsp_hda, hda_log_out, log_buf, LOG_BUF_SIZE); - -static void hda_log_periodic(struct k_timer *tm) -{ - ARG_UNUSED(tm); - - uint32_t written = 0; - k_spinlock_key_t key = k_spin_lock(&hda_log_lock); - - - if (hook != NULL) { - written = hda_log_flush(); - } - - - /* The hook may have log calls and needs to be done outside of the spin - * lock to avoid recursion on the spin lock (deadlocks) in cases of - * direct logging. - */ - if (hook != NULL && written > 0) { - hook(written); - } - - k_spin_unlock(&hda_log_lock, key); -} - -static inline void dropped(const struct log_backend *const backend, - uint32_t cnt) -{ - ARG_UNUSED(backend); - - if (IS_ENABLED(CONFIG_LOG_DICTIONARY_SUPPORT)) { - log_dict_output_dropped_process(&log_output_adsp_hda, cnt); - } else { - log_output_dropped_process(&log_output_adsp_hda, cnt); - } -} - -static void panic(struct log_backend const *const backend) -{ - ARG_UNUSED(backend); - - /* will immediately flush all future writes once set */ - atomic_set_bit(&hda_log_flags, HDA_LOG_PANIC_MODE); - - /* flushes the log queue */ - log_backend_std_panic(&log_output_adsp_hda); -} - -static int format_set(const struct log_backend *const backend, uint32_t log_type) -{ - ARG_UNUSED(backend); - - log_format_current = log_type; - - return 0; -} - -static volatile uint32_t counter; - -static void process(const struct log_backend *const backend, - union log_msg_generic *msg) -{ - ARG_UNUSED(backend); - uint32_t flags = log_backend_std_get_flags(); - - log_format_func_t log_output_func = log_format_func_t_get(log_format_current); - - log_output_func(&log_output_adsp_hda, &msg->log, flags); -} - -/** - * Lazily initialized, while the DMA may not be setup we continue - * to buffer log messages untilt he buffer is full. - */ -static void init(const struct log_backend *const backend) -{ - ARG_UNUSED(backend); - - hda_log_buffered = 0; -} - -const struct log_backend_api log_backend_adsp_hda_api = { - .process = process, - .dropped = IS_ENABLED(CONFIG_LOG_MODE_IMMEDIATE) ? NULL : dropped, - .panic = panic, - .format_set = format_set, - .init = init, -}; - -LOG_BACKEND_DEFINE(log_backend_adsp_hda, log_backend_adsp_hda_api, true); - -void adsp_hda_log_init(adsp_hda_log_hook_t fn, uint32_t channel) -{ - hook = fn; - - int res; - - __ASSERT(device_is_ready(hda_log_dev), "DMA device is not ready"); - - hda_log_chan = dma_request_channel(hda_log_dev, &channel); - __ASSERT(hda_log_chan >= 0, "No valid DMA channel"); - __ASSERT(hda_log_chan == channel, "Not requested channel"); - - hda_log_buffered = 0; - - /* configure channel */ - struct dma_block_config hda_log_dma_blk_cfg = { - .block_size = CONFIG_LOG_BACKEND_ADSP_HDA_SIZE, - .source_address = (uint32_t)(uintptr_t)&hda_log_buf, - }; - - struct dma_config hda_log_dma_cfg = { - .channel_direction = MEMORY_TO_HOST, - .block_count = 1, - .head_block = &hda_log_dma_blk_cfg, - .source_data_size = 4, - }; - - res = dma_config(hda_log_dev, hda_log_chan, &hda_log_dma_cfg); - __ASSERT(res == 0, "DMA config failed"); - - res = dma_start(hda_log_dev, hda_log_chan); - __ASSERT(res == 0, "DMA start failed"); - - atomic_set_bit(&hda_log_flags, HDA_LOG_DMA_READY); - - k_timer_init(&hda_log_timer, hda_log_periodic, NULL); - k_timer_start(&hda_log_timer, - K_MSEC(CONFIG_LOG_BACKEND_ADSP_HDA_FLUSH_TIME), - K_MSEC(CONFIG_LOG_BACKEND_ADSP_HDA_FLUSH_TIME)); - -} - -#ifdef CONFIG_LOG_BACKEND_ADSP_HDA_CAVSTOOL - -#include -#include - -#define CHANNEL 6 -#define IPC_TIMEOUT K_MSEC(1500) - -static inline void hda_ipc_msg(const struct device *dev, uint32_t data, - uint32_t ext, k_timeout_t timeout) -{ - int ret = intel_adsp_ipc_send_message_sync(dev, data, ext, timeout); - - __ASSERT(!ret, "Unexpected ipc send message failure, error code: %d", - ret); -} - - -void adsp_hda_log_cavstool_hook(uint32_t written) -{ - /* We *must* send this, but we may be in a timer ISR, so we are - * forced into a retry loop without timeouts and such. - */ - int ret = -1; - - /* Send IPC message notifying log data has been written */ - do { - ret = intel_adsp_ipc_send_message(INTEL_ADSP_IPC_HOST_DEV, IPCCMD_HDA_PRINT, - (written << 8) | CHANNEL); - if (ret == -ESHUTDOWN) { - return; - } - } while (ret); - - /* Wait for confirmation log data has been received */ - while (!intel_adsp_ipc_is_complete(INTEL_ADSP_IPC_HOST_DEV)) - ; -} - -int adsp_hda_log_cavstool_init(void) -{ - - hda_ipc_msg(INTEL_ADSP_IPC_HOST_DEV, IPCCMD_HDA_RESET, CHANNEL, IPC_TIMEOUT); - hda_ipc_msg(INTEL_ADSP_IPC_HOST_DEV, IPCCMD_HDA_CONFIG, - CHANNEL | (CONFIG_LOG_BACKEND_ADSP_HDA_SIZE << 8), IPC_TIMEOUT); - adsp_hda_log_init(adsp_hda_log_cavstool_hook, CHANNEL); - hda_ipc_msg(INTEL_ADSP_IPC_HOST_DEV, IPCCMD_HDA_START, CHANNEL, IPC_TIMEOUT); - - return 0; -} - -SYS_INIT(adsp_hda_log_cavstool_init, POST_KERNEL, 99); - -#endif /* CONFIG_LOG_BACKEND_ADSP_HDA_CAVSTOOL */ diff --git a/tests/boards/intel_adsp/hda_log/CMakeLists.txt b/tests/boards/intel_adsp/hda_log/CMakeLists.txt deleted file mode 100644 index 237186213d0..00000000000 --- a/tests/boards/intel_adsp/hda_log/CMakeLists.txt +++ /dev/null @@ -1,7 +0,0 @@ -# SPDX-License-Identifier: Apache-2.0 - -cmake_minimum_required(VERSION 3.20.0) -find_package(Zephyr REQUIRED HINTS $ENV{ZEPHYR_BASE}) -project(intel_adsp_hda_log) - -target_sources(app PRIVATE src/logger.c) diff --git a/tests/boards/intel_adsp/hda_log/prj.conf b/tests/boards/intel_adsp/hda_log/prj.conf deleted file mode 100644 index 2fd4793b5d9..00000000000 --- a/tests/boards/intel_adsp/hda_log/prj.conf +++ /dev/null @@ -1,12 +0,0 @@ -CONFIG_ZTEST=y -CONFIG_DMA=y -CONFIG_ASSERT=y -CONFIG_LOG=y -CONFIG_LOG_MODE_IMMEDIATE=y -CONFIG_LOG_BACKEND_ADSP=n -CONFIG_LOG_BACKEND_ADSP_HDA=y -CONFIG_LOG_BACKEND_ADSP_HDA_SIZE=2048 -CONFIG_LOG_BACKEND_ADSP_HDA_PADDING=y -CONFIG_LOG_BACKEND_ADSP_HDA_CAVSTOOL=y -CONFIG_LOG_BACKEND_ADSP_HDA_FLUSH_TIME=100 -CONFIG_XTENSA_ENABLE_BACKTRACE=n diff --git a/tests/boards/intel_adsp/hda_log/src/logger.c b/tests/boards/intel_adsp/hda_log/src/logger.c deleted file mode 100644 index 38cfcdbf92c..00000000000 --- a/tests/boards/intel_adsp/hda_log/src/logger.c +++ /dev/null @@ -1,61 +0,0 @@ -/* Copyright (c) 2022 Intel Corporation - * SPDX-License-Identifier: Apache-2.0 - */ - -#include -#include -#include -#include -#include -#include -#include -#include "tests.h" - -#include -LOG_MODULE_REGISTER(hda_test, LOG_LEVEL_DBG); - -/* Define a prime length message string (13 bytes long when including the \0 terminator) - * - * This helps ensure most if not all messages are not going to land on a 128 byte boundary - * which is important to test the padding and wrapping feature - */ -#ifdef CONFIG_LOG_PRINTK -#define FMT_STR "TEST:%06d\n" -#else -#define FMT_STR "TEST:%07d" -#endif - -#define FMT_STR_LEN 13 - -/* Now define the number of iterations such that we ensure a large number of wraps - * on the HDA ring. - */ -#define TEST_ITERATIONS ((CONFIG_LOG_BACKEND_ADSP_HDA_SIZE/FMT_STR_LEN)*200) - -ZTEST(intel_adsp_hda_log, test_hda_logger) -{ - TC_PRINT("Testing hda log backend, log buffer size %u, iterations %u\n", - CONFIG_LOG_BACKEND_ADSP_HDA_SIZE, TEST_ITERATIONS); - - /* Wait a moment so the output isn't mangled with the above printk */ - k_msleep(100); - - for (int i = 0; i < TEST_ITERATIONS; i++) { - if (IS_ENABLED(CONFIG_LOG_PRINTK)) { - printk(FMT_STR, i); - } else { - LOG_INF(FMT_STR, i); - } - } - - /* Wait for the flush to happen */ - k_msleep(CONFIG_LOG_BACKEND_ADSP_HDA_FLUSH_TIME + 10); - - /* Test the flush timer works by writing a short string */ - LOG_INF("Timeout flush working if shown"); - - /* Wait again for the flush to happen */ - k_msleep(CONFIG_LOG_BACKEND_ADSP_HDA_FLUSH_TIME + 10); -} - -ZTEST_SUITE(intel_adsp_hda_log, NULL, NULL, NULL, NULL, NULL); diff --git a/tests/boards/intel_adsp/hda_log/src/tests.h b/tests/boards/intel_adsp/hda_log/src/tests.h deleted file mode 100644 index f8186ab0643..00000000000 --- a/tests/boards/intel_adsp/hda_log/src/tests.h +++ /dev/null @@ -1,21 +0,0 @@ -/* Copyright (c) 2022 Intel Corporation - * SPDX-License-Identifier: Apache-2.0 - */ -#ifndef ZEPHYR_TESTS_INTEL_ADSP_TESTS_H -#define ZEPHYR_TESTS_INTEL_ADSP_TESTS_H - -#include -#include -#include -#include -#include - -static inline void hda_ipc_msg(const struct device *dev, uint32_t data, - uint32_t ext, k_timeout_t timeout) -{ - int ret = intel_adsp_ipc_send_message_sync(dev, data, ext, timeout); - - zassert_true(!ret, "Unexpected ipc send message failure, error code: %d", ret); -} - -#endif /* ZEPHYR_TESTS_INTEL_ADSP_TESTS_H */ diff --git a/tests/boards/intel_adsp/hda_log/testcase.yaml b/tests/boards/intel_adsp/hda_log/testcase.yaml deleted file mode 100644 index 5041feb5f1b..00000000000 --- a/tests/boards/intel_adsp/hda_log/testcase.yaml +++ /dev/null @@ -1,21 +0,0 @@ -common: - harness: console - platform_allow: intel_adsp_cavs25 - integration_platforms: - - intel_adsp_cavs25 - harness_config: - type: multi_line - regex: - - "TEST:([0-9]){6,7}" - - "Timeout flush working if shown" -tests: - boards.intel_adsp.hda_log: - timeout: 120 - boards.intel_adsp.hda_log.printk: - timeout: 120 - extra_configs: - - CONFIG_LOG_PRINTK=y - boards.intel_adsp.hda_log.1cpu: - timeout: 120 - extra_configs: - - CONFIG_MP_MAX_NUM_CPUS=1 From 7c0047263aee2d1ac6281a85448b52484ed7ba13 Mon Sep 17 00:00:00 2001 From: Miika Karanki Date: Mon, 15 Jan 2024 12:04:39 +0200 Subject: [PATCH 2323/3723] shell: telnet: Don't close the connection on ENOBUFS error If there's not enough networking buffers at certain moment, they might become available later. So instead of closing connection (and failing assertation) sleep and retry. This avoid the following assertion failure when there's much of data to send: net_pkt: Data buffer (1500) allocation failed. net_tcp: conn: 0x20076024 packet allocation failed, len=1460 shell_telnet: Failed to send -105, shutting down ASSERTION FAIL [err == 0] @ .../subsys/shell/shell_ops.c:416 os: r0/a1: 0x00000004 r1/a2: 0x000001a0 r2/a3: 0x00000004 os: r3/a4: 0x20044380 r12/ip: 0x00001958 r14/lr: 0x080c9027 os: xpsr: 0x41000000 os: Faulting instruction address (r15/pc): 0x0811ed26 os: >>> ZEPHYR FATAL ERROR 4: Kernel panic on CPU 0 os: Current thread: 0x20045100 (shell_telnet) os: Halting system Signed-off-by: Miika Karanki --- subsys/shell/backends/shell_telnet.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/subsys/shell/backends/shell_telnet.c b/subsys/shell/backends/shell_telnet.c index cd6f1184773..17a8683ac9d 100644 --- a/subsys/shell/backends/shell_telnet.c +++ b/subsys/shell/backends/shell_telnet.c @@ -76,7 +76,7 @@ static void telnet_command_send_reply(uint8_t *msg, uint16_t len) ret = net_context_send(sh_telnet->client_ctx, msg, len, telnet_sent_cb, K_FOREVER, NULL); - if (ret == -EAGAIN) { + if (ret == -EAGAIN || ret == -ENOBUFS) { k_sleep(K_MSEC(TELNET_RETRY_SEND_SLEEP_MS)); continue; } @@ -206,7 +206,7 @@ static int telnet_send(void) len, telnet_sent_cb, K_FOREVER, NULL); - if (ret == -EAGAIN) { + if (ret == -EAGAIN || ret == -ENOBUFS) { k_sleep(K_MSEC(TELNET_RETRY_SEND_SLEEP_MS)); continue; } From c55593cca3dcace9d49c7eedebd14fe239ad78ca Mon Sep 17 00:00:00 2001 From: Abderrahmane Jarmouni Date: Mon, 15 Jan 2024 11:28:37 +0100 Subject: [PATCH 2324/3723] board: arm: stm32h747i_disco: flashing Add the possibility to flash stm32h747i_disco board using west STM32CubeProgrammer runner, for both cores. Signed-off-by: Abderrahmane Jarmouni --- boards/arm/stm32h747i_disco/board.cmake | 2 ++ boards/arm/stm32h747i_disco/doc/index.rst | 7 +++++++ 2 files changed, 9 insertions(+) diff --git a/boards/arm/stm32h747i_disco/board.cmake b/boards/arm/stm32h747i_disco/board.cmake index ac0e473e57d..00da755afb0 100644 --- a/boards/arm/stm32h747i_disco/board.cmake +++ b/boards/arm/stm32h747i_disco/board.cmake @@ -9,6 +9,8 @@ board_runner_args(jlink "--device=STM32H747ZI_M4") board_runner_args(openocd "--config=${BOARD_DIR}/support/openocd_stm32h747i_disco_m4.cfg") board_runner_args(openocd --target-handle=_CHIPNAME.cpu1) endif() +board_runner_args(stm32cubeprogrammer "--port=swd" "--reset-mode=hw") include(${ZEPHYR_BASE}/boards/common/openocd.board.cmake) +include(${ZEPHYR_BASE}/boards/common/stm32cubeprogrammer.board.cmake) include(${ZEPHYR_BASE}/boards/common/jlink.board.cmake) diff --git a/boards/arm/stm32h747i_disco/doc/index.rst b/boards/arm/stm32h747i_disco/doc/index.rst index 6fc553ab42e..fa668e964c7 100644 --- a/boards/arm/stm32h747i_disco/doc/index.rst +++ b/boards/arm/stm32h747i_disco/doc/index.rst @@ -230,6 +230,13 @@ automatically. Zephyr flash configuration has been set to meet these default settings. +Alternatively, west `STM32CubeProgrammer`_ runner can be used, after installing +it, to flash applications for both cores. The target core is detected automatically. + +.. code-block:: console + + $ west flash --runner stm32cubeprogrammer + Flashing an application to STM32H747I M7 Core --------------------------------------------- From ba5bcb14ba9f44e7ea557e4abbcb915e6f8aac3f Mon Sep 17 00:00:00 2001 From: Ibe Van de Veire Date: Mon, 15 Jan 2024 13:35:45 +0100 Subject: [PATCH 2325/3723] net: ip: igmp: removed compiler warning when igmpv3 is enabled Made the definition of in_addr all_routers conditional to remove compiler warning: warning: 'all_routers' defined but not used [-Wunused-const-variable=] The warning occurs when igmpv3 is enabled. Signed-off-by: Ibe Van de Veire --- subsys/net/ip/igmp.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/subsys/net/ip/igmp.c b/subsys/net/ip/igmp.c index 91a7a4cad5c..2de3b2f9f94 100644 --- a/subsys/net/ip/igmp.c +++ b/subsys/net/ip/igmp.c @@ -36,9 +36,10 @@ LOG_MODULE_DECLARE(net_ipv4, CONFIG_NET_IPV4_LOG_LEVEL); #define IGMPV3_BLOCK_OLD_SOURCES 0x06 static const struct in_addr all_systems = { { { 224, 0, 0, 1 } } }; -static const struct in_addr all_routers = { { { 224, 0, 0, 2 } } }; #if defined(CONFIG_NET_IPV4_IGMPV3) static const struct in_addr igmp_multicast_addr = { { { 224, 0, 0, 22 } } }; +#else +static const struct in_addr all_routers = { { { 224, 0, 0, 2 } } }; #endif #define dbg_addr(action, pkt_str, src, dst) \ From fe9e306a831e6daebcc792aa596a344e1ce0d9ac Mon Sep 17 00:00:00 2001 From: Eduardo Montoya Date: Mon, 15 Jan 2024 15:32:40 +0100 Subject: [PATCH 2326/3723] net: openthread: fix `otLinkMetricsInit` usage Remove usage of `otPlatRadioGetReceiveSensitivity` without the `otInstance` parameter. Signed-off-by: Eduardo Montoya --- modules/openthread/platform/radio.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/modules/openthread/platform/radio.c b/modules/openthread/platform/radio.c index 480907380a2..a9fe75607da 100644 --- a/modules/openthread/platform/radio.c +++ b/modules/openthread/platform/radio.c @@ -63,6 +63,8 @@ LOG_MODULE_REGISTER(LOG_MODULE_NAME, CONFIG_OPENTHREAD_L2_LOG_LEVEL); */ #define PHR_DURATION_US 32U +#define DEFAULT_SENSITIVITY -100 + enum pending_events { PENDING_EVENT_FRAME_TO_SEND, /* There is a tx frame to send */ PENDING_EVENT_FRAME_RECEIVED, /* Radio has received new frame */ @@ -363,7 +365,7 @@ void platformRadioInit(void) radio_api->configure(radio_dev, IEEE802154_CONFIG_EVENT_HANDLER, &cfg); #if defined(CONFIG_OPENTHREAD_LINK_METRICS_SUBJECT) - otLinkMetricsInit(otPlatRadioGetReceiveSensitivity()); + otLinkMetricsInit(DEFAULT_SENSITIVITY); #endif } @@ -1110,7 +1112,7 @@ int8_t otPlatRadioGetReceiveSensitivity(otInstance *aInstance) { ARG_UNUSED(aInstance); - return -100; + return DEFAULT_SENSITIVITY; } otError otPlatRadioGetTransmitPower(otInstance *aInstance, int8_t *aPower) From 298ab2c95dd735e89558041f18952a9539f5f6eb Mon Sep 17 00:00:00 2001 From: Jukka Rissanen Date: Mon, 15 Jan 2024 16:01:37 +0200 Subject: [PATCH 2327/3723] net: socket: Add support for SO_DOMAIN option The getsockopt() will return the address domain of the given socket like AF_INET or AF_INET6. Signed-off-by: Jukka Rissanen --- include/zephyr/net/socket.h | 2 +- subsys/net/lib/sockets/sockets.c | 12 ++++++++++++ 2 files changed, 13 insertions(+), 1 deletion(-) diff --git a/include/zephyr/net/socket.h b/include/zephyr/net/socket.h index 3eca4347a85..bdbbd3b19e5 100644 --- a/include/zephyr/net/socket.h +++ b/include/zephyr/net/socket.h @@ -1166,7 +1166,7 @@ struct ifreq { /** Protocol used with the socket */ #define SO_PROTOCOL 38 -/** Domain used with SOCKET (ignored, for compatibility) */ +/** Domain used with SOCKET */ #define SO_DOMAIN 39 /** Enable SOCKS5 for Socket */ diff --git a/subsys/net/lib/sockets/sockets.c b/subsys/net/lib/sockets/sockets.c index a1f4610b504..c2045996da5 100644 --- a/subsys/net/lib/sockets/sockets.c +++ b/subsys/net/lib/sockets/sockets.c @@ -2447,6 +2447,18 @@ int zsock_getsockopt_ctx(struct net_context *ctx, int level, int optname, return 0; } + + case SO_DOMAIN: { + if (*optlen != sizeof(int)) { + errno = EINVAL; + return -1; + } + + *(int *)optval = net_context_get_family(ctx); + + return 0; + } + break; case SO_RCVBUF: From 4c88169d03e12dec62440bb8c6543245784e87fa Mon Sep 17 00:00:00 2001 From: Jukka Rissanen Date: Mon, 15 Jan 2024 16:17:22 +0200 Subject: [PATCH 2328/3723] tests: net: sockets: Add tests for SO_DOMAIN socket option Make sure that the SO_DOMAIN is a read only value and it returns correct socket domain (AF_INET or AF_INET6) in the tests. Signed-off-by: Jukka Rissanen --- tests/net/socket/misc/src/main.c | 35 ++++++++++++++++++++++++++++++++ 1 file changed, 35 insertions(+) diff --git a/tests/net/socket/misc/src/main.c b/tests/net/socket/misc/src/main.c index 06a9d8e625d..3ddf482f5d6 100644 --- a/tests/net/socket/misc/src/main.c +++ b/tests/net/socket/misc/src/main.c @@ -887,4 +887,39 @@ ZTEST(socket_misc_test_suite, test_ipv4_mapped_to_ipv6_server) test_ipv4_mapped_to_ipv6_server(); } +ZTEST(socket_misc_test_suite, test_so_domain_socket_option) +{ + int ret; + int sock_u; + int sock_t; + socklen_t optlen = sizeof(int); + int domain; + + sock_t = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP); + zassert_true(sock_t >= 0, "TCP socket open failed"); + sock_u = socket(AF_INET6, SOCK_DGRAM, IPPROTO_UDP); + zassert_true(sock_u >= 0, "UDP socket open failed"); + + ret = getsockopt(sock_t, SOL_SOCKET, SO_DOMAIN, &domain, &optlen); + zassert_equal(ret, 0, "getsockopt failed, %d", -errno); + zassert_equal(domain, AF_INET, "Mismatch domain value %d vs %d", + AF_INET, domain); + + ret = getsockopt(sock_u, SOL_SOCKET, SO_DOMAIN, &domain, &optlen); + zassert_equal(ret, 0, "getsockopt failed, %d", -errno); + zassert_equal(domain, AF_INET6, "Mismatch domain value %d vs %d", + AF_INET6, domain); + + /* setsockopt() is not supported for this option */ + domain = AF_INET; + ret = setsockopt(sock_u, SOL_SOCKET, SO_DOMAIN, &domain, optlen); + zassert_equal(ret, -1, "setsockopt succeed"); + zassert_equal(errno, ENOPROTOOPT, "Invalid errno %d", errno); + + ret = close(sock_t); + zassert_equal(ret, 0, "close failed, %d", -errno); + ret = close(sock_u); + zassert_equal(ret, 0, "close failed, %d", -errno); +} + ZTEST_SUITE(socket_misc_test_suite, NULL, setup, NULL, NULL, NULL); From 16a54f251a34117b7ef7d4e0a8ecd3ad5c12e0c1 Mon Sep 17 00:00:00 2001 From: Jukka Rissanen Date: Mon, 15 Jan 2024 16:29:37 +0200 Subject: [PATCH 2329/3723] net: sockets: Refactor accept() to support objcore better If user has not supplied address pointer when calling accept(), then we would not be able to figure out the used socket domain properly. But as there is now SO_DOMAIN option supported, use that to get the correct socket domain. Signed-off-by: Jukka Rissanen --- subsys/net/lib/sockets/socket_obj_core.c | 10 +++++++++- subsys/net/lib/sockets/sockets.c | 4 +--- subsys/net/lib/sockets/sockets_internal.h | 6 ++---- 3 files changed, 12 insertions(+), 8 deletions(-) diff --git a/subsys/net/lib/sockets/socket_obj_core.c b/subsys/net/lib/sockets/socket_obj_core.c index 4133c5cef2e..276576e825f 100644 --- a/subsys/net/lib/sockets/socket_obj_core.c +++ b/subsys/net/lib/sockets/socket_obj_core.c @@ -158,9 +158,11 @@ int sock_obj_core_alloc(int sock, struct net_socket_register *reg, return ret; } -int sock_obj_core_alloc_find(int sock, int new_sock, int family, int type) +int sock_obj_core_alloc_find(int sock, int new_sock, int type) { struct net_socket_register *reg = NULL; + socklen_t optlen = sizeof(int); + int family; int ret; if (new_sock < 0) { @@ -172,6 +174,12 @@ int sock_obj_core_alloc_find(int sock, int new_sock, int family, int type) goto out; } + ret = zsock_getsockopt(sock, SOL_SOCKET, SO_DOMAIN, &family, &optlen); + if (ret < 0) { + NET_ERR("Cannot get socket domain (%d)", -errno); + goto out; + } + ret = sock_obj_core_alloc(new_sock, reg, family, type, ret); if (ret < 0) { NET_ERR("Cannot allocate core object for socket %d (%d)", diff --git a/subsys/net/lib/sockets/sockets.c b/subsys/net/lib/sockets/sockets.c index c2045996da5..48fbad2d03f 100644 --- a/subsys/net/lib/sockets/sockets.c +++ b/subsys/net/lib/sockets/sockets.c @@ -684,9 +684,7 @@ int z_impl_zsock_accept(int sock, struct sockaddr *addr, socklen_t *addrlen) new_sock = VTABLE_CALL(accept, sock, addr, addrlen); - if (addr) { - (void)sock_obj_core_alloc_find(sock, new_sock, addr->sa_family, SOCK_STREAM); - } + (void)sock_obj_core_alloc_find(sock, new_sock, SOCK_STREAM); return new_sock; } diff --git a/subsys/net/lib/sockets/sockets_internal.h b/subsys/net/lib/sockets/sockets_internal.h index 7af35d2a219..7efd6745ed3 100644 --- a/subsys/net/lib/sockets/sockets_internal.h +++ b/subsys/net/lib/sockets/sockets_internal.h @@ -82,7 +82,7 @@ size_t msghdr_non_empty_iov_count(const struct msghdr *msg); #if defined(CONFIG_NET_SOCKETS_OBJ_CORE) int sock_obj_core_alloc(int sock, struct net_socket_register *reg, int family, int type, int proto); -int sock_obj_core_alloc_find(int sock, int new_sock, int family, int type); +int sock_obj_core_alloc_find(int sock, int new_sock, int type); int sock_obj_core_dealloc(int sock); void sock_obj_core_update_send_stats(int sock, int bytes); void sock_obj_core_update_recv_stats(int sock, int bytes); @@ -100,12 +100,10 @@ static inline int sock_obj_core_alloc(int sock, return -ENOTSUP; } -static inline int sock_obj_core_alloc_find(int sock, int new_sock, - int family, int type) +static inline int sock_obj_core_alloc_find(int sock, int new_sock, int type) { ARG_UNUSED(sock); ARG_UNUSED(new_sock); - ARG_UNUSED(family); ARG_UNUSED(type); return -ENOTSUP; From ac71dfae9003925d5a55940917c00515da892b3e Mon Sep 17 00:00:00 2001 From: Guennadi Liakhovetski Date: Mon, 15 Jan 2024 15:40:27 +0100 Subject: [PATCH 2330/3723] intel-adsp: use proper error codes Use proper errno.h error codes in pd_intel_adsp_set_power_enable() instead of -1. Signed-off-by: Guennadi Liakhovetski --- drivers/power_domain/power_domain_intel_adsp.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/power_domain/power_domain_intel_adsp.c b/drivers/power_domain/power_domain_intel_adsp.c index fa65257a214..b9d52bf85ef 100644 --- a/drivers/power_domain/power_domain_intel_adsp.c +++ b/drivers/power_domain/power_domain_intel_adsp.c @@ -32,7 +32,7 @@ static int pd_intel_adsp_set_power_enable(struct pg_bits *bits, bool power_enabl if (!WAIT_FOR(sys_read16((mem_addr_t)&ACE_DfPMCCU.dfpwrsts) & BIT(bits->CPA_bit), 10000, k_busy_wait(1))) { - return -1; + return -EIO; } } else { #if CONFIG_ACE_VERSION_1_5 @@ -43,7 +43,7 @@ static int pd_intel_adsp_set_power_enable(struct pg_bits *bits, bool power_enabl uint32_t key_value = *key_read_ptr; if (key_value != INTEL_ADSP_ACE15_MAGIC_KEY) - return -1; + return -EINVAL; } #endif sys_write16(sys_read16((mem_addr_t)&ACE_DfPMCCU.dfpwrctl) & ~(SPA_bit_mask), From a1fd8cd078ee470ceb89bf0fe77d9ee23274a849 Mon Sep 17 00:00:00 2001 From: Guennadi Liakhovetski Date: Mon, 15 Jan 2024 15:48:24 +0100 Subject: [PATCH 2331/3723] runtime-pm: remove a superfluous k_is_pre_kernel() test If runtime_suspend() is called early during Zephyr initialisation, while k_is_pre_kernel() returns 'true,' 'async' is set to 'false,' so if 'async' is 'true,' Zephyr initialisation is definitely complete, so there is no need to check k_is_pre_kernel() again. Signed-off-by: Guennadi Liakhovetski --- subsys/pm/device_runtime.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/subsys/pm/device_runtime.c b/subsys/pm/device_runtime.c index f7d9b7a8369..b6d3091e71d 100644 --- a/subsys/pm/device_runtime.c +++ b/subsys/pm/device_runtime.c @@ -76,7 +76,7 @@ static int runtime_suspend(const struct device *dev, bool async, goto unlock; } - if (async && !k_is_pre_kernel()) { + if (async) { /* queue suspend */ pm->state = PM_DEVICE_STATE_SUSPENDING; (void)k_work_schedule(&pm->work, delay); From c99a604bbf2cc353d0c1a4ba42053ecd0bef81bf Mon Sep 17 00:00:00 2001 From: Guennadi Liakhovetski Date: Mon, 15 Jan 2024 15:55:10 +0100 Subject: [PATCH 2332/3723] ace: remove superfluous variable initialisation 'ret' in pm_state_set() is always set before it's used, no need to initialise it. Signed-off-by: Guennadi Liakhovetski --- soc/xtensa/intel_adsp/ace/power.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/soc/xtensa/intel_adsp/ace/power.c b/soc/xtensa/intel_adsp/ace/power.c index 7c50923abdd..284426bf757 100644 --- a/soc/xtensa/intel_adsp/ace/power.c +++ b/soc/xtensa/intel_adsp/ace/power.c @@ -235,7 +235,7 @@ void pm_state_set(enum pm_state state, uint8_t substate_id) { ARG_UNUSED(substate_id); uint32_t cpu = arch_proc_id(); - int ret = 0; + int ret; ARG_UNUSED(ret); From e7217925c93e7d6a707c11099b9446bdc8e419be Mon Sep 17 00:00:00 2001 From: Guennadi Liakhovetski Date: Mon, 15 Jan 2024 15:56:50 +0100 Subject: [PATCH 2333/3723] ace: use a 'switch' statement in pm_state_set() Use 'switch' to emphasise that we're handling different values of 'state' in pm_state_set(). Signed-off-by: Guennadi Liakhovetski --- soc/xtensa/intel_adsp/ace/power.c | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/soc/xtensa/intel_adsp/ace/power.c b/soc/xtensa/intel_adsp/ace/power.c index 284426bf757..e35443d4cf8 100644 --- a/soc/xtensa/intel_adsp/ace/power.c +++ b/soc/xtensa/intel_adsp/ace/power.c @@ -243,7 +243,8 @@ void pm_state_set(enum pm_state state, uint8_t substate_id) core_desc[cpu].intenable = XTENSA_RSR("INTENABLE"); z_xt_ints_off(0xffffffff); - if (state == PM_STATE_SOFT_OFF) { + switch (state) { + case PM_STATE_SOFT_OFF: core_desc[cpu].bctl = DSPCS.bootctl[cpu].bctl; DSPCS.bootctl[cpu].bctl &= ~DSPBR_BCTL_WAITIPCG; if (cpu == 0) { @@ -307,7 +308,8 @@ void pm_state_set(enum pm_state state, uint8_t substate_id) } else { power_gate_entry(cpu); } - } else if (state == PM_STATE_RUNTIME_IDLE) { + break; + case PM_STATE_RUNTIME_IDLE: DSPCS.bootctl[cpu].bctl &= ~DSPBR_BCTL_WAITIPPG; DSPCS.bootctl[cpu].bctl &= ~DSPBR_BCTL_WAITIPCG; soc_cpu_power_down(cpu); @@ -321,7 +323,8 @@ void pm_state_set(enum pm_state state, uint8_t substate_id) ret = pm_device_runtime_put(INTEL_ADSP_HST_DOMAIN_DEV); __ASSERT_NO_MSG(ret == 0); power_gate_entry(cpu); - } else { + break; + default: __ASSERT(false, "invalid argument - unsupported power state"); } } From 2075a1b7708a115784772d966f7ba78efdd05540 Mon Sep 17 00:00:00 2001 From: Peter Mitsis Date: Thu, 11 Jan 2024 15:59:32 -0500 Subject: [PATCH 2334/3723] arch: xtensa: Use rsr.lowercase over rsr.UPPERCASE rsr.UPPERCASE can lead to compiler errors when UPPERCASE matches a macro defined in the special register header file. Signed-off-by: Peter Mitsis --- arch/xtensa/include/xtensa_asm2_s.h | 20 ++++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/arch/xtensa/include/xtensa_asm2_s.h b/arch/xtensa/include/xtensa_asm2_s.h index 1791b85a8cd..842c9252c7b 100644 --- a/arch/xtensa/include/xtensa_asm2_s.h +++ b/arch/xtensa/include/xtensa_asm2_s.h @@ -160,20 +160,20 @@ * Does not populate or modify the PS/PC save locations. */ .macro ODD_REG_SAVE - rsr.SAR a0 + rsr.sar a0 s32i a0, a1, ___xtensa_irq_bsa_t_sar_OFFSET #if XCHAL_HAVE_LOOPS - rsr.LBEG a0 + rsr.lbeg a0 s32i a0, a1, ___xtensa_irq_bsa_t_lbeg_OFFSET - rsr.LEND a0 + rsr.lend a0 s32i a0, a1, ___xtensa_irq_bsa_t_lend_OFFSET - rsr.LCOUNT a0 + rsr.lcount a0 s32i a0, a1, ___xtensa_irq_bsa_t_lcount_OFFSET #endif rsr.exccause a0 s32i a0, a1, ___xtensa_irq_bsa_t_exccause_OFFSET #if XCHAL_HAVE_S32C1I - rsr.SCOMPARE1 a0 + rsr.scompare1 a0 s32i a0, a1, ___xtensa_irq_bsa_t_scompare1_OFFSET #endif #if XCHAL_HAVE_THREADPTR && \ @@ -432,11 +432,11 @@ _xstack_returned_\@: * argument and expand two versions of this handler. An * optimization FIXME, I guess. */ - rsr.PS a0 + rsr.ps a0 movi a3, PS_INTLEVEL_MASK and a0, a0, a3 bnez a0, _not_l1 - rsr.PS a0 + rsr.ps a0 movi a3, PS_INTLEVEL(1) or a0, a0, a3 wsr.PS a0 @@ -600,7 +600,7 @@ _Level\LVL\()Vector: * turned on the EXCM bit and set INTLEVEL. */ .if \LVL == 1 - rsr.PS a0 + rsr.ps a0 #ifdef CONFIG_XTENSA_MMU /* TLB misses also come through level 1 interrupts. * We do not want to unconditionally unmask interrupts. @@ -616,11 +616,11 @@ _Level\LVL\()Vector: and a0, a0, a2 s32i a0, a1, ___xtensa_irq_bsa_t_ps_OFFSET .else - rsr.EPS\LVL a0 + rsr.eps\LVL a0 s32i a0, a1, ___xtensa_irq_bsa_t_ps_OFFSET .endif - rsr.EPC\LVL a0 + rsr.epc\LVL a0 s32i a0, a1, ___xtensa_irq_bsa_t_pc_OFFSET /* What's happening with this jump is that the L32R From 5c18a00d370dd4296078f93ab7fb33c92ba0d341 Mon Sep 17 00:00:00 2001 From: Peter Mitsis Date: Thu, 11 Jan 2024 16:04:53 -0500 Subject: [PATCH 2335/3723] arch: xtensa: Use wsr.lowercase over wsr.UPPERCASE wsr.UPPERCASE can lead to compiler errors when UPPERCASE matches a macro defined in the special register header file. Signed-off-by: Peter Mitsis --- arch/xtensa/include/xtensa_asm2_s.h | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/arch/xtensa/include/xtensa_asm2_s.h b/arch/xtensa/include/xtensa_asm2_s.h index 842c9252c7b..c075d42c3f0 100644 --- a/arch/xtensa/include/xtensa_asm2_s.h +++ b/arch/xtensa/include/xtensa_asm2_s.h @@ -371,7 +371,7 @@ _xstack_call0_\@: entry a1, 16 mov a1, a2 rsr.ZSR_EPS a2 - wsr.PS a2 + wsr.ps a2 call4 _xstack_call1_\@ mov a2, a6 /* copy return value */ retw @@ -439,7 +439,7 @@ _xstack_returned_\@: rsr.ps a0 movi a3, PS_INTLEVEL(1) or a0, a0, a3 - wsr.PS a0 + wsr.ps a0 _not_l1: /* Setting up the cross stack call below has states where the @@ -459,7 +459,7 @@ _xstack_returned_\@: movi a3, ~(PS_EXCM_MASK) & ~(PS_RING_MASK) and a0, a0, a3 wsr.ZSR_EPS a0 - wsr.PS a0 + wsr.ps a0 rsync /* A1 already contains our saved stack, and A2 our handler. From 0f9ebbded3b8daacdc6a9676f77d75fdd07bbdea Mon Sep 17 00:00:00 2001 From: Mustafa Abdullah Kus Date: Tue, 16 Jan 2024 12:17:54 +0300 Subject: [PATCH 2336/3723] dts: bindings: st,stm32h7-spi: add mssi and midi property add Master Inter-Data Idleness and Master SS Idleness field. That fields are integers. Signed-off-by: Mustafa Abdullah Kus --- dts/bindings/spi/st,stm32h7-spi.yaml | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/dts/bindings/spi/st,stm32h7-spi.yaml b/dts/bindings/spi/st,stm32h7-spi.yaml index 3843e420f71..a1082fff7c4 100644 --- a/dts/bindings/spi/st,stm32h7-spi.yaml +++ b/dts/bindings/spi/st,stm32h7-spi.yaml @@ -12,3 +12,18 @@ description: | compatible: "st,stm32h7-spi" include: st,stm32-spi-common.yaml + +properties: + midi-clock: + type: int + default: 0 + description: | + (Master Inter-Data Idleness) minimum clock inserted + between two consecutive data frames. + + mssi-clock: + type: int + default: 0 + description: | + (Master SS Idleness) minimum clock inserted between + start and first data transaction. From 3135a4cd0b88f09ab5df76c083b55ae9e118e7b4 Mon Sep 17 00:00:00 2001 From: Mustafa Abdullah Kus Date: Tue, 16 Jan 2024 12:19:54 +0300 Subject: [PATCH 2337/3723] drivers: spi: spi_ll_stm32: add midi and mssi impl Master Inter-Data Idleness and Master SS Idleness can configure with STM32 low level spi driver apis. Signed-off-by: Mustafa Abdullah Kus --- drivers/spi/spi_ll_stm32.c | 11 +++++++++++ drivers/spi/spi_ll_stm32.h | 4 ++++ 2 files changed, 15 insertions(+) diff --git a/drivers/spi/spi_ll_stm32.c b/drivers/spi/spi_ll_stm32.c index 027a9f8da23..b37e6b903e2 100644 --- a/drivers/spi/spi_ll_stm32.c +++ b/drivers/spi/spi_ll_stm32.c @@ -618,6 +618,11 @@ static int spi_stm32_configure(const struct device *dev, LL_SPI_SetDataWidth(spi, LL_SPI_DATAWIDTH_16BIT); } +#if DT_HAS_COMPAT_STATUS_OKAY(st_stm32h7_spi) + LL_SPI_SetMasterSSIdleness(spi, cfg->mssi_clocks); + LL_SPI_SetInterDataIdleness(spi, (cfg->midi_clocks << SPI_CFG2_MIDI_Pos)); +#endif + #if DT_HAS_COMPAT_STATUS_OKAY(st_stm32_spi_fifo) ll_func_set_fifo_threshold_8bit(spi); #endif @@ -1160,6 +1165,12 @@ static const struct spi_stm32_config spi_stm32_cfg_##id = { \ IF_ENABLED(DT_HAS_COMPAT_STATUS_OKAY(st_stm32_spi_subghz), \ (.use_subghzspi_nss = \ DT_INST_PROP_OR(id, use_subghzspi_nss, false),))\ + IF_ENABLED(DT_HAS_COMPAT_STATUS_OKAY(st_stm32h7_spi), \ + (.midi_clocks = \ + DT_INST_PROP(id, midi_clock),)) \ + IF_ENABLED(DT_HAS_COMPAT_STATUS_OKAY(st_stm32h7_spi), \ + (.mssi_clocks = \ + DT_INST_PROP(id, mssi_clock),)) \ }; \ \ static struct spi_stm32_data spi_stm32_dev_data_##id = { \ diff --git a/drivers/spi/spi_ll_stm32.h b/drivers/spi/spi_ll_stm32.h index a90b41311af..c241750c63e 100644 --- a/drivers/spi/spi_ll_stm32.h +++ b/drivers/spi/spi_ll_stm32.h @@ -27,6 +27,10 @@ struct spi_stm32_config { #endif #if DT_HAS_COMPAT_STATUS_OKAY(st_stm32_spi_subghz) bool use_subghzspi_nss; +#endif +#if DT_HAS_COMPAT_STATUS_OKAY(st_stm32h7_spi) + int midi_clocks; + int mssi_clocks; #endif size_t pclk_len; const struct stm32_pclken *pclken; From 8a3ba22f798c730febc9e3522d30bfae032c22d5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Martin=20J=C3=A4ger?= Date: Mon, 15 Jan 2024 18:27:38 +0100 Subject: [PATCH 2338/3723] boards: arm: nucleo_wl55jc: add flash partitions MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Add flash partitions required to use the board with MCUboot. Also fix the chosen zephyr,code-partition devicetree node and point it to slot0_partition. Signed-off-by: Martin Jäger --- boards/arm/nucleo_wl55jc/nucleo_wl55jc.dts | 16 +++++++++++++++- 1 file changed, 15 insertions(+), 1 deletion(-) diff --git a/boards/arm/nucleo_wl55jc/nucleo_wl55jc.dts b/boards/arm/nucleo_wl55jc/nucleo_wl55jc.dts index 1a5e0d2e73e..e83f45452dd 100644 --- a/boards/arm/nucleo_wl55jc/nucleo_wl55jc.dts +++ b/boards/arm/nucleo_wl55jc/nucleo_wl55jc.dts @@ -20,7 +20,7 @@ zephyr,shell-uart = &lpuart1; zephyr,sram = &sram0; zephyr,flash = &flash0; - zephyr,code-partition = &flash0; + zephyr,code-partition = &slot0_partition; }; leds: leds { @@ -191,6 +191,20 @@ stm32_lp_tick_source: &lptim1 { #address-cells = <1>; #size-cells = <1>; + boot_partition: partition@0 { + label = "mcuboot"; + reg = <0x00000000 DT_SIZE_K(32)>; + read-only; + }; + slot0_partition: partition@8000 { + label = "image-0"; + reg = <0x00008000 DT_SIZE_K(104)>; + }; + slot1_partition: partition@22000 { + label = "image-1"; + reg = <0x00022000 DT_SIZE_K(104)>; + }; + /* * Set 16kB of storage (8x2kB pages) at the end of the 256kB of * flash. From db24a8b4611876198ef3530e1fbc49d1757a7dbf Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Martin=20J=C3=A4ger?= Date: Mon, 15 Jan 2024 18:30:27 +0100 Subject: [PATCH 2339/3723] boards: arm: lora_e5_dev_board: add flash partitions MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Add flash partitions required to use the board with MCUboot. Also fix the chosen zephyr,code-partition devicetree node and point it to slot0_partition. Signed-off-by: Martin Jäger --- .../arm/lora_e5_dev_board/lora_e5_dev_board.dts | 15 ++++++++++++++- 1 file changed, 14 insertions(+), 1 deletion(-) diff --git a/boards/arm/lora_e5_dev_board/lora_e5_dev_board.dts b/boards/arm/lora_e5_dev_board/lora_e5_dev_board.dts index 390e949cfce..02602825712 100644 --- a/boards/arm/lora_e5_dev_board/lora_e5_dev_board.dts +++ b/boards/arm/lora_e5_dev_board/lora_e5_dev_board.dts @@ -17,7 +17,7 @@ zephyr,shell-uart = &usart1; zephyr,sram = &sram0; zephyr,flash = &flash0; - zephyr,code-partition = &flash0; + zephyr,code-partition = &slot0_partition; }; leds { @@ -176,6 +176,19 @@ grove_i2c: &i2c2 {}; #address-cells = <1>; #size-cells = <1>; + boot_partition: partition@0 { + label = "mcuboot"; + reg = <0x00000000 DT_SIZE_K(32)>; + read-only; + }; + slot0_partition: partition@8000 { + label = "image-0"; + reg = <0x00008000 DT_SIZE_K(104)>; + }; + slot1_partition: partition@22000 { + label = "image-1"; + reg = <0x00022000 DT_SIZE_K(104)>; + }; /* 16KB (8x2kB pages) of storage at the end of the flash */ storage_partition: partition@3c000 { label = "storage"; From 574e641297b1d97bb43d0cb0ba985a058fe53e66 Mon Sep 17 00:00:00 2001 From: Christopher Friedt Date: Sat, 25 Nov 2023 16:44:40 -0500 Subject: [PATCH 2340/3723] samples: cpp: add a Hello, world! C++ app Create a separate hello world C++ app for Zephyr. Signed-off-by: Christopher Friedt --- samples/cpp/hello_world/CMakeLists.txt | 8 +++++++ samples/cpp/hello_world/README.rst | 33 ++++++++++++++++++++++++++ samples/cpp/hello_world/prj.conf | 2 ++ samples/cpp/hello_world/sample.yaml | 24 +++++++++++++++++++ samples/cpp/hello_world/src/main.cpp | 13 ++++++++++ 5 files changed, 80 insertions(+) create mode 100644 samples/cpp/hello_world/CMakeLists.txt create mode 100644 samples/cpp/hello_world/README.rst create mode 100644 samples/cpp/hello_world/prj.conf create mode 100644 samples/cpp/hello_world/sample.yaml create mode 100644 samples/cpp/hello_world/src/main.cpp diff --git a/samples/cpp/hello_world/CMakeLists.txt b/samples/cpp/hello_world/CMakeLists.txt new file mode 100644 index 00000000000..da4e1f7da41 --- /dev/null +++ b/samples/cpp/hello_world/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(hello_cpp_world) + +target_sources(app PRIVATE src/main.cpp) diff --git a/samples/cpp/hello_world/README.rst b/samples/cpp/hello_world/README.rst new file mode 100644 index 00000000000..cfc2541ff39 --- /dev/null +++ b/samples/cpp/hello_world/README.rst @@ -0,0 +1,33 @@ +.. _hello_cpp_world: + +Hello C++ World +############### + +Overview +******** + +A simple :ref:`C++ ` sample that can be used with many supported board and prints +"Hello, C++ world!" to the console. + +Building and Running +******************** + +This configuration can be built and executed on QEMU as follows: + +.. zephyr-app-commands:: + :zephyr-app: samples/cpp/hello_world + :host-os: unix + :board: qemu_riscv32 + :goals: run + :compact: + +To build for another board, change "qemu_riscv32" above to that board's name. + +Sample Output +============= + +.. code-block:: console + + Hello C++, world! qemu_riscv32 + +Exit QEMU by pressing :kbd:`CTRL+C` diff --git a/samples/cpp/hello_world/prj.conf b/samples/cpp/hello_world/prj.conf new file mode 100644 index 00000000000..b801dee1855 --- /dev/null +++ b/samples/cpp/hello_world/prj.conf @@ -0,0 +1,2 @@ +CONFIG_CPP=y +CONFIG_REQUIRES_FULL_LIBCPP=y diff --git a/samples/cpp/hello_world/sample.yaml b/samples/cpp/hello_world/sample.yaml new file mode 100644 index 00000000000..244c7b4f345 --- /dev/null +++ b/samples/cpp/hello_world/sample.yaml @@ -0,0 +1,24 @@ +sample: + description: Hello World C++ sample, the simplest C++ Zephyr application + name: hello cpp world +common: + tags: introduction + integration_platforms: + - qemu_riscv32 + harness: console + harness_config: + type: one_line + regex: + - "Hello, C\\+\\+ world! (.*)" +tests: + sample.cpp.helloworld: + min_ram: 128 + arch_exclude: + # See #66027 + - xtensa + platform_exclude: + # See zephyrproject-rtos/sdk-ng#593 + - qemu_x86 + - intel_ish_5_4_1 + - intel_ish_5_6_0 + - intel_ish_5_8_0 diff --git a/samples/cpp/hello_world/src/main.cpp b/samples/cpp/hello_world/src/main.cpp new file mode 100644 index 00000000000..369e3573526 --- /dev/null +++ b/samples/cpp/hello_world/src/main.cpp @@ -0,0 +1,13 @@ +/* + * Copyright (c) 2023, Meta + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include + +int main(void) +{ + std::cout << "Hello, C++ world! " << CONFIG_BOARD << std::endl; + return 0; +} From e223d01b6756d9984c39c795f1a5bccb50bedc8e Mon Sep 17 00:00:00 2001 From: Christopher Friedt Date: Mon, 15 Jan 2024 17:38:58 -0500 Subject: [PATCH 2341/3723] tests: posix: shorten the filter in testcase.yaml CONFIG_NATIVE_LIBC can be used in place of CONFIG_NATIVE_BUILD and CONFIG_EXTERNAL_LIBC Signed-off-by: Christopher Friedt --- tests/posix/common/testcase.yaml | 2 +- tests/posix/eventfd/testcase.yaml | 2 +- tests/posix/fs/testcase.yaml | 2 +- tests/posix/getopt/testcase.yaml | 2 +- tests/posix/headers/testcase.yaml | 2 +- 5 files changed, 5 insertions(+), 5 deletions(-) diff --git a/tests/posix/common/testcase.yaml b/tests/posix/common/testcase.yaml index 03f7ee381ac..40c24f08d0e 100644 --- a/tests/posix/common/testcase.yaml +++ b/tests/posix/common/testcase.yaml @@ -1,5 +1,5 @@ common: - filter: not (CONFIG_NATIVE_BUILD and CONFIG_EXTERNAL_LIBC) + filter: not CONFIG_NATIVE_LIBC platform_exclude: - native_posix - native_posix_64 diff --git a/tests/posix/eventfd/testcase.yaml b/tests/posix/eventfd/testcase.yaml index f44c97fc100..e7e9d4e245a 100644 --- a/tests/posix/eventfd/testcase.yaml +++ b/tests/posix/eventfd/testcase.yaml @@ -1,5 +1,5 @@ common: - filter: not (CONFIG_NATIVE_BUILD and CONFIG_EXTERNAL_LIBC) + filter: not CONFIG_NATIVE_LIBC tags: - posix - eventfd diff --git a/tests/posix/fs/testcase.yaml b/tests/posix/fs/testcase.yaml index 5274053dad4..1c90ad9f0f0 100644 --- a/tests/posix/fs/testcase.yaml +++ b/tests/posix/fs/testcase.yaml @@ -1,5 +1,5 @@ common: - filter: not (CONFIG_NATIVE_BUILD and CONFIG_EXTERNAL_LIBC) + filter: not CONFIG_NATIVE_LIBC arch_exclude: - nios2 platform_exclude: diff --git a/tests/posix/getopt/testcase.yaml b/tests/posix/getopt/testcase.yaml index 312eacca986..06eb83556a2 100644 --- a/tests/posix/getopt/testcase.yaml +++ b/tests/posix/getopt/testcase.yaml @@ -1,5 +1,5 @@ common: - filter: not (CONFIG_NATIVE_BUILD and CONFIG_EXTERNAL_LIBC) + filter: not CONFIG_NATIVE_LIBC tags: - posix - getopt diff --git a/tests/posix/headers/testcase.yaml b/tests/posix/headers/testcase.yaml index 1a91d193001..bcbb83c9036 100644 --- a/tests/posix/headers/testcase.yaml +++ b/tests/posix/headers/testcase.yaml @@ -1,5 +1,5 @@ common: - filter: not (CONFIG_NATIVE_BUILD and CONFIG_EXTERNAL_LIBC) + filter: not CONFIG_NATIVE_LIBC tags: - posix min_ram: 32 From 73e20a89674403bc60829a5d51691f944416dbaa Mon Sep 17 00:00:00 2001 From: Yong Cong Sin Date: Mon, 15 Jan 2024 14:18:27 +0800 Subject: [PATCH 2342/3723] posix: clock: add ztest rule to reset clock base Make sure that the POSIX clock base is reset after every testsuite so that the initial time is the same for every test. Signed-off-by: Yong Cong Sin --- lib/posix/clock.c | 20 ++++++++++++++++++++ 1 file changed, 20 insertions(+) diff --git a/lib/posix/clock.c b/lib/posix/clock.c index 1a59aa741f9..a8835a44248 100644 --- a/lib/posix/clock.c +++ b/lib/posix/clock.c @@ -235,3 +235,23 @@ int clock_getcpuclockid(pid_t pid, clockid_t *clock_id) return 0; } + +#ifdef CONFIG_ZTEST +#include +static void reset_clock_base(void) +{ + K_SPINLOCK(&rt_clock_base_lock) { + rt_clock_base = (struct timespec){0}; + } +} + +static void clock_base_reset_rule_after(const struct ztest_unit_test *test, void *data) +{ + ARG_UNUSED(test); + ARG_UNUSED(data); + + reset_clock_base(); +} + +ZTEST_RULE(clock_base_reset_rule, NULL, clock_base_reset_rule_after); +#endif /* CONFIG_ZTEST */ From 498529ea76abe9714fe59e492598b08db6338b95 Mon Sep 17 00:00:00 2001 From: Yong Cong Sin Date: Fri, 12 Jan 2024 20:58:26 +0800 Subject: [PATCH 2343/3723] tests: posix: common: split `posix_apis` into multiple testsuites Currently all components live under the `posix_apis` testsuite, this commit split them into a testsuite of their own. This commit also prefixed a few local functions/variables with the `static` keyword. Signed-off-by: Yong Cong Sin --- tests/posix/common/src/clock.c | 12 +++++++----- tests/posix/common/src/fnmatch.c | 4 +++- tests/posix/common/src/key.c | 10 ++++++---- tests/posix/common/src/mqueue.c | 14 ++++++++------ tests/posix/common/src/mutex.c | 18 ++++++++++-------- tests/posix/common/src/nanosleep.c | 12 +++++++----- tests/posix/common/src/pthread.c | 18 +++++++++--------- tests/posix/common/src/rwlock.c | 4 +++- tests/posix/common/src/semaphore.c | 6 ++++-- tests/posix/common/src/signal.c | 24 +++++++++++++----------- tests/posix/common/src/sleep.c | 6 ++++-- tests/posix/common/src/spinlock.c | 8 +++++--- tests/posix/common/src/timer.c | 6 ++++-- tests/posix/common/src/uname.c | 4 +++- 14 files changed, 86 insertions(+), 60 deletions(-) diff --git a/tests/posix/common/src/clock.c b/tests/posix/common/src/clock.c index 21319bf3592..d36c74fe0de 100644 --- a/tests/posix/common/src/clock.c +++ b/tests/posix/common/src/clock.c @@ -63,7 +63,7 @@ static inline bool tp_diff_in_range_ns(const struct timespec *a, const struct ti return diff >= lo && diff < hi; } -ZTEST(posix_apis, test_clock_gettime) +ZTEST(clock, test_clock_gettime) { struct timespec ts; @@ -89,7 +89,7 @@ ZTEST(posix_apis, test_clock_gettime) } } -ZTEST(posix_apis, test_gettimeofday) +ZTEST(clock, test_gettimeofday) { struct timeval tv; struct timespec ts; @@ -114,7 +114,7 @@ ZTEST(posix_apis, test_gettimeofday) zassert_true(tp_ge(&rts, &ts)); } -ZTEST(posix_apis, test_clock_settime) +ZTEST(clock, test_clock_settime) { int64_t diff_ns; struct timespec ts = {0}; @@ -163,7 +163,7 @@ ZTEST(posix_apis, test_clock_settime) } } -ZTEST(posix_apis, test_realtime) +ZTEST(clock, test_realtime) { struct timespec then, now; /* @@ -214,7 +214,7 @@ ZTEST(posix_apis, test_realtime) zassert_between_inclusive(cma, lo, hi); } -ZTEST(posix_apis, test_clock_getcpuclockid) +ZTEST(clock, test_clock_getcpuclockid) { int ret = 0; clockid_t clock_id; @@ -225,3 +225,5 @@ ZTEST(posix_apis, test_clock_getcpuclockid) ret = clock_getcpuclockid((pid_t)2482, &clock_id); zassert_equal(ret, EPERM, "POSIX clock_getcpuclock id failed"); } + +ZTEST_SUITE(clock, NULL, NULL, NULL, NULL, NULL); diff --git a/tests/posix/common/src/fnmatch.c b/tests/posix/common/src/fnmatch.c index 0d33f634183..b18841080d5 100644 --- a/tests/posix/common/src/fnmatch.c +++ b/tests/posix/common/src/fnmatch.c @@ -12,7 +12,7 @@ * Adapted from * https://git.musl-libc.org/cgit/libc-testsuite/tree/fnmatch.c */ -ZTEST(posix_apis, test_fnmatch) +ZTEST(fnmatch, test_fnmatch) { /* Note: commented out lines indicate known problems to be addressed in #55186 */ @@ -82,3 +82,5 @@ ZTEST(posix_apis, test_fnmatch) zassert_ok(fnmatch("a*b", "a.b", FNM_PATHNAME | FNM_PERIOD)); zassert_ok(fnmatch("a[.]b", "a.b", FNM_PATHNAME | FNM_PERIOD)); } + +ZTEST_SUITE(fnmatch, NULL, NULL, NULL, NULL, NULL); diff --git a/tests/posix/common/src/key.c b/tests/posix/common/src/key.c index dbeddc3b6d0..4c6d9be16ef 100644 --- a/tests/posix/common/src/key.c +++ b/tests/posix/common/src/key.c @@ -74,7 +74,7 @@ static void make_keys(void) * multiple keys. */ -ZTEST(posix_apis, test_key_1toN_thread) +ZTEST(key, test_key_1toN_thread) { void *retval; pthread_t newthread[N_THR]; @@ -95,7 +95,7 @@ ZTEST(posix_apis, test_key_1toN_thread) zassert_ok(pthread_key_delete(key), "attempt to delete key failed"); } -ZTEST(posix_apis, test_key_Nto1_thread) +ZTEST(key, test_key_Nto1_thread) { pthread_t newthread; @@ -113,7 +113,7 @@ ZTEST(posix_apis, test_key_Nto1_thread) } } -ZTEST(posix_apis, test_key_resource_leak) +ZTEST(key, test_key_resource_leak) { pthread_key_t key; @@ -123,7 +123,7 @@ ZTEST(posix_apis, test_key_resource_leak) } } -ZTEST(posix_apis, test_correct_key_is_deleted) +ZTEST(key, test_correct_key_is_deleted) { pthread_key_t key; size_t j = CONFIG_MAX_PTHREAD_KEY_COUNT - 1; @@ -143,3 +143,5 @@ ZTEST(posix_apis, test_correct_key_is_deleted) zassert_ok(pthread_key_delete(keys[i]), "failed to delete key %zu", i); } } + +ZTEST_SUITE(key, NULL, NULL, NULL, NULL, NULL); diff --git a/tests/posix/common/src/mqueue.c b/tests/posix/common/src/mqueue.c index 4ddfdea2da9..1b0a82d66f5 100644 --- a/tests/posix/common/src/mqueue.c +++ b/tests/posix/common/src/mqueue.c @@ -17,9 +17,9 @@ #define MESSAGE_SIZE 16 #define MESG_COUNT_PERMQ 4 -char queue[16] = "server"; +static char queue[16] = "server"; -char send_data[MESSAGE_SIZE] = "timed data send"; +static char send_data[MESSAGE_SIZE] = "timed data send"; /* * For platforms that select CONFIG_KERNEL_COHERENCE, the receive buffer can @@ -28,9 +28,9 @@ char send_data[MESSAGE_SIZE] = "timed data send"; * receiver. */ -char rec_data[MESSAGE_SIZE]; +static char rec_data[MESSAGE_SIZE]; -void *sender_thread(void *p1) +static void *sender_thread(void *p1) { mqd_t mqd; struct timespec curtime; @@ -48,7 +48,7 @@ void *sender_thread(void *p1) } -void *receiver_thread(void *p1) +static void *receiver_thread(void *p1) { mqd_t mqd; struct timespec curtime; @@ -66,7 +66,7 @@ void *receiver_thread(void *p1) return NULL; } -ZTEST(posix_apis, test_mqueue) +ZTEST(mqueue, test_mqueue) { mqd_t mqd; struct mq_attr attrs; @@ -96,3 +96,5 @@ ZTEST(posix_apis, test_mqueue) "unable to close message queue descriptor."); zassert_false(mq_unlink(queue), "Not able to unlink Queue"); } + +ZTEST_SUITE(mqueue, NULL, NULL, NULL, NULL, NULL); diff --git a/tests/posix/common/src/mutex.c b/tests/posix/common/src/mutex.c index ded1055f7dc..a296d41e8e0 100644 --- a/tests/posix/common/src/mutex.c +++ b/tests/posix/common/src/mutex.c @@ -12,9 +12,9 @@ #define SLEEP_MS 100 -pthread_mutex_t mutex; +static pthread_mutex_t mutex; -void *normal_mutex_entry(void *p1) +static void *normal_mutex_entry(void *p1) { int i, rc; @@ -34,7 +34,7 @@ void *normal_mutex_entry(void *p1) return NULL; } -void *recursive_mutex_entry(void *p1) +static void *recursive_mutex_entry(void *p1) { zassert_false(pthread_mutex_lock(&mutex), "mutex is not taken"); zassert_false(pthread_mutex_lock(&mutex), "mutex is not taken 2nd time"); @@ -83,7 +83,7 @@ static void test_mutex_common(int type, void *(*entry)(void *arg)) * and pthread_mutex_lock are tested with mutex type being * normal. */ -ZTEST(posix_apis, test_mutex_normal) +ZTEST(mutex, test_mutex_normal) { test_mutex_common(PTHREAD_MUTEX_NORMAL, normal_mutex_entry); } @@ -95,7 +95,7 @@ ZTEST(posix_apis, test_mutex_normal) * twice and unlocked for the same number of time. * */ -ZTEST(posix_apis, test_mutex_recursive) +ZTEST(mutex, test_mutex_recursive) { test_mutex_common(PTHREAD_MUTEX_RECURSIVE, recursive_mutex_entry); } @@ -105,7 +105,7 @@ ZTEST(posix_apis, test_mutex_recursive) * * @details Exactly CONFIG_MAX_PTHREAD_MUTEX_COUNT can be in use at once. */ -ZTEST(posix_apis, test_mutex_resource_exhausted) +ZTEST(mutex, test_mutex_resource_exhausted) { size_t i; pthread_mutex_t m[CONFIG_MAX_PTHREAD_MUTEX_COUNT + 1]; @@ -129,7 +129,7 @@ ZTEST(posix_apis, test_mutex_resource_exhausted) * * @details Demonstrate that mutexes may be used over and over again. */ -ZTEST(posix_apis, test_mutex_resource_leak) +ZTEST(mutex, test_mutex_resource_leak) { pthread_mutex_t m; @@ -168,7 +168,7 @@ static void *test_mutex_timedlock_fn(void *arg) } /** @brief Test to verify @ref pthread_mutex_timedlock returns ETIMEDOUT */ -ZTEST(posix_apis, test_mutex_timedlock) +ZTEST(mutex, test_mutex_timedlock) { void *ret; pthread_t th; @@ -194,3 +194,5 @@ ZTEST(posix_apis, test_mutex_timedlock) zassert_ok(pthread_mutex_destroy(&mutex)); } + +ZTEST_SUITE(mutex, NULL, NULL, NULL, NULL, NULL); diff --git a/tests/posix/common/src/nanosleep.c b/tests/posix/common/src/nanosleep.c index 7820f823eb0..e139590bbea 100644 --- a/tests/posix/common/src/nanosleep.c +++ b/tests/posix/common/src/nanosleep.c @@ -104,12 +104,12 @@ static void common_errors(int selection, clockid_t clock_id, int flags) zassert_equal(req.tv_nsec, 0, "actual: %d expected: %d", req.tv_nsec, 0); } -ZTEST(posix_apis, test_nanosleep_errors_errno) +ZTEST(nanosleep, test_nanosleep_errors_errno) { common_errors(SELECT_NANOSLEEP, CLOCK_REALTIME, 0); } -ZTEST(posix_apis, test_clock_nanosleep_errors_errno) +ZTEST(nanosleep, test_clock_nanosleep_errors_errno) { struct timespec rem = {}; struct timespec req = {}; @@ -130,7 +130,7 @@ ZTEST(posix_apis, test_clock_nanosleep_errors_errno) } /** - * @brief Check that a call to nanosleep has yielded executiuon for some minimum time. + * @brief Check that a call to nanosleep has yielded execution for some minimum time. * * Check that the actual time slept is >= the total time specified by @p s (in seconds) and * @p ns (in nanoseconds). @@ -200,7 +200,7 @@ static void common_lower_bound_check(int selection, clockid_t clock_id, int flag /* TODO: Upper bounds check when hr timers are available */ } -ZTEST(posix_apis, test_nanosleep_execution) +ZTEST(nanosleep, test_nanosleep_execution) { /* sleep for 1ns */ common_lower_bound_check(SELECT_NANOSLEEP, 0, 0, 0, 1); @@ -221,7 +221,7 @@ ZTEST(posix_apis, test_nanosleep_execution) common_lower_bound_check(SELECT_NANOSLEEP, 0, 0, 1, 1001); } -ZTEST(posix_apis, test_clock_nanosleep_execution) +ZTEST(nanosleep, test_clock_nanosleep_execution) { struct timespec ts; @@ -281,3 +281,5 @@ ZTEST(posix_apis, test_clock_nanosleep_execution) common_lower_bound_check(SELECT_CLOCK_NANOSLEEP, CLOCK_REALTIME, TIMER_ABSTIME, ts.tv_sec + 2, 1001); } + +ZTEST_SUITE(nanosleep, NULL, NULL, NULL, NULL, NULL); diff --git a/tests/posix/common/src/pthread.c b/tests/posix/common/src/pthread.c index 02cff3d1e79..02d9465081e 100644 --- a/tests/posix/common/src/pthread.c +++ b/tests/posix/common/src/pthread.c @@ -21,15 +21,15 @@ #define PRIO_INVALID -1 #define PTHREAD_INVALID -1 -void *thread_top_exec(void *p1); -void *thread_top_term(void *p1); +static void *thread_top_exec(void *p1); +static void *thread_top_term(void *p1); static pthread_mutex_t lock = PTHREAD_MUTEX_INITIALIZER; static pthread_cond_t cvar0 = PTHREAD_COND_INITIALIZER; static pthread_cond_t cvar1 = PTHREAD_COND_INITIALIZER; static pthread_barrier_t barrier; -sem_t main_sem; +static sem_t main_sem; static int bounce_failed; static int bounce_done[N_THR_E]; @@ -53,7 +53,7 @@ static int barrier_return[N_THR_E]; * Test success is signaled to main() using a traditional semaphore. */ -void *thread_top_exec(void *p1) +static void *thread_top_exec(void *p1) { int i, j, id = (int) POINTER_TO_INT(p1); int policy; @@ -141,7 +141,7 @@ void *thread_top_exec(void *p1) return NULL; } -int bounce_test_done(void) +static int bounce_test_done(void) { int i; @@ -158,7 +158,7 @@ int bounce_test_done(void) return 1; } -int barrier_test_done(void) +static int barrier_test_done(void) { int i; @@ -175,7 +175,7 @@ int barrier_test_done(void) return 1; } -void *thread_top_term(void *p1) +static void *thread_top_term(void *p1) { pthread_t self; int oldstate, policy, ret; @@ -353,7 +353,7 @@ ZTEST(pthread, test_pthread_descriptor_leak) } } -ZTEST(posix_apis, test_sched_getparam) +ZTEST(pthread, test_sched_getparam) { struct sched_param param; int rc = sched_getparam(0, ¶m); @@ -362,7 +362,7 @@ ZTEST(posix_apis, test_sched_getparam) zassert_true((rc == -1 && err == ENOSYS)); } -ZTEST(posix_apis, test_sched_getscheduler) +ZTEST(pthread, test_sched_getscheduler) { int rc = sched_getscheduler(0); int err = errno; diff --git a/tests/posix/common/src/rwlock.c b/tests/posix/common/src/rwlock.c index b7d3ac2abe2..ffba9956a7e 100644 --- a/tests/posix/common/src/rwlock.c +++ b/tests/posix/common/src/rwlock.c @@ -47,7 +47,7 @@ static void *thread_top(void *p1) return NULL; } -ZTEST(posix_apis, test_rw_lock) +ZTEST(rwlock, test_rw_lock) { int ret; pthread_t newthread[N_THR]; @@ -116,3 +116,5 @@ ZTEST(posix_apis, test_rw_lock) zassert_ok(pthread_rwlock_destroy(&rwlock), "Failed to destroy rwlock"); } + +ZTEST_SUITE(rwlock, NULL, NULL, NULL, NULL, NULL); diff --git a/tests/posix/common/src/semaphore.c b/tests/posix/common/src/semaphore.c index fda34cfc23d..542ac70a624 100644 --- a/tests/posix/common/src/semaphore.c +++ b/tests/posix/common/src/semaphore.c @@ -90,7 +90,7 @@ static void semaphore_test(sem_t *sem) zassert_ok(pthread_join(thread2, NULL)); } -ZTEST(posix_apis, test_semaphore) +ZTEST(semaphore, test_semaphore) { sem_t sema; @@ -142,7 +142,7 @@ static void *nsem_close_func(void *p) return NULL; } -ZTEST(posix_apis, test_named_semaphore) +ZTEST(semaphore, test_named_semaphore) { pthread_t thread1, thread2; sem_t *sem1, *sem2, *different_sem1; @@ -311,3 +311,5 @@ ZTEST(posix_apis, test_named_semaphore) sem_close(sem1); zassert_equal(nsem_get_list_len(), 0); } + +ZTEST_SUITE(semaphore, NULL, NULL, NULL, NULL, NULL); diff --git a/tests/posix/common/src/signal.c b/tests/posix/common/src/signal.c index 92017ad4cde..11db9575f8b 100644 --- a/tests/posix/common/src/signal.c +++ b/tests/posix/common/src/signal.c @@ -12,7 +12,7 @@ #include #include -ZTEST(posix_apis, test_signal_emptyset) +ZTEST(signal, test_sigemptyset) { sigset_t set; @@ -27,7 +27,7 @@ ZTEST(posix_apis, test_signal_emptyset) } } -ZTEST(posix_apis, test_signal_fillset) +ZTEST(signal, test_sigfillset) { sigset_t set = (sigset_t){0}; @@ -38,7 +38,7 @@ ZTEST(posix_apis, test_signal_fillset) } } -ZTEST(posix_apis, test_signal_addset_oor) +ZTEST(signal, test_sigaddset_oor) { sigset_t set = (sigset_t){0}; @@ -52,7 +52,7 @@ ZTEST(posix_apis, test_signal_addset_oor) zassert_equal(errno, EINVAL, "errno should be %s", "EINVAL"); } -ZTEST(posix_apis, test_signal_addset) +ZTEST(signal, test_sigaddset) { int signo; sigset_t set = (sigset_t){0}; @@ -99,7 +99,7 @@ ZTEST(posix_apis, test_signal_addset) } } -ZTEST(posix_apis, test_signal_delset_oor) +ZTEST(signal, test_sigdelset_oor) { sigset_t set = (sigset_t){0}; @@ -113,7 +113,7 @@ ZTEST(posix_apis, test_signal_delset_oor) zassert_equal(errno, EINVAL, "errno should be %s", "EINVAL"); } -ZTEST(posix_apis, test_signal_delset) +ZTEST(signal, test_sigdelset) { int signo; sigset_t set = (sigset_t){0}; @@ -160,7 +160,7 @@ ZTEST(posix_apis, test_signal_delset) } } -ZTEST(posix_apis, test_signal_ismember_oor) +ZTEST(signal, test_sigismember_oor) { sigset_t set = {0}; @@ -174,7 +174,7 @@ ZTEST(posix_apis, test_signal_ismember_oor) zassert_equal(errno, EINVAL, "errno should be %s", "EINVAL"); } -ZTEST(posix_apis, test_signal_ismember) +ZTEST(signal, test_sigismember) { sigset_t set = (sigset_t){0}; @@ -195,7 +195,7 @@ ZTEST(posix_apis, test_signal_ismember) zassert_equal(sigismember(&set, SIGTERM), 0, "%s not expected to be member", "SIGTERM"); } -ZTEST(posix_apis, test_signal_strsignal) +ZTEST(signal, test_signal_strsignal) { /* Using -INT_MAX here because compiler resolves INT_MIN to (-2147483647 - 1) */ char buf[sizeof("RT signal -" STRINGIFY(INT_MAX))] = {0}; @@ -297,7 +297,7 @@ static void *test_sigmask_entry(void *arg) return NULL; } -ZTEST(posix_apis, test_pthread_sigmask) +ZTEST(signal, test_pthread_sigmask) { pthread_t th; @@ -305,7 +305,7 @@ ZTEST(posix_apis, test_pthread_sigmask) zassert_ok(pthread_join(th, NULL)); } -ZTEST(posix_apis, test_sigprocmask) +ZTEST(signal, test_sigprocmask) { if (IS_ENABLED(CONFIG_MULTITHREADING)) { if (!IS_ENABLED(CONFIG_ASSERT)) { @@ -319,3 +319,5 @@ ZTEST(posix_apis, test_sigprocmask) zassert_ok(pthread_join(th, NULL)); } } + +ZTEST_SUITE(signal, NULL, NULL, NULL, NULL, NULL); diff --git a/tests/posix/common/src/sleep.c b/tests/posix/common/src/sleep.c index a68895a74c1..d126a6645ea 100644 --- a/tests/posix/common/src/sleep.c +++ b/tests/posix/common/src/sleep.c @@ -24,7 +24,7 @@ static void waker_func(struct k_work *work) } K_WORK_DELAYABLE_DEFINE(waker, waker_func); -ZTEST(posix_apis, test_sleep) +ZTEST(sleep, test_sleep) { uint32_t then; uint32_t now; @@ -55,7 +55,7 @@ ZTEST(posix_apis, test_sleep) zassert_true(sleep(sleep_max_s) >= sleep_rem_s); } -ZTEST(posix_apis, test_usleep) +ZTEST(sleep, test_usleep) { uint32_t then; uint32_t now; @@ -86,3 +86,5 @@ ZTEST(posix_apis, test_usleep) zassert_equal(-1, usleep(USEC_PER_SEC - 1)); zassert_equal(EINTR, errno); } + +ZTEST_SUITE(sleep, NULL, NULL, NULL, NULL, NULL); diff --git a/tests/posix/common/src/spinlock.c b/tests/posix/common/src/spinlock.c index e6109923626..14072e729b4 100644 --- a/tests/posix/common/src/spinlock.c +++ b/tests/posix/common/src/spinlock.c @@ -9,7 +9,7 @@ #include #include -ZTEST(posix_apis, test_spin_init_destroy) +ZTEST(spinlock, test_spin_init_destroy) { pthread_spinlock_t lock; @@ -24,7 +24,7 @@ ZTEST(posix_apis, test_spin_init_destroy) zassert_ok(pthread_spin_destroy(&lock), "pthread_spin_destroy() failed"); } -ZTEST(posix_apis, test_spin_descriptor_leak) +ZTEST(spinlock, test_spin_descriptor_leak) { pthread_spinlock_t lock[CONFIG_MAX_PTHREAD_SPINLOCK_COUNT]; @@ -47,7 +47,7 @@ ZTEST(posix_apis, test_spin_descriptor_leak) } } -ZTEST(posix_apis, test_spin_lock_unlock) +ZTEST(spinlock, test_spin_lock_unlock) { pthread_spinlock_t lock; @@ -69,3 +69,5 @@ ZTEST(posix_apis, test_spin_lock_unlock) zassert_ok(pthread_spin_destroy(&lock), "pthread_spin_init() failed"); zassert_equal(pthread_spin_destroy(&lock), EINVAL, "pthread_spin_unlock() did not fail"); } + +ZTEST_SUITE(spinlock, NULL, NULL, NULL, NULL, NULL); diff --git a/tests/posix/common/src/timer.c b/tests/posix/common/src/timer.c index 1a1f7e718de..d5868d2959c 100644 --- a/tests/posix/common/src/timer.c +++ b/tests/posix/common/src/timer.c @@ -95,13 +95,13 @@ void test_timer(int sigev_notify) exp_count, expected_signal_count); } -ZTEST(posix_apis, test_timer) +ZTEST(timer, test_timer) { test_timer(SIGEV_SIGNAL); test_timer(SIGEV_THREAD); } -ZTEST(posix_apis, test_timer_overrun) +ZTEST(timer, test_timer_overrun) { timer_t timerid; struct sigevent sig = { 0 }; @@ -124,3 +124,5 @@ ZTEST(posix_apis, test_timer_overrun) timer_delete(timerid); zassert_equal(overruns, 4, "Number of overruns is incorrect"); } + +ZTEST_SUITE(timer, NULL, NULL, NULL, NULL, NULL); diff --git a/tests/posix/common/src/uname.c b/tests/posix/common/src/uname.c index bda6ce666ea..d41ab8306a1 100644 --- a/tests/posix/common/src/uname.c +++ b/tests/posix/common/src/uname.c @@ -7,7 +7,7 @@ #include #include -ZTEST(posix_apis, test_uname) +ZTEST(uname, test_uname) { struct utsname info; @@ -15,3 +15,5 @@ ZTEST(posix_apis, test_uname) zassert_ok(strncmp(info.sysname, "Zephyr", sizeof(info.sysname))); zassert_ok(strncmp(info.machine, CONFIG_ARCH, sizeof(info.machine))); } + +ZTEST_SUITE(uname, NULL, NULL, NULL, NULL, NULL); From d4c2d4140b82acf0026cdf00e232e55fb8bf3930 Mon Sep 17 00:00:00 2001 From: Yong Cong Sin Date: Mon, 15 Jan 2024 15:17:25 +0800 Subject: [PATCH 2344/3723] tests: posix: common: turn the fdtable init test into a testsuite As there isn't any ZTEST under the `posix_apis` testsuite, its the testsuite is skipped and its setup function never ran, let's convert the fdtable initialization setup function into a test of `posix_apis`. Signed-off-by: Yong Cong Sin --- tests/posix/common/src/_main.c | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/tests/posix/common/src/_main.c b/tests/posix/common/src/_main.c index cfec4adbd44..679795d10f4 100644 --- a/tests/posix/common/src/_main.c +++ b/tests/posix/common/src/_main.c @@ -8,14 +8,12 @@ extern bool fdtable_fd_is_initialized(int fd); -static void *setup(void) +ZTEST(posix_apis, test_fdtable_init) { /* ensure that the the stdin, stdout, and stderr fdtable entries are initialized */ zassert_true(fdtable_fd_is_initialized(0)); zassert_true(fdtable_fd_is_initialized(1)); zassert_true(fdtable_fd_is_initialized(2)); - - return NULL; } -ZTEST_SUITE(posix_apis, NULL, setup, NULL, NULL, NULL); +ZTEST_SUITE(posix_apis, NULL, NULL, NULL, NULL, NULL); From cbc9439bc0ff858e05674f8cc36ab10d8473397e Mon Sep 17 00:00:00 2001 From: Sateesh Kotapati Date: Fri, 12 Jan 2024 10:22:59 +0530 Subject: [PATCH 2345/3723] gecko: se_manager files updated | Update to GSDK 4.4.0 Updated the files present in gecko/se_manager folder in Silabs HAL as per latest version of gecko_sdk. Signed-off-by: Sateesh Kotapati --- west.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/west.yml b/west.yml index afd89e8f802..4cb40c8a773 100644 --- a/west.yml +++ b/west.yml @@ -219,7 +219,7 @@ manifest: groups: - hal - name: hal_silabs - revision: 4cfb0e3e363678dd96e19a5ea4eede771d0e3b1d + revision: 11ab59175a5ded618680a7692dbaae8f4fbd6325 path: modules/hal/silabs groups: - hal From 08d6ff059ef96a04acc3b8ab2c860eab0aedd193 Mon Sep 17 00:00:00 2001 From: Bjarki Arge Andreasen Date: Sun, 26 Nov 2023 11:34:06 +0100 Subject: [PATCH 2346/3723] scripts: dts: gen_defines: Generate interrupt-controller macro Extend the gen_defines.py write_interrupts(node) function to generate macros to get the interrupt controller for an interrupt specifier by idx and by name. The information is already generated by edtlib.py and stored in node.interrupts[].controller. This addition uses the node pointed to by the controller member to generate the following example output define DT_N_S_device1_IRQ_IDX_0_CONTROLLER \ DT_N_S_gpio_800 define DT_N_S_device1_IRQ_NAME_test4_CONTROLLER \ N_S_device1_IRQ_IDX_0_CONTROLLER Signed-off-by: Bjarki Arge Andreasen --- doc/build/dts/macros.bnf | 2 ++ scripts/dts/gen_defines.py | 7 +++++++ 2 files changed, 9 insertions(+) diff --git a/doc/build/dts/macros.bnf b/doc/build/dts/macros.bnf index 66e74bfbf55..c8c99db7ef6 100644 --- a/doc/build/dts/macros.bnf +++ b/doc/build/dts/macros.bnf @@ -40,8 +40,10 @@ node-macro =/ %s"DT_N" path-id %s"_IRQ_NUM" node-macro =/ %s"DT_N" path-id %s"_IRQ_IDX_" DIGIT "_EXISTS" node-macro =/ %s"DT_N" path-id %s"_IRQ_IDX_" DIGIT %s"_VAL_" dt-name [ %s"_EXISTS" ] +node-macro =/ %s"DT_N" path-id %s"_CONTROLLER" node-macro =/ %s"DT_N" path-id %s"_IRQ_NAME_" dt-name %s"_VAL_" dt-name [ %s"_EXISTS" ] +node-macro =/ %s"DT_N" path-id %s"_IRQ_NAME_" dt-name "_CONTROLLER" ; The ranges property is also special. node-macro =/ %s"DT_N" path-id %s"_RANGES_NUM" node-macro =/ %s"DT_N" path-id %s"_RANGES_IDX_" DIGIT "_EXISTS" diff --git a/scripts/dts/gen_defines.py b/scripts/dts/gen_defines.py index 7721b5b4fe8..0d84db4851f 100755 --- a/scripts/dts/gen_defines.py +++ b/scripts/dts/gen_defines.py @@ -477,6 +477,13 @@ def map_arm_gic_irq_type(irq, irq_num): name_vals.append((name_macro, f"DT_{idx_macro}")) name_vals.append((name_macro + "_EXISTS", 1)) + idx_controller_macro = f"{path_id}_IRQ_IDX_{i}_CONTROLLER" + idx_controller_path = f"DT_{irq.controller.z_path_id}" + idx_vals.append((idx_controller_macro, idx_controller_path)) + if irq.name: + name_controller_macro = f"{path_id}_IRQ_NAME_{str2ident(irq.name)}_CONTROLLER" + name_vals.append((name_controller_macro, f"DT_{idx_controller_macro}")) + for macro, val in idx_vals: out_dt_define(macro, val) for macro, val in name_vals: From 6516e7fac2f3f60c8e45c89d9ef307c952a7ec86 Mon Sep 17 00:00:00 2001 From: Bjarki Arge Andreasen Date: Sun, 26 Nov 2023 11:40:29 +0100 Subject: [PATCH 2347/3723] devicetree.h: Add macros for interrupt specifiers intc Add the following macros to devicetree.h to get an interrupt specifier's interrupt controller: DT_IRQ_INTC_BY_IDX(node_id, idx) DT_IRQ_INTC_BY_NAME(node_id, name) DT_IRQ_INTC(node_id) and their INST variants DT_INST_INTC_BY_IDX(inst, idx) DT_INST_INTC_BY_NAME(inst, name) DT_INST_IRQ(inst) which use the newly generated _CONTROLLER output from the previous commit. Signed-off-by: Bjarki Arge Andreasen --- include/zephyr/devicetree.h | 162 ++++++++++++++++++++++++++++++++++++ 1 file changed, 162 insertions(+) diff --git a/include/zephyr/devicetree.h b/include/zephyr/devicetree.h index 397deaa9fab..123159e2184 100644 --- a/include/zephyr/devicetree.h +++ b/include/zephyr/devicetree.h @@ -2399,6 +2399,140 @@ */ #define DT_IRQ(node_id, cell) DT_IRQ_BY_IDX(node_id, 0, cell) +/** + * @brief Get an interrupt specifier's interrupt controller by index + * + * @code{.dts} + * gpio0: gpio0 { + * interrupt-controller; + * #interrupt-cells = <2>; + * }; + * + * foo: foo { + * interrupt-parent = <&gpio0>; + * interrupts = <1 1>, <2 2>; + * }; + * + * bar: bar { + * interrupts-extended = <&gpio0 3 3>, <&pic0 4>; + * }; + * + * pic0: pic0 { + * interrupt-controller; + * #interrupt-cells = <1>; + * + * qux: qux { + * interrupts = <5>, <6>; + * interrupt-names = "int1", "int2"; + * }; + * }; + * @endcode + * + * Example usage: + * + * DT_IRQ_INTC_BY_IDX(DT_NODELABEL(foo), 0) // &gpio0 + * DT_IRQ_INTC_BY_IDX(DT_NODELABEL(foo), 1) // &gpio0 + * DT_IRQ_INTC_BY_IDX(DT_NODELABEL(bar), 0) // &gpio0 + * DT_IRQ_INTC_BY_IDX(DT_NODELABEL(bar), 1) // &pic0 + * DT_IRQ_INTC_BY_IDX(DT_NODELABEL(qux), 0) // &pic0 + * DT_IRQ_INTC_BY_IDX(DT_NODELABEL(qux), 1) // &pic0 + * + * @param node_id node identifier + * @param idx interrupt specifier's index + * @return node_id of interrupt specifier's interrupt controller + */ +#define DT_IRQ_INTC_BY_IDX(node_id, idx) \ + DT_CAT4(node_id, _IRQ_IDX_, idx, _CONTROLLER) + +/** + * @brief Get an interrupt specifier's interrupt controller by name + * + * @code{.dts} + * gpio0: gpio0 { + * interrupt-controller; + * #interrupt-cells = <2>; + * }; + * + * foo: foo { + * interrupt-parent = <&gpio0>; + * interrupts = <1 1>, <2 2>; + * interrupt-names = "int1", "int2"; + * }; + * + * bar: bar { + * interrupts-extended = <&gpio0 3 3>, <&pic0 4>; + * interrupt-names = "int1", "int2"; + * }; + * + * pic0: pic0 { + * interrupt-controller; + * #interrupt-cells = <1>; + * + * qux: qux { + * interrupts = <5>, <6>; + * interrupt-names = "int1", "int2"; + * }; + * }; + * @endcode + * + * Example usage: + * + * DT_IRQ_INTC_BY_NAME(DT_NODELABEL(foo), int1) // &gpio0 + * DT_IRQ_INTC_BY_NAME(DT_NODELABEL(foo), int2) // &gpio0 + * DT_IRQ_INTC_BY_NAME(DT_NODELABEL(bar), int1) // &gpio0 + * DT_IRQ_INTC_BY_NAME(DT_NODELABEL(bar), int2) // &pic0 + * DT_IRQ_INTC_BY_NAME(DT_NODELABEL(qux), int1) // &pic0 + * DT_IRQ_INTC_BY_NAME(DT_NODELABEL(qux), int2) // &pic0 + * + * @param node_id node identifier + * @param name interrupt specifier's name + * @return node_id of interrupt specifier's interrupt controller + */ +#define DT_IRQ_INTC_BY_NAME(node_id, name) \ + DT_CAT4(node_id, _IRQ_NAME_, name, _CONTROLLER) + +/** + * @brief Get an interrupt specifier's interrupt controller + * @note Equivalent to DT_IRQ_INTC_BY_IDX(node_id, 0) + * + * @code{.dts} + * gpio0: gpio0 { + * interrupt-controller; + * #interrupt-cells = <2>; + * }; + * + * foo: foo { + * interrupt-parent = <&gpio0>; + * interrupts = <1 1>; + * }; + * + * bar: bar { + * interrupts-extended = <&gpio0 3 3>; + * }; + * + * pic0: pic0 { + * interrupt-controller; + * #interrupt-cells = <1>; + * + * qux: qux { + * interrupts = <5>; + * }; + * }; + * @endcode + * + * Example usage: + * + * DT_IRQ_INTC(DT_NODELABEL(foo)) // &gpio0 + * DT_IRQ_INTC(DT_NODELABEL(bar)) // &gpio0 + * DT_IRQ_INTC(DT_NODELABEL(qux)) // &pic0 + * + * @param node_id node identifier + * @return node_id of interrupt specifier's interrupt controller + * @see DT_IRQ_INTC_BY_IDX() + */ +#define DT_IRQ_INTC(node_id) \ + DT_IRQ_INTC_BY_IDX(node_id, 0) + /** * @cond INTERNAL_HIDDEN */ @@ -3845,6 +3979,34 @@ #define DT_INST_IRQ_BY_IDX(inst, idx, cell) \ DT_IRQ_BY_IDX(DT_DRV_INST(inst), idx, cell) +/** + * @brief Get a `DT_DRV_COMPAT` interrupt specifier's interrupt controller by index + * @param inst instance number + * @param idx interrupt specifier's index + * @return node_id of interrupt specifier's interrupt controller + */ +#define DT_INST_IRQ_INTC_BY_IDX(inst, idx) \ + DT_IRQ_INTC_BY_IDX(DT_DRV_INST(inst), idx) + +/** + * @brief Get a `DT_DRV_COMPAT` interrupt specifier's interrupt controller by name + * @param inst instance number + * @param name interrupt specifier's name + * @return node_id of interrupt specifier's interrupt controller + */ +#define DT_INST_IRQ_INTC_BY_NAME(inst, name) \ + DT_IRQ_INTC_BY_NAME(DT_DRV_INST(inst), name) + +/** + * @brief Get a `DT_DRV_COMPAT` interrupt specifier's interrupt controller + * @note Equivalent to DT_INST_IRQ_INTC_BY_IDX(node_id, 0) + * @param inst instance number + * @return node_id of interrupt specifier's interrupt controller + * @see DT_INST_IRQ_INTC_BY_IDX() + */ +#define DT_INST_IRQ_INTC(inst) \ + DT_INST_IRQ_INTC_BY_IDX(inst, 0) + /** * @brief Get a `DT_DRV_COMPAT` interrupt specifier value by name * @param inst instance number From 4403d8f4c622fe858a57aeea4b555256102fa890 Mon Sep 17 00:00:00 2001 From: Bjarki Arge Andreasen Date: Fri, 8 Dec 2023 19:52:00 +0100 Subject: [PATCH 2348/3723] tests: lib: devicetree: api: Add tests for IRQ_INTC_* macros Extend api test suite to cover the new devicetree macros. This includes extending the devicetree overlay with two new bindings: - GPIO device which is also an interrupt controller - interrupt holder using interrupts-extended to point to both existing interrupt controller test_intc, and the newly added GPIO device Signed-off-by: Bjarki Arge Andreasen --- dts/bindings/test/vnd,gpio-intc-device.yaml | 29 ++++++++++++++++++ .../test/vnd,interrupt-holder-extended.yaml | 15 ++++++++++ tests/lib/devicetree/api/app.overlay | 19 ++++++++++++ tests/lib/devicetree/api/src/main.c | 30 +++++++++++++++++++ 4 files changed, 93 insertions(+) create mode 100644 dts/bindings/test/vnd,gpio-intc-device.yaml create mode 100644 dts/bindings/test/vnd,interrupt-holder-extended.yaml diff --git a/dts/bindings/test/vnd,gpio-intc-device.yaml b/dts/bindings/test/vnd,gpio-intc-device.yaml new file mode 100644 index 00000000000..b506062792c --- /dev/null +++ b/dts/bindings/test/vnd,gpio-intc-device.yaml @@ -0,0 +1,29 @@ +# Copyright (c) 2023 Bjarki Arge Andreasen +# SPDX-License-Identifier: Apache-2.0 + +description: Test GPIO with INTC node + +compatible: "vnd,gpio-intc-device" + +include: + - gpio-controller.yaml + - interrupt-controller.yaml + - base.yaml + +properties: + reg: + required: true + + "#gpio-cells": + const: 2 + + "#interrupt-cells": + const: 2 + +gpio-cells: + - pin + - flags + +interrupt-cells: + - pin + - flags diff --git a/dts/bindings/test/vnd,interrupt-holder-extended.yaml b/dts/bindings/test/vnd,interrupt-holder-extended.yaml new file mode 100644 index 00000000000..795b15d9313 --- /dev/null +++ b/dts/bindings/test/vnd,interrupt-holder-extended.yaml @@ -0,0 +1,15 @@ +# Copyright (c) 2023 Bjarki Arge Andreasen +# SPDX-License-Identifier: Apache-2.0 + +description: Test Interrupt Controller with extended interrupts + +compatible: "vnd,interrupt-holder-extended" + +include: [base.yaml] + +properties: + interrupts-extended: + required: true + + interrupt-names: + required: true diff --git a/tests/lib/devicetree/api/app.overlay b/tests/lib/devicetree/api/app.overlay index 66ff605bfcd..00fc428d733 100644 --- a/tests/lib/devicetree/api/app.overlay +++ b/tests/lib/devicetree/api/app.overlay @@ -203,6 +203,16 @@ status = "okay"; }; + test_gpio_4: gpio@1234abcd { + compatible = "vnd,gpio-intc-device"; + reg = <0x1234abcd 0x500>; + gpio-controller; + #gpio-cells = <0x2>; + interrupt-controller; + #interrupt-cells = <0x2>; + status = "okay"; + }; + test_i2c: i2c@11112222 { #address-cells = < 1 >; #size-cells = < 0 >; @@ -431,6 +441,15 @@ interrupt-names = "err", "stat", "done"; }; + /* there should only be one of these */ + test_irq_extended: interrupt-holder-extended { + compatible = "vnd,interrupt-holder-extended"; + status = "okay"; + interrupts-extended = <&test_intc 70 7>, + <&test_gpio_4 30 3>; + interrupt-names = "int1", "int2"; + }; + test_fixed_clk: test-fixed-clock { compatible = "fixed-clock"; clock-frequency = <25000000>; diff --git a/tests/lib/devicetree/api/src/main.c b/tests/lib/devicetree/api/src/main.c index 72c5426e01a..19e5c9e4767 100644 --- a/tests/lib/devicetree/api/src/main.c +++ b/tests/lib/devicetree/api/src/main.c @@ -21,12 +21,14 @@ #define TEST_ARRAYS DT_NODELABEL(test_arrays) #define TEST_PH DT_NODELABEL(test_phandles) #define TEST_IRQ DT_NODELABEL(test_irq) +#define TEST_IRQ_EXT DT_NODELABEL(test_irq_extended) #define TEST_TEMP DT_NODELABEL(test_temp_sensor) #define TEST_REG DT_NODELABEL(test_reg) #define TEST_VENDOR DT_NODELABEL(test_vendor) #define TEST_MODEL DT_NODELABEL(test_vendor) #define TEST_ENUM_0 DT_NODELABEL(test_enum_0) #define TEST_64BIT DT_NODELABEL(test_reg_64) +#define TEST_INTC DT_NODELABEL(test_intc) #define TEST_I2C DT_NODELABEL(test_i2c) #define TEST_I2C_DEV DT_PATH(test, i2c_11112222, test_i2c_dev_10) @@ -44,6 +46,7 @@ #define TEST_GPIO_1 DT_NODELABEL(test_gpio_1) #define TEST_GPIO_2 DT_NODELABEL(test_gpio_2) +#define TEST_GPIO_4 DT_NODELABEL(test_gpio_4) #define TEST_GPIO_HOG_1 DT_PATH(test, gpio_deadbeef, test_gpio_hog_1) #define TEST_GPIO_HOG_2 DT_PATH(test, gpio_deadbeef, test_gpio_hog_2) @@ -3149,4 +3152,31 @@ ZTEST(devicetree_api, test_reset) zassert_equal(DT_INST_RESET_ID(0), 10, ""); } +#undef DT_DRV_COMPAT +#define DT_DRV_COMPAT vnd_interrupt_holder_extended +ZTEST(devicetree_api, test_interrupt_controller) +{ + /* DT_IRQ_INTC_BY_IDX */ + zassert_true(DT_SAME_NODE(DT_IRQ_INTC_BY_IDX(TEST_IRQ_EXT, 0), TEST_INTC), ""); + zassert_true(DT_SAME_NODE(DT_IRQ_INTC_BY_IDX(TEST_IRQ_EXT, 1), TEST_GPIO_4), ""); + + /* DT_IRQ_INTC_BY_NAME */ + zassert_true(DT_SAME_NODE(DT_IRQ_INTC_BY_NAME(TEST_IRQ_EXT, int1), TEST_INTC), ""); + zassert_true(DT_SAME_NODE(DT_IRQ_INTC_BY_NAME(TEST_IRQ_EXT, int2), TEST_GPIO_4), ""); + + /* DT_IRQ_INTC */ + zassert_true(DT_SAME_NODE(DT_IRQ_INTC(TEST_IRQ_EXT), TEST_INTC), ""); + + /* DT_INST_IRQ_INTC_BY_IDX */ + zassert_true(DT_SAME_NODE(DT_INST_IRQ_INTC_BY_IDX(0, 0), TEST_INTC), ""); + zassert_true(DT_SAME_NODE(DT_INST_IRQ_INTC_BY_IDX(0, 1), TEST_GPIO_4), ""); + + /* DT_INST_IRQ_INTC_BY_NAME */ + zassert_true(DT_SAME_NODE(DT_INST_IRQ_INTC_BY_NAME(0, int1), TEST_INTC), ""); + zassert_true(DT_SAME_NODE(DT_INST_IRQ_INTC_BY_NAME(0, int2), TEST_GPIO_4), ""); + + /* DT_INST_IRQ_INTC */ + zassert_true(DT_SAME_NODE(DT_INST_IRQ_INTC(0), TEST_INTC), ""); +} + ZTEST_SUITE(devicetree_api, NULL, NULL, NULL, NULL, NULL); From abef8bde4eb9c232d970ea9ed4f605721f40273b Mon Sep 17 00:00:00 2001 From: Anas Nashif Date: Mon, 15 Jan 2024 20:23:53 -0500 Subject: [PATCH 2349/3723] twister: reuse test schema in common section Rather than duplicating the same schema, define it only once and reuse for both common section and tests section. Signed-off-by: Anas Nashif --- scripts/schemas/twister/testsuite-schema.yaml | 590 ++++++------------ 1 file changed, 202 insertions(+), 388 deletions(-) diff --git a/scripts/schemas/twister/testsuite-schema.yaml b/scripts/schemas/twister/testsuite-schema.yaml index cdec09e536c..454959fc608 100644 --- a/scripts/schemas/twister/testsuite-schema.yaml +++ b/scripts/schemas/twister/testsuite-schema.yaml @@ -8,200 +8,210 @@ # # The original spec comes from Zephyr's twister script # +schema;scenario-schema: + type: map + # has to be not-required, otherwise the parser gets + # confused and things it never found it + required: false + mapping: + "arch_exclude": + type: any + required: false + "arch_allow": + type: any + required: false + "testcases": + type: seq + required: false + sequence: + - type: str + "build_only": + type: bool + required: false + "build_on_all": + type: bool + required: false + "depends_on": + type: any + required: false + "extra_args": + type: any + required: false + "extra_configs": + type: seq + required: false + sequence: + - type: str + "extra_conf_files": + type: seq + required: false + sequence: + - type: str + "extra_overlay_confs": + type: seq + required: false + sequence: + - type: str + "extra_dtc_overlay_files": + type: seq + required: false + sequence: + - type: str + "extra_sections": + type: any + required: false + "required_snippets": + type: seq + required: false + sequence: + - type: str + "filter": + type: str + required: false + "levels": + type: seq + required: false + sequence: + - type: str + enum: ["smoke", "unit", "integration", "acceptance", "system", "regression"] + "integration_platforms": + type: seq + required: false + sequence: + - type: str + "ignore_faults": + type: bool + required: false + "ignore_qemu_crash": + type: bool + required: false + "harness": + type: str + required: false + "harness_config": + type: map + required: false + mapping: + "type": + type: str + required: false + "fixture": + type: str + required: false + "ordered": + type: bool + required: false + "repeat": + type: int + required: false + "pytest_root": + type: seq + required: false + sequence: + - type: str + "pytest_args": + type: seq + required: false + sequence: + - type: str + "pytest_dut_scope": + type: str + enum: ["function", "class", "module", "package", "session"] + required: false + "regex": + type: seq + required: false + sequence: + - type: str + "robot_test_path": + type: str + required: false + "record": + type: map + required: false + mapping: + "regex": + type: str + required: true + "bsim_exe_name": + type: str + required: false + "min_ram": + type: int + required: false + "min_flash": + type: int + required: false + "modules": + type: seq + required: false + sequence: + - type: str + "platform_exclude": + type: any + required: false + "platform_allow": + type: any + required: false + "platform_type": + type: seq + required: false + sequence: + - type: str + enum: ["mcu", "qemu", "sim", "unit", "native"] + "platform_key": + required: false + type: seq + matching: "all" + sequence: + - type: str + "simulation_exclude": + type: seq + required: false + sequence: + - type: str + enum: + [ + "qemu", + "simics", + "xt-sim", + "renode", + "nsim", + "mdb-nsim", + "tsim", + "armfvp", + "native", + "custom", + ] + "tags": + type: any + required: false + "timeout": + type: int + required: false + "toolchain_exclude": + type: any + required: false + "toolchain_allow": + type: any + required: false + "type": + type: str + enum: ["unit"] + "skip": + type: bool + required: false + "slow": + type: bool + required: false + "sysbuild": + type: bool + required: false + type: map mapping: "common": - type: map - required: false - mapping: - "arch_exclude": - type: any - required: false - "arch_allow": - type: any - required: false - "build_only": - type: bool - required: false - "build_on_all": - type: bool - required: false - "depends_on": - type: any - required: false - "extra_args": - type: any - required: false - "extra_conf_files": - type: seq - required: false - sequence: - - type: str - "extra_overlay_confs": - type: seq - required: false - sequence: - - type: str - "extra_dtc_overlay_files": - type: seq - required: false - sequence: - - type: str - "extra_sections": - type: any - required: false - "filter": - type: str - required: false - "integration_platforms": - type: seq - required: false - sequence: - - type: str - "ignore_faults": - type: bool - required: false - "ignore_qemu_crash": - type: bool - required: false - "levels": - type: seq - required: false - sequence: - - type: str - enum: ["smoke", "unit", "integration", "acceptance", "system", "regression"] - "testcases": - type: seq - required: false - sequence: - - type: str - "harness": - type: str - required: false - "harness_config": - type: map - required: false - mapping: - "type": - type: str - required: false - "fixture": - type: str - required: false - "ordered": - type: bool - required: false - "repeat": - type: int - required: false - "pytest_root": - type: seq - required: false - sequence: - - type: str - "pytest_args": - type: seq - required: false - sequence: - - type: str - "pytest_dut_scope": - type: str - enum: ["function", "class", "module", "package", "session"] - required: false - "regex": - type: seq - required: false - sequence: - - type: str - "robot_test_path": - type: str - required: false - "record": - type: map - required: false - mapping: - "regex": - type: str - required: true - "bsim_exe_name": - type: str - required: false - "min_ram": - type: int - required: false - "min_flash": - type: int - required: false - "modules": - type: seq - required: false - sequence: - - type: str - "platform_exclude": - type: any - required: false - "platform_allow": - type: any - required: false - "platform_type": - type: seq - required: false - sequence: - - type: str - enum: ["mcu", "qemu", "sim", "unit", "native"] - "platform_key": - required: false - type: seq - matching: "all" - sequence: - - type: str - "required_snippets": - type: seq - required: false - sequence: - - type: str - "simulation_exclude": - type: seq - required: false - sequence: - - type: str - enum: - [ - "qemu", - "simics", - "xt-sim", - "renode", - "nsim", - "mdb-nsim", - "tsim", - "armfvp", - "native", - "custom", - ] - "tags": - type: any - required: false - "timeout": - type: int - required: false - "toolchain_exclude": - type: any - required: false - "toolchain_allow": - type: any - required: false - "type": - type: str - enum: ["unit"] - "skip": - type: bool - required: false - "slow": - type: bool - required: false - "sysbuild": - type: bool - required: false + include: scenario-schema # The sample descriptor, if present "sample": type: map @@ -225,200 +235,4 @@ mapping: # regex;(([a-zA-Z0-9_]+)) for this to work, note below we # make it required: false regex;(([a-zA-Z0-9_]+)): - type: map - # has to be not-required, otherwise the parser gets - # confused and things it never found it - required: false - mapping: - "arch_exclude": - type: any - required: false - "arch_allow": - type: any - required: false - "testcases": - type: seq - required: false - sequence: - - type: str - "build_only": - type: bool - required: false - "build_on_all": - type: bool - required: false - "depends_on": - type: any - required: false - "extra_args": - type: any - required: false - "extra_configs": - type: seq - required: false - sequence: - - type: str - "extra_conf_files": - type: seq - required: false - sequence: - - type: str - "extra_overlay_confs": - type: seq - required: false - sequence: - - type: str - "extra_dtc_overlay_files": - type: seq - required: false - sequence: - - type: str - "extra_sections": - type: any - required: false - "required_snippets": - type: seq - required: false - sequence: - - type: str - "filter": - type: str - required: false - "levels": - type: seq - required: false - sequence: - - type: str - enum: ["smoke", "unit", "integration", "acceptance", "system", "regression"] - "integration_platforms": - type: seq - required: false - sequence: - - type: str - "ignore_faults": - type: bool - required: false - "ignore_qemu_crash": - type: bool - required: false - "harness": - type: str - required: false - "harness_config": - type: map - required: false - mapping: - "type": - type: str - required: false - "fixture": - type: str - required: false - "ordered": - type: bool - required: false - "repeat": - type: int - required: false - "pytest_root": - type: seq - required: false - sequence: - - type: str - "pytest_args": - type: seq - required: false - sequence: - - type: str - "pytest_dut_scope": - type: str - enum: ["function", "class", "module", "package", "session"] - required: false - "regex": - type: seq - required: false - sequence: - - type: str - "robot_test_path": - type: str - required: false - "record": - type: map - required: false - mapping: - "regex": - type: str - required: true - "bsim_exe_name": - type: str - required: false - "min_ram": - type: int - required: false - "min_flash": - type: int - required: false - "modules": - type: seq - required: false - sequence: - - type: str - "platform_exclude": - type: any - required: false - "platform_allow": - type: any - required: false - "platform_type": - type: seq - required: false - sequence: - - type: str - "platform_key": - required: false - type: seq - matching: "all" - sequence: - - type: str - "simulation_exclude": - type: seq - required: false - sequence: - - type: str - enum: - [ - "qemu", - "simics", - "xt-sim", - "renode", - "nsim", - "mdb-nsim", - "tsim", - "armfvp", - "native", - "custom", - ] - "tags": - type: any - required: false - "timeout": - type: int - required: false - "toolchain_exclude": - type: any - required: false - "toolchain_allow": - type: any - required: false - "type": - type: str - enum: ["unit"] - "skip": - type: bool - required: false - "slow": - type: bool - required: false - "sysbuild": - type: bool - required: false + include: scenario-schema From 7e7ab495c36ff6704fd1f764f0e7e2c10ae95870 Mon Sep 17 00:00:00 2001 From: Jordan Yates Date: Mon, 15 Jan 2024 22:22:10 +1000 Subject: [PATCH 2350/3723] wifi: esp_at: compile without `NET_NATIVE_IPV4` Allow the driver to compile without `CONFIG_NET_NATIVE_IPV4`. This can happen if the driver is only desired for SSID scanning. Signed-off-by: Jordan Yates --- drivers/wifi/esp_at/esp.c | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/drivers/wifi/esp_at/esp.c b/drivers/wifi/esp_at/esp.c index 1ac21abc560..bd410bd6dcc 100644 --- a/drivers/wifi/esp_at/esp.c +++ b/drivers/wifi/esp_at/esp.c @@ -443,7 +443,9 @@ static void esp_mgmt_disconnect_work(struct k_work *work) esp_flags_clear(dev, EDF_STA_CONNECTED); esp_mode_switch_submit_if_needed(dev); +#if defined(CONFIG_NET_NATIVE_IPV4) net_if_ipv4_addr_rm(dev->net_iface, &dev->ip); +#endif net_if_dormant_on(dev->net_iface); wifi_mgmt_raise_disconnect_result_event(dev->net_iface, 0); } @@ -509,6 +511,7 @@ static void esp_ip_addr_work(struct k_work *work) return; } +#if defined(CONFIG_NET_NATIVE_IPV4) /* update interface addresses */ net_if_ipv4_set_gw(dev->net_iface, &dev->gw); net_if_ipv4_set_netmask(dev->net_iface, &dev->nm); @@ -516,6 +519,7 @@ static void esp_ip_addr_work(struct k_work *work) net_if_ipv4_addr_add(dev->net_iface, &dev->ip, NET_ADDR_MANUAL, 0); #else net_if_ipv4_addr_add(dev->net_iface, &dev->ip, NET_ADDR_DHCP, 0); +#endif #endif if (IS_ENABLED(CONFIG_WIFI_ESP_AT_DNS_USE)) { @@ -761,7 +765,9 @@ MODEM_CMD_DEFINE(on_cmd_ready) dev->flags = 0; dev->mode = 0; +#if defined(CONFIG_NET_NATIVE_IPV4) net_if_ipv4_addr_rm(dev->net_iface, &dev->ip); +#endif k_work_submit_to_queue(&dev->workq, &dev->init_work); return 0; From 60c0087555fec0dcc9cda36f04faddecb617f708 Mon Sep 17 00:00:00 2001 From: Vinayak Kariappa Chettimada Date: Sun, 12 Feb 2023 18:01:10 +0530 Subject: [PATCH 2351/3723] Bluetooth: Controller: Fix ISO Sync Receiver time reservation calc Fix missing ISO Synchronized Receiver radio event time reservation that did not calculate for all the subevents. Introduce BT_CTLR_SYNC_ISO_RESERVE_MAX Kconfig option to allow using a minimal time reservation if needed to allow other role to pre-empt ISO Synchronized Receiver in pre-transmission and control subevents. Signed-off-by: Vinayak Kariappa Chettimada --- .../bluetooth/controller/Kconfig.ll_sw_split | 21 +++++-- .../bluetooth/controller/ll_sw/ull_sync_iso.c | 61 +++++++++++++++++-- tests/bluetooth/init/prj_ctlr_5_x_dbg.conf | 4 ++ 3 files changed, 75 insertions(+), 11 deletions(-) diff --git a/subsys/bluetooth/controller/Kconfig.ll_sw_split b/subsys/bluetooth/controller/Kconfig.ll_sw_split index ad292a87f0c..3ff4eb222bb 100644 --- a/subsys/bluetooth/controller/Kconfig.ll_sw_split +++ b/subsys/bluetooth/controller/Kconfig.ll_sw_split @@ -470,6 +470,14 @@ config BT_CTRL_ADV_ADI_IN_SCAN_RSP help Enable ADI field in AUX_SCAN_RSP PDU +config BT_CTLR_SCAN_AUX_SET + int "LE Extended Scanning Auxiliary Sets" + depends on BT_OBSERVER && BT_CTLR_ADV_EXT + range 1 64 + default 1 + help + Maximum supported auxiliary channel scan sets. + config BT_CTLR_SCAN_AUX_SYNC_RESERVE_MIN bool "Use minimal Scan Auxiliary and Periodic Sync PDU time reservation" depends on (BT_OBSERVER && BT_CTLR_ADV_EXT) || BT_CTLR_SYNC_PERIODIC @@ -502,13 +510,14 @@ config BT_CTLR_SYNC_PERIODIC_SKIP_ON_SCAN_AUX round robin scheduling to skip the overlapping Periodic Advertising Sync event. This permits new Periodic Advertising peers be discovered. -config BT_CTLR_SCAN_AUX_SET - int "LE Extended Scanning Auxiliary Sets" - depends on BT_OBSERVER && BT_CTLR_ADV_EXT - range 1 64 - default 1 +config BT_CTLR_SYNC_ISO_RESERVE_MAX + bool "Use maximum ISO Synchronized Receiver event time reservation" + depends on BT_CTLR_SYNC_ISO + default y help - Maximum supported auxiliary channel scan sets. + Use maximum ISO Synchronized Receiver event time reservation. If + disabled, then time reservation does not include the pre-transmissions + and any Control subevents. config BT_CTLR_ADV_ENABLE_STRICT bool "Enforce Strict Advertising Enable/Disable" diff --git a/subsys/bluetooth/controller/ll_sw/ull_sync_iso.c b/subsys/bluetooth/controller/ll_sw/ull_sync_iso.c index 2287a2bc356..606077d9dae 100644 --- a/subsys/bluetooth/controller/ll_sw/ull_sync_iso.c +++ b/subsys/bluetooth/controller/ll_sw/ull_sync_iso.c @@ -358,9 +358,13 @@ void ull_sync_iso_setup(struct ll_sync_iso_set *sync_iso, struct pdu_big_info *bi; uint32_t ready_delay_us; uint32_t ticks_expire; + uint32_t ctrl_spacing; + uint32_t pdu_spacing; uint32_t interval_us; uint32_t ticks_diff; struct pdu_adv *pdu; + uint32_t slot_us; + uint8_t num_bis; uint8_t bi_size; uint8_t handle; uint32_t ret; @@ -512,17 +516,64 @@ void ull_sync_iso_setup(struct ll_sync_iso_set *sync_iso, interval_us -= lll->window_widening_periodic_us; + /* Calculate ISO Receiver BIG event timings */ + pdu_spacing = PDU_BIS_US(lll->max_pdu, lll->enc, lll->phy, + PHY_FLAGS_S8) + + EVENT_MSS_US; + ctrl_spacing = PDU_BIS_US(sizeof(struct pdu_big_ctrl), lll->enc, + lll->phy, PHY_FLAGS_S8); + + /* Number of maximum BISes to sync from the first BIS to sync */ + /* NOTE: When ULL scheduling is implemented for subevents, then update + * the time reservation as required. + */ + num_bis = lll->num_bis - (stream->bis_index - 1U); + + /* 1. Maximum PDU transmission time in 1M/2M/S8 PHY is 17040 us, or + * represented in 15-bits. + * 2. NSE in the range 1 to 31 is represented in 5-bits + * 3. num_bis in the range 1 to 31 is represented in 5-bits + * + * Hence, worst case event time can be represented in 25-bits plus + * one each bit for added ctrl_spacing and radio event overheads. I.e. + * 27-bits required and sufficiently covered by using 32-bit data type + * for time_us. + */ + + if (IS_ENABLED(CONFIG_BT_CTLR_SYNC_ISO_RESERVE_MAX)) { + /* Maximum time reservation for both sequential and interleaved + * packing. + */ + slot_us = (pdu_spacing * lll->nse * num_bis) + ctrl_spacing; + + } else if (lll->bis_spacing >= (lll->sub_interval * lll->nse)) { + /* Time reservation omitting PTC subevents in sequetial + * packing. + */ + slot_us = pdu_spacing * ((lll->nse * num_bis) - lll->ptc); + + } else { + /* Time reservation omitting PTC subevents in interleaved + * packing. + */ + slot_us = pdu_spacing * ((lll->nse - lll->ptc) * num_bis); + } + + /* Add radio ready delay */ + slot_us += ready_delay_us; + + /* Add implementation defined radio event overheads */ + if (IS_ENABLED(CONFIG_BT_CTLR_EVENT_OVERHEAD_RESERVE_MAX)) { + slot_us += EVENT_OVERHEAD_START_US + EVENT_OVERHEAD_END_US; + } + /* TODO: active_to_start feature port */ sync_iso->ull.ticks_active_to_start = 0U; sync_iso->ull.ticks_prepare_to_start = HAL_TICKER_US_TO_TICKS(EVENT_OVERHEAD_XTAL_US); sync_iso->ull.ticks_preempt_to_start = HAL_TICKER_US_TO_TICKS(EVENT_OVERHEAD_PREEMPT_MIN_US); - sync_iso->ull.ticks_slot = HAL_TICKER_US_TO_TICKS_CEIL( - EVENT_OVERHEAD_START_US + ready_delay_us + - PDU_BIS_MAX_US(PDU_AC_EXT_PAYLOAD_SIZE_MAX, lll->enc, - lll->phy) + - EVENT_OVERHEAD_END_US); + sync_iso->ull.ticks_slot = HAL_TICKER_US_TO_TICKS_CEIL(slot_us); ticks_slot_offset = MAX(sync_iso->ull.ticks_active_to_start, sync_iso->ull.ticks_prepare_to_start); diff --git a/tests/bluetooth/init/prj_ctlr_5_x_dbg.conf b/tests/bluetooth/init/prj_ctlr_5_x_dbg.conf index 03e6838e3ed..0436807e8d2 100644 --- a/tests/bluetooth/init/prj_ctlr_5_x_dbg.conf +++ b/tests/bluetooth/init/prj_ctlr_5_x_dbg.conf @@ -35,6 +35,10 @@ CONFIG_BT_CTLR_ADV_INDICATION=y CONFIG_BT_CTLR_SCAN_REQ_NOTIFY=y CONFIG_BT_CTLR_SCAN_REQ_RSSI=y CONFIG_BT_CTLR_SCAN_INDICATION=y +CONFIG_BT_CTLR_ADV_RESERVE_MAX=n +CONFIG_BT_CTLR_ADV_ISO_RESERVE_MAX=n +CONFIG_BT_CTLR_SYNC_ISO_RESERVE_MAX=n +CONFIG_BT_CTLR_CENTRAL_RESERVE_MAX=n CONFIG_BT_CTLR_EVENT_OVERHEAD_RESERVE_MAX=n CONFIG_BT_CTLR_PROFILE_ISR=y CONFIG_BT_CTLR_DEBUG_PINS=y From 2dcb91ab46bc94a770543a55da6e192bbb8b7559 Mon Sep 17 00:00:00 2001 From: Jonathan Rico Date: Thu, 11 Jan 2024 17:44:39 +0100 Subject: [PATCH 2352/3723] Bluetooth: L2CAP: extract LE part of `bt_l2cap_chan_send` Separate most of the param checking in `bt_l2cap_chan_send()`, with the logic in `bt_l2cap_dyn_chan_send()`. Signed-off-by: Jonathan Rico --- subsys/bluetooth/host/l2cap.c | 60 +++++++++++++++++++++++------------ 1 file changed, 39 insertions(+), 21 deletions(-) diff --git a/subsys/bluetooth/host/l2cap.c b/subsys/bluetooth/host/l2cap.c index 833948730f5..90e826ce39f 100644 --- a/subsys/bluetooth/host/l2cap.c +++ b/subsys/bluetooth/host/l2cap.c @@ -3116,33 +3116,13 @@ int bt_l2cap_chan_disconnect(struct bt_l2cap_chan *chan) return 0; } -int bt_l2cap_chan_send(struct bt_l2cap_chan *chan, struct net_buf *buf) +static int bt_l2cap_dyn_chan_send(struct bt_l2cap_le_chan *le_chan, struct net_buf *buf) { - struct bt_l2cap_le_chan *le_chan = BT_L2CAP_LE_CHAN(chan); struct l2cap_tx_meta_data *data; void *old_user_data = l2cap_tx_meta_data(buf); uint16_t sdu_len; int err; - if (!buf) { - return -EINVAL; - } - - LOG_DBG("chan %p buf %p len %zu", chan, buf, net_buf_frags_len(buf)); - - if (!chan->conn || chan->conn->state != BT_CONN_CONNECTED) { - return -ENOTCONN; - } - - if (atomic_test_bit(chan->status, BT_L2CAP_STATUS_SHUTDOWN)) { - return -ESHUTDOWN; - } - - if (IS_ENABLED(CONFIG_BT_BREDR) && - chan->conn->type == BT_CONN_TYPE_BR) { - return bt_l2cap_br_chan_send_cb(chan, buf, NULL, NULL); - } - sdu_len = net_buf_frags_len(buf); if (sdu_len > le_chan->tx.mtu) { @@ -3219,4 +3199,42 @@ int bt_l2cap_chan_send(struct bt_l2cap_chan *chan, struct net_buf *buf) return err; } +int bt_l2cap_chan_send(struct bt_l2cap_chan *chan, struct net_buf *buf) +{ + if (!buf || !chan) { + return -EINVAL; + } + + LOG_DBG("chan %p buf %p len %zu", chan, buf, net_buf_frags_len(buf)); + + if (!chan->conn || chan->conn->state != BT_CONN_CONNECTED) { + return -ENOTCONN; + } + + if (atomic_test_bit(chan->status, BT_L2CAP_STATUS_SHUTDOWN)) { + return -ESHUTDOWN; + } + + if (IS_ENABLED(CONFIG_BT_BREDR) && + chan->conn->type == BT_CONN_TYPE_BR) { + return bt_l2cap_br_chan_send_cb(chan, buf, NULL, NULL); + } + + /* Sending over static channels is not supported by this fn. Use + * `bt_l2cap_send()` if external to this file, or `l2cap_send` if + * internal. + */ + if (IS_ENABLED(CONFIG_BT_L2CAP_DYNAMIC_CHANNEL)) { + struct bt_l2cap_le_chan *le_chan = BT_L2CAP_LE_CHAN(chan); + + __ASSERT_NO_MSG(le_chan); + __ASSERT_NO_MSG(L2CAP_LE_CID_IS_DYN(le_chan->tx.cid)); + + return bt_l2cap_dyn_chan_send(le_chan, buf); + } + + LOG_DBG("Invalid channel type (chan %p)", chan); + + return -EINVAL; +} #endif /* CONFIG_BT_L2CAP_DYNAMIC_CHANNEL */ From 81d524d0816a3567c05d267a1f5ca012624e3e71 Mon Sep 17 00:00:00 2001 From: Jonathan Rico Date: Thu, 11 Jan 2024 17:51:29 +0100 Subject: [PATCH 2353/3723] Bluetooth: L2CAP: always send from workqueue Always pull from the channel queue from the system workqueue context. This simplifies debugging. This also allows us to remove `sent` from the metadata struct. Signed-off-by: Jonathan Rico --- include/zephyr/bluetooth/l2cap.h | 2 +- subsys/bluetooth/host/l2cap.c | 62 ++++++++++---------------------- 2 files changed, 19 insertions(+), 45 deletions(-) diff --git a/include/zephyr/bluetooth/l2cap.h b/include/zephyr/bluetooth/l2cap.h index 7177d388015..d4046c431fb 100644 --- a/include/zephyr/bluetooth/l2cap.h +++ b/include/zephyr/bluetooth/l2cap.h @@ -593,7 +593,7 @@ int bt_l2cap_chan_disconnect(struct bt_l2cap_chan *chan); * @note Buffer ownership is transferred to the stack in case of success, in * case of an error the caller retains the ownership of the buffer. * - * @return Bytes sent in case of success or negative value in case of error. + * @return 0 in case of success or negative value in case of error. */ int bt_l2cap_chan_send(struct bt_l2cap_chan *chan, struct net_buf *buf); diff --git a/subsys/bluetooth/host/l2cap.c b/subsys/bluetooth/host/l2cap.c index 90e826ce39f..e9a6e744c5e 100644 --- a/subsys/bluetooth/host/l2cap.c +++ b/subsys/bluetooth/host/l2cap.c @@ -71,7 +71,6 @@ NET_BUF_POOL_FIXED_DEFINE(disc_pool, 1, #define l2cap_remove_ident(conn, ident) __l2cap_lookup_ident(conn, ident, true) struct l2cap_tx_meta_data { - int sent; uint16_t cid; bt_conn_tx_cb_t cb; void *user_data; @@ -924,24 +923,23 @@ static struct net_buf *l2cap_chan_le_get_tx_buf(struct bt_l2cap_le_chan *ch) } static int l2cap_chan_le_send_sdu(struct bt_l2cap_le_chan *ch, - struct net_buf **buf, uint16_t sent); + struct net_buf **buf); static void l2cap_chan_tx_process(struct k_work *work) { struct bt_l2cap_le_chan *ch; struct net_buf *buf; + int ret; ch = CONTAINER_OF(k_work_delayable_from_work(work), struct bt_l2cap_le_chan, tx_work); /* Resume tx in case there are buffers in the queue */ while ((buf = l2cap_chan_le_get_tx_buf(ch))) { - int sent = l2cap_tx_meta_data(buf)->sent; - - LOG_DBG("buf %p sent %u", buf, sent); + LOG_DBG("buf %p", buf); - sent = l2cap_chan_le_send_sdu(ch, &buf, sent); - if (sent < 0) { - if (sent == -EAGAIN) { + ret = l2cap_chan_le_send_sdu(ch, &buf); + if (ret < 0) { + if (ret == -EAGAIN) { ch->tx_buf = buf; /* If we don't reschedule, and the app doesn't nudge l2cap (e.g. by * sending another SDU), the channel will be stuck in limbo. To @@ -949,7 +947,7 @@ static void l2cap_chan_tx_process(struct k_work *work) */ k_work_schedule(&ch->tx_work, K_MSEC(CONFIG_BT_L2CAP_RESCHED_MS)); } else { - l2cap_tx_buf_destroy(ch->chan.conn, buf, sent); + l2cap_tx_buf_destroy(ch->chan.conn, buf, ret); } break; } @@ -2060,10 +2058,11 @@ static int l2cap_chan_le_send(struct bt_l2cap_le_chan *ch, } static int l2cap_chan_le_send_sdu(struct bt_l2cap_le_chan *ch, - struct net_buf **buf, uint16_t sent) + struct net_buf **buf) { int ret, total_len; struct net_buf *frag; + int sent = 0; total_len = net_buf_frags_len(*buf) + sent; @@ -2081,10 +2080,6 @@ static int l2cap_chan_le_send_sdu(struct bt_l2cap_le_chan *ch, ret = l2cap_chan_le_send(ch, frag, 0); if (ret < 0) { - if (ret == -EAGAIN) { - /* Store sent data into user_data */ - l2cap_tx_meta_data(frag)->sent = sent; - } *buf = frag; return ret; } @@ -3119,13 +3114,13 @@ int bt_l2cap_chan_disconnect(struct bt_l2cap_chan *chan) static int bt_l2cap_dyn_chan_send(struct bt_l2cap_le_chan *le_chan, struct net_buf *buf) { struct l2cap_tx_meta_data *data; - void *old_user_data = l2cap_tx_meta_data(buf); - uint16_t sdu_len; - int err; + uint16_t sdu_len = net_buf_frags_len(buf); - sdu_len = net_buf_frags_len(buf); + LOG_DBG("chan %p buf %p", le_chan, buf); if (sdu_len > le_chan->tx.mtu) { + LOG_ERR("attempt to send %u bytes on %u MTU chan", + sdu_len, le_chan->tx.mtu); return -EMSGSIZE; } @@ -3165,38 +3160,17 @@ static int bt_l2cap_dyn_chan_send(struct bt_l2cap_le_chan *le_chan, struct net_b */ net_buf_push_le16(buf, sdu_len); - data->sent = 0; + /* Put buffer on TX queue */ data->cid = le_chan->tx.cid; data->cb = NULL; data->user_data = NULL; l2cap_tx_meta_data(buf) = data; + net_buf_put(&le_chan->tx_queue, buf); - /* Queue if there are pending segments left from previous packet or - * there are no credits available. - */ - if (le_chan->tx_buf || !k_fifo_is_empty(&le_chan->tx_queue) || - !atomic_get(&le_chan->tx.credits)) { - l2cap_tx_meta_data(buf)->sent = 0; - net_buf_put(&le_chan->tx_queue, buf); - k_work_reschedule(&le_chan->tx_work, K_NO_WAIT); - return 0; - } - - err = l2cap_chan_le_send_sdu(le_chan, &buf, 0); - if (err < 0) { - if (err == -EAGAIN && l2cap_tx_meta_data(buf)->sent) { - /* Queue buffer if at least one segment could be sent */ - net_buf_put(&le_chan->tx_queue, buf); - return l2cap_tx_meta_data(buf)->sent; - } - - LOG_ERR("failed to send message %d", err); + /* Always process the queue in the same context */ + k_work_reschedule(&le_chan->tx_work, K_NO_WAIT); - l2cap_tx_meta_data(buf) = old_user_data; - free_tx_meta_data(data); - } - - return err; + return 0; } int bt_l2cap_chan_send(struct bt_l2cap_chan *chan, struct net_buf *buf) From 98a631b5bcae97d5b1ae13841a2132a2a67b4421 Mon Sep 17 00:00:00 2001 From: Yong Cong Sin Date: Fri, 12 Jan 2024 15:02:28 +0800 Subject: [PATCH 2354/3723] posix: pthread: allow `oldstate` & `oldtype` to be `NULL` The POSIX standard doesn't specify if the argument to store previous state/type in `pthread_setcancelstate`/`pthread_setcancelstate` can be `NULL`, but threading implementations in Linux & Apache NuttX permit the arguments to be `NULL`. This commit changes Zephyr's implementation to mimic that of Linux & NuttX, so that user do not get caught off-guard by NULL pointer dereferencing when porting code over from those OSes. Updated test accordingly. Signed-off-by: Yong Cong Sin --- lib/posix/pthread.c | 8 ++++++-- tests/posix/common/src/pthread.c | 7 +++---- 2 files changed, 9 insertions(+), 6 deletions(-) diff --git a/lib/posix/pthread.c b/lib/posix/pthread.c index 14760908031..a2e9a5b736c 100644 --- a/lib/posix/pthread.c +++ b/lib/posix/pthread.c @@ -572,7 +572,9 @@ int pthread_setcancelstate(int state, int *oldstate) } key = k_spin_lock(&pthread_pool_lock); - *oldstate = t->cancel_state; + if (oldstate != NULL) { + *oldstate = t->cancel_state; + } t->cancel_state = state; cancel_pending = t->cancel_pending; k_spin_unlock(&pthread_pool_lock, key); @@ -605,7 +607,9 @@ int pthread_setcanceltype(int type, int *oldtype) } key = k_spin_lock(&pthread_pool_lock); - *oldtype = t->cancel_type; + if (oldtype != NULL) { + *oldtype = t->cancel_type; + } t->cancel_type = type; k_spin_unlock(&pthread_pool_lock, key); diff --git a/tests/posix/common/src/pthread.c b/tests/posix/common/src/pthread.c index 02d9465081e..feab8d64d59 100644 --- a/tests/posix/common/src/pthread.c +++ b/tests/posix/common/src/pthread.c @@ -178,7 +178,7 @@ static int barrier_test_done(void) static void *thread_top_term(void *p1) { pthread_t self; - int oldstate, policy, ret; + int policy, ret; int id = POINTER_TO_INT(p1); struct sched_param param, getschedparam; @@ -198,7 +198,7 @@ static void *thread_top_term(void *p1) getschedparam.sched_priority); if (id % 2) { - ret = pthread_setcancelstate(PTHREAD_CANCEL_DISABLE, &oldstate); + ret = pthread_setcancelstate(PTHREAD_CANCEL_DISABLE, NULL); zassert_false(ret, "Unable to set cancel state!"); } @@ -309,7 +309,6 @@ ZTEST(pthread, test_pthread_execution) ZTEST(pthread, test_pthread_termination) { int32_t i, ret; - int oldstate; pthread_t newthread[N_THR_T] = {0}; void *retval; @@ -319,7 +318,7 @@ ZTEST(pthread, test_pthread_termination) } /* TESTPOINT: Try setting invalid cancel state to current thread */ - ret = pthread_setcancelstate(PTHREAD_CANCEL_INVALID, &oldstate); + ret = pthread_setcancelstate(PTHREAD_CANCEL_INVALID, NULL); zassert_equal(ret, EINVAL, "invalid cancel state set!"); for (i = 0; i < N_THR_T; i++) { From 72a51c7ec45b1b02c1fc13c3a655792e898afa27 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Gerhard=20J=C3=B6rges?= Date: Wed, 10 Jan 2024 14:20:07 +0100 Subject: [PATCH 2355/3723] net: add set hostname function MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This commit adds a function to set the hostname on runtime. Signed-off-by: Gerhard Jörges --- include/zephyr/net/hostname.h | 31 +++++++++++++++++++++++++++---- subsys/net/Kconfig.hostname | 17 ++++++++++++++++- subsys/net/hostname.c | 21 +++++++++++++++++++-- 3 files changed, 62 insertions(+), 7 deletions(-) diff --git a/include/zephyr/net/hostname.h b/include/zephyr/net/hostname.h index 292c4d62d72..196e9ab18e7 100644 --- a/include/zephyr/net/hostname.h +++ b/include/zephyr/net/hostname.h @@ -22,10 +22,16 @@ extern "C" { * @{ */ -#define NET_HOSTNAME_MAX_LEN \ - (sizeof(CONFIG_NET_HOSTNAME) - 1 + \ - (IS_ENABLED(CONFIG_NET_HOSTNAME_UNIQUE) ? \ - sizeof("0011223344556677") - 1 : 0)) +#if defined(CONFIG_NET_HOSTNAME_MAX_LEN) +#define NET_HOSTNAME_MAX_LEN \ + MAX(CONFIG_NET_HOSTNAME_MAX_LEN, \ + (sizeof(CONFIG_NET_HOSTNAME) - 1 + \ + (IS_ENABLED(CONFIG_NET_HOSTNAME_UNIQUE) ? sizeof("0011223344556677") - 1 : 0))) +#else +#define NET_HOSTNAME_MAX_LEN \ + (sizeof(CONFIG_NET_HOSTNAME) - 1 + \ + (IS_ENABLED(CONFIG_NET_HOSTNAME_UNIQUE) ? sizeof("0011223344556677") - 1 : 0)) +#endif #if defined(CONFIG_NET_HOSTNAME_ENABLE) #define NET_HOSTNAME_SIZE NET_HOSTNAME_MAX_LEN + 1 @@ -49,6 +55,23 @@ static inline const char *net_hostname_get(void) } #endif /* CONFIG_NET_HOSTNAME_ENABLE */ +/** + * @brief Set the device hostname + * + * @param host new hostname as char array. + * @param len Length of the hostname array. + * + * @return 0 if ok, <0 on error + */ +#if defined(CONFIG_NET_HOSTNAME_DYNAMIC) +int net_hostname_set(char *host, size_t len); +#else +static inline int net_hostname_set(char *host, size_t len) +{ + return -ENOTSUP; +} +#endif + /** * @brief Initialize and set the device hostname. * diff --git a/subsys/net/Kconfig.hostname b/subsys/net/Kconfig.hostname index eb5f32756a2..eb082d93476 100644 --- a/subsys/net/Kconfig.hostname +++ b/subsys/net/Kconfig.hostname @@ -17,10 +17,25 @@ config NET_HOSTNAME help The string should be a valid hostname. +config NET_HOSTNAME_DYNAMIC + bool "Allow the hostname to be set by the application" + depends on !NET_HOSTNAME_UNIQUE_UPDATE + help + This will enable the net_hostname_set() function. NET_HOSTNAME + will be used as default hostname. + +config NET_HOSTNAME_MAX_LEN + int "The maximum allowed hostname length" + depends on NET_HOSTNAME_DYNAMIC + range 1 63 + default 63 + help + This will set the number of bytes allocateed for the hostname. + config NET_HOSTNAME_UNIQUE bool "Make hostname unique" help - This will append link address to hostname to create a unique + This will append link address to NET_HOSTNAME to create a unique hostname. For example, zephyr00005e005357 could be the hostname if this setting is enabled. diff --git a/subsys/net/hostname.c b/subsys/net/hostname.c index 073756eb077..fa22a11e598 100644 --- a/subsys/net/hostname.c +++ b/subsys/net/hostname.c @@ -37,6 +37,23 @@ const char *net_hostname_get(void) return hostname; } +#if defined(CONFIG_NET_HOSTNAME_DYNAMIC) +int net_hostname_set(char *host, size_t len) +{ + if (len > NET_HOSTNAME_MAX_LEN) { + return -ENOMEM; + } + + memcpy(hostname, host, len); + hostname[len] = 0; + + NET_DBG("New hostname %s", hostname); + trigger_net_event(); + + return 0; +} +#endif + #if defined(CONFIG_NET_HOSTNAME_UNIQUE) int net_hostname_set_postfix(const uint8_t *hostname_postfix, int postfix_len) @@ -62,8 +79,8 @@ int net_hostname_set_postfix(const uint8_t *hostname_postfix, } for (i = 0; i < postfix_len; i++, pos += 2) { - snprintk(&hostname[sizeof(CONFIG_NET_HOSTNAME) - 1 + pos], - 2 + 1, "%02x", hostname_postfix[i]); + snprintk(&hostname[sizeof(CONFIG_NET_HOSTNAME) - 1 + pos], 2 + 1, "%02x", + hostname_postfix[i]); } NET_DBG("New hostname %s", hostname); From 13740696c715afa29e0c1cad5f871fc4ea892c56 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Gerhard=20J=C3=B6rges?= Date: Thu, 11 Jan 2024 12:59:09 +0100 Subject: [PATCH 2356/3723] tests: net: hostname: add test for net_hostname_set MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Add test that sets the hostname. Signed-off-by: Gerhard Jörges --- tests/net/hostname/src/main.c | 8 ++++++++ tests/net/hostname/testcase.yaml | 10 ++++++++++ 2 files changed, 18 insertions(+) diff --git a/tests/net/hostname/src/main.c b/tests/net/hostname/src/main.c index 58a7db6b9ae..679018de7ad 100644 --- a/tests/net/hostname/src/main.c +++ b/tests/net/hostname/src/main.c @@ -381,6 +381,14 @@ ZTEST(net_hostname, test_hostname_set) zassert_equal(ret, -EALREADY, "Could set hostname postfix (%d)", ret); } + + if (IS_ENABLED(CONFIG_NET_HOSTNAME_DYNAMIC)) { + int ret; + + ret = net_hostname_set("foobar", sizeof("foobar") - 1); + zassert_equal(ret, 0, "Could not set hostname (%d)", ret); + zassert_mem_equal("foobar", net_hostname_get(), sizeof("foobar")-1); + } } #ifdef CONFIG_NET_MGMT_EVENT diff --git a/tests/net/hostname/testcase.yaml b/tests/net/hostname/testcase.yaml index 67c02bc418a..61bb3038cd1 100644 --- a/tests/net/hostname/testcase.yaml +++ b/tests/net/hostname/testcase.yaml @@ -8,9 +8,19 @@ tests: net.hostname: extra_configs: - CONFIG_NET_HOSTNAME_UNIQUE=n + - CONFIG_NET_HOSTNAME_DYNAMIC=n net.hostname.unique: extra_configs: - CONFIG_NET_HOSTNAME_UNIQUE=y + - CONFIG_NET_HOSTNAME_DYNAMIC=n + net.hostname.dynamic: + extra_configs: + - CONFIG_NET_HOSTNAME_UNIQUE=n + - CONFIG_NET_HOSTNAME_DYNAMIC=y + net.hostname.unique.dynamic: + extra_configs: + - CONFIG_NET_HOSTNAME_UNIQUE=y + - CONFIG_NET_HOSTNAME_DYNAMIC=y net.hostname.event: extra_configs: - CONFIG_NET_MGMT=y From 2a0e5e93f355c7adbb60155ce859992205e35299 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Gerhard=20J=C3=B6rges?= Date: Fri, 12 Jan 2024 14:49:54 +0100 Subject: [PATCH 2357/3723] logging: net: update hostname MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This commit adds a function that updates the hostname displayed by the net backend. It is called by the network stack when the hostname is updated. Signed-off-by: Gerhard Jörges --- include/zephyr/logging/log_backend_net.h | 19 +++++++++++++++++++ subsys/logging/backends/log_backend_net.c | 8 ++++++++ subsys/net/hostname.c | 5 +++++ 3 files changed, 32 insertions(+) diff --git a/include/zephyr/logging/log_backend_net.h b/include/zephyr/logging/log_backend_net.h index 9141b481b8d..cde5ff3ea28 100644 --- a/include/zephyr/logging/log_backend_net.h +++ b/include/zephyr/logging/log_backend_net.h @@ -27,6 +27,25 @@ extern "C" { */ bool log_backend_net_set_addr(const char *addr); +/** + * @brief update the hostname + * + * @details This function allows to update the hostname displayed by the logging backend. It will be + * called by the network stack if the hostname is set with net_hostname_set(). + * + * @param hostname new hostname as char array. + * @param len Length of the hostname array. + */ +#if defined(CONFIG_NET_HOSTNAME_ENABLE) +void log_backend_net_hostname_set(char *hostname, size_t len); +#else +static inline void log_backend_net_hostname_set(const char *hostname, size_t len) +{ + ARG_UNUSED(hostname); + ARG_UNUSED(len); +} +#endif + #ifdef __cplusplus } #endif diff --git a/subsys/logging/backends/log_backend_net.c b/subsys/logging/backends/log_backend_net.c index 0681e5901c7..405bb563b65 100644 --- a/subsys/logging/backends/log_backend_net.c +++ b/subsys/logging/backends/log_backend_net.c @@ -235,6 +235,14 @@ bool log_backend_net_set_addr(const char *addr) return ret; } +#if defined(CONFIG_NET_HOSTNAME_ENABLE) +void log_backend_net_hostname_set(char *hostname, size_t len) +{ + (void)strncpy(dev_hostname, hostname, MIN(len, MAX_HOSTNAME_LEN)); + log_output_hostname_set(&log_output_net, dev_hostname); +} +#endif + static void init_net(struct log_backend const *const backend) { ARG_UNUSED(backend); diff --git a/subsys/net/hostname.c b/subsys/net/hostname.c index fa22a11e598..121c200013a 100644 --- a/subsys/net/hostname.c +++ b/subsys/net/hostname.c @@ -16,6 +16,7 @@ LOG_MODULE_REGISTER(net_hostname, CONFIG_NET_HOSTNAME_LOG_LEVEL); #include #include #include +#include static char hostname[NET_HOSTNAME_SIZE]; @@ -30,6 +31,10 @@ static void trigger_net_event(void) } else { net_mgmt_event_notify(NET_EVENT_HOSTNAME_CHANGED, NULL); } + + if (IS_ENABLED(CONFIG_LOG_BACKEND_NET)) { + log_backend_net_hostname_set(hostname, sizeof(hostname)); + } } const char *net_hostname_get(void) From 08cd5eb91d7195e0ee681171ed4f3ac5941e4c62 Mon Sep 17 00:00:00 2001 From: HaiLong Yang Date: Wed, 20 Dec 2023 09:39:58 +0800 Subject: [PATCH 2358/3723] drivers: display: update otm8009a config OTM8009A_MCS_NO_DOC2(0xCFD0U) only write buf[0], but write length set to 3. Signed-off-by: HaiLong Yang --- drivers/display/display_otm8009a.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/display/display_otm8009a.c b/drivers/display/display_otm8009a.c index c2349a3dfd6..5f00ac3a13c 100644 --- a/drivers/display/display_otm8009a.c +++ b/drivers/display/display_otm8009a.c @@ -324,7 +324,7 @@ static int otm8009a_configure(const struct device *dev) /* not documented */ buf[0] = 0x00; - ret = otm8009a_mcs_write(dev, OTM8009A_MCS_NO_DOC2, buf, 3); + ret = otm8009a_mcs_write(dev, OTM8009A_MCS_NO_DOC2, buf, 1); if (ret < 0) { return ret; } From 83f89da24ed1989f59dd0d294904409792b0a91d Mon Sep 17 00:00:00 2001 From: HaiLong Yang Date: Thu, 14 Dec 2023 10:52:29 +0800 Subject: [PATCH 2359/3723] drivers: memc: stm32 fmc add clock source select FMC default clock is hclk, it may affected by sys_ck change. Signed-off-by: HaiLong Yang --- drivers/memc/memc_stm32.c | 28 ++++++++++++++++++++++++---- 1 file changed, 24 insertions(+), 4 deletions(-) diff --git a/drivers/memc/memc_stm32.c b/drivers/memc/memc_stm32.c index 27786c16123..1609926b888 100644 --- a/drivers/memc/memc_stm32.c +++ b/drivers/memc/memc_stm32.c @@ -21,9 +21,18 @@ LOG_MODULE_REGISTER(memc_stm32, CONFIG_MEMC_LOG_LEVEL); #error "No compatible FMC devicetree node found" #endif +/* This symbol takes the value 1 if one of the device instances */ +/* is configured in dts with a domain clock */ +#if STM32_DT_INST_DEV_DOMAIN_CLOCK_SUPPORT +#define STM32_FMC_DOMAIN_CLOCK_SUPPORT 1 +#else +#define STM32_FMC_DOMAIN_CLOCK_SUPPORT 0 +#endif + struct memc_stm32_config { uint32_t fmc; - struct stm32_pclken pclken; + const struct stm32_pclken *pclken; + size_t pclk_len; const struct pinctrl_dev_config *pcfg; }; @@ -49,12 +58,21 @@ static int memc_stm32_init(const struct device *dev) return -ENODEV; } - r = clock_control_on(clk, (clock_control_subsys_t)&config->pclken); + r = clock_control_on(clk, (clock_control_subsys_t)&config->pclken[0]); if (r < 0) { LOG_ERR("Could not initialize FMC clock (%d)", r); return r; } + if (IS_ENABLED(STM32_FMC_DOMAIN_CLOCK_SUPPORT) && (config->pclk_len > 1)) { + /* Enable FMC clock source */ + r = clock_control_configure(clk, (clock_control_subsys_t)&config->pclken[1], NULL); + if (r < 0) { + LOG_ERR("Could not select FMC clock (%d)", r); + return r; + } + } + #if DT_HAS_COMPAT_STATUS_OKAY(st_stm32h7_fmc) #if (DT_ENUM_IDX(DT_DRV_INST(0), st_mem_swap) == 1) /* sdram-sram */ @@ -70,10 +88,12 @@ static int memc_stm32_init(const struct device *dev) PINCTRL_DT_INST_DEFINE(0); +static const struct stm32_pclken pclken[] = STM32_DT_INST_CLOCKS(0); + static const struct memc_stm32_config config = { .fmc = DT_INST_REG_ADDR(0), - .pclken = { .bus = DT_INST_CLOCKS_CELL(0, bus), - .enr = DT_INST_CLOCKS_CELL(0, bits) }, + .pclken = pclken, + .pclk_len = DT_INST_NUM_CLOCKS(0), .pcfg = PINCTRL_DT_INST_DEV_CONFIG_GET(0), }; From 39d74f1fd477bc6fcc15f855f951995aefdad266 Mon Sep 17 00:00:00 2001 From: HaiLong Yang Date: Thu, 14 Dec 2023 10:24:56 +0800 Subject: [PATCH 2360/3723] drivers: display: stm32 ltdc frame buffer number config This add frame number config to stm32 ltdc. Line interrupt is enabled to load new frambe buffer. Signed-off-by: HaiLong Yang --- drivers/display/Kconfig.stm32_ltdc | 22 +++++ drivers/display/display_stm32_ltdc.c | 132 +++++++++++++++++++++++---- 2 files changed, 134 insertions(+), 20 deletions(-) diff --git a/drivers/display/Kconfig.stm32_ltdc b/drivers/display/Kconfig.stm32_ltdc index 1d998c33e8f..12d7856a5e1 100644 --- a/drivers/display/Kconfig.stm32_ltdc +++ b/drivers/display/Kconfig.stm32_ltdc @@ -11,6 +11,8 @@ menuconfig STM32_LTDC help Enable driver for STM32 LCT-TFT display controller periheral. +if STM32_LTDC + choice STM32_LTDC_PIXEL_FORMAT prompt "Color pixel format" default STM32_LTDC_RGB565 @@ -37,3 +39,23 @@ config STM32_LTDC_RGB565 (2 bytes per pixel) endchoice + +config STM32_LTDC_FB_NUM + int "Frame buffer number" + default 1 + range 0 2 + help + STM32 LTDC frame buffer number config: + - 0 frame buffer maintained by application, must write with full screen pixels. + - 1 single frame buffer in stm32 ltdc driver. + - 2 double frame buffer in stm32 ltdc driver. + +config STM32_LTDC_DISABLE_FMC_BANK1 + bool "Disable FMC bank1 for STM32F7/H7 series" + depends on SOC_SERIES_STM32H7X || SOC_SERIES_STM32F7X + default y + help + Disable FMC bank1 if not used to prevent speculative read accesses. + Refer to AN4861 "4.6 Special recommendations for Cortex-M7 (STM32F7/H7)". + +endif # STM32_LTDC diff --git a/drivers/display/display_stm32_ltdc.c b/drivers/display/display_stm32_ltdc.c index 447252990e2..9360180eb08 100644 --- a/drivers/display/display_stm32_ltdc.c +++ b/drivers/display/display_stm32_ltdc.c @@ -57,13 +57,13 @@ LOG_MODULE_REGISTER(display_stm32_ltdc, CONFIG_DISPLAY_LOG_LEVEL); #if defined(CONFIG_HAS_CMSIS_CORE_M) #include -#if __DCACHE_PRESENT == 1 +#if defined(CONFIG_DCACHE) #define CACHE_INVALIDATE(addr, size) SCB_InvalidateDCache_by_Addr((addr), (size)) #define CACHE_CLEAN(addr, size) SCB_CleanDCache_by_Addr((addr), (size)) #else #define CACHE_INVALIDATE(addr, size) #define CACHE_CLEAN(addr, size) barrier_dsync_fence_full(); -#endif /* __DCACHE_PRESENT == 1 */ +#endif /* CONFIG_DCACHE */ #else #define CACHE_INVALIDATE(addr, size) @@ -75,6 +75,10 @@ struct display_stm32_ltdc_data { enum display_pixel_format current_pixel_format; uint8_t current_pixel_size; uint8_t *frame_buffer; + uint32_t frame_buffer_len; + const uint8_t *pend_buf; + const uint8_t *front_buf; + struct k_sem sem; }; struct display_stm32_ltdc_config { @@ -84,13 +88,26 @@ struct display_stm32_ltdc_config { struct gpio_dt_spec bl_ctrl_gpio; struct stm32_pclken pclken; const struct pinctrl_dev_config *pctrl; + void (*irq_config_func)(const struct device *dev); }; -static void *stm32_ltdc_get_framebuffer(const struct device *dev) +static void stm32_ltdc_global_isr(const struct device *dev) { struct display_stm32_ltdc_data *data = dev->data; - return (void *) data->frame_buffer; + if (__HAL_LTDC_GET_FLAG(&data->hltdc, LTDC_FLAG_LI) && + __HAL_LTDC_GET_IT_SOURCE(&data->hltdc, LTDC_IT_LI)) { + if (data->front_buf != data->pend_buf) { + data->front_buf = data->pend_buf; + + LTDC_LAYER(&data->hltdc, LTDC_LAYER_1)->CFBAR = (uint32_t)data->front_buf; + __HAL_LTDC_RELOAD_CONFIG(&data->hltdc); + + k_sem_give(&data->sem); + } + + __HAL_LTDC_CLEAR_FLAG(&data->hltdc, LTDC_FLAG_LI); + } } static int stm32_ltdc_set_pixel_format(const struct device *dev, @@ -161,21 +178,60 @@ static int stm32_ltdc_write(const struct device *dev, const uint16_t x, { const struct display_stm32_ltdc_config *config = dev->config; struct display_stm32_ltdc_data *data = dev->data; - uint8_t *dst = data->frame_buffer; + uint8_t *dst = NULL; + const uint8_t *pend_buf = NULL; const uint8_t *src = buf; uint16_t row; - /* dst = pointer to upper left pixel of the rectangle to be updated in frame buffer */ - dst += (x * data->current_pixel_size); - dst += (y * config->width * data->current_pixel_size); + if ((x == 0) && (y == 0) && + (desc->width == config->width) && + (desc->height == config->height) && + (desc->pitch == desc->width)) { + /* Use buf as ltdc frame buffer directly if it length same as ltdc frame buffer. */ + pend_buf = buf; + } else { + if (CONFIG_STM32_LTDC_FB_NUM == 0) { + LOG_ERR("Partial write requires internal frame buffer"); + return -ENOTSUP; + } - for (row = 0; row < desc->height; row++) { - (void) memcpy(dst, src, desc->width * data->current_pixel_size); - CACHE_CLEAN(dst, desc->width * data->current_pixel_size); - dst += (config->width * data->current_pixel_size); - src += (desc->pitch * data->current_pixel_size); + dst = data->frame_buffer; + + if (CONFIG_STM32_LTDC_FB_NUM == 2) { + if (data->front_buf == data->frame_buffer) { + dst = data->frame_buffer + data->frame_buffer_len; + } + + memcpy(dst, data->front_buf, data->frame_buffer_len); + } + + pend_buf = dst; + + /* dst = pointer to upper left pixel of the rectangle + * to be updated in frame buffer. + */ + dst += (x * data->current_pixel_size); + dst += (y * config->width * data->current_pixel_size); + + for (row = 0; row < desc->height; row++) { + (void) memcpy(dst, src, desc->width * data->current_pixel_size); + CACHE_CLEAN(dst, desc->width * data->current_pixel_size); + dst += (config->width * data->current_pixel_size); + src += (desc->pitch * data->current_pixel_size); + } + + } + + if (data->front_buf == pend_buf) { + return 0; } + k_sem_reset(&data->sem); + + data->pend_buf = pend_buf; + + k_sem_take(&data->sem, K_FOREVER); + return 0; } @@ -187,7 +243,7 @@ static int stm32_ltdc_read(const struct device *dev, const uint16_t x, const struct display_stm32_ltdc_config *config = dev->config; struct display_stm32_ltdc_data *data = dev->data; uint8_t *dst = buf; - const uint8_t *src = data->frame_buffer; + const uint8_t *src = data->front_buf; uint16_t row; /* src = pointer to upper left pixel of the rectangle to be read from frame buffer */ @@ -283,19 +339,41 @@ static int stm32_ltdc_init(const struct device *dev) data->current_pixel_format = DISPLAY_INIT_PIXEL_FORMAT; data->current_pixel_size = STM32_LTDC_INIT_PIXEL_SIZE; + k_sem_init(&data->sem, 0, 1); + + config->irq_config_func(dev); + +#ifdef CONFIG_STM32_LTDC_DISABLE_FMC_BANK1 + /* Clear MBKEN and MTYP[1:0] bits. */ +#ifdef CONFIG_SOC_SERIES_STM32F7X + FMC_Bank1->BTCR[0] &= ~(0x0000000D); +#else /* CONFIG_SOC_SERIES_STM32H7X */ + FMC_Bank1_R->BTCR[0] &= ~(0x0000000D); +#endif +#endif /* CONFIG_STM32_LTDC_DISABLE_FMC_BANK1 */ + /* Initialise the LTDC peripheral */ err = HAL_LTDC_Init(&data->hltdc); if (err != HAL_OK) { return err; } - /* Configure layer 0 (only one layer is used) */ + /* Configure layer 1 (only one layer is used) */ /* LTDC starts fetching pixels and sending them to display after this call */ - err = HAL_LTDC_ConfigLayer(&data->hltdc, &data->hltdc.LayerCfg[0], 0); + err = HAL_LTDC_ConfigLayer(&data->hltdc, &data->hltdc.LayerCfg[0], LTDC_LAYER_1); if (err != HAL_OK) { return err; } + /* Disable layer 2, since it not used */ + __HAL_LTDC_LAYER_DISABLE(&data->hltdc, LTDC_LAYER_2); + + /* Set the line interrupt position */ + LTDC->LIPCR = 0U; + + __HAL_LTDC_CLEAR_FLAG(&data->hltdc, LTDC_FLAG_LI); + __HAL_LTDC_ENABLE_IT(&data->hltdc, LTDC_IT_LI); + return 0; } @@ -359,7 +437,6 @@ static int stm32_ltdc_pm_action(const struct device *dev, static const struct display_driver_api stm32_ltdc_display_api = { .write = stm32_ltdc_write, .read = stm32_ltdc_read, - .get_framebuffer = stm32_ltdc_get_framebuffer, .get_capabilities = stm32_ltdc_get_capabilities, .set_pixel_format = stm32_ltdc_set_pixel_format, .set_orientation = stm32_ltdc_set_orientation @@ -388,16 +465,30 @@ static const struct display_driver_api stm32_ltdc_display_api = { #define STM32_LTDC_DEVICE_PINCTRL_GET(n) PINCTRL_DT_INST_DEV_CONFIG_GET(n) #endif +#define STM32_LTDC_FRAME_BUFFER_LEN(inst) \ + (STM32_LTDC_INIT_PIXEL_SIZE * DT_INST_PROP(inst, height) * DT_INST_PROP(inst, width)) \ + #define STM32_LTDC_DEVICE(inst) \ STM32_LTDC_DEVICE_PINCTRL_INIT(inst); \ PM_DEVICE_DT_INST_DEFINE(inst, stm32_ltdc_pm_action); \ + static void stm32_ltdc_irq_config_func_##inst(const struct device *dev) \ + { \ + IRQ_CONNECT(DT_INST_IRQN(inst), \ + DT_INST_IRQ(inst, priority), \ + stm32_ltdc_global_isr, \ + DEVICE_DT_INST_GET(inst), \ + 0); \ + irq_enable(DT_INST_IRQN(inst)); \ + } \ /* frame buffer aligned to cache line width for optimal cache flushing */ \ FRAME_BUFFER_SECTION static uint8_t __aligned(32) \ - frame_buffer_##inst[STM32_LTDC_INIT_PIXEL_SIZE * \ - DT_INST_PROP(inst, height) * \ - DT_INST_PROP(inst, width)]; \ + frame_buffer_##inst[CONFIG_STM32_LTDC_FB_NUM * \ + STM32_LTDC_FRAME_BUFFER_LEN(inst)]; \ static struct display_stm32_ltdc_data stm32_ltdc_data_##inst = { \ .frame_buffer = frame_buffer_##inst, \ + .frame_buffer_len = STM32_LTDC_FRAME_BUFFER_LEN(inst), \ + .front_buf = frame_buffer_##inst, \ + .pend_buf = frame_buffer_##inst, \ .hltdc = { \ .Instance = (LTDC_TypeDef *) DT_INST_REG_ADDR(inst), \ .Init = { \ @@ -492,6 +583,7 @@ static const struct display_driver_api stm32_ltdc_display_api = { .bus = DT_INST_CLOCKS_CELL(inst, bus) \ }, \ .pctrl = STM32_LTDC_DEVICE_PINCTRL_GET(inst), \ + .irq_config_func = stm32_ltdc_irq_config_func_##inst, \ }; \ DEVICE_DT_INST_DEFINE(inst, \ &stm32_ltdc_init, \ From be2700a8d9452a1923861974289c9af7ee350591 Mon Sep 17 00:00:00 2001 From: HaiLong Yang Date: Thu, 14 Dec 2023 10:39:47 +0800 Subject: [PATCH 2361/3723] boards: update stm32h747i_disco display This update stm32h747i_disco board display config to use ltdc frame buffer config feature. For lvgl, by default ltdc frame buffer number set to 0. Signed-off-by: HaiLong Yang --- boards/arm/stm32h747i_disco/CMakeLists.txt | 9 ++++ boards/arm/stm32h747i_disco/dc_ram.ld | 16 +++++++ .../st_b_lcd40_dsi1_mb1166/Kconfig.defconfig | 42 +++++++++++++++++++ .../boards/stm32h747i_disco_m7.overlay | 23 ++++++++++ 4 files changed, 90 insertions(+) create mode 100644 boards/arm/stm32h747i_disco/CMakeLists.txt create mode 100644 boards/arm/stm32h747i_disco/dc_ram.ld create mode 100644 boards/shields/st_b_lcd40_dsi1_mb1166/Kconfig.defconfig diff --git a/boards/arm/stm32h747i_disco/CMakeLists.txt b/boards/arm/stm32h747i_disco/CMakeLists.txt new file mode 100644 index 00000000000..2f480bd7966 --- /dev/null +++ b/boards/arm/stm32h747i_disco/CMakeLists.txt @@ -0,0 +1,9 @@ +# +# Copyright 2023 BrainCo Inc. +# +# SPDX-License-Identifier: Apache-2.0 +# + +# Add custom linker section to relocate framebuffers to PSRAM +zephyr_linker_sources_ifdef(CONFIG_LV_Z_VBD_CUSTOM_SECTION + SECTIONS dc_ram.ld) diff --git a/boards/arm/stm32h747i_disco/dc_ram.ld b/boards/arm/stm32h747i_disco/dc_ram.ld new file mode 100644 index 00000000000..bd1565960d5 --- /dev/null +++ b/boards/arm/stm32h747i_disco/dc_ram.ld @@ -0,0 +1,16 @@ +/* + * Copyright (c) 2023 BrainCo Inc. + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#if DT_NODE_HAS_STATUS(DT_NODELABEL(sdram2), okay) +GROUP_START(SDRAM2) + + SECTION_PROLOGUE(_STM32_SDRAM2_SECTION_NAME, (NOLOAD),) + { + *(.lvgl_buf) + } GROUP_LINK_IN(SDRAM2) + +GROUP_END(SDRAM2) +#endif diff --git a/boards/shields/st_b_lcd40_dsi1_mb1166/Kconfig.defconfig b/boards/shields/st_b_lcd40_dsi1_mb1166/Kconfig.defconfig new file mode 100644 index 00000000000..b192ce223f0 --- /dev/null +++ b/boards/shields/st_b_lcd40_dsi1_mb1166/Kconfig.defconfig @@ -0,0 +1,42 @@ +# Copyright (c) 2023 BrainCo Inc. +# SPDX-License-Identifier: Apache-2.0 + +if SHIELD_ST_B_LCD40_DSI1_MB1166 + +# Double frame buffer maintained by lvgl. +if LVGL + +config STM32_LTDC_FB_NUM + default 0 + +config INPUT + default y + +config LV_Z_VDB_SIZE + default 100 + +config LV_Z_DOUBLE_VDB + default y + +config LV_Z_VBD_CUSTOM_SECTION + default y + +config LV_Z_FULL_REFRESH + default y + +config LV_Z_BITS_PER_PIXEL + default 32 + +config LV_DPI_DEF + default 128 + +config LV_Z_FLUSH_THREAD + default y + +choice LV_COLOR_DEPTH + default LV_COLOR_DEPTH_32 +endchoice + +endif # LVGL + +endif # SHIELD_ST_B_LCD40_DSI1_MB1166 diff --git a/boards/shields/st_b_lcd40_dsi1_mb1166/boards/stm32h747i_disco_m7.overlay b/boards/shields/st_b_lcd40_dsi1_mb1166/boards/stm32h747i_disco_m7.overlay index a50b0ef6c53..bbaba0718b9 100644 --- a/boards/shields/st_b_lcd40_dsi1_mb1166/boards/stm32h747i_disco_m7.overlay +++ b/boards/shields/st_b_lcd40_dsi1_mb1166/boards/stm32h747i_disco_m7.overlay @@ -7,11 +7,22 @@ #include / { + lvgl_pointer { + compatible = "zephyr,lvgl-pointer-input"; + input = <&ft5336>; + invert-y; + }; + chosen { zephyr,display = <dc; }; }; +&sdram2 { + /* Frame buffer memory cache will cause screen flickering. */ + zephyr,memory-attr = <( DT_MEM_ARM(ATTR_MPU_RAM_NOCACHE) )>; +}; + <dc { status = "okay"; ext-sdram = <&sdram2>; @@ -72,3 +83,15 @@ pixel-format = ; rotation = <90>; }; + +&i2c4 { + pinctrl-0 = <&i2c4_scl_pd12 &i2c4_sda_pd13>; + pinctrl-names = "default"; + clock-frequency = ; + status = "okay"; + + ft5336: ft5336@38 { + compatible = "focaltech,ft5336"; + reg = <0x38>; + }; +}; From bedb6115492ba299e348909140e6d06dff0c8902 Mon Sep 17 00:00:00 2001 From: Daniel DeGrasse Date: Tue, 5 Dec 2023 22:27:04 +0000 Subject: [PATCH 2362/3723] include: audio: dmic: fixup parse_channel_map implementation Fixup parse_channel_map implementation. The previous implementation of this function did not use the "channel_map" values passed in by the user, and would not return correct values for the PDM hardware controller or L/R value. This function is not being used in tree, so correcting the implementation to align with documentation should have minimal affect. Signed-off-by: Daniel DeGrasse --- include/zephyr/audio/dmic.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/include/zephyr/audio/dmic.h b/include/zephyr/audio/dmic.h index e6736b8676c..f12296c1f5b 100644 --- a/include/zephyr/audio/dmic.h +++ b/include/zephyr/audio/dmic.h @@ -231,8 +231,8 @@ static inline void dmic_parse_channel_map(uint32_t channel_map_lo, channel_map = (channel < 8) ? channel_map_lo : channel_map_hi; channel_map >>= ((channel & BIT_MASK(3)) * 4U); - *pdm = (channel >> 1) & BIT_MASK(3); - *lr = (enum pdm_lr) (channel & BIT(0)); + *pdm = (channel_map >> 1) & BIT_MASK(3); + *lr = (enum pdm_lr) (channel_map & BIT(0)); } /** From b7e028b31c9b025ec796303398d6e0faf999b605 Mon Sep 17 00:00:00 2001 From: Daniel DeGrasse Date: Tue, 5 Dec 2023 22:28:58 +0000 Subject: [PATCH 2363/3723] include: audio: dmic: add DMIC_STATE_ERROR enum Add DMIC_STATE_ERROR enum. This can be used by DMIC drivers for instances in which a significant error has occurred (typically when the DMIC cannot allocate additional buffers for PCM data and starves) Signed-off-by: Daniel DeGrasse --- include/zephyr/audio/dmic.h | 1 + 1 file changed, 1 insertion(+) diff --git a/include/zephyr/audio/dmic.h b/include/zephyr/audio/dmic.h index f12296c1f5b..e0582c45deb 100644 --- a/include/zephyr/audio/dmic.h +++ b/include/zephyr/audio/dmic.h @@ -48,6 +48,7 @@ enum dmic_state { DMIC_STATE_CONFIGURED, /**< Configured */ DMIC_STATE_ACTIVE, /**< Active */ DMIC_STATE_PAUSED, /**< Paused */ + DMIC_STATE_ERROR, /**< Error */ }; /** From a5ef1a296a61ff3e1467b96507e30a97c7ea1ef9 Mon Sep 17 00:00:00 2001 From: Daniel DeGrasse Date: Tue, 5 Dec 2023 22:24:46 +0000 Subject: [PATCH 2364/3723] drivers: clock_control: mcux_syscon: add definition for DMIC clock Add definition for DMIC clock source to LPC SYSCON clock control driver. This constant allows drivers to get the DMIC bit clock frequency. Signed-off-by: Daniel DeGrasse --- drivers/clock_control/clock_control_mcux_syscon.c | 5 +++++ include/zephyr/dt-bindings/clock/mcux_lpc_syscon_clock.h | 2 ++ 2 files changed, 7 insertions(+) diff --git a/drivers/clock_control/clock_control_mcux_syscon.c b/drivers/clock_control/clock_control_mcux_syscon.c index 3dcc073954c..a0a7db57d28 100644 --- a/drivers/clock_control/clock_control_mcux_syscon.c +++ b/drivers/clock_control/clock_control_mcux_syscon.c @@ -178,6 +178,11 @@ static int mcux_lpc_syscon_clock_control_get_subsys_rate( case MCUX_LCDIF_PIXEL_CLK: *rate = CLOCK_GetDcPixelClkFreq(); break; +#endif +#if defined(CONFIG_AUDIO_DMIC_MCUX) + case MCUX_DMIC_CLK: + *rate = CLOCK_GetDmicClkFreq(); + break; #endif } 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 9f80b662c60..e273288a37e 100644 --- a/include/zephyr/dt-bindings/clock/mcux_lpc_syscon_clock.h +++ b/include/zephyr/dt-bindings/clock/mcux_lpc_syscon_clock.h @@ -51,6 +51,8 @@ #define MCUX_SCTIMER_CLK 34 +#define MCUX_DMIC_CLK 35 + #define MCUX_MRT_CLK 40 #endif /* ZEPHYR_INCLUDE_DT_BINDINGS_CLOCK_MCUX_LPC_SYSCON_H_ */ From 6fbd76bef3f7c528dd71c52a3e0bd535d33a585d Mon Sep 17 00:00:00 2001 From: Daniel DeGrasse Date: Tue, 5 Dec 2023 22:30:36 +0000 Subject: [PATCH 2365/3723] drivers: audio: dmic: add driver for NXP DMIC peripheral Add driver for NXP DMIC peripheral. This peripheral is present on the iMX RT5xx and iMX RT6xx parts, as well as some LPC SOCs. The following features are supported: - up to 2 simultaneous channels of L/R PCM data (4 channels are not supported due to limitations of the DMA engine) - individual configuration of gain and filter parameters for each DMIC channel input The driver has been tested with up to 4 PCM data streams (2 L/R channels), as well as the MEMS microphones present on the RT595 EVK. Signed-off-by: Daniel DeGrasse Co-authored-by: Yves Vandervennet --- drivers/audio/CMakeLists.txt | 1 + drivers/audio/Kconfig | 1 + drivers/audio/Kconfig.dmic_mcux | 32 ++ drivers/audio/dmic_mcux.c | 727 +++++++++++++++++++++++++++++++ dts/bindings/audio/nxp,dmic.yaml | 97 +++++ 5 files changed, 858 insertions(+) create mode 100644 drivers/audio/Kconfig.dmic_mcux create mode 100644 drivers/audio/dmic_mcux.c create mode 100644 dts/bindings/audio/nxp,dmic.yaml diff --git a/drivers/audio/CMakeLists.txt b/drivers/audio/CMakeLists.txt index 98544d6218c..c38c35c8807 100644 --- a/drivers/audio/CMakeLists.txt +++ b/drivers/audio/CMakeLists.txt @@ -8,3 +8,4 @@ zephyr_library_sources_ifdef(CONFIG_AUDIO_MPXXDTYY mpxxdtyy-i2s.c) zephyr_library_sources_ifdef(CONFIG_AUDIO_DMIC_NRFX_PDM dmic_nrfx_pdm.c) zephyr_library_sources_ifdef(CONFIG_AUDIO_TAS6422DAC tas6422dac.c) zephyr_library_sources_ifdef(CONFIG_AUDIO_CODEC_SHELL codec_shell.c) +zephyr_library_sources_ifdef(CONFIG_AUDIO_DMIC_MCUX dmic_mcux.c) diff --git a/drivers/audio/Kconfig b/drivers/audio/Kconfig index a9d11331676..500e36e7e44 100644 --- a/drivers/audio/Kconfig +++ b/drivers/audio/Kconfig @@ -59,6 +59,7 @@ source "subsys/logging/Kconfig.template.log_config" source "drivers/audio/Kconfig.mpxxdtyy" source "drivers/audio/Kconfig.dmic_pdm_nrfx" +source "drivers/audio/Kconfig.dmic_mcux" endif # AUDIO_DMIC diff --git a/drivers/audio/Kconfig.dmic_mcux b/drivers/audio/Kconfig.dmic_mcux new file mode 100644 index 00000000000..993e30fdb53 --- /dev/null +++ b/drivers/audio/Kconfig.dmic_mcux @@ -0,0 +1,32 @@ +# Copyright 2023 NXP +# SPDX-License-Identifier: Apache-2.0 + +config AUDIO_DMIC_MCUX + bool "DMIC driver for MCUX" + default y + depends on DT_HAS_NXP_DMIC_ENABLED + select DMA + help + Enable support for DMIC on NXP MCUX SoC's + +if AUDIO_DMIC_MCUX + +config DMIC_MCUX_DMA_BUFFERS + int "Number of buffers to reserve for DMIC DMA" + default 2 + range 2 16 + help + This determines how many buffers the driver should allocate and + reserve for the DMA engine. The memory slab used with the DMIC + API should provide at least one more buffer than this value, since + a buffer will always be in the RX queue. + +config DMIC_MCUX_QUEUE_SIZE + int "Size of DMIC buffer queue" + default 8 + help + This sets the size of the RX buffer queue for the DMIC. Up to this + many buffers may be queued by the DMIC once it is triggered, before + the application must read buffers to avoid data being dropped. + +endif # AUDIO_DMIC_MCUX diff --git a/drivers/audio/dmic_mcux.c b/drivers/audio/dmic_mcux.c new file mode 100644 index 00000000000..ff357fda9bb --- /dev/null +++ b/drivers/audio/dmic_mcux.c @@ -0,0 +1,727 @@ +/* + * Copyright 2023 NXP + * Copyright (c) 2021 Nordic Semiconductor ASA + * + * based on dmic_nrfx_pdm.c + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include +#include +#include +#include +#include +#include + +#include + +#include +#include +LOG_MODULE_REGISTER(dmic_mcux, CONFIG_AUDIO_DMIC_LOG_LEVEL); + +#define DT_DRV_COMPAT nxp_dmic + +struct mcux_dmic_pdm_chan { + dmic_channel_config_t dmic_channel_cfg; + const struct device *dma; + uint8_t dma_chan; +}; + +struct mcux_dmic_drv_data { + struct k_mem_slab *mem_slab; + void *dma_bufs[CONFIG_DMIC_MCUX_DMA_BUFFERS]; + uint8_t active_buf_idx; + uint32_t block_size; + DMIC_Type *base_address; + struct mcux_dmic_pdm_chan **pdm_channels; + uint8_t act_num_chan; + struct k_msgq *rx_queue; + uint32_t chan_map_lo; + uint32_t chan_map_hi; + enum dmic_state dmic_state; +}; + +struct mcux_dmic_cfg { + const struct pinctrl_dev_config *pcfg; + const struct device *clock_dev; + clock_control_subsys_t clock_name; + bool use2fs; +}; + +static int dmic_mcux_get_osr(uint32_t pcm_rate, uint32_t bit_clk, bool use_2fs) +{ + uint32_t use2fs_div = use_2fs ? 1 : 2; + + /* Note that the below calculation assumes the following: + * - DMIC DIVHFCLK is set to 0x0 (divide by 1) + * - DMIC PHY_HALF is set to 0x0 (standard sample rate) + */ + return (uint32_t)(bit_clk / (2 * pcm_rate * use2fs_div)); +} + +/* Gets hardware channel index from logical channel */ +static uint8_t dmic_mcux_hw_chan(struct mcux_dmic_drv_data *drv_data, + uint8_t log_chan) +{ + enum pdm_lr lr; + uint8_t hw_chan; + + /* This function assigns hardware channel "n" to the left channel, + * and hardware channel "n+1" to the right channel. This choice is + * arbitrary, but must be followed throughout the driver. + */ + dmic_parse_channel_map(drv_data->chan_map_lo, + drv_data->chan_map_hi, + log_chan, &hw_chan, &lr); + if (lr == PDM_CHAN_LEFT) { + return hw_chan * 2; + } else { + return (hw_chan * 2) + 1; + } +} + +static void dmic_mcux_activate_channels(struct mcux_dmic_drv_data *drv_data, + bool enable) +{ + + /* PDM channel 0 must always be enabled, as the RM states: + * "In order to output 8 channels of PDM Data, PDM_CLK01 must be used" + * therefore, even if we don't intend to capture PDM data from the + * channel 0 FIFO, we still enable the channel so the clock is active. + */ + uint32_t mask = 0x1; + + for (uint8_t chan = 0; chan < drv_data->act_num_chan; chan++) { + /* Set bitmask of hw channel to enable */ + mask |= BIT(dmic_mcux_hw_chan(drv_data, chan)); + } + + if (enable) { + DMIC_EnableChannnel(drv_data->base_address, mask); + } else { + /* No function to disable channels, we must bypass HAL here */ + drv_data->base_address->CHANEN &= ~mask; + } +} + +static int dmic_mcux_enable_dma(struct mcux_dmic_drv_data *drv_data, bool enable) +{ + struct mcux_dmic_pdm_chan *pdm_channel; + uint8_t num_chan = drv_data->act_num_chan; + uint8_t hw_chan; + int ret = 0; + + for (uint8_t chan = 0; chan < num_chan; chan++) { + /* Parse the channel map data */ + hw_chan = dmic_mcux_hw_chan(drv_data, chan); + pdm_channel = drv_data->pdm_channels[hw_chan]; + if (enable) { + ret = dma_start(pdm_channel->dma, pdm_channel->dma_chan); + if (ret < 0) { + LOG_ERR("Could not start DMA for HW channel %d", + hw_chan); + return ret; + } + } else { + if (dma_stop(pdm_channel->dma, pdm_channel->dma_chan)) { + ret = -EIO; + } + } + DMIC_EnableChannelDma(drv_data->base_address, + (dmic_channel_t)hw_chan, enable); + } + + return ret; +} + +/* Helper to reload DMA engine for all active channels with new buffer */ +static void dmic_mcux_reload_dma(struct mcux_dmic_drv_data *drv_data, + void *buffer) +{ + int ret; + uint8_t hw_chan; + struct mcux_dmic_pdm_chan *pdm_channel; + uint8_t num_chan = drv_data->act_num_chan; + uint32_t dma_buf_size = drv_data->block_size / num_chan; + uint32_t src, dst; + + /* This function reloads the DMA engine for all active DMA channels + * with the provided buffer. Each DMA channel will start + * at a different initial address to interleave channel data. + */ + for (uint8_t chan = 0; chan < num_chan; chan++) { + /* Parse the channel map data */ + hw_chan = dmic_mcux_hw_chan(drv_data, chan); + pdm_channel = drv_data->pdm_channels[hw_chan]; + src = DMIC_FifoGetAddress(drv_data->base_address, hw_chan); + dst = (uint32_t)(((uint16_t *)buffer) + chan); + ret = dma_reload(pdm_channel->dma, pdm_channel->dma_chan, + src, dst, dma_buf_size); + if (ret < 0) { + LOG_ERR("Could not reload DMIC HW channel %d", hw_chan); + return; + } + } +} + +/* Helper to get next buffer index for DMA */ +static uint8_t dmic_mcux_next_buf_idx(uint8_t current_idx) +{ + if ((current_idx + 1) == CONFIG_DMIC_MCUX_DMA_BUFFERS) { + return 0; + } + return current_idx + 1; +} + +static int dmic_mcux_stop(struct mcux_dmic_drv_data *drv_data) +{ + /* Disable active channels */ + dmic_mcux_activate_channels(drv_data, false); + /* Disable DMA */ + dmic_mcux_enable_dma(drv_data, false); + + /* Free all memory slabs */ + for (uint32_t i = 0; i < CONFIG_DMIC_MCUX_DMA_BUFFERS; i++) { + k_mem_slab_free(drv_data->mem_slab, drv_data->dma_bufs[i]); + } + + /* Purge the RX queue as well. */ + k_msgq_purge(drv_data->rx_queue); + + drv_data->dmic_state = DMIC_STATE_CONFIGURED; + + return 0; +} + +static void dmic_mcux_dma_cb(const struct device *dev, void *user_data, + uint32_t channel, int status) +{ + + struct mcux_dmic_drv_data *drv_data = (struct mcux_dmic_drv_data *)user_data; + int ret; + void *done_buffer = drv_data->dma_bufs[drv_data->active_buf_idx]; + void *new_buffer; + + LOG_DBG("CB: channel is %u", channel); + + if (status < 0) { + /* DMA has failed, free allocated blocks */ + LOG_ERR("DMA reports error"); + dmic_mcux_enable_dma(drv_data, false); + dmic_mcux_activate_channels(drv_data, false); + /* Free all allocated DMA buffers */ + dmic_mcux_stop(drv_data); + drv_data->dmic_state = DMIC_STATE_ERROR; + return; + } + + /* Before we queue the current buffer, make sure we can allocate + * another one to replace it. + */ + ret = k_mem_slab_alloc(drv_data->mem_slab, &new_buffer, K_NO_WAIT); + if (ret < 0) { + /* We can't allocate a new buffer to replace the current + * one, so we cannot release the current buffer to the + * rx queue (or the DMA would stave). Therefore, we just + * leave the current buffer in place to be overwritten + * by the DMA. + */ + LOG_ERR("Could not allocate RX buffer. Dropping RX data"); + drv_data->dmic_state = DMIC_STATE_ERROR; + /* Reload DMA */ + dmic_mcux_reload_dma(drv_data, done_buffer); + /* Advance active buffer index */ + drv_data->active_buf_idx = + dmic_mcux_next_buf_idx(drv_data->active_buf_idx); + return; + } + + /* DMA issues an interrupt at the completion of every block. + * we should put the active buffer into the rx queue for the + * application to read. The application is responsible for + * freeing this buffer once it processes it. + */ + ret = k_msgq_put(drv_data->rx_queue, &done_buffer, K_NO_WAIT); + if (ret < 0) { + /* Free the newly allocated buffer, we won't need it. */ + k_mem_slab_free(drv_data->mem_slab, new_buffer); + /* We cannot enqueue the current buffer, so we will drop + * the current buffer data and leave the current buffer + * in place to be overwritten by the DMA + */ + LOG_ERR("RX queue overflow, dropping RX buffer data"); + drv_data->dmic_state = DMIC_STATE_ERROR; + /* Reload DMA */ + dmic_mcux_reload_dma(drv_data, done_buffer); + /* Advance active buffer index */ + drv_data->active_buf_idx = + dmic_mcux_next_buf_idx(drv_data->active_buf_idx); + return; + } + + /* Previous buffer was enqueued, and new buffer is allocated. + * Replace pointer to previous buffer in our dma slots array, + * and reload DMA with next buffer. + */ + drv_data->dma_bufs[drv_data->active_buf_idx] = new_buffer; + dmic_mcux_reload_dma(drv_data, new_buffer); + /* Advance active buffer index */ + drv_data->active_buf_idx = dmic_mcux_next_buf_idx(drv_data->active_buf_idx); +} + +static int dmic_mcux_setup_dma(const struct device *dev) +{ + struct mcux_dmic_drv_data *drv_data = dev->data; + struct mcux_dmic_pdm_chan *pdm_channel; + struct dma_block_config blk_cfg[CONFIG_DMIC_MCUX_DMA_BUFFERS] = {0}; + struct dma_config dma_cfg = {0}; + uint8_t num_chan = drv_data->act_num_chan; + uint32_t dma_buf_size = drv_data->block_size / num_chan; + uint8_t dma_buf_idx = 0; + void *dma_buf = drv_data->dma_bufs[dma_buf_idx]; + uint8_t hw_chan; + int ret = 0; + + + /* Setup DMA configuration common between all channels */ + dma_cfg.user_data = drv_data; + dma_cfg.channel_direction = PERIPHERAL_TO_MEMORY; + dma_cfg.source_data_size = sizeof(uint16_t); /* Each sample is 16 bits */ + dma_cfg.dest_data_size = sizeof(uint16_t); + dma_cfg.block_count = CONFIG_DMIC_MCUX_DMA_BUFFERS; + dma_cfg.head_block = &blk_cfg[0]; + dma_cfg.complete_callback_en = 1; /* Callback at each block */ + dma_cfg.dma_callback = dmic_mcux_dma_cb; + + /* When multiple channels are enabled simultaneously, the DMA + * completion interrupt from one channel will signal that DMA data + * from multiple channels may be collected, provided the same + * amount of data was transferred. Therefore, we only enable the + * DMA completion callback for the first channel we setup + */ + for (uint8_t chan = 0; chan < num_chan; chan++) { + /* Parse the channel map data */ + hw_chan = dmic_mcux_hw_chan(drv_data, chan); + /* Configure blocks for hw_chan */ + for (uint32_t blk = 0; blk < CONFIG_DMIC_MCUX_DMA_BUFFERS; blk++) { + blk_cfg[blk].source_address = + DMIC_FifoGetAddress(drv_data->base_address, hw_chan); + /* We interleave samples within the output buffer + * based on channel map. So for a channel map like so: + * [pdm0_l, pdm0_r, pdm1_r, pdm1_l] + * the resulting DMA buffer would look like: + * [pdm0_l_s0, pdm0_r_s0, pdm1_r_s0, pdm1_l_s0, + * pdm0_l_s1, pdm0_r_s1, pdm1_r_s1, pdm1_l_s1, ...] + * Each sample is 16 bits wide. + */ + blk_cfg[blk].dest_address = + (uint32_t)(((uint16_t *)dma_buf) + chan); + blk_cfg[blk].dest_scatter_interval = + num_chan * sizeof(uint16_t); + blk_cfg[blk].dest_scatter_en = 1; + blk_cfg[blk].source_addr_adj = DMA_ADDR_ADJ_NO_CHANGE; + blk_cfg[blk].dest_addr_adj = DMA_ADDR_ADJ_INCREMENT; + blk_cfg[blk].block_size = dma_buf_size; + /* Enable circular mode- when the final DMA block + * is exhausted, we want the DMA controller + * to restart with the first one. + */ + blk_cfg[blk].source_reload_en = 1; + blk_cfg[blk].dest_reload_en = 1; + if (blk < (CONFIG_DMIC_MCUX_DMA_BUFFERS - 1)) { + blk_cfg[blk].next_block = &blk_cfg[blk + 1]; + } else { + /* Last block, enable circular reload */ + blk_cfg[blk].next_block = NULL; + } + /* Select next dma buffer in array */ + dma_buf_idx = dmic_mcux_next_buf_idx(dma_buf_idx); + dma_buf = drv_data->dma_bufs[dma_buf_idx]; + } + pdm_channel = drv_data->pdm_channels[hw_chan]; + /* Set configuration for hw_chan_0 */ + ret = dma_config(pdm_channel->dma, pdm_channel->dma_chan, &dma_cfg); + if (ret < 0) { + LOG_ERR("Could not configure DMIC channel %d", hw_chan); + return ret; + } + /* First channel is configured. Do not install callbacks for + * other channels. + */ + dma_cfg.dma_callback = NULL; + } + + return 0; +} + +/* Initializes a DMIC hardware channel */ +static int dmic_mcux_init_channel(const struct device *dev, uint32_t osr, + uint8_t chan, enum pdm_lr lr) +{ + struct mcux_dmic_drv_data *drv_data = dev->data; + + if (!drv_data->pdm_channels[chan]) { + /* Channel disabled at devicetree level */ + return -EINVAL; + } + + drv_data->pdm_channels[chan]->dmic_channel_cfg.osr = osr; + /* Configure channel settings */ + DMIC_ConfigChannel(drv_data->base_address, (dmic_channel_t)chan, + lr == PDM_CHAN_LEFT ? kDMIC_Left : kDMIC_Right, + &drv_data->pdm_channels[chan]->dmic_channel_cfg); + /* Setup channel FIFO. We use maximum threshold to avoid triggering + * DMA too frequently + */ + DMIC_FifoChannel(drv_data->base_address, chan, 15, true, true); + /* Disable interrupts. DMA will be enabled in dmic_mcux_trigger. */ + DMIC_EnableChannelInterrupt(drv_data->base_address, chan, false); + return 0; +} + +static int mcux_dmic_init(const struct device *dev) +{ + const struct mcux_dmic_cfg *config = dev->config; + struct mcux_dmic_drv_data *drv_data = dev->data; + int ret; + + ret = pinctrl_apply_state(config->pcfg, PINCTRL_STATE_DEFAULT); + if (ret < 0) { + return ret; + } + DMIC_Init(drv_data->base_address); + DMIC_Use2fs(drv_data->base_address, config->use2fs); +#if !(defined(FSL_FEATURE_DMIC_HAS_NO_IOCFG) && FSL_FEATURE_DMIC_HAS_NO_IOCFG) + /* Set IO to dual mode */ + DMIC_SetIOCFG(drv_data->base_address, kDMIC_PdmDual); +#endif + drv_data->dmic_state = DMIC_STATE_INITIALIZED; + return 0; +} + +static int dmic_mcux_configure(const struct device *dev, + struct dmic_cfg *config) +{ + + const struct mcux_dmic_cfg *drv_config = dev->config; + struct mcux_dmic_drv_data *drv_data = dev->data; + struct pdm_chan_cfg *channel = &config->channel; + struct pcm_stream_cfg *stream = &config->streams[0]; + enum pdm_lr lr_0 = 0, lr_1 = 0; + uint8_t hw_chan_0 = 0, hw_chan_1 = 0; + uint32_t bit_clk_rate, osr; + int ret; + + if (drv_data->dmic_state == DMIC_STATE_ACTIVE) { + LOG_ERR("Cannot configure device while it is active"); + return -EBUSY; + } + + /* Only one active channel is supported */ + if (channel->req_num_streams != 1) { + return -EINVAL; + } + + /* DMIC supports up to 8 active channels. Verify user is not + * requesting more + */ + if (channel->req_num_chan > FSL_FEATURE_DMIC_CHANNEL_NUM) { + LOG_ERR("DMIC only supports 8 channels or less"); + return -ENOTSUP; + } + + if (stream->pcm_rate == 0 || stream->pcm_width == 0) { + if (drv_data->dmic_state == DMIC_STATE_CONFIGURED) { + DMIC_DeInit(drv_data->base_address); + drv_data->dmic_state = DMIC_STATE_UNINIT; + } + return 0; + } + + /* If DMIC was deinitialized, reinit here */ + if (drv_data->dmic_state == DMIC_STATE_UNINIT) { + ret = mcux_dmic_init(dev); + if (ret < 0) { + LOG_ERR("Could not reinit DMIC"); + return ret; + } + } + + /* Currently, we only support 16 bit samples. This is because the DMIC + * API dictates that samples should be interleaved between channels, + * IE: {C0, C1, C2, C0, C1, C2}. To achieve this we must use the + * "destination address increment" function of the LPC DMA IP. Since + * the LPC DMA IP does not support 3 byte wide transfers, we cannot + * effectively use destination address increments to interleave 24 + * bit samples. + */ + if (stream->pcm_width != 16) { + LOG_ERR("Only 16 bit samples are supported"); + return -ENOTSUP; + } + + ret = clock_control_get_rate(drv_config->clock_dev, + drv_config->clock_name, &bit_clk_rate); + if (ret < 0) { + return ret; + } + + /* Check bit clock rate versus what user requested */ + if ((config->io.min_pdm_clk_freq > bit_clk_rate) || + (config->io.max_pdm_clk_freq < bit_clk_rate)) { + return -EINVAL; + } + /* Calculate the required OSR divider based on the PCM bit clock + * rate to the DMIC. + */ + osr = dmic_mcux_get_osr(stream->pcm_rate, bit_clk_rate, drv_config->use2fs); + /* Now, parse the channel map and set up each channel we should + * make active. We parse two channels at once, that way we can + * check to make sure that the L/R channels of each PDM controller + * are adjacent. + */ + channel->act_num_chan = 0; + /* Save channel request data */ + drv_data->chan_map_lo = channel->req_chan_map_lo; + drv_data->chan_map_hi = channel->req_chan_map_hi; + for (uint8_t chan = 0; chan < channel->req_num_chan; chan += 2) { + /* Get the channel map data for channel pair */ + dmic_parse_channel_map(channel->req_chan_map_lo, + channel->req_chan_map_hi, + chan, &hw_chan_0, &lr_0); + if ((chan + 1) < channel->req_num_chan) { + /* Paired channel is enabled */ + dmic_parse_channel_map(channel->req_chan_map_lo, + channel->req_chan_map_hi, + chan + 1, &hw_chan_1, &lr_1); + /* Verify that paired channels use same hardware index */ + if ((lr_0 == lr_1) || + (hw_chan_0 != hw_chan_1)) { + return -EINVAL; + } + } + /* Configure selected channels in DMIC */ + ret = dmic_mcux_init_channel(dev, osr, + dmic_mcux_hw_chan(drv_data, chan), + lr_0); + if (ret < 0) { + return ret; + } + channel->act_num_chan++; + if ((chan + 1) < channel->req_num_chan) { + /* Paired channel is enabled */ + ret = dmic_mcux_init_channel(dev, osr, + dmic_mcux_hw_chan(drv_data, + chan + 1), + lr_1); + if (ret < 0) { + return ret; + } + channel->act_num_chan++; + } + } + + channel->act_chan_map_lo = channel->req_chan_map_lo; + channel->act_chan_map_hi = channel->req_chan_map_hi; + + drv_data->mem_slab = stream->mem_slab; + drv_data->block_size = stream->block_size; + drv_data->act_num_chan = channel->act_num_chan; + drv_data->dmic_state = DMIC_STATE_CONFIGURED; + + return 0; +} + +static int dmic_mcux_start(const struct device *dev) +{ + struct mcux_dmic_drv_data *drv_data = dev->data; + int ret; + + /* Allocate the initial set of buffers reserved for use by the hardware. + * We queue buffers so that when the DMA is operating on buffer "n", + * buffer "n+1" is already queued in the DMA hardware. When buffer "n" + * completes, we allocate another buffer and add it to the tail of the + * DMA descriptor chain. This approach requires the driver to allocate + * a minimum of two buffers + */ + + for (uint32_t i = 0; i < CONFIG_DMIC_MCUX_DMA_BUFFERS; i++) { + /* Allocate buffers for DMA */ + ret = k_mem_slab_alloc(drv_data->mem_slab, + &drv_data->dma_bufs[i], K_NO_WAIT); + if (ret < 0) { + LOG_ERR("failed to allocate buffer"); + return -ENOBUFS; + } + } + + ret = dmic_mcux_setup_dma(dev); + if (ret < 0) { + return ret; + } + + ret = dmic_mcux_enable_dma(drv_data, true); + if (ret < 0) { + return ret; + } + dmic_mcux_activate_channels(drv_data, true); + + return 0; +} + +static int dmic_mcux_trigger(const struct device *dev, + enum dmic_trigger cmd) +{ + struct mcux_dmic_drv_data *drv_data = dev->data; + + switch (cmd) { + case DMIC_TRIGGER_PAUSE: + /* Disable active channels */ + if (drv_data->dmic_state == DMIC_STATE_ACTIVE) { + dmic_mcux_activate_channels(drv_data, false); + } + drv_data->dmic_state = DMIC_STATE_PAUSED; + break; + case DMIC_TRIGGER_STOP: + if (drv_data->dmic_state == DMIC_STATE_ACTIVE) { + dmic_mcux_stop(drv_data); + } + drv_data->dmic_state = DMIC_STATE_CONFIGURED; + break; + case DMIC_TRIGGER_RELEASE: + /* Enable active channels */ + if (drv_data->dmic_state == DMIC_STATE_PAUSED) { + dmic_mcux_activate_channels(drv_data, true); + } + drv_data->dmic_state = DMIC_STATE_ACTIVE; + break; + case DMIC_TRIGGER_START: + if ((drv_data->dmic_state != DMIC_STATE_CONFIGURED) && + (drv_data->dmic_state != DMIC_STATE_ACTIVE)) { + LOG_ERR("Device is not configured"); + return -EIO; + } else if (drv_data->dmic_state != DMIC_STATE_ACTIVE) { + if (dmic_mcux_start(dev) < 0) { + LOG_ERR("Could not start DMIC"); + return -EIO; + } + drv_data->dmic_state = DMIC_STATE_ACTIVE; + } + break; + case DMIC_TRIGGER_RESET: + /* Reset DMIC to uninitialized state */ + DMIC_DeInit(drv_data->base_address); + drv_data->dmic_state = DMIC_STATE_UNINIT; + break; + default: + LOG_ERR("Invalid command: %d", cmd); + return -EINVAL; + } + return 0; +} + +static int dmic_mcux_read(const struct device *dev, + uint8_t stream, + void **buffer, size_t *size, int32_t timeout) +{ + struct mcux_dmic_drv_data *drv_data = dev->data; + int ret; + + ARG_UNUSED(stream); + + if (drv_data->dmic_state == DMIC_STATE_ERROR) { + LOG_ERR("Device reports an error, please reset and reconfigure it"); + return -EIO; + } + + if ((drv_data->dmic_state != DMIC_STATE_CONFIGURED) && + (drv_data->dmic_state != DMIC_STATE_ACTIVE) && + (drv_data->dmic_state != DMIC_STATE_PAUSED)) { + LOG_ERR("Device state is not valid for read"); + return -EIO; + } + + ret = k_msgq_get(drv_data->rx_queue, buffer, SYS_TIMEOUT_MS(timeout)); + if (ret < 0) { + return ret; + } + *size = drv_data->block_size; + + LOG_DBG("read buffer = %p", *buffer); + return 0; +} + +static const struct _dmic_ops dmic_ops = { + .configure = dmic_mcux_configure, + .trigger = dmic_mcux_trigger, + .read = dmic_mcux_read, +}; + +/* Converts integer gainshift into 5 bit 2's complement value for GAINSHIFT reg */ +#define PDM_DMIC_GAINSHIFT(val) \ + (val >= 0) ? (val & 0xF) : (BIT(4) | (0x10 - (val & 0xF))) + +/* Defines structure for a given PDM channel node */ +#define PDM_DMIC_CHAN_DEFINE(pdm_node) \ + static struct mcux_dmic_pdm_chan \ + pdm_channel_##pdm_node = { \ + .dma = DEVICE_DT_GET(DT_DMAS_CTLR(pdm_node)), \ + .dma_chan = DT_DMAS_CELL_BY_IDX(pdm_node, 0, channel), \ + .dmic_channel_cfg = { \ + .gainshft = PDM_DMIC_GAINSHIFT(DT_PROP(pdm_node, \ + gainshift)), \ + .preac2coef = DT_ENUM_IDX(pdm_node, compensation_2fs), \ + .preac4coef = DT_ENUM_IDX(pdm_node, compensation_4fs), \ + .dc_cut_level = DT_ENUM_IDX(pdm_node, dc_cutoff), \ + .post_dc_gain_reduce = DT_PROP(pdm_node, dc_gain), \ + .sample_rate = kDMIC_PhyFullSpeed, \ + .saturate16bit = 1U, \ + }, \ + }; + +/* Defines structures for all enabled PDM channels */ +#define PDM_DMIC_CHANNELS_DEFINE(idx) \ + DT_INST_FOREACH_CHILD_STATUS_OKAY(idx, PDM_DMIC_CHAN_DEFINE) + +/* Gets pointer for a given PDM channel node */ +#define PDM_DMIC_CHAN_GET(pdm_node) \ + COND_CODE_1(DT_NODE_HAS_STATUS(pdm_node, okay), \ + (&pdm_channel_##pdm_node), (NULL)), + +/* Gets array of pointers to PDM channels */ +#define PDM_DMIC_CHANNELS_GET(idx) \ + DT_INST_FOREACH_CHILD(idx, PDM_DMIC_CHAN_GET) + +#define MCUX_DMIC_DEVICE(idx) \ + PDM_DMIC_CHANNELS_DEFINE(idx); \ + static struct mcux_dmic_pdm_chan \ + *pdm_channels##idx[FSL_FEATURE_DMIC_CHANNEL_NUM] = { \ + PDM_DMIC_CHANNELS_GET(idx) \ + }; \ + K_MSGQ_DEFINE(dmic_msgq##idx, sizeof(void *), \ + CONFIG_DMIC_MCUX_QUEUE_SIZE, 1); \ + static struct mcux_dmic_drv_data mcux_dmic_data##idx = { \ + .pdm_channels = pdm_channels##idx, \ + .base_address = (DMIC_Type *) DT_INST_REG_ADDR(idx), \ + .dmic_state = DMIC_STATE_UNINIT, \ + .rx_queue = &dmic_msgq##idx, \ + .active_buf_idx = 0U, \ + }; \ + \ + PINCTRL_DT_INST_DEFINE(idx); \ + static struct mcux_dmic_cfg mcux_dmic_cfg##idx = { \ + .pcfg = PINCTRL_DT_INST_DEV_CONFIG_GET(idx), \ + .clock_dev = DEVICE_DT_GET(DT_INST_CLOCKS_CTLR(idx)), \ + .clock_name = (clock_control_subsys_t) \ + DT_INST_CLOCKS_CELL(idx, name), \ + .use2fs = DT_INST_PROP(idx, use2fs), \ + }; \ + \ + DEVICE_DT_INST_DEFINE(idx, mcux_dmic_init, NULL, \ + &mcux_dmic_data##idx, &mcux_dmic_cfg##idx, \ + POST_KERNEL, CONFIG_AUDIO_DMIC_INIT_PRIORITY, \ + &dmic_ops); + +/* Existing SoCs only have one PDM instance. */ +DT_INST_FOREACH_STATUS_OKAY(MCUX_DMIC_DEVICE) diff --git a/dts/bindings/audio/nxp,dmic.yaml b/dts/bindings/audio/nxp,dmic.yaml new file mode 100644 index 00000000000..77f1d0e74a7 --- /dev/null +++ b/dts/bindings/audio/nxp,dmic.yaml @@ -0,0 +1,97 @@ +# Copyright 2023 NXP +# SPDX-License-Identifier: Apache-2.0 + +description: NXP DMIC + +compatible: "nxp,dmic" + +include: [base.yaml, pinctrl-device.yaml] + +properties: + reg: + required: true + + interrupts: + required: true + + pinctrl-0: + required: true + + clocks: + required: true + + use2fs: + type: boolean + description: | + Use 2FS output, and bypass final half band decimator. This will reduce + the required PDM bit clock frequency by a factor of two, and can reduce + power consumption. + +# Child binding definition, describes each channel of the DMIC +child-binding: + description: | + NXP DMIC channel. Can be used to configure filtering and gain attributes + of each channel + include: base.yaml + compatible: "nxp,dmic-channel" + properties: + reg: + required: true + dmas: + required: true + + gainshift: + type: int + default: 0 + description: | + Decimator gain shift. Sets the number of bits to shift decimated PCM + data by, as a positive or negative number. Range of [-15,15]. Default + is reset value of register + + compensation-2fs: + type: string + default: "zero" + enum: + - "zero" + - "-0.16" + - "-0.15" + - "-0.13" + description: | + 2FS compensation filter. See SOC reference manual for filter response + of each value. Default value is reset value of register, and + recommended filter setting. + + compensation-4fs: + type: string + default: "zero" + enum: + - "zero" + - "-0.16" + - "-0.15" + - "-0.13" + description: | + 4FS compensation filter. See SOC reference manual for filter response + of each value. Default value is reset value of register, and + recommended filter setting. + + dc-cutoff: + type: string + default: "flat" + enum: + - "flat" + - "155hz" + - "78hz" + - "39hz" + description: | + DC cutoff filter setting. Default is reset value of register. Note that + each cutoff frequency is based on a sample frequency of 16KHz, so + actual cutoff values will scale up or down based on your sampling + frequency + + dc-gain: + type: int + default: 0 + description: | + DC gain fine adjustment. Number of bits to downshift the final + conversion result. Max value of 15. Default is reset value of + register From 6d562f1750e30fc91f115a0595fbb622e500c217 Mon Sep 17 00:00:00 2001 From: Daniel DeGrasse Date: Tue, 5 Dec 2023 23:08:48 +0000 Subject: [PATCH 2366/3723] soc: arm: nxp_imx: rt5xx: clock DMIC0 Clock DMIC0 from the audio PLL when DMIC driver class is enabled. Signed-off-by: Daniel DeGrasse Co-authored-by: Yves Vandervennet --- soc/arm/nxp_imx/rt5xx/soc.c | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/soc/arm/nxp_imx/rt5xx/soc.c b/soc/arm/nxp_imx/rt5xx/soc.c index 85e4a900413..9be4c6c151d 100644 --- a/soc/arm/nxp_imx/rt5xx/soc.c +++ b/soc/arm/nxp_imx/rt5xx/soc.c @@ -427,6 +427,19 @@ void __weak rt5xx_clock_init(void) RESET_PeripheralReset(kMRT0_RST_SHIFT_RSTn); #endif +#if DT_NODE_HAS_COMPAT_STATUS(DT_NODELABEL(dmic0), nxp_dmic, okay) + /* Using the Audio PLL as input clock leads to better clock dividers + * for typical PCM sample rates ({8,16,24,32,48,96} kHz. + */ + /* DMIC source from audio pll, divider 8, 24.576M/8=3.072MHZ + * Select Audio PLL as clock source. This should produce a bit clock + * of 3.072MHZ + */ + CLOCK_AttachClk(kAUDIO_PLL_to_DMIC); + CLOCK_SetClkDiv(kCLOCK_DivDmicClk, 8); + +#endif + /* Set SystemCoreClock variable. */ SystemCoreClock = CLOCK_INIT_CORE_CLOCK; From 9a14bece2031454d623b946d9f95c40050786f04 Mon Sep 17 00:00:00 2001 From: Daniel DeGrasse Date: Tue, 5 Dec 2023 22:34:20 +0000 Subject: [PATCH 2367/3723] dts: arm: nxp_rt5xx: add definition of the DMIC to devicetree Add definition of the DMIC to the RT5xx devicetree, including all PDM channels. Signed-off-by: Daniel DeGrasse Co-authored-by: Yves Vandervennet --- dts/arm/nxp/nxp_rt5xx_common.dtsi | 66 +++++++++++++++++++++++++++++++ 1 file changed, 66 insertions(+) diff --git a/dts/arm/nxp/nxp_rt5xx_common.dtsi b/dts/arm/nxp/nxp_rt5xx_common.dtsi index f63e27b5d6a..d84d89b8528 100644 --- a/dts/arm/nxp/nxp_rt5xx_common.dtsi +++ b/dts/arm/nxp/nxp_rt5xx_common.dtsi @@ -388,6 +388,72 @@ #dma-cells = <1>; }; + dmic0: dmic@121000 { + #address-cells=<1>; + #size-cells=<0>; + compatible = "nxp,dmic"; + reg = <0x121000 0x1000>; + interrupts = <25 0>; + status = "disabled"; + clocks = <&clkctl0 MCUX_DMIC_CLK>; + + pdmc0: dmic-channel@0 { + compatible = "nxp,dmic-channel"; + reg = <0>; + dmas = <&dma0 16>; + status = "disabled"; + }; + + pdmc1: dmic-channel@1 { + compatible = "nxp,dmic-channel"; + reg = <1>; + dmas = <&dma0 17>; + status = "disabled"; + }; + + pdmc2: dmic-channel@2 { + compatible = "nxp,dmic-channel"; + reg = <2>; + dmas = <&dma0 18>; + status = "disabled"; + }; + + pdmc3: dmic-channel@3 { + compatible = "nxp,dmic-channel"; + reg = <3>; + dmas = <&dma0 19>; + status = "disabled"; + }; + + pdmc4: dmic-channel@4 { + compatible = "nxp,dmic-channel"; + reg = <4>; + dmas = <&dma0 20>; + status = "disabled"; + }; + + pdmc5: dmic-channel@5 { + compatible = "nxp,dmic-channel"; + reg = <5>; + dmas = <&dma0 21>; + status = "disabled"; + }; + + pdmc6: dmic-channel@6 { + compatible = "nxp,dmic-channel"; + reg = <6>; + dmas = <&dma0 22>; + status = "disabled"; + }; + + pdmc7: dmic-channel@7 { + compatible = "nxp,dmic-channel"; + reg = <7>; + dmas = <&dma0 23>; + status = "disabled"; + }; + }; + os_timer: timers@113000 { compatible = "nxp,os-timer"; reg = <0x113000 0x1000>; From ff4143acfbb80c0b64ed61fb46b5be1a6794e8ab Mon Sep 17 00:00:00 2001 From: Daniel DeGrasse Date: Tue, 5 Dec 2023 22:35:23 +0000 Subject: [PATCH 2368/3723] boards: arm: mimxrt595_evk_cm33: enable DMIC0 channels 0 and 1 Enable L/R channel pair for DMIC0 on the RT595 EVK. The RT595 EVK has a pair of MEMS microphones wired to PDM channel 0 and 1, so these channels are configured with appropriate gain and filter settings for the MEMS microphones. Signed-off-by: Daniel DeGrasse Co-authored-by: Yves Vandervennet --- boards/arm/mimxrt595_evk/doc/index.rst | 2 ++ .../mimxrt595_evk_cm33-pinctrl.dtsi | 10 ++++++++ .../arm/mimxrt595_evk/mimxrt595_evk_cm33.dts | 25 +++++++++++++++++++ .../arm/mimxrt595_evk/mimxrt595_evk_cm33.yaml | 1 + .../dmic/boards/mimxrt595_evk_cm33.overlay | 3 +++ 5 files changed, 41 insertions(+) create mode 100644 samples/drivers/audio/dmic/boards/mimxrt595_evk_cm33.overlay diff --git a/boards/arm/mimxrt595_evk/doc/index.rst b/boards/arm/mimxrt595_evk/doc/index.rst index a82735ba278..8bdbd864a4e 100644 --- a/boards/arm/mimxrt595_evk/doc/index.rst +++ b/boards/arm/mimxrt595_evk/doc/index.rst @@ -113,6 +113,8 @@ already supported, which can also be re-used on this mimxrt595_evk board: | | | :ref:`rk055hdmipi4ma0`, and | | | | :ref:`g1120b0mipi` display shields | +-----------+------------+-------------------------------------+ +| DMIC | on-chip | dmic | ++-----------+------------+-------------------------------------+ The default configuration can be found in the defconfig file: diff --git a/boards/arm/mimxrt595_evk/mimxrt595_evk_cm33-pinctrl.dtsi b/boards/arm/mimxrt595_evk/mimxrt595_evk_cm33-pinctrl.dtsi index 4073475446b..f00f6a34d0f 100644 --- a/boards/arm/mimxrt595_evk/mimxrt595_evk_cm33-pinctrl.dtsi +++ b/boards/arm/mimxrt595_evk/mimxrt595_evk_cm33-pinctrl.dtsi @@ -46,6 +46,16 @@ }; }; + pinmux_dmic0: pinmux_dmic0 { + group0 { + pinmux = , , + ; + slew-rate = "normal"; + drive-strength = "normal"; + input-enable; + }; + }; + pinmux_flexcomm4_i2c: pinmux_flexcomm4_i2c { group0 { pinmux = , diff --git a/boards/arm/mimxrt595_evk/mimxrt595_evk_cm33.dts b/boards/arm/mimxrt595_evk/mimxrt595_evk_cm33.dts index a00a5ca844e..f32420304df 100644 --- a/boards/arm/mimxrt595_evk/mimxrt595_evk_cm33.dts +++ b/boards/arm/mimxrt595_evk/mimxrt595_evk_cm33.dts @@ -28,6 +28,7 @@ accel0 = &fxos8700; sdhc0 = &usdhc0; pwm-0 = &sc_timer; + dmic-dev = &dmic0; }; chosen { @@ -482,6 +483,30 @@ zephyr_udc0: &usbhs { dma-names = "smartdma"; }; +&dmic0 { + status = "okay"; + pinctrl-0 = <&pinmux_dmic0>; + pinctrl-names = "default"; + use2fs; +}; + +/* Configure pdm channels 0 and 1 with gain, and cutoff settings + * appropriate for the attached MEMS microphones. + */ +&pdmc0 { + status = "okay"; + gainshift = <3>; + dc-cutoff = "155hz"; + dc-gain = <1>; +}; + +&pdmc1 { + status = "okay"; + gainshift = <3>; + dc-cutoff = "155hz"; + dc-gain = <1>; +}; + &mrt_channel0 { status = "okay"; }; diff --git a/boards/arm/mimxrt595_evk/mimxrt595_evk_cm33.yaml b/boards/arm/mimxrt595_evk/mimxrt595_evk_cm33.yaml index 6e35595c078..95b17cb059f 100644 --- a/boards/arm/mimxrt595_evk/mimxrt595_evk_cm33.yaml +++ b/boards/arm/mimxrt595_evk/mimxrt595_evk_cm33.yaml @@ -28,4 +28,5 @@ supported: - sdhc - pwm - i2s + - dmic vendor: nxp diff --git a/samples/drivers/audio/dmic/boards/mimxrt595_evk_cm33.overlay b/samples/drivers/audio/dmic/boards/mimxrt595_evk_cm33.overlay new file mode 100644 index 00000000000..ce71fa65f01 --- /dev/null +++ b/samples/drivers/audio/dmic/boards/mimxrt595_evk_cm33.overlay @@ -0,0 +1,3 @@ +dmic_dev: &dmic0 { + status = "okay"; +}; From c4e48b66bd3643941712b3cfe4d64a078956460f Mon Sep 17 00:00:00 2001 From: Daniel DeGrasse Date: Tue, 5 Dec 2023 22:37:10 +0000 Subject: [PATCH 2369/3723] tests: drivers: audio: add dmic API test Add DMIC API test, intended to verify DMIC drivers are functioning correctly within the DMIC API. The test verifies the following: - Mono channel audio - Stereo channel audio - Using maximum number of channels supported by DMIC IP - Pausing/restarting channels - Checks to make sure invalid channel maps are rejected by the DMIC. Signed-off-by: Daniel DeGrasse --- tests/drivers/audio/dmic_api/CMakeLists.txt | 8 + tests/drivers/audio/dmic_api/README.txt | 19 ++ .../boards/mimxrt595_evk_cm33.overlay | 39 +++ tests/drivers/audio/dmic_api/prj.conf | 9 + tests/drivers/audio/dmic_api/src/main.c | 291 ++++++++++++++++++ tests/drivers/audio/dmic_api/testcase.yaml | 8 + 6 files changed, 374 insertions(+) create mode 100644 tests/drivers/audio/dmic_api/CMakeLists.txt create mode 100644 tests/drivers/audio/dmic_api/README.txt create mode 100644 tests/drivers/audio/dmic_api/boards/mimxrt595_evk_cm33.overlay create mode 100644 tests/drivers/audio/dmic_api/prj.conf create mode 100644 tests/drivers/audio/dmic_api/src/main.c create mode 100644 tests/drivers/audio/dmic_api/testcase.yaml diff --git a/tests/drivers/audio/dmic_api/CMakeLists.txt b/tests/drivers/audio/dmic_api/CMakeLists.txt new file mode 100644 index 00000000000..7d66184eab4 --- /dev/null +++ b/tests/drivers/audio/dmic_api/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(dmic_api) + +FILE(GLOB app_sources src/*.c) +target_sources(app PRIVATE ${app_sources}) diff --git a/tests/drivers/audio/dmic_api/README.txt b/tests/drivers/audio/dmic_api/README.txt new file mode 100644 index 00000000000..66df40b33c5 --- /dev/null +++ b/tests/drivers/audio/dmic_api/README.txt @@ -0,0 +1,19 @@ +DMIC API Test +################## + +This test is designed to verify that DMIC peripherals implement the API +correctly. It performs the following checks: + +* Verify the DMIC will not start sampling before it is configured + +* Verify the DMIC can sample from one left channel + +* Verify the DMIC can sample from a stereo L/R pair + +* Verify that the DMIC works with the maximum number of channels possible + (defined based on the DTS compatible present in the build) + +* Verify that the DMIC can restart sampling after being paused and resumed + +* Verify that invalid channel maps (R/R pair, non-adjacent channels) are + rejected by the DMIC driver. diff --git a/tests/drivers/audio/dmic_api/boards/mimxrt595_evk_cm33.overlay b/tests/drivers/audio/dmic_api/boards/mimxrt595_evk_cm33.overlay new file mode 100644 index 00000000000..96cb58b52c1 --- /dev/null +++ b/tests/drivers/audio/dmic_api/boards/mimxrt595_evk_cm33.overlay @@ -0,0 +1,39 @@ +/* + * SPDX-License-Identifier: Apache-2.0 + * + * Copyright 2023 NXP + */ + +/* Enable PDM channels 0-3, + * Gain settings are configured for testing with a PDM generator, + * using a -20dbFS sine wave. + */ +&dmic0 { + dmic-channel@0 { + status = "okay"; + gainshift = <3>; + dc-cutoff = "155hz"; + dc-gain = <1>; + }; + + dmic-channel@1 { + status = "okay"; + gainshift = <3>; + dc-cutoff = "155hz"; + dc-gain = <1>; + }; + + dmic-channel@2 { + status = "okay"; + gainshift = <3>; + dc-cutoff = "155hz"; + dc-gain = <1>; + }; + + dmic-channel@3 { + status = "okay"; + gainshift = <3>; + dc-cutoff = "155hz"; + dc-gain = <1>; + }; +}; diff --git a/tests/drivers/audio/dmic_api/prj.conf b/tests/drivers/audio/dmic_api/prj.conf new file mode 100644 index 00000000000..2b2ac5a5f9b --- /dev/null +++ b/tests/drivers/audio/dmic_api/prj.conf @@ -0,0 +1,9 @@ +CONFIG_TEST=y +CONFIG_ZTEST=y +CONFIG_AUDIO=y +CONFIG_AUDIO_DMIC=y + +# Use deferred logging mode so the TC_PRINT calls while reading from DMIC +# do not block +CONFIG_LOG=y +CONFIG_LOG_MODE_DEFERRED=y diff --git a/tests/drivers/audio/dmic_api/src/main.c b/tests/drivers/audio/dmic_api/src/main.c new file mode 100644 index 00000000000..488490e219c --- /dev/null +++ b/tests/drivers/audio/dmic_api/src/main.c @@ -0,0 +1,291 @@ +/* + * Copyright 2023 NXP + * + * SPDX-License-Identifier: Apache-2.0 + */ + +/* + * Based on DMIC driver sample, which is: + * Copyright (c) 2021 Nordic Semiconductor ASA + */ + +#include +#include +#include + +static const struct device *dmic_dev = DEVICE_DT_GET(DT_ALIAS(dmic_dev)); + +#if DT_HAS_COMPAT_STATUS_OKAY(nxp_dmic) +#define PDM_CHANNELS 4 /* Two L/R pairs of channels */ +#define SAMPLE_BIT_WIDTH 16 +#define BYTES_PER_SAMPLE sizeof(int16_t) +#define SLAB_ALIGN 4 +#define MAX_SAMPLE_RATE 48000 +/* Milliseconds to wait for a block to be read. */ +#define READ_TIMEOUT 1000 +/* Size of a block for 100 ms of audio data. */ +#define BLOCK_SIZE(_sample_rate, _number_of_channels) \ + (BYTES_PER_SAMPLE * (_sample_rate / 10) * _number_of_channels) +#else +#error "Unsupported DMIC device" +#endif + +/* Driver will allocate blocks from this slab to receive audio data into them. + * Application, after getting a given block from the driver and processing its + * data, needs to free that block. + */ +#define MAX_BLOCK_SIZE BLOCK_SIZE(MAX_SAMPLE_RATE, PDM_CHANNELS) +#define BLOCK_COUNT 8 +K_MEM_SLAB_DEFINE_STATIC(mem_slab, MAX_BLOCK_SIZE, BLOCK_COUNT, SLAB_ALIGN); + +static struct pcm_stream_cfg pcm_stream = { + .pcm_width = SAMPLE_BIT_WIDTH, + .mem_slab = &mem_slab, +}; +static struct dmic_cfg dmic_cfg = { + .io = { + /* These fields can be used to limit the PDM clock + * configurations that the driver is allowed to use + * to those supported by the microphone. + */ + .min_pdm_clk_freq = 1000000, + .max_pdm_clk_freq = 3500000, + .min_pdm_clk_dc = 40, + .max_pdm_clk_dc = 60, + }, + .streams = &pcm_stream, + .channel = { + .req_num_streams = 1, + }, +}; + +/* Verify that dmic_trigger fails when DMIC is not configured + * this test must run first, before DMIC has been configured + */ +ZTEST(dmic, test_0_start_fail) +{ + int ret; + + zassert_true(device_is_ready(dmic_dev), "DMIC device is not ready"); + ret = dmic_trigger(dmic_dev, DMIC_TRIGGER_START); + zassert_not_equal(ret, 0, "DMIC trigger should fail when DMIC is not configured"); +} + +static int do_pdm_transfer(const struct device *dmic, + struct dmic_cfg *cfg) +{ + int ret; + void *buffer; + uint32_t size; + + TC_PRINT("PCM output rate: %u, channels: %u\n", + cfg->streams[0].pcm_rate, cfg->channel.req_num_chan); + + ret = dmic_configure(dmic, cfg); + if (ret < 0) { + TC_PRINT("DMIC configuration failed: %d\n", ret); + return ret; + } + + /* Check that the driver is properly populating the "act*" fields */ + zassert_equal(cfg->channel.act_num_chan, + cfg->channel.req_num_chan, + "DMIC configure should populate act_num_chan field"); + zassert_equal(cfg->channel.act_chan_map_lo, + cfg->channel.req_chan_map_lo, + "DMIC configure should populate act_chan_map_lo field"); + zassert_equal(cfg->channel.act_chan_map_hi, + cfg->channel.req_chan_map_hi, + "DMIC configure should populate act_chan_map_hi field"); + ret = dmic_trigger(dmic, DMIC_TRIGGER_START); + if (ret < 0) { + TC_PRINT("DMIC start trigger failed: %d\n", ret); + return ret; + } + + /* We read more than the total BLOCK_COUNT to insure the DMIC + * driver correctly reallocates memory slabs as it exhausts existing + * ones. + */ + for (int i = 0; i < (2 * BLOCK_COUNT); i++) { + ret = dmic_read(dmic, 0, &buffer, &size, READ_TIMEOUT); + if (ret < 0) { + TC_PRINT("DMIC read failed: %d\n", ret); + return ret; + } + + TC_PRINT("%d - got buffer %p of %u bytes\n", i, buffer, size); + k_mem_slab_free(&mem_slab, buffer); + } + + ret = dmic_trigger(dmic, DMIC_TRIGGER_STOP); + if (ret < 0) { + TC_PRINT("DMIC stop trigger failed: %d\n", ret); + return ret; + } + return 0; +} + + +/* Verify that the DMIC can transfer from a single channel */ +ZTEST(dmic, test_single_channel) +{ + dmic_cfg.channel.req_num_chan = 1; + dmic_cfg.channel.req_chan_map_lo = + dmic_build_channel_map(0, 0, PDM_CHAN_LEFT); + dmic_cfg.streams[0].pcm_rate = MAX_SAMPLE_RATE; + dmic_cfg.streams[0].block_size = + BLOCK_SIZE(dmic_cfg.streams[0].pcm_rate, + dmic_cfg.channel.req_num_chan); + zassert_equal(do_pdm_transfer(dmic_dev, &dmic_cfg), 0, + "Single channel transfer failed"); +} + +/* Verify that the DMIC can transfer from a L/R channel pair */ +ZTEST(dmic, test_stereo_channel) +{ + dmic_cfg.channel.req_num_chan = 2; + dmic_cfg.channel.req_chan_map_lo = + dmic_build_channel_map(0, 0, PDM_CHAN_LEFT) | + dmic_build_channel_map(1, 0, PDM_CHAN_RIGHT); + dmic_cfg.streams[0].pcm_rate = MAX_SAMPLE_RATE; + dmic_cfg.streams[0].block_size = + BLOCK_SIZE(dmic_cfg.streams[0].pcm_rate, + dmic_cfg.channel.req_num_chan); + zassert_equal(do_pdm_transfer(dmic_dev, &dmic_cfg), 0, + "L/R channel transfer failed"); + dmic_cfg.channel.req_chan_map_lo = + dmic_build_channel_map(0, 0, PDM_CHAN_RIGHT) | + dmic_build_channel_map(1, 0, PDM_CHAN_LEFT); + zassert_equal(do_pdm_transfer(dmic_dev, &dmic_cfg), 0, + "R/L channel transfer failed"); +} + +/* Test DMIC with maximum number of channels */ +ZTEST(dmic, test_max_channel) +{ + enum pdm_lr lr; + uint8_t pdm_hw_chan; + + dmic_cfg.channel.req_num_chan = PDM_CHANNELS; + dmic_cfg.channel.req_chan_map_lo = 0; + dmic_cfg.channel.req_chan_map_hi = 0; + for (uint8_t i = 0; i < PDM_CHANNELS; i++) { + lr = ((i % 2) == 0) ? PDM_CHAN_LEFT : PDM_CHAN_RIGHT; + pdm_hw_chan = i >> 1; + if (i < 4) { + dmic_cfg.channel.req_chan_map_lo |= + dmic_build_channel_map(i, pdm_hw_chan, lr); + } else { + dmic_cfg.channel.req_chan_map_hi |= + dmic_build_channel_map(i, pdm_hw_chan, lr); + } + } + + dmic_cfg.streams[0].pcm_rate = MAX_SAMPLE_RATE; + dmic_cfg.streams[0].block_size = + BLOCK_SIZE(dmic_cfg.streams[0].pcm_rate, + dmic_cfg.channel.req_num_chan); + zassert_equal(do_pdm_transfer(dmic_dev, &dmic_cfg), 0, + "Maximum channel transfer failed"); +} + +/* Test pausing and restarting a channel */ +ZTEST(dmic, test_pause_restart) +{ + int ret, i; + void *buffer; + uint32_t size; + + dmic_cfg.channel.req_num_chan = 1; + dmic_cfg.channel.req_chan_map_lo = + dmic_build_channel_map(0, 0, PDM_CHAN_LEFT); + dmic_cfg.streams[0].pcm_rate = MAX_SAMPLE_RATE; + dmic_cfg.streams[0].block_size = + BLOCK_SIZE(dmic_cfg.streams[0].pcm_rate, + dmic_cfg.channel.req_num_chan); + ret = dmic_configure(dmic_dev, &dmic_cfg); + zassert_equal(ret, 0, "DMIC configure failed"); + + /* Start the DMIC, and pause it immediately */ + ret = dmic_trigger(dmic_dev, DMIC_TRIGGER_START); + zassert_equal(ret, 0, "DMIC start failed"); + ret = dmic_trigger(dmic_dev, DMIC_TRIGGER_PAUSE); + zassert_equal(ret, 0, "DMIC pause failed"); + /* There may be some buffers in the DMIC queue, but a read + * should eventually time out while it is paused + */ + for (i = 0; i < (2 * BLOCK_COUNT); i++) { + ret = dmic_read(dmic_dev, 0, &buffer, &size, READ_TIMEOUT); + if (ret < 0) { + break; + } + k_mem_slab_free(&mem_slab, buffer); + } + zassert_not_equal(ret, 0, "DMIC is paused, reads should timeout"); + TC_PRINT("Queue drained after %d reads\n", i); + /* Unpause the DMIC */ + ret = dmic_trigger(dmic_dev, DMIC_TRIGGER_RELEASE); + zassert_equal(ret, 0, "DMIC release failed"); + /* Reads should not timeout now */ + for (i = 0; i < (2 * BLOCK_COUNT); i++) { + ret = dmic_read(dmic_dev, 0, &buffer, &size, READ_TIMEOUT); + if (ret < 0) { + break; + } + k_mem_slab_free(&mem_slab, buffer); + } + zassert_equal(ret, 0, "DMIC is active, reads should succeed"); + TC_PRINT("%d reads completed\n", (2 * BLOCK_COUNT)); + /* Stop the DMIC, and repeat the same tests */ + ret = dmic_trigger(dmic_dev, DMIC_TRIGGER_STOP); + zassert_equal(ret, 0, "DMIC stop failed"); + /* Versus a pause, DMIC reads should immediately stop once DMIC times + * out + */ + ret = dmic_read(dmic_dev, 0, &buffer, &size, READ_TIMEOUT); + zassert_not_equal(ret, 0, "DMIC read should timeout when DMIC is stopped"); + ret = dmic_trigger(dmic_dev, DMIC_TRIGGER_START); + zassert_equal(ret, 0, "DMIC restart failed"); + /* Reads should not timeout now */ + for (i = 0; i < (2 * BLOCK_COUNT); i++) { + ret = dmic_read(dmic_dev, 0, &buffer, &size, READ_TIMEOUT); + if (ret < 0) { + break; + } + k_mem_slab_free(&mem_slab, buffer); + } + zassert_equal(ret, 0, "DMIC is active, reads should succeed"); + TC_PRINT("%d reads completed\n", (2 * BLOCK_COUNT)); + /* Test is over. Stop the DMIC */ + ret = dmic_trigger(dmic_dev, DMIC_TRIGGER_STOP); + zassert_equal(ret, 0, "DMIC stop failed"); +} + +/* Verify that channel map without adjacent L/R pairs fails */ +ZTEST(dmic, test_bad_pair) +{ + int ret; + + dmic_cfg.channel.req_num_chan = 2; + dmic_cfg.channel.req_chan_map_lo = + dmic_build_channel_map(0, 0, PDM_CHAN_RIGHT) | + dmic_build_channel_map(1, 0, PDM_CHAN_RIGHT); + dmic_cfg.streams[0].pcm_rate = MAX_SAMPLE_RATE; + dmic_cfg.streams[0].block_size = + BLOCK_SIZE(dmic_cfg.streams[0].pcm_rate, + dmic_cfg.channel.req_num_chan); + ret = dmic_configure(dmic_dev, &dmic_cfg); + zassert_not_equal(ret, 0, "DMIC configure should fail with " + "two of same channel in map"); + + dmic_cfg.channel.req_num_chan = 2; + dmic_cfg.channel.req_chan_map_lo = + dmic_build_channel_map(0, 0, PDM_CHAN_RIGHT) | + dmic_build_channel_map(1, 1, PDM_CHAN_LEFT); + ret = dmic_configure(dmic_dev, &dmic_cfg); + zassert_not_equal(ret, 0, "DMIC configure should fail with " + "non adjacent channels in map"); +} + +ZTEST_SUITE(dmic, NULL, NULL, NULL, NULL, NULL); diff --git a/tests/drivers/audio/dmic_api/testcase.yaml b/tests/drivers/audio/dmic_api/testcase.yaml new file mode 100644 index 00000000000..960aad3323a --- /dev/null +++ b/tests/drivers/audio/dmic_api/testcase.yaml @@ -0,0 +1,8 @@ +tests: + drivers.audio.dmic_api: + depends_on: dmic + tags: dmic + harness: ztest + filter: dt_alias_exists("dmic-dev") + integration_platforms: + - mimxrt595_evk_cm33 From 056d5a354bcf549a37d968803d3c456a7e2e6252 Mon Sep 17 00:00:00 2001 From: Morten Priess Date: Mon, 30 Oct 2023 16:54:18 +0100 Subject: [PATCH 2370/3723] Bluetooth: controller: Handle peripheral CIS creation latency Instead of asserting, handle CIS creation latency for the peripheral by finding next valid ISO event at which to start the CIG ticker. Refactored calculations of the cig_offset to separate functions, to be used also when calculating a new start offset. Signed-off-by: Morten Priess --- .../bluetooth/controller/ll_sw/ull_conn_iso.c | 126 ++++++++++++------ 1 file changed, 87 insertions(+), 39 deletions(-) diff --git a/subsys/bluetooth/controller/ll_sw/ull_conn_iso.c b/subsys/bluetooth/controller/ll_sw/ull_conn_iso.c index 467460d2f30..4675c103ba4 100644 --- a/subsys/bluetooth/controller/ll_sw/ull_conn_iso.c +++ b/subsys/bluetooth/controller/ll_sw/ull_conn_iso.c @@ -775,18 +775,44 @@ void ull_conn_iso_ticker_cb(uint32_t ticks_at_expire, uint32_t ticks_drift, ull_conn_iso_transmit_test_cig_interval(cig->lll.handle, ticks_at_expire); } +static uint32_t cig_offset_calc(struct ll_conn_iso_group *cig, struct ll_conn_iso_stream *cis, + uint32_t cis_offset, uint32_t *ticks_at_expire, uint32_t remainder) +{ + uint32_t acl_to_cig_ref_point; + uint32_t cis_offs_to_cig_ref; + uint32_t remainder_us; + + remainder_us = remainder; + hal_ticker_remove_jitter(ticks_at_expire, &remainder_us); + + cis_offs_to_cig_ref = cig->sync_delay - cis->sync_delay; + + /* Establish the CIG reference point by adjusting ACL-to-CIS offset + * (cis->offset) by the difference between CIG- and CIS sync delays. + */ + acl_to_cig_ref_point = cis_offset - cis_offs_to_cig_ref; + + /* Calculate the CIG reference point of first CIG event. This + * calculation is inaccurate. However it is the best estimate available + * until the first anchor point for the leading CIS is available. + */ + cig->cig_ref_point = isoal_get_wrapped_time_us(HAL_TICKER_TICKS_TO_US(*ticks_at_expire), + remainder_us + + EVENT_OVERHEAD_START_US + + acl_to_cig_ref_point); + /* Calculate initial ticker offset */ + return remainder_us + acl_to_cig_ref_point; +} + void ull_conn_iso_start(struct ll_conn *conn, uint16_t cis_handle, uint32_t ticks_at_expire, uint32_t remainder, uint16_t instant_latency) { struct ll_conn_iso_group *cig; struct ll_conn_iso_stream *cis; - uint32_t acl_to_cig_ref_point; - uint32_t cis_offs_to_cig_ref; uint32_t ticks_remainder; uint32_t ticks_periodic; uint32_t ticker_status; - uint32_t remainder_us; int32_t cig_offset_us; uint32_t ticks_slot; uint8_t ticker_id; @@ -794,9 +820,7 @@ void ull_conn_iso_start(struct ll_conn *conn, uint16_t cis_handle, cis = ll_conn_iso_stream_get(cis_handle); cig = cis->group; - cis_offs_to_cig_ref = cig->sync_delay - cis->sync_delay; - - cis->lll.offset = cis_offs_to_cig_ref; + cis->lll.offset = cig->sync_delay - cis->sync_delay; cis->lll.handle = cis_handle; #if defined(CONFIG_BT_CTLR_LE_ENC) @@ -868,25 +892,7 @@ void ull_conn_iso_start(struct ll_conn *conn, uint16_t cis_handle, ticker_id = TICKER_ID_CONN_ISO_BASE + ll_conn_iso_group_handle_get(cig); - remainder_us = remainder; - hal_ticker_remove_jitter(&ticks_at_expire, &remainder_us); - - /* Establish the CIG reference point by adjusting ACL-to-CIS offset - * (cis->offset) by the difference between CIG- and CIS sync delays. - */ - acl_to_cig_ref_point = cis->offset - cis_offs_to_cig_ref; - - /* Calculate initial ticker offset */ - cig_offset_us = remainder_us + acl_to_cig_ref_point; - - /* Calculate the CIG reference point of first CIG event. This - * calculation is inaccurate. However it is the best estimate available - * until the first anchor point for the leading CIS is available. - */ - cig->cig_ref_point = isoal_get_wrapped_time_us(HAL_TICKER_TICKS_TO_US(ticks_at_expire), - remainder_us + - EVENT_OVERHEAD_START_US + - acl_to_cig_ref_point); + cig_offset_us = cig_offset_calc(cig, cis, cis->offset, &ticks_at_expire, remainder); if (false) { @@ -900,8 +906,6 @@ void ull_conn_iso_start(struct ll_conn *conn, uint16_t cis_handle, */ iso_interval_us_frac = EVENT_US_TO_US_FRAC(cig->iso_interval * ISO_INT_UNIT_US) - cig->lll.window_widening_periodic_us_frac; - ticks_periodic = EVENT_US_FRAC_TO_TICKS(iso_interval_us_frac); - ticks_remainder = EVENT_US_FRAC_TO_REMAINDER(iso_interval_us_frac); #if defined(CONFIG_BT_CTLR_PERIPHERAL_ISO_EARLY_CIG_START) bool early_start = (cis->offset < EVENT_OVERHEAD_START_US); @@ -914,22 +918,66 @@ void ull_conn_iso_start(struct ll_conn *conn, uint16_t cis_handle, cig_offset_us += (conn->lll.interval * CONN_INT_UNIT_US); cig->cig_ref_point = isoal_get_wrapped_time_us(cig->cig_ref_point, conn->lll.interval * CONN_INT_UNIT_US); - } else { - LL_ASSERT(instant_latency == 1U); + } else if (instant_latency > 1U) { + /* We have passed the last possible event for a timely start. For + * early_start this means the latency is actually one less. + */ + instant_latency--; } - } else { - /* FIXME: Handle latency due to skipped ACL events around the - * instant to start CIG - */ - LL_ASSERT(instant_latency == 0U); } -#else /* CONFIG_BT_CTLR_PERIPHERAL_ISO_EARLY_CIG_START */ - /* FIXME: Handle latency due to skipped ACL events around the - * instant to start CIG - */ - LL_ASSERT(instant_latency == 0U); #endif /* CONFIG_BT_CTLR_PERIPHERAL_ISO_EARLY_CIG_START */ + if (instant_latency > 0U) { + /* Try to start the CIG late by finding the CIG event relative to current + * ACL event, taking latency into consideration. Adjust ticker periodicity + * with increased window widening. + */ + uint32_t lost_cig_events; + uint32_t iso_interval_us; + uint32_t acl_latency_us; + uint32_t lost_payloads; + uint32_t cis_offset; + + acl_latency_us = instant_latency * conn->lll.interval * CONN_INT_UNIT_US; + iso_interval_us = cig->iso_interval * ISO_INT_UNIT_US; + + if (acl_latency_us > iso_interval_us) { + /* Latency is greater than the ISO interval - find the offset from + * this ACL event to the next active ISO event, and adjust the event + * counter accordingly. + */ + lost_cig_events = DIV_ROUND_UP(acl_latency_us - cis->offset, + iso_interval_us); + cis_offset = cis->offset + (lost_cig_events * iso_interval_us) - + acl_latency_us; + } else { + /* Latency is less than- or equal to one ISO interval - start at + * next ISO event. + */ + lost_cig_events = 1U; + cis_offset = cis->offset + iso_interval_us - acl_latency_us; + } + + cis->lll.event_count += lost_cig_events; + + lost_payloads = (lost_cig_events - (cis->lll.rx.ft - 1)) * cis->lll.rx.bn; + cis->lll.rx.payload_count += lost_payloads; + + lost_payloads = (lost_cig_events - (cis->lll.tx.ft - 1)) * cis->lll.tx.bn; + cis->lll.tx.payload_count += lost_payloads; + + /* Adjust for extra window widening */ + iso_interval_us_frac = EVENT_US_TO_US_FRAC(cig->iso_interval * + ISO_INT_UNIT_US); + iso_interval_us_frac -= cig->lll.window_widening_periodic_us_frac * + instant_latency; + /* Calculate new offset */ + cig_offset_us = cig_offset_calc(cig, cis, cis_offset, &ticks_at_expire, + remainder); + } + + ticks_periodic = EVENT_US_FRAC_TO_TICKS(iso_interval_us_frac); + ticks_remainder = EVENT_US_FRAC_TO_REMAINDER(iso_interval_us_frac); #endif /* CONFIG_BT_CTLR_PERIPHERAL_ISO */ } else if (IS_CENTRAL(cig)) { From 06edc375216bcfc6ab0b93e29aaf21ffd2f535b5 Mon Sep 17 00:00:00 2001 From: Armando Visconti Date: Wed, 17 Jan 2024 10:12:43 +0100 Subject: [PATCH 2371/3723] samples: sensor: lps22hb: fix sample document The LPS22HB is a pressure and temperature sensor, but this sample document is wrongly mentioning "humidity". Fix #66117 Signed-off-by: Armando Visconti --- samples/sensor/lps22hb/README.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/samples/sensor/lps22hb/README.rst b/samples/sensor/lps22hb/README.rst index f469f05b6db..4ff98457e50 100644 --- a/samples/sensor/lps22hb/README.rst +++ b/samples/sensor/lps22hb/README.rst @@ -1,6 +1,6 @@ .. _lps22hb: -LPS22HB: Temperature and Humidity Monitor +LPS22HB: Temperature and Pressure Monitor ######################################### Overview From c1146278536ccf135695004b24eb8242add74b75 Mon Sep 17 00:00:00 2001 From: Bjarki Arge Andreasen Date: Fri, 24 Nov 2023 14:47:59 +0100 Subject: [PATCH 2372/3723] modem: cmux: Implement TRANSMIT_IDLE event Implement transmit idle event both for transmitting data to the bus, and for the individual DLCI channels. Signed-off-by: Bjarki Arge Andreasen --- subsys/modem/modem_cmux.c | 58 ++++++++++++++++++++++++++++----------- 1 file changed, 42 insertions(+), 16 deletions(-) diff --git a/subsys/modem/modem_cmux.c b/subsys/modem/modem_cmux.c index dc7c3915566..13a153b8533 100644 --- a/subsys/modem/modem_cmux.c +++ b/subsys/modem/modem_cmux.c @@ -197,8 +197,17 @@ static void modem_cmux_bus_callback(struct modem_pipe *pipe, enum modem_pipe_eve { struct modem_cmux *cmux = (struct modem_cmux *)user_data; - if (event == MODEM_PIPE_EVENT_RECEIVE_READY) { + switch (event) { + case MODEM_PIPE_EVENT_RECEIVE_READY: k_work_schedule(&cmux->receive_work, K_NO_WAIT); + break; + + case MODEM_PIPE_EVENT_TRANSMIT_IDLE: + k_work_schedule(&cmux->transmit_work, K_NO_WAIT); + break; + + default: + break; } } @@ -833,6 +842,17 @@ static void modem_cmux_receive_handler(struct k_work *item) k_work_schedule(&cmux->receive_work, K_NO_WAIT); } +static void modem_cmux_dlci_notify_transmit_idle(struct modem_cmux *cmux) +{ + sys_snode_t *node; + struct modem_cmux_dlci *dlci; + + SYS_SLIST_FOR_EACH_NODE(&cmux->dlcis, node) { + dlci = (struct modem_cmux_dlci *)node; + modem_pipe_notify_transmit_idle(&dlci->pipe); + } +} + static void modem_cmux_transmit_handler(struct k_work *item) { struct k_work_delayable *dwork = k_work_delayable_from_work(item); @@ -840,31 +860,37 @@ static void modem_cmux_transmit_handler(struct k_work *item) uint8_t *reserved; uint32_t reserved_size; int ret; + bool transmit_rb_empty; k_mutex_lock(&cmux->transmit_rb_lock, K_FOREVER); - /* Reserve data to transmit from transmit ring buffer */ - reserved_size = ring_buf_get_claim(&cmux->transmit_rb, &reserved, UINT32_MAX); + while (true) { + transmit_rb_empty = ring_buf_is_empty(&cmux->transmit_rb); - /* Transmit reserved data */ - ret = modem_pipe_transmit(cmux->pipe, reserved, reserved_size); - if (ret < 1) { - ring_buf_get_finish(&cmux->transmit_rb, 0); - k_mutex_unlock(&cmux->transmit_rb_lock); - k_work_schedule(&cmux->transmit_work, K_NO_WAIT); + if (transmit_rb_empty) { + break; + } - return; - } + reserved_size = ring_buf_get_claim(&cmux->transmit_rb, &reserved, UINT32_MAX); - /* Release remaining reserved data */ - ring_buf_get_finish(&cmux->transmit_rb, ret); + ret = modem_pipe_transmit(cmux->pipe, reserved, reserved_size); + if (ret < 0) { + ring_buf_get_finish(&cmux->transmit_rb, 0); + break; + } - /* Resubmit transmit work if data remains */ - if (ring_buf_is_empty(&cmux->transmit_rb) == false) { - k_work_schedule(&cmux->transmit_work, K_NO_WAIT); + ring_buf_get_finish(&cmux->transmit_rb, (uint32_t)ret); + + if (ret == 0) { + break; + } } k_mutex_unlock(&cmux->transmit_rb_lock); + + if (transmit_rb_empty) { + modem_cmux_dlci_notify_transmit_idle(cmux); + } } static void modem_cmux_connect_handler(struct k_work *item) From 358f1ff93404d081b8f07c9faacb81097ce09346 Mon Sep 17 00:00:00 2001 From: Bjarki Arge Andreasen Date: Fri, 24 Nov 2023 16:09:40 +0100 Subject: [PATCH 2373/3723] tests: modem: cmux: Implement TRANSMIT_IDLE into test suite Use transmit idle event to synchronize with data transmitted through DLCI pipes to test TRANSMIT_IDLE implementation. Signed-off-by: Bjarki Arge Andreasen --- subsys/modem/modem_cmux.c | 2 +- tests/subsys/modem/modem_cmux/src/main.c | 61 ++++++++++++++++++++---- 2 files changed, 53 insertions(+), 10 deletions(-) diff --git a/subsys/modem/modem_cmux.c b/subsys/modem/modem_cmux.c index 13a153b8533..16dc60b7219 100644 --- a/subsys/modem/modem_cmux.c +++ b/subsys/modem/modem_cmux.c @@ -881,7 +881,7 @@ static void modem_cmux_transmit_handler(struct k_work *item) ring_buf_get_finish(&cmux->transmit_rb, (uint32_t)ret); - if (ret == 0) { + if (ret < reserved_size) { break; } } diff --git a/tests/subsys/modem/modem_cmux/src/main.c b/tests/subsys/modem/modem_cmux/src/main.c index d601eeb1446..b08cf26b5af 100644 --- a/tests/subsys/modem/modem_cmux/src/main.c +++ b/tests/subsys/modem/modem_cmux/src/main.c @@ -17,12 +17,16 @@ /*************************************************************************************************/ /* Definitions */ /*************************************************************************************************/ -#define EVENT_CMUX_CONNECTED BIT(0) -#define EVENT_CMUX_DLCI1_OPEN BIT(1) -#define EVENT_CMUX_DLCI2_OPEN BIT(2) -#define EVENT_CMUX_DLCI1_CLOSED BIT(3) -#define EVENT_CMUX_DLCI2_CLOSED BIT(4) -#define EVENT_CMUX_DISCONNECTED BIT(5) +#define EVENT_CMUX_CONNECTED BIT(0) +#define EVENT_CMUX_DLCI1_OPEN BIT(1) +#define EVENT_CMUX_DLCI2_OPEN BIT(2) +#define EVENT_CMUX_DLCI1_RECEIVE_READY BIT(3) +#define EVENT_CMUX_DLCI1_TRANSMIT_IDLE BIT(4) +#define EVENT_CMUX_DLCI2_RECEIVE_READY BIT(5) +#define EVENT_CMUX_DLCI2_TRANSMIT_IDLE BIT(6) +#define EVENT_CMUX_DLCI1_CLOSED BIT(7) +#define EVENT_CMUX_DLCI2_CLOSED BIT(8) +#define EVENT_CMUX_DISCONNECTED BIT(9) /*************************************************************************************************/ /* Instances */ @@ -59,6 +63,14 @@ static void test_modem_dlci1_pipe_callback(struct modem_pipe *pipe, enum modem_p k_event_post(&cmux_event, EVENT_CMUX_DLCI1_OPEN); break; + case MODEM_PIPE_EVENT_RECEIVE_READY: + k_event_post(&cmux_event, EVENT_CMUX_DLCI1_RECEIVE_READY); + break; + + case MODEM_PIPE_EVENT_TRANSMIT_IDLE: + k_event_post(&cmux_event, EVENT_CMUX_DLCI1_TRANSMIT_IDLE); + break; + case MODEM_PIPE_EVENT_CLOSED: k_event_post(&cmux_event, EVENT_CMUX_DLCI1_CLOSED); break; @@ -76,6 +88,14 @@ static void test_modem_dlci2_pipe_callback(struct modem_pipe *pipe, enum modem_p k_event_post(&cmux_event, EVENT_CMUX_DLCI2_OPEN); break; + case MODEM_PIPE_EVENT_RECEIVE_READY: + k_event_post(&cmux_event, EVENT_CMUX_DLCI2_RECEIVE_READY); + break; + + case MODEM_PIPE_EVENT_TRANSMIT_IDLE: + k_event_post(&cmux_event, EVENT_CMUX_DLCI2_TRANSMIT_IDLE); + break; + case MODEM_PIPE_EVENT_CLOSED: k_event_post(&cmux_event, EVENT_CMUX_DLCI2_CLOSED); break; @@ -300,6 +320,7 @@ static void test_modem_cmux_before(void *f) ZTEST(modem_cmux, test_modem_cmux_receive_dlci2_at) { int ret; + uint32_t events; modem_backend_mock_put(&bus_mock, cmux_frame_dlci2_at_cgdcont, sizeof(cmux_frame_dlci2_at_cgdcont)); @@ -309,6 +330,10 @@ ZTEST(modem_cmux, test_modem_cmux_receive_dlci2_at) k_msleep(100); + events = k_event_test(&cmux_event, EVENT_CMUX_DLCI2_RECEIVE_READY); + zassert_equal(events, EVENT_CMUX_DLCI2_RECEIVE_READY, + "Receive ready event not received for DLCI2 pipe"); + ret = modem_pipe_receive(dlci2_pipe, buffer2, sizeof(buffer2)); zassert_true(ret == (sizeof(cmux_frame_data_dlci2_at_cgdcont) + sizeof(cmux_frame_data_dlci2_at_newline)), @@ -327,6 +352,7 @@ ZTEST(modem_cmux, test_modem_cmux_receive_dlci2_at) ZTEST(modem_cmux, test_modem_cmux_receive_dlci1_at) { int ret; + uint32_t events; modem_backend_mock_put(&bus_mock, cmux_frame_dlci1_at_at, sizeof(cmux_frame_dlci1_at_at)); modem_backend_mock_put(&bus_mock, cmux_frame_dlci1_at_newline, @@ -334,6 +360,10 @@ ZTEST(modem_cmux, test_modem_cmux_receive_dlci1_at) k_msleep(100); + events = k_event_test(&cmux_event, EVENT_CMUX_DLCI1_RECEIVE_READY); + zassert_equal(events, EVENT_CMUX_DLCI1_RECEIVE_READY, + "Receive ready event not received for DLCI1 pipe"); + ret = modem_pipe_receive(dlci1_pipe, buffer1, sizeof(buffer1)); zassert_true(ret == (sizeof(cmux_frame_data_dlci1_at_at) + sizeof(cmux_frame_data_dlci1_at_newline)), @@ -352,12 +382,17 @@ ZTEST(modem_cmux, test_modem_cmux_receive_dlci1_at) ZTEST(modem_cmux, test_modem_cmux_receive_dlci2_ppp) { int ret; + uint32_t events; modem_backend_mock_put(&bus_mock, cmux_frame_dlci2_ppp_52, sizeof(cmux_frame_dlci2_ppp_52)); modem_backend_mock_put(&bus_mock, cmux_frame_dlci2_ppp_18, sizeof(cmux_frame_dlci2_ppp_18)); k_msleep(100); + events = k_event_test(&cmux_event, EVENT_CMUX_DLCI2_RECEIVE_READY); + zassert_equal(events, EVENT_CMUX_DLCI2_RECEIVE_READY, + "Receive ready event not received for DLCI2 pipe"); + ret = modem_pipe_receive(dlci2_pipe, buffer2, sizeof(buffer2)); zassert_true(ret == (sizeof(cmux_frame_data_dlci2_ppp_52) + sizeof(cmux_frame_data_dlci2_ppp_18)), @@ -376,17 +411,25 @@ ZTEST(modem_cmux, test_modem_cmux_receive_dlci2_ppp) ZTEST(modem_cmux, test_modem_cmux_transmit_dlci2_ppp) { int ret; + uint32_t events; ret = modem_pipe_transmit(dlci2_pipe, cmux_frame_data_dlci2_ppp_52, sizeof(cmux_frame_data_dlci2_ppp_52)); - zassert_true(ret == sizeof(cmux_frame_data_dlci2_ppp_52), "Failed to send DLCI2 PPP 52"); + + events = k_event_wait(&cmux_event, EVENT_CMUX_DLCI2_TRANSMIT_IDLE, false, K_MSEC(200)); + zassert_equal(events, EVENT_CMUX_DLCI2_TRANSMIT_IDLE, + "Transmit idle event not received for DLCI2 pipe"); + + k_event_clear(&cmux_event, EVENT_CMUX_DLCI2_TRANSMIT_IDLE); + ret = modem_pipe_transmit(dlci2_pipe, cmux_frame_data_dlci2_ppp_18, sizeof(cmux_frame_data_dlci2_ppp_18)); - zassert_true(ret == sizeof(cmux_frame_data_dlci2_ppp_18), "Failed to send DLCI2 PPP 18"); - k_msleep(100); + events = k_event_wait(&cmux_event, EVENT_CMUX_DLCI2_TRANSMIT_IDLE, false, K_MSEC(200)); + zassert_equal(events, EVENT_CMUX_DLCI2_TRANSMIT_IDLE, + "Transmit idle event not received for DLCI2 pipe"); ret = modem_backend_mock_get(&bus_mock, buffer2, sizeof(buffer2)); zassert_true(ret == (sizeof(cmux_frame_dlci2_ppp_52) + sizeof(cmux_frame_dlci2_ppp_18)), From 61e301a059a75c884eb22345ed295c1accc6efbb Mon Sep 17 00:00:00 2001 From: Pisit Sawangvonganan Date: Sun, 14 Jan 2024 00:02:12 +0700 Subject: [PATCH 2374/3723] bluetooth: hci: place tx/rx message buffer in .noinit section This change relocates the tx/rx message buffer from the .bss section to the .noinit section. This adjustment is aimed at reducing boot time by lowering the size of the .bss section, without impacting the operational functionality of the buffer. Signed-off-by: Pisit Sawangvonganan --- drivers/bluetooth/hci/hci_ambiq.c | 2 +- drivers/bluetooth/hci/hci_spi_st.c | 4 ++-- drivers/bluetooth/hci/hci_stm32wba.c | 2 +- drivers/bluetooth/hci/spi.c | 4 ++-- 4 files changed, 6 insertions(+), 6 deletions(-) diff --git a/drivers/bluetooth/hci/hci_ambiq.c b/drivers/bluetooth/hci/hci_ambiq.c index 387bc5611f1..3e990e209ba 100644 --- a/drivers/bluetooth/hci/hci_ambiq.c +++ b/drivers/bluetooth/hci/hci_ambiq.c @@ -52,7 +52,7 @@ LOG_MODULE_REGISTER(bt_hci_driver); #define SPI_MAX_TX_MSG_LEN 524 #define SPI_MAX_RX_MSG_LEN 258 -static uint8_t g_hciRxMsg[SPI_MAX_RX_MSG_LEN]; +static uint8_t __noinit g_hciRxMsg[SPI_MAX_RX_MSG_LEN]; static const struct device *spi_dev = DEVICE_DT_GET(SPI_DEV_NODE); static struct spi_config spi_cfg = { .operation = SPI_OP_MODE_MASTER | SPI_TRANSFER_MSB | SPI_MODE_CPOL | SPI_MODE_CPHA | diff --git a/drivers/bluetooth/hci/hci_spi_st.c b/drivers/bluetooth/hci/hci_spi_st.c index bd1e4d447ef..36263757684 100644 --- a/drivers/bluetooth/hci/hci_spi_st.c +++ b/drivers/bluetooth/hci/hci_spi_st.c @@ -71,8 +71,8 @@ LOG_MODULE_REGISTER(bt_driver); be transmitted across this HCI link #endif /* CONFIG_BT_L2CAP_TX_MTU > MAX_MTU */ -static uint8_t rxmsg[SPI_MAX_MSG_LEN]; -static uint8_t txmsg[SPI_MAX_MSG_LEN]; +static uint8_t __noinit rxmsg[SPI_MAX_MSG_LEN]; +static uint8_t __noinit txmsg[SPI_MAX_MSG_LEN]; static const struct gpio_dt_spec irq_gpio = GPIO_DT_SPEC_INST_GET(0, irq_gpios); static const struct gpio_dt_spec rst_gpio = GPIO_DT_SPEC_INST_GET(0, reset_gpios); diff --git a/drivers/bluetooth/hci/hci_stm32wba.c b/drivers/bluetooth/hci/hci_stm32wba.c index 0b9aad74a6e..fd718d5efb6 100644 --- a/drivers/bluetooth/hci/hci_stm32wba.c +++ b/drivers/bluetooth/hci/hci_stm32wba.c @@ -47,7 +47,7 @@ static K_SEM_DEFINE(hci_sem, 1, 1); #define DIVC(x, y) (((x)+(y)-1)/(y)) -static uint32_t buffer[DIVC(BLE_DYN_ALLOC_SIZE, 4)]; +static uint32_t __noinit buffer[DIVC(BLE_DYN_ALLOC_SIZE, 4)]; extern uint8_t ll_state_busy; diff --git a/drivers/bluetooth/hci/spi.c b/drivers/bluetooth/hci/spi.c index 5c2695435e4..8177e059261 100644 --- a/drivers/bluetooth/hci/spi.c +++ b/drivers/bluetooth/hci/spi.c @@ -71,8 +71,8 @@ LOG_MODULE_REGISTER(bt_driver); be transmitted across this HCI link #endif /* CONFIG_BT_L2CAP_TX_MTU > MAX_MTU */ -static uint8_t rxmsg[SPI_MAX_MSG_LEN]; -static uint8_t txmsg[SPI_MAX_MSG_LEN]; +static uint8_t __noinit rxmsg[SPI_MAX_MSG_LEN]; +static uint8_t __noinit txmsg[SPI_MAX_MSG_LEN]; static const struct gpio_dt_spec irq_gpio = GPIO_DT_SPEC_INST_GET(0, irq_gpios); static const struct gpio_dt_spec rst_gpio = GPIO_DT_SPEC_INST_GET(0, reset_gpios); From b8105c1408b28ce44af948572dc445e7ee01a6cc Mon Sep 17 00:00:00 2001 From: Pisit Sawangvonganan Date: Tue, 16 Jan 2024 23:04:09 +0700 Subject: [PATCH 2375/3723] drivers: bluetooth: ambiq: fix the naming of rx message buffer This change renames the RX message buffer from g_hciRxMsg to rxmsg, as it does not follow the Zephyr coding style. Signed-off-by: Pisit Sawangvonganan --- drivers/bluetooth/hci/hci_ambiq.c | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/drivers/bluetooth/hci/hci_ambiq.c b/drivers/bluetooth/hci/hci_ambiq.c index 3e990e209ba..b0c6ee43337 100644 --- a/drivers/bluetooth/hci/hci_ambiq.c +++ b/drivers/bluetooth/hci/hci_ambiq.c @@ -52,7 +52,7 @@ LOG_MODULE_REGISTER(bt_hci_driver); #define SPI_MAX_TX_MSG_LEN 524 #define SPI_MAX_RX_MSG_LEN 258 -static uint8_t __noinit g_hciRxMsg[SPI_MAX_RX_MSG_LEN]; +static uint8_t __noinit rxmsg[SPI_MAX_RX_MSG_LEN]; static const struct device *spi_dev = DEVICE_DT_GET(SPI_DEV_NODE); static struct spi_config spi_cfg = { .operation = SPI_OP_MODE_MASTER | SPI_TRANSFER_MSB | SPI_MODE_CPOL | SPI_MODE_CPHA | @@ -259,7 +259,7 @@ static void bt_spi_rx_thread(void *p1, void *p2, void *p3) do { /* Recevive the HCI packet via SPI */ - ret = spi_receive_packet(&g_hciRxMsg[0], &len); + ret = spi_receive_packet(&rxmsg[0], &len); if (ret) { break; } @@ -267,22 +267,22 @@ static void bt_spi_rx_thread(void *p1, void *p2, void *p3) /* Check if needs to handle the vendor specific events which are * incompatible with the standard Bluetooth HCI format. */ - if (bt_apollo_vnd_rcv_ongoing(&g_hciRxMsg[0], len)) { + if (bt_apollo_vnd_rcv_ongoing(&rxmsg[0], len)) { break; } - switch (g_hciRxMsg[PACKET_TYPE]) { + switch (rxmsg[PACKET_TYPE]) { case HCI_EVT: - buf = bt_hci_evt_recv(&g_hciRxMsg[PACKET_TYPE + PACKET_TYPE_SIZE], + buf = bt_hci_evt_recv(&rxmsg[PACKET_TYPE + PACKET_TYPE_SIZE], (len - PACKET_TYPE_SIZE)); break; case HCI_ACL: - buf = bt_hci_acl_recv(&g_hciRxMsg[PACKET_TYPE + PACKET_TYPE_SIZE], + buf = bt_hci_acl_recv(&rxmsg[PACKET_TYPE + PACKET_TYPE_SIZE], (len - PACKET_TYPE_SIZE)); break; default: buf = NULL; - LOG_WRN("Unknown BT buf type %d", g_hciRxMsg[PACKET_TYPE]); + LOG_WRN("Unknown BT buf type %d", rxmsg[PACKET_TYPE]); break; } From 917bec37d0849932c122d355ded690697a5bf812 Mon Sep 17 00:00:00 2001 From: Markus Swarowsky Date: Thu, 7 Dec 2023 18:26:01 +0100 Subject: [PATCH 2376/3723] manifest: TF-M v2.0.0 update Update TF-M to version 2.0.0 including MbedTLS to v3.5.0 TF-M-Tests to v2.0.0 PSA-Arch_Tests to v23.06_API1.5_ADAC_EAC Signed-off-by: Markus Swarowsky --- submanifests/optional.yaml | 4 ++-- west.yml | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/submanifests/optional.yaml b/submanifests/optional.yaml index b50e9479933..9cdec6d60c4 100644 --- a/submanifests/optional.yaml +++ b/submanifests/optional.yaml @@ -28,7 +28,7 @@ manifest: groups: - optional - name: psa-arch-tests - revision: 6a17330e0dfb5f319730f974d5b05f7b7f04757b + revision: 2cadb02a72eacda7042505dcbdd492371e8ce024 path: modules/tee/tf-m/psa-arch-tests remote: upstream groups: @@ -40,7 +40,7 @@ manifest: groups: - optional - name: tf-m-tests - revision: a878426da78fbd1486dfc29d6c6b82be4ee79e72 + revision: 08a3158f0623a4205608a52d880b17ae394e31d2 path: modules/tee/tf-m/tf-m-tests remote: upstream groups: diff --git a/west.yml b/west.yml index 4cb40c8a773..6187f0380d3 100644 --- a/west.yml +++ b/west.yml @@ -277,7 +277,7 @@ manifest: revision: 7c61a4cec26402d20c845c95dcad0e39dcd319f8 path: modules/lib/gui/lvgl - name: mbedtls - revision: 7053083b0cff8462464e3cbb826e87852fc03da6 + revision: 66ed2279d6222056af172c188eaf4dcfed481032 path: modules/crypto/mbedtls groups: - crypto @@ -322,7 +322,7 @@ manifest: groups: - crypto - name: trusted-firmware-m - revision: 33c0f47bcb19721a5c33e6fe1eee9225d00bb5bc + revision: 58d0b5367f0fada9dbaddad1e08e302aeb044863 path: modules/tee/tf-m/trusted-firmware-m groups: - tee From e53485c012e6b7cae1762bb41ea9d4cda0c05cd3 Mon Sep 17 00:00:00 2001 From: Markus Swarowsky Date: Fri, 8 Dec 2023 10:45:07 +0100 Subject: [PATCH 2377/3723] modules: mbedtls: Sort base src Sort the list of source files for the mbedTLSBase library Signed-off-by: Markus Swarowsky --- modules/mbedtls/CMakeLists.txt | 32 ++++++++++++++++---------------- 1 file changed, 16 insertions(+), 16 deletions(-) diff --git a/modules/mbedtls/CMakeLists.txt b/modules/mbedtls/CMakeLists.txt index f061605c027..ae6c7e13ad6 100644 --- a/modules/mbedtls/CMakeLists.txt +++ b/modules/mbedtls/CMakeLists.txt @@ -28,30 +28,24 @@ zephyr_interface_library_named(mbedTLS) # Base mbed TLS files list(APPEND mbedtls_base_src + ${ZEPHYR_CURRENT_MODULE_DIR}/library/aes.c + ${ZEPHYR_CURRENT_MODULE_DIR}/library/aesni.c + ${ZEPHYR_CURRENT_MODULE_DIR}/library/aria.c ${ZEPHYR_CURRENT_MODULE_DIR}/library/asn1parse.c ${ZEPHYR_CURRENT_MODULE_DIR}/library/asn1write.c ${ZEPHYR_CURRENT_MODULE_DIR}/library/base64.c - ${ZEPHYR_CURRENT_MODULE_DIR}/library/bignum.c ${ZEPHYR_CURRENT_MODULE_DIR}/library/bignum_core.c - ${ZEPHYR_CURRENT_MODULE_DIR}/library/bignum_mod.c ${ZEPHYR_CURRENT_MODULE_DIR}/library/bignum_mod_raw.c - ${ZEPHYR_CURRENT_MODULE_DIR}/library/nist_kw.c - ${ZEPHYR_CURRENT_MODULE_DIR}/library/oid.c - ${ZEPHYR_CURRENT_MODULE_DIR}/library/padlock.c - ${ZEPHYR_CURRENT_MODULE_DIR}/library/platform.c - ${ZEPHYR_CURRENT_MODULE_DIR}/library/platform_util.c - ${ZEPHYR_CURRENT_MODULE_DIR}/library/version.c - ${ZEPHYR_CURRENT_MODULE_DIR}/library/constant_time.c - ${ZEPHYR_CURRENT_MODULE_DIR}/library/aes.c - ${ZEPHYR_CURRENT_MODULE_DIR}/library/aesni.c - ${ZEPHYR_CURRENT_MODULE_DIR}/library/aria.c + ${ZEPHYR_CURRENT_MODULE_DIR}/library/bignum_mod.c + ${ZEPHYR_CURRENT_MODULE_DIR}/library/bignum.c ${ZEPHYR_CURRENT_MODULE_DIR}/library/camellia.c ${ZEPHYR_CURRENT_MODULE_DIR}/library/ccm.c ${ZEPHYR_CURRENT_MODULE_DIR}/library/chacha20.c ${ZEPHYR_CURRENT_MODULE_DIR}/library/chachapoly.c - ${ZEPHYR_CURRENT_MODULE_DIR}/library/cipher.c ${ZEPHYR_CURRENT_MODULE_DIR}/library/cipher_wrap.c + ${ZEPHYR_CURRENT_MODULE_DIR}/library/cipher.c ${ZEPHYR_CURRENT_MODULE_DIR}/library/cmac.c + ${ZEPHYR_CURRENT_MODULE_DIR}/library/constant_time.c ${ZEPHYR_CURRENT_MODULE_DIR}/library/ctr_drbg.c ${ZEPHYR_CURRENT_MODULE_DIR}/library/debug.c ${ZEPHYR_CURRENT_MODULE_DIR}/library/des.c @@ -59,10 +53,10 @@ zephyr_interface_library_named(mbedTLS) ${ZEPHYR_CURRENT_MODULE_DIR}/library/ecdh.c ${ZEPHYR_CURRENT_MODULE_DIR}/library/ecdsa.c ${ZEPHYR_CURRENT_MODULE_DIR}/library/ecjpake.c - ${ZEPHYR_CURRENT_MODULE_DIR}/library/ecp.c ${ZEPHYR_CURRENT_MODULE_DIR}/library/ecp_curves.c - ${ZEPHYR_CURRENT_MODULE_DIR}/library/entropy.c + ${ZEPHYR_CURRENT_MODULE_DIR}/library/ecp.c ${ZEPHYR_CURRENT_MODULE_DIR}/library/entropy_poll.c + ${ZEPHYR_CURRENT_MODULE_DIR}/library/entropy.c ${ZEPHYR_CURRENT_MODULE_DIR}/library/error.c ${ZEPHYR_CURRENT_MODULE_DIR}/library/gcm.c ${ZEPHYR_CURRENT_MODULE_DIR}/library/hash_info.c @@ -70,11 +64,16 @@ zephyr_interface_library_named(mbedTLS) ${ZEPHYR_CURRENT_MODULE_DIR}/library/hmac_drbg.c ${ZEPHYR_CURRENT_MODULE_DIR}/library/lmots.c ${ZEPHYR_CURRENT_MODULE_DIR}/library/lms.c - ${ZEPHYR_CURRENT_MODULE_DIR}/library/md5.c ${ZEPHYR_CURRENT_MODULE_DIR}/library/md.c + ${ZEPHYR_CURRENT_MODULE_DIR}/library/md5.c ${ZEPHYR_CURRENT_MODULE_DIR}/library/memory_buffer_alloc.c ${ZEPHYR_CURRENT_MODULE_DIR}/library/mps_reader.c ${ZEPHYR_CURRENT_MODULE_DIR}/library/mps_trace.c + ${ZEPHYR_CURRENT_MODULE_DIR}/library/nist_kw.c + ${ZEPHYR_CURRENT_MODULE_DIR}/library/oid.c + ${ZEPHYR_CURRENT_MODULE_DIR}/library/padlock.c + ${ZEPHYR_CURRENT_MODULE_DIR}/library/platform_util.c + ${ZEPHYR_CURRENT_MODULE_DIR}/library/platform.c ${ZEPHYR_CURRENT_MODULE_DIR}/library/poly1305.c ${ZEPHYR_CURRENT_MODULE_DIR}/library/psa_util.c ${ZEPHYR_CURRENT_MODULE_DIR}/library/ripemd160.c @@ -86,6 +85,7 @@ zephyr_interface_library_named(mbedTLS) ${ZEPHYR_CURRENT_MODULE_DIR}/library/threading.c ${ZEPHYR_CURRENT_MODULE_DIR}/library/timing.c ${ZEPHYR_CURRENT_MODULE_DIR}/library/version_features.c + ${ZEPHYR_CURRENT_MODULE_DIR}/library/version.c zephyr_init.c ) From 85ecdd70e4b35d63f942fc87165aa4da732ab5ea Mon Sep 17 00:00:00 2001 From: Markus Swarowsky Date: Fri, 8 Dec 2023 10:48:28 +0100 Subject: [PATCH 2378/3723] modules: mbedtls: Adapt source list to 3.5.0 remove hash_info.c and add ecp_curves_new.c Signed-off-by: Markus Swarowsky --- modules/mbedtls/CMakeLists.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/mbedtls/CMakeLists.txt b/modules/mbedtls/CMakeLists.txt index ae6c7e13ad6..74cd4853b8d 100644 --- a/modules/mbedtls/CMakeLists.txt +++ b/modules/mbedtls/CMakeLists.txt @@ -53,13 +53,13 @@ zephyr_interface_library_named(mbedTLS) ${ZEPHYR_CURRENT_MODULE_DIR}/library/ecdh.c ${ZEPHYR_CURRENT_MODULE_DIR}/library/ecdsa.c ${ZEPHYR_CURRENT_MODULE_DIR}/library/ecjpake.c + ${ZEPHYR_CURRENT_MODULE_DIR}/library/ecp_curves_new.c ${ZEPHYR_CURRENT_MODULE_DIR}/library/ecp_curves.c ${ZEPHYR_CURRENT_MODULE_DIR}/library/ecp.c ${ZEPHYR_CURRENT_MODULE_DIR}/library/entropy_poll.c ${ZEPHYR_CURRENT_MODULE_DIR}/library/entropy.c ${ZEPHYR_CURRENT_MODULE_DIR}/library/error.c ${ZEPHYR_CURRENT_MODULE_DIR}/library/gcm.c - ${ZEPHYR_CURRENT_MODULE_DIR}/library/hash_info.c ${ZEPHYR_CURRENT_MODULE_DIR}/library/hkdf.c ${ZEPHYR_CURRENT_MODULE_DIR}/library/hmac_drbg.c ${ZEPHYR_CURRENT_MODULE_DIR}/library/lmots.c From 21098acdec4bbec304a89caf5a969857059139e6 Mon Sep 17 00:00:00 2001 From: Markus Swarowsky Date: Fri, 8 Dec 2023 13:34:48 +0100 Subject: [PATCH 2379/3723] modules: tf-m: nrf5340_cpuapp: Change to cpuarch.cmake The preload.cmake was renamed to cpuarch.cmake in TF-M so change Signed-off-by: Markus Swarowsky --- .../nordic_nrf/nrf5340_cpuapp/{preload.cmake => cpuarch.cmake} | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) rename modules/trusted-firmware-m/nordic_nrf/nrf5340_cpuapp/{preload.cmake => cpuarch.cmake} (60%) diff --git a/modules/trusted-firmware-m/nordic_nrf/nrf5340_cpuapp/preload.cmake b/modules/trusted-firmware-m/nordic_nrf/nrf5340_cpuapp/cpuarch.cmake similarity index 60% rename from modules/trusted-firmware-m/nordic_nrf/nrf5340_cpuapp/preload.cmake rename to modules/trusted-firmware-m/nordic_nrf/nrf5340_cpuapp/cpuarch.cmake index d9bd226eb65..903b23e4cc6 100644 --- a/modules/trusted-firmware-m/nordic_nrf/nrf5340_cpuapp/preload.cmake +++ b/modules/trusted-firmware-m/nordic_nrf/nrf5340_cpuapp/cpuarch.cmake @@ -4,4 +4,4 @@ # SPDX-License-Identifier: Apache-2.0 # -include(platform/ext/target/nordic_nrf/common/nrf5340/preload.cmake) +include(platform/ext/target/nordic_nrf/common/nrf5340/cpuarch.cmake) From 132bfc45b7bfc5baefb02cc3d3c0dc51b7622838 Mon Sep 17 00:00:00 2001 From: Markus Swarowsky Date: Fri, 8 Dec 2023 13:35:11 +0100 Subject: [PATCH 2380/3723] modules: tf-m: nrf9120: Change to cpuarch.cmake The preload.cmake was renamed to cpuarch.cmake in TF-M so change Signed-off-by: Markus Swarowsky --- .../nordic_nrf/nrf9120/{preload.cmake => cpuarch.cmake} | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) rename modules/trusted-firmware-m/nordic_nrf/nrf9120/{preload.cmake => cpuarch.cmake} (60%) diff --git a/modules/trusted-firmware-m/nordic_nrf/nrf9120/preload.cmake b/modules/trusted-firmware-m/nordic_nrf/nrf9120/cpuarch.cmake similarity index 60% rename from modules/trusted-firmware-m/nordic_nrf/nrf9120/preload.cmake rename to modules/trusted-firmware-m/nordic_nrf/nrf9120/cpuarch.cmake index 4b3c6ee79ab..b34a8ddab1a 100644 --- a/modules/trusted-firmware-m/nordic_nrf/nrf9120/preload.cmake +++ b/modules/trusted-firmware-m/nordic_nrf/nrf9120/cpuarch.cmake @@ -4,4 +4,4 @@ # SPDX-License-Identifier: Apache-2.0 # -include(platform/ext/target/nordic_nrf/common/nrf9120/preload.cmake) +include(platform/ext/target/nordic_nrf/common/nrf9120/cpuarch.cmake) From 78fd53fae796aee3fd6087b0ac6ef86c8284ee6f Mon Sep 17 00:00:00 2001 From: Markus Swarowsky Date: Fri, 8 Dec 2023 13:35:33 +0100 Subject: [PATCH 2381/3723] modules: tf-m: nrf9160: Change to cpuarch.cmake The preload.cmake was renamed to cpuarch.cmake in TF-M so change Signed-off-by: Markus Swarowsky --- .../nordic_nrf/nrf9160/{preload.cmake => cpuarch.cmake} | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) rename modules/trusted-firmware-m/nordic_nrf/nrf9160/{preload.cmake => cpuarch.cmake} (60%) diff --git a/modules/trusted-firmware-m/nordic_nrf/nrf9160/preload.cmake b/modules/trusted-firmware-m/nordic_nrf/nrf9160/cpuarch.cmake similarity index 60% rename from modules/trusted-firmware-m/nordic_nrf/nrf9160/preload.cmake rename to modules/trusted-firmware-m/nordic_nrf/nrf9160/cpuarch.cmake index 364480a6f7f..228252f0147 100644 --- a/modules/trusted-firmware-m/nordic_nrf/nrf9160/preload.cmake +++ b/modules/trusted-firmware-m/nordic_nrf/nrf9160/cpuarch.cmake @@ -4,4 +4,4 @@ # SPDX-License-Identifier: Apache-2.0 # -include(platform/ext/target/nordic_nrf/common/nrf9160/preload.cmake) +include(platform/ext/target/nordic_nrf/common/nrf9160/cpuarch.cmake) From 11175c3ad3111f2bfb92084289f17f24207ed544 Mon Sep 17 00:00:00 2001 From: Markus Swarowsky Date: Fri, 8 Dec 2023 14:03:30 +0100 Subject: [PATCH 2382/3723] tf-m: Change NS include path for TF-M 2.0.0 The place where TF-M places its non-secure api header files has changed Therefore changing it for for all applications that use it. Signed-off-by: Markus Swarowsky --- boards/arm/bl5340_dvk/CMakeLists.txt | 2 +- boards/arm/nrf5340_audio_dk_nrf5340/CMakeLists.txt | 2 +- boards/arm/nrf5340dk_nrf5340/CMakeLists.txt | 2 +- drivers/entropy/CMakeLists.txt | 2 +- modules/uoscore-uedhoc/CMakeLists.txt | 2 +- samples/bluetooth/mesh/CMakeLists.txt | 2 +- samples/bluetooth/mesh_demo/CMakeLists.txt | 2 +- samples/bluetooth/mesh_provisioner/CMakeLists.txt | 2 +- samples/drivers/counter/alarm/CMakeLists.txt | 2 +- samples/subsys/usb/mass/CMakeLists.txt | 2 +- samples/tfm_integration/psa_crypto/CMakeLists.txt | 2 +- samples/tfm_integration/psa_protected_storage/CMakeLists.txt | 2 +- samples/tfm_integration/tfm_ipc/CMakeLists.txt | 2 +- samples/tfm_integration/tfm_psa_test/CMakeLists.txt | 2 +- samples/tfm_integration/tfm_secure_partition/CMakeLists.txt | 2 +- soc/arm/nordic_nrf/common/CMakeLists.txt | 2 +- subsys/bluetooth/mesh/CMakeLists.txt | 2 +- subsys/net/lib/tls_credentials/CMakeLists.txt | 2 +- tests/arch/arm/arm_thread_swap_tz/CMakeLists.txt | 2 +- 19 files changed, 19 insertions(+), 19 deletions(-) diff --git a/boards/arm/bl5340_dvk/CMakeLists.txt b/boards/arm/bl5340_dvk/CMakeLists.txt index 541334195dd..863c8bb599e 100644 --- a/boards/arm/bl5340_dvk/CMakeLists.txt +++ b/boards/arm/bl5340_dvk/CMakeLists.txt @@ -9,7 +9,7 @@ zephyr_library_sources(bl5340_dvk_cpunet_reset.c) if (CONFIG_BUILD_WITH_TFM) zephyr_library_include_directories( - $/install/interface/include + $/api_ns/interface/include ) endif() diff --git a/boards/arm/nrf5340_audio_dk_nrf5340/CMakeLists.txt b/boards/arm/nrf5340_audio_dk_nrf5340/CMakeLists.txt index c950fd91724..fa1c1ba14d9 100644 --- a/boards/arm/nrf5340_audio_dk_nrf5340/CMakeLists.txt +++ b/boards/arm/nrf5340_audio_dk_nrf5340/CMakeLists.txt @@ -8,7 +8,7 @@ if ((CONFIG_BOARD_NRF5340_AUDIO_DK_NRF5340_CPUAPP OR CONFIG_BOARD_NRF5340_AUDIO_ if (CONFIG_BUILD_WITH_TFM) zephyr_library_include_directories( - $/install/interface/include + $/api_ns/interface/include ) endif() diff --git a/boards/arm/nrf5340dk_nrf5340/CMakeLists.txt b/boards/arm/nrf5340dk_nrf5340/CMakeLists.txt index 8ba3238c40b..5128462d70c 100644 --- a/boards/arm/nrf5340dk_nrf5340/CMakeLists.txt +++ b/boards/arm/nrf5340dk_nrf5340/CMakeLists.txt @@ -8,7 +8,7 @@ zephyr_library_sources(nrf5340_cpunet_reset.c) if (CONFIG_BUILD_WITH_TFM) zephyr_library_include_directories( - $/install/interface/include + $/api_ns/interface/include ) endif() diff --git a/drivers/entropy/CMakeLists.txt b/drivers/entropy/CMakeLists.txt index 99184f3b1e5..7ca87d60944 100644 --- a/drivers/entropy/CMakeLists.txt +++ b/drivers/entropy/CMakeLists.txt @@ -28,6 +28,6 @@ zephyr_library_sources_ifdef(CONFIG_ENTROPY_PSA_CRYPTO_RNG entropy_psa_crypt if (CONFIG_BUILD_WITH_TFM) target_include_directories(${ZEPHYR_CURRENT_LIBRARY} PRIVATE - $/install/interface/include + $/api_ns/interface/include ) endif() diff --git a/modules/uoscore-uedhoc/CMakeLists.txt b/modules/uoscore-uedhoc/CMakeLists.txt index e23ad7da2e6..aaf842e392c 100644 --- a/modules/uoscore-uedhoc/CMakeLists.txt +++ b/modules/uoscore-uedhoc/CMakeLists.txt @@ -29,7 +29,7 @@ if (CONFIG_UOSCORE OR CONFIG_UEDHOC) if (CONFIG_BUILD_WITH_TFM) zephyr_library_include_directories( - $/install/interface/include + $/api_ns/interface/include ) endif() diff --git a/samples/bluetooth/mesh/CMakeLists.txt b/samples/bluetooth/mesh/CMakeLists.txt index 6ee28b12d48..74734eb84b4 100644 --- a/samples/bluetooth/mesh/CMakeLists.txt +++ b/samples/bluetooth/mesh/CMakeLists.txt @@ -16,6 +16,6 @@ endif() if (CONFIG_BUILD_WITH_TFM) target_include_directories(app PRIVATE - $/install/interface/include + $/api_ns/interface/include ) endif() diff --git a/samples/bluetooth/mesh_demo/CMakeLists.txt b/samples/bluetooth/mesh_demo/CMakeLists.txt index 07736d6c12e..f5d347ab373 100644 --- a/samples/bluetooth/mesh_demo/CMakeLists.txt +++ b/samples/bluetooth/mesh_demo/CMakeLists.txt @@ -15,6 +15,6 @@ endif() if (CONFIG_BUILD_WITH_TFM) target_include_directories(app PRIVATE - $/install/interface/include + $/api_ns/interface/include ) endif() diff --git a/samples/bluetooth/mesh_provisioner/CMakeLists.txt b/samples/bluetooth/mesh_provisioner/CMakeLists.txt index 7b22bd0fe14..aefe3628ba8 100644 --- a/samples/bluetooth/mesh_provisioner/CMakeLists.txt +++ b/samples/bluetooth/mesh_provisioner/CMakeLists.txt @@ -10,6 +10,6 @@ target_sources(app PRIVATE src/main.c) if (CONFIG_BUILD_WITH_TFM) target_include_directories(app PRIVATE - $/install/interface/include + $/api_ns/interface/include ) endif() diff --git a/samples/drivers/counter/alarm/CMakeLists.txt b/samples/drivers/counter/alarm/CMakeLists.txt index eadc9e99e67..747c2b27ebd 100644 --- a/samples/drivers/counter/alarm/CMakeLists.txt +++ b/samples/drivers/counter/alarm/CMakeLists.txt @@ -9,6 +9,6 @@ target_sources(app PRIVATE ${app_sources}) if(CONFIG_BUILD_WITH_TFM) target_include_directories(app PRIVATE - $/install/interface/include + $/api_ns/interface/include ) endif() diff --git a/samples/subsys/usb/mass/CMakeLists.txt b/samples/subsys/usb/mass/CMakeLists.txt index c0475b031f3..3b4d6a7ee64 100644 --- a/samples/subsys/usb/mass/CMakeLists.txt +++ b/samples/subsys/usb/mass/CMakeLists.txt @@ -16,6 +16,6 @@ target_sources(app PRIVATE ${app_sources}) if(CONFIG_BUILD_WITH_TFM) target_include_directories(app PRIVATE - $/install/interface/include + $/api_ns/interface/include ) endif() diff --git a/samples/tfm_integration/psa_crypto/CMakeLists.txt b/samples/tfm_integration/psa_crypto/CMakeLists.txt index 17339b470b8..f8ef1eca23f 100644 --- a/samples/tfm_integration/psa_crypto/CMakeLists.txt +++ b/samples/tfm_integration/psa_crypto/CMakeLists.txt @@ -16,7 +16,7 @@ target_sources(app PRIVATE src/util_app_log.c) target_sources(app PRIVATE src/util_sformat.c) target_include_directories(app PRIVATE - $/install/interface/include + $/api_ns/interface/include ) # In TF-M, default value of CRYPTO_ENGINE_BUF_SIZE is 0x2080. It causes diff --git a/samples/tfm_integration/psa_protected_storage/CMakeLists.txt b/samples/tfm_integration/psa_protected_storage/CMakeLists.txt index bbb8a2041fd..dfb0169eda6 100644 --- a/samples/tfm_integration/psa_protected_storage/CMakeLists.txt +++ b/samples/tfm_integration/psa_protected_storage/CMakeLists.txt @@ -13,5 +13,5 @@ project(protected_storage) target_sources(app PRIVATE src/main.c) target_include_directories(app PRIVATE - $/install/interface/include + $/api_ns/interface/include ) diff --git a/samples/tfm_integration/tfm_ipc/CMakeLists.txt b/samples/tfm_integration/tfm_ipc/CMakeLists.txt index f11b67af843..896af7bfbda 100644 --- a/samples/tfm_integration/tfm_ipc/CMakeLists.txt +++ b/samples/tfm_integration/tfm_ipc/CMakeLists.txt @@ -9,5 +9,5 @@ project(tfm_ipc) target_sources(app PRIVATE src/main.c) target_include_directories(app PRIVATE - $/install/interface/include + $/api_ns/interface/include ) diff --git a/samples/tfm_integration/tfm_psa_test/CMakeLists.txt b/samples/tfm_integration/tfm_psa_test/CMakeLists.txt index 9dcbf12ae64..7692ea3dfd1 100644 --- a/samples/tfm_integration/tfm_psa_test/CMakeLists.txt +++ b/samples/tfm_integration/tfm_psa_test/CMakeLists.txt @@ -13,5 +13,5 @@ project(tfm_psa_storage_test) target_sources(app PRIVATE src/main.c) target_include_directories(app PRIVATE - $/install/interface/include + $/api_ns/interface/include ) diff --git a/samples/tfm_integration/tfm_secure_partition/CMakeLists.txt b/samples/tfm_integration/tfm_secure_partition/CMakeLists.txt index 69901f73928..beadae9230a 100644 --- a/samples/tfm_integration/tfm_secure_partition/CMakeLists.txt +++ b/samples/tfm_integration/tfm_secure_partition/CMakeLists.txt @@ -28,7 +28,7 @@ target_sources(app PRIVATE ) target_include_directories(app PRIVATE - $/install/interface/include + $/api_ns/interface/include ) target_compile_definitions(app diff --git a/soc/arm/nordic_nrf/common/CMakeLists.txt b/soc/arm/nordic_nrf/common/CMakeLists.txt index eb074dd0548..1c12813f2c3 100644 --- a/soc/arm/nordic_nrf/common/CMakeLists.txt +++ b/soc/arm/nordic_nrf/common/CMakeLists.txt @@ -8,6 +8,6 @@ zephyr_include_directories(.) if (CONFIG_TFM_PARTITION_PLATFORM) zephyr_sources(soc_secure.c) zephyr_library_include_directories( - $/install/interface/include + $/api_ns/interface/include ) endif() diff --git a/subsys/bluetooth/mesh/CMakeLists.txt b/subsys/bluetooth/mesh/CMakeLists.txt index fe4444b28ab..4c597c12a68 100644 --- a/subsys/bluetooth/mesh/CMakeLists.txt +++ b/subsys/bluetooth/mesh/CMakeLists.txt @@ -134,6 +134,6 @@ zephyr_library_link_libraries_ifdef(CONFIG_MBEDTLS mbedTLS) if (CONFIG_BUILD_WITH_TFM) target_include_directories(${ZEPHYR_CURRENT_LIBRARY} PRIVATE - $/install/interface/include + $/api_ns/interface/include ) endif() diff --git a/subsys/net/lib/tls_credentials/CMakeLists.txt b/subsys/net/lib/tls_credentials/CMakeLists.txt index 9a605e0832b..5a80bed58a6 100644 --- a/subsys/net/lib/tls_credentials/CMakeLists.txt +++ b/subsys/net/lib/tls_credentials/CMakeLists.txt @@ -18,6 +18,6 @@ zephyr_library_link_libraries_ifdef(CONFIG_MBEDTLS mbedTLS) if (CONFIG_TLS_CREDENTIALS_BACKEND_PROTECTED_STORAGE AND CONFIG_BUILD_WITH_TFM) target_include_directories(${ZEPHYR_CURRENT_LIBRARY} PRIVATE - $/install/interface/include + $/api_ns/interface/include ) endif() diff --git a/tests/arch/arm/arm_thread_swap_tz/CMakeLists.txt b/tests/arch/arm/arm_thread_swap_tz/CMakeLists.txt index 93e91deafcb..10ee1786e16 100644 --- a/tests/arch/arm/arm_thread_swap_tz/CMakeLists.txt +++ b/tests/arch/arm/arm_thread_swap_tz/CMakeLists.txt @@ -14,6 +14,6 @@ target_sources(app PRIVATE ${app_sources}) if (CONFIG_BUILD_WITH_TFM) target_include_directories(app PRIVATE - $/install/interface/include + $/api_ns/interface/include ) endif() From 8b257c058da9249ecce580beed8516b274bf44a0 Mon Sep 17 00:00:00 2001 From: Markus Swarowsky Date: Fri, 8 Dec 2023 14:12:07 +0100 Subject: [PATCH 2383/3723] modules: tf-m: Remove platform_ns target The platform_ns library is no longer build with the split build anymore so removing it. Signed-off-by: Markus Swarowsky --- modules/trusted-firmware-m/nordic_nrf/CMakeLists.txt | 8 -------- 1 file changed, 8 deletions(-) diff --git a/modules/trusted-firmware-m/nordic_nrf/CMakeLists.txt b/modules/trusted-firmware-m/nordic_nrf/CMakeLists.txt index 41dca2f15a9..d5bc57ac5d9 100644 --- a/modules/trusted-firmware-m/nordic_nrf/CMakeLists.txt +++ b/modules/trusted-firmware-m/nordic_nrf/CMakeLists.txt @@ -36,14 +36,6 @@ target_include_directories(platform_s ${board_includes} ) -target_include_directories(platform_ns - PUBLIC - include - include/util - ${partition_includes} - ${board_includes} -) - if(BL2) target_include_directories(platform_bl2 PUBLIC From a14f42a817a3b9a412bf1669ae4134054131b210 Mon Sep 17 00:00:00 2001 From: Joakim Andersson Date: Fri, 8 Dec 2023 15:16:35 +0100 Subject: [PATCH 2384/3723] modules: Update source, lib and include path for TF-M interface files Update source lib and include path for TF-M interface files. Signed-off-by: Joakim Andersson Signed-off-by: Markus Swarowsky --- boards/arm/b_u585i_iot02a/CMakeLists.txt | 2 +- boards/arm/b_u585i_iot02a/doc/index.rst | 4 +-- boards/arm/nucleo_l552ze_q/CMakeLists.txt | 2 +- .../nucleo_l552ze_q/doc/nucleol552ze_q.rst | 2 +- boards/arm/nucleo_u575zi_q/doc/index.rst | 2 +- boards/arm/nucleo_u5a5zj_q/CMakeLists.txt | 2 +- boards/arm/nucleo_u5a5zj_q/doc/index.rst | 2 +- boards/arm/stm32l562e_dk/CMakeLists.txt | 2 +- boards/arm/stm32l562e_dk/doc/index.rst | 2 +- modules/trusted-firmware-m/CMakeLists.txt | 25 ++++++++----------- 10 files changed, 21 insertions(+), 24 deletions(-) diff --git a/boards/arm/b_u585i_iot02a/CMakeLists.txt b/boards/arm/b_u585i_iot02a/CMakeLists.txt index dde73804665..f6ca91f1a73 100644 --- a/boards/arm/b_u585i_iot02a/CMakeLists.txt +++ b/boards/arm/b_u585i_iot02a/CMakeLists.txt @@ -10,6 +10,6 @@ endif() if(CONFIG_BUILD_WITH_TFM) set_property(GLOBAL APPEND PROPERTY extra_post_build_commands #Execute post build script postbuild.sh - COMMAND $/postbuild.sh ${COMPILER_FULL_PATH} + COMMAND $/api_ns/postbuild.sh ${COMPILER_FULL_PATH} ) endif() diff --git a/boards/arm/b_u585i_iot02a/doc/index.rst b/boards/arm/b_u585i_iot02a/doc/index.rst index 56906f5ff08..4850b1efee7 100644 --- a/boards/arm/b_u585i_iot02a/doc/index.rst +++ b/boards/arm/b_u585i_iot02a/doc/index.rst @@ -346,14 +346,14 @@ can be generated using ``b_u585i_iot02a_ns`` as build target. $ west build -b b_u585i_iot02a_ns path/to/source/directory -Note: When building the ``*_ns`` image with TF-M, ``build/tfm/postbuild.sh`` bash script +Note: When building the ``*_ns`` image with TF-M, ``build/tfm/api_ns/postbuild.sh`` bash script is run automatically in a post-build step to make some required flash layout changes. Once the build is completed, run the following script to initialize the option bytes. .. code-block:: bash - $ build/tfm/regression.sh + $ build/tfm/api_ns/regression.sh Finally, to flash the board, run: diff --git a/boards/arm/nucleo_l552ze_q/CMakeLists.txt b/boards/arm/nucleo_l552ze_q/CMakeLists.txt index d170d283e99..260ecca2707 100644 --- a/boards/arm/nucleo_l552ze_q/CMakeLists.txt +++ b/boards/arm/nucleo_l552ze_q/CMakeLists.txt @@ -10,6 +10,6 @@ endif() if (CONFIG_BUILD_WITH_TFM) set_property(GLOBAL APPEND PROPERTY extra_post_build_commands #Execute post build script postbuild.sh - COMMAND $/postbuild.sh ${COMPILER_FULL_PATH} + COMMAND $/api_ns/postbuild.sh ${COMPILER_FULL_PATH} ) endif() diff --git a/boards/arm/nucleo_l552ze_q/doc/nucleol552ze_q.rst b/boards/arm/nucleo_l552ze_q/doc/nucleol552ze_q.rst index 0d9b7b37ae0..65a2df527a9 100644 --- a/boards/arm/nucleo_l552ze_q/doc/nucleol552ze_q.rst +++ b/boards/arm/nucleo_l552ze_q/doc/nucleol552ze_q.rst @@ -338,7 +338,7 @@ can be generated using ``nucleo_l552ze_q_ns`` as build target. $ west build -b nucleo_l552ze_q_ns path/to/source/directory -Note: When building the ``*_ns`` image with TF-M, ``build/tfm/postbuild.sh`` bash script +Note: When building the ``*_ns`` image with TF-M, ``build/tfm/api_ns/postbuild.sh`` bash script is run automatically in a post-build step to make some required flash layout changes. Once the build is completed, run the following script to initialize the option bytes. diff --git a/boards/arm/nucleo_u575zi_q/doc/index.rst b/boards/arm/nucleo_u575zi_q/doc/index.rst index d9f4c93d753..bbb547130d8 100644 --- a/boards/arm/nucleo_u575zi_q/doc/index.rst +++ b/boards/arm/nucleo_u575zi_q/doc/index.rst @@ -308,7 +308,7 @@ can be generated using ``nucleo_u575zi_q_ns`` as build target. $ west build -b nucleo_u575zi_q_ns path/to/source/directory -Note: When building the ``*_ns`` image with TF-M, ``build/tfm/postbuild.sh`` bash script +Note: When building the ``*_ns`` image with TF-M, ``build/tfm/api_ns/postbuild.sh`` bash script is run automatically in a post-build step to make some required flash layout changes. Once the build is completed, run the following script to initialize the option bytes. diff --git a/boards/arm/nucleo_u5a5zj_q/CMakeLists.txt b/boards/arm/nucleo_u5a5zj_q/CMakeLists.txt index c79a4b7b4e7..7c2da293e20 100644 --- a/boards/arm/nucleo_u5a5zj_q/CMakeLists.txt +++ b/boards/arm/nucleo_u5a5zj_q/CMakeLists.txt @@ -9,6 +9,6 @@ endif() if(CONFIG_BUILD_WITH_TFM) set_property(GLOBAL APPEND PROPERTY extra_post_build_commands #Execute post build script postbuild.sh - COMMAND $/postbuild.sh ${COMPILER_FULL_PATH} + COMMAND $/api_ns/postbuild.sh ${COMPILER_FULL_PATH} ) endif() diff --git a/boards/arm/nucleo_u5a5zj_q/doc/index.rst b/boards/arm/nucleo_u5a5zj_q/doc/index.rst index d9732bf430b..f6e96c63517 100644 --- a/boards/arm/nucleo_u5a5zj_q/doc/index.rst +++ b/boards/arm/nucleo_u5a5zj_q/doc/index.rst @@ -342,7 +342,7 @@ can be generated using ``nucleo_u5a5zj_q_ns`` as build target. $ west build -b nucleo_u5a5zj_q_ns path/to/source/directory -Note: When building the ``*_ns`` image with TF-M, ``build/tfm/postbuild.sh`` bash script +Note: When building the ``*_ns`` image with TF-M, ``build/tfm/api_ns/postbuild.sh`` bash script is run automatically in a post-build step to make some required flash layout changes. Once the build is completed, run the following script to initialize the option bytes. diff --git a/boards/arm/stm32l562e_dk/CMakeLists.txt b/boards/arm/stm32l562e_dk/CMakeLists.txt index dde73804665..f6ca91f1a73 100644 --- a/boards/arm/stm32l562e_dk/CMakeLists.txt +++ b/boards/arm/stm32l562e_dk/CMakeLists.txt @@ -10,6 +10,6 @@ endif() if(CONFIG_BUILD_WITH_TFM) set_property(GLOBAL APPEND PROPERTY extra_post_build_commands #Execute post build script postbuild.sh - COMMAND $/postbuild.sh ${COMPILER_FULL_PATH} + COMMAND $/api_ns/postbuild.sh ${COMPILER_FULL_PATH} ) endif() diff --git a/boards/arm/stm32l562e_dk/doc/index.rst b/boards/arm/stm32l562e_dk/doc/index.rst index f3dd058b341..16af6cb242b 100644 --- a/boards/arm/stm32l562e_dk/doc/index.rst +++ b/boards/arm/stm32l562e_dk/doc/index.rst @@ -340,7 +340,7 @@ can be generated using ``stm32l562e_dk_ns`` as build target. $ west build -b stm32l562e_dk_ns path/to/source/directory -Note: When building the ``*_ns`` image with TF-M, ``build/tfm/postbuild.sh`` bash script +Note: When building the ``*_ns`` image with TF-M, ``build/tfm/api_ns/postbuild.sh`` bash script is run automatically in a post-build step to make some required flash layout changes. Once the build is completed, run the following script to initialize the option bytes. diff --git a/modules/trusted-firmware-m/CMakeLists.txt b/modules/trusted-firmware-m/CMakeLists.txt index 958c985414e..6b3c0351097 100644 --- a/modules/trusted-firmware-m/CMakeLists.txt +++ b/modules/trusted-firmware-m/CMakeLists.txt @@ -181,11 +181,12 @@ if (CONFIG_BUILD_WITH_TFM) set(TFM_TEST_REPO_PATH ${ZEPHYR_CURRENT_MODULE_DIR}/../tf-m-tests) set(PSA_ARCH_TESTS_PATH ${ZEPHYR_CURRENT_MODULE_DIR}/../psa-arch-tests) - set(VENEERS_FILE ${TFM_BINARY_DIR}/secure_fw/s_veneers.o) + set(TFM_INTERFACE_SOURCE_DIR ${TFM_BINARY_DIR}/api_ns/interface/src) + set(TFM_INTERFACE_INCLUDE_DIR ${TFM_BINARY_DIR}/api_ns/interface/include) + set(TFM_INTERFACE_LIB_DIR ${TFM_BINARY_DIR}/api_ns/interface/lib) + set(TFM_API_NS_PATH ${TFM_BINARY_DIR}/tf-m-tests/app/libtfm_api_ns.a) set(PLATFORM_NS_FILE ${TFM_BINARY_DIR}/platform/ns/libplatform_ns.a) - set(TFM_GENERATED_INCLUDES ${TFM_BINARY_DIR}/generated/interface/include) - set(TFM_INTERFACE_SOURCE_DIR ${TFM_BINARY_DIR}/install/interface/src) if (TFM_PSA_TEST_SUITE) set(PSA_TEST_VAL_FILE ${TFM_BINARY_DIR}/tf-m-tests/app/psa_api_tests/val/val_nspe.a) @@ -213,9 +214,7 @@ if (CONFIG_BUILD_WITH_TFM) set(TFM_S_NS_SIGNED_BIN_FILE ${TFM_BINARY_DIR}/bin/tfm_s_ns_signed.bin) set(BUILD_BYPRODUCTS - ${VENEERS_FILE} ${TFM_API_NS_PATH} - ${TFM_GENERATED_INCLUDES}/psa_manifest/sid.h ${PSA_TEST_VAL_FILE} ${PSA_TEST_PAL_FILE} ${PSA_TEST_COMBINE_FILE} @@ -232,13 +231,15 @@ if (CONFIG_BUILD_WITH_TFM) ${TFM_NS_SIGNED_BIN_FILE} ${TFM_S_NS_SIGNED_BIN_FILE} + ${TFM_INTERFACE_LIB_DIR}/s_veneers.o + ${TFM_INTERFACE_SOURCE_DIR}/tfm_attest_api.c ${TFM_INTERFACE_SOURCE_DIR}/tfm_crypto_api.c ${TFM_INTERFACE_SOURCE_DIR}/tfm_fwu_api.c ${TFM_INTERFACE_SOURCE_DIR}/tfm_its_api.c ${TFM_INTERFACE_SOURCE_DIR}/tfm_platform_api.c ${TFM_INTERFACE_SOURCE_DIR}/tfm_ps_api.c - ${TFM_INTERFACE_SOURCE_DIR}/tfm_psa_ns_api.c + ${TFM_INTERFACE_SOURCE_DIR}/tfm_tz_psa_ns_api.c # Specific to nordic_nrf platform ${TFM_INTERFACE_SOURCE_DIR}/tfm_ioctl_core_ns_api.c @@ -434,7 +435,7 @@ if (CONFIG_BUILD_WITH_TFM) zephyr_library_sources_ifdef(CONFIG_TFM_PARTITION_INITIAL_ATTESTATION ${TFM_INTERFACE_SOURCE_DIR}/tfm_attest_api.c) zephyr_library_sources_ifdef(CONFIG_TFM_PARTITION_FIRMWARE_UPDATE ${TFM_INTERFACE_SOURCE_DIR}/tfm_fwu_api.c) - zephyr_library_sources(${TFM_INTERFACE_SOURCE_DIR}/tfm_psa_ns_api.c) + zephyr_library_sources(${TFM_INTERFACE_SOURCE_DIR}/tfm_tz_psa_ns_api.c) if(CONFIG_SOC_FAMILY_NRF) zephyr_library_sources_ifdef(CONFIG_TFM_PARTITION_PLATFORM ${TFM_INTERFACE_SOURCE_DIR}/tfm_ioctl_core_ns_api.c) @@ -447,17 +448,13 @@ if (CONFIG_BUILD_WITH_TFM) ) endif() - zephyr_include_directories( - ${TFM_GENERATED_INCLUDES} - ) - target_include_directories(tfm_api PRIVATE - ${TFM_BINARY_DIR}/install/interface/include - ${TFM_BINARY_DIR}/install/interface/include/crypto_keys + ${TFM_INTERFACE_INCLUDE_DIR} + ${TFM_INTERFACE_INCLUDE_DIR}/crypto_keys ) zephyr_library_link_libraries( - ${VENEERS_FILE} + ${TFM_INTERFACE_LIB_DIR}/s_veneers.o ) # To ensure that generated include files are created before they are used. From d931dded119f3fcbc7352ca0b580e3fdfd1fe296 Mon Sep 17 00:00:00 2001 From: Joakim Andersson Date: Fri, 8 Dec 2023 15:17:10 +0100 Subject: [PATCH 2385/3723] tfm: Use PSA error codes instead of TFM error codes The TFM error codes are no longer in the interface headers. All TF-M functions return PSA status codes, so use this here as well. Signed-off-by: Joakim Andersson Signed-off-by: Markus Swarowsky --- modules/trusted-firmware-m/interface/interface.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/modules/trusted-firmware-m/interface/interface.c b/modules/trusted-firmware-m/interface/interface.c index ad0ed1abdfe..d949a9dc027 100644 --- a/modules/trusted-firmware-m/interface/interface.c +++ b/modules/trusted-firmware-m/interface/interface.c @@ -35,7 +35,7 @@ int32_t tfm_ns_interface_dispatch(veneer_fn fn, if (!is_pre_kernel) { /* TF-M request protected by NS lock */ if (k_mutex_lock(&tfm_mutex, K_FOREVER) != 0) { - return (int32_t)TFM_ERROR_GENERIC; + return (int32_t)PSA_ERROR_GENERIC_ERROR; } #if !defined(CONFIG_ARM_NONSECURE_PREEMPTIBLE_SECURE_CALLS) @@ -79,7 +79,7 @@ uint32_t tfm_ns_interface_init(void) * The static K_MUTEX_DEFINE handles mutex initialization, * so this function may be implemented as no-op. */ - return TFM_SUCCESS; + return PSA_SUCCESS; } @@ -90,7 +90,7 @@ uint32_t tfm_ns_interface_init(void) static int ns_interface_init(void) { - __ASSERT(tfm_ns_interface_init() == TFM_SUCCESS, + __ASSERT(tfm_ns_interface_init() == PSA_SUCCESS, "TF-M NS interface init failed"); return 0; From f5eecd500d46a62a32f360bc42d082bd8cd7640c Mon Sep 17 00:00:00 2001 From: Joakim Andersson Date: Fri, 8 Dec 2023 15:18:21 +0100 Subject: [PATCH 2386/3723] tfm: nordic_nrf: Remove include of tfm_api.h, update install path Update install path of tfm_ioctl_api.h, remove include of tfm_api.h Signed-off-by: Joakim Andersson Signed-off-by: Markus Swarowsky --- modules/trusted-firmware-m/nordic_nrf/CMakeLists.txt | 2 +- modules/trusted-firmware-m/nordic_nrf/include/tfm_ioctl_api.h | 1 - samples/tfm_integration/tfm_ipc/src/main.c | 1 - .../tfm_secure_partition/dummy_partition/dummy_partition.c | 1 - .../tfm_integration/tfm_secure_partition/src/dummy_partition.h | 2 -- 5 files changed, 1 insertion(+), 6 deletions(-) diff --git a/modules/trusted-firmware-m/nordic_nrf/CMakeLists.txt b/modules/trusted-firmware-m/nordic_nrf/CMakeLists.txt index d5bc57ac5d9..39aa2199b47 100644 --- a/modules/trusted-firmware-m/nordic_nrf/CMakeLists.txt +++ b/modules/trusted-firmware-m/nordic_nrf/CMakeLists.txt @@ -48,7 +48,7 @@ endif() if (TFM_PARTITION_PLATFORM) install(FILES include/tfm_ioctl_api.h - DESTINATION ${TFM_INSTALL_PATH}/interface/include) + DESTINATION ${INSTALL_INTERFACE_INC_DIR}) endif() #========================= tfm_spm ============================================# diff --git a/modules/trusted-firmware-m/nordic_nrf/include/tfm_ioctl_api.h b/modules/trusted-firmware-m/nordic_nrf/include/tfm_ioctl_api.h index c6c36ee927f..3fade10525a 100644 --- a/modules/trusted-firmware-m/nordic_nrf/include/tfm_ioctl_api.h +++ b/modules/trusted-firmware-m/nordic_nrf/include/tfm_ioctl_api.h @@ -9,7 +9,6 @@ #include #include -#include #include /* Include core IOCTL services */ diff --git a/samples/tfm_integration/tfm_ipc/src/main.c b/samples/tfm_integration/tfm_ipc/src/main.c index 7179705cbe3..133c7203b0e 100644 --- a/samples/tfm_integration/tfm_ipc/src/main.c +++ b/samples/tfm_integration/tfm_ipc/src/main.c @@ -7,7 +7,6 @@ #include #include -#include "tfm_api.h" #include "tfm_ns_interface.h" #ifdef TFM_PSA_API #include "psa_manifest/sid.h" diff --git a/samples/tfm_integration/tfm_secure_partition/dummy_partition/dummy_partition.c b/samples/tfm_integration/tfm_secure_partition/dummy_partition/dummy_partition.c index 6519723058c..d618868ddbf 100644 --- a/samples/tfm_integration/tfm_secure_partition/dummy_partition/dummy_partition.c +++ b/samples/tfm_integration/tfm_secure_partition/dummy_partition/dummy_partition.c @@ -7,7 +7,6 @@ #include #include #include -#include "tfm_api.h" #include "psa/service.h" #include "psa_manifest/tfm_dummy_partition.h" diff --git a/samples/tfm_integration/tfm_secure_partition/src/dummy_partition.h b/samples/tfm_integration/tfm_secure_partition/src/dummy_partition.h index b31ce897d27..7ca52b3c5c4 100644 --- a/samples/tfm_integration/tfm_secure_partition/src/dummy_partition.h +++ b/samples/tfm_integration/tfm_secure_partition/src/dummy_partition.h @@ -4,8 +4,6 @@ * SPDX-License-Identifier: Apache-2.0 */ -#include "tfm_api.h" - psa_status_t dp_secret_digest(uint32_t secret_index, void *p_digest, size_t digest_size); From fbee1c61ed3f927c04a939f8a1ff9662c98f3c6c Mon Sep 17 00:00:00 2001 From: Markus Swarowsky Date: Mon, 11 Dec 2023 13:33:35 +0100 Subject: [PATCH 2387/3723] modules: mbedtls: Rename of psa_crypto_driver_wrappers psa_crypto_driver_wrappers.c got changed to psa_crypto_driver_wrappers_no_static.c Signed-off-by: Markus Swarowsky --- modules/mbedtls/CMakeLists.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/mbedtls/CMakeLists.txt b/modules/mbedtls/CMakeLists.txt index 74cd4853b8d..2bab7fe1038 100644 --- a/modules/mbedtls/CMakeLists.txt +++ b/modules/mbedtls/CMakeLists.txt @@ -111,7 +111,7 @@ zephyr_interface_library_named(mbedTLS) list(APPEND crypto_source ${ZEPHYR_CURRENT_MODULE_DIR}/library/psa_crypto_aead.c ${ZEPHYR_CURRENT_MODULE_DIR}/library/psa_crypto_cipher.c - ${ZEPHYR_CURRENT_MODULE_DIR}/library/psa_crypto_driver_wrappers.c + ${ZEPHYR_CURRENT_MODULE_DIR}/library/psa_crypto_driver_wrappers_no_static.c ${ZEPHYR_CURRENT_MODULE_DIR}/library/psa_crypto_ecp.c ${ZEPHYR_CURRENT_MODULE_DIR}/library/psa_crypto_hash.c ${ZEPHYR_CURRENT_MODULE_DIR}/library/psa_crypto_mac.c From dc7613865dc52b33d56a898ee27d8b0423ada6f0 Mon Sep 17 00:00:00 2001 From: Markus Swarowsky Date: Mon, 11 Dec 2023 17:27:32 +0100 Subject: [PATCH 2388/3723] modules: mbedtls: Add a mbedtls_ms_time implementation MbedTLS 3.5.0 requires a implementation of mbedtls_ms_time giving a time in ms for TLS 1.3 Therefor adding an alternative implementation using zephyrs k_uptime_get Signed-off-by: Markus Swarowsky --- modules/mbedtls/configs/config-mini-tls1_1.h | 1 + modules/mbedtls/configs/config-no-entropy.h | 1 + modules/mbedtls/configs/config-suite-b.h | 1 + modules/mbedtls/configs/config-tls-generic.h | 1 + modules/mbedtls/zephyr_init.c | 8 ++++++++ tests/subsys/jwt/src/tls_config/user-tls-conf.h | 1 + 6 files changed, 13 insertions(+) diff --git a/modules/mbedtls/configs/config-mini-tls1_1.h b/modules/mbedtls/configs/config-mini-tls1_1.h index 2bce8647caf..da8bf795c1d 100644 --- a/modules/mbedtls/configs/config-mini-tls1_1.h +++ b/modules/mbedtls/configs/config-mini-tls1_1.h @@ -59,6 +59,7 @@ /* System support */ #define MBEDTLS_HAVE_ASM #define MBEDTLS_HAVE_TIME +#define MBEDTLS_PLATFORM_MS_TIME_ALT /* mbed TLS feature support */ #define MBEDTLS_CIPHER_MODE_CBC diff --git a/modules/mbedtls/configs/config-no-entropy.h b/modules/mbedtls/configs/config-no-entropy.h index b5295bf1fb7..b3406a394b4 100644 --- a/modules/mbedtls/configs/config-no-entropy.h +++ b/modules/mbedtls/configs/config-no-entropy.h @@ -62,6 +62,7 @@ /* System support */ #define MBEDTLS_HAVE_ASM #define MBEDTLS_HAVE_TIME +#define MBEDTLS_PLATFORM_MS_TIME_ALT /* mbed TLS feature support */ #define MBEDTLS_CIPHER_MODE_CBC diff --git a/modules/mbedtls/configs/config-suite-b.h b/modules/mbedtls/configs/config-suite-b.h index 6f2cc963bd1..7468f763358 100644 --- a/modules/mbedtls/configs/config-suite-b.h +++ b/modules/mbedtls/configs/config-suite-b.h @@ -66,6 +66,7 @@ /* System support */ #define MBEDTLS_HAVE_ASM #define MBEDTLS_HAVE_TIME +#define MBEDTLS_PLATFORM_MS_TIME_ALT /* mbed TLS feature support */ #define MBEDTLS_ECP_DP_SECP256R1_ENABLED diff --git a/modules/mbedtls/configs/config-tls-generic.h b/modules/mbedtls/configs/config-tls-generic.h index 61278858ef2..59d98f65067 100644 --- a/modules/mbedtls/configs/config-tls-generic.h +++ b/modules/mbedtls/configs/config-tls-generic.h @@ -37,6 +37,7 @@ #if defined(CONFIG_MBEDTLS_HAVE_TIME_DATE) #define MBEDTLS_HAVE_TIME #define MBEDTLS_HAVE_TIME_DATE +#define MBEDTLS_PLATFORM_MS_TIME_ALT #endif #if defined(CONFIG_MBEDTLS_TEST) diff --git a/modules/mbedtls/zephyr_init.c b/modules/mbedtls/zephyr_init.c index d882b0aedb8..28a6a40fdc5 100644 --- a/modules/mbedtls/zephyr_init.c +++ b/modules/mbedtls/zephyr_init.c @@ -15,6 +15,8 @@ #include #include #include +#include + #include @@ -107,3 +109,9 @@ int mbedtls_init(void) { return _mbedtls_init(); } + +/* TLS 1.3 ticket lifetime needs a timing interface */ +mbedtls_ms_time_t mbedtls_ms_time(void) +{ + return (mbedtls_ms_time_t)k_uptime_get(); +} diff --git a/tests/subsys/jwt/src/tls_config/user-tls-conf.h b/tests/subsys/jwt/src/tls_config/user-tls-conf.h index 035f2b062ec..0d95ee80ac0 100644 --- a/tests/subsys/jwt/src/tls_config/user-tls-conf.h +++ b/tests/subsys/jwt/src/tls_config/user-tls-conf.h @@ -3,3 +3,4 @@ #define MBEDTLS_HAVE_TIME #define MBEDTLS_HAVE_TIME_DATE #define MBEDTLS_PLATFORM_TIME_ALT +#define MBEDTLS_PLATFORM_MS_TIME_ALT From 3398c987439eb06a8dcb8f27adc5d010dca2604c Mon Sep 17 00:00:00 2001 From: Joakim Andersson Date: Mon, 11 Dec 2023 21:52:07 +0100 Subject: [PATCH 2389/3723] modules: mbedtls: Use TF-M PSA API headers Use TF-M PSA API headers when compiling with TF-M enabled. Fixes: #43249 Signed-off-by: Joakim Andersson Signed-off-by: Markus Swarowsky --- modules/mbedtls/CMakeLists.txt | 13 +++++++------ 1 file changed, 7 insertions(+), 6 deletions(-) diff --git a/modules/mbedtls/CMakeLists.txt b/modules/mbedtls/CMakeLists.txt index 2bab7fe1038..929ea17ecea 100644 --- a/modules/mbedtls/CMakeLists.txt +++ b/modules/mbedtls/CMakeLists.txt @@ -16,6 +16,12 @@ zephyr_interface_library_named(mbedTLS) MBEDTLS_CONFIG_FILE="${CONFIG_MBEDTLS_CFG_FILE}" ) + if (CONFIG_BUILD_WITH_TFM) + target_include_directories(mbedTLS INTERFACE + $/api_ns/interface/include + ) + endif() + # Add regular includes target_include_directories(mbedTLS INTERFACE ${ZEPHYR_CURRENT_MODULE_DIR}/include @@ -107,7 +113,7 @@ zephyr_interface_library_named(mbedTLS) zephyr_library_named(mbedTLSCrypto) - if (CONFIG_MBEDTLS_PSA_CRYPTO_C) + if (CONFIG_MBEDTLS_PSA_CRYPTO_C AND NOT CONFIG_BUILD_WITH_TFM) list(APPEND crypto_source ${ZEPHYR_CURRENT_MODULE_DIR}/library/psa_crypto_aead.c ${ZEPHYR_CURRENT_MODULE_DIR}/library/psa_crypto_cipher.c @@ -119,11 +125,6 @@ zephyr_interface_library_named(mbedTLS) ${ZEPHYR_CURRENT_MODULE_DIR}/library/psa_crypto_se.c ${ZEPHYR_CURRENT_MODULE_DIR}/library/psa_crypto_storage.c ${ZEPHYR_CURRENT_MODULE_DIR}/library/psa_its_file.c - ) - endif() - - if (NOT CONFIG_BUILD_WITH_TFM) - list(APPEND crypto_source ${ZEPHYR_CURRENT_MODULE_DIR}/library/psa_crypto.c ${ZEPHYR_CURRENT_MODULE_DIR}/library/psa_crypto_client.c ${ZEPHYR_CURRENT_MODULE_DIR}/library/psa_crypto_slot_management.c From e8eeecddcf7d7b442106b92087696d837a2aa619 Mon Sep 17 00:00:00 2001 From: Markus Swarowsky Date: Wed, 13 Dec 2023 16:31:32 +0100 Subject: [PATCH 2390/3723] sample: tfm_secure_partition: Change tfm_partition_defs to tfm_config The target tfm_partition_defs got removed and tfm_config gets used now so updating it Signed-off-by: Markus Swarowsky --- .../tfm_secure_partition/dummy_partition/CMakeLists.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/samples/tfm_integration/tfm_secure_partition/dummy_partition/CMakeLists.txt b/samples/tfm_integration/tfm_secure_partition/dummy_partition/CMakeLists.txt index 0e335a73028..013332ccb1a 100644 --- a/samples/tfm_integration/tfm_secure_partition/dummy_partition/CMakeLists.txt +++ b/samples/tfm_integration/tfm_secure_partition/dummy_partition/CMakeLists.txt @@ -50,7 +50,7 @@ target_link_libraries(tfm_partitions tfm_app_rot_partition_dp ) -target_compile_definitions(tfm_partition_defs +target_compile_definitions(tfm_config INTERFACE TFM_PARTITION_DUMMY_PARTITION ) From 6c927490d0fc0ebc488e09c84b01ef7f924e1827 Mon Sep 17 00:00:00 2001 From: Joakim Andersson Date: Thu, 14 Dec 2023 12:47:13 +0100 Subject: [PATCH 2391/3723] tfm: Add NS build support for zephyr out-of-tree nordic_nrf platform. Add build of the NS application in the zephyr defined out-of-tree board support for the nordic_nrf platform. Signed-off-by: Joakim Andersson Signed-off-by: Markus Swarowsky --- .../nordic_nrf/CMakeLists.txt | 16 ++++--- .../nordic_nrf/nrf5340_cpuapp/CMakeLists.txt | 8 +++- .../nordic_nrf/nrf5340_cpuapp/config.cmake | 3 +- .../nordic_nrf/nrf5340_cpuapp/cpuarch.cmake | 4 +- .../nrf5340_cpuapp/ns/cpuarch_ns.cmake | 10 ++++ .../nordic_nrf/nrf9120/CMakeLists.txt | 11 ++++- .../nordic_nrf/nrf9120/config.cmake | 3 +- .../nordic_nrf/nrf9120/cpuarch.cmake | 3 +- .../nordic_nrf/nrf9120/ns/cpuarch_ns.cmake | 10 ++++ .../nordic_nrf/nrf9160/CMakeLists.txt | 11 ++++- .../nordic_nrf/nrf9160/config.cmake | 3 +- .../nordic_nrf/nrf9160/cpuarch.cmake | 4 +- .../nordic_nrf/nrf9160/ns/cpuarch_ns.cmake | 10 ++++ .../nordic_nrf/ns/CMakeLists.txt | 46 +++++++++++++++++++ 14 files changed, 127 insertions(+), 15 deletions(-) create mode 100644 modules/trusted-firmware-m/nordic_nrf/nrf5340_cpuapp/ns/cpuarch_ns.cmake create mode 100644 modules/trusted-firmware-m/nordic_nrf/nrf9120/ns/cpuarch_ns.cmake create mode 100644 modules/trusted-firmware-m/nordic_nrf/nrf9160/ns/cpuarch_ns.cmake create mode 100644 modules/trusted-firmware-m/nordic_nrf/ns/CMakeLists.txt diff --git a/modules/trusted-firmware-m/nordic_nrf/CMakeLists.txt b/modules/trusted-firmware-m/nordic_nrf/CMakeLists.txt index 39aa2199b47..d75b34a8109 100644 --- a/modules/trusted-firmware-m/nordic_nrf/CMakeLists.txt +++ b/modules/trusted-firmware-m/nordic_nrf/CMakeLists.txt @@ -46,14 +46,18 @@ if(BL2) ) endif() +target_sources(tfm_spm + PRIVATE + src/tfm_hal_platform.c +) + if (TFM_PARTITION_PLATFORM) install(FILES include/tfm_ioctl_api.h + include/device_cfg.h + include/RTE_Device.h + include/tfm_ioctl_api.h DESTINATION ${INSTALL_INTERFACE_INC_DIR}) endif() -#========================= tfm_spm ============================================# - -target_sources(tfm_spm - PRIVATE - src/tfm_hal_platform.c -) +install(FILES ns/CMakeLists.txt + DESTINATION ${INSTALL_PLATFORM_NS_DIR}) diff --git a/modules/trusted-firmware-m/nordic_nrf/nrf5340_cpuapp/CMakeLists.txt b/modules/trusted-firmware-m/nordic_nrf/nrf5340_cpuapp/CMakeLists.txt index 279ea385996..35338d542d7 100644 --- a/modules/trusted-firmware-m/nordic_nrf/nrf5340_cpuapp/CMakeLists.txt +++ b/modules/trusted-firmware-m/nordic_nrf/nrf5340_cpuapp/CMakeLists.txt @@ -5,8 +5,14 @@ # set(NRF_BOARD_SELECTED True) -set(NRF_SOC_VARIANT nrf5340) add_subdirectory(${Trusted\ Firmware\ M_SOURCE_DIR}/platform/ext/target/nordic_nrf/common/nrf5340 nrf5340) 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}) diff --git a/modules/trusted-firmware-m/nordic_nrf/nrf5340_cpuapp/config.cmake b/modules/trusted-firmware-m/nordic_nrf/nrf5340_cpuapp/config.cmake index b3e5d74181c..ae50a4846dd 100644 --- a/modules/trusted-firmware-m/nordic_nrf/nrf5340_cpuapp/config.cmake +++ b/modules/trusted-firmware-m/nordic_nrf/nrf5340_cpuapp/config.cmake @@ -4,5 +4,6 @@ # SPDX-License-Identifier: Apache-2.0 # -set(PLATFORM_PATH platform/ext/target/nordic_nrf/) +set(NRF_SOC_VARIANT nrf5340 CACHE STRING "nRF SoC Variant") + include(${PLATFORM_PATH}/common/nrf5340/config.cmake) diff --git a/modules/trusted-firmware-m/nordic_nrf/nrf5340_cpuapp/cpuarch.cmake b/modules/trusted-firmware-m/nordic_nrf/nrf5340_cpuapp/cpuarch.cmake index 903b23e4cc6..f19d7f43c67 100644 --- a/modules/trusted-firmware-m/nordic_nrf/nrf5340_cpuapp/cpuarch.cmake +++ b/modules/trusted-firmware-m/nordic_nrf/nrf5340_cpuapp/cpuarch.cmake @@ -4,4 +4,6 @@ # SPDX-License-Identifier: Apache-2.0 # -include(platform/ext/target/nordic_nrf/common/nrf5340/cpuarch.cmake) +set(PLATFORM_PATH platform/ext/target/nordic_nrf) + +include(${PLATFORM_PATH}/common/nrf5340/cpuarch.cmake) diff --git a/modules/trusted-firmware-m/nordic_nrf/nrf5340_cpuapp/ns/cpuarch_ns.cmake b/modules/trusted-firmware-m/nordic_nrf/nrf5340_cpuapp/ns/cpuarch_ns.cmake new file mode 100644 index 00000000000..077e88bd37b --- /dev/null +++ b/modules/trusted-firmware-m/nordic_nrf/nrf5340_cpuapp/ns/cpuarch_ns.cmake @@ -0,0 +1,10 @@ +# +# Copyright (c) 2023, 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/nrf5340/cpuarch.cmake) diff --git a/modules/trusted-firmware-m/nordic_nrf/nrf9120/CMakeLists.txt b/modules/trusted-firmware-m/nordic_nrf/nrf9120/CMakeLists.txt index a84c6fd9fd5..fe2c161200d 100644 --- a/modules/trusted-firmware-m/nordic_nrf/nrf9120/CMakeLists.txt +++ b/modules/trusted-firmware-m/nordic_nrf/nrf9120/CMakeLists.txt @@ -5,8 +5,17 @@ # set(NRF_BOARD_SELECTED True) -set(NRF_SOC_VARIANT nrf91) add_subdirectory(${Trusted\ Firmware\ M_SOURCE_DIR}/platform/ext/target/nordic_nrf/common/nrf91 nrf91) add_subdirectory(.. common) + +install(FILES ${CMAKE_CURRENT_LIST_DIR}/ns/cpuarch_ns.cmake + DESTINATION ${INSTALL_PLATFORM_NS_DIR} + RENAME cpuarch.cmake) + +install(FILES ${Trusted\ Firmware\ M_SOURCE_DIR}/platform/ext/target/nordic_nrf/common/nrf9120/cpuarch.cmake + DESTINATION ${INSTALL_PLATFORM_NS_DIR}/common/nrf9120) + +install(FILES config.cmake + DESTINATION ${INSTALL_PLATFORM_NS_DIR}) diff --git a/modules/trusted-firmware-m/nordic_nrf/nrf9120/config.cmake b/modules/trusted-firmware-m/nordic_nrf/nrf9120/config.cmake index 3f58e7b89eb..e858eda3a27 100644 --- a/modules/trusted-firmware-m/nordic_nrf/nrf9120/config.cmake +++ b/modules/trusted-firmware-m/nordic_nrf/nrf9120/config.cmake @@ -4,5 +4,6 @@ # SPDX-License-Identifier: Apache-2.0 # -set(PLATFORM_PATH platform/ext/target/nordic_nrf/) +set(NRF_SOC_VARIANT nrf91 CACHE STRING "nRF SoC Variant") + include(${PLATFORM_PATH}/common/nrf91/config.cmake) diff --git a/modules/trusted-firmware-m/nordic_nrf/nrf9120/cpuarch.cmake b/modules/trusted-firmware-m/nordic_nrf/nrf9120/cpuarch.cmake index b34a8ddab1a..9f0886c7a51 100644 --- a/modules/trusted-firmware-m/nordic_nrf/nrf9120/cpuarch.cmake +++ b/modules/trusted-firmware-m/nordic_nrf/nrf9120/cpuarch.cmake @@ -3,5 +3,6 @@ # # SPDX-License-Identifier: Apache-2.0 # +set(PLATFORM_PATH platform/ext/target/nordic_nrf) -include(platform/ext/target/nordic_nrf/common/nrf9120/cpuarch.cmake) +include(${PLATFORM_PATH}/common/nrf9120/cpuarch.cmake) diff --git a/modules/trusted-firmware-m/nordic_nrf/nrf9120/ns/cpuarch_ns.cmake b/modules/trusted-firmware-m/nordic_nrf/nrf9120/ns/cpuarch_ns.cmake new file mode 100644 index 00000000000..c53d684d7e8 --- /dev/null +++ b/modules/trusted-firmware-m/nordic_nrf/nrf9120/ns/cpuarch_ns.cmake @@ -0,0 +1,10 @@ +# +# Copyright (c) 2023, 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/nrf9120/cpuarch.cmake) diff --git a/modules/trusted-firmware-m/nordic_nrf/nrf9160/CMakeLists.txt b/modules/trusted-firmware-m/nordic_nrf/nrf9160/CMakeLists.txt index a84c6fd9fd5..ba840c6c8d1 100644 --- a/modules/trusted-firmware-m/nordic_nrf/nrf9160/CMakeLists.txt +++ b/modules/trusted-firmware-m/nordic_nrf/nrf9160/CMakeLists.txt @@ -5,8 +5,17 @@ # set(NRF_BOARD_SELECTED True) -set(NRF_SOC_VARIANT nrf91) add_subdirectory(${Trusted\ Firmware\ M_SOURCE_DIR}/platform/ext/target/nordic_nrf/common/nrf91 nrf91) add_subdirectory(.. common) + +install(FILES ${CMAKE_CURRENT_LIST_DIR}/ns/cpuarch_ns.cmake + DESTINATION ${INSTALL_PLATFORM_NS_DIR} + RENAME cpuarch.cmake) + +install(FILES ${Trusted\ Firmware\ M_SOURCE_DIR}/platform/ext/target/nordic_nrf/common/nrf9160/cpuarch.cmake + DESTINATION ${INSTALL_PLATFORM_NS_DIR}/common/nrf9160) + +install(FILES config.cmake + DESTINATION ${INSTALL_PLATFORM_NS_DIR}) diff --git a/modules/trusted-firmware-m/nordic_nrf/nrf9160/config.cmake b/modules/trusted-firmware-m/nordic_nrf/nrf9160/config.cmake index 3f58e7b89eb..e858eda3a27 100644 --- a/modules/trusted-firmware-m/nordic_nrf/nrf9160/config.cmake +++ b/modules/trusted-firmware-m/nordic_nrf/nrf9160/config.cmake @@ -4,5 +4,6 @@ # SPDX-License-Identifier: Apache-2.0 # -set(PLATFORM_PATH platform/ext/target/nordic_nrf/) +set(NRF_SOC_VARIANT nrf91 CACHE STRING "nRF SoC Variant") + include(${PLATFORM_PATH}/common/nrf91/config.cmake) diff --git a/modules/trusted-firmware-m/nordic_nrf/nrf9160/cpuarch.cmake b/modules/trusted-firmware-m/nordic_nrf/nrf9160/cpuarch.cmake index 228252f0147..f728014d3f7 100644 --- a/modules/trusted-firmware-m/nordic_nrf/nrf9160/cpuarch.cmake +++ b/modules/trusted-firmware-m/nordic_nrf/nrf9160/cpuarch.cmake @@ -4,4 +4,6 @@ # SPDX-License-Identifier: Apache-2.0 # -include(platform/ext/target/nordic_nrf/common/nrf9160/cpuarch.cmake) +set(PLATFORM_PATH platform/ext/target/nordic_nrf) + +include(${PLATFORM_PATH}/common/nrf9160/cpuarch.cmake) diff --git a/modules/trusted-firmware-m/nordic_nrf/nrf9160/ns/cpuarch_ns.cmake b/modules/trusted-firmware-m/nordic_nrf/nrf9160/ns/cpuarch_ns.cmake new file mode 100644 index 00000000000..902e7fe7ef4 --- /dev/null +++ b/modules/trusted-firmware-m/nordic_nrf/nrf9160/ns/cpuarch_ns.cmake @@ -0,0 +1,10 @@ +# +# Copyright (c) 2023, 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/nrf9160/cpuarch.cmake) diff --git a/modules/trusted-firmware-m/nordic_nrf/ns/CMakeLists.txt b/modules/trusted-firmware-m/nordic_nrf/ns/CMakeLists.txt new file mode 100644 index 00000000000..5bb8cb5bd94 --- /dev/null +++ b/modules/trusted-firmware-m/nordic_nrf/ns/CMakeLists.txt @@ -0,0 +1,46 @@ +# +# Copyright (c) 2023, Nordic Semiconductor ASA. +# +# SPDX-License-Identifier: Apache-2.0 +# + +cmake_policy(SET CMP0076 NEW) +set(CMAKE_CURRENT_SOURCE_DIR ${CMAKE_CURRENT_LIST_DIR}) +set(NRF_BOARD_SELECTED True) + +add_library(platform_ns STATIC) + +set(partition_includes + ${CMAKE_CURRENT_LIST_DIR}/common/${NRF_SOC_VARIANT}/partition + ${CMAKE_BINARY_DIR}/../zephyr/include/generated +) + +set(board_includes + ${CMAKE_BINARY_DIR}/../zephyr/misc/generated/syscalls_links/include + ${ZEPHYR_BASE}/include +) + +target_include_directories(platform_region_defs + INTERFACE + ${partition_includes} +) + +target_include_directories(platform_ns + PUBLIC + ${partition_includes} + ${board_includes} +) + +# Get the value of HAL_NORDIC_PATH +include(${CMAKE_CURRENT_LIST_DIR}/common/core/config_nordic_nrf_spe.cmake) +add_subdirectory(${CMAKE_CURRENT_LIST_DIR}/common/${NRF_SOC_VARIANT} ${NRF_SOC_VARIANT}) + +target_include_directories(platform_ns + PUBLIC + ${CMAKE_CURRENT_LIST_DIR} +) + +target_link_libraries(platform_ns + PUBLIC + platform_region_defs +) From f49cbf13ca8ff389bcf857eba542b2bb250a8545 Mon Sep 17 00:00:00 2001 From: Joakim Andersson Date: Thu, 14 Dec 2023 11:05:49 +0100 Subject: [PATCH 2392/3723] tfm: Remove TFM_BUILD_NS and update TFM_USE_NS_APP for NS build folder TF-M no longer builds the NS app, but exports build files to api_ns folder and expects the user to build the rest themselves. Remove the option to build the NS app, and update the TFM_USE_NS_APP to look for an output hex file in the tfm_ns folder. Signed-off-by: Joakim Andersson Signed-off-by: Markus Swarowsky --- modules/trusted-firmware-m/CMakeLists.txt | 41 +++++-------------- modules/trusted-firmware-m/Kconfig.tfm | 11 ----- samples/tfm_integration/tfm_psa_test/prj.conf | 1 - .../tfm_regression_test/prj.conf | 1 - 4 files changed, 10 insertions(+), 44 deletions(-) diff --git a/modules/trusted-firmware-m/CMakeLists.txt b/modules/trusted-firmware-m/CMakeLists.txt index 6b3c0351097..27591549b67 100644 --- a/modules/trusted-firmware-m/CMakeLists.txt +++ b/modules/trusted-firmware-m/CMakeLists.txt @@ -51,11 +51,6 @@ if (CONFIG_BUILD_WITH_TFM) else() list(APPEND TFM_CMAKE_ARGS -DBL2=FALSE) endif() - if (CONFIG_TFM_BUILD_NS) - list(APPEND TFM_CMAKE_ARGS -DNS=TRUE) - else() - list(APPEND TFM_CMAKE_ARGS -DNS=FALSE) - endif() if (CONFIG_TFM_ISOLATION_LEVEL) list(APPEND TFM_CMAKE_ARGS -DTFM_ISOLATION_LEVEL=${CONFIG_TFM_ISOLATION_LEVEL}) endif() @@ -185,9 +180,6 @@ if (CONFIG_BUILD_WITH_TFM) set(TFM_INTERFACE_INCLUDE_DIR ${TFM_BINARY_DIR}/api_ns/interface/include) set(TFM_INTERFACE_LIB_DIR ${TFM_BINARY_DIR}/api_ns/interface/lib) - set(TFM_API_NS_PATH ${TFM_BINARY_DIR}/tf-m-tests/app/libtfm_api_ns.a) - set(PLATFORM_NS_FILE ${TFM_BINARY_DIR}/platform/ns/libplatform_ns.a) - if (TFM_PSA_TEST_SUITE) set(PSA_TEST_VAL_FILE ${TFM_BINARY_DIR}/tf-m-tests/app/psa_api_tests/val/val_nspe.a) set(PSA_TEST_PAL_FILE ${TFM_BINARY_DIR}/tf-m-tests/app/psa_api_tests/platform/pal_nspe.a) @@ -208,27 +200,22 @@ if (CONFIG_BUILD_WITH_TFM) set(TFM_S_BIN_FILE ${TFM_BINARY_DIR}/bin/tfm_s.bin) set(TFM_S_HEX_FILE ${TFM_BINARY_DIR}/bin/tfm_s.hex) set(TFM_NS_BIN_FILE ${TFM_BINARY_DIR}/bin/tfm_ns.bin) - set(TFM_NS_HEX_FILE ${TFM_BINARY_DIR}/bin/tfm_ns.hex) + set(TFM_NS_HEX_FILE ${CMAKE_BINARY_DIR}/tfm_ns/bin/tfm_ns.hex) set(TFM_S_SIGNED_BIN_FILE ${TFM_BINARY_DIR}/bin/tfm_s_signed.bin) set(TFM_NS_SIGNED_BIN_FILE ${TFM_BINARY_DIR}/bin/tfm_ns_signed.bin) set(TFM_S_NS_SIGNED_BIN_FILE ${TFM_BINARY_DIR}/bin/tfm_s_ns_signed.bin) set(BUILD_BYPRODUCTS - ${TFM_API_NS_PATH} ${PSA_TEST_VAL_FILE} ${PSA_TEST_PAL_FILE} ${PSA_TEST_COMBINE_FILE} - ${PLATFORM_NS_FILE} ${BL2_ELF_FILE} ${BL2_BIN_FILE} ${BL2_HEX_FILE} ${TFM_S_ELF_FILE} ${TFM_S_BIN_FILE} ${TFM_S_HEX_FILE} - ${TFM_NS_BIN_FILE} - ${TFM_NS_HEX_FILE} ${TFM_S_SIGNED_BIN_FILE} - ${TFM_NS_SIGNED_BIN_FILE} ${TFM_S_NS_SIGNED_BIN_FILE} ${TFM_INTERFACE_LIB_DIR}/s_veneers.o @@ -427,25 +414,17 @@ if (CONFIG_BUILD_WITH_TFM) ) endif() - if(NOT CONFIG_TFM_BUILD_NS) - zephyr_library_sources_ifdef(CONFIG_TFM_PARTITION_PLATFORM ${TFM_INTERFACE_SOURCE_DIR}/tfm_platform_api.c) - zephyr_library_sources_ifdef(CONFIG_TFM_PARTITION_PROTECTED_STORAGE ${TFM_INTERFACE_SOURCE_DIR}/tfm_ps_api.c) - zephyr_library_sources_ifdef(CONFIG_TFM_PARTITION_INTERNAL_TRUSTED_STORAGE ${TFM_INTERFACE_SOURCE_DIR}/tfm_its_api.c) - zephyr_library_sources_ifdef(CONFIG_TFM_PARTITION_CRYPTO ${TFM_INTERFACE_SOURCE_DIR}/tfm_crypto_api.c) - zephyr_library_sources_ifdef(CONFIG_TFM_PARTITION_INITIAL_ATTESTATION ${TFM_INTERFACE_SOURCE_DIR}/tfm_attest_api.c) - zephyr_library_sources_ifdef(CONFIG_TFM_PARTITION_FIRMWARE_UPDATE ${TFM_INTERFACE_SOURCE_DIR}/tfm_fwu_api.c) - - zephyr_library_sources(${TFM_INTERFACE_SOURCE_DIR}/tfm_tz_psa_ns_api.c) + zephyr_library_sources_ifdef(CONFIG_TFM_PARTITION_PLATFORM ${TFM_INTERFACE_SOURCE_DIR}/tfm_platform_api.c) + zephyr_library_sources_ifdef(CONFIG_TFM_PARTITION_PROTECTED_STORAGE ${TFM_INTERFACE_SOURCE_DIR}/tfm_ps_api.c) + zephyr_library_sources_ifdef(CONFIG_TFM_PARTITION_INTERNAL_TRUSTED_STORAGE ${TFM_INTERFACE_SOURCE_DIR}/tfm_its_api.c) + zephyr_library_sources_ifdef(CONFIG_TFM_PARTITION_CRYPTO ${TFM_INTERFACE_SOURCE_DIR}/tfm_crypto_api.c) + zephyr_library_sources_ifdef(CONFIG_TFM_PARTITION_INITIAL_ATTESTATION ${TFM_INTERFACE_SOURCE_DIR}/tfm_attest_api.c) + zephyr_library_sources_ifdef(CONFIG_TFM_PARTITION_FIRMWARE_UPDATE ${TFM_INTERFACE_SOURCE_DIR}/tfm_fwu_api.c) - if(CONFIG_SOC_FAMILY_NRF) - zephyr_library_sources_ifdef(CONFIG_TFM_PARTITION_PLATFORM ${TFM_INTERFACE_SOURCE_DIR}/tfm_ioctl_core_ns_api.c) - endif() + zephyr_library_sources(${TFM_INTERFACE_SOURCE_DIR}/tfm_tz_psa_ns_api.c) - else() - zephyr_library_link_libraries( - ${PLATFORM_NS_FILE} - ${TFM_API_NS_PATH} - ) + if(CONFIG_SOC_FAMILY_NRF) + zephyr_library_sources_ifdef(CONFIG_TFM_PARTITION_PLATFORM ${TFM_INTERFACE_SOURCE_DIR}/tfm_ioctl_core_ns_api.c) endif() target_include_directories(tfm_api PRIVATE diff --git a/modules/trusted-firmware-m/Kconfig.tfm b/modules/trusted-firmware-m/Kconfig.tfm index 64ffef1fff8..277dd8a8d09 100644 --- a/modules/trusted-firmware-m/Kconfig.tfm +++ b/modules/trusted-firmware-m/Kconfig.tfm @@ -229,19 +229,8 @@ config TFM_BL2 TFM is designed to run with MCUboot in a certain configuration. This config adds MCUboot to the build - built via TFM's build system. -config TFM_BUILD_NS - bool "Build the TF-M Non-Secure application and libraries" - help - Instruct the TF-M build system to build the TF-M Non-Secure - application and libraries. - - This option is intended for testing purposes only, since this is the - easiest way to build the TF-M regression tests application and test - support libraries in the zephyr build system. - config TFM_USE_NS_APP bool "Use the TF-M Non-Secure application" - depends on TFM_BUILD_NS help The TF-M build system can produce multiple executable files. The main one is the TF-M secure firmware. Optionally the TF-M diff --git a/samples/tfm_integration/tfm_psa_test/prj.conf b/samples/tfm_integration/tfm_psa_test/prj.conf index 3ceca574528..aa35a6c27db 100644 --- a/samples/tfm_integration/tfm_psa_test/prj.conf +++ b/samples/tfm_integration/tfm_psa_test/prj.conf @@ -5,7 +5,6 @@ # CONFIG_BUILD_WITH_TFM=y -CONFIG_TFM_BUILD_NS=y CONFIG_TFM_PROFILE_TYPE_NOT_SET=y CONFIG_QEMU_ICOUNT_SHIFT=1 diff --git a/samples/tfm_integration/tfm_regression_test/prj.conf b/samples/tfm_integration/tfm_regression_test/prj.conf index 6817a7f717b..0a6573f811c 100644 --- a/samples/tfm_integration/tfm_regression_test/prj.conf +++ b/samples/tfm_integration/tfm_regression_test/prj.conf @@ -6,7 +6,6 @@ CONFIG_BUILD_WITH_TFM=y CONFIG_TFM_PROFILE_TYPE_NOT_SET=y -CONFIG_TFM_BUILD_NS=y CONFIG_TFM_USE_NS_APP=y CONFIG_TFM_REGRESSION_S=y CONFIG_TFM_REGRESSION_NS=y From f48467a2a61799b457750758ceeb3a393b841eda Mon Sep 17 00:00:00 2001 From: Joakim Andersson Date: Thu, 14 Dec 2023 13:13:50 +0100 Subject: [PATCH 2393/3723] tfm: Update TF-M regression tests sample to build NS app Update the TF-M regression tests sample to build the NS app in the tf-m-tests repository as an external project. The regression tests need to provide test configurations to both TF-M an NS app. Duplicate configuration done in the spe/CMakeLists.txt to configure TF-M image for the regression tests. Signed-off-by: Joakim Andersson Signed-off-by: Markus Swarowsky --- modules/trusted-firmware-m/CMakeLists.txt | 2 + .../tfm_regression_test/CMakeLists.txt | 48 +++++++++++++++++++ 2 files changed, 50 insertions(+) diff --git a/modules/trusted-firmware-m/CMakeLists.txt b/modules/trusted-firmware-m/CMakeLists.txt index 27591549b67..f8cb198d1ab 100644 --- a/modules/trusted-firmware-m/CMakeLists.txt +++ b/modules/trusted-firmware-m/CMakeLists.txt @@ -40,9 +40,11 @@ if (CONFIG_BUILD_WITH_TFM) endif() if (CONFIG_TFM_REGRESSION_S) list(APPEND TFM_CMAKE_ARGS -DTEST_S=ON) + list(APPEND TFM_CMAKE_ARGS -DTFM_S_REG_TEST:BOOL=ON) endif() if (CONFIG_TFM_REGRESSION_NS) list(APPEND TFM_CMAKE_ARGS -DTEST_NS=ON) + list(APPEND TFM_CMAKE_ARGS -DTFM_NS_REG_TEST:BOOL=ON) endif() if (CONFIG_TFM_BL2) list(APPEND TFM_CMAKE_ARGS -DBL2=TRUE) diff --git a/samples/tfm_integration/tfm_regression_test/CMakeLists.txt b/samples/tfm_integration/tfm_regression_test/CMakeLists.txt index 5f34b1c0b26..571bf986206 100644 --- a/samples/tfm_integration/tfm_regression_test/CMakeLists.txt +++ b/samples/tfm_integration/tfm_regression_test/CMakeLists.txt @@ -11,3 +11,51 @@ find_package(Zephyr REQUIRED HINTS $ENV{ZEPHYR_BASE}) project(tfm_regression_test) target_sources(app PRIVATE src/main.c) + +get_target_property(TFM_BINARY_DIR tfm TFM_BINARY_DIR) +get_target_property(TFM_NS_BIN_FILE tfm TFM_NS_BIN_FILE) +get_target_property(TFM_NS_HEX_FILE tfm TFM_NS_HEX_FILE) +get_target_property(TFM_NS_SIGNED_BIN_FILE tfm TFM_NS_SIGNED_BIN_FILE) + +set(TFM_TEST_REPO_PATH ${ZEPHYR_TRUSTED_FIRMWARE_M_MODULE_DIR}/../tf-m-tests) + +set(TFM_TEST_DIR "${TFM_TEST_REPO_PATH}/tests_reg/test/secure_regression") +set(TFM_TEST_CONFIG_FILE "${TFM_TEST_REPO_PATH}/tests_reg/test/config/config.cmake") + +set_property(TARGET zephyr_property_target + APPEND PROPERTY TFM_CMAKE_OPTIONS + -DCONFIG_TFM_TEST_DIR=${TFM_TEST_DIR} +) + +set_property(TARGET zephyr_property_target + APPEND PROPERTY TFM_CMAKE_OPTIONS + -DCONFIG_TFM_TEST_CONFIG_FILE=${TFM_TEST_CONFIG_FILE} +) + +include(ExternalProject) + +ExternalProject_Add(tfm_regression_test_app + SOURCE_DIR ${TFM_TEST_REPO_PATH}/tests_reg + BINARY_DIR ${PROJECT_BINARY_DIR}/tfm_ns + CONFIGURE_COMMAND + ${CMAKE_COMMAND} + -G ${CMAKE_GENERATOR} + -S ${TFM_TEST_REPO_PATH}/tests_reg + -B ${PROJECT_BINARY_DIR}/tfm_ns + -DCONFIG_SPE_PATH=${TFM_BINARY_DIR}/api_ns + -DTFM_TOOLCHAIN_FILE=cmake/toolchain_ns_GNUARM.cmake + -DQCBOR_PATH${QCBOR_PATH_TYPE}=${CONFIG_TFM_QCBOR_PATH} + -DCMAKE_BUILD_TYPE=RelWithDebInfo + BUILD_COMMAND ${CMAKE_COMMAND} --build . + INSTALL_COMMAND "" + BUILD_ALWAYS True + USES_TERMINAL_BUILD True + WORKING_DIRECTORY ${PROJECT_BINARY_DIR}/tfm_ns + DEPENDS tfm + BUILD_BYPRODUCTS + ${TFM_NS_HEX_FILE} + ${TFM_NS_BIN_FILE} + ${TFM_NS_SIGNED_BIN_FILE} +) + +add_dependencies(app tfm_regression_test_app) From cac7f4058ff3668b67fdb2c972ee9bb2fee1bfb5 Mon Sep 17 00:00:00 2001 From: Markus Swarowsky Date: Thu, 14 Dec 2023 18:01:59 +0100 Subject: [PATCH 2394/3723] modules: tf-m: Remove building of PSA arch tests This removed the CMake code that builds the TF-M arch tests within the TF-M CMakeFile. It will be moved to the tfm_integration/tfm_psa_test sample CMakeFile. Signed-off-by: Markus Swarowsky --- modules/trusted-firmware-m/CMakeLists.txt | 61 ------------------- .../src/zephyr_tfm_psa_test.c | 19 ------ 2 files changed, 80 deletions(-) delete mode 100644 modules/trusted-firmware-m/src/zephyr_tfm_psa_test.c diff --git a/modules/trusted-firmware-m/CMakeLists.txt b/modules/trusted-firmware-m/CMakeLists.txt index f8cb198d1ab..464832a885e 100644 --- a/modules/trusted-firmware-m/CMakeLists.txt +++ b/modules/trusted-firmware-m/CMakeLists.txt @@ -65,20 +65,6 @@ if (CONFIG_BUILD_WITH_TFM) if (CONFIG_TFM_PROFILE) list(APPEND TFM_CMAKE_ARGS -DTFM_PROFILE=${CONFIG_TFM_PROFILE}) endif() - if (CONFIG_TFM_PSA_TEST_CRYPTO) - set(TFM_PSA_TEST_SUITE CRYPTO) - elseif (CONFIG_TFM_PSA_TEST_PROTECTED_STORAGE) - set(TFM_PSA_TEST_SUITE PROTECTED_STORAGE) - elseif (CONFIG_TFM_PSA_TEST_INTERNAL_TRUSTED_STORAGE) - set(TFM_PSA_TEST_SUITE INTERNAL_TRUSTED_STORAGE) - elseif (CONFIG_TFM_PSA_TEST_STORAGE) - set(TFM_PSA_TEST_SUITE STORAGE) - elseif (CONFIG_TFM_PSA_TEST_INITIAL_ATTESTATION) - set(TFM_PSA_TEST_SUITE INITIAL_ATTESTATION) - endif() - if (DEFINED TFM_PSA_TEST_SUITE) - list(APPEND TFM_CMAKE_ARGS -DTEST_PSA_API=${TFM_PSA_TEST_SUITE}) - endif() if (CONFIG_TFM_CMAKE_BUILD_TYPE_RELEASE) set(TFM_CMAKE_BUILD_TYPE "Release") elseif (CONFIG_TFM_CMAKE_BUILD_TYPE_MINSIZEREL) @@ -182,17 +168,6 @@ if (CONFIG_BUILD_WITH_TFM) set(TFM_INTERFACE_INCLUDE_DIR ${TFM_BINARY_DIR}/api_ns/interface/include) set(TFM_INTERFACE_LIB_DIR ${TFM_BINARY_DIR}/api_ns/interface/lib) - if (TFM_PSA_TEST_SUITE) - set(PSA_TEST_VAL_FILE ${TFM_BINARY_DIR}/tf-m-tests/app/psa_api_tests/val/val_nspe.a) - set(PSA_TEST_PAL_FILE ${TFM_BINARY_DIR}/tf-m-tests/app/psa_api_tests/platform/pal_nspe.a) - set(COMBINE_DIR_STORAGE storage) - set(COMBINE_DIR_PROTECTED_STORAGE storage) - set(COMBINE_DIR_INTERNAL_TRUSTED_STORAGE storage) - set(COMBINE_DIR_CRYPTO crypto) - set(COMBINE_DIR_INITIAL_ATTESTATION initial_attestation) - set(PSA_TEST_COMBINE_FILE ${TFM_BINARY_DIR}/tf-m-tests/app/psa_api_tests/dev_apis/${COMBINE_DIR_${TFM_PSA_TEST_SUITE}}/test_combine.a) - endif() - if(CONFIG_TFM_BL2) set(BL2_ELF_FILE ${TFM_BINARY_DIR}/bin/bl2.elf) set(BL2_BIN_FILE ${TFM_BINARY_DIR}/bin/bl2.bin) @@ -253,26 +228,6 @@ if (CONFIG_BUILD_WITH_TFM) message(FATAL_ERROR "Unsupported ZEPHYR_TOOLCHAIN_VARIANT: ${ZEPHYR_TOOLCHAIN_VARIANT}") endif() - if (CONFIG_TFM_PARTITION_INITIAL_ATTESTATION AND CONFIG_TFM_QCBOR_PATH STREQUAL "") - # TODO: Remove this when QCBOR licensing issues w/t_cose have been resolved, - # or only allow it when 'QCBOR_PATH' is set to a local path where QCBOR has - # been manually downloaded by the user before starting the build. - message(FATAL_ERROR "CONFIG_TFM_PARTITION_INITIAL_ATTESTATION is not available " - "with TF-M 1.7.0 due to licensing issues with a dependent library. This " - "restriction will be removed once licensing issues have been resolved." - ) - endif() - - if (CONFIG_TFM_PSA_TEST_INITIAL_ATTESTATION AND CONFIG_TFM_QCBOR_PATH STREQUAL "") - # TODO: Remove this when QCBOR licensing issues w/t_cose have been resolved, - # or only allow it when 'QCBOR_PATH' is set to a local path where QCBOR has - # been manually downloaded by the user before starting the build. - message(FATAL_ERROR "CONFIG_TFM_PSA_TEST_INITIAL_ATTESTATION is not available " - "with TF-M 1.7.0 due to licensing issues with a dependent library. This " - "restriction will be removed once licensing issues have been resolved." - ) - endif() - if (CONFIG_TFM_QCBOR_PATH STREQUAL "DOWNLOAD") # Change CMake cache type to string to avoid QCBOR_PATH=/absolute/path/DOWNLOAD being set. set(QCBOR_PATH_TYPE ":STRING") @@ -296,13 +251,6 @@ if (CONFIG_BUILD_WITH_TFM) list(APPEND TFM_CMAKE_ARGS -DMCUBOOT_DATA_SHARING=ON) endif() - if(TFM_PSA_TEST_SUITE) - list(APPEND TFM_CMAKE_ARGS - -DPSA_TOOLCHAIN_FILE=${CMAKE_CURRENT_LIST_DIR}/psa/GNUARM.cmake - -DTOOLCHAIN=INHERIT - ) - endif() - if(CONFIG_FPU AND CONFIG_FP_HARDABI) list(APPEND TFM_CMAKE_ARGS -DCONFIG_TFM_ENABLE_FP=ON) # Note: This is not a cmake option in TF-M. @@ -406,15 +354,6 @@ if (CONFIG_BUILD_WITH_TFM) if (CONFIG_TFM_PARTITION_PLATFORM AND NOT CONFIG_TFM_PARTITION_PLATFORM_CUSTOM_REBOOT) zephyr_library_sources(src/reboot.c) endif() - zephyr_library_sources_ifndef(CONFIG_TFM_PSA_TEST_NONE src/zephyr_tfm_psa_test.c) - - if (TFM_PSA_TEST_SUITE) - zephyr_library_link_libraries( - ${PSA_TEST_VAL_FILE} - ${PSA_TEST_PAL_FILE} - ${PSA_TEST_COMBINE_FILE} - ) - endif() zephyr_library_sources_ifdef(CONFIG_TFM_PARTITION_PLATFORM ${TFM_INTERFACE_SOURCE_DIR}/tfm_platform_api.c) zephyr_library_sources_ifdef(CONFIG_TFM_PARTITION_PROTECTED_STORAGE ${TFM_INTERFACE_SOURCE_DIR}/tfm_ps_api.c) diff --git a/modules/trusted-firmware-m/src/zephyr_tfm_psa_test.c b/modules/trusted-firmware-m/src/zephyr_tfm_psa_test.c deleted file mode 100644 index d7d68f9db67..00000000000 --- a/modules/trusted-firmware-m/src/zephyr_tfm_psa_test.c +++ /dev/null @@ -1,19 +0,0 @@ -/* - * Copyright (c) 2021 Nordic Semiconductor ASA - * - * SPDX-License-Identifier: Apache-2.0 - */ - -#include - -/** - * \brief This symbol is the entry point provided by the PSA API compliance - * test libraries - */ -extern void val_entry(void); - - -void psa_test(void) -{ - val_entry(); -} From ad9cdf06c4c3021ddaad8721d4621acc9d1d9dec Mon Sep 17 00:00:00 2001 From: Markus Swarowsky Date: Thu, 14 Dec 2023 18:04:20 +0100 Subject: [PATCH 2395/3723] samples: tfm_psa_test: Adapt to TF-M split build The sample now builds the psa-arch-tests itself and doesn't rely anymore on the TF-M module CMakeFile. Additionally it will not run the zephyr main.c anymore but therefore only uses the tf-m non-secure application. Signed-off-by: Markus Swarowsky --- .../nordic_nrf/nrf5340_cpuapp/CMakeLists.txt | 5 + .../nordic_nrf/nrf9120/CMakeLists.txt | 4 + .../nordic_nrf/nrf9160/CMakeLists.txt | 4 + .../tfm_psa_test/CMakeLists.txt | 99 ++++++++++++++++++- samples/tfm_integration/tfm_psa_test/prj.conf | 2 + .../tfm_integration/tfm_psa_test/src/main.c | 12 +-- 6 files changed, 114 insertions(+), 12 deletions(-) diff --git a/modules/trusted-firmware-m/nordic_nrf/nrf5340_cpuapp/CMakeLists.txt b/modules/trusted-firmware-m/nordic_nrf/nrf5340_cpuapp/CMakeLists.txt index 35338d542d7..b74620fe2d5 100644 --- a/modules/trusted-firmware-m/nordic_nrf/nrf5340_cpuapp/CMakeLists.txt +++ b/modules/trusted-firmware-m/nordic_nrf/nrf5340_cpuapp/CMakeLists.txt @@ -16,3 +16,8 @@ install(FILES ${CMAKE_CURRENT_LIST_DIR}/ns/cpuarch_ns.cmake install(FILES config.cmake DESTINATION ${INSTALL_PLATFORM_NS_DIR}) + +install(DIRECTORY ${Trusted\ Firmware\ M_SOURCE_DIR}/platform/ext/target/nordic_nrf/nrf5340dk_nrf5340_cpuapp/tests + + DESTINATION ${INSTALL_PLATFORM_NS_DIR} +) diff --git a/modules/trusted-firmware-m/nordic_nrf/nrf9120/CMakeLists.txt b/modules/trusted-firmware-m/nordic_nrf/nrf9120/CMakeLists.txt index fe2c161200d..64fff7cdb86 100644 --- a/modules/trusted-firmware-m/nordic_nrf/nrf9120/CMakeLists.txt +++ b/modules/trusted-firmware-m/nordic_nrf/nrf9120/CMakeLists.txt @@ -19,3 +19,7 @@ install(FILES ${Trusted\ Firmware\ M_SOURCE_DIR}/platform/ext/target/nordi install(FILES config.cmake DESTINATION ${INSTALL_PLATFORM_NS_DIR}) + +install(DIRECTORY ${Trusted\ Firmware\ M_SOURCE_DIR}/platform/ext/target/nordic_nrf/nrf9161dk_nrf9161/tests + + DESTINATION ${INSTALL_PLATFORM_NS_DIR}) diff --git a/modules/trusted-firmware-m/nordic_nrf/nrf9160/CMakeLists.txt b/modules/trusted-firmware-m/nordic_nrf/nrf9160/CMakeLists.txt index ba840c6c8d1..aa2ef831031 100644 --- a/modules/trusted-firmware-m/nordic_nrf/nrf9160/CMakeLists.txt +++ b/modules/trusted-firmware-m/nordic_nrf/nrf9160/CMakeLists.txt @@ -19,3 +19,7 @@ install(FILES ${Trusted\ Firmware\ M_SOURCE_DIR}/platform/ext/target/nordi install(FILES config.cmake DESTINATION ${INSTALL_PLATFORM_NS_DIR}) + +install(DIRECTORY ${Trusted\ Firmware\ M_SOURCE_DIR}/platform/ext/target/nordic_nrf/nrf9160dk_nrf9160/tests + + DESTINATION ${INSTALL_PLATFORM_NS_DIR}) diff --git a/samples/tfm_integration/tfm_psa_test/CMakeLists.txt b/samples/tfm_integration/tfm_psa_test/CMakeLists.txt index 7692ea3dfd1..0d11c021627 100644 --- a/samples/tfm_integration/tfm_psa_test/CMakeLists.txt +++ b/samples/tfm_integration/tfm_psa_test/CMakeLists.txt @@ -8,10 +8,103 @@ cmake_minimum_required(VERSION 3.20.0) find_package(Zephyr REQUIRED HINTS $ENV{ZEPHYR_BASE}) -project(tfm_psa_storage_test) +project(tfm_psa_arch_test) target_sources(app PRIVATE src/main.c) -target_include_directories(app PRIVATE - $/api_ns/interface/include +get_target_property(TFM_BINARY_DIR tfm TFM_BINARY_DIR) +get_target_property(TFM_NS_BIN_FILE tfm TFM_NS_BIN_FILE) +get_target_property(TFM_NS_HEX_FILE tfm TFM_NS_HEX_FILE) +get_target_property(TFM_NS_SIGNED_BIN_FILE tfm TFM_NS_SIGNED_BIN_FILE) + +get_target_property(TFM_TOOLCHAIN_PATH tfm TFM_TOOLCHAIN_PATH) +get_target_property(TFM_TOOLCHAIN_PREFIX tfm TFM_TOOLCHAIN_PREFIX) +get_target_property(TFM_TOOLCHAIN_NS_FILE tfm TFM_TOOLCHAIN_NS_FILE) + +set(TFM_TEST_REPO_PATH ${ZEPHYR_TRUSTED_FIRMWARE_M_MODULE_DIR}/../tf-m-tests) +set(TFM_PSA_ARCHTEST_REPO_PATH ${ZEPHYR_TRUSTED_FIRMWARE_M_MODULE_DIR}/../psa-arch-tests) + +if (CONFIG_TFM_PSA_TEST_INITIAL_ATTESTATION AND CONFIG_TFM_QCBOR_PATH STREQUAL "") +# TODO: Remove this when QCBOR licensing issues w/t_cose have been resolved, +# or only allow it when 'QCBOR_PATH' is set to a local path where QCBOR has +# been manually downloaded by the user before starting the build. +message(FATAL_ERROR "CONFIG_TFM_PSA_TEST_INITIAL_ATTESTATION is not available " + "with TF-M 2.0.0 due to licensing issues with a dependent library. This " + "restriction will be removed once licensing issues have been resolved." + ) +endif() + + +set(TFM_TEST_DIR "${TFM_TEST_REPO_PATH}/tests_psa_arch/spe/partitions") +set(PSA_ARCH_TESTS_CONFIG_FILE "${TFM_TEST_REPO_PATH}/tests_psa_arch/spe/config/config_test_psa_api.cmake") +if (CONFIG_TFM_PSA_TEST_CRYPTO) +set(TFM_PSA_TEST_SUITE CRYPTO) +elseif (CONFIG_TFM_PSA_TEST_PROTECTED_STORAGE) +set(TFM_PSA_TEST_SUITE PROTECTED_STORAGE) +elseif (CONFIG_TFM_PSA_TEST_INTERNAL_TRUSTED_STORAGE) +set(TFM_PSA_TEST_SUITE INTERNAL_TRUSTED_STORAGE) +elseif (CONFIG_TFM_PSA_TEST_STORAGE) +set(TFM_PSA_TEST_SUITE STORAGE) +elseif (CONFIG_TFM_PSA_TEST_INITIAL_ATTESTATION) +set(TFM_PSA_TEST_SUITE INITIAL_ATTESTATION) +endif() + +if (NOT DEFINED TFM_PSA_TEST_SUITE) + message(FATAL_ERROR "Please define witch test suite to run: + CONFIG_TFM_PSA_TEST_CRYPTO + CONFIG_TFM_PSA_TEST_PROTECTED_STORAGE + CONFIG_TFM_PSA_TEST_STORAGE + CONFIG_TFM_PSA_TEST_INITIAL_ATTESTATION") +endif() +set(TEST_PSA_API "${TFM_PSA_TEST_SUITE}") + +set_property(TARGET zephyr_property_target + APPEND PROPERTY TFM_CMAKE_OPTIONS + -DPSA_ARCH_TESTS_PATH=${TFM_PSA_ARCHTEST_REPO_PATH} +) + +set_property(TARGET zephyr_property_target + APPEND PROPERTY TFM_CMAKE_OPTIONS + -DCONFIG_TFM_TEST_DIR=${TFM_TEST_DIR} ) + +set_property(TARGET zephyr_property_target + APPEND PROPERTY TFM_CMAKE_OPTIONS + -DCONFIG_PSA_ARCH_TESTS_CONFIG_FILE=${PSA_ARCH_TESTS_CONFIG_FILE} +) + +set_property(TARGET zephyr_property_target + APPEND PROPERTY TFM_CMAKE_OPTIONS + -DTEST_PSA_API=${TEST_PSA_API} +) + +include(ExternalProject) + +ExternalProject_Add(tfm_psa_arch_test_app + SOURCE_DIR ${TFM_TEST_REPO_PATH}/tests_psa_arch + BINARY_DIR ${PROJECT_BINARY_DIR}/tfm_ns + CONFIGURE_COMMAND + ${CMAKE_COMMAND} + -G ${CMAKE_GENERATOR} + -S ${TFM_TEST_REPO_PATH}/tests_psa_arch + -B ${PROJECT_BINARY_DIR}/tfm_ns + -DCROSS_COMPILE=${TFM_TOOLCHAIN_PATH}/${TFM_TOOLCHAIN_PREFIX} + -DPSA_TOOLCHAIN_FILE=${TFM_BINARY_DIR}/api_ns/cmake/${TFM_TOOLCHAIN_NS_FILE} + -DCONFIG_SPE_PATH=${TFM_BINARY_DIR}/api_ns + -DTFM_TOOLCHAIN_FILE=cmake/${TFM_TOOLCHAIN_NS_FILE} + -DQCBOR_PATH${QCBOR_PATH_TYPE}=${CONFIG_TFM_QCBOR_PATH} + -DCMAKE_BUILD_TYPE=RelWithDebInfo + -DTEST_PSA_API=${TEST_PSA_API} + BUILD_COMMAND ${CMAKE_COMMAND} --build . + INSTALL_COMMAND "" + BUILD_ALWAYS True + USES_TERMINAL_BUILD True + WORKING_DIRECTORY ${PROJECT_BINARY_DIR}/tfm_ns + DEPENDS tfm + BUILD_BYPRODUCTS + ${TFM_NS_HEX_FILE} + ${TFM_NS_BIN_FILE} + ${TFM_NS_SIGNED_BIN_FILE} +) + +add_dependencies(app tfm_psa_arch_test_app) diff --git a/samples/tfm_integration/tfm_psa_test/prj.conf b/samples/tfm_integration/tfm_psa_test/prj.conf index aa35a6c27db..bab1254229d 100644 --- a/samples/tfm_integration/tfm_psa_test/prj.conf +++ b/samples/tfm_integration/tfm_psa_test/prj.conf @@ -6,7 +6,9 @@ CONFIG_BUILD_WITH_TFM=y CONFIG_TFM_PROFILE_TYPE_NOT_SET=y +CONFIG_TFM_USE_NS_APP=y CONFIG_QEMU_ICOUNT_SHIFT=1 + # Needed for CRYPTO and INITIAL_ATTESTATION CONFIG_MAIN_STACK_SIZE=4096 diff --git a/samples/tfm_integration/tfm_psa_test/src/main.c b/samples/tfm_integration/tfm_psa_test/src/main.c index 232fc505cfd..9d2809fe269 100644 --- a/samples/tfm_integration/tfm_psa_test/src/main.c +++ b/samples/tfm_integration/tfm_psa_test/src/main.c @@ -1,21 +1,15 @@ /* - * Copyright (c) 2021 Nordic Semiconductor ASA. + * Copyright (c) 2023 Nordic Semiconductor ASA. * * SPDX-License-Identifier: Apache-2.0 */ #include -/* Run the PSA test suite */ -void psa_test(void); - int main(void) { -#ifdef CONFIG_TFM_PSA_TEST_NONE - #error "No PSA test suite set. Use Kconfig to enable a test suite.\n" -#else - psa_test(); -#endif + printk("Should not be printed, expected TF-M's NS application to be run instead.\n"); + k_panic(); for (;;) { } From 3a830433be49df2ddd2e30feac5ce494f9537026 Mon Sep 17 00:00:00 2001 From: Joakim Andersson Date: Fri, 15 Dec 2023 10:33:50 +0100 Subject: [PATCH 2396/3723] tfm: Provide properties for selected TF-M toolchain for NS application Provide properties for selected TF-M toolchain so that the NS application will use the same toolchain as TF-M. Signed-off-by: Joakim Andersson Signed-off-by: Markus Swarowsky --- modules/trusted-firmware-m/CMakeLists.txt | 7 +++++++ samples/tfm_integration/tfm_regression_test/CMakeLists.txt | 7 ++++++- 2 files changed, 13 insertions(+), 1 deletion(-) diff --git a/modules/trusted-firmware-m/CMakeLists.txt b/modules/trusted-firmware-m/CMakeLists.txt index 464832a885e..f647e385dcf 100644 --- a/modules/trusted-firmware-m/CMakeLists.txt +++ b/modules/trusted-firmware-m/CMakeLists.txt @@ -228,6 +228,8 @@ if (CONFIG_BUILD_WITH_TFM) message(FATAL_ERROR "Unsupported ZEPHYR_TOOLCHAIN_VARIANT: ${ZEPHYR_TOOLCHAIN_VARIANT}") endif() + string(REPLACE "toolchain" "toolchain_ns" TFM_TOOLCHAIN_NS_FILE ${TFM_TOOLCHAIN_FILE}) + if (CONFIG_TFM_QCBOR_PATH STREQUAL "DOWNLOAD") # Change CMake cache type to string to avoid QCBOR_PATH=/absolute/path/DOWNLOAD being set. set(QCBOR_PATH_TYPE ":STRING") @@ -318,6 +320,11 @@ if (CONFIG_BUILD_WITH_TFM) # This is the root of all TFM build artifacts. set_target_properties(tfm PROPERTIES TFM_BINARY_DIR ${TFM_BINARY_DIR}) + # Set TFM toolchain properties on 'tfm' + set_target_properties(tfm PROPERTIES TFM_TOOLCHAIN_NS_FILE ${TFM_TOOLCHAIN_NS_FILE}) + set_target_properties(tfm PROPERTIES TFM_TOOLCHAIN_PREFIX ${TFM_TOOLCHAIN_PREFIX}) + set_target_properties(tfm PROPERTIES TFM_TOOLCHAIN_PATH ${TFM_TOOLCHAIN_PATH}) + # Set BL2 (MCUboot) executable file paths as target properties on 'tfm' # These files are produced by the TFM build system. if(CONFIG_TFM_BL2) diff --git a/samples/tfm_integration/tfm_regression_test/CMakeLists.txt b/samples/tfm_integration/tfm_regression_test/CMakeLists.txt index 571bf986206..b86eebc4a81 100644 --- a/samples/tfm_integration/tfm_regression_test/CMakeLists.txt +++ b/samples/tfm_integration/tfm_regression_test/CMakeLists.txt @@ -17,6 +17,10 @@ get_target_property(TFM_NS_BIN_FILE tfm TFM_NS_BIN_FILE) get_target_property(TFM_NS_HEX_FILE tfm TFM_NS_HEX_FILE) get_target_property(TFM_NS_SIGNED_BIN_FILE tfm TFM_NS_SIGNED_BIN_FILE) +get_target_property(TFM_TOOLCHAIN_PATH tfm TFM_TOOLCHAIN_PATH) +get_target_property(TFM_TOOLCHAIN_PREFIX tfm TFM_TOOLCHAIN_PREFIX) +get_target_property(TFM_TOOLCHAIN_NS_FILE tfm TFM_TOOLCHAIN_NS_FILE) + set(TFM_TEST_REPO_PATH ${ZEPHYR_TRUSTED_FIRMWARE_M_MODULE_DIR}/../tf-m-tests) set(TFM_TEST_DIR "${TFM_TEST_REPO_PATH}/tests_reg/test/secure_regression") @@ -43,7 +47,8 @@ ExternalProject_Add(tfm_regression_test_app -S ${TFM_TEST_REPO_PATH}/tests_reg -B ${PROJECT_BINARY_DIR}/tfm_ns -DCONFIG_SPE_PATH=${TFM_BINARY_DIR}/api_ns - -DTFM_TOOLCHAIN_FILE=cmake/toolchain_ns_GNUARM.cmake + -DTFM_TOOLCHAIN_FILE=cmake/${TFM_TOOLCHAIN_NS_FILE} + -DCROSS_COMPILE=${TFM_TOOLCHAIN_PATH}/${TFM_TOOLCHAIN_PREFIX} -DQCBOR_PATH${QCBOR_PATH_TYPE}=${CONFIG_TFM_QCBOR_PATH} -DCMAKE_BUILD_TYPE=RelWithDebInfo BUILD_COMMAND ${CMAKE_COMMAND} --build . From ab2c9437d906b24bc2e843470a79fdd8db7acc3d Mon Sep 17 00:00:00 2001 From: Pisit Sawangvonganan Date: Mon, 25 Dec 2023 21:40:06 +0700 Subject: [PATCH 2397/3723] drivers: i2c: set 'i2c_driver_api' as 'static const' This change marks each instance of the 'i2c_driver_api' as 'static const'. The rationale is that 'i2c_driver_api' is used for declaring internal module interfaces and is not intended to be modified at runtime. By using 'static const', we ensure immutability, leading to usage of only .rodata and a reduction in the .data area. Signed-off-by: Pisit Sawangvonganan --- drivers/i2c/gpio_i2c_switch.c | 2 +- drivers/i2c/i2c_ambiq.c | 2 +- drivers/i2c/i2c_emul.c | 2 +- drivers/i2c/i2c_gd32.c | 2 +- drivers/i2c/i2c_gpio.c | 2 +- drivers/i2c/i2c_litex.c | 4 ++-- drivers/i2c/i2c_nios2.c | 2 +- drivers/i2c/i2c_sbcon.c | 2 +- drivers/i2c/i2c_sedi.c | 6 ++++-- drivers/i2c/i2c_sifive.c | 2 +- drivers/i2c/i2c_tca954x.c | 2 +- 11 files changed, 15 insertions(+), 13 deletions(-) diff --git a/drivers/i2c/gpio_i2c_switch.c b/drivers/i2c/gpio_i2c_switch.c index 07183d82e62..d5a125a531b 100644 --- a/drivers/i2c/gpio_i2c_switch.c +++ b/drivers/i2c/gpio_i2c_switch.c @@ -64,7 +64,7 @@ static int gpio_i2c_switch_transfer(const struct device *dev, struct i2c_msg *ms return res; } -const struct i2c_driver_api gpio_i2c_switch_api_funcs = { +static const struct i2c_driver_api gpio_i2c_switch_api_funcs = { .configure = gpio_i2c_switch_configure, .transfer = gpio_i2c_switch_transfer, }; diff --git a/drivers/i2c/i2c_ambiq.c b/drivers/i2c/i2c_ambiq.c index d5b94686739..e8b62fb2c45 100644 --- a/drivers/i2c/i2c_ambiq.c +++ b/drivers/i2c/i2c_ambiq.c @@ -152,7 +152,7 @@ static int i2c_ambiq_init(const struct device *dev) return ret; } -static struct i2c_driver_api i2c_ambiq_driver_api = { +static const struct i2c_driver_api i2c_ambiq_driver_api = { .configure = i2c_ambiq_configure, .transfer = i2c_ambiq_transfer, }; diff --git a/drivers/i2c/i2c_emul.c b/drivers/i2c/i2c_emul.c index 63488da8cfd..62e0b0d7621 100644 --- a/drivers/i2c/i2c_emul.c +++ b/drivers/i2c/i2c_emul.c @@ -134,7 +134,7 @@ int i2c_emul_register(const struct device *dev, struct i2c_emul *emul) /* Device instantiation */ -static struct i2c_driver_api i2c_emul_api = { +static const struct i2c_driver_api i2c_emul_api = { .configure = i2c_emul_configure, .get_config = i2c_emul_get_config, .transfer = i2c_emul_transfer, diff --git a/drivers/i2c/i2c_gd32.c b/drivers/i2c/i2c_gd32.c index ab4347f2352..4959bed65b1 100644 --- a/drivers/i2c/i2c_gd32.c +++ b/drivers/i2c/i2c_gd32.c @@ -644,7 +644,7 @@ static int i2c_gd32_configure(const struct device *dev, return err; } -static struct i2c_driver_api i2c_gd32_driver_api = { +static const struct i2c_driver_api i2c_gd32_driver_api = { .configure = i2c_gd32_configure, .transfer = i2c_gd32_transfer, }; diff --git a/drivers/i2c/i2c_gpio.c b/drivers/i2c/i2c_gpio.c index 17d1eac0d8a..4cb5606507a 100644 --- a/drivers/i2c/i2c_gpio.c +++ b/drivers/i2c/i2c_gpio.c @@ -123,7 +123,7 @@ static int i2c_gpio_recover_bus(const struct device *dev) return rc; } -static struct i2c_driver_api api = { +static const struct i2c_driver_api api = { .configure = i2c_gpio_configure, .transfer = i2c_gpio_transfer, .recover_bus = i2c_gpio_recover_bus, diff --git a/drivers/i2c/i2c_litex.c b/drivers/i2c/i2c_litex.c index 8f429ba5e59..a8e5f86a162 100644 --- a/drivers/i2c/i2c_litex.c +++ b/drivers/i2c/i2c_litex.c @@ -108,8 +108,8 @@ static int i2c_litex_transfer(const struct device *dev, struct i2c_msg *msgs, } static const struct i2c_driver_api i2c_litex_driver_api = { - .configure = i2c_litex_configure, - .transfer = i2c_litex_transfer, + .configure = i2c_litex_configure, + .transfer = i2c_litex_transfer, }; /* Device Instantiation */ diff --git a/drivers/i2c/i2c_nios2.c b/drivers/i2c/i2c_nios2.c index 2540a0a87ac..1300b2d95b6 100644 --- a/drivers/i2c/i2c_nios2.c +++ b/drivers/i2c/i2c_nios2.c @@ -152,7 +152,7 @@ static void i2c_nios2_isr(const struct device *dev) static int i2c_nios2_init(const struct device *dev); -static struct i2c_driver_api i2c_nios2_driver_api = { +static const struct i2c_driver_api i2c_nios2_driver_api = { .configure = i2c_nios2_configure, .transfer = i2c_nios2_transfer, }; diff --git a/drivers/i2c/i2c_sbcon.c b/drivers/i2c/i2c_sbcon.c index 8ef32d7bb89..e3ddd62b262 100644 --- a/drivers/i2c/i2c_sbcon.c +++ b/drivers/i2c/i2c_sbcon.c @@ -93,7 +93,7 @@ static int i2c_sbcon_transfer(const struct device *dev, struct i2c_msg *msgs, slave_address); } -static struct i2c_driver_api api = { +static const struct i2c_driver_api api = { .configure = i2c_sbcon_configure, .transfer = i2c_sbcon_transfer, }; diff --git a/drivers/i2c/i2c_sedi.c b/drivers/i2c/i2c_sedi.c index ab14a7be9dd..4802e0ba071 100644 --- a/drivers/i2c/i2c_sedi.c +++ b/drivers/i2c/i2c_sedi.c @@ -112,8 +112,10 @@ static int i2c_sedi_api_full_io(const struct device *dev, struct i2c_msg *msgs, return ret; } -static const struct i2c_driver_api i2c_sedi_apis = {.configure = i2c_sedi_api_configure, - .transfer = i2c_sedi_api_full_io}; +static const struct i2c_driver_api i2c_sedi_apis = { + .configure = i2c_sedi_api_configure, + .transfer = i2c_sedi_api_full_io +}; #ifdef CONFIG_PM_DEVICE diff --git a/drivers/i2c/i2c_sifive.c b/drivers/i2c/i2c_sifive.c index 671139bd266..ca2e4ae8b68 100644 --- a/drivers/i2c/i2c_sifive.c +++ b/drivers/i2c/i2c_sifive.c @@ -317,7 +317,7 @@ static int i2c_sifive_init(const struct device *dev) } -static struct i2c_driver_api i2c_sifive_api = { +static const struct i2c_driver_api i2c_sifive_api = { .configure = i2c_sifive_configure, .transfer = i2c_sifive_transfer, }; diff --git a/drivers/i2c/i2c_tca954x.c b/drivers/i2c/i2c_tca954x.c index da19336af73..9a61d2bad17 100644 --- a/drivers/i2c/i2c_tca954x.c +++ b/drivers/i2c/i2c_tca954x.c @@ -151,7 +151,7 @@ static int tca954x_channel_init(const struct device *dev) return 0; } -const struct i2c_driver_api tca954x_api_funcs = { +static const struct i2c_driver_api tca954x_api_funcs = { .configure = tca954x_configure, .transfer = tca954x_transfer, }; From 3a37c5d98707af6fe74d3ffc1d04f1fe02ff0271 Mon Sep 17 00:00:00 2001 From: Jukka Rissanen Date: Tue, 16 Jan 2024 10:51:42 +0200 Subject: [PATCH 2398/3723] net: shell: Require float printf support from libc Various network shell commands like ping need floating point support from libc so select the CONFIG_REQUIRES_FLOAT_PRINTF option for it. Fixes #67601 Signed-off-by: Jukka Rissanen --- subsys/net/ip/Kconfig | 1 + 1 file changed, 1 insertion(+) diff --git a/subsys/net/ip/Kconfig b/subsys/net/ip/Kconfig index a479561e132..4203a42ee18 100644 --- a/subsys/net/ip/Kconfig +++ b/subsys/net/ip/Kconfig @@ -165,6 +165,7 @@ config NET_SHELL select SHELL select NET_IPV4_IGMP if NET_IPV4 select NET_IPV6_MLD if NET_IPV6 + select REQUIRES_FLOAT_PRINTF help Activate shell module that provides network commands like ping to the console. From 33d4b6d1482c7ba2cf97a037b2a8dde260547379 Mon Sep 17 00:00:00 2001 From: Alberto Escolar Piedras Date: Tue, 16 Jan 2024 17:48:10 +0100 Subject: [PATCH 2399/3723] manifest: Update nrf hw models to latest * Update the HW models module to 6b6ae3652c92c95edd945dce6ad9ef9892aab89b Including the following: * 6b6ae36 UART: Minor optimization * afe84c1 fake timer: Minor speed optimization for nrf52 * a5a4dfd RTC: Fix counter value when CLEAR after STOP Signed-off-by: Alberto Escolar Piedras --- west.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/west.yml b/west.yml index 6187f0380d3..ae798440e16 100644 --- a/west.yml +++ b/west.yml @@ -295,7 +295,7 @@ manifest: groups: - tools - name: nrf_hw_models - revision: a08acc7d3a853f890df2bf82167c02ab2153ffe7 + revision: 6b6ae3652c92c95edd945dce6ad9ef9892aab89b path: modules/bsim_hw_models/nrf_hw_models - name: open-amp revision: da78aea63159771956fe0c9263f2e6985b66e9d5 From f59ab74ba8a6809f46e7d3a1f8943b9396259ca7 Mon Sep 17 00:00:00 2001 From: Laurin Wolf Date: Tue, 16 Jan 2024 19:52:34 +0100 Subject: [PATCH 2400/3723] docs: lwm2m: fix example x509 CA certificate resource id The resource ID of the CA certificate in the Security Object should be 0/0/4 instead of 0/0/5 Signed-off-by: Laurin Wolf --- doc/connectivity/networking/api/lwm2m.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/doc/connectivity/networking/api/lwm2m.rst b/doc/connectivity/networking/api/lwm2m.rst index 26b544144df..8aab68e54ca 100644 --- a/doc/connectivity/networking/api/lwm2m.rst +++ b/doc/connectivity/networking/api/lwm2m.rst @@ -450,7 +450,7 @@ An example of setting up the security object for X509 certificate mode: lwm2m_set_u8(&LWM2M_OBJ(LWM2M_OBJECT_SECURITY_ID, 0, 2), LWM2M_SECURITY_CERT); lwm2m_set_string(&LWM2M_OBJ(LWM2M_OBJECT_SECURITY_ID, 0, 3), certificate); lwm2m_set_string(&LWM2M_OBJ(LWM2M_OBJECT_SECURITY_ID, 0, 5), key); - lwm2m_set_string(&LWM2M_OBJ(LWM2M_OBJECT_SECURITY_ID, 0, 5), root_ca); + lwm2m_set_string(&LWM2M_OBJ(LWM2M_OBJECT_SECURITY_ID, 0, 4), root_ca); Before calling :c:func:`lwm2m_rd_client_start` assign the tls_tag # where the LwM2M library should store the DTLS information prior to connection (normally a From 4d854a193e4958659669afadad621f86636b0bff Mon Sep 17 00:00:00 2001 From: Ajay Parida Date: Wed, 17 Jan 2024 14:49:00 +0530 Subject: [PATCH 2401/3723] net: mgmt: Print correct TWT teardown status message Print success message for TWT teardown successful case. Signed-off-by: Ajay Parida --- subsys/net/l2/wifi/wifi_shell.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/subsys/net/l2/wifi/wifi_shell.c b/subsys/net/l2/wifi/wifi_shell.c index ebb47dd76cd..8c18cf9488c 100644 --- a/subsys/net/l2/wifi/wifi_shell.c +++ b/subsys/net/l2/wifi/wifi_shell.c @@ -292,7 +292,7 @@ static void handle_wifi_twt_event(struct net_mgmt_event_callback *cb) if (resp->operation == WIFI_TWT_TEARDOWN) { if (resp->teardown_status == WIFI_TWT_TEARDOWN_SUCCESS) { - print(context.sh, SHELL_NORMAL, "TWT teardown received for flow ID %d\n", + print(context.sh, SHELL_NORMAL, "TWT teardown succeeded for flow ID %d\n", resp->flow_id); } else { print(context.sh, SHELL_NORMAL, "TWT teardown failed for flow ID %d\n", From 77c76fd7aa33f9bc540e7ee909a9b3e514a7ed5f Mon Sep 17 00:00:00 2001 From: Emil Gydesen Date: Mon, 18 Dec 2023 22:38:41 +0100 Subject: [PATCH 2402/3723] doc: Bluetooth: Update audio status table Put CAP Commander into WIP. Put PBP source and sink into done. Put GMAP into done (minus samples). Signed-off-by: Emil Gydesen --- .../bluetooth/bluetooth-audio-arch.rst | 53 ++++++++++--------- 1 file changed, 28 insertions(+), 25 deletions(-) diff --git a/doc/connectivity/bluetooth/bluetooth-audio-arch.rst b/doc/connectivity/bluetooth/bluetooth-audio-arch.rst index aa62b426160..85388b6dc0f 100644 --- a/doc/connectivity/bluetooth/bluetooth-audio-arch.rst +++ b/doc/connectivity/bluetooth/bluetooth-audio-arch.rst @@ -132,7 +132,10 @@ Bluetooth Audio Stack. | | | | | - Shell Module | | | | | | | - BSIM test | | | +-------------------------------+---------+------------------+-----------------------+--------------------------------------------------+ - | | Commander | | | - Not Started | | + | | Commander | | | - WIP | - Feature complete | + | | | | | | - Shell Module | + | | | | | | - BSIM test | + | | | | | | - Sample Application | +--------+-------------------------------+---------+------------------+-----------------------+--------------------------------------------------+ | HAP | Hearing Aid | 1.0 | 3.1 | - Feature complete | | | | | | | - Shell Module | | @@ -179,40 +182,40 @@ Bluetooth Audio Stack. | | | | | - BSIM test | | | | | | | - Sample Application | | +--------+-------------------------------+---------+------------------+-----------------------+--------------------------------------------------+ - | PBP | Public Broadcast Source | | | - WIP :github:`60777` | - Feature complete | - | | | | | | - Shell Module | - | | | | | | - BSIM test | - | | | | | | - Sample Application | + | PBP | Public Broadcast Source | | 3.5 | - Feature complete | | + | | | | | - Shell Module | | + | | | | | - BSIM test | | + | | | | | - Sample Application | | | +-------------------------------+---------+------------------+-----------------------+--------------------------------------------------+ - | | Public Broadcast Sink | | | - WIP :github:`60777` | - Feature complete | - | | | | | | - Shell Module | - | | | | | | - BSIM test | - | | | | | | - Sample Application | + | | Public Broadcast Sink | | 3.5 | - Feature complete | | + | | | | | - Shell Module | | + | | | | | - BSIM test | | + | | | | | - Sample Application | | | +-------------------------------+---------+------------------+-----------------------+--------------------------------------------------+ | | Public Broadcast Assistant | | | | - Feature complete | | | | | | | - Shell Module | | | | | | | - BSIM test | | | | | | | - Sample Application | +--------+-------------------------------+---------+------------------+-----------------------+--------------------------------------------------+ - | GMAP | Unicast Game Gateway | | | - WIP :github:`57032` | - Feature complete | - | | | | | | - Shell Module | - | | | | | | - BSIM test | - | | | | | | - Sample Application | + | GMAP | Unicast Game Gateway | | 3.5 | - Feature complete | - Sample Application | + | | | | | - Shell Module | | + | | | | | - BSIM test | | + | | | | | | | | +-------------------------------+---------+------------------+-----------------------+--------------------------------------------------+ - | | Unicast Game Terminal | | | - WIP :github:`57032` | - Feature complete | - | | | | | | - Shell Module | - | | | | | | - BSIM test | - | | | | | | - Sample Application | + | | Unicast Game Terminal | | 3.5 | - Feature complete | - Sample Application | + | | | | | - Shell Module | | + | | | | | - BSIM test | | + | | | | | | | | +-------------------------------+---------+------------------+-----------------------+--------------------------------------------------+ - | | Broadcast Game Sender | | | - WIP :github:`57032` | - Feature complete | - | | | | | | - Shell Module | - | | | | | | - BSIM test | - | | | | | | - Sample Application | + | | Broadcast Game Sender | | 3.5 | - Feature complete | - Sample Application | + | | | | | - Shell Module | | + | | | | | - BSIM test | | + | | | | | | | | +-------------------------------+---------+------------------+-----------------------+--------------------------------------------------+ - | | Broadcast Game Receiver | | | - WIP :github:`57032` | - Feature complete | - | | | | | | - Shell Module | - | | | | | | - BSIM test | - | | | | | | - Sample Application | + | | Broadcast Game Receiver | | 3.5 | - Feature complete | - Sample Application | + | | | | | - Shell Module | | + | | | | | - BSIM test | | + | | | | | | | +--------+-------------------------------+---------+------------------+-----------------------+--------------------------------------------------+ Using the Bluetooth Audio Stack From 991523f462b1269b5eac63013a4b4e659a64ac0c Mon Sep 17 00:00:00 2001 From: Daniel Leung Date: Thu, 16 Nov 2023 11:39:14 -0800 Subject: [PATCH 2403/3723] x86: add CODE_UNREACHABLE to z_x86_cpu_init For some reason, unrelated code change triggered compiler warning about this function returns even though it is marked nonreturn. So add CODE_UNREACHABLE to silence the warning, possibly to catch any errors. Signed-off-by: Daniel Leung --- arch/x86/core/intel64/cpu.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/arch/x86/core/intel64/cpu.c b/arch/x86/core/intel64/cpu.c index 16d39ea1f1a..2a845960b87 100644 --- a/arch/x86/core/intel64/cpu.c +++ b/arch/x86/core/intel64/cpu.c @@ -208,4 +208,6 @@ FUNC_NORETURN void z_x86_cpu_init(struct x86_cpuboot *cpuboot) /* Enter kernel, never return */ cpuboot->ready++; cpuboot->fn(cpuboot->arg); + + CODE_UNREACHABLE; /* LCOV_EXCL_LINE */ } From f3bcf48590204de2847d4f66b4904c10341a4252 Mon Sep 17 00:00:00 2001 From: Daniel Leung Date: Thu, 2 Nov 2023 13:54:21 -0700 Subject: [PATCH 2404/3723] boards: qemu_x86_64: amend DTS to have 2 CPU nodes qemu_x86_64 has default of 2 CPUs but the device tree only has 1. For correctness, add another CPU node to the tree. Signed-off-by: Daniel Leung --- boards/x86/qemu_x86/qemu_x86_64.dts | 11 +++++++++++ boards/x86/qemu_x86/qemu_x86_64_nokpti.dts | 11 +++++++++++ 2 files changed, 22 insertions(+) diff --git a/boards/x86/qemu_x86/qemu_x86_64.dts b/boards/x86/qemu_x86/qemu_x86_64.dts index 83bf2c7fd0f..fc252104773 100644 --- a/boards/x86/qemu_x86/qemu_x86_64.dts +++ b/boards/x86/qemu_x86/qemu_x86_64.dts @@ -5,6 +5,17 @@ #include "qemu_x86.dts" +/ { + cpus { + cpu@1 { + device_type = "cpu"; + compatible = "intel,x86"; + d-cache-line-size = <64>; + reg = <1>; + }; + }; +}; + &pcie0 { smbus0: smbus0 { compatible = "intel,pch-smbus"; diff --git a/boards/x86/qemu_x86/qemu_x86_64_nokpti.dts b/boards/x86/qemu_x86/qemu_x86_64_nokpti.dts index 92522ab8a4e..8a5f2d51154 100644 --- a/boards/x86/qemu_x86/qemu_x86_64_nokpti.dts +++ b/boards/x86/qemu_x86/qemu_x86_64_nokpti.dts @@ -4,3 +4,14 @@ */ #include "qemu_x86.dts" + +/ { + cpus { + cpu@1 { + device_type = "cpu"; + compatible = "intel,x86"; + d-cache-line-size = <64>; + reg = <1>; + }; + }; +}; From 803e0e452f997a58d311b4c0786403056f0b8280 Mon Sep 17 00:00:00 2001 From: Daniel Leung Date: Wed, 1 Nov 2023 16:01:10 -0700 Subject: [PATCH 2405/3723] kernel: amend wording on CONFIG_SMP_BOOT_DELAY This extends the wording so that not only architecture code can start secondary CPUs at a later time. Also adds a missing 'to'. Signed-off-by: Daniel Leung --- kernel/Kconfig | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/kernel/Kconfig b/kernel/Kconfig index a01f40551e1..1620a3c9aa4 100644 --- a/kernel/Kconfig +++ b/kernel/Kconfig @@ -1177,8 +1177,9 @@ config SMP_BOOT_DELAY depends on SMP help By default Zephyr will boot all available CPUs during start up. - Select this option to skip this and allow architecture code boot - secondary CPUs at a later time. + Select this option to skip this and allow custom code + (architecture/SoC/board/application) to boot secondary CPUs at + a later time. config MP_NUM_CPUS int "Number of CPUs/cores [DEPRECATED]" From ad87d2667c3105b7de690af65da6eb08e2496c5a Mon Sep 17 00:00:00 2001 From: Daniel Leung Date: Wed, 1 Nov 2023 16:16:51 -0700 Subject: [PATCH 2406/3723] tests: kernel/smp_boot_delay: make test more generic This makes the test a bit more generic so it can run on other SMP enabled platforms. Though, we don't need CI running this on every SMP platforms as this is not testing the mechanism of bringing up a CPU. That is being tested on the other SMP test. Therefore, only enable qemu_x86_64 to be testing in CI so that this feature will still be tested on CI. Signed-off-by: Daniel Leung --- tests/kernel/smp_boot_delay/src/main.c | 4 ++-- tests/kernel/smp_boot_delay/testcase.yaml | 8 ++++---- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/tests/kernel/smp_boot_delay/src/main.c b/tests/kernel/smp_boot_delay/src/main.c index dfa0572f1fa..94df5271770 100644 --- a/tests/kernel/smp_boot_delay/src/main.c +++ b/tests/kernel/smp_boot_delay/src/main.c @@ -11,11 +11,10 @@ #define CPU_START_DELAY 10000 /* IPIs happen much faster than CPU startup */ -#define CPU_IPI_DELAY 100 +#define CPU_IPI_DELAY 1000 BUILD_ASSERT(CONFIG_SMP); BUILD_ASSERT(CONFIG_SMP_BOOT_DELAY); -BUILD_ASSERT(CONFIG_KERNEL_COHERENCE); BUILD_ASSERT(CONFIG_MP_MAX_NUM_CPUS > 1); #define STACKSZ 2048 @@ -55,6 +54,7 @@ ZTEST(smp_boot_delay, test_smp_boot_delay) zassert_true(mp_flag, "CPU1 did not start"); k_thread_abort(&cpu1_thr); + k_thread_join(&cpu1_thr, K_FOREVER); /* Spawn the same thread to do the same thing, but this time * expect that the thread is going to run synchronously on the diff --git a/tests/kernel/smp_boot_delay/testcase.yaml b/tests/kernel/smp_boot_delay/testcase.yaml index 4b4954aef37..3aef08bc67e 100644 --- a/tests/kernel/smp_boot_delay/testcase.yaml +++ b/tests/kernel/smp_boot_delay/testcase.yaml @@ -3,17 +3,17 @@ tests: tags: - kernel - smp - platform_allow: intel_adsp_cavs25 + platform_allow: intel_adsp_cavs25 qemu_x86_64 integration_platforms: - - intel_adsp_cavs25 + - qemu_x86_64 kernel.multiprocessing.smp_boot_delay.minimallibc: filter: CONFIG_MINIMAL_LIBC_SUPPORTED tags: - kernel - smp - libc - platform_allow: intel_adsp_cavs25 + platform_allow: intel_adsp_cavs25 qemu_x86_64 integration_platforms: - - intel_adsp_cavs25 + - qemu_x86_64 extra_configs: - CONFIG_MINIMAL_LIBC=y From 89b231e7e2d34b25ef7a52832bdd74873607c52e Mon Sep 17 00:00:00 2001 From: Daniel Leung Date: Mon, 6 Nov 2023 14:29:35 -0800 Subject: [PATCH 2407/3723] kernel: smp: introduce k_smp_cpu_start This renames z_smp_cpu_start() to k_smp_cpu_start(). This effectively promotes z_smp_cpu_start() into a public API which allows out of tree usage. Since this is a new API, we can afford to change it signature, where it allows an additional initialization steps to be done before a newly powered up CPU starts participating in scheduling threads to run. Signed-off-by: Daniel Leung --- include/zephyr/kernel/internal/smp.h | 1 - include/zephyr/kernel/smp.h | 35 +++++++++++++++++ kernel/smp.c | 43 ++++++++++++++++++--- tests/boards/intel_adsp/smoke/src/cpus.c | 3 +- tests/boards/intel_adsp/smoke/src/smpboot.c | 5 +-- tests/kernel/smp_boot_delay/src/main.c | 5 +-- 6 files changed, 78 insertions(+), 14 deletions(-) create mode 100644 include/zephyr/kernel/smp.h diff --git a/include/zephyr/kernel/internal/smp.h b/include/zephyr/kernel/internal/smp.h index d4f70d3c07b..c5d40ddf9f8 100644 --- a/include/zephyr/kernel/internal/smp.h +++ b/include/zephyr/kernel/internal/smp.h @@ -18,6 +18,5 @@ void z_smp_thread_swap(void); void z_init_cpu(int id); void z_sched_ipi(void); -void z_smp_start_cpu(int id); #endif diff --git a/include/zephyr/kernel/smp.h b/include/zephyr/kernel/smp.h new file mode 100644 index 00000000000..1672c58bfa0 --- /dev/null +++ b/include/zephyr/kernel/smp.h @@ -0,0 +1,35 @@ +/* + * Copyright (c) 2023 Intel Corporation + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#ifndef ZEPHYR_INCLUDE_KERNEL_SMP_H_ +#define ZEPHYR_INCLUDE_KERNEL_SMP_H_ + +typedef void (*smp_init_fn)(void *arg); + +/** + * @brief Start a CPU. + * + * This routine is used to manually start the CPU specified + * by @a id. It may be called to restart a CPU that had been + * stopped or powered down, as well as some other scenario. + * After the CPU has finished initialization, the CPU will be + * ready to participate in thread scheduling and execution. + * + * @note This function must not be used on currently running + * CPU. The target CPU must be in off state, or in + * certain architectural state(s) where the CPU is + * permitted to go through the power up process. + * Detection of such state(s) must be provided by + * the platform layers. + * + * @param id ID of target CPU. + * @param fn Function to be called before letting scheduler + * run. + * @param arg Argument to @a fn. + */ +void k_smp_cpu_start(int id, smp_init_fn fn, void *arg); + +#endif /* ZEPHYR_INCLUDE_KERNEL_SMP_H_ */ diff --git a/kernel/smp.c b/kernel/smp.c index dc30bd5f9ed..131fe999ac0 100644 --- a/kernel/smp.c +++ b/kernel/smp.c @@ -4,6 +4,7 @@ #include #include +#include #include #include #include @@ -12,6 +13,23 @@ static atomic_t global_lock; static atomic_t cpu_start_flag; static atomic_t ready_flag; +/** + * Struct holding the function to be called before handing off + * to schedule and its argument. + */ +static struct cpu_start_cb { + /** + * Function to be called before handing off to scheduler. + * Can be NULL. + */ + smp_init_fn fn; + + /** Argument to @ref cpu_start_fn.fn. */ + void *arg; +} cpu_start_fn; + +static struct k_spinlock cpu_start_lock; + unsigned int z_smp_global_lock(void) { unsigned int key = arch_irq_lock(); @@ -80,35 +98,48 @@ void z_smp_thread_swap(void) static inline FUNC_NORETURN void smp_init_top(void *arg) { struct k_thread dummy_thread; + struct cpu_start_cb *csc = arg; (void)atomic_set(&ready_flag, 1); - wait_for_start_signal(arg); + wait_for_start_signal(&cpu_start_flag); z_dummy_thread_init(&dummy_thread); #ifdef CONFIG_SYS_CLOCK_EXISTS smp_timer_init(); #endif + /* Do additional initialization steps if needed. */ + if ((csc != NULL) && (csc->fn != NULL)) { + csc->fn(csc->arg); + } + z_swap_unlocked(); CODE_UNREACHABLE; /* LCOV_EXCL_LINE */ } -static void start_cpu(int id, atomic_t *start_flag) +static void start_cpu(int id, struct cpu_start_cb *csc) { z_init_cpu(id); (void)atomic_clear(&ready_flag); arch_start_cpu(id, z_interrupt_stacks[id], CONFIG_ISR_STACK_SIZE, - smp_init_top, start_flag); + smp_init_top, csc); while (!atomic_get(&ready_flag)) { local_delay(); } } -void z_smp_start_cpu(int id) +void k_smp_cpu_start(int id, smp_init_fn fn, void *arg) { + k_spinlock_key_t key = k_spin_lock(&cpu_start_lock); + + cpu_start_fn.fn = fn; + cpu_start_fn.arg = arg; + (void)atomic_set(&cpu_start_flag, 1); /* async, don't care */ - start_cpu(id, &cpu_start_flag); + start_cpu(id, &cpu_start_fn); + + k_spin_unlock(&cpu_start_lock, key); } void z_smp_init(void) @@ -118,7 +149,7 @@ void z_smp_init(void) unsigned int num_cpus = arch_num_cpus(); for (int i = 1; i < num_cpus; i++) { - start_cpu(i, &cpu_start_flag); + start_cpu(i, NULL); } (void)atomic_set(&cpu_start_flag, 1); } diff --git a/tests/boards/intel_adsp/smoke/src/cpus.c b/tests/boards/intel_adsp/smoke/src/cpus.c index c3852bfb459..2c3f30af513 100644 --- a/tests/boards/intel_adsp/smoke/src/cpus.c +++ b/tests/boards/intel_adsp/smoke/src/cpus.c @@ -3,6 +3,7 @@ */ #include #include +#include #include #include @@ -188,7 +189,7 @@ static void halt_and_restart(int cpu) k_msleep(50); } - z_smp_start_cpu(cpu); + k_smp_cpu_start(cpu, NULL, NULL); /* Startup can be slow */ k_msleep(50); diff --git a/tests/boards/intel_adsp/smoke/src/smpboot.c b/tests/boards/intel_adsp/smoke/src/smpboot.c index bd9aad34be9..c54110e8b2d 100644 --- a/tests/boards/intel_adsp/smoke/src/smpboot.c +++ b/tests/boards/intel_adsp/smoke/src/smpboot.c @@ -3,6 +3,7 @@ */ #include +#include #include #include "tests.h" @@ -25,8 +26,6 @@ volatile bool mp_flag; struct k_thread cpu_thr; K_THREAD_STACK_DEFINE(thr_stack, STACKSZ); -extern void z_smp_start_cpu(int id); - static void thread_fn(void *a, void *b, void *c) { int cpuid = (int) a; @@ -62,7 +61,7 @@ ZTEST(intel_adsp_boot, test_1st_smp_boot_delay) zassert_false(mp_flag, "cpu %d must not be running yet", i); /* Start the second CPU */ - z_smp_start_cpu(i); + k_smp_cpu_start(i, NULL, NULL); /* Verify the thread ran */ k_busy_wait(CPU_START_DELAY); diff --git a/tests/kernel/smp_boot_delay/src/main.c b/tests/kernel/smp_boot_delay/src/main.c index 94df5271770..c4e1d55b073 100644 --- a/tests/kernel/smp_boot_delay/src/main.c +++ b/tests/kernel/smp_boot_delay/src/main.c @@ -3,6 +3,7 @@ */ #include +#include #include /* Experimentally 10ms is enough time to get the second CPU to run on @@ -25,8 +26,6 @@ volatile bool mp_flag; struct k_thread cpu1_thr; K_THREAD_STACK_DEFINE(thr_stack, STACKSZ); -extern void z_smp_start_cpu(int id); - static void thread_fn(void *a, void *b, void *c) { mp_flag = true; @@ -47,7 +46,7 @@ ZTEST(smp_boot_delay, test_smp_boot_delay) zassert_false(mp_flag, "CPU1 must not be running yet"); /* Start the second CPU */ - z_smp_start_cpu(1); + k_smp_cpu_start(1, NULL, NULL); /* Verify the thread ran */ k_busy_wait(CPU_START_DELAY); From fe66e35db00237b894e724b993f43348a4d6473b Mon Sep 17 00:00:00 2001 From: Daniel Leung Date: Thu, 2 Nov 2023 13:23:06 -0700 Subject: [PATCH 2408/3723] kernel: smp: put comment on SMP code Adds some comments to the SMP code to, hopefully, make it a bit more clear to future readers. Signed-off-by: Daniel Leung --- kernel/smp.c | 52 +++++++++++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 51 insertions(+), 1 deletion(-) diff --git a/kernel/smp.c b/kernel/smp.c index 131fe999ac0..7fe4f8503e7 100644 --- a/kernel/smp.c +++ b/kernel/smp.c @@ -10,7 +10,23 @@ #include static atomic_t global_lock; + +/** + * Flag to tell recently powered up CPU to start + * initialization routine. + * + * 0 to tell powered up CPU to wait. + * 1 to tell powered up CPU to continue initialization. + */ static atomic_t cpu_start_flag; + +/** + * Flag to tell caller that the target CPU is now + * powered up and ready to be initialized. + * + * 0 if target CPU is not yet ready. + * 1 if target CPU has powered up and ready to be initialized. + */ static atomic_t ready_flag; /** @@ -100,10 +116,19 @@ static inline FUNC_NORETURN void smp_init_top(void *arg) struct k_thread dummy_thread; struct cpu_start_cb *csc = arg; + /* Let start_cpu() know that this CPU has powered up. */ (void)atomic_set(&ready_flag, 1); + /* Wait for the CPU start caller to signal that + * we can start initialization. + */ wait_for_start_signal(&cpu_start_flag); + + /* Initialize the dummy thread struct so that + * the scheduler can schedule actual threads to run. + */ z_dummy_thread_init(&dummy_thread); + #ifdef CONFIG_SYS_CLOCK_EXISTS smp_timer_init(); #endif @@ -113,6 +138,7 @@ static inline FUNC_NORETURN void smp_init_top(void *arg) csc->fn(csc->arg); } + /* Let scheduler decide what thread to run next. */ z_swap_unlocked(); CODE_UNREACHABLE; /* LCOV_EXCL_LINE */ @@ -120,10 +146,21 @@ static inline FUNC_NORETURN void smp_init_top(void *arg) static void start_cpu(int id, struct cpu_start_cb *csc) { + /* Initialize various CPU structs related to this CPU. */ z_init_cpu(id); + + /* Clear the ready flag so the newly powered up CPU can + * signal that it has powered up. + */ (void)atomic_clear(&ready_flag); + + /* Power up the CPU */ arch_start_cpu(id, z_interrupt_stacks[id], CONFIG_ISR_STACK_SIZE, smp_init_top, csc); + + /* Wait until the newly powered up CPU to signal that + * it has powered up. + */ while (!atomic_get(&ready_flag)) { local_delay(); } @@ -136,7 +173,12 @@ void k_smp_cpu_start(int id, smp_init_fn fn, void *arg) cpu_start_fn.fn = fn; cpu_start_fn.arg = arg; - (void)atomic_set(&cpu_start_flag, 1); /* async, don't care */ + /* We are only starting one CPU so we do not need to synchronize + * across all CPUs using the start_flag. So just set it to 1. + */ + (void)atomic_set(&cpu_start_flag, 1); + + /* Start the CPU! */ start_cpu(id, &cpu_start_fn); k_spin_unlock(&cpu_start_lock, key); @@ -144,13 +186,21 @@ void k_smp_cpu_start(int id, smp_init_fn fn, void *arg) void z_smp_init(void) { + /* We are powering up all CPUs and we want to synchronize their + * entry into scheduler. So set the start flag to 0 here. + */ (void)atomic_clear(&cpu_start_flag); + /* Just start CPUs one by one. */ unsigned int num_cpus = arch_num_cpus(); for (int i = 1; i < num_cpus; i++) { start_cpu(i, NULL); } + + /* Let loose those CPUs so they can start scheduling + * threads to run. + */ (void)atomic_set(&cpu_start_flag, 1); } From eefaeee061c869cfa33be9693ff186ca60f76ff9 Mon Sep 17 00:00:00 2001 From: Daniel Leung Date: Wed, 8 Nov 2023 13:00:43 -0800 Subject: [PATCH 2409/3723] kernel: smp: introduce k_smp_cpu_resume This provides a path to resume a previously suspended CPU. This differs from k_smp_cpu_start() where per-CPU kernel structs are not initialized such that execution context can be saved during suspend and restored during resume. Though the actual context saving and restoring are platform specific. Signed-off-by: Daniel Leung --- include/zephyr/kernel/smp.h | 36 ++++++++++++++++ include/zephyr/sys/arch_interface.h | 2 +- kernel/smp.c | 67 ++++++++++++++++++++++++----- 3 files changed, 94 insertions(+), 11 deletions(-) diff --git a/include/zephyr/kernel/smp.h b/include/zephyr/kernel/smp.h index 1672c58bfa0..883f4820a74 100644 --- a/include/zephyr/kernel/smp.h +++ b/include/zephyr/kernel/smp.h @@ -7,6 +7,8 @@ #ifndef ZEPHYR_INCLUDE_KERNEL_SMP_H_ #define ZEPHYR_INCLUDE_KERNEL_SMP_H_ +#include + typedef void (*smp_init_fn)(void *arg); /** @@ -25,6 +27,11 @@ typedef void (*smp_init_fn)(void *arg); * Detection of such state(s) must be provided by * the platform layers. * + * @note This initializes per-CPU kernel structs and also + * initializes timers needed for MP operations. + * Use @ref k_smp_cpu_resume if these are not + * desired. + * * @param id ID of target CPU. * @param fn Function to be called before letting scheduler * run. @@ -32,4 +39,33 @@ typedef void (*smp_init_fn)(void *arg); */ void k_smp_cpu_start(int id, smp_init_fn fn, void *arg); +/** + * @brief Resume a previously suspended CPU. + * + * This function works like @ref k_smp_cpu_start, but does not + * re-initialize the kernel's internal tracking data for + * the target CPU. Therefore, @ref k_smp_cpu_start must have + * previously been called for the target CPU, and it must have + * verifiably reached an idle/off state (detection of which + * must be provided by the platform layers). It may be used + * in cases where platform layers require, for example, that + * data on the interrupt or idle stack be preserved. + * + * @note This function must not be used on currently running + * CPU. The target CPU must be in suspended state, or + * in certain architectural state(s) where the CPU is + * permitted to go through the resume process. + * Detection of such state(s) must be provided by + * the platform layers. + * + * @param id ID of target CPU. + * @param fn Function to be called before resuming context. + * @param arg Argument to @a fn. + * @param reinit_timer True if timer needs to be re-initialized. + * @param invoke_sched True if scheduler is invoked after the CPU + * has started. + */ +void k_smp_cpu_resume(int id, smp_init_fn fn, void *arg, + bool reinit_timer, bool invoke_sched); + #endif /* ZEPHYR_INCLUDE_KERNEL_SMP_H_ */ diff --git a/include/zephyr/sys/arch_interface.h b/include/zephyr/sys/arch_interface.h index dd5755c1e23..0ffc95c663b 100644 --- a/include/zephyr/sys/arch_interface.h +++ b/include/zephyr/sys/arch_interface.h @@ -216,7 +216,7 @@ void arch_cpu_atomic_idle(unsigned int key); * * @param data context parameter, implementation specific */ -typedef FUNC_NORETURN void (*arch_cpustart_t)(void *data); +typedef void (*arch_cpustart_t)(void *data); /** * @brief Start a numbered CPU on a MP-capable system diff --git a/kernel/smp.c b/kernel/smp.c index 7fe4f8503e7..ff231710e53 100644 --- a/kernel/smp.c +++ b/kernel/smp.c @@ -42,6 +42,14 @@ static struct cpu_start_cb { /** Argument to @ref cpu_start_fn.fn. */ void *arg; + + /** Invoke scheduler after CPU has started if true. */ + bool invoke_sched; + +#ifdef CONFIG_SYS_CLOCK_EXISTS + /** True if smp_timer_init() needs to be called. */ + bool reinit_timer; +#endif } cpu_start_fn; static struct k_spinlock cpu_start_lock; @@ -111,7 +119,7 @@ void z_smp_thread_swap(void) } #endif -static inline FUNC_NORETURN void smp_init_top(void *arg) +static inline void smp_init_top(void *arg) { struct k_thread dummy_thread; struct cpu_start_cb *csc = arg; @@ -124,13 +132,10 @@ static inline FUNC_NORETURN void smp_init_top(void *arg) */ wait_for_start_signal(&cpu_start_flag); - /* Initialize the dummy thread struct so that - * the scheduler can schedule actual threads to run. - */ - z_dummy_thread_init(&dummy_thread); - #ifdef CONFIG_SYS_CLOCK_EXISTS - smp_timer_init(); + if ((csc == NULL) || csc->reinit_timer) { + smp_timer_init(); + } #endif /* Do additional initialization steps if needed. */ @@ -138,6 +143,16 @@ static inline FUNC_NORETURN void smp_init_top(void *arg) csc->fn(csc->arg); } + if ((csc != NULL) && !csc->invoke_sched) { + /* Don't invoke scheduler. */ + return; + } + + /* Initialize the dummy thread struct so that + * the scheduler can schedule actual threads to run. + */ + z_dummy_thread_init(&dummy_thread); + /* Let scheduler decide what thread to run next. */ z_swap_unlocked(); @@ -146,9 +161,6 @@ static inline FUNC_NORETURN void smp_init_top(void *arg) static void start_cpu(int id, struct cpu_start_cb *csc) { - /* Initialize various CPU structs related to this CPU. */ - z_init_cpu(id); - /* Clear the ready flag so the newly powered up CPU can * signal that it has powered up. */ @@ -172,6 +184,40 @@ void k_smp_cpu_start(int id, smp_init_fn fn, void *arg) cpu_start_fn.fn = fn; cpu_start_fn.arg = arg; + cpu_start_fn.invoke_sched = true; + +#ifdef CONFIG_SYS_CLOCK_EXISTS + cpu_start_fn.reinit_timer = true; +#endif + + /* We are only starting one CPU so we do not need to synchronize + * across all CPUs using the start_flag. So just set it to 1. + */ + (void)atomic_set(&cpu_start_flag, 1); /* async, don't care */ + + /* Initialize various CPU structs related to this CPU. */ + z_init_cpu(id); + + /* Start the CPU! */ + start_cpu(id, &cpu_start_fn); + + k_spin_unlock(&cpu_start_lock, key); +} + +void k_smp_cpu_resume(int id, smp_init_fn fn, void *arg, + bool reinit_timer, bool invoke_sched) +{ + k_spinlock_key_t key = k_spin_lock(&cpu_start_lock); + + cpu_start_fn.fn = fn; + cpu_start_fn.arg = arg; + cpu_start_fn.invoke_sched = invoke_sched; + +#ifdef CONFIG_SYS_CLOCK_EXISTS + cpu_start_fn.reinit_timer = reinit_timer; +#else + ARG_UNUSED(reinit_timer); +#endif /* We are only starting one CPU so we do not need to synchronize * across all CPUs using the start_flag. So just set it to 1. @@ -195,6 +241,7 @@ void z_smp_init(void) unsigned int num_cpus = arch_num_cpus(); for (int i = 1; i < num_cpus; i++) { + z_init_cpu(i); start_cpu(i, NULL); } From ea797f28b6645877b0fd83e180a6bbd5ebed409f Mon Sep 17 00:00:00 2001 From: Daniel Leung Date: Thu, 2 Nov 2023 13:50:34 -0700 Subject: [PATCH 2410/3723] tests: smp_boot_delay: extend to test custom CPU start func This extends the smp_boot_delay test to test the newly introduced function k_smp_cpu_custom_start(). Signed-off-by: Daniel Leung --- .../smp_boot_delay/boards/qemu_x86_64.conf | 5 ++ .../smp_boot_delay/boards/qemu_x86_64.overlay | 23 +++++++ tests/kernel/smp_boot_delay/prj.conf | 1 + tests/kernel/smp_boot_delay/src/main.c | 65 +++++++++++++++++-- 4 files changed, 89 insertions(+), 5 deletions(-) create mode 100644 tests/kernel/smp_boot_delay/boards/qemu_x86_64.conf create mode 100644 tests/kernel/smp_boot_delay/boards/qemu_x86_64.overlay diff --git a/tests/kernel/smp_boot_delay/boards/qemu_x86_64.conf b/tests/kernel/smp_boot_delay/boards/qemu_x86_64.conf new file mode 100644 index 00000000000..b4360eba46f --- /dev/null +++ b/tests/kernel/smp_boot_delay/boards/qemu_x86_64.conf @@ -0,0 +1,5 @@ +# Copyright (c) 2023 Intel Corporation +# +# SPDX-License-Identifier: Apache-2.0 + +CONFIG_MP_MAX_NUM_CPUS=4 diff --git a/tests/kernel/smp_boot_delay/boards/qemu_x86_64.overlay b/tests/kernel/smp_boot_delay/boards/qemu_x86_64.overlay new file mode 100644 index 00000000000..0c9b50c57b0 --- /dev/null +++ b/tests/kernel/smp_boot_delay/boards/qemu_x86_64.overlay @@ -0,0 +1,23 @@ +/* + * Copyright (c) 2023 Intel Corporation + * + * SPDX-License-Identifier: Apache-2.0 + */ + +/ { + cpus { + cpu@2 { + device_type = "cpu"; + compatible = "intel,x86"; + d-cache-line-size = <64>; + reg = <2>; + }; + + cpu@3 { + device_type = "cpu"; + compatible = "intel,x86"; + d-cache-line-size = <64>; + reg = <3>; + }; + }; +}; diff --git a/tests/kernel/smp_boot_delay/prj.conf b/tests/kernel/smp_boot_delay/prj.conf index a7c6e63161a..30b23341a23 100644 --- a/tests/kernel/smp_boot_delay/prj.conf +++ b/tests/kernel/smp_boot_delay/prj.conf @@ -1,3 +1,4 @@ CONFIG_ZTEST=y CONFIG_SMP=y CONFIG_SMP_BOOT_DELAY=y +CONFIG_SCHED_CPU_MASK=y diff --git a/tests/kernel/smp_boot_delay/src/main.c b/tests/kernel/smp_boot_delay/src/main.c index c4e1d55b073..4a1e5255915 100644 --- a/tests/kernel/smp_boot_delay/src/main.c +++ b/tests/kernel/smp_boot_delay/src/main.c @@ -23,7 +23,7 @@ char stack[STACKSZ]; volatile bool mp_flag; -struct k_thread cpu1_thr; +struct k_thread cpu_thr; K_THREAD_STACK_DEFINE(thr_stack, STACKSZ); static void thread_fn(void *a, void *b, void *c) @@ -37,7 +37,7 @@ ZTEST(smp_boot_delay, test_smp_boot_delay) * another CPU if it was available, but will not preempt us * unless we block (which we do not). */ - k_thread_create(&cpu1_thr, thr_stack, K_THREAD_STACK_SIZEOF(thr_stack), + k_thread_create(&cpu_thr, thr_stack, K_THREAD_STACK_SIZEOF(thr_stack), thread_fn, NULL, NULL, NULL, 1, 0, K_NO_WAIT); @@ -52,8 +52,8 @@ ZTEST(smp_boot_delay, test_smp_boot_delay) k_busy_wait(CPU_START_DELAY); zassert_true(mp_flag, "CPU1 did not start"); - k_thread_abort(&cpu1_thr); - k_thread_join(&cpu1_thr, K_FOREVER); + k_thread_abort(&cpu_thr); + k_thread_join(&cpu_thr, K_FOREVER); /* Spawn the same thread to do the same thing, but this time * expect that the thread is going to run synchronously on the @@ -61,12 +61,67 @@ ZTEST(smp_boot_delay, test_smp_boot_delay) * IPIs were correctly set up on the runtime-launched CPU. */ mp_flag = false; - k_thread_create(&cpu1_thr, thr_stack, K_THREAD_STACK_SIZEOF(thr_stack), + k_thread_create(&cpu_thr, thr_stack, K_THREAD_STACK_SIZEOF(thr_stack), thread_fn, NULL, NULL, NULL, 1, 0, K_NO_WAIT); k_busy_wait(CPU_IPI_DELAY); + + k_thread_abort(&cpu_thr); + k_thread_join(&cpu_thr, K_FOREVER); + zassert_true(mp_flag, "CPU1 did not start thread via IPI"); } +volatile bool custom_init_flag; + +void custom_init_fn(void *arg) +{ + volatile bool *flag = (void *)arg; + + *flag = true; +} + +ZTEST(smp_boot_delay, test_smp_custom_start) +{ + k_tid_t thr; + + if (CONFIG_MP_MAX_NUM_CPUS <= 2) { + /* CPU#1 has been started in test_smp_boot_delay + * so we need another CPU for this test. + */ + ztest_test_skip(); + } + + mp_flag = false; + custom_init_flag = false; + + /* Create a thread pinned on CPU#2 so that it will not + * run on other CPUs. + */ + thr = k_thread_create(&cpu_thr, thr_stack, K_THREAD_STACK_SIZEOF(thr_stack), + thread_fn, NULL, NULL, NULL, + 1, 0, K_FOREVER); + (void)k_thread_cpu_pin(thr, 2); + k_thread_start(thr); + + /* Make sure that thread has not run (because the cpu is halted) */ + k_busy_wait(CPU_START_DELAY); + zassert_false(mp_flag, "CPU2 must not be running yet"); + + /* Start the third CPU */ + k_smp_cpu_start(2, custom_init_fn, (void *)&custom_init_flag); + + /* Verify the thread ran */ + k_busy_wait(CPU_START_DELAY); + zassert_true(mp_flag, "CPU2 did not start"); + + /* Verify that the custom init function has been called. */ + zassert_true(custom_init_flag, "Custom init function has not been called."); + + k_thread_abort(&cpu_thr); + k_thread_join(&cpu_thr, K_FOREVER); +} + + ZTEST_SUITE(smp_boot_delay, NULL, NULL, NULL, NULL, NULL); From f7bd449c523e7064f78228c034fce67e22bdf567 Mon Sep 17 00:00:00 2001 From: Daniel Leung Date: Fri, 3 Nov 2023 12:03:15 -0700 Subject: [PATCH 2411/3723] modules: sof: use k_smp_cpu_custom_start for core power up This updates the SOF to use the newly introduced k_smp_cpu_custom_start() for secondary core power up. This removes the need to mirror part of the SMP power up code from Zephyr kernel into SOF tree. Also removes the need to expose private kernel code to SOF. Signed-off-by: Daniel Leung --- submanifests/optional.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/submanifests/optional.yaml b/submanifests/optional.yaml index 9cdec6d60c4..13584b2437e 100644 --- a/submanifests/optional.yaml +++ b/submanifests/optional.yaml @@ -34,7 +34,7 @@ manifest: groups: - optional - name: sof - revision: e7cb489d430dc2181e4a5f7f953ed1eaeec6668d + revision: 37dd5e62663fcedca659c2104043529b3855a1b0 path: modules/audio/sof remote: upstream groups: From 35a1814c4d3eaac62c12072f0b4cc6d7245b6bbc Mon Sep 17 00:00:00 2001 From: Daniel Leung Date: Fri, 3 Nov 2023 12:06:42 -0700 Subject: [PATCH 2412/3723] kernel: smp: remove z_smp_thread_init/_swap This removes z_smp_thread_init() and z_smp_thread_swap() as SOF has been updated to use k_smp_cpu_custom_start() instead. This removes the need for SOF to mirror part of the SMP power up code, and thus these two functions are no longer needed. Signed-off-by: Daniel Leung --- include/zephyr/kernel/internal/smp.h | 10 ---------- kernel/smp.c | 13 ------------- 2 files changed, 23 deletions(-) diff --git a/include/zephyr/kernel/internal/smp.h b/include/zephyr/kernel/internal/smp.h index c5d40ddf9f8..58576201329 100644 --- a/include/zephyr/kernel/internal/smp.h +++ b/include/zephyr/kernel/internal/smp.h @@ -6,16 +6,6 @@ #ifndef ZEPHYR_INCLUDE_KERNEL_INTERNAL_SMP_H_ #define ZEPHYR_INCLUDE_KERNEL_INTERNAL_SMP_H_ -struct k_thread; - -/** - * @internal - */ -#ifdef CONFIG_SOF -void z_smp_thread_init(void *arg, struct k_thread *thread); -void z_smp_thread_swap(void); -#endif - void z_init_cpu(int id); void z_sched_ipi(void); diff --git a/kernel/smp.c b/kernel/smp.c index ff231710e53..45ec956dff9 100644 --- a/kernel/smp.c +++ b/kernel/smp.c @@ -106,19 +106,6 @@ static void wait_for_start_signal(atomic_t *start_flag) } } -/* Legacy interfaces for early-version SOF CPU bringup. To be removed */ -#ifdef CONFIG_SOF -void z_smp_thread_init(void *arg, struct k_thread *thread) -{ - z_dummy_thread_init(thread); - wait_for_start_signal(arg); -} -void z_smp_thread_swap(void) -{ - z_swap_unlocked(); -} -#endif - static inline void smp_init_top(void *arg) { struct k_thread dummy_thread; From 2cdd44801e8136198a09d18f3db286ade96824fd Mon Sep 17 00:00:00 2001 From: Daniel Leung Date: Wed, 15 Nov 2023 12:32:53 -0800 Subject: [PATCH 2413/3723] kernel: move z_init_cpu to private kernel headers z_init_cpu() is a private kernel API so move it under kernel/include. Signed-off-by: Daniel Leung --- include/zephyr/kernel/internal/smp.h | 1 - kernel/include/kernel_internal.h | 3 +++ 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/include/zephyr/kernel/internal/smp.h b/include/zephyr/kernel/internal/smp.h index 58576201329..e2b3ae15aec 100644 --- a/include/zephyr/kernel/internal/smp.h +++ b/include/zephyr/kernel/internal/smp.h @@ -6,7 +6,6 @@ #ifndef ZEPHYR_INCLUDE_KERNEL_INTERNAL_SMP_H_ #define ZEPHYR_INCLUDE_KERNEL_INTERNAL_SMP_H_ -void z_init_cpu(int id); void z_sched_ipi(void); #endif diff --git a/kernel/include/kernel_internal.h b/kernel/include/kernel_internal.h index 711313b5ce7..16efb3b54e8 100644 --- a/kernel/include/kernel_internal.h +++ b/kernel/include/kernel_internal.h @@ -24,6 +24,9 @@ extern "C" { #endif +/* Initialize per-CPU kernel data */ +void z_init_cpu(int id); + /* Initialize a thread */ void z_init_thread_base(struct _thread_base *thread_base, int priority, uint32_t initial_state, unsigned int options); From 6a0b1da158a4f8bc5f2ca5058637dce26a38660e Mon Sep 17 00:00:00 2001 From: Rander Wang Date: Fri, 17 Nov 2023 15:45:36 +0800 Subject: [PATCH 2414/3723] soc: intel_adsp: call framework callback function for restore When exiting power gated state, call the CPU start function passed to arch_start_cpu(). Signed-off-by: Rander Wang Signed-off-by: Daniel Leung --- soc/xtensa/intel_adsp/ace/power.c | 6 ++++++ soc/xtensa/intel_adsp/cavs/power.c | 6 ++++++ soc/xtensa/intel_adsp/common/multiprocessing.c | 5 +++++ 3 files changed, 17 insertions(+) diff --git a/soc/xtensa/intel_adsp/ace/power.c b/soc/xtensa/intel_adsp/ace/power.c index e35443d4cf8..4ef8575645a 100644 --- a/soc/xtensa/intel_adsp/ace/power.c +++ b/soc/xtensa/intel_adsp/ace/power.c @@ -150,6 +150,7 @@ static ALWAYS_INLINE void _restore_core_context(void) } void dsp_restore_vector(void); +void mp_resume_entry(void); void power_gate_entry(uint32_t core_id) { @@ -180,6 +181,11 @@ void power_gate_exit(void) cpu_early_init(); sys_cache_data_flush_and_invd_all(); _restore_core_context(); + + /* Secondary core is resumed by set_dx */ + if (arch_proc_id()) { + mp_resume_entry(); + } } __asm__(".align 4\n\t" diff --git a/soc/xtensa/intel_adsp/cavs/power.c b/soc/xtensa/intel_adsp/cavs/power.c index c0a75f5c0ec..3ae758ced61 100644 --- a/soc/xtensa/intel_adsp/cavs/power.c +++ b/soc/xtensa/intel_adsp/cavs/power.c @@ -52,6 +52,7 @@ LOG_MODULE_REGISTER(soc); * @biref FW entry point called by ROM during normal boot flow */ extern void rom_entry(void); +void mp_resume_entry(void); struct core_state { uint32_t a0; @@ -104,6 +105,11 @@ void power_gate_exit(void) cpu_early_init(); sys_cache_data_flush_and_invd_all(); _restore_core_context(); + + /* Secondary core is resumed by set_dx */ + if (arch_proc_id()) { + mp_resume_entry(); + } } __asm__(".align 4\n\t" diff --git a/soc/xtensa/intel_adsp/common/multiprocessing.c b/soc/xtensa/intel_adsp/common/multiprocessing.c index de76fa37eac..79d7d1883e0 100644 --- a/soc/xtensa/intel_adsp/common/multiprocessing.c +++ b/soc/xtensa/intel_adsp/common/multiprocessing.c @@ -110,6 +110,11 @@ __imr void z_mp_entry(void) __ASSERT(false, "arch_start_cpu() handler should never return"); } +void mp_resume_entry(void) +{ + start_rec.fn(start_rec.arg); +} + bool arch_cpu_active(int cpu_num) { return soc_cpus_active[cpu_num]; From 476e7b3fa33fe6d99f83b665635ccf8cad3cb4dd Mon Sep 17 00:00:00 2001 From: Emil Gydesen Date: Mon, 8 Jan 2024 14:38:01 +0100 Subject: [PATCH 2415/3723] Bluetooth: Audio: Ensure that read callbacks can handle conn == NULL The read callbacks may be called with conn == NULL if the device does a local read of the attributes. This commit ensures that all the read callbacks can handle the case where conn == NULL. Signed-off-by: Emil Gydesen --- include/zephyr/bluetooth/audio/pacs.h | 1 + subsys/bluetooth/audio/csip_set_member.c | 4 + subsys/bluetooth/audio/mcs.c | 219 +++++++++++++---------- subsys/bluetooth/audio/pacs.c | 76 ++++---- 4 files changed, 173 insertions(+), 127 deletions(-) diff --git a/include/zephyr/bluetooth/audio/pacs.h b/include/zephyr/bluetooth/audio/pacs.h index 6e0dcec4514..6db4d34b0a2 100644 --- a/include/zephyr/bluetooth/audio/pacs.h +++ b/include/zephyr/bluetooth/audio/pacs.h @@ -126,6 +126,7 @@ int bt_pacs_conn_set_available_contexts_for_conn(struct bt_conn *conn, enum bt_a * @param dir Direction of the endpoints to get contexts for. * * @return Bitmask of available contexts. + * @retval BT_AUDIO_CONTEXT_TYPE_PROHIBITED if @p conn or @p dir are invalid */ enum bt_audio_context bt_pacs_get_available_contexts_for_conn(struct bt_conn *conn, enum bt_audio_dir dir); diff --git a/subsys/bluetooth/audio/csip_set_member.c b/subsys/bluetooth/audio/csip_set_member.c index b6bd487af82..d738cf05f4c 100644 --- a/subsys/bluetooth/audio/csip_set_member.c +++ b/subsys/bluetooth/audio/csip_set_member.c @@ -235,6 +235,10 @@ static int sirk_encrypt(struct bt_conn *conn, LOG_DBG("Encrypting test SIRK"); k = test_k; } else { + if (conn == NULL) { + return -EINVAL; + } + k = conn->le.keys->ltk.val; } diff --git a/subsys/bluetooth/audio/mcs.c b/subsys/bluetooth/audio/mcs.c index 3d31af7a828..271ea690ad7 100644 --- a/subsys/bluetooth/audio/mcs.c +++ b/subsys/bluetooth/audio/mcs.c @@ -89,15 +89,18 @@ static ssize_t read_player_name(struct bt_conn *conn, const struct bt_gatt_attr *attr, void *buf, uint16_t len, uint16_t offset) { - struct client_state *client = &clients[bt_conn_index(conn)]; const char *name = media_proxy_sctrl_get_player_name(); LOG_DBG("Player name read: %s (offset %u)", name, offset); - if (offset == 0) { - atomic_clear_bit(client->flags, FLAG_PLAYER_NAME_CHANGED); - } else if (atomic_test_bit(client->flags, FLAG_PLAYER_NAME_CHANGED)) { - return BT_GATT_ERR(BT_MCS_ERR_LONG_VAL_CHANGED); + if (conn != NULL) { + struct client_state *client = &clients[bt_conn_index(conn)]; + + if (offset == 0) { + atomic_clear_bit(client->flags, FLAG_PLAYER_NAME_CHANGED); + } else if (atomic_test_bit(client->flags, FLAG_PLAYER_NAME_CHANGED)) { + return BT_GATT_ERR(BT_MCS_ERR_LONG_VAL_CHANGED); + } } return bt_gatt_attr_read(conn, attr, buf, len, offset, name, @@ -131,15 +134,18 @@ static ssize_t read_icon_url(struct bt_conn *conn, const struct bt_gatt_attr *attr, void *buf, uint16_t len, uint16_t offset) { - struct client_state *client = &clients[bt_conn_index(conn)]; const char *url = media_proxy_sctrl_get_icon_url(); LOG_DBG("Icon URL read, offset: %d, len:%d, URL: %s", offset, len, url); - if (offset == 0) { - atomic_clear_bit(client->flags, FLAG_ICON_URL_CHANGED); - } else if (atomic_test_bit(client->flags, FLAG_ICON_URL_CHANGED)) { - return BT_GATT_ERR(BT_MCS_ERR_LONG_VAL_CHANGED); + if (conn != NULL) { + struct client_state *client = &clients[bt_conn_index(conn)]; + + if (offset == 0) { + atomic_clear_bit(client->flags, FLAG_ICON_URL_CHANGED); + } else if (atomic_test_bit(client->flags, FLAG_ICON_URL_CHANGED)) { + return BT_GATT_ERR(BT_MCS_ERR_LONG_VAL_CHANGED); + } } return bt_gatt_attr_read(conn, attr, buf, len, offset, url, @@ -155,15 +161,18 @@ static ssize_t read_track_title(struct bt_conn *conn, const struct bt_gatt_attr *attr, void *buf, uint16_t len, uint16_t offset) { - struct client_state *client = &clients[bt_conn_index(conn)]; const char *title = media_proxy_sctrl_get_track_title(); LOG_DBG("Track title read, offset: %d, len:%d, title: %s", offset, len, title); - if (offset == 0) { - atomic_clear_bit(client->flags, FLAG_TRACK_TITLE_CHANGED); - } else if (atomic_test_bit(client->flags, FLAG_TRACK_TITLE_CHANGED)) { - return BT_GATT_ERR(BT_MCS_ERR_LONG_VAL_CHANGED); + if (conn != NULL) { + struct client_state *client = &clients[bt_conn_index(conn)]; + + if (offset == 0) { + atomic_clear_bit(client->flags, FLAG_TRACK_TITLE_CHANGED); + } else if (atomic_test_bit(client->flags, FLAG_TRACK_TITLE_CHANGED)) { + return BT_GATT_ERR(BT_MCS_ERR_LONG_VAL_CHANGED); + } } return bt_gatt_attr_read(conn, attr, buf, len, offset, title, @@ -180,35 +189,38 @@ static ssize_t read_track_duration(struct bt_conn *conn, const struct bt_gatt_attr *attr, void *buf, uint16_t len, uint16_t offset) { - struct client_state *client = &clients[bt_conn_index(conn)]; int32_t duration = media_proxy_sctrl_get_track_duration(); int32_t duration_le = sys_cpu_to_le32(duration); LOG_DBG("Track duration read: %d (0x%08x)", duration, duration); - atomic_clear_bit(client->flags, FLAG_TRACK_DURATION_CHANGED); + if (conn != NULL) { + struct client_state *client = &clients[bt_conn_index(conn)]; + + atomic_clear_bit(client->flags, FLAG_TRACK_DURATION_CHANGED); + } - return bt_gatt_attr_read(conn, attr, buf, len, offset, &duration_le, - sizeof(duration_le)); + return bt_gatt_attr_read(conn, attr, buf, len, offset, &duration_le, sizeof(duration_le)); } -static void track_duration_cfg_changed(const struct bt_gatt_attr *attr, - uint16_t value) +static void track_duration_cfg_changed(const struct bt_gatt_attr *attr, uint16_t value) { LOG_DBG("value 0x%04x", value); } -static ssize_t read_track_position(struct bt_conn *conn, - const struct bt_gatt_attr *attr, void *buf, +static ssize_t read_track_position(struct bt_conn *conn, const struct bt_gatt_attr *attr, void *buf, uint16_t len, uint16_t offset) { - struct client_state *client = &clients[bt_conn_index(conn)]; int32_t position = media_proxy_sctrl_get_track_position(); int32_t position_le = sys_cpu_to_le32(position); LOG_DBG("Track position read: %d (0x%08x)", position, position); - atomic_clear_bit(client->flags, FLAG_TRACK_POSITION_CHANGED); + if (conn != NULL) { + struct client_state *client = &clients[bt_conn_index(conn)]; + + atomic_clear_bit(client->flags, FLAG_TRACK_POSITION_CHANGED); + } return bt_gatt_attr_read(conn, attr, buf, len, offset, &position_le, sizeof(position_le)); @@ -248,21 +260,21 @@ static ssize_t read_playback_speed(struct bt_conn *conn, const struct bt_gatt_attr *attr, void *buf, uint16_t len, uint16_t offset) { - struct client_state *client = &clients[bt_conn_index(conn)]; int8_t speed = media_proxy_sctrl_get_playback_speed(); LOG_DBG("Playback speed read: %d", speed); - atomic_clear_bit(client->flags, FLAG_PLAYBACK_SPEED_CHANGED); + if (conn != NULL) { + struct client_state *client = &clients[bt_conn_index(conn)]; - return bt_gatt_attr_read(conn, attr, buf, len, offset, &speed, - sizeof(speed)); + atomic_clear_bit(client->flags, FLAG_PLAYBACK_SPEED_CHANGED); + } + + return bt_gatt_attr_read(conn, attr, buf, len, offset, &speed, sizeof(speed)); } -static ssize_t write_playback_speed(struct bt_conn *conn, - const struct bt_gatt_attr *attr, - const void *buf, uint16_t len, uint16_t offset, - uint8_t flags) +static ssize_t write_playback_speed(struct bt_conn *conn, const struct bt_gatt_attr *attr, + const void *buf, uint16_t len, uint16_t offset, uint8_t flags) { int8_t speed; @@ -282,22 +294,23 @@ static ssize_t write_playback_speed(struct bt_conn *conn, return len; } -static void playback_speed_cfg_changed(const struct bt_gatt_attr *attr, - uint16_t value) +static void playback_speed_cfg_changed(const struct bt_gatt_attr *attr, uint16_t value) { LOG_DBG("value 0x%04x", value); } -static ssize_t read_seeking_speed(struct bt_conn *conn, - const struct bt_gatt_attr *attr, void *buf, +static ssize_t read_seeking_speed(struct bt_conn *conn, const struct bt_gatt_attr *attr, void *buf, uint16_t len, uint16_t offset) { - struct client_state *client = &clients[bt_conn_index(conn)]; int8_t speed = media_proxy_sctrl_get_seeking_speed(); LOG_DBG("Seeking speed read: %d", speed); - atomic_clear_bit(client->flags, FLAG_SEEKING_SPEED_CHANGED); + if (conn != NULL) { + struct client_state *client = &clients[bt_conn_index(conn)]; + + atomic_clear_bit(client->flags, FLAG_SEEKING_SPEED_CHANGED); + } return bt_gatt_attr_read(conn, attr, buf, len, offset, &speed, sizeof(speed)); @@ -329,7 +342,6 @@ static ssize_t read_current_track_id(struct bt_conn *conn, const struct bt_gatt_attr *attr, void *buf, uint16_t len, uint16_t offset) { - struct client_state *client = &clients[bt_conn_index(conn)]; uint64_t track_id = media_proxy_sctrl_get_current_track_id(); uint8_t track_id_le[BT_OTS_OBJ_ID_SIZE]; @@ -337,7 +349,11 @@ static ssize_t read_current_track_id(struct bt_conn *conn, LOG_DBG_OBJ_ID("Current track ID read: ", track_id); - atomic_clear_bit(client->flags, FLAG_CURRENT_TRACK_OBJ_ID_CHANGED); + if (conn != NULL) { + struct client_state *client = &clients[bt_conn_index(conn)]; + + atomic_clear_bit(client->flags, FLAG_CURRENT_TRACK_OBJ_ID_CHANGED); + } return bt_gatt_attr_read(conn, attr, buf, len, offset, track_id_le, sizeof(track_id_le)); @@ -383,13 +399,16 @@ static ssize_t read_next_track_id(struct bt_conn *conn, const struct bt_gatt_attr *attr, void *buf, uint16_t len, uint16_t offset) { - struct client_state *client = &clients[bt_conn_index(conn)]; uint64_t track_id = media_proxy_sctrl_get_next_track_id(); uint8_t track_id_le[BT_OTS_OBJ_ID_SIZE]; sys_put_le48(track_id, track_id_le); - atomic_clear_bit(client->flags, FLAG_NEXT_TRACK_OBJ_ID_CHANGED); + if (conn != NULL) { + struct client_state *client = &clients[bt_conn_index(conn)]; + + atomic_clear_bit(client->flags, FLAG_NEXT_TRACK_OBJ_ID_CHANGED); + } if (track_id == MPL_NO_TRACK_ID) { LOG_DBG("Next track read, but it is empty"); @@ -443,7 +462,6 @@ static ssize_t read_parent_group_id(struct bt_conn *conn, const struct bt_gatt_attr *attr, void *buf, uint16_t len, uint16_t offset) { - struct client_state *client = &clients[bt_conn_index(conn)]; uint64_t group_id = media_proxy_sctrl_get_parent_group_id(); uint8_t group_id_le[BT_OTS_OBJ_ID_SIZE]; @@ -451,7 +469,11 @@ static ssize_t read_parent_group_id(struct bt_conn *conn, LOG_DBG_OBJ_ID("Parent group read: ", group_id); - atomic_clear_bit(client->flags, FLAG_PARENT_GROUP_OBJ_ID_CHANGED); + if (conn != NULL) { + struct client_state *client = &clients[bt_conn_index(conn)]; + + atomic_clear_bit(client->flags, FLAG_PARENT_GROUP_OBJ_ID_CHANGED); + } return bt_gatt_attr_read(conn, attr, buf, len, offset, group_id_le, sizeof(group_id_le)); @@ -467,7 +489,6 @@ static ssize_t read_current_group_id(struct bt_conn *conn, const struct bt_gatt_attr *attr, void *buf, uint16_t len, uint16_t offset) { - struct client_state *client = &clients[bt_conn_index(conn)]; uint64_t group_id = media_proxy_sctrl_get_current_group_id(); uint8_t group_id_le[BT_OTS_OBJ_ID_SIZE]; @@ -475,7 +496,11 @@ static ssize_t read_current_group_id(struct bt_conn *conn, LOG_DBG_OBJ_ID("Current group read: ", group_id); - atomic_clear_bit(client->flags, FLAG_CURRENT_GROUP_OBJ_ID_CHANGED); + if (conn != NULL) { + struct client_state *client = &clients[bt_conn_index(conn)]; + + atomic_clear_bit(client->flags, FLAG_CURRENT_GROUP_OBJ_ID_CHANGED); + } return bt_gatt_attr_read(conn, attr, buf, len, offset, group_id_le, sizeof(group_id_le)); @@ -522,21 +547,21 @@ static ssize_t read_playing_order(struct bt_conn *conn, const struct bt_gatt_attr *attr, void *buf, uint16_t len, uint16_t offset) { - struct client_state *client = &clients[bt_conn_index(conn)]; uint8_t order = media_proxy_sctrl_get_playing_order(); LOG_DBG("Playing order read: %d (0x%02x)", order, order); - atomic_clear_bit(client->flags, FLAG_PLAYING_ORDER_CHANGED); + if (conn != NULL) { + struct client_state *client = &clients[bt_conn_index(conn)]; - return bt_gatt_attr_read(conn, attr, buf, len, offset, &order, - sizeof(order)); + atomic_clear_bit(client->flags, FLAG_PLAYING_ORDER_CHANGED); + } + + return bt_gatt_attr_read(conn, attr, buf, len, offset, &order, sizeof(order)); } -static ssize_t write_playing_order(struct bt_conn *conn, - const struct bt_gatt_attr *attr, - const void *buf, uint16_t len, uint16_t offset, - uint8_t flags) +static ssize_t write_playing_order(struct bt_conn *conn, const struct bt_gatt_attr *attr, + const void *buf, uint16_t len, uint16_t offset, uint8_t flags) { LOG_DBG("Playing order write"); @@ -558,14 +583,12 @@ static ssize_t write_playing_order(struct bt_conn *conn, return len; } -static void playing_order_cfg_changed(const struct bt_gatt_attr *attr, - uint16_t value) +static void playing_order_cfg_changed(const struct bt_gatt_attr *attr, uint16_t value) { LOG_DBG("value 0x%04x", value); } -static ssize_t read_playing_orders_supported(struct bt_conn *conn, - const struct bt_gatt_attr *attr, +static ssize_t read_playing_orders_supported(struct bt_conn *conn, const struct bt_gatt_attr *attr, void *buf, uint16_t len, uint16_t offset) { uint16_t orders = media_proxy_sctrl_get_playing_orders_supported(); @@ -573,20 +596,21 @@ static ssize_t read_playing_orders_supported(struct bt_conn *conn, LOG_DBG("Playing orders read: %d (0x%04x)", orders, orders); - return bt_gatt_attr_read(conn, attr, buf, len, offset, &orders_le, - sizeof(orders_le)); + return bt_gatt_attr_read(conn, attr, buf, len, offset, &orders_le, sizeof(orders_le)); } -static ssize_t read_media_state(struct bt_conn *conn, - const struct bt_gatt_attr *attr, void *buf, +static ssize_t read_media_state(struct bt_conn *conn, const struct bt_gatt_attr *attr, void *buf, uint16_t len, uint16_t offset) { - struct client_state *client = &clients[bt_conn_index(conn)]; uint8_t state = media_proxy_sctrl_get_media_state(); LOG_DBG("Media state read: %d", state); - atomic_clear_bit(client->flags, FLAG_MEDIA_STATE_CHANGED); + if (conn != NULL) { + struct client_state *client = &clients[bt_conn_index(conn)]; + + atomic_clear_bit(client->flags, FLAG_MEDIA_STATE_CHANGED); + } return bt_gatt_attr_read(conn, attr, buf, len, offset, &state, sizeof(state)); @@ -603,7 +627,6 @@ static ssize_t write_control_point(struct bt_conn *conn, const void *buf, uint16_t len, uint16_t offset, uint8_t flags) { - struct client_state *client = &clients[bt_conn_index(conn)]; struct mpl_cmd command; if (offset != 0) { @@ -632,17 +655,23 @@ static ssize_t write_control_point(struct bt_conn *conn, notify(BT_UUID_MCS_MEDIA_CONTROL_POINT, &cmd_ntf, sizeof(cmd_ntf)); return BT_GATT_ERR(BT_ATT_ERR_VALUE_NOT_ALLOWED); - } else if (atomic_test_and_set_bit(client->flags, FLAG_MEDIA_CONTROL_POINT_BUSY)) { - const struct mpl_cmd_ntf cmd_ntf = { - .requested_opcode = command.opcode, - .result_code = BT_MCS_OPC_NTF_CANNOT_BE_COMPLETED, - }; + } - LOG_DBG("Busy with other operation"); + if (conn != NULL) { + struct client_state *client = &clients[bt_conn_index(conn)]; - notify(BT_UUID_MCS_MEDIA_CONTROL_POINT, &cmd_ntf, sizeof(cmd_ntf)); + if (atomic_test_and_set_bit(client->flags, FLAG_MEDIA_CONTROL_POINT_BUSY)) { + const struct mpl_cmd_ntf cmd_ntf = { + .requested_opcode = command.opcode, + .result_code = BT_MCS_OPC_NTF_CANNOT_BE_COMPLETED, + }; + + LOG_DBG("Busy with other operation"); + + notify(BT_UUID_MCS_MEDIA_CONTROL_POINT, &cmd_ntf, sizeof(cmd_ntf)); - return BT_GATT_ERR(BT_ATT_ERR_PROCEDURE_IN_PROGRESS); + return BT_GATT_ERR(BT_ATT_ERR_PROCEDURE_IN_PROGRESS); + } } if (len == sizeof(command.opcode) + sizeof(command.param)) { @@ -666,31 +695,30 @@ static ssize_t read_opcodes_supported(struct bt_conn *conn, const struct bt_gatt_attr *attr, void *buf, uint16_t len, uint16_t offset) { - struct client_state *client = &clients[bt_conn_index(conn)]; uint32_t opcodes = media_proxy_sctrl_get_commands_supported(); uint32_t opcodes_le = sys_cpu_to_le32(opcodes); LOG_DBG("Opcodes_supported read: %d (0x%08x)", opcodes, opcodes); - atomic_clear_bit(client->flags, FLAG_MEDIA_CONTROL_OPCODES_CHANGED); + if (conn != NULL) { + struct client_state *client = &clients[bt_conn_index(conn)]; - return bt_gatt_attr_read(conn, attr, buf, len, offset, - &opcodes_le, sizeof(opcodes_le)); + atomic_clear_bit(client->flags, FLAG_MEDIA_CONTROL_OPCODES_CHANGED); + } + + return bt_gatt_attr_read(conn, attr, buf, len, offset, &opcodes_le, sizeof(opcodes_le)); } -static void opcodes_supported_cfg_changed(const struct bt_gatt_attr *attr, - uint16_t value) +static void opcodes_supported_cfg_changed(const struct bt_gatt_attr *attr, uint16_t value) { LOG_DBG("value 0x%04x", value); } #ifdef CONFIG_BT_OTS -static ssize_t write_search_control_point(struct bt_conn *conn, - const struct bt_gatt_attr *attr, - const void *buf, uint16_t len, - uint16_t offset, uint8_t flags) +static ssize_t write_search_control_point(struct bt_conn *conn, const struct bt_gatt_attr *attr, + const void *buf, uint16_t len, uint16_t offset, + uint8_t flags) { - struct client_state *client = &clients[bt_conn_index(conn)]; struct mpl_search search = {0}; if (offset != 0) { @@ -701,14 +729,18 @@ static ssize_t write_search_control_point(struct bt_conn *conn, return BT_GATT_ERR(BT_ATT_ERR_INVALID_ATTRIBUTE_LEN); } - if (atomic_test_and_set_bit(client->flags, FLAG_SEARCH_CONTROL_POINT_BUSY)) { - const uint8_t result_code = BT_MCS_SCP_NTF_FAILURE; + if (conn != NULL) { + struct client_state *client = &clients[bt_conn_index(conn)]; - LOG_DBG("Busy with other operation"); + if (atomic_test_and_set_bit(client->flags, FLAG_SEARCH_CONTROL_POINT_BUSY)) { + const uint8_t result_code = BT_MCS_SCP_NTF_FAILURE; - notify(BT_UUID_MCS_SEARCH_CONTROL_POINT, &result_code, sizeof(result_code)); + LOG_DBG("Busy with other operation"); + + notify(BT_UUID_MCS_SEARCH_CONTROL_POINT, &result_code, sizeof(result_code)); - return BT_GATT_ERR(BT_ATT_ERR_PROCEDURE_IN_PROGRESS); + return BT_GATT_ERR(BT_ATT_ERR_PROCEDURE_IN_PROGRESS); + } } memcpy(&search.search, (char *)buf, len); @@ -731,12 +763,15 @@ static ssize_t read_search_results_id(struct bt_conn *conn, const struct bt_gatt_attr *attr, void *buf, uint16_t len, uint16_t offset) { - struct client_state *client = &clients[bt_conn_index(conn)]; uint64_t search_id = media_proxy_sctrl_get_search_results_id(); LOG_DBG_OBJ_ID("Search results id read: ", search_id); - atomic_clear_bit(client->flags, FLAG_SEARCH_RESULTS_OBJ_ID_CHANGED); + if (conn != NULL) { + struct client_state *client = &clients[bt_conn_index(conn)]; + + atomic_clear_bit(client->flags, FLAG_SEARCH_RESULTS_OBJ_ID_CHANGED); + } /* TODO: The permanent solution here should be that the call to */ /* mpl should fill the UUID in a pointed-to value, and return a */ diff --git a/subsys/bluetooth/audio/pacs.c b/subsys/bluetooth/audio/pacs.c index 6f32774d9f9..64f750523ff 100644 --- a/subsys/bluetooth/audio/pacs.c +++ b/subsys/bluetooth/audio/pacs.c @@ -199,15 +199,46 @@ static void available_context_cfg_changed(const struct bt_gatt_attr *attr, uint1 LOG_DBG("attr %p value 0x%04x", attr, value); } +static enum bt_audio_context pacs_get_available_contexts_for_conn(struct bt_conn *conn, + enum bt_audio_dir dir) +{ + const struct pacs_client *client; + + client = client_lookup_conn(conn); + if (client == NULL) { + LOG_DBG("No client context for conn %p", (void *)conn); + return bt_pacs_get_available_contexts(dir); + } + + switch (dir) { + case BT_AUDIO_DIR_SINK: +#if defined(CONFIG_BT_PAC_SNK) + if (client->snk_available_contexts != NULL) { + return POINTER_TO_UINT(client->snk_available_contexts); + } +#endif /* CONFIG_BT_PAC_SNK */ + break; + case BT_AUDIO_DIR_SOURCE: +#if defined(CONFIG_BT_PAC_SRC) + if (client->src_available_contexts != NULL) { + return POINTER_TO_UINT(client->src_available_contexts); + } +#endif /* CONFIG_BT_PAC_SRC */ + break; + } + + return bt_pacs_get_available_contexts(dir); +} + static ssize_t available_contexts_read(struct bt_conn *conn, const struct bt_gatt_attr *attr, void *buf, uint16_t len, uint16_t offset) { struct bt_pacs_context context = { .snk = sys_cpu_to_le16( - bt_pacs_get_available_contexts_for_conn(conn, BT_AUDIO_DIR_SINK)), + pacs_get_available_contexts_for_conn(conn, BT_AUDIO_DIR_SINK)), .src = sys_cpu_to_le16( - bt_pacs_get_available_contexts_for_conn(conn, BT_AUDIO_DIR_SOURCE)), + pacs_get_available_contexts_for_conn(conn, BT_AUDIO_DIR_SOURCE)), }; LOG_DBG("conn %p attr %p buf %p len %u offset %u", conn, attr, buf, len, offset); @@ -718,9 +749,9 @@ static int available_contexts_notify(struct bt_conn *conn) { struct bt_pacs_context context = { .snk = sys_cpu_to_le16( - bt_pacs_get_available_contexts_for_conn(conn, BT_AUDIO_DIR_SINK)), + pacs_get_available_contexts_for_conn(conn, BT_AUDIO_DIR_SINK)), .src = sys_cpu_to_le16( - bt_pacs_get_available_contexts_for_conn(conn, BT_AUDIO_DIR_SOURCE)), + pacs_get_available_contexts_for_conn(conn, BT_AUDIO_DIR_SOURCE)), }; int err; @@ -971,7 +1002,7 @@ static void pacs_disconnected(struct bt_conn *conn, uint8_t reason) uint16_t new; client->snk_available_contexts = NULL; - new = bt_pacs_get_available_contexts_for_conn(conn, BT_AUDIO_DIR_SINK); + new = pacs_get_available_contexts_for_conn(conn, BT_AUDIO_DIR_SINK); atomic_set_bit_to(client->flags, FLAG_AVAILABLE_AUDIO_CONTEXT_CHANGED, old != new); } @@ -983,7 +1014,7 @@ static void pacs_disconnected(struct bt_conn *conn, uint8_t reason) uint16_t new; client->src_available_contexts = NULL; - new = bt_pacs_get_available_contexts_for_conn(conn, BT_AUDIO_DIR_SOURCE); + new = pacs_get_available_contexts_for_conn(conn, BT_AUDIO_DIR_SOURCE); atomic_set_bit_to(client->flags, FLAG_AVAILABLE_AUDIO_CONTEXT_CHANGED, old != new); } @@ -1152,7 +1183,7 @@ int bt_pacs_set_available_contexts(enum bt_audio_dir dir, enum bt_audio_context int bt_pacs_conn_set_available_contexts_for_conn(struct bt_conn *conn, enum bt_audio_dir dir, enum bt_audio_context *contexts) { - enum bt_audio_context old = bt_pacs_get_available_contexts_for_conn(conn, dir); + enum bt_audio_context old = pacs_get_available_contexts_for_conn(conn, dir); struct bt_conn_info info = { 0 }; struct pacs_client *client; int err; @@ -1193,7 +1224,7 @@ int bt_pacs_conn_set_available_contexts_for_conn(struct bt_conn *conn, enum bt_a return -EINVAL; } - if (bt_pacs_get_available_contexts_for_conn(conn, dir) == old) { + if (pacs_get_available_contexts_for_conn(conn, dir) == old) { /* No change. Skip notification */ return 0; } @@ -1254,35 +1285,10 @@ enum bt_audio_context bt_pacs_get_available_contexts(enum bt_audio_dir dir) enum bt_audio_context bt_pacs_get_available_contexts_for_conn(struct bt_conn *conn, enum bt_audio_dir dir) { - const struct pacs_client *client; - CHECKIF(conn == NULL) { LOG_ERR("NULL conn"); - return -EINVAL; - } - - client = client_lookup_conn(conn); - if (client == NULL) { - LOG_ERR("No client context for conn %p", (void *)conn); - return bt_pacs_get_available_contexts(dir); + return BT_AUDIO_CONTEXT_TYPE_PROHIBITED; } - switch (dir) { - case BT_AUDIO_DIR_SINK: -#if defined(CONFIG_BT_PAC_SNK) - if (client->snk_available_contexts != NULL) { - return POINTER_TO_UINT(client->snk_available_contexts); - } -#endif /* CONFIG_BT_PAC_SNK */ - break; - case BT_AUDIO_DIR_SOURCE: -#if defined(CONFIG_BT_PAC_SRC) - if (client->src_available_contexts != NULL) { - return POINTER_TO_UINT(client->src_available_contexts); - } -#endif /* CONFIG_BT_PAC_SRC */ - break; - } - - return bt_pacs_get_available_contexts(dir); + return pacs_get_available_contexts_for_conn(conn, dir); } From 1faa5a2aa2a2c134f21e4a7dc62a374eaa5d7664 Mon Sep 17 00:00:00 2001 From: Emil Gydesen Date: Mon, 8 Jan 2024 12:03:29 +0100 Subject: [PATCH 2416/3723] Bluetooth: BAP: Add support for transparent coding format Add support for controlling whether the local controller should transcode, or whether it will be done by another module (e.g. the host). By default when using the macros, controller transcoding will be disabled. Signed-off-by: Emil Gydesen --- include/zephyr/bluetooth/audio/audio.h | 14 ++++++++++++++ subsys/bluetooth/audio/bap_stream.c | 22 ++++++++++++++++------ 2 files changed, 30 insertions(+), 6 deletions(-) diff --git a/include/zephyr/bluetooth/audio/audio.h b/include/zephyr/bluetooth/audio/audio.h index bb9c8d7eade..94311060512 100644 --- a/include/zephyr/bluetooth/audio/audio.h +++ b/include/zephyr/bluetooth/audio/audio.h @@ -209,6 +209,7 @@ enum bt_audio_metadata_type { ((struct bt_audio_codec_cfg){ \ /* Use HCI data path as default, can be overwritten by application */ \ .path_id = BT_ISO_DATA_PATH_HCI, \ + .ctlr_transcode = false, \ .id = _id, \ .cid = _cid, \ .vid = _vid, \ @@ -231,6 +232,7 @@ enum bt_audio_metadata_type { ((struct bt_audio_codec_cap){ \ /* Use HCI data path as default, can be overwritten by application */ \ .path_id = BT_ISO_DATA_PATH_HCI, \ + .ctlr_transcode = false, \ .id = (_id), \ .cid = (_cid), \ .vid = (_vid), \ @@ -316,6 +318,12 @@ struct bt_audio_codec_cap { * vendor specific ID. */ uint8_t path_id; + /** Whether or not the local controller should transcode + * + * This effectively sets the coding format for the ISO data path to @ref + * BT_HCI_CODING_FORMAT_TRANSPARENT if false, else uses the @ref bt_audio_codec_cfg.id. + */ + bool ctlr_transcode; /** Codec ID */ uint8_t id; /** Codec Company ID */ @@ -344,6 +352,12 @@ struct bt_audio_codec_cfg { * vendor specific ID. */ uint8_t path_id; + /** Whether or not the local controller should transcode + * + * This effectively sets the coding format for the ISO data path to @ref + * BT_HCI_CODING_FORMAT_TRANSPARENT if false, else uses the @ref bt_audio_codec_cfg.id. + */ + bool ctlr_transcode; /** Codec ID */ uint8_t id; /** Codec Company ID */ diff --git a/subsys/bluetooth/audio/bap_stream.c b/subsys/bluetooth/audio/bap_stream.c index ab27b32d237..2fc4b00bdbf 100644 --- a/subsys/bluetooth/audio/bap_stream.c +++ b/subsys/bluetooth/audio/bap_stream.c @@ -35,12 +35,22 @@ void bt_audio_codec_cfg_to_iso_path(struct bt_iso_chan_path *path, struct bt_audio_codec_cfg *codec_cfg) { path->pid = codec_cfg->path_id; - path->format = codec_cfg->id; - path->cid = codec_cfg->cid; - path->vid = codec_cfg->vid; - path->delay = 0; /* TODO: Add to bt_audio_codec_cfg? Use presentation delay? */ - path->cc_len = codec_cfg->data_len; - path->cc = codec_cfg->data; + + if (codec_cfg->ctlr_transcode) { + path->format = codec_cfg->id; + path->cid = codec_cfg->cid; + path->vid = codec_cfg->vid; + path->delay = 0; + path->cc_len = codec_cfg->data_len; + path->cc = codec_cfg->data; + } else { + path->format = BT_HCI_CODING_FORMAT_TRANSPARENT; + path->cid = 0; + path->vid = 0; + path->delay = 0; + path->cc_len = 0; + path->cc = NULL; + } } #if defined(CONFIG_BT_BAP_UNICAST_CLIENT) || defined(CONFIG_BT_BAP_BROADCAST_SOURCE) || \ From 09a3483b4e2a7063ad15ae0100b7fe283889314a Mon Sep 17 00:00:00 2001 From: Emil Gydesen Date: Wed, 3 Jan 2024 10:12:36 +0100 Subject: [PATCH 2417/3723] Bluetooth: Audio: Fix coverity for BT_AUDIO_METADATA_TYPE_IS_KNOWN Coverity is unhappy about using IN_RANGE ending with BT_AUDIO_METADATA_TYPE_VENDOR on uint8_t values, as uint8_t values are always <= 255. Fixed by modifying it into a specific value check which is also slightly more efficient. Signed-off-by: Emil Gydesen --- include/zephyr/bluetooth/audio/audio.h | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) diff --git a/include/zephyr/bluetooth/audio/audio.h b/include/zephyr/bluetooth/audio/audio.h index 94311060512..f6885c41a83 100644 --- a/include/zephyr/bluetooth/audio/audio.h +++ b/include/zephyr/bluetooth/audio/audio.h @@ -174,12 +174,14 @@ enum bt_audio_metadata_type { }; /** - * Helper to check whether metadata type is known by the stack. + * @brief Helper to check whether metadata type is known by the stack. + * + * @note @p _type is evaluated thrice. */ -#define BT_AUDIO_METADATA_TYPE_IS_KNOWN(_type) \ - (IN_RANGE(_type, BT_AUDIO_METADATA_TYPE_PREF_CONTEXT, \ - BT_AUDIO_METADATA_TYPE_BROADCAST_IMMEDIATE) || \ - IN_RANGE(_type, BT_AUDIO_METADATA_TYPE_EXTENDED, BT_AUDIO_METADATA_TYPE_VENDOR)) +#define BT_AUDIO_METADATA_TYPE_IS_KNOWN(_type) \ + (IN_RANGE((_type), BT_AUDIO_METADATA_TYPE_PREF_CONTEXT, \ + BT_AUDIO_METADATA_TYPE_BROADCAST_IMMEDIATE) || \ + (_type) == BT_AUDIO_METADATA_TYPE_EXTENDED || (_type) == BT_AUDIO_METADATA_TYPE_VENDOR) /* Unicast Announcement Type, Generic Audio */ #define BT_AUDIO_UNICAST_ANNOUNCEMENT_GENERAL 0x00 From b09ce2fade481e95cd859765e5aebda4b626599b Mon Sep 17 00:00:00 2001 From: Emil Gydesen Date: Wed, 15 Nov 2023 10:24:54 +0100 Subject: [PATCH 2418/3723] Bluetooth: CAP: Commander set volume support Add support for setting volume on one or more CAP acceptors using the CAP Commander API. Signed-off-by: Emil Gydesen --- include/zephyr/bluetooth/audio/cap.h | 40 ++- subsys/bluetooth/audio/cap_commander.c | 247 +++++++++++++++++- subsys/bluetooth/audio/cap_common.c | 45 +++- subsys/bluetooth/audio/cap_initiator.c | 10 +- subsys/bluetooth/audio/cap_internal.h | 24 +- .../audio/cap_commander/uut/CMakeLists.txt | 1 + tests/bluetooth/audio/cap_commander/uut/vcp.c | 45 ++++ 7 files changed, 397 insertions(+), 15 deletions(-) create mode 100644 tests/bluetooth/audio/cap_commander/uut/vcp.c diff --git a/include/zephyr/bluetooth/audio/cap.h b/include/zephyr/bluetooth/audio/cap.h index 19aa1e4092b..a9370251d3d 100644 --- a/include/zephyr/bluetooth/audio/cap.h +++ b/include/zephyr/bluetooth/audio/cap.h @@ -317,7 +317,7 @@ int bt_cap_initiator_unicast_audio_stop(struct bt_bap_unicast_group *unicast_gro * This will stop the current procedure from continuing and making it possible to run a new * Common Audio Profile procedure. * - * It is recommended to do this if any existing procedure take longer time than expected, which + * It is recommended to do this if any existing procedure takes longer time than expected, which * could indicate a missing response from the Common Audio Profile Acceptor. * * This does not send any requests to any Common Audio Profile Acceptors involved with the current @@ -655,6 +655,20 @@ struct bt_cap_commander_cb { */ void (*discovery_complete)(struct bt_conn *conn, int err, const struct bt_csip_set_coordinator_csis_inst *csis_inst); + +#if defined(CONFIG_BT_VCP_VOL_CTLR) + /** + * @brief Callback for bt_cap_commander_change_volume(). + * + * @param conn Pointer to the connection where the error + * occurred. NULL if @p err is 0 or if cancelled by + * bt_cap_commander_cancel() + * @param err 0 on success, BT_GATT_ERR() with a + * specific ATT (BT_ATT_ERR_*) error code or -ECANCELED if cancelled + * by bt_cap_commander_cancel(). + */ + void (*volume_changed)(struct bt_conn *conn, int err); +#endif /* CONFIG_BT_VCP_VOL_CTLR */ }; /** @@ -698,6 +712,30 @@ int bt_cap_commander_unregister_cb(const struct bt_cap_commander_cb *cb); */ int bt_cap_commander_discover(struct bt_conn *conn); +/** @brief Cancel any current Common Audio Profile commander procedure + * + * This will stop the current procedure from continuing and making it possible to run a new + * Common Audio Profile procedure. + * + * It is recommended to do this if any existing procedure takes longer time than expected, which + * could indicate a missing response from the Common Audio Profile Acceptor. + * + * This does not send any requests to any Common Audio Profile Acceptors involved with the current + * procedure, and thus notifications from the Common Audio Profile Acceptors may arrive after this + * has been called. It is thus recommended to either only use this if a procedure has stalled, or + * wait a short while before starting any new Common Audio Profile procedure after this has been + * called to avoid getting notifications from the cancelled procedure. The wait time depends on + * the connection interval, the number of devices in the previous procedure and the behavior of the + * Common Audio Profile Acceptors. + * + * The respective callbacks of the procedure will be called as part of this with the connection + * pointer set to NULL and the err value set to -ECANCELED. + * + * @retval 0 on success + * @retval -EALREADY if no procedure is active + */ +int bt_cap_commander_cancel(void); + struct bt_cap_commander_broadcast_reception_start_member_param { /** Coordinated or ad-hoc set member. */ union bt_cap_set_member member; diff --git a/subsys/bluetooth/audio/cap_commander.c b/subsys/bluetooth/audio/cap_commander.c index 611cf1fcacf..27346b822f7 100644 --- a/subsys/bluetooth/audio/cap_commander.c +++ b/subsys/bluetooth/audio/cap_commander.c @@ -8,7 +8,7 @@ #include #include #include -#include +#include #include "cap_internal.h" #include "ccid_internal.h" #include "csip_internal.h" @@ -86,10 +86,252 @@ int bt_cap_commander_broadcast_reception_stop( { return -ENOSYS; } +static void cap_commander_unicast_audio_proc_complete(void) +{ + struct bt_cap_common_proc *active_proc = bt_cap_common_get_active_proc(); + enum bt_cap_common_proc_type proc_type; + struct bt_conn *failed_conn; + int err; + + failed_conn = active_proc->failed_conn; + err = active_proc->err; + proc_type = active_proc->proc_type; + bt_cap_common_clear_active_proc(); + + if (cap_cb == NULL) { + return; + } + + switch (proc_type) { +#if defined(CONFIG_BT_VCP_VOL_CTLR) + case BT_CAP_COMMON_PROC_TYPE_VOLUME_CHANGE: + if (cap_cb->volume_changed != NULL) { + cap_cb->volume_changed(failed_conn, err); + } + break; +#endif /* CONFIG_BT_VCP_VOL_CTLR */ + case BT_CAP_COMMON_PROC_TYPE_NONE: + default: + __ASSERT(false, "Invalid proc_type: %u", proc_type); + } +} + +int bt_cap_commander_cancel(void) +{ + if (!bt_cap_common_proc_is_active() && !bt_cap_common_proc_is_aborted()) { + LOG_DBG("No CAP procedure is in progress"); + + return -EALREADY; + } + + bt_cap_common_abort_proc(NULL, -ECANCELED); + cap_commander_unicast_audio_proc_complete(); + + return 0; +} + +#if defined(CONFIG_BT_VCP_VOL_CTLR) +static bool valid_change_volume_param(const struct bt_cap_commander_change_volume_param *param) +{ + CHECKIF(param == NULL) { + LOG_DBG("param is NULL"); + return false; + } + + CHECKIF(param->count == 0) { + LOG_DBG("Invalid param->count: %u", param->count); + return false; + } + + CHECKIF(param->members == NULL) { + LOG_DBG("param->members is NULL"); + return false; + } + + CHECKIF(param->count > CONFIG_BT_MAX_CONN) { + LOG_DBG("param->count (%zu) is larger than CONFIG_BT_MAX_CONN (%d)", param->count, + CONFIG_BT_MAX_CONN); + return false; + } + + for (size_t i = 0U; i < param->count; i++) { + const union bt_cap_set_member *member = ¶m->members[i]; + struct bt_cap_common_client *client = NULL; + + if (param->type == BT_CAP_SET_TYPE_AD_HOC) { + + CHECKIF(member->member == NULL) { + LOG_DBG("param->members[%zu].member is NULL", i); + return false; + } + + client = bt_cap_common_get_client_by_acl(member->member); + if (client == NULL || !client->cas_found) { + LOG_DBG("CAS was not found for param->members[%zu]", i); + return false; + } + } else if (param->type == BT_CAP_SET_TYPE_CSIP) { + CHECKIF(member->csip == NULL) { + LOG_DBG("param->members[%zu].csip is NULL", i); + return false; + } + + client = bt_cap_common_get_client_by_csis(member->csip); + if (client == NULL) { + LOG_DBG("CSIS was not found for param->members[%zu]", i); + return false; + } + } + + if (client == NULL || !client->cas_found) { + LOG_DBG("CAS was not found for param->members[%zu]", i); + return false; + } + + if (bt_vcp_vol_ctlr_get_by_conn(client->conn) == NULL) { + LOG_DBG("Volume control not available for param->members[%zu]", i); + return false; + } + + for (size_t j = 0U; j < i; j++) { + const union bt_cap_set_member *other = ¶m->members[j]; + + if (other == member) { + LOG_DBG("param->members[%zu] (%p) is duplicated by " + "param->members[%zu] (%p)", + j, other, i, member); + return false; + } + } + } + + return true; +} + +static void cap_commander_vcp_vol_set_cb(struct bt_vcp_vol_ctlr *vol_ctlr, int err) +{ + struct bt_cap_common_proc *active_proc = bt_cap_common_get_active_proc(); + struct bt_conn *conn; + int vcp_err; + + LOG_DBG("vol_ctlr %p", (void *)vol_ctlr); + + vcp_err = bt_vcp_vol_ctlr_conn_get(vol_ctlr, &conn); + if (vcp_err != 0) { + LOG_ERR("Failed to get conn by vol_ctrl: %d", vcp_err); + return; + } + + LOG_DBG("conn %p", (void *)conn); + if (!bt_cap_common_conn_in_active_proc(conn)) { + /* State change happened outside of a procedure; ignore */ + return; + } + + if (err != 0) { + LOG_DBG("Failed to set volume: %d", err); + bt_cap_common_abort_proc(conn, err); + } else { + active_proc->proc_done_cnt++; + + LOG_DBG("Conn %p volume updated (%zu/%zu streams done)", (void *)conn, + active_proc->proc_done_cnt, active_proc->proc_cnt); + } + + if (bt_cap_common_proc_is_aborted()) { + LOG_DBG("Proc is aborted"); + if (bt_cap_common_proc_all_handled()) { + LOG_DBG("All handled"); + cap_commander_unicast_audio_proc_complete(); + } + + return; + } + + if (!bt_cap_common_proc_is_done()) { + const struct bt_cap_commander_proc_param *proc_param; + + proc_param = &active_proc->proc_param.commander[active_proc->proc_done_cnt]; + conn = proc_param->conn; + err = bt_vcp_vol_ctlr_set_vol(bt_vcp_vol_ctlr_get_by_conn(conn), + proc_param->change_volume.volume); + if (err != 0) { + LOG_DBG("Failed to set volume for conn %p: %d", (void *)conn, err); + bt_cap_common_abort_proc(conn, err); + cap_commander_unicast_audio_proc_complete(); + } else { + active_proc->proc_initiated_cnt++; + } + } else { + cap_commander_unicast_audio_proc_complete(); + } +} int bt_cap_commander_change_volume(const struct bt_cap_commander_change_volume_param *param) { - return -ENOSYS; + const struct bt_cap_commander_proc_param *proc_param; + static struct bt_vcp_vol_ctlr_cb vol_ctlr_cb = { + .vol_set = cap_commander_vcp_vol_set_cb, + }; + struct bt_cap_common_proc *active_proc; + static bool cb_registered; + struct bt_conn *conn; + int err; + + if (bt_cap_common_proc_is_active()) { + LOG_DBG("A CAP procedure is already in progress"); + + return -EBUSY; + } + + if (!valid_change_volume_param(param)) { + return -EINVAL; + } + + bt_cap_common_start_proc(BT_CAP_COMMON_PROC_TYPE_VOLUME_CHANGE, param->count); + + if (!cb_registered) { + /* Ensure that ops are registered before any procedures are started */ + err = bt_vcp_vol_ctlr_cb_register(&vol_ctlr_cb); + if (err != 0) { + LOG_DBG("Failed to register VCP callbacks: %d", err); + + return -ENOEXEC; + } + + cb_registered = true; + } + + active_proc = bt_cap_common_get_active_proc(); + + for (size_t i = 0U; i < param->count; i++) { + struct bt_conn *member_conn = + bt_cap_common_get_member_conn(param->type, ¶m->members[i]); + + if (member_conn == NULL) { + LOG_DBG("Invalid param->members[%zu]", i); + return -EINVAL; + } + + /* Store the necessary parameters as we cannot assume that the supplied parameters + * are kept valid + */ + active_proc->proc_param.commander[i].conn = member_conn; + active_proc->proc_param.commander[i].change_volume.volume = param->volume; + } + + proc_param = &active_proc->proc_param.commander[0]; + conn = proc_param->conn; + err = bt_vcp_vol_ctlr_set_vol(bt_vcp_vol_ctlr_get_by_conn(conn), + proc_param->change_volume.volume); + if (err != 0) { + LOG_DBG("Failed to set volume for conn %p: %d", (void *)conn, err); + return -ENOEXEC; + } + + active_proc->proc_initiated_cnt++; + + return 0; } int bt_cap_commander_change_volume_offset( @@ -103,6 +345,7 @@ int bt_cap_commander_change_volume_mute_state( { return -ENOSYS; } +#endif /* CONFIG_BT_VCP_VOL_CTLR */ int bt_cap_commander_change_microphone_mute_state( const struct bt_cap_commander_change_microphone_mute_state_param *param) diff --git a/subsys/bluetooth/audio/cap_common.c b/subsys/bluetooth/audio/cap_common.c index b341dcfc0d8..62ffbc7b874 100644 --- a/subsys/bluetooth/audio/cap_common.c +++ b/subsys/bluetooth/audio/cap_common.c @@ -51,6 +51,24 @@ bool bt_cap_common_subproc_is_type(enum bt_cap_common_subproc_type subproc_type) } #endif /* CONFIG_BT_CAP_INITIATOR_UNICAST */ +struct bt_conn *bt_cap_common_get_member_conn(enum bt_cap_set_type type, + union bt_cap_set_member *member) +{ + if (type == BT_CAP_SET_TYPE_CSIP) { + struct bt_cap_common_client *client; + + /* We have verified that `client` won't be NULL in + * `valid_change_volume_param`. + */ + client = bt_cap_common_get_client_by_csis(member->csip); + if (client != NULL) { + return client->conn; + } + } + + return member->member; +} + bool bt_cap_common_proc_is_active(void) { return atomic_test_bit(active_proc.proc_state_flags, BT_CAP_COMMON_PROC_STATE_ACTIVE); @@ -61,7 +79,7 @@ bool bt_cap_common_proc_is_aborted(void) return atomic_test_bit(active_proc.proc_state_flags, BT_CAP_COMMON_PROC_STATE_ABORTED); } -bool bt_cap_common_proc_all_streams_handled(void) +bool bt_cap_common_proc_all_handled(void) { return active_proc.proc_done_cnt == active_proc.proc_initiated_cnt; } @@ -97,21 +115,40 @@ static bool active_proc_is_initiator(void) } #endif /* CONFIG_BT_CAP_INITIATOR_UNICAST */ +#if defined(CONFIG_BT_CAP_COMMANDER) +static bool active_proc_is_commander(void) +{ + switch (active_proc.proc_type) { + case BT_CAP_COMMON_PROC_TYPE_VOLUME_CHANGE: + return true; + default: + return false; + } +} +#endif /* CONFIG_BT_CAP_INITIATOR_UNICAST */ + bool bt_cap_common_conn_in_active_proc(const struct bt_conn *conn) { if (!bt_cap_common_proc_is_active()) { return false; } + for (size_t i = 0U; i < active_proc.proc_initiated_cnt; i++) { #if defined(CONFIG_BT_CAP_INITIATOR_UNICAST) - if (active_proc_is_initiator()) { - for (size_t i = 0U; i < active_proc.proc_initiated_cnt; i++) { + if (active_proc_is_initiator()) { if (active_proc.proc_param.initiator[i].stream->bap_stream.conn == conn) { return true; } } - } #endif /* CONFIG_BT_CAP_INITIATOR_UNICAST */ +#if defined(CONFIG_BT_CAP_COMMANDER) + if (active_proc_is_commander()) { + if (active_proc.proc_param.commander[i].conn == conn) { + return true; + } + } +#endif /* CONFIG_BT_CAP_INITIATOR_UNICAST */ + } return false; } diff --git a/subsys/bluetooth/audio/cap_initiator.c b/subsys/bluetooth/audio/cap_initiator.c index 2b171548af2..79fb9faf44d 100644 --- a/subsys/bluetooth/audio/cap_initiator.c +++ b/subsys/bluetooth/audio/cap_initiator.c @@ -624,7 +624,7 @@ void bt_cap_initiator_codec_configured(struct bt_cap_stream *cap_stream) } if (bt_cap_common_proc_is_aborted()) { - if (bt_cap_common_proc_all_streams_handled()) { + if (bt_cap_common_proc_all_handled()) { cap_initiator_unicast_audio_proc_complete(); } @@ -757,7 +757,7 @@ void bt_cap_initiator_qos_configured(struct bt_cap_stream *cap_stream) } if (bt_cap_common_proc_is_aborted()) { - if (bt_cap_common_proc_all_streams_handled()) { + if (bt_cap_common_proc_all_handled()) { cap_initiator_unicast_audio_proc_complete(); } @@ -813,7 +813,7 @@ void bt_cap_initiator_enabled(struct bt_cap_stream *cap_stream) } if (bt_cap_common_proc_is_aborted()) { - if (bt_cap_common_proc_all_streams_handled()) { + if (bt_cap_common_proc_all_handled()) { cap_initiator_unicast_audio_proc_complete(); } @@ -1058,7 +1058,7 @@ void bt_cap_initiator_metadata_updated(struct bt_cap_stream *cap_stream) } if (bt_cap_common_proc_is_aborted()) { - if (bt_cap_common_proc_all_streams_handled()) { + if (bt_cap_common_proc_all_handled()) { cap_initiator_unicast_audio_proc_complete(); } @@ -1202,7 +1202,7 @@ void bt_cap_initiator_released(struct bt_cap_stream *cap_stream) } if (bt_cap_common_proc_is_aborted()) { - if (bt_cap_common_proc_all_streams_handled()) { + if (bt_cap_common_proc_all_handled()) { cap_initiator_unicast_audio_proc_complete(); } diff --git a/subsys/bluetooth/audio/cap_internal.h b/subsys/bluetooth/audio/cap_internal.h index 8823b3da2bb..4c833a1d8e5 100644 --- a/subsys/bluetooth/audio/cap_internal.h +++ b/subsys/bluetooth/audio/cap_internal.h @@ -36,6 +36,7 @@ enum bt_cap_common_proc_type { BT_CAP_COMMON_PROC_TYPE_START, BT_CAP_COMMON_PROC_TYPE_UPDATE, BT_CAP_COMMON_PROC_TYPE_STOP, + BT_CAP_COMMON_PROC_TYPE_VOLUME_CHANGE, }; enum bt_cap_common_subproc_type { @@ -65,13 +66,28 @@ struct bt_cap_initiator_proc_param { }; }; +struct bt_cap_commander_proc_param { + struct bt_conn *conn; + union { +#if defined(CONFIG_BT_VCP_VOL_CTLR) + struct { + uint8_t volume; + } change_volume; +#endif /* CONFIG_BT_VCP_VOL_CTLR */ + + /* TODO Add other procedures */ + }; +}; + struct bt_cap_common_proc_param { union { #if defined(CONFIG_BT_CAP_INITIATOR_UNICAST) struct bt_cap_initiator_proc_param initiator[CONFIG_BT_BAP_UNICAST_CLIENT_GROUP_STREAM_COUNT]; -#endif /* CONFIG_BT_CAP_INITIATOR_UNICAST */ - /* TODO: Add commander_proc_param struct */ +#endif /* CONFIG_BT_CAP_INITIATOR_UNICAST */ +#if defined(CONFIG_BT_CAP_COMMANDER) + struct bt_cap_commander_proc_param commander[CONFIG_BT_MAX_CONN]; +#endif /* CONFIG_BT_CAP_COMMANDER */ }; }; @@ -106,9 +122,11 @@ void bt_cap_common_clear_active_proc(void); void bt_cap_common_start_proc(enum bt_cap_common_proc_type proc_type, size_t proc_cnt); void bt_cap_common_set_subproc(enum bt_cap_common_subproc_type subproc_type); bool bt_cap_common_subproc_is_type(enum bt_cap_common_subproc_type subproc_type); +struct bt_conn *bt_cap_common_get_member_conn(enum bt_cap_set_type type, + union bt_cap_set_member *member); bool bt_cap_common_proc_is_active(void); bool bt_cap_common_proc_is_aborted(void); -bool bt_cap_common_proc_all_streams_handled(void); +bool bt_cap_common_proc_all_handled(void); bool bt_cap_common_proc_is_done(void); void bt_cap_common_abort_proc(struct bt_conn *conn, int err); bool bt_cap_common_conn_in_active_proc(const struct bt_conn *conn); diff --git a/tests/bluetooth/audio/cap_commander/uut/CMakeLists.txt b/tests/bluetooth/audio/cap_commander/uut/CMakeLists.txt index 8dc2539f682..8a0774a3182 100644 --- a/tests/bluetooth/audio/cap_commander/uut/CMakeLists.txt +++ b/tests/bluetooth/audio/cap_commander/uut/CMakeLists.txt @@ -12,6 +12,7 @@ add_library(uut STATIC ${ZEPHYR_BASE}/subsys/logging/log_minimal.c ${ZEPHYR_BASE}/subsys/net/buf_simple.c csip.c + vcp.c ) add_subdirectory(${ZEPHYR_BASE}/tests/bluetooth/audio/mocks mocks) diff --git a/tests/bluetooth/audio/cap_commander/uut/vcp.c b/tests/bluetooth/audio/cap_commander/uut/vcp.c new file mode 100644 index 00000000000..a031a8be0de --- /dev/null +++ b/tests/bluetooth/audio/cap_commander/uut/vcp.c @@ -0,0 +1,45 @@ +/* csip.c - CAP Commander specific VCP mocks */ + +/* + * Copyright (c) 2023 Nordic Semiconductor ASA + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include + +static struct bt_vcp_vol_ctlr_cb *vcp_cb; + +static struct bt_vcp_vol_ctlr { + struct bt_conn *conn; +} vol_ctlrs[CONFIG_BT_MAX_CONN]; + +struct bt_vcp_vol_ctlr *bt_vcp_vol_ctlr_get_by_conn(const struct bt_conn *conn) +{ + for (size_t i = 0; i < ARRAY_SIZE(vol_ctlrs); i++) { + if (vol_ctlrs[i].conn == conn) { + return &vol_ctlrs[i]; + } + } + + return NULL; +} + +int bt_vcp_vol_ctlr_conn_get(const struct bt_vcp_vol_ctlr *vol_ctlr, struct bt_conn **conn) +{ + *conn = vol_ctlr->conn; + + return 0; +} + +int bt_vcp_vol_ctlr_set_vol(struct bt_vcp_vol_ctlr *vol_ctlr, uint8_t volume) +{ + if (vcp_cb->vol_set != NULL) { + vcp_cb->vol_set(vol_ctlr, 0); + } +} + +int bt_vcp_vol_ctlr_cb_register(struct bt_vcp_vol_ctlr_cb *cb) +{ + vcp_cb = cb; +} From c999e4600d6cd67f4e92df87ca7d3cad89560c48 Mon Sep 17 00:00:00 2001 From: Emil Gydesen Date: Wed, 22 Nov 2023 14:54:06 +0100 Subject: [PATCH 2419/3723] tests: Bluetooth: CAP: Add test of change volume procedure Add testing of the CAP Commander Change Volume procedure in BSIM. Signed-off-by: Emil Gydesen --- tests/bsim/bluetooth/audio/prj.conf | 1 + .../bluetooth/audio/src/cap_acceptor_test.c | 47 ++++++- .../bluetooth/audio/src/cap_commander_test.c | 116 ++++++++++++++++-- 3 files changed, 153 insertions(+), 11 deletions(-) diff --git a/tests/bsim/bluetooth/audio/prj.conf b/tests/bsim/bluetooth/audio/prj.conf index e3510c63b18..9414077e031 100644 --- a/tests/bsim/bluetooth/audio/prj.conf +++ b/tests/bsim/bluetooth/audio/prj.conf @@ -190,6 +190,7 @@ CONFIG_BT_HAS_LOG_LEVEL_DBG=y CONFIG_BT_HAS_CLIENT_LOG_LEVEL_DBG=y CONFIG_BT_CAP_ACCEPTOR_LOG_LEVEL_DBG=y CONFIG_BT_CAP_INITIATOR_LOG_LEVEL_DBG=y +CONFIG_BT_CAP_COMMANDER_LOG_LEVEL_DBG=y CONFIG_BT_GMAP_LOG_LEVEL_DBG=y # LOGGING diff --git a/tests/bsim/bluetooth/audio/src/cap_acceptor_test.c b/tests/bsim/bluetooth/audio/src/cap_acceptor_test.c index ccb9eaed8c4..1082a52ea66 100644 --- a/tests/bsim/bluetooth/audio/src/cap_acceptor_test.c +++ b/tests/bsim/bluetooth/audio/src/cap_acceptor_test.c @@ -10,6 +10,7 @@ #include #include #include +#include #include #include "common.h" #include "bap_common.h" @@ -650,9 +651,49 @@ static void init(void) } } - set_supported_contexts(); - set_available_contexts(); - set_location(); + if (IS_ENABLED(CONFIG_BT_PACS)) { + set_supported_contexts(); + set_available_contexts(); + set_location(); + } + + if (IS_ENABLED(CONFIG_BT_VCP_VOL_REND)) { + char output_desc[CONFIG_BT_VCP_VOL_REND_VOCS_INSTANCE_COUNT][16]; + char input_desc[CONFIG_BT_VCP_VOL_REND_AICS_INSTANCE_COUNT][16]; + struct bt_vcp_vol_rend_register_param vcp_param = {0}; + + for (size_t i = 0U; i < ARRAY_SIZE(vcp_param.vocs_param); i++) { + vcp_param.vocs_param[i].location_writable = true; + vcp_param.vocs_param[i].desc_writable = true; + snprintf(output_desc[i], sizeof(output_desc[i]), "Output %d", i + 1); + vcp_param.vocs_param[i].output_desc = output_desc[i]; + vcp_param.vocs_param[i].cb = NULL; + } + + for (size_t i = 0U; i < ARRAY_SIZE(vcp_param.aics_param); i++) { + vcp_param.aics_param[i].desc_writable = true; + snprintf(input_desc[i], sizeof(input_desc[i]), "Input %d", i + 1); + vcp_param.aics_param[i].description = input_desc[i]; + vcp_param.aics_param[i].type = BT_AICS_INPUT_TYPE_DIGITAL; + vcp_param.aics_param[i].status = true; + vcp_param.aics_param[i].gain_mode = BT_AICS_MODE_MANUAL; + vcp_param.aics_param[i].units = 1; + vcp_param.aics_param[i].min_gain = 0; + vcp_param.aics_param[i].max_gain = 100; + vcp_param.aics_param[i].cb = NULL; + } + + vcp_param.step = 1; + vcp_param.mute = BT_VCP_STATE_UNMUTED; + vcp_param.volume = 100; + vcp_param.cb = NULL; + err = bt_vcp_vol_rend_register(&vcp_param); + if (err != 0) { + FAIL("Failed to register VCS (err %d)\n", err); + + return; + } + } } static void test_cap_acceptor_unicast(void) diff --git a/tests/bsim/bluetooth/audio/src/cap_commander_test.c b/tests/bsim/bluetooth/audio/src/cap_commander_test.c index 794ffe5d7dd..e45b93bd333 100644 --- a/tests/bsim/bluetooth/audio/src/cap_commander_test.c +++ b/tests/bsim/bluetooth/audio/src/cap_commander_test.c @@ -10,7 +10,7 @@ #include #include #include -#include +#include #include #include "common.h" #include "bap_common.h" @@ -20,14 +20,16 @@ extern enum bst_result_t bst_result; static struct bt_conn *connected_conns[CONFIG_BT_MAX_CONN]; static volatile size_t connected_conn_cnt; -CREATE_FLAG(flag_discovered); +CREATE_FLAG(flag_cas_discovered); +CREATE_FLAG(flag_vcs_discovered); CREATE_FLAG(flag_mtu_exchanged); +CREATE_FLAG(flag_volume_changed); static void cap_discovery_complete_cb(struct bt_conn *conn, int err, const struct bt_csip_set_coordinator_csis_inst *csis_inst) { if (err != 0) { - FAIL("Failed to discover CAS: %d", err); + FAIL("Failed to discover CAS: %d\n", err); return; } @@ -44,11 +46,51 @@ static void cap_discovery_complete_cb(struct bt_conn *conn, int err, printk("Found CAS\n"); } - SET_FLAG(flag_discovered); + SET_FLAG(flag_cas_discovered); +} + +static void cap_volume_changed_cb(struct bt_conn *conn, int err) +{ + if (err != 0) { + FAIL("Failed to change volume for conn %p: %d\n", conn, err); + return; + } + + SET_FLAG(flag_volume_changed); } static struct bt_cap_commander_cb cap_cb = { .discovery_complete = cap_discovery_complete_cb, + .volume_changed = cap_volume_changed_cb, +}; + +static void cap_vcp_discover_cb(struct bt_vcp_vol_ctlr *vol_ctlr, int err, uint8_t vocs_count, + uint8_t aics_count) +{ + if (err != 0) { + FAIL("Failed to discover VCS: %d\n", err); + + return; + } + + printk("VCS for %p found with %u VOCS and %u AICS\n", vol_ctlr, vocs_count, aics_count); + SET_FLAG(flag_vcs_discovered); +} + +static void cap_vcp_state_cb(struct bt_vcp_vol_ctlr *vol_ctlr, int err, uint8_t volume, + uint8_t mute) +{ + if (err != 0) { + FAIL("VCP state cb err (%d)\n", err); + return; + } + + printk("State for %p: volume %u, mute %u\n", vol_ctlr, volume, mute); +} + +static struct bt_vcp_vol_ctlr_cb vcp_cb = { + .discover = cap_vcp_discover_cb, + .state = cap_vcp_state_cb, }; static void att_mtu_updated(struct bt_conn *conn, uint16_t tx, uint16_t rx) @@ -78,6 +120,12 @@ static void init(void) FAIL("Failed to register CAP callbacks (err %d)\n", err); return; } + + err = bt_vcp_vol_ctlr_cb_register(&vcp_cb); + if (err != 0) { + FAIL("Failed to register VCP callbacks (err %d)\n", err); + return; + } } static void cap_device_found(const bt_addr_le_t *addr, int8_t rssi, uint8_t type, @@ -155,7 +203,7 @@ static void discover_cas(struct bt_conn *conn) { int err; - UNSET_FLAG(flag_discovered); + UNSET_FLAG(flag_cas_discovered); err = bt_cap_commander_discover(conn); if (err != 0) { @@ -163,7 +211,50 @@ static void discover_cas(struct bt_conn *conn) return; } - WAIT_FOR_FLAG(flag_discovered); + WAIT_FOR_FLAG(flag_cas_discovered); +} + +static void discover_vcs(struct bt_conn *conn) +{ + struct bt_vcp_vol_ctlr *vol_ctlr; + int err; + + UNSET_FLAG(flag_vcs_discovered); + + err = bt_vcp_vol_ctlr_discover(conn, &vol_ctlr); + if (err != 0) { + printk("Failed to discover VCS: %d\n", err); + return; + } + + WAIT_FOR_FLAG(flag_vcs_discovered); +} + +static void test_change_volume(void) +{ + union bt_cap_set_member members[CONFIG_BT_MAX_CONN]; + const struct bt_cap_commander_change_volume_param param = { + .type = BT_CAP_SET_TYPE_AD_HOC, + .members = members, + .count = connected_conn_cnt, + .volume = 177, + }; + int err; + + printk("Changing volume to %u\n", param.volume); + + for (size_t i = 0U; i < param.count; i++) { + param.members[i].member = connected_conns[i]; + } + + err = bt_cap_commander_change_volume(¶m); + if (err != 0) { + FAIL("Failed to change volume: %d\n", err); + return; + } + + WAIT_FOR_FLAG(flag_volume_changed); + printk("Volume changed to %u\n", param.volume); } static void test_main_cap_commander_capture_and_render(void) @@ -177,10 +268,19 @@ static void test_main_cap_commander_capture_and_render(void) WAIT_FOR_FLAG(flag_mtu_exchanged); /* TODO: We should use CSIP to find set members */ - discover_cas(default_conn); + discover_cas(connected_conns[i]); + + if (IS_ENABLED(CONFIG_BT_VCP_VOL_CTLR)) { + discover_vcs(connected_conns[i]); + } } - /* TODO: Do CAP Commander stuff */ + if (IS_ENABLED(CONFIG_BT_CSIP_SET_COORDINATOR)) { + if (IS_ENABLED(CONFIG_BT_VCP_VOL_CTLR)) { + test_change_volume(); + } + /* TODO: Add test of offset (VOCS), Mic (MICP) and gain (AICS) */ + } /* Disconnect all CAP acceptors */ for (size_t i = 0U; i < connected_conn_cnt; i++) { From 6e52f384c8e56d0c1b5e5d8d29b8d2aae17383e8 Mon Sep 17 00:00:00 2001 From: Emil Gydesen Date: Thu, 23 Nov 2023 12:32:59 +0100 Subject: [PATCH 2420/3723] tests: Bluetooth: CAP commander volume_change unit tests Adds unit tests for the CAP Commander volume_change procedure. Signed-off-by: Emil Gydesen --- subsys/bluetooth/audio/cap_commander.c | 6 +- subsys/bluetooth/audio/cap_initiator.c | 29 +-- .../audio/cap_commander/include/cap_mocks.h | 10 + tests/bluetooth/audio/cap_commander/prj.conf | 1 + .../bluetooth/audio/cap_commander/src/main.c | 239 +++++++++++++++++- tests/bluetooth/audio/cap_commander/uut/vcp.c | 28 +- .../audio/mocks/include/cap_commander.h | 3 +- .../bluetooth/audio/mocks/src/cap_commander.c | 17 +- 8 files changed, 299 insertions(+), 34 deletions(-) create mode 100644 tests/bluetooth/audio/cap_commander/include/cap_mocks.h diff --git a/subsys/bluetooth/audio/cap_commander.c b/subsys/bluetooth/audio/cap_commander.c index 27346b822f7..93567f34038 100644 --- a/subsys/bluetooth/audio/cap_commander.c +++ b/subsys/bluetooth/audio/cap_commander.c @@ -253,14 +253,13 @@ static void cap_commander_vcp_vol_set_cb(struct bt_vcp_vol_ctlr *vol_ctlr, int e proc_param = &active_proc->proc_param.commander[active_proc->proc_done_cnt]; conn = proc_param->conn; + active_proc->proc_initiated_cnt++; err = bt_vcp_vol_ctlr_set_vol(bt_vcp_vol_ctlr_get_by_conn(conn), proc_param->change_volume.volume); if (err != 0) { LOG_DBG("Failed to set volume for conn %p: %d", (void *)conn, err); bt_cap_common_abort_proc(conn, err); cap_commander_unicast_audio_proc_complete(); - } else { - active_proc->proc_initiated_cnt++; } } else { cap_commander_unicast_audio_proc_complete(); @@ -322,6 +321,7 @@ int bt_cap_commander_change_volume(const struct bt_cap_commander_change_volume_p proc_param = &active_proc->proc_param.commander[0]; conn = proc_param->conn; + active_proc->proc_initiated_cnt++; err = bt_vcp_vol_ctlr_set_vol(bt_vcp_vol_ctlr_get_by_conn(conn), proc_param->change_volume.volume); if (err != 0) { @@ -329,8 +329,6 @@ int bt_cap_commander_change_volume(const struct bt_cap_commander_change_volume_p return -ENOEXEC; } - active_proc->proc_initiated_cnt++; - return 0; } diff --git a/subsys/bluetooth/audio/cap_initiator.c b/subsys/bluetooth/audio/cap_initiator.c index 79fb9faf44d..32d86b726a1 100644 --- a/subsys/bluetooth/audio/cap_initiator.c +++ b/subsys/bluetooth/audio/cap_initiator.c @@ -552,6 +552,7 @@ static int cap_initiator_unicast_audio_configure( codec_cfg = &proc_param->start.codec_cfg; conn = proc_param->start.conn; ep = proc_param->start.ep; + active_proc->proc_initiated_cnt++; /* Since BAP operations may require a write long or a read long on the notification, * we cannot assume that we can do multiple streams at once, thus do it one at a time. @@ -562,8 +563,6 @@ static int cap_initiator_unicast_audio_configure( LOG_DBG("Failed to config stream %p: %d", proc_param->stream, err); bt_cap_common_clear_active_proc(); - } else { - active_proc->proc_initiated_cnt++; } return err; @@ -646,6 +645,7 @@ void bt_cap_initiator_codec_configured(struct bt_cap_stream *cap_stream) ep = proc_param->start.ep; codec_cfg = &proc_param->start.codec_cfg; bap_stream = &next_cap_stream->bap_stream; + active_proc->proc_initiated_cnt++; /* Since BAP operations may require a write long or a read long on the notification, * we cannot assume that we can do multiple streams at once, thus do it one at a @@ -659,8 +659,6 @@ void bt_cap_initiator_codec_configured(struct bt_cap_stream *cap_stream) bt_cap_common_abort_proc(conn, err); cap_initiator_unicast_audio_proc_complete(); - } else { - active_proc->proc_initiated_cnt++; } return; @@ -712,6 +710,8 @@ void bt_cap_initiator_codec_configured(struct bt_cap_stream *cap_stream) break; } + active_proc->proc_initiated_cnt++; + err = bt_bap_stream_qos(conns[i], unicast_group); if (err != 0) { LOG_DBG("Failed to set stream QoS for conn %p and group %p: %d", @@ -728,8 +728,6 @@ void bt_cap_initiator_codec_configured(struct bt_cap_stream *cap_stream) return; } - - active_proc->proc_initiated_cnt++; } } @@ -773,6 +771,7 @@ void bt_cap_initiator_qos_configured(struct bt_cap_stream *cap_stream) proc_param = &active_proc->proc_param.initiator[0]; next_cap_stream = proc_param->stream; bap_stream = &next_cap_stream->bap_stream; + active_proc->proc_initiated_cnt++; /* Since BAP operations may require a write long or a read long on the notification, we * cannot assume that we can do multiple streams at once, thus do it one at a time. @@ -785,8 +784,6 @@ void bt_cap_initiator_qos_configured(struct bt_cap_stream *cap_stream) bt_cap_common_abort_proc(bap_stream->conn, err); cap_initiator_unicast_audio_proc_complete(); - } else { - active_proc->proc_initiated_cnt++; } } @@ -825,6 +822,8 @@ void bt_cap_initiator_enabled(struct bt_cap_stream *cap_stream) active_proc->proc_param.initiator[active_proc->proc_done_cnt].stream; struct bt_bap_stream *next_bap_stream = &next_cap_stream->bap_stream; + active_proc->proc_initiated_cnt++; + /* Since BAP operations may require a write long or a read long on the notification, * we cannot assume that we can do multiple streams at once, thus do it one at a * time. @@ -838,8 +837,6 @@ void bt_cap_initiator_enabled(struct bt_cap_stream *cap_stream) bt_cap_common_abort_proc(next_bap_stream->conn, err); cap_initiator_unicast_audio_proc_complete(); - } else { - active_proc->proc_initiated_cnt++; } return; @@ -1011,14 +1008,13 @@ int bt_cap_initiator_unicast_audio_update(const struct bt_cap_unicast_audio_upda bap_stream = &proc_param->stream->bap_stream; meta_len = proc_param->meta_update.meta_len; meta = proc_param->meta_update.meta; + active_proc->proc_initiated_cnt++; err = bt_bap_stream_metadata(bap_stream, meta, meta_len); if (err != 0) { LOG_DBG("Failed to update metadata for stream %p: %d", proc_param->stream, err); bt_cap_common_clear_active_proc(); - } else { - active_proc->proc_initiated_cnt++; } return err; @@ -1079,6 +1075,7 @@ void bt_cap_initiator_metadata_updated(struct bt_cap_stream *cap_stream) meta = proc_param->meta_update.meta; next_cap_stream = proc_param->stream; bap_stream = &next_cap_stream->bap_stream; + active_proc->proc_initiated_cnt++; /* Since BAP operations may require a write long or a read long on the notification, * we cannot assume that we can do multiple streams at once, thus do it one at a @@ -1094,8 +1091,6 @@ void bt_cap_initiator_metadata_updated(struct bt_cap_stream *cap_stream) bt_cap_common_abort_proc(bap_stream->conn, err); cap_initiator_unicast_audio_proc_complete(); - } else { - active_proc->proc_initiated_cnt++; } return; @@ -1169,14 +1164,13 @@ int bt_cap_initiator_unicast_audio_stop(struct bt_bap_unicast_group *unicast_gro */ proc_param = &active_proc->proc_param.initiator[0]; bap_stream = &proc_param->stream->bap_stream; + active_proc->proc_initiated_cnt++; err = bt_bap_stream_release(bap_stream); if (err != 0) { LOG_DBG("Failed to stop bap_stream %p: %d", proc_param->stream, err); bt_cap_common_clear_active_proc(); - } else { - active_proc->proc_initiated_cnt++; } return err; @@ -1215,6 +1209,7 @@ void bt_cap_initiator_released(struct bt_cap_stream *cap_stream) struct bt_bap_stream *bap_stream = &next_cap_stream->bap_stream; int err; + active_proc->proc_initiated_cnt++; /* Since BAP operations may require a write long or a read long on the notification, * we cannot assume that we can do multiple streams at once, thus do it one at a * time. @@ -1227,8 +1222,6 @@ void bt_cap_initiator_released(struct bt_cap_stream *cap_stream) bt_cap_common_abort_proc(bap_stream->conn, err); cap_initiator_unicast_audio_proc_complete(); - } else { - active_proc->proc_initiated_cnt++; } } else { cap_initiator_unicast_audio_proc_complete(); diff --git a/tests/bluetooth/audio/cap_commander/include/cap_mocks.h b/tests/bluetooth/audio/cap_commander/include/cap_mocks.h new file mode 100644 index 00000000000..5c7751bf37a --- /dev/null +++ b/tests/bluetooth/audio/cap_commander/include/cap_mocks.h @@ -0,0 +1,10 @@ +/* + * Copyright (c) 2023 Nordic Semiconductor ASA + * + * SPDX-License-Identifier: Apache-2.0 + */ + +void mock_bt_csip_init(void); +void mock_bt_csip_cleanup(void); +void mock_bt_vcp_init(void); +void mock_bt_vcp_cleanup(void); diff --git a/tests/bluetooth/audio/cap_commander/prj.conf b/tests/bluetooth/audio/cap_commander/prj.conf index e4e2edeb05a..fd805ec06a1 100644 --- a/tests/bluetooth/audio/cap_commander/prj.conf +++ b/tests/bluetooth/audio/cap_commander/prj.conf @@ -2,6 +2,7 @@ CONFIG_ZTEST=y CONFIG_BT=y CONFIG_BT_CENTRAL=y +CONFIG_BT_MAX_CONN=2 CONFIG_BT_AUDIO=y # Requirements for CAP commander diff --git a/tests/bluetooth/audio/cap_commander/src/main.c b/tests/bluetooth/audio/cap_commander/src/main.c index b095eead8e5..1cabbce134c 100644 --- a/tests/bluetooth/audio/cap_commander/src/main.c +++ b/tests/bluetooth/audio/cap_commander/src/main.c @@ -9,29 +9,35 @@ #include #include +#include #include #include "bluetooth.h" #include "cap_commander.h" #include "conn.h" #include "expects_util.h" +#include "cap_mocks.h" DEFINE_FFF_GLOBALS; static void mock_init_rule_before(const struct ztest_unit_test *test, void *fixture) { mock_cap_commander_init(); + mock_bt_csip_init(); + mock_bt_vcp_init(); } static void mock_destroy_rule_after(const struct ztest_unit_test *test, void *fixture) { mock_cap_commander_cleanup(); + mock_bt_csip_cleanup(); + mock_bt_vcp_cleanup(); } ZTEST_RULE(mock_rule, mock_init_rule_before, mock_destroy_rule_after); struct cap_commander_test_suite_fixture { - struct bt_conn conn; + struct bt_conn conns[CONFIG_BT_MAX_CONN]; }; static void test_conn_init(struct bt_conn *conn) @@ -47,7 +53,9 @@ static void test_conn_init(struct bt_conn *conn) static void cap_commander_test_suite_fixture_init(struct cap_commander_test_suite_fixture *fixture) { - test_conn_init(&fixture->conn); + for (size_t i = 0; i < ARRAY_SIZE(fixture->conns); i++) { + test_conn_init(&fixture->conns[i]); + } } static void *cap_commander_test_suite_setup(void) @@ -68,7 +76,13 @@ static void cap_commander_test_suite_before(void *f) static void cap_commander_test_suite_after(void *f) { + struct cap_commander_test_suite_fixture *fixture = f; + bt_cap_commander_unregister_cb(&mock_cap_commander_cb); + + for (size_t i = 0; i < ARRAY_SIZE(fixture->conns); i++) { + mock_bt_conn_disconnected(&fixture->conns[i], BT_HCI_ERR_REMOTE_USER_TERM_CONN); + } } static void cap_commander_test_suite_teardown(void *f) @@ -147,10 +161,12 @@ ZTEST_F(cap_commander_test_suite, test_commander_discover) err = bt_cap_commander_register_cb(&mock_cap_commander_cb); zassert_equal(0, err, "Unexpected return value %d", err); - err = bt_cap_commander_discover(&fixture->conn); - zassert_equal(0, err, "Unexpected return value %d", err); + for (size_t i = 0; i < ARRAY_SIZE(fixture->conns); i++) { + err = bt_cap_commander_discover(&fixture->conns[i]); + zassert_equal(0, err, "Unexpected return value %d", err); + } - zexpect_call_count("bt_cap_commander_cb.discovery_complete", 1, + zexpect_call_count("bt_cap_commander_cb.discovery_complete", ARRAY_SIZE(fixture->conns), mock_cap_commander_discovery_complete_cb_fake.call_count); } @@ -164,3 +180,216 @@ ZTEST_F(cap_commander_test_suite, test_commander_discover_inval_param_null) err = bt_cap_commander_discover(NULL); zassert_equal(-EINVAL, err, "Unexpected return value %d", err); } + +ZTEST_F(cap_commander_test_suite, test_commander_change_volume) +{ + union bt_cap_set_member members[ARRAY_SIZE(fixture->conns)]; + const struct bt_cap_commander_change_volume_param param = { + .type = BT_CAP_SET_TYPE_AD_HOC, + .members = members, + .count = ARRAY_SIZE(fixture->conns), + .volume = 177, + }; + int err; + + for (size_t i = 0U; i < ARRAY_SIZE(members); i++) { + members[i].member = &fixture->conns[i]; + } + + err = bt_cap_commander_register_cb(&mock_cap_commander_cb); + zassert_equal(0, err, "Unexpected return value %d", err); + + for (size_t i = 0; i < ARRAY_SIZE(fixture->conns); i++) { + struct bt_vcp_vol_ctlr *vol_ctlr; /* We don't care about this */ + + err = bt_cap_commander_discover(&fixture->conns[i]); + zassert_equal(0, err, "Unexpected return value %d", err); + + err = bt_vcp_vol_ctlr_discover(&fixture->conns[i], &vol_ctlr); + zassert_equal(0, err, "Unexpected return value %d", err); + } + + err = bt_cap_commander_change_volume(¶m); + zassert_equal(0, err, "Unexpected return value %d", err); + + zexpect_call_count("bt_cap_commander_cb.volume_changed", 1, + mock_cap_commander_volume_changed_cb_fake.call_count); +} + +ZTEST_F(cap_commander_test_suite, test_commander_change_volume_double) +{ + union bt_cap_set_member members[ARRAY_SIZE(fixture->conns)]; + const struct bt_cap_commander_change_volume_param param = { + .type = BT_CAP_SET_TYPE_AD_HOC, + .members = members, + .count = ARRAY_SIZE(fixture->conns), + .volume = 177, + }; + int err; + + for (size_t i = 0U; i < ARRAY_SIZE(members); i++) { + members[i].member = &fixture->conns[i]; + } + + err = bt_cap_commander_register_cb(&mock_cap_commander_cb); + zassert_equal(0, err, "Unexpected return value %d", err); + + for (size_t i = 0; i < ARRAY_SIZE(fixture->conns); i++) { + struct bt_vcp_vol_ctlr *vol_ctlr; /* We don't care about this */ + + err = bt_cap_commander_discover(&fixture->conns[i]); + zassert_equal(0, err, "Unexpected return value %d", err); + + err = bt_vcp_vol_ctlr_discover(&fixture->conns[i], &vol_ctlr); + zassert_equal(0, err, "Unexpected return value %d", err); + } + + err = bt_cap_commander_change_volume(¶m); + zassert_equal(0, err, "Unexpected return value %d", err); + + zexpect_call_count("bt_cap_commander_cb.volume_changed", 1, + mock_cap_commander_volume_changed_cb_fake.call_count); + + /* Verify that it still works as expected if we set the same value twice */ + err = bt_cap_commander_change_volume(¶m); + zassert_equal(0, err, "Unexpected return value %d", err); + + zexpect_call_count("bt_cap_commander_cb.volume_changed", 2, + mock_cap_commander_volume_changed_cb_fake.call_count); +} + +ZTEST_F(cap_commander_test_suite, test_commander_change_volume_inval_param_null) +{ + int err; + + err = bt_cap_commander_change_volume(NULL); + zassert_equal(-EINVAL, err, "Unexpected return value %d", err); +} + +ZTEST_F(cap_commander_test_suite, test_commander_change_volume_inval_param_null_members) +{ + const struct bt_cap_commander_change_volume_param param = { + .type = BT_CAP_SET_TYPE_AD_HOC, + .members = NULL, + .count = ARRAY_SIZE(fixture->conns), + .volume = 177, + }; + int err; + + err = bt_cap_commander_change_volume(¶m); + zassert_equal(-EINVAL, err, "Unexpected return value %d", err); +} + +ZTEST_F(cap_commander_test_suite, test_commander_change_volume_inval_param_null_member) +{ + union bt_cap_set_member members[ARRAY_SIZE(fixture->conns)]; + const struct bt_cap_commander_change_volume_param param = { + .type = BT_CAP_SET_TYPE_AD_HOC, + .members = members, + .count = ARRAY_SIZE(fixture->conns), + .volume = 177, + }; + int err; + + for (size_t i = 0U; i < ARRAY_SIZE(members) - 1; i++) { + members[i].member = &fixture->conns[i]; + } + members[ARRAY_SIZE(members) - 1].member = NULL; + + err = bt_cap_commander_change_volume(¶m); + zassert_equal(-EINVAL, err, "Unexpected return value %d", err); +} + +ZTEST_F(cap_commander_test_suite, test_commander_change_volume_inval_missing_cas) +{ + union bt_cap_set_member members[ARRAY_SIZE(fixture->conns)]; + const struct bt_cap_commander_change_volume_param param = { + .type = BT_CAP_SET_TYPE_AD_HOC, + .members = members, + .count = ARRAY_SIZE(fixture->conns), + .volume = 177, + }; + int err; + + for (size_t i = 0U; i < ARRAY_SIZE(members); i++) { + members[i].member = &fixture->conns[i]; + } + + err = bt_cap_commander_register_cb(&mock_cap_commander_cb); + zassert_equal(0, err, "Unexpected return value %d", err); + + for (size_t i = 0; i < ARRAY_SIZE(fixture->conns); i++) { + struct bt_vcp_vol_ctlr *vol_ctlr; /* We don't care about this */ + + err = bt_vcp_vol_ctlr_discover(&fixture->conns[i], &vol_ctlr); + zassert_equal(0, err, "Unexpected return value %d", err); + } + + err = bt_cap_commander_change_volume(¶m); + zassert_equal(-EINVAL, err, "Unexpected return value %d", err); +} + +ZTEST_F(cap_commander_test_suite, test_commander_change_volume_inval_missing_vcs) +{ + union bt_cap_set_member members[ARRAY_SIZE(fixture->conns)]; + const struct bt_cap_commander_change_volume_param param = { + .type = BT_CAP_SET_TYPE_AD_HOC, + .members = members, + .count = ARRAY_SIZE(fixture->conns), + .volume = 177, + }; + int err; + + for (size_t i = 0U; i < ARRAY_SIZE(members); i++) { + members[i].member = &fixture->conns[i]; + } + + err = bt_cap_commander_register_cb(&mock_cap_commander_cb); + zassert_equal(0, err, "Unexpected return value %d", err); + + for (size_t i = 0; i < ARRAY_SIZE(fixture->conns); i++) { + err = bt_cap_commander_discover(&fixture->conns[i]); + zassert_equal(0, err, "Unexpected return value %d", err); + } + + err = bt_cap_commander_change_volume(¶m); + zassert_equal(-EINVAL, err, "Unexpected return value %d", err); +} + +ZTEST_F(cap_commander_test_suite, test_commander_change_volume_inval_param_zero_count) +{ + union bt_cap_set_member members[ARRAY_SIZE(fixture->conns)]; + const struct bt_cap_commander_change_volume_param param = { + .type = BT_CAP_SET_TYPE_AD_HOC, + .members = members, + .count = 0U, + .volume = 177, + }; + int err; + + for (size_t i = 0U; i < ARRAY_SIZE(members); i++) { + members[i].member = &fixture->conns[i]; + } + + err = bt_cap_commander_change_volume(¶m); + zassert_equal(-EINVAL, err, "Unexpected return value %d", err); +} + +ZTEST_F(cap_commander_test_suite, test_commander_change_volume_inval_param_inval_count) +{ + union bt_cap_set_member members[ARRAY_SIZE(fixture->conns)]; + const struct bt_cap_commander_change_volume_param param = { + .type = BT_CAP_SET_TYPE_AD_HOC, + .members = members, + .count = CONFIG_BT_MAX_CONN + 1, + .volume = 177, + }; + int err; + + for (size_t i = 0U; i < ARRAY_SIZE(members); i++) { + members[i].member = &fixture->conns[i]; + } + + err = bt_cap_commander_change_volume(¶m); + zassert_equal(-EINVAL, err, "Unexpected return value %d", err); +} diff --git a/tests/bluetooth/audio/cap_commander/uut/vcp.c b/tests/bluetooth/audio/cap_commander/uut/vcp.c index a031a8be0de..b6dc66afde5 100644 --- a/tests/bluetooth/audio/cap_commander/uut/vcp.c +++ b/tests/bluetooth/audio/cap_commander/uut/vcp.c @@ -34,12 +34,38 @@ int bt_vcp_vol_ctlr_conn_get(const struct bt_vcp_vol_ctlr *vol_ctlr, struct bt_c int bt_vcp_vol_ctlr_set_vol(struct bt_vcp_vol_ctlr *vol_ctlr, uint8_t volume) { - if (vcp_cb->vol_set != NULL) { + if (vcp_cb != NULL && vcp_cb->vol_set != NULL) { vcp_cb->vol_set(vol_ctlr, 0); } + + return 0; +} + +int bt_vcp_vol_ctlr_discover(struct bt_conn *conn, struct bt_vcp_vol_ctlr **vol_ctlr) +{ + for (size_t i = 0; i < ARRAY_SIZE(vol_ctlrs); i++) { + if (vol_ctlrs[i].conn == NULL) { + vol_ctlrs[i].conn = conn; + *vol_ctlr = &vol_ctlrs[i]; + return 0; + } + } + + return -ENOMEM; } int bt_vcp_vol_ctlr_cb_register(struct bt_vcp_vol_ctlr_cb *cb) { vcp_cb = cb; + + return 0; +} + +void mock_bt_vcp_init(void) +{ + memset(vol_ctlrs, 0, sizeof(vol_ctlrs)); +} + +void mock_bt_vcp_cleanup(void) +{ } diff --git a/tests/bluetooth/audio/mocks/include/cap_commander.h b/tests/bluetooth/audio/mocks/include/cap_commander.h index 0fd47ea8d51..86be0119671 100644 --- a/tests/bluetooth/audio/mocks/include/cap_commander.h +++ b/tests/bluetooth/audio/mocks/include/cap_commander.h @@ -10,12 +10,13 @@ #include #include -extern struct bt_cap_commander_cb mock_cap_commander_cb; +extern const struct bt_cap_commander_cb mock_cap_commander_cb; void mock_cap_commander_init(void); void mock_cap_commander_cleanup(void); DECLARE_FAKE_VOID_FUNC(mock_cap_commander_discovery_complete_cb, struct bt_conn *, int, const struct bt_csip_set_coordinator_csis_inst *); +DECLARE_FAKE_VOID_FUNC(mock_cap_commander_volume_changed_cb, struct bt_conn *, int); #endif /* MOCKS_CAP_COMMANDER_H_ */ diff --git a/tests/bluetooth/audio/mocks/src/cap_commander.c b/tests/bluetooth/audio/mocks/src/cap_commander.c index c55b72e1a5d..de0e309ecbd 100644 --- a/tests/bluetooth/audio/mocks/src/cap_commander.c +++ b/tests/bluetooth/audio/mocks/src/cap_commander.c @@ -9,18 +9,25 @@ #include "cap_commander.h" /* List of fakes used by this unit tester */ -#define FFF_FAKES_LIST(FAKE) FAKE(mock_cap_commander_discovery_complete_cb) - -struct bt_cap_commander_cb mock_cap_commander_cb; +#define FFF_FAKES_LIST(FAKE) \ + FAKE(mock_cap_commander_discovery_complete_cb) \ + FAKE(mock_cap_commander_volume_changed_cb) DEFINE_FAKE_VOID_FUNC(mock_cap_commander_discovery_complete_cb, struct bt_conn *, int, const struct bt_csip_set_coordinator_csis_inst *); +DEFINE_FAKE_VOID_FUNC(mock_cap_commander_volume_changed_cb, struct bt_conn *, int); + +const struct bt_cap_commander_cb mock_cap_commander_cb = { + .discovery_complete = mock_cap_commander_discovery_complete_cb, +#if defined(CONFIG_BT_VCP_VOL_CTLR) + .volume_changed = mock_cap_commander_volume_changed_cb, +#endif /* CONFIG_BT_VCP_VOL_CTLR */ +}; + void mock_cap_commander_init(void) { FFF_FAKES_LIST(RESET_FAKE); - - mock_cap_commander_cb.discovery_complete = mock_cap_commander_discovery_complete_cb; } void mock_cap_commander_cleanup(void) From 490c5e3b20beff6d10af9e2aa632d61fcd3a3e24 Mon Sep 17 00:00:00 2001 From: Emil Gydesen Date: Thu, 30 Nov 2023 11:16:05 +0100 Subject: [PATCH 2421/3723] Bluetooth: Audio: Shell: CAP change volume command Add sthe change volume command to the CAP commander shell. Signed-off-by: Emil Gydesen --- doc/connectivity/bluetooth/api/shell/cap.rst | 21 ++++- subsys/bluetooth/audio/shell/cap_commander.c | 93 ++++++++++++++++++++ subsys/bluetooth/audio/shell/vcp_vol_ctlr.c | 2 +- 3 files changed, 114 insertions(+), 2 deletions(-) diff --git a/doc/connectivity/bluetooth/api/shell/cap.rst b/doc/connectivity/bluetooth/api/shell/cap.rst index 13c8d665421..32d752d71fc 100644 --- a/doc/connectivity/bluetooth/api/shell/cap.rst +++ b/doc/connectivity/bluetooth/api/shell/cap.rst @@ -159,7 +159,9 @@ the optionally included CSIS instance by calling (:code:`cap_commander discover` cap_commander --help cap_commander - Bluetooth CAP commander shell commands Subcommands: - discover :Discover CAS + discover :Discover CAS + change_volume :Change volume on all connections + Before being able to perform any stream operation, the device must also perform the :code:`bap discover` operation to discover the ASEs and PAC records. The :code:`bap init` @@ -174,3 +176,20 @@ Discovering CAS and CSIS on a device: uart:~$ cap_commander discover discovery completed with CSIS + + +Setting the volume on all connected devices: + +.. code-block:: console + + uart:~$ vcp_vol_ctlr discover + VCP discover done with 1 VOCS and 1 AICS + uart:~$ cap_commander change_volume 15 + uart:~$ cap_commander change_volume 15 + Setting volume to 15 on 2 connections + VCP volume 15, mute 0 + VCP vol_set done + VCP volume 15, mute 0 + VCP flags 0x01 + VCP vol_set done + Volume change completed diff --git a/subsys/bluetooth/audio/shell/cap_commander.c b/subsys/bluetooth/audio/shell/cap_commander.c index 0545197341f..01675f8fc6c 100644 --- a/subsys/bluetooth/audio/shell/cap_commander.c +++ b/subsys/bluetooth/audio/shell/cap_commander.c @@ -27,8 +27,23 @@ static void cap_discover_cb(struct bt_conn *conn, int err, shell_print(ctx_shell, "discovery completed%s", csis_inst == NULL ? "" : " with CSIS"); } +#if defined(CONFIG_BT_VCP_VOL_CTLR) +static void cap_volume_changed_cb(struct bt_conn *conn, int err) +{ + if (err != 0) { + shell_error(ctx_shell, "Volume change failed (%d)", err); + return; + } + + shell_print(ctx_shell, "Volume change completed"); +} +#endif /* CONFIG_BT_VCP_VOL_CTLR */ + static struct bt_cap_commander_cb cbs = { .discovery_complete = cap_discover_cb, +#if defined(CONFIG_BT_VCP_VOL_CTLR) + .volume_changed = cap_volume_changed_cb, +#endif /* CONFIG_BT_VCP_VOL_CTLR */ }; static int cmd_cap_commander_discover(const struct shell *sh, size_t argc, char *argv[]) @@ -58,6 +73,80 @@ static int cmd_cap_commander_discover(const struct shell *sh, size_t argc, char return err; } +#if defined(CONFIG_BT_VCP_VOL_CTLR) +static void populate_connected_conns(struct bt_conn *conn, void *data) +{ + struct bt_conn **connected_conns = (struct bt_conn **)data; + + for (int i = 0; i < CONFIG_BT_MAX_CONN; i++) { + if (connected_conns[i] == NULL) { + connected_conns[i] = conn; + return; + } + } +} + +static int cmd_cap_commander_change_volume(const struct shell *sh, size_t argc, char *argv[]) +{ + struct bt_conn *connected_conns[CONFIG_BT_MAX_CONN] = {0}; + union bt_cap_set_member members[CONFIG_BT_MAX_CONN] = {0}; + struct bt_cap_commander_change_volume_param param = { + .members = members, + }; + unsigned long volume; + int err = 0; + + if (default_conn == NULL) { + shell_error(sh, "Not connected"); + return -ENOEXEC; + } + + volume = shell_strtoul(argv[1], 10, &err); + if (err != 0) { + shell_error(sh, "Failed to parse volume from %s", argv[1]); + + return -ENOEXEC; + } + + if (volume > UINT8_MAX) { + shell_error(sh, "Invalid volume %lu", volume); + + return -ENOEXEC; + } + param.volume = (uint8_t)volume; + + param.type = BT_CAP_SET_TYPE_AD_HOC; + /* TODO: Add support for coordinated sets */ + + /* Populate the array of connected connections */ + bt_conn_foreach(BT_CONN_TYPE_LE, populate_connected_conns, (void *)connected_conns); + + param.count = 0U; + param.members = members; + for (size_t i = 0; i < ARRAY_SIZE(connected_conns); i++) { + struct bt_conn *conn = connected_conns[i]; + + if (conn == NULL) { + break; + } + + param.members[i].member = conn; + param.count++; + } + + shell_print(sh, "Setting volume to %u on %zu connections", param.volume, param.count); + + err = bt_cap_commander_change_volume(¶m); + if (err != 0) { + shell_print(sh, "Failed to change volume: %d", err); + + return -ENOEXEC; + } + + return 0; +} +#endif /* CONFIG_BT_VCP_VOL_CTLR */ + static int cmd_cap_commander(const struct shell *sh, size_t argc, char **argv) { if (argc > 1) { @@ -72,6 +161,10 @@ static int cmd_cap_commander(const struct shell *sh, size_t argc, char **argv) SHELL_STATIC_SUBCMD_SET_CREATE( cap_commander_cmds, SHELL_CMD_ARG(discover, NULL, "Discover CAS", cmd_cap_commander_discover, 1, 0), +#if defined(CONFIG_BT_VCP_VOL_CTLR) + SHELL_CMD_ARG(change_volume, NULL, "Change volume on all connections ", + cmd_cap_commander_change_volume, 2, 0), +#endif /* CONFIG_BT_VCP_VOL_CTLR */ SHELL_SUBCMD_SET_END ); diff --git a/subsys/bluetooth/audio/shell/vcp_vol_ctlr.c b/subsys/bluetooth/audio/shell/vcp_vol_ctlr.c index 38d0abb0915..3ca3ecdd24a 100644 --- a/subsys/bluetooth/audio/shell/vcp_vol_ctlr.c +++ b/subsys/bluetooth/audio/shell/vcp_vol_ctlr.c @@ -24,7 +24,7 @@ static void vcs_discover_cb(struct bt_vcp_vol_ctlr *vol_ctlr, int err, if (err != 0) { shell_error(ctx_shell, "VCP discover failed (%d)", err); } else { - shell_print(ctx_shell, "VCP discover done with %u AICS", + shell_print(ctx_shell, "VCP discover done with %u VOCS and %u AICS", vocs_count, aics_count); if (bt_vcp_vol_ctlr_included_get(vol_ctlr, &vcp_included)) { From 2b2e6bad367182739cb5b8b927705edcd18a6ec3 Mon Sep 17 00:00:00 2001 From: Armin Brauns Date: Tue, 14 Nov 2023 14:12:36 +0000 Subject: [PATCH 2422/3723] drivers: allow changing max31865 three-wire mode at runtime Instead of only through static devicetree config at boot. Signed-off-by: Armin Brauns --- drivers/sensor/max31865/max31865.c | 27 +++++++++++++++++++++++- drivers/sensor/max31865/max31865.h | 1 + include/zephyr/drivers/sensor/max31865.h | 12 +++++++++++ 3 files changed, 39 insertions(+), 1 deletion(-) create mode 100644 include/zephyr/drivers/sensor/max31865.h diff --git a/drivers/sensor/max31865/max31865.c b/drivers/sensor/max31865/max31865.c index bced243b1a8..f94de01fdc6 100644 --- a/drivers/sensor/max31865/max31865.c +++ b/drivers/sensor/max31865/max31865.c @@ -139,6 +139,14 @@ static int max31865_set_vbias(const struct device *dev, bool enable) return configure_device(dev); } +static int max31865_set_three_wire(const struct device *dev, bool enable) +{ + struct max31865_data *data = dev->data; + + WRITE_BIT(data->config_control_bits, 4, enable); + return configure_device(dev); +} + static char *max31865_error_to_string(uint8_t fault_register) { switch (fault_register) { @@ -242,13 +250,13 @@ static int max31865_init(const struct device *dev) WRITE_BIT(data->config_control_bits, 6, config->conversion_mode); WRITE_BIT(data->config_control_bits, 5, config->one_shot); - WRITE_BIT(data->config_control_bits, 4, config->three_wire); data->config_control_bits |= config->fault_cycle & 0b00001100; WRITE_BIT(data->config_control_bits, 0, config->filter_50hz); configure_device(dev); set_threshold_values(dev); max31865_set_vbias(dev, false); + max31865_set_three_wire(dev, config->three_wire); return 0; } @@ -274,9 +282,26 @@ static int max31865_channel_get(const struct device *dev, enum sensor_channel ch } } +static int max31865_attr_set(const struct device *dev, enum sensor_channel chan, + enum sensor_attribute attr, const struct sensor_value *val) +{ + if (chan != SENSOR_CHAN_ALL && chan != SENSOR_CHAN_AMBIENT_TEMP) { + LOG_ERR("Invalid channel provided"); + return -ENOTSUP; + } + + switch (attr) { + case SENSOR_ATTR_MAX31865_THREE_WIRE: + return max31865_set_three_wire(dev, val->val1); + default: + return -ENOTSUP; + } +} + static const struct sensor_driver_api max31865_api_funcs = { .sample_fetch = max31865_sample_fetch, .channel_get = max31865_channel_get, + .attr_set = max31865_attr_set, }; #define MAX31865_DEFINE(inst) \ diff --git a/drivers/sensor/max31865/max31865.h b/drivers/sensor/max31865/max31865.h index cff6bca9940..9efc3221499 100644 --- a/drivers/sensor/max31865/max31865.h +++ b/drivers/sensor/max31865/max31865.h @@ -11,6 +11,7 @@ #include #include +#include #include #include #include diff --git a/include/zephyr/drivers/sensor/max31865.h b/include/zephyr/drivers/sensor/max31865.h new file mode 100644 index 00000000000..901637379bf --- /dev/null +++ b/include/zephyr/drivers/sensor/max31865.h @@ -0,0 +1,12 @@ +/* + * Copyright (c) 2023 SILA Embedded Solutions + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#ifndef _MAX31865_PUB_H +#define _MAX31865_PUB_H + +#define SENSOR_ATTR_MAX31865_THREE_WIRE SENSOR_ATTR_PRIV_START + +#endif /* _MAX31865_PUB_H */ From 8f7e3b8123859d7d9934e438dba2cbfaffaa7a20 Mon Sep 17 00:00:00 2001 From: Jordan Yates Date: Fri, 10 Nov 2023 15:04:03 +1000 Subject: [PATCH 2423/3723] scripts: twister: snippet roots from modules Automatically populate the snippet roots from Zephyr modules, instead of only looking in `ZEPHYR_BASE`. Signed-off-by: Jordan Yates --- scripts/pylib/twister/twisterlib/environment.py | 7 +++++++ scripts/pylib/twister/twisterlib/testplan.py | 2 +- 2 files changed, 8 insertions(+), 1 deletion(-) diff --git a/scripts/pylib/twister/twisterlib/environment.py b/scripts/pylib/twister/twisterlib/environment.py index 7e9c7dee7dd..42e48b6abe0 100644 --- a/scripts/pylib/twister/twisterlib/environment.py +++ b/scripts/pylib/twister/twisterlib/environment.py @@ -863,6 +863,13 @@ def __init__(self, options=None) -> None: self.board_roots = None self.outdir = None + self.snippet_roots = [Path(ZEPHYR_BASE)] + modules = zephyr_module.parse_modules(ZEPHYR_BASE) + for module in modules: + snippet_root = module.meta.get("build", {}).get("settings", {}).get("snippet_root") + if snippet_root: + self.snippet_roots.append(Path(module.project) / snippet_root) + self.hwm = None self.test_config = options.test_config if options else None diff --git a/scripts/pylib/twister/twisterlib/testplan.py b/scripts/pylib/twister/twisterlib/testplan.py index e813f031ee8..4ce4a8c317e 100755 --- a/scripts/pylib/twister/twisterlib/testplan.py +++ b/scripts/pylib/twister/twisterlib/testplan.py @@ -806,7 +806,7 @@ def apply_filters(self, **kwargs): if ts.required_snippets: missing_snippet = False snippet_args = {"snippets": ts.required_snippets} - found_snippets = snippets.find_snippets_in_roots(snippet_args, [Path(ZEPHYR_BASE), Path(ts.source_dir)]) + found_snippets = snippets.find_snippets_in_roots(snippet_args, [*self.env.snippet_roots, Path(ts.source_dir)]) # Search and check that all required snippet files are found for this_snippet in snippet_args['snippets']: From 9569e4410475fb62125e769a13222882902d8c75 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mart=C3=AD=20Bol=C3=ADvar?= Date: Wed, 17 Jan 2024 12:22:40 -0800 Subject: [PATCH 2424/3723] MAINTAINERS: retire myself as DT maintainer MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Unfortunately, I don't have the cycles to do this job well at the moment. Signed-off-by: Martí Bolívar --- MAINTAINERS.yml | 1 - 1 file changed, 1 deletion(-) diff --git a/MAINTAINERS.yml b/MAINTAINERS.yml index 6147f245e46..d0e881447f2 100644 --- a/MAINTAINERS.yml +++ b/MAINTAINERS.yml @@ -712,7 +712,6 @@ DFU: Devicetree: status: maintained maintainers: - - mbolivar-ampere - galak files: - scripts/dts/ From b98c7942ca8dd9d0953a8faae0d43fe01aeff8f0 Mon Sep 17 00:00:00 2001 From: Erwan Gouriou Date: Fri, 12 Jan 2024 15:15:55 +0100 Subject: [PATCH 2425/3723] pm: console: Use async runtime put to minimize resumption/suspension When device runtime pm is enabled on console device, do not suspend device synchronously on each char transmission, but rather use asynchronous suspension request. This will save useless and costly suspension/resumption procedure, which can involve uart device clock suspension but also pin configuration to sleep state (which itself involves gpio clock activation ...). On STM32, using asynch device suspension allows to divide by 3 the transmission time of a character chain. Signed-off-by: Erwan Gouriou --- drivers/console/uart_console.c | 7 +++++-- subsys/logging/backends/log_backend_uart.c | 7 +++++-- 2 files changed, 10 insertions(+), 4 deletions(-) diff --git a/drivers/console/uart_console.c b/drivers/console/uart_console.c index 6cdf6e43856..5e5e10963f0 100644 --- a/drivers/console/uart_console.c +++ b/drivers/console/uart_console.c @@ -99,8 +99,11 @@ static int console_out(int c) } uart_poll_out(uart_console_dev, c); - /* As errors cannot be returned, ignore the return value */ - (void)pm_device_runtime_put(uart_console_dev); + /* Use async put to avoid useless device suspension/resumption + * when tranmiting chain of chars. + * As errors cannot be returned, ignore the return value + */ + (void)pm_device_runtime_put_async(uart_console_dev, K_MSEC(1)); return c; } diff --git a/subsys/logging/backends/log_backend_uart.c b/subsys/logging/backends/log_backend_uart.c index 4173180f627..0cb3e29df1a 100644 --- a/subsys/logging/backends/log_backend_uart.c +++ b/subsys/logging/backends/log_backend_uart.c @@ -114,8 +114,11 @@ static int char_out(uint8_t *data, size_t length, void *ctx) (void)err; cleanup: - /* As errors cannot be returned, ignore the return value */ - (void)pm_device_runtime_put(uart_dev); + /* Use async put to avoid useless device suspension/resumption + * when tranmiting chain of chars. + * As errors cannot be returned, ignore the return value + */ + (void)pm_device_runtime_put_async(uart_dev, K_MSEC(1)); return length; } From d5026c6c6bb3d749cf86bfe197c4161c2245a23a Mon Sep 17 00:00:00 2001 From: Dino Li Date: Mon, 15 Jan 2024 17:02:30 +0800 Subject: [PATCH 2426/3723] drivers/pinctrl: it8xxx2: Modify the sequence of pinctrl setting Modify the sequence of pinctrl setting. Default setting as input mode prevents leakage during changes to extended setting. Signed-off-by: Tim Lin Signed-off-by: Dino Li --- drivers/pinctrl/pinctrl_ite_it8xxx2.c | 27 +++++++++++++++------------ 1 file changed, 15 insertions(+), 12 deletions(-) diff --git a/drivers/pinctrl/pinctrl_ite_it8xxx2.c b/drivers/pinctrl/pinctrl_ite_it8xxx2.c index 886a035483f..449e90953f0 100644 --- a/drivers/pinctrl/pinctrl_ite_it8xxx2.c +++ b/drivers/pinctrl/pinctrl_ite_it8xxx2.c @@ -144,22 +144,24 @@ static int pinctrl_gpio_it8xxx2_configure_pins(const pinctrl_soc_pin_t *pins) return -EINVAL; } + /* + * Default input mode prevents leakage during changes to extended + * setting (e.g. enabling i2c functionality on GPIO E1/E2 on IT82002) + */ + *reg_gpcr = (*reg_gpcr | GPCR_PORT_PIN_MODE_INPUT) & + ~GPCR_PORT_PIN_MODE_OUTPUT; + /* * If pincfg is input, we don't need to handle * alternate function. */ if (IT8XXX2_DT_PINCFG_INPUT(pins->pincfg)) { - *reg_gpcr = (*reg_gpcr | GPCR_PORT_PIN_MODE_INPUT) & - ~GPCR_PORT_PIN_MODE_OUTPUT; return 0; } /* * Handle alternate function. */ - /* Common settings for alternate function. */ - *reg_gpcr &= ~(GPCR_PORT_PIN_MODE_INPUT | - GPCR_PORT_PIN_MODE_OUTPUT); /* Ensure that func3-ext setting is in default state. */ if (reg_func3_ext != NULL) { *reg_func3_ext &= ~gpio->func3_ext_mask[pin]; @@ -167,12 +169,11 @@ static int pinctrl_gpio_it8xxx2_configure_pins(const pinctrl_soc_pin_t *pins) switch (pins->alt_func) { case IT8XXX2_ALT_FUNC_1: - /* Func1: Alternate function has been set above. */ + /* Func1: Alternate function will be set below. */ break; case IT8XXX2_ALT_FUNC_2: - /* Func2: WUI function: turn the pin into an input */ - *reg_gpcr |= GPCR_PORT_PIN_MODE_INPUT; - break; + /* Func2: WUI function: pin has been set as input above.*/ + return 0; case IT8XXX2_ALT_FUNC_3: /* * Func3: In addition to the alternate setting above, @@ -193,16 +194,18 @@ static int pinctrl_gpio_it8xxx2_configure_pins(const pinctrl_soc_pin_t *pins) *reg_func4_gcr |= gpio->func4_en_mask[pin]; break; case IT8XXX2_ALT_DEFAULT: - *reg_gpcr = (*reg_gpcr | GPCR_PORT_PIN_MODE_INPUT) & - ~GPCR_PORT_PIN_MODE_OUTPUT; *reg_func3_gcr &= ~gpio->func3_en_mask[pin]; *reg_func4_gcr &= ~gpio->func4_en_mask[pin]; - break; + return 0; default: LOG_ERR("This function is not supported."); return -EINVAL; } + /* Common settings for alternate function. */ + *reg_gpcr &= ~(GPCR_PORT_PIN_MODE_INPUT | + GPCR_PORT_PIN_MODE_OUTPUT); + return 0; } From 71271307fe12c26fc9172dab4682ccaa92057f9b Mon Sep 17 00:00:00 2001 From: Tim Lin Date: Thu, 11 Jan 2024 15:20:15 +0800 Subject: [PATCH 2427/3723] ITE: drivers/i2c: Extended setting required to use i2c5 In addition to setting SMB5PS, PMER1 also needs to be set when using i2c5. Signed-off-by: Tim Lin --- dts/riscv/ite/it82xx2.dtsi | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/dts/riscv/ite/it82xx2.dtsi b/dts/riscv/ite/it82xx2.dtsi index 6b3eea97aa9..b6de6c64586 100644 --- a/dts/riscv/ite/it82xx2.dtsi +++ b/dts/riscv/ite/it82xx2.dtsi @@ -525,6 +525,10 @@ NO_FUNC 0xf03e10 NO_FUNC 0xf02032>; func3-en-mask = <0x01 0x20 0x20 0 0 0x08 0 0x01 >; + func3-ext = ; + func3-ext-mask = <0 0x02 0x02 0 + 0 0 0 0 >; func4-gcr = <0xf03e13 NO_FUNC NO_FUNC NO_FUNC NO_FUNC NO_FUNC NO_FUNC NO_FUNC >; func4-en-mask = <0x01 0 0 0 From b09cd0308549da1b2dfbc21c0bf9078e91ade8ca Mon Sep 17 00:00:00 2001 From: Dino Li Date: Mon, 15 Jan 2024 18:11:30 +0800 Subject: [PATCH 2428/3723] soc: it8xxx2: Disable EGAD pin output of external gpio control Setting IT8XXX2_EGPIO_EEPODD bit will disable EGAD pin output driving to avoid leakage when GPIO E1/E2 on it82002 are set to alternate function. Signed-off-by: Tim Lin Signed-off-by: Dino Li --- soc/riscv/ite_ec/common/chip_chipregs.h | 11 +++++++++++ soc/riscv/ite_ec/it8xxx2/soc.c | 5 +++++ 2 files changed, 16 insertions(+) diff --git a/soc/riscv/ite_ec/common/chip_chipregs.h b/soc/riscv/ite_ec/common/chip_chipregs.h index 14130648435..4a5ca269d01 100644 --- a/soc/riscv/ite_ec/common/chip_chipregs.h +++ b/soc/riscv/ite_ec/common/chip_chipregs.h @@ -45,6 +45,17 @@ #define IT8XXX2_GCTRL_BASE 0x00F02000 #define IT8XXX2_GCTRL_EIDSR ECREG(IT8XXX2_GCTRL_BASE + 0x31) +/* --- External GPIO Control (EGPIO) --- */ +#define IT8XXX2_EGPIO_BASE 0x00F02100 +#define IT8XXX2_EGPIO_EGCR ECREG(IT8XXX2_EGPIO_BASE + 0x04) + +/* EGPIO register fields */ +/* + * 0x04: External GPIO Control + * BIT(4): EXGPIO EGAD Pin Output Driving Disable + */ +#define IT8XXX2_EGPIO_EEPODD BIT(4) + /** * * (11xxh) Interrupt controller (INTC) diff --git a/soc/riscv/ite_ec/it8xxx2/soc.c b/soc/riscv/ite_ec/it8xxx2/soc.c index 7bf213ad695..0808955a6ae 100644 --- a/soc/riscv/ite_ec/it8xxx2/soc.c +++ b/soc/riscv/ite_ec/it8xxx2/soc.c @@ -287,6 +287,11 @@ static int ite_it8xxx2_init(void) IT8XXX2_SMB_SFFCTL &= ~IT8XXX2_SMB_HSAPE; #elif CONFIG_SOC_IT8XXX2_REG_SET_V2 IT8XXX2_SMB_SCLKTS_BRGS &= ~IT8XXX2_SMB_PREDEN; + /* + * Setting this bit will disable EGAD pin output driving to avoid + * leakage when GPIO E1/E2 on it82002 are set to alternate function. + */ + IT8XXX2_EGPIO_EGCR |= IT8XXX2_EGPIO_EEPODD; #endif #if DT_NODE_HAS_STATUS(DT_NODELABEL(uart1), okay) From b8008c4727ceeb08496c390bc535058892439f33 Mon Sep 17 00:00:00 2001 From: Yong Cong Sin Date: Mon, 8 Jan 2024 17:54:16 +0800 Subject: [PATCH 2429/3723] shell: shell_uart: improve macro compatibility with previous version The `SHELL_UART_DEFINE` macro was previously `SHELL_UART_DEFINE(_name, _tx_ringbuf_size, _rx_ringbuf_size)`, before it got removed in #63967 and then reinstated in #66218 as `SHELL_UART_DEFINE(_name)`. However its current form isn't compatible with previous Zephyr version, and would cause compilation error when an application migrates from to v3.6, let's modify it to accept variable arguments for now. Added documentation for this public API and updated the migration guide accordingly. Signed-off-by: Yong Cong Sin --- doc/releases/migration-guide-3.6.rst | 4 ++++ include/zephyr/shell/shell_uart.h | 8 +++++++- 2 files changed, 11 insertions(+), 1 deletion(-) diff --git a/doc/releases/migration-guide-3.6.rst b/doc/releases/migration-guide-3.6.rst index d763e9f5f45..822b090c17d 100644 --- a/doc/releases/migration-guide-3.6.rst +++ b/doc/releases/migration-guide-3.6.rst @@ -242,6 +242,10 @@ Shell * :kconfig:option:`CONFIG_W1_SHELL` * :kconfig:option:`CONFIG_WDT_SHELL` +* The ``SHELL_UART_DEFINE`` macro now only requires a ``_name`` argument. In the meantime, the + macro accepts additional arguments (ring buffer TX & RX size arguments) for compatibility with + previous Zephyr version, but they are ignored, and will be removed in future release. + Bootloader ========== diff --git a/include/zephyr/shell/shell_uart.h b/include/zephyr/shell/shell_uart.h index 065ee418037..e424a185768 100644 --- a/include/zephyr/shell/shell_uart.h +++ b/include/zephyr/shell/shell_uart.h @@ -81,7 +81,13 @@ struct shell_uart_polling { #define SHELL_UART_STRUCT struct shell_uart_int_driven #endif -#define SHELL_UART_DEFINE(_name) \ +/** + * @brief Macro for creating shell UART transport instance named @p _name + * + * @note Additional arguments are accepted (but ignored) for compatibility with + * previous Zephyr version, it will be removed in future release. + */ +#define SHELL_UART_DEFINE(_name, ...) \ static SHELL_UART_STRUCT _name##_shell_uart; \ struct shell_transport _name = { \ .api = &shell_uart_transport_api, \ From 72758f96d1529e72c9fc00f1a270fd2211bb6d7b Mon Sep 17 00:00:00 2001 From: Mykola Kvach Date: Fri, 14 Apr 2023 04:51:38 +0300 Subject: [PATCH 2430/3723] drivers: pinctrl: pfc_rcar: add support of voltage control to pfc driver Add support of voltage control to Renesas PFC driver. Voltage register mappings have been added to r8a77951 and r8a77961 SoCs. Allow 'power-source' property for 'renesas,rcar-pfc' node. This property will be used for configuring IO voltage on appropriate pin. For now it is possible to have only two voltages: 1.8 and 3.3. Note: it is possible to change voltage only for SD/MMC pins on r8a77951 and r8a77961 SoCs. Signed-off-by: Mykola Kvach --- drivers/pinctrl/Kconfig.rcar | 5 + drivers/pinctrl/pfc_rcar.c | 118 ++++++++++++++++++ dts/bindings/pinctrl/renesas,rcar-pfc.yaml | 2 + .../pinctrl/renesas/pinctrl-rcar-common.h | 4 + soc/arm/renesas_rcar/common/pinctrl_rcar.h | 5 + soc/arm64/renesas_rcar/gen3/pinctrl_soc.h | 5 + 6 files changed, 139 insertions(+) diff --git a/drivers/pinctrl/Kconfig.rcar b/drivers/pinctrl/Kconfig.rcar index 5aabd54371d..cc3ff51b9d6 100644 --- a/drivers/pinctrl/Kconfig.rcar +++ b/drivers/pinctrl/Kconfig.rcar @@ -7,3 +7,8 @@ config PINCTRL_RCAR_PFC depends on DT_HAS_RENESAS_RCAR_PFC_ENABLED help Enable pin controller driver for Renesas RCar SoC + +config PINCTRL_RCAR_VOLTAGE_CONTROL + bool "Voltage control functionality of Renesas R-Car PFC driver" + default y if SOC_SERIES_RCAR_GEN3 + depends on PINCTRL_RCAR_PFC diff --git a/drivers/pinctrl/pfc_rcar.c b/drivers/pinctrl/pfc_rcar.c index 26c5d08c20b..17e4146bbaa 100644 --- a/drivers/pinctrl/pfc_rcar.c +++ b/drivers/pinctrl/pfc_rcar.c @@ -35,6 +35,14 @@ static const uintptr_t reg_base[] = { #error Unsupported SoC Series #endif +#ifdef CONFIG_PINCTRL_RCAR_VOLTAGE_CONTROL +/* POC Control Register can control IO voltage level that is supplied to the pin */ +struct pfc_pocctrl_reg { + uint32_t offset; + const uint16_t pins[32]; +}; +#endif /* CONFIG_PINCTRL_RCAR_VOLTAGE_CONTROL */ + /* * Each drive step is either encoded in 2 or 3 bits. * So based on a 24 mA maximum value each step is either @@ -189,6 +197,110 @@ int pfc_rcar_set_bias(uintptr_t pfc_base, uint16_t pin, uint16_t flags) return 0; } +#ifdef CONFIG_PINCTRL_RCAR_VOLTAGE_CONTROL + +const struct pfc_pocctrl_reg pfc_r8a77951_r8a77961_volt_regs[] = { + { + .offset = 0x0380, + .pins = { + [0] = RCAR_GP_PIN(3, 0), /* SD0_CLK */ + [1] = RCAR_GP_PIN(3, 1), /* SD0_CMD */ + [2] = RCAR_GP_PIN(3, 2), /* SD0_DAT0 */ + [3] = RCAR_GP_PIN(3, 3), /* SD0_DAT1 */ + [4] = RCAR_GP_PIN(3, 4), /* SD0_DAT2 */ + [5] = RCAR_GP_PIN(3, 5), /* SD0_DAT3 */ + [6] = RCAR_GP_PIN(3, 6), /* SD1_CLK */ + [7] = RCAR_GP_PIN(3, 7), /* SD1_CMD */ + [8] = RCAR_GP_PIN(3, 8), /* SD1_DAT0 */ + [9] = RCAR_GP_PIN(3, 9), /* SD1_DAT1 */ + [10] = RCAR_GP_PIN(3, 10), /* SD1_DAT2 */ + [11] = RCAR_GP_PIN(3, 11), /* SD1_DAT3 */ + [12] = RCAR_GP_PIN(4, 0), /* SD2_CLK */ + [13] = RCAR_GP_PIN(4, 1), /* SD2_CMD */ + [14] = RCAR_GP_PIN(4, 2), /* SD2_DAT0 */ + [15] = RCAR_GP_PIN(4, 3), /* SD2_DAT1 */ + [16] = RCAR_GP_PIN(4, 4), /* SD2_DAT2 */ + [17] = RCAR_GP_PIN(4, 5), /* SD2_DAT3 */ + [18] = RCAR_GP_PIN(4, 6), /* SD2_DS */ + [19] = RCAR_GP_PIN(4, 7), /* SD3_CLK */ + [20] = RCAR_GP_PIN(4, 8), /* SD3_CMD */ + [21] = RCAR_GP_PIN(4, 9), /* SD3_DAT0 */ + [22] = RCAR_GP_PIN(4, 10), /* SD3_DAT1 */ + [23] = RCAR_GP_PIN(4, 11), /* SD3_DAT2 */ + [24] = RCAR_GP_PIN(4, 12), /* SD3_DAT3 */ + [25] = RCAR_GP_PIN(4, 13), /* SD3_DAT4 */ + [26] = RCAR_GP_PIN(4, 14), /* SD3_DAT5 */ + [27] = RCAR_GP_PIN(4, 15), /* SD3_DAT6 */ + [28] = RCAR_GP_PIN(4, 16), /* SD3_DAT7 */ + [29] = RCAR_GP_PIN(4, 17), /* SD3_DS */ + [30] = -1, + [31] = -1, + } + }, + { /* sentinel */ }, +}; + +static const struct pfc_pocctrl_reg *pfc_rcar_get_io_voltage_regs(void) +{ + return pfc_r8a77951_r8a77961_volt_regs; +} + +static const struct pfc_pocctrl_reg *pfc_rcar_get_pocctrl_reg(uint16_t pin, uint8_t *bit) +{ + const struct pfc_pocctrl_reg *voltage_regs = pfc_rcar_get_io_voltage_regs(); + + BUILD_ASSERT(ARRAY_SIZE(voltage_regs->pins) < UINT8_MAX); + + /* Loop around all the registers to find the bit for a given pin */ + while (voltage_regs && voltage_regs->offset) { + uint8_t i; + + for (i = 0U; i < ARRAY_SIZE(voltage_regs->pins); i++) { + if (voltage_regs->pins[i] == pin) { + *bit = i; + return voltage_regs; + } + } + voltage_regs++; + } + + return NULL; +} + +static void pfc_rcar_set_voltage(uintptr_t pfc_base, uint16_t pin, uint16_t voltage) +{ + uint32_t val; + uint8_t bit; + const struct pfc_pocctrl_reg *voltage_reg; + + voltage_reg = pfc_rcar_get_pocctrl_reg(pin, &bit); + if (!voltage_reg) { + return; + } + + val = sys_read32(pfc_base + voltage_reg->offset); + + switch (voltage) { + case PIN_VOLTAGE_1P8V: + if (!(val & BIT(bit))) { + return; + } + val &= ~BIT(bit); + break; + case PIN_VOLTAGE_3P3V: + if (val & BIT(bit)) { + return; + } + val |= BIT(bit); + break; + default: + break; + } + + pfc_rcar_write(pfc_base, voltage_reg->offset, val); +} +#endif /* CONFIG_PINCTRL_RCAR_VOLTAGE_CONTROL */ + int pinctrl_configure_pin(const pinctrl_soc_pin_t *pin) { int ret = 0; @@ -214,6 +326,12 @@ int pinctrl_configure_pin(const pinctrl_soc_pin_t *pin) return -EINVAL; } +#ifdef CONFIG_PINCTRL_RCAR_VOLTAGE_CONTROL + if (pin->voltage != PIN_VOLTAGE_NONE) { + pfc_rcar_set_voltage(pfc_base, pin->pin, pin->voltage); + } +#endif + /* Select function for pin */ if ((pin->flags & RCAR_PIN_FLAGS_FUNC_SET) != 0U) { pfc_rcar_set_ipsr(pfc_base, &pin->func); diff --git a/dts/bindings/pinctrl/renesas,rcar-pfc.yaml b/dts/bindings/pinctrl/renesas,rcar-pfc.yaml index fa94cd11c05..8d7ee2c6bbb 100644 --- a/dts/bindings/pinctrl/renesas,rcar-pfc.yaml +++ b/dts/bindings/pinctrl/renesas,rcar-pfc.yaml @@ -51,6 +51,7 @@ description: | - bias-pull-down - bias-pull-up - drive-strength + - power-source To link pin configurations with a device, use a pinctrl-N property for some number N, like this example you could place in your board's DTS file: @@ -82,6 +83,7 @@ child-binding: - bias-pull-down - bias-pull-up - drive-strength + - power-source properties: pin: diff --git a/include/zephyr/dt-bindings/pinctrl/renesas/pinctrl-rcar-common.h b/include/zephyr/dt-bindings/pinctrl/renesas/pinctrl-rcar-common.h index 504ee2a4d55..f483ec1bb49 100644 --- a/include/zephyr/dt-bindings/pinctrl/renesas/pinctrl-rcar-common.h +++ b/include/zephyr/dt-bindings/pinctrl/renesas/pinctrl-rcar-common.h @@ -72,4 +72,8 @@ #define IP2SR5(shift, func) IPnSR(2, 5, shift, func) #define IP3SR5(shift, func) IPnSR(3, 5, shift, func) +#define PIN_VOLTAGE_NONE 0 +#define PIN_VOLTAGE_1P8V 1 +#define PIN_VOLTAGE_3P3V 2 + #endif /* ZEPHYR_INCLUDE_DT_BINDINGS_PINCTRL_RENESAS_PINCTRL_RCAR_COMMON_H_ */ diff --git a/soc/arm/renesas_rcar/common/pinctrl_rcar.h b/soc/arm/renesas_rcar/common/pinctrl_rcar.h index 0533649d413..c3563e014ba 100644 --- a/soc/arm/renesas_rcar/common/pinctrl_rcar.h +++ b/soc/arm/renesas_rcar/common/pinctrl_rcar.h @@ -38,6 +38,7 @@ typedef struct pinctrl_soc_pin { struct rcar_pin_func func; uint8_t flags; uint8_t drive_strength; + uint8_t voltage; } pinctrl_soc_pin_t; #define RCAR_IPSR(node_id) DT_PROP_BY_IDX(node_id, pin, 1) @@ -66,6 +67,10 @@ typedef struct pinctrl_soc_pin { .drive_strength = \ COND_CODE_1(DT_NODE_HAS_PROP(node_id, drive_strength), \ (DT_PROP(node_id, drive_strength)), (0)), \ + .voltage = COND_CODE_1(DT_NODE_HAS_PROP(node_id, \ + power_source), \ + (DT_PROP(node_id, power_source)), \ + (PIN_VOLTAGE_NONE)), \ }, /** diff --git a/soc/arm64/renesas_rcar/gen3/pinctrl_soc.h b/soc/arm64/renesas_rcar/gen3/pinctrl_soc.h index 72c07ae9a4f..0b80eb46634 100644 --- a/soc/arm64/renesas_rcar/gen3/pinctrl_soc.h +++ b/soc/arm64/renesas_rcar/gen3/pinctrl_soc.h @@ -37,6 +37,7 @@ typedef struct pinctrl_soc_pin { struct rcar_pin_func func; uint8_t flags; uint8_t drive_strength; + uint8_t voltage; } pinctrl_soc_pin_t; #define RCAR_IPSR(node_id) DT_PROP_BY_IDX(node_id, pin, 1) @@ -65,6 +66,10 @@ typedef struct pinctrl_soc_pin { .drive_strength = \ COND_CODE_1(DT_NODE_HAS_PROP(node_id, drive_strength), \ (DT_PROP(node_id, drive_strength)), (0)), \ + .voltage = COND_CODE_1(DT_NODE_HAS_PROP(node_id, \ + power_source), \ + (DT_PROP(node_id, power_source)), \ + (PIN_VOLTAGE_NONE)), \ }, /** From 1217656a2400cf34f0d39b2b534b70de5fb51f73 Mon Sep 17 00:00:00 2001 From: Greter Raffael Date: Thu, 21 Dec 2023 12:41:59 +0000 Subject: [PATCH 2431/3723] riscv: irq: Set prio for dynamic and direct irqs on clic The irq priority has to be called for dynamic and direct irqs, too. For direct isrs, this was missing completely, for direct irqs just for the clic. For dynamic irqs, I replaced the current implementation with `z_riscv_irq_priority_set`. For the plic, this is exaclty the same. Signed-off-by: Greter Raffael --- arch/riscv/core/irq_manage.c | 9 +++------ include/zephyr/arch/riscv/irq.h | 1 + 2 files changed, 4 insertions(+), 6 deletions(-) diff --git a/arch/riscv/core/irq_manage.c b/arch/riscv/core/irq_manage.c index f95b099a4da..bf0b6684a5d 100644 --- a/arch/riscv/core/irq_manage.c +++ b/arch/riscv/core/irq_manage.c @@ -43,15 +43,12 @@ int arch_irq_connect_dynamic(unsigned int irq, unsigned int priority, void (*routine)(const void *parameter), const void *parameter, uint32_t flags) { - ARG_UNUSED(flags); - z_isr_install(irq, routine, parameter); -#if defined(CONFIG_RISCV_HAS_PLIC) - if (irq_get_level(irq) == 2) { - riscv_plic_set_priority(irq, priority); - } +#if defined(CONFIG_RISCV_HAS_PLIC) || defined(CONFIG_RISCV_HAS_CLIC) + z_riscv_irq_priority_set(irq, priority, flags); #else + ARG_UNUSED(flags); ARG_UNUSED(priority); #endif return irq; diff --git a/include/zephyr/arch/riscv/irq.h b/include/zephyr/arch/riscv/irq.h index 84d3a4949a9..cf646809898 100644 --- a/include/zephyr/arch/riscv/irq.h +++ b/include/zephyr/arch/riscv/irq.h @@ -70,6 +70,7 @@ extern void z_riscv_irq_priority_set(unsigned int irq, { \ Z_ISR_DECLARE(irq_p + CONFIG_RISCV_RESERVED_IRQ_ISR_TABLES_OFFSET, \ ISR_FLAG_DIRECT, isr_p, NULL); \ + z_riscv_irq_priority_set(irq_p, priority_p, flags_p); \ } #define ARCH_ISR_DIRECT_HEADER() arch_isr_direct_header() From bc2e157cbad2995604acd08454f09997d351ffaf Mon Sep 17 00:00:00 2001 From: Greter Raffael Date: Thu, 21 Dec 2023 12:41:59 +0000 Subject: [PATCH 2432/3723] riscv: irq: Correct CLIC_INTATTR_TRIG_Msk The trig field of clicintattr is indeed in bits 2:1. However, the mask `CLIC_INTATTR_TRIG_Msk` is only applied directly to the bitfield `INTATTR.b.trg`. Therefore it doesn't have to be shifted additionally. Signed-off-by: Greter Raffael --- drivers/interrupt_controller/intc_nuclei_eclic.c | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/drivers/interrupt_controller/intc_nuclei_eclic.c b/drivers/interrupt_controller/intc_nuclei_eclic.c index 7c112c1a63f..fbef601d171 100644 --- a/drivers/interrupt_controller/intc_nuclei_eclic.c +++ b/drivers/interrupt_controller/intc_nuclei_eclic.c @@ -88,10 +88,8 @@ struct CLICCTRL { /** ECLIC Mode mask for MTVT CSR Register */ #define ECLIC_MODE_MTVEC_Msk 3U -/** CLIC INTATTR: TRIG Position */ -#define CLIC_INTATTR_TRIG_Pos 1U /** CLIC INTATTR: TRIG Mask */ -#define CLIC_INTATTR_TRIG_Msk (0x3UL << CLIC_INTATTR_TRIG_Pos) +#define CLIC_INTATTR_TRIG_Msk 0x3U #define ECLIC_CFG (*((volatile union CLICCFG *)(DT_REG_ADDR_BY_IDX(DT_NODELABEL(eclic), 0)))) #define ECLIC_INFO (*((volatile union CLICINFO *)(DT_REG_ADDR_BY_IDX(DT_NODELABEL(eclic), 1)))) From ef5c28cab29d75e5db5fd843b3e7d81a0a12afb0 Mon Sep 17 00:00:00 2001 From: Greter Raffael Date: Thu, 21 Dec 2023 12:41:59 +0000 Subject: [PATCH 2433/3723] riscv: irq: Set selective hardware vectoring The mechanism for hardware vectoring has changed in the clic spec (https://github.com/riscv/riscv-fast-interrupt) in 2019. Before vectoring was enabled via `mode` bits in `mtvec`. Support for this was added in fc480c9382a218130eaf7308cbbad7194c71b414. With more current clic implementations, this does not work anymore. Changing the `mode` bits is reserved. Vectoring can be enabled individually in the `shv` bit of `clicintattr[i]`. Since the old mechanism is still used, I added a new Kconfig for it. If this Kconfig is not set, we use the `shv` bit for harware vectoring. Signed-off-by: Greter Raffael --- drivers/interrupt_controller/Kconfig.clic | 7 +++++++ drivers/interrupt_controller/intc_nuclei_eclic.c | 15 +++++++++++++-- 2 files changed, 20 insertions(+), 2 deletions(-) diff --git a/drivers/interrupt_controller/Kconfig.clic b/drivers/interrupt_controller/Kconfig.clic index 729f4e7e0f5..95c7004ce19 100644 --- a/drivers/interrupt_controller/Kconfig.clic +++ b/drivers/interrupt_controller/Kconfig.clic @@ -8,3 +8,10 @@ config NUCLEI_ECLIC select MULTI_LEVEL_INTERRUPTS help Interrupt controller for Nuclei SoC core. + +config LEGACY_CLIC + bool "Use the legacy clic specification" + depends on RISCV_HAS_CLIC + help + Enables legacy clic, where smclicshv extension is not supported and + hardware vectoring is set via mode bits of mtvec. diff --git a/drivers/interrupt_controller/intc_nuclei_eclic.c b/drivers/interrupt_controller/intc_nuclei_eclic.c index fbef601d171..45648923a3d 100644 --- a/drivers/interrupt_controller/intc_nuclei_eclic.c +++ b/drivers/interrupt_controller/intc_nuclei_eclic.c @@ -156,8 +156,19 @@ void riscv_clic_irq_priority_set(uint32_t irq, uint32_t pri, uint32_t flags) ECLIC_CTRL[irq].INTCTRL = intctrl; - ECLIC_CTRL[irq].INTATTR.b.shv = 0; - ECLIC_CTRL[irq].INTATTR.b.trg = (uint8_t)(flags & CLIC_INTATTR_TRIG_Msk); + union CLICINTATTR intattr = {.w = 0}; +#if defined(CONFIG_RISCV_VECTORED_MODE) && !defined(CONFIG_LEGACY_CLIC) + /* + * Set Selective Hardware Vectoring. + * Legacy SiFive does not implement smclicshv extension and vectoring is + * enabled in the mode bits of mtvec. + */ + intattr.b.shv = 1; +#else + intattr.b.shv = 0; +#endif + intattr.b.trg = (uint8_t)(flags & CLIC_INTATTR_TRIG_Msk); + ECLIC_CTRL[irq].INTATTR = intattr; } static int nuclei_eclic_init(const struct device *dev) From 899ee686d8ed973cdf254df2e7395476e691bf2b Mon Sep 17 00:00:00 2001 From: Greter Raffael Date: Thu, 21 Dec 2023 15:15:19 +0000 Subject: [PATCH 2434/3723] riscv: irq: Adjust initialization of mtvec in non-legacy CLIC If CONFIG_LEGACY_CLIC is disabled, i.e. we adhere to the current CLIC spec, the mode bits of mtvec have to be 0x3. Everything else is reserved. Therefore if CONFIG_RISCV_VECTORED_MODE is enabled, the current implementation is correct. If CONFIG_RISCV_VECTORED_MODE is disabled, the mode bits have to be set, too. Signed-off-by: Greter Raffael --- soc/riscv/common/riscv-privileged/vector.S | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/soc/riscv/common/riscv-privileged/vector.S b/soc/riscv/common/riscv-privileged/vector.S index 5883bdcca85..bb113457874 100644 --- a/soc/riscv/common/riscv-privileged/vector.S +++ b/soc/riscv/common/riscv-privileged/vector.S @@ -76,6 +76,14 @@ SECTION_FUNC(vectors, __start) #else /* !CONFIG_RISCV_VECTORED_MODE */ +#if defined(CONFIG_RISCV_HAS_CLIC) && !defined(CONFIG_LEGACY_CLIC) + + la t0, _isr_wrapper + addi t0, t0, 0x03 /* Set mode bits to 3, signifying CLIC. Everything else is reserved. */ + csrw mtvec, t0 + +#else /* !CONFIG_RISCV_HAS_CLIC || CONFIG_LEGACY_CLIC */ + /* * CLINT direct mode * @@ -85,6 +93,8 @@ SECTION_FUNC(vectors, __start) la t0, _isr_wrapper csrw mtvec, t0 +#endif /* CONFIG_RISCV_HAS_CLIC&& !CONFIG_LEGACY_CLIC */ + #endif /* CONFIG_RISCV_VECTORED_MODE */ /* Jump to __reset */ From 5b19fcd7e88283c6dc01c955766f1833236f0af6 Mon Sep 17 00:00:00 2001 From: Greter Raffael Date: Thu, 21 Dec 2023 12:41:59 +0000 Subject: [PATCH 2435/3723] riscv: irq: Add trigger_irq function for clic In a clic the mip register does not exist and software irq are triggered in the clicintip register. Signed-off-by: Greter Raffael --- drivers/interrupt_controller/intc_nuclei_eclic.c | 8 ++++++++ subsys/testsuite/include/zephyr/interrupt_util.h | 9 ++++++++- 2 files changed, 16 insertions(+), 1 deletion(-) diff --git a/drivers/interrupt_controller/intc_nuclei_eclic.c b/drivers/interrupt_controller/intc_nuclei_eclic.c index 45648923a3d..fdd9d6ea93b 100644 --- a/drivers/interrupt_controller/intc_nuclei_eclic.c +++ b/drivers/interrupt_controller/intc_nuclei_eclic.c @@ -171,6 +171,14 @@ void riscv_clic_irq_priority_set(uint32_t irq, uint32_t pri, uint32_t flags) ECLIC_CTRL[irq].INTATTR = intattr; } +/** + * @brief Set pending bit of an interrupt + */ +void riscv_clic_irq_set_pending(uint32_t irq) +{ + ECLIC_CTRL[irq].INTIP.b.IP = 1; +} + static int nuclei_eclic_init(const struct device *dev) { /* check hardware support required interrupt levels */ diff --git a/subsys/testsuite/include/zephyr/interrupt_util.h b/subsys/testsuite/include/zephyr/interrupt_util.h index 616309c3eb9..61d1206d5f8 100644 --- a/subsys/testsuite/include/zephyr/interrupt_util.h +++ b/subsys/testsuite/include/zephyr/interrupt_util.h @@ -166,6 +166,13 @@ static inline void trigger_irq(int irq) } #elif defined(CONFIG_RISCV) +#if defined(CONFIG_NUCLEI_ECLIC) +void riscv_clic_irq_set_pending(uint32_t irq); +static inline void trigger_irq(int irq) +{ + riscv_clic_irq_set_pending(irq); +} +#else static inline void trigger_irq(int irq) { uint32_t mip; @@ -174,7 +181,7 @@ static inline void trigger_irq(int irq) : "=r" (mip) : "r" (1 << irq)); } - +#endif #elif defined(CONFIG_XTENSA) static inline void trigger_irq(int irq) { From 9c955ce869d67d9805d14b479910393527d78ef2 Mon Sep 17 00:00:00 2001 From: Greter Raffael Date: Thu, 21 Dec 2023 12:41:59 +0000 Subject: [PATCH 2436/3723] test: gen_isr_table: Adjust test for clic The CLIC has different software-triggerable irqs than the PLIC. I adjusted them. Additionally, in a clic the the irq flag 0 would mean triggering on a positive level. To work with software-triggering, the irqs have to trigger on a positive edge, i.e. 1. Signed-off-by: Greter Raffael --- tests/kernel/gen_isr_table/src/main.c | 28 ++++++++++++++++++++------- 1 file changed, 21 insertions(+), 7 deletions(-) diff --git a/tests/kernel/gen_isr_table/src/main.c b/tests/kernel/gen_isr_table/src/main.c index 6a6938c8e32..2f6476a1f34 100644 --- a/tests/kernel/gen_isr_table/src/main.c +++ b/tests/kernel/gen_isr_table/src/main.c @@ -20,6 +20,13 @@ extern uint32_t _irq_vector_table[]; #endif #if defined(CONFIG_RISCV) +#if defined(CONFIG_RISCV_HAS_CLIC) +#define ISR1_OFFSET 3 +#define ISR3_OFFSET 17 +#define ISR5_OFFSET 18 +#define TRIG_CHECK_SIZE 19 +#else + /* RISC-V has very few IRQ lines which can be triggered from software */ #define ISR3_OFFSET 1 @@ -31,10 +38,11 @@ extern uint32_t _irq_vector_table[]; #else #define ISR5_OFFSET 5 #endif +#define TRIG_CHECK_SIZE 6 +#endif #define IRQ_LINE(offset) offset #define TABLE_INDEX(offset) offset -#define TRIG_CHECK_SIZE 6 #else #define ISR1_OFFSET 0 #define ISR2_OFFSET 1 @@ -90,6 +98,12 @@ extern uint32_t _irq_vector_table[]; #define ISR5_ARG 0xf0ccac1a #define ISR6_ARG 0xba5eba11 +#if defined(CONFIG_RISCV_HAS_CLIC) +#define IRQ_FLAGS 1 /* rising edge */ +#else +#define IRQ_FLAGS 0 +#endif + static volatile int trigger_check[TRIG_CHECK_SIZE]; #ifdef HAS_DIRECT_IRQS @@ -262,7 +276,7 @@ ZTEST(gen_isr_table, test_build_time_direct_interrupt) #else #ifdef ISR1_OFFSET - IRQ_DIRECT_CONNECT(IRQ_LINE(ISR1_OFFSET), 0, isr1, 0); + IRQ_DIRECT_CONNECT(IRQ_LINE(ISR1_OFFSET), 0, isr1, IRQ_FLAGS); irq_enable(IRQ_LINE(ISR1_OFFSET)); TC_PRINT("isr1 isr=%p irq=%d\n", isr1, IRQ_LINE(ISR1_OFFSET)); zassert_ok(check_vector(isr1, ISR1_OFFSET), @@ -270,7 +284,7 @@ ZTEST(gen_isr_table, test_build_time_direct_interrupt) #endif #ifdef ISR2_OFFSET - IRQ_DIRECT_CONNECT(IRQ_LINE(ISR2_OFFSET), 0, isr2, 0); + IRQ_DIRECT_CONNECT(IRQ_LINE(ISR2_OFFSET), 0, isr2, IRQ_FLAGS); irq_enable(IRQ_LINE(ISR2_OFFSET)); TC_PRINT("isr2 isr=%p irq=%d\n", isr2, IRQ_LINE(ISR2_OFFSET)); @@ -305,7 +319,7 @@ ZTEST(gen_isr_table, test_build_time_interrupt) TC_PRINT("_sw_isr_table at location %p\n", _sw_isr_table); #ifdef ISR3_OFFSET - IRQ_CONNECT(IRQ_LINE(ISR3_OFFSET), 1, isr3, ISR3_ARG, 0); + IRQ_CONNECT(IRQ_LINE(ISR3_OFFSET), 1, isr3, ISR3_ARG, IRQ_FLAGS); irq_enable(IRQ_LINE(ISR3_OFFSET)); TC_PRINT("isr3 isr=%p irq=%d param=%p\n", isr3, IRQ_LINE(ISR3_OFFSET), (void *)ISR3_ARG); @@ -315,7 +329,7 @@ ZTEST(gen_isr_table, test_build_time_interrupt) #endif #ifdef ISR4_OFFSET - IRQ_CONNECT(IRQ_LINE(ISR4_OFFSET), 1, isr4, ISR4_ARG, 0); + IRQ_CONNECT(IRQ_LINE(ISR4_OFFSET), 1, isr4, ISR4_ARG, IRQ_FLAGS); irq_enable(IRQ_LINE(ISR4_OFFSET)); TC_PRINT("isr4 isr=%p irq=%d param=%p\n", isr4, IRQ_LINE(ISR4_OFFSET), (void *)ISR4_ARG); @@ -351,7 +365,7 @@ ZTEST(gen_isr_table, test_run_time_interrupt) #ifdef ISR5_OFFSET irq_connect_dynamic(IRQ_LINE(ISR5_OFFSET), 1, isr5, - (const void *)ISR5_ARG, 0); + (const void *)ISR5_ARG, IRQ_FLAGS); irq_enable(IRQ_LINE(ISR5_OFFSET)); TC_PRINT("isr5 isr=%p irq=%d param=%p\n", isr5, IRQ_LINE(ISR5_OFFSET), (void *)ISR5_ARG); @@ -361,7 +375,7 @@ ZTEST(gen_isr_table, test_run_time_interrupt) #ifdef ISR6_OFFSET irq_connect_dynamic(IRQ_LINE(ISR6_OFFSET), 1, isr6, - (const void *)ISR6_ARG, 0); + (const void *)ISR6_ARG, IRQ_FLAGS); irq_enable(IRQ_LINE(ISR6_OFFSET)); TC_PRINT("isr6 isr=%p irq=%d param=%p\n", isr6, IRQ_LINE(ISR6_OFFSET), (void *)ISR6_ARG); From 08a2ca5b9bad5a8ed5d7ab708b645e874da5bd06 Mon Sep 17 00:00:00 2001 From: Greter Raffael Date: Thu, 21 Dec 2023 12:41:59 +0000 Subject: [PATCH 2437/3723] riscv: irq: Correct interrupt handling in clic non-vectored mode According to the clic specification (https://github.com/riscv/riscv-fast-interrupt), the mnxti register has be written, in order to clear the pending bit for non-vectored interrupts. For vectored interrupts, this is automatically done. From the spec: "If the pending interrupt is edge-triggered, hardware will automatically clear the corresponding pending bit when the CSR instruction that accesses xnxti includes a write." I added a kconfig `RISCV_SOC_HAS_CUSTOM_IRQ_HANDLING` to allow custom irq handling. If enabled, `__soc_handle_all_irqs` has to be implemented. For clic, non-vectored mode, I added a `__soc_handle_all_irqs`, that handles the pending interrupts according to the pseudo code in the spec. Signed-off-by: Greter Raffael --- arch/riscv/Kconfig | 7 ++ arch/riscv/core/isr.S | 10 +++ drivers/interrupt_controller/CMakeLists.txt | 1 + drivers/interrupt_controller/Kconfig.clic | 1 + .../interrupt_controller/intc_nuclei_eclic.S | 79 +++++++++++++++++++ 5 files changed, 98 insertions(+) create mode 100644 drivers/interrupt_controller/intc_nuclei_eclic.S diff --git a/arch/riscv/Kconfig b/arch/riscv/Kconfig index 1c5defbacaf..357cce3d118 100644 --- a/arch/riscv/Kconfig +++ b/arch/riscv/Kconfig @@ -84,6 +84,13 @@ config RISCV_SOC_HAS_ISR_STACKING saved on the stack by the hardware, and the registers saved by the software macros. The structure must be called '__esf'. +config RISCV_SOC_HAS_CUSTOM_IRQ_HANDLING + bool + help + This allows the SoC to overwrite the irq handling. If enabled, the + function __soc_handle_all_irqs has to be implemented. It shall service + and clear all pending interrupts. + config RISCV_SOC_HAS_CUSTOM_IRQ_LOCK_OPS bool help diff --git a/arch/riscv/core/isr.S b/arch/riscv/core/isr.S index 558d2a41fbe..04e829a726e 100644 --- a/arch/riscv/core/isr.S +++ b/arch/riscv/core/isr.S @@ -73,6 +73,10 @@ GTEXT(sys_trace_isr_exit) GDATA(_k_syscall_table) #endif +#ifdef CONFIG_RISCV_SOC_HAS_CUSTOM_IRQ_HANDLING +GTEXT(__soc_handle_all_irqs) +#endif + /* exports */ GTEXT(_isr_wrapper) @@ -522,6 +526,10 @@ is_interrupt: on_irq_stack: +#ifdef CONFIG_RISCV_SOC_HAS_CUSTOM_IRQ_HANDLING + call __soc_handle_all_irqs +#else + #ifdef CONFIG_TRACING_ISR call sys_trace_isr_enter #endif @@ -558,6 +566,8 @@ on_irq_stack: call sys_trace_isr_exit #endif +#endif + irq_done: /* Decrement _current_cpu->nested */ lw t2, ___cpu_t_nested_OFFSET(s0) diff --git a/drivers/interrupt_controller/CMakeLists.txt b/drivers/interrupt_controller/CMakeLists.txt index 989a75ab6dc..1d4175e5408 100644 --- a/drivers/interrupt_controller/CMakeLists.txt +++ b/drivers/interrupt_controller/CMakeLists.txt @@ -32,6 +32,7 @@ zephyr_library_sources_ifdef(CONFIG_SWERV_PIC intc_swerv_pic.c) zephyr_library_sources_ifdef(CONFIG_VEXRISCV_LITEX_IRQ intc_vexriscv_litex.c) zephyr_library_sources_ifdef(CONFIG_VIM intc_vim.c) zephyr_library_sources_ifdef(CONFIG_NUCLEI_ECLIC intc_nuclei_eclic.c) +zephyr_library_sources_ifdef(CONFIG_NUCLEI_ECLIC intc_nuclei_eclic.S) zephyr_library_sources_ifdef(CONFIG_NXP_S32_EIRQ intc_eirq_nxp_s32.c) zephyr_library_sources_ifdef(CONFIG_NXP_S32_WKPU intc_wkpu_nxp_s32.c) zephyr_library_sources_ifdef(CONFIG_XMC4XXX_INTC intc_xmc4xxx.c) diff --git a/drivers/interrupt_controller/Kconfig.clic b/drivers/interrupt_controller/Kconfig.clic index 95c7004ce19..a047a832331 100644 --- a/drivers/interrupt_controller/Kconfig.clic +++ b/drivers/interrupt_controller/Kconfig.clic @@ -6,6 +6,7 @@ config NUCLEI_ECLIC default y depends on DT_HAS_NUCLEI_ECLIC_ENABLED select MULTI_LEVEL_INTERRUPTS + select RISCV_SOC_HAS_CUSTOM_IRQ_HANDLING if !RISCV_VECTORED_MODE help Interrupt controller for Nuclei SoC core. diff --git a/drivers/interrupt_controller/intc_nuclei_eclic.S b/drivers/interrupt_controller/intc_nuclei_eclic.S new file mode 100644 index 00000000000..b077d281751 --- /dev/null +++ b/drivers/interrupt_controller/intc_nuclei_eclic.S @@ -0,0 +1,79 @@ +/* + * Copyright (c) 2024 Baumer Electric AG + * + * SPDX-License-Identifier: Apache-2.0 + */ + +/** + * @brief Assembler-hooks specific to Nuclei's Extended Core Interrupt Controller + */ + +#include + + +GTEXT(__soc_handle_irq) +/* + * In an ECLIC, pending interrupts don't have to be cleared by hand. + * In vectored mode, interrupts are cleared automatically. + * In non-vectored mode, interrupts are cleared when writing the mnxti register (done in + * __soc_handle_all_irqs). + * Thus this function can directly return. + */ +SECTION_FUNC(exception.other, __soc_handle_irq) + ret + +#if !defined(CONFIG_RISCV_VECTORED_MODE) + +GTEXT(__soc_handle_all_irqs) + +#ifdef CONFIG_TRACING +/* imports */ +GTEXT(sys_trace_isr_enter) +GTEXT(sys_trace_isr_exit) +#endif + +/* + * This function services and clears all pending interrupts for an ECLIC in non-vectored mode. + */ +SECTION_FUNC(exception.other, __soc_handle_all_irqs) + mv t2, ra + + /* Read and clear mnxti to get highest current interrupt and enable interrupts. Will return + * original interrupt if no others appear. */ + csrrci a0, 0x345, MSTATUS_IEN + beqz a0, irq_done /* Check if original interrupt vanished. */ + +irq_loop: + +#ifdef CONFIG_TRACING_ISR + call sys_trace_isr_enter +#endif + + /* Call corresponding registered function in _sw_isr_table. a0 is offset in words, table is + * 2-word wide -> shift by one */ + la t0, _sw_isr_table + slli a0, a0, (1) + add t0, t0, a0 + + /* Load argument in a0 register */ + lw a0, 0(t0) + + /* Load ISR function address in register t1 */ + lw t1, RV_REGSIZE(t0) + + /* Call ISR function */ + jalr ra, t1, 0 + + /* Read and clear mnxti to get highest current interrupt and enable interrupts. */ + csrrci a0, 0x345, MSTATUS_IEN + +#ifdef CONFIG_TRACING_ISR + call sys_trace_isr_exit +#endif + + bnez a0, irq_loop + +irq_done: + mv ra, t2 + ret +#endif From 85219ed13c2de410a4d2678a9f2e3dbbcd652692 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Micha=C5=82=20Barna=C5=9B?= Date: Fri, 13 Oct 2023 17:46:53 +0200 Subject: [PATCH 2438/3723] usbc: add API for the Power Path Controllers MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This commit adds an API to the Power Path Controllers (PPC) that may be used with USB-C subsystem to control the current paths, enabling and disabling sourcing and sinking VBUS and protect against shorts, overvoltage and overcurrent. Signed-off-by: Michał Barnaś --- drivers/usb_c/Kconfig | 1 + drivers/usb_c/ppc/Kconfig | 23 ++ include/zephyr/drivers/usb_c/usbc_ppc.h | 277 ++++++++++++++++++++++++ 3 files changed, 301 insertions(+) create mode 100644 drivers/usb_c/ppc/Kconfig create mode 100644 include/zephyr/drivers/usb_c/usbc_ppc.h diff --git a/drivers/usb_c/Kconfig b/drivers/usb_c/Kconfig index f62da2a67c7..b30259c80b4 100644 --- a/drivers/usb_c/Kconfig +++ b/drivers/usb_c/Kconfig @@ -5,3 +5,4 @@ source "drivers/usb_c/tcpc/Kconfig" source "drivers/usb_c/vbus/Kconfig" +source "drivers/usb_c/ppc/Kconfig" diff --git a/drivers/usb_c/ppc/Kconfig b/drivers/usb_c/ppc/Kconfig new file mode 100644 index 00000000000..f06d0636067 --- /dev/null +++ b/drivers/usb_c/ppc/Kconfig @@ -0,0 +1,23 @@ +# Power path controllers configuration options + +# Copyright 2023 Google LLC +# SPDX-License-Identifier: Apache-2.0 + +menuconfig USBC_PPC_DRIVER + bool "USB-C PPC drivers" + help + Enable USB-C Power Path Controllers support + +if USBC_PPC_DRIVER + +config USBC_PPC_INIT_PRIORITY + int "USBC PPC driver init priority" + default 82 + help + Initialization priority of the USB-C PPC drivers in POST_KERNEL. + +module = USBC_PPC +module-str = usbc-ppc +source "subsys/logging/Kconfig.template.log_config" + +endif # USBC_PPC_DRIVER diff --git a/include/zephyr/drivers/usb_c/usbc_ppc.h b/include/zephyr/drivers/usb_c/usbc_ppc.h new file mode 100644 index 00000000000..c8f76c9227f --- /dev/null +++ b/include/zephyr/drivers/usb_c/usbc_ppc.h @@ -0,0 +1,277 @@ +/* + * Copyright 2023 Google LLC + * SPDX-License-Identifier: Apache-2.0 + */ + +/** + * @file + * @brief USB Type-C Power Path Controller device API + * + */ + +#ifndef ZEPHYR_INCLUDE_DRIVERS_USBC_USBC_PPC_H_ +#define ZEPHYR_INCLUDE_DRIVERS_USBC_USBC_PPC_H_ + +#include +#include +#include + +#ifdef __cplusplus +extern "C" { +#endif + +/** Type of event being notified by Power Path Controller */ +enum usbc_ppc_event { + /** Exit from dead-battery mode failed */ + USBC_PPC_EVENT_DEAD_BATTERY_ERROR = 0, + + /** Overvoltage detected while being in a source role */ + USBC_PPC_EVENT_SRC_OVERVOLTAGE, + /** Reverse current detected while being in a source role */ + USBC_PPC_EVENT_SRC_REVERSE_CURRENT, + /** Overcurrent detected while being in a source role */ + USBC_PPC_EVENT_SRC_OVERCURRENT, + /** VBUS short detected while being in a source role */ + USBC_PPC_EVENT_SRC_SHORT, + + /** Chip over temperature detected */ + USBC_PPC_EVENT_OVER_TEMPERATURE, + /** Sink and source paths enabled simultaneously */ + USBC_PPC_EVENT_BOTH_SNKSRC_ENABLED, + + /** Reverse current detected while being in a sink role */ + USBC_PPC_EVENT_SNK_REVERSE_CURRENT, + /** VBUS short detected while being in a sink role */ + USBC_PPC_EVENT_SNK_SHORT, + /** Overvoltage detected while being in a sink role */ + USBC_PPC_EVENT_SNK_OVERVOLTAGE, +}; + +typedef void (*usbc_ppc_event_cb_t)(const struct device *dev, void *data, enum usbc_ppc_event ev); + +/** Structure with pointers to the functions implemented by driver */ +__subsystem struct usbc_ppc_drv { + int (*is_dead_battery_mode)(const struct device *dev); + int (*exit_dead_battery_mode)(const struct device *dev); + int (*is_vbus_source)(const struct device *dev); + int (*is_vbus_sink)(const struct device *dev); + int (*set_snk_ctrl)(const struct device *dev, bool enable); + int (*set_src_ctrl)(const struct device *dev, bool enable); + int (*set_vbus_discharge)(const struct device *dev, bool enable); + int (*is_vbus_present)(const struct device *dev); + int (*set_event_handler)(const struct device *dev, usbc_ppc_event_cb_t handler, void *data); + int (*dump_regs)(const struct device *dev); +}; + +/* + * API functions + */ + +/** + * @brief Check if PPC is in the dead battery mode + * + * @param dev PPC device structure + * @retval 1 if PPC is in the dead battery mode + * @retval 0 if PPC is not in the dead battery mode + * @retval -EIO if I2C communication failed + * @retval -ENOSYS if this function is not supported by the driver + */ +static inline int ppc_is_dead_battery_mode(const struct device *dev) +{ + const struct usbc_ppc_drv *api = (const struct usbc_ppc_drv *)dev->api; + + if (api->is_dead_battery_mode == NULL) { + return -ENOSYS; + } + + return api->is_dead_battery_mode(dev); +} + +/** + * @brief Request the PPC to exit from the dead battery mode + * Return from this call doesn't mean that the PPC is not in the dead battery anymore. + * In the case of error, the driver should execute the callback with + * USBC_PPC_EVENT_DEAD_BATTERY_ERROR enum. To check if the PPC disabled the dead battery mode, + * the call to ppc_is_dead_battery_mode should be done. + * + * @param dev PPC device structure + * @retval 0 if request was successfully sent + * @retval -EIO if I2C communication failed + * @retval -ENOSYS if this function is not supported by the driver + */ +static inline int ppc_exit_dead_battery_mode(const struct device *dev) +{ + const struct usbc_ppc_drv *api = (const struct usbc_ppc_drv *)dev->api; + + if (api->exit_dead_battery_mode == NULL) { + return -ENOSYS; + } + + return api->exit_dead_battery_mode(dev); +} + +/** + * @brief Check if the PPC is sourcing the VBUS + * + * @param dev PPC device structure + * @retval 1 if the PPC is sourcing the VBUS + * @retval 0 if the PPC is not sourcing the VBUS + * @retval -EIO if I2C communication failed + * @retval -ENOSYS if this function is not supported by the driver + */ +static inline int ppc_is_vbus_source(const struct device *dev) +{ + const struct usbc_ppc_drv *api = (const struct usbc_ppc_drv *)dev->api; + + if (api->is_vbus_source == NULL) { + return -ENOSYS; + } + + return api->is_vbus_source(dev); +} + +/** + * @brief Check if the PPC is sinking the VBUS + * + * @param dev PPC device structure + * @retval 1 if the PPC is sinking the VBUS + * @retval 0 if the PPC is not sinking the VBUS + * @retval -EIO if I2C communication failed + * @retval -ENOSYS if this function is not supported by the driver + */ +static inline int ppc_is_vbus_sink(const struct device *dev) +{ + const struct usbc_ppc_drv *api = (const struct usbc_ppc_drv *)dev->api; + + if (api->is_vbus_sink == NULL) { + return -ENOSYS; + } + + return api->is_vbus_sink(dev); +} + +/** + * @brief Set the state of VBUS sinking + * + * @param dev PPC device structure + * @param enable True if sinking VBUS should be enabled, false if should be disabled + * @retval 0 if success + * @retval -EIO if I2C communication failed + * @retval -ENOSYS if this function is not supported by the driver + */ +static inline int ppc_set_snk_ctrl(const struct device *dev, bool enable) +{ + const struct usbc_ppc_drv *api = (const struct usbc_ppc_drv *)dev->api; + + if (api->set_snk_ctrl == NULL) { + return -ENOSYS; + } + + return api->set_snk_ctrl(dev, enable); +} + +/** + * @brief Set the state of VBUS sourcing + * + * @param dev PPC device structure + * @param enable True if sourcing VBUS should be enabled, false if should be disabled + * @retval 0 if success + * @retval -EIO if I2C communication failed + * @retval -ENOSYS if this function is not supported by the driver + */ +static inline int ppc_set_src_ctrl(const struct device *dev, bool enable) +{ + const struct usbc_ppc_drv *api = (const struct usbc_ppc_drv *)dev->api; + + if (api->set_src_ctrl == NULL) { + return -ENOSYS; + } + + return api->set_src_ctrl(dev, enable); +} + +/** + * @brief Set the state of VBUS discharging + * + * @param dev PPC device structure + * @param enable True if VBUS discharging should be enabled, false if should be disabled + * @retval 0 if success + * @retval -EIO if I2C communication failed + * @retval -ENOSYS if this function is not supported by the driver + */ +static inline int ppc_set_vbus_discharge(const struct device *dev, bool enable) +{ + const struct usbc_ppc_drv *api = (const struct usbc_ppc_drv *)dev->api; + + if (api->set_vbus_discharge == NULL) { + return -ENOSYS; + } + + return api->set_vbus_discharge(dev, enable); +} + +/** + * @brief Check if VBUS is present + * + * @param dev PPC device structure + * @retval 1 if VBUS voltage is present + * @retval 0 if no VBUS voltage is detected + * @retval -EIO if I2C communication failed + * @retval -ENOSYS if this function is not supported by the driver + */ +static inline int ppc_is_vbus_present(const struct device *dev) +{ + const struct usbc_ppc_drv *api = (const struct usbc_ppc_drv *)dev->api; + + if (api->is_vbus_present == NULL) { + return -ENOSYS; + } + + return api->is_vbus_present(dev); +} + +/** + * @brief Set the callback used to notify about PPC events + * + * @param dev PPC device structure + * @param handler Handler that will be called with events notifications + * @param data Pointer used as an argument to the callback + * @retval 0 if success + * @retval -ENOSYS if this function is not supported by the driver + */ +static inline int ppc_set_event_handler(const struct device *dev, + usbc_ppc_event_cb_t handler, void *data) +{ + const struct usbc_ppc_drv *api = (const struct usbc_ppc_drv *)dev->api; + + if (api->set_event_handler == NULL) { + return -ENOSYS; + } + + return api->set_event_handler(dev, handler, data); +} + +/** + * @brief Print the values or PPC registers + * + * @param dev PPC device structure + * @retval 0 if success + * @retval -EIO if I2C communication failed + * @retval -ENOSYS if this function is not supported by the driver + */ +static inline int ppc_dump_regs(const struct device *dev) +{ + const struct usbc_ppc_drv *api = (const struct usbc_ppc_drv *)dev->api; + + if (api->dump_regs == NULL) { + return -ENOSYS; + } + + return api->dump_regs(dev); +} + +#ifdef __cplusplus +} +#endif + +#endif /* ZEPHYR_INCLUDE_DRIVERS_USBC_USBC_PPC_H_ */ From 6bd26a05754f9732f7c32af72a15a5cb87d1282a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Micha=C5=82=20Barna=C5=9B?= Date: Fri, 13 Oct 2023 17:57:17 +0200 Subject: [PATCH 2439/3723] usbc: add shell commands for PPC manipulation MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Add support for ppc shell command with subcommands that can print the status of PPC (dead battery, sinking, sourcing, vbus detected), dump registers and request the PPC to exit dead battery mode. Signed-off-by: Michał Barnaś --- drivers/usb_c/CMakeLists.txt | 1 + drivers/usb_c/ppc/CMakeLists.txt | 5 ++ drivers/usb_c/ppc/Kconfig | 5 ++ drivers/usb_c/ppc/shell.c | 134 +++++++++++++++++++++++++++++++ 4 files changed, 145 insertions(+) create mode 100644 drivers/usb_c/ppc/CMakeLists.txt create mode 100644 drivers/usb_c/ppc/shell.c diff --git a/drivers/usb_c/CMakeLists.txt b/drivers/usb_c/CMakeLists.txt index d576f955cec..9629bbad2f6 100644 --- a/drivers/usb_c/CMakeLists.txt +++ b/drivers/usb_c/CMakeLists.txt @@ -2,3 +2,4 @@ add_subdirectory_ifdef(CONFIG_USBC_TCPC_DRIVER tcpc) add_subdirectory_ifdef(CONFIG_USBC_VBUS_DRIVER vbus) +add_subdirectory_ifdef(CONFIG_USBC_PPC_DRIVER ppc) diff --git a/drivers/usb_c/ppc/CMakeLists.txt b/drivers/usb_c/ppc/CMakeLists.txt new file mode 100644 index 00000000000..cb3e4634496 --- /dev/null +++ b/drivers/usb_c/ppc/CMakeLists.txt @@ -0,0 +1,5 @@ +# SPDX-License-Identifier: Apache-2.0 + +zephyr_library() + +zephyr_library_sources_ifdef(CONFIG_USBC_PPC_SHELL shell.c) diff --git a/drivers/usb_c/ppc/Kconfig b/drivers/usb_c/ppc/Kconfig index f06d0636067..da5364f5d45 100644 --- a/drivers/usb_c/ppc/Kconfig +++ b/drivers/usb_c/ppc/Kconfig @@ -16,6 +16,11 @@ config USBC_PPC_INIT_PRIORITY help Initialization priority of the USB-C PPC drivers in POST_KERNEL. +config USBC_PPC_SHELL + bool "Shell commands for PPC" + help + Add useful shell commands to manipulate and debug the PPCs + module = USBC_PPC module-str = usbc-ppc source "subsys/logging/Kconfig.template.log_config" diff --git a/drivers/usb_c/ppc/shell.c b/drivers/usb_c/ppc/shell.c new file mode 100644 index 00000000000..a69db474ce8 --- /dev/null +++ b/drivers/usb_c/ppc/shell.c @@ -0,0 +1,134 @@ +/* + * Copyright 2023 Google LLC + * SPDX-License-Identifier: Apache-2.0 + */ + +#include +#include +#include + +/** Macro used to iterate over USB-C connector and call a function if the node has PPC property */ +#define CALL_IF_HAS_PPC(usb_node, func) \ + COND_CODE_1(DT_NODE_HAS_PROP(usb_node, ppc), \ + (ret |= func(DEVICE_DT_GET(DT_PHANDLE_BY_IDX(usb_node, ppc, 0)));), ()) + +/** + * @brief Command that dumps registers of one or all of the PPCs + * + * @param sh Shell structure + * @param argc Arguments count + * @param argv Device name + * @return int ORed return values of all the functions executed, 0 in case of success + */ +static int cmd_ppc_dump(const struct shell *sh, size_t argc, char **argv) +{ + int ret = 0; + + if (argc <= 1) { + DT_FOREACH_STATUS_OKAY_VARGS(usb_c_connector, CALL_IF_HAS_PPC, ppc_dump_regs); + } else { + const struct device *dev = device_get_binding(argv[1]); + + ret = ppc_dump_regs(dev); + } + + return ret; +} + +/** + * @brief Function used to pretty print status of the PPC + * + * @param dev Pointer to the PPC device structure + */ +static int print_status(const struct device *dev) +{ + printk("PPC %s:\n", dev->name); + printk(" Dead battery: %d\n", ppc_is_dead_battery_mode(dev)); + printk(" Is sourcing: %d\n", ppc_is_vbus_source(dev)); + printk(" Is sinking: %d\n", ppc_is_vbus_sink(dev)); + printk(" Is VBUS present: %d\n", ppc_is_vbus_present(dev)); + + return 0; +} + +/** + * @brief Command that prints the status of one or all of the PPCs + * + * @param sh Shell structure + * @param argc Arguments count + * @param argv Device name + * @return int ORed return values of all the functions executed, 0 in case of success + */ +static int cmd_ppc_status(const struct shell *sh, size_t argc, char **argv) +{ + int ret = 0; + + if (argc <= 1) { + DT_FOREACH_STATUS_OKAY_VARGS(usb_c_connector, CALL_IF_HAS_PPC, print_status); + } else { + const struct device *dev = device_get_binding(argv[1]); + + ret = print_status(dev); + } + + return ret; +} + +/** + * @brief Command that requests one or all of the PPCs to try exiting the dead battery mode + * + * @param sh Shell structure + * @param argc Arguments count + * @param argv Device name + * @return int ORed return values of all the functions executed, 0 in case of success + */ +static int cmd_ppc_exit_db(const struct shell *sh, size_t argc, char **argv) +{ + int ret = 0; + + if (argc <= 1) { + DT_FOREACH_STATUS_OKAY_VARGS(usb_c_connector, CALL_IF_HAS_PPC, + ppc_exit_dead_battery_mode); + } else { + const struct device *dev = device_get_binding(argv[1]); + + ret = ppc_exit_dead_battery_mode(dev); + } + + return ret; +} + +/** + * @brief Function used to create subcommands with devices names + * + * @param idx counter of devices + * @param entry shell structure that will be filled + */ +static void device_name_get(size_t idx, struct shell_static_entry *entry) +{ + const struct device *dev = shell_device_lookup(idx, NULL); + + entry->syntax = (dev != NULL) ? dev->name : NULL; + entry->handler = NULL; + entry->help = NULL; + entry->subcmd = NULL; +} + +SHELL_DYNAMIC_CMD_CREATE(list_device_names, device_name_get); + +SHELL_STATIC_SUBCMD_SET_CREATE(sub_ppc_cmds, + SHELL_CMD_ARG(dump, &list_device_names, + "Dump PPC registers\n" + "Usage: ppc dump []", + cmd_ppc_dump, 1, 1), + SHELL_CMD_ARG(status, &list_device_names, + "Write PPC power status\n" + "Usage: ppc statuc []", + cmd_ppc_status, 1, 1), + SHELL_CMD_ARG(exitdb, &list_device_names, + "Exit from the dead battery mode\n" + "Usage: ppc exitdb []", + cmd_ppc_exit_db, 1, 1), + SHELL_SUBCMD_SET_END); + +SHELL_CMD_REGISTER(ppc, &sub_ppc_cmds, "PPC (USB-C PD) diagnostics", NULL); From 551c7654f5a738ef908e074f2d8cb212e7ab50b8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Micha=C5=82=20Barna=C5=9B?= Date: Fri, 13 Oct 2023 18:08:55 +0200 Subject: [PATCH 2440/3723] usbc: integrate the PPC with the USB-C stack MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Add calls to the PPC API that enables and disables the sink and source paths in the appropriate USB-C stack states. Signed-off-by: Michał Barnaś --- dts/bindings/usb-c/usb-c-connector.yaml | 5 +++++ subsys/usb/usb_c/usbc_stack.c | 2 ++ subsys/usb/usb_c/usbc_stack.h | 2 ++ subsys/usb/usb_c/usbc_tc_common.c | 6 ++++++ subsys/usb/usb_c/usbc_tc_snk_states.c | 19 +++++++++++++++++++ subsys/usb/usb_c/usbc_tc_src_states.c | 21 +++++++++++++++++++++ 6 files changed, 55 insertions(+) diff --git a/dts/bindings/usb-c/usb-c-connector.yaml b/dts/bindings/usb-c/usb-c-connector.yaml index c5e69653a33..4cbcf3f518c 100644 --- a/dts/bindings/usb-c/usb-c-connector.yaml +++ b/dts/bindings/usb-c/usb-c-connector.yaml @@ -54,6 +54,11 @@ properties: description: | VBUS measurement and control for this port. + ppc: + type: phandle + description: | + Power path controller for this port + power-role: type: string required: true diff --git a/subsys/usb/usb_c/usbc_stack.c b/subsys/usb/usb_c/usbc_stack.c index 08ac7cd3cb7..5cf32b70aa7 100644 --- a/subsys/usb/usb_c/usbc_stack.c +++ b/subsys/usb/usb_c/usbc_stack.c @@ -80,6 +80,8 @@ static ALWAYS_INLINE void usbc_handler(void *port_dev) .prl_hr = &prl_hr_##inst, \ .tcpc = DEVICE_DT_GET(DT_INST_PROP(inst, tcpc)), \ .vbus = DEVICE_DT_GET(DT_INST_PROP(inst, vbus)), \ + .ppc = COND_CODE_1(DT_INST_NODE_HAS_PROP(inst, ppc), \ + (DEVICE_DT_GET(DT_INST_PROP(inst, ppc))), (NULL)), \ }; \ \ static const struct usbc_port_config usbc_port_config_##inst = { \ diff --git a/subsys/usb/usb_c/usbc_stack.h b/subsys/usb/usb_c/usbc_stack.h index ca95f05f317..a7948ee33f3 100644 --- a/subsys/usb/usb_c/usbc_stack.h +++ b/subsys/usb/usb_c/usbc_stack.h @@ -101,6 +101,8 @@ struct usbc_port_data { const struct device *tcpc; /** VBUS Measurement and control device on this port */ const struct device *vbus; + /** Power Path Controller device on this port */ + const struct device *ppc; /** Device Policy Manager Request FIFO */ struct k_fifo request_fifo; diff --git a/subsys/usb/usb_c/usbc_tc_common.c b/subsys/usb/usb_c/usbc_tc_common.c index 94b34edf218..e4a58a24899 100644 --- a/subsys/usb/usb_c/usbc_tc_common.c +++ b/subsys/usb/usb_c/usbc_tc_common.c @@ -11,6 +11,7 @@ LOG_MODULE_DECLARE(usbc_stack, CONFIG_USBC_STACK_LOG_LEVEL); #include "usbc_tc_snk_states_internal.h" #include "usbc_tc_src_states_internal.h" #include "usbc_tc_common_internal.h" +#include static const struct smf_state tc_states[TC_STATE_COUNT]; static int tc_init(const struct device *dev); @@ -152,6 +153,11 @@ static int tc_init(const struct device *dev) return ret; } + /* Disable VBUS sourcing by the PPC */ + if (data->ppc != NULL) { + ppc_set_src_ctrl(data->ppc, false); + } + /* Stop sourcing VCONN */ ret = tcpc_set_vconn(tcpc, false); if (ret != 0 && ret != -ENOTSUP) { diff --git a/subsys/usb/usb_c/usbc_tc_snk_states.c b/subsys/usb/usb_c/usbc_tc_snk_states.c index 11cc456acfb..df89990dec8 100644 --- a/subsys/usb/usb_c/usbc_tc_snk_states.c +++ b/subsys/usb/usb_c/usbc_tc_snk_states.c @@ -10,6 +10,7 @@ LOG_MODULE_DECLARE(usbc_stack, CONFIG_USBC_STACK_LOG_LEVEL); #include "usbc_stack.h" #include "usbc_tc_snk_states_internal.h" #include "usbc_tc_common_internal.h" +#include /** * @brief Sink power sub states. Only called if a PD contract is not in place @@ -214,6 +215,14 @@ void tc_attached_snk_entry(void *obj) /* Enable PD */ tc_pd_enable(dev, true); + + /* Enable sink path for the PPC */ + if (data->ppc != NULL) { + ret = ppc_set_snk_ctrl(data->ppc, true); + if (ret != 0 && ret != -ENOTSUP) { + LOG_ERR("Couldn't enable PPC sink path: %d", ret); + } + } } /** @@ -245,9 +254,19 @@ void tc_attached_snk_exit(void *obj) { struct tc_sm_t *tc = (struct tc_sm_t *)obj; const struct device *dev = tc->dev; + struct usbc_port_data *data = dev->data; + int ret; /* Disable PD */ tc_pd_enable(dev, false); + + /* Disable sink path for the PPC */ + if (data->ppc != NULL) { + ret = ppc_set_snk_ctrl(data->ppc, false); + if (ret != 0 && ret != -ENOTSUP) { + LOG_ERR("Couldn't disable PPC sink path: %d", ret); + } + } } /** diff --git a/subsys/usb/usb_c/usbc_tc_src_states.c b/subsys/usb/usb_c/usbc_tc_src_states.c index 972c7cdef54..f24ba9fe8a0 100644 --- a/subsys/usb/usb_c/usbc_tc_src_states.c +++ b/subsys/usb/usb_c/usbc_tc_src_states.c @@ -9,6 +9,7 @@ LOG_MODULE_DECLARE(usbc_stack, CONFIG_USBC_STACK_LOG_LEVEL); #include "usbc_stack.h" #include "usbc_tc_src_states_internal.h" +#include /** * @brief Spec. Release 1.3, section 4.5.2.2.7 Unattached.SRC State @@ -253,6 +254,16 @@ void tc_attached_src_entry(void *obj) /* Enable PD */ tc_pd_enable(dev, true); + + /* Enable the VBUS sourcing by the PPC */ + if (data->ppc != NULL) { + int ret; + + ret = ppc_set_src_ctrl(data->ppc, true); + if (ret < 0 && ret != -ENOSYS) { + LOG_ERR("Couldn't disable PPC source"); + } + } } void tc_attached_src_run(void *obj) @@ -304,6 +315,16 @@ void tc_attached_src_exit(void *obj) /* Stop sourcing VBUS */ data->policy_cb_src_en(dev, false); + /* Disable the VBUS sourcing by the PPC */ + if (data->ppc != NULL) { + int ret; + + ret = ppc_set_src_ctrl(data->ppc, false); + if (ret < 0 && ret != -ENOSYS) { + LOG_ERR("Couldn't disable PPC source"); + } + } + /* Stop sourcing VCONN */ ret = tcpc_set_vconn(tcpc, false); if (ret != 0 && ret != -ENOSYS) { From 77187548ffafa5938be16381f1ca10cd5f432920 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Micha=C5=82=20Barna=C5=9B?= Date: Fri, 13 Oct 2023 18:24:46 +0200 Subject: [PATCH 2441/3723] usbc: add driver for nx20p3483 PPC chip MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Add driver for NXP nx20p3483 power path controller that can be used to control and protect sink and source path of USB-C connector. Signed-off-by: Michał Barnaś --- drivers/usb_c/ppc/CMakeLists.txt | 1 + drivers/usb_c/ppc/Kconfig | 2 + drivers/usb_c/ppc/Kconfig.nxp | 20 + drivers/usb_c/ppc/nxp_nx20p3483.c | 457 ++++++++++++++++++ drivers/usb_c/ppc/nxp_nx20p3483_priv.h | 127 +++++ dts/bindings/ppc/nxp,nx20p3483.yaml | 39 ++ .../zephyr/dt-bindings/usb-c/nxp_nx20p3483.h | 62 +++ 7 files changed, 708 insertions(+) create mode 100644 drivers/usb_c/ppc/Kconfig.nxp create mode 100644 drivers/usb_c/ppc/nxp_nx20p3483.c create mode 100644 drivers/usb_c/ppc/nxp_nx20p3483_priv.h create mode 100644 dts/bindings/ppc/nxp,nx20p3483.yaml create mode 100644 include/zephyr/dt-bindings/usb-c/nxp_nx20p3483.h diff --git a/drivers/usb_c/ppc/CMakeLists.txt b/drivers/usb_c/ppc/CMakeLists.txt index cb3e4634496..dc3fc83988c 100644 --- a/drivers/usb_c/ppc/CMakeLists.txt +++ b/drivers/usb_c/ppc/CMakeLists.txt @@ -3,3 +3,4 @@ zephyr_library() zephyr_library_sources_ifdef(CONFIG_USBC_PPC_SHELL shell.c) +zephyr_library_sources_ifdef(CONFIG_USBC_PPC_NX20P3483 nxp_nx20p3483.c) diff --git a/drivers/usb_c/ppc/Kconfig b/drivers/usb_c/ppc/Kconfig index da5364f5d45..c3fc93e1f4e 100644 --- a/drivers/usb_c/ppc/Kconfig +++ b/drivers/usb_c/ppc/Kconfig @@ -21,6 +21,8 @@ config USBC_PPC_SHELL help Add useful shell commands to manipulate and debug the PPCs +source "drivers/usb_c/ppc/Kconfig.nxp" + module = USBC_PPC module-str = usbc-ppc source "subsys/logging/Kconfig.template.log_config" diff --git a/drivers/usb_c/ppc/Kconfig.nxp b/drivers/usb_c/ppc/Kconfig.nxp new file mode 100644 index 00000000000..1d1de6a49e9 --- /dev/null +++ b/drivers/usb_c/ppc/Kconfig.nxp @@ -0,0 +1,20 @@ +# NXP NX20P3483 Configuration menu + +# Copyright 2023 Google LLC +# SPDX-License-Identifier: Apache-2.0 + +config USBC_PPC_NX20P3483 + bool "NXP NX20P3483 support" + default y + depends on DT_HAS_NXP_NX20P3483_ENABLED + help + Enable USB-C PPC support for NXP nx20p3483 chip + +if USBC_PPC_NX20P3483 + +config USBC_PPC_NX20P3483_DUMP_FULL_REG_NAMES + bool "Dump full register names" + help + Dump human-readable names instead of offsets of registers + +endif diff --git a/drivers/usb_c/ppc/nxp_nx20p3483.c b/drivers/usb_c/ppc/nxp_nx20p3483.c new file mode 100644 index 00000000000..8b6a2fe914d --- /dev/null +++ b/drivers/usb_c/ppc/nxp_nx20p3483.c @@ -0,0 +1,457 @@ +/* + * Copyright 2023 Google LLC + * SPDX-License-Identifier: Apache-2.0 + */ + +#include +#include +#include +#include +#include +#include + +#include "nxp_nx20p3483_priv.h" + +#define DT_DRV_COMPAT nxp_nx20p3483 +LOG_MODULE_REGISTER(nxp_nx20p3483, CONFIG_USBC_PPC_LOG_LEVEL); + +#ifdef CONFIG_USBC_PPC_NX20P3483_DUMP_FULL_REG_NAMES +static const char *const nx20p3483_reg_names[] = { + "Device ID ", "Device Status ", "Switch Control ", + "Switch Status ", "Interrupt 1 ", "Interrupt 2 ", + "Interrupt 1 Mask ", "Interrupt 2 Mask ", "OVLO Threshold ", + "HV SRC OCP Threshold", "5V SRC OCP Threshold", "Device Control ", +}; +#endif + +/* Driver structures */ + +struct nx20p3483_cfg { + /** Device address on I2C bus */ + const struct i2c_dt_spec bus; + /** GPIO used as interrupt request */ + const struct gpio_dt_spec irq_gpio; + + /** Overvoltage protection threshold for sink role */ + int snk_ovp_thresh; + /** Boolean value whether to use high-voltage source if true or 5V source if false */ + bool src_use_hv; + /** Overcurrent protection threshold for 5V source role */ + int src_5v_ocp_thresh; + /** Overcurrent protection threshold for HV source role */ + int src_hv_ocp_thresh; +}; + +struct nx20p3483_data { + /** Device structure to get from data structure */ + const struct device *dev; + /** Interrupt request callback object */ + struct gpio_callback irq_cb; + /** Workqueue object for handling interrupts */ + struct k_work irq_work; + + /** Callback used to notify about PPC events, like overcurrent or short */ + usbc_ppc_event_cb_t event_cb; + /** Data sent as parameter to the callback */ + void *event_cb_data; +}; + +/* Helper functions */ + +static int read_reg(const struct device *dev, uint8_t reg, uint8_t *value) +{ + const struct nx20p3483_cfg *cfg = dev->config; + int ret; + + ret = i2c_reg_read_byte(cfg->bus.bus, cfg->bus.addr, reg, value); + if (ret != 0) { + LOG_ERR("Error reading reg %02x: %d", reg, ret); + return ret; + } + + return 0; +} + +static int write_reg(const struct device *dev, uint8_t reg, uint8_t value) +{ + const struct nx20p3483_cfg *cfg = dev->config; + int ret; + + ret = i2c_reg_write_byte(cfg->bus.bus, cfg->bus.addr, reg, value); + if (ret != 0) { + LOG_ERR("Error writing reg %02x: %d", reg, ret); + return ret; + } + + return 0; +} + +static int nx20p3483_set_snk_ovp_limit(const struct device *dev, uint8_t u_thresh) +{ + int ret; + + if (u_thresh < NX20P3483_I_THRESHOLD_0_400 || u_thresh > NX20P3483_I_THRESHOLD_3_400) { + return -EINVAL; + } + + ret = write_reg(dev, NX20P3483_REG_OVLO_THRESHOLD, u_thresh); + if (ret != 0) { + LOG_ERR("Couldn't set SNK OVP: %d", ret); + return ret; + } + + LOG_DBG("Set SNK OVP: %d", u_thresh); + return 0; +} + +/* API functions */ + +int nx20p3483_is_dead_battery_mode(const struct device *dev) +{ + uint8_t sts_reg; + int ret; + + ret = read_reg(dev, NX20P3483_REG_DEVICE_STATUS, &sts_reg); + if (ret != 0) { + return ret; + } + + return ((sts_reg & NX20P3483_REG_DEVICE_STATUS_MODE_MASK) == NX20P3483_MODE_DEAD_BATTERY); +} + +int nx20p3483_exit_dead_battery_mode(const struct device *dev) +{ + uint8_t ctrl_reg; + int ret; + + ret = read_reg(dev, NX20P3483_REG_DEVICE_CTRL, &ctrl_reg); + if (ret != 0) { + return ret; + } + + ctrl_reg |= NX20P3483_REG_DEVICE_CTRL_DB_EXIT; + ret = write_reg(dev, NX20P3483_REG_DEVICE_CTRL, ctrl_reg); + if (ret != 0) { + return ret; + } + + return 0; +} + +static int nx20p3483_is_vbus_source(const struct device *dev) +{ + uint8_t sts_reg; + int ret; + + ret = read_reg(dev, NX20P3483_REG_SWITCH_STATUS, &sts_reg); + if (ret != 0) { + return ret; + } + + return !!(sts_reg & + (NX20P3483_REG_SWITCH_STATUS_5VSRC | NX20P3483_REG_SWITCH_STATUS_HVSRC)); +} + +static int nx20p3483_is_vbus_sink(const struct device *dev) +{ + uint8_t sts_reg; + int ret; + + ret = read_reg(dev, NX20P3483_REG_SWITCH_STATUS, &sts_reg); + if (ret != 0) { + return ret; + } + + return !!(sts_reg & NX20P3483_REG_SWITCH_STATUS_HVSNK); +} + +static int nx20p3483_set_vbus_sink(const struct device *dev, bool enable) +{ + const struct nx20p3483_cfg *cfg = dev->config; + + /* + * The nx20p3483 is enabled by external GPIO signal, however enabling it sets the + * overvoltage threshold to the highest possible value. Due to that, the threshold has + * to be set here again. Must be called after enabling the path by the external signal. + */ + return nx20p3483_set_snk_ovp_limit(dev, cfg->snk_ovp_thresh); +} + +static int nx20p3483_set_vbus_discharge(const struct device *dev, bool enable) +{ + uint8_t ctrl_reg; + int ret; + + ret = read_reg(dev, NX20P3483_REG_DEVICE_CTRL, &ctrl_reg); + if (ret != 0) { + return ret; + } + + if (enable) { + ctrl_reg |= NX20P3483_REG_DEVICE_CTRL_VBUSDIS_EN; + } else { + ctrl_reg &= ~NX20P3483_REG_DEVICE_CTRL_VBUSDIS_EN; + } + + ret = write_reg(dev, NX20P3483_REG_DEVICE_CTRL, ctrl_reg); + + return ret; +} + +static int nx20p3483_set_event_handler(const struct device *dev, usbc_ppc_event_cb_t handler, + void *handler_data) +{ + struct nx20p3483_data *data = dev->data; + + data->event_cb = handler; + data->event_cb_data = handler_data; + + return 0; +} + +static int nx20p3483_dump_regs(const struct device *dev) +{ + const struct nx20p3483_cfg *cfg = dev->config; + uint8_t val; + + LOG_INF("NX20P alert: %d", gpio_pin_get(cfg->irq_gpio.port, cfg->irq_gpio.pin)); + LOG_INF("PPC %s:%s registers:", cfg->bus.bus->name, dev->name); + for (int a = 0; a <= NX20P3483_REG_DEVICE_CTRL; a++) { + i2c_reg_read_byte(cfg->bus.bus, cfg->bus.addr, a, &val); + +#ifdef CONFIG_USBC_PPC_NX20P3483_DUMP_FULL_REG_NAMES + LOG_INF("- [%s] = 0x%02x", nx20p3483_reg_names[a], val); +#else + LOG_INF("- [%02x] = 0x%02x", a, val); +#endif + } + + return 0; +} + +static struct usbc_ppc_drv nx20p3483_driver_api = { + .is_dead_battery_mode = nx20p3483_is_dead_battery_mode, + .exit_dead_battery_mode = nx20p3483_exit_dead_battery_mode, + .is_vbus_source = nx20p3483_is_vbus_source, + .is_vbus_sink = nx20p3483_is_vbus_sink, + .set_snk_ctrl = nx20p3483_set_vbus_sink, + .set_vbus_discharge = nx20p3483_set_vbus_discharge, + .set_event_handler = nx20p3483_set_event_handler, + .dump_regs = nx20p3483_dump_regs, +}; + +static int nx20p3483_set_src_ovc_limit(const struct device *dev, uint8_t i_thresh_5v, + uint8_t i_thresh_hv) +{ + int ret; + + if (i_thresh_5v < NX20P3483_I_THRESHOLD_0_400 || + i_thresh_5v > NX20P3483_I_THRESHOLD_3_400) { + LOG_ERR("Invalid SRC 5V ovc threshold: %d", i_thresh_5v); + return -EINVAL; + } + + if (i_thresh_hv < NX20P3483_I_THRESHOLD_0_400 || + i_thresh_hv > NX20P3483_I_THRESHOLD_3_400) { + LOG_ERR("Invalid SRC HV ovc threshold: %d", i_thresh_hv); + return -EINVAL; + } + + ret = write_reg(dev, NX20P3483_REG_5V_SRC_OCP_THRESHOLD, i_thresh_5v); + if (ret != 0) { + return ret; + } + + ret = write_reg(dev, NX20P3483_REG_HV_SRC_OCP_THRESHOLD, i_thresh_hv); + if (ret != 0) { + return ret; + } + + LOG_DBG("Set SRC OVC 5V: %d, HV: %d", i_thresh_5v, i_thresh_hv); + return 0; +} + +static void nx20p3483_send_event(const struct device *dev, enum usbc_ppc_event ev) +{ + struct nx20p3483_data *data = dev->data; + + if (data->event_cb != NULL) { + data->event_cb(dev, data->event_cb_data, ev); + } +} + +static void nx20p3483_irq_handler(const struct device *port, struct gpio_callback *cb, + gpio_port_pins_t pins) +{ + struct nx20p3483_data *data = CONTAINER_OF(cb, struct nx20p3483_data, irq_cb); + + k_work_submit(&data->irq_work); +} + +static void nx20p3483_irq_worker(struct k_work *work) +{ + struct nx20p3483_data *data = CONTAINER_OF(work, struct nx20p3483_data, irq_work); + const struct device *dev = data->dev; + uint8_t irq1, irq2; + int ret; + + ret = read_reg(dev, NX20P3483_REG_INT1, &irq1); + if (ret != 0) { + LOG_ERR("Couldn't read irq1"); + return; + } + + ret = read_reg(dev, NX20P3483_REG_INT2, &irq2); + if (ret != 0) { + LOG_ERR("Couldn't read irq2"); + return; + } + + if (data->event_cb == NULL) { + LOG_DBG("No callback set: %02x %02x", irq1, irq1); + } + + /* Generic alerts */ + if (irq1 & NX20P3483_REG_INT1_DBEXIT_ERR) { + LOG_INF("PPC dead battery exit failed"); + nx20p3483_send_event(dev, USBC_PPC_EVENT_DEAD_BATTERY_ERROR); + } + + if (irq1 & NX20P3483_REG_INT1_OTP) { + LOG_INF("PPC over temperature"); + nx20p3483_send_event(dev, USBC_PPC_EVENT_OVER_TEMPERATURE); + } + + if (irq1 & NX20P3483_REG_INT2_EN_ERR) { + LOG_INF("PPC source and sink enabled"); + nx20p3483_send_event(dev, USBC_PPC_EVENT_BOTH_SNKSRC_ENABLED); + } + + /* Source */ + if (irq1 & NX20P3483_REG_INT1_OV_5VSRC || irq2 & NX20P3483_REG_INT2_OV_HVSRC) { + LOG_INF("PPC source overvoltage"); + nx20p3483_send_event(dev, USBC_PPC_EVENT_SRC_OVERVOLTAGE); + } + + if (irq1 & NX20P3483_REG_INT1_RCP_5VSRC || irq2 & NX20P3483_REG_INT2_RCP_HVSRC) { + LOG_INF("PPC source reverse current"); + nx20p3483_send_event(dev, USBC_PPC_EVENT_SRC_REVERSE_CURRENT); + } + + if (irq1 & NX20P3483_REG_INT1_OC_5VSRC || irq2 & NX20P3483_REG_INT2_OC_HVSRC) { + LOG_INF("PPC source overcurrent"); + nx20p3483_send_event(dev, USBC_PPC_EVENT_SRC_OVERCURRENT); + } + + if (irq1 & NX20P3483_REG_INT1_SC_5VSRC || irq2 & NX20P3483_REG_INT2_SC_HVSRC) { + LOG_INF("PPC source short"); + nx20p3483_send_event(dev, USBC_PPC_EVENT_SRC_SHORT); + } + + /* Sink */ + if (irq2 & NX20P3483_REG_INT2_RCP_HVSNK) { + LOG_INF("PPC sink reverse current"); + nx20p3483_send_event(dev, USBC_PPC_EVENT_SNK_REVERSE_CURRENT); + } + + if (irq2 & NX20P3483_REG_INT2_SC_HVSNK) { + LOG_INF("PPC sink short"); + nx20p3483_send_event(dev, USBC_PPC_EVENT_SNK_SHORT); + } + + if (irq2 & NX20P3483_REG_INT2_OV_HVSNK) { + LOG_INF("PPC sink overvoltage"); + nx20p3483_send_event(dev, USBC_PPC_EVENT_SNK_OVERVOLTAGE); + } +} + +static int nx20p3483_dev_init(const struct device *dev) +{ + const struct nx20p3483_cfg *cfg = dev->config; + struct nx20p3483_data *data = dev->data; + uint8_t reg; + int ret; + + LOG_INF("Initializing PPC"); + + /* Initialize irq */ + ret = gpio_pin_configure(cfg->irq_gpio.port, cfg->irq_gpio.pin, GPIO_INPUT | GPIO_PULL_UP); + if (ret != 0) { + return ret; + } + + ret = gpio_pin_interrupt_configure(cfg->irq_gpio.port, cfg->irq_gpio.pin, + GPIO_INT_EDGE_FALLING); + if (ret != 0) { + return ret; + } + + gpio_init_callback(&data->irq_cb, nx20p3483_irq_handler, BIT(cfg->irq_gpio.pin)); + ret = gpio_add_callback(cfg->irq_gpio.port, &data->irq_cb); + if (ret != 0) { + return ret; + } + + /* Initialize work_q */ + k_work_init(&data->irq_work, nx20p3483_irq_worker); + k_work_submit(&data->irq_work); + + /* If src_use_hv, select the HV src path but do not enable it yet */ + read_reg(dev, NX20P3483_REG_SWITCH_CTRL, ®); + if (cfg->src_use_hv) { + reg |= NX20P3483_REG_SWITCH_CTRL_SRC; + } else { + reg &= ~NX20P3483_REG_SWITCH_CTRL_SRC; + } + + write_reg(dev, NX20P3483_REG_SWITCH_CTRL, reg); + + /* Set limits */ + ret = nx20p3483_set_snk_ovp_limit(dev, cfg->snk_ovp_thresh); + if (ret != 0) { + return ret; + } + + ret = nx20p3483_set_src_ovc_limit(dev, cfg->src_5v_ocp_thresh, cfg->src_hv_ocp_thresh); + if (ret != 0) { + return ret; + } + + return 0; +} + +#define NX20P3483_DRIVER_CFG_INIT(node) \ + { \ + .bus = I2C_DT_SPEC_GET(node), .irq_gpio = GPIO_DT_SPEC_GET(node, irq_gpios), \ + .snk_ovp_thresh = DT_PROP(node, snk_ovp), .src_use_hv = DT_PROP(node, src_hv), \ + .src_5v_ocp_thresh = DT_PROP(node, src_5v_ocp), \ + .src_hv_ocp_thresh = DT_PROP(node, src_hv_ocp), \ + } + +#define NX20P3483_DRIVER_CFG_ASSERTS(node) \ + BUILD_ASSERT(DT_PROP(node, snk_ovp) >= NX20P3483_U_THRESHOLD_6_0 && \ + DT_PROP(node, snk_ovp) <= NX20P3483_U_THRESHOLD_23_0, \ + "Invalid overvoltage threshold"); \ + BUILD_ASSERT(DT_PROP(node, src_5v_ocp) >= NX20P3483_I_THRESHOLD_0_400 && \ + DT_PROP(node, src_5v_ocp) <= NX20P3483_I_THRESHOLD_3_400, \ + "Invalid overcurrent threshold"); \ + BUILD_ASSERT(DT_PROP(node, src_hv_ocp) >= NX20P3483_I_THRESHOLD_0_400 && \ + DT_PROP(node, src_hv_ocp) <= NX20P3483_I_THRESHOLD_3_400, \ + "Invalid overcurrent threshold"); + +#define NX20P3483_DRIVER_DATA_INIT(node) \ + { \ + .dev = DEVICE_DT_GET(node), \ + } + +#define NX20P3483_DRIVER_INIT(inst) \ + static struct nx20p3483_data drv_data_nx20p3483##inst = \ + NX20P3483_DRIVER_DATA_INIT(DT_DRV_INST(inst)); \ + NX20P3483_DRIVER_CFG_ASSERTS(DT_DRV_INST(inst)); \ + static struct nx20p3483_cfg drv_cfg_nx20p3483##inst = \ + NX20P3483_DRIVER_CFG_INIT(DT_DRV_INST(inst)); \ + DEVICE_DT_INST_DEFINE(inst, &nx20p3483_dev_init, NULL, &drv_data_nx20p3483##inst, \ + &drv_cfg_nx20p3483##inst, POST_KERNEL, \ + CONFIG_USBC_PPC_INIT_PRIORITY, &nx20p3483_driver_api); + +DT_INST_FOREACH_STATUS_OKAY(NX20P3483_DRIVER_INIT) diff --git a/drivers/usb_c/ppc/nxp_nx20p3483_priv.h b/drivers/usb_c/ppc/nxp_nx20p3483_priv.h new file mode 100644 index 00000000000..b033be4a730 --- /dev/null +++ b/drivers/usb_c/ppc/nxp_nx20p3483_priv.h @@ -0,0 +1,127 @@ +/* + * Copyright 2023 Google LLC + * SPDX-License-Identifier: Apache-2.0 + */ + +/** + * @file + * @brief NX20P3483 PPC registers definitions + */ + +#ifndef ZEPHYR_DRIVERS_USBC_PPC_NXP_NX20P3483_PRIV_H_ +#define ZEPHYR_DRIVERS_USBC_PPC_NXP_NX20P3483_PRIV_H_ + +#include + +/** Register address - device id */ +#define NX20P3483_REG_DEVICE_ID 0x00 +/** Bit mask for vendor id */ +#define NX20P3483_REG_DEVICE_ID_VENDOR_MASK GENMASK(7, 3) +/** Bit mask for version id */ +#define NX20P3483_REG_DEVICE_ID_REVISION_MASK GENMASK(2, 0) + +/** Register address - device status */ +#define NX20P3483_REG_DEVICE_STATUS 0x01 +/** Bit mask for device mode */ +#define NX20P3483_REG_DEVICE_STATUS_MODE_MASK GENMASK(2, 0) + +/** Value for dead battery mode */ +#define NX20P3483_MODE_DEAD_BATTERY 0 +/** Value for high-voltage sink mode */ +#define NX20P3483_MODE_HV_SNK 1 +/** Value for 5V source mode */ +#define NX20P3483_MODE_5V_SRC 2 +/** Value for high-voltage source mode */ +#define NX20P3483_MODE_HV_SRC 3 +/** Value for standby mode */ +#define NX20P3483_MODE_STANDBY 4 + +/** Register address - switch control */ +#define NX20P3483_REG_SWITCH_CTRL 0x02 +/** Bit field for source path selection. If set, HV source path is selected, 5V otherwise. */ +#define NX20P3483_REG_SWITCH_CTRL_SRC BIT(7) + +/** Register address - switch status */ +#define NX20P3483_REG_SWITCH_STATUS 0x03 +/** Bit field for 5V source switch enabled */ +#define NX20P3483_REG_SWITCH_STATUS_5VSRC BIT(2) +/** Bit field for HV source switch enabled */ +#define NX20P3483_REG_SWITCH_STATUS_HVSRC BIT(1) +/** Bit field for HV sink switch enabled */ +#define NX20P3483_REG_SWITCH_STATUS_HVSNK BIT(0) + +/** Register address - interrupt1 */ +#define NX20P3483_REG_INT1 0x04 +/** Bit field for exit dead battery error */ +#define NX20P3483_REG_INT1_DBEXIT_ERR BIT(7) +/** Bit field for overvoltage fault triggered on 5V source path */ +#define NX20P3483_REG_INT1_OV_5VSRC BIT(4) +/** Bit field for reverse current fault triggered on 5V source path */ +#define NX20P3483_REG_INT1_RCP_5VSRC BIT(3) +/** Bit field for short circuit fault triggered on 5V source path */ +#define NX20P3483_REG_INT1_SC_5VSRC BIT(2) +/** Bit field for overcurrent fault triggered on 5V source path */ +#define NX20P3483_REG_INT1_OC_5VSRC BIT(1) +/** Bit field for over temperature protection fault triggered */ +#define NX20P3483_REG_INT1_OTP BIT(0) + +/** Register address - interrupt2*/ +#define NX20P3483_REG_INT2 0x05 +/** Bit field for sink and source routes enabled fault */ +#define NX20P3483_REG_INT2_EN_ERR BIT(7) +/** Bit field for reverse current fault triggered on HV sink path */ +#define NX20P3483_REG_INT2_RCP_HVSNK BIT(6) +/** Bit field for short circuit fault triggered on HV sink path */ +#define NX20P3483_REG_INT2_SC_HVSNK BIT(5) +/** Bit field for overvoltage fault triggered on HV sink path */ +#define NX20P3483_REG_INT2_OV_HVSNK BIT(4) +/** Bit field for reverse current fault triggered on HV source path */ +#define NX20P3483_REG_INT2_RCP_HVSRC BIT(3) +/** Bit field for short circuit fault triggered on HV source path */ +#define NX20P3483_REG_INT2_SC_HVSRC BIT(2) +/** Bit field for overcurrent fault triggered on HV source path */ +#define NX20P3483_REG_INT2_OC_HVSRC BIT(1) +/** Bit field for overvoltage fault triggered on HV source path */ +#define NX20P3483_REG_INT2_OV_HVSRC BIT(0) + +/** Register address - interrupt1 mask */ +#define NX20P3483_REG_INT1_MASK 0x06 + +/** Register address - interrupt2 mask*/ +#define NX20P3483_REG_INT2_MASK 0x07 + +/** Register address - OVLO threshold (overvoltage threshold) */ +#define NX20P3483_REG_OVLO_THRESHOLD 0x08 +/** + * Bit mask for overvoltage threshold value + * Values used in this register are defined as NX20P3483_U_THRESHOLD_* + */ +#define NX20P3483_REG_OVLO_THRESHOLD_MASK GENMASK(2, 0) + +/* Internal 5V VBUS Switch Current Limit Settings (min) */ +#define NX20P3483_ILIM_MASK 0xF + +/** + * Register address - HV source switch OCP threshold + * Values used in this register are defined as NX20P3483_I_THRESHOLD_* + */ +#define NX20P3483_REG_HV_SRC_OCP_THRESHOLD 0x09 + +/** + * Register address - 5V source switch OCP threshold + * Values used in this register are defined as NX20P3483_I_THRESHOLD_* + */ +#define NX20P3483_REG_5V_SRC_OCP_THRESHOLD 0x0A + +/** Register address - device control */ +#define NX20P3483_REG_DEVICE_CTRL 0x0B +/** Bit field for fast role swap capability activated */ +#define NX20P3483_REG_DEVICE_CTRL_FRS_AT BIT(3) +/** Bit field for exit dead battery mode */ +#define NX20P3483_REG_DEVICE_CTRL_DB_EXIT BIT(2) +/** Bit field for VBUS discharge circuit enabled */ +#define NX20P3483_REG_DEVICE_CTRL_VBUSDIS_EN BIT(1) +/** Bit field for LDO shutdown */ +#define NX20P3483_REG_DEVICE_CTRL_LDO_SD BIT(0) + +#endif /* ZEPHYR_DRIVERS_USBC_PPC_NXP_NX20P3483_PRIV_H_ */ diff --git a/dts/bindings/ppc/nxp,nx20p3483.yaml b/dts/bindings/ppc/nxp,nx20p3483.yaml new file mode 100644 index 00000000000..c705ac32c33 --- /dev/null +++ b/dts/bindings/ppc/nxp,nx20p3483.yaml @@ -0,0 +1,39 @@ +# Copyright 2023 Google LLC +# SPDX-License-Identifier: Apache-2.0 + +description: NXP NX20P3483 Power path controller chip + +compatible: "nxp,nx20p3483" + +include: [base.yaml, i2c-device.yaml] + +properties: + irq-gpios: + type: phandle-array + description: Interrupt pin + + snk-ovp: + type: int + default: 1 + description: + Sink high-voltage overvoltage protection threshold in millivolts. + This value must be set using one of the NX20P348X_U_THRESHOLD_* defines. + + src-hv: + type: boolean + description: + If set, source role will use high-voltage path instead of 5V. + + src-hv-ocp: + type: int + default: 6 + description: + Source high-voltage overcurrent protection threshold in milliamperes. + This value must be set using one of the NX20P348X_I_THRESHOLD_* defines. + + src-5v-ocp: + type: int + default: 6 + description: + Source 5V overcurrent protection threshold in milliamperes. + This value must be set using one of the NX20P348X_I_THRESHOLD_* defines. diff --git a/include/zephyr/dt-bindings/usb-c/nxp_nx20p3483.h b/include/zephyr/dt-bindings/usb-c/nxp_nx20p3483.h new file mode 100644 index 00000000000..e25db0a1431 --- /dev/null +++ b/include/zephyr/dt-bindings/usb-c/nxp_nx20p3483.h @@ -0,0 +1,62 @@ +/* + * Copyright 2023 Google LLC + * SPDX-License-Identifier: Apache-2.0 + */ + +/** + * @file + * @brief Values used to define the sink overvoltage and source overcurrent protections thresholds. + */ + +#ifndef ZEPHYR_INCLUDE_DT_BINDINGS_USBC_NXP_NX20P3483_H_ +#define ZEPHYR_INCLUDE_DT_BINDINGS_USBC_NXP_NX20P3483_H_ + +/** Voltage limit of 6.0V */ +#define NX20P3483_U_THRESHOLD_6_0 0 +/** Voltage limit of 6.8V */ +#define NX20P3483_U_THRESHOLD_6_8 1 /* <-- default */ +/** Voltage limit of 10.0V */ +#define NX20P3483_U_THRESHOLD_10_0 2 +/** Voltage limit of 11.5V */ +#define NX20P3483_U_THRESHOLD_11_5 3 +/** Voltage limit of 14.0V */ +#define NX20P3483_U_THRESHOLD_14_0 4 +/** Voltage limit of 17.0V */ +#define NX20P3483_U_THRESHOLD_17_0 5 +/** Voltage limit of 23.0V */ +#define NX20P3483_U_THRESHOLD_23_0 6 + +/** Current limit of 400mA */ +#define NX20P3483_I_THRESHOLD_0_400 0 +/** Current limit of 600mA */ +#define NX20P3483_I_THRESHOLD_0_600 1 +/** Current limit of 800mA */ +#define NX20P3483_I_THRESHOLD_0_800 2 +/** Current limit of 1000mA */ +#define NX20P3483_I_THRESHOLD_1_000 3 +/** Current limit of 1200mA */ +#define NX20P3483_I_THRESHOLD_1_200 4 +/** Current limit of 1400mA */ +#define NX20P3483_I_THRESHOLD_1_400 5 +/** Current limit of 1600mA */ +#define NX20P3483_I_THRESHOLD_1_600 6 /* <-- default */ +/** Current limit of 1800mA */ +#define NX20P3483_I_THRESHOLD_1_800 7 +/** Current limit of 2000mA */ +#define NX20P3483_I_THRESHOLD_2_000 8 +/** Current limit of 2200mA */ +#define NX20P3483_I_THRESHOLD_2_200 9 +/** Current limit of 2400mA */ +#define NX20P3483_I_THRESHOLD_2_400 10 +/** Current limit of 2600mA */ +#define NX20P3483_I_THRESHOLD_2_600 11 +/** Current limit of 2800mA */ +#define NX20P3483_I_THRESHOLD_2_800 12 +/** Current limit of 3000mA */ +#define NX20P3483_I_THRESHOLD_3_000 13 +/** Current limit of 3200mA */ +#define NX20P3483_I_THRESHOLD_3_200 14 +/** Current limit of 3400mA */ +#define NX20P3483_I_THRESHOLD_3_400 15 + +#endif /* ZEPHYR_INCLUDE_DT_BINDINGS_USBC_NXP_NX20P3483_H_ */ From 53f01807f62d4aaa684d5ee38a9af89ef8719ffd Mon Sep 17 00:00:00 2001 From: Fabio Baltieri Date: Mon, 15 Jan 2024 11:18:54 +0000 Subject: [PATCH 2442/3723] SDK_VERSION: add a SDK_VERSION file Add a SDK_VERSION file pointing to the current SDK version. This is meant to be used by upstream and downstream CIs to automatically determined the current version of SDK based on the upstream checked out version, as well as the documentation references, and intended to stay in sync with the version used in the main CI. Signed-off-by: Fabio Baltieri --- SDK_VERSION | 1 + 1 file changed, 1 insertion(+) create mode 100644 SDK_VERSION diff --git a/SDK_VERSION b/SDK_VERSION new file mode 100644 index 00000000000..5f2491c5adc --- /dev/null +++ b/SDK_VERSION @@ -0,0 +1 @@ +0.16.4 From 24cf2f6548edd480ec10719f5f1fe8d1560c034d Mon Sep 17 00:00:00 2001 From: Fabio Baltieri Date: Mon, 15 Jan 2024 18:04:47 +0000 Subject: [PATCH 2443/3723] doc: use substitutions to replace all current harcoded SDK versions This creates a set of substitution rules to replace all current usages of SDK versions in the documentation, apart from a few that were not meant to be copy-pastable anyway and the version has just been swapped with a placeholder. Since code-block does not parse the content, these have all been replaced with parsed-literal. That one though parses URLs, which cannot be broken, so a series of URL substitutions are provided too. Signed-off-by: Fabio Baltieri --- doc/conf.py | 20 ++++- .../getting_started/installation_linux.rst | 27 ++++--- doc/develop/toolchains/zephyr_sdk.rst | 74 +++++++++---------- 3 files changed, 67 insertions(+), 54 deletions(-) diff --git a/doc/conf.py b/doc/conf.py index 808df88917f..a570eef7c35 100644 --- a/doc/conf.py +++ b/doc/conf.py @@ -66,6 +66,10 @@ release = version +# parse SDK version from 'SDK_VERSION' file +with open(ZEPHYR_BASE / "SDK_VERSION") as f: + sdk_version = f.read().strip() + # -- General configuration ------------------------------------------------ extensions = [ @@ -131,8 +135,22 @@ ("c:identifier", "va_list"), ] -rst_epilog = """ +SDK_URL_BASE="https://github.com/zephyrproject-rtos/sdk-ng/releases/download" + +rst_epilog = f""" .. include:: /substitutions.txt + +.. |sdk-version-literal| replace:: ``{sdk_version}`` +.. |sdk-version-trim| unicode:: {sdk_version} + :trim: +.. |sdk-version-ltrim| unicode:: {sdk_version} + :ltrim: +.. _Zephyr SDK bundle: https://github.com/zephyrproject-rtos/sdk-ng/releases/tag/v{sdk_version} +.. |sdk-url-linux| replace:: `{SDK_URL_BASE}/v{sdk_version}/zephyr-sdk-{sdk_version}_linux-x86_64.tar.xz` +.. |sdk-url-linux-sha| replace:: `{SDK_URL_BASE}/v{sdk_version}/sha256.sum` +.. |sdk-url-macos| replace:: `{SDK_URL_BASE}/v{sdk_version}/zephyr-sdk-{sdk_version}_macos-x86_64.tar.xz` +.. |sdk-url-macos-sha| replace:: `{SDK_URL_BASE}/v{sdk_version}/sha256.sum` +.. |sdk-url-windows| replace:: `{SDK_URL_BASE}/v{sdk_version}/zephyr-sdk-{sdk_version}_windows-x86_64.7z` """ # -- Options for HTML output ---------------------------------------------- diff --git a/doc/develop/getting_started/installation_linux.rst b/doc/develop/getting_started/installation_linux.rst index afe8fbfecf4..4638eded332 100644 --- a/doc/develop/getting_started/installation_linux.rst +++ b/doc/develop/getting_started/installation_linux.rst @@ -227,32 +227,31 @@ The Zephyr SDK supports the following target architectures: Follow these steps to install the Zephyr SDK: -#. Download and verify the `Zephyr SDK bundle - `_: +#. Download and verify the `Zephyr SDK bundle`_: - .. code-block:: bash + .. parsed-literal:: - wget https://github.com/zephyrproject-rtos/sdk-ng/releases/download/v0.16.4/zephyr-sdk-0.16.4_linux-x86_64.tar.xz - wget -O - https://github.com/zephyrproject-rtos/sdk-ng/releases/download/v0.16.4/sha256.sum | shasum --check --ignore-missing + wget |sdk-url-linux| + wget -O - |sdk-url-linux-sha| | shasum --check --ignore-missing - You can change ``0.16.4`` to another version if needed; the `Zephyr SDK - Releases`_ page contains all available SDK releases. + You can change |sdk-version-literal| to another version if needed; the + `Zephyr SDK Releases`_ page contains all available SDK releases. If your host architecture is 64-bit ARM (for example, Raspberry Pi), replace ``x86_64`` with ``aarch64`` in order to download the 64-bit ARM Linux SDK. #. Extract the Zephyr SDK bundle archive: - .. code-block:: bash + .. parsed-literal:: cd - tar xvf zephyr-sdk-0.16.4_linux-x86_64.tar.xz + tar xvf zephyr-sdk- |sdk-version-trim| _linux-x86_64.tar.xz #. Run the Zephyr SDK bundle setup script: - .. code-block:: bash + .. parsed-literal:: - cd zephyr-sdk-0.16.4 + cd zephyr-sdk- |sdk-version-ltrim| ./setup.sh If this fails, make sure Zephyr's dependencies were installed as described @@ -271,9 +270,9 @@ If you relocate the SDK directory, you need to re-run the setup script. * ``/opt`` * ``/usr/local`` - The Zephyr SDK bundle archive contains the ``zephyr-sdk-0.16.4`` directory and, when - extracted under ``$HOME``, the resulting installation path will be - ``$HOME/zephyr-sdk-0.16.4``. + The Zephyr SDK bundle archive contains the ``zephyr-sdk-`` + directory and, when extracted under ``$HOME``, the resulting installation + path will be ``$HOME/zephyr-sdk-``. If you install the Zephyr SDK outside any of these locations, you must register the Zephyr SDK in the CMake package registry by running the setup diff --git a/doc/develop/toolchains/zephyr_sdk.rst b/doc/develop/toolchains/zephyr_sdk.rst index 3574ca85bdd..14cf70f6141 100644 --- a/doc/develop/toolchains/zephyr_sdk.rst +++ b/doc/develop/toolchains/zephyr_sdk.rst @@ -74,7 +74,7 @@ Zephyr SDK installation .. toolchain_zephyr_sdk_install_start -.. note:: You can change ``0.16.4`` to another version in the instructions below +.. note:: You can change |sdk-version-literal| to another version in the instructions below if needed; the `Zephyr SDK Releases`_ page contains all available SDK releases. @@ -87,23 +87,22 @@ Zephyr SDK installation .. _ubuntu_zephyr_sdk: - #. Download and verify the `Zephyr SDK bundle - `_: + #. Download and verify the `Zephyr SDK bundle`_: - .. code-block:: bash + .. parsed-literal:: cd ~ - wget https://github.com/zephyrproject-rtos/sdk-ng/releases/download/v0.16.4/zephyr-sdk-0.16.4_linux-x86_64.tar.xz - wget -O - https://github.com/zephyrproject-rtos/sdk-ng/releases/download/v0.16.4/sha256.sum | shasum --check --ignore-missing + wget |sdk-url-linux| + wget -O - |sdk-url-linux-sha| | shasum --check --ignore-missing If your host architecture is 64-bit ARM (for example, Raspberry Pi), replace ``x86_64`` with ``aarch64`` in order to download the 64-bit ARM Linux SDK. #. Extract the Zephyr SDK bundle archive: - .. code-block:: bash + .. parsed-literal:: - tar xvf zephyr-sdk-0.16.4_linux-x86_64.tar.xz + tar xvf zephyr-sdk- |sdk-version-trim| _linux-x86_64.tar.xz .. note:: It is recommended to extract the Zephyr SDK bundle at one of the following locations: @@ -115,15 +114,15 @@ Zephyr SDK installation * ``/opt`` * ``/usr/local`` - The Zephyr SDK bundle archive contains the ``zephyr-sdk-0.16.4`` directory and, when - extracted under ``$HOME``, the resulting installation path will be - ``$HOME/zephyr-sdk-0.16.4``. + The Zephyr SDK bundle archive contains the ``zephyr-sdk-`` + directory and, when extracted under ``$HOME``, the resulting + installation path will be ``$HOME/zephyr-sdk-``. #. Run the Zephyr SDK bundle setup script: - .. code-block:: bash + .. parsed-literal:: - cd zephyr-sdk-0.16.4 + cd zephyr-sdk- |sdk-version-ltrim| ./setup.sh .. note:: @@ -135,32 +134,31 @@ Zephyr SDK installation #. Install `udev `_ rules, which allow you to flash most Zephyr boards as a regular user: - .. code-block:: bash + .. parsed-literal:: - sudo cp ~/zephyr-sdk-0.16.4/sysroots/x86_64-pokysdk-linux/usr/share/openocd/contrib/60-openocd.rules /etc/udev/rules.d + sudo cp ~/zephyr-sdk- |sdk-version-trim| /sysroots/x86_64-pokysdk-linux/usr/share/openocd/contrib/60-openocd.rules /etc/udev/rules.d sudo udevadm control --reload .. group-tab:: macOS .. _macos_zephyr_sdk: - #. Download and verify the `Zephyr SDK bundle - `_: + #. Download and verify the `Zephyr SDK bundle`_: - .. code-block:: bash + .. parsed-literal:: cd ~ - curl -L -O https://github.com/zephyrproject-rtos/sdk-ng/releases/download/v0.16.4/zephyr-sdk-0.16.4_macos-x86_64.tar.xz - curl -L https://github.com/zephyrproject-rtos/sdk-ng/releases/download/v0.16.4/sha256.sum | shasum --check --ignore-missing + curl -L -O |sdk-url-macos| + curl -L |sdk-url-macos-sha| | shasum --check --ignore-missing If your host architecture is 64-bit ARM (Apple Silicon, also known as M1), replace ``x86_64`` with ``aarch64`` in order to download the 64-bit ARM macOS SDK. #. Extract the Zephyr SDK bundle archive: - .. code-block:: bash + .. parsed-literal:: - tar xvf zephyr-sdk-0.16.4_macos-x86_64.tar.xz + tar xvf zephyr-sdk- |sdk-version-trim| _macos-x86_64.tar.xz .. note:: It is recommended to extract the Zephyr SDK bundle at one of the following locations: @@ -172,15 +170,15 @@ Zephyr SDK installation * ``/opt`` * ``/usr/local`` - The Zephyr SDK bundle archive contains the ``zephyr-sdk-0.16.4`` directory and, when - extracted under ``$HOME``, the resulting installation path will be - ``$HOME/zephyr-sdk-0.16.4``. + The Zephyr SDK bundle archive contains the ``zephyr-sdk-`` + directory and, when extracted under ``$HOME``, the resulting + installation path will be ``$HOME/zephyr-sdk-``. #. Run the Zephyr SDK bundle setup script: - .. code-block:: bash + .. parsed-literal:: - cd zephyr-sdk-0.16.4 + cd zephyr-sdk- |sdk-version-ltrim| ./setup.sh .. note:: @@ -195,19 +193,18 @@ Zephyr SDK installation #. Open a ``cmd.exe`` terminal window **as a regular user** - #. Download the `Zephyr SDK bundle - `_: + #. Download the `Zephyr SDK bundle`_: - .. code-block:: bat + .. parsed-literal:: cd %HOMEPATH% - wget https://github.com/zephyrproject-rtos/sdk-ng/releases/download/v0.16.4/zephyr-sdk-0.16.4_windows-x86_64.7z + wget |sdk-url-windows| #. Extract the Zephyr SDK bundle archive: - .. code-block:: bat + .. parsed-literal:: - 7z x zephyr-sdk-0.16.4_windows-x86_64.7z + 7z x zephyr-sdk- |sdk-version-trim| _windows-x86_64.7z .. note:: It is recommended to extract the Zephyr SDK bundle at one of the following locations: @@ -215,15 +212,15 @@ Zephyr SDK installation * ``%HOMEPATH%`` * ``%PROGRAMFILES%`` - The Zephyr SDK bundle archive contains the ``zephyr-sdk-0.16.4`` directory and, when - extracted under ``%HOMEPATH%``, the resulting installation path will be - ``%HOMEPATH%\zephyr-sdk-0.16.4``. + The Zephyr SDK bundle archive contains the ``zephyr-sdk-`` + directory and, when extracted under ``%HOMEPATH%``, the resulting + installation path will be ``%HOMEPATH%\zephyr-sdk-``. #. Run the Zephyr SDK bundle setup script: - .. code-block:: bat + .. parsed-literal:: - cd zephyr-sdk-0.16.4 + cd zephyr-sdk- |sdk-version-ltrim| setup.cmd .. note:: @@ -232,7 +229,6 @@ Zephyr SDK installation You must rerun the setup script if you relocate the Zephyr SDK bundle directory after the initial setup. -.. _Zephyr SDK bundle: https://github.com/zephyrproject-rtos/sdk-ng/releases/tag/v0.16.4 .. _Zephyr SDK Releases: https://github.com/zephyrproject-rtos/sdk-ng/tags .. _Zephyr SDK Version Compatibility Matrix: https://github.com/zephyrproject-rtos/sdk-ng/wiki/Zephyr-SDK-Version-Compatibility-Matrix From 6529e316a56a5ff78aa01852401dbaf8f1913bf6 Mon Sep 17 00:00:00 2001 From: Fabio Baltieri Date: Mon, 15 Jan 2024 18:29:46 +0000 Subject: [PATCH 2444/3723] workflows: find the SDK version from the top level SDK_VERSION file Drop all hardcoded ZEPHYR_SDK_INSTALL_DIR settings, set the variable automatically from the SDK_VERSION file instead. Signed-off-by: Fabio Baltieri --- .github/workflows/bsim-tests.yaml | 3 ++- .github/workflows/clang.yaml | 3 ++- .github/workflows/codecov.yaml | 7 ++++--- .github/workflows/errno.yml | 6 ++++-- .github/workflows/footprint-tracking.yml | 5 ++++- .github/workflows/footprint.yml | 5 ++++- .github/workflows/twister.yaml | 6 ++++-- .github/workflows/twister_tests_blackbox.yml | 4 ++-- 8 files changed, 26 insertions(+), 13 deletions(-) diff --git a/.github/workflows/bsim-tests.yaml b/.github/workflows/bsim-tests.yaml index c6abce73913..c62c75c5ec0 100644 --- a/.github/workflows/bsim-tests.yaml +++ b/.github/workflows/bsim-tests.yaml @@ -38,7 +38,6 @@ jobs: - /repo-cache/zephyrproject:/github/cache/zephyrproject env: ZEPHYR_TOOLCHAIN_VARIANT: zephyr - ZEPHYR_SDK_INSTALL_DIR: /opt/toolchains/zephyr-sdk-0.16.4 BSIM_OUT_PATH: /opt/bsim/ BSIM_COMPONENTS_PATH: /opt/bsim/components EDTT_PATH: ../tools/edtt @@ -82,6 +81,8 @@ jobs: west update --path-cache /github/cache/zephyrproject 2>&1 1> west.update.log || west update --path-cache /github/cache/zephyrproject 2>&1 1> west.update.log || ( rm -rf ../modules ../bootloader ../tools && west update --path-cache /github/cache/zephyrproject) west forall -c 'git reset --hard HEAD' + echo "ZEPHYR_SDK_INSTALL_DIR=/opt/toolchains/zephyr-sdk-$( cat SDK_VERSION )" >> $GITHUB_ENV + - name: Check common triggering files uses: tj-actions/changed-files@v41 id: check-common-files diff --git a/.github/workflows/clang.yaml b/.github/workflows/clang.yaml index 210617c8e56..dd1d0687d63 100644 --- a/.github/workflows/clang.yaml +++ b/.github/workflows/clang.yaml @@ -20,7 +20,6 @@ jobs: matrix: platform: ["native_sim"] env: - ZEPHYR_SDK_INSTALL_DIR: /opt/toolchains/zephyr-sdk-0.16.4 LLVM_TOOLCHAIN_PATH: /usr/lib/llvm-16 COMMIT_RANGE: ${{ github.event.pull_request.base.sha }}..${{ github.event.pull_request.head.sha }} BASE_REF: ${{ github.base_ref }} @@ -66,6 +65,8 @@ jobs: # west caching). west update --path-cache /github/cache/zephyrproject 2>&1 1> west.log || west update --path-cache /github/cache/zephyrproject 2>&1 1> west2.log || ( rm -rf ../modules ../bootloader ../tools && west update --path-cache /github/cache/zephyrproject) + echo "ZEPHYR_SDK_INSTALL_DIR=/opt/toolchains/zephyr-sdk-$( cat SDK_VERSION )" >> $GITHUB_ENV + - name: Check Environment run: | cmake --version diff --git a/.github/workflows/codecov.yaml b/.github/workflows/codecov.yaml index 85545cdc712..9a2add5aeb4 100644 --- a/.github/workflows/codecov.yaml +++ b/.github/workflows/codecov.yaml @@ -21,8 +21,6 @@ jobs: fail-fast: false matrix: platform: ["mps2_an385", "native_sim", "qemu_x86", "unit_testing"] - env: - ZEPHYR_SDK_INSTALL_DIR: /opt/toolchains/zephyr-sdk-0.16.4 steps: - name: Apply container owner mismatch workaround run: | @@ -52,11 +50,14 @@ jobs: west init -l . || true west update 1> west.update.log || west update 1> west.update-2.log - - name: Check Environment + - name: Environment Setup run: | cmake --version gcc --version ls -la + + echo "ZEPHYR_SDK_INSTALL_DIR=/opt/toolchains/zephyr-sdk-$( cat SDK_VERSION )" >> $GITHUB_ENV + - name: Prepare ccache keys id: ccache_cache_prop shell: cmake -P {0} diff --git a/.github/workflows/errno.yml b/.github/workflows/errno.yml index cea3f6f747c..629e09bfca3 100644 --- a/.github/workflows/errno.yml +++ b/.github/workflows/errno.yml @@ -11,8 +11,6 @@ jobs: runs-on: ubuntu-22.04 container: image: ghcr.io/zephyrproject-rtos/ci:v0.26.6 - env: - ZEPHYR_SDK_INSTALL_DIR: /opt/toolchains/zephyr-sdk-0.16.4 steps: - name: Apply container owner mismatch workaround @@ -26,6 +24,10 @@ jobs: - name: checkout uses: actions/checkout@v3 + - name: Environment Setup + run: | + echo "ZEPHYR_SDK_INSTALL_DIR=/opt/toolchains/zephyr-sdk-$( cat SDK_VERSION )" >> $GITHUB_ENV + - name: Run errno.py run: | export ZEPHYR_BASE=${PWD} diff --git a/.github/workflows/footprint-tracking.yml b/.github/workflows/footprint-tracking.yml index f35dd2e6759..a1b12d30eff 100644 --- a/.github/workflows/footprint-tracking.yml +++ b/.github/workflows/footprint-tracking.yml @@ -30,7 +30,6 @@ jobs: strategy: fail-fast: false env: - ZEPHYR_SDK_INSTALL_DIR: /opt/toolchains/zephyr-sdk-0.16.4 ZEPHYR_TOOLCHAIN_VARIANT: zephyr steps: - name: Apply container owner mismatch workaround @@ -57,6 +56,10 @@ jobs: ref: ${{ github.event.pull_request.head.sha }} fetch-depth: 0 + - name: Environment Setup + run: | + echo "ZEPHYR_SDK_INSTALL_DIR=/opt/toolchains/zephyr-sdk-$( cat SDK_VERSION )" >> $GITHUB_ENV + - name: west setup run: | west init -l . || true diff --git a/.github/workflows/footprint.yml b/.github/workflows/footprint.yml index be5a77c13e6..bf8e5e32059 100644 --- a/.github/workflows/footprint.yml +++ b/.github/workflows/footprint.yml @@ -16,7 +16,6 @@ jobs: strategy: fail-fast: false env: - ZEPHYR_SDK_INSTALL_DIR: /opt/toolchains/zephyr-sdk-0.16.4 ZEPHYR_TOOLCHAIN_VARIANT: zephyr steps: - name: Apply container owner mismatch workaround @@ -37,6 +36,10 @@ jobs: ref: ${{ github.event.pull_request.head.sha }} fetch-depth: 0 + - name: Environment Setup + run: | + echo "ZEPHYR_SDK_INSTALL_DIR=/opt/toolchains/zephyr-sdk-$( cat SDK_VERSION )" >> $GITHUB_ENV + - name: west setup run: | west init -l . || true diff --git a/.github/workflows/twister.yaml b/.github/workflows/twister.yaml index 983a97f8973..6d8c7dfdee5 100644 --- a/.github/workflows/twister.yaml +++ b/.github/workflows/twister.yaml @@ -36,7 +36,6 @@ jobs: MATRIX_SIZE: 10 PUSH_MATRIX_SIZE: 15 DAILY_MATRIX_SIZE: 80 - ZEPHYR_SDK_INSTALL_DIR: /opt/toolchains/zephyr-sdk-0.16.4 BSIM_OUT_PATH: /opt/bsim/ BSIM_COMPONENTS_PATH: /opt/bsim/components TESTS_PER_BUILDER: 700 @@ -80,6 +79,8 @@ jobs: west update --path-cache /github/cache/zephyrproject 2>&1 1> west.update.log || west update --path-cache /github/cache/zephyrproject 2>&1 1> west.update.log || ( rm -rf ../modules ../bootloader ../tools && west update --path-cache /github/cache/zephyrproject) west forall -c 'git reset --hard HEAD' + echo "ZEPHYR_SDK_INSTALL_DIR=/opt/toolchains/zephyr-sdk-$( cat SDK_VERSION )" >> $GITHUB_ENV + - name: Generate Test Plan with Twister if: github.event_name == 'pull_request_target' id: test-plan @@ -131,7 +132,6 @@ jobs: matrix: subset: ${{fromJSON(needs.twister-build-prep.outputs.subset)}} env: - ZEPHYR_SDK_INSTALL_DIR: /opt/toolchains/zephyr-sdk-0.16.4 BSIM_OUT_PATH: /opt/bsim/ BSIM_COMPONENTS_PATH: /opt/bsim/components TWISTER_COMMON: ' --force-color --inline-logs -v -N -M --retry-failed 3 ' @@ -185,6 +185,8 @@ jobs: wget -c https://github.com/Kitware/ninja/releases/download/v1.11.1.g95dee.kitware.jobserver-1/ninja-1.11.1.g95dee.kitware.jobserver-1_x86_64-linux-gnu.tar.gz -O - | tar xz --strip-components=1 sudo cp ninja /usr/local/bin + echo "ZEPHYR_SDK_INSTALL_DIR=/opt/toolchains/zephyr-sdk-$( cat SDK_VERSION )" >> $GITHUB_ENV + - name: Check Environment run: | cmake --version diff --git a/.github/workflows/twister_tests_blackbox.yml b/.github/workflows/twister_tests_blackbox.yml index 5e5a880a1a9..9ea454f8e59 100644 --- a/.github/workflows/twister_tests_blackbox.yml +++ b/.github/workflows/twister_tests_blackbox.yml @@ -23,8 +23,6 @@ jobs: os: [ubuntu-22.04] container: image: ghcr.io/zephyrproject-rtos/ci:v0.26.6 - env: - ZEPHYR_SDK_INSTALL_DIR: /opt/toolchains/zephyr-sdk-0.16.4 steps: - name: Apply Container Owner Mismatch Workaround @@ -47,6 +45,8 @@ jobs: west update --path-cache /github/cache/zephyrproject 2>&1 1> west.update.log || west update --path-cache /github/cache/zephyrproject 2>&1 1> west.update.log || ( rm -rf ../modules ../bootloader ../tools && west update --path-cache /github/cache/zephyrproject) west forall -c 'git reset --hard HEAD' + echo "ZEPHYR_SDK_INSTALL_DIR=/opt/toolchains/zephyr-sdk-$( cat SDK_VERSION )" >> $GITHUB_ENV + - name: Set Up Python ${{ matrix.python-version }} uses: actions/setup-python@v4 with: From d34cd3e311f796640d14c2f2a2b32ff7336b0308 Mon Sep 17 00:00:00 2001 From: Jun Lin Date: Tue, 16 Jan 2024 13:17:42 +0800 Subject: [PATCH 2445/3723] driver: I2C: npcx: re-enable interrupts after bus error When the I2C is in the target mode and encounters the bus error, the driver has to reset the bus to recover the I2C hardware. However, when the hardware is disabled, the interrupt enable bits are also cleared automatically by design. As a result, we need to enable the interrupts after resetting the I2C hardware. Signed-off-by: Jun Lin --- drivers/i2c/i2c_npcx_controller.c | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/drivers/i2c/i2c_npcx_controller.c b/drivers/i2c/i2c_npcx_controller.c index 5dbdbc65aa9..1349a535b93 100644 --- a/drivers/i2c/i2c_npcx_controller.c +++ b/drivers/i2c/i2c_npcx_controller.c @@ -770,8 +770,15 @@ static void i2c_ctrl_target_isr(const struct device *dev, uint8_t status) inst->SMBCTL2 &= ~BIT(NPCX_SMBCTL2_ENABLE); inst->SMBCTL2 |= BIT(NPCX_SMBCTL2_ENABLE); + /* + * Re-enable interrupts because they are turned off after the SMBus module + * is reset above. + */ + inst->SMBCTL1 |= BIT(NPCX_SMBCTL1_NMINTE) | BIT(NPCX_SMBCTL1_INTEN); /* End of transaction */ data->oper_state = NPCX_I2C_IDLE; + + LOG_DBG("target: Bus error on port%02x!", data->port); return; } From cf13057c8d6d2f125920acfd0fcd69d0b6d198cd Mon Sep 17 00:00:00 2001 From: Yong Cong Sin Date: Tue, 16 Jan 2024 13:15:42 +0800 Subject: [PATCH 2446/3723] samples: posix: uname: convert to use `printf` Convert to `printf` from `printk` to be more POSIX-y. Signed-off-by: Yong Cong Sin --- samples/posix/uname/src/main.c | 15 +++++++-------- 1 file changed, 7 insertions(+), 8 deletions(-) diff --git a/samples/posix/uname/src/main.c b/samples/posix/uname/src/main.c index 93af0af529d..45c2f2d8e76 100644 --- a/samples/posix/uname/src/main.c +++ b/samples/posix/uname/src/main.c @@ -4,11 +4,10 @@ * SPDX-License-Identifier: Apache-2.0 */ +#include #include - #include -#include #include int main(void) @@ -17,12 +16,12 @@ int main(void) uname(&info); - printk("\nPrinting everything in utsname...\n"); - printk("sysname[%zu]: %s\n", sizeof(info.sysname), info.sysname); - printk("nodename[%zu]: %s\n", sizeof(info.nodename), info.nodename); - printk("release[%zu]: %s\n", sizeof(info.release), info.release); - printk("version[%zu]: %s\n", sizeof(info.version), info.version); - printk("machine[%zu]: %s\n", sizeof(info.machine), info.machine); + printf("\nPrinting everything in utsname...\n"); + printf("sysname[%zu]: %s\n", sizeof(info.sysname), info.sysname); + printf("nodename[%zu]: %s\n", sizeof(info.nodename), info.nodename); + printf("release[%zu]: %s\n", sizeof(info.release), info.release); + printf("version[%zu]: %s\n", sizeof(info.version), info.version); + printf("machine[%zu]: %s\n", sizeof(info.machine), info.machine); return 0; } From 48c16f9052db4733bb9d583c95861fca076ee747 Mon Sep 17 00:00:00 2001 From: Yong Cong Sin Date: Tue, 16 Jan 2024 14:33:12 +0800 Subject: [PATCH 2447/3723] posix: uname: move `uname` shell from sample Relocate the `uname` shell implementation from uname sample, so that it can be reused by other application and the uname sample only uses POSIX APIs. Signed-off-by: Yong Cong Sin --- lib/posix/CMakeLists.txt | 1 + lib/posix/Kconfig | 2 + lib/posix/shell/CMakeLists.txt | 4 + lib/posix/shell/Kconfig | 8 ++ lib/posix/shell/Kconfig.uname | 12 +++ lib/posix/shell/uname.c | 157 +++++++++++++++++++++++++++++++++ samples/posix/uname/prj.conf | 2 +- samples/posix/uname/src/main.c | 150 ------------------------------- 8 files changed, 185 insertions(+), 151 deletions(-) create mode 100644 lib/posix/shell/CMakeLists.txt create mode 100644 lib/posix/shell/Kconfig create mode 100644 lib/posix/shell/Kconfig.uname create mode 100644 lib/posix/shell/uname.c diff --git a/lib/posix/CMakeLists.txt b/lib/posix/CMakeLists.txt index 21d25580aac..999fcd1f3ea 100644 --- a/lib/posix/CMakeLists.txt +++ b/lib/posix/CMakeLists.txt @@ -36,6 +36,7 @@ endif() zephyr_library() add_subdirectory_ifdef(CONFIG_GETOPT getopt) +add_subdirectory_ifdef(CONFIG_SHELL shell) zephyr_library_sources_ifdef(CONFIG_EVENTFD eventfd.c) zephyr_library_sources_ifdef(CONFIG_FNMATCH fnmatch.c) zephyr_library_sources_ifdef(CONFIG_POSIX_API perror.c) diff --git a/lib/posix/Kconfig b/lib/posix/Kconfig index 3202c13b7dd..a6f5021d520 100644 --- a/lib/posix/Kconfig +++ b/lib/posix/Kconfig @@ -55,3 +55,5 @@ source "lib/posix/Kconfig.signal" source "lib/posix/Kconfig.spinlock" source "lib/posix/Kconfig.timer" source "lib/posix/Kconfig.uname" + +rsource "shell/Kconfig" diff --git a/lib/posix/shell/CMakeLists.txt b/lib/posix/shell/CMakeLists.txt new file mode 100644 index 00000000000..a28853f142c --- /dev/null +++ b/lib/posix/shell/CMakeLists.txt @@ -0,0 +1,4 @@ +# Copyright (c) 2024 Meta +# SPDX-License-Identifier: Apache-2.0 + +zephyr_library_sources_ifdef(CONFIG_POSIX_UNAME_SHELL uname.c) diff --git a/lib/posix/shell/Kconfig b/lib/posix/shell/Kconfig new file mode 100644 index 00000000000..a2298040d81 --- /dev/null +++ b/lib/posix/shell/Kconfig @@ -0,0 +1,8 @@ +# Copyright (c) 2024 Meta +# SPDX-License-Identifier: Apache-2.0 + +if SHELL + +rsource "Kconfig.uname" + +endif # SHELL diff --git a/lib/posix/shell/Kconfig.uname b/lib/posix/shell/Kconfig.uname new file mode 100644 index 00000000000..c627bb1dc23 --- /dev/null +++ b/lib/posix/shell/Kconfig.uname @@ -0,0 +1,12 @@ +# Copyright (c) 2024 Meta +# SPDX-License-Identifier: Apache-2.0 + +if POSIX_UNAME + +config POSIX_UNAME_SHELL + bool "Support for `uname` command" + select SHELL_GETOPT + help + Support for `uname` command in the terminal. + +endif # POSIX_UNAME diff --git a/lib/posix/shell/uname.c b/lib/posix/shell/uname.c new file mode 100644 index 00000000000..28f057e204b --- /dev/null +++ b/lib/posix/shell/uname.c @@ -0,0 +1,157 @@ +/* + * Copyright (c) 2024 Meta + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include + +#include +#include + +#define UNAME_KERNEL BIT(0) +#define UNAME_NODE BIT(1) +#define UNAME_RELEASE BIT(2) +#define UNAME_VERSION BIT(3) +#define UNAME_MACHINE BIT(4) +#define UNAME_PLATFORM BIT(5) +#define UNAME_UNKNOWN BIT(6) +#define UNAME_ALL \ + (UNAME_KERNEL | UNAME_NODE | UNAME_RELEASE | UNAME_VERSION | UNAME_MACHINE | UNAME_PLATFORM) + +static void uname_print_usage(const struct shell *sh) +{ + shell_print(sh, "usage: uname [-asonrvmpi]"); +} + +static int uname_cmd_handler(const struct shell *sh, size_t argc, char **argv) +{ + struct getopt_state *state = getopt_state_get(); + struct utsname info; + unsigned int set; + int option; + char badarg = 0; + int ret; + + set = 0; + + /* Get the uname options */ + + optind = 1; + while ((option = getopt(argc, argv, "asonrvmpi")) != -1) { + switch (option) { + case 'a': + set = UNAME_ALL; + break; + + case 'o': + case 's': + set |= UNAME_KERNEL; + break; + + case 'n': + set |= UNAME_NODE; + break; + + case 'r': + set |= UNAME_RELEASE; + break; + + case 'v': + set |= UNAME_VERSION; + break; + + case 'm': + set |= UNAME_MACHINE; + break; + + case 'p': + if (set != UNAME_ALL) { + set |= UNAME_UNKNOWN; + } + break; + + case 'i': + set |= UNAME_PLATFORM; + break; + + case '?': + default: + badarg = (char)state->optopt; + break; + } + } + + if (argc != optind) { + shell_error(sh, "extra operand %s", argv[optind]); + uname_print_usage(sh); + return -1; + } + + /* If a bad argument was encountered, then return without processing the + * command + */ + + if (badarg != 0) { + shell_error(sh, "uname: illegal option -- %c", badarg); + uname_print_usage(sh); + return -1; + } + + /* If nothing is provided on the command line, the default is -s */ + + if (set == 0) { + set = UNAME_KERNEL; + } + + /* Get uname data */ + + ret = uname(&info); + if (ret < 0) { + shell_error(sh, "cannot get system name"); + return -1; + } + + /* Process each option */ + + /* print the kernel/operating system name */ + if (set & UNAME_KERNEL) { + shell_fprintf(sh, SHELL_NORMAL, "%s ", info.sysname); + } + + /* Print nodename */ + if (set & UNAME_NODE) { + shell_fprintf(sh, SHELL_NORMAL, "%s ", info.nodename); + } + + /* Print the kernel release */ + if (set & UNAME_RELEASE) { + shell_fprintf(sh, SHELL_NORMAL, "%s ", info.release); + } + + /* Print the kernel version */ + if (set & UNAME_VERSION) { + shell_fprintf(sh, SHELL_NORMAL, "%s ", info.version); + } + + /* Print the machine hardware name */ + if (set & UNAME_MACHINE) { + shell_fprintf(sh, SHELL_NORMAL, "%s ", info.machine); + } + + /* Print the machine platform name */ + if (set & UNAME_PLATFORM) { + shell_fprintf(sh, SHELL_NORMAL, "%s ", CONFIG_BOARD); + } + + /* Print "unknown" */ + if (set & UNAME_UNKNOWN) { + shell_fprintf(sh, SHELL_NORMAL, "%s ", "unknown"); + } + + shell_fprintf(sh, SHELL_NORMAL, "\n"); + + return 0; +} + +SHELL_CMD_REGISTER(uname, NULL, NULL, uname_cmd_handler); diff --git a/samples/posix/uname/prj.conf b/samples/posix/uname/prj.conf index 7b1dfc80964..1f171e76a4b 100644 --- a/samples/posix/uname/prj.conf +++ b/samples/posix/uname/prj.conf @@ -1,4 +1,4 @@ CONFIG_POSIX_API=y CONFIG_SHELL=y -CONFIG_SHELL_GETOPT=y +CONFIG_POSIX_UNAME_SHELL=y CONFIG_MP_MAX_NUM_CPUS=1 diff --git a/samples/posix/uname/src/main.c b/samples/posix/uname/src/main.c index 45c2f2d8e76..c6a480fe6dd 100644 --- a/samples/posix/uname/src/main.c +++ b/samples/posix/uname/src/main.c @@ -5,11 +5,8 @@ */ #include -#include #include -#include - int main(void) { struct utsname info; @@ -25,150 +22,3 @@ int main(void) return 0; } - -#define UNAME_KERNEL BIT(0) -#define UNAME_NODE BIT(1) -#define UNAME_RELEASE BIT(2) -#define UNAME_VERSION BIT(3) -#define UNAME_MACHINE BIT(4) -#define UNAME_PLATFORM BIT(5) -#define UNAME_UNKNOWN BIT(6) -#define UNAME_ALL \ - (UNAME_KERNEL | UNAME_NODE | UNAME_RELEASE | UNAME_VERSION | UNAME_MACHINE | UNAME_PLATFORM) - -static void uname_print_usage(const struct shell *sh) -{ - shell_print(sh, "usage: uname [-asonrvmpi]"); -} - -static int uname_cmd_handler(const struct shell *sh, size_t argc, char **argv) -{ - struct getopt_state *state = getopt_state_get(); - struct utsname info; - unsigned int set; - int option; - char badarg = 0; - int ret; - - set = 0; - - /* Get the uname options */ - - optind = 1; - while ((option = getopt(argc, argv, "asonrvmpi")) != -1) { - switch (option) { - case 'a': - set = UNAME_ALL; - break; - - case 'o': - case 's': - set |= UNAME_KERNEL; - break; - - case 'n': - set |= UNAME_NODE; - break; - - case 'r': - set |= UNAME_RELEASE; - break; - - case 'v': - set |= UNAME_VERSION; - break; - - case 'm': - set |= UNAME_MACHINE; - break; - - case 'p': - if (set != UNAME_ALL) { - set |= UNAME_UNKNOWN; - } - break; - - case 'i': - set |= UNAME_PLATFORM; - break; - - case '?': - default: - badarg = (char)state->optopt; - break; - } - } - - if (argc != optind) { - shell_error(sh, "extra operand %s", argv[optind]); - uname_print_usage(sh); - return -1; - } - - /* If a bad argument was encountered, then return without processing the - * command - */ - - if (badarg != 0) { - shell_error(sh, "uname: illegal option -- %c", badarg); - uname_print_usage(sh); - return -1; - } - - /* If nothing is provided on the command line, the default is -s */ - - if (set == 0) { - set = UNAME_KERNEL; - } - - /* Get uname data */ - - ret = uname(&info); - if (ret < 0) { - shell_error(sh, "cannot get system name"); - return -1; - } - - /* Process each option */ - - /* print the kernel/operating system name */ - if (set & UNAME_KERNEL) { - shell_fprintf(sh, SHELL_NORMAL, "%s ", info.sysname); - } - - /* Print nodename */ - if (set & UNAME_NODE) { - shell_fprintf(sh, SHELL_NORMAL, "%s ", info.nodename); - } - - /* Print the kernel release */ - if (set & UNAME_RELEASE) { - shell_fprintf(sh, SHELL_NORMAL, "%s ", info.release); - } - - /* Print the kernel version */ - if (set & UNAME_VERSION) { - shell_fprintf(sh, SHELL_NORMAL, "%s ", info.version); - } - - /* Print the machine hardware name */ - if (set & UNAME_MACHINE) { - shell_fprintf(sh, SHELL_NORMAL, "%s ", info.machine); - } - - /* Print the machine platform name */ - if (set & UNAME_PLATFORM) { - shell_fprintf(sh, SHELL_NORMAL, "%s ", CONFIG_BOARD); - } - - /* Print "unknown" */ - if (set & UNAME_UNKNOWN) { - shell_fprintf(sh, SHELL_NORMAL, "%s ", "unknown"); - } - - shell_fprintf(sh, SHELL_NORMAL, "\n"); - - return 0; -} - -SHELL_CMD_REGISTER(uname, NULL, NULL, uname_cmd_handler); From 635dabf07a2637777dbc16c01006bf0d9a3ebe2a Mon Sep 17 00:00:00 2001 From: Yong Cong Sin Date: Tue, 16 Jan 2024 23:03:51 +0800 Subject: [PATCH 2448/3723] posix: uname: shell: update help message with more information Populate the help message with more information when an error occurs. Signed-off-by: Yong Cong Sin --- lib/posix/shell/uname.c | 18 ++++++++++++++++-- 1 file changed, 16 insertions(+), 2 deletions(-) diff --git a/lib/posix/shell/uname.c b/lib/posix/shell/uname.c index 28f057e204b..345ebc6e33c 100644 --- a/lib/posix/shell/uname.c +++ b/lib/posix/shell/uname.c @@ -19,9 +19,23 @@ #define UNAME_ALL \ (UNAME_KERNEL | UNAME_NODE | UNAME_RELEASE | UNAME_VERSION | UNAME_MACHINE | UNAME_PLATFORM) +#define HELP_USAGE \ + "Usage: uname [OPTION]\n" \ + "Print system information\n" \ + "\n" \ + " -a, all informationn\n" \ + " -s, kernel name\n" \ + " -o, operating system\n" \ + " -n, network node hostname\n" \ + " -r, kernel release\n" \ + " -v, kernel version\n" \ + " -m, machine hardware name\n" \ + " -p, processor type\n" \ + " -i, hardware platform\n" + static void uname_print_usage(const struct shell *sh) { - shell_print(sh, "usage: uname [-asonrvmpi]"); + shell_print(sh, HELP_USAGE); } static int uname_cmd_handler(const struct shell *sh, size_t argc, char **argv) @@ -83,7 +97,7 @@ static int uname_cmd_handler(const struct shell *sh, size_t argc, char **argv) } if (argc != optind) { - shell_error(sh, "extra operand %s", argv[optind]); + shell_error(sh, "uname: extra operand %s", argv[optind]); uname_print_usage(sh); return -1; } From 2cd0265f7eab0cdaaf9facde40ffafade1b69ece Mon Sep 17 00:00:00 2001 From: Yong Cong Sin Date: Wed, 17 Jan 2024 12:05:18 +0800 Subject: [PATCH 2449/3723] samples: posix: uname: add Makefile to compile on POSIX OS Previously the sample was using some headers that aren't available to the host, now we can add a `Makefile.host` to compile the example on a POSIX OS like Linux: ``` # Go to the sample dir cd ${ZEPHYR_BASE}/samples/posix/uname # Compile the sample make -f Makefile.host # Run the binary ./build/uname sysname[65]: Linux nodename[65]: LAPTOP-YC release[65]: 5.10.16.3-microsoft-standard-WSL2 version[65]: #1 SMP Fri Apr 2 22:23:49 UTC 2021 machine[65]: x86_64 ``` Signed-off-by: Yong Cong Sin --- samples/posix/uname/Makefile.host | 5 +++++ 1 file changed, 5 insertions(+) create mode 100644 samples/posix/uname/Makefile.host diff --git a/samples/posix/uname/Makefile.host b/samples/posix/uname/Makefile.host new file mode 100644 index 00000000000..d5077cf0ec6 --- /dev/null +++ b/samples/posix/uname/Makefile.host @@ -0,0 +1,5 @@ +# This makefile builds the sample for a POSIX system, like Linux + +uname: src/main.c + mkdir -p build + $(CC) $^ -o build/$@ From 45c554d082d44de144dd2f8956ba115855f52ff5 Mon Sep 17 00:00:00 2001 From: Yong Cong Sin Date: Thu, 18 Jan 2024 00:36:58 +0800 Subject: [PATCH 2450/3723] posix: shell: introduce top level `posix` command Added a top level `posix` shell command for other POSIX commands. Currently only `uname` is supported. New POSIX commands can be added by including the `posix_shell.h` header and use the `POSIX_CMD_ADD` helper macro. Signed-off-by: Yong Cong Sin --- lib/posix/shell/CMakeLists.txt | 1 + lib/posix/shell/Kconfig | 5 +++++ lib/posix/shell/Kconfig.uname | 1 + lib/posix/shell/posix_shell.c | 10 ++++++++++ lib/posix/shell/posix_shell.h | 16 ++++++++++++++++ lib/posix/shell/uname.c | 4 +++- 6 files changed, 36 insertions(+), 1 deletion(-) create mode 100644 lib/posix/shell/posix_shell.c create mode 100644 lib/posix/shell/posix_shell.h diff --git a/lib/posix/shell/CMakeLists.txt b/lib/posix/shell/CMakeLists.txt index a28853f142c..b6dfe6a565f 100644 --- a/lib/posix/shell/CMakeLists.txt +++ b/lib/posix/shell/CMakeLists.txt @@ -1,4 +1,5 @@ # Copyright (c) 2024 Meta # SPDX-License-Identifier: Apache-2.0 +zephyr_library_sources_ifdef(CONFIG_POSIX_SHELL posix_shell.c) zephyr_library_sources_ifdef(CONFIG_POSIX_UNAME_SHELL uname.c) diff --git a/lib/posix/shell/Kconfig b/lib/posix/shell/Kconfig index a2298040d81..1ce4ae5a959 100644 --- a/lib/posix/shell/Kconfig +++ b/lib/posix/shell/Kconfig @@ -3,6 +3,11 @@ if SHELL +config POSIX_SHELL + bool + help + Compile the parent `posix` shell command. + rsource "Kconfig.uname" endif # SHELL diff --git a/lib/posix/shell/Kconfig.uname b/lib/posix/shell/Kconfig.uname index c627bb1dc23..11ea1166433 100644 --- a/lib/posix/shell/Kconfig.uname +++ b/lib/posix/shell/Kconfig.uname @@ -6,6 +6,7 @@ if POSIX_UNAME config POSIX_UNAME_SHELL bool "Support for `uname` command" select SHELL_GETOPT + select POSIX_SHELL help Support for `uname` command in the terminal. diff --git a/lib/posix/shell/posix_shell.c b/lib/posix/shell/posix_shell.c new file mode 100644 index 00000000000..95fdd4ef5a0 --- /dev/null +++ b/lib/posix/shell/posix_shell.c @@ -0,0 +1,10 @@ +/* + * Copyright (c) 2024 Meta + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include + +SHELL_SUBCMD_SET_CREATE(posix_cmds, (posix)); +SHELL_CMD_ARG_REGISTER(posix, &posix_cmds, "POSIX shell commands", NULL, 2, 0); diff --git a/lib/posix/shell/posix_shell.h b/lib/posix/shell/posix_shell.h new file mode 100644 index 00000000000..cb17d613b18 --- /dev/null +++ b/lib/posix/shell/posix_shell.h @@ -0,0 +1,16 @@ +/* + * Copyright (c) 2024 Meta + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#ifndef ZEPHYR_LIB_POSIX_SHELL_POSIX_SHELL_H_ +#define ZEPHYR_LIB_POSIX_SHELL_POSIX_SHELL_H_ + +#include + +/* Add command to the set of POSIX subcommands, see `SHELL_SUBCMD_ADD` */ +#define POSIX_CMD_ADD(_syntax, _subcmd, _help, _handler, _mand, _opt) \ + SHELL_SUBCMD_ADD((posix), _syntax, _subcmd, _help, _handler, _mand, _opt); + +#endif /* ZEPHYR_LIB_POSIX_SHELL_POSIX_SHELL_H_ */ diff --git a/lib/posix/shell/uname.c b/lib/posix/shell/uname.c index 345ebc6e33c..54e12de9a59 100644 --- a/lib/posix/shell/uname.c +++ b/lib/posix/shell/uname.c @@ -6,6 +6,8 @@ #include +#include "posix_shell.h" + #include #include @@ -168,4 +170,4 @@ static int uname_cmd_handler(const struct shell *sh, size_t argc, char **argv) return 0; } -SHELL_CMD_REGISTER(uname, NULL, NULL, uname_cmd_handler); +POSIX_CMD_ADD(uname, NULL, "Print system information", uname_cmd_handler, 1, 1); From 66fdd39ec5de0055d4a3f82d1133dbec5803222c Mon Sep 17 00:00:00 2001 From: Yong Cong Sin Date: Wed, 17 Jan 2024 12:36:21 +0800 Subject: [PATCH 2451/3723] posix: pthread: fix `zephyr_to_posix_priority` assert test If `z_prio` is negative and we want to make sure that it is within `[-CONFIG_NUM_COOP_PRIORITIES, -1]`, we should invert its sign and make sure that it is `<=` `CONFIG_NUM_COOP_PRIORITIES` instead of `<`. Signed-off-by: Yong Cong Sin --- lib/posix/pthread.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/posix/pthread.c b/lib/posix/pthread.c index a2e9a5b736c..ff4bdb8ef7d 100644 --- a/lib/posix/pthread.c +++ b/lib/posix/pthread.c @@ -230,7 +230,7 @@ static bool is_posix_policy_prio_valid(uint32_t priority, int policy) static uint32_t zephyr_to_posix_priority(int32_t z_prio, int *policy) { if (z_prio < 0) { - __ASSERT_NO_MSG(z_prio < CONFIG_NUM_COOP_PRIORITIES); + __ASSERT_NO_MSG(-z_prio <= CONFIG_NUM_COOP_PRIORITIES); } else { __ASSERT_NO_MSG(z_prio < CONFIG_NUM_PREEMPT_PRIORITIES); } From b2caec86013af364d8edbeb7a9fea22e10b90346 Mon Sep 17 00:00:00 2001 From: Yong Cong Sin Date: Wed, 17 Jan 2024 12:38:02 +0800 Subject: [PATCH 2452/3723] posix: pthread: fix typos - 'piority' should be 'priority' - COOP should start from `-CONFIG_NUM_COOP_PRIORITIES` Signed-off-by: Yong Cong Sin --- lib/posix/pthread.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/lib/posix/pthread.c b/lib/posix/pthread.c index ff4bdb8ef7d..f78dbb9fbfb 100644 --- a/lib/posix/pthread.c +++ b/lib/posix/pthread.c @@ -222,7 +222,7 @@ static bool is_posix_policy_prio_valid(uint32_t priority, int policy) return true; } - LOG_ERR("Invalid piority %d and / or policy %d", priority, policy); + LOG_ERR("Invalid priority %d and / or policy %d", priority, policy); return false; } @@ -242,7 +242,7 @@ static uint32_t zephyr_to_posix_priority(int32_t z_prio, int *policy) static int32_t posix_to_zephyr_priority(uint32_t priority, int policy) { if (policy == SCHED_FIFO) { - /* COOP: highest [CONFIG_NUM_COOP_PRIORITIES, -1] lowest */ + /* COOP: highest [-CONFIG_NUM_COOP_PRIORITIES, -1] lowest */ __ASSERT_NO_MSG(priority < CONFIG_NUM_COOP_PRIORITIES); } else { /* PREEMPT: lowest [0, CONFIG_NUM_PREEMPT_PRIORITIES - 1] highest */ From 5ad7f4b314d934a5ac8b7d7c76529b7e02acf667 Mon Sep 17 00:00:00 2001 From: Yong Cong Sin Date: Wed, 17 Jan 2024 12:42:23 +0800 Subject: [PATCH 2453/3723] posix: pthread: priority should be of `int` type Changed the variable type of the priority in the args and the return type of the conversion functions to `int`, as both Zephyr's priority & POSIX's `sched_priority` has type `int`. Signed-off-by: Yong Cong Sin --- lib/posix/pthread.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/lib/posix/pthread.c b/lib/posix/pthread.c index f78dbb9fbfb..fa08f5f53e7 100644 --- a/lib/posix/pthread.c +++ b/lib/posix/pthread.c @@ -227,7 +227,7 @@ static bool is_posix_policy_prio_valid(uint32_t priority, int policy) return false; } -static uint32_t zephyr_to_posix_priority(int32_t z_prio, int *policy) +static int zephyr_to_posix_priority(int z_prio, int *policy) { if (z_prio < 0) { __ASSERT_NO_MSG(-z_prio <= CONFIG_NUM_COOP_PRIORITIES); @@ -239,7 +239,7 @@ static uint32_t zephyr_to_posix_priority(int32_t z_prio, int *policy) return ZEPHYR_TO_POSIX_PRIORITY(z_prio); } -static int32_t posix_to_zephyr_priority(uint32_t priority, int policy) +static int posix_to_zephyr_priority(int priority, int policy) { if (policy == SCHED_FIFO) { /* COOP: highest [-CONFIG_NUM_COOP_PRIORITIES, -1] lowest */ @@ -701,7 +701,7 @@ int pthread_attr_init(pthread_attr_t *_attr) */ int pthread_getschedparam(pthread_t pthread, int *policy, struct sched_param *param) { - uint32_t priority; + int priority; struct posix_thread *t; t = to_posix_thread(pthread); From c3cc2e4e6dac2ebbf01c0f57a89e5385f9c76fcc Mon Sep 17 00:00:00 2001 From: Yong Cong Sin Date: Wed, 17 Jan 2024 12:45:47 +0800 Subject: [PATCH 2454/3723] posix: pthread: test the priority conversion functions Made the conversion functions non-static and added ztests for them to make sure that they work across the full range of Zephyr priorities. Signed-off-by: Yong Cong Sin --- lib/posix/pthread.c | 6 ++++-- tests/posix/common/src/pthread.c | 33 ++++++++++++++++++++++++++++++++ 2 files changed, 37 insertions(+), 2 deletions(-) diff --git a/lib/posix/pthread.c b/lib/posix/pthread.c index fa08f5f53e7..3a21d373989 100644 --- a/lib/posix/pthread.c +++ b/lib/posix/pthread.c @@ -227,7 +227,8 @@ static bool is_posix_policy_prio_valid(uint32_t priority, int policy) return false; } -static int zephyr_to_posix_priority(int z_prio, int *policy) +/* Non-static so that they can be tested in ztest */ +int zephyr_to_posix_priority(int z_prio, int *policy) { if (z_prio < 0) { __ASSERT_NO_MSG(-z_prio <= CONFIG_NUM_COOP_PRIORITIES); @@ -239,7 +240,8 @@ static int zephyr_to_posix_priority(int z_prio, int *policy) return ZEPHYR_TO_POSIX_PRIORITY(z_prio); } -static int posix_to_zephyr_priority(int priority, int policy) +/* Non-static so that they can be tested in ztest */ +int posix_to_zephyr_priority(int priority, int policy) { if (policy == SCHED_FIFO) { /* COOP: highest [-CONFIG_NUM_COOP_PRIORITIES, -1] lowest */ diff --git a/tests/posix/common/src/pthread.c b/tests/posix/common/src/pthread.c index feab8d64d59..d4038eba629 100644 --- a/tests/posix/common/src/pthread.c +++ b/tests/posix/common/src/pthread.c @@ -215,6 +215,39 @@ static void *thread_top_term(void *p1) return NULL; } +/* Test the internal priority conversion functions */ +int zephyr_to_posix_priority(int z_prio, int *policy); +int posix_to_zephyr_priority(int priority, int policy); +ZTEST(pthread, test_pthread_priority_conversion) +{ + /* + * ZEPHYR [-CONFIG_NUM_COOP_PRIORITIES, -1] + * TO + * POSIX(FIFO) [0, CONFIG_NUM_COOP_PRIORITIES - 1] + */ + for (int z_prio = -CONFIG_NUM_COOP_PRIORITIES, prio = CONFIG_NUM_COOP_PRIORITIES - 1, + p_prio, policy; + z_prio <= -1; z_prio++, prio--) { + p_prio = zephyr_to_posix_priority(z_prio, &policy); + zassert_equal(policy, SCHED_FIFO); + zassert_equal(p_prio, prio, "%d %d\n", p_prio, prio); + zassert_equal(z_prio, posix_to_zephyr_priority(p_prio, SCHED_FIFO)); + } + + /* + * ZEPHYR [0, CONFIG_NUM_PREEMPT_PRIORITIES - 1] + * TO + * POSIX(RR) [0, CONFIG_NUM_PREEMPT_PRIORITIES - 1] + */ + for (int z_prio = 0, prio = CONFIG_NUM_PREEMPT_PRIORITIES - 1, p_prio, policy; + z_prio < CONFIG_NUM_PREEMPT_PRIORITIES; z_prio++, prio--) { + p_prio = zephyr_to_posix_priority(z_prio, &policy); + zassert_equal(policy, SCHED_RR); + zassert_equal(p_prio, prio, "%d %d\n", p_prio, prio); + zassert_equal(z_prio, posix_to_zephyr_priority(p_prio, SCHED_RR)); + } +} + ZTEST(pthread, test_pthread_execution) { int i, ret; From 7c42c01f109514fdc13232b29044d4eed00ca4fa Mon Sep 17 00:00:00 2001 From: Yong Cong Sin Date: Wed, 17 Jan 2024 18:29:43 +0800 Subject: [PATCH 2455/3723] posix: pthread: use `is_posix_policy_prio_valid` to check POSIX priority Use the existing `is_posix_policy_prio_valid()` function to verify the POSIX's priority in the conversion functions. Changed the `priority` arg of `is_posix_policy_prio_valid` to `int` since that is the output of `sched_get_priority_min` & `sched_get_priority_max`. Signed-off-by: Yong Cong Sin --- lib/posix/pthread.c | 17 ++++++++--------- 1 file changed, 8 insertions(+), 9 deletions(-) diff --git a/lib/posix/pthread.c b/lib/posix/pthread.c index 3a21d373989..7b46fd7f4f9 100644 --- a/lib/posix/pthread.c +++ b/lib/posix/pthread.c @@ -215,7 +215,7 @@ void __z_pthread_cleanup_pop(int execute) } } -static bool is_posix_policy_prio_valid(uint32_t priority, int policy) +static bool is_posix_policy_prio_valid(int priority, int policy) { if (priority >= sched_get_priority_min(policy) && priority <= sched_get_priority_max(policy)) { @@ -230,6 +230,8 @@ static bool is_posix_policy_prio_valid(uint32_t priority, int policy) /* Non-static so that they can be tested in ztest */ int zephyr_to_posix_priority(int z_prio, int *policy) { + int priority; + if (z_prio < 0) { __ASSERT_NO_MSG(-z_prio <= CONFIG_NUM_COOP_PRIORITIES); } else { @@ -237,19 +239,16 @@ int zephyr_to_posix_priority(int z_prio, int *policy) } *policy = (z_prio < 0) ? SCHED_FIFO : SCHED_RR; - return ZEPHYR_TO_POSIX_PRIORITY(z_prio); + priority = ZEPHYR_TO_POSIX_PRIORITY(z_prio); + __ASSERT_NO_MSG(is_posix_policy_prio_valid(priority, *policy)); + + return priority; } /* Non-static so that they can be tested in ztest */ int posix_to_zephyr_priority(int priority, int policy) { - if (policy == SCHED_FIFO) { - /* COOP: highest [-CONFIG_NUM_COOP_PRIORITIES, -1] lowest */ - __ASSERT_NO_MSG(priority < CONFIG_NUM_COOP_PRIORITIES); - } else { - /* PREEMPT: lowest [0, CONFIG_NUM_PREEMPT_PRIORITIES - 1] highest */ - __ASSERT_NO_MSG(priority < CONFIG_NUM_PREEMPT_PRIORITIES); - } + __ASSERT_NO_MSG(is_posix_policy_prio_valid(priority, policy)); return POSIX_TO_ZEPHYR_PRIORITY(priority, policy); } From 715dc68b227537c6a249989c1df4c8d3ead9b409 Mon Sep 17 00:00:00 2001 From: Ian Wakely Date: Sun, 14 Jan 2024 21:54:01 -0500 Subject: [PATCH 2456/3723] boards: Enabling neopixel on Adafruit Qt Py RP2040 Using the recently added WS2812 PIO driver, this enables the LED on the QT PY to work with the built in RGB LED examples. Signed-off-by: Ian Wakely --- .../adafruit_qt_py_rp2040-pinctrl.dtsi | 6 +++ .../adafruit_qt_py_rp2040.dts | 40 +++++++++++++++++++ .../boards/adafruit_qt_py_rp2040.conf | 3 ++ 3 files changed, 49 insertions(+) create mode 100644 samples/drivers/led_ws2812/boards/adafruit_qt_py_rp2040.conf diff --git a/boards/arm/adafruit_qt_py_rp2040/adafruit_qt_py_rp2040-pinctrl.dtsi b/boards/arm/adafruit_qt_py_rp2040/adafruit_qt_py_rp2040-pinctrl.dtsi index 2048e0580e0..d2e84ae41f8 100644 --- a/boards/arm/adafruit_qt_py_rp2040/adafruit_qt_py_rp2040-pinctrl.dtsi +++ b/boards/arm/adafruit_qt_py_rp2040/adafruit_qt_py_rp2040-pinctrl.dtsi @@ -61,4 +61,10 @@ clocks_default: clocks_default { }; + + ws2812_pio1_default: ws2812_pio1_default { + ws2812 { + pinmux = ; + }; + }; }; diff --git a/boards/arm/adafruit_qt_py_rp2040/adafruit_qt_py_rp2040.dts b/boards/arm/adafruit_qt_py_rp2040/adafruit_qt_py_rp2040.dts index b42c48ab4d9..7e8448aec0a 100644 --- a/boards/arm/adafruit_qt_py_rp2040/adafruit_qt_py_rp2040.dts +++ b/boards/arm/adafruit_qt_py_rp2040/adafruit_qt_py_rp2040.dts @@ -11,6 +11,7 @@ #include "adafruit_qt_py_rp2040-pinctrl.dtsi" #include "seeed_xiao_connector.dtsi" #include +#include / { chosen { @@ -24,6 +25,7 @@ aliases { watchdog0 = &wdt0; + led-strip = &ws2812; }; }; @@ -68,6 +70,17 @@ &gpio0 { status = "okay"; + + /* + * Unlike some of the other Adafruit boards, the neopixel on this board has + * its positive side hooked up to a GPIO pin rather than a positive voltage + * rail to save on power. This will enable the LED on board initialization. + */ + neopixel-power-enable { + gpio-hog; + gpios = <11 GPIO_ACTIVE_HIGH>; + output-high; + }; }; &i2c0 { @@ -109,6 +122,33 @@ status = "okay"; }; +&pio1 { + status = "okay"; + + /* + * Need to put this on PIO1 as having this on PIO0 causes the GPIO hog to + * not work. + */ + pio-ws2812 { + compatible = "worldsemi,ws2812-rpi_pico-pio"; + status = "okay"; + pinctrl-0 = <&ws2812_pio1_default>; + pinctrl-names = "default"; + bit-waveform = <3>, <3>, <4>; + + ws2812: ws2812 { + status = "okay"; + output-pin = <12>; + chain-length = <1>; + color-mapping = ; + reset-delay = <280>; + frequency = <800000>; + }; + }; +}; + zephyr_udc0: &usbd { status = "okay"; }; diff --git a/samples/drivers/led_ws2812/boards/adafruit_qt_py_rp2040.conf b/samples/drivers/led_ws2812/boards/adafruit_qt_py_rp2040.conf new file mode 100644 index 00000000000..6805516207c --- /dev/null +++ b/samples/drivers/led_ws2812/boards/adafruit_qt_py_rp2040.conf @@ -0,0 +1,3 @@ +CONFIG_WS2812_STRIP_RPI_PICO_PIO=y +CONFIG_GPIO=y +CONFIG_GPIO_HOGS=y From f0b4e4c88dde9156587f3c06c7795197f32c073f Mon Sep 17 00:00:00 2001 From: Vit Stanicek Date: Mon, 20 Nov 2023 15:31:01 +0100 Subject: [PATCH 2457/3723] drivers: gpio_mcux_lpc: Fix xt-clang error Remove gpio_clock_names and gpio_mcux_lpc_config->clock_ip_name from drivers/gpio/gpio_mcux_lpc.c. The drivers/gpio/gpio_mcux_lpc.c file did not compile with xt-clang RI-2021.8-win32, as the gpio_clock_names was initialised with a reference to a static const array. The clock_ip_name member was initialised from this variable, but it isn't used anywhere else. Signed-off-by: Vit Stanicek --- drivers/gpio/gpio_mcux_lpc.c | 7 ++----- 1 file changed, 2 insertions(+), 5 deletions(-) diff --git a/drivers/gpio/gpio_mcux_lpc.c b/drivers/gpio/gpio_mcux_lpc.c index 297e83930f2..673ad496a14 100644 --- a/drivers/gpio/gpio_mcux_lpc.c +++ b/drivers/gpio/gpio_mcux_lpc.c @@ -44,7 +44,6 @@ struct gpio_mcux_lpc_config { IOCON_Type *pinmux_base; #endif uint32_t port_no; - clock_ip_name_t clock_ip_name; }; struct gpio_mcux_lpc_data { @@ -381,7 +380,6 @@ static int gpio_mcux_lpc_manage_cb(const struct device *port, static int gpio_mcux_lpc_init(const struct device *dev) { const struct gpio_mcux_lpc_config *config = dev->config; - GPIO_PortInit(config->gpio_base, config->port_no); return 0; @@ -398,7 +396,7 @@ static const struct gpio_driver_api gpio_mcux_lpc_driver_api = { .manage_callback = gpio_mcux_lpc_manage_cb, }; -static const clock_ip_name_t gpio_clock_names[] = GPIO_CLOCKS; + #ifdef IOPCTL #define PINMUX_BASE IOPCTL @@ -429,8 +427,7 @@ static const clock_ip_name_t gpio_clock_names[] = GPIO_CLOCKS; .gpio_base = GPIO, \ .pinmux_base = PINMUX_BASE, \ .int_source = DT_INST_ENUM_IDX(n, int_source), \ - .port_no = DT_INST_PROP(n, port), \ - .clock_ip_name = gpio_clock_names[DT_INST_PROP(n, port)], \ + .port_no = DT_INST_PROP(n, port) \ }; \ \ static struct gpio_mcux_lpc_data gpio_mcux_lpc_data_##n; \ From 1bc8490c6ccb67391ddd28c8fd3a569b859bd7e5 Mon Sep 17 00:00:00 2001 From: Bjarki Arge Andreasen Date: Tue, 16 Jan 2024 14:37:01 +0100 Subject: [PATCH 2458/3723] drivers: gnss: match: Change RMC/GGA sync from timeout to UTC Change the synchronization of RMC and GGA NMEA messages from a timeout to matching their UTC timestamps. Signed-off-by: Bjarki Arge Andreasen --- drivers/gnss/gnss_nmea0183_match.c | 58 ++++++++++++------------ drivers/gnss/gnss_nmea0183_match.h | 10 ++-- drivers/gnss/gnss_nmea_generic.c | 4 -- drivers/gnss/gnss_quectel_lcx6g.c | 1 - dts/bindings/gnss/gnss-nmea-generic.yaml | 10 ---- 5 files changed, 31 insertions(+), 52 deletions(-) diff --git a/drivers/gnss/gnss_nmea0183_match.c b/drivers/gnss/gnss_nmea0183_match.c index 2b971937c8d..cd82c552ee4 100644 --- a/drivers/gnss/gnss_nmea0183_match.c +++ b/drivers/gnss/gnss_nmea0183_match.c @@ -10,16 +10,22 @@ #include +#include "gnss_parse.h" #include "gnss_nmea0183.h" #include "gnss_nmea0183_match.h" -static bool gnss_nmea0183_match_timed_out(struct gnss_nmea0183_match_data *data) +static int gnss_nmea0183_match_parse_utc(char **argv, uint16_t argc, uint32_t *utc) { - int64_t delta; + int64_t i64; - delta = k_uptime_delta(&data->timestamp); - data->timestamp = k_uptime_get(); - return ((uint16_t)delta) > data->timeout_ms; + if ((gnss_parse_dec_to_milli(argv[1], &i64) < 0) || + (i64 < 0) || + (i64 > UINT32_MAX)) { + return -EINVAL; + } + + *utc = (uint32_t)i64; + return 0; } #if CONFIG_GNSS_SATELLITES @@ -30,10 +36,15 @@ static void gnss_nmea0183_match_reset_gsv(struct gnss_nmea0183_match_data *data) } #endif -static void gnss_nmea0183_match_reset(struct gnss_nmea0183_match_data *data) +static void gnss_nmea0183_match_publish(struct gnss_nmea0183_match_data *data) { - data->gga_received = false; - data->rmc_received = false; + if ((data->gga_utc == 0) || (data->rmc_utc == 0)) { + return; + } + + if (data->gga_utc == data->rmc_utc) { + gnss_publish_data(data->gnss, &data->data); + } } void gnss_nmea0183_match_gga_callback(struct modem_chat *chat, char **argv, uint16_t argc, @@ -41,19 +52,15 @@ void gnss_nmea0183_match_gga_callback(struct modem_chat *chat, char **argv, uint { struct gnss_nmea0183_match_data *data = user_data; - if (gnss_nmea0183_match_timed_out(data)) { - gnss_nmea0183_match_reset(data); - } - if (gnss_nmea0183_parse_gga((const char **)argv, argc, &data->data) < 0) { return; } - data->gga_received = true; - - if (data->gga_received && data->rmc_received) { - gnss_publish_data(data->gnss, &data->data); + if (gnss_nmea0183_match_parse_utc(argv, argc, &data->gga_utc) < 0) { + return; } + + gnss_nmea0183_match_publish(data); } void gnss_nmea0183_match_rmc_callback(struct modem_chat *chat, char **argv, uint16_t argc, @@ -61,19 +68,15 @@ void gnss_nmea0183_match_rmc_callback(struct modem_chat *chat, char **argv, uint { struct gnss_nmea0183_match_data *data = user_data; - if (gnss_nmea0183_match_timed_out(data)) { - gnss_nmea0183_match_reset(data); - } - if (gnss_nmea0183_parse_rmc((const char **)argv, argc, &data->data) < 0) { return; } - data->rmc_received = true; - - if (data->gga_received && data->rmc_received) { - gnss_publish_data(data->gnss, &data->data); + if (gnss_nmea0183_match_parse_utc(argv, argc, &data->rmc_utc) < 0) { + return; } + + gnss_nmea0183_match_publish(data); } #if CONFIG_GNSS_SATELLITES @@ -84,10 +87,6 @@ void gnss_nmea0183_match_gsv_callback(struct modem_chat *chat, char **argv, uint struct gnss_nmea0183_gsv_header header; int ret; - if (gnss_nmea0183_match_timed_out(data)) { - gnss_nmea0183_match_reset(data); - } - if (gnss_nmea0183_parse_gsv_header((const char **)argv, argc, &header) < 0) { return; } @@ -124,7 +123,7 @@ int gnss_nmea0183_match_init(struct gnss_nmea0183_match_data *data, const struct gnss_nmea0183_match_config *config) { __ASSERT(data != NULL, "data argument must be provided"); - __ASSERT(config != NULL, "data argument must be provided"); + __ASSERT(config != NULL, "config argument must be provided"); memset(data, 0, sizeof(struct gnss_nmea0183_match_data)); data->gnss = config->gnss; @@ -132,6 +131,5 @@ int gnss_nmea0183_match_init(struct gnss_nmea0183_match_data *data, data->satellites = config->satellites; data->satellites_size = config->satellites_size; #endif - data->timeout_ms = config->timeout_ms; return 0; } diff --git a/drivers/gnss/gnss_nmea0183_match.h b/drivers/gnss/gnss_nmea0183_match.h index 65104e1dc8a..28ed395320b 100644 --- a/drivers/gnss/gnss_nmea0183_match.h +++ b/drivers/gnss/gnss_nmea0183_match.h @@ -49,11 +49,9 @@ struct gnss_nmea0183_match_data { uint16_t satellites_size; uint16_t satellites_length; #endif - int64_t timestamp; - uint16_t timeout_ms; - uint8_t gga_received : 1; - uint8_t rmc_received : 1; - uint8_t gsv_message_number : 6; + uint32_t gga_utc; + uint32_t rmc_utc; + uint8_t gsv_message_number; }; /** GNSS NMEA0183 match configuration structure */ @@ -66,8 +64,6 @@ struct gnss_nmea0183_match_config { /** Number of elements in buffer for parsed satellites */ uint16_t satellites_size; #endif - /** The maximum time from the first to the last NMEA0183 message of a fix */ - uint16_t timeout_ms; }; /** diff --git a/drivers/gnss/gnss_nmea_generic.c b/drivers/gnss/gnss_nmea_generic.c index 0e7611ba495..6d9adfb6990 100644 --- a/drivers/gnss/gnss_nmea_generic.c +++ b/drivers/gnss/gnss_nmea_generic.c @@ -29,7 +29,6 @@ LOG_MODULE_REGISTER(gnss_nmea_generic, CONFIG_GNSS_LOG_LEVEL); struct gnss_nmea_generic_config { const struct device *uart; - uint16_t nmea_timeout_ms; }; struct gnss_nmea_generic_data { @@ -83,7 +82,6 @@ static struct gnss_driver_api gnss_api = { static int gnss_nmea_generic_init_nmea0183_match(const struct device *dev) { - const struct gnss_nmea_generic_config *cfg = dev->config; struct gnss_nmea_generic_data *data = dev->data; const struct gnss_nmea0183_match_config match_config = { @@ -92,7 +90,6 @@ static int gnss_nmea_generic_init_nmea0183_match(const struct device *dev) .satellites = data->satellites, .satellites_size = ARRAY_SIZE(data->satellites), #endif - .timeout_ms = cfg->nmea_timeout_ms, }; return gnss_nmea0183_match_init(&data->match_data, &match_config); @@ -163,7 +160,6 @@ static int gnss_nmea_generic_init(const struct device *dev) #define GNSS_NMEA_GENERIC(inst) \ static struct gnss_nmea_generic_config gnss_nmea_generic_cfg_##inst = { \ .uart = DEVICE_DT_GET(DT_INST_BUS(inst)), \ - .nmea_timeout_ms = DT_INST_PROP(inst, nmea_timeout_ms), \ }; \ \ static struct gnss_nmea_generic_data gnss_nmea_generic_data_##inst; \ diff --git a/drivers/gnss/gnss_quectel_lcx6g.c b/drivers/gnss/gnss_quectel_lcx6g.c index 9565d46cdfb..f7b29b4640d 100644 --- a/drivers/gnss/gnss_quectel_lcx6g.c +++ b/drivers/gnss/gnss_quectel_lcx6g.c @@ -649,7 +649,6 @@ static int quectel_lcx6g_init_nmea0183_match(const struct device *dev) .satellites = data->satellites, .satellites_size = ARRAY_SIZE(data->satellites), #endif - .timeout_ms = 50, }; return gnss_nmea0183_match_init(&data->match_data, &config); diff --git a/dts/bindings/gnss/gnss-nmea-generic.yaml b/dts/bindings/gnss/gnss-nmea-generic.yaml index 4be7bde1186..a3887995e10 100644 --- a/dts/bindings/gnss/gnss-nmea-generic.yaml +++ b/dts/bindings/gnss/gnss-nmea-generic.yaml @@ -20,13 +20,3 @@ compatible: "gnss-nmea-generic" include: - uart-device.yaml - -properties: - nmea-timeout-ms: - type: int - default: 500 - description: | - Synchronization timeout for NMEA sentences. The NMEA parser is expecting - to receive a GGA and RMC sentences within this time frame to publish a - location data. Set accordingly to the UART datarate and location - reporting frequency. Defaults to 500ms if unspecified. From 7a41a9d864cdd00bda521d09662ecf4fcfa6f2a5 Mon Sep 17 00:00:00 2001 From: Pavel Vasilyev Date: Tue, 16 Jan 2024 14:44:53 +0100 Subject: [PATCH 2459/3723] Bluetooth: Mesh: Fix processing SegAcks to wrong destination Do not process SegAcks which were not targeted to the node. They were rejected in the next if statement always, but generated the annyoing warning "No matching TX context for ack". Signed-off-by: Pavel Vasilyev --- subsys/bluetooth/mesh/transport.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/subsys/bluetooth/mesh/transport.c b/subsys/bluetooth/mesh/transport.c index 47e8492a901..a0364dceb25 100644 --- a/subsys/bluetooth/mesh/transport.c +++ b/subsys/bluetooth/mesh/transport.c @@ -869,6 +869,8 @@ static int trans_ack(struct bt_mesh_net_rx *rx, uint8_t hdr, /* Best effort - we don't have enough info for true SeqAuth */ *seq_auth = SEQ_AUTH(BT_MESH_NET_IVI_RX(rx), seq_zero); return 0; + } else if (!rx->local_match) { + return 0; } ack = net_buf_simple_pull_be32(buf); @@ -969,7 +971,7 @@ static int ctl_recv(struct bt_mesh_net_rx *rx, uint8_t hdr, return bt_mesh_hb_recv(rx, buf); } - /* Only acks and heartbeats may need processing without local_match */ + /* Only acks for friendship and heartbeats may need processing without local_match */ if (!rx->local_match) { return 0; } From 8ecda0418db87e5a994548aabd319b88eb763558 Mon Sep 17 00:00:00 2001 From: Dominik Ermel Date: Fri, 1 Sep 2023 18:10:45 +0000 Subject: [PATCH 2460/3723] tests/flash: Fix test assuming erase value to be 0xff Test assumed non-writen flash to contain 0xff while it is supposed to check for erase_value. The "random" buffer has also been updated to skip values that are equal to erase value. Signed-off-by: Dominik Ermel --- tests/drivers/flash/common/src/main.c | 26 ++++++++++++++++---------- 1 file changed, 16 insertions(+), 10 deletions(-) diff --git a/tests/drivers/flash/common/src/main.c b/tests/drivers/flash/common/src/main.c index 79d75ca9b13..91b478109d7 100644 --- a/tests/drivers/flash/common/src/main.c +++ b/tests/drivers/flash/common/src/main.c @@ -43,11 +43,12 @@ #endif #define EXPECTED_SIZE 512 -#define CANARY 0xff static const struct device *const flash_dev = TEST_AREA_DEVICE; static struct flash_pages_info page_info; static uint8_t __aligned(4) expected[EXPECTED_SIZE]; +static const struct flash_parameters *flash_params; +static uint8_t erase_value; static void *flash_driver_setup(void) { @@ -55,8 +56,8 @@ static void *flash_driver_setup(void) zassert_true(device_is_ready(flash_dev)); - const struct flash_parameters *flash_params = - flash_get_parameters(flash_dev); + flash_params = flash_get_parameters(flash_dev); + erase_value = flash_params->erase_value; /* For tests purposes use page (in nrf_qspi_nor page = 64 kB) */ flash_get_page_info_by_offs(flash_dev, TEST_AREA_OFFSET, @@ -70,8 +71,12 @@ static void *flash_driver_setup(void) zassert_equal(rc, 0, "Cannot read flash"); /* Fill test buffer with random data */ - for (int i = 0; i < EXPECTED_SIZE; i++) { - expected[i] = i; + for (int i = 0, val = 0; i < EXPECTED_SIZE; i++, val++) { + /* Skip erase value */ + if (val == erase_value) { + val++; + } + expected[i] = val; } /* Check if tested region fits in flash */ @@ -82,7 +87,7 @@ static void *flash_driver_setup(void) bool is_buf_clear = true; for (off_t i = 0; i < EXPECTED_SIZE; i++) { - if (buf[i] != flash_params->erase_value) { + if (buf[i] != erase_value) { is_buf_clear = false; break; } @@ -105,6 +110,7 @@ ZTEST(flash_driver, test_read_unaligned_address) { int rc; uint8_t buf[EXPECTED_SIZE]; + const uint8_t canary = erase_value; rc = flash_write(flash_dev, page_info.start_offset, @@ -118,8 +124,8 @@ ZTEST(flash_driver, test_read_unaligned_address) /* buffer offset; leave space for buffer guard */ for (off_t buf_o = 1; buf_o < 5; buf_o++) { /* buffer overflow protection */ - buf[buf_o - 1] = CANARY; - buf[buf_o + len] = CANARY; + buf[buf_o - 1] = canary; + buf[buf_o + len] = canary; memset(buf + buf_o, 0, len); rc = flash_read(flash_dev, page_info.start_offset + ad_o, @@ -131,10 +137,10 @@ ZTEST(flash_driver, test_read_unaligned_address) 0, "Flash read failed at len=%d, " "ad_o=%d, buf_o=%d", len, ad_o, buf_o); /* check buffer guards */ - zassert_equal(buf[buf_o - 1], CANARY, + zassert_equal(buf[buf_o - 1], canary, "Buffer underflow at len=%d, " "ad_o=%d, buf_o=%d", len, ad_o, buf_o); - zassert_equal(buf[buf_o + len], CANARY, + zassert_equal(buf[buf_o + len], canary, "Buffer overflow at len=%d, " "ad_o=%d, buf_o=%d", len, ad_o, buf_o); } From 2a8b25660a2d92636bd5ce3c49611b0d8f2ba8f5 Mon Sep 17 00:00:00 2001 From: Yves Vandervennet Date: Tue, 16 Jan 2024 09:21:24 -0600 Subject: [PATCH 2461/3723] boards: mimxrt1020_evk: enable linkserver support - adds the definitions in the board.cmake file - updates documentation Signed-off-by: Yves Vandervennet --- boards/arm/mimxrt1020_evk/board.cmake | 2 ++ boards/arm/mimxrt1020_evk/doc/index.rst | 23 +++++++++++++++++++---- 2 files changed, 21 insertions(+), 4 deletions(-) diff --git a/boards/arm/mimxrt1020_evk/board.cmake b/boards/arm/mimxrt1020_evk/board.cmake index f3c9ac623ed..cfab4278fb4 100644 --- a/boards/arm/mimxrt1020_evk/board.cmake +++ b/boards/arm/mimxrt1020_evk/board.cmake @@ -6,6 +6,8 @@ board_runner_args(pyocd "--target=mimxrt1020") board_runner_args(jlink "--device=MIMXRT1021xxx5A") +board_runner_args(linkserver "--device=MIMXRT1021xxxxx:EVK-MIMXRT1020") +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/arm/mimxrt1020_evk/doc/index.rst b/boards/arm/mimxrt1020_evk/doc/index.rst index 40f45565a6e..751ec16687b 100644 --- a/boards/arm/mimxrt1020_evk/doc/index.rst +++ b/boards/arm/mimxrt1020_evk/doc/index.rst @@ -231,8 +231,23 @@ however the :ref:`pyocd-debug-host-tools` do not yet support programming the external flashes on this board so you must reconfigure the board for one of the following debug probes instead. -Option 1: :ref:`opensda-jlink-onboard-debug-probe` (Recommended) ----------------------------------------------------------------- +Using LinkServer +---------------- + +Install the :ref:`linkserver-debug-host-tools` and make sure they are in your +search path. LinkServer works with the default CMSIS-DAP firmware included in +the on-board debugger. + +Linkserver is the default runner. You may also se the ``-r linkserver`` option +with West to use the LinkServer runner. + +.. code-block:: console + + west flash + west debug + +JLink (on-board): :ref:`opensda-jlink-onboard-debug-probe` +---------------------------------------------------------- Install the :ref:`jlink-debug-host-tools` and make sure they are in your search path. @@ -242,8 +257,8 @@ the `OpenSDA J-Link MIMXRT1020-EVK Firmware`_. Check that jumpers J27 and J28 are **on** (they are on by default when boards ship from the factory) to ensure SWD signals are connected to the OpenSDA microcontroller. -Option 2: :ref:`jlink-external-debug-probe` -------------------------------------------- +External JLink: :ref:`jlink-external-debug-probe` +------------------------------------------------- Install the :ref:`jlink-debug-host-tools` and make sure they are in your search path. From 4a1847eb2285a79cb612766b5fb9d2e0ecc80522 Mon Sep 17 00:00:00 2001 From: Chaitanya Tata Date: Tue, 16 Jan 2024 23:25:21 +0530 Subject: [PATCH 2462/3723] wifi: shell: Make channel mandatory for AP For starting an AP mode, channel is mandatory, so, fix the arguments and the help text. Signed-off-by: Chaitanya Tata --- subsys/net/l2/wifi/wifi_shell.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/subsys/net/l2/wifi/wifi_shell.c b/subsys/net/l2/wifi/wifi_shell.c index 8c18cf9488c..8d03fac83e2 100644 --- a/subsys/net/l2/wifi/wifi_shell.c +++ b/subsys/net/l2/wifi/wifi_shell.c @@ -463,7 +463,7 @@ static int __wifi_args_to_params(size_t argc, char *argv[], return -EINVAL; } - /* Channel (optional) */ + /* Channel (optional: STA, mandatory: AP) */ if ((idx < argc) && (strlen(argv[idx]) <= 3)) { params->channel = strtol(argv[idx], &endptr, 10); if (*endptr != '\0') { @@ -1782,14 +1782,14 @@ SHELL_STATIC_SUBCMD_SET_CREATE(wifi_cmd_ap, 1, 0), SHELL_CMD_ARG(enable, NULL, "\"\"\n" - "[channel number: 0 means all]\n" + "\n" "[PSK: valid only for secure SSIDs]\n" "[Security type: valid only for secure SSIDs]\n" "0:None, 1:WPA2-PSK, 2:WPA2-PSK-256, 3:SAE, 4:WAPI, 5:EAP, 6:WEP, 7: WPA-PSK\n" "[MFP (optional: needs security type to be specified)]\n" ": 0:Disable, 1:Optional, 2:Required.\n", cmd_wifi_ap_enable, - 2, 4), + 3, 3), SHELL_CMD_ARG(stations, NULL, "List stations connected to the AP", cmd_wifi_ap_stations, From c6f21523484e768d9964989f69111ba698464d06 Mon Sep 17 00:00:00 2001 From: Chaitanya Tata Date: Tue, 16 Jan 2024 23:38:47 +0530 Subject: [PATCH 2463/3723] wifi: shell: Add a sanity check for MFP For none and WPA-PSK MFP isn't applicable, it was only introduced in WPA2-PSK (RSN) and later. Signed-off-by: Chaitanya Tata --- subsys/net/l2/wifi/wifi_shell.c | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/subsys/net/l2/wifi/wifi_shell.c b/subsys/net/l2/wifi/wifi_shell.c index 8d03fac83e2..7be5830a678 100644 --- a/subsys/net/l2/wifi/wifi_shell.c +++ b/subsys/net/l2/wifi/wifi_shell.c @@ -499,6 +499,11 @@ static int __wifi_args_to_params(size_t argc, char *argv[], if (idx < argc) { unsigned int mfp = strtol(argv[idx], &endptr, 10); + if (security == WIFI_SECURITY_TYPE_NONE || + security == WIFI_SECURITY_TYPE_WPA_PSK) { + return -EINVAL; + } + if (mfp <= WIFI_MFP_REQUIRED) { params->mfp = mfp; } From 2f99379dd505e4d87c0d1884ae6e9417667b89e4 Mon Sep 17 00:00:00 2001 From: Chaitanya Tata Date: Tue, 16 Jan 2024 23:30:13 +0530 Subject: [PATCH 2464/3723] wifi: utils: Move channel helpers to public API These can be used for channel validation outside the utils. Signed-off-by: Chaitanya Tata --- include/zephyr/net/wifi_utils.h | 43 +++++++++++++++++++++++++++++++++ subsys/net/l2/wifi/wifi_utils.c | 8 +++--- 2 files changed, 47 insertions(+), 4 deletions(-) diff --git a/include/zephyr/net/wifi_utils.h b/include/zephyr/net/wifi_utils.h index c16eef0e5b2..537db787648 100644 --- a/include/zephyr/net/wifi_utils.h +++ b/include/zephyr/net/wifi_utils.h @@ -103,6 +103,49 @@ int wifi_utils_parse_scan_chan(char *scan_chan_str, struct wifi_band_channel *chan, uint8_t max_channels); + +/** + * @brief Validate a channel against a band. + * + * @param band Band to validate the channel against. + * @param chan Channel to validate. + * + * @retval true if the channel is valid for the band. + * @retval false if the channel is not valid for the band. + */ +bool wifi_utils_validate_chan(uint8_t band, + uint16_t chan); + +/** + * @brief Validate a channel against the 2.4 GHz band. + * + * @param chan Channel to validate. + * + * @retval true if the channel is valid for the band. + * @retval false if the channel is not valid for the band. + */ +bool wifi_utils_validate_chan_2g(uint16_t chan); + +/** + * @brief Validate a channel against the 5 GHz band. + * + * @param chan Channel to validate. + * + * @retval true if the channel is valid for the band. + * @retval false if the channel is not valid for the band. + */ +bool wifi_utils_validate_chan_5g(uint16_t chan); + +/** + * @brief Validate a channel against the 6 GHz band. + * + * @param chan Channel to validate. + * + * @retval true if the channel is valid for the band. + * @retval false if the channel is not valid for the band. + */ +bool wifi_utils_validate_chan_6g(uint16_t chan); + /** * @} */ diff --git a/subsys/net/l2/wifi/wifi_utils.c b/subsys/net/l2/wifi/wifi_utils.c index 177e0d8ee02..01c4bf1ea81 100644 --- a/subsys/net/l2/wifi/wifi_utils.c +++ b/subsys/net/l2/wifi/wifi_utils.c @@ -44,7 +44,7 @@ static enum wifi_frequency_bands wifi_utils_map_band_str_to_idx(char *band_str) } -static bool wifi_utils_validate_chan_2g(uint16_t chan) +bool wifi_utils_validate_chan_2g(uint16_t chan) { if ((chan >= 1) && (chan <= 14)) { return true; @@ -54,7 +54,7 @@ static bool wifi_utils_validate_chan_2g(uint16_t chan) } -static bool wifi_utils_validate_chan_5g(uint16_t chan) +bool wifi_utils_validate_chan_5g(uint16_t chan) { uint16_t i; @@ -68,7 +68,7 @@ static bool wifi_utils_validate_chan_5g(uint16_t chan) } -static bool wifi_utils_validate_chan_6g(uint16_t chan) +bool wifi_utils_validate_chan_6g(uint16_t chan) { if (((chan >= 1) && (chan <= 233) && (!((chan - 1)%4))) || (chan == 2)) { @@ -79,7 +79,7 @@ static bool wifi_utils_validate_chan_6g(uint16_t chan) } -static bool wifi_utils_validate_chan(uint8_t band, +bool wifi_utils_validate_chan(uint8_t band, uint16_t chan) { bool result = false; From 2f88df9cef4274392a08009a79616a5715e0bf9a Mon Sep 17 00:00:00 2001 From: Chaitanya Tata Date: Tue, 16 Jan 2024 23:44:23 +0530 Subject: [PATCH 2465/3723] wifi: shell: Add channel validation Validate the channel for both STA and AP modes. Signed-off-by: Chaitanya Tata --- subsys/net/l2/wifi/wifi_shell.c | 27 +++++++++++++++++++++++---- 1 file changed, 23 insertions(+), 4 deletions(-) diff --git a/subsys/net/l2/wifi/wifi_shell.c b/subsys/net/l2/wifi/wifi_shell.c index 7be5830a678..ae9c6bf5f4b 100644 --- a/subsys/net/l2/wifi/wifi_shell.c +++ b/subsys/net/l2/wifi/wifi_shell.c @@ -442,7 +442,8 @@ static void wifi_mgmt_event_handler(struct net_mgmt_event_callback *cb, } static int __wifi_args_to_params(size_t argc, char *argv[], - struct wifi_connect_req_params *params) + struct wifi_connect_req_params *params, + enum wifi_iface_mode iface_mode) { char *endptr; int idx = 1; @@ -470,8 +471,26 @@ static int __wifi_args_to_params(size_t argc, char *argv[], return -EINVAL; } - if (params->channel == 0U) { + if (iface_mode == WIFI_MODE_INFRA && params->channel == 0) { params->channel = WIFI_CHANNEL_ANY; + } else { + const uint8_t bands[] = {WIFI_FREQ_BAND_2_4_GHZ, + WIFI_FREQ_BAND_5_GHZ, + WIFI_FREQ_BAND_6_GHZ}; + uint8_t band; + bool found = false; + + for (band = 0; band < ARRAY_SIZE(bands); band++) { + if (wifi_utils_validate_chan(bands[band], + params->channel)) { + found = true; + break; + } + } + + if (!found) { + return -EINVAL; + } } idx++; @@ -530,7 +549,7 @@ static int cmd_wifi_connect(const struct shell *sh, size_t argc, struct net_if *iface = net_if_get_first_wifi(); struct wifi_connect_req_params cnx_params = { 0 }; - if (__wifi_args_to_params(argc - 1, &argv[1], &cnx_params)) { + if (__wifi_args_to_params(argc - 1, &argv[1], &cnx_params, WIFI_MODE_INFRA)) { shell_help(sh); return -ENOEXEC; } @@ -1223,7 +1242,7 @@ static int cmd_wifi_ap_enable(const struct shell *sh, size_t argc, static struct wifi_connect_req_params cnx_params; int ret; - if (__wifi_args_to_params(argc - 1, &argv[1], &cnx_params)) { + if (__wifi_args_to_params(argc - 1, &argv[1], &cnx_params, WIFI_MODE_AP)) { shell_help(sh); return -ENOEXEC; } From c9363a9c71fe9b88e8e244fe24b3d13c9bbc95c6 Mon Sep 17 00:00:00 2001 From: Chaitanya Tata Date: Tue, 16 Jan 2024 23:54:36 +0530 Subject: [PATCH 2466/3723] wifi: shell: Fix the channel extraction The channel extraction from string directly uses the end variable with limited data type, this causes issue if an invalid channel that exceeds the data is given as an input e.g., 300, which would end up as a valid channel 44. Use an intermediate variable with type that can hold all possible combinations (valid and invalid) and only after validation assign that to the end type. Signed-off-by: Chaitanya Tata --- subsys/net/l2/wifi/wifi_shell.c | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/subsys/net/l2/wifi/wifi_shell.c b/subsys/net/l2/wifi/wifi_shell.c index ae9c6bf5f4b..4098fdc9d39 100644 --- a/subsys/net/l2/wifi/wifi_shell.c +++ b/subsys/net/l2/wifi/wifi_shell.c @@ -466,12 +466,13 @@ static int __wifi_args_to_params(size_t argc, char *argv[], /* Channel (optional: STA, mandatory: AP) */ if ((idx < argc) && (strlen(argv[idx]) <= 3)) { - params->channel = strtol(argv[idx], &endptr, 10); + long channel = strtol(argv[idx], &endptr, 10); + if (*endptr != '\0') { return -EINVAL; } - if (iface_mode == WIFI_MODE_INFRA && params->channel == 0) { + if (iface_mode == WIFI_MODE_INFRA && channel == 0) { params->channel = WIFI_CHANNEL_ANY; } else { const uint8_t bands[] = {WIFI_FREQ_BAND_2_4_GHZ, @@ -482,7 +483,7 @@ static int __wifi_args_to_params(size_t argc, char *argv[], for (band = 0; band < ARRAY_SIZE(bands); band++) { if (wifi_utils_validate_chan(bands[band], - params->channel)) { + channel)) { found = true; break; } @@ -491,8 +492,9 @@ static int __wifi_args_to_params(size_t argc, char *argv[], if (!found) { return -EINVAL; } - } + params->channel = channel; + } idx++; } From df6d4e77171dfb7415fe0a3f7d7834ca83f0d3c1 Mon Sep 17 00:00:00 2001 From: Chaitanya Tata Date: Wed, 17 Jan 2024 00:15:15 +0530 Subject: [PATCH 2467/3723] wifi: shell: Log errors for validation Handy in giving feedback to the user rather than silent failure. Signed-off-by: Chaitanya Tata --- subsys/net/l2/wifi/wifi_shell.c | 43 ++++++++++++++++++++++++++++++--- 1 file changed, 40 insertions(+), 3 deletions(-) diff --git a/subsys/net/l2/wifi/wifi_shell.c b/subsys/net/l2/wifi/wifi_shell.c index 4098fdc9d39..ad0eb9d98a2 100644 --- a/subsys/net/l2/wifi/wifi_shell.c +++ b/subsys/net/l2/wifi/wifi_shell.c @@ -48,6 +48,8 @@ LOG_MODULE_REGISTER(net_wifi_shell, LOG_LEVEL_INF); NET_EVENT_WIFI_SCAN_RESULT) #endif /* CONFIG_WIFI_MGMT_RAW_SCAN_RESULTS_ONLY */ +#define MAX_BANDS_STR_LEN 64 + static struct { const struct shell *sh; @@ -449,6 +451,8 @@ static int __wifi_args_to_params(size_t argc, char *argv[], int idx = 1; if (argc < 1) { + print(context.sh, SHELL_WARNING, + "SSID not specified\n"); return -EINVAL; } @@ -461,6 +465,9 @@ static int __wifi_args_to_params(size_t argc, char *argv[], params->ssid = argv[0]; params->ssid_length = strlen(params->ssid); if (params->ssid_length > WIFI_SSID_MAX_LEN) { + print(context.sh, SHELL_WARNING, + "SSID too long (max %d characters)\n", + WIFI_SSID_MAX_LEN); return -EINVAL; } @@ -469,6 +476,11 @@ static int __wifi_args_to_params(size_t argc, char *argv[], long channel = strtol(argv[idx], &endptr, 10); if (*endptr != '\0') { + print(context.sh, SHELL_ERROR, + "Failed to parse channel: %s: endp: %s, err: %s\n", + argv[idx], + endptr, + strerror(errno)); return -EINVAL; } @@ -480,8 +492,23 @@ static int __wifi_args_to_params(size_t argc, char *argv[], WIFI_FREQ_BAND_6_GHZ}; uint8_t band; bool found = false; + char bands_str[MAX_BANDS_STR_LEN] = {0}; + size_t offset = 0; for (band = 0; band < ARRAY_SIZE(bands); band++) { + offset += snprintf(bands_str + offset, + sizeof(bands_str) - offset, + "%s%s", + band ? "," : "", + wifi_band_txt(bands[band])); + if (offset >= sizeof(bands_str)) { + print(context.sh, SHELL_ERROR, + "Failed to parse channel: %s: " + "band string too long\n", + argv[idx]); + return -EINVAL; + } + if (wifi_utils_validate_chan(bands[band], channel)) { found = true; @@ -490,6 +517,10 @@ static int __wifi_args_to_params(size_t argc, char *argv[], } if (!found) { + print(context.sh, SHELL_ERROR, + "Invalid channel: %ld, checked bands: %s\n", + channel, + bands_str); return -EINVAL; } @@ -522,6 +553,9 @@ static int __wifi_args_to_params(size_t argc, char *argv[], if (security == WIFI_SECURITY_TYPE_NONE || security == WIFI_SECURITY_TYPE_WPA_PSK) { + print(context.sh, SHELL_ERROR, + "MFP not supported for security type %s\n", + wifi_security_txt(security)); return -EINVAL; } @@ -537,6 +571,10 @@ static int __wifi_args_to_params(size_t argc, char *argv[], params->psk_length > WIFI_PSK_MAX_LEN) || (params->security == WIFI_SECURITY_TYPE_SAE && params->psk_length > WIFI_SAE_PSWD_MAX_LEN)) { + print(context.sh, SHELL_ERROR, + "Invalid PSK length (%d) for security type %s\n", + params->psk_length, + wifi_security_txt(params->security)); return -EINVAL; } } @@ -551,13 +589,13 @@ static int cmd_wifi_connect(const struct shell *sh, size_t argc, struct net_if *iface = net_if_get_first_wifi(); struct wifi_connect_req_params cnx_params = { 0 }; + context.sh = sh; if (__wifi_args_to_params(argc - 1, &argv[1], &cnx_params, WIFI_MODE_INFRA)) { shell_help(sh); return -ENOEXEC; } context.connecting = true; - context.sh = sh; if (net_mgmt(NET_REQUEST_WIFI_CONNECT, iface, &cnx_params, sizeof(struct wifi_connect_req_params))) { @@ -1244,13 +1282,12 @@ static int cmd_wifi_ap_enable(const struct shell *sh, size_t argc, static struct wifi_connect_req_params cnx_params; int ret; + context.sh = sh; if (__wifi_args_to_params(argc - 1, &argv[1], &cnx_params, WIFI_MODE_AP)) { shell_help(sh); return -ENOEXEC; } - context.sh = sh; - k_mutex_init(&wifi_ap_sta_list_lock); ret = net_mgmt(NET_REQUEST_WIFI_AP_ENABLE, iface, &cnx_params, From 5db55b01af3ddc5d9e41632e320c3f77e6631d51 Mon Sep 17 00:00:00 2001 From: Alexander Kozhinov Date: Fri, 12 Jan 2024 00:24:10 +0100 Subject: [PATCH 2468/3723] drivers: can: can_stm32h7_fdcan: add device fail on invalid fed clock value Fail on wrong FDCAN clock in can_stm32h7_clock_enable() stage. Signed-off-by: Alexander Kozhinov --- drivers/can/can_stm32h7_fdcan.c | 21 +++++++++++++++++++++ 1 file changed, 21 insertions(+) diff --git a/drivers/can/can_stm32h7_fdcan.c b/drivers/can/can_stm32h7_fdcan.c index 977da154dc0..b2e8b8060ef 100644 --- a/drivers/can/can_stm32h7_fdcan.c +++ b/drivers/can/can_stm32h7_fdcan.c @@ -28,6 +28,8 @@ LOG_MODULE_REGISTER(can_stm32h7, CONFIG_CAN_LOG_LEVEL); #define STM32H7_FDCAN_DOMAIN_CLOCK_SUPPORT 0 #endif +#define VOS0_MAX_FREQ MHZ(125) + struct can_stm32h7_config { mm_reg_t base; mem_addr_t mrba; @@ -107,6 +109,7 @@ static int can_stm32h7_clock_enable(const struct device *dev) const struct can_mcan_config *mcan_cfg = dev->config; const struct can_stm32h7_config *stm32h7_cfg = mcan_cfg->custom; const struct device *const clk = DEVICE_DT_GET(STM32_CLOCK_CONTROL_NODE); + uint32_t fdcan_clock = 0xffffffff; int ret; if (!device_is_ready(clk)) { @@ -122,6 +125,24 @@ static int can_stm32h7_clock_enable(const struct device *dev) LOG_ERR("Could not select can_stm32fd domain clock"); return ret; } + + /* Check if clock has correct range according to chosen regulator voltage + * scaling (Table 62 of RM0399 Rev 4). + * There is no need to test HSE case, since it's value is in range of + * 4 to 50 MHz (please refer to CubeMX clock control). + */ + ret = clock_control_get_rate(clk, + (clock_control_subsys_t)&stm32h7_cfg->pclken[1], &fdcan_clock); + if (ret != 0) { + LOG_ERR("failure getting clock rate"); + return ret; + } + + if (fdcan_clock > VOS0_MAX_FREQ) { + LOG_ERR("FDCAN Clock source %d exceeds max allowed %d", + fdcan_clock, VOS0_MAX_FREQ); + return -ENODEV; + } } ret = clock_control_on(clk, (clock_control_subsys_t)&stm32h7_cfg->pclken[0]); From 2854fc18fdbd626e9486a9808b598702198856a0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Krzysztof=20Chru=C5=9Bci=C5=84ski?= Date: Wed, 8 Nov 2023 13:33:57 +0100 Subject: [PATCH 2469/3723] drivers: serial: Add async to interrupt driven adaptation MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Add adaptation layer which allows to provide interrupt driven API for drivers which exposes only asynchronous API. Signed-off-by: Krzysztof Chruściński --- drivers/serial/CMakeLists.txt | 1 + drivers/serial/Kconfig | 15 + drivers/serial/uart_async_to_irq.c | 377 ++++++++++++++++++ .../zephyr/drivers/serial/uart_async_to_irq.h | 285 +++++++++++++ 4 files changed, 678 insertions(+) create mode 100644 drivers/serial/uart_async_to_irq.c create mode 100644 include/zephyr/drivers/serial/uart_async_to_irq.h diff --git a/drivers/serial/CMakeLists.txt b/drivers/serial/CMakeLists.txt index bfc38603864..2cd79e12f64 100644 --- a/drivers/serial/CMakeLists.txt +++ b/drivers/serial/CMakeLists.txt @@ -93,3 +93,4 @@ endif() zephyr_library_sources_ifdef(CONFIG_SERIAL_TEST serial_test.c) zephyr_library_sources_ifdef(CONFIG_UART_ASYNC_RX_HELPER uart_async_rx.c) +zephyr_library_sources_ifdef(CONFIG_UART_ASYNC_TO_INT_DRIVEN_API uart_async_to_irq.c) diff --git a/drivers/serial/Kconfig b/drivers/serial/Kconfig index 5eb183c9a3e..2d097932cf4 100644 --- a/drivers/serial/Kconfig +++ b/drivers/serial/Kconfig @@ -133,6 +133,21 @@ config UART_ASYNC_RX_HELPER is delayed. Module implements zero-copy approach with multiple reception buffers. +config UART_ASYNC_TO_INT_DRIVEN_API + bool + select UART_ASYNC_RX_HELPER + help + Asynchronous to Interrupt driven adaptation layer. When enabled device + which implements only asynchronous API can be used with interrupt driven + API implemented by the generic adaptation layer. + +config UART_ASYNC_TO_INT_DRIVEN_RX_TIMEOUT + int "Receiver timeout (in bauds)" + depends on UART_ASYNC_TO_INT_DRIVEN_API + default 100 + help + Receiver inactivity timeout. It is used to calculate timeout in microseconds. + comment "Serial Drivers" source "drivers/serial/Kconfig.b91" diff --git a/drivers/serial/uart_async_to_irq.c b/drivers/serial/uart_async_to_irq.c new file mode 100644 index 00000000000..209e8d4f205 --- /dev/null +++ b/drivers/serial/uart_async_to_irq.c @@ -0,0 +1,377 @@ +/* + * Copyright (c) 2023 Nordic Semiconductor ASA + * + * SPDX-License-Identifier: Apache-2.0 + */ +#include +#include +#include +LOG_MODULE_REGISTER(UART_ASYNC_TO_IRQ_LOG_NAME, CONFIG_UART_LOG_LEVEL); + +/* Internal state flags. */ + +/* RX interrupt enabled. */ +#define A2I_RX_IRQ_ENABLED BIT(0) + +/* TX interrupt enabled. */ +#define A2I_TX_IRQ_ENABLED BIT(1) + +/* Error interrupt enabled. */ +#define A2I_ERR_IRQ_ENABLED BIT(2) + +/* Receiver to be kept enabled. */ +#define A2I_RX_ENABLE BIT(3) + +/* TX busy. */ +#define A2I_TX_BUSY BIT(4) + +static struct uart_async_to_irq_data *get_data(const struct device *dev) +{ + struct uart_async_to_irq_data **data = dev->data; + + return *data; +} + +static const struct uart_async_to_irq_config *get_config(const struct device *dev) +{ + const struct uart_async_to_irq_config * const *config = dev->config; + + return *config; +} + +/* Function calculates RX timeout based on baudrate. */ +static uint32_t get_rx_timeout(const struct device *dev) +{ + struct uart_config cfg; + int err; + uint32_t baudrate; + + err = uart_config_get(dev, &cfg); + if (err == 0) { + baudrate = cfg.baudrate; + } else { + baudrate = get_config(dev)->baudrate; + } + + uint32_t us = (CONFIG_UART_ASYNC_TO_INT_DRIVEN_RX_TIMEOUT * 1000000) / baudrate; + + return us; +} + +static int rx_enable(const struct device *dev, + struct uart_async_to_irq_data *data, + uint8_t *buf, + size_t len) +{ + int err; + const struct uart_async_to_irq_config *config = get_config(dev); + + err = config->api->rx_enable(dev, buf, len, get_rx_timeout(dev)); + + return err; +} + +static int try_rx_enable(const struct device *dev, struct uart_async_to_irq_data *data) +{ + uint8_t *buf = uart_async_rx_buf_req(&data->rx.async_rx); + size_t len = uart_async_rx_get_buf_len(&data->rx.async_rx); + + if (buf == NULL) { + return -EBUSY; + } + + return rx_enable(dev, data, buf, len); +} + +static void on_rx_buf_req(const struct device *dev, + const struct uart_async_to_irq_config *config, + struct uart_async_to_irq_data *data) +{ + struct uart_async_rx *async_rx = &data->rx.async_rx; + uint8_t *buf = uart_async_rx_buf_req(async_rx); + size_t len = uart_async_rx_get_buf_len(async_rx); + + if (buf) { + int err = config->api->rx_buf_rsp(dev, buf, len); + + if (err < 0) { + uart_async_rx_on_buf_rel(async_rx, buf); + } + } else { + atomic_inc(&data->rx.pending_buf_req); + } +} + +static void on_rx_dis(const struct device *dev, struct uart_async_to_irq_data *data) +{ + if (data->flags & A2I_RX_ENABLE) { + data->rx.pending_buf_req = 0; + + int err = try_rx_enable(dev, data); + + LOG_INST_DBG(get_config(dev)->log, "Reenabling RX from RX_DISABLED (err:%d)", err); + __ASSERT_NO_MSG(err >= 0); + return; + } + + k_sem_give(&data->rx.sem); +} + +static void uart_async_to_irq_callback(const struct device *dev, + struct uart_event *evt, + void *user_data) +{ + struct uart_async_to_irq_data *data = (struct uart_async_to_irq_data *)user_data; + const struct uart_async_to_irq_config *config = get_config(dev); + bool call_handler = false; + + switch (evt->type) { + case UART_TX_DONE: + atomic_and(&data->flags, ~A2I_TX_BUSY); + call_handler = data->flags & A2I_TX_IRQ_ENABLED; + break; + case UART_RX_RDY: + uart_async_rx_on_rdy(&data->rx.async_rx, evt->data.rx.buf, evt->data.rx.len); + call_handler = data->flags & A2I_RX_IRQ_ENABLED; + break; + case UART_RX_BUF_REQUEST: + on_rx_buf_req(dev, config, data); + break; + case UART_RX_BUF_RELEASED: + uart_async_rx_on_buf_rel(&data->rx.async_rx, evt->data.rx_buf.buf); + break; + case UART_RX_STOPPED: + call_handler = data->flags & A2I_ERR_IRQ_ENABLED; + break; + case UART_RX_DISABLED: + on_rx_dis(dev, data); + break; + default: + break; + } + + if (data->callback && call_handler) { + atomic_inc(&data->irq_req); + config->trampoline(dev); + } +} + +int z_uart_async_to_irq_fifo_fill(const struct device *dev, const uint8_t *buf, int len) +{ + struct uart_async_to_irq_data *data = get_data(dev); + const struct uart_async_to_irq_config *config = get_config(dev); + int err; + + len = MIN(len, data->tx.len); + if (atomic_or(&data->flags, A2I_TX_BUSY) & A2I_TX_BUSY) { + return 0; + } + + memcpy(data->tx.buf, buf, len); + + err = config->api->tx(dev, data->tx.buf, len, SYS_FOREVER_US); + if (err < 0) { + atomic_and(&data->flags, ~A2I_TX_BUSY); + return 0; + } + + return len; +} + +/** Interrupt driven FIFO read function */ +int z_uart_async_to_irq_fifo_read(const struct device *dev, + uint8_t *buf, + const int len) +{ + struct uart_async_to_irq_data *data = get_data(dev); + const struct uart_async_to_irq_config *config = get_config(dev); + struct uart_async_rx *async_rx = &data->rx.async_rx; + size_t claim_len; + uint8_t *claim_buf; + + claim_len = uart_async_rx_data_claim(async_rx, &claim_buf, len); + if (claim_len == 0) { + return 0; + } + + memcpy(buf, claim_buf, claim_len); + uart_async_rx_data_consume(async_rx, claim_len); + + if (data->rx.pending_buf_req) { + buf = uart_async_rx_buf_req(async_rx); + if (buf) { + int err; + size_t rx_len = uart_async_rx_get_buf_len(async_rx); + + atomic_dec(&data->rx.pending_buf_req); + err = config->api->rx_buf_rsp(dev, buf, rx_len); + if (err < 0) { + if (err == -EACCES) { + data->rx.pending_buf_req = 0; + err = rx_enable(dev, data, buf, rx_len); + } + if (err < 0) { + return err; + } + } + } + } + + return (int)claim_len; +} + +static void dir_disable(const struct device *dev, uint32_t flag) +{ + struct uart_async_to_irq_data *data = get_data(dev); + + atomic_and(&data->flags, ~flag); +} + +static void dir_enable(const struct device *dev, uint32_t flag) +{ + struct uart_async_to_irq_data *data = get_data(dev); + + atomic_or(&data->flags, flag); + + atomic_inc(&data->irq_req); + get_config(dev)->trampoline(dev); +} + +/** Interrupt driven transfer enabling function */ +void z_uart_async_to_irq_irq_tx_enable(const struct device *dev) +{ + dir_enable(dev, A2I_TX_IRQ_ENABLED); +} + +/** Interrupt driven transfer disabling function */ +void z_uart_async_to_irq_irq_tx_disable(const struct device *dev) +{ + dir_disable(dev, A2I_TX_IRQ_ENABLED); +} + +/** Interrupt driven transfer ready function */ +int z_uart_async_to_irq_irq_tx_ready(const struct device *dev) +{ + struct uart_async_to_irq_data *data = get_data(dev); + + return (data->flags & A2I_TX_IRQ_ENABLED) && !(data->flags & A2I_TX_BUSY); +} + +/** Interrupt driven receiver enabling function */ +void z_uart_async_to_irq_irq_rx_enable(const struct device *dev) +{ + dir_enable(dev, A2I_RX_IRQ_ENABLED); +} + +/** Interrupt driven receiver disabling function */ +void z_uart_async_to_irq_irq_rx_disable(const struct device *dev) +{ + dir_disable(dev, A2I_RX_IRQ_ENABLED); +} + +/** Interrupt driven transfer complete function */ +int z_uart_async_to_irq_irq_tx_complete(const struct device *dev) +{ + return z_uart_async_to_irq_irq_tx_ready(dev); +} + +/** Interrupt driven receiver ready function */ +int z_uart_async_to_irq_irq_rx_ready(const struct device *dev) +{ + struct uart_async_to_irq_data *data = get_data(dev); + + return (data->flags & A2I_RX_IRQ_ENABLED) && (data->rx.async_rx.pending_bytes > 0); +} + +/** Interrupt driven error enabling function */ +void z_uart_async_to_irq_irq_err_enable(const struct device *dev) +{ + dir_enable(dev, A2I_ERR_IRQ_ENABLED); +} + +/** Interrupt driven error disabling function */ +void z_uart_async_to_irq_irq_err_disable(const struct device *dev) +{ + dir_disable(dev, A2I_ERR_IRQ_ENABLED); +} + +/** Interrupt driven pending status function */ +int z_uart_async_to_irq_irq_is_pending(const struct device *dev) +{ + return z_uart_async_to_irq_irq_tx_ready(dev) || z_uart_async_to_irq_irq_rx_ready(dev); +} + +/** Interrupt driven interrupt update function */ +int z_uart_async_to_irq_irq_update(const struct device *dev) +{ + return 1; +} + +/** Set the irq callback function */ +void z_uart_async_to_irq_irq_callback_set(const struct device *dev, + uart_irq_callback_user_data_t cb, + void *user_data) +{ + struct uart_async_to_irq_data *data = get_data(dev); + + data->callback = cb; + data->user_data = user_data; +} + +int uart_async_to_irq_rx_enable(const struct device *dev) +{ + struct uart_async_to_irq_data *data = get_data(dev); + const struct uart_async_to_irq_config *config = get_config(dev); + int err; + + err = config->api->callback_set(dev, uart_async_to_irq_callback, data); + if (err < 0) { + return err; + } + + uart_async_rx_reset(&data->rx.async_rx); + + err = try_rx_enable(dev, data); + if (err == 0) { + atomic_or(&data->flags, A2I_RX_ENABLE); + } + + return err; +} + +int uart_async_to_irq_rx_disable(const struct device *dev) +{ + struct uart_async_to_irq_data *data = get_data(dev); + const struct uart_async_to_irq_config *config = get_config(dev); + int err; + + if (atomic_and(&data->flags, ~A2I_RX_ENABLE) & A2I_RX_ENABLE) { + err = config->api->rx_disable(dev); + if (err < 0) { + return err; + } + k_sem_take(&data->rx.sem, K_FOREVER); + } + + return 0; +} + +void uart_async_to_irq_trampoline_cb(const struct device *dev) +{ + struct uart_async_to_irq_data *data = get_data(dev); + + do { + data->callback(dev, data->user_data); + } while (atomic_dec(&data->irq_req) > 1); +} + +int uart_async_to_irq_init(struct uart_async_to_irq_data *data, + const struct uart_async_to_irq_config *config) +{ + data->tx.buf = config->tx_buf; + data->tx.len = config->tx_len; + + k_sem_init(&data->rx.sem, 0, 1); + + return uart_async_rx_init(&data->rx.async_rx, &config->async_rx); +} diff --git a/include/zephyr/drivers/serial/uart_async_to_irq.h b/include/zephyr/drivers/serial/uart_async_to_irq.h new file mode 100644 index 00000000000..d5116dee2c0 --- /dev/null +++ b/include/zephyr/drivers/serial/uart_async_to_irq.h @@ -0,0 +1,285 @@ +/* + * Copyright (c) 2023 Nordic Semiconductor ASA + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#ifndef ZEPHYR_DRIVERS_SERIAL_UART_ASYNC_TO_IRQ_H_ +#define ZEPHYR_DRIVERS_SERIAL_UART_ASYNC_TO_IRQ_H_ + +#include +#include +#include +#include +#include + +/** + * @brief UART Asynchronous to Interrupt driven API adaptation layer + * @ingroup uart_interface + * @{ + */ + +#ifdef __cplusplus +extern "C" { +#endif + +/* Forward declarations. */ + +/** @brief Data structure used by the adaptation layer. + * + * Pointer to that data must be the first element of the UART device data structure. + */ +struct uart_async_to_irq_data; + +/** @brief Configuration structure used by the adaptation layer. + * + * Pointer to this data must be the first element of the UART device configuration structure. + */ +struct uart_async_to_irq_config; + +/* @brief Function that triggers trampoline to the interrupt context. + * + * This context is used to call user UART interrupt handler. It is to used to + * fulfill the requirement that UART interrupt driven API shall be called from + * the UART interrupt. Trampoline context shall have the same priority as UART. + * + * One option may be to use k_timer configured to expire immediately. + */ +typedef void (*uart_async_to_irq_trampoline)(const struct device *dev); + +/** @brief Callback to be called from trampoline context. + * + * @param dev UART device. + */ +void uart_async_to_irq_trampoline_cb(const struct device *dev); + +/** @brief Interrupt driven API initializer. + * + * It should be used in the initialization of the UART API structure in the + * driver to provide interrupt driven API functions. + */ +#define UART_ASYNC_TO_IRQ_API_INIT() \ + .fifo_fill = z_uart_async_to_irq_fifo_fill, \ + .fifo_read = z_uart_async_to_irq_fifo_read, \ + .irq_tx_enable = z_uart_async_to_irq_irq_tx_enable, \ + .irq_tx_disable = z_uart_async_to_irq_irq_tx_disable, \ + .irq_tx_ready = z_uart_async_to_irq_irq_tx_ready, \ + .irq_rx_enable = z_uart_async_to_irq_irq_rx_enable, \ + .irq_rx_disable = z_uart_async_to_irq_irq_rx_disable, \ + .irq_tx_complete = z_uart_async_to_irq_irq_tx_complete,\ + .irq_rx_ready = z_uart_async_to_irq_irq_rx_ready, \ + .irq_err_enable = z_uart_async_to_irq_irq_err_enable, \ + .irq_err_disable = z_uart_async_to_irq_irq_err_disable,\ + .irq_is_pending = z_uart_async_to_irq_irq_is_pending, \ + .irq_update = z_uart_async_to_irq_irq_update, \ + .irq_callback_set = z_uart_async_to_irq_irq_callback_set + +/** @brief Configuration structure initializer. + * + * @param _api Structure with UART asynchronous API. + * @param _trampoline Function that trampolines to the interrupt context. + * @param _baudrate UART baudrate. + * @param _tx_buf TX buffer. + * @param _tx_len TX buffer length. + * @param _rx_buf RX buffer. + * @param _rx_len RX buffer length. + * @param _rx_cnt Number of chunks into which RX buffer is divided. + * @param _log Logging instance, if not provided (empty) then default is used. + */ +#define UART_ASYNC_TO_IRQ_API_CONFIG_INITIALIZER(_api, _trampoline, _baudrate, _tx_buf, \ + _tx_len, _rx_buf, _rx_len, _rx_cnt, _log) \ + { \ + .tx_buf = _tx_buf, \ + .tx_len = _tx_len, \ + .async_rx = { \ + .buffer = _rx_buf, \ + .length = _rx_len, \ + .buf_cnt = _rx_cnt \ + }, \ + .api = _api, \ + .trampoline = _trampoline, \ + .baudrate = _baudrate, \ + LOG_OBJECT_PTR_INIT(log, \ + COND_CODE_1(IS_EMPTY(_log), \ + (LOG_OBJECT_PTR(UART_ASYNC_TO_IRQ_LOG_NAME)), \ + (_log) \ + ) \ + ) \ + } + +/** @brief Initialize the adaptation layer. + * + * @param data Data associated with the given adaptation layer instance. + * @param config Configuration structure. Must be persistent. + * + * @retval 0 On successful initialization. + */ +int uart_async_to_irq_init(struct uart_async_to_irq_data *data, + const struct uart_async_to_irq_config *config); + +/* @brief Enable RX for interrupt driven API. + * + * @param dev UART device. Device must support asynchronous API. + * + * @retval 0 on successful operation. + * @retval -EINVAL if adaption layer has wrong configuration. + * @retval negative value Error reported by the UART API. + */ +int uart_async_to_irq_rx_enable(const struct device *dev); + +/* @brief Disable RX for interrupt driven API. + * + * @param dev UART device. Device must support asynchronous API. + * + * @retval 0 on successful operation. + * @retval -EINVAL if adaption layer has wrong configuration. + * @retval negative value Error reported by the UART API. + */ +int uart_async_to_irq_rx_disable(const struct device *dev); + +/* Starting from here API is internal only. */ + +/** @cond INTERNAL_HIDDEN + * @brief Structure used by the adaptation layer. + */ +struct uart_async_to_irq_config { + /** Pointer to the TX buffer. */ + uint8_t *tx_buf; + + /** TX buffer length. */ + size_t tx_len; + + /** UART Asynchronous RX helper configuration. */ + struct uart_async_rx_config async_rx; + + /** Async API used by the a2i layer. */ + const struct uart_async_to_irq_async_api *api; + + /** Trampoline callback. */ + uart_async_to_irq_trampoline trampoline; + + /** Initial baudrate. */ + uint32_t baudrate; + + /** Instance logging handler. */ + LOG_INSTANCE_PTR_DECLARE(log); +}; + +/** @brief Asynchronous API used by the adaptation layer. */ +struct uart_async_to_irq_async_api { + int (*callback_set)(const struct device *dev, + uart_callback_t callback, + void *user_data); + + int (*tx)(const struct device *dev, const uint8_t *buf, size_t len, + int32_t timeout); + int (*tx_abort)(const struct device *dev); + + int (*rx_enable)(const struct device *dev, uint8_t *buf, size_t len, + int32_t timeout); + int (*rx_buf_rsp)(const struct device *dev, uint8_t *buf, size_t len); + int (*rx_disable)(const struct device *dev); +}; + +/** @brief Structure holding receiver data. */ +struct uart_async_to_irq_rx_data { + /** Asynchronous RX helper data. */ + struct uart_async_rx async_rx; + + /** Semaphore for pending on RX disable. */ + struct k_sem sem; + + /** Number of pending buffer requests which weren't handled because lack of free buffers. */ + atomic_t pending_buf_req; +}; + +/** @brief Structure holding transmitter data. */ +struct uart_async_to_irq_tx_data { + /** TX buffer. */ + uint8_t *buf; + + /** Length of the buffer. */ + size_t len; +}; + +/** @briref Data associated with the asynchronous to the interrupt driven API adaptation layer. */ +struct uart_async_to_irq_data { + /** User callback for interrupt driven API. */ + uart_irq_callback_user_data_t callback; + + /** User data. */ + void *user_data; + + /** Interrupt request counter. */ + atomic_t irq_req; + + /** RX specific data. */ + struct uart_async_to_irq_rx_data rx; + + /** TX specific data. */ + struct uart_async_to_irq_tx_data tx; + + /** Spinlock. */ + struct k_spinlock lock; + + /** Internally used flags for holding the state of the a2i layer. */ + atomic_t flags; +}; + +/** Interrupt driven FIFO fill function. */ +int z_uart_async_to_irq_fifo_fill(const struct device *dev, + const uint8_t *buf, + int len); + +/** Interrupt driven FIFO read function. */ +int z_uart_async_to_irq_fifo_read(const struct device *dev, + uint8_t *buf, + const int len); + +/** Interrupt driven transfer enabling function. */ +void z_uart_async_to_irq_irq_tx_enable(const struct device *dev); + +/** Interrupt driven transfer disabling function */ +void z_uart_async_to_irq_irq_tx_disable(const struct device *dev); + +/** Interrupt driven transfer ready function */ +int z_uart_async_to_irq_irq_tx_ready(const struct device *dev); + +/** Interrupt driven receiver enabling function */ +void z_uart_async_to_irq_irq_rx_enable(const struct device *dev); + +/** Interrupt driven receiver disabling function */ +void z_uart_async_to_irq_irq_rx_disable(const struct device *dev); + +/** Interrupt driven transfer complete function */ +int z_uart_async_to_irq_irq_tx_complete(const struct device *dev); + +/** Interrupt driven receiver ready function */ +int z_uart_async_to_irq_irq_rx_ready(const struct device *dev); + +/** Interrupt driven error enabling function */ +void z_uart_async_to_irq_irq_err_enable(const struct device *dev); + +/** Interrupt driven error disabling function */ +void z_uart_async_to_irq_irq_err_disable(const struct device *dev); + +/** Interrupt driven pending status function */ +int z_uart_async_to_irq_irq_is_pending(const struct device *dev); + +/** Interrupt driven interrupt update function */ +int z_uart_async_to_irq_irq_update(const struct device *dev); + +/** Set the irq callback function */ +void z_uart_async_to_irq_irq_callback_set(const struct device *dev, + uart_irq_callback_user_data_t cb, + void *user_data); + +/** @endcond */ + +#ifdef __cplusplus +} +#endif + +/** @} */ + +#endif /* ZEPHYR_DRIVERS_SERIAL_UART_ASYNC_TO_IRQ_H_ */ From a0382bd0f39e94461820fc31a7394d2be35cabf6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Krzysztof=20Chru=C5=9Bci=C5=84ski?= Date: Mon, 13 Nov 2023 11:14:37 +0100 Subject: [PATCH 2470/3723] soc: arm: nordic_nrf: Disable UART runtime configuration MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Since it takes 400 bytes of code and it is rarely used disable by default this feature. Signed-off-by: Krzysztof Chruściński --- doc/releases/migration-guide-3.6.rst | 4 ++++ soc/arm/nordic_nrf/Kconfig.defconfig | 3 +++ 2 files changed, 7 insertions(+) diff --git a/doc/releases/migration-guide-3.6.rst b/doc/releases/migration-guide-3.6.rst index 822b090c17d..ab621d2676e 100644 --- a/doc/releases/migration-guide-3.6.rst +++ b/doc/releases/migration-guide-3.6.rst @@ -204,6 +204,10 @@ Device Drivers and Device Tree <&rcc STM32_SRC_PLL1_Q FDCAN_SEL(1)>; }; +* Runtime configuration is now disabled by default for Nordic UART drivers. The motivation for the + change is that this feature is rarely used and disabling it significantly reduces the memory + footprint. + Power Management ================ diff --git a/soc/arm/nordic_nrf/Kconfig.defconfig b/soc/arm/nordic_nrf/Kconfig.defconfig index 3eedcf350c6..858c60d1d88 100644 --- a/soc/arm/nordic_nrf/Kconfig.defconfig +++ b/soc/arm/nordic_nrf/Kconfig.defconfig @@ -40,4 +40,7 @@ config GPIO default y depends on SPI +config UART_USE_RUNTIME_CONFIGURE + default n + endif # SOC_FAMILY_NRF From 4fcf8e0630b64c3f40c5c6acb5feb6ad1cab714f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Krzysztof=20Chru=C5=9Bci=C5=84ski?= Date: Wed, 17 Jan 2024 11:53:35 +0100 Subject: [PATCH 2471/3723] modules: hal_nordic: nrfx: Add new UARTE options to Kconfig MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Add Kconfig options to new configuration flags for nrfx_uarte. Signed-off-by: Krzysztof Chruściński --- modules/hal_nordic/nrfx/Kconfig | 21 +++++++++++++++++++++ modules/hal_nordic/nrfx/nrfx_config.h | 12 ++++++++++++ 2 files changed, 33 insertions(+) diff --git a/modules/hal_nordic/nrfx/Kconfig b/modules/hal_nordic/nrfx/Kconfig index a92aa93d9a2..b4c00040ee1 100644 --- a/modules/hal_nordic/nrfx/Kconfig +++ b/modules/hal_nordic/nrfx/Kconfig @@ -573,6 +573,27 @@ config NRFX_UARTE3 depends on $(dt_nodelabel_has_compat,uart3,$(DT_COMPAT_NORDIC_NRF_UARTE)) select NRFX_UARTE +config NRFX_UARTE_CONFIG_SKIP_GPIO_CONFIG + bool "UARTE GPIO configuration support" + depends on NRFX_UARTE + +config NRFX_UARTE_CONFIG_SKIP_PSEL_CONFIG + bool "UARTE PSEL configuration support" + depends on NRFX_UARTE + +config NRFX_UARTE_CONFIG_TX_LINK + bool "UARTE TX transfer linking support" + depends on NRFX_UARTE + +config NRFX_UARTE_CONFIG_RX_CACHE_ENABLED + bool "UARTE RX caching support" + default y if $(dt_nodelabel_has_compat,ram3x,$(DT_COMPAT_MMIO_SRAM)) + depends on NRFX_UARTE + help + Feature might be enabled on platforms which has limitations regarding addresses + to which receiver can write data. If enabled then internal driver buffers + (cache buffers) are used for DMA transfers and data is copied to the user buffer. + config NRFX_USBREG bool "USBREG driver" depends on $(dt_has_compat,$(DT_COMPAT_NORDIC_NRF_USBREG)) diff --git a/modules/hal_nordic/nrfx/nrfx_config.h b/modules/hal_nordic/nrfx/nrfx_config.h index 57417644c32..ac930b13639 100644 --- a/modules/hal_nordic/nrfx/nrfx_config.h +++ b/modules/hal_nordic/nrfx/nrfx_config.h @@ -563,6 +563,18 @@ #ifdef CONFIG_NRFX_UARTE3 #define NRFX_UARTE3_ENABLED 1 #endif +#ifdef CONFIG_NRFX_UARTE_CONFIG_SKIP_GPIO_CONFIG +#define NRFX_UARTE_CONFIG_SKIP_GPIO_CONFIG 1 +#endif +#ifdef CONFIG_NRFX_UARTE_CONFIG_SKIP_PSEL_CONFIG +#define NRFX_UARTE_CONFIG_SKIP_PSEL_CONFIG 1 +#endif +#ifdef CONFIG_NRFX_UARTE_CONFIG_TX_LINK +#define NRFX_UARTE_CONFIG_TX_LINK 1 +#endif +#ifdef CONFIG_NRFX_UARTE_CONFIG_RX_CACHE_ENABLED +#define NRFX_UARTE_CONFIG_RX_CACHE_ENABLED 1 +#endif #ifdef CONFIG_NRFX_USBREG #define NRFX_USBREG_ENABLED 1 From 4cc213bc8d17220a2569ff8bb7548d6ed03f7d2f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Krzysztof=20Chru=C5=9Bci=C5=84ski?= Date: Wed, 17 Jan 2024 11:54:10 +0100 Subject: [PATCH 2472/3723] drivers: serial: nrfx: Add new shim based on nrfx_uarte MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Add new shim which is based on nrfx driver. Legacy shim is kept for transition period. It can be used after setting CONFIG_UART_NRFX_UARTE_LEGACY_SHIM. Signed-off-by: Krzysztof Chruściński --- drivers/serial/CMakeLists.txt | 8 +- drivers/serial/Kconfig.nrfx | 11 +- drivers/serial/Kconfig.nrfx_uart_instance | 45 +- drivers/serial/uart_nrfx_uarte2.c | 1030 +++++++++++++++++++++ 4 files changed, 1091 insertions(+), 3 deletions(-) create mode 100644 drivers/serial/uart_nrfx_uarte2.c diff --git a/drivers/serial/CMakeLists.txt b/drivers/serial/CMakeLists.txt index 2cd79e12f64..67e02e0c261 100644 --- a/drivers/serial/CMakeLists.txt +++ b/drivers/serial/CMakeLists.txt @@ -26,7 +26,13 @@ zephyr_library_sources_ifdef(CONFIG_UART_MIV uart_miv.c) zephyr_library_sources_ifdef(CONFIG_UART_MSP432P4XX uart_msp432p4xx.c) zephyr_library_sources_ifdef(CONFIG_UART_NS16550 uart_ns16550.c) zephyr_library_sources_ifdef(CONFIG_UART_NRFX_UART uart_nrfx_uart.c) -zephyr_library_sources_ifdef(CONFIG_UART_NRFX_UARTE uart_nrfx_uarte.c) +if (CONFIG_UART_NRFX_UARTE) + if (CONFIG_UART_NRFX_UARTE_LEGACY_SHIM) + zephyr_library_sources(uart_nrfx_uarte.c) + else() + zephyr_library_sources(uart_nrfx_uarte2.c) + endif() +endif() zephyr_library_sources_ifdef(CONFIG_UART_NUMICRO uart_numicro.c) zephyr_library_sources_ifdef(CONFIG_UART_SAM uart_sam.c) zephyr_library_sources_ifdef(CONFIG_USART_SAM usart_sam.c) diff --git a/drivers/serial/Kconfig.nrfx b/drivers/serial/Kconfig.nrfx index 53553e3d06e..5709ca2d23a 100644 --- a/drivers/serial/Kconfig.nrfx +++ b/drivers/serial/Kconfig.nrfx @@ -25,11 +25,20 @@ config UART_NRFX_UART config UART_NRFX_UARTE def_bool y depends on DT_HAS_NORDIC_NRF_UARTE_ENABLED + imply NRFX_UARTE_CONFIG_SKIP_PSEL_CONFIG if !UART_NRFX_UARTE_LEGACY_SHIM + imply NRFX_UARTE_CONFIG_SKIP_GPIO_CONFIG if !UART_NRFX_UARTE_LEGACY_SHIM + +config UART_NRFX_UARTE_LEGACY_SHIM + bool "Legacy UARTE shim" + depends on UART_NRFX_UARTE + # New shim takes more ROM. Until it is fixed use legacy shim in memory + # constraint case. + default y if MCUBOOT config UART_ASYNC_TX_CACHE_SIZE int "TX cache buffer size" depends on UART_ASYNC_API - depends on UART_NRFX_UARTE + depends on UART_NRFX_UARTE_LEGACY_SHIM default 8 help For UARTE, TX cache buffer is used when provided TX buffer is not located diff --git a/drivers/serial/Kconfig.nrfx_uart_instance b/drivers/serial/Kconfig.nrfx_uart_instance index 39e774e2544..76f74caa038 100644 --- a/drivers/serial/Kconfig.nrfx_uart_instance +++ b/drivers/serial/Kconfig.nrfx_uart_instance @@ -6,6 +6,7 @@ config UART_$(nrfx_uart_num)_INTERRUPT_DRIVEN bool "Interrupt support on port $(nrfx_uart_num)" depends on UART_INTERRUPT_DRIVEN + select UART_ASYNC_TO_INT_DRIVEN_API if !UART_NRFX_UARTE_LEGACY_SHIM default y help This option enables UART interrupt support on port $(nrfx_uart_num). @@ -27,6 +28,9 @@ config UART_$(nrfx_uart_num)_ENHANCED_POLL_OUT When enabled, polling out does not trigger interrupt which stops TX. Feature uses a PPI channel. +config NRFX_UARTE$(nrfx_uart_num) + def_bool y if HAS_HW_NRF_UARTE$(nrfx_uart_num) && !UART_NRFX_UARTE_LEGACY_SHIM + config UART_$(nrfx_uart_num)_NRF_PARITY_BIT bool "Parity bit" help @@ -34,7 +38,8 @@ config UART_$(nrfx_uart_num)_NRF_PARITY_BIT config UART_$(nrfx_uart_num)_NRF_TX_BUFFER_SIZE int "Size of RAM buffer" - depends on UART_INTERRUPT_DRIVEN + depends on HAS_HW_NRF_UARTE$(nrfx_uart_num) + depends on UART_NRFX_UARTE_LEGACY_SHIM range 1 65535 default 32 help @@ -46,6 +51,7 @@ config UART_$(nrfx_uart_num)_NRF_HW_ASYNC bool "Use hardware RX byte counting" depends on HAS_HW_NRF_UARTE$(nrfx_uart_num) depends on UART_ASYNC_API + depends on UART_NRFX_UARTE_LEGACY_SHIM select NRFX_PPI if HAS_HW_NRF_PPI select NRFX_DPPI if HAS_HW_NRF_DPPIC help @@ -58,6 +64,7 @@ config UART_$(nrfx_uart_num)_NRF_ASYNC_LOW_POWER bool "Low power mode" depends on HAS_HW_NRF_UARTE$(nrfx_uart_num) depends on UART_ASYNC_API + depends on UART_NRFX_UARTE_LEGACY_SHIM help When enabled, UARTE is enabled before each TX or RX usage and disabled when not used. Disabling UARTE while in idle allows to achieve lowest @@ -67,6 +74,42 @@ config UART_$(nrfx_uart_num)_NRF_HW_ASYNC_TIMER int "Timer instance" depends on UART_$(nrfx_uart_num)_NRF_HW_ASYNC +config UART_$(nrfx_uart_num)_TX_CACHE_SIZE + int "TX cache buffer size" + depends on !UART_NRFX_UARTE_LEGACY_SHIM + default 8 + help + For UARTE, TX cache buffer is used when provided TX buffer is not located + in memory which can be used by the EasyDMA. + +config UART_$(nrfx_uart_num)_RX_CACHE_SIZE + int "RX cache buffer size" + depends on !UART_NRFX_UARTE_LEGACY_SHIM + default 32 if $(dt_nodelabel_has_compat,ram3x,$(DT_COMPAT_MMIO_SRAM)) + default 5 + range 5 255 + help + For UARTE, RX cache buffer is used when provided RX buffer is not located + in memory which can be used by the EasyDMA. It is also used to store + flushed data. + +config UART_$(nrfx_uart_num)_A2I_RX_SIZE + depends on !UART_NRFX_UARTE_LEGACY_SHIM + int "Asynchronous to interrupt driven adaptation layer RX buffer size" + default 64 if UART_$(nrfx_uart_num)_INTERRUPT_DRIVEN + default 0 + help + Amount of space dedicated for RX. It is divided into chunks with some + amount of that space used for control data. + +config UART_$(nrfx_uart_num)_A2I_RX_BUF_COUNT + depends on !UART_NRFX_UARTE_LEGACY_SHIM + int "Asynchronous to interrupt driven adaptation layer RX buffer count" + default 8 if UART_$(nrfx_uart_num)_INTERRUPT_DRIVEN + default 0 + help + Number of chunks into RX space is divided. + config UART_$(nrfx_uart_num)_GPIO_MANAGEMENT bool "GPIO management on port $(nrfx_uart_num)" depends on PM_DEVICE diff --git a/drivers/serial/uart_nrfx_uarte2.c b/drivers/serial/uart_nrfx_uarte2.c new file mode 100644 index 00000000000..c27f33c7284 --- /dev/null +++ b/drivers/serial/uart_nrfx_uarte2.c @@ -0,0 +1,1030 @@ +/* + * Copyright (c) 2023 Nordic Semiconductor ASA + * + * SPDX-License-Identifier: Apache-2.0 + */ + +/** + * @brief Driver for Nordic Semiconductor nRF UARTE + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#define LOG_MODULE_NAME uarte +LOG_MODULE_REGISTER(LOG_MODULE_NAME, CONFIG_UART_LOG_LEVEL); + +#define INSTANCE_INT_DRIVEN(periph, prefix, i, _) \ + IS_ENABLED(CONFIG_UART_##prefix##i##_INTERRUPT_DRIVEN) + +#define INSTANCE_ASYNC(periph, prefix, i, _) \ + IS_ENABLED(CONFIG_UART_##prefix##i##_ASYNC) + +#define INSTANCE_POLLING(periph, prefix, id, _) \ + UTIL_AND(CONFIG_HAS_HW_NRF_UARTE##prefix##id, \ + UTIL_AND(COND_CODE_1(CONFIG_UART_##prefix##id##_INTERRUPT_DRIVEN, (0), (1)), \ + COND_CODE_1(CONFIG_UART_##prefix##id##_ASYNC, (0), (1)))) + +#define INSTANCE_ENHANCED_POLL_OUT(periph, prefix, i, _) \ + IS_ENABLED(CONFIG_UART_##prefix##i##_ENHANCED_POLL_OUT) + +/* Macro determining if any instance is using interrupt driven API. */ +#if (NRFX_FOREACH_ENABLED(UARTE, INSTANCE_INT_DRIVEN, (+), (0), _)) +#define UARTE_ANY_INTERRUPT_DRIVEN 1 +#else +#define UARTE_ANY_INTERRUPT_DRIVEN 0 +#endif + +/* Macro determining if any instance is enabled and using ASYNC API. */ +#if (NRFX_FOREACH_ENABLED(UARTE, INSTANCE_ASYNC, (+), (0), _)) +#define UARTE_ANY_ASYNC 1 +#else +#define UARTE_ANY_ASYNC 0 +#endif + +/* Macro determining if any instance is using only polling API. */ +#if (NRFX_FOREACH_ENABLED(UARTE, INSTANCE_POLLING, (+), (0), _)) +#define UARTE_ANY_POLLING 1 +#else +#define UARTE_ANY_POLLING 0 +#endif + +/* Macro determining if any instance is using interrupt driven API. */ +#if (NRFX_FOREACH_ENABLED(UARTE, INSTANCE_ENHANCED_POLL_OUT, (+), (0), _)) +#define UARTE_ENHANCED_POLL_OUT 1 +#else +#define UARTE_ENHANCED_POLL_OUT 0 +#endif + +#if UARTE_ANY_INTERRUPT_DRIVEN || UARTE_ANY_ASYNC +#define UARTE_INT_ASYNC 1 +#else +#define UARTE_INT_ASYNC 0 +#endif + +#if defined(UARTE_CONFIG_PARITYTYPE_Msk) +#define UARTE_ODD_PARITY_ALLOWED 1 +#else +#define UARTE_ODD_PARITY_ALLOWED 0 +#endif + +/* + * RX timeout is divided into time slabs, this define tells how many divisions + * should be made. More divisions - higher timeout accuracy and processor usage. + */ +#define RX_TIMEOUT_DIV 5 + +/* Macro for converting numerical baudrate to register value. It is convenient + * to use this approach because for constant input it can calculate nrf setting + * at compile time. + */ +#define NRF_BAUDRATE(baudrate) ((baudrate) == 300 ? 0x00014000 :\ + (baudrate) == 600 ? 0x00027000 : \ + (baudrate) == 1200 ? NRF_UARTE_BAUDRATE_1200 : \ + (baudrate) == 2400 ? NRF_UARTE_BAUDRATE_2400 : \ + (baudrate) == 4800 ? NRF_UARTE_BAUDRATE_4800 : \ + (baudrate) == 9600 ? NRF_UARTE_BAUDRATE_9600 : \ + (baudrate) == 14400 ? NRF_UARTE_BAUDRATE_14400 : \ + (baudrate) == 19200 ? NRF_UARTE_BAUDRATE_19200 : \ + (baudrate) == 28800 ? NRF_UARTE_BAUDRATE_28800 : \ + (baudrate) == 31250 ? NRF_UARTE_BAUDRATE_31250 : \ + (baudrate) == 38400 ? NRF_UARTE_BAUDRATE_38400 : \ + (baudrate) == 56000 ? NRF_UARTE_BAUDRATE_56000 : \ + (baudrate) == 57600 ? NRF_UARTE_BAUDRATE_57600 : \ + (baudrate) == 76800 ? NRF_UARTE_BAUDRATE_76800 : \ + (baudrate) == 115200 ? NRF_UARTE_BAUDRATE_115200 : \ + (baudrate) == 230400 ? NRF_UARTE_BAUDRATE_230400 : \ + (baudrate) == 250000 ? NRF_UARTE_BAUDRATE_250000 : \ + (baudrate) == 460800 ? NRF_UARTE_BAUDRATE_460800 : \ + (baudrate) == 921600 ? NRF_UARTE_BAUDRATE_921600 : \ + (baudrate) == 1000000 ? NRF_UARTE_BAUDRATE_1000000 : 0) + +#define UARTE_DATA_FLAG_TRAMPOLINE BIT(0) +#define UARTE_DATA_FLAG_RX_ENABLED BIT(1) + +struct uarte_async_data { + uart_callback_t user_callback; + void *user_data; + + struct k_timer tx_timer; + struct k_timer rx_timer; + + k_timeout_t rx_timeout; + + /* Keeps the most recent error mask. */ + uint32_t err; + + uint8_t idle_cnt; +}; + +/* Device data structure */ +struct uarte_nrfx_data { + struct uart_async_to_irq_data *a2i_data; +#if CONFIG_UART_USE_RUNTIME_CONFIGURE + struct uart_config uart_config; +#endif + struct uarte_async_data *async; + atomic_t flags; + uint8_t rx_byte; +}; +BUILD_ASSERT(offsetof(struct uarte_nrfx_data, a2i_data) == 0); + +/* If set then pins are managed when going to low power mode. */ +#define UARTE_CFG_FLAG_GPIO_MGMT BIT(0) + +/* If set then receiver is not used. */ +#define UARTE_CFG_FLAG_NO_RX BIT(1) + +/* If set then instance is using interrupt driven API. */ +#define UARTE_CFG_FLAG_INTERRUPT_DRIVEN_API BIT(2) + +/** + * @brief Structure for UARTE configuration. + */ +struct uarte_nrfx_config { + const struct uart_async_to_irq_config *a2i_config; + nrfx_uarte_t nrfx_dev; + nrfx_uarte_config_t nrfx_config; + const struct pinctrl_dev_config *pcfg; + uint32_t flags; + + LOG_INSTANCE_PTR_DECLARE(log); +}; +BUILD_ASSERT(offsetof(struct uarte_nrfx_config, a2i_config) == 0); + +#define UARTE_ERROR_FROM_MASK(mask) \ + ((mask) & NRF_UARTE_ERROR_OVERRUN_MASK ? UART_ERROR_OVERRUN \ + : (mask) & NRF_UARTE_ERROR_PARITY_MASK ? UART_ERROR_PARITY \ + : (mask) & NRF_UARTE_ERROR_FRAMING_MASK ? UART_ERROR_FRAMING \ + : (mask) & NRF_UARTE_ERROR_BREAK_MASK ? UART_BREAK \ + : 0) + +/* Determine if the device has interrupt driven API enabled. */ +#define IS_INT_DRIVEN_API(dev) \ + (UARTE_ANY_INTERRUPT_DRIVEN && \ + (((const struct uarte_nrfx_config *)dev->config)->flags & \ + UARTE_CFG_FLAG_INTERRUPT_DRIVEN_API)) + +/* Determine if the device supports only polling API. */ +#define IS_POLLING_API(dev) \ + (!UARTE_INT_ASYNC || (((struct uarte_nrfx_data *)dev->data)->async == NULL)) + +/* Determine if the device supports asynchronous API. */ +#define IS_ASYNC_API(dev) (!IS_INT_DRIVEN_API(dev) && !IS_POLLING_API(dev)) + +static inline const nrfx_uarte_t *get_nrfx_dev(const struct device *dev) +{ + const struct uarte_nrfx_config *config = dev->config; + + return &config->nrfx_dev; +} + +static int callback_set(const struct device *dev, uart_callback_t callback, void *user_data) +{ + struct uarte_nrfx_data *data = dev->data; + + data->async->user_callback = callback; + data->async->user_data = user_data; + + return 0; +} + +#if UARTE_ANY_ASYNC +static int api_callback_set(const struct device *dev, uart_callback_t callback, void *user_data) +{ + if (!IS_ASYNC_API(dev)) { + return -ENOTSUP; + } + + return callback_set(dev, callback, user_data); +} +#endif + +static void on_tx_done(const struct device *dev, const nrfx_uarte_event_t *event) +{ + struct uarte_nrfx_data *data = dev->data; + struct uart_event evt = { + .type = (event->data.tx.flags & NRFX_UARTE_TX_DONE_ABORTED) ? + UART_TX_ABORTED : UART_TX_DONE, + .data.tx.buf = event->data.tx.p_buffer, + .data.tx.len = event->data.tx.length + }; + bool hwfc; + +#if CONFIG_UART_USE_RUNTIME_CONFIGURE + hwfc = data->uart_config.flow_ctrl == UART_CFG_FLOW_CTRL_RTS_CTS; +#else + const struct uarte_nrfx_config *config = dev->config; + + hwfc = config->nrfx_config.config.hwfc == NRF_UARTE_HWFC_ENABLED; +#endif + + if (hwfc) { + k_timer_stop(&data->async->tx_timer); + } + data->async->user_callback(dev, &evt, data->async->user_data); +} + +static void on_rx_done(const struct device *dev, const nrfx_uarte_event_t *event) +{ + struct uarte_nrfx_data *data = dev->data; + struct uart_event evt; + + if (event->data.rx.length) { + if (data->async->err) { + evt.type = UART_RX_STOPPED; + evt.data.rx_stop.reason = UARTE_ERROR_FROM_MASK(data->async->err); + evt.data.rx_stop.data.buf = event->data.rx.p_buffer; + evt.data.rx_stop.data.len = event->data.rx.length; + /* Keep error code for uart_err_check(). */ + if (!IS_INT_DRIVEN_API(dev)) { + data->async->err = 0; + } + } else { + evt.type = UART_RX_RDY, + evt.data.rx.buf = event->data.rx.p_buffer, + evt.data.rx.len = event->data.rx.length, + evt.data.rx.offset = 0; + } + data->async->user_callback(dev, &evt, data->async->user_data); + } + + evt.type = UART_RX_BUF_RELEASED; + evt.data.rx_buf.buf = event->data.rx.p_buffer; + + data->async->user_callback(dev, &evt, data->async->user_data); +} + +static void start_rx_timer(struct uarte_nrfx_data *data) +{ + struct uarte_async_data *adata = data->async; + + k_timer_start(&adata->rx_timer, adata->rx_timeout, K_NO_WAIT); +} + +static void on_rx_byte(const struct device *dev) +{ + struct uarte_nrfx_data *data = dev->data; + struct uarte_async_data *adata = data->async; + const nrfx_uarte_t *nrfx_dev = get_nrfx_dev(dev); + + nrfx_uarte_rxdrdy_disable(nrfx_dev); + adata->idle_cnt = RX_TIMEOUT_DIV; + start_rx_timer(data); +} + +static void on_rx_buf_req(const struct device *dev) +{ + struct uarte_nrfx_data *data = dev->data; + struct uarte_async_data *adata = data->async; + const nrfx_uarte_t *nrfx_dev = get_nrfx_dev(dev); + + struct uart_event evt = { + .type = UART_RX_BUF_REQUEST + }; + + /* If counter reached zero that indicates that timeout was reached and + * reception of one buffer was terminated to restart another transfer. + */ + if (!K_TIMEOUT_EQ(adata->rx_timeout, K_NO_WAIT)) { + /* Read and clear any pending new data information. */ + nrfx_uarte_rx_new_data_check(nrfx_dev); + nrfx_uarte_rxdrdy_enable(nrfx_dev); + } + data->async->user_callback(dev, &evt, data->async->user_data); +} + +static void on_rx_disabled(const struct device *dev, struct uarte_nrfx_data *data) +{ + struct uart_event evt = { + .type = UART_RX_DISABLED + }; + + atomic_and(&data->flags, ~UARTE_DATA_FLAG_RX_ENABLED); + k_timer_stop(&data->async->rx_timer); + + data->async->user_callback(dev, &evt, data->async->user_data); +} + +static void trigger_handler(const struct device *dev) +{ + struct uarte_nrfx_data *data = dev->data; + + if (UARTE_ANY_INTERRUPT_DRIVEN && + atomic_and(&data->flags, ~UARTE_DATA_FLAG_TRAMPOLINE) & + UARTE_DATA_FLAG_TRAMPOLINE) { + uart_async_to_irq_trampoline_cb(dev); + } +} + +static void evt_handler(nrfx_uarte_event_t const *event, void *context) +{ + const struct device *dev = context; + struct uarte_nrfx_data *data = dev->data; + + switch (event->type) { + case NRFX_UARTE_EVT_TX_DONE: + on_tx_done(dev, event); + break; + case NRFX_UARTE_EVT_RX_DONE: + on_rx_done(dev, event); + break; + case NRFX_UARTE_EVT_RX_BYTE: + on_rx_byte(dev); + break; + case NRFX_UARTE_EVT_ERROR: + data->async->err = event->data.error.error_mask; + break; + case NRFX_UARTE_EVT_RX_BUF_REQUEST: + on_rx_buf_req(dev); + break; + case NRFX_UARTE_EVT_RX_DISABLED: + on_rx_disabled(dev, data); + break; + case NRFX_UARTE_EVT_RX_BUF_TOO_LATE: + /* No support */ + break; + case NRFX_UARTE_EVT_TRIGGER: + trigger_handler(dev); + break; + default: + __ASSERT_NO_MSG(0); + } +} + +static int api_tx(const struct device *dev, const uint8_t *buf, size_t len, int32_t timeout) +{ + struct uarte_nrfx_data *data = dev->data; + const nrfx_uarte_t *nrfx_dev = get_nrfx_dev(dev); + nrfx_err_t err; + bool hwfc; + +#if CONFIG_UART_USE_RUNTIME_CONFIGURE + hwfc = data->uart_config.flow_ctrl == UART_CFG_FLOW_CTRL_RTS_CTS; +#else + const struct uarte_nrfx_config *config = dev->config; + + hwfc = config->nrfx_config.config.hwfc == NRF_UARTE_HWFC_ENABLED; +#endif + + err = nrfx_uarte_tx(nrfx_dev, buf, len, 0); + if (err != NRFX_SUCCESS) { + return (err == NRFX_ERROR_BUSY) ? -EBUSY : -EIO; + } + + if (hwfc && timeout != SYS_FOREVER_US) { + k_timer_start(&data->async->tx_timer, K_USEC(timeout), K_NO_WAIT); + } + + return 0; +} + +static int api_tx_abort(const struct device *dev) +{ + const nrfx_uarte_t *nrfx_dev = get_nrfx_dev(dev); + nrfx_err_t err; + + err = nrfx_uarte_tx_abort(nrfx_dev, false); + return (err == NRFX_SUCCESS) ? 0 : -EFAULT; +} + +static void tx_timeout_handler(struct k_timer *timer) +{ + const struct device *dev = k_timer_user_data_get(timer); + + (void)api_tx_abort(dev); +} + +static void rx_timeout_handler(struct k_timer *timer) +{ + const struct device *dev = (const struct device *)k_timer_user_data_get(timer); + struct uarte_nrfx_data *data = dev->data; + struct uarte_async_data *adata = data->async; + const nrfx_uarte_t *nrfx_dev = get_nrfx_dev(dev); + + if (nrfx_uarte_rx_new_data_check(nrfx_dev)) { + adata->idle_cnt = RX_TIMEOUT_DIV - 1; + } else { + adata->idle_cnt--; + if (adata->idle_cnt == 0) { + (void)nrfx_uarte_rx_abort(nrfx_dev, false, false); + return; + } + } + + start_rx_timer(data); +} + +/* Determine if RX FIFO content shall be kept when device is being disabled. + * When flow-control is used then we expect to keep RX FIFO content since HWFC + * enforces lossless communication. However, when HWFC is not used (by any instance + * then RX FIFO handling feature is disabled in the nrfx_uarte to save space. + * It is based on assumption that without HWFC it is expected that some data may + * be lost and there are means to prevent that (keeping receiver always opened by + * provided reception buffers on time). + */ +static inline uint32_t get_keep_fifo_content_flag(const struct device *dev) +{ +#if CONFIG_UART_USE_RUNTIME_CONFIGURE + struct uarte_nrfx_data *data = dev->data; + + if (data->uart_config.flow_ctrl == UART_CFG_FLOW_CTRL_RTS_CTS) { + return NRFX_UARTE_RX_ENABLE_KEEP_FIFO_CONTENT; + } +#else + const struct uarte_nrfx_config *config = dev->config; + + if (config->nrfx_config.config.hwfc == NRF_UARTE_HWFC_ENABLED) { + return NRFX_UARTE_RX_ENABLE_KEEP_FIFO_CONTENT; + } +#endif + + return 0; +} + +static int api_rx_enable(const struct device *dev, uint8_t *buf, size_t len, int32_t timeout) +{ + nrfx_err_t err; + const nrfx_uarte_t *nrfx_dev = get_nrfx_dev(dev); + const struct uarte_nrfx_config *cfg = dev->config; + struct uarte_nrfx_data *data = dev->data; + struct uarte_async_data *adata = data->async; + uint32_t flags = NRFX_UARTE_RX_ENABLE_CONT | + get_keep_fifo_content_flag(dev) | + (IS_ASYNC_API(dev) ? NRFX_UARTE_RX_ENABLE_STOP_ON_END : 0); + + if (cfg->flags & UARTE_CFG_FLAG_NO_RX) { + return -ENOTSUP; + } + + if (timeout != SYS_FOREVER_US) { + adata->idle_cnt = RX_TIMEOUT_DIV + 1; + adata->rx_timeout = K_USEC(timeout / RX_TIMEOUT_DIV); + } else { + adata->rx_timeout = K_NO_WAIT; + } + + err = nrfx_uarte_rx_buffer_set(nrfx_dev, buf, len); + if (err != NRFX_SUCCESS) { + return -EIO; + } + + err = nrfx_uarte_rx_enable(nrfx_dev, flags); + if (err != NRFX_SUCCESS) { + return (err == NRFX_ERROR_BUSY) ? -EBUSY : -EIO; + } + + atomic_or(&data->flags, UARTE_DATA_FLAG_RX_ENABLED); + + return 0; +} + +static int api_rx_buf_rsp(const struct device *dev, uint8_t *buf, size_t len) +{ + const nrfx_uarte_t *nrfx_dev = get_nrfx_dev(dev); + struct uarte_nrfx_data *data = dev->data; + nrfx_err_t err; + + if (!(data->flags & UARTE_DATA_FLAG_RX_ENABLED)) { + return -EACCES; + } + + err = nrfx_uarte_rx_buffer_set(nrfx_dev, buf, len); + switch (err) { + case NRFX_SUCCESS: + return 0; + case NRFX_ERROR_BUSY: + return -EBUSY; + default: + return -EIO; + } +} + +static int api_rx_disable(const struct device *dev) +{ + struct uarte_nrfx_data *data = dev->data; + + k_timer_stop(&data->async->rx_timer); + + return (nrfx_uarte_rx_abort(get_nrfx_dev(dev), true, false) == NRFX_SUCCESS) ? 0 : -EFAULT; +} + +static int api_poll_in(const struct device *dev, unsigned char *c) +{ + const struct uarte_nrfx_config *cfg = dev->config; + const nrfx_uarte_t *instance = &cfg->nrfx_dev; + nrfx_err_t err; + + if (IS_INT_DRIVEN_API(dev)) { + return uart_fifo_read(dev, c, 1) == 0 ? -1 : 0; + } + + if (IS_ASYNC_API(dev)) { + return -EBUSY; + } + + err = nrfx_uarte_rx_ready(instance, NULL); + if (err == NRFX_SUCCESS) { + uint8_t *rx_byte = cfg->nrfx_config.rx_cache.p_buffer; + + *c = *rx_byte; + err = nrfx_uarte_rx_buffer_set(instance, rx_byte, 1); + __ASSERT_NO_MSG(err == NRFX_SUCCESS); + + return 0; + } + + return -1; +} + +static void api_poll_out(const struct device *dev, unsigned char out_char) +{ + const nrfx_uarte_t *nrfx_dev = get_nrfx_dev(dev); + nrfx_err_t err; + + do { + /* When runtime PM is used we cannot use early return because then + * we have no information when UART is actually done with the + * transmission. It reduces UART performance however, polling in + * general is not power efficient and should be avoided in low + * power applications. + */ + err = nrfx_uarte_tx(nrfx_dev, &out_char, 1, NRFX_UARTE_TX_EARLY_RETURN); + __ASSERT(err != NRFX_ERROR_INVALID_ADDR, "Invalid address of the buffer"); + + if (err == NRFX_ERROR_BUSY && + IS_ENABLED(CONFIG_MULTITHREADING) && k_is_preempt_thread()) { + k_msleep(1); + } + Z_SPIN_DELAY(3); + } while (err == NRFX_ERROR_BUSY); +} + +#ifdef CONFIG_UART_USE_RUNTIME_CONFIGURE +/** + * @brief Set the baud rate + * + * This routine set the given baud rate for the UARTE. + * + * @param dev UARTE device struct + * @param baudrate Baud rate + * + * @return 0 on success or error code + */ +static int baudrate_set(NRF_UARTE_Type *uarte, uint32_t baudrate) +{ + nrf_uarte_baudrate_t nrf_baudrate = NRF_BAUDRATE(baudrate); + + if (baudrate == 0) { + return -EINVAL; + } + + nrfy_uarte_baudrate_set(uarte, nrf_baudrate); + + return 0; +} + +static int uarte_nrfx_configure(const struct device *dev, + const struct uart_config *cfg) +{ + const nrfx_uarte_t *nrfx_dev = get_nrfx_dev(dev); + struct uarte_nrfx_data *data = dev->data; + nrf_uarte_config_t uarte_cfg; + +#if defined(UARTE_CONFIG_STOP_Msk) + switch (cfg->stop_bits) { + case UART_CFG_STOP_BITS_1: + uarte_cfg.stop = NRF_UARTE_STOP_ONE; + break; + case UART_CFG_STOP_BITS_2: + uarte_cfg.stop = NRF_UARTE_STOP_TWO; + break; + default: + return -ENOTSUP; + } +#else + if (cfg->stop_bits != UART_CFG_STOP_BITS_1) { + return -ENOTSUP; + } +#endif + + if (cfg->data_bits != UART_CFG_DATA_BITS_8) { + return -ENOTSUP; + } + + switch (cfg->flow_ctrl) { + case UART_CFG_FLOW_CTRL_NONE: + uarte_cfg.hwfc = NRF_UARTE_HWFC_DISABLED; + break; + case UART_CFG_FLOW_CTRL_RTS_CTS: + uarte_cfg.hwfc = NRF_UARTE_HWFC_ENABLED; + break; + default: + return -ENOTSUP; + } + +#if defined(UARTE_CONFIG_PARITYTYPE_Msk) + uarte_cfg.paritytype = NRF_UARTE_PARITYTYPE_EVEN; +#endif + switch (cfg->parity) { + case UART_CFG_PARITY_NONE: + uarte_cfg.parity = NRF_UARTE_PARITY_EXCLUDED; + break; + case UART_CFG_PARITY_EVEN: + uarte_cfg.parity = NRF_UARTE_PARITY_INCLUDED; + break; +#if defined(UARTE_CONFIG_PARITYTYPE_Msk) + case UART_CFG_PARITY_ODD: + uarte_cfg.parity = NRF_UARTE_PARITY_INCLUDED; + uarte_cfg.paritytype = NRF_UARTE_PARITYTYPE_ODD; + break; +#endif + default: + return -ENOTSUP; + } + + if (baudrate_set(nrfx_dev->p_reg, cfg->baudrate) != 0) { + return -ENOTSUP; + } + + nrfy_uarte_configure(nrfx_dev->p_reg, &uarte_cfg); + + data->uart_config = *cfg; + + return 0; +} + +static int uarte_nrfx_config_get(const struct device *dev, + struct uart_config *cfg) +{ + struct uarte_nrfx_data *data = dev->data; + + *cfg = data->uart_config; + return 0; +} +#endif /* CONFIG_UART_USE_RUNTIME_CONFIGURE */ + +#if UARTE_ANY_POLLING || UARTE_ANY_INTERRUPT_DRIVEN +static int api_err_check(const struct device *dev) +{ + if (IS_POLLING_API(dev)) { + const struct uarte_nrfx_config *cfg = dev->config; + const nrfx_uarte_t *instance = &cfg->nrfx_dev; + uint32_t mask = nrfx_uarte_errorsrc_get(instance); + + return mask; + } + + struct uarte_nrfx_data *data = dev->data; + uint32_t rv = data->async->err; + + data->async->err = 0; + + return rv; +} +#endif + +static const struct uart_async_to_irq_async_api a2i_api = { + .callback_set = callback_set, + .tx = api_tx, + .tx_abort = api_tx_abort, + .rx_enable = api_rx_enable, + .rx_buf_rsp = api_rx_buf_rsp, + .rx_disable = api_rx_disable, +}; + +static const struct uart_driver_api uart_nrfx_uarte_driver_api = { + .poll_in = api_poll_in, + .poll_out = api_poll_out, +#ifdef CONFIG_UART_USE_RUNTIME_CONFIGURE + .configure = uarte_nrfx_configure, + .config_get = uarte_nrfx_config_get, +#endif /* CONFIG_UART_USE_RUNTIME_CONFIGURE */ +#if UARTE_ANY_POLLING || UARTE_ANY_INTERRUPT_DRIVEN + .err_check = api_err_check, +#endif +#if UARTE_ANY_ASYNC + .callback_set = api_callback_set, + .tx = api_tx, + .tx_abort = api_tx_abort, + .rx_enable = api_rx_enable, + .rx_buf_rsp = api_rx_buf_rsp, + .rx_disable = api_rx_disable, +#endif /* UARTE_ANY_ASYNC */ +#if UARTE_ANY_INTERRUPT_DRIVEN + UART_ASYNC_TO_IRQ_API_INIT(), +#endif /* UARTE_ANY_INTERRUPT_DRIVEN */ +}; + +static int endtx_stoptx_ppi_init(NRF_UARTE_Type *uarte) +{ + nrfx_err_t ret; + uint8_t ch; + + ret = nrfx_gppi_channel_alloc(&ch); + if (ret != NRFX_SUCCESS) { + LOG_ERR("Failed to allocate PPI Channel"); + return -EIO; + } + + nrfx_gppi_channel_endpoints_setup(ch, + nrfy_uarte_event_address_get(uarte, NRF_UARTE_EVENT_ENDTX), + nrfy_uarte_task_address_get(uarte, NRF_UARTE_TASK_STOPTX)); + nrfx_gppi_channels_enable(BIT(ch)); + + return 0; +} + +static int start_rx(const struct device *dev) +{ + const struct uarte_nrfx_config *cfg = dev->config; + + if (IS_INT_DRIVEN_API(dev)) { + return uart_async_to_irq_rx_enable(dev); + } + + __ASSERT_NO_MSG(IS_POLLING_API(dev)); + + nrfx_err_t err; + const nrfx_uarte_t *instance = &cfg->nrfx_dev; + uint8_t *rx_byte = cfg->nrfx_config.rx_cache.p_buffer; + + err = nrfx_uarte_rx_buffer_set(instance, rx_byte, 1); + __ASSERT_NO_MSG(err == NRFX_SUCCESS); + + err = nrfx_uarte_rx_enable(instance, 0); + __ASSERT_NO_MSG(err == NRFX_SUCCESS || err == NRFX_ERROR_BUSY); + + (void)err; + + return 0; +} + +static void async_to_irq_trampoline(const struct device *dev) +{ + const struct uarte_nrfx_config *cfg = dev->config; + struct uarte_nrfx_data *data = dev->data; + uint32_t prev = atomic_or(&data->flags, UARTE_DATA_FLAG_TRAMPOLINE); + + if (!(prev & UARTE_DATA_FLAG_TRAMPOLINE)) { + nrfx_uarte_int_trigger(&cfg->nrfx_dev); + } +} + +static int uarte_nrfx_init(const struct device *dev) +{ + int err; + nrfx_err_t nerr; + const nrfx_uarte_t *nrfx_dev = get_nrfx_dev(dev); + const struct uarte_nrfx_config *cfg = dev->config; + struct uarte_nrfx_data *data = dev->data; + + err = pinctrl_apply_state(cfg->pcfg, PINCTRL_STATE_DEFAULT); + if (err < 0) { + return err; + } + + if (UARTE_ENHANCED_POLL_OUT && cfg->nrfx_config.tx_stop_on_end) { + err = endtx_stoptx_ppi_init(nrfx_dev->p_reg); + if (err < 0) { + return err; + } + } + + if (UARTE_ANY_INTERRUPT_DRIVEN) { + if (cfg->a2i_config) { + err = uart_async_to_irq_init(data->a2i_data, cfg->a2i_config); + if (err < 0) { + return err; + } + } + } + + if (IS_ENABLED(UARTE_INT_ASYNC) && data->async) { + k_timer_init(&data->async->rx_timer, rx_timeout_handler, NULL); + k_timer_user_data_set(&data->async->rx_timer, (void *)dev); + k_timer_init(&data->async->tx_timer, tx_timeout_handler, NULL); + k_timer_user_data_set(&data->async->tx_timer, (void *)dev); + } + + nerr = nrfx_uarte_init(nrfx_dev, &cfg->nrfx_config, + IS_ENABLED(UARTE_INT_ASYNC) ? + (IS_POLLING_API(dev) ? NULL : evt_handler) : NULL); + if (nerr == NRFX_SUCCESS && !IS_ASYNC_API(dev) && !(cfg->flags & UARTE_CFG_FLAG_NO_RX)) { + err = start_rx(dev); + } + + switch (nerr) { + case NRFX_ERROR_INVALID_STATE: + return -EBUSY; + case NRFX_ERROR_BUSY: + return -EACCES; + case NRFX_ERROR_INVALID_PARAM: + return -EINVAL; + default: + return 0; + } +} + +#ifdef CONFIG_PM_DEVICE +static int stop_rx(const struct device *dev) +{ + const struct uarte_nrfx_config *cfg = dev->config; + + if (IS_INT_DRIVEN_API(dev)) { + return uart_async_to_irq_rx_disable(dev); + } + + __ASSERT_NO_MSG(IS_POLLING_API(dev)); + nrfx_err_t err; + const nrfx_uarte_t *instance = &cfg->nrfx_dev; + + err = nrfx_uarte_rx_abort(instance, true, true); + __ASSERT_NO_MSG(err == NRFX_SUCCESS); + + return 0; +} + +static int uarte_nrfx_pm_action(const struct device *dev, + enum pm_device_action action) +{ + const struct uarte_nrfx_config *cfg = dev->config; + int ret; + + switch (action) { + case PM_DEVICE_ACTION_RESUME: + if (cfg->flags & UARTE_CFG_FLAG_GPIO_MGMT) { + ret = pinctrl_apply_state(cfg->pcfg, PINCTRL_STATE_DEFAULT); + if (ret < 0) { + return ret; + } + } + if (!IS_ASYNC_API(dev) && !(cfg->flags & UARTE_CFG_FLAG_NO_RX)) { + return start_rx(dev); + } + + break; + case PM_DEVICE_ACTION_SUSPEND: + if (!IS_ASYNC_API(dev) && !(cfg->flags & UARTE_CFG_FLAG_NO_RX)) { + stop_rx(dev); + } + + if (cfg->flags & UARTE_CFG_FLAG_GPIO_MGMT) { + ret = pinctrl_apply_state(cfg->pcfg, PINCTRL_STATE_SLEEP); + if (ret < 0) { + return ret; + } + } + + break; + default: + return -ENOTSUP; + } + + return 0; +} +#endif + +#if defined(UARTE_CONFIG_STOP_Msk) +#define UARTE_HAS_STOP_CONFIG 1 +#endif + +#define UARTE(idx) DT_NODELABEL(uart##idx) +#define UARTE_HAS_PROP(idx, prop) DT_NODE_HAS_PROP(UARTE(idx), prop) +#define UARTE_PROP(idx, prop) DT_PROP(UARTE(idx), prop) + +/* Macro returning initial log level. Logs are off for UART used for console. */ +#define GET_INIT_LOG_LEVEL(idx) \ + COND_CODE_1(DT_HAS_CHOSEN(zephyr_console), \ + (DT_SAME_NODE(UARTE(idx), \ + DT_CHOSEN(zephyr_console)) ? \ + LOG_LEVEL_NONE : CONFIG_UART_LOG_LEVEL), \ + (CONFIG_UART_LOG_LEVEL)) + +/* Macro puts buffers in dedicated section if device tree property is set. */ +#define UARTE_MEMORY_SECTION(idx) \ + COND_CODE_1(UARTE_HAS_PROP(idx, memory_regions), \ + (__attribute__((__section__(LINKER_DT_NODE_REGION_NAME( \ + DT_PHANDLE(UARTE(idx), memory_regions)))))), \ + ()) + +#define UART_NRF_UARTE_DEVICE(idx) \ + LOG_INSTANCE_REGISTER(LOG_MODULE_NAME, idx, GET_INIT_LOG_LEVEL(idx)); \ + static uint8_t uarte##idx##_tx_cache[CONFIG_UART_##idx##_TX_CACHE_SIZE] \ + UARTE_MEMORY_SECTION(idx) __aligned(4); \ + static uint8_t uarte##idx##_rx_cache[CONFIG_UART_##idx##_RX_CACHE_SIZE] \ + UARTE_MEMORY_SECTION(idx) __aligned(4); \ + static nrfx_uarte_rx_cache_t uarte##idx##_rx_cache_scratch; \ + IF_ENABLED(CONFIG_UART_##idx##_INTERRUPT_DRIVEN, \ + (static uint8_t a2i_rx_buf##idx[CONFIG_UART_##idx##_A2I_RX_SIZE];)) \ + PINCTRL_DT_DEFINE(UARTE(idx)); \ + static const struct uart_async_to_irq_config uarte_a2i_config_##idx = \ + UART_ASYNC_TO_IRQ_API_CONFIG_INITIALIZER(&a2i_api, \ + async_to_irq_trampoline, \ + UARTE_PROP(idx, current_speed), \ + uarte##idx##_tx_cache, \ + /* nrfx_uarte driver is using the last byte in the */ \ + /* cache buffer for keeping a byte that is currently*/\ + /* polled out so it cannot be used as a cache buffer*/\ + /* by the adaptation layer. */ \ + sizeof(uarte##idx##_tx_cache) - 1, \ + COND_CODE_1(CONFIG_UART_##idx##_INTERRUPT_DRIVEN, \ + (a2i_rx_buf##idx), (NULL)), \ + COND_CODE_1(CONFIG_UART_##idx##_INTERRUPT_DRIVEN, \ + (sizeof(a2i_rx_buf##idx)), (0)), \ + CONFIG_UART_##idx##_A2I_RX_BUF_COUNT, \ + LOG_INSTANCE_PTR(LOG_MODULE_NAME, idx)); \ + static const struct uarte_nrfx_config uarte_config_##idx = { \ + .a2i_config = IS_ENABLED(CONFIG_UART_##idx## _INTERRUPT_DRIVEN) ? \ + &uarte_a2i_config_##idx : NULL, \ + .nrfx_dev = NRFX_UARTE_INSTANCE(idx), \ + .nrfx_config = { \ + .p_context = (void *)DEVICE_DT_GET(UARTE(idx)), \ + .tx_cache = { \ + .p_buffer = uarte##idx##_tx_cache, \ + .length = CONFIG_UART_##idx##_TX_CACHE_SIZE \ + }, \ + .rx_cache = { \ + .p_buffer = uarte##idx##_rx_cache, \ + .length = CONFIG_UART_##idx##_RX_CACHE_SIZE \ + }, \ + .p_rx_cache_scratch = &uarte##idx##_rx_cache_scratch, \ + .baudrate = NRF_BAUDRATE(UARTE_PROP(idx, current_speed)), \ + .interrupt_priority = DT_IRQ(UARTE(idx), priority), \ + .config = { \ + .hwfc = (UARTE_PROP(idx, hw_flow_control) == \ + UART_CFG_FLOW_CTRL_RTS_CTS) ? \ + NRF_UARTE_HWFC_ENABLED : NRF_UARTE_HWFC_DISABLED, \ + .parity = IS_ENABLED(CONFIG_UART_##idx##_NRF_PARITY_BIT) ? \ + NRF_UARTE_PARITY_INCLUDED : NRF_UARTE_PARITY_EXCLUDED, \ + IF_ENABLED(UARTE_HAS_STOP_CONFIG, (.stop = NRF_UARTE_STOP_ONE,))\ + IF_ENABLED(UARTE_ODD_PARITY_ALLOWED, \ + (.paritytype = NRF_UARTE_PARITYTYPE_EVEN,)) \ + }, \ + .tx_stop_on_end = IS_ENABLED(CONFIG_UART_##idx##_ENHANCED_POLL_OUT), \ + .skip_psel_cfg = true, \ + .skip_gpio_cfg = true, \ + }, \ + .pcfg = PINCTRL_DT_DEV_CONFIG_GET(UARTE(idx)), \ + .flags = (UARTE_PROP(idx, disable_rx) ? UARTE_CFG_FLAG_NO_RX : 0) | \ + (IS_ENABLED(CONFIG_UART_##idx##_GPIO_MANAGEMENT) ? \ + UARTE_CFG_FLAG_GPIO_MGMT : 0) | \ + (IS_ENABLED(CONFIG_UART_##idx##_INTERRUPT_DRIVEN) ? \ + UARTE_CFG_FLAG_INTERRUPT_DRIVEN_API : 0), \ + LOG_INSTANCE_PTR_INIT(log, LOG_MODULE_NAME, idx) \ + }; \ + static struct uart_async_to_irq_data uarte_a2i_data_##idx; \ + static struct uarte_async_data uarte_async_##idx; \ + static struct uarte_nrfx_data uarte_data_##idx = { \ + .a2i_data = IS_ENABLED(CONFIG_UART_##idx##_INTERRUPT_DRIVEN) ? \ + &uarte_a2i_data_##idx : NULL, \ + IF_ENABLED(CONFIG_UART_USE_RUNTIME_CONFIGURE, \ + (.uart_config = { \ + .baudrate = UARTE_PROP(idx, current_speed), \ + .parity = IS_ENABLED(CONFIG_UART_##idx##_NRF_PARITY_BIT) ? \ + UART_CFG_PARITY_EVEN : UART_CFG_PARITY_NONE, \ + .stop_bits = UART_CFG_STOP_BITS_1, \ + .data_bits = UART_CFG_DATA_BITS_8, \ + .flow_ctrl = UARTE_PROP(idx, hw_flow_control) ? \ + UART_CFG_FLOW_CTRL_RTS_CTS : UART_CFG_FLOW_CTRL_NONE, \ + },)) \ + .async = (IS_ENABLED(CONFIG_UART_##idx##_INTERRUPT_DRIVEN) || \ + IS_ENABLED(CONFIG_UART_##idx##_ASYNC)) ? &uarte_async_##idx : NULL \ + }; \ + static int uarte_init_##idx(const struct device *dev) \ + { \ + COND_CODE_1(INSTANCE_POLLING(_, /*empty*/, idx, _), (), \ + ( \ + IRQ_CONNECT(DT_IRQN(UARTE(idx)), DT_IRQ(UARTE(idx), priority), \ + nrfx_isr, nrfx_uarte_##idx##_irq_handler, 0); \ + irq_enable(DT_IRQN(UARTE(idx))); \ + ) \ + ) \ + return uarte_nrfx_init(dev); \ + } \ + PM_DEVICE_DT_DEFINE(UARTE(idx), uarte_nrfx_pm_action); \ + DEVICE_DT_DEFINE(UARTE(idx), \ + uarte_init_##idx, \ + PM_DEVICE_DT_GET(UARTE(idx)), \ + &uarte_data_##idx, \ + &uarte_config_##idx, \ + PRE_KERNEL_1, \ + CONFIG_KERNEL_INIT_PRIORITY_DEVICE, \ + &uart_nrfx_uarte_driver_api) + +/* Macro creates device instance if it is enabled in devicetree. */ +#define UARTE_DEVICE(periph, prefix, id, _) \ + IF_ENABLED(CONFIG_HAS_HW_NRF_UARTE##prefix##id, (UART_NRF_UARTE_DEVICE(prefix##id);)) + +/* Macro iterates over nrfx_uarte instances enabled in the nrfx_config.h. */ +NRFX_FOREACH_ENABLED(UARTE, UARTE_DEVICE, (), (), _) From b8c9aad728768dfc28551b5479865eff646436af Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Krzysztof=20Chru=C5=9Bci=C5=84ski?= Date: Mon, 13 Nov 2023 09:47:24 +0100 Subject: [PATCH 2473/3723] tests: drivers: uart: uart_mix_fifo_poll: Align the the new nrfx driver MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Align test configurations to the new uart driver based on nrfx_uarte. Signed-off-by: Krzysztof Chruściński --- .../uart/uart_mix_fifo_poll/testcase.yaml | 46 +++++++++---------- 1 file changed, 21 insertions(+), 25 deletions(-) diff --git a/tests/drivers/uart/uart_mix_fifo_poll/testcase.yaml b/tests/drivers/uart/uart_mix_fifo_poll/testcase.yaml index 1d1f97fbcc7..6652d45620a 100644 --- a/tests/drivers/uart/uart_mix_fifo_poll/testcase.yaml +++ b/tests/drivers/uart/uart_mix_fifo_poll/testcase.yaml @@ -19,22 +19,22 @@ tests: - CONFIG_UART_INTERRUPT_DRIVEN=n - CONFIG_UART_ASYNC_API=n - CONFIG_UART_0_ENHANCED_POLL_OUT=n + tags: bsim_skip_CI drivers.uart.uart_mix_poll_fifo: extra_configs: - CONFIG_UART_INTERRUPT_DRIVEN=y - CONFIG_UART_0_INTERRUPT_DRIVEN=y - CONFIG_UART_0_ENHANCED_POLL_OUT=n + tags: bsim_skip_CI drivers.uart.uart_mix_poll_async_api: extra_configs: - CONFIG_UART_ASYNC_API=y - CONFIG_UART_0_INTERRUPT_DRIVEN=n - CONFIG_UART_0_ASYNC=y - - CONFIG_UART_0_NRF_HW_ASYNC=y - - CONFIG_UART_0_NRF_HW_ASYNC_TIMER=2 - - CONFIG_NRFX_TIMER2=y - CONFIG_UART_0_ENHANCED_POLL_OUT=n + tags: bsim_skip_CI drivers.uart.uart_mix_poll_async_api_const: extra_args: TEST_CONST_BUFFER=1 @@ -42,25 +42,10 @@ tests: - CONFIG_UART_ASYNC_API=y - CONFIG_UART_0_INTERRUPT_DRIVEN=n - CONFIG_UART_0_ASYNC=y - - CONFIG_UART_0_NRF_HW_ASYNC=y - - CONFIG_UART_0_NRF_HW_ASYNC_TIMER=2 - - CONFIG_NRFX_TIMER2=y - CONFIG_UART_0_ENHANCED_POLL_OUT=n - - CONFIG_UART_ASYNC_TX_CACHE_SIZE=2 + - CONFIG_UART_0_TX_CACHE_SIZE=2 tags: bsim_skip_CI # We skip a few tests to save CI time, as they give little extra coverage - drivers.uart.uart_mix_poll_async_api_low_power: - extra_configs: - - CONFIG_UART_ASYNC_API=y - - CONFIG_UART_0_INTERRUPT_DRIVEN=n - - CONFIG_UART_0_ASYNC=y - - CONFIG_UART_0_NRF_HW_ASYNC=y - - CONFIG_UART_0_NRF_ASYNC_LOW_POWER=y - - CONFIG_UART_0_NRF_HW_ASYNC_TIMER=2 - - CONFIG_NRFX_TIMER2=y - - CONFIG_UART_0_ENHANCED_POLL_OUT=n - tags: bsim_skip_CI - drivers.uart.uart_mix_poll_with_ppi: extra_configs: - CONFIG_UART_INTERRUPT_DRIVEN=n @@ -80,19 +65,30 @@ tests: - CONFIG_UART_ASYNC_API=y - CONFIG_UART_0_INTERRUPT_DRIVEN=n - CONFIG_UART_0_ASYNC=y - - CONFIG_UART_0_NRF_HW_ASYNC=y - - CONFIG_UART_0_NRF_HW_ASYNC_TIMER=2 - - CONFIG_NRFX_TIMER2=y - CONFIG_UART_0_ENHANCED_POLL_OUT=y tags: bsim_skip_CI - drivers.uart.uart_mix_poll_async_api_with_ppi_low_power: + drivers.uart.legacy.uart_mix_poll: + extra_configs: + - CONFIG_UART_INTERRUPT_DRIVEN=n + - CONFIG_UART_ASYNC_API=n + - CONFIG_UART_0_ENHANCED_POLL_OUT=n + - CONFIG_UART_NRFX_UARTE_LEGACY_SHIM=y + + drivers.uart.legacy.uart_mix_poll_fifo: + extra_configs: + - CONFIG_UART_INTERRUPT_DRIVEN=y + - CONFIG_UART_0_INTERRUPT_DRIVEN=y + - CONFIG_UART_0_ENHANCED_POLL_OUT=n + - CONFIG_UART_NRFX_UARTE_LEGACY_SHIM=y + + drivers.uart.legacy.uart_mix_poll_async_api: extra_configs: - CONFIG_UART_ASYNC_API=y - CONFIG_UART_0_INTERRUPT_DRIVEN=n - CONFIG_UART_0_ASYNC=y + - CONFIG_UART_0_ENHANCED_POLL_OUT=n - CONFIG_UART_0_NRF_HW_ASYNC=y - - CONFIG_UART_0_NRF_ASYNC_LOW_POWER=y - CONFIG_UART_0_NRF_HW_ASYNC_TIMER=2 - CONFIG_NRFX_TIMER2=y - - CONFIG_UART_0_ENHANCED_POLL_OUT=y + - CONFIG_UART_NRFX_UARTE_LEGACY_SHIM=y From e47bdb2555c8c63443a2baf375571439ed9255a9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Krzysztof=20Chru=C5=9Bci=C5=84ski?= Date: Wed, 17 Jan 2024 12:24:05 +0100 Subject: [PATCH 2474/3723] tests: drivers: uart: async_api: Add configuration for legacy nrf driver MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Add configuration which tests legacy nrf uart driver. Prevent tests on nrf52_bsim of the new driver (it is requiring adjustments for the simulation). It will be fixed by another patch. Signed-off-by: Krzysztof Chruściński --- tests/drivers/uart/uart_async_api/testcase.yaml | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/tests/drivers/uart/uart_async_api/testcase.yaml b/tests/drivers/uart/uart_async_api/testcase.yaml index b2b1f80f316..9e3e3913d1d 100644 --- a/tests/drivers/uart/uart_async_api/testcase.yaml +++ b/tests/drivers/uart/uart_async_api/testcase.yaml @@ -13,6 +13,7 @@ tests: harness_config: fixture: gpio_loopback depends_on: gpio + tags: bsim_skip_CI drivers.uart.wide: filter: CONFIG_SERIAL_SUPPORT_ASYNC and not CONFIG_UART_MCUX_LPUART harness: ztest @@ -25,6 +26,15 @@ tests: platform_allow: nucleo_h743zi integration_platforms: - nucleo_h743zi + drivers.uart.async_api.nrf_uarte_legacy: + platform_allow: nrf52840dk_nrf52840 nrf52_bsim + filter: CONFIG_SERIAL_SUPPORT_ASYNC + harness: ztest + harness_config: + fixture: gpio_loopback + depends_on: gpio + extra_configs: + - CONFIG_UART_NRFX_UARTE_LEGACY_SHIM=y drivers.uart.async_api.nrf_uart: filter: CONFIG_SERIAL_SUPPORT_ASYNC harness: ztest From 2ebf83176c2bd7012a49f1d9b5b6247f36a20efe Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Krzysztof=20Chru=C5=9Bci=C5=84ski?= Date: Wed, 17 Jan 2024 12:25:02 +0100 Subject: [PATCH 2475/3723] tests: drivers: uart: uart_pm: Use legacy nrf driver MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit New nrf uart shim requires addiotional work around PM. Use legacy version for those tests until it is fixed. Signed-off-by: Krzysztof Chruściński --- tests/drivers/uart/uart_pm/testcase.yaml | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/tests/drivers/uart/uart_pm/testcase.yaml b/tests/drivers/uart/uart_pm/testcase.yaml index c8cb96fae2c..5417be597e0 100644 --- a/tests/drivers/uart/uart_pm/testcase.yaml +++ b/tests/drivers/uart/uart_pm/testcase.yaml @@ -15,12 +15,14 @@ tests: - CONFIG_UART_INTERRUPT_DRIVEN=n - CONFIG_UART_ASYNC_API=n - CONFIG_UART_0_ENHANCED_POLL_OUT=n + - CONFIG_UART_NRFX_UARTE_LEGACY_SHIM=y drivers.uart.pm.no_rxpin: extra_configs: - CONFIG_UART_INTERRUPT_DRIVEN=n - CONFIG_UART_ASYNC_API=n - CONFIG_UART_0_ENHANCED_POLL_OUT=n + - CONFIG_UART_NRFX_UARTE_LEGACY_SHIM=y extra_args: DTC_OVERLAY_FILE="boards/nrf52840dk_nrf52840.overlay;nrf_rx_disable.overlay" drivers.uart.pm.enhanced_poll: @@ -28,6 +30,7 @@ tests: - CONFIG_UART_INTERRUPT_DRIVEN=n - CONFIG_UART_ASYNC_API=n - CONFIG_UART_0_ENHANCED_POLL_OUT=y + - CONFIG_UART_NRFX_UARTE_LEGACY_SHIM=y drivers.uart.pm.int_driven: extra_configs: @@ -35,6 +38,7 @@ tests: - CONFIG_UART_0_INTERRUPT_DRIVEN=y - CONFIG_UART_ASYNC_API=n - CONFIG_UART_0_ENHANCED_POLL_OUT=n + - CONFIG_UART_NRFX_UARTE_LEGACY_SHIM=y drivers.uart.pm.int_driven.enhanced_poll: extra_configs: @@ -42,6 +46,7 @@ tests: - CONFIG_UART_0_INTERRUPT_DRIVEN=y - CONFIG_UART_ASYNC_API=n - CONFIG_UART_0_ENHANCED_POLL_OUT=y + - CONFIG_UART_NRFX_UARTE_LEGACY_SHIM=y drivers.uart.pm.async: extra_configs: @@ -52,6 +57,7 @@ tests: - CONFIG_UART_0_NRF_HW_ASYNC_TIMER=2 - CONFIG_NRFX_TIMER2=y - CONFIG_UART_0_ENHANCED_POLL_OUT=n + - CONFIG_UART_NRFX_UARTE_LEGACY_SHIM=y drivers.uart.pm.async.enhanced_poll: extra_configs: @@ -62,3 +68,4 @@ tests: - CONFIG_UART_0_NRF_HW_ASYNC_TIMER=2 - CONFIG_NRFX_TIMER2=y - CONFIG_UART_0_ENHANCED_POLL_OUT=y + - CONFIG_UART_NRFX_UARTE_LEGACY_SHIM=y From e2dccab4d5103fa6ac9745c610697666e244c708 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Krzysztof=20Chru=C5=9Bci=C5=84ski?= Date: Wed, 17 Jan 2024 12:56:28 +0100 Subject: [PATCH 2476/3723] boards: posix: nrf_bsim: Use legacy UART shim MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit New UART shim must be adapted to work in the simulated environment. Use legacy version until it is fixed. Signed-off-by: Krzysztof Chruściński --- boards/posix/nrf_bsim/Kconfig.defconfig | 3 +++ 1 file changed, 3 insertions(+) diff --git a/boards/posix/nrf_bsim/Kconfig.defconfig b/boards/posix/nrf_bsim/Kconfig.defconfig index d4e48ada7ad..99ad7af5ac3 100644 --- a/boards/posix/nrf_bsim/Kconfig.defconfig +++ b/boards/posix/nrf_bsim/Kconfig.defconfig @@ -91,4 +91,7 @@ config POSIX_ARCH_CONSOLE endif # CONSOLE +config UART_NRFX_UARTE_LEGACY_SHIM + default y + endif # SOC_SERIES_BSIM_NRFXX From 1c9be802bc090173fb308e1aaa76e3565cff9019 Mon Sep 17 00:00:00 2001 From: Fabio Baltieri Date: Thu, 18 Jan 2024 10:33:18 +0000 Subject: [PATCH 2477/3723] usbc: fix shadowed declaration build error Fixes: /__w/zephyr/zephyr/subsys/usb/usb_c/usbc_tc_src_states.c:260:21: error: declaration of 'ret' shadows a previous local [-Werror=shadow] Signed-off-by: Fabio Baltieri --- subsys/usb/usb_c/usbc_tc_src_states.c | 4 ---- 1 file changed, 4 deletions(-) diff --git a/subsys/usb/usb_c/usbc_tc_src_states.c b/subsys/usb/usb_c/usbc_tc_src_states.c index f24ba9fe8a0..b90f96f9624 100644 --- a/subsys/usb/usb_c/usbc_tc_src_states.c +++ b/subsys/usb/usb_c/usbc_tc_src_states.c @@ -257,8 +257,6 @@ void tc_attached_src_entry(void *obj) /* Enable the VBUS sourcing by the PPC */ if (data->ppc != NULL) { - int ret; - ret = ppc_set_src_ctrl(data->ppc, true); if (ret < 0 && ret != -ENOSYS) { LOG_ERR("Couldn't disable PPC source"); @@ -317,8 +315,6 @@ void tc_attached_src_exit(void *obj) /* Disable the VBUS sourcing by the PPC */ if (data->ppc != NULL) { - int ret; - ret = ppc_set_src_ctrl(data->ppc, false); if (ret < 0 && ret != -ENOSYS) { LOG_ERR("Couldn't disable PPC source"); From 979e7a6c5653d3b7e0d0e6c6207b03dfe6f80375 Mon Sep 17 00:00:00 2001 From: Fabio Baltieri Date: Thu, 18 Jan 2024 11:21:19 +0000 Subject: [PATCH 2478/3723] github: footprint: set ZEPHYR_SDK_INSTALL_DIR after the rebase The ZEPHYR_SDK_INSTALL_DIR currently tries to read the SDK_VERSION at the PR base ref, but this has only been introduced recently. Move the ZEPHYR_SDK_INSTALL_DIR settings down as part of the build step after the rebase so the file will always be found from now, even on old PRs. Signed-off-by: Fabio Baltieri --- .github/workflows/footprint.yml | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/.github/workflows/footprint.yml b/.github/workflows/footprint.yml index bf8e5e32059..89b57239bbe 100644 --- a/.github/workflows/footprint.yml +++ b/.github/workflows/footprint.yml @@ -36,10 +36,6 @@ jobs: ref: ${{ github.event.pull_request.head.sha }} fetch-depth: 0 - - name: Environment Setup - run: | - echo "ZEPHYR_SDK_INSTALL_DIR=/opt/toolchains/zephyr-sdk-$( cat SDK_VERSION )" >> $GITHUB_ENV - - name: west setup run: | west init -l . || true @@ -56,6 +52,9 @@ jobs: git remote -v git rebase origin/${BASE_REF} git checkout -b this_pr + + export ZEPHYR_SDK_INSTALL_DIR=/opt/toolchains/zephyr-sdk-$( cat SDK_VERSION ) + west update west build -b frdm_k64f tests/benchmarks/footprints -t ram_report cp build/ram.json ram2.json From 18deb582efc9de666c5648ffe7e6068ea319dbf9 Mon Sep 17 00:00:00 2001 From: Filip Kokosinski Date: Wed, 17 Jan 2024 12:56:01 +0100 Subject: [PATCH 2479/3723] boards/riscv: use the same board name convention for ITE platforms This commit unifies the board name convention used by ITE RISC-V platforms. Signed-off-by: Filip Kokosinski --- boards/riscv/it8xxx2_evb/it8xxx2_evb.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/boards/riscv/it8xxx2_evb/it8xxx2_evb.yaml b/boards/riscv/it8xxx2_evb/it8xxx2_evb.yaml index 3374ea96c32..308e2c73c14 100644 --- a/boards/riscv/it8xxx2_evb/it8xxx2_evb.yaml +++ b/boards/riscv/it8xxx2_evb/it8xxx2_evb.yaml @@ -1,5 +1,5 @@ identifier: it8xxx2_evb -name: it8xxx2_evb +name: ITE IT8XXX2 EVB type: mcu arch: riscv32 toolchain: From 37352d3d2993f02b26b027b1a3bde11ab2254319 Mon Sep 17 00:00:00 2001 From: Ben Wolsieffer Date: Sat, 30 Dec 2023 15:45:44 -0500 Subject: [PATCH 2480/3723] soc: nrf53: fix building anomaly 168 workaround With GCC 12.3 and binutils 2.40, the build fails with: <...>/zephyr/arch/arm/core/cortex_m/cpu_idle.S: Assembler messages: <...>/zephyr/arch/arm/core/cortex_m/cpu_idle.S:51: Error: junk at end of line, first unrecognized character is `n' <...>/zephyr/arch/arm/core/cortex_m/cpu_idle.S:133: Info: macro invoked from here Because the SOC_ON_EXIT_CPU_IDLE macro puts all the statements on a single line, there must be a semicolon after .rept Signed-off-by: Ben Wolsieffer --- soc/arm/nordic_nrf/nrf53/soc_cpu_idle.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/soc/arm/nordic_nrf/nrf53/soc_cpu_idle.h b/soc/arm/nordic_nrf/nrf53/soc_cpu_idle.h index dcb0c73d068..c02c9451419 100644 --- a/soc/arm/nordic_nrf/nrf53/soc_cpu_idle.h +++ b/soc/arm/nordic_nrf/nrf53/soc_cpu_idle.h @@ -13,12 +13,12 @@ #if defined(CONFIG_SOC_NRF53_ANOMALY_168_WORKAROUND_FOR_EXECUTION_FROM_RAM) #define SOC_ON_EXIT_CPU_IDLE \ - .rept 26 \ + .rept 26; \ nop; \ .endr #elif defined(CONFIG_SOC_NRF53_ANOMALY_168_WORKAROUND) #define SOC_ON_EXIT_CPU_IDLE \ - .rept 8 \ + .rept 8; \ nop; \ .endr #endif From 1d128f13b6b3f4e089d4151a36daf2b6ad71bc15 Mon Sep 17 00:00:00 2001 From: Gerard Marull-Paretas Date: Thu, 18 Jan 2024 12:52:31 +0100 Subject: [PATCH 2481/3723] samples: modules: tflite-micro: remove incorrect check sensor cannot be null because it is initialized with DEVICE_DT_GET_ONE, which always resolves to a device. The deleted check triggered a compiler warning ("warning: the address of '__device_dts_ord_23' will never be NULL"). Signed-off-by: Gerard Marull-Paretas --- .../magic_wand/src/accelerometer_handler.cpp | 9 ++------- 1 file changed, 2 insertions(+), 7 deletions(-) diff --git a/samples/modules/tflite-micro/magic_wand/src/accelerometer_handler.cpp b/samples/modules/tflite-micro/magic_wand/src/accelerometer_handler.cpp index 0491f7a7962..13733aaa0c6 100644 --- a/samples/modules/tflite-micro/magic_wand/src/accelerometer_handler.cpp +++ b/samples/modules/tflite-micro/magic_wand/src/accelerometer_handler.cpp @@ -40,13 +40,8 @@ TfLiteStatus SetupAccelerometer() return kTfLiteApplicationError; } - if (sensor == NULL) { - MicroPrintf("Failed to get accelerometer, name: %s\n", - sensor->name); - } else { - MicroPrintf("Got accelerometer, name: %s\n", - sensor->name); - } + MicroPrintf("Got accelerometer, name: %s\n", sensor->name); + return kTfLiteOk; } From ba11dc8065e52538ed973173db4e36f34f69227e Mon Sep 17 00:00:00 2001 From: Tim Lin Date: Tue, 26 Dec 2023 17:09:54 +0800 Subject: [PATCH 2482/3723] ITE: drivers/i2c: Add the property of I2C data hold time Add a property to adjust the I2C data hold time which will pass the SI test. Signed-off-by: Tim Lin --- drivers/i2c/i2c_ite_enhance.c | 7 +++++++ dts/bindings/i2c/ite,enhance-i2c.yaml | 17 +++++++++++++++++ 2 files changed, 24 insertions(+) diff --git a/drivers/i2c/i2c_ite_enhance.c b/drivers/i2c/i2c_ite_enhance.c index c1fbf6cc86c..cf8646689c0 100644 --- a/drivers/i2c/i2c_ite_enhance.c +++ b/drivers/i2c/i2c_ite_enhance.c @@ -71,6 +71,7 @@ struct i2c_enhance_config { /* I2C alternate configuration */ const struct pinctrl_dev_config *pcfg; uint8_t prescale_scl_low; + uint8_t data_hold_time; uint32_t clock_gate_offset; bool target_enable; bool target_pio_mode; @@ -1145,6 +1146,7 @@ static int i2c_enhance_init(const struct device *dev) struct i2c_enhance_data *data = dev->data; const struct i2c_enhance_config *config = dev->config; uint8_t *base = config->base; + uint8_t data_hold_time = config->data_hold_time; uint32_t bitrate_cfg; int error, status; @@ -1196,6 +1198,10 @@ static int i2c_enhance_init(const struct device *dev) (IT8XXX2_SMB_SMB45CHS &= ~GENMASK(6, 4)); } + /* Set I2C data hold time. */ + IT8XXX2_I2C_DHTR(base) = (IT8XXX2_I2C_DHTR(base) & ~GENMASK(2, 0)) | + (data_hold_time - 3); + /* Set clock frequency for I2C ports */ if (config->bitrate == I2C_BITRATE_STANDARD || config->bitrate == I2C_BITRATE_FAST || @@ -1453,6 +1459,7 @@ BUILD_ASSERT(IS_ENABLED(CONFIG_I2C_TARGET_BUFFER_MODE), .scl_gpios = GPIO_DT_SPEC_INST_GET(inst, scl_gpios), \ .sda_gpios = GPIO_DT_SPEC_INST_GET(inst, sda_gpios), \ .prescale_scl_low = DT_INST_PROP_OR(inst, prescale_scl_low, 0), \ + .data_hold_time = DT_INST_PROP_OR(inst, data_hold_time, 0), \ .clock_gate_offset = DT_INST_PROP(inst, clock_gate_offset), \ .pcfg = PINCTRL_DT_INST_DEV_CONFIG_GET(inst), \ .target_enable = DT_INST_PROP(inst, target_enable), \ diff --git a/dts/bindings/i2c/ite,enhance-i2c.yaml b/dts/bindings/i2c/ite,enhance-i2c.yaml index 446f3f09aea..95720c85158 100644 --- a/dts/bindings/i2c/ite,enhance-i2c.yaml +++ b/dts/bindings/i2c/ite,enhance-i2c.yaml @@ -18,6 +18,23 @@ properties: SCL cycle = 2 * (psr + prescale_tweak + 2) * SMBus clock cycle + data-hold-time: + type: int + default: 3 + enum: + - 3 + - 4 + - 5 + - 6 + - 7 + - 8 + - 9 + - 10 + description: | + This option is used to configure the data hold time of the I2C. + The unit is number of SMB clock cycles. The time calculation + is (data-hold-time / smb_clk) seconds. + target-enable: type: boolean description: | From 9948c29885860b9800257f5a1fd466eb046b426e Mon Sep 17 00:00:00 2001 From: Tim Lin Date: Thu, 28 Dec 2023 15:25:17 +0800 Subject: [PATCH 2483/3723] ITE: drivers/i2c: Adjust the prescale of I2C SCL low and high period When adjusting the prescale to increase the I2C SCL low period, the high period must also be subtracted to maintain a consistent frequency. Signed-off-by: Tim Lin --- drivers/i2c/i2c_ite_enhance.c | 28 +++++++++++++++++++++++----- 1 file changed, 23 insertions(+), 5 deletions(-) diff --git a/drivers/i2c/i2c_ite_enhance.c b/drivers/i2c/i2c_ite_enhance.c index cf8646689c0..ae799596270 100644 --- a/drivers/i2c/i2c_ite_enhance.c +++ b/drivers/i2c/i2c_ite_enhance.c @@ -294,8 +294,9 @@ static void i2c_enhanced_port_set_frequency(const struct device *dev, int freq_hz) { const struct i2c_enhance_config *config = dev->config; - uint32_t clk_div, psr, pll_clock; + uint32_t clk_div, psr, pll_clock, psr_h, psr_l; uint8_t *base = config->base; + uint8_t prescale_scl = config->prescale_scl_low; pll_clock = chip_get_pll_freq(); /* @@ -318,11 +319,28 @@ static void i2c_enhanced_port_set_frequency(const struct device *dev, } /* Adjust SCL low period prescale */ - psr += config->prescale_scl_low; + psr_l = psr + prescale_scl; + if (psr_l > 0xFD) { + psr_l = 0xFD; + LOG_WRN("(psr + prescale_scl) can not be greater than 0xfd."); + } + + /* + * Adjust SCL high period prescale + * The property setting prescale_scl must be less than psr and + * the minimum value of psr_h is 2. + */ + if (psr > (prescale_scl + 2)) { + psr_h = psr - prescale_scl; + } else { + psr_h = 2; + LOG_WRN("prescale_scl_low should be less than (psr - 2)."); + } - /* Set I2C Speed */ - IT8XXX2_I2C_PSR(base) = psr & 0xFF; - IT8XXX2_I2C_HSPR(base) = psr & 0xFF; + /* Set I2C Speed for SCL low period. */ + IT8XXX2_I2C_PSR(base) = psr_l & 0xFF; + /* Set I2C Speed for SCL high period. */ + IT8XXX2_I2C_HSPR(base) = psr_h & 0xFF; } } From b0a83a9177fdd01116bb7719d09249a56878b733 Mon Sep 17 00:00:00 2001 From: Christopher Friedt Date: Mon, 15 Jan 2024 23:37:58 -0500 Subject: [PATCH 2484/3723] posix: rwlock: make pthread_rwlock_t a pooled ipc type Like mutex, barrier, cond, spinlock, etc, make pthread_rwlock_t a pooled ipc type. Signed-off-by: Christopher Friedt --- include/zephyr/posix/posix_types.h | 8 +- include/zephyr/posix/pthread.h | 7 + lib/posix/CMakeLists.txt | 2 +- lib/posix/Kconfig | 1 + lib/posix/Kconfig.rwlock | 8 + lib/posix/rwlock.c | 237 ++++++++++++++++++++++------- 6 files changed, 199 insertions(+), 64 deletions(-) create mode 100644 lib/posix/Kconfig.rwlock diff --git a/include/zephyr/posix/posix_types.h b/include/zephyr/posix/posix_types.h index 3420d562679..52621656569 100644 --- a/include/zephyr/posix/posix_types.h +++ b/include/zephyr/posix/posix_types.h @@ -90,13 +90,7 @@ typedef struct pthread_barrierattr { typedef uint32_t pthread_rwlockattr_t; -typedef struct pthread_rwlock_obj { - struct k_sem rd_sem; - struct k_sem wr_sem; - struct k_sem reader_active;/* blocks WR till reader has acquired lock */ - int32_t status; - k_tid_t wr_owner; -} pthread_rwlock_t; +typedef uint32_t pthread_rwlock_t; struct pthread_once { bool flag; diff --git a/include/zephyr/posix/pthread.h b/include/zephyr/posix/pthread.h index 636a2844180..4cf6dcbe3d4 100644 --- a/include/zephyr/posix/pthread.h +++ b/include/zephyr/posix/pthread.h @@ -136,6 +136,13 @@ int pthread_condattr_setclock(pthread_condattr_t *att, clockid_t clock_id); */ #define PTHREAD_MUTEX_INITIALIZER (-1) +/** + * @brief Declare a rwlock as initialized + * + * Initialize a rwlock with the default rwlock attributes. + */ +#define PTHREAD_RWLOCK_INITIALIZER (-1) + /* * Mutex attributes - type * diff --git a/lib/posix/CMakeLists.txt b/lib/posix/CMakeLists.txt index 999fcd1f3ea..06782677999 100644 --- a/lib/posix/CMakeLists.txt +++ b/lib/posix/CMakeLists.txt @@ -54,7 +54,7 @@ zephyr_library_sources_ifdef(CONFIG_PTHREAD_COND cond.c) zephyr_library_sources_ifdef(CONFIG_PTHREAD_KEY key.c) zephyr_library_sources_ifdef(CONFIG_PTHREAD_MUTEX mutex.c) zephyr_library_sources_ifdef(CONFIG_PTHREAD pthread.c) -zephyr_library_sources_ifdef(CONFIG_PTHREAD_IPC rwlock.c) +zephyr_library_sources_ifdef(CONFIG_PTHREAD_RWLOCK rwlock.c) zephyr_library_sources_ifdef(CONFIG_POSIX_PRIORITY_SCHEDULING sched.c) zephyr_library_sources_ifdef(CONFIG_PTHREAD_IPC semaphore.c) zephyr_library_sources_ifdef(CONFIG_PTHREAD_SPINLOCK spinlock.c) diff --git a/lib/posix/Kconfig b/lib/posix/Kconfig index a6f5021d520..ccf1a036318 100644 --- a/lib/posix/Kconfig +++ b/lib/posix/Kconfig @@ -49,6 +49,7 @@ source "lib/posix/Kconfig.limits" source "lib/posix/Kconfig.mqueue" source "lib/posix/Kconfig.mutex" source "lib/posix/Kconfig.pthread" +source "lib/posix/Kconfig.rwlock" source "lib/posix/Kconfig.sched" source "lib/posix/Kconfig.semaphore" source "lib/posix/Kconfig.signal" diff --git a/lib/posix/Kconfig.rwlock b/lib/posix/Kconfig.rwlock new file mode 100644 index 00000000000..6bd89a0a9f5 --- /dev/null +++ b/lib/posix/Kconfig.rwlock @@ -0,0 +1,8 @@ +# Copyright (c) 2024 Meta +# +# SPDX-License-Identifier: Apache-2.0 + +TYPE = PTHREAD_RWLOCK +type = pthread_rwlock_t +type-function = pthread_rwlock_timedrdlock +source "lib/posix/Kconfig.template.pooled_ipc_type" diff --git a/lib/posix/rwlock.c b/lib/posix/rwlock.c index 60039fb088a..a380b5d5693 100644 --- a/lib/posix/rwlock.c +++ b/lib/posix/rwlock.c @@ -3,19 +3,102 @@ * * SPDX-License-Identifier: Apache-2.0 */ -#include -#include -#include -#include -#define INITIALIZED 1 -#define NOT_INITIALIZED 0 +#include "posix_internal.h" + +#include +#include +#include +#include +#include #define CONCURRENT_READER_LIMIT (CONFIG_MAX_PTHREAD_COUNT + 1) +struct posix_rwlock { + struct k_sem rd_sem; + struct k_sem wr_sem; + struct k_sem reader_active; /* blocks WR till reader has acquired lock */ + k_tid_t wr_owner; +}; + int64_t timespec_to_timeoutms(const struct timespec *abstime); -static uint32_t read_lock_acquire(pthread_rwlock_t *rwlock, int32_t timeout); -static uint32_t write_lock_acquire(pthread_rwlock_t *rwlock, int32_t timeout); +static uint32_t read_lock_acquire(struct posix_rwlock *rwl, int32_t timeout); +static uint32_t write_lock_acquire(struct posix_rwlock *rwl, int32_t timeout); + +LOG_MODULE_REGISTER(pthread_rwlock, CONFIG_PTHREAD_RWLOCK_LOG_LEVEL); + +static struct k_spinlock posix_rwlock_spinlock; + +static struct posix_rwlock posix_rwlock_pool[CONFIG_MAX_PTHREAD_RWLOCK_COUNT]; +SYS_BITARRAY_DEFINE_STATIC(posix_rwlock_bitarray, CONFIG_MAX_PTHREAD_RWLOCK_COUNT); + +/* + * We reserve the MSB to mark a pthread_rwlock_t as initialized (from the + * perspective of the application). With a linear space, this means that + * the theoretical pthread_rwlock_t range is [0,2147483647]. + */ +BUILD_ASSERT(CONFIG_MAX_PTHREAD_RWLOCK_COUNT < PTHREAD_OBJ_MASK_INIT, + "CONFIG_MAX_PTHREAD_RWLOCK_COUNT is too high"); + +static inline size_t posix_rwlock_to_offset(struct posix_rwlock *rwl) +{ + return rwl - posix_rwlock_pool; +} + +static inline size_t to_posix_rwlock_idx(pthread_rwlock_t rwlock) +{ + return mark_pthread_obj_uninitialized(rwlock); +} + +static struct posix_rwlock *get_posix_rwlock(pthread_rwlock_t rwlock) +{ + int actually_initialized; + size_t bit = to_posix_rwlock_idx(rwlock); + + /* if the provided rwlock does not claim to be initialized, its invalid */ + if (!is_pthread_obj_initialized(rwlock)) { + LOG_ERR("RWlock is uninitialized (%x)", rwlock); + return NULL; + } + + /* Mask off the MSB to get the actual bit index */ + if (sys_bitarray_test_bit(&posix_rwlock_bitarray, bit, &actually_initialized) < 0) { + LOG_ERR("RWlock is invalid (%x)", rwlock); + return NULL; + } + + if (actually_initialized == 0) { + /* The rwlock claims to be initialized but is actually not */ + LOG_ERR("RWlock claims to be initialized (%x)", rwlock); + return NULL; + } + + return &posix_rwlock_pool[bit]; +} + +struct posix_rwlock *to_posix_rwlock(pthread_rwlock_t *rwlock) +{ + size_t bit; + struct posix_rwlock *rwl; + + if (*rwlock != PTHREAD_RWLOCK_INITIALIZER) { + return get_posix_rwlock(*rwlock); + } + + /* Try and automatically associate a posix_rwlock */ + if (sys_bitarray_alloc(&posix_rwlock_bitarray, 1, &bit) < 0) { + LOG_ERR("Unable to allocate pthread_rwlock_t"); + return NULL; + } + + /* Record the associated posix_rwlock in rwl and mark as initialized */ + *rwlock = mark_pthread_obj_initialized(bit); + + /* Initialize the posix_rwlock */ + rwl = &posix_rwlock_pool[bit]; + + return rwl; +} /** * @brief Initialize read-write lock object. @@ -25,12 +108,23 @@ static uint32_t write_lock_acquire(pthread_rwlock_t *rwlock, int32_t timeout); int pthread_rwlock_init(pthread_rwlock_t *rwlock, const pthread_rwlockattr_t *attr) { - k_sem_init(&rwlock->rd_sem, CONCURRENT_READER_LIMIT, - CONCURRENT_READER_LIMIT); - k_sem_init(&rwlock->wr_sem, 1, 1); - k_sem_init(&rwlock->reader_active, 1, 1); - rwlock->wr_owner = NULL; - rwlock->status = INITIALIZED; + struct posix_rwlock *rwl; + + ARG_UNUSED(attr); + *rwlock = PTHREAD_RWLOCK_INITIALIZER; + + rwl = to_posix_rwlock(rwlock); + if (rwl == NULL) { + return ENOMEM; + } + + k_sem_init(&rwl->rd_sem, CONCURRENT_READER_LIMIT, CONCURRENT_READER_LIMIT); + k_sem_init(&rwl->wr_sem, 1, 1); + k_sem_init(&rwl->reader_active, 1, 1); + rwl->wr_owner = NULL; + + LOG_DBG("Initialized rwlock %p", rwl); + return 0; } @@ -41,20 +135,28 @@ int pthread_rwlock_init(pthread_rwlock_t *rwlock, */ int pthread_rwlock_destroy(pthread_rwlock_t *rwlock) { - if (rwlock->status == NOT_INITIALIZED) { + int ret = 0; + int err; + size_t bit; + struct posix_rwlock *rwl; + + rwl = get_posix_rwlock(*rwlock); + if (rwl == NULL) { return EINVAL; } - if (rwlock->wr_owner != NULL) { - return EBUSY; - } + K_SPINLOCK(&posix_rwlock_spinlock) { + if (rwl->wr_owner != NULL) { + ret = EBUSY; + K_SPINLOCK_BREAK; + } - if (rwlock->status == INITIALIZED) { - rwlock->status = NOT_INITIALIZED; - return 0; + bit = posix_rwlock_to_offset(rwl); + err = sys_bitarray_free(&posix_rwlock_bitarray, 1, bit); + __ASSERT_NO_MSG(err == 0); } - return EINVAL; + return ret; } /** @@ -67,11 +169,14 @@ int pthread_rwlock_destroy(pthread_rwlock_t *rwlock) */ int pthread_rwlock_rdlock(pthread_rwlock_t *rwlock) { - if (rwlock->status == NOT_INITIALIZED) { + struct posix_rwlock *rwl; + + rwl = get_posix_rwlock(*rwlock); + if (rwl == NULL) { return EINVAL; } - return read_lock_acquire(rwlock, SYS_FOREVER_MS); + return read_lock_acquire(rwl, SYS_FOREVER_MS); } /** @@ -87,15 +192,20 @@ int pthread_rwlock_timedrdlock(pthread_rwlock_t *rwlock, { int32_t timeout; uint32_t ret = 0U; + struct posix_rwlock *rwl; - if (rwlock->status == NOT_INITIALIZED || abstime->tv_nsec < 0 || - abstime->tv_nsec > NSEC_PER_SEC) { + if (abstime->tv_nsec < 0 || abstime->tv_nsec > NSEC_PER_SEC) { return EINVAL; } timeout = (int32_t) timespec_to_timeoutms(abstime); - if (read_lock_acquire(rwlock, timeout) != 0U) { + rwl = get_posix_rwlock(*rwlock); + if (rwl == NULL) { + return EINVAL; + } + + if (read_lock_acquire(rwl, timeout) != 0U) { ret = ETIMEDOUT; } @@ -112,11 +222,14 @@ int pthread_rwlock_timedrdlock(pthread_rwlock_t *rwlock, */ int pthread_rwlock_tryrdlock(pthread_rwlock_t *rwlock) { - if (rwlock->status == NOT_INITIALIZED) { + struct posix_rwlock *rwl; + + rwl = get_posix_rwlock(*rwlock); + if (rwl == NULL) { return EINVAL; } - return read_lock_acquire(rwlock, 0); + return read_lock_acquire(rwl, 0); } /** @@ -129,11 +242,14 @@ int pthread_rwlock_tryrdlock(pthread_rwlock_t *rwlock) */ int pthread_rwlock_wrlock(pthread_rwlock_t *rwlock) { - if (rwlock->status == NOT_INITIALIZED) { + struct posix_rwlock *rwl; + + rwl = get_posix_rwlock(*rwlock); + if (rwl == NULL) { return EINVAL; } - return write_lock_acquire(rwlock, SYS_FOREVER_MS); + return write_lock_acquire(rwl, SYS_FOREVER_MS); } /** @@ -149,15 +265,20 @@ int pthread_rwlock_timedwrlock(pthread_rwlock_t *rwlock, { int32_t timeout; uint32_t ret = 0U; + struct posix_rwlock *rwl; - if (rwlock->status == NOT_INITIALIZED || abstime->tv_nsec < 0 || - abstime->tv_nsec > NSEC_PER_SEC) { + if (abstime->tv_nsec < 0 || abstime->tv_nsec > NSEC_PER_SEC) { return EINVAL; } timeout = (int32_t) timespec_to_timeoutms(abstime); - if (write_lock_acquire(rwlock, timeout) != 0U) { + rwl = get_posix_rwlock(*rwlock); + if (rwl == NULL) { + return EINVAL; + } + + if (write_lock_acquire(rwl, timeout) != 0U) { ret = ETIMEDOUT; } @@ -174,11 +295,14 @@ int pthread_rwlock_timedwrlock(pthread_rwlock_t *rwlock, */ int pthread_rwlock_trywrlock(pthread_rwlock_t *rwlock) { - if (rwlock->status == NOT_INITIALIZED) { + struct posix_rwlock *rwl; + + rwl = get_posix_rwlock(*rwlock); + if (rwl == NULL) { return EINVAL; } - return write_lock_acquire(rwlock, 0); + return write_lock_acquire(rwl, 0); } /** @@ -189,37 +313,38 @@ int pthread_rwlock_trywrlock(pthread_rwlock_t *rwlock) */ int pthread_rwlock_unlock(pthread_rwlock_t *rwlock) { - if (rwlock->status == NOT_INITIALIZED) { + struct posix_rwlock *rwl; + + rwl = get_posix_rwlock(*rwlock); + if (rwl == NULL) { return EINVAL; } - if (k_current_get() == rwlock->wr_owner) { + if (k_current_get() == rwl->wr_owner) { /* Write unlock */ - rwlock->wr_owner = NULL; - k_sem_give(&rwlock->reader_active); - k_sem_give(&rwlock->wr_sem); + rwl->wr_owner = NULL; + k_sem_give(&rwl->reader_active); + k_sem_give(&rwl->wr_sem); } else { /* Read unlock */ - k_sem_give(&rwlock->rd_sem); + k_sem_give(&rwl->rd_sem); - if (k_sem_count_get(&rwlock->rd_sem) == - CONCURRENT_READER_LIMIT) { + if (k_sem_count_get(&rwl->rd_sem) == CONCURRENT_READER_LIMIT) { /* Last read lock, unlock writer */ - k_sem_give(&rwlock->reader_active); + k_sem_give(&rwl->reader_active); } } return 0; } - -static uint32_t read_lock_acquire(pthread_rwlock_t *rwlock, int32_t timeout) +static uint32_t read_lock_acquire(struct posix_rwlock *rwl, int32_t timeout) { uint32_t ret = 0U; - if (k_sem_take(&rwlock->wr_sem, SYS_TIMEOUT_MS(timeout)) == 0) { - k_sem_take(&rwlock->reader_active, K_NO_WAIT); - k_sem_take(&rwlock->rd_sem, K_NO_WAIT); - k_sem_give(&rwlock->wr_sem); + if (k_sem_take(&rwl->wr_sem, SYS_TIMEOUT_MS(timeout)) == 0) { + k_sem_take(&rwl->reader_active, K_NO_WAIT); + k_sem_take(&rwl->rd_sem, K_NO_WAIT); + k_sem_give(&rwl->wr_sem); } else { ret = EBUSY; } @@ -227,7 +352,7 @@ static uint32_t read_lock_acquire(pthread_rwlock_t *rwlock, int32_t timeout) return ret; } -static uint32_t write_lock_acquire(pthread_rwlock_t *rwlock, int32_t timeout) +static uint32_t write_lock_acquire(struct posix_rwlock *rwl, int32_t timeout) { uint32_t ret = 0U; int64_t elapsed_time, st_time = k_uptime_get(); @@ -236,7 +361,7 @@ static uint32_t write_lock_acquire(pthread_rwlock_t *rwlock, int32_t timeout) k_timeout = SYS_TIMEOUT_MS(timeout); /* waiting for release of write lock */ - if (k_sem_take(&rwlock->wr_sem, k_timeout) == 0) { + if (k_sem_take(&rwl->wr_sem, k_timeout) == 0) { /* update remaining timeout time for 2nd sem */ if (timeout != SYS_FOREVER_MS) { elapsed_time = k_uptime_get() - st_time; @@ -247,10 +372,10 @@ static uint32_t write_lock_acquire(pthread_rwlock_t *rwlock, int32_t timeout) k_timeout = SYS_TIMEOUT_MS(timeout); /* waiting for reader to complete operation */ - if (k_sem_take(&rwlock->reader_active, k_timeout) == 0) { - rwlock->wr_owner = k_current_get(); + if (k_sem_take(&rwl->reader_active, k_timeout) == 0) { + rwl->wr_owner = k_current_get(); } else { - k_sem_give(&rwlock->wr_sem); + k_sem_give(&rwl->wr_sem); ret = EBUSY; } From 8bcec18e25b44971f2d00a0fc9fc8d6bdbb84456 Mon Sep 17 00:00:00 2001 From: Lukasz Mrugala Date: Mon, 15 Jan 2024 13:30:36 +0000 Subject: [PATCH 2485/3723] scripts: tests: blackbox noclearout mark warning removal Currently, the noclearout pytest mark generates warnings because it is not registered. This commit adds its registration in the relevant conftest. Signed-off-by: Lukasz Mrugala --- scripts/tests/twister_blackbox/conftest.py | 3 +++ 1 file changed, 3 insertions(+) diff --git a/scripts/tests/twister_blackbox/conftest.py b/scripts/tests/twister_blackbox/conftest.py index 95fd0b3338a..11429319b96 100644 --- a/scripts/tests/twister_blackbox/conftest.py +++ b/scripts/tests/twister_blackbox/conftest.py @@ -23,6 +23,9 @@ testsuite_filename_mock = mock.PropertyMock(return_value='test_data.yaml') +def pytest_configure(config): + config.addinivalue_line("markers", "noclearout: disable the provide_out autouse fixture") + @pytest.fixture(name='zephyr_base') def zephyr_base_directory(): return ZEPHYR_BASE From 3b99fb1b4a55ce51be185b25fd2ba99dcb4d0125 Mon Sep 17 00:00:00 2001 From: Daniel Leung Date: Tue, 2 Jan 2024 14:14:33 -0800 Subject: [PATCH 2486/3723] xtensa: do not imply atomic ops kconfig Xtensa's arch level atomic implementation requries S32C1I support which may not exist as Xtensa cores are highly configurable. Implying CONFIG_ATOMIC_OPERATIONS_ARCH at arch level has a side effect that it is enabled regardless if the other options are enabled. Given how the header file's #ifdef is structured, only C atomic ops can override this, which means enabling CONFIG_ATOMIC_OPERATIONS_BUILTIN has no effect at all. So let the SoC or board decide which atomic ops are being used instead. Signed-off-by: Daniel Leung --- arch/Kconfig | 1 - 1 file changed, 1 deletion(-) diff --git a/arch/Kconfig b/arch/Kconfig index 8130d3fa6a8..b8661fa5964 100644 --- a/arch/Kconfig +++ b/arch/Kconfig @@ -126,7 +126,6 @@ config XTENSA select ARCH_HAS_CODE_DATA_RELOCATION select ARCH_HAS_TIMING_FUNCTIONS select ARCH_MEM_DOMAIN_DATA if USERSPACE - imply ATOMIC_OPERATIONS_ARCH help Xtensa architecture From a97b61e7ed624c02975cd1fa2c4a8bfa8e28aa45 Mon Sep 17 00:00:00 2001 From: Attie Grande Date: Mon, 2 Oct 2023 11:58:27 +0100 Subject: [PATCH 2487/3723] include: sd: revise the minimum alignment of card_buffer to 4-bytes Since a85ffa8, `struct sd_card.card_buffer` has naturally fallen at an offset that is unaligned. This meant that on systems without support for unaligned access (e.g: Cortex-M0), a hard fault would present when executing code that casts the buffer to `uint32_t` (such as `sdmmc_spi_read_cxd()`, `card_query_written()`, etc...) Historically, it appears that the alignment of the `card_buffer` member was good and operational only by chance. Altering the default value of `CONFIG_SDHC_BUFFER_ALIGNMENT` was rejected, as this has wider implications. Fixes #62619 Signed-off-by: Attie Grande --- include/zephyr/sd/sd.h | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/include/zephyr/sd/sd.h b/include/zephyr/sd/sd.h index 69d3057e8ad..b23fa2c260c 100644 --- a/include/zephyr/sd/sd.h +++ b/include/zephyr/sd/sd.h @@ -80,8 +80,14 @@ struct sd_card { uint8_t bus_width; /*!< Desired bus width */ uint32_t cccr_flags; /*!< SDIO CCCR data */ struct sdio_func func0; /*!< Function 0 common card data */ + + /* NOTE: The buffer is accessed as a uint32_t* by the SD subsystem, so must be + * aligned to 4 bytes for platforms that don't support unaligned access... + * Systems where the buffer is accessed by DMA may require wider alignment, in + * which case, use CONFIG_SDHC_BUFFER_ALIGNMENT. + */ uint8_t card_buffer[CONFIG_SD_BUFFER_SIZE] - __aligned(CONFIG_SDHC_BUFFER_ALIGNMENT); /* Card internal buffer */ + __aligned(MAX(4, CONFIG_SDHC_BUFFER_ALIGNMENT)); /* Card internal buffer */ }; /** From 640e70c9ce5f8bd5b2028533d38f52f8a8706c73 Mon Sep 17 00:00:00 2001 From: Ian Morris Date: Mon, 20 Nov 2023 12:17:04 -0800 Subject: [PATCH 2488/3723] drivers: clock_control: clock_control_ra.c: clock divider fix The clock divider value is not being applied as the address of the register to which it is being written is incorrect. A check of all RA MCU datasheets confirms that, in all cases, the SCKDIVCR register is at an offset of 0x20 (and not 0x21). Signed-off-by: Ian Morris --- drivers/clock_control/clock_control_ra.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/clock_control/clock_control_ra.c b/drivers/clock_control/clock_control_ra.c index 6211717b56a..46149f0099c 100644 --- a/drivers/clock_control/clock_control_ra.c +++ b/drivers/clock_control/clock_control_ra.c @@ -123,7 +123,7 @@ enum { }; enum { - SCKDIVCR_OFFSET = 0x021, + SCKDIVCR_OFFSET = 0x020, SCKSCR_OFFSET = 0x026, MEMWAIT_OFFSET = 0x031, MOSCCR_OFFSET = 0x032, From d26ba10640436ed4a2bade6f8906dd7aee477a82 Mon Sep 17 00:00:00 2001 From: Emil Gydesen Date: Mon, 15 Jan 2024 15:51:29 +0100 Subject: [PATCH 2489/3723] Bluetooth: GATT: Add missing busy check for auto discover CCC When using the auto discover CCC, and the function is called more than once with the same parameters before the previous discovery has completed, then that may cause issues when we reset the parameters when we get the response. This commit adds a small check for the callback function which is only set to the specified function when the discovery is in progress. This way we can return an error if the application calls bt_gatt_subscribe multiple times before the previous discovery has completed, rather than asserting. Signed-off-by: Emil Gydesen --- include/zephyr/bluetooth/gatt.h | 5 +++++ subsys/bluetooth/host/gatt.c | 7 +++++++ 2 files changed, 12 insertions(+) diff --git a/include/zephyr/bluetooth/gatt.h b/include/zephyr/bluetooth/gatt.h index b5c355fad21..2cbe96a7285 100644 --- a/include/zephyr/bluetooth/gatt.h +++ b/include/zephyr/bluetooth/gatt.h @@ -1896,6 +1896,11 @@ struct bt_gatt_subscribe_params { * Allow a pending request to resolve before retrying, or call this function * outside the BT RX thread to get blocking behavior. Queue size is controlled * by @kconfig{CONFIG_BT_ATT_TX_COUNT}. + * + * @retval -EALREADY if there already exist a subscription using the @p params. + * + * @retval -EBUSY if @p params.ccc_handle is 0 and @kconfig{CONFIG_BT_GATT_AUTO_DISCOVER_CCC} is + * enabled and discovery for the @p params is already in progress. */ int bt_gatt_subscribe(struct bt_conn *conn, struct bt_gatt_subscribe_params *params); diff --git a/subsys/bluetooth/host/gatt.c b/subsys/bluetooth/host/gatt.c index 451c3d29f7f..eda7d2dff26 100644 --- a/subsys/bluetooth/host/gatt.c +++ b/subsys/bluetooth/host/gatt.c @@ -5294,6 +5294,13 @@ int bt_gatt_subscribe(struct bt_conn *conn, return -ENOMEM; } +#if defined(CONFIG_BT_GATT_AUTO_DISCOVER_CCC) + if (params->disc_params != NULL && params->disc_params->func == gatt_ccc_discover_cb) { + /* Already in progress */ + return -EBUSY; + } +#endif + /* Lookup existing subscriptions */ SYS_SLIST_FOR_EACH_CONTAINER(&sub->list, tmp, node) { /* Fail if entry already exists */ From f14c3e06f47b8147e806c5671e6079f9f46e6c91 Mon Sep 17 00:00:00 2001 From: Laurentiu Mihalcea Date: Tue, 16 Jan 2024 12:15:49 +0200 Subject: [PATCH 2490/3723] xtensa: nxp_adsp: common: Remove soc.c The soc.c interrupt-related definitions are supposed to provide support for multi-level interrupts. At the moment, the way the functions work is they only process the LEVEL 1 interrupt from the encoded INTID and treats the provided INTID as if it were simply a LEVEL 1 interrupt, which is wrong. Another issue with soc.c is the fact that the definitions from it clash with the ones provided by the IRQSTEER driver. To fix this, remove the soc.c file altogether and change the corresponding CMakeLists.txt to only contain the necessary statements. Signed-off-by: Laurentiu Mihalcea --- soc/xtensa/nxp_adsp/common/CMakeLists.txt | 12 ------ soc/xtensa/nxp_adsp/common/soc.c | 47 ----------------------- 2 files changed, 59 deletions(-) delete mode 100644 soc/xtensa/nxp_adsp/common/soc.c diff --git a/soc/xtensa/nxp_adsp/common/CMakeLists.txt b/soc/xtensa/nxp_adsp/common/CMakeLists.txt index 02c2ef503e3..5c53c771f08 100644 --- a/soc/xtensa/nxp_adsp/common/CMakeLists.txt +++ b/soc/xtensa/nxp_adsp/common/CMakeLists.txt @@ -4,15 +4,3 @@ # SPDX-License-Identifier: Apache-2.0 zephyr_include_directories(include) - -zephyr_interface_library_named(NXP_ADSP_COMMON) - -zephyr_library_named(nxp_adsp_common) -zephyr_library_include_directories(${ZEPHYR_BASE}/drivers) - -zephyr_library_sources(soc.c) - -zephyr_library_link_libraries(NXP_ADSP_COMMON) - -target_include_directories(NXP_ADSP_COMMON INTERFACE include) -target_link_libraries(NXP_ADSP_COMMON INTERFACE nxp_adsp_common) diff --git a/soc/xtensa/nxp_adsp/common/soc.c b/soc/xtensa/nxp_adsp/common/soc.c deleted file mode 100644 index 903dd8e7805..00000000000 --- a/soc/xtensa/nxp_adsp/common/soc.c +++ /dev/null @@ -1,47 +0,0 @@ -/* - * Copyright (c) 2021 NXP - * - * SPDX-License-Identifier: Apache-2.0 - */ - -#include -#include -#include -#include -#include -#include - -#include "soc.h" - -#ifdef CONFIG_DYNAMIC_INTERRUPTS -#include -#endif -#define LOG_LEVEL CONFIG_SOC_LOG_LEVEL -#include -LOG_MODULE_REGISTER(soc); - -void z_soc_irq_enable(uint32_t irq) -{ - /* - * enable core interrupt - */ - xtensa_irq_enable(XTENSA_IRQ_NUMBER(irq)); -} - -void z_soc_irq_disable(uint32_t irq) -{ - /* - * disable the interrupt in interrupt controller - */ - xtensa_irq_disable(XTENSA_IRQ_NUMBER(irq)); -} - -int z_soc_irq_is_enabled(unsigned int irq) -{ - int ret = 0; - - /* regular interrupt */ - ret = xtensa_irq_is_enabled(XTENSA_IRQ_NUMBER(irq)); - - return ret; -} From 07823f771049bd64809b4c8b24854a0c116cab2b Mon Sep 17 00:00:00 2001 From: Jukka Rissanen Date: Tue, 16 Jan 2024 16:53:53 +0200 Subject: [PATCH 2491/3723] net: zperf: Convert TCP receiver to use socket services Use socket services API for TCP receiver. Signed-off-by: Jukka Rissanen --- subsys/net/lib/zperf/Kconfig | 1 + subsys/net/lib/zperf/zperf_common.c | 1 - subsys/net/lib/zperf/zperf_internal.h | 1 - subsys/net/lib/zperf/zperf_tcp_receiver.c | 302 +++++++++++----------- 4 files changed, 157 insertions(+), 148 deletions(-) diff --git a/subsys/net/lib/zperf/Kconfig b/subsys/net/lib/zperf/Kconfig index 204144a805b..0cb637f376e 100644 --- a/subsys/net/lib/zperf/Kconfig +++ b/subsys/net/lib/zperf/Kconfig @@ -5,6 +5,7 @@ menuconfig NET_ZPERF bool "zperf shell utility" select NET_CONTEXT_RCVTIMEO if NET_NATIVE_UDP + select NET_SOCKETS_SERVICE help This option enables zperf shell utility, which allows to generate network traffic and evaluate network bandwidth. diff --git a/subsys/net/lib/zperf/zperf_common.c b/subsys/net/lib/zperf/zperf_common.c index 4bc675ed45e..3a2674dc05c 100644 --- a/subsys/net/lib/zperf/zperf_common.c +++ b/subsys/net/lib/zperf/zperf_common.c @@ -223,7 +223,6 @@ static int zperf_init(void) zperf_udp_uploader_init(); zperf_tcp_uploader_init(); zperf_udp_receiver_init(); - zperf_tcp_receiver_init(); zperf_session_init(); diff --git a/subsys/net/lib/zperf/zperf_internal.h b/subsys/net/lib/zperf/zperf_internal.h index 592424a9446..6fdb545cdd2 100644 --- a/subsys/net/lib/zperf/zperf_internal.h +++ b/subsys/net/lib/zperf/zperf_internal.h @@ -104,7 +104,6 @@ void zperf_async_work_submit(struct k_work *work); void zperf_udp_uploader_init(void); void zperf_tcp_uploader_init(void); void zperf_udp_receiver_init(void); -void zperf_tcp_receiver_init(void); void zperf_shell_init(void); diff --git a/subsys/net/lib/zperf/zperf_tcp_receiver.c b/subsys/net/lib/zperf/zperf_tcp_receiver.c index 344d34fe98c..c782124e36b 100644 --- a/subsys/net/lib/zperf/zperf_tcp_receiver.c +++ b/subsys/net/lib/zperf/zperf_tcp_receiver.c @@ -14,6 +14,7 @@ LOG_MODULE_DECLARE(net_zperf, CONFIG_NET_ZPERF_LOG_LEVEL); #include #include +#include #include #include "zperf_internal.h" @@ -23,23 +24,11 @@ LOG_MODULE_DECLARE(net_zperf, CONFIG_NET_ZPERF_LOG_LEVEL); #define NET_LOG_ENABLED 1 #include "net_private.h" -#if defined(CONFIG_NET_TC_THREAD_COOPERATIVE) -#define TCP_RECEIVER_THREAD_PRIORITY K_PRIO_COOP(8) -#else -#define TCP_RECEIVER_THREAD_PRIORITY K_PRIO_PREEMPT(8) -#endif - -#define TCP_RECEIVER_STACK_SIZE 2048 - #define SOCK_ID_IPV4_LISTEN 0 #define SOCK_ID_IPV6_LISTEN 1 #define SOCK_ID_MAX (CONFIG_NET_ZPERF_MAX_SESSIONS + 2) #define TCP_RECEIVER_BUF_SIZE 1500 -#define POLL_TIMEOUT_MS 100 - -static K_THREAD_STACK_DEFINE(tcp_receiver_stack_area, TCP_RECEIVER_STACK_SIZE); -static struct k_thread tcp_receiver_thread_data; static zperf_callback tcp_session_cb; static void *tcp_user_data; @@ -49,6 +38,14 @@ static uint16_t tcp_server_port; static struct sockaddr tcp_server_addr; static K_SEM_DEFINE(tcp_server_run, 0, 1); +static struct zsock_pollfd fds[SOCK_ID_MAX]; +static struct sockaddr sock_addr[SOCK_ID_MAX]; + +static void tcp_svc_handler(struct k_work *work); + +NET_SOCKET_SERVICE_SYNC_DEFINE_STATIC(svc_tcp, NULL, tcp_svc_handler, + SOCK_ID_MAX); + static void tcp_received(const struct sockaddr *addr, size_t datalen) { struct session *session; @@ -99,6 +96,143 @@ static void tcp_received(const struct sockaddr *addr, size_t datalen) } } +static void tcp_session_error_report(void) +{ + if (tcp_session_cb != NULL) { + tcp_session_cb(ZPERF_SESSION_ERROR, NULL, tcp_user_data); + } +} + +static int tcp_recv_data(struct net_socket_service_event *pev) +{ + static uint8_t buf[TCP_RECEIVER_BUF_SIZE]; + int i, ret = 0; + int family, sock; + struct sockaddr addr_incoming_conn; + socklen_t optlen = sizeof(int); + socklen_t addrlen = sizeof(struct sockaddr); + + if (tcp_server_stop) { + ret = -ENOENT; + goto cleanup; + } + + if ((pev->event.revents & ZSOCK_POLLERR) || + (pev->event.revents & ZSOCK_POLLNVAL)) { + (void)zsock_getsockopt(pev->event.fd, SOL_SOCKET, + SO_DOMAIN, &family, &optlen); + NET_ERR("TCP receiver IPv%d socket error", + family == AF_INET ? 4 : 6); + goto error; + } + + if (!(pev->event.revents & ZSOCK_POLLIN)) { + return 0; + } + + /* What is the index to first accepted socket */ + i = SOCK_ID_IPV6_LISTEN + 1; + + /* Check first if we need to accept a connection */ + if (fds[SOCK_ID_IPV4_LISTEN].fd == pev->event.fd || + fds[SOCK_ID_IPV6_LISTEN].fd == pev->event.fd) { + sock = zsock_accept(pev->event.fd, + &addr_incoming_conn, + &addrlen); + if (sock < 0) { + (void)zsock_getsockopt(pev->event.fd, SOL_SOCKET, + SO_DOMAIN, &family, &optlen); + NET_ERR("TCP receiver IPv%d accept error", + family == AF_INET ? 4 : 6); + goto error; + } + + for (; i < SOCK_ID_MAX; i++) { + if (fds[i].fd < 0) { + break; + } + } + + if (i == SOCK_ID_MAX) { + /* Too many connections. */ + NET_ERR("Dropping TCP connection, reached maximum limit."); + zsock_close(sock); + } else { + fds[i].fd = sock; + fds[i].events = ZSOCK_POLLIN; + memcpy(&sock_addr[i], &addr_incoming_conn, addrlen); + + (void)net_socket_service_register(&svc_tcp, fds, + ARRAY_SIZE(fds), + NULL); + } + + } else { + ret = zsock_recv(pev->event.fd, buf, sizeof(buf), 0); + if (ret < 0) { + (void)zsock_getsockopt(pev->event.fd, SOL_SOCKET, + SO_DOMAIN, &family, &optlen); + NET_ERR("recv failed on IPv%d socket (%d)", + family == AF_INET ? 4 : 6, + errno); + tcp_session_error_report(); + /* This will close the zperf session */ + ret = 0; + } + + for (; i < SOCK_ID_MAX; i++) { + if (fds[i].fd == pev->event.fd) { + break; + } + } + + if (i == SOCK_ID_MAX) { + NET_ERR("Descriptor %d not found.", pev->event.fd); + } else { + tcp_received(&sock_addr[i], ret); + if (ret == 0) { + zsock_close(fds[i].fd); + fds[i].fd = -1; + memset(&sock_addr[i], 0, sizeof(struct sockaddr)); + + (void)net_socket_service_register(&svc_tcp, fds, + ARRAY_SIZE(fds), + NULL); + } + } + } + + return ret; + +error: + tcp_session_error_report(); + +cleanup: + for (i = 0; i < ARRAY_SIZE(fds); i++) { + if (fds[i].fd >= 0) { + zsock_close(fds[i].fd); + fds[i].fd = -1; + memset(&sock_addr[i], 0, sizeof(struct sockaddr)); + } + } + + (void)net_socket_service_unregister(&svc_tcp); + + return ret; +} + +static void tcp_svc_handler(struct k_work *work) +{ + struct net_socket_service_event *pev = + CONTAINER_OF(work, struct net_socket_service_event, work); + int ret; + + ret = tcp_recv_data(pev); + if (ret < 0) { + (void)net_socket_service_unregister(&svc_tcp); + } +} + static int tcp_bind_listen_connection(struct zsock_pollfd *pollfd, struct sockaddr *address) { @@ -114,14 +248,14 @@ static int tcp_bind_listen_connection(struct zsock_pollfd *pollfd, ret = zsock_bind(pollfd->fd, address, sizeof(*address)); if (ret < 0) { NET_ERR("Cannot bind IPv%d TCP port %d (%d)", - (address->sa_family == AF_INET ? 4 : 6), port, errno); + address->sa_family == AF_INET ? 4 : 6, port, errno); goto out; } ret = zsock_listen(pollfd->fd, 1); if (ret < 0) { NET_ERR("Cannot listen IPv%d TCP (%d)", - (address->sa_family == AF_INET ? 4 : 6), errno); + address->sa_family == AF_INET ? 4 : 6, errno); goto out; } @@ -131,18 +265,8 @@ static int tcp_bind_listen_connection(struct zsock_pollfd *pollfd, return ret; } -static void tcp_session_error_report(void) +static void zperf_tcp_receiver_init(void) { - if (tcp_session_cb != NULL) { - tcp_session_cb(ZPERF_SESSION_ERROR, NULL, tcp_user_data); - } -} - -static void tcp_server_session(void) -{ - static uint8_t buf[TCP_RECEIVER_BUF_SIZE]; - static struct zsock_pollfd fds[SOCK_ID_MAX]; - static struct sockaddr sock_addr[SOCK_ID_MAX]; int ret; for (int i = 0; i < ARRAY_SIZE(fds); i++) { @@ -243,130 +367,14 @@ static void tcp_server_session(void) NET_INFO("Listening on port %d", tcp_server_port); - while (true) { - ret = zsock_poll(fds, ARRAY_SIZE(fds), POLL_TIMEOUT_MS); - if (ret < 0) { - NET_ERR("TCP receiver poll error (%d)", errno); - goto error; - } - - if (tcp_server_stop) { - goto cleanup; - } - - if (ret == 0) { - continue; - } - - for (int i = 0; i < ARRAY_SIZE(fds); i++) { - if ((fds[i].revents & ZSOCK_POLLERR) || - (fds[i].revents & ZSOCK_POLLNVAL)) { - NET_ERR("TCP receiver IPv%d socket error", - (sock_addr[i].sa_family == AF_INET - ? 4 : 6)); - goto error; - } - - if (!(fds[i].revents & ZSOCK_POLLIN)) { - continue; - } - - if ((i >= SOCK_ID_IPV4_LISTEN) && (i <= SOCK_ID_IPV6_LISTEN)) { - int j = SOCK_ID_IPV6_LISTEN + 1; - struct sockaddr addr_incoming_conn; - socklen_t addrlen = sizeof(struct sockaddr); - int sock = zsock_accept(fds[i].fd, - &addr_incoming_conn, - &addrlen); - - if (sock < 0) { - NET_ERR("TCP receiver IPv%d accept error", - (sock_addr[i].sa_family == AF_INET - ? 4 : 6)); - goto error; - } - - for (; j < SOCK_ID_MAX; j++) { - if (fds[j].fd < 0) { - break; - } - } - - if (j == SOCK_ID_MAX) { - /* Too many connections. */ - NET_ERR("Dropping TCP connection, reached maximum limit."); - zsock_close(sock); - } else { - fds[j].fd = sock; - fds[j].events = ZSOCK_POLLIN; - memcpy(&sock_addr[j], - &addr_incoming_conn, - addrlen); - } - } else if ((i > SOCK_ID_IPV6_LISTEN) && (i < SOCK_ID_MAX)) { - ret = zsock_recv(fds[i].fd, buf, sizeof(buf), 0); - if (ret < 0) { - NET_ERR("recv failed on IPv%d socket (%d)", - (sock_addr[i].sa_family == AF_INET - ? 4 : 6), - errno); - tcp_session_error_report(); - /* This will close the zperf session */ - ret = 0; - } - - tcp_received(&sock_addr[i], ret); - - if (ret == 0) { - zsock_close(fds[i].fd); - fds[i].fd = -1; - memset(&sock_addr[i], 0, - sizeof(struct sockaddr)); - } - } else { - goto error; - } - } + ret = net_socket_service_register(&svc_tcp, fds, + ARRAY_SIZE(fds), NULL); + if (ret < 0) { + LOG_ERR("Cannot register socket service handler (%d)", ret); } error: - tcp_session_error_report(); - -cleanup: - for (int i = 0; i < ARRAY_SIZE(fds); i++) { - if (fds[i].fd >= 0) { - zsock_close(fds[i].fd); - memset(&sock_addr[i], 0, sizeof(struct sockaddr)); - } - } -} - -void tcp_receiver_thread(void *ptr1, void *ptr2, void *ptr3) -{ - ARG_UNUSED(ptr1); - ARG_UNUSED(ptr2); - ARG_UNUSED(ptr3); - - while (true) { - k_sem_take(&tcp_server_run, K_FOREVER); - - tcp_server_session(); - - tcp_server_running = false; - } -} - -void zperf_tcp_receiver_init(void) -{ - k_thread_create(&tcp_receiver_thread_data, - tcp_receiver_stack_area, - K_THREAD_STACK_SIZEOF(tcp_receiver_stack_area), - tcp_receiver_thread, - NULL, NULL, NULL, - TCP_RECEIVER_THREAD_PRIORITY, - IS_ENABLED(CONFIG_USERSPACE) ? K_USER | - K_INHERIT_PERMS : 0, - K_NO_WAIT); + return; } int zperf_tcp_download(const struct zperf_download_params *param, @@ -387,6 +395,8 @@ int zperf_tcp_download(const struct zperf_download_params *param, tcp_server_stop = false; memcpy(&tcp_server_addr, ¶m->addr, sizeof(struct sockaddr)); + zperf_tcp_receiver_init(); + k_sem_give(&tcp_server_run); return 0; From 1e8cbd5d43fc108ec4be8eebe653e62f842e0def Mon Sep 17 00:00:00 2001 From: Jukka Rissanen Date: Wed, 17 Jan 2024 14:57:43 +0200 Subject: [PATCH 2492/3723] net: zperf: Convert UDP receiver to use socket services Use socket services API for UDP receiver. Signed-off-by: Jukka Rissanen --- subsys/net/lib/zperf/zperf_common.c | 1 - subsys/net/lib/zperf/zperf_internal.h | 1 - subsys/net/lib/zperf/zperf_udp_receiver.c | 177 +++++++++++----------- 3 files changed, 86 insertions(+), 93 deletions(-) diff --git a/subsys/net/lib/zperf/zperf_common.c b/subsys/net/lib/zperf/zperf_common.c index 3a2674dc05c..89224b691ca 100644 --- a/subsys/net/lib/zperf/zperf_common.c +++ b/subsys/net/lib/zperf/zperf_common.c @@ -222,7 +222,6 @@ static int zperf_init(void) zperf_udp_uploader_init(); zperf_tcp_uploader_init(); - zperf_udp_receiver_init(); zperf_session_init(); diff --git a/subsys/net/lib/zperf/zperf_internal.h b/subsys/net/lib/zperf/zperf_internal.h index 6fdb545cdd2..b8cdb84cbbf 100644 --- a/subsys/net/lib/zperf/zperf_internal.h +++ b/subsys/net/lib/zperf/zperf_internal.h @@ -103,7 +103,6 @@ uint32_t zperf_packet_duration(uint32_t packet_size, uint32_t rate_in_kbps); void zperf_async_work_submit(struct k_work *work); void zperf_udp_uploader_init(void); void zperf_tcp_uploader_init(void); -void zperf_udp_receiver_init(void); void zperf_shell_init(void); diff --git a/subsys/net/lib/zperf/zperf_udp_receiver.c b/subsys/net/lib/zperf/zperf_udp_receiver.c index 75a0b35b234..ba44590c621 100644 --- a/subsys/net/lib/zperf/zperf_udp_receiver.c +++ b/subsys/net/lib/zperf/zperf_udp_receiver.c @@ -13,6 +13,7 @@ LOG_MODULE_DECLARE(net_zperf, CONFIG_NET_ZPERF_LOG_LEVEL); #include #include +#include #include #include "zperf_internal.h" @@ -25,14 +26,6 @@ LOG_MODULE_DECLARE(net_zperf, CONFIG_NET_ZPERF_LOG_LEVEL); static struct sockaddr_in6 *in6_addr_my; static struct sockaddr_in *in4_addr_my; -#if defined(CONFIG_NET_TC_THREAD_COOPERATIVE) -#define UDP_RECEIVER_THREAD_PRIORITY K_PRIO_COOP(8) -#else -#define UDP_RECEIVER_THREAD_PRIORITY K_PRIO_PREEMPT(8) -#endif - -#define UDP_RECEIVER_STACK_SIZE 2048 - #define SOCK_ID_IPV4 0 #define SOCK_ID_IPV6 1 #define SOCK_ID_MAX 2 @@ -40,9 +33,6 @@ static struct sockaddr_in *in4_addr_my; #define UDP_RECEIVER_BUF_SIZE 1500 #define POLL_TIMEOUT_MS 100 -static K_THREAD_STACK_DEFINE(udp_receiver_stack_area, UDP_RECEIVER_STACK_SIZE); -static struct k_thread udp_receiver_thread_data; - static zperf_callback udp_session_cb; static void *udp_user_data; static bool udp_server_running; @@ -51,6 +41,13 @@ static uint16_t udp_server_port; static struct sockaddr udp_server_addr; static K_SEM_DEFINE(udp_server_run, 0, 1); +struct zsock_pollfd fds[SOCK_ID_MAX] = { 0 }; + +static void udp_svc_handler(struct k_work *work); + +NET_SOCKET_SERVICE_SYNC_DEFINE_STATIC(svc_udp, NULL, udp_svc_handler, + SOCK_ID_MAX); + static inline void build_reply(struct zperf_udp_datagram *hdr, struct zperf_server_hdr *stat, uint8_t *buf) @@ -230,10 +227,79 @@ static void udp_received(int sock, const struct sockaddr *addr, uint8_t *data, } } -static void udp_server_session(void) +static int udp_recv_data(struct net_socket_service_event *pev) { static uint8_t buf[UDP_RECEIVER_BUF_SIZE]; - struct zsock_pollfd fds[SOCK_ID_MAX] = { 0 }; + int i, ret = 0; + int family; + struct sockaddr addr; + socklen_t optlen = sizeof(int); + socklen_t addrlen = sizeof(addr); + + if (udp_server_stop) { + ret = -ENOENT; + goto cleanup; + } + + if ((pev->event.revents & ZSOCK_POLLERR) || + (pev->event.revents & ZSOCK_POLLNVAL)) { + (void)zsock_getsockopt(pev->event.fd, SOL_SOCKET, + SO_DOMAIN, &family, &optlen); + NET_ERR("UDP receiver IPv%d socket error", + family == AF_INET ? 4 : 6); + goto error; + } + + if (!(pev->event.revents & ZSOCK_POLLIN)) { + return 0; + } + + ret = zsock_recvfrom(pev->event.fd, buf, sizeof(buf), 0, + &addr, &addrlen); + if (ret < 0) { + (void)zsock_getsockopt(pev->event.fd, SOL_SOCKET, + SO_DOMAIN, &family, &optlen); + NET_ERR("recv failed on IPv%d socket (%d)", + family == AF_INET ? 4 : 6, errno); + goto error; + } + + udp_received(pev->event.fd, &addr, buf, ret); + + return ret; + +error: + if (udp_session_cb != NULL) { + udp_session_cb(ZPERF_SESSION_ERROR, NULL, udp_user_data); + } + +cleanup: + for (i = 0; i < ARRAY_SIZE(fds); i++) { + if (fds[i].fd >= 0) { + zsock_close(fds[i].fd); + fds[i].fd = -1; + } + } + + (void)net_socket_service_unregister(&svc_udp); + + return ret; +} + +static void udp_svc_handler(struct k_work *work) +{ + struct net_socket_service_event *pev = + CONTAINER_OF(work, struct net_socket_service_event, work); + int ret; + + ret = udp_recv_data(pev); + if (ret < 0) { + (void)net_socket_service_unregister(&svc_udp); + } +} + +static void zperf_udp_receiver_init(void) +{ int ret; for (int i = 0; i < ARRAY_SIZE(fds); i++) { @@ -341,87 +407,14 @@ static void udp_server_session(void) NET_INFO("Listening on port %d", udp_server_port); - while (true) { - ret = zsock_poll(fds, ARRAY_SIZE(fds), POLL_TIMEOUT_MS); - if (ret < 0) { - NET_ERR("UDP receiver poll error (%d)", errno); - goto error; - } - - if (udp_server_stop) { - goto cleanup; - } - - if (ret == 0) { - continue; - } - - for (int i = 0; i < ARRAY_SIZE(fds); i++) { - struct sockaddr addr; - socklen_t addrlen = sizeof(addr); - - if ((fds[i].revents & ZSOCK_POLLERR) || - (fds[i].revents & ZSOCK_POLLNVAL)) { - NET_ERR("UDP receiver IPv%d socket error", - (i == SOCK_ID_IPV4) ? 4 : 6); - goto error; - } - - if (!(fds[i].revents & ZSOCK_POLLIN)) { - continue; - } - - ret = zsock_recvfrom(fds[i].fd, buf, sizeof(buf), 0, - &addr, &addrlen); - if (ret < 0) { - NET_ERR("recv failed on IPv%d socket (%d)", - (i == SOCK_ID_IPV4) ? 4 : 6, errno); - goto error; - } - - udp_received(fds[i].fd, &addr, buf, ret); - } + ret = net_socket_service_register(&svc_udp, fds, + ARRAY_SIZE(fds), NULL); + if (ret < 0) { + LOG_ERR("Cannot register socket service handler (%d)", ret); } error: - if (udp_session_cb != NULL) { - udp_session_cb(ZPERF_SESSION_ERROR, NULL, udp_user_data); - } - -cleanup: - for (int i = 0; i < ARRAY_SIZE(fds); i++) { - if (fds[i].fd >= 0) { - zsock_close(fds[i].fd); - } - } -} - -static void udp_receiver_thread(void *ptr1, void *ptr2, void *ptr3) -{ - ARG_UNUSED(ptr1); - ARG_UNUSED(ptr2); - ARG_UNUSED(ptr3); - - while (true) { - k_sem_take(&udp_server_run, K_FOREVER); - - udp_server_session(); - - udp_server_running = false; - } -} - -void zperf_udp_receiver_init(void) -{ - k_thread_create(&udp_receiver_thread_data, - udp_receiver_stack_area, - K_THREAD_STACK_SIZEOF(udp_receiver_stack_area), - udp_receiver_thread, - NULL, NULL, NULL, - UDP_RECEIVER_THREAD_PRIORITY, - IS_ENABLED(CONFIG_USERSPACE) ? K_USER | - K_INHERIT_PERMS : 0, - K_NO_WAIT); + return; } int zperf_udp_download(const struct zperf_download_params *param, @@ -442,6 +435,8 @@ int zperf_udp_download(const struct zperf_download_params *param, udp_server_stop = false; memcpy(&udp_server_addr, ¶m->addr, sizeof(struct sockaddr)); + zperf_udp_receiver_init(); + k_sem_give(&udp_server_run); return 0; From 1dc8249fcd50c86f74aa6f28f57b4e5e35b56cd5 Mon Sep 17 00:00:00 2001 From: Jukka Rissanen Date: Tue, 16 Jan 2024 16:59:11 +0200 Subject: [PATCH 2493/3723] samples: net: zperf: Increase the polled fd count We need more polled fd count so that socket services work ok. Signed-off-by: Jukka Rissanen --- samples/net/zperf/prj.conf | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/samples/net/zperf/prj.conf b/samples/net/zperf/prj.conf index 39f1217d62d..230e0462333 100644 --- a/samples/net/zperf/prj.conf +++ b/samples/net/zperf/prj.conf @@ -20,7 +20,7 @@ CONFIG_NET_MAX_CONTEXTS=5 CONFIG_NET_TC_TX_COUNT=1 CONFIG_NET_SOCKETS=y CONFIG_NET_SOCKETS_POSIX_NAMES=y -CONFIG_NET_SOCKETS_POLL_MAX=4 +CONFIG_NET_SOCKETS_POLL_MAX=9 CONFIG_POSIX_MAX_FDS=8 CONFIG_INIT_STACKS=y From d3bfef8399617e4f88812f6fd0283b22a48ed05f Mon Sep 17 00:00:00 2001 From: Jukka Rissanen Date: Tue, 16 Jan 2024 16:15:58 +0200 Subject: [PATCH 2494/3723] net: shell: Do not crash if no sockets are found The "net sockets" command was not checking if there is any sockets in the system before trying to access them. Signed-off-by: Jukka Rissanen --- subsys/net/lib/shell/sockets.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/subsys/net/lib/shell/sockets.c b/subsys/net/lib/shell/sockets.c index 012c572d777..68543344888 100644 --- a/subsys/net/lib/shell/sockets.c +++ b/subsys/net/lib/shell/sockets.c @@ -147,7 +147,9 @@ static int cmd_net_sockets(const struct shell *sh, size_t argc, char *argv[]) PR("\n"); obj_type = k_obj_type_find(K_OBJ_TYPE_SOCK); - k_obj_type_walk_unlocked(obj_type, walk_sockets, (void *)&user_data); + if (obj_type != NULL) { + k_obj_type_walk_unlocked(obj_type, walk_sockets, (void *)&user_data); + } if (count.opened == 0 && count.closed == 0) { PR("No sockets found.\n"); From 38cacc7f630c553bff9abdc0bfff0ff0938f475e Mon Sep 17 00:00:00 2001 From: Jukka Rissanen Date: Tue, 16 Jan 2024 16:19:51 +0200 Subject: [PATCH 2495/3723] net: shell: Make the thread name longer for sockets command The thread name output field was a bit too short in "net sockets" command, so make it 25 char long. Signed-off-by: Jukka Rissanen --- subsys/net/lib/shell/sockets.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/subsys/net/lib/shell/sockets.c b/subsys/net/lib/shell/sockets.c index 68543344888..665eeaa1840 100644 --- a/subsys/net/lib/shell/sockets.c +++ b/subsys/net/lib/shell/sockets.c @@ -22,7 +22,7 @@ int walk_sockets(struct k_obj_core *obj_core, void *user_data) #if defined(CONFIG_THREAD_NAME) #define THREAD_NAME_LEN CONFIG_THREAD_MAX_NAME_LEN #else -#define THREAD_NAME_LEN 16 +#define THREAD_NAME_LEN 23 #endif struct sock_obj_type_raw_stats stats = { 0 }; struct net_shell_user_data *data = user_data; @@ -65,7 +65,7 @@ int walk_sockets(struct k_obj_core *obj_core, void *user_data) count->opened++; } - PR("%16s %-12s %c%c%c\t%-5s%-13d %-10" PRId64 "%-10" PRId64 "\n", + PR("%25s %-12s %c%c%c\t%-5s%-13d %-10" PRId64 "%-10" PRId64 "\n", thread_name, obj->reg->name, obj->socket_family == AF_INET6 ? '6' : (obj->socket_family ? '4' : ' '), @@ -141,7 +141,7 @@ static int cmd_net_sockets(const struct shell *sh, size_t argc, char *argv[]) user_data.sh = sh; user_data.user_data = &count; - PR("%16s %-12s %-5s\t%-5s%-14s %-10s%-10s\n", + PR("%25s %-12s %-5s\t%-5s%-14s %-10s%-10s\n", "Creator", "Name", "Flags", "FD", "Lifetime (ms)", "Sent", "Received"); PR("\n"); From 84ff0e8cdfa985b325d4e1004df6484ae1fa6fa0 Mon Sep 17 00:00:00 2001 From: Jukka Rissanen Date: Wed, 17 Jan 2024 10:15:04 +0200 Subject: [PATCH 2496/3723] net: socket: Allow user to tweak service dispatcher thread priority User is able to tweak the socket service dispatcher thread priority in order to get better performance from the system if needed. By default the dispatcher thread runs in lowest application thread priority (K_LOWEST_APPLICATION_THREAD_PRIO). Signed-off-by: Jukka Rissanen --- subsys/net/lib/sockets/Kconfig | 21 +++++++++++++++++++++ subsys/net/lib/sockets/sockets_service.c | 4 +++- 2 files changed, 24 insertions(+), 1 deletion(-) diff --git a/subsys/net/lib/sockets/Kconfig b/subsys/net/lib/sockets/Kconfig index 40d86b9498f..fbf74114d82 100644 --- a/subsys/net/lib/sockets/Kconfig +++ b/subsys/net/lib/sockets/Kconfig @@ -86,6 +86,27 @@ config NET_SOCKETS_SERVICE system needs as multiple services can be activated at the same time depending on network configuration. +config NET_SOCKETS_SERVICE_THREAD_PRIO + int "Priority of the socket service dispatcher thread" + default NUM_PREEMPT_PRIORITIES + depends on NET_SOCKETS_SERVICE + help + Set the priority of the socket service dispatcher thread. This handler + polls the sockets and either places the triggered socket to work queue + for asynchronous handlers, or calls the user supplied callback directly + for synchronous handlers. + The value should be selected carefully because if this thread priority + is too high, the work queue handlers might not be able to run if using + asynchronous handlers that are called via a work queue. + + Note that >= 0 value means preemptive thread priority, the lowest + value is NUM_PREEMPT_PRIORITIES. + Highest preemptive thread priority is 0. + Lowest cooperative thread priority is -1. + Highest cooperative thread priority is -NUM_COOP_PRIORITIES. + Make sure the priority is lower than workqueue priority so that + we never block the workqueue handler. + config NET_SOCKETS_SERVICE_STACK_SIZE int "Stack size for the thread handling socket services" default 1200 diff --git a/subsys/net/lib/sockets/sockets_service.c b/subsys/net/lib/sockets/sockets_service.c index d253ece629c..2863de005ea 100644 --- a/subsys/net/lib/sockets/sockets_service.c +++ b/subsys/net/lib/sockets/sockets_service.c @@ -279,7 +279,9 @@ static void socket_service_thread(void) K_THREAD_DEFINE(socket_service_monitor, CONFIG_NET_SOCKETS_SERVICE_STACK_SIZE, socket_service_thread, NULL, NULL, NULL, - K_LOWEST_APPLICATION_THREAD_PRIO, 0, 0); + CLAMP(CONFIG_NET_SOCKETS_SERVICE_THREAD_PRIO, + K_HIGHEST_APPLICATION_THREAD_PRIO, + K_LOWEST_APPLICATION_THREAD_PRIO), 0, 0); static int init_socket_service(void) { From 5a933299bbfe33f32a78a2e0f6e730b60bd0f18f Mon Sep 17 00:00:00 2001 From: Jukka Rissanen Date: Wed, 17 Jan 2024 18:45:09 +0200 Subject: [PATCH 2497/3723] net: socket: Change the printf modifier to print size_t correctly The argument is size_t, so change the printf modifier to %zd to avoid warning prints. Signed-off-by: Jukka Rissanen --- subsys/net/lib/sockets/sockets_service.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/subsys/net/lib/sockets/sockets_service.c b/subsys/net/lib/sockets/sockets_service.c index 2863de005ea..19efef93add 100644 --- a/subsys/net/lib/sockets/sockets_service.c +++ b/subsys/net/lib/sockets/sockets_service.c @@ -196,7 +196,7 @@ static void socket_service_thread(void) if ((count + 1) > ARRAY_SIZE(ctx.events)) { NET_WARN("You have %d services to monitor but " - "%d poll entries configured.", + "%zd poll entries configured.", count + 1, ARRAY_SIZE(ctx.events)); NET_WARN("Consider increasing value of %s to %d", "CONFIG_NET_SOCKETS_POLL_MAX", count + 1); From 63c21bb3839fbc44595e55d0db43e625436ed287 Mon Sep 17 00:00:00 2001 From: Jamie McCrae Date: Tue, 16 Jan 2024 15:52:47 +0000 Subject: [PATCH 2498/3723] mgmt: mcumgr: transport: smp_udp: Fix error when message too large Fixes an issue whereby a message which is too large was attempted to be sent via the UDP transport would wrongly give an error in value error Signed-off-by: Jamie McCrae --- subsys/mgmt/mcumgr/transport/src/smp_udp.c | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) diff --git a/subsys/mgmt/mcumgr/transport/src/smp_udp.c b/subsys/mgmt/mcumgr/transport/src/smp_udp.c index c66bae5c9b1..5975d9b6b40 100644 --- a/subsys/mgmt/mcumgr/transport/src/smp_udp.c +++ b/subsys/mgmt/mcumgr/transport/src/smp_udp.c @@ -111,7 +111,11 @@ static int smp_udp4_tx(struct net_buf *nb) ret = sendto(smp_udp_configs.ipv4.sock, nb->data, nb->len, 0, addr, sizeof(*addr)); if (ret < 0) { - ret = MGMT_ERR_EINVAL; + if (errno == ENOMEM) { + ret = MGMT_ERR_EMSGSIZE; + } else { + ret = MGMT_ERR_EINVAL; + } } else { ret = MGMT_ERR_EOK; } @@ -131,7 +135,11 @@ static int smp_udp6_tx(struct net_buf *nb) ret = sendto(smp_udp_configs.ipv6.sock, nb->data, nb->len, 0, addr, sizeof(*addr)); if (ret < 0) { - ret = MGMT_ERR_EINVAL; + if (errno == ENOMEM) { + ret = MGMT_ERR_EMSGSIZE; + } else { + ret = MGMT_ERR_EINVAL; + } } else { ret = MGMT_ERR_EOK; } From aa523a4bde27203ca451395123b96f8fcf90c3c8 Mon Sep 17 00:00:00 2001 From: Jamie McCrae Date: Tue, 16 Jan 2024 15:58:31 +0000 Subject: [PATCH 2499/3723] doc: release: 3.6: Add note on fixed MCUmgr UDP error code Adds a note about a fixed error code Signed-off-by: Jamie McCrae --- doc/releases/release-notes-3.6.rst | 3 +++ 1 file changed, 3 insertions(+) diff --git a/doc/releases/release-notes-3.6.rst b/doc/releases/release-notes-3.6.rst index d213ccba259..dfc69a17c9f 100644 --- a/doc/releases/release-notes-3.6.rst +++ b/doc/releases/release-notes-3.6.rst @@ -325,6 +325,9 @@ Libraries / Subsystems * Fixed an issue whereby the ``mcuboot erase`` DFU shell command could be used to erase the MCUboot or currently running application slot. + * Fixed an issue whereby messages that were too large to be sent over the UDP transport would + wrongly return :c:enum:`MGMT_ERR_EINVAL` instead of :c:enum:`MGMT_ERR_EMSGSIZE`. + * File systems * Modem modules From 3f4cb96f80f329b8320e2d6d25f98dca9216d569 Mon Sep 17 00:00:00 2001 From: Anas Nashif Date: Thu, 18 Jan 2024 09:05:24 -0500 Subject: [PATCH 2500/3723] tests: benchmark: fix scenario identifier Always use `benchmark.kernel.latency` as the main test identifier, variants should extend that. Signed-off-by: Anas Nashif --- tests/benchmarks/latency_measure/testcase.yaml | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/tests/benchmarks/latency_measure/testcase.yaml b/tests/benchmarks/latency_measure/testcase.yaml index 272eeb8748b..e57edecba8d 100644 --- a/tests/benchmarks/latency_measure/testcase.yaml +++ b/tests/benchmarks/latency_measure/testcase.yaml @@ -60,7 +60,7 @@ tests: # Obtain the benchmark results for various user thread / kernel thread # configurations on platforms that support user space. - benchmark.user.latency: + benchmark.kernel.latency.userspace: filter: CONFIG_ARCH_HAS_USERSPACE timeout: 300 extra_args: CONF_FILE=prj_user.conf @@ -78,7 +78,7 @@ tests: # Obtain the benchmark results with object core statistics enabled for # various user thread / kernel thread configurations on platforms that # support user space - benchmark.user.latency.objcore.stats: + benchmark.kernel.latency.userspace.objcore.stats: filter: CONFIG_ARCH_HAS_USERSPACE timeout: 300 extra_args: CONF_FILE=prj_user.conf @@ -117,7 +117,7 @@ tests: - "PROJECT EXECUTION SUCCESSFUL" # Obtain the various userspace benchmark results with timeslicing enabled - benchmark.user.latency.timeslicing: + benchmark.kernel.latency.timeslicing.userspace: filter: CONFIG_ARCH_HAS_USERSPACE timeout: 300 extra_args: CONF_FILE=prj_user.conf From a1d33f62fff989c2876e675cc101299e128acd2b Mon Sep 17 00:00:00 2001 From: Seppo Takalo Date: Thu, 18 Jan 2024 11:53:14 +0200 Subject: [PATCH 2501/3723] tests: net: lwm2m: Increase stack on all, not just X86 Increase stack size on all test platforms, not just qemu_x86. Stack overflow was seen on HW tests as well, so it might happen on many platforms. Signed-off-by: Seppo Takalo --- tests/net/lib/lwm2m/lwm2m_engine/boards/qemu_x86.conf | 1 - tests/net/lib/lwm2m/lwm2m_engine/prj.conf | 2 +- 2 files changed, 1 insertion(+), 2 deletions(-) delete mode 100644 tests/net/lib/lwm2m/lwm2m_engine/boards/qemu_x86.conf diff --git a/tests/net/lib/lwm2m/lwm2m_engine/boards/qemu_x86.conf b/tests/net/lib/lwm2m/lwm2m_engine/boards/qemu_x86.conf deleted file mode 100644 index c735e1a8a2d..00000000000 --- a/tests/net/lib/lwm2m/lwm2m_engine/boards/qemu_x86.conf +++ /dev/null @@ -1 +0,0 @@ -CONFIG_TEST_EXTRA_STACK_SIZE=1024 diff --git a/tests/net/lib/lwm2m/lwm2m_engine/prj.conf b/tests/net/lib/lwm2m/lwm2m_engine/prj.conf index 775cea846a1..5d331d20c33 100644 --- a/tests/net/lib/lwm2m/lwm2m_engine/prj.conf +++ b/tests/net/lib/lwm2m/lwm2m_engine/prj.conf @@ -1,3 +1,3 @@ CONFIG_ZTEST=y -CONFIG_ZTEST_STACK_SIZE=4096 +CONFIG_ZTEST_STACK_SIZE=5120 CONFIG_MP_MAX_NUM_CPUS=1 From 69522b8694e11a0597935169c7d5c0ece0309496 Mon Sep 17 00:00:00 2001 From: Anas Nashif Date: Thu, 18 Jan 2024 10:43:20 -0500 Subject: [PATCH 2502/3723] MAINTAINERS: add arch/Kconfig Add file to common arch area. Signed-off-by: Anas Nashif --- MAINTAINERS.yml | 1 + 1 file changed, 1 insertion(+) diff --git a/MAINTAINERS.yml b/MAINTAINERS.yml index d0e881447f2..a571bb9bde2 100644 --- a/MAINTAINERS.yml +++ b/MAINTAINERS.yml @@ -622,6 +622,7 @@ Common Architecture Interface: - dcpleung - nashif files: + - arch/Kconfig - include/zephyr/arch/ - arch/common/ - include/zephyr/arch/common/ From 5eca596d5f34001c9044d7d5bce1bae792c8b466 Mon Sep 17 00:00:00 2001 From: Flavio Ceolin Date: Tue, 16 Jan 2024 21:56:34 +0000 Subject: [PATCH 2503/3723] tests: dynamic_thread_stack: Use app defined heap Instead of using the system heap, we define our own heap in incoherent memory because stacks should be in cached memory. Signed-off-by: Flavio Ceolin --- tests/kernel/threads/dynamic_thread_stack/prj.conf | 1 - tests/kernel/threads/dynamic_thread_stack/src/main.c | 12 ++++++------ 2 files changed, 6 insertions(+), 7 deletions(-) diff --git a/tests/kernel/threads/dynamic_thread_stack/prj.conf b/tests/kernel/threads/dynamic_thread_stack/prj.conf index 3a4e7fd4159..93c54a25347 100644 --- a/tests/kernel/threads/dynamic_thread_stack/prj.conf +++ b/tests/kernel/threads/dynamic_thread_stack/prj.conf @@ -5,7 +5,6 @@ CONFIG_MAX_THREAD_BYTES=5 CONFIG_DYNAMIC_THREAD=y CONFIG_DYNAMIC_THREAD_POOL_SIZE=2 CONFIG_DYNAMIC_THREAD_ALLOC=y -CONFIG_HEAP_MEM_POOL_SIZE=20480 CONFIG_ZTEST_STACK_SIZE=2048 CONFIG_MAIN_STACK_SIZE=2048 diff --git a/tests/kernel/threads/dynamic_thread_stack/src/main.c b/tests/kernel/threads/dynamic_thread_stack/src/main.c index aa55c5f4014..5d16b57dece 100644 --- a/tests/kernel/threads/dynamic_thread_stack/src/main.c +++ b/tests/kernel/threads/dynamic_thread_stack/src/main.c @@ -9,13 +9,17 @@ #define TIMEOUT_MS 500 +#define POOL_SIZE 20480 + #ifdef CONFIG_USERSPACE #define STACK_OBJ_SIZE Z_THREAD_STACK_SIZE_ADJUST(CONFIG_DYNAMIC_THREAD_STACK_SIZE) #else #define STACK_OBJ_SIZE Z_KERNEL_STACK_SIZE_ADJUST(CONFIG_DYNAMIC_THREAD_STACK_SIZE) #endif -#define MAX_HEAP_STACKS (CONFIG_HEAP_MEM_POOL_SIZE / STACK_OBJ_SIZE) +#define MAX_HEAP_STACKS (POOL_SIZE / STACK_OBJ_SIZE) + +Z_HEAP_DEFINE_IN_SECT(stack_heap, POOL_SIZE, __incoherent); ZTEST_DMEM bool tflag[MAX(CONFIG_DYNAMIC_THREAD_POOL_SIZE, MAX_HEAP_STACKS)]; @@ -130,11 +134,7 @@ ZTEST(dynamic_thread_stack, test_dynamic_thread_stack_alloc) static void *dynamic_thread_stack_setup(void) { -#ifdef CONFIG_USERSPACE - k_thread_system_pool_assign(k_current_get()); - /* k_thread_access_grant(k_current_get(), ... ); */ -#endif - + k_thread_heap_assign(k_current_get(), &stack_heap); return NULL; } From b6e48d04f62d3aeb2afa40a2fab38baae3ea5709 Mon Sep 17 00:00:00 2001 From: Dmitrii Golovanov Date: Mon, 25 Dec 2023 16:09:18 +0100 Subject: [PATCH 2504/3723] doc: posix: Fix internal links Fix several links to other Zephyr doc sections as internal. Signed-off-by: Dmitrii Golovanov --- doc/services/portability/posix/implementation/index.rst | 4 ++-- doc/services/portability/posix/overview/index.rst | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/doc/services/portability/posix/implementation/index.rst b/doc/services/portability/posix/implementation/index.rst index 011317fef34..361b0405576 100644 --- a/doc/services/portability/posix/implementation/index.rst +++ b/doc/services/portability/posix/implementation/index.rst @@ -18,7 +18,7 @@ Unlike other multi-purpose POSIX operating systems .. note:: Unlike the Linux kernel or FreeBSD, Zephyr does not maintain a static table of system call numbers for each supported architecture, but instead generates system calls dynamically at - build time. See `System Calls `_ for more information. + build time. See `System Calls ` for more information. Design ====== @@ -73,5 +73,5 @@ Some general design considerations: } - POSIX API calls should be provided as regular callable C functions; if a Zephyr - `System Call `_ is needed as part of the implementation, the declaration and the + `System Call ` is needed as part of the implementation, the declaration and the implementation of that system call should be hidden behind the POSIX API. diff --git a/doc/services/portability/posix/overview/index.rst b/doc/services/portability/posix/overview/index.rst index 384e7c142c0..53b7df30d23 100644 --- a/doc/services/portability/posix/overview/index.rst +++ b/doc/services/portability/posix/overview/index.rst @@ -38,8 +38,8 @@ Benefits of POSIX support in Zephyr include: POSIX Subprofiles ================= -While Zephyr supports running multiple `threads `_ (possibly in an `SMP `_ -configuration), as well as `Virtual Memory and MMUs `_, Zephyr code and data +While Zephyr supports running multiple `threads ` (possibly in an `SMP ` +configuration), as well as `Virtual Memory and MMUs `, Zephyr code and data normally share a common address space. The Zephyr kernel executable code and the application executable code are typically compiled into the same binary artifact. From that perspective, Zephyr apps can be seen as running in the context of a single process. From 681330aaf0c7f403f37451fa2cef579f41bfc4a9 Mon Sep 17 00:00:00 2001 From: Markus Lassila Date: Thu, 18 Jan 2024 15:58:24 +0200 Subject: [PATCH 2505/3723] net: sockets: tls: Fix crashes in get DTLS CID socket options Get TLS_DTLS_CID_STATUS and TLS_DTLS_PEER_CID_VALUE utilize mbedtls_ssl_get_peer_cid, which expects that mbedtls_ssl_setup has been done. Signed-off-by: Markus Lassila --- subsys/net/lib/sockets/sockets_tls.c | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/subsys/net/lib/sockets/sockets_tls.c b/subsys/net/lib/sockets/sockets_tls.c index 49222758ae2..736ca7f3854 100644 --- a/subsys/net/lib/sockets/sockets_tls.c +++ b/subsys/net/lib/sockets/sockets_tls.c @@ -1769,6 +1769,10 @@ static int tls_opt_dtls_peer_connection_id_value_get(struct tls_context *context int enabled = false; int ret; + if (!context->is_initialized) { + return -ENOTCONN; + } + ret = mbedtls_ssl_get_peer_cid(&context->ssl, &enabled, optval, optlen); if (!enabled) { *optlen = 0; @@ -1794,6 +1798,10 @@ static int tls_opt_dtls_connection_id_status_get(struct tls_context *context, return -EINVAL; } + if (!context->is_initialized) { + return -ENOTCONN; + } + ret = mbedtls_ssl_get_peer_cid(&context->ssl, &enabled, cid.cid, &cid.cid_len); From c9d489d38b0cd25f35d5e33c03144c90204600d0 Mon Sep 17 00:00:00 2001 From: Alberto Escolar Piedras Date: Thu, 18 Jan 2024 13:52:52 +0100 Subject: [PATCH 2506/3723] manifest: Update nrf hw models to latest * Update the HW models module to d17c9d749c817d2522468fa3c0eee3705feb8951 Including the following: * d17c9d7 UART: Bugfix: Support STARTRX while Rx is stopping * d982e76 UART: Minor bugfix: Fix 2 warning messages * eda7af9 UART: Bugfix: Handle task STOPTX while stopping * b8ea63b UART: BugFix: Support STARTTx even if Tx is not Off * c0d28cc nrf_common: Add replacement for nrf_dma_accessible_check() * feb91bb nrfx_common replacement: nrfx_get_irq_number() Add missing peri * c95d9af Makefile: By default lets build both 52833 and 5340 targets * cf41110 UART: FIFO backend: Check for failure of fcntl Signed-off-by: Alberto Escolar Piedras --- west.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/west.yml b/west.yml index ae798440e16..ca9b67d9bfa 100644 --- a/west.yml +++ b/west.yml @@ -295,7 +295,7 @@ manifest: groups: - tools - name: nrf_hw_models - revision: 6b6ae3652c92c95edd945dce6ad9ef9892aab89b + revision: d17c9d749c817d2522468fa3c0eee3705feb8951 path: modules/bsim_hw_models/nrf_hw_models - name: open-amp revision: da78aea63159771956fe0c9263f2e6985b66e9d5 From c22ce801e7fd6badde988e52e65a4b5c10bcef88 Mon Sep 17 00:00:00 2001 From: Kapil Bhatt Date: Thu, 18 Jan 2024 15:41:09 +0530 Subject: [PATCH 2507/3723] net: wifi_shell: Add help for maximum channels in scan Add a line for scan's -c parameter which specify to take care of maximum channels. Signed-off-by: Kapil Bhatt --- subsys/net/l2/wifi/wifi_shell.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/subsys/net/l2/wifi/wifi_shell.c b/subsys/net/l2/wifi/wifi_shell.c index ad0eb9d98a2..cf4434ace31 100644 --- a/subsys/net/l2/wifi/wifi_shell.c +++ b/subsys/net/l2/wifi/wifi_shell.c @@ -1919,7 +1919,7 @@ SHELL_STATIC_SUBCMD_SET_CREATE(wifi_commands, "[-p, --dwell_time_passive ] : Passive scan dwell time (in ms) on a channel. Range 10 ms to 1000 ms\n" "[-s, --ssid] : SSID to scan for. Can be provided multiple times\n" "[-m, --max_bss ] : Maximum BSSes to scan for. Range 1 - 65535\n" - "[-c, --chans ] : Channels to be scanned. The channels must be specified in the form band1:chan1,chan2_band2:chan3,..etc. band1, band2 must be valid band values and chan1, chan2, chan3 must be specified as a list of comma separated values where each value is either a single channel or a channel range specified as chan_start-chan_end. Each band channel set has to be separated by a _. For example, a valid channel specification can be 2:1,6_5:36 or 2:1,6-11,14_5:36,163-177,52\n" + "[-c, --chans ] : Channels to be scanned. The channels must be specified in the form band1:chan1,chan2_band2:chan3,..etc. band1, band2 must be valid band values and chan1, chan2, chan3 must be specified as a list of comma separated values where each value is either a single channel or a channel range specified as chan_start-chan_end. Each band channel set has to be separated by a _. For example, a valid channel specification can be 2:1,6_5:36 or 2:1,6-11,14_5:36,163-177,52. Care should be taken to ensure that configured channels don't exceed CONFIG_WIFI_MGMT_SCAN_CHAN_MAX_MANUAL\n" "[-h, --help] : Print out the help for the scan command.\n", cmd_wifi_scan, 1, 8), From e19533382d66b2777f12d0283f7e10cc1ce89d89 Mon Sep 17 00:00:00 2001 From: Henrik Brix Andersen Date: Wed, 17 Jan 2024 19:49:24 +0100 Subject: [PATCH 2508/3723] drivers: can: add structs for common configuration and data fields Add structs and initializers for common CAN controller driver configuration and data fields. Signed-off-by: Henrik Brix Andersen --- include/zephyr/drivers/can.h | 67 ++++++++++++++++++++++++++++++++++++ 1 file changed, 67 insertions(+) diff --git a/include/zephyr/drivers/can.h b/include/zephyr/drivers/can.h index 0028abb330d..c40df027d61 100644 --- a/include/zephyr/drivers/can.h +++ b/include/zephyr/drivers/can.h @@ -325,6 +325,73 @@ typedef void (*can_state_change_callback_t)(const struct device *dev, * For internal driver use only, skip these in public documentation. */ +/** + * @brief Common CAN controller driver configuration. + * + * This structure is common to all CAN controller drivers and is expected to be the first element in + * the object pointed to by the config field in the device structure. + */ +struct can_driver_config { + /** Pointer to the device structure for the associated CAN transceiver device or NULL. */ + const struct device *phy; + /** The maximum bitrate supported by the CAN controller/transceiver combination. */ + uint32_t max_bitrate; + /** Initial CAN classic/CAN FD arbitration phase bitrate. */ + uint32_t bus_speed; + /** Initial CAN classic/CAN FD arbitration phase sample point in permille. */ + uint16_t sample_point; +#ifdef CONFIG_CAN_FD_MODE + /** Initial CAN FD data phase sample point in permille. */ + uint16_t sample_point_data; + /** Initial CAN FD data phase bitrate. */ + uint32_t bus_speed_data; +#endif /* CONFIG_CAN_FD_MODE */ +}; + +/** + * @brief Static initializer for @p can_driver_config struct + * + * @param node_id Devicetree node identifier + * @param _max_bitrate maximum bitrate supported by the CAN controller + */ +#define CAN_DT_DRIVER_CONFIG_GET(node_id, _max_bitrate) \ + { \ + .phy = DEVICE_DT_GET_OR_NULL(DT_PHANDLE(node_id, phys)), \ + .max_bitrate = DT_CAN_TRANSCEIVER_MAX_BITRATE(node_id, _max_bitrate), \ + .bus_speed = DT_PROP(node_id, bus_speed), \ + .sample_point = DT_PROP_OR(node_id, sample_point, 0), \ + IF_ENABLED(CONFIG_CAN_FD_MODE, \ + (.bus_speed_data = DT_PROP_OR(node_id, bus_speed_data, 0), \ + .sample_point_data = DT_PROP_OR(node_id, sample_point_data, 0),)) \ + } + +/** + * @brief Static initializer for @p can_driver_config struct from DT_DRV_COMPAT instance + * + * @param inst DT_DRV_COMPAT instance number + * @param _max_bitrate maximum bitrate supported by the CAN controller + * @see CAN_DT_DRIVER_CONFIG_GET() + */ +#define CAN_DT_DRIVER_CONFIG_INST_GET(inst, _max_bitrate) \ + CAN_DT_DRIVER_CONFIG_GET(DT_DRV_INST(inst), _max_bitrate) + +/** + * @brief Common CAN controller driver data. + * + * This structure is common to all CAN controller drivers and is expected to be the first element in + * the driver's struct driver_data declaration. + */ +struct can_driver_data { + /** Current CAN controller mode. */ + can_mode_t mode; + /** True if the CAN controller is started, false otherwise. */ + bool started; + /** State change callback function pointer or NULL. */ + can_state_change_callback_t state_change_cb; + /** State change callback user data pointer or NULL. */ + void *state_change_cb_user_data; +}; + /** * @brief Callback API upon setting CAN bus timing * See @a can_set_timing() for argument description From 38565a18fa3ebd1027e2147f485880c888cb1ca3 Mon Sep 17 00:00:00 2001 From: Henrik Brix Andersen Date: Wed, 17 Jan 2024 19:51:18 +0100 Subject: [PATCH 2509/3723] drivers: can: loopback: use common config and data structures Use the common CAN controller driver configuration and data structures. Signed-off-by: Henrik Brix Andersen --- drivers/can/can_loopback.c | 34 ++++++++++++++-------------------- 1 file changed, 14 insertions(+), 20 deletions(-) diff --git a/drivers/can/can_loopback.c b/drivers/can/can_loopback.c index 863bf3a69ac..02f32b93c7a 100644 --- a/drivers/can/can_loopback.c +++ b/drivers/can/can_loopback.c @@ -29,16 +29,12 @@ struct can_loopback_filter { }; struct can_loopback_data { + struct can_driver_data common; struct can_loopback_filter filters[CONFIG_CAN_MAX_FILTER]; struct k_mutex mtx; struct k_msgq tx_msgq; char msgq_buffer[CONFIG_CAN_LOOPBACK_TX_MSGQ_SIZE * sizeof(struct can_loopback_frame)]; struct k_thread tx_thread_data; - bool started; - bool loopback; -#ifdef CONFIG_CAN_FD_MODE - bool fd; -#endif /* CONFIG_CAN_FD_MODE */ K_KERNEL_STACK_MEMBER(tx_thread_stack, CONFIG_CAN_LOOPBACK_TX_THREAD_STACK_SIZE); @@ -77,7 +73,7 @@ static void tx_thread(void *arg1, void *arg2, void *arg3) } frame.cb(dev, 0, frame.cb_arg); - if (!data->loopback) { + if ((data->common.mode & CAN_MODE_LOOPBACK) == 0U) { continue; } @@ -120,7 +116,7 @@ static int can_loopback_send(const struct device *dev, } if ((frame->flags & CAN_FRAME_FDF) != 0) { - if (!data->fd) { + if ((data->common.mode & CAN_MODE_FD) == 0U) { return -ENOTSUP; } @@ -138,7 +134,7 @@ static int can_loopback_send(const struct device *dev, return -EINVAL; } - if (!data->started) { + if (!data->common.started) { return -ENETDOWN; } @@ -239,11 +235,11 @@ static int can_loopback_start(const struct device *dev) { struct can_loopback_data *data = dev->data; - if (data->started) { + if (data->common.started) { return -EALREADY; } - data->started = true; + data->common.started = true; return 0; } @@ -252,11 +248,11 @@ static int can_loopback_stop(const struct device *dev) { struct can_loopback_data *data = dev->data; - if (!data->started) { + if (!data->common.started) { return -EALREADY; } - data->started = false; + data->common.started = false; k_msgq_purge(&data->tx_msgq); @@ -267,7 +263,7 @@ static int can_loopback_set_mode(const struct device *dev, can_mode_t mode) { struct can_loopback_data *data = dev->data; - if (data->started) { + if (data->common.started) { return -EBUSY; } @@ -276,8 +272,6 @@ static int can_loopback_set_mode(const struct device *dev, can_mode_t mode) LOG_ERR("unsupported mode: 0x%08x", mode); return -ENOTSUP; } - - data->fd = (mode & CAN_MODE_FD) != 0; #else if ((mode & ~(CAN_MODE_LOOPBACK)) != 0) { LOG_ERR("unsupported mode: 0x%08x", mode); @@ -285,7 +279,7 @@ static int can_loopback_set_mode(const struct device *dev, can_mode_t mode) } #endif /* CONFIG_CAN_FD_MODE */ - data->loopback = (mode & CAN_MODE_LOOPBACK) != 0; + data->common.mode = mode; return 0; } @@ -297,7 +291,7 @@ static int can_loopback_set_timing(const struct device *dev, ARG_UNUSED(timing); - if (data->started) { + if (data->common.started) { return -EBUSY; } @@ -312,7 +306,7 @@ static int can_loopback_set_timing_data(const struct device *dev, ARG_UNUSED(timing); - if (data->started) { + if (data->common.started) { return -EBUSY; } @@ -326,7 +320,7 @@ static int can_loopback_get_state(const struct device *dev, enum can_state *stat struct can_loopback_data *data = dev->data; if (state != NULL) { - if (data->started) { + if (data->common.started) { *state = CAN_STATE_ERROR_ACTIVE; } else { *state = CAN_STATE_STOPPED; @@ -348,7 +342,7 @@ static int can_loopback_recover(const struct device *dev, k_timeout_t timeout) ARG_UNUSED(timeout); - if (!data->started) { + if (!data->common.started) { return -ENETDOWN; } From c71ae7d7c5aca7e5a568b1eccdf7a3186daa8626 Mon Sep 17 00:00:00 2001 From: Henrik Brix Andersen Date: Wed, 17 Jan 2024 19:52:24 +0100 Subject: [PATCH 2510/3723] drivers: can: mcan: use common config and data structures Use the common CAN controller driver configuration and data structures. Signed-off-by: Henrik Brix Andersen --- drivers/can/can_mcan.c | 68 ++++++++++++++------------- include/zephyr/drivers/can/can_mcan.h | 26 ++-------- 2 files changed, 39 insertions(+), 55 deletions(-) diff --git a/drivers/can/can_mcan.c b/drivers/can/can_mcan.c index 529f2ed7dff..d45eca62d47 100644 --- a/drivers/can/can_mcan.c +++ b/drivers/can/can_mcan.c @@ -200,7 +200,7 @@ int can_mcan_set_timing(const struct device *dev, const struct can_timing *timin uint32_t nbtp = 0U; int err; - if (data->started) { + if (data->common.started) { return -EBUSY; } @@ -229,7 +229,7 @@ int can_mcan_set_timing_data(const struct device *dev, const struct can_timing * uint32_t dbtp = 0U; int err; - if (data->started) { + if (data->common.started) { return -EBUSY; } @@ -271,12 +271,12 @@ int can_mcan_start(const struct device *dev) struct can_mcan_data *data = dev->data; int err; - if (data->started) { + if (data->common.started) { return -EALREADY; } - if (config->phy != NULL) { - err = can_transceiver_enable(config->phy); + if (config->common.phy != NULL) { + err = can_transceiver_enable(config->common.phy); if (err != 0) { LOG_ERR("failed to enable CAN transceiver (err %d)", err); return err; @@ -290,15 +290,15 @@ int can_mcan_start(const struct device *dev) if (err != 0) { LOG_ERR("failed to leave init mode"); - if (config->phy != NULL) { + if (config->common.phy != NULL) { /* Attempt to disable the CAN transceiver in case of error */ - (void)can_transceiver_disable(config->phy); + (void)can_transceiver_disable(config->common.phy); } return -EIO; } - data->started = true; + data->common.started = true; return 0; } @@ -312,7 +312,7 @@ int can_mcan_stop(const struct device *dev) uint32_t tx_idx; int err; - if (!data->started) { + if (!data->common.started) { return -EALREADY; } @@ -323,8 +323,8 @@ int can_mcan_stop(const struct device *dev) return -EIO; } - if (config->phy != NULL) { - err = can_transceiver_disable(config->phy); + if (config->common.phy != NULL) { + err = can_transceiver_disable(config->common.phy); if (err != 0) { LOG_ERR("failed to disable CAN transceiver (err %d)", err); return err; @@ -333,7 +333,7 @@ int can_mcan_stop(const struct device *dev) can_mcan_enable_configuration_change(dev); - data->started = false; + data->common.started = false; for (tx_idx = 0U; tx_idx < cbs->num_tx; tx_idx++) { tx_cb = cbs->tx[tx_idx].function; @@ -367,7 +367,7 @@ int can_mcan_set_mode(const struct device *dev, can_mode_t mode) } #endif /* !CONFIG_CAN_FD_MODE */ - if (data->started) { + if (data->common.started) { return -EBUSY; } @@ -401,10 +401,8 @@ int can_mcan_set_mode(const struct device *dev, can_mode_t mode) #ifdef CONFIG_CAN_FD_MODE if ((mode & CAN_MODE_FD) != 0) { cccr |= CAN_MCAN_CCCR_FDOE | CAN_MCAN_CCCR_BRSE; - data->fd = true; } else { cccr &= ~(CAN_MCAN_CCCR_FDOE | CAN_MCAN_CCCR_BRSE); - data->fd = false; } #endif /* CONFIG_CAN_FD_MODE */ @@ -418,6 +416,8 @@ int can_mcan_set_mode(const struct device *dev, can_mode_t mode) goto unlock; } + data->common.mode = mode; + unlock: k_mutex_unlock(&data->lock); @@ -427,8 +427,8 @@ int can_mcan_set_mode(const struct device *dev, can_mode_t mode) static void can_mcan_state_change_handler(const struct device *dev) { struct can_mcan_data *data = dev->data; - const can_state_change_callback_t cb = data->state_change_cb; - void *cb_data = data->state_change_cb_data; + const can_state_change_callback_t cb = data->common.state_change_cb; + void *cb_data = data->common.state_change_cb_user_data; struct can_bus_err_cnt err_cnt; enum can_state state; @@ -802,7 +802,7 @@ int can_mcan_get_state(const struct device *dev, enum can_state *state, return err; } - if (!data->started) { + if (!data->common.started) { *state = CAN_STATE_STOPPED; } else if ((reg & CAN_MCAN_PSR_BO) != 0U) { *state = CAN_STATE_BUS_OFF; @@ -833,7 +833,7 @@ int can_mcan_recover(const struct device *dev, k_timeout_t timeout) { struct can_mcan_data *data = dev->data; - if (!data->started) { + if (!data->common.started) { return -ENETDOWN; } @@ -881,7 +881,8 @@ int can_mcan_send(const struct device *dev, const struct can_frame *frame, k_tim return -ENOTSUP; } - if (!data->fd && ((frame->flags & (CAN_FRAME_FDF | CAN_FRAME_BRS)) != 0U)) { + if ((data->common.mode & CAN_MODE_FD) == 0U && + ((frame->flags & (CAN_FRAME_FDF | CAN_FRAME_BRS)) != 0U)) { LOG_ERR("CAN FD format not supported in non-FD mode"); return -ENOTSUP; } @@ -910,7 +911,7 @@ int can_mcan_send(const struct device *dev, const struct can_frame *frame, k_tim } } - if (!data->started) { + if (!data->common.started) { return -ENETDOWN; } @@ -1193,15 +1194,15 @@ void can_mcan_set_state_change_callback(const struct device *dev, { struct can_mcan_data *data = dev->data; - data->state_change_cb = callback; - data->state_change_cb_data = user_data; + data->common.state_change_cb = callback; + data->common.state_change_cb_user_data = user_data; } int can_mcan_get_max_bitrate(const struct device *dev, uint32_t *max_bitrate) { const struct can_mcan_config *config = dev->config; - *max_bitrate = config->max_bitrate; + *max_bitrate = config->common.max_bitrate; return 0; } @@ -1354,8 +1355,8 @@ int can_mcan_init(const struct device *dev) k_mutex_init(&data->tx_mtx); k_sem_init(&data->tx_sem, cbs->num_tx, cbs->num_tx); - if (config->phy != NULL) { - if (!device_is_ready(config->phy)) { + if (config->common.phy != NULL) { + if (!device_is_ready(config->common.phy)) { LOG_ERR("CAN transceiver not ready"); return -ENODEV; } @@ -1450,8 +1451,9 @@ int can_mcan_init(const struct device *dev) return err; } - if (config->sample_point) { - err = can_calc_timing(dev, &timing, config->bus_speed, config->sample_point); + if (config->common.sample_point) { + err = can_calc_timing(dev, &timing, config->common.bus_speed, + config->common.sample_point); if (err == -EINVAL) { LOG_ERR("Can't find timing for given param"); return -EIO; @@ -1464,15 +1466,15 @@ int can_mcan_init(const struct device *dev) timing.prop_seg = 0U; timing.phase_seg1 = config->prop_ts1; timing.phase_seg2 = config->ts2; - err = can_calc_prescaler(dev, &timing, config->bus_speed); + err = can_calc_prescaler(dev, &timing, config->common.bus_speed); if (err != 0) { LOG_WRN("Bitrate error: %d", err); } } #ifdef CONFIG_CAN_FD_MODE - if (config->sample_point_data) { - err = can_calc_timing_data(dev, &timing_data, config->bus_speed_data, - config->sample_point_data); + if (config->common.sample_point_data) { + err = can_calc_timing_data(dev, &timing_data, config->common.bus_speed_data, + config->common.sample_point_data); if (err == -EINVAL) { LOG_ERR("Can't find timing for given dataphase param"); return -EIO; @@ -1484,7 +1486,7 @@ int can_mcan_init(const struct device *dev) timing_data.prop_seg = 0U; timing_data.phase_seg1 = config->prop_ts1_data; timing_data.phase_seg2 = config->ts2_data; - err = can_calc_prescaler(dev, &timing_data, config->bus_speed_data); + err = can_calc_prescaler(dev, &timing_data, config->common.bus_speed_data); if (err != 0) { LOG_WRN("Dataphase bitrate error: %d", err); } diff --git a/include/zephyr/drivers/can/can_mcan.h b/include/zephyr/drivers/can/can_mcan.h index b29adc857f7..86d0ad6fd38 100644 --- a/include/zephyr/drivers/can/can_mcan.h +++ b/include/zephyr/drivers/can/can_mcan.h @@ -1061,15 +1061,10 @@ struct can_mcan_ext_filter { * @brief Bosch M_CAN driver internal data structure. */ struct can_mcan_data { + struct can_driver_data common; struct k_mutex lock; struct k_sem tx_sem; struct k_mutex tx_mtx; - can_state_change_callback_t state_change_cb; - void *state_change_cb_data; - bool started; -#ifdef CONFIG_CAN_FD_MODE - bool fd; -#endif /* CONFIG_CAN_FD_MODE */ void *custom; } __aligned(4); @@ -1237,26 +1232,21 @@ struct can_mcan_callbacks { * @brief Bosch M_CAN driver internal configuration structure. */ struct can_mcan_config { + const struct can_driver_config common; const struct can_mcan_ops *ops; const struct can_mcan_callbacks *callbacks; uint16_t mram_elements[CAN_MCAN_MRAM_CFG_NUM_CELLS]; uint16_t mram_offsets[CAN_MCAN_MRAM_CFG_NUM_CELLS]; size_t mram_size; - uint32_t bus_speed; uint16_t sjw; - uint16_t sample_point; uint16_t prop_ts1; uint16_t ts2; #ifdef CONFIG_CAN_FD_MODE - uint32_t bus_speed_data; - uint16_t sample_point_data; uint8_t sjw_data; uint8_t prop_ts1_data; uint8_t ts2_data; uint8_t tx_delay_comp_offset; #endif - const struct device *phy; - uint32_t max_bitrate; const void *custom; }; @@ -1311,42 +1301,34 @@ struct can_mcan_config { #ifdef CONFIG_CAN_FD_MODE #define CAN_MCAN_DT_CONFIG_GET(node_id, _custom, _ops, _cbs) \ { \ + .common = CAN_DT_DRIVER_CONFIG_GET(node_id, 8000000), \ .ops = _ops, \ .callbacks = _cbs, \ .mram_elements = CAN_MCAN_DT_MRAM_ELEMENTS_GET(node_id), \ .mram_offsets = CAN_MCAN_DT_MRAM_OFFSETS_GET(node_id), \ .mram_size = CAN_MCAN_DT_MRAM_ELEMENTS_SIZE(node_id), \ - .bus_speed = DT_PROP(node_id, bus_speed), \ .sjw = DT_PROP(node_id, sjw), \ - .sample_point = DT_PROP_OR(node_id, sample_point, 0), \ .prop_ts1 = DT_PROP_OR(node_id, prop_seg, 0) + DT_PROP_OR(node_id, phase_seg1, 0), \ .ts2 = DT_PROP_OR(node_id, phase_seg2, 0), \ - .bus_speed_data = DT_PROP(node_id, bus_speed_data), \ .sjw_data = DT_PROP(node_id, sjw_data), \ - .sample_point_data = DT_PROP_OR(node_id, sample_point_data, 0), \ .prop_ts1_data = DT_PROP_OR(node_id, prop_seg_data, 0) + \ DT_PROP_OR(node_id, phase_seg1_data, 0), \ .ts2_data = DT_PROP_OR(node_id, phase_seg2_data, 0), \ .tx_delay_comp_offset = DT_PROP(node_id, tx_delay_comp_offset), \ - .phy = DEVICE_DT_GET_OR_NULL(DT_PHANDLE(node_id, phys)), \ - .max_bitrate = DT_CAN_TRANSCEIVER_MAX_BITRATE(node_id, 8000000), \ .custom = _custom, \ } #else /* CONFIG_CAN_FD_MODE */ #define CAN_MCAN_DT_CONFIG_GET(node_id, _custom, _ops, _cbs) \ { \ + .common = CAN_DT_DRIVER_CONFIG_GET(node_id, 8000000), \ .ops = _ops, \ .callbacks = _cbs, \ .mram_elements = CAN_MCAN_DT_MRAM_ELEMENTS_GET(node_id), \ .mram_offsets = CAN_MCAN_DT_MRAM_OFFSETS_GET(node_id), \ .mram_size = CAN_MCAN_DT_MRAM_ELEMENTS_SIZE(node_id), \ - .bus_speed = DT_PROP(node_id, bus_speed), \ .sjw = DT_PROP(node_id, sjw), \ - .sample_point = DT_PROP_OR(node_id, sample_point, 0), \ .prop_ts1 = DT_PROP_OR(node_id, prop_seg, 0) + DT_PROP_OR(node_id, phase_seg1, 0), \ .ts2 = DT_PROP_OR(node_id, phase_seg2, 0), \ - .phy = DEVICE_DT_GET_OR_NULL(DT_PHANDLE(node_id, phys)), \ - .max_bitrate = DT_CAN_TRANSCEIVER_MAX_BITRATE(node_id, 1000000), \ .custom = _custom, \ } #endif /* !CONFIG_CAN_FD_MODE */ From b41714b1a6be49ce121fb103ae44ae0a2c5222a7 Mon Sep 17 00:00:00 2001 From: Henrik Brix Andersen Date: Wed, 17 Jan 2024 19:52:49 +0100 Subject: [PATCH 2511/3723] drivers: can: sja1000: use common config and data structures Use the common CAN controller driver configuration and data structures. Signed-off-by: Henrik Brix Andersen --- drivers/can/can_esp32_twai.c | 4 +- drivers/can/can_sja1000.c | 63 ++++++++++++------------ include/zephyr/drivers/can/can_sja1000.h | 23 ++++----- 3 files changed, 43 insertions(+), 47 deletions(-) diff --git a/drivers/can/can_esp32_twai.c b/drivers/can/can_esp32_twai.c index 2fd379d0049..3545bb9fa9e 100644 --- a/drivers/can/can_esp32_twai.c +++ b/drivers/can/can_esp32_twai.c @@ -119,7 +119,7 @@ static int can_esp32_twai_set_timing(const struct device *dev, const struct can_ uint8_t btr0; uint8_t btr1; - if (data->started) { + if (data->common.started) { return -EBUSY; } @@ -130,7 +130,7 @@ static int can_esp32_twai_set_timing(const struct device *dev, const struct can_ btr1 = TWAI_TIME_SEG1_PREP(timing->phase_seg1 - 1) | TWAI_TIME_SEG2_PREP(timing->phase_seg2 - 1); - if ((data->mode & CAN_MODE_3_SAMPLES) != 0) { + if ((data->common.mode & CAN_MODE_3_SAMPLES) != 0) { btr1 |= TWAI_TIME_SAMP; } diff --git a/drivers/can/can_sja1000.c b/drivers/can/can_sja1000.c index 571fc2fb040..b0eac60063f 100644 --- a/drivers/can/can_sja1000.c +++ b/drivers/can/can_sja1000.c @@ -111,7 +111,7 @@ int can_sja1000_set_timing(const struct device *dev, const struct can_timing *ti uint8_t btr0; uint8_t btr1; - if (data->started) { + if (data->common.started) { return -EBUSY; } @@ -122,7 +122,7 @@ int can_sja1000_set_timing(const struct device *dev, const struct can_timing *ti btr1 = CAN_SJA1000_BTR1_TSEG1_PREP(timing->phase_seg1 - 1) | CAN_SJA1000_BTR1_TSEG2_PREP(timing->phase_seg2 - 1); - if ((data->mode & CAN_MODE_3_SAMPLES) != 0) { + if ((data->common.mode & CAN_MODE_3_SAMPLES) != 0) { btr1 |= CAN_SJA1000_BTR1_SAM; } @@ -150,12 +150,12 @@ int can_sja1000_start(const struct device *dev) struct can_sja1000_data *data = dev->data; int err; - if (data->started) { + if (data->common.started) { return -EALREADY; } - if (config->phy != NULL) { - err = can_transceiver_enable(config->phy); + if (config->common.phy != NULL) { + err = can_transceiver_enable(config->common.phy); if (err != 0) { LOG_ERR("failed to enable CAN transceiver (err %d)", err); return err; @@ -167,15 +167,15 @@ int can_sja1000_start(const struct device *dev) err = can_sja1000_leave_reset_mode(dev); if (err != 0) { - if (config->phy != NULL) { + if (config->common.phy != NULL) { /* Attempt to disable the CAN transceiver in case of error */ - (void)can_transceiver_disable(config->phy); + (void)can_transceiver_disable(config->common.phy); } return err; } - data->started = true; + data->common.started = true; return 0; } @@ -186,7 +186,7 @@ int can_sja1000_stop(const struct device *dev) struct can_sja1000_data *data = dev->data; int err; - if (!data->started) { + if (!data->common.started) { return -EALREADY; } @@ -196,15 +196,15 @@ int can_sja1000_stop(const struct device *dev) return err; } - if (config->phy != NULL) { - err = can_transceiver_disable(config->phy); + if (config->common.phy != NULL) { + err = can_transceiver_disable(config->common.phy); if (err != 0) { LOG_ERR("failed to disable CAN transceiver (err %d)", err); return err; } } - data->started = false; + data->common.started = false; can_sja1000_tx_done(dev, -ENETDOWN); @@ -223,7 +223,7 @@ int can_sja1000_set_mode(const struct device *dev, can_mode_t mode) return -ENOTSUP; } - if (data->started) { + if (data->common.started) { return -EBUSY; } @@ -255,7 +255,7 @@ int can_sja1000_set_mode(const struct device *dev, can_mode_t mode) can_sja1000_write_reg(dev, CAN_SJA1000_MOD, mod); can_sja1000_write_reg(dev, CAN_SJA1000_BTR1, btr1); - data->mode = mode; + data->common.mode = mode; k_mutex_unlock(&data->mod_lock); @@ -381,7 +381,7 @@ int can_sja1000_send(const struct device *dev, const struct can_frame *frame, k_ return -ENOTSUP; } - if (!data->started) { + if (!data->common.started) { return -ENETDOWN; } @@ -405,13 +405,13 @@ int can_sja1000_send(const struct device *dev, const struct can_frame *frame, k_ can_sja1000_write_frame(dev, frame); - if ((data->mode & CAN_MODE_LOOPBACK) != 0) { + if ((data->common.mode & CAN_MODE_LOOPBACK) != 0) { cmr = CAN_SJA1000_CMR_SRR; } else { cmr = CAN_SJA1000_CMR_TR; } - if ((data->mode & CAN_MODE_ONE_SHOT) != 0) { + if ((data->common.mode & CAN_MODE_ONE_SHOT) != 0) { cmr |= CAN_SJA1000_CMR_AT; } @@ -472,7 +472,7 @@ int can_sja1000_recover(const struct device *dev, k_timeout_t timeout) uint8_t sr; int err; - if (!data->started) { + if (!data->common.started) { return -ENETDOWN; } @@ -517,7 +517,7 @@ int can_sja1000_get_state(const struct device *dev, enum can_state *state, struct can_sja1000_data *data = dev->data; if (state != NULL) { - if (!data->started) { + if (!data->common.started) { *state = CAN_STATE_STOPPED; } else { *state = data->state; @@ -537,8 +537,8 @@ void can_sja1000_set_state_change_callback(const struct device *dev, { struct can_sja1000_data *data = dev->data; - data->state_change_cb = callback; - data->state_change_cb_data = user_data; + data->common.state_change_cb = callback; + data->common.state_change_cb_user_data = user_data; } int can_sja1000_get_max_filters(const struct device *dev, bool ide) @@ -553,7 +553,7 @@ int can_sja1000_get_max_bitrate(const struct device *dev, uint32_t *max_bitrate) { const struct can_sja1000_config *config = dev->config; - *max_bitrate = config->max_bitrate; + *max_bitrate = config->common.max_bitrate; return 0; } @@ -663,7 +663,7 @@ static void can_sja1000_handle_error_warning_irq(const struct device *dev) data->state = CAN_STATE_BUS_OFF; can_sja1000_tx_done(dev, -ENETUNREACH); #ifdef CONFIG_CAN_AUTO_BUS_OFF_RECOVERY - if (data->started) { + if (data->common.started) { can_sja1000_leave_reset_mode_nowait(dev); } #endif /* CONFIG_CAN_AUTO_BUS_OFF_RECOVERY */ @@ -688,8 +688,8 @@ static void can_sja1000_handle_error_passive_irq(const struct device *dev) void can_sja1000_isr(const struct device *dev) { struct can_sja1000_data *data = dev->data; - const can_state_change_callback_t cb = data->state_change_cb; - void *cb_data = data->state_change_cb_data; + const can_state_change_callback_t cb = data->common.state_change_cb; + void *cb_data = data->common.state_change_cb_user_data; enum can_state prev_state = data->state; struct can_bus_err_cnt err_cnt; uint8_t ir; @@ -739,8 +739,8 @@ int can_sja1000_init(const struct device *dev) __ASSERT_NO_MSG(config->read_reg != NULL); __ASSERT_NO_MSG(config->write_reg != NULL); - if (config->phy != NULL) { - if (!device_is_ready(config->phy)) { + if (config->common.phy != NULL) { + if (!device_is_ready(config->common.phy)) { LOG_ERR("CAN transceiver not ready"); return -ENODEV; } @@ -773,8 +773,9 @@ int can_sja1000_init(const struct device *dev) can_sja1000_write_reg(dev, CAN_SJA1000_AMR2, 0xFF); can_sja1000_write_reg(dev, CAN_SJA1000_AMR3, 0xFF); - if (config->sample_point != 0) { - err = can_calc_timing(dev, &timing, config->bitrate, config->sample_point); + if (config->common.sample_point != 0) { + err = can_calc_timing(dev, &timing, config->common.bus_speed, + config->common.sample_point); if (err == -EINVAL) { LOG_ERR("bitrate/sample point cannot be met (err %d)", err); return err; @@ -787,7 +788,7 @@ int can_sja1000_init(const struct device *dev) timing.phase_seg1 = config->phase_seg1; timing.phase_seg2 = config->phase_seg2; - err = can_calc_prescaler(dev, &timing, config->bitrate); + err = can_calc_prescaler(dev, &timing, config->common.bus_speed); if (err != 0) { LOG_WRN("initial bitrate error: %d", err); } @@ -810,7 +811,7 @@ int can_sja1000_init(const struct device *dev) can_sja1000_write_reg(dev, CAN_SJA1000_EWLR, 96); /* Set normal mode */ - data->mode = CAN_MODE_NORMAL; + data->common.mode = CAN_MODE_NORMAL; err = can_sja1000_set_mode(dev, CAN_MODE_NORMAL); if (err != 0) { return err; diff --git a/include/zephyr/drivers/can/can_sja1000.h b/include/zephyr/drivers/can/can_sja1000.h index fe826296db9..2a5c0edd8ae 100644 --- a/include/zephyr/drivers/can/can_sja1000.h +++ b/include/zephyr/drivers/can/can_sja1000.h @@ -102,15 +102,12 @@ typedef uint8_t (*can_sja1000_read_reg_t)(const struct device *dev, uint8_t reg) * @brief SJA1000 driver internal configuration structure. */ struct can_sja1000_config { + const struct can_driver_config common; can_sja1000_read_reg_t read_reg; can_sja1000_write_reg_t write_reg; - uint32_t bitrate; - uint32_t sample_point; uint32_t sjw; uint32_t phase_seg1; uint32_t phase_seg2; - const struct device *phy; - uint32_t max_bitrate; uint8_t ocr; uint8_t cdr; const void *custom; @@ -128,14 +125,15 @@ struct can_sja1000_config { */ #define CAN_SJA1000_DT_CONFIG_GET(node_id, _custom, _read_reg, _write_reg, _ocr, _cdr) \ { \ - .read_reg = _read_reg, .write_reg = _write_reg, \ - .bitrate = DT_PROP(node_id, bus_speed), .sjw = DT_PROP(node_id, sjw), \ + .common = CAN_DT_DRIVER_CONFIG_GET(node_id, 1000000), \ + .read_reg = _read_reg, \ + .write_reg = _write_reg, \ + .sjw = DT_PROP(node_id, sjw), \ .phase_seg1 = DT_PROP_OR(node_id, phase_seg1, 0), \ .phase_seg2 = DT_PROP_OR(node_id, phase_seg2, 0), \ - .sample_point = DT_PROP_OR(node_id, sample_point, 0), \ - .max_bitrate = DT_CAN_TRANSCEIVER_MAX_BITRATE(node_id, 1000000), \ - .phy = DEVICE_DT_GET_OR_NULL(DT_PHANDLE(node_id, phys)), \ - .ocr = _ocr, .cdr = _cdr, .custom = _custom, \ + .ocr = _ocr, \ + .cdr = _cdr, \ + .custom = _custom, \ } /** @@ -165,14 +163,11 @@ struct can_sja1000_rx_filter { * @brief SJA1000 driver internal data structure. */ struct can_sja1000_data { + struct can_driver_data common; ATOMIC_DEFINE(rx_allocs, CONFIG_CAN_MAX_FILTER); struct can_sja1000_rx_filter filters[CONFIG_CAN_MAX_FILTER]; struct k_mutex mod_lock; - bool started; - can_mode_t mode; enum can_state state; - can_state_change_callback_t state_change_cb; - void *state_change_cb_data; struct k_sem tx_idle; can_tx_callback_t tx_callback; void *tx_user_data; From 9051824fa3f1b2d22163e27abef8061c6242464e Mon Sep 17 00:00:00 2001 From: Henrik Brix Andersen Date: Wed, 17 Jan 2024 19:53:17 +0100 Subject: [PATCH 2512/3723] drivers: can: stm32: bxcan: use common config and data structures Use the common CAN controller driver configuration and data structures. Signed-off-by: Henrik Brix Andersen --- drivers/can/can_stm32_bxcan.c | 66 +++++++++++++++-------------------- 1 file changed, 29 insertions(+), 37 deletions(-) diff --git a/drivers/can/can_stm32_bxcan.c b/drivers/can/can_stm32_bxcan.c index 58df8f1db5d..71ac02cb202 100644 --- a/drivers/can/can_stm32_bxcan.c +++ b/drivers/can/can_stm32_bxcan.c @@ -66,6 +66,7 @@ struct can_stm32_mailbox { }; struct can_stm32_data { + struct can_driver_data common; struct k_mutex inst_mutex; struct k_sem tx_int_sem; struct can_stm32_mailbox mb0; @@ -75,25 +76,19 @@ struct can_stm32_data { can_rx_callback_t rx_cb_ext[CONFIG_CAN_MAX_EXT_ID_FILTER]; void *cb_arg_std[CONFIG_CAN_MAX_STD_ID_FILTER]; void *cb_arg_ext[CONFIG_CAN_MAX_EXT_ID_FILTER]; - can_state_change_callback_t state_change_cb; - void *state_change_cb_data; enum can_state state; - bool started; }; struct can_stm32_config { + const struct can_driver_config common; CAN_TypeDef *can; /*!< CAN Registers*/ CAN_TypeDef *master_can; /*!< CAN Registers for shared filter */ - uint32_t bus_speed; - uint16_t sample_point; uint8_t sjw; uint8_t prop_ts1; uint8_t ts2; struct stm32_pclken pclken; void (*config_irq)(CAN_TypeDef *can); const struct pinctrl_dev_config *pcfg; - const struct device *phy; - uint32_t max_bitrate; }; /* @@ -187,7 +182,7 @@ static int can_stm32_get_state(const struct device *dev, enum can_state *state, CAN_TypeDef *can = cfg->can; if (state != NULL) { - if (!data->started) { + if (!data->common.started) { *state = CAN_STATE_STOPPED; } else if (can->ESR & CAN_ESR_BOFF) { *state = CAN_STATE_BUS_OFF; @@ -215,8 +210,8 @@ static inline void can_stm32_bus_state_change_isr(const struct device *dev) struct can_stm32_data *data = dev->data; struct can_bus_err_cnt err_cnt; enum can_state state; - const can_state_change_callback_t cb = data->state_change_cb; - void *state_change_cb_data = data->state_change_cb_data; + const can_state_change_callback_t cb = data->common.state_change_cb; + void *state_change_cb_data = data->common.state_change_cb_user_data; #ifdef CONFIG_CAN_STATS const struct can_stm32_config *cfg = dev->config; @@ -418,13 +413,13 @@ static int can_stm32_start(const struct device *dev) k_mutex_lock(&data->inst_mutex, K_FOREVER); - if (data->started) { + if (data->common.started) { ret = -EALREADY; goto unlock; } - if (cfg->phy != NULL) { - ret = can_transceiver_enable(cfg->phy); + if (cfg->common.phy != NULL) { + ret = can_transceiver_enable(cfg->common.phy); if (ret != 0) { LOG_ERR("failed to enable CAN transceiver (err %d)", ret); goto unlock; @@ -437,16 +432,16 @@ static int can_stm32_start(const struct device *dev) if (ret < 0) { LOG_ERR("Failed to leave init mode"); - if (cfg->phy != NULL) { + if (cfg->common.phy != NULL) { /* Attempt to disable the CAN transceiver in case of error */ - (void)can_transceiver_disable(cfg->phy); + (void)can_transceiver_disable(cfg->common.phy); } ret = -EIO; goto unlock; } - data->started = true; + data->common.started = true; unlock: k_mutex_unlock(&data->inst_mutex); @@ -463,7 +458,7 @@ static int can_stm32_stop(const struct device *dev) k_mutex_lock(&data->inst_mutex, K_FOREVER); - if (!data->started) { + if (!data->common.started) { ret = -EALREADY; goto unlock; } @@ -481,15 +476,15 @@ static int can_stm32_stop(const struct device *dev) can_stm32_signal_tx_complete(dev, &data->mb2, -ENETDOWN); can->TSR |= CAN_TSR_ABRQ2 | CAN_TSR_ABRQ1 | CAN_TSR_ABRQ0; - if (cfg->phy != NULL) { - ret = can_transceiver_disable(cfg->phy); + if (cfg->common.phy != NULL) { + ret = can_transceiver_disable(cfg->common.phy); if (ret != 0) { LOG_ERR("failed to enable CAN transceiver (err %d)", ret); goto unlock; } } - data->started = false; + data->common.started = false; unlock: k_mutex_unlock(&data->inst_mutex); @@ -510,7 +505,7 @@ static int can_stm32_set_mode(const struct device *dev, can_mode_t mode) return -ENOTSUP; } - if (data->started) { + if (data->common.started) { return -EBUSY; } @@ -551,7 +546,7 @@ static int can_stm32_set_timing(const struct device *dev, k_mutex_lock(&data->inst_mutex, K_FOREVER); - if (data->started) { + if (data->common.started) { k_mutex_unlock(&data->inst_mutex); return -EBUSY; } @@ -591,7 +586,7 @@ static int can_stm32_get_max_bitrate(const struct device *dev, uint32_t *max_bit { const struct can_stm32_config *config = dev->config; - *max_bitrate = config->max_bitrate; + *max_bitrate = config->common.max_bitrate; return 0; } @@ -621,8 +616,8 @@ static int can_stm32_init(const struct device *dev) k_mutex_init(&data->inst_mutex); k_sem_init(&data->tx_int_sem, 0, 1); - if (cfg->phy != NULL) { - if (!device_is_ready(cfg->phy)) { + if (cfg->common.phy != NULL) { + if (!device_is_ready(cfg->common.phy)) { LOG_ERR("CAN transceiver not ready"); return -ENODEV; } @@ -673,9 +668,9 @@ static int can_stm32_init(const struct device *dev) #ifdef CONFIG_CAN_AUTO_BUS_OFF_RECOVERY can->MCR |= CAN_MCR_ABOM; #endif - if (cfg->sample_point && USE_SP_ALGO) { - ret = can_calc_timing(dev, &timing, cfg->bus_speed, - cfg->sample_point); + if (cfg->common.sample_point && USE_SP_ALGO) { + ret = can_calc_timing(dev, &timing, cfg->common.bus_speed, + cfg->common.sample_point); if (ret == -EINVAL) { LOG_ERR("Can't find timing for given param"); return -EIO; @@ -688,7 +683,7 @@ static int can_stm32_init(const struct device *dev) timing.prop_seg = 0; timing.phase_seg1 = cfg->prop_ts1; timing.phase_seg2 = cfg->ts2; - ret = can_calc_prescaler(dev, &timing, cfg->bus_speed); + ret = can_calc_prescaler(dev, &timing, cfg->common.bus_speed); if (ret) { LOG_WRN("Bitrate error: %d", ret); } @@ -720,8 +715,8 @@ static void can_stm32_set_state_change_callback(const struct device *dev, const struct can_stm32_config *cfg = dev->config; CAN_TypeDef *can = cfg->can; - data->state_change_cb = cb; - data->state_change_cb_data = user_data; + data->common.state_change_cb = cb; + data->common.state_change_cb_user_data = user_data; if (cb == NULL) { can->IER &= ~(CAN_IER_BOFIE | CAN_IER_EPVIE | CAN_IER_EWGIE); @@ -739,7 +734,7 @@ static int can_stm32_recover(const struct device *dev, k_timeout_t timeout) int ret = -EAGAIN; int64_t start_time; - if (!data->started) { + if (!data->common.started) { return -ENETDOWN; } @@ -809,7 +804,7 @@ static int can_stm32_send(const struct device *dev, const struct can_frame *fram return -ENOTSUP; } - if (!data->started) { + if (!data->common.started) { return -ENETDOWN; } @@ -1167,11 +1162,10 @@ static void config_can_##inst##_irq(CAN_TypeDef *can) \ #define CAN_STM32_CONFIG_INST(inst) \ PINCTRL_DT_INST_DEFINE(inst); \ static const struct can_stm32_config can_stm32_cfg_##inst = { \ + .common = CAN_DT_DRIVER_CONFIG_INST_GET(inst, 1000000), \ .can = (CAN_TypeDef *)DT_INST_REG_ADDR(inst), \ .master_can = (CAN_TypeDef *)DT_INST_PROP_OR(inst, \ master_can_reg, DT_INST_REG_ADDR(inst)), \ - .bus_speed = DT_INST_PROP(inst, bus_speed), \ - .sample_point = DT_INST_PROP_OR(inst, sample_point, 0), \ .sjw = DT_INST_PROP_OR(inst, sjw, 1), \ .prop_ts1 = DT_INST_PROP_OR(inst, prop_seg, 0) + \ DT_INST_PROP_OR(inst, phase_seg1, 0), \ @@ -1182,8 +1176,6 @@ static const struct can_stm32_config can_stm32_cfg_##inst = { \ }, \ .config_irq = config_can_##inst##_irq, \ .pcfg = PINCTRL_DT_INST_DEV_CONFIG_GET(inst), \ - .phy = DEVICE_DT_GET_OR_NULL(DT_INST_PHANDLE(inst, phys)), \ - .max_bitrate = DT_INST_CAN_TRANSCEIVER_MAX_BITRATE(inst, 1000000), \ }; #define CAN_STM32_DATA_INST(inst) \ From dfafe4c16163b246db700d88f0ef17263c30db87 Mon Sep 17 00:00:00 2001 From: Henrik Brix Andersen Date: Wed, 17 Jan 2024 19:53:37 +0100 Subject: [PATCH 2513/3723] drivers: can: rcar: use common config and data structures Use the common CAN controller driver configuration and data structures. Signed-off-by: Henrik Brix Andersen --- drivers/can/can_rcar.c | 72 +++++++++++++++++++----------------------- 1 file changed, 33 insertions(+), 39 deletions(-) diff --git a/drivers/can/can_rcar.c b/drivers/can/can_rcar.c index f015407c22f..35204b86c1f 100644 --- a/drivers/can/can_rcar.c +++ b/drivers/can/can_rcar.c @@ -166,21 +166,18 @@ LOG_MODULE_REGISTER(can_rcar, CONFIG_CAN_LOG_LEVEL); typedef void (*init_func_t)(const struct device *dev); struct can_rcar_cfg { + const struct can_driver_config common; uint32_t reg_addr; int reg_size; init_func_t init_func; const struct device *clock_dev; struct rcar_cpg_clk mod_clk; struct rcar_cpg_clk bus_clk; - uint32_t bus_speed; uint8_t sjw; uint8_t prop_seg; uint8_t phase_seg1; uint8_t phase_seg2; - uint16_t sample_point; const struct pinctrl_dev_config *pcfg; - const struct device *phy; - uint32_t max_bitrate; }; struct can_rcar_tx_cb { @@ -189,6 +186,7 @@ struct can_rcar_tx_cb { }; struct can_rcar_data { + struct can_driver_data common; struct k_mutex inst_mutex; struct k_sem tx_sem; struct can_rcar_tx_cb tx_cb[RCAR_CAN_FIFO_DEPTH]; @@ -199,10 +197,7 @@ struct can_rcar_data { can_rx_callback_t rx_callback[CONFIG_CAN_RCAR_MAX_FILTER]; void *rx_callback_arg[CONFIG_CAN_RCAR_MAX_FILTER]; struct can_filter filter[CONFIG_CAN_RCAR_MAX_FILTER]; - can_state_change_callback_t state_change_cb; - void *state_change_cb_data; enum can_state state; - bool started; }; static inline uint16_t can_rcar_read16(const struct can_rcar_cfg *config, @@ -244,8 +239,8 @@ static void can_rcar_state_change(const struct device *dev, uint32_t newstate) { const struct can_rcar_cfg *config = dev->config; struct can_rcar_data *data = dev->data; - const can_state_change_callback_t cb = data->state_change_cb; - void *state_change_cb_data = data->state_change_cb_data; + const can_state_change_callback_t cb = data->common.state_change_cb; + void *state_change_cb_data = data->common.state_change_cb_user_data; struct can_bus_err_cnt err_cnt; if (data->state == newstate) { @@ -578,12 +573,12 @@ static int can_rcar_start(const struct device *dev) struct can_rcar_data *data = dev->data; int ret; - if (data->started) { + if (data->common.started) { return -EALREADY; } - if (config->phy != NULL) { - ret = can_transceiver_enable(config->phy); + if (config->common.phy != NULL) { + ret = can_transceiver_enable(config->common.phy); if (ret != 0) { LOG_ERR("failed to enable CAN transceiver (err %d)", ret); return ret; @@ -598,12 +593,12 @@ static int can_rcar_start(const struct device *dev) if (ret != 0) { LOG_ERR("failed to enter operation mode (err %d)", ret); - if (config->phy != NULL) { + if (config->common.phy != NULL) { /* Attempt to disable the CAN transceiver in case of error */ - (void)can_transceiver_disable(config->phy); + (void)can_transceiver_disable(config->common.phy); } } else { - data->started = true; + data->common.started = true; } k_mutex_unlock(&data->inst_mutex); @@ -617,7 +612,7 @@ static int can_rcar_stop(const struct device *dev) struct can_rcar_data *data = dev->data; int ret; - if (!data->started) { + if (!data->common.started) { return -EALREADY; } @@ -630,12 +625,12 @@ static int can_rcar_stop(const struct device *dev) return ret; } - data->started = false; + data->common.started = false; k_mutex_unlock(&data->inst_mutex); - if (config->phy != NULL) { - ret = can_transceiver_disable(config->phy); + if (config->common.phy != NULL) { + ret = can_transceiver_disable(config->common.phy); if (ret != 0) { LOG_ERR("failed to disable CAN transceiver (err %d)", ret); return ret; @@ -666,7 +661,7 @@ static int can_rcar_set_mode(const struct device *dev, can_mode_t mode) return -ENOTSUP; } - if (data->started) { + if (data->common.started) { return -EBUSY; } @@ -690,6 +685,8 @@ static int can_rcar_set_mode(const struct device *dev, can_mode_t mode) sys_write8(tcr, config->reg_addr + RCAR_CAN_TCR); + data->common.mode = mode; + unlock: k_mutex_unlock(&data->inst_mutex); @@ -735,7 +732,7 @@ static int can_rcar_set_timing(const struct device *dev, struct reg_backup regs[3] = { { RCAR_CAN_TCR, 0 }, { RCAR_CAN_TFCR, 0 } , { RCAR_CAN_RFCR, 0 } }; - if (data->started) { + if (data->common.started) { return -EBUSY; } @@ -781,8 +778,8 @@ static void can_rcar_set_state_change_callback(const struct device *dev, { struct can_rcar_data *data = dev->data; - data->state_change_cb = cb; - data->state_change_cb_data = user_data; + data->common.state_change_cb = cb; + data->common.state_change_cb_user_data = user_data; } static int can_rcar_get_state(const struct device *dev, enum can_state *state, @@ -792,7 +789,7 @@ static int can_rcar_get_state(const struct device *dev, enum can_state *state, struct can_rcar_data *data = dev->data; if (state != NULL) { - if (!data->started) { + if (!data->common.started) { *state = CAN_STATE_STOPPED; } else { *state = data->state; @@ -814,7 +811,7 @@ static int can_rcar_recover(const struct device *dev, k_timeout_t timeout) int64_t start_time; int ret; - if (!data->started) { + if (!data->common.started) { return -ENETDOWN; } @@ -880,7 +877,7 @@ static int can_rcar_send(const struct device *dev, const struct can_frame *frame return -ENOTSUP; } - if (!data->started) { + if (!data->common.started) { return -ENETDOWN; } @@ -1004,11 +1001,11 @@ static int can_rcar_init(const struct device *dev) memset(data->rx_callback, 0, sizeof(data->rx_callback)); data->state = CAN_STATE_ERROR_ACTIVE; - data->state_change_cb = NULL; - data->state_change_cb_data = NULL; + data->common.state_change_cb = NULL; + data->common.state_change_cb_user_data = NULL; - if (config->phy != NULL) { - if (!device_is_ready(config->phy)) { + if (config->common.phy != NULL) { + if (!device_is_ready(config->common.phy)) { LOG_ERR("CAN transceiver not ready"); return -ENODEV; } @@ -1056,9 +1053,9 @@ static int can_rcar_init(const struct device *dev) return ret; } - if (config->sample_point) { - ret = can_calc_timing(dev, &timing, config->bus_speed, - config->sample_point); + if (config->common.sample_point) { + ret = can_calc_timing(dev, &timing, config->common.bus_speed, + config->common.sample_point); if (ret == -EINVAL) { LOG_ERR("Can't find timing for given param"); return -EIO; @@ -1071,7 +1068,7 @@ static int can_rcar_init(const struct device *dev) timing.prop_seg = config->prop_seg; timing.phase_seg1 = config->phase_seg1; timing.phase_seg2 = config->phase_seg2; - ret = can_calc_prescaler(dev, &timing, config->bus_speed); + ret = can_calc_prescaler(dev, &timing, config->common.bus_speed); if (ret) { LOG_WRN("Bitrate error: %d", ret); } @@ -1147,7 +1144,7 @@ static int can_rcar_get_max_bitrate(const struct device *dev, uint32_t *max_bitr { const struct can_rcar_cfg *config = dev->config; - *max_bitrate = config->max_bitrate; + *max_bitrate = config->common.max_bitrate; return 0; } @@ -1190,6 +1187,7 @@ static const struct can_driver_api can_rcar_driver_api = { PINCTRL_DT_INST_DEFINE(n); \ static void can_rcar_##n##_init(const struct device *dev); \ static const struct can_rcar_cfg can_rcar_cfg_##n = { \ + .common = CAN_DT_DRIVER_CONFIG_INST_GET(n, 1000000), \ .reg_addr = DT_INST_REG_ADDR(n), \ .reg_size = DT_INST_REG_SIZE(n), \ .init_func = can_rcar_##n##_init, \ @@ -1203,15 +1201,11 @@ static const struct can_driver_api can_rcar_driver_api = { .bus_clk.domain = \ DT_INST_CLOCKS_CELL_BY_IDX(n, 1, domain), \ .bus_clk.rate = 40000000, \ - .bus_speed = DT_INST_PROP(n, bus_speed), \ .sjw = DT_INST_PROP(n, sjw), \ .prop_seg = DT_INST_PROP_OR(n, prop_seg, 0), \ .phase_seg1 = DT_INST_PROP_OR(n, phase_seg1, 0), \ .phase_seg2 = DT_INST_PROP_OR(n, phase_seg2, 0), \ - .sample_point = DT_INST_PROP_OR(n, sample_point, 0), \ .pcfg = PINCTRL_DT_INST_DEV_CONFIG_GET(n), \ - .phy = DEVICE_DT_GET_OR_NULL(DT_INST_PHANDLE(n, phys)), \ - .max_bitrate = DT_INST_CAN_TRANSCEIVER_MAX_BITRATE(n, 1000000), \ }; \ static struct can_rcar_data can_rcar_data_##n; \ \ From fbe90f993b282586408cadcce4f2ed6a845bc9f9 Mon Sep 17 00:00:00 2001 From: Henrik Brix Andersen Date: Wed, 17 Jan 2024 19:53:56 +0100 Subject: [PATCH 2514/3723] drivers: can: nxp: canxl: use common config and data structures Use the common CAN controller driver configuration and data structures. Signed-off-by: Henrik Brix Andersen --- drivers/can/can_nxp_s32_canxl.c | 87 ++++++++++++++------------------- 1 file changed, 38 insertions(+), 49 deletions(-) diff --git a/drivers/can/can_nxp_s32_canxl.c b/drivers/can/can_nxp_s32_canxl.c index 59b2b24aa98..3cc6a8d96b2 100644 --- a/drivers/can/can_nxp_s32_canxl.c +++ b/drivers/can/can_nxp_s32_canxl.c @@ -76,6 +76,7 @@ LOG_MODULE_REGISTER(nxp_s32_canxl, CONFIG_CAN_LOG_LEVEL); #endif struct can_nxp_s32_config { + const struct can_driver_config common; CANXL_SIC_Type *base_sic; CANXL_GRP_CONTROL_Type *base_grp_ctrl; CANXL_DSC_CONTROL_Type *base_dsc_ctrl; @@ -86,22 +87,16 @@ struct can_nxp_s32_config { uint8 instance; const struct device *clock_dev; clock_control_subsys_t clock_subsys; - uint32_t bitrate; - uint32_t sample_point; uint32_t sjw; uint32_t prop_seg; uint32_t phase_seg1; uint32_t phase_seg2; #ifdef CONFIG_CAN_FD_MODE - uint32_t bitrate_data; - uint32_t sample_point_data; uint32_t sjw_data; uint32_t prop_seg_data; uint32_t phase_seg1_data; uint32_t phase_seg2_data; #endif - uint32_t max_bitrate; - const struct device *phy; const struct pinctrl_dev_config *pin_cfg; Canexcel_Ip_ConfigType *can_cfg; void (*irq_config_func)(void); @@ -123,6 +118,7 @@ struct can_nxp_s32_rx_callback { }; struct can_nxp_s32_data { + struct can_driver_data common; Canexcel_Ip_StateType *can_state; ATOMIC_DEFINE(rx_allocs, CONFIG_CAN_NXP_S32_MAX_RX); @@ -148,9 +144,6 @@ struct can_nxp_s32_data { struct can_timing timing_data; #endif enum can_state state; - can_state_change_callback_t state_change_cb; - void *state_change_cb_data; - bool started; }; static int can_nxp_s32_get_capabilities(const struct device *dev, can_mode_t *cap) @@ -216,19 +209,19 @@ static int can_nxp_s32_start(const struct device *dev) struct can_nxp_s32_data *data = dev->data; int err; - if (data->started) { + if (data->common.started) { return -EALREADY; } - if (config->phy != NULL) { - err = can_transceiver_enable(config->phy); + if (config->common.phy != NULL) { + err = can_transceiver_enable(config->common.phy); if (err != 0) { LOG_ERR("failed to enable CAN transceiver (err %d)", err); return err; } } - data->started = true; + data->common.started = true; return 0; } @@ -271,11 +264,11 @@ static int can_nxp_s32_stop(const struct device *dev) int alloc; int err; - if (!data->started) { + if (!data->common.started) { return -EALREADY; } - data->started = false; + data->common.started = false; /* Abort any pending TX frames before entering freeze mode */ for (alloc = 0; alloc < CONFIG_CAN_NXP_S32_MAX_TX; alloc++) { @@ -293,8 +286,8 @@ static int can_nxp_s32_stop(const struct device *dev) } } - if (config->phy != NULL) { - err = can_transceiver_disable(config->phy); + if (config->common.phy != NULL) { + err = can_transceiver_disable(config->common.phy); if (err != 0) { LOG_ERR("failed to disable CAN transceiver (err %d)", err); return err; @@ -313,7 +306,7 @@ static int can_nxp_s32_set_mode(const struct device *dev, can_mode_t mode) bool canfd = false; bool brs = false; - if (data->started) { + if (data->common.started) { return -EBUSY; } #ifdef CONFIG_CAN_FD_MODE @@ -349,6 +342,8 @@ static int can_nxp_s32_set_mode(const struct device *dev, can_mode_t mode) Canexcel_Ip_ExitFreezeMode(config->instance); + data->common.mode = mode; + return 0; } @@ -372,7 +367,7 @@ static int can_nxp_s32_get_max_bitrate(const struct device *dev, uint32_t *max_b { const struct can_nxp_s32_config *config = dev->config; - *max_bitrate = config->max_bitrate; + *max_bitrate = config->common.max_bitrate; return 0; } @@ -385,7 +380,7 @@ static int can_nxp_s32_get_state(const struct device *dev, enum can_state *state uint32_t sys_status = config->base_sic->SYSS; if (state) { - if (!data->started) { + if (!data->common.started) { *state = CAN_STATE_STOPPED; } else { if (sys_status & CANXL_SIC_SYSS_CBOFF_MASK) { @@ -416,8 +411,8 @@ static void can_nxp_s32_set_state_change_callback(const struct device *dev, { struct can_nxp_s32_data *data = dev->data; - data->state_change_cb = callback; - data->state_change_cb_data = user_data; + data->common.state_change_cb = callback; + data->common.state_change_cb_user_data = user_data; } #ifndef CONFIG_CAN_AUTO_BUS_OFF_RECOVERY @@ -429,7 +424,7 @@ static int can_nxp_s32_recover(const struct device *dev, k_timeout_t timeout) uint64_t start_time; int ret = 0; - if (!data->started) { + if (!data->common.started) { return -ENETDOWN; } @@ -647,7 +642,7 @@ static int can_nxp_s32_send(const struct device *dev, #endif } - if (!data->started) { + if (!data->common.started) { return -ENETDOWN; } @@ -727,7 +722,7 @@ static int can_nxp_s32_set_timing(const struct device *dev, struct can_nxp_s32_data *data = dev->data; Canexcel_Ip_TimeSegmentType can_time_segment = {0}; - if (data->started) { + if (data->common.started) { return -EBUSY; } @@ -747,7 +742,7 @@ static int can_nxp_s32_set_timing_data(const struct device *dev, struct can_nxp_s32_data *data = dev->data; Canexcel_Ip_TimeSegmentType can_fd_time_segment = {0}; - if (data->started) { + if (data->common.started) { return -EBUSY; } @@ -769,7 +764,7 @@ static void can_nxp_s32_err_callback(const struct device *dev, struct can_nxp_s32_data *data = dev->data; enum can_state state; struct can_bus_err_cnt err_cnt; - void *cb_data = data->state_change_cb_data; + void *cb_data = data->common.state_change_cb_user_data; can_tx_callback_t function; int alloc; void *arg; @@ -800,8 +795,8 @@ static void can_nxp_s32_err_callback(const struct device *dev, can_nxp_s32_get_state(dev, &state, &err_cnt); if (data->state != state) { data->state = state; - if (data->state_change_cb) { - data->state_change_cb(dev, state, err_cnt, cb_data); + if (data->common.state_change_cb) { + data->common.state_change_cb(dev, state, err_cnt, cb_data); } } @@ -950,8 +945,8 @@ static int can_nxp_s32_init(const struct device *dev) }; #endif - if (config->phy != NULL) { - if (!device_is_ready(config->phy)) { + if (config->common.phy != NULL) { + if (!device_is_ready(config->common.phy)) { LOG_ERR("CAN transceiver not ready"); return -ENODEV; } @@ -982,9 +977,9 @@ static int can_nxp_s32_init(const struct device *dev) ~(MC_RGM_PRST_0_PERIPH_16_RST_MASK | MC_RGM_PRST_0_PERIPH_24_RST_MASK); data->timing.sjw = config->sjw; - if (config->sample_point) { - err = can_calc_timing(dev, &data->timing, config->bitrate, - config->sample_point); + if (config->common.sample_point) { + err = can_calc_timing(dev, &data->timing, config->common.bus_speed, + config->common.sample_point); if (err == -EINVAL) { LOG_ERR("Can't find timing for given param"); return -EIO; @@ -996,20 +991,20 @@ static int can_nxp_s32_init(const struct device *dev) data->timing.prop_seg = config->prop_seg; data->timing.phase_seg1 = config->phase_seg1; data->timing.phase_seg2 = config->phase_seg2; - err = can_calc_prescaler(dev, &data->timing, config->bitrate); + err = can_calc_prescaler(dev, &data->timing, config->common.bus_speed); if (err) { LOG_WRN("Bitrate error: %d", err); } } - LOG_DBG("Setting CAN bitrate %d:", config->bitrate); + LOG_DBG("Setting CAN bitrate %d:", config->common.bus_speed); nxp_s32_zcan_timing_to_canxl_timing(&data->timing, &config->can_cfg->bitrate); #ifdef CONFIG_CAN_FD_MODE data->timing_data.sjw = config->sjw_data; - if (config->sample_point_data) { - err = can_calc_timing_data(dev, &data->timing_data, config->bitrate_data, - config->sample_point_data); + if (config->common.sample_point_data) { + err = can_calc_timing_data(dev, &data->timing_data, config->common.bus_speed_data, + config->common.sample_point_data); if (err == -EINVAL) { LOG_ERR("Can't find timing data for given param"); return -EIO; @@ -1021,13 +1016,13 @@ static int can_nxp_s32_init(const struct device *dev) data->timing_data.prop_seg = config->prop_seg_data; data->timing_data.phase_seg1 = config->phase_seg1_data; data->timing_data.phase_seg2 = config->phase_seg2_data; - err = can_calc_prescaler(dev, &data->timing_data, config->bitrate_data); + err = can_calc_prescaler(dev, &data->timing_data, config->common.bus_speed_data); if (err) { LOG_WRN("Bitrate data error: %d", err); } } - LOG_DBG("Setting CAN FD bitrate %d:", config->bitrate_data); + LOG_DBG("Setting CAN FD bitrate %d:", config->common.bus_speed_data); nxp_s32_zcan_timing_to_canxl_timing(&data->timing_data, &config->can_cfg->Fd_bitrate); #endif @@ -1162,12 +1157,10 @@ static const struct can_driver_api can_nxp_s32_driver_api = { #if defined(CONFIG_CAN_FD_MODE) #define CAN_NXP_S32_TIMING_DATA_CONFIG(n) \ - .bitrate_data = DT_INST_PROP(n, bus_speed_data), \ .sjw_data = DT_INST_PROP(n, sjw_data), \ .prop_seg_data = DT_INST_PROP_OR(n, prop_seg_data, 0), \ .phase_seg1_data = DT_INST_PROP_OR(n, phase_seg1_data, 0), \ - .phase_seg2_data = DT_INST_PROP_OR(n, phase_seg2_data, 0), \ - .sample_point_data = DT_INST_PROP_OR(n, sample_point_data, 0), + .phase_seg2_data = DT_INST_PROP_OR(n, phase_seg2_data, 0), #define CAN_NXP_S32_FD_MODE 1 #define CAN_NXP_S32_BRS 1 #else @@ -1234,6 +1227,7 @@ static const struct can_driver_api can_nxp_s32_driver_api = { (Canexcel_Ip_RxFifoFilterID_ADDR *)&rx_fifo_filter##n,))\ }; \ static struct can_nxp_s32_config can_nxp_s32_config_##n = { \ + .common = CAN_DT_DRIVER_CONFIG_INST_GET(n, CAN_NXP_S32_MAX_BITRATE), \ .base_sic = (CANXL_SIC_Type *)DT_INST_REG_ADDR_BY_NAME(n, sic), \ .base_grp_ctrl = (CANXL_GRP_CONTROL_Type *) \ DT_INST_REG_ADDR_BY_NAME(n, grp_ctrl), \ @@ -1248,16 +1242,11 @@ static const struct can_driver_api can_nxp_s32_driver_api = { .clock_dev = DEVICE_DT_GET(DT_INST_CLOCKS_CTLR(n)), \ .clock_subsys = (clock_control_subsys_t) \ DT_INST_CLOCKS_CELL(n, name), \ - .bitrate = DT_INST_PROP(n, bus_speed), \ .sjw = DT_INST_PROP(n, sjw), \ .prop_seg = DT_INST_PROP_OR(n, prop_seg, 0), \ .phase_seg1 = DT_INST_PROP_OR(n, phase_seg1, 0), \ .phase_seg2 = DT_INST_PROP_OR(n, phase_seg2, 0), \ - .sample_point = DT_INST_PROP_OR(n, sample_point, 0), \ CAN_NXP_S32_TIMING_DATA_CONFIG(n) \ - .max_bitrate = DT_INST_CAN_TRANSCEIVER_MAX_BITRATE(n, \ - CAN_NXP_S32_MAX_BITRATE), \ - .phy = DEVICE_DT_GET_OR_NULL(DT_INST_PHANDLE(n, phys)), \ .pin_cfg = PINCTRL_DT_INST_DEV_CONFIG_GET(n), \ .can_cfg = (Canexcel_Ip_ConfigType *)&can_nxp_s32_default_config##n, \ .irq_config_func = can_irq_config_##n \ From 2c7970d875819ff80e4d037fa40bb59bac528433 Mon Sep 17 00:00:00 2001 From: Henrik Brix Andersen Date: Wed, 17 Jan 2024 19:54:27 +0100 Subject: [PATCH 2515/3723] drivers: can: nxp: flexcan: use common config and data structures Use the common CAN controller driver configuration and data structures. Signed-off-by: Henrik Brix Andersen --- drivers/can/can_mcux_flexcan.c | 111 +++++++++++++++------------------ 1 file changed, 50 insertions(+), 61 deletions(-) diff --git a/drivers/can/can_mcux_flexcan.c b/drivers/can/can_mcux_flexcan.c index 4138678911c..859d5deacbd 100644 --- a/drivers/can/can_mcux_flexcan.c +++ b/drivers/can/can_mcux_flexcan.c @@ -85,20 +85,17 @@ LOG_MODULE_REGISTER(can_mcux_flexcan, CONFIG_CAN_LOG_LEVEL); >> CAN_ID_EXT_SHIFT)) struct mcux_flexcan_config { + const struct can_driver_config common; CAN_Type *base; const struct device *clock_dev; clock_control_subsys_t clock_subsys; int clk_source; - uint32_t bitrate; - uint32_t sample_point; uint32_t sjw; uint32_t prop_seg; uint32_t phase_seg1; uint32_t phase_seg2; #ifdef CONFIG_CAN_MCUX_FLEXCAN_FD bool flexcan_fd; - uint32_t bitrate_data; - uint32_t sample_point_data; uint32_t sjw_data; uint32_t prop_seg_data; uint32_t phase_seg1_data; @@ -107,8 +104,6 @@ struct mcux_flexcan_config { void (*irq_config_func)(const struct device *dev); void (*irq_enable_func)(void); void (*irq_disable_func)(void); - const struct device *phy; - uint32_t max_bitrate; const struct pinctrl_dev_config *pincfg; }; @@ -133,6 +128,7 @@ struct mcux_flexcan_tx_callback { }; struct mcux_flexcan_data { + struct can_driver_data common; const struct device *dev; flexcan_handle_t handle; @@ -145,14 +141,10 @@ struct mcux_flexcan_data { struct k_mutex tx_mutex; struct mcux_flexcan_tx_callback tx_cbs[MCUX_FLEXCAN_MAX_TX]; enum can_state state; - can_state_change_callback_t state_change_cb; - void *state_change_cb_data; struct can_timing timing; #ifdef CONFIG_CAN_MCUX_FLEXCAN_FD struct can_timing timing_data; - bool fd_mode; #endif /* CONFIG_CAN_MCUX_FLEXCAN_FD */ - bool started; }; static int mcux_flexcan_get_core_clock(const struct device *dev, uint32_t *rate) @@ -173,7 +165,7 @@ static int mcux_flexcan_get_max_bitrate(const struct device *dev, uint32_t *max_ { const struct mcux_flexcan_config *config = dev->config; - *max_bitrate = config->max_bitrate; + *max_bitrate = config->common.max_bitrate; return 0; } @@ -187,7 +179,7 @@ static int mcux_flexcan_set_timing(const struct device *dev, return -EINVAL; } - if (data->started) { + if (data->common.started) { return -EBUSY; } @@ -206,7 +198,7 @@ static int mcux_flexcan_set_timing_data(const struct device *dev, return -EINVAL; } - if (data->started) { + if (data->common.started) { return -EBUSY; } @@ -241,7 +233,7 @@ static status_t mcux_flexcan_mb_start(const struct device *dev, int alloc) xfer.mbIdx = ALLOC_IDX_TO_RXMB_IDX(alloc); #ifdef CONFIG_CAN_MCUX_FLEXCAN_FD - if (data->fd_mode) { + if ((data->common.mode & CAN_MODE_FD) != 0U) { xfer.framefd = &data->rx_cbs[alloc].frame.fd; FLEXCAN_SetFDRxMbConfig(config->base, ALLOC_IDX_TO_RXMB_IDX(alloc), &data->rx_cbs[alloc].mb_config, true); @@ -267,7 +259,7 @@ static void mcux_flexcan_mb_stop(const struct device *dev, int alloc) __ASSERT_NO_MSG(alloc >= 0 && alloc < ARRAY_SIZE(data->rx_cbs)); #ifdef CONFIG_CAN_MCUX_FLEXCAN_FD - if (data->fd_mode) { + if ((data->common.mode & CAN_MODE_FD) != 0U) { FLEXCAN_TransferFDAbortReceive(config->base, &data->handle, ALLOC_IDX_TO_RXMB_IDX(alloc)); FLEXCAN_SetFDRxMbConfig(config->base, ALLOC_IDX_TO_RXMB_IDX(alloc), @@ -290,12 +282,12 @@ static int mcux_flexcan_start(const struct device *dev) flexcan_timing_config_t timing; int err; - if (data->started) { + if (data->common.started) { return -EALREADY; } - if (config->phy != NULL) { - err = can_transceiver_enable(config->phy); + if (config->common.phy != NULL) { + err = can_transceiver_enable(config->common.phy); if (err != 0) { LOG_ERR("failed to enable CAN transceiver (err %d)", err); return err; @@ -349,7 +341,7 @@ static int mcux_flexcan_start(const struct device *dev) } #endif /* CONFIG_CAN_MCUX_FLEXCAN_FD */ - data->started = true; + data->common.started = true; return 0; } @@ -363,11 +355,11 @@ static int mcux_flexcan_stop(const struct device *dev) int alloc; int err; - if (!data->started) { + if (!data->common.started) { return -EALREADY; } - data->started = false; + data->common.started = false; /* Abort any pending TX frames before entering freeze mode */ for (alloc = 0; alloc < MCUX_FLEXCAN_MAX_TX; alloc++) { @@ -376,7 +368,7 @@ static int mcux_flexcan_stop(const struct device *dev) if (atomic_test_and_clear_bit(data->tx_allocs, alloc)) { #ifdef CONFIG_CAN_MCUX_FLEXCAN_FD - if (data->fd_mode) { + if ((data->common.mode & CAN_MODE_FD) != 0U) { FLEXCAN_TransferFDAbortSend(config->base, &data->handle, ALLOC_IDX_TO_TXMB_IDX(alloc)); } else { @@ -410,8 +402,8 @@ static int mcux_flexcan_stop(const struct device *dev) k_mutex_unlock(&data->rx_mutex); } - if (config->phy != NULL) { - err = can_transceiver_disable(config->phy); + if (config->common.phy != NULL) { + err = can_transceiver_disable(config->common.phy); if (err != 0) { LOG_ERR("failed to disable CAN transceiver (err %d)", err); return err; @@ -429,7 +421,7 @@ static int mcux_flexcan_set_mode(const struct device *dev, can_mode_t mode) uint32_t ctrl1; uint32_t mcr; - if (data->started) { + if (data->common.started) { return -EBUSY; } @@ -481,7 +473,6 @@ static int mcux_flexcan_set_mode(const struct device *dev, can_mode_t mode) if ((mode & CAN_MODE_FD) != 0) { /* Enable CAN FD mode */ mcr |= CAN_MCR_FDEN_MASK; - data->fd_mode = true; /* Transceiver Delay Compensation must be disabled in loopback mode */ if ((mode & CAN_MODE_LOOPBACK) != 0) { @@ -492,7 +483,6 @@ static int mcux_flexcan_set_mode(const struct device *dev, can_mode_t mode) } else { /* Disable CAN FD mode */ mcr &= ~(CAN_MCR_FDEN_MASK); - data->fd_mode = false; } } #endif /* CONFIG_CAN_MCUX_FLEXCAN_FD */ @@ -500,6 +490,8 @@ static int mcux_flexcan_set_mode(const struct device *dev, can_mode_t mode) config->base->CTRL1 = ctrl1; config->base->MCR = mcr; + data->common.mode = mode; + return 0; } @@ -664,7 +656,7 @@ static int mcux_flexcan_get_state(const struct device *dev, enum can_state *stat uint64_t status_flags; if (state != NULL) { - if (!data->started) { + if (!data->common.started) { *state = CAN_STATE_STOPPED; } else { status_flags = FLEXCAN_GetStatusFlags(config->base); @@ -705,7 +697,8 @@ static int mcux_flexcan_send(const struct device *dev, __ASSERT_NO_MSG(callback != NULL); - if (UTIL_AND(IS_ENABLED(CONFIG_CAN_MCUX_FLEXCAN_FD), data->fd_mode)) { + if (UTIL_AND(IS_ENABLED(CONFIG_CAN_MCUX_FLEXCAN_FD), + ((data->common.mode & CAN_MODE_FD) != 0U))) { if ((frame->flags & ~(CAN_FRAME_IDE | CAN_FRAME_RTR | CAN_FRAME_FDF | CAN_FRAME_BRS)) != 0) { LOG_ERR("unsupported CAN frame flags 0x%02x", frame->flags); @@ -727,7 +720,7 @@ static int mcux_flexcan_send(const struct device *dev, return -EINVAL; } - if (!data->started) { + if (!data->common.started) { return -ENETDOWN; } @@ -752,7 +745,7 @@ static int mcux_flexcan_send(const struct device *dev, xfer.mbIdx = ALLOC_IDX_TO_TXMB_IDX(alloc); #ifdef CONFIG_CAN_MCUX_FLEXCAN_FD - if (data->fd_mode) { + if ((data->common.mode & CAN_MODE_FD) != 0U) { FLEXCAN_SetFDTxMbConfig(config->base, xfer.mbIdx, true); } else { #endif /* CONFIG_CAN_MCUX_FLEXCAN_FD */ @@ -765,7 +758,7 @@ static int mcux_flexcan_send(const struct device *dev, config->irq_disable_func(); #ifdef CONFIG_CAN_MCUX_FLEXCAN_FD - if (data->fd_mode) { + if ((data->common.mode & CAN_MODE_FD) != 0U) { flexcan_fd_frame_t flexcan_frame; mcux_flexcan_fd_from_can_frame(frame, &flexcan_frame); @@ -844,13 +837,13 @@ static int mcux_flexcan_add_rx_filter(const struct device *dev, FLEXCAN_EnterFreezeMode(config->base); config->base->RXIMR[ALLOC_IDX_TO_RXMB_IDX(alloc)] = mask; - if (data->started) { + if (data->common.started) { FLEXCAN_ExitFreezeMode(config->base); } #ifdef CONFIG_CAN_MCUX_FLEXCAN_FD /* Defer starting FlexCAN FD MBs unless started */ - if (!config->flexcan_fd || data->started) { + if (!config->flexcan_fd || data->common.started) { #endif /* CONFIG_CAN_MCUX_FLEXCAN_FD */ status = mcux_flexcan_mb_start(dev, alloc); if (status != kStatus_Success) { @@ -874,8 +867,8 @@ static void mcux_flexcan_set_state_change_callback(const struct device *dev, { struct mcux_flexcan_data *data = dev->data; - data->state_change_cb = callback; - data->state_change_cb_data = user_data; + data->common.state_change_cb = callback; + data->common.state_change_cb_user_data = user_data; } #ifndef CONFIG_CAN_AUTO_BUS_OFF_RECOVERY @@ -887,7 +880,7 @@ static int mcux_flexcan_recover(const struct device *dev, k_timeout_t timeout) uint64_t start_time; int ret = 0; - if (!data->started) { + if (!data->common.started) { return -ENETDOWN; } @@ -934,7 +927,7 @@ static void mcux_flexcan_remove_rx_filter(const struct device *dev, int filter_i const struct mcux_flexcan_config *config = dev->config; /* Stop FlexCAN FD MBs unless already in stopped mode */ - if (!config->flexcan_fd || data->started) { + if (!config->flexcan_fd || data->common.started) { #endif /* CONFIG_CAN_MCUX_FLEXCAN_FD */ mcux_flexcan_mb_stop(dev, filter_id); #ifdef CONFIG_CAN_MCUX_FLEXCAN_FD @@ -955,8 +948,8 @@ static inline void mcux_flexcan_transfer_error_status(const struct device *dev, { const struct mcux_flexcan_config *config = dev->config; struct mcux_flexcan_data *data = dev->data; - const can_state_change_callback_t cb = data->state_change_cb; - void *cb_data = data->state_change_cb_data; + const can_state_change_callback_t cb = data->common.state_change_cb; + void *cb_data = data->common.state_change_cb_user_data; can_tx_callback_t function; void *arg; int alloc; @@ -1005,7 +998,7 @@ static inline void mcux_flexcan_transfer_error_status(const struct device *dev, if (atomic_test_and_clear_bit(data->tx_allocs, alloc)) { #ifdef CONFIG_CAN_MCUX_FLEXCAN_FD - if (data->fd_mode) { + if ((data->common.mode & CAN_MODE_FD) != 0U) { FLEXCAN_TransferFDAbortSend(config->base, &data->handle, ALLOC_IDX_TO_TXMB_IDX(alloc)); } else { @@ -1061,7 +1054,7 @@ static inline void mcux_flexcan_transfer_rx_idle(const struct device *dev, if (atomic_test_bit(data->rx_allocs, alloc)) { #ifdef CONFIG_CAN_MCUX_FLEXCAN_FD - if (data->fd_mode) { + if ((data->common.mode & CAN_MODE_FD) != 0U) { mcux_flexcan_fd_to_can_frame(&data->rx_cbs[alloc].frame.fd, &frame); } else { #endif /* CONFIG_CAN_MCUX_FLEXCAN_FD */ @@ -1079,7 +1072,7 @@ static inline void mcux_flexcan_transfer_rx_idle(const struct device *dev, /* Setup RX message buffer to receive next message */ xfer.mbIdx = mb; #ifdef CONFIG_CAN_MCUX_FLEXCAN_FD - if (data->fd_mode) { + if ((data->common.mode & CAN_MODE_FD) != 0U) { xfer.framefd = &data->rx_cbs[alloc].frame.fd; status = FLEXCAN_TransferFDReceiveNonBlocking(config->base, &data->handle, @@ -1125,7 +1118,7 @@ static FLEXCAN_CALLBACK(mcux_flexcan_transfer_callback) break; case kStatus_FLEXCAN_TxSwitchToRx: #ifdef CONFIG_CAN_MCUX_FLEXCAN_FD - if (data->fd_mode) { + if ((data->common.mode & CAN_MODE_FD) != 0U) { FLEXCAN_TransferFDAbortReceive(config->base, &data->handle, mb); } else { #endif /* CONFIG_CAN_MCUX_FLEXCAN_FD */ @@ -1168,8 +1161,8 @@ static int mcux_flexcan_init(const struct device *dev) uint32_t clock_freq; int err; - if (config->phy != NULL) { - if (!device_is_ready(config->phy)) { + if (config->common.phy != NULL) { + if (!device_is_ready(config->common.phy)) { LOG_ERR("CAN transceiver not ready"); return -ENODEV; } @@ -1186,9 +1179,9 @@ static int mcux_flexcan_init(const struct device *dev) MCUX_FLEXCAN_MAX_TX); data->timing.sjw = config->sjw; - if (config->sample_point && USE_SP_ALGO) { - err = can_calc_timing(dev, &data->timing, config->bitrate, - config->sample_point); + if (config->common.sample_point && USE_SP_ALGO) { + err = can_calc_timing(dev, &data->timing, config->common.bus_speed, + config->common.sample_point); if (err == -EINVAL) { LOG_ERR("Can't find timing for given param"); return -EIO; @@ -1202,7 +1195,7 @@ static int mcux_flexcan_init(const struct device *dev) data->timing.prop_seg = config->prop_seg; data->timing.phase_seg1 = config->phase_seg1; data->timing.phase_seg2 = config->phase_seg2; - err = can_calc_prescaler(dev, &data->timing, config->bitrate); + err = can_calc_prescaler(dev, &data->timing, config->common.bus_speed); if (err) { LOG_WRN("Bitrate error: %d", err); } @@ -1218,9 +1211,10 @@ static int mcux_flexcan_init(const struct device *dev) #ifdef CONFIG_CAN_MCUX_FLEXCAN_FD if (config->flexcan_fd) { data->timing_data.sjw = config->sjw_data; - if (config->sample_point_data && USE_SP_ALGO) { - err = can_calc_timing_data(dev, &data->timing_data, config->bitrate_data, - config->sample_point_data); + if (config->common.sample_point_data && USE_SP_ALGO) { + err = can_calc_timing_data(dev, &data->timing_data, + config->common.bus_speed_data, + config->common.sample_point_data); if (err == -EINVAL) { LOG_ERR("Can't find timing for given param"); return -EIO; @@ -1234,7 +1228,8 @@ static int mcux_flexcan_init(const struct device *dev) data->timing_data.prop_seg = config->prop_seg_data; data->timing_data.phase_seg1 = config->phase_seg1_data; data->timing_data.phase_seg2 = config->phase_seg2_data; - err = can_calc_prescaler(dev, &data->timing_data, config->bitrate_data); + err = can_calc_prescaler(dev, &data->timing_data, + config->common.bus_speed_data); if (err) { LOG_WRN("Bitrate error: %d", err); } @@ -1469,32 +1464,26 @@ static const struct can_driver_api mcux_flexcan_fd_driver_api = { static void mcux_flexcan_irq_disable_##id(void); \ \ static const struct mcux_flexcan_config mcux_flexcan_config_##id = { \ + .common = CAN_DT_DRIVER_CONFIG_INST_GET(id, FLEXCAN_MAX_BITRATE(id)), \ .base = (CAN_Type *)DT_INST_REG_ADDR(id), \ .clock_dev = DEVICE_DT_GET(DT_INST_CLOCKS_CTLR(id)), \ .clock_subsys = (clock_control_subsys_t) \ DT_INST_CLOCKS_CELL(id, name), \ .clk_source = DT_INST_PROP(id, clk_source), \ - .bitrate = DT_INST_PROP(id, bus_speed), \ .sjw = DT_INST_PROP(id, sjw), \ .prop_seg = DT_INST_PROP_OR(id, prop_seg, 0), \ .phase_seg1 = DT_INST_PROP_OR(id, phase_seg1, 0), \ .phase_seg2 = DT_INST_PROP_OR(id, phase_seg2, 0), \ - .sample_point = DT_INST_PROP_OR(id, sample_point, 0), \ IF_ENABLED(CONFIG_CAN_MCUX_FLEXCAN_FD, ( \ .flexcan_fd = DT_NODE_HAS_COMPAT(DT_DRV_INST(id), FLEXCAN_FD_DRV_COMPAT), \ - .bitrate_data = DT_INST_PROP_OR(id, bus_speed_data, 0), \ .sjw_data = DT_INST_PROP_OR(id, sjw_data, 0), \ .prop_seg_data = DT_INST_PROP_OR(id, prop_seg_data, 0), \ .phase_seg1_data = DT_INST_PROP_OR(id, phase_seg1_data, 0), \ .phase_seg2_data = DT_INST_PROP_OR(id, phase_seg2_data, 0), \ - .sample_point_data = DT_INST_PROP_OR(id, sample_point_data, 0), \ )) \ .irq_config_func = mcux_flexcan_irq_config_##id, \ .irq_enable_func = mcux_flexcan_irq_enable_##id, \ .irq_disable_func = mcux_flexcan_irq_disable_##id, \ - .phy = DEVICE_DT_GET_OR_NULL(DT_INST_PHANDLE(id, phys)),\ - .max_bitrate = DT_INST_CAN_TRANSCEIVER_MAX_BITRATE(id, \ - FLEXCAN_MAX_BITRATE(id)), \ .pincfg = PINCTRL_DT_INST_DEV_CONFIG_GET(id), \ }; \ \ From b55051ca9ebf4876d0e7dcdf99a0ff46d370e938 Mon Sep 17 00:00:00 2001 From: Henrik Brix Andersen Date: Wed, 17 Jan 2024 19:54:47 +0100 Subject: [PATCH 2516/3723] drivers: can: native_linux: flexcan: use common config and data structures Use the common CAN controller driver configuration and data structures. Signed-off-by: Henrik Brix Andersen --- drivers/can/can_native_linux.c | 40 ++++++++++++++++------------------ 1 file changed, 19 insertions(+), 21 deletions(-) diff --git a/drivers/can/can_native_linux.c b/drivers/can/can_native_linux.c index 3f73117ae66..01392c3ee2a 100644 --- a/drivers/can/can_native_linux.c +++ b/drivers/can/can_native_linux.c @@ -29,21 +29,20 @@ struct can_filter_context { }; struct can_native_linux_data { + struct can_driver_data common; struct can_filter_context filters[CONFIG_CAN_MAX_FILTER]; struct k_mutex filter_mutex; struct k_sem tx_idle; can_tx_callback_t tx_callback; void *tx_user_data; - bool loopback; - bool mode_fd; int dev_fd; /* Linux socket file descriptor */ struct k_thread rx_thread; - bool started; K_KERNEL_STACK_MEMBER(rx_thread_stack, CONFIG_ARCH_POSIX_RECOMMENDED_STACK_SIZE); }; struct can_native_linux_config { + const struct can_driver_config common; const char *if_name; }; @@ -96,11 +95,11 @@ static void rx_thread(void *arg1, void *arg2, void *arg3) data->tx_callback(dev, 0, data->tx_user_data); k_sem_give(&data->tx_idle); - if (!data->loopback) { + if ((data->common.mode & CAN_MODE_LOOPBACK) == 0U) { continue; } } - if ((count <= 0) || !data->started) { + if ((count <= 0) || !data->common.started) { break; } @@ -143,7 +142,7 @@ static int can_native_linux_send(const struct device *dev, const struct can_fram } if ((frame->flags & CAN_FRAME_FDF) != 0) { - if (!data->mode_fd) { + if ((data->common.mode & CAN_MODE_FD) == 0U) { return -ENOTSUP; } @@ -167,7 +166,7 @@ static int can_native_linux_send(const struct device *dev, const struct can_fram return -EIO; } - if (!data->started) { + if (!data->common.started) { return -ENETDOWN; } @@ -268,11 +267,11 @@ static int can_native_linux_start(const struct device *dev) { struct can_native_linux_data *data = dev->data; - if (data->started) { + if (data->common.started) { return -EALREADY; } - data->started = true; + data->common.started = true; return 0; } @@ -281,11 +280,11 @@ static int can_native_linux_stop(const struct device *dev) { struct can_native_linux_data *data = dev->data; - if (!data->started) { + if (!data->common.started) { return -EALREADY; } - data->started = false; + data->common.started = false; return 0; } @@ -307,20 +306,18 @@ static int can_native_linux_set_mode(const struct device *dev, can_mode_t mode) } #endif /* CONFIG_CAN_FD_MODE */ - if (data->started) { + if (data->common.started) { return -EBUSY; } - /* loopback is handled internally in rx_thread */ - data->loopback = (mode & CAN_MODE_LOOPBACK) != 0; - - data->mode_fd = (mode & CAN_MODE_FD) != 0; - err = linux_socketcan_set_mode_fd(data->dev_fd, data->mode_fd); + err = linux_socketcan_set_mode_fd(data->dev_fd, (mode & CAN_MODE_FD) != 0); if (err != 0) { LOG_ERR("failed to set mode"); return -EIO; } + data->common.mode = mode; + return 0; } @@ -330,7 +327,7 @@ static int can_native_linux_set_timing(const struct device *dev, const struct ca ARG_UNUSED(timing); - if (data->started) { + if (data->common.started) { return -EBUSY; } @@ -345,7 +342,7 @@ static int can_native_linux_set_timing_data(const struct device *dev, ARG_UNUSED(timing); - if (data->started) { + if (data->common.started) { return -EBUSY; } @@ -359,7 +356,7 @@ static int can_native_linux_get_state(const struct device *dev, enum can_state * struct can_native_linux_data *data = dev->data; if (state != NULL) { - if (!data->started) { + if (!data->common.started) { *state = CAN_STATE_STOPPED; } else { /* SocketCAN does not forward error frames by default */ @@ -382,7 +379,7 @@ static int can_native_linux_recover(const struct device *dev, k_timeout_t timeou ARG_UNUSED(timeout); - if (!data->started) { + if (!data->common.started) { return -ENETDOWN; } @@ -491,6 +488,7 @@ static int can_native_linux_init(const struct device *dev) #define CAN_NATIVE_LINUX_INIT(inst) \ \ static const struct can_native_linux_config can_native_linux_cfg_##inst = { \ + .common = CAN_DT_DRIVER_CONFIG_INST_GET(inst, 0), \ .if_name = DT_INST_PROP(inst, host_interface), \ }; \ \ From 639085b61403d37a42eaf2c537f218fb516e77d2 Mon Sep 17 00:00:00 2001 From: Henrik Brix Andersen Date: Wed, 17 Jan 2024 19:55:05 +0100 Subject: [PATCH 2517/3723] drivers: can: mcp2515: flexcan: use common config and data structures Use the common CAN controller driver configuration and data structures. Signed-off-by: Henrik Brix Andersen --- drivers/can/can_mcp2515.c | 59 +++++++++++++++++++-------------------- drivers/can/can_mcp2515.h | 13 +++------ 2 files changed, 33 insertions(+), 39 deletions(-) diff --git a/drivers/can/can_mcp2515.c b/drivers/can/can_mcp2515.c index 0a610fba601..8d02db834f7 100644 --- a/drivers/can/can_mcp2515.c +++ b/drivers/can/can_mcp2515.c @@ -338,7 +338,7 @@ static int mcp2515_get_max_bitrate(const struct device *dev, uint32_t *max_bitra { const struct mcp2515_config *dev_cfg = dev->config; - *max_bitrate = dev_cfg->max_bitrate; + *max_bitrate = dev_cfg->common.max_bitrate; return 0; } @@ -353,7 +353,7 @@ static int mcp2515_set_timing(const struct device *dev, return -EINVAL; } - if (dev_data->started) { + if (dev_data->common.started) { return -EBUSY; } @@ -439,12 +439,12 @@ static int mcp2515_start(const struct device *dev) struct mcp2515_data *dev_data = dev->data; int ret; - if (dev_data->started) { + if (dev_data->common.started) { return -EALREADY; } - if (dev_cfg->phy != NULL) { - ret = can_transceiver_enable(dev_cfg->phy); + if (dev_cfg->common.phy != NULL) { + ret = can_transceiver_enable(dev_cfg->common.phy); if (ret != 0) { LOG_ERR("Failed to enable CAN transceiver [%d]", ret); return ret; @@ -459,12 +459,12 @@ static int mcp2515_start(const struct device *dev) if (ret < 0) { LOG_ERR("Failed to set the mode [%d]", ret); - if (dev_cfg->phy != NULL) { + if (dev_cfg->common.phy != NULL) { /* Attempt to disable the CAN transceiver in case of error */ - (void)can_transceiver_disable(dev_cfg->phy); + (void)can_transceiver_disable(dev_cfg->common.phy); } } else { - dev_data->started = true; + dev_data->common.started = true; } k_mutex_unlock(&dev_data->mutex); @@ -479,7 +479,7 @@ static int mcp2515_stop(const struct device *dev) int ret; int i; - if (!dev_data->started) { + if (!dev_data->common.started) { return -EALREADY; } @@ -504,7 +504,7 @@ static int mcp2515_stop(const struct device *dev) return ret; } - dev_data->started = false; + dev_data->common.started = false; k_mutex_unlock(&dev_data->mutex); @@ -512,8 +512,8 @@ static int mcp2515_stop(const struct device *dev) mcp2515_tx_done(dev, i, -ENETDOWN); } - if (dev_cfg->phy != NULL) { - ret = can_transceiver_disable(dev_cfg->phy); + if (dev_cfg->common.phy != NULL) { + ret = can_transceiver_disable(dev_cfg->common.phy); if (ret != 0) { LOG_ERR("Failed to disable CAN transceiver [%d]", ret); return ret; @@ -527,7 +527,7 @@ static int mcp2515_set_mode(const struct device *dev, can_mode_t mode) { struct mcp2515_data *dev_data = dev->data; - if (dev_data->started) { + if (dev_data->common.started) { return -EBUSY; } @@ -546,6 +546,8 @@ static int mcp2515_set_mode(const struct device *dev, can_mode_t mode) return -ENOTSUP; } + dev_data->common.mode = mode; + return 0; } @@ -574,7 +576,7 @@ static int mcp2515_send(const struct device *dev, return -ENOTSUP; } - if (!dev_data->started) { + if (!dev_data->common.started) { return -ENETDOWN; } @@ -679,8 +681,8 @@ static void mcp2515_set_state_change_callback(const struct device *dev, { struct mcp2515_data *dev_data = dev->data; - dev_data->state_change_cb = cb; - dev_data->state_change_cb_data = user_data; + dev_data->common.state_change_cb = cb; + dev_data->common.state_change_cb_user_data = user_data; } static void mcp2515_rx_filter(const struct device *dev, @@ -744,7 +746,7 @@ static int mcp2515_get_state(const struct device *dev, enum can_state *state, } if (state != NULL) { - if (!dev_data->started) { + if (!dev_data->common.started) { *state = CAN_STATE_STOPPED; } else if (eflg & MCP2515_EFLG_TXBO) { *state = CAN_STATE_BUS_OFF; @@ -789,8 +791,8 @@ static int mcp2515_get_state(const struct device *dev, enum can_state *state, static void mcp2515_handle_errors(const struct device *dev) { struct mcp2515_data *dev_data = dev->data; - can_state_change_callback_t state_change_cb = dev_data->state_change_cb; - void *state_change_cb_data = dev_data->state_change_cb_data; + can_state_change_callback_t state_change_cb = dev_data->common.state_change_cb; + void *state_change_cb_data = dev_data->common.state_change_cb_user_data; enum can_state state; struct can_bus_err_cnt err_cnt; int err; @@ -814,7 +816,7 @@ static int mcp2515_recover(const struct device *dev, k_timeout_t timeout) ARG_UNUSED(timeout); - if (!dev_data->started) { + if (!dev_data->common.started) { return -ENETDOWN; } @@ -958,8 +960,8 @@ static int mcp2515_init(const struct device *dev) k_mutex_init(&dev_data->mutex); k_sem_init(&dev_data->tx_sem, MCP2515_TX_CNT, MCP2515_TX_CNT); - if (dev_cfg->phy != NULL) { - if (!device_is_ready(dev_cfg->phy)) { + if (dev_cfg->common.phy != NULL) { + if (!device_is_ready(dev_cfg->common.phy)) { LOG_ERR("CAN transceiver not ready"); return -ENODEV; } @@ -1011,9 +1013,9 @@ static int mcp2515_init(const struct device *dev) (void)memset(dev_data->filter, 0, sizeof(dev_data->filter)); dev_data->old_state = CAN_STATE_ERROR_ACTIVE; - if (dev_cfg->sample_point && USE_SP_ALGO) { - ret = can_calc_timing(dev, &timing, dev_cfg->bus_speed, - dev_cfg->sample_point); + if (dev_cfg->common.sample_point && USE_SP_ALGO) { + ret = can_calc_timing(dev, &timing, dev_cfg->common.bus_speed, + dev_cfg->common.sample_point); if (ret == -EINVAL) { LOG_ERR("Can't find timing for given param"); return -EIO; @@ -1026,7 +1028,7 @@ static int mcp2515_init(const struct device *dev) timing.prop_seg = dev_cfg->tq_prop; timing.phase_seg1 = dev_cfg->tq_bs1; timing.phase_seg2 = dev_cfg->tq_bs2; - ret = can_calc_prescaler(dev, &timing, dev_cfg->bus_speed); + ret = can_calc_prescaler(dev, &timing, dev_cfg->common.bus_speed); if (ret) { LOG_WRN("Bitrate error: %d", ret); } @@ -1055,6 +1057,7 @@ static int mcp2515_init(const struct device *dev) }; \ \ static const struct mcp2515_config mcp2515_config_##inst = { \ + .common = CAN_DT_DRIVER_CONFIG_INST_GET(inst, 1000000), \ .bus = SPI_DT_SPEC_INST_GET(inst, SPI_WORD_SET(8), 0), \ .int_gpio = GPIO_DT_SPEC_INST_GET(inst, int_gpios), \ .int_thread_stack_size = CONFIG_CAN_MCP2515_INT_THREAD_STACK_SIZE, \ @@ -1063,11 +1066,7 @@ static int mcp2515_init(const struct device *dev) .tq_prop = DT_INST_PROP_OR(inst, prop_seg, 0), \ .tq_bs1 = DT_INST_PROP_OR(inst, phase_seg1, 0), \ .tq_bs2 = DT_INST_PROP_OR(inst, phase_seg2, 0), \ - .bus_speed = DT_INST_PROP(inst, bus_speed), \ .osc_freq = DT_INST_PROP(inst, osc_freq), \ - .sample_point = DT_INST_PROP_OR(inst, sample_point, 0), \ - .phy = DEVICE_DT_GET_OR_NULL(DT_INST_PHANDLE(inst, phys)), \ - .max_bitrate = DT_INST_CAN_TRANSCEIVER_MAX_BITRATE(inst, 1000000), \ }; \ \ CAN_DEVICE_DT_INST_DEFINE(inst, mcp2515_init, NULL, &mcp2515_data_##inst, \ diff --git a/drivers/can/can_mcp2515.h b/drivers/can/can_mcp2515.h index f8e2921ba63..2582e19daa3 100644 --- a/drivers/can/can_mcp2515.h +++ b/drivers/can/can_mcp2515.h @@ -22,6 +22,8 @@ struct mcp2515_tx_cb { }; struct mcp2515_data { + struct can_driver_data common; + /* interrupt data */ struct gpio_callback int_gpio_cb; struct k_thread int_thread; @@ -38,17 +40,16 @@ struct mcp2515_data { can_rx_callback_t rx_cb[CONFIG_CAN_MAX_FILTER]; void *cb_arg[CONFIG_CAN_MAX_FILTER]; struct can_filter filter[CONFIG_CAN_MAX_FILTER]; - can_state_change_callback_t state_change_cb; - void *state_change_cb_data; /* general data */ struct k_mutex mutex; enum can_state old_state; uint8_t mcp2515_mode; - bool started; }; struct mcp2515_config { + const struct can_driver_config common; + /* spi configuration */ struct spi_dt_spec bus; @@ -62,13 +63,7 @@ struct mcp2515_config { uint8_t tq_prop; uint8_t tq_bs1; uint8_t tq_bs2; - uint32_t bus_speed; uint32_t osc_freq; - uint16_t sample_point; - - /* CAN transceiver */ - const struct device *phy; - uint32_t max_bitrate; }; /* From eeec09eb9ac4586fb36164a509c9dacddb7694c7 Mon Sep 17 00:00:00 2001 From: Henrik Brix Andersen Date: Wed, 17 Jan 2024 19:55:21 +0100 Subject: [PATCH 2518/3723] drivers: can: mcp251xfd: flexcan: use common config and data structures Use the common CAN controller driver configuration and data structures. Signed-off-by: Henrik Brix Andersen --- drivers/can/can_mcp251xfd.c | 67 ++++++++++++++++++------------------- drivers/can/can_mcp251xfd.h | 15 +++------ 2 files changed, 37 insertions(+), 45 deletions(-) diff --git a/drivers/can/can_mcp251xfd.c b/drivers/can/can_mcp251xfd.c index 2bb4f7e2cb5..1b90982d642 100644 --- a/drivers/can/can_mcp251xfd.c +++ b/drivers/can/can_mcp251xfd.c @@ -379,7 +379,7 @@ static int mcp251xfd_set_mode(const struct device *dev, can_mode_t mode) { struct mcp251xfd_data *dev_data = dev->data; - if (dev_data->started) { + if (dev_data->common.started) { return -EBUSY; } @@ -408,7 +408,7 @@ static int mcp251xfd_set_mode(const struct device *dev, can_mode_t mode) dev_data->next_mcp251xfd_mode = MCP251XFD_REG_CON_MODE_EXT_LOOPBACK; } - dev_data->mode = mode; + dev_data->common.mode = mode; return 0; } @@ -423,7 +423,7 @@ static int mcp251xfd_set_timing(const struct device *dev, const struct can_timin return -EINVAL; } - if (dev_data->started) { + if (dev_data->common.started) { return -EBUSY; } @@ -458,7 +458,7 @@ static int mcp251xfd_set_timing_data(const struct device *dev, const struct can_ return -EINVAL; } - if (dev_data->started) { + if (dev_data->common.started) { return -EBUSY; } @@ -502,7 +502,7 @@ static int mcp251xfd_send(const struct device *dev, const struct can_frame *msg, __ASSERT_NO_MSG(callback != NULL); - if (!dev_data->started) { + if (!dev_data->common.started) { return -ENETDOWN; } @@ -515,7 +515,7 @@ static int mcp251xfd_send(const struct device *dev, const struct can_frame *msg, return -EINVAL; } - if ((msg->flags & CAN_FRAME_FDF) && !(dev_data->mode & CAN_MODE_FD)) { + if ((msg->flags & CAN_FRAME_FDF) && !(dev_data->common.mode & CAN_MODE_FD)) { return -ENOTSUP; } @@ -678,8 +678,8 @@ static void mcp251xfd_set_state_change_callback(const struct device *dev, { struct mcp251xfd_data *dev_data = dev->data; - dev_data->state_change_cb = cb; - dev_data->state_change_cb_data = user_data; + dev_data->common.state_change_cb = cb; + dev_data->common.state_change_cb_user_data = user_data; } static int mcp251xfd_get_state(const struct device *dev, enum can_state *state, @@ -708,7 +708,7 @@ static int mcp251xfd_get_state(const struct device *dev, enum can_state *state, goto done; } - if (!dev_data->started) { + if (!dev_data->common.started) { *state = CAN_STATE_STOPPED; goto done; } @@ -751,7 +751,7 @@ static int mcp251xfd_get_max_bitrate(const struct device *dev, uint32_t *max_bit { const struct mcp251xfd_config *dev_cfg = dev->config; - *max_bitrate = dev_cfg->max_bitrate; + *max_bitrate = dev_cfg->common.max_bitrate; return 0; } @@ -763,7 +763,7 @@ static int mcp251xfd_recover(const struct device *dev, k_timeout_t timeout) ARG_UNUSED(timeout); - if (!dev_data->started) { + if (!dev_data->common.started) { return -ENETDOWN; } @@ -941,8 +941,9 @@ static int mcp251xfd_handle_cerrif(const struct device *dev) mcp251xfd_reset_tx_fifos(dev, -ENETDOWN); } - if (dev_data->state_change_cb) { - dev_data->state_change_cb(dev, new_state, err_cnt, dev_data->state_change_cb_data); + if (dev_data->common.state_change_cb) { + dev_data->common.state_change_cb(dev, new_state, err_cnt, + dev_data->common.state_change_cb_user_data); } done: @@ -973,7 +974,7 @@ static int mcp251xfd_handle_modif(const struct device *dev) } /* try to transition back into our target mode */ - if (dev_data->started) { + if (dev_data->common.started) { LOG_INF("Switching back into mode %d", dev_data->next_mcp251xfd_mode); ret = mcp251xfd_set_mode_internal(dev, dev_data->next_mcp251xfd_mode); } @@ -1169,15 +1170,15 @@ static int mcp251xfd_start(const struct device *dev) const struct mcp251xfd_config *dev_cfg = dev->config; int ret; - if (dev_data->started) { + if (dev_data->common.started) { return -EALREADY; } /* in case of a race between mcp251xfd_send() and mcp251xfd_stop() */ mcp251xfd_reset_tx_fifos(dev, -ENETDOWN); - if (dev_cfg->phy != NULL) { - ret = can_transceiver_enable(dev_cfg->phy); + if (dev_cfg->common.phy != NULL) { + ret = can_transceiver_enable(dev_cfg->common.phy); if (ret < 0) { LOG_ERR("Failed to enable CAN transceiver [%d]", ret); return ret; @@ -1189,12 +1190,12 @@ static int mcp251xfd_start(const struct device *dev) ret = mcp251xfd_set_mode_internal(dev, dev_data->next_mcp251xfd_mode); if (ret < 0) { LOG_ERR("Failed to set the mode [%d]", ret); - if (dev_cfg->phy != NULL) { + if (dev_cfg->common.phy != NULL) { /* Attempt to disable the CAN transceiver in case of error */ - (void)can_transceiver_disable(dev_cfg->phy); + (void)can_transceiver_disable(dev_cfg->common.phy); } } else { - dev_data->started = true; + dev_data->common.started = true; } k_mutex_unlock(&dev_data->mutex); @@ -1209,7 +1210,7 @@ static int mcp251xfd_stop(const struct device *dev) uint8_t *reg_byte; int ret; - if (!dev_data->started) { + if (!dev_data->common.started) { return -EALREADY; } @@ -1243,11 +1244,11 @@ static int mcp251xfd_stop(const struct device *dev) return ret; } - dev_data->started = false; + dev_data->common.started = false; k_mutex_unlock(&dev_data->mutex); - if (dev_cfg->phy != NULL) { - ret = can_transceiver_disable(dev_cfg->phy); + if (dev_cfg->common.phy != NULL) { + ret = can_transceiver_disable(dev_cfg->common.phy); if (ret < 0) { LOG_ERR("Failed to disable CAN transceiver [%d]", ret); return ret; @@ -1302,15 +1303,16 @@ static int mcp251xfd_init_timing_struct(struct can_timing *timing, const struct mcp251xfd_timing_params *timing_params, bool is_nominal) { + const struct mcp251xfd_config *dev_cfg = dev->config; int ret; - if (USE_SP_ALGO && timing_params->sample_point > 0) { + if (USE_SP_ALGO && dev_cfg->common.sample_point > 0) { if (is_nominal) { - ret = can_calc_timing(dev, timing, timing_params->bus_speed, - timing_params->sample_point); + ret = can_calc_timing(dev, timing, dev_cfg->common.bus_speed, + dev_cfg->common.sample_point); } else { - ret = can_calc_timing_data(dev, timing, timing_params->bus_speed, - timing_params->sample_point); + ret = can_calc_timing_data(dev, timing, dev_cfg->common.bus_speed, + dev_cfg->common.sample_point); } if (ret < 0) { return ret; @@ -1323,7 +1325,7 @@ static int mcp251xfd_init_timing_struct(struct can_timing *timing, timing->prop_seg = timing_params->prop_seg; timing->phase_seg1 = timing_params->phase_seg1; timing->phase_seg2 = timing_params->phase_seg2; - ret = can_calc_prescaler(dev, timing, timing_params->bus_speed); + ret = can_calc_prescaler(dev, timing, dev_cfg->common.bus_speed); if (ret > 0) { LOG_WRN("Bitrate error: %d", ret); } @@ -1717,8 +1719,6 @@ static const struct can_driver_api mcp251xfd_api_funcs = { .prop_seg = DT_INST_PROP_OR(inst, prop_seg##type, 0), \ .phase_seg1 = DT_INST_PROP_OR(inst, phase_seg1##type, 0), \ .phase_seg2 = DT_INST_PROP_OR(inst, phase_seg2##type, 0), \ - .bus_speed = DT_INST_PROP(inst, bus_speed##type), \ - .sample_point = DT_INST_PROP_OR(inst, sample_point##type, 0), \ } #if defined(CONFIG_CAN_FD_MODE) @@ -1744,6 +1744,7 @@ static const struct can_driver_api mcp251xfd_api_funcs = { .int_thread_stack = mcp251xfd_int_stack_##inst, \ }; \ static const struct mcp251xfd_config mcp251xfd_config_##inst = { \ + .common = CAN_DT_DRIVER_CONFIG_INST_GET(inst, 8000000), \ .bus = SPI_DT_SPEC_INST_GET(inst, SPI_WORD_SET(8), 0), \ .int_gpio_dt = GPIO_DT_SPEC_INST_GET(inst, int_gpios), \ \ @@ -1754,8 +1755,6 @@ static const struct can_driver_api mcp251xfd_api_funcs = { \ .osc_freq = DT_INST_PROP(inst, osc_freq), \ MCP251XFD_SET_TIMING(inst), \ - .phy = DEVICE_DT_GET_OR_NULL(DT_INST_PHANDLE(inst, phys)), \ - .max_bitrate = DT_INST_CAN_TRANSCEIVER_MAX_BITRATE(inst, 8000000), \ .rx_fifo = {.ram_start_addr = MCP251XFD_RX_FIFO_START_ADDR, \ .reg_fifocon_addr = MCP251XFD_REG_FIFOCON(MCP251XFD_RX_FIFO_IDX), \ .capacity = MCP251XFD_RX_FIFO_ITEMS, \ diff --git a/drivers/can/can_mcp251xfd.h b/drivers/can/can_mcp251xfd.h index b87c6ae53dd..475f91583c2 100644 --- a/drivers/can/can_mcp251xfd.h +++ b/drivers/can/can_mcp251xfd.h @@ -478,6 +478,8 @@ struct mcp251xfd_fifo { }; struct mcp251xfd_data { + struct can_driver_data common; + /* Interrupt Data */ struct gpio_callback int_gpio_cb; struct k_thread int_thread; @@ -486,8 +488,6 @@ struct mcp251xfd_data { /* General */ enum can_state state; - can_state_change_callback_t state_change_cb; - void *state_change_cb_data; struct k_mutex mutex; /* TX Callback */ @@ -503,13 +503,10 @@ struct mcp251xfd_data { const struct device *dev; - bool started; uint8_t next_mcp251xfd_mode; uint8_t current_mcp251xfd_mode; int tdco; - can_mode_t mode; - struct mcp251xfd_spi_data spi_data; }; @@ -519,11 +516,11 @@ struct mcp251xfd_timing_params { uint8_t prop_seg; uint8_t phase_seg1; uint8_t phase_seg2; - uint32_t bus_speed; - uint16_t sample_point; }; struct mcp251xfd_config { + const struct can_driver_config common; + /* spi configuration */ struct spi_dt_spec bus; struct gpio_dt_spec int_gpio_dt; @@ -543,10 +540,6 @@ struct mcp251xfd_config { struct mcp251xfd_timing_params timing_params_data; #endif - /* CAN transceiver */ - const struct device *phy; - uint32_t max_bitrate; - const struct device *clk_dev; uint8_t clk_id; From c62dbb13867f37f9d1fc4271ded6230b4d0c4e18 Mon Sep 17 00:00:00 2001 From: Thomas Gagneret Date: Wed, 17 Jan 2024 15:56:59 +0100 Subject: [PATCH 2519/3723] cmake: zephyr_module: Remove useless 'west_arg' variable 8cc716792ac5aaadd9c4601607abda4504e7044c renamed this variable to lower case to indicate it's only used locally however WEST_ARG is used as a parameter of zephyr_module.py in CMakeLists.txt when CONFIG_BUILD_OUTPUT_META is enabled. This variable was used when west had some limitation. It does not really make sense now, so it has been removed and content of west_arg variable has been added by default. Signed-off-by: Thomas Gagneret --- CMakeLists.txt | 2 +- cmake/modules/zephyr_module.cmake | 6 +----- 2 files changed, 2 insertions(+), 6 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index e3e65cf26eb..76d8466b8df 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -1627,10 +1627,10 @@ if(CONFIG_BUILD_OUTPUT_META) list(APPEND post_build_commands COMMAND ${PYTHON_EXECUTABLE} ${ZEPHYR_BASE}/scripts/zephyr_module.py - ${WEST_ARG} ${ZEPHYR_MODULES_ARG} ${EXTRA_ZEPHYR_MODULES_ARG} --meta-out ${KERNEL_META_PATH} + --zephyr-base=${ZEPHYR_BASE} $<$:--meta-state-propagate> ) list(APPEND diff --git a/cmake/modules/zephyr_module.cmake b/cmake/modules/zephyr_module.cmake index 90afc1f02e5..50ee05dfe25 100644 --- a/cmake/modules/zephyr_module.cmake +++ b/cmake/modules/zephyr_module.cmake @@ -48,17 +48,13 @@ set(cmake_modules_file ${CMAKE_BINARY_DIR}/zephyr_modules.txt) set(cmake_sysbuild_file ${CMAKE_BINARY_DIR}/sysbuild_modules.txt) set(zephyr_settings_file ${CMAKE_BINARY_DIR}/zephyr_settings.txt) -if(WEST) - set(west_arg "--zephyr-base" ${ZEPHYR_BASE}) -endif() - if(WEST OR ZEPHYR_MODULES) # Zephyr module uses west, so only call it if west is installed or # ZEPHYR_MODULES was provided as argument to CMake. execute_process( COMMAND ${PYTHON_EXECUTABLE} ${ZEPHYR_BASE}/scripts/zephyr_module.py - ${west_arg} + --zephyr-base=${ZEPHYR_BASE} ${ZEPHYR_MODULES_ARG} ${EXTRA_ZEPHYR_MODULES_ARG} --kconfig-out ${kconfig_modules_file} From 52be26a8e357b8a75e9eee0163290f8e4561c96a Mon Sep 17 00:00:00 2001 From: Bjarki Arge Andreasen Date: Wed, 17 Jan 2024 08:35:13 +0100 Subject: [PATCH 2520/3723] net: l2: ppp: Patch carrier lost and L2 enable/disable L2 PPP is not able to handle the carrier being lost gracefully, nor is it able to gracefully close the PPP connection when net_if_down() is called. This patch refactors the L2 PPP module to use the carrier state to either properly close or simply terminate the PPP connection. Additionally, it ensures that the PPP session is closed properly before calling ppp->stop(). Signed-off-by: Bjarki Arge Andreasen --- include/zephyr/net/ppp.h | 6 ++ subsys/net/l2/ppp/lcp.c | 6 +- subsys/net/l2/ppp/link.c | 4 ++ subsys/net/l2/ppp/ppp_l2.c | 121 +++++++++++++++++++++++++++++-------- 4 files changed, 108 insertions(+), 29 deletions(-) diff --git a/include/zephyr/net/ppp.h b/include/zephyr/net/ppp.h index a72d4f1feac..36c6bf64eeb 100644 --- a/include/zephyr/net/ppp.h +++ b/include/zephyr/net/ppp.h @@ -474,6 +474,12 @@ struct ppp_context { /** Current phase of PPP link */ enum ppp_phase phase; + /** Signal when PPP link is terminated */ + struct k_sem wait_ppp_link_terminated; + + /** Signal when PPP link is down */ + struct k_sem wait_ppp_link_down; + /** This tells what features the PPP supports. */ enum net_l2_flags ppp_l2_flags; diff --git a/subsys/net/l2/ppp/lcp.c b/subsys/net/l2/ppp/lcp.c index 9e54f631f48..098c2a4417e 100644 --- a/subsys/net/l2/ppp/lcp.c +++ b/subsys/net/l2/ppp/lcp.c @@ -179,11 +179,9 @@ static void lcp_down(struct ppp_fsm *fsm) ppp_link_down(ctx); - if (!net_if_is_carrier_ok(ctx->iface)) { - return; + if (net_if_is_carrier_ok(ctx->iface) && ctx->is_enabled) { + ppp_change_phase(ctx, PPP_ESTABLISH); } - - ppp_change_phase(ctx, PPP_ESTABLISH); } static void lcp_up(struct ppp_fsm *fsm) diff --git a/subsys/net/l2/ppp/link.c b/subsys/net/l2/ppp/link.c index 29f4ad6f40c..f99703f82aa 100644 --- a/subsys/net/l2/ppp/link.c +++ b/subsys/net/l2/ppp/link.c @@ -114,6 +114,8 @@ void ppp_link_authenticated(struct ppp_context *ctx) void ppp_link_terminated(struct ppp_context *ctx) { + k_sem_give(&ctx->wait_ppp_link_terminated); + if (ctx->phase == PPP_DEAD) { return; } @@ -127,6 +129,8 @@ void ppp_link_terminated(struct ppp_context *ctx) void ppp_link_down(struct ppp_context *ctx) { + k_sem_give(&ctx->wait_ppp_link_down); + if (ctx->phase == PPP_DEAD) { return; } diff --git a/subsys/net/l2/ppp/ppp_l2.c b/subsys/net/l2/ppp/ppp_l2.c index e2bf29274cc..efbd7b81008 100644 --- a/subsys/net/l2/ppp/ppp_l2.c +++ b/subsys/net/l2/ppp/ppp_l2.c @@ -190,16 +190,14 @@ static int ppp_send(struct net_if *iface, struct net_pkt *pkt) return ret; } -static void ppp_close(struct ppp_context *ctx) +static enum net_l2_flags ppp_flags(struct net_if *iface) { - if (ppp_lcp) { - ppp_lcp->close(ctx, "Shutdown"); - } else { - ppp_change_phase(ctx, PPP_DEAD); - } + struct ppp_context *ctx = net_if_l2_data(iface); + + return ctx->ppp_l2_flags; } -static void ppp_open(struct ppp_context *ctx) +static void ppp_open_async(struct ppp_context *ctx) { ppp_change_phase(ctx, PPP_ESTABLISH); @@ -210,37 +208,109 @@ static void ppp_open(struct ppp_context *ctx) } } -static enum net_l2_flags ppp_flags(struct net_if *iface) +static int ppp_up(struct net_if *iface) { - struct ppp_context *ctx = net_if_l2_data(iface); + const struct ppp_api *ppp = net_if_get_device(iface)->api; - return ctx->ppp_l2_flags; + if (ppp->start) { + ppp->start(net_if_get_device(iface)); + } + + return 0; } -static int ppp_enable(struct net_if *iface, bool state) +static int ppp_lcp_close(struct ppp_context *ctx) { - const struct ppp_api *ppp = - net_if_get_device(iface)->api; - struct ppp_context *ctx = net_if_l2_data(iface); + if (ppp_lcp == NULL) { + ppp_change_phase(ctx, PPP_DEAD); + } - if (ctx->is_enabled == state) { + if (ctx->phase == PPP_DEAD) { return 0; } - ctx->is_enabled = state; + k_sem_reset(&ctx->wait_ppp_link_terminated); + ppp_lcp->close(ctx, "L2 Disabled"); + return k_sem_take(&ctx->wait_ppp_link_terminated, K_MSEC(CONFIG_NET_L2_PPP_TIMEOUT)); +} + +static void ppp_lcp_lower_down_async(struct ppp_context *ctx) +{ + if (ctx->phase == PPP_DEAD) { + return; + } - if (!state) { - if (ppp->stop) { - ppp->stop(net_if_get_device(iface)); + if (ppp_lcp == NULL) { + ppp_change_phase(ctx, PPP_DEAD); + } else { + ppp_lcp->lower_down(ctx); + } +} + +static int ppp_lcp_lower_down(struct ppp_context *ctx) +{ + if (ppp_lcp == NULL) { + ppp_change_phase(ctx, PPP_DEAD); + } + + if (ctx->phase == PPP_DEAD) { + return 0; + } + + k_sem_reset(&ctx->wait_ppp_link_down); + ppp_lcp->lower_down(ctx); + return k_sem_take(&ctx->wait_ppp_link_down, K_MSEC(CONFIG_NET_L2_PPP_TIMEOUT)); +} + +/* Bring down network interface by terminating all protocols */ +static int ppp_down(struct net_if *iface) +{ + const struct ppp_api *ppp = net_if_get_device(iface)->api; + struct ppp_context *ctx = net_if_l2_data(iface); + + if (net_if_is_carrier_ok(iface)) { + /* Terminate protocols and close LCP */ + if (ppp_lcp_close(ctx) < 0) { + return -EAGAIN; } } else { - if (ppp->start) { - ppp->start(net_if_get_device(iface)); + /* Terminate protocols */ + if (ppp_lcp_lower_down(ctx) < 0) { + return -EAGAIN; } } + + if (ppp->stop) { + /* Inform L2 PPP device that PPP link is down */ + ppp->stop(net_if_get_device(iface)); + } + return 0; } +static int ppp_enable(struct net_if *iface, bool state) +{ + struct ppp_context *ctx = net_if_l2_data(iface); + int ret; + + /* Set the desired network interface state */ + ctx->is_enabled = state; + + /* Attempt to enter desired state */ + if (state) { + ret = ppp_up(iface); + } else { + ret = ppp_down(iface); + } + + if (ret < 0) { + /* Reset the desired state */ + ctx->is_enabled = !state; + } + + return ret; +} + NET_L2_INIT(PPP_L2, ppp_recv, ppp_send, ppp_enable, ppp_flags); #if defined(CONFIG_NET_SHELL) @@ -388,13 +458,12 @@ static void net_ppp_mgmt_evt_handler(struct net_mgmt_event_callback *cb, uint32_ } if (mgmt_event == NET_EVENT_IF_UP) { - ppp_open(ctx); + ppp_open_async(ctx); return; } - if (mgmt_event == NET_EVENT_IF_DOWN) { - ppp_close(ctx); - return; + if ((mgmt_event == NET_EVENT_IF_DOWN) && (!net_if_is_carrier_ok(iface))) { + ppp_lcp_lower_down_async(ctx); } } @@ -409,6 +478,8 @@ void net_ppp_init(struct net_if *iface) ctx->ppp_l2_flags = NET_L2_MULTICAST | NET_L2_POINT_TO_POINT; ctx->iface = iface; + k_sem_init(&ctx->wait_ppp_link_terminated, 0, 1); + k_sem_init(&ctx->wait_ppp_link_down, 0, 1); #if defined(CONFIG_NET_SHELL) k_sem_init(&ctx->shell.wait_echo_reply, 0, K_SEM_MAX_LIMIT); From 822e8d4cc4766f69c78288e5cc0b791454e97dae Mon Sep 17 00:00:00 2001 From: Eduardo Montoya Date: Wed, 17 Jan 2024 15:26:10 +0100 Subject: [PATCH 2521/3723] net: openthread: remove unneded call to `otLinkMetricsInit` Platforms calculate Link Metrics values internally after using `otPlatRadioConfigureEnhAckProbing`. Signed-off-by: Eduardo Montoya --- modules/openthread/platform/radio.c | 4 ---- 1 file changed, 4 deletions(-) diff --git a/modules/openthread/platform/radio.c b/modules/openthread/platform/radio.c index a9fe75607da..e6b4e2617ed 100644 --- a/modules/openthread/platform/radio.c +++ b/modules/openthread/platform/radio.c @@ -363,10 +363,6 @@ void platformRadioInit(void) cfg.event_handler = handle_radio_event; radio_api->configure(radio_dev, IEEE802154_CONFIG_EVENT_HANDLER, &cfg); - -#if defined(CONFIG_OPENTHREAD_LINK_METRICS_SUBJECT) - otLinkMetricsInit(DEFAULT_SENSITIVITY); -#endif } void transmit_message(struct k_work *tx_job) From 9eee8d2be594a23eca102e21790e2d6db65ec2de Mon Sep 17 00:00:00 2001 From: Juha Ylinen Date: Wed, 17 Jan 2024 14:02:34 +0200 Subject: [PATCH 2522/3723] net: lwm2m: Allow send operations when sleeping Add new kconfig CONFIG_LWM2M_QUEUE_MODE_NO_MSG_BUFFERING. When enabled and device is sleeping, Reqistration Update message is skipped and messages from send operation and notifications are sent right away. Reqistration update message is also skipped when lwm2m_engine resumes from pause state. Signed-off-by: Juha Ylinen --- subsys/net/lib/lwm2m/Kconfig | 7 +++++++ subsys/net/lib/lwm2m/lwm2m_engine.c | 1 + subsys/net/lib/lwm2m/lwm2m_message_handling.c | 7 +++++++ subsys/net/lib/lwm2m/lwm2m_rd_client.c | 7 ++++++- 4 files changed, 21 insertions(+), 1 deletion(-) diff --git a/subsys/net/lib/lwm2m/Kconfig b/subsys/net/lib/lwm2m/Kconfig index 1e5a7ac8f6a..33a093308df 100644 --- a/subsys/net/lib/lwm2m/Kconfig +++ b/subsys/net/lib/lwm2m/Kconfig @@ -110,6 +110,13 @@ config LWM2M_QUEUE_MODE_UPTIME defaults to 93 seconds, see RFC 7252), it does not forbid other values though. +config LWM2M_QUEUE_MODE_NO_MSG_BUFFERING + bool "Disable buffering notifications and messages on queue mode" + select EXPERIMENTAL + help + Messages are sent right away instead of waiting for next registration update. + This might not be supported on all servers. + config LWM2M_TLS_SESSION_CACHING bool "TLS session caching" help diff --git a/subsys/net/lib/lwm2m/lwm2m_engine.c b/subsys/net/lib/lwm2m/lwm2m_engine.c index e08bb4ca17e..60ea1bdb794 100644 --- a/subsys/net/lib/lwm2m/lwm2m_engine.c +++ b/subsys/net/lib/lwm2m/lwm2m_engine.c @@ -244,6 +244,7 @@ int lwm2m_push_queued_buffers(struct lwm2m_ctx *client_ctx) break; } msg = SYS_SLIST_CONTAINER(msg_node, msg, node); + msg->pending->t0 = k_uptime_get(); sys_slist_append(&msg->ctx->pending_sends, &msg->node); } #endif diff --git a/subsys/net/lib/lwm2m/lwm2m_message_handling.c b/subsys/net/lib/lwm2m/lwm2m_message_handling.c index 480c64372e8..19a2e1ccdd0 100644 --- a/subsys/net/lib/lwm2m/lwm2m_message_handling.c +++ b/subsys/net/lib/lwm2m/lwm2m_message_handling.c @@ -726,6 +726,13 @@ int lwm2m_information_interface_send(struct lwm2m_message *msg) return ret; } + if (IS_ENABLED(CONFIG_LWM2M_QUEUE_MODE_NO_MSG_BUFFERING)) { + sys_slist_append(&msg->ctx->pending_sends, &msg->node); + lwm2m_engine_wake_up(); + lwm2m_engine_connection_resume(msg->ctx); + return 0; + } + if (msg->ctx->buffer_client_messages) { sys_slist_append(&msg->ctx->queued_messages, &msg->node); lwm2m_engine_wake_up(); diff --git a/subsys/net/lib/lwm2m/lwm2m_rd_client.c b/subsys/net/lib/lwm2m/lwm2m_rd_client.c index 95b576cb1c6..22ce51e5248 100644 --- a/subsys/net/lib/lwm2m/lwm2m_rd_client.c +++ b/subsys/net/lib/lwm2m/lwm2m_rd_client.c @@ -1726,7 +1726,12 @@ int lwm2m_rd_client_connection_resume(struct lwm2m_ctx *client_ctx) IS_ENABLED(CONFIG_LWM2M_RD_CLIENT_LISTEN_AT_IDLE)) || !IS_ENABLED(CONFIG_LWM2M_DTLS_SUPPORT)) { client.engine_state = ENGINE_REGISTRATION_DONE; - client.trigger_update = true; + if (IS_ENABLED(CONFIG_LWM2M_QUEUE_MODE_NO_MSG_BUFFERING)) { + /* Force online for a short period */ + engine_update_tx_time(); + } else { + client.trigger_update = true; + } } else { client.engine_state = ENGINE_DO_REGISTRATION; } From c84dc7ee2ed6211eae7ec33abdbe5472fd5bf621 Mon Sep 17 00:00:00 2001 From: Juha Ylinen Date: Thu, 18 Jan 2024 09:55:02 +0200 Subject: [PATCH 2523/3723] tests: lwm2m: Update lwm2m_engine tests Fix lwm2m_message initialization. Pending struct was NULL. Signed-off-by: Juha Ylinen --- tests/net/lib/lwm2m/lwm2m_engine/src/main.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/tests/net/lib/lwm2m/lwm2m_engine/src/main.c b/tests/net/lib/lwm2m/lwm2m_engine/src/main.c index 5d80f5d1049..7078fbebe6d 100644 --- a/tests/net/lib/lwm2m/lwm2m_engine/src/main.c +++ b/tests/net/lib/lwm2m/lwm2m_engine/src/main.c @@ -260,11 +260,13 @@ ZTEST(lwm2m_engine, test_push_queued_buffers) int ret; struct lwm2m_ctx ctx; struct lwm2m_message msg; + struct coap_pending pending; (void)memset(&ctx, 0x0, sizeof(ctx)); sys_slist_init(&ctx.queued_messages); msg.ctx = &ctx; + msg.pending = &pending; sys_slist_append(&ctx.queued_messages, &msg.node); ret = lwm2m_push_queued_buffers(&ctx); zassert_equal(ret, 0); @@ -391,6 +393,7 @@ ZTEST(lwm2m_engine, test_socket_send) int ret; struct lwm2m_ctx ctx; struct lwm2m_message msg; + struct coap_pending pending; (void)memset(&ctx, 0x0, sizeof(ctx)); @@ -398,6 +401,7 @@ ZTEST(lwm2m_engine, test_socket_send) ctx.sock_fd = -1; sys_slist_init(&ctx.queued_messages); msg.ctx = &ctx; + msg.pending = &pending; msg.type = COAP_TYPE_CON; sys_slist_append(&ctx.queued_messages, &msg.node); From 60a9929affda3ecc2d3d280359c58de8e389f4c6 Mon Sep 17 00:00:00 2001 From: Daniel DeGrasse Date: Tue, 16 Jan 2024 16:22:11 -0600 Subject: [PATCH 2524/3723] boards: update generation comments for NXP board pinctrl files Update generation comment for NXP board pin control files, to point users to the current pin control scripting files in NXP's HAL. Note that these files have not been regenerated- the script name simply has changed, so update these references to avoid confusion. Signed-off-by: Daniel DeGrasse --- boards/arm/frdm_k22f/frdm_k22f-pinctrl.dtsi | 2 +- boards/arm/frdm_k64f/frdm_k64f-pinctrl.dtsi | 2 +- boards/arm/frdm_k82f/frdm_k82f-pinctrl.dtsi | 2 +- boards/arm/frdm_kl25z/frdm_kl25z-pinctrl.dtsi | 2 +- boards/arm/frdm_kw41z/frdm_kw41z-pinctrl.dtsi | 2 +- boards/arm/hexiwear_k64/hexiwear_k64-pinctrl.dtsi | 2 +- boards/arm/ip_k66f/ip_k66f-pinctrl.dtsi | 2 +- boards/arm/lpcxpresso51u68/lpcxpresso51u68-pinctrl.dtsi | 2 +- boards/arm/lpcxpresso54114/lpcxpresso54114-pinctrl.dtsi | 2 +- boards/arm/lpcxpresso55s06/lpcxpresso55s06-pinctrl.dtsi | 2 +- boards/arm/lpcxpresso55s16/lpcxpresso55s16-pinctrl.dtsi | 2 +- boards/arm/lpcxpresso55s28/lpcxpresso55s28-pinctrl.dtsi | 2 +- boards/arm/lpcxpresso55s36/lpcxpresso55s36-pinctrl.dtsi | 2 +- boards/arm/lpcxpresso55s69/lpcxpresso55s69-pinctrl.dtsi | 2 +- boards/arm/mimx8mm_evk/mimx8mm_evk-pinctrl.dtsi | 2 +- boards/arm/mimx8mp_evk/mimx8mp_evk-pinctrl.dtsi | 2 +- boards/arm/mimx8mq_evk/mimx8mq_evk-pinctrl.dtsi | 2 +- boards/arm/mimxrt1010_evk/mimxrt1010_evk-pinctrl.dtsi | 2 +- boards/arm/mimxrt1015_evk/mimxrt1015_evk-pinctrl.dtsi | 2 +- boards/arm/mimxrt1020_evk/mimxrt1020_evk-pinctrl.dtsi | 2 +- boards/arm/mimxrt1024_evk/mimxrt1024_evk-pinctrl.dtsi | 2 +- boards/arm/mimxrt1040_evk/mimxrt1040_evk-pinctrl.dtsi | 2 +- boards/arm/mimxrt1050_evk/mimxrt1050_evk-pinctrl.dtsi | 2 +- boards/arm/mimxrt1060_evk/mimxrt1060_evk-pinctrl.dtsi | 2 +- boards/arm/mimxrt1064_evk/mimxrt1064_evk-pinctrl.dtsi | 2 +- boards/arm/mimxrt1160_evk/mimxrt1160_evk-pinctrl.dtsi | 2 +- boards/arm/mimxrt1170_evk/mimxrt1170_evk-pinctrl.dtsi | 2 +- boards/arm/mimxrt595_evk/mimxrt595_evk_cm33-pinctrl.dtsi | 2 +- boards/arm/mimxrt685_evk/mimxrt685_evk_cm33-pinctrl.dtsi | 2 +- boards/arm/mm_feather/mm_feather-pinctrl.dtsi | 2 +- boards/arm/mm_swiftio/mm_swiftio-pinctrl.dtsi | 2 +- boards/arm/rddrone_fmuk66/rddrone_fmuk66-pinctrl.dtsi | 2 +- boards/arm/teensy4/teensy4-pinctrl.dtsi | 2 +- boards/arm/twr_ke18f/twr_ke18f-pinctrl.dtsi | 2 +- boards/arm/twr_kv58f220m/twr_kv58f220m-pinctrl.dtsi | 2 +- boards/arm/usb_kw24d512/usb_kw24d512-pinctrl.dtsi | 2 +- boards/arm/vmu_rt1170/vmu_rt1170-pinctrl.dtsi | 2 +- 37 files changed, 37 insertions(+), 37 deletions(-) diff --git a/boards/arm/frdm_k22f/frdm_k22f-pinctrl.dtsi b/boards/arm/frdm_k22f/frdm_k22f-pinctrl.dtsi index 6249cc554df..14d6fe7d021 100644 --- a/boards/arm/frdm_k22f/frdm_k22f-pinctrl.dtsi +++ b/boards/arm/frdm_k22f/frdm_k22f-pinctrl.dtsi @@ -1,5 +1,5 @@ /* - * NOTE: Autogenerated file by kinetis_signal2dts.py + * NOTE: Autogenerated file by gen_board_pinctrl.py * for MK22FN512VLH12/signal_configuration.xml * * Copyright (c) 2022, NXP diff --git a/boards/arm/frdm_k64f/frdm_k64f-pinctrl.dtsi b/boards/arm/frdm_k64f/frdm_k64f-pinctrl.dtsi index 5ac35405bdd..70af2305ce8 100644 --- a/boards/arm/frdm_k64f/frdm_k64f-pinctrl.dtsi +++ b/boards/arm/frdm_k64f/frdm_k64f-pinctrl.dtsi @@ -1,5 +1,5 @@ /* - * NOTE: Autogenerated file by kinetis_cfg_utils.py + * NOTE: Autogenerated file by gen_board_pinctrl.py * for MK64FN1M0VLL12/signal_configuration.xml * * Copyright (c) 2022, NXP diff --git a/boards/arm/frdm_k82f/frdm_k82f-pinctrl.dtsi b/boards/arm/frdm_k82f/frdm_k82f-pinctrl.dtsi index d09e5bcaa37..41fd7d9d210 100644 --- a/boards/arm/frdm_k82f/frdm_k82f-pinctrl.dtsi +++ b/boards/arm/frdm_k82f/frdm_k82f-pinctrl.dtsi @@ -1,5 +1,5 @@ /* - * NOTE: Autogenerated file by kinetis_cfg_utils.py + * NOTE: Autogenerated file by gen_board_pinctrl.py * for MK82FN256VLL15/signal_configuration.xml * * Copyright (c) 2022, NXP diff --git a/boards/arm/frdm_kl25z/frdm_kl25z-pinctrl.dtsi b/boards/arm/frdm_kl25z/frdm_kl25z-pinctrl.dtsi index 925aaf7fafe..d4326c422a2 100644 --- a/boards/arm/frdm_kl25z/frdm_kl25z-pinctrl.dtsi +++ b/boards/arm/frdm_kl25z/frdm_kl25z-pinctrl.dtsi @@ -1,5 +1,5 @@ /* - * NOTE: Autogenerated file by kinetis_signal2dts.py + * NOTE: Autogenerated file by gen_board_pinctrl.py * for MKL25Z128VLK4/signal_configuration.xml * * Copyright (c) 2022, NXP diff --git a/boards/arm/frdm_kw41z/frdm_kw41z-pinctrl.dtsi b/boards/arm/frdm_kw41z/frdm_kw41z-pinctrl.dtsi index 2377304c5c1..af7cbf8f26e 100644 --- a/boards/arm/frdm_kw41z/frdm_kw41z-pinctrl.dtsi +++ b/boards/arm/frdm_kw41z/frdm_kw41z-pinctrl.dtsi @@ -1,5 +1,5 @@ /* - * NOTE: Autogenerated file by kinetis_signal2dts.py + * NOTE: Autogenerated file by gen_board_pinctrl.py * for MKW41Z512VHT4/signal_configuration.xml * * Copyright (c) 2022, NXP diff --git a/boards/arm/hexiwear_k64/hexiwear_k64-pinctrl.dtsi b/boards/arm/hexiwear_k64/hexiwear_k64-pinctrl.dtsi index 255e1df3942..a776221cc32 100644 --- a/boards/arm/hexiwear_k64/hexiwear_k64-pinctrl.dtsi +++ b/boards/arm/hexiwear_k64/hexiwear_k64-pinctrl.dtsi @@ -1,5 +1,5 @@ /* - * NOTE: Autogenerated file by kinetis_signal2dts.py + * NOTE: Autogenerated file by gen_board_pinctrl.py * for MK64FN1M0VDC12/signal_configuration.xml * * Copyright (c) 2022, NXP diff --git a/boards/arm/ip_k66f/ip_k66f-pinctrl.dtsi b/boards/arm/ip_k66f/ip_k66f-pinctrl.dtsi index 86e0e71a4ca..30ccd75c81a 100644 --- a/boards/arm/ip_k66f/ip_k66f-pinctrl.dtsi +++ b/boards/arm/ip_k66f/ip_k66f-pinctrl.dtsi @@ -1,5 +1,5 @@ /* - * NOTE: Autogenerated file by kinetis_cfg_utils.py + * NOTE: Autogenerated file by gen_board_pinctrl.py * for MK66FN2M0VMD18/signal_configuration.xml * * Copyright (c) 2022, NXP diff --git a/boards/arm/lpcxpresso51u68/lpcxpresso51u68-pinctrl.dtsi b/boards/arm/lpcxpresso51u68/lpcxpresso51u68-pinctrl.dtsi index a99ee0b6018..da944a569f5 100644 --- a/boards/arm/lpcxpresso51u68/lpcxpresso51u68-pinctrl.dtsi +++ b/boards/arm/lpcxpresso51u68/lpcxpresso51u68-pinctrl.dtsi @@ -1,5 +1,5 @@ /* - * NOTE: File generated by lpc_cfg_utils.py + * NOTE: File generated by gen_board_pinctrl.py * from LPCXpresso51U68.mex */ diff --git a/boards/arm/lpcxpresso54114/lpcxpresso54114-pinctrl.dtsi b/boards/arm/lpcxpresso54114/lpcxpresso54114-pinctrl.dtsi index 7647f98ad44..b648cd94c4f 100644 --- a/boards/arm/lpcxpresso54114/lpcxpresso54114-pinctrl.dtsi +++ b/boards/arm/lpcxpresso54114/lpcxpresso54114-pinctrl.dtsi @@ -1,5 +1,5 @@ /* - * NOTE: File generated by lpc_cfg_utils.py + * NOTE: File generated by gen_board_pinctrl.py * from LPCXpresso54114.mex * * Copyright 2022 NXP diff --git a/boards/arm/lpcxpresso55s06/lpcxpresso55s06-pinctrl.dtsi b/boards/arm/lpcxpresso55s06/lpcxpresso55s06-pinctrl.dtsi index 3f4ed27b488..a6be7665a10 100644 --- a/boards/arm/lpcxpresso55s06/lpcxpresso55s06-pinctrl.dtsi +++ b/boards/arm/lpcxpresso55s06/lpcxpresso55s06-pinctrl.dtsi @@ -1,5 +1,5 @@ /* - * NOTE: File generated by lpc_cfg_utils.py + * NOTE: File generated by gen_board_pinctrl.py * from LPCXpresso55S06.mex * * Copyright 2022 NXP diff --git a/boards/arm/lpcxpresso55s16/lpcxpresso55s16-pinctrl.dtsi b/boards/arm/lpcxpresso55s16/lpcxpresso55s16-pinctrl.dtsi index c0b2c76c540..5da72450523 100644 --- a/boards/arm/lpcxpresso55s16/lpcxpresso55s16-pinctrl.dtsi +++ b/boards/arm/lpcxpresso55s16/lpcxpresso55s16-pinctrl.dtsi @@ -1,5 +1,5 @@ /* - * NOTE: File generated by lpc_cfg_utils.py + * NOTE: File generated by gen_board_pinctrl.py * from LPCXpresso55S16.mex * * Copyright 2022 NXP diff --git a/boards/arm/lpcxpresso55s28/lpcxpresso55s28-pinctrl.dtsi b/boards/arm/lpcxpresso55s28/lpcxpresso55s28-pinctrl.dtsi index a8955d2a034..dbf467f3c16 100644 --- a/boards/arm/lpcxpresso55s28/lpcxpresso55s28-pinctrl.dtsi +++ b/boards/arm/lpcxpresso55s28/lpcxpresso55s28-pinctrl.dtsi @@ -1,5 +1,5 @@ /* - * NOTE: File generated by lpc_cfg_utils.py + * NOTE: File generated by gen_board_pinctrl.py * from LPCXpresso55S28.mex * * Copyright 2022 NXP diff --git a/boards/arm/lpcxpresso55s36/lpcxpresso55s36-pinctrl.dtsi b/boards/arm/lpcxpresso55s36/lpcxpresso55s36-pinctrl.dtsi index 8ca6f659f2e..619b275b593 100644 --- a/boards/arm/lpcxpresso55s36/lpcxpresso55s36-pinctrl.dtsi +++ b/boards/arm/lpcxpresso55s36/lpcxpresso55s36-pinctrl.dtsi @@ -1,5 +1,5 @@ /* - * NOTE: File generated by lpc_cfg_utils.py + * NOTE: File generated by gen_board_pinctrl.py * from LPC55S36.mex * * Copyright 2022-2023 NXP diff --git a/boards/arm/lpcxpresso55s69/lpcxpresso55s69-pinctrl.dtsi b/boards/arm/lpcxpresso55s69/lpcxpresso55s69-pinctrl.dtsi index 5842f1f7eb2..96997936388 100644 --- a/boards/arm/lpcxpresso55s69/lpcxpresso55s69-pinctrl.dtsi +++ b/boards/arm/lpcxpresso55s69/lpcxpresso55s69-pinctrl.dtsi @@ -1,5 +1,5 @@ /* - * NOTE: File generated by lpc_cfg_utils.py + * NOTE: File generated by gen_board_pinctrl.py * from LPCXpresso55S69.mex * * Copyright 2022 NXP diff --git a/boards/arm/mimx8mm_evk/mimx8mm_evk-pinctrl.dtsi b/boards/arm/mimx8mm_evk/mimx8mm_evk-pinctrl.dtsi index c345742bc7e..c7b1943810e 100644 --- a/boards/arm/mimx8mm_evk/mimx8mm_evk-pinctrl.dtsi +++ b/boards/arm/mimx8mm_evk/mimx8mm_evk-pinctrl.dtsi @@ -2,7 +2,7 @@ * Copyright (c) 2022, NXP * SPDX-License-Identifier: Apache-2.0 * - * Note: File generated by imx_cfg_utils.py + * Note: File generated by gen_board_pinctrl.py * from MIMX8MM-EVK-REV-C.mex */ diff --git a/boards/arm/mimx8mp_evk/mimx8mp_evk-pinctrl.dtsi b/boards/arm/mimx8mp_evk/mimx8mp_evk-pinctrl.dtsi index f9ca5de1ff2..a690f201ba1 100644 --- a/boards/arm/mimx8mp_evk/mimx8mp_evk-pinctrl.dtsi +++ b/boards/arm/mimx8mp_evk/mimx8mp_evk-pinctrl.dtsi @@ -2,7 +2,7 @@ * Copyright (c) 2022, NXP * SPDX-License-Identifier: Apache-2.0 * - * Note: File generated by imx_cfg_utils.py + * Note: File generated by gen_board_pinctrl.py * from MIMX8MP-EVK-REV-A.mex */ diff --git a/boards/arm/mimx8mq_evk/mimx8mq_evk-pinctrl.dtsi b/boards/arm/mimx8mq_evk/mimx8mq_evk-pinctrl.dtsi index 62e3944f73c..c29fdcc7d28 100644 --- a/boards/arm/mimx8mq_evk/mimx8mq_evk-pinctrl.dtsi +++ b/boards/arm/mimx8mq_evk/mimx8mq_evk-pinctrl.dtsi @@ -2,7 +2,7 @@ * Copyright (c) 2022, NXP * SPDX-License-Identifier: Apache-2.0 * - * Note: File generated by imx_cfg_utils.py + * Note: File generated by gen_board_pinctrl.py * from fsl-imx8mq-evk.mex */ diff --git a/boards/arm/mimxrt1010_evk/mimxrt1010_evk-pinctrl.dtsi b/boards/arm/mimxrt1010_evk/mimxrt1010_evk-pinctrl.dtsi index 65b31812349..9d190081e32 100644 --- a/boards/arm/mimxrt1010_evk/mimxrt1010_evk-pinctrl.dtsi +++ b/boards/arm/mimxrt1010_evk/mimxrt1010_evk-pinctrl.dtsi @@ -2,7 +2,7 @@ * Copyright (c) 2022, NXP * SPDX-License-Identifier: Apache-2.0 * - * Note: File generated by rt_cfg_utils.py + * Note: File generated by gen_board_pinctrl.py * from mimxrt1010_evk.mex */ diff --git a/boards/arm/mimxrt1015_evk/mimxrt1015_evk-pinctrl.dtsi b/boards/arm/mimxrt1015_evk/mimxrt1015_evk-pinctrl.dtsi index 412eeeb0e4c..b77d1ee424e 100644 --- a/boards/arm/mimxrt1015_evk/mimxrt1015_evk-pinctrl.dtsi +++ b/boards/arm/mimxrt1015_evk/mimxrt1015_evk-pinctrl.dtsi @@ -2,7 +2,7 @@ * Copyright (c) 2022, NXP * SPDX-License-Identifier: Apache-2.0 * - * Note: File generated by rt_cfg_utils.py + * Note: File generated by gen_board_pinctrl.py * from mimxrt1015_evk.mex */ diff --git a/boards/arm/mimxrt1020_evk/mimxrt1020_evk-pinctrl.dtsi b/boards/arm/mimxrt1020_evk/mimxrt1020_evk-pinctrl.dtsi index 8da66d34084..9fe3a42bf9f 100644 --- a/boards/arm/mimxrt1020_evk/mimxrt1020_evk-pinctrl.dtsi +++ b/boards/arm/mimxrt1020_evk/mimxrt1020_evk-pinctrl.dtsi @@ -2,7 +2,7 @@ * Copyright (c) 2022, NXP * SPDX-License-Identifier: Apache-2.0 * - * Note: File generated by rt_cfg_utils.py + * Note: File generated by gen_board_pinctrl.py * from mimxrt1020_evk.mex */ diff --git a/boards/arm/mimxrt1024_evk/mimxrt1024_evk-pinctrl.dtsi b/boards/arm/mimxrt1024_evk/mimxrt1024_evk-pinctrl.dtsi index 3e27286cc23..1090e394381 100644 --- a/boards/arm/mimxrt1024_evk/mimxrt1024_evk-pinctrl.dtsi +++ b/boards/arm/mimxrt1024_evk/mimxrt1024_evk-pinctrl.dtsi @@ -2,7 +2,7 @@ * Copyright (c) 2022, NXP * SPDX-License-Identifier: Apache-2.0 * - * Note: File generated by rt_cfg_utils.py + * Note: File generated by gen_board_pinctrl.py * from mimxrt1024_evk.mex */ diff --git a/boards/arm/mimxrt1040_evk/mimxrt1040_evk-pinctrl.dtsi b/boards/arm/mimxrt1040_evk/mimxrt1040_evk-pinctrl.dtsi index 2ddc0771bb0..ad26eeecc3f 100644 --- a/boards/arm/mimxrt1040_evk/mimxrt1040_evk-pinctrl.dtsi +++ b/boards/arm/mimxrt1040_evk/mimxrt1040_evk-pinctrl.dtsi @@ -2,7 +2,7 @@ * Copyright (c) 2023, NXP * SPDX-License-Identifier: Apache-2.0 * - * Note: File generated by imx_cfg_utils.py + * Note: File generated by gen_board_pinctrl.py * from mimxrt1040_evk.mex */ diff --git a/boards/arm/mimxrt1050_evk/mimxrt1050_evk-pinctrl.dtsi b/boards/arm/mimxrt1050_evk/mimxrt1050_evk-pinctrl.dtsi index 27e48b64ae8..1b73a7453a9 100644 --- a/boards/arm/mimxrt1050_evk/mimxrt1050_evk-pinctrl.dtsi +++ b/boards/arm/mimxrt1050_evk/mimxrt1050_evk-pinctrl.dtsi @@ -2,7 +2,7 @@ * Copyright (c) 2022, NXP * SPDX-License-Identifier: Apache-2.0 * - * Note: File generated by rt_cfg_utils.py + * Note: File generated by gen_board_pinctrl.py * from mimxrt1050_evk.mex */ diff --git a/boards/arm/mimxrt1060_evk/mimxrt1060_evk-pinctrl.dtsi b/boards/arm/mimxrt1060_evk/mimxrt1060_evk-pinctrl.dtsi index 7d2ff7a43e4..f41f92ba1ee 100644 --- a/boards/arm/mimxrt1060_evk/mimxrt1060_evk-pinctrl.dtsi +++ b/boards/arm/mimxrt1060_evk/mimxrt1060_evk-pinctrl.dtsi @@ -2,7 +2,7 @@ * Copyright (c) 2022, NXP * SPDX-License-Identifier: Apache-2.0 * - * Note: File generated by imx_cfg_utils.py + * Note: File generated by gen_board_pinctrl.py * from mimxrt1060_evk.mex */ diff --git a/boards/arm/mimxrt1064_evk/mimxrt1064_evk-pinctrl.dtsi b/boards/arm/mimxrt1064_evk/mimxrt1064_evk-pinctrl.dtsi index 043b421dcfb..d8be3020998 100644 --- a/boards/arm/mimxrt1064_evk/mimxrt1064_evk-pinctrl.dtsi +++ b/boards/arm/mimxrt1064_evk/mimxrt1064_evk-pinctrl.dtsi @@ -2,7 +2,7 @@ * Copyright (c) 2022, NXP * SPDX-License-Identifier: Apache-2.0 * - * Note: File generated by imx_cfg_utils.py + * Note: File generated by gen_board_pinctrl.py * from mimxrt1064_evk.mex */ diff --git a/boards/arm/mimxrt1160_evk/mimxrt1160_evk-pinctrl.dtsi b/boards/arm/mimxrt1160_evk/mimxrt1160_evk-pinctrl.dtsi index f2a3c4ff9dd..1f17d8d62de 100644 --- a/boards/arm/mimxrt1160_evk/mimxrt1160_evk-pinctrl.dtsi +++ b/boards/arm/mimxrt1160_evk/mimxrt1160_evk-pinctrl.dtsi @@ -2,7 +2,7 @@ * Copyright (c) 2022, NXP * SPDX-License-Identifier: Apache-2.0 * - * Note: File generated by rt_cfg_utils.py + * Note: File generated by gen_board_pinctrl.py * from mimxrt1160_evk.mex */ diff --git a/boards/arm/mimxrt1170_evk/mimxrt1170_evk-pinctrl.dtsi b/boards/arm/mimxrt1170_evk/mimxrt1170_evk-pinctrl.dtsi index 41a5607e728..35e7c521532 100644 --- a/boards/arm/mimxrt1170_evk/mimxrt1170_evk-pinctrl.dtsi +++ b/boards/arm/mimxrt1170_evk/mimxrt1170_evk-pinctrl.dtsi @@ -2,7 +2,7 @@ * Copyright (c) 2022, NXP * SPDX-License-Identifier: Apache-2.0 * - * Note: File generated by rt_cfg_utils.py + * Note: File generated by gen_board_pinctrl.py * from mimxrt1170_evk.mex */ diff --git a/boards/arm/mimxrt595_evk/mimxrt595_evk_cm33-pinctrl.dtsi b/boards/arm/mimxrt595_evk/mimxrt595_evk_cm33-pinctrl.dtsi index f00f6a34d0f..3f1bb622689 100644 --- a/boards/arm/mimxrt595_evk/mimxrt595_evk_cm33-pinctrl.dtsi +++ b/boards/arm/mimxrt595_evk/mimxrt595_evk_cm33-pinctrl.dtsi @@ -1,5 +1,5 @@ /* - * NOTE: File generated by lpc_cfg_utils.py + * NOTE: File generated by gen_board_pinctrl.py * from MIMXRT595-EVK.mex * * Copyright 2022, NXP diff --git a/boards/arm/mimxrt685_evk/mimxrt685_evk_cm33-pinctrl.dtsi b/boards/arm/mimxrt685_evk/mimxrt685_evk_cm33-pinctrl.dtsi index ef48a752ef5..63febf90fce 100644 --- a/boards/arm/mimxrt685_evk/mimxrt685_evk_cm33-pinctrl.dtsi +++ b/boards/arm/mimxrt685_evk/mimxrt685_evk_cm33-pinctrl.dtsi @@ -1,5 +1,5 @@ /* - * NOTE: File generated by lpc_cfg_utils.py + * NOTE: File generated by gen_board_pinctrl.py * from MIMXRT685-EVK.mex * * Copyright 2022, NXP diff --git a/boards/arm/mm_feather/mm_feather-pinctrl.dtsi b/boards/arm/mm_feather/mm_feather-pinctrl.dtsi index f16de683d36..4a8c410bce9 100644 --- a/boards/arm/mm_feather/mm_feather-pinctrl.dtsi +++ b/boards/arm/mm_feather/mm_feather-pinctrl.dtsi @@ -2,7 +2,7 @@ * Copyright (c) 2022, NXP * SPDX-License-Identifier: Apache-2.0 * - * Note: File generated by rt_cfg_utils.py + * Note: File generated by gen_board_pinctrl.py * from mm_feather.mex */ diff --git a/boards/arm/mm_swiftio/mm_swiftio-pinctrl.dtsi b/boards/arm/mm_swiftio/mm_swiftio-pinctrl.dtsi index 1a385a3babc..1a9b44a01c0 100644 --- a/boards/arm/mm_swiftio/mm_swiftio-pinctrl.dtsi +++ b/boards/arm/mm_swiftio/mm_swiftio-pinctrl.dtsi @@ -2,7 +2,7 @@ * Copyright (c) 2022, NXP * SPDX-License-Identifier: Apache-2.0 * - * Note: File generated by rt_cfg_utils.py + * Note: File generated by gen_board_pinctrl.py * from mm_swiftio.mex */ diff --git a/boards/arm/rddrone_fmuk66/rddrone_fmuk66-pinctrl.dtsi b/boards/arm/rddrone_fmuk66/rddrone_fmuk66-pinctrl.dtsi index e1b4c3f971a..5d560f26154 100644 --- a/boards/arm/rddrone_fmuk66/rddrone_fmuk66-pinctrl.dtsi +++ b/boards/arm/rddrone_fmuk66/rddrone_fmuk66-pinctrl.dtsi @@ -1,5 +1,5 @@ /* - * NOTE: Autogenerated file by kinetis_cfg_utils.py + * NOTE: Autogenerated file by gen_board_pinctrl.py * for MK66FN2M0VMD18/signal_configuration.xml * * Copyright (c) 2022, NXP diff --git a/boards/arm/teensy4/teensy4-pinctrl.dtsi b/boards/arm/teensy4/teensy4-pinctrl.dtsi index 87e1e7ded41..4d9964bb521 100644 --- a/boards/arm/teensy4/teensy4-pinctrl.dtsi +++ b/boards/arm/teensy4/teensy4-pinctrl.dtsi @@ -2,7 +2,7 @@ * Copyright (c) 2022, NXP * SPDX-License-Identifier: Apache-2.0 * - * Note: File generated by rt_cfg_utils.py + * Note: File generated by gen_board_pinctrl.py * from teensy4.mex */ diff --git a/boards/arm/twr_ke18f/twr_ke18f-pinctrl.dtsi b/boards/arm/twr_ke18f/twr_ke18f-pinctrl.dtsi index 4e8f4849f75..d16cb81f896 100644 --- a/boards/arm/twr_ke18f/twr_ke18f-pinctrl.dtsi +++ b/boards/arm/twr_ke18f/twr_ke18f-pinctrl.dtsi @@ -1,5 +1,5 @@ /* - * NOTE: Autogenerated file by kinetis_cfg_utils.py + * NOTE: Autogenerated file by gen_board_pinctrl.py * for MKE18F512VLL16/signal_configuration.xml * * Copyright (c) 2022, NXP diff --git a/boards/arm/twr_kv58f220m/twr_kv58f220m-pinctrl.dtsi b/boards/arm/twr_kv58f220m/twr_kv58f220m-pinctrl.dtsi index 2495acc5e41..06e2deaf3d4 100644 --- a/boards/arm/twr_kv58f220m/twr_kv58f220m-pinctrl.dtsi +++ b/boards/arm/twr_kv58f220m/twr_kv58f220m-pinctrl.dtsi @@ -1,5 +1,5 @@ /* - * NOTE: Autogenerated file by kinetis_signal2dts.py + * NOTE: Autogenerated file by gen_board_pinctrl.py * for MKV58F1M0VLQ24/signal_configuration.xml * * Copyright (c) 2022, NXP diff --git a/boards/arm/usb_kw24d512/usb_kw24d512-pinctrl.dtsi b/boards/arm/usb_kw24d512/usb_kw24d512-pinctrl.dtsi index 143c28cff93..fd067dbf840 100644 --- a/boards/arm/usb_kw24d512/usb_kw24d512-pinctrl.dtsi +++ b/boards/arm/usb_kw24d512/usb_kw24d512-pinctrl.dtsi @@ -1,5 +1,5 @@ /* - * NOTE: Autogenerated file by kinetis_signal2dts.py + * NOTE: Autogenerated file by gen_board_pinctrl.py * for MKW24D512VHA5/signal_configuration.xml * * Copyright (c) 2022, NXP diff --git a/boards/arm/vmu_rt1170/vmu_rt1170-pinctrl.dtsi b/boards/arm/vmu_rt1170/vmu_rt1170-pinctrl.dtsi index d556fff21ae..d25bffa04c5 100644 --- a/boards/arm/vmu_rt1170/vmu_rt1170-pinctrl.dtsi +++ b/boards/arm/vmu_rt1170/vmu_rt1170-pinctrl.dtsi @@ -2,7 +2,7 @@ * Copyright 2023 NXP * SPDX-License-Identifier: Apache-2.0 * - * Note: File generated by rt_cfg_utils.py + * Note: File generated by gen_board_pinctrl.py * from vmu_rt1170.mex */ From c405d8d68f257a7d19d4241a29ad58a2d6b5f4f0 Mon Sep 17 00:00:00 2001 From: Lukasz Mrugala Date: Mon, 18 Dec 2023 14:43:45 +0000 Subject: [PATCH 2525/3723] scripts: tests: Blackbox test expansion Adds five new tests, covering six more flags: * -s, --test * --sub-test * -G, --integration * --test-config * --level * --filter Signed-off-by: Lukasz Mrugala --- .../test_data/test_config.yaml | 14 ++ scripts/tests/twister_blackbox/test_error.py | 63 ++++++ .../tests/twister_blackbox/test_testplan.py | 186 ++++++++++++++++++ 3 files changed, 263 insertions(+) create mode 100644 scripts/tests/twister_blackbox/test_data/test_config.yaml create mode 100644 scripts/tests/twister_blackbox/test_error.py create mode 100644 scripts/tests/twister_blackbox/test_testplan.py diff --git a/scripts/tests/twister_blackbox/test_data/test_config.yaml b/scripts/tests/twister_blackbox/test_data/test_config.yaml new file mode 100644 index 00000000000..d7e4828350c --- /dev/null +++ b/scripts/tests/twister_blackbox/test_data/test_config.yaml @@ -0,0 +1,14 @@ +platforms: + override_default_platforms: false + increased_platform_scope: true +levels: + - name: smoke + description: > + A plan to be used verifying basic features + adds: + - dummy.agnostic.* + - name: acceptance + description: > + More coverage + adds: + - dummy.* diff --git a/scripts/tests/twister_blackbox/test_error.py b/scripts/tests/twister_blackbox/test_error.py new file mode 100644 index 00000000000..693b90f5228 --- /dev/null +++ b/scripts/tests/twister_blackbox/test_error.py @@ -0,0 +1,63 @@ +#!/usr/bin/env python3 +# Copyright (c) 2024 Intel Corporation +# +# SPDX-License-Identifier: Apache-2.0 +""" +Blackbox tests for twister's command line functions - simple does-error-out or not tests +""" + +import importlib +import mock +import os +import pytest +import sys + +from conftest import ZEPHYR_BASE, TEST_DATA, testsuite_filename_mock +from twisterlib.testplan import TestPlan +from twisterlib.error import TwisterRuntimeError + + +class TestError: + TESTDATA_1 = [ + ( + os.path.join('scripts', 'tests', 'twister_blackbox', 'test_data', 'tests', + 'dummy', 'agnostic', 'group1', 'subgroup1', + 'dummy.agnostic.group1.subgroup1'), + SystemExit + ), + ('dummy.agnostic.group1.subgroup1', TwisterRuntimeError), + ] + + @classmethod + def setup_class(cls): + apath = os.path.join(ZEPHYR_BASE, 'scripts', 'twister') + cls.loader = importlib.machinery.SourceFileLoader('__main__', apath) + cls.spec = importlib.util.spec_from_loader(cls.loader.name, cls.loader) + cls.twister_module = importlib.util.module_from_spec(cls.spec) + + @classmethod + def teardown_class(cls): + pass + + @pytest.mark.usefixtures("clear_log") + @pytest.mark.parametrize( + 'test, expected_exception', + TESTDATA_1, + ids=['valid', 'invalid'] + ) + @mock.patch.object(TestPlan, 'TESTSUITE_FILENAME', testsuite_filename_mock) + def test_test(self, out_path, test, expected_exception): + test_platforms = ['qemu_x86', 'frdm_k64f'] + path = os.path.join(TEST_DATA, 'tests', 'dummy') + args = ['-i', '--outdir', out_path, '-T', path, '--test', test, '-y'] + \ + [val for pair in zip( + ['-p'] * len(test_platforms), test_platforms + ) for val in pair] + + with mock.patch.object(sys, 'argv', [sys.argv[0]] + args), \ + pytest.raises(expected_exception) as exc: + self.loader.exec_module(self.twister_module) + + if expected_exception == SystemExit: + assert str(exc.value) == '0' + assert True diff --git a/scripts/tests/twister_blackbox/test_testplan.py b/scripts/tests/twister_blackbox/test_testplan.py new file mode 100644 index 00000000000..0444a564455 --- /dev/null +++ b/scripts/tests/twister_blackbox/test_testplan.py @@ -0,0 +1,186 @@ +#!/usr/bin/env python3 +# Copyright (c) 2024 Intel Corporation +# +# SPDX-License-Identifier: Apache-2.0 +""" +Blackbox tests for twister's command line functions - those requiring testplan.json +""" + +import importlib +import mock +import os +import pytest +import sys +import json + +from conftest import ZEPHYR_BASE, TEST_DATA, testsuite_filename_mock +from twisterlib.testplan import TestPlan +from twisterlib.error import TwisterRuntimeError + + +class TestTestPlan: + TESTDATA_1 = [ + ('smoke', 5), + ('acceptance', 6), + ] + TESTDATA_2 = [ + ('dummy.agnostic.group2.assert1', SystemExit, 3), + ( + os.path.join('scripts', 'tests', 'twister_blackbox', 'test_data', 'tests', + 'dummy', 'agnostic', 'group1', 'subgroup1', + 'dummy.agnostic.group2.assert1'), + TwisterRuntimeError, + None + ), + ] + TESTDATA_3 = [ + ('buildable', 6), + ('runnable', 5), + ] + TESTDATA_4 = [ + (True, 1), + (False, 6), + ] + + @classmethod + def setup_class(cls): + apath = os.path.join(ZEPHYR_BASE, 'scripts', 'twister') + cls.loader = importlib.machinery.SourceFileLoader('__main__', apath) + cls.spec = importlib.util.spec_from_loader(cls.loader.name, cls.loader) + cls.twister_module = importlib.util.module_from_spec(cls.spec) + + @classmethod + def teardown_class(cls): + pass + + @pytest.mark.usefixtures("clear_log") + @pytest.mark.parametrize( + 'level, expected_tests', + TESTDATA_1, + ids=['smoke', 'acceptance'] + ) + @mock.patch.object(TestPlan, 'TESTSUITE_FILENAME', testsuite_filename_mock) + def test_level(self, out_path, level, expected_tests): + test_platforms = ['qemu_x86', 'frdm_k64f'] + path = os.path.join(TEST_DATA, 'tests') + config_path = os.path.join(TEST_DATA, 'test_config.yaml') + args = ['-i','--outdir', out_path, '-T', path, '--level', level, '-y', + '--test-config', config_path] + \ + [val for pair in zip( + ['-p'] * len(test_platforms), test_platforms + ) for val in pair] + + with mock.patch.object(sys, 'argv', [sys.argv[0]] + args), \ + pytest.raises(SystemExit) as sys_exit: + self.loader.exec_module(self.twister_module) + + with open(os.path.join(out_path, 'testplan.json')) as f: + j = json.load(f) + filtered_j = [ + (ts['platform'], ts['name'], tc['identifier']) \ + for ts in j['testsuites'] \ + for tc in ts['testcases'] if 'reason' not in tc + ] + + assert str(sys_exit.value) == '0' + + assert expected_tests == len(filtered_j) + + @pytest.mark.usefixtures("clear_log") + @pytest.mark.parametrize( + 'test, expected_exception, expected_subtest_count', + TESTDATA_2, + ids=['valid', 'invalid'] + ) + @mock.patch.object(TestPlan, 'TESTSUITE_FILENAME', testsuite_filename_mock) + def test_subtest(self, out_path, test, expected_exception, expected_subtest_count): + test_platforms = ['qemu_x86', 'frdm_k64f'] + path = os.path.join(TEST_DATA, 'tests', 'dummy') + args = ['-i', '--outdir', out_path, '-T', path, '--sub-test', test, '-y'] + \ + [val for pair in zip( + ['-p'] * len(test_platforms), test_platforms + ) for val in pair] + + with mock.patch.object(sys, 'argv', [sys.argv[0]] + args), \ + pytest.raises(expected_exception) as exc: + self.loader.exec_module(self.twister_module) + + if expected_exception != SystemExit: + assert True + return + + with open(os.path.join(out_path, 'testplan.json')) as f: + j = json.load(f) + filtered_j = [ + (ts['platform'], ts['name'], tc['identifier']) \ + for ts in j['testsuites'] \ + for tc in ts['testcases'] if 'reason' not in tc + ] + + assert str(exc.value) == '0' + assert len(filtered_j) == expected_subtest_count + + + @pytest.mark.usefixtures("clear_log") + @pytest.mark.parametrize( + 'filter, expected_count', + TESTDATA_3, + ids=['buildable', 'runnable'] + ) + @mock.patch.object(TestPlan, 'TESTSUITE_FILENAME', testsuite_filename_mock) + def test_filter(self, out_path, filter, expected_count): + test_platforms = ['qemu_x86', 'frdm_k64f'] + path = os.path.join(TEST_DATA, 'tests', 'dummy') + args = ['-i', '--outdir', out_path, '-T', path, '--filter', filter, '-y'] + \ + [val for pair in zip( + ['-p'] * len(test_platforms), test_platforms + ) for val in pair] + + with mock.patch.object(sys, 'argv', [sys.argv[0]] + args), \ + pytest.raises(SystemExit) as exc: + self.loader.exec_module(self.twister_module) + + assert str(exc.value) == '0' + + with open(os.path.join(out_path, 'testplan.json')) as f: + j = json.load(f) + filtered_j = [ + (ts['platform'], ts['name'], tc['identifier']) \ + for ts in j['testsuites'] \ + for tc in ts['testcases'] if 'reason' not in tc + ] + + assert expected_count == len(filtered_j) + + @pytest.mark.usefixtures("clear_log") + @pytest.mark.parametrize( + 'integration, expected_count', + TESTDATA_4, + ids=['integration', 'no integration'] + ) + @mock.patch.object(TestPlan, 'TESTSUITE_FILENAME', testsuite_filename_mock) + @mock.patch.object(TestPlan, 'SAMPLE_FILENAME', '') + def test_integration(self, out_path, integration, expected_count): + test_platforms = ['qemu_x86', 'frdm_k64f'] + path = os.path.join(TEST_DATA, 'tests', 'dummy') + args = ['-i', '--outdir', out_path, '-T', path, '-y'] + \ + (['--integration'] if integration else []) + \ + [val for pair in zip( + ['-p'] * len(test_platforms), test_platforms + ) for val in pair] + + with mock.patch.object(sys, 'argv', [sys.argv[0]] + args), \ + pytest.raises(SystemExit) as exc: + self.loader.exec_module(self.twister_module) + + assert str(exc.value) == '0' + + with open(os.path.join(out_path, 'testplan.json')) as f: + j = json.load(f) + filtered_j = [ + (ts['platform'], ts['name'], tc['identifier']) \ + for ts in j['testsuites'] \ + for tc in ts['testcases'] if 'reason' not in tc + ] + + assert expected_count == len(filtered_j) From aac43a2748cf5cf66b289b48e04260e77437c668 Mon Sep 17 00:00:00 2001 From: Daniel DeGrasse Date: Fri, 8 Dec 2023 03:45:23 +0000 Subject: [PATCH 2526/3723] drivers: pwm: pwm_mcux_sctimer: support reconfiguring period Add support for reconfiguring the period of an active PWM channel with the SCTimer driver. Due to the design of the SCTimer IP, the period can only be reconfigured when one channel is in use. Otherwise, only the duty cycle of each channel can be updated. Signed-off-by: Daniel DeGrasse --- drivers/pwm/pwm_mcux_sctimer.c | 137 +++++++++++++++++++++++++-------- 1 file changed, 107 insertions(+), 30 deletions(-) diff --git a/drivers/pwm/pwm_mcux_sctimer.c b/drivers/pwm/pwm_mcux_sctimer.c index 91d16092e8f..fcd3272cfdc 100644 --- a/drivers/pwm/pwm_mcux_sctimer.c +++ b/drivers/pwm/pwm_mcux_sctimer.c @@ -20,6 +20,9 @@ LOG_MODULE_REGISTER(pwm_mcux_sctimer, CONFIG_PWM_LOG_LEVEL); #define CHANNEL_COUNT FSL_FEATURE_SCT_NUMBER_OF_OUTPUTS +/* Constant identifying that no event number has been set */ +#define EVENT_NOT_SET FSL_FEATURE_SCT_NUMBER_OF_EVENTS + struct pwm_mcux_sctimer_config { SCT_Type *base; uint32_t prescale; @@ -29,11 +32,52 @@ struct pwm_mcux_sctimer_config { }; struct pwm_mcux_sctimer_data { - uint32_t period_cycles[CHANNEL_COUNT]; uint32_t event_number[CHANNEL_COUNT]; sctimer_pwm_signal_param_t channel[CHANNEL_COUNT]; + uint32_t match_period; + uint32_t configured_chan; }; +/* Helper to setup channel that has not previously been configured for PWM */ +static int mcux_sctimer_new_channel(const struct device *dev, + uint32_t channel, uint32_t period_cycles, + uint32_t duty_cycle) +{ + const struct pwm_mcux_sctimer_config *config = dev->config; + struct pwm_mcux_sctimer_data *data = dev->data; + uint32_t clock_freq; + uint32_t pwm_freq; + + data->match_period = period_cycles; + + if (clock_control_get_rate(config->clock_dev, config->clock_subsys, + &clock_freq)) { + return -EINVAL; + } + + pwm_freq = (clock_freq / config->prescale) / period_cycles; + + if (pwm_freq == 0) { + LOG_ERR("Could not set up pwm_freq=%d", pwm_freq); + return -EINVAL; + } + + SCTIMER_StopTimer(config->base, kSCTIMER_Counter_U); + + LOG_DBG("SETUP dutycycle to %u\n", duty_cycle); + data->channel[channel].dutyCyclePercent = duty_cycle; + if (SCTIMER_SetupPwm(config->base, &data->channel[channel], + kSCTIMER_EdgeAlignedPwm, pwm_freq, + clock_freq, &data->event_number[channel]) == kStatus_Fail) { + LOG_ERR("Could not set up pwm"); + return -ENOTSUP; + } + + SCTIMER_StartTimer(config->base, kSCTIMER_Counter_U); + data->configured_chan++; + return 0; +} + static int mcux_sctimer_pwm_set_cycles(const struct device *dev, uint32_t channel, uint32_t period_cycles, uint32_t pulse_cycles, pwm_flags_t flags) @@ -41,6 +85,7 @@ static int mcux_sctimer_pwm_set_cycles(const struct device *dev, const struct pwm_mcux_sctimer_config *config = dev->config; struct pwm_mcux_sctimer_data *data = dev->data; uint8_t duty_cycle; + int ret; if (channel >= CHANNEL_COUNT) { LOG_ERR("Invalid channel"); @@ -60,10 +105,14 @@ static int mcux_sctimer_pwm_set_cycles(const struct device *dev, duty_cycle = 100 * pulse_cycles / period_cycles; - if (duty_cycle == 0) { + if (duty_cycle == 0 && data->configured_chan == 1) { + /* Only one channel is active. We can turn off the SCTimer + * global counter. + */ SCT_Type *base = config->base; - SCTIMER_StopTimer(config->base, kSCTIMER_Counter_U); + /* Stop timer so we can set output directly */ + SCTIMER_StopTimer(base, kSCTIMER_Counter_U); /* Set the output to inactive State */ if (data->channel[channel].level == kSCTIMER_HighTrue) { @@ -75,39 +124,65 @@ static int mcux_sctimer_pwm_set_cycles(const struct device *dev, return 0; } - if (period_cycles != data->period_cycles[channel] && - duty_cycle != data->channel[channel].dutyCyclePercent) { - uint32_t clock_freq; - uint32_t pwm_freq; - - data->period_cycles[channel] = period_cycles; - - if (clock_control_get_rate(config->clock_dev, config->clock_subsys, - &clock_freq)) { - return -EINVAL; + /* SCTimer has some unique restrictions when operation as a PWM output. + * The peripheral is based around a single counter, with a block of + * match registers that can trigger corresponding events. When used + * as a PWM peripheral, MCUX SDK sets up the SCTimer as follows: + * - one match register is used to set PWM output high, and reset + * SCtimer counter. This sets the PWM period + * - one match register is used to set PWM output low. This sets the + * pulse length + * + * This means that when configured, multiple channels must have the + * same PWM period, since they all share the same SCTimer counter. + */ + if (period_cycles != data->match_period && + data->event_number[channel] == EVENT_NOT_SET && + data->match_period == 0U) { + /* No PWM signals have been configured. We can set up the first + * PWM output using the MCUX SDK. + */ + ret = mcux_sctimer_new_channel(dev, channel, period_cycles, + duty_cycle); + if (ret < 0) { + return ret; } - - pwm_freq = (clock_freq / config->prescale) / period_cycles; - - if (pwm_freq == 0) { - LOG_ERR("Could not set up pwm_freq=%d", pwm_freq); - return -EINVAL; + } else if (data->event_number[channel] == EVENT_NOT_SET) { + /* We have already configured a PWM signal, but this channel + * has not been setup. We can only support this channel + * if the period matches that of other PWM signals. + */ + if (period_cycles != data->match_period) { + LOG_ERR("Only one PWM period is supported between " + "multiple channels"); + return -ENOTSUP; } - - SCTIMER_StopTimer(config->base, kSCTIMER_Counter_U); - - LOG_DBG("SETUP dutycycle to %u\n", duty_cycle); - data->channel[channel].dutyCyclePercent = duty_cycle; - if (SCTIMER_SetupPwm(config->base, &data->channel[channel], - kSCTIMER_EdgeAlignedPwm, pwm_freq, - clock_freq, &data->event_number[channel]) == kStatus_Fail) { - LOG_ERR("Could not set up pwm"); + /* Setup PWM output using MCUX SDK */ + ret = mcux_sctimer_new_channel(dev, channel, period_cycles, + duty_cycle); + } else if (period_cycles != data->match_period) { + uint32_t period_event = data->event_number[channel]; + /* We are reconfiguring the period of a configured channel + * MCUX SDK does not provide support for this feature, and + * we cannot do this safely if multiple channels are setup. + */ + if (data->configured_chan != 1) { + LOG_ERR("Cannot change PWM period when multiple " + "channels active"); return -ENOTSUP; } + /* To make this change, we can simply set the MATCHREL + * registers for the period match, and the next match + * (which the SDK will setup as the pulse match event) + */ + SCTIMER_StopTimer(config->base, kSCTIMER_Counter_U); + config->base->MATCHREL[period_event] = period_cycles - 1U; + config->base->MATCHREL[period_event + 1] = pulse_cycles - 1U; SCTIMER_StartTimer(config->base, kSCTIMER_Counter_U); + data->match_period = period_cycles; } else { - data->period_cycles[channel] = period_cycles; + /* Only duty cycle needs to be updated */ SCTIMER_UpdatePwmDutycycle(config->base, channel, duty_cycle, data->event_number[channel]); } @@ -160,8 +235,10 @@ static int mcux_sctimer_pwm_init(const struct device *dev) data->channel[i].output = i; data->channel[i].level = kSCTIMER_HighTrue; data->channel[i].dutyCyclePercent = 0; - data->period_cycles[i] = 0; + data->event_number[i] = EVENT_NOT_SET; } + data->match_period = 0; + data->configured_chan = 0; return 0; } From 75117a0debee7ad5a1b2082b3770b0e8649d40f6 Mon Sep 17 00:00:00 2001 From: Henrik Brix Andersen Date: Fri, 10 Nov 2023 14:17:56 +0100 Subject: [PATCH 2527/3723] drivers: can: remove CAN_FILTER_FDF flag Remove the CAN_FILTER_FDF flag for filtering on classic CAN/CAN FD frames as it is not supported natively by any known CAN controller. Applications can still filter on classic CAN/CAN FD frames in their receive callback functions as needed. Fixes: #64554 Signed-off-by: Henrik Brix Andersen --- drivers/can/can_loopback.c | 5 ----- drivers/can/can_mcan.c | 15 ------------- drivers/can/can_mcux_flexcan.c | 21 ++----------------- drivers/can/can_native_linux.c | 5 ----- drivers/can/can_nxp_s32_canxl.c | 7 +------ drivers/can/can_shell.c | 13 ++++-------- include/zephyr/drivers/can.h | 13 ------------ include/zephyr/net/socketcan_utils.h | 5 ----- subsys/canbus/isotp/isotp.c | 4 +--- tests/drivers/can/api/src/canfd.c | 10 ++++----- tests/drivers/can/api/src/common.c | 20 ------------------ tests/drivers/can/api/src/common.h | 16 ++------------ tests/drivers/can/api/src/utilities.c | 14 ++----------- .../canbus/isotp/conformance/src/main.c | 3 +-- 14 files changed, 18 insertions(+), 133 deletions(-) diff --git a/drivers/can/can_loopback.c b/drivers/can/can_loopback.c index 02f32b93c7a..5eb88b163ed 100644 --- a/drivers/can/can_loopback.c +++ b/drivers/can/can_loopback.c @@ -172,12 +172,7 @@ static int can_loopback_add_rx_filter(const struct device *dev, can_rx_callback_ LOG_DBG("Setting filter ID: 0x%x, mask: 0x%x", filter->id, filter->mask); -#ifdef CONFIG_CAN_FD_MODE - if ((filter->flags & ~(CAN_FILTER_IDE | CAN_FILTER_DATA | - CAN_FILTER_RTR | CAN_FILTER_FDF)) != 0) { -#else if ((filter->flags & ~(CAN_FILTER_IDE | CAN_FILTER_DATA | CAN_FILTER_RTR)) != 0) { -#endif LOG_ERR("unsupported CAN filter flags 0x%02x", filter->flags); return -ENOTSUP; } diff --git a/drivers/can/can_mcan.c b/drivers/can/can_mcan.c index d45eca62d47..dc54bc19670 100644 --- a/drivers/can/can_mcan.c +++ b/drivers/can/can_mcan.c @@ -682,16 +682,6 @@ static void can_mcan_get_message(const struct device *dev, uint16_t fifo_offset, goto ack; } - if (((frame.flags & CAN_FRAME_FDF) != 0U && (flags & CAN_FILTER_FDF) == 0U) || - ((frame.flags & CAN_FRAME_FDF) == 0U && (flags & CAN_FILTER_FDF) != 0U)) { - /* FDF bit does not match filter, drop frame */ - err = can_mcan_write_reg(dev, fifo_ack_reg, get_idx); - if (err != 0) { - return; - } - goto ack; - } - data_length = can_dlc_to_bytes(frame.dlc); if (data_length <= sizeof(frame.data)) { if ((frame.flags & CAN_FRAME_RTR) == 0U) { @@ -1121,12 +1111,7 @@ int can_mcan_add_rx_filter(const struct device *dev, can_rx_callback_t callback, return -EINVAL; } -#ifdef CONFIG_CAN_FD_MODE - if ((filter->flags & - ~(CAN_FILTER_IDE | CAN_FILTER_DATA | CAN_FILTER_RTR | CAN_FILTER_FDF)) != 0U) { -#else /* CONFIG_CAN_FD_MODE */ if ((filter->flags & ~(CAN_FILTER_IDE | CAN_FILTER_DATA | CAN_FILTER_RTR)) != 0U) { -#endif /* !CONFIG_CAN_FD_MODE */ LOG_ERR("unsupported CAN filter flags 0x%02x", filter->flags); return -ENOTSUP; } diff --git a/drivers/can/can_mcux_flexcan.c b/drivers/can/can_mcux_flexcan.c index 859d5deacbd..cb300bb7536 100644 --- a/drivers/can/can_mcux_flexcan.c +++ b/drivers/can/can_mcux_flexcan.c @@ -115,9 +115,6 @@ struct mcux_flexcan_rx_callback { flexcan_fd_frame_t fd; #endif /* CONFIG_CAN_MCUX_FLEXCAN_FD */ } frame; -#ifdef CONFIG_CAN_MCUX_FLEXCAN_FD - bool fdf; -#endif /* CONFIG_CAN_MCUX_FLEXCAN_FD */ can_rx_callback_t function; void *arg; }; @@ -789,7 +786,7 @@ static int mcux_flexcan_add_rx_filter(const struct device *dev, void *user_data, const struct can_filter *filter) { - uint8_t supported = CAN_FILTER_IDE | CAN_FILTER_DATA | CAN_FILTER_RTR; + const uint8_t supported = CAN_FILTER_IDE | CAN_FILTER_DATA | CAN_FILTER_RTR; const struct mcux_flexcan_config *config = dev->config; struct mcux_flexcan_data *data = dev->data; status_t status; @@ -799,10 +796,6 @@ static int mcux_flexcan_add_rx_filter(const struct device *dev, __ASSERT_NO_MSG(callback); - if (UTIL_AND(IS_ENABLED(CONFIG_CAN_MCUX_FLEXCAN_FD), config->flexcan_fd)) { - supported |= CAN_FILTER_FDF; - } - if ((filter->flags & ~(supported)) != 0) { LOG_ERR("unsupported CAN filter flags 0x%02x", filter->flags); return -ENOTSUP; @@ -828,11 +821,6 @@ static int mcux_flexcan_add_rx_filter(const struct device *dev, data->rx_cbs[alloc].arg = user_data; data->rx_cbs[alloc].function = callback; -#ifdef CONFIG_CAN_MCUX_FLEXCAN_FD - /* FDF filtering not supported in hardware, must be handled in driver */ - data->rx_cbs[alloc].fdf = (filter->flags & CAN_FILTER_FDF) != 0; -#endif /* CONFIG_CAN_MCUX_FLEXCAN_FD */ - /* The indidual RX mask registers can only be written in freeze mode */ FLEXCAN_EnterFreezeMode(config->base); config->base->RXIMR[ALLOC_IDX_TO_RXMB_IDX(alloc)] = mask; @@ -1059,15 +1047,10 @@ static inline void mcux_flexcan_transfer_rx_idle(const struct device *dev, } else { #endif /* CONFIG_CAN_MCUX_FLEXCAN_FD */ mcux_flexcan_to_can_frame(&data->rx_cbs[alloc].frame.classic, &frame); -#ifdef CONFIG_CAN_MCUX_FLEXCAN_FD - } - - if (!!(frame.flags & CAN_FRAME_FDF) == data->rx_cbs[alloc].fdf) { -#endif /* CONFIG_CAN_MCUX_FLEXCAN_FD */ - function(dev, &frame, arg); #ifdef CONFIG_CAN_MCUX_FLEXCAN_FD } #endif /* CONFIG_CAN_MCUX_FLEXCAN_FD */ + function(dev, &frame, arg); /* Setup RX message buffer to receive next message */ xfer.mbIdx = mb; diff --git a/drivers/can/can_native_linux.c b/drivers/can/can_native_linux.c index 01392c3ee2a..e5bd763f937 100644 --- a/drivers/can/can_native_linux.c +++ b/drivers/can/can_native_linux.c @@ -197,12 +197,7 @@ static int can_native_linux_add_rx_filter(const struct device *dev, can_rx_callb LOG_DBG("Setting filter ID: 0x%x, mask: 0x%x", filter->id, filter->mask); -#ifdef CONFIG_CAN_FD_MODE - if ((filter->flags & ~(CAN_FILTER_IDE | CAN_FILTER_DATA | - CAN_FILTER_RTR | CAN_FILTER_FDF)) != 0) { -#else if ((filter->flags & ~(CAN_FILTER_IDE | CAN_FILTER_DATA | CAN_FILTER_RTR)) != 0) { -#endif LOG_ERR("unsupported CAN filter flags 0x%02x", filter->flags); return -ENOTSUP; } diff --git a/drivers/can/can_nxp_s32_canxl.c b/drivers/can/can_nxp_s32_canxl.c index 3cc6a8d96b2..6a2180867f4 100644 --- a/drivers/can/can_nxp_s32_canxl.c +++ b/drivers/can/can_nxp_s32_canxl.c @@ -506,11 +506,7 @@ static int can_nxp_s32_add_rx_filter(const struct device *dev, uint32_t mask; __ASSERT_NO_MSG(callback != NULL); -#if defined(CONFIG_CAN_FD_MODE) - if ((filter->flags & ~(CAN_FILTER_IDE | CAN_FILTER_DATA | CAN_FILTER_FDF)) != 0) { -#else if ((filter->flags & ~(CAN_FILTER_IDE | CAN_FILTER_DATA)) != 0) { -#endif LOG_ERR("unsupported CAN filter flags 0x%02x", filter->flags); return -ENOTSUP; } @@ -560,8 +556,7 @@ static int can_nxp_s32_add_rx_filter(const struct device *dev, can_nxp_s32_config_rx_fifo_filter(dev, mb_indx); #else data->rx_cbs[alloc].rx_info = (Canexcel_Ip_DataInfoType) { - .frame = !!(filter->flags & CAN_FILTER_FDF) ? - CANEXCEL_FD_FRAME : CANEXCEL_CLASIC_FRAME, + .frame = CANEXCEL_CLASIC_FRAME, .idType = !!(filter->flags & CAN_FILTER_IDE) ? CANEXCEL_MSG_ID_EXT : CANEXCEL_MSG_ID_STD, .dataLength = CAN_NXP_S32_DATA_LENGTH, diff --git a/drivers/can/can_shell.c b/drivers/can/can_shell.c index 46dac3fb06a..3780e20e8d0 100644 --- a/drivers/can/can_shell.c +++ b/drivers/can/can_shell.c @@ -812,9 +812,6 @@ static int cmd_can_filter_add(const struct shell *sh, size_t argc, char **argv) filter.flags |= CAN_FILTER_IDE; max_id = CAN_MAX_EXT_ID; argidx++; - } else if (strcmp(argv[argidx], "-f") == 0) { - filter.flags |= CAN_FILTER_FDF; - argidx++; } else if (strcmp(argv[argidx], "-r") == 0) { filter.flags |= CAN_FILTER_RTR; argidx++; @@ -878,14 +875,13 @@ static int cmd_can_filter_add(const struct shell *sh, size_t argc, char **argv) } shell_print(sh, "adding filter with %s (%d-bit) CAN ID 0x%0*x, " - "CAN ID mask 0x%0*x, data frames %d, RTR frames %d, CAN FD frames %d", + "CAN ID mask 0x%0*x, data frames %d, RTR frames %d", (filter.flags & CAN_FILTER_IDE) != 0 ? "extended" : "standard", (filter.flags & CAN_FILTER_IDE) != 0 ? 29 : 11, (filter.flags & CAN_FILTER_IDE) != 0 ? 8 : 3, filter.id, (filter.flags & CAN_FILTER_IDE) != 0 ? 8 : 3, filter.mask, (filter.flags & CAN_FILTER_DATA) != 0 ? 1 : 0, - (filter.flags & CAN_FILTER_RTR) != 0 ? 1 : 0, - (filter.flags & CAN_FILTER_FDF) != 0 ? 1 : 0); + (filter.flags & CAN_FILTER_RTR) != 0 ? 1 : 0); err = can_add_rx_filter_msgq(dev, &can_shell_rx_msgq, &filter); if (err < 0) { @@ -1003,12 +999,11 @@ SHELL_DYNAMIC_CMD_CREATE(dsub_can_device_name_mode, cmd_can_device_name_mode); SHELL_STATIC_SUBCMD_SET_CREATE(sub_can_filter_cmds, SHELL_CMD_ARG(add, &dsub_can_device_name, "Add rx filter\n" - "Usage: can filter add [-e] [-f] [-r] [-R] [CAN ID mask]\n" + "Usage: can filter add [-e] [-r] [-R] [CAN ID mask]\n" "-e use extended (29-bit) CAN ID/CAN ID mask\n" - "-f match CAN FD format frames\n" "-r also match Remote Transmission Request (RTR) frames\n" "-R only match Remote Transmission Request (RTR) frames", - cmd_can_filter_add, 3, 5), + cmd_can_filter_add, 3, 4), SHELL_CMD_ARG(remove, &dsub_can_device_name, "Remove rx filter\n" "Usage: can filter remove ", diff --git a/include/zephyr/drivers/can.h b/include/zephyr/drivers/can.h index c40df027d61..7221df1ea51 100644 --- a/include/zephyr/drivers/can.h +++ b/include/zephyr/drivers/can.h @@ -209,9 +209,6 @@ struct can_frame { /** Filter matches data frames */ #define CAN_FILTER_DATA BIT(2) -/** Filter matches CAN FD frames (FDF) */ -#define CAN_FILTER_FDF BIT(3) - /** @} */ /** @@ -1696,16 +1693,6 @@ static inline bool can_frame_matches_filter(const struct can_frame *frame, return false; } - if ((frame->flags & CAN_FRAME_FDF) != 0 && (filter->flags & CAN_FILTER_FDF) == 0) { - /* CAN FD format frame, classic format filter */ - return false; - } - - if ((frame->flags & CAN_FRAME_FDF) == 0 && (filter->flags & CAN_FILTER_FDF) != 0) { - /* Classic frame, CAN FD format filter */ - return false; - } - if ((frame->id ^ filter->id) & filter->mask) { /* Masked ID mismatch */ return false; diff --git a/include/zephyr/net/socketcan_utils.h b/include/zephyr/net/socketcan_utils.h index 22364cd328b..9b00d6dadc7 100644 --- a/include/zephyr/net/socketcan_utils.h +++ b/include/zephyr/net/socketcan_utils.h @@ -95,7 +95,6 @@ static inline void socketcan_to_can_filter(const struct socketcan_filter *sfilte zfilter->flags |= (sfilter->can_id & BIT(31)) != 0 ? CAN_FILTER_IDE : 0; zfilter->id = sfilter->can_id & BIT_MASK(29); zfilter->mask = sfilter->can_mask & BIT_MASK(29); - zfilter->flags |= (sfilter->flags & CANFD_FDF) != 0 ? CAN_FILTER_FDF : 0; if ((sfilter->can_mask & BIT(30)) == 0) { zfilter->flags |= CAN_FILTER_DATA | CAN_FILTER_RTR; @@ -128,10 +127,6 @@ static inline void socketcan_from_can_filter(const struct can_filter *zfilter, (CAN_FILTER_DATA | CAN_FILTER_RTR)) { sfilter->can_mask |= BIT(30); } - - if ((zfilter->flags & CAN_FILTER_FDF) != 0) { - sfilter->flags |= CANFD_FDF; - } } /** diff --git a/subsys/canbus/isotp/isotp.c b/subsys/canbus/isotp/isotp.c index 776cdd312a4..233cc0b2ee2 100644 --- a/subsys/canbus/isotp/isotp.c +++ b/subsys/canbus/isotp/isotp.c @@ -54,9 +54,7 @@ static inline void prepare_filter(struct can_filter *filter, struct isotp_msg_id { filter->id = addr->ext_id; filter->mask = mask; - filter->flags = CAN_FILTER_DATA | - ((addr->flags & ISOTP_MSG_IDE) != 0 ? CAN_FILTER_IDE : 0) | - ((addr->flags & ISOTP_MSG_FDF) != 0 ? CAN_FILTER_FDF : 0); + filter->flags = CAN_FILTER_DATA | ((addr->flags & ISOTP_MSG_IDE) != 0 ? CAN_FILTER_IDE : 0); } /* diff --git a/tests/drivers/can/api/src/canfd.c b/tests/drivers/can/api/src/canfd.c index d8dfb8b3c31..b0f6cb8a2d1 100644 --- a/tests/drivers/can/api/src/canfd.c +++ b/tests/drivers/can/api/src/canfd.c @@ -66,7 +66,7 @@ static void rx_std_callback_fd_1(const struct device *dev, struct can_frame *fra assert_frame_equal(frame, &test_std_fdf_frame_1, 0); zassert_equal(dev, can_dev, "CAN device does not match"); - zassert_equal_ptr(filter, &test_std_fdf_filter_1, "filter does not match"); + zassert_equal_ptr(filter, &test_std_filter_1, "filter does not match"); k_sem_give(&rx_callback_sem); } @@ -78,7 +78,7 @@ static void rx_std_callback_fd_2(const struct device *dev, struct can_frame *fra assert_frame_equal(frame, &test_std_fdf_frame_2, 0); zassert_equal(dev, can_dev, "CAN device does not match"); - zassert_equal_ptr(filter, &test_std_fdf_filter_2, "filter does not match"); + zassert_equal_ptr(filter, &test_std_filter_2, "filter does not match"); k_sem_give(&rx_callback_sem); } @@ -252,7 +252,7 @@ ZTEST(canfd, test_send_receive_classic) */ ZTEST(canfd, test_send_receive_fd) { - send_receive(&test_std_fdf_filter_1, &test_std_fdf_filter_2, + send_receive(&test_std_filter_1, &test_std_filter_2, &test_std_fdf_frame_1, &test_std_fdf_frame_2); } @@ -261,7 +261,7 @@ ZTEST(canfd, test_send_receive_fd) */ ZTEST(canfd, test_send_receive_mixed) { - send_receive(&test_std_fdf_filter_1, &test_std_filter_2, + send_receive(&test_std_filter_1, &test_std_filter_2, &test_std_fdf_frame_1, &test_std_frame_2); } @@ -292,7 +292,7 @@ static void check_filters_preserved_between_modes(can_mode_t first, can_mode_t s /* Add classic CAN and CAN FD filter */ filter_id_1 = add_rx_msgq(can_dev, &test_std_filter_1); - filter_id_2 = add_rx_msgq(can_dev, &test_std_fdf_filter_2); + filter_id_2 = add_rx_msgq(can_dev, &test_std_filter_2); /* Verify classic filter in first mode */ send_test_frame(can_dev, &test_std_frame_1); diff --git a/tests/drivers/can/api/src/common.c b/tests/drivers/can/api/src/common.c index 234bf1eb761..759733d3e8d 100644 --- a/tests/drivers/can/api/src/common.c +++ b/tests/drivers/can/api/src/common.c @@ -218,26 +218,6 @@ const struct can_filter test_std_some_filter = { .mask = CAN_STD_ID_MASK }; -/** - * @brief Standard (11-bit) CAN FD ID filter 1. This filter matches - * ``test_std_fdf_frame_1``. - */ -const struct can_filter test_std_fdf_filter_1 = { - .flags = CAN_FILTER_DATA | CAN_FILTER_FDF, - .id = TEST_CAN_STD_ID_1, - .mask = CAN_STD_ID_MASK -}; - -/** - * @brief Standard (11-bit) CAN FD ID filter 2. This filter matches - * ``test_std_fdf_frame_2``. - */ -const struct can_filter test_std_fdf_filter_2 = { - .flags = CAN_FILTER_DATA | CAN_FILTER_FDF, - .id = TEST_CAN_STD_ID_2, - .mask = CAN_STD_ID_MASK -}; - /** * @brief Assert that two CAN frames are equal given a CAN ID mask. * diff --git a/tests/drivers/can/api/src/common.h b/tests/drivers/can/api/src/common.h index 65475add23f..374141a71fb 100644 --- a/tests/drivers/can/api/src/common.h +++ b/tests/drivers/can/api/src/common.h @@ -98,13 +98,13 @@ extern const struct can_frame test_std_fdf_frame_2; /** * @brief Standard (11-bit) CAN ID filter 1. This filter matches - * ``test_std_frame_1``. + * ``test_std_frame_1`` and ``test_std_fdf_frame_1``. */ extern const struct can_filter test_std_filter_1; /** * @brief Standard (11-bit) CAN ID filter 2. This filter matches - * ``test_std_frame_2``. + * ``test_std_frame_2`` and ``test_std_fdf_frame_2``. */ extern const struct can_filter test_std_filter_2; @@ -162,18 +162,6 @@ extern const struct can_filter test_ext_rtr_filter_1; */ extern const struct can_filter test_std_some_filter; -/** - * @brief Standard (11-bit) CAN FD ID filter 1. This filter matches - * ``test_std_fdf_frame_1``. - */ -extern const struct can_filter test_std_fdf_filter_1; - -/** - * @brief Standard (11-bit) CAN FD ID filter 2. This filter matches - * ``test_std_fdf_frame_2``. - */ -extern const struct can_filter test_std_fdf_filter_2; - /** * @brief Assert that two CAN frames are equal given a CAN ID mask. * diff --git a/tests/drivers/can/api/src/utilities.c b/tests/drivers/can/api/src/utilities.c index 90f5cbd2cf5..c2e037bcbc9 100644 --- a/tests/drivers/can/api/src/utilities.c +++ b/tests/drivers/can/api/src/utilities.c @@ -120,18 +120,8 @@ ZTEST(can_utilities, test_can_frame_matches_filter) zassert_false(can_frame_matches_filter(&test_ext_frame_1, &test_ext_rtr_filter_1)); /* CAN FD format frames and filters */ - zassert_true(can_frame_matches_filter(&test_std_fdf_frame_1, &test_std_fdf_filter_1)); - zassert_true(can_frame_matches_filter(&test_std_fdf_frame_2, &test_std_fdf_filter_2)); - zassert_false(can_frame_matches_filter(&test_std_fdf_frame_1, &test_std_fdf_filter_2)); - zassert_false(can_frame_matches_filter(&test_std_fdf_frame_2, &test_std_fdf_filter_1)); - - /* CAN FD format frames and classic filters */ - zassert_false(can_frame_matches_filter(&test_std_fdf_frame_1, &test_std_filter_1)); - zassert_false(can_frame_matches_filter(&test_std_fdf_frame_2, &test_std_filter_2)); - - /* Classic format frames and CAN FD format filters */ - zassert_false(can_frame_matches_filter(&test_std_frame_1, &test_std_fdf_filter_1)); - zassert_false(can_frame_matches_filter(&test_std_frame_2, &test_std_fdf_filter_2)); + zassert_true(can_frame_matches_filter(&test_std_fdf_frame_1, &test_std_filter_1)); + zassert_true(can_frame_matches_filter(&test_std_fdf_frame_2, &test_std_filter_2)); } ZTEST_SUITE(can_utilities, NULL, NULL, NULL, NULL, NULL); diff --git a/tests/subsys/canbus/isotp/conformance/src/main.c b/tests/subsys/canbus/isotp/conformance/src/main.c index ba3e0890c7b..926742da5dd 100644 --- a/tests/subsys/canbus/isotp/conformance/src/main.c +++ b/tests/subsys/canbus/isotp/conformance/src/main.c @@ -306,8 +306,7 @@ static int add_rx_msgq(uint32_t id, uint32_t mask) { int filter_id; struct can_filter filter = { - .flags = CAN_FILTER_DATA | ((id > 0x7FF) ? CAN_FILTER_IDE : 0) | - (IS_ENABLED(CONFIG_TEST_USE_CAN_FD_MODE) ? CAN_FILTER_FDF : 0), + .flags = CAN_FILTER_DATA | ((id > 0x7FF) ? CAN_FILTER_IDE : 0), .id = id, .mask = mask }; From 93551a4a955d3d48972f483cf21e3860c4826479 Mon Sep 17 00:00:00 2001 From: Henrik Brix Andersen Date: Mon, 13 Nov 2023 09:03:59 +0100 Subject: [PATCH 2528/3723] doc: releases: migration-guide: 3.6: note on removal of CAN_FILTER_FDF Add a note about the removal of the CAN_FILTER_FDF flag from the CAN controller driver API. Signed-off-by: Henrik Brix Andersen --- doc/releases/migration-guide-3.6.rst | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/doc/releases/migration-guide-3.6.rst b/doc/releases/migration-guide-3.6.rst index ab621d2676e..e5acef50825 100644 --- a/doc/releases/migration-guide-3.6.rst +++ b/doc/releases/migration-guide-3.6.rst @@ -175,6 +175,10 @@ Device Drivers and Device Tree * The main Kconfig option was renamed from ``CONFIG_CAN_NATIVE_POSIX_LINUX`` to :kconfig:option:`CONFIG_CAN_NATIVE_LINUX`. +* The ``CAN_FILTER_FDF`` flag for filtering classic CAN/CAN FD frames was removed since no known CAN + controllers implement support for this. Applications can still filter on classic CAN/CAN FD frames + in their receive callback functions as needed. + * The io-channel cells of the following devicetree bindings were reduced from 2 (``positive`` and ``negative``) to the common ``input``, making it possible to use the various ADC DT macros with TI LMP90xxx ADC devices: From a691280b1270b7a6070c14e5106d896af0efed2a Mon Sep 17 00:00:00 2001 From: Andrej Butok Date: Mon, 11 Dec 2023 13:15:49 +0100 Subject: [PATCH 2529/3723] boards: nxp: Switch MCUBoot FW Update mode to Swap & Move Switch the default MCUBoot FW Update mode from Swap & Scratch to more preferable Swap & Move for the rest of NXP MCUs. Other NXP MCU platforms have been already switched. Delete the scratch partition. Save RAM & ROM. Slot 0 has one additional sector, for use with the swap move algorithm. Signed-off-by: Andrej Butok --- boards/arm/frdm_k22f/frdm_k22f.dts | 23 ++++++---------- boards/arm/frdm_k64f/frdm_k64f.dts | 26 +++++++------------ boards/arm/frdm_k82f/frdm_k82f.dts | 21 +++++++-------- boards/arm/mimxrt1020_evk/mimxrt1020_evk.dts | 17 ++++++------ boards/arm/mimxrt1024_evk/mimxrt1024_evk.dts | 21 ++++++--------- boards/arm/mimxrt1050_evk/mimxrt1050_evk.dts | 17 ++++++------ .../mimxrt1050_evk/mimxrt1050_evk_qspi.dts | 17 ++++++------ boards/arm/mimxrt1060_evk/mimxrt1060_evk.dts | 17 ++++++------ .../mimxrt1060_evk_hyperflash.dts | 17 ++++++------ .../mimxrt1062_fmurt6/mimxrt1062_fmurt6.dts | 8 ++---- boards/arm/mimxrt1064_evk/mimxrt1064_evk.dts | 13 +++++----- boards/arm/mimxrt1160_evk/mimxrt1160_evk.dtsi | 8 ++---- boards/arm/mimxrt1170_evk/mimxrt1170_evk.dtsi | 8 ++---- .../mimxrt1170_evk/mimxrt1170_evkb_cm4.dts | 8 ++---- .../mimxrt1170_evk/mimxrt1170_evkb_cm7.dts | 8 ++---- 15 files changed, 91 insertions(+), 138 deletions(-) diff --git a/boards/arm/frdm_k22f/frdm_k22f.dts b/boards/arm/frdm_k22f/frdm_k22f.dts index 7804af1056d..e11db24edfc 100644 --- a/boards/arm/frdm_k22f/frdm_k22f.dts +++ b/boards/arm/frdm_k22f/frdm_k22f.dts @@ -205,27 +205,20 @@ zephyr_udc0: &usbotg { reg = <0x00000000 0x00010000>; read-only; }; + /* Note slot 0 has one additional sector, + * this is intended for use with the swap move algorithm + */ slot0_partition: partition@10000 { label = "image-0"; - reg = <0x00010000 0x00020000>; + reg = <0x00010000 0x00028800>; }; - slot1_partition: partition@30000 { + slot1_partition: partition@38800 { label = "image-1"; - reg = <0x00030000 0x00020000>; - }; - scratch_partition: partition@50000 { - label = "image-scratch"; - reg = <0x00050000 0x00010000>; + reg = <0x00038800 0x00028000>; }; - - /* - * The flash starting at 0x00060000 and ending at - * 0x0007ffff (sectors 16-31) is reserved for use - * by the application. - */ - storage_partition: partition@60000 { + storage_partition: partition@60800 { label = "storage"; - reg = <0x00060000 0x00020000>; + reg = <0x00060800 0x0001f800>; }; }; diff --git a/boards/arm/frdm_k64f/frdm_k64f.dts b/boards/arm/frdm_k64f/frdm_k64f.dts index 5b0e26fb039..a5affc02797 100644 --- a/boards/arm/frdm_k64f/frdm_k64f.dts +++ b/boards/arm/frdm_k64f/frdm_k64f.dts @@ -234,28 +234,20 @@ zephyr_udc0: &usbotg { reg = <0x00000000 0x00010000>; read-only; }; - - /* - * The flash starting at 0x00010000 and ending at - * 0x0001ffff (sectors 16-31) is reserved for use - * by the application. + /* Note slot 0 has one additional sector, + * this is intended for use with the swap move algorithm */ - storage_partition: partition@1e000 { - label = "storage"; - reg = <0x0001e000 0x00002000>; - }; - - slot0_partition: partition@20000 { + slot0_partition: partition@10000 { label = "image-0"; - reg = <0x00020000 0x00060000>; + reg = <0x00010000 0x00069000>; }; - slot1_partition: partition@80000 { + slot1_partition: partition@79000 { label = "image-1"; - reg = <0x00080000 0x00060000>; + reg = <0x00079000 0x00068000>; }; - scratch_partition: partition@e0000 { - label = "image-scratch"; - reg = <0x000e0000 0x00020000>; + storage_partition: partition@e1000 { + label = "storage"; + reg = <0x000e1000 0x0001f000>; }; }; }; diff --git a/boards/arm/frdm_k82f/frdm_k82f.dts b/boards/arm/frdm_k82f/frdm_k82f.dts index a60a32d01d8..53eed0cd28b 100644 --- a/boards/arm/frdm_k82f/frdm_k82f.dts +++ b/boards/arm/frdm_k82f/frdm_k82f.dts @@ -161,21 +161,20 @@ label = "mcuboot"; reg = <0x0 DT_SIZE_K(48)>; }; - storage_partition: partition@c000 { - label = "storage"; - reg = <0xc000 DT_SIZE_K(32)>; - }; - slot0_partition: partition@14000 { + /* Note slot 0 has one additional sector, + * this is intended for use with the swap move algorithm + */ + slot0_partition: partition@c000 { label = "image-0"; - reg = <0x14000 DT_SIZE_K(80)>; + reg = <0xc000 DT_SIZE_K(100)>; }; - slot1_partition: partition@28000 { + slot1_partition: partition@25000 { label = "image-1"; - reg = <0x28000 DT_SIZE_K(80)>; + reg = <0x25000 DT_SIZE_K(96)>; }; - scratch_partition: partition@3c000 { - label = "image-scratch"; - reg = <0x3c000 DT_SIZE_K(16)>; + storage_partition: partition@3d000 { + label = "storage"; + reg = <0x3d000 DT_SIZE_K(12)>; }; }; }; diff --git a/boards/arm/mimxrt1020_evk/mimxrt1020_evk.dts b/boards/arm/mimxrt1020_evk/mimxrt1020_evk.dts index 4f8d3b803c6..e873a0f2167 100644 --- a/boards/arm/mimxrt1020_evk/mimxrt1020_evk.dts +++ b/boards/arm/mimxrt1020_evk/mimxrt1020_evk.dts @@ -112,21 +112,20 @@ arduino_serial: &lpuart2 { label = "mcuboot"; reg = <0x00000000 DT_SIZE_K(64)>; }; + /* Note slot 0 has one additional sector, + * this is intended for use with the swap move algorithm + */ slot0_partition: partition@10000 { label = "image-0"; - reg = <0x00010000 DT_SIZE_M(3)>; + reg = <0x00010000 (DT_SIZE_M(3) + DT_SIZE_K(4))>; }; - slot1_partition: partition@310000 { + slot1_partition: partition@311000 { label = "image-1"; - reg = <0x00310000 DT_SIZE_M(3)>; + reg = <0x00311000 DT_SIZE_M(3)>; }; - scratch_partition: partition@610000 { - label = "image-scratch"; - reg = <0x00610000 DT_SIZE_K(128)>; - }; - storage_partition: partition@630000 { + storage_partition: partition@611000 { label = "storage"; - reg = <0x00630000 DT_SIZE_K(1856)>; + reg = <0x00611000 DT_SIZE_K(1980)>; }; }; }; diff --git a/boards/arm/mimxrt1024_evk/mimxrt1024_evk.dts b/boards/arm/mimxrt1024_evk/mimxrt1024_evk.dts index 164e7cdb654..7377cd0f1d8 100644 --- a/boards/arm/mimxrt1024_evk/mimxrt1024_evk.dts +++ b/boards/arm/mimxrt1024_evk/mimxrt1024_evk.dts @@ -70,25 +70,20 @@ label = "mcuboot"; reg = <0x00000000 DT_SIZE_K(64)>; }; - + /* Note slot 0 has one additional sector, + * this is intended for use with the swap move algorithm + */ slot0_partition: partition@10000 { label = "image-0"; - reg = <0x00010000 DT_SIZE_K(1920)>; + reg = <0x00010000 DT_SIZE_K(1924)>; }; - - slot1_partition: partition@1f0000 { + slot1_partition: partition@1f1000 { label = "image-1"; - reg = <0x001F0000 DT_SIZE_K(1920)>; + reg = <0x001F1000 DT_SIZE_K(1920)>; }; - - storage_partition: partition@3d0000 { + storage_partition: partition@3d1000 { label = "storage"; - reg = <0x003D0000 DT_SIZE_K(128)>; - }; - - scratch_partition: partition@3f0000 { - label = "image-scratch"; - reg = <0x003f0000 DT_SIZE_K(64)>; + reg = <0x003D1000 DT_SIZE_K(188)>; }; }; }; diff --git a/boards/arm/mimxrt1050_evk/mimxrt1050_evk.dts b/boards/arm/mimxrt1050_evk/mimxrt1050_evk.dts index 5068bc674e4..d1e8da5834b 100644 --- a/boards/arm/mimxrt1050_evk/mimxrt1050_evk.dts +++ b/boards/arm/mimxrt1050_evk/mimxrt1050_evk.dts @@ -154,21 +154,20 @@ arduino_serial: &lpuart3 { label = "mcuboot"; reg = <0x00000000 DT_SIZE_K(256)>; }; + /* Note slot 0 has one additional sector, + * this is intended for use with the swap move algorithm + */ slot0_partition: partition@40000 { label = "image-0"; - reg = <0x00040000 DT_SIZE_M(3)>; + reg = <0x00040000 (DT_SIZE_M(3) + DT_SIZE_K(4))>; }; - slot1_partition: partition@340000 { + slot1_partition: partition@341000 { label = "image-1"; - reg = <0x00340000 DT_SIZE_M(3)>; + reg = <0x00341000 DT_SIZE_M(3)>; }; - scratch_partition: partition@640000 { - label = "image-scratch"; - reg = <0x00640000 DT_SIZE_K(768)>; - }; - storage_partition: partition@700000 { + storage_partition: partition@641000 { label = "storage"; - reg = <0x00700000 DT_SIZE_M(57)>; + reg = <0x00641000 (DT_SIZE_M(57) + DT_SIZE_K(764))>; }; }; }; diff --git a/boards/arm/mimxrt1050_evk/mimxrt1050_evk_qspi.dts b/boards/arm/mimxrt1050_evk/mimxrt1050_evk_qspi.dts index 46f78275a0c..27542b88bfd 100644 --- a/boards/arm/mimxrt1050_evk/mimxrt1050_evk_qspi.dts +++ b/boards/arm/mimxrt1050_evk/mimxrt1050_evk_qspi.dts @@ -41,21 +41,20 @@ label = "mcuboot"; reg = <0x00000000 DT_SIZE_K(64)>; }; + /* Note slot 0 has one additional sector, + * this is intended for use with the swap move algorithm + */ slot0_partition: partition@10000 { label = "image-0"; - reg = <0x00010000 DT_SIZE_M(3)>; + reg = <0x00010000 (DT_SIZE_M(3) + DT_SIZE_K(4))>; }; - slot1_partition: partition@310000 { + slot1_partition: partition@311000 { label = "image-1"; - reg = <0x00310000 DT_SIZE_M(3)>; + reg = <0x00311000 DT_SIZE_M(3)>; }; - scratch_partition: partition@610000 { - label = "image-scratch"; - reg = <0x00610000 DT_SIZE_K(128)>; - }; - storage_partition: partition@630000 { + storage_partition: partition@611000 { label = "storage"; - reg = <0x00630000 DT_SIZE_K(1856)>; + reg = <0x00611000 DT_SIZE_K(1980)>; }; }; }; diff --git a/boards/arm/mimxrt1060_evk/mimxrt1060_evk.dts b/boards/arm/mimxrt1060_evk/mimxrt1060_evk.dts index 998e942e5a2..42782b40454 100644 --- a/boards/arm/mimxrt1060_evk/mimxrt1060_evk.dts +++ b/boards/arm/mimxrt1060_evk/mimxrt1060_evk.dts @@ -143,21 +143,20 @@ arduino_serial: &lpuart3 { label = "mcuboot"; reg = <0x00000000 DT_SIZE_K(64)>; }; + /* Note slot 0 has one additional sector, + * this is intended for use with the swap move algorithm + */ slot0_partition: partition@10000 { label = "image-0"; - reg = <0x00010000 DT_SIZE_M(3)>; + reg = <0x00010000 (DT_SIZE_M(3) + DT_SIZE_K(4))>; }; - slot1_partition: partition@310000 { + slot1_partition: partition@311000 { label = "image-1"; - reg = <0x00310000 DT_SIZE_M(3)>; + reg = <0x00311000 DT_SIZE_M(3)>; }; - scratch_partition: partition@610000 { - label = "image-scratch"; - reg = <0x00610000 DT_SIZE_K(128)>; - }; - storage_partition: partition@630000 { + storage_partition: partition@611000 { label = "storage"; - reg = <0x00630000 DT_SIZE_K(1856)>; + reg = <0x00611000 DT_SIZE_K(1980)>; }; }; }; diff --git a/boards/arm/mimxrt1060_evk/mimxrt1060_evk_hyperflash.dts b/boards/arm/mimxrt1060_evk/mimxrt1060_evk_hyperflash.dts index a920010688b..efdf5e2ff22 100644 --- a/boards/arm/mimxrt1060_evk/mimxrt1060_evk_hyperflash.dts +++ b/boards/arm/mimxrt1060_evk/mimxrt1060_evk_hyperflash.dts @@ -53,21 +53,20 @@ label = "mcuboot"; reg = <0x00000000 DT_SIZE_K(256)>; }; + /* Note slot 0 has one additional sector, + * this is intended for use with the swap move algorithm + */ slot0_partition: partition@40000 { label = "image-0"; - reg = <0x00040000 DT_SIZE_M(3)>; + reg = <0x00040000 (DT_SIZE_M(3) + DT_SIZE_K(4))>; }; - slot1_partition: partition@340000 { + slot1_partition: partition@341000 { label = "image-1"; - reg = <0x00340000 DT_SIZE_M(3)>; + reg = <0x00341000 DT_SIZE_M(3)>; }; - scratch_partition: partition@640000 { - label = "image-scratch"; - reg = <0x00640000 DT_SIZE_K(768)>; - }; - storage_partition: partition@700000 { + storage_partition: partition@641000 { label = "storage"; - reg = <0x00700000 DT_SIZE_M(57)>; + reg = <0x00641000 (DT_SIZE_M(57) + DT_SIZE_K(764))>; }; }; }; diff --git a/boards/arm/mimxrt1062_fmurt6/mimxrt1062_fmurt6.dts b/boards/arm/mimxrt1062_fmurt6/mimxrt1062_fmurt6.dts index c3af13f1f0d..ff6f1bf6827 100644 --- a/boards/arm/mimxrt1062_fmurt6/mimxrt1062_fmurt6.dts +++ b/boards/arm/mimxrt1062_fmurt6/mimxrt1062_fmurt6.dts @@ -223,13 +223,9 @@ label = "image-1"; reg = <0x00340000 DT_SIZE_M(3)>; }; - scratch_partition: partition@640000 { - label = "image-scratch"; - reg = <0x00640000 DT_SIZE_K(768)>; - }; - storage_partition: partition@700000 { + storage_partition: partition@640000 { label = "storage"; - reg = <0x00700000 DT_SIZE_M(557)>; + reg = <0x00640000 (DT_SIZE_M(557) + DT_SIZE_K(768))>; }; }; }; diff --git a/boards/arm/mimxrt1064_evk/mimxrt1064_evk.dts b/boards/arm/mimxrt1064_evk/mimxrt1064_evk.dts index ebd88badcb6..f6b6d5c74b2 100644 --- a/boards/arm/mimxrt1064_evk/mimxrt1064_evk.dts +++ b/boards/arm/mimxrt1064_evk/mimxrt1064_evk.dts @@ -207,17 +207,16 @@ arduino_i2c: &lpi2c1 {}; label = "mcuboot"; reg = <0x00000000 DT_SIZE_K(64)>; }; + /* Note slot 0 has one additional sector, + * this is intended for use with the swap move algorithm + */ slot0_partition: partition@10000 { label = "image-0"; - reg = <0x00010000 DT_SIZE_K(1984)>; + reg = <0x00010000 DT_SIZE_K(2016)>; }; - slot1_partition: partition@200000 { + slot1_partition: partition@208000 { label = "image-1"; - reg = <0x00200000 DT_SIZE_K(1984)>; - }; - scratch_partition: partition@3f0000 { - label = "image-scratch"; - reg = <0x003f0000 DT_SIZE_K(64)>; + reg = <0x00208000 DT_SIZE_K(2012)>; }; }; }; diff --git a/boards/arm/mimxrt1160_evk/mimxrt1160_evk.dtsi b/boards/arm/mimxrt1160_evk/mimxrt1160_evk.dtsi index 02d09138e75..93e1c3452fa 100644 --- a/boards/arm/mimxrt1160_evk/mimxrt1160_evk.dtsi +++ b/boards/arm/mimxrt1160_evk/mimxrt1160_evk.dtsi @@ -119,13 +119,9 @@ label = "image-1"; reg = <0x00321000 0x300000>; }; - scratch_partition: partition@621000 { - label = "image-scratch"; - reg = <0x00621000 DT_SIZE_K(128)>; - }; - storage_partition: partition@641000 { + storage_partition: partition@621000 { label = "storage"; - reg = <0x00641000 DT_SIZE_K(1856)>; + reg = <0x00621000 DT_SIZE_K(1984)>; }; }; }; diff --git a/boards/arm/mimxrt1170_evk/mimxrt1170_evk.dtsi b/boards/arm/mimxrt1170_evk/mimxrt1170_evk.dtsi index 4d3b193e5dc..9e59e733ebc 100644 --- a/boards/arm/mimxrt1170_evk/mimxrt1170_evk.dtsi +++ b/boards/arm/mimxrt1170_evk/mimxrt1170_evk.dtsi @@ -193,13 +193,9 @@ label = "image-1"; reg = <0x00321000 0x300000>; }; - scratch_partition: partition@621000 { - label = "image-scratch"; - reg = <0x00621000 DT_SIZE_K(128)>; - }; - storage_partition: partition@641000 { + storage_partition: partition@621000 { label = "storage"; - reg = <0x00641000 DT_SIZE_K(1856)>; + reg = <0x00621000 DT_SIZE_K(1984)>; }; }; }; diff --git a/boards/arm/mimxrt1170_evk/mimxrt1170_evkb_cm4.dts b/boards/arm/mimxrt1170_evk/mimxrt1170_evkb_cm4.dts index 5700b77837c..79725d1ac35 100644 --- a/boards/arm/mimxrt1170_evk/mimxrt1170_evkb_cm4.dts +++ b/boards/arm/mimxrt1170_evk/mimxrt1170_evkb_cm4.dts @@ -58,13 +58,9 @@ label = "image-1"; reg = <0x00321000 0x300000>; }; - scratch_partition: partition@621000 { - label = "image-scratch"; - reg = <0x00621000 DT_SIZE_K(128)>; - }; - storage_partition: partition@641000 { + storage_partition: partition@621000 { label = "storage"; - reg = <0x00641000 DT_SIZE_K(1856)>; + reg = <0x00621000 DT_SIZE_K(1984)>; }; }; }; diff --git a/boards/arm/mimxrt1170_evk/mimxrt1170_evkb_cm7.dts b/boards/arm/mimxrt1170_evk/mimxrt1170_evkb_cm7.dts index e93f701cd87..feceb9eaa30 100644 --- a/boards/arm/mimxrt1170_evk/mimxrt1170_evkb_cm7.dts +++ b/boards/arm/mimxrt1170_evk/mimxrt1170_evkb_cm7.dts @@ -59,13 +59,9 @@ label = "image-1"; reg = <0x00321000 0x300000>; }; - scratch_partition: partition@621000 { - label = "image-scratch"; - reg = <0x00621000 DT_SIZE_K(128)>; - }; - storage_partition: partition@641000 { + storage_partition: partition@621000 { label = "storage"; - reg = <0x00641000 DT_SIZE_K(1856)>; + reg = <0x00621000 DT_SIZE_K(1984)>; }; }; }; From 9fe370ef3667651daaef0023f9fdef8462435f3f Mon Sep 17 00:00:00 2001 From: Doug Foster Date: Tue, 9 Jan 2024 22:45:25 -0600 Subject: [PATCH 2530/3723] samples: doc: Added/Updated README and Makefile for POSIX samples Added README.rst for eventfd and uname samples. Updated README for gettimeofday to align with other READMEs.Updated Makefile.host file for samples to store output file in 'build' directory. Signed-off-by: Doug Foster --- samples/posix/eventfd/Makefile.host | 3 +- samples/posix/eventfd/README.rst | 46 +++++++++++++++++++++ samples/posix/gettimeofday/Makefile.host | 3 +- samples/posix/gettimeofday/README.rst | 15 ++++--- samples/posix/uname/README.rst | 52 ++++++++++++++++++++++++ 5 files changed, 111 insertions(+), 8 deletions(-) create mode 100644 samples/posix/eventfd/README.rst create mode 100644 samples/posix/uname/README.rst diff --git a/samples/posix/eventfd/Makefile.host b/samples/posix/eventfd/Makefile.host index 8cb1f7d7da6..b5080991747 100644 --- a/samples/posix/eventfd/Makefile.host +++ b/samples/posix/eventfd/Makefile.host @@ -1,4 +1,5 @@ # This makefile builds the sample for a POSIX system, like Linux eventfd: src/main.c - $(CC) $^ -o $@ + mkdir -p build + $(CC) $^ -o build/$@ diff --git a/samples/posix/eventfd/README.rst b/samples/posix/eventfd/README.rst new file mode 100644 index 00000000000..c6947d6e57c --- /dev/null +++ b/samples/posix/eventfd/README.rst @@ -0,0 +1,46 @@ +.. _posix-eventfd-sample: + +POSIX eventfd() +############### + +Overview +******** + +This sample application demonstrates using the POSIX eventfd() function to create a file descriptor, +which can be used for event notification. The returned file descriptor is used with write/read calls +and write/read values are output to the console. + +Building and Running +******************** + +This project outputs to the console. It can be built and executed on QEMU as follows: + +.. zephyr-app-commands:: + :zephyr-app: samples/posix/eventfd + :host-os: unix + :board: qemu_x86 + :goals: run + :compact: + +For comparison, to build directly for your host OS if it is POSIX compliant (for ex. Linux): + +.. code-block:: console + + cd samples/posix/eventfd + make -f Makefile.host + +The make output file will be located in samples/posix/eventfd/build. + +Sample Output +============= + +.. code-block:: console + + Writing 1 to efd + Writing 2 to efd + Writing 3 to efd + Writing 4 to efd + Completed write loop + About to read + Read 10 (0xa) from efd + Finished diff --git a/samples/posix/gettimeofday/Makefile.host b/samples/posix/gettimeofday/Makefile.host index eb0529e1864..76023d7f21e 100644 --- a/samples/posix/gettimeofday/Makefile.host +++ b/samples/posix/gettimeofday/Makefile.host @@ -1,4 +1,5 @@ # This makefile builds the sample for a POSIX system, like Linux gettimeofday: src/main.c - $(CC) $^ -o $@ + mkdir -p build + $(CC) $^ -o build/$@ diff --git a/samples/posix/gettimeofday/README.rst b/samples/posix/gettimeofday/README.rst index c01f1c65e33..a9cd4771818 100644 --- a/samples/posix/gettimeofday/README.rst +++ b/samples/posix/gettimeofday/README.rst @@ -6,10 +6,9 @@ POSIX gettimeofday() with clock initialization over SNTP Overview ******** -This sample application demonstrates using the POSIX gettimeofday() -function to display the absolute wall clock time and local time every -second. At system startup, the current time is queried using the SNTP -networking protocol, enabled by setting the +This sample application demonstrates using the POSIX `gettimeofday()`_ function to display the +absolute wall clock time and local time every second. At system startup, the current time is +queried using the SNTP networking protocol, enabled by setting the :kconfig:option:`CONFIG_NET_CONFIG_CLOCK_SNTP_INIT` and :kconfig:option:`CONFIG_NET_CONFIG_SNTP_INIT_SERVER` options. @@ -24,8 +23,7 @@ Requirements Building and Running ******************** -This project outputs to the console. It can be built and executed -on QEMU as follows: +This project outputs to the console. It can be built and executed on QEMU as follows: .. zephyr-app-commands:: :zephyr-app: samples/posix/gettimeofday @@ -38,4 +36,9 @@ For comparison, to build directly for your host OS if it is POSIX compliant (for .. code-block:: console + cd samples/posix/gettimeofday make -f Makefile.host + +The make output file will be located in samples/posix/gettimeofday/build. + +.. _gettimeofday(): https://pubs.opengroup.org/onlinepubs/009604599/functions/gettimeofday.html diff --git a/samples/posix/uname/README.rst b/samples/posix/uname/README.rst new file mode 100644 index 00000000000..a7d6c69946b --- /dev/null +++ b/samples/posix/uname/README.rst @@ -0,0 +1,52 @@ +.. _posix-uname-sample: + +POSIX uname() +############# + +Overview +******** + +In this sample application, the POSIX `uname()`_ function is used to acquire system information and +it is output to the console. Additionally, uname is added as a shell command and system information +is displayed according to the option(s) provided for the command. + +Building and Running +******************** + +This project outputs to the console. It can be built and executed on QEMU as follows: + +.. zephyr-app-commands:: + :zephyr-app: samples/posix/uname + :host-os: unix + :board: qemu_x86 + :goals: run + :compact: + +For comparison, to build directly for your host OS if it is POSIX compliant (for ex. Linux): + +.. code-block:: console + + cd samples/posix/uname + make -f Makefile.host + +The make output file will be located in samples/posix/uname/build. + +Sample Output +============= + +.. code-block:: console + + Printing everything in utsname... + sysname[7]: Zephyr + nodename[7]: zephyr + release[13]: 3.5.99 + version[61]: zephyr-v3.5.0-3515-g10156f5f1d9c Jan 9 2024 22:23:04 + machine[4]: x86 + + + uart:~$ uname -a + Zephyr zephyr 3.5.99 zephyr-v3.5.0-3515-g10156f5f1d9c Jan 9 2024 22:23:04 x86 qemu_x86 + uart:~$ uname -smi + Zephyr x86 qemu_x86 + +.. _uname(): https://pubs.opengroup.org/onlinepubs/9699919799/functions/uname.html From 6a1f48bd4e2d63735d87819082c588006239c1ab Mon Sep 17 00:00:00 2001 From: Doug Foster Date: Sat, 13 Jan 2024 04:53:04 -0600 Subject: [PATCH 2531/3723] doc: posix: Update services/portability/posix doc Update index.rst located in doc/services/portability/posix/overview to include link to POSIX samples. Signed-off-by: Doug Foster --- doc/services/portability/posix/overview/index.rst | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/doc/services/portability/posix/overview/index.rst b/doc/services/portability/posix/overview/index.rst index 53b7df30d23..4ef1f9a596d 100644 --- a/doc/services/portability/posix/overview/index.rst +++ b/doc/services/portability/posix/overview/index.rst @@ -103,8 +103,7 @@ leverages the ``nanosleep()`` and ``perror()`` POSIX functions. return 0; } -.. - TODO: insert a link to a list of all samples tagged with 'posix' +For more examples of POSIX applications, please see the :ref:`POSIX sample applications`. .. _posix_config: From 5a2641b1d7ba7f77cd751edf5779d1b413d18df2 Mon Sep 17 00:00:00 2001 From: Alberto Escolar Piedras Date: Tue, 16 Jan 2024 15:42:05 +0100 Subject: [PATCH 2532/3723] native_simulator: Get latest from upstream Align with native_simulator's upstream main 3eae4374db5984a5defcefdeda254b37e72e2ca8 Which includes: * 3eae437 cmdline parsing: Allow providing more arguments progammatically * d148a28 Host trampolines: Add realloc Signed-off-by: Alberto Escolar Piedras --- .../common/src/include/nsi_cmdline_main_if.h | 1 + .../common/src/include/nsi_host_trampolines.h | 1 + .../common/src/nsi_host_trampolines.c | 5 ++++ .../native_simulator/native/src/nsi_cmdline.c | 29 +++++++++++++++++++ 4 files changed, 36 insertions(+) diff --git a/scripts/native_simulator/common/src/include/nsi_cmdline_main_if.h b/scripts/native_simulator/common/src/include/nsi_cmdline_main_if.h index 7c7df5cd0c6..2289fcc7bd4 100644 --- a/scripts/native_simulator/common/src/include/nsi_cmdline_main_if.h +++ b/scripts/native_simulator/common/src/include/nsi_cmdline_main_if.h @@ -18,6 +18,7 @@ extern "C" { #endif void nsi_handle_cmd_line(int argc, char *argv[]); +void nsi_register_extra_args(int argc, char *argv[]); #ifdef __cplusplus } diff --git a/scripts/native_simulator/common/src/include/nsi_host_trampolines.h b/scripts/native_simulator/common/src/include/nsi_host_trampolines.h index f7f7dce877d..90773f9c7d2 100644 --- a/scripts/native_simulator/common/src/include/nsi_host_trampolines.h +++ b/scripts/native_simulator/common/src/include/nsi_host_trampolines.h @@ -33,6 +33,7 @@ int nsi_host_open(const char *pathname, int flags); /* int nsi_host_printf (const char *fmt, ...); Use the nsi_tracing.h equivalents */ long nsi_host_random(void); long nsi_host_read(int fd, void *buffer, unsigned long size); +void *nsi_host_realloc(void *ptr, unsigned long size); void nsi_host_srandom(unsigned int seed); char *nsi_host_strdup(const char *s); long nsi_host_write(int fd, void *buffer, unsigned long size); diff --git a/scripts/native_simulator/common/src/nsi_host_trampolines.c b/scripts/native_simulator/common/src/nsi_host_trampolines.c index 3feb8482c91..093a66d53ca 100644 --- a/scripts/native_simulator/common/src/nsi_host_trampolines.c +++ b/scripts/native_simulator/common/src/nsi_host_trampolines.c @@ -56,6 +56,11 @@ long nsi_host_read(int fd, void *buffer, unsigned long size) return read(fd, buffer, size); } +void *nsi_host_realloc(void *ptr, unsigned long size) +{ + return realloc(ptr, size); +} + void nsi_host_srandom(unsigned int seed) { srandom(seed); diff --git a/scripts/native_simulator/native/src/nsi_cmdline.c b/scripts/native_simulator/native/src/nsi_cmdline.c index e2fefb677fa..c2490aa85cb 100644 --- a/scripts/native_simulator/native/src/nsi_cmdline.c +++ b/scripts/native_simulator/native/src/nsi_cmdline.c @@ -18,6 +18,10 @@ static int s_argc, test_argc; static char **s_argv, **test_argv; +/* Extra "command line options" provided programmatically: */ +static int extra_argc; +static char **extra_argv; + static struct args_struct_t *args_struct; static int used_args; static int args_aval; @@ -119,6 +123,13 @@ void nsi_handle_cmd_line(int argc, char *argv[]) nsi_cmd_args_set_defaults(args_struct); + for (int i = 0; i < extra_argc; i++) { + if (!nsi_cmd_parse_one_arg(extra_argv[i], args_struct)) { + nsi_cmd_print_switches_help(args_struct); + print_invalid_opt_error(extra_argv[i]); + } + } + for (i = 1; i < argc; i++) { if ((nsi_cmd_is_option(argv[i], "testargs", 0))) { @@ -134,6 +145,24 @@ void nsi_handle_cmd_line(int argc, char *argv[]) } } +void nsi_register_extra_args(int argc, char *argv[]) +{ + int new_size = extra_argc + argc; + + extra_argv = realloc(extra_argv, new_size*sizeof(char *)); + for (int i = 0; i < argc; i++) { + memcpy(&extra_argv[extra_argc], argv, argc*sizeof(char *)); + } + extra_argc += argc; +} + +static void clear_extra_args(void) +{ + free(extra_argv); +} + +NSI_TASK(clear_extra_args, ON_EXIT_PRE, 100); + /** * The application/test can use this function to inspect all the command line * arguments From 9d267b91e24c3bdf7c35272ed20069f2405cd4bc Mon Sep 17 00:00:00 2001 From: Alberto Escolar Piedras Date: Thu, 11 Jan 2024 16:38:59 +0100 Subject: [PATCH 2533/3723] boards native: Add extra arguments through kconfig Add a new way of passing extra command line arguments to native simulator based boards using kconfig. If this new kconfig option is set, its content will be treated as extra command line arguments/options which will be parsed before the other command line options. Signed-off-by: Alberto Escolar Piedras --- boards/posix/common/extra_args/CMakeLists.txt | 7 ++ boards/posix/common/extra_args/Kconfig | 9 ++ boards/posix/common/extra_args/extra_args.c | 75 +++++++++++++++ boards/posix/native_sim/CMakeLists.txt | 4 + boards/posix/native_sim/Kconfig | 1 + boards/posix/nrf_bsim/CMakeLists.txt | 4 + boards/posix/nrf_bsim/Kconfig | 2 + .../posix/nrf_bsim/common/bsim_args_runner.c | 93 +++++++++++++------ 8 files changed, 166 insertions(+), 29 deletions(-) create mode 100644 boards/posix/common/extra_args/CMakeLists.txt create mode 100644 boards/posix/common/extra_args/Kconfig create mode 100644 boards/posix/common/extra_args/extra_args.c diff --git a/boards/posix/common/extra_args/CMakeLists.txt b/boards/posix/common/extra_args/CMakeLists.txt new file mode 100644 index 00000000000..c3448051452 --- /dev/null +++ b/boards/posix/common/extra_args/CMakeLists.txt @@ -0,0 +1,7 @@ +# Copyright (c) 2024 Nordic Semiconductor ASA +# SPDX-License-Identifier: Apache-2.0 + +if (CONFIG_NATIVE_EXTRA_CMDLINE_ARGS) + zephyr_library() + zephyr_library_sources(extra_args.c) +endif() diff --git a/boards/posix/common/extra_args/Kconfig b/boards/posix/common/extra_args/Kconfig new file mode 100644 index 00000000000..e1e1f8d725e --- /dev/null +++ b/boards/posix/common/extra_args/Kconfig @@ -0,0 +1,9 @@ +# Copyright (c) 2024 Nordic Semiconductor ASA +# SPDX-License-Identifier: Apache-2.0 + +config NATIVE_EXTRA_CMDLINE_ARGS + depends on ARCH_POSIX + string "Extra command line arguments" + help + Extra command line options/arguments which will be handled like if they were passed to the + program from the shell. These will be parsed just before the shell provided ones. diff --git a/boards/posix/common/extra_args/extra_args.c b/boards/posix/common/extra_args/extra_args.c new file mode 100644 index 00000000000..b2e57dc674e --- /dev/null +++ b/boards/posix/common/extra_args/extra_args.c @@ -0,0 +1,75 @@ +/* + * Copyright (c) 2024 Nordic Semiconductor ASA + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include +#include +#include +#include +#include +#include +#include + +static void remove_one_char(char *str) +{ + int i; + + for (i = 0; str[i] != 0; i++) { + str[i] = str[i+1]; + } +} + +static void register_kconfig_args(void) +{ + static char kconfig_args[] = CONFIG_NATIVE_EXTRA_CMDLINE_ARGS; + int argc = 0; + char **argv = NULL; +#define REALLOC_INC 100 + int alloced = 0; + bool new_arg = true, literal = false, escape = false; + + if (kconfig_args[0] == 0) { + return; + } + + for (int i = 0; kconfig_args[i] != 0; i++) { + if ((literal == false) && (escape == false) && isspace(kconfig_args[i])) { + new_arg = true; + kconfig_args[i] = 0; + continue; + } + if ((escape == false) && (kconfig_args[i] == '\\')) { + escape = true; + remove_one_char(&kconfig_args[i]); + i--; + continue; + } + if ((escape == false) && (kconfig_args[i] == '"')) { + literal = !literal; + remove_one_char(&kconfig_args[i]); + i--; + continue; + } + escape = false; + + if (new_arg) { + new_arg = false; + if (argc >= alloced) { + alloced += REALLOC_INC; + argv = nsi_host_realloc(argv, alloced*sizeof(char *)); + if (argv == NULL) { + nsi_print_error_and_exit("Out of memory\n"); + } + } + argv[argc++] = &kconfig_args[i]; + } + } + + nsi_register_extra_args(argc, argv); + + nsi_host_free(argv); +} + +NATIVE_TASK(register_kconfig_args, PRE_BOOT_1, 100); diff --git a/boards/posix/native_sim/CMakeLists.txt b/boards/posix/native_sim/CMakeLists.txt index 34a538f4c60..5ddf0e5f143 100644 --- a/boards/posix/native_sim/CMakeLists.txt +++ b/boards/posix/native_sim/CMakeLists.txt @@ -27,6 +27,10 @@ if(CONFIG_HAS_SDL) add_subdirectory(${ZEPHYR_BASE}/boards/${ARCH}/common/sdl/ ${CMAKE_CURRENT_BINARY_DIR}/sdl) endif() +add_subdirectory(${ZEPHYR_BASE}/boards/${ARCH}/common/extra_args/ + ${CMAKE_CURRENT_BINARY_DIR}/extra_args +) + set(nsi_config_content ${nsi_config_content} "NSI_NATIVE=1" diff --git a/boards/posix/native_sim/Kconfig b/boards/posix/native_sim/Kconfig index aabbd4d794f..ddf76a5f157 100644 --- a/boards/posix/native_sim/Kconfig +++ b/boards/posix/native_sim/Kconfig @@ -46,5 +46,6 @@ config NATIVE_POSIX_SLOWDOWN_TO_REAL_TIME to set the correct native_sim option (CONFIG_NATIVE_SIM_SLOWDOWN_TO_REAL_TIME) source "boards/$(ARCH)/common/sdl/Kconfig" +source "boards/$(ARCH)/common/extra_args/Kconfig" endif # BOARD_NATIVE_SIM diff --git a/boards/posix/nrf_bsim/CMakeLists.txt b/boards/posix/nrf_bsim/CMakeLists.txt index dfa6248f7dc..3ff7d632d4f 100644 --- a/boards/posix/nrf_bsim/CMakeLists.txt +++ b/boards/posix/nrf_bsim/CMakeLists.txt @@ -73,4 +73,8 @@ set_property(TARGET native_simulator APPEND PROPERTY RUNNER_LINK_LIBRARIES target_compile_options(native_simulator INTERFACE "-DNSI_PRIMARY_MCU_N=${CONFIG_NATIVE_SIMULATOR_PRIMARY_MCU_INDEX}") +add_subdirectory(${ZEPHYR_BASE}/boards/${ARCH}/common/extra_args/ + ${CMAKE_CURRENT_BINARY_DIR}/extra_args +) + include(../common/natsim_config.cmake) diff --git a/boards/posix/nrf_bsim/Kconfig b/boards/posix/nrf_bsim/Kconfig index d86478a4f4c..c9a855d2111 100644 --- a/boards/posix/nrf_bsim/Kconfig +++ b/boards/posix/nrf_bsim/Kconfig @@ -8,6 +8,8 @@ if SOC_SERIES_BSIM_NRFXX # must be read also from here. source "soc/arm/nordic_nrf/Kconfig.peripherals" +source "boards/$(ARCH)/common/extra_args/Kconfig" + endif # SOC_SERIES_BSIM_NRFXX diff --git a/boards/posix/nrf_bsim/common/bsim_args_runner.c b/boards/posix/nrf_bsim/common/bsim_args_runner.c index 29e0d15dd2e..2e84ca812fe 100644 --- a/boards/posix/nrf_bsim/common/bsim_args_runner.c +++ b/boards/posix/nrf_bsim/common/bsim_args_runner.c @@ -15,6 +15,7 @@ #include #include #include +#include #include "bs_cmd_line.h" #include "bs_cmd_line_typical.h" #include "bs_dynargs.h" @@ -40,6 +41,10 @@ static struct bsim_global_args_t { static bool nosim; +/* Extra "command line options" provided programmatically: */ +static int extra_argc; +static char **extra_argv; + static void cmd_trace_lvl_found(char *argv, int offset) { bs_trace_set_level(global_args.verb); @@ -159,48 +164,76 @@ static void nsif_cpun_save_test_arg(int n, char *c) fptrs[n](c); } +static void nsi_handle_one_cmdline_argument(char *argv) +{ + static enum {Main = 0, Test = 1} parsing = Main; + static uint test_cpu_n; + + if (bs_is_option(argv, "argstest", 0)) { + parsing = Test; + test_cpu_n = NSI_PRIMARY_MCU_N; + return; + } else if (bs_is_multi_opt(argv, "argstest", &test_cpu_n, 0)) { + parsing = Test; + return; + } else if (bs_is_option(argv, "argsmain", 0)) { + parsing = Main; + return; + } + + if (parsing == Main) { + if (!bs_args_parse_one_arg(argv, args_struct)) { + bs_args_print_switches_help(args_struct); + bs_trace_error_line("Incorrect option %s\n", + argv); + } + } else if (parsing == Test) { + nsif_cpun_save_test_arg(test_cpu_n, argv); + } else { + bs_trace_error_line("Bad error\n"); + } +} + /** * Check the arguments provided in the command line: set args based on it or * defaults, and check they are correct */ void nsi_handle_cmd_line(int argc, char *argv[]) { - const char *bogus_sim_id = "bogus"; - bs_args_set_defaults(args_struct); global_args.verb = 2; bs_trace_set_level(global_args.verb); - static const char default_phy[] = "2G4"; - - enum {Main = 0, Test = 1} parsing = Main; - uint test_cpu_n; - + for (int i = 0; i < extra_argc; i++) { + nsi_handle_one_cmdline_argument(extra_argv[i]); + } for (int i = 1; i < argc; i++) { - if (bs_is_option(argv[i], "argstest", 0)) { - parsing = Test; - test_cpu_n = NSI_PRIMARY_MCU_N; - continue; - } else if (bs_is_multi_opt(argv[i], "argstest", &test_cpu_n, 0)) { - parsing = Test; - continue; - } else if (bs_is_option(argv[i], "argsmain", 0)) { - parsing = Main; - continue; - } + nsi_handle_one_cmdline_argument(argv[i]); + } +} - if (parsing == Main) { - if (!bs_args_parse_one_arg(argv[i], args_struct)) { - bs_args_print_switches_help(args_struct); - bs_trace_error_line("Incorrect option %s\n", - argv[i]); - } - } else if (parsing == Test) { - nsif_cpun_save_test_arg(test_cpu_n, argv[i]); - } else { - bs_trace_error_line("Bad error\n"); - } +void nsi_register_extra_args(int argc, char *argv[]) +{ + int new_size = extra_argc + argc; + + extra_argv = realloc(extra_argv, new_size*sizeof(char *)); + for (int i = 0; i < argc; i++) { + memcpy(&extra_argv[extra_argc], argv, argc*sizeof(char *)); } + extra_argc += argc; +} + +static void clear_extra_args(void) +{ + free(extra_argv); +} + +NSI_TASK(clear_extra_args, ON_EXIT_PRE, 100); + +static void postcheck_cmd_line(void) +{ + static const char *bogus_sim_id = "bogus"; + static const char default_phy[] = "2G4"; /** * If the user did not set the simulation id or device number @@ -246,6 +279,8 @@ void nsi_handle_cmd_line(int argc, char *argv[]) bs_random_init(global_args.rseed); } +NSI_TASK(postcheck_cmd_line, PRE_BOOT_2, 0); + /* * Get the simulation id */ From a019cc2c9fff9b86b06f60d82f704276d09092d4 Mon Sep 17 00:00:00 2001 From: Andrej Butok Date: Wed, 17 Jan 2024 09:40:57 +0100 Subject: [PATCH 2534/3723] test: mcuboot: enable test on lpc55s platforms Enable mcuboot test for lpcxpresso55s06/16/28/36/69 boards. Signed-off-by: Andrej Butok --- tests/boot/test_mcuboot/testcase.yaml | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/tests/boot/test_mcuboot/testcase.yaml b/tests/boot/test_mcuboot/testcase.yaml index 0fff9fa97d3..b4b7735c1c8 100644 --- a/tests/boot/test_mcuboot/testcase.yaml +++ b/tests/boot/test_mcuboot/testcase.yaml @@ -16,6 +16,11 @@ tests: - frdm_k22f - frdm_k64f - frdm_k82f + - lpcxpresso55s06 + - lpcxpresso55s16 + - lpcxpresso55s28 + - lpcxpresso55s36 + - lpcxpresso55s69_cpu0 - mimxrt1010_evk - mimxrt1015_evk - mimxrt1020_evk From efe92870c8e6b007b596371f18250e4a0f9a9df5 Mon Sep 17 00:00:00 2001 From: Dawid Niedzwiecki Date: Wed, 17 Jan 2024 09:41:59 +0100 Subject: [PATCH 2535/3723] ec_host_cmd: spi_stm32: prevent accessing null pointer There is a possibility that the SPI STM32 Host Command backend is being suspended, without earlier initialization. Make sure we are not accessing uninitialized pointer, namely the cs structure. Signed-off-by: Dawid Niedzwiecki --- .../backends/ec_host_cmd_backend_spi_stm32.c | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/subsys/mgmt/ec_host_cmd/backends/ec_host_cmd_backend_spi_stm32.c b/subsys/mgmt/ec_host_cmd/backends/ec_host_cmd_backend_spi_stm32.c index 55a58ad6627..bdc9faf6871 100644 --- a/subsys/mgmt/ec_host_cmd/backends/ec_host_cmd_backend_spi_stm32.c +++ b/subsys/mgmt/ec_host_cmd/backends/ec_host_cmd_backend_spi_stm32.c @@ -694,7 +694,7 @@ static int ec_host_cmd_spi_init(const struct ec_host_cmd_backend *backend, hc_spi->state = SPI_HOST_CMD_STATE_DISABLED; /* SPI backend needs rx and tx buffers provided by the handler */ - if (!rx_ctx->buf || !tx->buf) { + if (!rx_ctx->buf || !tx->buf || !hc_spi->cs.port) { return -EIO; } @@ -806,7 +806,9 @@ static int ec_host_cmd_spi_stm32_pm_action(const struct device *dev, return err; } /* Enable CS interrupts. */ - gpio_pin_interrupt_configure_dt(&hc_spi->cs, GPIO_INT_EDGE_BOTH); + if (hc_spi->cs.port) { + gpio_pin_interrupt_configure_dt(&hc_spi->cs, GPIO_INT_EDGE_BOTH); + } break; case PM_DEVICE_ACTION_SUSPEND: @@ -817,7 +819,9 @@ static int ec_host_cmd_spi_stm32_pm_action(const struct device *dev, WAIT_FOR((LL_SPI_IsActiveFlag_BSY(cfg->spi) == 0), 10 * USEC_PER_MSEC, NULL); #endif /* Disable unnecessary interrupts. */ - gpio_pin_interrupt_configure_dt(&hc_spi->cs, GPIO_INT_DISABLE); + if (hc_spi->cs.port) { + gpio_pin_interrupt_configure_dt(&hc_spi->cs, GPIO_INT_DISABLE); + } /* Stop device clock. */ err = clock_control_off(DEVICE_DT_GET(STM32_CLOCK_CONTROL_NODE), From 1d14f13d75eb31104eb84d5d00e835cf82fb8377 Mon Sep 17 00:00:00 2001 From: Robert Lubos Date: Tue, 16 Jan 2024 17:37:59 +0100 Subject: [PATCH 2536/3723] net: arp: Make arp_update() function externally visible So that it's possible to register ARP entries manually. Needed for DHCP server implementation, which in unicast mode needs to reply to an IP address that is not registered on the peer interface yet (hence no ARP reply will be sent). It's needed to add an ARP entry manually in that case, as hardware address is already known at that point. Signed-off-by: Robert Lubos --- subsys/net/l2/ethernet/arp.c | 34 +++++++++++++++++----------------- subsys/net/l2/ethernet/arp.h | 4 ++++ 2 files changed, 21 insertions(+), 17 deletions(-) diff --git a/subsys/net/l2/ethernet/arp.c b/subsys/net/l2/ethernet/arp.c index 39a06ed64a0..6be7255b19b 100644 --- a/subsys/net/l2/ethernet/arp.c +++ b/subsys/net/l2/ethernet/arp.c @@ -457,11 +457,11 @@ static void arp_gratuitous(struct net_if *iface, } } -static void arp_update(struct net_if *iface, - struct in_addr *src, - struct net_eth_addr *hwaddr, - bool gratuitous, - bool force) +void net_arp_update(struct net_if *iface, + struct in_addr *src, + struct net_eth_addr *hwaddr, + bool gratuitous, + bool force) { struct arp_entry *entry; struct net_pkt *pkt; @@ -647,10 +647,10 @@ enum net_verdict net_arp_input(struct net_pkt *pkt, /* If the IP address is in our cache, * then update it here. */ - arp_update(net_pkt_iface(pkt), - (struct in_addr *)arp_hdr->src_ipaddr, - &arp_hdr->src_hwaddr, - true, false); + net_arp_update(net_pkt_iface(pkt), + (struct in_addr *)arp_hdr->src_ipaddr, + &arp_hdr->src_hwaddr, + true, false); break; } } @@ -689,10 +689,10 @@ enum net_verdict net_arp_input(struct net_pkt *pkt, net_sprint_ll_addr((uint8_t *)&arp_hdr->src_hwaddr, arp_hdr->hwlen)); - arp_update(net_pkt_iface(pkt), - (struct in_addr *)arp_hdr->src_ipaddr, - &arp_hdr->src_hwaddr, - false, true); + net_arp_update(net_pkt_iface(pkt), + (struct in_addr *)arp_hdr->src_ipaddr, + &arp_hdr->src_hwaddr, + false, true); dst_hw_addr = &arp_hdr->src_hwaddr; } else { @@ -711,10 +711,10 @@ enum net_verdict net_arp_input(struct net_pkt *pkt, case NET_ARP_REPLY: if (net_ipv4_is_my_addr((struct in_addr *)arp_hdr->dst_ipaddr)) { - arp_update(net_pkt_iface(pkt), - (struct in_addr *)arp_hdr->src_ipaddr, - &arp_hdr->src_hwaddr, - false, false); + net_arp_update(net_pkt_iface(pkt), + (struct in_addr *)arp_hdr->src_ipaddr, + &arp_hdr->src_hwaddr, + false, false); } break; diff --git a/subsys/net/l2/ethernet/arp.h b/subsys/net/l2/ethernet/arp.h index 28cafe5f20a..46589cbc1f7 100644 --- a/subsys/net/l2/ethernet/arp.h +++ b/subsys/net/l2/ethernet/arp.h @@ -67,6 +67,9 @@ int net_arp_foreach(net_arp_cb_t cb, void *user_data); void net_arp_clear_cache(struct net_if *iface); void net_arp_init(void); +void net_arp_update(struct net_if *iface, struct in_addr *src, + struct net_eth_addr *hwaddr, bool gratuitous, + bool force); /** * @} @@ -83,6 +86,7 @@ void net_arp_init(void); #define net_arp_foreach(...) 0 #define net_arp_init(...) #define net_arp_clear_pending(...) 0 +#define net_arp_update(...) #endif /* CONFIG_NET_ARP */ From db80ed3e8df1d662f5e750b5629e5e6e7c1bddd5 Mon Sep 17 00:00:00 2001 From: Robert Lubos Date: Tue, 16 Jan 2024 17:38:16 +0100 Subject: [PATCH 2537/3723] net: if: Add function to obtain IPv4 netmask Add a helper function to obtain IPv4 netmask configured on an interface. Signed-off-by: Robert Lubos --- include/zephyr/net/net_if.h | 9 +++++++++ subsys/net/ip/net_if.c | 21 +++++++++++++++++++++ 2 files changed, 30 insertions(+) diff --git a/include/zephyr/net/net_if.h b/include/zephyr/net/net_if.h index 22a3e14fa14..d849451d0c2 100644 --- a/include/zephyr/net/net_if.h +++ b/include/zephyr/net/net_if.h @@ -2279,6 +2279,15 @@ struct in_addr *net_if_ipv4_get_ll(struct net_if *iface, struct in_addr *net_if_ipv4_get_global_addr(struct net_if *iface, enum net_addr_state addr_state); +/** + * @brief Get IPv4 netmask of an interface. + * + * @param iface Interface to use. + * + * @return The netmask set on the interface, unspecified address if not found. + */ +struct in_addr net_if_ipv4_get_netmask(struct net_if *iface); + /** * @brief Set IPv4 netmask for an interface. * diff --git a/subsys/net/ip/net_if.c b/subsys/net/ip/net_if.c index bb6099b9781..a5486ce4283 100644 --- a/subsys/net/ip/net_if.c +++ b/subsys/net/ip/net_if.c @@ -3619,6 +3619,27 @@ static inline int z_vrfy_net_if_ipv4_addr_lookup_by_index( #include #endif +struct in_addr net_if_ipv4_get_netmask(struct net_if *iface) +{ + struct in_addr netmask = { 0 }; + + net_if_lock(iface); + + if (net_if_config_ipv4_get(iface, NULL) < 0) { + goto out; + } + + if (!iface->config.ip.ipv4) { + goto out; + } + + netmask = iface->config.ip.ipv4->netmask; +out: + net_if_unlock(iface); + + return netmask; +} + void net_if_ipv4_set_netmask(struct net_if *iface, const struct in_addr *netmask) { From 1e08bbd5434f82e7a7849677e7dd10416d71488b Mon Sep 17 00:00:00 2001 From: Robert Lubos Date: Tue, 16 Jan 2024 17:38:56 +0100 Subject: [PATCH 2538/3723] net: dhcpv4: Implement DHCPv4 server Add basic socket-based implementation of DHCPv4 sever. Signed-off-by: Robert Lubos --- include/zephyr/net/dhcpv4_server.h | 118 ++ subsys/net/ip/dhcpv4.h | 11 + subsys/net/ip/net_core.c | 2 + subsys/net/lib/CMakeLists.txt | 1 + subsys/net/lib/Kconfig | 2 + subsys/net/lib/dhcpv4/CMakeLists.txt | 11 + subsys/net/lib/dhcpv4/Kconfig | 46 + subsys/net/lib/dhcpv4/dhcpv4_server.c | 1439 +++++++++++++++++++++++++ 8 files changed, 1630 insertions(+) create mode 100644 include/zephyr/net/dhcpv4_server.h create mode 100644 subsys/net/lib/dhcpv4/CMakeLists.txt create mode 100644 subsys/net/lib/dhcpv4/Kconfig create mode 100644 subsys/net/lib/dhcpv4/dhcpv4_server.c diff --git a/include/zephyr/net/dhcpv4_server.h b/include/zephyr/net/dhcpv4_server.h new file mode 100644 index 00000000000..18c4af114cd --- /dev/null +++ b/include/zephyr/net/dhcpv4_server.h @@ -0,0 +1,118 @@ +/** @file + * @brief DHCPv4 Server API + */ + +/* + * Copyright (c) 2024 Nordic Semiconductor ASA + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#ifndef ZEPHYR_INCLUDE_NET_DHCPV4_SERVER_H_ +#define ZEPHYR_INCLUDE_NET_DHCPV4_SERVER_H_ + +#include +#include + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * @brief DHCPv4 server + * @defgroup dhcpv4_server DHCPv4 server + * @ingroup networking + * @{ + */ + +/** @cond INTERNAL_HIDDEN */ + +struct net_if; + +#define DHCPV4_CLIENT_ID_MAX_SIZE 20 + +enum dhcpv4_server_addr_state { + DHCPV4_SERVER_ADDR_FREE, + DHCPV4_SERVER_ADDR_RESERVED, + DHCPV4_SERVER_ADDR_ALLOCATED, + DHCPV4_SERVER_ADDR_DECLINED, +}; + +struct dhcpv4_client_id { + uint8_t buf[DHCPV4_CLIENT_ID_MAX_SIZE]; + uint8_t len; +}; + +struct dhcpv4_addr_slot { + enum dhcpv4_server_addr_state state; + struct dhcpv4_client_id client_id; + struct in_addr addr; + uint32_t lease_time; + k_timepoint_t expiry; +}; + +/** @endcond */ + +/** + * @brief Start DHCPv4 server instance on an iface + * + * @details Start DHCPv4 server on a given interface. The server will start + * listening for DHCPv4 Discover/Request messages on the interface and assign + * IPv4 addresses from the configured address pool accordingly. + * + * @param iface A valid pointer on an interface + * @param base_addr First IPv4 address from the DHCPv4 address pool. The number + * of addresses in the pool is configured statically with Kconfig + * (CONFIG_NET_DHCPV4_SERVER_ADDR_COUNT). + * + * @return 0 on success, a negative error code otherwise. + */ +int net_dhcpv4_server_start(struct net_if *iface, struct in_addr *base_addr); + +/** + * @brief Stop DHCPv4 server instance on an iface + * + * @details Stop DHCPv4 server on a given interface. DHCPv4 requests will no + * longer be handled on the interface, and all of the allocations are cleared. + * + * @param iface A valid pointer on an interface + * + * @return 0 on success, a negative error code otherwise. + */ +int net_dhcpv4_server_stop(struct net_if *iface); + +/** + * @typedef net_dhcpv4_lease_cb_t + * @brief Callback used while iterating over active DHCPv4 address leases + * + * @param iface Pointer to the network interface + * @param lease Pointer to the DHPCv4 address lease slot + * @param user_data A valid pointer to user data or NULL + */ +typedef void (*net_dhcpv4_lease_cb_t)(struct net_if *iface, + struct dhcpv4_addr_slot *lease, + void *user_data); + +/** + * @brief Iterate over all DHCPv4 address leases on a given network interface + * and call callback for each lease. In case no network interface is provided + * (NULL interface pointer), will iterate over all interfaces running DHCPv4 + * server instance. + * + * @param iface Pointer to the network interface, can be NULL + * @param cb User-supplied callback function to call + * @param user_data User specified data + */ +int net_dhcpv4_server_foreach_lease(struct net_if *iface, + net_dhcpv4_lease_cb_t cb, + void *user_data); + +/** + * @} + */ + +#ifdef __cplusplus +} +#endif + +#endif /* ZEPHYR_INCLUDE_NET_DHCPV4_SERVER_H_ */ diff --git a/subsys/net/ip/dhcpv4.h b/subsys/net/ip/dhcpv4.h index a274e3a6aea..712d361ac80 100644 --- a/subsys/net/ip/dhcpv4.h +++ b/subsys/net/ip/dhcpv4.h @@ -62,6 +62,7 @@ struct dhcp_msg { #define DHCPV4_OPTIONS_REQ_LIST 55 #define DHCPV4_OPTIONS_RENEWAL 58 #define DHCPV4_OPTIONS_REBINDING 59 +#define DHCPV4_OPTIONS_CLIENT_ID 61 #define DHCPV4_OPTIONS_END 255 /* Useful size macros */ @@ -142,4 +143,14 @@ static inline bool net_dhcpv4_accept_unicast(struct net_pkt *pkt) #endif /* CONFIG_NET_DHCPV4 && CONFIG_NET_DHCPV4_ACCEPT_UNICAST */ +#if defined(CONFIG_NET_DHCPV4_SERVER) + +void net_dhcpv4_server_init(void); + +#else + +#define net_dhcpv4_server_init() + +#endif /* CONFIG_NET_DHCPV4_SERVER */ + #endif /* __INTERNAL_DHCPV4_H */ diff --git a/subsys/net/ip/net_core.c b/subsys/net/ip/net_core.c index 45f489dbb46..e5adf8adaff 100644 --- a/subsys/net/ip/net_core.c +++ b/subsys/net/ip/net_core.c @@ -559,6 +559,8 @@ static inline int services_init(void) return status; } + net_dhcpv4_server_init(); + dns_init_resolver(); websocket_init(); diff --git a/subsys/net/lib/CMakeLists.txt b/subsys/net/lib/CMakeLists.txt index 5e4eae7e028..e3319f6cd8d 100644 --- a/subsys/net/lib/CMakeLists.txt +++ b/subsys/net/lib/CMakeLists.txt @@ -15,6 +15,7 @@ add_subdirectory_ifdef(CONFIG_NET_CAPTURE capture) add_subdirectory_ifdef(CONFIG_NET_ZPERF zperf) add_subdirectory_ifdef(CONFIG_NET_SHELL shell) add_subdirectory_ifdef(CONFIG_NET_TRICKLE trickle) +add_subdirectory_ifdef(CONFIG_NET_DHCPV4_SERVER dhcpv4) if (CONFIG_DNS_RESOLVER OR CONFIG_MDNS_RESPONDER diff --git a/subsys/net/lib/Kconfig b/subsys/net/lib/Kconfig index b70105d5f9b..6cfa0445241 100644 --- a/subsys/net/lib/Kconfig +++ b/subsys/net/lib/Kconfig @@ -39,6 +39,8 @@ menu "Network additional services" source "subsys/net/lib/capture/Kconfig" +source "subsys/net/lib/dhcpv4/Kconfig" + source "subsys/net/lib/trickle/Kconfig" source "subsys/net/lib/zperf/Kconfig" diff --git a/subsys/net/lib/dhcpv4/CMakeLists.txt b/subsys/net/lib/dhcpv4/CMakeLists.txt new file mode 100644 index 00000000000..348b6c99bb7 --- /dev/null +++ b/subsys/net/lib/dhcpv4/CMakeLists.txt @@ -0,0 +1,11 @@ +# Copyright (c) 2024 Nordic Semiconductor ASA +# +# SPDX-License-Identifier: Apache-2.0 + +zephyr_library() + +zephyr_library_include_directories(${ZEPHYR_BASE}/subsys/net/ip) + +zephyr_library_sources( + dhcpv4_server.c + ) diff --git a/subsys/net/lib/dhcpv4/Kconfig b/subsys/net/lib/dhcpv4/Kconfig new file mode 100644 index 00000000000..801d536a5a1 --- /dev/null +++ b/subsys/net/lib/dhcpv4/Kconfig @@ -0,0 +1,46 @@ +# DHCPv4 server implementation for Zephyr + +# Copyright (c) 2024 Nordic Semiconductor ASA +# +# SPDX-License-Identifier: Apache-2.0 + +config NET_DHCPV4_SERVER + bool "DHCPv4 server" + depends on NET_IPV4 && NET_UDP + select NET_SOCKETS + select NET_SOCKETS_SERVICE + +if NET_DHCPV4_SERVER + +module = NET_DHCPV4_SERVER +module-dep = NET_LOG +module-str = Log level for DHCPv4 server +module-help = Enables DHCPv4 server output debug messages +source "subsys/net/Kconfig.template.log_config.net" + +config NET_DHCPV4_SERVER_INSTANCES + int "Maximum number of DHCPv4 server instances" + default 1 + help + Maximum number of DHCPv4 server instances supported by the system. + Each network interface that wants to act as a DHCPv4 server requires + a separate instance. + +config NET_DHCPV4_SERVER_ADDR_COUNT + int "Number of IPv4 addresses that can be assigned by the server" + default 4 + help + Maximum number of IPv4 addresses that can be assigned by the DHCPv4 + server instance. The base IPv4 address in the address pool is provided + at runtime, during server initialization. Consecutive addresses in the + pool have the lowest address octet incremented. + +config NET_DHCPV4_SERVER_ADDR_LEASE_TIME + int "Lease time for IPv4 addresses assigned by the server (seconds)" + default 86400 + help + Lease time in seconds for IPv4 addresses assigned by the server. + The lease time determines when the IPv4 address lease expires if the + client does not renew it. + +endif # NET_DHCPV4_SERVER diff --git a/subsys/net/lib/dhcpv4/dhcpv4_server.c b/subsys/net/lib/dhcpv4/dhcpv4_server.c new file mode 100644 index 00000000000..714d036ddde --- /dev/null +++ b/subsys/net/lib/dhcpv4/dhcpv4_server.c @@ -0,0 +1,1439 @@ +/** @file + * @brief DHCPv4 server implementation + */ + +/* + * Copyright (c) 2024 Nordic Semiconductor ASA + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +LOG_MODULE_REGISTER(net_dhcpv4_server, CONFIG_NET_DHCPV4_SERVER_LOG_LEVEL); + +#include "dhcpv4.h" +#include "net_private.h" +#include "../../l2/ethernet/arp.h" + +#define DHCPV4_OPTIONS_MSG_TYPE_SIZE 3 +#define DHCPV4_OPTIONS_IP_LEASE_TIME_SIZE 6 +#define DHCPV4_OPTIONS_SERVER_ID_SIZE 6 +#define DHCPV4_OPTIONS_SUBNET_MASK_SIZE 6 +#define DHCPV4_OPTIONS_CLIENT_ID_MIN_SIZE 2 + +#define ADDRESS_RESERVED_TIMEOUT K_SECONDS(5) + +/* RFC 1497 [17] */ +static const uint8_t magic_cookie[4] = { 0x63, 0x82, 0x53, 0x63 }; + +struct dhcpv4_server_ctx { + struct net_if *iface; + int sock; + struct k_work_delayable timeout_work; + struct dhcpv4_addr_slot addr_pool[CONFIG_NET_DHCPV4_SERVER_ADDR_COUNT]; + struct in_addr server_addr; + struct in_addr netmask; +}; + +static struct dhcpv4_server_ctx server_ctx[CONFIG_NET_DHCPV4_SERVER_INSTANCES]; +static struct zsock_pollfd fds[CONFIG_NET_DHCPV4_SERVER_INSTANCES]; +static K_MUTEX_DEFINE(server_lock); + +#define DHCPV4_MAX_PARAMETERS_REQUEST_LEN 16 + +struct dhcpv4_parameter_request_list { + uint8_t list[DHCPV4_MAX_PARAMETERS_REQUEST_LEN]; + uint8_t count; +}; + +static void dhcpv4_server_timeout_recalc(struct dhcpv4_server_ctx *ctx) +{ + k_timepoint_t next = sys_timepoint_calc(K_FOREVER); + k_timeout_t timeout; + + for (int i = 0; i < ARRAY_SIZE(ctx->addr_pool); i++) { + struct dhcpv4_addr_slot *slot = &ctx->addr_pool[i]; + + if (slot->state == DHCPV4_SERVER_ADDR_RESERVED || + slot->state == DHCPV4_SERVER_ADDR_ALLOCATED) { + if (sys_timepoint_cmp(slot->expiry, next) < 0) { + next = slot->expiry; + } + } + } + + timeout = sys_timepoint_timeout(next); + + if (K_TIMEOUT_EQ(timeout, K_FOREVER)) { + LOG_DBG("No more addresses, canceling timer"); + k_work_cancel_delayable(&ctx->timeout_work); + } else { + k_work_reschedule(&ctx->timeout_work, timeout); + } +} + +/* Option parsing. */ + +static uint8_t *dhcpv4_find_option(uint8_t *data, size_t datalen, + uint8_t *optlen, uint8_t opt_code) +{ + uint8_t *opt = NULL; + + while (datalen > 0) { + uint8_t code; + uint8_t len; + + code = *data; + + /* Two special cases (fixed sized options) */ + if (code == 0) { + data++; + datalen--; + continue; + } + + if (code == DHCPV4_OPTIONS_END) { + break; + } + + /* Length field should now follow. */ + if (datalen < 2) { + break; + } + + len = *(data + 1); + + if (datalen < len + 2) { + break; + } + + if (code == opt_code) { + /* Found the option. */ + opt = data + 2; + *optlen = len; + break; + } + + data += len + 2; + datalen -= len + 2; + } + + return opt; +} + +static int dhcpv4_find_message_type_option(uint8_t *data, size_t datalen, + uint8_t *msgtype) +{ + uint8_t *opt; + uint8_t optlen; + + opt = dhcpv4_find_option(data, datalen, &optlen, + DHCPV4_OPTIONS_MSG_TYPE); + if (opt == NULL) { + return -ENOENT; + } + + if (optlen != 1) { + return -EINVAL; + } + + *msgtype = *opt; + + return 0; +} + +static int dhcpv4_find_server_id_option(uint8_t *data, size_t datalen, + struct in_addr *server_id) +{ + uint8_t *opt; + uint8_t optlen; + + opt = dhcpv4_find_option(data, datalen, &optlen, + DHCPV4_OPTIONS_SERVER_ID); + if (opt == NULL) { + return -ENOENT; + } + + if (optlen != sizeof(struct in_addr)) { + return -EINVAL; + } + + memcpy(server_id, opt, sizeof(struct in_addr)); + + return 0; +} + +static int dhcpv4_find_client_id_option(uint8_t *data, size_t datalen, + uint8_t *client_id, uint8_t *len) +{ + uint8_t *opt; + uint8_t optlen; + + opt = dhcpv4_find_option(data, datalen, &optlen, + DHCPV4_OPTIONS_CLIENT_ID); + if (opt == NULL) { + return -ENOENT; + } + + if (optlen < DHCPV4_OPTIONS_CLIENT_ID_MIN_SIZE) { + return -EINVAL; + } + + if (optlen > *len) { + LOG_ERR("Not enough memory for DHCPv4 client identifier."); + return -ENOMEM; + } + + memcpy(client_id, opt, optlen); + *len = optlen; + + return 0; +} + +static int dhcpv4_find_requested_ip_option(uint8_t *data, size_t datalen, + struct in_addr *requested_ip) +{ + uint8_t *opt; + uint8_t optlen; + + opt = dhcpv4_find_option(data, datalen, &optlen, + DHCPV4_OPTIONS_REQ_IPADDR); + if (opt == NULL) { + return -ENOENT; + } + + if (optlen != sizeof(struct in_addr)) { + return -EINVAL; + } + + memcpy(requested_ip, opt, sizeof(struct in_addr)); + + return 0; +} + +static int dhcpv4_find_ip_lease_time_option(uint8_t *data, size_t datalen, + uint32_t *lease_time) +{ + uint8_t *opt; + uint8_t optlen; + + opt = dhcpv4_find_option(data, datalen, &optlen, + DHCPV4_OPTIONS_LEASE_TIME); + if (opt == NULL) { + return -ENOENT; + } + + if (optlen != sizeof(uint32_t)) { + return -EINVAL; + } + + *lease_time = sys_get_be32(opt); + + return 0; +} + +static int dhcpv4_find_parameter_request_list_option( + uint8_t *data, size_t datalen, + struct dhcpv4_parameter_request_list *params) +{ + uint8_t *opt; + uint8_t optlen; + + opt = dhcpv4_find_option(data, datalen, &optlen, + DHCPV4_OPTIONS_REQ_LIST); + if (opt == NULL) { + return -ENOENT; + } + + if (optlen > sizeof(params->list)) { + /* Best effort here, copy as much as we can. */ + optlen = sizeof(params->list); + } + + memcpy(params->list, opt, optlen); + params->count = optlen; + + return 0; +} + +/* Option encoding. */ + +static uint8_t *dhcpv4_encode_magic_cookie(uint8_t *buf, size_t *buflen) +{ + if (buf == NULL || *buflen < SIZE_OF_MAGIC_COOKIE) { + return NULL; + } + + memcpy(buf, magic_cookie, SIZE_OF_MAGIC_COOKIE); + + *buflen -= SIZE_OF_MAGIC_COOKIE; + + return buf + SIZE_OF_MAGIC_COOKIE; +} + +static uint8_t *dhcpv4_encode_ip_lease_time_option(uint8_t *buf, size_t *buflen, + uint32_t lease_time) +{ + if (buf == NULL || *buflen < DHCPV4_OPTIONS_IP_LEASE_TIME_SIZE) { + return NULL; + } + + buf[0] = DHCPV4_OPTIONS_LEASE_TIME; + buf[1] = sizeof(lease_time); + sys_put_be32(lease_time, &buf[2]); + + *buflen -= DHCPV4_OPTIONS_IP_LEASE_TIME_SIZE; + + return buf + DHCPV4_OPTIONS_IP_LEASE_TIME_SIZE; +} + +static uint8_t *dhcpv4_encode_message_type_option(uint8_t *buf, size_t *buflen, + uint8_t msgtype) +{ + if (buf == NULL || *buflen < DHCPV4_OPTIONS_MSG_TYPE_SIZE) { + return NULL; + } + + buf[0] = DHCPV4_OPTIONS_MSG_TYPE; + buf[1] = 1; + buf[2] = msgtype; + + *buflen -= DHCPV4_OPTIONS_MSG_TYPE_SIZE; + + return buf + DHCPV4_OPTIONS_MSG_TYPE_SIZE; +} + +static uint8_t *dhcpv4_encode_server_id_option(uint8_t *buf, size_t *buflen, + struct in_addr *server_id) +{ + if (buf == NULL || *buflen < DHCPV4_OPTIONS_SERVER_ID_SIZE) { + return NULL; + } + + buf[0] = DHCPV4_OPTIONS_SERVER_ID; + buf[1] = sizeof(struct in_addr); + memcpy(&buf[2], server_id->s4_addr, sizeof(struct in_addr)); + + *buflen -= DHCPV4_OPTIONS_SERVER_ID_SIZE; + + return buf + DHCPV4_OPTIONS_SERVER_ID_SIZE; +} + +static uint8_t *dhcpv4_encode_subnet_mask_option(uint8_t *buf, size_t *buflen, + struct in_addr *mask) +{ + if (buf == NULL || *buflen < DHCPV4_OPTIONS_SUBNET_MASK_SIZE) { + return NULL; + } + + buf[0] = DHCPV4_OPTIONS_SUBNET_MASK; + buf[1] = sizeof(struct in_addr); + memcpy(&buf[2], mask->s4_addr, sizeof(struct in_addr)); + + *buflen -= DHCPV4_OPTIONS_SUBNET_MASK_SIZE; + + return buf + DHCPV4_OPTIONS_SUBNET_MASK_SIZE; +} + +static uint8_t *dhcpv4_encode_end_option(uint8_t *buf, size_t *buflen) +{ + if (buf == NULL || *buflen < 1) { + return NULL; + } + + buf[0] = DHCPV4_OPTIONS_END; + + *buflen -= 1; + + return buf + 1; +} + +/* Response handlers. */ + +static uint8_t *dhcpv4_encode_header(uint8_t *buf, size_t *buflen, + struct dhcp_msg *msg, + struct in_addr *yiaddr) +{ + struct dhcp_msg *reply_msg = (struct dhcp_msg *)buf; + + if (buf == NULL || *buflen < sizeof(struct dhcp_msg)) { + return NULL; + } + + reply_msg->op = DHCPV4_MSG_BOOT_REPLY; + reply_msg->htype = msg->htype; + reply_msg->hlen = msg->hlen; + reply_msg->hops = 0; + reply_msg->xid = msg->xid; + reply_msg->secs = 0; + reply_msg->flags = msg->flags; + memcpy(reply_msg->ciaddr, msg->ciaddr, sizeof(reply_msg->ciaddr)); + if (yiaddr != NULL) { + memcpy(reply_msg->yiaddr, yiaddr, sizeof(struct in_addr)); + } else { + memset(reply_msg->yiaddr, 0, sizeof(reply_msg->ciaddr)); + } + memset(reply_msg->siaddr, 0, sizeof(reply_msg->siaddr)); + memcpy(reply_msg->giaddr, msg->giaddr, sizeof(reply_msg->giaddr)); + memcpy(reply_msg->chaddr, msg->chaddr, sizeof(reply_msg->chaddr)); + + *buflen -= sizeof(struct dhcp_msg); + + return buf + sizeof(struct dhcp_msg); +} + +static uint8_t *dhcpv4_encode_string(uint8_t *buf, size_t *buflen, char *str, + size_t max_len) +{ + if (buf == NULL || *buflen < max_len) { + return NULL; + } + + memset(buf, 0, max_len); + + if (str == NULL) { + goto out; + } + + strncpy(buf, str, max_len - 1); + + out: + *buflen -= max_len; + + return buf + max_len; +} + +static uint8_t *dhcpv4_encode_sname(uint8_t *buf, size_t *buflen, char *sname) +{ + return dhcpv4_encode_string(buf, buflen, sname, SIZE_OF_SNAME); +} + +static uint8_t *dhcpv4_encode_file(uint8_t *buf, size_t *buflen, char *file) +{ + return dhcpv4_encode_string(buf, buflen, file, SIZE_OF_FILE); +} + +static uint8_t *dhcpv4_encode_requested_params( + uint8_t *buf, size_t *buflen, + struct dhcpv4_server_ctx *ctx, + struct dhcpv4_parameter_request_list *params) +{ + for (uint8_t i = 0; i < params->count; i++) { + switch (params->list[i]) { + case DHCPV4_OPTIONS_SUBNET_MASK: + buf = dhcpv4_encode_subnet_mask_option( + buf, buflen, &ctx->netmask); + if (buf == NULL) { + goto out; + } + break; + + /* Others - just ignore. */ + default: + break; + } + } + +out: + return buf; +} + +static int dhcpv4_send(struct dhcpv4_server_ctx *ctx, enum net_dhcpv4_msg_type type, + uint8_t *reply, size_t len, struct dhcp_msg *msg, + struct in_addr *yiaddr) +{ + struct sockaddr_in dst_addr = { + .sin_family = AF_INET, + .sin_port = htons(DHCPV4_CLIENT_PORT), + }; + struct in_addr giaddr; /* Relay agent address */ + struct in_addr ciaddr; /* Client address */ + int ret; + + memcpy(&giaddr, msg->giaddr, sizeof(giaddr)); + memcpy(&ciaddr, msg->ciaddr, sizeof(ciaddr)); + + /* Select destination address as described in ch. 4.1. */ + if (!net_ipv4_is_addr_unspecified(&giaddr)) { + /* If the 'giaddr' field in a DHCP message from a client is + * non-zero, the server sends any return messages to the + * 'DHCP server' port on the BOOTP relay agent whose address + * appears in 'giaddr'. + */ + dst_addr.sin_addr = giaddr; + dst_addr.sin_port = htons(DHCPV4_SERVER_PORT); + } else if (type == NET_DHCPV4_MSG_TYPE_NAK) { + /* In all cases, when 'giaddr' is zero, the server broadcasts + * any DHCPNAK messages to 0xffffffff. + */ + dst_addr.sin_addr = *net_ipv4_broadcast_address(); + } else if (!net_ipv4_is_addr_unspecified(&ciaddr)) { + /* If the 'giaddr' field is zero and the 'ciaddr' field is + * nonzero, then the server unicasts DHCPOFFER and DHCPACK + * messages to the address in 'ciaddr'. + */ + dst_addr.sin_addr = ciaddr; + } else if (ntohs(msg->flags) & DHCPV4_MSG_BROADCAST) { + /* If 'giaddr' is zero and 'ciaddr' is zero, and the broadcast + * bit is set, then the server broadcasts DHCPOFFER and DHCPACK + * messages to 0xffffffff. + */ + dst_addr.sin_addr = *net_ipv4_broadcast_address(); + } else if (yiaddr != NULL) { + /* If the broadcast bit is not set and 'giaddr' is zero and + * 'ciaddr' is zero, then the server unicasts DHCPOFFER and + * DHCPACK messages to the client's hardware address and 'yiaddr' + * address. + */ + struct net_eth_addr hwaddr; + + memcpy(&hwaddr, msg->chaddr, sizeof(hwaddr)); + net_arp_update(ctx->iface, yiaddr, &hwaddr, false, true); + dst_addr.sin_addr = *yiaddr; + } else { + NET_ERR("Unspecified destination address."); + return -EDESTADDRREQ; + } + + ret = zsock_sendto(ctx->sock, reply, len, 0, (struct sockaddr *)&dst_addr, + sizeof(dst_addr)); + if (ret < 0) { + return -errno; + } + + return 0; +} + +static int dhcpv4_send_offer(struct dhcpv4_server_ctx *ctx, struct dhcp_msg *msg, + struct in_addr *addr, uint32_t lease_time, + struct dhcpv4_parameter_request_list *params) +{ + uint8_t reply[NET_IPV4_MTU]; + uint8_t *buf = reply; + size_t buflen = sizeof(reply); + size_t reply_len = 0; + int ret; + + buf = dhcpv4_encode_header(buf, &buflen, msg, addr); + buf = dhcpv4_encode_sname(buf, &buflen, NULL); + buf = dhcpv4_encode_file(buf, &buflen, NULL); + buf = dhcpv4_encode_magic_cookie(buf, &buflen); + buf = dhcpv4_encode_ip_lease_time_option(buf, &buflen, lease_time); + buf = dhcpv4_encode_message_type_option(buf, &buflen, + NET_DHCPV4_MSG_TYPE_OFFER); + buf = dhcpv4_encode_server_id_option(buf, &buflen, &ctx->server_addr); + buf = dhcpv4_encode_requested_params(buf, &buflen, ctx, params); + buf = dhcpv4_encode_end_option(buf, &buflen); + + if (buf == NULL) { + LOG_ERR("Failed to encode %s message", "Offer"); + return -ENOMEM; + } + + reply_len = sizeof(reply) - buflen; + + ret = dhcpv4_send(ctx, NET_DHCPV4_MSG_TYPE_OFFER, reply, reply_len, + msg, addr); + if (ret < 0) { + LOG_ERR("Failed to send %s message, %d", "Offer", ret); + return ret; + } + + return 0; +} + +static int dhcpv4_send_ack(struct dhcpv4_server_ctx *ctx, struct dhcp_msg *msg, + struct in_addr *addr, uint32_t lease_time, + struct dhcpv4_parameter_request_list *params, + bool inform) +{ + uint8_t reply[NET_IPV4_MTU]; + uint8_t *buf = reply; + size_t buflen = sizeof(reply); + size_t reply_len = 0; + int ret; + + buf = dhcpv4_encode_header(buf, &buflen, msg, inform ? NULL : addr); + buf = dhcpv4_encode_sname(buf, &buflen, NULL); + buf = dhcpv4_encode_file(buf, &buflen, NULL); + buf = dhcpv4_encode_magic_cookie(buf, &buflen); + if (!inform) { + buf = dhcpv4_encode_ip_lease_time_option(buf, &buflen, lease_time); + } + buf = dhcpv4_encode_message_type_option(buf, &buflen, + NET_DHCPV4_MSG_TYPE_ACK); + buf = dhcpv4_encode_server_id_option(buf, &buflen, &ctx->server_addr); + buf = dhcpv4_encode_requested_params(buf, &buflen, ctx, params); + buf = dhcpv4_encode_end_option(buf, &buflen); + + if (buf == NULL) { + LOG_ERR("Failed to encode %s message", "ACK"); + return -ENOMEM; + } + + reply_len = sizeof(reply) - buflen; + + ret = dhcpv4_send(ctx, NET_DHCPV4_MSG_TYPE_ACK, reply, reply_len, msg, + addr); + if (ret < 0) { + LOG_ERR("Failed to send %s message, %d", "ACK", ret); + return ret; + } + + return 0; +} + +static int dhcpv4_send_nak(struct dhcpv4_server_ctx *ctx, struct dhcp_msg *msg) +{ + uint8_t reply[NET_IPV4_MTU]; + uint8_t *buf = reply; + size_t buflen = sizeof(reply); + size_t reply_len = 0; + int ret; + + buf = dhcpv4_encode_header(buf, &buflen, msg, NULL); + buf = dhcpv4_encode_sname(buf, &buflen, NULL); + buf = dhcpv4_encode_file(buf, &buflen, NULL); + buf = dhcpv4_encode_magic_cookie(buf, &buflen); + buf = dhcpv4_encode_message_type_option(buf, &buflen, + NET_DHCPV4_MSG_TYPE_NAK); + buf = dhcpv4_encode_server_id_option(buf, &buflen, &ctx->server_addr); + buf = dhcpv4_encode_end_option(buf, &buflen); + + if (buf == NULL) { + LOG_ERR("Failed to encode %s message", "NAK"); + return -ENOMEM; + } + + reply_len = sizeof(reply) - buflen; + + ret = dhcpv4_send(ctx, NET_DHCPV4_MSG_TYPE_NAK, reply, reply_len, msg, + NULL); + if (ret < 0) { + LOG_ERR("Failed to send %s message, %d", "NAK", ret); + return ret; + } + + return 0; +} + +/* Message handlers. */ + +static int dhcpv4_get_client_id(struct dhcp_msg *msg, uint8_t *options, + uint8_t optlen, struct dhcpv4_client_id *client_id) +{ + int ret; + + client_id->len = sizeof(client_id->buf); + + ret = dhcpv4_find_client_id_option(options, optlen, client_id->buf, + &client_id->len); + if (ret == 0) { + return 0; + } + + /* No Client Id option or too long to use, fallback to hardware address. */ + if (msg->hlen > sizeof(msg->chaddr)) { + LOG_ERR("Malformed chaddr length."); + return -EINVAL; + } + + client_id->buf[0] = msg->htype; + client_id->buf[1] = msg->hlen; + memcpy(client_id->buf + 2, msg->chaddr, msg->hlen); + client_id->len = msg->hlen + 2; + + return 0; +} + +static uint32_t dhcpv4_get_lease_time(uint8_t *options, uint8_t optlen) +{ + uint32_t lease_time; + + if (dhcpv4_find_ip_lease_time_option(options, optlen, + &lease_time) == 0) { + return lease_time; + } + + return CONFIG_NET_DHCPV4_SERVER_ADDR_LEASE_TIME; +} + +static void dhcpv4_handle_discover(struct dhcpv4_server_ctx *ctx, + struct dhcp_msg *msg, uint8_t *options, + uint8_t optlen) +{ + struct dhcpv4_parameter_request_list params = { 0 }; + struct dhcpv4_addr_slot *selected = NULL; + struct dhcpv4_client_id client_id; + int ret; + + ret = dhcpv4_get_client_id(msg, options, optlen, &client_id); + if (ret < 0) { + return; + } + + (void)dhcpv4_find_parameter_request_list_option(options, optlen, ¶ms); + + /* Address pool and address selection algorithm as + * described in 4.3.1 + */ + + /* 1. Check for current bindings */ + for (int i = 0; i < ARRAY_SIZE(ctx->addr_pool); i++) { + struct dhcpv4_addr_slot *slot = &ctx->addr_pool[i]; + + if ((slot->state == DHCPV4_SERVER_ADDR_RESERVED || + slot->state == DHCPV4_SERVER_ADDR_ALLOCATED) && + slot->client_id.len == client_id.len && + memcmp(slot->client_id.buf, client_id.buf, + client_id.len) == 0) { + /* Got match in current bindings. */ + selected = slot; + break; + } + } + + /* 2. Skipped, for now expired/released entries are forgotten. */ + + /* 3. Check Requested IP Address option. */ + if (selected == NULL) { + struct in_addr requested_ip; + + ret = dhcpv4_find_requested_ip_option(options, optlen, + &requested_ip); + if (ret == 0) { + for (int i = 0; i < ARRAY_SIZE(ctx->addr_pool); i++) { + struct dhcpv4_addr_slot *slot = + &ctx->addr_pool[i]; + + if (net_ipv4_addr_cmp(&slot->addr, + &requested_ip) && + slot->state == DHCPV4_SERVER_ADDR_FREE) { + /* Requested address is free. */ + selected = slot; + break; + } + } + } + } + + /* 4. Allocate new address from pool, if available. */ + if (selected == NULL) { + struct in_addr giaddr; + + memcpy(&giaddr, msg->giaddr, sizeof(giaddr)); + if (!net_ipv4_is_addr_unspecified(&giaddr)) { + /* Only addresses in local subnet supproted for now. */ + return; + } + + for (int i = 0; i < ARRAY_SIZE(ctx->addr_pool); i++) { + struct dhcpv4_addr_slot *slot = &ctx->addr_pool[i]; + + if (slot->state == DHCPV4_SERVER_ADDR_FREE) { + /* Requested address is free. */ + selected = slot; + break; + } + } + } + + if (selected == NULL) { + LOG_ERR("No free address found in address pool"); + } else { + uint32_t lease_time = dhcpv4_get_lease_time(options, optlen); + + if (dhcpv4_send_offer(ctx, msg, &selected->addr, lease_time, + ¶ms) < 0) { + return; + } + + LOG_DBG("DHCPv4 processing Discover - reserved %s", + net_sprint_ipv4_addr(&selected->addr)); + + selected->state = DHCPV4_SERVER_ADDR_RESERVED; + selected->client_id.len = client_id.len; + memcpy(selected->client_id.buf, client_id.buf, client_id.len); + selected->lease_time = lease_time; + selected->expiry = sys_timepoint_calc(ADDRESS_RESERVED_TIMEOUT); + dhcpv4_server_timeout_recalc(ctx); + } +} + +static void dhcpv4_handle_request(struct dhcpv4_server_ctx *ctx, + struct dhcp_msg *msg, uint8_t *options, + uint8_t optlen) +{ + struct dhcpv4_parameter_request_list params = { 0 }; + struct dhcpv4_addr_slot *selected = NULL; + struct dhcpv4_client_id client_id; + struct in_addr requested_ip, server_id, ciaddr, giaddr; + int ret; + + memcpy(&ciaddr, msg->ciaddr, sizeof(ciaddr)); + memcpy(&giaddr, msg->giaddr, sizeof(giaddr)); + + if (!net_ipv4_is_addr_unspecified(&giaddr)) { + /* Only addresses in local subnet supported for now. */ + return; + } + + ret = dhcpv4_get_client_id(msg, options, optlen, &client_id); + if (ret < 0) { + /* Failed to obtain Client ID, ignore. */ + return; + } + + (void)dhcpv4_find_parameter_request_list_option(options, optlen, ¶ms); + + ret = dhcpv4_find_server_id_option(options, optlen, &server_id); + if (ret == 0) { + /* Server ID present, Request generated during SELECTING. */ + if (!net_ipv4_addr_cmp(&ctx->server_addr, &server_id)) { + /* Not for us, ignore. */ + return; + } + + ret = dhcpv4_find_requested_ip_option(options, optlen, + &requested_ip); + if (ret < 0) { + /* Requested IP missing, ignore. */ + return; + } + + if (!net_ipv4_is_addr_unspecified(&ciaddr)) { + /* ciaddr MUST be zero */ + return; + } + + for (int i = 0; i < ARRAY_SIZE(ctx->addr_pool); i++) { + struct dhcpv4_addr_slot *slot = &ctx->addr_pool[i]; + + if (net_ipv4_addr_cmp(&slot->addr, &requested_ip) && + slot->client_id.len == client_id.len && + memcmp(slot->client_id.buf, client_id.buf, + client_id.len) == 0 && + slot->state == DHCPV4_SERVER_ADDR_RESERVED) { + selected = slot; + break; + } + } + + if (selected == NULL) { + LOG_ERR("No valid slot found for DHCPv4 Request"); + } else { + uint32_t lease_time = dhcpv4_get_lease_time(options, optlen); + + if (dhcpv4_send_ack(ctx, msg, &selected->addr, lease_time, + ¶ms, false) < 0) { + return; + } + + LOG_DBG("DHCPv4 processing Request - allocated %s", + net_sprint_ipv4_addr(&selected->addr)); + + selected->lease_time = lease_time; + selected->expiry = sys_timepoint_calc( + K_SECONDS(lease_time)); + selected->state = DHCPV4_SERVER_ADDR_ALLOCATED; + dhcpv4_server_timeout_recalc(ctx); + } + + return; + } + + /* No server ID option - check requested address. */ + ret = dhcpv4_find_requested_ip_option(options, optlen, &requested_ip); + if (ret == 0) { + /* Requested IP present, Request generated during INIT-REBOOT. */ + if (!net_ipv4_is_addr_unspecified(&ciaddr)) { + /* ciaddr MUST be zero */ + return; + } + + if (!net_if_ipv4_addr_mask_cmp(ctx->iface, &requested_ip)) { + /* Wrong subnet. */ + dhcpv4_send_nak(ctx, msg); + } + + for (int i = 0; i < ARRAY_SIZE(ctx->addr_pool); i++) { + struct dhcpv4_addr_slot *slot = &ctx->addr_pool[i]; + + if (slot->client_id.len == client_id.len && + memcmp(slot->client_id.buf, client_id.buf, + client_id.len) == 0 && + (slot->state == DHCPV4_SERVER_ADDR_RESERVED || + slot->state == DHCPV4_SERVER_ADDR_ALLOCATED)) { + selected = slot; + break; + } + } + + if (selected != NULL) { + if (net_ipv4_addr_cmp(&selected->addr, &requested_ip)) { + uint32_t lease_time = dhcpv4_get_lease_time( + options, optlen); + + if (dhcpv4_send_ack(ctx, msg, &selected->addr, + lease_time, ¶ms, + false) < 0) { + return; + } + + selected->lease_time = lease_time; + selected->expiry = sys_timepoint_calc( + K_SECONDS(lease_time)); + dhcpv4_server_timeout_recalc(ctx); + } else { + dhcpv4_send_nak(ctx, msg); + } + } + + /* No notion of the client, remain silent. */ + return; + } + + /* Neither server ID or requested IP set, Request generated during + * RENEWING or REBINDING. + */ + + if (!net_if_ipv4_addr_mask_cmp(ctx->iface, &ciaddr)) { + /* Wrong subnet. */ + dhcpv4_send_nak(ctx, msg); + } + + for (int i = 0; i < ARRAY_SIZE(ctx->addr_pool); i++) { + struct dhcpv4_addr_slot *slot = &ctx->addr_pool[i]; + + if (net_ipv4_addr_cmp(&slot->addr, &ciaddr)) { + selected = slot; + break; + } + } + + if (selected != NULL) { + if (selected->state == DHCPV4_SERVER_ADDR_ALLOCATED && + selected->client_id.len == client_id.len && + memcmp(selected->client_id.buf, client_id.buf, + client_id.len) == 0) { + uint32_t lease_time = dhcpv4_get_lease_time( + options, optlen); + + if (dhcpv4_send_ack(ctx, msg, &ciaddr, lease_time, + ¶ms, false) < 0) { + return; + } + + selected->lease_time = lease_time; + selected->expiry = sys_timepoint_calc( + K_SECONDS(lease_time)); + dhcpv4_server_timeout_recalc(ctx); + } else { + dhcpv4_send_nak(ctx, msg); + } + } +} + +static void dhcpv4_handle_decline(struct dhcpv4_server_ctx *ctx, + struct dhcp_msg *msg, uint8_t *options, + uint8_t optlen) +{ + struct dhcpv4_client_id client_id; + struct in_addr requested_ip, server_id; + int ret; + + ret = dhcpv4_find_server_id_option(options, optlen, &server_id); + if (ret < 0) { + /* No server ID, ignore. */ + return; + } + + if (!net_ipv4_addr_cmp(&ctx->server_addr, &server_id)) { + /* Not for us, ignore. */ + return; + } + + ret = dhcpv4_get_client_id(msg, options, optlen, &client_id); + if (ret < 0) { + /* Failed to obtain Client ID, ignore. */ + return; + } + + ret = dhcpv4_find_requested_ip_option(options, optlen, + &requested_ip); + if (ret < 0) { + /* Requested IP missing, ignore. */ + return; + } + + LOG_ERR("Received DHCPv4 Decline for %s (address already in use)", + net_sprint_ipv4_addr(&requested_ip)); + + for (int i = 0; i < ARRAY_SIZE(ctx->addr_pool); i++) { + struct dhcpv4_addr_slot *slot = &ctx->addr_pool[i]; + + if (net_ipv4_addr_cmp(&slot->addr, &requested_ip) && + slot->client_id.len == client_id.len && + memcmp(slot->client_id.buf, client_id.buf, + client_id.len) == 0 && + (slot->state == DHCPV4_SERVER_ADDR_RESERVED || + slot->state == DHCPV4_SERVER_ADDR_ALLOCATED)) { + slot->state = DHCPV4_SERVER_ADDR_DECLINED; + slot->expiry = sys_timepoint_calc(K_FOREVER); + dhcpv4_server_timeout_recalc(ctx); + break; + } + } +} + +static void dhcpv4_handle_release(struct dhcpv4_server_ctx *ctx, + struct dhcp_msg *msg, uint8_t *options, + uint8_t optlen) +{ + struct dhcpv4_client_id client_id; + struct in_addr ciaddr, server_id; + int ret; + + ret = dhcpv4_find_server_id_option(options, optlen, &server_id); + if (ret < 0) { + /* No server ID, ignore. */ + return; + } + + if (!net_ipv4_addr_cmp(&ctx->server_addr, &server_id)) { + /* Not for us, ignore. */ + return; + } + + ret = dhcpv4_get_client_id(msg, options, optlen, &client_id); + if (ret < 0) { + /* Failed to obtain Client ID, ignore. */ + return; + } + + memcpy(&ciaddr, msg->ciaddr, sizeof(ciaddr)); + + for (int i = 0; i < ARRAY_SIZE(ctx->addr_pool); i++) { + struct dhcpv4_addr_slot *slot = &ctx->addr_pool[i]; + + if (net_ipv4_addr_cmp(&slot->addr, &ciaddr) && + slot->client_id.len == client_id.len && + memcmp(slot->client_id.buf, client_id.buf, + client_id.len) == 0 && + (slot->state == DHCPV4_SERVER_ADDR_RESERVED || + slot->state == DHCPV4_SERVER_ADDR_ALLOCATED)) { + LOG_DBG("DHCPv4 processing Release - %s", + net_sprint_ipv4_addr(&slot->addr)); + + slot->state = DHCPV4_SERVER_ADDR_FREE; + slot->expiry = sys_timepoint_calc(K_FOREVER); + dhcpv4_server_timeout_recalc(ctx); + break; + } + } +} + +static void dhcpv4_handle_inform(struct dhcpv4_server_ctx *ctx, + struct dhcp_msg *msg, uint8_t *options, + uint8_t optlen) +{ + struct dhcpv4_parameter_request_list params = { 0 }; + + (void)dhcpv4_find_parameter_request_list_option(options, optlen, ¶ms); + (void)dhcpv4_send_ack(ctx, msg, (struct in_addr *)msg->ciaddr, 0, + ¶ms, true); +} + +/* Server core. */ + +static void dhcpv4_server_timeout(struct k_work *work) +{ + struct k_work_delayable *dwork = k_work_delayable_from_work(work); + struct dhcpv4_server_ctx *ctx = + CONTAINER_OF(dwork, struct dhcpv4_server_ctx, timeout_work); + + + k_mutex_lock(&server_lock, K_FOREVER); + + for (int i = 0; i < ARRAY_SIZE(ctx->addr_pool); i++) { + struct dhcpv4_addr_slot *slot = &ctx->addr_pool[i]; + + if (slot->state == DHCPV4_SERVER_ADDR_RESERVED || + slot->state == DHCPV4_SERVER_ADDR_ALLOCATED) { + if (sys_timepoint_expired(slot->expiry)) { + LOG_DBG("Address %s expired", + net_sprint_ipv4_addr(&slot->addr)); + slot->state = DHCPV4_SERVER_ADDR_FREE; + } + } + } + + dhcpv4_server_timeout_recalc(ctx); + + k_mutex_unlock(&server_lock); +} + +static void dhcpv4_process_data(struct dhcpv4_server_ctx *ctx, uint8_t *data, + size_t datalen) +{ + struct dhcp_msg *msg; + uint8_t msgtype; + int ret; + + if (datalen < sizeof(struct dhcp_msg)) { + LOG_DBG("DHCPv4 server malformed message"); + return; + } + + msg = (struct dhcp_msg *)data; + + if (msg->op != DHCPV4_MSG_BOOT_REQUEST) { + /* Silently drop messages other than BOOTREQUEST */ + return; + } + + data += sizeof(struct dhcp_msg); + datalen -= sizeof(struct dhcp_msg); + + /* Skip server hostname/filename/option cookie */ + if (datalen < (SIZE_OF_SNAME + SIZE_OF_FILE + SIZE_OF_MAGIC_COOKIE)) { + return; + } + + data += SIZE_OF_SNAME + SIZE_OF_FILE + SIZE_OF_MAGIC_COOKIE; + datalen -= SIZE_OF_SNAME + SIZE_OF_FILE + SIZE_OF_MAGIC_COOKIE; + + /* Search options for DHCP message type. */ + ret = dhcpv4_find_message_type_option(data, datalen, &msgtype); + if (ret < 0) { + LOG_ERR("No message type option"); + return; + } + + k_mutex_lock(&server_lock, K_FOREVER); + + switch (msgtype) { + case NET_DHCPV4_MSG_TYPE_DISCOVER: + dhcpv4_handle_discover(ctx, msg, data, datalen); + break; + case NET_DHCPV4_MSG_TYPE_REQUEST: + dhcpv4_handle_request(ctx, msg, data, datalen); + break; + case NET_DHCPV4_MSG_TYPE_DECLINE: + dhcpv4_handle_decline(ctx, msg, data, datalen); + break; + case NET_DHCPV4_MSG_TYPE_RELEASE: + dhcpv4_handle_release(ctx, msg, data, datalen); + break; + case NET_DHCPV4_MSG_TYPE_INFORM: + dhcpv4_handle_inform(ctx, msg, data, datalen); + break; + + case NET_DHCPV4_MSG_TYPE_OFFER: + case NET_DHCPV4_MSG_TYPE_ACK: + case NET_DHCPV4_MSG_TYPE_NAK: + default: + /* Ignore server initiated and unknown message types. */ + break; + } + + k_mutex_unlock(&server_lock); +} + +static void dhcpv4_server_cb(struct k_work *work) +{ + struct net_socket_service_event *evt = + CONTAINER_OF(work, struct net_socket_service_event, work); + struct dhcpv4_server_ctx *ctx = NULL; + uint8_t recv_buf[NET_IPV4_MTU]; + int ret; + + for (int i = 0; i < ARRAY_SIZE(server_ctx); i++) { + if (server_ctx[i].sock == evt->event.fd) { + ctx = &server_ctx[i]; + break; + } + } + + if (ctx == NULL) { + LOG_ERR("No DHCPv4 server context found for given FD."); + return; + } + + if (evt->event.revents & ZSOCK_POLLERR) { + LOG_ERR("DHCPv4 server poll revents error"); + net_dhcpv4_server_stop(ctx->iface); + return; + } + + if (!(evt->event.revents & ZSOCK_POLLIN)) { + return; + } + + ret = zsock_recvfrom(evt->event.fd, recv_buf, sizeof(recv_buf), + ZSOCK_MSG_DONTWAIT, NULL, 0); + if (ret < 0) { + if (errno == EAGAIN) { + return; + } + + LOG_ERR("DHCPv4 server recv error, %d", errno); + net_dhcpv4_server_stop(ctx->iface); + return; + } + + dhcpv4_process_data(ctx, recv_buf, ret); +} + +NET_SOCKET_SERVICE_SYNC_DEFINE_STATIC(dhcpv4_server, NULL, dhcpv4_server_cb, + CONFIG_NET_DHCPV4_SERVER_INSTANCES); + +int net_dhcpv4_server_start(struct net_if *iface, struct in_addr *base_addr) +{ + struct sockaddr_in addr = { + .sin_family = AF_INET, + .sin_addr = INADDR_ANY_INIT, + .sin_port = htons(DHCPV4_SERVER_PORT), + }; + struct ifreq ifreq = { 0 }; + int ret, sock = -1, slot = -1; + const struct in_addr *server_addr; + struct in_addr netmask; + + if (iface == NULL || base_addr == NULL) { + return -EINVAL; + } + + if (!net_if_ipv4_addr_mask_cmp(iface, base_addr)) { + LOG_ERR("Address pool does not belong to the interface subnet."); + return -EINVAL; + } + + server_addr = net_if_ipv4_select_src_addr(iface, base_addr); + if (server_addr == NULL) { + LOG_ERR("Failed to obtain a valid server address."); + return -EINVAL; + } + + netmask = net_if_ipv4_get_netmask(iface); + if (net_ipv4_is_addr_unspecified(&netmask)) { + LOG_ERR("Failed to obtain subnet mask."); + return -EINVAL; + } + + k_mutex_lock(&server_lock, K_FOREVER); + + for (int i = 0; i < ARRAY_SIZE(server_ctx); i++) { + if (server_ctx[i].iface != NULL) { + if (server_ctx[i].iface == iface) { + LOG_ERR("DHCPv4 server instance already running."); + ret = -EALREADY; + goto error; + } + } else { + if (slot < 0) { + slot = i; + } + } + } + + if (slot < 0) { + LOG_ERR("No free DHCPv4 server intance."); + ret = -ENOMEM; + goto error; + } + + ret = net_if_get_name(iface, ifreq.ifr_name, sizeof(ifreq.ifr_name)); + if (ret < 0) { + LOG_ERR("Failed to obtain interface name."); + goto error; + } + + sock = zsock_socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP); + if (sock < 0) { + ret = errno; + LOG_ERR("Failed to create DHCPv4 server socket, %d", ret); + goto error; + } + + ret = zsock_setsockopt(sock, SOL_SOCKET, SO_BINDTODEVICE, &ifreq, + sizeof(ifreq)); + if (ret < 0) { + ret = errno; + LOG_ERR("Failed to bind DHCPv4 server socket with interface, %d", + ret); + goto error; + } + + ret = zsock_bind(sock, (struct sockaddr *)&addr, sizeof(addr)); + if (ret < 0) { + ret = errno; + LOG_ERR("Failed to bind DHCPv4 server socket, %d", ret); + goto error; + } + + fds[slot].fd = sock; + fds[slot].events = ZSOCK_POLLIN; + + server_ctx[slot].iface = iface; + server_ctx[slot].sock = sock; + server_ctx[slot].server_addr = *server_addr; + server_ctx[slot].netmask = netmask; + + k_work_init_delayable(&server_ctx[slot].timeout_work, + dhcpv4_server_timeout); + + LOG_DBG("Started DHCPv4 server, address pool:"); + for (int i = 0; i < ARRAY_SIZE(server_ctx[slot].addr_pool); i++) { + server_ctx[slot].addr_pool[i].state = DHCPV4_SERVER_ADDR_FREE; + server_ctx[slot].addr_pool[i].addr.s_addr = + htonl(ntohl(base_addr->s_addr) + i); + + LOG_DBG("\t%2d: %s", i, + net_sprint_ipv4_addr( + &server_ctx[slot].addr_pool[i].addr)); + } + + ret = net_socket_service_register(&dhcpv4_server, fds, ARRAY_SIZE(fds), + NULL); + if (ret < 0) { + LOG_ERR("Failed to register socket service, %d", ret); + memset(&server_ctx[slot], 0, sizeof(server_ctx[slot])); + fds[slot].fd = -1; + goto error; + } + + k_mutex_unlock(&server_lock); + + return 0; + +error: + if (sock >= 0) { + (void)zsock_close(sock); + } + + k_mutex_unlock(&server_lock); + + return ret; +} + +int net_dhcpv4_server_stop(struct net_if *iface) +{ + struct k_work_sync sync; + int slot = -1; + int ret = 0; + bool service_stop = true; + + if (iface == NULL) { + return -EINVAL; + } + + k_mutex_lock(&server_lock, K_FOREVER); + + for (int i = 0; i < ARRAY_SIZE(server_ctx); i++) { + if (server_ctx[i].iface == iface) { + slot = i; + break; + } + } + + if (slot < 0) { + ret = -ENOENT; + goto out; + } + + fds[slot].fd = -1; + (void)zsock_close(server_ctx[slot].sock); + + k_work_cancel_delayable_sync(&server_ctx[slot].timeout_work, &sync); + + memset(&server_ctx[slot], 0, sizeof(server_ctx[slot])); + + for (int i = 0; i < ARRAY_SIZE(fds); i++) { + if (fds[i].fd >= 0) { + service_stop = false; + break; + } + } + + if (service_stop) { + ret = net_socket_service_unregister(&dhcpv4_server); + } else { + ret = net_socket_service_register(&dhcpv4_server, fds, + ARRAY_SIZE(fds), NULL); + } + +out: + k_mutex_unlock(&server_lock); + + return ret; +} + +static void dhcpv4_server_foreach_lease_on_ctx(struct dhcpv4_server_ctx *ctx, + net_dhcpv4_lease_cb_t cb, + void *user_data) +{ + for (int i = 0; i < ARRAY_SIZE(ctx->addr_pool); i++) { + struct dhcpv4_addr_slot *addr = &ctx->addr_pool[i]; + + if (addr->state != DHCPV4_SERVER_ADDR_FREE) { + cb(ctx->iface, addr, user_data); + } + } +} + +int net_dhcpv4_server_foreach_lease(struct net_if *iface, + net_dhcpv4_lease_cb_t cb, + void *user_data) +{ + int slot = -1; + int ret = 0; + + k_mutex_lock(&server_lock, K_FOREVER); + + if (iface == NULL) { + for (int i = 0; i < ARRAY_SIZE(server_ctx); i++) { + if (server_ctx[i].iface != NULL) { + dhcpv4_server_foreach_lease_on_ctx( + &server_ctx[i], cb, user_data); + } + } + + return 0; + } + + for (int i = 0; i < ARRAY_SIZE(server_ctx); i++) { + if (server_ctx[i].iface == iface) { + slot = i; + break; + } + } + + if (slot < 0) { + ret = -ENOENT; + goto out; + } + + dhcpv4_server_foreach_lease_on_ctx(&server_ctx[slot], cb, user_data); + +out: + k_mutex_unlock(&server_lock); + + return ret; +} + +void net_dhcpv4_server_init(void) +{ + for (int i = 0; i < ARRAY_SIZE(fds); i++) { + fds[i].fd = -1; + } +} From 3bc50871bccb7a4ff9c03c845ac9a4a2208a0d12 Mon Sep 17 00:00:00 2001 From: Robert Lubos Date: Tue, 16 Jan 2024 17:38:40 +0100 Subject: [PATCH 2539/3723] net: socket_services: Increase default stack size for DHCPv4 server Increase socket services thread default stack size when DHCPv4 server is enabled, as it uses synchronous processing. Signed-off-by: Robert Lubos --- subsys/net/lib/sockets/Kconfig | 1 + 1 file changed, 1 insertion(+) diff --git a/subsys/net/lib/sockets/Kconfig b/subsys/net/lib/sockets/Kconfig index fbf74114d82..4d6c091b749 100644 --- a/subsys/net/lib/sockets/Kconfig +++ b/subsys/net/lib/sockets/Kconfig @@ -109,6 +109,7 @@ config NET_SOCKETS_SERVICE_THREAD_PRIO config NET_SOCKETS_SERVICE_STACK_SIZE int "Stack size for the thread handling socket services" + default 2400 if NET_DHCPV4_SERVER default 1200 depends on NET_SOCKETS_SERVICE help From 2c70c5d74adb250420506d8a7f2aa40631a24916 Mon Sep 17 00:00:00 2001 From: Robert Lubos Date: Tue, 16 Jan 2024 17:38:23 +0100 Subject: [PATCH 2540/3723] net: shell: Implement DHCPv4 server shell commands Implement DHCPv4 shell module, which allows to start/stop DHCPv4 server operation, and print server status (address leases). Signed-off-by: Robert Lubos --- subsys/net/lib/shell/CMakeLists.txt | 1 + subsys/net/lib/shell/dhcpv4.c | 215 ++++++++++++++++++++++++++++ 2 files changed, 216 insertions(+) create mode 100644 subsys/net/lib/shell/dhcpv4.c diff --git a/subsys/net/lib/shell/CMakeLists.txt b/subsys/net/lib/shell/CMakeLists.txt index 2c5c0757505..5cfb5c269b4 100644 --- a/subsys/net/lib/shell/CMakeLists.txt +++ b/subsys/net/lib/shell/CMakeLists.txt @@ -10,6 +10,7 @@ zephyr_library_sources(allocs.c) zephyr_library_sources(arp.c) zephyr_library_sources(capture.c) zephyr_library_sources(conn.c) +zephyr_library_sources(dhcpv4.c) zephyr_library_sources(dns.c) zephyr_library_sources(events.c) zephyr_library_sources(gptp.c) diff --git a/subsys/net/lib/shell/dhcpv4.c b/subsys/net/lib/shell/dhcpv4.c new file mode 100644 index 00000000000..a59b9c45edb --- /dev/null +++ b/subsys/net/lib/shell/dhcpv4.c @@ -0,0 +1,215 @@ +/* + * Copyright (c) 2024 Nordic Semiconductor ASA + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include +LOG_MODULE_DECLARE(net_shell); + +#include +#include +#include + +#include "net_shell_private.h" + +static int cmd_net_dhcpv4_server_start(const struct shell *sh, size_t argc, char *argv[]) +{ +#if defined(CONFIG_NET_DHCPV4_SERVER) + struct net_if *iface = NULL; + struct in_addr base_addr; + int idx, ret; + + idx = get_iface_idx(sh, argv[1]); + if (idx < 0) { + return -ENOEXEC; + } + + iface = net_if_get_by_index(idx); + if (!iface) { + PR_WARNING("No such interface in index %d\n", idx); + return -ENOEXEC; + } + + if (net_addr_pton(AF_INET, argv[2], &base_addr)) { + PR_ERROR("Invalid address: %s\n", argv[2]); + return -EINVAL; + } + + ret = net_dhcpv4_server_start(iface, &base_addr); + if (ret == -EALREADY) { + PR_WARNING("DHCPv4 server already running on interface %d\n", idx); + } else if (ret < 0) { + PR_ERROR("DHCPv4 server failed to start on interface %d, error %d\n", + idx, -ret); + } else { + PR("DHCPv4 server started on interface %d\n", idx); + } +#else /* CONFIG_NET_DHCPV4_SERVER */ + PR_INFO("Set %s to enable %s support.\n", + "CONFIG_NET_DHCPV4_SERVER", "DHCPv4 server"); +#endif /* CONFIG_NET_DHCPV4_SERVER */ + return 0; +} + +static int cmd_net_dhcpv4_server_stop(const struct shell *sh, size_t argc, char *argv[]) +{ +#if defined(CONFIG_NET_DHCPV4_SERVER) + struct net_if *iface = NULL; + int idx, ret; + + idx = get_iface_idx(sh, argv[1]); + if (idx < 0) { + return -ENOEXEC; + } + + iface = net_if_get_by_index(idx); + if (!iface) { + PR_WARNING("No such interface in index %d\n", idx); + return -ENOEXEC; + } + + ret = net_dhcpv4_server_stop(iface); + if (ret == -ENOENT) { + PR_WARNING("DHCPv4 server is not running on interface %d\n", idx); + } else if (ret < 0) { + PR_ERROR("DHCPv4 server failed to stop on interface %d, error %d\n", + idx, -ret); + } else { + PR("DHCPv4 server stopped on interface %d\n", idx); + } +#else /* CONFIG_NET_DHCPV4_SERVER */ + PR_INFO("Set %s to enable %s support.\n", + "CONFIG_NET_DHCPV4_SERVER", "DHCPv4 server"); +#endif /* CONFIG_NET_DHCPV4_SERVER */ + return 0; +} + +#if defined(CONFIG_NET_DHCPV4_SERVER) +static const char *dhcpv4_addr_state_to_str(enum dhcpv4_server_addr_state state) +{ + switch (state) { + case DHCPV4_SERVER_ADDR_FREE: + return "FREE"; + case DHCPV4_SERVER_ADDR_RESERVED: + return "RESERVED"; + case DHCPV4_SERVER_ADDR_ALLOCATED: + return "ALLOCATED"; + case DHCPV4_SERVER_ADDR_DECLINED: + return "DECLINED"; + } + + return ""; +} + +static uint32_t timepoint_to_s(k_timepoint_t timepoint) +{ + k_timeout_t timeout = sys_timepoint_timeout(timepoint); + + if (K_TIMEOUT_EQ(timeout, K_NO_WAIT)) { + return 0; + } + + if (K_TIMEOUT_EQ(timeout, K_FOREVER)) { + return UINT32_MAX; + } + + return k_ticks_to_ms_floor64(timeout.ticks) / 1000; +} + +static void dhcpv4_lease_cb(struct net_if *iface, + struct dhcpv4_addr_slot *lease, + void *user_data) +{ + struct net_shell_user_data *data = user_data; + const struct shell *sh = data->sh; + int *count = data->user_data; + char expiry_str[] = "4294967295"; /* Lease time is uint32_t, so take + * theoretical max. + */ + char iface_name[IFNAMSIZ] = ""; + + if (*count == 0) { + PR(" Iface Address\t State\tExpiry (sec)\n"); + } + + (*count)++; + + (void)net_if_get_name(iface, iface_name, sizeof(iface_name)); + + if (lease->state == DHCPV4_SERVER_ADDR_DECLINED) { + snprintk(expiry_str, sizeof(expiry_str) - 1, "infinite"); + } else { + snprintk(expiry_str, sizeof(expiry_str) - 1, "%u", + timepoint_to_s(lease->expiry)); + } + + PR("%2d. %6s %15s\t%9s\t%12s\n", + *count, iface_name, net_sprint_ipv4_addr(&lease->addr), + dhcpv4_addr_state_to_str(lease->state), expiry_str); +} +#endif /* CONFIG_NET_DHCPV4_SERVER */ + +static int cmd_net_dhcpv4_server_status(const struct shell *sh, size_t argc, char *argv[]) +{ +#if defined(CONFIG_NET_DHCPV4_SERVER) + struct net_shell_user_data user_data; + struct net_if *iface = NULL; + int idx = 0, ret; + int count = 0; + + if (argc > 1) { + idx = get_iface_idx(sh, argv[1]); + if (idx < 0) { + return -ENOEXEC; + } + + iface = net_if_get_by_index(idx); + if (!iface) { + PR_WARNING("No such interface in index %d\n", idx); + return -ENOEXEC; + } + } + + user_data.sh = sh; + user_data.user_data = &count; + + ret = net_dhcpv4_server_foreach_lease(iface, dhcpv4_lease_cb, &user_data); + if (ret == -ENOENT) { + PR_WARNING("DHCPv4 server is not running on interface %d\n", idx); + } else if (count == 0) { + PR("DHCPv4 server - no addresses assigned\n"); + } +#else /* CONFIG_NET_DHCPV4_SERVER */ + PR_INFO("Set %s to enable %s support.\n", + "CONFIG_NET_DHCPV4_SERVER", "DHCPv4 server"); +#endif /* CONFIG_NET_DHCPV4_SERVER */ + return 0; +} + +SHELL_STATIC_SUBCMD_SET_CREATE(net_cmd_dhcpv4_server, + SHELL_CMD_ARG(start, NULL, "Start the DHCPv4 server operation on the interface.\n" + "'net dhcpv4 server start '\n" + " is the network interface index.\n" + " is the first address for the address pool.", + cmd_net_dhcpv4_server_start, 3, 0), + SHELL_CMD_ARG(stop, NULL, "Stop the DHCPv4 server operation on the interface.\n" + "'net dhcpv4 server stop '\n" + " is the network interface index.", + cmd_net_dhcpv4_server_stop, 2, 0), + SHELL_CMD_ARG(status, NULL, "Print the DHCPv4 server status on the interface.\n" + "'net dhcpv4 server status '\n" + " is the network interface index. Optional.", + cmd_net_dhcpv4_server_status, 1, 1), + SHELL_SUBCMD_SET_END +); + +SHELL_STATIC_SUBCMD_SET_CREATE(net_cmd_dhcpv4, + SHELL_CMD(server, &net_cmd_dhcpv4_server, + "DHCPv4 server service management.", + NULL), + SHELL_SUBCMD_SET_END +); + +SHELL_SUBCMD_ADD((net), dhcpv4, &net_cmd_dhcpv4, "Manage DHPCv4 services.", + NULL, 1, 0); From 2438dbb613731f1abb90be9e1b4c7bd529d46574 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Micha=C5=82=20Barna=C5=9B?= Date: Thu, 18 Jan 2024 19:08:57 +0100 Subject: [PATCH 2541/3723] init: add missing initialization of dev pointer in SYS_INIT macro MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit When the -Werror=missing-field-initializers is enabled, the compiler complains about missing initialization of dev pointer in the init_entry struct when using the SYS_INIT[_NAMED] macro. This commit adds explicit assignment of NULL to it. Signed-off-by: Michał Barnaś --- include/zephyr/init.h | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/include/zephyr/init.h b/include/zephyr/init.h index 78ec454f27c..0e33223fdce 100644 --- a/include/zephyr/init.h +++ b/include/zephyr/init.h @@ -202,10 +202,10 @@ struct init_entry { * * @see SYS_INIT() */ -#define SYS_INIT_NAMED(name, init_fn_, level, prio) \ - static const Z_DECL_ALIGN(struct init_entry) \ - Z_INIT_ENTRY_SECTION(level, prio, 0) __used __noasan \ - Z_INIT_ENTRY_NAME(name) = {.init_fn = {.sys = (init_fn_)}} +#define SYS_INIT_NAMED(name, init_fn_, level, prio) \ + static const Z_DECL_ALIGN(struct init_entry) \ + Z_INIT_ENTRY_SECTION(level, prio, 0) __used __noasan \ + Z_INIT_ENTRY_NAME(name) = {.init_fn = {.sys = (init_fn_)}, .dev = NULL} /** @} */ From c772234e433adcb8f80ac940e812e44c227debf7 Mon Sep 17 00:00:00 2001 From: Michal Smola Date: Wed, 17 Jan 2024 10:51:12 +0100 Subject: [PATCH 2542/3723] twister: fix build dir path for mklink When twister is run on Windows with --short-build-path option, mklink fails to create link, because path to build dir contains forward slashes, which are not handled correctly by mklink. Fix it by using os.path.normpath in mklink call. Added os.path.join mock in twister unit test to handle path join consistently. Signed-off-by: Michal Smola --- scripts/pylib/twister/twisterlib/testplan.py | 2 +- scripts/tests/twister/test_testplan.py | 21 ++++++++++++-------- 2 files changed, 14 insertions(+), 9 deletions(-) diff --git a/scripts/pylib/twister/twisterlib/testplan.py b/scripts/pylib/twister/twisterlib/testplan.py index 4ce4a8c317e..f62aedab8cf 100755 --- a/scripts/pylib/twister/twisterlib/testplan.py +++ b/scripts/pylib/twister/twisterlib/testplan.py @@ -994,7 +994,7 @@ def _create_build_dir_link(self, links_dir_path, instance): link_path = os.path.join(links_dir_path, link_name) if os.name == "nt": # if OS is Windows - command = ["mklink", "/J", f"{link_path}", f"{instance.build_dir}"] + command = ["mklink", "/J", f"{link_path}", os.path.normpath(instance.build_dir)] subprocess.call(command, shell=True) else: # for Linux and MAC OS os.symlink(instance.build_dir, link_path) diff --git a/scripts/tests/twister/test_testplan.py b/scripts/tests/twister/test_testplan.py index 473085467d2..488c39ddf73 100644 --- a/scripts/tests/twister/test_testplan.py +++ b/scripts/tests/twister/test_testplan.py @@ -1696,11 +1696,6 @@ def mock_link(links_dir_path, instance): TESTDATA_13, ) def test_testplan_create_build_dir_link(os_name): - testplan = TestPlan(env=mock.Mock()) - links_dir_path = os.path.join('links', 'path') - instance_build_dir = os.path.join('some', 'far', 'off', 'build', 'dir') - instance = mock.Mock(build_dir=instance_build_dir) - def mock_makedirs(path, exist_ok=False): assert exist_ok assert path == instance_build_dir @@ -1714,14 +1709,24 @@ def mock_call(cmd, shell=False): assert cmd == ['mklink', '/J', os.path.join('links', 'path', 'test_0'), instance_build_dir] + def mock_join(*paths): + slash = "\\" if os.name == 'nt' else "/" + return slash.join(paths) + with mock.patch('os.name', os_name), \ mock.patch('os.symlink', side_effect=mock_symlink), \ mock.patch('os.makedirs', side_effect=mock_makedirs), \ - mock.patch('subprocess.call', side_effect=mock_call): + mock.patch('subprocess.call', side_effect=mock_call), \ + mock.patch('os.path.join', side_effect=mock_join): + + testplan = TestPlan(env=mock.Mock()) + links_dir_path = os.path.join('links', 'path') + instance_build_dir = os.path.join('some', 'far', 'off', 'build', 'dir') + instance = mock.Mock(build_dir=instance_build_dir) testplan._create_build_dir_link(links_dir_path, instance) - assert instance.build_dir == os.path.join('links', 'path', 'test_0') - assert testplan.link_dir_counter == 1 + assert instance.build_dir == os.path.join('links', 'path', 'test_0') + assert testplan.link_dir_counter == 1 TESTDATA_14 = [ From 981c79b7ce9377cebbab89ac1770ee922061db58 Mon Sep 17 00:00:00 2001 From: Pavel Vasilyev Date: Wed, 29 Nov 2023 13:28:08 +0100 Subject: [PATCH 2543/3723] Bluetooth: Mesh: Drop explicit support for Bluetooth Mesh 1.0.1 Bluetooth Mesh Protocol 1.1 is backward compatible with Bluetooth Mesh Profile 1.0.1, therefore the stack can still be qualified for 1.0.1 if needed. But explicit support for both versions requires additional maintenance efforts and doubles the CI time. To make the stack qualifiable for 1.0.1, the one needs to remove Private Beacons reception and compile out SHA256 algorithm support. What is changed: - Removed `CONFIG_BT_MESH_V1d1` option. - Removed `transport_legacy.c` which was using 1.0.1 implementation. The new transport layer has new SaR logic that should still be possible to qualify for 1.0.1. - Removed the legacy transport Kconfig options. They are superseded by the new transport Kconfig options. - Tester app: `overlay-mesh-v1d1.conf` is merged into `overlay-mesh.conf`. - Removed BabbleSim tests for 1.0.1. - Updated documentation. Signed-off-by: Pavel Vasilyev --- doc/connectivity/bluetooth/api/mesh.rst | 5 +- .../bluetooth/api/mesh/access.rst | 9 - .../bluetooth/api/mesh/sar_cfg.rst | 56 +- doc/releases/migration-guide-3.6.rst | 19 + doc/releases/release-notes-3.6.rst | 1 + include/zephyr/bluetooth/mesh/main.h | 4 - subsys/bluetooth/mesh/CMakeLists.txt | 7 +- subsys/bluetooth/mesh/Kconfig | 62 +- subsys/bluetooth/mesh/access.c | 3 +- subsys/bluetooth/mesh/beacon.c | 6 - subsys/bluetooth/mesh/net.c | 5 - subsys/bluetooth/mesh/subnet.h | 2 - subsys/bluetooth/mesh/transport_legacy.c | 1656 ----------------- tests/bluetooth/mesh/blob_io_flash/prj.conf | 1 - .../mesh_shell/proxy_solicitation.conf | 1 - tests/bluetooth/tester/overlay-mesh-v1d1.conf | 30 - tests/bluetooth/tester/overlay-mesh.conf | 29 + tests/bluetooth/tester/testcase.yaml | 10 - tests/bsim/bluetooth/mesh/CMakeLists.txt | 42 +- tests/bsim/bluetooth/mesh/compile.sh | 23 +- tests/bsim/bluetooth/mesh/overlay_pst.conf | 3 - tests/bsim/bluetooth/mesh/prj.conf | 28 +- tests/bsim/bluetooth/mesh/prj_mesh1d1.conf | 73 - tests/bsim/bluetooth/mesh/src/main.c | 13 - tests/bsim/bluetooth/mesh/src/test_beacon.c | 17 +- .../bsim/bluetooth/mesh/src/test_provision.c | 4 - .../bluetooth/mesh/src/test_replay_cache.c | 4 - .../bsim/bluetooth/mesh/src/test_transport.c | 2 - .../tests_scripts/access/access_cancel.sh | 5 - .../tests_scripts/access/access_ext_sub.sh | 5 - .../access/access_ext_sub_cap.sh | 4 - .../tests_scripts/access/access_period.sh | 5 - .../access/access_period_delayable.sh | 5 - .../tests_scripts/access/access_transmit.sh | 5 - .../access/access_transmit_delayable.sh | 5 - .../tests_scripts/advertiser/proxy_mixin.sh | 5 - .../tests_scripts/advertiser/random_order.sh | 4 - .../tests_scripts/advertiser/reverse_order.sh | 4 - .../tests_scripts/advertiser/send_order.sh | 4 - .../tests_scripts/advertiser/tx_cb_multi.sh | 4 - .../tests_scripts/advertiser/tx_cb_single.sh | 4 - .../mesh/tests_scripts/beacon/beacon_cache.sh | 6 - .../tests_scripts/beacon/beacon_interval.sh | 6 - .../mesh/tests_scripts/beacon/invalid.sh | 6 - .../mesh/tests_scripts/beacon/iv_update.sh | 6 - .../mesh/tests_scripts/beacon/key_refresh.sh | 6 - .../mesh/tests_scripts/beacon/kr_old_key.sh | 6 - .../tests_scripts/beacon/multiple_netkeys.sh | 6 - .../blob_mdls/blob_cli_broadcast_basic.sh | 2 - .../blob_mdls/blob_cli_broadcast_trans.sh | 2 - .../blob_mdls/blob_cli_broadcast_unicast.sh | 2 - .../blob_cli_broadcast_unicast_seq.sh | 2 - .../blob_mdls/blob_cli_caps_all_rsp.sh | 2 - .../blob_mdls/blob_cli_caps_cancelled.sh | 2 - .../blob_mdls/blob_cli_caps_no_rsp.sh | 2 - .../blob_mdls/blob_cli_caps_partial_rsp.sh | 2 - .../blob_mdls/blob_cli_friend.sh | 2 - .../blob_mdls/blob_cli_no_rsp_block.sh | 2 - .../blob_mdls/blob_cli_no_rsp_xfer.sh | 2 - .../blob_mdls/blob_cli_persistent_transfer.sh | 2 - .../blob_cli_persistent_transfer_pull.sh | 2 - .../blob_mdls/blob_cli_trans_complete_pull.sh | 2 - .../blob_mdls/blob_cli_trans_complete_push.sh | 2 - .../blob_mdls/blob_cli_trans_resume_pull.sh | 2 - .../blob_mdls/blob_cli_trans_resume_push.sh | 2 - .../blob_mdls/blob_srv_persistence.sh | 12 - .../comp_data/cdp1_encode_decode.sh | 2 - .../dfu/dfu_cli_all_targets_lost_on_apply.sh | 2 - .../dfu_cli_all_targets_lost_on_caps_get.sh | 2 - .../dfu_cli_all_targets_lost_on_metadata.sh | 2 - .../dfu_cli_all_targets_lost_on_update_get.sh | 2 - .../dfu/dfu_cli_all_targets_lost_on_verify.sh | 2 - .../dfu/dfu_cli_persistent_transfer.sh | 2 - .../tests_scripts/dfu/dfu_dist_self_update.sh | 2 - .../dfu/dfu_dist_self_update_mult_targets.sh | 2 - .../mesh/tests_scripts/dfu/dfu_mixed.sh | 2 - .../mesh/tests_scripts/dfu/dfu_mixed_fail.sh | 2 - .../mesh/tests_scripts/dfu/dfu_slot.sh | 2 - .../tests_scripts/dfu/dfu_slot_idempotency.sh | 2 - .../tests_scripts/dfu/dfu_slot_reservation.sh | 2 - .../tests_scripts/dfu/dfu_srv_persistence.sh | 14 - .../tests_scripts/friendship/establish.sh | 6 - .../friendship/establish_multi.sh | 10 - .../tests_scripts/friendship/lpn_disable.sh | 6 - .../tests_scripts/friendship/lpn_loopback.sh | 6 - .../friendship/lpn_terminate_cb.sh | 6 - .../mesh/tests_scripts/friendship/msg_frnd.sh | 6 - .../tests_scripts/friendship/msg_group.sh | 7 - .../mesh/tests_scripts/friendship/msg_mesh.sh | 7 - .../friendship/msg_mesh_low_lat.sh | 8 - .../friendship/msg_va_collision.sh | 6 - .../mesh/tests_scripts/friendship/overflow.sh | 6 - .../mesh/tests_scripts/friendship/poll.sh | 6 - .../tests_scripts/friendship/re-establish.sh | 6 - .../tests_scripts/heartbeat/sub_cb_api_all.sh | 7 - .../heartbeat/sub_cb_api_unicast.sh | 7 - .../tests_scripts/iv_index/iv_deferring.sh | 4 - .../tests_scripts/iv_index/iv_recovery.sh | 4 - .../mesh/tests_scripts/iv_index/iv_update.sh | 4 - .../large_comp_data/get_comp0_data_split.sh | 2 - .../get_comp0_data_split_dfu.sh | 2 - .../large_comp_data/get_comp128_data_split.sh | 2 - .../get_comp128_data_split_dfu.sh | 2 - .../large_comp_data/get_comp129_data_split.sh | 2 - .../get_comp129_data_split_dfu.sh | 2 - .../large_comp_data/get_comp130_data_split.sh | 2 - .../get_comp130_data_split_dfu.sh | 2 - .../large_comp_data/get_comp1_data_split.sh | 2 - .../get_comp1_data_split_dfu.sh | 2 - .../large_comp_data/get_comp2_data_split.sh | 2 - .../get_comp2_data_split_dfu.sh | 2 - .../large_comp_data/get_comp_data_max_sdu.sh | 2 - .../large_comp_data/get_metadata_max_sdu.sh | 2 - .../large_comp_data/get_metadata_split.sh | 2 - .../op_agg/full_status_msg_list.sh | 2 - .../mesh/tests_scripts/op_agg/loopback.sh | 2 - .../mesh/tests_scripts/op_agg/model_coex.sh | 2 - .../mesh/tests_scripts/persistence/access.sh | 35 - .../mesh/tests_scripts/persistence/cfg.sh | 24 - .../tests_scripts/persistence/provisioning.sh | 10 - .../persistence/reprovisioning.sh | 14 - .../priv_beacon/priv_beacon_adv.sh | 2 - .../priv_beacon/priv_beacon_cache.sh | 2 - .../priv_beacon/priv_beacon_interleave.sh | 2 - .../priv_beacon/priv_beacon_invalid.sh | 2 - .../priv_beacon/priv_beacon_ivu.sh | 2 - .../priv_beacon_ivu_long_interval.sh | 2 - .../priv_beacon/priv_beacon_kr.sh | 2 - .../priv_beacon_kr_long_interval.sh | 2 - .../priv_beacon/priv_proxy_gatt.sh | 2 - .../priv_beacon/priv_proxy_net_id.sh | 2 - .../priv_beacon/priv_proxy_net_id_multi.sh | 2 - .../priv_beacon/priv_proxy_node_id.sh | 2 - .../proxy_adv_multi_subnet_coex.sh | 2 - .../provision/ivu_flag_one_duration.sh | 4 - .../provision/ivu_flag_zero_duration.sh | 4 - .../tests_scripts/provision/pb_adv_multi.sh | 8 - .../tests_scripts/provision/pb_adv_no_oob.sh | 6 - .../provision/pb_adv_oob_auth_ib_pk.sh | 5 - .../pb_adv_oob_auth_ignore_oob_pk.sh | 5 - .../provision/pb_adv_oob_auth_oob_pk.sh | 5 - .../provision/pb_adv_reprovision.sh | 6 - .../pb_remote_client_server_same_dev.sh | 2 - .../provision/pb_remote_nppi_robustness.sh | 2 - .../provision/pb_remote_parallel.sh | 2 - .../provision/pb_remote_pst_ncrp.sh | 6 - .../provision/pb_remote_reprovision.sh | 2 - .../provision/pb_remote_timeout.sh | 2 - .../replay_cache/replay_attack.sh | 14 - .../tests_scripts/replay_cache/rpl_frag.sh | 13 - .../sar/sar_cfg_persistent_storage.sh | 2 - .../tests_scripts/sar/slow_transfer_test.sh | 2 - .../mesh/tests_scripts/sar/stress_test.sh | 2 - .../tests_scripts/scanner/invalid_ad_type.sh | 6 - .../scanner/wrong_packet_length.sh | 6 - .../suspend/gatt_suspend_disable_resume.sh | 7 - .../suspend/gatt_suspend_resume.sh | 7 - .../suspend/suspend_disable_resume.sh | 5 - .../tests_scripts/suspend/suspend_resume.sh | 5 - .../mesh/tests_scripts/transport/fixed.sh | 4 - .../mesh/tests_scripts/transport/group.sh | 4 - .../mesh/tests_scripts/transport/loopback.sh | 4 - .../tests_scripts/transport/loopback_group.sh | 4 - .../transport/loopback_group_low_lat.sh | 5 - .../mesh/tests_scripts/transport/seg_block.sh | 4 - .../tests_scripts/transport/seg_concurrent.sh | 4 - .../mesh/tests_scripts/transport/seg_fail.sh | 4 - .../mesh/tests_scripts/transport/seg_ivu.sh | 4 - .../mesh/tests_scripts/transport/unicast.sh | 4 - .../transport/unicast_low_lat.sh | 5 - .../tests_scripts/transport/unknown_app.sh | 4 - .../mesh/tests_scripts/transport/va.sh | 4 - .../tests_scripts/transport/va_collision.sh | 4 - 173 files changed, 112 insertions(+), 2635 deletions(-) delete mode 100644 subsys/bluetooth/mesh/transport_legacy.c delete mode 100644 tests/bluetooth/tester/overlay-mesh-v1d1.conf delete mode 100644 tests/bsim/bluetooth/mesh/prj_mesh1d1.conf diff --git a/doc/connectivity/bluetooth/api/mesh.rst b/doc/connectivity/bluetooth/api/mesh.rst index f234ff7cedc..358ba3dc62e 100644 --- a/doc/connectivity/bluetooth/api/mesh.rst +++ b/doc/connectivity/bluetooth/api/mesh.rst @@ -5,10 +5,7 @@ Bluetooth Mesh Profile The Bluetooth Mesh profile adds secure wireless multi-hop communication for Bluetooth Low Energy. This module implements the -`Bluetooth Mesh Profile Specification v1.0.1 `_. - -Implementation of the `Bluetooth Mesh Protocol Specification v1.1 `_ -is in experimental state. +`Bluetooth Mesh Protocol Specification v1.1 `_. Read more about Bluetooth Mesh on the `Bluetooth SIG Website `_. diff --git a/doc/connectivity/bluetooth/api/mesh/access.rst b/doc/connectivity/bluetooth/api/mesh/access.rst index cb02028b697..7af8ca7ec68 100644 --- a/doc/connectivity/bluetooth/api/mesh/access.rst +++ b/doc/connectivity/bluetooth/api/mesh/access.rst @@ -168,15 +168,6 @@ needs to be stored. Composition Data ================ -.. note:: - - The implementation of the Bluetooth Mesh Protocol Specification version 1.1 - is currently in an experimental state. For Bluetooth Mesh Profile Specification - version 1.0.1, only Composition Data Page 0 is supported. Users that are developing - for Bluetooth Mesh Profile Specification version 1.0.1 may therefore disregard all - parts of the following section mentioning the :ref:`bluetooth_mesh_lcd_srv` - model and Composition Data Pages 1, 2, 128, 129 and 130. - The Composition Data provides information about a mesh device. A device's Composition Data holds information about the elements on the device, the models that it supports, and other features. The Composition diff --git a/doc/connectivity/bluetooth/api/mesh/sar_cfg.rst b/doc/connectivity/bluetooth/api/mesh/sar_cfg.rst index 4f3354945c9..76bd0330a98 100644 --- a/doc/connectivity/bluetooth/api/mesh/sar_cfg.rst +++ b/doc/connectivity/bluetooth/api/mesh/sar_cfg.rst @@ -43,36 +43,8 @@ Keep this in mind when defining the size of the buffers. SAR does not impose extra overhead on the access layer payload per segment. -Intervals, timers and retransmission counters -********************************************* - -The current stable stack implementation allows you to configure the following SAR behavior. - -When sending a segmented message to a unicast address, the unacknowledged segments are repeated -the :kconfig:option:`CONFIG_BT_MESH_TX_SEG_RETRANS_COUNT` number of times before the transmission -is considered as failed. The same option configures a number of retransmissions to a group or -virtual address, but the transmission always succeedes after retransmitting all segments the -configured number of times. - -The timeout between each retransmission to a unicast address is configured by the Kconfig option -:kconfig:option:`CONFIG_BT_MESH_TX_SEG_RETRANS_TIMEOUT_UNICAST`. The timeout between each -retransmission to a group or a virtual address is configured by the Kconfig option -:kconfig:option:`CONFIG_BT_MESH_TX_SEG_RETRANS_TIMEOUT_GROUP`. - -The time before sending a Segment Acknowledgment message is controlled by the Kconfig options -:kconfig:option:`CONFIG_BT_MESH_SEG_ACK_BASE_TIMEOUT`, -:kconfig:option:`CONFIG_BT_MESH_SEG_ACK_PER_HOP_TIMEOUT` and -:kconfig:option:`CONFIG_BT_MESH_SEG_ACK_PER_SEGMENT_TIMEOUT`, and is defined as: - -.. math:: - \begin{aligned} - \max(&\mathtt{CONFIG\_BT\_MESH\_SEG\_ACK\_BASE\_TIMEOUT} \\ - &+ \text{TTL} \times \mathtt{CONFIG\_BT\_MESH\_SEG\_ACK\_PER\_HOP\_TIMEOUT} \\ - &+ \text{number of un-acked segments} \times \mathtt{CONFIG\_BT\_MESH\_SEG\_ACK\_PER\_SEGMENT\_TIMEOUT} , 400) - \end{aligned} - Segmentation and reassembly (SAR) Configuration models -====================================================== +****************************************************** With Bluetooth Mesh Protocol Specification version 1.1, it became possible to configure SAR behavior, such as intervals, timers and retransmission counters, over a mesh network using SAR @@ -139,7 +111,7 @@ of the `SAR Acknowledgment Retransmissions Count`_ state. .. _bt_mesh_sar_cfg_states: SAR states -========== +********** There are two states defined related to segmentation and reassembly: @@ -168,7 +140,7 @@ the following states: * SAR Receiver Segment Interval Step SAR Segment Interval Step -------------------------- +========================= SAR Segment Interval Step state holds a value that controls the interval between transmissions of segments of a segmented message. The interval is measured in milliseconds. @@ -182,7 +154,7 @@ value. Segment transmission interval is then calculated using the following form SAR Unicast Retransmissions Count ---------------------------------- +================================= SAR Unicast Retransmissions Count holds a value that defines the maximum number of retransmissions of a segmented message to a unicast destination. Use the @@ -190,7 +162,7 @@ of a segmented message to a unicast destination. Use the value for this state. SAR Unicast Retransmissions Without Progress Count --------------------------------------------------- +================================================== This state holds a value that defines the maximum number of retransmissions of a segmented message to a unicast address that will be sent if no acknowledgment was received during the timeout, or if @@ -199,7 +171,7 @@ an acknowledgment with already confirmed segments was received. Use the Kconfig of retransmissions. SAR Unicast Retransmissions Interval Step ------------------------------------------ +========================================= The value of this state controls the interval step used for delaying the retransmissions of unacknowledged segments of a segmented message to a unicast address. The interval step is measured @@ -214,7 +186,7 @@ default value. This value is then used to calculate the interval step using the SAR Unicast Retransmissions Interval Increment ----------------------------------------------- +============================================== SAR Unicast Retransmissions Interval Increment holds a value that controls the interval increment used for delaying the retransmissions of unacknowledged segments of a segmented message to a unicast @@ -230,7 +202,7 @@ formula: SAR Multicast Retransmissions Count ------------------------------------ +=================================== The state holds a value that controls the total number of retransmissions of a segmented message to a multicast address. Use the Kconfig option @@ -238,7 +210,7 @@ a multicast address. Use the Kconfig option retransmissions. SAR Multicast Retransmissions Interval Step -------------------------------------------- +=========================================== This state holds a value that controls the interval between retransmissions of all segments in a segmented message to a multicast address. The interval is measured in milliseconds. @@ -252,7 +224,7 @@ default value that is used to calculate the interval using the following formula SAR Discard Timeout -------------------- +=================== The value of this state defines the time in seconds that the lower transport layer waits after receiving segments of a segmented message before discarding that segmented message. Use the Kconfig @@ -265,7 +237,7 @@ timeout will be calculated using the following formula: SAR Acknowledgment Delay Increment ----------------------------------- +================================== This state holds a value that controls the delay increment of an interval used for delaying the transmission of an acknowledgment message after receiving a new segment. The increment is measured @@ -276,7 +248,7 @@ value. The increment value is calculated to be :math:`\verb|CONFIG_BT_MESH_SAR_RX_ACK_DELAY_INC| + 1.5`. SAR Segments Threshold ----------------------- +====================== SAR Segments Threshold state holds a value that defines a threshold in number of segments of a segmented message for acknowledgment retransmissions. Use the Kconfig option @@ -287,7 +259,7 @@ additionally retransmit every acknowledgment message the number of times given b :kconfig:option:`CONFIG_BT_MESH_SAR_RX_ACK_RETRANS_COUNT`. SAR Acknowledgment Retransmissions Count ----------------------------------------- +======================================== The SAR Acknowledgment Retransmissions Count state controls the number of retransmissions of Segment Acknowledgment messages sent by the lower transport layer. It gives the total number of @@ -300,7 +272,7 @@ value for this state. The maximum number of transmissions of a Segment Acknowle :math:`\verb|CONFIG_BT_MESH_SAR_RX_ACK_RETRANS_COUNT| + 1`. SAR Receiver Segment Interval Step ----------------------------------- +================================== The SAR Receiver Segment Interval Step defines the segments reception interval step used for delaying the transmission of an acknowledgment message after receiving a new segment. The interval diff --git a/doc/releases/migration-guide-3.6.rst b/doc/releases/migration-guide-3.6.rst index e5acef50825..53ad073a06b 100644 --- a/doc/releases/migration-guide-3.6.rst +++ b/doc/releases/migration-guide-3.6.rst @@ -302,6 +302,25 @@ Bluetooth * Deprecated :kconfig:option:`CONFIG_BT_MESH_PROV_DEVICE`. This option is replaced by new option :kconfig:option:`CONFIG_BT_MESH_PROVISIONEE` to be aligned with Mesh Protocol Specification v1.1, section 5.4. (:github:`64252`) + * Removed the ``CONFIG_BT_MESH_V1d1`` Kconfig option. + * Removed the ``CONFIG_BT_MESH_TX_SEG_RETRANS_COUNT``, + ``CONFIG_BT_MESH_TX_SEG_RETRANS_TIMEOUT_UNICAST``, + ``CONFIG_BT_MESH_TX_SEG_RETRANS_TIMEOUT_GROUP``, ``CONFIG_BT_MESH_SEG_ACK_BASE_TIMEOUT``, + ``CONFIG_BT_MESH_SEG_ACK_PER_HOP_TIMEOUT``, ``BT_MESH_SEG_ACK_PER_SEGMENT_TIMEOUT`` + Kconfig options. They are superseded by the + :kconfig:option:`CONFIG_BT_MESH_SAR_TX_SEG_INT_STEP`, + :kconfig:option:`CONFIG_BT_MESH_SAR_TX_UNICAST_RETRANS_COUNT`, + :kconfig:option:`CONFIG_BT_MESH_SAR_TX_UNICAST_RETRANS_WITHOUT_PROG_COUNT`, + :kconfig:option:`CONFIG_BT_MESH_SAR_TX_UNICAST_RETRANS_INT_STEP`, + :kconfig:option:`CONFIG_BT_MESH_SAR_TX_UNICAST_RETRANS_INT_INC`, + :kconfig:option:`CONFIG_BT_MESH_SAR_TX_MULTICAST_RETRANS_COUNT`, + :kconfig:option:`CONFIG_BT_MESH_SAR_TX_MULTICAST_RETRANS_INT`, + :kconfig:option:`CONFIG_BT_MESH_SAR_RX_SEG_THRESHOLD`, + :kconfig:option:`CONFIG_BT_MESH_SAR_RX_ACK_DELAY_INC`, + :kconfig:option:`CONFIG_BT_MESH_SAR_RX_SEG_INT_STEP`, + :kconfig:option:`CONFIG_BT_MESH_SAR_RX_DISCARD_TIMEOUT`, + :kconfig:option:`CONFIG_BT_MESH_SAR_RX_ACK_RETRANS_COUNT` Kconfig options. + LoRaWAN ======= diff --git a/doc/releases/release-notes-3.6.rst b/doc/releases/release-notes-3.6.rst index dfc69a17c9f..6fc4b7060d2 100644 --- a/doc/releases/release-notes-3.6.rst +++ b/doc/releases/release-notes-3.6.rst @@ -58,6 +58,7 @@ Bluetooth the transmitted responses on the Access layer. The functionality is enabled by the :kconfig:option:`CONFIG_BT_MESH_ACCESS_DELAYABLE_MSG` Kconfig option. + * The Bluetooth Mesh Protocol 1.1 is now supported by default. * Controller diff --git a/include/zephyr/bluetooth/mesh/main.h b/include/zephyr/bluetooth/mesh/main.h index a213e8ce22c..1622ccebbd8 100644 --- a/include/zephyr/bluetooth/mesh/main.h +++ b/include/zephyr/bluetooth/mesh/main.h @@ -783,7 +783,6 @@ struct bt_mesh_snb { uint64_t auth_val; }; -#if defined(CONFIG_BT_MESH_V1d1) struct bt_mesh_prb { /** Random */ uint8_t random[13]; @@ -797,7 +796,6 @@ struct bt_mesh_prb { /** Authentication tag */ uint64_t auth_tag; }; -#endif /** Beacon callback functions. */ struct bt_mesh_beacon_cb { @@ -810,7 +808,6 @@ struct bt_mesh_beacon_cb { */ void (*snb_received)(const struct bt_mesh_snb *snb); -#if defined(CONFIG_BT_MESH_V1d1) /** @brief Private Beacon received. * * This callback notifies the application that Private Beacon @@ -819,7 +816,6 @@ struct bt_mesh_beacon_cb { * @param prb Structure describing received Private Beacon */ void (*priv_received)(const struct bt_mesh_prb *prb); -#endif }; /** diff --git a/subsys/bluetooth/mesh/CMakeLists.txt b/subsys/bluetooth/mesh/CMakeLists.txt index 4c597c12a68..c628fb6d9db 100644 --- a/subsys/bluetooth/mesh/CMakeLists.txt +++ b/subsys/bluetooth/mesh/CMakeLists.txt @@ -18,14 +18,9 @@ zephyr_library_sources_ifdef(CONFIG_BT_MESH cfg_srv.c health_srv.c va.c + transport.c ) -if (CONFIG_BT_MESH_V1d1) - zephyr_library_sources(transport.c) -else() - zephyr_library_sources(transport_legacy.c) -endif() - zephyr_library_sources_ifdef(CONFIG_BT_MESH_ADV_LEGACY adv_legacy.c) zephyr_library_sources_ifdef(CONFIG_BT_MESH_ADV_EXT adv_ext.c) diff --git a/subsys/bluetooth/mesh/Kconfig b/subsys/bluetooth/mesh/Kconfig index 50d7ca3fb83..5f59e7f9be8 100644 --- a/subsys/bluetooth/mesh/Kconfig +++ b/subsys/bluetooth/mesh/Kconfig @@ -512,56 +512,6 @@ config BT_MESH_TX_SEG_MAX which leaves 56 bytes for application layer data using a 4-byte MIC and 52 bytes using an 8-byte MIC. -if !BT_MESH_V1d1 - -config BT_MESH_TX_SEG_RETRANS_COUNT - int "Transport message segment retransmit attempts" - default 4 - range 1 8 - help - Maximum number of transport message segment retransmit attempts - for outgoing segment message. - -config BT_MESH_TX_SEG_RETRANS_TIMEOUT_UNICAST - int "Transport message segment retransmit interval for unicast messages" - default 400 - range 200 500 - help - Maximum time of retransmit segment message to unicast address. - -config BT_MESH_TX_SEG_RETRANS_TIMEOUT_GROUP - int "Transport message segment retransmit interval for group messages" - default 50 - range 20 200 - help - Maximum time of retransmit segment message to group address. - -config BT_MESH_SEG_ACK_BASE_TIMEOUT - int "SegAck transmission base timeout" - default 150 - range 150 400 - help - Defines a base timeout for the acknowledgment timer used to delay - transmission of the Segmented Acknowledgment message. - -config BT_MESH_SEG_ACK_PER_HOP_TIMEOUT - int "SegAck transmission timeout per hop" - default 50 - range 50 250 - help - Defines an additional per-hop timeout for the acknowledgment timer - used to delay transmission of the Segmented Acknowledgment message. - -config BT_MESH_SEG_ACK_PER_SEGMENT_TIMEOUT - int "SegAck transmission timeout per segment not yet received" - default 0 - range 0 100 - help - Defines an additional timeout for the acknowledgment timer for every - segment not yet received. - -endif # !BT_MESH_V1d1 - endmenu # Transport SAR configuration config BT_MESH_DEFAULT_TTL @@ -1112,21 +1062,13 @@ config BT_MESH_FRIEND_ADV_LATENCY endif # BT_MESH_FRIEND -menuconfig BT_MESH_V1d1 - bool "Bluetooth Mesh v1.1 support" - help - This option enables Bluetooth Mesh v1.1 support. Bluetooth Mesh v1.1 - is backward compatible with v1.0.1. - config BT_MESH_ECDH_P256_CMAC_AES128_AES_CCM - bool "Support CMAC AES128 for OOB authentication" if BT_MESH_V1d1 + bool "Support CMAC AES128 for OOB authentication" depends on BT_MESH_PROV default y help Enable this option to support CMAC AES128 for OOB authentication. -if BT_MESH_V1d1 - config BT_MESH_ECDH_P256_HMAC_SHA256_AES_CCM bool "Support HMAC SHA256 for OOB authentication" depends on BT_MESH_PROV @@ -1696,8 +1638,6 @@ config BT_MESH_SAR_RX_ACK_RETRANS_COUNT endmenu -endif # BT_MESH_V1d1 - menu "Capabilities" config BT_MESH_SUBNET_COUNT diff --git a/subsys/bluetooth/mesh/access.c b/subsys/bluetooth/mesh/access.c index 23fbb8e82c2..4ff80333187 100644 --- a/subsys/bluetooth/mesh/access.c +++ b/subsys/bluetooth/mesh/access.c @@ -2380,7 +2380,6 @@ size_t bt_mesh_comp_page_size(uint8_t page) int bt_mesh_comp_store(void) { -#if IS_ENABLED(CONFIG_BT_MESH_V1d1) NET_BUF_SIMPLE_DEFINE(buf, CONFIG_BT_MESH_COMP_PST_BUF_SIZE); int err; @@ -2410,7 +2409,7 @@ int bt_mesh_comp_store(void) LOG_DBG("Stored CDP%d", comp_data_pages[i].page); } -#endif + return 0; } diff --git a/subsys/bluetooth/mesh/beacon.c b/subsys/bluetooth/mesh/beacon.c index ef337f9f510..6eb2c9be3a7 100644 --- a/subsys/bluetooth/mesh/beacon.c +++ b/subsys/bluetooth/mesh/beacon.c @@ -528,7 +528,6 @@ static bool secure_beacon_authenticate(struct bt_mesh_subnet *sub, void *cb_data return false; } -#if defined(CONFIG_BT_MESH_V1d1) static bool priv_beacon_decrypt(struct bt_mesh_subnet *sub, void *cb_data) { struct beacon_params *params = cb_data; @@ -567,7 +566,6 @@ static bool priv_beacon_decrypt(struct bt_mesh_subnet *sub, void *cb_data) return false; } -#endif static void net_beacon_register(struct bt_mesh_beacon *beacon, bool priv) { @@ -658,7 +656,6 @@ static void secure_beacon_recv(struct net_buf_simple *buf) net_beacon_resolve(¶ms, secure_beacon_authenticate); } -#if defined(CONFIG_BT_MESH_V1d1) static void private_beacon_recv(struct net_buf_simple *buf) { struct beacon_params params; @@ -675,7 +672,6 @@ static void private_beacon_recv(struct net_buf_simple *buf) net_beacon_resolve(¶ms, priv_beacon_decrypt); } -#endif void bt_mesh_beacon_recv(struct net_buf_simple *buf) { @@ -699,9 +695,7 @@ void bt_mesh_beacon_recv(struct net_buf_simple *buf) secure_beacon_recv(buf); break; case BEACON_TYPE_PRIVATE: -#if defined(CONFIG_BT_MESH_V1d1) private_beacon_recv(buf); -#endif break; default: LOG_WRN("Unknown beacon type 0x%02x", type); diff --git a/subsys/bluetooth/mesh/net.c b/subsys/bluetooth/mesh/net.c index 943a5e83c23..07c6f1aa18a 100644 --- a/subsys/bluetooth/mesh/net.c +++ b/subsys/bluetooth/mesh/net.c @@ -35,10 +35,7 @@ #include "prov.h" #include "cfg.h" #include "statistic.h" - -#ifdef CONFIG_BT_MESH_V1d1 #include "sar_cfg_internal.h" -#endif #define LOG_LEVEL CONFIG_BT_MESH_NET_LOG_LEVEL #include @@ -84,10 +81,8 @@ static uint16_t msg_cache_next; /* Singleton network context (the implementation only supports one) */ struct bt_mesh_net bt_mesh = { .local_queue = SYS_SLIST_STATIC_INIT(&bt_mesh.local_queue), -#ifdef CONFIG_BT_MESH_V1d1 .sar_tx = BT_MESH_SAR_TX_INIT, .sar_rx = BT_MESH_SAR_RX_INIT, -#endif #if defined(CONFIG_BT_MESH_PRIV_BEACONS) .priv_beacon_int = 0x3c, diff --git a/subsys/bluetooth/mesh/subnet.h b/subsys/bluetooth/mesh/subnet.h index f19b1d2abea..e04f9855b66 100644 --- a/subsys/bluetooth/mesh/subnet.h +++ b/subsys/bluetooth/mesh/subnet.h @@ -76,9 +76,7 @@ struct bt_mesh_subnet { struct bt_mesh_key identity; /* IdentityKey */ #endif struct bt_mesh_key beacon; /* BeaconKey */ -#if defined(CONFIG_BT_MESH_V1d1) struct bt_mesh_key priv_beacon; /* PrivateBeaconKey */ -#endif } keys[2]; #if defined(CONFIG_BT_MESH_PROXY_SOLICITATION) bool sol_tx; diff --git a/subsys/bluetooth/mesh/transport_legacy.c b/subsys/bluetooth/mesh/transport_legacy.c deleted file mode 100644 index 1a826db4ac4..00000000000 --- a/subsys/bluetooth/mesh/transport_legacy.c +++ /dev/null @@ -1,1656 +0,0 @@ -/* - * Copyright (c) 2017 Intel Corporation - * - * SPDX-License-Identifier: Apache-2.0 - */ - -#include -#include -#include -#include -#include -#include -#include - -#include - -#include -#include - -#include "common/bt_str.h" - -#include "host/testing.h" - -#include "crypto.h" -#include "mesh.h" -#include "net.h" -#include "app_keys.h" -#include "lpn.h" -#include "rpl.h" -#include "friend.h" -#include "access.h" -#include "foundation.h" -#include "settings.h" -#include "heartbeat.h" -#include "transport.h" -#include "va.h" - -#define LOG_LEVEL CONFIG_BT_MESH_TRANS_LOG_LEVEL -#include -LOG_MODULE_REGISTER(bt_mesh_transport); - -#define AID_MASK ((uint8_t)(BIT_MASK(6))) - -#define SEG(data) ((data)[0] >> 7) -#define AKF(data) (((data)[0] >> 6) & 0x01) -#define AID(data) ((data)[0] & AID_MASK) -#define ASZMIC(data) (((data)[1] >> 7) & 1) - -#define APP_MIC_LEN(aszmic) ((aszmic) ? BT_MESH_MIC_LONG : BT_MESH_MIC_SHORT) - -#define UNSEG_HDR(akf, aid) ((akf << 6) | (aid & AID_MASK)) -#define SEG_HDR(akf, aid) (UNSEG_HDR(akf, aid) | 0x80) - -#define BLOCK_COMPLETE(seg_n) (uint32_t)(((uint64_t)1 << (seg_n + 1)) - 1) - -#define SEQ_AUTH(iv_index, seq) (((uint64_t)iv_index) << 24 | (uint64_t)seq) - -/* Number of retransmit attempts (after the initial transmit) per segment */ -#define SEG_RETRANSMIT_ATTEMPTS CONFIG_BT_MESH_TX_SEG_RETRANS_COUNT - -/* "This timer shall be set to a minimum of 200 + 50 * TTL milliseconds.". - * We use 400 since 300 is a common send duration for standard HCI, and we - * need to have a timeout that's bigger than that. - */ -#define SEG_RETRANSMIT_TIMEOUT_UNICAST(tx) \ - (CONFIG_BT_MESH_TX_SEG_RETRANS_TIMEOUT_UNICAST + 50 * (tx)->ttl) - -/* When sending to a group, the messages are not acknowledged, and there's no - * reason to delay the repetitions significantly. Delaying by more than 0 ms - * to avoid flooding the network. - */ -#define SEG_RETRANSMIT_TIMEOUT_GROUP CONFIG_BT_MESH_TX_SEG_RETRANS_TIMEOUT_GROUP - -#define SEG_RETRANSMIT_TIMEOUT(tx) \ - (BT_MESH_ADDR_IS_UNICAST(tx->dst) ? \ - SEG_RETRANSMIT_TIMEOUT_UNICAST(tx) : \ - SEG_RETRANSMIT_TIMEOUT_GROUP) -/* How long to wait for available buffers before giving up */ -#define BUF_TIMEOUT K_NO_WAIT - -static struct seg_tx { - struct bt_mesh_subnet *sub; - void *seg[BT_MESH_TX_SEG_MAX]; - uint64_t seq_auth; - uint16_t src; - uint16_t dst; - uint16_t ack_src; - uint16_t len; - uint8_t hdr; - uint8_t xmit; - uint8_t seg_n; /* Last segment index */ - uint8_t seg_o; /* Segment being sent */ - uint8_t nack_count; /* Number of unacked segs */ - uint8_t attempts; /* Remaining tx attempts */ - uint8_t ttl; /* Transmitted TTL value */ - uint8_t blocked:1, /* Blocked by ongoing tx */ - ctl:1, /* Control packet */ - aszmic:1, /* MIC size */ - started:1, /* Start cb called */ - friend_cred:1, /* Using Friend credentials */ - seg_send_started:1; /* Used to check if seg_send_start cb is called */ - const struct bt_mesh_send_cb *cb; - void *cb_data; - struct k_work_delayable retransmit; /* Retransmit timer */ -} seg_tx[CONFIG_BT_MESH_TX_SEG_MSG_COUNT]; - -static struct seg_rx { - struct bt_mesh_subnet *sub; - void *seg[BT_MESH_RX_SEG_MAX]; - uint64_t seq_auth; - uint16_t src; - uint16_t dst; - uint16_t len; - uint8_t hdr; - uint8_t seg_n:5, - ctl:1, - in_use:1, - obo:1; - uint8_t ttl; - uint32_t block; - uint32_t last; - struct k_work_delayable ack; -} seg_rx[CONFIG_BT_MESH_RX_SEG_MSG_COUNT]; - -K_MEM_SLAB_DEFINE(segs, BT_MESH_APP_SEG_SDU_MAX, CONFIG_BT_MESH_SEG_BUFS, 4); - -static int send_unseg(struct bt_mesh_net_tx *tx, struct net_buf_simple *sdu, - const struct bt_mesh_send_cb *cb, void *cb_data, - const uint8_t *ctl_op) -{ - struct bt_mesh_adv *adv; - - adv = bt_mesh_adv_create(BT_MESH_ADV_DATA, BT_MESH_ADV_TAG_LOCAL, - tx->xmit, BUF_TIMEOUT); - if (!adv) { - LOG_ERR("Out of network advs"); - return -ENOBUFS; - } - - net_buf_simple_reserve(&adv->b, BT_MESH_NET_HDR_LEN); - - if (ctl_op) { - net_buf_simple_add_u8(&adv->b, TRANS_CTL_HDR(*ctl_op, 0)); - } else if (BT_MESH_IS_DEV_KEY(tx->ctx->app_idx)) { - net_buf_simple_add_u8(&adv->b, UNSEG_HDR(0, 0)); - } else { - net_buf_simple_add_u8(&adv->b, UNSEG_HDR(1, tx->aid)); - } - - net_buf_simple_add_mem(&adv->b, sdu->data, sdu->len); - - if (IS_ENABLED(CONFIG_BT_MESH_FRIEND)) { - if (!bt_mesh_friend_queue_has_space(tx->sub->net_idx, - tx->src, tx->ctx->addr, - NULL, 1)) { - if (BT_MESH_ADDR_IS_UNICAST(tx->ctx->addr)) { - LOG_ERR("Not enough space in Friend Queue"); - bt_mesh_adv_unref(adv); - return -ENOBUFS; - } - - LOG_WRN("No space in Friend Queue"); - goto send; - } - - if (bt_mesh_friend_enqueue_tx(tx, BT_MESH_FRIEND_PDU_SINGLE, - NULL, 1, &adv->b) && - BT_MESH_ADDR_IS_UNICAST(tx->ctx->addr)) { - /* PDUs for a specific Friend should only go - * out through the Friend Queue. - */ - bt_mesh_adv_unref(adv); - send_cb_finalize(cb, cb_data); - return 0; - } - } - -send: - return bt_mesh_net_send(tx, adv, cb, cb_data); -} - -static inline uint8_t seg_len(bool ctl) -{ - if (ctl) { - return BT_MESH_CTL_SEG_SDU_MAX; - } else { - return BT_MESH_APP_SEG_SDU_MAX; - } -} - -bool bt_mesh_tx_in_progress(void) -{ - int i; - - for (i = 0; i < ARRAY_SIZE(seg_tx); i++) { - if (seg_tx[i].nack_count) { - return true; - } - } - - return false; -} - -static void seg_tx_done(struct seg_tx *tx, uint8_t seg_idx) -{ - k_mem_slab_free(&segs, (void *)tx->seg[seg_idx]); - tx->seg[seg_idx] = NULL; - tx->nack_count--; -} - -static bool seg_tx_blocks(struct seg_tx *tx, uint16_t src, uint16_t dst) -{ - return (tx->src == src) && (tx->dst == dst); -} - -static void seg_tx_unblock_check(struct seg_tx *tx) -{ - struct seg_tx *blocked = NULL; - int i; - - /* Unblock the first blocked tx with the same params. */ - for (i = 0; i < ARRAY_SIZE(seg_tx); ++i) { - if (&seg_tx[i] != tx && - seg_tx[i].blocked && - seg_tx_blocks(tx, seg_tx[i].src, seg_tx[i].dst) && - (!blocked || seg_tx[i].seq_auth < blocked->seq_auth)) { - blocked = &seg_tx[i]; - } - } - - if (blocked) { - LOG_DBG("Unblocked 0x%04x", (uint16_t)(blocked->seq_auth & TRANS_SEQ_ZERO_MASK)); - blocked->blocked = false; - k_work_reschedule(&blocked->retransmit, K_NO_WAIT); - } -} - -static void seg_tx_reset(struct seg_tx *tx) -{ - int i; - - /* If this call fails, the handler will exit early, as nack_count is 0. */ - (void)k_work_cancel_delayable(&tx->retransmit); - - tx->cb = NULL; - tx->cb_data = NULL; - tx->seq_auth = 0U; - tx->sub = NULL; - tx->src = BT_MESH_ADDR_UNASSIGNED; - tx->dst = BT_MESH_ADDR_UNASSIGNED; - tx->ack_src = BT_MESH_ADDR_UNASSIGNED; - tx->blocked = false; - - for (i = 0; i <= tx->seg_n && tx->nack_count; i++) { - if (!tx->seg[i]) { - continue; - } - - seg_tx_done(tx, i); - } - - tx->nack_count = 0; - tx->seg_send_started = 0; - - if (atomic_test_and_clear_bit(bt_mesh.flags, BT_MESH_IVU_PENDING)) { - LOG_DBG("Proceeding with pending IV Update"); - /* bt_mesh_net_iv_update() will re-enable the flag if this - * wasn't the only transfer. - */ - bt_mesh_net_iv_update(bt_mesh.iv_index, false); - } -} - -static inline void seg_tx_complete(struct seg_tx *tx, int err) -{ - const struct bt_mesh_send_cb *cb = tx->cb; - void *cb_data = tx->cb_data; - - seg_tx_unblock_check(tx); - - seg_tx_reset(tx); - - if (cb && cb->end) { - cb->end(err, cb_data); - } -} - -static void schedule_retransmit(struct seg_tx *tx) -{ - if (!tx->nack_count) { - return; - } - - LOG_DBG(""); - - /* If we haven't gone through all the segments for this attempt yet, - * (likely because of a buffer allocation failure or because we - * called this from inside bt_mesh_net_send), we should continue the - * retransmit immediately, as we just freed up a tx buffer. - */ - k_work_reschedule(&tx->retransmit, K_NO_WAIT); -} - -static void seg_send_start(uint16_t duration, int err, void *user_data) -{ - struct seg_tx *tx = user_data; - - if (!tx->started && tx->cb && tx->cb->start) { - tx->cb->start(duration, err, tx->cb_data); - tx->started = 1U; - } - - tx->seg_send_started = 1U; - - /* If there's an error in transmitting the 'sent' callback will never - * be called. Make sure that we kick the retransmit timer also in this - * case since otherwise we risk the transmission of becoming stale. - */ - if (err) { - schedule_retransmit(tx); - } -} - -static void seg_sent(int err, void *user_data) -{ - struct seg_tx *tx = user_data; - - if (!tx->seg_send_started) { - return; - } - - schedule_retransmit(tx); -} - -static const struct bt_mesh_send_cb seg_sent_cb = { - .start = seg_send_start, - .end = seg_sent, -}; - -static void seg_tx_buf_build(struct seg_tx *tx, uint8_t seg_o, - struct net_buf_simple *buf) -{ - uint16_t seq_zero = tx->seq_auth & TRANS_SEQ_ZERO_MASK; - uint8_t len = MIN(seg_len(tx->ctl), tx->len - (seg_len(tx->ctl) * seg_o)); - - net_buf_simple_add_u8(buf, tx->hdr); - net_buf_simple_add_u8(buf, (tx->aszmic << 7) | seq_zero >> 6); - net_buf_simple_add_u8(buf, (((seq_zero & 0x3f) << 2) | (seg_o >> 3))); - net_buf_simple_add_u8(buf, ((seg_o & 0x07) << 5) | tx->seg_n); - net_buf_simple_add_mem(buf, tx->seg[seg_o], len); -} - -static void seg_tx_send_unacked(struct seg_tx *tx) -{ - if (!tx->nack_count) { - return; - } - - struct bt_mesh_msg_ctx ctx = { - .net_idx = tx->sub->net_idx, - /* App idx only used by network to detect control messages: */ - .app_idx = (tx->ctl ? BT_MESH_KEY_UNUSED : 0), - .addr = tx->dst, - .send_rel = true, - .send_ttl = tx->ttl, - }; - struct bt_mesh_net_tx net_tx = { - .sub = tx->sub, - .ctx = &ctx, - .src = tx->src, - .xmit = tx->xmit, - .friend_cred = tx->friend_cred, - .aid = tx->hdr & AID_MASK, - }; - - if (!tx->attempts) { - if (BT_MESH_ADDR_IS_UNICAST(tx->dst)) { - LOG_ERR("Ran out of retransmit attempts"); - seg_tx_complete(tx, -ETIMEDOUT); - } else { - /* Segmented sending to groups doesn't have acks, so - * running out of attempts is the expected behavior. - */ - seg_tx_complete(tx, 0); - } - - return; - } - - LOG_DBG("SeqZero: 0x%04x Attempts: %u", (uint16_t)(tx->seq_auth & TRANS_SEQ_ZERO_MASK), - tx->attempts); - - while (tx->seg_o <= tx->seg_n) { - struct bt_mesh_adv *seg; - int err; - - if (!tx->seg[tx->seg_o]) { - /* Move on to the next segment */ - tx->seg_o++; - continue; - } - - seg = bt_mesh_adv_create(BT_MESH_ADV_DATA, BT_MESH_ADV_TAG_LOCAL, - tx->xmit, BUF_TIMEOUT); - if (!seg) { - LOG_DBG("Allocating segment failed"); - goto end; - } - - net_buf_simple_reserve(&seg->b, BT_MESH_NET_HDR_LEN); - seg_tx_buf_build(tx, tx->seg_o, &seg->b); - - LOG_DBG("Sending %u/%u", tx->seg_o, tx->seg_n); - - err = bt_mesh_net_send(&net_tx, seg, &seg_sent_cb, tx); - if (err) { - LOG_DBG("Sending segment failed"); - goto end; - } - - /* Move on to the next segment */ - tx->seg_o++; - - return; - } - - tx->seg_o = 0U; - tx->attempts--; - -end: - if (IS_ENABLED(CONFIG_BT_MESH_LOW_POWER) && - bt_mesh_lpn_established() && !bt_mesh_has_addr(ctx.addr)) { - bt_mesh_lpn_poll(); - } - - k_work_reschedule(&tx->retransmit, K_MSEC(SEG_RETRANSMIT_TIMEOUT(tx))); -} - -static void seg_retransmit(struct k_work *work) -{ - struct k_work_delayable *dwork = k_work_delayable_from_work(work); - struct seg_tx *tx = CONTAINER_OF(dwork, struct seg_tx, retransmit); - - seg_tx_send_unacked(tx); -} - -static int send_seg(struct bt_mesh_net_tx *net_tx, struct net_buf_simple *sdu, - const struct bt_mesh_send_cb *cb, void *cb_data, - uint8_t *ctl_op) -{ - bool blocked = false; - struct seg_tx *tx; - uint8_t seg_o; - int i; - - LOG_DBG("src 0x%04x dst 0x%04x app_idx 0x%04x aszmic %u sdu_len %u", net_tx->src, - net_tx->ctx->addr, net_tx->ctx->app_idx, net_tx->aszmic, sdu->len); - - for (tx = NULL, i = 0; i < ARRAY_SIZE(seg_tx); i++) { - if (seg_tx[i].nack_count) { - blocked |= seg_tx_blocks(&seg_tx[i], net_tx->src, - net_tx->ctx->addr); - } else if (!tx) { - tx = &seg_tx[i]; - } - } - - if (!tx) { - LOG_ERR("No multi-segment message contexts available"); - return -EBUSY; - } - - if (ctl_op) { - tx->hdr = TRANS_CTL_HDR(*ctl_op, 1); - } else if (BT_MESH_IS_DEV_KEY(net_tx->ctx->app_idx)) { - tx->hdr = SEG_HDR(0, 0); - } else { - tx->hdr = SEG_HDR(1, net_tx->aid); - } - - tx->src = net_tx->src; - tx->dst = net_tx->ctx->addr; - tx->seg_n = (sdu->len - 1) / seg_len(!!ctl_op); - tx->seg_o = 0; - tx->len = sdu->len; - tx->nack_count = tx->seg_n + 1; - tx->seq_auth = SEQ_AUTH(BT_MESH_NET_IVI_TX, bt_mesh.seq); - tx->sub = net_tx->sub; - tx->cb = cb; - tx->cb_data = cb_data; - tx->attempts = SEG_RETRANSMIT_ATTEMPTS; - tx->xmit = net_tx->xmit; - tx->aszmic = net_tx->aszmic; - tx->friend_cred = net_tx->friend_cred; - tx->blocked = blocked; - tx->started = 0; - tx->seg_send_started = 0; - tx->ctl = !!ctl_op; - tx->ttl = net_tx->ctx->send_ttl; - - LOG_DBG("SeqZero 0x%04x (segs: %u)", (uint16_t)(tx->seq_auth & TRANS_SEQ_ZERO_MASK), - tx->nack_count); - - if (IS_ENABLED(CONFIG_BT_MESH_FRIEND) && - !bt_mesh_friend_queue_has_space(tx->sub->net_idx, net_tx->src, - tx->dst, &tx->seq_auth, - tx->seg_n + 1) && - BT_MESH_ADDR_IS_UNICAST(tx->dst)) { - LOG_ERR("Not enough space in Friend Queue for %u segments", tx->seg_n + 1); - seg_tx_reset(tx); - return -ENOBUFS; - } - - for (seg_o = 0U; sdu->len; seg_o++) { - void *buf; - uint16_t len; - int err; - - err = k_mem_slab_alloc(&segs, &buf, BUF_TIMEOUT); - if (err) { - LOG_ERR("Out of segment buffers"); - seg_tx_reset(tx); - return -ENOBUFS; - } - - len = MIN(sdu->len, seg_len(!!ctl_op)); - memcpy(buf, net_buf_simple_pull_mem(sdu, len), len); - - LOG_DBG("seg %u: %s", seg_o, bt_hex(buf, len)); - - tx->seg[seg_o] = buf; - - if (IS_ENABLED(CONFIG_BT_MESH_FRIEND)) { - enum bt_mesh_friend_pdu_type type; - - NET_BUF_SIMPLE_DEFINE(seg, 16); - seg_tx_buf_build(tx, seg_o, &seg); - - if (seg_o == tx->seg_n) { - type = BT_MESH_FRIEND_PDU_COMPLETE; - } else { - type = BT_MESH_FRIEND_PDU_PARTIAL; - } - - if (bt_mesh_friend_enqueue_tx( - net_tx, type, ctl_op ? NULL : &tx->seq_auth, - tx->seg_n + 1, &seg) && - BT_MESH_ADDR_IS_UNICAST(net_tx->ctx->addr)) { - /* PDUs for a specific Friend should only go - * out through the Friend Queue. - */ - k_mem_slab_free(&segs, buf); - tx->seg[seg_o] = NULL; - } - - } - - } - - /* This can happen if segments only went into the Friend Queue */ - if (IS_ENABLED(CONFIG_BT_MESH_FRIEND) && !tx->seg[0]) { - seg_tx_reset(tx); - - /* If there was a callback notify sending immediately since - * there's no other way to track this (at least currently) - * with the Friend Queue. - */ - send_cb_finalize(cb, cb_data); - return 0; - } - - if (blocked) { - /* Move the sequence number, so we don't end up creating - * another segmented transmission with the same SeqZero while - * this one is blocked. - */ - bt_mesh_next_seq(); - LOG_DBG("Blocked."); - return 0; - } - - seg_tx_send_unacked(tx); - - return 0; -} - -static int trans_encrypt(const struct bt_mesh_net_tx *tx, const struct bt_mesh_key *key, - struct net_buf_simple *msg) -{ - struct bt_mesh_app_crypto_ctx crypto = { - .dev_key = BT_MESH_IS_DEV_KEY(tx->ctx->app_idx), - .aszmic = tx->aszmic, - .src = tx->src, - .dst = tx->ctx->addr, - .seq_num = bt_mesh.seq, - .iv_index = BT_MESH_NET_IVI_TX, - }; - - if (BT_MESH_ADDR_IS_VIRTUAL(tx->ctx->addr)) { - crypto.ad = tx->ctx->uuid; - if (crypto.ad == NULL) { - return -ENOENT; - } - } - - return bt_mesh_app_encrypt(key, &crypto, msg); -} - -int bt_mesh_trans_send(struct bt_mesh_net_tx *tx, struct net_buf_simple *msg, - const struct bt_mesh_send_cb *cb, void *cb_data) -{ - const struct bt_mesh_key *key; - uint8_t aid; - int err; - - if (msg->len < 1) { - LOG_ERR("Zero-length SDU not allowed"); - return -EINVAL; - } - - if (msg->len > BT_MESH_TX_SDU_MAX - BT_MESH_MIC_SHORT) { - LOG_ERR("Message too big: %u", msg->len); - return -EMSGSIZE; - } - - if (net_buf_simple_tailroom(msg) < BT_MESH_MIC_SHORT) { - LOG_ERR("Insufficient tailroom for Transport MIC"); - return -EINVAL; - } - - if (tx->ctx->send_ttl == BT_MESH_TTL_DEFAULT) { - tx->ctx->send_ttl = bt_mesh_default_ttl_get(); - } else if (tx->ctx->send_ttl > BT_MESH_TTL_MAX) { - LOG_ERR("TTL too large (max 127)"); - return -EINVAL; - } - - if (msg->len > BT_MESH_SDU_UNSEG_MAX) { - tx->ctx->send_rel = true; - } - - if (tx->ctx->addr == BT_MESH_ADDR_UNASSIGNED || - (!BT_MESH_ADDR_IS_UNICAST(tx->ctx->addr) && - BT_MESH_IS_DEV_KEY(tx->ctx->app_idx))) { - LOG_ERR("Invalid destination address"); - return -EINVAL; - } - - err = bt_mesh_keys_resolve(tx->ctx, &tx->sub, &key, &aid); - if (err) { - return err; - } - - LOG_DBG("net_idx 0x%04x app_idx 0x%04x dst 0x%04x", tx->sub->net_idx, tx->ctx->app_idx, - tx->ctx->addr); - LOG_DBG("len %u: %s", msg->len, bt_hex(msg->data, msg->len)); - - tx->xmit = bt_mesh_net_transmit_get(); - tx->aid = aid; - - if (!tx->ctx->send_rel || net_buf_simple_tailroom(msg) < 8) { - tx->aszmic = 0U; - } else { - tx->aszmic = 1U; - } - - err = trans_encrypt(tx, key, msg); - if (err) { - return err; - } - - if (tx->ctx->send_rel) { - err = send_seg(tx, msg, cb, cb_data, NULL); - } else { - err = send_unseg(tx, msg, cb, cb_data, NULL); - } - - return err; -} - -static void seg_rx_assemble(struct seg_rx *rx, struct net_buf_simple *buf, - uint8_t aszmic) -{ - int i; - - net_buf_simple_reset(buf); - - for (i = 0; i <= rx->seg_n; i++) { - net_buf_simple_add_mem(buf, rx->seg[i], - MIN(seg_len(rx->ctl), - rx->len - (i * seg_len(rx->ctl)))); - } - - /* Adjust the length to not contain the MIC at the end */ - if (!rx->ctl) { - buf->len -= APP_MIC_LEN(aszmic); - } -} - -struct decrypt_ctx { - struct bt_mesh_app_crypto_ctx crypto; - struct net_buf_simple *buf; - struct net_buf_simple *sdu; - struct seg_rx *seg; -}; - -static int sdu_try_decrypt(struct bt_mesh_net_rx *rx, const struct bt_mesh_key *key, - void *cb_data) -{ - struct decrypt_ctx *ctx = cb_data; - int err; - - ctx->crypto.ad = NULL; - - do { - if (ctx->seg) { - seg_rx_assemble(ctx->seg, ctx->buf, ctx->crypto.aszmic); - } - - if (BT_MESH_ADDR_IS_VIRTUAL(rx->ctx.recv_dst)) { - ctx->crypto.ad = bt_mesh_va_uuid_get(rx->ctx.recv_dst, ctx->crypto.ad, - NULL); - - if (!ctx->crypto.ad) { - return -ENOENT; - } - } - - net_buf_simple_reset(ctx->sdu); - - err = bt_mesh_app_decrypt(key, &ctx->crypto, ctx->buf, ctx->sdu); - } while (err && ctx->crypto.ad != NULL); - - if (!err && BT_MESH_ADDR_IS_VIRTUAL(rx->ctx.recv_dst)) { - rx->ctx.uuid = ctx->crypto.ad; - } - - return err; -} - -static int sdu_recv(struct bt_mesh_net_rx *rx, uint8_t hdr, uint8_t aszmic, - struct net_buf_simple *buf, struct net_buf_simple *sdu, - struct seg_rx *seg) -{ - struct decrypt_ctx ctx = { - .crypto = { - .dev_key = !AKF(&hdr), - .aszmic = aszmic, - .src = rx->ctx.addr, - .dst = rx->ctx.recv_dst, - .seq_num = seg ? (seg->seq_auth & 0xffffff) : rx->seq, - .iv_index = BT_MESH_NET_IVI_RX(rx), - }, - .buf = buf, - .sdu = sdu, - .seg = seg, - }; - - LOG_DBG("AKF %u AID 0x%02x", !ctx.crypto.dev_key, AID(&hdr)); - - if (!rx->local_match) { - return 0; - } - - rx->ctx.app_idx = bt_mesh_app_key_find(ctx.crypto.dev_key, AID(&hdr), - rx, sdu_try_decrypt, &ctx); - if (rx->ctx.app_idx == BT_MESH_KEY_UNUSED) { - LOG_DBG("No matching AppKey"); - return 0; - } - - LOG_DBG("Decrypted (AppIdx: 0x%03x)", rx->ctx.app_idx); - - bt_mesh_model_recv(&rx->ctx, sdu); - - return 0; -} - -static struct seg_tx *seg_tx_lookup(uint16_t seq_zero, uint8_t obo, uint16_t addr) -{ - struct seg_tx *tx; - int i; - - for (i = 0; i < ARRAY_SIZE(seg_tx); i++) { - tx = &seg_tx[i]; - - if ((tx->seq_auth & TRANS_SEQ_ZERO_MASK) != seq_zero) { - continue; - } - - if (tx->dst == addr) { - return tx; - } - - /* If the expected remote address doesn't match, - * but the OBO flag is set and this is the first - * acknowledgment, assume it's a Friend that's - * responding and therefore accept the message. - */ - if (obo && (tx->nack_count == tx->seg_n + 1 || tx->ack_src == addr)) { - tx->ack_src = addr; - return tx; - } - } - - return NULL; -} - -static int trans_ack(struct bt_mesh_net_rx *rx, uint8_t hdr, - struct net_buf_simple *buf, uint64_t *seq_auth) -{ - struct seg_tx *tx; - unsigned int bit; - uint32_t ack; - uint16_t seq_zero; - uint8_t obo; - - if (buf->len < 6) { - LOG_ERR("Too short ack message"); - return -EINVAL; - } - - seq_zero = net_buf_simple_pull_be16(buf); - obo = seq_zero >> 15; - seq_zero = (seq_zero >> 2) & TRANS_SEQ_ZERO_MASK; - - if (IS_ENABLED(CONFIG_BT_MESH_FRIEND) && rx->friend_match) { - LOG_DBG("Ack for LPN 0x%04x of this Friend", rx->ctx.recv_dst); - /* Best effort - we don't have enough info for true SeqAuth */ - *seq_auth = SEQ_AUTH(BT_MESH_NET_IVI_RX(rx), seq_zero); - return 0; - } - - ack = net_buf_simple_pull_be32(buf); - - LOG_DBG("OBO %u seq_zero 0x%04x ack 0x%08x", obo, seq_zero, ack); - - tx = seg_tx_lookup(seq_zero, obo, rx->ctx.addr); - if (!tx) { - LOG_WRN("No matching TX context for ack"); - return -EINVAL; - } - - if (!BT_MESH_ADDR_IS_UNICAST(tx->dst)) { - LOG_ERR("Received ack for group seg"); - return -EINVAL; - } - - *seq_auth = tx->seq_auth; - - if (!ack) { - LOG_WRN("SDU canceled"); - seg_tx_complete(tx, -ECANCELED); - return 0; - } - - if (find_msb_set(ack) - 1 > tx->seg_n) { - LOG_ERR("Too large segment number in ack"); - return -EINVAL; - } - - while ((bit = find_lsb_set(ack))) { - if (tx->seg[bit - 1]) { - LOG_DBG("seg %u/%u acked", bit - 1, tx->seg_n); - seg_tx_done(tx, bit - 1); - } - - ack &= ~BIT(bit - 1); - } - - if (tx->nack_count) { - /* According to MshPRFv1.0.1: 3.5.3.3, we should reset the retransmit timer and - * retransmit immediately when receiving a valid ack message. Don't reset the - * retransmit timer if we didn't finish sending segments. - */ - if (tx->seg_o == 0) { - k_work_reschedule(&tx->retransmit, K_NO_WAIT); - } - } else { - LOG_DBG("SDU TX complete"); - seg_tx_complete(tx, 0); - } - - return 0; -} - -static int ctl_recv(struct bt_mesh_net_rx *rx, uint8_t hdr, - struct net_buf_simple *buf, uint64_t *seq_auth) -{ - uint8_t ctl_op = TRANS_CTL_OP(&hdr); - - LOG_DBG("OpCode 0x%02x len %u", ctl_op, buf->len); - - switch (ctl_op) { - case TRANS_CTL_OP_ACK: - return trans_ack(rx, hdr, buf, seq_auth); - case TRANS_CTL_OP_HEARTBEAT: - return bt_mesh_hb_recv(rx, buf); - } - - /* Only acks and heartbeats may need processing without local_match */ - if (!rx->local_match) { - return 0; - } - - if (IS_ENABLED(CONFIG_BT_MESH_FRIEND) && !bt_mesh_lpn_established()) { - switch (ctl_op) { - case TRANS_CTL_OP_FRIEND_POLL: - return bt_mesh_friend_poll(rx, buf); - case TRANS_CTL_OP_FRIEND_REQ: - return bt_mesh_friend_req(rx, buf); - case TRANS_CTL_OP_FRIEND_CLEAR: - return bt_mesh_friend_clear(rx, buf); - case TRANS_CTL_OP_FRIEND_CLEAR_CFM: - return bt_mesh_friend_clear_cfm(rx, buf); - case TRANS_CTL_OP_FRIEND_SUB_ADD: - return bt_mesh_friend_sub_add(rx, buf); - case TRANS_CTL_OP_FRIEND_SUB_REM: - return bt_mesh_friend_sub_rem(rx, buf); - } - } - -#if defined(CONFIG_BT_MESH_LOW_POWER) - if (ctl_op == TRANS_CTL_OP_FRIEND_OFFER) { - return bt_mesh_lpn_friend_offer(rx, buf); - } - - if (rx->ctx.addr == bt_mesh.lpn.frnd) { - if (ctl_op == TRANS_CTL_OP_FRIEND_CLEAR_CFM) { - return bt_mesh_lpn_friend_clear_cfm(rx, buf); - } - - if (!rx->friend_cred) { - LOG_WRN("Message from friend with wrong credentials"); - return -EINVAL; - } - - switch (ctl_op) { - case TRANS_CTL_OP_FRIEND_UPDATE: - return bt_mesh_lpn_friend_update(rx, buf); - case TRANS_CTL_OP_FRIEND_SUB_CFM: - return bt_mesh_lpn_friend_sub_cfm(rx, buf); - } - } -#endif /* CONFIG_BT_MESH_LOW_POWER */ - - LOG_WRN("Unhandled TransOpCode 0x%02x", ctl_op); - - return -ENOENT; -} - -static int trans_unseg(struct net_buf_simple *buf, struct bt_mesh_net_rx *rx, - uint64_t *seq_auth) -{ - NET_BUF_SIMPLE_DEFINE_STATIC(sdu, BT_MESH_SDU_UNSEG_MAX); - uint8_t hdr; - - LOG_DBG("AFK %u AID 0x%02x", AKF(buf->data), AID(buf->data)); - - if (buf->len < 1) { - LOG_ERR("Too small unsegmented PDU"); - return -EINVAL; - } - - if (bt_mesh_rpl_check(rx, NULL)) { - LOG_WRN("Replay: src 0x%04x dst 0x%04x seq 0x%06x", rx->ctx.addr, rx->ctx.recv_dst, - rx->seq); - return -EINVAL; - } - - hdr = net_buf_simple_pull_u8(buf); - - if (rx->ctl) { - return ctl_recv(rx, hdr, buf, seq_auth); - } - - if (buf->len < 1 + APP_MIC_LEN(0)) { - LOG_ERR("Too short SDU + MIC"); - return -EINVAL; - } - - /* Adjust the length to not contain the MIC at the end */ - buf->len -= APP_MIC_LEN(0); - - return sdu_recv(rx, hdr, 0, buf, &sdu, NULL); -} - -static inline int32_t ack_timeout(struct seg_rx *rx) -{ - int32_t to; - uint8_t ttl; - - if (rx->ttl == BT_MESH_TTL_DEFAULT) { - ttl = bt_mesh_default_ttl_get(); - } else { - ttl = rx->ttl; - } - - /* The acknowledgment timer shall be set to a minimum of - * 150 + 50 * TTL milliseconds. - */ - to = CONFIG_BT_MESH_SEG_ACK_BASE_TIMEOUT + - (ttl * (int32_t)CONFIG_BT_MESH_SEG_ACK_PER_HOP_TIMEOUT); - - /* Add timeout for evenry not yet received segment. */ - to += ((rx->seg_n + 1) - POPCOUNT(rx->block)) * - (int32_t)CONFIG_BT_MESH_SEG_ACK_PER_SEGMENT_TIMEOUT; - - /* Make sure we don't send more frequently than the duration for - * each packet (default is 400ms). - */ - return MAX(to, 400); -} - -int bt_mesh_ctl_send(struct bt_mesh_net_tx *tx, uint8_t ctl_op, void *data, - size_t data_len, - const struct bt_mesh_send_cb *cb, void *cb_data) -{ - struct net_buf_simple buf; - - if (tx->ctx->send_ttl == BT_MESH_TTL_DEFAULT) { - tx->ctx->send_ttl = bt_mesh_default_ttl_get(); - } else if (tx->ctx->send_ttl > BT_MESH_TTL_MAX) { - LOG_ERR("TTL too large (max 127)"); - return -EINVAL; - } - - net_buf_simple_init_with_data(&buf, data, data_len); - - if (data_len > BT_MESH_SDU_UNSEG_MAX) { - tx->ctx->send_rel = true; - } - - tx->ctx->app_idx = BT_MESH_KEY_UNUSED; - - if (tx->ctx->addr == BT_MESH_ADDR_UNASSIGNED || - BT_MESH_ADDR_IS_VIRTUAL(tx->ctx->addr)) { - LOG_ERR("Invalid destination address"); - return -EINVAL; - } - - LOG_DBG("src 0x%04x dst 0x%04x ttl 0x%02x ctl 0x%02x", tx->src, tx->ctx->addr, - tx->ctx->send_ttl, ctl_op); - LOG_DBG("len %zu: %s", data_len, bt_hex(data, data_len)); - - if (tx->ctx->send_rel) { - return send_seg(tx, &buf, cb, cb_data, &ctl_op); - } else { - return send_unseg(tx, &buf, cb, cb_data, &ctl_op); - } -} - -static int send_ack(struct bt_mesh_subnet *sub, uint16_t src, uint16_t dst, - uint8_t ttl, uint64_t *seq_auth, uint32_t block, uint8_t obo) -{ - struct bt_mesh_msg_ctx ctx = { - .net_idx = sub->net_idx, - .app_idx = BT_MESH_KEY_UNUSED, - .addr = dst, - .send_ttl = ttl, - }; - struct bt_mesh_net_tx tx = { - .sub = sub, - .ctx = &ctx, - .src = obo ? bt_mesh_primary_addr() : src, - .xmit = bt_mesh_net_transmit_get(), - }; - uint16_t seq_zero = *seq_auth & TRANS_SEQ_ZERO_MASK; - uint8_t buf[6]; - - LOG_DBG("SeqZero 0x%04x Block 0x%08x OBO %u", seq_zero, block, obo); - - if (bt_mesh_lpn_established() && !bt_mesh_has_addr(ctx.addr)) { - LOG_WRN("Not sending ack when LPN is enabled"); - return 0; - } - - /* This can happen if the segmented message was destined for a group - * or virtual address. - */ - if (!BT_MESH_ADDR_IS_UNICAST(src)) { - LOG_DBG("Not sending ack for non-unicast address"); - return 0; - } - - sys_put_be16(((seq_zero << 2) & 0x7ffc) | (obo << 15), buf); - sys_put_be32(block, &buf[2]); - - return bt_mesh_ctl_send(&tx, TRANS_CTL_OP_ACK, buf, sizeof(buf), - NULL, NULL); -} - -static void seg_rx_reset(struct seg_rx *rx, bool full_reset) -{ - int i; - - LOG_DBG("rx %p", rx); - - /* If this fails, the handler will exit early on the next execution, as - * it checks rx->in_use. - */ - (void)k_work_cancel_delayable(&rx->ack); - - if (IS_ENABLED(CONFIG_BT_MESH_FRIEND) && rx->obo && - rx->block != BLOCK_COMPLETE(rx->seg_n)) { - LOG_WRN("Clearing incomplete buffers from Friend queue"); - bt_mesh_friend_clear_incomplete(rx->sub, rx->src, rx->dst, - &rx->seq_auth); - } - - for (i = 0; i <= rx->seg_n; i++) { - if (!rx->seg[i]) { - continue; - } - - k_mem_slab_free(&segs, rx->seg[i]); - rx->seg[i] = NULL; - } - - rx->in_use = 0U; - - /* We don't always reset these values since we need to be able to - * send an ack if we receive a segment after we've already received - * the full SDU. - */ - if (full_reset) { - rx->seq_auth = 0U; - rx->sub = NULL; - rx->src = BT_MESH_ADDR_UNASSIGNED; - rx->dst = BT_MESH_ADDR_UNASSIGNED; - } -} - -static void seg_ack(struct k_work *work) -{ - struct k_work_delayable *dwork = k_work_delayable_from_work(work); - struct seg_rx *rx = CONTAINER_OF(dwork, struct seg_rx, ack); - int32_t timeout; - - if (!rx->in_use || rx->block == BLOCK_COMPLETE(rx->seg_n)) { - /* Cancellation of this timer may have failed. If it fails as - * part of seg_reset, in_use will be false. - * If it fails as part of the processing of a fully received - * SDU, the ack is already being sent from the receive handler, - * and the timer based ack sending can be ignored. - */ - return; - } - - LOG_DBG("rx %p", rx); - - if (k_uptime_get_32() - rx->last > (60 * MSEC_PER_SEC)) { - LOG_WRN("Incomplete timer expired"); - seg_rx_reset(rx, false); - - if (IS_ENABLED(CONFIG_BT_TESTING)) { - bt_test_mesh_trans_incomp_timer_exp(); - } - - return; - } - - send_ack(rx->sub, rx->dst, rx->src, rx->ttl, &rx->seq_auth, - rx->block, rx->obo); - - timeout = ack_timeout(rx); - k_work_schedule(&rx->ack, K_MSEC(timeout)); -} - -static inline bool sdu_len_is_ok(bool ctl, uint8_t seg_n) -{ - return (seg_n < BT_MESH_RX_SEG_MAX); -} - -static struct seg_rx *seg_rx_find(struct bt_mesh_net_rx *net_rx, - const uint64_t *seq_auth) -{ - int i; - - for (i = 0; i < ARRAY_SIZE(seg_rx); i++) { - struct seg_rx *rx = &seg_rx[i]; - - if (rx->src != net_rx->ctx.addr || - rx->dst != net_rx->ctx.recv_dst) { - continue; - } - - /* Return newer RX context in addition to an exact match, so - * the calling function can properly discard an old SeqAuth. - */ - if (rx->seq_auth >= *seq_auth) { - return rx; - } - - if (rx->in_use) { - LOG_WRN("Duplicate SDU from src 0x%04x", net_rx->ctx.addr); - - /* Clear out the old context since the sender - * has apparently started sending a new SDU. - */ - seg_rx_reset(rx, true); - - /* Return non-match so caller can re-allocate */ - return NULL; - } - } - - return NULL; -} - -static bool seg_rx_is_valid(struct seg_rx *rx, struct bt_mesh_net_rx *net_rx, - const uint8_t *hdr, uint8_t seg_n) -{ - if (rx->hdr != *hdr || rx->seg_n != seg_n) { - LOG_ERR("Invalid segment for ongoing session"); - return false; - } - - if (rx->src != net_rx->ctx.addr || rx->dst != net_rx->ctx.recv_dst) { - LOG_ERR("Invalid source or destination for segment"); - return false; - } - - if (rx->ctl != net_rx->ctl) { - LOG_ERR("Inconsistent CTL in segment"); - return false; - } - - return true; -} - -static struct seg_rx *seg_rx_alloc(struct bt_mesh_net_rx *net_rx, - const uint8_t *hdr, const uint64_t *seq_auth, - uint8_t seg_n) -{ - int i; - - /* No race condition on this check, as this function only executes in - * the collaborative Bluetooth rx thread: - */ - if (k_mem_slab_num_free_get(&segs) < 1) { - LOG_WRN("Not enough segments for incoming message"); - return NULL; - } - - for (i = 0; i < ARRAY_SIZE(seg_rx); i++) { - struct seg_rx *rx = &seg_rx[i]; - - if (rx->in_use) { - continue; - } - - rx->in_use = 1U; - rx->sub = net_rx->sub; - rx->ctl = net_rx->ctl; - rx->seq_auth = *seq_auth; - rx->seg_n = seg_n; - rx->hdr = *hdr; - rx->ttl = net_rx->ctx.send_ttl; - rx->src = net_rx->ctx.addr; - rx->dst = net_rx->ctx.recv_dst; - rx->block = 0U; - - LOG_DBG("New RX context. Block Complete 0x%08x", BLOCK_COMPLETE(seg_n)); - - return rx; - } - - return NULL; -} - -static int trans_seg(struct net_buf_simple *buf, struct bt_mesh_net_rx *net_rx, - enum bt_mesh_friend_pdu_type *pdu_type, uint64_t *seq_auth, - uint8_t *seg_count) -{ - struct bt_mesh_rpl *rpl = NULL; - struct seg_rx *rx; - uint8_t *hdr = buf->data; - uint16_t seq_zero; - uint32_t auth_seqnum; - uint8_t seg_n; - uint8_t seg_o; - int err; - - if (buf->len < 5) { - LOG_ERR("Too short segmented message (len %u)", buf->len); - return -EINVAL; - } - - if (bt_mesh_rpl_check(net_rx, &rpl)) { - LOG_WRN("Replay: src 0x%04x dst 0x%04x seq 0x%06x", net_rx->ctx.addr, - net_rx->ctx.recv_dst, net_rx->seq); - return -EINVAL; - } - - LOG_DBG("ASZMIC %u AKF %u AID 0x%02x", ASZMIC(hdr), AKF(hdr), AID(hdr)); - - net_buf_simple_pull(buf, 1); - - seq_zero = net_buf_simple_pull_be16(buf); - seg_o = (seq_zero & 0x03) << 3; - seq_zero = (seq_zero >> 2) & TRANS_SEQ_ZERO_MASK; - seg_n = net_buf_simple_pull_u8(buf); - seg_o |= seg_n >> 5; - seg_n &= 0x1f; - - LOG_DBG("SeqZero 0x%04x SegO %u SegN %u", seq_zero, seg_o, seg_n); - - if (seg_o > seg_n) { - LOG_ERR("SegO greater than SegN (%u > %u)", seg_o, seg_n); - return -EINVAL; - } - - /* According to MshPRFv1.0.1: - * "The SeqAuth is composed of the IV Index and the sequence number - * (SEQ) of the first segment" - * - * Therefore we need to calculate very first SEQ in order to find - * seqAuth. We can calculate as below: - * - * SEQ(0) = SEQ(n) - (delta between seqZero and SEQ(n) by looking into - * 14 least significant bits of SEQ(n)) - * - * Mentioned delta shall be >= 0, if it is not then seq_auth will - * be broken and it will be verified by the code below. - */ - *seq_auth = SEQ_AUTH(BT_MESH_NET_IVI_RX(net_rx), - (net_rx->seq - - ((((net_rx->seq & BIT_MASK(14)) - seq_zero)) & - BIT_MASK(13)))); - auth_seqnum = *seq_auth & BIT_MASK(24); - *seg_count = seg_n + 1; - - /* Look for old RX sessions */ - rx = seg_rx_find(net_rx, seq_auth); - if (rx) { - /* Discard old SeqAuth packet */ - if (rx->seq_auth > *seq_auth) { - LOG_WRN("Ignoring old SeqAuth"); - return -EINVAL; - } - - if (!seg_rx_is_valid(rx, net_rx, hdr, seg_n)) { - return -EINVAL; - } - - if (rx->in_use) { - LOG_DBG("Existing RX context. Block 0x%08x", rx->block); - goto found_rx; - } - - if (rx->block == BLOCK_COMPLETE(rx->seg_n)) { - LOG_DBG("Got segment for already complete SDU"); - - send_ack(net_rx->sub, net_rx->ctx.recv_dst, - net_rx->ctx.addr, net_rx->ctx.send_ttl, - seq_auth, rx->block, rx->obo); - - if (rpl) { - bt_mesh_rpl_update(rpl, net_rx); - } - - return -EALREADY; - } - - /* We ignore instead of sending block ack 0 since the - * ack timer is always smaller than the incomplete - * timer, i.e. the sender is misbehaving. - */ - LOG_WRN("Got segment for canceled SDU"); - return -EINVAL; - } - - /* Bail out early if we're not ready to receive such a large SDU */ - if (!sdu_len_is_ok(net_rx->ctl, seg_n)) { - LOG_ERR("Too big incoming SDU length"); - send_ack(net_rx->sub, net_rx->ctx.recv_dst, net_rx->ctx.addr, - net_rx->ctx.send_ttl, seq_auth, 0, - net_rx->friend_match); - return -EMSGSIZE; - } - - /* Verify early that there will be space in the Friend Queue(s) in - * case this message is destined to an LPN of ours. - */ - if (IS_ENABLED(CONFIG_BT_MESH_FRIEND) && - net_rx->friend_match && !net_rx->local_match && - !bt_mesh_friend_queue_has_space(net_rx->sub->net_idx, - net_rx->ctx.addr, - net_rx->ctx.recv_dst, seq_auth, - *seg_count)) { - LOG_ERR("No space in Friend Queue for %u segments", *seg_count); - send_ack(net_rx->sub, net_rx->ctx.recv_dst, net_rx->ctx.addr, - net_rx->ctx.send_ttl, seq_auth, 0, - net_rx->friend_match); - return -ENOBUFS; - } - - /* Keep track of the received SeqAuth values received from this address - * and discard segmented messages that are not newer, as described in - * MshPRFv1.0.1: 3.5.3.4. - * - * The logic on the first segmented receive is a bit special, since the - * initial value of rpl->seg is 0, which would normally fail the - * comparison check with auth_seqnum: - * - If this is the first time we receive from this source, rpl->src - * will be 0, and we can skip this check. - * - If this is the first time we receive from this source on the new IV - * index, rpl->old_iv will be set, and the check is also skipped. - * - If this is the first segmented message on the new IV index, but we - * have received an unsegmented message already, the unsegmented - * message will have reset rpl->seg to 0, and this message's SeqAuth - * cannot be zero. - */ - if (rpl && rpl->src && auth_seqnum <= rpl->seg && - (!rpl->old_iv || net_rx->old_iv)) { - LOG_WRN("Ignoring old SeqAuth 0x%06x", auth_seqnum); - return -EALREADY; - } - - /* Look for free slot for a new RX session */ - rx = seg_rx_alloc(net_rx, hdr, seq_auth, seg_n); - if (!rx) { - /* Warn but don't cancel since the existing slots will - * eventually be freed up and we'll be able to process - * this one. - */ - LOG_WRN("No free slots for new incoming segmented messages"); - return -ENOMEM; - } - - rx->obo = net_rx->friend_match; - -found_rx: - if (BIT(seg_o) & rx->block) { - LOG_DBG("Received already received fragment"); - return -EALREADY; - } - - /* All segments, except the last one, must either have 8 bytes of - * payload (for 64bit Net MIC) or 12 bytes of payload (for 32bit - * Net MIC). - */ - if (seg_o == seg_n) { - /* Set the expected final buffer length */ - rx->len = seg_n * seg_len(rx->ctl) + buf->len; - LOG_DBG("Target len %u * %u + %u = %u", seg_n, seg_len(rx->ctl), buf->len, rx->len); - - if (rx->len > BT_MESH_RX_SDU_MAX) { - LOG_ERR("Too large SDU len"); - send_ack(net_rx->sub, net_rx->ctx.recv_dst, - net_rx->ctx.addr, net_rx->ctx.send_ttl, - seq_auth, 0, rx->obo); - seg_rx_reset(rx, true); - return -EMSGSIZE; - } - } else { - if (buf->len != seg_len(rx->ctl)) { - LOG_ERR("Incorrect segment size for message type"); - return -EINVAL; - } - } - - /* Reset the Incomplete Timer */ - rx->last = k_uptime_get_32(); - - if (!bt_mesh_lpn_established()) { - int32_t timeout = ack_timeout(rx); - /* Should only start ack timer if it isn't running already: */ - k_work_schedule(&rx->ack, K_MSEC(timeout)); - } - - /* Allocated segment here */ - err = k_mem_slab_alloc(&segs, &rx->seg[seg_o], K_NO_WAIT); - if (err) { - LOG_WRN("Unable allocate buffer for Seg %u", seg_o); - return -ENOBUFS; - } - - memcpy(rx->seg[seg_o], buf->data, buf->len); - - LOG_DBG("Received %u/%u", seg_o, seg_n); - - /* Mark segment as received */ - rx->block |= BIT(seg_o); - - if (rx->block != BLOCK_COMPLETE(seg_n)) { - *pdu_type = BT_MESH_FRIEND_PDU_PARTIAL; - return 0; - } - - LOG_DBG("Complete SDU"); - - if (rpl) { - bt_mesh_rpl_update(rpl, net_rx); - /* Update the seg, unless it has already been surpassed: - * This needs to happen after rpl_update to ensure that the IV - * update reset logic inside rpl_update doesn't overwrite the - * change. - */ - rpl->seg = MAX(rpl->seg, auth_seqnum); - } - - *pdu_type = BT_MESH_FRIEND_PDU_COMPLETE; - - /* If this fails, the work handler will either exit early because the - * block is fully received, or rx->in_use is false. - */ - (void)k_work_cancel_delayable(&rx->ack); - send_ack(net_rx->sub, net_rx->ctx.recv_dst, net_rx->ctx.addr, - net_rx->ctx.send_ttl, seq_auth, rx->block, rx->obo); - - if (net_rx->ctl) { - NET_BUF_SIMPLE_DEFINE(sdu, BT_MESH_RX_CTL_MAX); - seg_rx_assemble(rx, &sdu, 0U); - err = ctl_recv(net_rx, *hdr, &sdu, seq_auth); - } else if (rx->len < 1 + APP_MIC_LEN(ASZMIC(hdr))) { - LOG_ERR("Too short SDU + MIC"); - err = -EINVAL; - } else { - NET_BUF_SIMPLE_DEFINE_STATIC(seg_buf, BT_MESH_RX_SDU_MAX); - struct net_buf_simple sdu; - - /* Decrypting in place to avoid creating two assembly buffers. - * We'll reassemble the buffer from the segments before each - * decryption attempt. - */ - net_buf_simple_init(&seg_buf, 0); - net_buf_simple_init_with_data( - &sdu, seg_buf.data, rx->len - APP_MIC_LEN(ASZMIC(hdr))); - - err = sdu_recv(net_rx, *hdr, ASZMIC(hdr), &seg_buf, &sdu, rx); - } - - seg_rx_reset(rx, false); - - return err; -} - -int bt_mesh_trans_recv(struct net_buf_simple *buf, struct bt_mesh_net_rx *rx) -{ - uint64_t seq_auth = TRANS_SEQ_AUTH_NVAL; - enum bt_mesh_friend_pdu_type pdu_type = BT_MESH_FRIEND_PDU_SINGLE; - struct net_buf_simple_state state; - uint8_t seg_count = 0; - int err; - - if (IS_ENABLED(CONFIG_BT_MESH_FRIEND)) { - rx->friend_match = bt_mesh_friend_match(rx->sub->net_idx, - rx->ctx.recv_dst); - } else { - rx->friend_match = false; - } - - LOG_DBG("src 0x%04x dst 0x%04x seq 0x%08x friend_match %u", rx->ctx.addr, rx->ctx.recv_dst, - rx->seq, rx->friend_match); - - /* Remove network headers */ - net_buf_simple_pull(buf, BT_MESH_NET_HDR_LEN); - - LOG_DBG("Payload %s", bt_hex(buf->data, buf->len)); - - if (IS_ENABLED(CONFIG_BT_TESTING)) { - bt_test_mesh_net_recv(rx->ctx.recv_ttl, rx->ctl, rx->ctx.addr, - rx->ctx.recv_dst, buf->data, buf->len); - } - - /* If LPN mode is enabled messages are only accepted when we've - * requested the Friend to send them. The messages must also - * be encrypted using the Friend Credentials. - */ - if (IS_ENABLED(CONFIG_BT_MESH_LOW_POWER) && - bt_mesh_lpn_established() && rx->net_if == BT_MESH_NET_IF_ADV && - (!bt_mesh_lpn_waiting_update() || !rx->friend_cred)) { - LOG_WRN("Ignoring unexpected message in Low Power mode"); - return -EAGAIN; - } - - /* Save the app-level state so the buffer can later be placed in - * the Friend Queue. - */ - net_buf_simple_save(buf, &state); - - if (SEG(buf->data)) { - /* Segmented messages must match a local element or an - * LPN of this Friend. - */ - if (!rx->local_match && !rx->friend_match) { - return 0; - } - - err = trans_seg(buf, rx, &pdu_type, &seq_auth, &seg_count); - } else { - seg_count = 1; - err = trans_unseg(buf, rx, &seq_auth); - } - - /* Notify LPN state machine so a Friend Poll will be sent. */ - if (IS_ENABLED(CONFIG_BT_MESH_LOW_POWER)) { - bt_mesh_lpn_msg_received(rx); - } - - net_buf_simple_restore(buf, &state); - - if (IS_ENABLED(CONFIG_BT_MESH_FRIEND) && rx->friend_match && !err) { - if (seq_auth == TRANS_SEQ_AUTH_NVAL) { - bt_mesh_friend_enqueue_rx(rx, pdu_type, NULL, - seg_count, buf); - } else { - bt_mesh_friend_enqueue_rx(rx, pdu_type, &seq_auth, - seg_count, buf); - } - } - - return err; -} - -void bt_mesh_rx_reset(void) -{ - int i; - - LOG_DBG(""); - - for (i = 0; i < ARRAY_SIZE(seg_rx); i++) { - seg_rx_reset(&seg_rx[i], true); - } -} - -void bt_mesh_trans_reset(void) -{ - int i; - - bt_mesh_rx_reset(); - - LOG_DBG(""); - - for (i = 0; i < ARRAY_SIZE(seg_tx); i++) { - seg_tx_reset(&seg_tx[i]); - } - - bt_mesh_rpl_clear(); - bt_mesh_va_clear(); -} - -void bt_mesh_trans_init(void) -{ - int i; - - for (i = 0; i < ARRAY_SIZE(seg_tx); i++) { - k_work_init_delayable(&seg_tx[i].retransmit, seg_retransmit); - } - - for (i = 0; i < ARRAY_SIZE(seg_rx); i++) { - k_work_init_delayable(&seg_rx[i].ack, seg_ack); - } -} diff --git a/tests/bluetooth/mesh/blob_io_flash/prj.conf b/tests/bluetooth/mesh/blob_io_flash/prj.conf index 2a0e98421fa..1e7864aa05d 100644 --- a/tests/bluetooth/mesh/blob_io_flash/prj.conf +++ b/tests/bluetooth/mesh/blob_io_flash/prj.conf @@ -15,7 +15,6 @@ CONFIG_BT_NO_DRIVER=y CONFIG_BT_OBSERVER=y CONFIG_BT_PERIPHERAL=y CONFIG_BT_MESH=y -CONFIG_BT_MESH_V1d1=y CONFIG_BT_MESH_BLOB_SRV=y CONFIG_BT_MESH_BLOB_CLI=y CONFIG_BT_MESH_BLOB_IO_FLASH=y diff --git a/tests/bluetooth/mesh_shell/proxy_solicitation.conf b/tests/bluetooth/mesh_shell/proxy_solicitation.conf index f900d743516..51e50c07a01 100644 --- a/tests/bluetooth/mesh_shell/proxy_solicitation.conf +++ b/tests/bluetooth/mesh_shell/proxy_solicitation.conf @@ -1,4 +1,3 @@ -CONFIG_BT_MESH_V1d1=y CONFIG_BT_CENTRAL=y CONFIG_BT_MESH_PROXY_CLIENT=y CONFIG_BT_MESH_PROXY_SOLICITATION=y diff --git a/tests/bluetooth/tester/overlay-mesh-v1d1.conf b/tests/bluetooth/tester/overlay-mesh-v1d1.conf deleted file mode 100644 index 52045ce34df..00000000000 --- a/tests/bluetooth/tester/overlay-mesh-v1d1.conf +++ /dev/null @@ -1,30 +0,0 @@ -CONFIG_ENTROPY_GENERATOR=y - -CONFIG_BT_MESH_V1d1=y -CONFIG_BT_MESH_OP_AGG_CLI=y -CONFIG_BT_MESH_OP_AGG_SRV=y -# PTS requires more key slots. -# First one is implicitly taken by Device Key. -CONFIG_BT_MESH_MODEL_KEY_COUNT=3 -CONFIG_BT_MESH_LARGE_COMP_DATA_CLI=y -CONFIG_BT_MESH_LARGE_COMP_DATA_SRV=y -CONFIG_BT_MESH_SAR_CFG_SRV=y -CONFIG_BT_MESH_SAR_CFG_CLI=y -CONFIG_BT_MESH_TX_SEG_MSG_COUNT=10 -CONFIG_BT_MESH_RPR_SRV=y -CONFIG_BT_MESH_RPR_CLI=y -CONFIG_BT_MESH_RPR_AD_TYPES_MAX=2 -CONFIG_BT_MESH_BLOB_CLI=y -CONFIG_BT_MESH_DFU_CLI=y -CONFIG_BT_MESH_BLOB_SRV=y -CONFIG_BT_MESH_DFU_SRV=y -CONFIG_BT_MESH_DFD_SRV=y -CONFIG_BT_MESH_DFU_SLOT_CNT=2 -CONFIG_BT_MESH_PRIV_BEACONS=y -CONFIG_BT_MESH_PRIV_BEACON_SRV=y -CONFIG_BT_MESH_PRIV_BEACON_CLI=y -CONFIG_BT_MESH_OD_PRIV_PROXY_SRV=y -CONFIG_BT_MESH_MODEL_EXTENSIONS=y -CONFIG_BT_MESH_COMP_PAGE_1=y -CONFIG_BT_MESH_COMP_PAGE_2=y -CONFIG_SETTINGS=y diff --git a/tests/bluetooth/tester/overlay-mesh.conf b/tests/bluetooth/tester/overlay-mesh.conf index 840af06c1c0..9fded71f792 100644 --- a/tests/bluetooth/tester/overlay-mesh.conf +++ b/tests/bluetooth/tester/overlay-mesh.conf @@ -1,3 +1,5 @@ +CONFIG_ENTROPY_GENERATOR=y + CONFIG_BT_MESH=y CONFIG_BT_MESH_RELAY=y CONFIG_BT_MESH_PB_ADV=y @@ -23,3 +25,30 @@ CONFIG_BT_MESH_CDB_NODE_COUNT=3 CONFIG_BT_MESH_PROV_OOB_PUBLIC_KEY=y CONFIG_BT_MESH_MSG_CACHE_SIZE=10 CONFIG_BT_MESH_PROXY_CLIENT=y +CONFIG_BT_MESH_OP_AGG_CLI=y +CONFIG_BT_MESH_OP_AGG_SRV=y +# PTS requires more key slots. +# First one is implicitly taken by Device Key. +CONFIG_BT_MESH_MODEL_KEY_COUNT=3 +CONFIG_BT_MESH_LARGE_COMP_DATA_CLI=y +CONFIG_BT_MESH_LARGE_COMP_DATA_SRV=y +CONFIG_BT_MESH_SAR_CFG_SRV=y +CONFIG_BT_MESH_SAR_CFG_CLI=y +CONFIG_BT_MESH_TX_SEG_MSG_COUNT=10 +CONFIG_BT_MESH_RPR_SRV=y +CONFIG_BT_MESH_RPR_CLI=y +CONFIG_BT_MESH_RPR_AD_TYPES_MAX=2 +CONFIG_BT_MESH_BLOB_CLI=y +CONFIG_BT_MESH_DFU_CLI=y +CONFIG_BT_MESH_BLOB_SRV=y +CONFIG_BT_MESH_DFU_SRV=y +CONFIG_BT_MESH_DFD_SRV=y +CONFIG_BT_MESH_DFU_SLOT_CNT=2 +CONFIG_BT_MESH_PRIV_BEACONS=y +CONFIG_BT_MESH_PRIV_BEACON_SRV=y +CONFIG_BT_MESH_PRIV_BEACON_CLI=y +CONFIG_BT_MESH_OD_PRIV_PROXY_SRV=y +CONFIG_BT_MESH_MODEL_EXTENSIONS=y +CONFIG_BT_MESH_COMP_PAGE_1=y +CONFIG_BT_MESH_COMP_PAGE_2=y +CONFIG_SETTINGS=y diff --git a/tests/bluetooth/tester/testcase.yaml b/tests/bluetooth/tester/testcase.yaml index 8c36291b30f..37c7ab3193d 100644 --- a/tests/bluetooth/tester/testcase.yaml +++ b/tests/bluetooth/tester/testcase.yaml @@ -28,13 +28,3 @@ tests: extra_args: OVERLAY_CONFIG="overlay-mesh.conf" tags: bluetooth harness: bluetooth - bluetooth.general.tester_mesh_v1d1: - build_only: true - platform_allow: - - qemu_x86 - - native_posix - - native_sim - - nrf52840dk_nrf52840 - extra_args: OVERLAY_CONFIG="overlay-mesh.conf;overlay-mesh-v1d1.conf" - tags: bluetooth - harness: bluetooth diff --git a/tests/bsim/bluetooth/mesh/CMakeLists.txt b/tests/bsim/bluetooth/mesh/CMakeLists.txt index f57b59c0c64..70190be7840 100644 --- a/tests/bsim/bluetooth/mesh/CMakeLists.txt +++ b/tests/bsim/bluetooth/mesh/CMakeLists.txt @@ -10,30 +10,20 @@ target_sources(app PRIVATE src/mesh_test.c src/friendship_common.c src/gatt_common.c + src/dfu_blob_common.c ) -if(CONFIG_BT_MESH_V1d1) - target_sources(app PRIVATE - src/dfu_blob_common.c - ) -endif() - if(CONFIG_SETTINGS) target_sources(app PRIVATE src/test_persistence.c src/test_replay_cache.c src/test_provision.c - ) - - if(CONFIG_BT_MESH_V1d1) - target_sources(app PRIVATE - src/test_dfu.c - src/test_blob.c - src/test_sar.c - src/test_lcd.c - ) - endif() + src/test_dfu.c + src/test_blob.c + src/test_sar.c + src/test_lcd.c +) if(CONFIG_BT_MESH_USES_MBEDTLS_PSA) target_sources(app PRIVATE @@ -47,13 +37,8 @@ elseif(CONFIG_BT_MESH_GATT_PROXY) target_sources(app PRIVATE src/test_advertiser.c src/test_suspend.c - ) - - if(CONFIG_BT_MESH_V1d1) - target_sources(app PRIVATE src/test_beacon.c - ) - endif() + ) elseif(CONFIG_BT_CTLR_LOW_LAT) @@ -76,17 +61,12 @@ else() src/test_iv_index.c src/test_advertiser.c src/test_suspend.c + src/test_blob.c + src/test_op_agg.c + src/test_sar.c + src/test_cdp1.c ) - if(CONFIG_BT_MESH_V1d1) - target_sources(app PRIVATE - src/test_blob.c - src/test_op_agg.c - src/test_sar.c - src/test_cdp1.c - ) - endif() - endif() zephyr_include_directories( diff --git a/tests/bsim/bluetooth/mesh/compile.sh b/tests/bsim/bluetooth/mesh/compile.sh index 4e3027a7681..06557ef0ebb 100755 --- a/tests/bsim/bluetooth/mesh/compile.sh +++ b/tests/bsim/bluetooth/mesh/compile.sh @@ -18,24 +18,13 @@ mkdir -p ${WORK_DIR} source ${ZEPHYR_BASE}/tests/bsim/compile.source app=tests/bsim/bluetooth/mesh compile -app=tests/bsim/bluetooth/mesh conf_overlay=overlay_low_lat.conf compile app=tests/bsim/bluetooth/mesh conf_overlay=overlay_pst.conf compile app=tests/bsim/bluetooth/mesh conf_overlay=overlay_gatt.conf compile -app=tests/bsim/bluetooth/mesh conf_file=prj_mesh1d1.conf compile -app=tests/bsim/bluetooth/mesh \ - conf_file=prj_mesh1d1.conf conf_overlay=overlay_pst.conf compile -app=tests/bsim/bluetooth/mesh \ - conf_file=prj_mesh1d1.conf conf_overlay=overlay_gatt.conf compile -app=tests/bsim/bluetooth/mesh \ - conf_file=prj_mesh1d1.conf conf_overlay=overlay_low_lat.conf compile -app=tests/bsim/bluetooth/mesh conf_file=prj_mesh1d1.conf conf_overlay=overlay_psa.conf compile -app=tests/bsim/bluetooth/mesh \ - conf_file=prj_mesh1d1.conf conf_overlay="overlay_pst.conf;overlay_psa.conf" compile -app=tests/bsim/bluetooth/mesh \ - conf_file=prj_mesh1d1.conf conf_overlay="overlay_gatt.conf;overlay_psa.conf" compile -app=tests/bsim/bluetooth/mesh \ - conf_file=prj_mesh1d1.conf conf_overlay="overlay_low_lat.conf;overlay_psa.conf" compile -app=tests/bsim/bluetooth/mesh \ - conf_file=prj_mesh1d1.conf conf_overlay="overlay_gatt.conf;overlay_low_lat.conf" compile +app=tests/bsim/bluetooth/mesh conf_overlay=overlay_low_lat.conf compile +app=tests/bsim/bluetooth/mesh conf_overlay=overlay_psa.conf compile +app=tests/bsim/bluetooth/mesh conf_overlay="overlay_pst.conf;overlay_psa.conf" compile +app=tests/bsim/bluetooth/mesh conf_overlay="overlay_gatt.conf;overlay_psa.conf" compile +app=tests/bsim/bluetooth/mesh conf_overlay="overlay_low_lat.conf;overlay_psa.conf" compile +app=tests/bsim/bluetooth/mesh conf_overlay="overlay_gatt.conf;overlay_low_lat.conf" compile wait_for_background_jobs diff --git a/tests/bsim/bluetooth/mesh/overlay_pst.conf b/tests/bsim/bluetooth/mesh/overlay_pst.conf index 6730b9ee233..e02c0ec2b93 100644 --- a/tests/bsim/bluetooth/mesh/overlay_pst.conf +++ b/tests/bsim/bluetooth/mesh/overlay_pst.conf @@ -18,7 +18,4 @@ CONFIG_BT_MESH_SUBNET_COUNT=2 CONFIG_BT_MESH_SEQ_STORE_RATE=1 CONFIG_BT_MESH_RPL_STORE_TIMEOUT=1 CONFIG_BT_MESH_STORE_TIMEOUT=1 -CONFIG_BT_MESH_TX_SEG_RETRANS_COUNT=1 -CONFIG_BT_MESH_TX_SEG_RETRANS_TIMEOUT_UNICAST=200 -CONFIG_BT_MESH_SEG_ACK_BASE_TIMEOUT=400 CONFIG_BT_MESH_COMP_PST_BUF_SIZE=600 diff --git a/tests/bsim/bluetooth/mesh/prj.conf b/tests/bsim/bluetooth/mesh/prj.conf index e9c719de6d7..1c343bb512f 100644 --- a/tests/bsim/bluetooth/mesh/prj.conf +++ b/tests/bsim/bluetooth/mesh/prj.conf @@ -19,11 +19,12 @@ CONFIG_BT_CTLR_PRIVACY=n CONFIG_BT_MESH=y CONFIG_BT_MESH_LOG_LEVEL_DBG=y CONFIG_BT_MESH_RELAY=y -CONFIG_BT_MESH_ADV_BUF_COUNT=32 +CONFIG_BT_MESH_ADV_BUF_COUNT=64 CONFIG_BT_MESH_TX_SEG_MAX=32 CONFIG_BT_MESH_RX_SEG_MAX=32 CONFIG_BT_MESH_TX_SEG_MSG_COUNT=10 CONFIG_BT_MESH_RX_SEG_MSG_COUNT=10 +CONFIG_BT_MESH_SEG_BUFS=100 CONFIG_BT_MESH_CFG_CLI=y CONFIG_BT_MESH_MODEL_GROUP_COUNT=3 CONFIG_BT_MESH_LOW_POWER=y @@ -43,4 +44,29 @@ CONFIG_BT_MESH_CDB_NODE_COUNT=4 CONFIG_BT_MESH_PROV_OOB_PUBLIC_KEY=y CONFIG_BT_MESH_MODEL_EXTENSIONS=y CONFIG_BT_MESH_SUBNET_COUNT=5 +CONFIG_BT_MESH_SAR_CFG_CLI=y +CONFIG_BT_MESH_SAR_CFG_SRV=y +CONFIG_BT_MESH_BLOB_SRV=y +CONFIG_BT_MESH_BLOB_CLI=y +CONFIG_BT_MESH_BLOB_BLOCK_SIZE_MIN=256 +CONFIG_BT_MESH_RPR_CLI=y +CONFIG_BT_MESH_RPR_SRV=y +CONFIG_BT_MESH_OP_AGG_CLI=y +CONFIG_BT_MESH_OP_AGG_SRV=y +CONFIG_BT_MESH_LARGE_COMP_DATA_CLI=y +CONFIG_BT_MESH_LARGE_COMP_DATA_SRV=y +CONFIG_BT_MESH_DFU_SRV=y +CONFIG_BT_MESH_DFU_CLI=y +CONFIG_BT_MESH_DFD_SRV=y +CONFIG_BT_MESH_DFD_SRV_OOB_UPLOAD=y +CONFIG_BT_MESH_DFU_SLOT_CNT=4 +CONFIG_BT_MESH_PRIV_BEACON_SRV=y +CONFIG_BT_MESH_PRIV_BEACON_CLI=y +CONFIG_BT_MESH_OD_PRIV_PROXY_SRV=y +CONFIG_BT_MESH_OD_PRIV_PROXY_CLI=y +CONFIG_BT_MESH_COMP_PAGE_1=y +CONFIG_BT_MESH_COMP_PAGE_2=y CONFIG_BT_TESTING=y + +# Needed for RPR tests due to huge amount of retransmitted messages +CONFIG_BT_MESH_MSG_CACHE_SIZE=64 diff --git a/tests/bsim/bluetooth/mesh/prj_mesh1d1.conf b/tests/bsim/bluetooth/mesh/prj_mesh1d1.conf deleted file mode 100644 index fd0c953226b..00000000000 --- a/tests/bsim/bluetooth/mesh/prj_mesh1d1.conf +++ /dev/null @@ -1,73 +0,0 @@ -CONFIG_LOG_MODE_IMMEDIATE=y -CONFIG_ASSERT=y -CONFIG_SYS_CLOCK_TICKS_PER_SEC=32768 - -# Bluetooth configuration -CONFIG_BT=y -CONFIG_LOG=y -CONFIG_BT_PRIVACY=n -CONFIG_BT_COMPANY_ID=0x0059 -CONFIG_BT_DEVICE_NAME="Mesh test" -CONFIG_BT_OBSERVER=y -CONFIG_BT_BROADCASTER=y - -# Disable unused Bluetooth features -CONFIG_BT_CTLR_DUP_FILTER_LEN=0 -CONFIG_BT_CTLR_PRIVACY=n - -# Bluetooth Mesh configuration -CONFIG_BT_MESH=y -CONFIG_BT_MESH_V1d1=y -CONFIG_BT_MESH_LOG_LEVEL_DBG=y -CONFIG_BT_MESH_RELAY=y -CONFIG_BT_MESH_ADV_BUF_COUNT=64 -CONFIG_BT_MESH_TX_SEG_MAX=32 -CONFIG_BT_MESH_RX_SEG_MAX=32 -CONFIG_BT_MESH_TX_SEG_MSG_COUNT=10 -CONFIG_BT_MESH_RX_SEG_MSG_COUNT=10 -CONFIG_BT_MESH_SEG_BUFS=100 -CONFIG_BT_MESH_CFG_CLI=y -CONFIG_BT_MESH_MODEL_GROUP_COUNT=3 -CONFIG_BT_MESH_LOW_POWER=y -CONFIG_BT_MESH_LPN_AUTO=n -CONFIG_BT_MESH_FRIEND=y -CONFIG_BT_MESH_FRIEND_ENABLED=n -CONFIG_BT_MESH_FRIEND_LPN_COUNT=5 -CONFIG_BT_MESH_APP_KEY_COUNT=2 -CONFIG_BT_MESH_MODEL_KEY_COUNT=2 -CONFIG_BT_MESH_LABEL_COUNT=3 -CONFIG_BT_MESH_IV_UPDATE_TEST=y -CONFIG_BT_MESH_PB_ADV=y -CONFIG_BT_MESH_PROVISIONER=y -CONFIG_BT_MESH_PROVISIONEE=y -CONFIG_BT_MESH_CDB=y -CONFIG_BT_MESH_CDB_NODE_COUNT=4 -CONFIG_BT_MESH_PROV_OOB_PUBLIC_KEY=y -CONFIG_BT_MESH_MODEL_EXTENSIONS=y -CONFIG_BT_MESH_SUBNET_COUNT=5 -CONFIG_BT_MESH_SAR_CFG_CLI=y -CONFIG_BT_MESH_SAR_CFG_SRV=y -CONFIG_BT_MESH_BLOB_SRV=y -CONFIG_BT_MESH_BLOB_CLI=y -CONFIG_BT_MESH_BLOB_BLOCK_SIZE_MIN=256 -CONFIG_BT_MESH_RPR_CLI=y -CONFIG_BT_MESH_RPR_SRV=y -CONFIG_BT_MESH_OP_AGG_CLI=y -CONFIG_BT_MESH_OP_AGG_SRV=y -CONFIG_BT_MESH_LARGE_COMP_DATA_CLI=y -CONFIG_BT_MESH_LARGE_COMP_DATA_SRV=y -CONFIG_BT_MESH_DFU_SRV=y -CONFIG_BT_MESH_DFU_CLI=y -CONFIG_BT_MESH_DFD_SRV=y -CONFIG_BT_MESH_DFD_SRV_OOB_UPLOAD=y -CONFIG_BT_MESH_DFU_SLOT_CNT=4 -CONFIG_BT_MESH_PRIV_BEACON_SRV=y -CONFIG_BT_MESH_PRIV_BEACON_CLI=y -CONFIG_BT_MESH_OD_PRIV_PROXY_SRV=y -CONFIG_BT_MESH_OD_PRIV_PROXY_CLI=y -CONFIG_BT_MESH_COMP_PAGE_1=y -CONFIG_BT_MESH_COMP_PAGE_2=y -CONFIG_BT_TESTING=y - -# Needed for RPR tests due to huge amount of retransmitted messages -CONFIG_BT_MESH_MSG_CACHE_SIZE=64 diff --git a/tests/bsim/bluetooth/mesh/src/main.c b/tests/bsim/bluetooth/mesh/src/main.c index 4b28d506627..275bb75de69 100644 --- a/tests/bsim/bluetooth/mesh/src/main.c +++ b/tests/bsim/bluetooth/mesh/src/main.c @@ -11,19 +11,14 @@ extern struct bst_test_list *test_persistence_install(struct bst_test_list *tests); extern struct bst_test_list *test_rpc_install(struct bst_test_list *tests); extern struct bst_test_list *test_provision_pst_install(struct bst_test_list *tests); -#if defined(CONFIG_BT_MESH_V1d1) extern struct bst_test_list *test_dfu_install(struct bst_test_list *test); extern struct bst_test_list *test_blob_pst_install(struct bst_test_list *test); extern struct bst_test_list *test_lcd_install(struct bst_test_list *test); extern struct bst_test_list *test_sar_pst_install(struct bst_test_list *test); -#endif /* defined(CONFIG_BT_MESH_V1d1) */ #elif defined(CONFIG_BT_MESH_GATT_PROXY) extern struct bst_test_list *test_adv_install(struct bst_test_list *test); extern struct bst_test_list *test_suspend_install(struct bst_test_list *test); -#if defined(CONFIG_BT_MESH_V1d1) extern struct bst_test_list *test_beacon_install(struct bst_test_list *tests); -#endif /* defined(CONFIG_BT_MESH_V1d1) */ - #elif defined(CONFIG_BT_CTLR_LOW_LAT) extern struct bst_test_list *test_transport_install(struct bst_test_list *tests); extern struct bst_test_list *test_friendship_install(struct bst_test_list *tests); @@ -39,31 +34,25 @@ extern struct bst_test_list *test_access_install(struct bst_test_list *test); extern struct bst_test_list *test_ivi_install(struct bst_test_list *test); extern struct bst_test_list *test_adv_install(struct bst_test_list *test); extern struct bst_test_list *test_suspend_install(struct bst_test_list *test); -#if defined(CONFIG_BT_MESH_V1d1) extern struct bst_test_list *test_blob_install(struct bst_test_list *test); extern struct bst_test_list *test_op_agg_install(struct bst_test_list *test); extern struct bst_test_list *test_sar_install(struct bst_test_list *test); extern struct bst_test_list *test_cdp1_install(struct bst_test_list *test); -#endif /* defined(CONFIG_BT_MESH_V1d1) */ #endif bst_test_install_t test_installers[] = { #if defined(CONFIG_SETTINGS) test_persistence_install, test_rpc_install, -#if defined(CONFIG_BT_MESH_V1d1) test_provision_pst_install, test_dfu_install, test_blob_pst_install, test_lcd_install, test_sar_pst_install, -#endif /* defined(CONFIG_BT_MESH_V1d1) */ #elif defined(CONFIG_BT_MESH_GATT_PROXY) test_adv_install, test_suspend_install, -#if defined(CONFIG_BT_MESH_V1d1) test_beacon_install, -#endif /* defined(CONFIG_BT_MESH_V1d1) */ #elif defined(CONFIG_BT_CTLR_LOW_LAT) test_transport_install, test_friendship_install, @@ -79,12 +68,10 @@ bst_test_install_t test_installers[] = { test_ivi_install, test_adv_install, test_suspend_install, -#if defined(CONFIG_BT_MESH_V1d1) test_blob_install, test_op_agg_install, test_sar_install, test_cdp1_install, -#endif /* defined(CONFIG_BT_MESH_V1d1) */ #endif NULL }; diff --git a/tests/bsim/bluetooth/mesh/src/test_beacon.c b/tests/bsim/bluetooth/mesh/src/test_beacon.c index 69dbad1f24c..b1d7c214dc0 100644 --- a/tests/bsim/bluetooth/mesh/src/test_beacon.c +++ b/tests/bsim/bluetooth/mesh/src/test_beacon.c @@ -27,9 +27,7 @@ LOG_MODULE_REGISTER(LOG_MODULE_NAME, LOG_LEVEL_INF); #define BEACON_INTERVAL 10 /*seconds*/ #define BEACON_TYPE_SECURE 0x01 -#if CONFIG_BT_MESH_V1d1 #define BEACON_TYPE_PRIVATE 0x02 -#endif static uint8_t test_net_key_2[16] = { 0xca, 0x11, 0xab, 0x1e }; static struct { @@ -71,7 +69,6 @@ BT_MESH_BEACON_CB_DEFINE(snb) = { /* Setting for scanner defining what beacon is expected next, SNB as default */ static uint8_t expected_beacon = BEACON_TYPE_SECURE; -#if CONFIG_BT_MESH_V1d1 static struct bt_mesh_cfg_cli cfg_cli; static struct bt_mesh_priv_beacon_cli priv_beacon_cli; @@ -99,7 +96,6 @@ static uint8_t last_random[13]; static bt_addr_le_t last_beacon_adv_addr; static struct bt_mesh_key priv_beacon_key; -#endif /* CONFIG_BT_MESH_V1d1 */ static int random_interval; @@ -330,13 +326,11 @@ static struct k_sem observer_sem; static struct { uint8_t flags; uint32_t iv_index; -#if CONFIG_BT_MESH_V1d1 uint8_t random[13]; uint64_t pp_hash; uint64_t pp_random; uint64_t net_id; bt_addr_le_t adv_addr; -#endif bool (*process_cb)(const uint8_t *net_id, void *ctx); void *user_ctx; } beacon; @@ -364,7 +358,6 @@ static void beacon_scan_cb(const bt_addr_le_t *addr, int8_t rssi, uint8_t adv_ty net_id = net_buf_simple_pull_mem(buf, 8); beacon.iv_index = net_buf_simple_pull_be32(buf); } -#if CONFIG_BT_MESH_V1d1 else if (expected_beacon == BEACON_TYPE_PRIVATE) { uint8_t private_beacon_data[5]; @@ -377,7 +370,7 @@ static void beacon_scan_cb(const bt_addr_le_t *addr, int8_t rssi, uint8_t adv_ty beacon.flags = private_beacon_data[0]; beacon.iv_index = sys_get_be32(&private_beacon_data[1]); } -#endif + if (!beacon.process_cb || beacon.process_cb(net_id, beacon.user_ctx)) { k_sem_give(&observer_sem); } @@ -1060,8 +1053,6 @@ static void test_tx_beacon_cache(void) PASS(); } -#if CONFIG_BT_MESH_V1d1 - typedef void (*priv_beacon_cb)(const struct bt_mesh_prb *prb); static priv_beacon_cb priv_beacon_cb_ptr; @@ -2196,8 +2187,6 @@ static void test_rx_priv_gatt_proxy(void) #endif -#endif /* CONFIG_BT_MESH_V1d1 */ - #define TEST_CASE(role, name, description) \ { \ .test_id = "beacon_" #role "_" #name, \ @@ -2216,7 +2205,6 @@ static const struct bst_test_instance test_beacon[] = { TEST_CASE(tx, multiple_netkeys, "Beacon: multiple Net Keys"), TEST_CASE(tx, secure_beacon_interval, "Beacon: send secure beacons"), TEST_CASE(tx, beacon_cache, "Beacon: advertise duplicate SNBs"), -#if CONFIG_BT_MESH_V1d1 TEST_CASE(tx, priv_on_iv_update, "Private Beacon: send on IV update"), TEST_CASE(tx, priv_on_key_refresh, "Private Beacon: send on Key Refresh"), TEST_CASE(tx, priv_adv, "Private Beacon: advertise Private Beacons"), @@ -2230,7 +2218,6 @@ static const struct bst_test_instance test_beacon[] = { TEST_CASE(tx, priv_gatt_proxy, "Private Proxy: Send Private Beacons over GATT"), TEST_CASE(tx, proxy_adv_multi_subnet_coex, "Proxy Adv: Multi subnet coex proxy adv"), TEST_CASE(tx, proxy_adv_solicit_trigger, "Proxy Adv: Trigger Solicitation"), -#endif #endif TEST_CASE(rx, on_iv_update, "Beacon: receive with IV update flag"), @@ -2240,7 +2227,6 @@ static const struct bst_test_instance test_beacon[] = { TEST_CASE(rx, multiple_netkeys, "Beacon: multiple Net Keys"), TEST_CASE(rx, secure_beacon_interval, "Beacon: receive and send secure beacons"), TEST_CASE(rx, beacon_cache, "Beacon: receive duplicate SNBs"), -#if CONFIG_BT_MESH_V1d1 TEST_CASE(rx, priv_adv, "Private Beacon: verify random regeneration"), TEST_CASE(rx, priv_invalid, "Private Beacon: receive invalid beacons"), TEST_CASE(rx, priv_interleave, "Private Beacon: interleaved with SNB"), @@ -2251,7 +2237,6 @@ static const struct bst_test_instance test_beacon[] = { TEST_CASE(rx, priv_multi_net_id, "Private Proxy: scan for multiple Net ID"), TEST_CASE(rx, priv_gatt_proxy, "Private Proxy: Receive Private Beacons over GATT"), TEST_CASE(rx, proxy_adv_multi_subnet_coex, "Proxy Adv: Multi subnet coex proxy adv"), -#endif #endif BSTEST_END_MARKER }; diff --git a/tests/bsim/bluetooth/mesh/src/test_provision.c b/tests/bsim/bluetooth/mesh/src/test_provision.c index 9a83f874e11..39e6e1b2bd3 100644 --- a/tests/bsim/bluetooth/mesh/src/test_provision.c +++ b/tests/bsim/bluetooth/mesh/src/test_provision.c @@ -52,11 +52,9 @@ enum test_flags { static uint8_t static_key1[] = {0x6E, 0x6F, 0x72, 0x64, 0x69, 0x63, 0x5F, 0x65, 0x78, 0x61, 0x6D, 0x70, 0x6C, 0x65, 0x5F, 0x31}; static uint8_t static_key2[] = {0x6E, 0x6F, 0x72, 0x64, 0x69, 0x63, 0x5F}; -#if IS_ENABLED(CONFIG_BT_MESH_V1d1) static uint8_t static_key3[] = {0x45, 0x6E, 0x68, 0x61, 0x6E, 0x63, 0x65, 0x64, 0x20, 0x70, 0x72, 0x6F, 0x76, 0x69, 0x73, 0x69, 0x6F, 0x6E, 0x69, 0x6E, 0x67, 0x20, 0x73, 0x74, 0x61, 0x74, 0x69, 0x63, 0x20, 0x4F, 0x4F, 0x42}; -#endif static uint8_t private_key_be[32]; static uint8_t public_key_be[64]; @@ -72,9 +70,7 @@ static struct oob_auth_test_vector_s { {NULL, 0, 0, 0, 0, 0}, {static_key1, sizeof(static_key1), 0, 0, 0, 0}, {static_key2, sizeof(static_key2), 0, 0, 0, 0}, -#if IS_ENABLED(CONFIG_BT_MESH_V1d1) {static_key3, sizeof(static_key3), 0, 0, 0, 0}, -#endif {NULL, 0, 3, BT_MESH_BLINK, 0, 0}, {NULL, 0, 5, BT_MESH_BEEP, 0, 0}, {NULL, 0, 6, BT_MESH_VIBRATE, 0, 0}, diff --git a/tests/bsim/bluetooth/mesh/src/test_replay_cache.c b/tests/bsim/bluetooth/mesh/src/test_replay_cache.c index 68dc52a7b5d..57d605fb97a 100644 --- a/tests/bsim/bluetooth/mesh/src/test_replay_cache.c +++ b/tests/bsim/bluetooth/mesh/src/test_replay_cache.c @@ -78,7 +78,6 @@ static void rx_ended(uint8_t *data, size_t len) static void tx_sar_conf(void) { -#ifdef CONFIG_BT_MESH_V1d1 /* Reconfigure SAR Transmitter state so that the transport layer doesn't * retransmit. */ @@ -97,12 +96,10 @@ static void tx_sar_conf(void) #else bt_mesh.sar_tx = tx_set; #endif -#endif } static void rx_sar_conf(void) { -#ifdef CONFIG_BT_MESH_V1d1 /* Reconfigure SAR Receiver state so that the transport layer does * generate Segmented Acks as rarely as possible. */ @@ -119,7 +116,6 @@ static void rx_sar_conf(void) #else bt_mesh.sar_rx = rx_set; #endif -#endif } static void test_tx_immediate_replay_attack(void) diff --git a/tests/bsim/bluetooth/mesh/src/test_transport.c b/tests/bsim/bluetooth/mesh/src/test_transport.c index 05026f6dcf7..309681ceafe 100644 --- a/tests/bsim/bluetooth/mesh/src/test_transport.c +++ b/tests/bsim/bluetooth/mesh/src/test_transport.c @@ -94,7 +94,6 @@ static void async_send_end(int err, void *data) static void rx_sar_conf(void) { -#ifdef CONFIG_BT_MESH_V1d1 /* Reconfigure SAR Receiver state so that the transport layer does * generate Segmented Acks as rarely as possible. */ @@ -111,7 +110,6 @@ static void rx_sar_conf(void) #else bt_mesh.sar_rx = rx_set; #endif -#endif } static const struct bt_mesh_send_cb async_send_cb = { diff --git a/tests/bsim/bluetooth/mesh/tests_scripts/access/access_cancel.sh b/tests/bsim/bluetooth/mesh/tests_scripts/access/access_cancel.sh index 6a56a084c60..85b76062b60 100755 --- a/tests/bsim/bluetooth/mesh/tests_scripts/access/access_cancel.sh +++ b/tests/bsim/bluetooth/mesh/tests_scripts/access/access_cancel.sh @@ -7,11 +7,6 @@ source $(dirname "${BASH_SOURCE[0]}")/../../_mesh_test.sh RunTest mesh_access_publication_cancel \ access_tx_cancel access_rx_cancel -conf=prj_mesh1d1_conf -RunTest mesh_access_publication_cancel_1d1 \ - access_tx_cancel access_rx_cancel - -conf=prj_mesh1d1_conf overlay=overlay_psa_conf RunTest mesh_access_publication_cancel_psa \ access_tx_cancel access_rx_cancel diff --git a/tests/bsim/bluetooth/mesh/tests_scripts/access/access_ext_sub.sh b/tests/bsim/bluetooth/mesh/tests_scripts/access/access_ext_sub.sh index 862291b4c76..66caf516bb2 100755 --- a/tests/bsim/bluetooth/mesh/tests_scripts/access/access_ext_sub.sh +++ b/tests/bsim/bluetooth/mesh/tests_scripts/access/access_ext_sub.sh @@ -7,11 +7,6 @@ source $(dirname "${BASH_SOURCE[0]}")/../../_mesh_test.sh RunTest mesh_access_extended_model_subs \ access_tx_ext_model access_sub_ext_model -conf=prj_mesh1d1_conf -RunTest mesh_access_extended_model_subs_1d1 \ - access_tx_ext_model access_sub_ext_model - -conf=prj_mesh1d1_conf overlay=overlay_psa_conf RunTest mesh_access_extended_model_subs_psa \ access_tx_ext_model access_sub_ext_model diff --git a/tests/bsim/bluetooth/mesh/tests_scripts/access/access_ext_sub_cap.sh b/tests/bsim/bluetooth/mesh/tests_scripts/access/access_ext_sub_cap.sh index 2a4f9ccc247..91576f34aa0 100755 --- a/tests/bsim/bluetooth/mesh/tests_scripts/access/access_ext_sub_cap.sh +++ b/tests/bsim/bluetooth/mesh/tests_scripts/access/access_ext_sub_cap.sh @@ -6,9 +6,5 @@ source $(dirname "${BASH_SOURCE[0]}")/../../_mesh_test.sh RunTest mesh_access_extended_model_subs_cap access_sub_capacity_ext_model -conf=prj_mesh1d1_conf -RunTest mesh_access_extended_model_subs_cap_1d1 access_sub_capacity_ext_model - -conf=prj_mesh1d1_conf overlay=overlay_psa_conf RunTest mesh_access_extended_model_subs_cap_psa access_sub_capacity_ext_model diff --git a/tests/bsim/bluetooth/mesh/tests_scripts/access/access_period.sh b/tests/bsim/bluetooth/mesh/tests_scripts/access/access_period.sh index d2bb07c6de7..f2e72085ac7 100755 --- a/tests/bsim/bluetooth/mesh/tests_scripts/access/access_period.sh +++ b/tests/bsim/bluetooth/mesh/tests_scripts/access/access_period.sh @@ -7,11 +7,6 @@ source $(dirname "${BASH_SOURCE[0]}")/../../_mesh_test.sh RunTest mesh_access_per_pub \ access_tx_period access_rx_period -conf=prj_mesh1d1_conf -RunTest mesh_access_per_pub_1d1 \ - access_tx_period access_rx_period - -conf=prj_mesh1d1_conf overlay=overlay_psa_conf RunTest mesh_access_per_pub_psa \ access_tx_period access_rx_period diff --git a/tests/bsim/bluetooth/mesh/tests_scripts/access/access_period_delayable.sh b/tests/bsim/bluetooth/mesh/tests_scripts/access/access_period_delayable.sh index 5ecd4a061de..0148026fc6f 100755 --- a/tests/bsim/bluetooth/mesh/tests_scripts/access/access_period_delayable.sh +++ b/tests/bsim/bluetooth/mesh/tests_scripts/access/access_period_delayable.sh @@ -7,11 +7,6 @@ source $(dirname "${BASH_SOURCE[0]}")/../../_mesh_test.sh RunTest mesh_access_pub_period_delayable_retr \ access_tx_period_delayable access_rx_period_delayable -conf=prj_mesh1d1_conf -RunTest mesh_access_pub_period_delayable_retr_1d1 \ - access_tx_period_delayable access_rx_period_delayable - -conf=prj_mesh1d1_conf overlay=overlay_psa_conf RunTest mesh_access_pub_period_delayable_retr_psa \ access_tx_period_delayable access_rx_period_delayable diff --git a/tests/bsim/bluetooth/mesh/tests_scripts/access/access_transmit.sh b/tests/bsim/bluetooth/mesh/tests_scripts/access/access_transmit.sh index c2f4a27ddbd..0a0ec47da15 100755 --- a/tests/bsim/bluetooth/mesh/tests_scripts/access/access_transmit.sh +++ b/tests/bsim/bluetooth/mesh/tests_scripts/access/access_transmit.sh @@ -7,11 +7,6 @@ source $(dirname "${BASH_SOURCE[0]}")/../../_mesh_test.sh RunTest mesh_access_pub_retr \ access_tx_transmit access_rx_transmit -conf=prj_mesh1d1_conf -RunTest mesh_access_pub_retr_1d1 \ - access_tx_transmit access_rx_transmit - -conf=prj_mesh1d1_conf overlay=overlay_psa_conf RunTest mesh_access_pub_retr_psa \ access_tx_period access_rx_period diff --git a/tests/bsim/bluetooth/mesh/tests_scripts/access/access_transmit_delayable.sh b/tests/bsim/bluetooth/mesh/tests_scripts/access/access_transmit_delayable.sh index 0e966288db0..2dba89f2d76 100755 --- a/tests/bsim/bluetooth/mesh/tests_scripts/access/access_transmit_delayable.sh +++ b/tests/bsim/bluetooth/mesh/tests_scripts/access/access_transmit_delayable.sh @@ -7,11 +7,6 @@ source $(dirname "${BASH_SOURCE[0]}")/../../_mesh_test.sh RunTest mesh_access_pub_transmit_delayable_retr \ access_tx_transmit_delayable access_rx_transmit_delayable -conf=prj_mesh1d1_conf -RunTest mesh_access_pub_transmit_delayable_retr_1d1 \ - access_tx_transmit_delayable access_rx_transmit_delayable - -conf=prj_mesh1d1_conf overlay=overlay_psa_conf RunTest mesh_access_pub_transmit_delayable_retr_psa \ access_tx_transmit_delayable access_rx_transmit_delayable diff --git a/tests/bsim/bluetooth/mesh/tests_scripts/advertiser/proxy_mixin.sh b/tests/bsim/bluetooth/mesh/tests_scripts/advertiser/proxy_mixin.sh index 86255277277..6c49d03fe9f 100755 --- a/tests/bsim/bluetooth/mesh/tests_scripts/advertiser/proxy_mixin.sh +++ b/tests/bsim/bluetooth/mesh/tests_scripts/advertiser/proxy_mixin.sh @@ -21,10 +21,5 @@ source $(dirname "${BASH_SOURCE[0]}")/../../_mesh_test.sh overlay=overlay_gatt_conf RunTest mesh_adv_proxy_mixin adv_tx_proxy_mixin adv_rx_proxy_mixin -conf=prj_mesh1d1_conf -overlay=overlay_gatt_conf -RunTest mesh_adv_proxy_mixin_1d1 adv_tx_proxy_mixin adv_rx_proxy_mixin - -conf=prj_mesh1d1_conf overlay="overlay_gatt_conf_overlay_psa_conf" RunTest mesh_adv_proxy_mixin_psa adv_tx_proxy_mixin adv_rx_proxy_mixin diff --git a/tests/bsim/bluetooth/mesh/tests_scripts/advertiser/random_order.sh b/tests/bsim/bluetooth/mesh/tests_scripts/advertiser/random_order.sh index 8cfe0f9366a..a171ffd60f3 100755 --- a/tests/bsim/bluetooth/mesh/tests_scripts/advertiser/random_order.sh +++ b/tests/bsim/bluetooth/mesh/tests_scripts/advertiser/random_order.sh @@ -7,9 +7,5 @@ source $(dirname "${BASH_SOURCE[0]}")/../../_mesh_test.sh # test buffer management by filling buffers and sending them in random order. RunTest mesh_adv_random_order adv_tx_random_order adv_rx_random_order -conf=prj_mesh1d1_conf -RunTest mesh_adv_random_order_1d1 adv_tx_random_order adv_rx_random_order - -conf=prj_mesh1d1_conf overlay=overlay_psa_conf RunTest mesh_adv_random_order_psa adv_tx_random_order adv_rx_random_order diff --git a/tests/bsim/bluetooth/mesh/tests_scripts/advertiser/reverse_order.sh b/tests/bsim/bluetooth/mesh/tests_scripts/advertiser/reverse_order.sh index 96b30394f12..2b047138109 100755 --- a/tests/bsim/bluetooth/mesh/tests_scripts/advertiser/reverse_order.sh +++ b/tests/bsim/bluetooth/mesh/tests_scripts/advertiser/reverse_order.sh @@ -7,9 +7,5 @@ source $(dirname "${BASH_SOURCE[0]}")/../../_mesh_test.sh # test buffer management by filling all the buffer and sending them in reversed order. RunTest mesh_adv_reverse_order adv_tx_reverse_order adv_rx_receive_order -conf=prj_mesh1d1_conf -RunTest mesh_adv_reverse_order_1d1 adv_tx_reverse_order adv_rx_receive_order - -conf=prj_mesh1d1_conf overlay=overlay_psa_conf RunTest mesh_adv_reverse_order_psa adv_tx_reverse_order adv_rx_receive_order diff --git a/tests/bsim/bluetooth/mesh/tests_scripts/advertiser/send_order.sh b/tests/bsim/bluetooth/mesh/tests_scripts/advertiser/send_order.sh index e208bf54579..a9e8d1ea861 100755 --- a/tests/bsim/bluetooth/mesh/tests_scripts/advertiser/send_order.sh +++ b/tests/bsim/bluetooth/mesh/tests_scripts/advertiser/send_order.sh @@ -7,9 +7,5 @@ source $(dirname "${BASH_SOURCE[0]}")/../../_mesh_test.sh # test buffer management by filling all the buffer and sending them all in order. RunTest mesh_adv_send_order adv_tx_send_order adv_rx_receive_order -conf=prj_mesh1d1_conf -RunTest mesh_adv_send_order_1d1 adv_tx_send_order adv_rx_receive_order - -conf=prj_mesh1d1_conf overlay=overlay_psa_conf RunTest mesh_adv_send_order_psa adv_tx_send_order adv_rx_receive_order diff --git a/tests/bsim/bluetooth/mesh/tests_scripts/advertiser/tx_cb_multi.sh b/tests/bsim/bluetooth/mesh/tests_scripts/advertiser/tx_cb_multi.sh index 28827c872f8..4ca2838ddf9 100755 --- a/tests/bsim/bluetooth/mesh/tests_scripts/advertiser/tx_cb_multi.sh +++ b/tests/bsim/bluetooth/mesh/tests_scripts/advertiser/tx_cb_multi.sh @@ -7,9 +7,5 @@ source $(dirname "${BASH_SOURCE[0]}")/../../_mesh_test.sh # test tx callbacks sequence for multiple advs RunTest mesh_adv_tx_cb_multi adv_tx_cb_multi -conf=prj_mesh1d1_conf -RunTest mesh_adv_tx_cb_multi_1d1 adv_tx_cb_multi - -conf=prj_mesh1d1_conf overlay=overlay_psa_conf RunTest mesh_adv_tx_cb_multi_psa adv_tx_cb_multi diff --git a/tests/bsim/bluetooth/mesh/tests_scripts/advertiser/tx_cb_single.sh b/tests/bsim/bluetooth/mesh/tests_scripts/advertiser/tx_cb_single.sh index edf4ba0996b..a2b1ad0e961 100755 --- a/tests/bsim/bluetooth/mesh/tests_scripts/advertiser/tx_cb_single.sh +++ b/tests/bsim/bluetooth/mesh/tests_scripts/advertiser/tx_cb_single.sh @@ -7,9 +7,5 @@ source $(dirname "${BASH_SOURCE[0]}")/../../_mesh_test.sh # test tx callbacks parameters and xmit sequence for single adv RunTest mesh_adv_tx_cb_single adv_tx_cb_single adv_rx_xmit -conf=prj_mesh1d1_conf -RunTest mesh_adv_tx_cb_single_1d1 adv_tx_cb_single adv_rx_xmit - -conf=prj_mesh1d1_conf overlay=overlay_psa_conf RunTest mesh_adv_tx_cb_single_psa adv_tx_cb_single adv_rx_xmit diff --git a/tests/bsim/bluetooth/mesh/tests_scripts/beacon/beacon_cache.sh b/tests/bsim/bluetooth/mesh/tests_scripts/beacon/beacon_cache.sh index c0f741e9aae..ab43e2b74db 100755 --- a/tests/bsim/bluetooth/mesh/tests_scripts/beacon/beacon_cache.sh +++ b/tests/bsim/bluetooth/mesh/tests_scripts/beacon/beacon_cache.sh @@ -15,12 +15,6 @@ RunTest mesh_beacon_cache \ beacon_tx_beacon_cache \ beacon_rx_beacon_cache -conf=prj_mesh1d1_conf -RunTest mesh_beacon_cache \ - beacon_tx_beacon_cache \ - beacon_rx_beacon_cache - -conf=prj_mesh1d1_conf overlay=overlay_psa_conf RunTest mesh_beacon_cache \ beacon_tx_beacon_cache \ diff --git a/tests/bsim/bluetooth/mesh/tests_scripts/beacon/beacon_interval.sh b/tests/bsim/bluetooth/mesh/tests_scripts/beacon/beacon_interval.sh index ec70eb2f02c..a671c90d668 100755 --- a/tests/bsim/bluetooth/mesh/tests_scripts/beacon/beacon_interval.sh +++ b/tests/bsim/bluetooth/mesh/tests_scripts/beacon/beacon_interval.sh @@ -22,12 +22,6 @@ RunTest mesh_beacon_interval \ beacon_tx_secure_beacon_interval \ beacon_rx_secure_beacon_interval -conf=prj_mesh1d1_conf -RunTest mesh_beacon_interval_1d1 \ - beacon_tx_secure_beacon_interval \ - beacon_rx_secure_beacon_interval - -conf=prj_mesh1d1_conf overlay=overlay_psa_conf RunTest mesh_beacon_interval_psa \ beacon_tx_secure_beacon_interval \ diff --git a/tests/bsim/bluetooth/mesh/tests_scripts/beacon/invalid.sh b/tests/bsim/bluetooth/mesh/tests_scripts/beacon/invalid.sh index ccce8c3a1f5..96d5b0a0f6b 100755 --- a/tests/bsim/bluetooth/mesh/tests_scripts/beacon/invalid.sh +++ b/tests/bsim/bluetooth/mesh/tests_scripts/beacon/invalid.sh @@ -8,12 +8,6 @@ RunTest mesh_beacon_invalid \ beacon_tx_invalid \ beacon_rx_invalid -conf=prj_mesh1d1_conf -RunTest mesh_beacon_invalid_1d1 \ - beacon_tx_invalid \ - beacon_rx_invalid - -conf=prj_mesh1d1_conf overlay=overlay_psa_conf RunTest mesh_beacon_invalid_psa \ beacon_tx_invalid \ diff --git a/tests/bsim/bluetooth/mesh/tests_scripts/beacon/iv_update.sh b/tests/bsim/bluetooth/mesh/tests_scripts/beacon/iv_update.sh index 64225fd9cf5..d719aef86bc 100755 --- a/tests/bsim/bluetooth/mesh/tests_scripts/beacon/iv_update.sh +++ b/tests/bsim/bluetooth/mesh/tests_scripts/beacon/iv_update.sh @@ -8,12 +8,6 @@ RunTest mesh_beacon_on_iv_update \ beacon_tx_on_iv_update \ beacon_rx_on_iv_update -conf=prj_mesh1d1_conf -RunTest mesh_beacon_on_iv_update_1d1 \ - beacon_tx_on_iv_update \ - beacon_rx_on_iv_update - -conf=prj_mesh1d1_conf overlay=overlay_psa_conf RunTest mesh_beacon_on_iv_update_psa \ beacon_tx_on_iv_update \ diff --git a/tests/bsim/bluetooth/mesh/tests_scripts/beacon/key_refresh.sh b/tests/bsim/bluetooth/mesh/tests_scripts/beacon/key_refresh.sh index 00f82704718..9223d7d1d29 100755 --- a/tests/bsim/bluetooth/mesh/tests_scripts/beacon/key_refresh.sh +++ b/tests/bsim/bluetooth/mesh/tests_scripts/beacon/key_refresh.sh @@ -8,12 +8,6 @@ RunTest mesh_beacon_on_key_refresh \ beacon_tx_on_key_refresh \ beacon_rx_on_key_refresh -conf=prj_mesh1d1_conf -RunTest mesh_beacon_on_key_refresh_1d1 \ - beacon_tx_on_key_refresh \ - beacon_rx_on_key_refresh - -conf=prj_mesh1d1_conf overlay=overlay_psa_conf RunTest mesh_beacon_on_key_refresh_psa \ beacon_tx_on_key_refresh \ diff --git a/tests/bsim/bluetooth/mesh/tests_scripts/beacon/kr_old_key.sh b/tests/bsim/bluetooth/mesh/tests_scripts/beacon/kr_old_key.sh index 3d6b151a068..ecd83e415a9 100755 --- a/tests/bsim/bluetooth/mesh/tests_scripts/beacon/kr_old_key.sh +++ b/tests/bsim/bluetooth/mesh/tests_scripts/beacon/kr_old_key.sh @@ -8,12 +8,6 @@ RunTest mesh_beacon_kr_old_key \ beacon_tx_kr_old_key \ beacon_rx_kr_old_key -conf=prj_mesh1d1_conf -RunTest mesh_beacon_kr_old_key_1d1 \ - beacon_tx_kr_old_key \ - beacon_rx_kr_old_key - -conf=prj_mesh1d1_conf overlay=overlay_psa_conf RunTest mesh_beacon_kr_old_key_psa \ beacon_tx_kr_old_key \ diff --git a/tests/bsim/bluetooth/mesh/tests_scripts/beacon/multiple_netkeys.sh b/tests/bsim/bluetooth/mesh/tests_scripts/beacon/multiple_netkeys.sh index 677e4227669..a8c154f5204 100755 --- a/tests/bsim/bluetooth/mesh/tests_scripts/beacon/multiple_netkeys.sh +++ b/tests/bsim/bluetooth/mesh/tests_scripts/beacon/multiple_netkeys.sh @@ -8,12 +8,6 @@ RunTest mesh_beacon_multiple_netkeys \ beacon_tx_multiple_netkeys \ beacon_rx_multiple_netkeys -conf=prj_mesh1d1_conf -RunTest mesh_beacon_multiple_netkeys_1d1 \ - beacon_tx_multiple_netkeys \ - beacon_rx_multiple_netkeys - -conf=prj_mesh1d1_conf overlay=overlay_psa_conf RunTest mesh_beacon_multiple_netkeys_psa \ beacon_tx_multiple_netkeys \ diff --git a/tests/bsim/bluetooth/mesh/tests_scripts/blob_mdls/blob_cli_broadcast_basic.sh b/tests/bsim/bluetooth/mesh/tests_scripts/blob_mdls/blob_cli_broadcast_basic.sh index 6f1ec61ad27..d8665ac4cfd 100755 --- a/tests/bsim/bluetooth/mesh/tests_scripts/blob_mdls/blob_cli_broadcast_basic.sh +++ b/tests/bsim/bluetooth/mesh/tests_scripts/blob_mdls/blob_cli_broadcast_basic.sh @@ -4,9 +4,7 @@ source $(dirname "${BASH_SOURCE[0]}")/../../_mesh_test.sh -conf=prj_mesh1d1_conf RunTest blob_broadcast_basic blob_cli_broadcast_basic -conf=prj_mesh1d1_conf overlay=overlay_psa_conf RunTest blob_broadcast_basic_psa blob_cli_broadcast_basic diff --git a/tests/bsim/bluetooth/mesh/tests_scripts/blob_mdls/blob_cli_broadcast_trans.sh b/tests/bsim/bluetooth/mesh/tests_scripts/blob_mdls/blob_cli_broadcast_trans.sh index d5d0f60d1ce..25198e70a38 100755 --- a/tests/bsim/bluetooth/mesh/tests_scripts/blob_mdls/blob_cli_broadcast_trans.sh +++ b/tests/bsim/bluetooth/mesh/tests_scripts/blob_mdls/blob_cli_broadcast_trans.sh @@ -4,9 +4,7 @@ source $(dirname "${BASH_SOURCE[0]}")/../../_mesh_test.sh -conf=prj_mesh1d1_conf RunTest blob_broadcast_trans blob_cli_broadcast_trans -conf=prj_mesh1d1_conf overlay=overlay_psa_conf RunTest blob_broadcast_trans_psa blob_cli_broadcast_trans diff --git a/tests/bsim/bluetooth/mesh/tests_scripts/blob_mdls/blob_cli_broadcast_unicast.sh b/tests/bsim/bluetooth/mesh/tests_scripts/blob_mdls/blob_cli_broadcast_unicast.sh index ee86ce33cfa..654753e2188 100755 --- a/tests/bsim/bluetooth/mesh/tests_scripts/blob_mdls/blob_cli_broadcast_unicast.sh +++ b/tests/bsim/bluetooth/mesh/tests_scripts/blob_mdls/blob_cli_broadcast_unicast.sh @@ -4,9 +4,7 @@ source $(dirname "${BASH_SOURCE[0]}")/../../_mesh_test.sh -conf=prj_mesh1d1_conf RunTest blob_broadcast_unicast blob_cli_broadcast_unicast -conf=prj_mesh1d1_conf overlay=overlay_psa_conf RunTest blob_broadcast_unicast_psa blob_cli_broadcast_unicast diff --git a/tests/bsim/bluetooth/mesh/tests_scripts/blob_mdls/blob_cli_broadcast_unicast_seq.sh b/tests/bsim/bluetooth/mesh/tests_scripts/blob_mdls/blob_cli_broadcast_unicast_seq.sh index c356122145c..cb569fdc3b4 100755 --- a/tests/bsim/bluetooth/mesh/tests_scripts/blob_mdls/blob_cli_broadcast_unicast_seq.sh +++ b/tests/bsim/bluetooth/mesh/tests_scripts/blob_mdls/blob_cli_broadcast_unicast_seq.sh @@ -4,9 +4,7 @@ source $(dirname "${BASH_SOURCE[0]}")/../../_mesh_test.sh -conf=prj_mesh1d1_conf RunTest blob_broadcast_unicast_seq blob_cli_broadcast_unicast_seq -conf=prj_mesh1d1_conf overlay=overlay_psa_conf RunTest blob_broadcast_unicast_seq_psa blob_cli_broadcast_unicast_seq diff --git a/tests/bsim/bluetooth/mesh/tests_scripts/blob_mdls/blob_cli_caps_all_rsp.sh b/tests/bsim/bluetooth/mesh/tests_scripts/blob_mdls/blob_cli_caps_all_rsp.sh index bc2aa351987..d7f54a34d22 100755 --- a/tests/bsim/bluetooth/mesh/tests_scripts/blob_mdls/blob_cli_caps_all_rsp.sh +++ b/tests/bsim/bluetooth/mesh/tests_scripts/blob_mdls/blob_cli_caps_all_rsp.sh @@ -5,11 +5,9 @@ source $(dirname "${BASH_SOURCE[0]}")/../../_mesh_test.sh # The test instance sequence must stay as it is due to addressing scheme -conf=prj_mesh1d1_conf RunTest blob_caps_all_rsp \ blob_cli_caps_all_rsp blob_srv_caps_standard blob_srv_caps_standard -conf=prj_mesh1d1_conf overlay=overlay_psa_conf RunTest blob_caps_all_rsp_psa \ blob_cli_caps_all_rsp blob_srv_caps_standard blob_srv_caps_standard diff --git a/tests/bsim/bluetooth/mesh/tests_scripts/blob_mdls/blob_cli_caps_cancelled.sh b/tests/bsim/bluetooth/mesh/tests_scripts/blob_mdls/blob_cli_caps_cancelled.sh index 3e1bd343a70..e287dcbd9fc 100755 --- a/tests/bsim/bluetooth/mesh/tests_scripts/blob_mdls/blob_cli_caps_cancelled.sh +++ b/tests/bsim/bluetooth/mesh/tests_scripts/blob_mdls/blob_cli_caps_cancelled.sh @@ -5,11 +5,9 @@ source $(dirname "${BASH_SOURCE[0]}")/../../_mesh_test.sh # The test instance seqence must stay as it is due to addressing scheme -conf=prj_mesh1d1_conf RunTest blob_caps_cancelled \ blob_cli_caps_cancelled blob_srv_caps_standard -conf=prj_mesh1d1_conf overlay=overlay_psa_conf RunTest blob_caps_cancelled_psa \ blob_cli_caps_cancelled blob_srv_caps_standard diff --git a/tests/bsim/bluetooth/mesh/tests_scripts/blob_mdls/blob_cli_caps_no_rsp.sh b/tests/bsim/bluetooth/mesh/tests_scripts/blob_mdls/blob_cli_caps_no_rsp.sh index e53864f8be4..e5ee44b5a08 100755 --- a/tests/bsim/bluetooth/mesh/tests_scripts/blob_mdls/blob_cli_caps_no_rsp.sh +++ b/tests/bsim/bluetooth/mesh/tests_scripts/blob_mdls/blob_cli_caps_no_rsp.sh @@ -5,11 +5,9 @@ source $(dirname "${BASH_SOURCE[0]}")/../../_mesh_test.sh # The test instance sequence must stay as it is due to addressing scheme -conf=prj_mesh1d1_conf RunTest blob_caps_no_rsp \ blob_cli_caps_no_rsp blob_srv_caps_no_rsp blob_srv_caps_no_rsp -conf=prj_mesh1d1_conf overlay=overlay_psa_conf RunTest blob_caps_no_rsp_psa \ blob_cli_caps_no_rsp blob_srv_caps_no_rsp blob_srv_caps_no_rsp diff --git a/tests/bsim/bluetooth/mesh/tests_scripts/blob_mdls/blob_cli_caps_partial_rsp.sh b/tests/bsim/bluetooth/mesh/tests_scripts/blob_mdls/blob_cli_caps_partial_rsp.sh index 9a1675bd279..2da51b0e37e 100755 --- a/tests/bsim/bluetooth/mesh/tests_scripts/blob_mdls/blob_cli_caps_partial_rsp.sh +++ b/tests/bsim/bluetooth/mesh/tests_scripts/blob_mdls/blob_cli_caps_partial_rsp.sh @@ -5,11 +5,9 @@ source $(dirname "${BASH_SOURCE[0]}")/../../_mesh_test.sh # The test instance sequence must stay as it is due to addressing scheme -conf=prj_mesh1d1_conf RunTest blob_caps_partial_rsp \ blob_cli_caps_partial_rsp blob_srv_caps_standard blob_srv_caps_no_rsp -conf=prj_mesh1d1_conf overlay=overlay_psa_conf RunTest blob_caps_partial_rsp_psa \ blob_cli_caps_partial_rsp blob_srv_caps_standard blob_srv_caps_no_rsp diff --git a/tests/bsim/bluetooth/mesh/tests_scripts/blob_mdls/blob_cli_friend.sh b/tests/bsim/bluetooth/mesh/tests_scripts/blob_mdls/blob_cli_friend.sh index 1c2bde7a109..0e82cf8df11 100755 --- a/tests/bsim/bluetooth/mesh/tests_scripts/blob_mdls/blob_cli_friend.sh +++ b/tests/bsim/bluetooth/mesh/tests_scripts/blob_mdls/blob_cli_friend.sh @@ -7,7 +7,6 @@ source $(dirname "${BASH_SOURCE[0]}")/../../_mesh_test.sh # Establish multiple different friendships concurrently. Perform BLOB transfer with BLOB Client # on friend node and BLOB Server on LPNs. # Note: The number of LPNs must match CONFIG_BT_MESH_FRIEND_LPN_COUNT. -conf=prj_mesh1d1_conf RunTest blob_transfer_lpn \ blob_cli_friend_pull \ blob_srv_lpn_pull \ @@ -16,7 +15,6 @@ RunTest blob_transfer_lpn \ blob_srv_lpn_pull \ blob_srv_lpn_pull -conf=prj_mesh1d1_conf overlay=overlay_psa_conf RunTest blob_transfer_lpn_psa \ blob_cli_friend_pull \ diff --git a/tests/bsim/bluetooth/mesh/tests_scripts/blob_mdls/blob_cli_no_rsp_block.sh b/tests/bsim/bluetooth/mesh/tests_scripts/blob_mdls/blob_cli_no_rsp_block.sh index 73728d1f141..a30a54f79ff 100755 --- a/tests/bsim/bluetooth/mesh/tests_scripts/blob_mdls/blob_cli_no_rsp_block.sh +++ b/tests/bsim/bluetooth/mesh/tests_scripts/blob_mdls/blob_cli_no_rsp_block.sh @@ -4,13 +4,11 @@ source $(dirname "${BASH_SOURCE[0]}")/../../_mesh_test.sh -conf=prj_mesh1d1_conf RunTest blob_no_rsp_block_get \ blob_cli_fail_on_no_rsp \ blob_srv_fail_on_block_get \ blob_srv_fail_on_block_get -- -argstest msg-fail-type=0 -conf=prj_mesh1d1_conf overlay=overlay_psa_conf RunTest blob_no_rsp_block_get_psa \ blob_cli_fail_on_no_rsp \ diff --git a/tests/bsim/bluetooth/mesh/tests_scripts/blob_mdls/blob_cli_no_rsp_xfer.sh b/tests/bsim/bluetooth/mesh/tests_scripts/blob_mdls/blob_cli_no_rsp_xfer.sh index 4137deba007..4ecc650aa8f 100755 --- a/tests/bsim/bluetooth/mesh/tests_scripts/blob_mdls/blob_cli_no_rsp_xfer.sh +++ b/tests/bsim/bluetooth/mesh/tests_scripts/blob_mdls/blob_cli_no_rsp_xfer.sh @@ -4,13 +4,11 @@ source $(dirname "${BASH_SOURCE[0]}")/../../_mesh_test.sh -conf=prj_mesh1d1_conf RunTest blob_no_rsp_xfer_get \ blob_cli_fail_on_no_rsp \ blob_srv_fail_on_xfer_get \ blob_srv_fail_on_xfer_get -- -argstest msg-fail-type=1 -conf=prj_mesh1d1_conf overlay=overlay_psa_conf RunTest blob_no_rsp_xfer_get_psa \ blob_cli_fail_on_no_rsp \ diff --git a/tests/bsim/bluetooth/mesh/tests_scripts/blob_mdls/blob_cli_persistent_transfer.sh b/tests/bsim/bluetooth/mesh/tests_scripts/blob_mdls/blob_cli_persistent_transfer.sh index e5bb421af14..a7cfdac206d 100755 --- a/tests/bsim/bluetooth/mesh/tests_scripts/blob_mdls/blob_cli_persistent_transfer.sh +++ b/tests/bsim/bluetooth/mesh/tests_scripts/blob_mdls/blob_cli_persistent_transfer.sh @@ -5,7 +5,6 @@ source $(dirname "${BASH_SOURCE[0]}")/../../_mesh_test.sh # The test instance sequence must stay as it is due to addressing scheme -conf=prj_mesh1d1_conf RunTest blob_fail \ blob_cli_fail_on_persistency \ blob_srv_fail_on_block_start\ @@ -13,7 +12,6 @@ RunTest blob_fail \ blob_srv_fail_on_xfer_get \ blob_srv_fail_on_nothing -conf=prj_mesh1d1_conf overlay=overlay_psa_conf RunTest blob_fail_psa \ blob_cli_fail_on_persistency \ diff --git a/tests/bsim/bluetooth/mesh/tests_scripts/blob_mdls/blob_cli_persistent_transfer_pull.sh b/tests/bsim/bluetooth/mesh/tests_scripts/blob_mdls/blob_cli_persistent_transfer_pull.sh index 8ead73c4ec7..11bafde8fbc 100755 --- a/tests/bsim/bluetooth/mesh/tests_scripts/blob_mdls/blob_cli_persistent_transfer_pull.sh +++ b/tests/bsim/bluetooth/mesh/tests_scripts/blob_mdls/blob_cli_persistent_transfer_pull.sh @@ -5,13 +5,11 @@ source $(dirname "${BASH_SOURCE[0]}")/../../_mesh_test.sh # Test that BLOB Client continues BLOB Transfer after one target timed out while sending chunks. -conf=prj_mesh1d1_conf RunTest blob_pst_pull \ blob_cli_trans_persistency_pull \ blob_srv_trans_persistency_pull \ blob_srv_trans_persistency_pull -conf=prj_mesh1d1_conf overlay=overlay_psa_conf RunTest blob_pst_pull_psa \ blob_cli_trans_persistency_pull \ diff --git a/tests/bsim/bluetooth/mesh/tests_scripts/blob_mdls/blob_cli_trans_complete_pull.sh b/tests/bsim/bluetooth/mesh/tests_scripts/blob_mdls/blob_cli_trans_complete_pull.sh index fdb1a8020e1..2e89819bb1f 100755 --- a/tests/bsim/bluetooth/mesh/tests_scripts/blob_mdls/blob_cli_trans_complete_pull.sh +++ b/tests/bsim/bluetooth/mesh/tests_scripts/blob_mdls/blob_cli_trans_complete_pull.sh @@ -5,13 +5,11 @@ source $(dirname "${BASH_SOURCE[0]}")/../../_mesh_test.sh # Test that BLOB Transfer completes successfully in Pull mode -conf=prj_mesh1d1_conf RunTest blob_success_pull blob_cli_trans_complete \ blob_srv_trans_complete blob_srv_trans_complete \ blob_srv_trans_complete blob_srv_trans_complete \ -- -argstest use-pull-mode=1 -conf=prj_mesh1d1_conf overlay=overlay_psa_conf RunTest blob_success_pull_psa blob_cli_trans_complete \ blob_srv_trans_complete blob_srv_trans_complete \ diff --git a/tests/bsim/bluetooth/mesh/tests_scripts/blob_mdls/blob_cli_trans_complete_push.sh b/tests/bsim/bluetooth/mesh/tests_scripts/blob_mdls/blob_cli_trans_complete_push.sh index 5345eab11e8..9695d1bb941 100755 --- a/tests/bsim/bluetooth/mesh/tests_scripts/blob_mdls/blob_cli_trans_complete_push.sh +++ b/tests/bsim/bluetooth/mesh/tests_scripts/blob_mdls/blob_cli_trans_complete_push.sh @@ -5,12 +5,10 @@ source $(dirname "${BASH_SOURCE[0]}")/../../_mesh_test.sh # Test that BLOB Transfer completes successfully in Push mode -conf=prj_mesh1d1_conf RunTest blob_success_push blob_cli_trans_complete \ blob_srv_trans_complete blob_srv_trans_complete \ blob_srv_trans_complete blob_srv_trans_complete -conf=prj_mesh1d1_conf overlay=overlay_psa_conf RunTest blob_success_push_psa blob_cli_trans_complete \ blob_srv_trans_complete blob_srv_trans_complete \ diff --git a/tests/bsim/bluetooth/mesh/tests_scripts/blob_mdls/blob_cli_trans_resume_pull.sh b/tests/bsim/bluetooth/mesh/tests_scripts/blob_mdls/blob_cli_trans_resume_pull.sh index 5b05446694b..4459c4419b4 100755 --- a/tests/bsim/bluetooth/mesh/tests_scripts/blob_mdls/blob_cli_trans_resume_pull.sh +++ b/tests/bsim/bluetooth/mesh/tests_scripts/blob_mdls/blob_cli_trans_resume_pull.sh @@ -5,11 +5,9 @@ source $(dirname "${BASH_SOURCE[0]}")/../../_mesh_test.sh # Test that BLOB Client can resume a suspended BLOB Transfer in Pull mode -conf=prj_mesh1d1_conf RunTest blob_resume_pull \ blob_cli_trans_resume blob_srv_trans_resume -- -argstest use-pull-mode=1 -conf=prj_mesh1d1_conf overlay=overlay_psa_conf RunTest blob_resume_pull_psa \ blob_cli_trans_resume blob_srv_trans_resume -- -argstest use-pull-mode=1 diff --git a/tests/bsim/bluetooth/mesh/tests_scripts/blob_mdls/blob_cli_trans_resume_push.sh b/tests/bsim/bluetooth/mesh/tests_scripts/blob_mdls/blob_cli_trans_resume_push.sh index 01150c8b0eb..2bbc627b05c 100755 --- a/tests/bsim/bluetooth/mesh/tests_scripts/blob_mdls/blob_cli_trans_resume_push.sh +++ b/tests/bsim/bluetooth/mesh/tests_scripts/blob_mdls/blob_cli_trans_resume_push.sh @@ -5,9 +5,7 @@ source $(dirname "${BASH_SOURCE[0]}")/../../_mesh_test.sh # Test that BLOB Client can resume a suspended BLOB Transfer in Push mode -conf=prj_mesh1d1_conf RunTest blob_resume_push blob_cli_trans_resume blob_srv_trans_resume -conf=prj_mesh1d1_conf overlay=overlay_psa_conf RunTest blob_resume_push_psa blob_cli_trans_resume blob_srv_trans_resume diff --git a/tests/bsim/bluetooth/mesh/tests_scripts/blob_mdls/blob_srv_persistence.sh b/tests/bsim/bluetooth/mesh/tests_scripts/blob_mdls/blob_srv_persistence.sh index 8c59c82da6f..9973a82dc49 100755 --- a/tests/bsim/bluetooth/mesh/tests_scripts/blob_mdls/blob_srv_persistence.sh +++ b/tests/bsim/bluetooth/mesh/tests_scripts/blob_mdls/blob_srv_persistence.sh @@ -10,65 +10,53 @@ source $(dirname "${BASH_SOURCE[0]}")/../../_mesh_test.sh # Tests with -flash_rm clean up stored settings after them # to run tests with -flash_erase correctly. # Test cases are designed to be run using single target. -conf=prj_mesh1d1_conf overlay=overlay_pst_conf RunTestFlash blob_recover_phase \ blob_cli_stop -flash_erase blob_srv_stop -flash_erase -- -argstest expected-phase=1 -conf=prj_mesh1d1_conf overlay=overlay_pst_conf RunTestFlash blob_recover_phase \ blob_cli_stop blob_srv_stop -- -argstest expected-phase=2 -conf=prj_mesh1d1_conf overlay=overlay_pst_conf RunTestFlash blob_recover_phase \ blob_cli_stop blob_srv_stop -- -argstest expected-phase=3 -conf=prj_mesh1d1_conf overlay=overlay_pst_conf RunTestFlash blob_recover_phase \ blob_cli_stop -flash_rm blob_srv_stop -flash_rm -- -argstest expected-phase=4 # Test reaching suspended state and continuation after reboot on new procedure. -conf=prj_mesh1d1_conf overlay=overlay_pst_conf RunTestFlash blob_recover_phase \ blob_cli_stop -flash_erase blob_srv_stop -flash_erase -- -argstest expected-phase=5 -conf=prj_mesh1d1_conf overlay=overlay_pst_conf RunTestFlash blob_recover_phase \ blob_cli_stop -flash_rm blob_srv_stop -flash_rm -- -argstest expected-phase=4 # The same test but with PSA crypto -conf=prj_mesh1d1_conf overlay="overlay_pst_conf_overlay_psa_conf" RunTestFlash blob_recover_phase_psa \ blob_cli_stop -flash_erase blob_srv_stop -flash_erase -- -argstest expected-phase=1 -conf=prj_mesh1d1_conf overlay="overlay_pst_conf_overlay_psa_conf" RunTestFlash blob_recover_phase_psa \ blob_cli_stop blob_srv_stop -- -argstest expected-phase=2 -conf=prj_mesh1d1_conf overlay="overlay_pst_conf_overlay_psa_conf" RunTestFlash blob_recover_phase_psa \ blob_cli_stop blob_srv_stop -- -argstest expected-phase=3 -conf=prj_mesh1d1_conf overlay="overlay_pst_conf_overlay_psa_conf" RunTestFlash blob_recover_phase_psa \ blob_cli_stop -flash_rm blob_srv_stop -flash_rm -- -argstest expected-phase=4 # Test reaching suspended state and continuation after reboot on new procedure. -conf=prj_mesh1d1_conf overlay="overlay_pst_conf_overlay_psa_conf" RunTestFlash blob_recover_phase_psa \ blob_cli_stop -flash_erase blob_srv_stop -flash_erase -- -argstest expected-phase=5 -conf=prj_mesh1d1_conf overlay="overlay_pst_conf_overlay_psa_conf" RunTestFlash blob_recover_phase_psa \ blob_cli_stop -flash_rm blob_srv_stop -flash_rm -- -argstest expected-phase=4 diff --git a/tests/bsim/bluetooth/mesh/tests_scripts/comp_data/cdp1_encode_decode.sh b/tests/bsim/bluetooth/mesh/tests_scripts/comp_data/cdp1_encode_decode.sh index e4f99e80d5d..d2a3c5de696 100755 --- a/tests/bsim/bluetooth/mesh/tests_scripts/comp_data/cdp1_encode_decode.sh +++ b/tests/bsim/bluetooth/mesh/tests_scripts/comp_data/cdp1_encode_decode.sh @@ -13,11 +13,9 @@ source $(dirname "${BASH_SOURCE[0]}")/../../_mesh_test.sh # 0. Provisioning and setup. # 1. Configuration client requests the node's CDP1. # 2. The received CDP1 is compared to a hardcoded version. -conf=prj_mesh1d1_conf RunTest mesh_cdp1_test \ cdp1_node_data_comparison -conf=prj_mesh1d1_conf overlay=overlay_psa_conf RunTest mesh_cdp1_test_psa \ cdp1_node_data_comparison diff --git a/tests/bsim/bluetooth/mesh/tests_scripts/dfu/dfu_cli_all_targets_lost_on_apply.sh b/tests/bsim/bluetooth/mesh/tests_scripts/dfu/dfu_cli_all_targets_lost_on_apply.sh index f612119bdee..4f87fb10fef 100755 --- a/tests/bsim/bluetooth/mesh/tests_scripts/dfu/dfu_cli_all_targets_lost_on_apply.sh +++ b/tests/bsim/bluetooth/mesh/tests_scripts/dfu/dfu_cli_all_targets_lost_on_apply.sh @@ -8,7 +8,6 @@ source $(dirname "${BASH_SOURCE[0]}")/../../_mesh_test.sh # callback is called when all targets are lost at this step. # The test instance sequence must stay as it is due to addressing scheme -conf=prj_mesh1d1_conf overlay=overlay_pst_conf RunTest dfu_all_tgts_lost_on_apply \ dfu_cli_all_targets_lost_on_apply \ @@ -17,7 +16,6 @@ RunTest dfu_all_tgts_lost_on_apply \ dfu_target_fail_on_apply \ -- -argstest targets=3 -conf=prj_mesh1d1_conf overlay="overlay_pst_conf_overlay_psa_conf" RunTest dfu_all_tgts_lost_on_apply_psa \ dfu_cli_all_targets_lost_on_apply \ diff --git a/tests/bsim/bluetooth/mesh/tests_scripts/dfu/dfu_cli_all_targets_lost_on_caps_get.sh b/tests/bsim/bluetooth/mesh/tests_scripts/dfu/dfu_cli_all_targets_lost_on_caps_get.sh index 36dcf8f24ae..572445e4779 100755 --- a/tests/bsim/bluetooth/mesh/tests_scripts/dfu/dfu_cli_all_targets_lost_on_caps_get.sh +++ b/tests/bsim/bluetooth/mesh/tests_scripts/dfu/dfu_cli_all_targets_lost_on_caps_get.sh @@ -8,7 +8,6 @@ source $(dirname "${BASH_SOURCE[0]}")/../../_mesh_test.sh # and `ended` callback is called when all targets are lost at this step. # The test instance sequence must stay as it is due to addressing scheme -conf=prj_mesh1d1_conf overlay=overlay_pst_conf RunTest dfu_all_tgts_lost_on_caps_get \ dfu_cli_all_targets_lost_on_caps_get \ @@ -17,7 +16,6 @@ RunTest dfu_all_tgts_lost_on_caps_get \ dfu_target_fail_on_caps_get \ -- -argstest targets=3 -conf=prj_mesh1d1_conf overlay="overlay_pst_conf_overlay_psa_conf" RunTest dfu_all_tgts_lost_on_caps_get_psa \ dfu_cli_all_targets_lost_on_caps_get \ diff --git a/tests/bsim/bluetooth/mesh/tests_scripts/dfu/dfu_cli_all_targets_lost_on_metadata.sh b/tests/bsim/bluetooth/mesh/tests_scripts/dfu/dfu_cli_all_targets_lost_on_metadata.sh index eacb921a214..e4fbe146dcd 100755 --- a/tests/bsim/bluetooth/mesh/tests_scripts/dfu/dfu_cli_all_targets_lost_on_metadata.sh +++ b/tests/bsim/bluetooth/mesh/tests_scripts/dfu/dfu_cli_all_targets_lost_on_metadata.sh @@ -8,7 +8,6 @@ source $(dirname "${BASH_SOURCE[0]}")/../../_mesh_test.sh # called when all targets are lost at this step. # The test instance sequence must stay as it is due to addressing scheme -conf=prj_mesh1d1_conf overlay=overlay_pst_conf RunTest dfu_all_tgts_lost_on_metadata \ dfu_cli_all_targets_lost_on_metadata \ @@ -17,7 +16,6 @@ RunTest dfu_all_tgts_lost_on_metadata \ dfu_target_fail_on_metadata \ -- -argstest targets=3 -conf=prj_mesh1d1_conf overlay="overlay_pst_conf_overlay_psa_conf" RunTest dfu_all_tgts_lost_on_metadata_psa \ dfu_cli_all_targets_lost_on_metadata \ diff --git a/tests/bsim/bluetooth/mesh/tests_scripts/dfu/dfu_cli_all_targets_lost_on_update_get.sh b/tests/bsim/bluetooth/mesh/tests_scripts/dfu/dfu_cli_all_targets_lost_on_update_get.sh index f6c53482834..7b96161eccd 100755 --- a/tests/bsim/bluetooth/mesh/tests_scripts/dfu/dfu_cli_all_targets_lost_on_update_get.sh +++ b/tests/bsim/bluetooth/mesh/tests_scripts/dfu/dfu_cli_all_targets_lost_on_update_get.sh @@ -8,7 +8,6 @@ source $(dirname "${BASH_SOURCE[0]}")/../../_mesh_test.sh # Firmware Update Get message and `ended` callback is called when all targets are lost at this step. # The test instance sequence must stay as it is due to addressing scheme -conf=prj_mesh1d1_conf overlay=overlay_pst_conf RunTest dfu_all_tgts_lost_on_update_get \ dfu_cli_all_targets_lost_on_update_get \ @@ -17,7 +16,6 @@ RunTest dfu_all_tgts_lost_on_update_get \ dfu_target_fail_on_update_get \ -- -argstest targets=3 -conf=prj_mesh1d1_conf overlay="overlay_pst_conf_overlay_psa_conf" RunTest dfu_all_tgts_lost_on_update_get_psa \ dfu_cli_all_targets_lost_on_update_get \ diff --git a/tests/bsim/bluetooth/mesh/tests_scripts/dfu/dfu_cli_all_targets_lost_on_verify.sh b/tests/bsim/bluetooth/mesh/tests_scripts/dfu/dfu_cli_all_targets_lost_on_verify.sh index 929ab93b81e..5daedaca71d 100755 --- a/tests/bsim/bluetooth/mesh/tests_scripts/dfu/dfu_cli_all_targets_lost_on_verify.sh +++ b/tests/bsim/bluetooth/mesh/tests_scripts/dfu/dfu_cli_all_targets_lost_on_verify.sh @@ -8,7 +8,6 @@ source $(dirname "${BASH_SOURCE[0]}")/../../_mesh_test.sh # callback is called when all targets are lost at this step. # The test instance sequence must stay as it is due to addressing scheme -conf=prj_mesh1d1_conf overlay=overlay_pst_conf RunTest dfu_all_tgts_lost_on_verify \ dfu_cli_all_targets_lost_on_verify \ @@ -17,7 +16,6 @@ RunTest dfu_all_tgts_lost_on_verify \ dfu_target_fail_on_verify \ -- -argstest targets=3 -conf=prj_mesh1d1_conf overlay="overlay_pst_conf_overlay_psa_conf" RunTest dfu_all_tgts_lost_on_verify_psa \ dfu_cli_all_targets_lost_on_verify \ diff --git a/tests/bsim/bluetooth/mesh/tests_scripts/dfu/dfu_cli_persistent_transfer.sh b/tests/bsim/bluetooth/mesh/tests_scripts/dfu/dfu_cli_persistent_transfer.sh index bcc98df48b5..2ff4a696639 100755 --- a/tests/bsim/bluetooth/mesh/tests_scripts/dfu/dfu_cli_persistent_transfer.sh +++ b/tests/bsim/bluetooth/mesh/tests_scripts/dfu/dfu_cli_persistent_transfer.sh @@ -5,7 +5,6 @@ source $(dirname "${BASH_SOURCE[0]}")/../../_mesh_test.sh # The test instance sequence must stay as it is due to addressing scheme -conf=prj_mesh1d1_conf overlay=overlay_pst_conf RunTest dfu_persistency \ dfu_cli_fail_on_persistency \ @@ -16,7 +15,6 @@ RunTest dfu_persistency \ dfu_target_fail_on_apply \ dfu_target_fail_on_nothing -conf=prj_mesh1d1_conf overlay="overlay_pst_conf_overlay_psa_conf" RunTest dfu_persistency_psa \ dfu_cli_fail_on_persistency \ diff --git a/tests/bsim/bluetooth/mesh/tests_scripts/dfu/dfu_dist_self_update.sh b/tests/bsim/bluetooth/mesh/tests_scripts/dfu/dfu_dist_self_update.sh index 64f33013e74..5c00349f24e 100755 --- a/tests/bsim/bluetooth/mesh/tests_scripts/dfu/dfu_dist_self_update.sh +++ b/tests/bsim/bluetooth/mesh/tests_scripts/dfu/dfu_dist_self_update.sh @@ -4,10 +4,8 @@ source $(dirname "${BASH_SOURCE[0]}")/../../_mesh_test.sh -conf=prj_mesh1d1_conf overlay=overlay_pst_conf RunTest dfu_self_update dfu_dist_dfu_self_update -- -argstest targets=1 -conf=prj_mesh1d1_conf overlay="overlay_pst_conf_overlay_psa_conf" RunTest dfu_self_update_psa dfu_dist_dfu_self_update -- -argstest targets=1 diff --git a/tests/bsim/bluetooth/mesh/tests_scripts/dfu/dfu_dist_self_update_mult_targets.sh b/tests/bsim/bluetooth/mesh/tests_scripts/dfu/dfu_dist_self_update_mult_targets.sh index af7acb10723..42087f1ad13 100755 --- a/tests/bsim/bluetooth/mesh/tests_scripts/dfu/dfu_dist_self_update_mult_targets.sh +++ b/tests/bsim/bluetooth/mesh/tests_scripts/dfu/dfu_dist_self_update_mult_targets.sh @@ -4,12 +4,10 @@ source $(dirname "${BASH_SOURCE[0]}")/../../_mesh_test.sh -conf=prj_mesh1d1_conf overlay=overlay_pst_conf RunTest dfu_self_update_no_change \ dfu_dist_dfu_self_update dfu_target_dfu_no_change -- -argstest targets=2 -conf=prj_mesh1d1_conf overlay="overlay_pst_conf_overlay_psa_conf" RunTest dfu_self_update_no_change_psa \ dfu_dist_dfu_self_update dfu_target_dfu_no_change -- -argstest targets=2 diff --git a/tests/bsim/bluetooth/mesh/tests_scripts/dfu/dfu_mixed.sh b/tests/bsim/bluetooth/mesh/tests_scripts/dfu/dfu_mixed.sh index bcac2cbba5b..1c5ff82d8fb 100755 --- a/tests/bsim/bluetooth/mesh/tests_scripts/dfu/dfu_mixed.sh +++ b/tests/bsim/bluetooth/mesh/tests_scripts/dfu/dfu_mixed.sh @@ -5,12 +5,10 @@ source $(dirname "${BASH_SOURCE[0]}")/../../_mesh_test.sh # Test DFU with all variants of firmware effect -conf=prj_mesh1d1_conf overlay=overlay_pst_conf RunTest dfu_mixed dfu_dist_dfu dfu_target_dfu_unprov dfu_target_dfu_no_change \ dfu_target_dfu_new_comp_rpr dfu_target_dfu_new_comp_no_rpr -- -argstest targets=4 -conf=prj_mesh1d1_conf overlay="overlay_pst_conf_overlay_psa_conf" RunTest dfu_mixed_psa dfu_dist_dfu dfu_target_dfu_unprov dfu_target_dfu_no_change \ dfu_target_dfu_new_comp_rpr dfu_target_dfu_new_comp_no_rpr -- -argstest targets=4 diff --git a/tests/bsim/bluetooth/mesh/tests_scripts/dfu/dfu_mixed_fail.sh b/tests/bsim/bluetooth/mesh/tests_scripts/dfu/dfu_mixed_fail.sh index c5f67e2521e..3382e458b2e 100755 --- a/tests/bsim/bluetooth/mesh/tests_scripts/dfu/dfu_mixed_fail.sh +++ b/tests/bsim/bluetooth/mesh/tests_scripts/dfu/dfu_mixed_fail.sh @@ -5,13 +5,11 @@ source $(dirname "${BASH_SOURCE[0]}")/../../_mesh_test.sh # Test that confirm step fails with all variants of firmware effect -conf=prj_mesh1d1_conf overlay=overlay_pst_conf RunTest dfu_mixed_fail dfu_dist_dfu dfu_target_dfu_unprov dfu_target_dfu_no_change \ dfu_target_dfu_new_comp_rpr dfu_target_dfu_new_comp_no_rpr -- -argstest targets=4 \ fail-confirm=1 -conf=prj_mesh1d1_conf overlay="overlay_pst_conf_overlay_psa_conf" RunTest dfu_mixed_fail_psa dfu_dist_dfu dfu_target_dfu_unprov dfu_target_dfu_no_change \ dfu_target_dfu_new_comp_rpr dfu_target_dfu_new_comp_no_rpr -- -argstest targets=4 \ diff --git a/tests/bsim/bluetooth/mesh/tests_scripts/dfu/dfu_slot.sh b/tests/bsim/bluetooth/mesh/tests_scripts/dfu/dfu_slot.sh index c187d8cfbff..587908c6497 100755 --- a/tests/bsim/bluetooth/mesh/tests_scripts/dfu/dfu_slot.sh +++ b/tests/bsim/bluetooth/mesh/tests_scripts/dfu/dfu_slot.sh @@ -11,7 +11,6 @@ source $(dirname "${BASH_SOURCE[0]}")/../../_mesh_test.sh # and verifies they do not exist. # - Fourth test is rebooted device that verifies if removing all slots also removed them # from storage. -conf=prj_mesh1d1_conf overlay=overlay_pst_conf RunTestFlash dfu_slot dfu_dist_dfu_slot_create -flash_erase @@ -21,7 +20,6 @@ RunTestFlash dfu_slot dfu_dist_dfu_slot_delete_all RunTestFlash dfu_slot dfu_dist_dfu_slot_check_delete_all -flash_rm -conf=prj_mesh1d1_conf overlay="overlay_pst_conf_overlay_psa_conf" RunTestFlash dfu_slot_psa dfu_dist_dfu_slot_create -flash_erase diff --git a/tests/bsim/bluetooth/mesh/tests_scripts/dfu/dfu_slot_idempotency.sh b/tests/bsim/bluetooth/mesh/tests_scripts/dfu/dfu_slot_idempotency.sh index 3f18f1a2651..abce47dba13 100755 --- a/tests/bsim/bluetooth/mesh/tests_scripts/dfu/dfu_slot_idempotency.sh +++ b/tests/bsim/bluetooth/mesh/tests_scripts/dfu/dfu_slot_idempotency.sh @@ -5,10 +5,8 @@ source $(dirname "${BASH_SOURCE[0]}")/../../_mesh_test.sh # Test DFU Slot API. This test tests that the APIs are idempotent. -conf=prj_mesh1d1_conf overlay=overlay_pst_conf RunTest dfu_slot_idempotency dfu_dist_dfu_slot_idempotency -conf=prj_mesh1d1_conf overlay="overlay_pst_conf_overlay_psa_conf" RunTest dfu_slot_idempotency_psa dfu_dist_dfu_slot_idempotency diff --git a/tests/bsim/bluetooth/mesh/tests_scripts/dfu/dfu_slot_reservation.sh b/tests/bsim/bluetooth/mesh/tests_scripts/dfu/dfu_slot_reservation.sh index ddd7d0123f5..0ce234116b2 100755 --- a/tests/bsim/bluetooth/mesh/tests_scripts/dfu/dfu_slot_reservation.sh +++ b/tests/bsim/bluetooth/mesh/tests_scripts/dfu/dfu_slot_reservation.sh @@ -5,10 +5,8 @@ source $(dirname "${BASH_SOURCE[0]}")/../../_mesh_test.sh # Test DFU Slot API. This test tests slot reservation APIs. -conf=prj_mesh1d1_conf overlay=overlay_pst_conf RunTest dfu_slot_reservation dfu_dist_dfu_slot_reservation -conf=prj_mesh1d1_conf overlay="overlay_pst_conf_overlay_psa_conf" RunTest dfu_slot_reservation_psa dfu_dist_dfu_slot_reservation diff --git a/tests/bsim/bluetooth/mesh/tests_scripts/dfu/dfu_srv_persistence.sh b/tests/bsim/bluetooth/mesh/tests_scripts/dfu/dfu_srv_persistence.sh index 6ed7099c987..b18a949b43d 100755 --- a/tests/bsim/bluetooth/mesh/tests_scripts/dfu/dfu_srv_persistence.sh +++ b/tests/bsim/bluetooth/mesh/tests_scripts/dfu/dfu_srv_persistence.sh @@ -13,32 +13,27 @@ source $(dirname "${BASH_SOURCE[0]}")/../../_mesh_test.sh # image index were loaded correctly. # Test cases are designed to be run using single target. `dfu_cli_stop` test case in recovery part # plays dummy role, and is there to keep order of settings files being loaded. -conf=prj_mesh1d1_conf overlay=overlay_pst_conf RunTestFlash dfu_dist_recover_phase \ dfu_cli_stop -flash_erase dfu_target_dfu_stop -flash_erase \ -- -argstest recover=0 expected-phase=2 -conf=prj_mesh1d1_conf overlay=overlay_pst_conf RunTestFlash dfu_dist_recover_phase \ dfu_cli_stop dfu_target_dfu_stop \ -- -argstest recover=1 expected-phase=3 -conf=prj_mesh1d1_conf overlay=overlay_pst_conf RunTestFlash dfu_dist_recover_phase \ dfu_cli_stop dfu_target_dfu_stop \ -- -argstest recover=1 expected-phase=4 -conf=prj_mesh1d1_conf overlay=overlay_pst_conf RunTestFlash dfu_dist_recover_phase \ dfu_cli_stop dfu_target_dfu_stop \ -- -argstest recover=1 expected-phase=6 # Use phase `BT_MESH_DFU_PHASE_APPLY_SUCCESS` as marker to bring whole procedure to an end -conf=prj_mesh1d1_conf overlay=overlay_pst_conf RunTestFlash dfu_dist_recover_phase \ dfu_cli_stop -flash_rm dfu_target_dfu_stop -flash_rm \ @@ -46,45 +41,38 @@ RunTestFlash dfu_dist_recover_phase \ # To test recovery from Verify Fail begin new distribution that will end there, # reboot devices and continue to Applying. -conf=prj_mesh1d1_conf overlay=overlay_pst_conf RunTestFlash dfu_dist_recover_phase \ dfu_cli_stop -flash_erase dfu_target_dfu_stop -flash_erase \ -- -argstest recover=0 expected-phase=5 -conf=prj_mesh1d1_conf overlay=overlay_pst_conf RunTestFlash dfu_dist_recover_phase \ dfu_cli_stop -flash_rm dfu_target_dfu_stop -flash_rm \ -- -argstest recover=1 expected-phase=6 # The same test but with PSA crypto -conf=prj_mesh1d1_conf overlay="overlay_pst_conf_overlay_psa_conf" RunTestFlash dfu_dist_recover_phase_psa \ dfu_cli_stop -flash_erase dfu_target_dfu_stop -flash_erase \ -- -argstest recover=0 expected-phase=2 -conf=prj_mesh1d1_conf overlay="overlay_pst_conf_overlay_psa_conf" RunTestFlash dfu_dist_recover_phase_psa \ dfu_cli_stop dfu_target_dfu_stop \ -- -argstest recover=1 expected-phase=3 -conf=prj_mesh1d1_conf overlay="overlay_pst_conf_overlay_psa_conf" RunTestFlash dfu_dist_recover_phase_psa \ dfu_cli_stop dfu_target_dfu_stop \ -- -argstest recover=1 expected-phase=4 -conf=prj_mesh1d1_conf overlay="overlay_pst_conf_overlay_psa_conf" RunTestFlash dfu_dist_recover_phase_psa \ dfu_cli_stop dfu_target_dfu_stop \ -- -argstest recover=1 expected-phase=6 # Use phase `BT_MESH_DFU_PHASE_APPLY_SUCCESS` as marker to bring whole procedure to an end -conf=prj_mesh1d1_conf overlay="overlay_pst_conf_overlay_psa_conf" RunTestFlash dfu_dist_recover_phase_psa \ dfu_cli_stop -flash_rm dfu_target_dfu_stop -flash_rm \ @@ -92,13 +80,11 @@ RunTestFlash dfu_dist_recover_phase_psa \ # To test recovery from Verify Fail begin new distribution that will end there, # reboot devices and continue to Applying. -conf=prj_mesh1d1_conf overlay="overlay_pst_conf_overlay_psa_conf" RunTestFlash dfu_dist_recover_phase_psa \ dfu_cli_stop -flash_erase dfu_target_dfu_stop -flash_erase \ -- -argstest recover=0 expected-phase=5 -conf=prj_mesh1d1_conf overlay="overlay_pst_conf_overlay_psa_conf" RunTestFlash dfu_dist_recover_phase_psa \ dfu_cli_stop -flash_rm dfu_target_dfu_stop -flash_rm \ diff --git a/tests/bsim/bluetooth/mesh/tests_scripts/friendship/establish.sh b/tests/bsim/bluetooth/mesh/tests_scripts/friendship/establish.sh index b89ad3af2c7..d1082fa9f29 100755 --- a/tests/bsim/bluetooth/mesh/tests_scripts/friendship/establish.sh +++ b/tests/bsim/bluetooth/mesh/tests_scripts/friendship/establish.sh @@ -9,12 +9,6 @@ RunTest mesh_friendship_est \ friendship_friend_est \ friendship_lpn_est -conf=prj_mesh1d1_conf -RunTest mesh_friendship_est_1d1 \ - friendship_friend_est \ - friendship_lpn_est - -conf=prj_mesh1d1_conf overlay=overlay_psa_conf RunTest mesh_friendship_est_psa \ friendship_friend_est \ diff --git a/tests/bsim/bluetooth/mesh/tests_scripts/friendship/establish_multi.sh b/tests/bsim/bluetooth/mesh/tests_scripts/friendship/establish_multi.sh index 725ddae596e..32e4752123d 100755 --- a/tests/bsim/bluetooth/mesh/tests_scripts/friendship/establish_multi.sh +++ b/tests/bsim/bluetooth/mesh/tests_scripts/friendship/establish_multi.sh @@ -14,16 +14,6 @@ RunTest mesh_friendship_est_multi \ friendship_lpn_est \ friendship_lpn_est -conf=prj_mesh1d1_conf -RunTest mesh_friendship_est_multi_1d1 \ - friendship_friend_est_multi \ - friendship_lpn_est \ - friendship_lpn_est \ - friendship_lpn_est \ - friendship_lpn_est \ - friendship_lpn_est - -conf=prj_mesh1d1_conf overlay=overlay_psa_conf RunTest mesh_friendship_est_multi_psa \ friendship_friend_est_multi \ diff --git a/tests/bsim/bluetooth/mesh/tests_scripts/friendship/lpn_disable.sh b/tests/bsim/bluetooth/mesh/tests_scripts/friendship/lpn_disable.sh index be22829d615..f8e24e51a3b 100755 --- a/tests/bsim/bluetooth/mesh/tests_scripts/friendship/lpn_disable.sh +++ b/tests/bsim/bluetooth/mesh/tests_scripts/friendship/lpn_disable.sh @@ -16,12 +16,6 @@ RunTest mesh_lpn_disable_check \ friendship_friend_no_est \ friendship_lpn_disable -conf=prj_mesh1d1_conf -RunTest mesh_lpn_disable_check_1d1 \ - friendship_friend_no_est \ - friendship_lpn_disable - -conf=prj_mesh1d1_conf overlay=overlay_psa_conf RunTest mesh_lpn_disable_check_psa \ friendship_friend_no_est \ diff --git a/tests/bsim/bluetooth/mesh/tests_scripts/friendship/lpn_loopback.sh b/tests/bsim/bluetooth/mesh/tests_scripts/friendship/lpn_loopback.sh index 676b6b81ccc..7c42d7912ff 100755 --- a/tests/bsim/bluetooth/mesh/tests_scripts/friendship/lpn_loopback.sh +++ b/tests/bsim/bluetooth/mesh/tests_scripts/friendship/lpn_loopback.sh @@ -9,12 +9,6 @@ RunTest mesh_friendship_lpn_loopback \ friendship_lpn_loopback \ friendship_friend_est -conf=prj_mesh1d1_conf -RunTest mesh_friendship_lpn_loopback_1d1 \ - friendship_lpn_loopback \ - friendship_friend_est - -conf=prj_mesh1d1_conf overlay=overlay_psa_conf RunTest mesh_friendship_lpn_loopback_psa \ friendship_lpn_loopback \ diff --git a/tests/bsim/bluetooth/mesh/tests_scripts/friendship/lpn_terminate_cb.sh b/tests/bsim/bluetooth/mesh/tests_scripts/friendship/lpn_terminate_cb.sh index 75163076af4..e51fec31dd2 100755 --- a/tests/bsim/bluetooth/mesh/tests_scripts/friendship/lpn_terminate_cb.sh +++ b/tests/bsim/bluetooth/mesh/tests_scripts/friendship/lpn_terminate_cb.sh @@ -14,12 +14,6 @@ RunTest mesh_lpn_terminate_cb_check \ friendship_friend_est \ friendship_lpn_term_cb_check -conf=prj_mesh1d1_conf -RunTest mesh_lpn_terminate_cb_check_1d1 \ - friendship_friend_est \ - friendship_lpn_term_cb_check - -conf=prj_mesh1d1_conf overlay=overlay_psa_conf RunTest mesh_lpn_terminate_cb_check_psa \ friendship_friend_est \ diff --git a/tests/bsim/bluetooth/mesh/tests_scripts/friendship/msg_frnd.sh b/tests/bsim/bluetooth/mesh/tests_scripts/friendship/msg_frnd.sh index 94d6224da5b..2329ed289eb 100755 --- a/tests/bsim/bluetooth/mesh/tests_scripts/friendship/msg_frnd.sh +++ b/tests/bsim/bluetooth/mesh/tests_scripts/friendship/msg_frnd.sh @@ -9,12 +9,6 @@ RunTest mesh_friendship_msg_frnd \ friendship_friend_msg \ friendship_lpn_msg_frnd -conf=prj_mesh1d1_conf -RunTest mesh_friendship_msg_frnd_1d1 \ - friendship_friend_msg \ - friendship_lpn_msg_frnd - -conf=prj_mesh1d1_conf overlay=overlay_psa_conf RunTest mesh_friendship_msg_frnd_psa \ friendship_friend_msg \ diff --git a/tests/bsim/bluetooth/mesh/tests_scripts/friendship/msg_group.sh b/tests/bsim/bluetooth/mesh/tests_scripts/friendship/msg_group.sh index 6e7287b00ff..d6de655ba5b 100755 --- a/tests/bsim/bluetooth/mesh/tests_scripts/friendship/msg_group.sh +++ b/tests/bsim/bluetooth/mesh/tests_scripts/friendship/msg_group.sh @@ -10,13 +10,6 @@ RunTest mesh_friendship_msg_group \ friendship_other_group \ friendship_friend_group -conf=prj_mesh1d1_conf -RunTest mesh_friendship_msg_group_1d1 \ - friendship_lpn_group \ - friendship_other_group \ - friendship_friend_group - -conf=prj_mesh1d1_conf overlay=overlay_psa_conf RunTest mesh_friendship_msg_group_psa \ friendship_lpn_group \ diff --git a/tests/bsim/bluetooth/mesh/tests_scripts/friendship/msg_mesh.sh b/tests/bsim/bluetooth/mesh/tests_scripts/friendship/msg_mesh.sh index 072e427d72a..f05261bb258 100755 --- a/tests/bsim/bluetooth/mesh/tests_scripts/friendship/msg_mesh.sh +++ b/tests/bsim/bluetooth/mesh/tests_scripts/friendship/msg_mesh.sh @@ -10,13 +10,6 @@ RunTest mesh_friendship_msg_mesh \ friendship_other_msg \ friendship_friend_est -conf=prj_mesh1d1_conf -RunTest mesh_friendship_msg_mesh_1d1 \ - friendship_lpn_msg_mesh \ - friendship_other_msg \ - friendship_friend_est - -conf=prj_mesh1d1_conf overlay=overlay_psa_conf RunTest mesh_friendship_msg_mesh_psa \ friendship_lpn_msg_mesh \ diff --git a/tests/bsim/bluetooth/mesh/tests_scripts/friendship/msg_mesh_low_lat.sh b/tests/bsim/bluetooth/mesh/tests_scripts/friendship/msg_mesh_low_lat.sh index d659281e4e9..3352d5812e6 100755 --- a/tests/bsim/bluetooth/mesh/tests_scripts/friendship/msg_mesh_low_lat.sh +++ b/tests/bsim/bluetooth/mesh/tests_scripts/friendship/msg_mesh_low_lat.sh @@ -11,14 +11,6 @@ RunTest mesh_friendship_msg_mesh_low_lat \ friendship_other_msg \ friendship_friend_est -conf=prj_mesh1d1_conf -overlay=overlay_low_lat_conf -RunTest mesh_friendship_msg_mesh_low_lat_1d1 \ - friendship_lpn_msg_mesh \ - friendship_other_msg \ - friendship_friend_est - -conf=prj_mesh1d1_conf overlay="overlay_low_lat_conf_overlay_psa_conf" RunTest mesh_friendship_msg_mesh_low_lat_psa \ friendship_lpn_msg_mesh \ diff --git a/tests/bsim/bluetooth/mesh/tests_scripts/friendship/msg_va_collision.sh b/tests/bsim/bluetooth/mesh/tests_scripts/friendship/msg_va_collision.sh index 360095d2e5f..3ec9cd29162 100755 --- a/tests/bsim/bluetooth/mesh/tests_scripts/friendship/msg_va_collision.sh +++ b/tests/bsim/bluetooth/mesh/tests_scripts/friendship/msg_va_collision.sh @@ -24,12 +24,6 @@ RunTest mesh_friendship_msg_va_collision \ friendship_lpn_va_collision \ friendship_friend_va_collision -conf=prj_mesh1d1_conf -RunTest mesh_friendship_msg_va_collision_1d1 \ - friendship_lpn_va_collision \ - friendship_friend_va_collision - -conf=prj_mesh1d1_conf overlay=overlay_psa_conf RunTest mesh_friendship_msg_va_collision_psa \ friendship_lpn_va_collision \ diff --git a/tests/bsim/bluetooth/mesh/tests_scripts/friendship/overflow.sh b/tests/bsim/bluetooth/mesh/tests_scripts/friendship/overflow.sh index d717be60292..90398fb4d8a 100755 --- a/tests/bsim/bluetooth/mesh/tests_scripts/friendship/overflow.sh +++ b/tests/bsim/bluetooth/mesh/tests_scripts/friendship/overflow.sh @@ -9,12 +9,6 @@ RunTest mesh_friendship_overflow \ friendship_friend_overflow \ friendship_lpn_overflow -conf=prj_mesh1d1_conf -RunTest mesh_friendship_overflow_1d1 \ - friendship_friend_overflow \ - friendship_lpn_overflow - -conf=prj_mesh1d1_conf overlay=overlay_psa_conf RunTest mesh_friendship_overflow_psa \ friendship_friend_overflow \ diff --git a/tests/bsim/bluetooth/mesh/tests_scripts/friendship/poll.sh b/tests/bsim/bluetooth/mesh/tests_scripts/friendship/poll.sh index 90e744a7001..328050ba39e 100755 --- a/tests/bsim/bluetooth/mesh/tests_scripts/friendship/poll.sh +++ b/tests/bsim/bluetooth/mesh/tests_scripts/friendship/poll.sh @@ -9,12 +9,6 @@ RunTest mesh_friendship_poll \ friendship_friend_est \ friendship_lpn_poll -conf=prj_mesh1d1_conf -RunTest mesh_friendship_poll_1d1 \ - friendship_friend_est \ - friendship_lpn_poll - -conf=prj_mesh1d1_conf overlay=overlay_psa_conf RunTest mesh_friendship_poll_psa \ friendship_friend_est \ diff --git a/tests/bsim/bluetooth/mesh/tests_scripts/friendship/re-establish.sh b/tests/bsim/bluetooth/mesh/tests_scripts/friendship/re-establish.sh index 10abb4413ea..27b3e07e5f6 100755 --- a/tests/bsim/bluetooth/mesh/tests_scripts/friendship/re-establish.sh +++ b/tests/bsim/bluetooth/mesh/tests_scripts/friendship/re-establish.sh @@ -9,12 +9,6 @@ RunTest mesh_friendship_re_est \ friendship_friend_est \ friendship_lpn_re_est -conf=prj_mesh1d1_conf -RunTest mesh_friendship_re_est_1d1 \ - friendship_friend_est \ - friendship_lpn_re_est - -conf=prj_mesh1d1_conf overlay=overlay_psa_conf RunTest mesh_friendship_re_est_psa \ friendship_friend_est \ diff --git a/tests/bsim/bluetooth/mesh/tests_scripts/heartbeat/sub_cb_api_all.sh b/tests/bsim/bluetooth/mesh/tests_scripts/heartbeat/sub_cb_api_all.sh index eef25d08cf2..5bef1473a07 100755 --- a/tests/bsim/bluetooth/mesh/tests_scripts/heartbeat/sub_cb_api_all.sh +++ b/tests/bsim/bluetooth/mesh/tests_scripts/heartbeat/sub_cb_api_all.sh @@ -10,13 +10,6 @@ RunTest mesh_heartbeat_sub_cb_api_all \ heartbeat_publish_all \ heartbeat_subscribe_all -conf=prj_mesh1d1_conf -RunTest mesh_heartbeat_sub_cb_api_all_1d1 \ - heartbeat_publish_all \ - heartbeat_publish_all \ - heartbeat_subscribe_all - -conf=prj_mesh1d1_conf overlay=overlay_psa_conf RunTest mesh_heartbeat_sub_cb_api_all_psa \ heartbeat_publish_all \ diff --git a/tests/bsim/bluetooth/mesh/tests_scripts/heartbeat/sub_cb_api_unicast.sh b/tests/bsim/bluetooth/mesh/tests_scripts/heartbeat/sub_cb_api_unicast.sh index fc0660e5676..93b1e2ffe9f 100755 --- a/tests/bsim/bluetooth/mesh/tests_scripts/heartbeat/sub_cb_api_unicast.sh +++ b/tests/bsim/bluetooth/mesh/tests_scripts/heartbeat/sub_cb_api_unicast.sh @@ -10,13 +10,6 @@ RunTest mesh_heartbeat_sub_cb_api_unicast \ heartbeat_publish_unicast \ heartbeat_subscribe_unicast -conf=prj_mesh1d1_conf -RunTest mesh_heartbeat_sub_cb_api_unicast_1d1 \ - heartbeat_publish_unicast \ - heartbeat_publish_unicast \ - heartbeat_subscribe_unicast - -conf=prj_mesh1d1_conf overlay=overlay_psa_conf RunTest mesh_heartbeat_sub_cb_api_unicast_psa \ heartbeat_publish_unicast \ diff --git a/tests/bsim/bluetooth/mesh/tests_scripts/iv_index/iv_deferring.sh b/tests/bsim/bluetooth/mesh/tests_scripts/iv_index/iv_deferring.sh index cdf39dac438..6696b28ae00 100755 --- a/tests/bsim/bluetooth/mesh/tests_scripts/iv_index/iv_deferring.sh +++ b/tests/bsim/bluetooth/mesh/tests_scripts/iv_index/iv_deferring.sh @@ -7,9 +7,5 @@ source $(dirname "${BASH_SOURCE[0]}")/../../_mesh_test.sh # test deferring of the IV index update procedure RunTest mesh_ivi_deferring ivi_ivu_deferring -conf=prj_mesh1d1_conf -RunTest mesh_ivi_deferring_1d1 ivi_ivu_deferring - -conf=prj_mesh1d1_conf overlay=overlay_psa_conf RunTest mesh_ivi_deferring_psa ivi_ivu_deferring diff --git a/tests/bsim/bluetooth/mesh/tests_scripts/iv_index/iv_recovery.sh b/tests/bsim/bluetooth/mesh/tests_scripts/iv_index/iv_recovery.sh index 39514bf39e6..a827f9b3abf 100755 --- a/tests/bsim/bluetooth/mesh/tests_scripts/iv_index/iv_recovery.sh +++ b/tests/bsim/bluetooth/mesh/tests_scripts/iv_index/iv_recovery.sh @@ -7,9 +7,5 @@ source $(dirname "${BASH_SOURCE[0]}")/../../_mesh_test.sh # test IV index recovery procedure RunTest mesh_ivi_recovery ivi_ivu_recovery -conf=prj_mesh1d1_conf -RunTest mesh_ivi_recovery_1d1 ivi_ivu_recovery - -conf=prj_mesh1d1_conf overlay=overlay_psa_conf RunTest mesh_ivi_recovery_psa ivi_ivu_recovery diff --git a/tests/bsim/bluetooth/mesh/tests_scripts/iv_index/iv_update.sh b/tests/bsim/bluetooth/mesh/tests_scripts/iv_index/iv_update.sh index ee2b6b20000..f2f652012b8 100755 --- a/tests/bsim/bluetooth/mesh/tests_scripts/iv_index/iv_update.sh +++ b/tests/bsim/bluetooth/mesh/tests_scripts/iv_index/iv_update.sh @@ -7,9 +7,5 @@ source $(dirname "${BASH_SOURCE[0]}")/../../_mesh_test.sh # test IV index update procedure RunTest mesh_ivi_update ivi_ivu_normal -conf=prj_mesh1d1_conf -RunTest mesh_ivi_update_1d1 ivi_ivu_normal - -conf=prj_mesh1d1_conf overlay=overlay_psa_conf RunTest mesh_ivi_update_psa ivi_ivu_normal diff --git a/tests/bsim/bluetooth/mesh/tests_scripts/large_comp_data/get_comp0_data_split.sh b/tests/bsim/bluetooth/mesh/tests_scripts/large_comp_data/get_comp0_data_split.sh index d65326b3d7f..dcaba598a57 100755 --- a/tests/bsim/bluetooth/mesh/tests_scripts/large_comp_data/get_comp0_data_split.sh +++ b/tests/bsim/bluetooth/mesh/tests_scripts/large_comp_data/get_comp0_data_split.sh @@ -19,12 +19,10 @@ source $(dirname "${BASH_SOURCE[0]}")/../../_mesh_test.sh # comp data with correspending bytes in local comp data. # 6. Client merges the two samples and checks that the collected data is # correctly merged, continuous, and matches its local comp data. -conf=prj_mesh1d1_conf overlay=overlay_pst_conf RunTest mesh_lcd_test_comp0_data_split \ lcd_srv_comp_data_status_respond lcd_cli_split_comp_data_request -- -argstest page=0 -conf=prj_mesh1d1_conf overlay="overlay_pst_conf_overlay_psa_conf" RunTest mesh_lcd_test_comp0_data_split \ lcd_srv_comp_data_status_respond lcd_cli_split_comp_data_request -- -argstest page=0 diff --git a/tests/bsim/bluetooth/mesh/tests_scripts/large_comp_data/get_comp0_data_split_dfu.sh b/tests/bsim/bluetooth/mesh/tests_scripts/large_comp_data/get_comp0_data_split_dfu.sh index 6a65a2492ed..004a5224961 100755 --- a/tests/bsim/bluetooth/mesh/tests_scripts/large_comp_data/get_comp0_data_split_dfu.sh +++ b/tests/bsim/bluetooth/mesh/tests_scripts/large_comp_data/get_comp0_data_split_dfu.sh @@ -20,13 +20,11 @@ source $(dirname "${BASH_SOURCE[0]}")/../../_mesh_test.sh # comp data with correspending bytes in local comp data. # 6. Client merges the two samples and checks that the collected data is # correctly merged, continuous, and matches its local comp data. -conf=prj_mesh1d1_conf overlay=overlay_pst_conf RunTest mesh_lcd_test_comp0_data_split_dfu \ lcd_srv_comp_data_status_respond \ lcd_cli_split_comp_data_request -- -argstest page=0 comp-changed-mode=1 -conf=prj_mesh1d1_conf overlay="overlay_pst_conf_overlay_psa_conf" RunTest mesh_lcd_test_comp0_data_split_dfu \ lcd_srv_comp_data_status_respond \ diff --git a/tests/bsim/bluetooth/mesh/tests_scripts/large_comp_data/get_comp128_data_split.sh b/tests/bsim/bluetooth/mesh/tests_scripts/large_comp_data/get_comp128_data_split.sh index 77d4a1737a5..f88db1b7391 100755 --- a/tests/bsim/bluetooth/mesh/tests_scripts/large_comp_data/get_comp128_data_split.sh +++ b/tests/bsim/bluetooth/mesh/tests_scripts/large_comp_data/get_comp128_data_split.sh @@ -19,12 +19,10 @@ source $(dirname "${BASH_SOURCE[0]}")/../../_mesh_test.sh # comp data with correspending bytes in local comp data. # 6. Client merges the two samples and checks that the collected data is # correctly merged, continuous, and matches its local comp data. -conf=prj_mesh1d1_conf overlay=overlay_pst_conf RunTest mesh_lcd_test_comp128_data_split \ lcd_srv_comp_data_status_respond lcd_cli_split_comp_data_request -- -argstest page=128 -conf=prj_mesh1d1_conf overlay="overlay_pst_conf_overlay_psa_conf" RunTest mesh_lcd_test_comp128_data_split \ lcd_srv_comp_data_status_respond lcd_cli_split_comp_data_request -- -argstest page=128 diff --git a/tests/bsim/bluetooth/mesh/tests_scripts/large_comp_data/get_comp128_data_split_dfu.sh b/tests/bsim/bluetooth/mesh/tests_scripts/large_comp_data/get_comp128_data_split_dfu.sh index 9abdfd00dd7..084125c79a4 100755 --- a/tests/bsim/bluetooth/mesh/tests_scripts/large_comp_data/get_comp128_data_split_dfu.sh +++ b/tests/bsim/bluetooth/mesh/tests_scripts/large_comp_data/get_comp128_data_split_dfu.sh @@ -20,13 +20,11 @@ source $(dirname "${BASH_SOURCE[0]}")/../../_mesh_test.sh # comp data with correspending bytes in local comp data. # 6. Client merges the two samples and checks that the collected data is # correctly merged, continuous, and matches its local comp data. -conf=prj_mesh1d1_conf overlay=overlay_pst_conf RunTest mesh_lcd_test_comp128_data_split_dfu \ lcd_srv_comp_data_status_respond \ lcd_cli_split_comp_data_request -- -argstest page=128 comp-changed-mode=1 -conf=prj_mesh1d1_conf overlay="overlay_pst_conf_overlay_psa_conf" RunTest mesh_lcd_test_comp128_data_split_dfu \ lcd_srv_comp_data_status_respond \ diff --git a/tests/bsim/bluetooth/mesh/tests_scripts/large_comp_data/get_comp129_data_split.sh b/tests/bsim/bluetooth/mesh/tests_scripts/large_comp_data/get_comp129_data_split.sh index fba1760cb36..ab46d32048f 100755 --- a/tests/bsim/bluetooth/mesh/tests_scripts/large_comp_data/get_comp129_data_split.sh +++ b/tests/bsim/bluetooth/mesh/tests_scripts/large_comp_data/get_comp129_data_split.sh @@ -19,12 +19,10 @@ source $(dirname "${BASH_SOURCE[0]}")/../../_mesh_test.sh # comp data with correspending bytes in local comp data. # 6. Client merges the two samples and checks that the collected data is # correctly merged, continuous, and matches its local comp data. -conf=prj_mesh1d1_conf overlay=overlay_pst_conf RunTest mesh_lcd_test_comp129_data_split \ lcd_srv_comp_data_status_respond lcd_cli_split_comp_data_request -- -argstest page=129 -conf=prj_mesh1d1_conf overlay="overlay_pst_conf_overlay_psa_conf" RunTest mesh_lcd_test_comp129_data_split \ lcd_srv_comp_data_status_respond lcd_cli_split_comp_data_request -- -argstest page=129 diff --git a/tests/bsim/bluetooth/mesh/tests_scripts/large_comp_data/get_comp129_data_split_dfu.sh b/tests/bsim/bluetooth/mesh/tests_scripts/large_comp_data/get_comp129_data_split_dfu.sh index 282c3425c81..179c052e0ef 100755 --- a/tests/bsim/bluetooth/mesh/tests_scripts/large_comp_data/get_comp129_data_split_dfu.sh +++ b/tests/bsim/bluetooth/mesh/tests_scripts/large_comp_data/get_comp129_data_split_dfu.sh @@ -20,13 +20,11 @@ source $(dirname "${BASH_SOURCE[0]}")/../../_mesh_test.sh # comp data with correspending bytes in local comp data. # 6. Client merges the two samples and checks that the collected data is # correctly merged, continuous, and matches its local comp data. -conf=prj_mesh1d1_conf overlay=overlay_pst_conf RunTest mesh_lcd_test_comp129_data_split_dfu \ lcd_srv_comp_data_status_respond \ lcd_cli_split_comp_data_request -- -argstest page=129 comp-changed-mode=1 -conf=prj_mesh1d1_conf overlay="overlay_pst_conf_overlay_psa_conf" RunTest mesh_lcd_test_comp129_data_split_dfu \ lcd_srv_comp_data_status_respond \ diff --git a/tests/bsim/bluetooth/mesh/tests_scripts/large_comp_data/get_comp130_data_split.sh b/tests/bsim/bluetooth/mesh/tests_scripts/large_comp_data/get_comp130_data_split.sh index e3e8f2bad85..eb25353581b 100755 --- a/tests/bsim/bluetooth/mesh/tests_scripts/large_comp_data/get_comp130_data_split.sh +++ b/tests/bsim/bluetooth/mesh/tests_scripts/large_comp_data/get_comp130_data_split.sh @@ -19,12 +19,10 @@ source $(dirname "${BASH_SOURCE[0]}")/../../_mesh_test.sh # comp data with correspending bytes in local comp data. # 6. Client merges the two samples and checks that the collected data is # correctly merged, continuous, and matches its local comp data. -conf=prj_mesh1d1_conf overlay=overlay_pst_conf RunTest mesh_lcd_test_comp130_data_split \ lcd_srv_comp_data_status_respond lcd_cli_split_comp_data_request -- -argstest page=130 -conf=prj_mesh1d1_conf overlay="overlay_pst_conf_overlay_psa_conf" RunTest mesh_lcd_test_comp130_data_split \ lcd_srv_comp_data_status_respond lcd_cli_split_comp_data_request -- -argstest page=130 diff --git a/tests/bsim/bluetooth/mesh/tests_scripts/large_comp_data/get_comp130_data_split_dfu.sh b/tests/bsim/bluetooth/mesh/tests_scripts/large_comp_data/get_comp130_data_split_dfu.sh index 5daf32c54c0..a667f53abc8 100755 --- a/tests/bsim/bluetooth/mesh/tests_scripts/large_comp_data/get_comp130_data_split_dfu.sh +++ b/tests/bsim/bluetooth/mesh/tests_scripts/large_comp_data/get_comp130_data_split_dfu.sh @@ -20,13 +20,11 @@ source $(dirname "${BASH_SOURCE[0]}")/../../_mesh_test.sh # comp data with correspending bytes in local comp data. # 6. Client merges the two samples and checks that the collected data is # correctly merged, continuous, and matches its local comp data. -conf=prj_mesh1d1_conf overlay=overlay_pst_conf RunTest mesh_lcd_test_comp130_data_split_dfu \ lcd_srv_comp_data_status_respond \ lcd_cli_split_comp_data_request -- -argstest page=130 comp-changed-mode=1 -conf=prj_mesh1d1_conf overlay="overlay_pst_conf_overlay_psa_conf" RunTest mesh_lcd_test_comp130_data_split_dfu \ lcd_srv_comp_data_status_respond \ diff --git a/tests/bsim/bluetooth/mesh/tests_scripts/large_comp_data/get_comp1_data_split.sh b/tests/bsim/bluetooth/mesh/tests_scripts/large_comp_data/get_comp1_data_split.sh index bc24a9c9bf9..06312cf558b 100755 --- a/tests/bsim/bluetooth/mesh/tests_scripts/large_comp_data/get_comp1_data_split.sh +++ b/tests/bsim/bluetooth/mesh/tests_scripts/large_comp_data/get_comp1_data_split.sh @@ -19,12 +19,10 @@ source $(dirname "${BASH_SOURCE[0]}")/../../_mesh_test.sh # comp data with correspending bytes in local comp data. # 6. Client merges the two samples and checks that the collected data is # correctly merged, continuous, and matches its local comp data. -conf=prj_mesh1d1_conf overlay=overlay_pst_conf RunTest mesh_lcd_test_comp1_data_split \ lcd_srv_comp_data_status_respond lcd_cli_split_comp_data_request -- -argstest page=1 -conf=prj_mesh1d1_conf overlay="overlay_pst_conf_overlay_psa_conf" RunTest mesh_lcd_test_comp1_data_split \ lcd_srv_comp_data_status_respond lcd_cli_split_comp_data_request -- -argstest page=1 diff --git a/tests/bsim/bluetooth/mesh/tests_scripts/large_comp_data/get_comp1_data_split_dfu.sh b/tests/bsim/bluetooth/mesh/tests_scripts/large_comp_data/get_comp1_data_split_dfu.sh index 59383bb18f1..61f19ea3dcc 100755 --- a/tests/bsim/bluetooth/mesh/tests_scripts/large_comp_data/get_comp1_data_split_dfu.sh +++ b/tests/bsim/bluetooth/mesh/tests_scripts/large_comp_data/get_comp1_data_split_dfu.sh @@ -20,13 +20,11 @@ source $(dirname "${BASH_SOURCE[0]}")/../../_mesh_test.sh # comp data with correspending bytes in local comp data. # 6. Client merges the two samples and checks that the collected data is # correctly merged, continuous, and matches its local comp data. -conf=prj_mesh1d1_conf overlay=overlay_pst_conf RunTest mesh_lcd_test_comp1_data_split_dfu \ lcd_srv_comp_data_status_respond \ lcd_cli_split_comp_data_request -- -argstest page=1 comp-changed-mode=1 -conf=prj_mesh1d1_conf overlay="overlay_pst_conf_overlay_psa_conf" RunTest mesh_lcd_test_comp1_data_split_dfu \ lcd_srv_comp_data_status_respond \ diff --git a/tests/bsim/bluetooth/mesh/tests_scripts/large_comp_data/get_comp2_data_split.sh b/tests/bsim/bluetooth/mesh/tests_scripts/large_comp_data/get_comp2_data_split.sh index 53def43d5a0..3da45434ee1 100755 --- a/tests/bsim/bluetooth/mesh/tests_scripts/large_comp_data/get_comp2_data_split.sh +++ b/tests/bsim/bluetooth/mesh/tests_scripts/large_comp_data/get_comp2_data_split.sh @@ -19,12 +19,10 @@ source $(dirname "${BASH_SOURCE[0]}")/../../_mesh_test.sh # comp data with correspending bytes in local comp data. # 6. Client merges the two samples and checks that the collected data is # correctly merged, continuous, and matches its local comp data. -conf=prj_mesh1d1_conf overlay=overlay_pst_conf RunTest mesh_lcd_test_comp2_data_split \ lcd_srv_comp_data_status_respond lcd_cli_split_comp_data_request -- -argstest page=2 -conf=prj_mesh1d1_conf overlay="overlay_pst_conf_overlay_psa_conf" RunTest mesh_lcd_test_comp2_data_split \ lcd_srv_comp_data_status_respond lcd_cli_split_comp_data_request -- -argstest page=2 diff --git a/tests/bsim/bluetooth/mesh/tests_scripts/large_comp_data/get_comp2_data_split_dfu.sh b/tests/bsim/bluetooth/mesh/tests_scripts/large_comp_data/get_comp2_data_split_dfu.sh index f314f00d6ef..8ad929f1374 100755 --- a/tests/bsim/bluetooth/mesh/tests_scripts/large_comp_data/get_comp2_data_split_dfu.sh +++ b/tests/bsim/bluetooth/mesh/tests_scripts/large_comp_data/get_comp2_data_split_dfu.sh @@ -20,13 +20,11 @@ source $(dirname "${BASH_SOURCE[0]}")/../../_mesh_test.sh # comp data with correspending bytes in local comp data. # 6. Client merges the two samples and checks that the collected data is # correctly merged, continuous, and matches its local comp data. -conf=prj_mesh1d1_conf overlay=overlay_pst_conf RunTest mesh_lcd_test_comp2_data_split_dfu \ lcd_srv_comp_data_status_respond \ lcd_cli_split_comp_data_request -- -argstest page=2 comp-changed-mode=1 -conf=prj_mesh1d1_conf overlay="overlay_pst_conf_overlay_psa_conf" RunTest mesh_lcd_test_comp2_data_split_dfu \ lcd_srv_comp_data_status_respond \ diff --git a/tests/bsim/bluetooth/mesh/tests_scripts/large_comp_data/get_comp_data_max_sdu.sh b/tests/bsim/bluetooth/mesh/tests_scripts/large_comp_data/get_comp_data_max_sdu.sh index b050037ccf0..71a692fa22c 100755 --- a/tests/bsim/bluetooth/mesh/tests_scripts/large_comp_data/get_comp_data_max_sdu.sh +++ b/tests/bsim/bluetooth/mesh/tests_scripts/large_comp_data/get_comp_data_max_sdu.sh @@ -14,12 +14,10 @@ source $(dirname "${BASH_SOURCE[0]}")/../../_mesh_test.sh # 3. When server status arrive, remove status field data and compare received # comp data with local comp data and assure that the received message length # is 378 bytes (380 bytes access payload). -conf=prj_mesh1d1_conf overlay=overlay_pst_conf RunTest mesh_lcd_test_max_access_payload \ lcd_cli_max_sdu_comp_data_request lcd_srv_comp_data_status_respond -conf=prj_mesh1d1_conf overlay="overlay_pst_conf_overlay_psa_conf" RunTest mesh_lcd_test_max_access_payload_psa \ lcd_cli_max_sdu_comp_data_request lcd_srv_comp_data_status_respond diff --git a/tests/bsim/bluetooth/mesh/tests_scripts/large_comp_data/get_metadata_max_sdu.sh b/tests/bsim/bluetooth/mesh/tests_scripts/large_comp_data/get_metadata_max_sdu.sh index 9b0be5ea20f..ef0f5712526 100755 --- a/tests/bsim/bluetooth/mesh/tests_scripts/large_comp_data/get_metadata_max_sdu.sh +++ b/tests/bsim/bluetooth/mesh/tests_scripts/large_comp_data/get_metadata_max_sdu.sh @@ -15,12 +15,10 @@ source $(dirname "${BASH_SOURCE[0]}")/../../_mesh_test.sh # is 378 bytes (380 bytes access payload). # 4. Remove status field data and compare received metadata with # local metadata data. -conf=prj_mesh1d1_conf overlay=overlay_pst_conf RunTest mesh_lcd_test_max_metadata_access_payload \ lcd_cli_max_sdu_metadata_request lcd_srv_metadata_status_respond -conf=prj_mesh1d1_conf overlay="overlay_pst_conf_overlay_psa_conf" RunTest mesh_lcd_test_max_metadata_access_payload_psa \ lcd_cli_max_sdu_metadata_request lcd_srv_metadata_status_respond diff --git a/tests/bsim/bluetooth/mesh/tests_scripts/large_comp_data/get_metadata_split.sh b/tests/bsim/bluetooth/mesh/tests_scripts/large_comp_data/get_metadata_split.sh index 0e29e7d4219..38e43f88601 100755 --- a/tests/bsim/bluetooth/mesh/tests_scripts/large_comp_data/get_metadata_split.sh +++ b/tests/bsim/bluetooth/mesh/tests_scripts/large_comp_data/get_metadata_split.sh @@ -18,12 +18,10 @@ source $(dirname "${BASH_SOURCE[0]}")/../../_mesh_test.sh # received metadata with corresponding bytes in local data. # 6. Client merges the two samples and checks that the collected data is # correctly merged, continuous, and matches its local metadata. -conf=prj_mesh1d1_conf overlay=overlay_pst_conf RunTest mesh_lcd_test_split_metadata \ lcd_cli_split_metadata_request lcd_srv_metadata_status_respond -conf=prj_mesh1d1_conf overlay="overlay_pst_conf_overlay_psa_conf" RunTest mesh_lcd_test_split_metadata_psa \ lcd_cli_split_metadata_request lcd_srv_metadata_status_respond diff --git a/tests/bsim/bluetooth/mesh/tests_scripts/op_agg/full_status_msg_list.sh b/tests/bsim/bluetooth/mesh/tests_scripts/op_agg/full_status_msg_list.sh index fb60110ad7b..7a226017470 100755 --- a/tests/bsim/bluetooth/mesh/tests_scripts/op_agg/full_status_msg_list.sh +++ b/tests/bsim/bluetooth/mesh/tests_scripts/op_agg/full_status_msg_list.sh @@ -22,11 +22,9 @@ source $(dirname "${BASH_SOURCE[0]}")/../../_mesh_test.sh # 6. The client keeps track of the number of received status messages. When X messages have been # received, the client pass if the sequence of received status messages corresponds to the order # in which the messages were sent, or the test fails. -conf=prj_mesh1d1_conf RunTest mesh_op_agg_test_max_access_payload \ op_agg_cli_max_len_sequence_msg_send op_agg_srv_max_len_status_msg_send -conf=prj_mesh1d1_conf overlay=overlay_psa_conf RunTest mesh_op_agg_test_max_access_payload_psa \ op_agg_cli_max_len_sequence_msg_send op_agg_srv_max_len_status_msg_send diff --git a/tests/bsim/bluetooth/mesh/tests_scripts/op_agg/loopback.sh b/tests/bsim/bluetooth/mesh/tests_scripts/op_agg/loopback.sh index 3a4720bdaf4..7d2c7eec7d2 100755 --- a/tests/bsim/bluetooth/mesh/tests_scripts/op_agg/loopback.sh +++ b/tests/bsim/bluetooth/mesh/tests_scripts/op_agg/loopback.sh @@ -12,11 +12,9 @@ source $(dirname "${BASH_SOURCE[0]}")/../../_mesh_test.sh # 2. The device starts sending the sequence on loopback. # 3. The device verifies that the sequence is correctly received by the server model. # 4. The device confirms that the client model received all status messages. -conf=prj_mesh1d1_conf RunTest mesh_op_agg_model_coex_loopback \ op_agg_dut_model_coex_loopback -conf=prj_mesh1d1_conf overlay=overlay_psa_conf RunTest mesh_op_agg_model_coex_loopback \ op_agg_dut_model_coex_loopback diff --git a/tests/bsim/bluetooth/mesh/tests_scripts/op_agg/model_coex.sh b/tests/bsim/bluetooth/mesh/tests_scripts/op_agg/model_coex.sh index 08fcdf9f41e..928abd666f9 100755 --- a/tests/bsim/bluetooth/mesh/tests_scripts/op_agg/model_coex.sh +++ b/tests/bsim/bluetooth/mesh/tests_scripts/op_agg/model_coex.sh @@ -21,11 +21,9 @@ source $(dirname "${BASH_SOURCE[0]}")/../../_mesh_test.sh # aggregated sequence from the DUT device is correctly received. # 5. Finally, the DUT device waits and confirms that it received all status messages # related to its own aggregated sequence from the cli device. -conf=prj_mesh1d1_conf RunTest mesh_op_agg_model_coex \ op_agg_tester_model_coex op_agg_dut_model_coex -conf=prj_mesh1d1_conf overlay=overlay_psa_conf RunTest mesh_op_agg_model_coex \ op_agg_tester_model_coex op_agg_dut_model_coex diff --git a/tests/bsim/bluetooth/mesh/tests_scripts/persistence/access.sh b/tests/bsim/bluetooth/mesh/tests_scripts/persistence/access.sh index 0392430adba..cf9ec54faec 100755 --- a/tests/bsim/bluetooth/mesh/tests_scripts/persistence/access.sh +++ b/tests/bsim/bluetooth/mesh/tests_scripts/persistence/access.sh @@ -31,60 +31,25 @@ overlay=overlay_pst_conf RunTestFlash mesh_pst_access_data_check persistence_access_data_load -flash_rm \ -- -argstest access-cfg=not-configured -conf=prj_mesh1d1_conf -overlay=overlay_pst_conf -RunTestFlash mesh_pst_access_data_check_1d1 persistence_access_data_save -flash_erase - -conf=prj_mesh1d1_conf -overlay=overlay_pst_conf -RunTestFlash mesh_pst_access_data_check_1d1 persistence_access_data_load \ - -- -argstest access-cfg=configured - -conf=prj_mesh1d1_conf -overlay=overlay_pst_conf -RunTestFlash mesh_pst_access_data_check_1d1 persistence_access_sub_overwrite \ - -- -argstest access-cfg=configured - -conf=prj_mesh1d1_conf -overlay=overlay_pst_conf -RunTestFlash mesh_pst_access_data_check_1d1 persistence_access_data_load \ - -- -argstest access-cfg=new-subs - -conf=prj_mesh1d1_conf -overlay=overlay_pst_conf -RunTestFlash mesh_pst_access_data_check_1d1 persistence_access_data_remove \ - -- -argstest access-cfg=new-subs - -conf=prj_mesh1d1_conf -overlay=overlay_pst_conf -RunTestFlash mesh_pst_access_data_check_1d1 persistence_access_data_load -flash_rm \ - -- -argstest access-cfg=not-configured - -conf=prj_mesh1d1_conf overlay="overlay_pst_conf_overlay_psa_conf" RunTestFlash mesh_pst_access_data_check_psa persistence_access_data_save -flash_erase -conf=prj_mesh1d1_conf overlay="overlay_pst_conf_overlay_psa_conf" RunTestFlash mesh_pst_access_data_check_psa persistence_access_data_load \ -- -argstest access-cfg=configured -conf=prj_mesh1d1_conf overlay="overlay_pst_conf_overlay_psa_conf" RunTestFlash mesh_pst_access_data_check_psa persistence_access_sub_overwrite \ -- -argstest access-cfg=configured -conf=prj_mesh1d1_conf overlay="overlay_pst_conf_overlay_psa_conf" RunTestFlash mesh_pst_access_data_check_psa persistence_access_data_load \ -- -argstest access-cfg=new-subs -conf=prj_mesh1d1_conf overlay="overlay_pst_conf_overlay_psa_conf" RunTestFlash mesh_pst_access_data_check_psa persistence_access_data_remove \ -- -argstest access-cfg=new-subs -conf=prj_mesh1d1_conf overlay="overlay_pst_conf_overlay_psa_conf" RunTestFlash mesh_pst_access_data_check_psa persistence_access_data_load -flash_rm \ -- -argstest access-cfg=not-configured diff --git a/tests/bsim/bluetooth/mesh/tests_scripts/persistence/cfg.sh b/tests/bsim/bluetooth/mesh/tests_scripts/persistence/cfg.sh index bb3074905a9..f9655ef7462 100755 --- a/tests/bsim/bluetooth/mesh/tests_scripts/persistence/cfg.sh +++ b/tests/bsim/bluetooth/mesh/tests_scripts/persistence/cfg.sh @@ -24,42 +24,18 @@ overlay=overlay_pst_conf RunTestFlash mesh_pst_cfg_check persistence_cfg_load -flash_rm \ -- -argstest stack-cfg=1 -conf=prj_mesh1d1_conf -overlay=overlay_pst_conf -RunTestFlash mesh_pst_cfg_check_1d1 persistence_cfg_save -flash_erase \ - -- -argstest stack-cfg=0 - -conf=prj_mesh1d1_conf -overlay=overlay_pst_conf -RunTestFlash mesh_pst_cfg_check_1d1 persistence_cfg_load -flash_rm \ - -- -argstest stack-cfg=0 - -conf=prj_mesh1d1_conf -overlay=overlay_pst_conf -RunTestFlash mesh_pst_cfg_check_1d1 persistence_cfg_save -flash_erase \ - -- -argstest stack-cfg=1 - -conf=prj_mesh1d1_conf -overlay=overlay_pst_conf -RunTestFlash mesh_pst_cfg_check_1d1 persistence_cfg_load -flash_rm \ - -- -argstest stack-cfg=1 - -conf=prj_mesh1d1_conf overlay="overlay_pst_conf_overlay_psa_conf" RunTestFlash mesh_pst_cfg_check_psa persistence_cfg_save -flash_erase \ -- -argstest stack-cfg=0 -conf=prj_mesh1d1_conf overlay="overlay_pst_conf_overlay_psa_conf" RunTestFlash mesh_pst_cfg_check_psa persistence_cfg_load -flash_rm \ -- -argstest stack-cfg=0 -conf=prj_mesh1d1_conf overlay="overlay_pst_conf_overlay_psa_conf" RunTestFlash mesh_pst_cfg_check_psa persistence_cfg_save -flash_erase \ -- -argstest stack-cfg=1 -conf=prj_mesh1d1_conf overlay="overlay_pst_conf_overlay_psa_conf" RunTestFlash mesh_pst_cfg_check_psa persistence_cfg_load -flash_rm \ -- -argstest stack-cfg=1 diff --git a/tests/bsim/bluetooth/mesh/tests_scripts/persistence/provisioning.sh b/tests/bsim/bluetooth/mesh/tests_scripts/persistence/provisioning.sh index f1e0591ef13..8dc7baa3e9d 100755 --- a/tests/bsim/bluetooth/mesh/tests_scripts/persistence/provisioning.sh +++ b/tests/bsim/bluetooth/mesh/tests_scripts/persistence/provisioning.sh @@ -16,18 +16,8 @@ RunTestFlash mesh_pst_prov_data_check persistence_provisioning_data_save -flash_ overlay=overlay_pst_conf RunTestFlash mesh_pst_prov_data_check persistence_provisioning_data_load -flash_rm -conf=prj_mesh1d1_conf -overlay=overlay_pst_conf -RunTestFlash mesh_pst_prov_data_check_1d1 persistence_provisioning_data_save -flash_erase - -conf=prj_mesh1d1_conf -overlay=overlay_pst_conf -RunTestFlash mesh_pst_prov_data_check_1d1 persistence_provisioning_data_load -flash_rm - -conf=prj_mesh1d1_conf overlay="overlay_pst_conf_overlay_psa_conf" RunTestFlash mesh_pst_prov_data_check_psa persistence_provisioning_data_save -flash_erase -conf=prj_mesh1d1_conf overlay="overlay_pst_conf_overlay_psa_conf" RunTestFlash mesh_pst_prov_data_check_psa persistence_provisioning_data_load -flash_rm diff --git a/tests/bsim/bluetooth/mesh/tests_scripts/persistence/reprovisioning.sh b/tests/bsim/bluetooth/mesh/tests_scripts/persistence/reprovisioning.sh index 922b4c8a513..511c04f766f 100755 --- a/tests/bsim/bluetooth/mesh/tests_scripts/persistence/reprovisioning.sh +++ b/tests/bsim/bluetooth/mesh/tests_scripts/persistence/reprovisioning.sh @@ -20,25 +20,11 @@ RunTest mesh_pst_repr persistence_reprovisioning_device \ -flash=../results/mesh_pst_repr/flash.bin -flash_rm \ persistence_reprovisioning_provisioner -conf=prj_mesh1d1_conf -overlay=overlay_pst_conf -RunTest mesh_pst_repr_1d1 persistence_reprovisioning_device \ - -flash=../results/mesh_pst_repr_1d1/flash.bin -flash_erase \ - persistence_reprovisioning_provisioner - -conf=prj_mesh1d1_conf -overlay=overlay_pst_conf -RunTest mesh_pst_repr_1d1 persistence_reprovisioning_device \ - -flash=../results/mesh_pst_repr_1d1/flash.bin -flash_rm \ - persistence_reprovisioning_provisioner - -conf=prj_mesh1d1_conf overlay="overlay_pst_conf_overlay_psa_conf" RunTest mesh_pst_repr_psa persistence_reprovisioning_device \ -flash=../results/mesh_pst_repr_psa/flash.bin -flash_erase \ persistence_reprovisioning_provisioner -conf=prj_mesh1d1_conf overlay="overlay_pst_conf_overlay_psa_conf" RunTest mesh_pst_repr_psa persistence_reprovisioning_device \ -flash=../results/mesh_pst_repr_psa/flash.bin -flash_rm \ diff --git a/tests/bsim/bluetooth/mesh/tests_scripts/priv_beacon/priv_beacon_adv.sh b/tests/bsim/bluetooth/mesh/tests_scripts/priv_beacon/priv_beacon_adv.sh index 48724dd7fbd..36c322a54da 100755 --- a/tests/bsim/bluetooth/mesh/tests_scripts/priv_beacon/priv_beacon_adv.sh +++ b/tests/bsim/bluetooth/mesh/tests_scripts/priv_beacon/priv_beacon_adv.sh @@ -6,9 +6,7 @@ source $(dirname "${BASH_SOURCE[0]}")/../../_mesh_test.sh # Test Private Beacon advertising on node supporting relay feature. # Test Random value changes for different Random intervals (10s, 0 - on every beacon, 30s). -conf=prj_mesh1d1_conf RunTest mesh_priv_beacon_adv beacon_rx_priv_adv beacon_tx_priv_adv -conf=prj_mesh1d1_conf overlay=overlay_psa_conf RunTest mesh_priv_beacon_adv_psa beacon_rx_priv_adv beacon_tx_priv_adv diff --git a/tests/bsim/bluetooth/mesh/tests_scripts/priv_beacon/priv_beacon_cache.sh b/tests/bsim/bluetooth/mesh/tests_scripts/priv_beacon/priv_beacon_cache.sh index 0cb5cdaea0a..46a460c7ec7 100755 --- a/tests/bsim/bluetooth/mesh/tests_scripts/priv_beacon/priv_beacon_cache.sh +++ b/tests/bsim/bluetooth/mesh/tests_scripts/priv_beacon/priv_beacon_cache.sh @@ -12,12 +12,10 @@ source $(dirname "${BASH_SOURCE[0]}")/../../_mesh_test.sh # 2. TX device sends a secondary private beacons to the RX device, marking the end of the test. # 3. RX device verifies that only one of the two identical beacons was processed. -conf=prj_mesh1d1_conf RunTest mesh_priv_beacon_cache \ beacon_tx_priv_beacon_cache \ beacon_rx_priv_beacon_cache -conf=prj_mesh1d1_conf overlay=overlay_psa_conf RunTest mesh_priv_beacon_cache \ beacon_tx_priv_beacon_cache \ diff --git a/tests/bsim/bluetooth/mesh/tests_scripts/priv_beacon/priv_beacon_interleave.sh b/tests/bsim/bluetooth/mesh/tests_scripts/priv_beacon/priv_beacon_interleave.sh index 6d574a72c73..cda94a89d93 100755 --- a/tests/bsim/bluetooth/mesh/tests_scripts/priv_beacon/priv_beacon_interleave.sh +++ b/tests/bsim/bluetooth/mesh/tests_scripts/priv_beacon/priv_beacon_interleave.sh @@ -15,9 +15,7 @@ source $(dirname "${BASH_SOURCE[0]}")/../../_mesh_test.sh # - PRB is disabled, SNB enabled: second SNB is advertised # - KR is initiated, third SNB is advertised with new flags (IVU + KR) # - PRB is enabled, SNB is disabled. Third PRB is advertised -conf=prj_mesh1d1_conf RunTest mesh_priv_beacon_interleave beacon_rx_priv_interleave beacon_tx_priv_interleave -conf=prj_mesh1d1_conf overlay=overlay_psa_conf RunTest mesh_priv_beacon_interleave_psa beacon_rx_priv_interleave beacon_tx_priv_interleave diff --git a/tests/bsim/bluetooth/mesh/tests_scripts/priv_beacon/priv_beacon_invalid.sh b/tests/bsim/bluetooth/mesh/tests_scripts/priv_beacon/priv_beacon_invalid.sh index b1983284a51..028ba0eabff 100755 --- a/tests/bsim/bluetooth/mesh/tests_scripts/priv_beacon/priv_beacon_invalid.sh +++ b/tests/bsim/bluetooth/mesh/tests_scripts/priv_beacon/priv_beacon_invalid.sh @@ -5,9 +5,7 @@ source $(dirname "${BASH_SOURCE[0]}")/../../_mesh_test.sh # Test if Private Beacons with invalid data do not affect device -conf=prj_mesh1d1_conf RunTest mesh_priv_beacon_invalid beacon_rx_priv_invalid beacon_tx_priv_invalid -conf=prj_mesh1d1_conf overlay=overlay_psa_conf RunTest mesh_priv_beacon_invalid_psa beacon_rx_priv_invalid beacon_tx_priv_invalid diff --git a/tests/bsim/bluetooth/mesh/tests_scripts/priv_beacon/priv_beacon_ivu.sh b/tests/bsim/bluetooth/mesh/tests_scripts/priv_beacon/priv_beacon_ivu.sh index bb9a591fcb0..32232573305 100755 --- a/tests/bsim/bluetooth/mesh/tests_scripts/priv_beacon/priv_beacon_ivu.sh +++ b/tests/bsim/bluetooth/mesh/tests_scripts/priv_beacon/priv_beacon_ivu.sh @@ -5,13 +5,11 @@ source $(dirname "${BASH_SOURCE[0]}")/../../_mesh_test.sh # Test Private Beacon advertising during IV Update procedure -conf=prj_mesh1d1_conf RunTest mesh_priv_beacon_on_iv_update \ beacon_rx_on_iv_update \ beacon_tx_priv_on_iv_update \ -- -argstest rand-int=1 -conf=prj_mesh1d1_conf overlay=overlay_psa_conf RunTest mesh_priv_beacon_on_iv_update_psa \ beacon_rx_on_iv_update \ diff --git a/tests/bsim/bluetooth/mesh/tests_scripts/priv_beacon/priv_beacon_ivu_long_interval.sh b/tests/bsim/bluetooth/mesh/tests_scripts/priv_beacon/priv_beacon_ivu_long_interval.sh index ad0d11dbc96..d44ba297a0e 100755 --- a/tests/bsim/bluetooth/mesh/tests_scripts/priv_beacon/priv_beacon_ivu_long_interval.sh +++ b/tests/bsim/bluetooth/mesh/tests_scripts/priv_beacon/priv_beacon_ivu_long_interval.sh @@ -7,13 +7,11 @@ source $(dirname "${BASH_SOURCE[0]}")/../../_mesh_test.sh # Test Private Beacon advertising during IV Update procedure, with long Random Interval set. # Random value is expected to change before Random Interval is reached due to # Flags field change. -conf=prj_mesh1d1_conf RunTest mesh_priv_beacon_on_iv_update_long_interval \ beacon_rx_on_iv_update \ beacon_tx_priv_on_iv_update \ -- -argstest rand-int=3 -conf=prj_mesh1d1_conf overlay=overlay_psa_conf RunTest mesh_priv_beacon_on_iv_update_long_interval_psa \ beacon_rx_on_iv_update \ diff --git a/tests/bsim/bluetooth/mesh/tests_scripts/priv_beacon/priv_beacon_kr.sh b/tests/bsim/bluetooth/mesh/tests_scripts/priv_beacon/priv_beacon_kr.sh index eaf6338684f..59fe95658c2 100755 --- a/tests/bsim/bluetooth/mesh/tests_scripts/priv_beacon/priv_beacon_kr.sh +++ b/tests/bsim/bluetooth/mesh/tests_scripts/priv_beacon/priv_beacon_kr.sh @@ -5,13 +5,11 @@ source $(dirname "${BASH_SOURCE[0]}")/../../_mesh_test.sh # Test Private Beacon advertising during Key Refresh procedure -conf=prj_mesh1d1_conf RunTest mesh_priv_beacon_on_key_refresh \ beacon_rx_on_key_refresh \ beacon_tx_priv_on_key_refresh \ -- -argstest rand-int=1 -conf=prj_mesh1d1_conf overlay=overlay_psa_conf RunTest mesh_priv_beacon_on_key_refresh_psa \ beacon_rx_on_key_refresh \ diff --git a/tests/bsim/bluetooth/mesh/tests_scripts/priv_beacon/priv_beacon_kr_long_interval.sh b/tests/bsim/bluetooth/mesh/tests_scripts/priv_beacon/priv_beacon_kr_long_interval.sh index cc5722e4432..b0ec45b3f1d 100755 --- a/tests/bsim/bluetooth/mesh/tests_scripts/priv_beacon/priv_beacon_kr_long_interval.sh +++ b/tests/bsim/bluetooth/mesh/tests_scripts/priv_beacon/priv_beacon_kr_long_interval.sh @@ -7,13 +7,11 @@ source $(dirname "${BASH_SOURCE[0]}")/../../_mesh_test.sh # Test Private Beacon advertising during Key Refresh procedure, with long Random Interval set. # Random value is expected to change before Random Interval is reached due to # Flags field change. -conf=prj_mesh1d1_conf RunTest mesh_priv_beacon_on_key_refresh_long_interval \ beacon_rx_on_key_refresh \ beacon_tx_priv_on_key_refresh \ -- -argstest rand-int=3 -conf=prj_mesh1d1_conf overlay=overlay_psa_conf RunTest mesh_priv_beacon_on_key_refresh_long_interval_psa \ beacon_rx_on_key_refresh \ diff --git a/tests/bsim/bluetooth/mesh/tests_scripts/priv_beacon/priv_proxy_gatt.sh b/tests/bsim/bluetooth/mesh/tests_scripts/priv_beacon/priv_proxy_gatt.sh index a1b9ea7d8d6..8080b6ec70f 100755 --- a/tests/bsim/bluetooth/mesh/tests_scripts/priv_beacon/priv_proxy_gatt.sh +++ b/tests/bsim/bluetooth/mesh/tests_scripts/priv_beacon/priv_proxy_gatt.sh @@ -17,13 +17,11 @@ source $(dirname "${BASH_SOURCE[0]}")/../../_mesh_test.sh # 4. Both TX and RX device verifies that the IV index has been updated. # This proves that the RX device (Proxy CLI) successfully received # a Private beacon over the GATT connection -conf=prj_mesh1d1_conf overlay=overlay_gatt_conf RunTest mesh_priv_proxy_gatt_priv_beacon \ beacon_tx_priv_gatt_proxy \ beacon_rx_priv_gatt_proxy -conf=prj_mesh1d1_conf overlay=overlay_gatt_conf_overlay_psa_conf RunTest mesh_priv_proxy_gatt_priv_beacon \ beacon_tx_priv_gatt_proxy \ diff --git a/tests/bsim/bluetooth/mesh/tests_scripts/priv_beacon/priv_proxy_net_id.sh b/tests/bsim/bluetooth/mesh/tests_scripts/priv_beacon/priv_proxy_net_id.sh index 02fcf03c001..a431cdd9f6b 100755 --- a/tests/bsim/bluetooth/mesh/tests_scripts/priv_beacon/priv_proxy_net_id.sh +++ b/tests/bsim/bluetooth/mesh/tests_scripts/priv_beacon/priv_proxy_net_id.sh @@ -18,13 +18,11 @@ source $(dirname "${BASH_SOURCE[0]}")/../../_mesh_test.sh # 5. Test passes if the random field of the two Private Net ID advertisements # are NOT equal. -conf=prj_mesh1d1_conf overlay=overlay_gatt_conf RunTest mesh_priv_proxy_net_id \ beacon_tx_priv_net_id \ beacon_rx_priv_net_id -conf=prj_mesh1d1_conf overlay=overlay_gatt_conf_overlay_psa_conf RunTest mesh_priv_proxy_net_id \ beacon_tx_priv_net_id \ diff --git a/tests/bsim/bluetooth/mesh/tests_scripts/priv_beacon/priv_proxy_net_id_multi.sh b/tests/bsim/bluetooth/mesh/tests_scripts/priv_beacon/priv_proxy_net_id_multi.sh index 9d89b5af36c..cffb5adbeb0 100755 --- a/tests/bsim/bluetooth/mesh/tests_scripts/priv_beacon/priv_proxy_net_id_multi.sh +++ b/tests/bsim/bluetooth/mesh/tests_scripts/priv_beacon/priv_proxy_net_id_multi.sh @@ -15,13 +15,11 @@ source $(dirname "${BASH_SOURCE[0]}")/../../_mesh_test.sh # advertisemen from each of the networks within the given time # limit. -conf=prj_mesh1d1_conf overlay=overlay_gatt_conf RunTest mesh_priv_proxy_net_id_multi \ beacon_tx_priv_multi_net_id \ beacon_rx_priv_multi_net_id -conf=prj_mesh1d1_conf overlay=overlay_gatt_conf_overlay_psa_conf RunTest mesh_priv_proxy_net_id_multi \ beacon_tx_priv_multi_net_id \ diff --git a/tests/bsim/bluetooth/mesh/tests_scripts/priv_beacon/priv_proxy_node_id.sh b/tests/bsim/bluetooth/mesh/tests_scripts/priv_beacon/priv_proxy_node_id.sh index 2aff351bd78..2557c9c1506 100755 --- a/tests/bsim/bluetooth/mesh/tests_scripts/priv_beacon/priv_proxy_node_id.sh +++ b/tests/bsim/bluetooth/mesh/tests_scripts/priv_beacon/priv_proxy_node_id.sh @@ -23,13 +23,11 @@ source $(dirname "${BASH_SOURCE[0]}")/../../_mesh_test.sh # 5. Test passes if the random field of the two Private Node ID advertisements # are NOT equal. -conf=prj_mesh1d1_conf overlay=overlay_gatt_conf RunTest mesh_priv_proxy_node_id \ beacon_tx_priv_node_id \ beacon_rx_priv_node_id -conf=prj_mesh1d1_conf overlay=overlay_gatt_conf_overlay_psa_conf RunTest mesh_priv_proxy_node_id \ beacon_tx_priv_node_id \ diff --git a/tests/bsim/bluetooth/mesh/tests_scripts/priv_beacon/proxy_adv_multi_subnet_coex.sh b/tests/bsim/bluetooth/mesh/tests_scripts/priv_beacon/proxy_adv_multi_subnet_coex.sh index 42863a13458..0a3b5771bfd 100755 --- a/tests/bsim/bluetooth/mesh/tests_scripts/priv_beacon/proxy_adv_multi_subnet_coex.sh +++ b/tests/bsim/bluetooth/mesh/tests_scripts/priv_beacon/proxy_adv_multi_subnet_coex.sh @@ -43,14 +43,12 @@ source $(dirname "${BASH_SOURCE[0]}")/../../_mesh_test.sh # to the adv medium again. -conf=prj_mesh1d1_conf overlay=overlay_gatt_conf RunTest proxy_adv_multi_subnet_coex \ beacon_tx_proxy_adv_multi_subnet_coex \ beacon_rx_proxy_adv_multi_subnet_coex \ beacon_tx_proxy_adv_solicit_trigger -conf=prj_mesh1d1_conf overlay=overlay_gatt_conf_overlay_psa_conf RunTest proxy_adv_multi_subnet_coex \ beacon_tx_proxy_adv_multi_subnet_coex \ diff --git a/tests/bsim/bluetooth/mesh/tests_scripts/provision/ivu_flag_one_duration.sh b/tests/bsim/bluetooth/mesh/tests_scripts/provision/ivu_flag_one_duration.sh index 168c2620212..36c996269cf 100755 --- a/tests/bsim/bluetooth/mesh/tests_scripts/provision/ivu_flag_one_duration.sh +++ b/tests/bsim/bluetooth/mesh/tests_scripts/provision/ivu_flag_one_duration.sh @@ -6,9 +6,5 @@ source $(dirname "${BASH_SOURCE[0]}")/../../_mesh_test.sh RunTest mesh_prov_iv_update_one_duration prov_provisioner_iv_update_flag_one -conf=prj_mesh1d1_conf -RunTest mesh_prov_iv_update_one_duration_1d1 prov_provisioner_iv_update_flag_one - -conf=prj_mesh1d1_conf overlay=overlay_psa_conf RunTest mesh_prov_iv_update_one_duration_psa prov_provisioner_iv_update_flag_one diff --git a/tests/bsim/bluetooth/mesh/tests_scripts/provision/ivu_flag_zero_duration.sh b/tests/bsim/bluetooth/mesh/tests_scripts/provision/ivu_flag_zero_duration.sh index 07165b31c1d..cb3294950f8 100755 --- a/tests/bsim/bluetooth/mesh/tests_scripts/provision/ivu_flag_zero_duration.sh +++ b/tests/bsim/bluetooth/mesh/tests_scripts/provision/ivu_flag_zero_duration.sh @@ -6,9 +6,5 @@ source $(dirname "${BASH_SOURCE[0]}")/../../_mesh_test.sh RunTest mesh_prov_iv_update_zero_duration prov_provisioner_iv_update_flag_zero -conf=prj_mesh1d1_conf -RunTest mesh_prov_iv_update_zero_duration_1d1 prov_provisioner_iv_update_flag_zero - -conf=prj_mesh1d1_conf overlay=overlay_psa_conf RunTest mesh_prov_iv_update_zero_duration_psa prov_provisioner_iv_update_flag_zero diff --git a/tests/bsim/bluetooth/mesh/tests_scripts/provision/pb_adv_multi.sh b/tests/bsim/bluetooth/mesh/tests_scripts/provision/pb_adv_multi.sh index 7d8dfbe6388..61bbbcc1a27 100755 --- a/tests/bsim/bluetooth/mesh/tests_scripts/provision/pb_adv_multi.sh +++ b/tests/bsim/bluetooth/mesh/tests_scripts/provision/pb_adv_multi.sh @@ -13,14 +13,6 @@ RunTest mesh_prov_pb_adv_multi \ prov_device_pb_adv_no_oob \ prov_device_pb_adv_no_oob -conf=prj_mesh1d1_conf -RunTest mesh_prov_pb_adv_multi_1d1 \ - prov_provisioner_pb_adv_multi \ - prov_device_pb_adv_no_oob \ - prov_device_pb_adv_no_oob \ - prov_device_pb_adv_no_oob - -conf=prj_mesh1d1_conf overlay=overlay_psa_conf RunTest mesh_prov_pb_adv_multi_psa \ prov_provisioner_pb_adv_multi \ diff --git a/tests/bsim/bluetooth/mesh/tests_scripts/provision/pb_adv_no_oob.sh b/tests/bsim/bluetooth/mesh/tests_scripts/provision/pb_adv_no_oob.sh index bfcb8540ae1..91bde356f2b 100755 --- a/tests/bsim/bluetooth/mesh/tests_scripts/provision/pb_adv_no_oob.sh +++ b/tests/bsim/bluetooth/mesh/tests_scripts/provision/pb_adv_no_oob.sh @@ -8,12 +8,6 @@ RunTest mesh_prov_pb_adv_on_oob \ prov_device_pb_adv_no_oob \ prov_provisioner_pb_adv_no_oob -conf=prj_mesh1d1_conf -RunTest mesh_prov_pb_adv_on_oob_1d1 \ - prov_device_pb_adv_no_oob \ - prov_provisioner_pb_adv_no_oob - -conf=prj_mesh1d1_conf overlay=overlay_psa_conf RunTest mesh_prov_pb_adv_on_oob_psa \ prov_device_pb_adv_no_oob \ diff --git a/tests/bsim/bluetooth/mesh/tests_scripts/provision/pb_adv_oob_auth_ib_pk.sh b/tests/bsim/bluetooth/mesh/tests_scripts/provision/pb_adv_oob_auth_ib_pk.sh index 22d197a0adc..ef8e07f7c80 100755 --- a/tests/bsim/bluetooth/mesh/tests_scripts/provision/pb_adv_oob_auth_ib_pk.sh +++ b/tests/bsim/bluetooth/mesh/tests_scripts/provision/pb_adv_oob_auth_ib_pk.sh @@ -8,11 +8,6 @@ source $(dirname "${BASH_SOURCE[0]}")/../../_mesh_test.sh RunTest mesh_prov_pb_adv_oob_auth \ prov_device_pb_adv_oob_auth prov_provisioner_pb_adv_oob_auth -conf=prj_mesh1d1_conf -RunTest mesh_prov_pb_adv_oob_auth_1d1 \ - prov_device_pb_adv_oob_auth prov_provisioner_pb_adv_oob_auth - -conf=prj_mesh1d1_conf overlay=overlay_psa_conf RunTest mesh_prov_pb_adv_oob_auth_psa \ prov_device_pb_adv_oob_auth prov_provisioner_pb_adv_oob_auth diff --git a/tests/bsim/bluetooth/mesh/tests_scripts/provision/pb_adv_oob_auth_ignore_oob_pk.sh b/tests/bsim/bluetooth/mesh/tests_scripts/provision/pb_adv_oob_auth_ignore_oob_pk.sh index 5459997e547..8df3c6a4bf6 100755 --- a/tests/bsim/bluetooth/mesh/tests_scripts/provision/pb_adv_oob_auth_ignore_oob_pk.sh +++ b/tests/bsim/bluetooth/mesh/tests_scripts/provision/pb_adv_oob_auth_ignore_oob_pk.sh @@ -9,11 +9,6 @@ source $(dirname "${BASH_SOURCE[0]}")/../../_mesh_test.sh RunTest mesh_prov_pb_adv_device_w_oob_pk_prvnr_wt_pk \ prov_device_pb_adv_oob_public_key prov_provisioner_pb_adv_oob_auth_no_oob_public_key -conf=prj_mesh1d1_conf -RunTest mesh_prov_pb_adv_device_w_oob_pk_prvnr_wt_pk_1d1 \ - prov_device_pb_adv_oob_public_key prov_provisioner_pb_adv_oob_auth_no_oob_public_key - -conf=prj_mesh1d1_conf overlay=overlay_psa_conf RunTest mesh_prov_pb_adv_device_w_oob_pk_prvnr_wt_pk_psa \ prov_device_pb_adv_oob_public_key prov_provisioner_pb_adv_oob_auth_no_oob_public_key diff --git a/tests/bsim/bluetooth/mesh/tests_scripts/provision/pb_adv_oob_auth_oob_pk.sh b/tests/bsim/bluetooth/mesh/tests_scripts/provision/pb_adv_oob_auth_oob_pk.sh index b8ab3a5d899..d24e5afccd4 100755 --- a/tests/bsim/bluetooth/mesh/tests_scripts/provision/pb_adv_oob_auth_oob_pk.sh +++ b/tests/bsim/bluetooth/mesh/tests_scripts/provision/pb_adv_oob_auth_oob_pk.sh @@ -8,11 +8,6 @@ source $(dirname "${BASH_SOURCE[0]}")/../../_mesh_test.sh RunTest mesh_prov_pb_adv_oob_public_key \ prov_device_pb_adv_oob_public_key prov_provisioner_pb_adv_oob_public_key -conf=prj_mesh1d1_conf -RunTest mesh_prov_pb_adv_oob_public_key_1d1 \ - prov_device_pb_adv_oob_public_key prov_provisioner_pb_adv_oob_public_key - -conf=prj_mesh1d1_conf overlay=overlay_psa_conf RunTest mesh_prov_pb_adv_oob_public_key_psa \ prov_device_pb_adv_oob_public_key prov_provisioner_pb_adv_oob_public_key diff --git a/tests/bsim/bluetooth/mesh/tests_scripts/provision/pb_adv_reprovision.sh b/tests/bsim/bluetooth/mesh/tests_scripts/provision/pb_adv_reprovision.sh index 9c70514a093..0e3b84e3138 100755 --- a/tests/bsim/bluetooth/mesh/tests_scripts/provision/pb_adv_reprovision.sh +++ b/tests/bsim/bluetooth/mesh/tests_scripts/provision/pb_adv_reprovision.sh @@ -8,12 +8,6 @@ RunTest mesh_prov_pb_adv_repr \ prov_device_pb_adv_reprovision \ prov_provisioner_pb_adv_reprovision -conf=prj_mesh1d1_conf -RunTest mesh_prov_pb_adv_repr_1d1 \ - prov_device_pb_adv_reprovision \ - prov_provisioner_pb_adv_reprovision - -conf=prj_mesh1d1_conf overlay=overlay_psa_conf RunTest mesh_prov_pb_adv_repr_psa \ prov_device_pb_adv_reprovision \ diff --git a/tests/bsim/bluetooth/mesh/tests_scripts/provision/pb_remote_client_server_same_dev.sh b/tests/bsim/bluetooth/mesh/tests_scripts/provision/pb_remote_client_server_same_dev.sh index 33de74370e1..9175a9ac015 100755 --- a/tests/bsim/bluetooth/mesh/tests_scripts/provision/pb_remote_client_server_same_dev.sh +++ b/tests/bsim/bluetooth/mesh/tests_scripts/provision/pb_remote_client_server_same_dev.sh @@ -20,12 +20,10 @@ source $(dirname "${BASH_SOURCE[0]}")/../../_mesh_test.sh # composition refresh procedure on it self with local RPR client and server. # 7. The first device (prov_device_pb_remote_client_server_same_dev) execute # address refresh procedure on it self with local RPR client and server. -conf=prj_mesh1d1_conf RunTest mesh_prov_pb_remote_client_server_same_dev \ prov_device_pb_remote_client_server_same_dev \ prov_device_pb_remote_server_same_dev -conf=prj_mesh1d1_conf overlay=overlay_psa_conf RunTest mesh_prov_pb_remote_client_server_same_dev \ prov_device_pb_remote_client_server_same_dev \ diff --git a/tests/bsim/bluetooth/mesh/tests_scripts/provision/pb_remote_nppi_robustness.sh b/tests/bsim/bluetooth/mesh/tests_scripts/provision/pb_remote_nppi_robustness.sh index d707fdb6d6c..a59cf04aef4 100755 --- a/tests/bsim/bluetooth/mesh/tests_scripts/provision/pb_remote_nppi_robustness.sh +++ b/tests/bsim/bluetooth/mesh/tests_scripts/provision/pb_remote_nppi_robustness.sh @@ -13,13 +13,11 @@ source $(dirname "${BASH_SOURCE[0]}")/../../_mesh_test.sh # 4. Execute composition refresh procedure 3 times for the third device. # 5. Execute address refresh procedure 3 times for the third device. # (Step 3-5 is executed without sending a node reset message) -conf=prj_mesh1d1_conf RunTest mesh_prov_pb_remote_nppi_robustness \ prov_provisioner_pb_remote_client_nppi_robustness \ prov_device_pb_remote_server_unproved \ prov_device_pb_remote_server_nppi_robustness -conf=prj_mesh1d1_conf overlay=overlay_psa_conf RunTest mesh_prov_pb_remote_nppi_robustness_psa \ prov_provisioner_pb_remote_client_nppi_robustness \ diff --git a/tests/bsim/bluetooth/mesh/tests_scripts/provision/pb_remote_parallel.sh b/tests/bsim/bluetooth/mesh/tests_scripts/provision/pb_remote_parallel.sh index 2c3394381cd..6ecb3292193 100755 --- a/tests/bsim/bluetooth/mesh/tests_scripts/provision/pb_remote_parallel.sh +++ b/tests/bsim/bluetooth/mesh/tests_scripts/provision/pb_remote_parallel.sh @@ -11,14 +11,12 @@ source $(dirname "${BASH_SOURCE[0]}")/../../_mesh_test.sh # 4. The provisioner scans for an unprovisioned device idx 3 through the node with RPR server; # 5. The provisioner checks scanning and provisioning succeeded; # 6. The provisioner provisions an unprovisioned device idx 3 through the node with RPR server; -conf=prj_mesh1d1_conf RunTest mesh_prov_pb_remote_parallel \ prov_provisioner_pb_remote_client_parallel \ prov_device_pb_remote_server_unproved \ prov_device_pb_adv_no_oob \ prov_device_pb_adv_no_oob -conf=prj_mesh1d1_conf overlay=overlay_psa_conf RunTest mesh_prov_pb_remote_parallel_psa \ prov_provisioner_pb_remote_client_parallel \ diff --git a/tests/bsim/bluetooth/mesh/tests_scripts/provision/pb_remote_pst_ncrp.sh b/tests/bsim/bluetooth/mesh/tests_scripts/provision/pb_remote_pst_ncrp.sh index ed5f619b310..2bba5147d8f 100755 --- a/tests/bsim/bluetooth/mesh/tests_scripts/provision/pb_remote_pst_ncrp.sh +++ b/tests/bsim/bluetooth/mesh/tests_scripts/provision/pb_remote_pst_ncrp.sh @@ -31,7 +31,6 @@ source $(dirname "${BASH_SOURCE[0]}")/../../_mesh_test.sh # - verify that the device is not re-provisioned again. # Step 1 -conf=prj_mesh1d1_conf overlay=overlay_pst_conf RunTestFlash mesh_prov_pst_pb_remote_ncrp \ prov_provisioner_pb_remote_client_ncrp_provision -flash_erase \ @@ -39,7 +38,6 @@ RunTestFlash mesh_prov_pst_pb_remote_ncrp \ prov_device_pb_remote_server_ncrp_prepare -flash_erase # Step 2 -conf=prj_mesh1d1_conf overlay=overlay_pst_conf RunTestFlash mesh_prov_pst_pb_remote_ncrp \ prov_provisioner_pb_remote_client_ncrp \ @@ -47,7 +45,6 @@ RunTestFlash mesh_prov_pst_pb_remote_ncrp \ prov_device_pb_remote_server_ncrp # Step 3 -conf=prj_mesh1d1_conf overlay=overlay_pst_conf RunTestFlash mesh_prov_pst_pb_remote_ncrp \ prov_provisioner_pb_remote_client_ncrp_second_time -flash_rm \ @@ -56,7 +53,6 @@ RunTestFlash mesh_prov_pst_pb_remote_ncrp \ # The same test but with PSA crypto # Step 1 -conf=prj_mesh1d1_conf overlay="overlay_pst_conf_overlay_psa_conf" RunTestFlash mesh_prov_pst_pb_remote_ncrp_psa \ prov_provisioner_pb_remote_client_ncrp_provision -flash_erase \ @@ -64,7 +60,6 @@ RunTestFlash mesh_prov_pst_pb_remote_ncrp_psa \ prov_device_pb_remote_server_ncrp_prepare -flash_erase # Step 2 -conf=prj_mesh1d1_conf overlay="overlay_pst_conf_overlay_psa_conf" RunTestFlash mesh_prov_pst_pb_remote_ncrp_psa \ prov_provisioner_pb_remote_client_ncrp \ @@ -72,7 +67,6 @@ RunTestFlash mesh_prov_pst_pb_remote_ncrp_psa \ prov_device_pb_remote_server_ncrp # Step 3 -conf=prj_mesh1d1_conf overlay="overlay_pst_conf_overlay_psa_conf" RunTestFlash mesh_prov_pst_pb_remote_ncrp_psa \ prov_provisioner_pb_remote_client_ncrp_second_time -flash_rm \ diff --git a/tests/bsim/bluetooth/mesh/tests_scripts/provision/pb_remote_reprovision.sh b/tests/bsim/bluetooth/mesh/tests_scripts/provision/pb_remote_reprovision.sh index a49cbcd7ca9..1a2ae89d655 100755 --- a/tests/bsim/bluetooth/mesh/tests_scripts/provision/pb_remote_reprovision.sh +++ b/tests/bsim/bluetooth/mesh/tests_scripts/provision/pb_remote_reprovision.sh @@ -12,13 +12,11 @@ source $(dirname "${BASH_SOURCE[0]}")/../../_mesh_test.sh # 5. The provisioner configures the health server on the recently provisioned device and sends Node # Reset; # 6. Repeat steps 3-5 multiple times. -conf=prj_mesh1d1_conf RunTest mesh_prov_pb_remote_reprovision \ prov_provisioner_pb_remote_client_reprovision \ prov_device_pb_remote_server_unproved \ prov_device_pb_adv_reprovision -conf=prj_mesh1d1_conf overlay=overlay_psa_conf RunTest mesh_prov_pb_remote_reprovision_psa \ prov_provisioner_pb_remote_client_reprovision \ diff --git a/tests/bsim/bluetooth/mesh/tests_scripts/provision/pb_remote_timeout.sh b/tests/bsim/bluetooth/mesh/tests_scripts/provision/pb_remote_timeout.sh index 8ef61c2666b..7feba542c44 100755 --- a/tests/bsim/bluetooth/mesh/tests_scripts/provision/pb_remote_timeout.sh +++ b/tests/bsim/bluetooth/mesh/tests_scripts/provision/pb_remote_timeout.sh @@ -24,13 +24,11 @@ source $(dirname "${BASH_SOURCE[0]}")/../../_mesh_test.sh # 11. 3rd device opens provisioning link. # 12. 2nd device stops communicating with either devices. # 13. After 60s RPR timeout is reached on 1st device. RPR Client closes provisioning link. -conf=prj_mesh1d1_conf RunTest mesh_prov_pb_remote_provisioning_timeout \ prov_provisioner_pb_remote_client_provision_timeout \ prov_device_pb_remote_server_unproved_unresponsive \ prov_device_unresponsive -conf=prj_mesh1d1_conf overlay=overlay_psa_conf RunTest mesh_prov_pb_remote_provisioning_timeout_psa \ prov_provisioner_pb_remote_client_provision_timeout \ diff --git a/tests/bsim/bluetooth/mesh/tests_scripts/replay_cache/replay_attack.sh b/tests/bsim/bluetooth/mesh/tests_scripts/replay_cache/replay_attack.sh index 50387776dfb..d09e014bd0e 100755 --- a/tests/bsim/bluetooth/mesh/tests_scripts/replay_cache/replay_attack.sh +++ b/tests/bsim/bluetooth/mesh/tests_scripts/replay_cache/replay_attack.sh @@ -14,25 +14,11 @@ RunTest mesh_replay_attack \ rpc_tx_power_replay_attack \ rpc_rx_power_replay_attack -flash=../results/mesh_replay_attack/flash.bin -flash_rm -conf=prj_mesh1d1_conf -overlay=overlay_pst_conf -RunTest mesh_replay_attack_1d1 \ - rpc_tx_immediate_replay_attack \ - rpc_rx_immediate_replay_attack -flash=../results/mesh_replay_attack_1d1/flash.bin -flash_erase - -conf=prj_mesh1d1_conf -overlay=overlay_pst_conf -RunTest mesh_replay_attack_1d1 \ - rpc_tx_power_replay_attack \ - rpc_rx_power_replay_attack -flash=../results/mesh_replay_attack_1d1/flash.bin -flash_rm - -conf=prj_mesh1d1_conf overlay="overlay_pst_conf_overlay_psa_conf" RunTest mesh_replay_attack_psa \ rpc_tx_immediate_replay_attack \ rpc_rx_immediate_replay_attack -flash=../results/mesh_replay_attack_psa/flash.bin -flash_erase -conf=prj_mesh1d1_conf overlay="overlay_pst_conf_overlay_psa_conf" RunTest mesh_replay_attack_psa \ rpc_tx_power_replay_attack \ diff --git a/tests/bsim/bluetooth/mesh/tests_scripts/replay_cache/rpl_frag.sh b/tests/bsim/bluetooth/mesh/tests_scripts/replay_cache/rpl_frag.sh index 8c7a7866eb3..7212b567a24 100755 --- a/tests/bsim/bluetooth/mesh/tests_scripts/replay_cache/rpl_frag.sh +++ b/tests/bsim/bluetooth/mesh/tests_scripts/replay_cache/rpl_frag.sh @@ -21,24 +21,11 @@ overlay=overlay_pst_conf RunTest mesh_replay_fragmentation \ rpc_rx_reboot_after_defrag -flash=../results/mesh_replay_fragmentation/flash.bin -flash_rm -conf=prj_mesh1d1_conf -overlay=overlay_pst_conf -RunTest mesh_replay_fragmentation_1d1 \ - rpc_rx_rpl_frag -flash=../results/mesh_replay_fragmentation_1d1/flash.bin -flash_erase \ - rpc_tx_rpl_frag - -conf=prj_mesh1d1_conf -overlay=overlay_pst_conf -RunTest mesh_replay_fragmentation_1d1 \ - rpc_rx_reboot_after_defrag -flash=../results/mesh_replay_fragmentation_1d1/flash.bin -flash_rm - -conf=prj_mesh1d1_conf overlay="overlay_pst_conf_overlay_psa_conf" RunTest mesh_replay_fragmentation_psa \ rpc_rx_rpl_frag -flash=../results/mesh_replay_fragmentation_psa/flash.bin -flash_erase \ rpc_tx_rpl_frag -conf=prj_mesh1d1_conf overlay="overlay_pst_conf_overlay_psa_conf" RunTest mesh_replay_fragmentation_psa \ rpc_rx_reboot_after_defrag -flash=../results/mesh_replay_fragmentation_psa/flash.bin -flash_rm diff --git a/tests/bsim/bluetooth/mesh/tests_scripts/sar/sar_cfg_persistent_storage.sh b/tests/bsim/bluetooth/mesh/tests_scripts/sar/sar_cfg_persistent_storage.sh index dc27c4dceda..0e67d5ab4d5 100755 --- a/tests/bsim/bluetooth/mesh/tests_scripts/sar/sar_cfg_persistent_storage.sh +++ b/tests/bsim/bluetooth/mesh/tests_scripts/sar/sar_cfg_persistent_storage.sh @@ -8,12 +8,10 @@ source $(dirname "${BASH_SOURCE[0]}")/../../_mesh_test.sh # Tests must be added in sequence. # First test sets SAR TX/RX configuration. # Second test restores it from flash and checks if configuration persisted. -conf=prj_mesh1d1_conf overlay=overlay_pst_conf RunTestFlash sar_persistence sar_srv_cfg_store -flash_erase RunTestFlash sar_persistence sar_srv_cfg_restore -flash_rm -conf=prj_mesh1d1_conf overlay="overlay_pst_conf_overlay_psa_conf" RunTestFlash sar_persistence_psa sar_srv_cfg_store -flash_erase RunTestFlash sar_persistence_psa sar_srv_cfg_restore -flash_rm diff --git a/tests/bsim/bluetooth/mesh/tests_scripts/sar/slow_transfer_test.sh b/tests/bsim/bluetooth/mesh/tests_scripts/sar/slow_transfer_test.sh index a022c23c3f4..db8f8f9dc21 100755 --- a/tests/bsim/bluetooth/mesh/tests_scripts/sar/slow_transfer_test.sh +++ b/tests/bsim/bluetooth/mesh/tests_scripts/sar/slow_transfer_test.sh @@ -14,11 +14,9 @@ source $(dirname "${BASH_SOURCE[0]}")/../../_mesh_test.sh # 4. The Client sends a Get-message with a maximum length SDU, targeting the server. # 5. The Server responds with a maximum length SDU Status-message. # 6. The test passes when the Client successfully receives the Status response. -conf=prj_mesh1d1_conf RunTest sar_slow_test \ sar_cli_max_len_sdu_slow_send sar_srv_max_len_sdu_slow_receive -conf=prj_mesh1d1_conf overlay=overlay_psa_conf RunTest sar_slow_test_psa \ sar_cli_max_len_sdu_slow_send sar_srv_max_len_sdu_slow_receive diff --git a/tests/bsim/bluetooth/mesh/tests_scripts/sar/stress_test.sh b/tests/bsim/bluetooth/mesh/tests_scripts/sar/stress_test.sh index 89707adf031..34b05446702 100755 --- a/tests/bsim/bluetooth/mesh/tests_scripts/sar/stress_test.sh +++ b/tests/bsim/bluetooth/mesh/tests_scripts/sar/stress_test.sh @@ -13,11 +13,9 @@ source $(dirname "${BASH_SOURCE[0]}")/../../_mesh_test.sh # 4. The Client sends a Get-message with a maximum length SDU, targeting the server. # 5. The Server responds with a maximum length SDU Status-message. # 6. The test passes when the Client successfully receives the Status response. -conf=prj_mesh1d1_conf RunTest sar_test \ sar_cli_max_len_sdu_send sar_srv_max_len_sdu_receive -conf=prj_mesh1d1_conf overlay=overlay_psa_conf RunTest sar_test_psa \ sar_cli_max_len_sdu_send sar_srv_max_len_sdu_receive diff --git a/tests/bsim/bluetooth/mesh/tests_scripts/scanner/invalid_ad_type.sh b/tests/bsim/bluetooth/mesh/tests_scripts/scanner/invalid_ad_type.sh index 9199ac69da8..c46088c5a15 100755 --- a/tests/bsim/bluetooth/mesh/tests_scripts/scanner/invalid_ad_type.sh +++ b/tests/bsim/bluetooth/mesh/tests_scripts/scanner/invalid_ad_type.sh @@ -8,12 +8,6 @@ RunTest mesh_scanner_invalid_ad_type \ scanner_tx_invalid_ad_type \ scanner_rx_invalid_packet -conf=prj_mesh1d1_conf -RunTest mesh_scanner_invalid_ad_type_1d1 \ - scanner_tx_invalid_ad_type \ - scanner_rx_invalid_packet - -conf=prj_mesh1d1_conf overlay=overlay_psa_conf RunTest mesh_scanner_invalid_ad_type_psa \ scanner_tx_invalid_ad_type \ diff --git a/tests/bsim/bluetooth/mesh/tests_scripts/scanner/wrong_packet_length.sh b/tests/bsim/bluetooth/mesh/tests_scripts/scanner/wrong_packet_length.sh index 8f0919058ed..80f8cacca83 100755 --- a/tests/bsim/bluetooth/mesh/tests_scripts/scanner/wrong_packet_length.sh +++ b/tests/bsim/bluetooth/mesh/tests_scripts/scanner/wrong_packet_length.sh @@ -8,12 +8,6 @@ RunTest mesh_scanner_wrong_packet_length \ scanner_tx_wrong_packet_length \ scanner_rx_invalid_packet -conf=prj_mesh1d1_conf -RunTest mesh_scanner_wrong_packet_length_1d1 \ - scanner_tx_wrong_packet_length \ - scanner_rx_invalid_packet - -conf=prj_mesh1d1_conf overlay=overlay_psa_conf RunTest mesh_scanner_wrong_packet_length_psa \ scanner_tx_wrong_packet_length \ diff --git a/tests/bsim/bluetooth/mesh/tests_scripts/suspend/gatt_suspend_disable_resume.sh b/tests/bsim/bluetooth/mesh/tests_scripts/suspend/gatt_suspend_disable_resume.sh index c723ea38610..711f92f4007 100755 --- a/tests/bsim/bluetooth/mesh/tests_scripts/suspend/gatt_suspend_disable_resume.sh +++ b/tests/bsim/bluetooth/mesh/tests_scripts/suspend/gatt_suspend_disable_resume.sh @@ -22,17 +22,10 @@ overlay=overlay_gatt_conf RunTest mesh_gatt_suspend_disable_resume \ suspend_dut_gatt_suspend_disable_resume suspend_tester_gatt -conf=prj_mesh1d1_conf overlay="overlay_gatt_conf_overlay_low_lat_conf" RunTest mesh_gatt_suspend_disable_resume_low_lat \ suspend_dut_gatt_suspend_disable_resume suspend_tester_gatt -conf=prj_mesh1d1_conf -overlay=overlay_gatt_conf -RunTest mesh_gatt_suspend_disable_resume_1d1 \ - suspend_dut_gatt_suspend_disable_resume suspend_tester_gatt - -conf=prj_mesh1d1_conf overlay="overlay_gatt_conf_overlay_psa_conf" RunTest mesh_gatt_suspend_disable_resume_psa \ suspend_dut_gatt_suspend_disable_resume suspend_tester_gatt diff --git a/tests/bsim/bluetooth/mesh/tests_scripts/suspend/gatt_suspend_resume.sh b/tests/bsim/bluetooth/mesh/tests_scripts/suspend/gatt_suspend_resume.sh index dc29ecfeadf..f0e4fb23502 100755 --- a/tests/bsim/bluetooth/mesh/tests_scripts/suspend/gatt_suspend_resume.sh +++ b/tests/bsim/bluetooth/mesh/tests_scripts/suspend/gatt_suspend_resume.sh @@ -22,17 +22,10 @@ overlay=overlay_gatt_conf RunTest mesh_gatt_suspend_resume \ suspend_dut_gatt_suspend_resume suspend_tester_gatt -conf=prj_mesh1d1_conf overlay="overlay_gatt_conf_overlay_low_lat_conf" RunTest mesh_gatt_suspend_resume_low_lat \ suspend_dut_gatt_suspend_resume suspend_tester_gatt -conf=prj_mesh1d1_conf -overlay=overlay_gatt_conf -RunTest mesh_gatt_suspend_resume_1d1 \ - suspend_dut_gatt_suspend_resume suspend_tester_gatt - -conf=prj_mesh1d1_conf overlay="overlay_gatt_conf_overlay_psa_conf" RunTest mesh_gatt_suspend_resume_psa \ suspend_dut_gatt_suspend_resume suspend_tester_gatt diff --git a/tests/bsim/bluetooth/mesh/tests_scripts/suspend/suspend_disable_resume.sh b/tests/bsim/bluetooth/mesh/tests_scripts/suspend/suspend_disable_resume.sh index 3329cc2d2bd..bfe42e15c16 100755 --- a/tests/bsim/bluetooth/mesh/tests_scripts/suspend/suspend_disable_resume.sh +++ b/tests/bsim/bluetooth/mesh/tests_scripts/suspend/suspend_disable_resume.sh @@ -19,15 +19,10 @@ source $(dirname "${BASH_SOURCE[0]}")/../../_mesh_test.sh RunTest mesh_suspend_disable_resume \ suspend_dut_suspend_disable_resume suspend_tester_pub -conf=prj_mesh1d1_conf -RunTest mesh_suspend_disable_resume_1d1 \ - suspend_dut_suspend_disable_resume suspend_tester_pub - overlay=overlay_low_lat_conf RunTest mesh_suspend_disable_resume_low_lat \ suspend_dut_suspend_disable_resume suspend_tester_pub -conf=prj_mesh1d1_conf overlay=overlay_psa_conf RunTest mesh_suspend_disable_resume_psa \ suspend_dut_suspend_disable_resume suspend_tester_pub diff --git a/tests/bsim/bluetooth/mesh/tests_scripts/suspend/suspend_resume.sh b/tests/bsim/bluetooth/mesh/tests_scripts/suspend/suspend_resume.sh index 90e1623b62b..31d151201a8 100755 --- a/tests/bsim/bluetooth/mesh/tests_scripts/suspend/suspend_resume.sh +++ b/tests/bsim/bluetooth/mesh/tests_scripts/suspend/suspend_resume.sh @@ -18,15 +18,10 @@ source $(dirname "${BASH_SOURCE[0]}")/../../_mesh_test.sh RunTest mesh_suspend_resume \ suspend_dut_suspend_resume suspend_tester_pub -conf=prj_mesh1d1_conf -RunTest mesh_suspend_resume_1d1 \ - suspend_dut_suspend_resume suspend_tester_pub - overlay=overlay_low_lat_conf RunTest mesh_suspend_resume_low_lat \ suspend_dut_suspend_resume suspend_tester_pub -conf=prj_mesh1d1_conf overlay=overlay_psa_conf RunTest mesh_suspend_resume_psa \ suspend_dut_suspend_resume suspend_tester_pub diff --git a/tests/bsim/bluetooth/mesh/tests_scripts/transport/fixed.sh b/tests/bsim/bluetooth/mesh/tests_scripts/transport/fixed.sh index d4b86d2f98a..f4d0cfc0cac 100755 --- a/tests/bsim/bluetooth/mesh/tests_scripts/transport/fixed.sh +++ b/tests/bsim/bluetooth/mesh/tests_scripts/transport/fixed.sh @@ -15,9 +15,5 @@ source $(dirname "${BASH_SOURCE[0]}")/../../_mesh_test.sh # model; RunTest mesh_transport_fixed transport_tx_fixed transport_rx_fixed -conf=prj_mesh1d1_conf -RunTest mesh_transport_fixed_1d1 transport_tx_fixed transport_rx_fixed - -conf=prj_mesh1d1_conf overlay=overlay_psa_conf RunTest mesh_transport_fixed_1d1 transport_tx_fixed transport_rx_fixed diff --git a/tests/bsim/bluetooth/mesh/tests_scripts/transport/group.sh b/tests/bsim/bluetooth/mesh/tests_scripts/transport/group.sh index d85d7cf8604..7b7c6a559fc 100755 --- a/tests/bsim/bluetooth/mesh/tests_scripts/transport/group.sh +++ b/tests/bsim/bluetooth/mesh/tests_scripts/transport/group.sh @@ -6,9 +6,5 @@ source $(dirname "${BASH_SOURCE[0]}")/../../_mesh_test.sh RunTest mesh_transport_group transport_tx_group transport_rx_group -conf=prj_mesh1d1_conf -RunTest mesh_transport_group_1d1 transport_tx_group transport_rx_group - -conf=prj_mesh1d1_conf overlay=overlay_psa_conf RunTest mesh_transport_group_psa transport_tx_group transport_rx_group diff --git a/tests/bsim/bluetooth/mesh/tests_scripts/transport/loopback.sh b/tests/bsim/bluetooth/mesh/tests_scripts/transport/loopback.sh index 9cc1fb33041..e2812efda23 100755 --- a/tests/bsim/bluetooth/mesh/tests_scripts/transport/loopback.sh +++ b/tests/bsim/bluetooth/mesh/tests_scripts/transport/loopback.sh @@ -6,9 +6,5 @@ source $(dirname "${BASH_SOURCE[0]}")/../../_mesh_test.sh RunTest transport_loopback transport_tx_loopback transport_rx_none -conf=prj_mesh1d1_conf -RunTest transport_loopback_1d1 transport_tx_loopback transport_rx_none - -conf=prj_mesh1d1_conf overlay=overlay_psa_conf RunTest transport_loopback_psa transport_tx_loopback transport_rx_none diff --git a/tests/bsim/bluetooth/mesh/tests_scripts/transport/loopback_group.sh b/tests/bsim/bluetooth/mesh/tests_scripts/transport/loopback_group.sh index 3be2bb24367..38b6c8dd906 100755 --- a/tests/bsim/bluetooth/mesh/tests_scripts/transport/loopback_group.sh +++ b/tests/bsim/bluetooth/mesh/tests_scripts/transport/loopback_group.sh @@ -6,9 +6,5 @@ source $(dirname "${BASH_SOURCE[0]}")/../../_mesh_test.sh RunTest mesh_transport_loopback_group transport_tx_loopback_group transport_rx_group -conf=prj_mesh1d1_conf -RunTest mesh_transport_loopback_group_1d1 transport_tx_loopback_group transport_rx_group - -conf=prj_mesh1d1_conf overlay=overlay_psa_conf RunTest mesh_transport_loopback_group_psa transport_tx_loopback_group transport_rx_group diff --git a/tests/bsim/bluetooth/mesh/tests_scripts/transport/loopback_group_low_lat.sh b/tests/bsim/bluetooth/mesh/tests_scripts/transport/loopback_group_low_lat.sh index 63829e012a5..3972edd3034 100755 --- a/tests/bsim/bluetooth/mesh/tests_scripts/transport/loopback_group_low_lat.sh +++ b/tests/bsim/bluetooth/mesh/tests_scripts/transport/loopback_group_low_lat.sh @@ -7,10 +7,5 @@ source $(dirname "${BASH_SOURCE[0]}")/../../_mesh_test.sh overlay=overlay_low_lat_conf RunTest mesh_transport_loopback_group_low_lat transport_tx_loopback_group transport_rx_group -conf=prj_mesh1d1_conf -overlay=overlay_low_lat_conf -RunTest mesh_transport_loopback_group_low_lat_1d1 transport_tx_loopback_group transport_rx_group - -conf=prj_mesh1d1_conf overlay="overlay_low_lat_conf_overlay_psa_conf" RunTest mesh_transport_loopback_group_low_lat_psa transport_tx_loopback_group transport_rx_group diff --git a/tests/bsim/bluetooth/mesh/tests_scripts/transport/seg_block.sh b/tests/bsim/bluetooth/mesh/tests_scripts/transport/seg_block.sh index 21a56f37478..788d3eeebdf 100755 --- a/tests/bsim/bluetooth/mesh/tests_scripts/transport/seg_block.sh +++ b/tests/bsim/bluetooth/mesh/tests_scripts/transport/seg_block.sh @@ -6,9 +6,5 @@ source $(dirname "${BASH_SOURCE[0]}")/../../_mesh_test.sh RunTest mesh_transport_seg_block transport_tx_seg_block transport_rx_seg_block -conf=prj_mesh1d1_conf -RunTest mesh_transport_seg_block_1d1 transport_tx_seg_block transport_rx_seg_block - -conf=prj_mesh1d1_conf overlay=overlay_psa_conf RunTest mesh_transport_seg_block_psa transport_tx_seg_block transport_rx_seg_block diff --git a/tests/bsim/bluetooth/mesh/tests_scripts/transport/seg_concurrent.sh b/tests/bsim/bluetooth/mesh/tests_scripts/transport/seg_concurrent.sh index 40ba38aae12..d07c90c8d22 100755 --- a/tests/bsim/bluetooth/mesh/tests_scripts/transport/seg_concurrent.sh +++ b/tests/bsim/bluetooth/mesh/tests_scripts/transport/seg_concurrent.sh @@ -6,9 +6,5 @@ source $(dirname "${BASH_SOURCE[0]}")/../../_mesh_test.sh RunTest mesh_transport_seg_concurrent transport_tx_seg_concurrent transport_rx_seg_concurrent -conf=prj_mesh1d1_conf -RunTest mesh_transport_seg_concurrent_1d1 transport_tx_seg_concurrent transport_rx_seg_concurrent - -conf=prj_mesh1d1_conf overlay=overlay_psa_conf RunTest mesh_transport_seg_concurrent_psa transport_tx_seg_concurrent transport_rx_seg_concurrent diff --git a/tests/bsim/bluetooth/mesh/tests_scripts/transport/seg_fail.sh b/tests/bsim/bluetooth/mesh/tests_scripts/transport/seg_fail.sh index ca650ede1f4..72639370b93 100755 --- a/tests/bsim/bluetooth/mesh/tests_scripts/transport/seg_fail.sh +++ b/tests/bsim/bluetooth/mesh/tests_scripts/transport/seg_fail.sh @@ -6,9 +6,5 @@ source $(dirname "${BASH_SOURCE[0]}")/../../_mesh_test.sh RunTest mesh_transport_seg_fail transport_tx_seg_fail -conf=prj_mesh1d1_conf -RunTest mesh_transport_seg_fail_1d1 transport_tx_seg_fail - -conf=prj_mesh1d1_conf overlay=overlay_psa_conf RunTest mesh_transport_seg_fail_psa transport_tx_seg_fail diff --git a/tests/bsim/bluetooth/mesh/tests_scripts/transport/seg_ivu.sh b/tests/bsim/bluetooth/mesh/tests_scripts/transport/seg_ivu.sh index 9268e42029e..0ef30273341 100755 --- a/tests/bsim/bluetooth/mesh/tests_scripts/transport/seg_ivu.sh +++ b/tests/bsim/bluetooth/mesh/tests_scripts/transport/seg_ivu.sh @@ -6,9 +6,5 @@ source $(dirname "${BASH_SOURCE[0]}")/../../_mesh_test.sh RunTest mesh_transport_seg_ivu transport_tx_seg_ivu transport_rx_seg_ivu -conf=prj_mesh1d1_conf -RunTest mesh_transport_seg_ivu_1d1 transport_tx_seg_ivu transport_rx_seg_ivu - -conf=prj_mesh1d1_conf overlay=overlay_psa_conf RunTest mesh_transport_seg_ivu_psa transport_tx_seg_ivu transport_rx_seg_ivu diff --git a/tests/bsim/bluetooth/mesh/tests_scripts/transport/unicast.sh b/tests/bsim/bluetooth/mesh/tests_scripts/transport/unicast.sh index a107a86146c..c91397f4f4b 100755 --- a/tests/bsim/bluetooth/mesh/tests_scripts/transport/unicast.sh +++ b/tests/bsim/bluetooth/mesh/tests_scripts/transport/unicast.sh @@ -6,9 +6,5 @@ source $(dirname "${BASH_SOURCE[0]}")/../../_mesh_test.sh RunTest mesh_transport_unicast transport_tx_unicast transport_rx_unicast -conf=prj_mesh1d1_conf -RunTest mesh_transport_unicast_1d1 transport_tx_unicast transport_rx_unicast - -conf=prj_mesh1d1_conf overlay=overlay_psa_conf RunTest mesh_transport_unicast_psa transport_tx_unicast transport_rx_unicast diff --git a/tests/bsim/bluetooth/mesh/tests_scripts/transport/unicast_low_lat.sh b/tests/bsim/bluetooth/mesh/tests_scripts/transport/unicast_low_lat.sh index cbfc8ea5ce7..981347a3385 100755 --- a/tests/bsim/bluetooth/mesh/tests_scripts/transport/unicast_low_lat.sh +++ b/tests/bsim/bluetooth/mesh/tests_scripts/transport/unicast_low_lat.sh @@ -7,10 +7,5 @@ source $(dirname "${BASH_SOURCE[0]}")/../../_mesh_test.sh overlay=overlay_low_lat_conf RunTest mesh_transport_unicast_low_lat transport_tx_unicast transport_rx_unicast -conf=prj_mesh1d1_conf -overlay=overlay_low_lat_conf -RunTest mesh_transport_unicast_low_lat_1d1 transport_tx_unicast transport_rx_unicast - -conf=prj_mesh1d1_conf overlay="overlay_low_lat_conf_overlay_psa_conf" RunTest mesh_transport_unicast_low_lat_psa transport_tx_unicast transport_rx_unicast diff --git a/tests/bsim/bluetooth/mesh/tests_scripts/transport/unknown_app.sh b/tests/bsim/bluetooth/mesh/tests_scripts/transport/unknown_app.sh index 2a1b2741b60..6f077ee0c8b 100755 --- a/tests/bsim/bluetooth/mesh/tests_scripts/transport/unknown_app.sh +++ b/tests/bsim/bluetooth/mesh/tests_scripts/transport/unknown_app.sh @@ -6,9 +6,5 @@ source $(dirname "${BASH_SOURCE[0]}")/../../_mesh_test.sh RunTest mesh_transport_unknown_app transport_tx_unknown_app transport_rx_none -conf=prj_mesh1d1_conf -RunTest mesh_transport_unknown_app_1d1 transport_tx_unknown_app transport_rx_none - -conf=prj_mesh1d1_conf overlay=overlay_psa_conf RunTest mesh_transport_unknown_app_psa transport_tx_unknown_app transport_rx_none diff --git a/tests/bsim/bluetooth/mesh/tests_scripts/transport/va.sh b/tests/bsim/bluetooth/mesh/tests_scripts/transport/va.sh index 698bd164485..4336a2aa042 100755 --- a/tests/bsim/bluetooth/mesh/tests_scripts/transport/va.sh +++ b/tests/bsim/bluetooth/mesh/tests_scripts/transport/va.sh @@ -6,9 +6,5 @@ source $(dirname "${BASH_SOURCE[0]}")/../../_mesh_test.sh RunTest mesh_transport_va transport_tx_va transport_rx_va -conf=prj_mesh1d1_conf -RunTest mesh_transport_va_1d1 transport_tx_va transport_rx_va - -conf=prj_mesh1d1_conf overlay=overlay_psa_conf RunTest mesh_transport_va_psa transport_tx_va transport_rx_va diff --git a/tests/bsim/bluetooth/mesh/tests_scripts/transport/va_collision.sh b/tests/bsim/bluetooth/mesh/tests_scripts/transport/va_collision.sh index 631c43790ef..dbcc3c64bc7 100755 --- a/tests/bsim/bluetooth/mesh/tests_scripts/transport/va_collision.sh +++ b/tests/bsim/bluetooth/mesh/tests_scripts/transport/va_collision.sh @@ -7,9 +7,5 @@ source $(dirname "${BASH_SOURCE[0]}")/../../_mesh_test.sh # Test transmission to virtual addresses with collision RunTest mesh_transport_va_collision transport_tx_va_collision transport_rx_va_collision -conf=prj_mesh1d1_conf -RunTest mesh_transport_va_collision_1d1 transport_tx_va_collision transport_rx_va_collision - -conf=prj_mesh1d1_conf overlay=overlay_psa_conf RunTest mesh_transport_va_collision_psa transport_tx_va_collision transport_rx_va_collision From 6060dfbc7fef9d81cfe887c7ed1230b2621015d0 Mon Sep 17 00:00:00 2001 From: Pavel Vasilyev Date: Thu, 14 Dec 2023 15:44:24 +0100 Subject: [PATCH 2544/3723] Bluetooth: Mesh: Move mesh-1.1 transport sar configuration Move mesh 1.1 transport sar configuration under transport menu Signed-off-by: Pavel Vasilyev --- subsys/bluetooth/mesh/Kconfig | 244 +++++++++++++++++----------------- 1 file changed, 120 insertions(+), 124 deletions(-) diff --git a/subsys/bluetooth/mesh/Kconfig b/subsys/bluetooth/mesh/Kconfig index 5f59e7f9be8..43428233f94 100644 --- a/subsys/bluetooth/mesh/Kconfig +++ b/subsys/bluetooth/mesh/Kconfig @@ -512,6 +512,126 @@ config BT_MESH_TX_SEG_MAX which leaves 56 bytes for application layer data using a 4-byte MIC and 52 bytes using an 8-byte MIC. +config BT_MESH_SAR_TX_SEG_INT_STEP + hex "Interval between sending two consecutive segments" + range 0x00 0x0F + default 0x05 + help + This value controls the interval between sending two consecutive + segments in a segmented message. The interval is measured in + milliseconds and calculated using the following formula: + (CONFIG_BT_MESH_SAR_TX_SEG_INT_STEP + 1) * 10 ms. + +config BT_MESH_SAR_TX_UNICAST_RETRANS_COUNT + hex "Maximum number of retransmissions to unicast address" + range 0x00 0x0F + default 0x02 + help + This value controls the maximum number of retransmissions of a + segmented message to a unicast address before giving up the transfer. + +config BT_MESH_SAR_TX_UNICAST_RETRANS_WITHOUT_PROG_COUNT + hex "Maximum number of retransmissions without progress to a unicast address" + range 0x00 0x0F + default 0x02 + help + This value defines the maximum number of retransmissions of a + segmented message to a unicast address that the stack will send if no + acknowledgment was received during timeout, or if an + acknowledgment with already confirmed segments was received. + +config BT_MESH_SAR_TX_UNICAST_RETRANS_INT_STEP + hex "Retransmissions interval step of missing segments to unicast address" + range 0x00 0x0F + default 0x07 + help + This value controls the interval step used for delaying the + retransmissions of unacknowledged segments of a segmented message to + a unicast address. The interval step is measured in milliseconds and + calculated using the following formula: + (CONFIG_BT_MESH_SAR_TX_UNICAST_RETRANS_INT_STEP + 1) * 25 ms. + +config BT_MESH_SAR_TX_UNICAST_RETRANS_INT_INC + hex "Retransmissions interval increment of missing segments to unicast address" + range 0x00 0x0F + default 0x01 + help + This value controls the interval increment used for delaying the + retransmissions of unacknowledged segments of a segmented message to + a unicast address. The increment is measured in milliseconds and + calculated using the following formula: + (CONFIG_BT_MESH_SAR_TX_UNICAST_RETRANS_INT_INC + 1) * 25 ms. + +config BT_MESH_SAR_TX_MULTICAST_RETRANS_COUNT + hex "Total number of retransmissions to multicast address" + range 0x00 0x0F + default 0x02 + help + This value controls the total number of retransmissions of a segmented + message to a multicast address. + +config BT_MESH_SAR_TX_MULTICAST_RETRANS_INT + hex "Interval between retransmissions to multicast address" + range 0x00 0x0F + default 0x09 + help + This value controls the interval between retransmissions of all + segments in a segmented message to a multicast address. The + interval is measured in milliseconds and calculated using the + following formula: + (CONFIG_BT_MESH_SAR_TX_MULTICAST_RETRANS_INT + 1) * 25 ms. + +config BT_MESH_SAR_RX_SEG_THRESHOLD + hex "Acknowledgments retransmission threshold" + range 0x00 0x1F + default 0x03 + help + This value defines a threshold in number of segments of a segmented + message for acknowledgment retransmissions. When the number of + segments of a segmented message is above this threshold, the stack + will additionally retransmit every acknowledgment message the + number of times given by value of CONFIG_BT_MESH_SAR_RX_ACK_RETRANS_COUNT. + +config BT_MESH_SAR_RX_ACK_DELAY_INC + hex "Acknowledgment delay increment" + range 0x00 0x07 + default 0x01 + help + This value controls the delay increment of an interval used for + delaying the transmission of an acknowledgment message after + receiving a new segment. The increment is measured in segments + and calculated using the following formula: + CONFIG_BT_MESH_SAR_RX_ACK_DELAY_INC + 1.5. + +config BT_MESH_SAR_RX_SEG_INT_STEP + hex "Segments reception interval step" + range 0x00 0x0F + default 0x05 + help + This value defines the segments reception interval step used for + delaying the transmission of an acknowledgment message after + receiving a new segmnet. The interval is measured in milliseconds + and calculated using the following formula: + (CONFIG_BT_MESH_SAR_RX_SEG_INT_STEP + 1) * 10 ms + +config BT_MESH_SAR_RX_DISCARD_TIMEOUT + hex "Discard timeout for reception of a segmented message" + range 0x00 0x0F + default 0x01 + help + This value defines the time since the last successfully received + segment before giving up the reception of a segmented message. + +config BT_MESH_SAR_RX_ACK_RETRANS_COUNT + hex "Total number of acknowledgment message retransmission" + range 0x00 0x03 + default 0x00 + help + This value defines the total number of retranmissions of an + acknowledgment message that the stack will additionally send when the + size of segments in a segmented message is above the + CONFIG_BT_MESH_SAR_RX_SEG_THRESHOLD value. + endmenu # Transport SAR configuration config BT_MESH_DEFAULT_TTL @@ -1514,130 +1634,6 @@ config BT_MESH_SOL_PDU_RPL_CLI_TIMEOUT for a response message to arrive. This value can be changed at runtime using @ref bt_mesh_sol_pdu_rpl_cli_timeout_set. -menu "Transport SAR configuration" - -config BT_MESH_SAR_TX_SEG_INT_STEP - hex "Interval between sending two consecutive segments" - range 0x00 0x0F - default 0x05 - help - This value controls the interval between sending two consecutive - segments in a segmented message. The interval is measured in - milliseconds and calculated using the following formula: - (CONFIG_BT_MESH_SAR_TX_SEG_INT_STEP + 1) * 10 ms. - -config BT_MESH_SAR_TX_UNICAST_RETRANS_COUNT - hex "Maximum number of retransmissions to unicast address" - range 0x00 0x0F - default 0x02 - help - This value controls the maximum number of retransmissions of a - segmented message to a unicast address before giving up the transfer. - -config BT_MESH_SAR_TX_UNICAST_RETRANS_WITHOUT_PROG_COUNT - hex "Maximum number of retransmissions without progress to a unicast address" - range 0x00 0x0F - default 0x02 - help - This value defines the maximum number of retransmissions of a - segmented message to a unicast address that the stack will send if no - acknowledgment was received during timeout, or if an - acknowledgment with already confirmed segments was received. - -config BT_MESH_SAR_TX_UNICAST_RETRANS_INT_STEP - hex "Retransmissions interval step of missing segments to unicast address" - range 0x00 0x0F - default 0x07 - help - This value controls the interval step used for delaying the - retransmissions of unacknowledged segments of a segmented message to - a unicast address. The interval step is measured in milliseconds and - calculated using the following formula: - (CONFIG_BT_MESH_SAR_TX_UNICAST_RETRANS_INT_STEP + 1) * 25 ms. - -config BT_MESH_SAR_TX_UNICAST_RETRANS_INT_INC - hex "Retransmissions interval increment of missing segments to unicast address" - range 0x00 0x0F - default 0x01 - help - This value controls the interval increment used for delaying the - retransmissions of unacknowledged segments of a segmented message to - a unicast address. The increment is measured in milliseconds and - calculated using the following formula: - (CONFIG_BT_MESH_SAR_TX_UNICAST_RETRANS_INT_INC + 1) * 25 ms. - -config BT_MESH_SAR_TX_MULTICAST_RETRANS_COUNT - hex "Total number of retransmissions to multicast address" - range 0x00 0x0F - default 0x02 - help - This value controls the total number of retransmissions of a segmented - message to a multicast address. - -config BT_MESH_SAR_TX_MULTICAST_RETRANS_INT - hex "Interval between retransmissions to multicast address" - range 0x00 0x0F - default 0x09 - help - This value controls the interval between retransmissions of all - segments in a segmented message to a multicast address. The - interval is measured in milliseconds and calculated using the - following formula: - (CONFIG_BT_MESH_SAR_TX_MULTICAST_RETRANS_INT + 1) * 25 ms. - -config BT_MESH_SAR_RX_SEG_THRESHOLD - hex "Acknowledgments retransmission threshold" - range 0x00 0x1F - default 0x03 - help - This value defines a threshold in number of segments of a segmented - message for acknowledgment retransmissions. When the number of - segments of a segmented message is above this threshold, the stack - will additionally retransmit every acknowledgment message the - number of times given by value of CONFIG_BT_MESH_SAR_RX_ACK_RETRANS_COUNT. - -config BT_MESH_SAR_RX_ACK_DELAY_INC - hex "Acknowledgment delay increment" - range 0x00 0x07 - default 0x01 - help - This value controls the delay increment of an interval used for - delaying the transmission of an acknowledgment message after - receiving a new segment. The increment is measured in segments - and calculated using the following formula: - CONFIG_BT_MESH_SAR_RX_ACK_DELAY_INC + 1.5. - -config BT_MESH_SAR_RX_SEG_INT_STEP - hex "Segments reception interval step" - range 0x00 0x0F - default 0x05 - help - This value defines the segments reception interval step used for - delaying the transmission of an acknowledgment message after - receiving a new segmnet. The interval is measured in milliseconds - and calculated using the following formula: - (CONFIG_BT_MESH_SAR_RX_SEG_INT_STEP + 1) * 10 ms - -config BT_MESH_SAR_RX_DISCARD_TIMEOUT - hex "Discard timeout for reception of a segmented message" - range 0x00 0x0F - default 0x01 - help - This value defines the time since the last successfully received - segment before giving up the reception of a segmented message. - -config BT_MESH_SAR_RX_ACK_RETRANS_COUNT - hex "Total number of acknowledgment message retransmission" - range 0x00 0x03 - default 0x00 - help - This value defines the total number of retranmissions of an - acknowledgment message that the stack will additionally send when the - size of segments in a segmented message is above the - CONFIG_BT_MESH_SAR_RX_SEG_THRESHOLD value. - -endmenu - menu "Capabilities" config BT_MESH_SUBNET_COUNT From b94b9c7759fefe5dfe424554afa87d65b32bfd73 Mon Sep 17 00:00:00 2001 From: Pavel Vasilyev Date: Thu, 14 Dec 2023 15:46:27 +0100 Subject: [PATCH 2545/3723] Bluetooth: Mesh: Move provisioning 1.1 Kconfig options Move provisioning 1.1 Kconfig options to the provisioning menu. Signed-off-by: Pavel Vasilyev --- subsys/bluetooth/mesh/Kconfig | 36 +++++++++++++++++------------------ 1 file changed, 18 insertions(+), 18 deletions(-) diff --git a/subsys/bluetooth/mesh/Kconfig b/subsys/bluetooth/mesh/Kconfig index 43428233f94..de100febf1c 100644 --- a/subsys/bluetooth/mesh/Kconfig +++ b/subsys/bluetooth/mesh/Kconfig @@ -289,6 +289,24 @@ config BT_MESH_PROV_OOB_PUBLIC_KEY help Enable this option if public key is to be exchanged via Out of Band (OOB) technology. +config BT_MESH_ECDH_P256_CMAC_AES128_AES_CCM + bool "Support CMAC AES128 for OOB authentication" + depends on BT_MESH_PROV + default y + help + Enable this option to support CMAC AES128 for OOB authentication. + +config BT_MESH_ECDH_P256_HMAC_SHA256_AES_CCM + bool "Support HMAC SHA256 for OOB authentication" + depends on BT_MESH_PROV + default y + help + Enable this option to support HMAC SHA256 for OOB authentication. + +config BT_MESH_OOB_AUTH_REQUIRED + bool "OOB authentication mandates to use HMAC SHA256" + depends on BT_MESH_ECDH_P256_HMAC_SHA256_AES_CCM + config BT_MESH_PROVISIONER bool "Provisioner support" depends on BT_MESH_CDB @@ -1182,24 +1200,6 @@ config BT_MESH_FRIEND_ADV_LATENCY endif # BT_MESH_FRIEND -config BT_MESH_ECDH_P256_CMAC_AES128_AES_CCM - bool "Support CMAC AES128 for OOB authentication" - depends on BT_MESH_PROV - default y - help - Enable this option to support CMAC AES128 for OOB authentication. - -config BT_MESH_ECDH_P256_HMAC_SHA256_AES_CCM - bool "Support HMAC SHA256 for OOB authentication" - depends on BT_MESH_PROV - default y - help - Enable this option to support HMAC SHA256 for OOB authentication. - -config BT_MESH_OOB_AUTH_REQUIRED - bool "OOB authentication mandates to use HMAC SHA256" - depends on BT_MESH_ECDH_P256_HMAC_SHA256_AES_CCM - menuconfig BT_MESH_BLOB_SRV bool "Support for BLOB Transfer Server model" help From dcdbb4bceb2dff4d80adb34ec38686483796e40f Mon Sep 17 00:00:00 2001 From: Pavel Vasilyev Date: Thu, 14 Dec 2023 15:48:07 +0100 Subject: [PATCH 2546/3723] Bluetooth: Mesh: Move CDP 1.1 Kconfig options Move CDP 1.1 Kconfig options to the access layer menu. Signed-off-by: Pavel Vasilyev --- subsys/bluetooth/mesh/Kconfig | 62 +++++++++++++++++------------------ 1 file changed, 31 insertions(+), 31 deletions(-) diff --git a/subsys/bluetooth/mesh/Kconfig b/subsys/bluetooth/mesh/Kconfig index de100febf1c..5b7c80782f1 100644 --- a/subsys/bluetooth/mesh/Kconfig +++ b/subsys/bluetooth/mesh/Kconfig @@ -710,6 +710,37 @@ config BT_MESH_MODEL_EXTENSIONS Enable support for the model extension concept, allowing the Access layer to know about mesh model relationships. +config BT_MESH_COMP_PAGE_1 + bool "Support for Composition Data Page 1" + depends on BT_MESH_MODEL_EXTENSIONS + help + Enable support for Composition Data Page 1. + +config BT_MESH_MODEL_EXTENSION_LIST_SIZE + int "Model extensions list size" + depends on BT_MESH_COMP_PAGE_1 + range 0 255 + default 10 + help + This option specifies how many models relations can be saved. + Equals to the number of `bt_mesh_model_extend` and `bt_mesh_model_correspond` calls. + This information is used to construct Composition Data Page 1. + +config BT_MESH_COMP_PAGE_2 + bool "Support for Composition Data Page 2" + help + Enable support for Composition Data Page 2. + +config BT_MESH_COMP_PST_BUF_SIZE + int "Composition Data Page persistence buffer size" + default 100 + help + Stack allocated buffer used to temporarily hold Composition + Data Pages during flash operations. Should reflect the size + of the largest Composition Data Page present in the application. + Note that this buffer should still be large enough to restore previously stored + pages after a performed device firmware update. + config BT_MESH_LABEL_NO_RECOVER bool "[DEPRECATED] Don't recover Label UUIDs from groups address subscription list" select DEPRECATED @@ -1530,37 +1561,6 @@ config BT_MESH_PRIV_BEACON_CLI endif # BT_MESH_PRIV_BEACONS -config BT_MESH_COMP_PST_BUF_SIZE - int "Composition Data Page persistence buffer size" - default 100 - help - Stack allocated buffer used to temporarily hold Composition - Data Pages during flash operations. Should reflect the size - of the largest Composition Data Page present in the application. - Note that this buffer should still be large enough to restore previously stored - pages after a performed device firmware update. - -config BT_MESH_COMP_PAGE_1 - bool "Support for Composition Data Page 1" - depends on BT_MESH_MODEL_EXTENSIONS - help - Enable support for Composition Data Page 1. - -config BT_MESH_COMP_PAGE_2 - bool "Support for Composition Data Page 2" - help - Enable support for Composition Data Page 2. - -config BT_MESH_MODEL_EXTENSION_LIST_SIZE - int "Model extensions list size" - depends on BT_MESH_COMP_PAGE_1 - range 0 255 - default 10 - help - This option specifies how many models relations can be saved. - Equals to the number of `bt_mesh_model_extend` and `bt_mesh_model_correspond` calls. - This information is used to construct Composition Data Page 1. - config BT_MESH_SOLICITATION bool From 11986a29d848d2b6cb082bf2dc9e7bf05aac8f3a Mon Sep 17 00:00:00 2001 From: Pavel Vasilyev Date: Thu, 14 Dec 2023 15:50:38 +0100 Subject: [PATCH 2547/3723] Bluetooth: Mesh: Move MBT models Kconfig options Move MBT models Kconfig options under the models menu. Signed-off-by: Pavel Vasilyev --- subsys/bluetooth/mesh/Kconfig | 210 +++++++++++++++++----------------- 1 file changed, 105 insertions(+), 105 deletions(-) diff --git a/subsys/bluetooth/mesh/Kconfig b/subsys/bluetooth/mesh/Kconfig index 5b7c80782f1..0ccf00a5f83 100644 --- a/subsys/bluetooth/mesh/Kconfig +++ b/subsys/bluetooth/mesh/Kconfig @@ -849,6 +849,111 @@ config BT_MESH_HEALTH_CLI_TIMEOUT endif # BT_MESH_HEALTH_CLI +menuconfig BT_MESH_BLOB_SRV + bool "Support for BLOB Transfer Server model" + help + Enable the Binary Large Object (BLOB) Transfer Server model. + +if BT_MESH_BLOB_SRV + +config BT_MESH_BLOB_SRV_PULL_REQ_COUNT + int "Number of chunks to request for each pull" + default 4 + range 1 16 + help + In Pull mode (Pull BLOB Transfer Mode), the BLOB Transfer Server + requests a fixed number of chunks from the Client. Use this option to + control the chunk count in the request. If the BLOB Transfer Server + is instantiated on a Low Power node, the pull request count will be + trimmed to not overflow the Friend queue. + +config BT_MESH_BLOB_SIZE_MAX + int "Largest BLOB size in bytes" + default 524288 + range 1 3257617792 + help + The maximum object size a BLOB Transfer Server can receive. + +config BT_MESH_BLOB_BLOCK_SIZE_MIN + int "Minimum block size" + default 4096 + range 64 1048576 # 2^6 - 2^20 + help + Minimum acceptable block size in a BLOB transfer. The transfer block + size will be some number that is a power of two, and is between block + size min and block size max. If no such number exists, a compile + time warning will be issued. + +config BT_MESH_BLOB_BLOCK_SIZE_MAX + int "Maximum block size" + default 4096 + range BT_MESH_BLOB_BLOCK_SIZE_MIN 1048576 + help + Maximum acceptable block size in a BLOB transfer. The transfer block + size will be some number that is a power of two, and is between block + size min and block size max. If no such number exists, a compile + time warning will be issued. + +config BT_MESH_BLOB_REPORT_TIMEOUT + int "Partial Block Report interval in Pull mode" + default 10 + range 1 31 + help + The timer value that Pull BLOB Transfer Server uses to report missed chunks. + +endif # BT_MESH_BLOB_SRV + +menuconfig BT_MESH_BLOB_CLI + bool "Support for BLOB Transfer Client model" + help + Enable the Binary Large Object (BLOB) Transfer Client model. + +if BT_MESH_BLOB_CLI + +config BT_MESH_BLOB_CLI_BLOCK_RETRIES + int "Number of retries per block" + default 5 + help + Controls the number of times the client will attempt to resend missing + chunks to the BLOB receivers for every block. + +endif + +menu "BLOB models common configuration" + visible if BT_MESH_BLOB_SRV || BT_MESH_BLOB_CLI + +config BT_MESH_BLOB_CHUNK_COUNT_MAX + int "Maximum chunk count per block" + default 256 + range 1 2992 + help + A BLOB transfer contains several blocks. Each block is made up of + several chunks. This option controls the maximum chunk count per + block. + +endmenu + +config BT_MESH_BLOB_IO_FLASH + bool "BLOB flash stream" + default y + depends on BT_MESH_BLOB_SRV || BT_MESH_BLOB_CLI + depends on FLASH_MAP + help + Enable the BLOB flash stream for reading and writing BLOBs directly to + and from flash. + +config BT_MESH_DFU_SRV + bool "Support for Firmware Update Server model" + depends on BT_MESH_BLOB_SRV + help + Enable the Firmware Update Server model. + +config BT_MESH_DFU_CLI + bool "Support for Firmware Update Client model" + depends on BT_MESH_BLOB_CLI + help + Enable the Firmware Update Client model. + endmenu # Models menu "Proxy" @@ -1231,111 +1336,6 @@ config BT_MESH_FRIEND_ADV_LATENCY endif # BT_MESH_FRIEND -menuconfig BT_MESH_BLOB_SRV - bool "Support for BLOB Transfer Server model" - help - Enable the Binary Large Object (BLOB) Transfer Server model. - -if BT_MESH_BLOB_SRV - -config BT_MESH_BLOB_SRV_PULL_REQ_COUNT - int "Number of chunks to request for each pull" - default 4 - range 1 16 - help - In Pull mode (Pull BLOB Transfer Mode), the BLOB Transfer Server - requests a fixed number of chunks from the Client. Use this option to - control the chunk count in the request. If the BLOB Transfer Server - is instantiated on a Low Power node, the pull request count will be - trimmed to not overflow the Friend queue. - -config BT_MESH_BLOB_SIZE_MAX - int "Largest BLOB size in bytes" - default 524288 - range 1 3257617792 - help - The maximum object size a BLOB Transfer Server can receive. - -config BT_MESH_BLOB_BLOCK_SIZE_MIN - int "Minimum block size" - default 4096 - range 64 1048576 # 2^6 - 2^20 - help - Minimum acceptable block size in a BLOB transfer. The transfer block - size will be some number that is a power of two, and is between block - size min and block size max. If no such number exists, a compile - time warning will be issued. - -config BT_MESH_BLOB_BLOCK_SIZE_MAX - int "Maximum block size" - default 4096 - range BT_MESH_BLOB_BLOCK_SIZE_MIN 1048576 - help - Maximum acceptable block size in a BLOB transfer. The transfer block - size will be some number that is a power of two, and is between block - size min and block size max. If no such number exists, a compile - time warning will be issued. - -config BT_MESH_BLOB_REPORT_TIMEOUT - int "Partial Block Report interval in Pull mode" - default 10 - range 1 31 - help - The timer value that Pull BLOB Transfer Server uses to report missed chunks. - -endif # BT_MESH_BLOB_SRV - -menuconfig BT_MESH_BLOB_CLI - bool "Support for BLOB Transfer Client model" - help - Enable the Binary Large Object (BLOB) Transfer Client model. - -if BT_MESH_BLOB_CLI - -config BT_MESH_BLOB_CLI_BLOCK_RETRIES - int "Number of retries per block" - default 5 - help - Controls the number of times the client will attempt to resend missing - chunks to the BLOB receivers for every block. - -endif - -menu "BLOB models common configuration" - visible if BT_MESH_BLOB_SRV || BT_MESH_BLOB_CLI - -config BT_MESH_BLOB_CHUNK_COUNT_MAX - int "Maximum chunk count per block" - default 256 - range 1 2992 - help - A BLOB transfer contains several blocks. Each block is made up of - several chunks. This option controls the maximum chunk count per - block. - -endmenu - -config BT_MESH_BLOB_IO_FLASH - bool "BLOB flash stream" - default y - depends on BT_MESH_BLOB_SRV || BT_MESH_BLOB_CLI - depends on FLASH_MAP - help - Enable the BLOB flash stream for reading and writing BLOBs directly to - and from flash. - -config BT_MESH_DFU_SRV - bool "Support for Firmware Update Server model" - depends on BT_MESH_BLOB_SRV - help - Enable the Firmware Update Server model. - -config BT_MESH_DFU_CLI - bool "Support for Firmware Update Client model" - depends on BT_MESH_BLOB_CLI - help - Enable the Firmware Update Client model. - menu "Firmware Update model configuration" visible if BT_MESH_DFU_SRV || BT_MESH_DFU_CLI From c2299e21206a54aa1234e2566d1f1572fdaa422a Mon Sep 17 00:00:00 2001 From: Pavel Vasilyev Date: Thu, 14 Dec 2023 15:51:29 +0100 Subject: [PATCH 2548/3723] Bluetooth: Mesh: Move DFU models Kconfig options Move DFU models Kconfig options under the models menu. Signed-off-by: Pavel Vasilyev --- subsys/bluetooth/mesh/Kconfig | 190 +++++++++++++++++----------------- 1 file changed, 95 insertions(+), 95 deletions(-) diff --git a/subsys/bluetooth/mesh/Kconfig b/subsys/bluetooth/mesh/Kconfig index 0ccf00a5f83..8a8356c0f62 100644 --- a/subsys/bluetooth/mesh/Kconfig +++ b/subsys/bluetooth/mesh/Kconfig @@ -954,6 +954,101 @@ config BT_MESH_DFU_CLI help Enable the Firmware Update Client model. +menu "Firmware Update model configuration" + visible if BT_MESH_DFU_SRV || BT_MESH_DFU_CLI + +config BT_MESH_DFU_FWID_MAXLEN + int "DFU FWID max length" + default 16 + range 0 106 + help + This value defines the maximum length of an image's firmware ID. + +config BT_MESH_DFU_METADATA_MAXLEN + int "DFU metadata max length" + default 32 + range 18 255 if BT_MESH_DFU_METADATA + range 0 255 + help + This value defines the maximum length of an image's metadata. + +config BT_MESH_DFU_METADATA + bool "Support for the default metadata format" + help + This option adds a set of functions that can be used to encode and decode a firmware + metadata using the format defined in the Bluetooth Mesh DFU subsystem. + +config BT_MESH_DFU_URI_MAXLEN + int "DFU URI max length" + default 32 + range 0 255 + help + This value defines the maximum length of an image's URI, not including + a string terminator. + +endmenu # Firmware Update model configuration + +menuconfig BT_MESH_DFU_SLOTS + bool "Firmware image slot manager" + default y if BT_MESH_DFU_CLI + help + Enable the DFU image slot manager, for managing firmware distribution slots + for the Firmware Update Client model. + +if BT_MESH_DFU_SLOTS + +config BT_MESH_DFU_SLOT_CNT + int "Number of firmware image slots" + default 1 + range 1 32767 + help + This value defines the number of firmware slots the DFU image slot manager + can keep simultaneously. + +endif + +menuconfig BT_MESH_DFD_SRV + bool "Support for Firmware Distribution Server model" + depends on BT_MESH_BLOB_SRV + depends on BT_MESH_DFU_CLI + help + Enable the Firmware Distribution Server model. + +if BT_MESH_DFD_SRV + +config BT_MESH_DFD_SRV_SLOT_MAX_SIZE + int "Largest DFU image that can be stored" + default BT_MESH_BLOB_SIZE_MAX + range 0 BT_MESH_BLOB_SIZE_MAX + help + This value defines the largest DFU image a single slot can store. + +config BT_MESH_DFD_SRV_SLOT_SPACE + int "Total DFU image storage space" + default BT_MESH_DFD_SRV_SLOT_MAX_SIZE + range 0 4294967295 + help + This value defines the total storage space dedicated to storing DFU + images on the Firmware Distribution Server. + +config BT_MESH_DFD_SRV_TARGETS_MAX + int "Maximum Target node count" + default 8 + range 1 65535 + help + This value defines the maximum number of Target nodes the Firmware + Distribution Server can target simultaneously. + +config BT_MESH_DFD_SRV_OOB_UPLOAD + bool "Support for DFU image OOB upload" + help + This enables support for OOB upload of firmware images for + distribution. This makes several callbacks and use of the init + macro BT_MESH_DFD_SRV_INIT_OOB mandatory. See the API documentation + for bt_mesh_dfd_srv_cb for details about the mandatory callbacks. + +endif + endmenu # Models menu "Proxy" @@ -1336,101 +1431,6 @@ config BT_MESH_FRIEND_ADV_LATENCY endif # BT_MESH_FRIEND -menu "Firmware Update model configuration" - visible if BT_MESH_DFU_SRV || BT_MESH_DFU_CLI - -config BT_MESH_DFU_FWID_MAXLEN - int "DFU FWID max length" - default 16 - range 0 106 - help - This value defines the maximum length of an image's firmware ID. - -config BT_MESH_DFU_METADATA_MAXLEN - int "DFU metadata max length" - default 32 - range 18 255 if BT_MESH_DFU_METADATA - range 0 255 - help - This value defines the maximum length of an image's metadata. - -config BT_MESH_DFU_METADATA - bool "Support for the default metadata format" - help - This option adds a set of functions that can be used to encode and decode a firmware - metadata using the format defined in the Bluetooth Mesh DFU subsystem. - -config BT_MESH_DFU_URI_MAXLEN - int "DFU URI max length" - default 32 - range 0 255 - help - This value defines the maximum length of an image's URI, not including - a string terminator. - -endmenu - -menuconfig BT_MESH_DFU_SLOTS - bool "Firmware image slot manager" - default y if BT_MESH_DFU_CLI - help - Enable the DFU image slot manager, for managing firmware distribution slots - for the Firmware Update Client model. - -if BT_MESH_DFU_SLOTS - -config BT_MESH_DFU_SLOT_CNT - int "Number of firmware image slots" - default 1 - range 1 32767 - help - This value defines the number of firmware slots the DFU image slot manager - can keep simultaneously. - -endif - -menuconfig BT_MESH_DFD_SRV - bool "Support for Firmware Distribution Server model" - depends on BT_MESH_BLOB_SRV - depends on BT_MESH_DFU_CLI - help - Enable the Firmware Distribution Server model. - -if BT_MESH_DFD_SRV - -config BT_MESH_DFD_SRV_SLOT_MAX_SIZE - int "Largest DFU image that can be stored" - default BT_MESH_BLOB_SIZE_MAX - range 0 BT_MESH_BLOB_SIZE_MAX - help - This value defines the largest DFU image a single slot can store. - -config BT_MESH_DFD_SRV_SLOT_SPACE - int "Total DFU image storage space" - default BT_MESH_DFD_SRV_SLOT_MAX_SIZE - range 0 4294967295 - help - This value defines the total storage space dedicated to storing DFU - images on the Firmware Distribution Server. - -config BT_MESH_DFD_SRV_TARGETS_MAX - int "Maximum Target node count" - default 8 - range 1 65535 - help - This value defines the maximum number of Target nodes the Firmware - Distribution Server can target simultaneously. - -config BT_MESH_DFD_SRV_OOB_UPLOAD - bool "Support for DFU image OOB upload" - help - This enables support for OOB upload of firmware images for - distribution. This makes several callbacks and use of the init - macro BT_MESH_DFD_SRV_INIT_OOB mandatory. See the API documentation - for bt_mesh_dfd_srv_cb for details about the mandatory callbacks. - -endif - config BT_MESH_RPR_SRV bool "Support for Remote Provisioning Server model" help From f89effbe755e06d9b8dab83cbda8473e4b739902 Mon Sep 17 00:00:00 2001 From: Pavel Vasilyev Date: Thu, 14 Dec 2023 15:52:20 +0100 Subject: [PATCH 2549/3723] Bluetooth: Mesh: Move RPR models Kconfig options Move RPR models Kconfig options under the models menu. Signed-off-by: Pavel Vasilyev --- subsys/bluetooth/mesh/Kconfig | 95 ++++++++++++++++++----------------- 1 file changed, 48 insertions(+), 47 deletions(-) diff --git a/subsys/bluetooth/mesh/Kconfig b/subsys/bluetooth/mesh/Kconfig index 8a8356c0f62..8f419511ee7 100644 --- a/subsys/bluetooth/mesh/Kconfig +++ b/subsys/bluetooth/mesh/Kconfig @@ -1049,6 +1049,54 @@ config BT_MESH_DFD_SRV_OOB_UPLOAD endif +config BT_MESH_RPR_SRV + bool "Support for Remote Provisioning Server model" + help + The Remote Provisioning Server is the proxy for a provisioning + process, allowing provisioners to tunnel their provisioning + messages through the mesh to the Remote Provisioning Server, which + communicates directly with the unprovisioned node. + +config BT_MESH_RPR_CLI + bool "Support for Remote Provisioning Client model" + depends on BT_MESH_PROVISIONER + help + The Remote Provisioning Client is instantiated on the provisioner + node, and allows provisioning of new devices through the mesh network + by tunnelling provisioning messages to a Remote Provisioning Server. + +menu "Remote Provisioning configuration" + visible if BT_MESH_RPR_SRV || BT_MESH_RPR_CLI + +config BT_MESH_RPR_AD_TYPES_MAX + int "Max AD types in extended scanning" + default 1 + range 1 16 + help + During extended scanning, the Remote Provisioning Server can include + a set of AD types in the scan reports, collected from the + unprovisioned device's advertisement data. This option controls + the highest number of AD types a single server can scan for, and a + Client can request. + +config BT_MESH_RPR_SRV_SCANNED_ITEMS_MAX + int "Max scannable unprovisioned devices for Remote Provisioning Server" + default 4 + range 4 255 + help + Max number of unique unprovisioned devices a single Remote + Provisioning Server can hold. + +config BT_MESH_RPR_SRV_AD_DATA_MAX + int "Max additional advertisement data to report" + default 31 + range 3 255 + help + Buffer size for the additional advertisement data reported during + extended scanning. + +endmenu # Remote Provisioning configuration + endmenu # Models menu "Proxy" @@ -1431,53 +1479,6 @@ config BT_MESH_FRIEND_ADV_LATENCY endif # BT_MESH_FRIEND -config BT_MESH_RPR_SRV - bool "Support for Remote Provisioning Server model" - help - The Remote Provisioning Server is the proxy for a provisioning - process, allowing provisioners to tunnel their provisioning - messages through the mesh to the Remote Provisioning Server, which - communicates directly with the unprovisioned node. - -config BT_MESH_RPR_CLI - bool "Support for Remote Provisioning Client model" - depends on BT_MESH_PROVISIONER - help - The Remote Provisioning Client is instantiated on the provisioner - node, and allows provisioning of new devices through the mesh network - by tunnelling provisioning messages to a Remote Provisioning Server. - -menu "Remote Provisioning configuration" - visible if BT_MESH_RPR_SRV || BT_MESH_RPR_CLI - -config BT_MESH_RPR_AD_TYPES_MAX - int "Max AD types in extended scanning" - default 1 - range 1 16 - help - During extended scanning, the Remote Provisioning Server can include - a set of AD types in the scan reports, collected from the - unprovisioned device's advertisement data. This option controls - the highest number of AD types a single server can scan for, and a - Client can request. - -config BT_MESH_RPR_SRV_SCANNED_ITEMS_MAX - int "Max scannable unprovisioned devices for Remote Provisioning Server" - default 4 - range 4 255 - help - Max number of unique unprovisioned devices a single Remote - Provisioning Server can hold. - -config BT_MESH_RPR_SRV_AD_DATA_MAX - int "Max additional advertisement data to report" - default 31 - range 3 255 - help - Buffer size for the additional advertisement data reported during - extended scanning. -endmenu - config BT_MESH_SAR_CFG bool From 5b0a1bb165b8f822f6bc5b75a44f986aa8dfd3f1 Mon Sep 17 00:00:00 2001 From: Pavel Vasilyev Date: Thu, 14 Dec 2023 15:53:04 +0100 Subject: [PATCH 2550/3723] Bluetooth: Mesh: Move SAR models Kconfig options Move SAR models Kconfig options under the models menu. Signed-off-by: Pavel Vasilyev --- subsys/bluetooth/mesh/Kconfig | 30 +++++++++++++++--------------- 1 file changed, 15 insertions(+), 15 deletions(-) diff --git a/subsys/bluetooth/mesh/Kconfig b/subsys/bluetooth/mesh/Kconfig index 8f419511ee7..4ddb62d3b57 100644 --- a/subsys/bluetooth/mesh/Kconfig +++ b/subsys/bluetooth/mesh/Kconfig @@ -1097,6 +1097,21 @@ config BT_MESH_RPR_SRV_AD_DATA_MAX endmenu # Remote Provisioning configuration +config BT_MESH_SAR_CFG + bool + +config BT_MESH_SAR_CFG_SRV + bool "Support for SAR Configuration Server model" + select BT_MESH_SAR_CFG + help + Enable support for the SAR configuration server model. + +config BT_MESH_SAR_CFG_CLI + bool "Support for SAR Configuration Client Model" + select BT_MESH_SAR_CFG + help + Enable support for the SAR configuration client model. + endmenu # Models menu "Proxy" @@ -1479,21 +1494,6 @@ config BT_MESH_FRIEND_ADV_LATENCY endif # BT_MESH_FRIEND -config BT_MESH_SAR_CFG - bool - -config BT_MESH_SAR_CFG_SRV - bool "Support for SAR Configuration Server model" - select BT_MESH_SAR_CFG - help - Enable support for the SAR configuration server model. - -config BT_MESH_SAR_CFG_CLI - bool "Support for SAR Configuration Client Model" - select BT_MESH_SAR_CFG - help - Enable support for the SAR configuration client model. - config BT_MESH_OP_AGG bool From 5156f78386efabecef54150b5dc5803c2541e1a7 Mon Sep 17 00:00:00 2001 From: Pavel Vasilyev Date: Thu, 14 Dec 2023 15:53:41 +0100 Subject: [PATCH 2551/3723] Bluetooth: Mesh: Move OpAgg models Kconfig options Move OpAgg models Kconfig options under the models menu. Signed-off-by: Pavel Vasilyev --- subsys/bluetooth/mesh/Kconfig | 64 +++++++++++++++++------------------ 1 file changed, 32 insertions(+), 32 deletions(-) diff --git a/subsys/bluetooth/mesh/Kconfig b/subsys/bluetooth/mesh/Kconfig index 4ddb62d3b57..e3b4ea38646 100644 --- a/subsys/bluetooth/mesh/Kconfig +++ b/subsys/bluetooth/mesh/Kconfig @@ -1112,6 +1112,38 @@ config BT_MESH_SAR_CFG_CLI help Enable support for the SAR configuration client model. +config BT_MESH_OP_AGG + bool + +config BT_MESH_OP_AGG_SRV + bool "Support for Opcode Aggregator Server Model" + select BT_MESH_OP_AGG + help + Enable support for the Opcode Aggregator Server model. + +config BT_MESH_OP_AGG_CLI + bool "Support for Opcode Aggregator Client Model" + select BT_MESH_OP_AGG + help + Enable support for the Opcode Aggregator Client model. + +if BT_MESH_OP_AGG_CLI + +config BT_MESH_OP_AGG_CLI_TIMEOUT + int "Opcodes Aggregator Client model timeout in milliseconds" + default 10000 + help + This timeout controls how long Opcodes Aggregator Client waits + for a response message to arrive. This value can be changed at + runtime using @ref bt_mesh_op_agg_cli_timeout_set. + +endif # BT_MESH_OP_AGG_CLI + +config BT_MESH_LARGE_COMP_DATA_SRV + bool "Support for Large Composition Data Server Model" + help + Enable support for the Large Composition Data Server model. + endmenu # Models menu "Proxy" @@ -1494,38 +1526,6 @@ config BT_MESH_FRIEND_ADV_LATENCY endif # BT_MESH_FRIEND -config BT_MESH_OP_AGG - bool - -config BT_MESH_OP_AGG_SRV - bool "Support for Opcode Aggregator Server Model" - select BT_MESH_OP_AGG - help - Enable support for the Opcode Aggregator Server model. - -config BT_MESH_OP_AGG_CLI - bool "Support for Opcode Aggregator Client Model" - select BT_MESH_OP_AGG - help - Enable support for the Opcode Aggregator Client model. - -if BT_MESH_OP_AGG_CLI - -config BT_MESH_OP_AGG_CLI_TIMEOUT - int "Opcodes Aggregator Client model timeout in milliseconds" - default 10000 - help - This timeout controls how long Opcodes Aggregator Client waits - for a response message to arrive. This value can be changed at - runtime using @ref bt_mesh_op_agg_cli_timeout_set. - -endif # BT_MESH_OP_AGG_CLI - -config BT_MESH_LARGE_COMP_DATA_SRV - bool "Support for Large Composition Data Server Model" - help - Enable support for the Large Composition Data Server model. - if BT_MESH_LARGE_COMP_DATA_SRV config BT_MESH_MODELS_METADATA_PAGE_LEN From 84febe83a9e37e4a47dba9e334865208849ec3bb Mon Sep 17 00:00:00 2001 From: Pavel Vasilyev Date: Thu, 14 Dec 2023 15:54:31 +0100 Subject: [PATCH 2552/3723] Bluetooth: Mesh: Move LCD models Kconfig options Move LCD models Kconfig options under the models menu. Signed-off-by: Pavel Vasilyev --- subsys/bluetooth/mesh/Kconfig | 32 ++++++++++++++++---------------- 1 file changed, 16 insertions(+), 16 deletions(-) diff --git a/subsys/bluetooth/mesh/Kconfig b/subsys/bluetooth/mesh/Kconfig index e3b4ea38646..db15e659249 100644 --- a/subsys/bluetooth/mesh/Kconfig +++ b/subsys/bluetooth/mesh/Kconfig @@ -1144,6 +1144,22 @@ config BT_MESH_LARGE_COMP_DATA_SRV help Enable support for the Large Composition Data Server model. +if BT_MESH_LARGE_COMP_DATA_SRV + +config BT_MESH_MODELS_METADATA_PAGE_LEN + int "Maximum length of the Models Metadata Page" + default 150 + help + This value is the combined total metadata length for + all models on the device. + +endif # BT_MESH_LARGE_COMP_DATA_SRV + +config BT_MESH_LARGE_COMP_DATA_CLI + bool "Support for Large Composition Data Client model" + help + Enable support for the Large Composition Data Client model. + endmenu # Models menu "Proxy" @@ -1526,22 +1542,6 @@ config BT_MESH_FRIEND_ADV_LATENCY endif # BT_MESH_FRIEND -if BT_MESH_LARGE_COMP_DATA_SRV - -config BT_MESH_MODELS_METADATA_PAGE_LEN - int "Maximum length of the Models Metadata Page" - default 150 - help - This value is the combined total metadata length for - all models on the device. - -endif # BT_MESH_LARGE_COMP_DATA_SRV - -config BT_MESH_LARGE_COMP_DATA_CLI - bool "Support for Large Composition Data Client model" - help - Enable support for the Large Composition Data Client model. - config BT_MESH_PRIV_BEACONS bool "Support for private beacons" default y From 168af2324d21ff1db187996e5484081ee94e5791 Mon Sep 17 00:00:00 2001 From: Pavel Vasilyev Date: Thu, 14 Dec 2023 15:55:06 +0100 Subject: [PATCH 2553/3723] Bluetooth: Mesh: Move PRB models Kconfig options Move PRB models Kconfig options under the models menu. Signed-off-by: Pavel Vasilyev --- subsys/bluetooth/mesh/Kconfig | 40 +++++++++++++++++------------------ 1 file changed, 20 insertions(+), 20 deletions(-) diff --git a/subsys/bluetooth/mesh/Kconfig b/subsys/bluetooth/mesh/Kconfig index db15e659249..98867104f49 100644 --- a/subsys/bluetooth/mesh/Kconfig +++ b/subsys/bluetooth/mesh/Kconfig @@ -1160,6 +1160,26 @@ config BT_MESH_LARGE_COMP_DATA_CLI help Enable support for the Large Composition Data Client model. +config BT_MESH_PRIV_BEACONS + bool "Support for private beacons" + default y + help + Enable support for private beacons. + +if BT_MESH_PRIV_BEACONS + +config BT_MESH_PRIV_BEACON_SRV + bool "Support for Private Beacon Server Model" + help + Enable support for the Private Beacon Server model. + +config BT_MESH_PRIV_BEACON_CLI + bool "Support for Private Beacon Client Model" + help + Enable support for the Private Beacon Client model. + +endif # BT_MESH_PRIV_BEACONS + endmenu # Models menu "Proxy" @@ -1542,26 +1562,6 @@ config BT_MESH_FRIEND_ADV_LATENCY endif # BT_MESH_FRIEND -config BT_MESH_PRIV_BEACONS - bool "Support for private beacons" - default y - help - Enable support for private beacons. - -if BT_MESH_PRIV_BEACONS - -config BT_MESH_PRIV_BEACON_SRV - bool "Support for Private Beacon Server Model" - help - Enable support for the Private Beacon Server model. - -config BT_MESH_PRIV_BEACON_CLI - bool "Support for Private Beacon Client Model" - help - Enable support for the Private Beacon Client model. - -endif # BT_MESH_PRIV_BEACONS - config BT_MESH_SOLICITATION bool From 343fa6d04439abc220d96e759165da9b750ab064 Mon Sep 17 00:00:00 2001 From: Pavel Vasilyev Date: Thu, 14 Dec 2023 15:56:32 +0100 Subject: [PATCH 2554/3723] Bluetooth: Mesh: Move OdProxy models Kconfig options Move OdProxy models Kconfig options under the models menu. Signed-off-by: Pavel Vasilyev --- subsys/bluetooth/mesh/Kconfig | 110 +++++++++++++++++----------------- 1 file changed, 55 insertions(+), 55 deletions(-) diff --git a/subsys/bluetooth/mesh/Kconfig b/subsys/bluetooth/mesh/Kconfig index 98867104f49..1d81c4df99b 100644 --- a/subsys/bluetooth/mesh/Kconfig +++ b/subsys/bluetooth/mesh/Kconfig @@ -1180,6 +1180,61 @@ config BT_MESH_PRIV_BEACON_CLI endif # BT_MESH_PRIV_BEACONS +config BT_MESH_OD_PRIV_PROXY_CLI + bool "Support for On-Demand Private Proxy Client model" + help + On-Demand Private Proxy Client allows to configure and check the state + of On-Demand Private Proxy Servers. The state determines if the peers will + advertise the Private Network Identity type after receiving a Solicitation PDU. + + +config BT_MESH_OD_PRIV_PROXY_CLI_TIMEOUT + int "Solicitation PDU RPL Configuration Client model timeout in milliseconds" + default 5000 + depends on BT_MESH_OD_PRIV_PROXY_CLI + help + This timeout controls how long the On-Demand Private Proxy Client waits + for a response message to arrive. This value can be changed at runtime + using @ref bt_mesh_od_priv_proxy_cli_timeout_set. + +config BT_MESH_OD_PRIV_PROXY_SRV + bool "Support for On-Demand Private Proxy Server model" + depends on BT_MESH_PRIV_BEACON_SRV + select BT_MESH_SOLICITATION + help + The On-Demand Private Proxy Server is used to support configuration of + advertising with Private Network Identity type of a node. + When enabled, the Solicitation PDU RPL Configuration Server model is also enabled. + +config BT_MESH_PROXY_SRPL_SIZE + int "Size of solicitation replay protection list (SRPL)" + depends on BT_MESH_OD_PRIV_PROXY_SRV + default 10 + range 1 255 + help + Size of SRPL. The list is used to determine if a received Solicitation PDU + is valid. It is valid when the SSRC field value of the received Solicitation PDU + is stored in the SRPL and the SSEQ field value is bigger than the corresponding + stored SSEQ value, or if the SSRC was not stored in the RPL and the SRPL still has + space for new entries. + +config BT_MESH_SOL_PDU_RPL_CLI + bool "Support for Solicitation PDU RPL Configuration Client model" + help + The Solicitation PDU RPL Configuration Client is used to support the + functionality of removing addresses from the solicitation replay + protection list (SRPL) of a node that supports the Solicitation + PDU RPL Configuration Server model. + +config BT_MESH_SOL_PDU_RPL_CLI_TIMEOUT + int "Solicitation PDU RPL Configuration Client model timeout in milliseconds" + default 5000 + depends on BT_MESH_SOL_PDU_RPL_CLI + help + This timeout controls how long Solicitation PDU RPL Configuration Client waits + for a response message to arrive. This value can be changed at runtime + using @ref bt_mesh_sol_pdu_rpl_cli_timeout_set. + endmenu # Models menu "Proxy" @@ -1580,61 +1635,6 @@ config BT_MESH_SOL_ADV_XMIT How many times Solicitation PDU advertisements will be repeated. 0 means that there will be 1 transmission without retransmissions. -config BT_MESH_OD_PRIV_PROXY_CLI - bool "Support for On-Demand Private Proxy Client model" - help - On-Demand Private Proxy Client allows to configure and check the state - of On-Demand Private Proxy Servers. The state determines if the peers will - advertise the Private Network Identity type after receiving a Solicitation PDU. - - -config BT_MESH_OD_PRIV_PROXY_CLI_TIMEOUT - int "Solicitation PDU RPL Configuration Client model timeout in milliseconds" - default 5000 - depends on BT_MESH_OD_PRIV_PROXY_CLI - help - This timeout controls how long the On-Demand Private Proxy Client waits - for a response message to arrive. This value can be changed at runtime - using @ref bt_mesh_od_priv_proxy_cli_timeout_set. - -config BT_MESH_OD_PRIV_PROXY_SRV - bool "Support for On-Demand Private Proxy Server model" - depends on BT_MESH_PRIV_BEACON_SRV - select BT_MESH_SOLICITATION - help - The On-Demand Private Proxy Server is used to support configuration of - advertising with Private Network Identity type of a node. - When enabled, the Solicitation PDU RPL Configuration Server model is also enabled. - -config BT_MESH_PROXY_SRPL_SIZE - int "Size of solicitation replay protection list (SRPL)" - depends on BT_MESH_OD_PRIV_PROXY_SRV - default 10 - range 1 255 - help - Size of SRPL. The list is used to determine if a received Solicitation PDU - is valid. It is valid when the SSRC field value of the received Solicitation PDU - is stored in the SRPL and the SSEQ field value is bigger than the corresponding - stored SSEQ value, or if the SSRC was not stored in the RPL and the SRPL still has - space for new entries. - -config BT_MESH_SOL_PDU_RPL_CLI - bool "Support for Solicitation PDU RPL Configuration Client model" - help - The Solicitation PDU RPL Configuration Client is used to support the - functionality of removing addresses from the solicitation replay - protection list (SRPL) of a node that supports the Solicitation - PDU RPL Configuration Server model. - -config BT_MESH_SOL_PDU_RPL_CLI_TIMEOUT - int "Solicitation PDU RPL Configuration Client model timeout in milliseconds" - default 5000 - depends on BT_MESH_SOL_PDU_RPL_CLI - help - This timeout controls how long Solicitation PDU RPL Configuration Client waits - for a response message to arrive. This value can be changed at runtime - using @ref bt_mesh_sol_pdu_rpl_cli_timeout_set. - menu "Capabilities" config BT_MESH_SUBNET_COUNT From bb75d1f8130faefff8775d513f4c23af8fe922b1 Mon Sep 17 00:00:00 2001 From: Pavel Vasilyev Date: Thu, 14 Dec 2023 15:57:17 +0100 Subject: [PATCH 2555/3723] Bluetooth: Mesh: Move Solicitation Kconfig options Move Solicitation Kconfig options under the models menu. Signed-off-by: Pavel Vasilyev --- subsys/bluetooth/mesh/Kconfig | 36 +++++++++++++++++------------------ 1 file changed, 18 insertions(+), 18 deletions(-) diff --git a/subsys/bluetooth/mesh/Kconfig b/subsys/bluetooth/mesh/Kconfig index 1d81c4df99b..b067259483c 100644 --- a/subsys/bluetooth/mesh/Kconfig +++ b/subsys/bluetooth/mesh/Kconfig @@ -1299,6 +1299,24 @@ config BT_MESH_PROXY_CLIENT i.e. the ability to act as a proxy between a Mesh GATT Service and a Mesh network. +config BT_MESH_SOLICITATION + bool + +config BT_MESH_PROXY_SOLICITATION + bool "Proxy solicitation feature" + select BT_MESH_SOLICITATION + help + This option enables support for sending Solicitation PDUs. + +config BT_MESH_SOL_ADV_XMIT + int "Solicitation PDU retransmission count" + depends on BT_MESH_PROXY_SOLICITATION + range 0 10 + default 2 + help + How many times Solicitation PDU advertisements will be repeated. 0 means that there will be + 1 transmission without retransmissions. + endmenu # Proxy choice BT_MESH_CRYPTO_LIB @@ -1617,24 +1635,6 @@ config BT_MESH_FRIEND_ADV_LATENCY endif # BT_MESH_FRIEND -config BT_MESH_SOLICITATION - bool - -config BT_MESH_PROXY_SOLICITATION - bool "Proxy solicitation feature" - select BT_MESH_SOLICITATION - help - This option enables support for sending Solicitation PDUs. - -config BT_MESH_SOL_ADV_XMIT - int "Solicitation PDU retransmission count" - depends on BT_MESH_PROXY_SOLICITATION - range 0 10 - default 2 - help - How many times Solicitation PDU advertisements will be repeated. 0 means that there will be - 1 transmission without retransmissions. - menu "Capabilities" config BT_MESH_SUBNET_COUNT From 83b7513937e03507230bdb35d59275f63fbb47d6 Mon Sep 17 00:00:00 2001 From: Pavel Vasilyev Date: Thu, 14 Dec 2023 16:01:00 +0100 Subject: [PATCH 2556/3723] Bluetooth: Mesh: Move beacons Kconfiguration under separate submenu Collect beacons Kconfiguration under own submenu. Signed-off-by: Pavel Vasilyev --- subsys/bluetooth/mesh/Kconfig | 16 ++++++++++------ 1 file changed, 10 insertions(+), 6 deletions(-) diff --git a/subsys/bluetooth/mesh/Kconfig b/subsys/bluetooth/mesh/Kconfig index b067259483c..25fb2e870d4 100644 --- a/subsys/bluetooth/mesh/Kconfig +++ b/subsys/bluetooth/mesh/Kconfig @@ -1160,12 +1160,6 @@ config BT_MESH_LARGE_COMP_DATA_CLI help Enable support for the Large Composition Data Client model. -config BT_MESH_PRIV_BEACONS - bool "Support for private beacons" - default y - help - Enable support for private beacons. - if BT_MESH_PRIV_BEACONS config BT_MESH_PRIV_BEACON_SRV @@ -1388,6 +1382,8 @@ config BT_MESH_PSA_KEY_ID_USER_MIN_OFFSET endif # BT_MESH_USES_MBEDTLS_PSA || BT_MESH_USES_TFM_PSA +menu "Beacons" + config BT_MESH_BEACON_ENABLED bool "Secure network beacon enabled" default y @@ -1395,6 +1391,14 @@ config BT_MESH_BEACON_ENABLED Controls whether the Secure network beacon feature is enabled by default. Can be changed through runtime configuration. +config BT_MESH_PRIV_BEACONS + bool "Support for private beacons" + default y + help + Enable support for private beacons. + +endmenu # Beacons + menu "IV Index & Sequence number" config BT_MESH_IV_UPDATE_TEST From 042cb6ac4e0042713c94f1823020ca35127ae5fd Mon Sep 17 00:00:00 2001 From: Tomasz Lissowski Date: Tue, 9 Jan 2024 09:00:55 +0100 Subject: [PATCH 2557/3723] soc: intel_adsp: enable DfTTS-based time stamping on ACE platforms This patch enables time stamping controlled by DSP Timers / Time Stamping logic on ACE1.5 / ACE2.0 platforms. Signed-off-by: Tomasz Lissowski --- soc/xtensa/intel_adsp/ace/CMakeLists.txt | 1 + .../intel_adsp/ace/include/adsp_timestamp.h | 29 ++++++ .../ace/include/intel_ace15_mtpm/adsp_shim.h | 11 +++ .../ace/include/intel_ace20_lnl/adsp_shim.h | 11 +++ soc/xtensa/intel_adsp/ace/timestamp.c | 96 +++++++++++++++++++ 5 files changed, 148 insertions(+) create mode 100644 soc/xtensa/intel_adsp/ace/include/adsp_timestamp.h create mode 100644 soc/xtensa/intel_adsp/ace/timestamp.c diff --git a/soc/xtensa/intel_adsp/ace/CMakeLists.txt b/soc/xtensa/intel_adsp/ace/CMakeLists.txt index a5aa90b59d0..28626787c5e 100644 --- a/soc/xtensa/intel_adsp/ace/CMakeLists.txt +++ b/soc/xtensa/intel_adsp/ace/CMakeLists.txt @@ -11,6 +11,7 @@ zephyr_library_sources( power_down.S power.c boot.c + timestamp.c ) zephyr_include_directories(include) diff --git a/soc/xtensa/intel_adsp/ace/include/adsp_timestamp.h b/soc/xtensa/intel_adsp/ace/include/adsp_timestamp.h new file mode 100644 index 00000000000..4c7796a5ae4 --- /dev/null +++ b/soc/xtensa/intel_adsp/ace/include/adsp_timestamp.h @@ -0,0 +1,29 @@ +/* + * Copyright (c) 2023 Intel Corporation + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#ifndef ZEPHYR_SOC_INTEL_ADSP_ACE_TIMESTAMP_H_ +#define ZEPHYR_SOC_INTEL_ADSP_ACE_TIMESTAMP_H_ + +#include + +/* Captured timestamp data - contains a copy of all DfTTS snapshot registers. */ +struct intel_adsp_timestamp { + uint32_t iscs; /* copy of DfISCS register */ + uint64_t lscs; /* copy of DfLSCS register */ + uint64_t dwccs; /* copy of DfDWCCS register */ + uint64_t artcs; /* copy of DfARTCS register */ + uint32_t lwccs; /* copy of DfLWCCS register */ +}; + +/* + * @brief Perform timestamping process using DfTTS logic. + * + * @param tsctrl Value to be applied to DfTSCTRL register to control timestamping logic + * @param timestamp Captured timestamp data + */ +int intel_adsp_get_timestamp(uint32_t tsctrl, struct intel_adsp_timestamp *timestamp); + +#endif /* ZEPHYR_SOC_INTEL_ADSP_ACE_TIMESTAMP_H_ */ diff --git a/soc/xtensa/intel_adsp/ace/include/intel_ace15_mtpm/adsp_shim.h b/soc/xtensa/intel_adsp/ace/include/intel_ace15_mtpm/adsp_shim.h index 56997ee84d1..521dc4e5fb1 100644 --- a/soc/xtensa/intel_adsp/ace/include/intel_ace15_mtpm/adsp_shim.h +++ b/soc/xtensa/intel_adsp/ace/include/intel_ace15_mtpm/adsp_shim.h @@ -8,6 +8,8 @@ #ifndef _ASMLANGUAGE +#include + /** * DfPMCCH * Power Management / Clock Control (HST) Registers @@ -138,6 +140,15 @@ struct ace_dfpmccu { #define ADSP_SHIM_DSPWCTCS_TTIE(c) BIT(8 + (c)) +#define ADSP_SHIM_TSCTRL_NTK BIT(31) +#define ADSP_SHIM_TSCTRL_IONTE BIT(30) +#define ADSP_SHIM_TSCTRL_DMATS GENMASK(13, 12) +#define ADSP_SHIM_TSCTRL_CLNKS GENMASK(11, 10) +#define ADSP_SHIM_TSCTRL_HHTSE BIT(7) +#define ADSP_SHIM_TSCTRL_LWCS BIT(6) +#define ADSP_SHIM_TSCTRL_ODTS BIT(5) +#define ADSP_SHIM_TSCTRL_CDMAS GENMASK(4, 0) + #endif /* _ASMLANGUAGE */ #define ACE_CLKCTL_WOVCRO BIT(21) /* Request WOVCRO clock */ diff --git a/soc/xtensa/intel_adsp/ace/include/intel_ace20_lnl/adsp_shim.h b/soc/xtensa/intel_adsp/ace/include/intel_ace20_lnl/adsp_shim.h index f7661317062..f640a0a9f59 100644 --- a/soc/xtensa/intel_adsp/ace/include/intel_ace20_lnl/adsp_shim.h +++ b/soc/xtensa/intel_adsp/ace/include/intel_ace20_lnl/adsp_shim.h @@ -8,6 +8,8 @@ #ifndef _ASMLANGUAGE +#include + /** * DfPMCCH * Power Management / Clock Control (HST) Registers @@ -138,6 +140,15 @@ struct ace_dfpmccu { #define ADSP_SHIM_DSPWCTCS_TTIE(c) BIT(8 + (c)) +#define ADSP_SHIM_TSCTRL_NTK BIT(31) +#define ADSP_SHIM_TSCTRL_IONTE BIT(30) +#define ADSP_SHIM_TSCTRL_DMATS GENMASK(13, 12) +#define ADSP_SHIM_TSCTRL_CLNKS GENMASK(11, 10) +#define ADSP_SHIM_TSCTRL_HHTSE BIT(7) +#define ADSP_SHIM_TSCTRL_LWCS BIT(6) +#define ADSP_SHIM_TSCTRL_ODTS BIT(5) +#define ADSP_SHIM_TSCTRL_CDMAS GENMASK(4, 0) + #endif /* _ASMLANGUAGE */ #define ACE_CLKCTL_WOVCRO BIT(4) /* Request WOVCRO clock */ diff --git a/soc/xtensa/intel_adsp/ace/timestamp.c b/soc/xtensa/intel_adsp/ace/timestamp.c new file mode 100644 index 00000000000..7f3168d87f4 --- /dev/null +++ b/soc/xtensa/intel_adsp/ace/timestamp.c @@ -0,0 +1,96 @@ +/* + * Copyright (c) 2023 Intel Corporation + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include +#include +#include +#include +#include + +#define TTS_BASE_ADDR DT_REG_ADDR(DT_NODELABEL(tts)) + +#define TSCTRL_ADDR (TTS_BASE_ADDR + ADSP_TSCTRL_OFFSET) +#define ISCS_ADDR (TTS_BASE_ADDR + ADSP_ISCS_OFFSET) +#define LSCS_ADDR (TTS_BASE_ADDR + ADSP_LSCS_OFFSET) +#define DWCCS_ADDR (TTS_BASE_ADDR + ADSP_DWCCS_OFFSET) +#define ARTCS_ADDR (TTS_BASE_ADDR + ADSP_ARTCS_OFFSET) +#define LWCCS_ADDR (TTS_BASE_ADDR + ADSP_LWCCS_OFFSET) + +/* Copies the bit-field specified by mask from src to dest */ +#define BITS_COPY(dest, src, mask) ((dest) = ((dest) & ~(mask)) | ((src) & (mask))) + +static struct k_spinlock lock; + +int intel_adsp_get_timestamp(uint32_t tsctrl, struct intel_adsp_timestamp *timestamp) +{ + uint32_t trigger_mask = ADSP_SHIM_TSCTRL_HHTSE | ADSP_SHIM_TSCTRL_ODTS; + uint32_t trigger_bits = tsctrl & trigger_mask; + uint32_t tsctrl_temp; + k_spinlock_key_t key; + int ret = 0; + + /* Exactly one trigger bit must be set in a valid request */ + if (POPCOUNT(trigger_bits) != 1) { + return -EINVAL; + } + + key = k_spin_lock(&lock); + + tsctrl_temp = sys_read32(TSCTRL_ADDR); + + /* Abort if any timestamp capture in progress */ + if (tsctrl_temp & trigger_mask) { + ret = -EBUSY; + goto out; + } + + /* Clear NTK (RW/1C) bit if needed */ + if (tsctrl_temp & ADSP_SHIM_TSCTRL_NTK) { + sys_write32(tsctrl_temp, TSCTRL_ADDR); + tsctrl_temp &= ~ADSP_SHIM_TSCTRL_NTK; + } + + /* Setup the timestamping logic according to request */ + BITS_COPY(tsctrl_temp, tsctrl, ADSP_SHIM_TSCTRL_IONTE); + BITS_COPY(tsctrl_temp, tsctrl, ADSP_SHIM_TSCTRL_DMATS); + BITS_COPY(tsctrl_temp, tsctrl, ADSP_SHIM_TSCTRL_CLNKS); + BITS_COPY(tsctrl_temp, tsctrl, ADSP_SHIM_TSCTRL_LWCS); + BITS_COPY(tsctrl_temp, tsctrl, ADSP_SHIM_TSCTRL_CDMAS); + sys_write32(tsctrl_temp, TSCTRL_ADDR); + + /* Start new timestamp capture by setting one of mutually exclusive + * trigger bits. + */ + tsctrl_temp |= trigger_bits; + sys_write32(tsctrl_temp, TSCTRL_ADDR); + + /* Wait for timestamp capture to complete */ + while (1) { + tsctrl_temp = sys_read32(TSCTRL_ADDR); + if (tsctrl_temp & ADSP_SHIM_TSCTRL_NTK) { + break; + } + } + + /* Copy the timestamp data from HW registers to the snapshot buffer + * provided by caller. As NTK bit is high at this stage, the timestamp + * data in HW is guaranteed to be valid and static. + */ + timestamp->iscs = sys_read32(ISCS_ADDR); + timestamp->lscs = sys_read64(LSCS_ADDR); + timestamp->dwccs = sys_read64(DWCCS_ADDR); + timestamp->artcs = sys_read64(ARTCS_ADDR); + timestamp->lwccs = sys_read32(LWCCS_ADDR); + + /* Clear NTK (RW/1C) bit */ + tsctrl_temp |= ADSP_SHIM_TSCTRL_NTK; + sys_write32(tsctrl_temp, TSCTRL_ADDR); + +out: + k_spin_unlock(&lock, key); + + return ret; +} From fb185fb5bd84efb9128ebceb671d051c711c2d71 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Krzysztof=20Chru=C5=9Bci=C5=84ski?= Date: Fri, 19 Jan 2024 10:59:10 +0100 Subject: [PATCH 2558/3723] drivers: serial: nrfx_uarte: Use legacy shim by default MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit New shim takes more flash and is causing some tests to overflow the ROM memory. Switching to the legacy shim as default until it is fixed. Signed-off-by: Krzysztof Chruściński --- drivers/serial/Kconfig.nrfx | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/drivers/serial/Kconfig.nrfx b/drivers/serial/Kconfig.nrfx index 5709ca2d23a..21a657fbaf4 100644 --- a/drivers/serial/Kconfig.nrfx +++ b/drivers/serial/Kconfig.nrfx @@ -31,9 +31,8 @@ config UART_NRFX_UARTE config UART_NRFX_UARTE_LEGACY_SHIM bool "Legacy UARTE shim" depends on UART_NRFX_UARTE - # New shim takes more ROM. Until it is fixed use legacy shim in memory - # constraint case. - default y if MCUBOOT + # New shim takes more ROM. Until it is fixed use legacy shim. + default y config UART_ASYNC_TX_CACHE_SIZE int "TX cache buffer size" From 3cdce5b1defdeacc35cfa59ddce76b895828db9b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Krzysztof=20Chru=C5=9Bci=C5=84ski?= Date: Fri, 19 Jan 2024 11:00:58 +0100 Subject: [PATCH 2559/3723] tests: drivers: uart: Adapt nrfx_uarte test configuration MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Adapt configuration after changing the default setting for CONFIG_UART_NRFX_UARTE_LEGACY_SHIM. Signed-off-by: Krzysztof Chruściński --- tests/drivers/uart/uart_async_api/testcase.yaml | 6 +++--- tests/drivers/uart/uart_mix_fifo_poll/testcase.yaml | 7 +++++++ 2 files changed, 10 insertions(+), 3 deletions(-) diff --git a/tests/drivers/uart/uart_async_api/testcase.yaml b/tests/drivers/uart/uart_async_api/testcase.yaml index 9e3e3913d1d..8d53d935412 100644 --- a/tests/drivers/uart/uart_async_api/testcase.yaml +++ b/tests/drivers/uart/uart_async_api/testcase.yaml @@ -13,7 +13,6 @@ tests: harness_config: fixture: gpio_loopback depends_on: gpio - tags: bsim_skip_CI drivers.uart.wide: filter: CONFIG_SERIAL_SUPPORT_ASYNC and not CONFIG_UART_MCUX_LPUART harness: ztest @@ -26,7 +25,7 @@ tests: platform_allow: nucleo_h743zi integration_platforms: - nucleo_h743zi - drivers.uart.async_api.nrf_uarte_legacy: + drivers.uart.async_api.nrf_uarte_new: platform_allow: nrf52840dk_nrf52840 nrf52_bsim filter: CONFIG_SERIAL_SUPPORT_ASYNC harness: ztest @@ -34,7 +33,8 @@ tests: fixture: gpio_loopback depends_on: gpio extra_configs: - - CONFIG_UART_NRFX_UARTE_LEGACY_SHIM=y + - CONFIG_UART_NRFX_UARTE_LEGACY_SHIM=n + tags: bsim_skip_CI drivers.uart.async_api.nrf_uart: filter: CONFIG_SERIAL_SUPPORT_ASYNC harness: ztest diff --git a/tests/drivers/uart/uart_mix_fifo_poll/testcase.yaml b/tests/drivers/uart/uart_mix_fifo_poll/testcase.yaml index 6652d45620a..ccfdd1aa717 100644 --- a/tests/drivers/uart/uart_mix_fifo_poll/testcase.yaml +++ b/tests/drivers/uart/uart_mix_fifo_poll/testcase.yaml @@ -19,6 +19,7 @@ tests: - CONFIG_UART_INTERRUPT_DRIVEN=n - CONFIG_UART_ASYNC_API=n - CONFIG_UART_0_ENHANCED_POLL_OUT=n + - CONFIG_UART_NRFX_UARTE_LEGACY_SHIM=n tags: bsim_skip_CI drivers.uart.uart_mix_poll_fifo: @@ -26,6 +27,7 @@ tests: - CONFIG_UART_INTERRUPT_DRIVEN=y - CONFIG_UART_0_INTERRUPT_DRIVEN=y - CONFIG_UART_0_ENHANCED_POLL_OUT=n + - CONFIG_UART_NRFX_UARTE_LEGACY_SHIM=n tags: bsim_skip_CI drivers.uart.uart_mix_poll_async_api: @@ -34,6 +36,7 @@ tests: - CONFIG_UART_0_INTERRUPT_DRIVEN=n - CONFIG_UART_0_ASYNC=y - CONFIG_UART_0_ENHANCED_POLL_OUT=n + - CONFIG_UART_NRFX_UARTE_LEGACY_SHIM=n tags: bsim_skip_CI drivers.uart.uart_mix_poll_async_api_const: @@ -44,6 +47,7 @@ tests: - CONFIG_UART_0_ASYNC=y - CONFIG_UART_0_ENHANCED_POLL_OUT=n - CONFIG_UART_0_TX_CACHE_SIZE=2 + - CONFIG_UART_NRFX_UARTE_LEGACY_SHIM=n tags: bsim_skip_CI # We skip a few tests to save CI time, as they give little extra coverage drivers.uart.uart_mix_poll_with_ppi: @@ -51,6 +55,7 @@ tests: - CONFIG_UART_INTERRUPT_DRIVEN=n - CONFIG_UART_ASYNC_API=n - CONFIG_UART_0_ENHANCED_POLL_OUT=y + - CONFIG_UART_NRFX_UARTE_LEGACY_SHIM=n tags: bsim_skip_CI drivers.uart.uart_mix_poll_fifo_with_ppi: @@ -58,6 +63,7 @@ tests: - CONFIG_UART_INTERRUPT_DRIVEN=y - CONFIG_UART_0_INTERRUPT_DRIVEN=y - CONFIG_UART_0_ENHANCED_POLL_OUT=y + - CONFIG_UART_NRFX_UARTE_LEGACY_SHIM=n tags: bsim_skip_CI drivers.uart.uart_mix_poll_async_api_with_ppi: @@ -66,6 +72,7 @@ tests: - CONFIG_UART_0_INTERRUPT_DRIVEN=n - CONFIG_UART_0_ASYNC=y - CONFIG_UART_0_ENHANCED_POLL_OUT=y + - CONFIG_UART_NRFX_UARTE_LEGACY_SHIM=n tags: bsim_skip_CI drivers.uart.legacy.uart_mix_poll: From bea34c599d22468fb1851149d6f451880330ead0 Mon Sep 17 00:00:00 2001 From: Balthazar Deliers Date: Tue, 16 Jan 2024 10:55:23 +0100 Subject: [PATCH 2560/3723] drivers: sensor: Aosong AGS10 TVOC sensor Added support for Aosong AGS10 TVOC sensor Signed-off-by: Balthazar Deliers --- drivers/sensor/CMakeLists.txt | 1 + drivers/sensor/Kconfig | 1 + drivers/sensor/ags10/CMakeLists.txt | 5 + drivers/sensor/ags10/Kconfig | 12 +++ drivers/sensor/ags10/ags10.c | 134 ++++++++++++++++++++++++ drivers/sensor/ags10/ags10.h | 46 ++++++++ dts/bindings/sensor/aosong,ags10.yaml | 10 ++ tests/drivers/build_all/sensor/i2c.dtsi | 5 + 8 files changed, 214 insertions(+) create mode 100644 drivers/sensor/ags10/CMakeLists.txt create mode 100644 drivers/sensor/ags10/Kconfig create mode 100644 drivers/sensor/ags10/ags10.c create mode 100644 drivers/sensor/ags10/ags10.h create mode 100644 dts/bindings/sensor/aosong,ags10.yaml diff --git a/drivers/sensor/CMakeLists.txt b/drivers/sensor/CMakeLists.txt index 915a13572e7..467f7a48094 100644 --- a/drivers/sensor/CMakeLists.txt +++ b/drivers/sensor/CMakeLists.txt @@ -9,6 +9,7 @@ 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_AGS10 ags10) add_subdirectory_ifdef(CONFIG_AK8975 ak8975) add_subdirectory_ifdef(CONFIG_AKM09918C akm09918c) add_subdirectory_ifdef(CONFIG_AMD_SB_TSI amd_sb_tsi) diff --git a/drivers/sensor/Kconfig b/drivers/sensor/Kconfig index f593ecd3213..36cf8075dbc 100644 --- a/drivers/sensor/Kconfig +++ b/drivers/sensor/Kconfig @@ -81,6 +81,7 @@ source "drivers/sensor/adxl345/Kconfig" source "drivers/sensor/adxl362/Kconfig" source "drivers/sensor/adxl367/Kconfig" source "drivers/sensor/adxl372/Kconfig" +source "drivers/sensor/ags10/Kconfig" source "drivers/sensor/ak8975/Kconfig" source "drivers/sensor/akm09918c/Kconfig" source "drivers/sensor/amd_sb_tsi/Kconfig" diff --git a/drivers/sensor/ags10/CMakeLists.txt b/drivers/sensor/ags10/CMakeLists.txt new file mode 100644 index 00000000000..bbc0a09038b --- /dev/null +++ b/drivers/sensor/ags10/CMakeLists.txt @@ -0,0 +1,5 @@ +# SPDX-License-Identifier: Apache-2.0 + + +zephyr_library() +zephyr_library_sources(ags10.c) diff --git a/drivers/sensor/ags10/Kconfig b/drivers/sensor/ags10/Kconfig new file mode 100644 index 00000000000..f406e29d3b7 --- /dev/null +++ b/drivers/sensor/ags10/Kconfig @@ -0,0 +1,12 @@ +# Copyright (c) 2023 Balthazar Deliers +# SPDX-License-Identifier: Apache-2.0 + +# AOSONG AGS10 TVOC sensor driver options. + +config AGS10 + bool "AOSONG AGS10 TVOC sensor" + default y + depends on DT_HAS_AOSONG_AGS10_ENABLED + select I2C + help + Enable AOSONG AGS10 TVOC sensor driver. diff --git a/drivers/sensor/ags10/ags10.c b/drivers/sensor/ags10/ags10.c new file mode 100644 index 00000000000..e5d761bfdf4 --- /dev/null +++ b/drivers/sensor/ags10/ags10.c @@ -0,0 +1,134 @@ +/* + * Copyright (c) 2023 Balthazar Deliers + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#define DT_DRV_COMPAT aosong_ags10 + +#include +#include +#include +#include +#include + +#include "ags10.h" + +LOG_MODULE_REGISTER(AGS10, CONFIG_SENSOR_LOG_LEVEL); + +#define AGS10_MAX_PAYLOAD_SIZE 5U /* Payload will be max 4 bytes + CRC (datasheet 3.1) */ + +static int ags10_read(const struct device *dev, uint8_t cmd, uint8_t *data, uint8_t rx_bytes) +{ + if (rx_bytes > AGS10_MAX_PAYLOAD_SIZE) { + return -EINVAL; + } + + const struct ags10_config *conf = dev->config; + + uint8_t recv_buf[AGS10_MAX_PAYLOAD_SIZE] = {0}; + int ret = i2c_write_read_dt(&conf->bus, &cmd, sizeof(cmd), &recv_buf, rx_bytes); + + if (ret < 0) { + return ret; + } + + memcpy(data, recv_buf, rx_bytes); + + return 0; +} + +static int ags10_sample_fetch(const struct device *dev, enum sensor_channel chan) +{ + if (chan != SENSOR_CHAN_VOC && chan != SENSOR_CHAN_ALL) { + return -ENOTSUP; + } + + struct ags10_data *data = dev->data; + int ret = -ENOTSUP; + uint8_t recv_buf[5] = {0}; + + ret = ags10_read(dev, AGS10_CMD_DATA_ACQUISITION, recv_buf, 5); + + if (ret == 0) { + /* If CRC is valid and data is valid too */ + if (crc8(&recv_buf[0], 4, 0x31, 0xFF, false) == recv_buf[4] && + ((recv_buf[0] & AGS10_MSK_STATUS) == AGS10_REG_STATUS_NRDY_READY)) { + data->status = recv_buf[0] & AGS10_MSK_STATUS; + data->tvoc_ppb = sys_get_be24(&recv_buf[1]); + return 0; + } + + LOG_WRN("Bad CRC or data not ready"); + ret = -EIO; + } + + return ret; +} + +static int ags10_channel_get(const struct device *dev, enum sensor_channel chan, + struct sensor_value *val) +{ + struct ags10_data *data = dev->data; + + if (chan == SENSOR_CHAN_VOC) { + val->val1 = data->tvoc_ppb; + } else { + return -ENOTSUP; + } + + val->val2 = 0; + + return 0; +} + +static int ags10_init(const struct device *dev) +{ + const struct ags10_config *conf = dev->config; + struct ags10_data *data = dev->data; + int ret; + + if (!i2c_is_ready_dt(&conf->bus)) { + LOG_ERR("Device not ready"); + return -ENODEV; + } + + /* Set initial data values */ + data->tvoc_ppb = 0; + data->status = 0xFF; + data->version = 0; + + /* Read firmware version and check CRC */ + uint8_t recv_buf[5] = {0}; + + ret = ags10_read(dev, AGS10_CMD_READ_VERSION, recv_buf, 5); + + /* Bytes 0 to 2 are reserved, byte 3 is version, byte 4 is CRC */ + if (ret == 0 && crc8(&recv_buf[0], 4, 0x31, 0xFF, false) == recv_buf[4]) { + data->version = recv_buf[3]; + LOG_DBG("Sensor detected"); + } else if (ret != 0) { + LOG_ERR("No reply from sensor"); + ret = -ENODEV; + } else { + LOG_WRN("Bad CRC"); + ret = -EIO; + } + + return ret; +} + +static const struct sensor_driver_api ags10_api = {.sample_fetch = ags10_sample_fetch, + .channel_get = ags10_channel_get}; + +#define AGS10_INIT(n) \ + static struct ags10_data ags10_data_##n; \ + \ + static const struct ags10_config ags10_config_##n = { \ + .bus = I2C_DT_SPEC_INST_GET(n), \ + }; \ + \ + SENSOR_DEVICE_DT_INST_DEFINE(n, ags10_init, NULL, &ags10_data_##n, &ags10_config_##n, \ + POST_KERNEL, CONFIG_SENSOR_INIT_PRIORITY, &ags10_api); + +DT_INST_FOREACH_STATUS_OKAY(AGS10_INIT) diff --git a/drivers/sensor/ags10/ags10.h b/drivers/sensor/ags10/ags10.h new file mode 100644 index 00000000000..d3f73ccd11b --- /dev/null +++ b/drivers/sensor/ags10/ags10.h @@ -0,0 +1,46 @@ +/* + * Copyright (c) 2023 Balthazar Deliers + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#ifndef ZEPHYR_INCLUDE_DRIVERS_SENSOR_AGS10_H_ +#define ZEPHYR_INCLUDE_DRIVERS_SENSOR_AGS10_H_ + +#ifdef __cplusplus +extern "C" { +#endif + +#include +#include + +#define AGS10_CMD_DATA_ACQUISITION 0x00 +#define AGS10_CMD_ZERO_POINT_CALIBRATION 0x01 +#define AGS10_CMD_READ_VERSION 0x11 +#define AGS10_CMD_READ_RESISTANCE 0x20 +#define AGS10_CMD_MODIFY_SLAVE_ADDRESS 0x21 + +#define AGS10_REG_ZERO_POINT_CALIBRATION_RESET 0xFFFF /* Reset to the factory value */ +#define AGS10_REG_ZERO_POINT_CALIBRATION_SET 0x0000 /* Set sensor resistance to zero-point */ +#define AGS10_REG_STATUS_NRDY_READY 0x00 /* Device is ready */ +#define AGS10_REG_STATUS_CH_PPB 0x00 /* Unit is PPB */ + +#define AGS10_MSK_STATUS 0x0F +#define AGS10_MSK_STATUS_NRDY 0x01 +#define AGS10_MSK_STATUS_CH 0x0E + +struct ags10_config { + struct i2c_dt_spec bus; +}; + +struct ags10_data { + uint32_t tvoc_ppb; + uint8_t status; + uint32_t version; +}; + +#ifdef __cplusplus +} +#endif + +#endif /* ZEPHYR_INCLUDE_DRIVERS_SENSOR_AGS10_H_ */ diff --git a/dts/bindings/sensor/aosong,ags10.yaml b/dts/bindings/sensor/aosong,ags10.yaml new file mode 100644 index 00000000000..fffd0f258fe --- /dev/null +++ b/dts/bindings/sensor/aosong,ags10.yaml @@ -0,0 +1,10 @@ +# Copyright (c) 2023 Balthazar Deliers +# SPDX-License-Identifier: Apache-2.0 + +description: | + AOSONG AGS10 a high-performance TVOC Sensor With I2C Interface. + See: http://www.aosong.com/en/products-86.html + +compatible: "aosong,ags10" + +include: [sensor-device.yaml, i2c-device.yaml] diff --git a/tests/drivers/build_all/sensor/i2c.dtsi b/tests/drivers/build_all/sensor/i2c.dtsi index aa5f6f3212b..7d684f42a37 100644 --- a/tests/drivers/build_all/sensor/i2c.dtsi +++ b/tests/drivers/build_all/sensor/i2c.dtsi @@ -884,3 +884,8 @@ test_i2c_bma4xx: bma4xx@7d { compatible = "bosch,bma4xx"; reg = <0x7d>; }; + +test_i2c_ags10: ags10@7e { + compatible = "aosong,ags10"; + reg = <0x7e>; +}; From e11bbb829f165bd05b58a58f84be35438c658058 Mon Sep 17 00:00:00 2001 From: Fabio Baltieri Date: Wed, 17 Jan 2024 23:18:11 +0000 Subject: [PATCH 2561/3723] input: longpress: move constant entries pointer to the config struct The entries pointer does not change, no need to have it in RAM, 4 bytes saved. Refactor the init macro a bit while at it. Signed-off-by: Fabio Baltieri --- subsys/input/input_longpress.c | 32 +++++++++++++++----------------- 1 file changed, 15 insertions(+), 17 deletions(-) diff --git a/subsys/input/input_longpress.c b/subsys/input/input_longpress.c index 5e0b6f0ac9f..b7ce3c7c8d6 100644 --- a/subsys/input/input_longpress.c +++ b/subsys/input/input_longpress.c @@ -15,6 +15,7 @@ LOG_MODULE_REGISTER(input_longpress, CONFIG_INPUT_LOG_LEVEL); struct longpress_config { const struct device *input_dev; + struct longpress_data_entry *entries; const uint16_t *input_codes; const uint16_t *short_codes; const uint16_t *long_codes; @@ -29,11 +30,6 @@ struct longpress_data_entry { bool long_fired; }; -struct longpress_data { - /* support data for every input code */ - struct longpress_data_entry *entries; -}; - static void longpress_deferred(struct k_work *work) { struct k_work_delayable *dwork = k_work_delayable_from_work(work); @@ -53,7 +49,6 @@ static void longpress_deferred(struct k_work *work) static void longpress_cb(const struct device *dev, struct input_event *evt) { const struct longpress_config *cfg = dev->config; - struct longpress_data *data = dev->data; struct longpress_data_entry *entry; int i; @@ -71,7 +66,7 @@ static void longpress_cb(const struct device *dev, struct input_event *evt) return; } - entry = &data->entries[i]; + entry = &cfg->entries[i]; if (evt->value) { entry->long_fired = false; @@ -90,7 +85,6 @@ static void longpress_cb(const struct device *dev, struct input_event *evt) static int longpress_init(const struct device *dev) { const struct longpress_config *cfg = dev->config; - struct longpress_data *data = dev->data; if (cfg->input_dev && !device_is_ready(cfg->input_dev)) { LOG_ERR("input device not ready"); @@ -98,7 +92,7 @@ static int longpress_init(const struct device *dev) } for (int i = 0; i < cfg->num_codes; i++) { - struct longpress_data_entry *entry = &data->entries[i]; + struct longpress_data_entry *entry = &cfg->entries[i]; entry->dev = dev; entry->index = i; @@ -112,21 +106,29 @@ static int longpress_init(const struct device *dev) BUILD_ASSERT((DT_INST_PROP_LEN(inst, input_codes) == \ DT_INST_PROP_LEN_OR(inst, short_codes, 0)) || \ !DT_INST_NODE_HAS_PROP(inst, short_codes)); \ - BUILD_ASSERT(DT_INST_PROP_LEN(inst, input_codes) == \ - DT_INST_PROP_LEN(inst, long_codes)); \ + BUILD_ASSERT(DT_INST_PROP_LEN(inst, input_codes) == DT_INST_PROP_LEN(inst, long_codes)); \ + \ static void longpress_cb_##inst(struct input_event *evt) \ { \ longpress_cb(DEVICE_DT_INST_GET(inst), evt); \ } \ INPUT_CALLBACK_DEFINE(DEVICE_DT_GET_OR_NULL(DT_INST_PHANDLE(inst, input)), \ longpress_cb_##inst); \ + \ static const uint16_t longpress_input_codes_##inst[] = DT_INST_PROP(inst, input_codes); \ + \ IF_ENABLED(DT_INST_NODE_HAS_PROP(inst, short_codes), ( \ static const uint16_t longpress_short_codes_##inst[] = DT_INST_PROP(inst, short_codes); \ )); \ + \ static const uint16_t longpress_long_codes_##inst[] = DT_INST_PROP(inst, long_codes); \ + \ + static struct longpress_data_entry longpress_data_entries_##inst[DT_INST_PROP_LEN( \ + inst, input_codes)]; \ + \ static const struct longpress_config longpress_config_##inst = { \ .input_dev = DEVICE_DT_GET_OR_NULL(DT_INST_PHANDLE(inst, input)), \ + .entries = longpress_data_entries_##inst, \ .input_codes = longpress_input_codes_##inst, \ IF_ENABLED(DT_INST_NODE_HAS_PROP(inst, short_codes), ( \ .short_codes = longpress_short_codes_##inst, \ @@ -135,13 +137,9 @@ static int longpress_init(const struct device *dev) .num_codes = DT_INST_PROP_LEN(inst, input_codes), \ .long_delays_ms = DT_INST_PROP(inst, long_delay_ms), \ }; \ - static struct longpress_data_entry longpress_data_entries_##inst[DT_INST_PROP_LEN( \ - inst, input_codes)]; \ - static struct longpress_data longpress_data_##inst = { \ - .entries = longpress_data_entries_##inst, \ - }; \ + \ DEVICE_DT_INST_DEFINE(inst, longpress_init, NULL, \ - &longpress_data_##inst, &longpress_config_##inst, \ + NULL, &longpress_config_##inst, \ POST_KERNEL, CONFIG_INPUT_INIT_PRIORITY, NULL); DT_INST_FOREACH_STATUS_OKAY(INPUT_LONGPRESS_DEFINE) From b9d4b9d9aba0489cd31b687afd9f7a7883230d78 Mon Sep 17 00:00:00 2001 From: Flavio Ceolin Date: Fri, 18 Aug 2023 05:09:12 +0000 Subject: [PATCH 2562/3723] pm: Remove CURRENT_CPU macro Just use _current_cpu that works with/without multicore. Signed-off-by: Flavio Ceolin --- subsys/pm/pm.c | 7 ++----- 1 file changed, 2 insertions(+), 5 deletions(-) diff --git a/subsys/pm/pm.c b/subsys/pm/pm.c index 07c197e246f..2982324441e 100644 --- a/subsys/pm/pm.c +++ b/subsys/pm/pm.c @@ -22,9 +22,6 @@ #include LOG_MODULE_REGISTER(pm, CONFIG_PM_LOG_LEVEL); -#define CURRENT_CPU \ - (COND_CODE_1(CONFIG_SMP, (arch_curr_cpu()->id), (_current_cpu->id))) - static ATOMIC_DEFINE(z_post_ops_required, CONFIG_MP_MAX_NUM_CPUS); static sys_slist_t pm_notifiers = SYS_SLIST_STATIC_INIT(&pm_notifiers); @@ -133,7 +130,7 @@ static inline void pm_state_notify(bool entering_state) void pm_system_resume(void) { - uint8_t id = CURRENT_CPU; + uint8_t id = _current_cpu->id; /* * This notification is called from the ISR of the event @@ -171,7 +168,7 @@ bool pm_state_force(uint8_t cpu, const struct pm_state_info *info) bool pm_system_suspend(int32_t ticks) { - uint8_t id = CURRENT_CPU; + uint8_t id = _current_cpu->id; k_spinlock_key_t key; SYS_PORT_TRACING_FUNC_ENTER(pm, system_suspend, ticks); From 2590ea280c36bc3746d8ac6f239ffab1bc16894e Mon Sep 17 00:00:00 2001 From: Flavio Ceolin Date: Wed, 17 Jan 2024 14:52:16 -0800 Subject: [PATCH 2563/3723] xtensa: mmu: Optimize autorefill invalidation There is no need to sync in every xtlb invalidation. Sync only after all tlb autofill ways invalidation. Signed-off-by: Flavio Ceolin --- arch/xtensa/include/xtensa_mmu_priv.h | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/arch/xtensa/include/xtensa_mmu_priv.h b/arch/xtensa/include/xtensa_mmu_priv.h index b6434e8ff0c..631760f03cb 100644 --- a/arch/xtensa/include/xtensa_mmu_priv.h +++ b/arch/xtensa/include/xtensa_mmu_priv.h @@ -339,10 +339,11 @@ static inline void xtensa_tlb_autorefill_invalidate(void) for (i = 0; i < entries; i++) { uint32_t entry = way + (i << XTENSA_MMU_PTE_PPN_SHIFT); - xtensa_dtlb_entry_invalidate_sync(entry); - xtensa_itlb_entry_invalidate_sync(entry); + xtensa_dtlb_entry_invalidate(entry); + xtensa_itlb_entry_invalidate(entry); } } + __asm__ volatile("isync"); } /** From e56c89eb0cfa31c78e64824638f809cf9d09da1f Mon Sep 17 00:00:00 2001 From: "Mike J. Chen" Date: Tue, 9 Jan 2024 18:14:02 -0800 Subject: [PATCH 2564/3723] sensor_shell: add CONFIG to support trigger for more than one sensor device Before, only one sensor device was supported. It was possible to set a trigger on a second sensor device, but the filtering of the channel data would cause no channels from the new sensor device to be read. Also in trigger handler log of sampled data, print the sensor name and channe name (instead of channel number). Signed-off-by: Mike J. Chen --- drivers/sensor/Kconfig | 8 +++ drivers/sensor/sensor_shell.c | 107 +++++++++++++++++++++++++++------- 2 files changed, 94 insertions(+), 21 deletions(-) diff --git a/drivers/sensor/Kconfig b/drivers/sensor/Kconfig index 36cf8075dbc..d135df369b9 100644 --- a/drivers/sensor/Kconfig +++ b/drivers/sensor/Kconfig @@ -68,6 +68,14 @@ config SENSOR_SHELL_TRIG_PRINT_TIMEOUT_MS Control the frequency of the sampling window over which the sensor interrupt handler will collect data. +config SENSOR_SHELL_MAX_TRIGGER_DEVICES + int "Maximum number of sensor devices that can have enabled triggers in shell" + default 1 + depends on SENSOR_SHELL + help + Maximum number of sensor devices that the shell cmd can have + enabled triggers for. + config SENSOR_INFO bool "Sensor Info iterable section" diff --git a/drivers/sensor/sensor_shell.c b/drivers/sensor/sensor_shell.c index bfeac4e452f..b0485b8378a 100644 --- a/drivers/sensor/sensor_shell.c +++ b/drivers/sensor/sensor_shell.c @@ -45,7 +45,7 @@ LOG_MODULE_REGISTER(sensor_shell); "Get or set the trigger type on a sensor. Currently only supports `data_ready`.\n" \ " " -const char *sensor_channel_name[SENSOR_CHAN_COMMON_COUNT] = { +static const char *sensor_channel_name[SENSOR_CHAN_COMMON_COUNT] = { [SENSOR_CHAN_ACCEL_X] = "accel_x", [SENSOR_CHAN_ACCEL_Y] = "accel_y", [SENSOR_CHAN_ACCEL_Z] = "accel_z", @@ -125,6 +125,33 @@ static const char *sensor_attribute_name[SENSOR_ATTR_COMMON_COUNT] = { [SENSOR_ATTR_BATCH_DURATION] = "batch_dur", }; +enum sample_stats_state { + SAMPLE_STATS_STATE_UNINITIALIZED = 0, + SAMPLE_STATS_STATE_ENABLED, + SAMPLE_STATS_STATE_DISABLED, +}; + +struct sample_stats { + int64_t accumulator; + uint64_t sample_window_start; + uint32_t count; + enum sample_stats_state state; +}; + +static struct sample_stats sensor_stats[CONFIG_SENSOR_SHELL_MAX_TRIGGER_DEVICES][SENSOR_CHAN_ALL]; + +static const struct device *sensor_trigger_devices[CONFIG_SENSOR_SHELL_MAX_TRIGGER_DEVICES]; + +static int find_sensor_trigger_device(const struct device *sensor) +{ + for (int i = 0; i < CONFIG_SENSOR_SHELL_MAX_TRIGGER_DEVICES; i++) { + if (sensor_trigger_devices[i] == sensor) { + return i; + } + } + return -1; +} + /* Forward declaration */ static void data_ready_trigger_handler(const struct device *sensor, const struct sensor_trigger *trigger); @@ -882,25 +909,27 @@ static int cmd_get_sensor_info(const struct shell *sh, size_t argc, char **argv) #endif } -enum sample_stats_state { - SAMPLE_STATS_STATE_UNINITIALIZED = 0, - SAMPLE_STATS_STATE_ENABLED, - SAMPLE_STATS_STATE_DISABLED, -}; - -struct sample_stats { - int64_t accumulator; - uint32_t count; - uint64_t sample_window_start; - enum sample_stats_state state; -}; - static void data_ready_trigger_handler(const struct device *sensor, const struct sensor_trigger *trigger) { - static struct sample_stats stats[SENSOR_CHAN_ALL]; const int64_t now = k_uptime_get(); struct sensor_value value; + int sensor_idx = find_sensor_trigger_device(sensor); + struct sample_stats *stats; + int sensor_name_len_before_at; + const char *sensor_name; + + if (sensor_idx < 0) { + LOG_ERR("Unable to find sensor trigger device"); + return; + } + stats = sensor_stats[sensor_idx]; + sensor_name = sensor_trigger_devices[sensor_idx]->name; + if (sensor_name) { + sensor_name_len_before_at = strchr(sensor_name, '@') - sensor_name; + } else { + sensor_name_len_before_at = 0; + } if (sensor_sample_fetch(sensor)) { LOG_ERR("Failed to fetch samples on data ready handler"); @@ -919,9 +948,16 @@ static void data_ready_trigger_handler(const struct device *sensor, } rc = sensor_channel_get(sensor, i, &value); - if (rc == -ENOTSUP && stats[i].state == SAMPLE_STATS_STATE_UNINITIALIZED) { - /* Stop reading this channel if the driver told us it's not supported. */ - stats[i].state = SAMPLE_STATS_STATE_DISABLED; + if (stats[i].state == SAMPLE_STATS_STATE_UNINITIALIZED) { + if (rc == -ENOTSUP) { + /* + * Stop reading this channel if the driver told us + * it's not supported. + */ + stats[i].state = SAMPLE_STATS_STATE_DISABLED; + } else if (rc == 0) { + stats[i].state = SAMPLE_STATS_STATE_ENABLED; + } } if (rc != 0) { /* Skip on any error. */ @@ -937,7 +973,10 @@ static void data_ready_trigger_handler(const struct device *sensor, value.val1 = micro_value / 1000000; value.val2 = (int32_t)llabs(micro_value - (value.val1 * 1000000)); - LOG_INF("chan=%d, num_samples=%u, data=%d.%06d", i, stats[i].count, + LOG_INF("sensor=%.*s, chan=%s, num_samples=%u, data=%d.%06d", + sensor_name_len_before_at, sensor_name, + sensor_channel_name[i], + stats[i].count, value.val1, value.val2); stats[i].accumulator = 0; @@ -973,11 +1012,37 @@ static int cmd_trig_sensor(const struct shell *sh, size_t argc, char **argv) /* Parse on/off */ if (strcmp(argv[2], "on") == 0) { - err = sensor_trigger_set(dev, &sensor_trigger_table[trigger].trigger, - sensor_trigger_table[trigger].handler); + /* find a free entry in sensor_trigger_devices[] */ + int sensor_idx = find_sensor_trigger_device(NULL); + + if (sensor_idx < 0) { + shell_error(sh, "Unable to support more simultaneous sensor trigger" + " devices"); + err = -ENOTSUP; + } else { + struct sample_stats *stats = sensor_stats[sensor_idx]; + + sensor_trigger_devices[sensor_idx] = dev; + /* reset stats state to UNINITIALIZED */ + for (unsigned int ch = 0; ch < SENSOR_CHAN_ALL; ch++) { + stats[ch].state = SAMPLE_STATS_STATE_UNINITIALIZED; + } + err = sensor_trigger_set(dev, &sensor_trigger_table[trigger].trigger, + sensor_trigger_table[trigger].handler); + } } else if (strcmp(argv[2], "off") == 0) { /* Clear the handler for the given trigger on this device */ err = sensor_trigger_set(dev, &sensor_trigger_table[trigger].trigger, NULL); + if (!err) { + /* find entry in sensor_trigger_devices[] and free it */ + int sensor_idx = find_sensor_trigger_device(dev); + + if (sensor_idx < 0) { + shell_error(sh, "Unable to find sensor device in trigger array"); + } else { + sensor_trigger_devices[sensor_idx] = NULL; + } + } } else { shell_error(sh, "Pass 'on' or 'off' to enable/disable trigger"); return -EINVAL; From 923d4fbad864a10fe2814c9ede3d454a7bd58e3b Mon Sep 17 00:00:00 2001 From: Alberto Escolar Piedras Date: Wed, 17 Jan 2024 09:19:14 +0100 Subject: [PATCH 2565/3723] boards nrf*_bsim: Detect attemtp to configure not existing int Prevent overrunning the irq vector table. This is not happening today in tree, but coverity thinks it does. Checking for it to prevent it is not a bad idea anyhow, so let's do it. Signed-off-by: Alberto Escolar Piedras --- boards/posix/nrf_bsim/irq_handler.c | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/boards/posix/nrf_bsim/irq_handler.c b/boards/posix/nrf_bsim/irq_handler.c index 5e2a79d7645..2d6ad4f66b7 100644 --- a/boards/posix/nrf_bsim/irq_handler.c +++ b/boards/posix/nrf_bsim/irq_handler.c @@ -258,6 +258,11 @@ int posix_get_current_irq(void) void posix_isr_declare(unsigned int irq_p, int flags, void isr_p(const void *), const void *isr_param_p) { + if (irq_p >= NHW_INTCTRL_MAX_INTLINES) { + bs_trace_error_time_line("Attempted to configure not existent interrupt %u\n", + irq_p); + return; + } irq_vector_table[irq_p].irq = irq_p; irq_vector_table[irq_p].func = isr_p; irq_vector_table[irq_p].param = isr_param_p; From e770128c20d384e973106d3800c939349895f944 Mon Sep 17 00:00:00 2001 From: Alberto Escolar Piedras Date: Wed, 17 Jan 2024 09:21:02 +0100 Subject: [PATCH 2566/3723] boards native_sim: Detect attemtp to configure not existing int Prevent overrunning the irq vector table. This is not happening today in tree, but coverity thinks it may. Checking for it to prevent it is not a bad idea anyhow, so let's do it. Signed-off-by: Alberto Escolar Piedras --- boards/posix/native_sim/irq_handler.c | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/boards/posix/native_sim/irq_handler.c b/boards/posix/native_sim/irq_handler.c index 899a4b7139c..38462b4b14a 100644 --- a/boards/posix/native_sim/irq_handler.c +++ b/boards/posix/native_sim/irq_handler.c @@ -236,6 +236,11 @@ int posix_get_current_irq(void) void posix_isr_declare(unsigned int irq_p, int flags, void isr_p(const void *), const void *isr_param_p) { + if (irq_p >= N_IRQS) { + posix_print_error_and_exit("Attempted to configure not existent interrupt %u\n", + irq_p); + return; + } irq_vector_table[irq_p].irq = irq_p; irq_vector_table[irq_p].func = isr_p; irq_vector_table[irq_p].param = isr_param_p; From 8f9a86cf5e19d466a2a13a2f34ee35230f17cfc4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?J=C4=99drzej=20Ciupis?= Date: Thu, 18 Jan 2024 11:34:34 +0100 Subject: [PATCH 2567/3723] drivers: ieee802154: fix nRF5 Rx error handling MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The current implementation implicitly assumes that if the device is configured to have the capability of acting as a CSL endpoint then in case a delayed reception with matching ID finishes with a timeout no action is needed. This assumption is correct when RxOnWhenIdle mode is disabled because the transition to sleep is done automatically by the driver below. However, it's wrong when RxOnWhenIdle is enabled. This commit fixes that case by adding a call to event handler that notifies the higher layer about the event and allows it to transition to RxOff if needed. Signed-off-by: Jędrzej Ciupis --- drivers/ieee802154/ieee802154_nrf5.c | 10 +++++++++- drivers/ieee802154/ieee802154_nrf5.h | 3 +++ 2 files changed, 12 insertions(+), 1 deletion(-) diff --git a/drivers/ieee802154/ieee802154_nrf5.c b/drivers/ieee802154/ieee802154_nrf5.c index 108bcd2e14a..715fa665df2 100644 --- a/drivers/ieee802154/ieee802154_nrf5.c +++ b/drivers/ieee802154/ieee802154_nrf5.c @@ -763,6 +763,7 @@ static int nrf5_init(const struct device *dev) nrf5_get_capabilities_at_boot(); + nrf5_radio->rx_on_when_idle = true; nrf5_radio_cfg->irq_config_func(dev); k_thread_create(&nrf5_radio->rx_thread, nrf5_radio->rx_stack, @@ -990,6 +991,7 @@ static int nrf5_configure(const struct device *dev, case IEEE802154_CONFIG_RX_ON_WHEN_IDLE: nrf_802154_rx_on_when_idle_set(config->rx_on_when_idle); + nrf5_data.rx_on_when_idle = config->rx_on_when_idle; break; default: @@ -1070,7 +1072,13 @@ void nrf_802154_receive_failed(nrf_802154_rx_error_t error, uint32_t id) #if defined(CONFIG_IEEE802154_CSL_ENDPOINT) if (id == DRX_SLOT_RX && error == NRF_802154_RX_ERROR_DELAYED_TIMEOUT) { - return; + if (!nrf5_data.rx_on_when_idle) { + /* Transition to RxOff done automatically by the driver */ + return; + } else if (nrf5_data.event_handler) { + /* Notify the higher layer to allow it to transition if needed */ + nrf5_data.event_handler(dev, IEEE802154_EVENT_RX_OFF, NULL); + } } #else ARG_UNUSED(id); diff --git a/drivers/ieee802154/ieee802154_nrf5.h b/drivers/ieee802154/ieee802154_nrf5.h index b9f46dff307..0d4d9c9accf 100644 --- a/drivers/ieee802154/ieee802154_nrf5.h +++ b/drivers/ieee802154/ieee802154_nrf5.h @@ -110,6 +110,9 @@ struct nrf5_802154_data { /* The last configured value of CSL phase time in nanoseconds. */ net_time_t csl_rx_time; #endif /* CONFIG_NRF_802154_SER_HOST && CONFIG_IEEE802154_CSL_ENDPOINT */ + + /* Indicates if RxOnWhenIdle mode is enabled. */ + bool rx_on_when_idle; }; #endif /* ZEPHYR_DRIVERS_IEEE802154_IEEE802154_NRF5_H_ */ From d019474766c1f4143db22a960e86c8ecd22c1961 Mon Sep 17 00:00:00 2001 From: Jonathan Rico Date: Thu, 18 Jan 2024 14:36:05 +0100 Subject: [PATCH 2568/3723] MAINTAINERS: Add Bluetooth Classic section This is the "legacy" Bluetooth protocol. lylezhu2012 (NXP) recently volunteered to maintain it. Signed-off-by: Jonathan Rico --- MAINTAINERS.yml | 22 ++++++++++++++++++++++ 1 file changed, 22 insertions(+) diff --git a/MAINTAINERS.yml b/MAINTAINERS.yml index a571bb9bde2..8954bbad735 100644 --- a/MAINTAINERS.yml +++ b/MAINTAINERS.yml @@ -421,6 +421,28 @@ Bluetooth Audio: tests: - bluetooth.audio +Bluetooth Classic: + status: maintained + maintainers: + - lylezhu2012 + collaborators: + - jhedberg + - sjanc + files: + - subsys/bluetooth/host/a2dp* + - subsys/bluetooth/host/at.* + - subsys/bluetooth/host/avdtp* + - subsys/bluetooth/host/br.* + - subsys/bluetooth/host/hfp* + - subsys/bluetooth/host/l2cap_br* + - subsys/bluetooth/host/rfcomm* + - subsys/bluetooth/host/sdp* + - subsys/bluetooth/host/ssp* + labels: + - "area: Bluetooth Classic" + tests: + - bluetooth + Bootloaders: status: odd fixes files: From 2e91d01c8055ff17b8788475806c16abc1851f69 Mon Sep 17 00:00:00 2001 From: Ioannis Karachalios Date: Wed, 20 Dec 2023 14:49:48 +0200 Subject: [PATCH 2569/3723] Renesas: Smartbond: HAL bugfixes Update west.yaml Signed-off-by: Ioannis Karachalios --- west.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/west.yml b/west.yml index ca9b67d9bfa..1dded6a5923 100644 --- a/west.yml +++ b/west.yml @@ -210,7 +210,7 @@ manifest: - hal - name: hal_renesas path: modules/hal/renesas - revision: 1471ed3cbf501434a5f3df2f9df520c3bd8e0258 + revision: 0b1f2fdb99d6386f125a8dba72083e3c56aecc2b groups: - hal - name: hal_rpi_pico From 68316ace22f87520bf0130b6e09a37c3ae78a173 Mon Sep 17 00:00:00 2001 From: Jonathan Rico Date: Thu, 11 Jan 2024 18:07:48 +0100 Subject: [PATCH 2570/3723] Bluetooth: L2CAP: remove `l2cap_chan_create_seg()` Remove the logic for adding the SDU length when allocating segments. That section was dead code after the recent patches. Inline the remainder of the logic into `l2cap_chan_le_send()`. Signed-off-by: Jonathan Rico --- subsys/bluetooth/host/l2cap.c | 95 ++++++++++++----------------------- 1 file changed, 33 insertions(+), 62 deletions(-) diff --git a/subsys/bluetooth/host/l2cap.c b/subsys/bluetooth/host/l2cap.c index e9a6e744c5e..5732f2615a3 100644 --- a/subsys/bluetooth/host/l2cap.c +++ b/subsys/bluetooth/host/l2cap.c @@ -935,7 +935,11 @@ static void l2cap_chan_tx_process(struct k_work *work) /* Resume tx in case there are buffers in the queue */ while ((buf = l2cap_chan_le_get_tx_buf(ch))) { - LOG_DBG("buf %p", buf); + /* Here buf is either: + * - a partially-sent SDU le_chan->tx_buf + * - a new SDU from the TX queue + */ + LOG_DBG("chan %p buf %p", ch, buf); ret = l2cap_chan_le_send_sdu(ch, &buf); if (ret < 0) { @@ -947,6 +951,7 @@ static void l2cap_chan_tx_process(struct k_work *work) */ k_work_schedule(&ch->tx_work, K_MSEC(CONFIG_BT_L2CAP_RESCHED_MS)); } else { + LOG_WRN("Failed to send (err %d), dropping buf %p", ret, buf); l2cap_tx_buf_destroy(ch->chan.conn, buf, ret); } break; @@ -1814,7 +1819,7 @@ static void le_disconn_rsp(struct bt_l2cap *l2cap, uint8_t ident, bt_l2cap_chan_del(&chan->chan); } -static inline struct net_buf *l2cap_alloc_seg(struct net_buf *buf, struct bt_l2cap_le_chan *ch) +static struct net_buf *l2cap_alloc_seg(struct bt_l2cap_le_chan *ch) { struct net_buf *seg = NULL; @@ -1836,60 +1841,6 @@ static inline struct net_buf *l2cap_alloc_seg(struct net_buf *buf, struct bt_l2c return seg; } -static struct net_buf *l2cap_chan_create_seg(struct bt_l2cap_le_chan *ch, - struct net_buf *buf, - size_t sdu_hdr_len) -{ - struct net_buf *seg; - uint16_t headroom; - uint16_t len; - - /* Segment if data (+ data headroom) is bigger than MPS */ - if (buf->len + sdu_hdr_len > ch->tx.mps) { - goto segment; - } - - headroom = BT_L2CAP_CHAN_SEND_RESERVE + sdu_hdr_len; - - /* Check if original buffer has enough headroom and don't have any - * fragments. - */ - if (net_buf_headroom(buf) >= headroom && !buf->frags) { - if (sdu_hdr_len) { - /* Push SDU length if set */ - net_buf_push_le16(buf, net_buf_frags_len(buf)); - } - return net_buf_ref(buf); - } else { - /* Unnecessary fragmentation. Ensure the source buffer has - * BT_L2CAP_SDU_BUF_SIZE(0) headroom. - */ - LOG_DBG("not enough headroom on %p", buf); - } - -segment: - seg = l2cap_alloc_seg(buf, ch); - - if (!seg) { - return NULL; - } - - if (sdu_hdr_len) { - net_buf_add_le16(seg, net_buf_frags_len(buf)); - } - - /* Don't send more that TX MPS including SDU length */ - len = MIN(net_buf_tailroom(seg), ch->tx.mps - sdu_hdr_len); - /* Limit if original buffer is smaller than the segment */ - len = MIN(buf->len, len); - net_buf_add_mem(seg, buf->data, len); - net_buf_pull(buf, len); - - LOG_DBG("ch %p seg %p len %u", ch, seg, seg->len); - - return seg; -} - static void l2cap_chan_tx_resume(struct bt_l2cap_le_chan *ch) { if (!atomic_get(&ch->tx.credits) || @@ -2002,10 +1953,29 @@ static int l2cap_chan_le_send(struct bt_l2cap_le_chan *ch, /* Save state so it can be restored if we failed to send */ net_buf_simple_save(&buf->b, &state); - seg = l2cap_chan_create_seg(ch, buf, sdu_hdr_len); - if (!seg) { - atomic_inc(&ch->tx.credits); - return -EAGAIN; + if (net_buf_frags_len(buf) <= ch->tx.mps) { + LOG_DBG("len <= MPS, not allocating seg for %p", buf); + seg = net_buf_ref(buf); + + len = seg->len; + } else { + LOG_DBG("allocating segment for %p (%u bytes left)", buf, buf->len); + seg = l2cap_alloc_seg(ch); + if (!seg) { + LOG_DBG("failed to allocate seg for %p", buf); + atomic_inc(&ch->tx.credits); + + return -EAGAIN; + } + + /* Don't send more than TX MPS */ + len = MIN(net_buf_tailroom(seg), ch->tx.mps); + + /* Limit if original buffer is smaller than the segment */ + len = MIN(buf->len, len); + + net_buf_add_mem(seg, buf->data, len); + net_buf_pull(buf, len); } LOG_DBG("ch %p cid 0x%04x len %u credits %lu", ch, ch->tx.cid, seg->len, @@ -2030,9 +2000,10 @@ static int l2cap_chan_le_send(struct bt_l2cap_le_chan *ch, /* The host takes ownership of the reference in seg when * bt_l2cap_send_cb is successful. The call returned an error, - * so we must get rid of the reference that was taken in - * l2cap_chan_create_seg. + * so we must get rid of the reference that was taken above. */ + LOG_DBG("unref %p (%s)", seg, + buf == seg ? "orig" : "seg"); net_buf_unref(seg); if (err == -ENOBUFS) { From 6852abf521ba3a56c2aa9fa21040d9341adb84bd Mon Sep 17 00:00:00 2001 From: Kamil Piszczek Date: Fri, 12 Jan 2024 11:30:21 +0100 Subject: [PATCH 2571/3723] bluetooth: gatt: add authorization callback API for gatt operations Added the GATT authorization callback API that allows the user to define application-specific authorization logic for GATT operations. Signed-off-by: Kamil Piszczek --- include/zephyr/bluetooth/gatt.h | 51 ++++++++++++++++++ subsys/bluetooth/host/Kconfig.gatt | 9 ++++ subsys/bluetooth/host/att.c | 83 ++++++++++++++++++++++++++++++ 3 files changed, 143 insertions(+) diff --git a/include/zephyr/bluetooth/gatt.h b/include/zephyr/bluetooth/gatt.h index 2cbe96a7285..585387a02aa 100644 --- a/include/zephyr/bluetooth/gatt.h +++ b/include/zephyr/bluetooth/gatt.h @@ -235,6 +235,37 @@ struct bt_gatt_cb { sys_snode_t node; }; +/** @brief GATT authorization callback structure. */ +struct bt_gatt_authorization_cb { + /** @brief Authorize the GATT read operation. + * + * This callback allows the application to authorize the GATT + * read operation for the attribute that is being read. + * + * @param conn Connection object. + * @param attr The attribute that is being read. + * + * @retval true Authorize the operation and allow it to execute. + * @retval false Reject the operation and prevent it from executing. + */ + bool (*read_operation_authorize)(struct bt_conn *conn, + const struct bt_gatt_attr *attr); + + /** @brief Authorize the GATT write operation. + * + * This callback allows the application to authorize the GATT + * write operation for the attribute that is being written. + * + * @param conn Connection object. + * @param attr The attribute that is being written. + * + * @retval true Authorize the operation and allow it to execute. + * @retval false Reject the operation and prevent it from executing. + */ + bool (*write_operation_authorize)(struct bt_conn *conn, + const struct bt_gatt_attr *attr); +}; + /** Characteristic Properties Bit field values */ /** @@ -377,6 +408,26 @@ struct bt_gatt_cpf { */ void bt_gatt_cb_register(struct bt_gatt_cb *cb); +/** @brief Register GATT authorization callbacks. + * + * Register callbacks to perform application-specific authorization of GATT + * operations on all registered GATT attributes. The callback structure must + * remain valid throughout the entire duration of the Bluetooth subsys + * activity. + * + * The @kconfig{CONFIG_BT_GATT_AUTHORIZATION_CUSTOM} Kconfig must be enabled + * to make this API functional. + * + * This API allows the user to register only one callback structure + * concurrently. Passing NULL unregisters the previous set of callbacks + * and makes it possible to register a new one. + * + * @param cb Callback struct. + * + * @return Zero on success or negative error code otherwise + */ +int bt_gatt_authorization_cb_register(const struct bt_gatt_authorization_cb *cb); + /** @brief Register GATT service. * * Register GATT service. Applications can make use of diff --git a/subsys/bluetooth/host/Kconfig.gatt b/subsys/bluetooth/host/Kconfig.gatt index 066cc56df58..310442423b9 100644 --- a/subsys/bluetooth/host/Kconfig.gatt +++ b/subsys/bluetooth/host/Kconfig.gatt @@ -274,4 +274,13 @@ config DEVICE_NAME_GATT_WRITABLE_AUTHEN endif #BT_DEVICE_NAME_GATT_WRITABLE +config BT_GATT_AUTHORIZATION_CUSTOM + bool "Custom authorization of GATT operations [EXPERIMENTAL]" + select EXPERIMENTAL + help + This option allows the user to define application-specific + authorization logic for GATT operations that can be registered + with the bt_gatt_authorization_cb_register API. See the API + documentation for more details. + endmenu diff --git a/subsys/bluetooth/host/att.c b/subsys/bluetooth/host/att.c index 50e5f7d42dc..6e16f98a0e6 100644 --- a/subsys/bluetooth/host/att.c +++ b/subsys/bluetooth/host/att.c @@ -131,6 +131,11 @@ static uint16_t bt_att_mtu(struct bt_att_chan *chan) return MIN(chan->chan.rx.mtu, chan->chan.tx.mtu); } +/* Descriptor of application-specific authorization callbacks that are used + * with the CONFIG_BT_GATT_AUTHORIZATION_CUSTOM Kconfig enabled. + */ +const static struct bt_gatt_authorization_cb *authorization_cb; + /* ATT connection specific data */ struct bt_att { struct bt_conn *conn; @@ -1259,6 +1264,20 @@ struct read_type_data { typedef bool (*attr_read_cb)(struct net_buf *buf, ssize_t read, void *user_data); +static bool attr_read_authorize(struct bt_conn *conn, + const struct bt_gatt_attr *attr) +{ + if (!IS_ENABLED(CONFIG_BT_GATT_AUTHORIZATION_CUSTOM)) { + return true; + } + + if (!authorization_cb || !authorization_cb->read_operation_authorize) { + return true; + } + + return authorization_cb->read_operation_authorize(conn, attr); +} + static bool attr_read_type_cb(struct net_buf *frag, ssize_t read, void *user_data) { @@ -1368,6 +1387,12 @@ static uint8_t read_type_cb(const struct bt_gatt_attr *attr, uint16_t handle, return BT_GATT_ITER_STOP; } + /* Check the attribute authorization logic */ + if (!attr_read_authorize(conn, attr)) { + data->err = BT_ATT_ERR_AUTHORIZATION; + return BT_GATT_ITER_STOP; + } + /* * If any attribute is founded in handle range it means that error * should be changed from pre-set: attr not found error to no error. @@ -1495,6 +1520,12 @@ static uint8_t read_cb(const struct bt_gatt_attr *attr, uint16_t handle, return BT_GATT_ITER_STOP; } + /* Check the attribute authorization logic */ + if (!attr_read_authorize(conn, attr)) { + data->err = BT_ATT_ERR_AUTHORIZATION; + return BT_GATT_ITER_STOP; + } + /* Read attribute value and store in the buffer */ ret = att_chan_read(chan, attr, data->buf, data->offset, NULL, NULL); if (ret < 0) { @@ -1660,6 +1691,12 @@ static uint8_t read_vl_cb(const struct bt_gatt_attr *attr, uint16_t handle, return BT_GATT_ITER_STOP; } + /* Check the attribute authorization logic */ + if (!attr_read_authorize(conn, attr)) { + data->err = BT_ATT_ERR_AUTHORIZATION; + return BT_GATT_ITER_STOP; + } + /* The Length Value Tuple List may be truncated within the first two * octets of a tuple due to the size limits of the current ATT_MTU. */ @@ -1905,6 +1942,20 @@ struct write_data { uint8_t err; }; +static bool attr_write_authorize(struct bt_conn *conn, + const struct bt_gatt_attr *attr) +{ + if (!IS_ENABLED(CONFIG_BT_GATT_AUTHORIZATION_CUSTOM)) { + return true; + } + + if (!authorization_cb || !authorization_cb->write_operation_authorize) { + return true; + } + + return authorization_cb->write_operation_authorize(conn, attr); +} + static uint8_t write_cb(const struct bt_gatt_attr *attr, uint16_t handle, void *user_data) { @@ -1921,6 +1972,12 @@ static uint8_t write_cb(const struct bt_gatt_attr *attr, uint16_t handle, return BT_GATT_ITER_STOP; } + /* Check the attribute authorization logic */ + if (!attr_write_authorize(data->conn, attr)) { + data->err = BT_ATT_ERR_AUTHORIZATION; + return BT_GATT_ITER_STOP; + } + /* Set command flag if not a request */ if (!data->req) { flags |= BT_GATT_WRITE_FLAG_CMD; @@ -2033,6 +2090,12 @@ static uint8_t prep_write_cb(const struct bt_gatt_attr *attr, uint16_t handle, return BT_GATT_ITER_STOP; } + /* Check the attribute authorization logic */ + if (!attr_write_authorize(data->conn, attr)) { + data->err = BT_ATT_ERR_AUTHORIZATION; + return BT_GATT_ITER_STOP; + } + /* Check if attribute requires handler to accept the data */ if (!(attr->perm & BT_GATT_PERM_PREPARE_WRITE)) { goto append; @@ -3938,3 +4001,23 @@ bool bt_att_chan_opt_valid(struct bt_conn *conn, enum bt_att_chan_opt chan_opt) return true; } + +int bt_gatt_authorization_cb_register(const struct bt_gatt_authorization_cb *cb) +{ + if (!IS_ENABLED(CONFIG_BT_GATT_AUTHORIZATION_CUSTOM)) { + return -ENOSYS; + } + + if (!cb) { + authorization_cb = NULL; + return 0; + } + + if (authorization_cb) { + return -EALREADY; + } + + authorization_cb = cb; + + return 0; +} From a369eb7b367f485bece73cd4973e531bf54cd27b Mon Sep 17 00:00:00 2001 From: Kamil Piszczek Date: Tue, 16 Jan 2024 13:11:57 +0100 Subject: [PATCH 2572/3723] tests: bsim: bluetooth: host: gatt: add authorization callback API test Added a new BabbleSim test that validates the authorization callback API from the Bluetooth GATT header. Signed-off-by: Kamil Piszczek --- tests/bsim/bluetooth/host/compile.sh | 1 + .../host/gatt/authorization/CMakeLists.txt | 14 + .../host/gatt/authorization/prj.conf | 7 + .../host/gatt/authorization/src/common.c | 20 + .../host/gatt/authorization/src/common.h | 73 ++++ .../gatt/authorization/src/gatt_client_test.c | 341 ++++++++++++++++ .../gatt/authorization/src/gatt_server_test.c | 370 ++++++++++++++++++ .../host/gatt/authorization/src/main.c | 22 ++ .../gatt/authorization/test_scripts/gatt.sh | 22 ++ 9 files changed, 870 insertions(+) create mode 100644 tests/bsim/bluetooth/host/gatt/authorization/CMakeLists.txt create mode 100644 tests/bsim/bluetooth/host/gatt/authorization/prj.conf create mode 100644 tests/bsim/bluetooth/host/gatt/authorization/src/common.c create mode 100644 tests/bsim/bluetooth/host/gatt/authorization/src/common.h create mode 100644 tests/bsim/bluetooth/host/gatt/authorization/src/gatt_client_test.c create mode 100644 tests/bsim/bluetooth/host/gatt/authorization/src/gatt_server_test.c create mode 100644 tests/bsim/bluetooth/host/gatt/authorization/src/main.c create mode 100755 tests/bsim/bluetooth/host/gatt/authorization/test_scripts/gatt.sh diff --git a/tests/bsim/bluetooth/host/compile.sh b/tests/bsim/bluetooth/host/compile.sh index efa02f8dfb8..44853bfc918 100755 --- a/tests/bsim/bluetooth/host/compile.sh +++ b/tests/bsim/bluetooth/host/compile.sh @@ -44,6 +44,7 @@ app=tests/bsim/bluetooth/host/att/pipeline/tester compile app=tests/bsim/bluetooth/host/att/long_read compile app=tests/bsim/bluetooth/host/att/open_close compile +app=tests/bsim/bluetooth/host/gatt/authorization compile app=tests/bsim/bluetooth/host/gatt/caching compile app=tests/bsim/bluetooth/host/gatt/general compile app=tests/bsim/bluetooth/host/gatt/notify compile diff --git a/tests/bsim/bluetooth/host/gatt/authorization/CMakeLists.txt b/tests/bsim/bluetooth/host/gatt/authorization/CMakeLists.txt new file mode 100644 index 00000000000..acb0dd45947 --- /dev/null +++ b/tests/bsim/bluetooth/host/gatt/authorization/CMakeLists.txt @@ -0,0 +1,14 @@ +# SPDX-License-Identifier: Apache-2.0 + +cmake_minimum_required(VERSION 3.20.0) + +find_package(Zephyr REQUIRED HINTS $ENV{ZEPHYR_BASE}) +project(bsim_test_gatt_authorization) + +FILE(GLOB app_sources src/*.c) +target_sources(app PRIVATE ${app_sources} ) + +zephyr_include_directories( + ${BSIM_COMPONENTS_PATH}/libUtilv1/src/ + ${BSIM_COMPONENTS_PATH}/libPhyComv1/src/ + ) diff --git a/tests/bsim/bluetooth/host/gatt/authorization/prj.conf b/tests/bsim/bluetooth/host/gatt/authorization/prj.conf new file mode 100644 index 00000000000..9cba554afef --- /dev/null +++ b/tests/bsim/bluetooth/host/gatt/authorization/prj.conf @@ -0,0 +1,7 @@ +CONFIG_BT=y +CONFIG_BT_DEVICE_NAME="GATT tester" +CONFIG_BT_PERIPHERAL=y +CONFIG_BT_CENTRAL=y +CONFIG_BT_GATT_CLIENT=y +CONFIG_BT_GATT_AUTHORIZATION_CUSTOM=y +CONFIG_BT_ATT_PREPARE_COUNT=3 diff --git a/tests/bsim/bluetooth/host/gatt/authorization/src/common.c b/tests/bsim/bluetooth/host/gatt/authorization/src/common.c new file mode 100644 index 00000000000..adff2dd05ef --- /dev/null +++ b/tests/bsim/bluetooth/host/gatt/authorization/src/common.c @@ -0,0 +1,20 @@ +/* + * Copyright (c) 2024 Nordic Semiconductor ASA + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include "common.h" + +void test_tick(bs_time_t HW_device_time) +{ + if (bst_result != Passed) { + FAIL("test failed (not passed after %i seconds)\n", WAIT_TIME); + } +} + +void test_init(void) +{ + bst_ticker_set_next_tick_absolute(WAIT_TIME); + bst_result = In_progress; +} diff --git a/tests/bsim/bluetooth/host/gatt/authorization/src/common.h b/tests/bsim/bluetooth/host/gatt/authorization/src/common.h new file mode 100644 index 00000000000..339919dfe88 --- /dev/null +++ b/tests/bsim/bluetooth/host/gatt/authorization/src/common.h @@ -0,0 +1,73 @@ +/** + * Common functions and helpers for BSIM GATT tests + * + * Copyright (c) 2024 Nordic Semiconductor ASA + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include + +#include "bs_types.h" +#include "bs_tracing.h" +#include "time_machine.h" +#include "bstests.h" + +#include +#include +#include + +#include +#include +#include +#include +#include + +extern enum bst_result_t bst_result; + +#define WAIT_TIME (30 * 1e6) /*seconds*/ + +#define CREATE_FLAG(flag) static atomic_t flag = (atomic_t)false +#define SET_FLAG(flag) (void)atomic_set(&flag, (atomic_t)true) +#define UNSET_FLAG(flag) (void)atomic_set(&flag, (atomic_t)false) +#define WAIT_FOR_FLAG(flag) \ + while (!(bool)atomic_get(&flag)) { \ + (void)k_sleep(K_MSEC(1)); \ + } + +#define FAIL(...) \ + do { \ + bst_result = Failed; \ + bs_trace_error_time_line(__VA_ARGS__); \ + } while (0) + +#define PASS(...) \ + do { \ + bst_result = Passed; \ + bs_trace_info_time(1, __VA_ARGS__); \ + } while (0) + +#define CHRC_SIZE 10 + +#define TEST_SERVICE_UUID \ + BT_UUID_DECLARE_128(0x01, 0x23, 0x45, 0x67, 0x89, 0x01, 0x02, 0x03, \ + 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x00, 0x00) + +#define TEST_UNHANDLED_CHRC_UUID \ + BT_UUID_DECLARE_128(0x01, 0x23, 0x45, 0x67, 0x89, 0x01, 0x02, 0x03, \ + 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0xFD, 0x00) + +#define TEST_UNAUTHORIZED_CHRC_UUID \ + BT_UUID_DECLARE_128(0x01, 0x23, 0x45, 0x67, 0x89, 0x01, 0x02, 0x03, \ + 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0xFE, 0x00) + +#define TEST_AUTHORIZED_CHRC_UUID \ + BT_UUID_DECLARE_128(0x01, 0x23, 0x45, 0x67, 0x89, 0x01, 0x02, 0x03, \ + 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0xFF, 0x00) + +#define TEST_CP_CHRC_UUID \ + BT_UUID_DECLARE_128(0x01, 0x23, 0x45, 0x67, 0x89, 0x01, 0x02, 0x03, \ + 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0xF0, 0x00) + +void test_tick(bs_time_t HW_device_time); +void test_init(void); diff --git a/tests/bsim/bluetooth/host/gatt/authorization/src/gatt_client_test.c b/tests/bsim/bluetooth/host/gatt/authorization/src/gatt_client_test.c new file mode 100644 index 00000000000..9c60c5b57b2 --- /dev/null +++ b/tests/bsim/bluetooth/host/gatt/authorization/src/gatt_client_test.c @@ -0,0 +1,341 @@ +/* + * Copyright (c) 2024 Nordic Semiconductor ASA + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include +#include + +#include "common.h" + +CREATE_FLAG(flag_is_connected); +CREATE_FLAG(flag_discover_complete); +CREATE_FLAG(flag_write_complete); +CREATE_FLAG(flag_read_complete); + +static struct bt_conn *g_conn; +static uint16_t unhandled_chrc_handle; +static uint16_t unauthorized_chrc_handle; +static uint16_t authorized_chrc_handle; +static uint16_t cp_chrc_handle; +static const struct bt_uuid *test_svc_uuid = TEST_SERVICE_UUID; + +#define ARRAY_ITEM(i, _) i +static uint8_t chrc_data[] = { LISTIFY(CHRC_SIZE, ARRAY_ITEM, (,)) }; /* 1, 2, 3 ... */ + +static void connected(struct bt_conn *conn, uint8_t err) +{ + char addr[BT_ADDR_LE_STR_LEN]; + + bt_addr_le_to_str(bt_conn_get_dst(conn), addr, sizeof(addr)); + + if (err != 0) { + FAIL("Failed to connect to %s (%u)\n", addr, err); + return; + } + + printk("Connected to %s\n", addr); + + __ASSERT_NO_MSG(g_conn == conn); + + SET_FLAG(flag_is_connected); +} + +static void disconnected(struct bt_conn *conn, uint8_t reason) +{ + char addr[BT_ADDR_LE_STR_LEN]; + + if (conn != g_conn) { + return; + } + + bt_addr_le_to_str(bt_conn_get_dst(conn), addr, sizeof(addr)); + + printk("Disconnected: %s (reason 0x%02x)\n", addr, reason); + + bt_conn_unref(g_conn); + + g_conn = NULL; + UNSET_FLAG(flag_is_connected); +} + +BT_CONN_CB_DEFINE(conn_callbacks) = { + .connected = connected, + .disconnected = disconnected, +}; + +void device_found(const bt_addr_le_t *addr, int8_t rssi, uint8_t type, + struct net_buf_simple *ad) +{ + char addr_str[BT_ADDR_LE_STR_LEN]; + int err; + + if (g_conn != NULL) { + return; + } + + /* We're only interested in connectable events */ + if (type != BT_HCI_ADV_IND && type != BT_HCI_ADV_DIRECT_IND) { + return; + } + + bt_addr_le_to_str(addr, addr_str, sizeof(addr_str)); + printk("Device found: %s (RSSI %d)\n", addr_str, rssi); + + printk("Stopping scan\n"); + err = bt_le_scan_stop(); + if (err != 0) { + FAIL("Could not stop scan: %d"); + return; + } + + err = bt_conn_le_create(addr, BT_CONN_LE_CREATE_CONN, + BT_LE_CONN_PARAM_DEFAULT, &g_conn); + if (err != 0) { + FAIL("Could not connect to peer: %d", err); + } +} + +static uint8_t discover_func(struct bt_conn *conn, + const struct bt_gatt_attr *attr, + struct bt_gatt_discover_params *params) +{ + int err; + + if (attr == NULL) { + if (unhandled_chrc_handle == 0 || + unauthorized_chrc_handle == 0 || + authorized_chrc_handle == 0) { + FAIL("Did not discover required characterstics"); + } + + (void)memset(params, 0, sizeof(*params)); + + SET_FLAG(flag_discover_complete); + + return BT_GATT_ITER_STOP; + } + + printk("[ATTRIBUTE] handle %u\n", attr->handle); + + if (params->type == BT_GATT_DISCOVER_PRIMARY && + bt_uuid_cmp(params->uuid, TEST_SERVICE_UUID) == 0) { + printk("Found test service\n"); + params->uuid = NULL; + params->start_handle = attr->handle + 1; + params->type = BT_GATT_DISCOVER_CHARACTERISTIC; + + err = bt_gatt_discover(conn, params); + if (err != 0) { + FAIL("Discover failed (err %d)\n", err); + } + + return BT_GATT_ITER_STOP; + } else if (params->type == BT_GATT_DISCOVER_CHARACTERISTIC) { + struct bt_gatt_chrc *chrc = (struct bt_gatt_chrc *)attr->user_data; + + if (bt_uuid_cmp(chrc->uuid, TEST_UNHANDLED_CHRC_UUID) == 0) { + printk("Found unhandled chrc\n"); + unhandled_chrc_handle = chrc->value_handle; + } else if (bt_uuid_cmp(chrc->uuid, TEST_UNAUTHORIZED_CHRC_UUID) == 0) { + printk("Found unauthorized\n"); + unauthorized_chrc_handle = chrc->value_handle; + } else if (bt_uuid_cmp(chrc->uuid, TEST_AUTHORIZED_CHRC_UUID) == 0) { + printk("Found authorized chrc\n"); + authorized_chrc_handle = chrc->value_handle; + } else if (bt_uuid_cmp(chrc->uuid, TEST_CP_CHRC_UUID) == 0) { + printk("Found CP chrc\n"); + cp_chrc_handle = chrc->value_handle; + } + } + + return BT_GATT_ITER_CONTINUE; +} + +static void gatt_discover(void) +{ + static struct bt_gatt_discover_params discover_params; + int err; + + printk("Discovering services and characteristics\n"); + + discover_params.uuid = test_svc_uuid; + discover_params.func = discover_func; + discover_params.start_handle = BT_ATT_FIRST_ATTRIBUTE_HANDLE; + discover_params.end_handle = BT_ATT_LAST_ATTRIBUTE_HANDLE; + discover_params.type = BT_GATT_DISCOVER_PRIMARY; + + err = bt_gatt_discover(g_conn, &discover_params); + if (err != 0) { + FAIL("Discover failed(err %d)\n", err); + } + + WAIT_FOR_FLAG(flag_discover_complete); + printk("Discover complete\n"); +} + +static void gatt_write_cb(struct bt_conn *conn, uint8_t err, + struct bt_gatt_write_params *params) +{ + if ((err != BT_ATT_ERR_SUCCESS) && (params->handle != unauthorized_chrc_handle)) { + FAIL("Write failed on authorized characteristics: 0x%02X\n", err); + } + + if ((err != BT_ATT_ERR_AUTHORIZATION) && (params->handle == unauthorized_chrc_handle)) { + FAIL("Write failed on unauthorized characteristics: 0x%02X\n", err); + } + + (void)memset(params, 0, sizeof(*params)); + + SET_FLAG(flag_write_complete); +} + +static void gatt_write(uint16_t handle) +{ + static struct bt_gatt_write_params write_params; + int err; + + printk("Writing to chrc\n"); + + write_params.data = chrc_data; + write_params.length = sizeof(chrc_data); + write_params.func = gatt_write_cb; + write_params.handle = handle; + + UNSET_FLAG(flag_write_complete); + + err = bt_gatt_write(g_conn, &write_params); + if (err != 0) { + FAIL("bt_gatt_write failed: %d\n", err); + } + + WAIT_FOR_FLAG(flag_write_complete); + printk("success\n"); +} + +static void gatt_cp_write(void) +{ + static struct bt_gatt_write_params write_params; + int err; + uint8_t cp_write_data[] = {0x00}; + + printk("Writing to CP chrc\n"); + + write_params.data = cp_write_data; + write_params.length = sizeof(cp_write_data); + write_params.func = gatt_write_cb; + write_params.handle = cp_chrc_handle; + + UNSET_FLAG(flag_write_complete); + + err = bt_gatt_write(g_conn, &write_params); + if (err != 0) { + FAIL("bt_gatt_write failed: %d\n", err); + } + + WAIT_FOR_FLAG(flag_write_complete); + printk("success\n"); +} + +static uint8_t gatt_read_cb(struct bt_conn *conn, uint8_t err, + struct bt_gatt_read_params *params, + const void *data, uint16_t length) +{ + if ((err != BT_ATT_ERR_SUCCESS) && + (params->single.handle != unauthorized_chrc_handle)) { + FAIL("Read failed on authorized characteristics: 0x%02X\n", err); + + if ((length != CHRC_SIZE) || (memcmp(data, chrc_data, length) != 0)) { + FAIL("chrc data different than expected", err); + } + } + + if ((err != BT_ATT_ERR_AUTHORIZATION) && + (params->single.handle == unauthorized_chrc_handle)) { + FAIL("Read failed on unauthorized characteristics: 0x%02X\n", err); + } + + (void)memset(params, 0, sizeof(*params)); + + SET_FLAG(flag_read_complete); + + return 0; +} + +static void gatt_read(uint16_t handle) +{ + static struct bt_gatt_read_params read_params; + int err; + + printk("Reading chrc\n"); + + read_params.func = gatt_read_cb; + read_params.handle_count = 1; + read_params.single.handle = handle; + read_params.single.offset = 0; + + UNSET_FLAG(flag_read_complete); + + err = bt_gatt_read(g_conn, &read_params); + if (err != 0) { + FAIL("bt_gatt_read failed: %d\n", err); + } + + WAIT_FOR_FLAG(flag_read_complete); + printk("success\n"); +} + +static void gatt_interact(uint16_t handle) +{ + gatt_write(handle); + gatt_read(handle); + gatt_cp_write(); +} + +static void test_main(void) +{ + int err; + + err = bt_enable(NULL); + if (err != 0) { + FAIL("Bluetooth discover failed (err %d)\n", err); + } + + err = bt_le_scan_start(BT_LE_SCAN_PASSIVE, device_found); + if (err != 0) { + FAIL("Scanning failed to start (err %d)\n", err); + } + + printk("Scanning successfully started\n"); + + WAIT_FOR_FLAG(flag_is_connected); + + gatt_discover(); + + printk("Interacting with the unhandled characteristic\n"); + gatt_interact(unhandled_chrc_handle); + + printk("Interacting with the unauthorized characteristic\n"); + gatt_interact(unauthorized_chrc_handle); + + printk("Interacting with the authorized characteristic\n"); + gatt_interact(authorized_chrc_handle); + + PASS("GATT client Passed\n"); +} + +static const struct bst_test_instance test_vcs[] = { + { + .test_id = "gatt_client", + .test_post_init_f = test_init, + .test_tick_f = test_tick, + .test_main_f = test_main + }, + BSTEST_END_MARKER +}; + +struct bst_test_list *test_gatt_client_install(struct bst_test_list *tests) +{ + return bst_add_tests(tests, test_vcs); +} diff --git a/tests/bsim/bluetooth/host/gatt/authorization/src/gatt_server_test.c b/tests/bsim/bluetooth/host/gatt/authorization/src/gatt_server_test.c new file mode 100644 index 00000000000..d5dd5e0e0a7 --- /dev/null +++ b/tests/bsim/bluetooth/host/gatt/authorization/src/gatt_server_test.c @@ -0,0 +1,370 @@ +/* + * Copyright (c) 2024 Nordic Semiconductor ASA + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include "common.h" + +extern enum bst_result_t bst_result; + +CREATE_FLAG(flag_is_chrc_ctx_validated); + +static struct bt_conn *g_conn; + +static void connected(struct bt_conn *conn, uint8_t err) +{ + char addr[BT_ADDR_LE_STR_LEN]; + + bt_addr_le_to_str(bt_conn_get_dst(conn), addr, sizeof(addr)); + + if (err != 0) { + FAIL("Failed to connect to %s (%u)\n", addr, err); + return; + } + + printk("Connected to %s\n", addr); + + g_conn = bt_conn_ref(conn); +} + +static void disconnected(struct bt_conn *conn, uint8_t reason) +{ + char addr[BT_ADDR_LE_STR_LEN]; + + if (conn != g_conn) { + return; + } + + bt_addr_le_to_str(bt_conn_get_dst(conn), addr, sizeof(addr)); + + printk("Disconnected: %s (reason 0x%02x)\n", addr, reason); + + bt_conn_unref(g_conn); + + g_conn = NULL; +} + +BT_CONN_CB_DEFINE(conn_callbacks) = { + .connected = connected, + .disconnected = disconnected, +}; + +struct test_chrc_ctx { + uint16_t auth_read_cnt; + uint16_t read_cnt; + uint16_t auth_write_cnt; + uint16_t write_cnt; + uint8_t data[CHRC_SIZE]; +}; + +static ssize_t read_test_chrc(struct test_chrc_ctx *chrc_ctx, + struct bt_conn *conn, + const struct bt_gatt_attr *attr, + void *buf, uint16_t len, uint16_t offset) +{ + chrc_ctx->read_cnt++; + + return bt_gatt_attr_read(conn, attr, buf, len, offset, + (void *)chrc_ctx->data, + sizeof(chrc_ctx->data)); +} + +static ssize_t write_test_chrc(struct test_chrc_ctx *chrc_ctx, + const void *buf, uint16_t len, + uint16_t offset, uint8_t flags) +{ + chrc_ctx->write_cnt++; + + if (len != sizeof(chrc_ctx->data)) { + printk("Invalid chrc length\n"); + return BT_GATT_ERR(BT_ATT_ERR_INVALID_ATTRIBUTE_LEN); + } + + if (offset != 0) { + printk("Invalid chrc offset and length\n"); + return BT_GATT_ERR(BT_ATT_ERR_INVALID_OFFSET); + } + + if (flags != 0) { + FAIL("Invalid flags %u\n", flags); + return BT_GATT_ERR(BT_ATT_ERR_UNLIKELY); + } + + (void)memcpy(chrc_ctx->data, buf, len); + + return len; +} + +static struct test_chrc_ctx unhandled_chrc_ctx; + +static ssize_t read_test_unhandled_chrc(struct bt_conn *conn, + const struct bt_gatt_attr *attr, + void *buf, uint16_t len, uint16_t offset) +{ + return read_test_chrc(&unhandled_chrc_ctx, conn, attr, buf, len, offset); +} + +static ssize_t write_test_unhandled_chrc(struct bt_conn *conn, + const struct bt_gatt_attr *attr, + const void *buf, uint16_t len, + uint16_t offset, uint8_t flags) +{ + printk("unhandled chrc len %u offset %u\n", len, offset); + + return write_test_chrc(&unhandled_chrc_ctx, buf, len, offset, flags); +} + +static struct test_chrc_ctx unauthorized_chrc_ctx; + +static ssize_t read_test_unauthorized_chrc(struct bt_conn *conn, + const struct bt_gatt_attr *attr, + void *buf, uint16_t len, uint16_t offset) +{ + return read_test_chrc(&unauthorized_chrc_ctx, conn, attr, buf, len, offset); +} + +static ssize_t write_test_unauthorized_chrc(struct bt_conn *conn, + const struct bt_gatt_attr *attr, + const void *buf, uint16_t len, + uint16_t offset, uint8_t flags) +{ + printk("unauthorized chrc len %u offset %u\n", len, offset); + + return write_test_chrc(&unauthorized_chrc_ctx, buf, len, offset, flags); +} + +static struct test_chrc_ctx authorized_chrc_ctx; + +static ssize_t read_test_authorized_chrc(struct bt_conn *conn, + const struct bt_gatt_attr *attr, + void *buf, uint16_t len, uint16_t offset) +{ + return read_test_chrc(&authorized_chrc_ctx, conn, attr, buf, len, offset); +} + +static ssize_t write_test_authorized_chrc(struct bt_conn *conn, + const struct bt_gatt_attr *attr, + const void *buf, uint16_t len, + uint16_t offset, uint8_t flags) +{ + printk("authorized chrc len %u offset %u\n", len, offset); + + return write_test_chrc(&authorized_chrc_ctx, buf, len, offset, flags); +} + +static const struct test_chrc_ctx zeroed_chrc_ctx; + +static bool unhandled_chrc_operation_validate(void) +{ + if (memcmp(&unauthorized_chrc_ctx, &zeroed_chrc_ctx, sizeof(zeroed_chrc_ctx)) != 0) { + return false; + } + + if (memcmp(&authorized_chrc_ctx, &zeroed_chrc_ctx, sizeof(zeroed_chrc_ctx)) != 0) { + return false; + } + + if ((unhandled_chrc_ctx.read_cnt != 1) && (unhandled_chrc_ctx.write_cnt != 1)) { + return false; + } + + if ((unhandled_chrc_ctx.auth_read_cnt != 0) && + (unhandled_chrc_ctx.auth_write_cnt != 0)) { + return false; + } + + return true; +} + +static bool unauthorized_chrc_operation_validate(void) +{ + if (memcmp(&unhandled_chrc_ctx, &zeroed_chrc_ctx, sizeof(zeroed_chrc_ctx)) != 0) { + return false; + } + + if (memcmp(&authorized_chrc_ctx, &zeroed_chrc_ctx, sizeof(zeroed_chrc_ctx)) != 0) { + return false; + } + + if ((unauthorized_chrc_ctx.read_cnt != 0) && (unauthorized_chrc_ctx.write_cnt != 0)) { + return false; + } + + if ((unauthorized_chrc_ctx.auth_read_cnt != 1) && + (unauthorized_chrc_ctx.auth_write_cnt != 1)) { + return false; + } + + return true; +} + +static bool authorized_chrc_operation_validate(void) +{ + if (memcmp(&unhandled_chrc_ctx, &zeroed_chrc_ctx, sizeof(zeroed_chrc_ctx)) != 0) { + return false; + } + + if (memcmp(&unauthorized_chrc_ctx, &zeroed_chrc_ctx, sizeof(zeroed_chrc_ctx)) != 0) { + return false; + } + + if ((authorized_chrc_ctx.read_cnt != 1) && (authorized_chrc_ctx.write_cnt != 1)) { + return false; + } + + if ((authorized_chrc_ctx.auth_read_cnt != 1) && + (authorized_chrc_ctx.auth_write_cnt != 1)) { + return false; + } + + return true; +} + +static ssize_t write_cp_chrc(struct bt_conn *conn, + const struct bt_gatt_attr *attr, + const void *buf, uint16_t len, + uint16_t offset, uint8_t flags) +{ + static uint16_t cp_write_cnt; + bool pass; + char *log_str; + + if (cp_write_cnt == 0) { + pass = unhandled_chrc_operation_validate(); + log_str = "unhandled"; + } else if (cp_write_cnt == 1) { + pass = unauthorized_chrc_operation_validate(); + log_str = "unauthorized"; + } else if (cp_write_cnt == 2) { + pass = authorized_chrc_operation_validate(); + log_str = "authorized"; + } else { + FAIL("Invalid value of CP write counter %u\n", cp_write_cnt); + return BT_GATT_ERR(BT_ATT_ERR_UNLIKELY); + } + + if (pass) { + printk("Correct context for %s chrc\n", log_str); + } else { + FAIL("Invalid context for %s chrc\n", log_str); + return BT_GATT_ERR(BT_ATT_ERR_UNLIKELY); + } + + memset(&unhandled_chrc_ctx, 0, sizeof(unhandled_chrc_ctx)); + memset(&unauthorized_chrc_ctx, 0, sizeof(unauthorized_chrc_ctx)); + memset(&authorized_chrc_ctx, 0, sizeof(authorized_chrc_ctx)); + + cp_write_cnt++; + + if (cp_write_cnt == 3) { + SET_FLAG(flag_is_chrc_ctx_validated); + } + + return len; +} + +BT_GATT_SERVICE_DEFINE(test_svc, + BT_GATT_PRIMARY_SERVICE(TEST_SERVICE_UUID), + BT_GATT_CHARACTERISTIC(TEST_UNHANDLED_CHRC_UUID, + BT_GATT_CHRC_WRITE | BT_GATT_CHRC_READ, + BT_GATT_PERM_WRITE | BT_GATT_PERM_READ, + read_test_unhandled_chrc, + write_test_unhandled_chrc, NULL), + BT_GATT_CHARACTERISTIC(TEST_UNAUTHORIZED_CHRC_UUID, + BT_GATT_CHRC_WRITE | BT_GATT_CHRC_READ, + BT_GATT_PERM_WRITE | BT_GATT_PERM_READ, + read_test_unauthorized_chrc, + write_test_unauthorized_chrc, NULL), + BT_GATT_CHARACTERISTIC(TEST_AUTHORIZED_CHRC_UUID, + BT_GATT_CHRC_WRITE | BT_GATT_CHRC_READ, + BT_GATT_PERM_WRITE | BT_GATT_PERM_READ, + read_test_authorized_chrc, + write_test_authorized_chrc, NULL), + BT_GATT_CHARACTERISTIC(TEST_CP_CHRC_UUID, + BT_GATT_CHRC_WRITE, + BT_GATT_PERM_WRITE, + NULL, write_cp_chrc, NULL), +); + +static bool gatt_read_operation_authorize(struct bt_conn *conn, + const struct bt_gatt_attr *attr) +{ + if (bt_uuid_cmp(attr->uuid, TEST_UNAUTHORIZED_CHRC_UUID) == 0) { + unauthorized_chrc_ctx.auth_read_cnt++; + return false; + } else if (bt_uuid_cmp(attr->uuid, TEST_AUTHORIZED_CHRC_UUID) == 0) { + authorized_chrc_ctx.auth_read_cnt++; + return true; + } else { + return true; + } +} + +static bool gatt_write_operation_authorize(struct bt_conn *conn, + const struct bt_gatt_attr *attr) +{ + if (bt_uuid_cmp(attr->uuid, TEST_UNAUTHORIZED_CHRC_UUID) == 0) { + unauthorized_chrc_ctx.auth_write_cnt++; + return false; + } else if (bt_uuid_cmp(attr->uuid, TEST_AUTHORIZED_CHRC_UUID) == 0) { + authorized_chrc_ctx.auth_write_cnt++; + return true; + } else { + return true; + } +} + +static const struct bt_gatt_authorization_cb gatt_authorization_callbacks = { + .read_operation_authorize = gatt_read_operation_authorize, + .write_operation_authorize = gatt_write_operation_authorize, +}; + +static void test_main(void) +{ + int err; + const struct bt_data ad[] = { + BT_DATA_BYTES(BT_DATA_FLAGS, (BT_LE_AD_GENERAL | BT_LE_AD_NO_BREDR)) + }; + + err = bt_gatt_authorization_cb_register(&gatt_authorization_callbacks); + if (err) { + FAIL("Registering GATT authorization callbacks failed (err %d)\n", err); + return; + } + + err = bt_enable(NULL); + if (err != 0) { + FAIL("Bluetooth init failed (err %d)\n", err); + return; + } + + printk("Bluetooth initialized\n"); + + err = bt_le_adv_start(BT_LE_ADV_CONN_NAME, ad, ARRAY_SIZE(ad), NULL, 0); + if (err != 0) { + FAIL("Advertising failed to start (err %d)\n", err); + return; + } + + printk("Advertising successfully started\n"); + + WAIT_FOR_FLAG(flag_is_chrc_ctx_validated); + + PASS("GATT server passed\n"); +} + +static const struct bst_test_instance test_gatt_server[] = { + { + .test_id = "gatt_server", + .test_post_init_f = test_init, + .test_tick_f = test_tick, + .test_main_f = test_main + }, + BSTEST_END_MARKER +}; + +struct bst_test_list *test_gatt_server_install(struct bst_test_list *tests) +{ + return bst_add_tests(tests, test_gatt_server); +} diff --git a/tests/bsim/bluetooth/host/gatt/authorization/src/main.c b/tests/bsim/bluetooth/host/gatt/authorization/src/main.c new file mode 100644 index 00000000000..a95f0285e75 --- /dev/null +++ b/tests/bsim/bluetooth/host/gatt/authorization/src/main.c @@ -0,0 +1,22 @@ +/* + * Copyright (c) 2024 Nordic Semiconductor ASA + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include "bstests.h" + +extern struct bst_test_list *test_gatt_server_install(struct bst_test_list *tests); +extern struct bst_test_list *test_gatt_client_install(struct bst_test_list *tests); + +bst_test_install_t test_installers[] = { + test_gatt_server_install, + test_gatt_client_install, + NULL +}; + +int main(void) +{ + bst_main(); + return 0; +} diff --git a/tests/bsim/bluetooth/host/gatt/authorization/test_scripts/gatt.sh b/tests/bsim/bluetooth/host/gatt/authorization/test_scripts/gatt.sh new file mode 100755 index 00000000000..edad0eb86c9 --- /dev/null +++ b/tests/bsim/bluetooth/host/gatt/authorization/test_scripts/gatt.sh @@ -0,0 +1,22 @@ +#!/usr/bin/env bash +# Copyright 2024 Nordic Semiconductor ASA +# SPDX-License-Identifier: Apache-2.0 + +source ${ZEPHYR_BASE}/tests/bsim/sh_common.source + +simulation_id="gatt_authorization" +verbosity_level=2 +EXECUTE_TIMEOUT=120 + +cd ${BSIM_OUT_PATH}/bin + +Execute ./bs_${BOARD}_tests_bsim_bluetooth_host_gatt_authorization_prj_conf \ + -v=${verbosity_level} -s=${simulation_id} -d=0 -testid=gatt_client + +Execute ./bs_${BOARD}_tests_bsim_bluetooth_host_gatt_authorization_prj_conf \ + -v=${verbosity_level} -s=${simulation_id} -d=1 -testid=gatt_server + +Execute ./bs_2G4_phy_v1 -v=${verbosity_level} -s=${simulation_id} \ + -D=2 -sim_length=60e6 $@ + +wait_for_background_jobs From ee36d9659f5974180baf27f0e65c35e992bf040f Mon Sep 17 00:00:00 2001 From: Philip Molloy Date: Fri, 29 Dec 2023 11:17:09 +0100 Subject: [PATCH 2573/3723] boards: add initial support for adi_sdp_k1 Add board configuration, dts and pinmux based on the stm32f469i_disco board. Signed-off-by: Philip Molloy --- boards/arm/adi_sdp_k1/Kconfig.board | 8 + boards/arm/adi_sdp_k1/Kconfig.defconfig | 15 ++ boards/arm/adi_sdp_k1/adi_sdp_k1.dts | 80 ++++++++ boards/arm/adi_sdp_k1/adi_sdp_k1.yaml | 13 ++ boards/arm/adi_sdp_k1/adi_sdp_k1_defconfig | 25 +++ .../arm/adi_sdp_k1/arduino_r3_connector.dtsi | 40 ++++ boards/arm/adi_sdp_k1/board.cmake | 6 + boards/arm/adi_sdp_k1/doc/img/adi_sdp_k1.webp | Bin 0 -> 92824 bytes .../adi_sdp_k1/doc/img/adi_sdp_k1_120pin.webp | Bin 0 -> 95984 bytes .../doc/img/adi_sdp_k1_arduino.webp | Bin 0 -> 97732 bytes boards/arm/adi_sdp_k1/doc/index.rst | 184 ++++++++++++++++++ boards/arm/adi_sdp_k1/revision.cmake | 8 + boards/arm/adi_sdp_k1/support/openocd.cfg | 12 ++ 13 files changed, 391 insertions(+) create mode 100644 boards/arm/adi_sdp_k1/Kconfig.board create mode 100644 boards/arm/adi_sdp_k1/Kconfig.defconfig create mode 100644 boards/arm/adi_sdp_k1/adi_sdp_k1.dts create mode 100644 boards/arm/adi_sdp_k1/adi_sdp_k1.yaml create mode 100644 boards/arm/adi_sdp_k1/adi_sdp_k1_defconfig create mode 100644 boards/arm/adi_sdp_k1/arduino_r3_connector.dtsi create mode 100644 boards/arm/adi_sdp_k1/board.cmake create mode 100644 boards/arm/adi_sdp_k1/doc/img/adi_sdp_k1.webp create mode 100644 boards/arm/adi_sdp_k1/doc/img/adi_sdp_k1_120pin.webp create mode 100644 boards/arm/adi_sdp_k1/doc/img/adi_sdp_k1_arduino.webp create mode 100644 boards/arm/adi_sdp_k1/doc/index.rst create mode 100644 boards/arm/adi_sdp_k1/revision.cmake create mode 100644 boards/arm/adi_sdp_k1/support/openocd.cfg diff --git a/boards/arm/adi_sdp_k1/Kconfig.board b/boards/arm/adi_sdp_k1/Kconfig.board new file mode 100644 index 00000000000..8aa4b969d61 --- /dev/null +++ b/boards/arm/adi_sdp_k1/Kconfig.board @@ -0,0 +1,8 @@ +# ADI SDP-K1 board configuration + +# Copyright (c) 2024 BayLibre +# SPDX-License-Identifier: Apache-2.0 + +config BOARD_ADI_SDP_K1 + bool "ADI SDP-K1 Controller Board" + depends on SOC_STM32F469XX diff --git a/boards/arm/adi_sdp_k1/Kconfig.defconfig b/boards/arm/adi_sdp_k1/Kconfig.defconfig new file mode 100644 index 00000000000..03e3bd4cdeb --- /dev/null +++ b/boards/arm/adi_sdp_k1/Kconfig.defconfig @@ -0,0 +1,15 @@ +# ADI SDP-K1 board configuration + +# Copyright (c) 2024 BayLibre +# SPDX-License-Identifier: Apache-2.0 + +if BOARD_ADI_SDP_K1 + +config BOARD + default "adi_sdp_k1" + +config SPI_STM32_INTERRUPT + default y + depends on SPI + +endif # BOARD_ADI_SDP_K1 diff --git a/boards/arm/adi_sdp_k1/adi_sdp_k1.dts b/boards/arm/adi_sdp_k1/adi_sdp_k1.dts new file mode 100644 index 00000000000..91aea8c60df --- /dev/null +++ b/boards/arm/adi_sdp_k1/adi_sdp_k1.dts @@ -0,0 +1,80 @@ +/* + * Copyright (c) 2024 BayLibre + * + * SPDX-License-Identifier: Apache-2.0 + */ + +/dts-v1/; +#include +#include +#include "arduino_r3_connector.dtsi" + +/ { + model = "Analog Devices Inc. SDP-K1 board"; + compatible = "adi,sdp-k1"; + + chosen { + zephyr,console = &uart5; + zephyr,shell-uart = &uart5; + zephyr,sram = &sram0; + zephyr,flash = &flash0; + zephyr,ccm = &ccm0; + }; + + leds { + compatible = "gpio-leds"; + status_led: led_ds3 { + gpios = <&gpiok 4 GPIO_ACTIVE_HIGH>; + label = "Status DS3"; + }; + green_led_1: led_ds4 { + gpios = <&gpiok 5 GPIO_ACTIVE_HIGH>; + label = "User LD1"; + }; + orange_led_2: led_ds5 { + gpios = <&gpiok 6 GPIO_ACTIVE_HIGH>; + label = "User LD2"; + }; + red_led_3: led_ds6 { + gpios = <&gpiok 7 GPIO_ACTIVE_HIGH>; + label = "User LD3"; + }; + }; + + aliases { + led0 = &status_led; + }; +}; + +&clk_lsi { + status = "okay"; +}; + +&clk_hse { + clock-frequency = ; + status = "okay"; +}; + +&pll { + div-m = <8>; + mul-n = <336>; + div-p = <2>; + div-q = <7>; + clocks = <&clk_hse>; + status = "okay"; +}; + +&rcc { + clocks = <&pll>; + clock-frequency = ; + ahb-prescaler = <1>; + apb1-prescaler = <4>; + apb2-prescaler = <2>; +}; + +&uart5 { + pinctrl-0 = <&uart5_tx_pc12 &uart5_rx_pd2>; + pinctrl-names = "default"; + current-speed = <115200>; + status = "okay"; +}; diff --git a/boards/arm/adi_sdp_k1/adi_sdp_k1.yaml b/boards/arm/adi_sdp_k1/adi_sdp_k1.yaml new file mode 100644 index 00000000000..800bedab7de --- /dev/null +++ b/boards/arm/adi_sdp_k1/adi_sdp_k1.yaml @@ -0,0 +1,13 @@ +identifier: adi_sdp_k1 +name: ADI SDP-K1 +type: mcu +arch: arm +toolchain: + - zephyr + - gnuarmemb + - xtools +ram: 384 +flash: 2048 +supported: + - gpio +vendor: adi diff --git a/boards/arm/adi_sdp_k1/adi_sdp_k1_defconfig b/boards/arm/adi_sdp_k1/adi_sdp_k1_defconfig new file mode 100644 index 00000000000..94a8f52809e --- /dev/null +++ b/boards/arm/adi_sdp_k1/adi_sdp_k1_defconfig @@ -0,0 +1,25 @@ +# SPDX-License-Identifier: Apache-2.0 + +CONFIG_SOC_SERIES_STM32F4X=y +CONFIG_SOC_STM32F469XX=y + +# Enable MPU +CONFIG_ARM_MPU=y + +# Enable HW stack protection +CONFIG_HW_STACK_PROTECTION=y + +CONFIG_SERIAL=y + +# console +CONFIG_CONSOLE=y +CONFIG_UART_CONSOLE=y + +# enable GPIO +CONFIG_GPIO=y + +# Enable Clocks +CONFIG_CLOCK_CONTROL=y + +# enable pin controller +CONFIG_PINCTRL=y diff --git a/boards/arm/adi_sdp_k1/arduino_r3_connector.dtsi b/boards/arm/adi_sdp_k1/arduino_r3_connector.dtsi new file mode 100644 index 00000000000..53c9a871173 --- /dev/null +++ b/boards/arm/adi_sdp_k1/arduino_r3_connector.dtsi @@ -0,0 +1,40 @@ +/* + * Copyright (c) 2024 BayLibre + * + * SPDX-License-Identifier: Apache-2.0 + */ + +/ { + arduino_header: connector { + compatible = "arduino-header-r3"; + #gpio-cells = <2>; + gpio-map-mask = <0xffffffff 0xffffffc0>; + gpio-map-pass-thru = <0 0x3f>; + gpio-map = <0 0 &gpioa 2 0>, /* A0 */ + <1 0 &gpioa 4 0>, /* A1 */ + <2 0 &gpioa 6 0>, /* A2 */ + <3 0 &gpioc 1 0>, /* A3 */ + <4 0 &gpioc 4 0>, /* A4 */ + <5 0 &gpioc 5 0>, /* A5 */ + <6 0 &gpioa 1 0>, /* D0 */ + <7 0 &gpioa 0 0>, /* D1 */ + <8 0 &gpiog 7 0>, /* D2 */ + <9 0 &gpiod 12 0>, /* D3 */ + <10 0 &gpiog 9 0>, /* D4 */ + <11 0 &gpioa 11 0>, /* D5 */ + <12 0 &gpioa 10 0>, /* D6 */ + <13 0 &gpiog 10 0>, /* D7 */ + <14 0 &gpiog 11 0>, /* D8 */ + <15 0 &gpiob 15 0>, /* D9 */ + <16 0 &gpioa 15 0>, /* D10 */ + <17 0 &gpioa 7 0>, /* D11 */ + <18 0 &gpiob 4 0>, /* D12 */ + <19 0 &gpiob 3 0>, /* D13 */ + <20 0 &gpiob 7 0>, /* D14 */ + <21 0 &gpiob 8 0>; /* D15 */ + }; +}; + +arduino_i2c: &i2c1 {}; +arduino_spi: &spi1 {}; +arduino_serial: &usart2 {}; diff --git a/boards/arm/adi_sdp_k1/board.cmake b/boards/arm/adi_sdp_k1/board.cmake new file mode 100644 index 00000000000..8a8885e9a95 --- /dev/null +++ b/boards/arm/adi_sdp_k1/board.cmake @@ -0,0 +1,6 @@ +# SPDX-License-Identifier: Apache-2.0 + +board_runner_args(jlink "--device=STM32F469NI" "--speed=4000") + +include(${ZEPHYR_BASE}/boards/common/openocd.board.cmake) +include(${ZEPHYR_BASE}/boards/common/jlink.board.cmake) diff --git a/boards/arm/adi_sdp_k1/doc/img/adi_sdp_k1.webp b/boards/arm/adi_sdp_k1/doc/img/adi_sdp_k1.webp new file mode 100644 index 0000000000000000000000000000000000000000..ea8add4d7d765c267da1f6766f8149eaead019c9 GIT binary patch literal 92824 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 YW#C^1{_ipHpUn*dh5M%Cf!n(LKQOQ+cmMzZ literal 0 HcmV?d00001 diff --git a/boards/arm/adi_sdp_k1/doc/img/adi_sdp_k1_120pin.webp b/boards/arm/adi_sdp_k1/doc/img/adi_sdp_k1_120pin.webp new file mode 100644 index 0000000000000000000000000000000000000000..a3729bcf6f4089a0d466e08cfadd29607702268f GIT binary patch literal 95984 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 nIso{05;u-hS6T_3aTA{iY%BhD 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 z zHOerHs4Zg2H%-b@3537k{Rr)YJVBUek!>K^%a?fKyNQ~V`}^1xfGPR=@A+)D zq=F{J)lugrZEZEU8~zlHTw1E{4ez9RnIv3AQ` zH81%NeT}AFpR%5nLjaE~W3lV~<6<|JO)v6t(^d%Rx{EJY+3A7}2A~ACSzTO2g~+f6 zr4J0%shy|K#82y@7Q@T4)o8soB?e~kDBL@v8|OPdP5bk^sK;eAb!-l<%HceHTh?M0 zQP0O$ymIXHz4*2dlU$4V!-TZL%qmXb5fl3F_^Or{lg{Y-M@qRH&d=-krAhGa*unx? zXGZ#n<05)Yr}Y4h5)|QP^v*n@CN0OHMU=*KMex&xm%c&nz!4gy2fp{s%ru6^DErtr z0u$zC=T@(khh#itc4IRus@CdgaX&moi$cqIjmGrzned7_#nCL#Bmn+|I*QbNMF;j9 zYG+gBF?2*tGVKk^!d`qM~P#vRn`EmvC_pn%L%?x{M zYyJpOD7A{UT7z7W4j|+4>S9ui7a0mHi0AlPNy)Q@ne~G5x1vDS&n)8}>%koHte_m~ zZ})1-QDq?o$Sl9H-{mf&*{>m3ukgj?^e{cMzM0G{Trg)>r3l`RMfVc^7?Ey+URS|6 zp@m9&K_elwpFyMQa^@v%hr_gkxA#=Xt4Mk4M@+Egz2RfaVZ9jv~t;o zhRq%^dJW}rM$$U&B?X)fP5e|Q)@4BcZm&|Fyu*~HWk{W73!b5>=-@TyaE#^Ahg{Ny z>ab6f-0yt^bv9%9uOS8#KR@7gS3lE#;$2>v{Z934bbYjeGsK@m^F^5D4CWRhbw#~7 zEMSO7^<({Q>uc9-#liyaGHSmzcgu&Gx9NNP1YNVA~&Xf86+qw%N>t| zKldQotQGFh#>H<%8Du_kw-p zT$GF=)y=DDN2Yf zY9B!KJkyjgm0k66i8p=r&8mU#nrdKA_(clB>jiJhak5@Q&x9q$qU1l9%)WZ>hkeXd z5kX3B65{KV=2L7w+O&i@qHG5}>{V{tKRjpmRWvZ5)fPPz==D4z<@s~x`tk1dU)vDQ zvFLY$ucjsqjU}|6cpV5xw>%Xao>6;hL+jDtG%wYFN1TkFyzEzaDlgB1fDTVF5fBiO z5fC3wp}@_*?Y1ZI2_NDU1bBiF3g7YJ_9NzTCqqQ}lSaX9^1tl_xXtu81_^F+A|fGR z!_##5&IPv#;b{qcw+{QOtTwp)xS{{~$ib~g=6}-H^2%ydT13jsk`%)=1`wuQJ*nL#YAp&~R#U)pJ?tj$Ge zba|Bl%8pVHD{DC~XNabkiWb<*7A$B^BPL2E>;d$!ceIDNfT%p|?VvEAhX@VG+`$Y2 zgximYIcTW<-SB9GrrJf*b%Y4lXV>ID!r433UN^ut8z8|1d~HU|?r!M;B`cDAgk) z$jrgjMT7=k{$GySJ1Q&xOALjv|8bKY>|oE~0dnNvWCw8A+dq2y2Mu$Paf4_6+l~Jf z4b$>;gm7p;U=FU%V2F$x1nNTjPj++gzj+;9o$dZqz#Pm0v4hydVK8`Uoc|W}*l7Qv zA1iEWZSVLe2VB{IQ7+aN|0T=+@aOT&ANT($9G>l8zW;&zr=E{MxEMfb2e9j-Kl0Kd zG>?S>%^kqj=Dn8a4;v3Zn3v5=fQz3EEC>+5^@W?}9 zE+8lv^2h^cX19iu@NfbI1;O0BY~~1pfh#;RJAD1AU#~cilb#S%^ z!JEw59%KpOaEF*V(oj803zSfk7op)|2mJk2%?{*Z0mq8aC|N^YJ^ntbWo-}9bOAjo z$H@=i;p627@BnxLoZOsTe;J7i z`FR0?X7Hvo16Xjg@$hg8vVl0c_}IAl1k45ac;GE9Xz@>en1h9jJIEO#VF{N8t^mAi z{TY?0nEpu4{149E3i7BYTmv=$CmVqOj|T7|3-GrF9B}{PtH@gb|Edbd|6R*J=l)yR y{{x4QC6DI6Lz5`gf42W9@E-;KqriU@_>ThrQQ-eS1^#Pt1A)S?bll-nm;VD3VI|Q3 literal 0 HcmV?d00001 diff --git a/boards/arm/adi_sdp_k1/doc/img/adi_sdp_k1_arduino.webp b/boards/arm/adi_sdp_k1/doc/img/adi_sdp_k1_arduino.webp new file mode 100644 index 0000000000000000000000000000000000000000..5712fb6f595fc5297b6c4204206280ae03192ea3 GIT binary patch literal 97732 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�O3B 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 E0keCrjsO4v literal 0 HcmV?d00001 diff --git a/boards/arm/adi_sdp_k1/doc/index.rst b/boards/arm/adi_sdp_k1/doc/index.rst new file mode 100644 index 00000000000..177f7bf3550 --- /dev/null +++ b/boards/arm/adi_sdp_k1/doc/index.rst @@ -0,0 +1,184 @@ +.. _adi_sdp_k1: + +ADI SDP-K1 +########## + +Overview +******** + +The EVAL-SDP-CK1Z (SDP-K1) controller board is a system demonstration platform +(SDP) from Analog Devices designed to connect to evaluation shields containing +ADI components. + +- STM32 microcontroller in BGA216 package +- USB 2.0 device with USB-C connector +- USB debug interface supporting CMSIS-DAP through a NXP Freescale + microcontroller +- Flexible board power supply + - USB VBUS 5 V max. 500 mA + - 5.5mm DC power jack 7 - 12 V min. 300 mA + - VIN from Arduino* compatible connectors + - VIN from 120-pin connector 5 V min. 300 mA +- 3 color LEDs (green, orange, red) and 1 status LED +- One push-buttons: RESET +- 16MB SDRAM +- Arduino UNO and 120-pin SDP connectors + +.. figure:: img/adi_sdp_k1.webp + :align: center + :alt: ADI SDP-K1 + + ADI SDP-K1 (Credit: Analog Devices, Inc.) + +More information about the board can be found on the `ADI SDP-K1 website`_. + +Hardware +******** + +ADI SDP-K1 provides the following hardware components: + +- STM32F469NIH6 in BGA216 package +- ARM |reg| 32-bit Cortex |reg| -M4 CPU with FPU +- 180 MHz max CPU frequency +- VDD of 1.8 V or 3.3 V +- 2 MB Flash +- 384 KB SRAM +- GPIO with external interrupt capability +- LCD parallel interface, 8080/6800 modes +- LCD TFT controller supporting up to XGA resolution +- MIPI |reg| DSI host controller supporting up to 720p 30Hz resolution +- 3x12-bit ADC with 24 channels +- 2x12-bit D/A converters +- RTC +- Advanced-control Timer +- General Purpose Timers (17) +- Watchdog Timers (2) +- USART/UART (8) +- I2C (3) +- SPI (6) +- 1xSAI (serial audio interface) +- SDIO +- 2xCAN +- USB 2.0 OTG FS with on-chip PHY +- USB 2.0 OTG HS/FS with dedicated DMA, on-chip full-speed PHY and ULPI +- 10/100 Ethernet MAC with dedicated DMA +- 8- to 14-bit parallel camera +- CRC calculation unit +- True random number generator +- DMA Controller + +More information about STM32F469NI can be found here: + - `STM32F469NI product page`_ + - `STM32F469 reference manual`_ + +Supported Features +================== + +The Zephyr stm32f469i_disco board configuration supports the following hardware features: + ++-----------+------------+-------------------------------------+ +| Interface | Controller | Driver/Component | ++===========+============+=====================================+ +| UART | on-chip | serial port-polling; | +| | | serial port-interrupt | ++-----------+------------+-------------------------------------+ +| PINMUX | on-chip | pinmux | ++-----------+------------+-------------------------------------+ +| GPIO | on-chip | gpio | ++-----------+------------+-------------------------------------+ + +Other hardware features are not yet supported on Zephyr porting. + +The default configuration can be found in the defconfig file: + + ``boards/arm/adi_sdp_k1/adi_sdp_k1_defconfig`` + +Pin Mapping +=========== + +For more details please refer to `EVAL-SDP-CK1Z User Guide`_. + +Arduino UNO headers +------------------- + +.. figure:: img/adi_sdp_k1_arduino.webp + :align: center + :alt: ADI SDP-K1 Arduino UNO headers pinout + + ADI SDP-K1 (Credit: Analog Devices, Inc.) + +120-pin SDP connector +--------------------- + +.. figure:: img/adi_sdp_k1_120pin.webp + :align: center + :alt: ADI SDP-K1 120-pin SDP connector pinout + + ADI SDP-K1 (Credit: Analog Devices, Inc.) + +Default Zephyr Peripheral Mapping: +---------------------------------- + +- UART_5 TX/RX : P2 (DAPLink USB-C) +- UART_5 TX/RX : P8 (DAPLink two position through hole) +- LED1 : DS6 (Red) +- LED2 : DS5 (Orange) +- LED3 : DS4 (Green) +- LED4 : DS4 (Status) + +Programming and Debugging +************************* + +The ADI SDP-K1 be programmed over USB using the DAPLink firmware running on an +embedded NXP Freescale microcontroller or a 10-pin ``DEBUG`` header connected +to a STLINK debugger. + +DAPLink exposes a storage device, as well as USB HID and CDC Endpoints, to the +host. For more details please refer to the `Official DAPLink website`_. + +Flashing +======== + +Flashing an application with a STLINK debugger +---------------------------------------------- + +First, connect the STLINK debugger to your host computer using the Micro-USB port. +Then attach the debugger to the 10-pin ``DEBUG`` header on the SDP-K1. Finally +connect the SDP-K1 to your host computer using the USB-C port. + +Run a serial host program to connect with your board: + +.. code-block:: console + + $ minicom -D /dev/serial/by-id/usb-ARM_DAPLink_CMSIS-DAP_<...> + +Here is an example for the :ref:`hello_world` application. + +.. zephyr-app-commands:: + :zephyr-app: samples/hello_world + :board: adi_sdp_k1 + :goals: build flash + +You should see the following message on the console: + +.. code-block:: console + + Hello World! adi_sdp_k1 + +Debugging +========= + +.. _ADI SDP-K1 website: + https://www.analog.com/en/design-center/evaluation-hardware-and-software/evaluation-boards-kits/sdp-k1.html + +.. _EVAL-SDP-CK1Z User Guide: + https://www.analog.com/media/en/technical-documentation/user-guides/EVAL-SDP-CK1Z-UG-1539.pdf + +.. _STM32F469NI product page: + https://www.st.com/en/microcontrollers/stm32f469ni.html + +.. _STM32F469 reference manual: + https://www.st.com/resource/en/reference_manual/dm00127514.pdf + +.. _Official DAPLink website: + https://daplink.io/ diff --git a/boards/arm/adi_sdp_k1/revision.cmake b/boards/arm/adi_sdp_k1/revision.cmake new file mode 100644 index 00000000000..b82df11ae6a --- /dev/null +++ b/boards/arm/adi_sdp_k1/revision.cmake @@ -0,0 +1,8 @@ +# Copyright (c) 2024 BayLibre +# SPDX-License-Identifier: Apache-2.0 + +board_check_revision( + FORMAT LETTER + DEFAULT_REVISION E + VALID_REVISIONS B E +) diff --git a/boards/arm/adi_sdp_k1/support/openocd.cfg b/boards/arm/adi_sdp_k1/support/openocd.cfg new file mode 100644 index 00000000000..d1426b667d5 --- /dev/null +++ b/boards/arm/adi_sdp_k1/support/openocd.cfg @@ -0,0 +1,12 @@ +source [find board/st_nucleo_f4.cfg] + +$_TARGETNAME configure -event gdb-attach { + echo "Debugger attaching: halting execution" + reset halt + gdb_breakpoint_override hard +} + +$_TARGETNAME configure -event gdb-detach { + echo "Debugger detaching: resuming execution" + resume +} From 1eb074ea0cd3fc55b0a15e0fe519593567bdd1b5 Mon Sep 17 00:00:00 2001 From: Philip Molloy Date: Wed, 10 Jan 2024 09:49:30 +0100 Subject: [PATCH 2574/3723] MAINTAINERS: add ARM boards to ADI platform Currently this just includes the ADI SDP-K1 Signed-off-by: Philip Molloy --- MAINTAINERS.yml | 1 + 1 file changed, 1 insertion(+) diff --git a/MAINTAINERS.yml b/MAINTAINERS.yml index 8954bbad735..31423b14400 100644 --- a/MAINTAINERS.yml +++ b/MAINTAINERS.yml @@ -2986,6 +2986,7 @@ ADI Platforms: - galak - microbuilder files: + - boards/arm/adi_*/ - drivers/*/max* - drivers/*/*max*/ - drivers/dac/dac_ltc* From 119f647426ee203a9b9f27595e4652c65bda5f79 Mon Sep 17 00:00:00 2001 From: Maksim Salau Date: Mon, 8 Jan 2024 22:49:54 +0100 Subject: [PATCH 2575/3723] boards: arm: nucleo_f042k6: fix pwm output Changes: * Fixed typo in the PWM channel number (32 -> 3) * Added a prescaler to make the board compatible with the blinky_pwm sample Output of the sample before the fix: PWM-based blinky Calibrating for channel 32... [00:00:00.010,000] pwm_stm32: Invalid channel (32) [00:00:00.016,000] pwm_stm32: Invalid channel (32) [00:00:00.022,000] pwm_stm32: Invalid channel (32) [00:00:00.028,000] pwm_stm32: Invalid channel (32) [00:00:00.034,000] pwm_stm32: Invalid channel (32) [00:00:00.040,000] pwm_stm32: Invalid channel (32) Error: PWM device does not support a period at least 31250000 After the fix: PWM-based blinky Calibrating for channel 3... Done calibrating; maximum/minimum periods 1000000000/7812500 nsec Presence of PWM signal after the fix has been confirmed using a logic analyzer. Signed-off-by: Maksim Salau --- boards/arm/nucleo_f042k6/nucleo_f042k6.dts | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/boards/arm/nucleo_f042k6/nucleo_f042k6.dts b/boards/arm/nucleo_f042k6/nucleo_f042k6.dts index d3afe9e59e3..ac1659dfc39 100644 --- a/boards/arm/nucleo_f042k6/nucleo_f042k6.dts +++ b/boards/arm/nucleo_f042k6/nucleo_f042k6.dts @@ -30,7 +30,7 @@ pwmleds { compatible = "pwm-leds"; green_pwm_led: green_pwm_led { - pwms = <&pwm3 32 PWM_MSEC(20) PWM_POLARITY_NORMAL>; + pwms = <&pwm3 3 PWM_MSEC(20) PWM_POLARITY_NORMAL>; }; }; @@ -66,6 +66,7 @@ &timers3 { status = "okay"; + st,prescaler = <10000>; pwm3: pwm { status = "okay"; From a4de15ba1c521cb65c2a87d17c0cb27f77341866 Mon Sep 17 00:00:00 2001 From: TOKITA Hiroshi Date: Wed, 10 Jan 2024 23:19:30 +0900 Subject: [PATCH 2576/3723] drivers: display: sdl: Add config for switch hardware accelerator Add SDL_DISPLAY_USE_HARDWARE_ACCELEREATOR to be able to switch enable/disable hardware accelerator. Signed-off-by: TOKITA Hiroshi --- drivers/display/Kconfig.sdl | 6 ++++++ drivers/display/display_sdl.c | 5 ++++- drivers/display/display_sdl_bottom.c | 9 +++++++-- drivers/display/display_sdl_bottom.h | 2 +- 4 files changed, 18 insertions(+), 4 deletions(-) diff --git a/drivers/display/Kconfig.sdl b/drivers/display/Kconfig.sdl index 5bf18115a33..28526fa840a 100644 --- a/drivers/display/Kconfig.sdl +++ b/drivers/display/Kconfig.sdl @@ -46,4 +46,10 @@ config SDL_DISPLAY_ZOOM_PCT help SDL window zoom percentage to adjust readability on small screens +config SDL_DISPLAY_USE_HARDWARE_ACCELERATOR + bool "Use hardware accelerator" + default y + help + Enable hardware acceleration for graphics rendering + endif # SDL_DISPLAY diff --git a/drivers/display/display_sdl.c b/drivers/display/display_sdl.c index dabd0a0c0a2..fc1c2ffba9d 100644 --- a/drivers/display/display_sdl.c +++ b/drivers/display/display_sdl.c @@ -39,8 +39,11 @@ static int sdl_display_init(const struct device *dev) { const struct sdl_display_config *config = dev->config; struct sdl_display_data *disp_data = dev->data; + bool use_accelerator = true; LOG_DBG("Initializing display driver"); + IF_DISABLED(CONFIG_SDL_DISPLAY_USE_HARDWARE_ACCELERATOR, (use_accelerator = false)); + disp_data->current_pixel_format = #if defined(CONFIG_SDL_DISPLAY_DEFAULT_PIXEL_FORMAT_RGB_888) PIXEL_FORMAT_RGB_888 @@ -62,7 +65,7 @@ static int sdl_display_init(const struct device *dev) } int rc = sdl_display_init_bottom(config->height, config->width, - sdl_display_zoom_pct, + sdl_display_zoom_pct, use_accelerator, &disp_data->window, &disp_data->renderer, &disp_data->texture); diff --git a/drivers/display/display_sdl_bottom.c b/drivers/display/display_sdl_bottom.c index bfeb70a8dba..3c4018a4608 100644 --- a/drivers/display/display_sdl_bottom.c +++ b/drivers/display/display_sdl_bottom.c @@ -12,7 +12,7 @@ #include "nsi_tracing.h" int sdl_display_init_bottom(uint16_t height, uint16_t width, uint16_t zoom_pct, - void **window, void **renderer, void **texture) + bool use_accelerator, void **window, void **renderer, void **texture) { *window = SDL_CreateWindow("Zephyr Display", SDL_WINDOWPOS_UNDEFINED, SDL_WINDOWPOS_UNDEFINED, width * zoom_pct / 100, @@ -22,7 +22,12 @@ int sdl_display_init_bottom(uint16_t height, uint16_t width, uint16_t zoom_pct, return -1; } - *renderer = SDL_CreateRenderer(*window, -1, SDL_RENDERER_ACCELERATED); + if (use_accelerator) { + *renderer = SDL_CreateRenderer(*window, -1, SDL_RENDERER_ACCELERATED); + } else { + *renderer = SDL_CreateRenderer(*window, -1, SDL_RENDERER_SOFTWARE); + } + if (*renderer == NULL) { nsi_print_warning("Failed to create SDL renderer: %s", SDL_GetError()); diff --git a/drivers/display/display_sdl_bottom.h b/drivers/display/display_sdl_bottom.h index d60c8b15f40..b4245fc031d 100644 --- a/drivers/display/display_sdl_bottom.h +++ b/drivers/display/display_sdl_bottom.h @@ -21,7 +21,7 @@ extern "C" { /* Note: None of these functions are public interfaces. But internal to the SDL display driver */ int sdl_display_init_bottom(uint16_t height, uint16_t width, uint16_t zoom_pct, - void **window, void **renderer, void **texture); + bool use_accelerator, void **window, void **renderer, void **texture); void sdl_display_write_bottom(const uint16_t height, const uint16_t width, const uint16_t x, const uint16_t y, void *renderer, void *texture, From 321389df92a62234e2337b5deebf3c0e31f4f494 Mon Sep 17 00:00:00 2001 From: TOKITA Hiroshi Date: Sat, 13 Jan 2024 06:40:13 +0900 Subject: [PATCH 2577/3723] drivers: display: sdl: Correcting `display_read()` Fixed an issue where `display_read()` in the SDL driver was not working. In the current implementation, use texture to represent screen images. To read this, draw it once on another surface and then read it. Signed-off-by: TOKITA Hiroshi --- drivers/display/display_sdl.c | 168 +++++++++++++++++++++++++-- drivers/display/display_sdl_bottom.c | 62 +++++++++- drivers/display/display_sdl_bottom.h | 11 +- 3 files changed, 221 insertions(+), 20 deletions(-) diff --git a/drivers/display/display_sdl.c b/drivers/display/display_sdl.c index fc1c2ffba9d..ee65b974483 100644 --- a/drivers/display/display_sdl.c +++ b/drivers/display/display_sdl.c @@ -10,6 +10,7 @@ #include #include +#include #include #include #include "display_sdl_bottom.h" @@ -29,10 +30,13 @@ struct sdl_display_config { struct sdl_display_data { void *window; void *renderer; + void *mutex; void *texture; + void *read_texture; bool display_on; enum display_pixel_format current_pixel_format; uint8_t *buf; + uint8_t *read_buf; }; static int sdl_display_init(const struct device *dev) @@ -64,10 +68,10 @@ static int sdl_display_init(const struct device *dev) sdl_display_zoom_pct = CONFIG_SDL_DISPLAY_ZOOM_PCT; } - int rc = sdl_display_init_bottom(config->height, config->width, - sdl_display_zoom_pct, use_accelerator, - &disp_data->window, &disp_data->renderer, - &disp_data->texture); + int rc = sdl_display_init_bottom(config->height, config->width, sdl_display_zoom_pct, + use_accelerator, &disp_data->window, &disp_data->renderer, + &disp_data->mutex, &disp_data->texture, + &disp_data->read_texture); if (rc != 0) { LOG_ERR("Failed to create SDL display"); @@ -248,28 +252,166 @@ static int sdl_display_write(const struct device *dev, const uint16_t x, } sdl_display_write_bottom(desc->height, desc->width, x, y, - disp_data->renderer, disp_data->texture, + disp_data->renderer, disp_data->mutex, disp_data->texture, disp_data->buf, disp_data->display_on); return 0; } +static void sdl_display_read_argb8888(const uint8_t *read_buf, + const struct display_buffer_descriptor *desc, void *buf) +{ + __ASSERT((desc->pitch * 4U * desc->height) <= desc->buf_size, "Read buffer is too small"); + + memcpy(buf, read_buf, desc->pitch * 4U * desc->height); +} + +static void sdl_display_read_rgb888(const uint8_t *read_buf, + const struct display_buffer_descriptor *desc, void *buf) +{ + uint32_t w_idx; + uint32_t h_idx; + uint8_t *buf8; + const uint32_t *pix_ptr; + + __ASSERT((desc->pitch * 3U * desc->height) <= desc->buf_size, "Read buffer is too small"); + + for (h_idx = 0U; h_idx < desc->height; ++h_idx) { + buf8 = ((uint8_t *)buf) + desc->pitch * 3U * h_idx; + + for (w_idx = 0U; w_idx < desc->width; ++w_idx) { + pix_ptr = (const uint32_t *)read_buf + ((h_idx * desc->pitch) + w_idx); + *buf8 = (*pix_ptr & 0xFF0000) >> 16; + buf8 += 1; + *buf8 = (*pix_ptr & 0xFF00) >> 8; + buf8 += 1; + *buf8 = (*pix_ptr & 0xFF); + buf8 += 1; + } + } +} + +static void sdl_display_read_rgb565(const uint8_t *read_buf, + const struct display_buffer_descriptor *desc, void *buf) +{ + uint32_t w_idx; + uint32_t h_idx; + uint16_t pixel; + uint16_t *buf16; + const uint32_t *pix_ptr; + + __ASSERT((desc->pitch * 2U * desc->height) <= desc->buf_size, "Read buffer is too small"); + + for (h_idx = 0U; h_idx < desc->height; ++h_idx) { + buf16 = (void *)(((uint8_t *)buf) + desc->pitch * 2U * h_idx); + + for (w_idx = 0U; w_idx < desc->width; ++w_idx) { + pix_ptr = (const uint32_t *)read_buf + ((h_idx * desc->pitch) + w_idx); + pixel = (*pix_ptr & 0xF80000) >> 8; + pixel |= (*pix_ptr & 0x00FC00) >> 5; + pixel |= (*pix_ptr & 0x0000F8) >> 3; + *buf16 = sys_be16_to_cpu(pixel); + buf16 += 1; + } + } +} + +static void sdl_display_read_bgr565(const uint8_t *read_buf, + const struct display_buffer_descriptor *desc, void *buf) +{ + uint32_t w_idx; + uint32_t h_idx; + uint16_t pixel; + uint16_t *buf16; + const uint32_t *pix_ptr; + + __ASSERT((desc->pitch * 2U * desc->height) <= desc->buf_size, "Read buffer is too small"); + + for (h_idx = 0U; h_idx < desc->height; ++h_idx) { + buf16 = (void *)(((uint8_t *)buf) + desc->pitch * 2U * h_idx); + + for (w_idx = 0U; w_idx < desc->width; ++w_idx) { + pix_ptr = (const uint32_t *)read_buf + ((h_idx * desc->pitch) + w_idx); + pixel = (*pix_ptr & 0xF80000) >> 8; + pixel |= (*pix_ptr & 0x00FC00) >> 5; + pixel |= (*pix_ptr & 0x0000F8) >> 3; + *buf16 = pixel; + buf16 += 1; + } + } +} + +static void sdl_display_read_mono(const uint8_t *read_buf, + const struct display_buffer_descriptor *desc, void *buf, + const bool one_is_black) +{ + uint32_t w_idx; + uint32_t h_idx; + uint32_t tile_idx; + uint8_t tile; + const uint32_t *pix_ptr; + uint8_t *buf8; + + __ASSERT((desc->pitch * desc->height) <= (desc->buf_size * 8U), "Read buffer is too small"); + __ASSERT((desc->height % 8U) == 0U, "Read buffer height not aligned per 8 pixels"); + + for (tile_idx = 0U; tile_idx < (desc->height / 8U); ++tile_idx) { + buf8 = (void *)(((uint8_t *)buf) + desc->pitch * tile_idx); + + for (w_idx = 0U; w_idx < desc->width; ++w_idx) { + tile = 0; + + for (h_idx = 0U; h_idx < 8; ++h_idx) { + pix_ptr = (const uint32_t *)read_buf + + ((tile_idx * 8 + h_idx) * desc->pitch + w_idx); + if ((*pix_ptr)) { + tile |= BIT(7 - h_idx); + } + } + *buf8 = one_is_black ? ~tile : tile; + buf8 += 1; + } + } +} + static int sdl_display_read(const struct device *dev, const uint16_t x, const uint16_t y, const struct display_buffer_descriptor *desc, void *buf) { struct sdl_display_data *disp_data = dev->data; + int err; LOG_DBG("Reading %dx%d (w,h) bitmap @ %dx%d (x,y)", desc->width, desc->height, x, y); - __ASSERT(desc->width <= desc->pitch, "Pitch is smaller then width"); - __ASSERT((desc->pitch * 3U * desc->height) <= desc->buf_size, - "Input buffer to small"); + __ASSERT(desc->width <= desc->pitch, "Pitch is smaller than width"); + + memset(disp_data->read_buf, 0, desc->pitch * desc->height * 4); + + err = sdl_display_read_bottom(desc->height, desc->width, x, y, disp_data->renderer, + disp_data->read_buf, desc->pitch, disp_data->mutex, + disp_data->texture, disp_data->read_texture); + + if (err) { + return err; + } - return sdl_display_read_bottom(desc->height, desc->width, x, y, - disp_data->renderer, buf, desc->pitch); + if (disp_data->current_pixel_format == PIXEL_FORMAT_ARGB_8888) { + sdl_display_read_argb8888(disp_data->read_buf, desc, buf); + } else if (disp_data->current_pixel_format == PIXEL_FORMAT_RGB_888) { + sdl_display_read_rgb888(disp_data->read_buf, desc, buf); + } else if (disp_data->current_pixel_format == PIXEL_FORMAT_MONO10) { + sdl_display_read_mono(disp_data->read_buf, desc, buf, true); + } else if (disp_data->current_pixel_format == PIXEL_FORMAT_MONO01) { + sdl_display_read_mono(disp_data->read_buf, desc, buf, false); + } else if (disp_data->current_pixel_format == PIXEL_FORMAT_RGB_565) { + sdl_display_read_rgb565(disp_data->read_buf, desc, buf); + } else if (disp_data->current_pixel_format == PIXEL_FORMAT_BGR_565) { + sdl_display_read_bgr565(disp_data->read_buf, desc, buf); + } + + return 0; } static int sdl_display_blanking_off(const struct device *dev) @@ -339,7 +481,8 @@ static int sdl_display_set_pixel_format(const struct device *dev, static void sdl_display_cleanup(struct sdl_display_data *disp_data) { - sdl_display_cleanup_bottom(&disp_data->window, &disp_data->renderer, &disp_data->texture); + sdl_display_cleanup_bottom(&disp_data->window, &disp_data->renderer, &disp_data->mutex, + &disp_data->texture, &disp_data->read_texture); } static const struct display_driver_api sdl_display_api = { @@ -359,8 +502,11 @@ static const struct display_driver_api sdl_display_api = { \ static uint8_t sdl_buf_##n[4 * DT_INST_PROP(n, height) \ * DT_INST_PROP(n, width)]; \ + static uint8_t sdl_read_buf_##n[4 * DT_INST_PROP(n, height) \ + * DT_INST_PROP(n, width)]; \ static struct sdl_display_data sdl_data_##n = { \ .buf = sdl_buf_##n, \ + .read_buf = sdl_read_buf_##n, \ }; \ \ DEVICE_DT_INST_DEFINE(n, &sdl_display_init, NULL, \ diff --git a/drivers/display/display_sdl_bottom.c b/drivers/display/display_sdl_bottom.c index 3c4018a4608..0e995a341c9 100644 --- a/drivers/display/display_sdl_bottom.c +++ b/drivers/display/display_sdl_bottom.c @@ -12,7 +12,8 @@ #include "nsi_tracing.h" int sdl_display_init_bottom(uint16_t height, uint16_t width, uint16_t zoom_pct, - bool use_accelerator, void **window, void **renderer, void **texture) + bool use_accelerator, void **window, void **renderer, void **mutex, + void **texture, void **read_texture) { *window = SDL_CreateWindow("Zephyr Display", SDL_WINDOWPOS_UNDEFINED, SDL_WINDOWPOS_UNDEFINED, width * zoom_pct / 100, @@ -34,6 +35,12 @@ int sdl_display_init_bottom(uint16_t height, uint16_t width, uint16_t zoom_pct, return -1; } + *mutex = SDL_CreateMutex(); + if (*mutex == NULL) { + nsi_print_warning("Failed to create SDL mutex: %s", SDL_GetError()); + return -1; + } + SDL_RenderSetLogicalSize(*renderer, width, height); *texture = SDL_CreateTexture(*renderer, SDL_PIXELFORMAT_ARGB8888, @@ -43,6 +50,13 @@ int sdl_display_init_bottom(uint16_t height, uint16_t width, uint16_t zoom_pct, return -1; } + *read_texture = SDL_CreateTexture(*renderer, SDL_PIXELFORMAT_ARGB8888, + SDL_TEXTUREACCESS_TARGET, width, height); + if (*read_texture == NULL) { + nsi_print_warning("Failed to create SDL texture for read: %s", SDL_GetError()); + return -1; + } + SDL_SetRenderDrawColor(*renderer, 0, 0, 0, 0xFF); SDL_RenderClear(*renderer); SDL_RenderPresent(*renderer); @@ -52,16 +66,23 @@ int sdl_display_init_bottom(uint16_t height, uint16_t width, uint16_t zoom_pct, void sdl_display_write_bottom(const uint16_t height, const uint16_t width, const uint16_t x, const uint16_t y, - void *renderer, void *texture, + void *renderer, void *mutex, void *texture, uint8_t *buf, bool display_on) { SDL_Rect rect; + int err; rect.x = x; rect.y = y; rect.w = width; rect.h = height; + err = SDL_TryLockMutex(mutex); + if (err) { + nsi_print_warning("Failed to lock SDL mutex: %s", SDL_GetError()); + return; + } + SDL_UpdateTexture(texture, &rect, buf, 4 * rect.w); if (display_on) { @@ -69,20 +90,40 @@ void sdl_display_write_bottom(const uint16_t height, const uint16_t width, SDL_RenderCopy(renderer, texture, NULL, NULL); SDL_RenderPresent(renderer); } + + SDL_UnlockMutex(mutex); } int sdl_display_read_bottom(const uint16_t height, const uint16_t width, const uint16_t x, const uint16_t y, - void *renderer, void *buf, uint16_t pitch) + void *renderer, void *buf, uint16_t pitch, + void *mutex, void *texture, void *read_texture) { SDL_Rect rect; + int err; rect.x = x; rect.y = y; rect.w = width; rect.h = height; - return SDL_RenderReadPixels(renderer, &rect, 0, buf, pitch * 4U); + err = SDL_TryLockMutex(mutex); + if (err) { + nsi_print_warning("Failed to lock SDL mutex: %s", SDL_GetError()); + return -1; + } + + SDL_SetRenderTarget(renderer, read_texture); + + SDL_RenderClear(renderer); + SDL_RenderCopy(renderer, texture, NULL, NULL); + SDL_RenderReadPixels(renderer, &rect, SDL_PIXELFORMAT_ARGB8888, buf, width * 4); + + SDL_SetRenderTarget(renderer, NULL); + + SDL_UnlockMutex(mutex); + + return err; } void sdl_display_blanking_off_bottom(void *renderer, void *texture) @@ -98,13 +139,24 @@ void sdl_display_blanking_on_bottom(void *renderer) SDL_RenderPresent(renderer); } -void sdl_display_cleanup_bottom(void **window, void **renderer, void **texture) +void sdl_display_cleanup_bottom(void **window, void **renderer, void **mutex, void **texture, + void **read_texture) { + if (*read_texture != NULL) { + SDL_DestroyTexture(*read_texture); + *read_texture = NULL; + } + if (*texture != NULL) { SDL_DestroyTexture(*texture); *texture = NULL; } + if (*mutex != NULL) { + SDL_DestroyMutex(*mutex); + *mutex = NULL; + } + if (*renderer != NULL) { SDL_DestroyRenderer(*renderer); *renderer = NULL; diff --git a/drivers/display/display_sdl_bottom.h b/drivers/display/display_sdl_bottom.h index b4245fc031d..54973777f1b 100644 --- a/drivers/display/display_sdl_bottom.h +++ b/drivers/display/display_sdl_bottom.h @@ -21,17 +21,20 @@ extern "C" { /* Note: None of these functions are public interfaces. But internal to the SDL display driver */ int sdl_display_init_bottom(uint16_t height, uint16_t width, uint16_t zoom_pct, - bool use_accelerator, void **window, void **renderer, void **texture); + bool use_accelerator, void **window, void **renderer, void **mutex, + void **texture, void **read_texture); void sdl_display_write_bottom(const uint16_t height, const uint16_t width, const uint16_t x, const uint16_t y, - void *renderer, void *texture, + void *renderer, void *mutex, void *texture, uint8_t *buf, bool display_on); int sdl_display_read_bottom(const uint16_t height, const uint16_t width, const uint16_t x, const uint16_t y, - void *renderer, void *buf, uint16_t pitch); + void *renderer, void *buf, uint16_t pitch, + void *mutex, void *texture, void **read_texture); void sdl_display_blanking_off_bottom(void *renderer, void *texture); void sdl_display_blanking_on_bottom(void *renderer); -void sdl_display_cleanup_bottom(void **window, void **renderer, void **texture); +void sdl_display_cleanup_bottom(void **window, void **renderer, void **mutex, void **texture, + void **read_texture); #ifdef __cplusplus } From 6489255648ffad9100eb25d08f92cf2d5ac9bfb7 Mon Sep 17 00:00:00 2001 From: TOKITA Hiroshi Date: Sun, 14 Jan 2024 05:23:02 +0900 Subject: [PATCH 2578/3723] drivers: display: sdl: add SDL_DISPLAY_MONO_MSB_FIRST option Added config for specifying bit order when using monochrome format. Signed-off-by: TOKITA Hiroshi --- drivers/display/Kconfig.sdl | 7 +++++++ drivers/display/display_sdl.c | 15 ++++++++++++--- 2 files changed, 19 insertions(+), 3 deletions(-) diff --git a/drivers/display/Kconfig.sdl b/drivers/display/Kconfig.sdl index 28526fa840a..bfa1f07c48e 100644 --- a/drivers/display/Kconfig.sdl +++ b/drivers/display/Kconfig.sdl @@ -52,4 +52,11 @@ config SDL_DISPLAY_USE_HARDWARE_ACCELERATOR help Enable hardware acceleration for graphics rendering +config SDL_DISPLAY_MONO_MSB_FIRST + bool "Configure bit order in monochrome formats to MSB first" + default y + help + If selected, set the MSB to represent the first pixel. + This applies when the pixel format is MONO01/MONO10. + endif # SDL_DISPLAY diff --git a/drivers/display/display_sdl.c b/drivers/display/display_sdl.c index ee65b974483..f21288d1b0f 100644 --- a/drivers/display/display_sdl.c +++ b/drivers/display/display_sdl.c @@ -39,6 +39,15 @@ struct sdl_display_data { uint8_t *read_buf; }; +static inline uint32_t mono_pixel_order(uint32_t order) +{ + if (IS_ENABLED(CONFIG_SDL_DISPLAY_MONO_MSB_FIRST)) { + return BIT(7 - order); + } else { + return BIT(order); + } +} + static int sdl_display_init(const struct device *dev) { const struct sdl_display_config *config = dev->config; @@ -195,7 +204,7 @@ static void sdl_display_write_mono(uint8_t *disp_buf, ((tile_idx * desc->pitch) + w_idx); disp_buf_start = disp_buf; for (h_idx = 0U; h_idx < 8; ++h_idx) { - if ((*byte_ptr & BIT(7-h_idx)) != 0U) { + if ((*byte_ptr & mono_pixel_order(h_idx)) != 0U) { pixel = one_color; } else { pixel = (~one_color) & 0x00FFFFFF; @@ -365,7 +374,7 @@ static void sdl_display_read_mono(const uint8_t *read_buf, pix_ptr = (const uint32_t *)read_buf + ((tile_idx * 8 + h_idx) * desc->pitch + w_idx); if ((*pix_ptr)) { - tile |= BIT(7 - h_idx); + tile |= mono_pixel_order(h_idx); } } *buf8 = one_is_black ? ~tile : tile; @@ -456,7 +465,7 @@ static void sdl_display_get_capabilities( PIXEL_FORMAT_BGR_565; capabilities->current_pixel_format = disp_data->current_pixel_format; capabilities->screen_info = SCREEN_INFO_MONO_VTILED | - SCREEN_INFO_MONO_MSB_FIRST; + (IS_ENABLED(CONFIG_SDL_DISPLAY_MONO_MSB_FIRST) ? SCREEN_INFO_MONO_MSB_FIRST : 0); } static int sdl_display_set_pixel_format(const struct device *dev, From 3578a9e646ab1803ca49662f938b5cfdf09e09dd Mon Sep 17 00:00:00 2001 From: TOKITA Hiroshi Date: Wed, 10 Jan 2024 18:11:49 +0900 Subject: [PATCH 2579/3723] tests: drivers: display: add read() and write() test Add test for `display_read()` and `display_write()` api. Note: The CI environment has no display device, which makes it fail the tests. So, I make this test case `build_only`. But it can run in a display device available environment. Signed-off-by: TOKITA Hiroshi --- .../display/display_read_write/CMakeLists.txt | 9 + .../display/display_read_write/prj.conf | 9 + .../display/display_read_write/src/main.c | 268 ++++++++++++++++++ .../display/display_read_write/testcase.yaml | 52 ++++ 4 files changed, 338 insertions(+) create mode 100644 tests/drivers/display/display_read_write/CMakeLists.txt create mode 100644 tests/drivers/display/display_read_write/prj.conf create mode 100644 tests/drivers/display/display_read_write/src/main.c create mode 100644 tests/drivers/display/display_read_write/testcase.yaml diff --git a/tests/drivers/display/display_read_write/CMakeLists.txt b/tests/drivers/display/display_read_write/CMakeLists.txt new file mode 100644 index 00000000000..3c88f23c187 --- /dev/null +++ b/tests/drivers/display/display_read_write/CMakeLists.txt @@ -0,0 +1,9 @@ +# Copyright 2024 (c) TOKITA Hiroshi +# SPDX-License-Identifier: Apache-2.0 + +cmake_minimum_required(VERSION 3.20.0) +find_package(Zephyr REQUIRED HINTS $ENV{ZEPHYR_BASE}) + +project(display_read_write) + +target_sources(app PRIVATE src/main.c) diff --git a/tests/drivers/display/display_read_write/prj.conf b/tests/drivers/display/display_read_write/prj.conf new file mode 100644 index 00000000000..c18b5f93da9 --- /dev/null +++ b/tests/drivers/display/display_read_write/prj.conf @@ -0,0 +1,9 @@ +# Copyright 2024 (c) TOKITA Hiroshi +# SPDX-License-Identifier: Apache-2.0 + +CONFIG_ZTEST=y +CONFIG_DISPLAY=y + +CONFIG_HEAP_MEM_POOL_SIZE=16384 + +CONFIG_LOG=y diff --git a/tests/drivers/display/display_read_write/src/main.c b/tests/drivers/display/display_read_write/src/main.c new file mode 100644 index 00000000000..2ae246e4fb9 --- /dev/null +++ b/tests/drivers/display/display_read_write/src/main.c @@ -0,0 +1,268 @@ +/* + * Copyright 2024 (c) TOKITA Hiroshi + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include +#include +#include +#include + +LOG_MODULE_DECLARE(display_api, CONFIG_DISPLAY_LOG_LEVEL); + +static const struct device *dev = DEVICE_DT_GET(DT_CHOSEN(zephyr_display)); +static const uint32_t display_width = DT_PROP(DT_CHOSEN(zephyr_display), width); +static const uint32_t display_height = DT_PROP(DT_CHOSEN(zephyr_display), height); +static uint8_t disp_buffer[DT_PROP(DT_CHOSEN(zephyr_display), width) * + DT_PROP(DT_CHOSEN(zephyr_display), height) * 4]; +static struct display_capabilities cfg; +static uint8_t bpp; +static bool is_tiled; + +static inline uint8_t bytes_per_pixel(enum display_pixel_format pixel_format) +{ + switch (pixel_format) { + case PIXEL_FORMAT_ARGB_8888: + return 4; + case PIXEL_FORMAT_RGB_888: + return 3; + case PIXEL_FORMAT_RGB_565: + case PIXEL_FORMAT_BGR_565: + return 2; + case PIXEL_FORMAT_MONO01: + case PIXEL_FORMAT_MONO10: + default: + return 1; + } + + return 0; +} + +static void verify_bytes_of_area(uint8_t *data, int cmp_x, int cmp_y, size_t width, size_t height) +{ + struct display_buffer_descriptor desc = { + .height = height, + .pitch = width, + .width = width, + .buf_size = height * width * bpp, + }; + + int err = display_read(dev, cmp_x, cmp_y, &desc, disp_buffer); + + zassert_ok(err, "display_read failed"); + + if (is_tiled) { + zassert_mem_equal(data, disp_buffer, width * height / 8, NULL); + } else { + zassert_mem_equal(data, disp_buffer, width * height * bpp, NULL); + } +} + +static void verify_background_color(int x, int y, size_t width, size_t height, uint32_t color) +{ + size_t buf_size = is_tiled ? (height * width / 8) : (height * width * bpp); + struct display_buffer_descriptor desc = { + .height = height, + .pitch = width, + .width = width, + .buf_size = buf_size, + }; + uint32_t *buf32 = (void *)disp_buffer; + uint16_t *buf16 = (void *)disp_buffer; + uint8_t *buf8 = disp_buffer; + int err; + + err = display_read(dev, x, y, &desc, disp_buffer); + zassert_ok(err, "display_read failed"); + + for (size_t i = 0; i < width * height; i++) { + switch (bpp) { + case 4: + zassert_equal(buf32[i], color, "@%d", i); + break; + case 2: + zassert_equal(buf16[i], (uint16_t)color, "@%d", i); + break; + case 1: + if (is_tiled) { + uint16_t x = i % (width); + uint16_t line = (i - x) / width; + uint16_t tile = line / 8; + uint16_t y = line % 8; + + uint8_t *tptr = disp_buffer + (tile * width + x); + + zassert_equal(!!(*tptr & BIT(y)), !!(color), "@%d", i); + } else { + zassert_equal(buf8[i], (uint8_t)color, "@%d", i); + } + break; + } + } +} + +/** + * Fill the buffer with 0 before running tests. + */ +static void display_before(void *text_fixture) +{ + display_get_capabilities(dev, &cfg); + bpp = bytes_per_pixel(cfg.current_pixel_format); + is_tiled = ((bpp == 1) && (cfg.screen_info & SCREEN_INFO_MONO_VTILED)); + + struct display_buffer_descriptor desc = { + .height = display_height, + .pitch = display_width, + .width = display_width, + .buf_size = display_height * display_width * bpp, + }; + + memset(disp_buffer, 0, sizeof(disp_buffer)); + display_write(dev, 0, 0, &desc, disp_buffer); +} + +/* + * Verify that we can get a color of '0' from all pixels + * when after zeroing the buffer. + */ +ZTEST(display_read_write, test_clear) +{ + verify_background_color(0, 0, display_width, display_height, 0); +} + +/* + * Write to the head of the buffer and check that + * the same value can be read. + */ +ZTEST(display_read_write, test_write_to_buffer_head) +{ + uint8_t data[4] = {0xFA, 0xAF, 0x9F, 0xFA}; + uint8_t height = (is_tiled ? 8 : 1); + uint16_t width = sizeof(data) / bpp; + uint16_t buf_size = width * bpp; + struct display_buffer_descriptor desc = { + .height = height, + .pitch = width, + .width = width, + .buf_size = buf_size, + }; + + /* write data to head of buffer */ + display_write(dev, 0, 0, &desc, data); + + /* check write data and read data are same */ + verify_bytes_of_area(data, 0, 0, width, height); + + /* check remaining region still black */ + verify_background_color(0, height, display_width, display_height - height, 0); + verify_background_color(width, 0, display_width - width, display_height, 0); +} + +/* + * Write to the tail of the buffer and check that + * the same value can be read. + */ +ZTEST(display_read_write, test_write_to_buffer_tail) +{ + uint8_t data[4] = {0xFA, 0xAF, 0x9F, 0xFA}; + uint16_t height = (is_tiled ? 8 : 1); + uint16_t width = sizeof(data) / bpp; + uint16_t buf_size = width * bpp; + struct display_buffer_descriptor desc = { + .height = height, + .pitch = width, + .width = width, + .buf_size = buf_size, + }; + struct display_buffer_descriptor desc_whole = { + .height = display_height, + .pitch = display_width, + .width = display_width, + .buf_size = display_height * display_width * bpp / height, + }; + int err; + + /* write data to tail of buffer */ + display_write(dev, display_width - width, display_height - height, &desc, data); + + /* read entire displayed data */ + err = display_read(dev, 0, 0, &desc_whole, disp_buffer); + zassert_ok(err, "display_read failed"); + + /* check write data and read data are same */ + if (is_tiled) { + zassert_mem_equal(data, + disp_buffer + (display_width * display_height / 8 - buf_size), + buf_size, NULL); + } else { + zassert_mem_equal(data, + disp_buffer + (display_width * display_height * bpp - buf_size), + buf_size, NULL); + } + + /* check remaining region still black */ + verify_background_color(0, 0, display_width, display_height - height, 0); + verify_background_color(0, display_height - height, display_width - width, height, 0); +} + +/* + * Verify that it will keep the drawn content even if display_read is executed + */ +ZTEST(display_read_write, test_read_does_not_clear_existing_buffer) +{ + uint8_t data[4] = {0xFA, 0xAF, 0x9F, 0xFA}; + uint8_t height = (is_tiled ? 8 : 1); + uint16_t width = sizeof(data) / bpp; + uint16_t buf_size = width * bpp; + struct display_buffer_descriptor desc = { + .height = height, + .pitch = width, + .width = width, + .buf_size = buf_size, + }; + struct display_buffer_descriptor desc_whole = { + .height = display_height, + .pitch = display_width, + .width = display_width, + .buf_size = display_height * display_width * bpp / height, + }; + int err; + + /* write data to head of buffer */ + display_write(dev, 0, 0, &desc, data); + + /* check write data and read data are same */ + verify_bytes_of_area(data, 0, 0, width, height); + + /* check remaining region still black */ + verify_background_color(0, height, display_width, display_height - height, 0); + verify_background_color(width, 0, display_width - width, display_height, 0); + + /* write data to tail of buffer */ + display_write(dev, display_width - width, display_height - height, &desc, data); + + /* read entire displayed data */ + err = display_read(dev, 0, 0, &desc_whole, disp_buffer); + zassert_ok(err, "display_read failed"); + + /* checking correctly write to the tail of buffer */ + if (is_tiled) { + zassert_mem_equal(data, + disp_buffer + (display_width * display_height / 8 - buf_size), + buf_size, NULL); + } else { + zassert_mem_equal(data, + disp_buffer + (display_width * display_height * bpp - buf_size), + buf_size, NULL); + } + + /* checking if the content written before reading is kept */ + verify_bytes_of_area(data, 0, 0, width, height); + + /* checking remaining region is still black */ + verify_background_color(width, 0, display_width - width, display_height - height, 0); + verify_background_color(0, height, display_width - width, display_height - height, 0); +} + +ZTEST_SUITE(display_read_write, NULL, NULL, display_before, NULL, NULL); diff --git a/tests/drivers/display/display_read_write/testcase.yaml b/tests/drivers/display/display_read_write/testcase.yaml new file mode 100644 index 00000000000..e991a022d48 --- /dev/null +++ b/tests/drivers/display/display_read_write/testcase.yaml @@ -0,0 +1,52 @@ +# Copyright 2024 (c) TOKITA Hiroshi +# SPDX-License-Identifier: Apache-2.0 + +common: + tags: + - drivers + - display + filter: dt_chosen_enabled("zephyr,display") + build_only: true # The CI environment has no display device +tests: + drivers.display.read_write.sdl.argb8888: + filter: dt_compat_enabled("zephyr,sdl-dc") + extra_configs: + - CONFIG_SDL_DISPLAY_DEFAULT_PIXEL_FORMAT_ARGB_8888=y + - CONFIG_SDL_DISPLAY_USE_HARDWARE_ACCELERATOR=n + drivers.display.read_write.sdl.rgb888: + filter: dt_compat_enabled("zephyr,sdl-dc") + extra_configs: + - CONFIG_SDL_DISPLAY_DEFAULT_PIXEL_FORMAT_RGB_888=y + - CONFIG_SDL_DISPLAY_USE_HARDWARE_ACCELERATOR=n + drivers.display.read_write.sdl.mono01: + filter: dt_compat_enabled("zephyr,sdl-dc") + extra_configs: + - CONFIG_SDL_DISPLAY_DEFAULT_PIXEL_FORMAT_MONO01=y + - CONFIG_SDL_DISPLAY_USE_HARDWARE_ACCELERATOR=n + drivers.display.read_write.sdl.mono10: + filter: dt_compat_enabled("zephyr,sdl-dc") + extra_configs: + - CONFIG_SDL_DISPLAY_DEFAULT_PIXEL_FORMAT_MONO10=y + - CONFIG_SDL_DISPLAY_USE_HARDWARE_ACCELERATOR=n + drivers.display.read_write.sdl.mono01.lsbfirst: + filter: dt_compat_enabled("zephyr,sdl-dc") + extra_configs: + - CONFIG_SDL_DISPLAY_DEFAULT_PIXEL_FORMAT_MONO01=y + - CONFIG_SDL_DISPLAY_USE_HARDWARE_ACCELERATOR=n + - CONFIG_SDL_DISPLAY_MONO_MSB_FIRST=n + drivers.display.read_write.sdl.mono10.lsbfirst: + filter: dt_compat_enabled("zephyr,sdl-dc") + extra_configs: + - CONFIG_SDL_DISPLAY_DEFAULT_PIXEL_FORMAT_MONO10=y + - CONFIG_SDL_DISPLAY_USE_HARDWARE_ACCELERATOR=n + - CONFIG_SDL_DISPLAY_MONO_MSB_FIRST=n + drivers.display.read_write.sdl.rgb565: + filter: dt_compat_enabled("zephyr,sdl-dc") + extra_configs: + - CONFIG_SDL_DISPLAY_DEFAULT_PIXEL_FORMAT_RGB_565=y + - CONFIG_SDL_DISPLAY_USE_HARDWARE_ACCELERATOR=n + drivers.display.read_write.sdl.bgr565: + filter: dt_compat_enabled("zephyr,sdl-dc") + extra_configs: + - CONFIG_SDL_DISPLAY_DEFAULT_PIXEL_FORMAT_BGR_565=y + - CONFIG_SDL_DISPLAY_USE_HARDWARE_ACCELERATOR=n From 7af4f7eb8a2ca9cd2eb3e5b2d2c74f31d2b2263e Mon Sep 17 00:00:00 2001 From: Gerard Marull-Paretas Date: Thu, 18 Jan 2024 15:25:29 +0100 Subject: [PATCH 2580/3723] arch: riscv: offsets: fix header race condition It looks like some soc_offsets.h files need to be included before kernel_offsets, otherwise there are some header race conditions due to the infamous soc.h. This problem is exposed if all soc.h are removed from RISC-V arch header files (see the upcoming commits). It can be reproduced by building rv32m1_vega_ri5cy board after applying all the patches in this series (excluding this one, of course). Signed-off-by: Gerard Marull-Paretas --- arch/riscv/core/offsets/offsets.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/arch/riscv/core/offsets/offsets.c b/arch/riscv/core/offsets/offsets.c index 7730138a376..96982341b1a 100644 --- a/arch/riscv/core/offsets/offsets.c +++ b/arch/riscv/core/offsets/offsets.c @@ -16,7 +16,6 @@ #include #include #include -#include #ifdef CONFIG_RISCV_SOC_CONTEXT_SAVE #include @@ -25,6 +24,8 @@ #include #endif +#include + /* struct _callee_saved member offsets */ GEN_OFFSET_SYM(_callee_saved_t, sp); GEN_OFFSET_SYM(_callee_saved_t, ra); From a5ded8aa9f75851931f1eb321a0e19790eb3181f Mon Sep 17 00:00:00 2001 From: Gerard Marull-Paretas Date: Tue, 16 Jan 2024 14:54:01 +0100 Subject: [PATCH 2581/3723] arch: riscv: smp: define MSIP_BASE Instead of relying on definitions included indirectly. Signed-off-by: Gerard Marull-Paretas --- arch/riscv/core/smp.c | 3 ++- soc/riscv/microchip_miv/polarfire/soc.h | 3 --- soc/riscv/virt/soc.h | 1 - 3 files changed, 2 insertions(+), 5 deletions(-) diff --git a/arch/riscv/core/smp.c b/arch/riscv/core/smp.c index 941213ab49a..54de29c0551 100644 --- a/arch/riscv/core/smp.c +++ b/arch/riscv/core/smp.c @@ -79,7 +79,8 @@ void arch_secondary_cpu_init(int hartid) #ifdef CONFIG_SMP -#define MSIP(hartid) ((volatile uint32_t *)RISCV_MSIP_BASE)[hartid] +#define MSIP_BASE 0x2000000UL +#define MSIP(hartid) ((volatile uint32_t *)MSIP_BASE)[hartid] static atomic_val_t cpu_pending_ipi[CONFIG_MP_MAX_NUM_CPUS]; #define IPI_SCHED 0 diff --git a/soc/riscv/microchip_miv/polarfire/soc.h b/soc/riscv/microchip_miv/polarfire/soc.h index f12bea7d533..3bcb9569c6e 100644 --- a/soc/riscv/microchip_miv/polarfire/soc.h +++ b/soc/riscv/microchip_miv/polarfire/soc.h @@ -8,7 +8,4 @@ #include - -#define RISCV_MSIP_BASE 0x02000000 - #endif /* __RISCV64_MPFS_SOC_H_ */ diff --git a/soc/riscv/virt/soc.h b/soc/riscv/virt/soc.h index d821c4653e6..8aa4238010c 100644 --- a/soc/riscv/virt/soc.h +++ b/soc/riscv/virt/soc.h @@ -8,6 +8,5 @@ #define __RISCV_VIRT_SOC_H_ #define SIFIVE_SYSCON_TEST 0x00100000 -#define RISCV_MSIP_BASE 0x02000000 #endif From 27f14eb3a8236a50efaddbc0f1d55921e1e8d6b4 Mon Sep 17 00:00:00 2001 From: Gerard Marull-Paretas Date: Thu, 18 Jan 2024 17:22:37 +0100 Subject: [PATCH 2582/3723] bluetooth: controller: ll_sw: RV32M1: add missing include cntr.c accesses some registers defined in fsl_device_registers.h. Signed-off-by: Gerard Marull-Paretas --- subsys/bluetooth/controller/ll_sw/openisa/hal/RV32M1/cntr.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/subsys/bluetooth/controller/ll_sw/openisa/hal/RV32M1/cntr.c b/subsys/bluetooth/controller/ll_sw/openisa/hal/RV32M1/cntr.c index e3e2496b1a4..f120a7398ad 100644 --- a/subsys/bluetooth/controller/ll_sw/openisa/hal/RV32M1/cntr.c +++ b/subsys/bluetooth/controller/ll_sw/openisa/hal/RV32M1/cntr.c @@ -15,6 +15,8 @@ #include "ll_irqs.h" +#include + #define PCS_SOURCE_RTC 2 void cntr_init(void) From c42ef7117dc97c43476f5cb278045fed10f0a37f Mon Sep 17 00:00:00 2001 From: Gerard Marull-Paretas Date: Tue, 16 Jan 2024 15:04:03 +0100 Subject: [PATCH 2583/3723] dts: riscv: sifive: fu540: add missing ngpios property FU540 SoC has 16 GPIOs, this way, the GPIO API can perform correct asserts when a pin is provided. Note that default is 32, correct for eg FE310. Signed-off-by: Gerard Marull-Paretas --- dts/riscv/sifive/riscv64-fu540.dtsi | 1 + 1 file changed, 1 insertion(+) diff --git a/dts/riscv/sifive/riscv64-fu540.dtsi b/dts/riscv/sifive/riscv64-fu540.dtsi index ed56401d462..ebb60e03aae 100644 --- a/dts/riscv/sifive/riscv64-fu540.dtsi +++ b/dts/riscv/sifive/riscv64-fu540.dtsi @@ -179,6 +179,7 @@ gpio0: gpio@10060000 { compatible = "sifive,gpio0"; gpio-controller; + ngpios = <16>; interrupt-parent = <&plic>; interrupts = <7 1>, <8 1>, <9 1>, <10 1>, <11 1>, <12 1>, <13 1>, <14 1>, From 8edd33bf27e7fdce9830fd275f15e697bc1fa3f2 Mon Sep 17 00:00:00 2001 From: Gerard Marull-Paretas Date: Thu, 18 Jan 2024 12:49:43 +0100 Subject: [PATCH 2584/3723] drivers: clock_control: litex: add missing include Drivers uses custom IO read/write API defined in soc.h. Signed-off-by: Gerard Marull-Paretas --- drivers/clock_control/clock_control_litex.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/drivers/clock_control/clock_control_litex.c b/drivers/clock_control/clock_control_litex.c index b2d04a3cc92..2eb0c6b3589 100644 --- a/drivers/clock_control/clock_control_litex.c +++ b/drivers/clock_control/clock_control_litex.c @@ -18,6 +18,8 @@ #include #include +#include + LOG_MODULE_REGISTER(CLK_CTRL_LITEX, CONFIG_CLOCK_CONTROL_LOG_LEVEL); static struct litex_clk_device *ldev; /* global struct for whole driver */ From d17405f255ad564a2e4d3f192d790f233252231c Mon Sep 17 00:00:00 2001 From: Gerard Marull-Paretas Date: Tue, 16 Jan 2024 15:28:28 +0100 Subject: [PATCH 2585/3723] drivers: gpio: atcgpio100: remove redundant include is not needed. Signed-off-by: Gerard Marull-Paretas --- drivers/gpio/gpio_andes_atcgpio100.c | 1 - 1 file changed, 1 deletion(-) diff --git a/drivers/gpio/gpio_andes_atcgpio100.c b/drivers/gpio/gpio_andes_atcgpio100.c index 4b5d18fc0a7..f7c8bdfc4da 100644 --- a/drivers/gpio/gpio_andes_atcgpio100.c +++ b/drivers/gpio/gpio_andes_atcgpio100.c @@ -12,7 +12,6 @@ #include #include #include -#include #include #include #include From 0363b74b38c3e2df4a4a001ad54b7690479d99e1 Mon Sep 17 00:00:00 2001 From: Gerard Marull-Paretas Date: Thu, 18 Jan 2024 13:08:28 +0100 Subject: [PATCH 2586/3723] drivers: gpio: mchp_mss: remove redundant include is not needed. Signed-off-by: Gerard Marull-Paretas --- drivers/gpio/gpio_mchp_mss.c | 1 - 1 file changed, 1 deletion(-) diff --git a/drivers/gpio/gpio_mchp_mss.c b/drivers/gpio/gpio_mchp_mss.c index b5b3a7033d5..7db42b77913 100644 --- a/drivers/gpio/gpio_mchp_mss.c +++ b/drivers/gpio/gpio_mchp_mss.c @@ -9,7 +9,6 @@ #include #include #include -#include #include #include #include From 9e8bd2f9761f2cff67680d81aa430e1c39966cd3 Mon Sep 17 00:00:00 2001 From: Gerard Marull-Paretas Date: Tue, 16 Jan 2024 15:05:26 +0100 Subject: [PATCH 2587/3723] drivers: gpio: sifive: remove unnecessary check The API already asserts for invalid pin based on DT `ngpios` property. Signed-off-by: Gerard Marull-Paretas --- drivers/gpio/gpio_sifive.c | 4 ---- 1 file changed, 4 deletions(-) diff --git a/drivers/gpio/gpio_sifive.c b/drivers/gpio/gpio_sifive.c index a412fdd1528..7e56b9dba3e 100644 --- a/drivers/gpio/gpio_sifive.c +++ b/drivers/gpio/gpio_sifive.c @@ -145,10 +145,6 @@ static int gpio_sifive_config(const struct device *dev, { volatile struct gpio_sifive_t *gpio = DEV_GPIO(dev); - if (pin >= SIFIVE_PINMUX_PINS) { - return -EINVAL; - } - /* We cannot support open-source open-drain configuration */ if ((flags & GPIO_SINGLE_ENDED) != 0) { return -ENOTSUP; From 0e9084ff9c461175f7e7bee39cc144fb31f33ea2 Mon Sep 17 00:00:00 2001 From: Gerard Marull-Paretas Date: Thu, 18 Jan 2024 14:49:05 +0100 Subject: [PATCH 2588/3723] drivers: i2c: litex: add missing include soc.h was missing for some IO r/w functions, e.g. litex_write8. Signed-off-by: Gerard Marull-Paretas --- drivers/i2c/i2c_litex.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/drivers/i2c/i2c_litex.c b/drivers/i2c/i2c_litex.c index a8e5f86a162..58636209bf6 100644 --- a/drivers/i2c/i2c_litex.c +++ b/drivers/i2c/i2c_litex.c @@ -10,6 +10,8 @@ #include #include "i2c_bitbang.h" +#include + #define SCL_BIT_POS 0 #define SDA_DIR_BIT_POS 1 #define SDA_BIT_W_POS 2 From 1a0c13d4aeb8795902ab79886bac34ac5fa3890b Mon Sep 17 00:00:00 2001 From: Gerard Marull-Paretas Date: Thu, 18 Jan 2024 13:09:53 +0100 Subject: [PATCH 2589/3723] drivers: i2c: mchp_mss: remove redundant include is not needed. Signed-off-by: Gerard Marull-Paretas --- drivers/i2c/i2c_mchp_mss.c | 1 - 1 file changed, 1 deletion(-) diff --git a/drivers/i2c/i2c_mchp_mss.c b/drivers/i2c/i2c_mchp_mss.c index 887579cf9a1..49b0da2a719 100644 --- a/drivers/i2c/i2c_mchp_mss.c +++ b/drivers/i2c/i2c_mchp_mss.c @@ -9,7 +9,6 @@ #include #include #include -#include #include #include #include From 436a9f22115fe91cc025bfe1417c3391d2ca9c4d Mon Sep 17 00:00:00 2001 From: Gerard Marull-Paretas Date: Tue, 16 Jan 2024 15:22:49 +0100 Subject: [PATCH 2590/3723] drivers: intc: nuclei_eclic: remove unnecessary include soc.h is empty for this platform. Signed-off-by: Gerard Marull-Paretas --- drivers/interrupt_controller/intc_nuclei_eclic.c | 1 - 1 file changed, 1 deletion(-) diff --git a/drivers/interrupt_controller/intc_nuclei_eclic.c b/drivers/interrupt_controller/intc_nuclei_eclic.c index fdd9d6ea93b..94f4d067ccb 100644 --- a/drivers/interrupt_controller/intc_nuclei_eclic.c +++ b/drivers/interrupt_controller/intc_nuclei_eclic.c @@ -13,7 +13,6 @@ #include #include #include -#include #include #include From 3381fb4b3da99cb24c43769057fb4e9c601f8327 Mon Sep 17 00:00:00 2001 From: Gerard Marull-Paretas Date: Tue, 16 Jan 2024 15:28:53 +0100 Subject: [PATCH 2591/3723] drivers: intc: plic: remove redundant include is not needed. Signed-off-by: Gerard Marull-Paretas --- drivers/interrupt_controller/intc_plic.c | 1 - 1 file changed, 1 deletion(-) diff --git a/drivers/interrupt_controller/intc_plic.c b/drivers/interrupt_controller/intc_plic.c index bdfccced192..f5f762e4aba 100644 --- a/drivers/interrupt_controller/intc_plic.c +++ b/drivers/interrupt_controller/intc_plic.c @@ -21,7 +21,6 @@ #include #include #include -#include #include #include From 7e3b3dd258c0a0db2575a2be874189cee4ff2cb9 Mon Sep 17 00:00:00 2001 From: Gerard Marull-Paretas Date: Tue, 16 Jan 2024 15:08:26 +0100 Subject: [PATCH 2592/3723] drivers: pinctrl: sifive: use DT ngpios property Instead of hardcoded definitions from soc.h. Signed-off-by: Gerard Marull-Paretas --- drivers/pinctrl/pinctrl_sifive.c | 3 ++- soc/riscv/sifive_freedom/e300/soc.h | 3 --- soc/riscv/sifive_freedom/u500/soc.h | 3 --- soc/riscv/sifive_freedom/u700/soc.h | 3 --- 4 files changed, 2 insertions(+), 10 deletions(-) diff --git a/drivers/pinctrl/pinctrl_sifive.c b/drivers/pinctrl/pinctrl_sifive.c index ff770b53a6a..7dd8c6f944f 100644 --- a/drivers/pinctrl/pinctrl_sifive.c +++ b/drivers/pinctrl/pinctrl_sifive.c @@ -13,6 +13,7 @@ #include +#define MAX_PIN_NUM DT_PROP(DT_INST_PARENT(0), ngpios) #define PINCTRL_BASE_ADDR DT_INST_REG_ADDR(0) #define PINCTRL_IOF_EN (PINCTRL_BASE_ADDR + 0x0) #define PINCTRL_IOF_SEL (PINCTRL_BASE_ADDR + 0x4) @@ -21,7 +22,7 @@ static int pinctrl_sifive_set(uint32_t pin, uint32_t func) { uint32_t val; - if (func > SIFIVE_PINMUX_IOF1 || pin >= SIFIVE_PINMUX_PINS) { + if (func > SIFIVE_PINMUX_IOF1 || pin >= MAX_PIN_NUM) { return -EINVAL; } diff --git a/soc/riscv/sifive_freedom/e300/soc.h b/soc/riscv/sifive_freedom/e300/soc.h index 3c29efb2a71..1194790bafa 100644 --- a/soc/riscv/sifive_freedom/e300/soc.h +++ b/soc/riscv/sifive_freedom/e300/soc.h @@ -11,9 +11,6 @@ #ifndef __RISCV_SIFIVE_FREEDOM_FE300_SOC_H_ #define __RISCV_SIFIVE_FREEDOM_FE300_SOC_H_ -/* PINMUX MAX PINS */ -#define SIFIVE_PINMUX_PINS 32 - /* Clock controller. */ #define PRCI_BASE_ADDR 0x10008000 diff --git a/soc/riscv/sifive_freedom/u500/soc.h b/soc/riscv/sifive_freedom/u500/soc.h index 1e18850787b..35526ed43be 100644 --- a/soc/riscv/sifive_freedom/u500/soc.h +++ b/soc/riscv/sifive_freedom/u500/soc.h @@ -14,9 +14,6 @@ /* Clock controller. */ #define PRCI_BASE_ADDR 0x10000000 -/* PINMUX MAX PINS */ -#define SIFIVE_PINMUX_PINS 16 - /* * On FE310 and FU540, peripherals such as SPI, UART, I2C and PWM are clocked * by TLCLK, which is derived from CORECLK. diff --git a/soc/riscv/sifive_freedom/u700/soc.h b/soc/riscv/sifive_freedom/u700/soc.h index 2f15ba3b1cb..aaaa13edb95 100644 --- a/soc/riscv/sifive_freedom/u700/soc.h +++ b/soc/riscv/sifive_freedom/u700/soc.h @@ -14,9 +14,6 @@ /* Clock controller. */ #define PRCI_BASE_ADDR 0x10000000 -/* PINMUX MAX PINS */ -#define SIFIVE_PINMUX_PINS 16 - /* On FU740, peripherals are clocked by PCLK. */ #define SIFIVE_PERIPHERAL_CLOCK_FREQUENCY \ DT_PROP(DT_NODELABEL(pclk), clock_frequency) From 183dd2042470be5b373f3792fe3fae860bd98593 Mon Sep 17 00:00:00 2001 From: Gerard Marull-Paretas Date: Thu, 18 Jan 2024 13:11:21 +0100 Subject: [PATCH 2593/3723] drivers: serial: neorv32: add missing include is needed for some NEORV32_SYSINFO_* definition. Signed-off-by: Gerard Marull-Paretas --- drivers/serial/uart_neorv32.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/drivers/serial/uart_neorv32.c b/drivers/serial/uart_neorv32.c index 547d1f46efb..5c14b18060e 100644 --- a/drivers/serial/uart_neorv32.c +++ b/drivers/serial/uart_neorv32.c @@ -11,9 +11,11 @@ #include #include #include - #include #include + +#include + LOG_MODULE_REGISTER(uart_neorv32, CONFIG_UART_LOG_LEVEL); /* NEORV32 UART registers offsets */ From 5e17b89804cc88f3a92af9a4bf431ead7b536e13 Mon Sep 17 00:00:00 2001 From: Gerard Marull-Paretas Date: Thu, 18 Jan 2024 14:47:45 +0100 Subject: [PATCH 2594/3723] drivers: serial: liteuart: add missing include soc.h was missing to access custom IO read/write functions, e.g. litex_read8. Signed-off-by: Gerard Marull-Paretas --- drivers/serial/uart_liteuart.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/drivers/serial/uart_liteuart.c b/drivers/serial/uart_liteuart.c index d23b68b7c5c..fe5e2580d08 100644 --- a/drivers/serial/uart_liteuart.c +++ b/drivers/serial/uart_liteuart.c @@ -14,6 +14,8 @@ #include #include +#include + #define UART_RXTX_ADDR DT_INST_REG_ADDR_BY_NAME(0, rxtx) #define UART_TXFULL_ADDR DT_INST_REG_ADDR_BY_NAME(0, txfull) #define UART_RXEMPTY_ADDR DT_INST_REG_ADDR_BY_NAME(0, rxempty) From 893a338f05b3dbd7fa8bd2937d3eea87e2632ed7 Mon Sep 17 00:00:00 2001 From: Gerard Marull-Paretas Date: Tue, 16 Jan 2024 15:35:41 +0100 Subject: [PATCH 2595/3723] drivers: serial: opentitan: remove redundant include is not needed. Signed-off-by: Gerard Marull-Paretas --- drivers/serial/uart_opentitan.c | 1 - 1 file changed, 1 deletion(-) diff --git a/drivers/serial/uart_opentitan.c b/drivers/serial/uart_opentitan.c index a762d75dac0..0d27c7a3d04 100644 --- a/drivers/serial/uart_opentitan.c +++ b/drivers/serial/uart_opentitan.c @@ -7,7 +7,6 @@ #include #include #include -#include #include /* Register offsets within the UART device register space. */ From ed166915bbd22d663e230a04c94d61a51c4d8364 Mon Sep 17 00:00:00 2001 From: Gerard Marull-Paretas Date: Thu, 18 Jan 2024 19:57:23 +0100 Subject: [PATCH 2596/3723] drivers: spi: rv32m1_lpspi: add missing include Add , for INST_DT_CLOCK_IP_NAME. Signed-off-by: Gerard Marull-Paretas --- drivers/spi/spi_rv32m1_lpspi.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/drivers/spi/spi_rv32m1_lpspi.c b/drivers/spi/spi_rv32m1_lpspi.c index 33911374225..282e59b4adc 100644 --- a/drivers/spi/spi_rv32m1_lpspi.c +++ b/drivers/spi/spi_rv32m1_lpspi.c @@ -19,6 +19,8 @@ #include LOG_MODULE_REGISTER(spi_rv32m1_lpspi); +#include + #include "spi_context.h" #define CHIP_SELECT_COUNT 4 From a63591c5cbe4294b6ca16207a34f2eda2da73153 Mon Sep 17 00:00:00 2001 From: Gerard Marull-Paretas Date: Thu, 18 Jan 2024 16:22:43 +0100 Subject: [PATCH 2597/3723] drivers: timer: litex: add missing include is needed to access IO R/W functions like litex_read8. Signed-off-by: Gerard Marull-Paretas --- drivers/timer/litex_timer.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/drivers/timer/litex_timer.c b/drivers/timer/litex_timer.c index ecc5b22a9d9..c12630eba34 100644 --- a/drivers/timer/litex_timer.c +++ b/drivers/timer/litex_timer.c @@ -13,6 +13,8 @@ #include #include +#include + #define TIMER_LOAD_ADDR DT_INST_REG_ADDR_BY_NAME(0, load) #define TIMER_RELOAD_ADDR DT_INST_REG_ADDR_BY_NAME(0, reload) #define TIMER_EN_ADDR DT_INST_REG_ADDR_BY_NAME(0, en) From 636a5990b53353c2230141a23d413033a300f913 Mon Sep 17 00:00:00 2001 From: Gerard Marull-Paretas Date: Thu, 18 Jan 2024 14:46:37 +0100 Subject: [PATCH 2598/3723] manifest: update hal_espressif Pull an include fix (missing soc.h). Signed-off-by: Gerard Marull-Paretas --- west.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/west.yml b/west.yml index 1dded6a5923..566231e1cec 100644 --- a/west.yml +++ b/west.yml @@ -152,7 +152,7 @@ manifest: groups: - hal - name: hal_espressif - revision: 19d2fe44ba988781f83eb70645c3757f96fcdf1c + revision: 67fa60bdffca7ba8ed199aecfaa26f485f24878b path: modules/hal/espressif west-commands: west/west-commands.yml groups: From 13e02a00f0fe9de6dab250d3faa50f0b351d2649 Mon Sep 17 00:00:00 2001 From: Gerard Marull-Paretas Date: Tue, 16 Jan 2024 15:26:31 +0100 Subject: [PATCH 2599/3723] soc: riscv: andes_v5: include soc_v5.h Instead of catch-all soc.h (which was now just being a proxy for soc_v5.h). Signed-off-by: Gerard Marull-Paretas --- soc/riscv/andes_v5/ae350/l2_cache.c | 2 ++ soc/riscv/andes_v5/ae350/soc.h | 3 --- soc/riscv/andes_v5/ae350/soc_irq.S | 4 ++-- soc/riscv/andes_v5/ae350/start.S | 3 ++- 4 files changed, 6 insertions(+), 6 deletions(-) diff --git a/soc/riscv/andes_v5/ae350/l2_cache.c b/soc/riscv/andes_v5/ae350/l2_cache.c index 69e8d00b947..83a048ca896 100644 --- a/soc/riscv/andes_v5/ae350/l2_cache.c +++ b/soc/riscv/andes_v5/ae350/l2_cache.c @@ -10,6 +10,8 @@ * @brief Andes V5 L2 Cache Controller driver */ +#include "soc_v5.h" + #include #include #include diff --git a/soc/riscv/andes_v5/ae350/soc.h b/soc/riscv/andes_v5/ae350/soc.h index fd3a9e63c0d..07d8c698820 100644 --- a/soc/riscv/andes_v5/ae350/soc.h +++ b/soc/riscv/andes_v5/ae350/soc.h @@ -11,7 +11,4 @@ #ifndef __RISCV_ANDES_AE350_SOC_H_ #define __RISCV_ANDES_AE350_SOC_H_ -/* Include CSRs available for Andes V5 SoCs */ -#include "soc_v5.h" - #endif /* __RISCV_ANDES_AE350_SOC_H_ */ diff --git a/soc/riscv/andes_v5/ae350/soc_irq.S b/soc/riscv/andes_v5/ae350/soc_irq.S index 459285c1281..f057cd8804f 100644 --- a/soc/riscv/andes_v5/ae350/soc_irq.S +++ b/soc/riscv/andes_v5/ae350/soc_irq.S @@ -4,11 +4,11 @@ * SPDX-License-Identifier: Apache-2.0 */ +#include "soc_v5.h" + #include #include -#include - #ifdef CONFIG_RISCV_SOC_CONTEXT_SAVE /* Exports */ diff --git a/soc/riscv/andes_v5/ae350/start.S b/soc/riscv/andes_v5/ae350/start.S index 84e0d91cb91..9f0ac85caa3 100644 --- a/soc/riscv/andes_v5/ae350/start.S +++ b/soc/riscv/andes_v5/ae350/start.S @@ -4,8 +4,9 @@ * SPDX-License-Identifier: Apache-2.0 */ +#include "soc_v5.h" + #include -#include /* exports */ GTEXT(entry) From 68a0f0a377cd89f80d9a75bf187c92e846ee91fb Mon Sep 17 00:00:00 2001 From: Gerard Marull-Paretas Date: Tue, 16 Jan 2024 15:29:25 +0100 Subject: [PATCH 2600/3723] soc: riscv: andes_v5: ae350: remove redundant include is not needed. Signed-off-by: Gerard Marull-Paretas --- soc/riscv/andes_v5/ae350/linker.ld | 1 - 1 file changed, 1 deletion(-) diff --git a/soc/riscv/andes_v5/ae350/linker.ld b/soc/riscv/andes_v5/ae350/linker.ld index a47aceb6038..9f7d1274655 100644 --- a/soc/riscv/andes_v5/ae350/linker.ld +++ b/soc/riscv/andes_v5/ae350/linker.ld @@ -12,7 +12,6 @@ * Linker script for the ae350 platform */ -#include #include #include From 3765b90c77d20749395a8dbcccfa9565488decd2 Mon Sep 17 00:00:00 2001 From: Gerard Marull-Paretas Date: Tue, 16 Jan 2024 15:18:50 +0100 Subject: [PATCH 2601/3723] soc: riscv: ite_ec: it8xxx2: reduce the scope of some definitions Do not expose them in soc.h, just move them to the module making use of them. Signed-off-by: Gerard Marull-Paretas --- soc/riscv/ite_ec/it8xxx2/soc.c | 18 +++++++++++++++++- soc/riscv/ite_ec/it8xxx2/soc.h | 16 ---------------- 2 files changed, 17 insertions(+), 17 deletions(-) diff --git a/soc/riscv/ite_ec/it8xxx2/soc.c b/soc/riscv/ite_ec/it8xxx2/soc.c index 0808955a6ae..f9a52a1cd3e 100644 --- a/soc/riscv/ite_ec/it8xxx2/soc.c +++ b/soc/riscv/ite_ec/it8xxx2/soc.c @@ -10,10 +10,26 @@ #include #include #include "ilm.h" -#include +#include #include "soc_espi.h" #include +/* + * This define gets the total number of USBPD ports available on the + * ITE EC chip from dtsi (include status disable). Both it81202 and + * it81302 support two USBPD ports. + */ +#define SOC_USBPD_ITE_PHY_PORT_COUNT \ +COND_CODE_1(DT_NODE_EXISTS(DT_INST(1, ite_it8xxx2_usbpd)), (2), (1)) + +/* + * This define gets the number of active USB Power Delivery (USB PD) + * ports in use on the ITE microcontroller from dts (only status okay). + * The active port usage should follow the order of ITE TCPC port index, + * ex. if we're active only one ITE USB PD port, then the port should be + * 0x3700 (port0 register base), instead of 0x3800 (port1 register base). + */ +#define SOC_USBPD_ITE_ACTIVE_PORT_COUNT DT_NUM_INST_STATUS_OKAY(ite_it8xxx2_usbpd) uint32_t chip_get_pll_freq(void) { diff --git a/soc/riscv/ite_ec/it8xxx2/soc.h b/soc/riscv/ite_ec/it8xxx2/soc.h index ea9d30d11fc..527152601d5 100644 --- a/soc/riscv/ite_ec/it8xxx2/soc.h +++ b/soc/riscv/ite_ec/it8xxx2/soc.h @@ -8,21 +8,5 @@ */ #include -/* - * This define gets the total number of USBPD ports available on the - * ITE EC chip from dtsi (include status disable). Both it81202 and - * it81302 support two USBPD ports. - */ -#define SOC_USBPD_ITE_PHY_PORT_COUNT \ -COND_CODE_1(DT_NODE_EXISTS(DT_INST(1, ite_it8xxx2_usbpd)), (2), (1)) - -/* - * This define gets the number of active USB Power Delivery (USB PD) - * ports in use on the ITE microcontroller from dts (only status okay). - * The active port usage should follow the order of ITE TCPC port index, - * ex. if we're active only one ITE USB PD port, then the port should be - * 0x3700 (port0 register base), instead of 0x3800 (port1 register base). - */ -#define SOC_USBPD_ITE_ACTIVE_PORT_COUNT DT_NUM_INST_STATUS_OKAY(ite_it8xxx2_usbpd) #endif /* __RISCV_ITE_SOC_H_ */ From c5699fac7fcf4b6646d94435474e393d87c43cce Mon Sep 17 00:00:00 2001 From: Gerard Marull-Paretas Date: Thu, 18 Jan 2024 12:46:06 +0100 Subject: [PATCH 2602/3723] soc: riscv: ite_ec: add missing soc_common.h include File uses some API declared in soc_common.h. Signed-off-by: Gerard Marull-Paretas --- soc/riscv/ite_ec/common/soc_common_irq.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/soc/riscv/ite_ec/common/soc_common_irq.c b/soc/riscv/ite_ec/common/soc_common_irq.c index aff5fe0d4b5..d2625c2766d 100644 --- a/soc/riscv/ite_ec/common/soc_common_irq.c +++ b/soc/riscv/ite_ec/common/soc_common_irq.c @@ -11,6 +11,8 @@ */ #include +#include + void arch_irq_enable(unsigned int irq) { if (IS_ENABLED(CONFIG_HAS_ITE_INTC)) { From 0c5a2b1fe4ac1e45a2c71b21bda489c138b24050 Mon Sep 17 00:00:00 2001 From: Gerard Marull-Paretas Date: Tue, 16 Jan 2024 15:15:23 +0100 Subject: [PATCH 2603/3723] soc: riscv: microchip_miv: miv: move MIV_UART_0_LINECFG to driver Instead of soc.h, since it's not used by anything else. Signed-off-by: Gerard Marull-Paretas --- drivers/serial/uart_miv.c | 2 ++ soc/riscv/microchip_miv/miv/soc.h | 2 -- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/serial/uart_miv.c b/drivers/serial/uart_miv.c index 24dbf3af370..bf35b4cf656 100644 --- a/drivers/serial/uart_miv.c +++ b/drivers/serial/uart_miv.c @@ -106,6 +106,8 @@ #define BAUDVALUE_MSB ((uint16_t)(0xFF00)) #define BAUDVALUE_SHIFT ((uint8_t)(5)) +#define MIV_UART_0_LINECFG 0x1 + #ifdef CONFIG_UART_INTERRUPT_DRIVEN static struct k_thread rx_thread; static K_KERNEL_STACK_DEFINE(rx_stack, 512); diff --git a/soc/riscv/microchip_miv/miv/soc.h b/soc/riscv/microchip_miv/miv/soc.h index c5827ceed21..d612cdaefa8 100644 --- a/soc/riscv/microchip_miv/miv/soc.h +++ b/soc/riscv/microchip_miv/miv/soc.h @@ -4,7 +4,5 @@ #ifndef __RISCV32_MIV_SOC_H_ #define __RISCV32_MIV_SOC_H_ -/* UART Configuration */ -#define MIV_UART_0_LINECFG 0x1 #endif /* __RISCV32_MIV_SOC_H_ */ From 95c573f02e5bd4d9548d20c63a92fe40704a81b2 Mon Sep 17 00:00:00 2001 From: Gerard Marull-Paretas Date: Thu, 18 Jan 2024 15:27:19 +0100 Subject: [PATCH 2604/3723] soc: riscv: openisa_rv32m1: add missing includes is needed to pull some APIs defined in soc.h. is needed to access EVENT0/1 addresses. Signed-off-by: Gerard Marull-Paretas --- soc/riscv/openisa_rv32m1/soc.c | 2 ++ soc/riscv/openisa_rv32m1/soc_offsets.h | 2 ++ 2 files changed, 4 insertions(+) diff --git a/soc/riscv/openisa_rv32m1/soc.c b/soc/riscv/openisa_rv32m1/soc.c index 2d99535bd9c..95edf0c5383 100644 --- a/soc/riscv/openisa_rv32m1/soc.c +++ b/soc/riscv/openisa_rv32m1/soc.c @@ -16,6 +16,8 @@ #include #endif +#include + #define LOG_LEVEL CONFIG_SOC_LOG_LEVEL #include LOG_MODULE_REGISTER(soc); diff --git a/soc/riscv/openisa_rv32m1/soc_offsets.h b/soc/riscv/openisa_rv32m1/soc_offsets.h index 8e0efdc7d62..7e7ac08de78 100644 --- a/soc/riscv/openisa_rv32m1/soc_offsets.h +++ b/soc/riscv/openisa_rv32m1/soc_offsets.h @@ -11,6 +11,8 @@ #ifndef SOC_RISCV32_OPENISA_RV32M1_SOC_OFFSETS_H_ #define SOC_RISCV32_OPENISA_RV32M1_SOC_OFFSETS_H_ +#include + #ifdef CONFIG_SOC_OPENISA_RV32M1_RI5CY #ifdef CONFIG_RISCV_SOC_CONTEXT_SAVE From cce467034fef2a2183ed1cf77618eb5ffc9793cb Mon Sep 17 00:00:00 2001 From: Gerard Marull-Paretas Date: Tue, 16 Jan 2024 14:58:08 +0100 Subject: [PATCH 2605/3723] soc: riscv: opentitan: reduce the scope of some definitions Some definitions were only used in soc.c, there's no need to expose them in a public header like soc.h. Signed-off-by: Gerard Marull-Paretas --- soc/riscv/opentitan/soc.c | 15 +++++++++++++++ soc/riscv/opentitan/soc.h | 18 ------------------ 2 files changed, 15 insertions(+), 18 deletions(-) diff --git a/soc/riscv/opentitan/soc.c b/soc/riscv/opentitan/soc.c index 0b04079233a..d627356c58f 100644 --- a/soc/riscv/opentitan/soc.c +++ b/soc/riscv/opentitan/soc.c @@ -8,8 +8,23 @@ #include #include +/* OpenTitan power management regs. */ #define PWRMGR_BASE (DT_REG_ADDR(DT_NODELABEL(pwrmgr))) +#define PWRMGR_CFG_CDC_SYNC_REG_OFFSET 0x018 +#define PWRMGR_RESET_EN_REG_OFFSET 0x02c +#define PWRMGR_RESET_EN_WDOG_SRC_MASK 0x002 + +/* Ibex timer registers. */ #define RV_TIMER_BASE (DT_REG_ADDR(DT_NODELABEL(mtimer))) +#define RV_TIMER_CTRL_REG_OFFSET 0x004 +#define RV_TIMER_INTR_ENABLE_REG_OFFSET 0x100 +#define RV_TIMER_CFG0_REG_OFFSET 0x10c +#define RV_TIMER_CFG0_PRESCALE_MASK 0xfff +#define RV_TIMER_CFG0_PRESCALE_OFFSET 0 +#define RV_TIMER_CFG0_STEP_MASK 0xff +#define RV_TIMER_CFG0_STEP_OFFSET 16 +#define RV_TIMER_LOWER0_OFFSET 0x110 +#define RV_TIMER_COMPARE_LOWER0_OFFSET 0x118 static int soc_opentitan_init(void) { diff --git a/soc/riscv/opentitan/soc.h b/soc/riscv/opentitan/soc.h index c7f75beb877..eae12eda48a 100644 --- a/soc/riscv/opentitan/soc.h +++ b/soc/riscv/opentitan/soc.h @@ -7,22 +7,4 @@ #ifndef __RISCV_OPENTITAN_SOC_H_ #define __RISCV_OPENTITAN_SOC_H_ -#include - -/* OpenTitan power management regs. */ -#define PWRMGR_CFG_CDC_SYNC_REG_OFFSET 0x018 -#define PWRMGR_RESET_EN_REG_OFFSET 0x02c -#define PWRMGR_RESET_EN_WDOG_SRC_MASK 0x002 - -/* Ibex timer registers. */ -#define RV_TIMER_CTRL_REG_OFFSET 0x004 -#define RV_TIMER_INTR_ENABLE_REG_OFFSET 0x100 -#define RV_TIMER_CFG0_REG_OFFSET 0x10c -#define RV_TIMER_CFG0_PRESCALE_MASK 0xfff -#define RV_TIMER_CFG0_PRESCALE_OFFSET 0 -#define RV_TIMER_CFG0_STEP_MASK 0xff -#define RV_TIMER_CFG0_STEP_OFFSET 16 -#define RV_TIMER_LOWER0_OFFSET 0x110 -#define RV_TIMER_COMPARE_LOWER0_OFFSET 0x118 - #endif /* __RISCV_OPENTITAN_SOC_H_ */ From 874513439b04ba6326e71f60f169a1333cb35c13 Mon Sep 17 00:00:00 2001 From: Gerard Marull-Paretas Date: Tue, 16 Jan 2024 15:13:16 +0100 Subject: [PATCH 2606/3723] soc: riscv: sifive_freedom: move PRCI base address to prci.h Instead of soc.h. This likely needs to be DT-ized at some point. Signed-off-by: Gerard Marull-Paretas --- soc/riscv/sifive_freedom/e300/prci.h | 3 ++- soc/riscv/sifive_freedom/e300/soc.h | 3 --- soc/riscv/sifive_freedom/u500/prci.h | 3 ++- soc/riscv/sifive_freedom/u500/soc.h | 3 --- soc/riscv/sifive_freedom/u700/prci.h | 3 ++- soc/riscv/sifive_freedom/u700/soc.h | 3 --- 6 files changed, 6 insertions(+), 12 deletions(-) diff --git a/soc/riscv/sifive_freedom/e300/prci.h b/soc/riscv/sifive_freedom/e300/prci.h index 07e088fbd82..6c2da210aad 100644 --- a/soc/riscv/sifive_freedom/e300/prci.h +++ b/soc/riscv/sifive_freedom/e300/prci.h @@ -7,7 +7,8 @@ #ifndef _SIFIVE_PRCI_H #define _SIFIVE_PRCI_H -#include +/* Clock controller. */ +#define PRCI_BASE_ADDR 0x10008000UL #define Z_REG32(p, i) (*(volatile uint32_t *) ((p) + (i))) #define PRCI_REG(offset) Z_REG32(PRCI_BASE_ADDR, offset) diff --git a/soc/riscv/sifive_freedom/e300/soc.h b/soc/riscv/sifive_freedom/e300/soc.h index 1194790bafa..3b4c4b54f8e 100644 --- a/soc/riscv/sifive_freedom/e300/soc.h +++ b/soc/riscv/sifive_freedom/e300/soc.h @@ -11,9 +11,6 @@ #ifndef __RISCV_SIFIVE_FREEDOM_FE300_SOC_H_ #define __RISCV_SIFIVE_FREEDOM_FE300_SOC_H_ -/* Clock controller. */ -#define PRCI_BASE_ADDR 0x10008000 - /* * On FE310 and FU540, peripherals such as SPI, UART, I2C and PWM are clocked * by TLCLK, which is derived from CORECLK. diff --git a/soc/riscv/sifive_freedom/u500/prci.h b/soc/riscv/sifive_freedom/u500/prci.h index 6709d4bfad2..4e80b7a131d 100644 --- a/soc/riscv/sifive_freedom/u500/prci.h +++ b/soc/riscv/sifive_freedom/u500/prci.h @@ -7,7 +7,8 @@ #ifndef _SIFIVE_FU540_PRCI_H #define _SIFIVE_FU540_PRCI_H -#include +/* Clock controller. */ +#define PRCI_BASE_ADDR 0x10000000UL #define Z_REG32(p, i) (*(volatile uint32_t *) ((p) + (i))) #define PRCI_REG(offset) Z_REG32(PRCI_BASE_ADDR, offset) diff --git a/soc/riscv/sifive_freedom/u500/soc.h b/soc/riscv/sifive_freedom/u500/soc.h index 35526ed43be..5ae3f5f00bd 100644 --- a/soc/riscv/sifive_freedom/u500/soc.h +++ b/soc/riscv/sifive_freedom/u500/soc.h @@ -11,9 +11,6 @@ #ifndef __RISCV_SIFIVE_FREEDOM_U500_SOC_H_ #define __RISCV_SIFIVE_FREEDOM_U500_SOC_H_ -/* Clock controller. */ -#define PRCI_BASE_ADDR 0x10000000 - /* * On FE310 and FU540, peripherals such as SPI, UART, I2C and PWM are clocked * by TLCLK, which is derived from CORECLK. diff --git a/soc/riscv/sifive_freedom/u700/prci.h b/soc/riscv/sifive_freedom/u700/prci.h index 00d529388c8..ed78e924939 100644 --- a/soc/riscv/sifive_freedom/u700/prci.h +++ b/soc/riscv/sifive_freedom/u700/prci.h @@ -7,7 +7,8 @@ #ifndef _SIFIVE_FU740_PRCI_H #define _SIFIVE_FU740_PRCI_H -#include +/* Clock controller. */ +#define PRCI_BASE_ADDR 0x10000000UL #define Z_REG32(p, i) (*(volatile uint32_t *) ((p) + (i))) #define PRCI_REG(offset) Z_REG32(PRCI_BASE_ADDR, offset) diff --git a/soc/riscv/sifive_freedom/u700/soc.h b/soc/riscv/sifive_freedom/u700/soc.h index aaaa13edb95..dcd37dfdc44 100644 --- a/soc/riscv/sifive_freedom/u700/soc.h +++ b/soc/riscv/sifive_freedom/u700/soc.h @@ -11,9 +11,6 @@ #ifndef __RISCV_SIFIVE_FREEDOM_U700_SOC_H_ #define __RISCV_SIFIVE_FREEDOM_U700_SOC_H_ -/* Clock controller. */ -#define PRCI_BASE_ADDR 0x10000000 - /* On FU740, peripherals are clocked by PCLK. */ #define SIFIVE_PERIPHERAL_CLOCK_FREQUENCY \ DT_PROP(DT_NODELABEL(pclk), clock_frequency) From 788fda525a88c956190e524c52104c87b027bad0 Mon Sep 17 00:00:00 2001 From: Gerard Marull-Paretas Date: Tue, 16 Jan 2024 14:55:51 +0100 Subject: [PATCH 2607/3723] soc: riscv: virt: reduce the scope of SIFIVE_SYSCON_TEST It was used nowhere else, there's no need to expose it publicly. Signed-off-by: Gerard Marull-Paretas --- soc/riscv/virt/soc.c | 2 ++ soc/riscv/virt/soc.h | 2 -- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/soc/riscv/virt/soc.c b/soc/riscv/virt/soc.c index 581f4116c9b..0bdcf6e80f2 100644 --- a/soc/riscv/virt/soc.c +++ b/soc/riscv/virt/soc.c @@ -13,6 +13,8 @@ #include #include +#define SIFIVE_SYSCON_TEST 0x00100000 + /* * Exit QEMU and tell error number. * Higher 16bits: indicates error number. diff --git a/soc/riscv/virt/soc.h b/soc/riscv/virt/soc.h index 8aa4238010c..df3559c96e3 100644 --- a/soc/riscv/virt/soc.h +++ b/soc/riscv/virt/soc.h @@ -7,6 +7,4 @@ #ifndef __RISCV_VIRT_SOC_H_ #define __RISCV_VIRT_SOC_H_ -#define SIFIVE_SYSCON_TEST 0x00100000 - #endif From e7cc2fafb49c1b760bdd85ebf2bc67c53b30c031 Mon Sep 17 00:00:00 2001 From: Gerard Marull-Paretas Date: Tue, 16 Jan 2024 15:22:23 +0100 Subject: [PATCH 2608/3723] arch: riscv: remode redundant soc.h includes They are just not needed. Signed-off-by: Gerard Marull-Paretas --- include/zephyr/arch/riscv/arch.h | 1 - include/zephyr/arch/riscv/common/linker.ld | 1 - include/zephyr/arch/riscv/irq.h | 1 - 3 files changed, 3 deletions(-) diff --git a/include/zephyr/arch/riscv/arch.h b/include/zephyr/arch/riscv/arch.h index 1b456a48d96..e7dcfbef3ae 100644 --- a/include/zephyr/arch/riscv/arch.h +++ b/include/zephyr/arch/riscv/arch.h @@ -26,7 +26,6 @@ #endif /* CONFIG_USERSPACE */ #include #include -#include #include #include #include diff --git a/include/zephyr/arch/riscv/common/linker.ld b/include/zephyr/arch/riscv/common/linker.ld index 38a254ba5ff..e9ac6d32d86 100644 --- a/include/zephyr/arch/riscv/common/linker.ld +++ b/include/zephyr/arch/riscv/common/linker.ld @@ -11,7 +11,6 @@ * Generic Linker script for the riscv platform */ -#include #include #include diff --git a/include/zephyr/arch/riscv/irq.h b/include/zephyr/arch/riscv/irq.h index cf646809898..3cf0d28523c 100644 --- a/include/zephyr/arch/riscv/irq.h +++ b/include/zephyr/arch/riscv/irq.h @@ -22,7 +22,6 @@ extern "C" { #include #include #include -#include #endif /* !_ASMLANGUAGE */ /* Exceptions 0-15 (MCAUSE interrupt=0) */ From 48dbcf54790af3b40b5aad0392c0ee4a7e0ced4f Mon Sep 17 00:00:00 2001 From: Gerard Marull-Paretas Date: Tue, 16 Jan 2024 15:41:14 +0100 Subject: [PATCH 2609/3723] soc: riscv: remove empty soc.h files Because they're just not needed. Signed-off-by: Gerard Marull-Paretas --- soc/riscv/andes_v5/ae350/soc.h | 14 -------------- soc/riscv/efinix_sapphire/soc.h | 17 ----------------- soc/riscv/gd_gd32/gd32vf103/soc.h | 14 -------------- soc/riscv/intel_niosv/niosv/soc.h | 12 ------------ soc/riscv/microchip_miv/miv/soc.h | 8 -------- soc/riscv/microchip_miv/polarfire/soc.h | 11 ----------- soc/riscv/opentitan/soc.h | 10 ---------- soc/riscv/renode_virt/soc.h | 10 ---------- soc/riscv/starfive_jh71xx/jh71xx/soc.h | 10 ---------- soc/riscv/virt/soc.h | 10 ---------- 10 files changed, 116 deletions(-) delete mode 100644 soc/riscv/andes_v5/ae350/soc.h delete mode 100644 soc/riscv/efinix_sapphire/soc.h delete mode 100644 soc/riscv/gd_gd32/gd32vf103/soc.h delete mode 100644 soc/riscv/intel_niosv/niosv/soc.h delete mode 100644 soc/riscv/microchip_miv/miv/soc.h delete mode 100644 soc/riscv/microchip_miv/polarfire/soc.h delete mode 100644 soc/riscv/opentitan/soc.h delete mode 100644 soc/riscv/renode_virt/soc.h delete mode 100644 soc/riscv/starfive_jh71xx/jh71xx/soc.h delete mode 100644 soc/riscv/virt/soc.h diff --git a/soc/riscv/andes_v5/ae350/soc.h b/soc/riscv/andes_v5/ae350/soc.h deleted file mode 100644 index 07d8c698820..00000000000 --- a/soc/riscv/andes_v5/ae350/soc.h +++ /dev/null @@ -1,14 +0,0 @@ -/* - * Copyright (c) 2021 Andes Technology Corporation - * - * SPDX-License-Identifier: Apache-2.0 - */ - -/** - * @brief Macros for the Andes AE350 platform - */ - -#ifndef __RISCV_ANDES_AE350_SOC_H_ -#define __RISCV_ANDES_AE350_SOC_H_ - -#endif /* __RISCV_ANDES_AE350_SOC_H_ */ diff --git a/soc/riscv/efinix_sapphire/soc.h b/soc/riscv/efinix_sapphire/soc.h deleted file mode 100644 index 5530af16729..00000000000 --- a/soc/riscv/efinix_sapphire/soc.h +++ /dev/null @@ -1,17 +0,0 @@ -/* - * Copyright (c) 2023 Efinix Inc. - * - * SPDX-License-Identifier: Apache-2.0 - */ - -#ifndef __RISCV32_EFINIX_SAPPHIRE_SOC_H_ -#define __RISCV32_EFINIX_SAPPHIRE_SOC_H_ - -#include -#include - -#ifndef _ASMLANGUAGE - -#endif /* _ASMLANGUAGE */ - -#endif /* __RISCV32_EFINIX_SAPPHIRE_SOC_H_ */ diff --git a/soc/riscv/gd_gd32/gd32vf103/soc.h b/soc/riscv/gd_gd32/gd32vf103/soc.h deleted file mode 100644 index ad2add6fa80..00000000000 --- a/soc/riscv/gd_gd32/gd32vf103/soc.h +++ /dev/null @@ -1,14 +0,0 @@ -/* - * Copyright (c) 2021 Tokita, Hiroshi - * - * SPDX-License-Identifier: Apache-2.0 - */ - -/** - * @file SoC configuration macros for the GigaDevice GD32VF103 processor - */ - -#ifndef RISCV_GD32VF103_SOC_H_ -#define RISCV_GD32VF103_SOC_H_ - -#endif /* RISCV_GD32VF103_SOC_H */ diff --git a/soc/riscv/intel_niosv/niosv/soc.h b/soc/riscv/intel_niosv/niosv/soc.h deleted file mode 100644 index 87458c91dff..00000000000 --- a/soc/riscv/intel_niosv/niosv/soc.h +++ /dev/null @@ -1,12 +0,0 @@ -/* - * Copyright (C) 2023, Intel Corporation - * - * SPDX-License-Identifier: Apache-2.0 - */ - -#ifndef RISCV_INTEL_FPGA_NIOSV_H -#define RISCV_INTEL_FPGA_NIOSV_H - -#include - -#endif /* RISCV_INTEL_FPGA_NIOSV_H */ diff --git a/soc/riscv/microchip_miv/miv/soc.h b/soc/riscv/microchip_miv/miv/soc.h deleted file mode 100644 index d612cdaefa8..00000000000 --- a/soc/riscv/microchip_miv/miv/soc.h +++ /dev/null @@ -1,8 +0,0 @@ -/* - * SPDX-License-Identifier: Apache-2.0 - */ -#ifndef __RISCV32_MIV_SOC_H_ -#define __RISCV32_MIV_SOC_H_ - - -#endif /* __RISCV32_MIV_SOC_H_ */ diff --git a/soc/riscv/microchip_miv/polarfire/soc.h b/soc/riscv/microchip_miv/polarfire/soc.h deleted file mode 100644 index 3bcb9569c6e..00000000000 --- a/soc/riscv/microchip_miv/polarfire/soc.h +++ /dev/null @@ -1,11 +0,0 @@ -/* - * SPDX-License-Identifier: Apache-2.0 - * - * Copyright (c) 2020-2021 Microchip Technology Inc - */ -#ifndef __RISCV64_MPFS_SOC_H_ -#define __RISCV64_MPFS_SOC_H_ - -#include - -#endif /* __RISCV64_MPFS_SOC_H_ */ diff --git a/soc/riscv/opentitan/soc.h b/soc/riscv/opentitan/soc.h deleted file mode 100644 index eae12eda48a..00000000000 --- a/soc/riscv/opentitan/soc.h +++ /dev/null @@ -1,10 +0,0 @@ -/* - * Copyright (c) 2023 Rivos Inc. - * - * SPDX-License-Identifier: Apache-2.0 - */ - -#ifndef __RISCV_OPENTITAN_SOC_H_ -#define __RISCV_OPENTITAN_SOC_H_ - -#endif /* __RISCV_OPENTITAN_SOC_H_ */ diff --git a/soc/riscv/renode_virt/soc.h b/soc/riscv/renode_virt/soc.h deleted file mode 100644 index 3edef49c88c..00000000000 --- a/soc/riscv/renode_virt/soc.h +++ /dev/null @@ -1,10 +0,0 @@ -/* - * Copyright (c) 2023 Meta - * - * SPDX-License-Identifier: Apache-2.0 - */ - -#ifndef __RISCV32_RENODE_SOC_H_ -#define __RISCV32_RENODE_SOC_H_ - -#endif /* __RISCV32_RENODE_SOC_H_ */ diff --git a/soc/riscv/starfive_jh71xx/jh71xx/soc.h b/soc/riscv/starfive_jh71xx/jh71xx/soc.h deleted file mode 100644 index df3559c96e3..00000000000 --- a/soc/riscv/starfive_jh71xx/jh71xx/soc.h +++ /dev/null @@ -1,10 +0,0 @@ -/* - * Copyright (c) 2020 Cobham Gaisler AB - * - * SPDX-License-Identifier: Apache-2.0 - */ - -#ifndef __RISCV_VIRT_SOC_H_ -#define __RISCV_VIRT_SOC_H_ - -#endif diff --git a/soc/riscv/virt/soc.h b/soc/riscv/virt/soc.h deleted file mode 100644 index df3559c96e3..00000000000 --- a/soc/riscv/virt/soc.h +++ /dev/null @@ -1,10 +0,0 @@ -/* - * Copyright (c) 2020 Cobham Gaisler AB - * - * SPDX-License-Identifier: Apache-2.0 - */ - -#ifndef __RISCV_VIRT_SOC_H_ -#define __RISCV_VIRT_SOC_H_ - -#endif From aeb25e3da18793298d9447ee430b4efc097768f5 Mon Sep 17 00:00:00 2001 From: Tanmay Kathpalia Date: Wed, 17 Jan 2024 12:15:32 +0000 Subject: [PATCH 2610/3723] drivers: sdhc: Cadence SDHC driver bug fixes and other improvements * Internal Clock not getting stable during initialization * SD clock was not enabled * Removed duplicate file. * Removed write to readonly registers * Moved function pointer structure from data section to RO section * Wrong macro names * Refactoring of lower layer header file. Signed-off-by: Tanmay Kathpalia --- drivers/sdhc/sdhc_cdns.c | 2 +- drivers/sdhc/sdhc_cdns/sdhc_cdns.c | 301 ---------- drivers/sdhc/sdhc_cdns/sdhc_cdns_ll.c | 791 -------------------------- drivers/sdhc/sdhc_cdns/sdhc_cdns_ll.h | 489 ---------------- drivers/sdhc/sdhc_cdns_ll.c | 52 +- drivers/sdhc/sdhc_cdns_ll.h | 165 +++--- 6 files changed, 120 insertions(+), 1680 deletions(-) delete mode 100644 drivers/sdhc/sdhc_cdns/sdhc_cdns.c delete mode 100644 drivers/sdhc/sdhc_cdns/sdhc_cdns_ll.c delete mode 100644 drivers/sdhc/sdhc_cdns/sdhc_cdns_ll.h diff --git a/drivers/sdhc/sdhc_cdns.c b/drivers/sdhc/sdhc_cdns.c index a2a071d8760..f5a880e5fb4 100644 --- a/drivers/sdhc/sdhc_cdns.c +++ b/drivers/sdhc/sdhc_cdns.c @@ -235,7 +235,7 @@ static int sdhc_cdns_set_io(const struct device *dev, struct sdhc_io *ios) return 0; } -static struct sdhc_driver_api sdhc_cdns_api = { +static const struct sdhc_driver_api sdhc_cdns_api = { .request = sdhc_cdns_request, .set_io = sdhc_cdns_set_io, .get_host_props = sdhc_cdns_get_host_props, diff --git a/drivers/sdhc/sdhc_cdns/sdhc_cdns.c b/drivers/sdhc/sdhc_cdns/sdhc_cdns.c deleted file mode 100644 index a2a071d8760..00000000000 --- a/drivers/sdhc/sdhc_cdns/sdhc_cdns.c +++ /dev/null @@ -1,301 +0,0 @@ -/* - * Copyright (C) 2023 Intel Corporation - * - * SPDX-License-Identifier: Apache-2.0 - */ - -#define DT_DRV_COMPAT cdns_sdhc - -#include -#include -#include -#include - -#include "sdhc_cdns_ll.h" - -#define SDHC_CDNS_DESC_SIZE (1<<20) -#define COMBOPHY_ADDR_MASK 0x0000FFFFU - -#define DEV_CFG(_dev) ((const struct sdhc_cdns_config *)(_dev)->config) -#define DEV_DATA(_dev) ((struct sdhc_cdns_data *const)(_dev)->data) - -LOG_MODULE_REGISTER(sdhc_cdns, CONFIG_SDHC_LOG_LEVEL); - -/* SDMMC operations FPs are the element of structure*/ -static const struct sdhc_cdns_ops *cdns_sdmmc_ops; - -struct sdhc_cdns_config { - DEVICE_MMIO_NAMED_ROM(reg_base); - DEVICE_MMIO_NAMED_ROM(combo_phy); - /* Clock rate for host */ - uint32_t clk_rate; - /* power delay prop for host */ - uint32_t power_delay_ms; - /* run time device structure */ - const struct device *cdns_clk_dev; - /* type to identify a clock controller sub-system */ - clock_control_subsys_t clkid; - /* Reset controller device configuration. */ - const struct reset_dt_spec reset_sdmmc; - const struct reset_dt_spec reset_sdmmcocp; - const struct reset_dt_spec reset_softphy; -}; - -struct sdhc_cdns_data { - DEVICE_MMIO_NAMED_RAM(reg_base); - DEVICE_MMIO_NAMED_RAM(combo_phy); - /* Host controller parameters */ - struct sdhc_cdns_params params; - /* sdmmc device informartaion for host */ - struct sdmmc_device_info info; - /* Input/Output configuration */ - struct sdhc_io host_io; -}; - -static int sdhc_cdns_request(const struct device *dev, - struct sdhc_command *cmd, - struct sdhc_data *data) -{ - int ret = 0; - struct sdmmc_cmd cdns_sdmmc_cmd; - - if (cmd == NULL) { - LOG_ERR("Wrong CMD parameter"); - return -EINVAL; - } - - /* Initialization of command structure */ - cdns_sdmmc_cmd.cmd_idx = cmd->opcode; - cdns_sdmmc_cmd.cmd_arg = cmd->arg; - cdns_sdmmc_cmd.resp_type = (cmd->response_type & SDHC_NATIVE_RESPONSE_MASK); - - /* Sending command as per the data or non data */ - if (data) { - ret = cdns_sdmmc_ops->prepare(data->block_addr, (uintptr_t)data->data, - data); - if (ret != 0) { - LOG_ERR("DMA Prepare failed"); - return -EINVAL; - } - } - - ret = cdns_sdmmc_ops->send_cmd(&cdns_sdmmc_cmd, data); - - if (ret == 0) { - if (cmd->opcode == SD_READ_SINGLE_BLOCK || cmd->opcode == SD_APP_SEND_SCR || - cmd->opcode == SD_READ_MULTIPLE_BLOCK) { - - if (data == NULL) { - LOG_ERR("Invalid data parameter"); - return -ENODATA; - } - ret = cdns_sdmmc_ops->cache_invd(data->block_addr, (uintptr_t)data->data, - data->block_size); - if (ret != 0) { - return ret; - } - } - } - /* copying all responses as per response type */ - for (int i = 0; i < 4; i++) { - cmd->response[i] = cdns_sdmmc_cmd.resp_data[i]; - } - return ret; -} - -static int sdhc_cdns_get_card_present(const struct device *dev) -{ - return cdns_sdmmc_ops->card_present(); -} - -static int sdhc_cdns_card_busy(const struct device *dev) -{ - return cdns_sdmmc_ops->busy(); -} - -static int sdhc_cdns_get_host_props(const struct device *dev, - struct sdhc_host_props *props) -{ - const struct sdhc_cdns_config *sdhc_config = DEV_CFG(dev); - - memset(props, 0, sizeof(struct sdhc_host_props)); - props->f_min = SDMMC_CLOCK_400KHZ; - /* - * default max speed is 25MHZ, as per SCR register - * it will switch accordingly - */ - props->f_max = SD_CLOCK_25MHZ; - props->power_delay = sdhc_config->power_delay_ms; - props->host_caps.vol_330_support = true; - props->is_spi = false; - return 0; -} - -static int sdhc_cdns_reset(const struct device *dev) -{ - return cdns_sdmmc_ops->reset(); -} - -static int sdhc_cdns_init(const struct device *dev) -{ - struct sdhc_cdns_data *const data = DEV_DATA(dev); - const struct sdhc_cdns_config *sdhc_config = DEV_CFG(dev); - int ret; - - /* SDHC reg base */ - DEVICE_MMIO_NAMED_MAP(dev, reg_base, K_MEM_CACHE_NONE); - /* ComboPhy reg base */ - DEVICE_MMIO_NAMED_MAP(dev, combo_phy, K_MEM_CACHE_NONE); - - /* clock setting */ - if (sdhc_config->clk_rate == 0U) { - if (!device_is_ready(sdhc_config->cdns_clk_dev)) { - LOG_ERR("Clock controller device is not ready"); - return -EINVAL; - } - - ret = clock_control_get_rate(sdhc_config->cdns_clk_dev, - sdhc_config->clkid, &data->params.clk_rate); - - if (ret != 0) { - return ret; - } - } else { - data->params.clk_rate = sdhc_config->clk_rate; - } - - /* Setting regbase */ - data->params.reg_base = DEVICE_MMIO_NAMED_GET(dev, reg_base); - data->params.reg_phy = DEVICE_MMIO_NAMED_GET(dev, combo_phy); - data->params.combophy = (DEVICE_MMIO_NAMED_ROM_PTR((dev), - combo_phy)->phys_addr); - data->params.combophy = (data->params.combophy & COMBOPHY_ADDR_MASK); - - /* resetting the lines */ - if (sdhc_config->reset_sdmmc.dev != NULL) { - if (!device_is_ready(sdhc_config->reset_sdmmc.dev) || - !device_is_ready(sdhc_config->reset_sdmmcocp.dev) || - !device_is_ready(sdhc_config->reset_softphy.dev)) { - LOG_ERR("Reset device not found"); - return -ENODEV; - } - - ret = reset_line_toggle(sdhc_config->reset_softphy.dev, - sdhc_config->reset_softphy.id); - if (ret != 0) { - LOG_ERR("Softphy Reset failed"); - return ret; - } - - ret = reset_line_toggle(sdhc_config->reset_sdmmc.dev, - sdhc_config->reset_sdmmc.id); - if (ret != 0) { - LOG_ERR("sdmmc Reset failed"); - return ret; - } - - ret = reset_line_toggle(sdhc_config->reset_sdmmcocp.dev, - sdhc_config->reset_sdmmcocp.id); - if (ret != 0) { - LOG_ERR("sdmmcocp Reset failed"); - return ret; - } - } - - /* Init function to call lower layer file */ - sdhc_cdns_sdmmc_init(&data->params, &data->info, &cdns_sdmmc_ops); - - ret = sdhc_cdns_reset(dev); - if (ret != 0U) { - LOG_ERR("Card reset failed"); - return ret; - } - - /* Init operation called for register initialisation */ - ret = cdns_sdmmc_ops->init(); - if (ret != 0U) { - LOG_ERR("Card initialization failed"); - return ret; - } - - return 0; -} - -static int sdhc_cdns_set_io(const struct device *dev, struct sdhc_io *ios) -{ - struct sdhc_cdns_data *data = dev->data; - struct sdhc_io *host_io = &data->host_io; - - if (host_io->bus_width != ios->bus_width || host_io->clock != - ios->clock) { - host_io->bus_width = ios->bus_width; - host_io->clock = ios->clock; - return cdns_sdmmc_ops->set_ios(ios->clock, ios->bus_width); - } - return 0; -} - -static struct sdhc_driver_api sdhc_cdns_api = { - .request = sdhc_cdns_request, - .set_io = sdhc_cdns_set_io, - .get_host_props = sdhc_cdns_get_host_props, - .get_card_present = sdhc_cdns_get_card_present, - .reset = sdhc_cdns_reset, - .card_busy = sdhc_cdns_card_busy, -}; - -#define SDHC_CDNS_CLOCK_RATE_INIT(inst) \ - COND_CODE_1(DT_INST_NODE_HAS_PROP(inst, clock_frequency), \ - ( \ - .clk_rate = DT_INST_PROP(inst, clock_frequency), \ - .cdns_clk_dev = NULL, \ - .clkid = (clock_control_subsys_t)0, \ - ), \ - ( \ - .clk_rate = 0, \ - .cdns_clk_dev = DEVICE_DT_GET(DT_INST_CLOCKS_CTLR(inst)), \ - .clkid = (clock_control_subsys_t)DT_INST_CLOCKS_CELL(inst, clkid), \ - ) \ - ) - -#define SDHC_CDNS_RESET_SPEC_INIT(inst) \ - .reset_sdmmc = RESET_DT_SPEC_INST_GET_BY_IDX(inst, 0), \ - .reset_sdmmcocp = RESET_DT_SPEC_INST_GET_BY_IDX(inst, 1),\ - .reset_softphy = RESET_DT_SPEC_INST_GET_BY_IDX(inst, 2), - -#define SDHC_CDNS_INIT(inst) \ - static struct sdhc_cdns_desc cdns_desc \ - [CONFIG_CDNS_DESC_COUNT]; \ - \ - static const struct sdhc_cdns_config sdhc_cdns_config_##inst = {\ - DEVICE_MMIO_NAMED_ROM_INIT_BY_NAME( \ - reg_base, DT_DRV_INST(inst)), \ - DEVICE_MMIO_NAMED_ROM_INIT_BY_NAME( \ - combo_phy, DT_DRV_INST(inst)), \ - SDHC_CDNS_CLOCK_RATE_INIT(inst) \ - IF_ENABLED(DT_INST_NODE_HAS_PROP(inst, resets), \ - (SDHC_CDNS_RESET_SPEC_INIT(inst))) \ - .power_delay_ms = DT_INST_PROP(inst, power_delay_ms), \ - }; \ - static struct sdhc_cdns_data sdhc_cdns_data_##inst = { \ - .params = { \ - .bus_width = SDHC_BUS_WIDTH1BIT, \ - .desc_base = (uintptr_t) &cdns_desc, \ - .desc_size = SDHC_CDNS_DESC_SIZE, \ - .flags = 0, \ - }, \ - .info = { \ - .cdn_sdmmc_dev_type = SD_DS, \ - .ocr_voltage = OCR_3_3_3_4 | OCR_3_2_3_3, \ - }, \ - }; \ - DEVICE_DT_INST_DEFINE(inst, \ - &sdhc_cdns_init, \ - NULL, \ - &sdhc_cdns_data_##inst, \ - &sdhc_cdns_config_##inst, \ - POST_KERNEL, \ - CONFIG_SDHC_INIT_PRIORITY, \ - &sdhc_cdns_api); - -DT_INST_FOREACH_STATUS_OKAY(SDHC_CDNS_INIT) diff --git a/drivers/sdhc/sdhc_cdns/sdhc_cdns_ll.c b/drivers/sdhc/sdhc_cdns/sdhc_cdns_ll.c deleted file mode 100644 index 3d8e3f97e4a..00000000000 --- a/drivers/sdhc/sdhc_cdns/sdhc_cdns_ll.c +++ /dev/null @@ -1,791 +0,0 @@ -/* - * Copyright (C) 2023 Intel Corporation - * SPDX-License-Identifier: Apache-2.0 - */ - -#include -#include "sdhc_cdns_ll.h" -#include - -LOG_MODULE_REGISTER(sdhc_cdns_ll, CONFIG_SDHC_LOG_LEVEL); - -/* card busy and present */ -#define CARD_BUSY 1 -#define CARD_NOT_BUSY 0 -#define CARD_PRESENT 1 - -/* SRS12 error mask */ -#define CDNS_SRS12_ERR_MASK 0xFFFF8000U -#define CDNS_CSD_BYTE_MASK 0x000000FFU - -/* General define */ -#define SDHC_REG_MASK 0xFFFFFFFFU -#define SD_HOST_BLOCK_SIZE 0x200 - -#define SDMMC_DMA_MAX_BUFFER_SIZE (64 * 1024) -#define CDNSMMC_ADDRESS_MASK (CONFIG_SDHC_BUFFER_ALIGNMENT - 1) - -#define SRS10_VAL_READ (ADMA2_32 | HS_EN | DT_WIDTH) -#define SRS10_VAL_SW (ADMA2_32 | DT_WIDTH) -#define SRS11_VAL_GEN (READ_CLK | CDNS_SRS11_ICE | CDNS_SRS11_ICS | CDNS_SRS11_SDCE) -#define SRS11_VAL_CID (CDNS_SRS11_ICE | CDNS_SRS11_ICS | CDNS_SRS11_SDCE) -#define SRS15_VAL_GEN (CDNS_SRS15_BIT_AD_64 | CDNS_SRS15_HV4E | CDNS_SRS15_V18SE) -#define SRS15_VAL_RD_WR (SRS15_VAL_GEN | CDNS_SRS15_SDR104 | CDNS_SRS15_PVE) -#define SRS15_VAL_CID (CDNS_SRS15_HV4E | CDNS_SRS15_V18SE) - -#define CARD_REG_TIME_DELAY_US 100000 -#define WAIT_ICS_TIME_DELAY_US 5000 -#define RESET_SRS14 0x00000000 - -static struct sdhc_cdns_params cdns_params; -static struct sdhc_cdns_combo_phy sdhc_cdns_combo_phy_reg_info; -static struct sdhc_cdns_sdmmc sdhc_cdns_sdmmc_reg_info; - -/* Function to write general phy registers */ -static int sdhc_cdns_write_phy_reg(uint32_t phy_reg_addr, uint32_t phy_reg_addr_value, - uint32_t phy_reg_data, uint32_t phy_reg_data_value) -{ - uint32_t data = 0; - - /* Set PHY register address, write HRS04*/ - sys_write32(phy_reg_addr_value, phy_reg_addr); - - /* Set PHY register data, write HRS05 */ - sys_write32(phy_reg_data_value, phy_reg_data); - data = sys_read32(phy_reg_data); - - if (data != phy_reg_data_value) { - LOG_ERR("PHY_REG_DATA is not set properly"); - return -ENXIO; - } - - return 0; -} - -int sdhc_cdns_wait_ics(uint16_t timeout, uint32_t cdn_srs_res) -{ - /* Wait status command response ready */ - if (!WAIT_FOR(((sys_read32(cdn_srs_res) & CDNS_SRS11_ICS) - == CDNS_SRS11_ICS), timeout, k_msleep(1))) { - LOG_ERR("Timed out waiting for ICS response"); - return -ETIMEDOUT; - } - - return 0; -} - -static int sdhc_cdns_busy(void) -{ - unsigned int data; - - data = sys_read32(cdns_params.reg_base + SDHC_CDNS_SRS09); - return (data & CDNS_SRS09_STAT_DAT_BUSY) ? CARD_BUSY : CARD_NOT_BUSY; -} - -static int sdhc_cdns_card_present(void) -{ - uint32_t timeout = CARD_REG_TIME_DELAY_US; - - if (!WAIT_FOR((((sys_read32(cdns_params.reg_base + SDHC_CDNS_SRS09)) - & CDNS_SRS09_CI) == CDNS_SRS09_CI), - timeout, k_msleep(1))) { - LOG_ERR("Card detection timeout"); - return -ETIMEDOUT; - } - - return CARD_PRESENT; -} - -static int sdhc_cdns_vol_reset(void) -{ - /* Reset embedded card */ - sys_write32((7 << CDNS_SRS10_BVS) | (0 << CDNS_SRS10_BP), - (cdns_params.reg_base + SDHC_CDNS_SRS10)); - - /* - * Turn on supply voltage - * CDNS_SRS10_BVS = 7, CDNS_SRS10_BP = 1, BP2 only in UHS2 mode - */ - sys_write32((7 << CDNS_SRS10_BVS) | (1 << CDNS_SRS10_BP), - (cdns_params.reg_base + SDHC_CDNS_SRS10)); - - return 0; -} - -/* - * Values are taken from IP documents and calc_setting.py script - * with input value- mode sd_ds, - * sdmclk 5000, - * sdclk 10000, - * iocell_input_delay 2500, - * iocell_output_delay 2500 and - * delay_element 24 - */ -void cdns_sdhc_set_sdmmc_params(struct sdhc_cdns_combo_phy *sdhc_cdns_combo_phy_reg, - struct sdhc_cdns_sdmmc *sdhc_cdns_sdmmc_reg) -{ - /* Values are taken by the reference of cadence IP documents */ - sdhc_cdns_combo_phy_reg->cp_clk_wr_delay = 0; - sdhc_cdns_combo_phy_reg->cp_clk_wrdqs_delay = 0; - sdhc_cdns_combo_phy_reg->cp_data_select_oe_end = 1; - sdhc_cdns_combo_phy_reg->cp_dll_bypass_mode = 1; - sdhc_cdns_combo_phy_reg->cp_dll_locked_mode = 3; - sdhc_cdns_combo_phy_reg->cp_dll_start_point = 4; - sdhc_cdns_combo_phy_reg->cp_gate_cfg_always_on = 1; - sdhc_cdns_combo_phy_reg->cp_io_mask_always_on = 0; - sdhc_cdns_combo_phy_reg->cp_io_mask_end = 2; - sdhc_cdns_combo_phy_reg->cp_io_mask_start = 0; - sdhc_cdns_combo_phy_reg->cp_rd_del_sel = 52; - sdhc_cdns_combo_phy_reg->cp_read_dqs_cmd_delay = 0; - sdhc_cdns_combo_phy_reg->cp_read_dqs_delay = 0; - sdhc_cdns_combo_phy_reg->cp_sw_half_cycle_shift = 0; - sdhc_cdns_combo_phy_reg->cp_sync_method = 1; - sdhc_cdns_combo_phy_reg->cp_underrun_suppress = 1; - sdhc_cdns_combo_phy_reg->cp_use_ext_lpbk_dqs = 1; - sdhc_cdns_combo_phy_reg->cp_use_lpbk_dqs = 1; - sdhc_cdns_combo_phy_reg->cp_use_phony_dqs = 1; - sdhc_cdns_combo_phy_reg->cp_use_phony_dqs_cmd = 1; - - sdhc_cdns_sdmmc_reg->sdhc_extended_rd_mode = 1; - sdhc_cdns_sdmmc_reg->sdhc_extended_wr_mode = 1; - sdhc_cdns_sdmmc_reg->sdhc_hcsdclkadj = 6; - sdhc_cdns_sdmmc_reg->sdhc_idelay_val = 1; - sdhc_cdns_sdmmc_reg->sdhc_rdcmd_en = 1; - sdhc_cdns_sdmmc_reg->sdhc_rddata_en = 1; - sdhc_cdns_sdmmc_reg->sdhc_rw_compensate = 10; - sdhc_cdns_sdmmc_reg->sdhc_sdcfsh = 0; - sdhc_cdns_sdmmc_reg->sdhc_sdcfsl = 1; - sdhc_cdns_sdmmc_reg->sdhc_wrcmd0_dly = 1; - sdhc_cdns_sdmmc_reg->sdhc_wrcmd0_sdclk_dly = 0; - sdhc_cdns_sdmmc_reg->sdhc_wrcmd1_dly = 0; - sdhc_cdns_sdmmc_reg->sdhc_wrcmd1_sdclk_dly = 0; - sdhc_cdns_sdmmc_reg->sdhc_wrdata0_dly = 1; - sdhc_cdns_sdmmc_reg->sdhc_wrdata0_sdclk_dly = 0; - sdhc_cdns_sdmmc_reg->sdhc_wrdata1_dly = 0; - sdhc_cdns_sdmmc_reg->sdhc_wrdata1_sdclk_dly = 0; -} - -/* Phy register programing for phy init */ -static int sdhc_cdns_program_phy_reg(struct sdhc_cdns_combo_phy *sdhc_cdns_combo_phy_reg, - struct sdhc_cdns_sdmmc *sdhc_cdns_sdmmc_reg) -{ - uint32_t value = 0; - int ret = 0; - - /* - * program PHY_DQS_TIMING_REG - * This register controls the DQS related timing - */ - value = (CP_USE_EXT_LPBK_DQS(sdhc_cdns_combo_phy_reg->cp_use_ext_lpbk_dqs)) - | (CP_USE_LPBK_DQS(sdhc_cdns_combo_phy_reg->cp_use_lpbk_dqs)) - | (CP_USE_PHONY_DQS(sdhc_cdns_combo_phy_reg->cp_use_phony_dqs)) - | (CP_USE_PHONY_DQS_CMD(sdhc_cdns_combo_phy_reg->cp_use_phony_dqs_cmd)); - ret = sdhc_cdns_write_phy_reg(cdns_params.reg_base + SDHC_CDNS_HRS04, - cdns_params.combophy + PHY_DQS_TIMING_REG, cdns_params.reg_base - + SDHC_CDNS_HRS05, value); - if (ret != 0U) { - LOG_ERR("Error in PHY_DQS_TIMING_REG programming"); - return ret; - } - - /* - * program PHY_GATE_LPBK_CTRL_REG - * This register controls the gate and loopback control related timing. - */ - value = (CP_SYNC_METHOD(sdhc_cdns_combo_phy_reg->cp_sync_method)) - | (CP_SW_HALF_CYCLE_SHIFT(sdhc_cdns_combo_phy_reg->cp_sw_half_cycle_shift)) - | (CP_RD_DEL_SEL(sdhc_cdns_combo_phy_reg->cp_rd_del_sel)) - | (CP_UNDERRUN_SUPPRESS(sdhc_cdns_combo_phy_reg->cp_underrun_suppress)) - | (CP_GATE_CFG_ALWAYS_ON(sdhc_cdns_combo_phy_reg->cp_gate_cfg_always_on)); - ret = sdhc_cdns_write_phy_reg(cdns_params.reg_base + SDHC_CDNS_HRS04, - cdns_params.combophy + PHY_GATE_LPBK_CTRL_REG, cdns_params.reg_base - + SDHC_CDNS_HRS05, value); - if (ret != 0U) { - LOG_ERR("Error in PHY_GATE_LPBK_CTRL_REG programming"); - return -ret; - } - - /* - * program PHY_DLL_MASTER_CTRL_REG - * This register holds the control for the Master DLL logic. - */ - value = (CP_DLL_BYPASS_MODE(sdhc_cdns_combo_phy_reg->cp_dll_bypass_mode)) - | (CP_DLL_START_POINT(sdhc_cdns_combo_phy_reg->cp_dll_start_point)); - ret = sdhc_cdns_write_phy_reg(cdns_params.reg_base + SDHC_CDNS_HRS04, - cdns_params.combophy + PHY_DLL_MASTER_CTRL_REG, cdns_params.reg_base - + SDHC_CDNS_HRS05, value); - if (ret != 0U) { - LOG_ERR("Error in PHY_DLL_MASTER_CTRL_REG programming"); - return ret; - } - - /* - * program PHY_DLL_SLAVE_CTRL_REG - * This register holds the control for the slave DLL logic. - */ - value = (CP_READ_DQS_CMD_DELAY(sdhc_cdns_combo_phy_reg->cp_read_dqs_cmd_delay)) - | (CP_CLK_WRDQS_DELAY(sdhc_cdns_combo_phy_reg->cp_clk_wrdqs_delay)) - | (CP_CLK_WR_DELAY(sdhc_cdns_combo_phy_reg->cp_clk_wr_delay)) - | (CP_READ_DQS_DELAY(sdhc_cdns_combo_phy_reg->cp_read_dqs_delay)); - ret = sdhc_cdns_write_phy_reg(cdns_params.reg_base + SDHC_CDNS_HRS04, - cdns_params.combophy + PHY_DLL_SLAVE_CTRL_REG, cdns_params.reg_base - + SDHC_CDNS_HRS05, value); - if (ret != 0U) { - LOG_ERR("Error in PHY_DLL_SLAVE_CTRL_REG programming"); - return ret; - } - - /* - * program PHY_CTRL_REG - * This register handles the global control settings for the PHY. - */ - sys_write32(cdns_params.combophy + PHY_CTRL_REG, cdns_params.reg_base - + SDHC_CDNS_HRS04); - value = sys_read32(cdns_params.reg_base + SDHC_CDNS_HRS05); - - /* phony_dqs_timing=0 */ - value &= ~(CP_PHONY_DQS_TIMING_MASK << CP_PHONY_DQS_TIMING_SHIFT); - sys_write32(value, cdns_params.reg_base + SDHC_CDNS_HRS05); - - /* switch off DLL_RESET */ - do { - value = sys_read32(cdns_params.reg_base + SDHC_CDNS_HRS09); - value |= CDNS_HRS09_PHY_SW_RESET; - sys_write32(value, cdns_params.reg_base + SDHC_CDNS_HRS09); - value = sys_read32(cdns_params.reg_base + SDHC_CDNS_HRS09); - /* polling PHY_INIT_COMPLETE */ - } while ((value & CDNS_HRS09_PHY_INIT_COMP) != CDNS_HRS09_PHY_INIT_COMP); - - /* - * program PHY_DQ_TIMING_REG - * This register controls the DQ related timing. - */ - sdhc_cdns_combo_phy_reg->cp_io_mask_end = 0U; - value = (CP_IO_MASK_ALWAYS_ON(sdhc_cdns_combo_phy_reg->cp_io_mask_always_on)) - | (CP_IO_MASK_END(sdhc_cdns_combo_phy_reg->cp_io_mask_end)) - | (CP_IO_MASK_START(sdhc_cdns_combo_phy_reg->cp_io_mask_start)) - | (CP_DATA_SELECT_OE_END(sdhc_cdns_combo_phy_reg->cp_data_select_oe_end)); - - ret = sdhc_cdns_write_phy_reg(cdns_params.reg_base + SDHC_CDNS_HRS04, - cdns_params.combophy + PHY_DQ_TIMING_REG, cdns_params.reg_base - + SDHC_CDNS_HRS05, value); - if (ret != 0U) { - LOG_ERR("Error in PHY_DQ_TIMING_REG programming"); - return ret; - } - return 0; -} - -static int sdhc_cdns_cache_invd(int lba, uintptr_t buf, size_t size) -{ - int ret = 0; - - ret = arch_dcache_invd_range((void *)buf, size); - if (ret != 0) { - LOG_ERR("%s: error in invalidate dcache with ret %d", __func__, ret); - return ret; - } - - return 0; -} - -/* DMA preparation for the read and write operation */ -static int sdhc_cdns_prepare(uint32_t dma_start_addr, uintptr_t dma_buff, - struct sdhc_data *data) -{ - struct sdhc_cdns_desc *desc; - uint32_t desc_cnt, i; - uintptr_t base; - uint64_t desc_base; - uint32_t size = data->blocks * data->block_size; - - __ASSERT_NO_MSG(((dma_buff & CDNSMMC_ADDRESS_MASK) == 0) && - (cdns_params.desc_size > 0) && - ((cdns_params.desc_size & MMC_BLOCK_MASK) == 0)); - - arch_dcache_flush_range((void *)dma_buff, size); - - desc_cnt = (size + (SDMMC_DMA_MAX_BUFFER_SIZE) - 1) / - (SDMMC_DMA_MAX_BUFFER_SIZE); - __ASSERT_NO_MSG(desc_cnt * sizeof(struct sdhc_cdns_desc) < - cdns_params.desc_size); - - if (desc_cnt > CONFIG_CDNS_DESC_COUNT) { - LOG_ERR("Requested data transfer length %u greater than configured length %u", - size, (CONFIG_CDNS_DESC_COUNT * SDMMC_DMA_MAX_BUFFER_SIZE)); - return -EINVAL; - } - - /* - * Creating descriptor as per the desc_count and linked list of - * descriptor for contiguous desc alignment - */ - base = cdns_params.reg_base; - desc = (struct sdhc_cdns_desc *)cdns_params.desc_base; - desc_base = (uint64_t)desc; - i = 0; - - while ((i+1) < desc_cnt) { - desc->attr = ADMA_DESC_ATTR_VALID | ADMA_DESC_TRANSFER_DATA; - desc->reserved = 0; - desc->len = MAX_64KB_PAGE; - desc->addr_lo = (dma_buff & 0xffffffff) + (SDMMC_DMA_MAX_BUFFER_SIZE * i); - desc->addr_hi = (dma_buff >> 32) & 0xffffffff; - size -= SDMMC_DMA_MAX_BUFFER_SIZE; - desc++; - i++; - } - - desc->attr = ADMA_DESC_ATTR_VALID | ADMA_DESC_TRANSFER_DATA | - ADMA_DESC_ATTR_END; - desc->reserved = 0; - desc->len = size; - desc->addr_lo = (dma_buff & 0xffffffff) + (SDMMC_DMA_MAX_BUFFER_SIZE * i); - desc->addr_hi = (dma_buff >> 32) & 0xffffffff; - - sys_write32((uint32_t)desc_base, cdns_params.reg_base + SDHC_CDNS_SRS22); - sys_write32((uint32_t)(desc_base >> 32), cdns_params.reg_base + SDHC_CDNS_SRS23); - arch_dcache_flush_range((void *)cdns_params.desc_base, - desc_cnt * sizeof(struct sdhc_cdns_desc)); - - sys_write32((data->block_size << CDNS_SRS01_BLK_SIZE | - data->blocks << CDNS_SRS01_BLK_COUNT_CT | CDNS_SRS01_SDMA_BUF), - cdns_params.reg_base + SDHC_CDNS_SRS01); - - return 0; -} - -static int sdhc_cdns_host_set_clk(int clk) -{ - uint32_t sdclkfsval = 0; - uint32_t dtcvval = 0xe; - int ret = 0; - - sdclkfsval = (cdns_params.clk_rate / 2000) / clk; - sys_write32(0, cdns_params.reg_base + SDHC_CDNS_SRS11); - sys_write32(((dtcvval << CDNS_SRS11_DTCV) | (sdclkfsval << CDNS_SRS11_SDCLKFS) | - (1 << CDNS_SRS11_ICE)), cdns_params.reg_base + SDHC_CDNS_SRS11); - - ret = sdhc_cdns_wait_ics(WAIT_ICS_TIME_DELAY_US, cdns_params.reg_base + SDHC_CDNS_SRS11); - if (ret != 0) { - return ret; - } - - /* Enable DLL reset */ - sys_clear_bit(cdns_params.reg_base + SDHC_CDNS_HRS09, 0); - /* Set extended_wr_mode */ - sys_write32(((sys_read32(cdns_params.reg_base + SDHC_CDNS_HRS09) - & 0xFFFFFFF7) | (1 << CDNS_HRS09_EXT_WR_MODE)), (cdns_params.reg_base - + SDHC_CDNS_HRS09)); - /* Release DLL reset */ - sys_set_bit(cdns_params.reg_base + SDHC_CDNS_HRS09, 1); - sys_set_bits(cdns_params.reg_base + SDHC_CDNS_HRS09, (3 << CDNS_HRS09_RDCMD_EN)); - - sys_write32(((dtcvval << CDNS_SRS11_DTCV) | (sdclkfsval << CDNS_SRS11_SDCLKFS) - | (1 << CDNS_SRS11_ICE) | (1 << CDNS_SRS11_SDCE)), - cdns_params.reg_base + SDHC_CDNS_SRS11); - - sys_write32(0xFFFFFFFF, cdns_params.reg_base + SDHC_CDNS_SRS13); - - return 0; -} - -static int sdhc_cdns_set_ios(unsigned int clk, unsigned int width) -{ - int ret = 0; - - switch (width) { - case SDHC_BUS_WIDTH1BIT: - sys_clear_bit(cdns_params.reg_base + SDHC_CDNS_SRS10, WIDTH_BIT1); - break; - case SDHC_BUS_WIDTH4BIT: - sys_set_bit(cdns_params.reg_base + SDHC_CDNS_SRS10, WIDTH_BIT4); - break; - case SDHC_BUS_WIDTH8BIT: - sys_set_bit(cdns_params.reg_base + SDHC_CDNS_SRS10, WIDTH_BIT8); - break; - default: - __ASSERT_NO_MSG(0); - break; - } - - /* Perform clock configuration when SD clock is not gated */ - if (clk != 0) { - ret = sdhc_cdns_host_set_clk(clk); - if (ret != 0) { - LOG_ERR("%s: Clock configuration failed", __func__); - return ret; - } - } - - return 0; -} - -/* Programming HRS register for initialisation */ -static int sdhc_cdns_init_hrs_io(struct sdhc_cdns_combo_phy *sdhc_cdns_combo_phy_reg, - struct sdhc_cdns_sdmmc *sdhc_cdns_sdmmc_reg) -{ - uint32_t value = 0; - int ret = 0; - - /* - * program HRS09, register 42 - * PHY Control and Status Register - */ - value = (CDNS_HRS09_RDDATA_EN(sdhc_cdns_sdmmc_reg->sdhc_rddata_en)) - | (CDNS_HRS09_RDCMD(sdhc_cdns_sdmmc_reg->sdhc_rdcmd_en)) - | (CDNS_HRS09_EXTENDED_WR(sdhc_cdns_sdmmc_reg->sdhc_extended_wr_mode)) - | (CDNS_HRS09_EXT_RD_MODE(sdhc_cdns_sdmmc_reg->sdhc_extended_rd_mode)); - sys_write32(value, cdns_params.reg_base + SDHC_CDNS_HRS09); - - /* - * program HRS10, register 43 - * Host Controller SDCLK start point adjustment - */ - value = (SDHC_HRS10_HCSDCLKADJ(sdhc_cdns_sdmmc_reg->sdhc_hcsdclkadj)); - sys_write32(value, cdns_params.reg_base + SDHC_CDNS_HRS10); - - /* - * program HRS16, register 48 - * CMD/DAT output delay - */ - value = (CDNS_HRS16_WRDATA1_SDCLK_DLY(sdhc_cdns_sdmmc_reg->sdhc_wrdata1_sdclk_dly)) - | (CDNS_HRS16_WRDATA0_SDCLK_DLY(sdhc_cdns_sdmmc_reg->sdhc_wrdata0_sdclk_dly)) - | (CDNS_HRS16_WRCMD1_SDCLK_DLY(sdhc_cdns_sdmmc_reg->sdhc_wrcmd1_sdclk_dly)) - | (CDNS_HRS16_WRCMD0_SDCLK_DLY(sdhc_cdns_sdmmc_reg->sdhc_wrcmd0_sdclk_dly)) - | (CDNS_HRS16_WRDATA1_DLY(sdhc_cdns_sdmmc_reg->sdhc_wrdata1_dly)) - | (CDNS_HRS16_WRDATA0_DLY(sdhc_cdns_sdmmc_reg->sdhc_wrdata0_dly)) - | (CDNS_HRS16_WRCMD1_DLY(sdhc_cdns_sdmmc_reg->sdhc_wrcmd1_dly)) - | (CDNS_HRS16_WRCMD0_DLY(sdhc_cdns_sdmmc_reg->sdhc_wrcmd0_dly)); - sys_write32(value, cdns_params.reg_base + SDHC_CDNS_HRS16); - - /* - * program HRS07, register 40 - * IO Delay Information Register - */ - value = (CDNS_HRS07_RW_COMPENSATE(sdhc_cdns_sdmmc_reg->sdhc_rw_compensate)) - | (CDNS_HRS07_IDELAY_VAL(sdhc_cdns_sdmmc_reg->sdhc_idelay_val)); - sys_write32(value, cdns_params.reg_base + SDHC_CDNS_HRS07); - - return ret; -} - -static int sdhc_cdns_set_clk(struct sdhc_cdns_params *cdn_sdmmc_dev_type_params) -{ - uint32_t dtcvval, sdclkfsval; - int ret = 0; - - dtcvval = DTC_VAL; - sdclkfsval = 0; - - /* Condition for Default speed mode and SDR12 and SDR_BC */ - if ((cdn_sdmmc_dev_type_params->cdn_sdmmc_dev_type == SD_DS) || - (cdn_sdmmc_dev_type_params->cdn_sdmmc_dev_type == SD_UHS_SDR12) || - (cdn_sdmmc_dev_type_params->cdn_sdmmc_dev_type == EMMC_SDR_BC)) { - sdclkfsval = 4; - } else if ((cdn_sdmmc_dev_type_params->cdn_sdmmc_dev_type == SD_HS) || - (cdn_sdmmc_dev_type_params->cdn_sdmmc_dev_type == SD_UHS_SDR25) || - (cdn_sdmmc_dev_type_params->cdn_sdmmc_dev_type == SD_UHS_DDR50) || - (cdn_sdmmc_dev_type_params->cdn_sdmmc_dev_type == EMMC_SDR)) { - sdclkfsval = 2; - } else if ((cdn_sdmmc_dev_type_params->cdn_sdmmc_dev_type == SD_UHS_SDR50) || - (cdn_sdmmc_dev_type_params->cdn_sdmmc_dev_type == EMMC_DDR) || - (cdn_sdmmc_dev_type_params->cdn_sdmmc_dev_type == EMMC_HS400) || - (cdn_sdmmc_dev_type_params->cdn_sdmmc_dev_type == EMMC_HS400ES)) { - sdclkfsval = 1; - } else if ((cdn_sdmmc_dev_type_params->cdn_sdmmc_dev_type == SD_UHS_SDR104) || - (cdn_sdmmc_dev_type_params->cdn_sdmmc_dev_type == EMMC_HS200)) { - sdclkfsval = 0; - } - - /* Disabling SD clock enable */ - sys_write32(0, cdns_params.reg_base + SDHC_CDNS_SRS11); - sys_write32((dtcvval << CDNS_SRS11_DTCV) | - (sdclkfsval << CDNS_SRS11_SDCLKFS) | (1 << CDNS_SRS11_ICE), - cdns_params.reg_base + SDHC_CDNS_SRS11); - ret = sdhc_cdns_wait_ics(WAIT_ICS_TIME_DELAY_US, cdns_params.reg_base + SDHC_CDNS_SRS11); - if (ret != 0) { - return ret; - } - - /* Enable DLL reset */ - sys_clear_bit(cdns_params.reg_base + SDHC_CDNS_HRS09, 0); - /* Set extended_wr_mode */ - sys_write32(((sys_read32(cdns_params.reg_base + SDHC_CDNS_HRS09) & - 0xFFFFFFF7) | (1 << CDNS_HRS09_EXT_WR_MODE)), (cdns_params.reg_base - + SDHC_CDNS_HRS09)); - /* Release DLL reset */ - sys_set_bit(cdns_params.reg_base + SDHC_CDNS_HRS09, 1); - sys_set_bits(cdns_params.reg_base + SDHC_CDNS_HRS09, (3 << CDNS_HRS09_RDCMD_EN)); - - sys_write32((dtcvval << CDNS_SRS11_DTCV) | (sdclkfsval << CDNS_SRS11_SDCLKFS) | - (1 << CDNS_SRS11_ICE) | (1 << CDNS_SRS11_SDCE), cdns_params.reg_base - + SDHC_CDNS_SRS11); - - sys_write32(0xFFFFFFFF, cdns_params.reg_base + SDHC_CDNS_SRS13); - return 0; -} - -static int sdhc_cdns_reset(void) -{ - int32_t timeout; - - sys_clear_bits(cdns_params.reg_base + SDHC_CDNS_SRS11, 0xFFFF); - - /* Software reset */ - sys_set_bit(cdns_params.reg_base + SDHC_CDNS_HRS00, CDNS_HRS00_SWR); - - /* Wait status command response ready */ - timeout = CARD_REG_TIME_DELAY_US; - if (!WAIT_FOR(((sys_read32(cdns_params.reg_base + SDHC_CDNS_HRS00) & - CDNS_HRS00_SWR) == 0), timeout, k_msleep(1))) { - LOG_ERR("Software reset is not completed...timedout"); - return -ETIMEDOUT; - } - - /* Step 1, switch on DLL_RESET */ - sys_clear_bit(cdns_params.reg_base + SDHC_CDNS_HRS09, CDNS_HRS09_PHY_SW_RESET); - - return 0; -} - -static int sdhc_cdns_init(void) -{ - int ret = 0; - - ret = sdhc_cdns_program_phy_reg(&sdhc_cdns_combo_phy_reg_info, &sdhc_cdns_sdmmc_reg_info); - if (ret != 0U) { - LOG_ERR("SoftPhy register configuration failed"); - return ret; - } - - ret = sdhc_cdns_init_hrs_io(&sdhc_cdns_combo_phy_reg_info, &sdhc_cdns_sdmmc_reg_info); - if (ret != 0U) { - LOG_ERR("Configuration for HRS IO reg failed"); - return ret; - } - - ret = sdhc_cdns_card_present(); - if (ret != CARD_PRESENT) { - LOG_ERR("SD card does not detect"); - return -ETIMEDOUT; - } - - ret = sdhc_cdns_vol_reset(); - if (ret != 0U) { - LOG_ERR("SD/MMC card reset failed"); - return ret; - } - - ret = sdhc_cdns_set_clk(&cdns_params); - if (ret != 0U) { - LOG_ERR("Host controller set clk failed"); - return ret; - } - - return 0; -} - -static int sdhc_cdns_send_cmd(struct sdmmc_cmd *cmd, struct sdhc_data *data) -{ - uint32_t op = 0; - uint32_t value; - uintptr_t base; - int32_t timeout; - uint32_t cmd_indx; - uint32_t status_check = 0; - - __ASSERT(cmd, "Assert %s function call", __func__); - base = cdns_params.reg_base; - cmd_indx = (cmd->cmd_idx) << CDNS_SRS03_COM_IDX; - - if (data) { - switch (cmd->cmd_idx) { - case SD_SWITCH: - op = CDNS_SRS03_DATA_PRSNT; - sys_set_bits(cdns_params.reg_base + SDHC_CDNS_SRS10, SRS10_VAL_SW); - sys_set_bits(cdns_params.reg_base + SDHC_CDNS_SRS11, SRS11_VAL_GEN); - sys_set_bits(cdns_params.reg_base + SDHC_CDNS_SRS15, SRS15_VAL_GEN); - break; - - case SD_WRITE_SINGLE_BLOCK: - case SD_READ_SINGLE_BLOCK: - op = CDNS_SRS03_DATA_PRSNT; - sys_set_bits(cdns_params.reg_base + SDHC_CDNS_SRS10, SRS10_VAL_READ); - sys_set_bits(cdns_params.reg_base + SDHC_CDNS_SRS11, SRS11_VAL_GEN); - sys_set_bits(cdns_params.reg_base + SDHC_CDNS_SRS15, SRS15_VAL_RD_WR); - sys_write32(CDNS_SRS00_SAAR, cdns_params.reg_base + SDHC_CDNS_SRS00); - break; - - case SD_WRITE_MULTIPLE_BLOCK: - case SD_READ_MULTIPLE_BLOCK: - op = CDNS_SRS03_DATA_PRSNT | AUTO_CMD23 | CDNS_SRS03_MULTI_BLK_READ; - sys_set_bits(cdns_params.reg_base + SDHC_CDNS_SRS10, SRS10_VAL_READ); - sys_set_bits(cdns_params.reg_base + SDHC_CDNS_SRS11, SRS11_VAL_GEN); - sys_set_bits(cdns_params.reg_base + SDHC_CDNS_SRS15, SRS15_VAL_RD_WR); - sys_write32(CDNS_SRS00_SAAR, cdns_params.reg_base + SDHC_CDNS_SRS00); - break; - - case SD_APP_SEND_SCR: - op = CDNS_SRS03_DATA_PRSNT; - sys_set_bits(cdns_params.reg_base + SDHC_CDNS_SRS10, ADMA2_32); - sys_set_bits(cdns_params.reg_base + SDHC_CDNS_SRS11, SRS11_VAL_GEN); - sys_set_bits(cdns_params.reg_base + SDHC_CDNS_SRS15, SRS15_VAL_GEN); - break; - - default: - op = 0; - break; - } - } else { - switch (cmd->cmd_idx) { - case SD_GO_IDLE_STATE: - sys_set_bits(cdns_params.reg_base + SDHC_CDNS_SRS11, SRS11_VAL_CID); - sys_set_bits(cdns_params.reg_base + SDHC_CDNS_SRS15, CDNS_SRS15_HV4E); - break; - - case SD_ALL_SEND_CID: - sys_set_bits(cdns_params.reg_base + SDHC_CDNS_SRS11, SRS11_VAL_CID); - sys_set_bits(cdns_params.reg_base + SDHC_CDNS_SRS15, SRS15_VAL_CID); - break; - - case SD_SEND_IF_COND: - op = CDNS_SRS03_CMD_IDX_CHK_EN; - sys_set_bits(cdns_params.reg_base + SDHC_CDNS_SRS11, SRS11_VAL_GEN); - sys_set_bits(cdns_params.reg_base + SDHC_CDNS_SRS15, CDNS_SRS15_HV4E); - break; - - case SD_STOP_TRANSMISSION: - op = CMD_STOP_ABORT_CMD; - break; - - case SD_SEND_STATUS: - break; - - case SD_SELECT_CARD: - op = CDNS_SRS03_MULTI_BLK_READ; - break; - - default: - op = 0; - break; - } - } - - switch (cmd->resp_type) { - case SD_RSP_TYPE_NONE: - op |= (CDNS_SRS03_CMD_READ | CDNS_SRS03_MULTI_BLK_READ | - CDNS_SRS03_DMA_EN | CDNS_SRS03_BLK_CNT_EN); - break; - - case SD_RSP_TYPE_R2: - op |= (CDNS_SRS03_CMD_READ | CDNS_SRS03_MULTI_BLK_READ | - CDNS_SRS03_DMA_EN | CDNS_SRS03_BLK_CNT_EN | - RES_TYPE_SEL_136 | CDNS_SRS03_RESP_CRC); - break; - - case SD_RSP_TYPE_R3: - op |= (CDNS_SRS03_CMD_READ | CDNS_SRS03_MULTI_BLK_READ | - CDNS_SRS03_DMA_EN | CDNS_SRS03_BLK_CNT_EN | RES_TYPE_SEL_48); - break; - - case SD_RSP_TYPE_R1: - if ((cmd->cmd_idx == SD_WRITE_SINGLE_BLOCK) || (cmd->cmd_idx - == SD_WRITE_MULTIPLE_BLOCK)) { - op |= (CDNS_SRS03_DMA_EN | CDNS_SRS03_BLK_CNT_EN | RES_TYPE_SEL_48 - | CDNS_SRS03_RESP_CRC | CDNS_SRS03_CMD_IDX_CHK_EN); - } else { - op |= (CDNS_SRS03_DMA_EN | CDNS_SRS03_BLK_CNT_EN | CDNS_SRS03_CMD_READ - | RES_TYPE_SEL_48 | CDNS_SRS03_RESP_CRC | CDNS_SRS03_CMD_IDX_CHK_EN); - } - break; - - default: - op |= (CDNS_SRS03_DMA_EN | CDNS_SRS03_BLK_CNT_EN | CDNS_SRS03_CMD_READ | - CDNS_SRS03_MULTI_BLK_READ | RES_TYPE_SEL_48 | CDNS_SRS03_RESP_CRC | - CDNS_SRS03_CMD_IDX_CHK_EN); - break; - } - - timeout = CARD_REG_TIME_DELAY_US; - if (!WAIT_FOR((sdhc_cdns_busy() == 0), timeout, k_msleep(1))) { - k_panic(); - } - - sys_write32(~0, cdns_params.reg_base + SDHC_CDNS_SRS12); - - sys_write32(cmd->cmd_arg, cdns_params.reg_base + SDHC_CDNS_SRS02); - sys_write32(RESET_SRS14, cdns_params.reg_base + SDHC_CDNS_SRS14); - sys_write32(op | cmd_indx, cdns_params.reg_base + SDHC_CDNS_SRS03); - - timeout = CARD_REG_TIME_DELAY_US; - if (!WAIT_FOR(((((sys_read32(cdns_params.reg_base + SDHC_CDNS_SRS12)) & - CDNS_SRS03_CMD_DONE) == 1) | (((sys_read32(cdns_params.reg_base + - SDHC_CDNS_SRS12)) & ERROR_INT) == ERROR_INT)), timeout, k_busy_wait(1))) { - LOG_ERR("Response timeout SRS12"); - return -ETIMEDOUT; - } - - value = sys_read32(cdns_params.reg_base + SDHC_CDNS_SRS12); - status_check = value & CDNS_SRS12_ERR_MASK; - if (status_check != 0U) { - LOG_ERR("SD host controller send command failed, SRS12 = %X", status_check); - return -EIO; - } - - if ((op & RES_TYPE_SEL_48) || (op & RES_TYPE_SEL_136)) { - cmd->resp_data[0] = sys_read32(cdns_params.reg_base + SDHC_CDNS_SRS04); - if (op & RES_TYPE_SEL_136) { - cmd->resp_data[1] = sys_read32(cdns_params.reg_base + SDHC_CDNS_SRS05); - cmd->resp_data[2] = sys_read32(cdns_params.reg_base + SDHC_CDNS_SRS06); - cmd->resp_data[3] = sys_read32(cdns_params.reg_base + SDHC_CDNS_SRS07); - - /* 136-bit: RTS=01b, Response field R[127:8] - RESP3[23:0], - * RESP2[31:0], RESP1[31:0], RESP0[31:0] - * Subsystem expects 128 bits response but cadence SDHC sends - * 120 bits response from R[127:8]. Bits manupulation to address - * the correct responses for the 136 bit response type. - */ - cmd->resp_data[3] = ((cmd->resp_data[3] << 8) | ((cmd->resp_data[2] >> 24) - & CDNS_CSD_BYTE_MASK)); - cmd->resp_data[2] = ((cmd->resp_data[2] << 8) | ((cmd->resp_data[1] >> 24) - & CDNS_CSD_BYTE_MASK)); - cmd->resp_data[1] = ((cmd->resp_data[1] << 8) | ((cmd->resp_data[0] >> 24) - & CDNS_CSD_BYTE_MASK)); - cmd->resp_data[0] = (cmd->resp_data[0] << 8); - } - } - - return 0; -} - -static const struct sdhc_cdns_ops cdns_sdmmc_ops = { - .init = sdhc_cdns_init, - .send_cmd = sdhc_cdns_send_cmd, - .card_present = sdhc_cdns_card_present, - .set_ios = sdhc_cdns_set_ios, - .prepare = sdhc_cdns_prepare, - .cache_invd = sdhc_cdns_cache_invd, - .busy = sdhc_cdns_busy, - .reset = sdhc_cdns_reset, -}; - -void sdhc_cdns_sdmmc_init(struct sdhc_cdns_params *params, struct sdmmc_device_info *info, - const struct sdhc_cdns_ops **cb_sdmmc_ops) -{ - __ASSERT_NO_MSG((params != NULL) && - ((params->reg_base & MMC_BLOCK_MASK) == 0) && - ((params->desc_size & MMC_BLOCK_MASK) == 0) && - ((params->reg_phy & MMC_BLOCK_MASK) == 0) && - (params->desc_size > 0) && - (params->clk_rate > 0) && - ((params->bus_width == MMC_BUS_WIDTH_1) || - (params->bus_width == MMC_BUS_WIDTH_4) || - (params->bus_width == MMC_BUS_WIDTH_8))); - - memcpy(&cdns_params, params, sizeof(struct sdhc_cdns_params)); - cdns_params.cdn_sdmmc_dev_type = info->cdn_sdmmc_dev_type; - *cb_sdmmc_ops = &cdns_sdmmc_ops; - - cdns_sdhc_set_sdmmc_params(&sdhc_cdns_combo_phy_reg_info, &sdhc_cdns_sdmmc_reg_info); -} diff --git a/drivers/sdhc/sdhc_cdns/sdhc_cdns_ll.h b/drivers/sdhc/sdhc_cdns/sdhc_cdns_ll.h deleted file mode 100644 index c07e446dad0..00000000000 --- a/drivers/sdhc/sdhc_cdns/sdhc_cdns_ll.h +++ /dev/null @@ -1,489 +0,0 @@ -/* - * Copyright (C) 2023 Intel Corporation - * SPDX-License-Identifier: Apache-2.0 - */ - -#include -#include - -/* HRS09 */ -#define CDNS_HRS09_PHY_SW_RESET BIT(0) -#define CDNS_HRS09_PHY_INIT_COMP BIT(1) -#define CDNS_HRS09_EXT_RD_MODE(x) ((x) << 2) -#define CDNS_HRS09_EXT_WR_MODE 3 -#define CDNS_HRS09_EXTENDED_WR(x) ((x) << 3) -#define CDNS_HRS09_RDCMD_EN 15 -#define CDNS_HRS09_RDCMD(x) ((x) << 15) -#define CDNS_HRS09_RDDATA_EN(x) ((x) << 16) - -/* HRS00 */ -#define CDNS_HRS00_SWR BIT(0) - -/* CMD_DATA_OUTPUT */ -#define SDHC_CDNS_HRS16 0x40 - -/* SRS09 */ -#define CDNS_SRS09_STAT_DAT_BUSY BIT(2) -#define CDNS_SRS09_CI BIT(16) - -/* SRS10 */ -#define CDNS_SRS10_DTW 1 -#define CDNS_SRS10_EDTW 5 -#define CDNS_SRS10_BP 8 -#define CDNS_SRS10_BVS 9 - -/* data bus width */ -#define WIDTH_BIT1 CDNS_SRS10_DTW -#define WIDTH_BIT4 CDNS_SRS10_DTW -#define WIDTH_BIT8 CDNS_SRS10_EDTW - -/* SRS11 */ -#define CDNS_SRS11_ICE BIT(0) -#define CDNS_SRS11_ICS BIT(1) -#define CDNS_SRS11_SDCE BIT(2) -#define CDNS_SRS11_USDCLKFS 6 -#define CDNS_SRS11_SDCLKFS 8 -#define CDNS_SRS11_DTCV 16 -#define CDNS_SRS11_SRFA BIT(24) -#define CDNS_SRS11_SRCMD BIT(25) -#define CDNS_SRS11_SRDAT BIT(26) - -/* - * This value determines the interval by which DAT line timeouts are detected - * The interval can be computed as below: - * • 1111b - Reserved - * • 1110b - t_sdmclk*2(27+2) - * • 1101b - t_sdmclk*2(26+2) - */ -#define READ_CLK (0xa << 16) -#define WRITE_CLK (0xe << 16) -#define DTC_VAL 0xE - -/* SRS12 */ -#define CDNS_SRS12_CC 0U -#define CDNS_SRS12_TC 1 -#define CDNS_SRS12_EINT 15 - -/* SRS01 */ -#define CDNS_SRS01_BLK_SIZE 0U -#define CDNS_SRS01_SDMA_BUF 7 << 12 -#define CDNS_SRS01_BLK_COUNT_CT 16 - -/* SRS15 Registers */ -#define CDNS_SRS15_SDR12 0U -#define CDNS_SRS15_SDR25 BIT(16) -#define CDNS_SRS15_SDR50 (2 << 16) -#define CDNS_SRS15_SDR104 (3 << 16) -#define CDNS_SRS15_DDR50 (4 << 16) -/* V18SE is 0 for DS and HS, 1 for UHS-I */ -#define CDNS_SRS15_V18SE BIT(19) -#define CDNS_SRS15_CMD23_EN BIT(27) -/* HC4E is 0 means version 3.0 and 1 means v 4.0 */ -#define CDNS_SRS15_HV4E BIT(28) -#define CDNS_SRS15_BIT_AD_32 0U -#define CDNS_SRS15_BIT_AD_64 BIT(29) -#define CDNS_SRS15_PVE BIT(31) - -/* Combo PHY */ -#define PHY_DQ_TIMING_REG 0x0 -#define PHY_DQS_TIMING_REG 0x04 -#define PHY_GATE_LPBK_CTRL_REG 0x08 -#define PHY_DLL_MASTER_CTRL_REG 0x0C -#define PHY_DLL_SLAVE_CTRL_REG 0x10 -#define PHY_CTRL_REG 0x80 - -#define PERIPHERAL_SDMMC_MASK 0x60 -#define PERIPHERAL_SDMMC_OFFSET 6 -#define DFI_INTF_MASK 0x1 - -/* PHY_DQS_TIMING_REG */ -#define CP_USE_EXT_LPBK_DQS(x) (x << 22) -#define CP_USE_LPBK_DQS(x) (x << 21) -#define CP_USE_PHONY_DQS(x) (x << 20) -#define CP_USE_PHONY_DQS_CMD(x) (x << 19) - -/* PHY_GATE_LPBK_CTRL_REG */ -#define CP_SYNC_METHOD(x) ((x) << 31) -#define CP_SW_HALF_CYCLE_SHIFT(x) ((x) << 28) -#define CP_RD_DEL_SEL(x) ((x) << 19) -#define CP_UNDERRUN_SUPPRESS(x) ((x) << 18) -#define CP_GATE_CFG_ALWAYS_ON(x) ((x) << 6) - -/* PHY_DLL_MASTER_CTRL_REG */ -#define CP_DLL_BYPASS_MODE(x) ((x) << 23) -#define CP_DLL_START_POINT(x) ((x) << 0) - -/* PHY_DLL_SLAVE_CTRL_REG */ -#define CP_READ_DQS_CMD_DELAY(x) ((x) << 24) -#define CP_CLK_WRDQS_DELAY(x) ((x) << 16) -#define CP_CLK_WR_DELAY(x) ((x) << 8) -#define CP_READ_DQS_DELAY(x) (x) - -/* PHY_DQ_TIMING_REG */ -#define CP_IO_MASK_ALWAYS_ON(x) ((x) << 31) -#define CP_IO_MASK_END(x) ((x) << 27) -#define CP_IO_MASK_START(x) ((x) << 24) -#define CP_DATA_SELECT_OE_END(x) (x) - -/* SW RESET REG */ -#define SDHC_CDNS_HRS00 (0x00) -#define CDNS_HRS00_SWR BIT(0) - -/* PHY access port */ -#define SDHC_CDNS_HRS04 0x10 -#define CDNS_HRS04_ADDR GENMASK(5, 0) - -/* PHY data access port */ -#define SDHC_CDNS_HRS05 0x14 - -/* eMMC control registers */ -#define SDHC_CDNS_HRS06 0x18 - -/* PHY_CTRL_REG */ -#define CP_PHONY_DQS_TIMING_MASK 0x3F -#define CP_PHONY_DQS_TIMING_SHIFT 4 - -/* SRS */ -#define SDHC_CDNS_SRS00 0x200 -#define SDHC_CDNS_SRS01 0x204 -#define SDHC_CDNS_SRS02 0x208 -#define SDHC_CDNS_SRS03 0x20c -#define SDHC_CDNS_SRS04 0x210 -#define SDHC_CDNS_SRS05 0x214 -#define SDHC_CDNS_SRS06 0x218 -#define SDHC_CDNS_SRS07 0x21C -#define SDHC_CDNS_SRS08 0x220 -#define SDHC_CDNS_SRS09 0x224 -#define SDHC_CDNS_SRS10 0x228 -#define SDHC_CDNS_SRS11 0x22C -#define SDHC_CDNS_SRS12 0x230 -#define SDHC_CDNS_SRS13 0x234 -#define SDHC_CDNS_SRS14 0x238 -#define SDHC_CDNS_SRS15 0x23c -#define SDHC_CDNS_SRS21 0x254 -#define SDHC_CDNS_SRS22 0x258 -#define SDHC_CDNS_SRS23 0x25c - -/* SRS00 */ -#define CDNS_SRS00_SAAR 1 - -/* SRS03 */ -#define CDNS_SRS03_CMD_START BIT(31) -#define CDNS_SRS03_CMD_USE_HOLD_REG BIT(29) -#define CDNS_SRS03_CMD_UPDATE_CLK_ONLY BIT(21) -#define CDNS_SRS03_CMD_SEND_INIT BIT(15) -/* Command type */ -#define CDNS_SRS03_CMD_TYPE BIT(22) -#define CMD_STOP_ABORT_CMD (3 << 22) -#define CMD_RESUME_CMD (2 << 22) -#define CMD_SUSPEND_CMD BIT(22) -#define CDNS_SRS03_DATA_PRSNT BIT(21) -#define CDNS_SRS03_CMD_IDX_CHK_EN BIT(20) -#define CDNS_SRS03_CMD_READ BIT(4) -#define CDNS_SRS03_MULTI_BLK_READ BIT(5) -#define CDNS_SRS03_RESP_ERR BIT(7) -#define CDNS_SRS03_RESP_CRC BIT(19) -#define CDNS_SRS03_CMD_DONE BIT(0) -/* Response type select */ -#define CDNS_SRS03_RES_TYPE_SEL BIT(16) -#define RES_TYPE_SEL_48 (2 << 16) -#define RES_TYPE_SEL_136 (1 << 16) -#define RES_TYPE_SEL_48_B (3 << 16) -#define RES_TYPE_SEL_NO (0 << 16) -/* Auto CMD Enable */ -#define CDNS_SRS03_AUTO_CMD_EN BIT(2) -#define AUTO_CMD23 (2 << 2) -#define AUTO_CMD12 BIT(2) -#define AUTO_CMD_AUTO (3 << 2) -#define CDNS_SRS03_COM_IDX 24 -#define ERROR_INT BIT(15) -#define CDNS_SRS03_DMA_EN BIT(0) -#define CDNS_SRS03_BLK_CNT_EN BIT(1) - -/* HRS07 */ -#define SDHC_CDNS_HRS07 0x1c -#define CDNS_HRS07_IDELAY_VAL(x) (x) -#define CDNS_HRS07_RW_COMPENSATE(x) ((x) << 16) - -/* PHY reset port */ -#define SDHC_CDNS_HRS09 0x24 - -/* HRS10 */ -/* PHY reset port */ -#define SDHC_CDNS_HRS10 0x28 - -/* HCSDCLKADJ DATA; DDR Mode */ -#define SDHC_HRS10_HCSDCLKADJ(x) ((x) << 16) - -/* HRS16 */ -#define CDNS_HRS16_WRCMD0_DLY(x) (x) -#define CDNS_HRS16_WRCMD1_DLY(x) ((x) << 4) -#define CDNS_HRS16_WRDATA0_DLY(x) ((x) << 8) -#define CDNS_HRS16_WRDATA1_DLY(x) ((x) << 12) -#define CDNS_HRS16_WRCMD0_SDCLK_DLY(x) ((x) << 16) -#define CDNS_HRS16_WRCMD1_SDCLK_DLY(x) ((x) << 20) -#define CDNS_HRS16_WRDATA0_SDCLK_DLY(x) ((x) << 24) -#define CDNS_HRS16_WRDATA1_SDCLK_DLY(x) ((x) << 28) - -/* Shared Macros */ -#define SDMMC_CDN(_reg) (SDMMC_CDN_REG_BASE + \ - (SDMMC_CDN_##_reg)) - -/* MMC Peripheral Definition */ -#define MMC_BLOCK_SIZE 512U -#define MMC_BLOCK_MASK (MMC_BLOCK_SIZE - 1) -#define MMC_BOOT_CLK_RATE (400 * 1000) - -#define OCR_POWERUP BIT(31) -#define OCR_HCS BIT(30) - -#define OCR_3_5_3_6 BIT(23) -#define OCR_3_4_3_5 BIT(22) -#define OCR_3_3_3_4 BIT(21) -#define OCR_3_2_3_3 BIT(20) -#define OCR_3_1_3_2 BIT(19) -#define OCR_3_0_3_1 BIT(18) -#define OCR_2_9_3_0 BIT(17) -#define OCR_2_8_2_9 BIT(16) -#define OCR_2_7_2_8 BIT(15) -#define OCR_VDD_MIN_2V7 GENMASK(23, 15) -#define OCR_VDD_MIN_2V0 GENMASK(14, 8) -#define OCR_VDD_MIN_1V7 BIT(7) - -#define MMC_RSP_48 BIT(0) -#define MMC_RSP_136 BIT(1) /* 136 bit response */ -#define MMC_RSP_CRC BIT(2) /* expect valid crc */ -#define MMC_RSP_CMD_IDX BIT(3) /* response contains cmd idx */ -#define MMC_RSP_BUSY BIT(4) /* device may be busy */ - -/* JEDEC 4.51 chapter 6.12 */ -#define MMC_RESPONSE_R1 (MMC_RSP_48 | MMC_RSP_CMD_IDX | MMC_RSP_CRC) -#define MMC_RESPONSE_R1B (MMC_RESPONSE_R1 | MMC_RSP_BUSY) -#define MMC_RESPONSE_R2 (MMC_RSP_48 | MMC_RSP_136 | MMC_RSP_CRC) -#define MMC_RESPONSE_R3 (MMC_RSP_48) -#define MMC_RESPONSE_R4 (MMC_RSP_48) -#define MMC_RESPONSE_R5 (MMC_RSP_48 | MMC_RSP_CRC | MMC_RSP_CMD_IDX) -#define MMC_RESPONSE_R6 (MMC_RSP_CRC | MMC_RSP_CMD_IDX) -#define MMC_RESPONSE_R7 (MMC_RSP_48 | MMC_RSP_CRC) -#define MMC_RESPONSE_NONE 0 - -/* Value randomly chosen for eMMC RCA, it should be > 1 */ -#define MMC_FIX_RCA 6 -#define RCA_SHIFT_OFFSET 16 - -#define CMD_EXTCSD_PARTITION_CONFIG 179 -#define CMD_EXTCSD_BUS_WIDTH 183 -#define CMD_EXTCSD_HS_TIMING 185 -#define CMD_EXTCSD_SEC_CNT 212 - -#define PART_CFG_BOOT_PARTITION1_ENABLE BIT(3) -#define PART_CFG_PARTITION1_ACCESS 1 - -/* Values in EXT CSD register */ -#define MMC_BUS_WIDTH_1 0 -#define MMC_BUS_WIDTH_4 1 -#define MMC_BUS_WIDTH_8 2 -#define MMC_BUS_WIDTH_DDR_4 5 -#define MMC_BUS_WIDTH_DDR_8 6 -#define MMC_BOOT_MODE_BACKWARD 0 -#define MMC_BOOT_MODE_HS_TIMING BIT(3) -#define MMC_BOOT_MODE_DDR (2 << 3) - -#define EXTCSD_SET_CMD 0 -#define EXTCSD_SET_BITS BIT(24) -#define EXTCSD_CLR_BITS (2 << 24) -#define EXTCSD_WRITE_BYTES (3 << 24) -#define EXTCSD_CMD(x) (((x) & 0xff) << 16) -#define EXTCSD_VALUE(x) (((x) & 0xff) << 8) -#define EXTCSD_CMD_SET_NORMAL 1 - -#define CSD_TRAN_SPEED_UNIT_MASK GENMASK(2, 0) -#define CSD_TRAN_SPEED_MULT_MASK GENMASK(6, 3) -#define CSD_TRAN_SPEED_MULT_SHIFT 3 - -#define STATUS_CURRENT_STATE(x) (((x) & 0xf) << 9) -#define STATUS_READY_FOR_DATA BIT(8) -#define STATUS_SWITCH_ERROR BIT(7) -#define MMC_GET_STATE(x) (((x) >> 9) & 0xf) -#define MMC_STATE_IDLE 0 -#define MMC_STATE_READY 1 -#define MMC_STATE_IDENT 2 -#define MMC_STATE_STBY 3 -#define MMC_STATE_TRAN 4 -#define MMC_STATE_DATA 5 -#define MMC_STATE_RCV 6 -#define MMC_STATE_PRG 7 -#define MMC_STATE_DIS 8 -#define MMC_STATE_BTST 9 -#define MMC_STATE_SLP 10 - -#define MMC_FLAG_CMD23 1 - -#define CMD8_CHECK_PATTERN 0xAA -#define VHS_2_7_3_6_V BIT(8) - -#define SD_SCR_BUS_WIDTH_1 BIT(8) -#define SD_SCR_BUS_WIDTH_4 BIT(10) - -/* ADMA table component */ -#define ADMA_DESC_ATTR_VALID BIT(0) -#define ADMA_DESC_ATTR_END BIT(1) -#define ADMA_DESC_ATTR_INT BIT(2) -#define ADMA_DESC_ATTR_ACT1 BIT(4) -#define ADMA_DESC_ATTR_ACT2 BIT(5) -#define ADMA_DESC_TRANSFER_DATA ADMA_DESC_ATTR_ACT2 - -/* SRS10 Register */ -#define LEDC BIT(0) -#define DT_WIDTH BIT(1) -#define HS_EN BIT(2) -/* Conf depends on SRS15.HV4E */ -#define SDMA 0 -#define ADMA2_32 (2 << 3) -#define ADMA2_64 (3 << 3) -/* here 0 defines the 64 Kb size */ -#define MAX_64KB_PAGE 0 - -struct sdmmc_cmd { - unsigned int cmd_idx; - unsigned int cmd_arg; - unsigned int resp_type; - unsigned int resp_data[4]; -}; - -struct sdhc_cdns_ops { - /* init function for card */ - int (*init)(void); - /* busy check function for card */ - int (*busy)(void); - /* card_present function check for card */ - int (*card_present)(void); - /* reset the card */ - int (*reset)(void); - /* send command and respective argument */ - int (*send_cmd)(struct sdmmc_cmd *cmd, struct sdhc_data *data); - /* io set up for card */ - int (*set_ios)(unsigned int clk, unsigned int width); - /* prepare dma descriptors */ - int (*prepare)(uint32_t lba, uintptr_t buf, struct sdhc_data *data); - /* cache invd api */ - int (*cache_invd)(int lba, uintptr_t buf, size_t size); -}; - -/* Combo Phy reg */ -struct sdhc_cdns_combo_phy { - uint32_t cp_clk_wr_delay; - uint32_t cp_clk_wrdqs_delay; - uint32_t cp_data_select_oe_end; - uint32_t cp_dll_bypass_mode; - uint32_t cp_dll_locked_mode; - uint32_t cp_dll_start_point; - uint32_t cp_gate_cfg_always_on; - uint32_t cp_io_mask_always_on; - uint32_t cp_io_mask_end; - uint32_t cp_io_mask_start; - uint32_t cp_rd_del_sel; - uint32_t cp_read_dqs_cmd_delay; - uint32_t cp_read_dqs_delay; - uint32_t cp_sw_half_cycle_shift; - uint32_t cp_sync_method; - uint32_t cp_underrun_suppress; - uint32_t cp_use_ext_lpbk_dqs; - uint32_t cp_use_lpbk_dqs; - uint32_t cp_use_phony_dqs; - uint32_t cp_use_phony_dqs_cmd; -}; - -/* sdmmc reg */ -struct sdhc_cdns_sdmmc { - uint32_t sdhc_extended_rd_mode; - uint32_t sdhc_extended_wr_mode; - uint32_t sdhc_hcsdclkadj; - uint32_t sdhc_idelay_val; - uint32_t sdhc_rdcmd_en; - uint32_t sdhc_rddata_en; - uint32_t sdhc_rw_compensate; - uint32_t sdhc_sdcfsh; - uint32_t sdhc_sdcfsl; - uint32_t sdhc_wrcmd0_dly; - uint32_t sdhc_wrcmd0_sdclk_dly; - uint32_t sdhc_wrcmd1_dly; - uint32_t sdhc_wrcmd1_sdclk_dly; - uint32_t sdhc_wrdata0_dly; - uint32_t sdhc_wrdata0_sdclk_dly; - uint32_t sdhc_wrdata1_dly; - uint32_t sdhc_wrdata1_sdclk_dly; -}; - -enum sdmmc_device_mode { - /* Identification */ - SD_DS_ID, - /* Default speed */ - SD_DS, - /* High speed */ - SD_HS, - /* Ultra high speed SDR12 */ - SD_UHS_SDR12, - /* Ultra high speed SDR25 */ - SD_UHS_SDR25, - /* Ultra high speed SDR`50 */ - SD_UHS_SDR50, - /* Ultra high speed SDR104 */ - SD_UHS_SDR104, - /* Ultra high speed DDR50 */ - SD_UHS_DDR50, - /* SDR backward compatible */ - EMMC_SDR_BC, - /* SDR */ - EMMC_SDR, - /* DDR */ - EMMC_DDR, - /* High speed 200Mhz in SDR */ - EMMC_HS200, - /* High speed 200Mhz in DDR */ - EMMC_HS400, - /* High speed 200Mhz in SDR with enhanced strobe */ - EMMC_HS400ES, -}; - -struct sdhc_cdns_params { - uintptr_t reg_base; - uintptr_t reg_phy; - uintptr_t desc_base; - size_t desc_size; - int clk_rate; - int bus_width; - unsigned int flags; - enum sdmmc_device_mode cdn_sdmmc_dev_type; - uint32_t combophy; -}; - -struct sdmmc_device_info { - /* Size of device in bytes */ - unsigned long long device_size; - /* Block size in bytes */ - unsigned int block_size; - /* Max bus freq in Hz */ - unsigned int max_bus_freq; - /* OCR voltage */ - unsigned int ocr_voltage; - /* Type of MMC */ - enum sdmmc_device_mode cdn_sdmmc_dev_type; -}; - -/*descriptor structure with 8 byte alignment*/ -struct sdhc_cdns_desc { - /* 8 bit attribute */ - uint8_t attr; - /* reserved bits in desc */ - uint8_t reserved; - /* page length for the descriptor */ - uint16_t len; - /* lower 32 bits for buffer (64 bit addressing) */ - uint32_t addr_lo; - /* higher 32 bits for buffer (64 bit addressing) */ - uint32_t addr_hi; -} __aligned(8); - -void sdhc_cdns_sdmmc_init(struct sdhc_cdns_params *params, struct sdmmc_device_info *info, - const struct sdhc_cdns_ops **cb_sdmmc_ops); diff --git a/drivers/sdhc/sdhc_cdns_ll.c b/drivers/sdhc/sdhc_cdns_ll.c index 3d8e3f97e4a..773b92b0e05 100644 --- a/drivers/sdhc/sdhc_cdns_ll.c +++ b/drivers/sdhc/sdhc_cdns_ll.c @@ -10,9 +10,9 @@ LOG_MODULE_REGISTER(sdhc_cdns_ll, CONFIG_SDHC_LOG_LEVEL); /* card busy and present */ -#define CARD_BUSY 1 -#define CARD_NOT_BUSY 0 -#define CARD_PRESENT 1 +#define CARD_BUSY 1 +#define CARD_NOT_BUSY 0 +#define CARD_PRESENT 1 /* SRS12 error mask */ #define CDNS_SRS12_ERR_MASK 0xFFFF8000U @@ -98,15 +98,15 @@ static int sdhc_cdns_card_present(void) static int sdhc_cdns_vol_reset(void) { - /* Reset embedded card */ - sys_write32((7 << CDNS_SRS10_BVS) | (0 << CDNS_SRS10_BP), + /* Reset embedded card, turn off supply voltage */ + sys_write32(BUS_VOLTAGE_3_3_V, (cdns_params.reg_base + SDHC_CDNS_SRS10)); /* * Turn on supply voltage * CDNS_SRS10_BVS = 7, CDNS_SRS10_BP = 1, BP2 only in UHS2 mode */ - sys_write32((7 << CDNS_SRS10_BVS) | (1 << CDNS_SRS10_BP), + sys_write32(BUS_VOLTAGE_3_3_V | CDNS_SRS10_BP, (cdns_params.reg_base + SDHC_CDNS_SRS10)); return 0; @@ -349,8 +349,9 @@ static int sdhc_cdns_prepare(uint32_t dma_start_addr, uintptr_t dma_buff, desc_cnt * sizeof(struct sdhc_cdns_desc)); sys_write32((data->block_size << CDNS_SRS01_BLK_SIZE | - data->blocks << CDNS_SRS01_BLK_COUNT_CT | CDNS_SRS01_SDMA_BUF), - cdns_params.reg_base + SDHC_CDNS_SRS01); + data->blocks << CDNS_SRS01_BLK_COUNT_CT | + BUFFER_BOUNDARY_512K << CDNS_SRS01_SDMA_BUF), + cdns_params.reg_base + SDHC_CDNS_SRS01); return 0; } @@ -364,7 +365,7 @@ static int sdhc_cdns_host_set_clk(int clk) sdclkfsval = (cdns_params.clk_rate / 2000) / clk; sys_write32(0, cdns_params.reg_base + SDHC_CDNS_SRS11); sys_write32(((dtcvval << CDNS_SRS11_DTCV) | (sdclkfsval << CDNS_SRS11_SDCLKFS) | - (1 << CDNS_SRS11_ICE)), cdns_params.reg_base + SDHC_CDNS_SRS11); + CDNS_SRS11_ICE), cdns_params.reg_base + SDHC_CDNS_SRS11); ret = sdhc_cdns_wait_ics(WAIT_ICS_TIME_DELAY_US, cdns_params.reg_base + SDHC_CDNS_SRS11); if (ret != 0) { @@ -375,14 +376,14 @@ static int sdhc_cdns_host_set_clk(int clk) sys_clear_bit(cdns_params.reg_base + SDHC_CDNS_HRS09, 0); /* Set extended_wr_mode */ sys_write32(((sys_read32(cdns_params.reg_base + SDHC_CDNS_HRS09) - & 0xFFFFFFF7) | (1 << CDNS_HRS09_EXT_WR_MODE)), (cdns_params.reg_base + & 0xFFFFFFF7) | CDNS_HRS09_EXT_WR_MODE), (cdns_params.reg_base + SDHC_CDNS_HRS09)); /* Release DLL reset */ - sys_set_bit(cdns_params.reg_base + SDHC_CDNS_HRS09, 1); - sys_set_bits(cdns_params.reg_base + SDHC_CDNS_HRS09, (3 << CDNS_HRS09_RDCMD_EN)); + sys_set_bits(cdns_params.reg_base + SDHC_CDNS_HRS09, CDNS_HRS09_RDCMD_EN_BIT | + CDNS_HRS09_RDDATA_EN_BIT); sys_write32(((dtcvval << CDNS_SRS11_DTCV) | (sdclkfsval << CDNS_SRS11_SDCLKFS) - | (1 << CDNS_SRS11_ICE) | (1 << CDNS_SRS11_SDCE)), + | CDNS_SRS11_ICE | CDNS_SRS11_SDCE), cdns_params.reg_base + SDHC_CDNS_SRS11); sys_write32(0xFFFFFFFF, cdns_params.reg_base + SDHC_CDNS_SRS13); @@ -433,7 +434,7 @@ static int sdhc_cdns_init_hrs_io(struct sdhc_cdns_combo_phy *sdhc_cdns_combo_phy * PHY Control and Status Register */ value = (CDNS_HRS09_RDDATA_EN(sdhc_cdns_sdmmc_reg->sdhc_rddata_en)) - | (CDNS_HRS09_RDCMD(sdhc_cdns_sdmmc_reg->sdhc_rdcmd_en)) + | (CDNS_HRS09_RDCMD_EN(sdhc_cdns_sdmmc_reg->sdhc_rdcmd_en)) | (CDNS_HRS09_EXTENDED_WR(sdhc_cdns_sdmmc_reg->sdhc_extended_wr_mode)) | (CDNS_HRS09_EXT_RD_MODE(sdhc_cdns_sdmmc_reg->sdhc_extended_rd_mode)); sys_write32(value, cdns_params.reg_base + SDHC_CDNS_HRS09); @@ -501,7 +502,7 @@ static int sdhc_cdns_set_clk(struct sdhc_cdns_params *cdn_sdmmc_dev_type_params) /* Disabling SD clock enable */ sys_write32(0, cdns_params.reg_base + SDHC_CDNS_SRS11); sys_write32((dtcvval << CDNS_SRS11_DTCV) | - (sdclkfsval << CDNS_SRS11_SDCLKFS) | (1 << CDNS_SRS11_ICE), + (sdclkfsval << CDNS_SRS11_SDCLKFS) | CDNS_SRS11_ICE, cdns_params.reg_base + SDHC_CDNS_SRS11); ret = sdhc_cdns_wait_ics(WAIT_ICS_TIME_DELAY_US, cdns_params.reg_base + SDHC_CDNS_SRS11); if (ret != 0) { @@ -512,14 +513,14 @@ static int sdhc_cdns_set_clk(struct sdhc_cdns_params *cdn_sdmmc_dev_type_params) sys_clear_bit(cdns_params.reg_base + SDHC_CDNS_HRS09, 0); /* Set extended_wr_mode */ sys_write32(((sys_read32(cdns_params.reg_base + SDHC_CDNS_HRS09) & - 0xFFFFFFF7) | (1 << CDNS_HRS09_EXT_WR_MODE)), (cdns_params.reg_base + 0xFFFFFFF7) | CDNS_HRS09_EXT_WR_MODE), (cdns_params.reg_base + SDHC_CDNS_HRS09)); /* Release DLL reset */ - sys_set_bit(cdns_params.reg_base + SDHC_CDNS_HRS09, 1); - sys_set_bits(cdns_params.reg_base + SDHC_CDNS_HRS09, (3 << CDNS_HRS09_RDCMD_EN)); + sys_set_bits(cdns_params.reg_base + SDHC_CDNS_HRS09, CDNS_HRS09_RDCMD_EN_BIT | + CDNS_HRS09_RDDATA_EN_BIT); sys_write32((dtcvval << CDNS_SRS11_DTCV) | (sdclkfsval << CDNS_SRS11_SDCLKFS) | - (1 << CDNS_SRS11_ICE) | (1 << CDNS_SRS11_SDCE), cdns_params.reg_base + CDNS_SRS11_ICE | CDNS_SRS11_SDCE, cdns_params.reg_base + SDHC_CDNS_SRS11); sys_write32(0xFFFFFFFF, cdns_params.reg_base + SDHC_CDNS_SRS13); @@ -681,7 +682,7 @@ static int sdhc_cdns_send_cmd(struct sdmmc_cmd *cmd, struct sdhc_data *data) case SD_RSP_TYPE_R2: op |= (CDNS_SRS03_CMD_READ | CDNS_SRS03_MULTI_BLK_READ | CDNS_SRS03_DMA_EN | CDNS_SRS03_BLK_CNT_EN | - RES_TYPE_SEL_136 | CDNS_SRS03_RESP_CRC); + RES_TYPE_SEL_136 | CDNS_SRS03_RESP_CRCCE); break; case SD_RSP_TYPE_R3: @@ -693,16 +694,16 @@ static int sdhc_cdns_send_cmd(struct sdmmc_cmd *cmd, struct sdhc_data *data) if ((cmd->cmd_idx == SD_WRITE_SINGLE_BLOCK) || (cmd->cmd_idx == SD_WRITE_MULTIPLE_BLOCK)) { op |= (CDNS_SRS03_DMA_EN | CDNS_SRS03_BLK_CNT_EN | RES_TYPE_SEL_48 - | CDNS_SRS03_RESP_CRC | CDNS_SRS03_CMD_IDX_CHK_EN); + | CDNS_SRS03_RESP_CRCCE | CDNS_SRS03_CMD_IDX_CHK_EN); } else { op |= (CDNS_SRS03_DMA_EN | CDNS_SRS03_BLK_CNT_EN | CDNS_SRS03_CMD_READ - | RES_TYPE_SEL_48 | CDNS_SRS03_RESP_CRC | CDNS_SRS03_CMD_IDX_CHK_EN); + | RES_TYPE_SEL_48 | CDNS_SRS03_RESP_CRCCE | CDNS_SRS03_CMD_IDX_CHK_EN); } break; default: op |= (CDNS_SRS03_DMA_EN | CDNS_SRS03_BLK_CNT_EN | CDNS_SRS03_CMD_READ | - CDNS_SRS03_MULTI_BLK_READ | RES_TYPE_SEL_48 | CDNS_SRS03_RESP_CRC | + CDNS_SRS03_MULTI_BLK_READ | RES_TYPE_SEL_48 | CDNS_SRS03_RESP_CRCCE | CDNS_SRS03_CMD_IDX_CHK_EN); break; } @@ -720,8 +721,9 @@ static int sdhc_cdns_send_cmd(struct sdmmc_cmd *cmd, struct sdhc_data *data) timeout = CARD_REG_TIME_DELAY_US; if (!WAIT_FOR(((((sys_read32(cdns_params.reg_base + SDHC_CDNS_SRS12)) & - CDNS_SRS03_CMD_DONE) == 1) | (((sys_read32(cdns_params.reg_base + - SDHC_CDNS_SRS12)) & ERROR_INT) == ERROR_INT)), timeout, k_busy_wait(1))) { + CDNS_SRS12_CC) == CDNS_SRS12_CC) | (((sys_read32(cdns_params.reg_base + + SDHC_CDNS_SRS12)) & CDNS_SRS12_EINT) == CDNS_SRS12_EINT)), + timeout, k_msleep(1))) { LOG_ERR("Response timeout SRS12"); return -ETIMEDOUT; } diff --git a/drivers/sdhc/sdhc_cdns_ll.h b/drivers/sdhc/sdhc_cdns_ll.h index c07e446dad0..5ffaa75c79c 100644 --- a/drivers/sdhc/sdhc_cdns_ll.h +++ b/drivers/sdhc/sdhc_cdns_ll.h @@ -9,11 +9,12 @@ /* HRS09 */ #define CDNS_HRS09_PHY_SW_RESET BIT(0) #define CDNS_HRS09_PHY_INIT_COMP BIT(1) +#define CDNS_HRS09_EXT_WR_MODE BIT(3) +#define CDNS_HRS09_RDCMD_EN_BIT BIT(15) +#define CDNS_HRS09_RDDATA_EN_BIT BIT(16) #define CDNS_HRS09_EXT_RD_MODE(x) ((x) << 2) -#define CDNS_HRS09_EXT_WR_MODE 3 #define CDNS_HRS09_EXTENDED_WR(x) ((x) << 3) -#define CDNS_HRS09_RDCMD_EN 15 -#define CDNS_HRS09_RDCMD(x) ((x) << 15) +#define CDNS_HRS09_RDCMD_EN(x) ((x) << 15) #define CDNS_HRS09_RDDATA_EN(x) ((x) << 16) /* HRS00 */ @@ -22,31 +23,40 @@ /* CMD_DATA_OUTPUT */ #define SDHC_CDNS_HRS16 0x40 -/* SRS09 */ +/* SRS09 - Present State Register */ #define CDNS_SRS09_STAT_DAT_BUSY BIT(2) #define CDNS_SRS09_CI BIT(16) -/* SRS10 */ -#define CDNS_SRS10_DTW 1 -#define CDNS_SRS10_EDTW 5 -#define CDNS_SRS10_BP 8 -#define CDNS_SRS10_BVS 9 +/* SRS10 - Host Control 1 (General / Power / Block-Gap / Wake-Up) */ +#define LEDC BIT(0) +#define DT_WIDTH BIT(1) +#define HS_EN BIT(2) + +#define CDNS_SRS10_DTW 1 +#define CDNS_SRS10_EDTW 5 +#define CDNS_SRS10_BP BIT(8) + +#define CDNS_SRS10_BVS 9 +#define BUS_VOLTAGE_1_8_V (5 << CDNS_SRS10_BVS) +#define BUS_VOLTAGE_3_0_V (6 << CDNS_SRS10_BVS) +#define BUS_VOLTAGE_3_3_V (7 << CDNS_SRS10_BVS) + /* data bus width */ -#define WIDTH_BIT1 CDNS_SRS10_DTW -#define WIDTH_BIT4 CDNS_SRS10_DTW -#define WIDTH_BIT8 CDNS_SRS10_EDTW +#define WIDTH_BIT1 CDNS_SRS10_DTW +#define WIDTH_BIT4 CDNS_SRS10_DTW +#define WIDTH_BIT8 CDNS_SRS10_EDTW /* SRS11 */ -#define CDNS_SRS11_ICE BIT(0) -#define CDNS_SRS11_ICS BIT(1) -#define CDNS_SRS11_SDCE BIT(2) -#define CDNS_SRS11_USDCLKFS 6 -#define CDNS_SRS11_SDCLKFS 8 -#define CDNS_SRS11_DTCV 16 -#define CDNS_SRS11_SRFA BIT(24) -#define CDNS_SRS11_SRCMD BIT(25) -#define CDNS_SRS11_SRDAT BIT(26) +#define CDNS_SRS11_ICE BIT(0) +#define CDNS_SRS11_ICS BIT(1) +#define CDNS_SRS11_SDCE BIT(2) +#define CDNS_SRS11_USDCLKFS 6 +#define CDNS_SRS11_SDCLKFS 8 +#define CDNS_SRS11_DTCV 16 +#define CDNS_SRS11_SRFA BIT(24) +#define CDNS_SRS11_SRCMD BIT(25) +#define CDNS_SRS11_SRDAT BIT(26) /* * This value determines the interval by which DAT line timeouts are detected @@ -55,26 +65,38 @@ * • 1110b - t_sdmclk*2(27+2) * • 1101b - t_sdmclk*2(26+2) */ -#define READ_CLK (0xa << 16) -#define WRITE_CLK (0xe << 16) #define DTC_VAL 0xE +#define READ_CLK (0xa << CDNS_SRS11_DTCV) +#define WRITE_CLK (0xe << CDNS_SRS11_DTCV) + /* SRS12 */ -#define CDNS_SRS12_CC 0U -#define CDNS_SRS12_TC 1 -#define CDNS_SRS12_EINT 15 +#define CDNS_SRS12_CC BIT(0) +#define CDNS_SRS12_TC BIT(1) +#define CDNS_SRS12_EINT BIT(15) + +/* SDMA Buffer Boundary */ +#define BUFFER_BOUNDARY_4K 0U +#define BUFFER_BOUNDARY_8K 1U +#define BUFFER_BOUNDARY_16K 2U +#define BUFFER_BOUNDARY_32K 3U +#define BUFFER_BOUNDARY_64K 4U +#define BUFFER_BOUNDARY_128K 5U +#define BUFFER_BOUNDARY_256K 6U +#define BUFFER_BOUNDARY_512K 7U /* SRS01 */ #define CDNS_SRS01_BLK_SIZE 0U -#define CDNS_SRS01_SDMA_BUF 7 << 12 +#define CDNS_SRS01_SDMA_BUF 12 #define CDNS_SRS01_BLK_COUNT_CT 16 /* SRS15 Registers */ -#define CDNS_SRS15_SDR12 0U -#define CDNS_SRS15_SDR25 BIT(16) -#define CDNS_SRS15_SDR50 (2 << 16) -#define CDNS_SRS15_SDR104 (3 << 16) -#define CDNS_SRS15_DDR50 (4 << 16) +#define CDNS_SRS15_UMS 16 +#define CDNS_SRS15_SDR12 (0 << CDNS_SRS15_UMS) +#define CDNS_SRS15_SDR25 (1 << CDNS_SRS15_UMS) +#define CDNS_SRS15_SDR50 (2 << CDNS_SRS15_UMS) +#define CDNS_SRS15_SDR104 (3 << CDNS_SRS15_UMS) +#define CDNS_SRS15_DDR50 (4 << CDNS_SRS15_UMS) /* V18SE is 0 for DS and HS, 1 for UHS-I */ #define CDNS_SRS15_V18SE BIT(19) #define CDNS_SRS15_CMD23_EN BIT(27) @@ -170,64 +192,65 @@ /* SRS03 */ #define CDNS_SRS03_CMD_START BIT(31) #define CDNS_SRS03_CMD_USE_HOLD_REG BIT(29) -#define CDNS_SRS03_CMD_UPDATE_CLK_ONLY BIT(21) -#define CDNS_SRS03_CMD_SEND_INIT BIT(15) +#define CDNS_SRS03_COM_IDX 24 + /* Command type */ -#define CDNS_SRS03_CMD_TYPE BIT(22) -#define CMD_STOP_ABORT_CMD (3 << 22) -#define CMD_RESUME_CMD (2 << 22) -#define CMD_SUSPEND_CMD BIT(22) +#define CDNS_SRS03_CMD_TYPE 22 +#define CMD_STOP_ABORT_CMD (3 << CDNS_SRS03_CMD_TYPE) +#define CMD_RESUME_CMD (2 << CDNS_SRS03_CMD_TYPE) +#define CMD_SUSPEND_CMD (1 << CDNS_SRS03_CMD_TYPE) + #define CDNS_SRS03_DATA_PRSNT BIT(21) #define CDNS_SRS03_CMD_IDX_CHK_EN BIT(20) -#define CDNS_SRS03_CMD_READ BIT(4) -#define CDNS_SRS03_MULTI_BLK_READ BIT(5) +#define CDNS_SRS03_RESP_CRCCE BIT(19) #define CDNS_SRS03_RESP_ERR BIT(7) -#define CDNS_SRS03_RESP_CRC BIT(19) -#define CDNS_SRS03_CMD_DONE BIT(0) +#define CDNS_SRS03_MULTI_BLK_READ BIT(5) +#define CDNS_SRS03_CMD_READ BIT(4) + /* Response type select */ -#define CDNS_SRS03_RES_TYPE_SEL BIT(16) -#define RES_TYPE_SEL_48 (2 << 16) -#define RES_TYPE_SEL_136 (1 << 16) -#define RES_TYPE_SEL_48_B (3 << 16) -#define RES_TYPE_SEL_NO (0 << 16) +#define CDNS_SRS03_RES_TYPE_SEL 16 +#define RES_TYPE_SEL_NO (0 << CDNS_SRS03_RES_TYPE_SEL) +#define RES_TYPE_SEL_136 (1 << CDNS_SRS03_RES_TYPE_SEL) +#define RES_TYPE_SEL_48 (2 << CDNS_SRS03_RES_TYPE_SEL) +#define RES_TYPE_SEL_48_B (3 << CDNS_SRS03_RES_TYPE_SEL) + /* Auto CMD Enable */ -#define CDNS_SRS03_AUTO_CMD_EN BIT(2) -#define AUTO_CMD23 (2 << 2) -#define AUTO_CMD12 BIT(2) -#define AUTO_CMD_AUTO (3 << 2) -#define CDNS_SRS03_COM_IDX 24 -#define ERROR_INT BIT(15) -#define CDNS_SRS03_DMA_EN BIT(0) -#define CDNS_SRS03_BLK_CNT_EN BIT(1) +#define CDNS_SRS03_ACE 2 +#define NO_AUTO_COMMAND (0 << CDNS_SRS03_ACE) +#define AUTO_CMD12 (1 << CDNS_SRS03_ACE) +#define AUTO_CMD23 (2 << CDNS_SRS03_ACE) +#define AUTO_CMD_AUTO (3 << CDNS_SRS03_ACE) + +#define CDNS_SRS03_DMA_EN BIT(0) +#define CDNS_SRS03_BLK_CNT_EN BIT(1) -/* HRS07 */ +/* HRS07 - IO Delay Information Register */ #define SDHC_CDNS_HRS07 0x1c #define CDNS_HRS07_IDELAY_VAL(x) (x) #define CDNS_HRS07_RW_COMPENSATE(x) ((x) << 16) -/* PHY reset port */ +/* HRS09 - PHY Control and Status Register */ #define SDHC_CDNS_HRS09 0x24 -/* HRS10 */ -/* PHY reset port */ +/* HRS10 - Host Controller SDCLK start point adjustment */ #define SDHC_CDNS_HRS10 0x28 /* HCSDCLKADJ DATA; DDR Mode */ #define SDHC_HRS10_HCSDCLKADJ(x) ((x) << 16) /* HRS16 */ -#define CDNS_HRS16_WRCMD0_DLY(x) (x) -#define CDNS_HRS16_WRCMD1_DLY(x) ((x) << 4) -#define CDNS_HRS16_WRDATA0_DLY(x) ((x) << 8) -#define CDNS_HRS16_WRDATA1_DLY(x) ((x) << 12) -#define CDNS_HRS16_WRCMD0_SDCLK_DLY(x) ((x) << 16) -#define CDNS_HRS16_WRCMD1_SDCLK_DLY(x) ((x) << 20) -#define CDNS_HRS16_WRDATA0_SDCLK_DLY(x) ((x) << 24) -#define CDNS_HRS16_WRDATA1_SDCLK_DLY(x) ((x) << 28) +#define CDNS_HRS16_WRCMD0_DLY(x) (x) +#define CDNS_HRS16_WRCMD1_DLY(x) ((x) << 4) +#define CDNS_HRS16_WRDATA0_DLY(x) ((x) << 8) +#define CDNS_HRS16_WRDATA1_DLY(x) ((x) << 12) +#define CDNS_HRS16_WRCMD0_SDCLK_DLY(x) ((x) << 16) +#define CDNS_HRS16_WRCMD1_SDCLK_DLY(x) ((x) << 20) +#define CDNS_HRS16_WRDATA0_SDCLK_DLY(x) ((x) << 24) +#define CDNS_HRS16_WRDATA1_SDCLK_DLY(x) ((x) << 28) /* Shared Macros */ -#define SDMMC_CDN(_reg) (SDMMC_CDN_REG_BASE + \ - (SDMMC_CDN_##_reg)) +#define SDMMC_CDN(_reg) (SDMMC_CDN_REG_BASE + \ + (SDMMC_CDN_##_reg)) /* MMC Peripheral Definition */ #define MMC_BLOCK_SIZE 512U @@ -333,10 +356,6 @@ #define ADMA_DESC_ATTR_ACT2 BIT(5) #define ADMA_DESC_TRANSFER_DATA ADMA_DESC_ATTR_ACT2 -/* SRS10 Register */ -#define LEDC BIT(0) -#define DT_WIDTH BIT(1) -#define HS_EN BIT(2) /* Conf depends on SRS15.HV4E */ #define SDMA 0 #define ADMA2_32 (2 << 3) From d267298af22e6a2e948eb5605481e7e800c94f50 Mon Sep 17 00:00:00 2001 From: Tanmay Kathpalia Date: Thu, 18 Jan 2024 10:38:48 +0000 Subject: [PATCH 2611/3723] CODEOWNERS: Update codeowners for SDHC Cadence Updated codeowners for SDHC Cadence Driver files. Signed-off-by: Tanmay Kathpalia --- CODEOWNERS | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CODEOWNERS b/CODEOWNERS index 46b71efa32b..060830cf52b 100644 --- a/CODEOWNERS +++ b/CODEOWNERS @@ -365,7 +365,7 @@ /drivers/spi/*esp32* @sylvioalves /drivers/spi/*pl022* @soburi /drivers/sdhc/ @danieldegrasse -/drivers/sdhc/sdhc_cdns* @roymurlidhar +/drivers/sdhc/sdhc_cdns* @roymurlidhar @tanmaykathpalia /drivers/timer/*arm_arch* @carlocaione /drivers/timer/*cortex_m_systick* @anangl /drivers/timer/*altera_avalon* @nashif From 8a313c152ad0fb9197c72ae508858a62513ead10 Mon Sep 17 00:00:00 2001 From: Fabio Baltieri Date: Thu, 18 Jan 2024 00:18:19 +0000 Subject: [PATCH 2612/3723] input: event-codes: define 0 as reserved Define code 0 as INPUT_KEY_RESERVED, same as linux. Signed-off-by: Fabio Baltieri --- include/zephyr/dt-bindings/input/input-event-codes.h | 2 ++ 1 file changed, 2 insertions(+) diff --git a/include/zephyr/dt-bindings/input/input-event-codes.h b/include/zephyr/dt-bindings/input/input-event-codes.h index 73d5f49b9bb..98d71a2db78 100644 --- a/include/zephyr/dt-bindings/input/input-event-codes.h +++ b/include/zephyr/dt-bindings/input/input-event-codes.h @@ -35,6 +35,8 @@ * @anchor INPUT_KEY_CODES * @{ */ +#define INPUT_KEY_RESERVED 0 /**< Reserved, do not use */ + #define INPUT_KEY_0 11 /**< 0 Key */ #define INPUT_KEY_1 2 /**< 1 Key */ #define INPUT_KEY_2 3 /**< 2 Key */ From 5f989e43787f3533f40fa602baa98e18b15d7202 Mon Sep 17 00:00:00 2001 From: Fabio Baltieri Date: Wed, 17 Jan 2024 23:10:53 +0000 Subject: [PATCH 2613/3723] input: add a keymap driver Add a "input-keymap" driver to translate keyboard matrix event into key events. Signed-off-by: Fabio Baltieri --- dts/bindings/input/input-keymap.yaml | 53 +++++++++ include/zephyr/dt-bindings/input/keymap.h | 13 +++ include/zephyr/input/input_keymap.h | 13 +++ subsys/input/CMakeLists.txt | 1 + subsys/input/Kconfig | 9 ++ subsys/input/input_keymap.c | 127 ++++++++++++++++++++++ tests/drivers/build_all/input/app.overlay | 7 ++ 7 files changed, 223 insertions(+) create mode 100644 dts/bindings/input/input-keymap.yaml create mode 100644 include/zephyr/dt-bindings/input/keymap.h create mode 100644 include/zephyr/input/input_keymap.h create mode 100644 subsys/input/input_keymap.c diff --git a/dts/bindings/input/input-keymap.yaml b/dts/bindings/input/input-keymap.yaml new file mode 100644 index 00000000000..195cb1efb11 --- /dev/null +++ b/dts/bindings/input/input-keymap.yaml @@ -0,0 +1,53 @@ +# Copyright 2024 Google LLC +# SPDX-License-Identifier: Apache-2.0 + +description: | + Row-column to key mapper + + Listens for row-column events from the parent device and reports key events. + + Example configuration: + + #include + #include + + kbd { + ... + keymap { + compatible = "input-keymap"; + keymap = < + MATRIX_KEY(0, 0, INPUT_KEY_1) + MATRIX_KEY(0, 1, INPUT_KEY_2) + MATRIX_KEY(0, 2, INPUT_KEY_3) + MATRIX_KEY(1, 0, INPUT_KEY_4) + MATRIX_KEY(1, 1, INPUT_KEY_5) + MATRIX_KEY(1, 2, INPUT_KEY_6) + MATRIX_KEY(2, 0, INPUT_KEY_7) + MATRIX_KEY(2, 1, INPUT_KEY_8) + MATRIX_KEY(2, 2, INPUT_KEY_9) + >; + row-size = <3>; + col-size = <3>; + }; + }; + +compatible: "input-keymap" + +properties: + keymap: + type: array + required: true + description: | + List of codes, using the MATRIX_KEY() macro. + + row-size: + type: int + required: true + description: | + The number of rows in the keymap. + + col-size: + type: int + required: true + description: | + The number of columns in the keymap. diff --git a/include/zephyr/dt-bindings/input/keymap.h b/include/zephyr/dt-bindings/input/keymap.h new file mode 100644 index 00000000000..65d4b108b03 --- /dev/null +++ b/include/zephyr/dt-bindings/input/keymap.h @@ -0,0 +1,13 @@ +/* + * Copyright 2024 Google LLC + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#ifndef ZEPHYR_INCLUDE_DT_BINDINGS_INPUT_KEYMAP_H_ +#define ZEPHYR_INCLUDE_DT_BINDINGS_INPUT_KEYMAP_H_ + +#define MATRIX_KEY(row, col, code) \ + ((((row) & 0xff) << 24) | (((col) & 0xff) << 16) | ((code) & 0xffff)) + +#endif /* ZEPHYR_INCLUDE_DT_BINDINGS_INPUT_KEYMAP_H_ */ diff --git a/include/zephyr/input/input_keymap.h b/include/zephyr/input/input_keymap.h new file mode 100644 index 00000000000..a3d3534b2ba --- /dev/null +++ b/include/zephyr/input/input_keymap.h @@ -0,0 +1,13 @@ +/* + * Copyright 2024 Google LLC + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#ifndef ZEPHYR_INCLUDE_INPUT_INPUT_KEYMAP_H_ +#define ZEPHYR_INCLUDE_INPUT_INPUT_KEYMAP_H_ + +#define MATRIX_ROW(keymap_entry) (((keymap_entry) >> 24) & 0xff) +#define MATRIX_COL(keymap_entry) (((keymap_entry) >> 16) & 0xff) + +#endif /* ZEPHYR_INCLUDE_INPUT_INPUT_KEYMAP_H_ */ diff --git a/subsys/input/CMakeLists.txt b/subsys/input/CMakeLists.txt index bd26093228b..99b31351399 100644 --- a/subsys/input/CMakeLists.txt +++ b/subsys/input/CMakeLists.txt @@ -5,4 +5,5 @@ zephyr_library() zephyr_library_sources(input.c) zephyr_library_sources(input_utils.c) +zephyr_library_sources_ifdef(CONFIG_INPUT_KEYMAP input_keymap.c) zephyr_library_sources_ifdef(CONFIG_INPUT_LONGPRESS input_longpress.c) diff --git a/subsys/input/Kconfig b/subsys/input/Kconfig index a32ebc03afb..8f6e1556409 100644 --- a/subsys/input/Kconfig +++ b/subsys/input/Kconfig @@ -85,5 +85,14 @@ config INPUT_LONGPRESS bool "Input longpress" default y depends on DT_HAS_ZEPHYR_INPUT_LONGPRESS_ENABLED + help + Enable the input longpress driver. + +config INPUT_KEYMAP + bool "Input keymap" + default y + depends on DT_HAS_INPUT_KEYMAP_ENABLED + help + Enable the input keymap driver. endif # INPUT diff --git a/subsys/input/input_keymap.c b/subsys/input/input_keymap.c new file mode 100644 index 00000000000..4d7e25d22f0 --- /dev/null +++ b/subsys/input/input_keymap.c @@ -0,0 +1,127 @@ +/* + * Copyright 2024 Google LLC + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#define DT_DRV_COMPAT input_keymap + +#include +#include +#include +#include +#include + +#include +LOG_MODULE_REGISTER(input_keymap, CONFIG_INPUT_LOG_LEVEL); + +struct keymap_config { + const struct device *input_dev; + const uint16_t *codes; + uint32_t num_codes; + uint8_t row_size; + uint8_t col_size; +}; + +struct keymap_data { + uint32_t row; + uint32_t col; + bool pressed; +}; + +static void keymap_cb(const struct device *dev, struct input_event *evt) +{ + const struct keymap_config *cfg = dev->config; + struct keymap_data *data = dev->data; + const uint16_t *codes = cfg->codes; + uint32_t offset; + + switch (evt->code) { + case INPUT_ABS_X: + data->col = evt->value; + break; + case INPUT_ABS_Y: + data->row = evt->value; + break; + case INPUT_BTN_TOUCH: + data->pressed = evt->value; + break; + } + + if (!evt->sync) { + return; + } + + if (data->row >= cfg->row_size || + data->col >= cfg->col_size) { + LOG_WRN("keymap event out of range: row=%u col=%u", data->row, data->col); + return; + } + + offset = (data->row * cfg->col_size) + data->col; + + if (offset >= cfg->num_codes || codes[offset] == 0) { + LOG_DBG("keymap event undefined: row=%u col=%u", data->row, data->col); + return; + } + + LOG_DBG("input event: %3u %3u %d", data->row, data->col, data->pressed); + + input_report_key(dev, codes[offset], data->pressed, true, K_FOREVER); +} + +static int keymap_init(const struct device *dev) +{ + const struct keymap_config *cfg = dev->config; + + if (!device_is_ready(cfg->input_dev)) { + LOG_ERR("input device not ready"); + return -ENODEV; + } + + return 0; +} + +#define KEYMAP_ENTRY_OFFSET(keymap_entry, col_size) \ + (MATRIX_ROW(keymap_entry) * col_size + MATRIX_COL(keymap_entry)) + +#define KEYMAP_ENTRY_CODE(keymap_entry) (keymap_entry & 0xffff) + +#define KEYMAP_ENTRY_VALIDATE(node_id, prop, idx) \ + BUILD_ASSERT(MATRIX_ROW(DT_PROP_BY_IDX(node_id, prop, idx)) < \ + DT_PROP(node_id, row_size), "invalid row"); \ + BUILD_ASSERT(MATRIX_COL(DT_PROP_BY_IDX(node_id, prop, idx)) < \ + DT_PROP(node_id, col_size), "invalid col"); + +#define CODES_INIT(node_id, prop, idx) \ + [KEYMAP_ENTRY_OFFSET(DT_PROP_BY_IDX(node_id, prop, idx), DT_PROP(node_id, col_size))] = \ + KEYMAP_ENTRY_CODE(DT_PROP_BY_IDX(node_id, prop, idx)), + +#define INPUT_KEYMAP_DEFINE(inst) \ + static void keymap_cb_##inst(struct input_event *evt) \ + { \ + keymap_cb(DEVICE_DT_INST_GET(inst), evt); \ + } \ + INPUT_CALLBACK_DEFINE(DEVICE_DT_GET_OR_NULL(DT_INST_PARENT(inst)), keymap_cb_##inst); \ + \ + DT_INST_FOREACH_PROP_ELEM(inst, keymap, KEYMAP_ENTRY_VALIDATE) \ + \ + static const uint16_t keymap_codes_##inst[] = { \ + DT_INST_FOREACH_PROP_ELEM(inst, keymap, CODES_INIT) \ + }; \ + \ + static const struct keymap_config keymap_config_##inst = { \ + .input_dev = DEVICE_DT_GET(DT_INST_PARENT(inst)), \ + .codes = keymap_codes_##inst, \ + .num_codes = ARRAY_SIZE(keymap_codes_##inst), \ + .row_size = DT_INST_PROP(inst, row_size), \ + .col_size = DT_INST_PROP(inst, col_size), \ + }; \ + \ + static struct keymap_data keymap_data_##inst; \ + \ + DEVICE_DT_INST_DEFINE(inst, keymap_init, NULL, \ + &keymap_data_##inst, &keymap_config_##inst, \ + POST_KERNEL, CONFIG_INPUT_INIT_PRIORITY, NULL); + +DT_INST_FOREACH_STATUS_OKAY(INPUT_KEYMAP_DEFINE) diff --git a/tests/drivers/build_all/input/app.overlay b/tests/drivers/build_all/input/app.overlay index d1baa128237..8603a479163 100644 --- a/tests/drivers/build_all/input/app.overlay +++ b/tests/drivers/build_all/input/app.overlay @@ -64,6 +64,13 @@ <&test_gpio 3 GPIO_ACTIVE_LOW>, <&test_gpio 4 GPIO_ACTIVE_LOW>; actual-key-mask = <0x0f 0x0a 0x0b>; + + keymap { + compatible = "input-keymap"; + keymap = <0 1 2>; + row-size = <2>; + col-size = <2>; + }; }; kbd-matrix-1 { From db429004fdea646289bdb778e40a171cacfd16cf Mon Sep 17 00:00:00 2001 From: Parthiban Nallathambi Date: Fri, 19 Jan 2024 15:53:38 +0530 Subject: [PATCH 2614/3723] drivers: modem: gsm fix rssi range rssi 31 will be -51dBm or greater, where -51 is valid. Fix the range by allowing until -51. Signed-off-by: Parthiban Nallathambi --- drivers/modem/gsm_ppp.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/modem/gsm_ppp.c b/drivers/modem/gsm_ppp.c index 154092ac356..88ea47b832a 100644 --- a/drivers/modem/gsm_ppp.c +++ b/drivers/modem/gsm_ppp.c @@ -814,7 +814,7 @@ static void gsm_finalize_connection(struct k_work *work) query_rssi_nolock(gsm); if (!((gsm->minfo.mdm_rssi) && (gsm->minfo.mdm_rssi != GSM_RSSI_INVALID) && - (gsm->minfo.mdm_rssi < GSM_RSSI_MAXVAL))) { + (gsm->minfo.mdm_rssi <= GSM_RSSI_MAXVAL))) { LOG_DBG("Not valid RSSI, %s", "retrying..."); if (gsm->retries-- > 0) { From d8108369bc4613b2e90589cf9758d289a032b253 Mon Sep 17 00:00:00 2001 From: Peter Mitsis Date: Tue, 16 Jan 2024 13:31:51 -0500 Subject: [PATCH 2615/3723] tests: smp_suspend: Tweak duration and timeouts Reduces the number of seconds that the test runs to 15 seconds (down from 30 seconds). This should still be sufficient time to determine if there is anything amiss with the synchonous thread suspend/resume. Furthermore, the test itself has been tagged as being slow and its timeout increased to 10 minutes (600 seconds) as some simulators are rather slow. Signed-off-by: Peter Mitsis --- tests/kernel/smp_suspend/src/main.c | 2 +- tests/kernel/smp_suspend/testcase.yaml | 1 + 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/tests/kernel/smp_suspend/src/main.c b/tests/kernel/smp_suspend/src/main.c index 8ddc2854e9d..0ed7111fae1 100644 --- a/tests/kernel/smp_suspend/src/main.c +++ b/tests/kernel/smp_suspend/src/main.c @@ -68,7 +68,7 @@ ZTEST(smp_suspend_resume, test_smp_thread_suspend_resume_stress) k_thread_resume(&thread[0]); - for (unsigned int iteration = 0; iteration < 30; iteration++) { + for (unsigned int iteration = 0; iteration < 15; iteration++) { k_sleep(K_MSEC(1000)); for (i = 0; i < NUM_THREADS; i++) { diff --git a/tests/kernel/smp_suspend/testcase.yaml b/tests/kernel/smp_suspend/testcase.yaml index 542d6b25850..114195ec1ff 100644 --- a/tests/kernel/smp_suspend/testcase.yaml +++ b/tests/kernel/smp_suspend/testcase.yaml @@ -3,4 +3,5 @@ tests: tags: - kernel - smp + timeout: 600 filter: (CONFIG_MP_MAX_NUM_CPUS > 1) From 18c23dec5f60836fc84a9cc93293769dff84e5c2 Mon Sep 17 00:00:00 2001 From: Christopher Friedt Date: Wed, 17 Jan 2024 04:21:26 -0500 Subject: [PATCH 2616/3723] tests: posix: common: free resource in after() for timer suite Create a separate ZTEST_SUITE() to properly manage resources that are shared between test cases. Add some assertions where they were missing. Additionally, we don't need verbose printing in this testsuite, so change `printk()` to `LOG_DBG()` Signed-off-by: Christopher Friedt --- tests/posix/common/src/timer.c | 79 ++++++++++++++++------------------ 1 file changed, 38 insertions(+), 41 deletions(-) diff --git a/tests/posix/common/src/timer.c b/tests/posix/common/src/timer.c index d5868d2959c..9463bc30d78 100644 --- a/tests/posix/common/src/timer.c +++ b/tests/posix/common/src/timer.c @@ -8,6 +8,7 @@ #include #include +#include #define SECS_TO_SLEEP 2 #define DURATION_SECS 1 @@ -15,19 +16,23 @@ #define PERIOD_SECS 0 #define PERIOD_NSECS 100000000 +#define TEST_SIGNAL_VAL SIGTSTP + +LOG_MODULE_REGISTER(timer_test); + static int exp_count; +static timer_t timerid = -1; void handler(union sigval val) { - printk("Handler Signal value :%d for %d times\n", val.sival_int, - ++exp_count); + ++exp_count; + LOG_DBG("Handler Signal value %d for %d times", val.sival_int, exp_count); + zassert_equal(val.sival_int, TEST_SIGNAL_VAL); } void test_timer(int sigev_notify) { - int ret; - struct sigevent sig = { 0 }; - timer_t timerid; + struct sigevent sig = {0}; struct itimerspec value, ovalue; struct timespec ts, te; int64_t nsecs_elapsed, secs_elapsed; @@ -35,46 +40,28 @@ void test_timer(int sigev_notify) exp_count = 0; sig.sigev_notify = sigev_notify; sig.sigev_notify_function = handler; - sig.sigev_value.sival_int = 20; - - if (sigev_notify == SIGEV_SIGNAL) - printk("POSIX timer test SIGEV_SIGNAL\n"); - else - printk("POSIX timer test SIGEV_THREAD\n"); - - ret = timer_create(CLOCK_MONOTONIC, &sig, &timerid); + sig.sigev_value.sival_int = TEST_SIGNAL_VAL; /*TESTPOINT: Check if timer is created successfully*/ - zassert_false(ret, "POSIX timer create failed"); + zassert_ok(timer_create(CLOCK_MONOTONIC, &sig, &timerid)); value.it_value.tv_sec = DURATION_SECS; value.it_value.tv_nsec = DURATION_NSECS; value.it_interval.tv_sec = PERIOD_SECS; value.it_interval.tv_nsec = PERIOD_NSECS; - ret = timer_settime(timerid, 0, &value, &ovalue); + zassert_ok(timer_settime(timerid, 0, &value, &ovalue)); usleep(100 * USEC_PER_MSEC); - ret = timer_gettime(timerid, &value); - zassert_false(ret, "Failed to get time to expire."); - - if (ret == 0) { - printk("Timer fires every %d secs and %d nsecs\n", - (int) value.it_interval.tv_sec, - (int) value.it_interval.tv_nsec); - printk("Time remaining to fire %d secs and %d nsecs\n", - (int) value.it_value.tv_sec, - (int) value.it_value.tv_nsec); - } - - clock_gettime(CLOCK_MONOTONIC, &ts); - /*TESTPOINT: Check if timer has started successfully*/ - zassert_false(ret, "POSIX timer failed to start"); + zassert_ok(timer_gettime(timerid, &value)); - sleep(SECS_TO_SLEEP); + LOG_DBG("Timer fires every %d secs and %d nsecs", (int)value.it_interval.tv_sec, + (int)value.it_interval.tv_nsec); + LOG_DBG("Time remaining to fire %d secs and %d nsecs", (int)value.it_value.tv_sec, + (int)value.it_value.tv_nsec); + clock_gettime(CLOCK_MONOTONIC, &ts); + sleep(SECS_TO_SLEEP); clock_gettime(CLOCK_MONOTONIC, &te); - zassert_equal(ret, 0, "Number of timer overruns is incorrect"); - timer_delete(timerid); if (te.tv_nsec >= ts.tv_nsec) { secs_elapsed = te.tv_sec - ts.tv_sec; @@ -95,34 +82,44 @@ void test_timer(int sigev_notify) exp_count, expected_signal_count); } -ZTEST(timer, test_timer) +ZTEST(timer, test_SIGEV_SIGNAL) { test_timer(SIGEV_SIGNAL); +} + +ZTEST(timer, test_SIGEV_THREAD) +{ test_timer(SIGEV_THREAD); } ZTEST(timer, test_timer_overrun) { - timer_t timerid; struct sigevent sig = { 0 }; struct itimerspec value; sig.sigev_notify = SIGEV_NONE; - timer_create(CLOCK_MONOTONIC, &sig, &timerid); + zassert_ok(timer_create(CLOCK_MONOTONIC, &sig, &timerid)); /*Set the timer to expire every 500 milliseconds*/ value.it_interval.tv_sec = 0; value.it_interval.tv_nsec = 500000000; value.it_value.tv_sec = 0; value.it_value.tv_nsec = 500000000; - timer_settime(timerid, 0, &value, NULL); + zassert_ok(timer_settime(timerid, 0, &value, NULL)); k_sleep(K_MSEC(2500)); - int overruns = timer_getoverrun(timerid); + zassert_equal(timer_getoverrun(timerid), 4, "Number of overruns is incorrect"); +} + +static void after(void *arg) +{ + ARG_UNUSED(arg); - timer_delete(timerid); - zassert_equal(overruns, 4, "Number of overruns is incorrect"); + if (timerid != -1) { + (void)timer_delete(timerid); + timerid = -1; + } } -ZTEST_SUITE(timer, NULL, NULL, NULL, NULL, NULL); +ZTEST_SUITE(timer, NULL, NULL, NULL, after, NULL); From 5a3f53551f353e3b6284eecd7de760f5d4a1b415 Mon Sep 17 00:00:00 2001 From: Martin Kiepfer Date: Wed, 27 Dec 2023 12:29:24 +0100 Subject: [PATCH 2617/3723] drivers: display: gc9a01a: Add support for SPI display controller gc9a01a Adding driver for GC9A01A 240x240 based LCD displays. Should be working with GC9C01 as well (untested). Signed-off-by: Martin Kiepfer --- drivers/display/CMakeLists.txt | 1 + drivers/display/Kconfig | 1 + drivers/display/Kconfig.gc9x01x | 10 + drivers/display/display_gc9x01x.c | 698 ++++++++++++++++++ drivers/display/display_gc9x01x.h | 101 +++ dts/bindings/display/galaxycore,gc9x01x.yaml | 149 ++++ dts/bindings/vendor-prefixes.txt | 1 + tests/drivers/build_all/display/app.overlay | 12 + .../build_all/display/display_gc9x01x.conf | 1 + tests/drivers/build_all/display/testcase.yaml | 2 + 10 files changed, 976 insertions(+) create mode 100644 drivers/display/Kconfig.gc9x01x create mode 100644 drivers/display/display_gc9x01x.c create mode 100644 drivers/display/display_gc9x01x.h create mode 100644 dts/bindings/display/galaxycore,gc9x01x.yaml create mode 100644 tests/drivers/build_all/display/display_gc9x01x.conf diff --git a/drivers/display/CMakeLists.txt b/drivers/display/CMakeLists.txt index 20bd8659aff..3b166e73892 100644 --- a/drivers/display/CMakeLists.txt +++ b/drivers/display/CMakeLists.txt @@ -23,6 +23,7 @@ zephyr_library_sources_ifdef(CONFIG_STM32_LTDC display_stm32_ltdc.c) zephyr_library_sources_ifdef(CONFIG_RM68200 display_rm68200.c) zephyr_library_sources_ifdef(CONFIG_RM67162 display_rm67162.c) zephyr_library_sources_ifdef(CONFIG_HX8394 display_hx8394.c) +zephyr_library_sources_ifdef(CONFIG_GC9X01X display_gc9x01x.c) zephyr_library_sources_ifdef(CONFIG_MICROBIT_DISPLAY mb_display.c diff --git a/drivers/display/Kconfig b/drivers/display/Kconfig index f6a39f0f984..53b1a6f3917 100644 --- a/drivers/display/Kconfig +++ b/drivers/display/Kconfig @@ -40,5 +40,6 @@ source "drivers/display/Kconfig.intel_multibootfb" source "drivers/display/Kconfig.mcux_dcnano_lcdif" source "drivers/display/Kconfig.otm8009a" source "drivers/display/Kconfig.hx8394" +source "drivers/display/Kconfig.gc9x01x" endif # DISPLAY diff --git a/drivers/display/Kconfig.gc9x01x b/drivers/display/Kconfig.gc9x01x new file mode 100644 index 00000000000..aba24c445f1 --- /dev/null +++ b/drivers/display/Kconfig.gc9x01x @@ -0,0 +1,10 @@ +# Copyright 2023 Martin Kiepfer +# SPDX-License-Identifier: Apache-2.0 + +config GC9X01X + bool "GC9X01X display driver" + default y + depends on DT_HAS_GALAXYCORE_GC9X01X_ENABLED + select SPI + help + Enable driver for GC9X01X display driver. diff --git a/drivers/display/display_gc9x01x.c b/drivers/display/display_gc9x01x.c new file mode 100644 index 00000000000..cddf14e11f2 --- /dev/null +++ b/drivers/display/display_gc9x01x.c @@ -0,0 +1,698 @@ +/** + * Copyright (c) 2023 Mr Beam Lasers GmbH. + * Copyright (c) 2023 Amrith Venkat Kesavamoorthi + * Copyright (c) 2023 Martin Kiepfer + * SPDX-License-Identifier: Apache-2.0 + */ +#define DT_DRV_COMPAT galaxycore_gc9x01x + +#include "display_gc9x01x.h" + +#include +#include +#include +#include +#include +#include +#include + +#include +LOG_MODULE_REGISTER(display_gc9x01x, CONFIG_DISPLAY_LOG_LEVEL); + +/* Command/data GPIO level for commands. */ +#define GC9X01X_GPIO_LEVEL_CMD 0U + +/* Command/data GPIO level for data. */ +#define GC9X01X_GPIO_LEVEL_DATA 1U + +/* Maximum number of default init registers */ +#define GC9X01X_NUM_DEFAULT_INIT_REGS 12U + +/* Display data struct */ +struct gc9x01x_data { + uint8_t bytes_per_pixel; + enum display_pixel_format pixel_format; + enum display_orientation orientation; +}; + +/* Configuration data struct.*/ +struct gc9x01x_config { + struct spi_dt_spec spi; + struct gpio_dt_spec cmd_data; + struct gpio_dt_spec reset; + uint8_t pixel_format; + uint16_t orientation; + uint16_t x_resolution; + uint16_t y_resolution; + bool inversion; + const void *regs; +}; + +/* Initialization command data struct */ +struct gc9x01x_default_init_regs { + uint8_t cmd; + uint8_t len; + uint8_t data[GC9X01X_NUM_DEFAULT_INIT_REGS]; +}; + +/* + * Default initialization commands. There are a lot of undocumented commands + * within the manufacturer sample code, that are essential for proper operation of + * the display controller + */ +static const struct gc9x01x_default_init_regs default_init_regs[] = { + { + .cmd = 0xEBU, + .len = 1U, + .data = {0x14U}, + }, + { + .cmd = 0x84U, + .len = 1U, + .data = {0x40U}, + }, + { + .cmd = 0x85U, + .len = 1U, + .data = {0xFFU}, + }, + { + .cmd = 0x86U, + .len = 1U, + .data = {0xFFU}, + }, + { + .cmd = 0x87U, + .len = 1U, + .data = {0xFFU}, + }, + { + .cmd = 0x88U, + .len = 1U, + .data = {0x0AU}, + }, + { + .cmd = 0x89U, + .len = 1U, + .data = {0x21U}, + }, + { + .cmd = 0x8AU, + .len = 1U, + .data = {0x00U}, + }, + { + .cmd = 0x8BU, + .len = 1U, + .data = {0x80U}, + }, + { + .cmd = 0x8CU, + .len = 1U, + .data = {0x01U}, + }, + { + .cmd = 0x8DU, + .len = 1U, + .data = {0x01U}, + }, + { + .cmd = 0x8EU, + .len = 1U, + .data = {0xFFU}, + }, + { + .cmd = 0x8FU, + .len = 1U, + .data = {0xFFU}, + }, + { + .cmd = 0xB6U, + .len = 2U, + .data = {0x00U, 0x20U}, + }, + { + .cmd = 0x90U, + .len = 4U, + .data = {0x08U, 0x08U, 0x08U, 0x08U}, + }, + { + .cmd = 0xBDU, + .len = 1U, + .data = {0x06U}, + }, + { + .cmd = 0xBCU, + .len = 1U, + .data = {0x00U}, + }, + { + .cmd = 0xFFU, + .len = 3U, + .data = {0x60U, 0x01U, 0x04U}, + }, + { + .cmd = 0xBEU, + .len = 1U, + .data = {0x11U}, + }, + { + .cmd = 0xE1U, + .len = 2U, + .data = {0x10U, 0x0EU}, + }, + { + .cmd = 0xDFU, + .len = 3U, + .data = {0x21U, 0x0CU, 0x02U}, + }, + { + .cmd = 0xEDU, + .len = 2U, + .data = {0x1BU, 0x0BU}, + }, + { + .cmd = 0xAEU, + .len = 1U, + .data = {0x77U}, + }, + { + .cmd = 0xCDU, + .len = 1U, + .data = {0x63U}, + }, + { + .cmd = 0x70U, + .len = 9U, + .data = {0x07U, 0x07U, 0x04U, 0x0EU, 0x0FU, 0x09U, 0x07U, 0x08U, 0x03U}, + }, + { + .cmd = 0x62U, + .len = 12U, + .data = {0x18U, 0x0DU, 0x71U, 0xEDU, 0x70U, 0x70U, 0x18U, 0x0FU, 0x71U, 0xEFU, + 0x70U, 0x70U}, + }, + { + .cmd = 0x63U, + .len = 12U, + .data = {0x18U, 0x11U, 0x71U, 0xF1U, 0x70U, 0x70U, 0x18U, 0x13U, 0x71U, 0xF3U, + 0x70U, 0x70U}, + }, + { + .cmd = 0x64U, + .len = 7U, + .data = {0x28U, 0x29U, 0xF1U, 0x01U, 0xF1U, 0x00U, 0x07U}, + }, + { + .cmd = 0x66U, + .len = 10U, + .data = {0x3CU, 0x00U, 0xCDU, 0x67U, 0x45U, 0x45U, 0x10U, 0x00U, 0x00U, 0x00U}, + }, + { + .cmd = 0x67U, + .len = 10U, + .data = {0x00U, 0x3CU, 0x00U, 0x00U, 0x00U, 0x01U, 0x54U, 0x10U, 0x32U, 0x98U}, + }, + { + .cmd = 0x74U, + .len = 7U, + .data = {0x10U, 0x85U, 0x80U, 0x00U, 0x00U, 0x4EU, 0x00U}, + }, + { + .cmd = 0x98U, + .len = 2U, + .data = {0x3EU, 0x07U}, + }, +}; + +static int gc9x01x_transmit(const struct device *dev, uint8_t cmd, const void *tx_data, + size_t tx_len) +{ + const struct gc9x01x_config *config = dev->config; + int ret; + struct spi_buf tx_buf = {.buf = &cmd, .len = 1U}; + struct spi_buf_set tx_bufs = {.buffers = &tx_buf, .count = 1U}; + + ret = gpio_pin_set_dt(&config->cmd_data, GC9X01X_GPIO_LEVEL_CMD); + if (ret < 0) { + return ret; + } + ret = spi_write_dt(&config->spi, &tx_bufs); + if (ret < 0) { + return ret; + } + + /* send data (if any) */ + if (tx_data != NULL) { + tx_buf.buf = (void *)tx_data; + tx_buf.len = tx_len; + + ret = gpio_pin_set_dt(&config->cmd_data, GC9X01X_GPIO_LEVEL_DATA); + if (ret < 0) { + return ret; + } + ret = spi_write_dt(&config->spi, &tx_bufs); + if (ret < 0) { + return ret; + } + } + + return 0; +} + +static int gc9x01x_regs_init(const struct device *dev) +{ + const struct gc9x01x_config *config = dev->config; + const struct gc9x01x_regs *regs = config->regs; + int ret; + + /* Enable inter-command mode */ + ret = gc9x01x_transmit(dev, GC9X01X_CMD_INREGEN1, NULL, 0); + if (ret < 0) { + return ret; + } + ret = gc9x01x_transmit(dev, GC9X01X_CMD_INREGEN2, NULL, 0); + if (ret < 0) { + return ret; + } + + /* Apply default init sequence */ + for (int i = 0; (i < ARRAY_SIZE(default_init_regs)) && (ret == 0); i++) { + ret = gc9x01x_transmit(dev, default_init_regs[i].cmd, default_init_regs[i].data, + default_init_regs[i].len); + if (ret < 0) { + return ret; + } + } + + /* Apply generic configuration */ + ret = gc9x01x_transmit(dev, GC9X01X_CMD_PWRCTRL2, regs->pwrctrl2, sizeof(regs->pwrctrl2)); + if (ret < 0) { + return ret; + } + ret = gc9x01x_transmit(dev, GC9X01X_CMD_PWRCTRL3, regs->pwrctrl3, sizeof(regs->pwrctrl3)); + if (ret < 0) { + return ret; + } + ret = gc9x01x_transmit(dev, GC9X01X_CMD_PWRCTRL4, regs->pwrctrl4, sizeof(regs->pwrctrl4)); + if (ret < 0) { + return ret; + } + ret = gc9x01x_transmit(dev, GC9X01X_CMD_GAMMA1, regs->gamma1, sizeof(regs->gamma1)); + if (ret < 0) { + return ret; + } + ret = gc9x01x_transmit(dev, GC9X01X_CMD_GAMMA2, regs->gamma2, sizeof(regs->gamma2)); + if (ret < 0) { + return ret; + } + ret = gc9x01x_transmit(dev, GC9X01X_CMD_GAMMA3, regs->gamma3, sizeof(regs->gamma3)); + if (ret < 0) { + return ret; + } + ret = gc9x01x_transmit(dev, GC9X01X_CMD_GAMMA4, regs->gamma4, sizeof(regs->gamma4)); + if (ret < 0) { + return ret; + } + ret = gc9x01x_transmit(dev, GC9X01X_CMD_FRAMERATE, regs->framerate, + sizeof(regs->framerate)); + if (ret < 0) { + return ret; + } + + /* Enable Tearing line */ + ret = gc9x01x_transmit(dev, GC9X01X_CMD_TEON, NULL, 0); + if (ret < 0) { + return ret; + } + + return 0; +} + +static int gc9x01x_exit_sleep(const struct device *dev) +{ + int ret; + + ret = gc9x01x_transmit(dev, GC9X01X_CMD_SLPOUT, NULL, 0); + if (ret < 0) { + return ret; + } + + /* + * Exit sleepmode and enable display. 30ms on top of the sleepout time to account for + * any manufacturing defects. + * This is to allow time for the supply voltages and clock circuits stabilize + */ + k_msleep(GC9X01X_SLEEP_IN_OUT_DURATION_MS + 30); + + return 0; +} + +#ifdef CONFIG_PM_DEVICE +static int gc9x01x_enter_sleep(const struct device *dev) +{ + int ret; + + ret = gc9x01x_transmit(dev, GC9X01X_CMD_SLPIN, NULL, 0); + if (ret < 0) { + return ret; + } + + /* + * Exit sleepmode and enable display. 30ms on top of the sleepout time to account for + * any manufacturing defects. + */ + k_msleep(GC9X01X_SLEEP_IN_OUT_DURATION_MS + 30); + + return 0; +} +#endif + +static int gc9x01x_hw_reset(const struct device *dev) +{ + const struct gc9x01x_config *config = dev->config; + + if (config->reset.port == NULL) { + return -ENODEV; + } + + gpio_pin_set_dt(&config->reset, 1U); + k_msleep(100); + gpio_pin_set_dt(&config->reset, 0U); + k_msleep(10); + + return 0; +} + +static int gc9x01x_display_blanking_off(const struct device *dev) +{ + LOG_DBG("Turning display blanking off"); + return gc9x01x_transmit(dev, GC9X01X_CMD_DISPON, NULL, 0); +} + +static int gc9x01x_display_blanking_on(const struct device *dev) +{ + LOG_DBG("Turning display blanking on"); + return gc9x01x_transmit(dev, GC9X01X_CMD_DISPOFF, NULL, 0); +} + +static int gc9x01x_set_pixel_format(const struct device *dev, + const enum display_pixel_format pixel_format) +{ + struct gc9x01x_data *data = dev->data; + int ret; + uint8_t tx_data; + uint8_t bytes_per_pixel; + + if (pixel_format == PIXEL_FORMAT_RGB_565) { + bytes_per_pixel = 2U; + tx_data = GC9X01X_PIXFMT_VAL_MCU_16_BIT | GC9X01X_PIXFMT_VAL_RGB_16_BIT; + } else if (pixel_format == PIXEL_FORMAT_RGB_888) { + bytes_per_pixel = 3U; + tx_data = GC9X01X_PIXFMT_VAL_MCU_18_BIT | GC9X01X_PIXFMT_VAL_RGB_18_BIT; + } else { + LOG_ERR("Unsupported pixel format"); + return -ENOTSUP; + } + + ret = gc9x01x_transmit(dev, GC9X01X_CMD_PIXFMT, &tx_data, 1U); + if (ret < 0) { + return ret; + } + + data->pixel_format = pixel_format; + data->bytes_per_pixel = bytes_per_pixel; + + return 0; +} + +static int gc9x01x_set_orientation(const struct device *dev, + const enum display_orientation orientation) +{ + struct gc9x01x_data *data = dev->data; + int ret; + uint8_t tx_data = GC9X01X_MADCTL_VAL_BGR; + + if (orientation == DISPLAY_ORIENTATION_NORMAL) { + /* works 0° - default */ + } else if (orientation == DISPLAY_ORIENTATION_ROTATED_90) { + /* works CW 90° */ + tx_data |= GC9X01X_MADCTL_VAL_MV | GC9X01X_MADCTL_VAL_MY; + } else if (orientation == DISPLAY_ORIENTATION_ROTATED_180) { + /* works CW 180° */ + tx_data |= GC9X01X_MADCTL_VAL_MY | GC9X01X_MADCTL_VAL_MX | GC9X01X_MADCTL_VAL_MH; + } else if (orientation == DISPLAY_ORIENTATION_ROTATED_270) { + /* works CW 270° */ + tx_data |= GC9X01X_MADCTL_VAL_MV | GC9X01X_MADCTL_VAL_MX; + } + + ret = gc9x01x_transmit(dev, GC9X01X_CMD_MADCTL, &tx_data, 1U); + if (ret < 0) { + return ret; + } + + data->orientation = orientation; + + return 0; +} + +static int gc9x01x_configure(const struct device *dev) +{ + const struct gc9x01x_config *config = dev->config; + int ret; + + /* Set all the required registers. */ + ret = gc9x01x_regs_init(dev); + if (ret < 0) { + return ret; + } + + /* Pixel format */ + ret = gc9x01x_set_pixel_format(dev, config->pixel_format); + if (ret < 0) { + return ret; + } + + /* Orientation */ + ret = gc9x01x_set_orientation(dev, config->orientation); + if (ret < 0) { + return ret; + } + + /* Display inversion mode. */ + if (config->inversion) { + ret = gc9x01x_transmit(dev, GC9X01X_CMD_INVON, NULL, 0); + if (ret < 0) { + return ret; + } + } + + return 0; +} + +static int gc9x01x_init(const struct device *dev) +{ + const struct gc9x01x_config *config = dev->config; + int ret; + + if (!spi_is_ready_dt(&config->spi)) { + LOG_ERR("SPI device is not ready"); + return -ENODEV; + } + + if (!gpio_is_ready_dt(&config->cmd_data)) { + LOG_ERR("Command/Data GPIO device not ready"); + return -ENODEV; + } + + ret = gpio_pin_configure_dt(&config->cmd_data, GPIO_OUTPUT); + if (ret < 0) { + LOG_ERR("Could not configure command/data GPIO (%d)", ret); + return ret; + } + + if (config->reset.port != NULL) { + if (!device_is_ready(config->reset.port)) { + LOG_ERR("Reset GPIO device not ready"); + return -ENODEV; + } + + ret = gpio_pin_configure_dt(&config->reset, GPIO_OUTPUT_INACTIVE); + if (ret < 0) { + LOG_ERR("Could not configure reset GPIO (%d)", ret); + return ret; + } + } + + gc9x01x_hw_reset(dev); + + gc9x01x_display_blanking_on(dev); + + ret = gc9x01x_configure(dev); + if (ret < 0) { + LOG_ERR("Could not configure display (%d)", ret); + return ret; + } + + ret = gc9x01x_exit_sleep(dev); + if (ret < 0) { + LOG_ERR("Could not exit sleep mode (%d)", ret); + return ret; + } + + return 0; +} + +static int gc9x01x_set_mem_area(const struct device *dev, const uint16_t x, const uint16_t y, + const uint16_t w, const uint16_t h) +{ + int ret; + uint16_t spi_data[2]; + + spi_data[0] = sys_cpu_to_be16(x); + spi_data[1] = sys_cpu_to_be16(x + w - 1U); + ret = gc9x01x_transmit(dev, GC9X01X_CMD_COLSET, &spi_data[0], 4U); + if (ret < 0) { + return ret; + } + + spi_data[0] = sys_cpu_to_be16(y); + spi_data[1] = sys_cpu_to_be16(y + h - 1U); + ret = gc9x01x_transmit(dev, GC9X01X_CMD_ROWSET, &spi_data[0], 4U); + if (ret < 0) { + return ret; + } + + return 0; +} + +static int gc9x01x_write(const struct device *dev, const uint16_t x, const uint16_t y, + const struct display_buffer_descriptor *desc, const void *buf) +{ + const struct gc9x01x_config *config = dev->config; + struct gc9x01x_data *data = dev->data; + int ret; + const uint8_t *write_data_start = (const uint8_t *)buf; + struct spi_buf tx_buf; + struct spi_buf_set tx_bufs; + uint16_t write_cnt; + uint16_t nbr_of_writes; + uint16_t write_h; + + __ASSERT(desc->width <= desc->pitch, "Pitch is smaller than width"); + __ASSERT((desc->pitch * data->bytes_per_pixel * desc->height) <= desc->buf_size, + "Input buffer to small"); + + LOG_DBG("Writing %dx%d (w,h) @ %dx%d (x,y)", desc->width, desc->height, x, y); + ret = gc9x01x_set_mem_area(dev, x, y, desc->width, desc->height); + if (ret < 0) { + return ret; + } + + if (desc->pitch > desc->width) { + write_h = 1U; + nbr_of_writes = desc->height; + } else { + write_h = desc->height; + nbr_of_writes = 1U; + } + + ret = gc9x01x_transmit(dev, GC9X01X_CMD_MEMWR, write_data_start, + desc->width * data->bytes_per_pixel * write_h); + if (ret < 0) { + return ret; + } + + tx_bufs.buffers = &tx_buf; + tx_bufs.count = 1U; + + write_data_start += desc->pitch * data->bytes_per_pixel; + for (write_cnt = 1U; write_cnt < nbr_of_writes; ++write_cnt) { + tx_buf.buf = (void *)write_data_start; + tx_buf.len = desc->width * data->bytes_per_pixel * write_h; + + ret = spi_write_dt(&config->spi, &tx_bufs); + if (ret < 0) { + return ret; + } + + write_data_start += desc->pitch * data->bytes_per_pixel; + } + + return 0; +} + +static void gc9x01x_get_capabilities(const struct device *dev, + struct display_capabilities *capabilities) +{ + struct gc9x01x_data *data = dev->data; + const struct gc9x01x_config *config = dev->config; + + memset(capabilities, 0, sizeof(struct display_capabilities)); + + capabilities->supported_pixel_formats = PIXEL_FORMAT_RGB_565 | PIXEL_FORMAT_RGB_888; + capabilities->current_pixel_format = data->pixel_format; + + if (data->orientation == DISPLAY_ORIENTATION_NORMAL || + data->orientation == DISPLAY_ORIENTATION_ROTATED_180) { + capabilities->x_resolution = config->x_resolution; + capabilities->y_resolution = config->y_resolution; + } else { + capabilities->x_resolution = config->y_resolution; + capabilities->y_resolution = config->x_resolution; + } + + capabilities->current_orientation = data->orientation; +} + +#ifdef CONFIG_PM_DEVICE +static int gc9x01x_pm_action(const struct device *dev, enum pm_device_action action) +{ + int ret; + + switch (action) { + case PM_DEVICE_ACTION_RESUME: + ret = gc9x01x_exit_sleep(dev); + break; + case PM_DEVICE_ACTION_SUSPEND: + ret = gc9x01x_enter_sleep(dev); + break; + default: + ret = -ENOTSUP; + break; + } + + return ret; +} +#endif /* CONFIG_PM_DEVICE */ + +/* Device driver API*/ +static const struct display_driver_api gc9x01x_api = { + .blanking_on = gc9x01x_display_blanking_on, + .blanking_off = gc9x01x_display_blanking_off, + .write = gc9x01x_write, + .get_capabilities = gc9x01x_get_capabilities, + .set_pixel_format = gc9x01x_set_pixel_format, + .set_orientation = gc9x01x_set_orientation, +}; + +#define GC9X01X_INIT(inst) \ + GC9X01X_REGS_INIT(inst); \ + static const struct gc9x01x_config gc9x01x_config_##inst = { \ + .spi = SPI_DT_SPEC_INST_GET(inst, SPI_OP_MODE_MASTER | SPI_WORD_SET(8), 0), \ + .cmd_data = GPIO_DT_SPEC_INST_GET(inst, cmd_data_gpios), \ + .reset = GPIO_DT_SPEC_INST_GET_OR(inst, reset_gpios, {0}), \ + .pixel_format = DT_INST_PROP(inst, pixel_format), \ + .orientation = DT_INST_ENUM_IDX(inst, orientation), \ + .x_resolution = DT_INST_PROP(inst, width), \ + .y_resolution = DT_INST_PROP(inst, height), \ + .inversion = DT_INST_PROP(inst, display_inversion), \ + .regs = &gc9x01x_regs_##inst, \ + }; \ + static struct gc9x01x_data gc9x01x_data_##inst; \ + PM_DEVICE_DT_INST_DEFINE(inst, gc9x01x_pm_action); \ + DEVICE_DT_INST_DEFINE(inst, &gc9x01x_init, PM_DEVICE_DT_INST_GET(inst), \ + &gc9x01x_data_##inst, &gc9x01x_config_##inst, POST_KERNEL, \ + CONFIG_DISPLAY_INIT_PRIORITY, &gc9x01x_api); + +DT_INST_FOREACH_STATUS_OKAY(GC9X01X_INIT) diff --git a/drivers/display/display_gc9x01x.h b/drivers/display/display_gc9x01x.h new file mode 100644 index 00000000000..ff989dd44cf --- /dev/null +++ b/drivers/display/display_gc9x01x.h @@ -0,0 +1,101 @@ +/** + * Copyright (c) 2023 Mr Beam Lasers GmbH. + * Copyright (c) 2023 Amrith Venkat Kesavamoorthi + * Copyright (c) 2023 Martin Kiepfer + * + * SPDX-License-Identifier: Apache-2.0 + */ +#ifndef ZEPHYR_DRIVERS_DISPLAY_GC9X01X_H_ +#define ZEPHYR_DRIVERS_DISPLAY_GC9X01X_H_ + +#include + +/* Command registers */ +#define GC9X01X_CMD_SLPIN 0x10U /* Enter Sleep Mode */ +#define GC9X01X_CMD_SLPOUT 0x11U /* Exit Sleep Mode */ +#define GC9X01X_CMD_PTLON 0x12U /* Partial Mode ON */ +#define GC9X01X_CMD_NORON 0x13U /* Normal Display Mode ON */ +#define GC9X01X_CMD_INVOFF 0x20U /* Display Inversion OFF */ +#define GC9X01X_CMD_INVON 0x21U /* Display Inversion ON */ +#define GC9X01X_CMD_DISPOFF 0x28U /* Display OFF */ +#define GC9X01X_CMD_DISPON 0x29U /* Display ON */ +#define GC9X01X_CMD_COLSET 0x2AU /* Column Address Set */ +#define GC9X01X_CMD_ROWSET 0x2BU /* Row Address Set */ +#define GC9X01X_CMD_MEMWR 0x2CU /* Memory Write */ +#define GC9X01X_CMD_PTLAR 0x30U /* Partial Area */ +#define GC9X01X_CMD_VSCRDEF 0x33U /* Vertical Scrolling Definition */ +#define GC9X01X_CMD_TEOFF 0x34U /* Tearing Effect Line OFF */ +#define GC9X01X_CMD_TEON 0x35U /* Tearing Effect Line ON */ +#define GC9X01X_CMD_MADCTL 0x36U /* Memory Access Control */ +#define GC9X01X_CMD_VSCRSADD 0x37U /* Vertical Scrolling Start Address */ +#define GC9X01X_CMD_PIXFMT 0x3AU /* Pixel Format Set */ +#define GC9X01X_CMD_DFUNCTR 0xB6U /* Display Function Control */ +#define GC9X01X_CMD_PWRCTRL1 0xC1U /* Power Control 1 */ +#define GC9X01X_CMD_PWRCTRL2 0xC3U /* Power Control 2 */ +#define GC9X01X_CMD_PWRCTRL3 0xC4U /* Power Control 3 */ +#define GC9X01X_CMD_PWRCTRL4 0xC9U /* Power Control 4 */ +#define GC9X01X_CMD_READID1 0xDAU /* Read ID 1 */ +#define GC9X01X_CMD_READID2 0xDBU /* Read ID 2 */ +#define GC9X01X_CMD_READID3 0xDCU /* Read ID 3 */ +#define GC9X01X_CMD_GAMMA1 0xF0U /* Gamma1 (negative polarity) */ +#define GC9X01X_CMD_GAMMA2 0xF1U /* Gamma2 */ +#define GC9X01X_CMD_GAMMA3 0xF2U /* Gamma3 (positive polarity) */ +#define GC9X01X_CMD_GAMMA4 0xF3U /* Gamma4 */ +#define GC9X01X_CMD_INREGEN1 0xFEU /* Inter Register Enable 1 */ +#define GC9X01X_CMD_INREGEN2 0xEFU /* Inter Register Enable 2 */ +#define GC9X01X_CMD_FRAMERATE 0xE8U /* Frame Rate Control */ + +/* GC9X01X_CMD_MADCTL register fields */ +#define GC9X01X_MADCTL_VAL_MY BIT(7U) +#define GC9X01X_MADCTL_VAL_MX BIT(6U) +#define GC9X01X_MADCTL_VAL_MV BIT(5U) +#define GC9X01X_MADCTL_VAL_ML BIT(4U) +#define GC9X01X_MADCTL_VAL_BGR BIT(3U) +#define GC9X01X_MADCTL_VAL_MH BIT(2U) + +/* GC9X01X_CMD_PIXFMT register fields */ +#define GC9X01X_PIXFMT_VAL_RGB_18_BIT 0x60U +#define GC9X01X_PIXFMT_VAL_RGB_16_BIT 0x50U +#define GC9X01X_PIXFMT_VAL_MCU_18_BIT 0x06U +#define GC9X01X_PIXFMT_VAL_MCU_16_BIT 0x05U + +/* Duration to enter/exit sleep mode (see 6.2.3 and 6.4.2 in datasheet) */ +#define GC9X01X_SLEEP_IN_OUT_DURATION_MS 120 + +/* GC9X01X registers to be intitialized */ +#define GC9X01X_CMD_PWRCTRL1_LEN 1U +#define GC9X01X_CMD_PWRCTRL2_LEN 1U +#define GC9X01X_CMD_PWRCTRL3_LEN 1U +#define GC9X01X_CMD_PWRCTRL4_LEN 1U +#define GC9X01X_CMD_GAMMA1_LEN 6U +#define GC9X01X_CMD_GAMMA2_LEN 6U +#define GC9X01X_CMD_GAMMA3_LEN 6U +#define GC9X01X_CMD_GAMMA4_LEN 6U +#define GC9X01X_CMD_FRAMERATE_LEN 1U + +struct gc9x01x_regs { + uint8_t pwrctrl1[GC9X01X_CMD_PWRCTRL1_LEN]; + uint8_t pwrctrl2[GC9X01X_CMD_PWRCTRL2_LEN]; + uint8_t pwrctrl3[GC9X01X_CMD_PWRCTRL3_LEN]; + uint8_t pwrctrl4[GC9X01X_CMD_PWRCTRL4_LEN]; + uint8_t gamma1[GC9X01X_CMD_GAMMA1_LEN]; + uint8_t gamma2[GC9X01X_CMD_GAMMA2_LEN]; + uint8_t gamma3[GC9X01X_CMD_GAMMA3_LEN]; + uint8_t gamma4[GC9X01X_CMD_GAMMA4_LEN]; + uint8_t framerate[GC9X01X_CMD_FRAMERATE_LEN]; +}; + +#define GC9X01X_REGS_INIT(inst) \ + static const struct gc9x01x_regs gc9x01x_regs_##inst = { \ + .pwrctrl1 = DT_INST_PROP(inst, pwrctrl1), \ + .pwrctrl2 = DT_INST_PROP(inst, pwrctrl2), \ + .pwrctrl3 = DT_INST_PROP(inst, pwrctrl3), \ + .pwrctrl4 = DT_INST_PROP(inst, pwrctrl4), \ + .gamma1 = DT_INST_PROP(inst, gamma1), \ + .gamma2 = DT_INST_PROP(inst, gamma2), \ + .gamma3 = DT_INST_PROP(inst, gamma3), \ + .gamma4 = DT_INST_PROP(inst, gamma4), \ + .framerate = DT_INST_PROP(inst, framerate), \ + }; + +#endif /* ZEPHYR_DRIVERS_DISPLAY_GC9X01X_H_ */ diff --git a/dts/bindings/display/galaxycore,gc9x01x.yaml b/dts/bindings/display/galaxycore,gc9x01x.yaml new file mode 100644 index 00000000000..fbfa6009a8a --- /dev/null +++ b/dts/bindings/display/galaxycore,gc9x01x.yaml @@ -0,0 +1,149 @@ +# Copyright (c) 2023 Mr Beam Lasers GmbH. +# Copyright (c) 2023 Amrith Venkat Kesavamoorthi +# Copyright (c) 2023 Martin Kiepfer +# SPDX-License-Identifier: Apache-2.0 + +description: | + GC9X01X display driver. + + This driver implements support for various GC9X01X graphics + controllers and different display sizes. It has been validated + for following controllers: + - GC9101A: (Waveshare 240x240, 1.28inch round lcd display 240x240) + + Here is an example to define a display interface: + + &spi2 { + gc9a01a_lcd: gc9a01a_lcd@0 { + compatible = "galaxycore,gc9x01x"; + reg = <0>; + spi-max-frequency = <100000000>; + cmd-data-gpios = <&gpio0 4 GPIO_ACTIVE_HIGH>; + reset-gpios = <&gpio0 8 GPIO_ACTIVE_LOW>; + pixel-format = ; + + width = <240>; + height = <240>; + pixel-format = ; + }; + }; + + +compatible: "galaxycore,gc9x01x" + +include: [spi-device.yaml, display-controller.yaml, lcd-controller.yaml] + +properties: + reset-gpios: + type: phandle-array + required: true + description: | + RESET pin of the GC9X01X. + If connected directly the MCU pin should be configured + as active low. + + cmd-data-gpios: + type: phandle-array + required: true + description: | + Data/Command pin of the GC9X01X is to be configured + high(1) for data, low(0) for command. + + orientation: + type: string + default: "normal" + enum: + - "normal" + - "90" + - "180" + - "270" + description: Display orientation (CW) in degrees. + + display-inversion: + type: boolean + description: | + Display inversion mode. Every bit is inverted from the frame memory to + the display. + + pwrctrl1: + type: uint8-array + default: [ + 0x00 + ] + description: Power-control 1 register value + + pwrctrl2: + type: uint8-array + default: [ + 0x13 + ] + description: Power-control 2 register value + + pwrctrl3: + type: uint8-array + default: [ + 0x13 + ] + description: Power-control 3 register value + + pwrctrl4: + type: uint8-array + default: [ + 0x22 + ] + description: Power-control 4 register value + + gamma1: + type: uint8-array + default: [ + 0x45, + 0x09, + 0x08, + 0x08, + 0x26, + 0x2A + ] + description: Gamma correction 1 register values (negative polarity) + + gamma2: + type: uint8-array + default: [ + 0x43, + 0x70, + 0x72, + 0x36, + 0x37, + 0x6F + ] + description: Gamma correction 3 register values + + gamma3: + type: uint8-array + default: [ + 0x45, + 0x09, + 0x08, + 0x08, + 0x26, + 0x2A + ] + description: Gamma correction 3 register values (positive polarity) + + gamma4: + type: uint8-array + default: [ + 0x43, + 0x70, + 0x72, + 0x36, + 0x37, + 0x6F + ] + description: Gamma correction 4 register values + + framerate: + type: uint8-array + default: [ + 0x34 + ] + description: Framerate register value diff --git a/dts/bindings/vendor-prefixes.txt b/dts/bindings/vendor-prefixes.txt index d75fd09e0bf..268e72ea8c7 100644 --- a/dts/bindings/vendor-prefixes.txt +++ b/dts/bindings/vendor-prefixes.txt @@ -224,6 +224,7 @@ fsl Freescale Semiconductor ftdi Future Technology Devices International Ltd. fujitsu Fujitsu Ltd. gaisler Gaisler +galaxycore Galaxycore, Inc. gardena GARDENA GmbH gateworks Gateworks Corporation gcw Game Consoles Worldwide diff --git a/tests/drivers/build_all/display/app.overlay b/tests/drivers/build_all/display/app.overlay index d8628f48c09..2ce1a401b37 100644 --- a/tests/drivers/build_all/display/app.overlay +++ b/tests/drivers/build_all/display/app.overlay @@ -44,6 +44,18 @@ width = <320>; height = <240>; }; + + test_spi_gc9x01x: gc9x01x@1 { + compatible = "galaxycore,gc9x01x"; + reg = <1>; + spi-max-frequency = <100000000>; + cmd-data-gpios = <&test_gpio 1 0>; + reset-gpios = <&test_gpio 2 0>; + pixel-format = <16>; + + width = <240>; + height = <240>; + }; }; }; }; diff --git a/tests/drivers/build_all/display/display_gc9x01x.conf b/tests/drivers/build_all/display/display_gc9x01x.conf new file mode 100644 index 00000000000..59bb4930ef3 --- /dev/null +++ b/tests/drivers/build_all/display/display_gc9x01x.conf @@ -0,0 +1 @@ +CONFIG_GC9X01X=y diff --git a/tests/drivers/build_all/display/testcase.yaml b/tests/drivers/build_all/display/testcase.yaml index 06798adb981..71f4ab6098a 100644 --- a/tests/drivers/build_all/display/testcase.yaml +++ b/tests/drivers/build_all/display/testcase.yaml @@ -5,3 +5,5 @@ common: tests: drivers.display.ili9342c.build: extra_args: CONF_FILE=display_ili9342c.conf + drivers.display.gc9x01x.build: + extra_args: CONF_FILE=display_gc9x01x.conf From b103dece67142d38823c545c2c75f97401b3ef4d Mon Sep 17 00:00:00 2001 From: Jai Arora Date: Tue, 9 Jan 2024 00:19:55 +0530 Subject: [PATCH 2618/3723] posix: Adds test for clock_getcpuclockid() Adds test for clock_getcpuclockid() to make sure clock_id is equal to CLOCK_PROCESS_CPUTIME_ID after a successful call Fixes #59954 Signed-off-by: Jai Arora --- tests/posix/common/src/clock.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/tests/posix/common/src/clock.c b/tests/posix/common/src/clock.c index d36c74fe0de..07a825434c5 100644 --- a/tests/posix/common/src/clock.c +++ b/tests/posix/common/src/clock.c @@ -217,10 +217,11 @@ ZTEST(clock, test_realtime) ZTEST(clock, test_clock_getcpuclockid) { int ret = 0; - clockid_t clock_id; + clockid_t clock_id = CLOCK_INVALID; ret = clock_getcpuclockid((pid_t)0, &clock_id); zassert_equal(ret, 0, "POSIX clock_getcpuclock id failed"); + zassert_equal(clock_id, CLOCK_PROCESS_CPUTIME_ID, "POSIX clock_getcpuclock id failed"); ret = clock_getcpuclockid((pid_t)2482, &clock_id); zassert_equal(ret, EPERM, "POSIX clock_getcpuclock id failed"); From ba7b7ffff243e19a5cb2804cab526b0c92ffe0c6 Mon Sep 17 00:00:00 2001 From: Jai Arora Date: Fri, 19 Jan 2024 20:39:35 +0530 Subject: [PATCH 2619/3723] posix: Adds test to check getpid() is not NULL Adds test to check getpid() function is not NULL Signed-off-by: Jai Arora --- tests/posix/headers/src/unistd_h.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/posix/headers/src/unistd_h.c b/tests/posix/headers/src/unistd_h.c index 79586c5b00e..6355997905f 100644 --- a/tests/posix/headers/src/unistd_h.c +++ b/tests/posix/headers/src/unistd_h.c @@ -342,7 +342,7 @@ ZTEST(posix_headers, test_unistd_h) zassert_not_null(getopt); /* zassert_not_null(getpgid); */ /* not implemented */ /* zassert_not_null(getpgrp); */ /* not implemented */ - /* zassert_not_null(getpid); */ /* not implemented */ + zassert_not_null(getpid); /* zassert_not_null(getppid); */ /* not implemented */ /* zassert_not_null(getsid); */ /* not implemented */ /* zassert_not_null(getuid); */ /* not implemented */ From 429188723e4960415d4510bfeea3c0e2b749006b Mon Sep 17 00:00:00 2001 From: Daniel DeGrasse Date: Wed, 17 Jan 2024 00:15:57 +0000 Subject: [PATCH 2620/3723] drivers: sdhc: sdhc_spi: wait for card response until cmd timeout In sdhc_spi_response_get, the logic for slow cards previously only retried reads 16 times. Instead of using this approach, read from the card every 10 ms until the command timeout is reached or it responds. This way, the command timeout will be respected for cards that do not respond. Signed-off-by: Daniel DeGrasse --- drivers/sdhc/sdhc_spi.c | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/drivers/sdhc/sdhc_spi.c b/drivers/sdhc/sdhc_spi.c index 42247044143..48e3704a098 100644 --- a/drivers/sdhc/sdhc_spi.c +++ b/drivers/sdhc/sdhc_spi.c @@ -206,7 +206,7 @@ static int sdhc_spi_response_get(const struct device *dev, struct sdhc_command * struct sdhc_spi_data *dev_data = dev->data; uint8_t *response = dev_data->scratch; uint8_t *end = response + rx_len; - int ret; + int ret, timeout = cmd->timeout_ms; uint8_t value, i; /* First step is finding the first valid byte of the response. @@ -224,7 +224,7 @@ static int sdhc_spi_response_get(const struct device *dev, struct sdhc_command * */ response = dev_data->scratch; end = response + 1; - for (i = 0; i < 16; i++) { + while (timeout > 0) { ret = sdhc_spi_rx(config->spi_dev, dev_data->spi_cfg, response, 1); if (ret < 0) { @@ -233,6 +233,9 @@ static int sdhc_spi_response_get(const struct device *dev, struct sdhc_command * if (*response != 0xff) { break; } + /* Delay for a bit, and poll the card again */ + k_msleep(10); + timeout -= 10; } if (*response == 0xff) { return -ETIMEDOUT; From 2ee2b6ac086a0c839a6d071e8c7eadc9304d8d56 Mon Sep 17 00:00:00 2001 From: Ryan McClelland Date: Sat, 28 Oct 2023 11:54:02 -0700 Subject: [PATCH 2621/3723] drivers: spi: dw: remove HAS_SPI_DW Kconfig The HAS_SPI_DW Kconfig is rather unncessary. If the synopsys designware spi is to be included. It should come from the devicetree. Signed-off-by: Ryan McClelland --- drivers/spi/Kconfig.dw | 7 +------ soc/arc/snps_emsdp/Kconfig.soc | 1 - soc/arc/snps_emsk/Kconfig.soc | 1 - soc/arm/intel_socfpga_std/cyclonev/Kconfig.series | 1 - 4 files changed, 1 insertion(+), 9 deletions(-) diff --git a/drivers/spi/Kconfig.dw b/drivers/spi/Kconfig.dw index 1902d36bc4d..3ebdd54ee93 100644 --- a/drivers/spi/Kconfig.dw +++ b/drivers/spi/Kconfig.dw @@ -1,18 +1,13 @@ # DesignWare SPI driver configuration options # Copyright (c) 2015-2016 Intel Corporation +# Copyright (c) 2023 Meta Platforms # SPDX-License-Identifier: Apache-2.0 -config HAS_SPI_DW - bool - help - Signifies whether DesignWare SPI compatible HW is available - menuconfig SPI_DW bool "Designware SPI controller driver" default y depends on DT_HAS_SNPS_DESIGNWARE_SPI_ENABLED - depends on HAS_SPI_DW help Enable support for Designware's SPI controllers. diff --git a/soc/arc/snps_emsdp/Kconfig.soc b/soc/arc/snps_emsdp/Kconfig.soc index a1358b8ad9d..ed0a2f88e20 100644 --- a/soc/arc/snps_emsdp/Kconfig.soc +++ b/soc/arc/snps_emsdp/Kconfig.soc @@ -4,4 +4,3 @@ config SOC_ARC_EMSDP bool "Synopsys ARC EM Software Development Platform" select ARC - select HAS_SPI_DW if SPI diff --git a/soc/arc/snps_emsk/Kconfig.soc b/soc/arc/snps_emsk/Kconfig.soc index 9b6e50abe60..d172c4144a7 100644 --- a/soc/arc/snps_emsk/Kconfig.soc +++ b/soc/arc/snps_emsk/Kconfig.soc @@ -5,4 +5,3 @@ config SOC_EMSK bool "Synopsys ARC EM Starter Kit SoC" select ARC - select HAS_SPI_DW if SPI diff --git a/soc/arm/intel_socfpga_std/cyclonev/Kconfig.series b/soc/arm/intel_socfpga_std/cyclonev/Kconfig.series index cb0dc6984e3..e9fba7bdba2 100644 --- a/soc/arm/intel_socfpga_std/cyclonev/Kconfig.series +++ b/soc/arm/intel_socfpga_std/cyclonev/Kconfig.series @@ -9,7 +9,6 @@ config SOC_SERIES_CYCLONE5 select CPU_CORTEX_A9 select SOC_FAMILY_INTEL_SOCFPGA_STD select ARM_ARCH_TIMER_ERRATUM_740657 if ARM_ARCH_TIMER - select HAS_SPI_DW if SPI select ARCH_HAS_RESERVED_PAGE_FRAMES help Support for Intel SoC FPGA Series From 330dba0861bd918f58715fffca04a6337167bcb9 Mon Sep 17 00:00:00 2001 From: Ryan McClelland Date: Sat, 28 Oct 2023 11:55:08 -0700 Subject: [PATCH 2622/3723] drivers: spi: dw: fix naming convention of aux-reg aux-reg should be defined with a hyphen in the bindings Signed-off-by: Ryan McClelland --- dts/arc/synopsys/emsdp.dtsi | 4 ++-- dts/bindings/spi/snps,designware-spi.yaml | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/dts/arc/synopsys/emsdp.dtsi b/dts/arc/synopsys/emsdp.dtsi index 375eb745594..2db3d3422f4 100644 --- a/dts/arc/synopsys/emsdp.dtsi +++ b/dts/arc/synopsys/emsdp.dtsi @@ -135,7 +135,7 @@ interrupts = <63 2>, <64 2>, <65 2>; interrupt-names = "err_int", "rx_avail", "tx_req"; interrupt-parent = <&intc>; - aux_reg; + aux-reg; fifo-depth = <16>; }; @@ -149,7 +149,7 @@ interrupts = <67 2>, <68 2>, <69 2>; interrupt-names = "err_int", "rx_avail", "tx_req"; interrupt-parent = <&intc>; - aux_reg; + aux-reg; fifo-depth = <16>; }; }; diff --git a/dts/bindings/spi/snps,designware-spi.yaml b/dts/bindings/spi/snps,designware-spi.yaml index 7e6673cd3c0..3567c2a56ad 100644 --- a/dts/bindings/spi/snps,designware-spi.yaml +++ b/dts/bindings/spi/snps,designware-spi.yaml @@ -14,11 +14,11 @@ properties: interrupts: required: true - aux_reg: + aux-reg: + type: boolean description: | This value is used for auxiliary register access. For other platform, this value should be default 0. - type: boolean fifo-depth: type: int From 909da582c52e906e02634e5b2dc9c749c5302e12 Mon Sep 17 00:00:00 2001 From: Ryan McClelland Date: Mon, 30 Oct 2023 10:40:09 -0700 Subject: [PATCH 2623/3723] drivers: spi: dw: cleanup instantiation macro This cleans up the instantiation macro. DBG_COUNTER was also removed as that appears to be unnecessary. This also allows for if it is a serial target to be configured from the devicetree. Signed-off-by: Ryan McClelland --- drivers/spi/spi_dw.c | 428 ++++------------------ drivers/spi/spi_dw.h | 3 +- dts/bindings/spi/snps,designware-spi.yaml | 8 + 3 files changed, 76 insertions(+), 363 deletions(-) diff --git a/drivers/spi/spi_dw.c b/drivers/spi/spi_dw.c index e5700863932..ed294896fea 100644 --- a/drivers/spi/spi_dw.c +++ b/drivers/spi/spi_dw.c @@ -1,6 +1,7 @@ /* * Copyright (c) 2015 Intel Corporation. * Copyright (c) 2023 Synopsys, Inc. All rights reserved. + * Copyright (c) 2023 Meta Platforms * * SPDX-License-Identifier: Apache-2.0 */ @@ -13,19 +14,6 @@ #include LOG_MODULE_REGISTER(spi_dw); -#if (CONFIG_SPI_LOG_LEVEL == 4) -#define DBG_COUNTER_INIT() \ - uint32_t __cnt = 0 -#define DBG_COUNTER_INC() \ - (__cnt++) -#define DBG_COUNTER_RESULT() \ - (__cnt) -#else -#define DBG_COUNTER_INIT() {; } -#define DBG_COUNTER_INC() {; } -#define DBG_COUNTER_RESULT() 0 -#endif - #include #include @@ -97,8 +85,6 @@ static void push_data(const struct device *dev) uint32_t data = 0U; uint32_t f_tx; - DBG_COUNTER_INIT(); - if (spi_context_rx_on(&spi->ctx)) { f_tx = info->fifo_depth - read_txflr(info) - read_rxflr(info); @@ -147,16 +133,12 @@ static void push_data(const struct device *dev) spi->fifo_diff++; f_tx--; - - DBG_COUNTER_INC(); } if (!spi_context_tx_on(&spi->ctx)) { /* prevents any further interrupts demanding TX fifo fill */ write_txftlr(info, 0); } - - LOG_DBG("Pushed: %d", DBG_COUNTER_RESULT()); } static void pull_data(const struct device *dev) @@ -164,13 +146,9 @@ static void pull_data(const struct device *dev) const struct spi_dw_config *info = dev->config; struct spi_dw_data *spi = dev->data; - DBG_COUNTER_INIT(); - while (read_rxflr(info)) { uint32_t data = read_dr(info); - DBG_COUNTER_INC(); - if (spi_context_rx_buf_on(&spi->ctx)) { switch (spi->dfs) { case 1: @@ -196,8 +174,6 @@ static void pull_data(const struct device *dev) } else if (read_rxftlr(info) >= spi->ctx.rx_len) { write_rxftlr(info, spi->ctx.rx_len - 1); } - - LOG_DBG("Pulled: %d", DBG_COUNTER_RESULT()); } static int spi_dw_configure(const struct spi_dw_config *info, @@ -220,12 +196,12 @@ static int spi_dw_configure(const struct spi_dw_config *info, /* Verify if requested op mode is relevant to this controller */ if (config->operation & SPI_OP_MODE_SLAVE) { - if (!(info->op_modes & SPI_CTX_RUNTIME_OP_MODE_SLAVE)) { + if (!(info->serial_target)) { LOG_ERR("Slave mode not supported"); return -ENOTSUP; } } else { - if (!(info->op_modes & SPI_CTX_RUNTIME_OP_MODE_MASTER)) { + if (info->serial_target) { LOG_ERR("Master mode not supported"); return -ENOTSUP; } @@ -558,339 +534,69 @@ int spi_dw_init(const struct device *dev) return 0; } - -#if DT_NODE_HAS_STATUS(DT_DRV_INST(0), okay) -void spi_config_0_irq(void); - -struct spi_dw_data spi_dw_data_port_0 = { - SPI_CONTEXT_INIT_LOCK(spi_dw_data_port_0, ctx), - SPI_CONTEXT_INIT_SYNC(spi_dw_data_port_0, ctx), - SPI_CONTEXT_CS_GPIOS_INITIALIZE(DT_DRV_INST(0), ctx) -}; - -#if DT_NODE_HAS_PROP(DT_INST_PHANDLE(0, clocks), clock_frequency) -#define INST_0_SNPS_DESIGNWARE_SPI_CLOCK_FREQ \ - DT_INST_PROP_BY_PHANDLE(0, clocks, clock_frequency) -#else -#define INST_0_SNPS_DESIGNWARE_SPI_CLOCK_FREQ \ - DT_INST_PROP(0, clock_frequency) -#endif - -#ifdef CONFIG_PINCTRL -PINCTRL_DT_INST_DEFINE(0); -#endif -const struct spi_dw_config spi_dw_config_0 = { - .regs = DT_INST_REG_ADDR(0), - .clock_frequency = INST_0_SNPS_DESIGNWARE_SPI_CLOCK_FREQ, - .config_func = spi_config_0_irq, - .op_modes = SPI_CTX_RUNTIME_OP_MODE_MASTER, - .fifo_depth = DT_INST_PROP(0, fifo_depth), -#ifdef CONFIG_PINCTRL - .pcfg = PINCTRL_DT_INST_DEV_CONFIG_GET(0), -#endif -#if DT_INST_PROP(0, aux_reg) - .read_func = aux_reg_read, - .write_func = aux_reg_write, - .set_bit_func = aux_reg_set_bit, - .clear_bit_func = aux_reg_clear_bit, - .test_bit_func = aux_reg_test_bit -#else - .read_func = reg_read, - .write_func = reg_write, - .set_bit_func = reg_set_bit, - .clear_bit_func = reg_clear_bit, - .test_bit_func = reg_test_bit -#endif -}; - -DEVICE_DT_INST_DEFINE(0, spi_dw_init, NULL, - &spi_dw_data_port_0, &spi_dw_config_0, - POST_KERNEL, CONFIG_SPI_INIT_PRIORITY, - &dw_spi_api); - -void spi_config_0_irq(void) -{ -#if DT_NUM_IRQS(DT_DRV_INST(0)) == 1 -#if DT_INST_IRQ_HAS_NAME(0, flags) -#define INST_0_IRQ_FLAGS DT_INST_IRQ_BY_NAME(0, flags, irq) -#else -#define INST_0_IRQ_FLAGS 0 -#endif - IRQ_CONNECT(DT_INST_IRQN(0), - DT_INST_IRQ(0, priority), - spi_dw_isr, DEVICE_DT_INST_GET(0), - INST_0_IRQ_FLAGS); - irq_enable(DT_INST_IRQN(0)); -#else - IRQ_CONNECT(DT_INST_IRQ_BY_NAME(0, rx_avail, irq), - DT_INST_IRQ_BY_NAME(0, rx_avail, priority), - spi_dw_isr, DEVICE_DT_INST_GET(0), - 0); - IRQ_CONNECT(DT_INST_IRQ_BY_NAME(0, tx_req, irq), - DT_INST_IRQ_BY_NAME(0, tx_req, priority), - spi_dw_isr, DEVICE_DT_INST_GET(0), - 0); - IRQ_CONNECT(DT_INST_IRQ_BY_NAME(0, err_int, irq), - DT_INST_IRQ_BY_NAME(0, err_int, priority), - spi_dw_isr, DEVICE_DT_INST_GET(0), - 0); - - irq_enable(DT_INST_IRQ_BY_NAME(0, rx_avail, irq)); - irq_enable(DT_INST_IRQ_BY_NAME(0, tx_req, irq)); - irq_enable(DT_INST_IRQ_BY_NAME(0, err_int, irq)); - -#endif -} -#endif /* DT_NODE_HAS_STATUS(DT_DRV_INST(0), okay) */ - -#if DT_NODE_HAS_STATUS(DT_DRV_INST(1), okay) -void spi_config_1_irq(void); - -struct spi_dw_data spi_dw_data_port_1 = { - SPI_CONTEXT_INIT_LOCK(spi_dw_data_port_1, ctx), - SPI_CONTEXT_INIT_SYNC(spi_dw_data_port_1, ctx), - SPI_CONTEXT_CS_GPIOS_INITIALIZE(DT_DRV_INST(1), ctx) -}; - -#if DT_NODE_HAS_PROP(DT_INST_PHANDLE(1, clocks), clock_frequency) -#define INST_1_SNPS_DESIGNWARE_SPI_CLOCK_FREQ \ - DT_INST_PROP_BY_PHANDLE(1, clocks, clock_frequency) -#else -#define INST_1_SNPS_DESIGNWARE_SPI_CLOCK_FREQ \ - DT_INST_PROP(1, clock_frequency) -#endif - -#ifdef CONFIG_PINCTRL -PINCTRL_DT_INST_DEFINE(1); -#endif -static const struct spi_dw_config spi_dw_config_1 = { - .regs = DT_INST_REG_ADDR(1), - .clock_frequency = INST_1_SNPS_DESIGNWARE_SPI_CLOCK_FREQ, - .config_func = spi_config_1_irq, - .op_modes = SPI_CTX_RUNTIME_OP_MODE_MASTER, - .fifo_depth = DT_INST_PROP(1, fifo_depth), -#ifdef CONFIG_PINCTRL - .pcfg = PINCTRL_DT_INST_DEV_CONFIG_GET(1), -#endif -#if DT_INST_PROP(1, aux_reg) - .read_func = aux_reg_read, - .write_func = aux_reg_write, - .set_bit_func = aux_reg_set_bit, - .clear_bit_func = aux_reg_clear_bit, - .test_bit_func = aux_reg_test_bit -#else - .read_func = reg_read, - .write_func = reg_write, - .set_bit_func = reg_set_bit, - .clear_bit_func = reg_clear_bit, - .test_bit_func = reg_test_bit -#endif -}; - -DEVICE_DT_INST_DEFINE(1, spi_dw_init, NULL, - &spi_dw_data_port_1, &spi_dw_config_1, - POST_KERNEL, CONFIG_SPI_INIT_PRIORITY, - &dw_spi_api); - -void spi_config_1_irq(void) -{ -#if DT_NUM_IRQS(DT_DRV_INST(1)) == 1 -#if DT_INST_IRQ_HAS_NAME(1, flags) -#define INST_1_IRQ_FLAGS DT_INST_IRQ_BY_NAME(1, flags, irq) -#else -#define INST_1_IRQ_FLAGS 0 -#endif - IRQ_CONNECT(DT_INST_IRQN(1), - DT_INST_IRQ(1, priority), - spi_dw_isr, DEVICE_DT_INST_GET(1), - INST_1_IRQ_FLAGS); - irq_enable(DT_INST_IRQN(1)); -#else - IRQ_CONNECT(DT_INST_IRQ_BY_NAME(1, rx_avail, irq), - DT_INST_IRQ_BY_NAME(1, rx_avail, priority), - spi_dw_isr, DEVICE_DT_INST_GET(1), - 0); - IRQ_CONNECT(DT_INST_IRQ_BY_NAME(1, tx_req, irq), - DT_INST_IRQ_BY_NAME(1, tx_req, priority), - spi_dw_isr, DEVICE_DT_INST_GET(1), - 0); - IRQ_CONNECT(DT_INST_IRQ_BY_NAME(1, err_int, irq), - DT_INST_IRQ_BY_NAME(1, err_int, priority), - spi_dw_isr, DEVICE_DT_INST_GET(1), - 0); - - irq_enable(DT_INST_IRQ_BY_NAME(1, rx_avail, irq)); - irq_enable(DT_INST_IRQ_BY_NAME(1, tx_req, irq)); - irq_enable(DT_INST_IRQ_BY_NAME(1, err_int, irq)); - -#endif -} -#endif /* DT_NODE_HAS_STATUS(DT_DRV_INST(1), okay) */ - -#if DT_NODE_HAS_STATUS(DT_DRV_INST(2), okay) -void spi_config_2_irq(void); - -struct spi_dw_data spi_dw_data_port_2 = { - SPI_CONTEXT_INIT_LOCK(spi_dw_data_port_2, ctx), - SPI_CONTEXT_INIT_SYNC(spi_dw_data_port_2, ctx), - SPI_CONTEXT_CS_GPIOS_INITIALIZE(DT_DRV_INST(2), ctx) -}; - -#if DT_NODE_HAS_PROP(DT_INST_PHANDLE(2, clocks), clock_frequency) -#define INST_2_SNPS_DESIGNWARE_SPI_CLOCK_FREQ \ - DT_INST_PROP_BY_PHANDLE(2, clocks, clock_frequency) -#else -#define INST_2_SNPS_DESIGNWARE_SPI_CLOCK_FREQ \ - DT_INST_PROP(2, clock_frequency) -#endif - -#ifdef CONFIG_PINCTRL -PINCTRL_DT_INST_DEFINE(2); -#endif -static const struct spi_dw_config spi_dw_config_2 = { - .regs = DT_INST_REG_ADDR(2), - .clock_frequency = INST_2_SNPS_DESIGNWARE_SPI_CLOCK_FREQ, - .config_func = spi_config_2_irq, - .op_modes = SPI_CTX_RUNTIME_OP_MODE_MASTER, - .fifo_depth = DT_INST_PROP(2, fifo_depth), -#ifdef CONFIG_PINCTRL - .pcfg = PINCTRL_DT_INST_DEV_CONFIG_GET(2), -#endif -#if DT_INST_PROP(2, aux_reg) - .read_func = aux_reg_read, - .write_func = aux_reg_write, - .set_bit_func = aux_reg_set_bit, - .clear_bit_func = aux_reg_clear_bit, - .test_bit_func = aux_reg_test_bit -#else - .read_func = reg_read, - .write_func = reg_write, - .set_bit_func = reg_set_bit, - .clear_bit_func = reg_clear_bit, - .test_bit_func = reg_test_bit -#endif -}; - -DEVICE_DT_INST_DEFINE(2, spi_dw_init, NULL, - &spi_dw_data_port_2, &spi_dw_config_2, - POST_KERNEL, CONFIG_SPI_INIT_PRIORITY, - &dw_spi_api); - -void spi_config_2_irq(void) -{ -#if DT_NUM_IRQS(DT_DRV_INST(2)) == 1 -#if DT_INST_IRQ_HAS_NAME(2, flags) -#define INST_2_IRQ_FLAGS DT_INST_IRQ_BY_NAME(2, flags, irq) -#else -#define INST_2_IRQ_FLAGS 0 -#endif - IRQ_CONNECT(DT_INST_IRQN(2), - DT_INST_IRQ(2, priority), - spi_dw_isr, DEVICE_DT_INST_GET(2), - INST_2_IRQ_FLAGS); - irq_enable(DT_INST_IRQN(2)); -#else - IRQ_CONNECT(DT_INST_IRQ_BY_NAME(2, rx_avail, irq), - DT_INST_IRQ_BY_NAME(2, rx_avail, priority), - spi_dw_isr, DEVICE_DT_INST_GET(2), - 0); - IRQ_CONNECT(DT_INST_IRQ_BY_NAME(2, tx_req, irq), - DT_INST_IRQ_BY_NAME(2, tx_req, priority), - spi_dw_isr, DEVICE_DT_INST_GET(2), - 0); - IRQ_CONNECT(DT_INST_IRQ_BY_NAME(2, err_int, irq), - DT_INST_IRQ_BY_NAME(2, err_int, priority), - spi_dw_isr, DEVICE_DT_INST_GET(2), - 0); - - irq_enable(DT_INST_IRQ_BY_NAME(2, rx_avail, irq)); - irq_enable(DT_INST_IRQ_BY_NAME(2, tx_req, irq)); - irq_enable(DT_INST_IRQ_BY_NAME(2, err_int, irq)); - -#endif +#define SPI_DW_IRQ_HANDLER(inst) \ +void spi_dw_irq_config_##inst(void) \ +{ \ +COND_CODE_1(IS_EQ(DT_NUM_IRQS(DT_DRV_INST(inst)), 1), \ + (IRQ_CONNECT(DT_INST_IRQN(inst), \ + DT_INST_IRQ(inst, priority), \ + spi_dw_isr, DEVICE_DT_INST_GET(inst), \ + 0); \ + irq_enable(DT_INST_IRQN(inst));), \ + (IRQ_CONNECT(DT_INST_IRQ_BY_NAME(inst, rx_avail, irq), \ + DT_INST_IRQ_BY_NAME(inst, rx_avail, priority), \ + spi_dw_isr, DEVICE_DT_INST_GET(inst), \ + 0); \ + IRQ_CONNECT(DT_INST_IRQ_BY_NAME(inst, tx_req, irq), \ + DT_INST_IRQ_BY_NAME(inst, tx_req, priority), \ + spi_dw_isr, DEVICE_DT_INST_GET(inst), \ + 0); \ + IRQ_CONNECT(DT_INST_IRQ_BY_NAME(inst, err_int, irq), \ + DT_INST_IRQ_BY_NAME(inst, err_int, priority), \ + spi_dw_isr, DEVICE_DT_INST_GET(inst), \ + 0); \ + irq_enable(DT_INST_IRQ_BY_NAME(inst, rx_avail, irq)); \ + irq_enable(DT_INST_IRQ_BY_NAME(inst, tx_req, irq)); \ + irq_enable(DT_INST_IRQ_BY_NAME(inst, err_int, irq));)) \ } -#endif /* DT_NODE_HAS_STATUS(DT_DRV_INST(2), okay) */ - -#if DT_NODE_HAS_STATUS(DT_DRV_INST(3), okay) -void spi_config_3_irq(void); - -struct spi_dw_data spi_dw_data_port_3 = { - SPI_CONTEXT_INIT_LOCK(spi_dw_data_port_3, ctx), - SPI_CONTEXT_INIT_SYNC(spi_dw_data_port_3, ctx), - SPI_CONTEXT_CS_GPIOS_INITIALIZE(DT_DRV_INST(3), ctx) -}; - -#if DT_NODE_HAS_PROP(DT_INST_PHANDLE(3, clocks), clock_frequency) -#define INST_3_SNPS_DESIGNWARE_SPI_CLOCK_FREQ \ - DT_INST_PROP_BY_PHANDLE(3, clocks, clock_frequency) -#else -#define INST_3_SNPS_DESIGNWARE_SPI_CLOCK_FREQ \ - DT_INST_PROP(3, clock_frequency) -#endif - -#ifdef CONFIG_PINCTRL -PINCTRL_DT_INST_DEFINE(3); -#endif -static const struct spi_dw_config spi_dw_config_3 = { - .regs = DT_INST_REG_ADDR(3), - .clock_frequency = INST_3_SNPS_DESIGNWARE_SPI_CLOCK_FREQ, - .config_func = spi_config_3_irq, - .op_modes = SPI_CTX_RUNTIME_OP_MODE_MASTER, - .fifo_depth = DT_INST_PROP(3, fifo_depth), -#ifdef CONFIG_PINCTRL - .pcfg = PINCTRL_DT_INST_DEV_CONFIG_GET(3), -#endif -#if DT_INST_PROP(3, aux_reg) - .read_func = aux_reg_read, - .write_func = aux_reg_write, - .set_bit_func = aux_reg_set_bit, - .clear_bit_func = aux_reg_clear_bit, - .test_bit_func = aux_reg_test_bit -#else - .read_func = reg_read, - .write_func = reg_write, - .set_bit_func = reg_set_bit, - .clear_bit_func = reg_clear_bit, - .test_bit_func = reg_test_bit -#endif -}; - -DEVICE_DT_INST_DEFINE(3, spi_dw_init, NULL, - &spi_dw_data_port_3, &spi_dw_config_3, - POST_KERNEL, CONFIG_SPI_INIT_PRIORITY, - &dw_spi_api); -void spi_config_3_irq(void) -{ -#if DT_NUM_IRQS(DT_DRV_INST(3)) == 1 -#if DT_INST_IRQ_HAS_NAME(3, flags) -#define INST_3_IRQ_FLAGS DT_INST_IRQ_BY_NAME(3, flags, irq) -#else -#define INST_3_IRQ_FLAGS 0 -#endif - IRQ_CONNECT(DT_INST_IRQN(3), - DT_INST_IRQ(3, priority), - spi_dw_isr, DEVICE_DT_INST_GET(3), - INST_3_IRQ_FLAGS); - irq_enable(DT_INST_IRQN(3)); -#else - IRQ_CONNECT(DT_INST_IRQ_BY_NAME(3, rx_avail, irq), - DT_INST_IRQ_BY_NAME(3, rx_avail, priority), - spi_dw_isr, DEVICE_DT_INST_GET(3), - 0); - IRQ_CONNECT(DT_INST_IRQ_BY_NAME(3, tx_req, irq), - DT_INST_IRQ_BY_NAME(3, tx_req, priority), - spi_dw_isr, DEVICE_DT_INST_GET(3), - 0); - IRQ_CONNECT(DT_INST_IRQ_BY_NAME(3, err_int, irq), - DT_INST_IRQ_BY_NAME(3, err_int, priority), - spi_dw_isr, DEVICE_DT_INST_GET(3), - 0); - - irq_enable(DT_INST_IRQ_BY_NAME(3, rx_avail, irq)); - irq_enable(DT_INST_IRQ_BY_NAME(3, tx_req, irq)); - irq_enable(DT_INST_IRQ_BY_NAME(3, err_int, irq)); - -#endif -} -#endif /* DT_NODE_HAS_STATUS(DT_DRV_INST(3), okay) */ +#define SPI_DW_INIT(inst) \ + IF_ENABLED(CONFIG_PINCTRL, (PINCTRL_DT_INST_DEFINE(inst);)) \ + SPI_DW_IRQ_HANDLER(inst); \ + static struct spi_dw_data spi_dw_data_##inst = { \ + SPI_CONTEXT_INIT_LOCK(spi_dw_data_##inst, ctx), \ + SPI_CONTEXT_INIT_SYNC(spi_dw_data_##inst, ctx), \ + SPI_CONTEXT_CS_GPIOS_INITIALIZE(DT_DRV_INST(inst), ctx) \ + }; \ + static const struct spi_dw_config spi_dw_config_##inst = { \ + .regs = DT_INST_REG_ADDR(inst), \ + .clock_frequency = COND_CODE_1( \ + DT_NODE_HAS_PROP(DT_INST_PHANDLE(inst, clocks), clock_frequency), \ + (DT_INST_PROP_BY_PHANDLE(inst, clocks, clock_frequency)), \ + (DT_INST_PROP(inst, clock_frequency))), \ + .config_func = spi_dw_irq_config_##inst, \ + .serial_target = DT_INST_PROP(inst, serial_target), \ + .fifo_depth = DT_INST_PROP(inst, fifo_depth), \ + IF_ENABLED(CONFIG_PINCTRL, (.pcfg = PINCTRL_DT_INST_DEV_CONFIG_GET(inst),)) \ + COND_CODE_1(DT_INST_PROP(inst, aux_reg), \ + (.read_func = aux_reg_read, \ + .write_func = aux_reg_write, \ + .set_bit_func = aux_reg_set_bit, \ + .clear_bit_func = aux_reg_clear_bit, \ + .test_bit_func = aux_reg_test_bit,), \ + (.read_func = reg_read, \ + .write_func = reg_write, \ + .set_bit_func = reg_set_bit, \ + .clear_bit_func = reg_clear_bit, \ + .test_bit_func = reg_test_bit,)) \ + }; \ + DEVICE_DT_INST_DEFINE(inst, \ + spi_dw_init, \ + NULL, \ + &spi_dw_data_##inst, \ + &spi_dw_config_##inst, \ + POST_KERNEL, \ + CONFIG_SPI_INIT_PRIORITY, \ + &dw_spi_api); + +DT_INST_FOREACH_STATUS_OKAY(SPI_DW_INIT) diff --git a/drivers/spi/spi_dw.h b/drivers/spi/spi_dw.h index dd518c9b853..54724dea0e7 100644 --- a/drivers/spi/spi_dw.h +++ b/drivers/spi/spi_dw.h @@ -31,7 +31,7 @@ struct spi_dw_config { uint32_t regs; uint32_t clock_frequency; spi_dw_config_t config_func; - uint8_t op_modes; + bool serial_target; uint8_t fifo_depth; #ifdef CONFIG_PINCTRL const struct pinctrl_dev_config *pcfg; @@ -47,7 +47,6 @@ struct spi_dw_data { struct spi_context ctx; uint8_t dfs; /* dfs in bytes: 1,2 or 4 */ uint8_t fifo_diff; /* cannot be bigger than FIFO depth */ - uint16_t _unused; }; /* Register operation functions */ diff --git a/dts/bindings/spi/snps,designware-spi.yaml b/dts/bindings/spi/snps,designware-spi.yaml index 3567c2a56ad..822cb8d508b 100644 --- a/dts/bindings/spi/snps,designware-spi.yaml +++ b/dts/bindings/spi/snps,designware-spi.yaml @@ -1,4 +1,5 @@ # Copyright (c) 2018 Synopsys, Inc. All rights reserved. +# Copyright (c) 2023 Meta Platforms All rights reserved. # SPDX-License-Identifier: Apache-2.0 description: Synopsys DesignWare SPI node @@ -26,3 +27,10 @@ properties: RX/TX FIFO depth. Corresponds to the SSI_TX_FIFO_DEPTH and SSI_RX_FIFO_DEPTH of the DesignWare Synchronous Serial Interface. Depth ranges from 2-256. + + serial-target: + type: boolean + description: | + True if it is a Serial Target. False if it is a Serial + Master. Corresponds to SSI_IS_MASTER of the Designware + Synchronous Serial Interface. From ff99687862552971ad34a987fd3d90ee108f3775 Mon Sep 17 00:00:00 2001 From: Ryan McClelland Date: Mon, 30 Oct 2023 10:40:29 -0700 Subject: [PATCH 2624/3723] drivers: spi: dw: fix hw cs and slave return rx len Only toggle the hw cs if the cs is not set as a gpio. SPI trancieve should also return the rx len when in slave configuration. Signed-off-by: Ryan McClelland --- drivers/spi/spi_dw.c | 26 +++++++++++++++++++++++--- 1 file changed, 23 insertions(+), 3 deletions(-) diff --git a/drivers/spi/spi_dw.c b/drivers/spi/spi_dw.c index ed294896fea..98904fbc267 100644 --- a/drivers/spi/spi_dw.c +++ b/drivers/spi/spi_dw.c @@ -50,6 +50,7 @@ static void completed(const struct device *dev, int error) { const struct spi_dw_config *info = dev->config; struct spi_dw_data *spi = dev->data; + struct spi_context *ctx = &spi->ctx; if (error) { goto out; @@ -70,7 +71,13 @@ static void completed(const struct device *dev, int error) /* Disabling the controller */ clear_bit_ssienr(info); - spi_context_cs_control(&spi->ctx, false); + if (!spi_dw_is_slave(spi)) { + if (spi_cs_is_gpio(ctx->config)) { + spi_context_cs_control(ctx, false); + } else { + write_ser(info, 0); + } + } LOG_DBG("SPI transaction completed %s error", error ? "with" : "without"); @@ -244,7 +251,6 @@ static int spi_dw_configure(const struct spi_dw_config *info, /* Baud rate and Slave select, for master only */ write_baudr(info, SPI_DW_CLK_DIVIDER(info->clock_frequency, config->frequency)); - write_ser(info, 1 << config->slave); } if (spi_dw_is_slave(spi)) { @@ -415,12 +421,26 @@ static int transceive(const struct device *dev, DW_SPI_IMR_UNMASK; write_imr(info, reg_data); - spi_context_cs_control(&spi->ctx, true); + if (!spi_dw_is_slave(spi)) { + /* if cs is not defined as gpio, use hw cs */ + if (spi_cs_is_gpio(config)) { + spi_context_cs_control(&spi->ctx, true); + } else { + write_ser(info, BIT(config->slave)); + } + } LOG_DBG("Enabling controller"); set_bit_ssienr(info); ret = spi_context_wait_for_completion(&spi->ctx); + +#ifdef CONFIG_SPI_SLAVE + if (spi_context_is_slave(&spi->ctx) && !ret) { + ret = spi->ctx.recv_frames; + } +#endif /* CONFIG_SPI_SLAVE */ + out: spi_context_release(&spi->ctx, ret); From 83c298cd32f779d371fd207816e588be5ba4e949 Mon Sep 17 00:00:00 2001 From: Ryan McClelland Date: Thu, 9 Nov 2023 15:27:21 -0800 Subject: [PATCH 2625/3723] drivers: spi: dw: define max-xfer-size The max size was determined by looking at the ARCH of the cpu. This really comes from the ip configuration when generated. Add `max-xfer-size` property to the devicetree. Signed-off-by: Ryan McClelland --- drivers/spi/spi_dw.c | 17 ++++++++++++----- drivers/spi/spi_dw.h | 7 +------ dts/arc/synopsys/arc_hs4xd.dtsi | 3 +++ dts/arc/synopsys/arc_hsdk.dtsi | 3 +++ dts/arc/synopsys/arc_iot.dtsi | 3 +++ dts/arc/synopsys/emsdp.dtsi | 4 ++++ dts/arc/synopsys/emsk.dtsi | 2 ++ dts/arm/intel_socfpga_std/socfpga.dtsi | 2 ++ dts/bindings/spi/snps,designware-spi.yaml | 10 ++++++++++ 9 files changed, 40 insertions(+), 11 deletions(-) diff --git a/drivers/spi/spi_dw.c b/drivers/spi/spi_dw.c index 98904fbc267..7126cac00a8 100644 --- a/drivers/spi/spi_dw.c +++ b/drivers/spi/spi_dw.c @@ -113,12 +113,10 @@ static void push_data(const struct device *dev) data = UNALIGNED_GET((uint16_t *) (spi->ctx.tx_buf)); break; -#ifndef CONFIG_ARC case 4: data = UNALIGNED_GET((uint32_t *) (spi->ctx.tx_buf)); break; -#endif } } else if (spi_context_rx_on(&spi->ctx)) { /* No need to push more than necessary */ @@ -164,11 +162,9 @@ static void pull_data(const struct device *dev) case 2: UNALIGNED_PUT(data, (uint16_t *)spi->ctx.rx_buf); break; -#ifndef CONFIG_ARC case 4: UNALIGNED_PUT(data, (uint32_t *)spi->ctx.rx_buf); break; -#endif } } @@ -222,8 +218,18 @@ static int spi_dw_configure(const struct spi_dw_config *info, return -EINVAL; } + if (info->max_xfer_size < SPI_WORD_SIZE_GET(config->operation)) { + LOG_ERR("Max xfer size is %u, word size of %u not allowed", + info->max_xfer_size, SPI_WORD_SIZE_GET(config->operation)); + return -ENOTSUP; + } + /* Word size */ - ctrlr0 |= DW_SPI_CTRLR0_DFS(SPI_WORD_SIZE_GET(config->operation)); + if (info->max_xfer_size == 32) { + ctrlr0 |= DW_SPI_CTRLR0_DFS_32(SPI_WORD_SIZE_GET(config->operation)); + } else { + ctrlr0 |= DW_SPI_CTRLR0_DFS_16(SPI_WORD_SIZE_GET(config->operation)); + } /* Determine how many bytes are required per-frame */ spi->dfs = SPI_WS_TO_DFS(SPI_WORD_SIZE_GET(config->operation)); @@ -597,6 +603,7 @@ COND_CODE_1(IS_EQ(DT_NUM_IRQS(DT_DRV_INST(inst)), 1), \ .config_func = spi_dw_irq_config_##inst, \ .serial_target = DT_INST_PROP(inst, serial_target), \ .fifo_depth = DT_INST_PROP(inst, fifo_depth), \ + .max_xfer_size = DT_INST_PROP(inst, max_xfer_size), \ IF_ENABLED(CONFIG_PINCTRL, (.pcfg = PINCTRL_DT_INST_DEV_CONFIG_GET(inst),)) \ COND_CODE_1(DT_INST_PROP(inst, aux_reg), \ (.read_func = aux_reg_read, \ diff --git a/drivers/spi/spi_dw.h b/drivers/spi/spi_dw.h index 54724dea0e7..54eeaa1ece1 100644 --- a/drivers/spi/spi_dw.h +++ b/drivers/spi/spi_dw.h @@ -33,6 +33,7 @@ struct spi_dw_config { spi_dw_config_t config_func; bool serial_target; uint8_t fifo_depth; + uint8_t max_xfer_size; #ifdef CONFIG_PINCTRL const struct pinctrl_dev_config *pcfg; #endif @@ -193,12 +194,6 @@ static int reg_test_bit(uint8_t bit, uint32_t addr, uint32_t off) #define DW_SPI_CTRLR0_DFS_16(__bpw) ((__bpw) - 1) #define DW_SPI_CTRLR0_DFS_32(__bpw) (((__bpw) - 1) << 16) -#if defined(CONFIG_ARC) -#define DW_SPI_CTRLR0_DFS DW_SPI_CTRLR0_DFS_16 -#else -#define DW_SPI_CTRLR0_DFS DW_SPI_CTRLR0_DFS_32 -#endif - /* 0x38 represents the bits 8, 16 and 32. Knowing that 24 is bits 8 and 16 * These are the bits were when you divide by 8, you keep the result as it is. * For all the other ones, 4 to 7, 9 to 15, etc... you need a +1, diff --git a/dts/arc/synopsys/arc_hs4xd.dtsi b/dts/arc/synopsys/arc_hs4xd.dtsi index 18a555cfbd4..d6650e651a9 100644 --- a/dts/arc/synopsys/arc_hs4xd.dtsi +++ b/dts/arc/synopsys/arc_hs4xd.dtsi @@ -185,6 +185,7 @@ reg = <0xf0020000 0x100>; interrupts = <40 1>; fifo-depth = <32>; + max-xfer-size = <16>; status = "disabled"; }; @@ -195,6 +196,7 @@ reg = <0xf0021000 0x100>; interrupts = <41 1>; fifo-depth = <32>; + max-xfer-size = <16>; status = "disabled"; }; @@ -205,6 +207,7 @@ reg = <0xf0022000 0x100>; interrupts = <42 1>; fifo-depth = <32>; + max-xfer-size = <16>; status = "disabled"; }; }; diff --git a/dts/arc/synopsys/arc_hsdk.dtsi b/dts/arc/synopsys/arc_hsdk.dtsi index bb127594e2e..6388db825a0 100644 --- a/dts/arc/synopsys/arc_hsdk.dtsi +++ b/dts/arc/synopsys/arc_hsdk.dtsi @@ -185,6 +185,7 @@ reg = <0xf0020000 0x1000>; interrupts = <40 1>; fifo-depth = <32>; + max-xfer-size = <16>; status = "disabled"; }; @@ -195,6 +196,7 @@ reg = <0xf0021000 0x1000>; interrupts = <41 1>; fifo-depth = <32>; + max-xfer-size = <16>; status = "disabled"; }; @@ -205,6 +207,7 @@ reg = <0xf0022000 0x1000>; interrupts = <42 1>; fifo-depth = <32>; + max-xfer-size = <16>; status = "disabled"; }; diff --git a/dts/arc/synopsys/arc_iot.dtsi b/dts/arc/synopsys/arc_iot.dtsi index 7d04321e0ee..1c809d1b0f8 100644 --- a/dts/arc/synopsys/arc_iot.dtsi +++ b/dts/arc/synopsys/arc_iot.dtsi @@ -233,6 +233,7 @@ #address-cells = <1>; #size-cells = <0>; reg = <0x80010000 0x100>; + max-xfer-size = <16>; clocks = <&sysclk>; interrupts = <70 2>, <71 2>, <72 2>; interrupt-names = "err-int", "rx-avail", "tx-req"; @@ -245,6 +246,7 @@ #address-cells = <1>; #size-cells = <0>; reg = <0x80010100 0x100>; + max-xfer-size = <16>; clocks = <&sysclk>; interrupts = <74 2>, <75 2>, <76 2>; interrupt-names = "err-int", "rx-avail", "tx-req"; @@ -257,6 +259,7 @@ #address-cells = <1>; #size-cells = <0>; reg = <0x80010200 0x100>; + max-xfer-size = <16>; clocks = <&sysclk>; interrupts = <78 2>, <79 2>, <80 2>; interrupt-names = "err-int", "rx-avail", "tx-req"; diff --git a/dts/arc/synopsys/emsdp.dtsi b/dts/arc/synopsys/emsdp.dtsi index 2db3d3422f4..1d7c4cf238c 100644 --- a/dts/arc/synopsys/emsdp.dtsi +++ b/dts/arc/synopsys/emsdp.dtsi @@ -95,6 +95,7 @@ reg = <0xf0008000 0x1000>; clocks = <&spiclk>; fifo-depth = <32>; + max-xfer-size = <16>; interrupt-parent = <&intc>; #address-cells = <1>; #size-cells = <0>; @@ -112,6 +113,7 @@ reg = <0xf1000000 0x1000>; clocks = <&spiclk>; fifo-depth = <32>; + max-xfer-size = <16>; interrupt-parent = <&intc>; #address-cells = <1>; #size-cells = <0>; @@ -137,6 +139,7 @@ interrupt-parent = <&intc>; aux-reg; fifo-depth = <16>; + max-xfer-size = <16>; }; /* DFSS-SPI1 */ @@ -151,6 +154,7 @@ interrupt-parent = <&intc>; aux-reg; fifo-depth = <16>; + max-xfer-size = <16>; }; }; }; diff --git a/dts/arc/synopsys/emsk.dtsi b/dts/arc/synopsys/emsk.dtsi index a701d2412ee..117421c228f 100644 --- a/dts/arc/synopsys/emsk.dtsi +++ b/dts/arc/synopsys/emsk.dtsi @@ -148,6 +148,7 @@ clocks = <&sysclk>; interrupt-parent = <&intc>; fifo-depth = <32>; + max-xfer-size = <16>; #address-cells = <1>; #size-cells = <0>; @@ -159,6 +160,7 @@ clocks = <&sysclk>; interrupt-parent = <&intc>; fifo-depth = <32>; + max-xfer-size = <16>; #address-cells = <1>; #size-cells = <0>; diff --git a/dts/arm/intel_socfpga_std/socfpga.dtsi b/dts/arm/intel_socfpga_std/socfpga.dtsi index e2e852a4791..7e1f37267d5 100644 --- a/dts/arm/intel_socfpga_std/socfpga.dtsi +++ b/dts/arm/intel_socfpga_std/socfpga.dtsi @@ -244,6 +244,7 @@ #size-cells = <0>; reg = <0xfff00000 0x1000>; fifo-depth = <256>; + max-xfer-size = <32>; interrupts = <0 154 4 IRQ_DEFAULT_PRIORITY>; clock-frequency = <200000000>; status = "okay"; @@ -255,6 +256,7 @@ #size-cells = <0>; reg = <0xfff01000 0x1000>; fifo-depth = <256>; + max-xfer-size = <32>; interrupts = <0 155 4 IRQ_DEFAULT_PRIORITY>; clock-frequency = <200000000>; status = "disabled"; diff --git a/dts/bindings/spi/snps,designware-spi.yaml b/dts/bindings/spi/snps,designware-spi.yaml index 822cb8d508b..01073f8d003 100644 --- a/dts/bindings/spi/snps,designware-spi.yaml +++ b/dts/bindings/spi/snps,designware-spi.yaml @@ -34,3 +34,13 @@ properties: True if it is a Serial Target. False if it is a Serial Master. Corresponds to SSI_IS_MASTER of the Designware Synchronous Serial Interface. + + max-xfer-size: + type: int + description: | + Maximum transfer size. Corresponds to SPI_MAX_XFER_SIZE + of the DesignWare Synchronous Serial Interface. Only + values of 16 and 32 are supported. + enum: + - 16 + - 32 From e9b26b5eb6cb91a530e28f1d131e1e45708367c7 Mon Sep 17 00:00:00 2001 From: Gerson Fernando Budke Date: Fri, 5 Jan 2024 19:34:34 +0100 Subject: [PATCH 2626/3723] soc: sam0: samd: Fix switching between clocks The clock z_arm_platform_init hangs switching between clocks when using MCUboot. This fixes the issue using the 8MHz internal clock as gclk_main source when configuring PLL/DFLL. Fixes: #67220 Signed-off-by: Gerson Fernando Budke --- soc/arm/atmel_sam0/common/soc_samd2x.c | 21 +++++++++++++++++---- 1 file changed, 17 insertions(+), 4 deletions(-) diff --git a/soc/arm/atmel_sam0/common/soc_samd2x.c b/soc/arm/atmel_sam0/common/soc_samd2x.c index bc488ab724c..b15108ead8c 100644 --- a/soc/arm/atmel_sam0/common/soc_samd2x.c +++ b/soc/arm/atmel_sam0/common/soc_samd2x.c @@ -38,9 +38,6 @@ #define FUSES_OSC32K_CAL_Msk FUSES_OSC32KCAL_Msk #endif -#if !CONFIG_SOC_ATMEL_SAMD_OSC8M || CONFIG_SOC_ATMEL_SAMD_DEFAULT_AS_MAIN -#define osc8m_init() -#else static inline void osc8m_init(void) { uint32_t reg; @@ -56,8 +53,24 @@ static inline void osc8m_init(void) while (!SYSCTRL->PCLKSR.bit.OSC8MRDY) { } + + /* Use 8Mhz clock as gclk_main to allow switching between clocks + * when using bootloaders + */ + GCLK->GENDIV.reg = GCLK_GENDIV_ID(0) + | GCLK_GENDIV_DIV(0); + + while (GCLK->STATUS.bit.SYNCBUSY) { + } + + GCLK->GENCTRL.reg = GCLK_GENCTRL_ID(0) + | GCLK_GENCTRL_SRC_OSC8M + | GCLK_GENCTRL_IDC + | GCLK_GENCTRL_GENEN; + + while (GCLK->STATUS.bit.SYNCBUSY) { + } } -#endif #if !CONFIG_SOC_ATMEL_SAMD_OSC32K || CONFIG_SOC_ATMEL_SAMD_DEFAULT_AS_MAIN #define osc32k_init() From d1bfea0e4ef3c3b06e502792c36c7d04f2a9fe1f Mon Sep 17 00:00:00 2001 From: Tom Rothamel Date: Tue, 21 Feb 2023 10:16:28 -0500 Subject: [PATCH 2627/3723] dts: atmel sam: Document what rxpo and txpo mean. The meaning of txpo is was a bit confusing, as it's an enumeration rather than a pad number. This confusion extended to the atsamd21_xpro board using the wrong pins. This commit adds ASCII-art tables that explain the meaning of rxpo and txpo on different platforms. Signed-off-by: Tom Rothamel --- dts/bindings/serial/atmel,sam0-uart.yaml | 74 +++++++++++++++++++++++- 1 file changed, 72 insertions(+), 2 deletions(-) diff --git a/dts/bindings/serial/atmel,sam0-uart.yaml b/dts/bindings/serial/atmel,sam0-uart.yaml index 30588f35dfd..f817137d7b6 100644 --- a/dts/bindings/serial/atmel,sam0-uart.yaml +++ b/dts/bindings/serial/atmel,sam0-uart.yaml @@ -22,12 +22,82 @@ properties: rxpo: type: int required: true - description: Receive Data Pinout + description: | + Receive Data Pinout. An enumeration with the following values: + + +-------+---------------+ + | Value | RX Pin | + +-------+---------------+ + | 0 | SERCOM_PAD[0] | + +-------+---------------+ + | 1 | SERCOM_PAD[1] | + +-------+---------------+ + | 2 | SERCOM_PAD[2] | + +-------+---------------+ + | 3 | SERCOM_PAD[3] | + +-------+---------------+ + txpo: type: int required: true - description: Transmit Data Pinout + description: | + Transmit Data Pinout. An enumeration with values that depend on the + hardware being used. This controls both the transmit pins and if + hardware flow control is used. + + SAMD20: + + +-------+---------------+ + | Value | TX Pin | + +-------+---------------+ + | 0 | SERCOM_PAD[0] | + +-------+---------------+ + | 1 | SERCOM_PAD[2] | + +-------+---------------+ + + SAMD21/DA21/R21: + + +-------+---------------+---------------+---------------+ + | Value | TX Pin | RTS | CTS | + +-------+---------------+---------------+---------------+ + | 0 | SERCOM_PAD[0] | N/A | N/A | + +-------+---------------+---------------+---------------+ + | 1 | SERCOM_PAD[2] | N/A | N/A | + +-------+---------------+---------------+---------------+ + | 2 | SERCOM_PAD[0] | SERCOM_PAD[2] | SERCOM_PAD[3] | + +-------+---------------+---------------+---------------+ + | 3 | Reserved | + +-------+-----------------------------------------------+ + + SAML2x/C2x: + + +-------+----------------+---------------+--------------+ + | Value | TX Pin | RTS | CTS | + +-------+---------------+---------------+---------------+ + | 0 | SERCOM_PAD[0] | N/A | N/A | + +-------+---------------+---------------+---------------+ + | 1 | SERCOM_PAD[2] | N/A | N/A | + +-------+---------------+---------------+---------------+ + | 2 | SERCOM_PAD[0] | SERCOM_PAD[2] | SERCOM_PAD[3] | + +-------+---------------+---------------+---------------+ + | 3 | SERCOM_PAD[0] | SERCOM_PAD[2] | N/A | + +-------+---------------+---------------+---------------+ + + SAMD5/E5: + + +-------+---------------+---------------+---------------+ + | Value | TX Pin | RTS | CTS | + +-------+---------------+---------------+---------------+ + | 0 | SERCOM_PAD[0] | N/A | N/A | + +-------+---------------+---------------+---------------+ + | 1 | Reserved | + +-------+---------------+---------------+---------------+ + | 2 | SERCOM_PAD[0] | SERCOM_PAD[2] | SERCOM_PAD[3] | + +-------+---------------+---------------+---------------+ + | 3 | SERCOM_PAD[0] | SERCOM_PAD[2] | N/A | + +-------+---------------+---------------+---------------+ + collision-detection: type: boolean From 3f655524463c8310943611fbeee34a66436b16ab Mon Sep 17 00:00:00 2001 From: Tom Rothamel Date: Tue, 21 Feb 2023 10:24:24 -0500 Subject: [PATCH 2628/3723] boards: arm: atsamd21_xpro: Change sercom0 tx pad and control. According to the documentation and pinctrl file, sercom0 tx should be available on PA10C/SERCOM_PAD[2]. However, and somewhat confusingly, txpo 2 meant SERCOM_PAD[0] with RTS/CTS flow control. Changing this to txpo 1 uses SERCOM_PAD[2], which allows sercom0 to work as documented. Signed-off-by: Tom Rothamel --- boards/arm/atsamd21_xpro/atsamd21_xpro.dts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/boards/arm/atsamd21_xpro/atsamd21_xpro.dts b/boards/arm/atsamd21_xpro/atsamd21_xpro.dts index e48e5afd467..d65d773a66f 100644 --- a/boards/arm/atsamd21_xpro/atsamd21_xpro.dts +++ b/boards/arm/atsamd21_xpro/atsamd21_xpro.dts @@ -75,7 +75,7 @@ compatible = "atmel,sam0-uart"; current-speed = <9600>; rxpo = <3>; - txpo = <2>; + txpo = <1>; pinctrl-0 = <&sercom0_uart_default>; pinctrl-names = "default"; From 0747cd3358269462955e17e191b1edf0e949c83c Mon Sep 17 00:00:00 2001 From: Luca Burelli Date: Fri, 12 Jan 2024 11:06:28 +0100 Subject: [PATCH 2629/3723] llext: define add_llext_target() for llext compilation This patch defines a generic function that encapsulates all the architecture-specific machinery needed to compile llexts from source files. Current tests are updated to use this function. Output and source files must be specified using the OUTPUT and SOURCES arguments. Only one source file is currently supported. Arch-specific flags will be added automatically. The C_FLAGS argument can be used to pass additional compiler flags to the compilation of the source file. Signed-off-by: Luca Burelli --- cmake/modules/extensions.cmake | 90 +++++++++++++++++++ tests/subsys/llext/hello_world/CMakeLists.txt | 34 ++----- 2 files changed, 97 insertions(+), 27 deletions(-) diff --git a/cmake/modules/extensions.cmake b/cmake/modules/extensions.cmake index e2904066e7a..a7cd28897a4 100644 --- a/cmake/modules/extensions.cmake +++ b/cmake/modules/extensions.cmake @@ -34,6 +34,7 @@ include(CheckCXXCompilerFlag) # 5. Zephyr linker functions # 5.1. zephyr_linker* # 6 Function helper macros +# 7 Linkable loadable extensions (llext) ######################################################## # 1. Zephyr-aware extensions @@ -4792,3 +4793,92 @@ macro(zephyr_check_flags_exclusive function prefix) ) endif() endmacro() + +######################################################## +# 7. Linkable loadable extensions (llext) +######################################################## +# +# These functions simplify the creation and management of linkable +# loadable extensions (llexts). +# + +# Add a custom target that compiles a single source file to a .llext file. +# +# Output and source files must be specified using the OUTPUT and SOURCES +# arguments. Only one source file is currently supported. +# +# Arch-specific flags will be added automatically. The C_FLAGS argument +# can be used to pass additional compiler flags to the compilation of +# the source file. +# +# Example usage: +# add_llext_target(hello_world +# OUTPUT ${PROJECT_BINARY_DIR}/hello_world.llext +# SOURCES ${PROJECT_SOURCE_DIR}/src/llext/hello_world.c +# C_FLAGS -Werror +# ) +# will compile the source file src/llext/hello_world.c to a file +# ${PROJECT_BINARY_DIR}/hello_world.llext, adding -Werror to the compilation. +# +function(add_llext_target target_name) + set(single_args OUTPUT) + set(multi_args SOURCES;C_FLAGS) + cmake_parse_arguments(PARSE_ARGV 1 LLEXT "${options}" "${single_args}" "${multi_args}") + + # Check that the llext subsystem is enabled for this build + if (NOT CONFIG_LLEXT) + message(FATAL_ERROR "add_llext_target: CONFIG_LLEXT must be enabled") + endif() + + # Output file must be provided + if(NOT LLEXT_OUTPUT) + message(FATAL_ERROR "add_llext_target: OUTPUT argument must be provided") + endif() + + # Source list length must currently be 1 + list(LENGTH LLEXT_SOURCES source_count) + if(NOT source_count EQUAL 1) + message(FATAL_ERROR "add_llext_target: only one source file is supported") + endif() + + set(output_file ${LLEXT_OUTPUT}) + set(source_file ${LLEXT_SOURCES}) + get_filename_component(output_name ${output_file} NAME) + + # Add user-visible target and dependency + add_custom_target(${target_name} + COMMENT "Compiling ${output_name}" + DEPENDS ${output_file} + ) + + # Compile the source file to an .llext file + if(CONFIG_ARM) + list(PREPEND LLEXT_C_FLAGS "-mlong-calls" "-mthumb") + add_custom_command(OUTPUT ${output_file} + COMMAND ${CMAKE_C_COMPILER} ${LLEXT_C_FLAGS} -c + -I ${ZEPHYR_BASE}/include + -imacros ${AUTOCONF_H} + -o ${output_file} + ${source_file} + DEPENDS ${source_file} + ) + elseif(CONFIG_XTENSA) + list(PREPEND LLEXT_C_FLAGS "-shared" "-fPIC" "-nostdlib" "-nodefaultlibs") + get_filename_component(output_dir ${output_file} DIRECTORY) + get_filename_component(output_name_we ${output_file} NAME_WE) + set(pre_output_file ${output_dir}/${output_name_we}.pre.llext) + add_custom_command(OUTPUT ${output_file} + COMMAND ${CMAKE_C_COMPILER} ${LLEXT_C_FLAGS} + -I ${ZEPHYR_BASE}/include + -imacros ${AUTOCONF_H} + -o ${pre_output_file} + ${source_file} + COMMAND ${CROSS_COMPILE}strip -R .xt.* + -o ${output_file} + ${pre_output_file} + DEPENDS ${source_file} + ) + else() + message(FATAL_ERROR "add_llext_target: unsupported architecture") + endif() +endfunction() diff --git a/tests/subsys/llext/hello_world/CMakeLists.txt b/tests/subsys/llext/hello_world/CMakeLists.txt index 980f0e97d00..45e0fa0b9a3 100644 --- a/tests/subsys/llext/hello_world/CMakeLists.txt +++ b/tests/subsys/llext/hello_world/CMakeLists.txt @@ -7,34 +7,14 @@ project(hello_world) if(NOT CONFIG_MODULES OR CONFIG_LLEXT_TEST_HELLO STREQUAL "m") -# TODO check which architecture is being used -if(CONFIG_ARM) - set(CMAKE_C_FLAGS "-mlong-calls" "-mthumb") + set(llext_src_file ${PROJECT_SOURCE_DIR}/hello_world.c) + set(llext_bin_file ${PROJECT_BINARY_DIR}/hello_world.llext) - add_custom_command(OUTPUT ${PROJECT_BINARY_DIR}/hello_world.llext - COMMAND ${CMAKE_C_COMPILER} ${CMAKE_C_FLAGS} -c - -I ${PROJECT_SOURCE_DIR}/../../../../include - -imacros${PROJECT_BINARY_DIR}/../zephyr/include/generated/autoconf.h - -o ${PROJECT_BINARY_DIR}/hello_world.llext - ${PROJECT_SOURCE_DIR}/hello_world.c - ) -elseif(CONFIG_XTENSA) - set(CMAKE_C_FLAGS "-shared" "-fPIC" "-nostdlib" "-nodefaultlibs") + add_llext_target(hello_world + OUTPUT ${llext_bin_file} + SOURCES ${llext_src_file} + ) - add_custom_command(OUTPUT ${PROJECT_BINARY_DIR}/hello_world.llext - COMMAND ${CMAKE_C_COMPILER} ${CMAKE_C_FLAGS} - -I ${PROJECT_SOURCE_DIR}/../../../../include - -imacros${PROJECT_BINARY_DIR}/../zephyr/include/generated/autoconf.h - -o ${PROJECT_BINARY_DIR}/hello_world.pre.llext - ${PROJECT_SOURCE_DIR}/hello_world.c - COMMAND ${CROSS_COMPILE}strip -R .xt.* - -o ${PROJECT_BINARY_DIR}/hello_world.llext - ${PROJECT_BINARY_DIR}/hello_world.pre.llext - ) -endif() - -set(HELLO_WORLD_LLEXT ${PROJECT_BINARY_DIR}/hello_world.llext PARENT_SCOPE) - -add_custom_target(hello_world DEPENDS ${PROJECT_BINARY_DIR}/hello_world.llext) + set(HELLO_WORLD_LLEXT ${llext_bin_file} PARENT_SCOPE) endif() From feee017767a212e01f1ec52b9f5bf2d7e372fd83 Mon Sep 17 00:00:00 2001 From: Luca Burelli Date: Fri, 19 Jan 2024 12:59:50 +0100 Subject: [PATCH 2630/3723] llext: rework add_llext_target() to use standard compile step Separate the compilation of the source file from the conversion to an llext file. This allows to reuse the include directories and macro definitions of the current Zephyr build while compiling the llext source. Signed-off-by: Luca Burelli --- cmake/modules/extensions.cmake | 64 +++++++++++++++++++++++++--------- 1 file changed, 48 insertions(+), 16 deletions(-) diff --git a/cmake/modules/extensions.cmake b/cmake/modules/extensions.cmake index a7cd28897a4..bdd4a6df959 100644 --- a/cmake/modules/extensions.cmake +++ b/cmake/modules/extensions.cmake @@ -4851,34 +4851,66 @@ function(add_llext_target target_name) DEPENDS ${output_file} ) - # Compile the source file to an .llext file + # Define arch-specific flags for the supported architectures if(CONFIG_ARM) list(PREPEND LLEXT_C_FLAGS "-mlong-calls" "-mthumb") - add_custom_command(OUTPUT ${output_file} - COMMAND ${CMAKE_C_COMPILER} ${LLEXT_C_FLAGS} -c - -I ${ZEPHYR_BASE}/include - -imacros ${AUTOCONF_H} - -o ${output_file} - ${source_file} - DEPENDS ${source_file} - ) elseif(CONFIG_XTENSA) list(PREPEND LLEXT_C_FLAGS "-shared" "-fPIC" "-nostdlib" "-nodefaultlibs") + else() + message(FATAL_ERROR "add_llext_target: unsupported architecture") + endif() + + # Compile the source file to an object file using current Zephyr settings + # but a different set of flags + add_library(${target_name}_lib OBJECT ${source_file}) + target_compile_definitions(${target_name}_lib PRIVATE + $ + ) + target_compile_options(${target_name}_lib PRIVATE + ${LLEXT_C_FLAGS} + -imacros "${AUTOCONF_H}" + ) + target_include_directories(${target_name}_lib PRIVATE + $ + -I${PROJECT_BINARY_DIR}/include/generated + ) + target_include_directories(${target_name}_lib SYSTEM PUBLIC + $ + ) + add_dependencies(${target_name}_lib + zephyr_interface + zephyr_generated_headers + ) + + # Arch-specific conversion of the object file to an llext + if(CONFIG_ARM) + + # No conversion required, simply copy the object file + add_custom_command( + OUTPUT ${output_file} + COMMAND ${CMAKE_COMMAND} -E copy $ ${output_file} + DEPENDS ${target_name}_lib $ + ) + + elseif(CONFIG_XTENSA) + + # Generate an intermediate file name get_filename_component(output_dir ${output_file} DIRECTORY) get_filename_component(output_name_we ${output_file} NAME_WE) set(pre_output_file ${output_dir}/${output_name_we}.pre.llext) - add_custom_command(OUTPUT ${output_file} + + # Need to convert the object file to a shared library, then strip some sections + add_custom_command( + OUTPUT ${output_file} + BYPRODUCTS ${pre_output_file} COMMAND ${CMAKE_C_COMPILER} ${LLEXT_C_FLAGS} - -I ${ZEPHYR_BASE}/include - -imacros ${AUTOCONF_H} -o ${pre_output_file} - ${source_file} + $ COMMAND ${CROSS_COMPILE}strip -R .xt.* -o ${output_file} ${pre_output_file} - DEPENDS ${source_file} + DEPENDS ${target_name}_lib $ ) - else() - message(FATAL_ERROR "add_llext_target: unsupported architecture") + endif() endfunction() From c5b7aabc063d558805b342e26749389d44c33a54 Mon Sep 17 00:00:00 2001 From: Luca Burelli Date: Fri, 19 Jan 2024 13:00:38 +0100 Subject: [PATCH 2631/3723] llext: move all flags to compiler specific cmake files Minimize the amount of flags that are hardcoded in the llext.cmake module by moving them to the compiler specific cmake files. The llext.cmake module will now use the new LLEXT_REMOVE_FLAGS and LLEXT_APPEND_FLAGS global variables to adjust the set of flags used to compile the llext code. This will make it easier to add support for new architectures and compilers. Signed-off-by: Luca Burelli --- cmake/bintools/gnu/target_bintools.cmake | 1 + cmake/compiler/gcc/target.cmake | 2 + cmake/compiler/gcc/target_arm.cmake | 19 ++++++++++ cmake/compiler/gcc/target_xtensa.cmake | 21 +++++++++++ cmake/modules/extensions.cmake | 48 +++++++++++++++--------- 5 files changed, 74 insertions(+), 17 deletions(-) create mode 100644 cmake/compiler/gcc/target_xtensa.cmake diff --git a/cmake/bintools/gnu/target_bintools.cmake b/cmake/bintools/gnu/target_bintools.cmake index e8cb6e181d5..8aac55b0400 100644 --- a/cmake/bintools/gnu/target_bintools.cmake +++ b/cmake/bintools/gnu/target_bintools.cmake @@ -93,6 +93,7 @@ set_property(TARGET bintools PROPERTY strip_flag_final "") set_property(TARGET bintools PROPERTY strip_flag_all --strip-all) set_property(TARGET bintools PROPERTY strip_flag_debug --strip-debug) set_property(TARGET bintools PROPERTY strip_flag_dwo --strip-dwo) +set_property(TARGET bintools PROPERTY strip_flag_remove_section -R ) set_property(TARGET bintools PROPERTY strip_flag_infile "") set_property(TARGET bintools PROPERTY strip_flag_outfile -o ) diff --git a/cmake/compiler/gcc/target.cmake b/cmake/compiler/gcc/target.cmake index 86807bd8a4f..5b1e5db1218 100644 --- a/cmake/compiler/gcc/target.cmake +++ b/cmake/compiler/gcc/target.cmake @@ -76,6 +76,8 @@ elseif("${ARCH}" STREQUAL "sparc") include(${CMAKE_CURRENT_LIST_DIR}/target_sparc.cmake) elseif("${ARCH}" STREQUAL "mips") include(${CMAKE_CURRENT_LIST_DIR}/target_mips.cmake) +elseif("${ARCH}" STREQUAL "xtensa") + include(${CMAKE_CURRENT_LIST_DIR}/target_xtensa.cmake) endif() if(SYSROOT_DIR) diff --git a/cmake/compiler/gcc/target_arm.cmake b/cmake/compiler/gcc/target_arm.cmake index a813c2563a3..6659c7bf417 100644 --- a/cmake/compiler/gcc/target_arm.cmake +++ b/cmake/compiler/gcc/target_arm.cmake @@ -41,3 +41,22 @@ endif() list(APPEND TOOLCHAIN_C_FLAGS ${ARM_C_FLAGS}) list(APPEND TOOLCHAIN_LD_FLAGS NO_SPLIT ${ARM_C_FLAGS}) + +# Flags not supported by llext linker +# (regexps are supported and match whole word) +set(LLEXT_REMOVE_FLAGS + -fno-pic + -fno-pie + -ffunction-sections + -fdata-sections + -g.* + -Os + -mcpu=.* +) + +# Flags to be added to llext code compilation +set(LLEXT_APPEND_FLAGS + -mlong-calls + -mthumb + -mcpu=cortex-m33+nodsp +) diff --git a/cmake/compiler/gcc/target_xtensa.cmake b/cmake/compiler/gcc/target_xtensa.cmake new file mode 100644 index 00000000000..177830427db --- /dev/null +++ b/cmake/compiler/gcc/target_xtensa.cmake @@ -0,0 +1,21 @@ +# SPDX-License-Identifier: Apache-2.0 + +# Flags not supported by llext linker +# (regexps are supported and match whole word) +set(LLEXT_REMOVE_FLAGS + -fno-pic + -fno-pie + -ffunction-sections + -fdata-sections + -g.* + -Os + -mcpu=.* +) + +# Flags to be added to llext code compilation +set(LLEXT_APPEND_FLAGS + -fPIC + -nostdlib + -nodefaultlibs + -shared +) diff --git a/cmake/modules/extensions.cmake b/cmake/modules/extensions.cmake index bdd4a6df959..594d8104a3b 100644 --- a/cmake/modules/extensions.cmake +++ b/cmake/modules/extensions.cmake @@ -4807,9 +4807,13 @@ endmacro() # Output and source files must be specified using the OUTPUT and SOURCES # arguments. Only one source file is currently supported. # -# Arch-specific flags will be added automatically. The C_FLAGS argument -# can be used to pass additional compiler flags to the compilation of -# the source file. +# The llext code will be compiled with mostly the same C compiler flags used +# in the Zephyr build, but with some important modifications. The list of +# flags to remove and flags to append is controlled respectively by the +# LLEXT_REMOVE_FLAGS and LLEXT_APPEND_FLAGS global variables. + +# The C_FLAGS argument can be used to pass additional compiler flags to the +# compilation of this particular llext. # # Example usage: # add_llext_target(hello_world @@ -4851,14 +4855,19 @@ function(add_llext_target target_name) DEPENDS ${output_file} ) - # Define arch-specific flags for the supported architectures - if(CONFIG_ARM) - list(PREPEND LLEXT_C_FLAGS "-mlong-calls" "-mthumb") - elseif(CONFIG_XTENSA) - list(PREPEND LLEXT_C_FLAGS "-shared" "-fPIC" "-nostdlib" "-nodefaultlibs") - else() - message(FATAL_ERROR "add_llext_target: unsupported architecture") - endif() + # Convert the LLEXT_REMOVE_FLAGS list to a regular expression, and use it to + # filter out these flags from the Zephyr target settings + list(TRANSFORM LLEXT_REMOVE_FLAGS + REPLACE "(.+)" "^\\1$" + OUTPUT_VARIABLE llext_remove_flags_regexp + ) + string(REPLACE ";" "|" llext_remove_flags_regexp "${llext_remove_flags_regexp}") + set(zephyr_flags + "$" + ) + set(zephyr_filtered_flags + "$" + ) # Compile the source file to an object file using current Zephyr settings # but a different set of flags @@ -4867,12 +4876,12 @@ function(add_llext_target target_name) $ ) target_compile_options(${target_name}_lib PRIVATE + ${zephyr_filtered_flags} + ${LLEXT_APPEND_FLAGS} ${LLEXT_C_FLAGS} - -imacros "${AUTOCONF_H}" ) target_include_directories(${target_name}_lib PRIVATE $ - -I${PROJECT_BINARY_DIR}/include/generated ) target_include_directories(${target_name}_lib SYSTEM PUBLIC $ @@ -4903,14 +4912,19 @@ function(add_llext_target target_name) add_custom_command( OUTPUT ${output_file} BYPRODUCTS ${pre_output_file} - COMMAND ${CMAKE_C_COMPILER} ${LLEXT_C_FLAGS} + COMMAND ${CMAKE_C_COMPILER} ${LLEXT_APPEND_FLAGS} -o ${pre_output_file} $ - COMMAND ${CROSS_COMPILE}strip -R .xt.* - -o ${output_file} - ${pre_output_file} + COMMAND $ + $ + $.xt.* + $${pre_output_file} + $${output_file} + $ DEPENDS ${target_name}_lib $ ) + else() + message(FATAL_ERROR "add_llext_target: unsupported architecture") endif() endfunction() From 3436c93387fc73dd0eb54cb3cb6959ac95ed639e Mon Sep 17 00:00:00 2001 From: Henrik Brix Andersen Date: Fri, 15 Dec 2023 13:36:18 +0100 Subject: [PATCH 2632/3723] drivers: can: remove run-time RTR filtering, add build-time RTR filter A growing number of CAN controllers do not have support for individual RX hardware filters based on the Remote Transmission Request (RTR) bit. This leads to various work-arounds on the driver level mixing hardware and software filtering. As the use of RTR frames is discouraged by CAN in Automation (CiA) - and not even supported by newer standards, e.g. CAN FD - this often leads to unnecessary overhead, added complexity, and worst-case to non-portable behavior between various CAN controller drivers. Instead, move to a simpler approach where the ability to accept/reject RTR frames is globally configured via Kconfig. By default, all incoming RTR frames are rejected at the driver level, a setting which can be supported in hardware by most in-tree CAN controllers drivers. Legacy applications or protocol implementations, where RTR reception is required, can now select CONFIG_CAN_ACCEPT_RTR to accept incoming RTR frames matching added CAN filters. These applications or protocols will need to distinguish between RTR and data frames in their respective CAN RX frame handling routines. Signed-off-by: Henrik Brix Andersen --- doc/hardware/peripherals/can/controller.rst | 4 +- drivers/can/Kconfig | 7 ++ drivers/can/can_loopback.c | 8 +- drivers/can/can_mcan.c | 21 +--- drivers/can/can_mcp2515.c | 8 +- drivers/can/can_mcp251xfd.c | 11 +- drivers/can/can_mcux_flexcan.c | 12 +- drivers/can/can_native_linux.c | 8 +- drivers/can/can_nxp_s32_canxl.c | 7 +- drivers/can/can_rcar.c | 8 +- drivers/can/can_shell.c | 24 +--- drivers/can/can_sja1000.c | 24 ++-- drivers/can/can_stm32_bxcan.c | 13 +- include/zephyr/drivers/can.h | 17 +-- include/zephyr/drivers/can/can_mcan.h | 1 - include/zephyr/net/socketcan_utils.h | 12 +- modules/canopennode/CO_driver.c | 18 ++- modules/canopennode/CO_driver_target.h | 3 + samples/drivers/can/counter/src/main.c | 12 +- samples/net/sockets/can/src/main.c | 2 +- subsys/canbus/isotp/isotp.c | 10 +- tests/drivers/can/api/src/classic.c | 111 +++++++++++++----- tests/drivers/can/api/src/common.c | 40 ++----- tests/drivers/can/api/src/common.h | 12 -- tests/drivers/can/api/src/utilities.c | 18 +-- tests/drivers/can/api/testcase.yaml | 16 +-- tests/drivers/can/shell/src/main.c | 34 +----- tests/net/socket/can/src/main.c | 15 ++- .../canbus/isotp/conformance/src/main.c | 2 +- 29 files changed, 243 insertions(+), 235 deletions(-) diff --git a/doc/hardware/peripherals/can/controller.rst b/doc/hardware/peripherals/can/controller.rst index 6943949d1a4..e8710201349 100644 --- a/doc/hardware/peripherals/can/controller.rst +++ b/doc/hardware/peripherals/can/controller.rst @@ -203,7 +203,7 @@ The filter for this example is configured to match the identifier 0x123 exactly. .. code-block:: C const struct can_filter my_filter = { - .flags = CAN_FILTER_DATA, + .flags = 0U, .id = 0x123, .mask = CAN_STD_ID_MASK }; @@ -226,7 +226,7 @@ The filter for this example is configured to match the extended identifier .. code-block:: C const struct can_filter my_filter = { - .flags = CAN_FILTER_DATA | CAN_FILTER_IDE, + .flags = CAN_FILTER_IDE, .id = 0x1234567, .mask = CAN_EXT_ID_MASK }; diff --git a/drivers/can/Kconfig b/drivers/can/Kconfig index e4fd4709505..d31d7b981b2 100644 --- a/drivers/can/Kconfig +++ b/drivers/can/Kconfig @@ -54,6 +54,13 @@ config CAN_STATS help Enable CAN controller device statistics. +config CAN_ACCEPT_RTR + bool "Accept Remote Transmission Requests (RTR) frames" + help + Accept incoming Remote Transmission Request (RTR) frames matching CAN RX filters. Unless + enabled, all incoming Remote Transmission Request (RTR) frames are rejected at the driver + level. + config CAN_FD_MODE bool "CAN FD" help diff --git a/drivers/can/can_loopback.c b/drivers/can/can_loopback.c index 5eb88b163ed..938002f5978 100644 --- a/drivers/can/can_loopback.c +++ b/drivers/can/can_loopback.c @@ -77,6 +77,12 @@ static void tx_thread(void *arg1, void *arg2, void *arg3) continue; } +#ifndef CONFIG_CAN_ACCEPT_RTR + if ((frame.frame.flags & CAN_FRAME_RTR) != 0U) { + continue; + } +#endif /* !CONFIG_CAN_ACCEPT_RTR */ + k_mutex_lock(&data->mtx, K_FOREVER); for (int i = 0; i < CONFIG_CAN_MAX_FILTER; i++) { @@ -172,7 +178,7 @@ static int can_loopback_add_rx_filter(const struct device *dev, can_rx_callback_ LOG_DBG("Setting filter ID: 0x%x, mask: 0x%x", filter->id, filter->mask); - if ((filter->flags & ~(CAN_FILTER_IDE | CAN_FILTER_DATA | CAN_FILTER_RTR)) != 0) { + if ((filter->flags & ~(CAN_FILTER_IDE)) != 0) { LOG_ERR("unsupported CAN filter flags 0x%02x", filter->flags); return -ENOTSUP; } diff --git a/drivers/can/can_mcan.c b/drivers/can/can_mcan.c index dc54bc19670..d777e325b82 100644 --- a/drivers/can/can_mcan.c +++ b/drivers/can/can_mcan.c @@ -615,7 +615,6 @@ static void can_mcan_get_message(const struct device *dev, uint16_t fifo_offset, struct can_frame frame = {0}; can_rx_callback_t cb; void *user_data; - uint8_t flags; uint32_t get_idx; uint32_t filt_idx; int data_length; @@ -666,20 +665,8 @@ static void can_mcan_get_message(const struct device *dev, uint16_t fifo_offset, if (hdr.xtd != 0) { frame.id = hdr.ext_id; frame.flags |= CAN_FRAME_IDE; - flags = cbs->ext[filt_idx].flags; } else { frame.id = hdr.std_id; - flags = cbs->std[filt_idx].flags; - } - - if (((frame.flags & CAN_FRAME_RTR) == 0U && (flags & CAN_FILTER_DATA) == 0U) || - ((frame.flags & CAN_FRAME_RTR) != 0U && (flags & CAN_FILTER_RTR) == 0U)) { - /* RTR bit does not match filter, drop frame */ - err = can_mcan_write_reg(dev, fifo_ack_reg, get_idx); - if (err != 0) { - return; - } - goto ack; } data_length = can_dlc_to_bytes(frame.dlc); @@ -718,7 +705,6 @@ static void can_mcan_get_message(const struct device *dev, uint16_t fifo_offset, LOG_ERR("Frame is too big"); } -ack: err = can_mcan_write_reg(dev, fifo_ack_reg, get_idx); if (err != 0) { return; @@ -1042,7 +1028,6 @@ int can_mcan_add_rx_filter_std(const struct device *dev, can_rx_callback_t callb __ASSERT_NO_MSG(filter_id <= cbs->num_std); cbs->std[filter_id].function = callback; cbs->std[filter_id].user_data = user_data; - cbs->std[filter_id].flags = filter->flags; return filter_id; } @@ -1095,7 +1080,6 @@ static int can_mcan_add_rx_filter_ext(const struct device *dev, can_rx_callback_ __ASSERT_NO_MSG(filter_id <= cbs->num_ext); cbs->ext[filter_id].function = callback; cbs->ext[filter_id].user_data = user_data; - cbs->ext[filter_id].flags = filter->flags; return filter_id; } @@ -1111,7 +1095,7 @@ int can_mcan_add_rx_filter(const struct device *dev, can_rx_callback_t callback, return -EINVAL; } - if ((filter->flags & ~(CAN_FILTER_IDE | CAN_FILTER_DATA | CAN_FILTER_RTR)) != 0U) { + if ((filter->flags & ~(CAN_FILTER_IDE)) != 0U) { LOG_ERR("unsupported CAN filter flags 0x%02x", filter->flags); return -ENOTSUP; } @@ -1430,6 +1414,9 @@ int can_mcan_init(const struct device *dev) } reg |= FIELD_PREP(CAN_MCAN_GFC_ANFE, 0x2) | FIELD_PREP(CAN_MCAN_GFC_ANFS, 0x2); + if (!IS_ENABLED(CONFIG_CAN_ACCEPT_RTR)) { + reg |= CAN_MCAN_GFC_RRFS | CAN_MCAN_GFC_RRFE; + } err = can_mcan_write_reg(dev, CAN_MCAN_GFC, reg); if (err != 0) { diff --git a/drivers/can/can_mcp2515.c b/drivers/can/can_mcp2515.c index 8d02db834f7..255a8cdbe70 100644 --- a/drivers/can/can_mcp2515.c +++ b/drivers/can/can_mcp2515.c @@ -631,7 +631,7 @@ static int mcp2515_add_rx_filter(const struct device *dev, __ASSERT(rx_cb != NULL, "response_ptr can not be null"); - if ((filter->flags & ~(CAN_FILTER_IDE | CAN_FILTER_DATA | CAN_FILTER_RTR)) != 0) { + if ((filter->flags & ~(CAN_FILTER_IDE)) != 0) { LOG_ERR("unsupported CAN filter flags 0x%02x", filter->flags); return -ENOTSUP; } @@ -693,6 +693,12 @@ static void mcp2515_rx_filter(const struct device *dev, can_rx_callback_t callback; struct can_frame tmp_frame; +#ifndef CONFIG_CAN_ACCEPT_RTR + if ((frame->flags & CAN_FRAME_RTR) != 0U) { + return; + } +#endif /* !CONFIG_CAN_ACCEPT_RTR */ + k_mutex_lock(&dev_data->mutex, K_FOREVER); for (; filter_id < CONFIG_CAN_MAX_FILTER; filter_id++) { diff --git a/drivers/can/can_mcp251xfd.c b/drivers/can/can_mcp251xfd.c index 1b90982d642..e029d54496b 100644 --- a/drivers/can/can_mcp251xfd.c +++ b/drivers/can/can_mcp251xfd.c @@ -576,11 +576,6 @@ static int mcp251xfd_add_rx_filter(const struct device *dev, can_rx_callback_t r goto done; } - if ((filter->flags & CAN_FILTER_RTR) != 0) { - filter_idx = -ENOTSUP; - goto done; - } - reg = mcp251xfd_get_spi_buf_ptr(dev); if ((filter->flags & CAN_FILTER_IDE) != 0) { @@ -1267,6 +1262,12 @@ static void mcp251xfd_rx_fifo_handler(const struct device *dev, void *data) mcp251xfd_rxobj_to_canframe(rxobj, &dst); +#ifndef CONFIG_CAN_ACCEPT_RTR + if ((dst.flags & CAN_FRAME_RTR) != 0U) { + return; + } +#endif /* !CONFIG_CAN_ACCEPT_RTR */ + filhit = FIELD_GET(MCP251XFD_OBJ_FILHIT_MASK, rxobj->flags); if ((dev_data->filter_usage & BIT(filhit)) != 0) { LOG_DBG("Received msg CAN id: 0x%x", dst.id); diff --git a/drivers/can/can_mcux_flexcan.c b/drivers/can/can_mcux_flexcan.c index cb300bb7536..f83b2ec212a 100644 --- a/drivers/can/can_mcux_flexcan.c +++ b/drivers/can/can_mcux_flexcan.c @@ -625,8 +625,7 @@ static void mcux_flexcan_can_filter_to_mbconfig(const struct can_filter *src, uint32_t *mask) { static const uint32_t ide_mask = 1U; - uint32_t rtr_mask = (src->flags & (CAN_FILTER_DATA | CAN_FILTER_RTR)) != - (CAN_FILTER_DATA | CAN_FILTER_RTR) ? 1U : 0U; + static const uint32_t rtr_mask = !IS_ENABLED(CONFIG_CAN_ACCEPT_RTR); if ((src->flags & CAN_FILTER_IDE) != 0) { dest->format = kFLEXCAN_FrameFormatExtend; @@ -638,11 +637,7 @@ static void mcux_flexcan_can_filter_to_mbconfig(const struct can_filter *src, *mask = FLEXCAN_RX_MB_STD_MASK(src->mask, rtr_mask, ide_mask); } - if ((src->flags & CAN_FILTER_RTR) != 0) { - dest->type = kFLEXCAN_FrameTypeRemote; - } else { - dest->type = kFLEXCAN_FrameTypeData; - } + dest->type = kFLEXCAN_FrameTypeData; } static int mcux_flexcan_get_state(const struct device *dev, enum can_state *state, @@ -786,7 +781,6 @@ static int mcux_flexcan_add_rx_filter(const struct device *dev, void *user_data, const struct can_filter *filter) { - const uint8_t supported = CAN_FILTER_IDE | CAN_FILTER_DATA | CAN_FILTER_RTR; const struct mcux_flexcan_config *config = dev->config; struct mcux_flexcan_data *data = dev->data; status_t status; @@ -796,7 +790,7 @@ static int mcux_flexcan_add_rx_filter(const struct device *dev, __ASSERT_NO_MSG(callback); - if ((filter->flags & ~(supported)) != 0) { + if ((filter->flags & ~(CAN_FILTER_IDE)) != 0) { LOG_ERR("unsupported CAN filter flags 0x%02x", filter->flags); return -ENOTSUP; } diff --git a/drivers/can/can_native_linux.c b/drivers/can/can_native_linux.c index e5bd763f937..940123bdd92 100644 --- a/drivers/can/can_native_linux.c +++ b/drivers/can/can_native_linux.c @@ -105,6 +105,12 @@ static void rx_thread(void *arg1, void *arg2, void *arg3) socketcan_to_can_frame(&sframe, &frame); +#ifndef CONFIG_CAN_ACCEPT_RTR + if ((frame.flags & CAN_FRAME_RTR) != 0U) { + continue; + } +#endif /* !CONFIG_CAN_ACCEPT_RTR*/ + LOG_DBG("Received %d bytes. Id: 0x%x, ID type: %s %s", frame.dlc, frame.id, (frame.flags & CAN_FRAME_IDE) != 0 ? "extended" : "standard", @@ -197,7 +203,7 @@ static int can_native_linux_add_rx_filter(const struct device *dev, can_rx_callb LOG_DBG("Setting filter ID: 0x%x, mask: 0x%x", filter->id, filter->mask); - if ((filter->flags & ~(CAN_FILTER_IDE | CAN_FILTER_DATA | CAN_FILTER_RTR)) != 0) { + if ((filter->flags & ~(CAN_FILTER_IDE)) != 0) { LOG_ERR("unsupported CAN filter flags 0x%02x", filter->flags); return -ENOTSUP; } diff --git a/drivers/can/can_nxp_s32_canxl.c b/drivers/can/can_nxp_s32_canxl.c index 6a2180867f4..2ea854fad9e 100644 --- a/drivers/can/can_nxp_s32_canxl.c +++ b/drivers/can/can_nxp_s32_canxl.c @@ -506,7 +506,8 @@ static int can_nxp_s32_add_rx_filter(const struct device *dev, uint32_t mask; __ASSERT_NO_MSG(callback != NULL); - if ((filter->flags & ~(CAN_FILTER_IDE | CAN_FILTER_DATA)) != 0) { + + if ((filter->flags & ~(CAN_FILTER_IDE)) != 0) { LOG_ERR("unsupported CAN filter flags 0x%02x", filter->flags); return -ENOTSUP; } @@ -538,6 +539,10 @@ static int can_nxp_s32_add_rx_filter(const struct device *dev, mask = (filter->mask << CANXL_IP_ID_STD_SHIFT) & CANXL_IP_ID_STD_MASK; } +#ifndef CONFIG_CAN_ACCEPT_RTR + mask |= CANXL_MSG_DESCRIPTORS_MDFLT1FD_RTRMSK_MASK; +#endif /* !CONFIG_CAN_ACCEPT_RTR */ + Canexcel_Ip_EnterFreezeMode(config->instance); #ifdef CONFIG_CAN_NXP_S32_RX_FIFO diff --git a/drivers/can/can_rcar.c b/drivers/can/can_rcar.c index 35204b86c1f..98c134ac509 100644 --- a/drivers/can/can_rcar.c +++ b/drivers/can/can_rcar.c @@ -362,6 +362,12 @@ static void can_rcar_rx_filter_isr(const struct device *dev, struct can_frame tmp_frame; uint8_t i; +#ifndef CONFIG_CAN_ACCEPT_RTR + if ((frame->flags & CAN_FRAME_RTR) != 0U) { + return; + } +#endif /* !CONFIG_CAN_ACCEPT_RTR */ + for (i = 0; i < CONFIG_CAN_RCAR_MAX_FILTER; i++) { if (data->rx_callback[i] == NULL) { continue; @@ -957,7 +963,7 @@ static int can_rcar_add_rx_filter(const struct device *dev, can_rx_callback_t cb struct can_rcar_data *data = dev->data; int filter_id; - if ((filter->flags & ~(CAN_FILTER_IDE | CAN_FILTER_DATA)) != 0) { + if ((filter->flags & ~(CAN_FILTER_IDE)) != 0) { LOG_ERR("unsupported CAN filter flags 0x%02x", filter->flags); return -ENOTSUP; } diff --git a/drivers/can/can_shell.c b/drivers/can/can_shell.c index 3780e20e8d0..3f193ae9497 100644 --- a/drivers/can/can_shell.c +++ b/drivers/can/can_shell.c @@ -801,7 +801,7 @@ static int cmd_can_filter_add(const struct shell *sh, size_t argc, char **argv) /* Defaults */ max_id = CAN_MAX_STD_ID; - filter.flags = CAN_FILTER_DATA; + filter.flags = 0U; /* Parse options */ while (argidx < argc && strncmp(argv[argidx], "-", 1) == 0) { @@ -812,13 +812,6 @@ static int cmd_can_filter_add(const struct shell *sh, size_t argc, char **argv) filter.flags |= CAN_FILTER_IDE; max_id = CAN_MAX_EXT_ID; argidx++; - } else if (strcmp(argv[argidx], "-r") == 0) { - filter.flags |= CAN_FILTER_RTR; - argidx++; - } else if (strcmp(argv[argidx], "-R") == 0) { - filter.flags &= ~(CAN_FILTER_DATA); - filter.flags |= CAN_FILTER_RTR; - argidx++; } else { shell_error(sh, "unsupported argument %s", argv[argidx]); shell_help(sh); @@ -874,14 +867,11 @@ static int cmd_can_filter_add(const struct shell *sh, size_t argc, char **argv) return err; } - shell_print(sh, "adding filter with %s (%d-bit) CAN ID 0x%0*x, " - "CAN ID mask 0x%0*x, data frames %d, RTR frames %d", + shell_print(sh, "adding filter with %s (%d-bit) CAN ID 0x%0*x, CAN ID mask 0x%0*x", (filter.flags & CAN_FILTER_IDE) != 0 ? "extended" : "standard", (filter.flags & CAN_FILTER_IDE) != 0 ? 29 : 11, (filter.flags & CAN_FILTER_IDE) != 0 ? 8 : 3, filter.id, - (filter.flags & CAN_FILTER_IDE) != 0 ? 8 : 3, filter.mask, - (filter.flags & CAN_FILTER_DATA) != 0 ? 1 : 0, - (filter.flags & CAN_FILTER_RTR) != 0 ? 1 : 0); + (filter.flags & CAN_FILTER_IDE) != 0 ? 8 : 3, filter.mask); err = can_add_rx_filter_msgq(dev, &can_shell_rx_msgq, &filter); if (err < 0) { @@ -999,11 +989,9 @@ SHELL_DYNAMIC_CMD_CREATE(dsub_can_device_name_mode, cmd_can_device_name_mode); SHELL_STATIC_SUBCMD_SET_CREATE(sub_can_filter_cmds, SHELL_CMD_ARG(add, &dsub_can_device_name, "Add rx filter\n" - "Usage: can filter add [-e] [-r] [-R] [CAN ID mask]\n" - "-e use extended (29-bit) CAN ID/CAN ID mask\n" - "-r also match Remote Transmission Request (RTR) frames\n" - "-R only match Remote Transmission Request (RTR) frames", - cmd_can_filter_add, 3, 4), + "Usage: can filter add [-e] [CAN ID mask]\n" + "-e use extended (29-bit) CAN ID/CAN ID mask\n", + cmd_can_filter_add, 3, 2), SHELL_CMD_ARG(remove, &dsub_can_device_name, "Remove rx filter\n" "Usage: can filter remove ", diff --git a/drivers/can/can_sja1000.c b/drivers/can/can_sja1000.c index b0eac60063f..c5ee7bebcfd 100644 --- a/drivers/can/can_sja1000.c +++ b/drivers/can/can_sja1000.c @@ -427,7 +427,7 @@ int can_sja1000_add_rx_filter(const struct device *dev, can_rx_callback_t callba int filter_id = -ENOSPC; int i; - if ((filter->flags & ~(CAN_FILTER_IDE | CAN_FILTER_DATA | CAN_FILTER_RTR)) != 0) { + if ((filter->flags & ~(CAN_FILTER_IDE)) != 0) { LOG_ERR("unsupported CAN filter flags 0x%02x", filter->flags); return -ENOTSUP; } @@ -569,18 +569,24 @@ static void can_sja1000_handle_receive_irq(const struct device *dev) do { can_sja1000_read_frame(dev, &frame); - for (i = 0; i < ARRAY_SIZE(data->filters); i++) { - if (!atomic_test_bit(data->rx_allocs, i)) { - continue; - } +#ifndef CONFIG_CAN_ACCEPT_RTR + if ((frame.flags & CAN_FRAME_RTR) == 0U) { +#endif /* !CONFIG_CAN_ACCEPT_RTR */ + for (i = 0; i < ARRAY_SIZE(data->filters); i++) { + if (!atomic_test_bit(data->rx_allocs, i)) { + continue; + } - if (can_frame_matches_filter(&frame, &data->filters[i].filter)) { - callback = data->filters[i].callback; - if (callback != NULL) { - callback(dev, &frame, data->filters[i].user_data); + if (can_frame_matches_filter(&frame, &data->filters[i].filter)) { + callback = data->filters[i].callback; + if (callback != NULL) { + callback(dev, &frame, data->filters[i].user_data); + } } } +#ifndef CONFIG_CAN_ACCEPT_RTR } +#endif /* !CONFIG_CAN_ACCEPT_RTR */ can_sja1000_write_reg(dev, CAN_SJA1000_CMR, CAN_SJA1000_CMR_RRB); sr = can_sja1000_read_reg(dev, CAN_SJA1000_SR); diff --git a/drivers/can/can_stm32_bxcan.c b/drivers/can/can_stm32_bxcan.c index 71ac02cb202..03f67e86670 100644 --- a/drivers/can/can_stm32_bxcan.c +++ b/drivers/can/can_stm32_bxcan.c @@ -886,8 +886,7 @@ static void can_stm32_set_filter_bank(int filter_id, CAN_FilterRegister_TypeDef static inline uint32_t can_stm32_filter_to_std_mask(const struct can_filter *filter) { - uint32_t rtr_mask = (filter->flags & (CAN_FILTER_DATA | CAN_FILTER_RTR)) != - (CAN_FILTER_DATA | CAN_FILTER_RTR) ? 1U : 0U; + uint32_t rtr_mask = !IS_ENABLED(CONFIG_CAN_ACCEPT_RTR); return (filter->mask << CAN_STM32_FIRX_STD_ID_POS) | (rtr_mask << CAN_STM32_FIRX_STD_RTR_POS) | @@ -896,8 +895,7 @@ static inline uint32_t can_stm32_filter_to_std_mask(const struct can_filter *fil static inline uint32_t can_stm32_filter_to_ext_mask(const struct can_filter *filter) { - uint32_t rtr_mask = (filter->flags & (CAN_FILTER_DATA | CAN_FILTER_RTR)) != - (CAN_FILTER_DATA | CAN_FILTER_RTR) ? 1U : 0U; + uint32_t rtr_mask = !IS_ENABLED(CONFIG_CAN_ACCEPT_RTR); return (filter->mask << CAN_STM32_FIRX_EXT_EXT_ID_POS) | (rtr_mask << CAN_STM32_FIRX_EXT_RTR_POS) | @@ -906,15 +904,12 @@ static inline uint32_t can_stm32_filter_to_ext_mask(const struct can_filter *fil static inline uint32_t can_stm32_filter_to_std_id(const struct can_filter *filter) { - return (filter->id << CAN_STM32_FIRX_STD_ID_POS) | - (((filter->flags & CAN_FILTER_RTR) != 0) ? (1U << CAN_STM32_FIRX_STD_RTR_POS) : 0U); + return (filter->id << CAN_STM32_FIRX_STD_ID_POS); } static inline uint32_t can_stm32_filter_to_ext_id(const struct can_filter *filter) { return (filter->id << CAN_STM32_FIRX_EXT_EXT_ID_POS) | - (((filter->flags & CAN_FILTER_RTR) != 0) ? - (1U << CAN_STM32_FIRX_EXT_RTR_POS) : 0U) | (1U << CAN_STM32_FIRX_EXT_IDE_POS); } @@ -995,7 +990,7 @@ static int can_stm32_add_rx_filter(const struct device *dev, can_rx_callback_t c struct can_stm32_data *data = dev->data; int filter_id; - if ((filter->flags & ~(CAN_FILTER_IDE | CAN_FILTER_DATA | CAN_FILTER_RTR)) != 0) { + if ((filter->flags & ~(CAN_FILTER_IDE)) != 0) { LOG_ERR("unsupported CAN filter flags 0x%02x", filter->flags); return -ENOTSUP; } diff --git a/include/zephyr/drivers/can.h b/include/zephyr/drivers/can.h index 7221df1ea51..dfcb62906dd 100644 --- a/include/zephyr/drivers/can.h +++ b/include/zephyr/drivers/can.h @@ -203,11 +203,6 @@ struct can_frame { /** Filter matches frames with extended (29-bit) CAN IDs */ #define CAN_FILTER_IDE BIT(0) -/** Filter matches Remote Transmission Request (RTR) frames */ -#define CAN_FILTER_RTR BIT(1) - -/** Filter matches data frames */ -#define CAN_FILTER_DATA BIT(2) /** @} */ @@ -1259,7 +1254,7 @@ static inline int can_add_rx_filter(const struct device *dev, can_rx_callback_t { const struct can_driver_api *api = (const struct can_driver_api *)dev->api; - if (filter == NULL || (filter->flags & (CAN_FILTER_DATA | CAN_FILTER_RTR)) == 0) { + if (filter == NULL) { return -EINVAL; } @@ -1683,16 +1678,6 @@ static inline bool can_frame_matches_filter(const struct can_frame *frame, return false; } - if ((frame->flags & CAN_FRAME_RTR) == 0 && (filter->flags & CAN_FILTER_DATA) == 0) { - /* non-RTR frame, remote transmission request (RTR) filter */ - return false; - } - - if ((frame->flags & CAN_FRAME_RTR) != 0 && (filter->flags & CAN_FILTER_RTR) == 0) { - /* Remote transmission request (RTR) frame, non-RTR filter */ - return false; - } - if ((frame->id ^ filter->id) & filter->mask) { /* Masked ID mismatch */ return false; diff --git a/include/zephyr/drivers/can/can_mcan.h b/include/zephyr/drivers/can/can_mcan.h index 86d0ad6fd38..8e09d589833 100644 --- a/include/zephyr/drivers/can/can_mcan.h +++ b/include/zephyr/drivers/can/can_mcan.h @@ -1164,7 +1164,6 @@ struct can_mcan_tx_callback { struct can_mcan_rx_callback { can_rx_callback_t function; void *user_data; - uint8_t flags; }; /** diff --git a/include/zephyr/net/socketcan_utils.h b/include/zephyr/net/socketcan_utils.h index 9b00d6dadc7..7db287ff847 100644 --- a/include/zephyr/net/socketcan_utils.h +++ b/include/zephyr/net/socketcan_utils.h @@ -95,14 +95,6 @@ static inline void socketcan_to_can_filter(const struct socketcan_filter *sfilte zfilter->flags |= (sfilter->can_id & BIT(31)) != 0 ? CAN_FILTER_IDE : 0; zfilter->id = sfilter->can_id & BIT_MASK(29); zfilter->mask = sfilter->can_mask & BIT_MASK(29); - - if ((sfilter->can_mask & BIT(30)) == 0) { - zfilter->flags |= CAN_FILTER_DATA | CAN_FILTER_RTR; - } else if ((sfilter->can_id & BIT(30)) == 0) { - zfilter->flags |= CAN_FILTER_DATA; - } else { - zfilter->flags |= CAN_FILTER_RTR; - } } /** @@ -118,13 +110,11 @@ static inline void socketcan_from_can_filter(const struct can_filter *zfilter, sfilter->can_id = zfilter->id; sfilter->can_id |= (zfilter->flags & CAN_FILTER_IDE) != 0 ? BIT(31) : 0; - sfilter->can_id |= (zfilter->flags & CAN_FILTER_RTR) != 0 ? BIT(30) : 0; sfilter->can_mask = zfilter->mask; sfilter->can_mask |= (zfilter->flags & CAN_FILTER_IDE) != 0 ? BIT(31) : 0; - if ((zfilter->flags & (CAN_FILTER_DATA | CAN_FILTER_RTR)) != - (CAN_FILTER_DATA | CAN_FILTER_RTR)) { + if (!IS_ENABLED(CONFIG_CAN_ACCEPT_RTR)) { sfilter->can_mask |= BIT(30); } } diff --git a/modules/canopennode/CO_driver.c b/modules/canopennode/CO_driver.c index e8892e080f5..4d161a49400 100644 --- a/modules/canopennode/CO_driver.c +++ b/modules/canopennode/CO_driver.c @@ -96,6 +96,11 @@ static void canopen_rx_callback(const struct device *dev, struct can_frame *fram } if (((frame->id ^ buffer->ident) & buffer->mask) == 0U) { +#ifdef CONFIG_CAN_ACCEPT_RTR + if (buffer->rtr && ((frame->flags & CAN_FRAME_RTR) == 0U)) { + continue; + } +#endif /* CONFIG_CAN_ACCEPT_RTR */ rxMsg.ident = frame->id; rxMsg.DLC = frame->dlc; memcpy(rxMsg.data, frame->data, frame->dlc); @@ -310,7 +315,18 @@ CO_ReturnError_t CO_CANrxBufferInit(CO_CANmodule_t *CANmodule, uint16_t index, buffer->ident = ident; buffer->mask = mask; - filter.flags = (rtr ? CAN_FILTER_RTR : CAN_FILTER_DATA); +#ifndef CONFIG_CAN_ACCEPT_RTR + if (rtr) { + LOG_ERR("request for RTR frames, but RTR frames are rejected"); + CO_errorReport(CANmodule->em, CO_EM_GENERIC_SOFTWARE_ERROR, + CO_EMC_SOFTWARE_INTERNAL, 0); + return CO_ERROR_ILLEGAL_ARGUMENT; + } +#else /* !CONFIG_CAN_ACCEPT_RTR */ + buffer->rtr = rtr; +#endif /* CONFIG_CAN_ACCEPT_RTR */ + + filter.flags = 0U; filter.id = ident; filter.mask = mask; diff --git a/modules/canopennode/CO_driver_target.h b/modules/canopennode/CO_driver_target.h index 27b1f1caa9d..5dba56ef800 100644 --- a/modules/canopennode/CO_driver_target.h +++ b/modules/canopennode/CO_driver_target.h @@ -69,6 +69,9 @@ typedef struct canopen_rx { CO_CANrxBufferCallback_t pFunct; uint16_t ident; uint16_t mask; +#ifdef CONFIG_CAN_ACCEPT_RTR + bool rtr; +#endif /* CONFIG_CAN_ACCEPT_RTR */ } CO_CANrx_t; typedef struct canopen_tx { diff --git a/samples/drivers/can/counter/src/main.c b/samples/drivers/can/counter/src/main.c index 78048308ca2..2119069e43e 100644 --- a/samples/drivers/can/counter/src/main.c +++ b/samples/drivers/can/counter/src/main.c @@ -63,7 +63,7 @@ void rx_thread(void *arg1, void *arg2, void *arg3) ARG_UNUSED(arg2); ARG_UNUSED(arg3); const struct can_filter filter = { - .flags = CAN_FILTER_DATA | CAN_FILTER_IDE, + .flags = CAN_FILTER_IDE, .id = COUNTER_MSG_ID, .mask = CAN_EXT_ID_MASK }; @@ -76,6 +76,10 @@ void rx_thread(void *arg1, void *arg2, void *arg3) while (1) { k_msgq_get(&counter_msgq, &frame, K_FOREVER); + if (IS_ENABLED(CONFIG_CAN_ACCEPT_RTR) && (frame.flags & CAN_FRAME_RTR) != 0U) { + continue; + } + if (frame.dlc != 2U) { printf("Wrong data length: %u\n", frame.dlc); continue; @@ -92,6 +96,10 @@ void change_led_work_handler(struct k_work *work) int ret; while (k_msgq_get(&change_led_msgq, &frame, K_NO_WAIT) == 0) { + if (IS_ENABLED(CONFIG_CAN_ACCEPT_RTR) && (frame.flags & CAN_FRAME_RTR) != 0U) { + continue; + } + if (led.port == NULL) { printf("LED %s\n", frame.data[0] == SET_LED ? "ON" : "OFF"); } else { @@ -192,7 +200,7 @@ void state_change_callback(const struct device *dev, enum can_state state, int main(void) { const struct can_filter change_led_filter = { - .flags = CAN_FILTER_DATA, + .flags = 0U, .id = LED_MSG_ID, .mask = CAN_STD_ID_MASK }; diff --git a/samples/net/sockets/can/src/main.c b/samples/net/sockets/can/src/main.c index 506157c6afe..8bd51984a64 100644 --- a/samples/net/sockets/can/src/main.c +++ b/samples/net/sockets/can/src/main.c @@ -32,7 +32,7 @@ static struct k_thread rx_data; #define CLOSE_PERIOD 15 static const struct can_filter zfilter = { - .flags = CAN_FILTER_DATA, + .flags = 0U, .id = 0x1, .mask = CAN_STD_ID_MASK }; diff --git a/subsys/canbus/isotp/isotp.c b/subsys/canbus/isotp/isotp.c index 233cc0b2ee2..b36665a2776 100644 --- a/subsys/canbus/isotp/isotp.c +++ b/subsys/canbus/isotp/isotp.c @@ -54,7 +54,7 @@ static inline void prepare_filter(struct can_filter *filter, struct isotp_msg_id { filter->id = addr->ext_id; filter->mask = mask; - filter->flags = CAN_FILTER_DATA | ((addr->flags & ISOTP_MSG_IDE) != 0 ? CAN_FILTER_IDE : 0); + filter->flags = (addr->flags & ISOTP_MSG_IDE) != 0 ? CAN_FILTER_IDE : 0; } /* @@ -557,6 +557,10 @@ static void receive_can_rx(const struct device *dev, struct can_frame *frame, vo ARG_UNUSED(dev); + if (IS_ENABLED(CONFIG_CAN_ACCEPT_RTR) && (frame->flags & CAN_FRAME_RTR) != 0U) { + return; + } + switch (rctx->state) { case ISOTP_RX_STATE_WAIT_FF_SF: __ASSERT_NO_MSG(rctx->buf); @@ -847,6 +851,10 @@ static void send_can_rx_cb(const struct device *dev, struct can_frame *frame, vo ARG_UNUSED(dev); + if (IS_ENABLED(CONFIG_CAN_ACCEPT_RTR) && (frame->flags & CAN_FRAME_RTR) != 0U) { + return; + } + if (sctx->state == ISOTP_TX_WAIT_FC) { k_timer_stop(&sctx->timer); send_process_fc(sctx, frame); diff --git a/tests/drivers/can/api/src/classic.c b/tests/drivers/can/api/src/classic.c index 34a9b42dc1d..3259f300b26 100644 --- a/tests/drivers/can/api/src/classic.c +++ b/tests/drivers/can/api/src/classic.c @@ -314,6 +314,8 @@ static void send_receive(const struct can_filter *filter1, int err; filter_id_1 = add_rx_msgq(can_dev, filter1); + zassert_not_equal(filter_id_1, -ENOSPC, "no filters available"); + zassert_true(filter_id_1 >= 0, "negative filter number"); send_test_frame(can_dev, frame1); err = k_msgq_get(&can_msgq, &frame_buffer, TEST_RECEIVE_TIMEOUT); @@ -360,6 +362,12 @@ static void send_receive(const struct can_filter *filter1, } } + zassert_not_equal(filter_id_1, -ENOSPC, "no filters available"); + zassert_true(filter_id_1 >= 0, "negative filter number"); + + zassert_not_equal(filter_id_2, -ENOSPC, "no filters available"); + zassert_true(filter_id_2 >= 0, "negative filter number"); + err = k_sem_take(&rx_callback_sem, TEST_RECEIVE_TIMEOUT); zassert_equal(err, 0, "receive timeout"); @@ -385,8 +393,7 @@ static void send_receive(const struct can_filter *filter1, * @param data_frame CAN data frame * @param rtr_frame CAN RTR frame */ -void send_receive_rtr(const struct can_filter *data_filter, - const struct can_filter *rtr_filter, +void send_receive_rtr(const struct can_filter *filter, const struct can_frame *data_frame, const struct can_frame *rtr_frame) { @@ -394,36 +401,24 @@ void send_receive_rtr(const struct can_filter *data_filter, int filter_id; int err; - filter_id = can_add_rx_filter_msgq(can_dev, &can_msgq, rtr_filter); - if (filter_id == -ENOTSUP) { - /* Not all CAN controller drivers support remote transmission requests */ - ztest_test_skip(); - } - + filter_id = can_add_rx_filter_msgq(can_dev, &can_msgq, filter); zassert_not_equal(filter_id, -ENOSPC, "no filters available"); zassert_true(filter_id >= 0, "negative filter number"); - /* Verify that RTR filter does not match data frame */ - send_test_frame(can_dev, data_frame); - err = k_msgq_get(&can_msgq, &frame, TEST_RECEIVE_TIMEOUT); - zassert_equal(err, -EAGAIN, "Data frame passed RTR filter"); + /* Verify that filter matches RTR frame */ + err = can_send(can_dev, rtr_frame, TEST_SEND_TIMEOUT, NULL, NULL); + if (err == -ENOTSUP) { + /* Not all drivers support transmission of RTR frames */ + can_remove_rx_filter(can_dev, filter_id); + ztest_test_skip(); + } + zassert_equal(err, 0, "failed to send RTR frame (err %d)", err); - /* Verify that RTR filter matches RTR frame */ - send_test_frame(can_dev, rtr_frame); err = k_msgq_get(&can_msgq, &frame, TEST_RECEIVE_TIMEOUT); zassert_equal(err, 0, "receive timeout"); assert_frame_equal(&frame, rtr_frame, 0); - can_remove_rx_filter(can_dev, filter_id); - - filter_id = add_rx_msgq(can_dev, data_filter); - - /* Verify that data filter does not match RTR frame */ - send_test_frame(can_dev, rtr_frame); - err = k_msgq_get(&can_msgq, &frame, TEST_RECEIVE_TIMEOUT); - zassert_equal(err, -EAGAIN, "RTR frame passed data filter"); - - /* Verify that data filter matches data frame */ + /* Verify that filter matches data frame */ send_test_frame(can_dev, data_frame); err = k_msgq_get(&can_msgq, &frame, TEST_RECEIVE_TIMEOUT); zassert_equal(err, 0, "receive timeout"); @@ -573,7 +568,7 @@ static void add_remove_max_filters(bool ide) { uint32_t id_mask = ide ? CAN_EXT_ID_MASK : CAN_STD_ID_MASK; struct can_filter filter = { - .flags = CAN_FILTER_DATA | (ide ? CAN_FILTER_IDE : 0), + .flags = (ide ? CAN_FILTER_IDE : 0), .id = 0, .mask = id_mask, }; @@ -737,8 +732,9 @@ ZTEST_USER(can_classic, test_send_receive_msgq) */ ZTEST_USER(can_classic, test_send_receive_std_id_rtr) { - send_receive_rtr(&test_std_filter_1, &test_std_rtr_filter_1, - &test_std_frame_1, &test_std_rtr_frame_1); + Z_TEST_SKIP_IFNDEF(CONFIG_CAN_ACCEPT_RTR); + + send_receive_rtr(&test_std_filter_1, &test_std_frame_1, &test_std_rtr_frame_1); } /** @@ -746,8 +742,63 @@ ZTEST_USER(can_classic, test_send_receive_std_id_rtr) */ ZTEST_USER(can_classic, test_send_receive_ext_id_rtr) { - send_receive_rtr(&test_ext_filter_1, &test_ext_rtr_filter_1, - &test_ext_frame_1, &test_ext_rtr_frame_1); + Z_TEST_SKIP_IFNDEF(CONFIG_CAN_ACCEPT_RTR); + + send_receive_rtr(&test_ext_filter_1, &test_ext_frame_1, &test_ext_rtr_frame_1); +} + +/** + * @brief Test rejection of standard (11-bit) CAN IDs and remote transmission request (RTR). + */ +ZTEST_USER(can_classic, test_reject_std_id_rtr) +{ + struct can_frame frame_buffer; + int filter_id; + int err; + + Z_TEST_SKIP_IFDEF(CONFIG_CAN_ACCEPT_RTR); + + filter_id = add_rx_msgq(can_dev, &test_std_filter_1); + + err = can_send(can_dev, &test_std_rtr_frame_1, TEST_SEND_TIMEOUT, NULL, NULL); + if (err == -ENOTSUP) { + /* Not all drivers support transmission of RTR frames */ + can_remove_rx_filter(can_dev, filter_id); + ztest_test_skip(); + } + zassert_equal(err, 0, "failed to send RTR frame (err %d)", err); + + err = k_msgq_get(&can_msgq, &frame_buffer, TEST_RECEIVE_TIMEOUT); + zassert_equal(err, -EAGAIN, "received a frame that should be rejected"); + + can_remove_rx_filter(can_dev, filter_id); +} + +/** + * @brief Test rejection of extended (29-bit) CAN IDs and remote transmission request (RTR). + */ +ZTEST_USER(can_classic, test_reject_ext_id_rtr) +{ + struct can_frame frame_buffer; + int filter_id; + int err; + + Z_TEST_SKIP_IFDEF(CONFIG_CAN_ACCEPT_RTR); + + filter_id = add_rx_msgq(can_dev, &test_ext_filter_1); + + err = can_send(can_dev, &test_ext_rtr_frame_1, TEST_SEND_TIMEOUT, NULL, NULL); + if (err == -ENOTSUP) { + /* Not all drivers support transmission of RTR frames */ + can_remove_rx_filter(can_dev, filter_id); + ztest_test_skip(); + } + zassert_equal(err, 0, "failed to send RTR frame (err %d)", err); + + err = k_msgq_get(&can_msgq, &frame_buffer, TEST_RECEIVE_TIMEOUT); + zassert_equal(err, -EAGAIN, "received a frame that should be rejected"); + + can_remove_rx_filter(can_dev, filter_id); } /** @@ -764,7 +815,7 @@ ZTEST(can_classic, test_send_receive_wrong_id) send_test_frame(can_dev, &test_std_frame_2); err = k_msgq_get(&can_msgq, &frame_buffer, TEST_RECEIVE_TIMEOUT); - zassert_equal(err, -EAGAIN, "recevied a frame that should not pass the filter"); + zassert_equal(err, -EAGAIN, "received a frame that should not pass the filter"); can_remove_rx_filter(can_dev, filter_id); } diff --git a/tests/drivers/can/api/src/common.c b/tests/drivers/can/api/src/common.c index 759733d3e8d..b38090690a3 100644 --- a/tests/drivers/can/api/src/common.c +++ b/tests/drivers/can/api/src/common.c @@ -74,7 +74,7 @@ const struct can_frame test_std_rtr_frame_1 = { * @brief Extended (29-bit) CAN ID RTR frame 1. */ const struct can_frame test_ext_rtr_frame_1 = { - .flags = CAN_FRAME_IDE | CAN_FILTER_RTR, + .flags = CAN_FRAME_IDE | CAN_FRAME_RTR, .id = TEST_CAN_EXT_ID_1, .dlc = 0, .data = {0} @@ -113,7 +113,7 @@ const struct can_frame test_std_fdf_frame_2 = { * ``test_std_frame_1``. */ const struct can_filter test_std_filter_1 = { - .flags = CAN_FILTER_DATA, + .flags = 0U, .id = TEST_CAN_STD_ID_1, .mask = CAN_STD_ID_MASK }; @@ -123,7 +123,7 @@ const struct can_filter test_std_filter_1 = { * ``test_std_frame_2``. */ const struct can_filter test_std_filter_2 = { - .flags = CAN_FILTER_DATA, + .flags = 0U, .id = TEST_CAN_STD_ID_2, .mask = CAN_STD_ID_MASK }; @@ -133,7 +133,7 @@ const struct can_filter test_std_filter_2 = { * ``test_std_frame_1``. */ const struct can_filter test_std_masked_filter_1 = { - .flags = CAN_FILTER_DATA, + .flags = 0U, .id = TEST_CAN_STD_MASK_ID_1, .mask = TEST_CAN_STD_MASK }; @@ -143,7 +143,7 @@ const struct can_filter test_std_masked_filter_1 = { * ``test_std_frame_2``. */ const struct can_filter test_std_masked_filter_2 = { - .flags = CAN_FILTER_DATA, + .flags = 0U, .id = TEST_CAN_STD_MASK_ID_2, .mask = TEST_CAN_STD_MASK }; @@ -153,7 +153,7 @@ const struct can_filter test_std_masked_filter_2 = { * ``test_ext_frame_1``. */ const struct can_filter test_ext_filter_1 = { - .flags = CAN_FILTER_DATA | CAN_FILTER_IDE, + .flags = CAN_FILTER_IDE, .id = TEST_CAN_EXT_ID_1, .mask = CAN_EXT_ID_MASK }; @@ -163,7 +163,7 @@ const struct can_filter test_ext_filter_1 = { * ``test_ext_frame_2``. */ const struct can_filter test_ext_filter_2 = { - .flags = CAN_FILTER_DATA | CAN_FILTER_IDE, + .flags = CAN_FILTER_IDE, .id = TEST_CAN_EXT_ID_2, .mask = CAN_EXT_ID_MASK }; @@ -173,7 +173,7 @@ const struct can_filter test_ext_filter_2 = { * ``test_ext_frame_1``. */ const struct can_filter test_ext_masked_filter_1 = { - .flags = CAN_FILTER_DATA | CAN_FILTER_IDE, + .flags = CAN_FILTER_IDE, .id = TEST_CAN_EXT_MASK_ID_1, .mask = TEST_CAN_EXT_MASK }; @@ -183,37 +183,17 @@ const struct can_filter test_ext_masked_filter_1 = { * ``test_ext_frame_2``. */ const struct can_filter test_ext_masked_filter_2 = { - .flags = CAN_FILTER_DATA | CAN_FILTER_IDE, + .flags = CAN_FILTER_IDE, .id = TEST_CAN_EXT_MASK_ID_2, .mask = TEST_CAN_EXT_MASK }; -/** - * @brief Standard (11-bit) CAN ID RTR filter 1. This filter matches - * ``test_std_rtr_frame_1``. - */ -const struct can_filter test_std_rtr_filter_1 = { - .flags = CAN_FILTER_RTR, - .id = TEST_CAN_STD_ID_1, - .mask = CAN_STD_ID_MASK -}; - -/** - * @brief Extended (29-bit) CAN ID RTR filter 1. This filter matches - * ``test_ext_rtr_frame_1``. - */ -const struct can_filter test_ext_rtr_filter_1 = { - .flags = CAN_FILTER_RTR | CAN_FILTER_IDE, - .id = TEST_CAN_EXT_ID_1, - .mask = CAN_EXT_ID_MASK -}; - /** * @brief Standard (11-bit) CAN ID filter. This filter matches * ``TEST_CAN_SOME_STD_ID``. */ const struct can_filter test_std_some_filter = { - .flags = CAN_FILTER_DATA, + .flags = 0U, .id = TEST_CAN_SOME_STD_ID, .mask = CAN_STD_ID_MASK }; diff --git a/tests/drivers/can/api/src/common.h b/tests/drivers/can/api/src/common.h index 374141a71fb..af192f574c5 100644 --- a/tests/drivers/can/api/src/common.h +++ b/tests/drivers/can/api/src/common.h @@ -144,18 +144,6 @@ extern const struct can_filter test_ext_masked_filter_1; */ extern const struct can_filter test_ext_masked_filter_2; -/** - * @brief Standard (11-bit) CAN ID RTR filter 1. This filter matches - * ``test_std_rtr_frame_1``. - */ -extern const struct can_filter test_std_rtr_filter_1; - -/** - * @brief Extended (29-bit) CAN ID RTR filter 1. This filter matches - * ``test_ext_rtr_frame_1``. - */ -extern const struct can_filter test_ext_rtr_filter_1; - /** * @brief Standard (11-bit) CAN ID filter. This filter matches * ``TEST_CAN_SOME_STD_ID``. diff --git a/tests/drivers/can/api/src/utilities.c b/tests/drivers/can/api/src/utilities.c index c2e037bcbc9..5fd251f5968 100644 --- a/tests/drivers/can/api/src/utilities.c +++ b/tests/drivers/can/api/src/utilities.c @@ -67,7 +67,7 @@ ZTEST(can_utilities, test_can_bytes_to_dlc) ZTEST(can_utilities, test_can_frame_matches_filter) { const struct can_filter test_ext_filter_std_id_1 = { - .flags = CAN_FILTER_DATA | CAN_FILTER_IDE, + .flags = CAN_FILTER_IDE, .id = TEST_CAN_STD_ID_1, .mask = CAN_EXT_ID_MASK }; @@ -105,19 +105,9 @@ ZTEST(can_utilities, test_can_frame_matches_filter) zassert_false(can_frame_matches_filter(&test_ext_frame_1, &test_std_masked_filter_1)); zassert_false(can_frame_matches_filter(&test_ext_frame_2, &test_std_masked_filter_2)); - /* Remote transmission request (RTR) frames and filters */ - zassert_true(can_frame_matches_filter(&test_std_rtr_frame_1, &test_std_rtr_filter_1)); - zassert_true(can_frame_matches_filter(&test_ext_rtr_frame_1, &test_ext_rtr_filter_1)); - zassert_false(can_frame_matches_filter(&test_std_rtr_frame_1, &test_ext_rtr_filter_1)); - zassert_false(can_frame_matches_filter(&test_ext_rtr_frame_1, &test_std_rtr_filter_1)); - - /* Remote transmission request (RTR) frames and non-RTR filters */ - zassert_false(can_frame_matches_filter(&test_std_rtr_frame_1, &test_std_filter_1)); - zassert_false(can_frame_matches_filter(&test_ext_rtr_frame_1, &test_ext_filter_1)); - - /* Non-RTR frames and Remote transmission request (RTR) filters */ - zassert_false(can_frame_matches_filter(&test_std_frame_1, &test_std_rtr_filter_1)); - zassert_false(can_frame_matches_filter(&test_ext_frame_1, &test_ext_rtr_filter_1)); + /* Remote transmission request (RTR) frames */ + zassert_true(can_frame_matches_filter(&test_std_rtr_frame_1, &test_std_filter_1)); + zassert_true(can_frame_matches_filter(&test_ext_rtr_frame_1, &test_ext_filter_1)); /* CAN FD format frames and filters */ zassert_true(can_frame_matches_filter(&test_std_fdf_frame_1, &test_std_filter_1)); diff --git a/tests/drivers/can/api/testcase.yaml b/tests/drivers/can/api/testcase.yaml index f24a25c15a3..11c72526a89 100644 --- a/tests/drivers/can/api/testcase.yaml +++ b/tests/drivers/can/api/testcase.yaml @@ -1,14 +1,16 @@ +common: + tags: + - drivers + - can + depends_on: can tests: drivers.can.api: - tags: - - drivers - - can - depends_on: can filter: dt_chosen_enabled("zephyr,canbus") and not dt_compat_enabled("kvaser,pcican") + drivers.can.api.rtr: + filter: dt_chosen_enabled("zephyr,canbus") and not dt_compat_enabled("kvaser,pcican") + extra_configs: + - CONFIG_CAN_ACCEPT_RTR=y drivers.can.api.twai: - tags: - - drivers - - can extra_args: DTC_OVERLAY_FILE=twai-enable.overlay filter: dt_compat_enabled("espressif,esp32-twai") platform_allow: diff --git a/tests/drivers/can/shell/src/main.c b/tests/drivers/can/shell/src/main.c index 61bd80ec72f..35681839bd2 100644 --- a/tests/drivers/can/shell/src/main.c +++ b/tests/drivers/can/shell/src/main.c @@ -487,7 +487,7 @@ static void can_shell_test_filter_add(const char *cmd, const struct can_filter * ZTEST(can_shell, test_can_filter_add_std_id) { struct can_filter expected = { - .flags = CAN_FILTER_DATA, + .flags = 0U, .id = 0x010, .mask = CAN_STD_ID_MASK, }; @@ -498,7 +498,7 @@ ZTEST(can_shell, test_can_filter_add_std_id) ZTEST(can_shell, test_can_filter_add_std_id_mask) { struct can_filter expected = { - .flags = CAN_FILTER_DATA, + .flags = 0U, .id = 0x010, .mask = 0x020, }; @@ -509,7 +509,7 @@ ZTEST(can_shell, test_can_filter_add_std_id_mask) ZTEST(can_shell, test_can_filter_add_ext_id) { struct can_filter expected = { - .flags = CAN_FILTER_DATA | CAN_FILTER_IDE, + .flags = CAN_FILTER_IDE, .id = 0x1024, .mask = CAN_EXT_ID_MASK, }; @@ -520,7 +520,7 @@ ZTEST(can_shell, test_can_filter_add_ext_id) ZTEST(can_shell, test_can_filter_add_ext_id_mask) { struct can_filter expected = { - .flags = CAN_FILTER_DATA | CAN_FILTER_IDE, + .flags = CAN_FILTER_IDE, .id = 0x1024, .mask = 0x2048, }; @@ -528,37 +528,15 @@ ZTEST(can_shell, test_can_filter_add_ext_id_mask) can_shell_test_filter_add("can filter add " FAKE_CAN_NAME " -e 1024 2048", &expected); } -ZTEST(can_shell, test_can_filter_add_rtr) -{ - struct can_filter expected = { - .flags = CAN_FILTER_DATA | CAN_FILTER_RTR, - .id = 0x022, - .mask = CAN_STD_ID_MASK, - }; - - can_shell_test_filter_add("can filter add " FAKE_CAN_NAME " -r 022", &expected); -} - -ZTEST(can_shell, test_can_filter_add_rtr_only) -{ - struct can_filter expected = { - .flags = CAN_FILTER_RTR, - .id = 0x322, - .mask = CAN_STD_ID_MASK, - }; - - can_shell_test_filter_add("can filter add " FAKE_CAN_NAME " -R 322", &expected); -} - ZTEST(can_shell, test_can_filter_add_all_options) { struct can_filter expected = { - .flags = CAN_FILTER_RTR | CAN_FILTER_IDE, + .flags = CAN_FILTER_IDE, .id = 0x2048, .mask = 0x4096, }; - can_shell_test_filter_add("can filter add " FAKE_CAN_NAME " -e -r -R 2048 4096", &expected); + can_shell_test_filter_add("can filter add " FAKE_CAN_NAME " -e 2048 4096", &expected); } ZTEST(can_shell, test_can_filter_remove_missing_value) diff --git a/tests/net/socket/can/src/main.c b/tests/net/socket/can/src/main.c index 02d209c022e..040f03d1e30 100644 --- a/tests/net/socket/can/src/main.c +++ b/tests/net/socket/can/src/main.c @@ -101,10 +101,10 @@ ZTEST(socket_can, test_socketcan_filter_to_can_filter) struct can_filter expected = { 0 }; struct can_filter zfilter = { 0 }; - sfilter.can_id = BIT(31) | BIT(30) | 1234; - sfilter.can_mask = BIT(31) | BIT(30) | 1234; + sfilter.can_id = BIT(31) | 1234; + sfilter.can_mask = BIT(31) | 1234; - expected.flags = CAN_FILTER_IDE | CAN_FILTER_RTR; + expected.flags = CAN_FILTER_IDE; expected.id = 1234U; expected.mask = 1234U; @@ -128,10 +128,13 @@ ZTEST(socket_can, test_can_filter_to_socketcan_filter) struct socketcan_filter expected = { 0 }; struct can_filter zfilter = { 0 }; - expected.can_id = BIT(31) | BIT(30) | 1234; - expected.can_mask = BIT(31) | BIT(30) | 1234; + expected.can_id = BIT(31) | 1234; + expected.can_mask = BIT(31) | 1234; +#ifndef CONFIG_CAN_ACCEPT_RTR + expected.can_mask |= BIT(30); +#endif /* !CONFIG_CAN_ACCEPT_RTR */ - zfilter.flags = CAN_FILTER_IDE | CAN_FILTER_RTR; + zfilter.flags = CAN_FILTER_IDE; zfilter.id = 1234U; zfilter.mask = 1234U; diff --git a/tests/subsys/canbus/isotp/conformance/src/main.c b/tests/subsys/canbus/isotp/conformance/src/main.c index 926742da5dd..bd4a7b52de2 100644 --- a/tests/subsys/canbus/isotp/conformance/src/main.c +++ b/tests/subsys/canbus/isotp/conformance/src/main.c @@ -306,7 +306,7 @@ static int add_rx_msgq(uint32_t id, uint32_t mask) { int filter_id; struct can_filter filter = { - .flags = CAN_FILTER_DATA | ((id > 0x7FF) ? CAN_FILTER_IDE : 0), + .flags = (id > 0x7FF) ? CAN_FILTER_IDE : 0, .id = id, .mask = mask }; From 53da5f6f87fa54658078b4fe5868f5863e759d81 Mon Sep 17 00:00:00 2001 From: Henrik Brix Andersen Date: Tue, 2 Jan 2024 23:45:08 +0100 Subject: [PATCH 2633/3723] doc: releases: migration-guide: 3.6: removal of run-time CAN RTR filter Add a note about the removal of the CAN_FILTER_DATA and CAN_FILTER_RTR flags from the CAN controller driver API. Signed-off-by: Henrik Brix Andersen --- doc/releases/migration-guide-3.6.rst | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/doc/releases/migration-guide-3.6.rst b/doc/releases/migration-guide-3.6.rst index 53ad073a06b..990f1d0e515 100644 --- a/doc/releases/migration-guide-3.6.rst +++ b/doc/releases/migration-guide-3.6.rst @@ -179,6 +179,14 @@ Device Drivers and Device Tree controllers implement support for this. Applications can still filter on classic CAN/CAN FD frames in their receive callback functions as needed. +* The ``CAN_FILTER_DATA`` and ``CAN_FILTER_RTR`` flags for filtering between Data and Remote + Transmission Request (RTR) frames were removed since not all CAN controllers implement support for + individual RX filtering based on the RTR bit. Applications can now use + :kconfig:option:`CONFIG_CAN_ACCEPT_RTR` to either accept incoming RTR frames matching CAN filters + or reject all incoming CAN RTR frames (the default). When :kconfig:option:`CONFIG_CAN_ACCEPT_RTR` + is enabled, applications can still filter between Data and RTR frames in their receive callback + functions as needed. + * The io-channel cells of the following devicetree bindings were reduced from 2 (``positive`` and ``negative``) to the common ``input``, making it possible to use the various ADC DT macros with TI LMP90xxx ADC devices: From 04de43b1a119665532b6b2a0c6bbcbefd47eb7d6 Mon Sep 17 00:00:00 2001 From: Jakub Rzeszutko Date: Tue, 9 Jan 2024 18:35:06 +0100 Subject: [PATCH 2634/3723] shell: Fix shell init procedure when configured as inactive on startup The previous behavior of the CONFIG_SHELL_AUTOSTART option, where setting it to 'n' disabled shell interaction at startup but kept the logger active as a shell backend, was inconsistent. Now, when CONFIG_SHELL_AUTOSTART is set to 'n', both the shell and the logger are inactive at startup. Calling the shell_start function will activate them and print any pending logs. This change ensures a more consistent and logical behavior regarding shell and logger activity at startup. Additionally, now when the shell_stop function is called, both the shell and the logger are halted. This enhancement ensures that stopping the shell also effectively stops the associated logger. Signed-off-by: Jakub Rzeszutko --- include/zephyr/shell/shell.h | 4 ++++ subsys/shell/shell.c | 18 ++++++++++-------- subsys/shell/shell_ops.h | 13 +++++++++++++ 3 files changed, 27 insertions(+), 8 deletions(-) diff --git a/include/zephyr/shell/shell.h b/include/zephyr/shell/shell.h index 8382dc8290a..0bcb831c90d 100644 --- a/include/zephyr/shell/shell.h +++ b/include/zephyr/shell/shell.h @@ -743,6 +743,7 @@ struct shell_backend_ctx_flags { uint32_t cmd_ctx :1; /*!< Shell is executing command */ uint32_t print_noinit :1; /*!< Print request from not initialized shell */ uint32_t sync_mode :1; /*!< Shell in synchronous mode */ + uint32_t handle_log :1; /*!< Shell is handling logger backend */ }; BUILD_ASSERT((sizeof(struct shell_backend_ctx_flags) == sizeof(uint32_t)), @@ -798,6 +799,9 @@ struct shell_ctx { /** When bypass is set, all incoming data is passed to the callback. */ shell_bypass_cb_t bypass; + /*!< Logging level for a backend. */ + uint32_t log_level; + #if defined CONFIG_SHELL_GETOPT /*!< getopt context for a shell backend. */ struct getopt_state getopt; diff --git a/subsys/shell/shell.c b/subsys/shell/shell.c index efff35e2631..944e30ae70b 100644 --- a/subsys/shell/shell.c +++ b/subsys/shell/shell.c @@ -1315,21 +1315,16 @@ void shell_thread(void *shell_handle, void *arg_log_backend, void *arg_log_level) { struct shell *sh = shell_handle; - bool log_backend = (bool)arg_log_backend; - uint32_t log_level = POINTER_TO_UINT(arg_log_level); int err; + z_flag_handle_log_set(sh, (bool)arg_log_backend); + sh->ctx->log_level = POINTER_TO_UINT(arg_log_level); + err = sh->iface->api->enable(sh->iface, false); if (err != 0) { return; } - if (IS_ENABLED(CONFIG_SHELL_LOG_BACKEND) && log_backend - && !IS_ENABLED(CONFIG_SHELL_START_OBSCURED)) { - z_shell_log_backend_enable(sh->log_backend, (void *)sh, - log_level); - } - if (IS_ENABLED(CONFIG_SHELL_AUTOSTART)) { /* Enable shell and print prompt. */ err = shell_start(sh); @@ -1430,6 +1425,11 @@ int shell_start(const struct shell *sh) return -ENOTSUP; } + if (IS_ENABLED(CONFIG_SHELL_LOG_BACKEND) && z_flag_handle_log_get(sh) + && !z_flag_obscure_get(sh)) { + z_shell_log_backend_enable(sh->log_backend, (void *)sh, sh->ctx->log_level); + } + k_mutex_lock(&sh->ctx->wr_mtx, K_FOREVER); if (IS_ENABLED(CONFIG_SHELL_VT100_COLORS)) { @@ -1460,6 +1460,8 @@ int shell_stop(const struct shell *sh) state_set(sh, SHELL_STATE_INITIALIZED); + z_shell_log_backend_disable(sh->log_backend); + return 0; } diff --git a/subsys/shell/shell_ops.h b/subsys/shell/shell_ops.h index 59c4d8f738c..293396cc289 100644 --- a/subsys/shell/shell_ops.h +++ b/subsys/shell/shell_ops.h @@ -221,6 +221,19 @@ static inline bool z_flag_sync_mode_set(const struct shell *sh, bool val) return ret; } +static inline bool z_flag_handle_log_get(const struct shell *sh) +{ + return sh->ctx->ctx.flags.handle_log == 1; +} + +static inline bool z_flag_handle_log_set(const struct shell *sh, bool val) +{ + bool ret; + + Z_SHELL_SET_FLAG_ATOMIC(sh, ctx, handle_log, val, ret); + return ret; +} + /* Function sends VT100 command to clear the screen from cursor position to * end of the screen. */ From 20f1f44120351acddc0564405c27f239c761501a Mon Sep 17 00:00:00 2001 From: Pieter De Gendt Date: Wed, 20 Dec 2023 11:15:45 +0100 Subject: [PATCH 2635/3723] soc: arm: atmel_sam: common: Add PMC API for clock management Add functions to Atmel SAM SoC PMC API. This is an effort to hide most of the internal registers used in different SAM families. Signed-off-by: Pieter De Gendt --- soc/arm/atmel_sam/common/soc_pmc.h | 485 +++++++++++++++++++++++++++++ 1 file changed, 485 insertions(+) diff --git a/soc/arm/atmel_sam/common/soc_pmc.h b/soc/arm/atmel_sam/common/soc_pmc.h index 8f31e24dbbe..3be251a3d09 100644 --- a/soc/arm/atmel_sam/common/soc_pmc.h +++ b/soc/arm/atmel_sam/common/soc_pmc.h @@ -1,5 +1,7 @@ /* * Copyright (c) 2016 Piotr Mienkowski + * Copyright (c) 2023 Basalte bv + * * SPDX-License-Identifier: Apache-2.0 */ @@ -11,7 +13,11 @@ #ifndef _ATMEL_SAM_SOC_PMC_H_ #define _ATMEL_SAM_SOC_PMC_H_ +#include +#include +#include #include +#include /** * @brief Enable the clock of specified peripheral module. @@ -35,4 +41,483 @@ void soc_pmc_peripheral_disable(uint32_t id); */ uint32_t soc_pmc_peripheral_is_enabled(uint32_t id); +#if !defined(CONFIG_SOC_SERIES_SAM4L) + +enum soc_pmc_fast_rc_freq { +#if defined(CKGR_MOR_MOSCRCF_4_MHz) + SOC_PMC_FAST_RC_FREQ_4MHZ = CKGR_MOR_MOSCRCF_4_MHz, +#endif +#if defined(CKGR_MOR_MOSCRCF_8_MHz) + SOC_PMC_FAST_RC_FREQ_8MHZ = CKGR_MOR_MOSCRCF_8_MHz, +#endif +#if defined(CKGR_MOR_MOSCRCF_12_MHz) + SOC_PMC_FAST_RC_FREQ_12MHZ = CKGR_MOR_MOSCRCF_12_MHz, +#endif +}; + +enum soc_pmc_mck_src { +#if defined(PMC_MCKR_CSS_SLOW_CLK) + SOC_PMC_MCK_SRC_SLOW_CLK = PMC_MCKR_CSS_SLOW_CLK, +#endif +#if defined(PMC_MCKR_CSS_MAIN_CLK) + SOC_PMC_MCK_SRC_MAIN_CLK = PMC_MCKR_CSS_MAIN_CLK, +#endif +#if defined(PMC_MCKR_CSS_PLLA_CLK) + SOC_PMC_MCK_SRC_PLLA_CLK = PMC_MCKR_CSS_PLLA_CLK, +#endif +#if defined(PMC_MCKR_CSS_PLLB_CLK) + SOC_PMC_MCK_SRC_PLLB_CLK = PMC_MCKR_CSS_PLLB_CLK, +#endif +#if defined(PMC_MCKR_CSS_UPLL_CLK) + SOC_PMC_MCK_SRC_UPLL_CLK = PMC_MCKR_CSS_UPLL_CLK, +#endif +}; + +/** + * @brief Set the prescaler of the Master clock. + * + * @param prescaler the prescaler value. + */ +static ALWAYS_INLINE void soc_pmc_mck_set_prescaler(uint32_t prescaler) +{ + uint32_t reg_val; + + switch (prescaler) { + case 1: + reg_val = PMC_MCKR_PRES_CLK_1; + break; + case 2: + reg_val = PMC_MCKR_PRES_CLK_2; + break; + case 4: + reg_val = PMC_MCKR_PRES_CLK_4; + break; + case 8: + reg_val = PMC_MCKR_PRES_CLK_8; + break; + case 16: + reg_val = PMC_MCKR_PRES_CLK_16; + break; + case 32: + reg_val = PMC_MCKR_PRES_CLK_32; + break; + case 64: + reg_val = PMC_MCKR_PRES_CLK_64; + break; + case 3: + reg_val = PMC_MCKR_PRES_CLK_3; + break; + default: + __ASSERT(false, "Invalid MCK prescaler"); + reg_val = PMC_MCKR_PRES_CLK_1; + break; + } + + PMC->PMC_MCKR = (PMC->PMC_MCKR & (~PMC_MCKR_PRES_Msk)) | reg_val; + + while (!(PMC->PMC_SR & PMC_SR_MCKRDY)) { + } +} + +#if defined(CONFIG_SOC_SERIES_SAME70) || defined(CONFIG_SOC_SERIES_SAMV71) + +/** + * @brief Set the divider of the Master clock. + * + * @param divider the divider value. + */ +static ALWAYS_INLINE void soc_pmc_mck_set_divider(uint32_t divider) +{ + uint32_t reg_val; + + switch (divider) { + case 1: + reg_val = PMC_MCKR_MDIV_EQ_PCK; + break; + case 2: + reg_val = PMC_MCKR_MDIV_PCK_DIV2; + break; + case 3: + reg_val = PMC_MCKR_MDIV_PCK_DIV3; + break; + case 4: + reg_val = PMC_MCKR_MDIV_PCK_DIV4; + break; + default: + __ASSERT(false, "Invalid MCK divider"); + reg_val = PMC_MCKR_MDIV_EQ_PCK; + break; + } + + PMC->PMC_MCKR = (PMC->PMC_MCKR & (~PMC_MCKR_MDIV_Msk)) | reg_val; + + while (!(PMC->PMC_SR & PMC_SR_MCKRDY)) { + } +} + +#endif /* CONFIG_SOC_SERIES_SAME70 || CONFIG_SOC_SERIES_SAMV71 */ + +/** + * @brief Set the source of the Master clock. + * + * @param source the source identifier. + */ +static ALWAYS_INLINE void soc_pmc_mck_set_source(enum soc_pmc_mck_src source) +{ + PMC->PMC_MCKR = (PMC->PMC_MCKR & (~PMC_MCKR_CSS_Msk)) | (uint32_t)source; + + while (!(PMC->PMC_SR & PMC_SR_MCKRDY)) { + } +} + +/** + * @brief Switch main clock source selection to internal fast RC. + * + * @param freq the internal fast RC desired frequency 4/8/12MHz. + */ +static ALWAYS_INLINE void soc_pmc_switch_mainck_to_fastrc(enum soc_pmc_fast_rc_freq freq) +{ + /* Enable Fast RC oscillator but DO NOT switch to RC now */ + PMC->CKGR_MOR |= CKGR_MOR_KEY_PASSWD | CKGR_MOR_MOSCRCEN; + + /* Wait for the Fast RC to stabilize */ + while (!(PMC->PMC_SR & PMC_SR_MOSCRCS)) { + } + + /* Change Fast RC oscillator frequency */ + PMC->CKGR_MOR = (PMC->CKGR_MOR & ~CKGR_MOR_MOSCRCF_Msk) + | CKGR_MOR_KEY_PASSWD + | (uint32_t)freq; + + /* Wait for the Fast RC to stabilize */ + while (!(PMC->PMC_SR & PMC_SR_MOSCRCS)) { + } + + /* Switch to Fast RC */ + PMC->CKGR_MOR = (PMC->CKGR_MOR & ~CKGR_MOR_MOSCSEL) + | CKGR_MOR_KEY_PASSWD; +} + +/** + * @brief Enable internal fast RC oscillator. + * + * @param freq the internal fast RC desired frequency 4/8/12MHz. + */ +static ALWAYS_INLINE void soc_pmc_osc_enable_fastrc(enum soc_pmc_fast_rc_freq freq) +{ + /* Enable Fast RC oscillator but DO NOT switch to RC */ + PMC->CKGR_MOR |= CKGR_MOR_KEY_PASSWD | CKGR_MOR_MOSCRCEN; + + /* Wait for the Fast RC to stabilize */ + while (!(PMC->PMC_SR & PMC_SR_MOSCRCS)) { + } + + /* Change Fast RC oscillator frequency */ + PMC->CKGR_MOR = (PMC->CKGR_MOR & ~CKGR_MOR_MOSCRCF_Msk) + | CKGR_MOR_KEY_PASSWD + | (uint32_t)freq; + + /* Wait for the Fast RC to stabilize */ + while (!(PMC->PMC_SR & PMC_SR_MOSCRCS)) { + } +} + +/** + * @brief Disable internal fast RC oscillator. + */ +static ALWAYS_INLINE void soc_pmc_osc_disable_fastrc(void) +{ + /* Disable Fast RC oscillator */ + PMC->CKGR_MOR = (PMC->CKGR_MOR & ~CKGR_MOR_MOSCRCEN & ~CKGR_MOR_MOSCRCF_Msk) + | CKGR_MOR_KEY_PASSWD; +} + +/** + * @brief Check if the internal fast RC is ready. + * + * @return true if internal fast RC is ready, false otherwise + */ +static ALWAYS_INLINE bool soc_pmc_osc_is_ready_fastrc(void) +{ + return (PMC->PMC_SR & PMC_SR_MOSCRCS); +} + +/** + * @brief Enable the external crystal oscillator. + * + * @param xtal_startup_time crystal start-up time, in number of slow clocks. + */ +static ALWAYS_INLINE void soc_pmc_osc_enable_main_xtal(uint32_t xtal_startup_time) +{ + uint32_t mor = PMC->CKGR_MOR; + + mor &= ~(CKGR_MOR_MOSCXTBY | CKGR_MOR_MOSCXTEN); + mor |= CKGR_MOR_KEY_PASSWD | CKGR_MOR_MOSCXTEN | CKGR_MOR_MOSCXTST(xtal_startup_time); + + PMC->CKGR_MOR = mor; + + /* Wait the main Xtal to stabilize */ + while (!(PMC->PMC_SR & PMC_SR_MOSCXTS)) { + } +} + +/** + * @brief Bypass the external crystal oscillator. + */ +static ALWAYS_INLINE void soc_pmc_osc_bypass_main_xtal(void) +{ + uint32_t mor = PMC->CKGR_MOR; + + mor &= ~(CKGR_MOR_MOSCXTBY | CKGR_MOR_MOSCXTEN); + mor |= CKGR_MOR_KEY_PASSWD | CKGR_MOR_MOSCXTBY; + + /* Enable Crystal oscillator but DO NOT switch now. Keep MOSCSEL to 0 */ + PMC->CKGR_MOR = mor; + /* The MOSCXTS in PMC_SR is automatically set */ +} + +/** + * @brief Disable the external crystal oscillator. + */ +static ALWAYS_INLINE void soc_pmc_osc_disable_main_xtal(void) +{ + uint32_t mor = PMC->CKGR_MOR; + + mor &= ~(CKGR_MOR_MOSCXTBY | CKGR_MOR_MOSCXTEN); + + PMC->CKGR_MOR = CKGR_MOR_KEY_PASSWD | mor; +} + +/** + * @brief Check if the external crystal oscillator is bypassed. + * + * @return true if external crystal oscillator is bypassed, false otherwise + */ +static ALWAYS_INLINE bool soc_pmc_osc_is_bypassed_main_xtal(void) +{ + return (PMC->CKGR_MOR & CKGR_MOR_MOSCXTBY); +} + +/** + * @brief Check if the external crystal oscillator is ready. + * + * @return true if external crystal oscillator is ready, false otherwise + */ +static ALWAYS_INLINE bool soc_pmc_osc_is_ready_main_xtal(void) +{ + return (PMC->PMC_SR & PMC_SR_MOSCXTS); +} + +/** + * @brief Switch main clock source selection to external crystal oscillator. + * + * @param bypass select bypass or xtal + * @param xtal_startup_time crystal start-up time, in number of slow clocks + */ +static ALWAYS_INLINE void soc_pmc_switch_mainck_to_xtal(bool bypass, uint32_t xtal_startup_time) +{ + soc_pmc_osc_enable_main_xtal(xtal_startup_time); + + /* Enable Main Xtal oscillator */ + if (bypass) { + PMC->CKGR_MOR = (PMC->CKGR_MOR & ~CKGR_MOR_MOSCXTEN) + | CKGR_MOR_KEY_PASSWD + | CKGR_MOR_MOSCXTBY + | CKGR_MOR_MOSCSEL; + } else { + PMC->CKGR_MOR = (PMC->CKGR_MOR & ~CKGR_MOR_MOSCXTBY) + | CKGR_MOR_KEY_PASSWD + | CKGR_MOR_MOSCXTEN + | CKGR_MOR_MOSCXTST(xtal_startup_time); + + /* Wait for the Xtal to stabilize */ + while (!(PMC->PMC_SR & PMC_SR_MOSCXTS)) { + } + + PMC->CKGR_MOR |= CKGR_MOR_KEY_PASSWD | CKGR_MOR_MOSCSEL; + } +} + +/** + * @brief Disable the external crystal oscillator. + * + * @param bypass select bypass or xtal + */ +static ALWAYS_INLINE void soc_pmc_osc_disable_xtal(bool bypass) +{ + /* Disable xtal oscillator */ + if (bypass) { + PMC->CKGR_MOR = (PMC->CKGR_MOR & ~CKGR_MOR_MOSCXTBY) + | CKGR_MOR_KEY_PASSWD; + } else { + PMC->CKGR_MOR = (PMC->CKGR_MOR & ~CKGR_MOR_MOSCXTEN) + | CKGR_MOR_KEY_PASSWD; + } +} + +/** + * @brief Check if the main clock is ready. Depending on MOSCEL, main clock can be one + * of external crystal, bypass or internal RC. + * + * @return true if main clock is ready, false otherwise + */ +static ALWAYS_INLINE bool soc_pmc_osc_is_ready_mainck(void) +{ + return PMC->PMC_SR & PMC_SR_MOSCSELS; +} + +/** + * @brief Enable Wait Mode. + */ +static ALWAYS_INLINE void soc_pmc_enable_waitmode(void) +{ + PMC->PMC_FSMR |= PMC_FSMR_LPM; +} + +/** + * @brief Enable Clock Failure Detector. + */ +static ALWAYS_INLINE void soc_pmc_enable_clock_failure_detector(void) +{ + uint32_t mor = PMC->CKGR_MOR; + + PMC->CKGR_MOR = CKGR_MOR_KEY_PASSWD | CKGR_MOR_CFDEN | mor; +} + +/** + * @brief Disable Clock Failure Detector. + */ +static ALWAYS_INLINE void soc_pmc_disable_clock_failure_detector(void) +{ + uint32_t mor = PMC->CKGR_MOR & (~CKGR_MOR_CFDEN); + + PMC->CKGR_MOR = CKGR_MOR_KEY_PASSWD | mor; +} + +#if defined(PMC_MCKR_CSS_PLLA_CLK) + +/** + * @brief Disable the PLLA clock. + */ +static ALWAYS_INLINE void soc_pmc_disable_pllack(void) +{ + PMC->CKGR_PLLAR = CKGR_PLLAR_ONE | CKGR_PLLAR_MULA(0); +} + +/** + * @brief Enable the PLLA clock. + * + * @param mula PLLA multiplier + * @param pllacount PLLA lock counter, in number of slow clocks + * @param diva PLLA Divider + */ +static ALWAYS_INLINE void soc_pmc_enable_pllack(uint32_t mula, uint32_t pllacount, uint32_t diva) +{ + __ASSERT(diva > 0, "Invalid PLLA divider"); + + /* first disable the PLL to unlock the lock */ + soc_pmc_disable_pllack(); + + PMC->CKGR_PLLAR = CKGR_PLLAR_ONE + | CKGR_PLLAR_DIVA(diva) + | CKGR_PLLAR_PLLACOUNT(pllacount) + | CKGR_PLLAR_MULA(mula); + + while ((PMC->PMC_SR & PMC_SR_LOCKA) == 0) { + } +} + +/** + * @brief Check if the PLLA is locked. + * + * @return true if PLLA is locked, false otherwise + */ +static ALWAYS_INLINE bool soc_pmc_is_locked_pllack(void) +{ + return (PMC->PMC_SR & PMC_SR_LOCKA); +} + +#endif /* PMC_MCKR_CSS_PLLA_CLK */ + +#if defined(PMC_MCKR_CSS_PLLB_CLK) + +/** + * @brief Disable the PLLB clock. + */ +static ALWAYS_INLINE void soc_pmc_disable_pllbck(void) +{ + PMC->CKGR_PLLBR = CKGR_PLLBR_MULB(0); +} + +/** + * @brief Enable the PLLB clock. + * + * @param mulb PLLB multiplier + * @param pllbcount PLLB lock counter, in number of slow clocks + * @param divb PLLB Divider + */ +static ALWAYS_INLINE void soc_pmc_enable_pllbck(uint32_t mulb, uint32_t pllbcount, uint32_t divb) +{ + __ASSERT(divb > 0, "Invalid PLLB divider"); + + /* first disable the PLL to unlock the lock */ + soc_pmc_disable_pllbck(); + + PMC->CKGR_PLLBR = CKGR_PLLBR_DIVB(divb) + | CKGR_PLLBR_PLLBCOUNT(pllbcount) + | CKGR_PLLBR_MULB(mulb); + + while ((PMC->PMC_SR & PMC_SR_LOCKB) == 0) { + } +} + +/** + * @brief Check if the PLLB is locked. + * + * @return true if PLLB is locked, false otherwise + */ +static ALWAYS_INLINE bool soc_pmc_is_locked_pllbck(void) +{ + return (PMC->PMC_SR & PMC_SR_LOCKB); +} + +#endif /* PMC_MCKR_CSS_PLLB_CLK */ + +#if defined(PMC_MCKR_CSS_UPLL_CLK) + +/** + * @brief Enable the UPLL clock. + */ +static ALWAYS_INLINE void soc_pmc_enable_upllck(uint32_t upllcount) +{ + PMC->CKGR_UCKR = CKGR_UCKR_UPLLCOUNT(upllcount) + | CKGR_UCKR_UPLLEN; + + /* Wait UTMI PLL Lock Status */ + while (!(PMC->PMC_SR & PMC_SR_LOCKU)) { + } +} + +/** + * @brief Disable the UPLL clock. + */ +static ALWAYS_INLINE void soc_pmc_disable_upllck(void) +{ + PMC->CKGR_UCKR &= ~CKGR_UCKR_UPLLEN; +} + +/** + * @brief Check if the UPLL is locked. + * + * @return true if UPLL is locked, false otherwise + */ +static ALWAYS_INLINE bool soc_pmc_is_locked_upllck(void) +{ + return (PMC->PMC_SR & PMC_SR_LOCKU); +} + +#endif /* PMC_MCKR_CSS_UPLL_CLK */ + +#endif /* !CONFIG_SOC_SERIES_SAM4L */ + #endif /* _ATMEL_SAM_SOC_PMC_H_ */ From a69d611de84dda0d60d5d12daf05fd24218d7cb7 Mon Sep 17 00:00:00 2001 From: Pieter De Gendt Date: Wed, 20 Dec 2023 11:17:48 +0100 Subject: [PATCH 2636/3723] soc: arm: atmel_sam: sam4s: Rework clock_init Update clock_init for the Atmel SAM4S SoC using the new PMC API. Signed-off-by: Pieter De Gendt --- soc/arm/atmel_sam/sam4s/soc.c | 188 +++++++++------------------------- 1 file changed, 51 insertions(+), 137 deletions(-) diff --git a/soc/arm/atmel_sam/sam4s/soc.c b/soc/arm/atmel_sam/sam4s/soc.c index e1041f8a2fc..5efaa35e894 100644 --- a/soc/arm/atmel_sam/sam4s/soc.c +++ b/soc/arm/atmel_sam/sam4s/soc.c @@ -3,6 +3,7 @@ * Copyright (c) 2016 Intel Corporation. * Copyright (c) 2017 Justin Watson * Copyright (c) 2023 Gerson Fernando Budke + * Copyright (c) 2023 Basalte bv * * SPDX-License-Identifier: Apache-2.0 */ @@ -15,9 +16,9 @@ * for the Atmel SAM4S series processor. */ -#include -#include #include +#include +#include /** * @brief Setup various clock on SoC at boot time. @@ -29,168 +30,81 @@ */ static ALWAYS_INLINE void clock_init(void) { - uint32_t reg_val; + /* Switch the main clock to the internal OSC with 12MHz */ + soc_pmc_switch_mainck_to_fastrc(SOC_PMC_FAST_RC_FREQ_12MHZ); -#ifdef CONFIG_SOC_ATMEL_SAM4S_EXT_SLCK - /* Switch slow clock to the external 32 KHz crystal oscillator. */ - SUPC->SUPC_CR = SUPC_CR_KEY_PASSWD | SUPC_CR_XTALSEL_CRYSTAL_SEL; + /* Switch MCK (Master Clock) to the main clock */ + soc_pmc_mck_set_source(SOC_PMC_MCK_SRC_MAIN_CLK); - /* Wait for oscillator to be stabilized. */ - while (!(SUPC->SUPC_SR & SUPC_SR_OSCSEL)) { - ; - } - -#endif /* CONFIG_SOC_ATMEL_SAM4S_EXT_SLCK */ - -#ifdef CONFIG_SOC_ATMEL_SAM4S_EXT_MAINCK - /* - * Setup main external crystal oscillator. - */ + EFC0->EEFC_FMR = EEFC_FMR_FWS(0); +#if defined(ID_EFC1) + EFC1->EEFC_FMR = EEFC_FMR_FWS(0); +#endif - /* Start the external crystal oscillator. */ - PMC->CKGR_MOR = CKGR_MOR_KEY_PASSWD - /* Fast RC oscillator frequency is at 4 MHz. */ - | CKGR_MOR_MOSCRCF_4_MHz - /* - * We select maximum setup time. While start up time - * could be shortened this optimization is not deemed - * critical right now. - */ - | CKGR_MOR_MOSCXTST(0xFFu) - /* RC oscillator must stay on. */ - | CKGR_MOR_MOSCRCEN - | CKGR_MOR_MOSCXTEN; - - /* Wait for oscillator to be stabilized. */ - while (!(PMC->PMC_SR & PMC_SR_MOSCXTS)) { - ; - } + soc_pmc_enable_clock_failure_detector(); - /* Select the external crystal oscillator as the main clock source. */ - PMC->CKGR_MOR = CKGR_MOR_KEY_PASSWD - | CKGR_MOR_MOSCRCF_4_MHz - | CKGR_MOR_MOSCRCEN - | CKGR_MOR_MOSCXTEN - | CKGR_MOR_MOSCXTST(0xFFu) - | CKGR_MOR_MOSCSEL; - - /* Wait for external oscillator to be selected. */ - while (!(PMC->PMC_SR & PMC_SR_MOSCSELS)) { - ; + if (IS_ENABLED(CONFIG_SOC_ATMEL_SAM4S_EXT_SLCK)) { + soc_supc_slow_clock_select_crystal_osc(); } - /* Turn off RC oscillator, not used any longer, to save power */ - PMC->CKGR_MOR = CKGR_MOR_KEY_PASSWD - | CKGR_MOR_MOSCSEL - | CKGR_MOR_MOSCXTST(0xFFu) - | CKGR_MOR_MOSCXTEN; - - /* Wait for the RC oscillator to be turned off. */ - while (PMC->PMC_SR & PMC_SR_MOSCRCS) { - ; + if (IS_ENABLED(CONFIG_SOC_ATMEL_SAM4S_EXT_MAINCK)) { + /* + * Setup main external crystal oscillator. + */ + + /* We select maximum setup time. + * While start up time could be shortened + * this optimization is not deemed + * critical now. + */ + soc_pmc_switch_mainck_to_xtal(false, 0xff); } -#ifdef CONFIG_SOC_ATMEL_SAM4S_WAIT_MODE /* - * Instruct CPU to enter Wait mode instead of Sleep mode to - * keep Processor Clock (HCLK) and thus be able to debug - * CPU using JTAG. + * Set FWS (Flash Wait State) value before increasing Master Clock + * (MCK) frequency. Look at table 44.73 in the SAM4S datasheet. + * This is set to the highest number of read cycles because it won't + * hurt lower clock frequencies. However, a high frequency with too + * few read cycles could cause flash read problems. FWS 5 (6 cycles) + * is the safe setting for all of this SoCs usable frequencies. */ - PMC->PMC_FSMR |= PMC_FSMR_LPM; + EFC0->EEFC_FMR = EEFC_FMR_FWS(5); +#if defined(ID_EFC1) + EFC1->EEFC_FMR = EEFC_FMR_FWS(5); #endif -#else - /* Setup main fast RC oscillator. */ - - /* - * NOTE: MOSCRCF must be changed only if MOSCRCS is set in the PMC_SR - * register, should normally be the case. - */ - while (!(PMC->PMC_SR & PMC_SR_MOSCRCS)) { - ; - } - - /* Set main fast RC oscillator to 12 MHz. */ - PMC->CKGR_MOR = CKGR_MOR_KEY_PASSWD - | CKGR_MOR_MOSCRCF_12_MHz - | CKGR_MOR_MOSCRCEN; - - /* Wait for RC oscillator to stabilize. */ - while (!(PMC->PMC_SR & PMC_SR_MOSCRCS)) { - ; - } -#endif /* CONFIG_SOC_ATMEL_SAM4S_EXT_MAINCK */ /* * Setup PLLA */ - - /* Switch MCK (Master Clock) to the main clock first. */ - reg_val = PMC->PMC_MCKR & ~PMC_MCKR_CSS_Msk; - PMC->PMC_MCKR = reg_val | PMC_MCKR_CSS_MAIN_CLK; - - /* Wait for clock selection to complete. */ - while (!(PMC->PMC_SR & PMC_SR_MCKRDY)) { - ; - } - - /* Setup PLLA. */ - PMC->CKGR_PLLAR = CKGR_PLLAR_ONE - | CKGR_PLLAR_MULA(CONFIG_SOC_ATMEL_SAM4S_PLLA_MULA) - | CKGR_PLLAR_PLLACOUNT(0x3Fu) - | CKGR_PLLAR_DIVA(CONFIG_SOC_ATMEL_SAM4S_PLLA_DIVA); - - /* - * NOTE: Both MULA and DIVA must be set to a value greater than 0 or - * otherwise PLL will be disabled. In this case we would get stuck in - * the following loop. - */ - - /* Wait for PLL lock. */ - while (!(PMC->PMC_SR & PMC_SR_LOCKA)) { - ; - } + soc_pmc_enable_pllack(CONFIG_SOC_ATMEL_SAM4S_PLLA_MULA, 0x3Fu, + CONFIG_SOC_ATMEL_SAM4S_PLLA_DIVA); /* * Final setup of the Master Clock */ - /* - * NOTE: PMC_MCKR must not be programmed in a single write operation. - * If CSS or PRES are modified we must wait for MCKRDY bit to be - * set again. - */ + /* prescaler has to be set before PLL lock */ + soc_pmc_mck_set_prescaler(1); - /* Setup prescaler - PLLA Clock / Processor Clock (HCLK). */ - reg_val = PMC->PMC_MCKR & ~PMC_MCKR_PRES_Msk; - PMC->PMC_MCKR = reg_val | PMC_MCKR_PRES_CLK_1; + /* Select PLL as Master Clock source. */ + soc_pmc_mck_set_source(SOC_PMC_MCK_SRC_PLLA_CLK); - /* Wait for Master Clock setup to complete */ - while (!(PMC->PMC_SR & PMC_SR_MCKRDY)) { - ; - } - - /* Finally select PLL as Master Clock source. */ - reg_val = PMC->PMC_MCKR & ~PMC_MCKR_CSS_Msk; - PMC->PMC_MCKR = reg_val | PMC_MCKR_CSS_PLLA_CLK; - - /* Wait for Master Clock setup to complete. */ - while (!(PMC->PMC_SR & PMC_SR_MCKRDY)) { - ; + /* Disable internal fast RC if we have an external crystal oscillator */ + if (IS_ENABLED(CONFIG_SOC_ATMEL_SAM4S_EXT_MAINCK)) { + soc_pmc_osc_disable_fastrc(); } } void z_arm_platform_init(void) { - /* - * Set FWS (Flash Wait State) value before increasing Master Clock - * (MCK) frequency. Look at table 44.73 in the SAM4S datasheet. - * This is set to the highest number of read cycles because it won't - * hurt lower clock frequencies. However, a high frequency with too - * few read cycles could cause flash read problems. FWS 5 (6 cycles) - * is the safe setting for all of this SoCs usable frequencies. - * TODO: Add code to handle SAM4SD devices that have 2 EFCs. - */ - EFC0->EEFC_FMR = EEFC_FMR_FWS(5); + if (IS_ENABLED(CONFIG_SOC_ATMEL_SAM4S_WAIT_MODE)) { + /* + * Instruct CPU to enter Wait mode instead of Sleep mode to + * keep Processor Clock (HCLK) and thus be able to debug + * CPU using JTAG. + */ + soc_pmc_enable_waitmode(); + } /* Setup system clocks. */ clock_init(); From 89f23f7947d29e7c6a814dbce24ba815fbeed440 Mon Sep 17 00:00:00 2001 From: Pieter De Gendt Date: Wed, 20 Dec 2023 11:59:06 +0100 Subject: [PATCH 2637/3723] soc: arm: atmel_sam: sam3x: Rework clock_init Update clock_init for the Atmel SAM3X SoC using the new PMC API. Signed-off-by: Pieter De Gendt --- soc/arm/atmel_sam/sam3x/soc.c | 204 +++++++++------------------------- 1 file changed, 54 insertions(+), 150 deletions(-) diff --git a/soc/arm/atmel_sam/sam3x/soc.c b/soc/arm/atmel_sam/sam3x/soc.c index 6f85c2c69d7..9a20d566375 100644 --- a/soc/arm/atmel_sam/sam3x/soc.c +++ b/soc/arm/atmel_sam/sam3x/soc.c @@ -2,6 +2,7 @@ * Copyright (c) 2013-2015 Wind River Systems, Inc. * Copyright (c) 2016 Intel Corporation. * Copyright (c) 2023 Gerson Fernando Budke + * Copyright (c) 2023 Basalte bv * * SPDX-License-Identifier: Apache-2.0 */ @@ -14,25 +15,9 @@ * for the Atmel SAM3X series processor. */ -#include -#include -#include #include - -/* - * PLL clock = Main * (MULA + 1) / DIVA - * - * By default, MULA == 6, DIVA == 1. - * With main crystal running at 12 MHz, - * PLL = 12 * (6 + 1) / 1 = 84 MHz - * - * With Processor Clock prescaler at 1 - * Processor Clock (HCLK) = 84 MHz. - */ -#define PMC_CKGR_PLLAR_MULA \ - (CKGR_PLLAR_MULA(CONFIG_SOC_ATMEL_SAM3X_PLLA_MULA)) -#define PMC_CKGR_PLLAR_DIVA \ - (CKGR_PLLAR_DIVA(CONFIG_SOC_ATMEL_SAM3X_PLLA_DIVA)) +#include +#include /** * @brief Setup various clocks on SoC at boot time. @@ -42,167 +27,86 @@ */ static ALWAYS_INLINE void clock_init(void) { - uint32_t reg_val; - -#ifdef CONFIG_SOC_ATMEL_SAM3X_EXT_SLCK - /* Switch slow clock to the external 32 kHz crystal oscillator */ - SUPC->SUPC_CR = SUPC_CR_KEY_PASSWD | SUPC_CR_XTALSEL; + /* Switch the main clock to the internal OSC with 12MHz */ + soc_pmc_switch_mainck_to_fastrc(SOC_PMC_FAST_RC_FREQ_12MHZ); - /* Wait for oscillator to be stabilized */ - while (!(SUPC->SUPC_SR & SUPC_SR_OSCSEL)) { - ; - } -#endif /* CONFIG_SOC_ATMEL_SAM3X_EXT_SLCK */ + /* Switch MCK (Master Clock) to the main clock */ + soc_pmc_mck_set_source(SOC_PMC_MCK_SRC_MAIN_CLK); -#ifdef CONFIG_SOC_ATMEL_SAM3X_EXT_MAINCK - /* - * Setup main external crystal oscillator - */ + EFC0->EEFC_FMR = EEFC_FMR_FWS(0); + EFC1->EEFC_FMR = EEFC_FMR_FWS(0); - /* Start the external crystal oscillator */ - PMC->CKGR_MOR = CKGR_MOR_KEY_PASSWD - /* Fast RC Oscillator Frequency is at 4 MHz (default) */ - | CKGR_MOR_MOSCRCF_4_MHz - /* We select maximum setup time. While start up time - * could be shortened this optimization is not deemed - * critical now. - */ - | CKGR_MOR_MOSCXTST(0xFFu) - /* RC OSC must stay on */ - | CKGR_MOR_MOSCRCEN - | CKGR_MOR_MOSCXTEN; - - /* Wait for oscillator to be stabilized */ - while (!(PMC->PMC_SR & PMC_SR_MOSCXTS)) { - ; - } + soc_pmc_enable_clock_failure_detector(); - /* Select the external crystal oscillator as the main clock source */ - PMC->CKGR_MOR = CKGR_MOR_KEY_PASSWD - | CKGR_MOR_MOSCRCF_4_MHz - | CKGR_MOR_MOSCSEL - | CKGR_MOR_MOSCXTST(0xFFu) - | CKGR_MOR_MOSCRCEN - | CKGR_MOR_MOSCXTEN; - - /* Wait for external oscillator to be selected */ - while (!(PMC->PMC_SR & PMC_SR_MOSCSELS)) { - ; + if (IS_ENABLED(CONFIG_SOC_ATMEL_SAM3X_EXT_SLCK)) { + soc_supc_slow_clock_select_crystal_osc(); } - /* Turn off RC OSC, not used any longer, to save power */ - PMC->CKGR_MOR = CKGR_MOR_KEY_PASSWD - | CKGR_MOR_MOSCSEL - | CKGR_MOR_MOSCXTST(0xFFu) - | CKGR_MOR_MOSCXTEN; - - /* Wait for RC OSC to be turned off */ - while (PMC->PMC_SR & PMC_SR_MOSCRCS) { - ; + if (IS_ENABLED(CONFIG_SOC_ATMEL_SAM3X_EXT_MAINCK)) { + /* + * Setup main external crystal oscillator. + */ + + /* We select maximum setup time. + * While start up time could be shortened + * this optimization is not deemed + * critical now. + */ + soc_pmc_switch_mainck_to_xtal(false, 0xff); } -#ifdef CONFIG_SOC_ATMEL_SAM3X_WAIT_MODE - /* - * Instruct CPU to enter Wait mode instead of Sleep mode to - * keep Processor Clock (HCLK) and thus be able to debug - * CPU using JTAG - */ - PMC->PMC_FSMR |= PMC_FSMR_LPM; -#endif -#else - /* - * Setup main fast RC oscillator - */ - /* - * NOTE: MOSCRCF must be changed only if MOSCRCS is set in the PMC_SR - * register, should normally be the case here + * Set FWS (Flash Wait State) value before increasing Master Clock + * (MCK) frequency. + * TODO: set FWS based on the actual MCK frequency and VDDCORE value + * rather than maximum supported 84 MHz at standard VDDCORE=1.8V */ - while (!(PMC->PMC_SR & PMC_SR_MOSCRCS)) { - ; - } - - /* Set main fast RC oscillator to 12 MHz */ - PMC->CKGR_MOR = CKGR_MOR_KEY_PASSWD - | CKGR_MOR_MOSCRCF_12_MHz - | CKGR_MOR_MOSCRCEN; - - /* Wait for oscillator to be stabilized */ - while (!(PMC->PMC_SR & PMC_SR_MOSCRCS)) { - ; - } -#endif /* CONFIG_SOC_ATMEL_SAM3X_EXT_MAINCK */ + EFC0->EEFC_FMR = EEFC_FMR_FWS(4); + EFC1->EEFC_FMR = EEFC_FMR_FWS(4); /* * Setup PLLA */ - /* Switch MCK (Master Clock) to the main clock first */ - reg_val = PMC->PMC_MCKR & ~PMC_MCKR_CSS_Msk; - PMC->PMC_MCKR = reg_val | PMC_MCKR_CSS_MAIN_CLK; - - /* Wait for clock selection to complete */ - while (!(PMC->PMC_SR & PMC_SR_MCKRDY)) { - ; - } - - /* Setup PLLA */ - PMC->CKGR_PLLAR = CKGR_PLLAR_ONE - | PMC_CKGR_PLLAR_MULA - | CKGR_PLLAR_PLLACOUNT(0x3Fu) - | PMC_CKGR_PLLAR_DIVA; - /* - * NOTE: Both MULA and DIVA must be set to a value greater than 0 or - * otherwise PLL will be disabled. In this case we would get stuck in - * the following loop. + * PLL clock = Main * (MULA + 1) / DIVA + * + * By default, MULA == 6, DIVA == 1. + * With main crystal running at 12 MHz, + * PLL = 12 * (6 + 1) / 1 = 84 MHz + * + * With Processor Clock prescaler at 1 + * Processor Clock (HCLK) = 84 MHz. */ - - /* Wait for PLL lock */ - while (!(PMC->PMC_SR & PMC_SR_LOCKA)) { - ; - } + soc_pmc_enable_pllack(CONFIG_SOC_ATMEL_SAM3X_PLLA_MULA, 0x3Fu, + CONFIG_SOC_ATMEL_SAM3X_PLLA_DIVA); /* * Final setup of the Master Clock */ - /* - * NOTE: PMC_MCKR must not be programmed in a single write operation. - * If CSS or PRES are modified we must wait for MCKRDY bit to be - * set again. - */ + /* prescaler has to be set before PLL lock */ + soc_pmc_mck_set_prescaler(1); - /* Setup prescaler - PLLA Clock / Processor Clock (HCLK) */ - reg_val = PMC->PMC_MCKR & ~PMC_MCKR_PRES_Msk; - PMC->PMC_MCKR = reg_val | PMC_MCKR_PRES_CLK_1; + /* Select PLL as Master Clock source. */ + soc_pmc_mck_set_source(SOC_PMC_MCK_SRC_PLLA_CLK); - /* Wait for Master Clock setup to complete */ - while (!(PMC->PMC_SR & PMC_SR_MCKRDY)) { - ; - } - - /* Finally select PLL as Master Clock source */ - reg_val = PMC->PMC_MCKR & ~PMC_MCKR_CSS_Msk; - PMC->PMC_MCKR = reg_val | PMC_MCKR_CSS_PLLA_CLK; - - /* Wait for Master Clock setup to complete */ - while (!(PMC->PMC_SR & PMC_SR_MCKRDY)) { - ; + /* Disable internal fast RC if we have an external crystal oscillator */ + if (IS_ENABLED(CONFIG_SOC_ATMEL_SAM3X_EXT_MAINCK)) { + soc_pmc_osc_disable_fastrc(); } } void z_arm_platform_init(void) { - /* - * Set FWS (Flash Wait State) value before increasing Master Clock - * (MCK) frequency. - * TODO: set FWS based on the actual MCK frequency and VDDCORE value - * rather than maximum supported 84 MHz at standard VDDCORE=1.8V - */ - EFC0->EEFC_FMR = EEFC_FMR_FWS(4); - EFC1->EEFC_FMR = EEFC_FMR_FWS(4); - + if (IS_ENABLED(CONFIG_SOC_ATMEL_SAM3X_WAIT_MODE)) { + /* + * Instruct CPU to enter Wait mode instead of Sleep mode to + * keep Processor Clock (HCLK) and thus be able to debug + * CPU using JTAG. + */ + soc_pmc_enable_waitmode(); + } /* Setup system clocks */ clock_init(); } From 5bba8dd101a729c9afc563b95f533001b8221495 Mon Sep 17 00:00:00 2001 From: Pieter De Gendt Date: Wed, 20 Dec 2023 12:02:58 +0100 Subject: [PATCH 2638/3723] soc: arm: atmel_sam: sam4e: Rework clock_init Update clock_init for the Atmel SAM4E SoC using the new PMC API. Signed-off-by: Pieter De Gendt --- soc/arm/atmel_sam/sam4e/soc.c | 184 +++++++++------------------------- 1 file changed, 46 insertions(+), 138 deletions(-) diff --git a/soc/arm/atmel_sam/sam4e/soc.c b/soc/arm/atmel_sam/sam4e/soc.c index 33a8dd0d25f..b1c8174fddc 100644 --- a/soc/arm/atmel_sam/sam4e/soc.c +++ b/soc/arm/atmel_sam/sam4e/soc.c @@ -3,6 +3,7 @@ * Copyright (c) 2016 Intel Corporation. * Copyright (c) 2017 Justin Watson * Copyright (c) 2019-2023 Gerson Fernando Budke + * Copyright (c) 2023 Basalte bv * * SPDX-License-Identifier: Apache-2.0 */ @@ -15,9 +16,9 @@ * for the Atmel SAM4E series processor. */ -#include -#include #include +#include +#include /** * @brief Setup various clock on SoC at boot time. @@ -29,168 +30,75 @@ */ static ALWAYS_INLINE void clock_init(void) { - uint32_t reg_val; + /* Switch the main clock to the internal OSC with 12MHz */ + soc_pmc_switch_mainck_to_fastrc(SOC_PMC_FAST_RC_FREQ_12MHZ); -#ifdef CONFIG_SOC_ATMEL_SAM4E_EXT_SLCK - /* Switch slow clock to the external 32 KHz crystal oscillator. */ - SUPC->SUPC_CR = SUPC_CR_KEY_PASSWD | SUPC_CR_XTALSEL_CRYSTAL_SEL; + /* Switch MCK (Master Clock) to the main clock */ + soc_pmc_mck_set_source(SOC_PMC_MCK_SRC_MAIN_CLK); - /* Wait for oscillator to be stabilized. */ - while (!(SUPC->SUPC_SR & SUPC_SR_OSCSEL)) { - ; - } - -#endif /* CONFIG_SOC_ATMEL_SAM4E_EXT_SLCK */ - -#ifdef CONFIG_SOC_ATMEL_SAM4E_EXT_MAINCK - /* - * Setup main external crystal oscillator. - */ + EFC->EEFC_FMR = EEFC_FMR_FWS(0); - /* Start the external crystal oscillator. */ - PMC->CKGR_MOR = CKGR_MOR_KEY_PASSWD - /* Fast RC oscillator frequency is at 4 MHz. */ - | CKGR_MOR_MOSCRCF_4_MHz - /* - * We select maximum setup time. While start up time - * could be shortened this optimization is not deemed - * critical right now. - */ - | CKGR_MOR_MOSCXTST(0xFFu) - /* RC oscillator must stay on. */ - | CKGR_MOR_MOSCRCEN - | CKGR_MOR_MOSCXTEN; - - /* Wait for oscillator to be stabilized. */ - while (!(PMC->PMC_SR & PMC_SR_MOSCXTS)) { - ; - } + soc_pmc_enable_clock_failure_detector(); - /* Select the external crystal oscillator as the main clock source. */ - PMC->CKGR_MOR = CKGR_MOR_KEY_PASSWD - | CKGR_MOR_MOSCRCF_4_MHz - | CKGR_MOR_MOSCRCEN - | CKGR_MOR_MOSCXTEN - | CKGR_MOR_MOSCXTST(0xFFu) - | CKGR_MOR_MOSCSEL; - - /* Wait for external oscillator to be selected. */ - while (!(PMC->PMC_SR & PMC_SR_MOSCSELS)) { - ; + if (IS_ENABLED(CONFIG_SOC_ATMEL_SAM4E_EXT_SLCK)) { + soc_supc_slow_clock_select_crystal_osc(); } - /* Turn off RC oscillator, not used any longer, to save power */ - PMC->CKGR_MOR = CKGR_MOR_KEY_PASSWD - | CKGR_MOR_MOSCSEL - | CKGR_MOR_MOSCXTST(0xFFu) - | CKGR_MOR_MOSCXTEN; - - /* Wait for the RC oscillator to be turned off. */ - while (PMC->PMC_SR & PMC_SR_MOSCRCS) { - ; + if (IS_ENABLED(CONFIG_SOC_ATMEL_SAM4E_EXT_MAINCK)) { + /* + * Setup main external crystal oscillator. + */ + + /* We select maximum setup time. + * While start up time could be shortened + * this optimization is not deemed + * critical now. + */ + soc_pmc_switch_mainck_to_xtal(false, 0xff); } -#ifdef CONFIG_SOC_ATMEL_SAM4E_WAIT_MODE - /* - * Instruct CPU to enter Wait mode instead of Sleep mode to - * keep Processor Clock (HCLK) and thus be able to debug - * CPU using JTAG. - */ - PMC->PMC_FSMR |= PMC_FSMR_LPM; -#endif -#else - /* Setup main fast RC oscillator. */ - /* - * NOTE: MOSCRCF must be changed only if MOSCRCS is set in the PMC_SR - * register, should normally be the case. + * Set FWS (Flash Wait State) value before increasing Master Clock + * (MCK) frequency. Look at table 44.73 in the SAM4E datasheet. + * This is set to the highest number of read cycles because it won't + * hurt lower clock frequencies. However, a high frequency with too + * few read cycles could cause flash read problems. FWS 5 (6 cycles) + * is the safe setting for all of this SoCs usable frequencies. */ - while (!(PMC->PMC_SR & PMC_SR_MOSCRCS)) { - ; - } - - /* Set main fast RC oscillator to 12 MHz. */ - PMC->CKGR_MOR = CKGR_MOR_KEY_PASSWD - | CKGR_MOR_MOSCRCF_12_MHz - | CKGR_MOR_MOSCRCEN; - - /* Wait for RC oscillator to stabilize. */ - while (!(PMC->PMC_SR & PMC_SR_MOSCRCS)) { - ; - } -#endif /* CONFIG_SOC_ATMEL_SAM4E_EXT_MAINCK */ + EFC->EEFC_FMR = EEFC_FMR_FWS(5); /* * Setup PLLA */ - - /* Switch MCK (Master Clock) to the main clock first. */ - reg_val = PMC->PMC_MCKR & ~PMC_MCKR_CSS_Msk; - PMC->PMC_MCKR = reg_val | PMC_MCKR_CSS_MAIN_CLK; - - /* Wait for clock selection to complete. */ - while (!(PMC->PMC_SR & PMC_SR_MCKRDY)) { - ; - } - - /* Setup PLLA. */ - PMC->CKGR_PLLAR = CKGR_PLLAR_ONE - | CKGR_PLLAR_MULA(CONFIG_SOC_ATMEL_SAM4E_PLLA_MULA) - | CKGR_PLLAR_PLLACOUNT(0x3Fu) - | CKGR_PLLAR_DIVA(CONFIG_SOC_ATMEL_SAM4E_PLLA_DIVA); - - /* - * NOTE: Both MULA and DIVA must be set to a value greater than 0 or - * otherwise PLL will be disabled. In this case we would get stuck in - * the following loop. - */ - - /* Wait for PLL lock. */ - while (!(PMC->PMC_SR & PMC_SR_LOCKA)) { - ; - } + soc_pmc_enable_pllack(CONFIG_SOC_ATMEL_SAM4E_PLLA_MULA, 0x3Fu, + CONFIG_SOC_ATMEL_SAM4E_PLLA_DIVA); /* * Final setup of the Master Clock */ - /* - * NOTE: PMC_MCKR must not be programmed in a single write operation. - * If CSS or PRES are modified we must wait for MCKRDY bit to be - * set again. - */ - - /* Setup prescaler - PLLA Clock / Processor Clock (HCLK). */ - reg_val = PMC->PMC_MCKR & ~PMC_MCKR_PRES_Msk; - PMC->PMC_MCKR = reg_val | PMC_MCKR_PRES_CLK_1; - - /* Wait for Master Clock setup to complete */ - while (!(PMC->PMC_SR & PMC_SR_MCKRDY)) { - ; - } + /* prescaler has to be set before PLL lock */ + soc_pmc_mck_set_prescaler(1); - /* Finally select PLL as Master Clock source. */ - reg_val = PMC->PMC_MCKR & ~PMC_MCKR_CSS_Msk; - PMC->PMC_MCKR = reg_val | PMC_MCKR_CSS_PLLA_CLK; + /* Select PLL as Master Clock source. */ + soc_pmc_mck_set_source(SOC_PMC_MCK_SRC_PLLA_CLK); - /* Wait for Master Clock setup to complete. */ - while (!(PMC->PMC_SR & PMC_SR_MCKRDY)) { - ; + /* Disable internal fast RC if we have an external crystal oscillator */ + if (IS_ENABLED(CONFIG_SOC_ATMEL_SAM4E_EXT_MAINCK)) { + soc_pmc_osc_disable_fastrc(); } } void z_arm_platform_init(void) { - /* - * Set FWS (Flash Wait State) value before increasing Master Clock - * (MCK) frequency. Look at table 44.73 in the SAM4E datasheet. - * This is set to the highest number of read cycles because it won't - * hurt lower clock frequencies. However, a high frequency with too - * few read cycles could cause flash read problems. FWS 5 (6 cycles) - * is the safe setting for all of this SoCs usable frequencies. - */ - EFC->EEFC_FMR = EEFC_FMR_FWS(5); - + if (IS_ENABLED(CONFIG_SOC_ATMEL_SAM4E_WAIT_MODE)) { + /* + * Instruct CPU to enter Wait mode instead of Sleep mode to + * keep Processor Clock (HCLK) and thus be able to debug + * CPU using JTAG. + */ + soc_pmc_enable_waitmode(); + } /* Setup system clocks. */ clock_init(); } From 23edb87cab459d16321bc54653a59161b055d2ec Mon Sep 17 00:00:00 2001 From: Pieter De Gendt Date: Thu, 4 Jan 2024 14:23:00 +0100 Subject: [PATCH 2639/3723] soc: arm: atmel_sam: same70: Rework clock_init Update clock_init for the Atmel SAME70 SoC using the new PMC API. Signed-off-by: Pieter De Gendt --- soc/arm/atmel_sam/same70/soc.c | 226 ++++++++------------------------- 1 file changed, 53 insertions(+), 173 deletions(-) diff --git a/soc/arm/atmel_sam/same70/soc.c b/soc/arm/atmel_sam/same70/soc.c index f68e520c724..02ebce73c6d 100644 --- a/soc/arm/atmel_sam/same70/soc.c +++ b/soc/arm/atmel_sam/same70/soc.c @@ -17,41 +17,14 @@ #include #include #include +#include +#include #include #include #define LOG_LEVEL CONFIG_SOC_LOG_LEVEL LOG_MODULE_REGISTER(soc); -/* Power Manager Controller */ - -/* - * PLL clock = Main * (MULA + 1) / DIVA - * - * By default, MULA == 24, DIVA == 1. - * With main crystal running at 12 MHz, - * PLL = 12 * (24 + 1) / 1 = 300 MHz - * - * With Processor Clock prescaler at 1 - * Processor Clock (HCLK)=300 MHz. - */ -#define PMC_CKGR_PLLAR_MULA \ - (CKGR_PLLAR_MULA(CONFIG_SOC_ATMEL_SAME70_PLLA_MULA)) -#define PMC_CKGR_PLLAR_DIVA \ - (CKGR_PLLAR_DIVA(CONFIG_SOC_ATMEL_SAME70_PLLA_DIVA)) - -#if CONFIG_SOC_ATMEL_SAME70_MDIV == 1 -#define SOC_ATMEL_SAME70_MDIV PMC_MCKR_MDIV_EQ_PCK -#elif CONFIG_SOC_ATMEL_SAME70_MDIV == 2 -#define SOC_ATMEL_SAME70_MDIV PMC_MCKR_MDIV_PCK_DIV2 -#elif CONFIG_SOC_ATMEL_SAME70_MDIV == 3 -#define SOC_ATMEL_SAME70_MDIV PMC_MCKR_MDIV_PCK_DIV3 -#elif CONFIG_SOC_ATMEL_SAME70_MDIV == 4 -#define SOC_ATMEL_SAME70_MDIV PMC_MCKR_MDIV_PCK_DIV4 -#else -#error "Invalid CONFIG_SOC_ATMEL_SAME70_MDIV define value" -#endif - /** * @brief Setup various clocks on SoC at boot time. * @@ -60,174 +33,89 @@ LOG_MODULE_REGISTER(soc); */ static ALWAYS_INLINE void clock_init(void) { - uint32_t reg_val; - -#ifdef CONFIG_SOC_ATMEL_SAME70_EXT_SLCK - /* Switch slow clock to the external 32 kHz crystal oscillator */ - SUPC->SUPC_CR = SUPC_CR_KEY_PASSWD | SUPC_CR_XTALSEL; - - /* Wait for oscillator to be stabilized */ - while (!(SUPC->SUPC_SR & SUPC_SR_OSCSEL)) { - ; - } -#endif /* CONFIG_SOC_ATMEL_SAME70_EXT_SLCK */ - -#ifdef CONFIG_SOC_ATMEL_SAME70_EXT_MAINCK - /* - * Setup main external crystal oscillator if not already done - * by a previous program i.e. bootloader - */ + /* Switch the main clock to the internal OSC with 12MHz */ + soc_pmc_switch_mainck_to_fastrc(SOC_PMC_FAST_RC_FREQ_12MHZ); - if (!(PMC->CKGR_MOR & CKGR_MOR_MOSCSEL_Msk)) { - /* Start the external crystal oscillator */ - PMC->CKGR_MOR = CKGR_MOR_KEY_PASSWD - /* We select maximum setup time. - * While start up time could be shortened - * this optimization is not deemed - * critical now. - */ - | CKGR_MOR_MOSCXTST(0xFFu) - /* RC OSC must stay on */ - | CKGR_MOR_MOSCRCEN - | CKGR_MOR_MOSCXTEN; + /* Switch MCK (Master Clock) to the main clock */ + soc_pmc_mck_set_source(SOC_PMC_MCK_SRC_MAIN_CLK); - /* Wait for oscillator to be stabilized */ - while (!(PMC->PMC_SR & PMC_SR_MOSCXTS)) { - ; - } + EFC->EEFC_FMR = EEFC_FMR_FWS(0) | EEFC_FMR_CLOE; - /* Select the external crystal oscillator as main clock */ - PMC->CKGR_MOR = CKGR_MOR_KEY_PASSWD - | CKGR_MOR_MOSCSEL - | CKGR_MOR_MOSCXTST(0xFFu) - | CKGR_MOR_MOSCRCEN - | CKGR_MOR_MOSCXTEN; + soc_pmc_enable_clock_failure_detector(); - /* Wait for external oscillator to be selected */ - while (!(PMC->PMC_SR & PMC_SR_MOSCSELS)) { - ; - } + if (IS_ENABLED(CONFIG_SOC_ATMEL_SAME70_EXT_SLCK)) { + soc_supc_slow_clock_select_crystal_osc(); } - /* Turn off RC OSC, not used any longer, to save power */ - PMC->CKGR_MOR = CKGR_MOR_KEY_PASSWD - | CKGR_MOR_MOSCSEL - | CKGR_MOR_MOSCXTST(0xFFu) - | CKGR_MOR_MOSCXTEN; - /* Wait for RC OSC to be turned off */ - while (PMC->PMC_SR & PMC_SR_MOSCRCS) { - ; - } + if (IS_ENABLED(CONFIG_SOC_ATMEL_SAME70_EXT_MAINCK)) { + /* + * Setup main external crystal oscillator. + */ -#ifdef CONFIG_SOC_ATMEL_SAME70_WAIT_MODE - /* - * Instruct CPU to enter Wait mode instead of Sleep mode to - * keep Processor Clock (HCLK) and thus be able to debug - * CPU using JTAG - */ - PMC->PMC_FSMR |= PMC_FSMR_LPM; -#endif -#else - /* Attempt to change main fast RC oscillator frequency */ + /* We select maximum setup time. + * While start up time could be shortened + * this optimization is not deemed + * critical now. + */ + soc_pmc_switch_mainck_to_xtal(false, 0xff); + } /* - * NOTE: MOSCRCF must be changed only if MOSCRCS is set in the PMC_SR - * register, should normally be the case here + * Set FWS (Flash Wait State) value before increasing Master Clock + * (MCK) frequency. + * TODO: set FWS based on the actual MCK frequency and VDDIO value + * rather than maximum supported 150 MHz at standard VDDIO=2.7V */ - while (!(PMC->PMC_SR & PMC_SR_MOSCRCS)) { - ; - } - - /* Set main fast RC oscillator to 12 MHz */ - PMC->CKGR_MOR = CKGR_MOR_KEY_PASSWD - | CKGR_MOR_MOSCRCF_12_MHz - | CKGR_MOR_MOSCRCEN; - - /* Wait for oscillator to be stabilized */ - while (!(PMC->PMC_SR & PMC_SR_MOSCRCS)) { - ; - } -#endif /* CONFIG_SOC_ATMEL_SAME70_EXT_MAINCK */ + EFC->EEFC_FMR = EEFC_FMR_FWS(5) | EEFC_FMR_CLOE; /* * Setup PLLA */ - /* Switch MCK (Master Clock) to the main clock first */ - reg_val = PMC->PMC_MCKR & ~PMC_MCKR_CSS_Msk; - PMC->PMC_MCKR = reg_val | PMC_MCKR_CSS_MAIN_CLK; - - /* Wait for clock selection to complete */ - while (!(PMC->PMC_SR & PMC_SR_MCKRDY)) { - ; - } - - /* Setup PLLA */ - PMC->CKGR_PLLAR = CKGR_PLLAR_ONE - | PMC_CKGR_PLLAR_MULA - | CKGR_PLLAR_PLLACOUNT(0x3Fu) - | PMC_CKGR_PLLAR_DIVA; - /* - * NOTE: Both MULA and DIVA must be set to a value greater than 0 or - * otherwise PLL will be disabled. In this case we would get stuck in - * the following loop. + * PLL clock = Main * (MULA + 1) / DIVA + * + * By default, MULA == 24, DIVA == 1. + * With main crystal running at 12 MHz, + * PLL = 12 * (24 + 1) / 1 = 300 MHz + * + * With Processor Clock prescaler at 1 + * Processor Clock (HCLK)=300 MHz. */ + soc_pmc_enable_pllack(CONFIG_SOC_ATMEL_SAME70_PLLA_MULA, 0x3Fu, + CONFIG_SOC_ATMEL_SAME70_PLLA_DIVA); - /* Wait for PLL lock */ - while (!(PMC->PMC_SR & PMC_SR_LOCKA)) { - ; - } - - /* Setup UPLL */ - PMC->CKGR_UCKR = CKGR_UCKR_UPLLCOUNT(0x3Fu) | CKGR_UCKR_UPLLEN; - /* Wait for PLL lock */ - while (!(PMC->PMC_SR & PMC_SR_LOCKU)) { - ; - } + soc_pmc_enable_upllck(0x3Fu); /* * Final setup of the Master Clock */ - /* - * NOTE: PMC_MCKR must not be programmed in a single write operation. - * If CSS, MDIV or PRES are modified we must wait for MCKRDY bit to be - * set again. - */ - - /* Setup prescaler - PLLA Clock / Processor Clock (HCLK) */ - reg_val = PMC->PMC_MCKR & ~PMC_MCKR_PRES_Msk; - PMC->PMC_MCKR = reg_val | PMC_MCKR_PRES_CLK_1; + /* Setting PLLA as MCK, first prescaler, then divider and source last */ + soc_pmc_mck_set_prescaler(1); + soc_pmc_mck_set_divider(CONFIG_SOC_ATMEL_SAME70_MDIV); + soc_pmc_mck_set_source(SOC_PMC_MCK_SRC_PLLA_CLK); - /* Wait for Master Clock setup to complete */ - while (!(PMC->PMC_SR & PMC_SR_MCKRDY)) { - ; - } - - /* Setup divider - Processor Clock (HCLK) / Master Clock (MCK) */ - reg_val = PMC->PMC_MCKR & ~PMC_MCKR_MDIV_Msk; - PMC->PMC_MCKR = reg_val | SOC_ATMEL_SAME70_MDIV; - /* Wait for Master Clock setup to complete */ - while (!(PMC->PMC_SR & PMC_SR_MCKRDY)) { - ; - } - - /* Finally select PLL as Master Clock source */ - reg_val = PMC->PMC_MCKR & ~PMC_MCKR_CSS_Msk; - PMC->PMC_MCKR = reg_val | PMC_MCKR_CSS_PLLA_CLK; - - /* Wait for Master Clock setup to complete */ - while (!(PMC->PMC_SR & PMC_SR_MCKRDY)) { - ; + /* Disable internal fast RC if we have an external crystal oscillator */ + if (IS_ENABLED(CONFIG_SOC_ATMEL_SAME70_EXT_MAINCK)) { + soc_pmc_osc_disable_fastrc(); } } void z_arm_platform_init(void) { + if (IS_ENABLED(CONFIG_SOC_ATMEL_SAME70_WAIT_MODE)) { + /* + * Instruct CPU to enter Wait mode instead of Sleep mode to + * keep Processor Clock (HCLK) and thus be able to debug + * CPU using JTAG. + */ + soc_pmc_enable_waitmode(); + } + /* * DTCM is enabled by default at reset, therefore we have to disable * it first to get the caches into a state where then the @@ -242,14 +130,6 @@ void z_arm_platform_init(void) sys_cache_instr_enable(); sys_cache_data_enable(); - /* - * Set FWS (Flash Wait State) value before increasing Master Clock - * (MCK) frequency. - * TODO: set FWS based on the actual MCK frequency and VDDIO value - * rather than maximum supported 150 MHz at standard VDDIO=2.7V - */ - EFC->EEFC_FMR = EEFC_FMR_FWS(5) | EEFC_FMR_CLOE; - /* Setup system clocks */ clock_init(); } From 1c190045b3e549ee70cc0d1723acde6df1e20f4a Mon Sep 17 00:00:00 2001 From: Pieter De Gendt Date: Thu, 4 Jan 2024 14:33:17 +0100 Subject: [PATCH 2640/3723] soc: arm: atmel_sam: samv71: Rework clock_init Update clock_init for the Atmel SAMV71 SoC using the new PMC API. Signed-off-by: Pieter De Gendt --- soc/arm/atmel_sam/samv71/soc.c | 225 ++++++++------------------------- 1 file changed, 51 insertions(+), 174 deletions(-) diff --git a/soc/arm/atmel_sam/samv71/soc.c b/soc/arm/atmel_sam/samv71/soc.c index f88a3cb440b..6e82b9fe2f6 100644 --- a/soc/arm/atmel_sam/samv71/soc.c +++ b/soc/arm/atmel_sam/samv71/soc.c @@ -23,35 +23,6 @@ #define LOG_LEVEL CONFIG_SOC_LOG_LEVEL LOG_MODULE_REGISTER(soc); -/* Power Manager Controller */ - -/* - * PLL clock = Main * (MULA + 1) / DIVA - * - * By default, MULA == 24, DIVA == 1. - * With main crystal running at 12 MHz, - * PLL = 12 * (24 + 1) / 1 = 300 MHz - * - * With Processor Clock prescaler at 1 - * Processor Clock (HCLK)=300 MHz. - */ -#define PMC_CKGR_PLLAR_MULA \ - (CKGR_PLLAR_MULA(CONFIG_SOC_ATMEL_SAMV71_PLLA_MULA)) -#define PMC_CKGR_PLLAR_DIVA \ - (CKGR_PLLAR_DIVA(CONFIG_SOC_ATMEL_SAMV71_PLLA_DIVA)) - -#if CONFIG_SOC_ATMEL_SAMV71_MDIV == 1 -#define SOC_ATMEL_SAMV71_MDIV PMC_MCKR_MDIV_EQ_PCK -#elif CONFIG_SOC_ATMEL_SAMV71_MDIV == 2 -#define SOC_ATMEL_SAMV71_MDIV PMC_MCKR_MDIV_PCK_DIV2 -#elif CONFIG_SOC_ATMEL_SAMV71_MDIV == 3 -#define SOC_ATMEL_SAMV71_MDIV PMC_MCKR_MDIV_PCK_DIV3 -#elif CONFIG_SOC_ATMEL_SAMV71_MDIV == 4 -#define SOC_ATMEL_SAMV71_MDIV PMC_MCKR_MDIV_PCK_DIV4 -#else -#error "Invalid CONFIG_SOC_ATMEL_SAMV71_MDIV define value" -#endif - /** * @brief Setup various clocks on SoC at boot time. * @@ -60,174 +31,88 @@ LOG_MODULE_REGISTER(soc); */ static ALWAYS_INLINE void clock_init(void) { - uint32_t reg_val; - -#ifdef CONFIG_SOC_ATMEL_SAMV71_EXT_SLCK - /* Switch slow clock to the external 32 kHz crystal oscillator */ - SUPC->SUPC_CR = SUPC_CR_KEY_PASSWD | SUPC_CR_XTALSEL; - - /* Wait for oscillator to be stabilized */ - while (!(SUPC->SUPC_SR & SUPC_SR_OSCSEL)) { - ; - } -#endif /* CONFIG_SOC_ATMEL_SAMV71_EXT_SLCK */ - -#ifdef CONFIG_SOC_ATMEL_SAMV71_EXT_MAINCK - /* - * Setup main external crystal oscillator if not already done - * by a previous program i.e. bootloader - */ + /* Switch the main clock to the internal OSC with 12MHz */ + soc_pmc_switch_mainck_to_fastrc(SOC_PMC_FAST_RC_FREQ_12MHZ); - if (!(PMC->CKGR_MOR & CKGR_MOR_MOSCSEL_Msk)) { - /* Start the external crystal oscillator */ - PMC->CKGR_MOR = CKGR_MOR_KEY_PASSWD - /* We select maximum setup time. - * While start up time could be shortened - * this optimization is not deemed - * critical now. - */ - | CKGR_MOR_MOSCXTST(0xFFu) - /* RC OSC must stay on */ - | CKGR_MOR_MOSCRCEN - | CKGR_MOR_MOSCXTEN; + /* Switch MCK (Master Clock) to the main clock */ + soc_pmc_mck_set_source(SOC_PMC_MCK_SRC_MAIN_CLK); - /* Wait for oscillator to be stabilized */ - while (!(PMC->PMC_SR & PMC_SR_MOSCXTS)) { - ; - } + EFC->EEFC_FMR = EEFC_FMR_FWS(0) | EEFC_FMR_CLOE; - /* Select the external crystal oscillator as main clock */ - PMC->CKGR_MOR = CKGR_MOR_KEY_PASSWD - | CKGR_MOR_MOSCSEL - | CKGR_MOR_MOSCXTST(0xFFu) - | CKGR_MOR_MOSCRCEN - | CKGR_MOR_MOSCXTEN; + soc_pmc_enable_clock_failure_detector(); - /* Wait for external oscillator to be selected */ - while (!(PMC->PMC_SR & PMC_SR_MOSCSELS)) { - ; - } + if (IS_ENABLED(CONFIG_SOC_ATMEL_SAMV71_EXT_SLCK)) { + soc_supc_slow_clock_select_crystal_osc(); } - /* Turn off RC OSC, not used any longer, to save power */ - PMC->CKGR_MOR = CKGR_MOR_KEY_PASSWD - | CKGR_MOR_MOSCSEL - | CKGR_MOR_MOSCXTST(0xFFu) - | CKGR_MOR_MOSCXTEN; - /* Wait for RC OSC to be turned off */ - while (PMC->PMC_SR & PMC_SR_MOSCRCS) { - ; - } + if (IS_ENABLED(CONFIG_SOC_ATMEL_SAMV71_EXT_MAINCK)) { + /* + * Setup main external crystal oscillator. + */ -#ifdef CONFIG_SOC_ATMEL_SAMV71_WAIT_MODE - /* - * Instruct CPU to enter Wait mode instead of Sleep mode to - * keep Processor Clock (HCLK) and thus be able to debug - * CPU using JTAG - */ - PMC->PMC_FSMR |= PMC_FSMR_LPM; -#endif -#else - /* Attempt to change main fast RC oscillator frequency */ + /* We select maximum setup time. + * While start up time could be shortened + * this optimization is not deemed + * critical now. + */ + soc_pmc_switch_mainck_to_xtal(false, 0xff); + } /* - * NOTE: MOSCRCF must be changed only if MOSCRCS is set in the PMC_SR - * register, should normally be the case here + * Set FWS (Flash Wait State) value before increasing Master Clock + * (MCK) frequency. + * TODO: set FWS based on the actual MCK frequency and VDDIO value + * rather than maximum supported 150 MHz at standard VDDIO=2.7V */ - while (!(PMC->PMC_SR & PMC_SR_MOSCRCS)) { - ; - } - - /* Set main fast RC oscillator to 12 MHz */ - PMC->CKGR_MOR = CKGR_MOR_KEY_PASSWD - | CKGR_MOR_MOSCRCF_12_MHz - | CKGR_MOR_MOSCRCEN; - - /* Wait for oscillator to be stabilized */ - while (!(PMC->PMC_SR & PMC_SR_MOSCRCS)) { - ; - } -#endif /* CONFIG_SOC_ATMEL_SAMV71_EXT_MAINCK */ + EFC->EEFC_FMR = EEFC_FMR_FWS(5) | EEFC_FMR_CLOE; /* * Setup PLLA */ - /* Switch MCK (Master Clock) to the main clock first */ - reg_val = PMC->PMC_MCKR & ~PMC_MCKR_CSS_Msk; - PMC->PMC_MCKR = reg_val | PMC_MCKR_CSS_MAIN_CLK; - - /* Wait for clock selection to complete */ - while (!(PMC->PMC_SR & PMC_SR_MCKRDY)) { - ; - } - - /* Setup PLLA */ - PMC->CKGR_PLLAR = CKGR_PLLAR_ONE - | PMC_CKGR_PLLAR_MULA - | CKGR_PLLAR_PLLACOUNT(0x3Fu) - | PMC_CKGR_PLLAR_DIVA; - /* - * NOTE: Both MULA and DIVA must be set to a value greater than 0 or - * otherwise PLL will be disabled. In this case we would get stuck in - * the following loop. + * PLL clock = Main * (MULA + 1) / DIVA + * + * By default, MULA == 24, DIVA == 1. + * With main crystal running at 12 MHz, + * PLL = 12 * (24 + 1) / 1 = 300 MHz + * + * With Processor Clock prescaler at 1 + * Processor Clock (HCLK)=300 MHz. */ + soc_pmc_enable_pllack(CONFIG_SOC_ATMEL_SAMV71_PLLA_MULA, 0x3Fu, + CONFIG_SOC_ATMEL_SAMV71_PLLA_DIVA); - /* Wait for PLL lock */ - while (!(PMC->PMC_SR & PMC_SR_LOCKA)) { - ; - } - - /* Setup UPLL */ - PMC->CKGR_UCKR = CKGR_UCKR_UPLLCOUNT(0x3Fu) | CKGR_UCKR_UPLLEN; - /* Wait for PLL lock */ - while (!(PMC->PMC_SR & PMC_SR_LOCKU)) { - ; - } + soc_pmc_enable_upllck(0x3Fu); /* * Final setup of the Master Clock */ - /* - * NOTE: PMC_MCKR must not be programmed in a single write operation. - * If CSS, MDIV or PRES are modified we must wait for MCKRDY bit to be - * set again. - */ - - /* Setup prescaler - PLLA Clock / Processor Clock (HCLK) */ - reg_val = PMC->PMC_MCKR & ~PMC_MCKR_PRES_Msk; - PMC->PMC_MCKR = reg_val | PMC_MCKR_PRES_CLK_1; - - /* Wait for Master Clock setup to complete */ - while (!(PMC->PMC_SR & PMC_SR_MCKRDY)) { - ; - } - - /* Setup divider - Processor Clock (HCLK) / Master Clock (MCK) */ - reg_val = PMC->PMC_MCKR & ~PMC_MCKR_MDIV_Msk; - PMC->PMC_MCKR = reg_val | SOC_ATMEL_SAMV71_MDIV; + /* Setting PLLA as MCK, first prescaler, then divider and source last */ + soc_pmc_mck_set_prescaler(1); + soc_pmc_mck_set_divider(CONFIG_SOC_ATMEL_SAMV71_MDIV); + soc_pmc_mck_set_source(SOC_PMC_MCK_SRC_PLLA_CLK); - /* Wait for Master Clock setup to complete */ - while (!(PMC->PMC_SR & PMC_SR_MCKRDY)) { - ; - } - - /* Finally select PLL as Master Clock source */ - reg_val = PMC->PMC_MCKR & ~PMC_MCKR_CSS_Msk; - PMC->PMC_MCKR = reg_val | PMC_MCKR_CSS_PLLA_CLK; - - /* Wait for Master Clock setup to complete */ - while (!(PMC->PMC_SR & PMC_SR_MCKRDY)) { - ; + /* Disable internal fast RC if we have an external crystal oscillator */ + if (IS_ENABLED(CONFIG_SOC_ATMEL_SAMV71_EXT_MAINCK)) { + soc_pmc_osc_disable_fastrc(); } } void z_arm_platform_init(void) { + if (IS_ENABLED(CONFIG_SOC_ATMEL_SAMV71_WAIT_MODE)) { + /* + * Instruct CPU to enter Wait mode instead of Sleep mode to + * keep Processor Clock (HCLK) and thus be able to debug + * CPU using JTAG. + */ + soc_pmc_enable_waitmode(); + } + /* * DTCM is enabled by default at reset, therefore we have to disable * it first to get the caches into a state where then the @@ -242,14 +127,6 @@ void z_arm_platform_init(void) sys_cache_instr_enable(); sys_cache_data_enable(); - /* - * Set FWS (Flash Wait State) value before increasing Master Clock - * (MCK) frequency. - * TODO: set FWS based on the actual MCK frequency and VDDIO value - * rather than maximum supported 150 MHz at standard VDDIO=2.7V - */ - EFC->EEFC_FMR = EEFC_FMR_FWS(5) | EEFC_FMR_CLOE; - /* Setup system clocks */ clock_init(); } From 5fd3f658ffe1c29fb6fdfbb72a37290155be88a1 Mon Sep 17 00:00:00 2001 From: Ian Morris Date: Thu, 14 Dec 2023 13:55:56 -0800 Subject: [PATCH 2641/3723] drivers: clock_control: clock_control_ra.c: protect register fix Protection for clock control and power mode registers was not being re-enabled. Signed-off-by: Ian Morris --- drivers/clock_control/clock_control_ra.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/clock_control/clock_control_ra.c b/drivers/clock_control/clock_control_ra.c index 46149f0099c..382625c2a2f 100644 --- a/drivers/clock_control/clock_control_ra.c +++ b/drivers/clock_control/clock_control_ra.c @@ -299,7 +299,7 @@ static int clock_control_ra_init(const struct device *dev) } SYSTEM_write8(MEMWAIT_OFFSET, 1); - SYSTEM_write16(PRCR_OFFSET, PRCR_KEY | PRCR_CLOCKS | PRCR_LOW_POWER); + SYSTEM_write16(PRCR_OFFSET, PRCR_KEY); return 0; } From a689228eb863a22b89fc5c9e0a3656ee47a7b294 Mon Sep 17 00:00:00 2001 From: Tomas Galbicka Date: Fri, 12 Jan 2024 15:43:30 +0100 Subject: [PATCH 2642/3723] drivers: mbox: fix nxp mbox data read channel This commit repairs reading of data from other channels than 0. Refactors irq handler outside of DT define. Trigger registered callback only when proper flag is set. Signed-off-by: Tomas Galbicka --- drivers/mbox/mbox_nxp_imx_mu.c | 152 ++++++++++++++++----------------- 1 file changed, 75 insertions(+), 77 deletions(-) diff --git a/drivers/mbox/mbox_nxp_imx_mu.c b/drivers/mbox/mbox_nxp_imx_mu.c index ddaac07e392..664a88e2065 100644 --- a/drivers/mbox/mbox_nxp_imx_mu.c +++ b/drivers/mbox/mbox_nxp_imx_mu.c @@ -1,4 +1,8 @@ /* + * Copyright 2024 NXP + * + * SPDX-License-Identifier: Apache-2.0 + * * Wrapper of the i.MX Message Unit driver into Zephyr's MBOX model. */ @@ -13,20 +17,20 @@ LOG_MODULE_REGISTER(nxp_mbox_imx_mu); #define DT_DRV_COMPAT nxp_mbox_imx_mu -#define MU_MAX_CHANNELS 4 -#define MU_MBOX_SIZE sizeof(uint32_t) +#define MU_MAX_CHANNELS 4 +#define MU_MBOX_SIZE sizeof(uint32_t) struct nxp_imx_mu_data { mbox_callback_t cb[MU_MAX_CHANNELS]; void *user_data[MU_MAX_CHANNELS]; + uint32_t received_data; }; struct nxp_imx_mu_config { MU_Type *base; }; -static int nxp_imx_mu_send(const struct device *dev, uint32_t channel, - const struct mbox_msg *msg) +static int nxp_imx_mu_send(const struct device *dev, uint32_t channel, const struct mbox_msg *msg) { uint32_t __aligned(4) data32; const struct nxp_imx_mu_config *cfg = dev->config; @@ -37,8 +41,7 @@ static int nxp_imx_mu_send(const struct device *dev, uint32_t channel, /* Signalling mode. */ if (msg == NULL) { - return MU_TriggerInterrupts( - cfg->base, kMU_GenInt0InterruptTrigger >> channel); + return MU_TriggerInterrupts(cfg->base, kMU_GenInt0InterruptTrigger >> channel); } /* Data transfer mode. */ @@ -54,7 +57,7 @@ static int nxp_imx_mu_send(const struct device *dev, uint32_t channel, } static int nxp_imx_mu_register_callback(const struct device *dev, uint32_t channel, - mbox_callback_t cb, void *user_data) + mbox_callback_t cb, void *user_data) { struct nxp_imx_mu_data *data = dev->data; @@ -80,8 +83,7 @@ static uint32_t nxp_imx_mu_max_channels_get(const struct device *dev) return MU_MAX_CHANNELS; } -static int nxp_imx_mu_set_enabled(const struct device *dev, uint32_t channel, - bool enable) +static int nxp_imx_mu_set_enabled(const struct device *dev, uint32_t channel, bool enable) { struct nxp_imx_mu_data *data = dev->data; const struct nxp_imx_mu_config *cfg = dev->config; @@ -94,17 +96,17 @@ static int nxp_imx_mu_set_enabled(const struct device *dev, uint32_t channel, if (data->cb[channel] == NULL) { LOG_WRN("Enabling channel without a registered callback"); } - MU_EnableInterrupts(cfg->base, - kMU_GenInt0InterruptEnable | kMU_GenInt1InterruptEnable | - kMU_GenInt2InterruptEnable | kMU_GenInt3InterruptEnable | - kMU_Rx0FullInterruptEnable | kMU_Rx1FullInterruptEnable | - kMU_Rx2FullInterruptEnable | kMU_Rx3FullInterruptEnable); + MU_EnableInterrupts( + cfg->base, kMU_GenInt0InterruptEnable | kMU_GenInt1InterruptEnable | + kMU_GenInt2InterruptEnable | kMU_GenInt3InterruptEnable | + kMU_Rx0FullInterruptEnable | kMU_Rx1FullInterruptEnable | + kMU_Rx2FullInterruptEnable | kMU_Rx3FullInterruptEnable); } else { - MU_DisableInterrupts(cfg->base, - kMU_GenInt0InterruptEnable | kMU_GenInt1InterruptEnable | - kMU_GenInt2InterruptEnable | kMU_GenInt3InterruptEnable | - kMU_Rx0FullInterruptEnable | kMU_Rx1FullInterruptEnable | - kMU_Rx2FullInterruptEnable | kMU_Rx3FullInterruptEnable); + MU_DisableInterrupts( + cfg->base, kMU_GenInt0InterruptEnable | kMU_GenInt1InterruptEnable | + kMU_GenInt2InterruptEnable | kMU_GenInt3InterruptEnable | + kMU_Rx0FullInterruptEnable | kMU_Rx1FullInterruptEnable | + kMU_Rx2FullInterruptEnable | kMU_Rx3FullInterruptEnable); } return 0; @@ -118,66 +120,62 @@ static const struct mbox_driver_api nxp_imx_mu_driver_api = { .set_enabled = nxp_imx_mu_set_enabled, }; -#define MU_INSTANCE_DEFINE(idx) \ - static struct nxp_imx_mu_data nxp_imx_mu_##idx##_data; \ - static struct nxp_imx_mu_config nxp_imx_mu_##idx##_config = { \ - .base = (MU_Type *)DT_INST_REG_ADDR(idx), \ - }; \ - \ - void MU_##idx##_IRQHandler(void); \ - static int nxp_imx_mu_##idx##_init(const struct device *dev) \ - { \ - ARG_UNUSED(dev); \ - MU_Init(nxp_imx_mu_##idx##_config.base); \ - IRQ_CONNECT(DT_INST_IRQN(idx), \ - DT_INST_IRQ(idx, priority), \ - MU_##idx##_IRQHandler, \ - NULL, \ - 0); \ - irq_enable(DT_INST_IRQN(idx)); \ - return 0; \ - } \ - DEVICE_DT_INST_DEFINE(idx, nxp_imx_mu_##idx##_init, NULL, \ - &nxp_imx_mu_##idx##_data, &nxp_imx_mu_##idx##_config, \ - POST_KERNEL, CONFIG_MBOX_INIT_PRIORITY, \ - &nxp_imx_mu_driver_api) - -#define MU_IRQ_HANDLER(idx) \ - static uint32_t mu_##idx##_received_data; \ - void MU_##idx##_IRQHandler(void) \ - { \ - const struct device *dev = DEVICE_DT_INST_GET(idx); \ - const struct nxp_imx_mu_data *data = dev->data; \ - const struct nxp_imx_mu_config *config = dev->config; \ - struct mbox_msg msg; \ - struct mbox_msg *callback_msg_ptr = NULL; \ - uint32_t flag = MU_GetStatusFlags(config->base); \ - \ - for (int i_channel = 0; i_channel < MU_MAX_CHANNELS; i_channel++) { \ - if ((flag & (kMU_Rx0FullFlag >> i_channel)) == \ - (kMU_Rx0FullFlag >> i_channel)) { \ - mu_##idx##_received_data = \ - MU_ReceiveMsgNonBlocking(config->base, 0); \ - msg.data = (const void *)&mu_##idx##_received_data; \ - msg.size = MU_MBOX_SIZE; \ - callback_msg_ptr = &msg; \ - } else if ((flag & (kMU_GenInt0Flag >> i_channel)) == \ - (kMU_GenInt0Flag >> i_channel)) { \ - MU_ClearStatusFlags(config->base, \ - (kMU_GenInt0Flag >> i_channel)); \ - callback_msg_ptr = NULL; \ - } \ - \ - if (data->cb[i_channel]) { \ - data->cb[i_channel](dev, i_channel, \ - data->user_data[i_channel], \ - callback_msg_ptr); \ - } \ - } \ +static void handle_irq(const struct device *dev); + +#define MU_INSTANCE_DEFINE(idx) \ + static struct nxp_imx_mu_data nxp_imx_mu_##idx##_data; \ + const static struct nxp_imx_mu_config nxp_imx_mu_##idx##_config = { \ + .base = (MU_Type *)DT_INST_REG_ADDR(idx), \ + }; \ + void MU_##idx##_IRQHandler(void); \ + static int nxp_imx_mu_##idx##_init(const struct device *dev) \ + { \ + ARG_UNUSED(dev); \ + MU_Init(nxp_imx_mu_##idx##_config.base); \ + IRQ_CONNECT(DT_INST_IRQN(idx), DT_INST_IRQ(idx, priority), MU_##idx##_IRQHandler, \ + NULL, 0); \ + irq_enable(DT_INST_IRQN(idx)); \ + return 0; \ + } \ + DEVICE_DT_INST_DEFINE(idx, nxp_imx_mu_##idx##_init, NULL, &nxp_imx_mu_##idx##_data, \ + &nxp_imx_mu_##idx##_config, POST_KERNEL, CONFIG_MBOX_INIT_PRIORITY, \ + &nxp_imx_mu_driver_api) + +#define MU_IRQ_HANDLER(idx) \ + void MU_##idx##_IRQHandler(void) \ + { \ + const struct device *dev = DEVICE_DT_INST_GET(idx); \ + handle_irq(dev); \ } -#define MU_INST(idx) \ - MU_INSTANCE_DEFINE(idx); \ +#define MU_INST(idx) \ + MU_INSTANCE_DEFINE(idx); \ MU_IRQ_HANDLER(idx); DT_INST_FOREACH_STATUS_OKAY(MU_INST) + +static void handle_irq(const struct device *dev) +{ + struct nxp_imx_mu_data *data = dev->data; + const struct nxp_imx_mu_config *config = dev->config; + const uint32_t flag = MU_GetStatusFlags(config->base); + + for (int i_channel = 0; i_channel < MU_MAX_CHANNELS; i_channel++) { + if ((flag & (kMU_Rx0FullFlag >> i_channel)) == (kMU_Rx0FullFlag >> i_channel)) { + data->received_data = MU_ReceiveMsgNonBlocking(config->base, i_channel); + struct mbox_msg msg = {(const void *)&data->received_data, MU_MBOX_SIZE}; + + if (data->cb[i_channel]) { + data->cb[i_channel](dev, i_channel, data->user_data[i_channel], + &msg); + } + } else if ((flag & (kMU_GenInt0Flag >> i_channel)) == + (kMU_GenInt0Flag >> i_channel)) { + MU_ClearStatusFlags(config->base, (kMU_GenInt0Flag >> i_channel)); + if (data->cb[i_channel]) { + data->cb[i_channel](dev, i_channel, data->user_data[i_channel], + NULL); + } + } + } +} From e776051cadfd9d723be6cbebeb2a41d2f94aec6a Mon Sep 17 00:00:00 2001 From: Tomas Galbicka Date: Fri, 12 Jan 2024 15:48:59 +0100 Subject: [PATCH 2643/3723] samples: mbox: Add mbox sample with data transfer This commits add mbox sample which supports transfering of 4 bytes of data between cores. Signed-off-by: Tomas Galbicka --- samples/drivers/mbox_data/CMakeLists.txt | 29 ++++++ samples/drivers/mbox_data/Kconfig | 11 +++ samples/drivers/mbox_data/Kconfig.sysbuild | 11 +++ samples/drivers/mbox_data/README.rst | 95 +++++++++++++++++++ .../mbox_data/boards/mimxrt1160_evk_cm7.conf | 3 + .../boards/mimxrt1160_evk_cm7.overlay | 29 ++++++ .../mbox_data/boards/mimxrt1170_evk_cm7.conf | 3 + .../boards/mimxrt1170_evk_cm7.overlay | 29 ++++++ .../mbox_data/boards/mimxrt1170_evkb_cm7.conf | 3 + .../boards/mimxrt1170_evkb_cm7.overlay | 29 ++++++ samples/drivers/mbox_data/prj.conf | 2 + .../drivers/mbox_data/remote/CMakeLists.txt | 20 ++++ .../remote/boards/mimxrt1160_evk_cm4.conf | 4 + .../remote/boards/mimxrt1160_evk_cm4.overlay | 54 +++++++++++ .../remote/boards/mimxrt1170_evk_cm4.conf | 4 + .../remote/boards/mimxrt1170_evk_cm4.overlay | 54 +++++++++++ .../remote/boards/mimxrt1170_evkb_cm4.conf | 4 + .../remote/boards/mimxrt1170_evkb_cm4.overlay | 55 +++++++++++ samples/drivers/mbox_data/remote/prj.conf | 2 + samples/drivers/mbox_data/remote/src/main.c | 75 +++++++++++++++ samples/drivers/mbox_data/sample.yaml | 27 ++++++ samples/drivers/mbox_data/src/main.c | 74 +++++++++++++++ samples/drivers/mbox_data/sysbuild.cmake | 28 ++++++ 23 files changed, 645 insertions(+) create mode 100644 samples/drivers/mbox_data/CMakeLists.txt create mode 100644 samples/drivers/mbox_data/Kconfig create mode 100644 samples/drivers/mbox_data/Kconfig.sysbuild create mode 100644 samples/drivers/mbox_data/README.rst create mode 100644 samples/drivers/mbox_data/boards/mimxrt1160_evk_cm7.conf create mode 100644 samples/drivers/mbox_data/boards/mimxrt1160_evk_cm7.overlay create mode 100644 samples/drivers/mbox_data/boards/mimxrt1170_evk_cm7.conf create mode 100644 samples/drivers/mbox_data/boards/mimxrt1170_evk_cm7.overlay create mode 100644 samples/drivers/mbox_data/boards/mimxrt1170_evkb_cm7.conf create mode 100644 samples/drivers/mbox_data/boards/mimxrt1170_evkb_cm7.overlay create mode 100644 samples/drivers/mbox_data/prj.conf create mode 100644 samples/drivers/mbox_data/remote/CMakeLists.txt create mode 100644 samples/drivers/mbox_data/remote/boards/mimxrt1160_evk_cm4.conf create mode 100644 samples/drivers/mbox_data/remote/boards/mimxrt1160_evk_cm4.overlay create mode 100644 samples/drivers/mbox_data/remote/boards/mimxrt1170_evk_cm4.conf create mode 100644 samples/drivers/mbox_data/remote/boards/mimxrt1170_evk_cm4.overlay create mode 100644 samples/drivers/mbox_data/remote/boards/mimxrt1170_evkb_cm4.conf create mode 100644 samples/drivers/mbox_data/remote/boards/mimxrt1170_evkb_cm4.overlay create mode 100644 samples/drivers/mbox_data/remote/prj.conf create mode 100644 samples/drivers/mbox_data/remote/src/main.c create mode 100644 samples/drivers/mbox_data/sample.yaml create mode 100644 samples/drivers/mbox_data/src/main.c create mode 100644 samples/drivers/mbox_data/sysbuild.cmake diff --git a/samples/drivers/mbox_data/CMakeLists.txt b/samples/drivers/mbox_data/CMakeLists.txt new file mode 100644 index 00000000000..a67552bf52e --- /dev/null +++ b/samples/drivers/mbox_data/CMakeLists.txt @@ -0,0 +1,29 @@ +# Copyright 2024 NXP +# +# SPDX-License-Identifier: Apache-2.0 +# + +cmake_minimum_required(VERSION 3.20.0) + +find_package(Zephyr REQUIRED HINTS $ENV{ZEPHYR_BASE}) + +set(REMOTE_ZEPHYR_DIR ${CMAKE_CURRENT_BINARY_DIR}/../remote/zephyr) + +if(("${BOARD}" STREQUAL "mimxrt1170_evkb_cm7") OR + ("${BOARD}" STREQUAL "mimxrt1170_evk_cm7") OR + ("${BOARD}" STREQUAL "mimxrt1160_evk_cm7")) + message(STATUS "${BOARD} compile as Main in this sample") +else() + message(FATAL_ERROR "${BOARD} is not supported for this sample") +endif() + +project(mbox_data_ipc) + +enable_language(C ASM) + +if(CONFIG_INCLUDE_REMOTE_DIR) + target_include_directories(zephyr_interface + INTERFACE ${REMOTE_ZEPHYR_DIR}/include/public) +endif() + +target_sources(app PRIVATE src/main.c) diff --git a/samples/drivers/mbox_data/Kconfig b/samples/drivers/mbox_data/Kconfig new file mode 100644 index 00000000000..ee3874c39f9 --- /dev/null +++ b/samples/drivers/mbox_data/Kconfig @@ -0,0 +1,11 @@ +# Copyright 2024 NXP +# +# SPDX-License-Identifier: Apache-2.0 + +source "Kconfig.zephyr" + +config INCLUDE_REMOTE_DIR + bool "Include remote core header directory" + help + Include remote build header files. Can be used if primary image + needs to be aware of size or base address of secondary image diff --git a/samples/drivers/mbox_data/Kconfig.sysbuild b/samples/drivers/mbox_data/Kconfig.sysbuild new file mode 100644 index 00000000000..e355713e714 --- /dev/null +++ b/samples/drivers/mbox_data/Kconfig.sysbuild @@ -0,0 +1,11 @@ +# Copyright 2024 NXP +# +# SPDX-License-Identifier: Apache-2.0 + +source "share/sysbuild/Kconfig" + +config REMOTE_BOARD +string + default "mimxrt1170_evkb_cm4" if $(BOARD) = "mimxrt1170_evkb_cm7" + default "mimxrt1170_evk_cm4" if $(BOARD) = "mimxrt1170_evk_cm7" + default "mimxrt1160_evk_cm4" if $(BOARD) = "mimxrt1160_evk_cm7" diff --git a/samples/drivers/mbox_data/README.rst b/samples/drivers/mbox_data/README.rst new file mode 100644 index 00000000000..3ead1ec3b87 --- /dev/null +++ b/samples/drivers/mbox_data/README.rst @@ -0,0 +1,95 @@ +.. zephyr:code-sample:: mbox_data + :name: MBOX Data + :relevant-api: mbox_interface + + Perform inter-processor mailbox communication using the MBOX API with data. + +Overview +******** + +This sample demonstrates how to use the :ref:`MBOX API ` in data transfer mode. +It can be used only with mbox driver which supports data transfer mode. + +Sample will ping-pong 4 bytes of data between two cores via two mbox channels. +After each core receives data, it increments it by one and sends it back to other core. + +Building and Running +******************** + +The sample can be built and executed on boards supporting MBOX with data transfer mode. + +Building the application for mimxrt1160_evk_cm7 +=============================================== + +.. zephyr-app-commands:: + :zephyr-app: samples/drivers/mbox_data/ + :board: mimxrt1160_evk_cm7 + :goals: debug + :west-args: --sysbuild + +Building the application for mimxrt1170_evk_cm7 +=============================================== + +.. zephyr-app-commands:: + :zephyr-app: samples/drivers/mbox_data/ + :board: mimxrt1170_evk_cm7 + :goals: debug + :west-args: --sysbuild + +Building the application for mimxrt1170_evkb_cm7 +================================================ + +.. zephyr-app-commands:: + :zephyr-app: samples/drivers/mbox_data/ + :board: mimxrt1170_evkb_cm7 + :goals: debug + :west-args: --sysbuild + +Sample Output +============= + +Open a serial terminal (minicom, putty, etc.) and connect the board with the +following settings: + +- Speed: 115200 +- Data: 8 bits +- Parity: None +- Stop bits: 1 + +Reset the board and the following message will appear on the corresponding +serial port, one is the main core another is the remote core: + +.. code-block:: console + + *** Booting Zephyr OS build zephyr-v3.5.0-4051-g12f4f4dc8679 *** + mbox_data Client demo started + Client send (on channel 3) value: 0 + Client received (on channel 2) value: 1 + Client send (on channel 3) value: 2 + Client received (on channel 2) value: 3 + Client send (on channel 3) value: 4 + ... + Client received (on channel 2) value: 95 + Client send (on channel 3) value: 96 + Client received (on channel 2) value: 97 + Client send (on channel 3) value: 98 + Client received (on channel 2) value: 99 + mbox_data Client demo ended + + +.. code-block:: console + + *** Booting Zephyr OS build zephyr-v3.5.0-4051-g12f4f4dc8679 *** + mbox_data Server demo started + Server receive (on channel 3) value: 0 + Server send (on channel 2) value: 1 + Server receive (on channel 3) value: 2 + Server send (on channel 2) value: 3 + Server receive (on channel 3) value: 4 + ... + Server send (on channel 2) value: 95 + Server receive (on channel 3) value: 96 + Server send (on channel 2) value: 97 + Server receive (on channel 3) value: 98 + Server send (on channel 2) value: 99 + mbox_data Server demo ended. diff --git a/samples/drivers/mbox_data/boards/mimxrt1160_evk_cm7.conf b/samples/drivers/mbox_data/boards/mimxrt1160_evk_cm7.conf new file mode 100644 index 00000000000..583b4950360 --- /dev/null +++ b/samples/drivers/mbox_data/boards/mimxrt1160_evk_cm7.conf @@ -0,0 +1,3 @@ +CONFIG_MBOX_NXP_IMX_MU=y +CONFIG_INCLUDE_REMOTE_DIR=y +CONFIG_SECOND_CORE_MCUX=y diff --git a/samples/drivers/mbox_data/boards/mimxrt1160_evk_cm7.overlay b/samples/drivers/mbox_data/boards/mimxrt1160_evk_cm7.overlay new file mode 100644 index 00000000000..870b9928faf --- /dev/null +++ b/samples/drivers/mbox_data/boards/mimxrt1160_evk_cm7.overlay @@ -0,0 +1,29 @@ +/* + * Copyright 2024 NXP + * + * SPDX-License-Identifier: Apache-2.0 + */ + +/ { + chosen { + /* Delete ipc chosen property where old IPM mailbox driver bellow is + * configured. + */ + /delete-property/ zephyr,ipc; + }; + + soc { + /* Delete IPM Driver node nxp,imx-mu */ + /delete-node/ mailbox@40c48000; + + /* Attach MBOX driver to MU Unit */ + mbox:mbox@40c48000 { + compatible = "nxp,mbox-imx-mu"; + reg = <0x40c48000 0x4000>; + interrupts = <118 0>; + rx-channels = <4>; + #mbox-cells = <1>; + status = "okay"; + }; + }; +}; diff --git a/samples/drivers/mbox_data/boards/mimxrt1170_evk_cm7.conf b/samples/drivers/mbox_data/boards/mimxrt1170_evk_cm7.conf new file mode 100644 index 00000000000..583b4950360 --- /dev/null +++ b/samples/drivers/mbox_data/boards/mimxrt1170_evk_cm7.conf @@ -0,0 +1,3 @@ +CONFIG_MBOX_NXP_IMX_MU=y +CONFIG_INCLUDE_REMOTE_DIR=y +CONFIG_SECOND_CORE_MCUX=y diff --git a/samples/drivers/mbox_data/boards/mimxrt1170_evk_cm7.overlay b/samples/drivers/mbox_data/boards/mimxrt1170_evk_cm7.overlay new file mode 100644 index 00000000000..870b9928faf --- /dev/null +++ b/samples/drivers/mbox_data/boards/mimxrt1170_evk_cm7.overlay @@ -0,0 +1,29 @@ +/* + * Copyright 2024 NXP + * + * SPDX-License-Identifier: Apache-2.0 + */ + +/ { + chosen { + /* Delete ipc chosen property where old IPM mailbox driver bellow is + * configured. + */ + /delete-property/ zephyr,ipc; + }; + + soc { + /* Delete IPM Driver node nxp,imx-mu */ + /delete-node/ mailbox@40c48000; + + /* Attach MBOX driver to MU Unit */ + mbox:mbox@40c48000 { + compatible = "nxp,mbox-imx-mu"; + reg = <0x40c48000 0x4000>; + interrupts = <118 0>; + rx-channels = <4>; + #mbox-cells = <1>; + status = "okay"; + }; + }; +}; diff --git a/samples/drivers/mbox_data/boards/mimxrt1170_evkb_cm7.conf b/samples/drivers/mbox_data/boards/mimxrt1170_evkb_cm7.conf new file mode 100644 index 00000000000..0dfb100ed70 --- /dev/null +++ b/samples/drivers/mbox_data/boards/mimxrt1170_evkb_cm7.conf @@ -0,0 +1,3 @@ +CONFIG_MBOX_NXP_IMX_MU=y +CONFIG_SECOND_CORE_MCUX=y +CONFIG_INCLUDE_REMOTE_DIR=y diff --git a/samples/drivers/mbox_data/boards/mimxrt1170_evkb_cm7.overlay b/samples/drivers/mbox_data/boards/mimxrt1170_evkb_cm7.overlay new file mode 100644 index 00000000000..870b9928faf --- /dev/null +++ b/samples/drivers/mbox_data/boards/mimxrt1170_evkb_cm7.overlay @@ -0,0 +1,29 @@ +/* + * Copyright 2024 NXP + * + * SPDX-License-Identifier: Apache-2.0 + */ + +/ { + chosen { + /* Delete ipc chosen property where old IPM mailbox driver bellow is + * configured. + */ + /delete-property/ zephyr,ipc; + }; + + soc { + /* Delete IPM Driver node nxp,imx-mu */ + /delete-node/ mailbox@40c48000; + + /* Attach MBOX driver to MU Unit */ + mbox:mbox@40c48000 { + compatible = "nxp,mbox-imx-mu"; + reg = <0x40c48000 0x4000>; + interrupts = <118 0>; + rx-channels = <4>; + #mbox-cells = <1>; + status = "okay"; + }; + }; +}; diff --git a/samples/drivers/mbox_data/prj.conf b/samples/drivers/mbox_data/prj.conf new file mode 100644 index 00000000000..293e2834f25 --- /dev/null +++ b/samples/drivers/mbox_data/prj.conf @@ -0,0 +1,2 @@ +CONFIG_PRINTK=y +CONFIG_MBOX=y diff --git a/samples/drivers/mbox_data/remote/CMakeLists.txt b/samples/drivers/mbox_data/remote/CMakeLists.txt new file mode 100644 index 00000000000..31f6db9b641 --- /dev/null +++ b/samples/drivers/mbox_data/remote/CMakeLists.txt @@ -0,0 +1,20 @@ +# Copyright 2024 NXP +# +# SPDX-License-Identifier: Apache-2.0 +# + +cmake_minimum_required(VERSION 3.20.0) + +find_package(Zephyr REQUIRED HINTS $ENV{ZEPHYR_BASE}) + +if(("${BOARD}" STREQUAL "mimxrt1170_evkb_cm4") OR + ("${BOARD}" STREQUAL "mimxrt1170_evk_cm4") OR + ("${BOARD}" STREQUAL "mimxrt1160_evk_cm4")) + message(STATUS "${BOARD} compile as remote in this sample") +else() + message(FATAL_ERROR "${BOARD} is not supported for this sample") +endif() + +project(mbox_data_ipc_remote) + +target_sources(app PRIVATE src/main.c) diff --git a/samples/drivers/mbox_data/remote/boards/mimxrt1160_evk_cm4.conf b/samples/drivers/mbox_data/remote/boards/mimxrt1160_evk_cm4.conf new file mode 100644 index 00000000000..0d36a72aec6 --- /dev/null +++ b/samples/drivers/mbox_data/remote/boards/mimxrt1160_evk_cm4.conf @@ -0,0 +1,4 @@ +CONFIG_MBOX_NXP_IMX_MU=y +CONFIG_BUILD_OUTPUT_INFO_HEADER=y +CONFIG_BUILD_OUTPUT_HEX=y +CONFIG_SECOND_CORE_MCUX=y diff --git a/samples/drivers/mbox_data/remote/boards/mimxrt1160_evk_cm4.overlay b/samples/drivers/mbox_data/remote/boards/mimxrt1160_evk_cm4.overlay new file mode 100644 index 00000000000..3f6115b9c58 --- /dev/null +++ b/samples/drivers/mbox_data/remote/boards/mimxrt1160_evk_cm4.overlay @@ -0,0 +1,54 @@ +/* + * Copyright 2024 NXP + * + * SPDX-License-Identifier: Apache-2.0 + */ + +/ { + chosen { + zephyr,flash = &ocram; + zephyr,console = &lpuart2; + zephyr,shell-uart = &lpuart2; + + /* Delete ipc chosen property where old IPM mailbox driver bellow is + * configured. + */ + /delete-property/ zephyr,ipc; + }; + + soc { + /delete-node/ gpt@400f0000; + + /* Replace GPT2 with another GPT kernel timer */ + gpt2_hw_timer:gpt@400f0000 { + compatible = "nxp,gpt-hw-timer"; + reg = <0x400f0000 0x4000>; + interrupts = <120 0>; + status = "okay"; + }; + + /* Delete IPM Driver node nxp,imx-mu */ + /delete-node/ mailbox@40c4c000; + + /* Attach MBOX driver to MU Unit */ + mbox:mbox@40c4c000 { + compatible = "nxp,mbox-imx-mu"; + reg = <0x40c4c000 0x4000>; + interrupts = <118 0>; + rx-channels = <4>; + #mbox-cells = <1>; + status = "okay"; + }; + }; +}; + +/* Enable secondary LPUART */ +&lpuart2 { + status = "okay"; + current-speed = <115200>; +}; + +/* Disable primary GPT timer */ +&gpt_hw_timer { + status = "disabled"; +}; diff --git a/samples/drivers/mbox_data/remote/boards/mimxrt1170_evk_cm4.conf b/samples/drivers/mbox_data/remote/boards/mimxrt1170_evk_cm4.conf new file mode 100644 index 00000000000..0d36a72aec6 --- /dev/null +++ b/samples/drivers/mbox_data/remote/boards/mimxrt1170_evk_cm4.conf @@ -0,0 +1,4 @@ +CONFIG_MBOX_NXP_IMX_MU=y +CONFIG_BUILD_OUTPUT_INFO_HEADER=y +CONFIG_BUILD_OUTPUT_HEX=y +CONFIG_SECOND_CORE_MCUX=y diff --git a/samples/drivers/mbox_data/remote/boards/mimxrt1170_evk_cm4.overlay b/samples/drivers/mbox_data/remote/boards/mimxrt1170_evk_cm4.overlay new file mode 100644 index 00000000000..3f6115b9c58 --- /dev/null +++ b/samples/drivers/mbox_data/remote/boards/mimxrt1170_evk_cm4.overlay @@ -0,0 +1,54 @@ +/* + * Copyright 2024 NXP + * + * SPDX-License-Identifier: Apache-2.0 + */ + +/ { + chosen { + zephyr,flash = &ocram; + zephyr,console = &lpuart2; + zephyr,shell-uart = &lpuart2; + + /* Delete ipc chosen property where old IPM mailbox driver bellow is + * configured. + */ + /delete-property/ zephyr,ipc; + }; + + soc { + /delete-node/ gpt@400f0000; + + /* Replace GPT2 with another GPT kernel timer */ + gpt2_hw_timer:gpt@400f0000 { + compatible = "nxp,gpt-hw-timer"; + reg = <0x400f0000 0x4000>; + interrupts = <120 0>; + status = "okay"; + }; + + /* Delete IPM Driver node nxp,imx-mu */ + /delete-node/ mailbox@40c4c000; + + /* Attach MBOX driver to MU Unit */ + mbox:mbox@40c4c000 { + compatible = "nxp,mbox-imx-mu"; + reg = <0x40c4c000 0x4000>; + interrupts = <118 0>; + rx-channels = <4>; + #mbox-cells = <1>; + status = "okay"; + }; + }; +}; + +/* Enable secondary LPUART */ +&lpuart2 { + status = "okay"; + current-speed = <115200>; +}; + +/* Disable primary GPT timer */ +&gpt_hw_timer { + status = "disabled"; +}; diff --git a/samples/drivers/mbox_data/remote/boards/mimxrt1170_evkb_cm4.conf b/samples/drivers/mbox_data/remote/boards/mimxrt1170_evkb_cm4.conf new file mode 100644 index 00000000000..0d36a72aec6 --- /dev/null +++ b/samples/drivers/mbox_data/remote/boards/mimxrt1170_evkb_cm4.conf @@ -0,0 +1,4 @@ +CONFIG_MBOX_NXP_IMX_MU=y +CONFIG_BUILD_OUTPUT_INFO_HEADER=y +CONFIG_BUILD_OUTPUT_HEX=y +CONFIG_SECOND_CORE_MCUX=y diff --git a/samples/drivers/mbox_data/remote/boards/mimxrt1170_evkb_cm4.overlay b/samples/drivers/mbox_data/remote/boards/mimxrt1170_evkb_cm4.overlay new file mode 100644 index 00000000000..e3576826702 --- /dev/null +++ b/samples/drivers/mbox_data/remote/boards/mimxrt1170_evkb_cm4.overlay @@ -0,0 +1,55 @@ +/* + * Copyright 2024 NXP + * + * SPDX-License-Identifier: Apache-2.0 + */ + +/ { + chosen { + zephyr,flash = &ocram; + zephyr,console = &lpuart2; + zephyr,shell-uart = &lpuart2; + + /* Delete ipc chosen property where old IPM mailbox driver bellow is + * configured. + */ + /delete-property/ zephyr,ipc; + }; + + soc { + /delete-node/ gpt@400f0000; + + /* Replace GPT2 with another GPT kernel timer */ + gpt2_hw_timer:gpt@400f0000 { + compatible = "nxp,gpt-hw-timer"; + reg = <0x400f0000 0x4000>; + interrupts = <120 0>; + status = "okay"; + }; + + /* Delete IPM Driver node nxp,imx-mu */ + /delete-node/ mailbox@40c4c000; + + /* Attach MBOX driver to MU Unit */ + mbox:mbox@40c4c000 { + compatible = "nxp,mbox-imx-mu"; + reg = <0x40c4c000 0x4000>; + interrupts = <118 0>; + rx-channels = <4>; + #mbox-cells = <1>; + status = "okay"; + }; + }; + +}; + +/* Enable secondary LPUART */ +&lpuart2 { + status = "okay"; + current-speed = <115200>; +}; + +/* Disable primary GPT timer */ +&gpt_hw_timer { + status = "disabled"; +}; diff --git a/samples/drivers/mbox_data/remote/prj.conf b/samples/drivers/mbox_data/remote/prj.conf new file mode 100644 index 00000000000..473e4280601 --- /dev/null +++ b/samples/drivers/mbox_data/remote/prj.conf @@ -0,0 +1,2 @@ +CONFIG_STDOUT_CONSOLE=n +CONFIG_MBOX=y diff --git a/samples/drivers/mbox_data/remote/src/main.c b/samples/drivers/mbox_data/remote/src/main.c new file mode 100644 index 00000000000..9fccf155c23 --- /dev/null +++ b/samples/drivers/mbox_data/remote/src/main.c @@ -0,0 +1,75 @@ +/* + * Copyright 2024 NXP + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include +#include +#include +#include + +static K_SEM_DEFINE(g_mbox_data_rx_sem, 0, 1); + +static uint32_t g_mbox_received_data; +static uint32_t g_mbox_received_channel; + +#define TX_ID (2) +#define RX_ID (3) + +static void callback(const struct device *dev, uint32_t channel, void *user_data, + struct mbox_msg *data) +{ + memcpy(&g_mbox_received_data, data->data, data->size); + g_mbox_received_channel = channel; + + k_sem_give(&g_mbox_data_rx_sem); +} + +int main(void) +{ + struct mbox_channel tx_channel; + struct mbox_channel rx_channel; + const struct device *dev; + struct mbox_msg msg = {0}; + uint32_t message = 0; + + printk("mbox_data Server demo started\n"); + + dev = DEVICE_DT_GET(DT_NODELABEL(mbox)); + + mbox_init_channel(&tx_channel, dev, TX_ID); + mbox_init_channel(&rx_channel, dev, RX_ID); + + if (mbox_register_callback(&rx_channel, callback, NULL)) { + printk("mbox_register_callback() error\n"); + return 0; + } + + if (mbox_set_enabled(&rx_channel, 1)) { + printk("mbox_set_enable() error\n"); + return 0; + } + + while (message < 99) { + k_sem_take(&g_mbox_data_rx_sem, K_FOREVER); + message = g_mbox_received_data; + + printk("Server receive (on channel %d) value: %d\n", g_mbox_received_channel, + g_mbox_received_data); + + message++; + + msg.data = &message; + msg.size = 4; + + printk("Server send (on channel %d) value: %d\n", tx_channel.id, message); + if (mbox_send(&tx_channel, &msg) < 0) { + printk("mbox_send() error\n"); + return 0; + } + } + + printk("mbox_data Server demo ended.\n"); + return 0; +} diff --git a/samples/drivers/mbox_data/sample.yaml b/samples/drivers/mbox_data/sample.yaml new file mode 100644 index 00000000000..5484233b2e8 --- /dev/null +++ b/samples/drivers/mbox_data/sample.yaml @@ -0,0 +1,27 @@ +sample: + name: MBOX Data IPC sample +common: + sysbuild: true + tags: mbox +tests: + sample.drivers.mbox_data.real_hw: + platform_allow: + - mimxrt1170_evkb_cm7 + - mimxrt1170_evk_cm7 + - mimxrt1160_evk_cm7 + integration_platforms: + - mimxrt1160_evk_cm7 + harness: console + harness_config: + type: multi_line + ordered: false + regex: + - "Client received \\(on channel 2\\) value: 1" + - "Client send \\(on channel 3\\) value: 2" + - "Client received \\(on channel 2\\) value: 3" + - "Client send \\(on channel 3\\) value: 4" + - "Client received \\(on channel 2\\) value: 41" + - "Client send \\(on channel 3\\) value: 42" + - "Client received \\(on channel 2\\) value: 97" + - "Client send \\(on channel 3\\) value: 98" + - "Client received \\(on channel 2\\) value: 99" diff --git a/samples/drivers/mbox_data/src/main.c b/samples/drivers/mbox_data/src/main.c new file mode 100644 index 00000000000..27c29b07554 --- /dev/null +++ b/samples/drivers/mbox_data/src/main.c @@ -0,0 +1,74 @@ +/* + * Copyright 2024 NXP + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include +#include +#include +#include + +static K_SEM_DEFINE(g_mbox_data_rx_sem, 0, 1); + +static uint32_t g_mbox_received_data; +static uint32_t g_mbox_received_channel; + +#define TX_ID (3) +#define RX_ID (2) + +static void callback(const struct device *dev, uint32_t channel, void *user_data, + struct mbox_msg *data) +{ + memcpy(&g_mbox_received_data, data->data, data->size); + g_mbox_received_channel = channel; + + k_sem_give(&g_mbox_data_rx_sem); +} + +int main(void) +{ + struct mbox_channel tx_channel; + struct mbox_channel rx_channel; + const struct device *dev; + struct mbox_msg msg = {0}; + uint32_t message = 0; + + printk("mbox_data Client demo started\n"); + + dev = DEVICE_DT_GET(DT_NODELABEL(mbox)); + + mbox_init_channel(&tx_channel, dev, TX_ID); + mbox_init_channel(&rx_channel, dev, RX_ID); + + if (mbox_register_callback(&rx_channel, callback, NULL)) { + printk("mbox_register_callback() error\n"); + return 0; + } + + if (mbox_set_enabled(&rx_channel, 1)) { + printk("mbox_set_enable() error\n"); + return 0; + } + + while (message < 100) { + msg.data = &message; + msg.size = 4; + + printk("Client send (on channel %d) value: %d\n", tx_channel.id, message); + if (mbox_send(&tx_channel, &msg) < 0) { + printk("mbox_send() error\n"); + return 0; + } + + k_sem_take(&g_mbox_data_rx_sem, K_FOREVER); + message = g_mbox_received_data; + + printk("Client received (on channel %d) value: %d\n", g_mbox_received_channel, + message); + message++; + } + + printk("mbox_data Client demo ended\n"); + return 0; +} diff --git a/samples/drivers/mbox_data/sysbuild.cmake b/samples/drivers/mbox_data/sysbuild.cmake new file mode 100644 index 00000000000..5c536a6229a --- /dev/null +++ b/samples/drivers/mbox_data/sysbuild.cmake @@ -0,0 +1,28 @@ +# Copyright 2024 NXP +# +# SPDX-License-Identifier: Apache-2.0 + +if("${SB_CONFIG_REMOTE_BOARD}" STREQUAL "") + message(FATAL_ERROR + "Target ${BOARD} not supported for this sample. " + "There is no remote board selected in Kconfig.sysbuild") +endif() + +set(REMOTE_APP remote) + +ExternalZephyrProject_Add( + APPLICATION ${REMOTE_APP} + SOURCE_DIR ${APP_DIR}/${REMOTE_APP} + BOARD ${SB_CONFIG_REMOTE_BOARD} +) + +if ("${BOARD}" STREQUAL "mimxrt1170_evkb_cm7" OR + "${BOARD}" STREQUAL "mimxrt1170_evk_cm7" OR + "${BOARD}" STREQUAL "mimxrt1160_evk_cm7" + ) + # For these NXP boards the main core application is dependent on + # 'zephyr_image_info.h' generated by remote application. + + # Let's build the remote application first + add_dependencies(${DEFAULT_IMAGE} ${REMOTE_APP}) +endif() From 554f2ba08e13f48571c3b91c824b4be41c4848b6 Mon Sep 17 00:00:00 2001 From: Tomas Galbicka Date: Fri, 12 Jan 2024 15:50:35 +0100 Subject: [PATCH 2644/3723] tests: mbox: Add test for mbox with data transfer This commit adds extended test for mbox driver with data transfer to verify correct mbox functionality. Signed-off-by: Tomas Galbicka --- tests/drivers/mbox/mbox_data/CMakeLists.txt | 29 +++ tests/drivers/mbox/mbox_data/Kconfig | 11 ++ tests/drivers/mbox/mbox_data/Kconfig.sysbuild | 11 ++ .../mbox_data/boards/mimxrt1160_evk_cm7.conf | 3 + .../boards/mimxrt1160_evk_cm7.overlay | 29 +++ .../mbox_data/boards/mimxrt1170_evk_cm7.conf | 3 + .../boards/mimxrt1170_evk_cm7.overlay | 29 +++ .../mbox_data/boards/mimxrt1170_evkb_cm7.conf | 3 + .../boards/mimxrt1170_evkb_cm7.overlay | 29 +++ tests/drivers/mbox/mbox_data/prj.conf | 3 + .../mbox/mbox_data/remote/CMakeLists.txt | 20 ++ .../remote/boards/mimxrt1160_evk_cm4.conf | 4 + .../remote/boards/mimxrt1160_evk_cm4.overlay | 54 +++++ .../remote/boards/mimxrt1170_evk_cm4.conf | 4 + .../remote/boards/mimxrt1170_evk_cm4.overlay | 54 +++++ .../remote/boards/mimxrt1170_evkb_cm4.conf | 4 + .../remote/boards/mimxrt1170_evkb_cm4.overlay | 55 ++++++ tests/drivers/mbox/mbox_data/remote/prj.conf | 3 + .../drivers/mbox/mbox_data/remote/src/main.c | 91 +++++++++ tests/drivers/mbox/mbox_data/src/main.c | 184 ++++++++++++++++++ tests/drivers/mbox/mbox_data/sysbuild.cmake | 28 +++ tests/drivers/mbox/mbox_data/testcase.yaml | 12 ++ 22 files changed, 663 insertions(+) create mode 100644 tests/drivers/mbox/mbox_data/CMakeLists.txt create mode 100644 tests/drivers/mbox/mbox_data/Kconfig create mode 100644 tests/drivers/mbox/mbox_data/Kconfig.sysbuild create mode 100644 tests/drivers/mbox/mbox_data/boards/mimxrt1160_evk_cm7.conf create mode 100644 tests/drivers/mbox/mbox_data/boards/mimxrt1160_evk_cm7.overlay create mode 100644 tests/drivers/mbox/mbox_data/boards/mimxrt1170_evk_cm7.conf create mode 100644 tests/drivers/mbox/mbox_data/boards/mimxrt1170_evk_cm7.overlay create mode 100644 tests/drivers/mbox/mbox_data/boards/mimxrt1170_evkb_cm7.conf create mode 100644 tests/drivers/mbox/mbox_data/boards/mimxrt1170_evkb_cm7.overlay create mode 100644 tests/drivers/mbox/mbox_data/prj.conf create mode 100644 tests/drivers/mbox/mbox_data/remote/CMakeLists.txt create mode 100644 tests/drivers/mbox/mbox_data/remote/boards/mimxrt1160_evk_cm4.conf create mode 100644 tests/drivers/mbox/mbox_data/remote/boards/mimxrt1160_evk_cm4.overlay create mode 100644 tests/drivers/mbox/mbox_data/remote/boards/mimxrt1170_evk_cm4.conf create mode 100644 tests/drivers/mbox/mbox_data/remote/boards/mimxrt1170_evk_cm4.overlay create mode 100644 tests/drivers/mbox/mbox_data/remote/boards/mimxrt1170_evkb_cm4.conf create mode 100644 tests/drivers/mbox/mbox_data/remote/boards/mimxrt1170_evkb_cm4.overlay create mode 100644 tests/drivers/mbox/mbox_data/remote/prj.conf create mode 100644 tests/drivers/mbox/mbox_data/remote/src/main.c create mode 100644 tests/drivers/mbox/mbox_data/src/main.c create mode 100644 tests/drivers/mbox/mbox_data/sysbuild.cmake create mode 100644 tests/drivers/mbox/mbox_data/testcase.yaml diff --git a/tests/drivers/mbox/mbox_data/CMakeLists.txt b/tests/drivers/mbox/mbox_data/CMakeLists.txt new file mode 100644 index 00000000000..a67552bf52e --- /dev/null +++ b/tests/drivers/mbox/mbox_data/CMakeLists.txt @@ -0,0 +1,29 @@ +# Copyright 2024 NXP +# +# SPDX-License-Identifier: Apache-2.0 +# + +cmake_minimum_required(VERSION 3.20.0) + +find_package(Zephyr REQUIRED HINTS $ENV{ZEPHYR_BASE}) + +set(REMOTE_ZEPHYR_DIR ${CMAKE_CURRENT_BINARY_DIR}/../remote/zephyr) + +if(("${BOARD}" STREQUAL "mimxrt1170_evkb_cm7") OR + ("${BOARD}" STREQUAL "mimxrt1170_evk_cm7") OR + ("${BOARD}" STREQUAL "mimxrt1160_evk_cm7")) + message(STATUS "${BOARD} compile as Main in this sample") +else() + message(FATAL_ERROR "${BOARD} is not supported for this sample") +endif() + +project(mbox_data_ipc) + +enable_language(C ASM) + +if(CONFIG_INCLUDE_REMOTE_DIR) + target_include_directories(zephyr_interface + INTERFACE ${REMOTE_ZEPHYR_DIR}/include/public) +endif() + +target_sources(app PRIVATE src/main.c) diff --git a/tests/drivers/mbox/mbox_data/Kconfig b/tests/drivers/mbox/mbox_data/Kconfig new file mode 100644 index 00000000000..ee3874c39f9 --- /dev/null +++ b/tests/drivers/mbox/mbox_data/Kconfig @@ -0,0 +1,11 @@ +# Copyright 2024 NXP +# +# SPDX-License-Identifier: Apache-2.0 + +source "Kconfig.zephyr" + +config INCLUDE_REMOTE_DIR + bool "Include remote core header directory" + help + Include remote build header files. Can be used if primary image + needs to be aware of size or base address of secondary image diff --git a/tests/drivers/mbox/mbox_data/Kconfig.sysbuild b/tests/drivers/mbox/mbox_data/Kconfig.sysbuild new file mode 100644 index 00000000000..e355713e714 --- /dev/null +++ b/tests/drivers/mbox/mbox_data/Kconfig.sysbuild @@ -0,0 +1,11 @@ +# Copyright 2024 NXP +# +# SPDX-License-Identifier: Apache-2.0 + +source "share/sysbuild/Kconfig" + +config REMOTE_BOARD +string + default "mimxrt1170_evkb_cm4" if $(BOARD) = "mimxrt1170_evkb_cm7" + default "mimxrt1170_evk_cm4" if $(BOARD) = "mimxrt1170_evk_cm7" + default "mimxrt1160_evk_cm4" if $(BOARD) = "mimxrt1160_evk_cm7" diff --git a/tests/drivers/mbox/mbox_data/boards/mimxrt1160_evk_cm7.conf b/tests/drivers/mbox/mbox_data/boards/mimxrt1160_evk_cm7.conf new file mode 100644 index 00000000000..583b4950360 --- /dev/null +++ b/tests/drivers/mbox/mbox_data/boards/mimxrt1160_evk_cm7.conf @@ -0,0 +1,3 @@ +CONFIG_MBOX_NXP_IMX_MU=y +CONFIG_INCLUDE_REMOTE_DIR=y +CONFIG_SECOND_CORE_MCUX=y diff --git a/tests/drivers/mbox/mbox_data/boards/mimxrt1160_evk_cm7.overlay b/tests/drivers/mbox/mbox_data/boards/mimxrt1160_evk_cm7.overlay new file mode 100644 index 00000000000..870b9928faf --- /dev/null +++ b/tests/drivers/mbox/mbox_data/boards/mimxrt1160_evk_cm7.overlay @@ -0,0 +1,29 @@ +/* + * Copyright 2024 NXP + * + * SPDX-License-Identifier: Apache-2.0 + */ + +/ { + chosen { + /* Delete ipc chosen property where old IPM mailbox driver bellow is + * configured. + */ + /delete-property/ zephyr,ipc; + }; + + soc { + /* Delete IPM Driver node nxp,imx-mu */ + /delete-node/ mailbox@40c48000; + + /* Attach MBOX driver to MU Unit */ + mbox:mbox@40c48000 { + compatible = "nxp,mbox-imx-mu"; + reg = <0x40c48000 0x4000>; + interrupts = <118 0>; + rx-channels = <4>; + #mbox-cells = <1>; + status = "okay"; + }; + }; +}; diff --git a/tests/drivers/mbox/mbox_data/boards/mimxrt1170_evk_cm7.conf b/tests/drivers/mbox/mbox_data/boards/mimxrt1170_evk_cm7.conf new file mode 100644 index 00000000000..583b4950360 --- /dev/null +++ b/tests/drivers/mbox/mbox_data/boards/mimxrt1170_evk_cm7.conf @@ -0,0 +1,3 @@ +CONFIG_MBOX_NXP_IMX_MU=y +CONFIG_INCLUDE_REMOTE_DIR=y +CONFIG_SECOND_CORE_MCUX=y diff --git a/tests/drivers/mbox/mbox_data/boards/mimxrt1170_evk_cm7.overlay b/tests/drivers/mbox/mbox_data/boards/mimxrt1170_evk_cm7.overlay new file mode 100644 index 00000000000..870b9928faf --- /dev/null +++ b/tests/drivers/mbox/mbox_data/boards/mimxrt1170_evk_cm7.overlay @@ -0,0 +1,29 @@ +/* + * Copyright 2024 NXP + * + * SPDX-License-Identifier: Apache-2.0 + */ + +/ { + chosen { + /* Delete ipc chosen property where old IPM mailbox driver bellow is + * configured. + */ + /delete-property/ zephyr,ipc; + }; + + soc { + /* Delete IPM Driver node nxp,imx-mu */ + /delete-node/ mailbox@40c48000; + + /* Attach MBOX driver to MU Unit */ + mbox:mbox@40c48000 { + compatible = "nxp,mbox-imx-mu"; + reg = <0x40c48000 0x4000>; + interrupts = <118 0>; + rx-channels = <4>; + #mbox-cells = <1>; + status = "okay"; + }; + }; +}; diff --git a/tests/drivers/mbox/mbox_data/boards/mimxrt1170_evkb_cm7.conf b/tests/drivers/mbox/mbox_data/boards/mimxrt1170_evkb_cm7.conf new file mode 100644 index 00000000000..0dfb100ed70 --- /dev/null +++ b/tests/drivers/mbox/mbox_data/boards/mimxrt1170_evkb_cm7.conf @@ -0,0 +1,3 @@ +CONFIG_MBOX_NXP_IMX_MU=y +CONFIG_SECOND_CORE_MCUX=y +CONFIG_INCLUDE_REMOTE_DIR=y diff --git a/tests/drivers/mbox/mbox_data/boards/mimxrt1170_evkb_cm7.overlay b/tests/drivers/mbox/mbox_data/boards/mimxrt1170_evkb_cm7.overlay new file mode 100644 index 00000000000..870b9928faf --- /dev/null +++ b/tests/drivers/mbox/mbox_data/boards/mimxrt1170_evkb_cm7.overlay @@ -0,0 +1,29 @@ +/* + * Copyright 2024 NXP + * + * SPDX-License-Identifier: Apache-2.0 + */ + +/ { + chosen { + /* Delete ipc chosen property where old IPM mailbox driver bellow is + * configured. + */ + /delete-property/ zephyr,ipc; + }; + + soc { + /* Delete IPM Driver node nxp,imx-mu */ + /delete-node/ mailbox@40c48000; + + /* Attach MBOX driver to MU Unit */ + mbox:mbox@40c48000 { + compatible = "nxp,mbox-imx-mu"; + reg = <0x40c48000 0x4000>; + interrupts = <118 0>; + rx-channels = <4>; + #mbox-cells = <1>; + status = "okay"; + }; + }; +}; diff --git a/tests/drivers/mbox/mbox_data/prj.conf b/tests/drivers/mbox/mbox_data/prj.conf new file mode 100644 index 00000000000..c4c2b474a7d --- /dev/null +++ b/tests/drivers/mbox/mbox_data/prj.conf @@ -0,0 +1,3 @@ +CONFIG_PRINTK=y +CONFIG_MBOX=y +CONFIG_ZTEST=y diff --git a/tests/drivers/mbox/mbox_data/remote/CMakeLists.txt b/tests/drivers/mbox/mbox_data/remote/CMakeLists.txt new file mode 100644 index 00000000000..31f6db9b641 --- /dev/null +++ b/tests/drivers/mbox/mbox_data/remote/CMakeLists.txt @@ -0,0 +1,20 @@ +# Copyright 2024 NXP +# +# SPDX-License-Identifier: Apache-2.0 +# + +cmake_minimum_required(VERSION 3.20.0) + +find_package(Zephyr REQUIRED HINTS $ENV{ZEPHYR_BASE}) + +if(("${BOARD}" STREQUAL "mimxrt1170_evkb_cm4") OR + ("${BOARD}" STREQUAL "mimxrt1170_evk_cm4") OR + ("${BOARD}" STREQUAL "mimxrt1160_evk_cm4")) + message(STATUS "${BOARD} compile as remote in this sample") +else() + message(FATAL_ERROR "${BOARD} is not supported for this sample") +endif() + +project(mbox_data_ipc_remote) + +target_sources(app PRIVATE src/main.c) diff --git a/tests/drivers/mbox/mbox_data/remote/boards/mimxrt1160_evk_cm4.conf b/tests/drivers/mbox/mbox_data/remote/boards/mimxrt1160_evk_cm4.conf new file mode 100644 index 00000000000..0d36a72aec6 --- /dev/null +++ b/tests/drivers/mbox/mbox_data/remote/boards/mimxrt1160_evk_cm4.conf @@ -0,0 +1,4 @@ +CONFIG_MBOX_NXP_IMX_MU=y +CONFIG_BUILD_OUTPUT_INFO_HEADER=y +CONFIG_BUILD_OUTPUT_HEX=y +CONFIG_SECOND_CORE_MCUX=y diff --git a/tests/drivers/mbox/mbox_data/remote/boards/mimxrt1160_evk_cm4.overlay b/tests/drivers/mbox/mbox_data/remote/boards/mimxrt1160_evk_cm4.overlay new file mode 100644 index 00000000000..3f6115b9c58 --- /dev/null +++ b/tests/drivers/mbox/mbox_data/remote/boards/mimxrt1160_evk_cm4.overlay @@ -0,0 +1,54 @@ +/* + * Copyright 2024 NXP + * + * SPDX-License-Identifier: Apache-2.0 + */ + +/ { + chosen { + zephyr,flash = &ocram; + zephyr,console = &lpuart2; + zephyr,shell-uart = &lpuart2; + + /* Delete ipc chosen property where old IPM mailbox driver bellow is + * configured. + */ + /delete-property/ zephyr,ipc; + }; + + soc { + /delete-node/ gpt@400f0000; + + /* Replace GPT2 with another GPT kernel timer */ + gpt2_hw_timer:gpt@400f0000 { + compatible = "nxp,gpt-hw-timer"; + reg = <0x400f0000 0x4000>; + interrupts = <120 0>; + status = "okay"; + }; + + /* Delete IPM Driver node nxp,imx-mu */ + /delete-node/ mailbox@40c4c000; + + /* Attach MBOX driver to MU Unit */ + mbox:mbox@40c4c000 { + compatible = "nxp,mbox-imx-mu"; + reg = <0x40c4c000 0x4000>; + interrupts = <118 0>; + rx-channels = <4>; + #mbox-cells = <1>; + status = "okay"; + }; + }; +}; + +/* Enable secondary LPUART */ +&lpuart2 { + status = "okay"; + current-speed = <115200>; +}; + +/* Disable primary GPT timer */ +&gpt_hw_timer { + status = "disabled"; +}; diff --git a/tests/drivers/mbox/mbox_data/remote/boards/mimxrt1170_evk_cm4.conf b/tests/drivers/mbox/mbox_data/remote/boards/mimxrt1170_evk_cm4.conf new file mode 100644 index 00000000000..0d36a72aec6 --- /dev/null +++ b/tests/drivers/mbox/mbox_data/remote/boards/mimxrt1170_evk_cm4.conf @@ -0,0 +1,4 @@ +CONFIG_MBOX_NXP_IMX_MU=y +CONFIG_BUILD_OUTPUT_INFO_HEADER=y +CONFIG_BUILD_OUTPUT_HEX=y +CONFIG_SECOND_CORE_MCUX=y diff --git a/tests/drivers/mbox/mbox_data/remote/boards/mimxrt1170_evk_cm4.overlay b/tests/drivers/mbox/mbox_data/remote/boards/mimxrt1170_evk_cm4.overlay new file mode 100644 index 00000000000..3f6115b9c58 --- /dev/null +++ b/tests/drivers/mbox/mbox_data/remote/boards/mimxrt1170_evk_cm4.overlay @@ -0,0 +1,54 @@ +/* + * Copyright 2024 NXP + * + * SPDX-License-Identifier: Apache-2.0 + */ + +/ { + chosen { + zephyr,flash = &ocram; + zephyr,console = &lpuart2; + zephyr,shell-uart = &lpuart2; + + /* Delete ipc chosen property where old IPM mailbox driver bellow is + * configured. + */ + /delete-property/ zephyr,ipc; + }; + + soc { + /delete-node/ gpt@400f0000; + + /* Replace GPT2 with another GPT kernel timer */ + gpt2_hw_timer:gpt@400f0000 { + compatible = "nxp,gpt-hw-timer"; + reg = <0x400f0000 0x4000>; + interrupts = <120 0>; + status = "okay"; + }; + + /* Delete IPM Driver node nxp,imx-mu */ + /delete-node/ mailbox@40c4c000; + + /* Attach MBOX driver to MU Unit */ + mbox:mbox@40c4c000 { + compatible = "nxp,mbox-imx-mu"; + reg = <0x40c4c000 0x4000>; + interrupts = <118 0>; + rx-channels = <4>; + #mbox-cells = <1>; + status = "okay"; + }; + }; +}; + +/* Enable secondary LPUART */ +&lpuart2 { + status = "okay"; + current-speed = <115200>; +}; + +/* Disable primary GPT timer */ +&gpt_hw_timer { + status = "disabled"; +}; diff --git a/tests/drivers/mbox/mbox_data/remote/boards/mimxrt1170_evkb_cm4.conf b/tests/drivers/mbox/mbox_data/remote/boards/mimxrt1170_evkb_cm4.conf new file mode 100644 index 00000000000..0d36a72aec6 --- /dev/null +++ b/tests/drivers/mbox/mbox_data/remote/boards/mimxrt1170_evkb_cm4.conf @@ -0,0 +1,4 @@ +CONFIG_MBOX_NXP_IMX_MU=y +CONFIG_BUILD_OUTPUT_INFO_HEADER=y +CONFIG_BUILD_OUTPUT_HEX=y +CONFIG_SECOND_CORE_MCUX=y diff --git a/tests/drivers/mbox/mbox_data/remote/boards/mimxrt1170_evkb_cm4.overlay b/tests/drivers/mbox/mbox_data/remote/boards/mimxrt1170_evkb_cm4.overlay new file mode 100644 index 00000000000..e3576826702 --- /dev/null +++ b/tests/drivers/mbox/mbox_data/remote/boards/mimxrt1170_evkb_cm4.overlay @@ -0,0 +1,55 @@ +/* + * Copyright 2024 NXP + * + * SPDX-License-Identifier: Apache-2.0 + */ + +/ { + chosen { + zephyr,flash = &ocram; + zephyr,console = &lpuart2; + zephyr,shell-uart = &lpuart2; + + /* Delete ipc chosen property where old IPM mailbox driver bellow is + * configured. + */ + /delete-property/ zephyr,ipc; + }; + + soc { + /delete-node/ gpt@400f0000; + + /* Replace GPT2 with another GPT kernel timer */ + gpt2_hw_timer:gpt@400f0000 { + compatible = "nxp,gpt-hw-timer"; + reg = <0x400f0000 0x4000>; + interrupts = <120 0>; + status = "okay"; + }; + + /* Delete IPM Driver node nxp,imx-mu */ + /delete-node/ mailbox@40c4c000; + + /* Attach MBOX driver to MU Unit */ + mbox:mbox@40c4c000 { + compatible = "nxp,mbox-imx-mu"; + reg = <0x40c4c000 0x4000>; + interrupts = <118 0>; + rx-channels = <4>; + #mbox-cells = <1>; + status = "okay"; + }; + }; + +}; + +/* Enable secondary LPUART */ +&lpuart2 { + status = "okay"; + current-speed = <115200>; +}; + +/* Disable primary GPT timer */ +&gpt_hw_timer { + status = "disabled"; +}; diff --git a/tests/drivers/mbox/mbox_data/remote/prj.conf b/tests/drivers/mbox/mbox_data/remote/prj.conf new file mode 100644 index 00000000000..f2859becbe9 --- /dev/null +++ b/tests/drivers/mbox/mbox_data/remote/prj.conf @@ -0,0 +1,3 @@ +CONFIG_STDOUT_CONSOLE=n +CONFIG_MBOX=y +# CONFIG_NO_OPTIMIZATIONS=y diff --git a/tests/drivers/mbox/mbox_data/remote/src/main.c b/tests/drivers/mbox/mbox_data/remote/src/main.c new file mode 100644 index 00000000000..7bbc1c2efd0 --- /dev/null +++ b/tests/drivers/mbox/mbox_data/remote/src/main.c @@ -0,0 +1,91 @@ +/* + * Copyright 2024 NXP + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include +#include +#include +#include + +static K_SEM_DEFINE(g_mbox_data_rx_sem, 0, 1); + +static uint32_t g_mbox_received_data; +static uint32_t g_mbox_received_channel; + +#define TX_ID0 (2) +#define RX_ID0 (3) +#define TX_ID1 (0) +#define RX_ID1 (1) +#define TX_ID2 (3) +#define RX_ID2 (2) +#define TX_ID3 (1) +#define RX_ID3 (0) + +#define CHANNELS_TO_TEST (4) +#define TX_CHANNEL_INDEX (0) +#define RX_CHANNEL_INDEX (1) +const static uint32_t TEST_CHANNELS[CHANNELS_TO_TEST][2] = { + {TX_ID0, RX_ID0}, {TX_ID1, RX_ID1}, {TX_ID2, RX_ID2}, {TX_ID3, RX_ID3}}; + +static void callback(const struct device *dev, uint32_t channel, void *user_data, + struct mbox_msg *data) +{ + if (data != NULL) { + memcpy(&g_mbox_received_data, data->data, data->size); + g_mbox_received_channel = channel; + } + + k_sem_give(&g_mbox_data_rx_sem); +} + +int main(void) +{ + struct mbox_channel tx_channel; + struct mbox_channel rx_channel; + const struct device *dev; + struct mbox_msg msg = {0}; + uint32_t message = 0; + + dev = DEVICE_DT_GET(DT_NODELABEL(mbox)); + + for (int i_test_channel = 0; i_test_channel < CHANNELS_TO_TEST; i_test_channel++) { + mbox_init_channel(&tx_channel, dev, + TEST_CHANNELS[i_test_channel][TX_CHANNEL_INDEX]); + mbox_init_channel(&rx_channel, dev, + TEST_CHANNELS[i_test_channel][RX_CHANNEL_INDEX]); + + if (mbox_register_callback(&rx_channel, callback, NULL)) { + printk("mbox_register_callback() error\n"); + return 0; + } + + if (mbox_set_enabled(&rx_channel, 1)) { + printk("mbox_set_enable() error\n"); + return 0; + } + + int test_count = 0; + + while (test_count < 100) { + test_count++; + + k_sem_take(&g_mbox_data_rx_sem, K_FOREVER); + message = g_mbox_received_data; + + message++; + + msg.data = &message; + msg.size = 4; + + if (mbox_send(&tx_channel, &msg) < 0) { + printk("mbox_send() error\n"); + return 0; + } + } + + /* Disable current rx channel after channel loop */ + mbox_set_enabled(&rx_channel, 0); + } +} diff --git a/tests/drivers/mbox/mbox_data/src/main.c b/tests/drivers/mbox/mbox_data/src/main.c new file mode 100644 index 00000000000..1cdfb0ca43e --- /dev/null +++ b/tests/drivers/mbox/mbox_data/src/main.c @@ -0,0 +1,184 @@ +/* + * Copyright 2024 NXP + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include +#include +#include +#include + +#include + +static K_SEM_DEFINE(g_mbox_data_rx_sem, 0, 1); + +static uint32_t g_mbox_received_data; +static uint32_t g_mbox_expected_data; +static uint32_t g_mbox_received_channel; +static uint32_t g_mbox_expected_channel; + +static bool g_received_size_error; +static size_t g_received_size; + +static struct mbox_channel g_tx_channel; +static struct mbox_channel g_rx_channel; + +#define TX_ID0 (3) +#define RX_ID0 (2) +#define TX_ID1 (1) +#define RX_ID1 (0) +#define TX_ID2 (2) +#define RX_ID2 (3) +#define TX_ID3 (0) +#define RX_ID3 (1) + +#define CHANNELS_TO_TEST (4) +#define TX_CHANNEL_INDEX (0) +#define RX_CHANNEL_INDEX (1) +const static uint32_t TEST_CHANNELS[CHANNELS_TO_TEST][2] = { + {TX_ID0, RX_ID0}, {TX_ID1, RX_ID1}, {TX_ID2, RX_ID2}, {TX_ID3, RX_ID3}}; +static uint32_t current_channel_index; + +static void callback(const struct device *dev, uint32_t channel, void *user_data, + struct mbox_msg *data) +{ + /* Handle the case if received invalid size */ + if (data->size > sizeof(g_mbox_received_data)) { + g_received_size_error = true; + g_received_size = data->size; + } else { + memcpy(&g_mbox_received_data, data->data, data->size); + } + + g_mbox_received_channel = channel; + + k_sem_give(&g_mbox_data_rx_sem); +} + +static void mbox_data_tests_before(void *f) +{ + zassert_false(current_channel_index >= CHANNELS_TO_TEST, "Channel to test is out of range"); + + const struct device *dev; + int ret_val = 0; + + dev = DEVICE_DT_GET(DT_NODELABEL(mbox)); + + mbox_init_channel(&g_tx_channel, dev, + TEST_CHANNELS[current_channel_index][TX_CHANNEL_INDEX]); + mbox_init_channel(&g_rx_channel, dev, + TEST_CHANNELS[current_channel_index][RX_CHANNEL_INDEX]); + + ret_val = mbox_register_callback(&g_rx_channel, callback, NULL); + zassert_false(ret_val != 0, "mbox failed to register callback. ret_val", ret_val); + + ret_val = mbox_set_enabled(&g_rx_channel, 1); + zassert_false(ret_val != 0, "mbox failed to enable mbox. ret_val: %d", ret_val); +} + +static void mbox_data_tests_after(void *f) +{ + /* Disable channel after test end */ + int ret_val = mbox_set_enabled(&g_rx_channel, 0); + + zassert_false(ret_val != 0, "mbox failed to disable mbox. ret_val: %d", ret_val); + + /* Increment current channel index to its prepared for next test */ + current_channel_index++; +} + +static void mbox_test(const uint32_t data) +{ + struct mbox_msg msg = {0}; + uint32_t test_data = data; + int test_count = 0; + int ret_val = 0; + + while (test_count < 100) { + /* Main core prepare test data */ + msg.data = &test_data; + msg.size = 4; + + /* Main core send test data */ + ret_val = mbox_send(&g_tx_channel, &msg); + zassert_false(ret_val < 0, "mbox failed to send. ret_val: %d", ret_val); + + /* Expect next received data will be incremented by one */ + g_mbox_expected_data = test_data; + g_mbox_expected_data++; + + k_sem_take(&g_mbox_data_rx_sem, K_FOREVER); + + if (g_received_size_error) { + zassert_false(1, "mbox received invalid size in callback: %d", + g_received_size); + } + + test_data = g_mbox_received_data; + + /* Main core check received data */ + zassert_equal(g_mbox_expected_data, test_data, + "Received test_data does not match!: Expected: %08X, Got: %08X", + g_mbox_expected_data, test_data); + + /* Expect reception of data on current RX channel */ + g_mbox_expected_channel = TEST_CHANNELS[current_channel_index][RX_CHANNEL_INDEX]; + zassert_equal(g_mbox_expected_channel, g_mbox_received_channel, + "Received channel does not match!: Expected: %d, Got: %d", + g_mbox_expected_channel, g_mbox_received_channel); + + /* Increment for next send */ + test_data++; + test_count++; + } +} + +/** + * @brief MBOX Data transfer by ping pong for first set of channels + * + * This test verifies that the data transfer via MBOX. + * Main core will transfer test data to remote core. + * Remote core will increment data by one and transfer it back to Main core. + * Main core will check that data it sent to remote core was incremented by one. + * Main core will again increment test data by one, send it to remote core and repeat 100 times. + */ +ZTEST(mbox_data_tests, test_ping_pong_1) +{ + mbox_test(0xADADADAD); +} + +/** + * @brief MBOX Data transfer by ping pong for second set of channels + * + * Description same as for test_ping_pong_1 + * + */ +ZTEST(mbox_data_tests, test_ping_pong_2) +{ + mbox_test(0xDADADADA); +} + +/** + * @brief MBOX Data transfer by ping pong for third set of channels + * + * Description same as for test_ping_pong_1 + * + */ +ZTEST(mbox_data_tests, test_ping_pong_3) +{ + mbox_test(0xADADADAD); +} + +/** + * @brief MBOX Data transfer by ping pong for forth set of channels + * + * Description same as for test_ping_pong_1 + * + */ +ZTEST(mbox_data_tests, test_ping_pong_4) +{ + mbox_test(0xDADADADA); +} + +ZTEST_SUITE(mbox_data_tests, NULL, NULL, mbox_data_tests_before, mbox_data_tests_after, NULL); diff --git a/tests/drivers/mbox/mbox_data/sysbuild.cmake b/tests/drivers/mbox/mbox_data/sysbuild.cmake new file mode 100644 index 00000000000..5c536a6229a --- /dev/null +++ b/tests/drivers/mbox/mbox_data/sysbuild.cmake @@ -0,0 +1,28 @@ +# Copyright 2024 NXP +# +# SPDX-License-Identifier: Apache-2.0 + +if("${SB_CONFIG_REMOTE_BOARD}" STREQUAL "") + message(FATAL_ERROR + "Target ${BOARD} not supported for this sample. " + "There is no remote board selected in Kconfig.sysbuild") +endif() + +set(REMOTE_APP remote) + +ExternalZephyrProject_Add( + APPLICATION ${REMOTE_APP} + SOURCE_DIR ${APP_DIR}/${REMOTE_APP} + BOARD ${SB_CONFIG_REMOTE_BOARD} +) + +if ("${BOARD}" STREQUAL "mimxrt1170_evkb_cm7" OR + "${BOARD}" STREQUAL "mimxrt1170_evk_cm7" OR + "${BOARD}" STREQUAL "mimxrt1160_evk_cm7" + ) + # For these NXP boards the main core application is dependent on + # 'zephyr_image_info.h' generated by remote application. + + # Let's build the remote application first + add_dependencies(${DEFAULT_IMAGE} ${REMOTE_APP}) +endif() diff --git a/tests/drivers/mbox/mbox_data/testcase.yaml b/tests/drivers/mbox/mbox_data/testcase.yaml new file mode 100644 index 00000000000..d4890ff7c55 --- /dev/null +++ b/tests/drivers/mbox/mbox_data/testcase.yaml @@ -0,0 +1,12 @@ +tests: + drivers.mbox_data: + tags: + - drivers + - mbox + sysbuild: true + platform_allow: + - mimxrt1170_evkb_cm7 + - mimxrt1170_evk_cm7 + - mimxrt1160_evk_cm7 + integration_platforms: + - mimxrt1170_evkb_cm7 From 902751a19e34817725b056c401ee28b343a22c52 Mon Sep 17 00:00:00 2001 From: Attie Grande Date: Mon, 15 Jan 2024 14:50:53 +0000 Subject: [PATCH 2645/3723] cmake: hex: fix conversion of zero to hex Previously, `to_hex(0 output)` would have placed `0x` into the `output` variable, which is undesirable... this fix ensures that `0x0` is placed into this variable if the input is zero. Signed-off-by: Attie Grande --- cmake/hex.cmake | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/cmake/hex.cmake b/cmake/hex.cmake index 5823dc9109b..c3935f613fd 100644 --- a/cmake/hex.cmake +++ b/cmake/hex.cmake @@ -34,6 +34,10 @@ function(from_hex HEX DEC) endfunction() function(to_hex DEC HEX) + if(DEC EQUAL 0) + set(${HEX} "0x0" PARENT_SCOPE) + return() + endif() while(DEC GREATER 0) math(EXPR _val "${DEC} % 16") math(EXPR DEC "${DEC} / 16") From 20e2318b9fe9613308b53321ac7f9d6ef481144e Mon Sep 17 00:00:00 2001 From: Attie Grande Date: Tue, 16 Jan 2024 17:24:54 +0000 Subject: [PATCH 2646/3723] cmake: hex: deprecate use of to_hex() and from_hex() utility functions Since v3.13, CMake has supported math(... OUTPUT_FORMAT ) and 0x prefixes on numbers, which together provides the same functionality as to_hex() and from_hex() that we've previously maintained. Users should switch to using math() instead, and our functions are now marked as deprecated. Signed-off-by: Attie Grande --- cmake/hex.cmake | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/cmake/hex.cmake b/cmake/hex.cmake index c3935f613fd..f5eb586f7bd 100644 --- a/cmake/hex.cmake +++ b/cmake/hex.cmake @@ -1,5 +1,9 @@ # SPDX-License-Identifier: Apache-2.0 +# This code was deprecated after Zephyr v3.5.0 +message(DEPRECATION "The to_hex() and from_hex() functions are deprecated. Please " + "use CMake's math(... OUTPUT_FORMAT ) instead.") + # from https://gist.github.com/korzo89/71a6de0f388f7cf8b349101b0134060c function(from_hex HEX DEC) string(SUBSTRING "${HEX}" 2 -1 HEX) From 003d2090b2184c4d59b7e812ace7475e2eb8aeca Mon Sep 17 00:00:00 2001 From: Attie Grande Date: Tue, 16 Jan 2024 17:28:35 +0000 Subject: [PATCH 2647/3723] cmake: version: stop using to_hex() in favour of CMake's math() Since v3.13, CMake has supported math(... OUTPUT_FORMAT ), which will perform the same functionality as to_hex(). Signed-off-by: Attie Grande --- cmake/modules/version.cmake | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/cmake/modules/version.cmake b/cmake/modules/version.cmake index 49d172871e7..34f2cf99d68 100644 --- a/cmake/modules/version.cmake +++ b/cmake/modules/version.cmake @@ -33,8 +33,6 @@ # Therefore `version.cmake` should not use include_guard(GLOBAL). # The final load of `version.cmake` will setup correct build version values. -include(${ZEPHYR_BASE}/cmake/hex.cmake) - if(NOT DEFINED VERSION_FILE AND NOT DEFINED VERSION_TYPE) set(VERSION_FILE ${ZEPHYR_BASE}/VERSION ${APPLICATION_SOURCE_DIR}/VERSION) set(VERSION_TYPE KERNEL APP) @@ -74,8 +72,8 @@ foreach(type file IN ZIP_LISTS VERSION_TYPE VERSION_FILE) math(EXPR ${type}_VERSION_NUMBER_INT "(${MAJOR} << 16) + (${MINOR} << 8) + (${PATCH})") math(EXPR ${type}VERSION_INT "(${MAJOR} << 24) + (${MINOR} << 16) + (${PATCH} << 8) + (${TWEAK})") - to_hex(${${type}_VERSION_NUMBER_INT} ${type}_VERSION_NUMBER) - to_hex(${${type}VERSION_INT} ${type}VERSION) + math(EXPR ${type}_VERSION_NUMBER "${${type}_VERSION_NUMBER_INT}" OUTPUT_FORMAT HEXADECIMAL) + math(EXPR ${type}VERSION "${${type}VERSION_INT}" OUTPUT_FORMAT HEXADECIMAL) if(${type}_VERSION_EXTRA) set(${type}_VERSION_STRING "${${type}_VERSION_WITHOUT_TWEAK}-${${type}_VERSION_EXTRA}") From 0bed5dd459d15506da5834ed5315e12ad3b9b377 Mon Sep 17 00:00:00 2001 From: Christopher Friedt Date: Sat, 20 Jan 2024 10:25:52 -0500 Subject: [PATCH 2648/3723] tests: posix: semaphore: speed up named semaphore test Reduce N_LOOPS from 999 to 32 by default and use a Kconfig to encode it as CONFIG_TEST_SEM_N_LOOPS. Running TESTSUITE semaphore =============================================================== START - test_named_semaphore PASS - test_named_semaphore in 5.685 seconds =============================================================== START - test_semaphore PASS - test_semaphore in 5.010 seconds =============================================================== TESTSUITE semaphore succeeded Signed-off-by: Christopher Friedt --- tests/posix/common/Kconfig | 7 +++++++ tests/posix/common/src/semaphore.c | 11 +++++------ 2 files changed, 12 insertions(+), 6 deletions(-) diff --git a/tests/posix/common/Kconfig b/tests/posix/common/Kconfig index 18b0b82daee..4ee1793253e 100644 --- a/tests/posix/common/Kconfig +++ b/tests/posix/common/Kconfig @@ -24,4 +24,11 @@ config TEST_CLOCK_RT_ERROR_MS help This option is specific to posix_apis.test_realtime in clock.c +config TEST_SEM_N_LOOPS + int "Number of loops in semaphore test" + range 16 1024 + default 32 + help + This option is specific to semaphore.test_named_semaphore in semaphore.c + source "Kconfig.zephyr" diff --git a/tests/posix/common/src/semaphore.c b/tests/posix/common/src/semaphore.c index 542ac70a624..f445c5ce2f4 100644 --- a/tests/posix/common/src/semaphore.c +++ b/tests/posix/common/src/semaphore.c @@ -109,13 +109,12 @@ ZTEST(semaphore, test_semaphore) int nsem_get_ref_count(sem_t *sem); size_t nsem_get_list_len(void); -#define N_LOOPS 999 static void *nsem_open_func(void *p) { const char *name = (char *)p; - for (int i = 0; i < N_LOOPS; i++) { + for (int i = 0; i < CONFIG_TEST_SEM_N_LOOPS; i++) { zassert_not_null(sem_open(name, 0, 0, 0), "%s is NULL", name); k_msleep(1); } @@ -130,9 +129,9 @@ static void *nsem_close_func(void *p) sem_t *sem = (sem_t *)p; /* Make sure that we have enough ref_count's initially */ - k_msleep(N_LOOPS >> 1); + k_msleep(CONFIG_TEST_SEM_N_LOOPS >> 1); - for (int i = 0; i < N_LOOPS; i++) { + for (int i = 0; i < CONFIG_TEST_SEM_N_LOOPS; i++) { zassert_ok(sem_close(sem)); k_msleep(1); } @@ -188,7 +187,7 @@ ZTEST(semaphore, test_named_semaphore) zassert_equal(nsem_get_list_len(), 2); /* Open created named sem repeatedly */ - for (size_t i = 1; i <= N_LOOPS; i++) { + for (size_t i = 1; i <= CONFIG_TEST_SEM_N_LOOPS; i++) { sem_t *new_sem1, *new_sem2; /* oflags are ignored (except when both O_CREAT & O_EXCL are set) */ @@ -217,7 +216,7 @@ ZTEST(semaphore, test_named_semaphore) zassert_equal(nsem_get_list_len(), 2); /* Close sem */ - for (size_t i = N_LOOPS; + for (size_t i = CONFIG_TEST_SEM_N_LOOPS; /* close until one left, required by the test later */ i >= 1; i--) { zassert_ok(sem_close(sem1)); From c16d9699a3fbf3f4312961f4afc8234be5b31dfd Mon Sep 17 00:00:00 2001 From: Kamil Piszczek Date: Fri, 19 Jan 2024 13:39:08 +0100 Subject: [PATCH 2649/3723] tests: bsim: bluetooth: host: gatt: general: improve conn ref handling Improved the connection reference handling in the BabbleSim test project in the Bluetooth Host category. Signed-off-by: Kamil Piszczek --- tests/bsim/bluetooth/host/gatt/general/src/gatt_client_test.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/tests/bsim/bluetooth/host/gatt/general/src/gatt_client_test.c b/tests/bsim/bluetooth/host/gatt/general/src/gatt_client_test.c index b91929054a1..53bf4fd1f51 100644 --- a/tests/bsim/bluetooth/host/gatt/general/src/gatt_client_test.c +++ b/tests/bsim/bluetooth/host/gatt/general/src/gatt_client_test.c @@ -36,7 +36,8 @@ static void connected(struct bt_conn *conn, uint8_t err) printk("Connected to %s\n", addr); - g_conn = conn; + __ASSERT_NO_MSG(g_conn == conn); + SET_FLAG(flag_is_connected); } From e5fe1c162570fcd2be4de583ce5e21273e282c41 Mon Sep 17 00:00:00 2001 From: Yves Vandervennet Date: Wed, 17 Jan 2024 09:01:11 -0600 Subject: [PATCH 2650/3723] boards: mimxrt1015_evk: enable support for linkserver - adds the definitions in the board.cmake file - updates documentation Signed-off-by: Yves Vandervennet --- boards/arm/mimxrt1015_evk/board.cmake | 5 ++++- boards/arm/mimxrt1015_evk/doc/index.rst | 25 +++++++++++++++++++------ 2 files changed, 23 insertions(+), 7 deletions(-) diff --git a/boards/arm/mimxrt1015_evk/board.cmake b/boards/arm/mimxrt1015_evk/board.cmake index be9b7ba10e1..442bf1b43e2 100644 --- a/boards/arm/mimxrt1015_evk/board.cmake +++ b/boards/arm/mimxrt1015_evk/board.cmake @@ -1,10 +1,13 @@ # -# Copyright (c) 2019, NXP +# Copyright (c) 2019, 2024 NXP # # SPDX-License-Identifier: Apache-2.0 # board_runner_args(pyocd "--target=mimxrt1015") board_runner_args(jlink "--device=MIMXRT1015") +board_runner_args(linkserver "--device=MIMXRT1015xxxxx:EVK-MIMXRT1015") + +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/arm/mimxrt1015_evk/doc/index.rst b/boards/arm/mimxrt1015_evk/doc/index.rst index d3e44a5b040..f7d6bc1db6e 100644 --- a/boards/arm/mimxrt1015_evk/doc/index.rst +++ b/boards/arm/mimxrt1015_evk/doc/index.rst @@ -168,13 +168,26 @@ 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 :ref:`opensda-daplink-onboard-debug-probe`, -however the :ref:`pyocd-debug-host-tools` do not yet support programming the -external flashes on this board so you must reconfigure the board for one of the -following debug probes instead. +configured by default to use the :ref:`opensda-daplink-onboard-debug-probe`. -:ref:`jlink-external-debug-probe` -------------------------------------------- +Using LinkServer: :ref:`opensda-daplink-onboard-debug-probe` +------------------------------------------------------------ + +Install the :ref:`linkserver-debug-host-tools` and make sure they are in your +search path. LinkServer works with the default CMSIS-DAP firmware included in +the on-board debugger. + +Linkserver is the default runner. You may also se the ``-r linkserver`` option +with West to use the LinkServer runner. + +.. code-block:: console + + west flash + west debug + + +External JLink: :ref:`jlink-external-debug-probe` +------------------------------------------------- Install the :ref:`jlink-debug-host-tools` and make sure they are in your search path. From a9779eca400e67e2eebfc1f774eb4186efdc7a96 Mon Sep 17 00:00:00 2001 From: Bjarki Arge Andreasen Date: Mon, 27 Nov 2023 15:09:01 +0100 Subject: [PATCH 2651/3723] modem: ppp: Implement TRANSMIT_IDLE event Implement TRANSMIT_IDLE event for modem_ppp module. This addition optimizes the sys workque CPU time when performing a throughput test from 36% to 5%, while only reducing the throughput by 12%. Signed-off-by: Bjarki Arge Andreasen --- subsys/modem/modem_ppp.c | 35 +++++++++++++++++++++-------------- 1 file changed, 21 insertions(+), 14 deletions(-) diff --git a/subsys/modem/modem_ppp.c b/subsys/modem/modem_ppp.c index 476926f4db3..1d47542f24a 100644 --- a/subsys/modem/modem_ppp.c +++ b/subsys/modem/modem_ppp.c @@ -314,8 +314,17 @@ static void modem_ppp_pipe_callback(struct modem_pipe *pipe, enum modem_pipe_eve { struct modem_ppp *ppp = (struct modem_ppp *)user_data; - if (event == MODEM_PIPE_EVENT_RECEIVE_READY) { + switch (event) { + case MODEM_PIPE_EVENT_RECEIVE_READY: k_work_submit(&ppp->process_work); + break; + + case MODEM_PIPE_EVENT_TRANSMIT_IDLE: + k_work_submit(&ppp->send_work); + break; + + default: + break; } } @@ -351,22 +360,20 @@ static void modem_ppp_send_handler(struct k_work *item) } } - reserved_size = ring_buf_get_claim(&ppp->transmit_rb, &reserved, UINT32_MAX); - if (reserved_size == 0) { - ring_buf_get_finish(&ppp->transmit_rb, 0); - return; - } + while (!ring_buf_is_empty(&ppp->transmit_rb)) { + reserved_size = ring_buf_get_claim(&ppp->transmit_rb, &reserved, UINT32_MAX); + + ret = modem_pipe_transmit(ppp->pipe, reserved, reserved_size); + if (ret < 0) { + ring_buf_get_finish(&ppp->transmit_rb, 0); + break; + } - ret = modem_pipe_transmit(ppp->pipe, reserved, reserved_size); - if (ret < 0) { - ring_buf_get_finish(&ppp->transmit_rb, 0); - } else { ring_buf_get_finish(&ppp->transmit_rb, (uint32_t)ret); - } - /* Resubmit send work if data remains */ - if ((ring_buf_is_empty(&ppp->transmit_rb) == false) || (ppp->tx_pkt != NULL)) { - k_work_submit(&ppp->send_work); + if (ret < reserved_size) { + break; + } } } From 23714980b0fc3a3022b16d6be5122affcd723513 Mon Sep 17 00:00:00 2001 From: Fabio Baltieri Date: Thu, 18 Jan 2024 09:45:18 +0000 Subject: [PATCH 2652/3723] input: utils: fix kbd_matrix_state_log types Change row and col static types to unsigned, this should prevent really bad things from happening if a negative number ends up there for whatever reasons without having to explicitly check for < 0. Signed-off-by: Fabio Baltieri --- subsys/input/input_utils.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/subsys/input/input_utils.c b/subsys/input/input_utils.c index 0a08f1ad2fa..32d26fc7211 100644 --- a/subsys/input/input_utils.c +++ b/subsys/input/input_utils.c @@ -165,7 +165,8 @@ static void kbd_matrix_state_log_entry(char *header, kbd_row_t *data) static void kbd_matrix_state_log(struct input_event *evt) { const struct input_kbd_matrix_common_config *cfg; - static int row, col, val; + static uint32_t row, col; + static bool val; if (kbd_matrix_state_dev == NULL || kbd_matrix_state_dev != evt->dev) { return; From 0d6dc0ca53ed8fcb1209d51ee4b4c8e8336e3aaa Mon Sep 17 00:00:00 2001 From: Christopher Friedt Date: Sat, 20 Jan 2024 08:14:02 -0500 Subject: [PATCH 2653/3723] posix: signal: reduce padding in sigevent sigval The sigevent struct and sigval union members were previously not ordered in a way that produces optimal alignment / reduces padding on 64-bit systems. Reorder members so that pointers come first. Signed-off-by: Christopher Friedt --- include/zephyr/posix/signal.h | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/include/zephyr/posix/signal.h b/include/zephyr/posix/signal.h index d22ac34c48d..3bbdee7317a 100644 --- a/include/zephyr/posix/signal.h +++ b/include/zephyr/posix/signal.h @@ -80,16 +80,16 @@ typedef struct { typedef int sig_atomic_t; /* Atomic entity type (ANSI) */ union sigval { - int sival_int; void *sival_ptr; + int sival_int; }; struct sigevent { - int sigev_notify; - int sigev_signo; - union sigval sigev_value; void (*sigev_notify_function)(union sigval val); pthread_attr_t *sigev_notify_attributes; + union sigval sigev_value; + int sigev_notify; + int sigev_signo; }; #ifdef CONFIG_POSIX_SIGNAL From 689dc4a45b90bee7c276408a7a58786aa19dc197 Mon Sep 17 00:00:00 2001 From: Christopher Friedt Date: Sat, 20 Jan 2024 08:20:08 -0500 Subject: [PATCH 2654/3723] posix: timer: support other clocks There is no requirement that says e.g. CLOCK_REALTIME cannot be used for timer_create(). In fact, the spec explicitly requires it. It might not be ideal, but users should still be able to use it. Signed-off-by: Christopher Friedt --- lib/posix/timer.c | 23 ++++++++++------------- 1 file changed, 10 insertions(+), 13 deletions(-) diff --git a/lib/posix/timer.c b/lib/posix/timer.c index da4272f3bf1..7e522420305 100644 --- a/lib/posix/timer.c +++ b/lib/posix/timer.c @@ -18,9 +18,7 @@ static void zephyr_timer_wrapper(struct k_timer *ztimer); struct timer_obj { struct k_timer ztimer; - void (*sigev_notify_function)(union sigval val); - union sigval val; - int sigev_notify; + struct sigevent sev; struct k_sem sem_cond; pthread_t thread; struct timespec interval; /* Reload value */ @@ -41,7 +39,7 @@ static void zephyr_timer_wrapper(struct k_timer *ztimer) timer->status = NOT_ACTIVE; } - (timer->sigev_notify_function)(timer->val); + (timer->sev.sigev_notify_function)(timer->sev.sigev_value); } static void *zephyr_thread_wrapper(void *arg) @@ -55,7 +53,7 @@ static void *zephyr_thread_wrapper(void *arg) k_sem_take(&timer->sem_cond, K_FOREVER); - (timer->sigev_notify_function)(timer->val); + (timer->sev.sigev_notify_function)(timer->sev.sigev_value); } return NULL; @@ -82,10 +80,8 @@ int timer_create(clockid_t clockid, struct sigevent *evp, timer_t *timerid) struct timer_obj *timer; const k_timeout_t alloc_timeout = K_MSEC(CONFIG_TIMER_CREATE_WAIT); - if (clockid != CLOCK_MONOTONIC || evp == NULL || - (evp->sigev_notify != SIGEV_NONE && - evp->sigev_notify != SIGEV_SIGNAL && - evp->sigev_notify != SIGEV_THREAD)) { + if (evp == NULL || (evp->sigev_notify != SIGEV_NONE && evp->sigev_notify != SIGEV_SIGNAL && + evp->sigev_notify != SIGEV_THREAD)) { errno = EINVAL; return -1; } @@ -97,8 +93,8 @@ int timer_create(clockid_t clockid, struct sigevent *evp, timer_t *timerid) return -1; } - timer->sigev_notify_function = evp->sigev_notify_function; - timer->val = evp->sigev_value; + timer->sev.sigev_notify_function = evp->sigev_notify_function; + timer->sev.sigev_value = evp->sigev_value; timer->interval.tv_sec = 0; timer->interval.tv_nsec = 0; timer->reload = 0U; @@ -109,7 +105,7 @@ int timer_create(clockid_t clockid, struct sigevent *evp, timer_t *timerid) } else if (evp->sigev_notify == SIGEV_THREAD) { int ret; - timer->sigev_notify = SIGEV_THREAD; + timer->sev.sigev_notify = SIGEV_THREAD; k_sem_init(&timer->sem_cond, 0, 1); ret = pthread_create(&timer->thread, evp->sigev_notify_attributes, zephyr_thread_wrapper, timer); @@ -266,8 +262,9 @@ int timer_delete(timer_t timerid) k_timer_stop(&timer->ztimer); } - if (timer->sigev_notify == SIGEV_THREAD) + if (timer->sev.sigev_notify == SIGEV_THREAD) { pthread_cancel(timer->thread); + } k_mem_slab_free(&posix_timer_slab, (void *)timer); From 3ff7c04f30d8bbc4b0918a290650ae8fcad7e74b Mon Sep 17 00:00:00 2001 From: Christopher Friedt Date: Sat, 20 Jan 2024 09:07:21 -0500 Subject: [PATCH 2655/3723] posix: timer: use async pthread cancellation Previously, Zephyr's POSIX API did not differentiate between deferred and asynchronous pthread cancellation. In fact all pthread cancellation was asynchronous. According to the spec, all pthreads should be created with deferred cancellation by default. Note: PTHREAD_CANCEL_ASYNCHRONOUS means cancel asynchronously with respect to cancellation points (but synchronously with respect to the thread that callse pthread_cancel(), which is perhaps unintuitive). The POSIX timer relied on this non-standard convention. Oddly, this change prevents what would have otherwise been a regression that would have been caused by fixing pthread behaviour (in a separate commit). We are effectively uncovering bugs which were probably always present in the pthread.c and timer.c implementations going back quite a few years. Signed-off-by: Christopher Friedt --- lib/posix/timer.c | 132 +++++++++++++++++++++++++++++++++++----------- 1 file changed, 101 insertions(+), 31 deletions(-) diff --git a/lib/posix/timer.c b/lib/posix/timer.c index 7e522420305..7caecc180a1 100644 --- a/lib/posix/timer.c +++ b/lib/posix/timer.c @@ -1,24 +1,27 @@ /* * Copyright (c) 2018 Intel Corporation + * Copyright (c) 2024, Meta * * SPDX-License-Identifier: Apache-2.0 */ -#include #include -#include + +#include +#include #include -#include #include #include #define ACTIVE 1 #define NOT_ACTIVE 0 +LOG_MODULE_REGISTER(posix_timer); + static void zephyr_timer_wrapper(struct k_timer *ztimer); struct timer_obj { struct k_timer ztimer; - struct sigevent sev; + struct sigevent evp; struct k_sem sem_cond; pthread_t thread; struct timespec interval; /* Reload value */ @@ -37,23 +40,53 @@ static void zephyr_timer_wrapper(struct k_timer *ztimer) if (timer->reload == 0U) { timer->status = NOT_ACTIVE; + LOG_DBG("timer %p not active", timer); + return; + } + + if (timer->evp.sigev_notify == SIGEV_NONE) { + LOG_DBG("SIGEV_NONE"); + return; } - (timer->sev.sigev_notify_function)(timer->sev.sigev_value); + if (timer->evp.sigev_notify_function == NULL) { + LOG_DBG("NULL sigev_notify_function"); + return; + } + + LOG_DBG("calling sigev_notify_function %p", timer->evp.sigev_notify_function); + (timer->evp.sigev_notify_function)(timer->evp.sigev_value); } static void *zephyr_thread_wrapper(void *arg) { + int ret; struct timer_obj *timer = (struct timer_obj *)arg; + ret = pthread_setcanceltype(PTHREAD_CANCEL_ASYNCHRONOUS, NULL); + __ASSERT(ret == 0, "pthread_setcanceltype() failed: %d", ret); + + if (timer->evp.sigev_notify_attributes == NULL) { + ret = pthread_detach(pthread_self()); + __ASSERT(ret == 0, "pthread_detach() failed: %d", ret); + } + while (1) { if (timer->reload == 0U) { timer->status = NOT_ACTIVE; + LOG_DBG("timer %p not active", timer); } - k_sem_take(&timer->sem_cond, K_FOREVER); + ret = k_sem_take(&timer->sem_cond, K_FOREVER); + __ASSERT(ret == 0, "k_sem_take() failed: %d", ret); + + if (timer->evp.sigev_notify_function == NULL) { + LOG_DBG("NULL sigev_notify_function"); + continue; + } - (timer->sev.sigev_notify_function)(timer->sev.sigev_value); + LOG_DBG("calling sigev_notify_function %p", timer->evp.sigev_notify_function); + (timer->evp.sigev_notify_function)(timer->evp.sigev_value); } return NULL; @@ -77,52 +110,89 @@ static void zephyr_timer_interrupt(struct k_timer *ztimer) */ int timer_create(clockid_t clockid, struct sigevent *evp, timer_t *timerid) { + int ret = 0; + int detachstate; struct timer_obj *timer; const k_timeout_t alloc_timeout = K_MSEC(CONFIG_TIMER_CREATE_WAIT); - if (evp == NULL || (evp->sigev_notify != SIGEV_NONE && evp->sigev_notify != SIGEV_SIGNAL && - evp->sigev_notify != SIGEV_THREAD)) { + if (evp == NULL || timerid == NULL) { errno = EINVAL; return -1; } - if (k_mem_slab_alloc(&posix_timer_slab, (void **)&timer, alloc_timeout) == 0) { - (void)memset(timer, 0, sizeof(struct timer_obj)); - } else { + if (k_mem_slab_alloc(&posix_timer_slab, (void **)&timer, alloc_timeout) != 0) { + LOG_DBG("k_mem_slab_alloc() failed: %d", ret); errno = ENOMEM; return -1; } - timer->sev.sigev_notify_function = evp->sigev_notify_function; - timer->sev.sigev_value = evp->sigev_value; - timer->interval.tv_sec = 0; - timer->interval.tv_nsec = 0; - timer->reload = 0U; - timer->status = NOT_ACTIVE; + *timer = (struct timer_obj){0}; + timer->evp = *evp; + evp = &timer->evp; - if (evp->sigev_notify == SIGEV_NONE) { + switch (evp->sigev_notify) { + case SIGEV_NONE: k_timer_init(&timer->ztimer, NULL, NULL); - } else if (evp->sigev_notify == SIGEV_THREAD) { - int ret; + break; + case SIGEV_SIGNAL: + k_timer_init(&timer->ztimer, zephyr_timer_wrapper, NULL); + break; + case SIGEV_THREAD: + if (evp->sigev_notify_attributes != NULL) { + ret = pthread_attr_getdetachstate(evp->sigev_notify_attributes, + &detachstate); + if (ret != 0) { + LOG_DBG("pthread_attr_getdetachstate() failed: %d", ret); + errno = ret; + ret = -1; + goto free_timer; + } + + if (detachstate != PTHREAD_CREATE_DETACHED) { + ret = pthread_attr_setdetachstate(evp->sigev_notify_attributes, + PTHREAD_CREATE_DETACHED); + if (ret != 0) { + LOG_DBG("pthread_attr_setdetachstate() failed: %d", ret); + errno = ret; + ret = -1; + goto free_timer; + } + } + } + + ret = k_sem_init(&timer->sem_cond, 0, 1); + if (ret != 0) { + LOG_DBG("k_sem_init() failed: %d", ret); + errno = -ret; + ret = -1; + goto free_timer; + } - timer->sev.sigev_notify = SIGEV_THREAD; - k_sem_init(&timer->sem_cond, 0, 1); ret = pthread_create(&timer->thread, evp->sigev_notify_attributes, zephyr_thread_wrapper, timer); if (ret != 0) { - k_mem_slab_free(&posix_timer_slab, (void *) &timer); - return ret; + LOG_DBG("pthread_create() failed: %d", ret); + errno = ret; + ret = -1; + goto free_timer; } - pthread_detach(timer->thread); k_timer_init(&timer->ztimer, zephyr_timer_interrupt, NULL); - } else { - k_timer_init(&timer->ztimer, zephyr_timer_wrapper, NULL); + break; + default: + ret = -1; + errno = EINVAL; + goto free_timer; } *timerid = (timer_t)timer; + goto out; - return 0; +free_timer: + k_mem_slab_free(&posix_timer_slab, (void *)&timer); + +out: + return ret; } /** @@ -262,8 +332,8 @@ int timer_delete(timer_t timerid) k_timer_stop(&timer->ztimer); } - if (timer->sev.sigev_notify == SIGEV_THREAD) { - pthread_cancel(timer->thread); + if (timer->evp.sigev_notify == SIGEV_THREAD) { + (void)pthread_cancel(timer->thread); } k_mem_slab_free(&posix_timer_slab, (void *)timer); From 7f57d5d6eb34531f22fbc679c6f0d969876e336d Mon Sep 17 00:00:00 2001 From: Christopher Friedt Date: Sat, 20 Jan 2024 11:55:11 -0500 Subject: [PATCH 2656/3723] tests: posix: timer: run tests for realtime as well Ensure that the realtime clock may also be used with timer_create(). Signed-off-by: Christopher Friedt --- tests/posix/common/src/timer.c | 26 ++++++++++++++++++-------- 1 file changed, 18 insertions(+), 8 deletions(-) diff --git a/tests/posix/common/src/timer.c b/tests/posix/common/src/timer.c index 9463bc30d78..ffb94e93618 100644 --- a/tests/posix/common/src/timer.c +++ b/tests/posix/common/src/timer.c @@ -30,7 +30,7 @@ void handler(union sigval val) zassert_equal(val.sival_int, TEST_SIGNAL_VAL); } -void test_timer(int sigev_notify) +void test_timer(clockid_t clock_id, int sigev_notify) { struct sigevent sig = {0}; struct itimerspec value, ovalue; @@ -43,7 +43,7 @@ void test_timer(int sigev_notify) sig.sigev_value.sival_int = TEST_SIGNAL_VAL; /*TESTPOINT: Check if timer is created successfully*/ - zassert_ok(timer_create(CLOCK_MONOTONIC, &sig, &timerid)); + zassert_ok(timer_create(clock_id, &sig, &timerid)); value.it_value.tv_sec = DURATION_SECS; value.it_value.tv_nsec = DURATION_NSECS; @@ -59,9 +59,9 @@ void test_timer(int sigev_notify) LOG_DBG("Time remaining to fire %d secs and %d nsecs", (int)value.it_value.tv_sec, (int)value.it_value.tv_nsec); - clock_gettime(CLOCK_MONOTONIC, &ts); + clock_gettime(clock_id, &ts); sleep(SECS_TO_SLEEP); - clock_gettime(CLOCK_MONOTONIC, &te); + clock_gettime(clock_id, &te); if (te.tv_nsec >= ts.tv_nsec) { secs_elapsed = te.tv_sec - ts.tv_sec; @@ -82,14 +82,24 @@ void test_timer(int sigev_notify) exp_count, expected_signal_count); } -ZTEST(timer, test_SIGEV_SIGNAL) +ZTEST(timer, test_CLOCK_REALTIME__SIGEV_SIGNAL) +{ + test_timer(CLOCK_REALTIME, SIGEV_SIGNAL); +} + +ZTEST(timer, test_CLOCK_REALTIME__SIGEV_THREAD) +{ + test_timer(CLOCK_REALTIME, SIGEV_THREAD); +} + +ZTEST(timer, test_CLOCK_MONOTONIC__SIGEV_SIGNAL) { - test_timer(SIGEV_SIGNAL); + test_timer(CLOCK_MONOTONIC, SIGEV_SIGNAL); } -ZTEST(timer, test_SIGEV_THREAD) +ZTEST(timer, test_CLOCK_MONOTONIC__SIGEV_THREAD) { - test_timer(SIGEV_THREAD); + test_timer(CLOCK_MONOTONIC, SIGEV_THREAD); } ZTEST(timer, test_timer_overrun) From 3111b801d90ff9d109e678421097da01f45685e0 Mon Sep 17 00:00:00 2001 From: Robert Lubos Date: Thu, 18 Jan 2024 12:55:25 +0100 Subject: [PATCH 2657/3723] net: socket_service: Add underscore in the idx variable name Nothing critical, but it just looks better if the service name is separated from the prefix, i.e: _z_net_socket_service_idx_udp_service_async vs current: _z_net_socket_service_idxudp_service_async Signed-off-by: Robert Lubos --- include/zephyr/net/socket_service.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/include/zephyr/net/socket_service.h b/include/zephyr/net/socket_service.h index 16da94d238b..a4e21f00a33 100644 --- a/include/zephyr/net/socket_service.h +++ b/include/zephyr/net/socket_service.h @@ -76,7 +76,7 @@ struct net_socket_service_desc { }; #define __z_net_socket_svc_get_name(_svc_id) __z_net_socket_service_##_svc_id -#define __z_net_socket_svc_get_idx(_svc_id) __z_net_socket_service_idx##_svc_id +#define __z_net_socket_svc_get_idx(_svc_id) __z_net_socket_service_idx_##_svc_id #define __z_net_socket_svc_get_owner __FILE__ ":" STRINGIFY(__LINE__) extern void net_socket_service_callback(struct k_work *work); From 8ad0e5763f844e1cff81b21ebc54c1cc6101ff41 Mon Sep 17 00:00:00 2001 From: Robert Lubos Date: Thu, 18 Jan 2024 12:57:49 +0100 Subject: [PATCH 2658/3723] net: socket_service: Fix iterable section location The iterable section should be located in ROM and not RAM, this caused crashes on multiple platforms running socket services. Fixes #67762 Signed-off-by: Robert Lubos --- include/zephyr/linker/common-rom/common-rom-net.ld | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/include/zephyr/linker/common-rom/common-rom-net.ld b/include/zephyr/linker/common-rom/common-rom-net.ld index 8b386ee8ce8..e73addfd166 100644 --- a/include/zephyr/linker/common-rom/common-rom-net.ld +++ b/include/zephyr/linker/common-rom/common-rom-net.ld @@ -27,5 +27,5 @@ #endif #if defined(CONFIG_NET_SOCKETS_SERVICE) - ITERABLE_SECTION_RAM(net_socket_service_desc, 4) + ITERABLE_SECTION_ROM(net_socket_service_desc, 4) #endif From b857ef7f83aa683940c35c0383fe1686ca3218af Mon Sep 17 00:00:00 2001 From: Emil Gydesen Date: Thu, 28 Dec 2023 13:50:56 +0100 Subject: [PATCH 2659/3723] Bluetooth: BAP: Add ISO state callbacks Add callbacks to the stream objects that reflects the state of the isochronous channel. The connected callback is called when the isochronous channel is connected, and similarly the disconnected callback is called when it is disconnected. There is a special case for unicast, where if the ACL disconnects first, then we won't get a ISO disconnect callback. It should be assumed that the isochronous channel is no longer valid when the BAP stream enters the idle state, i.e. when the "released" callback is called. The purpose of the new callbacks is to provide additional information to the application. Especially the unicast client can use this to determine when the stream_start function can be called again, as there can only ever be 1 outstanding CIS connection request at a time, but there can be multiple GATT requests. Signed-off-by: Emil Gydesen --- include/zephyr/bluetooth/audio/bap.h | 30 ++++++++- subsys/bluetooth/audio/ascs.c | 28 +++++--- subsys/bluetooth/audio/bap_broadcast_sink.c | 16 +++-- subsys/bluetooth/audio/bap_broadcast_source.c | 14 ++-- subsys/bluetooth/audio/bap_unicast_client.c | 50 +++++++++++--- subsys/bluetooth/audio/cap_stream.c | 24 +++++++ tests/bluetooth/audio/ascs/src/main.c | 6 ++ .../ascs/src/test_ase_state_transition.c | 6 ++ .../audio/bap_broadcast_source/src/main.c | 4 ++ .../audio/mocks/include/bap_stream.h | 2 + .../audio/mocks/include/bap_stream_expects.h | 41 +++++++++++- tests/bluetooth/audio/mocks/src/bap_stream.c | 6 ++ .../audio/src/bap_unicast_client_test.c | 66 ++++++++++++++++++- 13 files changed, 264 insertions(+), 29 deletions(-) diff --git a/include/zephyr/bluetooth/audio/bap.h b/include/zephyr/bluetooth/audio/bap.h index 5fad95df0b5..793364435d3 100644 --- a/include/zephyr/bluetooth/audio/bap.h +++ b/include/zephyr/bluetooth/audio/bap.h @@ -581,10 +581,38 @@ struct bt_bap_stream_ops { * * This callback is only used if the ISO data path is HCI. * - * @param chan The channel which has sent data. + * @param stream Stream object. */ void (*sent)(struct bt_bap_stream *stream); #endif /* CONFIG_BT_AUDIO_TX */ + + /** + * @brief Isochronous channel connected callback + * + * If this callback is provided it will be called whenever the isochronous channel for the + * stream has been connected. This does not mean that the stream is ready to be used, which + * is indicated by the @ref bt_bap_stream_ops.started callback. + * + * If the stream shares an isochronous channel with another stream, then this callback may + * still be called, without the stream going into the started state. + * + * @param stream Stream object. + */ + void (*connected)(struct bt_bap_stream *stream); + + /** + * @brief Isochronous channel disconnected callback + * + * If this callback is provided it will be called whenever the isochronous channel is + * disconnected, including when a connection gets rejected. + * + * If the stream shares an isochronous channel with another stream, then this callback may + * not be called, even if the stream is leaving the streaming state. + * + * @param stream Stream object. + * @param reason BT_HCI_ERR_* reason for the disconnection. + */ + void (*disconnected)(struct bt_bap_stream *stream, uint8_t reason); }; /** diff --git a/subsys/bluetooth/audio/ascs.c b/subsys/bluetooth/audio/ascs.c index d3ba31cf7a2..686c13443ca 100644 --- a/subsys/bluetooth/audio/ascs.c +++ b/subsys/bluetooth/audio/ascs.c @@ -386,7 +386,6 @@ static void ase_exit_state_streaming(struct bt_ascs_ase *ase) struct bt_bap_stream *stream = ase->ep.stream; struct bt_bap_stream_ops *ops; const enum bt_bap_ep_state next_state = ascs_ep_get_state(&ase->ep); - uint8_t reason = ase->ep.reason; __ASSERT_NO_MSG(stream != NULL); @@ -397,11 +396,6 @@ static void ase_exit_state_streaming(struct bt_ascs_ase *ase) } ops = stream->ops; - if (ops != NULL && ops->stopped != NULL) { - ops->stopped(stream, reason); - } else { - LOG_WRN("No callback for stopped set"); - } /* * On link-loss we go from streaming state to QOS configured state, @@ -415,6 +409,12 @@ static void ase_exit_state_streaming(struct bt_ascs_ase *ase) LOG_WRN("No callback for disabled set"); } } + + if (ops != NULL && ops->stopped != NULL) { + ops->stopped(stream, reason); + } else { + LOG_WRN("No callback for stopped set"); + } } static void ase_exit_state_enabling(struct bt_ascs_ase *ase) @@ -940,6 +940,7 @@ static void ascs_update_sdu_size(struct bt_bap_ep *ep) static void ascs_ep_iso_connected(struct bt_bap_ep *ep) { struct bt_ascs_ase *ase = CONTAINER_OF(ep, struct bt_ascs_ase, ep); + const struct bt_bap_stream_ops *stream_ops; struct bt_bap_stream *stream; if (ep->status.state != BT_BAP_EP_STATE_ENABLING) { @@ -964,6 +965,13 @@ static void ascs_ep_iso_connected(struct bt_bap_ep *ep) */ ascs_update_sdu_size(ep); + LOG_DBG("stream %p ep %p dir %s", stream, ep, bt_audio_dir_str(ep->dir)); + + stream_ops = stream->ops; + if (stream_ops != NULL && stream_ops->connected != NULL) { + stream_ops->connected(stream); + } + if (ep->dir == BT_AUDIO_DIR_SINK && ep->receiver_ready) { /* Source ASEs shall be ISO connected first, and then receive * the receiver start ready command to enter the streaming @@ -971,8 +979,6 @@ static void ascs_ep_iso_connected(struct bt_bap_ep *ep) */ ascs_ep_set_state(ep, BT_BAP_EP_STATE_STREAMING); } - - LOG_DBG("stream %p ep %p dir %s", stream, ep, bt_audio_dir_str(ep->dir)); } static void ascs_iso_connected(struct bt_iso_chan *chan) @@ -996,6 +1002,7 @@ static void ascs_iso_connected(struct bt_iso_chan *chan) static void ascs_ep_iso_disconnected(struct bt_bap_ep *ep, uint8_t reason) { struct bt_ascs_ase *ase = CONTAINER_OF(ep, struct bt_ascs_ase, ep); + const struct bt_bap_stream_ops *stream_ops; struct bt_bap_stream *stream; stream = ep->stream; @@ -1007,6 +1014,11 @@ static void ascs_ep_iso_disconnected(struct bt_bap_ep *ep, uint8_t reason) LOG_DBG("stream %p ep %p state %s reason 0x%02x", stream, stream->ep, bt_bap_ep_state_str(ep->status.state), reason); + stream_ops = stream->ops; + if (stream_ops != NULL && stream_ops->disconnected != NULL) { + stream_ops->disconnected(stream, reason); + } + /* Cancel ASE disconnect work if pending */ (void)k_work_cancel_delayable(&ase->disconnect_work); ep->reason = reason; diff --git a/subsys/bluetooth/audio/bap_broadcast_sink.c b/subsys/bluetooth/audio/bap_broadcast_sink.c index d7e6914684b..827b3e20b2c 100644 --- a/subsys/bluetooth/audio/bap_broadcast_sink.c +++ b/subsys/bluetooth/audio/bap_broadcast_sink.c @@ -296,10 +296,13 @@ static void broadcast_sink_iso_connected(struct bt_iso_chan *chan) return; } - ops = stream->ops; - LOG_DBG("stream %p", stream); + ops = stream->ops; + if (ops != NULL && ops->connected != NULL) { + ops->connected(stream); + } + sink = broadcast_sink_lookup_iso_chan(chan); if (sink == NULL) { LOG_ERR("Could not lookup sink by iso %p", chan); @@ -311,7 +314,7 @@ static void broadcast_sink_iso_connected(struct bt_iso_chan *chan) if (ops != NULL && ops->started != NULL) { ops->started(stream); } else { - LOG_WRN("No callback for connected set"); + LOG_WRN("No callback for started set"); } all_connected = true; @@ -349,10 +352,13 @@ static void broadcast_sink_iso_disconnected(struct bt_iso_chan *chan, return; } - ops = stream->ops; - LOG_DBG("stream %p ep %p reason 0x%02x", stream, ep, reason); + ops = stream->ops; + if (ops != NULL && ops->disconnected != NULL) { + ops->disconnected(stream, reason); + } + broadcast_sink_set_ep_state(ep, BT_BAP_EP_STATE_IDLE); sink = broadcast_sink_lookup_iso_chan(chan); diff --git a/subsys/bluetooth/audio/bap_broadcast_source.c b/subsys/bluetooth/audio/bap_broadcast_source.c index 1cd83155994..375e4da9c29 100644 --- a/subsys/bluetooth/audio/bap_broadcast_source.c +++ b/subsys/bluetooth/audio/bap_broadcast_source.c @@ -166,10 +166,13 @@ static void broadcast_source_iso_connected(struct bt_iso_chan *chan) return; } - ops = stream->ops; - LOG_DBG("stream %p ep %p", stream, ep); + ops = stream->ops; + if (ops != NULL && ops->connected != NULL) { + ops->connected(stream); + } + broadcast_source_set_ep_state(ep, BT_BAP_EP_STATE_STREAMING); if (ops != NULL && ops->started != NULL) { @@ -197,10 +200,13 @@ static void broadcast_source_iso_disconnected(struct bt_iso_chan *chan, uint8_t return; } - ops = stream->ops; - LOG_DBG("stream %p ep %p reason 0x%02x", stream, stream->ep, reason); + ops = stream->ops; + if (ops != NULL && ops->disconnected != NULL) { + ops->disconnected(stream, reason); + } + broadcast_source_set_ep_state(ep, BT_BAP_EP_STATE_QOS_CONFIGURED); if (ops != NULL && ops->stopped != NULL) { diff --git a/subsys/bluetooth/audio/bap_unicast_client.c b/subsys/bluetooth/audio/bap_unicast_client.c index 933db93ec72..af34ac6e74c 100644 --- a/subsys/bluetooth/audio/bap_unicast_client.c +++ b/subsys/bluetooth/audio/bap_unicast_client.c @@ -296,6 +296,7 @@ static void unicast_client_ep_iso_sent(struct bt_iso_chan *chan) static void unicast_client_ep_iso_connected(struct bt_bap_ep *ep) { + const struct bt_bap_stream_ops *stream_ops; struct bt_bap_stream *stream; if (ep->status.state != BT_BAP_EP_STATE_ENABLING) { @@ -313,6 +314,11 @@ static void unicast_client_ep_iso_connected(struct bt_bap_ep *ep) LOG_DBG("stream %p ep %p dir %s receiver_ready %u", stream, ep, bt_audio_dir_str(ep->dir), ep->receiver_ready); + stream_ops = stream->ops; + if (stream_ops != NULL && stream_ops->connected != NULL) { + stream_ops->connected(stream); + } + if (ep->receiver_ready && ep->dir == BT_AUDIO_DIR_SOURCE) { const int err = unicast_client_send_start(ep); @@ -345,6 +351,7 @@ static void unicast_client_iso_connected(struct bt_iso_chan *chan) static void unicast_client_ep_iso_disconnected(struct bt_bap_ep *ep, uint8_t reason) { + const struct bt_bap_stream_ops *stream_ops; struct bt_bap_stream *stream; stream = ep->stream; @@ -356,6 +363,11 @@ static void unicast_client_ep_iso_disconnected(struct bt_bap_ep *ep, uint8_t rea LOG_DBG("stream %p ep %p reason 0x%02x", stream, ep, reason); ep->reason = reason; + stream_ops = stream->ops; + if (stream_ops != NULL && stream_ops->disconnected != NULL) { + stream_ops->disconnected(stream, reason); + } + /* If we were in the idle state when we started the ISO disconnection * then we need to call unicast_client_ep_idle_state again when * the ISO has finalized the disconnection @@ -714,6 +726,7 @@ static void unicast_client_ep_config_state(struct bt_bap_ep *ep, struct net_buf_ static void unicast_client_ep_qos_state(struct bt_bap_ep *ep, struct net_buf_simple *buf, uint8_t old_state) { + const struct bt_bap_stream_ops *ops; struct bt_ascs_ase_status_qos *qos; struct bt_bap_stream *stream; @@ -727,17 +740,36 @@ static void unicast_client_ep_qos_state(struct bt_bap_ep *ep, struct net_buf_sim LOG_ERR("No stream active for endpoint"); return; } + ops = stream->ops; - if (ep->dir == BT_AUDIO_DIR_SINK && stream->ops != NULL && stream->ops->disabled != NULL) { - /* If the old state was enabling or streaming, then the sink - * ASE has been disabled. Since the sink ASE does not have a - * disabling state, we can check if by comparing the old_state - */ - const bool disabled = old_state == BT_BAP_EP_STATE_ENABLING || - old_state == BT_BAP_EP_STATE_STREAMING; + if (ops != NULL) { + if (ep->dir == BT_AUDIO_DIR_SINK && ops->disabled != NULL) { + /* If the old state was enabling or streaming, then the sink + * ASE has been disabled. Since the sink ASE does not have a + * disabling state, we can check if by comparing the old_state + */ + const bool disabled = old_state == BT_BAP_EP_STATE_ENABLING || + old_state == BT_BAP_EP_STATE_STREAMING; + + if (disabled) { + ops->disabled(stream); + } + } else if (ep->dir == BT_AUDIO_DIR_SOURCE && + old_state == BT_BAP_EP_STATE_DISABLING && ops->stopped != NULL) { + /* We left the disabling state, let the upper layers know that the stream is + * stopped + */ + uint8_t reason = ep->reason; + + if (reason == BT_HCI_ERR_SUCCESS) { + /* Default to BT_HCI_ERR_UNSPECIFIED if no other reason is set */ + reason = BT_HCI_ERR_UNSPECIFIED; + } else { + /* Reset reason */ + ep->reason = BT_HCI_ERR_SUCCESS; + } - if (disabled) { - stream->ops->disabled(stream); + ops->stopped(stream, reason); } } diff --git a/subsys/bluetooth/audio/cap_stream.c b/subsys/bluetooth/audio/cap_stream.c index 863d32874a2..9d0a1004517 100644 --- a/subsys/bluetooth/audio/cap_stream.c +++ b/subsys/bluetooth/audio/cap_stream.c @@ -182,6 +182,28 @@ static void cap_stream_sent_cb(struct bt_bap_stream *bap_stream) } #endif /* CONFIG_BT_AUDIO_TX */ +static void cap_stream_connected_cb(struct bt_bap_stream *bap_stream) +{ + struct bt_cap_stream *cap_stream = + CONTAINER_OF(bap_stream, struct bt_cap_stream, bap_stream); + struct bt_bap_stream_ops *ops = cap_stream->ops; + + if (ops != NULL && ops->connected != NULL) { + ops->connected(bap_stream); + } +} + +static void cap_stream_disconnected_cb(struct bt_bap_stream *bap_stream, uint8_t reason) +{ + struct bt_cap_stream *cap_stream = + CONTAINER_OF(bap_stream, struct bt_cap_stream, bap_stream); + struct bt_bap_stream_ops *ops = cap_stream->ops; + + if (ops != NULL && ops->disconnected != NULL) { + ops->disconnected(bap_stream, reason); + } +} + static struct bt_bap_stream_ops bap_stream_ops = { #if defined(CONFIG_BT_BAP_UNICAST) .configured = cap_stream_configured_cb, @@ -199,6 +221,8 @@ static struct bt_bap_stream_ops bap_stream_ops = { #if defined(CONFIG_BT_AUDIO_TX) .sent = cap_stream_sent_cb, #endif /* CONFIG_BT_AUDIO_TX */ + .connected = cap_stream_connected_cb, + .disconnected = cap_stream_disconnected_cb, }; void bt_cap_stream_ops_register_bap(struct bt_cap_stream *cap_stream) diff --git a/tests/bluetooth/audio/ascs/src/main.c b/tests/bluetooth/audio/ascs/src/main.c index fa1ad698a36..69e738dceb8 100644 --- a/tests/bluetooth/audio/ascs/src/main.c +++ b/tests/bluetooth/audio/ascs/src/main.c @@ -404,6 +404,7 @@ ZTEST_F(ascs_test_suite, test_cis_link_loss_in_streaming_state) expect_bt_bap_stream_ops_qos_set_called_once(stream); expect_bt_bap_stream_ops_disabled_called_once(stream); expect_bt_bap_stream_ops_released_not_called(); + expect_bt_bap_stream_ops_disconnected_called_once(stream); bt_bap_unicast_server_unregister_cb(&mock_bap_unicast_server_cb); } @@ -448,6 +449,7 @@ static void test_cis_link_loss_in_disabling_state(struct ascs_test_suite_fixture expect_bt_bap_stream_ops_qos_set_called_once(stream); expect_bt_bap_stream_ops_disabled_not_called(); expect_bt_bap_stream_ops_released_not_called(); + expect_bt_bap_stream_ops_disconnected_called_once(stream); bt_bap_unicast_server_unregister_cb(&mock_bap_unicast_server_cb); } @@ -495,6 +497,7 @@ ZTEST_F(ascs_test_suite, test_cis_link_loss_in_enabling_state) /* Expected no change in ASE state */ expect_bt_bap_stream_ops_qos_set_not_called(); expect_bt_bap_stream_ops_released_not_called(); + expect_bt_bap_stream_ops_disconnected_called_once(stream); err = bt_bap_stream_disable(stream); zassert_equal(0, err, "Failed to disable stream: err %d", err); @@ -534,6 +537,7 @@ ZTEST_F(ascs_test_suite, test_cis_link_loss_in_enabling_state_client_retries) test_preamble_state_enabling(conn, ase_id, stream); err = mock_bt_iso_accept(conn, 0x01, 0x01, &chan); zassert_equal(0, err, "Failed to connect iso: err %d", err); + expect_bt_bap_stream_ops_connected_called_once(stream); /* Mock CIS disconnection */ mock_bt_iso_disconnected(chan, BT_HCI_ERR_CONN_FAIL_TO_ESTAB); @@ -541,6 +545,7 @@ ZTEST_F(ascs_test_suite, test_cis_link_loss_in_enabling_state_client_retries) /* Expected to not notify the upper layers */ expect_bt_bap_stream_ops_qos_set_not_called(); expect_bt_bap_stream_ops_released_not_called(); + expect_bt_bap_stream_ops_disconnected_called_once(stream); /* Client retries to establish CIS */ err = mock_bt_iso_accept(conn, 0x01, 0x01, &chan); @@ -552,6 +557,7 @@ ZTEST_F(ascs_test_suite, test_cis_link_loss_in_enabling_state_client_retries) zassert_equal(0, err, "bt_bap_stream_start err %d", err); } + expect_bt_bap_stream_ops_connected_called_twice(stream); expect_bt_bap_stream_ops_started_called_once(stream); bt_bap_unicast_server_unregister_cb(&mock_bap_unicast_server_cb); diff --git a/tests/bluetooth/audio/ascs/src/test_ase_state_transition.c b/tests/bluetooth/audio/ascs/src/test_ase_state_transition.c index 4f7914b1f23..71f0a582eec 100644 --- a/tests/bluetooth/audio/ascs/src/test_ase_state_transition.c +++ b/tests/bluetooth/audio/ascs/src/test_ase_state_transition.c @@ -288,6 +288,7 @@ ZTEST_F(test_sink_ase_state_transition, test_client_streaming_to_releasing) expect_bt_bap_stream_ops_stopped_called_once(stream, BT_HCI_ERR_REMOTE_USER_TERM_CONN); expect_bt_bap_stream_ops_released_called_once(stream); expect_bt_bap_stream_ops_disabled_not_called(); + expect_bt_bap_stream_ops_disconnected_called_once(stream); } ZTEST_F(test_sink_ase_state_transition, test_client_streaming_to_streaming) @@ -510,6 +511,7 @@ ZTEST_F(test_sink_ase_state_transition, test_server_enabling_to_streaming) zassert_false(err < 0, "bt_bap_stream_start returned err %d", err); /* Verification */ + expect_bt_bap_stream_ops_connected_called_once(stream); expect_bt_bap_stream_ops_started_called_once(stream); expect_bt_bap_stream_ops_disabled_not_called(); /* XXX: unicast_server_cb->start is not called for Sink ASE */ @@ -585,6 +587,7 @@ ZTEST_F(test_sink_ase_state_transition, test_server_streaming_to_releasing) expect_bt_bap_stream_ops_stopped_called_once(stream, BT_HCI_ERR_LOCALHOST_TERM_CONN); expect_bt_bap_stream_ops_released_called_once(stream); expect_bt_bap_stream_ops_disabled_not_called(); + expect_bt_bap_stream_ops_disconnected_called_once(stream); } static void *test_source_ase_state_transition_setup(void) @@ -711,6 +714,7 @@ ZTEST_F(test_source_ase_state_transition, test_client_enabling_to_streaming) /* Verification */ expect_bt_bap_unicast_server_cb_start_called_once(stream); + expect_bt_bap_stream_ops_connected_called_once(stream); expect_bt_bap_stream_ops_started_called_once(stream); expect_bt_bap_stream_ops_disabled_not_called(); } @@ -841,6 +845,7 @@ ZTEST_F(test_source_ase_state_transition, test_client_streaming_to_releasing) expect_bt_bap_stream_ops_stopped_called_once(stream, BT_HCI_ERR_REMOTE_USER_TERM_CONN); expect_bt_bap_stream_ops_released_called_once(stream); expect_bt_bap_stream_ops_disabled_not_called(); + expect_bt_bap_stream_ops_disconnected_called_once(stream); } ZTEST_F(test_source_ase_state_transition, test_client_streaming_to_streaming) @@ -1160,4 +1165,5 @@ ZTEST_F(test_source_ase_state_transition, test_server_streaming_to_releasing) expect_bt_bap_stream_ops_stopped_called_once(stream, BT_HCI_ERR_LOCALHOST_TERM_CONN); expect_bt_bap_stream_ops_released_called_once(stream); expect_bt_bap_stream_ops_disabled_not_called(); + expect_bt_bap_stream_ops_disconnected_called_once(stream); } diff --git a/tests/bluetooth/audio/bap_broadcast_source/src/main.c b/tests/bluetooth/audio/bap_broadcast_source/src/main.c index 8d85eb321ac..49605562269 100644 --- a/tests/bluetooth/audio/bap_broadcast_source/src/main.c +++ b/tests/bluetooth/audio/bap_broadcast_source/src/main.c @@ -218,6 +218,8 @@ ZTEST_F(bap_broadcast_source_test_suite, test_broadcast_source_create_start_send err = bt_bap_broadcast_source_start(fixture->source, &ext_adv); zassert_equal(0, err, "Unable to start broadcast source: err %d", err); + zexpect_call_count("bt_bap_stream_ops.connected", fixture->stream_cnt, + mock_bap_stream_connected_cb_fake.call_count); zexpect_call_count("bt_bap_stream_ops.started", fixture->stream_cnt, mock_bap_stream_started_cb_fake.call_count); @@ -239,6 +241,8 @@ ZTEST_F(bap_broadcast_source_test_suite, test_broadcast_source_create_start_send err = bt_bap_broadcast_source_stop(fixture->source); zassert_equal(0, err, "Unable to stop broadcast source: err %d", err); + zexpect_call_count("bt_bap_stream_ops.disconnected", fixture->stream_cnt, + mock_bap_stream_disconnected_cb_fake.call_count); zexpect_call_count("bt_bap_stream_ops.stopped", fixture->stream_cnt, mock_bap_stream_stopped_cb_fake.call_count); diff --git a/tests/bluetooth/audio/mocks/include/bap_stream.h b/tests/bluetooth/audio/mocks/include/bap_stream.h index 41d146f810d..8bc1d3217e4 100644 --- a/tests/bluetooth/audio/mocks/include/bap_stream.h +++ b/tests/bluetooth/audio/mocks/include/bap_stream.h @@ -27,5 +27,7 @@ DECLARE_FAKE_VOID_FUNC(mock_bap_stream_stopped_cb, struct bt_bap_stream *, uint8 DECLARE_FAKE_VOID_FUNC(mock_bap_stream_recv_cb, struct bt_bap_stream *, const struct bt_iso_recv_info *, struct net_buf *); DECLARE_FAKE_VOID_FUNC(mock_bap_stream_sent_cb, struct bt_bap_stream *); +DECLARE_FAKE_VOID_FUNC(mock_bap_stream_connected_cb, struct bt_bap_stream *); +DECLARE_FAKE_VOID_FUNC(mock_bap_stream_disconnected_cb, struct bt_bap_stream *, uint8_t); #endif /* MOCKS_BAP_STREAM_H_ */ diff --git a/tests/bluetooth/audio/mocks/include/bap_stream_expects.h b/tests/bluetooth/audio/mocks/include/bap_stream_expects.h index 3912f9331d0..526e7a4ed40 100644 --- a/tests/bluetooth/audio/mocks/include/bap_stream_expects.h +++ b/tests/bluetooth/audio/mocks/include/bap_stream_expects.h @@ -135,7 +135,7 @@ static inline void expect_bt_bap_stream_ops_released_called(const struct bt_bap_ } } -static inline void expect_bt_bap_stream_ops_released_called_once(struct bt_bap_stream *stream) +static inline void expect_bt_bap_stream_ops_released_called_once(const struct bt_bap_stream *stream) { expect_bt_bap_stream_ops_released_called(&stream, 1); } @@ -193,6 +193,45 @@ static inline void expect_bt_bap_stream_ops_stopped_not_called(void) zexpect_call_count(func_name, 0, mock_bap_stream_stopped_cb_fake.call_count); } +static inline void +expect_bt_bap_stream_ops_connected_called_once(const struct bt_bap_stream *stream) +{ + const char *func_name = "bt_bap_stream_ops.connected"; + + zexpect_call_count(func_name, 1, mock_bap_stream_connected_cb_fake.call_count); + + if (mock_bap_stream_connected_cb_fake.call_count > 0) { + zexpect_equal_ptr(stream, mock_bap_stream_connected_cb_fake.arg0_val, + "'%s()' was called with incorrect '%s'", func_name, "stream"); + } +} + +static inline void +expect_bt_bap_stream_ops_connected_called_twice(const struct bt_bap_stream *stream) +{ + const char *func_name = "bt_bap_stream_ops.connected"; + + zexpect_call_count(func_name, 2, mock_bap_stream_connected_cb_fake.call_count); + + if (mock_bap_stream_connected_cb_fake.call_count > 0) { + zexpect_equal_ptr(stream, mock_bap_stream_connected_cb_fake.arg0_val, + "'%s()' was called with incorrect '%s'", func_name, "stream"); + } +} + +static inline void +expect_bt_bap_stream_ops_disconnected_called_once(const struct bt_bap_stream *stream) +{ + const char *func_name = "bt_bap_stream_ops.disconnected"; + + zexpect_call_count(func_name, 1, mock_bap_stream_disconnected_cb_fake.call_count); + + if (mock_bap_stream_disconnected_cb_fake.call_count > 0) { + zexpect_equal_ptr(stream, mock_bap_stream_disconnected_cb_fake.arg0_val, + "'%s()' was called with incorrect '%s'", func_name, "stream"); + } +} + static inline void expect_bt_bap_stream_ops_recv_called_once(struct bt_bap_stream *stream, const struct bt_iso_recv_info *info, struct net_buf *buf) diff --git a/tests/bluetooth/audio/mocks/src/bap_stream.c b/tests/bluetooth/audio/mocks/src/bap_stream.c index f55fe226ec7..940dbeb76dc 100644 --- a/tests/bluetooth/audio/mocks/src/bap_stream.c +++ b/tests/bluetooth/audio/mocks/src/bap_stream.c @@ -20,6 +20,8 @@ FAKE(mock_bap_stream_stopped_cb) \ FAKE(mock_bap_stream_recv_cb) \ FAKE(mock_bap_stream_sent_cb) \ + FAKE(mock_bap_stream_connected_cb) \ + FAKE(mock_bap_stream_disconnected_cb) struct bt_bap_stream_ops mock_bap_stream_ops; @@ -35,6 +37,8 @@ DEFINE_FAKE_VOID_FUNC(mock_bap_stream_stopped_cb, struct bt_bap_stream *, uint8_ DEFINE_FAKE_VOID_FUNC(mock_bap_stream_recv_cb, struct bt_bap_stream *, const struct bt_iso_recv_info *, struct net_buf *); DEFINE_FAKE_VOID_FUNC(mock_bap_stream_sent_cb, struct bt_bap_stream *); +DEFINE_FAKE_VOID_FUNC(mock_bap_stream_connected_cb, struct bt_bap_stream *); +DEFINE_FAKE_VOID_FUNC(mock_bap_stream_disconnected_cb, struct bt_bap_stream *, uint8_t); void mock_bap_stream_init(void) { @@ -56,6 +60,8 @@ void mock_bap_stream_init(void) #if defined(CONFIG_BT_AUDIO_TX) mock_bap_stream_ops.sent = mock_bap_stream_sent_cb; #endif /* CONFIG_BT_AUDIO_TX */ + mock_bap_stream_ops.connected = mock_bap_stream_connected_cb; + mock_bap_stream_ops.disconnected = mock_bap_stream_disconnected_cb; } void mock_bap_stream_cleanup(void) diff --git a/tests/bsim/bluetooth/audio/src/bap_unicast_client_test.c b/tests/bsim/bluetooth/audio/src/bap_unicast_client_test.c index 0fe3156afe8..3386986e568 100644 --- a/tests/bsim/bluetooth/audio/src/bap_unicast_client_test.c +++ b/tests/bsim/bluetooth/audio/src/bap_unicast_client_test.c @@ -45,7 +45,10 @@ static atomic_t flag_stream_qos_configured; CREATE_FLAG(flag_stream_enabled); CREATE_FLAG(flag_stream_metadata); CREATE_FLAG(flag_stream_started); +CREATE_FLAG(flag_stream_connected); +CREATE_FLAG(flag_stream_disconnected); CREATE_FLAG(flag_stream_disabled); +CREATE_FLAG(flag_stream_stopped); CREATE_FLAG(flag_stream_released); CREATE_FLAG(flag_operation_success); @@ -86,6 +89,20 @@ static void stream_started(struct bt_bap_stream *stream) SET_FLAG(flag_stream_started); } +static void stream_connected(struct bt_bap_stream *stream) +{ + printk("Connected stream %p\n", stream); + + SET_FLAG(flag_stream_connected); +} + +static void stream_disconnected(struct bt_bap_stream *stream, uint8_t reason) +{ + printk("Disconnected stream %p with reason %u\n", stream, reason); + + SET_FLAG(flag_stream_disconnected); +} + static void stream_metadata_updated(struct bt_bap_stream *stream) { printk("Metadata updated stream %p\n", stream); @@ -107,6 +124,8 @@ static void stream_disabled(struct bt_bap_stream *stream) static void stream_stopped(struct bt_bap_stream *stream, uint8_t reason) { printk("Stopped stream %p with reason 0x%02X\n", stream, reason); + + SET_FLAG(flag_stream_stopped); } static void stream_released(struct bt_bap_stream *stream) @@ -198,6 +217,8 @@ static struct bt_bap_stream_ops stream_ops = { .released = stream_released, .recv = stream_recv_cb, .sent = stream_sent_cb, + .connected = stream_connected, + .disconnected = stream_disconnected, }; static void unicast_client_location_cb(struct bt_conn *conn, @@ -764,6 +785,8 @@ static void start_streams(void) source_stream = pair_params[0].rx_param == NULL ? NULL : pair_params[0].rx_param->stream; sink_stream = pair_params[0].tx_param == NULL ? NULL : pair_params[0].tx_param->stream; + UNSET_FLAG(flag_stream_connected); + if (sink_stream != NULL) { const int err = start_stream(sink_stream); @@ -783,6 +806,8 @@ static void start_streams(void) return; } } + + WAIT_FOR_FLAG(flag_stream_connected); } static void transceive_streams(void) @@ -843,6 +868,42 @@ static void disable_streams(size_t stream_cnt) } } +static void stop_streams(size_t stream_cnt) +{ + UNSET_FLAG(flag_stream_disconnected); + + for (size_t i = 0; i < stream_cnt; i++) { + struct bt_bap_stream *source_stream; + int err; + + /* We can only stop source streams */ + source_stream = + pair_params[i].rx_param == NULL ? NULL : pair_params[i].rx_param->stream; + + if (source_stream == NULL) { + continue; + } + + UNSET_FLAG(flag_operation_success); + UNSET_FLAG(flag_stream_stopped); + + do { + err = bt_bap_stream_stop(source_stream); + if (err == -EBUSY) { + k_sleep(BAP_STREAM_RETRY_WAIT); + } else if (err != 0) { + FAIL("Could not stop stream: %d\n", err); + return; + } + } while (err == -EBUSY); + + WAIT_FOR_FLAG(flag_operation_success); + WAIT_FOR_FLAG(flag_stream_stopped); + } + + WAIT_FOR_FLAG(flag_stream_disconnected); +} + static void release_streams(size_t stream_cnt) { for (size_t i = 0; i < stream_cnt; i++) { @@ -994,9 +1055,12 @@ static void test_main(void) printk("Starting transceiving\n"); transceive_streams(); - printk("Stopping streams\n"); + printk("Disabling streams\n"); disable_streams(stream_cnt); + printk("Stopping streams\n"); + stop_streams(stream_cnt); + printk("Releasing streams\n"); release_streams(stream_cnt); From ce1be0e121d37cc1d22c8b57cdbab811bbe77da8 Mon Sep 17 00:00:00 2001 From: Sylvio Alves Date: Wed, 10 Jan 2024 11:49:35 -0300 Subject: [PATCH 2660/3723] boards: esp32xx: decrease Wi-Fi minimum heap size Decrease total RAM usage when Wi-Fi is enabled, specially after `config HEAP_MEM_POOL_ADD_SIZE_BOARD` was added. This allows application to handle additional HEAP as required. Signed-off-by: Sylvio Alves --- boards/riscv/esp32c3_devkitm/Kconfig.defconfig | 3 ++- boards/riscv/esp32c3_luatos_core/Kconfig.defconfig | 3 ++- boards/riscv/icev_wireless/Kconfig.defconfig | 3 ++- boards/riscv/stamp_c3/Kconfig.defconfig | 3 ++- boards/riscv/xiao_esp32c3/Kconfig.defconfig | 3 ++- boards/xtensa/esp32_devkitc_wroom/Kconfig.defconfig | 3 ++- boards/xtensa/esp32_devkitc_wrover/Kconfig.defconfig | 3 ++- boards/xtensa/esp32_ethernet_kit/Kconfig.defconfig | 3 ++- boards/xtensa/esp32s2_franzininho/Kconfig.defconfig | 2 +- boards/xtensa/esp32s3_devkitm/Kconfig.defconfig | 3 ++- boards/xtensa/esp32s3_luatos_core/Kconfig.defconfig | 3 ++- boards/xtensa/esp_wrover_kit/Kconfig.defconfig | 3 ++- boards/xtensa/heltec_wifi_lora32_v2/Kconfig.defconfig | 3 ++- boards/xtensa/heltec_wireless_stick_lite_v3/Kconfig.defconfig | 3 ++- boards/xtensa/kincony_kc868_a32/Kconfig.defconfig | 3 ++- boards/xtensa/m5stack_atoms3/Kconfig.defconfig | 3 ++- boards/xtensa/m5stack_core2/Kconfig.defconfig | 3 ++- boards/xtensa/m5stickc_plus/Kconfig.defconfig | 3 ++- boards/xtensa/odroid_go/Kconfig.defconfig | 3 ++- boards/xtensa/olimex_esp32_evb/Kconfig.defconfig | 3 ++- boards/xtensa/xiao_esp32s3/Kconfig.defconfig | 3 ++- boards/xtensa/yd_esp32/Kconfig.defconfig | 3 ++- samples/net/wifi/boards/esp32_devkitc_wroom.conf | 1 - samples/net/wifi/boards/esp32_devkitc_wrover.conf | 1 - samples/net/wifi/boards/esp32c3_devkitm.conf | 1 - samples/net/wifi/boards/esp32c3_luatos_core.conf | 1 - samples/net/wifi/boards/esp32c3_luatos_core_usb.conf | 1 - samples/net/wifi/boards/yd_esp32.conf | 1 - 28 files changed, 43 insertions(+), 28 deletions(-) diff --git a/boards/riscv/esp32c3_devkitm/Kconfig.defconfig b/boards/riscv/esp32c3_devkitm/Kconfig.defconfig index 50f3d6b382c..922368f923b 100644 --- a/boards/riscv/esp32c3_devkitm/Kconfig.defconfig +++ b/boards/riscv/esp32c3_devkitm/Kconfig.defconfig @@ -9,7 +9,8 @@ config BOARD config HEAP_MEM_POOL_ADD_SIZE_BOARD int - default 98304 if WIFI + default 65535 if WIFI && BT + default 51200 if WIFI default 40960 if BT default 4096 diff --git a/boards/riscv/esp32c3_luatos_core/Kconfig.defconfig b/boards/riscv/esp32c3_luatos_core/Kconfig.defconfig index d132f546144..82e3a5a0c94 100644 --- a/boards/riscv/esp32c3_luatos_core/Kconfig.defconfig +++ b/boards/riscv/esp32c3_luatos_core/Kconfig.defconfig @@ -9,7 +9,8 @@ config BOARD config HEAP_MEM_POOL_ADD_SIZE_BOARD int - default 98304 if WIFI + default 65535 if WIFI && BT + default 51200 if WIFI default 40960 if BT default 4096 diff --git a/boards/riscv/icev_wireless/Kconfig.defconfig b/boards/riscv/icev_wireless/Kconfig.defconfig index 1eca2f02e6d..44157fd5b6a 100644 --- a/boards/riscv/icev_wireless/Kconfig.defconfig +++ b/boards/riscv/icev_wireless/Kconfig.defconfig @@ -7,7 +7,8 @@ config BOARD config HEAP_MEM_POOL_ADD_SIZE_BOARD int - default 98304 if WIFI + default 65535 if WIFI && BT + default 51200 if WIFI default 40960 if BT default 4096 diff --git a/boards/riscv/stamp_c3/Kconfig.defconfig b/boards/riscv/stamp_c3/Kconfig.defconfig index 6ad89229799..911a8845d70 100644 --- a/boards/riscv/stamp_c3/Kconfig.defconfig +++ b/boards/riscv/stamp_c3/Kconfig.defconfig @@ -9,7 +9,8 @@ config BOARD config HEAP_MEM_POOL_ADD_SIZE_BOARD int - default 98304 if WIFI + default 65535 if WIFI && BT + default 51200 if WIFI default 40960 if BT default 4096 diff --git a/boards/riscv/xiao_esp32c3/Kconfig.defconfig b/boards/riscv/xiao_esp32c3/Kconfig.defconfig index 52c7a95c46c..2852d11301d 100644 --- a/boards/riscv/xiao_esp32c3/Kconfig.defconfig +++ b/boards/riscv/xiao_esp32c3/Kconfig.defconfig @@ -7,7 +7,8 @@ config BOARD config HEAP_MEM_POOL_ADD_SIZE_BOARD int - default 98304 if WIFI + default 65535 if WIFI && BT + default 51200 if WIFI default 40960 if BT default 4096 diff --git a/boards/xtensa/esp32_devkitc_wroom/Kconfig.defconfig b/boards/xtensa/esp32_devkitc_wroom/Kconfig.defconfig index 58146fb1202..aadb2d833f8 100644 --- a/boards/xtensa/esp32_devkitc_wroom/Kconfig.defconfig +++ b/boards/xtensa/esp32_devkitc_wroom/Kconfig.defconfig @@ -10,7 +10,8 @@ config BOARD config HEAP_MEM_POOL_ADD_SIZE_BOARD int - default 98304 if WIFI + default 65535 if WIFI && BT + default 51200 if WIFI default 40960 if BT default 4096 diff --git a/boards/xtensa/esp32_devkitc_wrover/Kconfig.defconfig b/boards/xtensa/esp32_devkitc_wrover/Kconfig.defconfig index ec1ce4ff87e..84b365c2b77 100644 --- a/boards/xtensa/esp32_devkitc_wrover/Kconfig.defconfig +++ b/boards/xtensa/esp32_devkitc_wrover/Kconfig.defconfig @@ -8,7 +8,8 @@ config BOARD config HEAP_MEM_POOL_ADD_SIZE_BOARD int - default 98304 if WIFI + default 65535 if WIFI && BT + default 51200 if WIFI default 40960 if BT default 4096 diff --git a/boards/xtensa/esp32_ethernet_kit/Kconfig.defconfig b/boards/xtensa/esp32_ethernet_kit/Kconfig.defconfig index 78dd56efa0f..8797780b74e 100644 --- a/boards/xtensa/esp32_ethernet_kit/Kconfig.defconfig +++ b/boards/xtensa/esp32_ethernet_kit/Kconfig.defconfig @@ -19,7 +19,8 @@ config ENTROPY_GENERATOR config HEAP_MEM_POOL_ADD_SIZE_BOARD int - default 98304 if WIFI + default 65535 if WIFI && BT + default 51200 if WIFI default 40960 if BT default 4096 diff --git a/boards/xtensa/esp32s2_franzininho/Kconfig.defconfig b/boards/xtensa/esp32s2_franzininho/Kconfig.defconfig index d8bd4c6916f..2319c0061e4 100644 --- a/boards/xtensa/esp32s2_franzininho/Kconfig.defconfig +++ b/boards/xtensa/esp32s2_franzininho/Kconfig.defconfig @@ -12,5 +12,5 @@ config ENTROPY_GENERATOR config HEAP_MEM_POOL_ADD_SIZE_BOARD int - default 98304 if WIFI + default 32768 if WIFI default 4096 diff --git a/boards/xtensa/esp32s3_devkitm/Kconfig.defconfig b/boards/xtensa/esp32s3_devkitm/Kconfig.defconfig index 0fdbe2af120..54a01595721 100644 --- a/boards/xtensa/esp32s3_devkitm/Kconfig.defconfig +++ b/boards/xtensa/esp32s3_devkitm/Kconfig.defconfig @@ -10,7 +10,8 @@ config BOARD config HEAP_MEM_POOL_ADD_SIZE_BOARD int - default 98304 if WIFI + default 65535 if WIFI && BT + default 51200 if WIFI default 40960 if BT default 4096 diff --git a/boards/xtensa/esp32s3_luatos_core/Kconfig.defconfig b/boards/xtensa/esp32s3_luatos_core/Kconfig.defconfig index e5b99a7818a..35d4a9bc3fc 100644 --- a/boards/xtensa/esp32s3_luatos_core/Kconfig.defconfig +++ b/boards/xtensa/esp32s3_luatos_core/Kconfig.defconfig @@ -12,7 +12,8 @@ config ENTROPY_GENERATOR config HEAP_MEM_POOL_ADD_SIZE_BOARD int - default 98304 if WIFI + default 65535 if WIFI && BT + default 51200 if WIFI default 40960 if BT default 4096 diff --git a/boards/xtensa/esp_wrover_kit/Kconfig.defconfig b/boards/xtensa/esp_wrover_kit/Kconfig.defconfig index 02ef06aba61..378b557eb7f 100644 --- a/boards/xtensa/esp_wrover_kit/Kconfig.defconfig +++ b/boards/xtensa/esp_wrover_kit/Kconfig.defconfig @@ -9,7 +9,8 @@ config BOARD config HEAP_MEM_POOL_ADD_SIZE_BOARD int - default 98304 if WIFI + default 65535 if WIFI && BT + default 51200 if WIFI default 40960 if BT default 4096 diff --git a/boards/xtensa/heltec_wifi_lora32_v2/Kconfig.defconfig b/boards/xtensa/heltec_wifi_lora32_v2/Kconfig.defconfig index 79349187103..eaf538cd281 100644 --- a/boards/xtensa/heltec_wifi_lora32_v2/Kconfig.defconfig +++ b/boards/xtensa/heltec_wifi_lora32_v2/Kconfig.defconfig @@ -12,7 +12,8 @@ config ENTROPY_GENERATOR config HEAP_MEM_POOL_ADD_SIZE_BOARD int - default 98304 if WIFI + default 65535 if WIFI && BT + default 51200 if WIFI default 40960 if BT default 4096 diff --git a/boards/xtensa/heltec_wireless_stick_lite_v3/Kconfig.defconfig b/boards/xtensa/heltec_wireless_stick_lite_v3/Kconfig.defconfig index d5cdd956f81..ea79f62e2fa 100644 --- a/boards/xtensa/heltec_wireless_stick_lite_v3/Kconfig.defconfig +++ b/boards/xtensa/heltec_wireless_stick_lite_v3/Kconfig.defconfig @@ -13,7 +13,8 @@ config ENTROPY_GENERATOR config HEAP_MEM_POOL_ADD_SIZE_BOARD int - default 98304 if WIFI + default 65535 if WIFI && BT + default 51200 if WIFI default 40960 if BT default 4096 diff --git a/boards/xtensa/kincony_kc868_a32/Kconfig.defconfig b/boards/xtensa/kincony_kc868_a32/Kconfig.defconfig index 229aaaeb4e3..85e02264b5a 100644 --- a/boards/xtensa/kincony_kc868_a32/Kconfig.defconfig +++ b/boards/xtensa/kincony_kc868_a32/Kconfig.defconfig @@ -9,6 +9,7 @@ config ENTROPY_GENERATOR default y config HEAP_MEM_POOL_SIZE - default 98304 if WIFI + default 65535 if WIFI && BT + default 51200 if WIFI default 40960 if BT default 4096 diff --git a/boards/xtensa/m5stack_atoms3/Kconfig.defconfig b/boards/xtensa/m5stack_atoms3/Kconfig.defconfig index 2ae18530839..94f209758eb 100644 --- a/boards/xtensa/m5stack_atoms3/Kconfig.defconfig +++ b/boards/xtensa/m5stack_atoms3/Kconfig.defconfig @@ -13,7 +13,8 @@ config ENTROPY_GENERATOR config HEAP_MEM_POOL_ADD_SIZE_BOARD int - default 98304 if WIFI + default 65535 if WIFI && BT + default 51200 if WIFI default 65536 if BT default 4096 diff --git a/boards/xtensa/m5stack_core2/Kconfig.defconfig b/boards/xtensa/m5stack_core2/Kconfig.defconfig index 388bc5c027c..0edbda5d302 100644 --- a/boards/xtensa/m5stack_core2/Kconfig.defconfig +++ b/boards/xtensa/m5stack_core2/Kconfig.defconfig @@ -14,7 +14,8 @@ config ENTROPY_GENERATOR config HEAP_MEM_POOL_ADD_SIZE_BOARD int - default 98304 if WIFI + default 65535 if WIFI && BT + default 51200 if WIFI default 65536 if BT default 4096 diff --git a/boards/xtensa/m5stickc_plus/Kconfig.defconfig b/boards/xtensa/m5stickc_plus/Kconfig.defconfig index 20bb58c5872..a9e73202781 100644 --- a/boards/xtensa/m5stickc_plus/Kconfig.defconfig +++ b/boards/xtensa/m5stickc_plus/Kconfig.defconfig @@ -12,7 +12,8 @@ config ENTROPY_GENERATOR config HEAP_MEM_POOL_ADD_SIZE_BOARD int - default 98304 if WIFI + default 65535 if WIFI && BT + default 51200 if WIFI default 40960 if BT default 4096 diff --git a/boards/xtensa/odroid_go/Kconfig.defconfig b/boards/xtensa/odroid_go/Kconfig.defconfig index 049138994e5..1827d83a041 100644 --- a/boards/xtensa/odroid_go/Kconfig.defconfig +++ b/boards/xtensa/odroid_go/Kconfig.defconfig @@ -18,7 +18,8 @@ config ENTROPY_GENERATOR config HEAP_MEM_POOL_ADD_SIZE_BOARD int - default 98304 if WIFI + default 65535 if WIFI && BT + default 51200 if WIFI default 40960 if BT default 4096 diff --git a/boards/xtensa/olimex_esp32_evb/Kconfig.defconfig b/boards/xtensa/olimex_esp32_evb/Kconfig.defconfig index 34808e57c67..6aca00ecad5 100644 --- a/boards/xtensa/olimex_esp32_evb/Kconfig.defconfig +++ b/boards/xtensa/olimex_esp32_evb/Kconfig.defconfig @@ -13,7 +13,8 @@ config ENTROPY_GENERATOR config HEAP_MEM_POOL_ADD_SIZE_BOARD int - default 98304 if WIFI + default 65535 if WIFI && BT + default 51200 if WIFI default 40960 if BT default 4096 diff --git a/boards/xtensa/xiao_esp32s3/Kconfig.defconfig b/boards/xtensa/xiao_esp32s3/Kconfig.defconfig index 123fff98e82..3bc3e999189 100644 --- a/boards/xtensa/xiao_esp32s3/Kconfig.defconfig +++ b/boards/xtensa/xiao_esp32s3/Kconfig.defconfig @@ -10,7 +10,8 @@ config ENTROPY_GENERATOR config HEAP_MEM_POOL_ADD_SIZE_BOARD int - default 98304 if WIFI + default 65535 if WIFI && BT + default 51200 if WIFI default 40960 if BT default 4096 diff --git a/boards/xtensa/yd_esp32/Kconfig.defconfig b/boards/xtensa/yd_esp32/Kconfig.defconfig index 7a2b83553f4..4807671ca79 100644 --- a/boards/xtensa/yd_esp32/Kconfig.defconfig +++ b/boards/xtensa/yd_esp32/Kconfig.defconfig @@ -12,7 +12,8 @@ config ENTROPY_GENERATOR config HEAP_MEM_POOL_ADD_SIZE_BOARD int - default 98304 if WIFI + default 65535 if WIFI && BT + default 51200 if WIFI default 40960 if BT default 4096 diff --git a/samples/net/wifi/boards/esp32_devkitc_wroom.conf b/samples/net/wifi/boards/esp32_devkitc_wroom.conf index 5c37cfc402d..a72fdf39efa 100644 --- a/samples/net/wifi/boards/esp32_devkitc_wroom.conf +++ b/samples/net/wifi/boards/esp32_devkitc_wroom.conf @@ -1,5 +1,4 @@ CONFIG_WIFI=y -CONFIG_HEAP_MEM_POOL_SIZE=98304 CONFIG_NETWORKING=y CONFIG_NET_L2_ETHERNET=y diff --git a/samples/net/wifi/boards/esp32_devkitc_wrover.conf b/samples/net/wifi/boards/esp32_devkitc_wrover.conf index 5c37cfc402d..a72fdf39efa 100644 --- a/samples/net/wifi/boards/esp32_devkitc_wrover.conf +++ b/samples/net/wifi/boards/esp32_devkitc_wrover.conf @@ -1,5 +1,4 @@ CONFIG_WIFI=y -CONFIG_HEAP_MEM_POOL_SIZE=98304 CONFIG_NETWORKING=y CONFIG_NET_L2_ETHERNET=y diff --git a/samples/net/wifi/boards/esp32c3_devkitm.conf b/samples/net/wifi/boards/esp32c3_devkitm.conf index 5c37cfc402d..a72fdf39efa 100644 --- a/samples/net/wifi/boards/esp32c3_devkitm.conf +++ b/samples/net/wifi/boards/esp32c3_devkitm.conf @@ -1,5 +1,4 @@ CONFIG_WIFI=y -CONFIG_HEAP_MEM_POOL_SIZE=98304 CONFIG_NETWORKING=y CONFIG_NET_L2_ETHERNET=y diff --git a/samples/net/wifi/boards/esp32c3_luatos_core.conf b/samples/net/wifi/boards/esp32c3_luatos_core.conf index 5c37cfc402d..a72fdf39efa 100644 --- a/samples/net/wifi/boards/esp32c3_luatos_core.conf +++ b/samples/net/wifi/boards/esp32c3_luatos_core.conf @@ -1,5 +1,4 @@ CONFIG_WIFI=y -CONFIG_HEAP_MEM_POOL_SIZE=98304 CONFIG_NETWORKING=y CONFIG_NET_L2_ETHERNET=y diff --git a/samples/net/wifi/boards/esp32c3_luatos_core_usb.conf b/samples/net/wifi/boards/esp32c3_luatos_core_usb.conf index 5c37cfc402d..a72fdf39efa 100644 --- a/samples/net/wifi/boards/esp32c3_luatos_core_usb.conf +++ b/samples/net/wifi/boards/esp32c3_luatos_core_usb.conf @@ -1,5 +1,4 @@ CONFIG_WIFI=y -CONFIG_HEAP_MEM_POOL_SIZE=98304 CONFIG_NETWORKING=y CONFIG_NET_L2_ETHERNET=y diff --git a/samples/net/wifi/boards/yd_esp32.conf b/samples/net/wifi/boards/yd_esp32.conf index 5c37cfc402d..a72fdf39efa 100644 --- a/samples/net/wifi/boards/yd_esp32.conf +++ b/samples/net/wifi/boards/yd_esp32.conf @@ -1,5 +1,4 @@ CONFIG_WIFI=y -CONFIG_HEAP_MEM_POOL_SIZE=98304 CONFIG_NETWORKING=y CONFIG_NET_L2_ETHERNET=y From db588104921ac8bfd3f4c2b1b41c84cf5e710ec2 Mon Sep 17 00:00:00 2001 From: Rubin Gerritsen Date: Thu, 18 Jan 2024 15:32:47 +0100 Subject: [PATCH 2661/3723] Bluetooth: ISO: Fix CIS peripheral disconnection during setup When the central aborts the CIS setup during the CIS Creation procedure after it has accepted the CIS request, the peripheral will receive the HCI LE CIS Established event with an error code. It does not receive a disconnection event. See the message sequence chart in Core_v5.4, Vol 6, Part D, Section 6.23. This commit ensures that the perirpheral disconnected callback gets called for this particular scenario. Signed-off-by: Rubin Gerritsen --- subsys/bluetooth/host/iso.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/subsys/bluetooth/host/iso.c b/subsys/bluetooth/host/iso.c index 9559a552371..9a1284a03a3 100644 --- a/subsys/bluetooth/host/iso.c +++ b/subsys/bluetooth/host/iso.c @@ -1118,7 +1118,8 @@ void hci_le_cis_established(struct net_buf *buf) bt_conn_set_state(iso, BT_CONN_CONNECTED); bt_conn_unref(iso); return; - } else if (evt->status != BT_HCI_ERR_OP_CANCELLED_BY_HOST) { + } else if (iso->role == BT_HCI_ROLE_PERIPHERAL || + evt->status != BT_HCI_ERR_OP_CANCELLED_BY_HOST) { iso->err = evt->status; bt_iso_disconnected(iso); } /* else we wait for disconnect event */ From d3a3d63afb5eed868aa4ae1bd3e4ba9c69540f02 Mon Sep 17 00:00:00 2001 From: Peter Mitsis Date: Wed, 17 Jan 2024 13:17:07 -0500 Subject: [PATCH 2662/3723] tests: latency_measure: Increase verbosity of summary lines Feedback from the previous summary line change has been that it had become more difficult for people to parse and understand what is being tested/benchmarked when the description consisted of just using a terse tag. To improve the situation a more human oriented description has been added to follow that tag so that not only can tools still parse on the tag, but people can use both tag and the extra description to understand the test/benchmark. Summary lines for each test now consist of the following: 1. A terse tag (for tools to parse) 2. A more human oriented description. 3. Number of cycles. 4. Number of nanoseconds. Signed-off-by: Peter Mitsis --- tests/benchmarks/latency_measure/README.rst | 303 +++++++++--------- tests/benchmarks/latency_measure/src/events.c | 58 ++-- tests/benchmarks/latency_measure/src/fifo.c | 62 ++-- .../latency_measure/src/heap_malloc_free.c | 14 +- .../latency_measure/src/int_to_thread.c | 19 +- tests/benchmarks/latency_measure/src/lifo.c | 62 ++-- .../latency_measure/src/mutex_lock_unlock.c | 15 +- .../src/sema_test_signal_release.c | 34 +- tests/benchmarks/latency_measure/src/thread.c | 33 +- .../latency_measure/src/thread_switch_yield.c | 16 +- tests/benchmarks/latency_measure/src/utils.h | 4 +- 11 files changed, 356 insertions(+), 264 deletions(-) diff --git a/tests/benchmarks/latency_measure/README.rst b/tests/benchmarks/latency_measure/README.rst index 7e6f5787ab8..8ba99d05171 100644 --- a/tests/benchmarks/latency_measure/README.rst +++ b/tests/benchmarks/latency_measure/README.rst @@ -16,10 +16,10 @@ including: * Time it takes to suspend a thread * Time it takes to resume a suspended thread * Time it takes to abort a thread -* Time it takes to add data to a FIFO/LIFO -* Time it takes to retrieve data from a FIFO/LIFO -* Time it takes to wait on a FIFO/LIFO (and context switch) -* Time it takes to wake and switch to a thread waiting on a FIFO/LIFO +* Time it takes to add data to a fifo.LIFO +* Time it takes to retrieve data from a fifo.LIFO +* Time it takes to wait on a fifo.lifo.(and context switch) +* Time it takes to wake and switch to a thread waiting on a fifo.LIFO * Time it takes to send and receive events * Time it takes to wait for events (and context switch) * Time it takes to wake and switch to a thread waiting for events @@ -36,157 +36,158 @@ threads: Sample output of the benchmark (without userspace enabled):: - *** Booting Zephyr OS build zephyr-v3.5.0-3537-g5dbe0ce2622d *** - THREAD yield.preemptive.ctx.(K -> K) : 344 cycles , 2866 ns : - THREAD yield.cooperative.ctx.(K -> K) : 344 cycles , 2867 ns : - ISR resume.interrupted.thread.kernel : 498 cycles , 4158 ns : - ISR resume.different.thread.kernel : 383 cycles , 3199 ns : - THREAD create.kernel.from.kernel : 401 cycles , 3349 ns : - THREAD start.kernel.from.kernel : 418 cycles , 3491 ns : - THREAD suspend.kernel.from.kernel : 433 cycles , 3616 ns : - THREAD resume.kernel.from.kernel : 351 cycles , 2933 ns : - THREAD abort.kernel.from.kernel : 349 cycles , 2909 ns : - FIFO put.immediate.kernel : 294 cycles , 2450 ns : - FIFO get.immediate.kernel : 135 cycles , 1133 ns : - FIFO put.alloc.immediate.kernel : 906 cycles , 7550 ns : - FIFO get.free.immediate.kernel : 570 cycles , 4750 ns : - FIFO get.blocking.(K -> K) : 545 cycles , 4542 ns : - FIFO put.wake+ctx.(K -> K) : 675 cycles , 5625 ns : - FIFO get.free.blocking.(K -> K) : 555 cycles , 4625 ns : - FIFO put.alloc.wake+ctx.(K -> K) : 670 cycles , 5583 ns : - LIFO put.immediate.kernel : 282 cycles , 2350 ns : - LIFO get.immediate.kernel : 135 cycles , 1133 ns : - LIFO put.alloc.immediate.kernel : 903 cycles , 7526 ns : - LIFO get.free.immediate.kernel : 570 cycles , 4750 ns : - LIFO get.blocking.(K -> K) : 542 cycles , 4524 ns : - LIFO put.wake+ctx.(K -> K) : 670 cycles , 5584 ns : - LIFO get.free.blocking.(K -> K) : 547 cycles , 4558 ns : - LIFO put.alloc.wake+ctx.(K -> K) : 670 cycles , 5583 ns : - EVENTS post.immediate.kernel : 220 cycles , 1833 ns : - EVENTS set.immediate.kernel : 225 cycles , 1875 ns : - EVENTS wait.immediate.kernel : 125 cycles , 1041 ns : - EVENTS wait_all.immediate.kernel : 145 cycles , 1208 ns : - EVENTS wait.blocking.(K -> K) : 594 cycles , 4958 ns : - EVENTS set.wake+ctx.(K -> K) : 774 cycles , 6451 ns : - EVENTS wait_all.blocking.(K -> K) : 605 cycles , 5042 ns : - EVENTS post.wake+ctx.(K -> K) : 785 cycles , 6542 ns : - SEMAPHORE give.immediate.kernel : 165 cycles , 1375 ns : - SEMAPHORE take.immediate.kernel : 69 cycles , 575 ns : - SEMAPHORE take.blocking.(K -> K) : 489 cycles , 4075 ns : - SEMAPHORE give.wake+ctx.(K -> K) : 604 cycles , 5033 ns : - MUTEX lock.immediate.recursive.kernel : 115 cycles , 958 ns : - MUTEX unlock.immediate.recursive.kernel : 40 cycles , 333 ns : - HEAP malloc.immediate : 615 cycles , 5125 ns : - HEAP free.immediate : 431 cycles , 3591 ns : + *** Booting Zephyr OS build zephyr-v3.5.0-4267-g6ccdc31233a3 *** + thread.yield.preemptive.ctx.k_to_k - Context switch via k_yield : 329 cycles , 2741 ns : + thread.yield.cooperative.ctx.k_to_k - Context switch via k_yield : 329 cycles , 2741 ns : + isr.resume.interrupted.thread.kernel - Return from ISR to interrupted thread : 363 cycles , 3033 ns : + isr.resume.different.thread.kernel - Return from ISR to another thread : 404 cycles , 3367 ns : + thread.create.kernel.from.kernel - Create thread : 404 cycles , 3374 ns : + thread.start.kernel.from.kernel - Start thread : 423 cycles , 3533 ns : + thread.suspend.kernel.from.kernel - Suspend thread : 428 cycles , 3574 ns : + thread.resume.kernel.from.kernel - Resume thread : 350 cycles , 2924 ns : + thread.abort.kernel.from.kernel - Abort thread : 339 cycles , 2826 ns : + fifo.put.immediate.kernel - Add data to FIFO (no ctx switch) : 269 cycles , 2242 ns : + fifo.get.immediate.kernel - Get data from FIFO (no ctx switch) : 128 cycles , 1074 ns : + fifo.put.alloc.immediate.kernel - Allocate to add data to FIFO (no ctx switch) : 945 cycles , 7875 ns : + fifo.get.free.immediate.kernel - Free when getting data from FIFO (no ctx switch) : 575 cycles , 4792 ns : + fifo.get.blocking.k_to_k - Get data from FIFO (w/ ctx switch) : 551 cycles , 4592 ns : + fifo.put.wake+ctx.k_to_k - Add data to FIFO (w/ ctx switch) : 660 cycles , 5500 ns : + fifo.get.free.blocking.k_to_k - Free when getting data from FIFO (w/ ctx siwtch) : 553 cycles , 4608 ns : + fifo.put.alloc.wake+ctx.k_to_k - Allocate to add data to FIFO (w/ ctx switch) : 655 cycles , 5458 ns : + lifo.put.immediate.kernel - Add data to LIFO (no ctx switch) : 280 cycles , 2341 ns : + lifo.get.immediate.kernel - Get data from LIFO (no ctx switch) : 133 cycles , 1116 ns : + lifo.put.alloc.immediate.kernel - Allocate to add data to LIFO (no ctx switch) : 945 cycles , 7875 ns : + lifo.get.free.immediate.kernel - Free when getting data from LIFO (no ctx switch) : 580 cycles , 4833 ns : + lifo.get.blocking.k_to_k - Get data from LIFO (w/ ctx switch) : 553 cycles , 4608 ns : + lifo.put.wake+ctx.k_to_k - Add data to LIFO (w/ ctx switch) : 655 cycles , 5458 ns : + lifo.get.free.blocking.k_to_k - Free when getting data from LIFO (w/ ctx switch) : 550 cycles , 4583 ns : + lifo.put.alloc.wake+ctx.k_to_k - Allocate to add data to LIFO (w/ ctx siwtch) : 655 cycles , 5458 ns : + events.post.immediate.kernel - Post events (nothing wakes) : 225 cycles , 1875 ns : + events.set.immediate.kernel - Set events (nothing wakes) : 225 cycles , 1875 ns : + events.wait.immediate.kernel - Wait for any events (no ctx switch) : 130 cycles , 1083 ns : + events.wait_all.immediate.kernel - Wait for all events (no ctx switch) : 135 cycles , 1125 ns : + events.wait.blocking.k_to_k - Wait for any events (w/ ctx switch) : 573 cycles , 4783 ns : + events.set.wake+ctx.k_to_k - Set events (w/ ctx switch) : 784 cycles , 6534 ns : + events.wait_all.blocking.k_to_k - Wait for all events (w/ ctx switch) : 589 cycles , 4916 ns : + events.post.wake+ctx.k_to_k - Post events (w/ ctx switch) : 795 cycles , 6626 ns : + semaphore.give.immediate.kernel - Give a semaphore (no waiters) : 125 cycles , 1041 ns : + semaphore.take.immediate.kernel - Take a semaphore (no blocking) : 69 cycles , 575 ns : + semaphore.take.blocking.k_to_k - Take a semaphore (context switch) : 494 cycles , 4116 ns : + semaphore.give.wake+ctx.k_to_k - Give a semaphore (context switch) : 599 cycles , 4992 ns : + mutex.lock.immediate.recursive.kernel - Lock a mutex : 100 cycles , 833 ns : + mutex.unlock.immediate.recursive.kernel - Unlock a mutex : 40 cycles , 333 ns : + heap.malloc.immediate - Average time for heap malloc : 627 cycles , 5225 ns : + heap.free.immediate - Average time for heap free : 432 cycles , 3600 ns : =================================================================== PROJECT EXECUTION SUCCESSFUL + Sample output of the benchmark (with userspace enabled):: - *** Booting Zephyr OS build zephyr-v3.5.0-3537-g5dbe0ce2622d *** - THREAD yield.preemptive.ctx.(K -> K) : 990 cycles , 8250 ns : - THREAD yield.preemptive.ctx.(U -> U) : 1285 cycles , 10712 ns : - THREAD yield.preemptive.ctx.(K -> U) : 1178 cycles , 9817 ns : - THREAD yield.preemptive.ctx.(U -> K) : 1097 cycles , 9145 ns : - THREAD yield.cooperative.ctx.(K -> K) : 990 cycles , 8250 ns : - THREAD yield.cooperative.ctx.(U -> U) : 1285 cycles , 10712 ns : - THREAD yield.cooperative.ctx.(K -> U) : 1178 cycles , 9817 ns : - THREAD yield.cooperative.ctx.(U -> K) : 1097 cycles , 9146 ns : - ISR resume.interrupted.thread.kernel : 1120 cycles , 9333 ns : - ISR resume.different.thread.kernel : 1010 cycles , 8417 ns : - ISR resume.different.thread.user : 1207 cycles , 10062 ns : - THREAD create.kernel.from.kernel : 955 cycles , 7958 ns : - THREAD start.kernel.from.kernel : 1095 cycles , 9126 ns : - THREAD suspend.kernel.from.kernel : 1064 cycles , 8874 ns : - THREAD resume.kernel.from.kernel : 999 cycles , 8333 ns : - THREAD abort.kernel.from.kernel : 2280 cycles , 19000 ns : - THREAD create.user.from.kernel : 822 cycles , 6855 ns : - THREAD start.user.from.kernel : 6572 cycles , 54774 ns : - THREAD suspend.user.from.kernel : 1422 cycles , 11857 ns : - THREAD resume.user.from.kernel : 1177 cycles , 9812 ns : - THREAD abort.user.from.kernel : 2147 cycles , 17897 ns : - THREAD create.user.from.user : 2105 cycles , 17542 ns : - THREAD start.user.from.user : 6960 cycles , 58002 ns : - THREAD suspend user.from.user : 1610 cycles , 13417 ns : - THREAD resume user.from.user : 1565 cycles , 13042 ns : - THREAD abort user.from.user : 2780 cycles , 23167 ns : - THREAD start.kernel.from.user : 1482 cycles , 12353 ns : - THREAD suspend.kernel.from.user : 1252 cycles , 10437 ns : - THREAD resume.kernel.from.user : 1387 cycles , 11564 ns : - THREAD abort.kernel.from.user : 2912 cycles , 24272 ns : - FIFO put.immediate.kernel : 314 cycles , 2624 ns : - FIFO get.immediate.kernel : 215 cycles , 1792 ns : - FIFO put.alloc.immediate.kernel : 1025 cycles , 8541 ns : - FIFO get.free.immediate.kernel : 655 cycles , 5458 ns : - FIFO put.alloc.immediate.user : 1740 cycles , 14500 ns : - FIFO get.free.immediate.user : 1410 cycles , 11751 ns : - FIFO get.blocking.(K -> K) : 1249 cycles , 10416 ns : - FIFO put.wake+ctx.(K -> K) : 1320 cycles , 11000 ns : - FIFO get.free.blocking.(K -> K) : 1235 cycles , 10292 ns : - FIFO put.alloc.wake+ctx.(K -> K) : 1355 cycles , 11292 ns : - FIFO get.free.blocking.(U -> K) : 1750 cycles , 14584 ns : - FIFO put.alloc.wake+ctx.(K -> U) : 1680 cycles , 14001 ns : - FIFO get.free.blocking.(K -> U) : 1555 cycles , 12959 ns : - FIFO put.alloc.wake+ctx.(U -> K) : 1845 cycles , 15375 ns : - FIFO get.free.blocking.(U -> U) : 2070 cycles , 17251 ns : - FIFO put.alloc.wake+ctx.(U -> U) : 2170 cycles , 18084 ns : - LIFO put.immediate.kernel : 299 cycles , 2499 ns : - LIFO get.immediate.kernel : 204 cycles , 1708 ns : - LIFO put.alloc.immediate.kernel : 1015 cycles , 8459 ns : - LIFO get.free.immediate.kernel : 645 cycles , 5375 ns : - LIFO put.alloc.immediate.user : 1760 cycles , 14668 ns : - LIFO get.free.immediate.user : 1400 cycles , 11667 ns : - LIFO get.blocking.(K -> K) : 1234 cycles , 10291 ns : - LIFO put.wake+ctx.(K -> K) : 1315 cycles , 10959 ns : - LIFO get.free.blocking.(K -> K) : 1230 cycles , 10251 ns : - LIFO put.alloc.wake+ctx.(K -> K) : 1345 cycles , 11208 ns : - LIFO get.free.blocking.(U -> K) : 1745 cycles , 14544 ns : - LIFO put.alloc.wake+ctx.(K -> U) : 1680 cycles , 14000 ns : - LIFO get.free.blocking.(K -> U) : 1555 cycles , 12958 ns : - LIFO put.alloc.wake+ctx.(U -> K) : 1855 cycles , 15459 ns : - LIFO get.free.blocking.(U -> U) : 2070 cycles , 17251 ns : - LIFO put.alloc.wake+ctx.(U -> U) : 2190 cycles , 18251 ns : - EVENTS post.immediate.kernel : 285 cycles , 2375 ns : - EVENTS set.immediate.kernel : 285 cycles , 2375 ns : - EVENTS wait.immediate.kernel : 215 cycles , 1791 ns : - EVENTS wait_all.immediate.kernel : 215 cycles , 1791 ns : - EVENTS post.immediate.user : 775 cycles , 6459 ns : - EVENTS set.immediate.user : 780 cycles , 6500 ns : - EVENTS wait.immediate.user : 715 cycles , 5959 ns : - EVENTS wait_all.immediate.user : 720 cycles , 6000 ns : - EVENTS wait.blocking.(K -> K) : 1212 cycles , 10108 ns : - EVENTS set.wake+ctx.(K -> K) : 1450 cycles , 12084 ns : - EVENTS wait_all.blocking.(K -> K) : 1260 cycles , 10500 ns : - EVENTS post.wake+ctx.(K -> K) : 1490 cycles , 12417 ns : - EVENTS wait.blocking.(U -> K) : 1577 cycles , 13145 ns : - EVENTS set.wake+ctx.(K -> U) : 1617 cycles , 13479 ns : - EVENTS wait_all.blocking.(U -> K) : 1760 cycles , 14667 ns : - EVENTS post.wake+ctx.(K -> U) : 1790 cycles , 14917 ns : - EVENTS wait.blocking.(K -> U) : 1400 cycles , 11671 ns : - EVENTS set.wake+ctx.(U -> K) : 1812 cycles , 15104 ns : - EVENTS wait_all.blocking.(K -> U) : 1580 cycles , 13167 ns : - EVENTS post.wake+ctx.(U -> K) : 1985 cycles , 16542 ns : - EVENTS wait.blocking.(U -> U) : 1765 cycles , 14709 ns : - EVENTS set.wake+ctx.(U -> U) : 1979 cycles , 16499 ns : - EVENTS wait_all.blocking.(U -> U) : 2080 cycles , 17334 ns : - EVENTS post.wake+ctx.(U -> U) : 2285 cycles , 19043 ns : - SEMAPHORE give.immediate.kernel : 210 cycles , 1750 ns : - SEMAPHORE take.immediate.kernel : 145 cycles , 1208 ns : - SEMAPHORE give.immediate.user : 715 cycles , 5959 ns : - SEMAPHORE take.immediate.user : 660 cycles , 5500 ns : - SEMAPHORE take.blocking.(K -> K) : 1150 cycles , 9584 ns : - SEMAPHORE give.wake+ctx.(K -> K) : 1279 cycles , 10666 ns : - SEMAPHORE take.blocking.(K -> U) : 1343 cycles , 11192 ns : - SEMAPHORE give.wake+ctx.(U -> K) : 1637 cycles , 13645 ns : - SEMAPHORE take.blocking.(U -> K) : 1522 cycles , 12688 ns : - SEMAPHORE give.wake+ctx.(K -> U) : 1472 cycles , 12270 ns : - SEMAPHORE take.blocking.(U -> U) : 1715 cycles , 14296 ns : - SEMAPHORE give.wake+ctx.(U -> U) : 1830 cycles , 15250 ns : - MUTEX lock.immediate.recursive.kernel : 150 cycles , 1250 ns : - MUTEX unlock.immediate.recursive.kernel : 57 cycles , 475 ns : - MUTEX lock.immediate.recursive.user : 670 cycles , 5583 ns : - MUTEX unlock.immediate.recursive.user : 595 cycles , 4959 ns : - HEAP malloc.immediate : 629 cycles , 5241 ns : - HEAP free.immediate : 414 cycles , 3450 ns : + *** Booting Zephyr OS build zephyr-v3.5.0-4268-g6af7a1230a08 *** + thread.yield.preemptive.ctx.k_to_k - Context switch via k_yield : 970 cycles , 8083 ns : + thread.yield.preemptive.ctx.u_to_u - Context switch via k_yield : 1260 cycles , 10506 ns : + thread.yield.preemptive.ctx.k_to_u - Context switch via k_yield : 1155 cycles , 9632 ns : + thread.yield.preemptive.ctx.u_to_k - Context switch via k_yield : 1075 cycles , 8959 ns : + thread.yield.cooperative.ctx.k_to_k - Context switch via k_yield : 970 cycles , 8083 ns : + thread.yield.cooperative.ctx.u_to_u - Context switch via k_yield : 1260 cycles , 10506 ns : + thread.yield.cooperative.ctx.k_to_u - Context switch via k_yield : 1155 cycles , 9631 ns : + thread.yield.cooperative.ctx.u_to_k - Context switch via k_yield : 1075 cycles , 8959 ns : + isr.resume.interrupted.thread.kernel - Return from ISR to interrupted thread : 415 cycles , 3458 ns : + isr.resume.different.thread.kernel - Return from ISR to another thread : 985 cycles , 8208 ns : + isr.resume.different.thread.user - Return from ISR to another thread : 1180 cycles , 9833 ns : + thread.create.kernel.from.kernel - Create thread : 989 cycles , 8249 ns : + thread.start.kernel.from.kernel - Start thread : 1059 cycles , 8833 ns : + thread.suspend.kernel.from.kernel - Suspend thread : 1030 cycles , 8583 ns : + thread.resume.kernel.from.kernel - Resume thread : 994 cycles , 8291 ns : + thread.abort.kernel.from.kernel - Abort thread : 2370 cycles , 19751 ns : + thread.create.user.from.kernel - Create thread : 860 cycles , 7167 ns : + thread.start.user.from.kernel - Start thread : 8965 cycles , 74713 ns : + thread.suspend.user.from.kernel - Suspend thread : 1400 cycles , 11666 ns : + thread.resume.user.from.kernel - Resume thread : 1174 cycles , 9791 ns : + thread.abort.user.from.kernel - Abort thread : 2240 cycles , 18666 ns : + thread.create.user.from.user - Create thread : 2105 cycles , 17542 ns : + thread.start.user.from.user - Start thread : 9345 cycles , 77878 ns : + thread.suspend.user.from.user - Suspend thread : 1590 cycles , 13250 ns : + thread.resume.user.from.user - Resume thread : 1534 cycles , 12791 ns : + thread.abort.user.from.user - Abort thread : 2850 cycles , 23750 ns : + thread.start.kernel.from.user - Start thread : 1440 cycles , 12000 ns : + thread.suspend.kernel.from.user - Suspend thread : 1219 cycles , 10166 ns : + thread.resume.kernel.from.user - Resume thread : 1355 cycles , 11292 ns : + thread.abort.kernel.from.user - Abort thread : 2980 cycles , 24834 ns : + fifo.put.immediate.kernel - Add data to FIFO (no ctx switch) : 315 cycles , 2625 ns : + fifo.get.immediate.kernel - Get data from FIFO (no ctx switch) : 209 cycles , 1749 ns : + fifo.put.alloc.immediate.kernel - Allocate to add data to FIFO (no ctx switch) : 1040 cycles , 8667 ns : + fifo.get.free.immediate.kernel - Free when getting data from FIFO (no ctx switch) : 670 cycles , 5583 ns : + fifo.put.alloc.immediate.user - Allocate to add data to FIFO (no ctx switch) : 1765 cycles , 14709 ns : + fifo.get.free.immediate.user - Free when getting data from FIFO (no ctx switch) : 1410 cycles , 11750 ns : + fifo.get.blocking.k_to_k - Get data from FIFO (w/ ctx switch) : 1220 cycles , 10168 ns : + fifo.put.wake+ctx.k_to_k - Add data to FIFO (w/ ctx switch) : 1285 cycles , 10708 ns : + fifo.get.free.blocking.k_to_k - Free when getting data from FIFO (w/ ctx siwtch) : 1235 cycles , 10291 ns : + fifo.put.alloc.wake+ctx.k_to_k - Allocate to add data to FIFO (w/ ctx switch) : 1340 cycles , 11167 ns : + fifo.get.free.blocking.u_to_k - Free when getting data from FIFO (w/ ctx siwtch) : 1715 cycles , 14292 ns : + fifo.put.alloc.wake+ctx.k_to_u - Allocate to add data to FIFO (w/ ctx switch) : 1665 cycles , 13876 ns : + fifo.get.free.blocking.k_to_u - Free when getting data from FIFO (w/ ctx siwtch) : 1565 cycles , 13042 ns : + fifo.put.alloc.wake+ctx.u_to_k - Allocate to add data to FIFO (w/ ctx switch) : 1815 cycles , 15126 ns : + fifo.get.free.blocking.u_to_u - Free when getting data from FIFO (w/ ctx siwtch) : 2045 cycles , 17042 ns : + fifo.put.alloc.wake+ctx.u_to_u - Allocate to add data to FIFO (w/ ctx switch) : 2140 cycles , 17834 ns : + lifo.put.immediate.kernel - Add data to LIFO (no ctx switch) : 309 cycles , 2583 ns : + lifo.get.immediate.kernel - Get data from LIFO (no ctx switch) : 219 cycles , 1833 ns : + lifo.put.alloc.immediate.kernel - Allocate to add data to LIFO (no ctx switch) : 1030 cycles , 8583 ns : + lifo.get.free.immediate.kernel - Free when getting data from LIFO (no ctx switch) : 685 cycles , 5708 ns : + lifo.put.alloc.immediate.user - Allocate to add data to LIFO (no ctx switch) : 1755 cycles , 14625 ns : + lifo.get.free.immediate.user - Free when getting data from LIFO (no ctx switch) : 1405 cycles , 11709 ns : + lifo.get.blocking.k_to_k - Get data from LIFO (w/ ctx switch) : 1229 cycles , 10249 ns : + lifo.put.wake+ctx.k_to_k - Add data to LIFO (w/ ctx switch) : 1290 cycles , 10751 ns : + lifo.get.free.blocking.k_to_k - Free when getting data from LIFO (w/ ctx switch) : 1235 cycles , 10292 ns : + lifo.put.alloc.wake+ctx.k_to_k - Allocate to add data to LIFO (w/ ctx siwtch) : 1310 cycles , 10917 ns : + lifo.get.free.blocking.u_to_k - Free when getting data from LIFO (w/ ctx switch) : 1715 cycles , 14293 ns : + lifo.put.alloc.wake+ctx.k_to_u - Allocate to add data to LIFO (w/ ctx siwtch) : 1630 cycles , 13583 ns : + lifo.get.free.blocking.k_to_u - Free when getting data from LIFO (w/ ctx switch) : 1554 cycles , 12958 ns : + lifo.put.alloc.wake+ctx.u_to_k - Allocate to add data to LIFO (w/ ctx siwtch) : 1805 cycles , 15043 ns : + lifo.get.free.blocking.u_to_u - Free when getting data from LIFO (w/ ctx switch) : 2035 cycles , 16959 ns : + lifo.put.alloc.wake+ctx.u_to_u - Allocate to add data to LIFO (w/ ctx siwtch) : 2125 cycles , 17709 ns : + events.post.immediate.kernel - Post events (nothing wakes) : 295 cycles , 2458 ns : + events.set.immediate.kernel - Set events (nothing wakes) : 300 cycles , 2500 ns : + events.wait.immediate.kernel - Wait for any events (no ctx switch) : 220 cycles , 1833 ns : + events.wait_all.immediate.kernel - Wait for all events (no ctx switch) : 215 cycles , 1791 ns : + events.post.immediate.user - Post events (nothing wakes) : 795 cycles , 6625 ns : + events.set.immediate.user - Set events (nothing wakes) : 790 cycles , 6584 ns : + events.wait.immediate.user - Wait for any events (no ctx switch) : 740 cycles , 6167 ns : + events.wait_all.immediate.user - Wait for all events (no ctx switch) : 740 cycles , 6166 ns : + events.wait.blocking.k_to_k - Wait for any events (w/ ctx switch) : 1190 cycles , 9918 ns : + events.set.wake+ctx.k_to_k - Set events (w/ ctx switch) : 1464 cycles , 12208 ns : + events.wait_all.blocking.k_to_k - Wait for all events (w/ ctx switch) : 1235 cycles , 10292 ns : + events.post.wake+ctx.k_to_k - Post events (w/ ctx switch) : 1500 cycles , 12500 ns : + events.wait.blocking.u_to_k - Wait for any events (w/ ctx switch) : 1580 cycles , 13167 ns : + events.set.wake+ctx.k_to_u - Set events (w/ ctx switch) : 1630 cycles , 13583 ns : + events.wait_all.blocking.u_to_k - Wait for all events (w/ ctx switch) : 1765 cycles , 14708 ns : + events.post.wake+ctx.k_to_u - Post events (w/ ctx switch) : 1795 cycles , 14960 ns : + events.wait.blocking.k_to_u - Wait for any events (w/ ctx switch) : 1375 cycles , 11459 ns : + events.set.wake+ctx.u_to_k - Set events (w/ ctx switch) : 1825 cycles , 15209 ns : + events.wait_all.blocking.k_to_u - Wait for all events (w/ ctx switch) : 1555 cycles , 12958 ns : + events.post.wake+ctx.u_to_k - Post events (w/ ctx switch) : 1995 cycles , 16625 ns : + events.wait.blocking.u_to_u - Wait for any events (w/ ctx switch) : 1765 cycles , 14708 ns : + events.set.wake+ctx.u_to_u - Set events (w/ ctx switch) : 1989 cycles , 16583 ns : + events.wait_all.blocking.u_to_u - Wait for all events (w/ ctx switch) : 2085 cycles , 17376 ns : + events.post.wake+ctx.u_to_u - Post events (w/ ctx switch) : 2290 cycles , 19084 ns : + semaphore.give.immediate.kernel - Give a semaphore (no waiters) : 220 cycles , 1833 ns : + semaphore.take.immediate.kernel - Take a semaphore (no blocking) : 130 cycles , 1083 ns : + semaphore.give.immediate.user - Give a semaphore (no waiters) : 710 cycles , 5917 ns : + semaphore.take.immediate.user - Take a semaphore (no blocking) : 655 cycles , 5458 ns : + semaphore.take.blocking.k_to_k - Take a semaphore (context switch) : 1135 cycles , 9458 ns : + semaphore.give.wake+ctx.k_to_k - Give a semaphore (context switch) : 1244 cycles , 10374 ns : + semaphore.take.blocking.k_to_u - Take a semaphore (context switch) : 1325 cycles , 11048 ns : + semaphore.give.wake+ctx.u_to_k - Give a semaphore (context switch) : 1610 cycles , 13416 ns : + semaphore.take.blocking.u_to_k - Take a semaphore (context switch) : 1499 cycles , 12499 ns : + semaphore.give.wake+ctx.k_to_u - Give a semaphore (context switch) : 1434 cycles , 11957 ns : + semaphore.take.blocking.u_to_u - Take a semaphore (context switch) : 1690 cycles , 14090 ns : + semaphore.give.wake+ctx.u_to_u - Give a semaphore (context switch) : 1800 cycles , 15000 ns : + mutex.lock.immediate.recursive.kernel - Lock a mutex : 155 cycles , 1291 ns : + mutex.unlock.immediate.recursive.kernel - Unlock a mutex : 57 cycles , 475 ns : + mutex.lock.immediate.recursive.user - Lock a mutex : 665 cycles , 5541 ns : + mutex.unlock.immediate.recursive.user - Unlock a mutex : 585 cycles , 4875 ns : + heap.malloc.immediate - Average time for heap malloc : 640 cycles , 5341 ns : + heap.free.immediate - Average time for heap free : 436 cycles , 3633 ns : =================================================================== PROJECT EXECUTION SUCCESSFUL diff --git a/tests/benchmarks/latency_measure/src/events.c b/tests/benchmarks/latency_measure/src/events.c index dac6f8ea1fa..0e80b5978c0 100644 --- a/tests/benchmarks/latency_measure/src/events.c +++ b/tests/benchmarks/latency_measure/src/events.c @@ -33,7 +33,8 @@ static void event_ops_entry(void *p1, void *p2, void *p3) timing_t finish; uint32_t i; uint64_t cycles; - char description[80]; + char tag[50]; + char description[120]; k_event_clear(&event_set, ALL_EVENTS); @@ -43,9 +44,10 @@ static void event_ops_entry(void *p1, void *p2, void *p3) } finish = timing_timestamp_get(); - snprintf(description, sizeof(description), - "EVENTS post.immediate.%s", + snprintf(tag, sizeof(tag), "events.post.immediate.%s", (options & K_USER) ? "user" : "kernel"); + snprintf(description, sizeof(description), + "%-40s - Post events (nothing wakes)", tag); cycles = timing_cycles_get(&start, &finish); PRINT_STATS_AVG(description, (uint32_t)cycles, num_iterations, false, ""); @@ -56,9 +58,10 @@ static void event_ops_entry(void *p1, void *p2, void *p3) } finish = timing_timestamp_get(); - snprintf(description, sizeof(description), - "EVENTS set.immediate.%s", + snprintf(tag, sizeof(tag), "events.set.immediate.%s", (options & K_USER) ? "user" : "kernel"); + snprintf(description, sizeof(description), + "%-40s - Set events (nothing wakes)", tag); cycles = timing_cycles_get(&start, &finish); PRINT_STATS_AVG(description, (uint32_t)cycles, num_iterations, false, ""); @@ -69,9 +72,10 @@ static void event_ops_entry(void *p1, void *p2, void *p3) } finish = timing_timestamp_get(); - snprintf(description, sizeof(description), - "EVENTS wait.immediate.%s", + snprintf(tag, sizeof(tag), "events.wait.immediate.%s", (options & K_USER) ? "user" : "kernel"); + snprintf(description, sizeof(description), + "%-40s - Wait for any events (no ctx switch)", tag); cycles = timing_cycles_get(&start, &finish); PRINT_STATS_AVG(description, (uint32_t)cycles, num_iterations, false, ""); @@ -82,9 +86,10 @@ static void event_ops_entry(void *p1, void *p2, void *p3) } finish = timing_timestamp_get(); - snprintf(description, sizeof(description), - "EVENTS wait_all.immediate.%s", + snprintf(tag, sizeof(tag), "events.wait_all.immediate.%s", (options & K_USER) ? "user" : "kernel"); + snprintf(description, sizeof(description), + "%-40s - Wait for all events (no ctx switch)", tag); cycles = timing_cycles_get(&start, &finish); PRINT_STATS_AVG(description, (uint32_t)cycles, num_iterations, false, ""); @@ -97,7 +102,8 @@ static void start_thread_entry(void *p1, void *p2, void *p3) uint32_t alt_options = (uint32_t)(uintptr_t)p3; uint32_t i; uint64_t cycles; - char description[80]; + char tag[50]; + char description[120]; k_thread_start(&alt_thread); @@ -109,20 +115,24 @@ static void start_thread_entry(void *p1, void *p2, void *p3) k_event_set(&event_set, BENCH_EVENT_SET); } + snprintf(tag, sizeof(tag), + "events.wait.blocking.%c_to_%c", + (alt_options & K_USER) ? 'u' : 'k', + (options & K_USER) ? 'u' : 'k'); snprintf(description, sizeof(description), - "EVENTS wait.blocking.(%c -> %c)", - (alt_options & K_USER) ? 'U' : 'K', - (options & K_USER) ? 'U' : 'K'); + "%-40s - Wait for any events (w/ ctx switch)", tag); cycles = timestamp.cycles - timestamp_overhead_adjustment(options, alt_options); PRINT_STATS_AVG(description, (uint32_t)cycles, num_iterations, false, ""); k_sem_give(&pause_sem); + snprintf(tag, sizeof(tag), + "events.set.wake+ctx.%c_to_%c", + (options & K_USER) ? 'u' : 'k', + (alt_options & K_USER) ? 'u' : 'k'); snprintf(description, sizeof(description), - "EVENTS set.wake+ctx.(%c -> %c)", - (options & K_USER) ? 'U' : 'K', - (alt_options & K_USER) ? 'U' : 'K'); + "%-40s - Set events (w/ ctx switch)", tag); cycles = timestamp.cycles - timestamp_overhead_adjustment(options, alt_options); PRINT_STATS_AVG(description, (uint32_t)cycles, @@ -137,19 +147,23 @@ static void start_thread_entry(void *p1, void *p2, void *p3) k_event_post(&event_set, BENCH_EVENT_SET); } + snprintf(tag, sizeof(tag), + "events.wait_all.blocking.%c_to_%c", + (alt_options & K_USER) ? 'u' : 'k', + (options & K_USER) ? 'u' : 'k'); snprintf(description, sizeof(description), - "EVENTS wait_all.blocking.(%c -> %c)", - (alt_options & K_USER) ? 'U' : 'K', - (options & K_USER) ? 'U' : 'K'); + "%-40s - Wait for all events (w/ ctx switch)", tag); cycles = timestamp.cycles; PRINT_STATS_AVG(description, (uint32_t)cycles, num_iterations, false, ""); k_sem_give(&pause_sem); + snprintf(tag, sizeof(tag), + "events.post.wake+ctx.%c_to_%c", + (options & K_USER) ? 'u' : 'k', + (alt_options & K_USER) ? 'u' : 'k'); snprintf(description, sizeof(description), - "EVENTS post.wake+ctx.(%c -> %c)", - (options & K_USER) ? 'U' : 'K', - (alt_options & K_USER) ? 'U' : 'K'); + "%-40s - Post events (w/ ctx switch)", tag); cycles = timestamp.cycles; PRINT_STATS_AVG(description, (uint32_t)cycles, num_iterations, false, ""); diff --git a/tests/benchmarks/latency_measure/src/fifo.c b/tests/benchmarks/latency_measure/src/fifo.c index 4bd1750e89a..6dd8ffc1824 100644 --- a/tests/benchmarks/latency_measure/src/fifo.c +++ b/tests/benchmarks/latency_measure/src/fifo.c @@ -93,7 +93,8 @@ int fifo_ops(uint32_t num_iterations, uint32_t options) { int priority; uint64_t cycles; - char description[80]; + char tag[50]; + char description[120]; priority = k_thread_priority_get(k_current_get()); @@ -111,9 +112,11 @@ int fifo_ops(uint32_t num_iterations, uint32_t options) k_thread_start(&start_thread); if ((options & K_USER) == 0) { - snprintf(description, sizeof(description), - "FIFO put.immediate.%s", + snprintf(tag, sizeof(tag), + "fifo.put.immediate.%s", options & K_USER ? "user" : "kernel"); + snprintf(description, sizeof(description), + "%-40s - Add data to FIFO (no ctx switch)", tag); cycles = timestamp.cycles; cycles -= timestamp_overhead_adjustment(options, options); @@ -121,9 +124,11 @@ int fifo_ops(uint32_t num_iterations, uint32_t options) num_iterations, false, ""); k_sem_give(&pause_sem); - snprintf(description, sizeof(description), - "FIFO get.immediate.%s", + snprintf(tag, sizeof(tag), + "fifo.get.immediate.%s", options & K_USER ? "user" : "kernel"); + snprintf(description, sizeof(description), + "%-40s - Get data from FIFO (no ctx switch)", tag); cycles = timestamp.cycles; cycles -= timestamp_overhead_adjustment(options, options); PRINT_STATS_AVG(description, (uint32_t)cycles, @@ -131,18 +136,22 @@ int fifo_ops(uint32_t num_iterations, uint32_t options) k_sem_give(&pause_sem); } - snprintf(description, sizeof(description), - "FIFO put.alloc.immediate.%s", + snprintf(tag, sizeof(tag), + "fifo.put.alloc.immediate.%s", options & K_USER ? "user" : "kernel"); + snprintf(description, sizeof(description), + "%-40s - Allocate to add data to FIFO (no ctx switch)", tag); cycles = timestamp.cycles; PRINT_STATS_AVG(description, (uint32_t)cycles, num_iterations, false, ""); k_sem_give(&pause_sem); - snprintf(description, sizeof(description), - "FIFO get.free.immediate.%s", + snprintf(tag, sizeof(tag), + "fifo.get.free.immediate.%s", options & K_USER ? "user" : "kernel"); + snprintf(description, sizeof(description), + "%-40s - Free when getting data from FIFO (no ctx switch)", tag); cycles = timestamp.cycles; PRINT_STATS_AVG(description, (uint32_t)cycles, num_iterations, false, ""); @@ -258,7 +267,8 @@ int fifo_blocking_ops(uint32_t num_iterations, uint32_t start_options, { int priority; uint64_t cycles; - char description[80]; + char tag[50]; + char description[120]; priority = k_thread_priority_get(k_current_get()); @@ -284,40 +294,48 @@ int fifo_blocking_ops(uint32_t num_iterations, uint32_t start_options, k_thread_start(&start_thread); if (((start_options | alt_options) & K_USER) == 0) { + snprintf(tag, sizeof(tag), + "fifo.get.blocking.%s_to_%s", + alt_options & K_USER ? "u" : "k", + start_options & K_USER ? "u" : "k"); snprintf(description, sizeof(description), - "FIFO get.blocking.(%s -> %s)", - alt_options & K_USER ? "U" : "K", - start_options & K_USER ? "U" : "K"); + "%-40s - Get data from FIFO (w/ ctx switch)", tag); cycles = timestamp.cycles; PRINT_STATS_AVG(description, (uint32_t)cycles, num_iterations, false, ""); k_sem_give(&pause_sem); + snprintf(tag, sizeof(tag), + "fifo.put.wake+ctx.%s_to_%s", + start_options & K_USER ? "u" : "k", + alt_options & K_USER ? "u" : "k"); snprintf(description, sizeof(description), - "FIFO put.wake+ctx.(%s -> %s)", - start_options & K_USER ? "U" : "K", - alt_options & K_USER ? "U" : "K"); + "%-40s - Add data to FIFO (w/ ctx switch)", tag); cycles = timestamp.cycles; PRINT_STATS_AVG(description, (uint32_t)cycles, num_iterations, false, ""); k_sem_give(&pause_sem); } + snprintf(tag, sizeof(tag), + "fifo.get.free.blocking.%s_to_%s", + alt_options & K_USER ? "u" : "k", + start_options & K_USER ? "u" : "k"); snprintf(description, sizeof(description), - "FIFO get.free.blocking.(%s -> %s)", - alt_options & K_USER ? "U" : "K", - start_options & K_USER ? "U" : "K"); + "%-40s - Free when getting data from FIFO (w/ ctx siwtch)", tag); cycles = timestamp.cycles; PRINT_STATS_AVG(description, (uint32_t)cycles, num_iterations, false, ""); k_sem_give(&pause_sem); + snprintf(tag, sizeof(tag), + "fifo.put.alloc.wake+ctx.%s_to_%s", + start_options & K_USER ? "u" : "k", + alt_options & K_USER ? "u" : "k"); snprintf(description, sizeof(description), - "FIFO put.alloc.wake+ctx.(%s -> %s)", - start_options & K_USER ? "U" : "K", - alt_options & K_USER ? "U" : "K"); + "%-40s - Allocate to add data to FIFO (w/ ctx switch)", tag); cycles = timestamp.cycles; PRINT_STATS_AVG(description, (uint32_t)cycles, num_iterations, false, ""); diff --git a/tests/benchmarks/latency_measure/src/heap_malloc_free.c b/tests/benchmarks/latency_measure/src/heap_malloc_free.c index 4ff93cdc806..fddae035304 100644 --- a/tests/benchmarks/latency_measure/src/heap_malloc_free.c +++ b/tests/benchmarks/latency_measure/src/heap_malloc_free.c @@ -25,6 +25,7 @@ void heap_malloc_free(void) bool failed = false; char error_string[80]; + char description[120]; const char *notes = ""; timing_start(); @@ -63,10 +64,15 @@ void heap_malloc_free(void) notes = "Memory heap too small--increase it."; } - PRINT_STATS_AVG("HEAP malloc.immediate", sum_malloc, count, - failed, notes); - PRINT_STATS_AVG("HEAP free.immediate", sum_free, count, - failed, notes); + snprintf(description, sizeof(description), + "%-40s - Average time for heap malloc", + "heap.malloc.immediate"); + PRINT_STATS_AVG(description, sum_malloc, count, failed, notes); + + snprintf(description, sizeof(description), + "%-40s - Average time for heap free", + "heap.free.immediate"); + PRINT_STATS_AVG(description, sum_free, count, failed, notes); timing_stop(); } diff --git a/tests/benchmarks/latency_measure/src/int_to_thread.c b/tests/benchmarks/latency_measure/src/int_to_thread.c index 62fa8cdca6c..cb7ca72d32f 100644 --- a/tests/benchmarks/latency_measure/src/int_to_thread.c +++ b/tests/benchmarks/latency_measure/src/int_to_thread.c @@ -166,6 +166,7 @@ static void int_to_another_thread(uint32_t num_iterations, uint64_t *sum, int int_to_thread(uint32_t num_iterations) { uint64_t sum; + char description[120]; timing_start(); TICK_SYNCH(); @@ -174,8 +175,10 @@ int int_to_thread(uint32_t num_iterations) sum -= timestamp_overhead_adjustment(0, 0); - PRINT_STATS_AVG("ISR resume.interrupted.thread.kernel", - (uint32_t)sum, num_iterations, false, ""); + snprintf(description, sizeof(description), + "%-40s - Return from ISR to interrupted thread", + "isr.resume.interrupted.thread.kernel"); + PRINT_STATS_AVG(description, (uint32_t)sum, num_iterations, false, ""); /* ************** */ @@ -183,8 +186,10 @@ int int_to_thread(uint32_t num_iterations) sum -= timestamp_overhead_adjustment(0, 0); - PRINT_STATS_AVG("ISR resume.different.thread.kernel", - (uint32_t)sum, num_iterations, false, ""); + snprintf(description, sizeof(description), + "%-40s - Return from ISR to another thread", + "isr.resume.different.thread.kernel"); + PRINT_STATS_AVG(description, (uint32_t)sum, num_iterations, false, ""); /* ************** */ @@ -193,8 +198,10 @@ int int_to_thread(uint32_t num_iterations) sum -= timestamp_overhead_adjustment(0, K_USER); - PRINT_STATS_AVG("ISR resume.different.thread.user", - (uint32_t)sum, num_iterations, false, ""); + snprintf(description, sizeof(description), + "%-40s - Return from ISR to another thread", + "isr.resume.different.thread.user"); + PRINT_STATS_AVG(description, (uint32_t)sum, num_iterations, false, ""); #endif timing_stop(); diff --git a/tests/benchmarks/latency_measure/src/lifo.c b/tests/benchmarks/latency_measure/src/lifo.c index 052f7b212ff..2de1ba81681 100644 --- a/tests/benchmarks/latency_measure/src/lifo.c +++ b/tests/benchmarks/latency_measure/src/lifo.c @@ -93,7 +93,8 @@ int lifo_ops(uint32_t num_iterations, uint32_t options) { int priority; uint64_t cycles; - char description[80]; + char tag[50]; + char description[120]; priority = k_thread_priority_get(k_current_get()); @@ -111,9 +112,11 @@ int lifo_ops(uint32_t num_iterations, uint32_t options) k_thread_start(&start_thread); if ((options & K_USER) == 0) { - snprintf(description, sizeof(description), - "LIFO put.immediate.%s", + snprintf(tag, sizeof(tag), + "lifo.put.immediate.%s", options & K_USER ? "user" : "kernel"); + snprintf(description, sizeof(description), + "%-40s - Add data to LIFO (no ctx switch)", tag); cycles = timestamp.cycles; cycles -= timestamp_overhead_adjustment(options, options); @@ -121,9 +124,11 @@ int lifo_ops(uint32_t num_iterations, uint32_t options) num_iterations, false, ""); k_sem_give(&pause_sem); - snprintf(description, sizeof(description), - "LIFO get.immediate.%s", + snprintf(tag, sizeof(tag), + "lifo.get.immediate.%s", options & K_USER ? "user" : "kernel"); + snprintf(description, sizeof(description), + "%-40s - Get data from LIFO (no ctx switch)", tag); cycles = timestamp.cycles; cycles -= timestamp_overhead_adjustment(options, options); PRINT_STATS_AVG(description, (uint32_t)cycles, @@ -131,18 +136,22 @@ int lifo_ops(uint32_t num_iterations, uint32_t options) k_sem_give(&pause_sem); } - snprintf(description, sizeof(description), - "LIFO put.alloc.immediate.%s", + snprintf(tag, sizeof(tag), + "lifo.put.alloc.immediate.%s", options & K_USER ? "user" : "kernel"); + snprintf(description, sizeof(description), + "%-40s - Allocate to add data to LIFO (no ctx switch)", tag); cycles = timestamp.cycles; PRINT_STATS_AVG(description, (uint32_t)cycles, num_iterations, false, ""); k_sem_give(&pause_sem); - snprintf(description, sizeof(description), - "LIFO get.free.immediate.%s", + snprintf(tag, sizeof(tag), + "lifo.get.free.immediate.%s", options & K_USER ? "user" : "kernel"); + snprintf(description, sizeof(description), + "%-40s - Free when getting data from LIFO (no ctx switch)", tag); cycles = timestamp.cycles; PRINT_STATS_AVG(description, (uint32_t)cycles, num_iterations, false, ""); @@ -258,7 +267,8 @@ int lifo_blocking_ops(uint32_t num_iterations, uint32_t start_options, { int priority; uint64_t cycles; - char description[80]; + char tag[50]; + char description[120]; priority = k_thread_priority_get(k_current_get()); @@ -284,40 +294,48 @@ int lifo_blocking_ops(uint32_t num_iterations, uint32_t start_options, k_thread_start(&start_thread); if (((start_options | alt_options) & K_USER) == 0) { + snprintf(tag, sizeof(tag), + "lifo.get.blocking.%s_to_%s", + alt_options & K_USER ? "u" : "k", + start_options & K_USER ? "u" : "k"); snprintf(description, sizeof(description), - "LIFO get.blocking.(%s -> %s)", - alt_options & K_USER ? "U" : "K", - start_options & K_USER ? "U" : "K"); + "%-40s - Get data from LIFO (w/ ctx switch)", tag); cycles = timestamp.cycles; PRINT_STATS_AVG(description, (uint32_t)cycles, num_iterations, false, ""); k_sem_give(&pause_sem); + snprintf(tag, sizeof(tag), + "lifo.put.wake+ctx.%s_to_%s", + start_options & K_USER ? "u" : "k", + alt_options & K_USER ? "u" : "k"); snprintf(description, sizeof(description), - "LIFO put.wake+ctx.(%s -> %s)", - start_options & K_USER ? "U" : "K", - alt_options & K_USER ? "U" : "K"); + "%-40s - Add data to LIFO (w/ ctx switch)", tag); cycles = timestamp.cycles; PRINT_STATS_AVG(description, (uint32_t)cycles, num_iterations, false, ""); k_sem_give(&pause_sem); } + snprintf(tag, sizeof(tag), + "lifo.get.free.blocking.%s_to_%s", + alt_options & K_USER ? "u" : "k", + start_options & K_USER ? "u" : "k"); snprintf(description, sizeof(description), - "LIFO get.free.blocking.(%s -> %s)", - alt_options & K_USER ? "U" : "K", - start_options & K_USER ? "U" : "K"); + "%-40s - Free when getting data from LIFO (w/ ctx switch)", tag); cycles = timestamp.cycles; PRINT_STATS_AVG(description, (uint32_t)cycles, num_iterations, false, ""); k_sem_give(&pause_sem); + snprintf(tag, sizeof(tag), + "lifo.put.alloc.wake+ctx.%s_to_%s", + start_options & K_USER ? "u" : "k", + alt_options & K_USER ? "u" : "k"); snprintf(description, sizeof(description), - "LIFO put.alloc.wake+ctx.(%s -> %s)", - start_options & K_USER ? "U" : "K", - alt_options & K_USER ? "U" : "K"); + "%-40s - Allocate to add data to LIFO (w/ ctx siwtch)", tag); cycles = timestamp.cycles; PRINT_STATS_AVG(description, (uint32_t)cycles, num_iterations, false, ""); diff --git a/tests/benchmarks/latency_measure/src/mutex_lock_unlock.c b/tests/benchmarks/latency_measure/src/mutex_lock_unlock.c index 6011f697606..f022b0db936 100644 --- a/tests/benchmarks/latency_measure/src/mutex_lock_unlock.c +++ b/tests/benchmarks/latency_measure/src/mutex_lock_unlock.c @@ -73,7 +73,8 @@ static void start_lock_unlock(void *p1, void *p2, void *p3) */ int mutex_lock_unlock(uint32_t num_iterations, uint32_t options) { - char description[80]; + char tag[50]; + char description[120]; int priority; uint64_t cycles; @@ -93,17 +94,21 @@ int mutex_lock_unlock(uint32_t num_iterations, uint32_t options) cycles = timestamp.cycles; k_sem_give(&pause_sem); - snprintf(description, sizeof(description), - "MUTEX lock.immediate.recursive.%s", + snprintf(tag, sizeof(tag), + "mutex.lock.immediate.recursive.%s", (options & K_USER) == K_USER ? "user" : "kernel"); + snprintf(description, sizeof(description), + "%-40s - Lock a mutex", tag); PRINT_STATS_AVG(description, (uint32_t)cycles, num_iterations, false, ""); cycles = timestamp.cycles; - snprintf(description, sizeof(description), - "MUTEX unlock.immediate.recursive.%s", + snprintf(tag, sizeof(tag), + "mutex.unlock.immediate.recursive.%s", (options & K_USER) == K_USER ? "user" : "kernel"); + snprintf(description, sizeof(description), + "%-40s - Unlock a mutex", tag); PRINT_STATS_AVG(description, (uint32_t)cycles, num_iterations, false, ""); diff --git a/tests/benchmarks/latency_measure/src/sema_test_signal_release.c b/tests/benchmarks/latency_measure/src/sema_test_signal_release.c index bd3078cf42c..37e0acccd58 100644 --- a/tests/benchmarks/latency_measure/src/sema_test_signal_release.c +++ b/tests/benchmarks/latency_measure/src/sema_test_signal_release.c @@ -106,7 +106,8 @@ void sema_context_switch(uint32_t num_iterations, uint32_t start_options, uint32_t alt_options) { uint64_t cycles; - char description[80]; + char tag[50]; + char description[120]; int priority; timing_start(); @@ -138,10 +139,12 @@ void sema_context_switch(uint32_t num_iterations, cycles = timestamp.cycles; cycles -= timestamp_overhead_adjustment(start_options, alt_options); + snprintf(tag, sizeof(tag), + "semaphore.take.blocking.%c_to_%c", + ((start_options & K_USER) == K_USER) ? 'u' : 'k', + ((alt_options & K_USER) == K_USER) ? 'u' : 'k'); snprintf(description, sizeof(description), - "SEMAPHORE take.blocking.(%c -> %c)", - ((start_options & K_USER) == K_USER) ? 'U' : 'K', - ((alt_options & K_USER) == K_USER) ? 'U' : 'K'); + "%-40s - Take a semaphore (context switch)", tag); PRINT_STATS_AVG(description, (uint32_t)cycles, num_iterations, false, ""); @@ -154,10 +157,12 @@ void sema_context_switch(uint32_t num_iterations, cycles = timestamp.cycles; cycles -= timestamp_overhead_adjustment(start_options, alt_options); + snprintf(tag, sizeof(tag), + "semaphore.give.wake+ctx.%c_to_%c", + ((alt_options & K_USER) == K_USER) ? 'u' : 'k', + ((start_options & K_USER) == K_USER) ? 'u' : 'k'); snprintf(description, sizeof(description), - "SEMAPHORE give.wake+ctx.(%c -> %c)", - ((alt_options & K_USER) == K_USER) ? 'U' : 'K', - ((start_options & K_USER) == K_USER) ? 'U' : 'K'); + "%-40s - Give a semaphore (context switch)", tag); PRINT_STATS_AVG(description, (uint32_t)cycles, num_iterations, false, ""); @@ -233,7 +238,8 @@ int sema_test_signal(uint32_t num_iterations, uint32_t options) { uint64_t cycles; int priority; - char description[80]; + char tag[50]; + char description[120]; timing_start(); @@ -254,9 +260,11 @@ int sema_test_signal(uint32_t num_iterations, uint32_t options) cycles = timestamp.cycles; - snprintf(description, sizeof(description), - "SEMAPHORE give.immediate.%s", + snprintf(tag, sizeof(tag), + "semaphore.give.immediate.%s", (options & K_USER) == K_USER ? "user" : "kernel"); + snprintf(description, sizeof(description), + "%-40s - Give a semaphore (no waiters)", tag); PRINT_STATS_AVG(description, (uint32_t)cycles, num_iterations, false, ""); @@ -273,9 +281,11 @@ int sema_test_signal(uint32_t num_iterations, uint32_t options) cycles = timestamp.cycles; - snprintf(description, sizeof(description), - "SEMAPHORE take.immediate.%s", + snprintf(tag, sizeof(tag), + "semaphore.take.immediate.%s", (options & K_USER) == K_USER ? "user" : "kernel"); + snprintf(description, sizeof(description), + "%-40s - Take a semaphore (no blocking)", tag); PRINT_STATS_AVG(description, (uint32_t)cycles, num_iterations, false, ""); diff --git a/tests/benchmarks/latency_measure/src/thread.c b/tests/benchmarks/latency_measure/src/thread.c index 99c7c9f534d..fe58067fcc8 100644 --- a/tests/benchmarks/latency_measure/src/thread.c +++ b/tests/benchmarks/latency_measure/src/thread.c @@ -174,7 +174,8 @@ int thread_ops(uint32_t num_iterations, uint32_t start_options, uint32_t alt_opt int priority; uint64_t cycles; uint32_t bit_options = START_ALT; - char description[80]; + char tag[50]; + char description[120]; priority = k_thread_priority_get(k_current_get()); @@ -247,10 +248,12 @@ int thread_ops(uint32_t num_iterations, uint32_t start_options, uint32_t alt_opt /* Only report stats if created */ - snprintf(description, sizeof(description), - "THREAD create.%s.from.%s", + snprintf(tag, sizeof(tag), + "thread.create.%s.from.%s", (alt_options & K_USER) != 0 ? "user" : "kernel", (start_options & K_USER) != 0 ? "user" : "kernel"); + snprintf(description, sizeof(description), + "%-40s - Create thread", tag); PRINT_STATS_AVG(description, (uint32_t)cycles, num_iterations, false, ""); @@ -260,10 +263,12 @@ int thread_ops(uint32_t num_iterations, uint32_t start_options, uint32_t alt_opt cycles -= timestamp_overhead_adjustment(start_options, alt_options); k_sem_give(&pause_sem); - snprintf(description, sizeof(description), - "THREAD start.%s.from.%s", + snprintf(tag, sizeof(tag), + "thread.start.%s.from.%s", (alt_options & K_USER) != 0 ? "user" : "kernel", (start_options & K_USER) != 0 ? "user" : "kernel"); + snprintf(description, sizeof(description), + "%-40s - Start thread", tag); PRINT_STATS_AVG(description, (uint32_t)cycles, num_iterations, false, ""); @@ -272,10 +277,12 @@ int thread_ops(uint32_t num_iterations, uint32_t start_options, uint32_t alt_opt cycles -= timestamp_overhead_adjustment(start_options, alt_options); k_sem_give(&pause_sem); - snprintf(description, sizeof(description), - "THREAD suspend.%s.from.%s", + snprintf(tag, sizeof(tag), + "thread.suspend.%s.from.%s", (alt_options & K_USER) != 0 ? "user" : "kernel", (start_options & K_USER) != 0 ? "user" : "kernel"); + snprintf(description, sizeof(description), + "%-40s - Suspend thread", tag); PRINT_STATS_AVG(description, (uint32_t)cycles, num_iterations, false, ""); @@ -284,10 +291,12 @@ int thread_ops(uint32_t num_iterations, uint32_t start_options, uint32_t alt_opt cycles -= timestamp_overhead_adjustment(start_options, alt_options); k_sem_give(&pause_sem); - snprintf(description, sizeof(description), - "THREAD resume.%s.from.%s", + snprintf(tag, sizeof(tag), + "thread.resume.%s.from.%s", (alt_options & K_USER) != 0 ? "user" : "kernel", (start_options & K_USER) != 0 ? "user" : "kernel"); + snprintf(description, sizeof(description), + "%-40s - Resume thread", tag); PRINT_STATS_AVG(description, (uint32_t)cycles, num_iterations, false, ""); @@ -296,10 +305,12 @@ int thread_ops(uint32_t num_iterations, uint32_t start_options, uint32_t alt_opt cycles -= timestamp_overhead_adjustment(start_options, alt_options); k_sem_give(&pause_sem); - snprintf(description, sizeof(description), - "THREAD abort.%s.from.%s", + snprintf(tag, sizeof(tag), + "thread.abort.%s.from.%s", (alt_options & K_USER) != 0 ? "user" : "kernel", (start_options & K_USER) != 0 ? "user" : "kernel"); + snprintf(description, sizeof(description), + "%-40s - Abort thread", tag); PRINT_STATS_AVG(description, (uint32_t)cycles, num_iterations, false, ""); diff --git a/tests/benchmarks/latency_measure/src/thread_switch_yield.c b/tests/benchmarks/latency_measure/src/thread_switch_yield.c index f0e626d53a7..cca2bd909e9 100644 --- a/tests/benchmarks/latency_measure/src/thread_switch_yield.c +++ b/tests/benchmarks/latency_measure/src/thread_switch_yield.c @@ -96,7 +96,8 @@ static void thread_switch_yield_common(const char *description, int priority) { uint64_t sum; - char summary[80]; + char tag[50]; + char summary[120]; /* Create the two threads */ @@ -130,11 +131,12 @@ static void thread_switch_yield_common(const char *description, sum -= timestamp_overhead_adjustment(start_options, alt_options); + snprintf(tag, sizeof(tag), + "%s.%c_to_%c", description, + (start_options & K_USER) == K_USER ? 'u' : 'k', + (alt_options & K_USER) == K_USER ? 'u' : 'k'); snprintf(summary, sizeof(summary), - "%s.(%c -> %c)", - description, - (start_options & K_USER) == K_USER ? 'U' : 'K', - (alt_options & K_USER) == K_USER ? 'U' : 'K'); + "%-40s - Context switch via k_yield", tag); PRINT_STATS_AVG(summary, (uint32_t)sum, num_iterations, 0, ""); } @@ -142,13 +144,13 @@ static void thread_switch_yield_common(const char *description, void thread_switch_yield(uint32_t num_iterations, bool is_cooperative) { int priority; - char description[60]; + char description[40]; priority = is_cooperative ? K_PRIO_COOP(6) : k_thread_priority_get(k_current_get()) - 1; snprintf(description, sizeof(description), - "THREAD yield.%s.ctx", + "thread.yield.%s.ctx", is_cooperative ? "cooperative" : "preemptive"); /* Kernel -> Kernel */ diff --git a/tests/benchmarks/latency_measure/src/utils.h b/tests/benchmarks/latency_measure/src/utils.h index 7f3f0bde4e1..b9cba6bee5d 100644 --- a/tests/benchmarks/latency_measure/src/utils.h +++ b/tests/benchmarks/latency_measure/src/utils.h @@ -50,11 +50,11 @@ extern int error_count; #define TICK_OCCURRENCE_ERROR "Error: Tick Occurred" #ifdef CSV_FORMAT_OUTPUT -#define FORMAT_STR "%-52s,%s,%s,%s\n" +#define FORMAT_STR "%-94s,%s,%s,%s\n" #define CYCLE_FORMAT "%8u" #define NSEC_FORMAT "%8u" #else -#define FORMAT_STR "%-52s:%s , %s : %s\n" +#define FORMAT_STR "%-94s:%s , %s : %s\n" #define CYCLE_FORMAT "%8u cycles" #define NSEC_FORMAT "%8u ns" #endif From 070b07efc1a21ccf06909d921806bc884018c541 Mon Sep 17 00:00:00 2001 From: Peter Mitsis Date: Thu, 18 Jan 2024 11:28:39 -0500 Subject: [PATCH 2663/3723] tests: latency_measure: Remove prj_user.conf Moves the enablement of userspace from the project configuration file to testcase.yaml. Signed-off-by: Peter Mitsis --- .../benchmarks/latency_measure/prj_user.conf | 33 ------------------- .../benchmarks/latency_measure/testcase.yaml | 7 ++-- 2 files changed, 4 insertions(+), 36 deletions(-) delete mode 100644 tests/benchmarks/latency_measure/prj_user.conf diff --git a/tests/benchmarks/latency_measure/prj_user.conf b/tests/benchmarks/latency_measure/prj_user.conf deleted file mode 100644 index 7119db2962d..00000000000 --- a/tests/benchmarks/latency_measure/prj_user.conf +++ /dev/null @@ -1,33 +0,0 @@ -CONFIG_TEST=y - -# eliminate timer interrupts during the benchmark -CONFIG_SYS_CLOCK_TICKS_PER_SEC=1 - -# We use irq_offload(), enable it -CONFIG_IRQ_OFFLOAD=y - -# Reduce memory/code footprint -CONFIG_BT=n -CONFIG_FORCE_NO_ASSERT=y - -CONFIG_TEST_HW_STACK_PROTECTION=n -# Disable HW Stack Protection (see #28664) -CONFIG_HW_STACK_PROTECTION=n -CONFIG_COVERAGE=n - -# Disable system power management -CONFIG_PM=n - -# Can only run under 1 CPU -CONFIG_MP_MAX_NUM_CPUS=1 -CONFIG_TIMING_FUNCTIONS=y - -CONFIG_HEAP_MEM_POOL_SIZE=2048 -CONFIG_APPLICATION_DEFINED_SYSCALL=y -CONFIG_USERSPACE=y - -# Disable time slicing -CONFIG_TIMESLICING=n - -# Enable events -CONFIG_EVENTS=y diff --git a/tests/benchmarks/latency_measure/testcase.yaml b/tests/benchmarks/latency_measure/testcase.yaml index e57edecba8d..e6af80305c7 100644 --- a/tests/benchmarks/latency_measure/testcase.yaml +++ b/tests/benchmarks/latency_measure/testcase.yaml @@ -63,7 +63,8 @@ tests: benchmark.kernel.latency.userspace: filter: CONFIG_ARCH_HAS_USERSPACE timeout: 300 - extra_args: CONF_FILE=prj_user.conf + extra_configs: + - CONFIG_USERSPACE=y harness: console integration_platforms: - qemu_x86 @@ -81,12 +82,12 @@ tests: benchmark.kernel.latency.userspace.objcore.stats: filter: CONFIG_ARCH_HAS_USERSPACE timeout: 300 - extra_args: CONF_FILE=prj_user.conf harness: console integration_platforms: - qemu_x86 - qemu_cortex_a53 extra_configs: + - CONFIG_USERSPACE=y - CONFIG_OBJ_CORE=y - CONFIG_OBJ_CORE_STATS=y harness_config: @@ -120,12 +121,12 @@ tests: benchmark.kernel.latency.timeslicing.userspace: filter: CONFIG_ARCH_HAS_USERSPACE timeout: 300 - extra_args: CONF_FILE=prj_user.conf harness: console integration_platforms: - qemu_x86 - qemu_cortex_a53 extra_configs: + - CONFIG_USERSPACE=y - CONFIG_TIMESLICING=y harness_config: type: one_line From 5573b20ec6c13a2ecfa9d746010c11db3a78aaef Mon Sep 17 00:00:00 2001 From: Peter Mitsis Date: Thu, 18 Jan 2024 11:32:33 -0500 Subject: [PATCH 2664/3723] tests: latency_measure: tweak frdm_k64f config The FRDM K64F board runs at 120 MHz and has a 24 bit timer. According to its timer driver, its MAX_TICKS (which comes into play for a tickless kernel) is calculated as ... CYC_PER_TICK = 120 MHz / ticks per second MAX_TICKS = (COUNTER_MAX / CYC_PER_TICK) - 1 To achieve a minimum value of MAX_TICKS=1, ticks per second must be set to at least 15. Experimentation has shown that setting the number of ticks per second below this threshhold on a tickless kerenl leads to unreliable timestamps. Signed-off-by: Peter Mitsis --- tests/benchmarks/latency_measure/boards/frdm_k64f.conf | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/tests/benchmarks/latency_measure/boards/frdm_k64f.conf b/tests/benchmarks/latency_measure/boards/frdm_k64f.conf index 34b1402918b..376cf521f31 100644 --- a/tests/benchmarks/latency_measure/boards/frdm_k64f.conf +++ b/tests/benchmarks/latency_measure/boards/frdm_k64f.conf @@ -1,4 +1,4 @@ -# eliminate timer interrupts during the benchmark -# for platforms that do not allow frequency dividers large enough to get -# system clock tick period in 1 sec, make system clock tick to 0.1 sec -CONFIG_SYS_CLOCK_TICKS_PER_SEC=10 +# The minimum number of system ticks per second that this platform will +# allow for a tickless kernel given its 24-bit timer and its 120 MHz +# clock rate is 15. +CONFIG_SYS_CLOCK_TICKS_PER_SEC=15 From 441b1b7de8a897650a99c3e6cf7819e3957ce15f Mon Sep 17 00:00:00 2001 From: Yves Vandervennet Date: Thu, 18 Jan 2024 14:16:04 -0600 Subject: [PATCH 2665/3723] boards: frdm_kl25z: enable support for linkserver - adds the definitions in the board.cmake file - updates documentation Signed-off-by: Yves Vandervennet --- boards/arm/frdm_kl25z/board.cmake | 2 ++ boards/arm/frdm_kl25z/doc/index.rst | 25 +++++++++++++++++++------ 2 files changed, 21 insertions(+), 6 deletions(-) diff --git a/boards/arm/frdm_kl25z/board.cmake b/boards/arm/frdm_kl25z/board.cmake index 7f7a37db23f..d711b305325 100644 --- a/boards/arm/frdm_kl25z/board.cmake +++ b/boards/arm/frdm_kl25z/board.cmake @@ -1,7 +1,9 @@ # SPDX-License-Identifier: Apache-2.0 board_runner_args(jlink "--device=MKL25Z128xxx4") +board_runner_args(linkserver "--device=MKL25Z128xxx4:FRDM-KL25Z") board_runner_args(pyocd "--target=kl25z") +include(${ZEPHYR_BASE}/boards/common/linkserver.board.cmake) include(${ZEPHYR_BASE}/boards/common/pyocd.board.cmake) include(${ZEPHYR_BASE}/boards/common/jlink.board.cmake) diff --git a/boards/arm/frdm_kl25z/doc/index.rst b/boards/arm/frdm_kl25z/doc/index.rst index 333f686f640..22261a26e57 100644 --- a/boards/arm/frdm_kl25z/doc/index.rst +++ b/boards/arm/frdm_kl25z/doc/index.rst @@ -130,14 +130,21 @@ Early versions of this board have an outdated version of the OpenSDA bootloader and require an update. Please see the `DAPLink Bootloader Update`_ page for instructions to update from the CMSIS-DAP bootloader to the DAPLink bootloader. -Option 1: :ref:`opensda-daplink-onboard-debug-probe` (Recommended) ------------------------------------------------------------------- +Option 1: Linkserver: :ref:`opensda-daplink-onboard-debug-probe` (Recommended) +------------------------------------------------------------------------------ -Install the :ref:`pyocd-debug-host-tools` and make sure they are in your search -path. + Install the :ref:`linkserver-debug-host-tools` and make sure they are in your + search path. LinkServer works with the CMSIS-DAP debug firmware. Please follow the + instructions on :ref:`opensda-daplink-onboard-debug-probe` and select the latest revision + of the firmware image. + + Linkserver is the default for this board, ``west flash`` and ``west debug`` will + call the linkserver runner. + + .. code-block:: console -Follow the instructions in :ref:`opensda-daplink-onboard-debug-probe` to program -the `OpenSDA DAPLink FRDM-KL25Z Firmware`_. + west flash + west debug Option 2: :ref:`opensda-jlink-onboard-debug-probe` -------------------------------------------------- @@ -158,6 +165,12 @@ default runner from pyOCD to J-Link: :gen-args: -DBOARD_FLASH_RUNNER=jlink -DBOARD_DEBUG_RUNNER=jlink :goals: build +Note: +----- + +The runners supported by NXP are LinkServer and JLink. pyOCD is another potential option, +but NXP does not test or support the pyOCD runner. + Configuring a Console ===================== From 140a510030ef5cfc1feca9fc44249a2d2373cc01 Mon Sep 17 00:00:00 2001 From: Bjarki Arge Andreasen Date: Fri, 19 Jan 2024 09:03:26 +0100 Subject: [PATCH 2666/3723] tests: build_all: modem: Remove net tag and clean up Remove the net tag, allowing the modem driver tests to be built for PRs, and limit the scope of the test suite to only build for select emulated 32 and 64 bit boards. Signed-off-by: Bjarki Arge Andreasen --- .../build_all/modem/modem_cellular.conf | 6 +- .../drivers/build_all/modem/modem_esp_at.conf | 5 +- tests/drivers/build_all/modem/modem_gsm.conf | 5 +- .../build_all/modem/modem_gsm_mux.conf | 11 ++ .../modem/{modem.conf => modem_hl7800.conf} | 6 +- .../build_all/modem/modem_quectel_bg9x.conf | 6 +- .../build_all/modem/modem_simcom_sim7080.conf | 7 +- .../build_all/modem/modem_ublox_sara.conf | 6 +- tests/drivers/build_all/modem/prj.conf | 3 - tests/drivers/build_all/modem/testcase.yaml | 137 ++++++++---------- 10 files changed, 88 insertions(+), 104 deletions(-) create mode 100644 tests/drivers/build_all/modem/modem_gsm_mux.conf rename tests/drivers/build_all/modem/{modem.conf => modem_hl7800.conf} (79%) delete mode 100644 tests/drivers/build_all/modem/prj.conf diff --git a/tests/drivers/build_all/modem/modem_cellular.conf b/tests/drivers/build_all/modem/modem_cellular.conf index 3366fcf32d4..4582216f772 100644 --- a/tests/drivers/build_all/modem/modem_cellular.conf +++ b/tests/drivers/build_all/modem/modem_cellular.conf @@ -1,10 +1,8 @@ -CONFIG_TEST=y -CONFIG_TEST_RANDOM_GENERATOR=y +CONFIG_GPIO=y CONFIG_SERIAL=y +CONFIG_MODEM=y CONFIG_NETWORKING=y CONFIG_NET_L2_PPP=y -CONFIG_MODEM=y CONFIG_PM_DEVICE=y CONFIG_MODEM_CELLULAR=y CONFIG_UART_ASYNC_API=y -CONFIG_GPIO=y diff --git a/tests/drivers/build_all/modem/modem_esp_at.conf b/tests/drivers/build_all/modem/modem_esp_at.conf index 01d4b62ba50..6ba79c82653 100644 --- a/tests/drivers/build_all/modem/modem_esp_at.conf +++ b/tests/drivers/build_all/modem/modem_esp_at.conf @@ -1,7 +1,6 @@ -CONFIG_TEST=y -CONFIG_TEST_RANDOM_GENERATOR=y -CONFIG_SERIAL=y CONFIG_GPIO=y +CONFIG_SERIAL=y +CONFIG_MODEM=y CONFIG_NETWORKING=y CONFIG_NET_SOCKETS=y CONFIG_NET_IPV4=y diff --git a/tests/drivers/build_all/modem/modem_gsm.conf b/tests/drivers/build_all/modem/modem_gsm.conf index a7c4e492bc3..dd5b37afb9e 100644 --- a/tests/drivers/build_all/modem/modem_gsm.conf +++ b/tests/drivers/build_all/modem/modem_gsm.conf @@ -1,10 +1,9 @@ -CONFIG_TEST=y -CONFIG_TEST_RANDOM_GENERATOR=y +CONFIG_GPIO=y CONFIG_SERIAL=y +CONFIG_MODEM=y CONFIG_NETWORKING=y CONFIG_NET_IPV4=y CONFIG_NET_DRIVERS=y CONFIG_NET_PPP=y CONFIG_NET_L2_PPP=y -CONFIG_MODEM=y CONFIG_MODEM_GSM_PPP=y diff --git a/tests/drivers/build_all/modem/modem_gsm_mux.conf b/tests/drivers/build_all/modem/modem_gsm_mux.conf new file mode 100644 index 00000000000..952ace2466d --- /dev/null +++ b/tests/drivers/build_all/modem/modem_gsm_mux.conf @@ -0,0 +1,11 @@ +CONFIG_GPIO=y +CONFIG_SERIAL=y +CONFIG_MODEM=y +CONFIG_NETWORKING=y +CONFIG_NET_IPV4=y +CONFIG_NET_DRIVERS=y +CONFIG_NET_PPP=y +CONFIG_NET_L2_PPP=y +CONFIG_MODEM_GSM_PPP=y +CONFIG_GSM_MUX=y +CONFIG_UART_MUX=y diff --git a/tests/drivers/build_all/modem/modem.conf b/tests/drivers/build_all/modem/modem_hl7800.conf similarity index 79% rename from tests/drivers/build_all/modem/modem.conf rename to tests/drivers/build_all/modem/modem_hl7800.conf index 0143f6fcd7f..5cc44bb71ea 100644 --- a/tests/drivers/build_all/modem/modem.conf +++ b/tests/drivers/build_all/modem/modem_hl7800.conf @@ -1,10 +1,8 @@ -CONFIG_TEST=y -CONFIG_TEST_RANDOM_GENERATOR=y -CONFIG_TEST_USERSPACE=y +CONFIG_GPIO=y CONFIG_SERIAL=y +CONFIG_MODEM=y CONFIG_NETWORKING=y CONFIG_NET_IPV4=y -CONFIG_MODEM=y CONFIG_MODEM_HL7800=y CONFIG_MODEM_HL7800_FW_UPDATE=y CONFIG_MODEM_HL7800_SET_APN_NAME_ON_STARTUP=y diff --git a/tests/drivers/build_all/modem/modem_quectel_bg9x.conf b/tests/drivers/build_all/modem/modem_quectel_bg9x.conf index 9fb71bbe412..f868a0ef77a 100644 --- a/tests/drivers/build_all/modem/modem_quectel_bg9x.conf +++ b/tests/drivers/build_all/modem/modem_quectel_bg9x.conf @@ -1,9 +1,7 @@ -CONFIG_TEST=y -CONFIG_TEST_RANDOM_GENERATOR=y -CONFIG_SERIAL=y CONFIG_GPIO=y +CONFIG_SERIAL=y +CONFIG_MODEM=y CONFIG_NETWORKING=y CONFIG_NET_SOCKETS=y -CONFIG_MODEM=y CONFIG_MODEM_QUECTEL_BG9X=y CONFIG_MODEM_QUECTEL_BG9X_APN="hologram" diff --git a/tests/drivers/build_all/modem/modem_simcom_sim7080.conf b/tests/drivers/build_all/modem/modem_simcom_sim7080.conf index dc4645a2455..b6f1530f8a2 100644 --- a/tests/drivers/build_all/modem/modem_simcom_sim7080.conf +++ b/tests/drivers/build_all/modem/modem_simcom_sim7080.conf @@ -1,8 +1,7 @@ -CONFIG_TEST=y -CONFIG_TEST_RANDOM_GENERATOR=y -CONFIG_SERIAL=y CONFIG_GPIO=y +CONFIG_SERIAL=y +CONFIG_MODEM=y CONFIG_NETWORKING=y +CONFIG_GPIO=y CONFIG_NET_SOCKETS=y -CONFIG_MODEM=y CONFIG_MODEM_SIM7080=y diff --git a/tests/drivers/build_all/modem/modem_ublox_sara.conf b/tests/drivers/build_all/modem/modem_ublox_sara.conf index 21e61c8ec54..8cef947f051 100644 --- a/tests/drivers/build_all/modem/modem_ublox_sara.conf +++ b/tests/drivers/build_all/modem/modem_ublox_sara.conf @@ -1,8 +1,6 @@ -CONFIG_TEST=y -CONFIG_TEST_RANDOM_GENERATOR=y -CONFIG_SERIAL=y CONFIG_GPIO=y +CONFIG_SERIAL=y +CONFIG_MODEM=y CONFIG_NETWORKING=y CONFIG_NET_SOCKETS=y -CONFIG_MODEM=y CONFIG_MODEM_UBLOX_SARA=y diff --git a/tests/drivers/build_all/modem/prj.conf b/tests/drivers/build_all/modem/prj.conf deleted file mode 100644 index bb5ccbec1ba..00000000000 --- a/tests/drivers/build_all/modem/prj.conf +++ /dev/null @@ -1,3 +0,0 @@ -CONFIG_TEST=y -CONFIG_TEST_USERSPACE=y -CONFIG_SERIAL=y diff --git a/tests/drivers/build_all/modem/testcase.yaml b/tests/drivers/build_all/modem/testcase.yaml index 25c338b9fda..303e0ee44e8 100644 --- a/tests/drivers/build_all/modem/testcase.yaml +++ b/tests/drivers/build_all/modem/testcase.yaml @@ -1,86 +1,73 @@ common: build_only: true - tags: - - drivers - - net - - modem + platform_allow: + - native_sim + - native_sim_64 + - qemu_x86 + - qemu_x86_64 + tests: - drivers.modem.build: - extra_args: CONF_FILE=modem.conf - platform_exclude: - - serpente - - particle_boron - - rak5010_nrf52840 - - litex_vexriscv - - ip_k66f - min_ram: 68 - min_flash: 115 - drivers.modem.ublox_sara.build: + drivers.modem.modem_hl7800.interrupt_driven.build: + extra_args: CONF_FILE=modem_hl7800.conf + extra_configs: + - CONFIG_UART_INTERRUPT_DRIVEN=y + drivers.modem.modem_hl7800.async.build: + extra_args: CONF_FILE=modem_hl7800.conf + extra_configs: + - CONFIG_UART_ASYNC_API=y + drivers.modem.modem_ublox_sara.interrupt_driven.build: extra_args: CONF_FILE=modem_ublox_sara.conf - platform_exclude: - - serpente - - pinnacle_100_dvk - - litex_vexriscv - - ip_k66f - - mg100 - drivers.modem.simcom_sim7080.build: - extra_args: CONF_FILE=modem_simcom_sim7080.conf - platform_exclude: - - serpente - - pinnacle_100_dvk - - litex_vexriscv - - ip_k66f - - mg100 - drivers.modem.quectel_bg9x.build: + extra_configs: + - CONFIG_UART_INTERRUPT_DRIVEN=y + drivers.modem.modem_ublox_sara.async.build: + extra_args: CONF_FILE=modem_ublox_sara.conf + extra_configs: + - CONFIG_UART_ASYNC_API=y + drivers.modem.modem_quectel_bg9x.interrupt_driven.build: extra_args: CONF_FILE=modem_quectel_bg9x.conf - platform_exclude: - - serpente - - pinnacle_100_dvk - - litex_vexriscv - - ip_k66f - - mg100 - min_ram: 36 - drivers.modem.gsm.build: + extra_configs: + - CONFIG_UART_INTERRUPT_DRIVEN=y + drivers.modem.modem_quectel_bg9x.async.build: + extra_args: CONF_FILE=modem_quectel_bg9x.conf + extra_configs: + - CONFIG_UART_ASYNC_API=y + drivers.modem.modem_gsm.interrupt_driven.build: extra_args: CONF_FILE=modem_gsm.conf - platform_exclude: - - serpente - - particle_boron - - rak5010_nrf52840 - - litex_vexriscv - - ip_k66f - min_ram: 36 - drivers.modem.gsm_mux.build: + extra_configs: + - CONFIG_UART_INTERRUPT_DRIVEN=y + drivers.modem.modem_gsm.async.build: extra_args: CONF_FILE=modem_gsm.conf - platform_exclude: - - serpente - - particle_boron - - rak5010_nrf52840 - - litex_vexriscv - - ip_k66f - min_ram: 36 - extra_configs: - - CONFIG_GSM_MUX=y - - CONFIG_UART_MUX=y - drivers.modem.esp_at.build: + extra_configs: + - CONFIG_UART_ASYNC_API=y + drivers.modem.modem_gsm_mux.interrupt_driven.build: + extra_args: CONF_FILE=modem_gsm_mux.conf + extra_configs: + - CONFIG_UART_INTERRUPT_DRIVEN=y + drivers.modem.modem_gsm_mux.async.build: + extra_args: CONF_FILE=modem_gsm_mux.conf + extra_configs: + - CONFIG_UART_ASYNC_API=y + drivers.modem.modem_esp_at.interrupt_driven.build: extra_args: CONF_FILE=modem_esp_at.conf - platform_exclude: - - ip_k66f - - cy8cproto_062_4343w - filter: CONFIG_SERIAL - min_ram: 36 - drivers.modem.esp_at.async.build: + extra_configs: + - CONFIG_UART_INTERRUPT_DRIVEN=y + drivers.modem.modem_esp_at.async.build: extra_args: CONF_FILE=modem_esp_at.conf - filter: CONFIG_SERIAL and CONFIG_QEMU_TARGET - min_ram: 36 extra_configs: - - CONFIG_MODEM_IFACE_UART_ASYNC=y - drivers.modem.modem_cellular.build: + - CONFIG_UART_ASYNC_API=y + drivers.modem.modem_cellular.interrupt_driven.build: + extra_args: CONF_FILE=modem_cellular.conf + extra_configs: + - CONFIG_UART_INTERRUPT_DRIVEN=y + drivers.modem.modem_cellular.async.build: extra_args: CONF_FILE=modem_cellular.conf - platform_allow: - - native_posix_64 - - native_posix - - native_sim_64 - - native_sim - - qemu_x86 - - qemu_x86_64 - min_ram: 36 + extra_configs: + - CONFIG_UART_ASYNC_API=y + drivers.modem.modem_simcom_sim7080.interrupt_driven.build: + extra_args: CONF_FILE=modem_simcom_sim7080.conf + extra_configs: + - CONFIG_UART_INTERRUPT_DRIVEN=y + drivers.modem.modem_simcom_sim7080.async.build: + extra_args: CONF_FILE=modem_simcom_sim7080.conf + extra_configs: + - CONFIG_UART_ASYNC_API=y From fb639ab81b220b89d15a324c9d55550678d66a66 Mon Sep 17 00:00:00 2001 From: Henrik Brix Andersen Date: Fri, 19 Jan 2024 13:47:57 +0100 Subject: [PATCH 2667/3723] drivers: can: loopback: add common configuration structure Add the common configuration structure to the CAN loopback driver. Signed-off-by: Henrik Brix Andersen --- drivers/can/can_loopback.c | 21 +++++++++++++++------ 1 file changed, 15 insertions(+), 6 deletions(-) diff --git a/drivers/can/can_loopback.c b/drivers/can/can_loopback.c index 938002f5978..ffab53b315e 100644 --- a/drivers/can/can_loopback.c +++ b/drivers/can/can_loopback.c @@ -28,6 +28,10 @@ struct can_loopback_filter { struct can_filter filter; }; +struct can_loopback_config { + const struct can_driver_config common; +}; + struct can_loopback_data { struct can_driver_data common; struct can_loopback_filter filters[CONFIG_CAN_MAX_FILTER]; @@ -452,12 +456,17 @@ static int can_loopback_init(const struct device *dev) return 0; } -#define CAN_LOOPBACK_INIT(inst) \ - static struct can_loopback_data can_loopback_dev_data_##inst; \ - \ - CAN_DEVICE_DT_INST_DEFINE(inst, can_loopback_init, NULL, \ - &can_loopback_dev_data_##inst, NULL, \ - POST_KERNEL, CONFIG_CAN_INIT_PRIORITY,\ +#define CAN_LOOPBACK_INIT(inst) \ + static const struct can_loopback_config can_loopback_config_##inst = { \ + .common = CAN_DT_DRIVER_CONFIG_INST_GET(inst, 0U), \ + }; \ + \ + static struct can_loopback_data can_loopback_data_##inst; \ + \ + CAN_DEVICE_DT_INST_DEFINE(inst, can_loopback_init, NULL, \ + &can_loopback_data_##inst, \ + &can_loopback_config_##inst, \ + POST_KERNEL, CONFIG_CAN_INIT_PRIORITY, \ &can_loopback_driver_api); DT_INST_FOREACH_STATUS_OKAY(CAN_LOOPBACK_INIT) From 766ce3c1e222b274bd242f166344fe7a977bb695 Mon Sep 17 00:00:00 2001 From: Henrik Brix Andersen Date: Fri, 19 Jan 2024 13:49:22 +0100 Subject: [PATCH 2668/3723] drivers: can: fake: add common configuration and data structures Add common configuration and data structures to the fake CAN driver. Signed-off-by: Henrik Brix Andersen --- drivers/can/can_fake.c | 17 ++++++++++++++++- 1 file changed, 16 insertions(+), 1 deletion(-) diff --git a/drivers/can/can_fake.c b/drivers/can/can_fake.c index 88d7780eaad..8020ad8563b 100644 --- a/drivers/can/can_fake.c +++ b/drivers/can/can_fake.c @@ -15,6 +15,14 @@ #define DT_DRV_COMPAT zephyr_fake_can +struct fake_can_config { + const struct can_driver_config common; +}; + +struct fake_can_data { + struct can_driver_data common; +}; + DEFINE_FAKE_VALUE_FUNC(int, fake_can_start, const struct device *); DEFINE_FAKE_VALUE_FUNC(int, fake_can_stop, const struct device *); @@ -139,7 +147,14 @@ static const struct can_driver_api fake_can_driver_api = { }; #define FAKE_CAN_INIT(inst) \ - CAN_DEVICE_DT_INST_DEFINE(inst, NULL, NULL, NULL, NULL, POST_KERNEL, \ + static const struct fake_can_config fake_can_config_##inst = { \ + .common = CAN_DT_DRIVER_CONFIG_INST_GET(inst, 0U), \ + }; \ + \ + static struct fake_can_data fake_can_data_##inst; \ + \ + CAN_DEVICE_DT_INST_DEFINE(inst, NULL, NULL, &fake_can_data_##inst, \ + &fake_can_config_##inst, POST_KERNEL, \ CONFIG_CAN_INIT_PRIORITY, \ &fake_can_driver_api); From 0875a752c12c6bcea4960d772af40eebea35a785 Mon Sep 17 00:00:00 2001 From: Henrik Brix Andersen Date: Fri, 19 Jan 2024 13:49:51 +0100 Subject: [PATCH 2669/3723] tests: drivers: can: api: fix uninitialized variable warning. Fix a warning about unitialized variable. The test will be skipped in this code path. Signed-off-by: Henrik Brix Andersen --- tests/drivers/can/api/src/classic.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/drivers/can/api/src/classic.c b/tests/drivers/can/api/src/classic.c index 3259f300b26..b70ff7e1003 100644 --- a/tests/drivers/can/api/src/classic.c +++ b/tests/drivers/can/api/src/classic.c @@ -480,7 +480,7 @@ ZTEST(can_classic, test_set_state_change_callback) */ ZTEST_USER(can_classic, test_set_bitrate_too_high) { - uint32_t max; + uint32_t max = 0U; int err; err = can_get_max_bitrate(can_dev, &max); From 4340724fd047db454f8aaf534877085e36c8f3bf Mon Sep 17 00:00:00 2001 From: Henrik Brix Andersen Date: Fri, 19 Jan 2024 13:10:27 +0100 Subject: [PATCH 2670/3723] drivers: can: use common accessor for getting maximum supported bitrate Use a common accessor for getting the maximum supported bitrate of a CAN controller. Signed-off-by: Henrik Brix Andersen --- drivers/can/can_esp32_twai.c | 1 - drivers/can/can_fake.c | 10 ---------- drivers/can/can_handlers.c | 1 - drivers/can/can_kvaser_pci.c | 1 - drivers/can/can_mcan.c | 9 --------- drivers/can/can_mcp2515.c | 10 ---------- drivers/can/can_mcp251xfd.c | 10 ---------- drivers/can/can_mcux_flexcan.c | 11 ----------- drivers/can/can_mcux_mcan.c | 1 - drivers/can/can_numaker.c | 1 - drivers/can/can_nxp_s32_canxl.c | 10 ---------- drivers/can/can_rcar.c | 10 ---------- drivers/can/can_sam.c | 1 - drivers/can/can_sam0.c | 1 - drivers/can/can_sja1000.c | 9 --------- drivers/can/can_stm32_bxcan.c | 10 ---------- drivers/can/can_stm32_fdcan.c | 1 - drivers/can/can_stm32h7_fdcan.c | 1 - drivers/can/can_tcan4x5x.c | 1 - include/zephyr/drivers/can.h | 15 +++++---------- include/zephyr/drivers/can/can_mcan.h | 6 ------ include/zephyr/drivers/can/can_sja1000.h | 6 ------ 22 files changed, 5 insertions(+), 121 deletions(-) diff --git a/drivers/can/can_esp32_twai.c b/drivers/can/can_esp32_twai.c index 3545bb9fa9e..11c30a2338c 100644 --- a/drivers/can/can_esp32_twai.c +++ b/drivers/can/can_esp32_twai.c @@ -224,7 +224,6 @@ const struct can_driver_api can_esp32_twai_driver_api = { .set_state_change_callback = can_sja1000_set_state_change_callback, .get_core_clock = can_esp32_twai_get_core_clock, .get_max_filters = can_sja1000_get_max_filters, - .get_max_bitrate = can_sja1000_get_max_bitrate, #ifndef CONFIG_CAN_AUTO_BUS_OFF_RECOVERY .recover = can_sja1000_recover, #endif /* !CONFIG_CAN_AUTO_BUS_OFF_RECOVERY */ diff --git a/drivers/can/can_fake.c b/drivers/can/can_fake.c index 8020ad8563b..f2845bbee9b 100644 --- a/drivers/can/can_fake.c +++ b/drivers/can/can_fake.c @@ -87,15 +87,6 @@ static int fake_can_get_core_clock(const struct device *dev, uint32_t *rate) return 0; } -static int fake_can_get_max_bitrate(const struct device *dev, uint32_t *max_bitrate) -{ - ARG_UNUSED(dev); - - *max_bitrate = 5000000; - - return 0; -} - static const struct can_driver_api fake_can_driver_api = { .start = fake_can_start, .stop = fake_can_stop, @@ -112,7 +103,6 @@ static const struct can_driver_api fake_can_driver_api = { .set_state_change_callback = fake_can_set_state_change_callback, .get_core_clock = fake_can_get_core_clock, .get_max_filters = fake_can_get_max_filters, - .get_max_bitrate = fake_can_get_max_bitrate, .timing_min = { .sjw = 0x01, .prop_seg = 0x01, diff --git a/drivers/can/can_handlers.c b/drivers/can/can_handlers.c index 57201ce6eca..6113f149541 100644 --- a/drivers/can/can_handlers.c +++ b/drivers/can/can_handlers.c @@ -48,7 +48,6 @@ static inline int z_vrfy_can_get_core_clock(const struct device *dev, static inline int z_vrfy_can_get_max_bitrate(const struct device *dev, uint32_t *max_bitrate) { - /* Optional API function */ K_OOPS(K_SYSCALL_OBJ(dev, K_OBJ_DRIVER_CAN)); K_OOPS(K_SYSCALL_MEMORY_WRITE(max_bitrate, sizeof(*max_bitrate))); diff --git a/drivers/can/can_kvaser_pci.c b/drivers/can/can_kvaser_pci.c index 2aa002efd8c..909b29a0a34 100644 --- a/drivers/can/can_kvaser_pci.c +++ b/drivers/can/can_kvaser_pci.c @@ -143,7 +143,6 @@ const struct can_driver_api can_kvaser_pci_driver_api = { .set_state_change_callback = can_sja1000_set_state_change_callback, .get_core_clock = can_kvaser_pci_get_core_clock, .get_max_filters = can_sja1000_get_max_filters, - .get_max_bitrate = can_sja1000_get_max_bitrate, #ifndef CONFIG_CAN_AUTO_BUS_OFF_RECOVERY .recover = can_sja1000_recover, #endif /* !CONFIG_CAN_AUTO_BUS_OFF_RECOVERY */ diff --git a/drivers/can/can_mcan.c b/drivers/can/can_mcan.c index d777e325b82..8718e91d223 100644 --- a/drivers/can/can_mcan.c +++ b/drivers/can/can_mcan.c @@ -1167,15 +1167,6 @@ void can_mcan_set_state_change_callback(const struct device *dev, data->common.state_change_cb_user_data = user_data; } -int can_mcan_get_max_bitrate(const struct device *dev, uint32_t *max_bitrate) -{ - const struct can_mcan_config *config = dev->config; - - *max_bitrate = config->common.max_bitrate; - - return 0; -} - /* helper function allowing mcan drivers without access to private mcan * definitions to set CCCR_CCE, which might be needed to disable write * protection for some registers. diff --git a/drivers/can/can_mcp2515.c b/drivers/can/can_mcp2515.c index 255a8cdbe70..126dee34c6f 100644 --- a/drivers/can/can_mcp2515.c +++ b/drivers/can/can_mcp2515.c @@ -334,15 +334,6 @@ static int mcp2515_get_max_filters(const struct device *dev, bool ide) return CONFIG_CAN_MAX_FILTER; } -static int mcp2515_get_max_bitrate(const struct device *dev, uint32_t *max_bitrate) -{ - const struct mcp2515_config *dev_cfg = dev->config; - - *max_bitrate = dev_cfg->common.max_bitrate; - - return 0; -} - static int mcp2515_set_timing(const struct device *dev, const struct can_timing *timing) { @@ -936,7 +927,6 @@ static const struct can_driver_api can_api_funcs = { .set_state_change_callback = mcp2515_set_state_change_callback, .get_core_clock = mcp2515_get_core_clock, .get_max_filters = mcp2515_get_max_filters, - .get_max_bitrate = mcp2515_get_max_bitrate, .timing_min = { .sjw = 0x1, .prop_seg = 0x01, diff --git a/drivers/can/can_mcp251xfd.c b/drivers/can/can_mcp251xfd.c index e029d54496b..24e7c1bd9bf 100644 --- a/drivers/can/can_mcp251xfd.c +++ b/drivers/can/can_mcp251xfd.c @@ -742,15 +742,6 @@ static int mcp251xfd_get_max_filters(const struct device *dev, bool ide) return CONFIG_CAN_MAX_FILTER; } -static int mcp251xfd_get_max_bitrate(const struct device *dev, uint32_t *max_bitrate) -{ - const struct mcp251xfd_config *dev_cfg = dev->config; - - *max_bitrate = dev_cfg->common.max_bitrate; - - return 0; -} - #ifndef CONFIG_CAN_AUTO_BUS_OFF_RECOVERY static int mcp251xfd_recover(const struct device *dev, k_timeout_t timeout) { @@ -1681,7 +1672,6 @@ static const struct can_driver_api mcp251xfd_api_funcs = { .set_state_change_callback = mcp251xfd_set_state_change_callback, .get_core_clock = mcp251xfd_get_core_clock, .get_max_filters = mcp251xfd_get_max_filters, - .get_max_bitrate = mcp251xfd_get_max_bitrate, .timing_min = { .sjw = 1, .prop_seg = 0, diff --git a/drivers/can/can_mcux_flexcan.c b/drivers/can/can_mcux_flexcan.c index f83b2ec212a..8d3eccac150 100644 --- a/drivers/can/can_mcux_flexcan.c +++ b/drivers/can/can_mcux_flexcan.c @@ -158,15 +158,6 @@ static int mcux_flexcan_get_max_filters(const struct device *dev, bool ide) return CONFIG_CAN_MAX_FILTER; } -static int mcux_flexcan_get_max_bitrate(const struct device *dev, uint32_t *max_bitrate) -{ - const struct mcux_flexcan_config *config = dev->config; - - *max_bitrate = config->common.max_bitrate; - - return 0; -} - static int mcux_flexcan_set_timing(const struct device *dev, const struct can_timing *timing) { @@ -1310,7 +1301,6 @@ __maybe_unused static const struct can_driver_api mcux_flexcan_driver_api = { .set_state_change_callback = mcux_flexcan_set_state_change_callback, .get_core_clock = mcux_flexcan_get_core_clock, .get_max_filters = mcux_flexcan_get_max_filters, - .get_max_bitrate = mcux_flexcan_get_max_bitrate, /* * FlexCAN timing limits are specified in the "FLEXCANx_CTRL1 field * descriptions" table in the SoC reference manual. @@ -1354,7 +1344,6 @@ static const struct can_driver_api mcux_flexcan_fd_driver_api = { .set_state_change_callback = mcux_flexcan_set_state_change_callback, .get_core_clock = mcux_flexcan_get_core_clock, .get_max_filters = mcux_flexcan_get_max_filters, - .get_max_bitrate = mcux_flexcan_get_max_bitrate, /* * FlexCAN FD timing limits are specified in the "CAN Bit Timing * Register (CBT)" and "CAN FD Bit Timing Register" field description diff --git a/drivers/can/can_mcux_mcan.c b/drivers/can/can_mcux_mcan.c index b4c24e2b19e..28a709a023c 100644 --- a/drivers/can/can_mcux_mcan.c +++ b/drivers/can/can_mcux_mcan.c @@ -139,7 +139,6 @@ static const struct can_driver_api mcux_mcan_driver_api = { .set_state_change_callback = can_mcan_set_state_change_callback, .get_core_clock = mcux_mcan_get_core_clock, .get_max_filters = can_mcan_get_max_filters, - .get_max_bitrate = can_mcan_get_max_bitrate, /* * MCUX MCAN timing limits are specified in the "Nominal bit timing and * prescaler register (NBTP)" table in the SoC reference manual. diff --git a/drivers/can/can_numaker.c b/drivers/can/can_numaker.c index c2e7bba3943..ba51b8b82fd 100644 --- a/drivers/can/can_numaker.c +++ b/drivers/can/can_numaker.c @@ -176,7 +176,6 @@ static const struct can_driver_api can_numaker_driver_api = { .set_state_change_callback = can_mcan_set_state_change_callback, .get_core_clock = can_numaker_get_core_clock, .get_max_filters = can_mcan_get_max_filters, - .get_max_bitrate = can_mcan_get_max_bitrate, .timing_min = CAN_MCAN_TIMING_MIN_INITIALIZER, .timing_max = CAN_MCAN_TIMING_MAX_INITIALIZER, #ifdef CONFIG_CAN_FD_MODE diff --git a/drivers/can/can_nxp_s32_canxl.c b/drivers/can/can_nxp_s32_canxl.c index 2ea854fad9e..bd5e19ce7bd 100644 --- a/drivers/can/can_nxp_s32_canxl.c +++ b/drivers/can/can_nxp_s32_canxl.c @@ -363,15 +363,6 @@ static int can_nxp_s32_get_max_filters(const struct device *dev, bool ide) return CONFIG_CAN_NXP_S32_MAX_RX; } -static int can_nxp_s32_get_max_bitrate(const struct device *dev, uint32_t *max_bitrate) -{ - const struct can_nxp_s32_config *config = dev->config; - - *max_bitrate = config->common.max_bitrate; - - return 0; -} - static int can_nxp_s32_get_state(const struct device *dev, enum can_state *state, struct can_bus_err_cnt *err_cnt) { @@ -1088,7 +1079,6 @@ static const struct can_driver_api can_nxp_s32_driver_api = { .set_state_change_callback = can_nxp_s32_set_state_change_callback, .get_core_clock = can_nxp_s32_get_core_clock, .get_max_filters = can_nxp_s32_get_max_filters, - .get_max_bitrate = can_nxp_s32_get_max_bitrate, .timing_min = { .sjw = 0x01, .prop_seg = 0x01, diff --git a/drivers/can/can_rcar.c b/drivers/can/can_rcar.c index 98c134ac509..b988e748afc 100644 --- a/drivers/can/can_rcar.c +++ b/drivers/can/can_rcar.c @@ -1146,15 +1146,6 @@ static int can_rcar_get_max_filters(const struct device *dev, bool ide) return CONFIG_CAN_RCAR_MAX_FILTER; } -static int can_rcar_get_max_bitrate(const struct device *dev, uint32_t *max_bitrate) -{ - const struct can_rcar_cfg *config = dev->config; - - *max_bitrate = config->common.max_bitrate; - - return 0; -} - static const struct can_driver_api can_rcar_driver_api = { .get_capabilities = can_rcar_get_capabilities, .start = can_rcar_start, @@ -1171,7 +1162,6 @@ static const struct can_driver_api can_rcar_driver_api = { .set_state_change_callback = can_rcar_set_state_change_callback, .get_core_clock = can_rcar_get_core_clock, .get_max_filters = can_rcar_get_max_filters, - .get_max_bitrate = can_rcar_get_max_bitrate, .timing_min = { .sjw = 0x1, .prop_seg = 0x00, diff --git a/drivers/can/can_sam.c b/drivers/can/can_sam.c index 4be722386ae..4f0f32bce91 100644 --- a/drivers/can/can_sam.c +++ b/drivers/can/can_sam.c @@ -131,7 +131,6 @@ static const struct can_driver_api can_sam_driver_api = { #endif /* CONFIG_CAN_AUTO_BUS_OFF_RECOVERY */ .get_core_clock = can_sam_get_core_clock, .get_max_filters = can_mcan_get_max_filters, - .get_max_bitrate = can_mcan_get_max_bitrate, .set_state_change_callback = can_mcan_set_state_change_callback, .timing_min = CAN_MCAN_TIMING_MIN_INITIALIZER, .timing_max = CAN_MCAN_TIMING_MAX_INITIALIZER, diff --git a/drivers/can/can_sam0.c b/drivers/can/can_sam0.c index af584df619a..0a8bacda05c 100644 --- a/drivers/can/can_sam0.c +++ b/drivers/can/can_sam0.c @@ -176,7 +176,6 @@ static const struct can_driver_api can_sam0_driver_api = { #endif /* CONFIG_CAN_AUTO_BUS_OFF_RECOVERY */ .get_core_clock = can_sam0_get_core_clock, .get_max_filters = can_mcan_get_max_filters, - .get_max_bitrate = can_mcan_get_max_bitrate, .set_state_change_callback = can_mcan_set_state_change_callback, .timing_min = CAN_MCAN_TIMING_MIN_INITIALIZER, .timing_max = CAN_MCAN_TIMING_MAX_INITIALIZER, diff --git a/drivers/can/can_sja1000.c b/drivers/can/can_sja1000.c index c5ee7bebcfd..d6c565f9ea2 100644 --- a/drivers/can/can_sja1000.c +++ b/drivers/can/can_sja1000.c @@ -549,15 +549,6 @@ int can_sja1000_get_max_filters(const struct device *dev, bool ide) return CONFIG_CAN_MAX_FILTER; } -int can_sja1000_get_max_bitrate(const struct device *dev, uint32_t *max_bitrate) -{ - const struct can_sja1000_config *config = dev->config; - - *max_bitrate = config->common.max_bitrate; - - return 0; -} - static void can_sja1000_handle_receive_irq(const struct device *dev) { struct can_sja1000_data *data = dev->data; diff --git a/drivers/can/can_stm32_bxcan.c b/drivers/can/can_stm32_bxcan.c index 03f67e86670..0f2a121e790 100644 --- a/drivers/can/can_stm32_bxcan.c +++ b/drivers/can/can_stm32_bxcan.c @@ -582,15 +582,6 @@ static int can_stm32_get_core_clock(const struct device *dev, uint32_t *rate) return 0; } -static int can_stm32_get_max_bitrate(const struct device *dev, uint32_t *max_bitrate) -{ - const struct can_stm32_config *config = dev->config; - - *max_bitrate = config->common.max_bitrate; - - return 0; -} - static int can_stm32_get_max_filters(const struct device *dev, bool ide) { ARG_UNUSED(dev); @@ -1097,7 +1088,6 @@ static const struct can_driver_api can_api_funcs = { #endif .set_state_change_callback = can_stm32_set_state_change_callback, .get_core_clock = can_stm32_get_core_clock, - .get_max_bitrate = can_stm32_get_max_bitrate, .get_max_filters = can_stm32_get_max_filters, .timing_min = { .sjw = 0x1, diff --git a/drivers/can/can_stm32_fdcan.c b/drivers/can/can_stm32_fdcan.c index 1237ddad7b3..fffd291778d 100644 --- a/drivers/can/can_stm32_fdcan.c +++ b/drivers/can/can_stm32_fdcan.c @@ -590,7 +590,6 @@ static const struct can_driver_api can_stm32fd_driver_api = { .recover = can_mcan_recover, #endif /* CONFIG_CAN_AUTO_BUS_OFF_RECOVERY */ .get_core_clock = can_stm32fd_get_core_clock, - .get_max_bitrate = can_mcan_get_max_bitrate, .get_max_filters = can_mcan_get_max_filters, .set_state_change_callback = can_mcan_set_state_change_callback, .timing_min = CAN_MCAN_TIMING_MIN_INITIALIZER, diff --git a/drivers/can/can_stm32h7_fdcan.c b/drivers/can/can_stm32h7_fdcan.c index b2e8b8060ef..e4965f32a92 100644 --- a/drivers/can/can_stm32h7_fdcan.c +++ b/drivers/can/can_stm32h7_fdcan.c @@ -208,7 +208,6 @@ static const struct can_driver_api can_stm32h7_driver_api = { .recover = can_mcan_recover, #endif .get_core_clock = can_stm32h7_get_core_clock, - .get_max_bitrate = can_mcan_get_max_bitrate, .get_max_filters = can_mcan_get_max_filters, .set_state_change_callback = can_mcan_set_state_change_callback, /* Timing limits are per the STM32H7 Reference Manual (RM0433 Rev 7), diff --git a/drivers/can/can_tcan4x5x.c b/drivers/can/can_tcan4x5x.c index d80f8e77526..8d8a1a612ad 100644 --- a/drivers/can/can_tcan4x5x.c +++ b/drivers/can/can_tcan4x5x.c @@ -729,7 +729,6 @@ static const struct can_driver_api tcan4x5x_driver_api = { .set_state_change_callback = can_mcan_set_state_change_callback, .get_core_clock = tcan4x5x_get_core_clock, .get_max_filters = can_mcan_get_max_filters, - .get_max_bitrate = can_mcan_get_max_bitrate, .timing_min = CAN_MCAN_TIMING_MIN_INITIALIZER, .timing_max = CAN_MCAN_TIMING_MAX_INITIALIZER, #ifdef CONFIG_CAN_FD_MODE diff --git a/include/zephyr/drivers/can.h b/include/zephyr/drivers/can.h index dfcb62906dd..ce97a15e832 100644 --- a/include/zephyr/drivers/can.h +++ b/include/zephyr/drivers/can.h @@ -482,12 +482,6 @@ typedef int (*can_get_core_clock_t)(const struct device *dev, uint32_t *rate); */ typedef int (*can_get_max_filters_t)(const struct device *dev, bool ide); -/** - * @brief Optional callback API upon getting the maximum supported bitrate - * See @a can_get_max_bitrate() for argument description - */ -typedef int (*can_get_max_bitrate_t)(const struct device *dev, uint32_t *max_bitrate); - __subsystem struct can_driver_api { can_get_capabilities_t get_capabilities; can_start_t start; @@ -504,7 +498,6 @@ __subsystem struct can_driver_api { can_set_state_change_callback_t set_state_change_callback; can_get_core_clock_t get_core_clock; can_get_max_filters_t get_max_filters; - can_get_max_bitrate_t get_max_bitrate; /* Min values for the timing registers */ struct can_timing timing_min; /* Max values for the timing registers */ @@ -824,13 +817,15 @@ __syscall int can_get_max_bitrate(const struct device *dev, uint32_t *max_bitrat static inline int z_impl_can_get_max_bitrate(const struct device *dev, uint32_t *max_bitrate) { - const struct can_driver_api *api = (const struct can_driver_api *)dev->api; + const struct can_driver_config *common = (const struct can_driver_config *)dev->config; - if (api->get_max_bitrate == NULL) { + if (common->max_bitrate == 0U) { return -ENOSYS; } - return api->get_max_bitrate(dev, max_bitrate); + *max_bitrate = common->max_bitrate; + + return 0; } /** diff --git a/include/zephyr/drivers/can/can_mcan.h b/include/zephyr/drivers/can/can_mcan.h index 8e09d589833..a20f9864880 100644 --- a/include/zephyr/drivers/can/can_mcan.h +++ b/include/zephyr/drivers/can/can_mcan.h @@ -1709,10 +1709,4 @@ int can_mcan_get_state(const struct device *dev, enum can_state *state, void can_mcan_set_state_change_callback(const struct device *dev, can_state_change_callback_t callback, void *user_data); -/** - * @brief Bosch M_CAN driver callback API upon getting the maximum supported bitrate - * See @a can_get_max_bitrate() for argument description - */ -int can_mcan_get_max_bitrate(const struct device *dev, uint32_t *max_bitrate); - #endif /* ZEPHYR_INCLUDE_DRIVERS_CAN_CAN_MCAN_H_ */ diff --git a/include/zephyr/drivers/can/can_sja1000.h b/include/zephyr/drivers/can/can_sja1000.h index 2a5c0edd8ae..a3a316c26b8 100644 --- a/include/zephyr/drivers/can/can_sja1000.h +++ b/include/zephyr/drivers/can/can_sja1000.h @@ -261,12 +261,6 @@ void can_sja1000_set_state_change_callback(const struct device *dev, */ int can_sja1000_get_max_filters(const struct device *dev, bool ide); -/** - * @brief SJA1000 callback API upon getting the maximum supported bitrate - * See @a can_get_max_bitrate() for argument description - */ -int can_sja1000_get_max_bitrate(const struct device *dev, uint32_t *max_bitrate); - /** * @brief SJA1000 IRQ handler callback. * From e4c3f30febafd6fd44de3e829dce849469eb10a1 Mon Sep 17 00:00:00 2001 From: Henrik Brix Andersen Date: Fri, 19 Jan 2024 13:18:44 +0100 Subject: [PATCH 2671/3723] doc: releases: migration-guide: 3.6: list removal of can_get_max_bitrate_t Add a note about the removal of the optional can_get_max_bitrate_t callback from the CAN controller driver API. Signed-off-by: Henrik Brix Andersen --- doc/releases/migration-guide-3.6.rst | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/doc/releases/migration-guide-3.6.rst b/doc/releases/migration-guide-3.6.rst index 990f1d0e515..45aae4ca87e 100644 --- a/doc/releases/migration-guide-3.6.rst +++ b/doc/releases/migration-guide-3.6.rst @@ -175,6 +175,15 @@ Device Drivers and Device Tree * The main Kconfig option was renamed from ``CONFIG_CAN_NATIVE_POSIX_LINUX`` to :kconfig:option:`CONFIG_CAN_NATIVE_LINUX`. +* Two new structures for holding common CAN controller driver configuration (``struct + can_driver_config``) and data (``struct can_driver_data``) fields were introduced. Out-of-tree CAN + controller drivers need to be updated to use these new, common configuration and data structures + along with their initializer macros. + +* The optional ``can_get_max_bitrate_t`` CAN controller driver callback was removed in favor of a + common accessor function. Out-of-tree CAN controller drivers need to be updated to no longer + supply this callback. + * The ``CAN_FILTER_FDF`` flag for filtering classic CAN/CAN FD frames was removed since no known CAN controllers implement support for this. Applications can still filter on classic CAN/CAN FD frames in their receive callback functions as needed. From aef39f69239bf2c4f2e07c11171d1d3ad896ad4f Mon Sep 17 00:00:00 2001 From: Emil Gydesen Date: Fri, 19 Jan 2024 13:13:08 +0100 Subject: [PATCH 2672/3723] Bluetooth: BAP: Fix issue with setting invalid iso data path BAP would always set up the ISO data path in both directions, even for unidirectional CIS. This meant that in the unconfigured direction, the data path configuration data would all be 0, which causes issues on some controllers. The new refactored approach implemented by this commit will always ensure that the data path is setup correctly, and that we only set the data path in one direction for unidirectional CIS. The unset path will use the default ISO path of HCI and transparant format, which should always be allowed by a controller. This is building on the requirement in BAP that all streams in a unicast group shall be QoS configured at the same time. This ensures that before any streams in the CIG has been connected, they have all been configured. Signed-off-by: Emil Gydesen --- subsys/bluetooth/audio/ascs.c | 6 +-- subsys/bluetooth/audio/bap_broadcast_sink.c | 2 +- subsys/bluetooth/audio/bap_broadcast_source.c | 4 +- subsys/bluetooth/audio/bap_iso.c | 48 +++++++++++++++---- subsys/bluetooth/audio/bap_iso.h | 1 + subsys/bluetooth/audio/bap_stream.c | 22 --------- subsys/bluetooth/audio/bap_stream.h | 2 - subsys/bluetooth/audio/bap_unicast_client.c | 13 +---- 8 files changed, 46 insertions(+), 52 deletions(-) diff --git a/subsys/bluetooth/audio/ascs.c b/subsys/bluetooth/audio/ascs.c index 686c13443ca..229eb90edb8 100644 --- a/subsys/bluetooth/audio/ascs.c +++ b/subsys/bluetooth/audio/ascs.c @@ -1929,11 +1929,7 @@ static void ase_qos(struct bt_ascs_ase *ase, uint8_t cig_id, uint8_t cis_id, * we have the ISO <-> EP coupling completed (due to setting * the CIS ID in the QoS procedure). */ - if (ep->dir == BT_AUDIO_DIR_SINK) { - bt_audio_codec_cfg_to_iso_path(&ep->iso->rx.path, stream->codec_cfg); - } else { - bt_audio_codec_cfg_to_iso_path(&ep->iso->tx.path, stream->codec_cfg); - } + bt_bap_iso_configure_data_path(ep, stream->codec_cfg); ep->cig_id = cig_id; ep->cis_id = cis_id; diff --git a/subsys/bluetooth/audio/bap_broadcast_sink.c b/subsys/bluetooth/audio/bap_broadcast_sink.c index 827b3e20b2c..3ec003349f5 100644 --- a/subsys/bluetooth/audio/bap_broadcast_sink.c +++ b/subsys/bluetooth/audio/bap_broadcast_sink.c @@ -892,7 +892,7 @@ static int bt_bap_broadcast_sink_setup_stream(struct bt_bap_broadcast_sink *sink bt_bap_iso_bind_ep(iso, ep); bt_audio_codec_qos_to_iso_qos(iso->chan.qos->rx, &sink->codec_qos); - bt_audio_codec_cfg_to_iso_path(iso->chan.qos->rx->path, codec_cfg); + bt_bap_iso_configure_data_path(ep, codec_cfg); bt_bap_iso_unref(iso); diff --git a/subsys/bluetooth/audio/bap_broadcast_source.c b/subsys/bluetooth/audio/bap_broadcast_source.c index 375e4da9c29..3982be82e74 100644 --- a/subsys/bluetooth/audio/bap_broadcast_source.c +++ b/subsys/bluetooth/audio/bap_broadcast_source.c @@ -294,7 +294,7 @@ static int broadcast_source_setup_stream(uint8_t index, struct bt_bap_stream *st bt_bap_iso_bind_ep(iso, ep); bt_audio_codec_qos_to_iso_qos(iso->chan.qos->tx, qos); - bt_audio_codec_cfg_to_iso_path(iso->chan.qos->tx->path, codec_cfg); + bt_bap_iso_configure_data_path(ep, codec_cfg); #if defined(CONFIG_BT_ISO_TEST_PARAMS) iso->chan.qos->num_subevents = qos->num_subevents; #endif /* CONFIG_BT_ISO_TEST_PARAMS */ @@ -884,7 +884,7 @@ int bt_bap_broadcast_source_reconfig(struct bt_bap_broadcast_source *source, iso_qos = stream->ep->iso->chan.qos->tx; bt_bap_stream_attach(NULL, stream, stream->ep, codec_cfg); - bt_audio_codec_cfg_to_iso_path(iso_qos->path, codec_cfg); + bt_bap_iso_configure_data_path(stream->ep, codec_cfg); } } diff --git a/subsys/bluetooth/audio/bap_iso.c b/subsys/bluetooth/audio/bap_iso.c index cb68a8032f5..3fa2059ea94 100644 --- a/subsys/bluetooth/audio/bap_iso.c +++ b/subsys/bluetooth/audio/bap_iso.c @@ -129,19 +129,12 @@ void bt_bap_iso_init(struct bt_bap_iso *iso, struct bt_iso_chan_ops *ops) iso->chan.ops = ops; iso->chan.qos = &iso->qos; - /* Setup points for both Tx and Rx + /* Setup the QoS for both Tx and Rx * This is due to the limitation in the ISO API where pointers like - * the `qos->tx` shall be initialized before the CIS is connected if - * ever want to use it for TX, and ditto for RX. They cannot be - * initialized after the CIS has been connected + * the `qos->tx` shall be initialized before the CIS is created */ iso->chan.qos->rx = &iso->rx.qos; - iso->chan.qos->rx->path = &iso->rx.path; - iso->chan.qos->rx->path->cc = iso->rx.cc; - iso->chan.qos->tx = &iso->tx.qos; - iso->chan.qos->tx->path = &iso->tx.path; - iso->chan.qos->tx->path->cc = iso->tx.cc; } static struct bt_bap_iso_dir *bap_iso_get_iso_dir(bool unicast_client, struct bt_bap_iso *iso, @@ -164,6 +157,43 @@ static struct bt_bap_iso_dir *bap_iso_get_iso_dir(bool unicast_client, struct bt } } +void bt_bap_iso_configure_data_path(struct bt_bap_ep *ep, struct bt_audio_codec_cfg *codec_cfg) +{ + struct bt_bap_iso *bap_iso = ep->iso; + struct bt_iso_chan_qos *qos = bap_iso->chan.qos; + const bool is_unicast_client = + IS_ENABLED(CONFIG_BT_BAP_UNICAST_CLIENT) && bt_bap_ep_is_unicast_client(ep); + struct bt_bap_iso_dir *iso_dir = bap_iso_get_iso_dir(is_unicast_client, bap_iso, ep->dir); + struct bt_iso_chan_path *path = &iso_dir->path; + + /* Setup the data path objects */ + if (iso_dir == &bap_iso->rx) { + qos->rx->path = path; + } else { + qos->tx->path = path; + } + + /* Configure the data path to either use the controller for transcoding, or set the path to + * be transparant to indicate that the transcoding happens somewhere else + */ + path->pid = codec_cfg->path_id; + + if (codec_cfg->ctlr_transcode) { + path->format = codec_cfg->id; + path->cid = codec_cfg->cid; + path->vid = codec_cfg->vid; + path->delay = 0; + path->cc_len = codec_cfg->data_len; + path->cc = codec_cfg->data; + } else { + path->format = BT_HCI_CODING_FORMAT_TRANSPARENT; + path->cid = 0; + path->vid = 0; + path->delay = 0; + path->cc_len = 0; + path->cc = NULL; + } +} static bool is_unicast_client_ep(struct bt_bap_ep *ep) { return IS_ENABLED(CONFIG_BT_BAP_UNICAST_CLIENT) && bt_bap_ep_is_unicast_client(ep); diff --git a/subsys/bluetooth/audio/bap_iso.h b/subsys/bluetooth/audio/bap_iso.h index d3b27f3823a..4384182d697 100644 --- a/subsys/bluetooth/audio/bap_iso.h +++ b/subsys/bluetooth/audio/bap_iso.h @@ -41,6 +41,7 @@ void bt_bap_iso_foreach(bt_bap_iso_func_t func, void *user_data); struct bt_bap_iso *bt_bap_iso_find(bt_bap_iso_func_t func, void *user_data); void bt_bap_iso_init(struct bt_bap_iso *iso, struct bt_iso_chan_ops *ops); void bt_bap_iso_bind_ep(struct bt_bap_iso *iso, struct bt_bap_ep *ep); +void bt_bap_iso_configure_data_path(struct bt_bap_ep *ep, struct bt_audio_codec_cfg *codec_cfg); void bt_bap_iso_unbind_ep(struct bt_bap_iso *iso, struct bt_bap_ep *ep); struct bt_bap_ep *bt_bap_iso_get_ep(bool unicast_client, struct bt_bap_iso *iso, enum bt_audio_dir dir); diff --git a/subsys/bluetooth/audio/bap_stream.c b/subsys/bluetooth/audio/bap_stream.c index 2fc4b00bdbf..8377ec6e20e 100644 --- a/subsys/bluetooth/audio/bap_stream.c +++ b/subsys/bluetooth/audio/bap_stream.c @@ -31,28 +31,6 @@ LOG_MODULE_REGISTER(bt_bap_stream, CONFIG_BT_BAP_STREAM_LOG_LEVEL); -void bt_audio_codec_cfg_to_iso_path(struct bt_iso_chan_path *path, - struct bt_audio_codec_cfg *codec_cfg) -{ - path->pid = codec_cfg->path_id; - - if (codec_cfg->ctlr_transcode) { - path->format = codec_cfg->id; - path->cid = codec_cfg->cid; - path->vid = codec_cfg->vid; - path->delay = 0; - path->cc_len = codec_cfg->data_len; - path->cc = codec_cfg->data; - } else { - path->format = BT_HCI_CODING_FORMAT_TRANSPARENT; - path->cid = 0; - path->vid = 0; - path->delay = 0; - path->cc_len = 0; - path->cc = NULL; - } -} - #if defined(CONFIG_BT_BAP_UNICAST_CLIENT) || defined(CONFIG_BT_BAP_BROADCAST_SOURCE) || \ defined(CONFIG_BT_BAP_BROADCAST_SINK) void bt_audio_codec_qos_to_iso_qos(struct bt_iso_chan_io_qos *io, diff --git a/subsys/bluetooth/audio/bap_stream.h b/subsys/bluetooth/audio/bap_stream.h index 67e8c0470df..d16cf2cfcc9 100644 --- a/subsys/bluetooth/audio/bap_stream.h +++ b/subsys/bluetooth/audio/bap_stream.h @@ -17,8 +17,6 @@ void bt_bap_stream_reset(struct bt_bap_stream *stream); void bt_bap_stream_attach(struct bt_conn *conn, struct bt_bap_stream *stream, struct bt_bap_ep *ep, struct bt_audio_codec_cfg *codec_cfg); -void bt_audio_codec_cfg_to_iso_path(struct bt_iso_chan_path *path, - struct bt_audio_codec_cfg *codec_cfg); void bt_audio_codec_qos_to_iso_qos(struct bt_iso_chan_io_qos *io, const struct bt_audio_codec_qos *codec_qos); diff --git a/subsys/bluetooth/audio/bap_unicast_client.c b/subsys/bluetooth/audio/bap_unicast_client.c index af34ac6e74c..e823a094de5 100644 --- a/subsys/bluetooth/audio/bap_unicast_client.c +++ b/subsys/bluetooth/audio/bap_unicast_client.c @@ -806,17 +806,8 @@ static void unicast_client_ep_qos_state(struct bt_bap_ep *ep, struct net_buf_sim * we have the ISO <-> EP coupling completed (due to setting * the CIS ID in the QoS procedure). */ - if (ep->dir == BT_AUDIO_DIR_SOURCE) { - /* If the endpoint is a source, then we need to - * configure our RX parameters - */ - bt_audio_codec_cfg_to_iso_path(&ep->iso->rx.path, stream->codec_cfg); - } else { - /* If the endpoint is a sink, then we need to - * configure our TX parameters - */ - bt_audio_codec_cfg_to_iso_path(&ep->iso->tx.path, stream->codec_cfg); - } + + bt_bap_iso_configure_data_path(ep, stream->codec_cfg); } /* Notify upper layer */ From 68bea801119fe9a479f4a53185dfa0c95d26ce95 Mon Sep 17 00:00:00 2001 From: Sandip Dalvi Date: Fri, 17 Nov 2023 10:08:20 +0530 Subject: [PATCH 2673/3723] net: ipv6: Add APIs to check ipv6 address is site local and global Add APIs to check the IPv6 address is site local or is global. Signed-off-by: Sandip Dalvi --- include/zephyr/net/net_ip.h | 25 +++++++++++++++++++++++++ 1 file changed, 25 insertions(+) diff --git a/include/zephyr/net/net_ip.h b/include/zephyr/net/net_ip.h index b392184a815..75f75aa1f42 100644 --- a/include/zephyr/net/net_ip.h +++ b/include/zephyr/net/net_ip.h @@ -841,6 +841,19 @@ static inline bool net_ipv6_is_ll_addr(const struct in6_addr *addr) return UNALIGNED_GET(&addr->s6_addr16[0]) == htons(0xFE80); } +/** + * @brief Check if the given IPv6 address is a site local address. + * + * @param addr A valid pointer on an IPv6 address + * + * @return True if it is, false otherwise. + */ +static inline bool net_ipv6_is_sl_addr(const struct in6_addr *addr) +{ + return UNALIGNED_GET(&addr->s6_addr16[0]) == htons(0xFEC0); +} + + /** * @brief Check if the given IPv6 address is a unique local address. * @@ -853,6 +866,18 @@ static inline bool net_ipv6_is_ula_addr(const struct in6_addr *addr) return addr->s6_addr[0] == 0xFD; } +/** + * @brief Check if the given IPv6 address is a global address. + * + * @param addr A valid pointer on an IPv6 address + * + * @return True if it is, false otherwise. + */ +static inline bool net_ipv6_is_global_addr(const struct in6_addr *addr) +{ + return (addr->s6_addr[0] & 0xE0) == 0x20; +} + /** * @brief Return pointer to any (all bits zeros) IPv6 address. * From 2a11c648763f7d6891c97be513b7d0d232caccb5 Mon Sep 17 00:00:00 2001 From: Fabian Blatz Date: Fri, 8 Dec 2023 12:50:22 +0100 Subject: [PATCH 2674/3723] manifest: update LVGL to v8.3.11 Related to zephyrproject-rtos/lvgl#47 Signed-off-by: Fabian Blatz --- west.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/west.yml b/west.yml index 566231e1cec..a3e75541246 100644 --- a/west.yml +++ b/west.yml @@ -274,7 +274,7 @@ manifest: revision: 842413c5fb98707eb5f26e619e8e792453877897 path: modules/lib/loramac-node - name: lvgl - revision: 7c61a4cec26402d20c845c95dcad0e39dcd319f8 + revision: pull/47/head path: modules/lib/gui/lvgl - name: mbedtls revision: 66ed2279d6222056af172c188eaf4dcfed481032 From 7cc46e6948d3ae1e48c930af64a2f36d3f2243d2 Mon Sep 17 00:00:00 2001 From: Fabian Blatz Date: Fri, 8 Dec 2023 12:52:50 +0100 Subject: [PATCH 2675/3723] modules: lvgl: Update CMakeLists for 8.3.11 Update CMakeLists to include new files, sort existing ones. Signed-off-by: Fabian Blatz --- modules/lvgl/CMakeLists.txt | 18 +++++++++++++----- west.yml | 2 +- 2 files changed, 14 insertions(+), 6 deletions(-) diff --git a/modules/lvgl/CMakeLists.txt b/modules/lvgl/CMakeLists.txt index 9f119b016eb..a78950e4322 100644 --- a/modules/lvgl/CMakeLists.txt +++ b/modules/lvgl/CMakeLists.txt @@ -36,8 +36,8 @@ zephyr_library_sources( ${LVGL_DIR}/src/core/lv_theme.c ${LVGL_DIR}/src/draw/arm2d/lv_gpu_arm2d.c - ${LVGL_DIR}/src/draw/lv_draw.c ${LVGL_DIR}/src/draw/lv_draw_arc.c + ${LVGL_DIR}/src/draw/lv_draw.c ${LVGL_DIR}/src/draw/lv_draw_img.c ${LVGL_DIR}/src/draw/lv_draw_label.c ${LVGL_DIR}/src/draw/lv_draw_layer.c @@ -50,15 +50,21 @@ zephyr_library_sources( ${LVGL_DIR}/src/draw/lv_img_cache.c ${LVGL_DIR}/src/draw/lv_img_decoder.c ${LVGL_DIR}/src/draw/nxp/pxp/lv_draw_pxp_blend.c + ${LVGL_DIR}/src/draw/nxp/pxp/lv_draw_pxp.c ${LVGL_DIR}/src/draw/nxp/pxp/lv_gpu_nxp_pxp.c ${LVGL_DIR}/src/draw/nxp/pxp/lv_gpu_nxp_pxp_osa.c ${LVGL_DIR}/src/draw/nxp/vglite/lv_draw_vglite_arc.c ${LVGL_DIR}/src/draw/nxp/vglite/lv_draw_vglite_blend.c - ${LVGL_DIR}/src/draw/nxp/vglite/lv_draw_vglite_rect.c ${LVGL_DIR}/src/draw/nxp/vglite/lv_draw_vglite.c - ${LVGL_DIR}/src/draw/sdl/lv_draw_sdl.c + ${LVGL_DIR}/src/draw/nxp/vglite/lv_draw_vglite_line.c + ${LVGL_DIR}/src/draw/nxp/vglite/lv_draw_vglite_rect.c + ${LVGL_DIR}/src/draw/nxp/vglite/lv_vglite_buf.c + ${LVGL_DIR}/src/draw/nxp/vglite/lv_vglite_utils.c + ${LVGL_DIR}/src/draw/renesas/lv_gpu_d2_draw_label.c + ${LVGL_DIR}/src/draw/renesas/lv_gpu_d2_ra6m3.c ${LVGL_DIR}/src/draw/sdl/lv_draw_sdl_arc.c ${LVGL_DIR}/src/draw/sdl/lv_draw_sdl_bg.c + ${LVGL_DIR}/src/draw/sdl/lv_draw_sdl.c ${LVGL_DIR}/src/draw/sdl/lv_draw_sdl_composite.c ${LVGL_DIR}/src/draw/sdl/lv_draw_sdl_img.c ${LVGL_DIR}/src/draw/sdl/lv_draw_sdl_label.c @@ -71,9 +77,9 @@ zephyr_library_sources( ${LVGL_DIR}/src/draw/sdl/lv_draw_sdl_texture_cache.c ${LVGL_DIR}/src/draw/sdl/lv_draw_sdl_utils.c ${LVGL_DIR}/src/draw/stm32_dma2d/lv_gpu_stm32_dma2d.c - ${LVGL_DIR}/src/draw/sw/lv_draw_sw.c ${LVGL_DIR}/src/draw/sw/lv_draw_sw_arc.c ${LVGL_DIR}/src/draw/sw/lv_draw_sw_blend.c + ${LVGL_DIR}/src/draw/sw/lv_draw_sw.c ${LVGL_DIR}/src/draw/sw/lv_draw_sw_dither.c ${LVGL_DIR}/src/draw/sw/lv_draw_sw_gradient.c ${LVGL_DIR}/src/draw/sw/lv_draw_sw_img.c @@ -91,6 +97,7 @@ zephyr_library_sources( ${LVGL_DIR}/src/extra/libs/ffmpeg/lv_ffmpeg.c ${LVGL_DIR}/src/extra/libs/freetype/lv_freetype.c ${LVGL_DIR}/src/extra/libs/fsdrv/lv_fs_fatfs.c + ${LVGL_DIR}/src/extra/libs/fsdrv/lv_fs_littlefs.c ${LVGL_DIR}/src/extra/libs/fsdrv/lv_fs_posix.c ${LVGL_DIR}/src/extra/libs/fsdrv/lv_fs_stdio.c ${LVGL_DIR}/src/extra/libs/fsdrv/lv_fs_win32.c @@ -103,6 +110,7 @@ zephyr_library_sources( ${LVGL_DIR}/src/extra/libs/rlottie/lv_rlottie.c ${LVGL_DIR}/src/extra/libs/sjpg/lv_sjpg.c ${LVGL_DIR}/src/extra/libs/sjpg/tjpgd.c + ${LVGL_DIR}/src/extra/libs/tiny_ttf/lv_tiny_ttf.c ${LVGL_DIR}/src/extra/lv_extra.c ${LVGL_DIR}/src/extra/others/fragment/lv_fragment.c ${LVGL_DIR}/src/extra/others/fragment/lv_fragment_manager.c @@ -189,8 +197,8 @@ zephyr_library_sources( ${LVGL_DIR}/src/misc/lv_templ.c ${LVGL_DIR}/src/misc/lv_timer.c ${LVGL_DIR}/src/misc/lv_tlsf.c - ${LVGL_DIR}/src/misc/lv_txt.c ${LVGL_DIR}/src/misc/lv_txt_ap.c + ${LVGL_DIR}/src/misc/lv_txt.c ${LVGL_DIR}/src/misc/lv_utils.c ${LVGL_DIR}/src/widgets/lv_arc.c diff --git a/west.yml b/west.yml index a3e75541246..82c84a79f70 100644 --- a/west.yml +++ b/west.yml @@ -274,7 +274,7 @@ manifest: revision: 842413c5fb98707eb5f26e619e8e792453877897 path: modules/lib/loramac-node - name: lvgl - revision: pull/47/head + revision: 2b76c641749725ac90c6ac7959ca7718804cf356 path: modules/lib/gui/lvgl - name: mbedtls revision: 66ed2279d6222056af172c188eaf4dcfed481032 From e51c47bf4338aebd0b3b76c653d8082739bb8a2b Mon Sep 17 00:00:00 2001 From: Mustafa Homsi Date: Sun, 7 Jan 2024 18:02:24 -0800 Subject: [PATCH 2676/3723] Bluetooth: Controller: Fix regression in BT_CTLR_USED_PPI_CHANNELS Fix regression in BT_CTLR_USED_PPI_CHANNELS introduced in commit e39d98302d9f ("Bluetooth: Controller: nRF53: Cleanup dppi and dppi resources file"). Signed-off-by: Mustafa Homsi Signed-off-by: Vinayak Kariappa Chettimada --- .../hal/nrf5/nrfx_glue/bt_ctlr_used_resources.h | 7 ++++++- .../ll_sw/nordic/hal/nrf5/radio/radio_nrf5_dppi.h | 2 ++ .../hal/nrf5/radio/radio_nrf5_dppi_resources.h | 13 ++++++++++++- .../ll_sw/nordic/hal/nrf5/radio/radio_nrf5_ppi.h | 4 ++-- .../hal/nrf5/radio/radio_nrf5_ppi_resources.h | 14 +++++++++++--- 5 files changed, 33 insertions(+), 7 deletions(-) diff --git a/subsys/bluetooth/controller/ll_sw/nordic/hal/nrf5/nrfx_glue/bt_ctlr_used_resources.h b/subsys/bluetooth/controller/ll_sw/nordic/hal/nrf5/nrfx_glue/bt_ctlr_used_resources.h index a84e14cb9fb..b19abb3dfbb 100644 --- a/subsys/bluetooth/controller/ll_sw/nordic/hal/nrf5/nrfx_glue/bt_ctlr_used_resources.h +++ b/subsys/bluetooth/controller/ll_sw/nordic/hal/nrf5/nrfx_glue/bt_ctlr_used_resources.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2021 Nordic Semiconductor ASA + * Copyright (c) 2021-2024 Nordic Semiconductor ASA * * SPDX-License-Identifier: Apache-2.0 */ @@ -7,6 +7,11 @@ #include "../radio/radio_nrf5_resources.h" #include "../radio/radio_nrf5_fem.h" +/* NOTE: BT_CTLR_USED_PPI_CHANNELS is defined based on PPI defines being + * defined in the below PPI/DPPI resources header file. Take care to + * conditionally compile them based on feature Kconfig defines in those + * resources header file. + */ #ifdef DPPI_PRESENT #include "../radio/radio_nrf5_dppi_resources.h" #else diff --git a/subsys/bluetooth/controller/ll_sw/nordic/hal/nrf5/radio/radio_nrf5_dppi.h b/subsys/bluetooth/controller/ll_sw/nordic/hal/nrf5/radio/radio_nrf5_dppi.h index 1fdf7d90d30..5783589592a 100644 --- a/subsys/bluetooth/controller/ll_sw/nordic/hal/nrf5/radio/radio_nrf5_dppi.h +++ b/subsys/bluetooth/controller/ll_sw/nordic/hal/nrf5/radio/radio_nrf5_dppi.h @@ -171,6 +171,7 @@ static inline void hal_trigger_aar_ppi_config(void) nrf_aar_subscribe_set(NRF_AAR, NRF_AAR_TASK_START, HAL_TRIGGER_AAR_PPI); } +#if defined(CONFIG_BT_CTLR_PHY_CODED) && defined(CONFIG_HAS_HW_NRF_RADIO_BLE_CODED) /******************************************************************************* * Trigger Radio Rate override upon Rateboost event. */ @@ -179,6 +180,7 @@ static inline void hal_trigger_rateoverride_ppi_config(void) nrf_radio_publish_set(NRF_RADIO, NRF_RADIO_EVENT_RATEBOOST, HAL_TRIGGER_RATEOVERRIDE_PPI); nrf_ccm_subscribe_set(NRF_CCM, NRF_CCM_TASK_RATEOVERRIDE, HAL_TRIGGER_RATEOVERRIDE_PPI); } +#endif /* CONFIG_BT_CTLR_PHY_CODED && CONFIG_HAS_HW_NRF_RADIO_BLE_CODED */ /******************************************************************************/ #if defined(HAL_RADIO_GPIO_HAVE_PA_PIN) || defined(HAL_RADIO_GPIO_HAVE_LNA_PIN) diff --git a/subsys/bluetooth/controller/ll_sw/nordic/hal/nrf5/radio/radio_nrf5_dppi_resources.h b/subsys/bluetooth/controller/ll_sw/nordic/hal/nrf5/radio/radio_nrf5_dppi_resources.h index a8bbe8e63b4..8a6ba36a235 100644 --- a/subsys/bluetooth/controller/ll_sw/nordic/hal/nrf5/radio/radio_nrf5_dppi_resources.h +++ b/subsys/bluetooth/controller/ll_sw/nordic/hal/nrf5/radio/radio_nrf5_dppi_resources.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2021 Nordic Semiconductor ASA + * Copyright (c) 2021-2024 Nordic Semiconductor ASA * * SPDX-License-Identifier: Apache-2.0 */ @@ -61,11 +61,15 @@ */ #define HAL_TRIGGER_AAR_PPI 12 +#if defined(CONFIG_BT_CTLR_PHY_CODED) && \ + defined(CONFIG_HAS_HW_NRF_RADIO_BLE_CODED) /******************************************************************************* * Trigger Radio Rate override upon Rateboost event. */ #define HAL_TRIGGER_RATEOVERRIDE_PPI 13 +#endif /* CONFIG_BT_CTLR_PHY_CODED && CONFIG_HAS_HW_NRF_RADIO_BLE_CODED */ +#if defined(HAL_RADIO_GPIO_HAVE_PA_PIN) || defined(HAL_RADIO_GPIO_HAVE_LNA_PIN) /******************************************************************************/ #define HAL_ENABLE_PALNA_PPI 5 @@ -78,6 +82,8 @@ #define HAL_ENABLE_FEM_PPI 3 #define HAL_DISABLE_FEM_PPI HAL_DISABLE_PALNA_PPI +#endif /* HAL_RADIO_GPIO_HAVE_PA_PIN || HAL_RADIO_GPIO_HAVE_LNA_PIN */ + /******************************************************************************/ #if !defined(CONFIG_BT_CTLR_TIFS_HW) /* DPPI setup used for SW-based auto-switching during TIFS. */ @@ -123,6 +129,9 @@ */ #define HAL_SW_SWITCH_RADIO_ENABLE_PPI_BASE 14 +#if defined(CONFIG_BT_CTLR_PHY_CODED) && \ + defined(CONFIG_HAS_HW_NRF_RADIO_BLE_CODED) + #define HAL_SW_SWITCH_RADIO_ENABLE_S2_PPI_BASE \ HAL_SW_SWITCH_RADIO_ENABLE_PPI_BASE @@ -133,6 +142,8 @@ */ #define HAL_SW_SWITCH_TIMER_S8_DISABLE_PPI HAL_TRIGGER_RATEOVERRIDE_PPI +#endif /* CONFIG_BT_CTLR_PHY_CODED && CONFIG_HAS_HW_NRF_RADIO_BLE_CODED */ + #if defined(CONFIG_BT_CTLR_DF_PHYEND_OFFSET_COMPENSATION_ENABLE) /* Cancel the SW switch timer running considering PHYEND delay compensation timing: * wire the RADIO EVENTS_CTEPRESENT event to SW_SWITCH_TIMER TASKS_CAPTURE task. diff --git a/subsys/bluetooth/controller/ll_sw/nordic/hal/nrf5/radio/radio_nrf5_ppi.h b/subsys/bluetooth/controller/ll_sw/nordic/hal/nrf5/radio/radio_nrf5_ppi.h index 44cec4621a3..60fd8944ac4 100644 --- a/subsys/bluetooth/controller/ll_sw/nordic/hal/nrf5/radio/radio_nrf5_ppi.h +++ b/subsys/bluetooth/controller/ll_sw/nordic/hal/nrf5/radio/radio_nrf5_ppi.h @@ -257,7 +257,7 @@ static inline void hal_trigger_aar_ppi_config(void) /******************************************************************************* * Trigger Radio Rate override upon Rateboost event. */ -#if defined(CONFIG_HAS_HW_NRF_RADIO_BLE_CODED) +#if defined(CONFIG_BT_CTLR_PHY_CODED) && defined(CONFIG_HAS_HW_NRF_RADIO_BLE_CODED) static inline void hal_trigger_rateoverride_ppi_config(void) { nrf_ppi_channel_endpoint_setup( @@ -266,7 +266,7 @@ static inline void hal_trigger_rateoverride_ppi_config(void) (uint32_t)&(NRF_RADIO->EVENTS_RATEBOOST), (uint32_t)&(NRF_CCM->TASKS_RATEOVERRIDE)); } -#endif /* CONFIG_HAS_HW_NRF_RADIO_BLE_CODED */ +#endif /* CONFIG_BT_CTLR_PHY_CODED && CONFIG_HAS_HW_NRF_RADIO_BLE_CODED */ /******************************************************************************/ #if defined(HAL_RADIO_GPIO_HAVE_PA_PIN) || defined(HAL_RADIO_GPIO_HAVE_LNA_PIN) diff --git a/subsys/bluetooth/controller/ll_sw/nordic/hal/nrf5/radio/radio_nrf5_ppi_resources.h b/subsys/bluetooth/controller/ll_sw/nordic/hal/nrf5/radio/radio_nrf5_ppi_resources.h index ab196e17d58..58c2c57d974 100644 --- a/subsys/bluetooth/controller/ll_sw/nordic/hal/nrf5/radio/radio_nrf5_ppi_resources.h +++ b/subsys/bluetooth/controller/ll_sw/nordic/hal/nrf5/radio/radio_nrf5_ppi_resources.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2021 Nordic Semiconductor ASA + * Copyright (c) 2021-2024 Nordic Semiconductor ASA * * SPDX-License-Identifier: Apache-2.0 */ @@ -74,12 +74,15 @@ #define HAL_TRIGGER_AAR_PPI 23 /* Trigger Radio Rate override upon Rateboost event. */ -#if defined(CONFIG_HAS_HW_NRF_RADIO_BLE_CODED) +#if defined(CONFIG_BT_CTLR_PHY_CODED) && \ + defined(CONFIG_HAS_HW_NRF_RADIO_BLE_CODED) #define HAL_TRIGGER_RATEOVERRIDE_PPI 14 -#endif /* CONFIG_HAS_HW_NRF_RADIO_BLE_CODED */ +#endif /* CONFIG_BT_CTLR_PHY_CODED && CONFIG_HAS_HW_NRF_RADIO_BLE_CODED */ +#if defined(HAL_RADIO_GPIO_HAVE_PA_PIN) || defined(HAL_RADIO_GPIO_HAVE_LNA_PIN) #define HAL_ENABLE_PALNA_PPI 15 #define HAL_DISABLE_PALNA_PPI 16 +#endif /* HAL_RADIO_GPIO_HAVE_PA_PIN || HAL_RADIO_GPIO_HAVE_LNA_PIN */ #if defined(HAL_RADIO_FEM_IS_NRF21540) #define HAL_ENABLE_FEM_PPI 4 @@ -143,6 +146,9 @@ #define HAL_SW_SWITCH_RADIO_ENABLE_PPI_BASE 12 #endif +#if defined(CONFIG_BT_CTLR_PHY_CODED) && \ + defined(CONFIG_HAS_HW_NRF_RADIO_BLE_CODED) + /* Wire the SW SWITCH TIMER EVENTS_COMPARE[] event * to RADIO TASKS_TXEN/RXEN task. */ @@ -153,6 +159,8 @@ */ #define HAL_SW_SWITCH_TIMER_S8_DISABLE_PPI 19 +#endif /* CONFIG_BT_CTLR_PHY_CODED && CONFIG_HAS_HW_NRF_RADIO_BLE_CODED */ + #if defined(CONFIG_BT_CTLR_DF_PHYEND_OFFSET_COMPENSATION_ENABLE) /* Wire the SW SWITCH PHYEND delay compensation TIMER EVENTS_COMPARE[] event to software * switch TIMER0->CLEAR taks task. From 78faf5eb8e5c1f79dc7afd3183a4d969b3b7b146 Mon Sep 17 00:00:00 2001 From: Pisit Sawangvonganan Date: Mon, 22 Jan 2024 15:33:13 +0700 Subject: [PATCH 2677/3723] drivers: gnss: quectel_lcx6g: fix compilation error when CONFIG_PM_DEVICE=y Fixes a compilation error in quectel_lcx6g driver when CONFIG_PM_DEVICE=y. Corrects the function call in quectel_lcx6g_suspend from 'modem_chat_run_script_run' to 'modem_chat_run_script'. Signed-off-by: Pisit Sawangvonganan --- drivers/gnss/gnss_quectel_lcx6g.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/gnss/gnss_quectel_lcx6g.c b/drivers/gnss/gnss_quectel_lcx6g.c index f7b29b4640d..61d39140a9a 100644 --- a/drivers/gnss/gnss_quectel_lcx6g.c +++ b/drivers/gnss/gnss_quectel_lcx6g.c @@ -211,7 +211,7 @@ static int quectel_lcx6g_suspend(const struct device *dev) struct quectel_lcx6g_data *data = dev->data; int ret; - ret = modem_chat_run_script_run(&data->chat, &suspend_script); + ret = modem_chat_run_script(&data->chat, &suspend_script); if (ret < 0) { modem_pipe_close(data->uart_pipe); } From 7bcd0699e6c42217567d5297271fe3ca1b13aba7 Mon Sep 17 00:00:00 2001 From: Greter Raffael Date: Tue, 14 Nov 2023 15:54:27 +0000 Subject: [PATCH 2678/3723] gen_isr_tables: Add meaningful error message When using direct isrs, a vector table is needed. However, if none is present , i.e. `CONFIG_GEN_IRQ_VECTOR_TABLE=n`, this script failed. The given error message was not helpful (`'NoneType' has no len()`). This change makes it clearer, where to look for the problem. Signed-off-by: Greter Raffael --- scripts/build/gen_isr_tables.py | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/scripts/build/gen_isr_tables.py b/scripts/build/gen_isr_tables.py index 13c9d79b0b3..08ab9cc148c 100755 --- a/scripts/build/gen_isr_tables.py +++ b/scripts/build/gen_isr_tables.py @@ -358,6 +358,10 @@ def main(): for irq, flags, func, param in intlist["interrupts"]: if flags & ISR_FLAG_DIRECT: + if not vt: + error("Direct Interrupt %d declared with parameter 0x%x " + "but no vector table in use" + % (irq, param)) if param != 0: error("Direct irq %d declared, but has non-NULL parameter" % irq) From 8262766a0affca4046bc8131da8c6fa2df5afab0 Mon Sep 17 00:00:00 2001 From: Yong Cong Sin Date: Sat, 23 Dec 2023 15:06:02 +0800 Subject: [PATCH 2679/3723] tests: lib: devicetree: api: fix reg addr mismatch for test-mtd@ffeeddcc Fix unit address and first address in 'reg' (0x0) don't match for /test/test-mtd@ffeeddcc. Signed-off-by: Yong Cong Sin --- tests/lib/devicetree/api/app.overlay | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/lib/devicetree/api/app.overlay b/tests/lib/devicetree/api/app.overlay index 00fc428d733..c5bcbca2092 100644 --- a/tests/lib/devicetree/api/app.overlay +++ b/tests/lib/devicetree/api/app.overlay @@ -669,7 +669,7 @@ }; test-mtd@ffeeddcc { - reg = < 0x0 0x1000 >; + reg = < 0xffeeddcc 0x1000 >; #address-cells = < 1 >; #size-cells = < 1 >; From 4158d9523ea98c3fb92fbd2396a340017381e6f0 Mon Sep 17 00:00:00 2001 From: Vinayak Kariappa Chettimada Date: Thu, 18 Jan 2024 12:04:28 +0100 Subject: [PATCH 2680/3723] Bluetooth: Controller: Fix extended scanning data length assertion Fix assertion due to LLL scheduling of auxiliary PDU reception was not considered in the ULL when checking for accumulated data length exceeding the supported maximum scan data length. This caused the auxiliary context to be release while LLL was still active with scheduled PDU reception. Signed-off-by: Vinayak Kariappa Chettimada --- subsys/bluetooth/controller/ll_sw/ull_scan_aux.c | 15 ++++++++++++++- 1 file changed, 14 insertions(+), 1 deletion(-) diff --git a/subsys/bluetooth/controller/ll_sw/ull_scan_aux.c b/subsys/bluetooth/controller/ll_sw/ull_scan_aux.c index 9a86a473b02..3efb8c237e9 100644 --- a/subsys/bluetooth/controller/ll_sw/ull_scan_aux.c +++ b/subsys/bluetooth/controller/ll_sw/ull_scan_aux.c @@ -538,8 +538,21 @@ void ull_scan_aux_setup(memq_link_t *link, struct node_rx_hdr *rx) } else { aux->data_len += data_len; + /* Flush auxiliary PDU receptions and stop any more ULL + * scheduling if accumulated data length exceeds configured + * maximum supported. + */ if (aux->data_len >= CONFIG_BT_CTLR_SCAN_DATA_LEN_MAX) { - goto ull_scan_aux_rx_flush; + /* If LLL has already scheduled, then let it proceed. + * + * TODO: LLL to check accumulated data length and + * stop further reception. + * Currently LLL will schedule as long as there + * are free node rx available. + */ + if (!ftr->aux_lll_sched) { + goto ull_scan_aux_rx_flush; + } } } From 54a938a67ac6c451de0b4bfad4a46044667d9247 Mon Sep 17 00:00:00 2001 From: Markus Swarowsky Date: Mon, 22 Jan 2024 10:02:15 +0100 Subject: [PATCH 2681/3723] doc: services: tfm: Update version 2.0.0 in overview Update the mention of the "currently integrated" version of TFM to match the latest upgrade. Signed-off-by: Markus Swarowsky --- doc/services/tfm/overview.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/doc/services/tfm/overview.rst b/doc/services/tfm/overview.rst index 7b2f8db51de..ef71b53a113 100644 --- a/doc/services/tfm/overview.rst +++ b/doc/services/tfm/overview.rst @@ -8,7 +8,7 @@ It defines and implements an architecture and a set of software components that aim to address some of the main security concerns in IoT products. Zephyr RTOS has been PSA Certified since Zephyr 2.0.0 with TF-M 1.0, and -is currently integrated with TF-M 1.8.0. +is currently integrated with TF-M 2.0.0. What Does TF-M Offer? ********************* From f96c766fd8ec6e579b872cda4d547763201153a2 Mon Sep 17 00:00:00 2001 From: Seppo Takalo Date: Mon, 22 Jan 2024 14:43:54 +0200 Subject: [PATCH 2682/3723] tests: lwm2m: Rename engine to observation "engine" directory contained tests for observation so rename it. There is separate "lwm2m_engine" directory that contains tests for the engine itself. Signed-off-by: Seppo Takalo --- tests/net/lib/lwm2m/{engine => observation}/CMakeLists.txt | 0 tests/net/lib/lwm2m/{engine => observation}/prj.conf | 0 .../lib/lwm2m/{engine => observation}/src/lwm2m_observation.c | 0 tests/net/lib/lwm2m/{engine => observation}/testcase.yaml | 2 +- 4 files changed, 1 insertion(+), 1 deletion(-) rename tests/net/lib/lwm2m/{engine => observation}/CMakeLists.txt (100%) rename tests/net/lib/lwm2m/{engine => observation}/prj.conf (100%) rename tests/net/lib/lwm2m/{engine => observation}/src/lwm2m_observation.c (100%) rename tests/net/lib/lwm2m/{engine => observation}/testcase.yaml (83%) diff --git a/tests/net/lib/lwm2m/engine/CMakeLists.txt b/tests/net/lib/lwm2m/observation/CMakeLists.txt similarity index 100% rename from tests/net/lib/lwm2m/engine/CMakeLists.txt rename to tests/net/lib/lwm2m/observation/CMakeLists.txt diff --git a/tests/net/lib/lwm2m/engine/prj.conf b/tests/net/lib/lwm2m/observation/prj.conf similarity index 100% rename from tests/net/lib/lwm2m/engine/prj.conf rename to tests/net/lib/lwm2m/observation/prj.conf diff --git a/tests/net/lib/lwm2m/engine/src/lwm2m_observation.c b/tests/net/lib/lwm2m/observation/src/lwm2m_observation.c similarity index 100% rename from tests/net/lib/lwm2m/engine/src/lwm2m_observation.c rename to tests/net/lib/lwm2m/observation/src/lwm2m_observation.c diff --git a/tests/net/lib/lwm2m/engine/testcase.yaml b/tests/net/lib/lwm2m/observation/testcase.yaml similarity index 83% rename from tests/net/lib/lwm2m/engine/testcase.yaml rename to tests/net/lib/lwm2m/observation/testcase.yaml index b13ecef4753..cacebf227a6 100644 --- a/tests/net/lib/lwm2m/engine/testcase.yaml +++ b/tests/net/lib/lwm2m/observation/testcase.yaml @@ -1,5 +1,5 @@ tests: - net.lwm2m.engine: + net.lwm2m.observation: platform_key: - simulation tags: From bf872870eab5177e2eb2700e5ebfde8e41a0a6d1 Mon Sep 17 00:00:00 2001 From: Seppo Takalo Date: Mon, 22 Jan 2024 14:35:45 +0200 Subject: [PATCH 2683/3723] net: lwm2m: Fix segfault on failed bootstrap If bootstrap fails, RD client will call lwm2m_engine_stop() which will close the context. The socket loop, however still contains a call to hint_socket_state(context, NULL) which has a null pointer now. Fix the segfault by allowing nullpointer on hint_socket_state(). Signed-off-by: Seppo Takalo --- subsys/net/lib/lwm2m/lwm2m_engine.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/subsys/net/lib/lwm2m/lwm2m_engine.c b/subsys/net/lib/lwm2m/lwm2m_engine.c index 60ea1bdb794..bad54c521d7 100644 --- a/subsys/net/lib/lwm2m/lwm2m_engine.c +++ b/subsys/net/lib/lwm2m/lwm2m_engine.c @@ -645,7 +645,7 @@ static int64_t check_notifications(struct lwm2m_ctx *ctx, const int64_t timestam */ static void hint_socket_state(struct lwm2m_ctx *ctx, struct lwm2m_message *ongoing_tx) { - if (!ctx->set_socket_state) { + if (!ctx || !ctx->set_socket_state) { return; } From ea630294d3798249bf21068217fb308f183375dd Mon Sep 17 00:00:00 2001 From: Dawid Niedzwiecki Date: Mon, 15 Jan 2024 08:47:37 +0100 Subject: [PATCH 2684/3723] logging: add flag to skip source info Add a flag to skip printing the source info. Signed-off-by: Dawid Niedzwiecki --- include/zephyr/logging/log_output.h | 3 +++ subsys/logging/log_output.c | 4 +++- .../logging/log_output/src/log_output_test.c | 18 ++++++++++++++++++ 3 files changed, 24 insertions(+), 1 deletion(-) diff --git a/include/zephyr/logging/log_output.h b/include/zephyr/logging/log_output.h index dff4ff81dcd..e28d1015aa4 100644 --- a/include/zephyr/logging/log_output.h +++ b/include/zephyr/logging/log_output.h @@ -54,6 +54,9 @@ extern "C" { /** @brief Flag thread id or name prefix. */ #define LOG_OUTPUT_FLAG_THREAD BIT(7) +/** @brief Flag forcing to skip logging the source. */ +#define LOG_OUTPUT_FLAG_SKIP_SOURCE BIT(8) + /**@} */ /** @brief Supported backend logging format types for use diff --git a/subsys/logging/log_output.c b/subsys/logging/log_output.c index b93f3439961..519c0248ff2 100644 --- a/subsys/logging/log_output.c +++ b/subsys/logging/log_output.c @@ -452,6 +452,7 @@ static uint32_t prefix_print(const struct log_output *output, bool level_on = flags & LOG_OUTPUT_FLAG_LEVEL; bool thread_on = IS_ENABLED(CONFIG_LOG_THREAD_ID_PREFIX) && (flags & LOG_OUTPUT_FLAG_THREAD); + bool source_off = flags & LOG_OUTPUT_FLAG_SKIP_SOURCE; const char *tag = IS_ENABLED(CONFIG_LOG) ? z_log_get_tag() : NULL; if (IS_ENABLED(CONFIG_LOG_BACKEND_NET) && @@ -489,7 +490,8 @@ static uint32_t prefix_print(const struct log_output *output, color_prefix(output, colors_on, level); } - length += ids_print(output, level_on, func_on, thread_on, domain, source, tid, level); + length += ids_print(output, level_on, func_on, thread_on, domain, + source_off ? NULL : source, tid, level); return length; } diff --git a/tests/subsys/logging/log_output/src/log_output_test.c b/tests/subsys/logging/log_output/src/log_output_test.c index 1166bf815ea..e13c18f1a11 100644 --- a/tests/subsys/logging/log_output/src/log_output_test.c +++ b/tests/subsys/logging/log_output/src/log_output_test.c @@ -247,6 +247,24 @@ ZTEST(test_log_output, test_thread_id) zassert_equal(strcmp(exp_str, mock_buffer), 0); } +ZTEST(test_log_output, test_skip_src) +{ + char package[256]; + const char exp_str[] = TEST_STR "\r\n"; + uint32_t flags = LOG_OUTPUT_FLAG_SKIP_SOURCE; + int err; + + err = cbprintf_package(package, sizeof(package), 0, TEST_STR); + zassert_true(err > 0); + + reset_mock_buffer(); + log_output_process(&log_output, 0, NULL, SNAME, NULL, LOG_LEVEL_INF, + package, NULL, 0, flags); + + mock_buffer[mock_len] = '\0'; + zassert_equal(strcmp(exp_str, mock_buffer), 0); +} + static void before(void *notused) { reset_mock_buffer(); From cbdc91f7a38438838c7b138e22750710314229bb Mon Sep 17 00:00:00 2001 From: Jonathan Rico Date: Thu, 18 Jan 2024 13:02:58 +0100 Subject: [PATCH 2685/3723] MAINTAINERS: Add "Bluetooth HCI" section Split out the HCI drivers from the main Bluetooth sections. The contributors to those are usually silicon vendors. Signed-off-by: Jonathan Rico --- MAINTAINERS.yml | 23 +++++++++++++++++++++-- 1 file changed, 21 insertions(+), 2 deletions(-) diff --git a/MAINTAINERS.yml b/MAINTAINERS.yml index 31423b14400..de1c86492de 100644 --- a/MAINTAINERS.yml +++ b/MAINTAINERS.yml @@ -299,7 +299,6 @@ Bluetooth: files: - doc/connectivity/bluetooth/ - include/zephyr/bluetooth/ - - include/zephyr/drivers/bluetooth/ - samples/bluetooth/ - subsys/bluetooth/ - subsys/bluetooth/common/ @@ -328,6 +327,27 @@ Bluetooth: tests: - bluetooth +Bluetooth HCI: + status: maintained + maintainers: + - jhedberg + - jori-nordic + collaborators: + - hermabe + - alwa-nordic + - Thalley + - sjanc + - theob-pro + files: + - include/zephyr/drivers/bluetooth/ + - drivers/bluetooth/ + - samples/bluetooth/hci_*/ + labels: + - "area: Bluetooth Host" + - "area: Bluetooth" + tests: + - bluetooth + Bluetooth controller: status: maintained maintainers: @@ -362,7 +382,6 @@ Bluetooth Host: - sjanc - theob-pro files: - - drivers/bluetooth/ - subsys/bluetooth/host/ - subsys/bluetooth/services/ - subsys/bluetooth/shell/ From 52a44eb19b04cd8afd4273b2beb4e549667549d3 Mon Sep 17 00:00:00 2001 From: Jonathan Rico Date: Thu, 18 Jan 2024 13:06:22 +0100 Subject: [PATCH 2686/3723] MAINTAINERS: Add HoZHel to "Bluetooth HCI" They are actively contributing to Bluetooth HCI drivers. Signed-off-by: Jonathan Rico --- MAINTAINERS.yml | 1 + 1 file changed, 1 insertion(+) diff --git a/MAINTAINERS.yml b/MAINTAINERS.yml index de1c86492de..8dc8e215278 100644 --- a/MAINTAINERS.yml +++ b/MAINTAINERS.yml @@ -338,6 +338,7 @@ Bluetooth HCI: - Thalley - sjanc - theob-pro + - HoZHel files: - include/zephyr/drivers/bluetooth/ - drivers/bluetooth/ From 5df0cf17017a2bff859923ea25d233f5fb7c9010 Mon Sep 17 00:00:00 2001 From: Anas Nashif Date: Thu, 18 Jan 2024 07:21:29 -0500 Subject: [PATCH 2687/3723] MAINTAINERS: add wildcard for ITE drivers Include ITE drivers in ITE platforms area. Signed-off-by: Anas Nashif --- MAINTAINERS.yml | 1 + 1 file changed, 1 insertion(+) diff --git a/MAINTAINERS.yml b/MAINTAINERS.yml index 8dc8e215278..7111fc58b0f 100644 --- a/MAINTAINERS.yml +++ b/MAINTAINERS.yml @@ -3453,6 +3453,7 @@ ITE Platforms: - boards/riscv/it8*_evb/ - drivers/*/*/*it8xxx2*.c - drivers/*/*it8xxx2*.c + - drivers/*/*_ite_* - dts/bindings/*/*ite* - dts/riscv/ite/ - soc/riscv/ite_ec/ From e4b761aafb9bc69e7681807ab89c399b14268c46 Mon Sep 17 00:00:00 2001 From: Declan Snyder Date: Thu, 18 Jan 2024 08:31:09 -0600 Subject: [PATCH 2688/3723] MAINTAINERS: Create NXP Drivers group Create NXP Drivers group separate from the platforms. The idea being that currently there are two problems: - All the Drivers drivers are falling under the responsibility of the MCUX platforms' maintainers, some of whom do not have the cycles or interest to maintain these things. - The maintainers of the other platform groups do not get counted as reviewers of the Drivers drivers that their platforms use. So, separate all the driver files from the MCUX platforms, and add the relevant people who have an interest in maintaining the Drivers, including: - At least one maintainer of each platform group, and - The NXP contributors who are highly active in maintaining and reviewing the NXP drivers in upstream Zephyr. Another two problems this PR fixes: - The platforms of the other NXP groups are still falling under the MCUX group. Exclude the platforms of the other NXP groups from MCUX group. MCUX group will still be the default group for unsorted NXP platforms. - Add a few file paths to some of these groups to cover a few missed files, and add description properties of the NXP groups. Signed-off-by: Declan Snyder --- MAINTAINERS.yml | 90 +++++++++++++++++++++++++++++++++++-------------- 1 file changed, 64 insertions(+), 26 deletions(-) diff --git a/MAINTAINERS.yml b/MAINTAINERS.yml index 7111fc58b0f..b2614c33ab6 100644 --- a/MAINTAINERS.yml +++ b/MAINTAINERS.yml @@ -3214,29 +3214,42 @@ Intel Platforms (Agilex): labels: - "platform: Intel SoC FPGA Agilex" -NXP Platforms (S32): +NXP Drivers: status: maintained maintainers: - - manuargue + - dleach02 collaborators: - - PetervdPerk-NXP - - bperseghetti - - Dat-NguyenDuy + - mmahadevan108 + - danieldegrasse + - decsny + - manuargue + - dbaluta files: - - boards/arm/s32*/ - - boards/arm/mr_canhubk3/ - - boards/arm/ucans32k1sic/ - - soc/arm/nxp_s32/ - - drivers/*/*nxp_s32* - - dts/bindings/*/nxp,s32* - - samples/boards/nxp_s32/ - - include/zephyr/dt-bindings/*/nxp-s32* - - include/zephyr/dt-bindings/*/nxp_s32* - - include/zephyr/drivers/*/*nxp_s32* + - drivers/*/*imx* + - drivers/*/*lpc*.c + - drivers/*/*mcux*.c + - drivers/*/*.mcux + - drivers/*/*.nxp + - drivers/*/*nxp* + - drivers/*/*kinetis* + - drivers/misc/*/nxp* + - include/zephyr/dt-bindings/*/*nxp* + - include/zephyr/dt-bindings/*/*mcux* + - include/zephyr/drivers/*/*nxp* + - include/zephyr/drivers/*/*mcux* + - arch/arm/core/mpu/nxp_mpu.c + - dts/bindings/*/nxp* + files-exclude: + - drivers/*/*s32* + - drivers/misc/*/*s32*/ + - include/zephyr/dt-bindings/*/*s32* + - include/zephyr/drivers/*/*s32* + - dts/bindings/*/*s32* labels: - - "platform: NXP S32" + - "platform: NXP Drivers" + description: NXP Drivers -NXP Platforms: +NXP Platforms (MCUX): status: maintained maintainers: - dleach02 @@ -3249,24 +3262,48 @@ NXP Platforms: - decsny files: - boards/arm/mimx*/ - - boards/arm/frdm_k*/ + - boards/arm/frdm*/ - boards/arm/lpcxpress*/ - boards/arm/twr_*/ + - boards/arm/vmu*/ - soc/arm/nxp_imx/ - soc/arm/nxp_kinetis/ - soc/arm/nxp_lpc/ - - drivers/*/*imx* - - drivers/*/*lpc*.c - - drivers/*/*mcux*.c - - drivers/*/*.mcux - - drivers/*/*.nxp - - drivers/*/*nxp* - dts/arm/nxp/ - - dts/bindings/*/nxp* - samples/boards/nxp*/ - - include/zephyr/dt-bindings/*/nxp* + files-exclude: + - boards/arm/*s32*/ + - dts/arm/nxp/*s32* + - samples/boards/nxp_s32/ labels: - "platform: NXP" + description: NXP Platforms supported by MCUXpresso suite + +NXP Platforms (S32): + status: maintained + maintainers: + - manuargue + collaborators: + - PetervdPerk-NXP + - bperseghetti + - Dat-NguyenDuy + files: + - boards/arm/s32*/ + - boards/arm/mr_canhubk3/ + - boards/arm/ucans32k1sic/ + - boards/common/*nxp_s32* + - soc/arm/nxp_s32/ + - drivers/*/*nxp_s32* + - drivers/misc/*nxp_s32*/ + - dts/bindings/*/nxp,s32* + - dts/arm/nxp/*s32* + - samples/boards/nxp_s32/ + - include/zephyr/dt-bindings/*/nxp-s32* + - include/zephyr/dt-bindings/*/nxp_s32* + - include/zephyr/drivers/*/*nxp_s32* + labels: + - "platform: NXP S32" + description: NXP S32 platforms and S32-specific drivers NXP Platforms (Xtensa): status: maintained @@ -3279,6 +3316,7 @@ NXP Platforms (Xtensa): - boards/xtensa/nxp_adsp_*/ labels: - "platform: NXP ADSP" + description: NXP Xtensa platforms Microchip MEC Platforms: status: maintained From 6df6935b674c6a253e3e1ed2628f42821e3b90e7 Mon Sep 17 00:00:00 2001 From: Anas Nashif Date: Mon, 22 Jan 2024 12:23:29 -0500 Subject: [PATCH 2689/3723] intel_adsp: ace: do not use external kconfigs in code use CONFIG_SOC_INTEL_ACE15_MTPM instead of CONFIG_ACE_VERSION_1_5. CONFIG_ACE_VERSION_1_5 leaked from SOF. Signed-off-by: Anas Nashif --- drivers/power_domain/power_domain_intel_adsp.c | 6 +++--- soc/xtensa/intel_adsp/ace/multiprocessing.c | 8 ++++---- 2 files changed, 7 insertions(+), 7 deletions(-) diff --git a/drivers/power_domain/power_domain_intel_adsp.c b/drivers/power_domain/power_domain_intel_adsp.c index b9d52bf85ef..84820829661 100644 --- a/drivers/power_domain/power_domain_intel_adsp.c +++ b/drivers/power_domain/power_domain_intel_adsp.c @@ -9,9 +9,9 @@ #include #include -#if CONFIG_ACE_VERSION_1_5 +#if CONFIG_SOC_INTEL_ACE15_MTPM #include -#endif /* CONFIG_ACE_VERSION_1_5 */ +#endif /* CONFIG_SOC_INTEL_ACE15_MTPM */ #include LOG_MODULE_REGISTER(power_domain_intel_adsp, LOG_LEVEL_INF); @@ -35,7 +35,7 @@ static int pd_intel_adsp_set_power_enable(struct pg_bits *bits, bool power_enabl return -EIO; } } else { -#if CONFIG_ACE_VERSION_1_5 +#if CONFIG_SOC_INTEL_ACE15_MTPM extern uint32_t g_key_read_holder; if (bits->SPA_bit == INTEL_ADSP_HST_DOMAIN_BIT) { diff --git a/soc/xtensa/intel_adsp/ace/multiprocessing.c b/soc/xtensa/intel_adsp/ace/multiprocessing.c index d3a4bef4094..885294e6cad 100644 --- a/soc/xtensa/intel_adsp/ace/multiprocessing.c +++ b/soc/xtensa/intel_adsp/ace/multiprocessing.c @@ -27,10 +27,10 @@ #define ACE_INTC_IRQ DT_IRQN(DT_NODELABEL(ace_intc)) -#if CONFIG_ACE_VERSION_1_5 +#if CONFIG_SOC_INTEL_ACE15_MTPM /* .bss is uncached, we further check it below */ uint32_t g_key_read_holder; -#endif /* CONFIG_ACE_VERSION_1_5 */ +#endif /* CONFIG_SOC_INTEL_ACE15_MTPM */ static void ipc_isr(void *arg) { @@ -88,11 +88,11 @@ void soc_mp_init(void) /* Set the core 0 active */ soc_cpus_active[0] = true; -#if CONFIG_ACE_VERSION_1_5 +#if CONFIG_SOC_INTEL_ACE15_MTPM __ASSERT(!arch_xtensa_is_ptr_cached(&g_key_read_holder), "g_key_read_holder must be uncached"); g_key_read_holder = INTEL_ADSP_ACE15_MAGIC_KEY; -#endif /* CONFIG_ACE_VERSION_1_5 */ +#endif /* CONFIG_SOC_INTEL_ACE15_MTPM */ } static int host_runtime_get(void) From 00904c42676c78d275869a85dad95f202dc91eb0 Mon Sep 17 00:00:00 2001 From: Gerard Marull-Paretas Date: Tue, 16 Jan 2024 15:47:44 +0100 Subject: [PATCH 2690/3723] boards: riscv: beaglev_fire|mpfs_icicle: drop redundant options CONFIG_RISCV_SOC_INTERRUPT_INIT=y and CONFIG_RISCV_HAS_PLIC=y are both defaulted to y by the board SoC. Signed-off-by: Gerard Marull-Paretas --- boards/riscv/beaglev_fire/beaglev_fire_defconfig | 2 -- boards/riscv/mpfs_icicle/mpfs_icicle_defconfig | 2 -- 2 files changed, 4 deletions(-) diff --git a/boards/riscv/beaglev_fire/beaglev_fire_defconfig b/boards/riscv/beaglev_fire/beaglev_fire_defconfig index 3b264d6c288..eaf7d9c6f15 100644 --- a/boards/riscv/beaglev_fire/beaglev_fire_defconfig +++ b/boards/riscv/beaglev_fire/beaglev_fire_defconfig @@ -10,8 +10,6 @@ CONFIG_BOARD_BEAGLEV_FIRE=y CONFIG_CONSOLE=y CONFIG_SERIAL=y CONFIG_UART_CONSOLE=y -CONFIG_RISCV_SOC_INTERRUPT_INIT=y -CONFIG_RISCV_HAS_PLIC=y CONFIG_XIP=n CONFIG_INIT_STACKS=y CONFIG_SYS_CLOCK_TICKS_PER_SEC=1000 diff --git a/boards/riscv/mpfs_icicle/mpfs_icicle_defconfig b/boards/riscv/mpfs_icicle/mpfs_icicle_defconfig index 00b44f7a6d5..60df70677e1 100644 --- a/boards/riscv/mpfs_icicle/mpfs_icicle_defconfig +++ b/boards/riscv/mpfs_icicle/mpfs_icicle_defconfig @@ -10,8 +10,6 @@ CONFIG_BOARD_MPFS_ICICLE=y CONFIG_CONSOLE=y CONFIG_SERIAL=y CONFIG_UART_CONSOLE=y -CONFIG_RISCV_SOC_INTERRUPT_INIT=y -CONFIG_RISCV_HAS_PLIC=y CONFIG_XIP=n CONFIG_INIT_STACKS=y CONFIG_SYS_CLOCK_TICKS_PER_SEC=1000 From 2dcbb0ee3fbbc738f94c1ccea9761b42ee8b5b39 Mon Sep 17 00:00:00 2001 From: Gerard Marull-Paretas Date: Tue, 16 Jan 2024 15:55:41 +0100 Subject: [PATCH 2691/3723] soc: riscv: make RISCV_HAS_(C|P)LIC promptless These options are meant to be selected by SoC series supporting (C|P)LIC. Signed-off-by: Gerard Marull-Paretas --- soc/riscv/andes_v5/ae350/Kconfig.defconfig.series | 3 --- soc/riscv/andes_v5/ae350/Kconfig.series | 1 + soc/riscv/common/riscv-privileged/Kconfig | 4 ++-- soc/riscv/efinix_sapphire/Kconfig.defconfig | 4 ---- soc/riscv/efinix_sapphire/Kconfig.soc | 1 + soc/riscv/gd_gd32/gd32vf103/Kconfig.defconfig.gd32vf103 | 3 --- soc/riscv/litex_vexriscv/Kconfig.defconfig | 3 --- soc/riscv/microchip_miv/miv/Kconfig.defconfig.series | 3 --- soc/riscv/microchip_miv/miv/Kconfig.series | 1 + soc/riscv/microchip_miv/polarfire/Kconfig.defconfig.series | 3 --- soc/riscv/microchip_miv/polarfire/Kconfig.series | 1 + soc/riscv/opentitan/Kconfig.defconfig | 3 --- soc/riscv/opentitan/Kconfig.soc | 1 + soc/riscv/renode_virt/Kconfig.defconfig | 3 --- soc/riscv/renode_virt/Kconfig.soc | 1 + soc/riscv/sifive_freedom/e300/Kconfig.defconfig.series | 3 --- soc/riscv/sifive_freedom/e300/Kconfig.series | 1 + soc/riscv/sifive_freedom/u500/Kconfig.defconfig.series | 3 --- soc/riscv/sifive_freedom/u500/Kconfig.series | 1 + soc/riscv/sifive_freedom/u700/Kconfig.defconfig.series | 3 --- soc/riscv/sifive_freedom/u700/Kconfig.series | 1 + soc/riscv/starfive_jh71xx/jh71xx/Kconfig.defconfig.series | 3 --- soc/riscv/starfive_jh71xx/jh71xx/Kconfig.series | 1 + soc/riscv/telink_tlsr/tlsr951x/Kconfig.defconfig.series | 4 ---- soc/riscv/telink_tlsr/tlsr951x/Kconfig.series | 1 + soc/riscv/virt/Kconfig.defconfig | 3 --- soc/riscv/virt/Kconfig.soc | 1 + 27 files changed, 14 insertions(+), 46 deletions(-) diff --git a/soc/riscv/andes_v5/ae350/Kconfig.defconfig.series b/soc/riscv/andes_v5/ae350/Kconfig.defconfig.series index 699e54e66b8..7b9bbc3eadb 100644 --- a/soc/riscv/andes_v5/ae350/Kconfig.defconfig.series +++ b/soc/riscv/andes_v5/ae350/Kconfig.defconfig.series @@ -24,9 +24,6 @@ config RISCV_GENERIC_TOOLCHAIN config RISCV_SOC_INTERRUPT_INIT default y -config RISCV_HAS_PLIC - default y - config RISCV_GP default y diff --git a/soc/riscv/andes_v5/ae350/Kconfig.series b/soc/riscv/andes_v5/ae350/Kconfig.series index ebf68f7a3aa..c2e9b40bfb7 100644 --- a/soc/riscv/andes_v5/ae350/Kconfig.series +++ b/soc/riscv/andes_v5/ae350/Kconfig.series @@ -5,6 +5,7 @@ config SOC_SERIES_ANDES_AE350 bool "Andes V5 AE350 SoC Series Implementation" select RISCV select RISCV_PRIVILEGED + select RISCV_HAS_PLIC select SOC_FAMILY_ANDES_V5 help Enable support for Andes V5 AE350 SoC Series diff --git a/soc/riscv/common/riscv-privileged/Kconfig b/soc/riscv/common/riscv-privileged/Kconfig index a4a8da0bf1f..016919c4661 100644 --- a/soc/riscv/common/riscv-privileged/Kconfig +++ b/soc/riscv/common/riscv-privileged/Kconfig @@ -5,13 +5,13 @@ # SPDX-License-Identifier: Apache-2.0 config RISCV_HAS_PLIC - bool "Does the SOC provide support for a Platform Level Interrupt Controller (PLIC)" + bool depends on RISCV_PRIVILEGED help Does the SOC provide support for a Platform Level Interrupt Controller (PLIC). config RISCV_HAS_CLIC - bool "Does the SOC provide support for a Core-Local Interrupt Controller (CLIC)" + bool depends on RISCV_PRIVILEGED help Does the SOC provide support for a Core-Local Interrupt Controller (CLIC). diff --git a/soc/riscv/efinix_sapphire/Kconfig.defconfig b/soc/riscv/efinix_sapphire/Kconfig.defconfig index 08e2c851a21..95a33b4ab82 100644 --- a/soc/riscv/efinix_sapphire/Kconfig.defconfig +++ b/soc/riscv/efinix_sapphire/Kconfig.defconfig @@ -13,10 +13,6 @@ config RISCV_SOC_INTERRUPT_INIT bool default y -config RISCV_HAS_PLIC - bool - default y - config NUM_IRQS int default 36 diff --git a/soc/riscv/efinix_sapphire/Kconfig.soc b/soc/riscv/efinix_sapphire/Kconfig.soc index bf57d9cc541..4bad3b5cb79 100644 --- a/soc/riscv/efinix_sapphire/Kconfig.soc +++ b/soc/riscv/efinix_sapphire/Kconfig.soc @@ -12,3 +12,4 @@ config SOC_EFINIX_SAPPHIRE select RISCV_ISA_EXT_ZIFENCEI select RISCV select RISCV_PRIVILEGED + select RISCV_HAS_PLIC diff --git a/soc/riscv/gd_gd32/gd32vf103/Kconfig.defconfig.gd32vf103 b/soc/riscv/gd_gd32/gd32vf103/Kconfig.defconfig.gd32vf103 index 63f0799b38e..d37b27ffbf0 100644 --- a/soc/riscv/gd_gd32/gd32vf103/Kconfig.defconfig.gd32vf103 +++ b/soc/riscv/gd_gd32/gd32vf103/Kconfig.defconfig.gd32vf103 @@ -23,9 +23,6 @@ config RISCV_SOC_INTERRUPT_INIT config RISCV_GP default y -config RISCV_HAS_PLIC - default n - config NUM_IRQS default 87 if NUCLEI_ECLIC default 16 if !NUCLEI_ECLIC diff --git a/soc/riscv/litex_vexriscv/Kconfig.defconfig b/soc/riscv/litex_vexriscv/Kconfig.defconfig index f3e4c7cc79c..0088420459f 100644 --- a/soc/riscv/litex_vexriscv/Kconfig.defconfig +++ b/soc/riscv/litex_vexriscv/Kconfig.defconfig @@ -9,9 +9,6 @@ config SOC config SYS_CLOCK_HW_CYCLES_PER_SEC default 100000000 -config RISCV_HAS_PLIC - bool - config NUM_IRQS default 12 diff --git a/soc/riscv/microchip_miv/miv/Kconfig.defconfig.series b/soc/riscv/microchip_miv/miv/Kconfig.defconfig.series index fc5aaa7c186..35f4365b02b 100644 --- a/soc/riscv/microchip_miv/miv/Kconfig.defconfig.series +++ b/soc/riscv/microchip_miv/miv/Kconfig.defconfig.series @@ -11,9 +11,6 @@ config SYS_CLOCK_HW_CYCLES_PER_SEC config RISCV_SOC_INTERRUPT_INIT default y -config RISCV_HAS_PLIC - default y - config RISCV_GP default y diff --git a/soc/riscv/microchip_miv/miv/Kconfig.series b/soc/riscv/microchip_miv/miv/Kconfig.series index 2989876c0e0..9f348619624 100644 --- a/soc/riscv/microchip_miv/miv/Kconfig.series +++ b/soc/riscv/microchip_miv/miv/Kconfig.series @@ -8,5 +8,6 @@ config SOC_SERIES_MIV select SOC_FAMILY_MICROCHIP_MIV select RISCV select RISCV_PRIVILEGED + select RISCV_HAS_PLIC help Enable support for Microchip Mi-V diff --git a/soc/riscv/microchip_miv/polarfire/Kconfig.defconfig.series b/soc/riscv/microchip_miv/polarfire/Kconfig.defconfig.series index 4399972dd9d..53e88f1096e 100644 --- a/soc/riscv/microchip_miv/polarfire/Kconfig.defconfig.series +++ b/soc/riscv/microchip_miv/polarfire/Kconfig.defconfig.series @@ -14,9 +14,6 @@ config SYS_CLOCK_HW_CYCLES_PER_SEC config RISCV_SOC_INTERRUPT_INIT default y -config RISCV_HAS_PLIC - default y - config RISCV_GP default y diff --git a/soc/riscv/microchip_miv/polarfire/Kconfig.series b/soc/riscv/microchip_miv/polarfire/Kconfig.series index 9001efc2858..59ec4dbdd7a 100644 --- a/soc/riscv/microchip_miv/polarfire/Kconfig.series +++ b/soc/riscv/microchip_miv/polarfire/Kconfig.series @@ -8,5 +8,6 @@ config SOC_SERIES_POLARFIRE select SOC_FAMILY_MICROCHIP_MIV select RISCV select RISCV_PRIVILEGED + select RISCV_HAS_PLIC help Enable support for Microchip RISCV 64bit diff --git a/soc/riscv/opentitan/Kconfig.defconfig b/soc/riscv/opentitan/Kconfig.defconfig index 4ec6bffc4e7..19a72fc70bd 100644 --- a/soc/riscv/opentitan/Kconfig.defconfig +++ b/soc/riscv/opentitan/Kconfig.defconfig @@ -12,9 +12,6 @@ config SYS_CLOCK_HW_CYCLES_PER_SEC config RISCV_SOC_INTERRUPT_INIT default y -config RISCV_HAS_PLIC - default y - config RISCV_GP default y diff --git a/soc/riscv/opentitan/Kconfig.soc b/soc/riscv/opentitan/Kconfig.soc index 8270fde110d..c76cfe013b1 100644 --- a/soc/riscv/opentitan/Kconfig.soc +++ b/soc/riscv/opentitan/Kconfig.soc @@ -16,6 +16,7 @@ config SOC_OPENTITAN select RISCV_ISA_EXT_ZBS select RISCV select RISCV_PRIVILEGED + select RISCV_HAS_PLIC # OpenTitan Ibex core mtvec mode is read-only / forced to vectored mode. select RISCV_VECTORED_MODE select GEN_IRQ_VECTOR_TABLE diff --git a/soc/riscv/renode_virt/Kconfig.defconfig b/soc/riscv/renode_virt/Kconfig.defconfig index 5d2cd649b0b..fab59719595 100644 --- a/soc/riscv/renode_virt/Kconfig.defconfig +++ b/soc/riscv/renode_virt/Kconfig.defconfig @@ -12,9 +12,6 @@ config SYS_CLOCK_HW_CYCLES_PER_SEC config RISCV_SOC_INTERRUPT_INIT default y -config RISCV_HAS_PLIC - default y - config RISCV_GP default y diff --git a/soc/riscv/renode_virt/Kconfig.soc b/soc/riscv/renode_virt/Kconfig.soc index 5aae660880a..ba42c40c28d 100644 --- a/soc/riscv/renode_virt/Kconfig.soc +++ b/soc/riscv/renode_virt/Kconfig.soc @@ -13,3 +13,4 @@ config SOC_RISCV32_VIRTUAL_RENODE select RISCV_ISA_EXT_C select RISCV_ISA_EXT_ZICSR select RISCV_ISA_EXT_ZIFENCEI + select RISCV_HAS_PLIC diff --git a/soc/riscv/sifive_freedom/e300/Kconfig.defconfig.series b/soc/riscv/sifive_freedom/e300/Kconfig.defconfig.series index 661fe4ba1eb..eaa43e68e70 100644 --- a/soc/riscv/sifive_freedom/e300/Kconfig.defconfig.series +++ b/soc/riscv/sifive_freedom/e300/Kconfig.defconfig.series @@ -12,9 +12,6 @@ config SYS_CLOCK_HW_CYCLES_PER_SEC config RISCV_SOC_INTERRUPT_INIT default y -config RISCV_HAS_PLIC - default y - config RISCV_GP default y diff --git a/soc/riscv/sifive_freedom/e300/Kconfig.series b/soc/riscv/sifive_freedom/e300/Kconfig.series index 47ae89e6d4c..81634da000d 100644 --- a/soc/riscv/sifive_freedom/e300/Kconfig.series +++ b/soc/riscv/sifive_freedom/e300/Kconfig.series @@ -7,6 +7,7 @@ config SOC_SERIES_SIFIVE_FREEDOM_E300 bool "SiFive Freedom E300 SOC implementation" select RISCV select RISCV_PRIVILEGED + select RISCV_HAS_PLIC select SOC_FAMILY_SIFIVE_FREEDOM help Enable support for SiFive Freedom FE300 SOC diff --git a/soc/riscv/sifive_freedom/u500/Kconfig.defconfig.series b/soc/riscv/sifive_freedom/u500/Kconfig.defconfig.series index 3db750cb1a6..d306b60252a 100644 --- a/soc/riscv/sifive_freedom/u500/Kconfig.defconfig.series +++ b/soc/riscv/sifive_freedom/u500/Kconfig.defconfig.series @@ -12,9 +12,6 @@ config SYS_CLOCK_HW_CYCLES_PER_SEC config RISCV_SOC_INTERRUPT_INIT default y -config RISCV_HAS_PLIC - default y - config RISCV_GP default y diff --git a/soc/riscv/sifive_freedom/u500/Kconfig.series b/soc/riscv/sifive_freedom/u500/Kconfig.series index a576dfbc6f7..7335a1a5293 100644 --- a/soc/riscv/sifive_freedom/u500/Kconfig.series +++ b/soc/riscv/sifive_freedom/u500/Kconfig.series @@ -7,6 +7,7 @@ config SOC_SERIES_SIFIVE_FREEDOM_U500 bool "SiFive Freedom U500 SOC implementation" select RISCV select RISCV_PRIVILEGED + select RISCV_HAS_PLIC select SOC_FAMILY_SIFIVE_FREEDOM help Enable support for SiFive Freedom U500 SOC diff --git a/soc/riscv/sifive_freedom/u700/Kconfig.defconfig.series b/soc/riscv/sifive_freedom/u700/Kconfig.defconfig.series index 83165d58870..a0e730d608f 100644 --- a/soc/riscv/sifive_freedom/u700/Kconfig.defconfig.series +++ b/soc/riscv/sifive_freedom/u700/Kconfig.defconfig.series @@ -12,9 +12,6 @@ config SYS_CLOCK_HW_CYCLES_PER_SEC config RISCV_SOC_INTERRUPT_INIT default y -config RISCV_HAS_PLIC - default y - config RISCV_GP default y diff --git a/soc/riscv/sifive_freedom/u700/Kconfig.series b/soc/riscv/sifive_freedom/u700/Kconfig.series index 613844703c7..04bdc1fb9b2 100644 --- a/soc/riscv/sifive_freedom/u700/Kconfig.series +++ b/soc/riscv/sifive_freedom/u700/Kconfig.series @@ -7,6 +7,7 @@ config SOC_SERIES_SIFIVE_FREEDOM_U700 bool "SiFive Freedom SOC U700 implementation" select RISCV select RISCV_PRIVILEGED + select RISCV_HAS_PLIC select SOC_FAMILY_SIFIVE_FREEDOM help Enable support for SiFive Freedom U700 SOC diff --git a/soc/riscv/starfive_jh71xx/jh71xx/Kconfig.defconfig.series b/soc/riscv/starfive_jh71xx/jh71xx/Kconfig.defconfig.series index 2dc45e1f347..0f058cb6c25 100644 --- a/soc/riscv/starfive_jh71xx/jh71xx/Kconfig.defconfig.series +++ b/soc/riscv/starfive_jh71xx/jh71xx/Kconfig.defconfig.series @@ -12,9 +12,6 @@ config SYS_CLOCK_HW_CYCLES_PER_SEC config RISCV_SOC_INTERRUPT_INIT default y -config RISCV_HAS_PLIC - default y - config RISCV_GP default y diff --git a/soc/riscv/starfive_jh71xx/jh71xx/Kconfig.series b/soc/riscv/starfive_jh71xx/jh71xx/Kconfig.series index 19cedcefe27..f392a5d1f97 100644 --- a/soc/riscv/starfive_jh71xx/jh71xx/Kconfig.series +++ b/soc/riscv/starfive_jh71xx/jh71xx/Kconfig.series @@ -5,5 +5,6 @@ config SOC_SERIES_STARFIVE_JH71XX bool "Starfive JH71XX series" select RISCV select RISCV_PRIVILEGED + select RISCV_HAS_PLIC help Enable support for Starfive JH71XX SoC Series. diff --git a/soc/riscv/telink_tlsr/tlsr951x/Kconfig.defconfig.series b/soc/riscv/telink_tlsr/tlsr951x/Kconfig.defconfig.series index 5b62959858e..2b72ad9960c 100644 --- a/soc/riscv/telink_tlsr/tlsr951x/Kconfig.defconfig.series +++ b/soc/riscv/telink_tlsr/tlsr951x/Kconfig.defconfig.series @@ -15,10 +15,6 @@ config RISCV_SOC_INTERRUPT_INIT bool default y -config RISCV_HAS_PLIC - bool - default y - config RISCV_GP bool default y diff --git a/soc/riscv/telink_tlsr/tlsr951x/Kconfig.series b/soc/riscv/telink_tlsr/tlsr951x/Kconfig.series index 5ad3053725e..5d5fc3226e5 100644 --- a/soc/riscv/telink_tlsr/tlsr951x/Kconfig.series +++ b/soc/riscv/telink_tlsr/tlsr951x/Kconfig.series @@ -11,6 +11,7 @@ config SOC_SERIES_TELINK_TLSR951X select RISCV_ISA_EXT_ZICSR select RISCV_ISA_EXT_ZIFENCEI select RISCV_PRIVILEGED + select RISCV_HAS_PLIC select HAS_TELINK_DRIVERS select ATOMIC_OPERATIONS_BUILTIN select CPU_HAS_FPU diff --git a/soc/riscv/virt/Kconfig.defconfig b/soc/riscv/virt/Kconfig.defconfig index e0982bc185b..bed5ff8bec7 100644 --- a/soc/riscv/virt/Kconfig.defconfig +++ b/soc/riscv/virt/Kconfig.defconfig @@ -12,9 +12,6 @@ config SYS_CLOCK_HW_CYCLES_PER_SEC config RISCV_SOC_INTERRUPT_INIT default y -config RISCV_HAS_PLIC - default y - config RISCV_GP default y diff --git a/soc/riscv/virt/Kconfig.soc b/soc/riscv/virt/Kconfig.soc index 9a9168f5a8c..59e553a9d7b 100644 --- a/soc/riscv/virt/Kconfig.soc +++ b/soc/riscv/virt/Kconfig.soc @@ -10,3 +10,4 @@ config SOC_RISCV_VIRT select RISCV_ISA_EXT_C select RISCV select RISCV_PRIVILEGED + select RISCV_HAS_PLIC From 49e2bc69a2fc5a8cbb2873d4a35fd416a38ee84d Mon Sep 17 00:00:00 2001 From: Gerard Marull-Paretas Date: Tue, 16 Jan 2024 16:01:41 +0100 Subject: [PATCH 2692/3723] arch: riscv: add RISCV_HAS_(C|P)LIC from soc/riscv Because these are general RISC-V options, not soc specific. Signed-off-by: Gerard Marull-Paretas --- arch/riscv/Kconfig | 12 ++++++++++++ soc/riscv/common/riscv-privileged/Kconfig | 12 ------------ 2 files changed, 12 insertions(+), 12 deletions(-) diff --git a/arch/riscv/Kconfig b/arch/riscv/Kconfig index 357cce3d118..433bbe30aff 100644 --- a/arch/riscv/Kconfig +++ b/arch/riscv/Kconfig @@ -160,6 +160,18 @@ config RISCV_SOC_OFFSETS in offsets.h. The last one should not end in a semicolon. See gen_offset.h for more details. +config RISCV_HAS_PLIC + bool + depends on RISCV_PRIVILEGED + help + Does the SOC provide support for a Platform Level Interrupt Controller (PLIC). + +config RISCV_HAS_CLIC + bool + depends on RISCV_PRIVILEGED + help + Does the SOC provide support for a Core-Local Interrupt Controller (CLIC). + config RISCV_SOC_INTERRUPT_INIT bool "SOC-based interrupt initialization" help diff --git a/soc/riscv/common/riscv-privileged/Kconfig b/soc/riscv/common/riscv-privileged/Kconfig index 016919c4661..10c2e37712b 100644 --- a/soc/riscv/common/riscv-privileged/Kconfig +++ b/soc/riscv/common/riscv-privileged/Kconfig @@ -4,18 +4,6 @@ # Copyright (c) 2017 Jean-Paul Etienne # SPDX-License-Identifier: Apache-2.0 -config RISCV_HAS_PLIC - bool - depends on RISCV_PRIVILEGED - help - Does the SOC provide support for a Platform Level Interrupt Controller (PLIC). - -config RISCV_HAS_CLIC - bool - depends on RISCV_PRIVILEGED - help - Does the SOC provide support for a Core-Local Interrupt Controller (CLIC). - config RISCV_VECTORED_MODE bool "Should the SOC use vectored mode" depends on RISCV_PRIVILEGED From 68799d507da32fde0459c6abffba33182ba73f2f Mon Sep 17 00:00:00 2001 From: Gerard Marull-Paretas Date: Tue, 16 Jan 2024 16:31:26 +0100 Subject: [PATCH 2693/3723] arch: riscv: make __soc_is_irq optional It looks like all SoCs in tree check if an exception comes from an IRQ the same way, so let's provide a common logic by default, still customizable if the SoC selects RISCV_SOC_ISR_CHECK. Signed-off-by: Gerard Marull-Paretas --- arch/riscv/Kconfig | 7 ++++++ arch/riscv/core/isr.S | 13 +++++++--- include/zephyr/arch/riscv/irq.h | 6 +++-- soc/riscv/common/riscv-privileged/soc_irq.S | 27 --------------------- soc/riscv/espressif_esp32/esp32c3/soc_irq.S | 6 ----- soc/riscv/ite_ec/common/soc_irq.S | 18 -------------- soc/riscv/openisa_rv32m1/soc_irq.S | 10 -------- 7 files changed, 21 insertions(+), 66 deletions(-) diff --git a/arch/riscv/Kconfig b/arch/riscv/Kconfig index 433bbe30aff..2e55d446a75 100644 --- a/arch/riscv/Kconfig +++ b/arch/riscv/Kconfig @@ -172,6 +172,13 @@ config RISCV_HAS_CLIC help Does the SOC provide support for a Core-Local Interrupt Controller (CLIC). +config RISCV_SOC_EXCEPTION_FROM_IRQ + bool + help + Option selected by SoCs that require a custom mechanism to check if + an exception is the result of an interrupt or not. If selected, + __soc_is_irq() needs to be implemented by the SoC. + config RISCV_SOC_INTERRUPT_INIT bool "SOC-based interrupt initialization" help diff --git a/arch/riscv/core/isr.S b/arch/riscv/core/isr.S index 04e829a726e..422c2ce23bf 100644 --- a/arch/riscv/core/isr.S +++ b/arch/riscv/core/isr.S @@ -51,7 +51,9 @@ /* imports */ GDATA(_sw_isr_table) +#ifdef CONFIG_RISCV_SOC_EXCEPTION_FROM_IRQ GTEXT(__soc_is_irq) +#endif GTEXT(__soc_handle_irq) GTEXT(_Fault) #ifdef CONFIG_RISCV_SOC_CONTEXT_SAVE @@ -95,7 +97,8 @@ GTEXT(_isr_wrapper) * what standard behavior is defined). Hence, the arch level code expects * the following functions to be provided at the SOC level: * - * - __soc_is_irq: decide if we're handling an interrupt or an exception + * - __soc_is_irq (optional): decide if we're handling an interrupt or an + exception * - __soc_handle_irq: handle SoC-specific details for a pending IRQ * (e.g. clear a pending bit in a SoC-specific register) * @@ -288,10 +291,14 @@ no_fp: /* increment _current->arch.exception_depth */ * function (that needs to be implemented by each SOC). The result is * returned via register a0 (1: interrupt, 0 exception) */ +#ifdef CONFIG_RISCV_SOC_EXCEPTION_FROM_IRQ jal ra, __soc_is_irq - - /* If a0 != 0, jump to is_interrupt */ bnez a0, is_interrupt +#else + csrr t0, mcause + srli t0, t0, RISCV_MCAUSE_IRQ_POS + bnez t0, is_interrupt +#endif /* * If the exception is the result of an ECALL, check whether to diff --git a/include/zephyr/arch/riscv/irq.h b/include/zephyr/arch/riscv/irq.h index 3cf0d28523c..c3764f8289b 100644 --- a/include/zephyr/arch/riscv/irq.h +++ b/include/zephyr/arch/riscv/irq.h @@ -39,9 +39,11 @@ extern "C" { #define RISCV_IRQ_MEXT 11 #ifdef CONFIG_64BIT -#define RISCV_MCAUSE_IRQ_BIT (1 << 63) +#define RISCV_MCAUSE_IRQ_POS 63U +#define RISCV_MCAUSE_IRQ_BIT BIT64(RISCV_MCAUSE_IRQ_POS) #else -#define RISCV_MCAUSE_IRQ_BIT (1 << 31) +#define RISCV_MCAUSE_IRQ_POS 31U +#define RISCV_MCAUSE_IRQ_BIT BIT(RISCV_MCAUSE_IRQ_POS) #endif #ifndef _ASMLANGUAGE diff --git a/soc/riscv/common/riscv-privileged/soc_irq.S b/soc/riscv/common/riscv-privileged/soc_irq.S index 377edbf600d..acf7e724aea 100644 --- a/soc/riscv/common/riscv-privileged/soc_irq.S +++ b/soc/riscv/common/riscv-privileged/soc_irq.S @@ -32,30 +32,3 @@ SECTION_FUNC(exception.other, __soc_handle_irq) /* Return */ ret - -/* - * __soc_is_irq is defined as .weak to allow re-implementation by - * SOCs that do not truly follow the riscv privilege specification. - */ -WTEXT(__soc_is_irq) - -/* - * SOC-specific function to determine if the exception is the result of a - * an interrupt or an exception - * return 1 (interrupt) or 0 (exception) - * - */ -SECTION_FUNC(exception.other, __soc_is_irq) - /* Read mcause and check if interrupt bit is set */ - csrr t0, mcause - li t1, RISCV_MCAUSE_IRQ_BIT - and t0, t0, t1 - - /* If interrupt bit is not set, return with 0 */ - addi a0, x0, 0 - beqz t0, not_interrupt - addi a0, a0, 1 - -not_interrupt: - /* return */ - ret diff --git a/soc/riscv/espressif_esp32/esp32c3/soc_irq.S b/soc/riscv/espressif_esp32/esp32c3/soc_irq.S index c1ad164c153..6ce11ae6a81 100644 --- a/soc/riscv/espressif_esp32/esp32c3/soc_irq.S +++ b/soc/riscv/espressif_esp32/esp32c3/soc_irq.S @@ -7,15 +7,9 @@ #include /* Exports */ -GTEXT(__soc_is_irq) GTEXT(__soc_handle_irq) GTEXT(soc_intr_get_next_source) -SECTION_FUNC(exception.other, __soc_is_irq) - csrr a0, mcause - srli a0, a0, 31 - ret - SECTION_FUNC(exception.other, __soc_handle_irq) addi sp, sp,-4 sw ra, 0x00(sp) diff --git a/soc/riscv/ite_ec/common/soc_irq.S b/soc/riscv/ite_ec/common/soc_irq.S index a412ca6a796..ceb0f3afecb 100644 --- a/soc/riscv/ite_ec/common/soc_irq.S +++ b/soc/riscv/ite_ec/common/soc_irq.S @@ -25,21 +25,3 @@ GTEXT(__soc_handle_irq) */ SECTION_FUNC(exception.other, __soc_handle_irq) j get_irq - -/* - * __soc_is_irq is defined as .weak to allow re-implementation by - * SOCs that does not truely follow the riscv privilege specification. - */ -WTEXT(__soc_is_irq) - -/* - * SOC-specific function to determine if the exception is the result of a - * an interrupt or an exception - * return 1 (interrupt) or 0 (exception) - * - */ -SECTION_FUNC(exception.other, __soc_is_irq) - /* Read mcause and check if interrupt bit (bit 31) is set */ - csrr a0, mcause - srli a0, a0, 31 - ret diff --git a/soc/riscv/openisa_rv32m1/soc_irq.S b/soc/riscv/openisa_rv32m1/soc_irq.S index 23222ea2c70..d3059d2bd28 100644 --- a/soc/riscv/openisa_rv32m1/soc_irq.S +++ b/soc/riscv/openisa_rv32m1/soc_irq.S @@ -10,22 +10,12 @@ #include /* Exports */ -GTEXT(__soc_is_irq) GTEXT(__soc_handle_irq) #ifdef CONFIG_RISCV_SOC_CONTEXT_SAVE GTEXT(__soc_save_context) GTEXT(__soc_restore_context) #endif -/* - * Whether we're in an IRQ is bog-standard RISC-V on this SoC: - * yes if the top mcause bit is set, otherwise no. - */ -SECTION_FUNC(exception.other, __soc_is_irq) - csrr a0, mcause - srli a0, a0, 31 - ret - /* * With a0 == irq_num, this is equivalent to: * From 93a6ee501ae01bd480eda1151a681aa1f76d84d7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Anders=20Storr=C3=B8?= Date: Thu, 18 Jan 2024 14:01:37 +0100 Subject: [PATCH 2694/3723] Bluetooth: Mesh: Add artificial beacon delay MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit After removing 20ms in advertiser, all subnetwork beacons are sent as high dense packet of frames with minimal distance between them. That might cause collisions if beacon interval on devices will coincide. This commit adds an artificial delay between each subnet advertsing beacons. Signed-off-by: Anders Storrø --- subsys/bluetooth/mesh/beacon.c | 78 ++++++++++++++++----- tests/bsim/bluetooth/mesh/src/test_beacon.c | 22 +++--- 2 files changed, 76 insertions(+), 24 deletions(-) diff --git a/subsys/bluetooth/mesh/beacon.c b/subsys/bluetooth/mesh/beacon.c index 6eb2c9be3a7..cdd5862330e 100644 --- a/subsys/bluetooth/mesh/beacon.c +++ b/subsys/bluetooth/mesh/beacon.c @@ -40,6 +40,8 @@ LOG_MODULE_REGISTER(bt_mesh_beacon); #define PROV_XMIT BT_MESH_TRANSMIT(0, 20) static struct k_work_delayable beacon_timer; +static struct bt_mesh_subnet *beacon_send_sub_curr; + #if defined(CONFIG_BT_MESH_PRIV_BEACONS) static struct { /** @@ -111,13 +113,26 @@ void bt_mesh_beacon_cache_clear(struct bt_mesh_subnet *sub) #endif } +static void beacon_start(uint16_t duration, int err, void *user_data) +{ + if (err) { + LOG_ERR("Failed to send beacon: err %d", err); + if (beacon_send_sub_curr) { + k_work_reschedule(&beacon_timer, K_NO_WAIT); + } + } +} + static void beacon_complete(int err, void *user_data) { struct bt_mesh_beacon *beacon = user_data; LOG_DBG("err %d", err); - beacon->sent = k_uptime_get_32(); + + if (beacon_send_sub_curr) { + k_work_reschedule(&beacon_timer, K_MSEC(20)); + } } static int secure_beacon_create(struct bt_mesh_subnet *sub, @@ -247,11 +262,12 @@ static bool secure_beacon_is_running(void) atomic_test_bit(bt_mesh.flags, BT_MESH_IVU_INITIATOR); } -static bool net_beacon_send(struct bt_mesh_subnet *sub, struct bt_mesh_beacon *beacon, - void *cb_data, int (*beacon_create)(struct bt_mesh_subnet *sub, - struct net_buf_simple *buf)) +static int net_beacon_send(struct bt_mesh_subnet *sub, struct bt_mesh_beacon *beacon, + int (*beacon_create)(struct bt_mesh_subnet *sub, + struct net_buf_simple *buf)) { static const struct bt_mesh_send_cb send_cb = { + .start = beacon_start, .end = beacon_complete, }; uint32_t now = k_uptime_get_32(); @@ -267,14 +283,14 @@ static bool net_beacon_send(struct bt_mesh_subnet *sub, struct bt_mesh_beacon *b if (time_diff < (600 * MSEC_PER_SEC) && (time_diff < BEACON_THRESHOLD(beacon) || time_since_last_recv < (10 * MSEC_PER_SEC))) { - return false; + return -ENOMSG; } adv = bt_mesh_adv_create(BT_MESH_ADV_BEACON, BT_MESH_ADV_TAG_LOCAL, PROV_XMIT, K_NO_WAIT); if (!adv) { LOG_ERR("Unable to allocate beacon adv"); - return true; /* Bail out */ + return -ENOMEM; /* Bail out */ } err = beacon_create(sub, &adv->b); @@ -284,12 +300,12 @@ static bool net_beacon_send(struct bt_mesh_subnet *sub, struct bt_mesh_beacon *b bt_mesh_adv_unref(adv); - return err != 0; + return err; } -static bool net_beacon_for_subnet_send(struct bt_mesh_subnet *sub, void *cb_data) +static int net_beacon_for_subnet_send(struct bt_mesh_subnet *sub) { - bool res = true; + int err = -ENOMSG; struct { struct bt_mesh_beacon *beacon; @@ -315,14 +331,14 @@ static bool net_beacon_for_subnet_send(struct bt_mesh_subnet *sub, void *cb_data continue; } - res = net_beacon_send(sub, beacons[i].beacon, cb_data, beacons[i].create_fn); - if (res) { + err = net_beacon_send(sub, beacons[i].beacon, beacons[i].create_fn); + if (err < 0) { /* Bail out */ break; } } - return res; + return err; } static int unprovisioned_beacon_send(void) @@ -449,6 +465,30 @@ static bool net_beacon_is_running(void) (bt_mesh_priv_beacon_get() == BT_MESH_FEATURE_ENABLED); } +static bool beacons_send_next(void) +{ + int err; + struct bt_mesh_subnet *sub_first = bt_mesh_subnet_next(NULL); + struct bt_mesh_subnet *sub_next; + + do { + sub_next = bt_mesh_subnet_next(beacon_send_sub_curr); + if (sub_next == sub_first && beacon_send_sub_curr != NULL) { + beacon_send_sub_curr = NULL; + return false; + } + + beacon_send_sub_curr = sub_next; + err = net_beacon_for_subnet_send(beacon_send_sub_curr); + if (err < 0 && (err != -ENOMSG)) { + LOG_ERR("Failed to advertise subnet %d: err %d", + beacon_send_sub_curr->net_idx, err); + } + } while (err); + + return true; +} + static void beacon_send(struct k_work *work) { LOG_DBG(""); @@ -458,10 +498,14 @@ static void beacon_send(struct k_work *work) return; } - update_beacon_observation(); - (void)bt_mesh_subnet_find(net_beacon_for_subnet_send, NULL); + if (!beacon_send_sub_curr) { + update_beacon_observation(); + } + + if (!beacons_send_next()) { + k_work_schedule(&beacon_timer, PROVISIONED_INTERVAL); + } - k_work_schedule(&beacon_timer, PROVISIONED_INTERVAL); return; } @@ -473,7 +517,6 @@ static void beacon_send(struct k_work *work) k_work_schedule(&beacon_timer, K_SECONDS(CONFIG_BT_MESH_UNPROV_BEACON_INT)); } - } static bool auth_match(struct bt_mesh_subnet_keys *keys, @@ -757,6 +800,7 @@ void bt_mesh_beacon_ivu_initiator(bool enable) * still have to implement an early exit mechanism, so we might as well * just use this every time. */ + beacon_send_sub_curr = NULL; k_work_schedule(&beacon_timer, K_NO_WAIT); } @@ -779,11 +823,13 @@ void bt_mesh_beacon_enable(void) bt_mesh_subnet_foreach(subnet_beacon_enable); } + beacon_send_sub_curr = NULL; k_work_reschedule(&beacon_timer, K_NO_WAIT); } void bt_mesh_beacon_disable(void) { /* If this fails, we'll do an early exit in the work handler. */ + beacon_send_sub_curr = NULL; (void)k_work_cancel_delayable(&beacon_timer); } diff --git a/tests/bsim/bluetooth/mesh/src/test_beacon.c b/tests/bsim/bluetooth/mesh/src/test_beacon.c index b1d7c214dc0..e3a601e4134 100644 --- a/tests/bsim/bluetooth/mesh/src/test_beacon.c +++ b/tests/bsim/bluetooth/mesh/src/test_beacon.c @@ -483,8 +483,11 @@ static void corrupted_beacon_test(const uint8_t *offsets, } /* Now the beacon payload is valid and it shall trigger IV Update on the node. It shall also - * increase the beacon interval. + * increase the beacon interval. We delay the outgoing beacon for a couple of seconds to + * avoid near perfect syncing with the beacon interval cycle of the device we just received + * a beacon from. */ + k_sleep(K_SECONDS(3)); send_beacon(buf); /* The beacon interval shall be changed and the node shall skip transmission of the next @@ -1361,7 +1364,7 @@ static void test_tx_priv_interleave(void) struct bt_mesh_subnet *sub; - bt_mesh_test_cfg_set(NULL, BEACON_INTERVAL_WAIT_TIME); + bt_mesh_test_cfg_set(NULL, WAIT_TIME); bt_mesh_device_setup(&prov, &prb_comp); provision(&tx_cfg); @@ -1394,6 +1397,8 @@ static void test_tx_priv_interleave(void) k_sleep(K_SECONDS(BEACON_INTERVAL + 5)); toggle_priv_beacon(tx_cfg.addr, 0); + /* Small delay to let beacons complete before subnet update is applied */ + k_sleep(K_MSEC(20)); status = bt_mesh_subnet_update(BT_MESH_KEY_PRIMARY, net_key_new); ASSERT_TRUE(status == STATUS_SUCCESS); @@ -1419,7 +1424,7 @@ static void test_rx_priv_interleave(void) int err; bool same_random = false; - bt_mesh_test_cfg_set(&rx_cfg, BEACON_INTERVAL_WAIT_TIME); + bt_mesh_test_cfg_set(&rx_cfg, WAIT_TIME); bt_mesh_crypto_init(); k_sem_init(&observer_sem, 0, 1); @@ -1894,9 +1899,10 @@ static void proxy_adv_confirm_evt(struct expected_proxy_adv_evt *exp_evts, uint8 for (int i = 0; i < cnt; i++) { if (exp_evts[i].evt_cnt) { - LOG_ERR("Missing %d expected %s events in period %llums-%llums", + LOG_ERR("Missing %d expected %s idx %d events in period %llums-%llums", exp_evts[i].evt_cnt, proxy_adv_str[exp_evts[i].evt_type], - exp_evts[i].time.after, exp_evts[i].time.before); + exp_evts[i].net_idx, exp_evts[i].time.after, + exp_evts[i].time.before); missing_evts = true; } } @@ -2029,13 +2035,13 @@ static void test_rx_proxy_adv_multi_subnet_coex(void) * is advertised by this subnet, and that the two others * continues to advertise NET_ID. */ - {.evt_type = BEACON_TYPE_NET_ID, .net_idx = 0, .evt_cnt = 17, + {.evt_type = BEACON_TYPE_NET_ID, .net_idx = 0, .evt_cnt = 16, .time = {.after = PROXY_ADV_MULTI_CHECKPOINT_2, .before = PROXY_ADV_MULTI_CHECKPOINT_3}}, - {.evt_type = BEACON_TYPE_NODE_ID, .net_idx = 1, .evt_cnt = 17, + {.evt_type = BEACON_TYPE_NODE_ID, .net_idx = 1, .evt_cnt = 16, .time = {.after = PROXY_ADV_MULTI_CHECKPOINT_2, .before = PROXY_ADV_MULTI_CHECKPOINT_3}}, - {.evt_type = BEACON_TYPE_NET_ID, .net_idx = 2, .evt_cnt = 17, + {.evt_type = BEACON_TYPE_NET_ID, .net_idx = 2, .evt_cnt = 16, .time = {.after = PROXY_ADV_MULTI_CHECKPOINT_2, .before = PROXY_ADV_MULTI_CHECKPOINT_3}}, From f661aa7641ef4e9561ec9d7f654afbe7d7669f2e Mon Sep 17 00:00:00 2001 From: Przemyslaw Bida Date: Mon, 22 Jan 2024 08:39:32 +0100 Subject: [PATCH 2695/3723] net: openthread: Regular openthread upmerge to `00076af` Regular upmerge. Signed-off-by: Przemyslaw Bida --- west.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/west.yml b/west.yml index 82c84a79f70..0bd2a871b0c 100644 --- a/west.yml +++ b/west.yml @@ -301,7 +301,7 @@ manifest: revision: da78aea63159771956fe0c9263f2e6985b66e9d5 path: modules/lib/open-amp - name: openthread - revision: 4ed44bc7d58d9a98c6cca13a50d38129045ab3df + revision: 00076aff3ae571db7c90509ec9dc293457098c35 path: modules/lib/openthread - name: percepio path: modules/debug/percepio From a6184b9be3d14166c21827b3540cec6514fafe12 Mon Sep 17 00:00:00 2001 From: Przemyslaw Bida Date: Thu, 11 Jan 2024 12:25:18 +0100 Subject: [PATCH 2696/3723] net: openthread: Fix key import in case of ECDSA. According to PSA specification in case of `PSA_KEY_TYPE_ECC_KEY_PAIR` function `psa_import_key` takes private key from key pair as argument. This commit adds extraction of Private key from ECDSA key pair. Also removes not needed `otPlatCryptoEcdsaGetPublicKey`. Signed-off-by: Przemyslaw Bida --- modules/openthread/platform/crypto_psa.c | 114 +++++++++++------------ 1 file changed, 52 insertions(+), 62 deletions(-) diff --git a/modules/openthread/platform/crypto_psa.c b/modules/openthread/platform/crypto_psa.c index 55018254154..c818c5695a3 100644 --- a/modules/openthread/platform/crypto_psa.c +++ b/modules/openthread/platform/crypto_psa.c @@ -16,6 +16,7 @@ #if defined(CONFIG_OPENTHREAD_ECDSA) #include +#include #endif static otError psaToOtError(psa_status_t aStatus) @@ -62,7 +63,7 @@ static psa_algorithm_t toPsaAlgorithm(otCryptoKeyAlgorithm aAlgorithm) * There is currently no constant like PSA_ALG_NONE, but 0 is used * to indicate an unknown algorithm. */ - return (psa_algorithm_t) 0; + return (psa_algorithm_t)0; } } @@ -96,11 +97,9 @@ static psa_key_usage_t toPsaKeyUsage(int aUsage) static bool checkKeyUsage(int aUsage) { /* Check if only supported flags have been passed */ - int supported_flags = OT_CRYPTO_KEY_USAGE_EXPORT | - OT_CRYPTO_KEY_USAGE_ENCRYPT | - OT_CRYPTO_KEY_USAGE_DECRYPT | - OT_CRYPTO_KEY_USAGE_SIGN_HASH | - OT_CRYPTO_KEY_USAGE_VERIFY_HASH; + int supported_flags = OT_CRYPTO_KEY_USAGE_EXPORT | OT_CRYPTO_KEY_USAGE_ENCRYPT | + OT_CRYPTO_KEY_USAGE_DECRYPT | OT_CRYPTO_KEY_USAGE_SIGN_HASH | + OT_CRYPTO_KEY_USAGE_VERIFY_HASH; return (aUsage & ~supported_flags) == 0; } @@ -121,26 +120,57 @@ void otPlatCryptoInit(void) * PSA with emulated TFM, Settings have to be initialized at the end of otPlatCryptoInit(), * to be available before storing Network Key. */ - __ASSERT_EVAL((void) settings_subsys_init(), int err = settings_subsys_init(), - !err, "Failed to initialize settings"); + __ASSERT_EVAL((void)settings_subsys_init(), int err = settings_subsys_init(), !err, + "Failed to initialize settings"); #endif } -otError otPlatCryptoImportKey(otCryptoKeyRef *aKeyRef, - otCryptoKeyType aKeyType, - otCryptoKeyAlgorithm aKeyAlgorithm, - int aKeyUsage, - otCryptoKeyStorage aKeyPersistence, - const uint8_t *aKey, +otError otPlatCryptoImportKey(otCryptoKeyRef *aKeyRef, otCryptoKeyType aKeyType, + otCryptoKeyAlgorithm aKeyAlgorithm, int aKeyUsage, + otCryptoKeyStorage aKeyPersistence, const uint8_t *aKey, size_t aKeyLen) { +#if defined(CONFIG_OPENTHREAD_ECDSA) + int version; + size_t len; + unsigned char *p = (unsigned char *)aKey; + unsigned char *end; +#endif + psa_key_attributes_t attributes = PSA_KEY_ATTRIBUTES_INIT; - psa_status_t status; + psa_status_t status = 0; if (aKeyRef == NULL || aKey == NULL || !checkKeyUsage(aKeyUsage)) { return OT_ERROR_INVALID_ARGS; } +#if defined(CONFIG_OPENTHREAD_ECDSA) + /* Check if key is ECDSA pair and extract private key from it since PSA expects it. */ + if (aKeyType == OT_CRYPTO_KEY_TYPE_ECDSA) { + + end = p + aKeyLen; + status = mbedtls_asn1_get_tag(&p, end, &len, + MBEDTLS_ASN1_CONSTRUCTED | MBEDTLS_ASN1_SEQUENCE); + if (status != 0) { + return OT_ERROR_FAILED; + } + + end = p + len; + status = mbedtls_asn1_get_int(&p, end, &version); + if (status != 0) { + return OT_ERROR_FAILED; + } + + status = mbedtls_asn1_get_tag(&p, end, &len, MBEDTLS_ASN1_OCTET_STRING); + if (status != 0 || len != 32) { + return OT_ERROR_FAILED; + } + + aKey = p; + aKeyLen = len; + } +#endif + psa_set_key_type(&attributes, toPsaKeyType(aKeyType)); psa_set_key_algorithm(&attributes, toPsaAlgorithm(aKeyAlgorithm)); psa_set_key_usage_flags(&attributes, toPsaKeyUsage(aKeyUsage)); @@ -161,9 +191,7 @@ otError otPlatCryptoImportKey(otCryptoKeyRef *aKeyRef, return psaToOtError(status); } -otError otPlatCryptoExportKey(otCryptoKeyRef aKeyRef, - uint8_t *aBuffer, - size_t aBufferLen, +otError otPlatCryptoExportKey(otCryptoKeyRef aKeyRef, uint8_t *aBuffer, size_t aBufferLen, size_t *aKeyLen) { if (aBuffer == NULL) { @@ -231,8 +259,7 @@ otError otPlatCryptoHmacSha256Start(otCryptoContext *aContext, const otCryptoKey return psaToOtError(status); } -otError otPlatCryptoHmacSha256Update(otCryptoContext *aContext, - const void *aBuf, +otError otPlatCryptoHmacSha256Update(otCryptoContext *aContext, const void *aBuf, uint16_t aBufLength) { psa_mac_operation_t *operation; @@ -243,7 +270,7 @@ otError otPlatCryptoHmacSha256Update(otCryptoContext *aContext, operation = aContext->mContext; - return psaToOtError(psa_mac_update(operation, (const uint8_t *) aBuf, aBufLength)); + return psaToOtError(psa_mac_update(operation, (const uint8_t *)aBuf, aBufLength)); } otError otPlatCryptoHmacSha256Finish(otCryptoContext *aContext, uint8_t *aBuf, size_t aBufLength) @@ -269,7 +296,7 @@ otError otPlatCryptoAesInit(otCryptoContext *aContext) } key_ref = aContext->mContext; - *key_ref = (psa_key_id_t) 0; /* In TF-M 1.5.0 this can be replaced with PSA_KEY_ID_NULL */ + *key_ref = (psa_key_id_t)0; /* In TF-M 1.5.0 this can be replaced with PSA_KEY_ID_NULL */ return OT_ERROR_NONE; } @@ -300,13 +327,8 @@ otError otPlatCryptoAesEncrypt(otCryptoContext *aContext, const uint8_t *aInput, } key_ref = aContext->mContext; - status = psa_cipher_encrypt(*key_ref, - PSA_ALG_ECB_NO_PADDING, - aInput, - block_size, - aOutput, - block_size, - &cipher_length); + status = psa_cipher_encrypt(*key_ref, PSA_ALG_ECB_NO_PADDING, aInput, block_size, aOutput, + block_size, &cipher_length); return psaToOtError(status); } @@ -366,7 +388,7 @@ otError otPlatCryptoSha256Update(otCryptoContext *aContext, const void *aBuf, ui operation = aContext->mContext; - return psaToOtError(psa_hash_update(operation, (const uint8_t *) aBuf, aBufLength)); + return psaToOtError(psa_hash_update(operation, (const uint8_t *)aBuf, aBufLength)); } otError otPlatCryptoSha256Finish(otCryptoContext *aContext, uint8_t *aHash, uint16_t aHashSize) @@ -430,38 +452,6 @@ otError otPlatCryptoEcdsaGenerateKey(otPlatCryptoEcdsaKeyPair *aKeyPair) return psaToOtError(status); } -otError otPlatCryptoEcdsaGetPublicKey(const otPlatCryptoEcdsaKeyPair *aKeyPair, - otPlatCryptoEcdsaPublicKey *aPublicKey) -{ - psa_key_attributes_t attributes = PSA_KEY_ATTRIBUTES_INIT; - psa_key_id_t key_id = 0; - psa_status_t status; - size_t exported_length; - uint8_t buffer[1 + OT_CRYPTO_ECDSA_PUBLIC_KEY_SIZE]; - - psa_set_key_algorithm(&attributes, PSA_ALG_DETERMINISTIC_ECDSA(PSA_ALG_SHA_256)); - psa_set_key_type(&attributes, PSA_KEY_TYPE_ECC_KEY_PAIR(PSA_ECC_FAMILY_SECP_R1)); - psa_set_key_bits(&attributes, 256); - - status = psa_import_key(&attributes, aKeyPair->mDerBytes, aKeyPair->mDerLength, &key_id); - if (status != PSA_SUCCESS) { - goto out; - } - - status = psa_export_public_key(key_id, buffer, sizeof(buffer), &exported_length); - if (status != PSA_SUCCESS) { - goto out; - } - __ASSERT_NO_MSG(exported_length == sizeof(buffer)); - memcpy(aPublicKey->m8, buffer + 1, OT_CRYPTO_ECDSA_PUBLIC_KEY_SIZE); - -out: - psa_reset_key_attributes(&attributes); - psa_destroy_key(key_id); - - return psaToOtError(status); -} - otError otPlatCryptoEcdsaSign(const otPlatCryptoEcdsaKeyPair *aKeyPair, const otPlatCryptoSha256Hash *aHash, otPlatCryptoEcdsaSignature *aSignature) From a9a3b808e8893d266f5e054ada40ea3f14887b01 Mon Sep 17 00:00:00 2001 From: Sean Madigan Date: Thu, 18 Jan 2024 12:52:46 +0000 Subject: [PATCH 2697/3723] samples: bluetooth: iso_receive: Allow syncing any subevent number When using softdevice controller on iso_broadcast sample, the BIG created uses more than 1 subevent. This means that when you try to use the iso_receive sample to sync it does not work. So update the sample to use mse=0 and allow any number of subevents, making the sample more flexible and work with SDC without any changes. Signed-off-by: Sean Madigan --- samples/bluetooth/iso_receive/src/main.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/samples/bluetooth/iso_receive/src/main.c b/samples/bluetooth/iso_receive/src/main.c index a746a2f2fd0..844a7161443 100644 --- a/samples/bluetooth/iso_receive/src/main.c +++ b/samples/bluetooth/iso_receive/src/main.c @@ -277,7 +277,7 @@ static struct bt_iso_big_sync_param big_sync_param = { .bis_channels = bis, .num_bis = BIS_ISO_CHAN_COUNT, .bis_bitfield = (BIT_MASK(BIS_ISO_CHAN_COUNT) << 1), - .mse = 1, + .mse = BT_ISO_SYNC_MSE_ANY, /* any number of subevents */ .sync_timeout = 100, /* in 10 ms units */ }; From ef04b5226ee308012950d8e48a176608167f2d37 Mon Sep 17 00:00:00 2001 From: Ayush Singh Date: Fri, 19 Jan 2024 19:32:15 +0530 Subject: [PATCH 2698/3723] MAINTAINERS: Add BeagleBoard Platforms - Due to the incresing support for ZephyrRTOS in BeagleBoard boards, it would be good to have this entry. - Was discussed in Discord when asking for help for PR review Signed-off-by: Ayush Singh --- MAINTAINERS.yml | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/MAINTAINERS.yml b/MAINTAINERS.yml index b2614c33ab6..1dd2be5fa25 100644 --- a/MAINTAINERS.yml +++ b/MAINTAINERS.yml @@ -259,6 +259,20 @@ Ambiq Platforms: labels: - "platform: Ambiq" +BeagleBoard Platforms: + status: maintained + maintainers: + - jadonk + collaborators: + - ayush1325 + - con-pax + - vaishnavachath + files: + - boards/arm/beagle*/ + - boards/riscv/beagle*/ + labels: + - "platform: BeagleBoard" + Benchmarks: status: maintained maintainers: From de21b500029425466e746da3b4475cb3717cb0df Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Benjamin=20Cab=C3=A9?= Date: Fri, 19 Jan 2024 18:30:03 +0100 Subject: [PATCH 2699/3723] doc: guidelines: drop mentions of Parasoft Codescan MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Drop the section of the coding guidelines that's referring to Parasoft Codescan as it's not used by the project anymore. Signed-off-by: Benjamin Cabé --- doc/contribute/coding_guidelines/index.rst | 99 ---------------------- 1 file changed, 99 deletions(-) diff --git a/doc/contribute/coding_guidelines/index.rst b/doc/contribute/coding_guidelines/index.rst index f3bcecddfd9..69a159d9573 100644 --- a/doc/contribute/coding_guidelines/index.rst +++ b/doc/contribute/coding_guidelines/index.rst @@ -1481,102 +1481,3 @@ toolchains that come with their own C standard libraries. .. _main Zephyr repository: https://github.com/zephyrproject-rtos/zephyr .. _strnlen(): https://pubs.opengroup.org/onlinepubs/9699919799/functions/strlen.html .. _strtok_r(): https://pubs.opengroup.org/onlinepubs/9699919799/functions/strtok.html - -Parasoft Codescan Tool -********************** - -Parasoft Codescan is an official static code analysis tool used by the Zephyr -project. It is used to automate compliance with a range of coding and security -standards. -The tool is currently set to the MISRA-C:2012 Coding Standard because the Zephyr -:ref:`coding_guidelines` are based on that standard. -It is used together with the Coverity Scan tool to achieve the best code health -and precision in bug findings. - -Violations fixing process -========================= - -Step 1 - Any Zephyr Project member, company or a developer can request access - to the Parasoft reporting centre if they wish to get involved in fixing - violations by submitting issues. - -Step 2 - A developer starts to review violations. - -Step 3 - A developer submits a Github PR with the fix. Commit messages should follow - the same guidelines as other PRs in the Zephyr project. Please add a comment - that your fix was found by a static coding scanning tool. - Developers should follow and refer to the Zephyr :ref:`coding_guidelines` - as basic rules for coding. These rules are based on the MISRA-C standard. - - Below you can find an example of a recommended commit message:: - - lib: os: add braces to 'if' statements - - An 'if' (expression) construct shall be followed by a compound statement. - Add braces to improve readability and maintainability. - - Found as a coding guideline violation (Rule 15.6) by static - coding scanning tool. - - Signed-off-by: Johnny Developer - -Step 4 - If a violation is a false positive, the developer should mark it for the Codescan - tool just like they would do for the Coverity tool. - The developer should also add a comment to the code explaining that - the violation raised by the static code analysis tool should be considered a - false positive. - -Step 5 - If the developer has found a real violation that the community decided to ignore, - the developer must submit a PR with a suppression tag - and a comment explaining why the violation has been deviated. - The template structure of the comment and tag in the code should be:: - - /* Explain why that part of the code doesn't follow the standard, - * explain why it is a deliberate deviation from the standard. - * Don't refer to the Parasoft tool here, just mention that static code - * analysis tool raised a violation in the line below. - */ - code_line_with_a_violation /* parasoft-suppress Rule ID */ - - Below you can find an example of a recommended commit message:: - - testsuite: suppress usage of setjmp in a testcode (rule 21.4) - - According to the Rule 21.4 the standard header file shall not - be used. We will suppress this violation because it is in - test code. Tag suppresses reporting of the violation for the - line where the violation is located. - This is a deliberate deviation. - - Found as a coding guideline violation (Rule 21.4) by static coding - scanning tool. - - Signed-off-by: Johnny Developer - - The example below demonstrates how deviations can be suppressed in the code:: - - /* Static code analysis tool can raise a violation that the standard - * header shall not be used. - * Since this violation is in test code, we will suppress it. - * Deliberate deviation. - */ - #include /* parasoft-suppress MISRAC2012-RULE_21_4-a MISRAC2012-RULE_21_4-b */ - - This variant above suppresses item ``MISRAC2012-RULE_21_4-a`` and ``MISRAC2012-RULE_21_4-b`` - on the line with "setjump" header include. You can add as many rules to suppress you want - - just make sure to keep the Parasoft tag on one line and separate rules with a space. - To read more about suppressing findings in the Parasoft tool, refer to the - official Parasoft `documentation`_ - - .. _documentation: https://docs.parasoft.com/display/CPPTEST1031/Suppressing+Findings - -Step 6 - After a PR is submitted, the developer should add the ``Coding guidelines`` - and ``MISRA-C`` Github labels so their PR can be easily tracked by maintainers. - If you have any concerns about what your PR should look like, you can search - on Github using those tags and refer to similar PRs that have already been merged. From 7c5a57b87b6178c71b9d1f811133d4e53236d3b5 Mon Sep 17 00:00:00 2001 From: Peter Mitsis Date: Fri, 19 Jan 2024 13:45:16 -0500 Subject: [PATCH 2700/3723] tests: latency_measure: Fix MPU fault Fixes an MPU fault that was occurring on some ARM platforms when executing the events portion of the latency_measure benchmark. The fault was tracked to an attempt by a user thread to read an MMIO register that it did not have permissions to access. The solution was to move the printing of the stats averages out of the test thread and into the main thread as the main thread always executes at kernel/supervisor level and will always have permissions to read that MMIO register. Fixes #67438 Signed-off-by: Peter Mitsis --- tests/benchmarks/latency_measure/src/events.c | 254 ++++++++++-------- 1 file changed, 145 insertions(+), 109 deletions(-) diff --git a/tests/benchmarks/latency_measure/src/events.c b/tests/benchmarks/latency_measure/src/events.c index 0e80b5978c0..3cbc4350eff 100644 --- a/tests/benchmarks/latency_measure/src/events.c +++ b/tests/benchmarks/latency_measure/src/events.c @@ -28,13 +28,11 @@ static K_EVENT_DEFINE(event_set); static void event_ops_entry(void *p1, void *p2, void *p3) { uint32_t num_iterations = (uint32_t)(uintptr_t)p1; - uint32_t options = (uint32_t)(uintptr_t)p2; timing_t start; timing_t finish; uint32_t i; - uint64_t cycles; - char tag[50]; - char description[120]; + + /* 2. Benchmark k_event_post() with no waiters */ k_event_clear(&event_set, ALL_EVENTS); @@ -44,13 +42,13 @@ static void event_ops_entry(void *p1, void *p2, void *p3) } finish = timing_timestamp_get(); - snprintf(tag, sizeof(tag), "events.post.immediate.%s", - (options & K_USER) ? "user" : "kernel"); - snprintf(description, sizeof(description), - "%-40s - Post events (nothing wakes)", tag); - cycles = timing_cycles_get(&start, &finish); - PRINT_STATS_AVG(description, (uint32_t)cycles, - num_iterations, false, ""); + timestamp.cycles = timing_cycles_get(&start, &finish); + + /* 3. Pause to allow main thread to print results */ + + k_sem_take(&pause_sem, K_FOREVER); + + /* 5. Benchmark k_event_set() with no waiters */ start = timing_timestamp_get(); for (i = 0; i < num_iterations; i++) { @@ -58,13 +56,13 @@ static void event_ops_entry(void *p1, void *p2, void *p3) } finish = timing_timestamp_get(); - snprintf(tag, sizeof(tag), "events.set.immediate.%s", - (options & K_USER) ? "user" : "kernel"); - snprintf(description, sizeof(description), - "%-40s - Set events (nothing wakes)", tag); - cycles = timing_cycles_get(&start, &finish); - PRINT_STATS_AVG(description, (uint32_t)cycles, - num_iterations, false, ""); + timestamp.cycles = timing_cycles_get(&start, &finish); + + /* 6. Pause to allow main thread to print results */ + + k_sem_take(&pause_sem, K_FOREVER); + + /* 8. Benchmark k_event_wait() (events have already been set) */ start = timing_timestamp_get(); for (i = 0; i < num_iterations; i++) { @@ -72,13 +70,13 @@ static void event_ops_entry(void *p1, void *p2, void *p3) } finish = timing_timestamp_get(); - snprintf(tag, sizeof(tag), "events.wait.immediate.%s", - (options & K_USER) ? "user" : "kernel"); - snprintf(description, sizeof(description), - "%-40s - Wait for any events (no ctx switch)", tag); - cycles = timing_cycles_get(&start, &finish); - PRINT_STATS_AVG(description, (uint32_t)cycles, - num_iterations, false, ""); + timestamp.cycles = timing_cycles_get(&start, &finish); + + /* 9. Pause to allow main thread to print results */ + + k_sem_take(&pause_sem, K_FOREVER); + + /* 11. Benchmark k_event_wait_all() (events have already been set) */ start = timing_timestamp_get(); for (i = 0; i < num_iterations; i++) { @@ -86,24 +84,15 @@ static void event_ops_entry(void *p1, void *p2, void *p3) } finish = timing_timestamp_get(); - snprintf(tag, sizeof(tag), "events.wait_all.immediate.%s", - (options & K_USER) ? "user" : "kernel"); - snprintf(description, sizeof(description), - "%-40s - Wait for all events (no ctx switch)", tag); - cycles = timing_cycles_get(&start, &finish); - PRINT_STATS_AVG(description, (uint32_t)cycles, - num_iterations, false, ""); + timestamp.cycles = timing_cycles_get(&start, &finish); + + /* 12. Thread finishes */ } static void start_thread_entry(void *p1, void *p2, void *p3) { uint32_t num_iterations = (uint32_t)(uintptr_t)p1; - uint32_t options = (uint32_t)(uintptr_t)p2; - uint32_t alt_options = (uint32_t)(uintptr_t)p3; uint32_t i; - uint64_t cycles; - char tag[50]; - char description[120]; k_thread_start(&alt_thread); @@ -115,30 +104,6 @@ static void start_thread_entry(void *p1, void *p2, void *p3) k_event_set(&event_set, BENCH_EVENT_SET); } - snprintf(tag, sizeof(tag), - "events.wait.blocking.%c_to_%c", - (alt_options & K_USER) ? 'u' : 'k', - (options & K_USER) ? 'u' : 'k'); - snprintf(description, sizeof(description), - "%-40s - Wait for any events (w/ ctx switch)", tag); - cycles = timestamp.cycles - - timestamp_overhead_adjustment(options, alt_options); - PRINT_STATS_AVG(description, (uint32_t)cycles, - num_iterations, false, ""); - k_sem_give(&pause_sem); - - snprintf(tag, sizeof(tag), - "events.set.wake+ctx.%c_to_%c", - (options & K_USER) ? 'u' : 'k', - (alt_options & K_USER) ? 'u' : 'k'); - snprintf(description, sizeof(description), - "%-40s - Set events (w/ ctx switch)", tag); - cycles = timestamp.cycles - - timestamp_overhead_adjustment(options, alt_options); - PRINT_STATS_AVG(description, (uint32_t)cycles, - num_iterations, false, ""); - k_sem_give(&pause_sem); - for (i = 0; i < num_iterations; i++) { /* 5. Post the events to wake alt_thread */ @@ -147,27 +112,6 @@ static void start_thread_entry(void *p1, void *p2, void *p3) k_event_post(&event_set, BENCH_EVENT_SET); } - snprintf(tag, sizeof(tag), - "events.wait_all.blocking.%c_to_%c", - (alt_options & K_USER) ? 'u' : 'k', - (options & K_USER) ? 'u' : 'k'); - snprintf(description, sizeof(description), - "%-40s - Wait for all events (w/ ctx switch)", tag); - cycles = timestamp.cycles; - PRINT_STATS_AVG(description, (uint32_t)cycles, - num_iterations, false, ""); - k_sem_give(&pause_sem); - - snprintf(tag, sizeof(tag), - "events.post.wake+ctx.%c_to_%c", - (options & K_USER) ? 'u' : 'k', - (alt_options & K_USER) ? 'u' : 'k'); - snprintf(description, sizeof(description), - "%-40s - Post events (w/ ctx switch)", tag); - cycles = timestamp.cycles; - PRINT_STATS_AVG(description, (uint32_t)cycles, - num_iterations, false, ""); - k_thread_join(&alt_thread, K_FOREVER); } @@ -178,8 +122,7 @@ static void alt_thread_entry(void *p1, void *p2, void *p3) timing_t start; timing_t mid; timing_t finish; - uint64_t sum1 = 0ULL; - uint64_t sum2 = 0ULL; + uint64_t sum[4] = {0ULL, 0ULL, 0ULL, 0ULL}; for (i = 0; i < num_iterations; i++) { @@ -193,21 +136,10 @@ static void alt_thread_entry(void *p1, void *p2, void *p3) finish = timing_timestamp_get(); mid = timestamp.sample; - sum1 += timing_cycles_get(&start, &mid); - sum2 += timing_cycles_get(&mid, &finish); + sum[0] += timing_cycles_get(&start, &mid); + sum[1] += timing_cycles_get(&mid, &finish); } - /* Let start_thread print the results */ - - timestamp.cycles = sum1; - k_sem_take(&pause_sem, K_FOREVER); - - timestamp.cycles = sum2; - k_sem_take(&pause_sem, K_FOREVER); - - sum1 = 0ULL; - sum2 = 0ULL; - for (i = 0; i < num_iterations; i++) { /* 4. Wait for all of the events */ @@ -220,21 +152,30 @@ static void alt_thread_entry(void *p1, void *p2, void *p3) finish = timing_timestamp_get(); mid = timestamp.sample; - sum1 += timing_cycles_get(&start, &mid); - sum2 += timing_cycles_get(&mid, &finish); + sum[2] += timing_cycles_get(&start, &mid); + sum[3] += timing_cycles_get(&mid, &finish); } - /* Let start_thread print the results */ + /* Let the main thread print the results */ + + timestamp.cycles = sum[0]; + k_sem_take(&pause_sem, K_FOREVER); - timestamp.cycles = sum1; + timestamp.cycles = sum[1]; k_sem_take(&pause_sem, K_FOREVER); - timestamp.cycles = sum2; + timestamp.cycles = sum[2]; + k_sem_take(&pause_sem, K_FOREVER); + + timestamp.cycles = sum[3]; } int event_ops(uint32_t num_iterations, uint32_t options) { - int priority; + int priority; + char tag[50]; + char description[120]; + uint64_t cycles; priority = k_thread_priority_get(k_current_get()); @@ -244,13 +185,61 @@ int event_ops(uint32_t num_iterations, uint32_t options) K_THREAD_STACK_SIZEOF(start_stack), event_ops_entry, (void *)(uintptr_t)num_iterations, - (void *)(uintptr_t)options, NULL, + NULL, NULL, priority - 1, options, K_FOREVER); - k_thread_access_grant(&start_thread, &event_set); + k_thread_access_grant(&start_thread, &event_set, &pause_sem); + + /* 1. Start test thread */ k_thread_start(&start_thread); + /* 4. Benchmark thread has paused */ + + snprintf(tag, sizeof(tag), "events.post.immediate.%s", + (options & K_USER) ? "user" : "kernel"); + snprintf(description, sizeof(description), + "%-40s - Post events (nothing wakes)", tag); + + cycles = timestamp.cycles; + PRINT_STATS_AVG(description, (uint32_t)cycles, + num_iterations, false, ""); + + k_sem_give(&pause_sem); + + /* 7. Benchmark thread has paused */ + + snprintf(tag, sizeof(tag), "events.set.immediate.%s", + (options & K_USER) ? "user" : "kernel"); + snprintf(description, sizeof(description), + "%-40s - Set events (nothing wakes)", tag); + cycles = timestamp.cycles; + PRINT_STATS_AVG(description, (uint32_t)cycles, + num_iterations, false, ""); + + k_sem_give(&pause_sem); + + /* 10. Benchmark thread has paused */ + + snprintf(tag, sizeof(tag), "events.wait.immediate.%s", + (options & K_USER) ? "user" : "kernel"); + snprintf(description, sizeof(description), + "%-40s - Wait for any events (no ctx switch)", tag); + cycles = timestamp.cycles; + PRINT_STATS_AVG(description, (uint32_t)cycles, + num_iterations, false, ""); + + k_sem_give(&pause_sem); + + /* 13. Benchmark thread has finished */ + + snprintf(tag, sizeof(tag), "events.wait_all.immediate.%s", + (options & K_USER) ? "user" : "kernel"); + snprintf(description, sizeof(description), + "%-40s - Wait for all events (no ctx switch)", tag); + cycles = timestamp.cycles; + PRINT_STATS_AVG(description, (uint32_t)cycles, + num_iterations, false, ""); k_thread_join(&start_thread, K_FOREVER); timing_stop(); @@ -261,7 +250,10 @@ int event_ops(uint32_t num_iterations, uint32_t options) int event_blocking_ops(uint32_t num_iterations, uint32_t start_options, uint32_t alt_options) { - int priority; + int priority; + char tag[50]; + char description[120]; + uint64_t cycles; priority = k_thread_priority_get(k_current_get()); @@ -271,15 +263,14 @@ int event_blocking_ops(uint32_t num_iterations, uint32_t start_options, K_THREAD_STACK_SIZEOF(start_stack), start_thread_entry, (void *)(uintptr_t)num_iterations, - (void *)(uintptr_t)start_options, - (void *)(uintptr_t)alt_options, + NULL, NULL, priority - 1, start_options, K_FOREVER); k_thread_create(&alt_thread, alt_stack, K_THREAD_STACK_SIZEOF(alt_stack), alt_thread_entry, (void *)(uintptr_t)num_iterations, - (void *)(uintptr_t)alt_options, NULL, + NULL, NULL, priority - 2, alt_options, K_FOREVER); k_thread_access_grant(&start_thread, &alt_thread, &event_set, @@ -288,6 +279,51 @@ int event_blocking_ops(uint32_t num_iterations, uint32_t start_options, k_thread_start(&start_thread); + snprintf(tag, sizeof(tag), + "events.wait.blocking.%c_to_%c", + (alt_options & K_USER) ? 'u' : 'k', + (start_options & K_USER) ? 'u' : 'k'); + snprintf(description, sizeof(description), + "%-40s - Wait for any events (w/ ctx switch)", tag); + cycles = timestamp.cycles - + timestamp_overhead_adjustment(start_options, alt_options); + PRINT_STATS_AVG(description, (uint32_t)cycles, + num_iterations, false, ""); + k_sem_give(&pause_sem); + + snprintf(tag, sizeof(tag), + "events.set.wake+ctx.%c_to_%c", + (start_options & K_USER) ? 'u' : 'k', + (alt_options & K_USER) ? 'u' : 'k'); + snprintf(description, sizeof(description), + "%-40s - Set events (w/ ctx switch)", tag); + cycles = timestamp.cycles - + timestamp_overhead_adjustment(start_options, alt_options); + PRINT_STATS_AVG(description, (uint32_t)cycles, + num_iterations, false, ""); + k_sem_give(&pause_sem); + + snprintf(tag, sizeof(tag), + "events.wait_all.blocking.%c_to_%c", + (alt_options & K_USER) ? 'u' : 'k', + (start_options & K_USER) ? 'u' : 'k'); + snprintf(description, sizeof(description), + "%-40s - Wait for all events (w/ ctx switch)", tag); + cycles = timestamp.cycles; + PRINT_STATS_AVG(description, (uint32_t)cycles, + num_iterations, false, ""); + k_sem_give(&pause_sem); + + snprintf(tag, sizeof(tag), + "events.post.wake+ctx.%c_to_%c", + (start_options & K_USER) ? 'u' : 'k', + (alt_options & K_USER) ? 'u' : 'k'); + snprintf(description, sizeof(description), + "%-40s - Post events (w/ ctx switch)", tag); + cycles = timestamp.cycles; + PRINT_STATS_AVG(description, (uint32_t)cycles, + num_iterations, false, ""); + k_thread_join(&start_thread, K_FOREVER); timing_stop(); From f6373d6918455d4941865698ff0e8c66cfb5d6bd Mon Sep 17 00:00:00 2001 From: Christopher Friedt Date: Mon, 22 Jan 2024 12:15:31 -0500 Subject: [PATCH 2701/3723] samples: portability: link to posix samples POSIX API Samples live in another directory, but they should still be easy to find from Portability Samples. Signed-off-by: Christopher Friedt --- samples/subsys/portability/portability.rst | 2 ++ 1 file changed, 2 insertions(+) diff --git a/samples/subsys/portability/portability.rst b/samples/subsys/portability/portability.rst index b47ee35edc9..9034372320f 100644 --- a/samples/subsys/portability/portability.rst +++ b/samples/subsys/portability/portability.rst @@ -8,3 +8,5 @@ Portability Samples :glob: **/* + +See also :ref:`POSIX API Samples `. From 8556ae5afece5b10baadeaf01308a3f04fd366d9 Mon Sep 17 00:00:00 2001 From: Christopher Friedt Date: Mon, 22 Jan 2024 12:18:30 -0500 Subject: [PATCH 2702/3723] samples: posix: change Subsystem to API The POSIX API in Zephyr is considered more of a library than a Subsystem. Adjust the samples doc to reflect that. Signed-off-by: Christopher Friedt --- samples/posix/posix.rst | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/samples/posix/posix.rst b/samples/posix/posix.rst index c7b2e1d83a3..f7d026eb2cd 100644 --- a/samples/posix/posix.rst +++ b/samples/posix/posix.rst @@ -1,7 +1,7 @@ .. _posix-samples: -POSIX Subsystem Samples -####################### +POSIX API Samples +################# .. toctree:: :maxdepth: 1 From 89fb8f8b9887aeb47f4503fd7a09e168928f9ee2 Mon Sep 17 00:00:00 2001 From: Yong Cong Sin Date: Thu, 4 Jan 2024 00:56:37 +0800 Subject: [PATCH 2703/3723] gen_isr_tables: print index number at the end of each entry as comment Make it easier to debug by printing the index number at the end, this is especially helpful when there's a lot of interrupts. Before: ```c /* build/zephyr/isr_tables.c */ {(const void *)0x0, (ISR)((uintptr_t)&z_irq_spurious)}, {(const void *)0x0, (ISR)((uintptr_t)&z_irq_spurious)}, {(const void *)0x0, (ISR)((uintptr_t)&z_irq_spurious)}, {(const void *)0x0, (ISR)((uintptr_t)&z_irq_spurious)}, {(const void *)0x0, (ISR)((uintptr_t)&z_irq_spurious)}, {(const void *)0x0, (ISR)((uintptr_t)&z_irq_spurious)}, {(const void *)0x0, (ISR)((uintptr_t)&z_irq_spurious)}, ``` After: ```c /* build/zephyr/isr_tables.c */ {(const void *)0x0, (ISR)((uintptr_t)&z_irq_spurious)}, /* 0 */ {(const void *)0x0, (ISR)((uintptr_t)&z_irq_spurious)}, /* 1 */ {(const void *)0x0, (ISR)((uintptr_t)&z_irq_spurious)}, /* 2 */ {(const void *)0x0, (ISR)((uintptr_t)&z_irq_spurious)}, /* 3 */ {(const void *)0x0, (ISR)((uintptr_t)&z_irq_spurious)}, /* 4 */ {(const void *)0x0, (ISR)((uintptr_t)&z_irq_spurious)}, /* 5 */ {(const void *)0x0, (ISR)((uintptr_t)&z_irq_spurious)}, /* 6 */ ``` Signed-off-by: Yong Cong Sin --- scripts/build/gen_isr_tables.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/scripts/build/gen_isr_tables.py b/scripts/build/gen_isr_tables.py index 08ab9cc148c..e257074e55b 100755 --- a/scripts/build/gen_isr_tables.py +++ b/scripts/build/gen_isr_tables.py @@ -250,7 +250,7 @@ def write_source_file(fp, vt, swt, intlist, syms, shared): fp.write("\t/* Level 3 interrupts start here (offset: {}) */\n". format(level3_offset)) - fp.write("\t{{(const void *){0}, (ISR){1}}},\n".format(param, func_as_string)) + fp.write("\t{{(const void *){0}, (ISR){1}}}, /* {2} */\n".format(param, func_as_string, i)) fp.write("};\n") def get_symbols(obj): From 450a66fa3632f2f0e260cb13578798eddf6d8974 Mon Sep 17 00:00:00 2001 From: Yong Cong Sin Date: Fri, 22 Dec 2023 16:20:10 +0800 Subject: [PATCH 2704/3723] gen_defines: output the interrupt level of a node Currently it is tedious to know the level of an interrupt for a node in C. One would have to go through a very complex and error prone macros to check if there's a parent interrupt controller & if the controller has an interrupt number and thus not a pseudo interrupt controller like the one found in `rv32m1`. The level of a node is required to encode the Zephyr's multi-level interrupt number Since it is easier to do it in the `gen_defines` script, let's do the heavy lifting there so that we can introduce new DT macros to get the interrupt level very easily later. Signed-off-by: Yong Cong Sin --- doc/build/dts/macros.bnf | 1 + scripts/dts/gen_defines.py | 10 ++++++++++ 2 files changed, 11 insertions(+) diff --git a/doc/build/dts/macros.bnf b/doc/build/dts/macros.bnf index c8c99db7ef6..f42f4838877 100644 --- a/doc/build/dts/macros.bnf +++ b/doc/build/dts/macros.bnf @@ -37,6 +37,7 @@ node-macro =/ %s"DT_N" path-id %s"_REG_NAME_" dt-name %s"_VAL_" ( %s"ADDRESS" / %s"SIZE") ; The interrupts property is also special. node-macro =/ %s"DT_N" path-id %s"_IRQ_NUM" +node-macro =/ %s"DT_N" path-id %s"_IRQ_LEVEL" node-macro =/ %s"DT_N" path-id %s"_IRQ_IDX_" DIGIT "_EXISTS" node-macro =/ %s"DT_N" path-id %s"_IRQ_IDX_" DIGIT %s"_VAL_" dt-name [ %s"_EXISTS" ] diff --git a/scripts/dts/gen_defines.py b/scripts/dts/gen_defines.py index 0d84db4851f..b23a4cb76fe 100755 --- a/scripts/dts/gen_defines.py +++ b/scripts/dts/gen_defines.py @@ -484,6 +484,16 @@ def map_arm_gic_irq_type(irq, irq_num): name_controller_macro = f"{path_id}_IRQ_NAME_{str2ident(irq.name)}_CONTROLLER" name_vals.append((name_controller_macro, f"DT_{idx_controller_macro}")) + # Interrupt controller info + irqs = [] + while node.interrupts is not None and len(node.interrupts) > 0: + irq = node.interrupts[0] + irqs.append(irq) + if node == irq.controller: + break + node = irq.controller + idx_vals.append((f"{path_id}_IRQ_LEVEL", len(irqs))) + for macro, val in idx_vals: out_dt_define(macro, val) for macro, val in name_vals: From 0b43699366b916ee6ae87cb7e51bba6d08a2396a Mon Sep 17 00:00:00 2001 From: Yong Cong Sin Date: Fri, 22 Dec 2023 16:21:22 +0800 Subject: [PATCH 2705/3723] devicetree.h: add macros to get the interrupt level of a node Added new DT macros to get the interrupt level of a node. Signed-off-by: Yong Cong Sin --- include/zephyr/devicetree.h | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/include/zephyr/devicetree.h b/include/zephyr/devicetree.h index 123159e2184..0e565a80f30 100644 --- a/include/zephyr/devicetree.h +++ b/include/zephyr/devicetree.h @@ -2287,6 +2287,14 @@ */ #define DT_NUM_IRQS(node_id) DT_CAT(node_id, _IRQ_NUM) +/** + * @brief Get the interrupt level for the node + * + * @param node_id node identifier + * @return interrupt level + */ +#define DT_IRQ_LEVEL(node_id) DT_CAT(node_id, _IRQ_LEVEL) + /** * @brief Is @p idx a valid interrupt index? * @@ -3969,6 +3977,14 @@ */ #define DT_INST_REG_SIZE(inst) DT_INST_REG_SIZE_BY_IDX(inst, 0) +/** + * @brief Get a `DT_DRV_COMPAT` interrupt level + * + * @param inst instance number + * @return interrupt level + */ +#define DT_INST_IRQ_LEVEL(inst) DT_IRQ_LEVEL(DT_DRV_INST(inst)) + /** * @brief Get a `DT_DRV_COMPAT` interrupt specifier value at an index * @param inst instance number From 170c6592928a08b95ed437e7f5e527cb61004c50 Mon Sep 17 00:00:00 2001 From: Yong Cong Sin Date: Fri, 22 Dec 2023 16:27:09 +0800 Subject: [PATCH 2706/3723] tests: devicetree: api: test DT_IRQ_LEVEL and DT_INST_IRQ_LEVEL Added new test for `DT_IRQ_LEVEL` and `DT_INST_IRQ_LEVEL`. Introduced a new `vnd.cpu-intc` compatible so that we have a root level interrupt controller that acts as level 1 aggregator, and modified `test_intc` to be level 2 aggregator, updated test of `DT_IRQN(TEST_I2C_BUS)` accordingly. Signed-off-by: Yong Cong Sin --- dts/bindings/test/vnd,cpu-intc.yaml | 15 +++++++++++++++ tests/lib/devicetree/api/app.overlay | 8 ++++++++ tests/lib/devicetree/api/src/main.c | 26 +++++++++++++++++++++++++- 3 files changed, 48 insertions(+), 1 deletion(-) create mode 100644 dts/bindings/test/vnd,cpu-intc.yaml diff --git a/dts/bindings/test/vnd,cpu-intc.yaml b/dts/bindings/test/vnd,cpu-intc.yaml new file mode 100644 index 00000000000..75f3c02306c --- /dev/null +++ b/dts/bindings/test/vnd,cpu-intc.yaml @@ -0,0 +1,15 @@ +# Copyright (c) 2023 Meta +# SPDX-License-Identifier: Apache-2.0 + +description: Test CPU Interrupt Controller + +compatible: "vnd,cpu-intc" + +include: [interrupt-controller.yaml, base.yaml] + +properties: + "#interrupt-cells": + const: 1 + +interrupt-cells: + - irq diff --git a/tests/lib/devicetree/api/app.overlay b/tests/lib/devicetree/api/app.overlay index c5bcbca2092..4c72c59fa29 100644 --- a/tests/lib/devicetree/api/app.overlay +++ b/tests/lib/devicetree/api/app.overlay @@ -29,6 +29,13 @@ #size-cells = < 0x1 >; interrupt-parent = <&test_intc>; + test_cpu_intc: interrupt-controller { + compatible = "vnd,cpu-intc"; + #address-cells = <0>; + #interrupt-cells = < 0x01 >; + interrupt-controller; + }; + test_pinctrl: pin-controller { compatible = "vnd,pinctrl"; test_pincfg_a: pincfg-a {}; @@ -430,6 +437,7 @@ interrupt-controller; #interrupt-cells = <2>; interrupts = <11 0>; + interrupt-parent = <&test_cpu_intc>; }; /* there should only be one of these */ diff --git a/tests/lib/devicetree/api/src/main.c b/tests/lib/devicetree/api/src/main.c index 19e5c9e4767..8cdac64eb81 100644 --- a/tests/lib/devicetree/api/src/main.c +++ b/tests/lib/devicetree/api/src/main.c @@ -20,6 +20,7 @@ #define TEST_INST DT_INST(0, vnd_gpio_device) #define TEST_ARRAYS DT_NODELABEL(test_arrays) #define TEST_PH DT_NODELABEL(test_phandles) +#define TEST_INTC DT_NODELABEL(test_intc) #define TEST_IRQ DT_NODELABEL(test_irq) #define TEST_IRQ_EXT DT_NODELABEL(test_irq_extended) #define TEST_TEMP DT_NODELABEL(test_temp_sensor) @@ -657,10 +658,12 @@ ZTEST(devicetree_api, test_irq) zassert_equal(DT_IRQ(TEST_I2C_BUS, priority), 2, ""); /* DT_IRQN */ - zassert_equal(DT_IRQN(TEST_I2C_BUS), 6, ""); #ifndef CONFIG_MULTI_LEVEL_INTERRUPTS + zassert_equal(DT_IRQN(TEST_I2C_BUS), 6, ""); zassert_equal(DT_IRQN(DT_INST(0, DT_DRV_COMPAT)), 30, ""); #else + zassert_equal(DT_IRQN(TEST_I2C_BUS), + ((6 + 1) << CONFIG_1ST_LEVEL_INTERRUPT_BITS) | 11, ""); zassert_equal(DT_IRQN(DT_INST(0, DT_DRV_COMPAT)), ((30 + 1) << CONFIG_1ST_LEVEL_INTERRUPT_BITS) | 11, ""); #endif @@ -749,6 +752,27 @@ ZTEST(devicetree_api, test_irq) zassert_false(DT_INST_IRQ_HAS_NAME(0, alpha), ""); } +ZTEST(devicetree_api, test_irq_level) +{ + /* DT_IRQ_LEVEL */ + zassert_equal(DT_IRQ_LEVEL(TEST_TEMP), 0, ""); + zassert_equal(DT_IRQ_LEVEL(TEST_INTC), 1, ""); + zassert_equal(DT_IRQ_LEVEL(TEST_SPI), 2, ""); + + /* DT_IRQ_LEVEL */ + #undef DT_DRV_COMPAT + #define DT_DRV_COMPAT vnd_adc_temp_sensor + zassert_equal(DT_INST_IRQ_LEVEL(0), 0, ""); + + #undef DT_DRV_COMPAT + #define DT_DRV_COMPAT vnd_intc + zassert_equal(DT_INST_IRQ_LEVEL(1), 1, ""); + + #undef DT_DRV_COMPAT + #define DT_DRV_COMPAT vnd_spi + zassert_equal(DT_INST_IRQ_LEVEL(0), 2, ""); +} + struct gpios_struct { gpio_pin_t pin; gpio_flags_t flags; From 734a7db5c4e7be498e026c0e0912be593e909c46 Mon Sep 17 00:00:00 2001 From: Yong Cong Sin Date: Sat, 23 Dec 2023 12:31:14 +0800 Subject: [PATCH 2707/3723] devicetree.h: rework multilevel interrupt encoding macros Now that we have a very easy way to get the interrupt controller and the interrupt level of a node, we can simplify the multilevel interrupt encoding macros. Signed-off-by: Yong Cong Sin --- include/zephyr/devicetree.h | 52 ++++++++----------------------------- 1 file changed, 11 insertions(+), 41 deletions(-) diff --git a/include/zephyr/devicetree.h b/include/zephyr/devicetree.h index 0e565a80f30..a463aaf4fbd 100644 --- a/include/zephyr/devicetree.h +++ b/include/zephyr/devicetree.h @@ -2545,55 +2545,25 @@ * @cond INTERNAL_HIDDEN */ -/* DT helper macro to get interrupt-parent node */ -#define DT_PARENT_INTC_INTERNAL(node_id) DT_PROP(node_id, interrupt_parent) -/* DT helper macro to get the node's interrupt grandparent node */ -#define DT_GPARENT_INTC_INTERNAL(node_id) DT_PARENT_INTC_INTERNAL(DT_PARENT_INTC_INTERNAL(node_id)) -/* DT helper macro to check if a node is an interrupt controller */ -#define DT_IS_INTC_INTERNAL(node_id) DT_NODE_HAS_PROP(node_id, interrupt_controller) -/* DT helper macro to check if the node has a parent interrupt controller */ -#define DT_HAS_PARENT_INTC_INTERNAL(node_id) \ - /* node has `interrupt-parent`? */ \ - IF_ENABLED(DT_NODE_HAS_PROP(node_id, interrupt_parent), \ - /* `interrupt-parent` node is an interrupt controller? */ \ - (IF_ENABLED(DT_IS_INTC_INTERNAL(DT_PARENT_INTC_INTERNAL(node_id)), \ - /* `interrupt-parent` node has interrupt cell(s) ? 1 : 0 */ \ - (COND_CODE_0(DT_NUM_IRQS(DT_PARENT_INTC_INTERNAL(node_id)), (0), \ - (1)))))) -/* DT helper macro to check if the node has a grandparent interrupt controller */ -#define DT_HAS_GPARENT_INTC_INTERNAL(node_id) \ - IF_ENABLED(DT_HAS_PARENT_INTC_INTERNAL(node_id), \ - (DT_HAS_PARENT_INTC_INTERNAL(DT_PARENT_INTC_INTERNAL(node_id)))) - -/** - * DT helper macro to get the as-seen interrupt number in devicetree, - * or ARM GIC IRQ encoded output from `gen_defines.py` - */ -#define DT_IRQN_BY_IDX_INTERNAL(node_id, idx) DT_IRQ_BY_IDX(node_id, idx, irq) - -/* DT helper macro to get the node's parent intc's (only) irq number */ -#define DT_PARENT_INTC_IRQN_INTERNAL(node_id) DT_IRQ(DT_PARENT_INTC_INTERNAL(node_id), irq) -/* DT helper macro to get the node's grandparent intc's (only) irq number */ -#define DT_GPARENT_INTC_IRQN_INTERNAL(node_id) DT_IRQ(DT_GPARENT_INTC_INTERNAL(node_id), irq) - +/* DT helper macro to encode a node's IRQN to level 1 according to the multi-level scheme */ +#define DT_IRQN_L1_INTERNAL(node_id, idx) DT_IRQ_BY_IDX(node_id, idx, irq) /* DT helper macro to encode a node's IRQN to level 2 according to the multi-level scheme */ #define DT_IRQN_L2_INTERNAL(node_id, idx) \ - (IRQ_TO_L2(DT_IRQN_BY_IDX_INTERNAL(node_id, idx)) | \ - DT_PARENT_INTC_IRQN_INTERNAL(node_id)) + (IRQ_TO_L2(DT_IRQN_L1_INTERNAL(node_id, idx)) | DT_IRQ(DT_IRQ_INTC(node_id), irq)) /* DT helper macro to encode a node's IRQN to level 3 according to the multi-level scheme */ #define DT_IRQN_L3_INTERNAL(node_id, idx) \ - (IRQ_TO_L3(DT_IRQN_BY_IDX_INTERNAL(node_id, idx)) | \ - IRQ_TO_L2(DT_PARENT_INTC_IRQN_INTERNAL(node_id)) | \ - DT_GPARENT_INTC_IRQN_INTERNAL(node_id)) + (IRQ_TO_L3(DT_IRQN_L1_INTERNAL(node_id, idx)) | \ + IRQ_TO_L2(DT_IRQ(DT_IRQ_INTC(node_id), irq)) | \ + DT_IRQ(DT_IRQ_INTC(DT_IRQ_INTC(node_id)), irq)) +/* DT helper macro for the macros above */ +#define DT_IRQN_LVL_INTERNAL(node_id, idx, level) DT_CAT3(DT_IRQN_L, level, _INTERNAL)(node_id, idx) + /** * DT helper macro to encode a node's interrupt number according to the Zephyr's multi-level scheme * See doc/kernel/services/interrupts.rst for details */ #define DT_MULTI_LEVEL_IRQN_INTERNAL(node_id, idx) \ - COND_CODE_1(DT_HAS_GPARENT_INTC_INTERNAL(node_id), (DT_IRQN_L3_INTERNAL(node_id, idx)), \ - (COND_CODE_1(DT_HAS_PARENT_INTC_INTERNAL(node_id), \ - (DT_IRQN_L2_INTERNAL(node_id, idx)), \ - (DT_IRQN_BY_IDX_INTERNAL(node_id, idx))))) + DT_IRQN_LVL_INTERNAL(node_id, idx, DT_IRQ_LEVEL(node_id)) /** * INTERNAL_HIDDEN @endcond @@ -2610,7 +2580,7 @@ #define DT_IRQN_BY_IDX(node_id, idx) \ COND_CODE_1(IS_ENABLED(CONFIG_MULTI_LEVEL_INTERRUPTS), \ (DT_MULTI_LEVEL_IRQN_INTERNAL(node_id, idx)), \ - (DT_IRQN_BY_IDX_INTERNAL(node_id, idx))) + (DT_IRQ_BY_IDX(node_id, idx, irq))) /** * @brief Get a node's (only) irq number From 8cfff4b48fdca0bec5357721fd477fe3caa17cf3 Mon Sep 17 00:00:00 2001 From: Yong Cong Sin Date: Sun, 24 Dec 2023 01:43:49 +0800 Subject: [PATCH 2708/3723] tests: devicetree: api: align `DT_IRQN` test Not sure why the `DT_IRQN` tests are tabbed, fix that. Signed-off-by: Yong Cong Sin --- tests/lib/devicetree/api/src/main.c | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/tests/lib/devicetree/api/src/main.c b/tests/lib/devicetree/api/src/main.c index 8cdac64eb81..c9a1d668279 100644 --- a/tests/lib/devicetree/api/src/main.c +++ b/tests/lib/devicetree/api/src/main.c @@ -658,15 +658,15 @@ ZTEST(devicetree_api, test_irq) zassert_equal(DT_IRQ(TEST_I2C_BUS, priority), 2, ""); /* DT_IRQN */ - #ifndef CONFIG_MULTI_LEVEL_INTERRUPTS - zassert_equal(DT_IRQN(TEST_I2C_BUS), 6, ""); - zassert_equal(DT_IRQN(DT_INST(0, DT_DRV_COMPAT)), 30, ""); - #else - zassert_equal(DT_IRQN(TEST_I2C_BUS), - ((6 + 1) << CONFIG_1ST_LEVEL_INTERRUPT_BITS) | 11, ""); - zassert_equal(DT_IRQN(DT_INST(0, DT_DRV_COMPAT)), - ((30 + 1) << CONFIG_1ST_LEVEL_INTERRUPT_BITS) | 11, ""); - #endif +#ifndef CONFIG_MULTI_LEVEL_INTERRUPTS + zassert_equal(DT_IRQN(TEST_I2C_BUS), 6, ""); + zassert_equal(DT_IRQN(DT_INST(0, DT_DRV_COMPAT)), 30, ""); +#else + zassert_equal(DT_IRQN(TEST_I2C_BUS), + ((6 + 1) << CONFIG_1ST_LEVEL_INTERRUPT_BITS) | 11, ""); + zassert_equal(DT_IRQN(DT_INST(0, DT_DRV_COMPAT)), + ((30 + 1) << CONFIG_1ST_LEVEL_INTERRUPT_BITS) | 11, ""); +#endif /* DT_IRQN_BY_IDX */ #ifndef CONFIG_MULTI_LEVEL_INTERRUPTS From 6e51950cd8efd0559fdcc6011a499ab85017921b Mon Sep 17 00:00:00 2001 From: Vinayak Kariappa Chettimada Date: Tue, 9 Jan 2024 16:44:21 +0100 Subject: [PATCH 2709/3723] Bluetooth: Controller: Use EVENT_OVERHEAD_RESERVE_MAX in Periodic Sync Use EVENT_OVERHEAD_RESERVE_MAX conditional compile in Periodic Advertising Sync implementation. Signed-off-by: Vinayak Kariappa Chettimada --- subsys/bluetooth/controller/ll_sw/ull_sync.c | 15 +++++++++++---- 1 file changed, 11 insertions(+), 4 deletions(-) diff --git a/subsys/bluetooth/controller/ll_sw/ull_sync.c b/subsys/bluetooth/controller/ll_sw/ull_sync.c index 18ec492621c..93d0b88f72d 100644 --- a/subsys/bluetooth/controller/ll_sw/ull_sync.c +++ b/subsys/bluetooth/controller/ll_sw/ull_sync.c @@ -673,6 +673,7 @@ void ull_sync_setup(struct ll_scan_set *scan, struct ll_scan_aux_set *aux, uint32_t interval_us; struct pdu_adv *pdu; uint16_t interval; + uint32_t slot_us; uint8_t chm_last; uint32_t ret; uint8_t sca; @@ -820,16 +821,22 @@ void ull_sync_setup(struct ll_scan_set *scan, struct ll_scan_aux_set *aux, interval_us -= lll->window_widening_periodic_us; + /* Calculate event time reservation */ + slot_us = PDU_AC_MAX_US(PDU_AC_EXT_PAYLOAD_RX_SIZE, lll->phy); + slot_us += ready_delay_us; + + /* Add implementation defined radio event overheads */ + if (IS_ENABLED(CONFIG_BT_CTLR_EVENT_OVERHEAD_RESERVE_MAX)) { + slot_us += EVENT_OVERHEAD_START_US + EVENT_OVERHEAD_END_US; + } + /* TODO: active_to_start feature port */ sync->ull.ticks_active_to_start = 0U; sync->ull.ticks_prepare_to_start = HAL_TICKER_US_TO_TICKS(EVENT_OVERHEAD_XTAL_US); sync->ull.ticks_preempt_to_start = HAL_TICKER_US_TO_TICKS(EVENT_OVERHEAD_PREEMPT_MIN_US); - sync->ull.ticks_slot = HAL_TICKER_US_TO_TICKS_CEIL( - EVENT_OVERHEAD_START_US + ready_delay_us + - PDU_AC_MAX_US(PDU_AC_EXT_PAYLOAD_RX_SIZE, lll->phy) + - EVENT_OVERHEAD_END_US); + sync->ull.ticks_slot = HAL_TICKER_US_TO_TICKS_CEIL(slot_us); ticks_slot_offset = MAX(sync->ull.ticks_active_to_start, sync->ull.ticks_prepare_to_start); From 83174ef7dc4a8aadc63f2545f7e69443ffd40c18 Mon Sep 17 00:00:00 2001 From: Vinayak Kariappa Chettimada Date: Thu, 11 Jan 2024 13:03:55 +0100 Subject: [PATCH 2710/3723] Bluetooth: Controller: Fix ISO Sync Receiver sequential subevent skip Fix ISO Synchronized Receiver sequential packing subevent skip to next BIS subevent, so that radio channel is correctly calculated. Signed-off-by: Vinayak Kariappa Chettimada --- .../bluetooth/controller/ll_sw/nordic/lll/lll_sync_iso.c | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/subsys/bluetooth/controller/ll_sw/nordic/lll/lll_sync_iso.c b/subsys/bluetooth/controller/ll_sw/nordic/lll/lll_sync_iso.c index d4611425f2c..de0294fe9b5 100644 --- a/subsys/bluetooth/controller/ll_sw/nordic/lll/lll_sync_iso.c +++ b/subsys/bluetooth/controller/ll_sw/nordic/lll/lll_sync_iso.c @@ -785,7 +785,7 @@ static void isr_rx(void *param) */ if (!lll->payload[bis_idx_new][payload_index]) { /* bn = 1 Rx PDU not received */ - skipped = (bis_idx_new - bis_idx - 1U) * + skipped = (bis_idx_new - bis_idx) * ((lll->bn * lll->irc) + lll->ptc); @@ -799,8 +799,7 @@ static void isr_rx(void *param) /* bn = 1 Rx PDU already received, skip * subevent. */ - skipped = ((bis_idx_new - bis_idx - - 1U) * + skipped = ((bis_idx_new - bis_idx) * ((lll->bn * lll->irc) + lll->ptc)) + 1U; @@ -895,7 +894,7 @@ static void isr_rx(void *param) &lll->data_chan_prn_s, &lll->data_chan_remap_idx); - skipped -= (bis_idx_new - bis_idx - 1U) * + skipped -= (bis_idx_new - bis_idx) * ((lll->bn * lll->irc) + lll->ptc); } From 4a51f68bcc91429792608a3f4a693b87881a3947 Mon Sep 17 00:00:00 2001 From: Vinayak Kariappa Chettimada Date: Thu, 11 Jan 2024 13:53:08 +0100 Subject: [PATCH 2711/3723] Bluetooth: Controller: Fix ISO Sync Receiver subevent Rx window Fix ISO Synchronized Receiver subevent Rx window timing and PDU address receive timeout to consider the +/- 2us active clock jitter. Signed-off-by: Vinayak Kariappa Chettimada --- .../controller/ll_sw/nordic/lll/lll_sync_iso.c | 11 +++++------ 1 file changed, 5 insertions(+), 6 deletions(-) diff --git a/subsys/bluetooth/controller/ll_sw/nordic/lll/lll_sync_iso.c b/subsys/bluetooth/controller/ll_sw/nordic/lll/lll_sync_iso.c index de0294fe9b5..8ac45f9a84f 100644 --- a/subsys/bluetooth/controller/ll_sw/nordic/lll/lll_sync_iso.c +++ b/subsys/bluetooth/controller/ll_sw/nordic/lll/lll_sync_iso.c @@ -987,7 +987,7 @@ static void isr_rx(void *param) hcto -= radio_rx_chain_delay_get(lll->phy, PHY_FLAGS_S8); hcto -= addr_us_get(lll->phy); hcto -= radio_rx_ready_delay_get(lll->phy, PHY_FLAGS_S8); - hcto -= (EVENT_CLOCK_JITTER_US << 1); + hcto -= (EVENT_CLOCK_JITTER_US << 1) * nse; start_us = hcto; hcto = radio_tmr_start_us(0U, start_us); @@ -996,12 +996,11 @@ static void isr_rx(void *param) */ /* LL_ASSERT(hcto == (start_us + 1U)); */ - /* Add 4 us + 4 us + (4 us * subevents so far), as radio - * was setup to listen 4 us early and subevents could have - * a 4 us drift each until the current subevent we are - * listening. + /* Add 8 us * subevents so far, as radio was setup to listen + * 4 us early and subevents could have a 4 us drift each until + * the current subevent we are listening. */ - hcto += ((EVENT_CLOCK_JITTER_US << 1) * (2U + nse)) + + hcto += (((EVENT_CLOCK_JITTER_US << 1) * nse) << 1) + RANGE_DELAY_US + HCTO_START_DELAY_US; } else { /* First subevent PDU was not received, hence setup radio packet From 585d98e0d87bab48d886806d15bf393ea73eb81d Mon Sep 17 00:00:00 2001 From: Vinayak Kariappa Chettimada Date: Mon, 15 Jan 2024 10:17:29 +0100 Subject: [PATCH 2712/3723] Bluetooth: Controller: Fix prepare overhead in scheduling ISO Fix double prepare overhead considered in scheduling extended, periodic and ISO broadcast radio events when using LOW LAT variant. ticks_slot maintained in ticker includes the overhead, the ticks_slot stored in role/state context exclude the overhead hence take care to include ticks_slot_overhead when value is used from context and not when value used from ticker nodes. Add jitter due to ticker resolution unit between scheduled radio events. This will allow the synchronizing side too to not overlap due to ticker resolution related jitter. Signed-off-by: Vinayak Kariappa Chettimada --- subsys/bluetooth/controller/ll_sw/ull_sched.c | 41 +++++-------------- 1 file changed, 11 insertions(+), 30 deletions(-) diff --git a/subsys/bluetooth/controller/ll_sw/ull_sched.c b/subsys/bluetooth/controller/ll_sw/ull_sched.c index 4eb7687b97d..980a4b7a221 100644 --- a/subsys/bluetooth/controller/ll_sw/ull_sched.c +++ b/subsys/bluetooth/controller/ll_sw/ull_sched.c @@ -324,15 +324,16 @@ static int group_free_slot_get(uint8_t user_id, uint32_t ticks_slot_abs, #if defined(CONFIG_BT_BROADCASTER) && CONFIG_BT_CTLR_ADV_AUX_SET > 0 } else if (IN_RANGE(ticker_id, TICKER_ID_ADV_AUX_BASE, TICKER_ID_ADV_AUX_LAST)) { - const struct ll_adv_aux_set *aux; - *ticks_anchor += ticks_to_expire; *ticks_anchor += ticks_slot; + *ticks_anchor += HAL_TICKER_US_TO_TICKS( + EVENT_TICKER_RES_MARGIN_US << 1); + +#if defined(CONFIG_BT_CTLR_ADV_PERIODIC) + const struct ll_adv_aux_set *aux; aux = ull_adv_aux_get(ticker_id - TICKER_ID_ADV_AUX_BASE); - -#if defined(CONFIG_BT_CTLR_ADV_PERIODIC) if (aux->lll.adv->sync) { const struct ll_adv_sync_set *sync; @@ -345,12 +346,6 @@ static int group_free_slot_get(uint8_t user_id, uint32_t ticks_slot_abs, } #endif /* CONFIG_BT_CTLR_ADV_PERIODIC */ - if (IS_ENABLED(CONFIG_BT_CTLR_LOW_LAT)) { - *ticks_anchor += - MAX(aux->ull.ticks_active_to_start, - aux->ull.ticks_prepare_to_start); - } - return 0; #if defined(CONFIG_BT_CTLR_ADV_PERIODIC) @@ -358,16 +353,8 @@ static int group_free_slot_get(uint8_t user_id, uint32_t ticks_slot_abs, TICKER_ID_ADV_SYNC_LAST)) { *ticks_anchor += ticks_to_expire; *ticks_anchor += ticks_slot; - - if (IS_ENABLED(CONFIG_BT_CTLR_LOW_LAT)) { - const struct ll_adv_sync_set *sync; - - sync = ull_adv_sync_get(ticker_id - - TICKER_ID_ADV_SYNC_BASE); - *ticks_anchor += - MAX(sync->ull.ticks_active_to_start, - sync->ull.ticks_prepare_to_start); - } + *ticks_anchor += HAL_TICKER_US_TO_TICKS( + EVENT_TICKER_RES_MARGIN_US << 1); return 0; @@ -376,16 +363,8 @@ static int group_free_slot_get(uint8_t user_id, uint32_t ticks_slot_abs, TICKER_ID_ADV_ISO_LAST)) { *ticks_anchor += ticks_to_expire; *ticks_anchor += ticks_slot; - - if (IS_ENABLED(CONFIG_BT_CTLR_LOW_LAT)) { - const struct ll_adv_iso_set *iso; - - iso = ull_adv_iso_get(ticker_id - - TICKER_ID_ADV_ISO_BASE); - *ticks_anchor += - MAX(iso->ull.ticks_active_to_start, - iso->ull.ticks_prepare_to_start); - } + *ticks_anchor += HAL_TICKER_US_TO_TICKS( + EVENT_TICKER_RES_MARGIN_US << 1); return 0; @@ -398,6 +377,8 @@ static int group_free_slot_get(uint8_t user_id, uint32_t ticks_slot_abs, TICKER_ID_CONN_LAST)) { *ticks_anchor += ticks_to_expire; *ticks_anchor += ticks_slot; + *ticks_anchor += HAL_TICKER_US_TO_TICKS( + EVENT_TICKER_RES_MARGIN_US << 1); return 0; #endif /* CONFIG_BT_CONN */ From 3e234966dc46e41b1fa55a9a0e92589a6a9e7fdc Mon Sep 17 00:00:00 2001 From: Grzegorz Chwierut Date: Wed, 17 Jan 2024 16:18:52 +0100 Subject: [PATCH 2713/3723] twister: pytest: Update MCUmgr helper method Update helper method used by pytest fixtures. Extended upload method with 'slot' parameter. Added searching of uploaded images that can be tested or confirmed. Signed-off-by: Grzegorz Chwierut --- .../src/twister_harness/helpers/mcumgr.py | 27 +++++++++++++------ 1 file changed, 19 insertions(+), 8 deletions(-) diff --git a/scripts/pylib/pytest-twister-harness/src/twister_harness/helpers/mcumgr.py b/scripts/pylib/pytest-twister-harness/src/twister_harness/helpers/mcumgr.py index b6cab6475c1..c1cb109524e 100755 --- a/scripts/pylib/pytest-twister-harness/src/twister_harness/helpers/mcumgr.py +++ b/scripts/pylib/pytest-twister-harness/src/twister_harness/helpers/mcumgr.py @@ -54,8 +54,11 @@ def run_command(self, cmd: str) -> str: def reset_device(self): self.run_command('reset') - def image_upload(self, image: Path | str, timeout: int = 30): - self.run_command(f'-t {timeout} image upload {image}') + def image_upload(self, image: Path | str, slot: int | None = None, timeout: int = 30): + command = f'-t {timeout} image upload {image}' + if slot: + command += f' -e -n {slot}' + self.run_command(command) logger.info('Image successfully uploaded') def get_image_list(self) -> list[MCUmgrImage]: @@ -88,10 +91,19 @@ def _parse_image_list(cmd_output: str) -> list[MCUmgrImage]: def get_hash_to_test(self) -> str: image_list = self.get_image_list() - if len(image_list) < 2: - logger.info(image_list) - raise MCUmgrException('Please check image list returned by mcumgr') - return image_list[1].hash + for image in image_list: + if 'active' not in image.flags: + return image.hash + logger.warning(f'Images returned by mcumgr (no not active):\n{image_list}') + raise MCUmgrException('No not active image found') + + def get_hash_to_confirm(self): + image_list = self.mcumgr.get_image_list() + for image in image_list: + if 'confirmed' not in image.flags: + return image.hash + logger.warning(f'Images returned by mcumgr (no not confirmed):\n{image_list}') + raise MCUmgrException('No not confirmed image found') def image_test(self, hash: str | None = None): if not hash: @@ -100,6 +112,5 @@ def image_test(self, hash: str | None = None): def image_confirm(self, hash: str | None = None): if not hash: - image_list = self.get_image_list() - hash = image_list[0].hash + hash = self.get_hash_to_confirm() self.run_command(f'image confirm {hash}') From 91ee5c4db2be459682f81c738252b9e2f1ca7168 Mon Sep 17 00:00:00 2001 From: Fabio Baltieri Date: Fri, 17 Nov 2023 12:09:44 +0000 Subject: [PATCH 2714/3723] input: gpio_qdec: rename gpio to ab_gpio Rename gpio to ab_gpio, this is in preparation for adding another gpio pointer. Signed-off-by: Fabio Baltieri --- drivers/input/input_gpio_qdec.c | 18 ++++++++++-------- 1 file changed, 10 insertions(+), 8 deletions(-) diff --git a/drivers/input/input_gpio_qdec.c b/drivers/input/input_gpio_qdec.c index fe02ad6ff83..363ca4199f7 100644 --- a/drivers/input/input_gpio_qdec.c +++ b/drivers/input/input_gpio_qdec.c @@ -20,7 +20,7 @@ LOG_MODULE_REGISTER(input_gpio_qdec, CONFIG_INPUT_LOG_LEVEL); #define GPIO_QDEC_GPIO_NUM 2 struct gpio_qdec_config { - struct gpio_dt_spec gpio[GPIO_QDEC_GPIO_NUM]; + struct gpio_dt_spec ab_gpio[GPIO_QDEC_GPIO_NUM]; uint32_t sample_time_us; uint32_t idle_timeout_ms; uint16_t axis; @@ -54,10 +54,10 @@ static uint8_t gpio_qdec_get_step(const struct device *dev) const struct gpio_qdec_config *cfg = dev->config; uint8_t step = 0x00; - if (gpio_pin_get_dt(&cfg->gpio[0])) { + if (gpio_pin_get_dt(&cfg->ab_gpio[0])) { step |= 0x01; } - if (gpio_pin_get_dt(&cfg->gpio[1])) { + if (gpio_pin_get_dt(&cfg->ab_gpio[1])) { step |= 0x02; } @@ -135,7 +135,7 @@ static void gpio_qdec_irq_setup(const struct device *dev, bool enable) int ret; for (int i = 0; i < GPIO_QDEC_GPIO_NUM; i++) { - const struct gpio_dt_spec *gpio = &cfg->gpio[i]; + const struct gpio_dt_spec *gpio = &cfg->ab_gpio[i]; ret = gpio_pin_interrupt_configure_dt(gpio, flags); if (ret != 0) { @@ -190,9 +190,9 @@ static int gpio_qdec_init(const struct device *dev) k_timer_user_data_set(&data->sample_timer, (void *)dev); gpio_init_callback(&data->gpio_cb, gpio_qdec_cb, - BIT(cfg->gpio[0].pin) | BIT(cfg->gpio[1].pin)); + BIT(cfg->ab_gpio[0].pin) | BIT(cfg->ab_gpio[1].pin)); for (int i = 0; i < GPIO_QDEC_GPIO_NUM; i++) { - const struct gpio_dt_spec *gpio = &cfg->gpio[i]; + const struct gpio_dt_spec *gpio = &cfg->ab_gpio[i]; if (!gpio_is_ready_dt(gpio)) { LOG_ERR("%s is not ready", gpio->port->name); @@ -226,8 +226,10 @@ static int gpio_qdec_init(const struct device *dev) "input_gpio_qdec: gpios must have exactly two entries"); \ \ static const struct gpio_qdec_config gpio_qdec_cfg_##n = { \ - .gpio = {GPIO_DT_SPEC_INST_GET_BY_IDX(n, gpios, 0), \ - GPIO_DT_SPEC_INST_GET_BY_IDX(n, gpios, 1)}, \ + .ab_gpio = { \ + GPIO_DT_SPEC_INST_GET_BY_IDX(n, gpios, 0), \ + GPIO_DT_SPEC_INST_GET_BY_IDX(n, gpios, 1), \ + }, \ .sample_time_us = DT_INST_PROP(n, sample_time_us), \ .idle_timeout_ms = DT_INST_PROP(n, idle_timeout_ms), \ .steps_per_period = DT_INST_PROP(n, steps_per_period), \ From 1dd2307b3f1696a9711134d1e8b34608c324cb9f Mon Sep 17 00:00:00 2001 From: Fabio Baltieri Date: Fri, 1 Dec 2023 21:41:52 +0000 Subject: [PATCH 2715/3723] input: gpio_qdec: add optical encoder support Change the gpio_qdec driver to support optical encoders. Add a property to use for defining an arbitrary number of GPIOs for the sensing devices (typically infrared LEDs, but could also be the biasing for the phototransistor), and one for adding a delay between turning those on and reading the pin status. The infrared LEDs typically consume a non negligible amount of power, so there's also a new idle-poll-time-us property that enables two possible modes of operation: - if idle-poll-time-us is zero (default) the LEDs are enabled all the time and the driver enters polling mode using the GPIO interrupt as with mechanical encoders. This is usable for mains powered devices and has the lowest overhead on the CPU. - if idle-poll-time-us is non zero, then the driver polls the encoder all the time, turning on the LEDs just before reading the state and shutting them off immediately after, but when the encoder is idle it switches the polling rate to idle-poll-time-us to save power, and only polls at sample-time-us when some movement is detected. Signed-off-by: Fabio Baltieri --- drivers/input/input_gpio_qdec.c | 164 ++++++++++++++++++---- dts/bindings/input/gpio-qdec.yaml | 22 +++ tests/drivers/build_all/input/app.overlay | 12 ++ 3 files changed, 168 insertions(+), 30 deletions(-) diff --git a/drivers/input/input_gpio_qdec.c b/drivers/input/input_gpio_qdec.c index 363ca4199f7..66066d32acc 100644 --- a/drivers/input/input_gpio_qdec.c +++ b/drivers/input/input_gpio_qdec.c @@ -13,6 +13,8 @@ #include #include #include +#include +#include #include LOG_MODULE_REGISTER(input_gpio_qdec, CONFIG_INPUT_LOG_LEVEL); @@ -21,7 +23,11 @@ LOG_MODULE_REGISTER(input_gpio_qdec, CONFIG_INPUT_LOG_LEVEL); struct gpio_qdec_config { struct gpio_dt_spec ab_gpio[GPIO_QDEC_GPIO_NUM]; + const struct gpio_dt_spec *led_gpio; + uint8_t led_gpio_count; + uint32_t led_pre_us; uint32_t sample_time_us; + uint32_t idle_poll_time_us; uint32_t idle_timeout_ms; uint16_t axis; uint8_t steps_per_period; @@ -35,6 +41,7 @@ struct gpio_qdec_data { struct k_work event_work; struct k_work_delayable idle_work; struct gpio_callback gpio_cb; + atomic_t polling; }; /* Positive transitions */ @@ -49,11 +56,82 @@ struct gpio_qdec_data { #define QDEC_HH_LH 0x31 #define QDEC_HL_HH 0x23 +static void gpio_qdec_irq_setup(const struct device *dev, bool enable) +{ + const struct gpio_qdec_config *cfg = dev->config; + gpio_flags_t flags = enable ? GPIO_INT_EDGE_BOTH : GPIO_INT_DISABLE; + int ret; + + for (int i = 0; i < GPIO_QDEC_GPIO_NUM; i++) { + const struct gpio_dt_spec *gpio = &cfg->ab_gpio[i]; + + ret = gpio_pin_interrupt_configure_dt(gpio, flags); + if (ret != 0) { + LOG_ERR("Pin %d interrupt configuration failed: %d", i, ret); + return; + } + } +} + +static bool gpio_qdec_idle_polling_mode(const struct device *dev) +{ + const struct gpio_qdec_config *cfg = dev->config; + + if (cfg->idle_poll_time_us > 0) { + return true; + } + + return false; +} + +static void gpio_qdec_poll_mode(const struct device *dev) +{ + const struct gpio_qdec_config *cfg = dev->config; + struct gpio_qdec_data *data = dev->data; + + if (!gpio_qdec_idle_polling_mode(dev)) { + gpio_qdec_irq_setup(dev, false); + } + + k_timer_start(&data->sample_timer, K_NO_WAIT, + K_USEC(cfg->sample_time_us)); + + atomic_set(&data->polling, 1); + + LOG_DBG("polling start"); +} + +static void gpio_qdec_idle_mode(const struct device *dev) +{ + const struct gpio_qdec_config *cfg = dev->config; + struct gpio_qdec_data *data = dev->data; + + if (gpio_qdec_idle_polling_mode(dev)) { + k_timer_start(&data->sample_timer, K_NO_WAIT, + K_USEC(cfg->idle_poll_time_us)); + } else { + k_timer_stop(&data->sample_timer); + gpio_qdec_irq_setup(dev, true); + } + + atomic_set(&data->polling, 0); + + LOG_DBG("polling stop"); +} + static uint8_t gpio_qdec_get_step(const struct device *dev) { const struct gpio_qdec_config *cfg = dev->config; uint8_t step = 0x00; + if (gpio_qdec_idle_polling_mode(dev)) { + for (int i = 0; i < cfg->led_gpio_count; i++) { + gpio_pin_set_dt(&cfg->led_gpio[i], 1); + } + + k_busy_wait(cfg->led_pre_us); + } + if (gpio_pin_get_dt(&cfg->ab_gpio[0])) { step |= 0x01; } @@ -61,6 +139,12 @@ static uint8_t gpio_qdec_get_step(const struct device *dev) step |= 0x02; } + if (gpio_qdec_idle_polling_mode(dev)) { + for (int i = 0; i < cfg->led_gpio_count; i++) { + gpio_pin_set_dt(&cfg->led_gpio[i], 0); + } + } + return step; } @@ -79,6 +163,11 @@ static void gpio_qdec_sample_timer_timeout(struct k_timer *timer) return; } + if (gpio_qdec_idle_polling_mode(dev) && + atomic_get(&data->polling) == 0) { + gpio_qdec_poll_mode(dev); + } + switch ((data->prev_step << 4U) | step) { case QDEC_LL_LH: case QDEC_LH_HH: @@ -128,23 +217,6 @@ static void gpio_qdec_event_worker(struct k_work *work) } } -static void gpio_qdec_irq_setup(const struct device *dev, bool enable) -{ - const struct gpio_qdec_config *cfg = dev->config; - gpio_flags_t flags = enable ? GPIO_INT_EDGE_BOTH : GPIO_INT_DISABLE; - int ret; - - for (int i = 0; i < GPIO_QDEC_GPIO_NUM; i++) { - const struct gpio_dt_spec *gpio = &cfg->ab_gpio[i]; - - ret = gpio_pin_interrupt_configure_dt(gpio, flags); - if (ret != 0) { - LOG_ERR("Pin %d interrupt configuration failed: %d", i, ret); - return; - } - } -} - static void gpio_qdec_idle_worker(struct k_work *work) { struct k_work_delayable *dwork = k_work_delayable_from_work(work); @@ -152,11 +224,7 @@ static void gpio_qdec_idle_worker(struct k_work *work) dwork, struct gpio_qdec_data, idle_work); const struct device *dev = data->dev; - k_timer_stop(&data->sample_timer); - - gpio_qdec_irq_setup(dev, true); - - LOG_DBG("polling stop"); + gpio_qdec_idle_mode(dev); } static void gpio_qdec_cb(const struct device *gpio_dev, struct gpio_callback *cb, @@ -165,14 +233,8 @@ static void gpio_qdec_cb(const struct device *gpio_dev, struct gpio_callback *cb struct gpio_qdec_data *data = CONTAINER_OF( cb, struct gpio_qdec_data, gpio_cb); const struct device *dev = data->dev; - const struct gpio_qdec_config *cfg = dev->config; - gpio_qdec_irq_setup(dev, false); - - k_timer_start(&data->sample_timer, K_NO_WAIT, - K_USEC(cfg->sample_time_us)); - - LOG_DBG("polling start"); + gpio_qdec_poll_mode(dev); } static int gpio_qdec_init(const struct device *dev) @@ -205,6 +267,10 @@ static int gpio_qdec_init(const struct device *dev) return ret; } + if (gpio_qdec_idle_polling_mode(dev)) { + continue; + } + ret = gpio_add_callback_dt(gpio, &data->gpio_cb); if (ret < 0) { LOG_ERR("Could not set gpio callback"); @@ -212,9 +278,28 @@ static int gpio_qdec_init(const struct device *dev) } } + for (int i = 0; i < cfg->led_gpio_count; i++) { + const struct gpio_dt_spec *gpio = &cfg->led_gpio[i]; + gpio_flags_t mode; + + if (!gpio_is_ready_dt(gpio)) { + LOG_ERR("%s is not ready", gpio->port->name); + return -ENODEV; + } + + mode = gpio_qdec_idle_polling_mode(dev) ? + GPIO_OUTPUT_INACTIVE : GPIO_OUTPUT_ACTIVE; + + ret = gpio_pin_configure_dt(gpio, mode); + if (ret != 0) { + LOG_ERR("Pin %d configuration failed: %d", i, ret); + return ret; + } + } + data->prev_step = gpio_qdec_get_step(dev); - gpio_qdec_irq_setup(dev, true); + gpio_qdec_idle_mode(dev); LOG_DBG("Device %s initialized", dev->name); @@ -225,12 +310,31 @@ static int gpio_qdec_init(const struct device *dev) BUILD_ASSERT(DT_INST_PROP_LEN(n, gpios) == GPIO_QDEC_GPIO_NUM, \ "input_gpio_qdec: gpios must have exactly two entries"); \ \ + BUILD_ASSERT(!(DT_INST_NODE_HAS_PROP(n, led_gpios) && \ + DT_INST_NODE_HAS_PROP(n, idle_poll_time_us)) || \ + DT_INST_NODE_HAS_PROP(n, led_pre_us), \ + "led-pre-us must be specified when setting led-gpios and " \ + "idle-poll-time-us"); \ + \ + IF_ENABLED(DT_INST_NODE_HAS_PROP(n, led_gpios), ( \ + static const struct gpio_dt_spec gpio_qdec_led_gpio_##n[] = { \ + DT_INST_FOREACH_PROP_ELEM_SEP(n, led_gpios, \ + GPIO_DT_SPEC_GET_BY_IDX, (,)) \ + }; \ + )) \ + \ static const struct gpio_qdec_config gpio_qdec_cfg_##n = { \ .ab_gpio = { \ GPIO_DT_SPEC_INST_GET_BY_IDX(n, gpios, 0), \ GPIO_DT_SPEC_INST_GET_BY_IDX(n, gpios, 1), \ }, \ + IF_ENABLED(DT_INST_NODE_HAS_PROP(n, led_gpios), ( \ + .led_gpio = gpio_qdec_led_gpio_##n, \ + .led_gpio_count = ARRAY_SIZE(gpio_qdec_led_gpio_##n), \ + .led_pre_us = DT_INST_PROP_OR(n, led_pre_us, 0), \ + )) \ .sample_time_us = DT_INST_PROP(n, sample_time_us), \ + .idle_poll_time_us = DT_INST_PROP_OR(n, idle_poll_time_us, 0), \ .idle_timeout_ms = DT_INST_PROP(n, idle_timeout_ms), \ .steps_per_period = DT_INST_PROP(n, steps_per_period), \ .axis = DT_INST_PROP(n, zephyr_axis), \ diff --git a/dts/bindings/input/gpio-qdec.yaml b/dts/bindings/input/gpio-qdec.yaml index 963a60e1491..96afde35b40 100644 --- a/dts/bindings/input/gpio-qdec.yaml +++ b/dts/bindings/input/gpio-qdec.yaml @@ -35,6 +35,19 @@ properties: description: | GPIO for the A and B encoder signals. + led-gpios: + type: phandle-array + description: | + GPIOs for LED or other components needed for sensing the AB signals. + + led-pre-us: + type: int + description: | + Time between enabling the led-gpios output pins and reading the encoder + state on the input pins, meant to give the state detector (such a + phototransistor) time to settle to right state. Required if led-gpios and + idle-poll-time-us are specified, can be explicitly set to 0 for no delay. + steps-per-period: type: int required: true @@ -55,6 +68,15 @@ properties: How often to sample the A and B signal lines when tracking the encoder movement. + idle-poll-time-us: + type: int + description: | + How often to sample the A and B signal while idling. If unset then the + driver will use the GPIO interrupt to exit idle state, and any GPIO + specified in led-gpios will be enabled all the time. If non zero, then + the driver will poll every idle-poll-time-us microseconds while idle, and + only activate led-gpios before sampling the encoder state. + idle-timeout-ms: type: int required: true diff --git a/tests/drivers/build_all/input/app.overlay b/tests/drivers/build_all/input/app.overlay index 8603a479163..d9c71553e49 100644 --- a/tests/drivers/build_all/input/app.overlay +++ b/tests/drivers/build_all/input/app.overlay @@ -104,6 +104,18 @@ idle-timeout-ms = <200>; }; + qdec-gpio-polled { + compatible = "gpio-qdec"; + gpios = <&test_gpio 0 0>, <&test_gpio 1 0>; + led-gpios = <&test_gpio 2 0>; + led-pre-us = <5>; + steps-per-period = <4>; + zephyr,axis = <0>; + sample-time-us = <2000>; + idle-timeout-ms = <200>; + idle-poll-time-us = <5000>; + }; + analog_axis { compatible = "analog-axis"; axis-x { From 8ae315764c8cdd0a20267b65c8386defbbcf9319 Mon Sep 17 00:00:00 2001 From: Toon Stegen Date: Tue, 2 Jan 2024 17:03:36 +0100 Subject: [PATCH 2716/3723] boards: arm: stm32h750b_dk: add support for QPSI flash devicetree definition for quad spi Signed-off-by: Toon Stegen --- boards/arm/stm32h750b_dk/stm32h750b_dk.dts | 40 ++++++++++++++++++++++ 1 file changed, 40 insertions(+) diff --git a/boards/arm/stm32h750b_dk/stm32h750b_dk.dts b/boards/arm/stm32h750b_dk/stm32h750b_dk.dts index 52222253796..ff074167e2a 100644 --- a/boards/arm/stm32h750b_dk/stm32h750b_dk.dts +++ b/boards/arm/stm32h750b_dk/stm32h750b_dk.dts @@ -18,6 +18,7 @@ zephyr,shell-uart = &usart3; zephyr,sram = &sram0; zephyr,flash = &flash0; + zephyr,flash-controller = &mt25ql512ab1; }; leds { @@ -45,6 +46,7 @@ led0 = &green_led; led1 = &red_led; sw0 = &user_button; + spi-flash0 = &mt25ql512ab1; }; }; @@ -81,3 +83,41 @@ current-speed = <115200>; status = "okay"; }; + +&quadspi { + pinctrl-names = "default"; + pinctrl-0 = <&quadspi_clk_pf10 &quadspi_bk1_ncs_pg6 + &quadspi_bk1_io0_pd11 &quadspi_bk1_io1_pf9 + &quadspi_bk1_io2_pf7 &quadspi_bk1_io3_pf6 + &quadspi_bk2_io0_ph2 &quadspi_bk2_io1_ph3 + &quadspi_bk2_io2_pg9 &quadspi_bk2_io3_pg14>; + flash-id = <1>; + status = "okay"; + + mt25ql512ab1: qspi-nor-flash-1@0 { + compatible = "st,stm32-qspi-nor"; + reg = <0>; + qspi-max-frequency = <72000000>; + size = ; /* 64 MBytes */ + spi-bus-width = <4>; + status = "okay"; + + partitions { + compatible = "fixed-partitions"; + #address-cells = <1>; + #size-cells = <1>; + + partition@0 { + reg = <0x0 DT_SIZE_M(64)>; + }; + }; + }; + + mt25ql512ab2: qspi-nor-flash-2@1 { + compatible = "st,stm32-qspi-nor"; + reg = <1>; + qspi-max-frequency = <72000000>; + size = ; /* 64 MBytes */ + status = "okay"; + }; +}; From 2141bb4561bdbabe4e526b751179d55f431d1123 Mon Sep 17 00:00:00 2001 From: Benedikt Schmidt Date: Wed, 17 Jan 2024 17:44:38 +0100 Subject: [PATCH 2717/3723] drivers: spi: fix unreliable SPI busy flag for some STM32 devices Extend the workaround for the unreliable SPI busy flag to all F7 and L4 devices, which are affected by the same erratum. Fixes #67739 Signed-off-by: Benedikt Schmidt --- drivers/spi/Kconfig.stm32 | 13 ++++++------- drivers/spi/spi_ll_stm32.c | 2 +- 2 files changed, 7 insertions(+), 8 deletions(-) diff --git a/drivers/spi/Kconfig.stm32 b/drivers/spi/Kconfig.stm32 index 6a53f30cbc4..04bc6dabcd2 100644 --- a/drivers/spi/Kconfig.stm32 +++ b/drivers/spi/Kconfig.stm32 @@ -32,22 +32,21 @@ config SPI_STM32_USE_HW_SS help Use Slave Select pin instead of software Slave Select. -config SPI_STM32F7_ERRATA_BUSY +config SPI_STM32_ERRATA_BUSY bool default y - depends on SOC_STM32F745XX || SOC_STM32F746XX || \ - SOC_STM32F750XX || SOC_STM32F756XX + depends on SOC_SERIES_STM32F7X || SOC_SERIES_STM32L4X help Handles erratum "BSY bit may stay high at the end of a data - transfer in Slave mode". - Seen in Errata Sheet 0290 §2.11.2 + transfer in slave mode". + Seen for instance in Errata Sheet 0290 §2.11.2 -if SPI_STM32F7_ERRATA_BUSY +if SPI_STM32_ERRATA_BUSY config SPI_STM32_BUSY_FLAG_TIMEOUT int "timeout in us for the STM32 busy flag workaround" default 10000 -endif # SPI_STM32F7_ERRATA_BUSY +endif # SPI_STM32_ERRATA_BUSY endif # SPI_STM32 diff --git a/drivers/spi/spi_ll_stm32.c b/drivers/spi/spi_ll_stm32.c index b37e6b903e2..c222a624434 100644 --- a/drivers/spi/spi_ll_stm32.c +++ b/drivers/spi/spi_ll_stm32.c @@ -922,7 +922,7 @@ static int transceive_dma(const struct device *dev, } #endif -#ifdef CONFIG_SPI_STM32F7_ERRATA_BUSY +#ifdef CONFIG_SPI_STM32_ERRATA_BUSY WAIT_FOR(ll_func_spi_dma_busy(spi) != 0, CONFIG_SPI_STM32_BUSY_FLAG_TIMEOUT, k_yield()); From 193ad777f443414cc0d3a9092a80aee0ea219834 Mon Sep 17 00:00:00 2001 From: Michael R Rosen Date: Wed, 15 Nov 2023 20:48:41 -0800 Subject: [PATCH 2718/3723] driver: adc: stm32: combine shared and separate irqs Several STM32 variants include both shared IRQs for some ADCs and separate IRQs for others (for example, STM32G473 has 5 ADCs, ADC1 and ADC2 share one IRQ while ADC3, ADC4 and ADC5 each have unique IRQs). The STM32 ADC driver however previously only supported either separate IRQ lines for each operational ADC in the devicetree or a single shared IRQ for all operational ADCs in the devicetree which prevented all ADCs from being usable at the same time when the variant contained a mix of both shared and separate ADC IRQ lines (only either all the shared or all the separate and one of the shared might be used at most for one application). To allow for all ADCs in an STM32 variant to be usable in a single application, generate an ISR and initialization function for each unique IRQn as defined in the devicetree and give the task of initialization to the first ADC which connects to that particular IRQ. Each ISR function will generate code to call the ISR for each ADC associated with that IRQn as was previously done for CONFIG_ADC_STM32_SHARED_IRQS, allowing an ISR to be shared for the ADCs sharing an IRQ while simultaneously providing separate ISRs for each IRQ. Thus, the only information required to have ADCs either share an ISR or not is provided by the devicetree. Signed-off-by: Michael R Rosen --- drivers/adc/Kconfig.stm32 | 11 --- drivers/adc/adc_stm32.c | 181 +++++++++++++++++++++++--------------- 2 files changed, 108 insertions(+), 84 deletions(-) diff --git a/drivers/adc/Kconfig.stm32 b/drivers/adc/Kconfig.stm32 index f185e7664b6..4672a6396a4 100644 --- a/drivers/adc/Kconfig.stm32 +++ b/drivers/adc/Kconfig.stm32 @@ -23,15 +23,4 @@ config ADC_STM32_DMA Enable the ADC DMA mode for ADC instances that enable dma channels in their device tree node. -if SOC_SERIES_STM32F2X || (SOC_SERIES_STM32F3X && !SOC_STM32F373XC) || SOC_SERIES_STM32F4X || SOC_SERIES_STM32F7X || SOC_SERIES_STM32G4X - -config ADC_STM32_SHARED_IRQS - bool "STM32 ADC shared interrupts" - default y - depends on ADC_STM32 && !ADC_STM32_DMA - help - Enable the use of shared interrupts for families that only have a single interrupt for all ADC's - -endif - endif diff --git a/drivers/adc/adc_stm32.c b/drivers/adc/adc_stm32.c index abc5a7514b6..d55e851ec7c 100644 --- a/drivers/adc/adc_stm32.c +++ b/drivers/adc/adc_stm32.c @@ -212,10 +212,6 @@ struct adc_stm32_cfg { const uint32_t res_table[]; }; -#ifdef CONFIG_ADC_STM32_SHARED_IRQS -static bool init_irq = true; -#endif - #ifdef CONFIG_ADC_STM32_DMA static void adc_stm32_enable_dma_support(ADC_TypeDef *adc) { @@ -1379,7 +1375,9 @@ static int adc_stm32_init(const struct device *dev) k_busy_wait(LL_ADC_DELAY_INTERNAL_REGUL_STAB_US); #endif - config->irq_cfg_func(); + if (config->irq_cfg_func) { + config->irq_cfg_func(); + } #if defined(HAS_CALIBRATION) adc_stm32_calibrate(dev); @@ -1502,52 +1500,7 @@ static const struct adc_driver_api api_stm32_driver_api = { _CONCAT(ADC_STM32_CLOCK_PREFIX(x), ADC_STM32_DIV(x)) #endif -#ifdef CONFIG_ADC_STM32_SHARED_IRQS - -bool adc_stm32_is_irq_active(ADC_TypeDef *adc) -{ -#if DT_HAS_COMPAT_STATUS_OKAY(st_stm32f4_adc) - return LL_ADC_IsActiveFlag_EOCS(adc) || -#else - return LL_ADC_IsActiveFlag_EOC(adc) || -#endif /* DT_HAS_COMPAT_STATUS_OKAY(st_stm32f4_adc) */ - LL_ADC_IsActiveFlag_OVR(adc) || - LL_ADC_IsActiveFlag_JEOS(adc) || - LL_ADC_IsActiveFlag_AWD1(adc); -} - -#define HANDLE_IRQS(index) \ - static const struct device *const dev_##index = \ - DEVICE_DT_INST_GET(index); \ - const struct adc_stm32_cfg *cfg_##index = dev_##index->config; \ - ADC_TypeDef *adc_##index = (ADC_TypeDef *)(cfg_##index->base); \ - \ - if (adc_stm32_is_irq_active(adc_##index)) { \ - adc_stm32_isr(dev_##index); \ - } - -static void adc_stm32_shared_irq_handler(void) -{ - DT_INST_FOREACH_STATUS_OKAY(HANDLE_IRQS); -} - -static void adc_stm32_irq_init(void) -{ - if (init_irq) { - init_irq = false; - IRQ_CONNECT(DT_INST_IRQN(0), - DT_INST_IRQ(0, priority), - adc_stm32_shared_irq_handler, NULL, 0); - irq_enable(DT_INST_IRQN(0)); - } -} - -#define ADC_STM32_IRQ_CONFIG(index) -#define ADC_STM32_IRQ_FUNC(index) \ - .irq_cfg_func = adc_stm32_irq_init, -#define ADC_DMA_CHANNEL(id, src, dest) - -#elif defined(CONFIG_ADC_STM32_DMA) /* !CONFIG_ADC_STM32_SHARED_IRQS */ +#if defined(CONFIG_ADC_STM32_DMA) #define ADC_DMA_CHANNEL_INIT(index, src_dev, dest_dev) \ .dma = { \ @@ -1574,39 +1527,121 @@ static void adc_stm32_irq_init(void) STM32_DMA_CHANNEL_CONFIG_BY_IDX(index, 0)), \ } -#define ADC_DMA_CHANNEL(id, src, dest) \ - COND_CODE_1(DT_INST_DMAS_HAS_IDX(id, 0), \ - (ADC_DMA_CHANNEL_INIT(id, src, dest)), \ - (/* Required for other adc instances without dma */)) - -#define ADC_STM32_IRQ_CONFIG(index) \ -static void adc_stm32_cfg_func_##index(void){ EMPTY } #define ADC_STM32_IRQ_FUNC(index) \ - .irq_cfg_func = adc_stm32_cfg_func_##index, + .irq_cfg_func = NULL, #else /* CONFIG_ADC_STM32_DMA */ -#define ADC_STM32_IRQ_CONFIG(index) \ -static void adc_stm32_cfg_func_##index(void) \ -{ \ - IRQ_CONNECT(DT_INST_IRQN(index), \ - DT_INST_IRQ(index, priority), \ - adc_stm32_isr, DEVICE_DT_INST_GET(index), 0); \ - irq_enable(DT_INST_IRQN(index)); \ -} -#define ADC_STM32_IRQ_FUNC(index) \ - .irq_cfg_func = adc_stm32_cfg_func_##index, -#define ADC_DMA_CHANNEL(id, src, dest) +/* + * For series that share interrupt lines for multiple ADC instances + * and have separate interrupt lines for other ADCs (example, + * STM32G473 has 5 ADC instances, ADC1 and ADC2 share IRQn 18 while + * ADC3, ADC4 and ADC5 use IRQns 47, 61 and 62 respectively), generate + * a single common ISR function for each IRQn and call adc_stm32_isr + * for each device using that interrupt line for all enabled ADCs. + * + * To achieve the above, a "first" ADC instance must be chosen for all + * ADC instances sharing the same IRQn. This "first" ADC instance + * generates the code for the common ISR and for installing and + * enabling it while any other ADC sharing the same IRQn skips this + * code generation and does nothing. The common ISR code is generated + * to include calls to adc_stm32_isr for all instances using that same + * IRQn. From the example above, four ISR functions would be generated + * for IRQn 18, 47, 61 and 62, with possible "first" ADC instances + * being ADC1, ADC3, ADC4 and ADC5 if all ADCs were enabled, with the + * ISR function 18 calling adc_stm32_isr for both ADC1 and ADC2. + * + * For some of the macros below, pseudo-code is provided to describe + * its function. + */ -#endif /* CONFIG_ADC_STM32_DMA && CONFIG_ADC_STM32_SHARED_IRQS */ +/* + * return (irqn == device_irqn(index)) ? index : NULL + */ +#define FIRST_WITH_IRQN_INTERNAL(index, irqn) \ + COND_CODE_1(IS_EQ(irqn, DT_INST_IRQN(index)), (index,), (EMPTY,)) + +/* + * Returns the "first" instance's index: + * + * instances = [] + * for instance in all_active_adcs: + * instances.append(first_with_irqn_internal(device_irqn(index))) + * for instance in instances: + * if instance == NULL: + * instances.remove(instance) + * return instances[0] + */ +#define FIRST_WITH_IRQN(index) \ + GET_ARG_N(1, LIST_DROP_EMPTY(DT_INST_FOREACH_STATUS_OKAY_VARGS(FIRST_WITH_IRQN_INTERNAL, \ + DT_INST_IRQN(index)))) + +/* + * Provides code for calling adc_stm32_isr for an instance if its IRQn + * matches: + * + * if (irqn == device_irqn(index)): + * return "adc_stm32_isr(DEVICE_DT_INST_GET(index));" + */ +#define HANDLE_IRQS(index, irqn) \ + COND_CODE_1(IS_EQ(irqn, DT_INST_IRQN(index)), (adc_stm32_isr(DEVICE_DT_INST_GET(index));), \ + (EMPTY)) +/* + * Name of the common ISR for a given IRQn (taken from a device with a + * given index). Example, for an ADC instance with IRQn 18, returns + * "adc_stm32_isr_18". + */ +#define ISR_FUNC(index) UTIL_CAT(adc_stm32_isr_, DT_INST_IRQN(index)) + +/* + * Macro for generating code for the common ISRs (by looping of all + * ADC instances that share the same IRQn as that of the given device + * by index) and the function for setting up the ISR. + * + * Here is where both "first" and non-"first" instances have code + * generated for their interrupts via HANDLE_IRQS. + */ +#define GENERATE_ISR_CODE(index) \ + static void ISR_FUNC(index)(void) \ + { \ + DT_INST_FOREACH_STATUS_OKAY_VARGS(HANDLE_IRQS, DT_INST_IRQN(index)) \ + } \ + \ + static void UTIL_CAT(ISR_FUNC(index), _init)(void) \ + { \ + IRQ_CONNECT(DT_INST_IRQN(index), DT_INST_IRQ(index, priority), ISR_FUNC(index), \ + NULL, 0); \ + irq_enable(DT_INST_IRQN(index)); \ + } + +/* + * Limit generating code to only the "first" instance: + * + * if (first_with_irqn(index) == index): + * generate_isr_code(index) + */ +#define GENERATE_ISR(index) \ + COND_CODE_1(IS_EQ(index, FIRST_WITH_IRQN(index)), (GENERATE_ISR_CODE(index)), (EMPTY)) + +DT_INST_FOREACH_STATUS_OKAY(GENERATE_ISR) + +/* Only "first" instances need to call the ISR setup function */ +#define ADC_STM32_IRQ_FUNC(index) \ + .irq_cfg_func = COND_CODE_1(IS_EQ(index, FIRST_WITH_IRQN(index)), \ + (UTIL_CAT(ISR_FUNC(index), _init)), (NULL)), + +#endif /* CONFIG_ADC_STM32_DMA */ + +#define ADC_DMA_CHANNEL(id, src, dest) \ + COND_CODE_1(DT_INST_DMAS_HAS_IDX(id, 0), \ + (ADC_DMA_CHANNEL_INIT(id, src, dest)), \ + (/* Required for other adc instances without dma */)) #define ADC_STM32_INIT(index) \ \ PINCTRL_DT_INST_DEFINE(index); \ \ -ADC_STM32_IRQ_CONFIG(index) \ - \ static const struct stm32_pclken pclken_##index[] = \ STM32_DT_INST_CLOCKS(index); \ \ From 6f28ea08a5d4220da89c09a9fe468083085ee713 Mon Sep 17 00:00:00 2001 From: Bjarki Arge Andreasen Date: Sat, 21 Oct 2023 22:01:17 +0200 Subject: [PATCH 2719/3723] atmel: sam: flash: Add flash pages property This commit adds layput page cells to the atmel sam flash controller and the flash node. These allow for describing the actual flash page layout of each soc, allowing the flash driver to fully utilize the capabilities of the flash. With this update, we unlock the following capabilties: - utilize 2048 erase block size for small sectors - utilize 16384 erase block size for large sectors Signed-off-by: Bjarki Arge Andreasen --- dts/arm/atmel/sam4e.dtsi | 9 +- dts/arm/atmel/sam4e16c.dtsi | 1 + dts/arm/atmel/sam4e16e.dtsi | 1 + dts/arm/atmel/sam4e8c.dtsi | 1 + dts/arm/atmel/sam4e8e.dtsi | 1 + dts/arm/atmel/sam4s.dtsi | 8 +- dts/arm/atmel/sam4s16b.dtsi | 1 + dts/arm/atmel/sam4s16c.dtsi | 1 + dts/arm/atmel/sam4s2a.dtsi | 1 + dts/arm/atmel/sam4s2b.dtsi | 1 + dts/arm/atmel/sam4s2c.dtsi | 1 + dts/arm/atmel/sam4s4a.dtsi | 1 + dts/arm/atmel/sam4s4b.dtsi | 1 + dts/arm/atmel/sam4s4c.dtsi | 1 + dts/arm/atmel/sam4s8b.dtsi | 1 + dts/arm/atmel/sam4s8c.dtsi | 1 + dts/arm/atmel/sam4sa16c.dtsi | 1 + dts/arm/atmel/same70.dtsi | 5 +- dts/arm/atmel/same70q19.dtsi | 1 + dts/arm/atmel/same70q19b.dtsi | 1 + dts/arm/atmel/same70q21.dtsi | 1 + dts/arm/atmel/same70q21b.dtsi | 1 + dts/arm/atmel/samv71x19.dtsi | 1 + dts/arm/atmel/samv71x19b.dtsi | 1 + dts/arm/atmel/samv71x20.dtsi | 1 + dts/arm/atmel/samv71x20b.dtsi | 1 + dts/arm/atmel/samv71x21.dtsi | 1 + dts/arm/atmel/samv71x21b.dtsi | 1 + .../atmel,sam-flash-controller.yaml | 8 ++ dts/bindings/mtd/atmel,sam-flash.yaml | 117 ++++++++++++++++++ 30 files changed, 161 insertions(+), 11 deletions(-) create mode 100644 dts/bindings/mtd/atmel,sam-flash.yaml diff --git a/dts/arm/atmel/sam4e.dtsi b/dts/arm/atmel/sam4e.dtsi index 21d6f2d2846..545030e8334 100644 --- a/dts/arm/atmel/sam4e.dtsi +++ b/dts/arm/atmel/sam4e.dtsi @@ -79,15 +79,16 @@ compatible = "atmel,sam-flash-controller"; reg = <0x400e0a00 0x200>; clocks = <&pmc PMC_TYPE_PERIPHERAL 6>; + status = "okay"; #address-cells = <1>; #size-cells = <1>; + #erase-block-cells = <2>; flash0: flash@400000 { - compatible = "soc-nv-flash"; - - write-block-size = <16>; - erase-block-size = <8192>; + compatible = "atmel,sam-flash", "soc-nv-flash"; + write-block-size = <8>; + erase-block-size = <4096>; }; }; diff --git a/dts/arm/atmel/sam4e16c.dtsi b/dts/arm/atmel/sam4e16c.dtsi index c3c0226e9d4..ffa4b475c91 100644 --- a/dts/arm/atmel/sam4e16c.dtsi +++ b/dts/arm/atmel/sam4e16c.dtsi @@ -12,6 +12,7 @@ flash-controller@400e0a00 { flash0: flash@400000 { reg = <0x00400000 DT_SIZE_K(1024)>; + erase-blocks = <&eefc 8 2048>, <&eefc 252 4096>; }; }; diff --git a/dts/arm/atmel/sam4e16e.dtsi b/dts/arm/atmel/sam4e16e.dtsi index c3c0226e9d4..ffa4b475c91 100644 --- a/dts/arm/atmel/sam4e16e.dtsi +++ b/dts/arm/atmel/sam4e16e.dtsi @@ -12,6 +12,7 @@ flash-controller@400e0a00 { flash0: flash@400000 { reg = <0x00400000 DT_SIZE_K(1024)>; + erase-blocks = <&eefc 8 2048>, <&eefc 252 4096>; }; }; diff --git a/dts/arm/atmel/sam4e8c.dtsi b/dts/arm/atmel/sam4e8c.dtsi index 1af988dfce5..d47729b0f62 100644 --- a/dts/arm/atmel/sam4e8c.dtsi +++ b/dts/arm/atmel/sam4e8c.dtsi @@ -12,6 +12,7 @@ flash-controller@400e0a00 { flash0: flash@400000 { reg = <0x00400000 DT_SIZE_K(512)>; + erase-blocks = <&eefc 8 2048>, <&eefc 124 4096>; }; }; diff --git a/dts/arm/atmel/sam4e8e.dtsi b/dts/arm/atmel/sam4e8e.dtsi index 1af988dfce5..d47729b0f62 100644 --- a/dts/arm/atmel/sam4e8e.dtsi +++ b/dts/arm/atmel/sam4e8e.dtsi @@ -12,6 +12,7 @@ flash-controller@400e0a00 { flash0: flash@400000 { reg = <0x00400000 DT_SIZE_K(512)>; + erase-blocks = <&eefc 8 2048>, <&eefc 124 4096>; }; }; diff --git a/dts/arm/atmel/sam4s.dtsi b/dts/arm/atmel/sam4s.dtsi index 768f5351817..dcd74ec6ca8 100644 --- a/dts/arm/atmel/sam4s.dtsi +++ b/dts/arm/atmel/sam4s.dtsi @@ -66,12 +66,12 @@ #address-cells = <1>; #size-cells = <1>; + #erase-block-cells = <2>; flash0: flash@400000 { - compatible = "soc-nv-flash"; - - write-block-size = <16>; - erase-block-size = <8192>; + compatible = "atmel,sam-flash", "soc-nv-flash"; + write-block-size = <8>; + erase-block-size = <4096>; }; }; diff --git a/dts/arm/atmel/sam4s16b.dtsi b/dts/arm/atmel/sam4s16b.dtsi index 4ab4d64c4a6..f671f6fccc4 100644 --- a/dts/arm/atmel/sam4s16b.dtsi +++ b/dts/arm/atmel/sam4s16b.dtsi @@ -12,6 +12,7 @@ flash-controller@400e0a00 { flash0: flash@400000 { reg = <0x00400000 DT_SIZE_K(1024)>; + erase-blocks = <&eefc 8 2048>, <&eefc 252 4096>; }; }; diff --git a/dts/arm/atmel/sam4s16c.dtsi b/dts/arm/atmel/sam4s16c.dtsi index 4ab4d64c4a6..f671f6fccc4 100644 --- a/dts/arm/atmel/sam4s16c.dtsi +++ b/dts/arm/atmel/sam4s16c.dtsi @@ -12,6 +12,7 @@ flash-controller@400e0a00 { flash0: flash@400000 { reg = <0x00400000 DT_SIZE_K(1024)>; + erase-blocks = <&eefc 8 2048>, <&eefc 252 4096>; }; }; diff --git a/dts/arm/atmel/sam4s2a.dtsi b/dts/arm/atmel/sam4s2a.dtsi index f85ca2b2a61..b57ddb0cec6 100644 --- a/dts/arm/atmel/sam4s2a.dtsi +++ b/dts/arm/atmel/sam4s2a.dtsi @@ -12,6 +12,7 @@ flash-controller@400e0a00 { flash0: flash@400000 { reg = <0x00400000 DT_SIZE_K(128)>; + erase-blocks = <&eefc 8 2048>, <&eefc 28 4096>; }; }; diff --git a/dts/arm/atmel/sam4s2b.dtsi b/dts/arm/atmel/sam4s2b.dtsi index f85ca2b2a61..b57ddb0cec6 100644 --- a/dts/arm/atmel/sam4s2b.dtsi +++ b/dts/arm/atmel/sam4s2b.dtsi @@ -12,6 +12,7 @@ flash-controller@400e0a00 { flash0: flash@400000 { reg = <0x00400000 DT_SIZE_K(128)>; + erase-blocks = <&eefc 8 2048>, <&eefc 28 4096>; }; }; diff --git a/dts/arm/atmel/sam4s2c.dtsi b/dts/arm/atmel/sam4s2c.dtsi index f85ca2b2a61..b57ddb0cec6 100644 --- a/dts/arm/atmel/sam4s2c.dtsi +++ b/dts/arm/atmel/sam4s2c.dtsi @@ -12,6 +12,7 @@ flash-controller@400e0a00 { flash0: flash@400000 { reg = <0x00400000 DT_SIZE_K(128)>; + erase-blocks = <&eefc 8 2048>, <&eefc 28 4096>; }; }; diff --git a/dts/arm/atmel/sam4s4a.dtsi b/dts/arm/atmel/sam4s4a.dtsi index 36d0ba7729b..1ea079b054c 100644 --- a/dts/arm/atmel/sam4s4a.dtsi +++ b/dts/arm/atmel/sam4s4a.dtsi @@ -12,6 +12,7 @@ flash-controller@400e0a00 { flash0: flash@400000 { reg = <0x00400000 DT_SIZE_K(256)>; + erase-blocks = <&eefc 8 2048>, <&eefc 60 4096>; }; }; diff --git a/dts/arm/atmel/sam4s4b.dtsi b/dts/arm/atmel/sam4s4b.dtsi index 7fbe9118f18..959c4d591e2 100644 --- a/dts/arm/atmel/sam4s4b.dtsi +++ b/dts/arm/atmel/sam4s4b.dtsi @@ -12,6 +12,7 @@ flash-controller@400e0a00 { flash0: flash@400000 { reg = <0x00400000 DT_SIZE_K(356)>; + erase-blocks = <&eefc 8 2048>, <&eefc 60 4096>; }; }; diff --git a/dts/arm/atmel/sam4s4c.dtsi b/dts/arm/atmel/sam4s4c.dtsi index 36d0ba7729b..1ea079b054c 100644 --- a/dts/arm/atmel/sam4s4c.dtsi +++ b/dts/arm/atmel/sam4s4c.dtsi @@ -12,6 +12,7 @@ flash-controller@400e0a00 { flash0: flash@400000 { reg = <0x00400000 DT_SIZE_K(256)>; + erase-blocks = <&eefc 8 2048>, <&eefc 60 4096>; }; }; diff --git a/dts/arm/atmel/sam4s8b.dtsi b/dts/arm/atmel/sam4s8b.dtsi index f047b4a073b..2e00a78b4d6 100644 --- a/dts/arm/atmel/sam4s8b.dtsi +++ b/dts/arm/atmel/sam4s8b.dtsi @@ -12,6 +12,7 @@ flash-controller@400e0a00 { flash0: flash@400000 { reg = <0x00400000 DT_SIZE_K(512)>; + erase-blocks = <&eefc 8 2048>, <&eefc 124 4096>; }; }; diff --git a/dts/arm/atmel/sam4s8c.dtsi b/dts/arm/atmel/sam4s8c.dtsi index f047b4a073b..2e00a78b4d6 100644 --- a/dts/arm/atmel/sam4s8c.dtsi +++ b/dts/arm/atmel/sam4s8c.dtsi @@ -12,6 +12,7 @@ flash-controller@400e0a00 { flash0: flash@400000 { reg = <0x00400000 DT_SIZE_K(512)>; + erase-blocks = <&eefc 8 2048>, <&eefc 124 4096>; }; }; diff --git a/dts/arm/atmel/sam4sa16c.dtsi b/dts/arm/atmel/sam4sa16c.dtsi index ae96e4b27ad..789e482b0f6 100644 --- a/dts/arm/atmel/sam4sa16c.dtsi +++ b/dts/arm/atmel/sam4sa16c.dtsi @@ -12,6 +12,7 @@ flash-controller@400e0a00 { flash0: flash@400000 { reg = <0x00400000 DT_SIZE_K(1024)>; + erase-blocks = <&eefc 8 2048>, <&eefc 252 4096>; }; }; diff --git a/dts/arm/atmel/same70.dtsi b/dts/arm/atmel/same70.dtsi index 10f103d1ecd..878ad822d68 100644 --- a/dts/arm/atmel/same70.dtsi +++ b/dts/arm/atmel/same70.dtsi @@ -71,14 +71,13 @@ #address-cells = <1>; #size-cells = <1>; + #erase-block-cells = <2>; flash0: flash@400000 { - compatible = "soc-nv-flash"; - + compatible = "atmel,sam-flash", "soc-nv-flash"; write-block-size = <16>; erase-block-size = <8192>; }; - }; wdt: watchdog@400e1850 { diff --git a/dts/arm/atmel/same70q19.dtsi b/dts/arm/atmel/same70q19.dtsi index e8f3329bd2e..abf0e5b67e5 100644 --- a/dts/arm/atmel/same70q19.dtsi +++ b/dts/arm/atmel/same70q19.dtsi @@ -17,6 +17,7 @@ flash-controller@400e0c00 { flash0: flash@400000 { reg = <0x00400000 DT_SIZE_K(512)>; + erase-blocks = <&eefc 8 2048>, <&eefc 62 8192>; }; }; }; diff --git a/dts/arm/atmel/same70q19b.dtsi b/dts/arm/atmel/same70q19b.dtsi index 0815fdc2dfa..cc97dc64458 100644 --- a/dts/arm/atmel/same70q19b.dtsi +++ b/dts/arm/atmel/same70q19b.dtsi @@ -17,6 +17,7 @@ flash-controller@400e0c00 { flash0: flash@400000 { reg = <0x00400000 DT_SIZE_K(512)>; + erase-blocks = <&eefc 8 2048>, <&eefc 62 8192>; }; }; }; diff --git a/dts/arm/atmel/same70q21.dtsi b/dts/arm/atmel/same70q21.dtsi index 494fdc0d026..4138d6ca066 100644 --- a/dts/arm/atmel/same70q21.dtsi +++ b/dts/arm/atmel/same70q21.dtsi @@ -17,6 +17,7 @@ flash-controller@400e0c00 { flash0: flash@400000 { reg = <0x00400000 DT_SIZE_K(2048)>; + erase-blocks = <&eefc 8 2048>, <&eefc 252 8192>; }; }; }; diff --git a/dts/arm/atmel/same70q21b.dtsi b/dts/arm/atmel/same70q21b.dtsi index 8f13909f911..d6fe0fa4a2e 100644 --- a/dts/arm/atmel/same70q21b.dtsi +++ b/dts/arm/atmel/same70q21b.dtsi @@ -18,6 +18,7 @@ flash-controller@400e0c00 { flash0: flash@400000 { reg = <0x00400000 DT_SIZE_K(2048)>; + erase-blocks = <&eefc 8 2048>, <&eefc 252 8192>; }; }; }; diff --git a/dts/arm/atmel/samv71x19.dtsi b/dts/arm/atmel/samv71x19.dtsi index b124cb7cb40..46c1d7a8756 100644 --- a/dts/arm/atmel/samv71x19.dtsi +++ b/dts/arm/atmel/samv71x19.dtsi @@ -16,6 +16,7 @@ flash-controller@400e0c00 { flash0: flash@400000 { reg = <0x00400000 DT_SIZE_K(512)>; + erase-blocks = <&eefc 8 2048>, <&eefc 62 8192>; }; }; }; diff --git a/dts/arm/atmel/samv71x19b.dtsi b/dts/arm/atmel/samv71x19b.dtsi index 966c5b27ca3..520c9398151 100644 --- a/dts/arm/atmel/samv71x19b.dtsi +++ b/dts/arm/atmel/samv71x19b.dtsi @@ -17,6 +17,7 @@ flash-controller@400e0c00 { flash0: flash@400000 { reg = <0x00400000 DT_SIZE_K(512)>; + erase-blocks = <&eefc 8 2048>, <&eefc 62 8192>; }; }; }; diff --git a/dts/arm/atmel/samv71x20.dtsi b/dts/arm/atmel/samv71x20.dtsi index e251f68feb6..10228d242a2 100644 --- a/dts/arm/atmel/samv71x20.dtsi +++ b/dts/arm/atmel/samv71x20.dtsi @@ -16,6 +16,7 @@ flash-controller@400e0c00 { flash0: flash@400000 { reg = <0x00400000 DT_SIZE_K(1024)>; + erase-blocks = <&eefc 8 2048>, <&eefc 126 8192>; }; }; }; diff --git a/dts/arm/atmel/samv71x20b.dtsi b/dts/arm/atmel/samv71x20b.dtsi index c26a88299ad..d425e524aa8 100644 --- a/dts/arm/atmel/samv71x20b.dtsi +++ b/dts/arm/atmel/samv71x20b.dtsi @@ -17,6 +17,7 @@ flash-controller@400e0c00 { flash0: flash@400000 { reg = <0x00400000 DT_SIZE_K(1024)>; + erase-blocks = <&eefc 8 2048>, <&eefc 126 8192>; }; }; }; diff --git a/dts/arm/atmel/samv71x21.dtsi b/dts/arm/atmel/samv71x21.dtsi index bd72c69835a..d59fa5be590 100644 --- a/dts/arm/atmel/samv71x21.dtsi +++ b/dts/arm/atmel/samv71x21.dtsi @@ -16,6 +16,7 @@ flash-controller@400e0c00 { flash0: flash@400000 { reg = <0x00400000 DT_SIZE_K(2048)>; + erase-blocks = <&eefc 8 2048>, <&eefc 252 8192>; }; }; }; diff --git a/dts/arm/atmel/samv71x21b.dtsi b/dts/arm/atmel/samv71x21b.dtsi index c7acf1b2530..c55ac8b1284 100644 --- a/dts/arm/atmel/samv71x21b.dtsi +++ b/dts/arm/atmel/samv71x21b.dtsi @@ -17,6 +17,7 @@ flash-controller@400e0c00 { flash0: flash@400000 { reg = <0x00400000 DT_SIZE_K(2048)>; + erase-blocks = <&eefc 8 2048>, <&eefc 252 8192>; }; }; }; diff --git a/dts/bindings/flash_controller/atmel,sam-flash-controller.yaml b/dts/bindings/flash_controller/atmel,sam-flash-controller.yaml index 64a84a03758..80257970fad 100644 --- a/dts/bindings/flash_controller/atmel,sam-flash-controller.yaml +++ b/dts/bindings/flash_controller/atmel,sam-flash-controller.yaml @@ -10,3 +10,11 @@ include: flash-controller.yaml properties: clocks: required: true + + "#erase-block-cells": + type: int + const: 2 + +erase-block-cells: + - pages-count + - pages-size diff --git a/dts/bindings/mtd/atmel,sam-flash.yaml b/dts/bindings/mtd/atmel,sam-flash.yaml new file mode 100644 index 00000000000..559dcebe4ea --- /dev/null +++ b/dts/bindings/mtd/atmel,sam-flash.yaml @@ -0,0 +1,117 @@ +# Copyright (c) 2023 Bjarki Arge Andreasen +# SPDX-License-Identifier: Apache-2.0 + +description: | + This binding describes the Atmel SAM flash area layout. + + The Atmel SAM flash area varies in write-block-size, memory area, + and the layout of erase-blocks. + + E.g. the flash area layout of the ATSAM4E16C: + + |--------------------| + | 8 Kbytes | erase block size = 2048 + |--------------------| + | 8 Kbytes | erase block size = 2048 + |--------------------| + | 48 Kbytes | erase block size = 4096 + |--------------------| + | 64 Kbytes | erase block size = 4096 + |--------------------| + | ... | + + The ATSAM4E16C has a flash area which is 1000Kbytes + (1024 * 1024 bytes) with a write-block-size of 8 bytes. The first + 16 Kbytes can be erased in blocks of 2048 bytes + (8 blocks of 2048 bytes), the remaining flash area is erasable + in blocks of 4096 bytes (252 blocks of 4096 bytes). + + This flash area layout would described as: + + / { + soc { + eefc: flash-controller@400e0a00 { + compatible = "atmel,sam-flash-controller"; + reg = <0x400e0a00 0x200>; + clocks = <&pmc PMC_TYPE_PERIPHERAL 6>; + status = "okay"; + + #address-cells = <1>; + #size-cells = <1>; + #erase-block-cells = <2>; + + flash0: flash@400000 { + compatible = "atmel,sam-flash", "soc-nv-flash"; + reg = <0x400000 0x100000>; + write-block-size = <8>; + erase-block-size = <4096>; + erase-blocks = <&eefc 8 2048>, <&eefc 252 4096>; + }; + }; + }; + + Notes: + The flash area layout node flash0 should have both this + compatible, "atmel,sam-flash", and the "soc-nv-flash" + compatible. The latter is used from mcuboot and other + modules to identify the flash area. + + If partitions are used, remember that their addresses are + offsets relative to the flash area address. E.g. using + mcuboot and a allocating a storage partition: + + &flash0 { + partitions { + compatible = "fixed-partitions"; + #address-cells = <1>; + #size-cells = <1>; + + boot_partition: partition@0 { + label = "mcuboot"; + reg = <0x0 0x10000>; + }; + + slot0_partition: partition@10000 { + label = "slot0"; + reg = <0x10000 0x70000>; + }; + + slot1_partition: partition@80000 { + label = "slot1"; + reg = <0x80000 0x70000>; + }; + + storage_partition: partition@f0000 { + label = "storage"; + reg = <0xf0000 0x100000>; + }; + }; + }; + +compatible: "atmel,sam-flash" + +include: base.yaml + +properties: + write-block-size: + type: int + description: | + The flash controller is limited by hardware to writing blocks of + this size, aligned to this size, in bytes, to previously erased + flash, within the flash memory area. + + erase-block-size: + type: int + description: | + The flash controller is limited by hardware to erase whole + blocks of flash at a time. This property describes the largest + erase block size in erase-blocks. + + erase-blocks: + type: phandle-array + required: true + description: | + The flash controller is limited by hardware to erase whole + blocks of flash at a time. This propery describes the layout of + the erase-blocks, which can vary in size within the flash memory + area. From ed854f008ae1547762fe6f3c2a922ab8b03babb8 Mon Sep 17 00:00:00 2001 From: Bjarki Arge Andreasen Date: Sat, 21 Oct 2023 22:11:32 +0200 Subject: [PATCH 2720/3723] flash: sam: Rewrite driver to dyncamically adapt to pages This commit updates the driver to use the flash layout pages, rewriting it to utilize the flash_page_layout.c driver to avoid duplicate code. Signed-off-by: Bjarki Arge Andreasen --- drivers/flash/Kconfig.sam | 1 + drivers/flash/flash_sam.c | 604 ++++++++++++++------------ dts/bindings/mtd/atmel,sam-flash.yaml | 2 +- 3 files changed, 330 insertions(+), 277 deletions(-) diff --git a/drivers/flash/Kconfig.sam b/drivers/flash/Kconfig.sam index bb014d65279..64df895bd6a 100644 --- a/drivers/flash/Kconfig.sam +++ b/drivers/flash/Kconfig.sam @@ -7,6 +7,7 @@ config SOC_FLASH_SAM bool "Atmel SAM flash driver" default y depends on DT_HAS_ATMEL_SAM_FLASH_CONTROLLER_ENABLED + select FLASH_PAGE_LAYOUT select FLASH_HAS_PAGE_LAYOUT select FLASH_HAS_DRIVER_ENABLED select MPU_ALLOW_FLASH_WRITE if ARM_MPU diff --git a/drivers/flash/flash_sam.c b/drivers/flash/flash_sam.c index 118775d29f3..d87d766d41f 100644 --- a/drivers/flash/flash_sam.c +++ b/drivers/flash/flash_sam.c @@ -1,404 +1,456 @@ /* * Copyright (c) 2018 Aurelien Jarno + * Copyright (c) 2023 Bjarki Arge Andreasen * * SPDX-License-Identifier: Apache-2.0 */ -#define DT_DRV_COMPAT atmel_sam_flash_controller -#define SOC_NV_FLASH_NODE DT_INST(0, soc_nv_flash) +/* + * This driver defines a page as the erase_block_size. + * This driver defines a write page as defined by the flash controller + * This driver defines a section as a contiguous array of bytes + * This driver defines an area as the entire flash area + * This driver defines the write block size as the minimum write block size + */ -#define FLASH_WRITE_BLK_SZ DT_PROP(SOC_NV_FLASH_NODE, write_block_size) -#define FLASH_ERASE_BLK_SZ DT_PROP(SOC_NV_FLASH_NODE, erase_block_size) +#define DT_DRV_COMPAT atmel_sam_flash_controller -#include -#include -#include #include +#include +#include #include -#include #include +#include -#define LOG_LEVEL CONFIG_FLASH_LOG_LEVEL #include -LOG_MODULE_REGISTER(flash_sam0); +LOG_MODULE_REGISTER(flash_sam, CONFIG_FLASH_LOG_LEVEL); -/* - * The SAM flash memories use very different granularity for writing, - * erasing and locking. In addition the first sector is composed of two - * 8-KiB small sectors with a minimum 512-byte erase size, while the - * other sectors have a minimum 8-KiB erase size. - * - * For simplicity reasons this flash controller driver only addresses the - * flash by 8-KiB blocks (called "pages" in the Zephyr terminology). - */ - - -/* - * We only use block mode erases. The datasheet gives a maximum erase time - * of 200ms for a 8KiB block. - */ -#define SAM_FLASH_TIMEOUT_MS 220 -#if defined(IFLASH0_PAGE_SIZE) -#define IFLASH_PAGE_SIZE IFLASH0_PAGE_SIZE -#endif +#define SAM_FLASH_WRITE_PAGE_SIZE (512) -struct flash_sam_dev_cfg { +struct sam_flash_config { Efc *regs; + off_t area_address; + off_t area_size; + struct flash_parameters parameters; + struct flash_pages_layout *pages_layouts; + size_t pages_layouts_size; }; -struct flash_sam_dev_data { - struct k_sem sem; +struct sam_flash_erase_data { + off_t section_start; + size_t section_end; + bool succeeded; }; -static const struct flash_parameters flash_sam_parameters = { - .write_block_size = FLASH_WRITE_BLK_SZ, - .erase_value = 0xff, +struct sam_flash_data { + const struct device *dev; + struct k_spinlock lock; + struct sam_flash_erase_data erase_data; }; -static int flash_sam_write_protection(const struct device *dev, bool enable); - -static inline void flash_sam_sem_take(const struct device *dev) +static bool sam_flash_validate_offset_len(off_t offset, size_t len) { - struct flash_sam_dev_data *data = dev->data; - - k_sem_take(&data->sem, K_FOREVER); -} - -static inline void flash_sam_sem_give(const struct device *dev) -{ - struct flash_sam_dev_data *data = dev->data; - - k_sem_give(&data->sem); -} - -/* Check that the offset is within the flash */ -static bool flash_sam_valid_range(const struct device *dev, off_t offset, - size_t len) -{ - if (offset > CONFIG_FLASH_SIZE * 1024) { + if (offset < 0) { return false; } - if (len && ((offset + len - 1) > (CONFIG_FLASH_SIZE * 1024))) { + if ((offset + len) < len) { return false; } return true; } -/* Convert an offset in the flash into a page number */ -static off_t flash_sam_get_page(off_t offset) +static bool sam_flash_aligned(size_t value, size_t alignment) { - return offset / IFLASH_PAGE_SIZE; + return (value & (alignment - 1)) == 0; } -/* - * This function checks for errors and waits for the end of the - * previous command. - */ -static int flash_sam_wait_ready(const struct device *dev) +static bool sam_flash_offset_is_on_write_page_boundary(off_t offset) { - const struct flash_sam_dev_cfg *config = dev->config; - - Efc * const efc = config->regs; + return (sam_flash_aligned(offset, SAM_FLASH_WRITE_PAGE_SIZE)); +} - uint64_t timeout_time = k_uptime_get() + SAM_FLASH_TIMEOUT_MS; - uint32_t fsr; +static int sam_flash_section_wait_until_ready(const struct device *dev) +{ + const struct sam_flash_config *config = dev->config; + Efc *regs = config->regs; - do { - fsr = efc->EEFC_FSR; + while (!(regs->EEFC_FSR & EEFC_FSR_FRDY)) { + k_msleep(20); + } - /* Flash Error Status */ - if (fsr & EEFC_FSR_FLERR) { - return -EIO; - } - /* Flash Lock Error Status */ - if (fsr & EEFC_FSR_FLOCKE) { - return -EACCES; - } - /* Flash Command Error */ - if (fsr & EEFC_FSR_FCMDE) { - return -EINVAL; - } + if (regs->EEFC_FSR & EEFC_FSR_FCMDE) { + LOG_ERR("Invalid command requested"); + return -EPERM; + } - /* - * ECC error bits are intentionally not checked as they - * might be set outside of the programming code. - */ + if (regs->EEFC_FSR & EEFC_FSR_FLOCKE) { + LOG_ERR("Tried to modify locked region"); + return -EPERM; + } - /* Check for timeout */ - if (k_uptime_get() > timeout_time) { - return -ETIMEDOUT; - } - } while (!(fsr & EEFC_FSR_FRDY)); + if (regs->EEFC_FSR & EEFC_FSR_FLERR) { + LOG_ERR("Programming failed"); + return -EPERM; + } return 0; } -/* This function writes a single page, either fully or partially. */ -static int flash_sam_write_page(const struct device *dev, off_t offset, - const void *data, size_t len) +static bool sam_flash_section_is_within_area(const struct device *dev, off_t offset, size_t len) { - const struct flash_sam_dev_cfg *config = dev->config; + const struct sam_flash_config *config = dev->config; - Efc * const efc = config->regs; - const uint32_t *src = data; - uint32_t *dst = (uint32_t *)((uint8_t *)CONFIG_FLASH_BASE_ADDRESS + offset); - - LOG_DBG("offset = 0x%lx, len = %zu", (long)offset, len); + if ((offset + ((off_t)len)) < offset) { + return false; + } - /* We need to copy the data using 32-bit accesses */ - for (; len > 0; len -= sizeof(*src)) { - *dst++ = *src++; - /* Assure data are written to the latch buffer consecutively */ - barrier_dsync_fence_full(); + if ((offset >= 0) && ((offset + len) <= config->area_size)) { + return true; } - /* Trigger the flash write */ - efc->EEFC_FCR = EEFC_FCR_FKEY_PASSWD | - EEFC_FCR_FARG(flash_sam_get_page(offset)) | - EEFC_FCR_FCMD_WP; - barrier_dsync_fence_full(); + return false; +} + +static bool sam_flash_section_is_aligned_with_write_block_size(const struct device *dev, + off_t offset, size_t len) +{ + const struct sam_flash_config *config = dev->config; - /* Wait for the flash write to finish */ - return flash_sam_wait_ready(dev); + return sam_flash_aligned(offset, config->parameters.write_block_size) && + sam_flash_aligned(len, config->parameters.write_block_size); } -/* Write data to the flash, page by page */ -static int flash_sam_write(const struct device *dev, off_t offset, - const void *data, size_t len) +static bool sam_flash_section_is_aligned_with_pages(const struct device *dev, off_t offset, + size_t len) { - int rc; - const uint8_t *data8 = data; + const struct sam_flash_config *config = dev->config; + struct flash_pages_info pages_info; - LOG_DBG("offset = 0x%lx, len = %zu", (long)offset, len); + /* Get the page offset points to */ + if (flash_get_page_info_by_offs(dev, offset, &pages_info) < 0) { + return false; + } - /* Check that the offset is within the flash */ - if (!flash_sam_valid_range(dev, offset, len)) { - return -EINVAL; + /* Validate offset points to start of page */ + if (offset != pages_info.start_offset) { + return false; + } + + /* Check if end of section is aligned with end of area */ + if ((offset + len) == (config->area_size)) { + return true; + } + + /* Get the page pointed to by end of section */ + if (flash_get_page_info_by_offs(dev, offset + len, &pages_info) < 0) { + return false; } - if (!len) { + /* Validate offset points to start of page */ + if ((offset + len) != pages_info.start_offset) { + return false; + } + + return true; +} + +static int sam_flash_read(const struct device *dev, off_t offset, void *data, size_t len) +{ + struct sam_flash_data *sam_data = dev->data; + const struct sam_flash_config *sam_config = dev->config; + k_spinlock_key_t key; + + if (len == 0) { return 0; } - /* - * Check that the offset and length are multiples of the write - * block size. - */ - if ((offset % FLASH_WRITE_BLK_SZ) != 0) { + if (!sam_flash_validate_offset_len(offset, len)) { return -EINVAL; } - if ((len % FLASH_WRITE_BLK_SZ) != 0) { + + if (!sam_flash_section_is_within_area(dev, offset, len)) { return -EINVAL; } - flash_sam_sem_take(dev); + key = k_spin_lock(&sam_data->lock); + memcpy(data, (uint8_t *)(sam_config->area_address + offset), len); + k_spin_unlock(&sam_data->lock, key); + return 0; +} - rc = flash_sam_write_protection(dev, false); - if (rc >= 0) { - rc = flash_sam_wait_ready(dev); - } +static int sam_flash_write_latch_buffer_to_page(const struct device *dev, off_t offset) +{ + const struct sam_flash_config *sam_config = dev->config; + Efc *regs = sam_config->regs; + uint32_t page = offset / SAM_FLASH_WRITE_PAGE_SIZE; - if (rc >= 0) { - while (len > 0) { - size_t eop_len, write_len; + regs->EEFC_FCR = EEFC_FCR_FCMD_WP | EEFC_FCR_FARG(page) | EEFC_FCR_FKEY_PASSWD; + sam_flash_section_wait_until_ready(dev); + return 0; +} - /* Maximum size without crossing a page */ - eop_len = -(offset | ~(IFLASH_PAGE_SIZE - 1)); - write_len = MIN(len, eop_len); +static int sam_flash_write_latch_buffer_to_previous_page(const struct device *dev, off_t offset) +{ + return sam_flash_write_latch_buffer_to_page(dev, offset - SAM_FLASH_WRITE_PAGE_SIZE); +} - rc = flash_sam_write_page(dev, offset, data8, write_len); - if (rc < 0) { - break; - } +static void sam_flash_write_dword_to_latch_buffer(off_t offset, uint32_t dword) +{ + *((uint32_t *)offset) = dword; + barrier_dsync_fence_full(); +} - offset += write_len; - data8 += write_len; - len -= write_len; +static int sam_flash_write_dwords_to_flash(const struct device *dev, off_t offset, + const uint32_t *dwords, size_t size) +{ + for (size_t i = 0; i < size; i++) { + sam_flash_write_dword_to_latch_buffer(offset, dwords[i]); + offset += sizeof(uint32_t); + if (sam_flash_offset_is_on_write_page_boundary(offset)) { + sam_flash_write_latch_buffer_to_previous_page(dev, offset); } } - int rc2 = flash_sam_write_protection(dev, true); - - if (!rc) { - rc = rc2; + if (!sam_flash_offset_is_on_write_page_boundary(offset)) { + sam_flash_write_latch_buffer_to_page(dev, offset); } - flash_sam_sem_give(dev); - - return rc; + return 0; } -/* Read data from flash */ -static int flash_sam_read(const struct device *dev, off_t offset, void *data, - size_t len) +static int sam_flash_write(const struct device *dev, off_t offset, const void *data, size_t len) { - LOG_DBG("offset = 0x%lx, len = %zu", (long)offset, len); + struct sam_flash_data *sam_data = dev->data; + k_spinlock_key_t key; + + if (len == 0) { + return 0; + } - if (!flash_sam_valid_range(dev, offset, len)) { + if (!sam_flash_validate_offset_len(offset, len)) { return -EINVAL; } - memcpy(data, (uint8_t *)CONFIG_FLASH_BASE_ADDRESS + offset, len); + if (!sam_flash_section_is_aligned_with_write_block_size(dev, offset, len)) { + return -EINVAL; + } + key = k_spin_lock(&sam_data->lock); + if (sam_flash_write_dwords_to_flash(dev, offset, data, len / sizeof(uint32_t)) < 0) { + k_spin_unlock(&sam_data->lock, key); + return -EAGAIN; + } + + k_spin_unlock(&sam_data->lock, key); return 0; } -/* Erase a single 8KiB block */ -static int flash_sam_erase_block(const struct device *dev, off_t offset) +static int sam_flash_unlock_write_page(const struct device *dev, uint16_t page_index) { - const struct flash_sam_dev_cfg *config = dev->config; - - Efc * const efc = config->regs; - - LOG_DBG("offset = 0x%lx", (long)offset); + const struct sam_flash_config *sam_config = dev->config; + Efc *regs = sam_config->regs; - efc->EEFC_FCR = EEFC_FCR_FKEY_PASSWD | - EEFC_FCR_FARG(flash_sam_get_page(offset) | 2) | - EEFC_FCR_FCMD_EPA; - barrier_dsync_fence_full(); + /* Perform unlock command of write page */ + regs->EEFC_FCR = EEFC_FCR_FCMD_CLB + | EEFC_FCR_FARG(page_index) + | EEFC_FCR_FKEY_PASSWD; - return flash_sam_wait_ready(dev); + return sam_flash_section_wait_until_ready(dev); } -/* Erase multiple blocks */ -static int flash_sam_erase(const struct device *dev, off_t offset, size_t len) +static int sam_flash_unlock_page(const struct device *dev, const struct flash_pages_info *info) { - int rc = 0; - off_t i; + uint16_t page_index_start; + uint16_t page_index_end; + int ret; + + /* Convert from page offset and size to write page index and count */ + page_index_start = info->start_offset / SAM_FLASH_WRITE_PAGE_SIZE; + page_index_end = page_index_start + (info->size / SAM_FLASH_WRITE_PAGE_SIZE); + + for (uint16_t i = page_index_start; i < page_index_end; i++) { + ret = sam_flash_unlock_write_page(dev, i); + if (ret < 0) { + return ret; + } + } - LOG_DBG("offset = 0x%lx, len = %zu", (long)offset, len); + return 0; +} - if (!flash_sam_valid_range(dev, offset, len)) { +static int sam_flash_erase_page(const struct device *dev, const struct flash_pages_info *info) +{ + const struct sam_flash_config *sam_config = dev->config; + Efc *regs = sam_config->regs; + uint32_t page_index; + + /* Convert from page offset to write page index */ + page_index = info->start_offset / SAM_FLASH_WRITE_PAGE_SIZE; + + /* Perform erase command of page */ + switch (info->size) { + case 0x800: + regs->EEFC_FCR = EEFC_FCR_FCMD_EPA + | EEFC_FCR_FARG(page_index) + | EEFC_FCR_FKEY_PASSWD; + break; + + case 0x1000: + regs->EEFC_FCR = EEFC_FCR_FCMD_EPA + | EEFC_FCR_FARG(page_index | 1) + | EEFC_FCR_FKEY_PASSWD; + break; + + case 0x2000: + regs->EEFC_FCR = EEFC_FCR_FCMD_EPA + | EEFC_FCR_FARG(page_index | 2) + | EEFC_FCR_FKEY_PASSWD; + break; + + case 0x4000: + regs->EEFC_FCR = EEFC_FCR_FCMD_EPA + | EEFC_FCR_FARG(page_index | 3) + | EEFC_FCR_FKEY_PASSWD; + break; + + default: return -EINVAL; } - if (!len) { - return 0; - } + return sam_flash_section_wait_until_ready(dev); +} - /* - * Check that the offset and length are multiples of the write - * erase block size. - */ - if ((offset % FLASH_ERASE_BLK_SZ) != 0) { - return -EINVAL; +static bool sam_flash_erase_foreach_page(const struct flash_pages_info *info, void *data) +{ + struct sam_flash_data *sam_data = data; + const struct device *dev = sam_data->dev; + struct sam_flash_erase_data *erase_data = &sam_data->erase_data; + + /* Validate we reached first page to erase */ + if (info->start_offset < erase_data->section_start) { + /* Next page */ + return true; } - if ((len % FLASH_ERASE_BLK_SZ) != 0) { - return -EINVAL; + + /* Check if we've reached the end of pages to erase */ + if (info->start_offset >= erase_data->section_end) { + /* Succeeded, stop iterating */ + erase_data->succeeded = true; + return false; } - flash_sam_sem_take(dev); + if (sam_flash_unlock_page(dev, info) < 0) { + /* Failed to unlock page, stop iterating */ + return false; + } - rc = flash_sam_write_protection(dev, false); - if (rc >= 0) { - /* Loop through the pages to erase */ - for (i = offset; i < offset + len; i += FLASH_ERASE_BLK_SZ) { - rc = flash_sam_erase_block(dev, i); - if (rc < 0) { - break; - } - } + if (sam_flash_erase_page(dev, info) < 0) { + /* Failed to erase page, stop iterating */ + return false; } - int rc2 = flash_sam_write_protection(dev, true); + /* Next page */ + return true; +} + +static int sam_flash_erase(const struct device *dev, off_t offset, size_t size) +{ + struct sam_flash_data *sam_data = dev->data; + k_spinlock_key_t key; - if (!rc) { - rc = rc2; + if (size == 0) { + return 0; } - flash_sam_sem_give(dev); - - /* - * Invalidate the cache addresses corresponding to the erased blocks, - * so that they really appear as erased. - */ -#ifdef __DCACHE_PRESENT - SCB_InvalidateDCache_by_Addr((void *)(CONFIG_FLASH_BASE_ADDRESS + offset), len); -#endif + if (!sam_flash_validate_offset_len(offset, size)) { + return -EINVAL; + } - return rc; -} + if (!sam_flash_section_is_aligned_with_pages(dev, offset, size)) { + return -EINVAL; + } -/* Enable or disable the write protection */ -static int flash_sam_write_protection(const struct device *dev, bool enable) -{ -#if defined(EFC_6450) - const struct flash_sam_dev_cfg *config = dev->config; - Efc *const efc = config->regs; -#endif - int rc = 0; - - if (enable) { - rc = flash_sam_wait_ready(dev); - if (rc < 0) { - goto done; - } -#if defined(EFC_6450) - efc->EEFC_WPMR = EEFC_WPMR_WPKEY_PASSWD | EEFC_WPMR_WPEN; - } else { - efc->EEFC_WPMR = EEFC_WPMR_WPKEY_PASSWD; -#endif + key = k_spin_lock(&sam_data->lock); + sam_data->erase_data.section_start = offset; + sam_data->erase_data.section_end = offset + size; + sam_data->erase_data.succeeded = false; + flash_page_foreach(dev, sam_flash_erase_foreach_page, sam_data); + if (!sam_data->erase_data.succeeded) { + k_spin_unlock(&sam_data->lock, key); + return -EFAULT; } -done: - return rc; + k_spin_unlock(&sam_data->lock, key); + return 0; } -#if CONFIG_FLASH_PAGE_LAYOUT -/* - * The notion of pages is different in Zephyr and in the SAM documentation. - * Here a page refers to the granularity at which the flash can be erased. - */ -static const struct flash_pages_layout flash_sam_pages_layout = { - .pages_count = DT_REG_SIZE(SOC_NV_FLASH_NODE) / FLASH_ERASE_BLK_SZ, - .pages_size = DT_PROP(SOC_NV_FLASH_NODE, erase_block_size), -}; - -void flash_sam_page_layout(const struct device *dev, - const struct flash_pages_layout **layout, - size_t *layout_size) +static const struct flash_parameters *sam_flash_get_parameters(const struct device *dev) { - *layout = &flash_sam_pages_layout; - *layout_size = 1; + const struct sam_flash_config *config = dev->config; + + return &config->parameters; } -#endif -static const struct flash_parameters * -flash_sam_get_parameters(const struct device *dev) +static void sam_flash_api_pages_layout(const struct device *dev, + const struct flash_pages_layout **layout, + size_t *layout_size) { - ARG_UNUSED(dev); + const struct sam_flash_config *config = dev->config; - return &flash_sam_parameters; + *layout = config->pages_layouts; + *layout_size = config->pages_layouts_size; } -static int flash_sam_init(const struct device *dev) -{ - struct flash_sam_dev_data *const data = dev->data; +static struct flash_driver_api sam_flash_api = { + .read = sam_flash_read, + .write = sam_flash_write, + .erase = sam_flash_erase, + .get_parameters = sam_flash_get_parameters, + .page_layout = sam_flash_api_pages_layout, +}; - k_sem_init(&data->sem, 1, 1); +static int sam_flash_init(const struct device *dev) +{ + struct sam_flash_data *sam_data = dev->data; + sam_data->dev = dev; return 0; } -static const struct flash_driver_api flash_sam_api = { - .erase = flash_sam_erase, - .write = flash_sam_write, - .read = flash_sam_read, - .get_parameters = flash_sam_get_parameters, -#ifdef CONFIG_FLASH_PAGE_LAYOUT - .page_layout = flash_sam_page_layout, -#endif -}; - -static const struct flash_sam_dev_cfg flash_sam_cfg = { - .regs = (Efc *)DT_INST_REG_ADDR(0), -}; +#define SAM_FLASH_DEVICE DT_INST(0, atmel_sam_flash) -static struct flash_sam_dev_data flash_sam_data; +#define SAM_FLASH_PAGES_LAYOUT(node_id, prop, idx) \ + { \ + .pages_count = DT_PHA_BY_IDX(node_id, prop, idx, pages_count), \ + .pages_size = DT_PHA_BY_IDX(node_id, prop, idx, pages_size), \ + } -DEVICE_DT_INST_DEFINE(0, flash_sam_init, NULL, - &flash_sam_data, &flash_sam_cfg, - POST_KERNEL, CONFIG_FLASH_INIT_PRIORITY, - &flash_sam_api); +#define SAM_FLASH_PAGES_LAYOUTS \ + DT_FOREACH_PROP_ELEM_SEP(SAM_FLASH_DEVICE, erase_blocks, SAM_FLASH_PAGES_LAYOUT, (,)) + +#define SAM_FLASH_CONTROLLER(inst) \ + struct flash_pages_layout sam_flash_pages_layouts##inst[] = { \ + SAM_FLASH_PAGES_LAYOUTS \ + }; \ + \ + static const struct sam_flash_config sam_flash_config##inst = { \ + .regs = (Efc *)DT_INST_REG_ADDR(inst), \ + .area_address = DT_REG_ADDR(SAM_FLASH_DEVICE), \ + .area_size = DT_REG_SIZE(SAM_FLASH_DEVICE), \ + .parameters = { \ + .write_block_size = DT_PROP(SAM_FLASH_DEVICE, write_block_size), \ + .erase_value = 0xFF, \ + }, \ + .pages_layouts = sam_flash_pages_layouts##inst, \ + .pages_layouts_size = ARRAY_SIZE(sam_flash_pages_layouts##inst), \ + }; \ + \ + static struct sam_flash_data sam_flash_data##inst; \ + \ + DEVICE_DT_INST_DEFINE(inst, sam_flash_init, NULL, &sam_flash_data##inst, \ + &sam_flash_config##inst, POST_KERNEL, CONFIG_FLASH_INIT_PRIORITY, \ + &sam_flash_api); + +SAM_FLASH_CONTROLLER(0) diff --git a/dts/bindings/mtd/atmel,sam-flash.yaml b/dts/bindings/mtd/atmel,sam-flash.yaml index 559dcebe4ea..c2a16328105 100644 --- a/dts/bindings/mtd/atmel,sam-flash.yaml +++ b/dts/bindings/mtd/atmel,sam-flash.yaml @@ -112,6 +112,6 @@ properties: required: true description: | The flash controller is limited by hardware to erase whole - blocks of flash at a time. This propery describes the layout of + blocks of flash at a time. This property describes the layout of the erase-blocks, which can vary in size within the flash memory area. From efa4727296711dc37ff78edba0d604491790f28f Mon Sep 17 00:00:00 2001 From: Bjarki Arge Andreasen Date: Fri, 10 Nov 2023 18:14:39 +0100 Subject: [PATCH 2721/3723] drivers: flash: sam: Add logging Add log messages to help diagnose and understand flash driver behavior. Signed-off-by: Bjarki Arge Andreasen --- drivers/flash/flash_sam.c | 31 ++++++++++++++++++++++++++++--- 1 file changed, 28 insertions(+), 3 deletions(-) diff --git a/drivers/flash/flash_sam.c b/drivers/flash/flash_sam.c index d87d766d41f..ab5fe286f98 100644 --- a/drivers/flash/flash_sam.c +++ b/drivers/flash/flash_sam.c @@ -110,6 +110,9 @@ static bool sam_flash_section_is_within_area(const struct device *dev, off_t off return true; } + LOG_WRN("Section from 0x%x to 0x%x is not within flash area (0x0 to %x)", + (size_t)offset, (size_t)(offset + len), (size_t)config->area_size); + return false; } @@ -118,8 +121,15 @@ static bool sam_flash_section_is_aligned_with_write_block_size(const struct devi { const struct sam_flash_config *config = dev->config; - return sam_flash_aligned(offset, config->parameters.write_block_size) && - sam_flash_aligned(len, config->parameters.write_block_size); + if (sam_flash_aligned(offset, config->parameters.write_block_size) && + sam_flash_aligned(len, config->parameters.write_block_size)) { + return true; + } + + LOG_WRN("Section from 0x%x to 0x%x is not aligned with write block size (%u)", + (size_t)offset, (size_t)(offset + len), config->parameters.write_block_size); + + return false; } static bool sam_flash_section_is_aligned_with_pages(const struct device *dev, off_t offset, @@ -237,6 +247,8 @@ static int sam_flash_write(const struct device *dev, off_t offset, const void *d return -EINVAL; } + LOG_DBG("Writing sector from 0x%x to 0x%x", (size_t)offset, (size_t)(offset + len)); + key = k_spin_lock(&sam_data->lock); if (sam_flash_write_dwords_to_flash(dev, offset, data, len / sizeof(uint32_t)) < 0) { k_spin_unlock(&sam_data->lock, key); @@ -285,10 +297,13 @@ static int sam_flash_erase_page(const struct device *dev, const struct flash_pag const struct sam_flash_config *sam_config = dev->config; Efc *regs = sam_config->regs; uint32_t page_index; + int ret; /* Convert from page offset to write page index */ page_index = info->start_offset / SAM_FLASH_WRITE_PAGE_SIZE; + LOG_DBG("Erasing page at 0x%x of size 0x%x", (size_t)info->start_offset, info->size); + /* Perform erase command of page */ switch (info->size) { case 0x800: @@ -319,7 +334,15 @@ static int sam_flash_erase_page(const struct device *dev, const struct flash_pag return -EINVAL; } - return sam_flash_section_wait_until_ready(dev); + ret = sam_flash_section_wait_until_ready(dev); + if (ret == 0) { + return ret; + } + + LOG_ERR("Failed to erase page at 0x%x of size 0x%x", (size_t)info->start_offset, + info->size); + + return ret; } static bool sam_flash_erase_foreach_page(const struct flash_pages_info *info, void *data) @@ -372,6 +395,8 @@ static int sam_flash_erase(const struct device *dev, off_t offset, size_t size) return -EINVAL; } + LOG_DBG("Erasing sector from 0x%x to 0x%x", (size_t)offset, (size_t)(offset + size)); + key = k_spin_lock(&sam_data->lock); sam_data->erase_data.section_start = offset; sam_data->erase_data.section_end = offset + size; From b6c1bf8225e438d53e2778f5fc1b0755ab4af813 Mon Sep 17 00:00:00 2001 From: Bjarki Arge Andreasen Date: Fri, 10 Nov 2023 18:42:52 +0100 Subject: [PATCH 2722/3723] drivers: flash: sam: Use interrupt to sync Use interrupt to wait for flash controller to finish its command and become ready. Signed-off-by: Bjarki Arge Andreasen --- drivers/flash/flash_sam.c | 61 +++++++++++++++++++++++++++++++++++---- dts/arm/atmel/sam3x.dtsi | 1 + dts/arm/atmel/sam4e.dtsi | 1 + dts/arm/atmel/sam4s.dtsi | 1 + 4 files changed, 58 insertions(+), 6 deletions(-) diff --git a/drivers/flash/flash_sam.c b/drivers/flash/flash_sam.c index ab5fe286f98..e4a807552fc 100644 --- a/drivers/flash/flash_sam.c +++ b/drivers/flash/flash_sam.c @@ -27,8 +27,11 @@ LOG_MODULE_REGISTER(flash_sam, CONFIG_FLASH_LOG_LEVEL); #define SAM_FLASH_WRITE_PAGE_SIZE (512) +typedef void (*sam_flash_irq_init_fn_ptr)(void); + struct sam_flash_config { Efc *regs; + sam_flash_irq_init_fn_ptr irq_init; off_t area_address; off_t area_size; struct flash_parameters parameters; @@ -46,6 +49,7 @@ struct sam_flash_data { const struct device *dev; struct k_spinlock lock; struct sam_flash_erase_data erase_data; + struct k_sem ready_sem; }; static bool sam_flash_validate_offset_len(off_t offset, size_t len) @@ -68,29 +72,61 @@ static bool sam_flash_aligned(size_t value, size_t alignment) static bool sam_flash_offset_is_on_write_page_boundary(off_t offset) { - return (sam_flash_aligned(offset, SAM_FLASH_WRITE_PAGE_SIZE)); + return sam_flash_aligned(offset, SAM_FLASH_WRITE_PAGE_SIZE); +} + +static inline void sam_flash_mask_ready_interrupt(const struct sam_flash_config *config) +{ + Efc *regs = config->regs; + + regs->EEFC_FMR &= ~EEFC_FMR_FRDY; +} + +static inline void sam_flash_unmask_ready_interrupt(const struct sam_flash_config *config) +{ + Efc *regs = config->regs; + + regs->EEFC_FMR |= EEFC_FMR_FRDY; +} + +static void sam_flash_isr(const struct device *dev) +{ + struct sam_flash_data *data = dev->data; + const struct sam_flash_config *config = dev->config; + + sam_flash_mask_ready_interrupt(config); + k_sem_give(&data->ready_sem); } static int sam_flash_section_wait_until_ready(const struct device *dev) { + struct sam_flash_data *data = dev->data; const struct sam_flash_config *config = dev->config; Efc *regs = config->regs; + uint32_t eefc_fsr; + + k_sem_reset(&data->ready_sem); + sam_flash_unmask_ready_interrupt(config); - while (!(regs->EEFC_FSR & EEFC_FSR_FRDY)) { - k_msleep(20); + if (k_sem_take(&data->ready_sem, K_MSEC(500)) < 0) { + LOG_ERR("Command did not execute in time"); + return -EFAULT; } - if (regs->EEFC_FSR & EEFC_FSR_FCMDE) { + /* FSR register is cleared on read */ + eefc_fsr = regs->EEFC_FSR; + + if (eefc_fsr & EEFC_FSR_FCMDE) { LOG_ERR("Invalid command requested"); return -EPERM; } - if (regs->EEFC_FSR & EEFC_FSR_FLOCKE) { + if (eefc_fsr & EEFC_FSR_FLOCKE) { LOG_ERR("Tried to modify locked region"); return -EPERM; } - if (regs->EEFC_FSR & EEFC_FSR_FLERR) { + if (eefc_fsr & EEFC_FSR_FLERR) { LOG_ERR("Programming failed"); return -EPERM; } @@ -439,8 +475,12 @@ static struct flash_driver_api sam_flash_api = { static int sam_flash_init(const struct device *dev) { struct sam_flash_data *sam_data = dev->data; + const struct sam_flash_config *sam_config = dev->config; sam_data->dev = dev; + k_sem_init(&sam_data->ready_sem, 0, 1); + sam_flash_mask_ready_interrupt(sam_config); + sam_config->irq_init(); return 0; } @@ -460,8 +500,17 @@ static int sam_flash_init(const struct device *dev) SAM_FLASH_PAGES_LAYOUTS \ }; \ \ + static void sam_flash_irq_init_##inst(void) \ + { \ + IRQ_CONNECT(DT_INST_IRQN(inst), DT_INST_IRQ(inst, priority), \ + sam_flash_isr, DEVICE_DT_INST_GET(inst), 0); \ + irq_enable(DT_INST_IRQN(inst)); \ + \ + } \ + \ static const struct sam_flash_config sam_flash_config##inst = { \ .regs = (Efc *)DT_INST_REG_ADDR(inst), \ + .irq_init = sam_flash_irq_init_##inst, \ .area_address = DT_REG_ADDR(SAM_FLASH_DEVICE), \ .area_size = DT_REG_SIZE(SAM_FLASH_DEVICE), \ .parameters = { \ diff --git a/dts/arm/atmel/sam3x.dtsi b/dts/arm/atmel/sam3x.dtsi index 1fc5dbe9733..67d99418fd2 100644 --- a/dts/arm/atmel/sam3x.dtsi +++ b/dts/arm/atmel/sam3x.dtsi @@ -53,6 +53,7 @@ eefc: flash-controller@400e0a00 { compatible = "atmel,sam-flash-controller"; reg = <0x400e0a00 0x200>; + interrupts = <6 0>; clocks = <&pmc PMC_TYPE_PERIPHERAL 6>; #address-cells = <1>; diff --git a/dts/arm/atmel/sam4e.dtsi b/dts/arm/atmel/sam4e.dtsi index 545030e8334..c90fed140b3 100644 --- a/dts/arm/atmel/sam4e.dtsi +++ b/dts/arm/atmel/sam4e.dtsi @@ -78,6 +78,7 @@ eefc: flash-controller@400e0a00 { compatible = "atmel,sam-flash-controller"; reg = <0x400e0a00 0x200>; + interrupts = <6 0>; clocks = <&pmc PMC_TYPE_PERIPHERAL 6>; status = "okay"; diff --git a/dts/arm/atmel/sam4s.dtsi b/dts/arm/atmel/sam4s.dtsi index dcd74ec6ca8..64828f3a7d5 100644 --- a/dts/arm/atmel/sam4s.dtsi +++ b/dts/arm/atmel/sam4s.dtsi @@ -62,6 +62,7 @@ eefc: flash-controller@400e0a00 { compatible = "atmel,sam-flash-controller"; reg = <0x400e0a00 0x200>; + interrupts = <6 0>; clocks = <&pmc PMC_TYPE_PERIPHERAL 6>; #address-cells = <1>; From 592647cf0b8adb713bdd98bc7e1d67986fda4d3b Mon Sep 17 00:00:00 2001 From: Bjarki Arge Andreasen Date: Fri, 15 Dec 2023 23:48:07 +0100 Subject: [PATCH 2723/3723] tests: flash: Add erase_blocks test for flash controllers Add test suite which tests writing to and erasing all pages, of any size defined by the page layout. If the test is built with MCUBOOT, the test will jump into the application, then run write/erase/boundary tests on the bootload partition. If MCUBOOT is not selected, the test will target the slot1 partition instead, performing the same tests. Signed-off-by: Bjarki Arge Andreasen --- .../drivers/flash/erase_blocks/CMakeLists.txt | 8 + tests/drivers/flash/erase_blocks/prj.conf | 5 + tests/drivers/flash/erase_blocks/src/main.c | 218 ++++++++++++++++++ .../drivers/flash/erase_blocks/sysbuild.conf | 4 + .../drivers/flash/erase_blocks/testcase.yaml | 17 ++ 5 files changed, 252 insertions(+) create mode 100644 tests/drivers/flash/erase_blocks/CMakeLists.txt create mode 100644 tests/drivers/flash/erase_blocks/prj.conf create mode 100644 tests/drivers/flash/erase_blocks/src/main.c create mode 100644 tests/drivers/flash/erase_blocks/sysbuild.conf create mode 100644 tests/drivers/flash/erase_blocks/testcase.yaml diff --git a/tests/drivers/flash/erase_blocks/CMakeLists.txt b/tests/drivers/flash/erase_blocks/CMakeLists.txt new file mode 100644 index 00000000000..e743e085b04 --- /dev/null +++ b/tests/drivers/flash/erase_blocks/CMakeLists.txt @@ -0,0 +1,8 @@ +# Copyright (c) 2023 Bjarki Arge Andreasen +# SPDX-License-Identifier: Apache-2.0 + +cmake_minimum_required(VERSION 3.20.0) +find_package(Zephyr REQUIRED HINTS $ENV{ZEPHYR_BASE}) +project(erase_blocks) + +target_sources(app PRIVATE src/main.c) diff --git a/tests/drivers/flash/erase_blocks/prj.conf b/tests/drivers/flash/erase_blocks/prj.conf new file mode 100644 index 00000000000..527328df1b8 --- /dev/null +++ b/tests/drivers/flash/erase_blocks/prj.conf @@ -0,0 +1,5 @@ +# Copyright (c) 2023 Bjarki Arge Andreasen +# SPDX-License-Identifier: Apache-2.0 + +CONFIG_FLASH=y +CONFIG_ZTEST=y diff --git a/tests/drivers/flash/erase_blocks/src/main.c b/tests/drivers/flash/erase_blocks/src/main.c new file mode 100644 index 00000000000..0269f7c7691 --- /dev/null +++ b/tests/drivers/flash/erase_blocks/src/main.c @@ -0,0 +1,218 @@ +/* + * Copyright (c) 2023 Bjarki Arge Andreasen + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include +#include +#include +#include +#include +#include + +LOG_MODULE_REGISTER(test_flash); + +#ifdef CONFIG_BOOTLOADER_MCUBOOT + +#define TEST_FLASH_PART_NODE \ + DT_NODELABEL(boot_partition) + +#else + +#define TEST_FLASH_PART_NODE \ + DT_NODELABEL(slot1_partition) + +#endif + +#define TEST_FLASH_PART_OFFSET \ + DT_REG_ADDR(TEST_FLASH_PART_NODE) + +#define TEST_FLASH_PART_SIZE \ + DT_REG_SIZE(TEST_FLASH_PART_NODE) + +#define TEST_FLASH_PART_END_OFFSET \ + (TEST_FLASH_PART_OFFSET + TEST_FLASH_PART_SIZE) + +#define TEST_FLASH_CONTROLLER_NODE \ + DT_MTD_FROM_FIXED_PARTITION(TEST_FLASH_PART_NODE) + +static const struct device *flash_controller = DEVICE_DT_GET(TEST_FLASH_CONTROLLER_NODE); +static uint8_t test_write_block[128]; +static uint8_t test_read_block[128]; + +static void test_flash_fill_test_write_block(void) +{ + for (uint8_t i = 0; i < sizeof(test_write_block); i++) { + test_write_block[i] = i; + } +} + +static void *test_flash_setup(void) +{ + test_flash_fill_test_write_block(); + return NULL; +} + +static bool test_flash_mem_is_set_to(const uint8_t *data, uint8_t to, size_t size) +{ + for (size_t i = 0; i < size; i++) { + if (data[i] != to) { + return false; + } + } + + return true; +} + +static bool test_flash_is_erased(off_t offset, size_t size) +{ + static uint8_t test_erase_buffer[99]; + const struct flash_parameters *parameters = flash_get_parameters(flash_controller); + size_t remaining; + size_t readsize; + + while (offset < size) { + remaining = size - (size_t)offset; + readsize = MIN(sizeof(test_erase_buffer), remaining); + + if (flash_read(flash_controller, offset, test_erase_buffer, readsize) < 0) { + return false; + } + + if (!test_flash_mem_is_set_to(test_erase_buffer, parameters->erase_value, + readsize)) { + return false; + } + + offset += (off_t)readsize; + } + + return true; +} + +static bool test_flash_verify_partition_is_erased(void) +{ + return test_flash_is_erased(TEST_FLASH_PART_OFFSET, TEST_FLASH_PART_SIZE); +} + +static int test_flash_erase_partition(void) +{ + LOG_INF("Erasing section of size %zu at offset %zu controlled by %s", + TEST_FLASH_PART_SIZE, + TEST_FLASH_PART_OFFSET, + flash_controller->name); + + return flash_erase(flash_controller, TEST_FLASH_PART_OFFSET, + TEST_FLASH_PART_SIZE); +} + +static void test_flash_before(void *f) +{ + ARG_UNUSED(f); + __ASSERT(test_flash_erase_partition() == 0, + "Failed to erase partition"); + __ASSERT(test_flash_verify_partition_is_erased(), + "Failed to erase partition"); +} + +static void test_flash_write_block_at_offset(off_t offset, size_t size) +{ + zassert_ok(flash_write(flash_controller, offset, test_write_block, size), + "Failed to write block at offset %zu, of size %zu", (size_t)offset, size); + zassert_ok(flash_read(flash_controller, offset, test_read_block, size), + "Failed to read block at offset %zu, of size %zu", (size_t)offset, size); + zassert_ok(memcmp(test_write_block, test_read_block, size), + "Failed to write block at offset %zu, of size %zu to page", (size_t)offset, + size); +} + +static void test_flash_write_across_page_boundary(const struct flash_pages_info *info, + size_t write_block_size) +{ + off_t page_boundary = info->start_offset; + uint32_t page0_index = info->index - 1; + uint32_t page1_index = info->index; + off_t cross_write_start_offset = page_boundary - (off_t)write_block_size; + size_t cross_write_size = write_block_size * 2; + + LOG_INF("Writing across page boundary at %zu, between page index %u and %u", + (size_t)page_boundary, + page0_index, + page1_index); + + test_flash_write_block_at_offset(cross_write_start_offset, cross_write_size); +} + +static bool test_flash_write_across_page_boundaries(const struct flash_pages_info *info, + void *data) +{ + size_t write_block_size = *((size_t *)data); + + if (info->start_offset <= TEST_FLASH_PART_OFFSET) { + /* Not yet reached second page within partition */ + return true; + } + + if (info->start_offset >= TEST_FLASH_PART_END_OFFSET) { + /* Reached first page after partition end */ + return false; + } + + test_flash_write_across_page_boundary(info, write_block_size); + return true; +} + +ZTEST(flash_page_layout, test_write_across_page_boundaries_in_part) +{ + const struct flash_parameters *parameters = flash_get_parameters(flash_controller); + size_t write_block_size = parameters->write_block_size; + + flash_page_foreach(flash_controller, test_flash_write_across_page_boundaries, + &write_block_size); +} + +static void test_flash_erase_page(const struct flash_pages_info *info) +{ + off_t page_offset = info->start_offset; + size_t page_size = info->size; + size_t page_index = info->index; + + LOG_INF("Erasing page at %zu of size %zu with index %zu", + (size_t)page_offset, page_size, page_index); + + zassert_ok(flash_erase(flash_controller, page_offset, page_size), + "Failed to erase page"); + + zassert_true(test_flash_is_erased(page_offset, page_size), + "Failed to erase page"); +} + +static bool test_flash_erase_pages(const struct flash_pages_info *info, void *data) +{ + if (info->start_offset < TEST_FLASH_PART_OFFSET) { + /* Not yet reached first page within partition */ + return true; + } + + if (info->start_offset >= TEST_FLASH_PART_END_OFFSET) { + /* Reached first page after partition end */ + return false; + } + + test_flash_erase_page(info); + return true; +} + +ZTEST(flash_page_layout, test_erase_single_pages_in_part) +{ + const struct flash_parameters *parameters = flash_get_parameters(flash_controller); + size_t write_block_size = parameters->write_block_size; + + flash_page_foreach(flash_controller, test_flash_write_across_page_boundaries, + &write_block_size); + + flash_page_foreach(flash_controller, test_flash_erase_pages, NULL); +} + +ZTEST_SUITE(flash_page_layout, NULL, test_flash_setup, test_flash_before, NULL, NULL); diff --git a/tests/drivers/flash/erase_blocks/sysbuild.conf b/tests/drivers/flash/erase_blocks/sysbuild.conf new file mode 100644 index 00000000000..7692e45673c --- /dev/null +++ b/tests/drivers/flash/erase_blocks/sysbuild.conf @@ -0,0 +1,4 @@ +# Copyright (c) 2023 Bjarki Arge Andreasen +# SPDX-License-Identifier: Apache-2.0 + +SB_CONFIG_BOOTLOADER_MCUBOOT=y diff --git a/tests/drivers/flash/erase_blocks/testcase.yaml b/tests/drivers/flash/erase_blocks/testcase.yaml new file mode 100644 index 00000000000..2382563bd4e --- /dev/null +++ b/tests/drivers/flash/erase_blocks/testcase.yaml @@ -0,0 +1,17 @@ +# Copyright (c) 2023 Bjarki Arge Andreasen +# SPDX-License-Identifier: Apache-2.0 + +common: + sysbuild: true + tags: + - drivers + - flash +tests: + flash.erase_blocks.build_only: + harness: ztest + build_only: true + platform_allow: + - sam_v71_xult + - b_u585i_iot02a + - nrf9160dk_nrf9160 + - nrf5340dk_nrf5340_cpuapp From c3a185f4ee1a8be88983ba6acc1504c8bf2f690e Mon Sep 17 00:00:00 2001 From: Laurentiu Mihalcea Date: Thu, 23 Nov 2023 13:56:12 +0200 Subject: [PATCH 2724/3723] manifest: Bump up hal_nxp revision Bump up hal_nxp revision to contain the EDMA REV2-related changes from NXP HAL. Signed-off-by: Laurentiu Mihalcea --- west.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/west.yml b/west.yml index 0bd2a871b0c..7760e945206 100644 --- a/west.yml +++ b/west.yml @@ -193,7 +193,7 @@ manifest: groups: - hal - name: hal_nxp - revision: 9b2693c7659f37f84bcf2604995c88f7fa5206be + revision: d6d43cab73f1a0fc73ec26084dab3f54c6324d2e path: modules/hal/nxp groups: - hal From 6abc5921e1ce81af50a6c45be8a81c8517569e3e Mon Sep 17 00:00:00 2001 From: Laurentiu Mihalcea Date: Mon, 2 Oct 2023 16:21:53 +0300 Subject: [PATCH 2725/3723] drivers: dma: Introduce driver for NXP's eDMA IP This commit introduces a driver for NXP's eDMA IP. The main reasons for introducing a new driver are the following: 1) The HAL EDMA wrappers don't support well different eDMA versions (e.g: i.MX93 and i.MX8QM). As such, a new revision had to be introduced, thus requiring a new Zephyr driver. 2) The eDMA versions found on i.MX93, i.MX8QM, and i.MX8QXP don't use the DMAMUX IP (instead, channel MUX-ing is performed through an eDMA register in the case of i.MX93). Signed-off-by: Laurentiu Mihalcea --- drivers/dma/CMakeLists.txt | 1 + drivers/dma/Kconfig | 2 + drivers/dma/Kconfig.nxp_edma | 34 ++ drivers/dma/dma_nxp_edma.c | 669 +++++++++++++++++++++++++++++++++ drivers/dma/dma_nxp_edma.h | 530 ++++++++++++++++++++++++++ dts/bindings/dma/nxp,edma.yaml | 41 ++ 6 files changed, 1277 insertions(+) create mode 100644 drivers/dma/Kconfig.nxp_edma create mode 100644 drivers/dma/dma_nxp_edma.c create mode 100644 drivers/dma/dma_nxp_edma.h create mode 100644 dts/bindings/dma/nxp,edma.yaml diff --git a/drivers/dma/CMakeLists.txt b/drivers/dma/CMakeLists.txt index 75eef49a32c..7231848a05a 100644 --- a/drivers/dma/CMakeLists.txt +++ b/drivers/dma/CMakeLists.txt @@ -39,3 +39,4 @@ zephyr_library_sources_ifdef(CONFIG_DMA_SEDI dma_sedi.c) zephyr_library_sources_ifdef(CONFIG_DMA_SMARTBOND dma_smartbond.c) zephyr_library_sources_ifdef(CONFIG_DMA_NXP_SOF_HOST_DMA dma_nxp_sof_host_dma.c) zephyr_library_sources_ifdef(CONFIG_DMA_EMUL dma_emul.c) +zephyr_library_sources_ifdef(CONFIG_DMA_NXP_EDMA dma_nxp_edma.c) diff --git a/drivers/dma/Kconfig b/drivers/dma/Kconfig index 7d2b7f94d90..7f584dae57b 100644 --- a/drivers/dma/Kconfig +++ b/drivers/dma/Kconfig @@ -74,4 +74,6 @@ source "drivers/dma/Kconfig.nxp_sof_host_dma" source "drivers/dma/Kconfig.emul" +source "drivers/dma/Kconfig.nxp_edma" + endif # DMA diff --git a/drivers/dma/Kconfig.nxp_edma b/drivers/dma/Kconfig.nxp_edma new file mode 100644 index 00000000000..3698605451a --- /dev/null +++ b/drivers/dma/Kconfig.nxp_edma @@ -0,0 +1,34 @@ +# Copyright 2024 NXP +# SPDX-License-Identifier: Apache-2.0 + +config DMA_NXP_EDMA + bool "NXP enhanced Direct Memory Access (eDMA) driver" + default y + depends on DT_HAS_NXP_EDMA_ENABLED + help + Enable driver for NXP's eDMA IP. + +if DMA_NXP_EDMA + +config DMA_NXP_EDMA_ALIGN + int "Alignment (in bytes) required for the transfers" + default 8 + help + Use this to set the alignment (in bytes) + used by entities employing this driver to + adjust the addresses and sizes of the memory + regions involved in the transfer process. + This value needs to match one of the possible + values for SSIZE and DSIZE, otherwise the + driver will return an error upon configuration. + +config DMA_NXP_EDMA_ENABLE_HALFMAJOR_IRQ + bool "Set if CPU should be interrupted when CITER = BITER / 2" + default n + help + Enable this configuration if the CPU should be + interrupted when CITER = BITER / 2. Using this, + the CPU will be interrupted when CITER = BITER and + when CITER = BITER / 2. + +endif # DMA_NXP_EDMA diff --git a/drivers/dma/dma_nxp_edma.c b/drivers/dma/dma_nxp_edma.c new file mode 100644 index 00000000000..aea1e25a5f0 --- /dev/null +++ b/drivers/dma/dma_nxp_edma.c @@ -0,0 +1,669 @@ +/* + * Copyright 2024 NXP + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include "dma_nxp_edma.h" + +/* TODO list: + * 1) Support for requesting a specific channel. + * 2) Support for checking if DMA transfer is pending when attempting config. (?) + * 3) Support for error interrupt. + * 4) Support for error if buffer overflow/underrun. + * 5) Ideally, HALFMAJOR should be set on a per-channel basis not through a + * config. If not possible, this should be done through a DTS property. Also, + * maybe do the same for INTMAJOR IRQ. + */ + +static void edma_isr(const void *parameter) +{ + const struct edma_config *cfg; + struct edma_data *data; + struct edma_channel *chan; + int ret; + uint32_t update_size; + + chan = (struct edma_channel *)parameter; + cfg = chan->dev->config; + data = chan->dev->data; + + if (!EDMA_ChannelRegRead(data->hal_cfg, chan->id, EDMA_TCD_CH_INT)) { + /* skip, interrupt was probably triggered by another channel */ + return; + } + + /* clear interrupt */ + EDMA_ChannelRegUpdate(data->hal_cfg, chan->id, + EDMA_TCD_CH_INT, EDMA_TCD_CH_INT_MASK, 0); + + if (chan->cyclic_buffer) { + update_size = chan->bsize; + + if (IS_ENABLED(CONFIG_DMA_NXP_EDMA_ENABLE_HALFMAJOR_IRQ)) { + update_size = chan->bsize / 2; + } else { + update_size = chan->bsize; + } + + /* TODO: add support for error handling here */ + ret = EDMA_CHAN_PRODUCE_CONSUME_A(chan, update_size); + if (ret < 0) { + LOG_ERR("chan %d buffer overflow/underrun", chan->id); + } + } + + /* TODO: are there any sanity checks we have to perform before invoking + * the registered callback? + */ + if (chan->cb) { + chan->cb(chan->dev, chan->arg, chan->id, DMA_STATUS_COMPLETE); + } +} + +static struct edma_channel *lookup_channel(const struct device *dev, + uint32_t chan_id) +{ + struct edma_data *data; + const struct edma_config *cfg; + int i; + + data = dev->data; + cfg = dev->config; + + + /* optimization: if dma-channels property is present then + * the channel data associated with the passed channel ID + * can be found at index chan_id in the array of channels. + */ + if (cfg->contiguous_channels) { + /* check for index out of bounds */ + if (chan_id >= data->ctx.dma_channels) { + return NULL; + } + + return &data->channels[chan_id]; + } + + /* channels are passed through the valid-channels property. + * As such, since some channels may be missing we need to + * look through the entire channels array for an ID match. + */ + for (i = 0; i < data->ctx.dma_channels; i++) { + if (data->channels[i].id == chan_id) { + return &data->channels[i]; + } + } + + return NULL; +} + +static int edma_config(const struct device *dev, uint32_t chan_id, + struct dma_config *dma_cfg) +{ + struct edma_data *data; + const struct edma_config *cfg; + struct edma_channel *chan; + uint32_t transfer_type; + int ret; + + data = dev->data; + cfg = dev->config; + + if (!dma_cfg->head_block) { + LOG_ERR("head block shouldn't be NULL"); + return -EINVAL; + } + + /* validate source data size (SSIZE) */ + if (!EDMA_TransferWidthIsValid(data->hal_cfg, dma_cfg->source_data_size)) { + LOG_ERR("invalid source data size: %d", + dma_cfg->source_data_size); + return -EINVAL; + } + + /* validate destination data size (DSIZE) */ + if (!EDMA_TransferWidthIsValid(data->hal_cfg, dma_cfg->dest_data_size)) { + LOG_ERR("invalid destination data size: %d", + dma_cfg->dest_data_size); + return -EINVAL; + } + + /* validate configured alignment */ + if (!EDMA_TransferWidthIsValid(data->hal_cfg, CONFIG_DMA_NXP_EDMA_ALIGN)) { + LOG_ERR("configured alignment %d is invalid", + CONFIG_DMA_NXP_EDMA_ALIGN); + return -EINVAL; + } + + /* Scatter-Gather configurations currently not supported */ + if (dma_cfg->block_count != 1) { + LOG_ERR("number of blocks %d not supported", dma_cfg->block_count); + return -ENOTSUP; + } + + /* source address shouldn't be NULL */ + if (!dma_cfg->head_block->source_address) { + LOG_ERR("source address cannot be NULL"); + return -EINVAL; + } + + /* destination address shouldn't be NULL */ + if (!dma_cfg->head_block->dest_address) { + LOG_ERR("destination address cannot be NULL"); + return -EINVAL; + } + + /* check source address's (SADDR) alignment with respect to the data size (SSIZE) + * + * Failing to meet this condition will lead to the assertion of the SAE + * bit (see CHn_ES register). + * + * TODO: this will also restrict scenarios such as the following: + * SADDR is 8B aligned and SSIZE is 16B. I've tested this + * scenario and seems to raise no hardware errors (I'm assuming + * because this doesn't break the 8B boundary of the 64-bit system + * I tested it on). Is there a need to allow such a scenario? + */ + if (dma_cfg->head_block->source_address % dma_cfg->source_data_size) { + LOG_ERR("source address 0x%x alignment doesn't match data size %d", + dma_cfg->head_block->source_address, + dma_cfg->source_data_size); + return -EINVAL; + } + + /* check destination address's (DADDR) alignment with respect to the data size (DSIZE) + * Failing to meet this condition will lead to the assertion of the DAE + * bit (see CHn_ES register). + */ + if (dma_cfg->head_block->dest_address % dma_cfg->dest_data_size) { + LOG_ERR("destination address 0x%x alignment doesn't match data size %d", + dma_cfg->head_block->dest_address, + dma_cfg->dest_data_size); + return -EINVAL; + } + + /* source burst length should match destination burst length. + * This is because the burst length is the equivalent of NBYTES which + * is used for both the destination and the source. + */ + if (dma_cfg->source_burst_length != + dma_cfg->dest_burst_length) { + LOG_ERR("source burst length %d doesn't match destination burst length %d", + dma_cfg->source_burst_length, + dma_cfg->dest_burst_length); + return -EINVAL; + } + + /* total number of bytes should be a multiple of NBYTES. + * + * This is needed because the EDMA engine performs transfers based + * on CITER (integer value) and NBYTES, thus it has no knowledge of + * the total transfer size. If the total transfer size is not a + * multiple of NBYTES then we'll end up with copying a wrong number + * of bytes (CITER = TOTAL_SIZE / BITER). This, of course, raises + * no error in the hardware but it's still wrong. + */ + if (dma_cfg->head_block->block_size % dma_cfg->source_burst_length) { + LOG_ERR("block size %d should be a multiple of NBYTES %d", + dma_cfg->head_block->block_size, + dma_cfg->source_burst_length); + return -EINVAL; + } + + /* check if NBYTES is a multiple of MAX(SSIZE, DSIZE). + * + * This stems from the fact that NBYTES needs to be a multiple + * of SSIZE AND DSIZE. If NBYTES is a multiple of MAX(SSIZE, DSIZE) + * then it will for sure satisfy the aforementioned condition (since + * SSIZE and DSIZE are powers of 2). + * + * Failing to meet this condition will lead to the assertion of the + * NCE bit (see CHn_ES register). + */ + if (dma_cfg->source_burst_length % + MAX(dma_cfg->source_data_size, dma_cfg->dest_data_size)) { + LOG_ERR("NBYTES %d should be a multiple of MAX(SSIZE(%d), DSIZE(%d))", + dma_cfg->source_burst_length, + dma_cfg->source_data_size, + dma_cfg->dest_data_size); + return -EINVAL; + } + + /* fetch channel data */ + chan = lookup_channel(dev, chan_id); + if (!chan) { + LOG_ERR("channel ID %u is not valid", chan_id); + return -EINVAL; + } + + /* save the block size for later usage in edma_reload */ + chan->bsize = dma_cfg->head_block->block_size; + + if (dma_cfg->cyclic) { + chan->cyclic_buffer = true; + + chan->stat.read_position = 0; + chan->stat.write_position = 0; + + /* ASSUMPTION: for CONSUMER-type channels, the buffer from + * which the engine consumes should be full, while in the + * case of PRODUCER-type channels it should be empty. + */ + switch (dma_cfg->channel_direction) { + case MEMORY_TO_PERIPHERAL: + chan->type = CHAN_TYPE_CONSUMER; + chan->stat.free = 0; + chan->stat.pending_length = chan->bsize; + break; + case PERIPHERAL_TO_MEMORY: + chan->type = CHAN_TYPE_PRODUCER; + chan->stat.pending_length = 0; + chan->stat.free = chan->bsize; + break; + default: + LOG_ERR("unsupported transfer dir %d for cyclic mode", + dma_cfg->channel_direction); + return -ENOTSUP; + } + } else { + chan->cyclic_buffer = false; + } + + /* change channel's state to CONFIGURED */ + ret = channel_change_state(chan, CHAN_STATE_CONFIGURED); + if (ret < 0) { + LOG_ERR("failed to change channel %d state to CONFIGURED", chan_id); + return ret; + } + + ret = get_transfer_type(dma_cfg->channel_direction, &transfer_type); + if (ret < 0) { + return ret; + } + + chan->cb = dma_cfg->dma_callback; + chan->arg = dma_cfg->user_data; + + /* warning: this sets SOFF and DOFF to SSIZE and DSIZE which are POSITIVE. */ + ret = EDMA_ConfigureTransfer(data->hal_cfg, chan_id, + dma_cfg->head_block->source_address, + dma_cfg->head_block->dest_address, + dma_cfg->source_data_size, + dma_cfg->dest_data_size, + dma_cfg->source_burst_length, + dma_cfg->head_block->block_size, + transfer_type); + if (ret < 0) { + LOG_ERR("failed to configure transfer"); + return to_std_error(ret); + } + + /* TODO: channel MUX should be forced to 0 based on the previous state */ + if (EDMA_HAS_MUX(data->hal_cfg)) { + ret = EDMA_SetChannelMux(data->hal_cfg, chan_id, dma_cfg->dma_slot); + if (ret < 0) { + LOG_ERR("failed to set channel MUX"); + return to_std_error(ret); + } + } + + /* set SLAST and DLAST */ + ret = set_slast_dlast(dma_cfg, transfer_type, data, chan_id); + if (ret < 0) { + return ret; + } + + /* allow interrupting the CPU when a major cycle is completed. + * + * interesting note: only 1 major loop is performed per slave peripheral + * DMA request. For instance, if block_size = 768 and burst_size = 192 + * we're going to get 4 transfers of 192 bytes. Each of these transfers + * translates to a DMA request made by the slave peripheral. + */ + EDMA_ChannelRegUpdate(data->hal_cfg, chan_id, + EDMA_TCD_CSR, EDMA_TCD_CSR_INTMAJOR_MASK, 0); + + if (IS_ENABLED(CONFIG_DMA_NXP_EDMA_ENABLE_HALFMAJOR_IRQ)) { + /* if enabled through the above configuration, also + * allow the CPU to be interrupted when CITER = BITER / 2. + */ + EDMA_ChannelRegUpdate(data->hal_cfg, chan_id, EDMA_TCD_CSR, + EDMA_TCD_CSR_INTHALF_MASK, 0); + } + + /* enable channel interrupt */ + irq_enable(chan->irq); + + /* dump register status - for debugging purposes */ + edma_dump_channel_registers(data, chan_id); + + return 0; +} + +static int edma_get_status(const struct device *dev, uint32_t chan_id, + struct dma_status *stat) +{ + struct edma_data *data; + struct edma_channel *chan; + uint32_t citer, biter, done; + unsigned int key; + + data = dev->data; + + /* fetch channel data */ + chan = lookup_channel(dev, chan_id); + if (!chan) { + LOG_ERR("channel ID %u is not valid", chan_id); + return -EINVAL; + } + + if (chan->cyclic_buffer) { + key = irq_lock(); + + stat->free = chan->stat.free; + stat->pending_length = chan->stat.pending_length; + + irq_unlock(key); + } else { + /* note: no locking required here. The DMA interrupts + * have no effect over CITER and BITER. + */ + citer = EDMA_ChannelRegRead(data->hal_cfg, chan_id, EDMA_TCD_CITER); + biter = EDMA_ChannelRegRead(data->hal_cfg, chan_id, EDMA_TCD_BITER); + done = EDMA_ChannelRegRead(data->hal_cfg, chan_id, EDMA_TCD_CH_CSR) & + EDMA_TCD_CH_CSR_DONE_MASK; + if (done) { + stat->free = chan->bsize; + stat->pending_length = 0; + } else { + stat->free = (biter - citer) * (chan->bsize / biter); + stat->pending_length = chan->bsize - stat->free; + } + } + + LOG_DBG("free: %d, pending: %d", stat->free, stat->pending_length); + + return 0; +} + +static int edma_suspend(const struct device *dev, uint32_t chan_id) +{ + struct edma_data *data; + const struct edma_config *cfg; + struct edma_channel *chan; + int ret; + + data = dev->data; + cfg = dev->config; + + /* fetch channel data */ + chan = lookup_channel(dev, chan_id); + if (!chan) { + LOG_ERR("channel ID %u is not valid", chan_id); + return -EINVAL; + } + + edma_dump_channel_registers(data, chan_id); + + /* change channel's state to SUSPENDED */ + ret = channel_change_state(chan, CHAN_STATE_SUSPENDED); + if (ret < 0) { + LOG_ERR("failed to change channel %d state to SUSPENDED", chan_id); + return ret; + } + + LOG_DBG("suspending channel %u", chan_id); + + /* disable HW requests */ + EDMA_ChannelRegUpdate(data->hal_cfg, chan_id, + EDMA_TCD_CH_CSR, 0, EDMA_TCD_CH_CSR_ERQ_MASK); + + return 0; +} + +static int edma_stop(const struct device *dev, uint32_t chan_id) +{ + struct edma_data *data; + const struct edma_config *cfg; + struct edma_channel *chan; + enum channel_state prev_state; + int ret; + + data = dev->data; + cfg = dev->config; + + /* fetch channel data */ + chan = lookup_channel(dev, chan_id); + if (!chan) { + LOG_ERR("channel ID %u is not valid", chan_id); + return -EINVAL; + } + + prev_state = chan->state; + + /* change channel's state to STOPPED */ + ret = channel_change_state(chan, CHAN_STATE_STOPPED); + if (ret < 0) { + LOG_ERR("failed to change channel %d state to STOPPED", chan_id); + return ret; + } + + LOG_DBG("stopping channel %u", chan_id); + + if (prev_state == CHAN_STATE_SUSPENDED) { + /* if the channel has been suspended then there's + * no point in disabling the HW requests again. Just + * jump to the channel release operation. + */ + goto out_release_channel; + } + + /* disable HW requests */ + EDMA_ChannelRegUpdate(data->hal_cfg, chan_id, EDMA_TCD_CH_CSR, 0, + EDMA_TCD_CH_CSR_ERQ_MASK); +out_release_channel: + + /* clear the channel MUX so that it can used by a different peripheral. + * + * note: because the channel is released during dma_stop() that means + * dma_start() can no longer be immediately called. This is because + * one needs to re-configure the channel MUX which can only be done + * through dma_config(). As such, if one intends to reuse the current + * configuration then please call dma_suspend() instead of dma_stop(). + */ + if (EDMA_HAS_MUX(data->hal_cfg)) { + ret = EDMA_SetChannelMux(data->hal_cfg, chan_id, 0); + if (ret < 0) { + LOG_ERR("failed to set channel MUX"); + return to_std_error(ret); + } + } + + edma_dump_channel_registers(data, chan_id); + + return 0; +} + +static int edma_start(const struct device *dev, uint32_t chan_id) +{ + struct edma_data *data; + const struct edma_config *cfg; + struct edma_channel *chan; + int ret; + + data = dev->data; + cfg = dev->config; + + /* fetch channel data */ + chan = lookup_channel(dev, chan_id); + if (!chan) { + LOG_ERR("channel ID %u is not valid", chan_id); + return -EINVAL; + } + + /* change channel's state to STARTED */ + ret = channel_change_state(chan, CHAN_STATE_STARTED); + if (ret < 0) { + LOG_ERR("failed to change channel %d state to STARTED", chan_id); + return ret; + } + + LOG_DBG("starting channel %u", chan_id); + + /* enable HW requests */ + EDMA_ChannelRegUpdate(data->hal_cfg, chan_id, + EDMA_TCD_CH_CSR, EDMA_TCD_CH_CSR_ERQ_MASK, 0); + + return 0; +} + +static int edma_reload(const struct device *dev, uint32_t chan_id, uint32_t src, + uint32_t dst, size_t size) +{ + struct edma_data *data; + struct edma_channel *chan; + int ret; + unsigned int key; + + data = dev->data; + + /* fetch channel data */ + chan = lookup_channel(dev, chan_id); + if (!chan) { + LOG_ERR("channel ID %u is not valid", chan_id); + return -EINVAL; + } + + /* channel needs to be started to allow reloading */ + if (chan->state != CHAN_STATE_STARTED) { + LOG_ERR("reload is only supported on started channels"); + return -EINVAL; + } + + if (chan->cyclic_buffer) { + key = irq_lock(); + ret = EDMA_CHAN_PRODUCE_CONSUME_B(chan, size); + irq_unlock(key); + if (ret < 0) { + LOG_ERR("chan %d buffer overflow/underrun", chan_id); + return ret; + } + } + + return 0; +} + +static int edma_get_attribute(const struct device *dev, uint32_t type, uint32_t *val) +{ + switch (type) { + case DMA_ATTR_BUFFER_SIZE_ALIGNMENT: + case DMA_ATTR_BUFFER_ADDRESS_ALIGNMENT: + *val = CONFIG_DMA_NXP_EDMA_ALIGN; + break; + case DMA_ATTR_MAX_BLOCK_COUNT: + /* this is restricted to 1 because SG configurations are not supported */ + *val = 1; + break; + default: + LOG_ERR("invalid attribute type: %d", type); + return -EINVAL; + } + + return 0; +} + +static const struct dma_driver_api edma_api = { + .reload = edma_reload, + .config = edma_config, + .start = edma_start, + .stop = edma_stop, + .suspend = edma_suspend, + .resume = edma_start, + .get_status = edma_get_status, + .get_attribute = edma_get_attribute, +}; + +static int edma_init(const struct device *dev) +{ + const struct edma_config *cfg; + struct edma_data *data; + mm_reg_t regmap; + + data = dev->data; + cfg = dev->config; + + /* map instance MMIO */ + device_map(®map, cfg->regmap_phys, cfg->regmap_size, K_MEM_CACHE_NONE); + + /* overwrite physical address set in the HAL configuration. + * We can down-cast the virtual address to a 32-bit address because + * we know we're working with 32-bit addresses only. + */ + data->hal_cfg->regmap = (uint32_t)POINTER_TO_UINT(regmap); + + cfg->irq_config(); + + /* dma_request_channel() uses this variable to keep track of the + * available channels. As such, it needs to be initialized with NULL + * which signifies that all channels are initially available. + */ + data->channel_flags = ATOMIC_INIT(0); + data->ctx.atomic = &data->channel_flags; + + return 0; +} + +/* a few comments about the BUILD_ASSERT statements: + * 1) dma-channels and valid-channels should be mutually exclusive. + * This means that you specify the one or the other. There's no real + * need to have both of them. + * 2) Number of channels should match the number of interrupts for + * said channels (TODO: what about error interrupts?) + * 3) The channel-mux property shouldn't be specified unless + * the eDMA is MUX-capable (signaled via the EDMA_HAS_CHAN_MUX + * configuration). + */ +#define EDMA_INIT(inst) \ + \ +BUILD_ASSERT(!DT_NODE_HAS_PROP(DT_INST(inst, DT_DRV_COMPAT), dma_channels) || \ + !DT_NODE_HAS_PROP(DT_INST(inst, DT_DRV_COMPAT), valid_channels), \ + "dma_channels and valid_channels are mutually exclusive"); \ + \ +BUILD_ASSERT(DT_INST_PROP_OR(inst, dma_channels, 0) == \ + DT_NUM_IRQS(DT_INST(inst, DT_DRV_COMPAT)) || \ + DT_INST_PROP_LEN_OR(inst, valid_channels, 0) == \ + DT_NUM_IRQS(DT_INST(inst, DT_DRV_COMPAT)), \ + "number of interrupts needs to match number of channels"); \ + \ +BUILD_ASSERT(DT_PROP_OR(DT_INST(inst, DT_DRV_COMPAT), hal_cfg_index, 0) < \ + ARRAY_SIZE(s_edmaConfigs), \ + "HAL configuration index out of bounds"); \ + \ +static struct edma_channel channels_##inst[] = EDMA_CHANNEL_ARRAY_GET(inst); \ + \ +static void interrupt_config_function_##inst(void) \ +{ \ + EDMA_CONNECT_INTERRUPTS(inst); \ +} \ + \ +static struct edma_config edma_config_##inst = { \ + .regmap_phys = DT_INST_REG_ADDR(inst), \ + .regmap_size = DT_INST_REG_SIZE(inst), \ + .irq_config = interrupt_config_function_##inst, \ + .contiguous_channels = EDMA_CHANS_ARE_CONTIGUOUS(inst), \ +}; \ + \ +static struct edma_data edma_data_##inst = { \ + .channels = channels_##inst, \ + .ctx.dma_channels = ARRAY_SIZE(channels_##inst), \ + .ctx.magic = DMA_MAGIC, \ + .hal_cfg = &EDMA_HAL_CFG_GET(inst), \ +}; \ + \ +DEVICE_DT_INST_DEFINE(inst, &edma_init, NULL, \ + &edma_data_##inst, &edma_config_##inst, \ + PRE_KERNEL_1, CONFIG_DMA_INIT_PRIORITY, \ + &edma_api); \ + +DT_INST_FOREACH_STATUS_OKAY(EDMA_INIT); diff --git a/drivers/dma/dma_nxp_edma.h b/drivers/dma/dma_nxp_edma.h new file mode 100644 index 00000000000..234b3fcb70a --- /dev/null +++ b/drivers/dma/dma_nxp_edma.h @@ -0,0 +1,530 @@ +/* + * Copyright 2024 NXP + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#ifndef ZEPHYR_DRIVERS_DMA_DMA_NXP_EDMA_H_ +#define ZEPHYR_DRIVERS_DMA_DMA_NXP_EDMA_H_ + +#include +#include +#include +#include + +#include "fsl_edma_soc_rev2.h" + +LOG_MODULE_REGISTER(nxp_edma); + +/* used for driver binding */ +#define DT_DRV_COMPAT nxp_edma + +/* workaround the fact that device_map() is not defined for SoCs with no MMU */ +#ifndef DEVICE_MMIO_IS_IN_RAM +#define device_map(virt, phys, size, flags) *(virt) = (phys) +#endif /* DEVICE_MMIO_IS_IN_RAM */ + +/* macros used to parse DTS properties */ + +/* used in conjunction with LISTIFY which expects F to also take a variable + * number of arguments. Since IDENTITY doesn't do that we need to use a version + * of it which also takes a variable number of arguments. + */ +#define IDENTITY_VARGS(V, ...) IDENTITY(V) + +/* used to generate an array of indexes for the channels */ +#define _EDMA_CHANNEL_INDEX_ARRAY(inst)\ + LISTIFY(DT_INST_PROP_LEN_OR(inst, valid_channels, 0), IDENTITY_VARGS, (,)) + +/* used to generate an array of indexes for the channels - this is different + * from _EDMA_CHANNEL_INDEX_ARRAY because the number of channels is passed + * explicitly through dma-channels so no need to deduce it from the length + * of the valid-channels property. + */ +#define _EDMA_CHANNEL_INDEX_ARRAY_EXPLICIT(inst)\ + LISTIFY(DT_INST_PROP_OR(inst, dma_channels, 0), IDENTITY_VARGS, (,)) + +/* used to generate an array of indexes for the interrupt */ +#define _EDMA_INT_INDEX_ARRAY(inst)\ + LISTIFY(DT_NUM_IRQS(DT_INST(inst, DT_DRV_COMPAT)), IDENTITY_VARGS, (,)) + +/* used to register an ISR/arg pair. TODO: should we also use the priority? */ +#define _EDMA_INT_CONNECT(idx, inst) \ + IRQ_CONNECT(DT_INST_IRQ_BY_IDX(inst, idx, irq), \ + 0, edma_isr, \ + &channels_##inst[idx], 0) + +/* used to declare a struct edma_channel by the non-explicit macro suite */ +#define _EDMA_CHANNEL_DECLARE(idx, inst) \ +{ \ + .id = DT_INST_PROP_BY_IDX(inst, valid_channels, idx), \ + .dev = DEVICE_DT_INST_GET(inst), \ + .irq = DT_INST_IRQ_BY_IDX(inst, idx, irq), \ +} + +/* used to declare a struct edma_channel by the explicit macro suite */ +#define _EDMA_CHANNEL_DECLARE_EXPLICIT(idx, inst) \ +{ \ + .id = idx, \ + .dev = DEVICE_DT_INST_GET(inst), \ + .irq = DT_INST_IRQ_BY_IDX(inst, idx, irq), \ +} + +/* used to create an array of channel IDs via the valid-channels property */ +#define _EDMA_CHANNEL_ARRAY(inst) \ + { FOR_EACH_FIXED_ARG(_EDMA_CHANNEL_DECLARE, (,), \ + inst, _EDMA_CHANNEL_INDEX_ARRAY(inst)) } + +/* used to create an array of channel IDs via the dma-channels property */ +#define _EDMA_CHANNEL_ARRAY_EXPLICIT(inst) \ + { FOR_EACH_FIXED_ARG(_EDMA_CHANNEL_DECLARE_EXPLICIT, (,), inst, \ + _EDMA_CHANNEL_INDEX_ARRAY_EXPLICIT(inst)) } + +/* used to construct the channel array based on the specified property: + * dma-channels or valid-channels. + */ +#define EDMA_CHANNEL_ARRAY_GET(inst) \ + COND_CODE_1(DT_NODE_HAS_PROP(DT_INST(inst, DT_DRV_COMPAT), dma_channels), \ + (_EDMA_CHANNEL_ARRAY_EXPLICIT(inst)), \ + (_EDMA_CHANNEL_ARRAY(inst))) + +#define EDMA_HAL_CFG_GET(inst) \ + COND_CODE_1(DT_NODE_HAS_PROP(DT_INST(inst, DT_DRV_COMPAT), hal_cfg_index), \ + (s_edmaConfigs[DT_INST_PROP(inst, hal_cfg_index)]), \ + (s_edmaConfigs[0])) + +/* used to register edma_isr for all specified interrupts */ +#define EDMA_CONNECT_INTERRUPTS(inst) \ + FOR_EACH_FIXED_ARG(_EDMA_INT_CONNECT, (;), \ + inst, _EDMA_INT_INDEX_ARRAY(inst)) + +#define EDMA_CHANS_ARE_CONTIGUOUS(inst)\ + DT_NODE_HAS_PROP(DT_INST(inst, DT_DRV_COMPAT), dma_channels) + +/* utility macros */ + +/* a few words about EDMA_CHAN_PRODUCE_CONSUME_{A/B}: + * - in the context of cyclic buffers we introduce + * the concepts of consumer and producer channels. + * + * - a consumer channel is a channel for which the + * DMA copies data from a buffer, thus leading to + * less data in said buffer (data is consumed with + * each transfer). + * + * - a producer channel is a channel for which the + * DMA copies data into a buffer, thus leading to + * more data in said buffer (data is produced with + * each transfer). + * + * - for consumer channels, each DMA interrupt will + * signal that an amount of data has been consumed + * from the buffer (half of the buffer size if + * HALFMAJOR is enabled, the whole buffer otherwise). + * + * - for producer channels, each DMA interrupt will + * signal that an amount of data has been added + * to the buffer. + * + * - to signal this, the ISR uses EDMA_CHAN_PRODUCE_CONSUME_A + * which will "consume" data from the buffer for + * consumer channels and "produce" data for + * producer channels. + * + * - since the upper layers using this driver need + * to let the EDMA driver know whenever they've produced + * (in the case of consumer channels) or consumed + * data (in the case of producer channels) they can + * do so through the reload() function. + * + * - reload() uses EDMA_CHAN_PRODUCE_CONSUME_B which + * for consumer channels will "produce" data and + * "consume" data for producer channels, thus letting + * the driver know what action the upper layer has + * performed (if the channel is a consumer it's only + * natural that the upper layer will write/produce more + * data to the buffer. The same rationale applies to + * producer channels). + * + * - EDMA_CHAN_PRODUCE_CONSUME_B is just the opposite + * of EDMA_CHAN_PRODUCE_CONSUME_A. If one produces + * data, the other will consume and vice-versa. + * + * - all of this information is valid only in the + * context of cyclic buffers. If this behaviour is + * not enabled, querying the status will simply + * resolve to querying CITER and BITER. + */ +#define EDMA_CHAN_PRODUCE_CONSUME_A(chan, size)\ + ((chan)->type == CHAN_TYPE_CONSUMER ?\ + edma_chan_cyclic_consume(chan, size) :\ + edma_chan_cyclic_produce(chan, size)) + +#define EDMA_CHAN_PRODUCE_CONSUME_B(chan, size)\ + ((chan)->type == CHAN_TYPE_CONSUMER ?\ + edma_chan_cyclic_produce(chan, size) :\ + edma_chan_cyclic_consume(chan, size)) + +enum channel_type { + CHAN_TYPE_CONSUMER = 0, + CHAN_TYPE_PRODUCER, +}; + +enum channel_state { + CHAN_STATE_INIT = 0, + CHAN_STATE_CONFIGURED, + CHAN_STATE_STARTED, + CHAN_STATE_STOPPED, + CHAN_STATE_SUSPENDED, +}; + +struct edma_channel { + /* channel ID, needs to be the same as the hardware channel ID */ + uint32_t id; + /* pointer to device representing the EDMA instance, used by edma_isr */ + const struct device *dev; + /* current state of the channel */ + enum channel_state state; + /* type of the channel (PRODUCER/CONSUMER) - only applicable to cyclic + * buffer configurations. + */ + enum channel_type type; + /* argument passed to the user-defined DMA callback */ + void *arg; + /* user-defined callback, called at the end of a channel's interrupt + * handling. + */ + dma_callback_t cb; + /* INTID associated with the channel */ + int irq; + /* the channel's status */ + struct dma_status stat; + /* cyclic buffer size - currently, this is set to head_block's size */ + uint32_t bsize; + /* set to true if the channel uses a cyclic buffer configuration */ + bool cyclic_buffer; +}; + +struct edma_data { + /* this needs to be the first member */ + struct dma_context ctx; + mm_reg_t regmap; + struct edma_channel *channels; + atomic_t channel_flags; + edma_config_t *hal_cfg; +}; + +struct edma_config { + uint32_t regmap_phys; + uint32_t regmap_size; + void (*irq_config)(void); + /* true if channels are contiguous. The channels may not be contiguous + * if the valid-channels property is used instead of dma-channels. This + * is used to improve the time complexity of the channel lookup + * function. + */ + bool contiguous_channels; +}; + +static inline int channel_change_state(struct edma_channel *chan, + enum channel_state next) +{ + enum channel_state prev = chan->state; + + LOG_DBG("attempting to change state from %d to %d for channel %d", prev, next, chan->id); + + /* validate transition */ + switch (prev) { + case CHAN_STATE_INIT: + if (next != CHAN_STATE_CONFIGURED) { + return -EPERM; + } + break; + case CHAN_STATE_CONFIGURED: + if (next != CHAN_STATE_STARTED) { + return -EPERM; + } + break; + case CHAN_STATE_STARTED: + if (next != CHAN_STATE_STOPPED && + next != CHAN_STATE_SUSPENDED) { + return -EPERM; + } + break; + case CHAN_STATE_STOPPED: + if (next != CHAN_STATE_CONFIGURED) { + return -EPERM; + } + break; + case CHAN_STATE_SUSPENDED: + if (next != CHAN_STATE_STARTED && + next != CHAN_STATE_STOPPED) { + return -EPERM; + } + break; + default: + LOG_ERR("invalid channel previous state: %d", prev); + return -EINVAL; + } + + /* transition OK, proceed */ + chan->state = next; + + return 0; +} + +static inline int get_transfer_type(enum dma_channel_direction dir, uint32_t *type) +{ + switch (dir) { + case MEMORY_TO_MEMORY: + *type = kEDMA_TransferTypeM2M; + break; + case MEMORY_TO_PERIPHERAL: + *type = kEDMA_TransferTypeM2P; + break; + case PERIPHERAL_TO_MEMORY: + *type = kEDMA_TransferTypeP2M; + break; + default: + LOG_ERR("invalid channel direction: %d", dir); + return -EINVAL; + } + + return 0; +} + +static inline bool data_size_is_valid(uint16_t size) +{ + switch (size) { + case 1: + case 2: + case 4: + case 8: + case 16: + case 32: + case 64: + break; + default: + return false; + } + + return true; +} + +/* TODO: we may require setting the channel type through DTS + * or through struct dma_config. For now, we'll only support + * MEMORY_TO_PERIPHERAL and PERIPHERAL_TO_MEMORY directions + * and assume that these are bound to a certain channel type. + */ +static inline int edma_set_channel_type(struct edma_channel *chan, + enum dma_channel_direction dir) +{ + switch (dir) { + case MEMORY_TO_PERIPHERAL: + chan->type = CHAN_TYPE_CONSUMER; + break; + case PERIPHERAL_TO_MEMORY: + chan->type = CHAN_TYPE_PRODUCER; + break; + default: + LOG_ERR("unsupported transfer direction: %d", dir); + return -ENOTSUP; + } + + return 0; +} + +/* this function is used in cyclic buffer configurations. What it does + * is it updates the channel's read position based on the number of + * bytes requested. If the number of bytes that's being read is higher + * than the number of bytes available in the buffer (pending_length) + * this will lead to an error. The main point of this check is to + * provide a way for the user to determine if data is consumed at a + * higher rate than it is being produced. + * + * This function is used in edma_isr() for CONSUMER channels to mark + * that data has been consumed (i.e: data has been transferred to the + * destination) (this is done via EDMA_CHAN_PRODUCE_CONSUME_A that's + * called in edma_isr()). For producer channels, this function is used + * in edma_reload() to mark the fact that the user of the EDMA driver + * has consumed data. + */ +static inline int edma_chan_cyclic_consume(struct edma_channel *chan, + uint32_t bytes) +{ + if (bytes > chan->stat.pending_length) { + return -EINVAL; + } + + chan->stat.read_position = + (chan->stat.read_position + bytes) % chan->bsize; + + if (chan->stat.read_position > chan->stat.write_position) { + chan->stat.free = chan->stat.read_position - + chan->stat.write_position; + } else if (chan->stat.read_position == chan->stat.write_position) { + chan->stat.free = chan->bsize; + } else { + chan->stat.free = chan->bsize - + (chan->stat.write_position - chan->stat.read_position); + } + + chan->stat.pending_length = chan->bsize - chan->stat.free; + + return 0; +} + +/* this function is used in cyclic buffer configurations. What it does + * is it updates the channel's write position based on the number of + * bytes requested. If the number of bytes that's being written is higher + * than the number of free bytes in the buffer this will lead to an error. + * The main point of this check is to provide a way for the user to determine + * if data is produced at a higher rate than it is being consumed. + * + * This function is used in edma_isr() for PRODUCER channels to mark + * that data has been produced (i.e: data has been transferred to the + * destination) (this is done via EDMA_CHAN_PRODUCE_CONSUME_A that's + * called in edma_isr()). For consumer channels, this function is used + * in edma_reload() to mark the fact that the user of the EDMA driver + * has produced data. + */ +static inline int edma_chan_cyclic_produce(struct edma_channel *chan, + uint32_t bytes) +{ + if (bytes > chan->stat.free) { + return -EINVAL; + } + + chan->stat.write_position = + (chan->stat.write_position + bytes) % chan->bsize; + + if (chan->stat.write_position > chan->stat.read_position) { + chan->stat.pending_length = chan->stat.write_position - + chan->stat.read_position; + } else if (chan->stat.write_position == chan->stat.read_position) { + chan->stat.pending_length = chan->bsize; + } else { + chan->stat.pending_length = chan->bsize - + (chan->stat.read_position - chan->stat.write_position); + } + + chan->stat.free = chan->bsize - chan->stat.pending_length; + + return 0; +} + +static inline void edma_dump_channel_registers(struct edma_data *data, + uint32_t chan_id) +{ + LOG_DBG("dumping channel data for channel %d", chan_id); + + LOG_DBG("CH_CSR: 0x%x", + EDMA_ChannelRegRead(data->hal_cfg, chan_id, EDMA_TCD_CH_CSR)); + LOG_DBG("CH_ES: 0x%x", + EDMA_ChannelRegRead(data->hal_cfg, chan_id, EDMA_TCD_CH_ES)); + LOG_DBG("CH_INT: 0x%x", + EDMA_ChannelRegRead(data->hal_cfg, chan_id, EDMA_TCD_CH_INT)); + LOG_DBG("CH_SBR: 0x%x", + EDMA_ChannelRegRead(data->hal_cfg, chan_id, EDMA_TCD_CH_SBR)); + LOG_DBG("CH_PRI: 0x%x", + EDMA_ChannelRegRead(data->hal_cfg, chan_id, EDMA_TCD_CH_PRI)); + + if (EDMA_HAS_MUX(data->hal_cfg)) { + LOG_DBG("CH_MUX: 0x%x", + EDMA_ChannelRegRead(data->hal_cfg, chan_id, EDMA_TCD_CH_MUX)); + } + + LOG_DBG("TCD_SADDR: 0x%x", + EDMA_ChannelRegRead(data->hal_cfg, chan_id, EDMA_TCD_SADDR)); + LOG_DBG("TCD_SOFF: 0x%x", + EDMA_ChannelRegRead(data->hal_cfg, chan_id, EDMA_TCD_SOFF)); + LOG_DBG("TCD_ATTR: 0x%x", + EDMA_ChannelRegRead(data->hal_cfg, chan_id, EDMA_TCD_ATTR)); + LOG_DBG("TCD_NBYTES: 0x%x", + EDMA_ChannelRegRead(data->hal_cfg, chan_id, EDMA_TCD_NBYTES)); + LOG_DBG("TCD_SLAST_SDA: 0x%x", + EDMA_ChannelRegRead(data->hal_cfg, chan_id, EDMA_TCD_SLAST_SDA)); + LOG_DBG("TCD_DADDR: 0x%x", + EDMA_ChannelRegRead(data->hal_cfg, chan_id, EDMA_TCD_DADDR)); + LOG_DBG("TCD_DOFF: 0x%x", + EDMA_ChannelRegRead(data->hal_cfg, chan_id, EDMA_TCD_DOFF)); + LOG_DBG("TCD_CITER: 0x%x", + EDMA_ChannelRegRead(data->hal_cfg, chan_id, EDMA_TCD_CITER)); + LOG_DBG("TCD_DLAST_SGA: 0x%x", + EDMA_ChannelRegRead(data->hal_cfg, chan_id, EDMA_TCD_DLAST_SGA)); + LOG_DBG("TCD_CSR: 0x%x", + EDMA_ChannelRegRead(data->hal_cfg, chan_id, EDMA_TCD_CSR)); + LOG_DBG("TCD_BITER: 0x%x", + EDMA_ChannelRegRead(data->hal_cfg, chan_id, EDMA_TCD_BITER)); +} + +static inline int set_slast_dlast(struct dma_config *dma_cfg, + uint32_t transfer_type, + struct edma_data *data, + uint32_t chan_id) +{ + int32_t slast, dlast; + + if (transfer_type == kEDMA_TransferTypeP2M) { + slast = 0; + } else { + switch (dma_cfg->head_block->source_addr_adj) { + case DMA_ADDR_ADJ_INCREMENT: + slast = (int32_t)dma_cfg->head_block->block_size; + break; + case DMA_ADDR_ADJ_DECREMENT: + slast = (-1) * (int32_t)dma_cfg->head_block->block_size; + break; + default: + LOG_ERR("unsupported SADDR adjustment: %d", + dma_cfg->head_block->source_addr_adj); + return -EINVAL; + } + } + + if (transfer_type == kEDMA_TransferTypeM2P) { + dlast = 0; + } else { + switch (dma_cfg->head_block->dest_addr_adj) { + case DMA_ADDR_ADJ_INCREMENT: + dlast = (int32_t)dma_cfg->head_block->block_size; + break; + case DMA_ADDR_ADJ_DECREMENT: + dlast = (-1) * (int32_t)dma_cfg->head_block->block_size; + break; + default: + LOG_ERR("unsupported DADDR adjustment: %d", + dma_cfg->head_block->dest_addr_adj); + return -EINVAL; + } + } + + LOG_DBG("attempting to commit SLAST %d", slast); + LOG_DBG("attempting to commit DLAST %d", dlast); + + /* commit configuration */ + EDMA_ChannelRegWrite(data->hal_cfg, chan_id, EDMA_TCD_SLAST_SDA, slast); + EDMA_ChannelRegWrite(data->hal_cfg, chan_id, EDMA_TCD_DLAST_SGA, dlast); + + return 0; +} + +/* the NXP HAL EDMA driver uses some custom return values + * that need to be converted to standard error codes. This function + * performs exactly this translation. + */ +static inline int to_std_error(int edma_err) +{ + switch (edma_err) { + case kStatus_EDMA_InvalidConfiguration: + case kStatus_InvalidArgument: + return -EINVAL; + case kStatus_Busy: + return -EBUSY; + default: + LOG_ERR("unknown EDMA error code: %d", edma_err); + return -EINVAL; + } +} + +#endif /* ZEPHYR_DRIVERS_DMA_DMA_NXP_EDMA_H_ */ diff --git a/dts/bindings/dma/nxp,edma.yaml b/dts/bindings/dma/nxp,edma.yaml new file mode 100644 index 00000000000..5c3305cb7dd --- /dev/null +++ b/dts/bindings/dma/nxp,edma.yaml @@ -0,0 +1,41 @@ +# Copyright 2024 NXP +# SPDX-License-Identifier: Apache-2.0 + +description: NXP enhanced Direct Memory Access (eDMA) node + +compatible: "nxp,edma" + +include: [dma-controller.yaml, base.yaml] + +properties: + reg: + required: true + valid-channels: + type: array + description: | + Use this property to specify which channel indexes are + to be considered valid. The difference between this + property and "dma-channels" is the fact that this + property allows you to have "gaps" between the channel + indexes. This is useful in cases where you know you're + not going to be using all of the possible channels, thus + leading to a more readable DTS. Of course, this property + and "dma-channels" are mutually exclusive, meaning you + can't specify both properties as this will lead to a + BUILD_ASSERT() failure. + hal-cfg-index: + type: int + description: | + Use this property to specify which HAL configuration + should be used. In the case of some SoCs (e.g: i.MX93), + there can be multiple eDMA variants, each of them having + different configurations (e.g: i.MX93 eDMA3 has 31 channels, + i.MX93 eDMA4 has 64 channels and both of them have slightly + different register layouts). To overcome this issue, the HAL + exposes an array of configurations called "edma_hal_configs". + To perform various operations, the HAL uses an eDMA configuration + which will tell it what register layout the IP has, the number of + channels, various flags and offsets. As such, if there's multiple + configurations available, the user will have to specify which + configuration to use through this property. If missing, the + configuration found at index 0 will be used. From 33c84d8af063586fd280882add96951a309fa03e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C3=98yvind=20R=C3=B8nningstad?= Date: Fri, 19 Jan 2024 09:11:18 +0100 Subject: [PATCH 2726/3723] west.yml: Update uoscore-edhoc MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit from 2.2.1 to 3.0.2 Signed-off-by: Øyvind Rønningstad --- west.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/west.yml b/west.yml index 7760e945206..20a611a65b7 100644 --- a/west.yml +++ b/west.yml @@ -332,7 +332,7 @@ manifest: groups: - tee - name: uoscore-uedhoc - revision: 5fe2cb613bd7e4590bd1b00c2adf181ac0229379 + revision: 5024d8c98b3864c6698f0195a53e19c484bc8cd3 path: modules/lib/uoscore-uedhoc - name: zcbor revision: 67fd8bb88d3136738661fa8bb5f9989103f4599e From 1d23ac55777cf6ad8f7cebebeaf043bc7f9d99ff Mon Sep 17 00:00:00 2001 From: Toon Stegen Date: Wed, 3 Jan 2024 15:51:13 +0100 Subject: [PATCH 2727/3723] boards: arm: stm32h750b_dk: add support for sdram 128 Mbit sdram devicetree definition Signed-off-by: Toon Stegen --- boards/arm/stm32h750b_dk/stm32h750b_dk.dts | 44 ++++++++++++++++++++++ 1 file changed, 44 insertions(+) diff --git a/boards/arm/stm32h750b_dk/stm32h750b_dk.dts b/boards/arm/stm32h750b_dk/stm32h750b_dk.dts index ff074167e2a..efe4b7b2743 100644 --- a/boards/arm/stm32h750b_dk/stm32h750b_dk.dts +++ b/boards/arm/stm32h750b_dk/stm32h750b_dk.dts @@ -21,6 +21,14 @@ zephyr,flash-controller = &mt25ql512ab1; }; + sdram2: sdram@d0000000 { + compatible = "zephyr,memory-region", "mmio-sram"; + device_type = "memory"; + reg = <0xd0000000 DT_SIZE_M(16)>; /* 128Mbit */ + zephyr,memory-region = "SDRAM2"; + zephyr,memory-attr = <( DT_MEM_ARM(ATTR_MPU_RAM) )>; + }; + leds { compatible = "gpio-leds"; red_led: led_1 { @@ -121,3 +129,39 @@ status = "okay"; }; }; + +&fmc { + pinctrl-0 = <&fmc_nbl0_pe0 &fmc_nbl1_pe1 + &fmc_sdclk_pg8 &fmc_sdnwe_ph5 &fmc_sdcke1_ph7 + &fmc_sdne1_ph6 &fmc_sdnras_pf11 &fmc_sdncas_pg15 + &fmc_a0_pf0 &fmc_a1_pf1 &fmc_a2_pf2 &fmc_a3_pf3 &fmc_a4_pf4 + &fmc_a5_pf5 &fmc_a6_pf12 &fmc_a7_pf13 &fmc_a8_pf14 + &fmc_a9_pf15 &fmc_a10_pg0 &fmc_a11_pg1 + &fmc_a14_pg4 &fmc_a15_pg5 &fmc_d0_pd14 &fmc_d1_pd15 + &fmc_d2_pd0 &fmc_d3_pd1 &fmc_d4_pe7 &fmc_d5_pe8 &fmc_d6_pe9 + &fmc_d7_pe10 &fmc_d8_pe11 &fmc_d9_pe12 &fmc_d10_pe13 + &fmc_d11_pe14 &fmc_d12_pe15 &fmc_d13_pd8 &fmc_d14_pd9 + &fmc_d15_pd10>; + pinctrl-names = "default"; + status = "okay"; + + sdram { + status = "okay"; + power-up-delay = <100>; + num-auto-refresh = <8>; + mode-register = <0x220>; + refresh-rate = <0x603>; + bank@1 { + reg = <1>; + st,sdram-control = ; + st,sdram-timing = <2 7 4 7 2 2 2>; + }; + }; +}; From 72b3c3ea3a863e617c1dc7491b5832db199d0061 Mon Sep 17 00:00:00 2001 From: Armando Visconti Date: Tue, 23 Jan 2024 17:32:06 +0100 Subject: [PATCH 2728/3723] drivers: i2c: rv32m1: Fix build error This fixes following build error when rv32m1_vega_zero_riscy board gets compiled: implicit declaration of function 'INST_DT_CLOCK_IP_NAME' Fixes #68012 Signed-off-by: Armando Visconti --- drivers/i2c/i2c_rv32m1_lpi2c.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/i2c/i2c_rv32m1_lpi2c.c b/drivers/i2c/i2c_rv32m1_lpi2c.c index ca0f6e6ef2e..ef64f1ac3d3 100644 --- a/drivers/i2c/i2c_rv32m1_lpi2c.c +++ b/drivers/i2c/i2c_rv32m1_lpi2c.c @@ -15,6 +15,7 @@ #include #include #include +#include #include LOG_MODULE_REGISTER(rv32m1_lpi2c); From b302308e5f666a960a84ff8d76cfbe531a932fdf Mon Sep 17 00:00:00 2001 From: Andriy Gelman Date: Sun, 21 Jan 2024 10:57:50 -0500 Subject: [PATCH 2729/3723] drivers: eth_sam_gmac: Use CONFIG_PTP_CLOCK_INIT_PRIORITY to init ptp Use dedicated Kconfig symbol to set init priority. Signed-off-by: Andriy Gelman --- drivers/ethernet/eth_sam_gmac.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/ethernet/eth_sam_gmac.c b/drivers/ethernet/eth_sam_gmac.c index 9acefcd833b..80d43f3616c 100644 --- a/drivers/ethernet/eth_sam_gmac.c +++ b/drivers/ethernet/eth_sam_gmac.c @@ -2494,6 +2494,6 @@ static int ptp_gmac_init(const struct device *port) DEVICE_DEFINE(gmac_ptp_clock_0, PTP_CLOCK_NAME, ptp_gmac_init, NULL, &ptp_gmac_0_context, NULL, POST_KERNEL, - CONFIG_APPLICATION_INIT_PRIORITY, &ptp_api); + CONFIG_PTP_CLOCK_INIT_PRIORITY, &ptp_api); #endif /* CONFIG_PTP_CLOCK_SAM_GMAC */ From 117dc55233d36b829d5bf48521f8455864b59877 Mon Sep 17 00:00:00 2001 From: Derek Snell Date: Tue, 23 Jan 2024 16:30:41 -0500 Subject: [PATCH 2730/3723] doc: linkserver: update installer link Updates link to MCUXpresso Installer Signed-off-by: Derek Snell --- doc/develop/flash_debug/host-tools.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/doc/develop/flash_debug/host-tools.rst b/doc/develop/flash_debug/host-tools.rst index 785bd6c7aef..dff685ba7da 100644 --- a/doc/develop/flash_debug/host-tools.rst +++ b/doc/develop/flash_debug/host-tools.rst @@ -479,7 +479,7 @@ afterwards detach the debug session: https://www.nxp.com/design/software/development-software/mcuxpresso-software-and-tools-/mcuxpresso-for-visual-studio-code:MCUXPRESSO-VSC .. _MCUXpresso Installer: - https://www.nxp.com/lgfiles/updates/mcuxpresso/MCUXpressoInstaller.exe + https://github.com/nxp-mcuxpresso/vscode-for-mcux/wiki/Dependency-Installation .. _NXP S32 Design Studio for S32 Platform: https://www.nxp.com/design/software/development-software/s32-design-studio-ide/s32-design-studio-for-s32-platform:S32DS-S32PLATFORM From 114548ef607aefd712dda7e5ea954981e778185b Mon Sep 17 00:00:00 2001 From: Paszkiet Kamil Date: Thu, 18 Jan 2024 11:19:47 +0100 Subject: [PATCH 2731/3723] scripts: twister_blackbox: Added the ability to clear log from the code clear_log is used as a fixture by pytest. We need to be able to call it from the code level. Example of use in the file test_harwaremap.py line 157. Signed-off-by: Paszkiet Kamil --- scripts/tests/twister_blackbox/conftest.py | 5 +++++ scripts/tests/twister_blackbox/test_hardwaremap.py | 12 ++---------- 2 files changed, 7 insertions(+), 10 deletions(-) diff --git a/scripts/tests/twister_blackbox/conftest.py b/scripts/tests/twister_blackbox/conftest.py index 11429319b96..1271af06694 100644 --- a/scripts/tests/twister_blackbox/conftest.py +++ b/scripts/tests/twister_blackbox/conftest.py @@ -37,6 +37,11 @@ def zephyr_test_directory(): @pytest.fixture def clear_log(): + # clear_log is used by pytest fixture + # However, clear_log_in_test is prepared to be used directly in the code, wherever required + clear_log_in_test() + +def clear_log_in_test(): # Required to fix the pytest logging error # See: https://github.com/pytest-dev/pytest/issues/5502 loggers = [logging.getLogger()] \ diff --git a/scripts/tests/twister_blackbox/test_hardwaremap.py b/scripts/tests/twister_blackbox/test_hardwaremap.py index c1efd5be495..c1f6ff1eaf8 100644 --- a/scripts/tests/twister_blackbox/test_hardwaremap.py +++ b/scripts/tests/twister_blackbox/test_hardwaremap.py @@ -5,14 +5,13 @@ """ Blackbox tests for twister's command line functions """ -import logging import importlib import mock import os import pytest import sys -from conftest import ZEPHYR_BASE, testsuite_filename_mock +from conftest import ZEPHYR_BASE, testsuite_filename_mock, clear_log_in_test from twisterlib.testplan import TestPlan sys.path.insert(0, os.path.join(ZEPHYR_BASE, "scripts/pylib/twister/twisterlib")) @@ -155,14 +154,7 @@ def mocked_comports(): os.remove(path) assert str(sys_exit.value) == '0' - loggers = [logging.getLogger()] + \ - list(logging.Logger.manager.loggerDict.values()) + \ - [logging.getLogger(name) for \ - name in logging.root.manager.loggerDict] - for logger in loggers: - handlers = getattr(logger, 'handlers', []) - for handler in handlers: - logger.removeHandler(handler) + clear_log_in_test() @pytest.mark.parametrize( ('manufacturer', 'product', 'serial', 'runner'), From db4bf8d409ce7d0b8b96363e868258d99ba2d28f Mon Sep 17 00:00:00 2001 From: Vivekananda Uppunda Date: Mon, 22 Jan 2024 10:08:03 +0530 Subject: [PATCH 2732/3723] net: l2: ethernet: bring in TX-Injection mode to l2 ethernet This set of changes brings in raw packet tx injection mode feature to ethernet and removes it from being a Wi-Fi only feature. It was earlier envisaged as Wi-Fi net management feature only. Signed-off-by: Vivekananda Uppunda --- include/zephyr/net/ethernet.h | 16 ++++++++++++++++ include/zephyr/net/ethernet_mgmt.h | 13 +++++++++++++ subsys/net/l2/ethernet/ethernet.c | 14 ++++++++++++++ subsys/net/l2/ethernet/ethernet_mgmt.c | 26 ++++++++++++++++++++++++++ 4 files changed, 69 insertions(+) diff --git a/include/zephyr/net/ethernet.h b/include/zephyr/net/ethernet.h index 181503140a7..faa6cf7fc0b 100644 --- a/include/zephyr/net/ethernet.h +++ b/include/zephyr/net/ethernet.h @@ -179,6 +179,9 @@ enum ethernet_hw_caps { /** TXTIME supported */ ETHERNET_TXTIME = BIT(19), + + /** TX-Injection supported */ + ETHERNET_TXINJECTION_MODE = BIT(20), }; /** @cond INTERNAL_HIDDEN */ @@ -197,6 +200,7 @@ enum ethernet_config_type { ETHERNET_CONFIG_TYPE_FILTER, ETHERNET_CONFIG_TYPE_PORTS_NUM, ETHERNET_CONFIG_TYPE_T1S_PARAM, + ETHERNET_CONFIG_TYPE_TXINJECTION_MODE, }; enum ethernet_qav_param_type { @@ -442,6 +446,7 @@ struct ethernet_config { bool auto_negotiation; bool full_duplex; bool promisc_mode; + bool txinjection_mode; struct { bool link_10bt; @@ -1029,6 +1034,17 @@ void net_eth_carrier_off(struct net_if *iface); */ int net_eth_promisc_mode(struct net_if *iface, bool enable); +/** + * @brief Set TX-Injection mode either ON or OFF. + * + * @param iface Network interface + * + * @param enable on (true) or off (false) + * + * @return 0 if mode set or unset was successful, <0 otherwise. + */ +int net_eth_txinjection_mode(struct net_if *iface, bool enable); + /** * @brief Return PTP clock that is tied to this ethernet network interface. * diff --git a/include/zephyr/net/ethernet_mgmt.h b/include/zephyr/net/ethernet_mgmt.h index 32a38f2df88..18039e9f3aa 100644 --- a/include/zephyr/net/ethernet_mgmt.h +++ b/include/zephyr/net/ethernet_mgmt.h @@ -52,6 +52,8 @@ enum net_request_ethernet_cmd { NET_REQUEST_ETHERNET_CMD_GET_QBU_PARAM, NET_REQUEST_ETHERNET_CMD_GET_TXTIME_PARAM, NET_REQUEST_ETHERNET_CMD_SET_T1S_PARAM, + NET_REQUEST_ETHERNET_CMD_SET_TXINJECTION_MODE, + NET_REQUEST_ETHERNET_CMD_GET_TXINJECTION_MODE, }; #define NET_REQUEST_ETHERNET_SET_AUTO_NEGOTIATION \ @@ -134,6 +136,16 @@ NET_MGMT_DEFINE_REQUEST_HANDLER(NET_REQUEST_ETHERNET_GET_TXTIME_PARAM); NET_MGMT_DEFINE_REQUEST_HANDLER(NET_REQUEST_ETHERNET_SET_T1S_PARAM); +#define NET_REQUEST_ETHERNET_SET_TXINJECTION_MODE \ + (_NET_ETHERNET_BASE | NET_REQUEST_ETHERNET_CMD_SET_TXINJECTION_MODE) + +NET_MGMT_DEFINE_REQUEST_HANDLER(NET_REQUEST_ETHERNET_SET_TXINJECTION_MODE); + +#define NET_REQUEST_ETHERNET_GET_TXINJECTION_MODE \ + (_NET_ETHERNET_BASE | NET_REQUEST_ETHERNET_CMD_GET_TXINJECTION_MODE) + +NET_MGMT_DEFINE_REQUEST_HANDLER(NET_REQUEST_ETHERNET_GET_TXINJECTION_MODE); + struct net_eth_addr; struct ethernet_qav_param; struct ethernet_qbv_param; @@ -145,6 +157,7 @@ struct ethernet_req_params { bool auto_negotiation; bool full_duplex; bool promisc_mode; + bool txinjection_mode; struct { bool link_10bt; diff --git a/subsys/net/l2/ethernet/ethernet.c b/subsys/net/l2/ethernet/ethernet.c index dd4d1e1bdbc..70cc81bd32d 100644 --- a/subsys/net/l2/ethernet/ethernet.c +++ b/subsys/net/l2/ethernet/ethernet.c @@ -1201,6 +1201,20 @@ int net_eth_promisc_mode(struct net_if *iface, bool enable) } #endif/* CONFIG_NET_PROMISCUOUS_MODE */ +int net_eth_txinjection_mode(struct net_if *iface, bool enable) +{ + struct ethernet_req_params params; + + if (!(net_eth_get_hw_capabilities(iface) & ETHERNET_TXINJECTION_MODE)) { + return -ENOTSUP; + } + + params.txinjection_mode = enable; + + return net_mgmt(NET_REQUEST_ETHERNET_SET_TXINJECTION_MODE, iface, + ¶ms, sizeof(struct ethernet_req_params)); +} + void ethernet_init(struct net_if *iface) { struct ethernet_context *ctx = net_if_l2_data(iface); diff --git a/subsys/net/l2/ethernet/ethernet_mgmt.c b/subsys/net/l2/ethernet/ethernet_mgmt.c index 3e957e52c1e..899aa7a9516 100644 --- a/subsys/net/l2/ethernet/ethernet_mgmt.c +++ b/subsys/net/l2/ethernet/ethernet_mgmt.c @@ -200,6 +200,13 @@ static int ethernet_set_config(uint32_t mgmt_request, memcpy(&config.t1s_param, ¶ms->t1s_param, sizeof(struct ethernet_t1s_param)); type = ETHERNET_CONFIG_TYPE_T1S_PARAM; + } else if (mgmt_request == NET_REQUEST_ETHERNET_SET_TXINJECTION_MODE) { + if (!is_hw_caps_supported(dev, ETHERNET_TXINJECTION_MODE)) { + return -ENOTSUP; + } + + config.txinjection_mode = params->txinjection_mode; + type = ETHERNET_CONFIG_TYPE_TXINJECTION_MODE; } else { return -EINVAL; } @@ -237,6 +244,9 @@ NET_MGMT_REGISTER_REQUEST_HANDLER(NET_REQUEST_ETHERNET_SET_PROMISC_MODE, NET_MGMT_REGISTER_REQUEST_HANDLER(NET_REQUEST_ETHERNET_SET_T1S_PARAM, ethernet_set_config); +NET_MGMT_REGISTER_REQUEST_HANDLER(NET_REQUEST_ETHERNET_SET_TXINJECTION_MODE, + ethernet_set_config); + static int ethernet_get_config(uint32_t mgmt_request, struct net_if *iface, void *data, size_t len) @@ -430,6 +440,19 @@ static int ethernet_get_config(uint32_t mgmt_request, config.txtime_param.enable_txtime; break; } + } else if (mgmt_request == NET_REQUEST_ETHERNET_GET_TXINJECTION_MODE) { + if (!is_hw_caps_supported(dev, ETHERNET_TXINJECTION_MODE)) { + return -ENOTSUP; + } + + type = ETHERNET_CONFIG_TYPE_TXINJECTION_MODE; + + ret = api->get_config(dev, type, &config); + if (ret) { + return ret; + } + + params->txinjection_mode = config.txinjection_mode; } else { return -EINVAL; } @@ -455,6 +478,9 @@ NET_MGMT_REGISTER_REQUEST_HANDLER(NET_REQUEST_ETHERNET_GET_QBU_PARAM, NET_MGMT_REGISTER_REQUEST_HANDLER(NET_REQUEST_ETHERNET_GET_TXTIME_PARAM, ethernet_get_config); +NET_MGMT_REGISTER_REQUEST_HANDLER(NET_REQUEST_ETHERNET_GET_TXINJECTION_MODE, + ethernet_get_config); + void ethernet_mgmt_raise_carrier_on_event(struct net_if *iface) { net_mgmt_event_notify(NET_EVENT_ETHERNET_CARRIER_ON, iface); From 7eb0aa04689b3086bf513f30531747393d86007b Mon Sep 17 00:00:00 2001 From: Vivekananda Uppunda Date: Mon, 22 Jan 2024 12:30:53 +0530 Subject: [PATCH 2733/3723] net: wifi_shell: Remove TX-Injection and Promiscuous mode from Wi-Fi mode Remove TX-Injection and Promiscuous mode setting from Wi-Fi mode shell command. These commands are being moved to ethernet l2 layer Signed-off-by: Vivekananda Uppunda --- subsys/net/l2/wifi/wifi_shell.c | 10 ---------- 1 file changed, 10 deletions(-) diff --git a/subsys/net/l2/wifi/wifi_shell.c b/subsys/net/l2/wifi/wifi_shell.c index cf4434ace31..f833dc52c2a 100644 --- a/subsys/net/l2/wifi/wifi_shell.c +++ b/subsys/net/l2/wifi/wifi_shell.c @@ -1519,8 +1519,6 @@ void parse_mode_args_to_params(const struct shell *sh, int argc, static struct option long_options[] = {{"if-index", optional_argument, 0, 'i'}, {"sta", no_argument, 0, 's'}, {"monitor", no_argument, 0, 'm'}, - {"tx-injection", no_argument, 0, 't'}, - {"promiscuous", no_argument, 0, 'p'}, {"ap", no_argument, 0, 'a'}, {"softap", no_argument, 0, 'k'}, {"get", no_argument, 0, 'g'}, @@ -1535,12 +1533,6 @@ void parse_mode_args_to_params(const struct shell *sh, int argc, case 'm': mode->mode |= WIFI_MONITOR_MODE; break; - case 't': - mode->mode |= WIFI_TX_INJECTION_MODE; - break; - case 'p': - mode->mode |= WIFI_PROMISCUOUS_MODE; - break; case 'a': mode->mode |= WIFI_AP_MODE; break; @@ -1938,8 +1930,6 @@ SHELL_STATIC_SUBCMD_SET_CREATE(wifi_commands, "[-i, --if-index ] : Interface index\n" "[-s, --sta] : Station mode\n" "[-m, --monitor] : Monitor mode\n" - "[-p, --promiscuous] : Promiscuous mode\n" - "[-t, --tx-injection] : TX-Injection mode\n" "[-a, --ap] : AP mode\n" "[-k, --softap] : Softap mode\n" "[-h, --help] : Help\n" From 8a2a44f9e98c313038f59ad3ceef857af58c5892 Mon Sep 17 00:00:00 2001 From: Caspar Friedrich Date: Sun, 19 Nov 2023 21:11:37 +0100 Subject: [PATCH 2734/3723] drivers: adc: tla2021: Raise default initialization priority The TLA2021 driver depends on it's i2c controller and therefore needs to be initialized later. ADC_INIT_PRIORITY by default equals KERNEL_INIT_PRIORITY_DEVICE which should be used by independent devices. Using this by default causing projects to fail where this driver is enabled implicitly through board configuration and the priority is not explicitly set. Signed-off-by: Caspar Friedrich --- drivers/adc/Kconfig.tla2021 | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/adc/Kconfig.tla2021 b/drivers/adc/Kconfig.tla2021 index fff48ed82af..9c09b74536e 100644 --- a/drivers/adc/Kconfig.tla2021 +++ b/drivers/adc/Kconfig.tla2021 @@ -13,7 +13,7 @@ if ADC_TLA2021 config ADC_TLA2021_INIT_PRIORITY int "Priority for the driver initialization" - default ADC_INIT_PRIORITY + default 80 help Fine tune the priority for the driver initialization. Make sure it's higher (-> lower priority) than I2C_INIT_PRIORITY. From 89d4f06c17498856a0e37e43a273bf23327f7721 Mon Sep 17 00:00:00 2001 From: Miika Karanki Date: Fri, 19 Jan 2024 10:18:34 +0200 Subject: [PATCH 2735/3723] fs: remove not needed SYS_INIT function fs_init was just initializing mutex and dlist. Those can be done statically. Not having the SYS_INIT function helps in ordering the init functions in case e.g. file system mounts are wanted to happen early stage on the system startup. Signed-off-by: Miika Karanki --- subsys/fs/fs.c | 13 ++----------- 1 file changed, 2 insertions(+), 11 deletions(-) diff --git a/subsys/fs/fs.c b/subsys/fs/fs.c index 60bb3e36453..bf3cd71901a 100644 --- a/subsys/fs/fs.c +++ b/subsys/fs/fs.c @@ -22,10 +22,10 @@ LOG_MODULE_REGISTER(fs); /* list of mounted file systems */ -static sys_dlist_t fs_mnt_list; +static sys_dlist_t fs_mnt_list = SYS_DLIST_STATIC_INIT(&fs_mnt_list); /* lock to protect mount list operations */ -static struct k_mutex mutex; +static K_MUTEX_DEFINE(mutex); /* Maps an identifier used in mount points to the file system * implementation. @@ -875,12 +875,3 @@ int fs_unregister(int type, const struct fs_file_system_t *fs) LOG_DBG("fs unregister %d: %d", type, rc); return rc; } - -static int fs_init(void) -{ - k_mutex_init(&mutex); - sys_dlist_init(&fs_mnt_list); - return 0; -} - -SYS_INIT(fs_init, POST_KERNEL, CONFIG_KERNEL_INIT_PRIORITY_DEFAULT); From 8b866451089bbb0ccf031e365d4d00629145d341 Mon Sep 17 00:00:00 2001 From: Miika Karanki Date: Mon, 22 Jan 2024 09:57:52 +0200 Subject: [PATCH 2736/3723] fs: Add Kconfig key for init priority Non-configurable init priority POST_KERNEL/99 might be too late for certain uses cases (e.g. fetching data from the file system in driver initialization). Chabge it to be configurable so that applications can mount the file systems earlies if they want. Signed-off-by: Miika Karanki --- subsys/fs/Kconfig | 8 ++++++++ subsys/fs/fat_fs.c | 2 +- subsys/fs/littlefs_fs.c | 2 +- 3 files changed, 10 insertions(+), 2 deletions(-) diff --git a/subsys/fs/Kconfig b/subsys/fs/Kconfig index fcc38312a66..f02ed046ead 100644 --- a/subsys/fs/Kconfig +++ b/subsys/fs/Kconfig @@ -43,6 +43,14 @@ config FILE_SYSTEM_MAX_FILE_NAME supported by a file system may result in memory access violations. +config FILE_SYSTEM_INIT_PRIORITY + int "File system initialization priority" + default 99 + help + Specify the initialization priority for file systems. In case + automount is enabled, the initialization should be done after + the underlying storage device is initialized. + config FILE_SYSTEM_SHELL bool "File system shell" depends on SHELL diff --git a/subsys/fs/fat_fs.c b/subsys/fs/fat_fs.c index a87bc880e93..4f79a97ec9e 100644 --- a/subsys/fs/fat_fs.c +++ b/subsys/fs/fat_fs.c @@ -527,4 +527,4 @@ static int fatfs_init(void) return fs_register(FS_FATFS, &fatfs_fs); } -SYS_INIT(fatfs_init, POST_KERNEL, 99); +SYS_INIT(fatfs_init, POST_KERNEL, CONFIG_FILE_SYSTEM_INIT_PRIORITY); diff --git a/subsys/fs/littlefs_fs.c b/subsys/fs/littlefs_fs.c index 3058f402d73..b373ca92ba8 100644 --- a/subsys/fs/littlefs_fs.c +++ b/subsys/fs/littlefs_fs.c @@ -1098,4 +1098,4 @@ static int littlefs_init(void) return rc; } -SYS_INIT(littlefs_init, POST_KERNEL, 99); +SYS_INIT(littlefs_init, POST_KERNEL, CONFIG_FILE_SYSTEM_INIT_PRIORITY); From 2166a6f92ffdc056793a453b9344339694516039 Mon Sep 17 00:00:00 2001 From: Yong Cong Sin Date: Mon, 22 Jan 2024 16:56:36 +0800 Subject: [PATCH 2737/3723] doc: release: migration guide: 3.6: add note on DT IRQ macros changes Add a note on the Devicetree IRQ macros changes, especially for multilevel interrupt platforms. Signed-off-by: Yong Cong Sin --- doc/releases/migration-guide-3.6.rst | 42 ++++++++++++++++++++++++++++ 1 file changed, 42 insertions(+) diff --git a/doc/releases/migration-guide-3.6.rst b/doc/releases/migration-guide-3.6.rst index 45aae4ca87e..fc6982c97d9 100644 --- a/doc/releases/migration-guide-3.6.rst +++ b/doc/releases/migration-guide-3.6.rst @@ -229,6 +229,48 @@ Device Drivers and Device Tree change is that this feature is rarely used and disabling it significantly reduces the memory footprint. +* For platforms that enabled :kconfig:option:`CONFIG_MULTI_LEVEL_INTERRUPTS`, the ``IRQ`` variant + of the Devicetree macros now return the as-seen value in the devicetree instead of the Zephyr + multilevel-encoded IRQ number. To get the IRQ number in Zephyr multilevel-encoded format, use + ``IRQN`` variant instead. For example, consider the following devicetree: + + .. code-block:: devicetree + + plic: interrupt-controller@c000000 { + riscv,max-priority = <7>; + riscv,ndev = <1024>; + reg = <0x0c000000 0x04000000>; + interrupts-extended = <&hlic0 11>; + interrupt-controller; + compatible = "sifive,plic-1.0.0"; + #address-cells = <0x0>; + #interrupt-cells = <0x2>; + }; + + uart0: uart@10000000 { + interrupts = <10 1>; + interrupt-parent = <&plic>; + clock-frequency = <0x384000>; + reg = <0x10000000 0x100>; + compatible = "ns16550"; + reg-shift = <0>; + }; + + ``plic`` is a second level interrupt aggregator and ``uart0`` is a child of ``plic``. + ``DT_IRQ_BY_IDX(DT_NODELABEL(uart0), 0, irq)`` will return ``10`` + (as-seen value in the devicetree), while ``DT_IRQN_BY_IDX(DT_NODELABEL(uart0), 0)`` will return + ``(((10 + 1) << CONFIG_1ST_LEVEL_INTERRUPT_BITS) | 11)``. + + Drivers and applications that are supposed to work in multilevel-interrupt configurations should + be updated to use the ``IRQN`` variant, i.e.: + + * ``DT_IRQ(node_id, irq)`` -> ``DT_IRQN(node_id)`` + * ``DT_IRQ_BY_IDX(node_id, idx, irq)`` -> ``DT_IRQN_BY_IDX(node_id, idx)`` + * ``DT_IRQ_BY_NAME(node_id, name, irq)`` -> ``DT_IRQN_BY_NAME(node_id, name)`` + * ``DT_INST_IRQ(inst, irq)`` -> ``DT_INST_IRQN(inst)`` + * ``DT_INST_IRQ_BY_IDX(inst, idx, irq)`` -> ``DT_INST_IRQN_BY_IDX(inst, idx)`` + * ``DT_INST_IRQ_BY_NAME(inst, name, irq)`` -> ``DT_INST_IRQN_BY_NAME(inst, name)`` + Power Management ================ From b9b714c8bd401cb9bdbe0117d120813ea0403f8d Mon Sep 17 00:00:00 2001 From: Guangfu Hu Date: Tue, 27 Jun 2023 17:35:00 +0800 Subject: [PATCH 2738/3723] sensing: refine sensing API 1) move variable shift behind struct sensing_sensor_value_header in struct sensing_sensor_value_q31 2) add pointer checking for sensing API 3) add context sensing_callback_list and sensing_data_event_t 4) add macro SENSING_SENSITIVITY_INDEX_ALL 5) rename zephyr,sensing-phy-3d-sensor.yaml Signed-off-by: Guangfu Hu --- ...nsor.yaml => zephyr,sensing-phy-3d-sensor.yaml} | 0 include/zephyr/sensing/sensing.h | 12 +++++++++++- include/zephyr/sensing/sensing_datatypes.h | 2 +- samples/subsys/sensing/simple/src/main.c | 4 +++- subsys/sensing/sensing.c | 14 +++++++++++++- 5 files changed, 28 insertions(+), 4 deletions(-) rename dts/bindings/sensor/{zephyr,senss-phy-3d-sensor.yaml => zephyr,sensing-phy-3d-sensor.yaml} (100%) diff --git a/dts/bindings/sensor/zephyr,senss-phy-3d-sensor.yaml b/dts/bindings/sensor/zephyr,sensing-phy-3d-sensor.yaml similarity index 100% rename from dts/bindings/sensor/zephyr,senss-phy-3d-sensor.yaml rename to dts/bindings/sensor/zephyr,sensing-phy-3d-sensor.yaml diff --git a/include/zephyr/sensing/sensing.h b/include/zephyr/sensing/sensing.h index e29b1aa7624..62e48873f56 100644 --- a/include/zephyr/sensing/sensing.h +++ b/include/zephyr/sensing/sensing.h @@ -72,6 +72,11 @@ struct sensing_sensor_version { */ #define SENSING_SENSOR_FLAG_REPORT_ON_CHANGE BIT(1) +/** + * @brief SENSING_SENSITIVITY_INDEX_ALL indicating sensitivity of each data field should be set + * + */ +#define SENSING_SENSITIVITY_INDEX_ALL -1 /** * @brief Sensing subsystem sensor state. @@ -110,7 +115,8 @@ typedef void *sensing_sensor_handle_t; */ typedef void (*sensing_data_event_t)( sensing_sensor_handle_t handle, - const void *buf); + const void *buf, + void *context); /** * @struct sensing_sensor_info @@ -144,6 +150,7 @@ struct sensing_sensor_info { */ struct sensing_callback_list { sensing_data_event_t on_data_event; + void *context; }; /** * @struct sensing_sensor_config @@ -152,7 +159,10 @@ struct sensing_callback_list { */ struct sensing_sensor_config { enum sensing_sensor_attribute attri; + + /** \ref SENSING_SENSITIVITY_INDEX_ALL */ int8_t data_field; + union { uint32_t interval; uint32_t sensitivity; diff --git a/include/zephyr/sensing/sensing_datatypes.h b/include/zephyr/sensing/sensing_datatypes.h index 3549aab4bdb..a5abcc3c8f8 100644 --- a/include/zephyr/sensing/sensing_datatypes.h +++ b/include/zephyr/sensing/sensing_datatypes.h @@ -99,8 +99,8 @@ struct sensing_sensor_value_uint32 { * q31 version */ struct sensing_sensor_value_q31 { - int8_t shift; struct sensing_sensor_value_header header; + int8_t shift; struct { uint32_t timestamp_delta; q31_t v; diff --git a/samples/subsys/sensing/simple/src/main.c b/samples/subsys/sensing/simple/src/main.c index 9a5b6687682..7884acef3a6 100644 --- a/samples/subsys/sensing/simple/src/main.c +++ b/samples/subsys/sensing/simple/src/main.c @@ -12,10 +12,12 @@ LOG_MODULE_REGISTER(main, LOG_LEVEL_INF); -static void acc_data_event_callback(sensing_sensor_handle_t handle, const void *buf) +static void acc_data_event_callback(sensing_sensor_handle_t handle, const void *buf, + void *context) { const struct sensing_sensor_info *info = sensing_get_sensor_info(handle); struct sensing_sensor_value_3d_q31 *sample = (struct sensing_sensor_value_3d_q31 *)buf; + ARG_UNUSED(context); LOG_INF("%s(%d), handle:%p, Sensor:%s data:(x:%d, y:%d, z:%d)", __func__, __LINE__, handle, info->name, diff --git a/subsys/sensing/sensing.c b/subsys/sensing/sensing.c index 60749254379..9b5469b5c7e 100644 --- a/subsys/sensing/sensing.c +++ b/subsys/sensing/sensing.c @@ -19,7 +19,7 @@ int sensing_open_sensor(const struct sensing_sensor_info *sensor_info, { int ret = 0; - if (handle == NULL) { + if (sensor_info == NULL || handle == NULL) { return -ENODEV; } @@ -64,6 +64,10 @@ int sensing_open_sensor_by_dt(const struct device *dev, /* sensing_close_sensor is normally called by applications: hid, chre, zephyr main, etc */ int sensing_close_sensor(sensing_sensor_handle_t *handle) { + if (handle == NULL) { + return -ENODEV; + } + return close_sensor((struct sensing_connection **)handle); } @@ -74,6 +78,10 @@ int sensing_set_config(sensing_sensor_handle_t handle, struct sensing_sensor_config *cfg; int i, ret = 0; + if (handle == NULL || configs == NULL) { + return -ENODEV; + } + if (count <= 0 || count > SENSING_SENSOR_ATTRIBUTE_MAX) { LOG_ERR("invalid config count:%d", count); return -EINVAL; @@ -110,6 +118,10 @@ int sensing_get_config(sensing_sensor_handle_t handle, struct sensing_sensor_config *cfg; int i, ret = 0; + if (handle == NULL || configs == NULL) { + return -ENODEV; + } + if (count <= 0 || count > SENSING_SENSOR_ATTRIBUTE_MAX) { LOG_ERR("invalid config count:%d", count); return -EINVAL; From 46eb27cf7328ca194a4a00572ab9e7b8fac8fd62 Mon Sep 17 00:00:00 2001 From: Zhang Lixu Date: Mon, 23 Oct 2023 15:30:57 +0800 Subject: [PATCH 2739/3723] sensing: unified the sensing sensor api 1. use the sensor_driver_api instead of the sensing_sensor_api. 2. clean up the sensing_sensor.h after using the unified api. 3. select RTIO while CONFIG_SENSING is enabled. 4. remove the sensing_sensor_post_data and sensing_sensor_xxx_data_ready by introducing the RTIO Signed-off-by: Zhang Lixu --- include/zephyr/sensing/sensing_sensor.h | 624 +++++------------- subsys/sensing/Kconfig | 4 + subsys/sensing/sensing_sensor.c | 37 +- .../sensor/phy_3d_sensor/phy_3d_sensor.c | 67 +- .../sensor/phy_3d_sensor/phy_3d_sensor.h | 7 +- subsys/sensing/sensor_mgmt.c | 189 +----- subsys/sensing/sensor_mgmt.h | 169 +++-- 7 files changed, 327 insertions(+), 770 deletions(-) diff --git a/include/zephyr/sensing/sensing_sensor.h b/include/zephyr/sensing/sensing_sensor.h index 8c9e0c83811..85f0db5a2a8 100644 --- a/include/zephyr/sensing/sensing_sensor.h +++ b/include/zephyr/sensing/sensing_sensor.h @@ -7,10 +7,10 @@ #ifndef ZEPHYR_INCLUDE_SENSING_SENSOR_H_ #define ZEPHYR_INCLUDE_SENSING_SENSOR_H_ -#include -#include #include +#include #include +#include /** * @defgroup sensing_sensor Sensing Sensor API @@ -34,7 +34,6 @@ extern "C" { * */ struct sensing_sensor_register_info { - /** * Sensor flags */ @@ -58,105 +57,188 @@ struct sensing_sensor_register_info { struct sensing_sensor_version version; }; -/** - * @brief Sensor context data structure - * - */ -struct sensing_sensor_ctx { - - /** - * For sensing runtime internal private data, sensor should not see and touch - */ - void *priv_ptr; - - /** - * Pointer to the sensor register information. - */ - const struct sensing_sensor_register_info *register_info; +enum { + EVENT_CONFIG_READY, +}; - /** - * For sensor private context data, registered by sensor with \ref SENSING_SENSOR_DT_DEFINE. - * Sensor could use \ref sensing_sensor_get_ctx_data to fetch out this filed with - * struct device. - */ - void *const sensor_ctx_ptr; +enum { + SENSOR_LATER_CFG_BIT, }; -static inline int sensing_sensor_dev_init( - const struct device *dev) -{ - /** - * Nothing need to do in system auto initialization. - * Sensor subsystem runtime will call each sensor instance's initialization - * function via API callback according sensor reporting dependency sequences. - * Sensor subsystem can make sure the depends sensor instances always initialized before - * client sensors. - */ - return 0; -} +/** + * @struct sensing_connection information + * @brief sensing_connection indicates connection from reporter(source) to client(sink) + */ +struct sensing_connection { + sys_snode_t snode; + struct sensing_sensor *source; + struct sensing_sensor *sink; + /* interval and sensitivity set from client(sink) to reporter(source) */ + uint32_t interval; + int sensitivity[CONFIG_SENSING_MAX_SENSITIVITY_COUNT]; + /* copy sensor data to connection data buf from reporter */ + void *data; + /* client(sink) next consume time */ + uint64_t next_consume_time; + /* post data to application */ + struct sensing_callback_list callback_list; +}; /** - * @brief Macro for define a sensor instance from device tree node id + * @struct sensing_sensor + * @brief Internal sensor instance data structure. * - * This macro also defined a struct device for this sensor instance, and registered sensors' - * private context data, configuration data structure and API. - * - * sensing_init will enumerate all sensor instances from device tree, and initialize each sensor - * instance defined by this macro. + * Each sensor instance will have its unique data structure for storing all + * it's related information. * + * Sensor management will enumerate all these instance data structures, + * build report relationship model base on them, etc. */ +struct sensing_sensor { + const struct device *dev; + const struct sensing_sensor_info *info; + const struct sensing_sensor_register_info *register_info; + const uint16_t reporter_num; + sys_slist_t client_list; + uint32_t interval; + uint8_t sensitivity_count; + int sensitivity[CONFIG_SENSING_MAX_SENSITIVITY_COUNT]; + enum sensing_sensor_state state; + /* runtime info */ + struct rtio_iodev *iodev; + struct k_timer timer; + struct rtio_sqe *stream_sqe; + atomic_t flag; + struct sensing_connection *conns; +}; -#define SENSING_SENSOR_DT_DEFINE(node_id, reg_ptr, ctx_ptr, api_ptr) \ - static struct sensing_sensor_ctx \ - _CONCAT(__sensing_sensor_ctx_, Z_DEVICE_DT_DEV_ID(node_id)) = { \ - .register_info = reg_ptr, \ - .sensor_ctx_ptr = ctx_ptr, \ - }; \ - DEVICE_DT_DEFINE(node_id, sensing_sensor_dev_init, NULL, \ - &_CONCAT(__sensing_sensor_ctx_, Z_DEVICE_DT_DEV_ID(node_id)), \ - NULL, POST_KERNEL, 99, api_ptr) +#define PHANDLE_DEVICE_BY_IDX(idx, node, prop) \ + DEVICE_DT_GET(DT_PHANDLE_BY_IDX(node, prop, idx)) -/** - * @brief Get registered context data pointer for a sensor instance. - * - * Used by a sensor instance to get its registered context data pointer with its struct device. - * - * @param dev The sensor instance device structure. - */ -static inline void *sensing_sensor_get_ctx_data( - const struct device *dev) -{ - struct sensing_sensor_ctx *data = dev->data; +#define PHANDLE_DEVICE_LIST(node, prop) \ +{ \ + LISTIFY(DT_PROP_LEN_OR(node, prop, 0), \ + PHANDLE_DEVICE_BY_IDX, \ + (,), \ + node, \ + prop) \ +} - return data->sensor_ctx_ptr; +#define SENSING_SENSOR_INFO_NAME(node) \ + _CONCAT(__sensing_sensor_info_, DEVICE_DT_NAME_GET(node)) + +#define SENSING_SENSOR_INFO_DEFINE(node) \ + const static STRUCT_SECTION_ITERABLE(sensing_sensor_info, \ + SENSING_SENSOR_INFO_NAME(node)) = { \ + .type = DT_PROP(node, sensor_type), \ + .name = DT_NODE_FULL_NAME(node), \ + .friendly_name = DT_PROP(node, friendly_name), \ + .vendor = DT_NODE_VENDOR_OR(node, NULL), \ + .model = DT_NODE_MODEL_OR(node, NULL), \ + .minimal_interval = DT_PROP(node, minimal_interval), \ + }; + +#define SENSING_CONNECTIONS_NAME(node) \ + _CONCAT(__sensing_connections, DEVICE_DT_NAME_GET(node)) + +#define SENSING_SENSOR_SOURCE_EXTERN(idx, node) \ +extern struct sensing_sensor SENSING_SENSOR_NAME(DT_PHANDLE_BY_IDX(node, reporters, idx)); + +#define SENSING_CONNECTION_INITIALIZER(source_node, cb_list_ptr) \ +{ \ + .callback_list = *cb_list_ptr, \ + .source = &SENSING_SENSOR_NAME(source_node), \ } +#define SENSING_CONNECTION_DEFINE(idx, node, cb_list_ptr) \ + SENSING_CONNECTION_INITIALIZER(DT_PHANDLE_BY_IDX(node, reporters, idx), cb_list_ptr) + +#define SENSING_CONNECTIONS_DEFINE(node, num, cb_list_ptr) \ + LISTIFY(num, SENSING_SENSOR_SOURCE_EXTERN, \ + (), node) \ + static struct sensing_connection \ + SENSING_CONNECTIONS_NAME(node)[(num)] = { \ + LISTIFY(num, SENSING_CONNECTION_DEFINE, \ + (,), node, cb_list_ptr) \ + }; + +#define SENSING_SENSOR_IODEV_NAME(node) \ + _CONCAT(__sensing_iodev_, DEVICE_DT_NAME_GET(node)) + +#define SENSING_SENSOR_IODEV_DEFINE(node) \ + COND_CODE_1(DT_PROP(node, stream_mode), \ + (SENSOR_DT_STREAM_IODEV(SENSING_SENSOR_IODEV_NAME(node), node)), \ + (SENSOR_DT_READ_IODEV(SENSING_SENSOR_IODEV_NAME(node), node))); + +#define SENSING_SENSOR_NAME(node) \ + _CONCAT(__sensing_sensor_, DEVICE_DT_NAME_GET(node)) + +#define SENSING_SENSOR_DEFINE(node, reg_ptr, cb_list_ptr) \ + SENSING_SENSOR_INFO_DEFINE(node) \ + SENSING_CONNECTIONS_DEFINE(node, \ + DT_PROP_LEN_OR(node, reporters, 0), cb_list_ptr)\ + SENSING_SENSOR_IODEV_DEFINE(node) \ + STRUCT_SECTION_ITERABLE(sensing_sensor, \ + SENSING_SENSOR_NAME(node)) = { \ + .dev = DEVICE_DT_GET(node), \ + .info = &SENSING_SENSOR_INFO_NAME(node), \ + .register_info = reg_ptr, \ + .reporter_num = DT_PROP_LEN_OR(node, reporters, 0), \ + .conns = SENSING_CONNECTIONS_NAME(node), \ + .iodev = &SENSING_SENSOR_IODEV_NAME(node), \ + }; + /** - * @brief Post sensor data, sensor subsystem runtime will deliver to it's - * clients. + * @brief Like SENSOR_DEVICE_DT_DEFINE() with sensing specifics. * - * Unblocked function, returned immediately. + * @details Defines a sensor which implements the sensor API. May define an + * element in the sensing sensor iterable section used to enumerate all sensing + * sensors. * - * Used by a virtual sensor to post data to it's clients. + * @param node_id The devicetree node identifier. * - * A reporter sensor can use this API to post data to it's clients. - * For example, when a virtual sensor computed a data, then can use this API - * to deliver the data to it's clients. - * Please note, this API just for reporter post data to the sensor subsystem - * runtime, the runtime will help delivered the data to it's all clients - * according clients' configurations such as reporter interval, data change sensitivity. + * @param reg_ptr Pointer to the device's sensing_sensor_register_info. * - * @param dev The sensor instance device structure. + * @param init_fn Name of the init function of the driver. * - * @param buf The data buffer. + * @param pm_device PM device resources reference (NULL if device does not use + * PM). * - * @param size The buffer size in bytes. + * @param data_ptr Pointer to the device's private data. * - * @return 0 on success or negative error value on failure. + * @param cfg_ptr The address to the structure containing the configuration + * information for this instance of the driver. + * + * @param level The initialization level. See SYS_INIT() for details. + * + * @param prio Priority within the selected initialization level. See + * SYS_INIT() for details. + * + * @param api_ptr Provides an initial pointer to the API function struct used + * by the driver. Can be NULL. */ -int sensing_sensor_post_data( - const struct device *dev, - void *buf, int size); +#define SENSING_SENSOR_DT_DEFINE(node_id, reg_ptr, cb_list_ptr, \ + init_fn, pm_device, \ + data_ptr, cfg_ptr, level, prio, \ + api_ptr, ...) \ + SENSOR_DEVICE_DT_DEFINE(node_id, init_fn, pm_device, \ + data_ptr, cfg_ptr, level, prio, \ + api_ptr, __VA_ARGS__); \ + \ + SENSING_SENSOR_DEFINE(node_id, reg_ptr, cb_list_ptr); + +/** + * @brief Like SENSING_SENSOR_DT_DEFINE() for an instance of a DT_DRV_COMPAT + * compatible + * + * @param inst instance number. This is replaced by + * DT_DRV_COMPAT(inst) in the call to SENSING_SENSOR_DT_DEFINE(). + * + * @param ... other parameters as expected by SENSING_SENSOR_DT_DEFINE(). + */ +#define SENSING_SENSOR_DT_INST_DEFINE(inst, reg_ptr, cb_list_ptr, ...) \ + SENSING_SENSOR_DT_DEFINE(DT_DRV_INST(inst), reg_ptr, \ + cb_list_ptr, __VA_ARGS__) /** * @brief Get reporter handles of a given sensor instance by sensor type. @@ -176,7 +258,7 @@ int sensing_sensor_post_data( */ int sensing_sensor_get_reporters( const struct device *dev, int type, - const int *reporter_handles, int max_handles); + sensing_sensor_handle_t *reporter_handles, int max_handles); /** * @brief Get reporters count of a given sensor instance by sensor type. @@ -203,386 +285,6 @@ int sensing_sensor_get_state( const struct device *dev, enum sensing_sensor_state *state); -/** - * @brief Trigger the data ready event to sensing - * - * @param dev Pointer to the sensor device - * - * @return 0 on success or negative error value on failure. - */ -int sensing_sensor_notify_data_ready( - const struct device *dev); - -/** - * @brief Set the data ready mode of the sensor - * - * @param dev Pointer to the sensor device - * - * @param data_ready Enable/disable the data ready mode. Default:disabled - * - * @return 0 on success or negative error value on failure. - */ -int sensing_sensor_set_data_ready( - const struct device *dev, bool data_ready); - -/** - * @} - */ - -/** - * @brief Sensor Callbacks - * @addtogroup sensing_sensor_callbacks - * \{ - */ - -/** - * @brief Sensor initialize. - * - * Sensor can initialize it's runtime context in this callback. - * - * @param dev The sensor instance device structure. - * - * @param info The sensor instance's constant information. - * - * @param reporter_handles The reporters handles for this sensor, NULL for physical sensors. - * - * @param reporters_count The number of reporters, zero for physical sensors. - * - * @return 0 on success or negative error value on failure. - * - */ -typedef int (*sensing_sensor_init_t)( - const struct device *dev, const struct sensing_sensor_info *info, - const sensing_sensor_handle_t *reporter_handles, int reporters_count); - -/** - * @brief Sensor's de-initialize. - * - * Sensor can release it's runtime context in this callback. - * - * @param dev The sensor instance device structure. - * - * @return 0 on success or negative error value on failure. - * - */ -typedef int (*sensing_sensor_deinit_t)( - const struct device *dev); - -/** - * @brief Sensor reset. - * - * Sensor can reset its runtime context in this callback to default values without resources - * release and re-allocation. - * - * Its very useful for a virtual sensor to quickly reset its runtime context to a default state. - * - * @param dev The sensor instance device structure. - * - * @return 0 on success or negative error value on failure. - * - */ -typedef int (*sensing_sensor_reset_t)( - const struct device *dev); - -/** - * @brief Sensor read sample. - * - * Only physical sensor need implement this callback. - * Physical sensor can fetch sample data from sensor device in this callback - * - * @param dev The sensor instance device structure. - * - * @param buf Sensor subsystem runtime allocated buffer, and passed its pointer - * to this sensor for store fetched sample. - * - * @param size The size of the buffer in bytes. - * - * @return 0 on success or negative error value on failure. - * - */ -typedef int (*sensing_sensor_read_sample_t)( - const struct device *dev, - void *buf, int size); - -/** - * @brief Sensor process data. - * - * Only virtual sensor need implement this callback. - * Virtual sensor can receive reporter's data and do fusion computing - * in this callback. - * - * @param dev The sensor instance device structure. - * - * @param reporter The reporter handle who delivered this sensor data - * - * @param buf The buffer stored the reporter's sensor data. - * - * @param size The size of the buffer in bytes. - * - * @return 0 on success or negative error value on failure. - * - */ -typedef int (*sensing_sensor_process_t)( - const struct device *dev, - int reporter, - void *buf, int size); - -/** - * @brief Trigger a sensor to do self calibration - * - * If not support self calibration, can not implement this callback. - * - * @param dev The sensor instance device structure. - * - * @return 0 on success or negative error value on failure. - * - */ -typedef int (*sensing_sensor_self_calibration_t)( - const struct device *dev); - -/** - * @brief Sensitivity arbitration. - * - * This callback API provides a chance for sensor to do customized arbitration on data change - * sensitivity. - * The sensor can check two sequential samples with client's sensitivity value (passed with - * parameters in this callback) and decide if can pass the sensor sample to its client. - * - * @param dev The sensor instance device structure. - * - * @param index The value fields index to be set, -1 for all fields (global). - * - * @param sensitivity The sensitivity value. - * - * @param last_sample_buf The buffer stored last sample data. - * - * @param last_sample_size The size of last sample's data buffer in bytes - * - * @param current_sample_buf The buffer stored current sample data. - * - * @param current_sample_size The size of current sample's data buffer in bytes - * - * @return 0 on test passed or negative error value on failure. - * - */ -typedef int (*sensing_sensor_sensitivity_test_t)( - const struct device *dev, - int index, uint32_t sensitivity, - void *last_sample_buf, int last_sample_size, - void *current_sample_buf, int current_sample_size); - -/** - * @brief Set current report interval. - * - * @param dev The sensor instance device structure. - * - * @param value The value to be set. - * - * @return 0 on success or negative error value on failure. - * - */ -typedef int (*sensing_sensor_set_interval_t)( - const struct device *dev, - uint32_t value); - -/** - * @brief Get current report interval. - * - * @param dev The sensor instance device structure. - * - * @param value The data buffer to receive value. - * - * @return 0 on success or negative error value on failure. - * - */ -typedef int (*sensing_sensor_get_interval_t)( - const struct device *dev, - uint32_t *value); - -/** - * @brief Set data change sensitivity. - * - * Since each sensor type may have multiple data fields for it's value, this - * API support set separated sensitivity for each data field, or global - * sensitivity for all data fields. - * - * @param dev The sensor instance device structure. - * - * @param index The value fields index to be set, -1 for all fields (global). - * - * @param value The value to be set. - * - * @return 0 on success or negative error value on failure. - * - */ -typedef int (*sensing_sensor_set_sensitivity_t)( - const struct device *dev, - int index, uint32_t value); - -/** - * @brief Get current data change sensitivity. - * - * Since each sensor type may have multiple data fields for it's value, this - * API support get separated sensitivity for each data field, or global - * sensitivity for all data fields. - * - * @param dev The sensor instance device structure. - * - * @param index The value fields index to be set, -1 for all fields (global). - * - * @param value The data buffer to receive value. - * - * @return 0 on success or negative error value on failure, not support etc. - */ -typedef int (*sensing_sensor_get_sensitivity_t)( - const struct device *dev, - int index, uint32_t *value); - -/** - * @brief Set data range. - * - * Some sensors especially for physical sensors, support data range - * configuration, this may change data resolution. - * - * Since each sensor type may have multiple data fields for it's value, this - * API support set separated range for each data field, or global range for - * all data fields. - * - * @param dev The sensor instance device structure. - * - * @param index The value fields index to be set, -1 for all fields (global). - * - * @param value The value to be set. - * - * @return 0 on success or negative error value on failure, not support etc. - */ -typedef int (*sensing_sensor_set_range_t)( - const struct device *dev, - int index, uint32_t value); - -/** - * @brief Get current data range. - * - * Some sensors especially for physical sensors, support data range - * configuration, this may change data resolution. - * - * Since each sensor type may have multiple data fields for it's value, this - * API support get separated range for each data field, or global range for - * all data fields. - * - * @param dev The sensor instance device structure. - * - * @param index The value fields index to be set, -1 for all fields (global). - * - * @param value The data buffer to receive value. - * - * @return 0 on success or negative error value on failure, not support etc. - */ -typedef int (*sensing_sensor_get_range_t)( - const struct device *dev, - int index, uint32_t *value); - -/** - * @brief Set current sensor's hardware fifo size - * - * Some sensors especially for physical sensors, support hardware fifo, this API can - * configure the current fifo size. - * - * @param dev The sensor instance device structure. - * - * @param samples The sample number to set for fifo. - * - * @return 0 on success or negative error value on failure, not support etc. - */ -typedef int (*sensing_sensor_set_fifo_t)( - const struct device *dev, - uint32_t samples); - -/** - * @brief Get current sensor's hardware fifo size - * - * Some sensors especially for physical sensors, support fifo, this API can - * get the current fifo size. - * - * @param dev The sensor instance device structure. - * - * @param samples The data buffer to receive the fifo sample number. - * - * @return 0 on success or negative error value on failure, not support etc. - */ -typedef int (*sensing_sensor_get_fifo_t)( - const struct device *dev, - uint32_t *samples); - -/** - * @brief Set current sensor data offset - * - * Some sensors especially for physical sensors, such as accelerometer senors, - * as data drift, need configure offset calibration. - * - * Since each sensor type may have multiple data fields for it's value, this - * API support set separated offset for each data field, or global offset for - * all data fields. - * - * @param dev The sensor instance device structure. - * - * @param index The value fields index to be set, -1 for all fields (global). - * - * @param value The offset value to be set. - * - * @return 0 on success or negative error value on failure, not support etc. - */ -typedef int (*sensing_sensor_set_offset_t)( - const struct device *dev, - int index, int32_t value); - -/** - * @brief Get current sensor data offset - * - * Some sensors especially for physical sensors, such as accelerometer senors, - * as data drift, need configure offset calibration. - * - * Since each sensor type may have multiple data fields for it's value, this - * API support get separated offset for each data field, or global offset for - * all data fields. - * - * @param dev The sensor instance device structure. - * - * @param index The value fields index to be set, -1 for all fields (global). - * - * @param value The data buffer to receive the offset value. - * - * @return 0 on success or negative error value on failure, not support etc. - */ -typedef int (*sensing_sensor_get_offset_t)( - const struct device *dev, - int index, int32_t *value); -/** - * @struct sensing_sensor_api - * @brief Sensor callback api - * - * A sensor must register this callback API during sensor registration. - */ -struct sensing_sensor_api { - sensing_sensor_init_t init; - sensing_sensor_reset_t reset; - sensing_sensor_deinit_t deinit; - sensing_sensor_set_interval_t set_interval; - sensing_sensor_get_interval_t get_interval; - sensing_sensor_set_range_t set_range; - sensing_sensor_get_range_t get_range; - sensing_sensor_set_offset_t set_offset; - sensing_sensor_get_offset_t get_offset; - sensing_sensor_get_fifo_t get_fifo; - sensing_sensor_set_fifo_t set_fifo; - sensing_sensor_set_sensitivity_t set_sensitivity; - sensing_sensor_get_sensitivity_t get_sensitivity; - sensing_sensor_read_sample_t read_sample; - sensing_sensor_process_t process; - sensing_sensor_sensitivity_test_t sensitivity_test; - sensing_sensor_self_calibration_t self_calibration; -}; - /** * @} */ diff --git a/subsys/sensing/Kconfig b/subsys/sensing/Kconfig index 9101db07445..aec9cab59c1 100644 --- a/subsys/sensing/Kconfig +++ b/subsys/sensing/Kconfig @@ -5,6 +5,10 @@ config SENSING bool "Sensing Subsystem" default y depends on DT_HAS_ZEPHYR_SENSING_ENABLED + select RTIO + select RTIO_CONSUME_SEM + select SENSOR + select SENSOR_ASYNC_API help Enable Sensing Subsystem. diff --git a/subsys/sensing/sensing_sensor.c b/subsys/sensing/sensing_sensor.c index c305cbb35c4..da921c538af 100644 --- a/subsys/sensing/sensing_sensor.c +++ b/subsys/sensing/sensing_sensor.c @@ -8,21 +8,40 @@ #include #include #include - #include +#include "sensor_mgmt.h" + LOG_MODULE_DECLARE(sensing, CONFIG_SENSING_LOG_LEVEL); -int sensing_sensor_notify_data_ready(const struct device *dev) +int sensing_sensor_get_reporters(const struct device *dev, int type, + sensing_sensor_handle_t *reporter_handles, + int max_handles) { - return -ENOTSUP; -} + struct sensing_sensor *sensor = get_sensor_by_dev(dev); + int i, num = 0; -int sensing_sensor_set_data_ready(const struct device *dev, bool data_ready) -{ - return -ENOTSUP; + for (i = 0; i < sensor->reporter_num && num < max_handles; ++i) { + if (type == sensor->conns[i].source->info->type + || type == SENSING_SENSOR_TYPE_ALL) { + reporter_handles[num] = &sensor->conns[i]; + num++; + } + } + + return num; } -int sensing_sensor_post_data(const struct device *dev, void *buf, int size) +int sensing_sensor_get_reporters_count(const struct device *dev, int type) { - return -ENOTSUP; + struct sensing_sensor *sensor = get_sensor_by_dev(dev); + int i, num = 0; + + for (i = 0; i < sensor->reporter_num; ++i) { + if (type == sensor->conns[i].source->info->type + || type == SENSING_SENSOR_TYPE_ALL) { + num++; + } + } + + return num; } diff --git a/subsys/sensing/sensor/phy_3d_sensor/phy_3d_sensor.c b/subsys/sensing/sensor/phy_3d_sensor/phy_3d_sensor.c index 6ee2131bc3b..7b381bc1e83 100644 --- a/subsys/sensing/sensor/phy_3d_sensor/phy_3d_sensor.c +++ b/subsys/sensing/sensor/phy_3d_sensor/phy_3d_sensor.c @@ -9,6 +9,7 @@ #include #include #include +#include #include #include #include @@ -18,65 +19,32 @@ LOG_MODULE_REGISTER(phy_3d_sensor, CONFIG_SENSING_LOG_LEVEL); -static int phy_3d_sensor_init(const struct device *dev, - const struct sensing_sensor_info *info, - const sensing_sensor_handle_t *reporter_handles, - int reporters_count) +static int phy_3d_sensor_init(const struct device *dev) { - return 0; -} - -static int phy_3d_sensor_deinit(const struct device *dev) -{ - return 0; -} - -static int phy_3d_sensor_read_sample(const struct device *dev, - void *buf, int size) -{ - return 0; -} + const struct phy_3d_sensor_config *cfg = dev->config; -static int phy_3d_sensor_sensitivity_test(const struct device *dev, - int index, uint32_t sensitivity, - void *last_sample_buf, int last_sample_size, - void *current_sample_buf, int current_sample_size) -{ - return 0; -} + LOG_INF("%s: Underlying device: %s", dev->name, cfg->hw_dev->name); -static int phy_3d_sensor_set_interval(const struct device *dev, uint32_t value) -{ - return 0; -} - -static int phy_3d_sensor_get_interval(const struct device *dev, - uint32_t *value) -{ return 0; } -static int phy_3d_sensor_set_sensitivity(const struct device *dev, - int index, uint32_t value) +static int phy_3d_sensor_attr_set(const struct device *dev, + enum sensor_channel chan, + enum sensor_attribute attr, + const struct sensor_value *val) { return 0; } -static int phy_3d_sensor_get_sensitivity(const struct device *dev, - int index, uint32_t *value) +static int phy_3d_sensor_submit(const struct device *dev, + struct rtio_iodev_sqe *sqe) { return 0; } -static const struct sensing_sensor_api phy_3d_sensor_api = { - .init = phy_3d_sensor_init, - .deinit = phy_3d_sensor_deinit, - .set_interval = phy_3d_sensor_set_interval, - .get_interval = phy_3d_sensor_get_interval, - .set_sensitivity = phy_3d_sensor_set_sensitivity, - .get_sensitivity = phy_3d_sensor_get_sensitivity, - .read_sample = phy_3d_sensor_read_sample, - .sensitivity_test = phy_3d_sensor_sensitivity_test, +static const struct sensor_driver_api phy_3d_sensor_api = { + .attr_set = phy_3d_sensor_attr_set, + .submit = phy_3d_sensor_submit, }; static const struct sensing_sensor_register_info phy_3d_sensor_reg = { @@ -87,14 +55,17 @@ static const struct sensing_sensor_register_info phy_3d_sensor_reg = { }; #define SENSING_PHY_3D_SENSOR_DT_DEFINE(_inst) \ - static struct phy_3d_sensor_context _CONCAT(ctx, _inst) = { \ + static struct phy_3d_sensor_data _CONCAT(data, _inst); \ + static const struct phy_3d_sensor_config _CONCAT(cfg, _inst) = {\ .hw_dev = DEVICE_DT_GET( \ DT_PHANDLE(DT_DRV_INST(_inst), \ underlying_device)), \ .sensor_type = DT_PROP(DT_DRV_INST(_inst), sensor_type),\ }; \ - SENSING_SENSOR_DT_DEFINE(DT_DRV_INST(_inst), \ - &phy_3d_sensor_reg, &_CONCAT(ctx, _inst), \ + SENSING_SENSOR_DT_INST_DEFINE(_inst, &phy_3d_sensor_reg, NULL, \ + &phy_3d_sensor_init, NULL, \ + &_CONCAT(data, _inst), &_CONCAT(cfg, _inst), \ + POST_KERNEL, CONFIG_SENSOR_INIT_PRIORITY, \ &phy_3d_sensor_api); DT_INST_FOREACH_STATUS_OKAY(SENSING_PHY_3D_SENSOR_DT_DEFINE); diff --git a/subsys/sensing/sensor/phy_3d_sensor/phy_3d_sensor.h b/subsys/sensing/sensor/phy_3d_sensor/phy_3d_sensor.h index 966a6f088c3..e426a552832 100644 --- a/subsys/sensing/sensor/phy_3d_sensor/phy_3d_sensor.h +++ b/subsys/sensing/sensor/phy_3d_sensor/phy_3d_sensor.h @@ -11,8 +11,11 @@ #define PHY_3D_SENSOR_CHANNEL_NUM 3 -struct phy_3d_sensor_context { - const struct device *dev; +struct phy_3d_sensor_data { + struct sensor_value sensitivities[PHY_3D_SENSOR_CHANNEL_NUM]; +}; + +struct phy_3d_sensor_config { const struct device *hw_dev; const int32_t sensor_type; }; diff --git a/subsys/sensing/sensor_mgmt.c b/subsys/sensing/sensor_mgmt.c index 55ac7232af4..5fb9d3e03a6 100644 --- a/subsys/sensing/sensor_mgmt.c +++ b/subsys/sensing/sensor_mgmt.c @@ -15,33 +15,14 @@ #define DT_DRV_COMPAT zephyr_sensing -#define SENSING_SENSOR_NUM (sizeof((int []){ DT_FOREACH_CHILD_STATUS_OKAY_SEP( \ - DT_DRV_INST(0), DT_NODE_EXISTS, (,))}) / sizeof(int)) - BUILD_ASSERT(DT_NUM_INST_STATUS_OKAY(DT_DRV_COMPAT) == 1, "only one 'zephyr_sensing' compatible node may be present"); LOG_MODULE_REGISTER(sensing, CONFIG_SENSING_LOG_LEVEL); -DT_FOREACH_CHILD_STATUS_OKAY(DT_DRV_INST(0), SENSING_SENSOR_INFO_DEFINE) -DT_FOREACH_CHILD_STATUS_OKAY(DT_DRV_INST(0), SENSING_SENSOR_DEFINE) - - -/** - * @struct sensing_context - * @brief sensing subsystem context to include global variables - */ -struct sensing_context { - bool sensing_initialized; - int sensor_num; - struct sensing_sensor *sensors[SENSING_SENSOR_NUM]; -}; - static struct sensing_context sensing_ctx = { - .sensor_num = SENSING_SENSOR_NUM, }; - static int set_sensor_state(struct sensing_sensor *sensor, enum sensing_sensor_state state) { __ASSERT(sensor, "set sensor state, sensing_sensor is NULL"); @@ -57,159 +38,52 @@ static void init_connection(struct sensing_connection *conn, { __ASSERT(conn, "init each connection, invalid connection"); - conn->source = source; - conn->sink = sink; + if (source) { + conn->source = source; + } + + if (sink) { + conn->sink = sink; + } + conn->interval = 0; memset(conn->sensitivity, 0x00, sizeof(conn->sensitivity)); /* link connection to its reporter's client_list */ - sys_slist_append(&source->client_list, &conn->snode); + sys_slist_append(&conn->source->client_list, &conn->snode); } -static int init_sensor(struct sensing_sensor *sensor, int conns_num) +static int init_sensor(struct sensing_sensor *sensor) { - const struct sensing_sensor_api *sensor_api; - struct sensing_sensor *reporter; struct sensing_connection *conn; - void *tmp_conns[conns_num]; int i; __ASSERT(sensor && sensor->dev, "init sensor, sensor or sensor device is NULL"); - sensor_api = sensor->dev->api; - __ASSERT(sensor_api, "init sensor, sensor device sensor_api is NULL"); - - if (sensor->data_buf == NULL) { - LOG_ERR("sensor:%s memory alloc failed", sensor->dev->name); - return -ENOMEM; - } - /* physical sensor has no reporters, conns_num is 0 */ - if (conns_num == 0) { - sensor->conns = NULL; - } - - for (i = 0; i < conns_num; i++) { - conn = &sensor->conns[i]; - reporter = get_reporter_sensor(sensor, i); - __ASSERT(reporter, "sensor's reporter should not be NULL"); - - init_connection(conn, reporter, sensor); - - LOG_DBG("init sensor, reporter:%s, client:%s, connection:%d", - reporter->dev->name, sensor->dev->name, i); - - tmp_conns[i] = conn; - } - /* physical sensor is working at polling mode by default, - * virtual sensor working mode is inherited from its reporter - */ - if (is_phy_sensor(sensor)) { - sensor->mode = SENSOR_TRIGGER_MODE_POLLING; - } - - return sensor_api->init(sensor->dev, sensor->info, tmp_conns, conns_num); -} - -/* create struct sensing_sensor *sensor according to sensor device tree */ -static int pre_init_sensor(struct sensing_sensor *sensor) -{ - struct sensing_sensor_ctx *sensor_ctx; - uint16_t sample_size, total_size; - uint16_t conn_sample_size = 0; - int i = 0; - void *tmp_data; - - __ASSERT(sensor && sensor->dev, "sensor or sensor dev is invalid"); - sensor_ctx = sensor->dev->data; - __ASSERT(sensor_ctx, "sensing sensor context is invalid"); + sys_slist_init(&sensor->client_list); - sample_size = sensor_ctx->register_info->sample_size; for (i = 0; i < sensor->reporter_num; i++) { - conn_sample_size += get_reporter_sample_size(sensor, i); - } - - /* total memory to be allocated for a sensor according to sensor device tree: - * 1) sample data point to struct sensing_sensor->data_buf - * 2) size of struct sensing_connection* for sensor connection to its reporter - * 3) reporter sample size to be stored in connection data - */ - total_size = sample_size + sensor->reporter_num * sizeof(*sensor->conns) + - conn_sample_size; - - /* total size for different sensor maybe different, for example: - * there's no reporter for physical sensor, so no connection memory is needed - * reporter num of each virtual sensor may also different, so connection memory is also - * varied, so here malloc is a must for different sensor. - */ - tmp_data = malloc(total_size); - if (!tmp_data) { - LOG_ERR("malloc memory for sensing_sensor error"); - return -ENOMEM; - } - sensor->sample_size = sample_size; - sensor->data_buf = tmp_data; - sensor->conns = (struct sensing_connection *)((uint8_t *)sensor->data_buf + sample_size); + conn = &sensor->conns[i]; - tmp_data = sensor->conns + sensor->reporter_num; - for (i = 0; i < sensor->reporter_num; i++) { - sensor->conns[i].data = tmp_data; - tmp_data = (uint8_t *)tmp_data + get_reporter_sample_size(sensor, i); - } + /* source sensor has been assigned in compile time */ + init_connection(conn, NULL, sensor); - if (tmp_data != ((uint8_t *)sensor->data_buf + total_size)) { - LOG_ERR("sensor memory assign error, data_buf:%p, tmp_data:%p, size:%d", - sensor->data_buf, tmp_data, total_size); - free(sensor->data_buf); - sensor->data_buf = NULL; - return -EINVAL; + LOG_INF("init sensor, reporter:%s, client:%s, connection:%d(%p)", + conn->source->dev->name, sensor->dev->name, i, conn); } - LOG_INF("pre init sensor, sensor:%s, min_ri:%d(us)", - sensor->dev->name, sensor->info->minimal_interval); - - sensor->interval = 0; - sensor->sensitivity_count = sensor_ctx->register_info->sensitivity_count; - __ASSERT(sensor->sensitivity_count <= CONFIG_SENSING_MAX_SENSITIVITY_COUNT, - "sensitivity count:%d should not exceed MAX_SENSITIVITY_COUNT", - sensor->sensitivity_count); - memset(sensor->sensitivity, 0x00, sizeof(sensor->sensitivity)); - - sys_slist_init(&sensor->client_list); - - sensor_ctx->priv_ptr = sensor; - return 0; } -static int sensing_init(void) +static int sensing_init(const struct device *dev) { - struct sensing_context *ctx = &sensing_ctx; - struct sensing_sensor *sensor; + struct sensing_context *ctx = dev->data; enum sensing_sensor_state state; int ret = 0; - int i = 0; LOG_INF("sensing init begin..."); - if (ctx->sensing_initialized) { - LOG_INF("sensing is already initialized"); - return 0; - } - - if (ctx->sensor_num == 0) { - LOG_WRN("no sensor created by device tree yet"); - return 0; - } - - STRUCT_SECTION_FOREACH(sensing_sensor, tmp_sensor) { - ret = pre_init_sensor(tmp_sensor); - if (ret) { - LOG_ERR("sensing init, pre init sensor error"); - } - ctx->sensors[i++] = tmp_sensor; - } - - for_each_sensor(ctx, i, sensor) { - ret = init_sensor(sensor, sensor->reporter_num); + for_each_sensor(sensor) { + ret = init_sensor(sensor); if (ret) { LOG_ERR("sensor:%s initial error", sensor->dev->name); } @@ -218,9 +92,14 @@ static int sensing_init(void) if (ret) { LOG_ERR("set sensor:%s state:%d error", sensor->dev->name, state); } - LOG_INF("sensing init, sensor:%s state:%d", sensor->dev->name, sensor->state); + LOG_INF("sensing init, sensor:%s, state:%d", sensor->dev->name, sensor->state); } + k_sem_init(&ctx->event_sem, 0, 1); + + LOG_INF("create sensing runtime thread ok"); + ctx->sensing_initialized = true; + return ret; } @@ -231,15 +110,12 @@ int open_sensor(struct sensing_sensor *sensor, struct sensing_connection **conn) if (sensor->state != SENSING_SENSOR_STATE_READY) return -EINVAL; - /* allocate struct sensing_connection *conn and conn data for application client */ - tmp_conn = malloc(sizeof(*tmp_conn) + sensor->sample_size); + /* create connection from sensor to application(client = NULL) */ + tmp_conn = malloc(sizeof(*tmp_conn)); if (!tmp_conn) { - LOG_ERR("malloc memory for struct sensing_connection error"); return -ENOMEM; } - tmp_conn->data = (uint8_t *)tmp_conn + sizeof(*tmp_conn); - /* create connection from sensor to application(client = NULL) */ init_connection(tmp_conn, sensor, NULL); *conn = tmp_conn; @@ -258,10 +134,12 @@ int close_sensor(struct sensing_connection **conn) __ASSERT(!tmp_conn->sink, "sensor derived from device tree cannot be closed"); + __ASSERT(tmp_conn->source, "reporter should not be NULL"); + sys_slist_find_and_remove(&tmp_conn->source->client_list, &tmp_conn->snode); - *conn = NULL; free(*conn); + *conn = NULL; return 0; } @@ -280,7 +158,7 @@ int sensing_register_callback(struct sensing_connection *conn, LOG_ERR("callback should not be NULL"); return -ENODEV; } - conn->data_evt_cb = cb_list->on_data_event; + conn->callback_list = *cb_list; return 0; } @@ -320,4 +198,5 @@ int sensing_get_sensors(int *sensor_nums, const struct sensing_sensor_info **inf } -SYS_INIT(sensing_init, APPLICATION, CONFIG_APPLICATION_INIT_PRIORITY); +DEVICE_DT_INST_DEFINE(0, sensing_init, NULL, &sensing_ctx, NULL, \ + POST_KERNEL, CONFIG_SENSOR_INIT_PRIORITY, NULL); diff --git a/subsys/sensing/sensor_mgmt.h b/subsys/sensing/sensor_mgmt.h index 38219305304..7988958af29 100644 --- a/subsys/sensing/sensor_mgmt.h +++ b/subsys/sensing/sensor_mgmt.h @@ -11,100 +11,42 @@ #include #include #include +#include +#include #ifdef __cplusplus extern "C" { #endif -#define PHANDLE_DEVICE_BY_IDX(idx, node, prop) \ - DEVICE_DT_GET(DT_PHANDLE_BY_IDX(node, prop, idx)) +#define for_each_sensor(sensor) \ + STRUCT_SECTION_FOREACH(sensing_sensor, sensor) -#define PHANDLE_DEVICE_LIST(node, prop) \ -{ \ - LISTIFY(DT_PROP_LEN_OR(node, prop, 0), \ - PHANDLE_DEVICE_BY_IDX, \ - (,), \ - node, \ - prop) \ -} +#define for_each_sensor_reverse(sensor) \ + STRUCT_SECTION_START_EXTERN(sensing_sensor); \ + STRUCT_SECTION_END_EXTERN(sensing_sensor); \ + for (struct sensing_sensor *sensor = STRUCT_SECTION_END(sensing_sensor) \ + - 1; \ + ({ __ASSERT(sensor >= STRUCT_SECTION_START(sensing_sensor) - 1, \ + "unexpected list start location"); \ + sensor >= STRUCT_SECTION_START(sensing_sensor); }); \ + sensor--) -#define SENSING_SENSOR_INFO_NAME(node) \ - _CONCAT(__sensing_sensor_info_, DEVICE_DT_NAME_GET(node)) - -#define SENSING_SENSOR_INFO_DEFINE(node) \ - const static STRUCT_SECTION_ITERABLE(sensing_sensor_info, \ - SENSING_SENSOR_INFO_NAME(node)) = { \ - .type = DT_PROP(node, sensor_type), \ - .name = DT_NODE_FULL_NAME(node), \ - .friendly_name = DT_PROP(node, friendly_name), \ - .vendor = DT_NODE_VENDOR_OR(node, NULL), \ - .model = DT_NODE_MODEL_OR(node, NULL), \ - .minimal_interval = DT_PROP(node, minimal_interval), \ - }; - -#define SENSING_SENSOR_NAME(node) \ - _CONCAT(__sensing_sensor_, DEVICE_DT_NAME_GET(node)) - -#define SENSING_SENSOR_DEFINE(node) \ - static STRUCT_SECTION_ITERABLE(sensing_sensor, \ - SENSING_SENSOR_NAME(node)) = { \ - .dev = DEVICE_DT_GET(node), \ - .info = &SENSING_SENSOR_INFO_NAME(node), \ - .reporter_num = DT_PROP_LEN_OR(node, reporters, 0), \ - .reporters = PHANDLE_DEVICE_LIST(node, reporters), \ - }; - -#define for_each_sensor(ctx, i, sensor) \ - for (i = 0; i < ctx->sensor_num && (sensor = ctx->sensors[i]) != NULL; i++) - -enum sensor_trigger_mode { - SENSOR_TRIGGER_MODE_POLLING = 1, - SENSOR_TRIGGER_MODE_DATA_READY = 2, -}; -/** - * @struct sensing_connection information - * @brief sensing_connection indicates connection from reporter(source) to client(sink) - */ -struct sensing_connection { - struct sensing_sensor *source; - struct sensing_sensor *sink; - /* interval and sensitivity set from client(sink) to reporter(source) */ - uint32_t interval; - int sensitivity[CONFIG_SENSING_MAX_SENSITIVITY_COUNT]; - /* copy sensor data to connection data buf from reporter */ - void *data; - /* client(sink) next consume time */ - sys_snode_t snode; - /* post data to application */ - sensing_data_event_t data_evt_cb; -}; +#define for_each_client_conn(sensor, client) \ + SYS_SLIST_FOR_EACH_CONTAINER(&sensor->client_list, client, snode) +#define EXEC_TIME_INIT 0 +#define EXEC_TIME_OFF UINT64_MAX + +extern struct rtio sensing_rtio_ctx; /** - * @struct sensing_sensor - * @brief Internal sensor instance data structure. - * - * Each sensor instance will have its unique data structure for storing all - * it's related information. - * - * Sensor management will enumerate all these instance data structures, - * build report relationship model base on them, etc. + * @struct sensing_context + * @brief sensing subsystem context to include global variables */ -struct sensing_sensor { - const struct device *dev; - const struct sensing_sensor_info *info; - const uint16_t reporter_num; - sys_slist_t client_list; - uint32_t interval; - uint8_t sensitivity_count; - int sensitivity[CONFIG_SENSING_MAX_SENSITIVITY_COUNT]; - enum sensing_sensor_state state; - enum sensor_trigger_mode mode; - /* runtime info */ - uint16_t sample_size; - void *data_buf; - struct sensing_connection *conns; - const struct device *reporters[]; +struct sensing_context { + bool sensing_initialized; + struct k_sem event_sem; + atomic_t event_flag; }; int open_sensor(struct sensing_sensor *sensor, struct sensing_connection **conn); @@ -116,24 +58,28 @@ int get_interval(struct sensing_connection *con, uint32_t *sensitivity); int set_sensitivity(struct sensing_connection *conn, int8_t index, uint32_t interval); int get_sensitivity(struct sensing_connection *con, int8_t index, uint32_t *sensitivity); - -static inline bool is_phy_sensor(struct sensing_sensor *sensor) +static inline struct sensing_sensor *get_sensor_by_dev(const struct device *dev) { - return sensor->reporter_num == 0; + STRUCT_SECTION_FOREACH(sensing_sensor, sensor) { + if (sensor->dev == dev) { + return sensor; + } + } + + __ASSERT(true, "device %s is not a sensing sensor", dev->name); + + return NULL; } static inline uint16_t get_reporter_sample_size(const struct sensing_sensor *sensor, int i) { + const struct sensing_sensor *reporter; + __ASSERT(i < sensor->reporter_num, "dt index should less than reporter num"); - return ((struct sensing_sensor_ctx *) - sensor->reporters[i]->data)->register_info->sample_size; -} + reporter = sensor->conns[i].source; -static inline struct sensing_sensor *get_sensor_by_dev(const struct device *dev) -{ - return dev ? - (struct sensing_sensor *)((struct sensing_sensor_ctx *)dev->data)->priv_ptr : NULL; + return reporter->register_info->sample_size; } static inline struct sensing_sensor *get_reporter_sensor(struct sensing_sensor *sensor, int index) @@ -142,7 +88,7 @@ static inline struct sensing_sensor *get_reporter_sensor(struct sensing_sensor * return NULL; } - return get_sensor_by_dev(sensor->reporters[index]); + return sensor->conns[index].source; } static inline const struct sensing_sensor_info *get_sensor_info(struct sensing_connection *conn) @@ -154,6 +100,40 @@ static inline const struct sensing_sensor_info *get_sensor_info(struct sensing_c return conn->source->info; } +/* check if client has requested data from reporter */ +static inline bool is_client_request_data(struct sensing_connection *conn) +{ + return conn->interval != 0; +} + +static inline uint64_t get_us(void) +{ + return k_ticks_to_us_floor64(k_uptime_ticks()); +} + +static inline bool is_sensor_state_ready(struct sensing_sensor *sensor) +{ + return (sensor->state == SENSING_SENSOR_STATE_READY); +} + +/* this function is used to decide whether filtering sensitivity checking + * for example: filter sensitivity checking if sensitivity value is 0. + */ +static inline bool is_filtering_sensitivity(int *sensitivity) +{ + bool filtering = false; + + __ASSERT(sensitivity, "sensitivity should not be NULL"); + for (int i = 0; i < CONFIG_SENSING_MAX_SENSITIVITY_COUNT; i++) { + if (sensitivity[i] != 0) { + filtering = true; + break; + } + } + + return filtering; +} + /** * @} */ @@ -162,5 +142,4 @@ static inline const struct sensing_sensor_info *get_sensor_info(struct sensing_c } #endif - #endif /* SENSOR_MGMT_H_ */ From b73eafcc6141c38489d4151e203bc1459e78a9a5 Mon Sep 17 00:00:00 2001 From: Zhang Lixu Date: Mon, 23 Oct 2023 21:25:21 +0800 Subject: [PATCH 2740/3723] sensing: implement set/get interval and sensitivity 1. set/get interval sensitivity is implmented in sensor management module. 2. add the runtime thread to handle the sensor configuration. Signed-off-by: Zhang Lixu --- subsys/sensing/Kconfig | 39 +++++ subsys/sensing/sensor_mgmt.c | 307 ++++++++++++++++++++++++++++++++++- 2 files changed, 342 insertions(+), 4 deletions(-) diff --git a/subsys/sensing/Kconfig b/subsys/sensing/Kconfig index aec9cab59c1..5bd00c8a145 100644 --- a/subsys/sensing/Kconfig +++ b/subsys/sensing/Kconfig @@ -18,6 +18,22 @@ module = SENSING module-str = sensing source "subsys/logging/Kconfig.template.log_config" +config SENSING_RTIO_SQE_NUM + int "Number of the sensing RTIO SQE" + default 32 + +config SENSING_RTIO_CQE_NUM + int "Number of the sensing RTIO SQE" + default 32 + +config SENSING_RTIO_BLOCK_SIZE + int "Block size of the RTIO context" + default 64 + +config SENSING_RTIO_BLOCK_COUNT + int "Number of memory blocks of the RTIO context" + default 32 + config SENSING_MAX_SENSITIVITY_COUNT int "maximum sensitivity count one sensor could support" depends on SENSING @@ -28,6 +44,29 @@ config SENSING_MAX_SENSITIVITY_COUNT So, maximum sensitivity count is needed for sensors Typical values are 6 +config SENSING_RUNTIME_THREAD_STACK_SIZE + int "stack size for sensing subsystem runtime thread" + depends on SENSING + default 4096 + help + This is the stack size for sensing subsystem runtime thread + Typical values are 4096 + +config SENSING_RUNTIME_THREAD_PRIORITY + int "priority for sensing subsystem runtime thread" + depends on SENSING + default 7 + help + This is the thread priority for sensor subsystem runtime thread + Ring buffer data is stored by runtime thread, and then give semaphore + to notify dispatch thread, runtime thread priority should lower than + dispatch thread priority to ensure dispatch thread could fetch data as + soon as runtime thread give semaphore. Take for example, if runtime + priority is higher than dispatch thread, and runtime running in full + loading with no sleep, then dispatch thread has no change to fetch + data, then ring buf will always be put into data until overflow. + Typical values are 9 + source "subsys/sensing/sensor/phy_3d_sensor/Kconfig" endif # SENSING diff --git a/subsys/sensing/sensor_mgmt.c b/subsys/sensing/sensor_mgmt.c index 5fb9d3e03a6..403311934da 100644 --- a/subsys/sensing/sensor_mgmt.c +++ b/subsys/sensing/sensor_mgmt.c @@ -5,8 +5,10 @@ */ #include #include +#include #include #include +#include #include #include #include @@ -22,6 +24,216 @@ LOG_MODULE_REGISTER(sensing, CONFIG_SENSING_LOG_LEVEL); static struct sensing_context sensing_ctx = { }; +RTIO_DEFINE_WITH_MEMPOOL(sensing_rtio_ctx, CONFIG_SENSING_RTIO_SQE_NUM, + CONFIG_SENSING_RTIO_CQE_NUM, + CONFIG_SENSING_RTIO_BLOCK_COUNT, + CONFIG_SENSING_RTIO_BLOCK_SIZE, 4); + +/* sensor_later_config including arbitrate/set interval/sensitivity + */ +static uint32_t arbitrate_interval(struct sensing_sensor *sensor) +{ + struct sensing_connection *conn; + uint32_t min_interval = UINT32_MAX; + uint32_t interval; + + /* search from all clients, arbitrate the interval */ + for_each_client_conn(sensor, conn) { + LOG_INF("arbitrate interval, sensor:%s for each conn:%p, interval:%d(us)", + sensor->dev->name, conn, conn->interval); + if (!is_client_request_data(conn)) { + continue; + } + if (conn->interval < min_interval) { + min_interval = conn->interval; + } + } + /* min_interval == UINT32_MAX means sensor is not opened by any clients, + * then interval should be 0 + */ + interval = (min_interval == UINT32_MAX ? 0 : min_interval); + + LOG_DBG("arbitrate interval, sensor:%s, interval:%d(us)", + sensor->dev->name, interval); + + return interval; +} + +static int set_arbitrate_interval(struct sensing_sensor *sensor, uint32_t interval) +{ + struct sensor_read_config *config = sensor->iodev->data; + struct sensor_value odr = {0}; + int ret; + + __ASSERT(sensor && sensor->dev, "set arbitrate interval, sensor or sensor device is NULL"); + + LOG_INF("set arbitrate interval:%d, sensor:%s, is_streaming:%d", + interval, sensor->dev->name, config->is_streaming); + + if (interval) { + odr.val1 = USEC_PER_SEC / interval; + odr.val2 = (uint64_t)USEC_PER_SEC * 1000000 / interval % 1000000; + } + + /* The SENSOR_CHAN_MAX should be overridden by sensing sensor driver */ + ret = sensor_attr_set(sensor->dev, SENSOR_CHAN_MAX, + SENSOR_ATTR_SAMPLING_FREQUENCY, &odr); + if (ret) { + LOG_ERR("%s set attr freq failed:%d", sensor->dev->name, ret); + return ret; + } + + if (sensor->interval) { + if (config->is_streaming) { + rtio_sqe_cancel(sensor->stream_sqe); + } else { + k_timer_stop(&sensor->timer); + } + } + + if (interval) { + if (config->is_streaming) { + ret = sensor_stream(sensor->iodev, &sensing_rtio_ctx, + sensor, &sensor->stream_sqe); + } else { + k_timer_start(&sensor->timer, K_USEC(interval), + K_USEC(interval)); + } + } + + sensor->interval = interval; + + return ret; +} + +static int config_interval(struct sensing_sensor *sensor) +{ + uint32_t interval = arbitrate_interval(sensor); + + LOG_INF("config interval, sensor:%s, interval:%d", sensor->dev->name, interval); + + return set_arbitrate_interval(sensor, interval); +} + +static uint32_t arbitrate_sensitivity(struct sensing_sensor *sensor, int index) +{ + struct sensing_connection *conn; + uint32_t min_sensitivity = UINT32_MAX; + + /* search from all clients, arbitrate the sensitivity */ + for_each_client_conn(sensor, conn) { + LOG_DBG("arbitrate sensitivity, sensor:%s for each conn:%p, idx:%d, sens:%d", + sensor->dev->name, conn, index, + conn->sensitivity[index]); + if (!is_client_request_data(conn)) { + continue; + } + if (conn->sensitivity[index] < min_sensitivity) { + min_sensitivity = conn->sensitivity[index]; + } + } + LOG_DBG("arbitrate sensitivity, sensor:%s, min_sensitivity:%d", + sensor->dev->name, min_sensitivity); + + /* min_sensitivity == UINT32_MAX means no client is requesting to open sensor, + * by any client, in this case, return sensitivity 0 + */ + return (min_sensitivity == UINT32_MAX ? 0 : min_sensitivity); +} + +static int set_arbitrate_sensitivity(struct sensing_sensor *sensor, int index, uint32_t sensitivity) +{ + struct sensor_value threshold = {.val1 = sensitivity}; + + /* update sensor sensitivity */ + sensor->sensitivity[index] = sensitivity; + + /* The SENSOR_CHAN_PRIV_START should be overridden by sensing sensor + * driver, SENSOR_ATTR_HYSTERESIS can be overridden for different + * sensora type. + */ + return sensor_attr_set(sensor->dev, SENSOR_CHAN_PRIV_START + index, + SENSOR_ATTR_HYSTERESIS, &threshold); +} + +static int config_sensitivity(struct sensing_sensor *sensor, int index) +{ + uint32_t sensitivity = arbitrate_sensitivity(sensor, index); + + LOG_INF("config sensitivity, sensor:%s, index:%d, sensitivity:%d", + sensor->dev->name, index, sensitivity); + + return set_arbitrate_sensitivity(sensor, index, sensitivity); +} + +static int config_sensor(struct sensing_sensor *sensor) +{ + int ret; + int i = 0; + + ret = config_interval(sensor); + if (ret) { + LOG_WRN("sensor:%s config interval error", sensor->dev->name); + } + + for (i = 0; i < sensor->sensitivity_count; i++) { + ret = config_sensitivity(sensor, i); + if (ret) { + LOG_WRN("sensor:%s config sensitivity index:%d error:%d", + sensor->dev->name, i, ret); + } + } + + return ret; +} + +static void sensor_later_config(void) +{ + LOG_INF("sensor later config begin..."); + + for_each_sensor_reverse(sensor) { + if (atomic_test_and_clear_bit(&sensor->flag, SENSOR_LATER_CFG_BIT)) { + LOG_INF("sensor later config, sensor:%s", + sensor->dev->name); + config_sensor(sensor); + } + } +} + +static void sensing_runtime_thread(void *p1, void *p2, void *p3) +{ + struct sensing_context *ctx = p1; + int ret; + + LOG_INF("sensing runtime thread start..."); + + do { + ret = k_sem_take(&ctx->event_sem, K_FOREVER); + if (!ret) { + if (atomic_test_and_clear_bit(&ctx->event_flag, EVENT_CONFIG_READY)) { + LOG_INF("runtime thread triggered by EVENT_CONFIG_READY"); + sensor_later_config(); + } + } + } while (1); +} + +static void save_config_and_notify(struct sensing_sensor *sensor) +{ + struct sensing_context *ctx = &sensing_ctx; + + __ASSERT(sensor, "save config and notify, sensing_sensor not be NULL"); + + LOG_INF("save config and notify, sensor:%s", sensor->dev->name); + + /* remember sensor_later_config bit to sensor */ + atomic_set_bit(&sensor->flag, SENSOR_LATER_CFG_BIT); + + /*remember event config ready and notify sensing_runtime_thread */ + atomic_set_bit(&ctx->event_flag, EVENT_CONFIG_READY); + + k_sem_give(&ctx->event_sem); +} static int set_sensor_state(struct sensing_sensor *sensor, enum sensing_sensor_state state) { @@ -52,6 +264,15 @@ static void init_connection(struct sensing_connection *conn, sys_slist_append(&conn->source->client_list, &conn->snode); } +static void sensing_sensor_polling_timer(struct k_timer *timer_id) +{ + struct sensing_sensor *sensor = CONTAINER_OF(timer_id, + struct sensing_sensor, timer); + + /* TODO: move it into sensing_runtime_thread */ + sensor_read(sensor->iodev, &sensing_rtio_ctx, sensor); +} + static int init_sensor(struct sensing_sensor *sensor) { struct sensing_connection *conn; @@ -59,6 +280,7 @@ static int init_sensor(struct sensing_sensor *sensor) __ASSERT(sensor && sensor->dev, "init sensor, sensor or sensor device is NULL"); + k_timer_init(&sensor->timer, sensing_sensor_polling_timer, NULL); sys_slist_init(&sensor->client_list); for (i = 0; i < sensor->reporter_num; i++) { @@ -138,6 +360,8 @@ int close_sensor(struct sensing_connection **conn) sys_slist_find_and_remove(&tmp_conn->source->client_list, &tmp_conn->snode); + save_config_and_notify(tmp_conn->source); + free(*conn); *conn = NULL; @@ -165,22 +389,95 @@ int sensing_register_callback(struct sensing_connection *conn, int set_interval(struct sensing_connection *conn, uint32_t interval) { - return -ENOTSUP; + LOG_INF("set interval, sensor:%s, interval:%u(us)", conn->source->dev->name, interval); + + __ASSERT(conn && conn->source, "set interval, connection or reporter not be NULL"); + + if (interval > 0 && interval < conn->source->info->minimal_interval) { + LOG_ERR("interval:%d(us) should no less than min interval:%d(us)", + interval, conn->source->info->minimal_interval); + return -EINVAL; + } + + conn->interval = interval; + conn->next_consume_time = EXEC_TIME_INIT; + + LOG_INF("set interval, sensor:%s, conn:%p, interval:%d", + conn->source->dev->name, conn, interval); + + save_config_and_notify(conn->source); + + return 0; } int get_interval(struct sensing_connection *conn, uint32_t *interval) { - return -ENOTSUP; + __ASSERT(conn, "get interval, connection not be NULL"); + *interval = conn->interval; + + LOG_INF("get interval, sensor:%s, interval:%u(us)", conn->source->dev->name, *interval); + + return 0; } int set_sensitivity(struct sensing_connection *conn, int8_t index, uint32_t sensitivity) { - return -ENOTSUP; + int i; + + __ASSERT(conn && conn->source, "set sensitivity, connection or reporter not be NULL"); + + LOG_INF("set sensitivity, sensor:%s, index:%d, sensitivity:%d, count:%d", + conn->source->dev->name, index, + sensitivity, conn->source->sensitivity_count); + + if (index < SENSING_SENSITIVITY_INDEX_ALL || index >= conn->source->sensitivity_count) { + LOG_ERR("sensor:%s sensitivity index:%d invalid", conn->source->dev->name, index); + return -EINVAL; + } + + if (index == SENSING_SENSITIVITY_INDEX_ALL) { + for (i = 0; i < conn->source->sensitivity_count; i++) { + conn->sensitivity[i] = sensitivity; + } + } else { + conn->sensitivity[index] = sensitivity; + } + + return 0; } int get_sensitivity(struct sensing_connection *conn, int8_t index, uint32_t *sensitivity) { - return -ENOTSUP; + int i = 0; + + __ASSERT(conn && conn->source, "get sensitivity, connection or reporter not be NULL"); + + *sensitivity = UINT32_MAX; + + if (index < SENSING_SENSITIVITY_INDEX_ALL || index >= conn->source->sensitivity_count) { + LOG_ERR("sensor:%s sensitivity index:%d invalid", conn->source->dev->name, index); + return -EINVAL; + } + + if (index == SENSING_SENSITIVITY_INDEX_ALL) { + /* each sensitivity index value should be same for global sensitivity */ + for (i = 1; i < conn->source->sensitivity_count; i++) { + if (conn->sensitivity[i] != conn->sensitivity[0]) { + LOG_ERR("sensitivity[%d]:%d should be same as sensitivity:%d", + i, conn->sensitivity[i], conn->sensitivity[0]); + return -EINVAL; + } + } + *sensitivity = conn->sensitivity[0]; + } else { + *sensitivity = conn->sensitivity[index]; + } + + LOG_INF("get_sensitivity, sensor:%s, index:%d, sensitivity:%d, count:%d", + conn->source->dev->name, index, + *sensitivity, conn->source->sensitivity_count); + + return 0; } int sensing_get_sensors(int *sensor_nums, const struct sensing_sensor_info **info) @@ -197,6 +494,8 @@ int sensing_get_sensors(int *sensor_nums, const struct sensing_sensor_info **inf return 0; } +K_THREAD_DEFINE(sensing_runtime, CONFIG_SENSING_RUNTIME_THREAD_STACK_SIZE, sensing_runtime_thread, + &sensing_ctx, NULL, NULL, CONFIG_SENSING_RUNTIME_THREAD_PRIORITY, 0, 0); DEVICE_DT_INST_DEFINE(0, sensing_init, NULL, &sensing_ctx, NULL, \ POST_KERNEL, CONFIG_SENSOR_INIT_PRIORITY, NULL); From 7b6e1a32d083fe00e8b144eb2bae1fad9b613745 Mon Sep 17 00:00:00 2001 From: Zhang Lixu Date: Mon, 23 Oct 2023 21:35:28 +0800 Subject: [PATCH 2741/3723] sensing: implement sensor data dispatching Create the dispatch thread to send sensor data to its client by checking time. Signed-off-by: Zhang Lixu --- subsys/sensing/CMakeLists.txt | 1 + subsys/sensing/Kconfig | 18 +++++ subsys/sensing/dispatch.c | 124 ++++++++++++++++++++++++++++++++++ 3 files changed, 143 insertions(+) create mode 100644 subsys/sensing/dispatch.c diff --git a/subsys/sensing/CMakeLists.txt b/subsys/sensing/CMakeLists.txt index 59aa28514b0..eab862ac4a0 100644 --- a/subsys/sensing/CMakeLists.txt +++ b/subsys/sensing/CMakeLists.txt @@ -5,6 +5,7 @@ zephyr_library_include_directories(include) zephyr_library_sources( sensor_mgmt.c + dispatch.c sensing.c sensing_sensor.c ) diff --git a/subsys/sensing/Kconfig b/subsys/sensing/Kconfig index 5bd00c8a145..ee2f3f6abdf 100644 --- a/subsys/sensing/Kconfig +++ b/subsys/sensing/Kconfig @@ -67,6 +67,24 @@ config SENSING_RUNTIME_THREAD_PRIORITY data, then ring buf will always be put into data until overflow. Typical values are 9 +config SENSING_DISPATCH_THREAD_STACK_SIZE + int "stack size for sensor dispatch thread" + depends on SENSING + default 1024 + help + This is the stack size for sensor dispatch thread + Typical values are 1024 + +config SENSING_DISPATCH_THREAD_PRIORITY + int "priority for sensor dispatch thread" + depends on SENSING + default 8 + help + This is the thread priority for sensing subsystem dispatch thread + Ring buffer data should be fetched ASAP, so Dispatch + thread priority should be higher than runtime thread + Typical values are 8 + source "subsys/sensing/sensor/phy_3d_sensor/Kconfig" endif # SENSING diff --git a/subsys/sensing/dispatch.c b/subsys/sensing/dispatch.c new file mode 100644 index 00000000000..5a85bd1d218 --- /dev/null +++ b/subsys/sensing/dispatch.c @@ -0,0 +1,124 @@ +/* + * Copyright (c) 2022 Intel Corporation. + * + * SPDX-License-Identifier: Apache-2.0 + */ +#include +#include +#include +#include +#include "sensor_mgmt.h" + +LOG_MODULE_DECLARE(sensing, CONFIG_SENSING_LOG_LEVEL); + +/* check whether it is right time for client to consume this sample */ +static inline bool sensor_test_consume_time(struct sensing_sensor *sensor, + struct sensing_connection *conn, + uint64_t cur_time) +{ + LOG_DBG("sensor:%s next_consume_time:%lld cur_time:%lld", + sensor->dev->name, conn->next_consume_time, cur_time); + + return conn->next_consume_time <= cur_time; +} + +static void update_client_consume_time(struct sensing_sensor *sensor, + struct sensing_connection *conn) +{ + uint32_t interval = conn->interval; + + if (conn->next_consume_time == 0) { + conn->next_consume_time = get_us(); + } + + conn->next_consume_time += interval; +} + +/* send data to clients based on interval and sensitivity */ +static int send_data_to_clients(struct sensing_sensor *sensor, + void *data) +{ + struct sensing_sensor *client; + struct sensing_connection *conn; + + for_each_client_conn(sensor, conn) { + client = conn->sink; + LOG_DBG("sensor:%s send data to client:%p", conn->source->dev->name, conn); + + if (!is_client_request_data(conn)) { + continue; + } + + /* sensor_test_consume_time(), check whether time is ready or not: + * true: it's time for client consuming the data + * false: client time not arrived yet, not consume the data + */ + if (!sensor_test_consume_time(sensor, conn, get_us())) { + continue; + } + + update_client_consume_time(sensor, conn); + + if (!conn->callback_list.on_data_event) { + LOG_WRN("sensor:%s event callback not registered", + conn->source->dev->name); + continue; + } + conn->callback_list.on_data_event(conn, data, + conn->callback_list.context); + } + + return 0; +} + +STRUCT_SECTION_START_EXTERN(sensing_sensor); +STRUCT_SECTION_END_EXTERN(sensing_sensor); + +static void dispatch_task(void *a, void *b, void *c) +{ + uint8_t *data = NULL; + uint32_t data_len = 0; + int rc; + int get_data_rc; + + ARG_UNUSED(a); + ARG_UNUSED(b); + ARG_UNUSED(c); + + if (IS_ENABLED(CONFIG_USERSPACE) && !k_is_user_context()) { + rtio_access_grant(&sensing_rtio_ctx, k_current_get()); + k_thread_user_mode_enter(dispatch_task, a, b, c); + } + + while (true) { + struct rtio_cqe cqe; + + rc = rtio_cqe_copy_out(&sensing_rtio_ctx, &cqe, 1, K_FOREVER); + if (rc < 1) { + continue; + } + + /* Cache the data from the CQE */ + rc = cqe.result; + + /* Get the associated data */ + get_data_rc = + rtio_cqe_get_mempool_buffer(&sensing_rtio_ctx, &cqe, &data, &data_len); + if (get_data_rc != 0 || data_len == 0) { + continue; + } + + if ((uintptr_t)cqe.userdata >= + (uintptr_t)STRUCT_SECTION_START(sensing_sensor) && + (uintptr_t)cqe.userdata < (uintptr_t)STRUCT_SECTION_END(sensing_sensor)) { + struct sensing_sensor *sensor = cqe.userdata; + + send_data_to_clients(sensor, data); + } + + rtio_release_buffer(&sensing_rtio_ctx, data, data_len); + } +} + +K_THREAD_DEFINE(sensing_dispatch, CONFIG_SENSING_DISPATCH_THREAD_STACK_SIZE, dispatch_task, + NULL, NULL, NULL, CONFIG_SENSING_DISPATCH_THREAD_PRIORITY, 0, 0); From 7675f3acbe3fc78c855263266b1d4a07bc83cd23 Mon Sep 17 00:00:00 2001 From: Zhang Lixu Date: Wed, 5 Jul 2023 09:30:08 +0800 Subject: [PATCH 2742/3723] sensor: add helper functions to convert milli/micro to sensor_value Add two helper functions as the couple functions of sensor_value_to_milli and sensor_value_to_micro. Signed-off-by: Zhang Lixu --- include/zephyr/drivers/sensor.h | 40 +++++++++++++++++++++++++++++++++ 1 file changed, 40 insertions(+) diff --git a/include/zephyr/drivers/sensor.h b/include/zephyr/drivers/sensor.h index 9a719948672..53d55e1f1a3 100644 --- a/include/zephyr/drivers/sensor.h +++ b/include/zephyr/drivers/sensor.h @@ -1353,6 +1353,46 @@ static inline int64_t sensor_value_to_micro(const struct sensor_value *val) return ((int64_t)val->val1 * 1000000) + val->val2; } +/** + * @brief Helper function for converting integer milli units to struct sensor_value. + * + * @param val A pointer to a sensor_value struct. + * @param milli The converted value. + * @return 0 if successful, negative errno code if failure. + */ +static inline int sensor_value_from_milli(struct sensor_value *val, int64_t milli) +{ + if (milli < ((int64_t)INT32_MIN - 1) * 1000LL || + milli > ((int64_t)INT32_MAX + 1) * 1000LL) { + return -ERANGE; + } + + val->val1 = (int32_t)(milli / 1000); + val->val2 = (int32_t)(milli % 1000) * 1000; + + return 0; +} + +/** + * @brief Helper function for converting integer micro units to struct sensor_value. + * + * @param val A pointer to a sensor_value struct. + * @param micro The converted value. + * @return 0 if successful, negative errno code if failure. + */ +static inline int sensor_value_from_micro(struct sensor_value *val, int64_t micro) +{ + if (micro < ((int64_t)INT32_MIN - 1) * 1000000LL || + micro > ((int64_t)INT32_MAX + 1) * 1000000LL) { + return -ERANGE; + } + + val->val1 = (int32_t)(micro / 1000000LL); + val->val2 = (int32_t)(micro % 1000000LL); + + return 0; +} + /** * @} */ From 593dab821880b0bfbfa891da20fd01a70488d249 Mon Sep 17 00:00:00 2001 From: Zhang Lixu Date: Mon, 23 Oct 2023 22:07:37 +0800 Subject: [PATCH 2743/3723] sensing: implement the phy_3d_sensor This patch is to implement the phy_3d_sensor in sensing subsystem. It's a wrapper layer of AGM sensor driver for sensing subsystem. It supports the accelerometer and gyrometer now. This has been tested with bmi160 on native_posix simulator. Signed-off-by: Zhang Lixu --- .../sensor/phy_3d_sensor/phy_3d_sensor.c | 192 +++++++++++++++++- .../sensor/phy_3d_sensor/phy_3d_sensor.h | 9 + 2 files changed, 200 insertions(+), 1 deletion(-) diff --git a/subsys/sensing/sensor/phy_3d_sensor/phy_3d_sensor.c b/subsys/sensing/sensor/phy_3d_sensor/phy_3d_sensor.c index 7b381bc1e83..d721836f91b 100644 --- a/subsys/sensing/sensor/phy_3d_sensor/phy_3d_sensor.c +++ b/subsys/sensing/sensor/phy_3d_sensor/phy_3d_sensor.c @@ -19,26 +19,216 @@ LOG_MODULE_REGISTER(phy_3d_sensor, CONFIG_SENSING_LOG_LEVEL); +#define SENSING_ACCEL_Q31_SHIFT 6 +#define SENSING_GYRO_Q31_SHIFT 15 + +static int64_t shifted_q31_to_scaled_int64(q31_t q, int8_t shift, int64_t scale) +{ + int64_t scaled_value; + int64_t shifted_value; + + shifted_value = (int64_t)q << shift; + shifted_value = llabs(shifted_value); + + scaled_value = + FIELD_GET(GENMASK64(31 + shift, 31), shifted_value) * scale + + (FIELD_GET(GENMASK64(30, 0), shifted_value) * scale / BIT(31)); + + if (q < 0) { + scaled_value = -scaled_value; + } + + return scaled_value; +} + +static q31_t scaled_int64_to_shifted_q31(int64_t val, int64_t scale, + int8_t shift) +{ + return (q31_t)((val * BIT(31 - shift) / scale)); +} + +static q31_t accel_sensor_value_to_q31(struct sensor_value *val) +{ + int64_t micro_ms2 = sensor_value_to_micro(val); + int64_t micro_g = micro_ms2 * 1000000LL / SENSOR_G; + + return scaled_int64_to_shifted_q31(micro_g, 1000000LL, + SENSING_ACCEL_Q31_SHIFT); +} + +static void accel_q31_to_sensor_value(q31_t q, struct sensor_value *val) +{ + int64_t micro_g = shifted_q31_to_scaled_int64(q, + SENSING_ACCEL_Q31_SHIFT, 1000000LL); + int64_t micro_ms2 = micro_g * SENSOR_G / 1000000LL; + + sensor_value_from_micro(val, micro_ms2); +} + +static const struct phy_3d_sensor_custom custom_accel = { + .chan_all = SENSOR_CHAN_ACCEL_XYZ, + .shift = SENSING_ACCEL_Q31_SHIFT, + .q31_to_sensor_value = accel_q31_to_sensor_value, + .sensor_value_to_q31 = accel_sensor_value_to_q31, +}; + +static q31_t gyro_sensor_value_to_q31(struct sensor_value *val) +{ + int64_t micro_rad = (int64_t)sensor_value_to_micro(val); + int64_t micro_deg = micro_rad * 180000000LL / SENSOR_PI; + + return scaled_int64_to_shifted_q31(micro_deg, 1000000LL, + SENSING_GYRO_Q31_SHIFT); +} + +static void gyro_q31_to_sensor_value(q31_t q, struct sensor_value *val) +{ + int64_t micro_deg = shifted_q31_to_scaled_int64(q, + SENSING_GYRO_Q31_SHIFT, 1000000LL); + int64_t micro_rad = micro_deg * SENSOR_PI / 180000000LL; + + sensor_value_from_micro(val, micro_rad); +} + +static const struct phy_3d_sensor_custom custom_gyro = { + .chan_all = SENSOR_CHAN_GYRO_XYZ, + .shift = SENSING_GYRO_Q31_SHIFT, + .q31_to_sensor_value = gyro_q31_to_sensor_value, + .sensor_value_to_q31 = gyro_sensor_value_to_q31, +}; + static int phy_3d_sensor_init(const struct device *dev) { const struct phy_3d_sensor_config *cfg = dev->config; + struct phy_3d_sensor_data *data = dev->data; + + switch (cfg->sensor_type) { + case SENSING_SENSOR_TYPE_MOTION_ACCELEROMETER_3D: + data->custom = &custom_accel; + break; + case SENSING_SENSOR_TYPE_MOTION_GYROMETER_3D: + data->custom = &custom_gyro; + break; + default: + LOG_ERR("phy_3d_sensor doesn't support sensor type %d", + cfg->sensor_type); + return -ENOTSUP; + } LOG_INF("%s: Underlying device: %s", dev->name, cfg->hw_dev->name); return 0; } +static int phy_3d_sensor_attr_set_hyst(const struct device *dev, + enum sensor_channel chan, + const struct sensor_value *val) +{ + const struct phy_3d_sensor_config *cfg = dev->config; + struct phy_3d_sensor_data *data = dev->data; + int index = chan - SENSOR_CHAN_PRIV_START; + int i, min = 0; + + if (index >= 0 && index < ARRAY_SIZE(data->sensitivities)) { + data->sensitivities[index] = *val; + } else if (index == SENSING_SENSITIVITY_INDEX_ALL) { + for (i = 0; i < ARRAY_SIZE(data->sensitivities); ++i) { + data->sensitivities[i] = *val; + } + min = ARRAY_SIZE(data->sensitivities) - 1; + } else { + LOG_ERR("%s: set sensitivity: invalid index: %d", + dev->name, index); + return -EINVAL; + } + + for (i = min + 1; i < ARRAY_SIZE(data->sensitivities); ++i) { + if ((data->sensitivities[i].val1 < + data->sensitivities[min].val1) || + (data->sensitivities[i].val1 == + data->sensitivities[min].val1 && + data->sensitivities[i].val2 < + data->sensitivities[min].val2)) { + min = i; + } + } + + chan = data->custom->chan_all; + + return sensor_attr_set(cfg->hw_dev, chan, SENSOR_ATTR_SLOPE_TH, + &data->sensitivities[min]); +} + static int phy_3d_sensor_attr_set(const struct device *dev, enum sensor_channel chan, enum sensor_attribute attr, const struct sensor_value *val) { - return 0; + const struct phy_3d_sensor_config *cfg = dev->config; + struct phy_3d_sensor_data *data = dev->data; + int ret = 0; + + switch (attr) { + case SENSOR_ATTR_HYSTERESIS: + ret = phy_3d_sensor_attr_set_hyst(dev, chan, val); + break; + + default: + chan = data->custom->chan_all; + ret = sensor_attr_set(cfg->hw_dev, chan, attr, val); + break; + } + + LOG_INF("%s:%s attr:%d ret:%d", __func__, dev->name, attr, ret); + return ret; } static int phy_3d_sensor_submit(const struct device *dev, struct rtio_iodev_sqe *sqe) { + const struct phy_3d_sensor_config *cfg = dev->config; + struct phy_3d_sensor_data *data = dev->data; + struct sensing_sensor_value_3d_q31 *sample; + struct sensor_value value[PHY_3D_SENSOR_CHANNEL_NUM]; + uint32_t buffer_len; + int i, ret; + + ret = rtio_sqe_rx_buf(sqe, sizeof(*sample), sizeof(*sample), + (uint8_t **)&sample, &buffer_len); + if (ret) { + rtio_iodev_sqe_err(sqe, ret); + return ret; + } + + ret = sensor_sample_fetch_chan(cfg->hw_dev, data->custom->chan_all); + if (ret) { + LOG_ERR("%s: sample fetch failed: %d", dev->name, ret); + rtio_iodev_sqe_err(sqe, ret); + return ret; + } + + ret = sensor_channel_get(cfg->hw_dev, data->custom->chan_all, value); + if (ret) { + LOG_ERR("%s: channel get failed: %d", dev->name, ret); + rtio_iodev_sqe_err(sqe, ret); + return ret; + } + + for (i = 0; i < ARRAY_SIZE(value); ++i) { + sample->readings[0].v[i] = + data->custom->sensor_value_to_q31(&value[i]); + } + + sample->header.reading_count = 1; + sample->shift = data->custom->shift; + + LOG_DBG("%s: Sample data:\t x: %d, y: %d, z: %d", + dev->name, + sample->readings[0].x, + sample->readings[0].y, + sample->readings[0].z); + + rtio_iodev_sqe_ok(sqe, 0); return 0; } diff --git a/subsys/sensing/sensor/phy_3d_sensor/phy_3d_sensor.h b/subsys/sensing/sensor/phy_3d_sensor/phy_3d_sensor.h index e426a552832..071c40dfcfb 100644 --- a/subsys/sensing/sensor/phy_3d_sensor/phy_3d_sensor.h +++ b/subsys/sensing/sensor/phy_3d_sensor/phy_3d_sensor.h @@ -8,10 +8,19 @@ #define ZEPHYR_INCLUDE_SPHY_3D_SENSOR_H_ #include +#include #define PHY_3D_SENSOR_CHANNEL_NUM 3 +struct phy_3d_sensor_custom { + const enum sensor_channel chan_all; + const int8_t shift; + void (*q31_to_sensor_value)(q31_t q31, struct sensor_value *val); + q31_t (*sensor_value_to_q31)(struct sensor_value *val); +}; + struct phy_3d_sensor_data { + const struct phy_3d_sensor_custom *custom; struct sensor_value sensitivities[PHY_3D_SENSOR_CHANNEL_NUM]; }; From f2bbfc8613ca83b5e69c584ac5235657f875ceea Mon Sep 17 00:00:00 2001 From: Zhang Lixu Date: Mon, 23 Oct 2023 22:31:18 +0800 Subject: [PATCH 2744/3723] sensing: add stream mode property for sensing sensor Add stream-mode property to indicate sensing sensor working stream mode or poll mode. Signed-off-by: Zhang Lixu --- dts/bindings/sensor/zephyr,sensing-sensor.yaml | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/dts/bindings/sensor/zephyr,sensing-sensor.yaml b/dts/bindings/sensor/zephyr,sensing-sensor.yaml index 5bcaa39f257..6b78dbdec0a 100644 --- a/dts/bindings/sensor/zephyr,sensing-sensor.yaml +++ b/dts/bindings/sensor/zephyr,sensing-sensor.yaml @@ -23,3 +23,7 @@ properties: reporters: type: phandles description: sensor reporters + + stream-mode: + type: boolean + description: sensor works on stream mode or poll mode From 18a257cbe40c3dd7f2227cd19844d76572cefe13 Mon Sep 17 00:00:00 2001 From: Zhang Lixu Date: Mon, 23 Oct 2023 22:24:32 +0800 Subject: [PATCH 2745/3723] sensing: add hinge angle sensor Add hinge angle virtual sensor for sensing subsystem, hinge angle sensor takes both base accel and lid accel as reporter. Signed-off-by: Zhang Lixu --- .../sensor/zephyr,sensing-hinge-angle.yaml | 10 ++ subsys/sensing/CMakeLists.txt | 1 + subsys/sensing/Kconfig | 1 + .../sensing/sensor/hinge_angle/CMakeLists.txt | 3 + subsys/sensing/sensor/hinge_angle/Kconfig | 9 + .../sensing/sensor/hinge_angle/hinge_angle.c | 167 ++++++++++++++++++ 6 files changed, 191 insertions(+) create mode 100644 dts/bindings/sensor/zephyr,sensing-hinge-angle.yaml create mode 100644 subsys/sensing/sensor/hinge_angle/CMakeLists.txt create mode 100644 subsys/sensing/sensor/hinge_angle/Kconfig create mode 100644 subsys/sensing/sensor/hinge_angle/hinge_angle.c diff --git a/dts/bindings/sensor/zephyr,sensing-hinge-angle.yaml b/dts/bindings/sensor/zephyr,sensing-hinge-angle.yaml new file mode 100644 index 00000000000..4d4e4415677 --- /dev/null +++ b/dts/bindings/sensor/zephyr,sensing-hinge-angle.yaml @@ -0,0 +1,10 @@ +# Copyright (c) 2023, Intel Corporation +# SPDX-License-Identifier: Apache-2.0 +# + +description: Sensing subsystem hinge angle sensor bindings. + +compatible: "zephyr,sensing-hinge-angle" + +# Common sensor subsystem sensor properties. +include: ["zephyr,sensing-sensor.yaml"] diff --git a/subsys/sensing/CMakeLists.txt b/subsys/sensing/CMakeLists.txt index eab862ac4a0..348f4ac54eb 100644 --- a/subsys/sensing/CMakeLists.txt +++ b/subsys/sensing/CMakeLists.txt @@ -11,3 +11,4 @@ zephyr_library_sources( ) add_subdirectory_ifdef(CONFIG_SENSING_SENSOR_PHY_3D_SENSOR sensor/phy_3d_sensor) +add_subdirectory_ifdef(CONFIG_SENSING_SENSOR_HINGE_ANGLE sensor/hinge_angle) diff --git a/subsys/sensing/Kconfig b/subsys/sensing/Kconfig index ee2f3f6abdf..971d5a6faf1 100644 --- a/subsys/sensing/Kconfig +++ b/subsys/sensing/Kconfig @@ -86,5 +86,6 @@ config SENSING_DISPATCH_THREAD_PRIORITY Typical values are 8 source "subsys/sensing/sensor/phy_3d_sensor/Kconfig" +source "subsys/sensing/sensor/hinge_angle/Kconfig" endif # SENSING diff --git a/subsys/sensing/sensor/hinge_angle/CMakeLists.txt b/subsys/sensing/sensor/hinge_angle/CMakeLists.txt new file mode 100644 index 00000000000..48d791eba80 --- /dev/null +++ b/subsys/sensing/sensor/hinge_angle/CMakeLists.txt @@ -0,0 +1,3 @@ +# SPDX-License-Identifier: Apache-2.0 + +zephyr_library_sources(hinge_angle.c) diff --git a/subsys/sensing/sensor/hinge_angle/Kconfig b/subsys/sensing/sensor/hinge_angle/Kconfig new file mode 100644 index 00000000000..465ab2fb148 --- /dev/null +++ b/subsys/sensing/sensor/hinge_angle/Kconfig @@ -0,0 +1,9 @@ +# Copyright (c) 2023 Intel Corporation +# SPDX-License-Identifier: Apache-2.0 + +config SENSING_SENSOR_HINGE_ANGLE + bool "Sensing hinge angle sensor" + default y + depends on DT_HAS_ZEPHYR_SENSING_HINGE_ANGLE_ENABLED + help + Enable sensing hinge angle sensor. diff --git a/subsys/sensing/sensor/hinge_angle/hinge_angle.c b/subsys/sensing/sensor/hinge_angle/hinge_angle.c new file mode 100644 index 00000000000..9df92f5927b --- /dev/null +++ b/subsys/sensing/sensor/hinge_angle/hinge_angle.c @@ -0,0 +1,167 @@ +/* + * Copyright (c) 2023 Intel Corporation. + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include +#include +#include +#include +#include + +LOG_MODULE_REGISTER(hinge_angle, CONFIG_SENSING_LOG_LEVEL); + +#define HINGE_REPORTER_NUM 2 + +static struct sensing_sensor_register_info hinge_reg = { + .flags = SENSING_SENSOR_FLAG_REPORT_ON_CHANGE, + .sample_size = sizeof(struct sensing_sensor_value_q31), + .sensitivity_count = 1, + .version.value = SENSING_SENSOR_VERSION(1, 0, 0, 0), +}; + +struct hinge_angle_context { + struct rtio_iodev_sqe *sqe; + sensing_sensor_handle_t reporters[HINGE_REPORTER_NUM]; + struct sensing_sensor_value_3d_q31 sample[HINGE_REPORTER_NUM]; + int has_sample[HINGE_REPORTER_NUM]; +}; + +static int hinge_init(const struct device *dev) +{ + struct hinge_angle_context *data = dev->data; + int ret; + + ret = sensing_sensor_get_reporters(dev, + SENSING_SENSOR_TYPE_MOTION_ACCELEROMETER_3D, + data->reporters, HINGE_REPORTER_NUM); + if (ret != HINGE_REPORTER_NUM) { + LOG_ERR("%s: reporter mismatch:%d", dev->name, ret); + return -ENODEV; + } + + LOG_INF("%s:Found reporter 0: %s", dev->name, + sensing_get_sensor_info(data->reporters[0])->name); + LOG_INF("%s:Found reporter 1: %s", dev->name, + sensing_get_sensor_info(data->reporters[1])->name); + + return 0; +} + +static int hinge_attr_set(const struct device *dev, + enum sensor_channel chan, + enum sensor_attribute attr, + const struct sensor_value *val) +{ + struct sensing_sensor_config config = {0}; + struct hinge_angle_context *data = dev->data; + int ret = 0; + + switch (attr) { + case SENSOR_ATTR_SAMPLING_FREQUENCY: + config.attri = SENSING_SENSOR_ATTRIBUTE_INTERVAL; + config.interval = (uint32_t)(USEC_PER_SEC * 1000LL / + sensor_value_to_milli(val)); + ret = sensing_set_config(data->reporters[0], &config, 1); + ret |= sensing_set_config(data->reporters[1], &config, 1); + break; + + case SENSOR_ATTR_HYSTERESIS: + break; + + default: + ret = -ENOTSUP; + break; + } + + LOG_INF("%s set attr:%d ret:%d", dev->name, attr, ret); + return ret; +} + +static int hinge_submit(const struct device *dev, + struct rtio_iodev_sqe *sqe) +{ + struct hinge_angle_context *data = dev->data; + + if (data->sqe) { + return -EBUSY; + } + + data->sqe = sqe; + return 0; +} + +static const struct sensor_driver_api hinge_api = { + .attr_set = hinge_attr_set, + .submit = hinge_submit, +}; + +static q31_t calc_hinge_angle(struct hinge_angle_context *data) +{ + q31_t val; + + LOG_INF("Acc 0: x:%08x y:%08x z:%08x", + data->sample[0].readings[0].x, + data->sample[0].readings[0].y, + data->sample[0].readings[0].z); + LOG_INF("Acc 1: x:%08x y:%08x z:%08x", + data->sample[1].readings[0].x, + data->sample[1].readings[0].y, + data->sample[1].readings[0].z); + + /* Todo: calc hinge angle base on data->sample[0] and data->sample[1] */ + val = 0; + + return val; +} + +static void hinge_reporter_on_data_event(sensing_sensor_handle_t handle, + const void *buf, void *context) +{ + struct hinge_angle_context *data = context; + struct sensing_sensor_value_q31 *sample; + uint32_t buffer_len = 0; + int both = 0; + int i, ret; + + for (i = 0; i < HINGE_REPORTER_NUM; ++i) { + if (handle == data->reporters[i]) { + memcpy(&data->sample[i], buf, sizeof(data->sample[i])); + data->has_sample[i] = 1; + } + both += data->has_sample[i]; + } + + if (both == HINGE_REPORTER_NUM) { + data->has_sample[0] = 0; + data->has_sample[1] = 0; + + ret = rtio_sqe_rx_buf(data->sqe, sizeof(*sample), sizeof(*sample), + (uint8_t **)&sample, &buffer_len); + if (ret) { + rtio_iodev_sqe_err(data->sqe, ret); + return; + } + + sample->readings[0].v = calc_hinge_angle(data); + + rtio_iodev_sqe_ok(data->sqe, 0); + } +} + +#define DT_DRV_COMPAT zephyr_sensing_hinge_angle +#define SENSING_HINGE_ANGLE_DT_DEFINE(_inst) \ + static struct hinge_angle_context _CONCAT(hinge_ctx, _inst); \ + static const struct sensing_callback_list _CONCAT(hinge_cb, _inst) = { \ + .on_data_event = hinge_reporter_on_data_event, \ + .context = &_CONCAT(hinge_ctx, _inst), \ + }; \ + SENSING_SENSOR_DT_INST_DEFINE(_inst, &hinge_reg, \ + &_CONCAT(hinge_cb, _inst), \ + &hinge_init, NULL, \ + &_CONCAT(hinge_ctx, _inst), NULL, \ + POST_KERNEL, CONFIG_SENSOR_INIT_PRIORITY, \ + &hinge_api); + +DT_INST_FOREACH_STATUS_OKAY(SENSING_HINGE_ANGLE_DT_DEFINE); From 91774cb0eb43560d1fa8b8c2d2287c6f9405f527 Mon Sep 17 00:00:00 2001 From: Zhang Lixu Date: Fri, 27 Oct 2023 11:49:00 +0800 Subject: [PATCH 2746/3723] samples: sensing: add more sample code 1. add sensing_set_config/sensing_get_config in sample code 2. add hinge_angle sensor in sample code. Build and test: west build -p -b native_sim samples/subsys/sensing/simple/ -t run Signed-off-by: Zhang Lixu --- .../sensing/simple/boards/native_sim.overlay | 10 ++ samples/subsys/sensing/simple/src/main.c | 126 +++++++++++++++++- 2 files changed, 133 insertions(+), 3 deletions(-) diff --git a/samples/subsys/sensing/simple/boards/native_sim.overlay b/samples/subsys/sensing/simple/boards/native_sim.overlay index d11630cd5d9..4f51532424f 100644 --- a/samples/subsys/sensing/simple/boards/native_sim.overlay +++ b/samples/subsys/sensing/simple/boards/native_sim.overlay @@ -41,5 +41,15 @@ minimal-interval = <625>; underlying-device = <&bmi160_spi>; }; + + hinge_angle: hinge-angle { + compatible = "zephyr,sensing-hinge-angle"; + status = "okay"; + sensor-type = <0x20B>; + friendly-name = "Hinge Angle Sensor"; + reporters = <&base_accel &lid_accel>; + minimal-interval = <100000>; + stream-mode; + }; }; }; diff --git a/samples/subsys/sensing/simple/src/main.c b/samples/subsys/sensing/simple/src/main.c index 7884acef3a6..277517bd307 100644 --- a/samples/subsys/sensing/simple/src/main.c +++ b/samples/subsys/sensing/simple/src/main.c @@ -17,6 +17,7 @@ static void acc_data_event_callback(sensing_sensor_handle_t handle, const void * { const struct sensing_sensor_info *info = sensing_get_sensor_info(handle); struct sensing_sensor_value_3d_q31 *sample = (struct sensing_sensor_value_3d_q31 *)buf; + ARG_UNUSED(context); LOG_INF("%s(%d), handle:%p, Sensor:%s data:(x:%d, y:%d, z:%d)", @@ -26,6 +27,17 @@ static void acc_data_event_callback(sensing_sensor_handle_t handle, const void * sample->readings[0].z); } +static void hinge_angle_data_event_callback(sensing_sensor_handle_t handle, const void *buf, + void *context) +{ + const struct sensing_sensor_info *info = sensing_get_sensor_info(handle); + struct sensing_sensor_value_q31 *sample = (struct sensing_sensor_value_q31 *)buf; + + ARG_UNUSED(context); + + LOG_INF("handle:%p, Sensor:%s data:(v:%d)", handle, info->name, sample->readings[0].v); +} + int main(void) { const struct sensing_callback_list base_acc_cb_list = { @@ -34,9 +46,17 @@ int main(void) const struct sensing_callback_list lid_acc_cb_list = { .on_data_event = &acc_data_event_callback, }; + const struct sensing_callback_list hinge_angle_cb_list = { + .on_data_event = &hinge_angle_data_event_callback, + }; const struct sensing_sensor_info *info; sensing_sensor_handle_t base_acc; sensing_sensor_handle_t lid_acc; + sensing_sensor_handle_t hinge_angle; + struct sensing_sensor_config base_acc_config; + struct sensing_sensor_config lid_acc_config; + struct sensing_sensor_config hinge_angle_config; + const struct sensing_sensor_info *tmp_sensor_info; int ret, i, num = 0; ret = sensing_get_sensors(&num, &info); @@ -65,18 +85,118 @@ int main(void) &lid_acc_cb_list, &lid_acc); if (ret) { - LOG_ERR("sensing_open_sensor, type:0x%x index:1 error:%d", + LOG_ERR("sensing_open_sensor_by_dt, type:0x%x index:1 error:%d", SENSING_SENSOR_TYPE_MOTION_ACCELEROMETER_3D, ret); } + ret = sensing_open_sensor_by_dt(DEVICE_DT_GET(DT_NODELABEL(hinge_angle)), + &hinge_angle_cb_list, + &hinge_angle); + if (ret) { + LOG_ERR("sensing_open_sensor_by_type, type:0x%x index:0 error:%d", + SENSING_SENSOR_TYPE_MOTION_HINGE_ANGLE, ret); + } + + /* set base acc, lid acc, hinge sensor interval */ + base_acc_config.attri = SENSING_SENSOR_ATTRIBUTE_INTERVAL; + base_acc_config.interval = 100 * USEC_PER_MSEC; + ret = sensing_set_config(base_acc, &base_acc_config, 1); + if (ret) { + LOG_ERR("base_acc sensing_set_interval error:%d\n", ret); + } + + lid_acc_config.attri = SENSING_SENSOR_ATTRIBUTE_INTERVAL; + lid_acc_config.interval = 100 * USEC_PER_MSEC; + ret = sensing_set_config(lid_acc, &lid_acc_config, 1); + if (ret) { + LOG_ERR("lid_acc sensing_set_interval error:%d\n", ret); + } + + tmp_sensor_info = sensing_get_sensor_info(hinge_angle); + hinge_angle_config.attri = SENSING_SENSOR_ATTRIBUTE_INTERVAL; + hinge_angle_config.interval = tmp_sensor_info->minimal_interval; + ret = sensing_set_config(hinge_angle, &hinge_angle_config, 1); + if (ret) { + LOG_ERR("hinge_angle sensing_set_interval error:%d\n", ret); + } + + memset(&base_acc_config, 0x00, sizeof(struct sensing_sensor_config)); + memset(&lid_acc_config, 0x00, sizeof(struct sensing_sensor_config)); + memset(&hinge_angle_config, 0x00, sizeof(struct sensing_sensor_config)); + + /* get base acc, lid acc, hinge sensor interval */ + base_acc_config.attri = SENSING_SENSOR_ATTRIBUTE_INTERVAL; + ret = sensing_get_config(base_acc, &base_acc_config, 1); + if (ret) { + LOG_ERR("base_acc sensing_get_interval error:%d\n", ret); + } + + lid_acc_config.attri = SENSING_SENSOR_ATTRIBUTE_INTERVAL; + ret = sensing_get_config(lid_acc, &lid_acc_config, 1); + if (ret) { + LOG_ERR("lid_acc sensing_get_interval error:%d\n", ret); + } + + hinge_angle_config.attri = SENSING_SENSOR_ATTRIBUTE_INTERVAL; + ret = sensing_get_config(hinge_angle, &hinge_angle_config, 1); + if (ret) { + LOG_ERR("hinge_angle sensing_get_interval error:%d\n", ret); + } + + /* set base acc, lid acc, hinge sensor sensitivity */ + base_acc_config.attri = SENSING_SENSOR_ATTRIBUTE_SENSITIVITY; + base_acc_config.data_field = SENSING_SENSITIVITY_INDEX_ALL; + base_acc_config.sensitivity = 0; + ret = sensing_set_config(base_acc, &base_acc_config, 1); + if (ret) { + LOG_ERR("base_acc sensing_set_sensitivity error:%d\n", ret); + } + + lid_acc_config.attri = SENSING_SENSOR_ATTRIBUTE_SENSITIVITY; + lid_acc_config.data_field = SENSING_SENSITIVITY_INDEX_ALL; + lid_acc_config.sensitivity = 0; + ret = sensing_set_config(lid_acc, &lid_acc_config, 1); + if (ret) { + LOG_ERR("lid_acc sensing_set_sensitivity error:%d\n", ret); + } + + hinge_angle_config.attri = SENSING_SENSOR_ATTRIBUTE_SENSITIVITY; + hinge_angle_config.data_field = SENSING_SENSITIVITY_INDEX_ALL; + hinge_angle_config.sensitivity = 1; + ret = sensing_set_config(hinge_angle, &hinge_angle_config, 1); + if (ret) { + LOG_ERR("hinge_angle sensing_set_sensitivity error:%d\n", ret); + } + + memset(&base_acc_config, 0x00, sizeof(struct sensing_sensor_config)); + memset(&lid_acc_config, 0x00, sizeof(struct sensing_sensor_config)); + memset(&hinge_angle_config, 0x00, sizeof(struct sensing_sensor_config)); + + /* get base acc, lid acc, hinge sensor sensitivity */ + base_acc_config.attri = SENSING_SENSOR_ATTRIBUTE_SENSITIVITY; + base_acc_config.data_field = SENSING_SENSITIVITY_INDEX_ALL; + ret = sensing_get_config(base_acc, &base_acc_config, 1); + if (ret) { + LOG_ERR("base_acc sensing_get_sensitivity error:%d\n", ret); + } + + lid_acc_config.attri = SENSING_SENSOR_ATTRIBUTE_SENSITIVITY; + lid_acc_config.data_field = SENSING_SENSITIVITY_INDEX_ALL; + ret = sensing_get_config(lid_acc, &lid_acc_config, 1); + if (ret) { + LOG_ERR("lid_acc sensing_get_sensitivity error:%d\n", ret); + } - ret = sensing_close_sensor(&base_acc); + hinge_angle_config.attri = SENSING_SENSOR_ATTRIBUTE_SENSITIVITY; + hinge_angle_config.data_field = SENSING_SENSITIVITY_INDEX_ALL; + ret = sensing_get_config(hinge_angle, &hinge_angle_config, 1); if (ret) { - LOG_ERR("sensing_close_sensor:%p error:%d", base_acc, ret); + LOG_ERR("hinge_angle sensing_get_sensitivity error:%d\n", ret); } ret = sensing_close_sensor(&lid_acc); if (ret) { LOG_ERR("sensing_close_sensor:%p error:%d", lid_acc, ret); } + return 0; } From f5595b4b9c3bbeb44a56d27a2854a172fc5eaad6 Mon Sep 17 00:00:00 2001 From: Zhang Lixu Date: Mon, 27 Nov 2023 14:28:56 +0800 Subject: [PATCH 2747/3723] sensing: support multiple sensor types in one device Many sensors have multiple functions, for example, icm42688 supports accel, gyro and temperature, and the sensor streaming api always mixes the multiple functions in one function call. So we need add a layer in sensing subsystem to dispatch the result returned from sensor streaming api for each function. I changed the sensor-type(int) to sensor-types(array) in sensing sensor device bindings, so that one device can map to multiple instances of sensing sensor. Signed-off-by: Zhang Lixu --- .../sensor/zephyr,sensing-sensor.yaml | 8 +- include/zephyr/sensing/sensing_sensor.h | 94 +++++++++---------- .../sensing/simple/boards/native_sim.overlay | 19 ++-- samples/subsys/sensing/simple/src/main.c | 66 +++---------- .../sensing/sensor/hinge_angle/hinge_angle.c | 2 +- .../sensor/phy_3d_sensor/phy_3d_sensor.c | 5 +- 6 files changed, 81 insertions(+), 113 deletions(-) diff --git a/dts/bindings/sensor/zephyr,sensing-sensor.yaml b/dts/bindings/sensor/zephyr,sensing-sensor.yaml index 6b78dbdec0a..e0b8aae492d 100644 --- a/dts/bindings/sensor/zephyr,sensing-sensor.yaml +++ b/dts/bindings/sensor/zephyr,sensing-sensor.yaml @@ -7,8 +7,8 @@ description: Sensing subsystem sensor common properties bindings. include: sensor-device.yaml properties: - sensor-type: - type: int + sensor-types: + type: array required: true description: sensor type id (follow HID spec definition) @@ -24,6 +24,10 @@ properties: type: phandles description: sensor reporters + reporters-index: + type: array + description: the index in sensor-types of reporter if the reporter support multiple sensor-types + stream-mode: type: boolean description: sensor works on stream mode or poll mode diff --git a/include/zephyr/sensing/sensing_sensor.h b/include/zephyr/sensing/sensing_sensor.h index 85f0db5a2a8..f1515c02574 100644 --- a/include/zephyr/sensing/sensing_sensor.h +++ b/include/zephyr/sensing/sensing_sensor.h @@ -112,82 +112,78 @@ struct sensing_sensor { struct sensing_connection *conns; }; -#define PHANDLE_DEVICE_BY_IDX(idx, node, prop) \ - DEVICE_DT_GET(DT_PHANDLE_BY_IDX(node, prop, idx)) +#define SENSING_SENSOR_INFO_NAME(node, idx) \ + _CONCAT(_CONCAT(__sensing_sensor_info_, idx), DEVICE_DT_NAME_GET(node)) -#define PHANDLE_DEVICE_LIST(node, prop) \ -{ \ - LISTIFY(DT_PROP_LEN_OR(node, prop, 0), \ - PHANDLE_DEVICE_BY_IDX, \ - (,), \ - node, \ - prop) \ -} - -#define SENSING_SENSOR_INFO_NAME(node) \ - _CONCAT(__sensing_sensor_info_, DEVICE_DT_NAME_GET(node)) - -#define SENSING_SENSOR_INFO_DEFINE(node) \ +#define SENSING_SENSOR_INFO_DEFINE(node, idx) \ const static STRUCT_SECTION_ITERABLE(sensing_sensor_info, \ - SENSING_SENSOR_INFO_NAME(node)) = { \ - .type = DT_PROP(node, sensor_type), \ + SENSING_SENSOR_INFO_NAME(node, idx)) = { \ + .type = DT_PROP_BY_IDX(node, sensor_types, idx), \ .name = DT_NODE_FULL_NAME(node), \ .friendly_name = DT_PROP(node, friendly_name), \ .vendor = DT_NODE_VENDOR_OR(node, NULL), \ .model = DT_NODE_MODEL_OR(node, NULL), \ - .minimal_interval = DT_PROP(node, minimal_interval), \ + .minimal_interval = DT_PROP(node, minimal_interval),\ }; -#define SENSING_CONNECTIONS_NAME(node) \ - _CONCAT(__sensing_connections, DEVICE_DT_NAME_GET(node)) +#define SENSING_CONNECTIONS_NAME(node, idx) \ + _CONCAT(_CONCAT(__sensing_connections_, idx), DEVICE_DT_NAME_GET(node)) + +#define SENSING_SENSOR_SOURCE_NAME(idx, node) \ + SENSING_SENSOR_NAME(DT_PHANDLE_BY_IDX(node, reporters, idx), \ + DT_PROP_BY_IDX(node, reporters_index, idx)) #define SENSING_SENSOR_SOURCE_EXTERN(idx, node) \ -extern struct sensing_sensor SENSING_SENSOR_NAME(DT_PHANDLE_BY_IDX(node, reporters, idx)); +extern struct sensing_sensor SENSING_SENSOR_SOURCE_NAME(idx, node); \ -#define SENSING_CONNECTION_INITIALIZER(source_node, cb_list_ptr) \ +#define SENSING_CONNECTION_INITIALIZER(source_name, cb_list_ptr) \ { \ .callback_list = *cb_list_ptr, \ - .source = &SENSING_SENSOR_NAME(source_node), \ + .source = &source_name, \ } -#define SENSING_CONNECTION_DEFINE(idx, node, cb_list_ptr) \ - SENSING_CONNECTION_INITIALIZER(DT_PHANDLE_BY_IDX(node, reporters, idx), cb_list_ptr) +#define SENSING_CONNECTION_DEFINE(idx, node, cb_list_ptr) \ + SENSING_CONNECTION_INITIALIZER(SENSING_SENSOR_SOURCE_NAME(idx, node), \ + cb_list_ptr) -#define SENSING_CONNECTIONS_DEFINE(node, num, cb_list_ptr) \ +#define SENSING_CONNECTIONS_DEFINE(node, idx, num, cb_list_ptr) \ LISTIFY(num, SENSING_SENSOR_SOURCE_EXTERN, \ (), node) \ static struct sensing_connection \ - SENSING_CONNECTIONS_NAME(node)[(num)] = { \ + SENSING_CONNECTIONS_NAME(node, idx)[(num)] = { \ LISTIFY(num, SENSING_CONNECTION_DEFINE, \ (,), node, cb_list_ptr) \ }; -#define SENSING_SENSOR_IODEV_NAME(node) \ - _CONCAT(__sensing_iodev_, DEVICE_DT_NAME_GET(node)) +#define SENSING_SENSOR_IODEV_NAME(node, idx) \ + _CONCAT(_CONCAT(__sensing_iodev_, idx), DEVICE_DT_NAME_GET(node)) -#define SENSING_SENSOR_IODEV_DEFINE(node) \ +#define SENSING_SENSOR_IODEV_DEFINE(node, idx) \ COND_CODE_1(DT_PROP(node, stream_mode), \ - (SENSOR_DT_STREAM_IODEV(SENSING_SENSOR_IODEV_NAME(node), node)), \ - (SENSOR_DT_READ_IODEV(SENSING_SENSOR_IODEV_NAME(node), node))); + (SENSOR_DT_STREAM_IODEV(SENSING_SENSOR_IODEV_NAME(node, idx), node)), \ + (SENSOR_DT_READ_IODEV(SENSING_SENSOR_IODEV_NAME(node, idx), node))); -#define SENSING_SENSOR_NAME(node) \ - _CONCAT(__sensing_sensor_, DEVICE_DT_NAME_GET(node)) +#define SENSING_SENSOR_NAME(node, idx) \ + _CONCAT(_CONCAT(__sensing_sensor_, idx), DEVICE_DT_NAME_GET(node)) -#define SENSING_SENSOR_DEFINE(node, reg_ptr, cb_list_ptr) \ - SENSING_SENSOR_INFO_DEFINE(node) \ - SENSING_CONNECTIONS_DEFINE(node, \ +#define SENSING_SENSOR_DEFINE(node, prop, idx, reg_ptr, cb_list_ptr) \ + SENSING_SENSOR_INFO_DEFINE(node, idx) \ + SENSING_CONNECTIONS_DEFINE(node, idx, \ DT_PROP_LEN_OR(node, reporters, 0), cb_list_ptr)\ - SENSING_SENSOR_IODEV_DEFINE(node) \ + SENSING_SENSOR_IODEV_DEFINE(node, idx) \ STRUCT_SECTION_ITERABLE(sensing_sensor, \ - SENSING_SENSOR_NAME(node)) = { \ + SENSING_SENSOR_NAME(node, idx)) = { \ .dev = DEVICE_DT_GET(node), \ - .info = &SENSING_SENSOR_INFO_NAME(node), \ + .info = &SENSING_SENSOR_INFO_NAME(node, idx), \ .register_info = reg_ptr, \ .reporter_num = DT_PROP_LEN_OR(node, reporters, 0), \ - .conns = SENSING_CONNECTIONS_NAME(node), \ - .iodev = &SENSING_SENSOR_IODEV_NAME(node), \ + .conns = SENSING_CONNECTIONS_NAME(node, idx), \ + .iodev = &SENSING_SENSOR_IODEV_NAME(node, idx), \ }; +#define SENSING_SENSORS_DEFINE(node, reg_ptr, cb_list_ptr) \ + DT_FOREACH_PROP_ELEM_VARGS(node, sensor_types, \ + SENSING_SENSOR_DEFINE, reg_ptr, cb_list_ptr) /** * @brief Like SENSOR_DEVICE_DT_DEFINE() with sensing specifics. * @@ -217,7 +213,7 @@ extern struct sensing_sensor SENSING_SENSOR_NAME(DT_PHANDLE_BY_IDX(node, reporte * @param api_ptr Provides an initial pointer to the API function struct used * by the driver. Can be NULL. */ -#define SENSING_SENSOR_DT_DEFINE(node_id, reg_ptr, cb_list_ptr, \ +#define SENSING_SENSORS_DT_DEFINE(node_id, reg_ptr, cb_list_ptr, \ init_fn, pm_device, \ data_ptr, cfg_ptr, level, prio, \ api_ptr, ...) \ @@ -225,19 +221,19 @@ extern struct sensing_sensor SENSING_SENSOR_NAME(DT_PHANDLE_BY_IDX(node, reporte data_ptr, cfg_ptr, level, prio, \ api_ptr, __VA_ARGS__); \ \ - SENSING_SENSOR_DEFINE(node_id, reg_ptr, cb_list_ptr); + SENSING_SENSORS_DEFINE(node_id, reg_ptr, cb_list_ptr); /** - * @brief Like SENSING_SENSOR_DT_DEFINE() for an instance of a DT_DRV_COMPAT + * @brief Like SENSING_SENSORS_DT_DEFINE() for an instance of a DT_DRV_COMPAT * compatible * * @param inst instance number. This is replaced by - * DT_DRV_COMPAT(inst) in the call to SENSING_SENSOR_DT_DEFINE(). + * DT_DRV_COMPAT(inst) in the call to SENSING_SENSORS_DT_DEFINE(). * - * @param ... other parameters as expected by SENSING_SENSOR_DT_DEFINE(). + * @param ... other parameters as expected by SENSING_SENSORS_DT_DEFINE(). */ -#define SENSING_SENSOR_DT_INST_DEFINE(inst, reg_ptr, cb_list_ptr, ...) \ - SENSING_SENSOR_DT_DEFINE(DT_DRV_INST(inst), reg_ptr, \ +#define SENSING_SENSORS_DT_INST_DEFINE(inst, reg_ptr, cb_list_ptr, ...) \ + SENSING_SENSORS_DT_DEFINE(DT_DRV_INST(inst), reg_ptr, \ cb_list_ptr, __VA_ARGS__) /** diff --git a/samples/subsys/sensing/simple/boards/native_sim.overlay b/samples/subsys/sensing/simple/boards/native_sim.overlay index 4f51532424f..73a81b81f64 100644 --- a/samples/subsys/sensing/simple/boards/native_sim.overlay +++ b/samples/subsys/sensing/simple/boards/native_sim.overlay @@ -4,6 +4,8 @@ * SPDX-License-Identifier: Apache-2.0 */ +#include + &i2c0 { bmi160_i2c: bmi@68 { compatible = "bosch,bmi160"; @@ -24,20 +26,20 @@ compatible = "zephyr,sensing"; status = "okay"; - base_accel: base-accel { + base_accel_gyro: base-accel-gyro { compatible = "zephyr,sensing-phy-3d-sensor"; status = "okay"; - sensor-type = <0x73>; - friendly-name = "Base Accelerometer Sensor"; + sensor-types = ; + friendly-name = "Base Accel Gyro Sensor"; minimal-interval = <625>; underlying-device = <&bmi160_i2c>; }; - lid_accel: lid-accel { + lid_accel_gyro: lid-accel-gyro { compatible = "zephyr,sensing-phy-3d-sensor"; status = "okay"; - sensor-type = <0x73>; - friendly-name = "Lid Accelerometer Sensor"; + sensor-types = ; + friendly-name = "Lid Accel Gyro Sensor"; minimal-interval = <625>; underlying-device = <&bmi160_spi>; }; @@ -45,9 +47,10 @@ hinge_angle: hinge-angle { compatible = "zephyr,sensing-hinge-angle"; status = "okay"; - sensor-type = <0x20B>; + sensor-types = ; friendly-name = "Hinge Angle Sensor"; - reporters = <&base_accel &lid_accel>; + reporters = <&base_accel_gyro &lid_accel_gyro>; + reporters-index = <0 0>; minimal-interval = <100000>; stream-mode; }; diff --git a/samples/subsys/sensing/simple/src/main.c b/samples/subsys/sensing/simple/src/main.c index 277517bd307..b57c65c718c 100644 --- a/samples/subsys/sensing/simple/src/main.c +++ b/samples/subsys/sensing/simple/src/main.c @@ -43,20 +43,17 @@ int main(void) const struct sensing_callback_list base_acc_cb_list = { .on_data_event = &acc_data_event_callback, }; - const struct sensing_callback_list lid_acc_cb_list = { - .on_data_event = &acc_data_event_callback, - }; const struct sensing_callback_list hinge_angle_cb_list = { .on_data_event = &hinge_angle_data_event_callback, }; const struct sensing_sensor_info *info; sensing_sensor_handle_t base_acc; - sensing_sensor_handle_t lid_acc; sensing_sensor_handle_t hinge_angle; struct sensing_sensor_config base_acc_config; - struct sensing_sensor_config lid_acc_config; struct sensing_sensor_config hinge_angle_config; - const struct sensing_sensor_info *tmp_sensor_info; + const struct sensing_sensor_info *tmp_sensor_info = NULL; + const struct sensing_sensor_info *accle_info = NULL; + const struct sensing_sensor_info *hinge_info = NULL; int ret, i, num = 0; ret = sensing_get_sensors(&num, &info); @@ -71,25 +68,27 @@ int main(void) info[i].name, info[i].friendly_name, info[i].type); + switch (info[i].type) { + case SENSING_SENSOR_TYPE_MOTION_ACCELEROMETER_3D: + accle_info = &info[i]; + break; + case SENSING_SENSOR_TYPE_MOTION_HINGE_ANGLE: + hinge_info = &info[i]; + break; + default: + break; + } } LOG_INF("sensing subsystem run successfully"); - ret = sensing_open_sensor(&info[0], &base_acc_cb_list, &base_acc); + ret = sensing_open_sensor(accle_info, &base_acc_cb_list, &base_acc); if (ret) { LOG_ERR("sensing_open_sensor, type:0x%x index:0 error:%d", SENSING_SENSOR_TYPE_MOTION_ACCELEROMETER_3D, ret); } - ret = sensing_open_sensor_by_dt(DEVICE_DT_GET(DT_NODELABEL(lid_accel)), - &lid_acc_cb_list, - &lid_acc); - if (ret) { - LOG_ERR("sensing_open_sensor_by_dt, type:0x%x index:1 error:%d", - SENSING_SENSOR_TYPE_MOTION_ACCELEROMETER_3D, ret); - } - ret = sensing_open_sensor_by_dt(DEVICE_DT_GET(DT_NODELABEL(hinge_angle)), - &hinge_angle_cb_list, + ret = sensing_open_sensor(hinge_info, &hinge_angle_cb_list, &hinge_angle); if (ret) { LOG_ERR("sensing_open_sensor_by_type, type:0x%x index:0 error:%d", @@ -104,13 +103,6 @@ int main(void) LOG_ERR("base_acc sensing_set_interval error:%d\n", ret); } - lid_acc_config.attri = SENSING_SENSOR_ATTRIBUTE_INTERVAL; - lid_acc_config.interval = 100 * USEC_PER_MSEC; - ret = sensing_set_config(lid_acc, &lid_acc_config, 1); - if (ret) { - LOG_ERR("lid_acc sensing_set_interval error:%d\n", ret); - } - tmp_sensor_info = sensing_get_sensor_info(hinge_angle); hinge_angle_config.attri = SENSING_SENSOR_ATTRIBUTE_INTERVAL; hinge_angle_config.interval = tmp_sensor_info->minimal_interval; @@ -120,7 +112,6 @@ int main(void) } memset(&base_acc_config, 0x00, sizeof(struct sensing_sensor_config)); - memset(&lid_acc_config, 0x00, sizeof(struct sensing_sensor_config)); memset(&hinge_angle_config, 0x00, sizeof(struct sensing_sensor_config)); /* get base acc, lid acc, hinge sensor interval */ @@ -130,12 +121,6 @@ int main(void) LOG_ERR("base_acc sensing_get_interval error:%d\n", ret); } - lid_acc_config.attri = SENSING_SENSOR_ATTRIBUTE_INTERVAL; - ret = sensing_get_config(lid_acc, &lid_acc_config, 1); - if (ret) { - LOG_ERR("lid_acc sensing_get_interval error:%d\n", ret); - } - hinge_angle_config.attri = SENSING_SENSOR_ATTRIBUTE_INTERVAL; ret = sensing_get_config(hinge_angle, &hinge_angle_config, 1); if (ret) { @@ -151,14 +136,6 @@ int main(void) LOG_ERR("base_acc sensing_set_sensitivity error:%d\n", ret); } - lid_acc_config.attri = SENSING_SENSOR_ATTRIBUTE_SENSITIVITY; - lid_acc_config.data_field = SENSING_SENSITIVITY_INDEX_ALL; - lid_acc_config.sensitivity = 0; - ret = sensing_set_config(lid_acc, &lid_acc_config, 1); - if (ret) { - LOG_ERR("lid_acc sensing_set_sensitivity error:%d\n", ret); - } - hinge_angle_config.attri = SENSING_SENSOR_ATTRIBUTE_SENSITIVITY; hinge_angle_config.data_field = SENSING_SENSITIVITY_INDEX_ALL; hinge_angle_config.sensitivity = 1; @@ -168,7 +145,6 @@ int main(void) } memset(&base_acc_config, 0x00, sizeof(struct sensing_sensor_config)); - memset(&lid_acc_config, 0x00, sizeof(struct sensing_sensor_config)); memset(&hinge_angle_config, 0x00, sizeof(struct sensing_sensor_config)); /* get base acc, lid acc, hinge sensor sensitivity */ @@ -179,13 +155,6 @@ int main(void) LOG_ERR("base_acc sensing_get_sensitivity error:%d\n", ret); } - lid_acc_config.attri = SENSING_SENSOR_ATTRIBUTE_SENSITIVITY; - lid_acc_config.data_field = SENSING_SENSITIVITY_INDEX_ALL; - ret = sensing_get_config(lid_acc, &lid_acc_config, 1); - if (ret) { - LOG_ERR("lid_acc sensing_get_sensitivity error:%d\n", ret); - } - hinge_angle_config.attri = SENSING_SENSOR_ATTRIBUTE_SENSITIVITY; hinge_angle_config.data_field = SENSING_SENSITIVITY_INDEX_ALL; ret = sensing_get_config(hinge_angle, &hinge_angle_config, 1); @@ -193,10 +162,5 @@ int main(void) LOG_ERR("hinge_angle sensing_get_sensitivity error:%d\n", ret); } - ret = sensing_close_sensor(&lid_acc); - if (ret) { - LOG_ERR("sensing_close_sensor:%p error:%d", lid_acc, ret); - } - return 0; } diff --git a/subsys/sensing/sensor/hinge_angle/hinge_angle.c b/subsys/sensing/sensor/hinge_angle/hinge_angle.c index 9df92f5927b..9d9dc70cef7 100644 --- a/subsys/sensing/sensor/hinge_angle/hinge_angle.c +++ b/subsys/sensing/sensor/hinge_angle/hinge_angle.c @@ -157,7 +157,7 @@ static void hinge_reporter_on_data_event(sensing_sensor_handle_t handle, .on_data_event = hinge_reporter_on_data_event, \ .context = &_CONCAT(hinge_ctx, _inst), \ }; \ - SENSING_SENSOR_DT_INST_DEFINE(_inst, &hinge_reg, \ + SENSING_SENSORS_DT_INST_DEFINE(_inst, &hinge_reg, \ &_CONCAT(hinge_cb, _inst), \ &hinge_init, NULL, \ &_CONCAT(hinge_ctx, _inst), NULL, \ diff --git a/subsys/sensing/sensor/phy_3d_sensor/phy_3d_sensor.c b/subsys/sensing/sensor/phy_3d_sensor/phy_3d_sensor.c index d721836f91b..1a725a5bc01 100644 --- a/subsys/sensing/sensor/phy_3d_sensor/phy_3d_sensor.c +++ b/subsys/sensing/sensor/phy_3d_sensor/phy_3d_sensor.c @@ -4,6 +4,7 @@ * SPDX-License-Identifier: Apache-2.0 */ +#include "zephyr/devicetree.h" #define DT_DRV_COMPAT zephyr_sensing_phy_3d_sensor #include @@ -250,9 +251,9 @@ static const struct sensing_sensor_register_info phy_3d_sensor_reg = { .hw_dev = DEVICE_DT_GET( \ DT_PHANDLE(DT_DRV_INST(_inst), \ underlying_device)), \ - .sensor_type = DT_PROP(DT_DRV_INST(_inst), sensor_type),\ + .sensor_type = DT_PROP_BY_IDX(DT_DRV_INST(_inst), sensor_types, 0),\ }; \ - SENSING_SENSOR_DT_INST_DEFINE(_inst, &phy_3d_sensor_reg, NULL, \ + SENSING_SENSORS_DT_INST_DEFINE(_inst, &phy_3d_sensor_reg, NULL, \ &phy_3d_sensor_init, NULL, \ &_CONCAT(data, _inst), &_CONCAT(cfg, _inst), \ POST_KERNEL, CONFIG_SENSOR_INIT_PRIORITY, \ From 92bd7b51233be2cabae797c00c9ce678c44e5576 Mon Sep 17 00:00:00 2001 From: Tom Burdick Date: Thu, 30 Nov 2023 16:33:11 -0600 Subject: [PATCH 2748/3723] sensing: Simplify and correct some docstrings Some doc comments were making doxygen unhappy and the doc build fail. The description of the sensor connection was also updated slightly to simplify the description a bit. Signed-off-by: Tom Burdick --- include/zephyr/sensing/sensing_sensor.h | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/include/zephyr/sensing/sensing_sensor.h b/include/zephyr/sensing/sensing_sensor.h index f1515c02574..a4e87d8ed9e 100644 --- a/include/zephyr/sensing/sensing_sensor.h +++ b/include/zephyr/sensing/sensing_sensor.h @@ -66,8 +66,7 @@ enum { }; /** - * @struct sensing_connection information - * @brief sensing_connection indicates connection from reporter(source) to client(sink) + * @brief Connection between a source and sink of sensor data */ struct sensing_connection { sys_snode_t snode; @@ -85,7 +84,6 @@ struct sensing_connection { }; /** - * @struct sensing_sensor * @brief Internal sensor instance data structure. * * Each sensor instance will have its unique data structure for storing all From fe4056a7e39c70c476072787389837775700f5cf Mon Sep 17 00:00:00 2001 From: Tom Burdick Date: Fri, 1 Dec 2023 12:01:51 -0600 Subject: [PATCH 2749/3723] sensing: Code formatting fixups Fixes a few small code formatting issues in sensor_mgmt.c adding brackets where needed for an if and droping a line continuation slash that failed one of the CI lints. Signed-off-by: Tom Burdick --- subsys/sensing/sensor_mgmt.c | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/subsys/sensing/sensor_mgmt.c b/subsys/sensing/sensor_mgmt.c index 403311934da..4270844ec00 100644 --- a/subsys/sensing/sensor_mgmt.c +++ b/subsys/sensing/sensor_mgmt.c @@ -329,8 +329,9 @@ int open_sensor(struct sensing_sensor *sensor, struct sensing_connection **conn) { struct sensing_connection *tmp_conn; - if (sensor->state != SENSING_SENSOR_STATE_READY) + if (sensor->state != SENSING_SENSOR_STATE_READY) { return -EINVAL; + } /* create connection from sensor to application(client = NULL) */ tmp_conn = malloc(sizeof(*tmp_conn)); @@ -497,5 +498,5 @@ int sensing_get_sensors(int *sensor_nums, const struct sensing_sensor_info **inf K_THREAD_DEFINE(sensing_runtime, CONFIG_SENSING_RUNTIME_THREAD_STACK_SIZE, sensing_runtime_thread, &sensing_ctx, NULL, NULL, CONFIG_SENSING_RUNTIME_THREAD_PRIORITY, 0, 0); -DEVICE_DT_INST_DEFINE(0, sensing_init, NULL, &sensing_ctx, NULL, \ - POST_KERNEL, CONFIG_SENSOR_INIT_PRIORITY, NULL); +DEVICE_DT_INST_DEFINE(0, sensing_init, NULL, &sensing_ctx, NULL, POST_KERNEL, + CONFIG_SENSOR_INIT_PRIORITY, NULL); From e69ce68d409417b0519734056e10de528c9eeded Mon Sep 17 00:00:00 2001 From: Tom Burdick Date: Fri, 1 Dec 2023 13:40:25 -0600 Subject: [PATCH 2750/3723] sensing: Fix initializer compile-time constant Initializers must be compile time constants (not expressions!) for clang to be happy. Clang rightfully pointed out that the callback_list member of sensing_connection was being initialized using an expression that was not compile-time constant. The macros passed along a pointer created by taking the address of a global constant and then at initialization time attempting to dereference it using the * operator. So in the end the compiler has identifier its trying to first take the address of and then later dereference in an initializer. Clang didn't appreciate this, though gcc seemed to be just fine. Actually clang 17 might work just fine with this as well, but clang 16 (the clang I tried) didn't like it at all. Instead store the pointer to the callback list rather than copying the struct. This could be done the other way and not passing a pointer through the macros perhaps. Signed-off-by: Tom Burdick --- include/zephyr/sensing/sensing.h | 10 ++++++---- include/zephyr/sensing/sensing_sensor.h | 4 ++-- samples/subsys/sensing/simple/src/main.c | 14 ++++++++------ subsys/sensing/dispatch.c | 6 +++--- subsys/sensing/sensing.c | 4 ++-- subsys/sensing/sensor/hinge_angle/hinge_angle.c | 2 +- subsys/sensing/sensor_mgmt.c | 4 ++-- subsys/sensing/sensor_mgmt.h | 2 +- 8 files changed, 25 insertions(+), 21 deletions(-) diff --git a/include/zephyr/sensing/sensing.h b/include/zephyr/sensing/sensing.h index 62e48873f56..4491874fc84 100644 --- a/include/zephyr/sensing/sensing.h +++ b/include/zephyr/sensing/sensing.h @@ -196,7 +196,8 @@ int sensing_get_sensors(int *num_sensors, const struct sensing_sensor_info **inf * * @param info The sensor info got from \ref sensing_get_sensors * - * @param cb_list callback list to be registered to sensing. + * @param cb_list callback list to be registered to sensing, must have a static + * lifetime. * * @param handle The opened instance handle, if failed will be set to NULL. * @@ -204,7 +205,7 @@ int sensing_get_sensors(int *num_sensors, const struct sensing_sensor_info **inf */ int sensing_open_sensor( const struct sensing_sensor_info *info, - const struct sensing_callback_list *cb_list, + struct sensing_callback_list *cb_list, sensing_sensor_handle_t *handle); /** @@ -217,14 +218,15 @@ int sensing_open_sensor( * * @param dev pointer device get from device tree. * - * @param cb_list callback list to be registered to sensing. + * @param cb_list callback list to be registered to sensing, must have a static + * lifetime. * * @param handle The opened instance handle, if failed will be set to NULL. * * @return 0 on success or negative error value on failure. */ int sensing_open_sensor_by_dt( - const struct device *dev, const struct sensing_callback_list *cb_list, + const struct device *dev, struct sensing_callback_list *cb_list, sensing_sensor_handle_t *handle); /** diff --git a/include/zephyr/sensing/sensing_sensor.h b/include/zephyr/sensing/sensing_sensor.h index a4e87d8ed9e..55f00a5c29d 100644 --- a/include/zephyr/sensing/sensing_sensor.h +++ b/include/zephyr/sensing/sensing_sensor.h @@ -80,7 +80,7 @@ struct sensing_connection { /* client(sink) next consume time */ uint64_t next_consume_time; /* post data to application */ - struct sensing_callback_list callback_list; + struct sensing_callback_list *callback_list; }; /** @@ -136,7 +136,7 @@ extern struct sensing_sensor SENSING_SENSOR_SOURCE_NAME(idx, node); \ #define SENSING_CONNECTION_INITIALIZER(source_name, cb_list_ptr) \ { \ - .callback_list = *cb_list_ptr, \ + .callback_list = cb_list_ptr, \ .source = &source_name, \ } diff --git a/samples/subsys/sensing/simple/src/main.c b/samples/subsys/sensing/simple/src/main.c index b57c65c718c..d0749d3b52c 100644 --- a/samples/subsys/sensing/simple/src/main.c +++ b/samples/subsys/sensing/simple/src/main.c @@ -38,14 +38,16 @@ static void hinge_angle_data_event_callback(sensing_sensor_handle_t handle, cons LOG_INF("handle:%p, Sensor:%s data:(v:%d)", handle, info->name, sample->readings[0].v); } +static struct sensing_callback_list base_acc_cb_list = { + .on_data_event = &acc_data_event_callback, +}; + +static struct sensing_callback_list hinge_angle_cb_list = { + .on_data_event = &hinge_angle_data_event_callback, +}; + int main(void) { - const struct sensing_callback_list base_acc_cb_list = { - .on_data_event = &acc_data_event_callback, - }; - const struct sensing_callback_list hinge_angle_cb_list = { - .on_data_event = &hinge_angle_data_event_callback, - }; const struct sensing_sensor_info *info; sensing_sensor_handle_t base_acc; sensing_sensor_handle_t hinge_angle; diff --git a/subsys/sensing/dispatch.c b/subsys/sensing/dispatch.c index 5a85bd1d218..34cd45cf3c8 100644 --- a/subsys/sensing/dispatch.c +++ b/subsys/sensing/dispatch.c @@ -59,13 +59,13 @@ static int send_data_to_clients(struct sensing_sensor *sensor, update_client_consume_time(sensor, conn); - if (!conn->callback_list.on_data_event) { + if (!conn->callback_list->on_data_event) { LOG_WRN("sensor:%s event callback not registered", conn->source->dev->name); continue; } - conn->callback_list.on_data_event(conn, data, - conn->callback_list.context); + conn->callback_list->on_data_event(conn, data, + conn->callback_list->context); } return 0; diff --git a/subsys/sensing/sensing.c b/subsys/sensing/sensing.c index 9b5469b5c7e..1f3f05f6ab1 100644 --- a/subsys/sensing/sensing.c +++ b/subsys/sensing/sensing.c @@ -14,7 +14,7 @@ LOG_MODULE_DECLARE(sensing, CONFIG_SENSING_LOG_LEVEL); /* sensing_open_sensor is normally called by applications: hid, chre, zephyr main, etc */ int sensing_open_sensor(const struct sensing_sensor_info *sensor_info, - const struct sensing_callback_list *cb_list, + struct sensing_callback_list *cb_list, sensing_sensor_handle_t *handle) { int ret = 0; @@ -37,7 +37,7 @@ int sensing_open_sensor(const struct sensing_sensor_info *sensor_info, } int sensing_open_sensor_by_dt(const struct device *dev, - const struct sensing_callback_list *cb_list, + struct sensing_callback_list *cb_list, sensing_sensor_handle_t *handle) { int ret = 0; diff --git a/subsys/sensing/sensor/hinge_angle/hinge_angle.c b/subsys/sensing/sensor/hinge_angle/hinge_angle.c index 9d9dc70cef7..077f7ca3774 100644 --- a/subsys/sensing/sensor/hinge_angle/hinge_angle.c +++ b/subsys/sensing/sensor/hinge_angle/hinge_angle.c @@ -153,7 +153,7 @@ static void hinge_reporter_on_data_event(sensing_sensor_handle_t handle, #define DT_DRV_COMPAT zephyr_sensing_hinge_angle #define SENSING_HINGE_ANGLE_DT_DEFINE(_inst) \ static struct hinge_angle_context _CONCAT(hinge_ctx, _inst); \ - static const struct sensing_callback_list _CONCAT(hinge_cb, _inst) = { \ + static struct sensing_callback_list _CONCAT(hinge_cb, _inst) = { \ .on_data_event = hinge_reporter_on_data_event, \ .context = &_CONCAT(hinge_ctx, _inst), \ }; \ diff --git a/subsys/sensing/sensor_mgmt.c b/subsys/sensing/sensor_mgmt.c index 4270844ec00..08c5ea0462d 100644 --- a/subsys/sensing/sensor_mgmt.c +++ b/subsys/sensing/sensor_mgmt.c @@ -370,7 +370,7 @@ int close_sensor(struct sensing_connection **conn) } int sensing_register_callback(struct sensing_connection *conn, - const struct sensing_callback_list *cb_list) + struct sensing_callback_list *cb_list) { if (conn == NULL) { LOG_ERR("register sensing callback list, connection not be NULL"); @@ -383,7 +383,7 @@ int sensing_register_callback(struct sensing_connection *conn, LOG_ERR("callback should not be NULL"); return -ENODEV; } - conn->callback_list = *cb_list; + conn->callback_list = cb_list; return 0; } diff --git a/subsys/sensing/sensor_mgmt.h b/subsys/sensing/sensor_mgmt.h index 7988958af29..b29bd184b23 100644 --- a/subsys/sensing/sensor_mgmt.h +++ b/subsys/sensing/sensor_mgmt.h @@ -52,7 +52,7 @@ struct sensing_context { int open_sensor(struct sensing_sensor *sensor, struct sensing_connection **conn); int close_sensor(struct sensing_connection **conn); int sensing_register_callback(struct sensing_connection *conn, - const struct sensing_callback_list *cb_list); + struct sensing_callback_list *cb_list); int set_interval(struct sensing_connection *conn, uint32_t interval); int get_interval(struct sensing_connection *con, uint32_t *sensitivity); int set_sensitivity(struct sensing_connection *conn, int8_t index, uint32_t interval); From da5118001e291f890b67280a48ae233a0141864a Mon Sep 17 00:00:00 2001 From: Zhang Lixu Date: Mon, 4 Dec 2023 11:51:09 +0800 Subject: [PATCH 2751/3723] sensing: using the single sensing_connections for the same device The sensing_connections can be shared between sensing_sensors under the same device. Signed-off-by: Zhang Lixu --- include/zephyr/sensing/sensing_sensor.h | 28 ++++++++++++------------- 1 file changed, 14 insertions(+), 14 deletions(-) diff --git a/include/zephyr/sensing/sensing_sensor.h b/include/zephyr/sensing/sensing_sensor.h index 55f00a5c29d..fb7eb1e2c94 100644 --- a/include/zephyr/sensing/sensing_sensor.h +++ b/include/zephyr/sensing/sensing_sensor.h @@ -124,8 +124,8 @@ struct sensing_sensor { .minimal_interval = DT_PROP(node, minimal_interval),\ }; -#define SENSING_CONNECTIONS_NAME(node, idx) \ - _CONCAT(_CONCAT(__sensing_connections_, idx), DEVICE_DT_NAME_GET(node)) +#define SENSING_CONNECTIONS_NAME(node) \ + _CONCAT(__sensing_connections_, DEVICE_DT_NAME_GET(node)) #define SENSING_SENSOR_SOURCE_NAME(idx, node) \ SENSING_SENSOR_NAME(DT_PHANDLE_BY_IDX(node, reporters, idx), \ @@ -144,11 +144,11 @@ extern struct sensing_sensor SENSING_SENSOR_SOURCE_NAME(idx, node); \ SENSING_CONNECTION_INITIALIZER(SENSING_SENSOR_SOURCE_NAME(idx, node), \ cb_list_ptr) -#define SENSING_CONNECTIONS_DEFINE(node, idx, num, cb_list_ptr) \ +#define SENSING_CONNECTIONS_DEFINE(node, num, cb_list_ptr) \ LISTIFY(num, SENSING_SENSOR_SOURCE_EXTERN, \ (), node) \ static struct sensing_connection \ - SENSING_CONNECTIONS_NAME(node, idx)[(num)] = { \ + SENSING_CONNECTIONS_NAME(node)[(num)] = { \ LISTIFY(num, SENSING_CONNECTION_DEFINE, \ (,), node, cb_list_ptr) \ }; @@ -166,8 +166,6 @@ extern struct sensing_sensor SENSING_SENSOR_SOURCE_NAME(idx, node); \ #define SENSING_SENSOR_DEFINE(node, prop, idx, reg_ptr, cb_list_ptr) \ SENSING_SENSOR_INFO_DEFINE(node, idx) \ - SENSING_CONNECTIONS_DEFINE(node, idx, \ - DT_PROP_LEN_OR(node, reporters, 0), cb_list_ptr)\ SENSING_SENSOR_IODEV_DEFINE(node, idx) \ STRUCT_SECTION_ITERABLE(sensing_sensor, \ SENSING_SENSOR_NAME(node, idx)) = { \ @@ -175,7 +173,7 @@ extern struct sensing_sensor SENSING_SENSOR_SOURCE_NAME(idx, node); \ .info = &SENSING_SENSOR_INFO_NAME(node, idx), \ .register_info = reg_ptr, \ .reporter_num = DT_PROP_LEN_OR(node, reporters, 0), \ - .conns = SENSING_CONNECTIONS_NAME(node, idx), \ + .conns = SENSING_CONNECTIONS_NAME(node), \ .iodev = &SENSING_SENSOR_IODEV_NAME(node, idx), \ }; @@ -189,7 +187,7 @@ extern struct sensing_sensor SENSING_SENSOR_SOURCE_NAME(idx, node); \ * element in the sensing sensor iterable section used to enumerate all sensing * sensors. * - * @param node_id The devicetree node identifier. + * @param node The devicetree node identifier. * * @param reg_ptr Pointer to the device's sensing_sensor_register_info. * @@ -211,15 +209,17 @@ extern struct sensing_sensor SENSING_SENSOR_SOURCE_NAME(idx, node); \ * @param api_ptr Provides an initial pointer to the API function struct used * by the driver. Can be NULL. */ -#define SENSING_SENSORS_DT_DEFINE(node_id, reg_ptr, cb_list_ptr, \ +#define SENSING_SENSORS_DT_DEFINE(node, reg_ptr, cb_list_ptr, \ init_fn, pm_device, \ data_ptr, cfg_ptr, level, prio, \ api_ptr, ...) \ - SENSOR_DEVICE_DT_DEFINE(node_id, init_fn, pm_device, \ - data_ptr, cfg_ptr, level, prio, \ - api_ptr, __VA_ARGS__); \ - \ - SENSING_SENSORS_DEFINE(node_id, reg_ptr, cb_list_ptr); + SENSOR_DEVICE_DT_DEFINE(node, init_fn, pm_device, \ + data_ptr, cfg_ptr, level, prio, \ + api_ptr, __VA_ARGS__); \ + SENSING_CONNECTIONS_DEFINE(node, \ + DT_PROP_LEN_OR(node, reporters, 0), \ + cb_list_ptr); \ + SENSING_SENSORS_DEFINE(node, reg_ptr, cb_list_ptr); /** * @brief Like SENSING_SENSORS_DT_DEFINE() for an instance of a DT_DRV_COMPAT From 5058355c1b405a81cfeb9a83f0b132aed8479149 Mon Sep 17 00:00:00 2001 From: Zhang Lixu Date: Mon, 11 Dec 2023 16:56:10 +0800 Subject: [PATCH 2752/3723] sensing: add rtio implement for sensing subsys 1. add function sensing_iodev_submit and defined struct sensing_submit_config 2. fix the issue of phy_3d_sensor Signed-off-by: Zhang Lixu --- include/zephyr/sensing/sensing_sensor.h | 23 +++- subsys/sensing/sensing_sensor.c | 17 +++ .../sensor/phy_3d_sensor/phy_3d_sensor.c | 101 ++++++++---------- .../sensor/phy_3d_sensor/phy_3d_sensor.h | 6 +- subsys/sensing/sensor_mgmt.c | 35 ++++-- subsys/sensing/sensor_mgmt.h | 11 -- 6 files changed, 110 insertions(+), 83 deletions(-) diff --git a/include/zephyr/sensing/sensing_sensor.h b/include/zephyr/sensing/sensing_sensor.h index fb7eb1e2c94..65271d08704 100644 --- a/include/zephyr/sensing/sensing_sensor.h +++ b/include/zephyr/sensing/sensing_sensor.h @@ -153,13 +153,28 @@ extern struct sensing_sensor SENSING_SENSOR_SOURCE_NAME(idx, node); \ (,), node, cb_list_ptr) \ }; -#define SENSING_SENSOR_IODEV_NAME(node, idx) \ +struct sensing_submit_config { + enum sensor_channel chan; + const int info_index; + const bool is_streaming; +}; + +extern const struct rtio_iodev_api __sensing_iodev_api; + +#define SENSING_SUBMIT_CFG_NAME(node, idx) \ + _CONCAT(_CONCAT(__sensing_submit_cfg_, idx), DEVICE_DT_NAME_GET(node)) + +#define SENSING_SENSOR_IODEV_NAME(node, idx) \ _CONCAT(_CONCAT(__sensing_iodev_, idx), DEVICE_DT_NAME_GET(node)) #define SENSING_SENSOR_IODEV_DEFINE(node, idx) \ - COND_CODE_1(DT_PROP(node, stream_mode), \ - (SENSOR_DT_STREAM_IODEV(SENSING_SENSOR_IODEV_NAME(node, idx), node)), \ - (SENSOR_DT_READ_IODEV(SENSING_SENSOR_IODEV_NAME(node, idx), node))); + static struct sensing_submit_config SENSING_SUBMIT_CFG_NAME(node, idx) = { \ + .is_streaming = DT_PROP(node, stream_mode), \ + .info_index = idx, \ + }; \ + RTIO_IODEV_DEFINE(SENSING_SENSOR_IODEV_NAME(node, idx), \ + &__sensing_iodev_api, \ + &SENSING_SUBMIT_CFG_NAME(node, idx)); #define SENSING_SENSOR_NAME(node, idx) \ _CONCAT(_CONCAT(__sensing_sensor_, idx), DEVICE_DT_NAME_GET(node)) diff --git a/subsys/sensing/sensing_sensor.c b/subsys/sensing/sensing_sensor.c index da921c538af..a2ebd9ff7d3 100644 --- a/subsys/sensing/sensing_sensor.c +++ b/subsys/sensing/sensing_sensor.c @@ -13,6 +13,23 @@ LOG_MODULE_DECLARE(sensing, CONFIG_SENSING_LOG_LEVEL); +static void sensing_iodev_submit(struct rtio_iodev_sqe *iodev_sqe) +{ + struct sensing_sensor *sensor = (struct sensing_sensor *)iodev_sqe->sqe.userdata; + const struct device *dev = sensor->dev; + const struct sensor_driver_api *api = dev->api; + + if (api->submit != NULL) { + api->submit(dev, iodev_sqe); + } else { + rtio_iodev_sqe_err(iodev_sqe, -ENOTSUP); + } +} + +const struct rtio_iodev_api __sensing_iodev_api = { + .submit = sensing_iodev_submit, +}; + int sensing_sensor_get_reporters(const struct device *dev, int type, sensing_sensor_handle_t *reporter_handles, int max_handles) diff --git a/subsys/sensing/sensor/phy_3d_sensor/phy_3d_sensor.c b/subsys/sensing/sensor/phy_3d_sensor/phy_3d_sensor.c index 1a725a5bc01..3ad2e499fff 100644 --- a/subsys/sensing/sensor/phy_3d_sensor/phy_3d_sensor.c +++ b/subsys/sensing/sensor/phy_3d_sensor/phy_3d_sensor.c @@ -102,18 +102,21 @@ static int phy_3d_sensor_init(const struct device *dev) { const struct phy_3d_sensor_config *cfg = dev->config; struct phy_3d_sensor_data *data = dev->data; + int i; - switch (cfg->sensor_type) { - case SENSING_SENSOR_TYPE_MOTION_ACCELEROMETER_3D: - data->custom = &custom_accel; + for (i = 0; i < cfg->sensor_num; i++) { + switch (cfg->sensor_types[i]) { + case SENSING_SENSOR_TYPE_MOTION_ACCELEROMETER_3D: + data->customs[i] = &custom_accel; break; - case SENSING_SENSOR_TYPE_MOTION_GYROMETER_3D: - data->custom = &custom_gyro; + case SENSING_SENSOR_TYPE_MOTION_GYROMETER_3D: + data->customs[i] = &custom_gyro; break; - default: - LOG_ERR("phy_3d_sensor doesn't support sensor type %d", - cfg->sensor_type); - return -ENOTSUP; + default: + LOG_ERR("phy_3d_sensor doesn't support sensor type %d", + cfg->sensor_types[i]); + return -ENOTSUP; + } } LOG_INF("%s: Underlying device: %s", dev->name, cfg->hw_dev->name); @@ -126,38 +129,12 @@ static int phy_3d_sensor_attr_set_hyst(const struct device *dev, const struct sensor_value *val) { const struct phy_3d_sensor_config *cfg = dev->config; - struct phy_3d_sensor_data *data = dev->data; - int index = chan - SENSOR_CHAN_PRIV_START; - int i, min = 0; - - if (index >= 0 && index < ARRAY_SIZE(data->sensitivities)) { - data->sensitivities[index] = *val; - } else if (index == SENSING_SENSITIVITY_INDEX_ALL) { - for (i = 0; i < ARRAY_SIZE(data->sensitivities); ++i) { - data->sensitivities[i] = *val; - } - min = ARRAY_SIZE(data->sensitivities) - 1; - } else { - LOG_ERR("%s: set sensitivity: invalid index: %d", - dev->name, index); - return -EINVAL; - } - for (i = min + 1; i < ARRAY_SIZE(data->sensitivities); ++i) { - if ((data->sensitivities[i].val1 < - data->sensitivities[min].val1) || - (data->sensitivities[i].val1 == - data->sensitivities[min].val1 && - data->sensitivities[i].val2 < - data->sensitivities[min].val2)) { - min = i; - } + if (chan == SENSOR_CHAN_ACCEL_XYZ || chan == SENSOR_CHAN_GYRO_XYZ) { + return sensor_attr_set(cfg->hw_dev, chan, SENSOR_ATTR_SLOPE_TH, val); + } else { + return sensor_attr_set(cfg->hw_dev, chan, SENSOR_ATTR_HYSTERESIS, val); } - - chan = data->custom->chan_all; - - return sensor_attr_set(cfg->hw_dev, chan, SENSOR_ATTR_SLOPE_TH, - &data->sensitivities[min]); } static int phy_3d_sensor_attr_set(const struct device *dev, @@ -166,7 +143,6 @@ static int phy_3d_sensor_attr_set(const struct device *dev, const struct sensor_value *val) { const struct phy_3d_sensor_config *cfg = dev->config; - struct phy_3d_sensor_data *data = dev->data; int ret = 0; switch (attr) { @@ -175,7 +151,6 @@ static int phy_3d_sensor_attr_set(const struct device *dev, break; default: - chan = data->custom->chan_all; ret = sensor_attr_set(cfg->hw_dev, chan, attr, val); break; } @@ -187,8 +162,10 @@ static int phy_3d_sensor_attr_set(const struct device *dev, static int phy_3d_sensor_submit(const struct device *dev, struct rtio_iodev_sqe *sqe) { + struct sensing_submit_config *config = (struct sensing_submit_config *)sqe->sqe.iodev->data; const struct phy_3d_sensor_config *cfg = dev->config; struct phy_3d_sensor_data *data = dev->data; + const struct phy_3d_sensor_custom *custom = data->customs[config->info_index]; struct sensing_sensor_value_3d_q31 *sample; struct sensor_value value[PHY_3D_SENSOR_CHANNEL_NUM]; uint32_t buffer_len; @@ -201,14 +178,14 @@ static int phy_3d_sensor_submit(const struct device *dev, return ret; } - ret = sensor_sample_fetch_chan(cfg->hw_dev, data->custom->chan_all); + ret = sensor_sample_fetch_chan(cfg->hw_dev, custom->chan_all); if (ret) { LOG_ERR("%s: sample fetch failed: %d", dev->name, ret); rtio_iodev_sqe_err(sqe, ret); return ret; } - ret = sensor_channel_get(cfg->hw_dev, data->custom->chan_all, value); + ret = sensor_channel_get(cfg->hw_dev, custom->chan_all, value); if (ret) { LOG_ERR("%s: channel get failed: %d", dev->name, ret); rtio_iodev_sqe_err(sqe, ret); @@ -216,12 +193,11 @@ static int phy_3d_sensor_submit(const struct device *dev, } for (i = 0; i < ARRAY_SIZE(value); ++i) { - sample->readings[0].v[i] = - data->custom->sensor_value_to_q31(&value[i]); + sample->readings[0].v[i] = custom->sensor_value_to_q31(&value[i]); } sample->header.reading_count = 1; - sample->shift = data->custom->shift; + sample->shift = custom->shift; LOG_DBG("%s: Sample data:\t x: %d, y: %d, z: %d", dev->name, @@ -238,6 +214,7 @@ static const struct sensor_driver_api phy_3d_sensor_api = { .submit = phy_3d_sensor_submit, }; +/* To be removed */ static const struct sensing_sensor_register_info phy_3d_sensor_reg = { .flags = SENSING_SENSOR_FLAG_REPORT_ON_CHANGE, .sample_size = sizeof(struct sensing_sensor_value_3d_q31), @@ -245,18 +222,26 @@ static const struct sensing_sensor_register_info phy_3d_sensor_reg = { .version.value = SENSING_SENSOR_VERSION(0, 8, 0, 0), }; -#define SENSING_PHY_3D_SENSOR_DT_DEFINE(_inst) \ - static struct phy_3d_sensor_data _CONCAT(data, _inst); \ - static const struct phy_3d_sensor_config _CONCAT(cfg, _inst) = {\ - .hw_dev = DEVICE_DT_GET( \ - DT_PHANDLE(DT_DRV_INST(_inst), \ - underlying_device)), \ - .sensor_type = DT_PROP_BY_IDX(DT_DRV_INST(_inst), sensor_types, 0),\ - }; \ - SENSING_SENSORS_DT_INST_DEFINE(_inst, &phy_3d_sensor_reg, NULL, \ - &phy_3d_sensor_init, NULL, \ - &_CONCAT(data, _inst), &_CONCAT(cfg, _inst), \ - POST_KERNEL, CONFIG_SENSOR_INIT_PRIORITY, \ +#define SENSING_PHY_3D_SENSOR_DT_DEFINE(_inst) \ + static struct rtio_iodev_sqe _CONCAT(sqes, _inst)[DT_INST_PROP_LEN(_inst, \ + sensor_types)]; \ + static const struct phy_3d_sensor_custom *_CONCAT(customs, _inst) \ + [DT_INST_PROP_LEN(_inst, sensor_types)]; \ + static struct phy_3d_sensor_data _CONCAT(data, _inst) = { \ + .sqes = _CONCAT(sqes, _inst), \ + .customs = _CONCAT(customs, _inst), \ + }; \ + static const struct phy_3d_sensor_config _CONCAT(cfg, _inst) = { \ + .hw_dev = DEVICE_DT_GET( \ + DT_PHANDLE(DT_DRV_INST(_inst), \ + underlying_device)), \ + .sensor_num = DT_INST_PROP_LEN(_inst, sensor_types), \ + .sensor_types = DT_PROP(DT_DRV_INST(_inst), sensor_types), \ + }; \ + SENSING_SENSORS_DT_INST_DEFINE(_inst, &phy_3d_sensor_reg, NULL, \ + &phy_3d_sensor_init, NULL, \ + &_CONCAT(data, _inst), &_CONCAT(cfg, _inst), \ + POST_KERNEL, CONFIG_SENSOR_INIT_PRIORITY, \ &phy_3d_sensor_api); DT_INST_FOREACH_STATUS_OKAY(SENSING_PHY_3D_SENSOR_DT_DEFINE); diff --git a/subsys/sensing/sensor/phy_3d_sensor/phy_3d_sensor.h b/subsys/sensing/sensor/phy_3d_sensor/phy_3d_sensor.h index 071c40dfcfb..8711c9a5700 100644 --- a/subsys/sensing/sensor/phy_3d_sensor/phy_3d_sensor.h +++ b/subsys/sensing/sensor/phy_3d_sensor/phy_3d_sensor.h @@ -20,13 +20,15 @@ struct phy_3d_sensor_custom { }; struct phy_3d_sensor_data { - const struct phy_3d_sensor_custom *custom; struct sensor_value sensitivities[PHY_3D_SENSOR_CHANNEL_NUM]; + const struct phy_3d_sensor_custom **customs; + struct rtio_iodev_sqe *sqes; }; struct phy_3d_sensor_config { const struct device *hw_dev; - const int32_t sensor_type; + const int sensor_num; + const int32_t sensor_types[]; }; #endif diff --git a/subsys/sensing/sensor_mgmt.c b/subsys/sensing/sensor_mgmt.c index 08c5ea0462d..9f8a1ae2537 100644 --- a/subsys/sensing/sensor_mgmt.c +++ b/subsys/sensing/sensor_mgmt.c @@ -29,6 +29,20 @@ RTIO_DEFINE_WITH_MEMPOOL(sensing_rtio_ctx, CONFIG_SENSING_RTIO_SQE_NUM, CONFIG_SENSING_RTIO_BLOCK_COUNT, CONFIG_SENSING_RTIO_BLOCK_SIZE, 4); +static enum sensor_channel sensing_sensor_type_to_chan(const int32_t type) +{ + switch (type) { + case SENSING_SENSOR_TYPE_MOTION_ACCELEROMETER_3D: + return SENSOR_CHAN_ACCEL_XYZ; + case SENSING_SENSOR_TYPE_MOTION_GYROMETER_3D: + return SENSOR_CHAN_GYRO_XYZ; + default: + break; + } + + return SENSOR_CHAN_PRIV_START; +} + /* sensor_later_config including arbitrate/set interval/sensitivity */ static uint32_t arbitrate_interval(struct sensing_sensor *sensor) @@ -61,7 +75,7 @@ static uint32_t arbitrate_interval(struct sensing_sensor *sensor) static int set_arbitrate_interval(struct sensing_sensor *sensor, uint32_t interval) { - struct sensor_read_config *config = sensor->iodev->data; + struct sensing_submit_config *config = sensor->iodev->data; struct sensor_value odr = {0}; int ret; @@ -75,8 +89,7 @@ static int set_arbitrate_interval(struct sensing_sensor *sensor, uint32_t interv odr.val2 = (uint64_t)USEC_PER_SEC * 1000000 / interval % 1000000; } - /* The SENSOR_CHAN_MAX should be overridden by sensing sensor driver */ - ret = sensor_attr_set(sensor->dev, SENSOR_CHAN_MAX, + ret = sensor_attr_set(sensor->dev, config->chan, SENSOR_ATTR_SAMPLING_FREQUENCY, &odr); if (ret) { LOG_ERR("%s set attr freq failed:%d", sensor->dev->name, ret); @@ -143,16 +156,18 @@ static uint32_t arbitrate_sensitivity(struct sensing_sensor *sensor, int index) static int set_arbitrate_sensitivity(struct sensing_sensor *sensor, int index, uint32_t sensitivity) { + struct sensing_submit_config *config = (struct sensing_submit_config *)sensor->iodev->data; struct sensor_value threshold = {.val1 = sensitivity}; + int i; /* update sensor sensitivity */ sensor->sensitivity[index] = sensitivity; - /* The SENSOR_CHAN_PRIV_START should be overridden by sensing sensor - * driver, SENSOR_ATTR_HYSTERESIS can be overridden for different - * sensora type. - */ - return sensor_attr_set(sensor->dev, SENSOR_CHAN_PRIV_START + index, + for (i = 0; i < sensor->sensitivity_count; i++) { + threshold.val1 = MIN(sensor->sensitivity[i], threshold.val1); + } + + return sensor_attr_set(sensor->dev, config->chan, SENSOR_ATTR_HYSTERESIS, &threshold); } @@ -275,6 +290,7 @@ static void sensing_sensor_polling_timer(struct k_timer *timer_id) static int init_sensor(struct sensing_sensor *sensor) { + struct sensing_submit_config *config; struct sensing_connection *conn; int i; @@ -293,6 +309,9 @@ static int init_sensor(struct sensing_sensor *sensor) conn->source->dev->name, sensor->dev->name, i, conn); } + config = sensor->iodev->data; + config->chan = sensing_sensor_type_to_chan(sensor->info->type); + return 0; } diff --git a/subsys/sensing/sensor_mgmt.h b/subsys/sensing/sensor_mgmt.h index b29bd184b23..4672833e009 100644 --- a/subsys/sensing/sensor_mgmt.h +++ b/subsys/sensing/sensor_mgmt.h @@ -71,17 +71,6 @@ static inline struct sensing_sensor *get_sensor_by_dev(const struct device *dev) return NULL; } -static inline uint16_t get_reporter_sample_size(const struct sensing_sensor *sensor, int i) -{ - const struct sensing_sensor *reporter; - - __ASSERT(i < sensor->reporter_num, "dt index should less than reporter num"); - - reporter = sensor->conns[i].source; - - return reporter->register_info->sample_size; -} - static inline struct sensing_sensor *get_reporter_sensor(struct sensing_sensor *sensor, int index) { if (!sensor || index >= sensor->reporter_num) { From 033d87d53f8198d40bd39864de4a92313c91891b Mon Sep 17 00:00:00 2001 From: Laurentiu Mihalcea Date: Thu, 23 Nov 2023 15:01:55 +0200 Subject: [PATCH 2753/3723] soc: mimx9: Remove SAI and EDMA static mappings With the introduction of the SAI and EDMA drivers, there's no longer a need to map the MMIOs using the mmu_regions.c method since this is taken care of by the drivers via device_map(). As such, remove entries for EDMA and SAI from mmu_regions.c. Signed-off-by: Laurentiu Mihalcea --- soc/arm64/nxp_imx/mimx9/mmu_regions.c | 15 --------------- 1 file changed, 15 deletions(-) diff --git a/soc/arm64/nxp_imx/mimx9/mmu_regions.c b/soc/arm64/nxp_imx/mimx9/mmu_regions.c index 15ca8c39618..4305d8ff7e2 100644 --- a/soc/arm64/nxp_imx/mimx9/mmu_regions.c +++ b/soc/arm64/nxp_imx/mimx9/mmu_regions.c @@ -44,21 +44,6 @@ static const struct arm_mmu_region mmu_regions[] = { DT_REG_SIZE(DT_NODELABEL(mu2_a)), MT_DEVICE_nGnRnE | MT_P_RW_U_NA | MT_NS), - MMU_REGION_FLAT_ENTRY("SAI3", - DT_REG_ADDR(DT_NODELABEL(sai3)), - DT_REG_SIZE(DT_NODELABEL(sai3)), - MT_DEVICE_nGnRnE | MT_P_RW_U_NA | MT_NS), - - MMU_REGION_FLAT_ENTRY("EDMA2_CH0", - DT_REG_ADDR(DT_NODELABEL(edma2_ch0)), - DT_REG_SIZE(DT_NODELABEL(edma2_ch0)), - MT_DEVICE_nGnRnE | MT_P_RW_U_NA | MT_NS), - - MMU_REGION_FLAT_ENTRY("EDMA2_CH1", - DT_REG_ADDR(DT_NODELABEL(edma2_ch1)), - DT_REG_SIZE(DT_NODELABEL(edma2_ch1)), - MT_DEVICE_nGnRnE | MT_P_RW_U_NA | MT_NS), - MMU_REGION_FLAT_ENTRY("OUTBOX", DT_REG_ADDR(DT_NODELABEL(outbox)), DT_REG_SIZE(DT_NODELABEL(outbox)), From a4ed3994b736a0fcb328ce2f17b1456814ed8334 Mon Sep 17 00:00:00 2001 From: Alberto Escolar Piedras Date: Thu, 18 Jan 2024 16:37:01 +0100 Subject: [PATCH 2754/3723] hal_nordic: Take latest including UART driver fixes for simulation Point to the latest nordic hal module which includes UART driver fixes needed for simulation. Signed-off-by: Alberto Escolar Piedras --- west.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/west.yml b/west.yml index 20a611a65b7..ecc0d9943f2 100644 --- a/west.yml +++ b/west.yml @@ -183,7 +183,7 @@ manifest: groups: - hal - name: hal_nordic - revision: 64bd075a06f6a16d6ea9101cda82b41465a35211 + revision: a5f11c33864264c60a81bf83e5d5643260296eb5 path: modules/hal/nordic groups: - hal From 6447b1c4fdbd8699ee5611d582890ba70880f721 Mon Sep 17 00:00:00 2001 From: Alberto Escolar Piedras Date: Thu, 18 Jan 2024 11:02:39 +0100 Subject: [PATCH 2755/3723] drivers/serial/uart_nrfx_uarte2: Fix for simulation Just like for the old driver, for simulation, we cannot get the UART regiter address for the pinctrl config structure from DT, as that cannot match the one allocated at build time. So let's override it at runtime with the correct address which is stored in the UART config structure. Also, do improve the condition for the busy wait during the poll_out, for simulation, so we only busy wait if we will loop/the Tx was busy. Signed-off-by: Alberto Escolar Piedras --- drivers/serial/uart_nrfx_uarte2.c | 15 +++++++++++---- 1 file changed, 11 insertions(+), 4 deletions(-) diff --git a/drivers/serial/uart_nrfx_uarte2.c b/drivers/serial/uart_nrfx_uarte2.c index c27f33c7284..65bfeccdafd 100644 --- a/drivers/serial/uart_nrfx_uarte2.c +++ b/drivers/serial/uart_nrfx_uarte2.c @@ -562,11 +562,13 @@ static void api_poll_out(const struct device *dev, unsigned char out_char) err = nrfx_uarte_tx(nrfx_dev, &out_char, 1, NRFX_UARTE_TX_EARLY_RETURN); __ASSERT(err != NRFX_ERROR_INVALID_ADDR, "Invalid address of the buffer"); - if (err == NRFX_ERROR_BUSY && - IS_ENABLED(CONFIG_MULTITHREADING) && k_is_preempt_thread()) { - k_msleep(1); + if (err == NRFX_ERROR_BUSY) { + if (IS_ENABLED(CONFIG_MULTITHREADING) && k_is_preempt_thread()) { + k_msleep(1); + } else { + Z_SPIN_DELAY(3); + } } - Z_SPIN_DELAY(3); } while (err == NRFX_ERROR_BUSY); } @@ -789,6 +791,11 @@ static int uarte_nrfx_init(const struct device *dev) const struct uarte_nrfx_config *cfg = dev->config; struct uarte_nrfx_data *data = dev->data; +#ifdef CONFIG_ARCH_POSIX + /* For simulation the DT provided peripheral address needs to be corrected */ + ((struct pinctrl_dev_config *)cfg->pcfg)->reg = (uintptr_t)nrfx_dev->p_reg; +#endif + err = pinctrl_apply_state(cfg->pcfg, PINCTRL_STATE_DEFAULT); if (err < 0) { return err; From 98e9dd7398bc59dda834422b41b505c9d7375a13 Mon Sep 17 00:00:00 2001 From: Alberto Escolar Piedras Date: Thu, 18 Jan 2024 11:06:50 +0100 Subject: [PATCH 2756/3723] boards nrf52_bsim: Don't avoid new UART driver Let's not treat this driver differently for simulation than for real HW. There is a few cases which are not yet working, but the driver is disabled by default for all platforms. Signed-off-by: Alberto Escolar Piedras --- boards/posix/nrf_bsim/Kconfig.defconfig | 3 --- 1 file changed, 3 deletions(-) diff --git a/boards/posix/nrf_bsim/Kconfig.defconfig b/boards/posix/nrf_bsim/Kconfig.defconfig index 99ad7af5ac3..d4e48ada7ad 100644 --- a/boards/posix/nrf_bsim/Kconfig.defconfig +++ b/boards/posix/nrf_bsim/Kconfig.defconfig @@ -91,7 +91,4 @@ config POSIX_ARCH_CONSOLE endif # CONSOLE -config UART_NRFX_UARTE_LEGACY_SHIM - default y - endif # SOC_SERIES_BSIM_NRFXX From ac39ad724911d79557fd12b40b085ab639fca173 Mon Sep 17 00:00:00 2001 From: Vinayak Kariappa Chettimada Date: Fri, 19 Jan 2024 06:49:37 +0100 Subject: [PATCH 2757/3723] Bluetooth: Controller: Fix extended scanning assertion Fix extended scanning assertion after long duration. Signed-off-by: Vinayak Kariappa Chettimada --- subsys/bluetooth/controller/ll_sw/nordic/lll/lll_scan.c | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/subsys/bluetooth/controller/ll_sw/nordic/lll/lll_scan.c b/subsys/bluetooth/controller/ll_sw/nordic/lll/lll_scan.c index 0fa44d1447d..7279d407ad8 100644 --- a/subsys/bluetooth/controller/ll_sw/nordic/lll/lll_scan.c +++ b/subsys/bluetooth/controller/ll_sw/nordic/lll/lll_scan.c @@ -915,11 +915,11 @@ static void isr_window(void *param) } lll_chan_set(37 + lll->chan); +#if defined(CONFIG_BT_CENTRAL) || defined(CONFIG_BT_CTLR_ADV_EXT) #if defined(CONFIG_BT_CENTRAL) bool is_sched_advanced = IS_ENABLED(CONFIG_BT_CTLR_SCHED_ADVANCED) && lll->conn && lll->conn_win_offset_us; uint32_t ticks_anchor_prev; - uint32_t ticks_at_start; if (is_sched_advanced) { /* Get the ticks_anchor when the offset to free time space for @@ -932,14 +932,17 @@ static void isr_window(void *param) } else { ticks_anchor_prev = 0U; } +#endif /* CONFIG_BT_CENTRAL */ + + uint32_t ticks_at_start; ticks_at_start = ticker_ticks_now_get() + HAL_TICKER_CNTR_CMP_OFFSET_MIN; remainder_us = radio_tmr_start_tick(0, ticks_at_start); -#else /* !CONFIG_BT_CENTRAL */ +#else /* !CONFIG_BT_CENTRAL && !CONFIG_BT_CTLR_ADV_EXT */ remainder_us = radio_tmr_start_now(0); -#endif /* !CONFIG_BT_CENTRAL */ +#endif /* !CONFIG_BT_CENTRAL && !CONFIG_BT_CTLR_ADV_EXT */ /* capture end of Rx-ed PDU, for initiator to calculate first * central event. From d1e4c17e6dd43a623ba9396f1e427fb7959b3a44 Mon Sep 17 00:00:00 2001 From: Vinayak Kariappa Chettimada Date: Mon, 22 Jan 2024 11:55:49 +0100 Subject: [PATCH 2758/3723] tests: bsim: Bluetooth: Mesh: Adjust timeout for Adv Extensions use Adjust mesh test timing and timeout value for Advertising Extensions use/fix in Zephyr Controller. The scanning in Zephyr Controller is delayed when using extended scanning. Signed-off-by: Vinayak Kariappa Chettimada --- tests/bsim/bluetooth/mesh/src/test_beacon.c | 2 +- tests/bsim/bluetooth/mesh/src/test_provision.c | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/tests/bsim/bluetooth/mesh/src/test_beacon.c b/tests/bsim/bluetooth/mesh/src/test_beacon.c index e3a601e4134..04e89671a5f 100644 --- a/tests/bsim/bluetooth/mesh/src/test_beacon.c +++ b/tests/bsim/bluetooth/mesh/src/test_beacon.c @@ -1413,7 +1413,7 @@ static void test_tx_priv_interleave(void) ASSERT_TRUE(status == STATUS_SUCCESS); ASSERT_TRUE(phase == BT_MESH_KR_PHASE_2); - k_sleep(K_SECONDS(BEACON_INTERVAL + 5)); + k_sleep(K_SECONDS(BEACON_INTERVAL + 7)); toggle_priv_beacon(tx_cfg.addr, 1); PASS(); diff --git a/tests/bsim/bluetooth/mesh/src/test_provision.c b/tests/bsim/bluetooth/mesh/src/test_provision.c index 39e6e1b2bd3..40af4ad2bc4 100644 --- a/tests/bsim/bluetooth/mesh/src/test_provision.c +++ b/tests/bsim/bluetooth/mesh/src/test_provision.c @@ -1009,11 +1009,11 @@ static void test_provisioner_pb_remote_client_parallel(void) /* scanning device with dev index 3 */ uuid[6] = '0' + 3; uuid_to_provision_remote = uuid; - ASSERT_OK(bt_mesh_rpr_scan_start(&rpr_cli, &srv, uuid, 5, 1, &scan_status)); + ASSERT_OK(bt_mesh_rpr_scan_start(&rpr_cli, &srv, uuid, 15, 1, &scan_status)); ASSERT_EQUAL(BT_MESH_RPR_SUCCESS, scan_status.status); ASSERT_EQUAL(BT_MESH_RPR_SCAN_SINGLE, scan_status.scan); ASSERT_EQUAL(1, scan_status.max_devs); - ASSERT_EQUAL(5, scan_status.timeout); + ASSERT_EQUAL(15, scan_status.timeout); ASSERT_OK(k_sem_take(&scan_sem, K_SECONDS(20))); ASSERT_OK(k_sem_take(&prov_sem, K_SECONDS(20))); From ec3ec8cd2a60ad48f42dab43b47f1bba9326e26d Mon Sep 17 00:00:00 2001 From: Seppo Takalo Date: Fri, 19 Jan 2024 16:14:37 +0200 Subject: [PATCH 2759/3723] net: lwm2m: Add LWM2M_ON_INIT() macro Add macro that allows registration of initialization functions that are called when LwM2M engine starts. On LwM2M engine starts up, it first executes all initialization functions in following priority order: 1. LWM2M_PRIO_ENGINE 2. LWM2M_PRIO_CORE, this is where all LwM2M core objects are initialized 3. LWM2M_PRIO_OBJ, this is where all other objects are initialized 4. LwM2M_PRIO_APP, application initialization. Now on the initialization phase, we could rely that certain objects have already been registered. For example custom objects can register callbacks to core objects. On application phase, we can initialize sensor objects and register their callbacks because objects have already been initialized. This LWM2M_ON_INIT() should replace all use of SYS_INIT() with the default CONFIG_KERNEL_INIT_PRIORITY_DEFAULT. Priority order is actually just alphabetical order of names, so the order is set on a linkin phase, and we don't need any runtime checking for it. Signed-off-by: Seppo Takalo --- subsys/net/lib/lwm2m/CMakeLists.txt | 2 + subsys/net/lib/lwm2m/ipso_accelerometer.c | 2 +- subsys/net/lib/lwm2m/ipso_buzzer.c | 2 +- subsys/net/lib/lwm2m/ipso_current_sensor.c | 3 +- subsys/net/lib/lwm2m/ipso_filling_sensor.c | 4 +- subsys/net/lib/lwm2m/ipso_generic_sensor.c | 3 +- subsys/net/lib/lwm2m/ipso_humidity_sensor.c | 3 +- subsys/net/lib/lwm2m/ipso_light_control.c | 3 +- subsys/net/lib/lwm2m/ipso_onoff_switch.c | 2 +- subsys/net/lib/lwm2m/ipso_pressure_sensor.c | 3 +- subsys/net/lib/lwm2m/ipso_push_button.c | 2 +- subsys/net/lib/lwm2m/ipso_temp_sensor.c | 3 +- subsys/net/lib/lwm2m/ipso_timer.c | 2 +- subsys/net/lib/lwm2m/ipso_voltage_sensor.c | 3 +- subsys/net/lib/lwm2m/iterables.ld | 1 + subsys/net/lib/lwm2m/lwm2m_engine.c | 9 ++- subsys/net/lib/lwm2m/lwm2m_engine.h | 60 +++++++++++++++++++ .../net/lib/lwm2m/lwm2m_obj_access_control.c | 2 +- .../net/lib/lwm2m/lwm2m_obj_binaryappdata.c | 2 +- subsys/net/lib/lwm2m/lwm2m_obj_connmon.c | 2 +- subsys/net/lib/lwm2m/lwm2m_obj_device.c | 2 +- subsys/net/lib/lwm2m/lwm2m_obj_event_log.c | 2 +- subsys/net/lib/lwm2m/lwm2m_obj_firmware.c | 2 +- subsys/net/lib/lwm2m/lwm2m_obj_gateway.c | 4 +- subsys/net/lib/lwm2m/lwm2m_obj_location.c | 2 +- subsys/net/lib/lwm2m/lwm2m_obj_portfolio.c | 2 +- subsys/net/lib/lwm2m/lwm2m_obj_security.c | 2 +- subsys/net/lib/lwm2m/lwm2m_obj_server.c | 3 +- subsys/net/lib/lwm2m/lwm2m_obj_swmgmt.c | 2 +- subsys/net/lib/lwm2m/lwm2m_rd_client.c | 4 +- subsys/net/lib/lwm2m/lwm2m_registry.c | 7 ++- subsys/net/lib/lwm2m/lwm2m_registry.h | 1 - subsys/net/lib/lwm2m/ucifi_battery.c | 2 +- subsys/net/lib/lwm2m/ucifi_lpwan.c | 2 +- .../net/lib/lwm2m/lwm2m_engine/CMakeLists.txt | 1 + .../lwm2m/lwm2m_registry/src/lwm2m_registry.c | 1 - 36 files changed, 105 insertions(+), 47 deletions(-) create mode 100644 subsys/net/lib/lwm2m/iterables.ld diff --git a/subsys/net/lib/lwm2m/CMakeLists.txt b/subsys/net/lib/lwm2m/CMakeLists.txt index 2e895ec381b..7246ff70999 100644 --- a/subsys/net/lib/lwm2m/CMakeLists.txt +++ b/subsys/net/lib/lwm2m/CMakeLists.txt @@ -127,4 +127,6 @@ zephyr_library_sources_ifdef(CONFIG_LWM2M_SHELL lwm2m_shell.c ) +zephyr_linker_sources(SECTIONS iterables.ld) + zephyr_library_link_libraries_ifdef(CONFIG_MBEDTLS mbedTLS) diff --git a/subsys/net/lib/lwm2m/ipso_accelerometer.c b/subsys/net/lib/lwm2m/ipso_accelerometer.c index 2458bf75321..0c1be988408 100644 --- a/subsys/net/lib/lwm2m/ipso_accelerometer.c +++ b/subsys/net/lib/lwm2m/ipso_accelerometer.c @@ -157,4 +157,4 @@ static int ipso_accel_init(void) return 0; } -SYS_INIT(ipso_accel_init, APPLICATION, CONFIG_KERNEL_INIT_PRIORITY_DEFAULT); +LWM2M_OBJ_INIT(ipso_accel_init); diff --git a/subsys/net/lib/lwm2m/ipso_buzzer.c b/subsys/net/lib/lwm2m/ipso_buzzer.c index 4bd41735fa6..f679d7e4a60 100644 --- a/subsys/net/lib/lwm2m/ipso_buzzer.c +++ b/subsys/net/lib/lwm2m/ipso_buzzer.c @@ -258,4 +258,4 @@ static int ipso_buzzer_init(void) return 0; } -SYS_INIT(ipso_buzzer_init, APPLICATION, CONFIG_KERNEL_INIT_PRIORITY_DEFAULT); +LWM2M_OBJ_INIT(ipso_buzzer_init); diff --git a/subsys/net/lib/lwm2m/ipso_current_sensor.c b/subsys/net/lib/lwm2m/ipso_current_sensor.c index 0684db94220..1268b7da56d 100644 --- a/subsys/net/lib/lwm2m/ipso_current_sensor.c +++ b/subsys/net/lib/lwm2m/ipso_current_sensor.c @@ -228,5 +228,4 @@ static int ipso_current_sensor_init(void) return 0; } -SYS_INIT(ipso_current_sensor_init, APPLICATION, - CONFIG_KERNEL_INIT_PRIORITY_DEFAULT); +LWM2M_OBJ_INIT(ipso_current_sensor_init); diff --git a/subsys/net/lib/lwm2m/ipso_filling_sensor.c b/subsys/net/lib/lwm2m/ipso_filling_sensor.c index 072d6d35bbb..96944e0c16a 100644 --- a/subsys/net/lib/lwm2m/ipso_filling_sensor.c +++ b/subsys/net/lib/lwm2m/ipso_filling_sensor.c @@ -228,7 +228,7 @@ static struct lwm2m_engine_obj_inst *filling_sensor_create(uint16_t obj_inst_id) return &inst[index]; } -static int init(void) +static int fill_sensor_init(void) { fill_sensor.obj_id = IPSO_OBJECT_ID; fill_sensor.version_major = FILLING_VERSION_MAJOR; @@ -243,4 +243,4 @@ static int init(void) return 0; } -SYS_INIT(init, APPLICATION, CONFIG_KERNEL_INIT_PRIORITY_DEFAULT); +LWM2M_OBJ_INIT(fill_sensor_init); diff --git a/subsys/net/lib/lwm2m/ipso_generic_sensor.c b/subsys/net/lib/lwm2m/ipso_generic_sensor.c index def650ce9e4..05a1afc9806 100644 --- a/subsys/net/lib/lwm2m/ipso_generic_sensor.c +++ b/subsys/net/lib/lwm2m/ipso_generic_sensor.c @@ -237,5 +237,4 @@ static int ipso_generic_sensor_init(void) return 0; } -SYS_INIT(ipso_generic_sensor_init, APPLICATION, - CONFIG_KERNEL_INIT_PRIORITY_DEFAULT); +LWM2M_OBJ_INIT(ipso_generic_sensor_init); diff --git a/subsys/net/lib/lwm2m/ipso_humidity_sensor.c b/subsys/net/lib/lwm2m/ipso_humidity_sensor.c index 24be33d37f2..b2d147060a0 100644 --- a/subsys/net/lib/lwm2m/ipso_humidity_sensor.c +++ b/subsys/net/lib/lwm2m/ipso_humidity_sensor.c @@ -218,5 +218,4 @@ static int ipso_humidity_sensor_init(void) return 0; } -SYS_INIT(ipso_humidity_sensor_init, APPLICATION, - CONFIG_KERNEL_INIT_PRIORITY_DEFAULT); +LWM2M_OBJ_INIT(ipso_humidity_sensor_init); diff --git a/subsys/net/lib/lwm2m/ipso_light_control.c b/subsys/net/lib/lwm2m/ipso_light_control.c index fc9a897461a..b7f727ff4a4 100644 --- a/subsys/net/lib/lwm2m/ipso_light_control.c +++ b/subsys/net/lib/lwm2m/ipso_light_control.c @@ -201,5 +201,4 @@ static int ipso_light_control_init(void) return 0; } -SYS_INIT(ipso_light_control_init, APPLICATION, - CONFIG_KERNEL_INIT_PRIORITY_DEFAULT); +LWM2M_OBJ_INIT(ipso_light_control_init); diff --git a/subsys/net/lib/lwm2m/ipso_onoff_switch.c b/subsys/net/lib/lwm2m/ipso_onoff_switch.c index 3bf8ba65c4e..3da496b2ca1 100644 --- a/subsys/net/lib/lwm2m/ipso_onoff_switch.c +++ b/subsys/net/lib/lwm2m/ipso_onoff_switch.c @@ -249,4 +249,4 @@ static int ipso_switch_init(void) return 0; } -SYS_INIT(ipso_switch_init, APPLICATION, CONFIG_KERNEL_INIT_PRIORITY_DEFAULT); +LWM2M_OBJ_INIT(ipso_switch_init); diff --git a/subsys/net/lib/lwm2m/ipso_pressure_sensor.c b/subsys/net/lib/lwm2m/ipso_pressure_sensor.c index 87f87e4a277..7dca2ed3956 100644 --- a/subsys/net/lib/lwm2m/ipso_pressure_sensor.c +++ b/subsys/net/lib/lwm2m/ipso_pressure_sensor.c @@ -221,5 +221,4 @@ static int ipso_pressure_sensor_init(void) return 0; } -SYS_INIT(ipso_pressure_sensor_init, APPLICATION, - CONFIG_KERNEL_INIT_PRIORITY_DEFAULT); +LWM2M_OBJ_INIT(ipso_pressure_sensor_init); diff --git a/subsys/net/lib/lwm2m/ipso_push_button.c b/subsys/net/lib/lwm2m/ipso_push_button.c index 2cccd276aa9..07782a86756 100644 --- a/subsys/net/lib/lwm2m/ipso_push_button.c +++ b/subsys/net/lib/lwm2m/ipso_push_button.c @@ -186,4 +186,4 @@ static int ipso_button_init(void) return 0; } -SYS_INIT(ipso_button_init, APPLICATION, CONFIG_KERNEL_INIT_PRIORITY_DEFAULT); +LWM2M_OBJ_INIT(ipso_button_init); diff --git a/subsys/net/lib/lwm2m/ipso_temp_sensor.c b/subsys/net/lib/lwm2m/ipso_temp_sensor.c index bdf59563833..ba843db0ebd 100644 --- a/subsys/net/lib/lwm2m/ipso_temp_sensor.c +++ b/subsys/net/lib/lwm2m/ipso_temp_sensor.c @@ -221,5 +221,4 @@ static int ipso_temp_sensor_init(void) return 0; } -SYS_INIT(ipso_temp_sensor_init, APPLICATION, - CONFIG_KERNEL_INIT_PRIORITY_DEFAULT); +LWM2M_OBJ_INIT(ipso_temp_sensor_init); diff --git a/subsys/net/lib/lwm2m/ipso_timer.c b/subsys/net/lib/lwm2m/ipso_timer.c index 6085d36d04c..833002e56c4 100644 --- a/subsys/net/lib/lwm2m/ipso_timer.c +++ b/subsys/net/lib/lwm2m/ipso_timer.c @@ -366,4 +366,4 @@ static int ipso_timer_init(void) return 0; } -SYS_INIT(ipso_timer_init, APPLICATION, CONFIG_KERNEL_INIT_PRIORITY_DEFAULT); +LWM2M_OBJ_INIT(ipso_timer_init); diff --git a/subsys/net/lib/lwm2m/ipso_voltage_sensor.c b/subsys/net/lib/lwm2m/ipso_voltage_sensor.c index 55b45902234..ec1274d07ff 100644 --- a/subsys/net/lib/lwm2m/ipso_voltage_sensor.c +++ b/subsys/net/lib/lwm2m/ipso_voltage_sensor.c @@ -229,5 +229,4 @@ static int ipso_voltage_sensor_init(void) return 0; } -SYS_INIT(ipso_voltage_sensor_init, APPLICATION, - CONFIG_KERNEL_INIT_PRIORITY_DEFAULT); +LWM2M_OBJ_INIT(ipso_voltage_sensor_init); diff --git a/subsys/net/lib/lwm2m/iterables.ld b/subsys/net/lib/lwm2m/iterables.ld new file mode 100644 index 00000000000..83ce9070ef0 --- /dev/null +++ b/subsys/net/lib/lwm2m/iterables.ld @@ -0,0 +1 @@ +ITERABLE_SECTION_ROM(lwm2m_init_func, 4) diff --git a/subsys/net/lib/lwm2m/lwm2m_engine.c b/subsys/net/lib/lwm2m/lwm2m_engine.c index bad54c521d7..ba408c1de8e 100644 --- a/subsys/net/lib/lwm2m/lwm2m_engine.c +++ b/subsys/net/lib/lwm2m/lwm2m_engine.c @@ -1330,9 +1330,12 @@ static int lwm2m_engine_init(void) (void)memset(output_block_contexts, 0, sizeof(output_block_contexts)); #endif - if (IS_ENABLED(CONFIG_LWM2M_RESOURCE_DATA_CACHE_SUPPORT)) { - /* Init data cache */ - lwm2m_engine_data_cache_init(); + STRUCT_SECTION_FOREACH(lwm2m_init_func, init) { + int ret = init->f(); + + if (ret) { + LOG_ERR("Init function %p returned %d", init, ret); + } } /* start sock receive thread */ diff --git a/subsys/net/lib/lwm2m/lwm2m_engine.h b/subsys/net/lib/lwm2m/lwm2m_engine.h index 81b28395662..bd96a380cf7 100644 --- a/subsys/net/lib/lwm2m/lwm2m_engine.h +++ b/subsys/net/lib/lwm2m/lwm2m_engine.h @@ -12,6 +12,7 @@ #include "lwm2m_object.h" #include "lwm2m_observation.h" #include "lwm2m_registry.h" +#include #define LWM2M_PROTOCOL_VERSION_MAJOR 1 #if defined(CONFIG_LWM2M_VERSION_1_1) @@ -30,6 +31,65 @@ /* length of time in milliseconds to wait for buffer allocations */ #define BUF_ALLOC_TIMEOUT K_SECONDS(1) +/** initialization function */ +struct lwm2m_init_func { + int (*f)(void); +}; +/** + * @defgroup LWM2M_PRIO LwM2M initialization priorities + * @{ + */ +#define LWM2M_PRIO_ENGINE 0 /**< Engine initialization */ +#define LWM2M_PRIO_CORE 1 /**< Core object initialization */ +#define LWM2M_PRIO_OBJ 2 /**< Object initializations */ +#define LwM2M_PRIO_APP 3 /**< Application logic initialization */ +/** @} */ + +/** + * @brief Declare an initialization function to be executed when LwM2M engine starts. + * + * When LwM2M engine starts up, it first executes all initialization functions in following + * priority order: + * 1. LWM2M_PRIO_ENGINE + * 2. LWM2M_PRIO_CORE, this is where all LwM2M core objects are initialized + * 3. LWM2M_PRIO_OBJ, this is where all other than core objects are initialized + * 4. LwM2M_PRIO_APP, application initialization. + * For example create sensor objects, and register object callbacks. + * + * @param[in] prio Priority, one of @ref LWM2M_PRIO macros. + * @param[in] init_function Initialization function + */ +#define LWM2M_ON_INIT(prio, init_function) \ + STRUCT_SECTION_ITERABLE(lwm2m_init_func, \ + CONCAT(LWM2M, prio, init_function)) = {.f = init_function} + +/** + * @brief Declare engine initialization function. + * @sa LWM2M_ON_INIT + * @param[in] init_function Initialization function + */ +#define LWM2M_ENGINE_INIT(init_function) LWM2M_ON_INIT(LWM2M_PRIO_ENGINE, init_function) + +/** + * @brief Declare core object initialization function. + * @sa LWM2M_ON_INIT + * @param[in] init_function Initialization function + */ +#define LWM2M_CORE_INIT(init_function) LWM2M_ON_INIT(LWM2M_PRIO_CORE, init_function) + +/** + * @brief Declare object initialization function. + * @sa LWM2M_ON_INIT + * @param[in] init_function Initialization function + */ +#define LWM2M_OBJ_INIT(init_function) LWM2M_ON_INIT(LWM2M_PRIO_OBJ, init_function) + +/** + * @brief Declare application specific initialization function. + * @sa LWM2M_ON_INIT + * @param[in] init_function Initialization function + */ +#define LWM2M_APP_INIT(init_function) LWM2M_ON_INIT(LWM2M_PRIO_APP, init_function) /** * @brief Validates that writing is a legal operation on the field given by the object in diff --git a/subsys/net/lib/lwm2m/lwm2m_obj_access_control.c b/subsys/net/lib/lwm2m/lwm2m_obj_access_control.c index 383dbe9b539..e5eb8c56efb 100644 --- a/subsys/net/lib/lwm2m/lwm2m_obj_access_control.c +++ b/subsys/net/lib/lwm2m/lwm2m_obj_access_control.c @@ -439,4 +439,4 @@ static int ac_control_init(void) return 0; } -SYS_INIT(ac_control_init, APPLICATION, CONFIG_KERNEL_INIT_PRIORITY_DEFAULT); +LWM2M_CORE_INIT(ac_control_init); diff --git a/subsys/net/lib/lwm2m/lwm2m_obj_binaryappdata.c b/subsys/net/lib/lwm2m/lwm2m_obj_binaryappdata.c index e9166f9e678..51e90b820ec 100644 --- a/subsys/net/lib/lwm2m/lwm2m_obj_binaryappdata.c +++ b/subsys/net/lib/lwm2m/lwm2m_obj_binaryappdata.c @@ -122,4 +122,4 @@ static int lwm2m_binaryappdata_init(void) return ret; } -SYS_INIT(lwm2m_binaryappdata_init, APPLICATION, CONFIG_KERNEL_INIT_PRIORITY_DEFAULT); +LWM2M_OBJ_INIT(lwm2m_binaryappdata_init); diff --git a/subsys/net/lib/lwm2m/lwm2m_obj_connmon.c b/subsys/net/lib/lwm2m/lwm2m_obj_connmon.c index 70309a0d3d6..a3cfaad8fa2 100644 --- a/subsys/net/lib/lwm2m/lwm2m_obj_connmon.c +++ b/subsys/net/lib/lwm2m/lwm2m_obj_connmon.c @@ -222,4 +222,4 @@ static int lwm2m_connmon_init(void) return ret; } -SYS_INIT(lwm2m_connmon_init, APPLICATION, CONFIG_KERNEL_INIT_PRIORITY_DEFAULT); +LWM2M_CORE_INIT(lwm2m_connmon_init); diff --git a/subsys/net/lib/lwm2m/lwm2m_obj_device.c b/subsys/net/lib/lwm2m/lwm2m_obj_device.c index f5399fefc1e..c4abb72d506 100644 --- a/subsys/net/lib/lwm2m/lwm2m_obj_device.c +++ b/subsys/net/lib/lwm2m/lwm2m_obj_device.c @@ -393,4 +393,4 @@ static int lwm2m_device_init(void) return ret; } -SYS_INIT(lwm2m_device_init, APPLICATION, CONFIG_KERNEL_INIT_PRIORITY_DEFAULT); +LWM2M_CORE_INIT(lwm2m_device_init); diff --git a/subsys/net/lib/lwm2m/lwm2m_obj_event_log.c b/subsys/net/lib/lwm2m/lwm2m_obj_event_log.c index 907dd596611..e80dfc10ee6 100644 --- a/subsys/net/lib/lwm2m/lwm2m_obj_event_log.c +++ b/subsys/net/lib/lwm2m/lwm2m_obj_event_log.c @@ -103,4 +103,4 @@ static int lwm2m_event_log_init(void) return ret; } -SYS_INIT(lwm2m_event_log_init, APPLICATION, CONFIG_KERNEL_INIT_PRIORITY_DEFAULT); +LWM2M_OBJ_INIT(lwm2m_event_log_init); diff --git a/subsys/net/lib/lwm2m/lwm2m_obj_firmware.c b/subsys/net/lib/lwm2m/lwm2m_obj_firmware.c index 1f0f6bb5b1e..082197c83a5 100644 --- a/subsys/net/lib/lwm2m/lwm2m_obj_firmware.c +++ b/subsys/net/lib/lwm2m/lwm2m_obj_firmware.c @@ -506,4 +506,4 @@ static int lwm2m_firmware_init(void) return ret; } -SYS_INIT(lwm2m_firmware_init, APPLICATION, CONFIG_KERNEL_INIT_PRIORITY_DEFAULT); +LWM2M_CORE_INIT(lwm2m_firmware_init); diff --git a/subsys/net/lib/lwm2m/lwm2m_obj_gateway.c b/subsys/net/lib/lwm2m/lwm2m_obj_gateway.c index 5bb12f80f47..106ef951653 100644 --- a/subsys/net/lib/lwm2m/lwm2m_obj_gateway.c +++ b/subsys/net/lib/lwm2m/lwm2m_obj_gateway.c @@ -206,7 +206,7 @@ static int lwm2m_gw_init(void) lwm2m_gw.obj_id = LWM2M_OBJECT_GATEWAY_ID; lwm2m_gw.version_major = GATEWAY_VERSION_MAJOR; lwm2m_gw.version_minor = GATEWAY_VERSION_MINOR; - lwm2m_gw.is_core = true; + lwm2m_gw.is_core = false; lwm2m_gw.fields = fields; lwm2m_gw.field_count = ARRAY_SIZE(fields); lwm2m_gw.max_instance_count = MAX_INSTANCE_COUNT; @@ -215,4 +215,4 @@ static int lwm2m_gw_init(void) return ret; } -SYS_INIT(lwm2m_gw_init, APPLICATION, CONFIG_KERNEL_INIT_PRIORITY_DEFAULT); +LWM2M_OBJ_INIT(lwm2m_gw_init); diff --git a/subsys/net/lib/lwm2m/lwm2m_obj_location.c b/subsys/net/lib/lwm2m/lwm2m_obj_location.c index 73c43ff78eb..b7b9828982c 100644 --- a/subsys/net/lib/lwm2m/lwm2m_obj_location.c +++ b/subsys/net/lib/lwm2m/lwm2m_obj_location.c @@ -117,4 +117,4 @@ static int ipso_location_init(void) return ret; } -SYS_INIT(ipso_location_init, APPLICATION, CONFIG_KERNEL_INIT_PRIORITY_DEFAULT); +LWM2M_CORE_INIT(ipso_location_init); diff --git a/subsys/net/lib/lwm2m/lwm2m_obj_portfolio.c b/subsys/net/lib/lwm2m/lwm2m_obj_portfolio.c index e5cdc2198e6..b77fc722130 100644 --- a/subsys/net/lib/lwm2m/lwm2m_obj_portfolio.c +++ b/subsys/net/lib/lwm2m/lwm2m_obj_portfolio.c @@ -122,4 +122,4 @@ static int lwm2m_portfolio_init(void) return 0; } -SYS_INIT(lwm2m_portfolio_init, APPLICATION, CONFIG_KERNEL_INIT_PRIORITY_DEFAULT); +LWM2M_OBJ_INIT(lwm2m_portfolio_init); diff --git a/subsys/net/lib/lwm2m/lwm2m_obj_security.c b/subsys/net/lib/lwm2m/lwm2m_obj_security.c index 00796648634..a926cb39b27 100644 --- a/subsys/net/lib/lwm2m/lwm2m_obj_security.c +++ b/subsys/net/lib/lwm2m/lwm2m_obj_security.c @@ -261,4 +261,4 @@ static int lwm2m_security_init(void) return ret; } -SYS_INIT(lwm2m_security_init, APPLICATION, CONFIG_KERNEL_INIT_PRIORITY_DEFAULT); +LWM2M_CORE_INIT(lwm2m_security_init); diff --git a/subsys/net/lib/lwm2m/lwm2m_obj_server.c b/subsys/net/lib/lwm2m/lwm2m_obj_server.c index a9432340038..a7d3e541bbe 100644 --- a/subsys/net/lib/lwm2m/lwm2m_obj_server.c +++ b/subsys/net/lib/lwm2m/lwm2m_obj_server.c @@ -18,6 +18,7 @@ LOG_MODULE_REGISTER(LOG_MODULE_NAME); #include "lwm2m_obj_server.h" #include "lwm2m_rd_client.h" #include "lwm2m_registry.h" +#include "lwm2m_engine.h" #define SERVER_VERSION_MAJOR 1 #if defined(CONFIG_LWM2M_SERVER_OBJECT_VERSION_1_1) @@ -458,4 +459,4 @@ static int lwm2m_server_init(void) return ret; } -SYS_INIT(lwm2m_server_init, APPLICATION, CONFIG_KERNEL_INIT_PRIORITY_DEFAULT); +LWM2M_CORE_INIT(lwm2m_server_init); diff --git a/subsys/net/lib/lwm2m/lwm2m_obj_swmgmt.c b/subsys/net/lib/lwm2m/lwm2m_obj_swmgmt.c index a8376ea8621..1ccd22520b6 100644 --- a/subsys/net/lib/lwm2m/lwm2m_obj_swmgmt.c +++ b/subsys/net/lib/lwm2m/lwm2m_obj_swmgmt.c @@ -794,4 +794,4 @@ static int lwm2m_swmgmt_init(void) return 0; } -SYS_INIT(lwm2m_swmgmt_init, APPLICATION, CONFIG_KERNEL_INIT_PRIORITY_DEFAULT); +LWM2M_OBJ_INIT(lwm2m_swmgmt_init); diff --git a/subsys/net/lib/lwm2m/lwm2m_rd_client.c b/subsys/net/lib/lwm2m/lwm2m_rd_client.c index 22ce51e5248..99f673ce6b1 100644 --- a/subsys/net/lib/lwm2m/lwm2m_rd_client.c +++ b/subsys/net/lib/lwm2m/lwm2m_rd_client.c @@ -1791,6 +1791,4 @@ static int sys_lwm2m_rd_client_init(void) return lwm2m_rd_client_init(); } - -SYS_INIT(sys_lwm2m_rd_client_init, APPLICATION, - CONFIG_KERNEL_INIT_PRIORITY_DEFAULT); +LWM2M_ENGINE_INIT(sys_lwm2m_rd_client_init); diff --git a/subsys/net/lib/lwm2m/lwm2m_registry.c b/subsys/net/lib/lwm2m/lwm2m_registry.c index 1701b7f7412..6c1bab92b25 100644 --- a/subsys/net/lib/lwm2m/lwm2m_registry.c +++ b/subsys/net/lib/lwm2m/lwm2m_registry.c @@ -2234,9 +2234,9 @@ int lwm2m_engine_enable_cache(const char *resource_path, struct lwm2m_time_serie #endif /* CONFIG_LWM2M_RESOURCE_DATA_CACHE_SUPPORT */ } -int lwm2m_engine_data_cache_init(void) -{ #if defined(CONFIG_LWM2M_RESOURCE_DATA_CACHE_SUPPORT) +static int lwm2m_engine_data_cache_init(void) +{ int i; sys_slist_init(&lwm2m_timed_cache_list); @@ -2244,9 +2244,10 @@ int lwm2m_engine_data_cache_init(void) for (i = 0; i < ARRAY_SIZE(lwm2m_cache_entries); i++) { lwm2m_cache_entries[i].path.level = LWM2M_PATH_LEVEL_NONE; } -#endif return 0; } +LWM2M_ENGINE_INIT(lwm2m_engine_data_cache_init); +#endif bool lwm2m_cache_write(struct lwm2m_time_series_resource *cache_entry, struct lwm2m_time_series_elem *buf) diff --git a/subsys/net/lib/lwm2m/lwm2m_registry.h b/subsys/net/lib/lwm2m/lwm2m_registry.h index 0d817d00442..554babd93cd 100644 --- a/subsys/net/lib/lwm2m/lwm2m_registry.h +++ b/subsys/net/lib/lwm2m/lwm2m_registry.h @@ -242,7 +242,6 @@ struct lwm2m_cache_read_info { }; #endif -int lwm2m_engine_data_cache_init(void); struct lwm2m_time_series_resource * lwm2m_cache_entry_get_by_object(const struct lwm2m_obj_path *obj_path); bool lwm2m_cache_write(struct lwm2m_time_series_resource *cache_entry, diff --git a/subsys/net/lib/lwm2m/ucifi_battery.c b/subsys/net/lib/lwm2m/ucifi_battery.c index 11da0980967..468f4bbc4c3 100644 --- a/subsys/net/lib/lwm2m/ucifi_battery.c +++ b/subsys/net/lib/lwm2m/ucifi_battery.c @@ -150,4 +150,4 @@ static int ucifi_battery_init(void) return 0; } -SYS_INIT(ucifi_battery_init, APPLICATION, CONFIG_KERNEL_INIT_PRIORITY_DEFAULT); +LWM2M_OBJ_INIT(ucifi_battery_init); diff --git a/subsys/net/lib/lwm2m/ucifi_lpwan.c b/subsys/net/lib/lwm2m/ucifi_lpwan.c index 82878724405..0acbb0ecf3b 100644 --- a/subsys/net/lib/lwm2m/ucifi_lpwan.c +++ b/subsys/net/lib/lwm2m/ucifi_lpwan.c @@ -178,4 +178,4 @@ static int ucifi_lpwan_init(void) return 0; } -SYS_INIT(ucifi_lpwan_init, APPLICATION, CONFIG_KERNEL_INIT_PRIORITY_DEFAULT); +LWM2M_OBJ_INIT(ucifi_lpwan_init); diff --git a/tests/net/lib/lwm2m/lwm2m_engine/CMakeLists.txt b/tests/net/lib/lwm2m/lwm2m_engine/CMakeLists.txt index 36e161c6b11..d4a60e2bb9c 100644 --- a/tests/net/lib/lwm2m/lwm2m_engine/CMakeLists.txt +++ b/tests/net/lib/lwm2m/lwm2m_engine/CMakeLists.txt @@ -10,6 +10,7 @@ set(APP_SRC_DIR ${CMAKE_CURRENT_SOURCE_DIR}/src) target_sources(app PRIVATE ${APP_SRC_DIR}/main.c) target_sources(app PRIVATE ${APP_SRC_DIR}/stubs.c) target_sources(app PRIVATE ${ZEPHYR_BASE}/subsys/net/lib/lwm2m/lwm2m_engine.c) +zephyr_linker_sources(SECTIONS ${ZEPHYR_BASE}/subsys/net/lib/lwm2m/iterables.ld) # Add includes directories target_include_directories(app PRIVATE ${CMAKE_CURRENT_SOURCE_DIR}/src) diff --git a/tests/net/lib/lwm2m/lwm2m_registry/src/lwm2m_registry.c b/tests/net/lib/lwm2m/lwm2m_registry/src/lwm2m_registry.c index 8e99f666b7f..7763469bc4e 100644 --- a/tests/net/lib/lwm2m/lwm2m_registry/src/lwm2m_registry.c +++ b/tests/net/lib/lwm2m/lwm2m_registry/src/lwm2m_registry.c @@ -612,7 +612,6 @@ ZTEST(lwm2m_registry, test_resource_cache) struct lwm2m_time_series_elem e; /* Resource cache is turned off */ - zassert_equal(lwm2m_engine_data_cache_init(), 0); zassert_is_null(lwm2m_cache_entry_get_by_object(&path)); zassert_equal(lwm2m_enable_cache(&path, &e, 1), -ENOTSUP); /* deprecated */ From c51a18f85189fd3b3ad66c63b9717d7d817590df Mon Sep 17 00:00:00 2001 From: Fabio Baltieri Date: Fri, 19 Jan 2024 23:56:05 +0000 Subject: [PATCH 2760/3723] input: input-event-codes: add few codes used by HID devices Add few input codes used in HID tables. Signed-off-by: Fabio Baltieri --- include/zephyr/dt-bindings/input/input-event-codes.h | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/include/zephyr/dt-bindings/input/input-event-codes.h b/include/zephyr/dt-bindings/input/input-event-codes.h index 98d71a2db78..34dd00f8514 100644 --- a/include/zephyr/dt-bindings/input/input-event-codes.h +++ b/include/zephyr/dt-bindings/input/input-event-codes.h @@ -119,10 +119,12 @@ #define INPUT_KEY_KPASTERISK 55 /**< Keypad Asterisk Key */ #define INPUT_KEY_KPCOMMA 121 /**< Keypad Comma Key */ #define INPUT_KEY_KPDOT 83 /**< Keypad Dot Key */ +#define INPUT_KEY_KPENTER 96 /**< Keypad Enter Key */ #define INPUT_KEY_KPEQUAL 117 /**< Keypad Equal Key */ #define INPUT_KEY_KPMINUS 74 /**< Keypad Minus Key */ #define INPUT_KEY_KPPLUS 78 /**< Keypad Plus Key */ #define INPUT_KEY_KPPLUSMINUS 118 /**< Keypad Plus Key */ +#define INPUT_KEY_KPSLASH 98 /**< Keypad Slash Key */ #define INPUT_KEY_L 38 /**< L Key */ #define INPUT_KEY_LEFT 105 /**< Left Key */ #define INPUT_KEY_LEFTALT 56 /**< Left Alt Key */ @@ -147,7 +149,9 @@ #define INPUT_KEY_Q 16 /**< Q Key */ #define INPUT_KEY_R 19 /**< R Key */ #define INPUT_KEY_RIGHT 106 /**< Right Key */ +#define INPUT_KEY_RIGHTALT 100 /**< Right Alt Key */ #define INPUT_KEY_RIGHTBRACE 27 /**< Right Brace Key */ +#define INPUT_KEY_RIGHTCTRL 97 /**< Right Ctrl Key */ #define INPUT_KEY_RIGHTMETA 126 /**< Right Meta Key */ #define INPUT_KEY_RIGHTSHIFT 54 /**< Right Shift Key */ #define INPUT_KEY_S 31 /**< S Key */ @@ -157,6 +161,7 @@ #define INPUT_KEY_SLASH 53 /**< Slash Key */ #define INPUT_KEY_SLEEP 142 /**< System Sleep Key */ #define INPUT_KEY_SPACE 57 /**< Space Key */ +#define INPUT_KEY_SYSRQ 99 /**< SysReq Key */ #define INPUT_KEY_T 20 /**< T Key */ #define INPUT_KEY_TAB 15 /**< Tab Key*/ #define INPUT_KEY_U 22 /**< U Key */ From 297faf71d0890e19bdcc39097cb1e8ed93db07fb Mon Sep 17 00:00:00 2001 From: Fabio Baltieri Date: Sat, 20 Jan 2024 00:02:26 +0000 Subject: [PATCH 2761/3723] input: add two input to hid code translation functions Add a pair of functions to translate from input events to hid codes, mapping most of the current hid codes defined in zephyr/usb/class/hid.h. Use a sparse table for the mapping, which takes advantage of the fact that code 0 is reserved. Inspired by the linux equivalent hid to input map: https://elixir.bootlin.com/linux/latest/source/drivers/hid/hid-input.c#L27 Signed-off-by: Fabio Baltieri --- include/zephyr/input/input_hid.h | 42 +++++++++ subsys/input/CMakeLists.txt | 1 + subsys/input/input_hid.c | 148 +++++++++++++++++++++++++++++++ 3 files changed, 191 insertions(+) create mode 100644 include/zephyr/input/input_hid.h create mode 100644 subsys/input/input_hid.c diff --git a/include/zephyr/input/input_hid.h b/include/zephyr/input/input_hid.h new file mode 100644 index 00000000000..2a89dde0530 --- /dev/null +++ b/include/zephyr/input/input_hid.h @@ -0,0 +1,42 @@ +/* + * Copyright 2024 Google LLC + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#ifndef ZEPHYR_INCLUDE_INPUT_HID_H_ +#define ZEPHYR_INCLUDE_INPUT_HID_H_ + +/** + * @addtogroup input_interface + * @{ + */ + +/** + * @brief Convert an input code to HID code. + * + * Takes an input code as input and returns the corresponding HID code as + * output. The return value is -1 if the code is not found, if found it can + * safely be casted to a uint8_t type. + * + * @param input_code Event code (see @ref INPUT_KEY_CODES). + * @retval the HID code corresponding to the input code. + * @retval -1 if there's no HID code for the specified input code. + */ +int16_t input_to_hid_code(uint16_t input_code); + +/** + * @brief Convert an input code to HID modifier. + * + * Takes an input code as input and returns the corresponding HID modifier as + * output or 0. + * + * @param input_code Event code (see @ref INPUT_KEY_CODES). + * @retval the HID modifier corresponding to the input code. + * @retval 0 if there's no HID modifier for the specified input code. + */ +uint8_t input_to_hid_modifier(uint16_t input_code); + +/** @} */ + +#endif /* ZEPHYR_INCLUDE_INPUT_HID_H_ */ diff --git a/subsys/input/CMakeLists.txt b/subsys/input/CMakeLists.txt index 99b31351399..f536787d1ea 100644 --- a/subsys/input/CMakeLists.txt +++ b/subsys/input/CMakeLists.txt @@ -3,6 +3,7 @@ zephyr_library() zephyr_library_sources(input.c) +zephyr_library_sources(input_hid.c) zephyr_library_sources(input_utils.c) zephyr_library_sources_ifdef(CONFIG_INPUT_KEYMAP input_keymap.c) diff --git a/subsys/input/input_hid.c b/subsys/input/input_hid.c new file mode 100644 index 00000000000..6ace46eb1a1 --- /dev/null +++ b/subsys/input/input_hid.c @@ -0,0 +1,148 @@ +/* + * Copyright 2024 Google LLC + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include +#include +#include +#include + +static uint8_t input_to_hid_map[] = { + [INPUT_KEY_A] = HID_KEY_A, + [INPUT_KEY_B] = HID_KEY_B, + [INPUT_KEY_C] = HID_KEY_C, + [INPUT_KEY_D] = HID_KEY_D, + [INPUT_KEY_E] = HID_KEY_E, + [INPUT_KEY_F] = HID_KEY_F, + [INPUT_KEY_G] = HID_KEY_G, + [INPUT_KEY_H] = HID_KEY_H, + [INPUT_KEY_I] = HID_KEY_I, + [INPUT_KEY_J] = HID_KEY_J, + [INPUT_KEY_K] = HID_KEY_K, + [INPUT_KEY_L] = HID_KEY_L, + [INPUT_KEY_M] = HID_KEY_M, + [INPUT_KEY_N] = HID_KEY_N, + [INPUT_KEY_O] = HID_KEY_O, + [INPUT_KEY_P] = HID_KEY_P, + [INPUT_KEY_Q] = HID_KEY_Q, + [INPUT_KEY_R] = HID_KEY_R, + [INPUT_KEY_S] = HID_KEY_S, + [INPUT_KEY_T] = HID_KEY_T, + [INPUT_KEY_U] = HID_KEY_U, + [INPUT_KEY_V] = HID_KEY_V, + [INPUT_KEY_W] = HID_KEY_W, + [INPUT_KEY_X] = HID_KEY_X, + [INPUT_KEY_Y] = HID_KEY_Y, + [INPUT_KEY_Z] = HID_KEY_Z, + [INPUT_KEY_1] = HID_KEY_1, + [INPUT_KEY_2] = HID_KEY_2, + [INPUT_KEY_3] = HID_KEY_3, + [INPUT_KEY_4] = HID_KEY_4, + [INPUT_KEY_5] = HID_KEY_5, + [INPUT_KEY_6] = HID_KEY_6, + [INPUT_KEY_7] = HID_KEY_7, + [INPUT_KEY_8] = HID_KEY_8, + [INPUT_KEY_9] = HID_KEY_9, + [INPUT_KEY_0] = HID_KEY_0, + [INPUT_KEY_ENTER] = HID_KEY_ENTER, + [INPUT_KEY_ESC] = HID_KEY_ESC, + [INPUT_KEY_BACKSPACE] = HID_KEY_BACKSPACE, + [INPUT_KEY_TAB] = HID_KEY_TAB, + [INPUT_KEY_SPACE] = HID_KEY_SPACE, + [INPUT_KEY_MINUS] = HID_KEY_MINUS, + [INPUT_KEY_EQUAL] = HID_KEY_EQUAL, + [INPUT_KEY_LEFTBRACE] = HID_KEY_LEFTBRACE, + [INPUT_KEY_RIGHTBRACE] = HID_KEY_RIGHTBRACE, + [INPUT_KEY_BACKSLASH] = HID_KEY_BACKSLASH, + [INPUT_KEY_SEMICOLON] = HID_KEY_SEMICOLON, + [INPUT_KEY_APOSTROPHE] = HID_KEY_APOSTROPHE, + [INPUT_KEY_GRAVE] = HID_KEY_GRAVE, + [INPUT_KEY_COMMA] = HID_KEY_COMMA, + [INPUT_KEY_DOT] = HID_KEY_DOT, + [INPUT_KEY_SLASH] = HID_KEY_SLASH, + [INPUT_KEY_CAPSLOCK] = HID_KEY_CAPSLOCK, + [INPUT_KEY_F1] = HID_KEY_F1, + [INPUT_KEY_F2] = HID_KEY_F2, + [INPUT_KEY_F3] = HID_KEY_F3, + [INPUT_KEY_F4] = HID_KEY_F4, + [INPUT_KEY_F5] = HID_KEY_F5, + [INPUT_KEY_F6] = HID_KEY_F6, + [INPUT_KEY_F7] = HID_KEY_F7, + [INPUT_KEY_F8] = HID_KEY_F8, + [INPUT_KEY_F9] = HID_KEY_F9, + [INPUT_KEY_F10] = HID_KEY_F10, + [INPUT_KEY_F11] = HID_KEY_F11, + [INPUT_KEY_F12] = HID_KEY_F12, + [INPUT_KEY_SYSRQ] = HID_KEY_SYSRQ, + [INPUT_KEY_SCROLLLOCK] = HID_KEY_SCROLLLOCK, + [INPUT_KEY_PAUSE] = HID_KEY_PAUSE, + [INPUT_KEY_INSERT] = HID_KEY_INSERT, + [INPUT_KEY_HOME] = HID_KEY_HOME, + [INPUT_KEY_PAGEUP] = HID_KEY_PAGEUP, + [INPUT_KEY_DELETE] = HID_KEY_DELETE, + [INPUT_KEY_END] = HID_KEY_END, + [INPUT_KEY_PAGEDOWN] = HID_KEY_PAGEDOWN, + [INPUT_KEY_RIGHT] = HID_KEY_RIGHT, + [INPUT_KEY_LEFT] = HID_KEY_LEFT, + [INPUT_KEY_DOWN] = HID_KEY_DOWN, + [INPUT_KEY_UP] = HID_KEY_UP, + [INPUT_KEY_NUMLOCK] = HID_KEY_NUMLOCK, + [INPUT_KEY_KPSLASH] = HID_KEY_KPSLASH, + [INPUT_KEY_KPASTERISK] = HID_KEY_KPASTERISK, + [INPUT_KEY_KPMINUS] = HID_KEY_KPMINUS, + [INPUT_KEY_KPPLUS] = HID_KEY_KPPLUS, + [INPUT_KEY_KPENTER] = HID_KEY_KPENTER, + [INPUT_KEY_KP1] = HID_KEY_KP_1, + [INPUT_KEY_KP2] = HID_KEY_KP_2, + [INPUT_KEY_KP3] = HID_KEY_KP_3, + [INPUT_KEY_KP4] = HID_KEY_KP_4, + [INPUT_KEY_KP5] = HID_KEY_KP_5, + [INPUT_KEY_KP6] = HID_KEY_KP_6, + [INPUT_KEY_KP7] = HID_KEY_KP_7, + [INPUT_KEY_KP8] = HID_KEY_KP_8, + [INPUT_KEY_KP9] = HID_KEY_KP_9, + [INPUT_KEY_KP0] = HID_KEY_KP_0, +}; + +int16_t input_to_hid_code(uint16_t input_code) +{ + uint8_t hid_code; + + if (input_code >= ARRAY_SIZE(input_to_hid_map)) { + return -1; + } + + hid_code = input_to_hid_map[input_code]; + + if (hid_code == 0) { + return -1; + } + + return hid_code; +} + +uint8_t input_to_hid_modifier(uint16_t input_code) +{ + switch (input_code) { + case INPUT_KEY_LEFTCTRL: + return HID_KBD_MODIFIER_LEFT_CTRL; + case INPUT_KEY_LEFTSHIFT: + return HID_KBD_MODIFIER_LEFT_SHIFT; + case INPUT_KEY_LEFTALT: + return HID_KBD_MODIFIER_LEFT_ALT; + case INPUT_KEY_LEFTMETA: + return HID_KBD_MODIFIER_LEFT_UI; + case INPUT_KEY_RIGHTCTRL: + return HID_KBD_MODIFIER_RIGHT_CTRL; + case INPUT_KEY_RIGHTSHIFT: + return HID_KBD_MODIFIER_RIGHT_SHIFT; + case INPUT_KEY_RIGHTALT: + return HID_KBD_MODIFIER_RIGHT_ALT; + case INPUT_KEY_RIGHTMETA: + return HID_KBD_MODIFIER_RIGHT_UI; + default: + return HID_KBD_MODIFIER_NONE; + } +} From 5697d25901446a7ed60ccfa5ca45a88b16ce6fae Mon Sep 17 00:00:00 2001 From: Luca Burelli Date: Fri, 12 Jan 2024 10:55:56 +0100 Subject: [PATCH 2762/3723] llext: fix test Kconfig module conditions Make it so LLEXT_TEST_HELLO is enabled by default, and it is actually compiled only when the config is enabled. The check for MODULES==y and LLEXT_TEST_HELLO!=m is redundant, as the Twister machinery already causes an error when Kconfig flags specified in the YAML file are coerced to different values. Signed-off-by: Luca Burelli --- tests/subsys/llext/Kconfig | 4 ++-- tests/subsys/llext/hello_world/CMakeLists.txt | 4 +++- 2 files changed, 5 insertions(+), 3 deletions(-) diff --git a/tests/subsys/llext/Kconfig b/tests/subsys/llext/Kconfig index b09068f9810..047e1a45026 100644 --- a/tests/subsys/llext/Kconfig +++ b/tests/subsys/llext/Kconfig @@ -7,6 +7,6 @@ source "Kconfig.zephyr" config LLEXT_TEST_HELLO tristate "llext hello test" - default n + default y help - Set to "m" to test hello-world loading + This enables building the hello_world test case. diff --git a/tests/subsys/llext/hello_world/CMakeLists.txt b/tests/subsys/llext/hello_world/CMakeLists.txt index 45e0fa0b9a3..4fd023801cb 100644 --- a/tests/subsys/llext/hello_world/CMakeLists.txt +++ b/tests/subsys/llext/hello_world/CMakeLists.txt @@ -5,7 +5,9 @@ cmake_minimum_required(VERSION 3.20.0) find_package(Zephyr REQUIRED HINTS $ENV{ZEPHYR_BASE}) project(hello_world) -if(NOT CONFIG_MODULES OR CONFIG_LLEXT_TEST_HELLO STREQUAL "m") +if(NOT CONFIG_LLEXT_TEST_HELLO) + # test disabled, nothing to do +else() set(llext_src_file ${PROJECT_SOURCE_DIR}/hello_world.c) set(llext_bin_file ${PROJECT_BINARY_DIR}/hello_world.llext) From 92a5e3ace755f33006b0579e874fc926041977f5 Mon Sep 17 00:00:00 2001 From: Luca Burelli Date: Fri, 12 Jan 2024 10:34:47 +0100 Subject: [PATCH 2763/3723] llext: rework testcases to share common config This patch reworks the YAML files for the llext samples and tests to share a common restriction list. Also, using an arch-specific config to disable the MPU for the ARM architecture only, there is no need to duplicate the test cases per architecture. Use this to enable the "writable" test case for the ARM architecture and separate the "modules_enabled" case to test building as a module. Signed-off-by: Luca Burelli --- samples/subsys/llext/shell_loader/sample.yaml | 15 +++++---- tests/subsys/llext/testcase.yaml | 33 +++++++++++-------- 2 files changed, 28 insertions(+), 20 deletions(-) diff --git a/samples/subsys/llext/shell_loader/sample.yaml b/samples/subsys/llext/shell_loader/sample.yaml index acb30def4da..3cf54e45020 100644 --- a/samples/subsys/llext/shell_loader/sample.yaml +++ b/samples/subsys/llext/shell_loader/sample.yaml @@ -1,3 +1,11 @@ +common: + tags: llext + arch_allow: + - arm + - xtensa + filter: not CONFIG_MPU and not CONFIG_MMU and not CONFIG_SOC_SERIES_S32ZE_R52 + platform_exclude: + - nuvoton_pfm_m487 # See #63167 sample: description: Loadable extensions with shell sample name: Extension loader shell @@ -5,10 +13,5 @@ tests: sample.llext.shell: tags: shell llext harness: keyboard - filter: not CONFIG_CPU_HAS_MMU and not CONFIG_SOC_SERIES_S32ZE_R52 - arch_allow: arm extra_configs: - - CONFIG_ARM_MPU=n - # Broken platforms - platform_exclude: - - nuvoton_pfm_m487 # See #63167 + - arch:arm:CONFIG_ARM_MPU=n diff --git a/tests/subsys/llext/testcase.yaml b/tests/subsys/llext/testcase.yaml index 6a5fdd1ef0f..23201d9d3f0 100644 --- a/tests/subsys/llext/testcase.yaml +++ b/tests/subsys/llext/testcase.yaml @@ -1,22 +1,27 @@ common: tags: llext + arch_allow: + - arm + - xtensa + filter: not CONFIG_MPU and not CONFIG_MMU and not CONFIG_SOC_SERIES_S32ZE_R52 + platform_exclude: + - nuvoton_pfm_m487 # See #63167 tests: - llext.simple.arm: - filter: not CONFIG_CPU_HAS_MMU and not CONFIG_SOC_SERIES_S32ZE_R52 - arch_allow: arm + llext.simple.readonly: + arch_exclude: xtensa # for now extra_configs: - - CONFIG_ARM_MPU=n - - CONFIG_MODULES=y - - CONFIG_LLEXT_TEST_HELLO=m - # Broken platforms - platform_exclude: - - nuvoton_pfm_m487 # See #63167 - llext.simple.xtensa: - arch_allow: xtensa + - arch:arm:CONFIG_ARM_MPU=n + - CONFIG_LLEXT_STORAGE_WRITABLE=n + llext.simple.writable: extra_configs: + - arch:arm:CONFIG_ARM_MPU=n - CONFIG_LLEXT_STORAGE_WRITABLE=y + llext.simple.modules_enabled: + platform_key: + - simulation + platform_exclude: + - qemu_cortex_a9 # MMU + extra_configs: + - arch:arm:CONFIG_ARM_MPU=n - CONFIG_MODULES=y - CONFIG_LLEXT_TEST_HELLO=m - # Broken platforms - platform_exclude: - - qemu_xtensa_mmu # ELF sections are read-only, and without peek() .text copy isn't executable From 938d3547d0d83f0be458a305deabf410b8a19d49 Mon Sep 17 00:00:00 2001 From: Luca Burelli Date: Wed, 17 Jan 2024 12:57:59 +0100 Subject: [PATCH 2764/3723] llext: move current test to a hello_world subdir In preparation for multiple tests, move the current hello_world test to its own subdirectory. Also, merge the llext compilation in the parent CMakeLists.txt. Signed-off-by: Luca Burelli --- tests/subsys/llext/CMakeLists.txt | 26 ---------------- tests/subsys/llext/hello_world/CMakeLists.txt | 30 +++++++++++-------- tests/subsys/llext/{ => hello_world}/Kconfig | 0 tests/subsys/llext/{ => hello_world}/prj.conf | 0 .../hello_world/{ => src/llext}/hello_world.c | 0 .../src/test}/test_llext_simple.c | 0 .../llext/{ => hello_world}/testcase.yaml | 0 7 files changed, 18 insertions(+), 38 deletions(-) delete mode 100644 tests/subsys/llext/CMakeLists.txt rename tests/subsys/llext/{ => hello_world}/Kconfig (100%) rename tests/subsys/llext/{ => hello_world}/prj.conf (100%) rename tests/subsys/llext/hello_world/{ => src/llext}/hello_world.c (100%) rename tests/subsys/llext/{src => hello_world/src/test}/test_llext_simple.c (100%) rename tests/subsys/llext/{ => hello_world}/testcase.yaml (100%) diff --git a/tests/subsys/llext/CMakeLists.txt b/tests/subsys/llext/CMakeLists.txt deleted file mode 100644 index adb199761dd..00000000000 --- a/tests/subsys/llext/CMakeLists.txt +++ /dev/null @@ -1,26 +0,0 @@ -# Copyright (c) 2023 Intel Corporation. -# SPDX-License-Identifier: Apache-2.0 - -cmake_minimum_required(VERSION 3.20.0) -find_package(Zephyr REQUIRED HINTS $ENV{ZEPHYR_BASE}) -project(llext_test) - -add_subdirectory(hello_world) - -target_sources(app PRIVATE src/test_llext_simple.c) - -target_include_directories(app PRIVATE - ${ZEPHYR_BASE}/include - ${ZEPHYR_BASE}/kernel/include - ${ZEPHYR_BASE}/arch/${ARCH}/include - ) - -set(gen_dir ${ZEPHYR_BINARY_DIR}/include/generated/) - -generate_inc_file_for_target( - app - ${HELLO_WORLD_LLEXT} - ${gen_dir}/hello_world.inc - ) - -add_dependencies(app hello_world) diff --git a/tests/subsys/llext/hello_world/CMakeLists.txt b/tests/subsys/llext/hello_world/CMakeLists.txt index 4fd023801cb..2f107bd5346 100644 --- a/tests/subsys/llext/hello_world/CMakeLists.txt +++ b/tests/subsys/llext/hello_world/CMakeLists.txt @@ -3,20 +3,26 @@ cmake_minimum_required(VERSION 3.20.0) find_package(Zephyr REQUIRED HINTS $ENV{ZEPHYR_BASE}) -project(hello_world) +project(llext_hello_world_test) -if(NOT CONFIG_LLEXT_TEST_HELLO) - # test disabled, nothing to do -else() +target_sources(app PRIVATE + src/test/test_llext_simple.c +) - set(llext_src_file ${PROJECT_SOURCE_DIR}/hello_world.c) - set(llext_bin_file ${PROJECT_BINARY_DIR}/hello_world.llext) +target_include_directories(app PRIVATE + ${ZEPHYR_BASE}/include + ${ZEPHYR_BASE}/kernel/include + ${ZEPHYR_BASE}/arch/${ARCH}/include +) - add_llext_target(hello_world - OUTPUT ${llext_bin_file} - SOURCES ${llext_src_file} - ) +# Compile a simple hello world llext to an include file +set(llext_src_file ${PROJECT_SOURCE_DIR}/src/llext/hello_world.c) +set(llext_bin_file ${ZEPHYR_BINARY_DIR}/hello_world.llext) +set(llext_inc_file ${ZEPHYR_BINARY_DIR}/include/generated/hello_world.inc) - set(HELLO_WORLD_LLEXT ${llext_bin_file} PARENT_SCOPE) +add_llext_target(hello_world + OUTPUT ${llext_bin_file} + SOURCES ${llext_src_file} +) -endif() +generate_inc_file_for_target(app ${llext_bin_file} ${llext_inc_file}) diff --git a/tests/subsys/llext/Kconfig b/tests/subsys/llext/hello_world/Kconfig similarity index 100% rename from tests/subsys/llext/Kconfig rename to tests/subsys/llext/hello_world/Kconfig diff --git a/tests/subsys/llext/prj.conf b/tests/subsys/llext/hello_world/prj.conf similarity index 100% rename from tests/subsys/llext/prj.conf rename to tests/subsys/llext/hello_world/prj.conf diff --git a/tests/subsys/llext/hello_world/hello_world.c b/tests/subsys/llext/hello_world/src/llext/hello_world.c similarity index 100% rename from tests/subsys/llext/hello_world/hello_world.c rename to tests/subsys/llext/hello_world/src/llext/hello_world.c diff --git a/tests/subsys/llext/src/test_llext_simple.c b/tests/subsys/llext/hello_world/src/test/test_llext_simple.c similarity index 100% rename from tests/subsys/llext/src/test_llext_simple.c rename to tests/subsys/llext/hello_world/src/test/test_llext_simple.c diff --git a/tests/subsys/llext/testcase.yaml b/tests/subsys/llext/hello_world/testcase.yaml similarity index 100% rename from tests/subsys/llext/testcase.yaml rename to tests/subsys/llext/hello_world/testcase.yaml From 12bc02031e0cd5fc56f5ace1be3027b67a815074 Mon Sep 17 00:00:00 2001 From: Andriy Gelman Date: Mon, 22 Jan 2024 11:41:30 -0500 Subject: [PATCH 2765/3723] drivers: can_mcp251xfd: Fix setting data phase parameters Commit eeec09eb9ac4586fb36164a509c9dacddb7694c7 unintentionally modified can_calc_timing_data() to be called with the nominal phase parameters instead of the data phase parameters. Before the change, the parameters were properly initialized in the macro MCP251XFD_SET_TIMING_MACRO(inst, _data). After the commit, can_calc_timing_data() gets called with the parameters pointing to dev_cfg->common.sample_point instead of dev_cfg->commom.sample_point_data. This PR creates a separate function mcp251xfd_set_timing_data() which calls can_calc_timing_data with the correct data parameters. Signed-off-by: Andriy Gelman --- drivers/can/can_mcp251xfd.c | 50 ++++++++++++++++++++++++++++--------- 1 file changed, 38 insertions(+), 12 deletions(-) diff --git a/drivers/can/can_mcp251xfd.c b/drivers/can/can_mcp251xfd.c index 24e7c1bd9bf..490d660169a 100644 --- a/drivers/can/can_mcp251xfd.c +++ b/drivers/can/can_mcp251xfd.c @@ -1290,22 +1290,48 @@ static void mcp251xfd_tef_fifo_handler(const struct device *dev, void *data) k_sem_give(&dev_data->tx_sem); } +#if defined(CONFIG_CAN_FD_MODE) +static int mcp251xfd_init_timing_struct_data(struct can_timing *timing, + const struct device *dev, + const struct mcp251xfd_timing_params *timing_params) +{ + const struct mcp251xfd_config *dev_cfg = dev->config; + int ret; + + if (USE_SP_ALGO && dev_cfg->common.sample_point_data > 0) { + ret = can_calc_timing_data(dev, timing, dev_cfg->common.bus_speed_data, + dev_cfg->common.sample_point_data); + if (ret < 0) { + return ret; + } + LOG_DBG("Data phase Presc: %d, BS1: %d, BS2: %d", timing->prescaler, + timing->phase_seg1, timing->phase_seg2); + LOG_DBG("Data phase Sample-point err : %d", ret); + } else { + timing->sjw = timing_params->sjw; + timing->prop_seg = timing_params->prop_seg; + timing->phase_seg1 = timing_params->phase_seg1; + timing->phase_seg2 = timing_params->phase_seg2; + ret = can_calc_prescaler(dev, timing, dev_cfg->common.bus_speed_data); + if (ret > 0) { + LOG_WRN("Data phase Bitrate error: %d", ret); + } + } + + return ret; +} +#endif + static int mcp251xfd_init_timing_struct(struct can_timing *timing, const struct device *dev, - const struct mcp251xfd_timing_params *timing_params, - bool is_nominal) + const struct mcp251xfd_timing_params *timing_params) { const struct mcp251xfd_config *dev_cfg = dev->config; int ret; if (USE_SP_ALGO && dev_cfg->common.sample_point > 0) { - if (is_nominal) { - ret = can_calc_timing(dev, timing, dev_cfg->common.bus_speed, - dev_cfg->common.sample_point); - } else { - ret = can_calc_timing_data(dev, timing, dev_cfg->common.bus_speed, - dev_cfg->common.sample_point); - } + ret = can_calc_timing(dev, timing, dev_cfg->common.bus_speed, + dev_cfg->common.sample_point); if (ret < 0) { return ret; } @@ -1552,16 +1578,16 @@ static int mcp251xfd_init(const struct device *dev) goto done; } - ret = mcp251xfd_init_timing_struct(&timing, dev, &dev_cfg->timing_params, true); + ret = mcp251xfd_init_timing_struct(&timing, dev, &dev_cfg->timing_params); if (ret < 0) { LOG_ERR("Can't find timing for given param"); goto done; } #if defined(CONFIG_CAN_FD_MODE) - ret = mcp251xfd_init_timing_struct(&timing_data, dev, &dev_cfg->timing_params_data, false); + ret = mcp251xfd_init_timing_struct_data(&timing_data, dev, &dev_cfg->timing_params_data); if (ret < 0) { - LOG_ERR("Can't find timing for given param"); + LOG_ERR("Can't find data timing for given param"); goto done; } #endif From 8f0ae3b3a22bb14f3cb047f67014ccc70dc97aab Mon Sep 17 00:00:00 2001 From: Marius Scholtz Date: Mon, 18 Dec 2023 11:24:40 -0800 Subject: [PATCH 2766/3723] west.yml: update hal_atmel to include samx7x pa21 fix This update fixes a mistake in the pinctrl where pa21 was mapped to afe1_ad1 instead of afe0_1 as it ought to be. Signed-off-by: Marius Scholtz --- west.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/west.yml b/west.yml index ecc0d9943f2..71caf9c661b 100644 --- a/west.yml +++ b/west.yml @@ -147,7 +147,7 @@ manifest: groups: - hal - name: hal_atmel - revision: 942d664e48f7a2725933a93facc112b87b1de32b + revision: b0cc87f2a494d8b3c383292d1d6c7d10323932bd path: modules/hal/atmel groups: - hal From fcaed380cd1d9be4f461dd982b2ac9d4a63a4f66 Mon Sep 17 00:00:00 2001 From: Pieter De Gendt Date: Tue, 16 Jan 2024 19:16:23 +0100 Subject: [PATCH 2767/3723] cmake: Introduce ZEPHYR_CURRENT_MODULE_NAME Add a cmake variable for the current module's name. Signed-off-by: Pieter De Gendt --- CMakeLists.txt | 4 +++- cmake/modules/zephyr_module.cmake | 1 + 2 files changed, 4 insertions(+), 1 deletion(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 76d8466b8df..ff12e0852ec 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -581,12 +581,14 @@ foreach(module_name ${ZEPHYR_MODULE_NAMES}) # https://cmake.org/pipermail/cmake/2019-June/069547.html zephyr_string(SANITIZE TOUPPER MODULE_NAME_UPPER ${module_name}) if(NOT ${ZEPHYR_${MODULE_NAME_UPPER}_CMAKE_DIR} STREQUAL "") + set(ZEPHYR_CURRENT_MODULE_NAME ${ZEPHYR_${MODULE_NAME_UPPER}_MODULE_NAME}) set(ZEPHYR_CURRENT_MODULE_DIR ${ZEPHYR_${MODULE_NAME_UPPER}_MODULE_DIR}) set(ZEPHYR_CURRENT_CMAKE_DIR ${ZEPHYR_${MODULE_NAME_UPPER}_CMAKE_DIR}) add_subdirectory(${ZEPHYR_CURRENT_CMAKE_DIR} ${CMAKE_BINARY_DIR}/modules/${module_name}) endif() endforeach() -# Done processing modules, clear ZEPHYR_CURRENT_MODULE_DIR and ZEPHYR_CURRENT_CMAKE_DIR. +# Done processing modules, clear module variables +set(ZEPHYR_CURRENT_MODULE_NAME) set(ZEPHYR_CURRENT_MODULE_DIR) set(ZEPHYR_CURRENT_CMAKE_DIR) diff --git a/cmake/modules/zephyr_module.cmake b/cmake/modules/zephyr_module.cmake index 50ee05dfe25..191c71c193b 100644 --- a/cmake/modules/zephyr_module.cmake +++ b/cmake/modules/zephyr_module.cmake @@ -137,6 +137,7 @@ if(WEST OR ZEPHYR_MODULES) zephyr_string(SANITIZE TOUPPER MODULE_NAME_UPPER ${module_name}) if(NOT ${MODULE_NAME_UPPER} STREQUAL CURRENT) + set(ZEPHYR_${MODULE_NAME_UPPER}_MODULE_NAME ${module_name}) set(ZEPHYR_${MODULE_NAME_UPPER}_MODULE_DIR ${module_path}) set(ZEPHYR_${MODULE_NAME_UPPER}_CMAKE_DIR ${cmake_path}) else() From b0150d3ac3733f294be7f5262e763fa6283ff5dd Mon Sep 17 00:00:00 2001 From: Pieter De Gendt Date: Mon, 15 Jan 2024 10:59:15 +0100 Subject: [PATCH 2768/3723] cmake: modules: extensions: Add function to verify binary blobs Add a cmake helper function to verify if blobs have a valid checksum. Signed-off-by: Pieter De Gendt --- cmake/modules/extensions.cmake | 67 ++++++++++++++++++++++++++++++++++ 1 file changed, 67 insertions(+) diff --git a/cmake/modules/extensions.cmake b/cmake/modules/extensions.cmake index 594d8104a3b..f3d0dd5e53f 100644 --- a/cmake/modules/extensions.cmake +++ b/cmake/modules/extensions.cmake @@ -1566,6 +1566,73 @@ function(zephyr_syscall_header_ifdef feature_toggle) endif() endfunction() +# Verify blobs fetched using west. If the sha256 checksum isn't valid, a warning/ +# fatal error message is printed (depends on REQUIRED flag). +# +# Usage: +# zephyr_blobs_verify( [REQUIRED]) +# +# Example: +# zephyr_blobs_verify(MODULE my_module REQUIRED) # verify all blobs in my_module and fail on error +# zephyr_blobs_verify(FILES img/file.bin) # verify a single file and print on error +function(zephyr_blobs_verify) + cmake_parse_arguments(BLOBS_VERIFY "REQUIRED" "MODULE" "FILES" ${ARGN}) + + if((DEFINED BLOBS_VERIFY_MODULE) EQUAL (DEFINED BLOBS_VERIFY_FILES)) + message(FATAL_ERROR "Either MODULE or FILES required when calling ${CMAKE_CURRENT_FUNCTION}") + endif() + + if(NOT WEST) + return() + endif() + + execute_process( + COMMAND ${WEST} blobs list ${BLOBS_VERIFY_MODULE} --format "{status} {abspath}" + OUTPUT_VARIABLE BLOBS_LIST_OUTPUT + OUTPUT_STRIP_TRAILING_WHITESPACE + COMMAND_ERROR_IS_FATAL ANY + ) + + if(${BLOBS_VERIFY_REQUIRED}) + set(msg_lvl FATAL_ERROR) + else() + set(msg_lvl WARNING) + endif() + + string(REPLACE "\n" ";" BLOBS_LIST ${BLOBS_LIST_OUTPUT}) + + if(DEFINED BLOBS_VERIFY_FILES) + foreach(file ${BLOBS_VERIFY_FILES}) + # Resolve path. + if(IS_ABSOLUTE ${file}) + file(REAL_PATH "${file}" real_path) + else() + file(REAL_PATH "${CMAKE_CURRENT_SOURCE_DIR}/${file}" real_path) + endif() + file(TO_NATIVE_PATH ${real_path} path) + + message(VERBOSE "Verifying blob \"${path}\"") + + # Each path that has a correct sha256 is prefixed with an A + if(NOT "A ${path}" IN_LIST BLOBS_LIST) + message(${msg_lvl} "Blob for path \"${path}\" isn't valid.") + endif() + endforeach() + else() + foreach(blob ${BLOBS_LIST}) + separate_arguments(blob) + list(GET blob 0 status) + list(GET blob 1 path) + + message(VERBOSE "Verifying blob \"${path}\"") + + if(NOT "${status}" STREQUAL "A") + message(${msg_lvl} "Blob for path \"${path}\" isn't valid. Update with: west blobs fetch ${BLOBS_VERIFY_MODULE}") + endif() + endforeach() + endif() +endfunction() + ######################################################## # 2. Kconfig-aware extensions ######################################################## From 71d8213ef996a6a72510e3b053675549a41a85f7 Mon Sep 17 00:00:00 2001 From: Pieter De Gendt Date: Wed, 17 Jan 2024 11:09:50 +0100 Subject: [PATCH 2769/3723] doc: develop: modules: Add entry for ZEPHYR_CURRENT_MODULE_NAME A new cmake variable is added for zephyr modules, namely `${ZEPHYR_CURRENT_MODULE_NAME}`. Add it to the documentation. Signed-off-by: Pieter De Gendt --- doc/develop/modules.rst | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/doc/develop/modules.rst b/doc/develop/modules.rst index 42d10c32e98..875f6f62ff1 100644 --- a/doc/develop/modules.rst +++ b/doc/develop/modules.rst @@ -611,9 +611,10 @@ For example, to include the file :file:`some/Kconfig` in module ``foo``: source "$(ZEPHYR_FOO_MODULE_DIR)/some/Kconfig" -During CMake processing of each Zephyr module, the following two variables are +During CMake processing of each Zephyr module, the following variables are also available: +- the current module's name: ``${ZEPHYR_CURRENT_MODULE_NAME}`` - the current module's top level directory: ``${ZEPHYR_CURRENT_MODULE_DIR}`` - the current module's :file:`CMakeLists.txt` directory: ``${ZEPHYR_CURRENT_CMAKE_DIR}`` From a03c1ace6bc5773861c173ad03eb09408e75b0b1 Mon Sep 17 00:00:00 2001 From: Sateesh Kotapati Date: Fri, 19 Jan 2024 15:21:57 +0530 Subject: [PATCH 2770/3723] gecko: service files updated | Update to GSDK 4.4.0 Updated the files present in device_init, hfxo_manager, power_manager and sleeptimer folder as per latest version of gecko_sdk. Added SL_DEVICE_INIT_HFXO_PRECISION in sl_device_init_hfxo_config. Signed-off-by: Sateesh Kotapati --- dts/arm/silabs/efr32bg2x.dtsi | 1 + dts/arm/silabs/efr32mg24.dtsi | 1 + dts/bindings/clock/silabs,hfxo.yaml | 4 ++++ soc/arm/silabs_exx32/common/sl_device_init_hfxo_config.h | 1 + west.yml | 2 +- 5 files changed, 8 insertions(+), 1 deletion(-) diff --git a/dts/arm/silabs/efr32bg2x.dtsi b/dts/arm/silabs/efr32bg2x.dtsi index 2f50f1bcbda..70df9708d11 100644 --- a/dts/arm/silabs/efr32bg2x.dtsi +++ b/dts/arm/silabs/efr32bg2x.dtsi @@ -23,6 +23,7 @@ compatible = "silabs,hfxo"; clock-frequency = ; ctune = <120>; + precision = <50>; }; }; diff --git a/dts/arm/silabs/efr32mg24.dtsi b/dts/arm/silabs/efr32mg24.dtsi index b42b775397f..860cedddeda 100644 --- a/dts/arm/silabs/efr32mg24.dtsi +++ b/dts/arm/silabs/efr32mg24.dtsi @@ -24,6 +24,7 @@ compatible = "silabs,hfxo"; clock-frequency = ; ctune = <140>; + precision = <50>; }; }; diff --git a/dts/bindings/clock/silabs,hfxo.yaml b/dts/bindings/clock/silabs,hfxo.yaml index cd0d3ad1742..a5d0fdeff95 100644 --- a/dts/bindings/clock/silabs,hfxo.yaml +++ b/dts/bindings/clock/silabs,hfxo.yaml @@ -7,3 +7,7 @@ properties: type: int required: true description: Load capacitance configuration + precision: + type: int + required: true + description: Precision configuration diff --git a/soc/arm/silabs_exx32/common/sl_device_init_hfxo_config.h b/soc/arm/silabs_exx32/common/sl_device_init_hfxo_config.h index 533a591fbde..14a59b29612 100644 --- a/soc/arm/silabs_exx32/common/sl_device_init_hfxo_config.h +++ b/soc/arm/silabs_exx32/common/sl_device_init_hfxo_config.h @@ -12,5 +12,6 @@ #define SL_DEVICE_INIT_HFXO_MODE cmuHfxoOscMode_Crystal #define SL_DEVICE_INIT_HFXO_FREQ DT_PROP(DT_NODELABEL(clk_hfxo), clock_frequency) #define SL_DEVICE_INIT_HFXO_CTUNE DT_PROP(DT_NODELABEL(clk_hfxo), ctune) +#define SL_DEVICE_INIT_HFXO_PRECISION DT_PROP(DT_NODELABEL(clk_hfxo), precision) #endif /* SL_DEVICE_INIT_HFXO_CONFIG_H */ diff --git a/west.yml b/west.yml index 71caf9c661b..0a158a972b8 100644 --- a/west.yml +++ b/west.yml @@ -219,7 +219,7 @@ manifest: groups: - hal - name: hal_silabs - revision: 11ab59175a5ded618680a7692dbaae8f4fbd6325 + revision: 2ea874714edf5ce76b7b5fd19e7fa83507e83cc2 path: modules/hal/silabs groups: - hal From f2bafa4844fe9acbd1ee9dd107cb9eb269343136 Mon Sep 17 00:00:00 2001 From: Erwan Gouriou Date: Wed, 17 Jan 2024 12:03:02 +0100 Subject: [PATCH 2771/3723] boards: nucleo_wba55cg: Document BLE support and blobs fetching In order to build a BLE application nucleo_wba55cg fecthing controller blobs is required. Document the command. Signed-off-by: Erwan Gouriou --- boards/arm/nucleo_wba55cg/doc/nucleo_wba55cg.rst | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/boards/arm/nucleo_wba55cg/doc/nucleo_wba55cg.rst b/boards/arm/nucleo_wba55cg/doc/nucleo_wba55cg.rst index f4d170040bf..2ea660da1f1 100644 --- a/boards/arm/nucleo_wba55cg/doc/nucleo_wba55cg.rst +++ b/boards/arm/nucleo_wba55cg/doc/nucleo_wba55cg.rst @@ -175,12 +175,27 @@ The Zephyr nucleo_wba55cg board configuration supports the following hardware fe +-----------+------------+-------------------------------------+ | RNG | on-chip | True Random number generator | +-----------+------------+-------------------------------------+ +| RADIO | on-chip | Bluetooth Low Energy | ++-----------+------------+-------------------------------------+ Other hardware features are not yet supported on this Zephyr port. The default configuration can be found in the defconfig file: ``boards/arm/nucleo_wba55cg/nucleo_wba55cg_defconfig`` +Bluetooh support +---------------- + +BLE support is enabled on nucleo_wba55cg. To build a zephyr sample using this board +you first need to install Bluetooth Controller libraries available in Zephyr as binary +blobs. + +To fetch Binary Blobs: + +.. code-block:: console + + west blobs fetch stm32 + Connections and IOs =================== From 7e5c260708e3a9e6c21bca21823559ae41658509 Mon Sep 17 00:00:00 2001 From: Cong Nguyen Huu Date: Tue, 23 Jan 2024 14:04:57 +0700 Subject: [PATCH 2772/3723] drivers: nxp_s32_canxl: remove support CAN FD mode for non-RX_FIFO This is driver limitation after removing CAN_FILTER_FDF flag #65108. CANXL driver need to know CAN_FILTER_FDF for configuring Rx filter so that it receives CAN classic or CAN FD frames when using non RX_FIFO. So update driver that just supports CAN classic for non RX_FIFO. Signed-off-by: Cong Nguyen Huu --- drivers/can/can_nxp_s32_canxl.c | 30 ++++++++++++++++-------------- 1 file changed, 16 insertions(+), 14 deletions(-) diff --git a/drivers/can/can_nxp_s32_canxl.c b/drivers/can/can_nxp_s32_canxl.c index bd5e19ce7bd..f214b3924eb 100644 --- a/drivers/can/can_nxp_s32_canxl.c +++ b/drivers/can/can_nxp_s32_canxl.c @@ -50,6 +50,10 @@ #define CAN_NXP_S32_RX_FIFO_WATERMARK 1 #endif +#if defined(CONFIG_CAN_FD_MODE) && defined(CONFIG_CAN_NXP_S32_RX_FIFO) +#define CAN_NXP_S32_FD_MODE 1 +#endif + LOG_MODULE_REGISTER(nxp_s32_canxl, CONFIG_CAN_LOG_LEVEL); #define SP_AND_TIMING_NOT_SET(inst) \ @@ -62,7 +66,7 @@ LOG_MODULE_REGISTER(nxp_s32_canxl, CONFIG_CAN_LOG_LEVEL); #error You must either set a sampling-point or timings (phase-seg* and prop-seg) #endif -#ifdef CONFIG_CAN_FD_MODE +#ifdef CAN_NXP_S32_FD_MODE #define SP_AND_TIMING_DATA_NOT_SET(inst) \ (!DT_INST_NODE_HAS_PROP(inst, sample_point_data) && \ @@ -91,7 +95,7 @@ struct can_nxp_s32_config { uint32_t prop_seg; uint32_t phase_seg1; uint32_t phase_seg2; -#ifdef CONFIG_CAN_FD_MODE +#ifdef CAN_NXP_S32_FD_MODE uint32_t sjw_data; uint32_t prop_seg_data; uint32_t phase_seg1_data; @@ -140,7 +144,7 @@ struct can_nxp_s32_data { #endif struct can_timing timing; -#ifdef CONFIG_CAN_FD_MODE +#ifdef CAN_NXP_S32_FD_MODE struct can_timing timing_data; #endif enum can_state state; @@ -152,7 +156,7 @@ static int can_nxp_s32_get_capabilities(const struct device *dev, can_mode_t *ca *cap = CAN_MODE_NORMAL | CAN_MODE_LOOPBACK | CAN_MODE_LISTENONLY; -#if CONFIG_CAN_FD_MODE +#ifdef CAN_NXP_S32_FD_MODE *cap |= CAN_MODE_FD; #endif @@ -309,7 +313,7 @@ static int can_nxp_s32_set_mode(const struct device *dev, can_mode_t mode) if (data->common.started) { return -EBUSY; } -#ifdef CONFIG_CAN_FD_MODE +#ifdef CAN_NXP_S32_FD_MODE if ((mode & ~(CAN_MODE_LOOPBACK | CAN_MODE_LISTENONLY | CAN_MODE_FD)) != 0) { #else if ((mode & ~(CAN_MODE_LOOPBACK | CAN_MODE_LISTENONLY)) != 0) { @@ -589,7 +593,7 @@ static int can_nxp_s32_send(const struct device *dev, __ASSERT_NO_MSG(callback != NULL); -#ifdef CONFIG_CAN_FD_MODE +#ifdef CAN_NXP_S32_FD_MODE if ((frame->flags & ~(CAN_FRAME_IDE | CAN_FRAME_FDF | CAN_FRAME_BRS)) != 0) { LOG_ERR("unsupported CAN frame flags 0x%02x", frame->flags); return -ENOTSUP; @@ -624,7 +628,7 @@ static int can_nxp_s32_send(const struct device *dev, LOG_ERR("DLC of %d for non-FD format frame", frame->dlc); return -EINVAL; } -#ifdef CONFIG_CAN_FD_MODE +#ifdef CAN_NXP_S32_FD_MODE } else { if (frame->dlc > CANFD_MAX_DLC) { LOG_ERR("DLC of %d for CAN FD format frame", frame->dlc); @@ -725,7 +729,7 @@ static int can_nxp_s32_set_timing(const struct device *dev, return 0; } -#ifdef CONFIG_CAN_FD_MODE +#ifdef CAN_NXP_S32_FD_MODE static int can_nxp_s32_set_timing_data(const struct device *dev, const struct can_timing *timing_data) { @@ -991,7 +995,7 @@ static int can_nxp_s32_init(const struct device *dev) LOG_DBG("Setting CAN bitrate %d:", config->common.bus_speed); nxp_s32_zcan_timing_to_canxl_timing(&data->timing, &config->can_cfg->bitrate); -#ifdef CONFIG_CAN_FD_MODE +#ifdef CAN_NXP_S32_FD_MODE data->timing_data.sjw = config->sjw_data; if (config->common.sample_point_data) { err = can_calc_timing_data(dev, &data->timing_data, config->common.bus_speed_data, @@ -1093,7 +1097,7 @@ static const struct can_driver_api can_nxp_s32_driver_api = { .phase_seg2 = 0x08, .prescaler = 0x100 }, -#ifdef CONFIG_CAN_FD_MODE +#ifdef CAN_NXP_S32_FD_MODE .set_timing_data = can_nxp_s32_set_timing_data, .timing_data_min = { .sjw = 0x01, @@ -1145,17 +1149,15 @@ static const struct can_driver_api can_nxp_s32_driver_api = { can_nxp_s32_ctrl_callback(dev, eventType, buffIdx, canexcelState); \ } -#if defined(CONFIG_CAN_FD_MODE) +#if defined(CAN_NXP_S32_FD_MODE) #define CAN_NXP_S32_TIMING_DATA_CONFIG(n) \ .sjw_data = DT_INST_PROP(n, sjw_data), \ .prop_seg_data = DT_INST_PROP_OR(n, prop_seg_data, 0), \ .phase_seg1_data = DT_INST_PROP_OR(n, phase_seg1_data, 0), \ .phase_seg2_data = DT_INST_PROP_OR(n, phase_seg2_data, 0), -#define CAN_NXP_S32_FD_MODE 1 #define CAN_NXP_S32_BRS 1 #else #define CAN_NXP_S32_TIMING_DATA_CONFIG(n) -#define CAN_NXP_S32_FD_MODE 0 #define CAN_NXP_S32_BRS 0 #endif @@ -1190,7 +1192,7 @@ static const struct can_driver_api can_nxp_s32_driver_api = { 0 : CONFIG_CAN_NXP_S32_MAX_RX, \ .tx_mbdesc = (uint8)CONFIG_CAN_NXP_S32_MAX_TX, \ .CanxlMode = CANEXCEL_LISTEN_ONLY_MODE, \ - .fd_enable = (boolean)CAN_NXP_S32_FD_MODE, \ + .fd_enable = (boolean)IS_ENABLED(CAN_NXP_S32_FD_MODE), \ .bitRateSwitch = (boolean)CAN_NXP_S32_BRS, \ .ctrlOptions = (uint32)CAN_NXP_S32_CTRL_OPTIONS, \ .Callback = nxp_s32_can_##n##_ctrl_callback, \ From cc9d0d1c124b77dfb33f781cd83c9de52d5e3627 Mon Sep 17 00:00:00 2001 From: Cong Nguyen Huu Date: Thu, 18 Jan 2024 10:11:11 +0700 Subject: [PATCH 2773/3723] tests: drivers: can: api: add testcase for testing CANXL non RX FIFO Add testcase for testing CANXL non RX FIFO Signed-off-by: Cong Nguyen Huu --- tests/drivers/can/api/testcase.yaml | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/tests/drivers/can/api/testcase.yaml b/tests/drivers/can/api/testcase.yaml index 11c72526a89..cd2211e0bb9 100644 --- a/tests/drivers/can/api/testcase.yaml +++ b/tests/drivers/can/api/testcase.yaml @@ -20,3 +20,7 @@ tests: - esp32s2_saola - esp32s3_devkitm - xiao_esp32s3 + drivers.can.api.nxp_s32_canxl.non_rx_fifo: + extra_configs: + - CONFIG_CAN_NXP_S32_RX_FIFO=n + filter: dt_compat_enabled("nxp,s32-canxl") From 97f8ce83ef24deee0438a82af9d4af41c2e701bc Mon Sep 17 00:00:00 2001 From: Cong Nguyen Huu Date: Thu, 18 Jan 2024 15:33:17 +0700 Subject: [PATCH 2774/3723] tests: drivers: can: api: wrap the code belong to CAN FD mode To avoid build warnings when building non CAN FD mode Signed-off-by: Cong Nguyen Huu --- tests/drivers/can/api/src/common.c | 2 ++ tests/drivers/can/api/src/common.h | 2 ++ tests/drivers/can/api/src/utilities.c | 2 ++ 3 files changed, 6 insertions(+) diff --git a/tests/drivers/can/api/src/common.c b/tests/drivers/can/api/src/common.c index b38090690a3..22c2bce192d 100644 --- a/tests/drivers/can/api/src/common.c +++ b/tests/drivers/can/api/src/common.c @@ -80,6 +80,7 @@ const struct can_frame test_ext_rtr_frame_1 = { .data = {0} }; +#ifdef CONFIG_CAN_FD_MODE /** * @brief Standard (11-bit) CAN ID frame 1 with CAN FD payload. */ @@ -107,6 +108,7 @@ const struct can_frame test_std_fdf_frame_2 = { 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, 64 } }; +#endif /* CONFIG_CAN_FD_MODE */ /** * @brief Standard (11-bit) CAN ID filter 1. This filter matches diff --git a/tests/drivers/can/api/src/common.h b/tests/drivers/can/api/src/common.h index af192f574c5..ff328d156a0 100644 --- a/tests/drivers/can/api/src/common.h +++ b/tests/drivers/can/api/src/common.h @@ -86,6 +86,7 @@ extern const struct can_frame test_std_rtr_frame_1; */ extern const struct can_frame test_ext_rtr_frame_1; +#ifdef CONFIG_CAN_FD_MODE /** * @brief Standard (11-bit) CAN ID frame 1 with CAN FD payload. */ @@ -95,6 +96,7 @@ extern const struct can_frame test_std_fdf_frame_1; * @brief Standard (11-bit) CAN ID frame 2 with CAN FD payload. */ extern const struct can_frame test_std_fdf_frame_2; +#endif /* CONFIG_CAN_FD_MODE */ /** * @brief Standard (11-bit) CAN ID filter 1. This filter matches diff --git a/tests/drivers/can/api/src/utilities.c b/tests/drivers/can/api/src/utilities.c index 5fd251f5968..678f593b018 100644 --- a/tests/drivers/can/api/src/utilities.c +++ b/tests/drivers/can/api/src/utilities.c @@ -109,9 +109,11 @@ ZTEST(can_utilities, test_can_frame_matches_filter) zassert_true(can_frame_matches_filter(&test_std_rtr_frame_1, &test_std_filter_1)); zassert_true(can_frame_matches_filter(&test_ext_rtr_frame_1, &test_ext_filter_1)); +#ifdef CONFIG_CAN_FD_MODE /* CAN FD format frames and filters */ zassert_true(can_frame_matches_filter(&test_std_fdf_frame_1, &test_std_filter_1)); zassert_true(can_frame_matches_filter(&test_std_fdf_frame_2, &test_std_filter_2)); +#endif /* CONFIG_CAN_FD_MODE */ } ZTEST_SUITE(can_utilities, NULL, NULL, NULL, NULL, NULL); From e832a87e1c9bb2f98590409840aceefcdae16ecd Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Gerhard=20J=C3=B6rges?= Date: Tue, 23 Jan 2024 09:50:52 +0100 Subject: [PATCH 2775/3723] include: usb: include usb_ch9.h MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit In usb_hid.h `struct usb_setup_packet` is used. This is defined in usb_ch9.h but not included in usb_hid.h which leads to build errors when you include the usb header files in the wrong order. This commit fixes this behaviour. Signed-off-by: Gerhard Jörges --- include/zephyr/usb/class/usb_hid.h | 1 + 1 file changed, 1 insertion(+) diff --git a/include/zephyr/usb/class/usb_hid.h b/include/zephyr/usb/class/usb_hid.h index 8cc21e7a573..8fc380b970e 100644 --- a/include/zephyr/usb/class/usb_hid.h +++ b/include/zephyr/usb/class/usb_hid.h @@ -14,6 +14,7 @@ #define ZEPHYR_INCLUDE_USB_HID_CLASS_DEVICE_H_ #include +#include #ifdef __cplusplus extern "C" { From 92ed610cd283b6d1a46172000d5ee8c7eecacf62 Mon Sep 17 00:00:00 2001 From: Dominik Ermel Date: Fri, 17 Nov 2023 14:02:09 +0000 Subject: [PATCH 2776/3723] west.yaml: Update LittleFS to version 2.8.1 from upstream The commit shifts sha of Zephyr LittleFS fork to revision that includes merge of tag v2.8.1 from upstream: https://github.com/littlefs-project/littlefs/releases/tag/v2.8.1 Signed-off-by: Dominik Ermel --- west.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/west.yml b/west.yml index 0a158a972b8..b07c73568ea 100644 --- a/west.yml +++ b/west.yml @@ -269,7 +269,7 @@ manifest: path: modules/fs/littlefs groups: - fs - revision: ca583fd297ceb48bced3c2548600dc615d67af24 + revision: 408c16a909dd6cf128874a76f21c793798c9e423 - name: loramac-node revision: 842413c5fb98707eb5f26e619e8e792453877897 path: modules/lib/loramac-node From 14839e80d5e45e12bb81088e24295a542b4ee584 Mon Sep 17 00:00:00 2001 From: Guillaume Gautier Date: Wed, 27 Sep 2023 11:05:40 +0200 Subject: [PATCH 2777/3723] drivers: adc: stm32: add support for two sampling time common channels For series that have two sampling time common channels, only one was used. This commit add the support for the second one. The first two different acquisition time values are used for the sequence and all further values must match either of them, otherwise generating an error. Signed-off-by: Guillaume Gautier --- drivers/adc/adc_stm32.c | 117 +++++++++++++++++++++++----------------- 1 file changed, 68 insertions(+), 49 deletions(-) diff --git a/drivers/adc/adc_stm32.c b/drivers/adc/adc_stm32.c index d55e851ec7c..0b8a1415535 100644 --- a/drivers/adc/adc_stm32.c +++ b/drivers/adc/adc_stm32.c @@ -190,7 +190,7 @@ struct adc_stm32_data { uint32_t channels; uint8_t channel_count; uint8_t samples_count; - int8_t acq_time_index; + int8_t acq_time_index[2]; #ifdef CONFIG_ADC_STM32_DMA volatile int dma_error; @@ -1081,7 +1081,8 @@ static void adc_context_on_complete(struct adc_context *ctx, int status) adc_stm32_disable(adc); /* Reset acquisition time used for the sequence */ - data->acq_time_index = -1; + data->acq_time_index[0] = -1; + data->acq_time_index[1] = -1; #if defined(CONFIG_SOC_SERIES_STM32H7X) || defined(CONFIG_SOC_SERIES_STM32U5X) /* Reset channel preselection register */ @@ -1120,7 +1121,7 @@ static int adc_stm32_read_async(const struct device *dev, } #endif -static int adc_stm32_check_acq_time(const struct device *dev, uint16_t acq_time) +static int adc_stm32_sampling_time_check(const struct device *dev, uint16_t acq_time) { const struct adc_stm32_cfg *config = (const struct adc_stm32_cfg *)dev->config; @@ -1140,16 +1141,24 @@ static int adc_stm32_check_acq_time(const struct device *dev, uint16_t acq_time) } } - LOG_ERR("Conversion time not supported."); + LOG_ERR("Sampling time value not supported."); return -EINVAL; } -static int adc_stm32_setup_speed(const struct device *dev, uint8_t id, - uint8_t acq_time_index) +static int adc_stm32_sampling_time_setup(const struct device *dev, uint8_t id, + uint16_t acq_time) { const struct adc_stm32_cfg *config = (const struct adc_stm32_cfg *)dev->config; ADC_TypeDef *adc = config->base; + struct adc_stm32_data *data = dev->data; + + int acq_time_index; + + acq_time_index = adc_stm32_sampling_time_check(dev, acq_time); + if (acq_time_index < 0) { + return acq_time_index; + } /* * For all series we use the fact that the macros LL_ADC_SAMPLINGTIME_* @@ -1160,25 +1169,60 @@ static int adc_stm32_setup_speed(const struct device *dev, uint8_t id, switch (config->num_sampling_time_common_channels) { case 0: #if ANY_NUM_COMMON_SAMPLING_TIME_CHANNELS_IS(0) + ARG_UNUSED(data); LL_ADC_SetChannelSamplingTime(adc, - __LL_ADC_DECIMAL_NB_TO_CHANNEL(id), - acq_time_index); + __LL_ADC_DECIMAL_NB_TO_CHANNEL(id), + (uint32_t)acq_time_index); #endif break; case 1: #if ANY_NUM_COMMON_SAMPLING_TIME_CHANNELS_IS(1) - LL_ADC_SetSamplingTimeCommonChannels(adc, - acq_time_index); + /* Only one sampling time can be selected for all channels. + * The first one we find is used, all others must match. + */ + if ((data->acq_time_index[0] == -1) || + (acq_time_index == data->acq_time_index[0])) { + /* Reg is empty or value matches */ + data->acq_time_index[0] = acq_time_index; + LL_ADC_SetSamplingTimeCommonChannels(adc, + (uint32_t)acq_time_index); + } else { + /* Reg is used and value does not match */ + LOG_ERR("Multiple sampling times not supported"); + return -EINVAL; + } #endif break; case 2: #if ANY_NUM_COMMON_SAMPLING_TIME_CHANNELS_IS(2) - LL_ADC_SetChannelSamplingTime(adc, - __LL_ADC_DECIMAL_NB_TO_CHANNEL(id), - LL_ADC_SAMPLINGTIME_COMMON_1); - LL_ADC_SetSamplingTimeCommonChannels(adc, - LL_ADC_SAMPLINGTIME_COMMON_1, - acq_time_index); + /* Two different sampling times can be selected for all channels. + * The first two we find are used, all others must match either one. + */ + if ((data->acq_time_index[0] == -1) || + (acq_time_index == data->acq_time_index[0])) { + /* 1st reg is empty or value matches 1st reg */ + data->acq_time_index[0] = acq_time_index; + LL_ADC_SetChannelSamplingTime(adc, + __LL_ADC_DECIMAL_NB_TO_CHANNEL(id), + LL_ADC_SAMPLINGTIME_COMMON_1); + LL_ADC_SetSamplingTimeCommonChannels(adc, + LL_ADC_SAMPLINGTIME_COMMON_1, + (uint32_t)acq_time_index); + } else if ((data->acq_time_index[1] == -1) || + (acq_time_index == data->acq_time_index[1])) { + /* 2nd reg is empty or value matches 2nd reg */ + data->acq_time_index[1] = acq_time_index; + LL_ADC_SetChannelSamplingTime(adc, + __LL_ADC_DECIMAL_NB_TO_CHANNEL(id), + LL_ADC_SAMPLINGTIME_COMMON_2); + LL_ADC_SetSamplingTimeCommonChannels(adc, + LL_ADC_SAMPLINGTIME_COMMON_2, + (uint32_t)acq_time_index); + } else { + /* Both regs are used, value does not match any of them */ + LOG_ERR("Only two different sampling times supported"); + return -EINVAL; + } #endif break; default: @@ -1191,32 +1235,6 @@ static int adc_stm32_setup_speed(const struct device *dev, uint8_t id, static int adc_stm32_channel_setup(const struct device *dev, const struct adc_channel_cfg *channel_cfg) { - const struct adc_stm32_cfg *config = - (const struct adc_stm32_cfg *)dev->config; - - struct adc_stm32_data *data = dev->data; - int acq_time_index; - - acq_time_index = adc_stm32_check_acq_time(dev, - channel_cfg->acquisition_time); - if (acq_time_index < 0) { - return acq_time_index; - } - if (config->num_sampling_time_common_channels) { - if (data->acq_time_index == -1) { - data->acq_time_index = acq_time_index; - } else { - /* - * All families that use common channel must have - * identical acquisition time. - */ - if (acq_time_index != data->acq_time_index) { - LOG_ERR("Multiple sampling times not supported"); - return -EINVAL; - } - } - } - if (channel_cfg->differential) { LOG_ERR("Differential channels are not supported"); return -EINVAL; @@ -1232,8 +1250,8 @@ static int adc_stm32_channel_setup(const struct device *dev, return -EINVAL; } - if (adc_stm32_setup_speed(dev, channel_cfg->channel_id, - acq_time_index) != 0) { + if (adc_stm32_sampling_time_setup(dev, channel_cfg->channel_id, + channel_cfg->acquisition_time) != 0) { LOG_ERR("Invalid sampling time"); return -EINVAL; } @@ -1320,12 +1338,13 @@ static int adc_stm32_init(const struct device *dev) * For series that use common channels for sampling time, all * conversion time for all channels on one ADC instance has to * be the same. - * For series that use two common channels, currently only one - * of the two available common channel conversion times is used. - * This additional variable is for checking if the conversion time - * selection of all channels on one ADC instance is the same. + * For series that use two common channels, there can be up to two + * conversion times selected for all channels in a sequence. + * This additional table is for checking that the conversion time + * selection of all channels respects these requirements. */ - data->acq_time_index = -1; + data->acq_time_index[0] = -1; + data->acq_time_index[1] = -1; adc_stm32_set_clock(dev); From 7228642c724a6164a7ce1cdd7a82c3ccc1eb412c Mon Sep 17 00:00:00 2001 From: Guillaume Gautier Date: Fri, 5 Jan 2024 10:34:37 +0100 Subject: [PATCH 2778/3723] tests: drivers: adc: adc_api: boards: st: use different acquisition time Use different acquisition time for a board (WB55) that has individual sampling register, and for another (WBA52) that have two common registers. Signed-off-by: Guillaume Gautier --- tests/drivers/adc/adc_api/boards/nucleo_wb55rg.overlay | 3 ++- tests/drivers/adc/adc_api/boards/nucleo_wba52cg.overlay | 3 ++- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/tests/drivers/adc/adc_api/boards/nucleo_wb55rg.overlay b/tests/drivers/adc/adc_api/boards/nucleo_wb55rg.overlay index 82f3300458c..d88a1e3d08c 100644 --- a/tests/drivers/adc/adc_api/boards/nucleo_wb55rg.overlay +++ b/tests/drivers/adc/adc_api/boards/nucleo_wb55rg.overlay @@ -28,7 +28,8 @@ reg = <4>; zephyr,gain = "ADC_GAIN_1"; zephyr,reference = "ADC_REF_INTERNAL"; - zephyr,acquisition-time = ; + /* Use a different acquisition time for test purposes */ + zephyr,acquisition-time = ; zephyr,resolution = <12>; }; }; diff --git a/tests/drivers/adc/adc_api/boards/nucleo_wba52cg.overlay b/tests/drivers/adc/adc_api/boards/nucleo_wba52cg.overlay index ae2f4afc58c..fa018756494 100644 --- a/tests/drivers/adc/adc_api/boards/nucleo_wba52cg.overlay +++ b/tests/drivers/adc/adc_api/boards/nucleo_wba52cg.overlay @@ -28,7 +28,8 @@ reg = <8>; zephyr,gain = "ADC_GAIN_1"; zephyr,reference = "ADC_REF_INTERNAL"; - zephyr,acquisition-time = ; + /* Use a different acquisition time for test purposes */ + zephyr,acquisition-time = ; zephyr,resolution = <12>; }; }; From 9d5217f68bfb391372c7d669417c513b2b147ed8 Mon Sep 17 00:00:00 2001 From: Jonathan Rico Date: Wed, 24 Jan 2024 08:41:08 +0100 Subject: [PATCH 2779/3723] Bluetooth: L2CAP: call `bt_l2cap_send_cb` once Small refactor to improve readability. Signed-off-by: Jonathan Rico --- subsys/bluetooth/host/l2cap.c | 18 ++++++++++++------ 1 file changed, 12 insertions(+), 6 deletions(-) diff --git a/subsys/bluetooth/host/l2cap.c b/subsys/bluetooth/host/l2cap.c index 5732f2615a3..bd13c1bba1a 100644 --- a/subsys/bluetooth/host/l2cap.c +++ b/subsys/bluetooth/host/l2cap.c @@ -1944,6 +1944,7 @@ static int l2cap_chan_le_send(struct bt_l2cap_le_chan *ch, struct net_buf *seg; struct net_buf_simple_state state; int len, err; + bt_conn_tx_cb_t cb; if (!test_and_dec(&ch->tx.credits)) { LOG_DBG("No credits to transmit packet"); @@ -1985,15 +1986,20 @@ static int l2cap_chan_le_send(struct bt_l2cap_le_chan *ch, /* Set a callback if there is no data left in the buffer */ if (buf == seg || !buf->len) { - err = bt_l2cap_send_cb(ch->chan.conn, ch->tx.cid, seg, - l2cap_chan_sdu_sent, - l2cap_tx_meta_data(buf)); + cb = l2cap_chan_sdu_sent; } else { - err = bt_l2cap_send_cb(ch->chan.conn, ch->tx.cid, seg, - l2cap_chan_seg_sent, - l2cap_tx_meta_data(buf)); + cb = l2cap_chan_seg_sent; } + /* Forward the PDU to the lower layer. + * + * Note: after this call, anything in buf->user_data should be + * considered lost, as the lower layers are free to re-use it as they + * see fit. Reading from it later is obviously a no-no. + */ + err = bt_l2cap_send_cb(ch->chan.conn, ch->tx.cid, seg, + cb, l2cap_tx_meta_data(buf)); + if (err) { LOG_DBG("Unable to send seg %d", err); atomic_inc(&ch->tx.credits); From 6fa5d1e6a5d2739313f019ce5a7533d06600a37f Mon Sep 17 00:00:00 2001 From: Jonathan Rico Date: Thu, 11 Jan 2024 18:18:10 +0100 Subject: [PATCH 2780/3723] Bluetooth: L2CAP: fix net buf frags handling Fix the handling of buffers with fragments. What seems to have been broken is the metadata reference that was not passed to the next frag in the chain. Add a test to regression too. The main user of this is IPSP. Signed-off-by: Jonathan Rico --- subsys/bluetooth/host/l2cap.c | 70 ++- tests/bsim/bluetooth/host/compile.sh | 1 + .../bluetooth/host/l2cap/frags/CMakeLists.txt | 16 + .../bsim/bluetooth/host/l2cap/frags/prj.conf | 22 + .../bluetooth/host/l2cap/frags/src/common.c | 22 + .../bluetooth/host/l2cap/frags/src/common.h | 57 ++ .../bluetooth/host/l2cap/frags/src/main.c | 489 ++++++++++++++++++ .../l2cap/frags/tests_scripts/_compile.sh | 16 + .../host/l2cap/frags/tests_scripts/run.sh | 20 + 9 files changed, 695 insertions(+), 18 deletions(-) create mode 100644 tests/bsim/bluetooth/host/l2cap/frags/CMakeLists.txt create mode 100644 tests/bsim/bluetooth/host/l2cap/frags/prj.conf create mode 100644 tests/bsim/bluetooth/host/l2cap/frags/src/common.c create mode 100644 tests/bsim/bluetooth/host/l2cap/frags/src/common.h create mode 100644 tests/bsim/bluetooth/host/l2cap/frags/src/main.c create mode 100755 tests/bsim/bluetooth/host/l2cap/frags/tests_scripts/_compile.sh create mode 100755 tests/bsim/bluetooth/host/l2cap/frags/tests_scripts/run.sh diff --git a/subsys/bluetooth/host/l2cap.c b/subsys/bluetooth/host/l2cap.c index bd13c1bba1a..05900f34885 100644 --- a/subsys/bluetooth/host/l2cap.c +++ b/subsys/bluetooth/host/l2cap.c @@ -1954,7 +1954,8 @@ static int l2cap_chan_le_send(struct bt_l2cap_le_chan *ch, /* Save state so it can be restored if we failed to send */ net_buf_simple_save(&buf->b, &state); - if (net_buf_frags_len(buf) <= ch->tx.mps) { + if ((buf->len <= ch->tx.mps) && + (net_buf_headroom(buf) >= BT_L2CAP_BUF_SIZE(0))) { LOG_DBG("len <= MPS, not allocating seg for %p", buf); seg = net_buf_ref(buf); @@ -1984,8 +1985,12 @@ static int l2cap_chan_le_send(struct bt_l2cap_le_chan *ch, len = seg->len - sdu_hdr_len; - /* Set a callback if there is no data left in the buffer */ - if (buf == seg || !buf->len) { + /* SDU will be considered sent when there is no data left in the + * buffers, or if there will be no data left, if we are sending `buf` + * directly. + */ + if (net_buf_frags_len(buf) == 0 || + (buf == seg && net_buf_frags_len(buf) == len)) { cb = l2cap_chan_sdu_sent; } else { cb = l2cap_chan_seg_sent; @@ -1997,8 +2002,7 @@ static int l2cap_chan_le_send(struct bt_l2cap_le_chan *ch, * considered lost, as the lower layers are free to re-use it as they * see fit. Reading from it later is obviously a no-no. */ - err = bt_l2cap_send_cb(ch->chan.conn, ch->tx.cid, seg, - cb, l2cap_tx_meta_data(buf)); + err = bt_l2cap_send_cb(ch->chan.conn, ch->tx.cid, seg, cb, l2cap_tx_meta_data(buf)); if (err) { LOG_DBG("Unable to send seg %d", err); @@ -2034,37 +2038,67 @@ static int l2cap_chan_le_send(struct bt_l2cap_le_chan *ch, return len; } +/* return next netbuf fragment if present, also assign metadata */ +static struct net_buf *prepare_next_frag(struct net_buf *parent, + struct l2cap_tx_meta_data *meta) +{ + /* this does an unref on `parent` */ + struct net_buf *next = net_buf_frag_del(NULL, parent); + + if (next) { + LOG_DBG("process next frag: %p -> %p", parent, next); + + /* Copy the l2cap metadata ref to the next buffer in the chain. + * We need it to figure out which channel the PDU has been sent + * on, in order to either send the rest of the SDU or call the + * application callback. + */ + l2cap_tx_meta_data(next) = meta; + } + + return next; +} + static int l2cap_chan_le_send_sdu(struct bt_l2cap_le_chan *ch, struct net_buf **buf) { - int ret, total_len; + int ret; + size_t sent, rem_len, frag_len; struct net_buf *frag; - int sent = 0; - - total_len = net_buf_frags_len(*buf) + sent; + struct l2cap_tx_meta_data *meta = l2cap_tx_meta_data(*buf); frag = *buf; if (!frag->len && frag->frags) { frag = frag->frags; } - /* Send remaining segments */ - for (ret = 0; sent < total_len; sent += ret) { - /* Proceed to next fragment */ - if (!frag->len) { - frag = net_buf_frag_del(NULL, frag); - } + rem_len = net_buf_frags_len(frag); + sent = 0; + while (frag && sent != rem_len) { + LOG_DBG("send frag %p (orig buf %p)", frag, *buf); + frag_len = frag->len; ret = l2cap_chan_le_send(ch, frag, 0); if (ret < 0) { *buf = frag; + + LOG_DBG("failed to send frag (ch %p cid 0x%04x sent %d)", + ch, ch->tx.cid, sent); + return ret; } - } - LOG_DBG("ch %p cid 0x%04x sent %u total_len %u", ch, ch->tx.cid, sent, total_len); + sent += ret; + + /* If the current buffer has been fully consumed, destroy it and + * proceed to the next fragment of the netbuf chain. + */ + if (ret == frag_len) { + frag = prepare_next_frag(frag, meta); + } + } - net_buf_unref(frag); + LOG_DBG("ch %p cid 0x%04x sent %u", ch, ch->tx.cid, sent); return sent; } diff --git a/tests/bsim/bluetooth/host/compile.sh b/tests/bsim/bluetooth/host/compile.sh index 44853bfc918..11ee242f12c 100755 --- a/tests/bsim/bluetooth/host/compile.sh +++ b/tests/bsim/bluetooth/host/compile.sh @@ -66,6 +66,7 @@ app=tests/bsim/bluetooth/host/l2cap/credits compile app=tests/bsim/bluetooth/host/l2cap/credits conf_file=prj_ecred.conf compile app=tests/bsim/bluetooth/host/l2cap/credits_seg_recv compile app=tests/bsim/bluetooth/host/l2cap/credits_seg_recv conf_file=prj_ecred.conf compile +app=tests/bsim/bluetooth/host/l2cap/frags compile app=tests/bsim/bluetooth/host/l2cap/send_on_connect compile app=tests/bsim/bluetooth/host/l2cap/send_on_connect conf_file=prj_ecred.conf compile diff --git a/tests/bsim/bluetooth/host/l2cap/frags/CMakeLists.txt b/tests/bsim/bluetooth/host/l2cap/frags/CMakeLists.txt new file mode 100644 index 00000000000..0a40ef4a135 --- /dev/null +++ b/tests/bsim/bluetooth/host/l2cap/frags/CMakeLists.txt @@ -0,0 +1,16 @@ +# SPDX-License-Identifier: Apache-2.0 + +cmake_minimum_required(VERSION 3.20.0) + +find_package(Zephyr REQUIRED HINTS $ENV{ZEPHYR_BASE}) +project(bsim_test_l2cap_frags) + +target_sources(app PRIVATE + src/main.c + src/common.c) + +zephyr_include_directories( + src/ + ${BSIM_COMPONENTS_PATH}/libUtilv1/src/ + ${BSIM_COMPONENTS_PATH}/libPhyComv1/src/ + ) diff --git a/tests/bsim/bluetooth/host/l2cap/frags/prj.conf b/tests/bsim/bluetooth/host/l2cap/frags/prj.conf new file mode 100644 index 00000000000..6681ea288ee --- /dev/null +++ b/tests/bsim/bluetooth/host/l2cap/frags/prj.conf @@ -0,0 +1,22 @@ +CONFIG_BT=y +CONFIG_BT_CENTRAL=y +CONFIG_BT_PERIPHERAL=y +CONFIG_BT_DEVICE_NAME="L2CAP frags test" + +CONFIG_BT_EATT=n +CONFIG_BT_L2CAP_ECRED=n + +CONFIG_BT_SMP=y # Next config depends on it +CONFIG_BT_L2CAP_DYNAMIC_CHANNEL=y + +# Disable auto-initiated procedures so they don't +# mess with the test's execution. +CONFIG_BT_AUTO_PHY_UPDATE=n +CONFIG_BT_AUTO_DATA_LEN_UPDATE=n +CONFIG_BT_GAP_AUTO_UPDATE_CONN_PARAMS=n + +CONFIG_LOG=y +CONFIG_ASSERT=y + +CONFIG_BT_L2CAP_LOG_LEVEL_DBG=y +CONFIG_ARCH_POSIX_TRAP_ON_FATAL=y diff --git a/tests/bsim/bluetooth/host/l2cap/frags/src/common.c b/tests/bsim/bluetooth/host/l2cap/frags/src/common.c new file mode 100644 index 00000000000..c6679d83494 --- /dev/null +++ b/tests/bsim/bluetooth/host/l2cap/frags/src/common.c @@ -0,0 +1,22 @@ +/* + * Copyright (c) 2024 Nordic Semiconductor ASA + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include "common.h" + +extern enum bst_result_t bst_result; + +void test_init(void) +{ + bst_ticker_set_next_tick_absolute(WAIT_TIME); + bst_result = In_progress; +} + +void test_tick(bs_time_t HW_device_time) +{ + if (bst_result != Passed) { + FAIL("test failed (not passed after %i seconds)\n", WAIT_SECONDS); + } +} diff --git a/tests/bsim/bluetooth/host/l2cap/frags/src/common.h b/tests/bsim/bluetooth/host/l2cap/frags/src/common.h new file mode 100644 index 00000000000..4fb971616b3 --- /dev/null +++ b/tests/bsim/bluetooth/host/l2cap/frags/src/common.h @@ -0,0 +1,57 @@ +/* + * Common functions and helpers for L2CAP tests + * + * Copyright (c) 2024 Nordic Semiconductor ASA + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include + +#include +#include +#include + +#include +#include +#include +#include "bs_types.h" +#include "bs_tracing.h" +#include "bstests.h" +#include "bs_pc_backchannel.h" + +extern enum bst_result_t bst_result; + +#define CREATE_FLAG(flag) static atomic_t flag = (atomic_t)false +#define SET_FLAG(flag) (void)atomic_set(&flag, (atomic_t)true) +#define UNSET_FLAG(flag) (void)atomic_set(&flag, (atomic_t)false) +#define TEST_FLAG(flag) (atomic_get(&flag) == (atomic_t)true) +#define WAIT_FOR_FLAG_SET(flag) \ + while (!(bool)atomic_get(&flag)) { \ + (void)k_sleep(K_MSEC(1)); \ + } +#define WAIT_FOR_FLAG_UNSET(flag) \ + while ((bool)atomic_get(&flag)) { \ + (void)k_sleep(K_MSEC(1)); \ + } + + +#define WAIT_SECONDS 30 /* seconds */ +#define WAIT_TIME (WAIT_SECONDS * USEC_PER_SEC) /* microseconds*/ + +#define FAIL(...) \ + do { \ + bst_result = Failed; \ + bs_trace_error_time_line(__VA_ARGS__); \ + } while (0) + +#define PASS(...) \ + do { \ + bst_result = Passed; \ + bs_trace_info_time(1, __VA_ARGS__); \ + } while (0) + +#define ASSERT(expr, ...) if (!(expr)) {FAIL(__VA_ARGS__); } + +void test_init(void); +void test_tick(bs_time_t HW_device_time); diff --git a/tests/bsim/bluetooth/host/l2cap/frags/src/main.c b/tests/bsim/bluetooth/host/l2cap/frags/src/main.c new file mode 100644 index 00000000000..df7924e1829 --- /dev/null +++ b/tests/bsim/bluetooth/host/l2cap/frags/src/main.c @@ -0,0 +1,489 @@ +/* + * The goal of this test is to verify the buf->frags feature works with L2CAP + * credit-based channels. + * + * Copyright (c) 2024 Nordic Semiconductor + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include "bstests.h" +#include "common.h" + +#define LOG_MODULE_NAME main +#include +LOG_MODULE_REGISTER(LOG_MODULE_NAME, LOG_LEVEL_DBG); + +CREATE_FLAG(is_connected); +CREATE_FLAG(flag_l2cap_connected); + +#define SMALL_BUF_SIZE 10 +#define LARGE_BUF_SIZE 50 +#define POOL_NUM 2 +#define PAYLOAD_SIZE (POOL_NUM * (SMALL_BUF_SIZE + LARGE_BUF_SIZE)) + +#define L2CAP_MTU PAYLOAD_SIZE +#define PAYLOAD_NUM 3 + +NET_BUF_POOL_DEFINE(sdu_rx_pool, 1, BT_L2CAP_SDU_BUF_SIZE(L2CAP_MTU), + CONFIG_BT_CONN_TX_USER_DATA_SIZE, NULL); + +static void small_buf_destroy(struct net_buf *buf) +{ + LOG_DBG("%p", buf); + net_buf_destroy(buf); +} + +NET_BUF_POOL_DEFINE(small_buf_pool, POOL_NUM, BT_L2CAP_SDU_BUF_SIZE(SMALL_BUF_SIZE), + CONFIG_BT_CONN_TX_USER_DATA_SIZE, small_buf_destroy); + +static void large_buf_destroy(struct net_buf *buf) +{ + LOG_DBG("%p", buf); + net_buf_destroy(buf); +} + +NET_BUF_POOL_DEFINE(large_buf_pool, POOL_NUM, LARGE_BUF_SIZE, + CONFIG_BT_CONN_TX_USER_DATA_SIZE, large_buf_destroy); + +static uint8_t tx_data[PAYLOAD_SIZE]; +static uint16_t rx_cnt; + +K_SEM_DEFINE(sdu_received, 0, 1); +K_SEM_DEFINE(tx_sem, 1, 1); + +struct test_ctx { + struct bt_l2cap_le_chan le_chan; + size_t tx_remaining; + struct net_buf *rx_sdu; +} test_ctx; + +struct net_buf *alloc_and_memcpy(struct net_buf_pool *pool, + size_t reserve, + uint8_t *data, + size_t len) +{ + struct net_buf *buf = net_buf_alloc(pool, K_NO_WAIT); + + if (buf == NULL) { + FAIL("No more memory\n"); + return NULL; + } + + net_buf_reserve(buf, reserve); + net_buf_add_mem(buf, data, len); + + return buf; +} + +int l2cap_chan_send(struct bt_l2cap_chan *chan, uint8_t *data, size_t len) +{ + uint8_t *data_start = data; + struct net_buf *buf, *b; + int ret; + + LOG_DBG("chan %p conn %u data %p len %d", + chan, bt_conn_index(chan->conn), data, len); + + if (k_sem_take(&tx_sem, K_NO_WAIT)) { + FAIL("Already TXing\n"); + return -EAGAIN; + } + + /* Payload is comprised of two small buffers and two big buffers. The + * very first buffer needs a reserve() called on it as per l2cap API + * requirements. + */ + buf = alloc_and_memcpy(&small_buf_pool, + BT_L2CAP_SDU_CHAN_SEND_RESERVE, + data, SMALL_BUF_SIZE); + ASSERT(buf, "No more memory\n"); + + data += SMALL_BUF_SIZE; + + b = alloc_and_memcpy(&small_buf_pool, 0, data, SMALL_BUF_SIZE); + ASSERT(buf, "No more memory\n"); + + LOG_DBG("append frag %p to buf %p", b, buf); + net_buf_frag_add(buf, b); + data += SMALL_BUF_SIZE; + + b = alloc_and_memcpy(&large_buf_pool, 0, data, LARGE_BUF_SIZE); + ASSERT(buf, "No more memory\n"); + + LOG_DBG("append frag %p to buf %p", b, buf); + net_buf_frag_add(buf, b); + data += LARGE_BUF_SIZE; + + b = alloc_and_memcpy(&large_buf_pool, 0, data, LARGE_BUF_SIZE); + ASSERT(buf, "No more memory\n"); + + LOG_DBG("append frag %p to buf %p", b, buf); + net_buf_frag_add(buf, b); + data += LARGE_BUF_SIZE; + + ASSERT(data == (data_start + len), "logic error\n"); + + ret = bt_l2cap_chan_send(chan, buf); + ASSERT(ret >= 0, "Failed sending: err %d", ret); + + LOG_DBG("sent: len %d", len); + + return ret; +} + +struct net_buf *alloc_buf_cb(struct bt_l2cap_chan *chan) +{ + return net_buf_alloc(&sdu_rx_pool, K_NO_WAIT); +} + +void continue_sending(struct test_ctx *ctx) +{ + struct bt_l2cap_chan *chan = &ctx->le_chan.chan; + + LOG_DBG("%p, remaining %d", chan, ctx->tx_remaining); + + if (ctx->tx_remaining) { + l2cap_chan_send(chan, tx_data, sizeof(tx_data)); + } else { + LOG_DBG("Done sending %u", bt_conn_index(chan->conn)); + } +} + +void sent_cb(struct bt_l2cap_chan *chan) +{ + LOG_DBG("%p", chan); + + if (test_ctx.tx_remaining) { + test_ctx.tx_remaining--; + } + + k_sem_give(&tx_sem); + continue_sending(&test_ctx); +} + +int recv_cb(struct bt_l2cap_chan *chan, struct net_buf *buf) +{ + LOG_DBG("len %d", buf->len); + rx_cnt++; + + /* Verify SDU data matches TX'd data. */ + ASSERT(memcmp(buf->data, tx_data, buf->len) == 0, "RX data doesn't match TX"); + + return 0; +} + +void l2cap_chan_connected_cb(struct bt_l2cap_chan *l2cap_chan) +{ + struct bt_l2cap_le_chan *chan = + CONTAINER_OF(l2cap_chan, struct bt_l2cap_le_chan, chan); + + /* TODO: check that actual MPS < expected MPS */ + + SET_FLAG(flag_l2cap_connected); + LOG_DBG("%x (tx mtu %d mps %d) (tx mtu %d mps %d)", + l2cap_chan, + chan->tx.mtu, + chan->tx.mps, + chan->rx.mtu, + chan->rx.mps); +} + +void l2cap_chan_disconnected_cb(struct bt_l2cap_chan *chan) +{ + UNSET_FLAG(flag_l2cap_connected); + LOG_DBG("%p", chan); +} + +static struct bt_l2cap_chan_ops ops = { + .connected = l2cap_chan_connected_cb, + .disconnected = l2cap_chan_disconnected_cb, + .alloc_buf = alloc_buf_cb, + .recv = recv_cb, + .sent = sent_cb, +}; + +int server_accept_cb(struct bt_conn *conn, struct bt_l2cap_server *server, + struct bt_l2cap_chan **chan) +{ + struct bt_l2cap_le_chan *le_chan = &test_ctx.le_chan; + + memset(le_chan, 0, sizeof(*le_chan)); + le_chan->chan.ops = &ops; + le_chan->rx.mtu = L2CAP_MTU; + *chan = &le_chan->chan; + + return 0; +} + +static struct bt_l2cap_server test_l2cap_server = { + .accept = server_accept_cb +}; + +static int l2cap_server_register(bt_security_t sec_level) +{ + test_l2cap_server.psm = 0; + test_l2cap_server.sec_level = sec_level; + + int err = bt_l2cap_server_register(&test_l2cap_server); + + ASSERT(err == 0, "Failed to register l2cap server."); + + return test_l2cap_server.psm; +} + +static void connected(struct bt_conn *conn, uint8_t conn_err) +{ + char addr[BT_ADDR_LE_STR_LEN]; + + bt_addr_le_to_str(bt_conn_get_dst(conn), addr, sizeof(addr)); + + if (conn_err) { + FAIL("Failed to connect to %s (%u)", addr, conn_err); + return; + } + + LOG_DBG("%s", addr); + + SET_FLAG(is_connected); +} + +static void disconnected(struct bt_conn *conn, uint8_t reason) +{ + char addr[BT_ADDR_LE_STR_LEN]; + + bt_addr_le_to_str(bt_conn_get_dst(conn), addr, sizeof(addr)); + + LOG_DBG("%p %s (reason 0x%02x)", conn, addr, reason); + + UNSET_FLAG(is_connected); +} + +BT_CONN_CB_DEFINE(conn_callbacks) = { + .connected = connected, + .disconnected = disconnected, +}; + +static void disconnect_device(struct bt_conn *conn, void *data) +{ + int err; + + SET_FLAG(is_connected); + + err = bt_conn_disconnect(conn, BT_HCI_ERR_REMOTE_USER_TERM_CONN); + ASSERT(!err, "Failed to initate disconnect (err %d)", err); + + LOG_DBG("Waiting for disconnection..."); + WAIT_FOR_FLAG_UNSET(is_connected); +} + +#define BT_LE_ADV_CONN_NAME_OT BT_LE_ADV_PARAM(BT_LE_ADV_OPT_CONNECTABLE | \ + BT_LE_ADV_OPT_USE_NAME | \ + BT_LE_ADV_OPT_ONE_TIME, \ + BT_GAP_ADV_FAST_INT_MIN_2, \ + BT_GAP_ADV_FAST_INT_MAX_2, NULL) + +static const struct bt_data ad[] = { + BT_DATA_BYTES(BT_DATA_FLAGS, (BT_LE_AD_GENERAL | BT_LE_AD_NO_BREDR)), +}; + +static void test_peripheral_main(void) +{ + LOG_DBG("*L2CAP FRAGS Peripheral started*"); + int err; + + /* Prepare tx_data */ + for (size_t i = 0; i < sizeof(tx_data); i++) { + tx_data[i] = (uint8_t)i; + } + + err = bt_enable(NULL); + if (err) { + FAIL("Can't enable Bluetooth (err %d)", err); + return; + } + + LOG_DBG("Peripheral Bluetooth initialized."); + LOG_DBG("Connectable advertising..."); + err = bt_le_adv_start(BT_LE_ADV_CONN_NAME_OT, ad, ARRAY_SIZE(ad), NULL, 0); + if (err) { + FAIL("Advertising failed to start (err %d)", err); + return; + } + + LOG_DBG("Advertising started."); + LOG_DBG("Peripheral waiting for connection..."); + WAIT_FOR_FLAG_SET(is_connected); + LOG_DBG("Peripheral Connected."); + + int psm = l2cap_server_register(BT_SECURITY_L1); + + LOG_DBG("Registered server PSM %x", psm); + + LOG_DBG("Peripheral waiting for transfer completion"); + while (rx_cnt < PAYLOAD_NUM) { + k_sleep(K_MSEC(100)); + } + + bt_conn_foreach(BT_CONN_TYPE_LE, disconnect_device, NULL); + LOG_INF("Total received: %d", rx_cnt); + + ASSERT(rx_cnt == PAYLOAD_NUM, "Did not receive expected no of SDUs\n"); + + PASS("L2CAP FRAGS Peripheral passed\n"); +} + +static void device_found(const bt_addr_le_t *addr, int8_t rssi, uint8_t type, + struct net_buf_simple *ad) +{ + struct bt_le_conn_param *param; + struct bt_conn *conn; + int err; + + err = bt_le_scan_stop(); + if (err) { + FAIL("Stop LE scan failed (err %d)", err); + return; + } + + char str[BT_ADDR_LE_STR_LEN]; + + bt_addr_le_to_str(addr, str, sizeof(str)); + + LOG_DBG("Connecting to %s", str); + + param = BT_LE_CONN_PARAM_DEFAULT; + err = bt_conn_le_create(addr, BT_CONN_LE_CREATE_CONN, param, &conn); + if (err) { + FAIL("Create conn failed (err %d)", err); + return; + } +} + +static void connect_peripheral(void) +{ + struct bt_le_scan_param scan_param = { + .type = BT_LE_SCAN_TYPE_ACTIVE, + .options = BT_LE_SCAN_OPT_NONE, + .interval = BT_GAP_SCAN_FAST_INTERVAL, + .window = BT_GAP_SCAN_FAST_WINDOW, + }; + + UNSET_FLAG(is_connected); + + int err = bt_le_scan_start(&scan_param, device_found); + + ASSERT(!err, "Scanning failed to start (err %d)\n", err); + + LOG_DBG("Central initiating connection..."); + WAIT_FOR_FLAG_SET(is_connected); +} + +static void connect_l2cap_channel(struct bt_conn *conn, void *data) +{ + int err; + struct bt_l2cap_le_chan *le_chan = &test_ctx.le_chan; + + le_chan->chan.ops = &ops; + le_chan->rx.mtu = L2CAP_MTU; + + UNSET_FLAG(flag_l2cap_connected); + + err = bt_l2cap_chan_connect(conn, &le_chan->chan, 0x0080); + ASSERT(!err, "Error connecting l2cap channel (err %d)\n", err); + + WAIT_FOR_FLAG_SET(flag_l2cap_connected); +} + +static void connect_l2cap_ecred_channel(struct bt_conn *conn, void *data) +{ + int err; + struct bt_l2cap_le_chan *le_chan = &test_ctx.le_chan; + struct bt_l2cap_chan *chan_list[2] = { &le_chan->chan, 0 }; + + le_chan->chan.ops = &ops; + le_chan->rx.mtu = L2CAP_MTU; + + UNSET_FLAG(flag_l2cap_connected); + + err = bt_l2cap_ecred_chan_connect(conn, chan_list, 0x0080); + ASSERT(!err, "Error connecting l2cap channel (err %d)\n", err); + + WAIT_FOR_FLAG_SET(flag_l2cap_connected); +} + +static void test_central_main(void) +{ + LOG_DBG("*L2CAP FRAGS Central started*"); + int err; + + /* Prepare tx_data */ + for (size_t i = 0; i < sizeof(tx_data); i++) { + tx_data[i] = (uint8_t)i; + } + + err = bt_enable(NULL); + ASSERT(err == 0, "Can't enable Bluetooth (err %d)\n", err); + LOG_DBG("Central Bluetooth initialized."); + + connect_peripheral(); + + /* Connect L2CAP channels */ + LOG_DBG("Connect L2CAP channels"); + if (IS_ENABLED(CONFIG_BT_L2CAP_ECRED)) { + bt_conn_foreach(BT_CONN_TYPE_LE, connect_l2cap_ecred_channel, NULL); + } else { + bt_conn_foreach(BT_CONN_TYPE_LE, connect_l2cap_channel, NULL); + } + + /* Send PAYLOAD_NUM SDUs to each peripheral */ + LOG_DBG("Start sending SDUs"); + test_ctx.tx_remaining = PAYLOAD_NUM; + l2cap_chan_send(&test_ctx.le_chan.chan, tx_data, sizeof(tx_data)); + + LOG_DBG("Wait until all transfers are completed."); + while (test_ctx.tx_remaining) { + k_msleep(100); + } + + WAIT_FOR_FLAG_UNSET(is_connected); + LOG_DBG("Peripheral disconnected."); + PASS("L2CAP FRAGS Central passed\n"); +} + +static const struct bst_test_instance test_def[] = { + { + .test_id = "peripheral", + .test_descr = "Peripheral L2CAP FRAGS", + .test_post_init_f = test_init, + .test_tick_f = test_tick, + .test_main_f = test_peripheral_main + }, + { + .test_id = "central", + .test_descr = "Central L2CAP FRAGS", + .test_post_init_f = test_init, + .test_tick_f = test_tick, + .test_main_f = test_central_main + }, + BSTEST_END_MARKER +}; + +struct bst_test_list *test_main_l2cap_credits_install(struct bst_test_list *tests) +{ + return bst_add_tests(tests, test_def); +} + +extern struct bst_test_list *test_main_l2cap_credits_install(struct bst_test_list *tests); + +bst_test_install_t test_installers[] = { + test_main_l2cap_credits_install, + NULL +}; + +int main(void) +{ + bst_main(); + + return 0; +} diff --git a/tests/bsim/bluetooth/host/l2cap/frags/tests_scripts/_compile.sh b/tests/bsim/bluetooth/host/l2cap/frags/tests_scripts/_compile.sh new file mode 100755 index 00000000000..e4d6157f76f --- /dev/null +++ b/tests/bsim/bluetooth/host/l2cap/frags/tests_scripts/_compile.sh @@ -0,0 +1,16 @@ +#!/usr/bin/env bash +# Copyright 2024 Nordic Semiconductor ASA +# SPDX-License-Identifier: Apache-2.0 + +# Path checks, etc +source ${ZEPHYR_BASE}/tests/bsim/sh_common.source + +# Place yourself in the test's root (i.e. ./../) +rm -rf ${BSIM_OUT_PATH}/bin/bs_nrf52_bsim_tests* + +# terminate running simulations (if any) +${BSIM_COMPONENTS_PATH}/common/stop_bsim.sh + +bsim_exe=bs_nrf52_bsim_tests_bsim_bluetooth_host_l2cap_frags_prj_conf +west build -b nrf52_bsim && \ + cp build/zephyr/zephyr.exe ${BSIM_OUT_PATH}/bin/${bsim_exe} diff --git a/tests/bsim/bluetooth/host/l2cap/frags/tests_scripts/run.sh b/tests/bsim/bluetooth/host/l2cap/frags/tests_scripts/run.sh new file mode 100755 index 00000000000..2c71c95001e --- /dev/null +++ b/tests/bsim/bluetooth/host/l2cap/frags/tests_scripts/run.sh @@ -0,0 +1,20 @@ +#!/usr/bin/env bash +# Copyright (c) 2024 Nordic Semiconductor +# SPDX-License-Identifier: Apache-2.0 + +source ${ZEPHYR_BASE}/tests/bsim/sh_common.source + +verbosity_level=2 +EXECUTE_TIMEOUT=20 + +cd ${BSIM_OUT_PATH}/bin + +simulation_id=bluetooth_host_l2cap_frags_prj_conf +bsim_exe=./bs_nrf52_bsim_tests_bsim_bluetooth_host_l2cap_frags_prj_conf + +Execute "${bsim_exe}" -v=${verbosity_level} -s=${simulation_id} -d=0 -testid=central -rs=420 +Execute "${bsim_exe}" -v=${verbosity_level} -s=${simulation_id} -d=1 -testid=peripheral -rs=100 + +Execute ./bs_2G4_phy_v1 -v=${verbosity_level} -s=${simulation_id} -D=2 -sim_length=30e6 $@ + +wait_for_background_jobs From 32b4388ba80bb401597962c725f5899ac6d70f63 Mon Sep 17 00:00:00 2001 From: Marco Widmer Date: Mon, 20 Mar 2023 11:23:04 +0100 Subject: [PATCH 2781/3723] drivers: dma: stm32: do not clear busy flag in cyclic mode The STM32 DMA driver supports cyclic mode by setting source_reload_en and dest_reload_en. This causes the dma_callback to be called twice per buffer run-through, at half-time and when wrapping back to the start of the buffer. However, the current implementation only calls dma_callback twice. When wrapping the first time, it sets stream->busy to false and ignores subsequent interrupts. With this change, the busy flag is only cleared in non-cyclic mode. Signed-off-by: Marco Widmer --- drivers/dma/dma_stm32.c | 11 ++++++++--- drivers/dma/dma_stm32.h | 1 + 2 files changed, 9 insertions(+), 3 deletions(-) diff --git a/drivers/dma/dma_stm32.c b/drivers/dma/dma_stm32.c index 2e7e37a7cfb..178d83665b4 100644 --- a/drivers/dma/dma_stm32.c +++ b/drivers/dma/dma_stm32.c @@ -123,7 +123,10 @@ static void dma_stm32_irq_handler(const struct device *dev, uint32_t id) stream->dma_callback(dev, stream->user_data, callback_arg, DMA_STATUS_BLOCK); } else if (stm32_dma_is_tc_irq_active(dma, id)) { #ifdef CONFIG_DMAMUX_STM32 - stream->busy = false; + /* Circular buffer never stops receiving as long as peripheral is enabled */ + if (!stream->cyclic) { + stream->busy = false; + } #endif /* Let HAL DMA handle flags on its own */ if (!stream->hal_override) { @@ -312,6 +315,7 @@ DMA_STM32_EXPORT_API int dma_stm32_configure(const struct device *dev, stream->hal_override = true; stream->dma_callback = config->dma_callback; stream->user_data = config->user_data; + stream->cyclic = false; return 0; } @@ -361,6 +365,7 @@ DMA_STM32_EXPORT_API int dma_stm32_configure(const struct device *dev, stream->user_data = config->user_data; stream->src_size = config->source_data_size; stream->dst_size = config->dest_data_size; + stream->cyclic = config->head_block->source_reload_en; /* Check dest or source memory address, warn if 0 */ if (config->head_block->source_address == 0) { @@ -432,7 +437,7 @@ DMA_STM32_EXPORT_API int dma_stm32_configure(const struct device *dev, LOG_DBG("Channel (%d) peripheral inc (%x).", id, DMA_InitStruct.PeriphOrM2MSrcIncMode); - if (config->head_block->source_reload_en) { + if (stream->cyclic) { DMA_InitStruct.Mode = LL_DMA_MODE_CIRCULAR; } else { DMA_InitStruct.Mode = LL_DMA_MODE_NORMAL; @@ -494,7 +499,7 @@ DMA_STM32_EXPORT_API int dma_stm32_configure(const struct device *dev, LL_DMA_EnableIT_TC(dma, dma_stm32_id_to_stream(id)); /* Enable Half-Transfer irq if circular mode is enabled */ - if (config->head_block->source_reload_en) { + if (stream->cyclic) { LL_DMA_EnableIT_HT(dma, dma_stm32_id_to_stream(id)); } diff --git a/drivers/dma/dma_stm32.h b/drivers/dma/dma_stm32.h index 9e88b7dfc2d..f21cb07e183 100644 --- a/drivers/dma/dma_stm32.h +++ b/drivers/dma/dma_stm32.h @@ -27,6 +27,7 @@ struct dma_stm32_stream { uint32_t dst_size; void *user_data; /* holds the client data */ dma_callback_t dma_callback; + bool cyclic; }; struct dma_stm32_data { From 8534767aed7d411f3081b02ec271b253a3d4fde4 Mon Sep 17 00:00:00 2001 From: Javad Rahimipetroudi Date: Fri, 19 Jan 2024 08:16:17 +0100 Subject: [PATCH 2782/3723] boards: arm: stm32wb5mm-dk: add basic board support This patch add the basic board support for the STM32WB5MM-DK Discovery Kit. At the moment only debug UART Debug is ported. Other peripherals will be added in the following patches. Signed-off-by: Javad Rahimipetroudi --- boards/arm/stm32wb5mm_dk/Kconfig.board | 8 + boards/arm/stm32wb5mm_dk/Kconfig.defconfig | 16 ++ boards/arm/stm32wb5mm_dk/board.cmake | 7 + .../stm32wb5mm_dk/doc/img/STM32WB5MM_DK.jpg | Bin 0 -> 43925 bytes .../arm/stm32wb5mm_dk/doc/stm32wb5mm_dk.rst | 226 ++++++++++++++++++ boards/arm/stm32wb5mm_dk/stm32wb5mm_dk.dts | 145 +++++++++++ boards/arm/stm32wb5mm_dk/stm32wb5mm_dk.yaml | 14 ++ .../arm/stm32wb5mm_dk/stm32wb5mm_dk_defconfig | 24 ++ boards/arm/stm32wb5mm_dk/support/openocd.cfg | 7 + 9 files changed, 447 insertions(+) create mode 100644 boards/arm/stm32wb5mm_dk/Kconfig.board create mode 100644 boards/arm/stm32wb5mm_dk/Kconfig.defconfig create mode 100644 boards/arm/stm32wb5mm_dk/board.cmake create mode 100644 boards/arm/stm32wb5mm_dk/doc/img/STM32WB5MM_DK.jpg create mode 100644 boards/arm/stm32wb5mm_dk/doc/stm32wb5mm_dk.rst create mode 100644 boards/arm/stm32wb5mm_dk/stm32wb5mm_dk.dts create mode 100644 boards/arm/stm32wb5mm_dk/stm32wb5mm_dk.yaml create mode 100644 boards/arm/stm32wb5mm_dk/stm32wb5mm_dk_defconfig create mode 100644 boards/arm/stm32wb5mm_dk/support/openocd.cfg diff --git a/boards/arm/stm32wb5mm_dk/Kconfig.board b/boards/arm/stm32wb5mm_dk/Kconfig.board new file mode 100644 index 00000000000..28ca74d81a9 --- /dev/null +++ b/boards/arm/stm32wb5mm_dk/Kconfig.board @@ -0,0 +1,8 @@ +# STM32WB5MM-DK Discovery Development board configuration + +# Copyright (c) 2024 Javad Rahimipetroudi +# SPDX-License-Identifier: Apache-2.0 + +config BOARD_STM32WB5MM_DK + bool "stm32wb5mm-dk Discovery Development Board" + depends on SOC_STM32WB55XX diff --git a/boards/arm/stm32wb5mm_dk/Kconfig.defconfig b/boards/arm/stm32wb5mm_dk/Kconfig.defconfig new file mode 100644 index 00000000000..5ce31881bd0 --- /dev/null +++ b/boards/arm/stm32wb5mm_dk/Kconfig.defconfig @@ -0,0 +1,16 @@ +# STM32WB5MM-DK Discovery Development board configuration + +# Copyright (c) 2024 Javad Rahimipetroudi +# SPDX-License-Identifier: Apache-2.0 + +if BOARD_STM32WB5MM_DK + +config BOARD + default "stm32wb5mm_dk" + +choice BT_HCI_BUS_TYPE + default BT_STM32_IPM + depends on BT +endchoice + +endif # BOARD_STM32WB5MM_DK diff --git a/boards/arm/stm32wb5mm_dk/board.cmake b/boards/arm/stm32wb5mm_dk/board.cmake new file mode 100644 index 00000000000..47fc12f1308 --- /dev/null +++ b/boards/arm/stm32wb5mm_dk/board.cmake @@ -0,0 +1,7 @@ +# SPDX-License-Identifier: Apache-2.0 +board_runner_args(pyocd "--target=stm32wb55vgyx") +board_runner_args(stm32cubeprogrammer "--port=swd" "--reset-mode=hw") + +include(${ZEPHYR_BASE}/boards/common/stm32cubeprogrammer.board.cmake) +include(${ZEPHYR_BASE}/boards/common/openocd.board.cmake) +include(${ZEPHYR_BASE}/boards/common/pyocd.board.cmake) diff --git a/boards/arm/stm32wb5mm_dk/doc/img/STM32WB5MM_DK.jpg b/boards/arm/stm32wb5mm_dk/doc/img/STM32WB5MM_DK.jpg new file mode 100644 index 0000000000000000000000000000000000000000..0e9cc26ac2013eb700852663585e1edb16875a2a GIT binary patch literal 43925 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 + * + * SPDX-License-Identifier: Apache-2.0 + */ + +/dts-v1/; +#include +#include +#include + +/ { + model = "STMicroelectronics STM32WB5MM Discovery Development Kit"; + compatible = "st,stm32wb5mm-dk"; + + chosen { + zephyr,console = &usart1; + zephyr,shell-uart = &usart1; + zephyr,bt-mon-uart = &lpuart1; + zephyr,bt-c2h-uart = &lpuart1; + zephyr,sram = &sram0; + zephyr,flash = &flash0; + zephyr,code-partition = &slot0_partition; + }; + aliases { + watchdog0 = &iwdg; + die-temp0 = &die_temp; + volt-sensor0 = &vref; + volt-sensor1 = &vbat; + }; +}; + +&die_temp { + status = "okay"; +}; + +&clk_hse { + status = "okay"; +}; + +&clk_lse { + status = "okay"; +}; + +&clk_hsi48 { + status = "okay"; +}; + +&clk48 { + /* Node is disabled by default as default source is HSI48 */ + /* To select another clock, enable the node */ + clocks = <&rcc STM32_SRC_HSI48 CLK48_SEL(0)>; +}; + +&rcc { + clocks = <&clk_hse>; + clock-frequency = ; + cpu1-prescaler = <1>; + cpu2-prescaler = <1>; + ahb4-prescaler = <1>; + apb1-prescaler = <1>; + apb2-prescaler = <1>; +}; + +&usart1 { + pinctrl-0 = <&usart1_tx_pb6 &usart1_rx_pb7>; + pinctrl-names = "default"; + current-speed = <115200>; + status = "okay"; +}; + + +&lpuart1 { + pinctrl-0 = <&lpuart1_tx_pa2 &lpuart1_rx_pa3>; + pinctrl-names = "default"; + current-speed = <100000>; + status = "okay"; +}; + +&adc1 { + pinctrl-0 = <&adc1_in3_pc2>; + pinctrl-names = "default"; + st,adc-clock-source = ; + st,adc-prescaler = <4>; + status = "okay"; +}; + +&iwdg { + status = "okay"; +}; + +zephyr_udc0: &usb { + status = "okay"; + pinctrl-0 = <&usb_dm_pa11 &usb_dp_pa12>; + pinctrl-names = "default"; +}; + +&aes1 { + status = "okay"; +}; + +&flash0 { + partitions { + compatible = "fixed-partitions"; + #address-cells = <1>; + #size-cells = <1>; + + /* + * Configure partitions while leaving space for M0 BLE f/w + * Since STM32WBCube release V1.13.2, only _HCIOnly_ f/w are supported. + * These FW are expected to be located not before 0x080DB000 + * Current partition is using the first 876K of the flash for M4 + */ + + boot_partition: partition@0 { + label = "mcuboot"; + reg = <0x00000000 DT_SIZE_K(48)>; + }; + slot0_partition: partition@c000 { + label = "image-0"; + reg = <0x0000c000 DT_SIZE_K(400)>; + }; + slot1_partition: partition@70000 { + label = "image-1"; + reg = <0x00070000 DT_SIZE_K(400)>; + }; + scratch_partition: partition@d4000 { + label = "image-scratch"; + reg = <0x000d4000 DT_SIZE_K(16)>; + }; + storage_partition: partition@d8000 { + label = "storage"; + reg = <0x000d8000 DT_SIZE_K(8)>; + }; + + }; +}; + +&vref { + status = "okay"; +}; + +&vbat { + status = "okay"; +}; diff --git a/boards/arm/stm32wb5mm_dk/stm32wb5mm_dk.yaml b/boards/arm/stm32wb5mm_dk/stm32wb5mm_dk.yaml new file mode 100644 index 00000000000..63c75d4473f --- /dev/null +++ b/boards/arm/stm32wb5mm_dk/stm32wb5mm_dk.yaml @@ -0,0 +1,14 @@ +identifier: stm32wb5mm_dk +name: ST STM32WB5MM-DK Discovery Development Board +type: mcu +arch: arm +toolchain: + - zephyr + - gnuarmemb + - xtools +ram: 256 +flash: 1024 +supported: + - gpio + - uart +vendor: st diff --git a/boards/arm/stm32wb5mm_dk/stm32wb5mm_dk_defconfig b/boards/arm/stm32wb5mm_dk/stm32wb5mm_dk_defconfig new file mode 100644 index 00000000000..9fdd732848e --- /dev/null +++ b/boards/arm/stm32wb5mm_dk/stm32wb5mm_dk_defconfig @@ -0,0 +1,24 @@ +CONFIG_SOC_SERIES_STM32WBX=y +CONFIG_SOC_STM32WB55XX=y + +# enable uart driver +CONFIG_SERIAL=y + +# enable GPIO +CONFIG_GPIO=y + +# enable clocks +CONFIG_CLOCK_CONTROL=y + +# console +CONFIG_CONSOLE=y +CONFIG_UART_CONSOLE=y + +# Enable MPU +CONFIG_ARM_MPU=y + +# Enable HW stack protection +CONFIG_HW_STACK_PROTECTION=y + +# enable pin controller +CONFIG_PINCTRL=y diff --git a/boards/arm/stm32wb5mm_dk/support/openocd.cfg b/boards/arm/stm32wb5mm_dk/support/openocd.cfg new file mode 100644 index 00000000000..2ad58270368 --- /dev/null +++ b/boards/arm/stm32wb5mm_dk/support/openocd.cfg @@ -0,0 +1,7 @@ +source [find interface/stlink.cfg] + +transport select hla_swd + +source [find target/stm32wbx.cfg] + +reset_config srst_only From 4ce0555d90a20d2878ae086fd3dbb89cd7f2c447 Mon Sep 17 00:00:00 2001 From: Talha Can Havadar Date: Tue, 1 Nov 2022 10:57:47 +0100 Subject: [PATCH 2783/3723] drivers: bmp581: Add BMP581 driver MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This commit adds source and header files required for bmp581 I2C driver. I have used bmp581_user.h to add more usage related definitions but bmp581.h to add hardware related definitions. Signed-off-by: Talha Can Havadar Signed-off-by: Gerhard Jörges --- drivers/sensor/CMakeLists.txt | 1 + drivers/sensor/Kconfig | 1 + drivers/sensor/bmp581/CMakeLists.txt | 8 + drivers/sensor/bmp581/Kconfig | 11 + drivers/sensor/bmp581/bmp581.c | 560 ++++++++++++++++++++ drivers/sensor/bmp581/bmp581.h | 318 +++++++++++ dts/bindings/sensor/bosch,bmp581.yml | 16 + include/zephyr/drivers/sensor/bmp581_user.h | 95 ++++ tests/drivers/build_all/sensor/i2c.dtsi | 6 + 9 files changed, 1016 insertions(+) create mode 100644 drivers/sensor/bmp581/CMakeLists.txt create mode 100644 drivers/sensor/bmp581/Kconfig create mode 100644 drivers/sensor/bmp581/bmp581.c create mode 100644 drivers/sensor/bmp581/bmp581.h create mode 100644 dts/bindings/sensor/bosch,bmp581.yml create mode 100644 include/zephyr/drivers/sensor/bmp581_user.h diff --git a/drivers/sensor/CMakeLists.txt b/drivers/sensor/CMakeLists.txt index 467f7a48094..a2c3a0f34cb 100644 --- a/drivers/sensor/CMakeLists.txt +++ b/drivers/sensor/CMakeLists.txt @@ -30,6 +30,7 @@ add_subdirectory_ifdef(CONFIG_BMI270 bmi270) add_subdirectory_ifdef(CONFIG_BMI323 bmi323) add_subdirectory_ifdef(CONFIG_BMM150 bmm150) add_subdirectory_ifdef(CONFIG_BMP388 bmp388) +add_subdirectory_ifdef(CONFIG_BMP581 bmp581) add_subdirectory_ifdef(CONFIG_BQ274XX bq274xx) add_subdirectory_ifdef(CONFIG_CCS811 ccs811) add_subdirectory_ifdef(CONFIG_CURRENT_AMP current_amp) diff --git a/drivers/sensor/Kconfig b/drivers/sensor/Kconfig index d135df369b9..4a446e59783 100644 --- a/drivers/sensor/Kconfig +++ b/drivers/sensor/Kconfig @@ -110,6 +110,7 @@ source "drivers/sensor/bmi270/Kconfig" source "drivers/sensor/bmi323/Kconfig" source "drivers/sensor/bmm150/Kconfig" source "drivers/sensor/bmp388/Kconfig" +source "drivers/sensor/bmp581/Kconfig" source "drivers/sensor/bq274xx/Kconfig" source "drivers/sensor/ccs811/Kconfig" source "drivers/sensor/current_amp/Kconfig" diff --git a/drivers/sensor/bmp581/CMakeLists.txt b/drivers/sensor/bmp581/CMakeLists.txt new file mode 100644 index 00000000000..2f471fda359 --- /dev/null +++ b/drivers/sensor/bmp581/CMakeLists.txt @@ -0,0 +1,8 @@ +# +# Copyright (c) 2022 Badgerd Technologies B.V and its affiliates +# +# SPDX-License-Identifier: Apache-2.0 +# + +zephyr_library() +zephyr_library_sources(bmp581.c) diff --git a/drivers/sensor/bmp581/Kconfig b/drivers/sensor/bmp581/Kconfig new file mode 100644 index 00000000000..325276b7a97 --- /dev/null +++ b/drivers/sensor/bmp581/Kconfig @@ -0,0 +1,11 @@ +# +# Copyright (c) 2022 Badgerd Technologies B.V and its affiliates +# +# SPDX-License-Identifier: Apache-2.0 +# + +config BMP581 + bool "BMP581 barometric pressure sensor" + depends on DT_HAS_BOSCH_BMP581_ENABLED + select I2C + default y diff --git a/drivers/sensor/bmp581/bmp581.c b/drivers/sensor/bmp581/bmp581.c new file mode 100644 index 00000000000..9989f51d0ad --- /dev/null +++ b/drivers/sensor/bmp581/bmp581.c @@ -0,0 +1,560 @@ +/* + * Copyright (c) 2022 Badgerd Technologies B.V. + * Copyright (c) 2023 Metratec GmbH + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include "bmp581.h" + +#include + +#include +#include +#include +#include +#include +#include +#include + +LOG_MODULE_REGISTER(bmp581, CONFIG_SENSOR_LOG_LEVEL); + +#if DT_NUM_INST_STATUS_OKAY(DT_DRV_COMPAT) == 0 +#warning "BMP581 driver enabled without any devices" +#endif + +static int power_up_check(const struct device *dev); +static int get_nvm_status(uint8_t *nvm_status, const struct device *dev); +static int get_interrupt_status(uint8_t *int_status, const struct device *dev); +static int validate_chip_id(struct bmp581_data *drv); +static int get_osr_odr_press_config(struct bmp581_osr_odr_press_config *osr_odr_press_cfg, + const struct device *dev); +static int set_osr_config(const struct sensor_value *osr, enum sensor_channel chan, + const struct device *dev); +static int set_odr_config(const struct sensor_value *odr, const struct device *dev); +static int soft_reset(const struct device *dev); +static int set_iir_config(const struct sensor_value *iir, const struct device *dev); +static int get_power_mode(enum bmp5_powermode *powermode, const struct device *dev); +static int set_power_mode(enum bmp5_powermode powermode, const struct device *dev); + +static int set_power_mode(enum bmp5_powermode powermode, const struct device *dev) +{ + struct bmp581_config *conf = (struct bmp581_config *)dev->config; + int ret = BMP5_OK; + uint8_t odr = 0; + enum bmp5_powermode current_powermode; + + CHECKIF(dev == NULL) { + return -EINVAL; + } + + ret = get_power_mode(¤t_powermode, dev); + if (ret != BMP5_OK) { + LOG_ERR("Couldnt set the power mode because something went wrong when getting the " + "current power mode."); + return ret; + } + + if (current_powermode != BMP5_POWERMODE_STANDBY) { + /* + * Device should be set to standby before transitioning to forced mode or normal + * mode or continuous mode. + */ + + ret = i2c_reg_read_byte_dt(&conf->i2c, BMP5_REG_ODR_CONFIG, &odr); + if (ret == BMP5_OK) { + /* Setting deep_dis = 1(BMP5_DEEP_DISABLED) disables the deep standby mode + */ + odr = BMP5_SET_BITSLICE(odr, BMP5_DEEP_DISABLE, BMP5_DEEP_DISABLED); + odr = BMP5_SET_BITS_POS_0(odr, BMP5_POWERMODE, BMP5_POWERMODE_STANDBY); + ret = i2c_reg_write_byte_dt(&conf->i2c, BMP5_REG_ODR_CONFIG, odr); + + if (ret != BMP5_OK) { + LOG_DBG("Failed to set power mode to BMP5_POWERMODE_STANDBY."); + return ret; + } + } + } + + /* lets update the power mode */ + switch (powermode) { + case BMP5_POWERMODE_STANDBY: + /* this change is already done so we can just return */ + ret = BMP5_OK; + break; + case BMP5_POWERMODE_DEEP_STANDBY: + LOG_DBG("Setting power mode to DEEP STANDBY is not supported, current power mode " + "is BMP5_POWERMODE_STANDBY."); + ret = -ENOTSUP; + break; + case BMP5_POWERMODE_NORMAL: + case BMP5_POWERMODE_FORCED: + case BMP5_POWERMODE_CONTINUOUS: + odr = BMP5_SET_BITSLICE(odr, BMP5_DEEP_DISABLE, BMP5_DEEP_DISABLED); + odr = BMP5_SET_BITS_POS_0(odr, BMP5_POWERMODE, powermode); + ret = i2c_reg_write_byte_dt(&conf->i2c, BMP5_REG_ODR_CONFIG, odr); + break; + default: + /* invalid power mode */ + ret = -EINVAL; + break; + } + + return ret; +} + +static int get_power_mode(enum bmp5_powermode *powermode, const struct device *dev) +{ + struct bmp581_config *conf = (struct bmp581_config *)dev->config; + int ret = BMP5_OK; + + CHECKIF(powermode == NULL || dev == NULL) { + return -EINVAL; + } + + uint8_t reg = 0; + uint8_t raw_power_mode = 0; + + ret = i2c_reg_read_byte_dt(&conf->i2c, BMP5_REG_ODR_CONFIG, ®); + if (ret != BMP5_OK) { + LOG_DBG("Failed to read odr config to get power mode!"); + return ret; + } + + raw_power_mode = BMP5_GET_BITS_POS_0(reg, BMP5_POWERMODE); + + switch (raw_power_mode) { + case BMP5_POWERMODE_STANDBY: { + /* Getting deep disable status */ + uint8_t deep_dis = BMP5_GET_BITSLICE(reg, BMP5_DEEP_DISABLE); + + /* Checking deepstandby status only when powermode is in standby mode */ + + /* If deep_dis = 0(BMP5_DEEP_ENABLED) then deepstandby mode is enabled. + * If deep_dis = 1(BMP5_DEEP_DISABLED) then deepstandby mode is disabled + */ + if (deep_dis == BMP5_DEEP_ENABLED) { + /* TODO: check if it is really deep standby */ + *powermode = BMP5_POWERMODE_DEEP_STANDBY; + } else { + *powermode = BMP5_POWERMODE_STANDBY; + } + + break; + } + case BMP5_POWERMODE_NORMAL: + *powermode = BMP5_POWERMODE_NORMAL; + break; + case BMP5_POWERMODE_FORCED: + *powermode = BMP5_POWERMODE_FORCED; + break; + case BMP5_POWERMODE_CONTINUOUS: + *powermode = BMP5_POWERMODE_CONTINUOUS; + break; + default: + /* invalid power mode */ + ret = -EINVAL; + LOG_DBG("Something went wrong invalid powermode!"); + break; + } + + return ret; +} + +static int power_up_check(const struct device *dev) +{ + int8_t rslt = 0; + uint8_t nvm_status = 0; + + CHECKIF(dev == NULL) { + return -EINVAL; + } + + rslt = get_nvm_status(&nvm_status, dev); + + if (rslt == BMP5_OK) { + /* Check if nvm_rdy status = 1 and nvm_err status = 0 to proceed */ + if ((nvm_status & BMP5_INT_NVM_RDY) && (!(nvm_status & BMP5_INT_NVM_ERR))) { + rslt = BMP5_OK; + } else { + rslt = -EFAULT; + } + } + + return rslt; +} + +static int get_interrupt_status(uint8_t *int_status, const struct device *dev) +{ + struct bmp581_config *conf = (struct bmp581_config *)dev->config; + + CHECKIF(int_status == NULL || dev == NULL) { + return -EINVAL; + } + + return i2c_reg_read_byte_dt(&conf->i2c, BMP5_REG_INT_STATUS, int_status); +} + +static int get_nvm_status(uint8_t *nvm_status, const struct device *dev) +{ + struct bmp581_config *conf = (struct bmp581_config *)dev->config; + + CHECKIF(nvm_status == NULL || dev == NULL) { + return -EINVAL; + } + + return i2c_reg_read_byte_dt(&conf->i2c, BMP5_REG_STATUS, nvm_status); +} + +static int validate_chip_id(struct bmp581_data *drv) +{ + int8_t rslt = 0; + + CHECKIF(drv == NULL) { + return -EINVAL; + } + + if ((drv->chip_id == BMP5_CHIP_ID_PRIM) || (drv->chip_id == BMP5_CHIP_ID_SEC)) { + rslt = BMP5_OK; + } else { + drv->chip_id = 0; + rslt = -ENODEV; + } + + return rslt; +} + +/*! + * This API gets the configuration for oversampling of temperature, oversampling of + * pressure and ODR configuration along with pressure enable. + */ +static int get_osr_odr_press_config(struct bmp581_osr_odr_press_config *osr_odr_press_cfg, + const struct device *dev) +{ + struct bmp581_config *conf = (struct bmp581_config *)dev->config; + + /* Variable to store the function result */ + int8_t rslt = 0; + + /* Variable to store OSR and ODR config */ + uint8_t reg_data[2] = {0}; + + CHECKIF(osr_odr_press_cfg == NULL || dev == NULL) { + return -EINVAL; + } + + /* Get OSR and ODR configuration in burst read */ + rslt = i2c_burst_read_dt(&conf->i2c, BMP5_REG_OSR_CONFIG, reg_data, 2); + + if (rslt == BMP5_OK) { + osr_odr_press_cfg->osr_t = BMP5_GET_BITS_POS_0(reg_data[0], BMP5_TEMP_OS); + osr_odr_press_cfg->osr_p = BMP5_GET_BITSLICE(reg_data[0], BMP5_PRESS_OS); + osr_odr_press_cfg->press_en = BMP5_GET_BITSLICE(reg_data[0], BMP5_PRESS_EN); + osr_odr_press_cfg->odr = BMP5_GET_BITSLICE(reg_data[1], BMP5_ODR); + } + + return rslt; +} + +static int set_osr_config(const struct sensor_value *osr, enum sensor_channel chan, + const struct device *dev) +{ + CHECKIF(osr == NULL || dev == NULL) { + return -EINVAL; + } + + struct bmp581_data *drv = (struct bmp581_data *)dev->data; + struct bmp581_config *conf = (struct bmp581_config *)dev->config; + int ret = 0; + + uint8_t oversampling = osr->val1; + uint8_t press_en = osr->val2 != 0; /* if it is not 0 then pressure is enabled */ + uint8_t osr_val = 0; + + ret = i2c_reg_read_byte_dt(&conf->i2c, BMP5_REG_OSR_CONFIG, &osr_val); + if (ret == BMP5_OK) { + switch (chan) { + case SENSOR_CHAN_ALL: + osr_val = BMP5_SET_BITS_POS_0(osr_val, BMP5_TEMP_OS, oversampling); + osr_val = BMP5_SET_BITSLICE(osr_val, BMP5_PRESS_OS, oversampling); + osr_val = BMP5_SET_BITSLICE(osr_val, BMP5_PRESS_EN, press_en); + break; + case SENSOR_CHAN_PRESS: + osr_val = BMP5_SET_BITSLICE(osr_val, BMP5_PRESS_OS, oversampling); + osr_val = BMP5_SET_BITSLICE(osr_val, BMP5_PRESS_EN, press_en); + break; + case SENSOR_CHAN_AMBIENT_TEMP: + osr_val = BMP5_SET_BITS_POS_0(osr_val, BMP5_TEMP_OS, oversampling); + break; + default: + ret = -ENOTSUP; + break; + } + + if (ret == BMP5_OK) { + ret = i2c_reg_write_byte_dt(&conf->i2c, BMP5_REG_OSR_CONFIG, osr_val); + get_osr_odr_press_config(&drv->osr_odr_press_config, dev); + } + } + + return ret; +} + +static int set_odr_config(const struct sensor_value *odr, const struct device *dev) +{ + CHECKIF(odr == NULL || dev == NULL) { + return -EINVAL; + } + + struct bmp581_data *drv = (struct bmp581_data *)dev->data; + struct bmp581_config *conf = (struct bmp581_config *)dev->config; + int ret = 0; + uint8_t odr_val = 0; + + ret = i2c_reg_read_byte_dt(&conf->i2c, BMP5_REG_ODR_CONFIG, &odr_val); + if (ret != BMP5_OK) { + return ret; + } + odr_val = BMP5_SET_BITSLICE(odr_val, BMP5_ODR, odr->val1); + ret = i2c_reg_write_byte_dt(&conf->i2c, BMP5_REG_ODR_CONFIG, odr_val); + get_osr_odr_press_config(&drv->osr_odr_press_config, dev); + + return ret; +} + +static int soft_reset(const struct device *dev) +{ + struct bmp581_config *conf = (struct bmp581_config *)dev->config; + int ret = 0; + const uint8_t reset_cmd = BMP5_SOFT_RESET_CMD; + uint8_t int_status = 0; + + CHECKIF(dev == NULL) { + return -EINVAL; + } + + ret = i2c_reg_write_byte_dt(&conf->i2c, BMP5_REG_CMD, reset_cmd); + + if (ret == BMP5_OK) { + k_usleep(BMP5_DELAY_US_SOFT_RESET); + ret = get_interrupt_status(&int_status, dev); + if (ret == BMP5_OK) { + if (int_status & BMP5_INT_ASSERTED_POR_SOFTRESET_COMPLETE) { + ret = BMP5_OK; + } else { + ret = -EFAULT; + } + } + } else { + LOG_DBG("Failed perform soft-reset."); + } + + return ret; +} + +static int bmp581_sample_fetch(const struct device *dev, enum sensor_channel chan) +{ + CHECKIF(dev == NULL) { + return -EINVAL; + } + + if (chan != SENSOR_CHAN_ALL) { + return -ENOTSUP; + } + + struct bmp581_data *drv = (struct bmp581_data *)dev->data; + struct bmp581_config *conf = (struct bmp581_config *)dev->config; + uint8_t data[6]; + int ret = 0; + + ret = i2c_burst_read_dt(&conf->i2c, BMP5_REG_TEMP_DATA_XLSB, data, 6); + if (ret == BMP5_OK) { + /* convert raw sensor data to sensor_value. Shift the decimal part by 1 decimal + * place to compensate for the conversion in sensor_value_to_double() + */ + drv->last_sample.temperature.val1 = data[2]; + drv->last_sample.temperature.val2 = (data[1] << 8 | data[0]) * 10; + + if (drv->osr_odr_press_config.press_en == BMP5_ENABLE) { + uint32_t raw_pressure = (uint32_t)((uint32_t)(data[5] << 16) | + (uint16_t)(data[4] << 8) | data[3]); + /* convert raw sensor data to sensor_value. Shift the decimal part by + * 4 decimal places to compensate for the conversion in + * sensor_value_to_double() + */ + drv->last_sample.pressure.val1 = raw_pressure >> 6; + drv->last_sample.pressure.val2 = (raw_pressure & BIT_MASK(6)) * 10000; + } else { + drv->last_sample.pressure.val1 = 0; + drv->last_sample.pressure.val2 = 0; + } + } + + return ret; +} + +static int bmp581_channel_get(const struct device *dev, enum sensor_channel chan, + struct sensor_value *val) +{ + CHECKIF(dev == NULL || val == NULL) { + return -EINVAL; + } + + struct bmp581_data *drv = (struct bmp581_data *)dev->data; + + switch (chan) { + case SENSOR_CHAN_PRESS: + /* returns pressure in Pa */ + *val = drv->last_sample.pressure; + return BMP5_OK; + case SENSOR_CHAN_AMBIENT_TEMP: + /* returns temperature in Celcius */ + *val = drv->last_sample.temperature; + return BMP5_OK; + default: + return -ENOTSUP; + } +} + +static int set_iir_config(const struct sensor_value *iir, const struct device *dev) +{ + struct bmp581_config *conf = (struct bmp581_config *)dev->config; + int ret = BMP5_OK; + + CHECKIF((iir == NULL) | (dev == NULL)) { + return -EINVAL; + } + + /* Variable to store existing powermode */ + enum bmp5_powermode prev_powermode; + + ret = get_power_mode(&prev_powermode, dev); + if (ret != BMP5_OK) { + LOG_DBG("Not able to get current power mode."); + return ret; + } + /* IIR configuration is writable only during STANDBY mode(as per datasheet) */ + set_power_mode(BMP5_POWERMODE_STANDBY, dev); + + /* update IIR config */ + uint8_t dsp_config[2]; + + ret = i2c_burst_read_dt(&conf->i2c, BMP5_REG_DSP_CONFIG, dsp_config, 2); + if (ret != BMP5_OK) { + LOG_DBG("Failed to read dsp config register."); + return ret; + } + /* Put IIR filtered values in data registers */ + dsp_config[0] = BMP5_SET_BITSLICE(dsp_config[0], BMP5_SHDW_SET_IIR_TEMP, BMP5_ENABLE); + dsp_config[0] = BMP5_SET_BITSLICE(dsp_config[0], BMP5_SHDW_SET_IIR_PRESS, BMP5_ENABLE); + + /* Configure IIR filter */ + dsp_config[1] = iir->val1; + dsp_config[1] = BMP5_SET_BITSLICE(dsp_config[1], BMP5_SET_IIR_PRESS, iir->val2); + + /* Set IIR configuration */ + ret = i2c_burst_write_dt(&conf->i2c, BMP5_REG_DSP_CONFIG, dsp_config, 2); + + if (ret != BMP5_OK) { + LOG_DBG("Failed to configure IIR filter."); + return ret; + } + + /* Restore previous power mode if it is not standby already */ + if (prev_powermode != BMP5_POWERMODE_STANDBY) { + ret = set_power_mode(prev_powermode, dev); + } + + return ret; +} + +static int bmp581_attr_set(const struct device *dev, enum sensor_channel chan, + enum sensor_attribute attr, const struct sensor_value *val) +{ + CHECKIF(dev == NULL || val == NULL) { + return -EINVAL; + } + + int ret; + + switch ((int)attr) { + case SENSOR_ATTR_SAMPLING_FREQUENCY: + ret = set_odr_config(val, dev); + break; + case SENSOR_ATTR_OVERSAMPLING: + ret = set_osr_config(val, chan, dev); + break; + case BMP5_ATTR_POWER_MODE: { + enum bmp5_powermode powermode = (enum bmp5_powermode)val->val1; + + ret = set_power_mode(powermode, dev); + break; + } + case BMP5_ATTR_IIR_CONFIG: + ret = set_iir_config(val, dev); + break; + default: + ret = -ENOTSUP; + break; + } + return ret; +} + +static int bmp581_init(const struct device *dev) +{ + CHECKIF(dev == NULL) { + return -EINVAL; + } + + struct bmp581_data *drv = (struct bmp581_data *)dev->data; + struct bmp581_config *conf = (struct bmp581_config *)dev->config; + int ret = -1; + + /* Reset the chip id. */ + drv->chip_id = 0; + memset(&drv->osr_odr_press_config, 0, sizeof(drv->osr_odr_press_config)); + memset(&drv->last_sample, 0, sizeof(drv->last_sample)); + + soft_reset(dev); + + ret = i2c_reg_read_byte_dt(&conf->i2c, BMP5_REG_CHIP_ID, &drv->chip_id); + if (ret != BMP5_OK) { + return ret; + } + + if (drv->chip_id != 0) { + ret = power_up_check(dev); + if (ret == BMP5_OK) { + ret = validate_chip_id(drv); + if (ret != BMP5_OK) { + LOG_ERR("Unexpected chip id (%x). Expected (%x or %x)", + drv->chip_id, BMP5_CHIP_ID_PRIM, BMP5_CHIP_ID_SEC); + } + } + } else { + /* that means something went wrong */ + LOG_ERR("Unexpected chip id (%x). Expected (%x or %x)", drv->chip_id, + BMP5_CHIP_ID_PRIM, BMP5_CHIP_ID_SEC); + return -EINVAL; + } + return ret; +} + +static const struct sensor_driver_api bmp581_driver_api = {.sample_fetch = bmp581_sample_fetch, + .channel_get = bmp581_channel_get, + .attr_set = bmp581_attr_set}; + +#define BMP581_CONFIG(i) \ + static const struct bmp581_config bmp581_config_##i = { \ + .i2c = I2C_DT_SPEC_INST_GET(i), \ + } + +#define BMP581_INIT(i) \ + static struct bmp581_data bmp581_data_##i; \ + BMP581_CONFIG(i); \ + \ + SENSOR_DEVICE_DT_INST_DEFINE(i, bmp581_init, NULL, &bmp581_data_##i, &bmp581_config_##i, \ + POST_KERNEL, CONFIG_SENSOR_INIT_PRIORITY, \ + &bmp581_driver_api); + +DT_INST_FOREACH_STATUS_OKAY(BMP581_INIT) diff --git a/drivers/sensor/bmp581/bmp581.h b/drivers/sensor/bmp581/bmp581.h new file mode 100644 index 00000000000..cdbe7f7e0b8 --- /dev/null +++ b/drivers/sensor/bmp581/bmp581.h @@ -0,0 +1,318 @@ +/* + * Copyright (c) 2022 Badgerd Technologies B.V. + * + * SPDX-License-Identifier: Apache-2.0 + * + * Driver is developed to be used with Zephyr. And it only supports i2c interface. + * + * Author: Talha Can Havadar + * + */ + +#ifndef ZEPHYR_DRIVERS_SENSOR_BMP581_BMP581_H_ +#define ZEPHYR_DRIVERS_SENSOR_BMP581_BMP581_H_ + +#include +#include +#include +#include +#include +#include +#include + +#define DT_DRV_COMPAT bosch_bmp581 + +/* UTILITY MACROS */ +#define BMP5_SET_LOW_BYTE 0x00FFu +#define BMP5_SET_HIGH_BYTE 0xFF00u + +/* BIT SLICE GET AND SET FUNCTIONS */ +#define BMP5_GET_BITSLICE(regvar, bitname) ((regvar & bitname##_MSK) >> bitname##_POS) + +#define BMP5_SET_BITSLICE(regvar, bitname, val) \ + ((regvar & ~bitname##_MSK) | ((val << bitname##_POS) & bitname##_MSK)) + +#define BMP5_GET_LSB(var) (uint8_t)(var & BMP5_SET_LOW_BYTE) +#define BMP5_GET_MSB(var) (uint8_t)((var & BMP5_SET_HIGH_BYTE) >> 8) + +#define BMP5_SET_BIT_VAL_0(reg_data, bitname) (reg_data & ~(bitname##_MSK)) + +#define BMP5_SET_BITS_POS_0(reg_data, bitname, data) \ + ((reg_data & ~(bitname##_MSK)) | (data & bitname##_MSK)) + +#define BMP5_GET_BITS_POS_0(reg_data, bitname) (reg_data & (bitname##_MSK)) + +#define BMP5_OK 0 +#define BMP5_ENABLE 1u +#define BMP5_DISABLE 0u + +/* BMP5 Registers */ +#define BMP5_REG_CHIP_ID 0x01 +#define BMP5_REG_REV_ID 0x02 +#define BMP5_REG_CHIP_STATUS 0x11 +#define BMP5_REG_DRIVE_CONFIG 0x13 +#define BMP5_REG_INT_CONFIG 0x14 +#define BMP5_REG_INT_SOURCE 0x15 +#define BMP5_REG_FIFO_CONFIG 0x16 +#define BMP5_REG_FIFO_COUNT 0x17 +#define BMP5_REG_FIFO_SEL 0x18 +#define BMP5_REG_TEMP_DATA_XLSB 0x1D +#define BMP5_REG_TEMP_DATA_LSB 0x1E +#define BMP5_REG_TEMP_DATA_MSB 0x1F +#define BMP5_REG_PRESS_DATA_XLSB 0x20 +#define BMP5_REG_PRESS_DATA_LSB 0x21 +#define BMP5_REG_PRESS_DATA_MSB 0x22 +#define BMP5_REG_INT_STATUS 0x27 +#define BMP5_REG_STATUS 0x28 +#define BMP5_REG_FIFO_DATA 0x29 +#define BMP5_REG_NVM_ADDR 0x2B +#define BMP5_REG_NVM_DATA_LSB 0x2C +#define BMP5_REG_NVM_DATA_MSB 0x2D +#define BMP5_REG_DSP_CONFIG 0x30 +#define BMP5_REG_DSP_IIR 0x31 +#define BMP5_REG_OOR_THR_P_LSB 0x32 +#define BMP5_REG_OOR_THR_P_MSB 0x33 +#define BMP5_REG_OOR_RANGE 0x34 +#define BMP5_REG_OOR_CONFIG 0x35 +#define BMP5_REG_OSR_CONFIG 0x36 +#define BMP5_REG_ODR_CONFIG 0x37 +#define BMP5_REG_OSR_EFF 0x38 +#define BMP5_REG_CMD 0x7E +/* endof BMP5 Registers */ + +/* Chip id of BMP5 */ +#define BMP5_CHIP_ID_PRIM 0x50 +#define BMP5_CHIP_ID_SEC 0x51 + +/* I2C addresses */ +#define BMP5_I2C_ADDR_PRIM 0x46 +#define BMP5_I2C_ADDR_SEC 0x47 + +/* NVM addresses */ +#define BMP5_NVM_START_ADDR 0x20 +#define BMP5_NVM_END_ADDR 0x22 + +/* Interface settings */ +#define BMP5_SPI_RD_MASK 0x80 + +/* Delay definition */ +#define BMP5_DELAY_US_SOFT_RESET 2000 +#define BMP5_DELAY_US_STANDBY 2500 +#define BMP5_DELAY_US_NVM_READY_READ 800 +#define BMP5_DELAY_US_NVM_READY_WRITE 10000 + +/* Soft reset command */ +#define BMP5_SOFT_RESET_CMD 0xB6 + +/*! NVM command */ +#define BMP5_NVM_FIRST_CMND 0x5D +#define BMP5_NVM_READ_ENABLE_CMND 0xA5 +#define BMP5_NVM_WRITE_ENABLE_CMND 0xA0 + +/* Deepstandby enable/disable */ +#define BMP5_DEEP_ENABLED 0 +#define BMP5_DEEP_DISABLED 1 + +/*! Fifo frame configuration */ +#define BMP5_FIFO_EMPTY 0X7F +#define BMP5_FIFO_MAX_THRESHOLD_P_T_MODE 0x0F +#define BMP5_FIFO_MAX_THRESHOLD_P_MODE 0x1F + +/* Macro is used to bypass both iir_t and iir_p together */ +#define BMP5_IIR_BYPASS 0xC0 + +/* Pressure Out-of-range count limit */ +#define BMP5_OOR_COUNT_LIMIT_1 0x00 +#define BMP5_OOR_COUNT_LIMIT_3 0x01 +#define BMP5_OOR_COUNT_LIMIT_7 0x02 +#define BMP5_OOR_COUNT_LIMIT_15 0x03 + +/* Interrupt configurations */ +#define BMP5_INT_MODE_PULSED 0 +#define BMP5_INT_MODE_LATCHED 1 + +#define BMP5_INT_POL_ACTIVE_LOW 0 +#define BMP5_INT_POL_ACTIVE_HIGH 1 + +#define BMP5_INT_OD_PUSHPULL 0 +#define BMP5_INT_OD_OPENDRAIN 1 + +/* NVM and Interrupt status asserted macros */ +#define BMP5_INT_ASSERTED_DRDY 0x01 +#define BMP5_INT_ASSERTED_FIFO_FULL 0x02 +#define BMP5_INT_ASSERTED_FIFO_THRES 0x04 +#define BMP5_INT_ASSERTED_PRESSURE_OOR 0x08 +#define BMP5_INT_ASSERTED_POR_SOFTRESET_COMPLETE 0x10 +#define BMP5_INT_NVM_RDY 0x02 +#define BMP5_INT_NVM_ERR 0x04 +#define BMP5_INT_NVM_CMD_ERR 0x08 + +/* Interrupt configurations */ +#define BMP5_INT_MODE_MSK 0x01 + +#define BMP5_INT_POL_MSK 0x02 +#define BMP5_INT_POL_POS 1 + +#define BMP5_INT_OD_MSK 0x04 +#define BMP5_INT_OD_POS 2 + +#define BMP5_INT_EN_MSK 0x08 +#define BMP5_INT_EN_POS 3 + +#define BMP5_INT_DRDY_EN_MSK 0x01 + +#define BMP5_INT_FIFO_FULL_EN_MSK 0x02 +#define BMP5_INT_FIFO_FULL_EN_POS 1 + +#define BMP5_INT_FIFO_THRES_EN_MSK 0x04 +#define BMP5_INT_FIFO_THRES_EN_POS 2 + +#define BMP5_INT_OOR_PRESS_EN_MSK 0x08 +#define BMP5_INT_OOR_PRESS_EN_POS 3 + +/* ODR configuration */ +#define BMP5_ODR_MSK 0x7C +#define BMP5_ODR_POS 2 + +/* OSR configurations */ +#define BMP5_TEMP_OS_MSK 0x07 + +#define BMP5_PRESS_OS_MSK 0x38 +#define BMP5_PRESS_OS_POS 3 + +/* Pressure enable */ +#define BMP5_PRESS_EN_MSK 0x40 +#define BMP5_PRESS_EN_POS 6 + +/* IIR configurations */ +#define BMP5_SET_IIR_TEMP_MSK 0x07 + +#define BMP5_SET_IIR_PRESS_MSK 0x38 +#define BMP5_SET_IIR_PRESS_POS 3 + +#define BMP5_OOR_SEL_IIR_PRESS_MSK 0x80 +#define BMP5_OOR_SEL_IIR_PRESS_POS 7 + +#define BMP5_SHDW_SET_IIR_TEMP_MSK 0x08 +#define BMP5_SHDW_SET_IIR_TEMP_POS 3 + +#define BMP5_SHDW_SET_IIR_PRESS_MSK 0x20 +#define BMP5_SHDW_SET_IIR_PRESS_POS 5 + +#define BMP5_SET_FIFO_IIR_TEMP_MSK 0x10 +#define BMP5_SET_FIFO_IIR_TEMP_POS 4 + +#define BMP5_SET_FIFO_IIR_PRESS_MSK 0x40 +#define BMP5_SET_FIFO_IIR_PRESS_POS 6 + +#define BMP5_IIR_FLUSH_FORCED_EN_MSK 0x04 +#define BMP5_IIR_FLUSH_FORCED_EN_POS 2 + +/* Effective OSR configurations and ODR valid status */ +#define BMP5_OSR_TEMP_EFF_MSK 0x07 + +#define BMP5_OSR_PRESS_EFF_MSK 0x38 +#define BMP5_OSR_PRESS_EFF_POS 3 + +#define BMP5_ODR_IS_VALID_MSK 0x80 +#define BMP5_ODR_IS_VALID_POS 7 + +/* Powermode */ +#define BMP5_POWERMODE_MSK 0x03 + +#define BMP5_DEEP_DISABLE_MSK 0x80 +#define BMP5_DEEP_DISABLE_POS 7 + +/* Fifo configurations */ +#define BMP5_FIFO_THRESHOLD_MSK 0x1F + +#define BMP5_FIFO_MODE_MSK 0x20 +#define BMP5_FIFO_MODE_POS 5 + +#define BMP5_FIFO_DEC_SEL_MSK 0x1C +#define BMP5_FIFO_DEC_SEL_POS 2 + +#define BMP5_FIFO_COUNT_MSK 0x3F + +#define BMP5_FIFO_FRAME_SEL_MSK 0x03 + +/* Out-of-range configuration */ +#define BMP5_OOR_THR_P_LSB_MSK 0x0000FF + +#define BMP5_OOR_THR_P_MSB_MSK 0x00FF00 + +#define BMP5_OOR_THR_P_XMSB_MSK 0x010000 +#define BMP5_OOR_THR_P_XMSB_POS 16 + +/* Macro to mask xmsb value of oor threshold from register(0x35) value */ +#define BMP5_OOR_THR_P_XMSB_REG_MSK 0x01 + +#define BMP5_OOR_COUNT_LIMIT_MSK 0xC0 +#define BMP5_OOR_COUNT_LIMIT_POS 6 + +/* NVM configuration */ +#define BMP5_NVM_ADDR_MSK 0x3F + +#define BMP5_NVM_PROG_EN_MSK 0x40 +#define BMP5_NVM_PROG_EN_POS 6 + +#define BMP5_NVM_DATA_LSB_MSK 0x00FF + +#define BMP5_NVM_DATA_MSB_MSK 0xFF00 + +/*! + * @brief OSR, ODR and pressure configuration structure + */ +struct bmp581_osr_odr_press_config { + /*! Temperature oversampling + * Assignable macros : + * - BMP5_OVERSAMPLING_1X + * - BMP5_OVERSAMPLING_2X + * - BMP5_OVERSAMPLING_4X + * - BMP5_OVERSAMPLING_8X + * - BMP5_OVERSAMPLING_16X + * - BMP5_OVERSAMPLING_32X + * - BMP5_OVERSAMPLING_64X + * - BMP5_OVERSAMPLING_128X + */ + uint8_t osr_t; + + /*! Pressure oversampling + * Assignable macros : + * - BMP5_OVERSAMPLING_1X + * - BMP5_OVERSAMPLING_2X + * - BMP5_OVERSAMPLING_4X + * - BMP5_OVERSAMPLING_8X + * - BMP5_OVERSAMPLING_16X + * - BMP5_OVERSAMPLING_32X + * - BMP5_OVERSAMPLING_64X + * - BMP5_OVERSAMPLING_128X + */ + uint8_t osr_p; + + /*! Enable pressure + * BMP5_ENABLE = Enables pressure data + * BMP5_DISABLE = Disables pressure data + */ + uint8_t press_en; + + /*! Output Data Rate */ + uint8_t odr; +}; + +struct bmp581_sample { + struct sensor_value pressure; + struct sensor_value temperature; +}; + +struct bmp581_data { + uint8_t chip_id; + struct bmp581_sample last_sample; + struct bmp581_osr_odr_press_config osr_odr_press_config; +}; + +struct bmp581_config { + struct i2c_dt_spec i2c; +}; + +#endif /* ZEPHYR_DRIVERS_SENSOR_BMP581_BMP581_H_ */ diff --git a/dts/bindings/sensor/bosch,bmp581.yml b/dts/bindings/sensor/bosch,bmp581.yml new file mode 100644 index 00000000000..0d842142929 --- /dev/null +++ b/dts/bindings/sensor/bosch,bmp581.yml @@ -0,0 +1,16 @@ +description: | + The BMP581 is a Barometric pressure sensor. See more info at: + https://www.bosch-sensortec.com/products/environmental-sensors/pressure-sensors/bmp581/ + +compatible: "bosch,bmp581" + +include: [sensor-device.yaml, i2c-device.yaml] + +properties: + int-gpios: + type: phandle-array + required: false + description: Interrupt pin. + + The interrupt pin of BMP581 is open-drain, active low. If connected directly to the MCU, + the pin should be configured as pull-up, active low. diff --git a/include/zephyr/drivers/sensor/bmp581_user.h b/include/zephyr/drivers/sensor/bmp581_user.h new file mode 100644 index 00000000000..e0fd000c8c0 --- /dev/null +++ b/include/zephyr/drivers/sensor/bmp581_user.h @@ -0,0 +1,95 @@ +/* + * Copyright (c) 2022 Badgerd Technologies B.V. + * + * SPDX-License-Identifier: Apache-2.0 + * + * Driver is developed to be used with Zephyr. And it only supports i2c interface. + * + * Author: Talha Can Havadar + * + */ + +#ifndef ZEPHYR_INCLUDE_DRIVERS_SENSOR_BMP581_USER_H_ +#define ZEPHYR_INCLUDE_DRIVERS_SENSOR_BMP581_USER_H_ + +#include + +#define BMP5_SEA_LEVEL_PRESSURE_PA 101325 + +/* ODR settings */ +#define BMP5_ODR_240_HZ 0x00 +#define BMP5_ODR_218_5_HZ 0x01 +#define BMP5_ODR_199_1_HZ 0x02 +#define BMP5_ODR_179_2_HZ 0x03 +#define BMP5_ODR_160_HZ 0x04 +#define BMP5_ODR_149_3_HZ 0x05 +#define BMP5_ODR_140_HZ 0x06 +#define BMP5_ODR_129_8_HZ 0x07 +#define BMP5_ODR_120_HZ 0x08 +#define BMP5_ODR_110_1_HZ 0x09 +#define BMP5_ODR_100_2_HZ 0x0A +#define BMP5_ODR_89_6_HZ 0x0B +#define BMP5_ODR_80_HZ 0x0C +#define BMP5_ODR_70_HZ 0x0D +#define BMP5_ODR_60_HZ 0x0E +#define BMP5_ODR_50_HZ 0x0F +#define BMP5_ODR_45_HZ 0x10 +#define BMP5_ODR_40_HZ 0x11 +#define BMP5_ODR_35_HZ 0x12 +#define BMP5_ODR_30_HZ 0x13 +#define BMP5_ODR_25_HZ 0x14 +#define BMP5_ODR_20_HZ 0x15 +#define BMP5_ODR_15_HZ 0x16 +#define BMP5_ODR_10_HZ 0x17 +#define BMP5_ODR_05_HZ 0x18 +#define BMP5_ODR_04_HZ 0x19 +#define BMP5_ODR_03_HZ 0x1A +#define BMP5_ODR_02_HZ 0x1B +#define BMP5_ODR_01_HZ 0x1C +#define BMP5_ODR_0_5_HZ 0x1D +#define BMP5_ODR_0_250_HZ 0x1E +#define BMP5_ODR_0_125_HZ 0x1F + +/* Oversampling for temperature and pressure */ +#define BMP5_OVERSAMPLING_1X 0x00 +#define BMP5_OVERSAMPLING_2X 0x01 +#define BMP5_OVERSAMPLING_4X 0x02 +#define BMP5_OVERSAMPLING_8X 0x03 +#define BMP5_OVERSAMPLING_16X 0x04 +#define BMP5_OVERSAMPLING_32X 0x05 +#define BMP5_OVERSAMPLING_64X 0x06 +#define BMP5_OVERSAMPLING_128X 0x07 + +/* IIR filter for temperature and pressure */ +#define BMP5_IIR_FILTER_BYPASS 0x00 +#define BMP5_IIR_FILTER_COEFF_1 0x01 +#define BMP5_IIR_FILTER_COEFF_3 0x02 +#define BMP5_IIR_FILTER_COEFF_7 0x03 +#define BMP5_IIR_FILTER_COEFF_15 0x04 +#define BMP5_IIR_FILTER_COEFF_31 0x05 +#define BMP5_IIR_FILTER_COEFF_63 0x06 +#define BMP5_IIR_FILTER_COEFF_127 0x07 + +/* Custom ATTR values */ + +/* This is used to enable IIR config, + * keep in mind that disabling IIR back in runtime is not + * supported yet + */ +#define BMP5_ATTR_IIR_CONFIG (SENSOR_ATTR_PRIV_START + 1u) +#define BMP5_ATTR_POWER_MODE (SENSOR_ATTR_PRIV_START + 2u) + +enum bmp5_powermode { + /*! Standby powermode */ + BMP5_POWERMODE_STANDBY, + /*! Normal powermode */ + BMP5_POWERMODE_NORMAL, + /*! Forced powermode */ + BMP5_POWERMODE_FORCED, + /*! Continuous powermode */ + BMP5_POWERMODE_CONTINUOUS, + /*! Deep standby powermode */ + BMP5_POWERMODE_DEEP_STANDBY +}; + +#endif /* ZEPHYR_INCLUDE_DRIVERS_SENSOR_BMP581_USER_H_ */ diff --git a/tests/drivers/build_all/sensor/i2c.dtsi b/tests/drivers/build_all/sensor/i2c.dtsi index 7d684f42a37..4de9e954c1e 100644 --- a/tests/drivers/build_all/sensor/i2c.dtsi +++ b/tests/drivers/build_all/sensor/i2c.dtsi @@ -889,3 +889,9 @@ test_i2c_ags10: ags10@7e { compatible = "aosong,ags10"; reg = <0x7e>; }; + +test_i2c_bmp581: bmp581@7f { + compatible = "bosch,bmp581"; + reg = <0x7f>; + int-gpios = <&test_gpio 0 0>; +}; From d744719eb8513783b332fb5dc0352ea4bc920f41 Mon Sep 17 00:00:00 2001 From: Hake Huang Date: Fri, 29 Dec 2023 00:06:23 +0800 Subject: [PATCH 2784/3723] test: dma: fix dma code-data_relocation failure on nxp rt platforms NXP RT series DMA need use buffer in nocached area, so only use memory region relocated is not enough. fixing: #67053 Signed-off-by: Hake Huang --- .../chan_blen_transfer/boards/mimxrt1024_evk.conf | 3 +++ .../boards/mimxrt1024_evk.overlay | 7 +++++++ .../chan_blen_transfer/boards/mimxrt1050_evk.conf | 3 +++ .../boards/mimxrt1050_evk.overlay | 11 +++++++++-- .../chan_blen_transfer/boards/mimxrt1060_evk.conf | 3 +++ .../boards/mimxrt1060_evk.overlay | 7 +++++++ .../chan_blen_transfer/boards/mimxrt1060_evkb.conf | 3 +++ .../boards/mimxrt1060_evkb.overlay | 7 +++++++ .../chan_blen_transfer/boards/mimxrt1064_evk.conf | 3 +++ .../boards/mimxrt1064_evk.overlay | 7 +++++++ .../boards/mimxrt1160_evk_cm4.conf | 3 +++ .../boards/mimxrt1160_evk_cm4.overlay | 7 +++++++ .../boards/mimxrt1160_evk_cm7.conf | 3 +++ .../boards/mimxrt1160_evk_cm7.overlay | 7 +++++++ .../boards/mimxrt1170_evk_cm4.conf | 4 ++++ .../boards/mimxrt1170_evk_cm4.overlay | 7 +++++++ .../boards/mimxrt1170_evk_cm7.conf | 3 +++ .../boards/mimxrt1170_evk_cm7.overlay | 7 +++++++ .../boards/mimxrt1170_evkb_cm4.conf | 3 +++ .../boards/mimxrt1170_evkb_cm4.overlay | 9 ++++++++- .../boards/mimxrt595_evk_cm33.conf | 1 + .../boards/mimxrt685_evk_cm33.conf | 1 + .../dma/loop_transfer/boards/mimxrt1024_evk.conf | 3 +++ .../loop_transfer/boards/mimxrt1024_evk.overlay | 7 +++++++ .../dma/loop_transfer/boards/mimxrt1050_evk.conf | 3 +++ .../loop_transfer/boards/mimxrt1050_evk.overlay | 14 ++++++++++++++ .../dma/loop_transfer/boards/mimxrt1060_evk.conf | 3 +++ .../loop_transfer/boards/mimxrt1060_evk.overlay | 7 +++++++ .../dma/loop_transfer/boards/mimxrt1060_evkb.conf | 3 +++ .../loop_transfer/boards/mimxrt1060_evkb.overlay | 7 +++++++ .../dma/loop_transfer/boards/mimxrt1064_evk.conf | 3 +++ .../loop_transfer/boards/mimxrt1064_evk.overlay | 7 +++++++ .../loop_transfer/boards/mimxrt1160_evk_cm4.conf | 3 +++ .../boards/mimxrt1160_evk_cm4.overlay | 7 +++++++ .../loop_transfer/boards/mimxrt1160_evk_cm7.conf | 3 +++ .../boards/mimxrt1160_evk_cm7.overlay | 7 +++++++ .../loop_transfer/boards/mimxrt1170_evk_cm4.conf | 3 +++ .../boards/mimxrt1170_evk_cm4.overlay | 7 +++++++ .../loop_transfer/boards/mimxrt1170_evk_cm7.conf | 3 +++ .../boards/mimxrt1170_evk_cm7.overlay | 7 +++++++ .../loop_transfer/boards/mimxrt1170_evkb_cm4.conf | 3 +++ .../boards/mimxrt1170_evkb_cm4.overlay | 9 ++++++++- .../loop_transfer/boards/mimxrt1170_evkb_cm7.conf | 3 +++ 43 files changed, 217 insertions(+), 4 deletions(-) create mode 100644 tests/drivers/dma/chan_blen_transfer/boards/mimxrt1024_evk.conf create mode 100644 tests/drivers/dma/chan_blen_transfer/boards/mimxrt1050_evk.conf create mode 100644 tests/drivers/dma/chan_blen_transfer/boards/mimxrt1060_evk.conf create mode 100644 tests/drivers/dma/chan_blen_transfer/boards/mimxrt1060_evkb.conf create mode 100644 tests/drivers/dma/chan_blen_transfer/boards/mimxrt1064_evk.conf create mode 100644 tests/drivers/dma/chan_blen_transfer/boards/mimxrt1160_evk_cm4.conf create mode 100644 tests/drivers/dma/chan_blen_transfer/boards/mimxrt1160_evk_cm7.conf create mode 100644 tests/drivers/dma/chan_blen_transfer/boards/mimxrt1170_evk_cm4.conf create mode 100644 tests/drivers/dma/chan_blen_transfer/boards/mimxrt1170_evk_cm7.conf create mode 100644 tests/drivers/dma/chan_blen_transfer/boards/mimxrt1170_evkb_cm4.conf create mode 100644 tests/drivers/dma/chan_blen_transfer/boards/mimxrt595_evk_cm33.conf create mode 100644 tests/drivers/dma/chan_blen_transfer/boards/mimxrt685_evk_cm33.conf create mode 100644 tests/drivers/dma/loop_transfer/boards/mimxrt1024_evk.conf create mode 100644 tests/drivers/dma/loop_transfer/boards/mimxrt1050_evk.conf create mode 100644 tests/drivers/dma/loop_transfer/boards/mimxrt1050_evk.overlay create mode 100644 tests/drivers/dma/loop_transfer/boards/mimxrt1060_evk.conf create mode 100644 tests/drivers/dma/loop_transfer/boards/mimxrt1060_evkb.conf create mode 100644 tests/drivers/dma/loop_transfer/boards/mimxrt1064_evk.conf create mode 100644 tests/drivers/dma/loop_transfer/boards/mimxrt1160_evk_cm4.conf create mode 100644 tests/drivers/dma/loop_transfer/boards/mimxrt1160_evk_cm7.conf create mode 100644 tests/drivers/dma/loop_transfer/boards/mimxrt1170_evk_cm4.conf create mode 100644 tests/drivers/dma/loop_transfer/boards/mimxrt1170_evk_cm7.conf create mode 100644 tests/drivers/dma/loop_transfer/boards/mimxrt1170_evkb_cm4.conf create mode 100644 tests/drivers/dma/loop_transfer/boards/mimxrt1170_evkb_cm7.conf diff --git a/tests/drivers/dma/chan_blen_transfer/boards/mimxrt1024_evk.conf b/tests/drivers/dma/chan_blen_transfer/boards/mimxrt1024_evk.conf new file mode 100644 index 00000000000..8aa11602c69 --- /dev/null +++ b/tests/drivers/dma/chan_blen_transfer/boards/mimxrt1024_evk.conf @@ -0,0 +1,3 @@ +CONFIG_CODE_DATA_RELOCATION=y +CONFIG_MEM_ATTR_HEAP=y +CONFIG_DMA_LOOP_TRANSFER_RELOCATE_SECTION="ITCM" diff --git a/tests/drivers/dma/chan_blen_transfer/boards/mimxrt1024_evk.overlay b/tests/drivers/dma/chan_blen_transfer/boards/mimxrt1024_evk.overlay index 8a7bab0e501..91e460ff4ea 100644 --- a/tests/drivers/dma/chan_blen_transfer/boards/mimxrt1024_evk.overlay +++ b/tests/drivers/dma/chan_blen_transfer/boards/mimxrt1024_evk.overlay @@ -1,7 +1,14 @@ /* * Copyright (c) 2022 Kumar Gala + * Copyright (c) 2024 NXP * * SPDX-License-Identifier: Apache-2.0 */ +#include + +&itcm { + zephyr,memory-attr = <( DT_MEM_ARM(ATTR_MPU_RAM_NOCACHE) )>; +}; + test_dma0: &edma0 { }; diff --git a/tests/drivers/dma/chan_blen_transfer/boards/mimxrt1050_evk.conf b/tests/drivers/dma/chan_blen_transfer/boards/mimxrt1050_evk.conf new file mode 100644 index 00000000000..8aa11602c69 --- /dev/null +++ b/tests/drivers/dma/chan_blen_transfer/boards/mimxrt1050_evk.conf @@ -0,0 +1,3 @@ +CONFIG_CODE_DATA_RELOCATION=y +CONFIG_MEM_ATTR_HEAP=y +CONFIG_DMA_LOOP_TRANSFER_RELOCATE_SECTION="ITCM" diff --git a/tests/drivers/dma/chan_blen_transfer/boards/mimxrt1050_evk.overlay b/tests/drivers/dma/chan_blen_transfer/boards/mimxrt1050_evk.overlay index 5965bf744f9..91e460ff4ea 100644 --- a/tests/drivers/dma/chan_blen_transfer/boards/mimxrt1050_evk.overlay +++ b/tests/drivers/dma/chan_blen_transfer/boards/mimxrt1050_evk.overlay @@ -1,7 +1,14 @@ /* - * Copyright 2023 NXP + * Copyright (c) 2022 Kumar Gala + * Copyright (c) 2024 NXP * * SPDX-License-Identifier: Apache-2.0 */ -test_dma0: &edma0 {}; +#include + +&itcm { + zephyr,memory-attr = <( DT_MEM_ARM(ATTR_MPU_RAM_NOCACHE) )>; +}; + +test_dma0: &edma0 { }; diff --git a/tests/drivers/dma/chan_blen_transfer/boards/mimxrt1060_evk.conf b/tests/drivers/dma/chan_blen_transfer/boards/mimxrt1060_evk.conf new file mode 100644 index 00000000000..433a67585be --- /dev/null +++ b/tests/drivers/dma/chan_blen_transfer/boards/mimxrt1060_evk.conf @@ -0,0 +1,3 @@ +CONFIG_CODE_DATA_RELOCATION=y +CONFIG_MEM_ATTR_HEAP=y +CONFIG_DMA_LOOP_TRANSFER_RELOCATE_SECTION="DTCM" diff --git a/tests/drivers/dma/chan_blen_transfer/boards/mimxrt1060_evk.overlay b/tests/drivers/dma/chan_blen_transfer/boards/mimxrt1060_evk.overlay index 8a7bab0e501..bce7a33518c 100644 --- a/tests/drivers/dma/chan_blen_transfer/boards/mimxrt1060_evk.overlay +++ b/tests/drivers/dma/chan_blen_transfer/boards/mimxrt1060_evk.overlay @@ -1,7 +1,14 @@ /* * Copyright (c) 2022 Kumar Gala + * Copyright (c) 2024 NXP * * SPDX-License-Identifier: Apache-2.0 */ +#include + +&dtcm { + zephyr,memory-attr = <( DT_MEM_ARM(ATTR_MPU_RAM_NOCACHE) )>; +}; + test_dma0: &edma0 { }; diff --git a/tests/drivers/dma/chan_blen_transfer/boards/mimxrt1060_evkb.conf b/tests/drivers/dma/chan_blen_transfer/boards/mimxrt1060_evkb.conf new file mode 100644 index 00000000000..8aa11602c69 --- /dev/null +++ b/tests/drivers/dma/chan_blen_transfer/boards/mimxrt1060_evkb.conf @@ -0,0 +1,3 @@ +CONFIG_CODE_DATA_RELOCATION=y +CONFIG_MEM_ATTR_HEAP=y +CONFIG_DMA_LOOP_TRANSFER_RELOCATE_SECTION="ITCM" diff --git a/tests/drivers/dma/chan_blen_transfer/boards/mimxrt1060_evkb.overlay b/tests/drivers/dma/chan_blen_transfer/boards/mimxrt1060_evkb.overlay index 8a7bab0e501..91e460ff4ea 100644 --- a/tests/drivers/dma/chan_blen_transfer/boards/mimxrt1060_evkb.overlay +++ b/tests/drivers/dma/chan_blen_transfer/boards/mimxrt1060_evkb.overlay @@ -1,7 +1,14 @@ /* * Copyright (c) 2022 Kumar Gala + * Copyright (c) 2024 NXP * * SPDX-License-Identifier: Apache-2.0 */ +#include + +&itcm { + zephyr,memory-attr = <( DT_MEM_ARM(ATTR_MPU_RAM_NOCACHE) )>; +}; + test_dma0: &edma0 { }; diff --git a/tests/drivers/dma/chan_blen_transfer/boards/mimxrt1064_evk.conf b/tests/drivers/dma/chan_blen_transfer/boards/mimxrt1064_evk.conf new file mode 100644 index 00000000000..8aa11602c69 --- /dev/null +++ b/tests/drivers/dma/chan_blen_transfer/boards/mimxrt1064_evk.conf @@ -0,0 +1,3 @@ +CONFIG_CODE_DATA_RELOCATION=y +CONFIG_MEM_ATTR_HEAP=y +CONFIG_DMA_LOOP_TRANSFER_RELOCATE_SECTION="ITCM" diff --git a/tests/drivers/dma/chan_blen_transfer/boards/mimxrt1064_evk.overlay b/tests/drivers/dma/chan_blen_transfer/boards/mimxrt1064_evk.overlay index 8a7bab0e501..91e460ff4ea 100644 --- a/tests/drivers/dma/chan_blen_transfer/boards/mimxrt1064_evk.overlay +++ b/tests/drivers/dma/chan_blen_transfer/boards/mimxrt1064_evk.overlay @@ -1,7 +1,14 @@ /* * Copyright (c) 2022 Kumar Gala + * Copyright (c) 2024 NXP * * SPDX-License-Identifier: Apache-2.0 */ +#include + +&itcm { + zephyr,memory-attr = <( DT_MEM_ARM(ATTR_MPU_RAM_NOCACHE) )>; +}; + test_dma0: &edma0 { }; diff --git a/tests/drivers/dma/chan_blen_transfer/boards/mimxrt1160_evk_cm4.conf b/tests/drivers/dma/chan_blen_transfer/boards/mimxrt1160_evk_cm4.conf new file mode 100644 index 00000000000..cdc6eb7c7f1 --- /dev/null +++ b/tests/drivers/dma/chan_blen_transfer/boards/mimxrt1160_evk_cm4.conf @@ -0,0 +1,3 @@ +CONFIG_CODE_DATA_RELOCATION=y +CONFIG_MEM_ATTR_HEAP=y +CONFIG_DMA_LOOP_TRANSFER_RELOCATE_SECTION="SRAM1" diff --git a/tests/drivers/dma/chan_blen_transfer/boards/mimxrt1160_evk_cm4.overlay b/tests/drivers/dma/chan_blen_transfer/boards/mimxrt1160_evk_cm4.overlay index 44f3f92a3d4..7cc5ca66e24 100644 --- a/tests/drivers/dma/chan_blen_transfer/boards/mimxrt1160_evk_cm4.overlay +++ b/tests/drivers/dma/chan_blen_transfer/boards/mimxrt1160_evk_cm4.overlay @@ -1,7 +1,14 @@ /* * Copyright (c) 2022 Kumar Gala + * Copyright (c) 2024 NXP * * SPDX-License-Identifier: Apache-2.0 */ +#include + +&sram1 { + zephyr,memory-attr = <( DT_MEM_ARM(ATTR_MPU_RAM_NOCACHE) )>; +}; + test_dma0: &edma_lpsr0 { }; diff --git a/tests/drivers/dma/chan_blen_transfer/boards/mimxrt1160_evk_cm7.conf b/tests/drivers/dma/chan_blen_transfer/boards/mimxrt1160_evk_cm7.conf new file mode 100644 index 00000000000..433a67585be --- /dev/null +++ b/tests/drivers/dma/chan_blen_transfer/boards/mimxrt1160_evk_cm7.conf @@ -0,0 +1,3 @@ +CONFIG_CODE_DATA_RELOCATION=y +CONFIG_MEM_ATTR_HEAP=y +CONFIG_DMA_LOOP_TRANSFER_RELOCATE_SECTION="DTCM" diff --git a/tests/drivers/dma/chan_blen_transfer/boards/mimxrt1160_evk_cm7.overlay b/tests/drivers/dma/chan_blen_transfer/boards/mimxrt1160_evk_cm7.overlay index 8a7bab0e501..bce7a33518c 100644 --- a/tests/drivers/dma/chan_blen_transfer/boards/mimxrt1160_evk_cm7.overlay +++ b/tests/drivers/dma/chan_blen_transfer/boards/mimxrt1160_evk_cm7.overlay @@ -1,7 +1,14 @@ /* * Copyright (c) 2022 Kumar Gala + * Copyright (c) 2024 NXP * * SPDX-License-Identifier: Apache-2.0 */ +#include + +&dtcm { + zephyr,memory-attr = <( DT_MEM_ARM(ATTR_MPU_RAM_NOCACHE) )>; +}; + test_dma0: &edma0 { }; diff --git a/tests/drivers/dma/chan_blen_transfer/boards/mimxrt1170_evk_cm4.conf b/tests/drivers/dma/chan_blen_transfer/boards/mimxrt1170_evk_cm4.conf new file mode 100644 index 00000000000..f3ceb4ecbb8 --- /dev/null +++ b/tests/drivers/dma/chan_blen_transfer/boards/mimxrt1170_evk_cm4.conf @@ -0,0 +1,4 @@ +CONFIG_CODE_DATA_RELOCATION=y +CONFIG_NOCACHE_MEMORY=y +CONFIG_MEM_ATTR_HEAP=y +CONFIG_DMA_LOOP_TRANSFER_RELOCATE_SECTION="SRAM1" diff --git a/tests/drivers/dma/chan_blen_transfer/boards/mimxrt1170_evk_cm4.overlay b/tests/drivers/dma/chan_blen_transfer/boards/mimxrt1170_evk_cm4.overlay index 44f3f92a3d4..7cc5ca66e24 100644 --- a/tests/drivers/dma/chan_blen_transfer/boards/mimxrt1170_evk_cm4.overlay +++ b/tests/drivers/dma/chan_blen_transfer/boards/mimxrt1170_evk_cm4.overlay @@ -1,7 +1,14 @@ /* * Copyright (c) 2022 Kumar Gala + * Copyright (c) 2024 NXP * * SPDX-License-Identifier: Apache-2.0 */ +#include + +&sram1 { + zephyr,memory-attr = <( DT_MEM_ARM(ATTR_MPU_RAM_NOCACHE) )>; +}; + test_dma0: &edma_lpsr0 { }; diff --git a/tests/drivers/dma/chan_blen_transfer/boards/mimxrt1170_evk_cm7.conf b/tests/drivers/dma/chan_blen_transfer/boards/mimxrt1170_evk_cm7.conf new file mode 100644 index 00000000000..433a67585be --- /dev/null +++ b/tests/drivers/dma/chan_blen_transfer/boards/mimxrt1170_evk_cm7.conf @@ -0,0 +1,3 @@ +CONFIG_CODE_DATA_RELOCATION=y +CONFIG_MEM_ATTR_HEAP=y +CONFIG_DMA_LOOP_TRANSFER_RELOCATE_SECTION="DTCM" diff --git a/tests/drivers/dma/chan_blen_transfer/boards/mimxrt1170_evk_cm7.overlay b/tests/drivers/dma/chan_blen_transfer/boards/mimxrt1170_evk_cm7.overlay index 8a7bab0e501..bce7a33518c 100644 --- a/tests/drivers/dma/chan_blen_transfer/boards/mimxrt1170_evk_cm7.overlay +++ b/tests/drivers/dma/chan_blen_transfer/boards/mimxrt1170_evk_cm7.overlay @@ -1,7 +1,14 @@ /* * Copyright (c) 2022 Kumar Gala + * Copyright (c) 2024 NXP * * SPDX-License-Identifier: Apache-2.0 */ +#include + +&dtcm { + zephyr,memory-attr = <( DT_MEM_ARM(ATTR_MPU_RAM_NOCACHE) )>; +}; + test_dma0: &edma0 { }; diff --git a/tests/drivers/dma/chan_blen_transfer/boards/mimxrt1170_evkb_cm4.conf b/tests/drivers/dma/chan_blen_transfer/boards/mimxrt1170_evkb_cm4.conf new file mode 100644 index 00000000000..cdc6eb7c7f1 --- /dev/null +++ b/tests/drivers/dma/chan_blen_transfer/boards/mimxrt1170_evkb_cm4.conf @@ -0,0 +1,3 @@ +CONFIG_CODE_DATA_RELOCATION=y +CONFIG_MEM_ATTR_HEAP=y +CONFIG_DMA_LOOP_TRANSFER_RELOCATE_SECTION="SRAM1" diff --git a/tests/drivers/dma/chan_blen_transfer/boards/mimxrt1170_evkb_cm4.overlay b/tests/drivers/dma/chan_blen_transfer/boards/mimxrt1170_evkb_cm4.overlay index c2d4a85453f..7cc5ca66e24 100644 --- a/tests/drivers/dma/chan_blen_transfer/boards/mimxrt1170_evkb_cm4.overlay +++ b/tests/drivers/dma/chan_blen_transfer/boards/mimxrt1170_evkb_cm4.overlay @@ -1,7 +1,14 @@ /* - * Copyright 2023 NXP + * Copyright (c) 2022 Kumar Gala + * Copyright (c) 2024 NXP * * SPDX-License-Identifier: Apache-2.0 */ +#include + +&sram1 { + zephyr,memory-attr = <( DT_MEM_ARM(ATTR_MPU_RAM_NOCACHE) )>; +}; + test_dma0: &edma_lpsr0 { }; diff --git a/tests/drivers/dma/chan_blen_transfer/boards/mimxrt595_evk_cm33.conf b/tests/drivers/dma/chan_blen_transfer/boards/mimxrt595_evk_cm33.conf new file mode 100644 index 00000000000..023be2edbc4 --- /dev/null +++ b/tests/drivers/dma/chan_blen_transfer/boards/mimxrt595_evk_cm33.conf @@ -0,0 +1 @@ +CONFIG_CODE_DATA_RELOCATION=y diff --git a/tests/drivers/dma/chan_blen_transfer/boards/mimxrt685_evk_cm33.conf b/tests/drivers/dma/chan_blen_transfer/boards/mimxrt685_evk_cm33.conf new file mode 100644 index 00000000000..023be2edbc4 --- /dev/null +++ b/tests/drivers/dma/chan_blen_transfer/boards/mimxrt685_evk_cm33.conf @@ -0,0 +1 @@ +CONFIG_CODE_DATA_RELOCATION=y diff --git a/tests/drivers/dma/loop_transfer/boards/mimxrt1024_evk.conf b/tests/drivers/dma/loop_transfer/boards/mimxrt1024_evk.conf new file mode 100644 index 00000000000..8aa11602c69 --- /dev/null +++ b/tests/drivers/dma/loop_transfer/boards/mimxrt1024_evk.conf @@ -0,0 +1,3 @@ +CONFIG_CODE_DATA_RELOCATION=y +CONFIG_MEM_ATTR_HEAP=y +CONFIG_DMA_LOOP_TRANSFER_RELOCATE_SECTION="ITCM" diff --git a/tests/drivers/dma/loop_transfer/boards/mimxrt1024_evk.overlay b/tests/drivers/dma/loop_transfer/boards/mimxrt1024_evk.overlay index 8a7bab0e501..91e460ff4ea 100644 --- a/tests/drivers/dma/loop_transfer/boards/mimxrt1024_evk.overlay +++ b/tests/drivers/dma/loop_transfer/boards/mimxrt1024_evk.overlay @@ -1,7 +1,14 @@ /* * Copyright (c) 2022 Kumar Gala + * Copyright (c) 2024 NXP * * SPDX-License-Identifier: Apache-2.0 */ +#include + +&itcm { + zephyr,memory-attr = <( DT_MEM_ARM(ATTR_MPU_RAM_NOCACHE) )>; +}; + test_dma0: &edma0 { }; diff --git a/tests/drivers/dma/loop_transfer/boards/mimxrt1050_evk.conf b/tests/drivers/dma/loop_transfer/boards/mimxrt1050_evk.conf new file mode 100644 index 00000000000..8aa11602c69 --- /dev/null +++ b/tests/drivers/dma/loop_transfer/boards/mimxrt1050_evk.conf @@ -0,0 +1,3 @@ +CONFIG_CODE_DATA_RELOCATION=y +CONFIG_MEM_ATTR_HEAP=y +CONFIG_DMA_LOOP_TRANSFER_RELOCATE_SECTION="ITCM" diff --git a/tests/drivers/dma/loop_transfer/boards/mimxrt1050_evk.overlay b/tests/drivers/dma/loop_transfer/boards/mimxrt1050_evk.overlay new file mode 100644 index 00000000000..91e460ff4ea --- /dev/null +++ b/tests/drivers/dma/loop_transfer/boards/mimxrt1050_evk.overlay @@ -0,0 +1,14 @@ +/* + * Copyright (c) 2022 Kumar Gala + * Copyright (c) 2024 NXP + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include + +&itcm { + zephyr,memory-attr = <( DT_MEM_ARM(ATTR_MPU_RAM_NOCACHE) )>; +}; + +test_dma0: &edma0 { }; diff --git a/tests/drivers/dma/loop_transfer/boards/mimxrt1060_evk.conf b/tests/drivers/dma/loop_transfer/boards/mimxrt1060_evk.conf new file mode 100644 index 00000000000..433a67585be --- /dev/null +++ b/tests/drivers/dma/loop_transfer/boards/mimxrt1060_evk.conf @@ -0,0 +1,3 @@ +CONFIG_CODE_DATA_RELOCATION=y +CONFIG_MEM_ATTR_HEAP=y +CONFIG_DMA_LOOP_TRANSFER_RELOCATE_SECTION="DTCM" diff --git a/tests/drivers/dma/loop_transfer/boards/mimxrt1060_evk.overlay b/tests/drivers/dma/loop_transfer/boards/mimxrt1060_evk.overlay index 8a7bab0e501..bce7a33518c 100644 --- a/tests/drivers/dma/loop_transfer/boards/mimxrt1060_evk.overlay +++ b/tests/drivers/dma/loop_transfer/boards/mimxrt1060_evk.overlay @@ -1,7 +1,14 @@ /* * Copyright (c) 2022 Kumar Gala + * Copyright (c) 2024 NXP * * SPDX-License-Identifier: Apache-2.0 */ +#include + +&dtcm { + zephyr,memory-attr = <( DT_MEM_ARM(ATTR_MPU_RAM_NOCACHE) )>; +}; + test_dma0: &edma0 { }; diff --git a/tests/drivers/dma/loop_transfer/boards/mimxrt1060_evkb.conf b/tests/drivers/dma/loop_transfer/boards/mimxrt1060_evkb.conf new file mode 100644 index 00000000000..8aa11602c69 --- /dev/null +++ b/tests/drivers/dma/loop_transfer/boards/mimxrt1060_evkb.conf @@ -0,0 +1,3 @@ +CONFIG_CODE_DATA_RELOCATION=y +CONFIG_MEM_ATTR_HEAP=y +CONFIG_DMA_LOOP_TRANSFER_RELOCATE_SECTION="ITCM" diff --git a/tests/drivers/dma/loop_transfer/boards/mimxrt1060_evkb.overlay b/tests/drivers/dma/loop_transfer/boards/mimxrt1060_evkb.overlay index 8a7bab0e501..91e460ff4ea 100644 --- a/tests/drivers/dma/loop_transfer/boards/mimxrt1060_evkb.overlay +++ b/tests/drivers/dma/loop_transfer/boards/mimxrt1060_evkb.overlay @@ -1,7 +1,14 @@ /* * Copyright (c) 2022 Kumar Gala + * Copyright (c) 2024 NXP * * SPDX-License-Identifier: Apache-2.0 */ +#include + +&itcm { + zephyr,memory-attr = <( DT_MEM_ARM(ATTR_MPU_RAM_NOCACHE) )>; +}; + test_dma0: &edma0 { }; diff --git a/tests/drivers/dma/loop_transfer/boards/mimxrt1064_evk.conf b/tests/drivers/dma/loop_transfer/boards/mimxrt1064_evk.conf new file mode 100644 index 00000000000..433a67585be --- /dev/null +++ b/tests/drivers/dma/loop_transfer/boards/mimxrt1064_evk.conf @@ -0,0 +1,3 @@ +CONFIG_CODE_DATA_RELOCATION=y +CONFIG_MEM_ATTR_HEAP=y +CONFIG_DMA_LOOP_TRANSFER_RELOCATE_SECTION="DTCM" diff --git a/tests/drivers/dma/loop_transfer/boards/mimxrt1064_evk.overlay b/tests/drivers/dma/loop_transfer/boards/mimxrt1064_evk.overlay index 8a7bab0e501..bce7a33518c 100644 --- a/tests/drivers/dma/loop_transfer/boards/mimxrt1064_evk.overlay +++ b/tests/drivers/dma/loop_transfer/boards/mimxrt1064_evk.overlay @@ -1,7 +1,14 @@ /* * Copyright (c) 2022 Kumar Gala + * Copyright (c) 2024 NXP * * SPDX-License-Identifier: Apache-2.0 */ +#include + +&dtcm { + zephyr,memory-attr = <( DT_MEM_ARM(ATTR_MPU_RAM_NOCACHE) )>; +}; + test_dma0: &edma0 { }; diff --git a/tests/drivers/dma/loop_transfer/boards/mimxrt1160_evk_cm4.conf b/tests/drivers/dma/loop_transfer/boards/mimxrt1160_evk_cm4.conf new file mode 100644 index 00000000000..cdc6eb7c7f1 --- /dev/null +++ b/tests/drivers/dma/loop_transfer/boards/mimxrt1160_evk_cm4.conf @@ -0,0 +1,3 @@ +CONFIG_CODE_DATA_RELOCATION=y +CONFIG_MEM_ATTR_HEAP=y +CONFIG_DMA_LOOP_TRANSFER_RELOCATE_SECTION="SRAM1" diff --git a/tests/drivers/dma/loop_transfer/boards/mimxrt1160_evk_cm4.overlay b/tests/drivers/dma/loop_transfer/boards/mimxrt1160_evk_cm4.overlay index 44f3f92a3d4..7cc5ca66e24 100644 --- a/tests/drivers/dma/loop_transfer/boards/mimxrt1160_evk_cm4.overlay +++ b/tests/drivers/dma/loop_transfer/boards/mimxrt1160_evk_cm4.overlay @@ -1,7 +1,14 @@ /* * Copyright (c) 2022 Kumar Gala + * Copyright (c) 2024 NXP * * SPDX-License-Identifier: Apache-2.0 */ +#include + +&sram1 { + zephyr,memory-attr = <( DT_MEM_ARM(ATTR_MPU_RAM_NOCACHE) )>; +}; + test_dma0: &edma_lpsr0 { }; diff --git a/tests/drivers/dma/loop_transfer/boards/mimxrt1160_evk_cm7.conf b/tests/drivers/dma/loop_transfer/boards/mimxrt1160_evk_cm7.conf new file mode 100644 index 00000000000..8aa11602c69 --- /dev/null +++ b/tests/drivers/dma/loop_transfer/boards/mimxrt1160_evk_cm7.conf @@ -0,0 +1,3 @@ +CONFIG_CODE_DATA_RELOCATION=y +CONFIG_MEM_ATTR_HEAP=y +CONFIG_DMA_LOOP_TRANSFER_RELOCATE_SECTION="ITCM" diff --git a/tests/drivers/dma/loop_transfer/boards/mimxrt1160_evk_cm7.overlay b/tests/drivers/dma/loop_transfer/boards/mimxrt1160_evk_cm7.overlay index 8a7bab0e501..91e460ff4ea 100644 --- a/tests/drivers/dma/loop_transfer/boards/mimxrt1160_evk_cm7.overlay +++ b/tests/drivers/dma/loop_transfer/boards/mimxrt1160_evk_cm7.overlay @@ -1,7 +1,14 @@ /* * Copyright (c) 2022 Kumar Gala + * Copyright (c) 2024 NXP * * SPDX-License-Identifier: Apache-2.0 */ +#include + +&itcm { + zephyr,memory-attr = <( DT_MEM_ARM(ATTR_MPU_RAM_NOCACHE) )>; +}; + test_dma0: &edma0 { }; diff --git a/tests/drivers/dma/loop_transfer/boards/mimxrt1170_evk_cm4.conf b/tests/drivers/dma/loop_transfer/boards/mimxrt1170_evk_cm4.conf new file mode 100644 index 00000000000..cdc6eb7c7f1 --- /dev/null +++ b/tests/drivers/dma/loop_transfer/boards/mimxrt1170_evk_cm4.conf @@ -0,0 +1,3 @@ +CONFIG_CODE_DATA_RELOCATION=y +CONFIG_MEM_ATTR_HEAP=y +CONFIG_DMA_LOOP_TRANSFER_RELOCATE_SECTION="SRAM1" diff --git a/tests/drivers/dma/loop_transfer/boards/mimxrt1170_evk_cm4.overlay b/tests/drivers/dma/loop_transfer/boards/mimxrt1170_evk_cm4.overlay index 44f3f92a3d4..7cc5ca66e24 100644 --- a/tests/drivers/dma/loop_transfer/boards/mimxrt1170_evk_cm4.overlay +++ b/tests/drivers/dma/loop_transfer/boards/mimxrt1170_evk_cm4.overlay @@ -1,7 +1,14 @@ /* * Copyright (c) 2022 Kumar Gala + * Copyright (c) 2024 NXP * * SPDX-License-Identifier: Apache-2.0 */ +#include + +&sram1 { + zephyr,memory-attr = <( DT_MEM_ARM(ATTR_MPU_RAM_NOCACHE) )>; +}; + test_dma0: &edma_lpsr0 { }; diff --git a/tests/drivers/dma/loop_transfer/boards/mimxrt1170_evk_cm7.conf b/tests/drivers/dma/loop_transfer/boards/mimxrt1170_evk_cm7.conf new file mode 100644 index 00000000000..8aa11602c69 --- /dev/null +++ b/tests/drivers/dma/loop_transfer/boards/mimxrt1170_evk_cm7.conf @@ -0,0 +1,3 @@ +CONFIG_CODE_DATA_RELOCATION=y +CONFIG_MEM_ATTR_HEAP=y +CONFIG_DMA_LOOP_TRANSFER_RELOCATE_SECTION="ITCM" diff --git a/tests/drivers/dma/loop_transfer/boards/mimxrt1170_evk_cm7.overlay b/tests/drivers/dma/loop_transfer/boards/mimxrt1170_evk_cm7.overlay index 8a7bab0e501..91e460ff4ea 100644 --- a/tests/drivers/dma/loop_transfer/boards/mimxrt1170_evk_cm7.overlay +++ b/tests/drivers/dma/loop_transfer/boards/mimxrt1170_evk_cm7.overlay @@ -1,7 +1,14 @@ /* * Copyright (c) 2022 Kumar Gala + * Copyright (c) 2024 NXP * * SPDX-License-Identifier: Apache-2.0 */ +#include + +&itcm { + zephyr,memory-attr = <( DT_MEM_ARM(ATTR_MPU_RAM_NOCACHE) )>; +}; + test_dma0: &edma0 { }; diff --git a/tests/drivers/dma/loop_transfer/boards/mimxrt1170_evkb_cm4.conf b/tests/drivers/dma/loop_transfer/boards/mimxrt1170_evkb_cm4.conf new file mode 100644 index 00000000000..cdc6eb7c7f1 --- /dev/null +++ b/tests/drivers/dma/loop_transfer/boards/mimxrt1170_evkb_cm4.conf @@ -0,0 +1,3 @@ +CONFIG_CODE_DATA_RELOCATION=y +CONFIG_MEM_ATTR_HEAP=y +CONFIG_DMA_LOOP_TRANSFER_RELOCATE_SECTION="SRAM1" diff --git a/tests/drivers/dma/loop_transfer/boards/mimxrt1170_evkb_cm4.overlay b/tests/drivers/dma/loop_transfer/boards/mimxrt1170_evkb_cm4.overlay index c2d4a85453f..7cc5ca66e24 100644 --- a/tests/drivers/dma/loop_transfer/boards/mimxrt1170_evkb_cm4.overlay +++ b/tests/drivers/dma/loop_transfer/boards/mimxrt1170_evkb_cm4.overlay @@ -1,7 +1,14 @@ /* - * Copyright 2023 NXP + * Copyright (c) 2022 Kumar Gala + * Copyright (c) 2024 NXP * * SPDX-License-Identifier: Apache-2.0 */ +#include + +&sram1 { + zephyr,memory-attr = <( DT_MEM_ARM(ATTR_MPU_RAM_NOCACHE) )>; +}; + test_dma0: &edma_lpsr0 { }; diff --git a/tests/drivers/dma/loop_transfer/boards/mimxrt1170_evkb_cm7.conf b/tests/drivers/dma/loop_transfer/boards/mimxrt1170_evkb_cm7.conf new file mode 100644 index 00000000000..8aa11602c69 --- /dev/null +++ b/tests/drivers/dma/loop_transfer/boards/mimxrt1170_evkb_cm7.conf @@ -0,0 +1,3 @@ +CONFIG_CODE_DATA_RELOCATION=y +CONFIG_MEM_ATTR_HEAP=y +CONFIG_DMA_LOOP_TRANSFER_RELOCATE_SECTION="ITCM" From c1b7b817cca7e5847ae6785adc8b84b086e4887c Mon Sep 17 00:00:00 2001 From: Daniel DeGrasse Date: Wed, 6 Dec 2023 13:26:12 -0600 Subject: [PATCH 2785/3723] sd: modify sdmmc_wait_ready to always decrement timeout As described in issue: https://github.com/zephyrproject-rtos/zephyr/issues/65027, sdmmc_wait_ready can enter an infinite loop if the card is removed while waiting for it to report an idle status. Fix this by always decrementing the timeout in sdmmc_wait_ready, regardless of whether the SD card is busy. Fixes #65027 Signed-off-by: Daniel DeGrasse --- subsys/sd/sd_ops.c | 27 +++++++++++++++++---------- 1 file changed, 17 insertions(+), 10 deletions(-) diff --git a/subsys/sd/sd_ops.c b/subsys/sd/sd_ops.c index e77160cea21..8fc6400dcf0 100644 --- a/subsys/sd/sd_ops.c +++ b/subsys/sd/sd_ops.c @@ -63,21 +63,28 @@ int sdmmc_read_status(struct sd_card *card) int sdmmc_wait_ready(struct sd_card *card) { int ret, timeout = CONFIG_SD_DATA_TIMEOUT * 1000; - bool busy = true; do { - busy = sdhc_card_busy(card->sdhc); - if (!busy) { + if (!sdhc_card_busy(card->sdhc)) { /* Check card status */ ret = sd_retry(sdmmc_read_status, card, CONFIG_SD_RETRY_COUNT); - busy = (ret != 0); - } else { - /* Delay 125us before polling again */ - k_busy_wait(125); - timeout -= 125; + if (ret == 0) { + return 0; + } + if (ret == -ETIMEDOUT) { + /* If this check timed out, then the total + * time elapsed in microseconds is + * SD_CMD_TIMEOUT * SD_RETRY_COUNT * 1000 + */ + timeout -= (CONFIG_SD_CMD_TIMEOUT * + CONFIG_SD_RETRY_COUNT) * 1000; + } } - } while (busy && (timeout > 0)); - return busy; + /* Delay 125us before polling again */ + k_busy_wait(125); + timeout -= 125; + } while (timeout > 0); + return -EBUSY; } static inline void sdmmc_decode_csd(struct sd_csd *csd, uint32_t *raw_csd, uint32_t *blk_count, From c1dfa9796080de9066925736ff6d1fef0433f732 Mon Sep 17 00:00:00 2001 From: Johan Hedberg Date: Wed, 24 Jan 2024 13:57:23 +0200 Subject: [PATCH 2786/3723] doc: coding_guidelines: Update reference to Bluetooth language document Update the reference to the Bluetooth Appropriate Language Mapping Tables document. The link is now the same as the Bluetooth SIG website uses. Signed-off-by: Johan Hedberg --- doc/contribute/coding_guidelines/index.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/doc/contribute/coding_guidelines/index.rst b/doc/contribute/coding_guidelines/index.rst index 69a159d9573..a5777454eb5 100644 --- a/doc/contribute/coding_guidelines/index.rst +++ b/doc/contribute/coding_guidelines/index.rst @@ -1250,7 +1250,7 @@ Related GitHub Issues and Pull Requests are tagged with the `Inclusive Language .. _Inclusive Language Label: https://github.com/zephyrproject-rtos/zephyr/issues?q=label%3A%22Inclusive+Language%22 .. _I2C Specification: https://www.nxp.com/docs/en/user-guide/UM10204.pdf -.. _Bluetooth Appropriate Language Mapping Tables: https://btprodspecificationrefs.blob.core.windows.net/language-mapping/Appropriate_Language_Mapping_Table.pdf +.. _Bluetooth Appropriate Language Mapping Tables: https://specificationrefs.bluetooth.com/language-mapping/Appropriate_Language_Mapping_Table.pdf .. _OSHWA Resolution to Redefine SPI Signal Names: https://www.oshwa.org/a-resolution-to-redefine-spi-signal-names/ .. _CAN in Automation Inclusive Language news post: https://www.can-cia.org/news/archive/view/?tx_news_pi1%5Bnews%5D=699&tx_news_pi1%5Bday%5D=6&tx_news_pi1%5Bmonth%5D=12&tx_news_pi1%5Byear%5D=2020&cHash=784e79eb438141179386cf7c29ed9438 .. _CAN in Automation Inclusive Language: https://can-newsletter.org/canopen/categories/ From 43d57ce1c2eb0cb9c0f0f1b10a4726bd83cadc96 Mon Sep 17 00:00:00 2001 From: Dominik Ermel Date: Wed, 24 Jan 2024 15:42:13 +0000 Subject: [PATCH 2787/3723] doc/releases: Add note on update of LittleFS The LittleFS is now at version 2.8.1. Signed-off-by: Dominik Ermel --- doc/releases/release-notes-3.6.rst | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/doc/releases/release-notes-3.6.rst b/doc/releases/release-notes-3.6.rst index 6fc4b7060d2..9d95857901e 100644 --- a/doc/releases/release-notes-3.6.rst +++ b/doc/releases/release-notes-3.6.rst @@ -342,6 +342,10 @@ Libraries / Subsystems * Fixed issue whereby :kconfig:option:`CONFIG_RETENTION_BUFFER_SIZE` values over 256 would cause an infinite loop due to use of 8-bit variables. +* Storage + + * File systems: LittleFS module has been updated to version 2.8.1. + * Binary descriptors * POSIX API From 8317f9ea4fcb64c7ff7e41aa5db475b57ccb7959 Mon Sep 17 00:00:00 2001 From: Tim Lin Date: Tue, 16 Jan 2024 14:34:47 +0800 Subject: [PATCH 2788/3723] ITE: drivers/gpio: Add keyboard-controller property When set, this GPIO controller has pins associated with the keyboard controller. In this case the reg_gpcr property is overloaded and used to write the keyboard GCTRL register Signed-off-by: Tim Lin --- drivers/gpio/gpio_ite_it8xxx2_v2.c | 61 +++++++++++++++++----- dts/bindings/gpio/ite,it8xxx2-gpio-v2.yaml | 14 +++++ dts/riscv/ite/it82xx2.dtsi | 3 ++ soc/riscv/ite_ec/common/chip_chipregs.h | 5 ++ 4 files changed, 70 insertions(+), 13 deletions(-) diff --git a/drivers/gpio/gpio_ite_it8xxx2_v2.c b/drivers/gpio/gpio_ite_it8xxx2_v2.c index a05e480f558..16f505587f9 100644 --- a/drivers/gpio/gpio_ite_it8xxx2_v2.c +++ b/drivers/gpio/gpio_ite_it8xxx2_v2.c @@ -54,6 +54,8 @@ struct gpio_ite_cfg { uint8_t has_volt_sel[8]; /* Number of pins per group of GPIO */ uint8_t num_pins; + /* gpioksi, gpioksoh and gpioksol extended setting */ + bool kbs_ctrl; }; /* Structure gpio_ite_data is about callback function */ @@ -159,25 +161,57 @@ static int gpio_ite_configure(const struct device *dev, } /* Set input or output. */ - if (flags & GPIO_OUTPUT) { - ECREG(reg_gpcr) = (ECREG(reg_gpcr) | GPCR_PORT_PIN_MODE_OUTPUT) & - ~GPCR_PORT_PIN_MODE_INPUT; + if (gpio_config->kbs_ctrl) { + /* Handle keyboard scan controller */ + uint8_t ksxgctrlr = ECREG(reg_gpcr); + + ksxgctrlr |= KSIX_KSOX_KBS_GPIO_MODE; + if (flags & GPIO_OUTPUT) { + ksxgctrlr |= KSIX_KSOX_GPIO_OUTPUT; + } else { + ksxgctrlr &= ~KSIX_KSOX_GPIO_OUTPUT; + } + ECREG(reg_gpcr) = ksxgctrlr; } else { - ECREG(reg_gpcr) = (ECREG(reg_gpcr) | GPCR_PORT_PIN_MODE_INPUT) & + /* Handle regular GPIO controller */ + if (flags & GPIO_OUTPUT) { + ECREG(reg_gpcr) = (ECREG(reg_gpcr) | GPCR_PORT_PIN_MODE_OUTPUT) & + ~GPCR_PORT_PIN_MODE_INPUT; + } else { + ECREG(reg_gpcr) = (ECREG(reg_gpcr) | GPCR_PORT_PIN_MODE_INPUT) & ~GPCR_PORT_PIN_MODE_OUTPUT; + } } /* Handle pullup / pulldown */ - if (flags & GPIO_PULL_UP) { - ECREG(reg_gpcr) = (ECREG(reg_gpcr) | GPCR_PORT_PIN_MODE_PULLUP) & - ~GPCR_PORT_PIN_MODE_PULLDOWN; - } else if (flags & GPIO_PULL_DOWN) { - ECREG(reg_gpcr) = (ECREG(reg_gpcr) | GPCR_PORT_PIN_MODE_PULLDOWN) & - ~GPCR_PORT_PIN_MODE_PULLUP; + if (gpio_config->kbs_ctrl) { + /* Handle keyboard scan controller */ + uint8_t ksxgctrlr = ECREG(reg_gpcr); + + if (flags & GPIO_PULL_UP) { + ksxgctrlr = (ksxgctrlr | KSIX_KSOX_GPIO_PULLUP) & + ~KSIX_KSOX_GPIO_PULLDOWN; + } else if (flags & GPIO_PULL_DOWN) { + ksxgctrlr = (ksxgctrlr | KSIX_KSOX_GPIO_PULLDOWN) & + ~KSIX_KSOX_GPIO_PULLUP; + } else { + /* No pull up/down */ + ksxgctrlr &= ~(KSIX_KSOX_GPIO_PULLUP | KSIX_KSOX_GPIO_PULLDOWN); + } + ECREG(reg_gpcr) = ksxgctrlr; } else { - /* No pull up/down */ - ECREG(reg_gpcr) &= ~(GPCR_PORT_PIN_MODE_PULLUP | - GPCR_PORT_PIN_MODE_PULLDOWN); + /* Handle regular GPIO controller */ + if (flags & GPIO_PULL_UP) { + ECREG(reg_gpcr) = (ECREG(reg_gpcr) | GPCR_PORT_PIN_MODE_PULLUP) & + ~GPCR_PORT_PIN_MODE_PULLDOWN; + } else if (flags & GPIO_PULL_DOWN) { + ECREG(reg_gpcr) = (ECREG(reg_gpcr) | GPCR_PORT_PIN_MODE_PULLDOWN) & + ~GPCR_PORT_PIN_MODE_PULLUP; + } else { + /* No pull up/down */ + ECREG(reg_gpcr) &= ~(GPCR_PORT_PIN_MODE_PULLUP | + GPCR_PORT_PIN_MODE_PULLDOWN); + } } unlock_and_return: @@ -512,6 +546,7 @@ static const struct gpio_ite_cfg gpio_ite_cfg_##inst = { \ .gpio_irq = IT8XXX2_DT_GPIO_IRQ_LIST(inst), \ .has_volt_sel = DT_INST_PROP_OR(inst, has_volt_sel, {0}), \ .num_pins = DT_INST_PROP(inst, ngpios), \ + .kbs_ctrl = DT_INST_PROP_OR(inst, keyboard_controller, 0), \ }; \ DEVICE_DT_INST_DEFINE(inst, \ gpio_ite_init, \ diff --git a/dts/bindings/gpio/ite,it8xxx2-gpio-v2.yaml b/dts/bindings/gpio/ite,it8xxx2-gpio-v2.yaml index 7c77e610a23..744365cc5a3 100644 --- a/dts/bindings/gpio/ite,it8xxx2-gpio-v2.yaml +++ b/dts/bindings/gpio/ite,it8xxx2-gpio-v2.yaml @@ -27,6 +27,20 @@ properties: wuc-mask: type: array + keyboard-controller: + type: boolean + description: | + When set, this GPIO controller has pins associated with the + keyboard controller. In this case the reg_gpcr property is + overloaded and used to write the keyboard GCTRL register. + This setting will be found in the gpio_ite_configure function + when the judgment of gpio_config->ksb_ctrl is true. + The GPIO control register that will be set for these three + nodes is as follows: + gpioksi: 0xf01d40-0xf01d47 + gpioksol: 0xf01d48-0xf01d4f + gpioksoh: 0xf01d50-0xf01d57 + gpio-cells: - pin - flags diff --git a/dts/riscv/ite/it82xx2.dtsi b/dts/riscv/ite/it82xx2.dtsi index b6de6c64586..ad11462b92b 100644 --- a/dts/riscv/ite/it82xx2.dtsi +++ b/dts/riscv/ite/it82xx2.dtsi @@ -390,6 +390,7 @@ NO_FUNC 0 NO_FUNC 0>; interrupt-parent = <&intc>; + keyboard-controller; #gpio-cells = <2>; }; @@ -411,6 +412,7 @@ NO_FUNC 0 NO_FUNC 0>; interrupt-parent = <&intc>; + keyboard-controller; #gpio-cells = <2>; }; @@ -432,6 +434,7 @@ NO_FUNC 0 NO_FUNC 0>; interrupt-parent = <&intc>; + keyboard-controller; #gpio-cells = <2>; }; diff --git a/soc/riscv/ite_ec/common/chip_chipregs.h b/soc/riscv/ite_ec/common/chip_chipregs.h index 4a5ca269d01..75e240de530 100644 --- a/soc/riscv/ite_ec/common/chip_chipregs.h +++ b/soc/riscv/ite_ec/common/chip_chipregs.h @@ -1073,6 +1073,11 @@ struct gpio_it8xxx2_regs { #define IT8XXX2_GPIO_GPH1VS BIT(1) #define IT8XXX2_GPIO_GPH2VS BIT(0) +#define KSIX_KSOX_KBS_GPIO_MODE BIT(7) +#define KSIX_KSOX_GPIO_OUTPUT BIT(6) +#define KSIX_KSOX_GPIO_PULLUP BIT(2) +#define KSIX_KSOX_GPIO_PULLDOWN BIT(1) + #define GPCR_PORT_PIN_MODE_INPUT BIT(7) #define GPCR_PORT_PIN_MODE_OUTPUT BIT(6) #define GPCR_PORT_PIN_MODE_PULLUP BIT(2) From 4c5a96ec65150f3adc1ea837b7294c8e04f1796d Mon Sep 17 00:00:00 2001 From: Peter Mitsis Date: Wed, 24 Jan 2024 09:57:55 -0500 Subject: [PATCH 2789/3723] tests: latency_measure: Configurable iterations Updates the latency_measure benchmark to make the number of iterations for which each test executes to be configurable. This allows someone to make a tradeoff between accuracy and execution time (can be useful for simulators). Signed-off-by: Peter Mitsis --- tests/benchmarks/latency_measure/Kconfig | 10 +++ tests/benchmarks/latency_measure/src/main.c | 70 ++++++++++----------- 2 files changed, 44 insertions(+), 36 deletions(-) create mode 100644 tests/benchmarks/latency_measure/Kconfig diff --git a/tests/benchmarks/latency_measure/Kconfig b/tests/benchmarks/latency_measure/Kconfig new file mode 100644 index 00000000000..557d4df33f5 --- /dev/null +++ b/tests/benchmarks/latency_measure/Kconfig @@ -0,0 +1,10 @@ +# Copyright (c) 2024 Intel Corporation +# SPDX-License-Identifier: Apache-2.0 + +mainmenu "Latency Measure Benchmark" + +source "Kconfig.zephyr" + +config BENCHMARK_NUM_ITERATIONS + int "Number of iterations to gather data" + default 1000 diff --git a/tests/benchmarks/latency_measure/src/main.c b/tests/benchmarks/latency_measure/src/main.c index d499e65ad6f..7a46c77bc99 100644 --- a/tests/benchmarks/latency_measure/src/main.c +++ b/tests/benchmarks/latency_measure/src/main.c @@ -16,8 +16,6 @@ #include "timing_sc.h" #include -#define NUM_ITERATIONS 10000 - #define STACK_SIZE (1024 + CONFIG_TEST_EXTRA_STACK_SIZE) uint32_t tm_off; @@ -79,77 +77,77 @@ static void test_thread(void *arg1, void *arg2, void *arg3) TC_START("Time Measurement"); TC_PRINT("Timing results: Clock frequency: %u MHz\n", freq); - timestamp_overhead_init(NUM_ITERATIONS); + timestamp_overhead_init(CONFIG_BENCHMARK_NUM_ITERATIONS); /* Preemptive threads context switching */ - thread_switch_yield(NUM_ITERATIONS, false); + thread_switch_yield(CONFIG_BENCHMARK_NUM_ITERATIONS, false); /* Cooperative threads context switching */ - thread_switch_yield(NUM_ITERATIONS, true); + thread_switch_yield(CONFIG_BENCHMARK_NUM_ITERATIONS, true); - int_to_thread(NUM_ITERATIONS); + int_to_thread(CONFIG_BENCHMARK_NUM_ITERATIONS); /* Thread creation, starting, suspending, resuming and aborting. */ - thread_ops(NUM_ITERATIONS, 0, 0); + thread_ops(CONFIG_BENCHMARK_NUM_ITERATIONS, 0, 0); #ifdef CONFIG_USERSPACE - thread_ops(NUM_ITERATIONS, 0, K_USER); - thread_ops(NUM_ITERATIONS, K_USER, K_USER); - thread_ops(NUM_ITERATIONS, K_USER, 0); + thread_ops(CONFIG_BENCHMARK_NUM_ITERATIONS, 0, K_USER); + thread_ops(CONFIG_BENCHMARK_NUM_ITERATIONS, K_USER, K_USER); + thread_ops(CONFIG_BENCHMARK_NUM_ITERATIONS, K_USER, 0); #endif - fifo_ops(NUM_ITERATIONS, 0); + fifo_ops(CONFIG_BENCHMARK_NUM_ITERATIONS, 0); #ifdef CONFIG_USERSPACE - fifo_ops(NUM_ITERATIONS, K_USER); + fifo_ops(CONFIG_BENCHMARK_NUM_ITERATIONS, K_USER); #endif - fifo_blocking_ops(NUM_ITERATIONS, 0, 0); + fifo_blocking_ops(CONFIG_BENCHMARK_NUM_ITERATIONS, 0, 0); #ifdef CONFIG_USERSPACE - fifo_blocking_ops(NUM_ITERATIONS, 0, K_USER); - fifo_blocking_ops(NUM_ITERATIONS, K_USER, 0); - fifo_blocking_ops(NUM_ITERATIONS, K_USER, K_USER); + fifo_blocking_ops(CONFIG_BENCHMARK_NUM_ITERATIONS, 0, K_USER); + fifo_blocking_ops(CONFIG_BENCHMARK_NUM_ITERATIONS, K_USER, 0); + fifo_blocking_ops(CONFIG_BENCHMARK_NUM_ITERATIONS, K_USER, K_USER); #endif - lifo_ops(NUM_ITERATIONS, 0); + lifo_ops(CONFIG_BENCHMARK_NUM_ITERATIONS, 0); #ifdef CONFIG_USERSPACE - lifo_ops(NUM_ITERATIONS, K_USER); + lifo_ops(CONFIG_BENCHMARK_NUM_ITERATIONS, K_USER); #endif - lifo_blocking_ops(NUM_ITERATIONS, 0, 0); + lifo_blocking_ops(CONFIG_BENCHMARK_NUM_ITERATIONS, 0, 0); #ifdef CONFIG_USERSPACE - lifo_blocking_ops(NUM_ITERATIONS, 0, K_USER); - lifo_blocking_ops(NUM_ITERATIONS, K_USER, 0); - lifo_blocking_ops(NUM_ITERATIONS, K_USER, K_USER); + lifo_blocking_ops(CONFIG_BENCHMARK_NUM_ITERATIONS, 0, K_USER); + lifo_blocking_ops(CONFIG_BENCHMARK_NUM_ITERATIONS, K_USER, 0); + lifo_blocking_ops(CONFIG_BENCHMARK_NUM_ITERATIONS, K_USER, K_USER); #endif - event_ops(NUM_ITERATIONS, 0); + event_ops(CONFIG_BENCHMARK_NUM_ITERATIONS, 0); #ifdef CONFIG_USERSPACE - event_ops(NUM_ITERATIONS, K_USER); + event_ops(CONFIG_BENCHMARK_NUM_ITERATIONS, K_USER); #endif - event_blocking_ops(NUM_ITERATIONS, 0, 0); + event_blocking_ops(CONFIG_BENCHMARK_NUM_ITERATIONS, 0, 0); #ifdef CONFIG_USERSPACE - event_blocking_ops(NUM_ITERATIONS, 0, K_USER); - event_blocking_ops(NUM_ITERATIONS, K_USER, 0); - event_blocking_ops(NUM_ITERATIONS, K_USER, K_USER); + event_blocking_ops(CONFIG_BENCHMARK_NUM_ITERATIONS, 0, K_USER); + event_blocking_ops(CONFIG_BENCHMARK_NUM_ITERATIONS, K_USER, 0); + event_blocking_ops(CONFIG_BENCHMARK_NUM_ITERATIONS, K_USER, K_USER); #endif - sema_test_signal(NUM_ITERATIONS, 0); + sema_test_signal(CONFIG_BENCHMARK_NUM_ITERATIONS, 0); #ifdef CONFIG_USERSPACE - sema_test_signal(NUM_ITERATIONS, K_USER); + sema_test_signal(CONFIG_BENCHMARK_NUM_ITERATIONS, K_USER); #endif - sema_context_switch(NUM_ITERATIONS, 0, 0); + sema_context_switch(CONFIG_BENCHMARK_NUM_ITERATIONS, 0, 0); #ifdef CONFIG_USERSPACE - sema_context_switch(NUM_ITERATIONS, 0, K_USER); - sema_context_switch(NUM_ITERATIONS, K_USER, 0); - sema_context_switch(NUM_ITERATIONS, K_USER, K_USER); + sema_context_switch(CONFIG_BENCHMARK_NUM_ITERATIONS, 0, K_USER); + sema_context_switch(CONFIG_BENCHMARK_NUM_ITERATIONS, K_USER, 0); + sema_context_switch(CONFIG_BENCHMARK_NUM_ITERATIONS, K_USER, K_USER); #endif - mutex_lock_unlock(NUM_ITERATIONS, 0); + mutex_lock_unlock(CONFIG_BENCHMARK_NUM_ITERATIONS, 0); #ifdef CONFIG_USERSPACE - mutex_lock_unlock(NUM_ITERATIONS, K_USER); + mutex_lock_unlock(CONFIG_BENCHMARK_NUM_ITERATIONS, K_USER); #endif heap_malloc_free(); From cf6a3824a033aeac16723c27b205b07708942ab8 Mon Sep 17 00:00:00 2001 From: Alberto Escolar Piedras Date: Wed, 24 Jan 2024 15:52:35 +0100 Subject: [PATCH 2790/3723] tests/bsim host/privacy/peripheral: Minor fixes to allow equality check Minor fixes in this test script to: * Start with an empty flash even if there was a left over flash file on disk * Not overwrite the simulation activity from the first part of the test in the second part of the test, to allow looking into the traffic and to allow rerunning the test in check mode, to ensure there is no radio activity changes when another change is done. * Set the simulation id to something more unique (it was just "peripheral" before which is too easy to be repeated in another test) Signed-off-by: Alberto Escolar Piedras --- .../host/privacy/peripheral/test_scripts/run_test.sh | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/tests/bsim/bluetooth/host/privacy/peripheral/test_scripts/run_test.sh b/tests/bsim/bluetooth/host/privacy/peripheral/test_scripts/run_test.sh index 37929a4efb2..169d9b8510b 100755 --- a/tests/bsim/bluetooth/host/privacy/peripheral/test_scripts/run_test.sh +++ b/tests/bsim/bluetooth/host/privacy/peripheral/test_scripts/run_test.sh @@ -9,19 +9,19 @@ source "${bash_source_dir}/_env.sh" source ${ZEPHYR_BASE}/tests/bsim/sh_common.source verbosity_level=2 -simulation_id="$(basename "$(realpath "$bash_source_dir/..")")" +simulation_id="host_privacy_peripheral" EXECUTE_TIMEOUT=30 cd ${BSIM_OUT_PATH}/bin Execute "$central_exe" \ -v=${verbosity_level} -s=${simulation_id} -d=0 -testid=central -RealEncryption=1 \ - -flash="${simulation_id}.central.log.bin" + -flash="${simulation_id}.central.log.bin" -flash_erase Execute "$peripheral_exe" \ -v=${verbosity_level} -s=${simulation_id} -d=1 -testid=peripheral -RealEncryption=1 \ - -flash="${simulation_id}.peripheral.log.bin" + -flash="${simulation_id}.peripheral.log.bin" -flash_erase Execute ./bs_2G4_phy_v1 -v=${verbosity_level} -s=${simulation_id} \ @@ -30,16 +30,16 @@ Execute ./bs_2G4_phy_v1 -v=${verbosity_level} -s=${simulation_id} \ wait_for_background_jobs Execute "$central_exe" \ - -v=${verbosity_level} -s=${simulation_id} -d=0 -testid=central -RealEncryption=1 \ + -v=${verbosity_level} -s=${simulation_id}.2 -d=0 -testid=central -RealEncryption=1 \ -flash="${simulation_id}.central.log.bin" -flash_rm Execute "$peripheral_exe" \ - -v=${verbosity_level} -s=${simulation_id} -d=1 -testid=peripheral -RealEncryption=1 \ + -v=${verbosity_level} -s=${simulation_id}.2 -d=1 -testid=peripheral -RealEncryption=1 \ -flash="${simulation_id}.peripheral.log.bin" -flash_rm -Execute ./bs_2G4_phy_v1 -v=${verbosity_level} -s=${simulation_id} \ +Execute ./bs_2G4_phy_v1 -v=${verbosity_level} -s=${simulation_id}.2 \ -D=2 -sim_length=70e6 $@ wait_for_background_jobs From e7875de3f9ad434e1c6e21416c58afcb21ed3acf Mon Sep 17 00:00:00 2001 From: Pisit Sawangvonganan Date: Thu, 4 Jan 2024 22:36:32 +0700 Subject: [PATCH 2791/3723] drivers: sdhc: set 'sdhc_driver_api' as 'static const' This change marks each instance of the 'api' as 'static const'. The rationale is that 'api' is used for declaring internal module interfaces and is not intended to be modified at runtime. By using 'static const', we ensure immutability, leading to usage of only .rodata and a reduction in the .data area. Signed-off-by: Pisit Sawangvonganan --- drivers/sdhc/sdhc_spi.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/sdhc/sdhc_spi.c b/drivers/sdhc/sdhc_spi.c index 48e3704a098..7462e711dcd 100644 --- a/drivers/sdhc/sdhc_spi.c +++ b/drivers/sdhc/sdhc_spi.c @@ -762,7 +762,7 @@ static int sdhc_spi_init(const struct device *dev) return ret; } -static struct sdhc_driver_api sdhc_spi_api = { +static const struct sdhc_driver_api sdhc_spi_api = { .request = sdhc_spi_request, .set_io = sdhc_spi_set_io, .get_host_props = sdhc_spi_get_host_props, From 9506720bd8951312898547487d8c320e180c6745 Mon Sep 17 00:00:00 2001 From: Flavio Ceolin Date: Mon, 22 Jan 2024 13:43:10 -0800 Subject: [PATCH 2792/3723] drivers: power_domain/gpio_monitor: Init priority option Add a Kconfig option to customize initialization priority of gpio monitor power domain. Signed-off-by: Flavio Ceolin --- drivers/power_domain/Kconfig | 10 ++++++++++ drivers/power_domain/power_domain_gpio_monitor.c | 2 +- 2 files changed, 11 insertions(+), 1 deletion(-) diff --git a/drivers/power_domain/Kconfig b/drivers/power_domain/Kconfig index 22ffc388503..77d4764ddb7 100644 --- a/drivers/power_domain/Kconfig +++ b/drivers/power_domain/Kconfig @@ -41,4 +41,14 @@ config POWER_DOMAIN_GPIO_MONITOR depends on GPIO select DEVICE_DEPS +if POWER_DOMAIN_GPIO_MONITOR + +config POWER_DOMAIN_GPIO_MONITOR_INIT_PRIORITY + int "GPIO monitor power domain init priority" + default POWER_DOMAIN_INIT_PRIORITY + help + GPIO monitor power domain initialization priority. + +endif #POWER_DOMAIN_GPIO_MONITOR + endif diff --git a/drivers/power_domain/power_domain_gpio_monitor.c b/drivers/power_domain/power_domain_gpio_monitor.c index 55e44570553..40c03bb8dd7 100644 --- a/drivers/power_domain/power_domain_gpio_monitor.c +++ b/drivers/power_domain/power_domain_gpio_monitor.c @@ -145,6 +145,6 @@ static int pd_gpio_monitor_init(const struct device *dev) DEVICE_DT_INST_DEFINE(inst, pd_gpio_monitor_init, \ PM_DEVICE_DT_INST_GET(inst), &pd_gpio_monitor_data_##inst, \ &pd_gpio_monitor_config_##inst, POST_KERNEL, \ - CONFIG_POWER_DOMAIN_INIT_PRIORITY, NULL); + CONFIG_POWER_DOMAIN_GPIO_MONITOR_INIT_PRIORITY, NULL); DT_INST_FOREACH_STATUS_OKAY(POWER_DOMAIN_DEVICE) From e80ea1e1291bc3288095b630daa5f77bcf05df33 Mon Sep 17 00:00:00 2001 From: Flavio Ceolin Date: Mon, 22 Jan 2024 13:48:07 -0800 Subject: [PATCH 2793/3723] drivers: power_domain/gpio: Init priority option Add a Kconfig option to customize initialization priority of gpio power domain. Signed-off-by: Flavio Ceolin --- drivers/power_domain/Kconfig | 10 ++++++++++ drivers/power_domain/power_domain_gpio.c | 2 +- 2 files changed, 11 insertions(+), 1 deletion(-) diff --git a/drivers/power_domain/Kconfig b/drivers/power_domain/Kconfig index 77d4764ddb7..46f88ce4cc9 100644 --- a/drivers/power_domain/Kconfig +++ b/drivers/power_domain/Kconfig @@ -26,6 +26,16 @@ config POWER_DOMAIN_GPIO depends on TIMEOUT_64BIT select DEVICE_DEPS +if POWER_DOMAIN_GPIO + +config POWER_DOMAIN_GPIO_INIT_PRIORITY + int "GPIO power domain init priority" + default POWER_DOMAIN_INIT_PRIORITY + help + GPIO power domain initialization priority. + +endif #POWER_DOMAIN_GPIO_MONITOR + config POWER_DOMAIN_INTEL_ADSP bool "Use Intel ADSP power gating mechanisms" default y diff --git a/drivers/power_domain/power_domain_gpio.c b/drivers/power_domain/power_domain_gpio.c index 15c60a65d75..82d9a17ef9e 100644 --- a/drivers/power_domain/power_domain_gpio.c +++ b/drivers/power_domain/power_domain_gpio.c @@ -135,7 +135,7 @@ static int pd_gpio_init(const struct device *dev) PM_DEVICE_DT_INST_DEFINE(id, pd_gpio_pm_action); \ DEVICE_DT_INST_DEFINE(id, pd_gpio_init, PM_DEVICE_DT_INST_GET(id), \ &pd_gpio_##id##_data, &pd_gpio_##id##_cfg, \ - POST_KERNEL, CONFIG_POWER_DOMAIN_INIT_PRIORITY, \ + POST_KERNEL, CONFIG_POWER_DOMAIN_GPIO_INIT_PRIORITY, \ NULL); DT_INST_FOREACH_STATUS_OKAY(POWER_DOMAIN_DEVICE) From 4e39f79eeb2f19b6af5a74d822c02bf0227e56a1 Mon Sep 17 00:00:00 2001 From: Flavio Ceolin Date: Mon, 22 Jan 2024 13:53:37 -0800 Subject: [PATCH 2794/3723] drivers: power_domain/intel_adsp: Init priority option Add a Kconfig option to customize initialization priority of Intel ADSP power domain. Signed-off-by: Flavio Ceolin --- drivers/power_domain/Kconfig | 10 ++++++++++ drivers/power_domain/power_domain_intel_adsp.c | 2 +- 2 files changed, 11 insertions(+), 1 deletion(-) diff --git a/drivers/power_domain/Kconfig b/drivers/power_domain/Kconfig index 46f88ce4cc9..fc552490b8e 100644 --- a/drivers/power_domain/Kconfig +++ b/drivers/power_domain/Kconfig @@ -44,6 +44,16 @@ config POWER_DOMAIN_INTEL_ADSP help Include Intel ADSP power domain control mechanisms +if POWER_DOMAIN_INTEL_ADSP + +config POWER_DOMAIN_INTEL_ADSP_INIT_PRIORITY + int "Intel ADSP power domain init priority" + default KERNEL_INIT_PRIORITY_DEFAULT + help + Intel ADSP power domain initialization priority. + +endif #POWER_DOMAIN_INTEL_ADSP + config POWER_DOMAIN_GPIO_MONITOR bool "GPIO monitor for sensing power on rail" default y diff --git a/drivers/power_domain/power_domain_intel_adsp.c b/drivers/power_domain/power_domain_intel_adsp.c index 84820829661..8a82f26650f 100644 --- a/drivers/power_domain/power_domain_intel_adsp.c +++ b/drivers/power_domain/power_domain_intel_adsp.c @@ -99,6 +99,6 @@ static int pd_intel_adsp_init(const struct device *dev) PM_DEVICE_DT_INST_DEFINE(id, pd_intel_adsp_pm_action); \ DEVICE_DT_INST_DEFINE(id, pd_intel_adsp_init, PM_DEVICE_DT_INST_GET(id), \ &pd_pg_reg##id, NULL, POST_KERNEL, \ - CONFIG_KERNEL_INIT_PRIORITY_DEFAULT, NULL); + CONFIG_POWER_DOMAIN_INTEL_ADSP_INIT_PRIORITY, NULL); DT_INST_FOREACH_STATUS_OKAY(POWER_DOMAIN_DEVICE) From 2236e57e42a7fb1b0ced894108ca9283348d38a2 Mon Sep 17 00:00:00 2001 From: Christopher Friedt Date: Wed, 24 Jan 2024 14:06:24 -0500 Subject: [PATCH 2795/3723] samples: thrift: update doc to include optional modules Update the Thrift sample to include instructions on fetching optional modules. Without this, user builds will fail. Signed-off-by: Christopher Friedt --- samples/modules/thrift/hello/README.rst | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/samples/modules/thrift/hello/README.rst b/samples/modules/thrift/hello/README.rst index 90a6d089a92..a773bc547b5 100644 --- a/samples/modules/thrift/hello/README.rst +++ b/samples/modules/thrift/hello/README.rst @@ -48,6 +48,14 @@ layers in thrift can be combined to build an application with desired features. Requirements ************ +- Optional Modules + +.. code-block:: console + :caption: Download optional modules with west + + west config manifest.group-filter -- +optional + west update + - QEMU Networking (described in :ref:`networking_with_qemu`) - Thrift dependencies installed for your host OS e.g. in Ubuntu From f64af1aecb61c7f6d2d7ee3b13fd02c32ba7df93 Mon Sep 17 00:00:00 2001 From: Yong Cong Sin Date: Tue, 23 Jan 2024 16:53:06 +0800 Subject: [PATCH 2796/3723] devicetree: use `DT_CAT*` wherever possible Use `DT_CAT*` macros to paste simple things together instead of `UTIL_CAT` wherever possible. This should reduce the amount of error messages from the compiler when something goes wrong. Signed-off-by: Yong Cong Sin --- include/zephyr/devicetree.h | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/include/zephyr/devicetree.h b/include/zephyr/devicetree.h index a463aaf4fbd..720aea69628 100644 --- a/include/zephyr/devicetree.h +++ b/include/zephyr/devicetree.h @@ -356,7 +356,7 @@ * @param node_id node identifier * @return a node identifier for the node's parent */ -#define DT_PARENT(node_id) UTIL_CAT(node_id, _PARENT) +#define DT_PARENT(node_id) DT_CAT(node_id, _PARENT) /** * @brief Get a node identifier for a grandparent node @@ -3087,7 +3087,7 @@ */ #define DT_FOREACH_STATUS_OKAY(compat, fn) \ COND_CODE_1(DT_HAS_COMPAT_STATUS_OKAY(compat), \ - (UTIL_CAT(DT_FOREACH_OKAY_, compat)(fn)), \ + (DT_CAT(DT_FOREACH_OKAY_, compat)(fn)), \ ()) /** @@ -3136,7 +3136,7 @@ */ #define DT_FOREACH_STATUS_OKAY_VARGS(compat, fn, ...) \ COND_CODE_1(DT_HAS_COMPAT_STATUS_OKAY(compat), \ - (UTIL_CAT(DT_FOREACH_OKAY_VARGS_, \ + (DT_CAT(DT_FOREACH_OKAY_VARGS_, \ compat)(fn, __VA_ARGS__)), \ ()) @@ -4107,7 +4107,7 @@ * 0 otherwise */ #define DT_HAS_COMPAT_ON_BUS_STATUS_OKAY(compat, bus) \ - IS_ENABLED(UTIL_CAT(DT_CAT(DT_COMPAT_, compat), _BUS_##bus)) + IS_ENABLED(DT_CAT4(DT_COMPAT_, compat, _BUS_, bus)) /** * @brief Test if any `DT_DRV_COMPAT` node is on a bus of a given type From acfb87dca3e422a07acdd23a72e317a7d3dc59f4 Mon Sep 17 00:00:00 2001 From: Yong Cong Sin Date: Tue, 23 Jan 2024 16:55:24 +0800 Subject: [PATCH 2797/3723] devicetree: reuse `DT_CAT*` instead of pasting manually Reuse `DT_CAT*` macros to paste these things together instead of pasting manually. Signed-off-by: Yong Cong Sin --- include/zephyr/devicetree.h | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/include/zephyr/devicetree.h b/include/zephyr/devicetree.h index 720aea69628..483a659f46c 100644 --- a/include/zephyr/devicetree.h +++ b/include/zephyr/devicetree.h @@ -1208,7 +1208,7 @@ * @return the property's value as a sequence of tokens, with no quotes */ #define DT_STRING_UNQUOTED_BY_IDX(node_id, prop, idx) \ - DT_CAT4(node_id, _P_, prop##_IDX_##idx, _STRING_UNQUOTED) + DT_CAT6(node_id, _P_, prop, _IDX_, idx, _STRING_UNQUOTED) /* * phandle properties @@ -1383,7 +1383,7 @@ * @return the cell's value or @p default_value */ #define DT_PHA_BY_IDX_OR(node_id, pha, idx, cell, default_value) \ - DT_PROP_OR(node_id, pha##_IDX_##idx##_VAL_##cell, default_value) + DT_PROP_OR(node_id, DT_CAT5(pha, _IDX_, idx, _VAL_, cell), default_value) /** * @brief Equivalent to DT_PHA_BY_IDX(node_id, pha, 0, cell) @@ -1476,7 +1476,7 @@ * @return the cell's value or @p default_value */ #define DT_PHA_BY_NAME_OR(node_id, pha, name, cell, default_value) \ - DT_PROP_OR(node_id, pha##_NAME_##name##_VAL_##cell, default_value) + DT_PROP_OR(node_id, DT_CAT5(pha, _NAME_, name, _VAL_, cell), default_value) /** * @brief Get a phandle's node identifier from a phandle array by @p name From 33ffe001f89d20c1a23575e2fcd297d77b79d88b Mon Sep 17 00:00:00 2001 From: Greter Raffael Date: Tue, 14 Nov 2023 08:20:53 +0000 Subject: [PATCH 2798/3723] linker: Generate snippets files for dtcm and itcm This allows to link code and data blocks, e.g. the vector table, into tightly coupled memory using `zephyr_linker_sources`. Signed-off-by: Greter Raffael --- cmake/modules/extensions.cmake | 15 +++++++++++++-- .../zephyr/arch/arm/cortex_m/scripts/linker.ld | 10 ++++++++++ include/zephyr/arch/riscv/common/linker.ld | 10 ++++++++++ soc/riscv/andes_v5/ae350/linker.ld | 10 ++++++++++ 4 files changed, 43 insertions(+), 2 deletions(-) diff --git a/cmake/modules/extensions.cmake b/cmake/modules/extensions.cmake index f3d0dd5e53f..629e8411ce8 100644 --- a/cmake/modules/extensions.cmake +++ b/cmake/modules/extensions.cmake @@ -1170,6 +1170,8 @@ endfunction(zephyr_check_compiler_flag_hardcoded) # DATA_SECTIONS Inside the RAMABLE_REGION GROUP, initialized. # RAMFUNC_SECTION Inside the RAMFUNC RAMABLE_REGION GROUP, not initialized. # NOCACHE_SECTION Inside the NOCACHE section +# ITCM_SECTION Inside the itcm section. +# DTCM_SECTION Inside the dtcm data section. # SECTIONS Near the end of the file. Don't use this when linking into # RAMABLE_REGION, use RAM_SECTIONS instead. # PINNED_RODATA Similar to RODATA but pinned in memory. @@ -1184,8 +1186,9 @@ endfunction(zephyr_check_compiler_flag_hardcoded) # Use NOINIT, RWDATA, and RODATA unless they don't work for your use case. # # When placing into NOINIT, RWDATA, RODATA, ROM_START, RAMFUNC_SECTION, -# NOCACHE_SECTION the contents of the files will be placed inside -# an output section, so assume the section definition is already present, e.g.: +# NOCACHE_SECTION, DTCM_SECTION or ITCM_SECTION the contents of the files will +# be placed inside an output section, so assume the section definition is +# already present, e.g.: # _mysection_start = .; # KEEP(*(.mysection)); # _mysection_end = .; @@ -1220,6 +1223,8 @@ function(zephyr_linker_sources location) set(rodata_path "${snippet_base}/snippets-rodata.ld") set(ramfunc_path "${snippet_base}/snippets-ramfunc-section.ld") set(nocache_path "${snippet_base}/snippets-nocache-section.ld") + set(itcm_path "${snippet_base}/snippets-itcm-section.ld") + set(dtcm_path "${snippet_base}/snippets-dtcm-section.ld") set(pinned_ram_sections_path "${snippet_base}/snippets-pinned-ram-sections.ld") set(pinned_data_sections_path "${snippet_base}/snippets-pinned-data-sections.ld") @@ -1237,6 +1242,8 @@ function(zephyr_linker_sources location) file(WRITE ${rodata_path} "") file(WRITE ${ramfunc_path} "") file(WRITE ${nocache_path} "") + file(WRITE ${itcm_path} "") + file(WRITE ${dtcm_path} "") file(WRITE ${pinned_ram_sections_path} "") file(WRITE ${pinned_data_sections_path} "") file(WRITE ${pinned_rodata_path} "") @@ -1262,6 +1269,10 @@ function(zephyr_linker_sources location) set(snippet_path "${ramfunc_path}") elseif("${location}" STREQUAL "NOCACHE_SECTION") set(snippet_path "${nocache_path}") + elseif("${location}" STREQUAL "ITCM_SECTION") + set(snippet_path "${itcm_path}") + elseif("${location}" STREQUAL "DTCM_SECTION") + set(snippet_path "${dtcm_path}") elseif("${location}" STREQUAL "PINNED_RAM_SECTIONS") set(snippet_path "${pinned_ram_sections_path}") elseif("${location}" STREQUAL "PINNED_DATA_SECTIONS") diff --git a/include/zephyr/arch/arm/cortex_m/scripts/linker.ld b/include/zephyr/arch/arm/cortex_m/scripts/linker.ld index 9ed4009db91..7d842ae0567 100644 --- a/include/zephyr/arch/arm/cortex_m/scripts/linker.ld +++ b/include/zephyr/arch/arm/cortex_m/scripts/linker.ld @@ -396,6 +396,11 @@ GROUP_START(ITCM) __itcm_start = .; *(.itcm) *(".itcm.*") + +/* Located in generated directory. This file is populated by the + * zephyr_linker_sources() Cmake function. */ +#include + __itcm_end = .; } GROUP_LINK_IN(ITCM AT> ROMABLE_REGION) @@ -430,6 +435,11 @@ GROUP_START(DTCM) __dtcm_data_start = .; *(.dtcm_data) *(".dtcm_data.*") + +/* Located in generated directory. This file is populated by the + * zephyr_linker_sources() Cmake function. */ +#include + __dtcm_data_end = .; } GROUP_LINK_IN(DTCM AT> ROMABLE_REGION) diff --git a/include/zephyr/arch/riscv/common/linker.ld b/include/zephyr/arch/riscv/common/linker.ld index e9ac6d32d86..8c3dee305f9 100644 --- a/include/zephyr/arch/riscv/common/linker.ld +++ b/include/zephyr/arch/riscv/common/linker.ld @@ -327,6 +327,11 @@ GROUP_START(ITCM) __itcm_start = .; *(.itcm) *(".itcm.*") + +/* Located in generated directory. This file is populated by the + * zephyr_linker_sources() Cmake function. */ +#include + __itcm_end = .; } GROUP_LINK_IN(ITCM AT> ROMABLE_REGION) @@ -361,6 +366,11 @@ GROUP_START(DTCM) __dtcm_data_start = .; *(.dtcm_data) *(".dtcm_data.*") + +/* Located in generated directory. This file is populated by the + * zephyr_linker_sources() Cmake function. */ +#include + __dtcm_data_end = .; } GROUP_LINK_IN(DTCM AT> ROMABLE_REGION) diff --git a/soc/riscv/andes_v5/ae350/linker.ld b/soc/riscv/andes_v5/ae350/linker.ld index 9f7d1274655..041d0aad530 100644 --- a/soc/riscv/andes_v5/ae350/linker.ld +++ b/soc/riscv/andes_v5/ae350/linker.ld @@ -322,6 +322,11 @@ GROUP_START(ITCM) __itcm_start = .; *(.itcm) *(".itcm.*") + +/* Located in generated directory. This file is populated by the + * zephyr_linker_sources() Cmake function. */ +#include + __itcm_end = .; } GROUP_LINK_IN(ITCM AT> ROMABLE_REGION) @@ -356,6 +361,11 @@ GROUP_START(DTCM) __dtcm_data_start = .; *(.dtcm_data) *(".dtcm_data.*") + +/* Located in generated directory. This file is populated by the + * zephyr_linker_sources() Cmake function. */ +#include + __dtcm_data_end = .; } GROUP_LINK_IN(DTCM AT> ROMABLE_REGION) From 81022fae79ac481b367b2b29d93aeb38fc665cf1 Mon Sep 17 00:00:00 2001 From: Greter Raffael Date: Tue, 14 Nov 2023 08:33:57 +0000 Subject: [PATCH 2799/3723] linker: Only use itcm and dtcm snippets if regions exist This tests whether there actually is an itcm or dtcm in the device tree. Otherwise a FATAL_ERROR is generated. Signed-off-by: Greter Raffael --- cmake/modules/extensions.cmake | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/cmake/modules/extensions.cmake b/cmake/modules/extensions.cmake index 629e8411ce8..1c3e7d5abf1 100644 --- a/cmake/modules/extensions.cmake +++ b/cmake/modules/extensions.cmake @@ -1270,8 +1270,20 @@ function(zephyr_linker_sources location) elseif("${location}" STREQUAL "NOCACHE_SECTION") set(snippet_path "${nocache_path}") elseif("${location}" STREQUAL "ITCM_SECTION") + dt_has_chosen(HAS_ITCM PROPERTY "zephyr,itcm") + if(NOT HAS_ITCM) + message(FATAL_ERROR "Trying to link snippet into itcm but no itcm available. " + "Add `zephyr,itcm` to the device tree if supported on your device or choose another " + "location.") + endif() set(snippet_path "${itcm_path}") elseif("${location}" STREQUAL "DTCM_SECTION") + dt_has_chosen(HAS_DTCM PROPERTY "zephyr,dtcm") + if(NOT HAS_DTCM) + message(FATAL_ERROR "Trying to link snippet into dtcm but no dtcm available. " + "Add `zephyr,dtcm` to the device tree if supported on your device or choose another " + "location.") + endif() set(snippet_path "${dtcm_path}") elseif("${location}" STREQUAL "PINNED_RAM_SECTIONS") set(snippet_path "${pinned_ram_sections_path}") From 88c4362ef7b9c408f0428430afa01fa91c039110 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?J=C4=99drzej=20Ciupis?= Date: Tue, 23 Jan 2024 07:55:49 +0100 Subject: [PATCH 2800/3723] manifest: update hal_nordic revision MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This commit updates revision of hal_nordic repo. Signed-off-by: Jędrzej Ciupis --- west.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/west.yml b/west.yml index b07c73568ea..0a6c6f07e33 100644 --- a/west.yml +++ b/west.yml @@ -183,7 +183,7 @@ manifest: groups: - hal - name: hal_nordic - revision: a5f11c33864264c60a81bf83e5d5643260296eb5 + revision: 4362d0fcdbac80942212bffc999654beac7ab30e path: modules/hal/nordic groups: - hal From a7ba06bedb9530aa53516b64e7bcb4541517fc1b Mon Sep 17 00:00:00 2001 From: Jordan Yates Date: Tue, 23 Jan 2024 13:49:50 +1000 Subject: [PATCH 2801/3723] flash: spi_nor: don't hard loop in `wait_until_ready` Don't monopolise the CPU in `spi_nor_wait_until_ready`. For slow flash chips, operations can take minutes (Full chip erase on MX25R is listed as 120s typical, 240s max). Signed-off-by: Jordan Yates --- drivers/flash/Kconfig.nor | 10 ++++++++++ drivers/flash/spi_nor.c | 15 ++++++++++++--- 2 files changed, 22 insertions(+), 3 deletions(-) diff --git a/drivers/flash/Kconfig.nor b/drivers/flash/Kconfig.nor index 507e681c120..8263f7f6785 100644 --- a/drivers/flash/Kconfig.nor +++ b/drivers/flash/Kconfig.nor @@ -55,6 +55,16 @@ config SPI_NOR_CS_WAIT_DELAY help This is the wait delay (in us) to allow for CS switching to take effect +config SPI_NOR_SLEEP_WHILE_WAITING_UNTIL_READY + bool "Sleep while waiting for flash operations to complete" + default y + help + Flash operations can take anywhere from 1ms to 240 seconds to + complete. Enabling this option adds a delay between polls on the + status register for slow operations. Disabling this option can + result in significant flash savings if this driver is the only user + of "k_sleep". This can be the case when building as a bootloader. + config SPI_NOR_FLASH_LAYOUT_PAGE_SIZE int "Page size to use for FLASH_LAYOUT feature" default 65536 diff --git a/drivers/flash/spi_nor.c b/drivers/flash/spi_nor.c index 06518175e45..5f7282d22a6 100644 --- a/drivers/flash/spi_nor.c +++ b/drivers/flash/spi_nor.c @@ -402,10 +402,19 @@ static int spi_nor_wait_until_ready(const struct device *dev) int ret; uint8_t reg; - do { - ret = spi_nor_cmd_read(dev, SPI_NOR_CMD_RDSR, ®, sizeof(reg)); - } while (!ret && (reg & SPI_NOR_WIP_BIT)); + ARG_UNUSED(poll_delay); + while (true) { + ret = spi_nor_cmd_read(dev, SPI_NOR_CMD_RDSR, ®, sizeof(reg)); + /* Exit on error or no longer WIP */ + if (ret || !(reg & SPI_NOR_WIP_BIT)) { + break; + } +#ifdef CONFIG_SPI_NOR_SLEEP_WHILE_WAITING_UNTIL_READY + /* Don't monopolise the CPU while waiting for ready */ + k_sleep(K_TICKS(1)); +#endif /* CONFIG_SPI_NOR_SLEEP_WHILE_WAITING_UNTIL_READY */ + } return ret; } From 4019d1774621563cbba609fe94d34aec77f7d2a1 Mon Sep 17 00:00:00 2001 From: Jordan Yates Date: Tue, 23 Jan 2024 14:03:04 +1000 Subject: [PATCH 2802/3723] flash: spi_nor: different `wait_until_ready` delays Provide different loop delays to `wait_until_ready` based upon the operation that we are waiting for. Signed-off-by: Jordan Yates --- drivers/flash/spi_nor.c | 22 +++++++++++++++------- 1 file changed, 15 insertions(+), 7 deletions(-) diff --git a/drivers/flash/spi_nor.c b/drivers/flash/spi_nor.c index 5f7282d22a6..065795d4924 100644 --- a/drivers/flash/spi_nor.c +++ b/drivers/flash/spi_nor.c @@ -186,6 +186,13 @@ static const struct jesd216_erase_type minimal_erase_types[JESD216_NUM_ERASE_TYP }; #endif /* CONFIG_SPI_NOR_SFDP_MINIMAL */ +/* Register writes should be ready extremely quickly */ +#define WAIT_READY_REGISTER K_NO_WAIT +/* Page writes range from sub-ms to 10ms */ +#define WAIT_READY_WRITE K_TICKS(1) +/* Erases can range from 45ms to 240sec */ +#define WAIT_READY_ERASE K_MSEC(50) + static int spi_nor_write_protection_set(const struct device *dev, bool write_protect); @@ -395,9 +402,10 @@ static int spi_nor_access(const struct device *const dev, * in the code. * * @param dev The device structure + * @param poll_delay Duration between polls of status register * @return 0 on success, negative errno code otherwise */ -static int spi_nor_wait_until_ready(const struct device *dev) +static int spi_nor_wait_until_ready(const struct device *dev, k_timeout_t poll_delay) { int ret; uint8_t reg; @@ -412,7 +420,7 @@ static int spi_nor_wait_until_ready(const struct device *dev) } #ifdef CONFIG_SPI_NOR_SLEEP_WHILE_WAITING_UNTIL_READY /* Don't monopolise the CPU while waiting for ready */ - k_sleep(K_TICKS(1)); + k_sleep(poll_delay); #endif /* CONFIG_SPI_NOR_SLEEP_WHILE_WAITING_UNTIL_READY */ } return ret; @@ -567,7 +575,7 @@ static int spi_nor_wrsr(const struct device *dev, if (ret == 0) { ret = spi_nor_access(dev, SPI_NOR_CMD_WRSR, NOR_ACCESS_WRITE, 0, &sr, sizeof(sr)); - spi_nor_wait_until_ready(dev); + spi_nor_wait_until_ready(dev, WAIT_READY_REGISTER); } return ret; @@ -635,7 +643,7 @@ static int mxicy_wrcr(const struct device *dev, ret = spi_nor_access(dev, SPI_NOR_CMD_WRSR, NOR_ACCESS_WRITE, 0, data, sizeof(data)); - spi_nor_wait_until_ready(dev); + spi_nor_wait_until_ready(dev, WAIT_READY_REGISTER); } return ret; @@ -781,7 +789,7 @@ static int spi_nor_write(const struct device *dev, off_t addr, src = (const uint8_t *)src + to_write; addr += to_write; - spi_nor_wait_until_ready(dev); + spi_nor_wait_until_ready(dev, WAIT_READY_WRITE); } } @@ -863,7 +871,7 @@ static int spi_nor_erase(const struct device *dev, off_t addr, size_t size) */ volatile int xcc_ret = #endif - spi_nor_wait_until_ready(dev); + spi_nor_wait_until_ready(dev, WAIT_READY_ERASE); } int ret2 = spi_nor_write_protection_set(dev, true); @@ -1248,7 +1256,7 @@ static int spi_nor_configure(const struct device *dev) rc = spi_nor_rdsr(dev); if (rc > 0 && (rc & SPI_NOR_WIP_BIT)) { LOG_WRN("Waiting until flash is ready"); - spi_nor_wait_until_ready(dev); + spi_nor_wait_until_ready(dev, WAIT_READY_REGISTER); } release_device(dev); From 019fbefa0ffffcc83526ea753337c9d5bcea6c58 Mon Sep 17 00:00:00 2001 From: Timm Knape Date: Wed, 24 Jan 2024 14:26:19 +0100 Subject: [PATCH 2803/3723] doc: Clarified usage of STL with Minimal C++ Library STL is not available, so the applications should *not* rely on it. Signed-off-by: Timm Knape --- doc/develop/languages/cpp/index.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/doc/develop/languages/cpp/index.rst b/doc/develop/languages/cpp/index.rst index 5ba5c7d7688..492872d7e9c 100644 --- a/doc/develop/languages/cpp/index.rst +++ b/doc/develop/languages/cpp/index.rst @@ -83,7 +83,7 @@ The scope of the minimal C++ library is strictly limited to providing the basic C++ language support, and it does not implement any `Standard Template Library (STL)`_ classes and functions. For this reason, it is only suitable for use in the applications that implement their own (non-standard) class library and do -rely on the Standard Template Library (STL) components. +not rely on the Standard Template Library (STL) components. Any application that makes use of the Standard Template Library (STL) components, such as ``std::string`` and ``std::vector``, must enable the C++ From caf9a533301aed7d8213e4f28670cb424de1a9ce Mon Sep 17 00:00:00 2001 From: Mykola Kvach Date: Tue, 23 Jan 2024 00:43:58 +0200 Subject: [PATCH 2804/3723] drivers: pinctrl: renesas: fix ipsr generation for S4 Avoid unexpected memory access in cases where the IPSR has an odd register index. In the scenario where an odd register index is present in IPSR, the LSB of the register index is utilized as MSB of the bank number. Observe how we pack reg/bank: 'IPSR(((reg) << 4U) | (bank), shift, func)' (macro IPnSR) and how it is read from the device tree source: '(RCAR_IPSR(node_id) >> 10U) & 0x1FU' (macro RCAR_PIN_FUNC). Finally, this bank is used to obtain the required IPSR offset: 'PFC_RCAR_IPSR + rcar_func->bank * sizeof(uint32_t)' in the 'pfc_rcar_set_ipsr' function. For example, if we have the 1 as a reg index and the 3-rd bank, the resulting offset would be 19, which is beyond the IPSR range. Align the IPSR comment with the definition of the 'rcar_pin_func' structure. Note: we can omit the usage of the register index entirely since this information is obtained from the pin number inside the 'pfc_rcar_get_reg_index' function. Signed-off-by: Mykola Kvach --- .../dt-bindings/pinctrl/renesas/pinctrl-rcar-common.h | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/include/zephyr/dt-bindings/pinctrl/renesas/pinctrl-rcar-common.h b/include/zephyr/dt-bindings/pinctrl/renesas/pinctrl-rcar-common.h index f483ec1bb49..43068fcad47 100644 --- a/include/zephyr/dt-bindings/pinctrl/renesas/pinctrl-rcar-common.h +++ b/include/zephyr/dt-bindings/pinctrl/renesas/pinctrl-rcar-common.h @@ -17,8 +17,10 @@ * @param func the 4 bits encoded alternate function. * * Function code [ 0 : 3 ] - * Function shift [ 4 : 9 ] - * IPSR bank [ 10 : 13 ] + * Function shift [ 4 : 8 ] + * Empty [ 9 ] + * IPSR bank [ 10 : 14 ] + * Register index [ 15 : 17 ] (S4 only) */ #define IPSR(bank, shift, func) (((bank) << 10U) | ((shift) << 4U) | (func)) @@ -45,7 +47,7 @@ * Each base address has 4 IPSR banks. */ #define IPnSR(bank, reg, shift, func) \ - IPSR(((reg) << 4U) | (bank), shift, func) + IPSR(((reg) << 5U) | (bank), shift, func) #define IP0SR0(shift, func) IPnSR(0, 0, shift, func) #define IP1SR0(shift, func) IPnSR(1, 0, shift, func) From 09fbd4c2cd52c221cb4093342d392b4610838491 Mon Sep 17 00:00:00 2001 From: Mykola Kvach Date: Tue, 23 Jan 2024 02:32:53 +0200 Subject: [PATCH 2805/3723] drivers: pinctrl: renesas: add definitions of missed IPSR macros Add missed definitions of IP[0-3]SR[67] macros. Signed-off-by: Mykola Kvach --- .../dt-bindings/pinctrl/renesas/pinctrl-rcar-common.h | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/include/zephyr/dt-bindings/pinctrl/renesas/pinctrl-rcar-common.h b/include/zephyr/dt-bindings/pinctrl/renesas/pinctrl-rcar-common.h index 43068fcad47..30a2afe1db1 100644 --- a/include/zephyr/dt-bindings/pinctrl/renesas/pinctrl-rcar-common.h +++ b/include/zephyr/dt-bindings/pinctrl/renesas/pinctrl-rcar-common.h @@ -73,6 +73,14 @@ #define IP1SR5(shift, func) IPnSR(1, 5, shift, func) #define IP2SR5(shift, func) IPnSR(2, 5, shift, func) #define IP3SR5(shift, func) IPnSR(3, 5, shift, func) +#define IP0SR6(shift, func) IPnSR(0, 6, shift, func) +#define IP1SR6(shift, func) IPnSR(1, 6, shift, func) +#define IP2SR6(shift, func) IPnSR(2, 6, shift, func) +#define IP3SR6(shift, func) IPnSR(3, 6, shift, func) +#define IP0SR7(shift, func) IPnSR(0, 7, shift, func) +#define IP1SR7(shift, func) IPnSR(1, 7, shift, func) +#define IP2SR7(shift, func) IPnSR(2, 7, shift, func) +#define IP3SR7(shift, func) IPnSR(3, 7, shift, func) #define PIN_VOLTAGE_NONE 0 #define PIN_VOLTAGE_1P8V 1 From e541666d90b3f5e621649c8fc488796ebf02c0da Mon Sep 17 00:00:00 2001 From: Guillaume Gautier Date: Mon, 27 Nov 2023 12:15:06 +0100 Subject: [PATCH 2806/3723] drivers: timer: stm32: lptim: remove init to 0 of static Remove initialization of static variable to 0 to prevent resetting the value when reinitializing the driver after resume from standby. This has no impact since static variables are initialized to 0 by default. Signed-off-by: Guillaume Gautier --- drivers/timer/stm32_lptim_timer.c | 2 -- 1 file changed, 2 deletions(-) diff --git a/drivers/timer/stm32_lptim_timer.c b/drivers/timer/stm32_lptim_timer.c index 16e8b62c3d3..4ad3bae3cad 100644 --- a/drivers/timer/stm32_lptim_timer.c +++ b/drivers/timer/stm32_lptim_timer.c @@ -448,8 +448,6 @@ static int sys_clock_driver_init(void) stm32_lptim_wait_ready(); LL_LPTIM_ClearFlag_ARROK(LPTIM); - accumulated_lptim_cnt = 0; - #if !defined(CONFIG_SOC_SERIES_STM32U5X) && \ !defined(CONFIG_SOC_SERIES_STM32WBAX) /* Enable the LPTIM counter */ From 58c296b30ffde8e4f40e9e7f0131f6f12ee5c088 Mon Sep 17 00:00:00 2001 From: Guillaume Gautier Date: Mon, 27 Nov 2023 12:15:06 +0100 Subject: [PATCH 2807/3723] drivers: timer: stm32 lptim: add support for backup standby timer Add support for a backup standby timer in STM32 LPTIM driver for cases when the LPTIM is not available (ie standby low power mode). A counter (typically RTC) is used for such a case. Signed-off-by: Guillaume Gautier --- drivers/timer/Kconfig.stm32_lptim | 20 ++++++ drivers/timer/stm32_lptim_timer.c | 113 ++++++++++++++++++++++++++++++ 2 files changed, 133 insertions(+) diff --git a/drivers/timer/Kconfig.stm32_lptim b/drivers/timer/Kconfig.stm32_lptim index dc64ec5bda3..31bddc07409 100644 --- a/drivers/timer/Kconfig.stm32_lptim +++ b/drivers/timer/Kconfig.stm32_lptim @@ -3,6 +3,8 @@ # Copyright (c) 2019 STMicroelectronics # SPDX-License-Identifier: Apache-2.0 +DT_CHOSEN_STDBY_TIMER := st,lptim-stdby-timer + menuconfig STM32_LPTIM_TIMER bool "STM32 Low Power Timer [EXPERIMENTAL]" default y @@ -56,4 +58,22 @@ config STM32_LPTIM_TICK_FREQ_RATIO_OVERRIDE in the driver. This options allows to override this check +config STM32_LPTIM_STDBY_TIMER + bool "Use an additional timer while entering Standby mode" + default $(dt_chosen_enabled,$(DT_CHOSEN_STDBY_TIMER)) + depends on COUNTER + depends on TICKLESS_KERNEL + select EXPERIMENTAL + help + There are chips e.g. STM32WBAX family that use LPTIM as a system timer, + but LPTIM is not clocked in standby mode. These chips usually have + another timer that is not stopped, but it has lower frequency e.g. + RTC, thus it can't be used as a main system timer. + + Use the Standby timer for timeout (wakeup) when the system is entering + Standby state. + + The chosen Standby timer node has to support setting alarm from the + counter API. + endif # STM32_LPTIM_TIMER diff --git a/drivers/timer/stm32_lptim_timer.c b/drivers/timer/stm32_lptim_timer.c index 4ad3bae3cad..ba00014ad45 100644 --- a/drivers/timer/stm32_lptim_timer.c +++ b/drivers/timer/stm32_lptim_timer.c @@ -17,6 +17,8 @@ #include #include #include +#include +#include #include @@ -80,6 +82,32 @@ static bool autoreload_ready = true; static struct k_spinlock lock; +#ifdef CONFIG_STM32_LPTIM_STDBY_TIMER + +#define CURRENT_CPU \ + (COND_CODE_1(CONFIG_SMP, (arch_curr_cpu()->id), (_current_cpu->id))) + +#define cycle_t uint32_t + +/* This local variable indicates that the timeout was set right before + * entering standby state. + * + * It is used for chips that has to use a separate standby timer in such + * case because the LPTIM is not clocked in some low power mode state. + */ +static bool timeout_stdby; + +/* Cycle counter before entering the standby state. */ +static cycle_t lptim_cnt_pre_stdby; + +/* Standby timer value before entering the standby state. */ +static uint32_t stdby_timer_pre_stdby; + +/* Standby timer used for timer while entering the standby state */ +static const struct device *stdby_timer = DEVICE_DT_GET(DT_CHOSEN(st_lptim_stdby_timer)); + +#endif /* CONFIG_STM32_LPTIM_STDBY_TIMER */ + static inline bool arrm_state_get(void) { return (LL_LPTIM_IsActiveFlag_ARRM(LPTIM) && LL_LPTIM_IsEnabledIT_ARRM(LPTIM)); @@ -171,6 +199,41 @@ void sys_clock_set_timeout(int32_t ticks, bool idle) ARG_UNUSED(idle); +#ifdef CONFIG_STM32_LPTIM_STDBY_TIMER + const struct pm_state_info *next; + + next = pm_policy_next_state(CURRENT_CPU, ticks); + + if ((next != NULL) && (next->state == PM_STATE_SUSPEND_TO_RAM)) { + uint64_t timeout_us = + ((uint64_t)ticks * USEC_PER_SEC) / CONFIG_SYS_CLOCK_TICKS_PER_SEC; + + struct counter_alarm_cfg cfg = { + .callback = NULL, + .ticks = counter_us_to_ticks(stdby_timer, timeout_us), + .user_data = NULL, + .flags = 0, + }; + + timeout_stdby = true; + + /* Set the alarm using timer that runs the standby. + * Needed rump-up/setting time, lower accurency etc. should be + * included in the exit-latency in the power state definition. + */ + counter_cancel_channel_alarm(stdby_timer, 0); + counter_set_channel_alarm(stdby_timer, 0, &cfg); + + /* Store current values to calculate a difference in + * measurements after exiting the standby state. + */ + counter_get_value(stdby_timer, &stdby_timer_pre_stdby); + lptim_cnt_pre_stdby = z_clock_lptim_getcounter(); + + return; + } +#endif /* CONFIG_STM32_LPTIM_STDBY_TIMER */ + if (!IS_ENABLED(CONFIG_TICKLESS_KERNEL)) { return; } @@ -480,5 +543,55 @@ static int sys_clock_driver_init(void) return 0; } +void sys_clock_idle_exit(void) +{ +#ifdef CONFIG_STM32_LPTIM_STDBY_TIMER + if (clock_control_get_status(clk_ctrl, + (clock_control_subsys_t) &lptim_clk[0]) + != CLOCK_CONTROL_STATUS_ON) { + sys_clock_driver_init(); + } else if (timeout_stdby) { + cycle_t missed_lptim_cnt; + uint32_t stdby_timer_diff, stdby_timer_post, dticks; + uint64_t stdby_timer_us; + + /* Get current value for standby timer and reset LPTIM counter value + * to start anew. + */ + LL_LPTIM_ResetCounter(LPTIM); + counter_get_value(stdby_timer, &stdby_timer_post); + + /* Calculate how much time has passed since last measurement for standby timer */ + /* Check IDLE timer overflow */ + if (stdby_timer_pre_stdby > stdby_timer_post) { + stdby_timer_diff = + (counter_get_top_value(stdby_timer) - stdby_timer_pre_stdby) + + stdby_timer_post + 1; + + } else { + stdby_timer_diff = stdby_timer_post - stdby_timer_pre_stdby; + } + stdby_timer_us = counter_ticks_to_us(stdby_timer, stdby_timer_diff); + + /* Convert standby time in LPTIM cnt */ + missed_lptim_cnt = (sys_clock_hw_cycles_per_sec() * stdby_timer_us) / + USEC_PER_SEC; + /* Add the LPTIM cnt pre standby */ + missed_lptim_cnt += lptim_cnt_pre_stdby; + + /* Update the cycle counter to include the cycles missed in standby */ + accumulated_lptim_cnt += missed_lptim_cnt; + + /* Announce the passed ticks to the kernel */ + dticks = (missed_lptim_cnt * CONFIG_SYS_CLOCK_TICKS_PER_SEC) + / lptim_clock_freq; + sys_clock_announce(dticks); + + /* We've already performed all needed operations */ + timeout_stdby = false; + } +#endif /* CONFIG_STM32_LPTIM_STDBY_TIMER */ +} + SYS_INIT(sys_clock_driver_init, PRE_KERNEL_2, CONFIG_SYSTEM_CLOCK_INIT_PRIORITY); From 02ef0c5fb9ef21762dcfdfd3b9d0f787b840a6bf Mon Sep 17 00:00:00 2001 From: Guillaume Gautier Date: Wed, 29 Nov 2023 11:55:45 +0100 Subject: [PATCH 2808/3723] drivers: gpio: stm32: do not resume device when flag is DISCONNECTED Fix a bug where after a standby, it was impossible to reenable a GPIO clock. A counter is incremented each time pm_device_runtime_get is called, and decremented each time pm_device_runtime_put is called. The clock is only enabled if this counter equals 1. When configuring a GPIO (as input or output), the timer is incremented, and when disconnecting it, it is both incremented and decremented. Thus the next time we try to configuring it, the clock is not enabled (since the counter will now be equal to 2). This causes a problem when using low power standby mode: after wakeup all clocks are disabled and the GPIO clock can not be reenabled. This commit fixes this bug by not incrementing the counter when disconnect is asked (or in other words incrementing it only when configuring either an input or an output). Signed-off-by: Guillaume Gautier --- drivers/gpio/gpio_stm32.c | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/drivers/gpio/gpio_stm32.c b/drivers/gpio/gpio_stm32.c index fe6d98d7a35..e2cdb1d5325 100644 --- a/drivers/gpio/gpio_stm32.c +++ b/drivers/gpio/gpio_stm32.c @@ -524,9 +524,11 @@ static int gpio_stm32_config(const struct device *dev, } /* Enable device clock before configuration (requires bank writes) */ - err = pm_device_runtime_get(dev); - if (err < 0) { - return err; + if (((flags & GPIO_OUTPUT) != 0) || ((flags & GPIO_INPUT) != 0)) { + err = pm_device_runtime_get(dev); + if (err < 0) { + return err; + } } if ((flags & GPIO_OUTPUT) != 0) { From be26c71fd40e15e99195e5dd8eea9fbf195b48ad Mon Sep 17 00:00:00 2001 From: Guillaume Gautier Date: Wed, 17 Jan 2024 09:02:53 +0100 Subject: [PATCH 2809/3723] drivers: serial: stm32: prevent suspend to ram when operation in progress Prevent the system to enter Suspend to RAM state while UART operation is in progress. Signed-off-by: Guillaume Gautier --- drivers/serial/uart_stm32.c | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/drivers/serial/uart_stm32.c b/drivers/serial/uart_stm32.c index c785c1e4f89..cba80aa6f00 100644 --- a/drivers/serial/uart_stm32.c +++ b/drivers/serial/uart_stm32.c @@ -96,6 +96,9 @@ static void uart_stm32_pm_policy_state_lock_get(const struct device *dev) if (!data->pm_policy_state_on) { data->pm_policy_state_on = true; pm_policy_state_lock_get(PM_STATE_SUSPEND_TO_IDLE, PM_ALL_SUBSTATES); + if (IS_ENABLED(CONFIG_PM_S2RAM)) { + pm_policy_state_lock_get(PM_STATE_SUSPEND_TO_RAM, PM_ALL_SUBSTATES); + } } } @@ -106,6 +109,9 @@ static void uart_stm32_pm_policy_state_lock_put(const struct device *dev) if (data->pm_policy_state_on) { data->pm_policy_state_on = false; pm_policy_state_lock_put(PM_STATE_SUSPEND_TO_IDLE, PM_ALL_SUBSTATES); + if (IS_ENABLED(CONFIG_PM_S2RAM)) { + pm_policy_state_lock_put(PM_STATE_SUSPEND_TO_RAM, PM_ALL_SUBSTATES); + } } } #endif /* CONFIG_PM */ From 0792a85f77340f09cf15f333692b1c6506414f5d Mon Sep 17 00:00:00 2001 From: Guillaume Gautier Date: Fri, 8 Dec 2023 14:11:53 +0100 Subject: [PATCH 2810/3723] drivers: serial: stm32: add reinit after standby When resuming from low power mode, if UART is disabled, this means that we come from a mode that reset the registers, so we redo a full init of the driver. Signed-off-by: Guillaume Gautier --- drivers/serial/uart_stm32.c | 29 +++++++++++++++++++---------- 1 file changed, 19 insertions(+), 10 deletions(-) diff --git a/drivers/serial/uart_stm32.c b/drivers/serial/uart_stm32.c index cba80aa6f00..107dd88d7ce 100644 --- a/drivers/serial/uart_stm32.c +++ b/drivers/serial/uart_stm32.c @@ -2081,17 +2081,26 @@ static int uart_stm32_pm_action(const struct device *dev, switch (action) { case PM_DEVICE_ACTION_RESUME: - /* Set pins to active state */ - err = pinctrl_apply_state(config->pcfg, PINCTRL_STATE_DEFAULT); - if (err < 0) { - return err; - } + /* When exiting low power mode, check whether UART is enabled. + * If not, it means we are exiting Suspend to RAM mode (STM32 + * Standby), and the driver need to be reinitialized + */ + if (LL_USART_IsEnabled(config->usart)) { + /* Set pins to active state */ + err = pinctrl_apply_state(config->pcfg, PINCTRL_STATE_DEFAULT); + if (err < 0) { + return err; + } - /* enable clock */ - err = clock_control_on(data->clock, (clock_control_subsys_t)&config->pclken[0]); - if (err != 0) { - LOG_ERR("Could not enable (LP)UART clock"); - return err; + /* enable clock */ + err = clock_control_on(data->clock, + (clock_control_subsys_t)&config->pclken[0]); + if (err != 0) { + LOG_ERR("Could not enable (LP)UART clock"); + return err; + } + } else { + uart_stm32_init(dev); } break; case PM_DEVICE_ACTION_SUSPEND: From 276fc569d6e6de64b47c83b661f01e80d5e25030 Mon Sep 17 00:00:00 2001 From: Guillaume Gautier Date: Fri, 15 Dec 2023 09:07:30 +0100 Subject: [PATCH 2811/3723] drivers: adc: stm32: prevent suspend to ram while measure in progress Prevents the system to go in Suspend to RAM low power mode while ADC measurement is in progress. Signed-off-by: Guillaume Gautier --- drivers/adc/adc_stm32.c | 16 +++++++++++++++- 1 file changed, 15 insertions(+), 1 deletion(-) diff --git a/drivers/adc/adc_stm32.c b/drivers/adc/adc_stm32.c index 0b8a1415535..158743f7464 100644 --- a/drivers/adc/adc_stm32.c +++ b/drivers/adc/adc_stm32.c @@ -676,7 +676,7 @@ static void adc_stm32_oversampling_ratioshift(ADC_TypeDef *adc, uint32_t ratio, } /* - * Function to configure the oversampling ratio and shit using stm32 LL + * Function to configure the oversampling ratio and shift using stm32 LL * ratio is directly the sequence->oversampling (a 2^n value) * shift is the corresponding LL_ADC_OVS_SHIFT_RIGHT_x constant */ @@ -760,6 +760,10 @@ static void dma_callback(const struct device *dev, void *user_data, adc_context_on_sampling_done(&data->ctx, dev); pm_policy_state_lock_put(PM_STATE_SUSPEND_TO_IDLE, PM_ALL_SUBSTATES); + if (IS_ENABLED(CONFIG_PM_S2RAM)) { + pm_policy_state_lock_put(PM_STATE_SUSPEND_TO_RAM, + PM_ALL_SUBSTATES); + } } else if (status < 0) { LOG_ERR("DMA sampling complete, but DMA reported error %d", status); data->dma_error = status; @@ -1062,6 +1066,10 @@ static void adc_stm32_isr(const struct device *dev) adc_context_on_sampling_done(&data->ctx, dev); pm_policy_state_lock_put(PM_STATE_SUSPEND_TO_IDLE, PM_ALL_SUBSTATES); + if (IS_ENABLED(CONFIG_PM_S2RAM)) { + pm_policy_state_lock_put(PM_STATE_SUSPEND_TO_RAM, + PM_ALL_SUBSTATES); + } } } @@ -1098,6 +1106,9 @@ static int adc_stm32_read(const struct device *dev, adc_context_lock(&data->ctx, false, NULL); pm_policy_state_lock_get(PM_STATE_SUSPEND_TO_IDLE, PM_ALL_SUBSTATES); + if (IS_ENABLED(CONFIG_PM_S2RAM)) { + pm_policy_state_lock_get(PM_STATE_SUSPEND_TO_RAM, PM_ALL_SUBSTATES); + } error = start_read(dev, sequence); adc_context_release(&data->ctx, error); @@ -1114,6 +1125,9 @@ static int adc_stm32_read_async(const struct device *dev, adc_context_lock(&data->ctx, true, async); pm_policy_state_lock_get(PM_STATE_SUSPEND_TO_IDLE, PM_ALL_SUBSTATES); + if (IS_ENABLED(CONFIG_PM_S2RAM)) { + pm_policy_state_lock_get(PM_STATE_SUSPEND_TO_RAM, PM_ALL_SUBSTATES); + } error = start_read(dev, sequence); adc_context_release(&data->ctx, error); From b8fdcbb59ee551d8b02c4e6a35f254ea3d0b3e42 Mon Sep 17 00:00:00 2001 From: Guillaume Gautier Date: Tue, 2 Jan 2024 14:54:54 +0100 Subject: [PATCH 2812/3723] drivers: entropy: stm32: prevent suspend to ram when operation in progress Prevent the system to enter Suspend to RAM state while RNG operation is in progress. Signed-off-by: Guillaume Gautier --- drivers/entropy/entropy_stm32.c | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/drivers/entropy/entropy_stm32.c b/drivers/entropy/entropy_stm32.c index 910a40c6640..b526156fd79 100644 --- a/drivers/entropy/entropy_stm32.c +++ b/drivers/entropy/entropy_stm32.c @@ -417,6 +417,9 @@ static int start_pool_filling(bool wait) * rng pool is filled. */ pm_policy_state_lock_get(PM_STATE_SUSPEND_TO_IDLE, PM_ALL_SUBSTATES); + if (IS_ENABLED(CONFIG_PM_S2RAM)) { + pm_policy_state_lock_get(PM_STATE_SUSPEND_TO_RAM, PM_ALL_SUBSTATES); + } acquire_rng(); irq_enable(IRQN); @@ -546,6 +549,9 @@ static void stm32_rng_isr(const void *arg) irq_disable(IRQN); release_rng(); pm_policy_state_lock_put(PM_STATE_SUSPEND_TO_IDLE, PM_ALL_SUBSTATES); + if (IS_ENABLED(CONFIG_PM_S2RAM)) { + pm_policy_state_lock_put(PM_STATE_SUSPEND_TO_RAM, PM_ALL_SUBSTATES); + } entropy_stm32_rng_data.filling_pools = false; } From 5aff88ab936d1246881b3bdbff0be257cc5aa35a Mon Sep 17 00:00:00 2001 From: Guillaume Gautier Date: Wed, 10 Jan 2024 16:09:04 +0100 Subject: [PATCH 2813/3723] drivers: entropy: stm32: reinit rng when exiting suspend to ram With PM, when resuming from low power mode, reenable the RNG register clocks and check the health register. If it is not set to the desired value, it means we exit Suspend to RAM mode, and that the RNG needs to be reinitialized. Signed-off-by: Guillaume Gautier --- drivers/entropy/entropy_stm32.c | 27 ++++++++++++++++++++++++--- 1 file changed, 24 insertions(+), 3 deletions(-) diff --git a/drivers/entropy/entropy_stm32.c b/drivers/entropy/entropy_stm32.c index b526156fd79..9d0e0eb6c48 100644 --- a/drivers/entropy/entropy_stm32.c +++ b/drivers/entropy/entropy_stm32.c @@ -701,16 +701,37 @@ static int entropy_stm32_rng_init(const struct device *dev) static int entropy_stm32_rng_pm_action(const struct device *dev, enum pm_device_action action) { + struct entropy_stm32_rng_dev_data *dev_data = dev->data; + int res = 0; + /* Remove warning on some platforms */ + ARG_UNUSED(dev_data); + switch (action) { case PM_DEVICE_ACTION_SUSPEND: res = entropy_stm32_suspend(); break; case PM_DEVICE_ACTION_RESUME: - /* Resume RNG only if it was suspended during filling pool */ - if (entropy_stm32_rng_data.filling_pools) { - res = entropy_stm32_resume(); + if (IS_ENABLED(CONFIG_PM_S2RAM)) { +#if DT_INST_NODE_HAS_PROP(0, health_test_config) + entropy_stm32_resume(); +#if DT_INST_NODE_HAS_PROP(0, health_test_magic) + LL_RNG_SetHealthConfig(rng, DT_INST_PROP(0, health_test_magic)); +#endif /* health_test_magic */ + if (LL_RNG_GetHealthConfig(dev_data->rng) != + DT_INST_PROP_OR(0, health_test_config, 0U)) { + entropy_stm32_rng_init(dev); + } else if (!entropy_stm32_rng_data.filling_pools) { + /* Resume RNG only if it was suspended during filling pool */ + entropy_stm32_suspend(); + } +#endif /* health_test_config */ + } else { + /* Resume RNG only if it was suspended during filling pool */ + if (entropy_stm32_rng_data.filling_pools) { + res = entropy_stm32_resume(); + } } break; default: From 62809d758160baed837b6589ff8122cedc29951d Mon Sep 17 00:00:00 2001 From: Magdalena Kasenberg Date: Wed, 24 Jan 2024 14:51:35 +0100 Subject: [PATCH 2814/3723] bluetooth: tester: Enable BT_CTLR_ISOAL_PSN_IGNORE Temporarily ignore the Tx ISO Data Packet Sequence Number use as the tester app does not have yet a synchronization mechanism for the sequence number and it constantly fails to send ISO data on time. Signed-off-by: Magdalena Kasenberg --- tests/bluetooth/tester/nrf5340_hci_ipc_cpunet.conf | 1 + 1 file changed, 1 insertion(+) diff --git a/tests/bluetooth/tester/nrf5340_hci_ipc_cpunet.conf b/tests/bluetooth/tester/nrf5340_hci_ipc_cpunet.conf index 399262b47c9..b5b8a8971ce 100644 --- a/tests/bluetooth/tester/nrf5340_hci_ipc_cpunet.conf +++ b/tests/bluetooth/tester/nrf5340_hci_ipc_cpunet.conf @@ -3,3 +3,4 @@ CONFIG_BT_CTLR_CONN_ISO_LOW_LATENCY_POLICY=y CONFIG_BT_CTLR_DATA_LENGTH_MAX=100 CONFIG_BT_BUF_ACL_RX_SIZE=100 CONFIG_BT_CTLR_PERIPHERAL_ISO_EARLY_CIG_START=y +CONFIG_BT_CTLR_ISOAL_PSN_IGNORE=y From 27b0d4e3fee2f56413757e13a3fcd522e9447921 Mon Sep 17 00:00:00 2001 From: Bjarki Arge Andreasen Date: Mon, 15 Jan 2024 10:19:29 +0100 Subject: [PATCH 2815/3723] modem: chat: remove receive and transmit timeouts Remove receive and transmit timeouts which are no longer useful as the RECEIVE_READY and TRANSMIT_IDLE events will be used to efficiently manage timeouts between transmit/receive calls. Then update the the in-tree drivers using the modem_chat module to omit the process timeout parameter. Signed-off-by: Bjarki Arge Andreasen --- drivers/gnss/gnss_nmea_generic.c | 1 - drivers/gnss/gnss_quectel_lcx6g.c | 1 - drivers/modem/modem_cellular.c | 1 - include/zephyr/modem/chat.h | 7 ++---- subsys/modem/modem_chat.c | 27 +++++++++++------------- tests/subsys/modem/modem_chat/src/main.c | 1 - 6 files changed, 14 insertions(+), 24 deletions(-) diff --git a/drivers/gnss/gnss_nmea_generic.c b/drivers/gnss/gnss_nmea_generic.c index 6d9adfb6990..2f23f4d7353 100644 --- a/drivers/gnss/gnss_nmea_generic.c +++ b/drivers/gnss/gnss_nmea_generic.c @@ -127,7 +127,6 @@ static int gnss_nmea_generic_init_chat(const struct device *dev) .argv_size = ARRAY_SIZE(data->chat_argv), .unsol_matches = unsol_matches, .unsol_matches_size = ARRAY_SIZE(unsol_matches), - .process_timeout = K_MSEC(2), }; return modem_chat_init(&data->chat, &chat_config); diff --git a/drivers/gnss/gnss_quectel_lcx6g.c b/drivers/gnss/gnss_quectel_lcx6g.c index 61d39140a9a..9c706e237a3 100644 --- a/drivers/gnss/gnss_quectel_lcx6g.c +++ b/drivers/gnss/gnss_quectel_lcx6g.c @@ -686,7 +686,6 @@ static int quectel_lcx6g_init_chat(const struct device *dev) .argv_size = ARRAY_SIZE(data->chat_argv), .unsol_matches = unsol_matches, .unsol_matches_size = ARRAY_SIZE(unsol_matches), - .process_timeout = K_MSEC(2), }; return modem_chat_init(&data->chat, &chat_config); diff --git a/drivers/modem/modem_cellular.c b/drivers/modem/modem_cellular.c index d1f3a69c94e..8aca855f55b 100644 --- a/drivers/modem/modem_cellular.c +++ b/drivers/modem/modem_cellular.c @@ -1520,7 +1520,6 @@ static int modem_cellular_init(const struct device *dev) .argv_size = ARRAY_SIZE(data->chat_argv), .unsol_matches = unsol_matches, .unsol_matches_size = ARRAY_SIZE(unsol_matches), - .process_timeout = K_MSEC(2), }; modem_chat_init(&data->chat, &chat_config); diff --git a/include/zephyr/modem/chat.h b/include/zephyr/modem/chat.h index d46ffc7c24a..7079cb8c61d 100644 --- a/include/zephyr/modem/chat.h +++ b/include/zephyr/modem/chat.h @@ -242,7 +242,7 @@ struct modem_chat { /* Script sending */ uint16_t script_send_request_pos; uint16_t script_send_delimiter_pos; - struct k_work_delayable script_send_work; + struct k_work script_send_work; struct k_work_delayable script_send_timeout_work; /* Match parsing */ @@ -252,8 +252,7 @@ struct modem_chat { uint16_t parse_match_type; /* Process received data */ - struct k_work_delayable process_work; - k_timeout_t process_timeout; + struct k_work receive_work; }; /** @@ -282,8 +281,6 @@ struct modem_chat_config { const struct modem_chat_match *unsol_matches; /** Elements in array of unsolicited matches */ uint16_t unsol_matches_size; - /** Delay from receive ready event to pipe receive occurs */ - k_timeout_t process_timeout; }; /** diff --git a/subsys/modem/modem_chat.c b/subsys/modem/modem_chat.c index f3857bcfbc3..99cf9bdbfa6 100644 --- a/subsys/modem/modem_chat.c +++ b/subsys/modem/modem_chat.c @@ -97,7 +97,7 @@ static void modem_chat_script_stop(struct modem_chat *chat, enum modem_chat_scri /* Cancel work */ k_work_cancel_delayable(&chat->script_timeout_work); - k_work_cancel_delayable(&chat->script_send_work); + k_work_cancel(&chat->script_send_work); k_work_cancel_delayable(&chat->script_send_timeout_work); /* Clear script running state */ @@ -117,7 +117,7 @@ static void modem_chat_script_send(struct modem_chat *chat) chat->script_send_delimiter_pos = 0; /* Schedule script send work */ - k_work_schedule(&chat->script_send_work, K_NO_WAIT); + k_work_submit(&chat->script_send_work); } static void modem_chat_script_set_response_matches(struct modem_chat *chat) @@ -308,8 +308,7 @@ static uint16_t modem_chat_script_chat_get_send_timeout(struct modem_chat *chat) static void modem_chat_script_send_handler(struct k_work *item) { - struct k_work_delayable *dwork = k_work_delayable_from_work(item); - struct modem_chat *chat = CONTAINER_OF(dwork, struct modem_chat, script_send_work); + struct modem_chat *chat = CONTAINER_OF(item, struct modem_chat, script_send_work); uint16_t timeout; /* Validate script running */ @@ -319,13 +318,13 @@ static void modem_chat_script_send_handler(struct k_work *item) /* Send request */ if (modem_chat_script_send_request(chat) == false) { - k_work_schedule(&chat->script_send_work, chat->process_timeout); + k_work_submit(&chat->script_send_work); return; } /* Send delimiter */ if (modem_chat_script_send_delimiter(chat) == false) { - k_work_schedule(&chat->script_send_work, chat->process_timeout); + k_work_submit(&chat->script_send_work); return; } @@ -687,8 +686,7 @@ static void modem_chat_process_bytes(struct modem_chat *chat) static void modem_chat_process_handler(struct k_work *item) { - struct k_work_delayable *dwork = k_work_delayable_from_work(item); - struct modem_chat *chat = CONTAINER_OF(dwork, struct modem_chat, process_work); + struct modem_chat *chat = CONTAINER_OF(item, struct modem_chat, receive_work); int ret; /* Fill work buffer */ @@ -702,7 +700,7 @@ static void modem_chat_process_handler(struct k_work *item) /* Process data */ modem_chat_process_bytes(chat); - k_work_schedule(&chat->process_work, K_NO_WAIT); + k_work_submit(&chat->receive_work); } static void modem_chat_pipe_callback(struct modem_pipe *pipe, enum modem_pipe_event event, @@ -711,7 +709,7 @@ static void modem_chat_pipe_callback(struct modem_pipe *pipe, enum modem_pipe_ev struct modem_chat *chat = (struct modem_chat *)user_data; if (event == MODEM_PIPE_EVENT_RECEIVE_READY) { - k_work_schedule(&chat->process_work, chat->process_timeout); + k_work_submit(&chat->receive_work); } } @@ -741,14 +739,13 @@ int modem_chat_init(struct modem_chat *chat, const struct modem_chat_config *con chat->filter_size = config->filter_size; chat->matches[MODEM_CHAT_MATCHES_INDEX_UNSOL] = config->unsol_matches; chat->matches_size[MODEM_CHAT_MATCHES_INDEX_UNSOL] = config->unsol_matches_size; - chat->process_timeout = config->process_timeout; atomic_set(&chat->script_state, 0); k_sem_init(&chat->script_stopped_sem, 0, 1); - k_work_init_delayable(&chat->process_work, modem_chat_process_handler); + k_work_init(&chat->receive_work, modem_chat_process_handler); k_work_init(&chat->script_run_work, modem_chat_script_run_handler); k_work_init_delayable(&chat->script_timeout_work, modem_chat_script_timeout_handler); k_work_init(&chat->script_abort_work, modem_chat_script_abort_handler); - k_work_init_delayable(&chat->script_send_work, modem_chat_script_send_handler); + k_work_init(&chat->script_send_work, modem_chat_script_send_handler); k_work_init_delayable(&chat->script_send_timeout_work, modem_chat_script_send_timeout_handler); @@ -831,8 +828,8 @@ void modem_chat_release(struct modem_chat *chat) k_work_cancel_sync(&chat->script_run_work, &sync); k_work_cancel_sync(&chat->script_abort_work, &sync); - k_work_cancel_delayable_sync(&chat->process_work, &sync); - k_work_cancel_delayable_sync(&chat->script_send_work, &sync); + k_work_cancel_sync(&chat->receive_work, &sync); + k_work_cancel_sync(&chat->script_send_work, &sync); chat->pipe = NULL; chat->receive_buf_len = 0; diff --git a/tests/subsys/modem/modem_chat/src/main.c b/tests/subsys/modem/modem_chat/src/main.c index 3f1ef57754d..f9a37ecc6cc 100644 --- a/tests/subsys/modem/modem_chat/src/main.c +++ b/tests/subsys/modem/modem_chat/src/main.c @@ -254,7 +254,6 @@ static void *test_modem_chat_setup(void) .argv_size = ARRAY_SIZE(cmd_argv), .unsol_matches = unsol_matches, .unsol_matches_size = ARRAY_SIZE(unsol_matches), - .process_timeout = K_MSEC(2), }; zassert(modem_chat_init(&cmd, &cmd_config) == 0, "Failed to init modem CMD"); From d801e697ddd1b0a3ae3df14f66c1d3a8f646d79b Mon Sep 17 00:00:00 2001 From: Bjarki Arge Andreasen Date: Mon, 15 Jan 2024 14:29:48 +0100 Subject: [PATCH 2816/3723] modem: chat: Implement TRANSMIT_IDLE event Refactors modem chat module to use TRANSMIT_IDLE event instead of polling when transmitting, cleaning up the transmit handler by combining duplicate code and using an internal state instead of multiple iterators to track send state. Signed-off-by: Bjarki Arge Andreasen --- include/zephyr/modem/chat.h | 4 +- subsys/modem/modem_chat.c | 153 ++++++++++++++++-------------------- 2 files changed, 71 insertions(+), 86 deletions(-) diff --git a/include/zephyr/modem/chat.h b/include/zephyr/modem/chat.h index 7079cb8c61d..28a2bc6bf9f 100644 --- a/include/zephyr/modem/chat.h +++ b/include/zephyr/modem/chat.h @@ -240,8 +240,8 @@ struct modem_chat { struct k_sem script_stopped_sem; /* Script sending */ - uint16_t script_send_request_pos; - uint16_t script_send_delimiter_pos; + enum modem_chat_script_send_state script_send_state; + uint16_t script_send_pos; struct k_work script_send_work; struct k_work_delayable script_send_timeout_work; diff --git a/subsys/modem/modem_chat.c b/subsys/modem/modem_chat.c index 99cf9bdbfa6..b2d63b05e9e 100644 --- a/subsys/modem/modem_chat.c +++ b/subsys/modem/modem_chat.c @@ -110,13 +110,16 @@ static void modem_chat_script_stop(struct modem_chat *chat, enum modem_chat_scri k_sem_give(&chat->script_stopped_sem); } -static void modem_chat_script_send(struct modem_chat *chat) +static void modem_chat_set_script_send_state(struct modem_chat *chat, + enum modem_chat_script_send_state state) { - /* Initialize script send work */ - chat->script_send_request_pos = 0; - chat->script_send_delimiter_pos = 0; + chat->script_send_pos = 0; + chat->script_send_state = state; +} - /* Schedule script send work */ +static void modem_chat_script_send(struct modem_chat *chat) +{ + modem_chat_set_script_send_state(chat, MODEM_CHAT_SCRIPT_SEND_STATE_REQUEST); k_work_submit(&chat->script_send_work); } @@ -219,91 +222,58 @@ static void modem_chat_script_abort_handler(struct k_work *item) modem_chat_script_stop(chat, MODEM_CHAT_SCRIPT_RESULT_ABORT); } -static bool modem_chat_script_send_request(struct modem_chat *chat) +static bool modem_chat_script_chat_is_no_response(struct modem_chat *chat) { const struct modem_chat_script_chat *script_chat = &chat->script->script_chats[chat->script_chat_it]; - uint8_t *script_chat_request_start; - uint16_t script_chat_request_remaining; - int ret; - - /* Validate data to send */ - if (script_chat->request_size == chat->script_send_request_pos) { - return true; - } - - script_chat_request_start = (uint8_t *)&script_chat->request[chat->script_send_request_pos]; - script_chat_request_remaining = script_chat->request_size - chat->script_send_request_pos; - - /* Send data through pipe */ - ret = modem_pipe_transmit(chat->pipe, script_chat_request_start, - script_chat_request_remaining); - - /* Validate transmit successful */ - if (ret < 1) { - return false; - } - - /* Update script send position */ - chat->script_send_request_pos += (uint16_t)ret; + return (script_chat->response_matches_size == 0) ? true : false; +} - /* Check if data remains */ - if (chat->script_send_request_pos < script_chat->request_size) { - return false; - } +static uint16_t modem_chat_script_chat_get_send_timeout(struct modem_chat *chat) +{ + const struct modem_chat_script_chat *script_chat = + &chat->script->script_chats[chat->script_chat_it]; - return true; + return script_chat->timeout; } -static bool modem_chat_script_send_delimiter(struct modem_chat *chat) +/* Returns true when request part has been sent */ +static bool modem_chat_send_script_request_part(struct modem_chat *chat) { - uint8_t *script_chat_delimiter_start; - uint8_t script_chat_delimiter_remaining; - int ret; + const struct modem_chat_script_chat *script_chat = + &chat->script->script_chats[chat->script_chat_it]; - /* Validate data to send */ - if (chat->delimiter_size == chat->script_send_delimiter_pos) { - return true; - } + uint8_t *request_part; + uint16_t request_size; + uint16_t request_part_size; + int ret; - script_chat_delimiter_start = (uint8_t *)&chat->delimiter[chat->script_send_delimiter_pos]; - script_chat_delimiter_remaining = chat->delimiter_size - chat->script_send_delimiter_pos; + switch (chat->script_send_state) { + case MODEM_CHAT_SCRIPT_SEND_STATE_REQUEST: + request_part = (uint8_t *)(&script_chat->request[chat->script_send_pos]); + request_size = script_chat->request_size; + break; - /* Send data through pipe */ - ret = modem_pipe_transmit(chat->pipe, script_chat_delimiter_start, - script_chat_delimiter_remaining); + case MODEM_CHAT_SCRIPT_SEND_STATE_DELIMITER: + request_part = (uint8_t *)(&chat->delimiter[chat->script_send_pos]); + request_size = chat->delimiter_size; + break; - /* Validate transmit successful */ - if (ret < 1) { + default: return false; } - /* Update script send position */ - chat->script_send_delimiter_pos += (uint8_t)ret; - - /* Check if data remains */ - if (chat->script_send_delimiter_pos < chat->delimiter_size) { + request_part_size = request_size - chat->script_send_pos; + ret = modem_pipe_transmit(chat->pipe, request_part, request_part_size); + if (ret < 1) { return false; } - return true; -} - -static bool modem_chat_script_chat_is_no_response(struct modem_chat *chat) -{ - const struct modem_chat_script_chat *script_chat = - &chat->script->script_chats[chat->script_chat_it]; - - return (script_chat->response_matches_size == 0) ? true : false; -} + chat->script_send_pos += (uint16_t)ret; -static uint16_t modem_chat_script_chat_get_send_timeout(struct modem_chat *chat) -{ - const struct modem_chat_script_chat *script_chat = - &chat->script->script_chats[chat->script_chat_it]; - - return script_chat->timeout; + /* Return true if all data was sent */ + return request_size <= chat->script_send_pos; } static void modem_chat_script_send_handler(struct k_work *item) @@ -311,27 +281,33 @@ static void modem_chat_script_send_handler(struct k_work *item) struct modem_chat *chat = CONTAINER_OF(item, struct modem_chat, script_send_work); uint16_t timeout; - /* Validate script running */ if (chat->script == NULL) { return; } - /* Send request */ - if (modem_chat_script_send_request(chat) == false) { - k_work_submit(&chat->script_send_work); + switch (chat->script_send_state) { + case MODEM_CHAT_SCRIPT_SEND_STATE_IDLE: return; - } - /* Send delimiter */ - if (modem_chat_script_send_delimiter(chat) == false) { - k_work_submit(&chat->script_send_work); - return; + case MODEM_CHAT_SCRIPT_SEND_STATE_REQUEST: + if (!modem_chat_send_script_request_part(chat)) { + return; + } + + modem_chat_set_script_send_state(chat, MODEM_CHAT_SCRIPT_SEND_STATE_DELIMITER); + __fallthrough; + + case MODEM_CHAT_SCRIPT_SEND_STATE_DELIMITER: + if (!modem_chat_send_script_request_part(chat)) { + return; + } + + modem_chat_set_script_send_state(chat, MODEM_CHAT_SCRIPT_SEND_STATE_IDLE); + break; } - /* Check if script command is no response */ if (modem_chat_script_chat_is_no_response(chat)) { timeout = modem_chat_script_chat_get_send_timeout(chat); - if (timeout == 0) { modem_chat_script_next(chat, false); } else { @@ -708,8 +684,17 @@ static void modem_chat_pipe_callback(struct modem_pipe *pipe, enum modem_pipe_ev { struct modem_chat *chat = (struct modem_chat *)user_data; - if (event == MODEM_PIPE_EVENT_RECEIVE_READY) { + switch (event) { + case MODEM_PIPE_EVENT_RECEIVE_READY: k_work_submit(&chat->receive_work); + break; + + case MODEM_PIPE_EVENT_TRANSMIT_IDLE: + k_work_submit(&chat->script_send_work); + break; + + default: + break; } } @@ -840,8 +825,8 @@ void modem_chat_release(struct modem_chat *chat) atomic_set(&chat->script_state, 0); chat->script_result = MODEM_CHAT_SCRIPT_RESULT_ABORT; k_sem_reset(&chat->script_stopped_sem); - chat->script_send_request_pos = 0; - chat->script_send_delimiter_pos = 0; + chat->script_send_state = MODEM_CHAT_SCRIPT_SEND_STATE_IDLE; + chat->script_send_pos = 0; chat->parse_match = NULL; chat->parse_match_len = 0; chat->parse_arg_len = 0; From 57057b141c232bc7555de3ce4f0a8847bf721590 Mon Sep 17 00:00:00 2001 From: Christopher Friedt Date: Wed, 24 Jan 2024 13:28:45 -0500 Subject: [PATCH 2817/3723] posix: add a top-level menu Add a top-level menu to prevent POSIX API options from cluttering the menuconfig view under "Additional libraries". Signed-off-by: Christopher Friedt --- lib/posix/Kconfig | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/lib/posix/Kconfig b/lib/posix/Kconfig index ccf1a036318..b1443a5ab71 100644 --- a/lib/posix/Kconfig +++ b/lib/posix/Kconfig @@ -3,6 +3,8 @@ # # SPDX-License-Identifier: Apache-2.0 +menu "POSIX API Support" + config POSIX_MAX_FDS int "Maximum number of open file descriptors" default 16 if WIFI_NM_WPA_SUPPLICANT @@ -58,3 +60,5 @@ source "lib/posix/Kconfig.timer" source "lib/posix/Kconfig.uname" rsource "shell/Kconfig" + +endmenu # "POSIX API Support" From 4f40dd1f950c43b982e524f18e7e7f5f595f5ee9 Mon Sep 17 00:00:00 2001 From: Keith Packard Date: Sun, 21 Jan 2024 17:37:46 -0800 Subject: [PATCH 2818/3723] tests/strerror: Remove test for non-standard strerror_r function Zephyr does not include this function under Rule A.4: C Standard Library Usage Restrictions in Zephyr Kernel, hence a conforming C library need not provide it. Signed-off-by: Keith Packard --- tests/lib/c_lib/strerror/src/main.c | 42 ----------------------------- 1 file changed, 42 deletions(-) diff --git a/tests/lib/c_lib/strerror/src/main.c b/tests/lib/c_lib/strerror/src/main.c index 8bfd06bbff5..494902b019c 100644 --- a/tests/lib/c_lib/strerror/src/main.c +++ b/tests/lib/c_lib/strerror/src/main.c @@ -55,46 +55,4 @@ ZTEST(libc_strerror, test_strerror) } } -ZTEST(libc_strerror, test_strerror_r) -{ - const char *expected; - char actual[] = {'1', 'n', 'v', 'a', '1', '1', 'd', ' ', 'a', - '2', 'g', 'u', 'm', '3', 'n', '7', 0x00, 0x42}; - static const size_t n = sizeof(actual); - - if (IS_ENABLED(CONFIG_NEWLIB_LIBC) || IS_ENABLED(CONFIG_ARCMWDT_LIBC)) { - /* FIXME: Please see Issue #46846 */ - ztest_test_skip(); - } - - errno = 4242; - if (IS_ENABLED(CONFIG_MINIMAL_LIBC_DISABLE_STRING_ERROR_TABLE)) { - expected = ""; - zassert_equal(0, strerror_r(EINVAL, actual, n), ""); - zassert_equal(0, strncmp(expected, actual, n), - "mismatch: exp: %s act: %s", expected, actual); - } else { - expected = "Invalid argument"; - zassert_equal(0, strerror_r(EINVAL, actual, n), "%d", - strerror_r(EINVAL, actual, n)); - zassert_equal(0, strncmp(expected, actual, n), - "mismatch: exp: %s act: %s", expected, actual); - /* only the necessary buffer area is written */ - zassert_equal(0x42, (uint8_t)actual[n - 1], - "exp: %02x act: %02x", 0x42, - (uint8_t)actual[n - 1]); - - zassert_equal(ERANGE, strerror_r(EINVAL, actual, 0), ""); - } - - /* do not change errno on success */ - zassert_equal(4242, errno, ""); - - errno = 0; - zassert_equal(EINVAL, strerror_r(-42, actual, n), ""); - zassert_equal(EINVAL, strerror_r(4242, actual, n), ""); - /* do not change errno on failure */ - zassert_equal(0, errno, ""); -} - ZTEST_SUITE(libc_strerror, NULL, NULL, NULL, NULL, NULL); From b27494b7eded21187b3a97cdfd4e99d3a8adda55 Mon Sep 17 00:00:00 2001 From: Keith Packard Date: Sun, 21 Jan 2024 15:35:56 -0800 Subject: [PATCH 2819/3723] lib/libc: Update picolibc to 1.8.6 * Reduces memory usage for ctype while fixing an 'isblank' related compatibility issue. * Resolves compatibility issues with GCC 13 * Removes explicit _POSIX_C_SOURCE definition when building as a module. * Fix some _FORTIFY_SOURCE issues. Signed-off-by: Keith Packard --- west.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/west.yml b/west.yml index 0a6c6f07e33..9d1a4a21529 100644 --- a/west.yml +++ b/west.yml @@ -310,7 +310,7 @@ manifest: - debug - name: picolibc path: modules/lib/picolibc - revision: 1a5c603b9f8e228f9459bdafedad15ea28efc700 + revision: 764ef4e401a8f4c6a86ab723533841f072885a5b - name: segger revision: 9d0191285956cef43daf411edc2f1a7788346def path: modules/debug/segger From 3fc5d971fe2868675028e32e5d0a60a5c5ebe2b7 Mon Sep 17 00:00:00 2001 From: Flavio Ceolin Date: Mon, 30 Oct 2023 13:39:41 -0700 Subject: [PATCH 2820/3723] security: Add compiler static analysis support Enable GCC builtin static analysis in Zephyr's static code analysis (SCA) infra. When this option is enabled GCC performs a static analysis and can point problems like: sample.c + int *j; + + if (j != NULL) { + printf("j != NULL\n"); output: ${ZEPHYR_BASE}/samples/userspace/hello_world_user/src/main.c:30:12: warning: use of uninitialized value 'j' [CWE-457] [-Wanalyzer-use-of-uninitialized-value] 30 | if (j != NULL) { | ^ 'main': events 1-2 | | 25 | int *j; | | ^ | | | | | (1) region created on stack here |...... | 30 | if (j != NULL) { | | ~ | | | | | (2) use of uninitialized value 'j' here Signed-off-by: Flavio Ceolin --- cmake/sca/gcc/sca.cmake | 5 +++++ doc/develop/sca/gcc.rst | 18 ++++++++++++++++++ doc/develop/sca/index.rst | 1 + 3 files changed, 24 insertions(+) create mode 100644 cmake/sca/gcc/sca.cmake create mode 100644 doc/develop/sca/gcc.rst diff --git a/cmake/sca/gcc/sca.cmake b/cmake/sca/gcc/sca.cmake new file mode 100644 index 00000000000..c106933c101 --- /dev/null +++ b/cmake/sca/gcc/sca.cmake @@ -0,0 +1,5 @@ +# SPDX-License-Identifier: Apache-2.0 +# +# Copyright (c) 2024 Intel Corporation + +list(APPEND TOOLCHAIN_C_FLAGS -fanalyzer) diff --git a/doc/develop/sca/gcc.rst b/doc/develop/sca/gcc.rst new file mode 100644 index 00000000000..4ae852c81ad --- /dev/null +++ b/doc/develop/sca/gcc.rst @@ -0,0 +1,18 @@ +.. _gcc: + +GCC static analysis support +########################### + +Static analysis was introduced in `GCC `__ 10 and it is enabled +with the option ``-fanalyzer``. This option performs a much more expensive and thorough +analysis of the code than traditional warnings. + +Run GCC static analysis +*********************** + +To run GCC static analysis, :ref:`west build ` should be +called with a ``-DZEPHYR_SCA_VARIANT=gcc`` parameter, e.g. + +.. code-block:: shell + + west build -b qemu_x86 samples/userspace/hello_world_user -- -DZEPHYR_SCA_VARIANT=gcc diff --git a/doc/develop/sca/index.rst b/doc/develop/sca/index.rst index 08b9d96a0cc..b0896f566b9 100644 --- a/doc/develop/sca/index.rst +++ b/doc/develop/sca/index.rst @@ -63,3 +63,4 @@ The following is a list of SCA tools natively supported by Zephyr build system. codechecker sparse + gcc From c6ed39e3adcdcafd3edc874aae6711f8a6c802bf Mon Sep 17 00:00:00 2001 From: Alberto Escolar Piedras Date: Tue, 23 Jan 2024 13:09:50 +0100 Subject: [PATCH 2821/3723] drivers entropy fake_native: Add option to seed generator randomly Add a command line option which will seed the random generator from /dev/urandom. This can be usefull for some particular tests in which we are interested in having different random numbers in each run, but we cannot provide a different random seed from command line. Signed-off-by: Alberto Escolar Piedras --- drivers/entropy/CMakeLists.txt | 10 +++++- drivers/entropy/fake_entropy_native_bottom.c | 34 ++++++++++++++++++++ drivers/entropy/fake_entropy_native_bottom.h | 21 ++++++++++++ drivers/entropy/fake_entropy_native_posix.c | 32 ++++++++++-------- 4 files changed, 83 insertions(+), 14 deletions(-) create mode 100644 drivers/entropy/fake_entropy_native_bottom.c create mode 100644 drivers/entropy/fake_entropy_native_bottom.h diff --git a/drivers/entropy/CMakeLists.txt b/drivers/entropy/CMakeLists.txt index 7ca87d60944..11e361517c2 100644 --- a/drivers/entropy/CMakeLists.txt +++ b/drivers/entropy/CMakeLists.txt @@ -17,7 +17,15 @@ zephyr_library_sources_ifdef(CONFIG_ENTROPY_SAM_RNG entropy_sam.c) zephyr_library_sources_ifdef(CONFIG_ENTROPY_SMARTBOND_TRNG entropy_smartbond.c) zephyr_library_sources_ifdef(CONFIG_ENTROPY_STM32_RNG entropy_stm32.c) zephyr_library_sources_ifdef(CONFIG_ENTROPY_LITEX_RNG entropy_litex.c) -zephyr_library_sources_ifdef(CONFIG_FAKE_ENTROPY_NATIVE_POSIX fake_entropy_native_posix.c) +if(CONFIG_FAKE_ENTROPY_NATIVE_POSIX) + zephyr_library_sources(fake_entropy_native_posix.c) + if(CONFIG_NATIVE_LIBRARY) + target_sources(native_simulator INTERFACE fake_entropy_native_bottom.c) + else() + zephyr_library_sources(fake_entropy_native_bottom.c) + endif() +endif() + zephyr_library_sources_ifdef(CONFIG_USERSPACE entropy_handlers.c) zephyr_library_sources_ifdef(CONFIG_ENTROPY_RV32M1_TRNG entropy_rv32m1_trng.c) zephyr_library_sources_ifdef(CONFIG_ENTROPY_GECKO_TRNG entropy_gecko_trng.c) diff --git a/drivers/entropy/fake_entropy_native_bottom.c b/drivers/entropy/fake_entropy_native_bottom.c new file mode 100644 index 00000000000..ccfb7974e34 --- /dev/null +++ b/drivers/entropy/fake_entropy_native_bottom.c @@ -0,0 +1,34 @@ +/* + * Copyright (c) 2024 Nordic Semiconductor ASA + * + * SPDX-License-Identifier: Apache-2.0 + * + * Bottom/Linux side of the pseudo-random entropy generator for + * ARCH_POSIX architecture + */ + +#include +#include +#include +#include +#include +#include "nsi_tracing.h" + +void entropy_native_seed(unsigned int seed, bool seed_random) +{ + if (seed_random == false) { + srandom(seed); + } else { + unsigned int buf; + int err = getrandom(&buf, sizeof(buf), 0); + + if (err != sizeof(buf)) { + nsi_print_error_and_exit("Could not get random number (%i, %s)\n", + err, strerror(errno)); + } + srandom(buf); + + /* Let's print the seed so users can still reproduce the run if they need to */ + nsi_print_trace("Random generator seeded with 0x%X\n", buf); + } +} diff --git a/drivers/entropy/fake_entropy_native_bottom.h b/drivers/entropy/fake_entropy_native_bottom.h new file mode 100644 index 00000000000..3fedffc0aac --- /dev/null +++ b/drivers/entropy/fake_entropy_native_bottom.h @@ -0,0 +1,21 @@ +/* + * Copyright (c) 2024 Nordic Semiconductor ASA + * + * SPDX-License-Identifier: Apache-2.0 + */ + + +#ifndef DRIVERS_ENTROPY_FAKE_ENTROPY_NATIVE_BOTTOM_H +#define DRIVERS_ENTROPY_FAKE_ENTROPY_NATIVE_BOTTOM_H + +#ifdef __cplusplus +extern "C" { +#endif + +void entropy_native_seed(unsigned int seed, bool seed_random); + +#ifdef __cplusplus +} +#endif + +#endif /* DRIVERS_ENTROPY_FAKE_ENTROPY_NATIVE_BOTTOM_H */ diff --git a/drivers/entropy/fake_entropy_native_posix.c b/drivers/entropy/fake_entropy_native_posix.c index 33658155595..ccdd3aa46e5 100644 --- a/drivers/entropy/fake_entropy_native_posix.c +++ b/drivers/entropy/fake_entropy_native_posix.c @@ -23,8 +23,10 @@ #include "soc.h" #include "cmdline.h" /* native_posix command line options header */ #include "nsi_host_trampolines.h" +#include "fake_entropy_native_bottom.h" static unsigned int seed = 0x5678; +static bool seed_random; static int entropy_native_posix_get_entropy(const struct device *dev, uint8_t *buffer, @@ -67,7 +69,7 @@ static int entropy_native_posix_get_entropy_isr(const struct device *dev, static int entropy_native_posix_init(const struct device *dev) { ARG_UNUSED(dev); - nsi_host_srandom(seed); + entropy_native_seed(seed, seed_random); posix_print_warning("WARNING: " "Using a test - not safe - entropy source\n"); return 0; @@ -87,18 +89,22 @@ DEVICE_DT_INST_DEFINE(0, static void add_fake_entropy_option(void) { static struct args_struct_t entropy_options[] = { - /* - * Fields: - * manual, mandatory, switch, - * option_name, var_name ,type, - * destination, callback, - * description - */ - {false, false, false, - "seed", "r_seed", 'u', - (void *)&seed, NULL, - "A 32-bit integer seed value for the entropy device, such as " - "97229 (decimal), 0x17BCD (hex), or 0275715 (octal)"}, + { + .option = "seed", + .name = "r_seed", + .type = 'u', + .dest = (void *)&seed, + .descript = "A 32-bit integer seed value for the entropy device, such as " + "97229 (decimal), 0x17BCD (hex), or 0275715 (octal)" + }, + { + .is_switch = true, + .option = "seed-random", + .type = 'b', + .dest = (void *)&seed_random, + .descript = "Seed the random generator from /dev/urandom. " + "Note your test may not be reproducible if you set this option" + }, ARG_TABLE_ENDMARKER }; From 571b647825b0402b1b46b4347b1db508b14cdf88 Mon Sep 17 00:00:00 2001 From: Alberto Escolar Piedras Date: Thu, 28 Dec 2023 18:03:14 +0100 Subject: [PATCH 2822/3723] subsys/net/lib/lwm2m: Change how we seed the random generator Instead of seeding the random generator from the test itself calling into a host API, let's use the entropy generator option to be seeded from /dev/urandom This avoids trouble with the srandom() and time() calls not existing depending on the chosen C library. Signed-off-by: Alberto Escolar Piedras --- tests/net/lib/lwm2m/interop/boards/native_sim.conf | 1 + tests/net/lib/lwm2m/interop/src/lwm2m-client.c | 4 ---- 2 files changed, 1 insertion(+), 4 deletions(-) diff --git a/tests/net/lib/lwm2m/interop/boards/native_sim.conf b/tests/net/lib/lwm2m/interop/boards/native_sim.conf index 2dc86f3d484..99b234c8e66 100644 --- a/tests/net/lib/lwm2m/interop/boards/native_sim.conf +++ b/tests/net/lib/lwm2m/interop/boards/native_sim.conf @@ -6,3 +6,4 @@ CONFIG_NET_CONFIG_MY_IPV4_GW="192.0.2.2" CONFIG_NATIVE_SIM_SLOWDOWN_TO_REAL_TIME=y CONFIG_NATIVE_UART_0_ON_STDINOUT=y CONFIG_ASAN=y +CONFIG_NATIVE_EXTRA_CMDLINE_ARGS="--seed-random" diff --git a/tests/net/lib/lwm2m/interop/src/lwm2m-client.c b/tests/net/lib/lwm2m/interop/src/lwm2m-client.c index a150f1b41cb..cb4ab22acd2 100644 --- a/tests/net/lib/lwm2m/interop/src/lwm2m-client.c +++ b/tests/net/lib/lwm2m/interop/src/lwm2m-client.c @@ -224,10 +224,6 @@ int main(void) { int ret; -#if defined(CONFIG_BOARD_NATIVE_POSIX) - srandom(time(NULL)); -#endif - ret = lwm2m_setup(); if (ret < 0) { LOG_ERR("Cannot setup LWM2M fields (%d)", ret); From 7c21df641d66ba39027f757d2f9a1821bb927cd4 Mon Sep 17 00:00:00 2001 From: Nicolas Pitre Date: Tue, 23 Jan 2024 16:29:49 -0500 Subject: [PATCH 2823/3723] multi_heap: keep number of heaps as an unsigned value Although very unlikely for this value to ever be negative in practice, this would make Coverity happy. Fixes #67969 Signed-off-by: Nicolas Pitre --- include/zephyr/sys/multi_heap.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/include/zephyr/sys/multi_heap.h b/include/zephyr/sys/multi_heap.h index 1eebc1c150e..0b8c56bdbe0 100644 --- a/include/zephyr/sys/multi_heap.h +++ b/include/zephyr/sys/multi_heap.h @@ -58,7 +58,7 @@ struct sys_multi_heap_rec { }; struct sys_multi_heap { - int nheaps; + unsigned int nheaps; sys_multi_heap_fn_t choice; struct sys_multi_heap_rec heaps[MAX_MULTI_HEAPS]; }; From 73396f9f8644762c4b547679d9b2baabadc80924 Mon Sep 17 00:00:00 2001 From: Patryk Duda Date: Mon, 22 Jan 2024 16:01:21 +0100 Subject: [PATCH 2824/3723] flash: Add program/erase parallelism support for STM32F4x The implementation uses the same approach as STM32F1x. Program/erase speed can be set by setting 'write-block-size' flash property to 1, 2, 4 or 8. Signed-off-by: Patryk Duda --- drivers/flash/flash_stm32f4x.c | 31 ++++++++++++++++++++++++++----- 1 file changed, 26 insertions(+), 5 deletions(-) diff --git a/drivers/flash/flash_stm32f4x.c b/drivers/flash/flash_stm32f4x.c index 4261c26a589..10134a68a7c 100644 --- a/drivers/flash/flash_stm32f4x.c +++ b/drivers/flash/flash_stm32f4x.c @@ -20,6 +20,22 @@ LOG_MODULE_REGISTER(flash_stm32f4x, CONFIG_FLASH_LOG_LEVEL); +#if FLASH_STM32_WRITE_BLOCK_SIZE == 8 +typedef uint64_t flash_prg_t; +#define FLASH_PROGRAM_SIZE FLASH_PSIZE_DOUBLE_WORD +#elif FLASH_STM32_WRITE_BLOCK_SIZE == 4 +typedef uint32_t flash_prg_t; +#define FLASH_PROGRAM_SIZE FLASH_PSIZE_WORD +#elif FLASH_STM32_WRITE_BLOCK_SIZE == 2 +typedef uint16_t flash_prg_t; +#define FLASH_PROGRAM_SIZE FLASH_PSIZE_HALF_WORD +#elif FLASH_STM32_WRITE_BLOCK_SIZE == 1 +typedef uint8_t flash_prg_t; +#define FLASH_PROGRAM_SIZE FLASH_PSIZE_BYTE +#else +#error Write block size must be a power of 2, from 1 to 8 +#endif + bool flash_stm32_valid_range(const struct device *dev, off_t offset, uint32_t len, bool write) @@ -64,7 +80,7 @@ static inline void flush_cache(FLASH_TypeDef *regs) } } -static int write_byte(const struct device *dev, off_t offset, uint8_t val) +static int write_value(const struct device *dev, off_t offset, flash_prg_t val) { FLASH_TypeDef *regs = FLASH_STM32_REGS(dev); #if defined(FLASH_OPTCR_DB1M) @@ -95,13 +111,13 @@ static int write_byte(const struct device *dev, off_t offset, uint8_t val) #endif /* FLASH_OPTCR_DB1M */ regs->CR &= CR_PSIZE_MASK; - regs->CR |= FLASH_PSIZE_BYTE; + regs->CR |= FLASH_PROGRAM_SIZE; regs->CR |= FLASH_CR_PG; /* flush the register write */ tmp = regs->CR; - *((uint8_t *) offset + CONFIG_FLASH_BASE_ADDRESS) = val; + *((flash_prg_t *)(offset + CONFIG_FLASH_BASE_ADDRESS)) = val; rc = flash_stm32_wait_flash_idle(dev); regs->CR &= (~FLASH_CR_PG); @@ -152,6 +168,9 @@ static int erase_sector(const struct device *dev, uint32_t sector) } #endif + regs->CR &= CR_PSIZE_MASK; + regs->CR |= FLASH_PROGRAM_SIZE; + regs->CR &= ~FLASH_CR_SNB; regs->CR |= FLASH_CR_SER | (sector << 3); regs->CR |= FLASH_CR_STRT; @@ -199,9 +218,11 @@ int flash_stm32_write_range(const struct device *dev, unsigned int offset, const void *data, unsigned int len) { int i, rc = 0; + flash_prg_t value; - for (i = 0; i < len; i++, offset++) { - rc = write_byte(dev, offset, ((const uint8_t *) data)[i]); + for (i = 0; i < len / sizeof(flash_prg_t); i++) { + value = UNALIGNED_GET((flash_prg_t *)data + i); + rc = write_value(dev, offset + i * sizeof(flash_prg_t), value); if (rc < 0) { return rc; } From b3d2891e167fcff5e7e81b3cdc28a0c18d80005d Mon Sep 17 00:00:00 2001 From: Hang Fan Date: Tue, 23 Jan 2024 22:10:04 +0800 Subject: [PATCH 2825/3723] Bluetooth: Classic: Add support for class of device Add `CONFIG_BT_COD` for class of device. < HCI Command: Write Class of Device (0x03|0x0024) plen 3 Class: 0x200408 Major class: Audio/Video (headset, speaker, stereo, video, vcr) Minor class: Hands-free Device Audio (Speaker, Microphone, Headset) > HCI Event: Command Complete (0x0e) plen 4 Write Class of Device (0x03|0x0024) ncmd 1 Status: Success (0x00) Signed-off-by: Hang Fan --- samples/bluetooth/handsfree/prj.conf | 1 + subsys/bluetooth/host/Kconfig | 8 ++++++++ subsys/bluetooth/host/br.c | 14 ++++++++++++++ 3 files changed, 23 insertions(+) diff --git a/samples/bluetooth/handsfree/prj.conf b/samples/bluetooth/handsfree/prj.conf index ce7e742f10b..924d9c0af0e 100644 --- a/samples/bluetooth/handsfree/prj.conf +++ b/samples/bluetooth/handsfree/prj.conf @@ -4,3 +4,4 @@ CONFIG_BT_RFCOMM=y CONFIG_BT_HFP_HF=y CONFIG_BT_PERIPHERAL=y CONFIG_BT_DEVICE_NAME="test-Handsfree" +CONFIG_BT_COD=0x200408 diff --git a/subsys/bluetooth/host/Kconfig b/subsys/bluetooth/host/Kconfig index d17aa7d1b0e..eb9db567469 100644 --- a/subsys/bluetooth/host/Kconfig +++ b/subsys/bluetooth/host/Kconfig @@ -1089,6 +1089,14 @@ config BT_PAGE_TIMEOUT This option sets the page timeout value. Value is selected as (N * 0.625) ms. +config BT_COD + hex "Bluetooth Class of Device(CoD)" + default 0 + help + This option sets the class of device.For the list of possible values please + consult the following link: + https://www.bluetooth.com/specifications/assigned-numbers + endif # BT_BREDR config BT_HCI_VS_EVT_USER diff --git a/subsys/bluetooth/host/br.c b/subsys/bluetooth/host/br.c index ab2ce914708..70cf6a76274 100644 --- a/subsys/bluetooth/host/br.c +++ b/subsys/bluetooth/host/br.c @@ -806,6 +806,7 @@ int bt_br_init(void) struct bt_hci_cp_write_ssp_mode *ssp_cp; struct bt_hci_cp_write_inquiry_mode *inq_cp; struct bt_hci_write_local_name *name_cp; + struct bt_hci_cp_write_class_of_device *cod; int err; /* Read extended local features */ @@ -869,6 +870,19 @@ int bt_br_init(void) return err; } + /* Set Class of device */ + buf = bt_hci_cmd_create(BT_HCI_OP_WRITE_CLASS_OF_DEVICE, sizeof(*cod)); + if (!buf) { + return -ENOBUFS; + } + + net_buf_add_le24(buf, CONFIG_BT_COD); + + err = bt_hci_cmd_send_sync(BT_HCI_OP_WRITE_CLASS_OF_DEVICE, buf, NULL); + if (err) { + return err; + } + /* Set page timeout*/ buf = bt_hci_cmd_create(BT_HCI_OP_WRITE_PAGE_TIMEOUT, sizeof(uint16_t)); if (!buf) { From 0786e523da4b247dd8f60cbb5da4aea2f954a021 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C3=98yvind=20R=C3=B8nningstad?= Date: Wed, 10 Jan 2024 09:09:41 +0100 Subject: [PATCH 2826/3723] west.yml: Update zcbor to 0.8.0 as well as uoscore-uedhoc and MCUboot MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Highlights of zcbor 0.8.0: - Add support for unordered maps - Performance improvements - Naming improvements for generated code - Bugfixes Update MCUboot and uoscore-uedhoc to bring in changes related to zcbor 0.8.0. Signed-off-by: Øyvind Rønningstad --- west.yml | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/west.yml b/west.yml index 9d1a4a21529..904d857d6e0 100644 --- a/west.yml +++ b/west.yml @@ -282,7 +282,7 @@ manifest: groups: - crypto - name: mcuboot - revision: b994ba2ce29425587957dcbb6c96d4e1872b5737 + revision: f09e205b1e4a8d2bc3f50dffa7960d6ccd14df59 path: bootloader/mcuboot - name: mipi-sys-t path: modules/debug/mipi-sys-t @@ -332,10 +332,10 @@ manifest: groups: - tee - name: uoscore-uedhoc - revision: 5024d8c98b3864c6698f0195a53e19c484bc8cd3 + revision: 150f4eb2955eaf36ac0f9519d4f4f58d5ade5740 path: modules/lib/uoscore-uedhoc - name: zcbor - revision: 67fd8bb88d3136738661fa8bb5f9989103f4599e + revision: dbe20afd00b3ddd6956f4b47f5df202bb49a8707 path: modules/lib/zcbor self: From 5d95776514df12a9dbfc239dd05f05e78ed461ed Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C3=98yvind=20R=C3=B8nningstad?= Date: Wed, 24 Jan 2024 15:20:57 +0100 Subject: [PATCH 2827/3723] scripts: requirements-extra.txt: Update zcbor from 0.6.0 to 0.8.0 MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit If people are using the zcbor script for code generation, it needs to be at the latest version Signed-off-by: Øyvind Rønningstad --- scripts/requirements-extras.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/scripts/requirements-extras.txt b/scripts/requirements-extras.txt index f210f069de9..99fa4f16cf4 100644 --- a/scripts/requirements-extras.txt +++ b/scripts/requirements-extras.txt @@ -32,4 +32,4 @@ PyGithub graphviz # used to generate CBOR encoders and decoders, e.g. lwm2m_senml_cbor. -zcbor>=0.6.0 +zcbor>=0.8.0 From ea4c12df8229519961b27aa6b4af4e5205cfe27e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C3=98yvind=20R=C3=B8nningstad?= Date: Thu, 11 Jan 2024 14:18:21 +0100 Subject: [PATCH 2828/3723] modules: zcbor: Add config CONFIG_ZCBOR_MAX_STR_LEN MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit For use with zcbor_tstr_put_term() which needs a maximum string length. Signed-off-by: Øyvind Rønningstad --- modules/zcbor/Kconfig | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/modules/zcbor/Kconfig b/modules/zcbor/Kconfig index 1b3fd15d5e3..655fb2ed2a8 100644 --- a/modules/zcbor/Kconfig +++ b/modules/zcbor/Kconfig @@ -33,4 +33,11 @@ config ZCBOR_ASSERT config ZCBOR_BIG_ENDIAN def_bool BIG_ENDIAN +config ZCBOR_MAX_STR_LEN + int "Default max length when calling zcbor_tstr_put_term()" + default 256 + help + This can be manually used if no other value is readily available, but + using this is discouraged. + endif # ZCBOR From 1bbb0a9ddb40f1c7ca5af66b19f3cb279fa2aa65 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C3=98yvind=20R=C3=B8nningstad?= Date: Wed, 10 Jan 2024 10:00:53 +0100 Subject: [PATCH 2829/3723] lwm2m: Adapt to zcbor 0.8.0 MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Regenerate from CDDL, update patch, fix references in code. Signed-off-by: Øyvind Rønningstad --- subsys/net/lib/lwm2m/lwm2m_rw_cbor.c | 22 +- subsys/net/lib/lwm2m/lwm2m_rw_senml_cbor.c | 144 +++++----- subsys/net/lib/lwm2m/lwm2m_senml_cbor.patch | 218 +++++---------- .../net/lib/lwm2m/lwm2m_senml_cbor_decode.c | 220 ++++++++------- .../net/lib/lwm2m/lwm2m_senml_cbor_decode.h | 2 +- .../net/lib/lwm2m/lwm2m_senml_cbor_encode.c | 254 ++++++++++-------- .../net/lib/lwm2m/lwm2m_senml_cbor_encode.h | 2 +- subsys/net/lib/lwm2m/lwm2m_senml_cbor_types.h | 116 ++++---- 8 files changed, 465 insertions(+), 513 deletions(-) diff --git a/subsys/net/lib/lwm2m/lwm2m_rw_cbor.c b/subsys/net/lib/lwm2m/lwm2m_rw_cbor.c index daa37d3b4ba..3b35d579569 100644 --- a/subsys/net/lib/lwm2m/lwm2m_rw_cbor.c +++ b/subsys/net/lib/lwm2m/lwm2m_rw_cbor.c @@ -66,7 +66,7 @@ static int put_time(struct lwm2m_output_context *out, struct lwm2m_obj_path *pat ZCBOR_STATE_E(states, 0, CPKT_BUF_W_PTR(out->out_cpkt), CPKT_BUF_W_SIZE(out->out_cpkt), 1); /* Are tags required? V1.1 leaves this unspecified but some servers require tags */ - ret = zcbor_tag_encode(states, ZCBOR_TAG_TIME_TSTR); + ret = zcbor_tag_put(states, ZCBOR_TAG_TIME_TSTR); if (!ret) { LOG_ERR("unable to encode date/time string tag"); @@ -77,7 +77,7 @@ static int put_time(struct lwm2m_output_context *out, struct lwm2m_obj_path *pat out->out_cpkt->offset += tag_sz; - ret = zcbor_tstr_put_term(states, time_str); + ret = zcbor_tstr_put_term(states, time_str, sizeof(time_str)); if (!ret) { LOG_ERR("unable to encode date/time string"); return -ENOMEM; @@ -232,7 +232,7 @@ static int put_objlnk(struct lwm2m_output_context *out, struct lwm2m_obj_path *p static int get_s64(struct lwm2m_input_context *in, int64_t *value) { - ZCBOR_STATE_D(states, 0, ICTX_BUF_R_PTR(in), ICTX_BUF_R_LEFT_SZ(in), 1); + ZCBOR_STATE_D(states, 0, ICTX_BUF_R_PTR(in), ICTX_BUF_R_LEFT_SZ(in), 1, 0); if (!zcbor_int64_decode(states, value)) { LOG_WRN("unable to decode a 64-bit integer value"); @@ -248,7 +248,7 @@ static int get_s64(struct lwm2m_input_context *in, int64_t *value) static int get_s32(struct lwm2m_input_context *in, int32_t *value) { - ZCBOR_STATE_D(states, 0, ICTX_BUF_R_PTR(in), ICTX_BUF_R_LEFT_SZ(in), 1); + ZCBOR_STATE_D(states, 0, ICTX_BUF_R_PTR(in), ICTX_BUF_R_LEFT_SZ(in), 1, 0); if (!zcbor_int32_decode(states, value)) { LOG_WRN("unable to decode a 32-bit integer value, err: %d", @@ -265,7 +265,7 @@ static int get_s32(struct lwm2m_input_context *in, int32_t *value) static int get_float(struct lwm2m_input_context *in, double *value) { - ZCBOR_STATE_D(states, 0, ICTX_BUF_R_PTR(in), ICTX_BUF_R_LEFT_SZ(in), 1); + ZCBOR_STATE_D(states, 0, ICTX_BUF_R_PTR(in), ICTX_BUF_R_LEFT_SZ(in), 1, 0); if (!zcbor_float_decode(states, value)) { LOG_ERR("unable to decode a floating-point value"); @@ -284,7 +284,7 @@ static int get_string(struct lwm2m_input_context *in, uint8_t *value, size_t buf struct zcbor_string hndl; int len; - ZCBOR_STATE_D(states, 0, ICTX_BUF_R_PTR(in), ICTX_BUF_R_LEFT_SZ(in), 1); + ZCBOR_STATE_D(states, 0, ICTX_BUF_R_PTR(in), ICTX_BUF_R_LEFT_SZ(in), 1, 0); if (!zcbor_tstr_decode(states, &hndl)) { LOG_WRN("unable to decode a string"); @@ -313,7 +313,7 @@ static int get_time_string(struct lwm2m_input_context *in, int64_t *value) char time_str[sizeof("4294967295")] = { 0 }; struct zcbor_string hndl = { .value = time_str, .len = sizeof(time_str) - 1 }; - ZCBOR_STATE_D(states, 0, ICTX_BUF_R_PTR(in), ICTX_BUF_R_LEFT_SZ(in), 1); + ZCBOR_STATE_D(states, 0, ICTX_BUF_R_PTR(in), ICTX_BUF_R_LEFT_SZ(in), 1, 0); if (!zcbor_tstr_decode(states, &hndl)) { return -EBADMSG; @@ -331,7 +331,7 @@ static int get_time_string(struct lwm2m_input_context *in, int64_t *value) */ static int get_time_numerical(struct lwm2m_input_context *in, int64_t *value) { - ZCBOR_STATE_D(states, 0, ICTX_BUF_R_PTR(in), ICTX_BUF_R_LEFT_SZ(in), 1); + ZCBOR_STATE_D(states, 0, ICTX_BUF_R_PTR(in), ICTX_BUF_R_LEFT_SZ(in), 1, 0); if (!zcbor_int64_decode(states, value)) { LOG_WRN("unable to decode seconds since Epoch"); @@ -350,7 +350,7 @@ static int get_time(struct lwm2m_input_context *in, time_t *value) bool success; int64_t temp64; - ZCBOR_STATE_D(states, 0, ICTX_BUF_R_PTR(in), ICTX_BUF_R_LEFT_SZ(in), 1); + ZCBOR_STATE_D(states, 0, ICTX_BUF_R_PTR(in), ICTX_BUF_R_LEFT_SZ(in), 1, 0); success = zcbor_tag_decode(states, &tag); @@ -400,7 +400,7 @@ static int get_time(struct lwm2m_input_context *in, time_t *value) static int get_bool(struct lwm2m_input_context *in, bool *value) { - ZCBOR_STATE_D(states, 0, ICTX_BUF_R_PTR(in), ICTX_BUF_R_LEFT_SZ(in), 1); + ZCBOR_STATE_D(states, 0, ICTX_BUF_R_PTR(in), ICTX_BUF_R_LEFT_SZ(in), 1, 0); if (!zcbor_bool_decode(states, value)) { LOG_WRN("unable to decode a boolean value"); @@ -420,7 +420,7 @@ static int get_opaque(struct lwm2m_input_context *in, uint8_t *value, size_t buf struct zcbor_string_fragment hndl = { 0 }; int ret; - ZCBOR_STATE_D(states, 1, ICTX_BUF_R_PTR(in), ICTX_BUF_R_LEFT_SZ(in), 1); + ZCBOR_STATE_D(states, 1, ICTX_BUF_R_PTR(in), ICTX_BUF_R_LEFT_SZ(in), 1, 0); /* Get the CBOR header only on first read. */ if (opaque->remaining == 0) { diff --git a/subsys/net/lib/lwm2m/lwm2m_rw_senml_cbor.c b/subsys/net/lib/lwm2m/lwm2m_rw_senml_cbor.c index dd963aa0583..6c20024bbde 100644 --- a/subsys/net/lib/lwm2m/lwm2m_rw_senml_cbor.c +++ b/subsys/net/lib/lwm2m/lwm2m_rw_senml_cbor.c @@ -81,12 +81,12 @@ K_MUTEX_DEFINE(fd_mtx); #define GET_CBOR_FD_NAME(fd) ((fd)->names[(fd)->name_cnt]) /* Get the current record */ #define GET_CBOR_FD_REC(fd) \ - &((fd)->input._lwm2m_senml__record[(fd)->input._lwm2m_senml__record_count]) + &((fd)->input.lwm2m_senml_record_m[(fd)->input.lwm2m_senml_record_m_count]) /* Get a record */ -#define GET_IN_FD_REC_I(fd, i) &((fd)->dcd._lwm2m_senml__record[i]) +#define GET_IN_FD_REC_I(fd, i) &((fd)->dcd.lwm2m_senml_record_m[i]) /* Consume the current record */ #define CONSUME_CBOR_FD_REC(fd) \ - &((fd)->input._lwm2m_senml__record[(fd)->input._lwm2m_senml__record_count++]) + &((fd)->input.lwm2m_senml_record_m[(fd)->input.lwm2m_senml_record_m_count++]) /* Get CBOR output formatter data */ #define LWM2M_OFD_CBOR(octx) ((struct cbor_out_fmt_data *)engine_get_out_user_data(octx)) @@ -131,7 +131,7 @@ static int fmt_range_check(struct cbor_out_fmt_data *fd) { if (fd->name_cnt >= CONFIG_LWM2M_RW_SENML_CBOR_RECORDS || fd->objlnk_cnt >= CONFIG_LWM2M_RW_SENML_CBOR_RECORDS || - fd->input._lwm2m_senml__record_count >= CONFIG_LWM2M_RW_SENML_CBOR_RECORDS) { + fd->input.lwm2m_senml_record_m_count >= CONFIG_LWM2M_RW_SENML_CBOR_RECORDS) { LOG_ERR("CONFIG_LWM2M_RW_SENML_CBOR_RECORDS too small"); return -ENOMEM; } @@ -161,9 +161,9 @@ static int put_basename(struct lwm2m_output_context *out, struct lwm2m_obj_path /* Tell CBOR encoder where to find the name */ struct record *record = GET_CBOR_FD_REC(fd); - record->_record_bn._record_bn.value = basename; - record->_record_bn._record_bn.len = len; - record->_record_bn_present = 1; + record->record_bn.record_bn.value = basename; + record->record_bn.record_bn.len = len; + record->record_bn_present = 1; if ((len < sizeof("/0/0") - 1) || (len >= SENML_MAX_NAME_SIZE)) { __ASSERT_NO_MSG(false); @@ -190,7 +190,7 @@ static int put_end(struct lwm2m_output_context *out, struct lwm2m_obj_path *path size_t len; struct lwm2m_senml *input = &(LWM2M_OFD_CBOR(out)->input); - if (!input->_lwm2m_senml__record_count) { + if (!input->lwm2m_senml_record_m_count) { len = put_empty_array(out); return len; @@ -258,9 +258,9 @@ static int put_begin_r(struct lwm2m_output_context *out, struct lwm2m_obj_path * /* Tell CBOR encoder where to find the name */ struct record *record = GET_CBOR_FD_REC(fd); - record->_record_n._record_n.value = name; - record->_record_n._record_n.len = len; - record->_record_n_present = 1; + record->record_n.record_n.value = name; + record->record_n.record_n.len = len; + record->record_n_present = 1; /* Makes possible to use same slot for storing r/ri name combination. * No need to increase the name count if an existing name has been used @@ -287,12 +287,12 @@ static int put_data_timestamp(struct lwm2m_output_context *out, time_t value) out_record = GET_CBOR_FD_REC(fd); if (fd->basetime) { - out_record->_record_t._record_t = value - fd->basetime; - out_record->_record_t_present = 1; + out_record->record_t.record_t = value - fd->basetime; + out_record->record_t_present = 1; } else { fd->basetime = value; - out_record->_record_bt._record_bt = value; - out_record->_record_bt_present = 1; + out_record->record_bt.record_bt = value; + out_record->record_bt_present = 1; } return 0; @@ -332,9 +332,9 @@ static int put_begin_ri(struct lwm2m_output_context *out, struct lwm2m_obj_path } /* Tell CBOR encoder where to find the name */ - record->_record_n._record_n.value = name; - record->_record_n._record_n.len = len; - record->_record_n_present = 1; + record->record_n.record_n.value = name; + record->record_n.record_n.len = len; + record->record_n_present = 1; /* No need to increase the name count if an existing name has been used */ if (name == GET_CBOR_FD_NAME(fd)) { @@ -353,7 +353,7 @@ static int put_name_nth_ri(struct lwm2m_output_context *out, struct lwm2m_obj_pa /* With the first ri the resource name (and ri name) are already in place*/ if (path->res_inst_id > 0) { ret = put_begin_ri(out, path); - } else if (record && record->_record_t_present) { + } else if (record && record->record_t_present) { /* Name need to be add for each time serialized record */ ret = put_begin_r(out, path); } @@ -372,9 +372,9 @@ static int put_value(struct lwm2m_output_context *out, struct lwm2m_obj_path *pa struct record *record = CONSUME_CBOR_FD_REC(LWM2M_OFD_CBOR(out)); /* Write the value */ - record->_record_union._record_union_choice = _union_vi; - record->_record_union._union_vi = value; - record->_record_union_present = 1; + record->record_union.record_union_choice = union_vi_c; + record->record_union.union_vi = value; + record->record_union_present = 1; return 0; } @@ -410,9 +410,9 @@ static int put_time(struct lwm2m_output_context *out, struct lwm2m_obj_path *pat struct record *record = CONSUME_CBOR_FD_REC(LWM2M_OFD_CBOR(out)); /* Write the value */ - record->_record_union._record_union_choice = _union_vi; - record->_record_union._union_vi = (int64_t)value; - record->_record_union_present = 1; + record->record_union.record_union_choice = union_vi_c; + record->record_union.union_vi = (int64_t)value; + record->record_union_present = 1; return 0; } @@ -428,9 +428,9 @@ static int put_float(struct lwm2m_output_context *out, struct lwm2m_obj_path *pa struct record *record = CONSUME_CBOR_FD_REC(LWM2M_OFD_CBOR(out)); /* Write the value */ - record->_record_union._record_union_choice = _union_vf; - record->_record_union._union_vf = *value; - record->_record_union_present = 1; + record->record_union.record_union_choice = union_vf_c; + record->record_union.union_vf = *value; + record->record_union_present = 1; return 0; } @@ -447,10 +447,10 @@ static int put_string(struct lwm2m_output_context *out, struct lwm2m_obj_path *p struct record *record = CONSUME_CBOR_FD_REC(LWM2M_OFD_CBOR(out)); /* Write the value */ - record->_record_union._record_union_choice = _union_vs; - record->_record_union._union_vs.value = buf; - record->_record_union._union_vs.len = buflen; - record->_record_union_present = 1; + record->record_union.record_union_choice = union_vs_c; + record->record_union.union_vs.value = buf; + record->record_union.union_vs.len = buflen; + record->record_union_present = 1; return 0; } @@ -466,9 +466,9 @@ static int put_bool(struct lwm2m_output_context *out, struct lwm2m_obj_path *pat struct record *record = CONSUME_CBOR_FD_REC(LWM2M_OFD_CBOR(out)); /* Write the value */ - record->_record_union._record_union_choice = _union_vb; - record->_record_union._union_vb = value; - record->_record_union_present = 1; + record->record_union.record_union_choice = union_vb_c; + record->record_union.union_vb = value; + record->record_union_present = 1; return 0; } @@ -485,10 +485,10 @@ static int put_opaque(struct lwm2m_output_context *out, struct lwm2m_obj_path *p struct record *record = CONSUME_CBOR_FD_REC(LWM2M_OFD_CBOR(out)); /* Write the value */ - record->_record_union._record_union_choice = _union_vd; - record->_record_union._union_vd.value = buf; - record->_record_union._union_vd.len = buflen; - record->_record_union_present = 1; + record->record_union.record_union_choice = union_vd_c; + record->record_union.union_vd.value = buf; + record->record_union.union_vd.len = buflen; + record->record_union_present = 1; return 0; } @@ -522,10 +522,10 @@ static int put_objlnk(struct lwm2m_output_context *out, struct lwm2m_obj_path *p struct record *record = CONSUME_CBOR_FD_REC(LWM2M_OFD_CBOR(out)); /* Write the value */ - record->_record_union._record_union_choice = _union_vlo; - record->_record_union._union_vlo.value = objlink_buf; - record->_record_union._union_vlo.len = objlnk_len; - record->_record_union_present = 1; + record->record_union.record_union_choice = union_vlo_c; + record->record_union.union_vlo.value = objlink_buf; + record->record_union.union_vlo.len = objlnk_len; + record->record_union_present = 1; fd->objlnk_cnt++; @@ -548,14 +548,14 @@ static int get_opaque(struct lwm2m_input_context *in, return -EINVAL; } - opaque->len = fd->current->_record_union._union_vd.len; + opaque->len = fd->current->record_union.union_vd.len; if (buflen < opaque->len) { LOG_DBG("Write opaque failed, no buffer space"); return -ENOMEM; } - dest = memcpy(value, fd->current->_record_union._union_vd.value, opaque->len); + dest = memcpy(value, fd->current->record_union.union_vd.value, opaque->len); *last_block = true; } else { LOG_DBG("Blockwise transfer not supported with SenML CBOR"); @@ -574,7 +574,7 @@ static int get_s32(struct lwm2m_input_context *in, int32_t *value) return -EINVAL; } - *value = fd->current->_record_union._union_vi; + *value = fd->current->record_union.union_vi; fd->current = NULL; return 0; @@ -589,7 +589,7 @@ static int get_s64(struct lwm2m_input_context *in, int64_t *value) return -EINVAL; } - *value = fd->current->_record_union._union_vi; + *value = fd->current->record_union.union_vi; fd->current = NULL; return 0; @@ -615,7 +615,7 @@ static int get_float(struct lwm2m_input_context *in, double *value) return -EINVAL; } - *value = fd->current->_record_union._union_vf; + *value = fd->current->record_union.union_vf; fd->current = NULL; return 0; @@ -631,9 +631,9 @@ static int get_string(struct lwm2m_input_context *in, uint8_t *buf, size_t bufle return -EINVAL; } - len = MIN(buflen-1, fd->current->_record_union._union_vs.len); + len = MIN(buflen-1, fd->current->record_union.union_vs.len); - memcpy(buf, fd->current->_record_union._union_vs.value, len); + memcpy(buf, fd->current->record_union.union_vs.value, len); buf[len] = '\0'; fd->current = NULL; @@ -698,7 +698,7 @@ static int get_bool(struct lwm2m_input_context *in, bool *value) return -EINVAL; } - *value = fd->current->_record_union._union_vb; + *value = fd->current->record_union.union_vb; fd->current = NULL; return 0; @@ -727,9 +727,9 @@ static int do_write_op_item(struct lwm2m_message *msg, struct record *rec) } /* If there's no name then the basename forms the path */ - if (rec->_record_n_present) { - len = MIN(sizeof(name) - 1, rec->_record_n._record_n.len); - snprintk(name, len + 1, "%s", rec->_record_n._record_n.value); + if (rec->record_n_present) { + len = MIN(sizeof(name) - 1, rec->record_n.record_n.len); + snprintk(name, len + 1, "%s", rec->record_n.record_n.value); } /* Form fully qualified path name */ @@ -853,29 +853,29 @@ static uint8_t parse_composite_read_paths(struct lwm2m_message *msg, msg->in.offset += isize; - for (int idx = 0; idx < fd->dcd._lwm2m_senml__record_count; idx++) { + for (int idx = 0; idx < fd->dcd.lwm2m_senml_record_m_count; idx++) { /* Where to find the basenames and names */ struct record *record = GET_IN_FD_REC_I(fd, idx); /* Set null terminated effective basename */ - if (record->_record_bn_present) { - len = MIN(sizeof(basename)-1, record->_record_bn._record_bn.len); - snprintk(basename, len + 1, "%s", record->_record_bn._record_bn.value); + if (record->record_bn_present) { + len = MIN(sizeof(basename)-1, record->record_bn.record_bn.len); + snprintk(basename, len + 1, "%s", record->record_bn.record_bn.value); basename[len] = '\0'; } /* Best effort with read, skip if no proper name is available */ - if (!record->_record_n_present) { + if (!record->record_n_present) { if (strcmp(basename, "") == 0) { continue; } } /* Set null terminated name */ - if (record->_record_n_present) { - len = MIN(sizeof(name)-1, record->_record_n._record_n.len); - snprintk(name, len + 1, "%s", record->_record_n._record_n.value); + if (record->record_n_present) { + len = MIN(sizeof(name)-1, record->record_n.record_n.len); + snprintk(name, len + 1, "%s", record->record_n.record_n.value); name[len] = '\0'; } @@ -979,30 +979,30 @@ int do_write_op_senml_cbor(struct lwm2m_message *msg) msg->in.offset += decoded_sz; - for (int idx = 0; idx < fd->dcd._lwm2m_senml__record_count; idx++) { + for (int idx = 0; idx < fd->dcd.lwm2m_senml_record_m_count; idx++) { - struct record *rec = &fd->dcd._lwm2m_senml__record[idx]; + struct record *rec = &fd->dcd.lwm2m_senml_record_m[idx]; /* Basename applies for current and succeeding records */ - if (rec->_record_bn_present) { + if (rec->record_bn_present) { int len = MIN(sizeof(fd->basename) - 1, - rec->_record_bn._record_bn.len); + rec->record_bn.record_bn.len); - snprintk(fd->basename, len + 1, "%s", rec->_record_bn._record_bn.value); + snprintk(fd->basename, len + 1, "%s", rec->record_bn.record_bn.value); goto write; } /* Keys' lexicographic order differ from the default */ - for (int jdx = 0; jdx < rec->_record__key_value_pair_count; jdx++) { + for (int jdx = 0; jdx < rec->record_key_value_pair_m_count; jdx++) { struct key_value_pair *kvp = - &(rec->_record__key_value_pair[jdx]._record__key_value_pair); + &(rec->record_key_value_pair_m[jdx].record_key_value_pair_m); - if (kvp->_key_value_pair_key == lwm2m_senml_cbor_key_bn) { + if (kvp->key_value_pair_key == lwm2m_senml_cbor_key_bn) { int len = MIN(sizeof(fd->basename) - 1, - kvp->_key_value_pair._value_tstr.len); + kvp->key_value_pair.value_tstr.len); snprintk(fd->basename, len + 1, "%s", - kvp->_key_value_pair._value_tstr.value); + kvp->key_value_pair.value_tstr.value); break; } } diff --git a/subsys/net/lib/lwm2m/lwm2m_senml_cbor.patch b/subsys/net/lib/lwm2m/lwm2m_senml_cbor.patch index 48b984aafac..81ec06bab8b 100644 --- a/subsys/net/lib/lwm2m/lwm2m_senml_cbor.patch +++ b/subsys/net/lib/lwm2m/lwm2m_senml_cbor.patch @@ -1,94 +1,59 @@ diff --git a/subsys/net/lib/lwm2m/lwm2m_senml_cbor_decode.c b/subsys/net/lib/lwm2m/lwm2m_senml_cbor_decode.c -index f97f0ebb2d..1c1233d616 100644 +index c12f477cce..f41b81275d 100644 --- a/subsys/net/lib/lwm2m/lwm2m_senml_cbor_decode.c +++ b/subsys/net/lib/lwm2m/lwm2m_senml_cbor_decode.c @@ -4,7 +4,7 @@ * SPDX-License-Identifier: Apache-2.0 * - * Generated using zcbor version 0.7.0 + * Generated using zcbor version 0.8.0 - * https://github.com/NordicSemiconductor/zcbor + * https://github.com/zephyrproject-rtos/zcbor * Generated with a --default-max-qty of 99 */ -@@ -15,9 +15,6 @@ - #include "zcbor_decode.h" +@@ -16,10 +16,6 @@ #include "lwm2m_senml_cbor_decode.h" + #include "zcbor_print.h" -#if DEFAULT_MAX_QTY != 99 -#error "The type file was generated with a different default_max_qty than this file" -#endif - +- static bool decode_repeated_record_bn(zcbor_state_t *state, struct record_bn *result); static bool decode_repeated_record_bt(zcbor_state_t *state, struct record_bt *result); -@@ -52,7 +49,7 @@ static bool decode_repeated_record_bt( - - bool tmp_result = ((((zcbor_int32_expect(state, (-3)))) - && (zcbor_int64_decode(state, (&(*result)._record_bt))) -- && ((((*result)._record_bt >= -9223372036854775807LL) -+ && ((((*result)._record_bt >= INT64_MIN) - && ((*result)._record_bt <= INT64_MAX)) || (zcbor_error(state, ZCBOR_ERR_WRONG_RANGE), false)))); - - if (!tmp_result) -@@ -82,7 +79,7 @@ static bool decode_repeated_record_t( - - bool tmp_result = ((((zcbor_uint32_expect(state, (6)))) - && (zcbor_int64_decode(state, (&(*result)._record_t))) -- && ((((*result)._record_t >= -9223372036854775807LL) -+ && ((((*result)._record_t >= INT64_MIN) - && ((*result)._record_t <= INT64_MAX)) || (zcbor_error(state, ZCBOR_ERR_WRONG_RANGE), false)))); - - if (!tmp_result) -@@ -100,7 +97,7 @@ static bool decode_repeated_record_union( - - bool tmp_result = (((zcbor_union_start_code(state) && (int_res = (((((zcbor_uint32_expect_union(state, (2)))) - && (zcbor_int64_decode(state, (&(*result)._union_vi))) -- && ((((*result)._union_vi >= -9223372036854775807LL) -+ && ((((*result)._union_vi >= INT64_MIN) - && ((*result)._union_vi <= INT64_MAX)) || (zcbor_error(state, ZCBOR_ERR_WRONG_RANGE), false))) && (((*result)._record_union_choice = _union_vi), true)) - || ((((zcbor_uint32_expect_union(state, (2)))) - && (zcbor_float_decode(state, (&(*result)._union_vf)))) && (((*result)._record_union_choice = _union_vf), true)) -@@ -128,7 +125,7 @@ static bool decode_value( - bool tmp_result = (((zcbor_union_start_code(state) && (int_res = ((((zcbor_tstr_decode(state, (&(*result)._value_tstr)))) && (((*result)._value_choice = _value_tstr), true)) - || (((zcbor_bstr_decode(state, (&(*result)._value_bstr)))) && (((*result)._value_choice = _value_bstr), true)) - || (((zcbor_int64_decode(state, (&(*result)._value_int))) -- && ((((*result)._value_int >= -9223372036854775807LL) -+ && ((((*result)._value_int >= INT64_MIN) - && ((*result)._value_int <= INT64_MAX)) || (zcbor_error(state, ZCBOR_ERR_WRONG_RANGE), false))) && (((*result)._value_choice = _value_int), true)) - || (((zcbor_float_decode(state, (&(*result)._value_float)))) && (((*result)._value_choice = _value_float), true)) - || (((zcbor_bool_decode(state, (&(*result)._value_bool)))) && (((*result)._value_choice = _value_bool), true))), zcbor_union_end_code(state), int_res)))); -@@ -176,7 +173,7 @@ static bool decode_record( - && zcbor_present_decode(&((*result)._record_n_present), (zcbor_decoder_t *)decode_repeated_record_n, state, (&(*result)._record_n)) - && zcbor_present_decode(&((*result)._record_t_present), (zcbor_decoder_t *)decode_repeated_record_t, state, (&(*result)._record_t)) - && zcbor_present_decode(&((*result)._record_union_present), (zcbor_decoder_t *)decode_repeated_record_union, state, (&(*result)._record_union)) -- && zcbor_multi_decode(0, 5, &(*result)._record__key_value_pair_count, (zcbor_decoder_t *)decode_repeated_record__key_value_pair, state, (&(*result)._record__key_value_pair), sizeof(struct record__key_value_pair))) || (zcbor_list_map_end_force_decode(state), false)) && zcbor_map_end_decode(state)))); -+ && zcbor_multi_decode(0, ZCBOR_ARRAY_SIZE(result->_record__key_value_pair), &(*result)._record__key_value_pair_count, (zcbor_decoder_t *)decode_repeated_record__key_value_pair, state, (&(*result)._record__key_value_pair), sizeof(struct record__key_value_pair))) || (zcbor_list_map_end_force_decode(state), false)) && zcbor_map_end_decode(state)))); - - if (!tmp_result) - zcbor_trace(); -@@ -189,7 +186,7 @@ static bool decode_lwm2m_senml( + static bool decode_repeated_record_n(zcbor_state_t *state, struct record_n *result); +@@ -209,7 +205,7 @@ static bool decode_record( + && zcbor_present_decode(&((*result).record_n_present), (zcbor_decoder_t *)decode_repeated_record_n, state, (&(*result).record_n)) + && zcbor_present_decode(&((*result).record_t_present), (zcbor_decoder_t *)decode_repeated_record_t, state, (&(*result).record_t)) + && zcbor_present_decode(&((*result).record_union_present), (zcbor_decoder_t *)decode_repeated_record_union, state, (&(*result).record_union)) +- && zcbor_multi_decode(0, 5, &(*result).record_key_value_pair_m_count, (zcbor_decoder_t *)decode_repeated_record_key_value_pair_m, state, (&(*result).record_key_value_pair_m), sizeof(struct record_key_value_pair_m))) || (zcbor_list_map_end_force_decode(state), false)) && zcbor_map_end_decode(state)))); ++ && zcbor_multi_decode(0, ZCBOR_ARRAY_SIZE(result->record_key_value_pair_m), &(*result).record_key_value_pair_m_count, (zcbor_decoder_t *)decode_repeated_record_key_value_pair_m, state, (&(*result).record_key_value_pair_m), sizeof(struct record_key_value_pair_m))) || (zcbor_list_map_end_force_decode(state), false)) && zcbor_map_end_decode(state)))); + + if (!tmp_result) { + zcbor_trace_file(state); +@@ -226,7 +222,7 @@ static bool decode_lwm2m_senml( { - zcbor_print("%s\r\n", __func__); + zcbor_log("%s\r\n", __func__); -- bool tmp_result = (((zcbor_list_start_decode(state) && ((zcbor_multi_decode(1, 99, &(*result)._lwm2m_senml__record_count, (zcbor_decoder_t *)decode_record, state, (&(*result)._lwm2m_senml__record), sizeof(struct record))) || (zcbor_list_map_end_force_decode(state), false)) && zcbor_list_end_decode(state)))); -+ bool tmp_result = (((zcbor_list_start_decode(state) && ((zcbor_multi_decode(1, ZCBOR_ARRAY_SIZE(result->_lwm2m_senml__record), &(*result)._lwm2m_senml__record_count, (zcbor_decoder_t *)decode_record, state, (&(*result)._lwm2m_senml__record), sizeof(struct record))) || (zcbor_list_map_end_force_decode(state), false)) && zcbor_list_end_decode(state)))); +- bool tmp_result = (((zcbor_list_start_decode(state) && ((zcbor_multi_decode(1, 99, &(*result).lwm2m_senml_record_m_count, (zcbor_decoder_t *)decode_record, state, (&(*result).lwm2m_senml_record_m), sizeof(struct record))) || (zcbor_list_map_end_force_decode(state), false)) && zcbor_list_end_decode(state)))); ++ bool tmp_result = (((zcbor_list_start_decode(state) && ((zcbor_multi_decode(1, ZCBOR_ARRAY_SIZE(result->lwm2m_senml_record_m), &(*result).lwm2m_senml_record_m_count, (zcbor_decoder_t *)decode_record, state, (&(*result).lwm2m_senml_record_m), sizeof(struct record))) || (zcbor_list_map_end_force_decode(state), false)) && zcbor_list_end_decode(state)))); - if (!tmp_result) - zcbor_trace(); + if (!tmp_result) { + zcbor_trace_file(state); diff --git a/subsys/net/lib/lwm2m/lwm2m_senml_cbor_decode.h b/subsys/net/lib/lwm2m/lwm2m_senml_cbor_decode.h -index cb5d5c9695..7db7ed0591 100644 +index a36f8782c6..b913fb78e9 100644 --- a/subsys/net/lib/lwm2m/lwm2m_senml_cbor_decode.h +++ b/subsys/net/lib/lwm2m/lwm2m_senml_cbor_decode.h @@ -4,7 +4,7 @@ * SPDX-License-Identifier: Apache-2.0 * - * Generated using zcbor version 0.7.0 + * Generated using zcbor version 0.8.0 - * https://github.com/NordicSemiconductor/zcbor + * https://github.com/zephyrproject-rtos/zcbor * Generated with a --default-max-qty of 99 */ -@@ -21,10 +21,6 @@ +@@ -21,11 +21,6 @@ extern "C" { #endif @@ -96,25 +61,26 @@ index cb5d5c9695..7db7ed0591 100644 -#error "The type file was generated with a different default_max_qty than this file" -#endif - - +- int cbor_decode_lwm2m_senml( - const uint8_t *payload, size_t payload_len, + const uint8_t *payload, size_t payload_len, + struct lwm2m_senml *result, diff --git a/subsys/net/lib/lwm2m/lwm2m_senml_cbor_encode.c b/subsys/net/lib/lwm2m/lwm2m_senml_cbor_encode.c -index 982cfca6c3..afdc6a32f7 100644 +index 94926c531f..5521917853 100644 --- a/subsys/net/lib/lwm2m/lwm2m_senml_cbor_encode.c +++ b/subsys/net/lib/lwm2m/lwm2m_senml_cbor_encode.c @@ -4,7 +4,7 @@ * SPDX-License-Identifier: Apache-2.0 * - * Generated using zcbor version 0.7.0 + * Generated using zcbor version 0.8.0 - * https://github.com/NordicSemiconductor/zcbor + * https://github.com/zephyrproject-rtos/zcbor * Generated with a --default-max-qty of 99 */ -@@ -15,10 +15,6 @@ - #include "zcbor_encode.h" +@@ -16,10 +16,6 @@ #include "lwm2m_senml_cbor_encode.h" + #include "zcbor_print.h" -#if DEFAULT_MAX_QTY != 99 -#error "The type file was generated with a different default_max_qty than this file" @@ -123,80 +89,44 @@ index 982cfca6c3..afdc6a32f7 100644 static bool encode_repeated_record_bn(zcbor_state_t *state, const struct record_bn *input); static bool encode_repeated_record_bt(zcbor_state_t *state, const struct record_bt *input); static bool encode_repeated_record_n(zcbor_state_t *state, const struct record_n *input); -@@ -51,7 +47,7 @@ static bool encode_repeated_record_bt( - zcbor_print("%s\r\n", __func__); - - bool tmp_result = ((((zcbor_int32_put(state, (-3)))) -- && ((((*input)._record_bt >= -9223372036854775807LL) -+ && ((((*input)._record_bt >= INT64_MIN) - && ((*input)._record_bt <= INT64_MAX)) || (zcbor_error(state, ZCBOR_ERR_WRONG_RANGE), false)) - && (zcbor_int64_encode(state, (&(*input)._record_bt))))); - -@@ -81,7 +77,7 @@ static bool encode_repeated_record_t( - zcbor_print("%s\r\n", __func__); - - bool tmp_result = ((((zcbor_uint32_put(state, (6)))) -- && ((((*input)._record_t >= -9223372036854775807LL) -+ && ((((*input)._record_t >= INT64_MIN) - && ((*input)._record_t <= INT64_MAX)) || (zcbor_error(state, ZCBOR_ERR_WRONG_RANGE), false)) - && (zcbor_int64_encode(state, (&(*input)._record_t))))); - -@@ -98,7 +94,7 @@ static bool encode_repeated_record_union( - struct zcbor_string tmp_str; - - bool tmp_result = (((((*input)._record_union_choice == _union_vi) ? (((zcbor_uint32_put(state, (2)))) -- && ((((*input)._union_vi >= -9223372036854775807LL) -+ && ((((*input)._union_vi >= INT64_MIN) - && ((*input)._union_vi <= INT64_MAX)) || (zcbor_error(state, ZCBOR_ERR_WRONG_RANGE), false)) - && (zcbor_int64_encode(state, (&(*input)._union_vi)))) - : (((*input)._record_union_choice == _union_vf) ? (((zcbor_uint32_put(state, (2)))) -@@ -126,7 +122,7 @@ static bool encode_value( - - bool tmp_result = (((((*input)._value_choice == _value_tstr) ? ((zcbor_tstr_encode(state, (&(*input)._value_tstr)))) - : (((*input)._value_choice == _value_bstr) ? ((zcbor_bstr_encode(state, (&(*input)._value_bstr)))) -- : (((*input)._value_choice == _value_int) ? (((((*input)._value_int >= -9223372036854775807LL) -+ : (((*input)._value_choice == _value_int) ? (((((*input)._value_int >= INT64_MIN) - && ((*input)._value_int <= INT64_MAX)) || (zcbor_error(state, ZCBOR_ERR_WRONG_RANGE), false)) - && (zcbor_int64_encode(state, (&(*input)._value_int)))) - : (((*input)._value_choice == _value_float) ? ((zcbor_float64_encode(state, (&(*input)._value_float)))) -@@ -171,12 +167,12 @@ static bool encode_record( +@@ -204,12 +200,12 @@ static bool encode_record( { - zcbor_print("%s\r\n", __func__); - -- bool tmp_result = (((zcbor_map_start_encode(state, 10) && ((zcbor_present_encode(&((*input)._record_bn_present), (zcbor_encoder_t *)encode_repeated_record_bn, state, (&(*input)._record_bn)) -+ bool tmp_result = (((zcbor_map_start_encode(state, ZCBOR_ARRAY_SIZE(input->_record__key_value_pair)) && ((zcbor_present_encode(&((*input)._record_bn_present), (zcbor_encoder_t *)encode_repeated_record_bn, state, (&(*input)._record_bn)) - && zcbor_present_encode(&((*input)._record_bt_present), (zcbor_encoder_t *)encode_repeated_record_bt, state, (&(*input)._record_bt)) - && zcbor_present_encode(&((*input)._record_n_present), (zcbor_encoder_t *)encode_repeated_record_n, state, (&(*input)._record_n)) - && zcbor_present_encode(&((*input)._record_t_present), (zcbor_encoder_t *)encode_repeated_record_t, state, (&(*input)._record_t)) - && zcbor_present_encode(&((*input)._record_union_present), (zcbor_encoder_t *)encode_repeated_record_union, state, (&(*input)._record_union)) -- && zcbor_multi_encode_minmax(0, 5, &(*input)._record__key_value_pair_count, (zcbor_encoder_t *)encode_repeated_record__key_value_pair, state, (&(*input)._record__key_value_pair), sizeof(struct record__key_value_pair))) || (zcbor_list_map_end_force_encode(state), false)) && zcbor_map_end_encode(state, 10)))); -+ && zcbor_multi_encode_minmax(0, ZCBOR_ARRAY_SIZE(input->_record__key_value_pair), &(*input)._record__key_value_pair_count, (zcbor_encoder_t *)encode_repeated_record__key_value_pair, state, (&(*input)._record__key_value_pair), sizeof(struct record__key_value_pair))) || (zcbor_list_map_end_force_encode(state), false)) && zcbor_map_end_encode(state, ZCBOR_ARRAY_SIZE(input->_record__key_value_pair))))); - - if (!tmp_result) - zcbor_trace(); -@@ -189,7 +185,7 @@ static bool encode_lwm2m_senml( + zcbor_log("%s\r\n", __func__); + +- bool tmp_result = (((zcbor_map_start_encode(state, 10) && (((!(*input).record_bn_present || encode_repeated_record_bn(state, (&(*input).record_bn))) ++ bool tmp_result = (((zcbor_map_start_encode(state, ZCBOR_ARRAY_SIZE(input->record_key_value_pair_m)) && (((!(*input).record_bn_present || encode_repeated_record_bn(state, (&(*input).record_bn))) + && (!(*input).record_bt_present || encode_repeated_record_bt(state, (&(*input).record_bt))) + && (!(*input).record_n_present || encode_repeated_record_n(state, (&(*input).record_n))) + && (!(*input).record_t_present || encode_repeated_record_t(state, (&(*input).record_t))) + && (!(*input).record_union_present || encode_repeated_record_union(state, (&(*input).record_union))) +- && zcbor_multi_encode_minmax(0, 5, &(*input).record_key_value_pair_m_count, (zcbor_encoder_t *)encode_repeated_record_key_value_pair_m, state, (&(*input).record_key_value_pair_m), sizeof(struct record_key_value_pair_m))) || (zcbor_list_map_end_force_encode(state), false)) && zcbor_map_end_encode(state, 10)))); ++ && zcbor_multi_encode_minmax(0, ZCBOR_ARRAY_SIZE(input->record_key_value_pair_m), &(*input).record_key_value_pair_m_count, (zcbor_encoder_t *)encode_repeated_record_key_value_pair_m, state, (&(*input).record_key_value_pair_m), sizeof(struct record_key_value_pair_m))) || (zcbor_list_map_end_force_encode(state), false)) && zcbor_map_end_encode(state, ZCBOR_ARRAY_SIZE(input->record_key_value_pair_m))))); + + if (!tmp_result) { + zcbor_trace_file(state); +@@ -226,7 +222,7 @@ static bool encode_lwm2m_senml( { - zcbor_print("%s\r\n", __func__); + zcbor_log("%s\r\n", __func__); -- bool tmp_result = (((zcbor_list_start_encode(state, 99) && ((zcbor_multi_encode_minmax(1, 99, &(*input)._lwm2m_senml__record_count, (zcbor_encoder_t *)encode_record, state, (&(*input)._lwm2m_senml__record), sizeof(struct record))) || (zcbor_list_map_end_force_encode(state), false)) && zcbor_list_end_encode(state, 99)))); -+ bool tmp_result = (((zcbor_list_start_encode(state, ZCBOR_ARRAY_SIZE(input->_lwm2m_senml__record)) && ((zcbor_multi_encode_minmax(1, ZCBOR_ARRAY_SIZE(input->_lwm2m_senml__record), &(*input)._lwm2m_senml__record_count, (zcbor_encoder_t *)encode_record, state, (&(*input)._lwm2m_senml__record), sizeof(struct record))) || (zcbor_list_map_end_force_encode(state), false)) && zcbor_list_end_encode(state, ZCBOR_ARRAY_SIZE(input->_lwm2m_senml__record))))); +- bool tmp_result = (((zcbor_list_start_encode(state, 99) && ((zcbor_multi_encode_minmax(1, 99, &(*input).lwm2m_senml_record_m_count, (zcbor_encoder_t *)encode_record, state, (&(*input).lwm2m_senml_record_m), sizeof(struct record))) || (zcbor_list_map_end_force_encode(state), false)) && zcbor_list_end_encode(state, 99)))); ++ bool tmp_result = (((zcbor_list_start_encode(state, ZCBOR_ARRAY_SIZE(input->lwm2m_senml_record_m)) && ((zcbor_multi_encode_minmax(1, ZCBOR_ARRAY_SIZE(input->lwm2m_senml_record_m), &(*input).lwm2m_senml_record_m_count, (zcbor_encoder_t *)encode_record, state, (&(*input).lwm2m_senml_record_m), sizeof(struct record))) || (zcbor_list_map_end_force_encode(state), false)) && zcbor_list_end_encode(state, ZCBOR_ARRAY_SIZE(input->lwm2m_senml_record_m))))); - if (!tmp_result) - zcbor_trace(); + if (!tmp_result) { + zcbor_trace_file(state); diff --git a/subsys/net/lib/lwm2m/lwm2m_senml_cbor_encode.h b/subsys/net/lib/lwm2m/lwm2m_senml_cbor_encode.h -index b6c54afde5..cbc32e540c 100644 +index df2f0ac6a1..8fa1eedb2b 100644 --- a/subsys/net/lib/lwm2m/lwm2m_senml_cbor_encode.h +++ b/subsys/net/lib/lwm2m/lwm2m_senml_cbor_encode.h @@ -4,7 +4,7 @@ * SPDX-License-Identifier: Apache-2.0 * - * Generated using zcbor version 0.7.0 + * Generated using zcbor version 0.8.0 - * https://github.com/NordicSemiconductor/zcbor + * https://github.com/zephyrproject-rtos/zcbor * Generated with a --default-max-qty of 99 */ -@@ -21,10 +21,6 @@ +@@ -21,11 +21,6 @@ extern "C" { #endif @@ -204,26 +134,36 @@ index b6c54afde5..cbc32e540c 100644 -#error "The type file was generated with a different default_max_qty than this file" -#endif - - +- int cbor_encode_lwm2m_senml( - uint8_t *payload, size_t payload_len, + uint8_t *payload, size_t payload_len, + const struct lwm2m_senml *input, diff --git a/subsys/net/lib/lwm2m/lwm2m_senml_cbor_types.h b/subsys/net/lib/lwm2m/lwm2m_senml_cbor_types.h -index e12f33636e..f709086a5c 100644 +index 77649036ef..f0a2958072 100644 --- a/subsys/net/lib/lwm2m/lwm2m_senml_cbor_types.h +++ b/subsys/net/lib/lwm2m/lwm2m_senml_cbor_types.h @@ -4,7 +4,7 @@ * SPDX-License-Identifier: Apache-2.0 * - * Generated using zcbor version 0.7.0 + * Generated using zcbor version 0.8.0 - * https://github.com/NordicSemiconductor/zcbor + * https://github.com/zephyrproject-rtos/zcbor * Generated with a --default-max-qty of 99 */ -@@ -20,6 +20,18 @@ +@@ -20,14 +20,18 @@ extern "C" { #endif +-/** Which value for --default-max-qty this file was created with. +- * +- * The define is used in the other generated file to do a build-time +- * compatibility check. +- * +- * See `zcbor --help` for more information about --default-max-qty +- */ +-#define DEFAULT_MAX_QTY 99 ++ +enum lwm2m_senml_cbor_key { + lwm2m_senml_cbor_key_bn = -2, + lwm2m_senml_cbor_key_bt = -3, @@ -235,25 +175,15 @@ index e12f33636e..f709086a5c 100644 + lwm2m_senml_cbor_key_vb = 4, + lwm2m_senml_cbor_key_vd = 8, +}; -+ - /** Which value for --default-max-qty this file was created with. - * - * The define is used in the other generated file to do a build-time -@@ -27,7 +39,7 @@ extern "C" { - * - * See `zcbor --help` for more information about --default-max-qty - */ --#define DEFAULT_MAX_QTY 99 -+#define DEFAULT_MAX_QTY CONFIG_LWM2M_RW_SENML_CBOR_RECORDS struct record_bn { - struct zcbor_string _record_bn; -@@ -118,7 +130,7 @@ struct record { + struct zcbor_string record_bn; +@@ -118,7 +122,7 @@ struct record { }; struct lwm2m_senml { -- struct record _lwm2m_senml__record[99]; -+ struct record _lwm2m_senml__record[DEFAULT_MAX_QTY]; - size_t _lwm2m_senml__record_count; +- struct record lwm2m_senml_record_m[99]; ++ struct record lwm2m_senml_record_m[CONFIG_LWM2M_RW_SENML_CBOR_RECORDS]; + size_t lwm2m_senml_record_m_count; }; diff --git a/subsys/net/lib/lwm2m/lwm2m_senml_cbor_decode.c b/subsys/net/lib/lwm2m/lwm2m_senml_cbor_decode.c index a75aee02120..3906d476cac 100644 --- a/subsys/net/lib/lwm2m/lwm2m_senml_cbor_decode.c +++ b/subsys/net/lib/lwm2m/lwm2m_senml_cbor_decode.c @@ -3,7 +3,7 @@ * * SPDX-License-Identifier: Apache-2.0 * - * Generated using zcbor version 0.7.0 + * Generated using zcbor version 0.8.0 * https://github.com/zephyrproject-rtos/zcbor * Generated with a --default-max-qty of 99 */ @@ -14,28 +14,32 @@ #include #include "zcbor_decode.h" #include "lwm2m_senml_cbor_decode.h" +#include "zcbor_print.h" static bool decode_repeated_record_bn(zcbor_state_t *state, struct record_bn *result); static bool decode_repeated_record_bt(zcbor_state_t *state, struct record_bt *result); static bool decode_repeated_record_n(zcbor_state_t *state, struct record_n *result); static bool decode_repeated_record_t(zcbor_state_t *state, struct record_t *result); -static bool decode_repeated_record_union(zcbor_state_t *state, struct record_union_ *result); -static bool decode_value(zcbor_state_t *state, struct value_ *result); +static bool decode_repeated_record_union(zcbor_state_t *state, struct record_union_r *result); +static bool decode_value(zcbor_state_t *state, struct value_r *result); static bool decode_key_value_pair(zcbor_state_t *state, struct key_value_pair *result); -static bool decode_repeated_record__key_value_pair(zcbor_state_t *state, - struct record__key_value_pair *result); +static bool decode_repeated_record_key_value_pair_m(zcbor_state_t *state, + struct record_key_value_pair_m *result); static bool decode_record(zcbor_state_t *state, struct record *result); static bool decode_lwm2m_senml(zcbor_state_t *state, struct lwm2m_senml *result); static bool decode_repeated_record_bn(zcbor_state_t *state, struct record_bn *result) { - zcbor_print("%s\r\n", __func__); + zcbor_log("%s\r\n", __func__); bool tmp_result = ((((zcbor_int32_expect(state, (-2)))) && - (zcbor_tstr_decode(state, (&(*result)._record_bn))))); + (zcbor_tstr_decode(state, (&(*result).record_bn))))); if (!tmp_result) { - zcbor_trace(); + zcbor_trace_file(state); + zcbor_log("%s error: %s\r\n", __func__, zcbor_error_str(zcbor_peek_error(state))); + } else { + zcbor_log("%s success\r\n", __func__); } return tmp_result; @@ -43,16 +47,19 @@ static bool decode_repeated_record_bn(zcbor_state_t *state, struct record_bn *re static bool decode_repeated_record_bt(zcbor_state_t *state, struct record_bt *result) { - zcbor_print("%s\r\n", __func__); + zcbor_log("%s\r\n", __func__); bool tmp_result = ((((zcbor_int32_expect(state, (-3)))) && - (zcbor_int64_decode(state, (&(*result)._record_bt))) && - ((((*result)._record_bt >= INT64_MIN) && ((*result)._record_bt <= INT64_MAX)) || + (zcbor_int64_decode(state, (&(*result).record_bt))) && + ((((*result).record_bt >= INT64_MIN) && ((*result).record_bt <= INT64_MAX)) || (zcbor_error(state, ZCBOR_ERR_WRONG_RANGE), false)))); if (!tmp_result) { - zcbor_trace(); + zcbor_trace_file(state); + zcbor_log("%s error: %s\r\n", __func__, zcbor_error_str(zcbor_peek_error(state))); + } else { + zcbor_log("%s success\r\n", __func__); } return tmp_result; @@ -60,13 +67,16 @@ static bool decode_repeated_record_bt(zcbor_state_t *state, struct record_bt *re static bool decode_repeated_record_n(zcbor_state_t *state, struct record_n *result) { - zcbor_print("%s\r\n", __func__); + zcbor_log("%s\r\n", __func__); bool tmp_result = ((((zcbor_uint32_expect(state, (0)))) && - (zcbor_tstr_decode(state, (&(*result)._record_n))))); + (zcbor_tstr_decode(state, (&(*result).record_n))))); if (!tmp_result) { - zcbor_trace(); + zcbor_trace_file(state); + zcbor_log("%s error: %s\r\n", __func__, zcbor_error_str(zcbor_peek_error(state))); + } else { + zcbor_log("%s success\r\n", __func__); } return tmp_result; @@ -74,86 +84,94 @@ static bool decode_repeated_record_n(zcbor_state_t *state, struct record_n *resu static bool decode_repeated_record_t(zcbor_state_t *state, struct record_t *result) { - zcbor_print("%s\r\n", __func__); + zcbor_log("%s\r\n", __func__); bool tmp_result = ((((zcbor_uint32_expect(state, (6)))) && - (zcbor_int64_decode(state, (&(*result)._record_t))) && - ((((*result)._record_t >= INT64_MIN) && ((*result)._record_t <= INT64_MAX)) || + (zcbor_int64_decode(state, (&(*result).record_t))) && + ((((*result).record_t >= INT64_MIN) && ((*result).record_t <= INT64_MAX)) || (zcbor_error(state, ZCBOR_ERR_WRONG_RANGE), false)))); if (!tmp_result) { - zcbor_trace(); + zcbor_trace_file(state); + zcbor_log("%s error: %s\r\n", __func__, zcbor_error_str(zcbor_peek_error(state))); + } else { + zcbor_log("%s success\r\n", __func__); } return tmp_result; } -static bool decode_repeated_record_union(zcbor_state_t *state, struct record_union_ *result) +static bool decode_repeated_record_union(zcbor_state_t *state, struct record_union_r *result) { - zcbor_print("%s\r\n", __func__); + zcbor_log("%s\r\n", __func__); struct zcbor_string tmp_str; bool int_res; bool tmp_result = (((zcbor_union_start_code(state) && (int_res = (((((zcbor_uint32_expect_union(state, (2)))) && - (zcbor_int64_decode(state, (&(*result)._union_vi))) && - ((((*result)._union_vi >= INT64_MIN) && - ((*result)._union_vi <= INT64_MAX)) || + (zcbor_int64_decode(state, (&(*result).union_vi))) && + ((((*result).union_vi >= INT64_MIN) && + ((*result).union_vi <= INT64_MAX)) || (zcbor_error(state, ZCBOR_ERR_WRONG_RANGE), false))) && - (((*result)._record_union_choice = _union_vi), true)) || + (((*result).record_union_choice = union_vi_c), true)) || ((((zcbor_uint32_expect_union(state, (2)))) && - (zcbor_float_decode(state, (&(*result)._union_vf)))) && - (((*result)._record_union_choice = _union_vf), true)) || + (zcbor_float_decode(state, (&(*result).union_vf)))) && + (((*result).record_union_choice = union_vf_c), true)) || ((((zcbor_uint32_expect_union(state, (3)))) && - (zcbor_tstr_decode(state, (&(*result)._union_vs)))) && - (((*result)._record_union_choice = _union_vs), true)) || + (zcbor_tstr_decode(state, (&(*result).union_vs)))) && + (((*result).record_union_choice = union_vs_c), true)) || ((((zcbor_uint32_expect_union(state, (4)))) && - (zcbor_bool_decode(state, (&(*result)._union_vb)))) && - (((*result)._record_union_choice = _union_vb), true)) || + (zcbor_bool_decode(state, (&(*result).union_vb)))) && + (((*result).record_union_choice = union_vb_c), true)) || ((((zcbor_uint32_expect_union(state, (8)))) && - (zcbor_bstr_decode(state, (&(*result)._union_vd)))) && - (((*result)._record_union_choice = _union_vd), true)) || + (zcbor_bstr_decode(state, (&(*result).union_vd)))) && + (((*result).record_union_choice = union_vd_c), true)) || (zcbor_union_elem_code(state) && ((((zcbor_tstr_expect( state, ((tmp_str.value = (uint8_t *)"vlo", tmp_str.len = sizeof("vlo") - 1, &tmp_str))))) && - (zcbor_tstr_decode(state, (&(*result)._union_vlo)))) && - (((*result)._record_union_choice = _union_vlo), true)))), + (zcbor_tstr_decode(state, (&(*result).union_vlo)))) && + (((*result).record_union_choice = union_vlo_c), true)))), zcbor_union_end_code(state), int_res)))); if (!tmp_result) { - zcbor_trace(); + zcbor_trace_file(state); + zcbor_log("%s error: %s\r\n", __func__, zcbor_error_str(zcbor_peek_error(state))); + } else { + zcbor_log("%s success\r\n", __func__); } return tmp_result; } -static bool decode_value(zcbor_state_t *state, struct value_ *result) +static bool decode_value(zcbor_state_t *state, struct value_r *result) { - zcbor_print("%s\r\n", __func__); + zcbor_log("%s\r\n", __func__); bool int_res; - bool tmp_result = - (((zcbor_union_start_code(state) && - (int_res = ((((zcbor_tstr_decode(state, (&(*result)._value_tstr)))) && - (((*result)._value_choice = _value_tstr), true)) || - (((zcbor_bstr_decode(state, (&(*result)._value_bstr)))) && - (((*result)._value_choice = _value_bstr), true)) || - (((zcbor_int64_decode(state, (&(*result)._value_int))) && - ((((*result)._value_int >= INT64_MIN) && - ((*result)._value_int <= INT64_MAX)) || - (zcbor_error(state, ZCBOR_ERR_WRONG_RANGE), false))) && - (((*result)._value_choice = _value_int), true)) || - (((zcbor_float_decode(state, (&(*result)._value_float)))) && - (((*result)._value_choice = _value_float), true)) || - (((zcbor_bool_decode(state, (&(*result)._value_bool)))) && - (((*result)._value_choice = _value_bool), true))), - zcbor_union_end_code(state), int_res)))); + bool tmp_result = (((zcbor_union_start_code(state) && + (int_res = ((((zcbor_tstr_decode(state, (&(*result).value_tstr)))) && + (((*result).value_choice = value_tstr_c), true)) || + (((zcbor_bstr_decode(state, (&(*result).value_bstr)))) && + (((*result).value_choice = value_bstr_c), true)) || + (((zcbor_int64_decode(state, (&(*result).value_int))) && + ((((*result).value_int >= INT64_MIN) && + ((*result).value_int <= INT64_MAX)) || + (zcbor_error(state, ZCBOR_ERR_WRONG_RANGE), false))) && + (((*result).value_choice = value_int_c), true)) || + (((zcbor_float_decode(state, (&(*result).value_float)))) && + (((*result).value_choice = value_float_c), true)) || + (((zcbor_bool_decode(state, (&(*result).value_bool)))) && + (((*result).value_choice = value_bool_c), true))), + zcbor_union_end_code(state), int_res)))); if (!tmp_result) { - zcbor_trace(); + zcbor_trace_file(state); + zcbor_log("%s error: %s\r\n", __func__, zcbor_error_str(zcbor_peek_error(state))); + } else { + zcbor_log("%s success\r\n", __func__); } return tmp_result; @@ -161,27 +179,33 @@ static bool decode_value(zcbor_state_t *state, struct value_ *result) static bool decode_key_value_pair(zcbor_state_t *state, struct key_value_pair *result) { - zcbor_print("%s\r\n", __func__); + zcbor_log("%s\r\n", __func__); - bool tmp_result = ((((zcbor_int32_decode(state, (&(*result)._key_value_pair_key)))) && - (decode_value(state, (&(*result)._key_value_pair))))); + bool tmp_result = ((((zcbor_int32_decode(state, (&(*result).key_value_pair_key)))) && + (decode_value(state, (&(*result).key_value_pair))))); if (!tmp_result) { - zcbor_trace(); + zcbor_trace_file(state); + zcbor_log("%s error: %s\r\n", __func__, zcbor_error_str(zcbor_peek_error(state))); + } else { + zcbor_log("%s success\r\n", __func__); } return tmp_result; } -static bool decode_repeated_record__key_value_pair(zcbor_state_t *state, - struct record__key_value_pair *result) +static bool decode_repeated_record_key_value_pair_m(zcbor_state_t *state, + struct record_key_value_pair_m *result) { - zcbor_print("%s\r\n", __func__); + zcbor_log("%s\r\n", __func__); - bool tmp_result = (((decode_key_value_pair(state, (&(*result)._record__key_value_pair))))); + bool tmp_result = (((decode_key_value_pair(state, (&(*result).record_key_value_pair_m))))); if (!tmp_result) { - zcbor_trace(); + zcbor_trace_file(state); + zcbor_log("%s error: %s\r\n", __func__, zcbor_error_str(zcbor_peek_error(state))); + } else { + zcbor_log("%s success\r\n", __func__); } return tmp_result; @@ -189,35 +213,38 @@ static bool decode_repeated_record__key_value_pair(zcbor_state_t *state, static bool decode_record(zcbor_state_t *state, struct record *result) { - zcbor_print("%s\r\n", __func__); + zcbor_log("%s\r\n", __func__); bool tmp_result = (((zcbor_map_start_decode(state) && - ((zcbor_present_decode(&((*result)._record_bn_present), + ((zcbor_present_decode(&((*result).record_bn_present), (zcbor_decoder_t *)decode_repeated_record_bn, state, - (&(*result)._record_bn)) && - zcbor_present_decode(&((*result)._record_bt_present), + (&(*result).record_bn)) && + zcbor_present_decode(&((*result).record_bt_present), (zcbor_decoder_t *)decode_repeated_record_bt, state, - (&(*result)._record_bt)) && - zcbor_present_decode(&((*result)._record_n_present), + (&(*result).record_bt)) && + zcbor_present_decode(&((*result).record_n_present), (zcbor_decoder_t *)decode_repeated_record_n, state, - (&(*result)._record_n)) && - zcbor_present_decode(&((*result)._record_t_present), + (&(*result).record_n)) && + zcbor_present_decode(&((*result).record_t_present), (zcbor_decoder_t *)decode_repeated_record_t, state, - (&(*result)._record_t)) && - zcbor_present_decode(&((*result)._record_union_present), + (&(*result).record_t)) && + zcbor_present_decode(&((*result).record_union_present), (zcbor_decoder_t *)decode_repeated_record_union, state, - (&(*result)._record_union)) && - zcbor_multi_decode(0, ZCBOR_ARRAY_SIZE(result->_record__key_value_pair), - &(*result)._record__key_value_pair_count, - (zcbor_decoder_t *)decode_repeated_record__key_value_pair, - state, (&(*result)._record__key_value_pair), - sizeof(struct record__key_value_pair))) || + (&(*result).record_union)) && + zcbor_multi_decode(0, ZCBOR_ARRAY_SIZE(result->record_key_value_pair_m), + &(*result).record_key_value_pair_m_count, + (zcbor_decoder_t *)decode_repeated_record_key_value_pair_m, + state, (&(*result).record_key_value_pair_m), + sizeof(struct record_key_value_pair_m))) || (zcbor_list_map_end_force_decode(state), false)) && zcbor_map_end_decode(state)))); if (!tmp_result) { - zcbor_trace(); + zcbor_trace_file(state); + zcbor_log("%s error: %s\r\n", __func__, zcbor_error_str(zcbor_peek_error(state))); + } else { + zcbor_log("%s success\r\n", __func__); } return tmp_result; @@ -225,19 +252,22 @@ static bool decode_record(zcbor_state_t *state, struct record *result) static bool decode_lwm2m_senml(zcbor_state_t *state, struct lwm2m_senml *result) { - zcbor_print("%s\r\n", __func__); + zcbor_log("%s\r\n", __func__); bool tmp_result = (((zcbor_list_start_decode(state) && ((zcbor_multi_decode( - 1, ZCBOR_ARRAY_SIZE(result->_lwm2m_senml__record), - &(*result)._lwm2m_senml__record_count, (zcbor_decoder_t *)decode_record, - state, (&(*result)._lwm2m_senml__record), sizeof(struct record))) || + 1, ZCBOR_ARRAY_SIZE(result->lwm2m_senml_record_m), + &(*result).lwm2m_senml_record_m_count, (zcbor_decoder_t *)decode_record, + state, (&(*result).lwm2m_senml_record_m), sizeof(struct record))) || (zcbor_list_map_end_force_decode(state), false)) && zcbor_list_end_decode(state)))); if (!tmp_result) { - zcbor_trace(); + zcbor_trace_file(state); + zcbor_log("%s error: %s\r\n", __func__, zcbor_error_str(zcbor_peek_error(state))); + } else { + zcbor_log("%s success\r\n", __func__); } return tmp_result; @@ -248,19 +278,7 @@ int cbor_decode_lwm2m_senml(const uint8_t *payload, size_t payload_len, struct l { zcbor_state_t states[5]; - zcbor_new_state(states, sizeof(states) / sizeof(zcbor_state_t), payload, payload_len, 1); - - bool ret = decode_lwm2m_senml(states, result); - - if (ret && (payload_len_out != NULL)) { - *payload_len_out = MIN(payload_len, (size_t)states[0].payload - (size_t)payload); - } - - if (!ret) { - int err = zcbor_pop_error(states); - - zcbor_print("Return error: %d\r\n", err); - return (err == ZCBOR_SUCCESS) ? ZCBOR_ERR_UNKNOWN : err; - } - return ZCBOR_SUCCESS; + return zcbor_entry_function(payload, payload_len, (void *)result, payload_len_out, states, + (zcbor_decoder_t *)decode_lwm2m_senml, + sizeof(states) / sizeof(zcbor_state_t), 1); } diff --git a/subsys/net/lib/lwm2m/lwm2m_senml_cbor_decode.h b/subsys/net/lib/lwm2m/lwm2m_senml_cbor_decode.h index a8ae779b6a1..b47b79de615 100644 --- a/subsys/net/lib/lwm2m/lwm2m_senml_cbor_decode.h +++ b/subsys/net/lib/lwm2m/lwm2m_senml_cbor_decode.h @@ -3,7 +3,7 @@ * * SPDX-License-Identifier: Apache-2.0 * - * Generated using zcbor version 0.7.0 + * Generated using zcbor version 0.8.0 * https://github.com/zephyrproject-rtos/zcbor * Generated with a --default-max-qty of 99 */ diff --git a/subsys/net/lib/lwm2m/lwm2m_senml_cbor_encode.c b/subsys/net/lib/lwm2m/lwm2m_senml_cbor_encode.c index 74c9310941b..9cf4f3457c6 100644 --- a/subsys/net/lib/lwm2m/lwm2m_senml_cbor_encode.c +++ b/subsys/net/lib/lwm2m/lwm2m_senml_cbor_encode.c @@ -3,7 +3,7 @@ * * SPDX-License-Identifier: Apache-2.0 * - * Generated using zcbor version 0.7.0 + * Generated using zcbor version 0.8.0 * https://github.com/zephyrproject-rtos/zcbor * Generated with a --default-max-qty of 99 */ @@ -14,28 +14,32 @@ #include #include "zcbor_encode.h" #include "lwm2m_senml_cbor_encode.h" +#include "zcbor_print.h" static bool encode_repeated_record_bn(zcbor_state_t *state, const struct record_bn *input); static bool encode_repeated_record_bt(zcbor_state_t *state, const struct record_bt *input); static bool encode_repeated_record_n(zcbor_state_t *state, const struct record_n *input); static bool encode_repeated_record_t(zcbor_state_t *state, const struct record_t *input); -static bool encode_repeated_record_union(zcbor_state_t *state, const struct record_union_ *input); -static bool encode_value(zcbor_state_t *state, const struct value_ *input); +static bool encode_repeated_record_union(zcbor_state_t *state, const struct record_union_r *input); +static bool encode_value(zcbor_state_t *state, const struct value_r *input); static bool encode_key_value_pair(zcbor_state_t *state, const struct key_value_pair *input); -static bool encode_repeated_record__key_value_pair(zcbor_state_t *state, - const struct record__key_value_pair *input); +static bool encode_repeated_record_key_value_pair_m(zcbor_state_t *state, + const struct record_key_value_pair_m *input); static bool encode_record(zcbor_state_t *state, const struct record *input); static bool encode_lwm2m_senml(zcbor_state_t *state, const struct lwm2m_senml *input); static bool encode_repeated_record_bn(zcbor_state_t *state, const struct record_bn *input) { - zcbor_print("%s\r\n", __func__); + zcbor_log("%s\r\n", __func__); bool tmp_result = ((((zcbor_int32_put(state, (-2)))) && - (zcbor_tstr_encode(state, (&(*input)._record_bn))))); + (zcbor_tstr_encode(state, (&(*input).record_bn))))); if (!tmp_result) { - zcbor_trace(); + zcbor_trace_file(state); + zcbor_log("%s error: %s\r\n", __func__, zcbor_error_str(zcbor_peek_error(state))); + } else { + zcbor_log("%s success\r\n", __func__); } return tmp_result; @@ -43,16 +47,19 @@ static bool encode_repeated_record_bn(zcbor_state_t *state, const struct record_ static bool encode_repeated_record_bt(zcbor_state_t *state, const struct record_bt *input) { - zcbor_print("%s\r\n", __func__); + zcbor_log("%s\r\n", __func__); bool tmp_result = ((((zcbor_int32_put(state, (-3)))) && - ((((*input)._record_bt >= INT64_MIN) && ((*input)._record_bt <= INT64_MAX)) || + ((((*input).record_bt >= INT64_MIN) && ((*input).record_bt <= INT64_MAX)) || (zcbor_error(state, ZCBOR_ERR_WRONG_RANGE), false)) && - (zcbor_int64_encode(state, (&(*input)._record_bt))))); + (zcbor_int64_encode(state, (&(*input).record_bt))))); if (!tmp_result) { - zcbor_trace(); + zcbor_trace_file(state); + zcbor_log("%s error: %s\r\n", __func__, zcbor_error_str(zcbor_peek_error(state))); + } else { + zcbor_log("%s success\r\n", __func__); } return tmp_result; @@ -60,13 +67,16 @@ static bool encode_repeated_record_bt(zcbor_state_t *state, const struct record_ static bool encode_repeated_record_n(zcbor_state_t *state, const struct record_n *input) { - zcbor_print("%s\r\n", __func__); + zcbor_log("%s\r\n", __func__); bool tmp_result = ((((zcbor_uint32_put(state, (0)))) && - (zcbor_tstr_encode(state, (&(*input)._record_n))))); + (zcbor_tstr_encode(state, (&(*input).record_n))))); if (!tmp_result) { - zcbor_trace(); + zcbor_trace_file(state); + zcbor_log("%s error: %s\r\n", __func__, zcbor_error_str(zcbor_peek_error(state))); + } else { + zcbor_log("%s success\r\n", __func__); } return tmp_result; @@ -74,81 +84,98 @@ static bool encode_repeated_record_n(zcbor_state_t *state, const struct record_n static bool encode_repeated_record_t(zcbor_state_t *state, const struct record_t *input) { - zcbor_print("%s\r\n", __func__); + zcbor_log("%s\r\n", __func__); bool tmp_result = ((((zcbor_uint32_put(state, (6)))) && - ((((*input)._record_t >= INT64_MIN) && ((*input)._record_t <= INT64_MAX)) || + ((((*input).record_t >= INT64_MIN) && ((*input).record_t <= INT64_MAX)) || (zcbor_error(state, ZCBOR_ERR_WRONG_RANGE), false)) && - (zcbor_int64_encode(state, (&(*input)._record_t))))); + (zcbor_int64_encode(state, (&(*input).record_t))))); if (!tmp_result) { - zcbor_trace(); + zcbor_trace_file(state); + zcbor_log("%s error: %s\r\n", __func__, zcbor_error_str(zcbor_peek_error(state))); + } else { + zcbor_log("%s success\r\n", __func__); } return tmp_result; } -static bool encode_repeated_record_union(zcbor_state_t *state, const struct record_union_ *input) +static bool encode_repeated_record_union(zcbor_state_t *state, const struct record_union_r *input) { - zcbor_print("%s\r\n", __func__); + zcbor_log("%s\r\n", __func__); struct zcbor_string tmp_str; bool tmp_result = ((( - ((*input)._record_union_choice == _union_vi) + ((*input).record_union_choice == union_vi_c) ? (((zcbor_uint32_put(state, (2)))) && - ((((*input)._union_vi >= INT64_MIN) && - ((*input)._union_vi <= INT64_MAX)) || + ((((*input).union_vi >= INT64_MIN) && + ((*input).union_vi <= INT64_MAX)) || (zcbor_error(state, ZCBOR_ERR_WRONG_RANGE), false)) && - (zcbor_int64_encode(state, (&(*input)._union_vi)))) - : (((*input)._record_union_choice == _union_vf) - ? (((zcbor_uint32_put(state, (2)))) && - (zcbor_float64_encode(state, (&(*input)._union_vf)))) - : (((*input)._record_union_choice == _union_vs) - ? (((zcbor_uint32_put(state, (3)))) && - (zcbor_tstr_encode(state, (&(*input)._union_vs)))) - : (((*input)._record_union_choice == _union_vb) - ? (((zcbor_uint32_put(state, (4)))) && - (zcbor_bool_encode(state, (&(*input)._union_vb)))) - : (((*input)._record_union_choice == _union_vd) - ? (((zcbor_uint32_put(state, (8)))) && - (zcbor_bstr_encode(state, (&(*input)._union_vd)))) - : (((*input)._record_union_choice == _union_vlo) - ? (((zcbor_tstr_encode(state, ((tmp_str.value = (uint8_t *)"vlo", - tmp_str.len = sizeof("vlo") - 1, - &tmp_str))))) && - (zcbor_tstr_encode(state, (&(*input)._union_vlo)))) - : false)))))))); + (zcbor_int64_encode(state, (&(*input).union_vi)))) + : (((*input).record_union_choice == union_vf_c) + ? (((zcbor_uint32_put(state, (2)))) && + (zcbor_float64_encode(state, (&(*input).union_vf)))) + : (((*input).record_union_choice == union_vs_c) + ? (((zcbor_uint32_put(state, (3)))) && + (zcbor_tstr_encode(state, (&(*input).union_vs)))) + : (((*input).record_union_choice == union_vb_c) + ? (((zcbor_uint32_put(state, (4)))) && + (zcbor_bool_encode(state, (&(*input).union_vb)))) + : (((*input).record_union_choice == union_vd_c) + ? (((zcbor_uint32_put(state, (8)))) && + (zcbor_bstr_encode(state, (&(*input).union_vd)))) + : (((*input).record_union_choice == union_vlo_c) + ? (((zcbor_tstr_encode( + state, + ((tmp_str.value = (uint8_t *)"vlo", + tmp_str.len = sizeof("vlo") - 1, + &tmp_str))))) && + (zcbor_tstr_encode( + state, + (&(*input).union_vlo)))) + : false)))))))); if (!tmp_result) { - zcbor_trace(); + zcbor_trace_file(state); + zcbor_log("%s error: %s\r\n", __func__, zcbor_error_str(zcbor_peek_error(state))); + } else { + zcbor_log("%s success\r\n", __func__); } return tmp_result; } -static bool encode_value(zcbor_state_t *state, const struct value_ *input) +static bool encode_value(zcbor_state_t *state, const struct value_r *input) { - zcbor_print("%s\r\n", __func__); + zcbor_log("%s\r\n", __func__); bool tmp_result = ((( - ((*input)._value_choice == _value_tstr) - ? ((zcbor_tstr_encode(state, (&(*input)._value_tstr)))) - : (((*input)._value_choice == _value_bstr) - ? ((zcbor_bstr_encode(state, (&(*input)._value_bstr)))) - : (((*input)._value_choice == _value_int) - ? (((((*input)._value_int >= INT64_MIN) && - ((*input)._value_int <= INT64_MAX)) || - (zcbor_error(state, ZCBOR_ERR_WRONG_RANGE), false)) && - (zcbor_int64_encode(state, (&(*input)._value_int)))) - : (((*input)._value_choice == _value_float) - ? ((zcbor_float64_encode(state, (&(*input)._value_float)))) - : (((*input)._value_choice == _value_bool) - ? ((zcbor_bool_encode(state, (&(*input)._value_bool)))) - : false))))))); + ((*input).value_choice == value_tstr_c) + ? ((zcbor_tstr_encode(state, (&(*input).value_tstr)))) + : (((*input).value_choice == value_bstr_c) + ? ((zcbor_bstr_encode(state, (&(*input).value_bstr)))) + : (((*input).value_choice == value_int_c) + ? (((((*input).value_int >= INT64_MIN) && + ((*input).value_int <= INT64_MAX)) || + (zcbor_error(state, ZCBOR_ERR_WRONG_RANGE), + false)) && + (zcbor_int64_encode(state, (&(*input).value_int)))) + : (((*input).value_choice == value_float_c) + ? ((zcbor_float64_encode( + state, (&(*input).value_float)))) + : (((*input).value_choice == value_bool_c) + ? ((zcbor_bool_encode( + state, + (&(*input).value_bool)))) + : false))))))); if (!tmp_result) { - zcbor_trace(); + zcbor_trace_file(state); + zcbor_log("%s error: %s\r\n", __func__, zcbor_error_str(zcbor_peek_error(state))); + } else { + zcbor_log("%s success\r\n", __func__); } return tmp_result; @@ -156,27 +183,33 @@ static bool encode_value(zcbor_state_t *state, const struct value_ *input) static bool encode_key_value_pair(zcbor_state_t *state, const struct key_value_pair *input) { - zcbor_print("%s\r\n", __func__); + zcbor_log("%s\r\n", __func__); - bool tmp_result = ((((zcbor_int32_encode(state, (&(*input)._key_value_pair_key)))) && - (encode_value(state, (&(*input)._key_value_pair))))); + bool tmp_result = ((((zcbor_int32_encode(state, (&(*input).key_value_pair_key)))) && + (encode_value(state, (&(*input).key_value_pair))))); if (!tmp_result) { - zcbor_trace(); + zcbor_trace_file(state); + zcbor_log("%s error: %s\r\n", __func__, zcbor_error_str(zcbor_peek_error(state))); + } else { + zcbor_log("%s success\r\n", __func__); } return tmp_result; } -static bool encode_repeated_record__key_value_pair(zcbor_state_t *state, - const struct record__key_value_pair *input) +static bool encode_repeated_record_key_value_pair_m(zcbor_state_t *state, + const struct record_key_value_pair_m *input) { - zcbor_print("%s\r\n", __func__); + zcbor_log("%s\r\n", __func__); - bool tmp_result = (((encode_key_value_pair(state, (&(*input)._record__key_value_pair))))); + bool tmp_result = (((encode_key_value_pair(state, (&(*input).record_key_value_pair_m))))); if (!tmp_result) { - zcbor_trace(); + zcbor_trace_file(state); + zcbor_log("%s error: %s\r\n", __func__, zcbor_error_str(zcbor_peek_error(state))); + } else { + zcbor_log("%s success\r\n", __func__); } return tmp_result; @@ -184,36 +217,34 @@ static bool encode_repeated_record__key_value_pair(zcbor_state_t *state, static bool encode_record(zcbor_state_t *state, const struct record *input) { - zcbor_print("%s\r\n", __func__); + zcbor_log("%s\r\n", __func__); bool tmp_result = (( - (zcbor_map_start_encode(state, ZCBOR_ARRAY_SIZE(input->_record__key_value_pair)) && - ((zcbor_present_encode(&((*input)._record_bn_present), - (zcbor_encoder_t *)encode_repeated_record_bn, state, - (&(*input)._record_bn)) && - zcbor_present_encode(&((*input)._record_bt_present), - (zcbor_encoder_t *)encode_repeated_record_bt, state, - (&(*input)._record_bt)) && - zcbor_present_encode(&((*input)._record_n_present), - (zcbor_encoder_t *)encode_repeated_record_n, state, - (&(*input)._record_n)) && - zcbor_present_encode(&((*input)._record_t_present), - (zcbor_encoder_t *)encode_repeated_record_t, state, - (&(*input)._record_t)) && - zcbor_present_encode(&((*input)._record_union_present), - (zcbor_encoder_t *)encode_repeated_record_union, state, - (&(*input)._record_union)) && + (zcbor_map_start_encode(state, ZCBOR_ARRAY_SIZE(input->record_key_value_pair_m)) && + (((!(*input).record_bn_present || + encode_repeated_record_bn(state, (&(*input).record_bn))) && + (!(*input).record_bt_present || + encode_repeated_record_bt(state, (&(*input).record_bt))) && + (!(*input).record_n_present || + encode_repeated_record_n(state, (&(*input).record_n))) && + (!(*input).record_t_present || + encode_repeated_record_t(state, (&(*input).record_t))) && + (!(*input).record_union_present || + encode_repeated_record_union(state, (&(*input).record_union))) && zcbor_multi_encode_minmax( - 0, ZCBOR_ARRAY_SIZE(input->_record__key_value_pair), - &(*input)._record__key_value_pair_count, - (zcbor_encoder_t *)encode_repeated_record__key_value_pair, state, - (&(*input)._record__key_value_pair), - sizeof(struct record__key_value_pair))) || + 0, ZCBOR_ARRAY_SIZE(input->record_key_value_pair_m), + &(*input).record_key_value_pair_m_count, + (zcbor_encoder_t *)encode_repeated_record_key_value_pair_m, state, + (&(*input).record_key_value_pair_m), + sizeof(struct record_key_value_pair_m))) || (zcbor_list_map_end_force_encode(state), false)) && - zcbor_map_end_encode(state, ZCBOR_ARRAY_SIZE(input->_record__key_value_pair))))); + zcbor_map_end_encode(state, ZCBOR_ARRAY_SIZE(input->record_key_value_pair_m))))); if (!tmp_result) { - zcbor_trace(); + zcbor_trace_file(state); + zcbor_log("%s error: %s\r\n", __func__, zcbor_error_str(zcbor_peek_error(state))); + } else { + zcbor_log("%s success\r\n", __func__); } return tmp_result; @@ -221,19 +252,22 @@ static bool encode_record(zcbor_state_t *state, const struct record *input) static bool encode_lwm2m_senml(zcbor_state_t *state, const struct lwm2m_senml *input) { - zcbor_print("%s\r\n", __func__); + zcbor_log("%s\r\n", __func__); bool tmp_result = - (((zcbor_list_start_encode(state, ZCBOR_ARRAY_SIZE(input->_lwm2m_senml__record)) && + (((zcbor_list_start_encode(state, ZCBOR_ARRAY_SIZE(input->lwm2m_senml_record_m)) && ((zcbor_multi_encode_minmax( - 1, ZCBOR_ARRAY_SIZE(input->_lwm2m_senml__record), - &(*input)._lwm2m_senml__record_count, (zcbor_encoder_t *)encode_record, - state, (&(*input)._lwm2m_senml__record), sizeof(struct record))) || + 1, ZCBOR_ARRAY_SIZE(input->lwm2m_senml_record_m), + &(*input).lwm2m_senml_record_m_count, (zcbor_encoder_t *)encode_record, + state, (&(*input).lwm2m_senml_record_m), sizeof(struct record))) || (zcbor_list_map_end_force_encode(state), false)) && - zcbor_list_end_encode(state, ZCBOR_ARRAY_SIZE(input->_lwm2m_senml__record))))); + zcbor_list_end_encode(state, ZCBOR_ARRAY_SIZE(input->lwm2m_senml_record_m))))); if (!tmp_result) { - zcbor_trace(); + zcbor_trace_file(state); + zcbor_log("%s error: %s\r\n", __func__, zcbor_error_str(zcbor_peek_error(state))); + } else { + zcbor_log("%s success\r\n", __func__); } return tmp_result; @@ -244,19 +278,7 @@ int cbor_encode_lwm2m_senml(uint8_t *payload, size_t payload_len, const struct l { zcbor_state_t states[5]; - zcbor_new_state(states, sizeof(states) / sizeof(zcbor_state_t), payload, payload_len, 1); - - bool ret = encode_lwm2m_senml(states, input); - - if (ret && (payload_len_out != NULL)) { - *payload_len_out = MIN(payload_len, (size_t)states[0].payload - (size_t)payload); - } - - if (!ret) { - int err = zcbor_pop_error(states); - - zcbor_print("Return error: %d\r\n", err); - return (err == ZCBOR_SUCCESS) ? ZCBOR_ERR_UNKNOWN : err; - } - return ZCBOR_SUCCESS; + return zcbor_entry_function(payload, payload_len, (void *)input, payload_len_out, states, + (zcbor_decoder_t *)encode_lwm2m_senml, + sizeof(states) / sizeof(zcbor_state_t), 1); } diff --git a/subsys/net/lib/lwm2m/lwm2m_senml_cbor_encode.h b/subsys/net/lib/lwm2m/lwm2m_senml_cbor_encode.h index 05d2664c2a0..49ce5c55159 100644 --- a/subsys/net/lib/lwm2m/lwm2m_senml_cbor_encode.h +++ b/subsys/net/lib/lwm2m/lwm2m_senml_cbor_encode.h @@ -3,7 +3,7 @@ * * SPDX-License-Identifier: Apache-2.0 * - * Generated using zcbor version 0.7.0 + * Generated using zcbor version 0.8.0 * https://github.com/zephyrproject-rtos/zcbor * Generated with a --default-max-qty of 99 */ diff --git a/subsys/net/lib/lwm2m/lwm2m_senml_cbor_types.h b/subsys/net/lib/lwm2m/lwm2m_senml_cbor_types.h index f1b86bb60b0..4c41385ba4b 100644 --- a/subsys/net/lib/lwm2m/lwm2m_senml_cbor_types.h +++ b/subsys/net/lib/lwm2m/lwm2m_senml_cbor_types.h @@ -3,7 +3,7 @@ * * SPDX-License-Identifier: Apache-2.0 * - * Generated using zcbor version 0.7.0 + * Generated using zcbor version 0.8.0 * https://github.com/zephyrproject-rtos/zcbor * Generated with a --default-max-qty of 99 */ @@ -32,115 +32,97 @@ enum lwm2m_senml_cbor_key { lwm2m_senml_cbor_key_vd = 8, }; -/** Which value for --default-max-qty this file was created with. - * - * The define is used in the other generated file to do a build-time - * compatibility check. - * - * See `zcbor --help` for more information about --default-max-qty - */ -#define DEFAULT_MAX_QTY CONFIG_LWM2M_RW_SENML_CBOR_RECORDS - struct record_bn { - struct zcbor_string _record_bn; + struct zcbor_string record_bn; }; struct record_bt { - int64_t _record_bt; + int64_t record_bt; }; struct record_n { - struct zcbor_string _record_n; + struct zcbor_string record_n; }; struct record_t { - int64_t _record_t; + int64_t record_t; }; -/* The union members and enum members have the same names. - * This is intentional so we need to ignore -Wshadow to avoid - * compiler complaining about them. - */ -#pragma GCC diagnostic push -#pragma GCC diagnostic ignored "-Wshadow" - -struct record_union_ { +struct record_union_r { union { struct { - int64_t _union_vi; + int64_t union_vi; }; struct { - double _union_vf; + double union_vf; }; struct { - struct zcbor_string _union_vs; + struct zcbor_string union_vs; }; struct { - bool _union_vb; + bool union_vb; }; struct { - struct zcbor_string _union_vd; + struct zcbor_string union_vd; }; struct { - struct zcbor_string _union_vlo; + struct zcbor_string union_vlo; }; }; enum { - _union_vi, - _union_vf, - _union_vs, - _union_vb, - _union_vd, - _union_vlo, - } _record_union_choice; + union_vi_c, + union_vf_c, + union_vs_c, + union_vb_c, + union_vd_c, + union_vlo_c, + } record_union_choice; }; -struct value_ { +struct value_r { union { - struct zcbor_string _value_tstr; - struct zcbor_string _value_bstr; - int64_t _value_int; - double _value_float; - bool _value_bool; + struct zcbor_string value_tstr; + struct zcbor_string value_bstr; + int64_t value_int; + double value_float; + bool value_bool; }; enum { - _value_tstr, - _value_bstr, - _value_int, - _value_float, - _value_bool, - } _value_choice; + value_tstr_c, + value_bstr_c, + value_int_c, + value_float_c, + value_bool_c, + } value_choice; }; -#pragma GCC diagnostic pop - struct key_value_pair { - int32_t _key_value_pair_key; - struct value_ _key_value_pair; + int32_t key_value_pair_key; + struct value_r key_value_pair; }; -struct record__key_value_pair { - struct key_value_pair _record__key_value_pair; +struct record_key_value_pair_m { + struct key_value_pair record_key_value_pair_m; }; struct record { - struct record_bn _record_bn; - bool _record_bn_present; - struct record_bt _record_bt; - bool _record_bt_present; - struct record_n _record_n; - bool _record_n_present; - struct record_t _record_t; - bool _record_t_present; - struct record_union_ _record_union; - bool _record_union_present; - struct record__key_value_pair _record__key_value_pair[5]; - size_t _record__key_value_pair_count; + struct record_bn record_bn; + bool record_bn_present; + struct record_bt record_bt; + bool record_bt_present; + struct record_n record_n; + bool record_n_present; + struct record_t record_t; + bool record_t_present; + struct record_union_r record_union; + bool record_union_present; + struct record_key_value_pair_m record_key_value_pair_m[5]; + size_t record_key_value_pair_m_count; }; struct lwm2m_senml { - struct record _lwm2m_senml__record[DEFAULT_MAX_QTY]; - size_t _lwm2m_senml__record_count; + struct record lwm2m_senml_record_m[CONFIG_LWM2M_RW_SENML_CBOR_RECORDS]; + size_t lwm2m_senml_record_m_count; }; #ifdef __cplusplus From 527af809f88166725ae1ac432851d0e81e97e56d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C3=98yvind=20R=C3=B8nningstad?= Date: Wed, 10 Jan 2024 14:39:42 +0100 Subject: [PATCH 2830/3723] mgmt: Adapt to API changes in zcbor 0.8.0 MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit zcbor_new_state and zcbor_tstr_put_term Signed-off-by: Øyvind Rønningstad --- include/zephyr/mgmt/mcumgr/grp/os_mgmt/os_mgmt_client.h | 3 ++- subsys/mgmt/mcumgr/grp/fs_mgmt/src/fs_mgmt.c | 2 +- subsys/mgmt/mcumgr/grp/img_mgmt/src/img_mgmt_state.c | 4 ++-- .../mcumgr/grp/img_mgmt_client/src/img_mgmt_client.c | 6 +++--- subsys/mgmt/mcumgr/grp/os_mgmt/src/os_mgmt.c | 2 +- .../mgmt/mcumgr/grp/os_mgmt_client/src/os_mgmt_client.c | 7 ++++--- subsys/mgmt/mcumgr/grp/stat_mgmt/Kconfig | 9 ++++++--- subsys/mgmt/mcumgr/grp/stat_mgmt/src/stat_mgmt.c | 5 +++-- subsys/mgmt/mcumgr/smp/src/smp.c | 4 ++-- 9 files changed, 24 insertions(+), 18 deletions(-) diff --git a/include/zephyr/mgmt/mcumgr/grp/os_mgmt/os_mgmt_client.h b/include/zephyr/mgmt/mcumgr/grp/os_mgmt/os_mgmt_client.h index 0b12ccdb684..ba63c136f50 100644 --- a/include/zephyr/mgmt/mcumgr/grp/os_mgmt/os_mgmt_client.h +++ b/include/zephyr/mgmt/mcumgr/grp/os_mgmt/os_mgmt_client.h @@ -45,11 +45,12 @@ void os_mgmt_client_init(struct os_mgmt_client *client, struct smp_client_object * * @param client OS mgmt client object * @param echo_string Echo string + * @param max_len Max length of @p echo_string * * @return 0 on success. * @return @ref mcumgr_err_t code on failure. */ -int os_mgmt_client_echo(struct os_mgmt_client *client, const char *echo_string); +int os_mgmt_client_echo(struct os_mgmt_client *client, const char *echo_string, size_t max_len); /** * @brief Send SMP Reset command. diff --git a/subsys/mgmt/mcumgr/grp/fs_mgmt/src/fs_mgmt.c b/subsys/mgmt/mcumgr/grp/fs_mgmt/src/fs_mgmt.c index 7cb31627d35..ac6b011d6bf 100644 --- a/subsys/mgmt/mcumgr/grp/fs_mgmt/src/fs_mgmt.c +++ b/subsys/mgmt/mcumgr/grp/fs_mgmt/src/fs_mgmt.c @@ -785,7 +785,7 @@ static int fs_mgmt_file_hash_checksum(struct smp_streamer *ctxt) } ok &= zcbor_tstr_put_lit(zse, "type") && - zcbor_tstr_put_term(zse, type_arr); + zcbor_tstr_put_term(zse, type_arr, sizeof(type_arr)); if (off != 0) { ok &= zcbor_tstr_put_lit(zse, "off") && diff --git a/subsys/mgmt/mcumgr/grp/img_mgmt/src/img_mgmt_state.c b/subsys/mgmt/mcumgr/grp/img_mgmt/src/img_mgmt_state.c index 0968694c614..c54fbd4d0c6 100644 --- a/subsys/mgmt/mcumgr/grp/img_mgmt/src/img_mgmt_state.c +++ b/subsys/mgmt/mcumgr/grp/img_mgmt/src/img_mgmt_state.c @@ -442,11 +442,11 @@ static bool img_mgmt_state_encode_slot(zcbor_state_t *zse, uint32_t slot, int st ok = zcbor_tstr_put_lit(zse, "<\?\?\?>"); } else { vers_str[sizeof(vers_str) - 1] = '\0'; - ok = zcbor_tstr_put_term(zse, vers_str); + ok = zcbor_tstr_put_term(zse, vers_str, sizeof(vers_str)); } } - ok = ok && zcbor_tstr_put_term(zse, "hash") && + ok = ok && zcbor_tstr_put_lit(zse, "hash") && zcbor_bstr_encode(zse, &zhash) && ZCBOR_ENCODE_FLAG(zse, "bootable", !(flags & IMAGE_F_NON_BOOTABLE)) && ZCBOR_ENCODE_FLAG(zse, "pending", state_flags & REPORT_SLOT_PENDING) && diff --git a/subsys/mgmt/mcumgr/grp/img_mgmt_client/src/img_mgmt_client.c b/subsys/mgmt/mcumgr/grp/img_mgmt_client/src/img_mgmt_client.c index 9ab8ee02dcd..b8cbc38b275 100644 --- a/subsys/mgmt/mcumgr/grp/img_mgmt_client/src/img_mgmt_client.c +++ b/subsys/mgmt/mcumgr/grp/img_mgmt_client/src/img_mgmt_client.c @@ -74,7 +74,7 @@ static int image_state_res_fn(struct net_buf *nb, void *user_data) goto out; } - zcbor_new_decode_state(zsd, ARRAY_SIZE(zsd), nb->data, nb->len, 1); + zcbor_new_decode_state(zsd, ARRAY_SIZE(zsd), nb->data, nb->len, 1, NULL, 0); ok = zcbor_map_start_decode(zsd); if (!ok) { @@ -201,7 +201,7 @@ static int image_upload_res_fn(struct net_buf *nb, void *user_data) goto end; } - zcbor_new_decode_state(zsd, ARRAY_SIZE(zsd), nb->data, nb->len, 1); + zcbor_new_decode_state(zsd, ARRAY_SIZE(zsd), nb->data, nb->len, 1, NULL, 0); rc = zcbor_map_decode_bulk(zsd, upload_res_decode, ARRAY_SIZE(upload_res_decode), &decoded); if (rc || image_upload_buf->image_upload_offset == SIZE_MAX) { @@ -233,7 +233,7 @@ static int erase_res_fn(struct net_buf *nb, void *user_data) goto end; } - zcbor_new_decode_state(zsd, ARRAY_SIZE(zsd), nb->data, nb->len, 1); + zcbor_new_decode_state(zsd, ARRAY_SIZE(zsd), nb->data, nb->len, 1, NULL, 0); rc = zcbor_map_decode_bulk(zsd, upload_res_decode, ARRAY_SIZE(upload_res_decode), &decoded); if (rc) { diff --git a/subsys/mgmt/mcumgr/grp/os_mgmt/src/os_mgmt.c b/subsys/mgmt/mcumgr/grp/os_mgmt/src/os_mgmt.c index 7eef7f398f7..3e524362fa3 100644 --- a/subsys/mgmt/mcumgr/grp/os_mgmt/src/os_mgmt.c +++ b/subsys/mgmt/mcumgr/grp/os_mgmt/src/os_mgmt.c @@ -205,7 +205,7 @@ os_mgmt_taskstat_encode_thread_name(zcbor_state_t *zse, int idx, snprintf(thread_name, sizeof(thread_name) - 1, "%d", idx); thread_name[sizeof(thread_name) - 1] = 0; - return zcbor_tstr_put_term(zse, thread_name); + return zcbor_tstr_put_term(zse, thread_name, sizeof(thread_name)); } #endif diff --git a/subsys/mgmt/mcumgr/grp/os_mgmt_client/src/os_mgmt_client.c b/subsys/mgmt/mcumgr/grp/os_mgmt_client/src/os_mgmt_client.c index 2bd804494c4..0bd174d1c97 100644 --- a/subsys/mgmt/mcumgr/grp/os_mgmt_client/src/os_mgmt_client.c +++ b/subsys/mgmt/mcumgr/grp/os_mgmt_client/src/os_mgmt_client.c @@ -104,7 +104,7 @@ static int echo_res_fn(struct net_buf *nb, void *user_data) } /* Init ZCOR decoder state */ - zcbor_new_decode_state(zsd, ARRAY_SIZE(zsd), nb->data, nb->len, 1); + zcbor_new_decode_state(zsd, ARRAY_SIZE(zsd), nb->data, nb->len, 1, NULL, 0); ok = zcbor_map_decode_bulk(zsd, echo_response, ARRAY_SIZE(echo_response), &decoded) == 0; @@ -119,7 +119,7 @@ static int echo_res_fn(struct net_buf *nb, void *user_data) return rc; } -int os_mgmt_client_echo(struct os_mgmt_client *client, const char *echo_string) +int os_mgmt_client_echo(struct os_mgmt_client *client, const char *echo_string, size_t max_len) { struct net_buf *nb; int rc; @@ -138,7 +138,8 @@ int os_mgmt_client_echo(struct os_mgmt_client *client, const char *echo_string) zcbor_new_encode_state(zse, ARRAY_SIZE(zse), nb->data + nb->len, net_buf_tailroom(nb), 0); ok = zcbor_map_start_encode(zse, 2) && - zcbor_tstr_put_lit(zse, "d") && zcbor_tstr_put_term(zse, echo_string) && + zcbor_tstr_put_lit(zse, "d") && + zcbor_tstr_put_term(zse, echo_string, max_len) && zcbor_map_end_encode(zse, 2); if (!ok) { diff --git a/subsys/mgmt/mcumgr/grp/stat_mgmt/Kconfig b/subsys/mgmt/mcumgr/grp/stat_mgmt/Kconfig index 757d290d10d..1ab882c33ee 100644 --- a/subsys/mgmt/mcumgr/grp/stat_mgmt/Kconfig +++ b/subsys/mgmt/mcumgr/grp/stat_mgmt/Kconfig @@ -28,9 +28,12 @@ config MCUMGR_GRP_STAT_MAX_NAME_LEN depends on MCUMGR_GRP_STAT help Limits the maximum stat group name length in MCUmgr requests, in bytes. - A buffer of this size gets allocated on the stack during handling of all - stat read commands. If a stat group's name exceeds this limit, it will - be impossible to retrieve its values with a stat show command. + For stat group names. a buffer of this size gets allocated on the stack + during handling of all stat read commands. If a stat group's name + exceeds this limit, it will be impossible to retrieve its values with + a stat show command. + For stat names s_name and snm_name, this is the maximum length when + encoding the name to cbor. module = MCUMGR_GRP_STAT module-str = mcumgr_grp_stat diff --git a/subsys/mgmt/mcumgr/grp/stat_mgmt/src/stat_mgmt.c b/subsys/mgmt/mcumgr/grp/stat_mgmt/src/stat_mgmt.c index 4740073cf01..29e546bdb86 100644 --- a/subsys/mgmt/mcumgr/grp/stat_mgmt/src/stat_mgmt.c +++ b/subsys/mgmt/mcumgr/grp/stat_mgmt/src/stat_mgmt.c @@ -110,7 +110,7 @@ stat_mgmt_foreach_entry(zcbor_state_t *zse, const char *group_name, stat_mgmt_fo static int stat_mgmt_cb_encode(zcbor_state_t *zse, struct stat_mgmt_entry *entry) { - bool ok = zcbor_tstr_put_term(zse, entry->name) && + bool ok = zcbor_tstr_put_term(zse, entry->name, CONFIG_MCUMGR_GRP_STAT_MAX_NAME_LEN) && zcbor_uint32_put(zse, entry->value); return ok ? MGMT_ERR_EOK : MGMT_ERR_EMSGSIZE; @@ -215,7 +215,8 @@ stat_mgmt_list(struct smp_streamer *ctxt) do { cur = stats_group_get_next(cur); if (cur != NULL) { - ok = zcbor_tstr_put_term(zse, cur->s_name); + ok = zcbor_tstr_put_term(zse, cur->s_name, + CONFIG_MCUMGR_GRP_STAT_MAX_NAME_LEN); } } while (ok && cur != NULL); diff --git a/subsys/mgmt/mcumgr/smp/src/smp.c b/subsys/mgmt/mcumgr/smp/src/smp.c index 7aff480e091..39314a78ceb 100644 --- a/subsys/mgmt/mcumgr/smp/src/smp.c +++ b/subsys/mgmt/mcumgr/smp/src/smp.c @@ -53,7 +53,7 @@ static void cbor_nb_reader_init(struct cbor_nb_reader *cnr, struct net_buf *nb) { cnr->nb = nb; zcbor_new_decode_state(cnr->zs, ARRAY_SIZE(cnr->zs), nb->data, - nb->len, 1); + nb->len, 1, NULL, 0); } static void cbor_nb_writer_init(struct cbor_nb_writer *cnw, struct net_buf *nb) @@ -125,7 +125,7 @@ static int smp_build_err_rsp(struct smp_streamer *streamer, const struct smp_hdr #ifdef CONFIG_MCUMGR_SMP_VERBOSE_ERR_RESPONSE if (ok && rc_rsn != NULL) { ok = zcbor_tstr_put_lit(zsp, "rsn") && - zcbor_tstr_put_term(zsp, rc_rsn); + zcbor_tstr_put_term(zsp, rc_rsn, CONFIG_ZCBOR_MAX_STR_LEN); } #else ARG_UNUSED(rc_rsn); From 223b4c372f3af02e55980526256482d2a8b3e70b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C3=98yvind=20R=C3=B8nningstad?= Date: Wed, 10 Jan 2024 14:39:42 +0100 Subject: [PATCH 2831/3723] tests: mgmt: Adapt to API changes in zcbor 0.8.0 MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit zcbor_new_state and zcbor_tstr_put_term Signed-off-by: Øyvind Rønningstad --- .../cb_notifications/src/smp_test_util.c | 2 +- .../mcumgr/fs_mgmt_hash_supported/src/main.c | 2 +- .../mcumgr/mcumgr_client/src/img_gr_stub.c | 11 +++-- .../mgmt/mcumgr/mcumgr_client/src/main.c | 4 +- .../mcumgr/mcumgr_client/src/os_gr_stub.c | 3 +- .../mgmt/mcumgr/os_mgmt_datetime/src/main.c | 44 +++++++++---------- .../os_mgmt_datetime/src/smp_test_util.c | 6 +-- .../mgmt/mcumgr/os_mgmt_info/src/build_date.c | 4 +- .../mgmt/mcumgr/os_mgmt_info/src/limited.c | 6 +-- .../mgmt/mcumgr/os_mgmt_info/src/main.c | 44 +++++++++---------- .../mcumgr/os_mgmt_info/src/smp_test_util.c | 2 +- .../mgmt/mcumgr/settings_mgmt/src/main.c | 14 +++--- .../mcumgr/settings_mgmt/src/smp_test_util.c | 18 ++++---- .../subsys/mgmt/mcumgr/smp_version/src/main.c | 6 +-- .../mcumgr/smp_version/src/smp_test_util.c | 2 +- .../subsys/mgmt/mcumgr/zcbor_bulk/src/main.c | 22 +++++----- 16 files changed, 97 insertions(+), 93 deletions(-) diff --git a/tests/subsys/mgmt/mcumgr/cb_notifications/src/smp_test_util.c b/tests/subsys/mgmt/mcumgr/cb_notifications/src/smp_test_util.c index a20f948f30b..270f232af77 100644 --- a/tests/subsys/mgmt/mcumgr/cb_notifications/src/smp_test_util.c +++ b/tests/subsys/mgmt/mcumgr/cb_notifications/src/smp_test_util.c @@ -29,7 +29,7 @@ bool create_mcumgr_format_packet(zcbor_state_t *zse, uint8_t *buffer, uint8_t *o ok = zcbor_map_start_encode(zse, 2) && zcbor_tstr_put_lit(zse, "d") && - zcbor_tstr_put_term(zse, "some test data") && + zcbor_tstr_put_lit(zse, "some test data") && zcbor_map_end_encode(zse, 2); *buffer_size = (zse->payload_mut - buffer); diff --git a/tests/subsys/mgmt/mcumgr/fs_mgmt_hash_supported/src/main.c b/tests/subsys/mgmt/mcumgr/fs_mgmt_hash_supported/src/main.c index a5cafef589d..30575172a84 100644 --- a/tests/subsys/mgmt/mcumgr/fs_mgmt_hash_supported/src/main.c +++ b/tests/subsys/mgmt/mcumgr/fs_mgmt_hash_supported/src/main.c @@ -97,7 +97,7 @@ ZTEST(fs_mgmt_hash_supported, test_supported) /* Search expected type array for this type and update details */ zcbor_new_decode_state(state, 10, &nb->data[sizeof(struct smp_hdr)], - (nb->len - sizeof(struct smp_hdr)), 1); + (nb->len - sizeof(struct smp_hdr)), 1, NULL, 0); ok = zcbor_map_start_decode(state); diff --git a/tests/subsys/mgmt/mcumgr/mcumgr_client/src/img_gr_stub.c b/tests/subsys/mgmt/mcumgr/mcumgr_client/src/img_gr_stub.c index aea03935fe6..9b12fd7b2b0 100644 --- a/tests/subsys/mgmt/mcumgr/mcumgr_client/src/img_gr_stub.c +++ b/tests/subsys/mgmt/mcumgr/mcumgr_client/src/img_gr_stub.c @@ -120,9 +120,10 @@ void img_read_response(int count) zcbor_tstr_put_lit(zse, "slot") && zcbor_uint32_put(zse, image_dummy_info[i].slot_num) && zcbor_tstr_put_lit(zse, "version") && - zcbor_tstr_put_term(zse, image_dummy_info[i].version) && + zcbor_tstr_put_term(zse, image_dummy_info[i].version, + sizeof(image_dummy_info[i].version)) && - zcbor_tstr_put_term(zse, "hash") && + zcbor_tstr_put_lit(zse, "hash") && zcbor_bstr_encode_ptr(zse, image_dummy_info[i].hash, IMG_MGMT_DATA_SHA_LEN) && ZCBOR_ENCODE_FLAG(zse, "bootable", image_dummy_info[i].flags.bootable) && ZCBOR_ENCODE_FLAG(zse, "pending", image_dummy_info[i].flags.pending) && @@ -180,7 +181,8 @@ void img_state_write_verify(struct net_buf *nb) ZCBOR_MAP_DECODE_KEY_DECODER("hash", zcbor_bstr_decode, &hash) }; - zcbor_new_decode_state(zsd, ARRAY_SIZE(zsd), nb->data + sizeof(struct smp_hdr), nb->len, 1); + zcbor_new_decode_state(zsd, ARRAY_SIZE(zsd), nb->data + sizeof(struct smp_hdr), nb->len, 1, + NULL, 0); decoded = 0; /* Init buffer values */ @@ -231,7 +233,8 @@ void img_upload_init_verify(struct net_buf *nb) ZCBOR_MAP_DECODE_KEY_DECODER("sha", zcbor_bstr_decode, &sha) }; - zcbor_new_decode_state(zsd, ARRAY_SIZE(zsd), nb->data + sizeof(struct smp_hdr), nb->len, 1); + zcbor_new_decode_state(zsd, ARRAY_SIZE(zsd), nb->data + sizeof(struct smp_hdr), nb->len, 1, + NULL, 0); decoded = 0; /* Init buffer values */ diff --git a/tests/subsys/mgmt/mcumgr/mcumgr_client/src/main.c b/tests/subsys/mgmt/mcumgr/mcumgr_client/src/main.c index bf70f178fe7..c724c72c2cc 100644 --- a/tests/subsys/mgmt/mcumgr/mcumgr_client/src/main.c +++ b/tests/subsys/mgmt/mcumgr/mcumgr_client/src/main.c @@ -225,12 +225,12 @@ ZTEST(mcumgr_client, test_os_echo) smp_stub_set_rx_data_verify(NULL); smp_client_send_status_stub(MGMT_ERR_EOK); /* Test timeout */ - rc = os_mgmt_client_echo(&os_client, os_echo_test); + rc = os_mgmt_client_echo(&os_client, os_echo_test, sizeof(os_echo_test)); zassert_equal(MGMT_ERR_ETIMEOUT, rc, "Expected to receive %d response %d", MGMT_ERR_ETIMEOUT, rc); /* Test successfully operation */ smp_stub_set_rx_data_verify(os_echo_verify); - rc = os_mgmt_client_echo(&os_client, os_echo_test); + rc = os_mgmt_client_echo(&os_client, os_echo_test, sizeof(os_echo_test)); zassert_equal(MGMT_ERR_EOK, rc, "Expected to receive %d response %d", MGMT_ERR_EOK, rc); } diff --git a/tests/subsys/mgmt/mcumgr/mcumgr_client/src/os_gr_stub.c b/tests/subsys/mgmt/mcumgr/mcumgr_client/src/os_gr_stub.c index 888f00dba38..c7196874556 100644 --- a/tests/subsys/mgmt/mcumgr/mcumgr_client/src/os_gr_stub.c +++ b/tests/subsys/mgmt/mcumgr/mcumgr_client/src/os_gr_stub.c @@ -81,7 +81,8 @@ void os_echo_verify(struct net_buf *nb) ZCBOR_MAP_DECODE_KEY_DECODER("d", zcbor_tstr_decode, &echo_data) }; - zcbor_new_decode_state(zsd, ARRAY_SIZE(zsd), nb->data + sizeof(struct smp_hdr), nb->len, 1); + zcbor_new_decode_state(zsd, ARRAY_SIZE(zsd), nb->data + sizeof(struct smp_hdr), nb->len, 1, + NULL, 0); echo_data.len = 0; rc = zcbor_map_decode_bulk(zsd, list_res_decode, ARRAY_SIZE(list_res_decode), &decoded); diff --git a/tests/subsys/mgmt/mcumgr/os_mgmt_datetime/src/main.c b/tests/subsys/mgmt/mcumgr/os_mgmt_datetime/src/main.c index c3a3c71d2b2..47e8720cb63 100644 --- a/tests/subsys/mgmt/mcumgr/os_mgmt_datetime/src/main.c +++ b/tests/subsys/mgmt/mcumgr/os_mgmt_datetime/src/main.c @@ -191,7 +191,7 @@ ZTEST(os_mgmt_datetime_not_set, test_datetime_get_not_set_v1) /* Process received data by removing header */ (void)net_buf_pull(nb, sizeof(struct smp_hdr)); - zcbor_new_decode_state(zsd, 4, nb->data, nb->len, 1); + zcbor_new_decode_state(zsd, 4, nb->data, nb->len, 1, NULL, 0); ok = zcbor_map_decode_bulk(zsd, output_decode, ARRAY_SIZE(output_decode), &decoded) == 0; zassert_true(ok, "Expected decode to be successful"); @@ -253,7 +253,7 @@ ZTEST(os_mgmt_datetime_not_set, test_datetime_get_not_set_v2) /* Process received data by removing header */ (void)net_buf_pull(nb, sizeof(struct smp_hdr)); - zcbor_new_decode_state(zsd, 4, nb->data, nb->len, 1); + zcbor_new_decode_state(zsd, 4, nb->data, nb->len, 1, NULL, 0); ok = zcbor_map_decode_bulk(zsd, output_decode, ARRAY_SIZE(output_decode), &decoded) == 0; zassert_true(ok, "Expected decode to be successful"); @@ -318,7 +318,7 @@ ZTEST(os_mgmt_datetime_not_set, test_datetime_set_invalid_v1_1) /* Process received data by removing header */ (void)net_buf_pull(nb, sizeof(struct smp_hdr)); - zcbor_new_decode_state(zsd, 4, nb->data, nb->len, 1); + zcbor_new_decode_state(zsd, 4, nb->data, nb->len, 1, NULL, 0); ok = zcbor_map_decode_bulk(zsd, output_decode, ARRAY_SIZE(output_decode), &decoded) == 0; zassert_true(ok, "Expected decode to be successful"); @@ -365,7 +365,7 @@ ZTEST(os_mgmt_datetime_not_set, test_datetime_set_invalid_v1_1) /* Process received data by removing header */ (void)net_buf_pull(nb, sizeof(struct smp_hdr)); - zcbor_new_decode_state(zsd, 4, nb->data, nb->len, 1); + zcbor_new_decode_state(zsd, 4, nb->data, nb->len, 1, NULL, 0); ok = zcbor_map_decode_bulk(zsd, output_decode, ARRAY_SIZE(output_decode), &decoded) == 0; zassert_true(ok, "Expected decode to be successful"); @@ -428,7 +428,7 @@ ZTEST(os_mgmt_datetime_not_set, test_datetime_set_invalid_v1_2) /* Process received data by removing header */ (void)net_buf_pull(nb, sizeof(struct smp_hdr)); - zcbor_new_decode_state(zsd, 4, nb->data, nb->len, 1); + zcbor_new_decode_state(zsd, 4, nb->data, nb->len, 1, NULL, 0); ok = zcbor_map_decode_bulk(zsd, output_decode, ARRAY_SIZE(output_decode), &decoded) == 0; zassert_true(ok, "Expected decode to be successful"); @@ -475,7 +475,7 @@ ZTEST(os_mgmt_datetime_not_set, test_datetime_set_invalid_v1_2) /* Process received data by removing header */ (void)net_buf_pull(nb, sizeof(struct smp_hdr)); - zcbor_new_decode_state(zsd, 4, nb->data, nb->len, 1); + zcbor_new_decode_state(zsd, 4, nb->data, nb->len, 1, NULL, 0); ok = zcbor_map_decode_bulk(zsd, output_decode, ARRAY_SIZE(output_decode), &decoded) == 0; zassert_true(ok, "Expected decode to be successful"); @@ -538,7 +538,7 @@ ZTEST(os_mgmt_datetime_not_set, test_datetime_set_invalid_v1_3) /* Process received data by removing header */ (void)net_buf_pull(nb, sizeof(struct smp_hdr)); - zcbor_new_decode_state(zsd, 4, nb->data, nb->len, 1); + zcbor_new_decode_state(zsd, 4, nb->data, nb->len, 1, NULL, 0); ok = zcbor_map_decode_bulk(zsd, output_decode, ARRAY_SIZE(output_decode), &decoded) == 0; zassert_true(ok, "Expected decode to be successful"); @@ -585,7 +585,7 @@ ZTEST(os_mgmt_datetime_not_set, test_datetime_set_invalid_v1_3) /* Process received data by removing header */ (void)net_buf_pull(nb, sizeof(struct smp_hdr)); - zcbor_new_decode_state(zsd, 4, nb->data, nb->len, 1); + zcbor_new_decode_state(zsd, 4, nb->data, nb->len, 1, NULL, 0); ok = zcbor_map_decode_bulk(zsd, output_decode, ARRAY_SIZE(output_decode), &decoded) == 0; zassert_true(ok, "Expected decode to be successful"); @@ -648,7 +648,7 @@ ZTEST(os_mgmt_datetime_not_set, test_datetime_set_invalid_v2_1) /* Process received data by removing header */ (void)net_buf_pull(nb, sizeof(struct smp_hdr)); - zcbor_new_decode_state(zsd, 4, nb->data, nb->len, 1); + zcbor_new_decode_state(zsd, 4, nb->data, nb->len, 1, NULL, 0); ok = zcbor_map_decode_bulk(zsd, output_decode, ARRAY_SIZE(output_decode), &decoded) == 0; zassert_true(ok, "Expected decode to be successful"); @@ -695,7 +695,7 @@ ZTEST(os_mgmt_datetime_not_set, test_datetime_set_invalid_v2_1) /* Process received data by removing header */ (void)net_buf_pull(nb, sizeof(struct smp_hdr)); - zcbor_new_decode_state(zsd, 4, nb->data, nb->len, 1); + zcbor_new_decode_state(zsd, 4, nb->data, nb->len, 1, NULL, 0); ok = zcbor_map_decode_bulk(zsd, output_decode, ARRAY_SIZE(output_decode), &decoded) == 0; zassert_true(ok, "Expected decode to be successful"); @@ -760,7 +760,7 @@ ZTEST(os_mgmt_datetime_not_set, test_datetime_set_invalid_v2_2) /* Process received data by removing header */ (void)net_buf_pull(nb, sizeof(struct smp_hdr)); - zcbor_new_decode_state(zsd, 4, nb->data, nb->len, 1); + zcbor_new_decode_state(zsd, 4, nb->data, nb->len, 1, NULL, 0); ok = zcbor_map_decode_bulk(zsd, output_decode, ARRAY_SIZE(output_decode), &decoded) == 0; zassert_true(ok, "Expected decode to be successful"); @@ -807,7 +807,7 @@ ZTEST(os_mgmt_datetime_not_set, test_datetime_set_invalid_v2_2) /* Process received data by removing header */ (void)net_buf_pull(nb, sizeof(struct smp_hdr)); - zcbor_new_decode_state(zsd, 4, nb->data, nb->len, 1); + zcbor_new_decode_state(zsd, 4, nb->data, nb->len, 1, NULL, 0); ok = zcbor_map_decode_bulk(zsd, output_decode, ARRAY_SIZE(output_decode), &decoded) == 0; zassert_true(ok, "Expected decode to be successful"); @@ -872,7 +872,7 @@ ZTEST(os_mgmt_datetime_not_set, test_datetime_set_invalid_v2_3) /* Process received data by removing header */ (void)net_buf_pull(nb, sizeof(struct smp_hdr)); - zcbor_new_decode_state(zsd, 4, nb->data, nb->len, 1); + zcbor_new_decode_state(zsd, 4, nb->data, nb->len, 1, NULL, 0); ok = zcbor_map_decode_bulk(zsd, output_decode, ARRAY_SIZE(output_decode), &decoded) == 0; zassert_true(ok, "Expected decode to be successful"); @@ -919,7 +919,7 @@ ZTEST(os_mgmt_datetime_not_set, test_datetime_set_invalid_v2_3) /* Process received data by removing header */ (void)net_buf_pull(nb, sizeof(struct smp_hdr)); - zcbor_new_decode_state(zsd, 4, nb->data, nb->len, 1); + zcbor_new_decode_state(zsd, 4, nb->data, nb->len, 1, NULL, 0); ok = zcbor_map_decode_bulk(zsd, output_decode, ARRAY_SIZE(output_decode), &decoded) == 0; zassert_true(ok, "Expected decode to be successful"); @@ -984,7 +984,7 @@ ZTEST(os_mgmt_datetime_set, test_datetime_set_v1) /* Process received data by removing header */ (void)net_buf_pull(nb, sizeof(struct smp_hdr)); - zcbor_new_decode_state(zsd, 4, nb->data, nb->len, 1); + zcbor_new_decode_state(zsd, 4, nb->data, nb->len, 1, NULL, 0); ok = zcbor_map_decode_bulk(zsd, output_decode, ARRAY_SIZE(output_decode), &decoded) == 0; zassert_true(ok, "Expected decode to be successful"); @@ -1030,7 +1030,7 @@ ZTEST(os_mgmt_datetime_set, test_datetime_set_v1) /* Process received data by removing header */ (void)net_buf_pull(nb, sizeof(struct smp_hdr)); - zcbor_new_decode_state(zsd, 4, nb->data, nb->len, 1); + zcbor_new_decode_state(zsd, 4, nb->data, nb->len, 1, NULL, 0); ok = zcbor_map_decode_bulk(zsd, output_decode, ARRAY_SIZE(output_decode), &decoded) == 0; zassert_true(ok, "Expected decode to be successful"); @@ -1098,7 +1098,7 @@ ZTEST(os_mgmt_datetime_set, test_datetime_set_v2) /* Process received data by removing header */ (void)net_buf_pull(nb, sizeof(struct smp_hdr)); - zcbor_new_decode_state(zsd, 4, nb->data, nb->len, 1); + zcbor_new_decode_state(zsd, 4, nb->data, nb->len, 1, NULL, 0); ok = zcbor_map_decode_bulk(zsd, output_decode, ARRAY_SIZE(output_decode), &decoded) == 0; zassert_true(ok, "Expected decode to be successful"); @@ -1144,7 +1144,7 @@ ZTEST(os_mgmt_datetime_set, test_datetime_set_v2) /* Process received data by removing header */ (void)net_buf_pull(nb, sizeof(struct smp_hdr)); - zcbor_new_decode_state(zsd, 4, nb->data, nb->len, 1); + zcbor_new_decode_state(zsd, 4, nb->data, nb->len, 1, NULL, 0); ok = zcbor_map_decode_bulk(zsd, output_decode, ARRAY_SIZE(output_decode), &decoded) == 0; zassert_true(ok, "Expected decode to be successful"); @@ -1225,7 +1225,7 @@ ZTEST(os_mgmt_datetime_hook, test_datetime_set_valid_hook_v1) /* Process received data by removing header */ (void)net_buf_pull(nb, sizeof(struct smp_hdr)); - zcbor_new_decode_state(zsd, 4, nb->data, nb->len, 1); + zcbor_new_decode_state(zsd, 4, nb->data, nb->len, 1, NULL, 0); ok = zcbor_map_decode_bulk(zsd, output_decode, ARRAY_SIZE(output_decode), &decoded) == 0; zassert_true(ok, "Expected decode to be successful"); @@ -1287,7 +1287,7 @@ ZTEST(os_mgmt_datetime_hook, test_datetime_set_valid_hook_v1) /* Process received data by removing header */ (void)net_buf_pull(nb, sizeof(struct smp_hdr)); - zcbor_new_decode_state(zsd, 4, nb->data, nb->len, 1); + zcbor_new_decode_state(zsd, 4, nb->data, nb->len, 1, NULL, 0); ok = zcbor_map_decode_bulk(zsd, output_decode, ARRAY_SIZE(output_decode), &decoded) == 0; zassert_true(ok, "Expected decode to be successful"); @@ -1357,7 +1357,7 @@ ZTEST(os_mgmt_datetime_hook, test_datetime_set_valid_hook_v2) /* Process received data by removing header */ (void)net_buf_pull(nb, sizeof(struct smp_hdr)); - zcbor_new_decode_state(zsd, 4, nb->data, nb->len, 1); + zcbor_new_decode_state(zsd, 4, nb->data, nb->len, 1, NULL, 0); ok = zcbor_map_decode_bulk(zsd, output_decode, ARRAY_SIZE(output_decode), &decoded) == 0; zassert_true(ok, "Expected decode to be successful"); @@ -1418,7 +1418,7 @@ ZTEST(os_mgmt_datetime_hook, test_datetime_set_valid_hook_v2) /* Process received data by removing header */ (void)net_buf_pull(nb, sizeof(struct smp_hdr)); - zcbor_new_decode_state(zsd, 4, nb->data, nb->len, 1); + zcbor_new_decode_state(zsd, 4, nb->data, nb->len, 1, NULL, 0); ok = zcbor_map_decode_bulk(zsd, output_decode, ARRAY_SIZE(output_decode), &decoded) == 0; zassert_true(ok, "Expected decode to be successful"); diff --git a/tests/subsys/mgmt/mcumgr/os_mgmt_datetime/src/smp_test_util.c b/tests/subsys/mgmt/mcumgr/os_mgmt_datetime/src/smp_test_util.c index 927089c3ee3..d2b969999cd 100644 --- a/tests/subsys/mgmt/mcumgr/os_mgmt_datetime/src/smp_test_util.c +++ b/tests/subsys/mgmt/mcumgr/os_mgmt_datetime/src/smp_test_util.c @@ -49,9 +49,9 @@ bool create_mcumgr_datetime_set_packet_str(zcbor_state_t *zse, bool version2, co uint8_t *buffer, uint8_t *output_buffer, uint16_t *buffer_size) { - bool ok = zcbor_map_start_encode(zse, 2) && - zcbor_tstr_put_lit(zse, "datetime") && - zcbor_tstr_put_term(zse, data) && + bool ok = zcbor_map_start_encode(zse, 2) && + zcbor_tstr_put_lit(zse, "datetime") && + zcbor_tstr_put_term(zse, data, CONFIG_ZCBOR_MAX_STR_LEN) && zcbor_map_end_encode(zse, 2); *buffer_size = (zse->payload_mut - buffer); diff --git a/tests/subsys/mgmt/mcumgr/os_mgmt_info/src/build_date.c b/tests/subsys/mgmt/mcumgr/os_mgmt_info/src/build_date.c index 4af977895c3..5674e338dfa 100644 --- a/tests/subsys/mgmt/mcumgr/os_mgmt_info/src/build_date.c +++ b/tests/subsys/mgmt/mcumgr/os_mgmt_info/src/build_date.c @@ -121,7 +121,7 @@ ZTEST(os_mgmt_info_build_date, test_info_build_date_1_build_date) /* Process received data by removing header */ (void)net_buf_pull(nb, sizeof(struct smp_hdr)); - zcbor_new_decode_state(zsd, 3, nb->data, nb->len, 1); + zcbor_new_decode_state(zsd, 3, nb->data, nb->len, 1, NULL, 0); ok = zcbor_map_decode_bulk(zsd, output_decode, ARRAY_SIZE(output_decode), &decoded) == 0; @@ -197,7 +197,7 @@ ZTEST(os_mgmt_info_build_date, test_info_build_date_2_all) /* Process received data by removing header */ (void)net_buf_pull(nb, sizeof(struct smp_hdr)); - zcbor_new_decode_state(zsd, 3, nb->data, nb->len, 1); + zcbor_new_decode_state(zsd, 3, nb->data, nb->len, 1, NULL, 0); ok = zcbor_map_decode_bulk(zsd, output_decode, ARRAY_SIZE(output_decode), &decoded) == 0; diff --git a/tests/subsys/mgmt/mcumgr/os_mgmt_info/src/limited.c b/tests/subsys/mgmt/mcumgr/os_mgmt_info/src/limited.c index f8899734351..613402e1624 100644 --- a/tests/subsys/mgmt/mcumgr/os_mgmt_info/src/limited.c +++ b/tests/subsys/mgmt/mcumgr/os_mgmt_info/src/limited.c @@ -81,7 +81,7 @@ ZTEST(os_mgmt_info_limited, test_info_1_kernel_name) /* Process received data by removing header */ (void)net_buf_pull(nb, sizeof(struct smp_hdr)); - zcbor_new_decode_state(zsd, 3, nb->data, nb->len, 1); + zcbor_new_decode_state(zsd, 3, nb->data, nb->len, 1, NULL, 0); ok = zcbor_map_decode_bulk(zsd, output_decode, ARRAY_SIZE(output_decode), &decoded) == 0; @@ -147,7 +147,7 @@ ZTEST(os_mgmt_info_limited, test_info_2_all) /* Process received data by removing header */ (void)net_buf_pull(nb, sizeof(struct smp_hdr)); - zcbor_new_decode_state(zsd, 3, nb->data, nb->len, 1); + zcbor_new_decode_state(zsd, 3, nb->data, nb->len, 1, NULL, 0); /* Ensure only an error is received */ ok = zcbor_map_decode_bulk(zsd, output_decode, ARRAY_SIZE(output_decode), &decoded) == 0; @@ -155,7 +155,7 @@ ZTEST(os_mgmt_info_limited, test_info_2_all) zassert_true(ok, "Expected decode to be successful\n"); zassert_equal(decoded, 0, "Expected to receive 0 decoded zcbor element\n"); - zcbor_new_decode_state(zsd, 3, nb->data, nb->len, 1); + zcbor_new_decode_state(zsd, 3, nb->data, nb->len, 1, NULL, 0); ok = zcbor_map_decode_bulk(zsd, error_decode, ARRAY_SIZE(error_decode), &decoded) == 0; zassert_true(ok, "Expected decode to be successful\n"); diff --git a/tests/subsys/mgmt/mcumgr/os_mgmt_info/src/main.c b/tests/subsys/mgmt/mcumgr/os_mgmt_info/src/main.c index d07b8ed6d4d..bc86791b350 100644 --- a/tests/subsys/mgmt/mcumgr/os_mgmt_info/src/main.c +++ b/tests/subsys/mgmt/mcumgr/os_mgmt_info/src/main.c @@ -338,7 +338,7 @@ ZTEST(os_mgmt_info, test_info_2_kernel_name) /* Process received data by removing header */ (void)net_buf_pull(nb, sizeof(struct smp_hdr)); - zcbor_new_decode_state(zsd, 3, nb->data, nb->len, 1); + zcbor_new_decode_state(zsd, 3, nb->data, nb->len, 1, NULL, 0); ok = zcbor_map_decode_bulk(zsd, output_decode, ARRAY_SIZE(output_decode), &decoded) == 0; @@ -399,7 +399,7 @@ ZTEST(os_mgmt_info, test_info_3_node_name) /* Process received data by removing header */ (void)net_buf_pull(nb, sizeof(struct smp_hdr)); - zcbor_new_decode_state(zsd, 3, nb->data, nb->len, 1); + zcbor_new_decode_state(zsd, 3, nb->data, nb->len, 1, NULL, 0); ok = zcbor_map_decode_bulk(zsd, output_decode, ARRAY_SIZE(output_decode), &decoded) == 0; @@ -461,7 +461,7 @@ ZTEST(os_mgmt_info, test_info_4_kernel_release) /* Process received data by removing header */ (void)net_buf_pull(nb, sizeof(struct smp_hdr)); - zcbor_new_decode_state(zsd, 3, nb->data, nb->len, 1); + zcbor_new_decode_state(zsd, 3, nb->data, nb->len, 1, NULL, 0); ok = zcbor_map_decode_bulk(zsd, output_decode, ARRAY_SIZE(output_decode), &decoded) == 0; @@ -523,7 +523,7 @@ ZTEST(os_mgmt_info, test_info_5_kernel_version) /* Process received data by removing header */ (void)net_buf_pull(nb, sizeof(struct smp_hdr)); - zcbor_new_decode_state(zsd, 3, nb->data, nb->len, 1); + zcbor_new_decode_state(zsd, 3, nb->data, nb->len, 1, NULL, 0); ok = zcbor_map_decode_bulk(zsd, output_decode, ARRAY_SIZE(output_decode), &decoded) == 0; @@ -584,7 +584,7 @@ ZTEST(os_mgmt_info, test_info_6_machine) /* Process received data by removing header */ (void)net_buf_pull(nb, sizeof(struct smp_hdr)); - zcbor_new_decode_state(zsd, 3, nb->data, nb->len, 1); + zcbor_new_decode_state(zsd, 3, nb->data, nb->len, 1, NULL, 0); ok = zcbor_map_decode_bulk(zsd, output_decode, ARRAY_SIZE(output_decode), &decoded) == 0; @@ -645,7 +645,7 @@ ZTEST(os_mgmt_info, test_info_7_processor) /* Process received data by removing header */ (void)net_buf_pull(nb, sizeof(struct smp_hdr)); - zcbor_new_decode_state(zsd, 3, nb->data, nb->len, 1); + zcbor_new_decode_state(zsd, 3, nb->data, nb->len, 1, NULL, 0); ok = zcbor_map_decode_bulk(zsd, output_decode, ARRAY_SIZE(output_decode), &decoded) == 0; @@ -706,7 +706,7 @@ ZTEST(os_mgmt_info, test_info_8_platform) /* Process received data by removing header */ (void)net_buf_pull(nb, sizeof(struct smp_hdr)); - zcbor_new_decode_state(zsd, 3, nb->data, nb->len, 1); + zcbor_new_decode_state(zsd, 3, nb->data, nb->len, 1, NULL, 0); ok = zcbor_map_decode_bulk(zsd, output_decode, ARRAY_SIZE(output_decode), &decoded) == 0; @@ -778,7 +778,7 @@ ZTEST(os_mgmt_info, test_info_9_os) /* Process received data by removing header */ (void)net_buf_pull(nb, sizeof(struct smp_hdr)); - zcbor_new_decode_state(zsd, 3, nb->data, nb->len, 1); + zcbor_new_decode_state(zsd, 3, nb->data, nb->len, 1, NULL, 0); ok = zcbor_map_decode_bulk(zsd, output_decode, ARRAY_SIZE(output_decode), &decoded) == 0; @@ -839,7 +839,7 @@ ZTEST(os_mgmt_info, test_info_10_all) /* Process received data by removing header */ (void)net_buf_pull(nb, sizeof(struct smp_hdr)); - zcbor_new_decode_state(zsd, 3, nb->data, nb->len, 1); + zcbor_new_decode_state(zsd, 3, nb->data, nb->len, 1, NULL, 0); ok = zcbor_map_decode_bulk(zsd, output_decode, ARRAY_SIZE(output_decode), &decoded) == 0; @@ -914,7 +914,7 @@ ZTEST(os_mgmt_info, test_info_11_multi_1) /* Process received data by removing header */ (void)net_buf_pull(nb, sizeof(struct smp_hdr)); - zcbor_new_decode_state(zsd, 3, nb->data, nb->len, 1); + zcbor_new_decode_state(zsd, 3, nb->data, nb->len, 1, NULL, 0); ok = zcbor_map_decode_bulk(zsd, output_decode, ARRAY_SIZE(output_decode), &decoded) == 0; @@ -979,7 +979,7 @@ ZTEST(os_mgmt_info, test_info_12_multi_2) /* Process received data by removing header */ (void)net_buf_pull(nb, sizeof(struct smp_hdr)); - zcbor_new_decode_state(zsd, 3, nb->data, nb->len, 1); + zcbor_new_decode_state(zsd, 3, nb->data, nb->len, 1, NULL, 0); ok = zcbor_map_decode_bulk(zsd, output_decode, ARRAY_SIZE(output_decode), &decoded) == 0; @@ -1051,7 +1051,7 @@ ZTEST(os_mgmt_info, test_info_13_invalid_1) /* Process received data by removing header */ (void)net_buf_pull(nb, sizeof(struct smp_hdr)); - zcbor_new_decode_state(zsd, 3, nb->data, nb->len, 1); + zcbor_new_decode_state(zsd, 3, nb->data, nb->len, 1, NULL, 0); /* Ensure only an error is received */ ok = zcbor_map_decode_bulk(zsd, output_decode, ARRAY_SIZE(output_decode), &decoded) == 0; @@ -1059,7 +1059,7 @@ ZTEST(os_mgmt_info, test_info_13_invalid_1) zassert_true(ok, "Expected decode to be successful\n"); zassert_equal(decoded, 0, "Expected to receive 0 decoded zcbor element\n"); - zcbor_new_decode_state(zsd, 3, nb->data, nb->len, 1); + zcbor_new_decode_state(zsd, 3, nb->data, nb->len, 1, NULL, 0); ok = zcbor_map_decode_bulk(zsd, error_decode, ARRAY_SIZE(error_decode), &decoded) == 0; zassert_true(ok, "Expected decode to be successful\n"); @@ -1122,7 +1122,7 @@ ZTEST(os_mgmt_info, test_info_14_invalid_2) /* Process received data by removing header */ (void)net_buf_pull(nb, sizeof(struct smp_hdr)); - zcbor_new_decode_state(zsd, 3, nb->data, nb->len, 1); + zcbor_new_decode_state(zsd, 3, nb->data, nb->len, 1, NULL, 0); /* Ensure only an error is received */ ok = zcbor_map_decode_bulk(zsd, output_decode, ARRAY_SIZE(output_decode), &decoded) == 0; @@ -1130,7 +1130,7 @@ ZTEST(os_mgmt_info, test_info_14_invalid_2) zassert_true(ok, "Expected decode to be successful\n"); zassert_equal(decoded, 0, "Expected to receive 0 decoded zcbor element\n"); - zcbor_new_decode_state(zsd, 3, nb->data, nb->len, 1); + zcbor_new_decode_state(zsd, 3, nb->data, nb->len, 1, NULL, 0); ok = zcbor_map_decode_bulk(zsd, error_decode, ARRAY_SIZE(error_decode), &decoded) == 0; zassert_true(ok, "Expected decode to be successful\n"); @@ -1199,7 +1199,7 @@ ZTEST(os_mgmt_info_custom_os, test_info_os_custom) /* Process received data by removing header */ (void)net_buf_pull(nb, sizeof(struct smp_hdr)); - zcbor_new_decode_state(zsd, 3, nb->data, nb->len, 1); + zcbor_new_decode_state(zsd, 3, nb->data, nb->len, 1, NULL, 0); ok = zcbor_map_decode_bulk(zsd, output_decode, ARRAY_SIZE(output_decode), &decoded) == 0; @@ -1260,7 +1260,7 @@ ZTEST(os_mgmt_info_custom_os_disabled, test_info_os_custom_disabled) /* Process received data by removing header */ (void)net_buf_pull(nb, sizeof(struct smp_hdr)); - zcbor_new_decode_state(zsd, 3, nb->data, nb->len, 1); + zcbor_new_decode_state(zsd, 3, nb->data, nb->len, 1, NULL, 0); ok = zcbor_map_decode_bulk(zsd, output_decode, ARRAY_SIZE(output_decode), &decoded) == 0; @@ -1333,7 +1333,7 @@ ZTEST(os_mgmt_info_custom_cmd, test_info_cmd_custom) /* Process received data by removing header */ (void)net_buf_pull(nb, sizeof(struct smp_hdr)); - zcbor_new_decode_state(zsd, 3, nb->data, nb->len, 1); + zcbor_new_decode_state(zsd, 3, nb->data, nb->len, 1, NULL, 0); ok = zcbor_map_decode_bulk(zsd, output_decode, ARRAY_SIZE(output_decode), &decoded) == 0; @@ -1399,14 +1399,14 @@ ZTEST(os_mgmt_info_custom_cmd_disabled, test_info_cmd_custom_disabled) /* Process received data by removing header */ (void)net_buf_pull(nb, sizeof(struct smp_hdr)); - zcbor_new_decode_state(zsd, 3, nb->data, nb->len, 1); + zcbor_new_decode_state(zsd, 3, nb->data, nb->len, 1, NULL, 0); ok = zcbor_map_decode_bulk(zsd, output_decode, ARRAY_SIZE(output_decode), &decoded) == 0; zassert_true(ok, "Expected decode to be successful\n"); zassert_equal(decoded, 0, "Expected to receive 0 decoded zcbor element\n"); - zcbor_new_decode_state(zsd, 3, nb->data, nb->len, 1); + zcbor_new_decode_state(zsd, 3, nb->data, nb->len, 1, NULL, 0); ok = zcbor_map_decode_bulk(zsd, error_decode, ARRAY_SIZE(error_decode), &decoded) == 0; zassert_true(ok, "Expected decode to be successful\n"); @@ -1468,14 +1468,14 @@ ZTEST(os_mgmt_info_custom_cmd_disabled_verify, test_info_cmd_custom_disabled) /* Process received data by removing header */ (void)net_buf_pull(nb, sizeof(struct smp_hdr)); - zcbor_new_decode_state(zsd, 3, nb->data, nb->len, 1); + zcbor_new_decode_state(zsd, 3, nb->data, nb->len, 1, NULL, 0); ok = zcbor_map_decode_bulk(zsd, output_decode, ARRAY_SIZE(output_decode), &decoded) == 0; zassert_true(ok, "Expected decode to be successful\n"); zassert_equal(decoded, 0, "Expected to receive 0 decoded zcbor element\n"); - zcbor_new_decode_state(zsd, 3, nb->data, nb->len, 1); + zcbor_new_decode_state(zsd, 3, nb->data, nb->len, 1, NULL, 0); ok = zcbor_map_decode_bulk(zsd, error_decode, ARRAY_SIZE(error_decode), &decoded) == 0; zassert_true(ok, "Expected decode to be successful\n"); diff --git a/tests/subsys/mgmt/mcumgr/os_mgmt_info/src/smp_test_util.c b/tests/subsys/mgmt/mcumgr/os_mgmt_info/src/smp_test_util.c index c1dcded0ff6..b76ac1ad623 100644 --- a/tests/subsys/mgmt/mcumgr/os_mgmt_info/src/smp_test_util.c +++ b/tests/subsys/mgmt/mcumgr/os_mgmt_info/src/smp_test_util.c @@ -31,7 +31,7 @@ bool create_mcumgr_format_packet(zcbor_state_t *zse, const uint8_t *format, uint ok = zcbor_map_start_encode(zse, 2) && zcbor_tstr_put_lit(zse, "format") && - zcbor_tstr_put_term(zse, format) && + zcbor_tstr_put_term(zse, format, CONFIG_ZCBOR_MAX_STR_LEN) && zcbor_map_end_encode(zse, 2); *buffer_size = (zse->payload_mut - buffer); diff --git a/tests/subsys/mgmt/mcumgr/settings_mgmt/src/main.c b/tests/subsys/mgmt/mcumgr/settings_mgmt/src/main.c index 745fa333790..869a4f750d9 100644 --- a/tests/subsys/mgmt/mcumgr/settings_mgmt/src/main.c +++ b/tests/subsys/mgmt/mcumgr/settings_mgmt/src/main.c @@ -487,7 +487,7 @@ ZTEST(settings_mgmt, test_set_read) zassert_equal(smp_header->nh_version, 1, "SMP header version mismatch"); /* Get the response value to compare */ - zcbor_new_decode_state(zsd, 4, nb->data, nb->len, 1); + zcbor_new_decode_state(zsd, 4, nb->data, nb->len, 1, NULL, 0); ok = zcbor_map_decode_bulk(zsd, output_decode, ARRAY_SIZE(output_decode), &decoded) == 0; zassert_true(ok, "Expected decode to be successful"); @@ -590,7 +590,7 @@ ZTEST(settings_mgmt, test_read_max_size) zassert_equal(smp_header->nh_version, 1, "SMP header version mismatch"); /* Get the response value to compare */ - zcbor_new_decode_state(zsd, 4, nb->data, nb->len, 1); + zcbor_new_decode_state(zsd, 4, nb->data, nb->len, 1, NULL, 0); ok = zcbor_map_decode_bulk(zsd, output_decode, ARRAY_SIZE(output_decode), &decoded) == 0; zassert_true(ok, "Expected decode to be successful"); zassert_equal(decoded, 2, "Expected to receive 2 decoded zcbor elements"); @@ -745,7 +745,7 @@ ZTEST(settings_mgmt, test_set_disallowed) zassert_equal(smp_header->nh_version, 1, "SMP header version mismatch"); /* Get the response value to compare */ - zcbor_new_decode_state(zsd, 4, nb->data, nb->len, 1); + zcbor_new_decode_state(zsd, 4, nb->data, nb->len, 1, NULL, 0); ok = zcbor_map_decode_bulk(zsd, output_decode, ARRAY_SIZE(output_decode), &decoded) == 0; zassert_true(ok, "Expected decode to be successful"); zassert_equal(decoded, 1, "Expected to receive 1 decoded zcbor element"); @@ -875,7 +875,7 @@ ZTEST(settings_mgmt, test_set_disallowed) zassert_equal(smp_header->nh_version, 1, "SMP header version mismatch"); /* Get the response value to compare */ - zcbor_new_decode_state(zsd, 4, nb->data, nb->len, 1); + zcbor_new_decode_state(zsd, 4, nb->data, nb->len, 1, NULL, 0); ok = zcbor_map_decode_bulk(zsd, output_decode, ARRAY_SIZE(output_decode), &decoded) == 0; zassert_true(ok, "Expected decode to be successful"); zassert_equal(decoded, 1, "Expected to receive 1 decoded zcbor element"); @@ -1147,7 +1147,7 @@ ZTEST(settings_mgmt, test_delete) zassert_equal(smp_header->nh_version, 1, "SMP header version mismatch"); /* Get the response value to compare */ - zcbor_new_decode_state(zsd, 4, nb->data, nb->len, 1); + zcbor_new_decode_state(zsd, 4, nb->data, nb->len, 1, NULL, 0); ok = zcbor_map_decode_bulk(zsd, output_decode, ARRAY_SIZE(output_decode), &decoded) == 0; zassert_true(ok, "Expected decode to be successful"); zassert_equal(decoded, 1, "Expected to receive 1 decoded zcbor element"); @@ -1274,7 +1274,7 @@ ZTEST(settings_mgmt, test_delete) zassert_equal(smp_header->nh_version, 1, "SMP header version mismatch"); /* Get the response value to compare */ - zcbor_new_decode_state(zsd, 4, nb->data, nb->len, 1); + zcbor_new_decode_state(zsd, 4, nb->data, nb->len, 1, NULL, 0); ok = zcbor_map_decode_bulk(zsd, output_decode, ARRAY_SIZE(output_decode), &decoded) == 0; zassert_true(ok, "Expected decode to be successful"); zassert_equal(decoded, 1, "Expected to receive 1 decoded zcbor element"); @@ -1519,7 +1519,7 @@ ZTEST(settings_mgmt, test_delete) zassert_equal(smp_header->nh_version, 1, "SMP header version mismatch"); /* Get the response value to compare */ - zcbor_new_decode_state(zsd, 4, nb->data, nb->len, 1); + zcbor_new_decode_state(zsd, 4, nb->data, nb->len, 1, NULL, 0); ok = zcbor_map_decode_bulk(zsd, output_decode, ARRAY_SIZE(output_decode), &decoded) == 0; zassert_true(ok, "Expected decode to be successful"); zassert_equal(decoded, 1, "Expected to receive 1 decoded zcbor element"); diff --git a/tests/subsys/mgmt/mcumgr/settings_mgmt/src/smp_test_util.c b/tests/subsys/mgmt/mcumgr/settings_mgmt/src/smp_test_util.c index 63b91151797..dcabd0d08c3 100644 --- a/tests/subsys/mgmt/mcumgr/settings_mgmt/src/smp_test_util.c +++ b/tests/subsys/mgmt/mcumgr/settings_mgmt/src/smp_test_util.c @@ -31,7 +31,7 @@ bool create_settings_mgmt_read_packet(zcbor_state_t *zse, uint8_t *buffer, uint8 ok = zcbor_map_start_encode(zse, 2) && zcbor_tstr_put_lit(zse, "name") && - zcbor_tstr_put_term(zse, name) && + zcbor_tstr_put_term(zse, name, CONFIG_ZCBOR_MAX_STR_LEN) && (max_size == 0 || (zcbor_tstr_put_lit(zse, "max_size") && zcbor_uint32_put(zse, max_size))) && zcbor_map_end_encode(zse, 2); @@ -51,11 +51,11 @@ bool create_settings_mgmt_write_packet(zcbor_state_t *zse, uint8_t *buffer, uint { bool ok; - ok = zcbor_map_start_encode(zse, 2) && - zcbor_tstr_put_lit(zse, "name") && - zcbor_tstr_put_term(zse, name) && - zcbor_tstr_put_lit(zse, "val") && - zcbor_bstr_encode_ptr(zse, val, val_size) && + ok = zcbor_map_start_encode(zse, 2) && + zcbor_tstr_put_lit(zse, "name") && + zcbor_tstr_put_term(zse, name, CONFIG_ZCBOR_MAX_STR_LEN) && + zcbor_tstr_put_lit(zse, "val") && + zcbor_bstr_encode_ptr(zse, val, val_size) && zcbor_map_end_encode(zse, 2); *buffer_size = (zse->payload_mut - buffer); @@ -72,9 +72,9 @@ bool create_settings_mgmt_delete_packet(zcbor_state_t *zse, uint8_t *buffer, { bool ok; - ok = zcbor_map_start_encode(zse, 2) && - zcbor_tstr_put_lit(zse, "name") && - zcbor_tstr_put_term(zse, name) && + ok = zcbor_map_start_encode(zse, 2) && + zcbor_tstr_put_lit(zse, "name") && + zcbor_tstr_put_term(zse, name, CONFIG_ZCBOR_MAX_STR_LEN) && zcbor_map_end_encode(zse, 2); *buffer_size = (zse->payload_mut - buffer); diff --git a/tests/subsys/mgmt/mcumgr/smp_version/src/main.c b/tests/subsys/mgmt/mcumgr/smp_version/src/main.c index 8676678336e..ed596ae964e 100644 --- a/tests/subsys/mgmt/mcumgr/smp_version/src/main.c +++ b/tests/subsys/mgmt/mcumgr/smp_version/src/main.c @@ -155,7 +155,7 @@ ZTEST(smp_version, test_legacy_command) zassert_equal(smp_header->nh_version, LEGACY_VERSION, "Expected response header version mismatch"); - zcbor_new_decode_state(zsd, 4, nb->data, nb->len, 1); + zcbor_new_decode_state(zsd, 4, nb->data, nb->len, 1, NULL, 0); ok = zcbor_map_decode_bulk(zsd, output_decode, ARRAY_SIZE(output_decode), &decoded) == 0; zassert_true(ok, "Expected decode to be successful"); @@ -242,7 +242,7 @@ ZTEST(smp_version, test_current_command) zassert_equal(smp_header->nh_version, CURRENT_VERSION, "Expected response header version mismatch"); - zcbor_new_decode_state(zsd, 4, nb->data, nb->len, 1); + zcbor_new_decode_state(zsd, 4, nb->data, nb->len, 1, NULL, 0); ok = zcbor_map_decode_bulk(zsd, output_decode, ARRAY_SIZE(output_decode), &decoded) == 0; zassert_true(ok, "Expected decode to be successful"); @@ -328,7 +328,7 @@ ZTEST(smp_version, test_new_command) zassert_equal(smp_header->nh_version, CURRENT_VERSION, "Expected response header version mismatch"); - zcbor_new_decode_state(zsd, 4, nb->data, nb->len, 1); + zcbor_new_decode_state(zsd, 4, nb->data, nb->len, 1, NULL, 0); ok = zcbor_map_decode_bulk(zsd, output_decode, ARRAY_SIZE(output_decode), &decoded) == 0; zassert_true(ok, "Expected decode to be successful"); diff --git a/tests/subsys/mgmt/mcumgr/smp_version/src/smp_test_util.c b/tests/subsys/mgmt/mcumgr/smp_version/src/smp_test_util.c index e93ad69ff2a..96d97a6b6fa 100644 --- a/tests/subsys/mgmt/mcumgr/smp_version/src/smp_test_util.c +++ b/tests/subsys/mgmt/mcumgr/smp_version/src/smp_test_util.c @@ -32,7 +32,7 @@ bool create_mcumgr_format_packet(zcbor_state_t *zse, const uint8_t *format, uint ok = zcbor_map_start_encode(zse, 2) && zcbor_tstr_put_lit(zse, "format") && - zcbor_tstr_put_term(zse, format) && + zcbor_tstr_put_term(zse, format, CONFIG_ZCBOR_MAX_STR_LEN) && zcbor_map_end_encode(zse, 2); *buffer_size = (zse->payload_mut - buffer); diff --git a/tests/subsys/mgmt/mcumgr/zcbor_bulk/src/main.c b/tests/subsys/mgmt/mcumgr/zcbor_bulk/src/main.c index e50dc8fe51f..b1d3d79b30a 100644 --- a/tests/subsys/mgmt/mcumgr/zcbor_bulk/src/main.c +++ b/tests/subsys/mgmt/mcumgr/zcbor_bulk/src/main.c @@ -60,7 +60,7 @@ ZTEST(zcbor_bulk, test_correct) zassert_true(ok, "Expected to be successful in encoding test pattern"); - zcbor_new_decode_state(zsd, 4, buffer, ARRAY_SIZE(buffer), 1); + zcbor_new_decode_state(zsd, 4, buffer, ARRAY_SIZE(buffer), 1, NULL, 0); int rc = zcbor_map_decode_bulk(zsd, dm, ARRAY_SIZE(dm), &decoded); @@ -101,7 +101,7 @@ ZTEST(zcbor_bulk, test_correct_out_of_order) zassert_true(ok, "Expected to be successful in encoding test pattern"); - zcbor_new_decode_state(zsd, 4, buffer, ARRAY_SIZE(buffer), 1); + zcbor_new_decode_state(zsd, 4, buffer, ARRAY_SIZE(buffer), 1, NULL, 0); int rc = zcbor_map_decode_bulk(zsd, dm, ARRAY_SIZE(dm), &decoded); @@ -140,7 +140,7 @@ ZTEST(zcbor_bulk, test_not_map) zassert_true(ok, "Expected to be successful in encoding test pattern"); - zcbor_new_decode_state(zsd, 4, buffer, ARRAY_SIZE(buffer), 1); + zcbor_new_decode_state(zsd, 4, buffer, ARRAY_SIZE(buffer), 1, NULL, 0); int rc = zcbor_map_decode_bulk(zsd, dm, ARRAY_SIZE(dm), &decoded); @@ -175,7 +175,7 @@ ZTEST(zcbor_bulk, test_bad_type) zassert_true(ok, "Expected to be successful in encoding test pattern"); - zcbor_new_decode_state(zsd, 4, buffer, ARRAY_SIZE(buffer), 1); + zcbor_new_decode_state(zsd, 4, buffer, ARRAY_SIZE(buffer), 1, NULL, 0); int rc = zcbor_map_decode_bulk(zsd, dm, ARRAY_SIZE(dm), &decoded); @@ -211,7 +211,7 @@ ZTEST(zcbor_bulk, test_bad_type_2) zcbor_tstr_put_lit(zsd, "bool val") && zcbor_true_put(zsd) && zcbor_map_end_encode(zsd, 10); - zcbor_new_decode_state(zsd, 4, buffer, ARRAY_SIZE(buffer), 1); + zcbor_new_decode_state(zsd, 4, buffer, ARRAY_SIZE(buffer), 1, NULL, 0); int rc = zcbor_map_decode_bulk(zsd, dm, ARRAY_SIZE(dm), &decoded); @@ -252,7 +252,7 @@ ZTEST(zcbor_bulk, test_bad_type_encoded) zassert_true(ok, "Expected to be successful in encoding test pattern"); - zcbor_new_decode_state(zsd, 4, buffer, ARRAY_SIZE(buffer), 1); + zcbor_new_decode_state(zsd, 4, buffer, ARRAY_SIZE(buffer), 1, NULL, 0); int rc = zcbor_map_decode_bulk(zsd, dm, ARRAY_SIZE(dm), &decoded); @@ -287,7 +287,7 @@ ZTEST(zcbor_bulk, test_duplicate) zcbor_tstr_put_lit(zsd, "hello") && zcbor_tstr_put_lit(zsd, "world") && zcbor_map_end_encode(zsd, 10); - zcbor_new_decode_state(zsd, 4, buffer, ARRAY_SIZE(buffer), 1); + zcbor_new_decode_state(zsd, 4, buffer, ARRAY_SIZE(buffer), 1, NULL, 0); int rc = zcbor_map_decode_bulk(zsd, dm, ARRAY_SIZE(dm), &decoded); @@ -366,7 +366,7 @@ ZTEST(zcbor_bulk, test_map_in_map_correct) zassert_true(ok, "Expected to be successful in encoding test pattern"); - zcbor_new_decode_state(zsd, 4, buffer, ARRAY_SIZE(buffer), 1); + zcbor_new_decode_state(zsd, 4, buffer, ARRAY_SIZE(buffer), 1, NULL, 0); int rc = zcbor_map_decode_bulk(zsd, dm, ARRAY_SIZE(dm), &decoded); @@ -445,7 +445,7 @@ ZTEST(zcbor_bulk, test_map_in_map_bad) zassert_true(ok, "Expected to be successful in encoding test pattern"); - zcbor_new_decode_state(zsd, 4, buffer, ARRAY_SIZE(buffer), 1); + zcbor_new_decode_state(zsd, 4, buffer, ARRAY_SIZE(buffer), 1, NULL, 0); int rc = zcbor_map_decode_bulk(zsd, dm, ARRAY_SIZE(dm), &decoded); @@ -486,7 +486,7 @@ ZTEST(zcbor_bulk, test_key_found) zassert_true(ok, "Expected to be successful in encoding test pattern"); - zcbor_new_decode_state(zsd, 4, buffer, ARRAY_SIZE(buffer), 1); + zcbor_new_decode_state(zsd, 4, buffer, ARRAY_SIZE(buffer), 1, NULL, 0); int rc = zcbor_map_decode_bulk(zsd, dm, ARRAY_SIZE(dm), &decoded); @@ -528,7 +528,7 @@ ZTEST(zcbor_bulk, test_reset) zassert_true(ok, "Expected to be successful in encoding test pattern"); - zcbor_new_decode_state(zsd, 4, buffer, ARRAY_SIZE(buffer), 1); + zcbor_new_decode_state(zsd, 4, buffer, ARRAY_SIZE(buffer), 1, NULL, 0); int rc = zcbor_map_decode_bulk(zsd, dm, ARRAY_SIZE(dm), &decoded); From 0176a27474e029bb11e64c5235b4a33cc8bfdb96 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C3=98yvind=20R=C3=B8nningstad?= Date: Wed, 24 Jan 2024 15:19:41 +0100 Subject: [PATCH 2832/3723] doc: Add release notes and migration guide for zcbor 0.8.0 MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit A short release note referring to the official release notes, and a migration guide with the most likely changes that need to be made. Signed-off-by: Øyvind Rønningstad --- doc/releases/migration-guide-3.6.rst | 27 +++++++++++++++++++++++++++ doc/releases/release-notes-3.6.rst | 14 ++++++++++++++ 2 files changed, 41 insertions(+) diff --git a/doc/releases/migration-guide-3.6.rst b/doc/releases/migration-guide-3.6.rst index fc6982c97d9..af7c9c7c444 100644 --- a/doc/releases/migration-guide-3.6.rst +++ b/doc/releases/migration-guide-3.6.rst @@ -430,6 +430,33 @@ Networking cannot be accessed from usermode thread. This means that the API calls will need to made from supervisor mode thread. +zcbor +===== + +* If you have zcbor-generated code that relies on the zcbor libraries through Zephyr, you must + regenerate the files using zcbor 0.8.0. Note that the names of generated types and members has + been overhauled, so the code using the generated code must likely be changed. + For example: + + * Leading single underscores and all double underscores are largely gone, + * Names sometimes gain suffixes like ``_m`` or ``_l`` for disambiguation. + * All enum (choice) names have now gained a ``_c`` suffix, so the enum name no longer matches + the corresponding member name exactly (because this broke C++ namespace rules). + +* The function :c:func:`zcbor_new_state`, :c:func:`zcbor_new_decode_state` and the macro + :c:macro:`ZCBOR_STATE_D` have gained new parameters related to decoding of unordered maps. + Unless you are using that new functionality, these can all be set to NULL or 0. + +* The functions :c:func:`zcbor_bstr_put_term` and :c:func:`zcbor_tstr_put_term` have gained a new + parameter ``maxlen``, referring to the maximum length of the parameter ``str``. + This parameter is passed directly to :c:func:`strnlen` under the hood. + +* The function :c:func:`zcbor_tag_encode` has been renamed to :c:func:`zcbor_tag_put`. + +* Printing has been changed significantly, e.g. :c:func:`zcbor_print` is now called + :c:func:`zcbor_log`, and :c:func:`zcbor_trace` with no parameters is gone, and in its place are + :c:func:`zcbor_trace_file` and :c:func:`zcbor_trace`, both of which take a ``state`` parameter. + Other Subsystems ================ diff --git a/doc/releases/release-notes-3.6.rst b/doc/releases/release-notes-3.6.rst index 9d95857901e..ad3bfc01703 100644 --- a/doc/releases/release-notes-3.6.rst +++ b/doc/releases/release-notes-3.6.rst @@ -372,6 +372,20 @@ MCUboot Nanopb ****** +zcbor +***** + +zcbor has been updated from 0.7.0 to 0.8.0. +Full release notes can be found at: +https://github.com/zephyrproject-rtos/zcbor/blob/0.8.0/RELEASE_NOTES.md + +Highlights: + +* Add support for unordered maps +* Performance improvements +* Naming improvements for generated code +* Bugfixes + LVGL **** From 80f7d518c604c12d36f858fb91d4453c27721172 Mon Sep 17 00:00:00 2001 From: Jean Nanchen Date: Mon, 15 Jan 2024 09:11:07 +0000 Subject: [PATCH 2833/3723] modbus: Remove mode reset in modbus_disable function Remove reset mode in modbus_disable. Signed-off-by: Jean Nanchen --- subsys/modbus/modbus_core.c | 1 - 1 file changed, 1 deletion(-) diff --git a/subsys/modbus/modbus_core.c b/subsys/modbus/modbus_core.c index 777887f2275..b5c9df25398 100644 --- a/subsys/modbus/modbus_core.c +++ b/subsys/modbus/modbus_core.c @@ -398,7 +398,6 @@ int modbus_disable(const uint8_t iface) k_work_cancel_sync(&ctx->server_work, &work_sync); ctx->rxwait_to = 0; ctx->unit_id = 0; - ctx->mode = MODBUS_MODE_RTU; ctx->mbs_user_cb = NULL; atomic_clear_bit(&ctx->state, MODBUS_STATE_CONFIGURED); From c8dfdda02759bb2371c3238eba6ba05e4614bd79 Mon Sep 17 00:00:00 2001 From: Daniel DeGrasse Date: Fri, 19 Jan 2024 23:20:11 +0000 Subject: [PATCH 2834/3723] drivers: i2s: i2s_mcux_flexcomm: support additional channels and formats Add support for more than 2 I2S channels to the I2S Flexcomm driver. Additionally, remove comment stating I2S PCM and Left justified formats are not supported, as these formats are now validated to function correctly. Signed-off-by: Daniel DeGrasse --- drivers/i2s/i2s_mcux_flexcomm.c | 91 +++++++++++++++++++-------------- 1 file changed, 53 insertions(+), 38 deletions(-) diff --git a/drivers/i2s/i2s_mcux_flexcomm.c b/drivers/i2s/i2s_mcux_flexcomm.c index 24fb0873a82..ab61097c023 100644 --- a/drivers/i2s/i2s_mcux_flexcomm.c +++ b/drivers/i2s/i2s_mcux_flexcomm.c @@ -75,16 +75,24 @@ static int i2s_mcux_flexcomm_cfg_convert(uint32_t base_frequency, I2S_TxGetDefaultConfig(fsl_cfg); } - /* Support single channel pair */ - if (i2s_cfg->channels == 0 || i2s_cfg->channels > 2) { - LOG_ERR("unsupported number of channels"); - return -EINVAL; + fsl_cfg->dataLength = i2s_cfg->word_size; + if ((i2s_cfg->format & I2S_FMT_DATA_FORMAT_MASK) == + I2S_FMT_DATA_FORMAT_I2S) { + /* Classic I2S. We always use 2 channels */ + fsl_cfg->frameLength = 2 * i2s_cfg->word_size; + } else { + fsl_cfg->frameLength = i2s_cfg->channels * i2s_cfg->word_size; } - fsl_cfg->oneChannel = (i2s_cfg->channels == 1); + if (fsl_cfg->dataLength < 4 || fsl_cfg->dataLength > 32) { + LOG_ERR("Unsupported data length"); + return -EINVAL; + } - fsl_cfg->dataLength = i2s_cfg->word_size; - fsl_cfg->frameLength = i2s_cfg->channels * i2s_cfg->word_size; + if (fsl_cfg->frameLength < 4 || fsl_cfg->frameLength > 2048) { + LOG_ERR("Unsupported frame length"); + return -EINVAL; + } /* Set master/slave configuration */ switch (i2s_cfg->options & (I2S_OPT_BIT_CLK_SLAVE | @@ -105,11 +113,6 @@ static int i2s_mcux_flexcomm_cfg_convert(uint32_t base_frequency, break; } - /* - * Set format. Zephyr choose arbitrary subset of possible - * formats, the mapping below is not tested for anything - * but classic mode and is not guaranteed to be correct. - */ switch (i2s_cfg->format & I2S_FMT_DATA_FORMAT_MASK) { case I2S_FMT_DATA_FORMAT_I2S: fsl_cfg->mode = kI2S_ModeI2sClassic; @@ -126,10 +129,6 @@ static int i2s_mcux_flexcomm_cfg_convert(uint32_t base_frequency, fsl_cfg->mode = kI2S_ModeDspWs50; fsl_cfg->wsPol = true; break; - case I2S_FMT_DATA_FORMAT_RIGHT_JUSTIFIED: - fsl_cfg->mode = kI2S_ModeDspWs50; - fsl_cfg->wsPol = true; - break; default: LOG_ERR("Unsupported I2S data format"); return -EINVAL; @@ -191,13 +190,10 @@ static int i2s_mcux_configure(const struct device *dev, enum i2s_dir dir, { const struct i2s_mcux_config *cfg = dev->config; struct i2s_mcux_data *dev_data = dev->data; - I2S_Type *base = cfg->base; struct stream *stream; uint32_t base_frequency; i2s_config_t fsl_cfg; int result; - uint8_t bits_per_word = 0; - uint8_t bytes_per_word = 0; if (dir == I2S_DIR_RX) { stream = &dev_data->rx; @@ -261,27 +257,46 @@ static int i2s_mcux_configure(const struct device *dev, enum i2s_dir dir, I2S_TxInit(cfg->base, &fsl_cfg); } - /* Data length in bits */ - bits_per_word = (uint8_t)(((base->CFG1 & I2S_CFG1_DATALEN_MASK) >> - I2S_CFG1_DATALEN_SHIFT) + 1U); - - /* Convert to bytes */ - bytes_per_word = (bits_per_word + 7U) / 8U; - - /* if one channel is disabled, bytes_per_word should be 4U, user should - * pay attention that when data length is shorter than 16, - * the data format: left data put in 0-15 bit and right data should put in 16-31 - */ - if (((base->CFG1 & I2S_CFG1_ONECHANNEL_MASK) == 0U)) { - bytes_per_word = 4U; - } - /* since DMA do not support 24bit transfer width, use 32bit instead */ - if (bytes_per_word == 3U) { - bytes_per_word = 4U; + if ((i2s_cfg->channels > 2) && + (i2s_cfg->format & I2S_FMT_DATA_FORMAT_MASK) != + I2S_FMT_DATA_FORMAT_I2S) { + /* + * More than 2 channels are enabled, so we need to enable + * secondary channel pairs. + */ + for (uint32_t slot = 1; slot < i2s_cfg->channels / 2; slot++) { + /* Position must be set so that data does not overlap + * with previous channel pair. Each channel pair + * will occupy slots of "word_size" bits. + */ + I2S_EnableSecondaryChannel(cfg->base, slot - 1, false, + i2s_cfg->word_size * 2 * slot); + } } - stream->dma_cfg.dest_data_size = bytes_per_word; - stream->dma_cfg.source_data_size = bytes_per_word; + /* + * I2S API definition specifies that a "16 bit word will occupy 2 bytes, + * a 24 or 32 bit word will occupy 4 bytes". Therefore, we will assume + * that "odd" word sizes will be aligned to 16 or 32 bit boundaries. + * + * FIFO depth is controlled by the number of bits per word (DATALEN). + * Per the RM: + * If the data length is 4-16, the FIFO should be filled + * with two 16 bit values (one for left, one for right channel) + * + * If the data length is 17-24, the FIFO should be filled with 2 24 bit + * values (one for left, one for right channel). We can just transfer + * 4 bytes, since the I2S API specifies 24 bit values would be aligned + * to a 32 bit boundary. + * + * If the data length is 25-32, the FIFO should be filled + * with one 32 bit value. First value is left channel, second is right. + * + * All this is to say that we can always use 4 byte transfer widths + * with the DMA engine, regardless of the data length. + */ + stream->dma_cfg.dest_data_size = 4U; + stream->dma_cfg.source_data_size = 4U; /* Save configuration for get_config */ memcpy(&stream->cfg, i2s_cfg, sizeof(struct i2s_config)); From c1ae6e5b4e8e084a639efd1c1fa560296eb4ad8d Mon Sep 17 00:00:00 2001 From: Adrien MARTIN Date: Thu, 18 Jan 2024 08:48:47 +0100 Subject: [PATCH 2835/3723] soc: stm32g0: add fdcan2 The STM32G0 soc has 2 CAN controllers. The 2nd on was not working with zephyr yet as both controllers shares the same IRQ. Recently, the shared irq system was integrated on now, both can controllers can work on this chip. Shared interrupts must be enabled only if both can controllers are enabled. Signed-off-by: Adrien MARTIN --- dts/arm/st/g0/stm32g0b1.dtsi | 13 +++++++++++++ .../st_stm32/stm32g0/Kconfig.defconfig.stm32g0b1xx | 7 +++++++ 2 files changed, 20 insertions(+) diff --git a/dts/arm/st/g0/stm32g0b1.dtsi b/dts/arm/st/g0/stm32g0b1.dtsi index 28b55fc70de..f6a8ae129e0 100644 --- a/dts/arm/st/g0/stm32g0b1.dtsi +++ b/dts/arm/st/g0/stm32g0b1.dtsi @@ -43,6 +43,19 @@ status = "disabled"; }; + fdcan2: can@40006800 { + compatible = "st,stm32-fdcan"; + reg = <0x40006800 0x400>, <0x4000b750 0x350>; + reg-names = "m_can", "message_ram"; + interrupts = <21 0>, <22 0>; + interrupt-names = "int0", "int1"; + clocks = <&rcc STM32_CLOCK_BUS_APB1 0x00001000>; + bosch,mram-cfg = <0x0 28 8 3 3 0 3 3>; + sample-point = <875>; + sample-point-data = <875>; + status = "disabled"; + }; + usart5: serial@40005000 { compatible = "st,stm32-usart", "st,stm32-uart"; reg = <0x40005000 0x400>; diff --git a/soc/arm/st_stm32/stm32g0/Kconfig.defconfig.stm32g0b1xx b/soc/arm/st_stm32/stm32g0/Kconfig.defconfig.stm32g0b1xx index 86c47b158e9..767cea2556c 100644 --- a/soc/arm/st_stm32/stm32g0/Kconfig.defconfig.stm32g0b1xx +++ b/soc/arm/st_stm32/stm32g0/Kconfig.defconfig.stm32g0b1xx @@ -11,4 +11,11 @@ config SOC config NUM_IRQS default 31 +if CAN_STM32_FDCAN + +config SHARED_INTERRUPTS + default y if $(dt_nodelabel_enabled,fdcan1) && $(dt_nodelabel_enabled,fdcan2) + +endif # CAN_STM32_FDCAN + endif # SOC_STM32G0B1XX From 2d8f4d1899a333e67ef4f95d0809eba8668f2b51 Mon Sep 17 00:00:00 2001 From: Adrien MARTIN Date: Thu, 25 Jan 2024 12:16:33 +0100 Subject: [PATCH 2836/3723] boards: arm: nucleo_g0b1re: add fdcan2 support The nucleo_g0b1re board is based on stm32g0 that supports 2 can controllers. This commit adds support for the second can controller. Add also can label in yml board file. Signed-off-by: Adrien MARTIN --- boards/arm/nucleo_g0b1re/doc/index.rst | 3 ++- boards/arm/nucleo_g0b1re/nucleo_g0b1re.dts | 10 ++++++++++ boards/arm/nucleo_g0b1re/nucleo_g0b1re.yaml | 1 + 3 files changed, 13 insertions(+), 1 deletion(-) diff --git a/boards/arm/nucleo_g0b1re/doc/index.rst b/boards/arm/nucleo_g0b1re/doc/index.rst index 00a3c94b110..9627b094fc0 100644 --- a/boards/arm/nucleo_g0b1re/doc/index.rst +++ b/boards/arm/nucleo_g0b1re/doc/index.rst @@ -108,7 +108,7 @@ The Zephyr nucleo_g0b1re board configuration supports the following hardware fea +-----------+------------+-------------------------------------+ | die-temp | on-chip | die temperature sensor | +-----------+------------+-------------------------------------+ -| FDCAN1 | on-chip | CAN controller | +| FDCAN | on-chip | CAN controller | +-----------+------------+-------------------------------------+ Other hardware features are not yet supported in this Zephyr port. @@ -140,6 +140,7 @@ Default Zephyr Peripheral Mapping: - ADC1 IN1 : PA1 - DAC1_OUT1 : PA4 - FDCAN1 RX/TX: PA11/PA12 +- FDCAN2 RX/TX: PB0/PB1 For more details please refer to `STM32 Nucleo-64 board User Manual`_. diff --git a/boards/arm/nucleo_g0b1re/nucleo_g0b1re.dts b/boards/arm/nucleo_g0b1re/nucleo_g0b1re.dts index 9e024db953a..337d73ebe89 100644 --- a/boards/arm/nucleo_g0b1re/nucleo_g0b1re.dts +++ b/boards/arm/nucleo_g0b1re/nucleo_g0b1re.dts @@ -187,6 +187,16 @@ zephyr_udc0: &usb { status = "okay"; }; +&fdcan2 { + clocks = <&rcc STM32_CLOCK_BUS_APB1 0x00001000>, + <&rcc STM32_SRC_PLL_Q FDCAN_SEL(1)>; + pinctrl-0 = <&fdcan2_rx_pb0 &fdcan2_tx_pb1>; + pinctrl-names = "default"; + bus-speed = <125000>; + bus-speed-data = <1000000>; + status = "okay"; +}; + &flash0 { partitions { compatible = "fixed-partitions"; diff --git a/boards/arm/nucleo_g0b1re/nucleo_g0b1re.yaml b/boards/arm/nucleo_g0b1re/nucleo_g0b1re.yaml index bc267274401..e2389efdbb7 100644 --- a/boards/arm/nucleo_g0b1re/nucleo_g0b1re.yaml +++ b/boards/arm/nucleo_g0b1re/nucleo_g0b1re.yaml @@ -14,6 +14,7 @@ supported: - arduino_i2c - arduino_spi - arduino_serial + - can - uart - gpio - i2c From a06b7a4676962b39a8b8ccdcaf343c964a0ce86b Mon Sep 17 00:00:00 2001 From: Fabio Baltieri Date: Thu, 25 Jan 2024 11:50:20 +0000 Subject: [PATCH 2837/3723] input: keymap: use the non `_OR_NULL` DEVICE_DT_GET variant This driver really needs a device associated with it for the syncronization bit to make sense, and since the argument is DT_PARENT it will get it all the time, so no changes in practice, but this should have been using the normal macro anyway. Signed-off-by: Fabio Baltieri --- subsys/input/input_keymap.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/subsys/input/input_keymap.c b/subsys/input/input_keymap.c index 4d7e25d22f0..938d238b2b0 100644 --- a/subsys/input/input_keymap.c +++ b/subsys/input/input_keymap.c @@ -102,7 +102,7 @@ static int keymap_init(const struct device *dev) { \ keymap_cb(DEVICE_DT_INST_GET(inst), evt); \ } \ - INPUT_CALLBACK_DEFINE(DEVICE_DT_GET_OR_NULL(DT_INST_PARENT(inst)), keymap_cb_##inst); \ + INPUT_CALLBACK_DEFINE(DEVICE_DT_GET(DT_INST_PARENT(inst)), keymap_cb_##inst); \ \ DT_INST_FOREACH_PROP_ELEM(inst, keymap, KEYMAP_ENTRY_VALIDATE) \ \ From 2dc1cc712afb275faa8c062ce64fe26e67925b78 Mon Sep 17 00:00:00 2001 From: Anas Nashif Date: Mon, 22 Jan 2024 13:22:47 -0500 Subject: [PATCH 2838/3723] manifest: optional: update SOF to latest from upstream Update to latest commit with patches to align with zephyr tree. Signed-off-by: Anas Nashif --- submanifests/optional.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/submanifests/optional.yaml b/submanifests/optional.yaml index 13584b2437e..a15d0fd6be5 100644 --- a/submanifests/optional.yaml +++ b/submanifests/optional.yaml @@ -34,7 +34,7 @@ manifest: groups: - optional - name: sof - revision: 37dd5e62663fcedca659c2104043529b3855a1b0 + revision: 7a0ff76e05cab6b1d99767258680a7b8711dd476 path: modules/audio/sof remote: upstream groups: From 7b55b99cac0a65f56d4b571061e8f51f5bc31fbf Mon Sep 17 00:00:00 2001 From: Benedikt Schmidt Date: Thu, 30 Nov 2023 15:27:56 +0100 Subject: [PATCH 2839/3723] drivers: gpio: implement daisy chaining for BD8LB600FS This implements the daisy chain feature of the low side switch BD8LB600FS. The daisy chaining is in hardware achieved via connecting the MISO and MOSI lines of multiple instances of the IC in a row. It is implemented in the driver through a variable number of GPIOs on one instance. Therefore, one device tree instance of the IC will handle multiple daisy chained physical instances. Signed-off-by: Benedikt Schmidt --- drivers/gpio/gpio_bd8lb600fs.c | 81 ++++++++++++++++++-------- dts/bindings/gpio/rohm,bd8lb600fs.yaml | 10 +++- 2 files changed, 65 insertions(+), 26 deletions(-) diff --git a/drivers/gpio/gpio_bd8lb600fs.c b/drivers/gpio/gpio_bd8lb600fs.c index 04eed39170b..3a80bbe6529 100644 --- a/drivers/gpio/gpio_bd8lb600fs.c +++ b/drivers/gpio/gpio_bd8lb600fs.c @@ -30,40 +30,61 @@ struct bd8lb600fs_config { struct spi_dt_spec bus; const struct gpio_dt_spec gpio_reset; + int gpios_count; }; struct bd8lb600fs_drv_data { /* gpio_driver_data needs to be first */ struct gpio_driver_data data; - uint8_t state; /* each bit is one output channel, bit 0 = channel 1, ... */ - uint8_t configured; /* each bit defines if the output channel is configured, see state */ + uint32_t state; /* each bit is one output channel, bit 0 = channel 1, ... */ + uint32_t configured; /* each bit defines if the output channel is configured, see state */ struct k_mutex lock; + int instance_count_actual; + int gpios_count_actual; }; -static int write_state(const struct bd8lb600fs_config *config, uint8_t state) +static int write_state(const struct device *dev, uint32_t state) { - LOG_DBG("writing state 0x%02X to BD8LB600FS", state); + const struct bd8lb600fs_config *config = dev->config; + struct bd8lb600fs_drv_data *drv_data = dev->data; + + LOG_DBG("%s: writing state 0x%08X to BD8LB600FS", dev->name, state); uint16_t state_converted = 0; - uint8_t buffer_tx[2]; - const struct spi_buf tx_buf[] = {{ + uint8_t buffer_tx[8]; + const struct spi_buf tx_buf = { .buf = buffer_tx, - .len = ARRAY_SIZE(buffer_tx), - }}; + .len = drv_data->instance_count_actual * sizeof(state_converted), + }; const struct spi_buf_set tx = { - .buffers = tx_buf, - .count = ARRAY_SIZE(tx_buf), + .buffers = &tx_buf, + .count = 1, }; - for (size_t i = 0; i < 8; ++i) { - if ((state & BIT(i)) == 0) { - state_converted |= OUTPUT_OFF_WITH_OPEN_LOAD_DETECTION << (i * 2); - } else { - state_converted |= OUTPUT_ON << (i * 2); + memset(buffer_tx, 0x00, sizeof(buffer_tx)); + + for (size_t j = 0; j < drv_data->instance_count_actual; ++j) { + int instance_position = (drv_data->instance_count_actual - j - 1) * 2; + + state_converted = 0; + + for (size_t i = 0; i < 8; ++i) { + if ((state & BIT(i + j*8)) == 0) { + state_converted |= OUTPUT_OFF_WITH_OPEN_LOAD_DETECTION << (i * 2); + } else { + state_converted |= OUTPUT_ON << (i * 2); + } } + + LOG_DBG("%s: configuration for instance %i: %04X (position %i)", + dev->name, + j, + state_converted, + instance_position); + sys_put_be16(state_converted, buffer_tx + instance_position); } - sys_put_be16(state_converted, buffer_tx); + LOG_HEXDUMP_DBG(buffer_tx, ARRAY_SIZE(buffer_tx), "configuration written out"); int result = spi_write_dt(&config->bus, &tx); @@ -77,7 +98,6 @@ static int write_state(const struct bd8lb600fs_config *config, uint8_t state) static int bd8lb600fs_pin_configure(const struct device *dev, gpio_pin_t pin, gpio_flags_t flags) { - const struct bd8lb600fs_config *config = dev->config; struct bd8lb600fs_drv_data *drv_data = dev->data; /* cannot execute a bus operation in an ISR context */ @@ -85,7 +105,7 @@ static int bd8lb600fs_pin_configure(const struct device *dev, gpio_pin_t pin, gp return -EWOULDBLOCK; } - if (pin > 7) { + if (pin >= drv_data->gpios_count_actual) { LOG_ERR("invalid pin number %i", pin); return -EINVAL; } @@ -130,7 +150,7 @@ static int bd8lb600fs_pin_configure(const struct device *dev, gpio_pin_t pin, gp WRITE_BIT(drv_data->configured, pin, 1); - int result = write_state(config, drv_data->state); + int result = write_state(dev, drv_data->state); k_mutex_unlock(&drv_data->lock); @@ -145,7 +165,6 @@ static int bd8lb600fs_port_get_raw(const struct device *dev, uint32_t *value) static int bd8lb600fs_port_set_masked_raw(const struct device *dev, uint32_t mask, uint32_t value) { - const struct bd8lb600fs_config *config = dev->config; struct bd8lb600fs_drv_data *drv_data = dev->data; /* cannot execute a bus operation in an ISR context */ @@ -156,7 +175,7 @@ static int bd8lb600fs_port_set_masked_raw(const struct device *dev, uint32_t mas k_mutex_lock(&drv_data->lock, K_FOREVER); drv_data->state = (drv_data->state & ~mask) | (mask & value); - int result = write_state(config, drv_data->state); + int result = write_state(dev, drv_data->state); k_mutex_unlock(&drv_data->lock); @@ -175,7 +194,6 @@ static int bd8lb600fs_port_clear_bits_raw(const struct device *dev, uint32_t mas static int bd8lb600fs_port_toggle_bits(const struct device *dev, uint32_t mask) { - const struct bd8lb600fs_config *config = dev->config; struct bd8lb600fs_drv_data *drv_data = dev->data; /* cannot execute a bus operation in an ISR context */ @@ -186,7 +204,7 @@ static int bd8lb600fs_port_toggle_bits(const struct device *dev, uint32_t mask) k_mutex_lock(&drv_data->lock, K_FOREVER); drv_data->state ^= mask; - int result = write_state(config, drv_data->state); + int result = write_state(dev, drv_data->state); k_mutex_unlock(&drv_data->lock); @@ -219,6 +237,22 @@ static int bd8lb600fs_init(const struct device *dev) return result; } + drv_data->instance_count_actual = config->gpios_count / 8; + + if (config->gpios_count % 8 != 0) { + LOG_ERR("%s: number of GPIOs %i is not a multiple of 8", + dev->name, config->gpios_count); + return -EINVAL; + } + + if (drv_data->instance_count_actual > 4) { + LOG_ERR("%s: only a maximum of 4 devices are supported for the daisy chaining", + dev->name); + return -EINVAL; + } + + drv_data->gpios_count_actual = drv_data->instance_count_actual * 8; + result = gpio_pin_configure_dt(&config->gpio_reset, GPIO_OUTPUT_ACTIVE); if (result != 0) { @@ -242,6 +276,7 @@ static int bd8lb600fs_init(const struct device *dev) .bus = SPI_DT_SPEC_INST_GET( \ inst, SPI_OP_MODE_MASTER | SPI_MODE_CPHA | SPI_WORD_SET(8), 0), \ .gpio_reset = GPIO_DT_SPEC_GET_BY_IDX(DT_DRV_INST(inst), reset_gpios, 0), \ + .gpios_count = DT_INST_PROP(inst, ngpios), \ }; \ \ static struct bd8lb600fs_drv_data bd8lb600fs_##inst##_drvdata = { \ diff --git a/dts/bindings/gpio/rohm,bd8lb600fs.yaml b/dts/bindings/gpio/rohm,bd8lb600fs.yaml index 486953428b4..205b44ce83b 100644 --- a/dts/bindings/gpio/rohm,bd8lb600fs.yaml +++ b/dts/bindings/gpio/rohm,bd8lb600fs.yaml @@ -6,6 +6,8 @@ description: | This is a representation of the Rohm BD8LB600FS SPI Gpio Expander. + Multiple instances may be daisy chained, which can be configured + via the number of supported GPIOs. compatible: "rohm,bd8lb600fs" @@ -18,13 +20,15 @@ properties: ngpios: type: int required: true - const: 8 - description: Number of gpios supported + description: | + Number of pins for the expander. This must be a multiple of 8. + The number of pins also defines how many devices are daisy chained. + Set to 8 for one instance without daisy chaining. reset-gpios: type: phandle-array required: true - description: "GPIO for reset" + description: GPIO for reset gpio-cells: - pin From 5a618057deb2f4b28779739734c410c809b0e031 Mon Sep 17 00:00:00 2001 From: Benedikt Schmidt Date: Tue, 12 Dec 2023 09:47:03 +0100 Subject: [PATCH 2840/3723] drivers: gpio: add missing check if GPIO is ready for BD8LB600FS Add a missing call to gpio_is_ready_dt in the driver of the BD8LB600FS. Signed-off-by: Benedikt Schmidt --- drivers/gpio/gpio_bd8lb600fs.c | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/drivers/gpio/gpio_bd8lb600fs.c b/drivers/gpio/gpio_bd8lb600fs.c index 3a80bbe6529..45650e716a7 100644 --- a/drivers/gpio/gpio_bd8lb600fs.c +++ b/drivers/gpio/gpio_bd8lb600fs.c @@ -230,6 +230,11 @@ static int bd8lb600fs_init(const struct device *dev) return -ENODEV; } + if (!gpio_is_ready_dt(&config->gpio_reset)) { + LOG_ERR("%s: reset GPIO is not ready", dev->name); + return -ENODEV; + } + int result = k_mutex_init(&drv_data->lock); if (result != 0) { From de667a7fae1144a15bee835dfd3dcb4a85fa134b Mon Sep 17 00:00:00 2001 From: Chaitanya Tata Date: Tue, 23 Jan 2024 19:55:32 +0530 Subject: [PATCH 2841/3723] wifi: ap: Add support to disconnect a STA In AP mode, this can be used to disconnect a connected station. Signed-off-by: Chaitanya Tata --- include/zephyr/net/wifi_mgmt.h | 15 +++++++++++++++ subsys/net/l2/wifi/wifi_mgmt.c | 24 ++++++++++++++++++++++++ 2 files changed, 39 insertions(+) diff --git a/include/zephyr/net/wifi_mgmt.h b/include/zephyr/net/wifi_mgmt.h index db15fa7b1ab..982184a103b 100644 --- a/include/zephyr/net/wifi_mgmt.h +++ b/include/zephyr/net/wifi_mgmt.h @@ -81,6 +81,8 @@ enum net_request_wifi_cmd { NET_REQUEST_WIFI_CMD_PACKET_FILTER, /** Set or get Wi-Fi channel for Monitor or TX-Injection mode */ NET_REQUEST_WIFI_CMD_CHANNEL, + /** Disconnect a STA from AP */ + NET_REQUEST_WIFI_CMD_AP_STA_DISCONNECT, NET_REQUEST_WIFI_CMD_MAX }; @@ -158,6 +160,11 @@ NET_MGMT_DEFINE_REQUEST_HANDLER(NET_REQUEST_WIFI_PACKET_FILTER); NET_MGMT_DEFINE_REQUEST_HANDLER(NET_REQUEST_WIFI_CHANNEL); +#define NET_REQUEST_WIFI_AP_STA_DISCONNECT \ + (_NET_WIFI_BASE | NET_REQUEST_WIFI_CMD_AP_STA_DISCONNECT) + +NET_MGMT_DEFINE_REQUEST_HANDLER(NET_REQUEST_WIFI_AP_STA_DISCONNECT); + /** Wi-Fi management events */ enum net_event_wifi_cmd { /** Scan results available */ @@ -735,6 +742,14 @@ struct wifi_mgmt_ops { * @return 0 if ok, < 0 if error */ int (*ap_disable)(const struct device *dev); + /** Disconnect a STA from AP + * + * @param dev Pointer to the device structure for the driver instance. + * @param mac MAC address of the STA to disconnect + * + * @return 0 if ok, < 0 if error + */ + int (*ap_sta_disconnect)(const struct device *dev, const uint8_t *mac); /** Get interface status * * @param dev Pointer to the device structure for the driver instance. diff --git a/subsys/net/l2/wifi/wifi_mgmt.c b/subsys/net/l2/wifi/wifi_mgmt.c index 6e0cb761dbf..2cfe8e25d89 100644 --- a/subsys/net/l2/wifi/wifi_mgmt.c +++ b/subsys/net/l2/wifi/wifi_mgmt.c @@ -410,6 +410,30 @@ static int wifi_ap_disable(uint32_t mgmt_request, struct net_if *iface, NET_MGMT_REGISTER_REQUEST_HANDLER(NET_REQUEST_WIFI_AP_DISABLE, wifi_ap_disable); +static int wifi_ap_sta_disconnect(uint32_t mgmt_request, struct net_if *iface, + void *data, size_t len) +{ + const struct device *dev = net_if_get_device(iface); + const struct wifi_mgmt_ops *const wifi_mgmt_api = get_wifi_api(iface); + uint8_t *mac = data; + + if (dev == NULL) { + return -ENODEV; + } + + if (wifi_mgmt_api == NULL || wifi_mgmt_api->ap_sta_disconnect == NULL) { + return -ENOTSUP; + } + + if (!data || len != sizeof(uint8_t) * WIFI_MAC_ADDR_LEN) { + return -EINVAL; + } + + return wifi_mgmt_api->ap_sta_disconnect(dev, mac); +} + +NET_MGMT_REGISTER_REQUEST_HANDLER(NET_REQUEST_WIFI_AP_STA_DISCONNECT, wifi_ap_sta_disconnect); + static int wifi_iface_status(uint32_t mgmt_request, struct net_if *iface, void *data, size_t len) { From c53a1df1381cd11bb93cbee93993c80fafcdf234 Mon Sep 17 00:00:00 2001 From: Chaitanya Tata Date: Tue, 23 Jan 2024 20:03:59 +0530 Subject: [PATCH 2842/3723] wifi: shell: ap: Add a command to disconnect a station The shell commands can be used to disconnect a connected station in AP mode. Signed-off-by: Chaitanya Tata --- subsys/net/l2/wifi/wifi_shell.c | 27 +++++++++++++++++++++++++++ 1 file changed, 27 insertions(+) diff --git a/subsys/net/l2/wifi/wifi_shell.c b/subsys/net/l2/wifi/wifi_shell.c index f833dc52c2a..6bd21c86ad2 100644 --- a/subsys/net/l2/wifi/wifi_shell.c +++ b/subsys/net/l2/wifi/wifi_shell.c @@ -1361,6 +1361,28 @@ static int cmd_wifi_ap_stations(const struct shell *sh, size_t argc, return 0; } +static int cmd_wifi_ap_sta_disconnect(const struct shell *sh, size_t argc, + char *argv[]) +{ + struct net_if *iface = net_if_get_first_wifi(); + uint8_t mac[6]; + int ret; + + if (net_bytes_from_str(mac, sizeof(mac), argv[1]) < 0) { + shell_fprintf(sh, SHELL_WARNING, "Invalid MAC address\n"); + return -ENOEXEC; + } + + ret = net_mgmt(NET_REQUEST_WIFI_AP_STA_DISCONNECT, iface, mac, sizeof(mac)); + if (ret) { + shell_fprintf(sh, SHELL_WARNING, "AP station disconnect failed: %s\n", + strerror(-ret)); + return -ENOEXEC; + } + + shell_fprintf(sh, SHELL_NORMAL, "AP station disconnect requested\n"); + return 0; +} static int cmd_wifi_reg_domain(const struct shell *sh, size_t argc, char *argv[]) @@ -1849,6 +1871,11 @@ SHELL_STATIC_SUBCMD_SET_CREATE(wifi_cmd_ap, "List stations connected to the AP", cmd_wifi_ap_stations, 1, 0), + SHELL_CMD_ARG(disconnect, NULL, + "Disconnect a station from the AP\n" + "\n", + cmd_wifi_ap_sta_disconnect, + 2, 0), SHELL_SUBCMD_SET_END ); From c07d6483044f63a57ea26b65405793d5fa8f5c95 Mon Sep 17 00:00:00 2001 From: Chaitanya Tata Date: Tue, 23 Jan 2024 21:46:24 +0530 Subject: [PATCH 2843/3723] wifi: shell: Remove duplicate argument count checks Now that we are using the shell macro to enforce argument count check, both mandatory and optional arguments, these additions checks are unnecessary. Signed-off-by: Chaitanya Tata --- subsys/net/l2/wifi/wifi_shell.c | 46 +++++---------------------------- 1 file changed, 6 insertions(+), 40 deletions(-) diff --git a/subsys/net/l2/wifi/wifi_shell.c b/subsys/net/l2/wifi/wifi_shell.c index 6bd21c86ad2..75dc59d4fc5 100644 --- a/subsys/net/l2/wifi/wifi_shell.c +++ b/subsys/net/l2/wifi/wifi_shell.c @@ -450,12 +450,6 @@ static int __wifi_args_to_params(size_t argc, char *argv[], char *endptr; int idx = 1; - if (argc < 1) { - print(context.sh, SHELL_WARNING, - "SSID not specified\n"); - return -EINVAL; - } - /* Defaults */ params->band = WIFI_FREQ_BAND_UNKNOWN; params->channel = WIFI_CHANNEL_ANY; @@ -1058,12 +1052,6 @@ static int cmd_wifi_twt_setup_quick(const struct shell *sh, size_t argc, context.sh = sh; - if (argc != 3) { - shell_fprintf(sh, SHELL_WARNING, "Invalid number of arguments\n"); - shell_help(sh); - return -ENOEXEC; - } - /* Sensible defaults */ params.operation = WIFI_TWT_SETUP; params.negotiation_type = WIFI_TWT_INDIVIDUAL; @@ -1112,12 +1100,6 @@ static int cmd_wifi_twt_setup(const struct shell *sh, size_t argc, context.sh = sh; - if (argc != 12) { - shell_fprintf(sh, SHELL_WARNING, "Invalid number of arguments\n"); - shell_help(sh); - return -ENOEXEC; - } - params.operation = WIFI_TWT_SETUP; if (!parse_number(sh, &value, argv[idx++], WIFI_TWT_INDIVIDUAL, @@ -1203,12 +1185,6 @@ static int cmd_wifi_twt_teardown(const struct shell *sh, size_t argc, context.sh = sh; int idx = 1; - if (argc != 5) { - shell_fprintf(sh, SHELL_WARNING, "Invalid number of arguments\n"); - shell_help(sh); - return -ENOEXEC; - } - params.operation = WIFI_TWT_TEARDOWN; if (!parse_number(sh, &value, argv[idx++], WIFI_TWT_INDIVIDUAL, @@ -1675,13 +1651,8 @@ static int cmd_wifi_channel(const struct shell *sh, size_t argc, char *argv[]) int ret; bool do_channel_oper = true; - if (argc > 1) { - channel_info.oper = WIFI_MGMT_SET; - parse_channel_args_to_params(sh, argc, argv, &channel_info, &do_channel_oper); - } else { - shell_fprintf(sh, SHELL_ERROR, "Invalid number of arguments\n"); - return -EINVAL; - } + channel_info.oper = WIFI_MGMT_SET; + parse_channel_args_to_params(sh, argc, argv, &channel_info, &do_channel_oper); if (do_channel_oper) { /* @@ -1797,13 +1768,8 @@ static int cmd_wifi_packet_filter(const struct shell *sh, size_t argc, char *arg int ret; bool do_filter_oper = true; - if (argc > 1) { - packet_filter.oper = WIFI_MGMT_SET; - parse_filter_args_to_params(sh, argc, argv, &packet_filter, &do_filter_oper); - } else { - shell_fprintf(sh, SHELL_ERROR, "Invalid number of arguments\n"); - return -EINVAL; - } + packet_filter.oper = WIFI_MGMT_SET; + parse_filter_args_to_params(sh, argc, argv, &packet_filter, &do_filter_oper); if (do_filter_oper) { /* @@ -1984,7 +1950,7 @@ SHELL_STATIC_SUBCMD_SET_CREATE(wifi_commands, "Set operation example for interface index 1 - set data+management frame filter\n" "wifi packet_filter -i1 -md.\n", cmd_wifi_packet_filter, - 1, 8), + 2, 8), SHELL_CMD_ARG(channel, NULL, "wifi channel setting\n" "This command is used to set the channel when\n" "monitor or TX-Injection mode is enabled\n" @@ -1998,7 +1964,7 @@ SHELL_STATIC_SUBCMD_SET_CREATE(wifi_commands, "Set operation example for interface index 1 (setting channel 5)\n" "wifi -i1 -c5.\n", cmd_wifi_channel, - 1, 4), + 2, 4), SHELL_CMD_ARG(ps_timeout, NULL, " - PS inactivity timer(in ms).\n", From f26da17723084652f45016b77550ff49c7c74186 Mon Sep 17 00:00:00 2001 From: Benedikt Schmidt Date: Wed, 8 Nov 2023 16:42:46 +0100 Subject: [PATCH 2844/3723] drivers: gpio: make reset of TLE9104 optional In some hardware designs it might happen that the reset signal for the TLE9104 is not used only for this purpose, but instead for instance to reset other devices at the same time. For such a hardware design it is then necessary to make the reset GPIO optional. The reset will have to be triggered earlier on. Signed-off-by: Benedikt Schmidt --- drivers/gpio/gpio_tle9104.c | 22 ++++++++++++---------- dts/bindings/gpio/infineon,tle9104.yaml | 1 - 2 files changed, 12 insertions(+), 11 deletions(-) diff --git a/drivers/gpio/gpio_tle9104.c b/drivers/gpio/gpio_tle9104.c index 3494cdb2533..b2066b9ab46 100644 --- a/drivers/gpio/gpio_tle9104.c +++ b/drivers/gpio/gpio_tle9104.c @@ -440,16 +440,18 @@ static int tle9104_init(const struct device *dev) } } - result = gpio_pin_configure_dt(&config->gpio_reset, GPIO_OUTPUT_ACTIVE); - if (result != 0) { - LOG_ERR("failed to initialize GPIO for reset"); - return result; - } + if (config->gpio_reset.port != NULL) { + result = gpio_pin_configure_dt(&config->gpio_reset, GPIO_OUTPUT_ACTIVE); + if (result != 0) { + LOG_ERR("failed to initialize GPIO for reset"); + return result; + } - k_busy_wait(TLE9104_RESET_DURATION_TIME_US); - gpio_pin_set_dt(&config->gpio_reset, 0); - k_busy_wait(TLE9104_RESET_DURATION_WAIT_TIME_US + - TLE9104_RESET_DURATION_WAIT_TIME_SAFETY_MARGIN_US); + k_busy_wait(TLE9104_RESET_DURATION_TIME_US); + gpio_pin_set_dt(&config->gpio_reset, 0); + k_busy_wait(TLE9104_RESET_DURATION_WAIT_TIME_US + + TLE9104_RESET_DURATION_WAIT_TIME_SAFETY_MARGIN_US); + } /* * The first read value should be the ICVID, this acts also as the setup of the @@ -525,7 +527,7 @@ BUILD_ASSERT(CONFIG_GPIO_TLE9104_INIT_PRIORITY > CONFIG_SPI_INIT_PRIORITY, .bus = SPI_DT_SPEC_INST_GET( \ inst, SPI_OP_MODE_MASTER | SPI_MODE_CPHA | SPI_WORD_SET(8), 0), \ .gpio_enable = TLE9104_INIT_GPIO_FIELDS(inst, en_gpios), \ - .gpio_reset = GPIO_DT_SPEC_GET_BY_IDX(DT_DRV_INST(inst), resn_gpios, 0), \ + .gpio_reset = TLE9104_INIT_GPIO_FIELDS(inst, resn_gpios), \ .gpio_control = { \ TLE9104_INIT_GPIO_FIELDS(inst, in1_gpios), \ TLE9104_INIT_GPIO_FIELDS(inst, in2_gpios), \ diff --git a/dts/bindings/gpio/infineon,tle9104.yaml b/dts/bindings/gpio/infineon,tle9104.yaml index 5893f1a355a..cb82ecbde92 100644 --- a/dts/bindings/gpio/infineon,tle9104.yaml +++ b/dts/bindings/gpio/infineon,tle9104.yaml @@ -26,7 +26,6 @@ properties: resn-gpios: type: phandle-array - required: true description: "GPIO for reset" in1-gpios: From 23ed31383eb6390f36c169d78055bc28a4ee5f05 Mon Sep 17 00:00:00 2001 From: Benedikt Schmidt Date: Mon, 11 Dec 2023 13:37:01 +0100 Subject: [PATCH 2845/3723] drivers: gpio: use gpio_is_ready_dt in TLE9104 Use gpio_is_ready_dt in the driver for the TLE9104 before actually using the GPIO. Signed-off-by: Benedikt Schmidt --- drivers/gpio/gpio_tle9104.c | 13 +++++++++---- 1 file changed, 9 insertions(+), 4 deletions(-) diff --git a/drivers/gpio/gpio_tle9104.c b/drivers/gpio/gpio_tle9104.c index b2066b9ab46..47a899e1615 100644 --- a/drivers/gpio/gpio_tle9104.c +++ b/drivers/gpio/gpio_tle9104.c @@ -415,8 +415,8 @@ static int tle9104_init(const struct device *dev) register_cfg |= TLE9104_CFG_OUT1DD_BIT << i; - if (!device_is_ready(current->port)) { - LOG_ERR("control GPIO %s is not ready", current->port->name); + if (!gpio_is_ready_dt(current)) { + LOG_ERR("%s: control GPIO is not ready", dev->name); return -ENODEV; } @@ -428,8 +428,8 @@ static int tle9104_init(const struct device *dev) } if (config->gpio_enable.port != NULL) { - if (!device_is_ready(config->gpio_enable.port)) { - LOG_ERR("enable GPIO %s is not ready", config->gpio_enable.port->name); + if (!gpio_is_ready_dt(&config->gpio_enable)) { + LOG_ERR("%s: enable GPIO is not ready", dev->name); return -ENODEV; } @@ -441,6 +441,11 @@ static int tle9104_init(const struct device *dev) } if (config->gpio_reset.port != NULL) { + if (!gpio_is_ready_dt(&config->gpio_reset)) { + LOG_ERR("%s: reset GPIO is not yet ready", dev->name); + return -ENODEV; + } + result = gpio_pin_configure_dt(&config->gpio_reset, GPIO_OUTPUT_ACTIVE); if (result != 0) { LOG_ERR("failed to initialize GPIO for reset"); From 5ff55630a30a48b52e87ca85faec9d0d1884e53d Mon Sep 17 00:00:00 2001 From: Benjamin Lemouzy Date: Thu, 5 Oct 2023 11:45:32 +0200 Subject: [PATCH 2846/3723] drivers: audio: tas6422dac: fix codec_mute_output function Mute GPIO mutes both channel 1 and channel 2. So, only control it when all channels have to be muted. Signed-off-by: Benjamin Lemouzy --- drivers/audio/tas6422dac.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/drivers/audio/tas6422dac.c b/drivers/audio/tas6422dac.c index 91c36de2897..cb1efb597ed 100644 --- a/drivers/audio/tas6422dac.c +++ b/drivers/audio/tas6422dac.c @@ -123,7 +123,9 @@ static void codec_mute_output(const struct device *dev, enum tas6422dac_channel_ #if TAS6422DAC_MUTE_GPIO_SUPPORT const struct codec_driver_config *const dev_cfg = dev->config; - gpio_pin_configure_dt(&dev_cfg->mute_gpio, GPIO_OUTPUT_ACTIVE); + if (channel == TAS6422DAC_CHANNEL_ALL) { + gpio_pin_configure_dt(&dev_cfg->mute_gpio, GPIO_OUTPUT_ACTIVE); + } #endif codec_read_reg(dev, CH_STATE_CTRL_ADDR, &val); From f6995feae912cccbad8d31e362d4318a17382dec Mon Sep 17 00:00:00 2001 From: Kai Vehmanen Date: Thu, 25 Jan 2024 14:29:34 +0200 Subject: [PATCH 2847/3723] soc: xtensa: intel_adsp: cavs: fix XCC build Commit 3b99fb1b4a55c ("xtensa: do not imply atomic ops kconfig") removed ATOMIC_OPERATIONS_ARCH at xtensa arch level. This triggers a bug in intel_adsp cavs builds with XCC compiler as CONFIG_ATOMIC_OPERATIONS_BUILTIN is not defined but neither is CONFIG_ATOMIC_OPERATIONS_ARCH anymore, resulting in failed builds. Fix the XCC build by defining CONFIG_ATOMIC_OPERATIONS_ARCH at soc level. Signed-off-by: Kai Vehmanen --- soc/xtensa/intel_adsp/cavs/Kconfig.series | 1 + 1 file changed, 1 insertion(+) diff --git a/soc/xtensa/intel_adsp/cavs/Kconfig.series b/soc/xtensa/intel_adsp/cavs/Kconfig.series index adbc1f39e1d..a88bec1ec2e 100644 --- a/soc/xtensa/intel_adsp/cavs/Kconfig.series +++ b/soc/xtensa/intel_adsp/cavs/Kconfig.series @@ -9,6 +9,7 @@ config SOC_SERIES_INTEL_ADSP_CAVS select XTENSA_RESET_VECTOR select XTENSA_USE_CORE_CRT1 select ATOMIC_OPERATIONS_BUILTIN if "$(ZEPHYR_TOOLCHAIN_VARIANT)" != "xcc" + select ATOMIC_OPERATIONS_ARCH if "$(ZEPHYR_TOOLCHAIN_VARIANT)" = "xcc" select ARCH_HAS_COHERENCE select HAS_PM help From f38b01c7ac82e4cf889a78456f39086092b7f76e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Manuel=20Arg=C3=BCelles?= Date: Sun, 21 Jan 2024 14:33:54 +0700 Subject: [PATCH 2848/3723] soc: arm: nxp_s32: s32k1: enable watchdog driver MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Enable on-chip watchdog driver support for S32K1 devices. Signed-off-by: Manuel Argüelles --- dts/arm/nxp/nxp_s32k1xx.dtsi | 15 ++++++++++++++- soc/arm/nxp_s32/s32k1/Kconfig.series | 3 ++- soc/arm/nxp_s32/s32k1/soc.c | 2 -- west.yml | 2 +- 4 files changed, 17 insertions(+), 5 deletions(-) diff --git a/dts/arm/nxp/nxp_s32k1xx.dtsi b/dts/arm/nxp/nxp_s32k1xx.dtsi index a8c07d14028..10c3d207bf7 100644 --- a/dts/arm/nxp/nxp_s32k1xx.dtsi +++ b/dts/arm/nxp/nxp_s32k1xx.dtsi @@ -1,5 +1,5 @@ /* - * Copyright 2023 NXP + * Copyright 2023-2024 NXP * * SPDX-License-Identifier: Apache-2.0 */ @@ -9,6 +9,10 @@ #include / { + aliases { + watchdog0 = &wdog; + }; + cpus { #address-cells = <1>; #size-cells = <0>; @@ -124,6 +128,15 @@ clocks = <&clock NXP_S32_PORTE_CLK>; }; + wdog: watchdog@40052000 { + compatible = "nxp,kinetis-wdog32"; + reg = <0x40052000 0x1000>; + interrupts = <22 0>; + clocks = <&clock NXP_S32_LPO_128K_CLK>; + clk-source = <1>; + clk-divider = <256>; + }; + clock: clock-controller@40064000 { compatible = "nxp,s32-clock"; reg = <0x40064000 0x1000>, <0x40065000 0x1000>; diff --git a/soc/arm/nxp_s32/s32k1/Kconfig.series b/soc/arm/nxp_s32/s32k1/Kconfig.series index 12d74205412..07fe41bda9e 100644 --- a/soc/arm/nxp_s32/s32k1/Kconfig.series +++ b/soc/arm/nxp_s32/s32k1/Kconfig.series @@ -1,6 +1,6 @@ # NXP S32K1XX MCU series -# Copyright 2023 NXP +# Copyright 2023-2024 NXP # SPDX-License-Identifier: Apache-2.0 config SOC_SERIES_S32K1XX @@ -18,5 +18,6 @@ config SOC_SERIES_S32K1XX select HAS_MCUX_LPSPI select HAS_MCUX_FTM select HAS_MCUX_FLEXCAN + select HAS_MCUX_WDOG32 help Enable support for NXP S32K1XX MCU series. diff --git a/soc/arm/nxp_s32/s32k1/soc.c b/soc/arm/nxp_s32/s32k1/soc.c index 50cff147846..bed85dbc91d 100644 --- a/soc/arm/nxp_s32/s32k1/soc.c +++ b/soc/arm/nxp_s32/s32k1/soc.c @@ -20,8 +20,6 @@ #endif #if defined(CONFIG_WDOG_INIT) -#define WDOG_UPDATE_KEY 0xD928C520U - void z_arm_watchdog_init(void) { /* diff --git a/west.yml b/west.yml index 904d857d6e0..79af241f523 100644 --- a/west.yml +++ b/west.yml @@ -193,7 +193,7 @@ manifest: groups: - hal - name: hal_nxp - revision: d6d43cab73f1a0fc73ec26084dab3f54c6324d2e + revision: 3d4be32141dd8605515d95f8d1a2340974190cff path: modules/hal/nxp groups: - hal From ed0ccbbc0b8cfb56c95e6a18575ee9fb0a658362 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Manuel=20Arg=C3=BCelles?= Date: Sun, 21 Jan 2024 14:35:21 +0700 Subject: [PATCH 2849/3723] boards: arm: ucans32k1sic: enable watchdog support MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Document support and enable testing for the watchdog driver on this board. Signed-off-by: Manuel Argüelles --- boards/arm/ucans32k1sic/doc/index.rst | 1 + boards/arm/ucans32k1sic/ucans32k1sic.yaml | 3 ++- 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/boards/arm/ucans32k1sic/doc/index.rst b/boards/arm/ucans32k1sic/doc/index.rst index adceb43de03..e89daf9c324 100644 --- a/boards/arm/ucans32k1sic/doc/index.rst +++ b/boards/arm/ucans32k1sic/doc/index.rst @@ -51,6 +51,7 @@ LPI2C on-chip i2c LPSPI on-chip spi FTM on-chip pwm FlexCAN on-chip can +Watchdog on-chip watchdog ============ ========== ================================ The default configuration can be found in the Kconfig file diff --git a/boards/arm/ucans32k1sic/ucans32k1sic.yaml b/boards/arm/ucans32k1sic/ucans32k1sic.yaml index d4bf0d5065c..96926263e21 100644 --- a/boards/arm/ucans32k1sic/ucans32k1sic.yaml +++ b/boards/arm/ucans32k1sic/ucans32k1sic.yaml @@ -1,4 +1,4 @@ -# Copyright 2023 NXP +# Copyright 2023-2024 NXP # SPDX-License-Identifier: Apache-2.0 identifier: ucans32k1sic @@ -19,3 +19,4 @@ supported: - spi - pwm - can + - watchdog From cc3040aed6e28dcc553a489c8c71f6085c1ebf41 Mon Sep 17 00:00:00 2001 From: Armando Visconti Date: Thu, 18 Jan 2024 10:54:10 +0100 Subject: [PATCH 2850/3723] boards/shields: add support for x-nucleo-iks4a1 shield x-nucleo-iks4a1 shield is an arduino compatible companion board which can be used on top of Nucleo standard boards for industrial applications. Following MEMS sensor are currently supported: - LSM6DSO16IS: MEMS 3D accelerometer + 3D gyroscope - LSM6DSV16X: MEMS 3D accelerometer + 3D gyroscope - LIS2MDL: MEMS 3D magnetometer - LPS22DF: Low-power and high-precision MEMS pressure sensor (https://www.st.com/resource/en/data_brief/x-nucleo-iks4a1.pdf) The board exports three overlays: 1. x_nucleo_iks4a1.overlay (standard mode) All MEMS sensors are connected to micro-controller. 2. x_nucleo_iks4a1_shub1.overlay (HUB1 mode) LSM6DSV16X IMU sensor act as a sensor_hub with LIS2MDL and LPS22DF connected to it. 3. x_nucleo_iks4a1_shub2.overlay (HUB2 mode) LSM6DSO16IS IMU sensor act as a sensor_hub with LIS2MDL and LPS22DF connected to it. Signed-off-by: Armando Visconti --- boards/shields/x_nucleo_iks4a1/Kconfig.shield | 5 + .../doc/img/x-nucleo-iks4a1.jpg | Bin 0 -> 72304 bytes boards/shields/x_nucleo_iks4a1/doc/index.rst | 157 ++++++++++++++++++ .../x_nucleo_iks4a1/x_nucleo_iks4a1.overlay | 48 ++++++ .../x_nucleo_iks4a1_shub1.overlay | 22 +++ .../x_nucleo_iks4a1_shub2.overlay | 20 +++ 6 files changed, 252 insertions(+) create mode 100644 boards/shields/x_nucleo_iks4a1/Kconfig.shield create mode 100644 boards/shields/x_nucleo_iks4a1/doc/img/x-nucleo-iks4a1.jpg create mode 100644 boards/shields/x_nucleo_iks4a1/doc/index.rst create mode 100644 boards/shields/x_nucleo_iks4a1/x_nucleo_iks4a1.overlay create mode 100644 boards/shields/x_nucleo_iks4a1/x_nucleo_iks4a1_shub1.overlay create mode 100644 boards/shields/x_nucleo_iks4a1/x_nucleo_iks4a1_shub2.overlay diff --git a/boards/shields/x_nucleo_iks4a1/Kconfig.shield b/boards/shields/x_nucleo_iks4a1/Kconfig.shield new file mode 100644 index 00000000000..a7532594de0 --- /dev/null +++ b/boards/shields/x_nucleo_iks4a1/Kconfig.shield @@ -0,0 +1,5 @@ +# Copyright (c) 2024 STMicroelectronics +# SPDX-License-Identifier: Apache-2.0 + +config SHIELD_X_NUCLEO_IKS01A4 + def_bool $(shields_list_contains,x_nucleo_iks4a1) diff --git a/boards/shields/x_nucleo_iks4a1/doc/img/x-nucleo-iks4a1.jpg b/boards/shields/x_nucleo_iks4a1/doc/img/x-nucleo-iks4a1.jpg new file mode 100644 index 0000000000000000000000000000000000000000..2b631c634c4c8657a2a9ef143de7dfa9b669dd9b GIT binary patch literal 72304 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 literal 0 HcmV?d00001 diff --git a/boards/shields/x_nucleo_iks4a1/doc/index.rst b/boards/shields/x_nucleo_iks4a1/doc/index.rst new file mode 100644 index 00000000000..048cd089659 --- /dev/null +++ b/boards/shields/x_nucleo_iks4a1/doc/index.rst @@ -0,0 +1,157 @@ +.. _x-nucleo-iks4a1: + +X-NUCLEO-IKS4A1: MEMS Inertial and Environmental Multi sensor shield +#################################################################### + +Overview +******** +The X-NUCLEO-IKS4A1 is a motion MEMS and environmental sensor expansion board +for the STM32 Nucleo. It is equipped with Arduino UNO R3 connector layout, and +allows application development with features like sensor HUB (LSM6DSO16IS and +LSM6DSV16X), camera module integration and Qvar touch/swipe gestures (thanks to +the equipped electrode). + +.. image:: img/x-nucleo-iks4a1.jpg + :align: center + :alt: X-NUCLEO-IKS4A1 + +More general information about the board can be found at the +`X-NUCLEO-IKS4A1 website`_. + +Hardware Description +******************** + +X-NUCLEO-IKS4A1 provides the following key features: + + - LSM6DSO16IS: MEMS 3D accelerometer (±2/±4/±8/±16 g) + 3D gyroscope + (±125/±250/±500/±1000/±2000 dps) with ISPU (Intelligent Processing Unit) + - LIS2MDL: MEMS 3D magnetometer (±50 gauss) + - LIS2DUXS12: Ultra low-power MEMS 3D accelerometer (±2/±4/±8/±16 g) with + Qvar, AI, & anti-aliasing + - LPS22DF: Low-power and high-precision MEMS pressure sensor, 260-1260 hPa + absolute digital output barometer + - SHT40AD1B: High-accuracy, ultra-low-power relative humidity and temperature + sensor (by Sensirion) + - STTS22H: Low-voltage, ultralow-power, 0.5 °C accuracy temperature sensor + (–40 °C to +125 °C) + - LSM6DSV16X: MEMS 3D accelerometer (±2/±4/±8/±16 g) + 3D gyroscope + (±125/±250/±500/±1000/±2000/±4000 dps) with embedded sensor fusion, AI, Qvar + - DIL 24-pin socket available for additional MEMS adapters and other sensors + - Free comprehensive development firmware library and example for all sensors + compatible with STM32Cube firmware + - Equipped with Qvar touch/swipe electrode + - I²C sensor hub features on LSM6DSO and LSM6DSV16X available + - MIPI I3C® compatibility for communication with LIS2DUXS12, LSM6DSV16X and + LPS22DF + - Compatible with STM32 Nucleo boards + - Equipped with Arduino UNO R3 connector + - Equipped with industrial connector for IR sensor (STHS34PF80) application + development. It can be connected at the same time of external MEMS through + DIL24 adapter + - Available interface for external camera module applications coupled with + LSM6DSV16X through aux SPI (3/4 w) + - RoHS compliant + - WEEE compliant + - UKCA compliant + +Hardware Configuration +********************** + +X-NUCLEO-IKS4A1 board can be configured in five different modes, which can be +selected through J4 and J5 jumpers. Additional information about X-NUCLEO-IKS4A1 +configuration modes and how sensors are connected together can be found in the +`X-NUCLEO-IKS4A1 user manual`_ + +.. _x-nucleo-iks4a1-mode-1: + +Mode 1: Standard Mode +===================== + +In standard I2C mode, all devices are connected to an external main board via the +same I2C bus. + +The board configuration is: + + - J4: 1-2, 11-12 (STM_SDA = SENS_SDA, HUB_SDx = GND) + - J5: 1-2, 11-12 (STM_SCL = SENS_SCL, HUB_SCx = GND) + +.. _x-nucleo-iks4a1-mode-2: + +Mode 2: LSM6DSO16IS SensorHub Mode (SHUB2) +========================================== + +In this sensor hub I2C mode, it is possible to power-up the 6-axes IMU +(Inertial Measurement Unit) functionalities by collecting external data +through a direct control of the on-board environmental sensors (temperature, +pressure and magnetometer) and external sensor (DIL24) through the auxiliary +I2Cz bus "SENS_I2C". LSM6DSV16X, LIS2DUXS12 and SHT40AD1B remains connected +to the main bus "uC_I2C" coming from the external board. + +The board configuration is: + + - J4: 7-8 (HUB2_SDx = SENS_SDA) + - J5: 7-8 (HUB2_SCx = SENS_SCL) + +.. _x-nucleo-iks4a1-mode-3: + +Mode 3: LSM6DSV16X SensorHub Mode (SHUB1) +========================================= + +In this sensor hub, it is possible to power-up the 6-axes IMU (Inertial +Measurement Unit) functionalities by collecting external data through +a direct control of the on-board environmental sensors (temperature, +pressure and magnetometer) and external sensor (DIL24) through the auxiliary +I2C bus "SENS_I2C". LSM6DSO16IS, LIS2DUXS12 and SHT40AD1B remains connected +to the main bus "uC_I2C" coming from the external board. + +The board configuration is: + + - J4: 5-6 (HUB1_SDx = SENS_SDA) + - J5: 5-6 (HUB1_SDx = SENS_SDA) + +Mode 4: DIL24 SensorHub Mode +============================ + +In case a sensor with sensor hub embedded functionality is mounted to the +board through DIL24 adapter, it is possible to exploit this functionality +as for LSM6DSO16IS and the LSM6DSV16X. In this configuration, may be necessary +to connect the DIL24 to the external board through SPI lines in order to +avoid an address conflict on I2C bus with the LSM6DSO16IS and the LSM6DSV16X. +This is done by changing the SBx configuration. + +The board configuration is: + + - J4: 9-10 (DIL_SDx = SENS_SDA) + - J5: 9-10 (DIL_SDx = SENS_SDA) + +Mode 5: LSM6DSO16IS as Qvar controller +====================================== + +In this configuration, it is possible to use the equipped Qvar swipe electrode +(by plugging it on JP6 and JP7 connectors) through the LSM6DSO16IS. + +The board configuration is: + + - J4: 3-4 (HUB1_SDx = QVAR1) + - J5: 3-4 (HUB1_Scx = QVAR2) + +Devicetree Overlays +******************* + +There are three predefined DT overlays in the board: + +- :zephyr_file:`boards/shields/x_nucleo_iks4a1/x_nucleo_iks4a1.overlay` + This overlay describes sensor connections (and matching h/w configuration to be done) + as explained in Standard Mode (:ref:`x-nucleo-iks4a1-mode-1`) +- :zephyr_file:`boards/shields/x_nucleo_iks4a1/x_nucleo_iks4a1_shub1.overlay` + This overlay describes sensor connections (and matching h/w configuration to be done) + as explained in SHUB1 Mode (:ref:`x-nucleo-iks4a1-mode-3`) +- :zephyr_file:`boards/shields/x_nucleo_iks4a1/x_nucleo_iks4a1_shub2.overlay` + This overlay describes sensor connections (and matching h/w configuration to be done) + as explained in SHUB2 Mode (:ref:`x-nucleo-iks4a1-mode-2`) + +.. _X-NUCLEO-IKS4A1 website: + http://www.st.com/en/ecosystems/x-nucleo-iks4a1.html + +.. _X-NUCLEO-IKS4A1 user manual: + https://www.st.com/resource/en/user_manual/um3239-getting-started-with-the-xnucleoiks4a1-motion-mems-and-environmental-sensor-expansion-board-for-stm32-nucleo-stmicroelectronics.pdf diff --git a/boards/shields/x_nucleo_iks4a1/x_nucleo_iks4a1.overlay b/boards/shields/x_nucleo_iks4a1/x_nucleo_iks4a1.overlay new file mode 100644 index 00000000000..3cda8324777 --- /dev/null +++ b/boards/shields/x_nucleo_iks4a1/x_nucleo_iks4a1.overlay @@ -0,0 +1,48 @@ +/* + * Copyright (c) 2024 STMicroelectronics + * + * SPDX-License-Identifier: Apache-2.0 + */ + +/ { + aliases { + magn0 = &lis2mdl_1e_x_nucleo_iks4a1; + accel0 = &lsm6dso16is_6a_x_nucleo_iks4a1; + accel1 = &lsm6dsv16x_6b_x_nucleo_iks4a1; + press0 = &lps22df_5d_x_nucleo_iks4a1; + }; +}; + +&arduino_i2c { + lsm6dso16is_6a_x_nucleo_iks4a1: lsm6dso16is@6a { + compatible = "st,lsm6dso16is"; + reg = <0x6a>; + accel-odr = <0x1b>; + gyro-odr = <0x11>; + irq-gpios = <&arduino_header 5 GPIO_ACTIVE_HIGH>; /* A5 (PC0) */ + drdy-pin = <1>; + }; + + lsm6dsv16x_6b_x_nucleo_iks4a1: lsm6dsv16x@6b { + compatible = "st,lsm6dsv16x"; + reg = <0x6b>; + accel-odr = <0x02>; + gyro-odr = <0x02>; + int2-gpios = <&arduino_header 10 GPIO_ACTIVE_HIGH>; /* D4 (PB5) */ + drdy-pin = <2>; + drdy-pulsed; + }; + + lis2mdl_1e_x_nucleo_iks4a1: lis2mdl@1e { + compatible = "st,lis2mdl"; + reg = <0x1e>; + irq-gpios = <&arduino_header 2 GPIO_ACTIVE_HIGH>; /* A2 (PA4) */ + }; + + lps22df_5d_x_nucleo_iks4a1: lps22df@5d { + compatible = "st,lps22df"; + reg = <0x5d>; + drdy-pulsed; + drdy-gpios = <&arduino_header 12 GPIO_ACTIVE_HIGH>; /* D6 (PB10) */ + }; +}; diff --git a/boards/shields/x_nucleo_iks4a1/x_nucleo_iks4a1_shub1.overlay b/boards/shields/x_nucleo_iks4a1/x_nucleo_iks4a1_shub1.overlay new file mode 100644 index 00000000000..6560816c25c --- /dev/null +++ b/boards/shields/x_nucleo_iks4a1/x_nucleo_iks4a1_shub1.overlay @@ -0,0 +1,22 @@ +/* + * Copyright (c) 2024 STMicroelectronics + * + * SPDX-License-Identifier: Apache-2.0 + */ + +/ { + aliases { + accel0 = &lsm6dsv16x_6b_x_nucleo_iks4a1; + }; +}; + +&arduino_i2c { + lsm6dsv16x_6b_x_nucleo_iks4a1: lsm6dsv16x@6b { + compatible = "st,lsm6dsv16x"; + reg = <0x6b>; + accel-odr = <0x02>; + gyro-odr = <0x02>; + int1-gpios = <&arduino_header 11 GPIO_ACTIVE_HIGH>; /* D5 */ + drdy-pin = <1>; + }; +}; diff --git a/boards/shields/x_nucleo_iks4a1/x_nucleo_iks4a1_shub2.overlay b/boards/shields/x_nucleo_iks4a1/x_nucleo_iks4a1_shub2.overlay new file mode 100644 index 00000000000..6c259fb221b --- /dev/null +++ b/boards/shields/x_nucleo_iks4a1/x_nucleo_iks4a1_shub2.overlay @@ -0,0 +1,20 @@ +/* + * Copyright (c) 2024 STMicroelectronics + * + * SPDX-License-Identifier: Apache-2.0 + */ + +/ { + aliases { + accel0 = &lsm6dso16is_6a_x_nucleo_iks4a1_shub; + }; +}; + +&arduino_i2c { + lsm6dso16is_6a_x_nucleo_iks4a1_shub: lsm6dso16is@6a { + compatible = "st,lsm6dso16is"; + reg = <0x6a>; + irq-gpios = <&arduino_header 5 GPIO_ACTIVE_HIGH>; /* A5 */ + drdy-pin = <1>; + }; +}; From 9f1c256e46e65d8109561808b23ed7091e36b42a Mon Sep 17 00:00:00 2001 From: Armando Visconti Date: Thu, 18 Jan 2024 11:21:24 +0100 Subject: [PATCH 2851/3723] samples/shields: add samples to test x-nucleo-iks4a1 shield Provide three basic examples to test the x-nucleo-iks4a1 shield: - Test shield in standard mode Acquire sensor data from shield with all MEMS sensors connected to micro-controller - Test shield in HUB1 mode Acquire sensor data from shield with lis2mdl and lps22df connected to LSM6DSV16X sensor hub - Test shield in HUB2 mode Acquire sensor data from shield with lis2mdl and lps22df connected to LSm6DSO16IS sensor hub Signed-off-by: Armando Visconti --- boards/shields/x_nucleo_iks4a1/doc/index.rst | 15 + .../x_nucleo_iks4a1/sensorhub1/CMakeLists.txt | 14 + .../x_nucleo_iks4a1/sensorhub1/README.rst | 60 +++ .../x_nucleo_iks4a1/sensorhub1/prj.conf | 10 + .../x_nucleo_iks4a1/sensorhub1/sample.yaml | 12 + .../x_nucleo_iks4a1/sensorhub1/src/main.c | 190 ++++++++++ .../x_nucleo_iks4a1/sensorhub2/CMakeLists.txt | 14 + .../x_nucleo_iks4a1/sensorhub2/README.rst | 60 +++ .../x_nucleo_iks4a1/sensorhub2/prj.conf | 11 + .../x_nucleo_iks4a1/sensorhub2/sample.yaml | 13 + .../x_nucleo_iks4a1/sensorhub2/src/main.c | 190 ++++++++++ .../x_nucleo_iks4a1/standard/CMakeLists.txt | 14 + .../x_nucleo_iks4a1/standard/README.rst | 66 ++++ .../shields/x_nucleo_iks4a1/standard/prj.conf | 11 + .../x_nucleo_iks4a1/standard/sample.yaml | 16 + .../x_nucleo_iks4a1/standard/src/main.c | 358 ++++++++++++++++++ 16 files changed, 1054 insertions(+) create mode 100644 samples/shields/x_nucleo_iks4a1/sensorhub1/CMakeLists.txt create mode 100644 samples/shields/x_nucleo_iks4a1/sensorhub1/README.rst create mode 100644 samples/shields/x_nucleo_iks4a1/sensorhub1/prj.conf create mode 100644 samples/shields/x_nucleo_iks4a1/sensorhub1/sample.yaml create mode 100644 samples/shields/x_nucleo_iks4a1/sensorhub1/src/main.c create mode 100644 samples/shields/x_nucleo_iks4a1/sensorhub2/CMakeLists.txt create mode 100644 samples/shields/x_nucleo_iks4a1/sensorhub2/README.rst create mode 100644 samples/shields/x_nucleo_iks4a1/sensorhub2/prj.conf create mode 100644 samples/shields/x_nucleo_iks4a1/sensorhub2/sample.yaml create mode 100644 samples/shields/x_nucleo_iks4a1/sensorhub2/src/main.c create mode 100644 samples/shields/x_nucleo_iks4a1/standard/CMakeLists.txt create mode 100644 samples/shields/x_nucleo_iks4a1/standard/README.rst create mode 100644 samples/shields/x_nucleo_iks4a1/standard/prj.conf create mode 100644 samples/shields/x_nucleo_iks4a1/standard/sample.yaml create mode 100644 samples/shields/x_nucleo_iks4a1/standard/src/main.c diff --git a/boards/shields/x_nucleo_iks4a1/doc/index.rst b/boards/shields/x_nucleo_iks4a1/doc/index.rst index 048cd089659..a43492bf948 100644 --- a/boards/shields/x_nucleo_iks4a1/doc/index.rst +++ b/boards/shields/x_nucleo_iks4a1/doc/index.rst @@ -150,6 +150,21 @@ There are three predefined DT overlays in the board: This overlay describes sensor connections (and matching h/w configuration to be done) as explained in SHUB2 Mode (:ref:`x-nucleo-iks4a1-mode-2`) +Examples +******** + +Three samples are provided as examples for ``x-nucleo-iks4a1`` shield, each one associated +with one of the overlays described above: + +- :ref:`x-nucleo-iks4a1-std-sample` application, to be used when the shield is configured + in Standard Mode (Mode 1) +- :ref:`x-nucleo-iks4a1-shub1-sample` application, to be used when the shield is configured + in SHUB1 Mode (Mode 3) +- :ref:`x-nucleo-iks4a1-shub2-sample` application, to be used when the shield is configured + in SHUB2 Mode (Mode 2) + +See also :ref:`shields` for more details. + .. _X-NUCLEO-IKS4A1 website: http://www.st.com/en/ecosystems/x-nucleo-iks4a1.html diff --git a/samples/shields/x_nucleo_iks4a1/sensorhub1/CMakeLists.txt b/samples/shields/x_nucleo_iks4a1/sensorhub1/CMakeLists.txt new file mode 100644 index 00000000000..e901945a062 --- /dev/null +++ b/samples/shields/x_nucleo_iks4a1/sensorhub1/CMakeLists.txt @@ -0,0 +1,14 @@ +# Copyright (c) 2024 STMicroelectronics +# +# SPDX-License-Identifier: Apache-2.0 +# +cmake_minimum_required(VERSION 3.20.0) + +# This sample is specific to x_nucleo_iks4a1 shield. Enforce -DSHIELD option +set(SHIELD x_nucleo_iks4a1_shub1) + +find_package(Zephyr REQUIRED HINTS $ENV{ZEPHYR_BASE}) +project(x_nucleo_iks4a1) + +FILE(GLOB app_sources src/*.c) +target_sources(app PRIVATE ${app_sources}) diff --git a/samples/shields/x_nucleo_iks4a1/sensorhub1/README.rst b/samples/shields/x_nucleo_iks4a1/sensorhub1/README.rst new file mode 100644 index 00000000000..73296ce36ca --- /dev/null +++ b/samples/shields/x_nucleo_iks4a1/sensorhub1/README.rst @@ -0,0 +1,60 @@ +.. _x-nucleo-iks4a1-shub1-sample: + +X-NUCLEO-IKS4A1 shield SHUB1 (Mode 3) sample +############################################ + +Overview +******** +This sample is provided as an example to test the X-NUCLEO-IKS4A1 shield +configured in SHUB1 (Mode 3). +Please refer to :ref:`x-nucleo-iks4a1-mode-3` for more info on this configuration. + +This sample enables LSM6DSV16X IMU in sensorhub mode with LIS2MDL magnetometer and +LPS22DF pressure and temperature sensor. + +Then sensor data are displayed periodically + +- LSM6DSV16X 6-Axis acceleration and angular velocity +- LSM6DSV16X (from LIS2MDL) 3-Axis magnetic field intensity +- LSM6DSV16X (from LPS22DF) ambient temperature and atmospheric pressure + +Requirements +************ + +This sample communicates over I2C with the X-NUCLEO-IKS4A1 shield +stacked on a board with an Arduino connector, e.g. the +:ref:`nucleo_f411re_board` board. + +Building and Running +******************** + +This sample runs with X-NUCLEO-IKS4A1 stacked on any board with a matching +Arduino connector. For this example, we use a :ref:`nucleo_f411re_board` board. + +.. zephyr-app-commands:: + :zephyr-app: samples/shields/x_nucleo_iks4a1/sensorhub1/ + :host-os: unix + :board: nucleo_f411re + :goals: build flash + :compact: + +Sample Output +============= + + .. code-block:: console + + X-NUCLEO-IKS01A4 sensor dashboard + + LSM6DSV16X: Accel (m.s-2): x: 0.081, y: -0.177, z: 9.945 + LSM6DSV16X: GYro (dps): x: 0.001, y: -0.000, z: 0.004 + LSM6DSV16X: Magn (gauss): x: 0.217, y: 0.015, z: -0.415 + LSM6DSV16X: Temperature: 19.8 C + LSM6DSV16X: Pressure:99.655 kpa + 16:: lsm6dso16is acc trig 6432 + + + +References +********** + +:ref:`x-nucleo-iks4a1` diff --git a/samples/shields/x_nucleo_iks4a1/sensorhub1/prj.conf b/samples/shields/x_nucleo_iks4a1/sensorhub1/prj.conf new file mode 100644 index 00000000000..f7af0f8fe0f --- /dev/null +++ b/samples/shields/x_nucleo_iks4a1/sensorhub1/prj.conf @@ -0,0 +1,10 @@ +CONFIG_LOG=y +CONFIG_STDOUT_CONSOLE=y +CONFIG_I2C=y +CONFIG_SENSOR=y +CONFIG_SENSOR_LOG_LEVEL_DBG=y +CONFIG_LSM6DSV16X_TRIGGER_OWN_THREAD=y +CONFIG_LSM6DSV16X_SENSORHUB=y +CONFIG_LSM6DSV16X_EXT_LIS2MDL=y +CONFIG_LSM6DSV16X_EXT_LPS22DF=y +CONFIG_CBPRINTF_FP_SUPPORT=y diff --git a/samples/shields/x_nucleo_iks4a1/sensorhub1/sample.yaml b/samples/shields/x_nucleo_iks4a1/sensorhub1/sample.yaml new file mode 100644 index 00000000000..bec5bda73ff --- /dev/null +++ b/samples/shields/x_nucleo_iks4a1/sensorhub1/sample.yaml @@ -0,0 +1,12 @@ +sample: + name: X-NUCLEO-IKS01A4 sensor shield +tests: + sample.shields.x_nucleo_iks4a1.sensorhub1: + harness: shield + tags: shield + depends_on: arduino_i2c arduino_gpio + platform_exclude: + - disco_l475_iot1 + - lpcxpresso55s16 + - mimxrt1010_evk + - stm32mp157c_dk2 diff --git a/samples/shields/x_nucleo_iks4a1/sensorhub1/src/main.c b/samples/shields/x_nucleo_iks4a1/sensorhub1/src/main.c new file mode 100644 index 00000000000..0454a75dd90 --- /dev/null +++ b/samples/shields/x_nucleo_iks4a1/sensorhub1/src/main.c @@ -0,0 +1,190 @@ +/* + * Copyright (c) 2019 STMicroelectronics + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include +#include +#include +#include +#include + +#ifdef CONFIG_LSM6DSV16X_TRIGGER +static int lsm6dsv16x_acc_trig_cnt; + +static void lsm6dsv16x_acc_trig_handler(const struct device *dev, + const struct sensor_trigger *trig) +{ + sensor_sample_fetch_chan(dev, SENSOR_CHAN_ALL); + lsm6dsv16x_acc_trig_cnt++; +} +#endif + +static void lsm6dsv16x_config(const struct device *lsm6dsv16x) +{ + struct sensor_value odr_attr, fs_attr; + + /* set LSM6DSV16X accel sampling frequency to 208 Hz */ + odr_attr.val1 = 208; + odr_attr.val2 = 0; + + if (sensor_attr_set(lsm6dsv16x, SENSOR_CHAN_ACCEL_XYZ, + SENSOR_ATTR_SAMPLING_FREQUENCY, &odr_attr) < 0) { + printk("Cannot set sampling frequency for LSM6DSV16X accel\n"); + return; + } + + sensor_g_to_ms2(16, &fs_attr); + + if (sensor_attr_set(lsm6dsv16x, SENSOR_CHAN_ACCEL_XYZ, + SENSOR_ATTR_FULL_SCALE, &fs_attr) < 0) { + printk("Cannot set full scale for LSM6DSV16X accel\n"); + return; + } + + /* set LSM6DSV16X gyro sampling frequency to 208 Hz */ + odr_attr.val1 = 208; + odr_attr.val2 = 0; + + if (sensor_attr_set(lsm6dsv16x, SENSOR_CHAN_GYRO_XYZ, + SENSOR_ATTR_SAMPLING_FREQUENCY, &odr_attr) < 0) { + printk("Cannot set sampling frequency for LSM6DSV16X gyro\n"); + return; + } + + sensor_degrees_to_rad(250, &fs_attr); + + if (sensor_attr_set(lsm6dsv16x, SENSOR_CHAN_GYRO_XYZ, + SENSOR_ATTR_FULL_SCALE, &fs_attr) < 0) { + printk("Cannot set full scale for LSM6DSV16X gyro\n"); + return; + } + + /* set LSM6DSV16X external magn sampling frequency to 100 Hz */ + odr_attr.val1 = 100; + odr_attr.val2 = 0; + +#ifdef CONFIG_LSM6DSV16X_EXT_LIS2MDL + if (sensor_attr_set(lsm6dsv16x, SENSOR_CHAN_MAGN_XYZ, + SENSOR_ATTR_SAMPLING_FREQUENCY, &odr_attr) < 0) { + printk("Cannot set sampling frequency for LSM6DSV16X ext magn\n"); + } +#endif + +#ifdef CONFIG_LSM6DSV16X_EXT_LPS22DF + if (sensor_attr_set(lsm6dsv16x, SENSOR_CHAN_PRESS, + SENSOR_ATTR_SAMPLING_FREQUENCY, &odr_attr) < 0) { + printk("Cannot set sampling frequency for LSM6DSV16X ext pressure\n"); + } +#endif + +#ifdef CONFIG_LSM6DSV16X_EXT_HTS221 + odr_attr.val1 = 12; + if (sensor_attr_set(lsm6dsv16x, SENSOR_CHAN_HUMIDITY, + SENSOR_ATTR_SAMPLING_FREQUENCY, &odr_attr) < 0) { + printk("Cannot set sampling frequency for LSM6DSV16X ext humidity\n"); + } +#endif + +#ifdef CONFIG_LSM6DSV16X_TRIGGER + struct sensor_trigger trig; + + trig.type = SENSOR_TRIG_DATA_READY; + trig.chan = SENSOR_CHAN_ACCEL_XYZ; + sensor_trigger_set(lsm6dsv16x, &trig, lsm6dsv16x_acc_trig_handler); +#endif +} + +int main(void) +{ + struct sensor_value lsm6dsv16x_xl[3], lsm6dsv16x_gy[3]; +#ifdef CONFIG_LSM6DSV16X_ENABLE_TEMP + struct sensor_value lsm6dsv16x_temp; +#endif +#ifdef CONFIG_LSM6DSV16X_EXT_LIS2MDL + struct sensor_value lis2mdl_magn[3]; +#endif +#ifdef CONFIG_LSM6DSV16X_EXT_LPS22DF + struct sensor_value lps22df_press; + struct sensor_value lps22df_temp; +#endif + const struct device *const lsm6dsv16x = DEVICE_DT_GET_ONE(st_lsm6dsv16x); + int cnt = 1; + + if (!device_is_ready(lsm6dsv16x)) { + printk("%s: device not ready.\n", lsm6dsv16x->name); + return 0; + } + + lsm6dsv16x_config(lsm6dsv16x); + + while (1) { + /* Get sensor samples */ +#ifndef CONFIG_LSM6DSV16X_TRIGGER + if (sensor_sample_fetch(lsm6dsv16x) < 0) { + printf("LSM6DSV16X Sensor sample update error\n"); + return 0; + } +#endif + + /* Get sensor data */ + sensor_channel_get(lsm6dsv16x, SENSOR_CHAN_ACCEL_XYZ, lsm6dsv16x_xl); + sensor_channel_get(lsm6dsv16x, SENSOR_CHAN_GYRO_XYZ, lsm6dsv16x_gy); +#ifdef CONFIG_LSM6DSV16X_ENABLE_TEMP + sensor_channel_get(lsm6dsv16x, SENSOR_CHAN_DIE_TEMP, &lsm6dsv16x_temp); +#endif +#ifdef CONFIG_LSM6DSV16X_EXT_LIS2MDL + sensor_channel_get(lsm6dsv16x, SENSOR_CHAN_MAGN_XYZ, lis2mdl_magn); +#endif +#ifdef CONFIG_LSM6DSV16X_EXT_LPS22DF + sensor_channel_get(lsm6dsv16x, SENSOR_CHAN_AMBIENT_TEMP, &lps22df_temp); + sensor_channel_get(lsm6dsv16x, SENSOR_CHAN_PRESS, &lps22df_press); +#endif + + /* Display sensor data */ + + /* Erase previous */ + printf("\0033\014"); + + printf("X-NUCLEO-IKS01A4 sensor dashboard\n\n"); + + printf("LSM6DSV16X: Accel (m.s-2): x: %.3f, y: %.3f, z: %.3f\n", + sensor_value_to_double(&lsm6dsv16x_xl[0]), + sensor_value_to_double(&lsm6dsv16x_xl[1]), + sensor_value_to_double(&lsm6dsv16x_xl[2])); + + printf("LSM6DSV16X: Gyro (dps): x: %.3f, y: %.3f, z: %.3f\n", + sensor_value_to_double(&lsm6dsv16x_gy[0]), + sensor_value_to_double(&lsm6dsv16x_gy[1]), + sensor_value_to_double(&lsm6dsv16x_gy[2])); + +#ifdef CONFIG_LSM6DSV16X_ENABLE_TEMP + /* temperature */ + printf("LSM6DSV16X: Temperature: %.1f C\n", + sensor_value_to_double(&lsm6dsv16x_temp)); +#endif + +#ifdef CONFIG_LSM6DSV16X_EXT_LIS2MDL + printf("LSM6DSV16X: Magn (gauss): x: %.3f, y: %.3f, z: %.3f\n", + sensor_value_to_double(&lis2mdl_magn[0]), + sensor_value_to_double(&lis2mdl_magn[1]), + sensor_value_to_double(&lis2mdl_magn[2])); +#endif + +#ifdef CONFIG_LSM6DSV16X_EXT_LPS22DF + printf("LSM6DSV16X: Temperature: %.1f C\n", + sensor_value_to_double(&lps22df_temp)); + + printf("LSM6DSV16X: Pressure:%.3f kpa\n", + sensor_value_to_double(&lps22df_press)); +#endif + +#ifdef CONFIG_LSM6DSV16X_TRIGGER + printk("%d: lsm6dsv16x acc trig %d\n", cnt, lsm6dsv16x_acc_trig_cnt); +#endif + + cnt++; + k_sleep(K_MSEC(2000)); + } +} diff --git a/samples/shields/x_nucleo_iks4a1/sensorhub2/CMakeLists.txt b/samples/shields/x_nucleo_iks4a1/sensorhub2/CMakeLists.txt new file mode 100644 index 00000000000..9ad8c2e6b01 --- /dev/null +++ b/samples/shields/x_nucleo_iks4a1/sensorhub2/CMakeLists.txt @@ -0,0 +1,14 @@ +# Copyright (c) 2024 STMicroelectronics +# +# SPDX-License-Identifier: Apache-2.0 +# +cmake_minimum_required(VERSION 3.20.0) + +# This sample is specific to x_nucleo_iks4a1 shield. Enforce -DSHIELD option +set(SHIELD x_nucleo_iks4a1_shub2) + +find_package(Zephyr REQUIRED HINTS $ENV{ZEPHYR_BASE}) +project(x_nucleo_iks4a1) + +FILE(GLOB app_sources src/*.c) +target_sources(app PRIVATE ${app_sources}) diff --git a/samples/shields/x_nucleo_iks4a1/sensorhub2/README.rst b/samples/shields/x_nucleo_iks4a1/sensorhub2/README.rst new file mode 100644 index 00000000000..9fc28a45b57 --- /dev/null +++ b/samples/shields/x_nucleo_iks4a1/sensorhub2/README.rst @@ -0,0 +1,60 @@ +.. _x-nucleo-iks4a1-shub2-sample: + +X-NUCLEO-IKS4A1: shield SHUB2 (Mode 2) sample +############################################# + +Overview +******** +This sample is provided as an example to test the X-NUCLEO-IKS4A1 shield +configured in Sensor Hub mode (Mode 2). +Please refer to :ref:`x-nucleo-iks4a1-mode-2` for more info on this configuration. + +This sample enables LSM6DSO16IS IMU in sensorhub mode with LIS2MDL magnetometer and +LPS22DF pressure and temperature sensor. + +Then sensor data are displayed periodically + +- LSM6DSO16IS 6-Axis acceleration and angular velocity +- LSM6DSO16IS (from LIS2MDL) 3-Axis magnetic field intensity +- LSM6DSO16IS (from LPS22DF) ambient temperature and atmospheric pressure + +Requirements +************ + +This sample communicates over I2C with the X-NUCLEO-IKS4A1 shield +stacked on a board with an Arduino connector, e.g. the +:ref:`nucleo_f411re_board` board. + +Building and Running +******************** + +This sample runs with X-NUCLEO-IKS4A1 stacked on any board with a matching +Arduino connector. For this example, we use a :ref:`nucleo_f411re_board` board. + +.. zephyr-app-commands:: + :zephyr-app: samples/shields/x_nucleo_iks4a1/sensorhub2/ + :host-os: unix + :board: nucleo_f411re + :goals: build flash + :compact: + +Sample Output +============= + + .. code-block:: console + + X-NUCLEO-IKS01A4 sensor dashboard + + LSM6DSO16IS: Accel (m.s-2): x: 0.081, y: -0.177, z: 9.945 + LSM6DSO16IS: GYro (dps): x: 0.001, y: -0.000, z: 0.004 + LSM6DSO16IS: Magn (gauss): x: 0.217, y: 0.015, z: -0.415 + LSM6DSO16IS: Temperature: 20.8 C + LSM6DSO16IS: Pressure:99.756 kpa + 736:: lsm6dso16is acc trig 314944 + + + +References +********** + +:ref:`x-nucleo-iks4a1` diff --git a/samples/shields/x_nucleo_iks4a1/sensorhub2/prj.conf b/samples/shields/x_nucleo_iks4a1/sensorhub2/prj.conf new file mode 100644 index 00000000000..8637d6b6c1a --- /dev/null +++ b/samples/shields/x_nucleo_iks4a1/sensorhub2/prj.conf @@ -0,0 +1,11 @@ +CONFIG_LOG=y +CONFIG_STDOUT_CONSOLE=y +CONFIG_I2C=y +CONFIG_SENSOR=y +CONFIG_SENSOR_LOG_LEVEL_DBG=y +CONFIG_LSM6DSO16IS_ENABLE_TEMP=n +CONFIG_LSM6DSO16IS_TRIGGER_OWN_THREAD=y +CONFIG_LSM6DSO16IS_SENSORHUB=y +CONFIG_LSM6DSO16IS_EXT_LIS2MDL=y +CONFIG_LSM6DSO16IS_EXT_LPS22DF=y +CONFIG_CBPRINTF_FP_SUPPORT=y diff --git a/samples/shields/x_nucleo_iks4a1/sensorhub2/sample.yaml b/samples/shields/x_nucleo_iks4a1/sensorhub2/sample.yaml new file mode 100644 index 00000000000..1931d2aaa4a --- /dev/null +++ b/samples/shields/x_nucleo_iks4a1/sensorhub2/sample.yaml @@ -0,0 +1,13 @@ +sample: + name: X-NUCLEO-IKS01A4 sensor shield +tests: + sample.shields.x_nucleo_iks4a1.sensorhub2: + harness: shield + tags: shield + depends_on: arduino_i2c arduino_gpio + platform_exclude: + - disco_l475_iot1 + - lpcxpresso55s16 + - pan1781_evb + - pan1782_evb + - stm32mp157c_dk2 diff --git a/samples/shields/x_nucleo_iks4a1/sensorhub2/src/main.c b/samples/shields/x_nucleo_iks4a1/sensorhub2/src/main.c new file mode 100644 index 00000000000..e4351acb360 --- /dev/null +++ b/samples/shields/x_nucleo_iks4a1/sensorhub2/src/main.c @@ -0,0 +1,190 @@ +/* + * Copyright (c) 2024 STMicroelectronics + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include +#include +#include +#include +#include + +#ifdef CONFIG_LSM6DSO16IS_TRIGGER +static int lsm6dso16is_acc_trig_cnt; + +static void lsm6dso16is_acc_trig_handler(const struct device *dev, + const struct sensor_trigger *trig) +{ + sensor_sample_fetch_chan(dev, SENSOR_CHAN_ALL); + lsm6dso16is_acc_trig_cnt++; +} +#endif + +static void lsm6dso16is_config(const struct device *lsm6dso16is) +{ + struct sensor_value odr_attr, fs_attr; + + /* set LSM6DSO16IS accel sampling frequency to 208 Hz */ + odr_attr.val1 = 208; + odr_attr.val2 = 0; + + if (sensor_attr_set(lsm6dso16is, SENSOR_CHAN_ACCEL_XYZ, + SENSOR_ATTR_SAMPLING_FREQUENCY, &odr_attr) < 0) { + printk("Cannot set sampling frequency for LSM6DSO16IS accel\n"); + return; + } + + sensor_g_to_ms2(16, &fs_attr); + + if (sensor_attr_set(lsm6dso16is, SENSOR_CHAN_ACCEL_XYZ, + SENSOR_ATTR_FULL_SCALE, &fs_attr) < 0) { + printk("Cannot set full scale for LSM6DSO16IS accel\n"); + return; + } + + /* set LSM6DSO16IS gyro sampling frequency to 208 Hz */ + odr_attr.val1 = 208; + odr_attr.val2 = 0; + + if (sensor_attr_set(lsm6dso16is, SENSOR_CHAN_GYRO_XYZ, + SENSOR_ATTR_SAMPLING_FREQUENCY, &odr_attr) < 0) { + printk("Cannot set sampling frequency for LSM6DSO16IS gyro\n"); + return; + } + + sensor_degrees_to_rad(250, &fs_attr); + + if (sensor_attr_set(lsm6dso16is, SENSOR_CHAN_GYRO_XYZ, + SENSOR_ATTR_FULL_SCALE, &fs_attr) < 0) { + printk("Cannot set full scale for LSM6DSO16IS gyro\n"); + return; + } + + /* set LSM6DSO16IS external magn sampling frequency to 100 Hz */ + odr_attr.val1 = 100; + odr_attr.val2 = 0; + +#ifdef CONFIG_LSM6DSO16IS_EXT_LIS2MDL + if (sensor_attr_set(lsm6dso16is, SENSOR_CHAN_MAGN_XYZ, + SENSOR_ATTR_SAMPLING_FREQUENCY, &odr_attr) < 0) { + printk("Cannot set sampling frequency for LSM6DSO16IS ext magn\n"); + } +#endif + +#ifdef CONFIG_LSM6DSO16IS_EXT_LPS22DF + if (sensor_attr_set(lsm6dso16is, SENSOR_CHAN_PRESS, + SENSOR_ATTR_SAMPLING_FREQUENCY, &odr_attr) < 0) { + printk("Cannot set sampling frequency for LSM6DSO16IS ext pressure\n"); + } +#endif + +#ifdef CONFIG_LSM6DSO16IS_EXT_HTS221 + odr_attr.val1 = 12; + if (sensor_attr_set(lsm6dso16is, SENSOR_CHAN_HUMIDITY, + SENSOR_ATTR_SAMPLING_FREQUENCY, &odr_attr) < 0) { + printk("Cannot set sampling frequency for LSM6DSO16IS ext humidity\n"); + } +#endif + +#ifdef CONFIG_LSM6DSO16IS_TRIGGER + struct sensor_trigger trig; + + trig.type = SENSOR_TRIG_DATA_READY; + trig.chan = SENSOR_CHAN_ACCEL_XYZ; + sensor_trigger_set(lsm6dso16is, &trig, lsm6dso16is_acc_trig_handler); +#endif +} + +int main(void) +{ + struct sensor_value lsm6dso16is_xl[3], lsm6dso16is_gy[3]; +#ifdef CONFIG_LSM6DSO16IS_ENABLE_TEMP + struct sensor_value lsm6dso16is_temp; +#endif +#ifdef CONFIG_LSM6DSO16IS_EXT_LIS2MDL + struct sensor_value lis2mdl_magn[3]; +#endif +#ifdef CONFIG_LSM6DSO16IS_EXT_LPS22DF + struct sensor_value lps22df_press; + struct sensor_value lps22df_temp; +#endif + const struct device *const lsm6dso16is = DEVICE_DT_GET_ONE(st_lsm6dso16is); + int cnt = 1; + + if (!device_is_ready(lsm6dso16is)) { + printk("%s: device not ready.\n", lsm6dso16is->name); + return 0; + } + + lsm6dso16is_config(lsm6dso16is); + + while (1) { + /* Get sensor samples */ +#ifndef CONFIG_LSM6DSO16IS_TRIGGER + if (sensor_sample_fetch(lsm6dso16is) < 0) { + printf("LSM6DSO16IS Sensor sample update error\n"); + return 0; + } +#endif + + /* Get sensor data */ + sensor_channel_get(lsm6dso16is, SENSOR_CHAN_ACCEL_XYZ, lsm6dso16is_xl); + sensor_channel_get(lsm6dso16is, SENSOR_CHAN_GYRO_XYZ, lsm6dso16is_gy); +#ifdef CONFIG_LSM6DSO16IS_ENABLE_TEMP + sensor_channel_get(lsm6dso16is, SENSOR_CHAN_DIE_TEMP, &lsm6dso16is_temp); +#endif +#ifdef CONFIG_LSM6DSO16IS_EXT_LIS2MDL + sensor_channel_get(lsm6dso16is, SENSOR_CHAN_MAGN_XYZ, lis2mdl_magn); +#endif +#ifdef CONFIG_LSM6DSO16IS_EXT_LPS22DF + sensor_channel_get(lsm6dso16is, SENSOR_CHAN_AMBIENT_TEMP, &lps22df_temp); + sensor_channel_get(lsm6dso16is, SENSOR_CHAN_PRESS, &lps22df_press); +#endif + + /* Display sensor data */ + + /* Erase previous */ + printf("\0033\014"); + + printf("X-NUCLEO-IKS01A4 sensor dashboard\n\n"); + + printf("LSM6DSO16IS: Accel (m.s-2): x: %.3f, y: %.3f, z: %.3f\n", + sensor_value_to_double(&lsm6dso16is_xl[0]), + sensor_value_to_double(&lsm6dso16is_xl[1]), + sensor_value_to_double(&lsm6dso16is_xl[2])); + + printf("LSM6DSO16IS: Gyro (dps): x: %.3f, y: %.3f, z: %.3f\n", + sensor_value_to_double(&lsm6dso16is_gy[0]), + sensor_value_to_double(&lsm6dso16is_gy[1]), + sensor_value_to_double(&lsm6dso16is_gy[2])); + +#ifdef CONFIG_LSM6DSO16IS_ENABLE_TEMP + /* temperature */ + printf("LSM6DSO16IS: Temperature: %.1f C\n", + sensor_value_to_double(&lsm6dso16is_temp)); +#endif + +#ifdef CONFIG_LSM6DSO16IS_EXT_LIS2MDL + printf("LSM6DSO16IS: Magn (gauss): x: %.3f, y: %.3f, z: %.3f\n", + sensor_value_to_double(&lis2mdl_magn[0]), + sensor_value_to_double(&lis2mdl_magn[1]), + sensor_value_to_double(&lis2mdl_magn[2])); +#endif + +#ifdef CONFIG_LSM6DSO16IS_EXT_LPS22DF + printf("LSM6DSO16IS: Temperature: %.1f C\n", + sensor_value_to_double(&lps22df_temp)); + + printf("LSM6DSO16IS: Pressure:%.3f kpa\n", + sensor_value_to_double(&lps22df_press)); +#endif + +#ifdef CONFIG_LSM6DSO16IS_TRIGGER + printk("%d: lsm6dso16is acc trig %d\n", cnt, lsm6dso16is_acc_trig_cnt); +#endif + + cnt++; + k_sleep(K_MSEC(2000)); + } +} diff --git a/samples/shields/x_nucleo_iks4a1/standard/CMakeLists.txt b/samples/shields/x_nucleo_iks4a1/standard/CMakeLists.txt new file mode 100644 index 00000000000..1e8a99f3f81 --- /dev/null +++ b/samples/shields/x_nucleo_iks4a1/standard/CMakeLists.txt @@ -0,0 +1,14 @@ +# Copyright (c) 2024 STMicroelectronics +# +# SPDX-License-Identifier: Apache-2.0 +# +cmake_minimum_required(VERSION 3.20.0) + +# This sample is specific to x_nucleo_iks4a1 shield. Enforce -DSHIELD option +set(SHIELD x_nucleo_iks4a1) + +find_package(Zephyr REQUIRED HINTS $ENV{ZEPHYR_BASE}) +project(x_nucleo_iks4a1) + +FILE(GLOB app_sources src/*.c) +target_sources(app PRIVATE ${app_sources}) diff --git a/samples/shields/x_nucleo_iks4a1/standard/README.rst b/samples/shields/x_nucleo_iks4a1/standard/README.rst new file mode 100644 index 00000000000..0dfc2651da7 --- /dev/null +++ b/samples/shields/x_nucleo_iks4a1/standard/README.rst @@ -0,0 +1,66 @@ +.. _x-nucleo-iks4a1-std-sample: + +X-NUCLEO-IKS4A1 shield Standard (Mode 1) sample +############################################### + +Overview +******** +This sample is provided as an example to test the X-NUCLEO-IKS4A1 shield +configured in Standard mode (Mode 1). +Please refer to :ref:`x-nucleo-iks4a1-mode-1` for more info on this configuration. + +This sample enables the following four sensors of a X-NUCLEO-IKS4A1 shield, and then +periodically reads and displays data from the shield sensors: + +- LSM6DSV16X 6-Axis acceleration and angular velocity +- LSM6DSO16IS 6-Axis acceleration and angular velocity +- LPS22DF ambient temperature and atmospheric pressure +- LIS2MDL 3-Axis magnetic field intensity + +Requirements +************ + +This sample communicates over I2C with the X-NUCLEO-IKS4A1 shield +stacked on a board with an Arduino connector, e.g. the +:ref:`nucleo_f411re_board` board. + +Building and Running +******************** + +This sample runs with X-NUCLEO-IKS4A1 stacked on any board with a matching +Arduino connector. For this example, we use a :ref:`nucleo_f411re_board` board. + +.. zephyr-app-commands:: + :zephyr-app: samples/shields/x_nucleo_iks4a1/standard/ + :host-os: unix + :board: nucleo_f411re + :goals: build flash + :compact: + +Sample Output +============= + + .. code-block:: console + + X-NUCLEO-IKS4A1 sensor dashboard + + LIS2MDL: Magn (gauss): x: -0.364, y: -0.523, z: -0.399 + LIS2MDL: Temperature: 22.4 C + LSM6DSO16IS: Accel (m.s-2): x: -0.167, y: -0.249, z: 9.954 + LSM6DSO16IS: GYro (dps): x: 0.047, y: -0.052, z: -0.042 + LSM6DSO16IS: Temperature: 25.8 C + LSM6DSV16X: Accel (m.s-2): x: 0.005, y: 0.053, z: 9.930 + LSM6DSV16X: GYro (dps): x: -0.000, y: 0.000, z: 0.005 + LPS22DF: Temperature: 25.2 C + LPS22DF: Pressure:98.121 kpa + 10:: lis2mdl trig 1839 + 10:: lsm6dso16is acc trig 3892 + 10:: lsm6dsv16x acc trig 4412 + 10:: lps22df trig 174 + + + +References +********** + +:ref:`x-nucleo-iks4a1` diff --git a/samples/shields/x_nucleo_iks4a1/standard/prj.conf b/samples/shields/x_nucleo_iks4a1/standard/prj.conf new file mode 100644 index 00000000000..2e9e206de76 --- /dev/null +++ b/samples/shields/x_nucleo_iks4a1/standard/prj.conf @@ -0,0 +1,11 @@ +CONFIG_LOG=y +CONFIG_STDOUT_CONSOLE=y +CONFIG_I2C=y +CONFIG_SENSOR=y +CONFIG_SENSOR_LOG_LEVEL_DBG=y +CONFIG_LIS2MDL_TRIGGER_OWN_THREAD=y +CONFIG_LPS2XDF_TRIGGER_OWN_THREAD=y +CONFIG_LSM6DSO16IS_TRIGGER_OWN_THREAD=y +CONFIG_LSM6DSO16IS_ENABLE_TEMP=y +CONFIG_LSM6DSV16X_TRIGGER_OWN_THREAD=y +CONFIG_CBPRINTF_FP_SUPPORT=y diff --git a/samples/shields/x_nucleo_iks4a1/standard/sample.yaml b/samples/shields/x_nucleo_iks4a1/standard/sample.yaml new file mode 100644 index 00000000000..54a66edb45a --- /dev/null +++ b/samples/shields/x_nucleo_iks4a1/standard/sample.yaml @@ -0,0 +1,16 @@ +sample: + name: X-NUCLEO-IKS01A4 sensor shield +common: + min_ram: 16 +tests: + sample.shields.x_nucleo_iks4a1.standard: + harness: shield + tags: shield + depends_on: arduino_i2c arduino_gpio + platform_exclude: + - disco_l475_iot1 + - lpcxpresso55s16 + - mimxrt1010_evk + - pan1781_evb + - pan1782_evb + - stm32mp157c_dk2 diff --git a/samples/shields/x_nucleo_iks4a1/standard/src/main.c b/samples/shields/x_nucleo_iks4a1/standard/src/main.c new file mode 100644 index 00000000000..15ac7805452 --- /dev/null +++ b/samples/shields/x_nucleo_iks4a1/standard/src/main.c @@ -0,0 +1,358 @@ +/* + * Copyright (c) 2024 STMicroelectronics + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include +#include +#include +#include +#include + +#ifdef CONFIG_LPS2XDF_TRIGGER +static int lps22df_trig_cnt; + +static void lps22df_trigger_handler(const struct device *dev, + const struct sensor_trigger *trig) +{ + sensor_sample_fetch_chan(dev, SENSOR_CHAN_ALL); + lps22df_trig_cnt++; +} +#endif + +#ifdef CONFIG_LIS2MDL_TRIGGER +static int lis2mdl_trig_cnt; + +static void lis2mdl_trigger_handler(const struct device *dev, + const struct sensor_trigger *trig) +{ + sensor_sample_fetch_chan(dev, SENSOR_CHAN_ALL); + lis2mdl_trig_cnt++; +} +#endif + +#ifdef CONFIG_LSM6DSO16IS_TRIGGER +static int lsm6dso16is_acc_trig_cnt; + +static void lsm6dso16is_acc_trig_handler(const struct device *dev, + const struct sensor_trigger *trig) +{ + sensor_sample_fetch_chan(dev, SENSOR_CHAN_ALL); + lsm6dso16is_acc_trig_cnt++; +} +#endif + +#ifdef CONFIG_LSM6DSV16X_TRIGGER +static int lsm6dsv16x_acc_trig_cnt; + +static void lsm6dsv16x_acc_trig_handler(const struct device *dev, + const struct sensor_trigger *trig) +{ + sensor_sample_fetch_chan(dev, SENSOR_CHAN_ALL); + lsm6dsv16x_acc_trig_cnt++; +} +#endif + +static void lis2mdl_config(const struct device *lis2mdl) +{ + struct sensor_value odr_attr; + + /* set LIS2MDL sampling frequency to 100 Hz */ + odr_attr.val1 = 100; + odr_attr.val2 = 0; + + if (sensor_attr_set(lis2mdl, SENSOR_CHAN_ALL, + SENSOR_ATTR_SAMPLING_FREQUENCY, &odr_attr) < 0) { + printk("Cannot set sampling frequency for LIS2MDL\n"); + return; + } + +#ifdef CONFIG_LIS2MDL_TRIGGER + struct sensor_trigger trig; + + trig.type = SENSOR_TRIG_DATA_READY; + trig.chan = SENSOR_CHAN_MAGN_XYZ; + sensor_trigger_set(lis2mdl, &trig, lis2mdl_trigger_handler); +#endif +} + +static void lsm6dso16is_config(const struct device *lsm6dso16is) +{ + struct sensor_value odr_attr, fs_attr, mode_attr; + + mode_attr.val1 = 0; /* HP */ + + if (sensor_attr_set(lsm6dso16is, SENSOR_CHAN_ACCEL_XYZ, + SENSOR_ATTR_CONFIGURATION, &mode_attr) < 0) { + printk("Cannot set mode for LSM6DSO16IS accel\n"); + return; + } + + /* set LSM6DSO16IS accel sampling frequency to 208 Hz */ + odr_attr.val1 = 208; + odr_attr.val2 = 0; + + if (sensor_attr_set(lsm6dso16is, SENSOR_CHAN_ACCEL_XYZ, + SENSOR_ATTR_SAMPLING_FREQUENCY, &odr_attr) < 0) { + printk("Cannot set sampling frequency for LSM6DSO16IS accel\n"); + return; + } + + sensor_g_to_ms2(16, &fs_attr); + + if (sensor_attr_set(lsm6dso16is, SENSOR_CHAN_ACCEL_XYZ, + SENSOR_ATTR_FULL_SCALE, &fs_attr) < 0) { + printk("Cannot set full scale for LSM6DSO16IS accel\n"); + return; + } + + /* set LSM6DSO16IS gyro sampling frequency to 208 Hz */ + odr_attr.val1 = 208; + odr_attr.val2 = 0; + + if (sensor_attr_set(lsm6dso16is, SENSOR_CHAN_GYRO_XYZ, + SENSOR_ATTR_SAMPLING_FREQUENCY, &odr_attr) < 0) { + printk("Cannot set sampling frequency for LSM6DSO16IS gyro\n"); + return; + } + + sensor_degrees_to_rad(250, &fs_attr); + + if (sensor_attr_set(lsm6dso16is, SENSOR_CHAN_GYRO_XYZ, + SENSOR_ATTR_FULL_SCALE, &fs_attr) < 0) { + printk("Cannot set full scale for LSM6DSO16IS gyro\n"); + return; + } + +#ifdef CONFIG_LSM6DSO16IS_TRIGGER + struct sensor_trigger trig; + + trig.type = SENSOR_TRIG_DATA_READY; + trig.chan = SENSOR_CHAN_ACCEL_XYZ; + sensor_trigger_set(lsm6dso16is, &trig, lsm6dso16is_acc_trig_handler); +#endif +} + +static void lsm6dsv16x_config(const struct device *lsm6dsv16x) +{ + struct sensor_value odr_attr, fs_attr, mode_attr; + + mode_attr.val1 = 0; /* HP */ + + if (sensor_attr_set(lsm6dsv16x, SENSOR_CHAN_ACCEL_XYZ, + SENSOR_ATTR_CONFIGURATION, &mode_attr) < 0) { + printk("Cannot set mode for LSM6DSV16X accel\n"); + return; + } + + /* set LSM6DSV16X accel sampling frequency to 208 Hz */ + odr_attr.val1 = 208; + odr_attr.val2 = 0; + + if (sensor_attr_set(lsm6dsv16x, SENSOR_CHAN_ACCEL_XYZ, + SENSOR_ATTR_SAMPLING_FREQUENCY, &odr_attr) < 0) { + printk("Cannot set sampling frequency for LSM6DSV16X accel\n"); + return; + } + + sensor_g_to_ms2(16, &fs_attr); + + if (sensor_attr_set(lsm6dsv16x, SENSOR_CHAN_ACCEL_XYZ, + SENSOR_ATTR_FULL_SCALE, &fs_attr) < 0) { + printk("Cannot set full scale for LSM6DSV16X accel\n"); + return; + } + + /* set LSM6DSV16X gyro sampling frequency to 208 Hz */ + odr_attr.val1 = 208; + odr_attr.val2 = 0; + + if (sensor_attr_set(lsm6dsv16x, SENSOR_CHAN_GYRO_XYZ, + SENSOR_ATTR_SAMPLING_FREQUENCY, &odr_attr) < 0) { + printk("Cannot set sampling frequency for LSM6DSV16X gyro\n"); + return; + } + + sensor_degrees_to_rad(250, &fs_attr); + + if (sensor_attr_set(lsm6dsv16x, SENSOR_CHAN_GYRO_XYZ, + SENSOR_ATTR_FULL_SCALE, &fs_attr) < 0) { + printk("Cannot set full scale for LSM6DSV16X gyro\n"); + return; + } + +#ifdef CONFIG_LSM6DSV16X_TRIGGER + struct sensor_trigger trig; + + trig.type = SENSOR_TRIG_DATA_READY; + trig.chan = SENSOR_CHAN_ACCEL_XYZ; + sensor_trigger_set(lsm6dsv16x, &trig, lsm6dsv16x_acc_trig_handler); +#endif +} + +static void lps22df_config(const struct device *lps22df) +{ + struct sensor_value odr_attr; + + /* set LPS22DF accel sampling frequency to 10 Hz */ + odr_attr.val1 = 10; + odr_attr.val2 = 0; + + if (sensor_attr_set(lps22df, SENSOR_CHAN_ALL, + SENSOR_ATTR_SAMPLING_FREQUENCY, &odr_attr) < 0) { + printk("Cannot set sampling frequency for LPS22DF accel\n"); + return; + } + +#ifdef CONFIG_LPS2XDF_TRIGGER + struct sensor_trigger trig; + + trig.type = SENSOR_TRIG_DATA_READY; + trig.chan = SENSOR_CHAN_ALL; + sensor_trigger_set(lps22df, &trig, lps22df_trigger_handler); +#endif +} + +int main(void) +{ + struct sensor_value lis2mdl_magn[3], lis2mdl_temp, lps22df_press, lps22df_temp; + struct sensor_value lsm6dso16is_xl[3], lsm6dso16is_gy[3]; +#ifdef CONFIG_LSM6DSO16IS_ENABLE_TEMP + struct sensor_value lsm6dso16is_temp; +#endif + struct sensor_value lsm6dsv16x_xl[3], lsm6dsv16x_gy[3]; + const struct device *const lis2mdl = DEVICE_DT_GET_ONE(st_lis2mdl); + const struct device *const lsm6dso16is = DEVICE_DT_GET_ONE(st_lsm6dso16is); + const struct device *const lsm6dsv16x = DEVICE_DT_GET_ONE(st_lsm6dsv16x); + const struct device *const lps22df = DEVICE_DT_GET_ONE(st_lps22df); + int cnt = 1; + + if (!device_is_ready(lsm6dso16is)) { + printk("%s: device not ready.\n", lsm6dso16is->name); + return 0; + } + if (!device_is_ready(lsm6dsv16x)) { + printk("%s: device not ready.\n", lsm6dsv16x->name); + return 0; + } + if (!device_is_ready(lis2mdl)) { + printk("%s: device not ready.\n", lis2mdl->name); + return 0; + } + if (!device_is_ready(lps22df)) { + printk("%s: device not ready.\n", lps22df->name); + return 0; + } + + lis2mdl_config(lis2mdl); + lsm6dso16is_config(lsm6dso16is); + lsm6dsv16x_config(lsm6dsv16x); + lps22df_config(lps22df); + + while (1) { + /* Get sensor samples */ + +#ifndef CONFIG_LIS2MDL_TRIGGER + if (sensor_sample_fetch(lis2mdl) < 0) { + printf("LIS2MDL Magn Sensor sample update error\n"); + return 0; + } +#endif +#ifndef CONFIG_LSM6DSO16IS_TRIGGER + if (sensor_sample_fetch(lsm6dso16is) < 0) { + printf("LSM6DSO16IS Sensor sample update error\n"); + return 0; + } +#endif +#ifndef CONFIG_LSM6DSV16X_TRIGGER + if (sensor_sample_fetch(lsm6dsv16x) < 0) { + printf("LSM6DSV16X Sensor sample update error\n"); + return 0; + } +#endif +#ifndef CONFIG_LPS2XDF_TRIGGER + if (sensor_sample_fetch(lps22df) < 0) { + printf("LPS22DF pressure sample update error\n"); + return 0; + } +#endif + + /* Get sensor data */ + sensor_channel_get(lis2mdl, SENSOR_CHAN_MAGN_XYZ, lis2mdl_magn); + sensor_channel_get(lis2mdl, SENSOR_CHAN_DIE_TEMP, &lis2mdl_temp); + sensor_channel_get(lsm6dso16is, SENSOR_CHAN_ACCEL_XYZ, lsm6dso16is_xl); + sensor_channel_get(lsm6dso16is, SENSOR_CHAN_GYRO_XYZ, lsm6dso16is_gy); +#ifdef CONFIG_LSM6DSO16IS_ENABLE_TEMP + sensor_channel_get(lsm6dso16is, SENSOR_CHAN_DIE_TEMP, &lsm6dso16is_temp); +#endif + sensor_channel_get(lsm6dsv16x, SENSOR_CHAN_ACCEL_XYZ, lsm6dsv16x_xl); + sensor_channel_get(lsm6dsv16x, SENSOR_CHAN_GYRO_XYZ, lsm6dsv16x_gy); + + sensor_channel_get(lps22df, SENSOR_CHAN_PRESS, &lps22df_press); + sensor_channel_get(lps22df, SENSOR_CHAN_AMBIENT_TEMP, &lps22df_temp); + + /* Display sensor data */ + + /* Erase previous */ + printf("\0033\014"); + + printf("X-NUCLEO-IKS4A1 sensor dashboard\n\n"); + + /* lis2mdl */ + printf("LIS2MDL: Magn (gauss): x: %.3f, y: %.3f, z: %.3f\n", + sensor_value_to_double(&lis2mdl_magn[0]), + sensor_value_to_double(&lis2mdl_magn[1]), + sensor_value_to_double(&lis2mdl_magn[2])); + + printf("LIS2MDL: Temperature: %.1f C\n", + sensor_value_to_double(&lis2mdl_temp)); + + printf("LSM6DSO16IS: Accel (m.s-2): x: %.3f, y: %.3f, z: %.3f\n", + sensor_value_to_double(&lsm6dso16is_xl[0]), + sensor_value_to_double(&lsm6dso16is_xl[1]), + sensor_value_to_double(&lsm6dso16is_xl[2])); + + printf("LSM6DSO16IS: Gyro (dps): x: %.3f, y: %.3f, z: %.3f\n", + sensor_value_to_double(&lsm6dso16is_gy[0]), + sensor_value_to_double(&lsm6dso16is_gy[1]), + sensor_value_to_double(&lsm6dso16is_gy[2])); + +#ifdef CONFIG_LSM6DSO16IS_ENABLE_TEMP + /* temperature */ + printf("LSM6DSO16IS: Temperature: %.1f C\n", + sensor_value_to_double(&lsm6dso16is_temp)); +#endif + + printf("LSM6DSV16X: Accel (m.s-2): x: %.3f, y: %.3f, z: %.3f\n", + sensor_value_to_double(&lsm6dsv16x_xl[0]), + sensor_value_to_double(&lsm6dsv16x_xl[1]), + sensor_value_to_double(&lsm6dsv16x_xl[2])); + + printf("LSM6DSV16X: GYro (dps): x: %.3f, y: %.3f, z: %.3f\n", + sensor_value_to_double(&lsm6dsv16x_gy[0]), + sensor_value_to_double(&lsm6dsv16x_gy[1]), + sensor_value_to_double(&lsm6dsv16x_gy[2])); + + printf("LPS22DF: Temperature: %.1f C\n", sensor_value_to_double(&lps22df_temp)); + printf("LPS22DF: Pressure:%.3f kpa\n", sensor_value_to_double(&lps22df_press)); + +#if defined(CONFIG_LIS2MDL_TRIGGER) + printk("%d: lis2mdl trig %d\n", cnt, lis2mdl_trig_cnt); +#endif + +#ifdef CONFIG_LSM6DSO16IS_TRIGGER + printk("%d: lsm6dso16is acc trig %d\n", cnt, lsm6dso16is_acc_trig_cnt); +#endif + +#ifdef CONFIG_LSM6DSV16X_TRIGGER + printk("%d: lsm6dsv16x acc trig %d\n", cnt, lsm6dsv16x_acc_trig_cnt); +#endif +#ifdef CONFIG_LPS2XDF_TRIGGER + printk("%d: lps22df trig %d\n", cnt, lps22df_trig_cnt); +#endif + + cnt++; + k_sleep(K_MSEC(2000)); + } +} From c1643f9701b658aa824476e370761eb5033a4f36 Mon Sep 17 00:00:00 2001 From: Adam Wojasinski Date: Tue, 23 Jan 2024 10:08:57 +0100 Subject: [PATCH 2852/3723] posix: Add implementation of mq_notify() function The function was the last missing piece of the `_POSIX_MESSAGE_PASSING` option group. Due to lack of signal subsystem in the Zephyr RTOS the `sigev_notify` member of the `sigevent` structure that describes the notification cannot be set to `SIGEV_SIGNAL` - this notification type is not implemented, the function will return -1 and set `errno` to `ENOSYS`. `mq_notify` documentation: https://pubs.opengroup.org/onlinepubs/9699919799/functions/mq_notify.html Fixes #66958 Signed-off-by: Adam Wojasinski --- include/zephyr/posix/mqueue.h | 2 + lib/posix/mqueue.c | 102 +++++++++++++++++++++++++++++++++- 2 files changed, 102 insertions(+), 2 deletions(-) diff --git a/include/zephyr/posix/mqueue.h b/include/zephyr/posix/mqueue.h index 29f67607e2c..dbaa6d42a53 100644 --- a/include/zephyr/posix/mqueue.h +++ b/include/zephyr/posix/mqueue.h @@ -10,6 +10,7 @@ #include #include #include +#include #include #include "posix_types.h" @@ -40,6 +41,7 @@ int mq_timedreceive(mqd_t mqdes, char *msg_ptr, size_t msg_len, unsigned int *msg_prio, const struct timespec *abstime); int mq_timedsend(mqd_t mqdes, const char *msg_ptr, size_t msg_len, unsigned int msg_prio, const struct timespec *abstime); +int mq_notify(mqd_t mqdes, const struct sigevent *notification); #ifdef __cplusplus } diff --git a/lib/posix/mqueue.c b/lib/posix/mqueue.c index 47e660111bb..042b40910a8 100644 --- a/lib/posix/mqueue.c +++ b/lib/posix/mqueue.c @@ -1,5 +1,6 @@ /* * Copyright (c) 2018 Intel Corporation + * Copyright (c) 2024 BayLibre, SAS * * SPDX-License-Identifier: Apache-2.0 */ @@ -7,8 +8,10 @@ #include #include #include -#include #include +#include + +#define SIGEV_MASK (SIGEV_NONE | SIGEV_SIGNAL | SIGEV_THREAD) typedef struct mqueue_object { sys_snode_t snode; @@ -17,6 +20,7 @@ typedef struct mqueue_object { struct k_msgq queue; atomic_t ref_count; char *name; + struct sigevent not; } mqueue_object; typedef struct mqueue_desc { @@ -34,9 +38,11 @@ int64_t timespec_to_timeoutms(const struct timespec *abstime); static mqueue_object *find_in_list(const char *name); static int32_t send_message(mqueue_desc *mqd, const char *msg_ptr, size_t msg_len, k_timeout_t timeout); -static int receive_message(mqueue_desc *mqd, char *msg_ptr, size_t msg_len, +static int32_t receive_message(mqueue_desc *mqd, char *msg_ptr, size_t msg_len, k_timeout_t timeout); +static void remove_notification(mqueue_object *msg_queue); static void remove_mq(mqueue_object *msg_queue); +static void *mq_notify_thread(void *arg); /** * @brief Open a message queue. @@ -341,6 +347,74 @@ int mq_setattr(mqd_t mqdes, const struct mq_attr *mqstat, return 0; } +/** + * @brief Notify process that a message is available. + * + * See IEEE 1003.1 + */ +int mq_notify(mqd_t mqdes, const struct sigevent *notification) +{ + mqueue_desc *mqd = (mqueue_desc *)mqdes; + + if (mqd == NULL) { + errno = EBADF; + return -1; + } + + mqueue_object *msg_queue = mqd->mqueue; + + if (notification == NULL) { + if ((msg_queue->not.sigev_notify & SIGEV_MASK) == 0) { + errno = EINVAL; + return -1; + } + remove_notification(msg_queue); + return 0; + } + + if ((msg_queue->not.sigev_notify & SIGEV_MASK) != 0) { + errno = EBUSY; + return -1; + } + if (notification->sigev_notify == SIGEV_SIGNAL) { + errno = ENOSYS; + return -1; + } + if (notification->sigev_notify_attributes != NULL) { + int ret = pthread_attr_setdetachstate(notification->sigev_notify_attributes, + PTHREAD_CREATE_DETACHED); + if (ret != 0) { + errno = ret; + return -1; + } + } + + k_sem_take(&mq_sem, K_FOREVER); + memcpy(&msg_queue->not, notification, sizeof(struct sigevent)); + k_sem_give(&mq_sem); + + return 0; +} + +static void *mq_notify_thread(void *arg) +{ + mqueue_object *mqueue = (mqueue_object *)arg; + struct sigevent *sevp = &mqueue->not; + + pthread_setcanceltype(PTHREAD_CANCEL_ASYNCHRONOUS, NULL); + + if (sevp->sigev_notify_attributes == NULL) { + pthread_detach(pthread_self()); + } + + sevp->sigev_notify_function(sevp->sigev_value); + + remove_notification(mqueue); + + pthread_exit(NULL); + return NULL; +} + /* Internal functions */ static mqueue_object *find_in_list(const char *name) { @@ -380,11 +454,28 @@ static int32_t send_message(mqueue_desc *mqd, const char *msg_ptr, size_t msg_le return ret; } + uint32_t msgq_num = k_msgq_num_used_get(&mqd->mqueue->queue); + if (k_msgq_put(&mqd->mqueue->queue, (void *)msg_ptr, timeout) != 0) { errno = K_TIMEOUT_EQ(timeout, K_NO_WAIT) ? EAGAIN : ETIMEDOUT; return ret; } + if (k_msgq_num_used_get(&mqd->mqueue->queue) - msgq_num > 0) { + struct sigevent *sevp = &mqd->mqueue->not; + + if (sevp->sigev_notify == SIGEV_NONE) { + sevp->sigev_notify_function(sevp->sigev_value); + } else if (sevp->sigev_notify == SIGEV_THREAD) { + pthread_t th; + + ret = pthread_create(&th, + sevp->sigev_notify_attributes, + mq_notify_thread, + mqd->mqueue); + } + } + return 0; } @@ -428,3 +519,10 @@ static void remove_mq(mqueue_object *msg_queue) k_free(msg_queue->mem_obj); } } + +static void remove_notification(mqueue_object *msg_queue) +{ + k_sem_take(&mq_sem, K_FOREVER); + memset(&msg_queue->not, 0, sizeof(struct sigevent)); + k_sem_give(&mq_sem); +} From dfb6e5aa965c6d480f25e4cd6d63a7d9c4fecdf8 Mon Sep 17 00:00:00 2001 From: Adam Wojasinski Date: Thu, 18 Jan 2024 10:00:54 +0100 Subject: [PATCH 2853/3723] tests: posix: Add test cases for mq_notify() Adds test cases testing following features: - function error handling - basic notification type - thread notification type - adding notification to non-empty queue Signed-off-by: Adam Wojasinski --- tests/posix/common/src/mqueue.c | 183 ++++++++++++++++++++++++++++- tests/posix/headers/src/mqueue_h.c | 2 +- 2 files changed, 182 insertions(+), 3 deletions(-) diff --git a/tests/posix/common/src/mqueue.c b/tests/posix/common/src/mqueue.c index 1b0a82d66f5..45229ba9d13 100644 --- a/tests/posix/common/src/mqueue.c +++ b/tests/posix/common/src/mqueue.c @@ -1,5 +1,6 @@ /* * Copyright (c) 2018 Intel Corporation + * Copyright (c) 2024 BayLibre, SAS * * SPDX-License-Identifier: Apache-2.0 */ @@ -12,8 +13,6 @@ #include #define N_THR 2 -#define SENDER_THREAD 0 -#define RECEIVER_THREAD 1 #define MESSAGE_SIZE 16 #define MESG_COUNT_PERMQ 4 @@ -97,4 +96,184 @@ ZTEST(mqueue, test_mqueue) zassert_false(mq_unlink(queue), "Not able to unlink Queue"); } +static bool notification_executed; + +void notify_function_basic(union sigval val) +{ + mqd_t mqd; + bool *executed = (bool *)val.sival_ptr; + + mqd = mq_open(queue, O_RDONLY); + + mq_receive(mqd, rec_data, MESSAGE_SIZE, 0); + zassert_ok(strcmp(rec_data, send_data), + "Error in data reception. exp: %s act: %s", send_data, rec_data); + + zassert_ok(mq_close(mqd), "Unable to close message queue descriptor."); + + *executed = true; +} + +ZTEST(mqueue, test_mqueue_notify_basic) +{ + mqd_t mqd; + struct mq_attr attrs = { + .mq_msgsize = MESSAGE_SIZE, + .mq_maxmsg = MESG_COUNT_PERMQ, + }; + struct sigevent not = { + .sigev_notify = SIGEV_NONE, + .sigev_value.sival_ptr = (void *)¬ification_executed, + .sigev_notify_function = notify_function_basic, + }; + int32_t mode = 0777; + int flags = O_RDWR | O_CREAT; + + notification_executed = false; + memset(rec_data, 0, MESSAGE_SIZE); + + mqd = mq_open(queue, flags, mode, &attrs); + + zassert_ok(mq_notify(mqd, ¬), "Unable to set notification."); + + zassert_ok(mq_send(mqd, send_data, MESSAGE_SIZE, 0), "Unable to send message"); + + zassert_true(notification_executed, "Notification not triggered."); + + zassert_ok(mq_close(mqd), "Unable to close message queue descriptor."); + zassert_ok(mq_unlink(queue), "Unable to unlink queue"); +} + +void notify_function_thread(union sigval val) +{ + mqd_t mqd; + pthread_t sender = (pthread_t)val.sival_int; + + zassert_not_equal(sender, pthread_self(), + "Notification function should be executed from different thread."); + + mqd = mq_open(queue, O_RDONLY); + + mq_receive(mqd, rec_data, MESSAGE_SIZE, 0); + zassert_ok(strcmp(rec_data, send_data), + "Error in data reception. exp: %s act: %s", send_data, rec_data); + + zassert_ok(mq_close(mqd), "Unable to close message queue descriptor."); + + notification_executed = true; +} + +ZTEST(mqueue, test_mqueue_notify_thread) +{ + mqd_t mqd; + struct mq_attr attrs = { + .mq_msgsize = MESSAGE_SIZE, + .mq_maxmsg = MESG_COUNT_PERMQ, + }; + struct sigevent not = { + .sigev_notify = SIGEV_THREAD, + .sigev_value.sival_int = (int)pthread_self(), + .sigev_notify_function = notify_function_thread, + }; + int32_t mode = 0777; + int flags = O_RDWR | O_CREAT; + + notification_executed = false; + memset(rec_data, 0, MESSAGE_SIZE); + + mqd = mq_open(queue, flags, mode, &attrs); + + zassert_ok(mq_notify(mqd, ¬), "Unable to set notification."); + + zassert_ok(mq_send(mqd, send_data, MESSAGE_SIZE, 0), "Unable to send message"); + + usleep(USEC_PER_MSEC * 10U); + + zassert_true(notification_executed, "Notification not triggered."); + + zassert_ok(mq_close(mqd), "Unable to close message queue descriptor."); + zassert_ok(mq_unlink(queue), "Unable to unlink queue"); +} + +ZTEST(mqueue, test_mqueue_notify_non_empty_queue) +{ + mqd_t mqd; + struct mq_attr attrs = { + .mq_msgsize = MESSAGE_SIZE, + .mq_maxmsg = MESG_COUNT_PERMQ, + }; + struct sigevent not = { + .sigev_notify = SIGEV_NONE, + .sigev_value.sival_ptr = (void *)¬ification_executed, + .sigev_notify_function = notify_function_basic, + }; + int32_t mode = 0777; + int flags = O_RDWR | O_CREAT; + + notification_executed = false; + memset(rec_data, 0, MESSAGE_SIZE); + + mqd = mq_open(queue, flags, mode, &attrs); + + zassert_ok(mq_send(mqd, send_data, MESSAGE_SIZE, 0), "Unable to send message"); + + zassert_ok(mq_notify(mqd, ¬), "Unable to set notification."); + + zassert_false(notification_executed, "Notification shouldn't be processed."); + + mq_receive(mqd, rec_data, MESSAGE_SIZE, 0); + zassert_false(strcmp(rec_data, send_data), + "Error in data reception. exp: %s act: %s", send_data, rec_data); + + memset(rec_data, 0, MESSAGE_SIZE); + + zassert_ok(mq_send(mqd, send_data, MESSAGE_SIZE, 0), "Unable to send message"); + + zassert_true(notification_executed, "Notification not triggered."); + + zassert_ok(mq_close(mqd), "Unable to close message queue descriptor."); + zassert_ok(mq_unlink(queue), "Unable to unlink queue"); +} + +ZTEST(mqueue, test_mqueue_notify_errors) +{ + mqd_t mqd; + struct mq_attr attrs = { + .mq_msgsize = MESSAGE_SIZE, + .mq_maxmsg = MESG_COUNT_PERMQ, + }; + struct sigevent not = { + .sigev_notify = SIGEV_SIGNAL, + .sigev_value.sival_ptr = (void *)¬ification_executed, + .sigev_notify_function = notify_function_basic, + }; + int32_t mode = 0777; + int flags = O_RDWR | O_CREAT; + + zassert_not_ok(mq_notify(NULL, NULL), "Should return -1 and set errno to EBADF."); + zassert_equal(errno, EBADF); + + mqd = mq_open(queue, flags, mode, &attrs); + + zassert_not_ok(mq_notify(mqd, NULL), "Should return -1 and set errno to EINVAL."); + zassert_equal(errno, EINVAL); + + zassert_not_ok(mq_notify(mqd, ¬), "SIGEV_SIGNAL not supported should return -1."); + zassert_equal(errno, ENOSYS); + + not.sigev_notify = SIGEV_NONE; + + zassert_ok(mq_notify(mqd, ¬), + "Unexpected error while asigning notification to the queue."); + + zassert_not_ok(mq_notify(mqd, ¬), + "Can't assign notification when there is another assigned."); + zassert_equal(errno, EBUSY); + + zassert_ok(mq_notify(mqd, NULL), "Unable to remove notification from the message queue."); + + zassert_ok(mq_close(mqd), "Unable to close message queue descriptor."); + zassert_ok(mq_unlink(queue), "Unable to unlink queue"); +} + ZTEST_SUITE(mqueue, NULL, NULL, NULL, NULL, NULL); diff --git a/tests/posix/headers/src/mqueue_h.c b/tests/posix/headers/src/mqueue_h.c index 4a1209fe539..68fa4b2c9c0 100644 --- a/tests/posix/headers/src/mqueue_h.c +++ b/tests/posix/headers/src/mqueue_h.c @@ -29,7 +29,7 @@ ZTEST(posix_headers, test_mqueue_h) if (IS_ENABLED(CONFIG_POSIX_API)) { zassert_not_null(mq_close); zassert_not_null(mq_getattr); - /* zassert_not_null(mq_notify); */ /* not implemented */ + zassert_not_null(mq_notify); zassert_not_null(mq_open); zassert_not_null(mq_receive); zassert_not_null(mq_send); From 2e7a1f9702f7d1531a3682391bf777e331fdd2a2 Mon Sep 17 00:00:00 2001 From: Adam Wojasinski Date: Tue, 23 Jan 2024 19:17:34 +0100 Subject: [PATCH 2854/3723] doc: posix: Update POSIX supported API documentation Updates in documentation support for `mq_notify` API in `_POSIX_MESSAGE_PASSING` group option. Signed-off-by: Adam Wojasinski --- doc/services/portability/posix/option_groups/index.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/doc/services/portability/posix/option_groups/index.rst b/doc/services/portability/posix/option_groups/index.rst index 2a1eefdc0a1..40871f99820 100644 --- a/doc/services/portability/posix/option_groups/index.rst +++ b/doc/services/portability/posix/option_groups/index.rst @@ -359,7 +359,7 @@ _POSIX_MESSAGE_PASSING mq_close(),yes mq_getattr(),yes - mq_notify(), + mq_notify(),yes mq_open(),yes mq_receive(),yes mq_send(),yes From cc2563712681b44d92ad68449d9e03992611291d Mon Sep 17 00:00:00 2001 From: Daniel Leung Date: Tue, 23 Jan 2024 11:01:52 -0800 Subject: [PATCH 2855/3723] soc: intel_adsp/ace: fix assert for uncached pointer Only when CONFIG_MP_MAX_NUM_CPUS > 1, then .bss is put in uncached region. Otherwise, .bss is in cached region. So the assertion that g_key_read_holder must be in uncached region must take into account how many CPUs are enabled on build. Signed-off-by: Daniel Leung --- soc/xtensa/intel_adsp/ace/multiprocessing.c | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/soc/xtensa/intel_adsp/ace/multiprocessing.c b/soc/xtensa/intel_adsp/ace/multiprocessing.c index 885294e6cad..8e5657f033f 100644 --- a/soc/xtensa/intel_adsp/ace/multiprocessing.c +++ b/soc/xtensa/intel_adsp/ace/multiprocessing.c @@ -89,8 +89,14 @@ void soc_mp_init(void) /* Set the core 0 active */ soc_cpus_active[0] = true; #if CONFIG_SOC_INTEL_ACE15_MTPM +#if defined(CONFIG_SMP) && (CONFIG_MP_MAX_NUM_CPUS > 1) + /* + * Only when more than 1 CPUs is enabled, then this is in uncached area. + * Otherwise, this is in cached area and will fail this test. + */ __ASSERT(!arch_xtensa_is_ptr_cached(&g_key_read_holder), "g_key_read_holder must be uncached"); +#endif /* defined(CONFIG_SMP) && (CONFIG_MP_MAX_NUM_CPUS > 1) */ g_key_read_holder = INTEL_ADSP_ACE15_MAGIC_KEY; #endif /* CONFIG_SOC_INTEL_ACE15_MTPM */ } From 612aa7169a77e79a454beeaed76c5a4e64caac60 Mon Sep 17 00:00:00 2001 From: Pisit Sawangvonganan Date: Wed, 24 Jan 2024 02:06:05 +0700 Subject: [PATCH 2856/3723] sd: add config SD_CMD_RETRIES Introduced the config SD_CMD_RETRIES option as a build-time parameter. This allows the assignment of a specific value to cmd.retries. The default value has been set to 0 to preserve the previous setting. Signed-off-by: Pisit Sawangvonganan --- subsys/sd/Kconfig | 6 ++++++ subsys/sd/sd.c | 3 +++ subsys/sd/sd_ops.c | 12 ++++++++++-- 3 files changed, 19 insertions(+), 2 deletions(-) diff --git a/subsys/sd/Kconfig b/subsys/sd/Kconfig index 403eaef341a..be2a5775664 100644 --- a/subsys/sd/Kconfig +++ b/subsys/sd/Kconfig @@ -80,6 +80,12 @@ config SD_BUFFER_SIZE Size in bytes of internal buffer SD card uses for unaligned reads and internal data reads during initialization +config SD_CMD_RETRIES + int "Number of times to retry sending command to card" + default 0 + help + Number of times to retry sending command to SD card in case of failure + config SD_DATA_RETRIES int "Number of times to retry sending data to card" default 3 diff --git a/subsys/sd/sd.c b/subsys/sd/sd.c index 87ec7a29910..f4859b25a43 100644 --- a/subsys/sd/sd.c +++ b/subsys/sd/sd.c @@ -27,6 +27,7 @@ static inline int sd_idle(struct sd_card *card) cmd.opcode = SD_GO_IDLE_STATE; cmd.arg = 0x0; cmd.response_type = (SD_RSP_TYPE_NONE | SD_SPI_RSP_TYPE_R1); + cmd.retries = CONFIG_SD_CMD_RETRIES; cmd.timeout_ms = CONFIG_SD_CMD_TIMEOUT; return sdhc_request(card->sdhc, &cmd, NULL); } @@ -41,6 +42,7 @@ static int sd_send_interface_condition(struct sd_card *card) cmd.opcode = SD_SEND_IF_COND; cmd.arg = SD_IF_COND_VHS_3V3 | SD_IF_COND_CHECK; cmd.response_type = (SD_RSP_TYPE_R7 | SD_SPI_RSP_TYPE_R7); + cmd.retries = CONFIG_SD_CMD_RETRIES; cmd.timeout_ms = CONFIG_SD_CMD_TIMEOUT; ret = sdhc_request(card->sdhc, &cmd, NULL); if (ret) { @@ -77,6 +79,7 @@ static int sd_enable_crc(struct sd_card *card) cmd.opcode = SD_SPI_CRC_ON_OFF; cmd.arg = 0x1; /* Enable CRC */ cmd.response_type = SD_SPI_RSP_TYPE_R1; + cmd.retries = CONFIG_SD_CMD_RETRIES; cmd.timeout_ms = CONFIG_SD_CMD_TIMEOUT; return sdhc_request(card->sdhc, &cmd, NULL); } diff --git a/subsys/sd/sd_ops.c b/subsys/sd/sd_ops.c index 8fc6400dcf0..bf804679d68 100644 --- a/subsys/sd/sd_ops.c +++ b/subsys/sd/sd_ops.c @@ -27,6 +27,7 @@ int sdmmc_read_status(struct sd_card *card) cmd.arg = (card->relative_addr << 16U); } cmd.response_type = (SD_RSP_TYPE_R1 | SD_SPI_RSP_TYPE_R2); + cmd.retries = CONFIG_SD_CMD_RETRIES; cmd.timeout_ms = CONFIG_SD_CMD_TIMEOUT; ret = sdhc_request(card->sdhc, &cmd, NULL); @@ -211,6 +212,7 @@ static int sdmmc_spi_read_cxd(struct sd_card *card, uint32_t opcode, uint32_t *c cmd.opcode = opcode; cmd.arg = 0; cmd.response_type = SD_SPI_RSP_TYPE_R1; + cmd.retries = CONFIG_SD_CMD_RETRIES; cmd.timeout_ms = CONFIG_SD_CMD_TIMEOUT; /* CID/CSD is 16 bytes */ @@ -239,6 +241,7 @@ static int sdmmc_read_cxd(struct sd_card *card, uint32_t opcode, uint32_t rca, u cmd.opcode = opcode; cmd.arg = (rca << 16); cmd.response_type = SD_RSP_TYPE_R2; + cmd.retries = CONFIG_SD_CMD_RETRIES; cmd.timeout_ms = CONFIG_SD_CMD_TIMEOUT; ret = sdhc_request(card->sdhc, &cmd, NULL); @@ -332,6 +335,7 @@ int sdmmc_switch_voltage(struct sd_card *card) cmd.opcode = SD_VOL_SWITCH; cmd.arg = 0U; cmd.response_type = SD_RSP_TYPE_R1; + cmd.retries = CONFIG_SD_CMD_RETRIES; cmd.timeout_ms = CONFIG_SD_CMD_TIMEOUT; ret = sdhc_request(card->sdhc, &cmd, NULL); if (ret) { @@ -410,6 +414,7 @@ int sdmmc_request_rca(struct sd_card *card) cmd.opcode = SD_SEND_RELATIVE_ADDR; cmd.arg = 0; cmd.response_type = SD_RSP_TYPE_R6; + cmd.retries = CONFIG_SD_CMD_RETRIES; cmd.timeout_ms = CONFIG_SD_CMD_TIMEOUT; /* Issue CMD3 until card responds with nonzero RCA */ do { @@ -436,6 +441,7 @@ int sdmmc_select_card(struct sd_card *card) cmd.opcode = SD_SELECT_CARD; cmd.arg = ((card->relative_addr) << 16U); cmd.response_type = SD_RSP_TYPE_R1; + cmd.retries = CONFIG_SD_CMD_RETRIES; cmd.timeout_ms = CONFIG_SD_CMD_TIMEOUT; ret = sdhc_request(card->sdhc, &cmd, NULL); @@ -460,6 +466,7 @@ int card_app_command(struct sd_card *card, int relative_card_address) cmd.opcode = SD_APP_CMD; cmd.arg = relative_card_address << 16U; cmd.response_type = (SD_RSP_TYPE_R1 | SD_SPI_RSP_TYPE_R1); + cmd.retries = CONFIG_SD_CMD_RETRIES; cmd.timeout_ms = CONFIG_SD_CMD_TIMEOUT; ret = sdhc_request(card->sdhc, &cmd, NULL); if (ret) { @@ -505,8 +512,8 @@ static int card_read(struct sd_card *card, uint8_t *rbuf, uint32_t start_block, cmd.arg = start_block; } cmd.response_type = (SD_RSP_TYPE_R1 | SD_SPI_RSP_TYPE_R1); - cmd.timeout_ms = CONFIG_SD_CMD_TIMEOUT; cmd.retries = CONFIG_SD_DATA_RETRIES; + cmd.timeout_ms = CONFIG_SD_CMD_TIMEOUT; data.block_addr = start_block; data.block_size = card->block_size; @@ -617,6 +624,7 @@ static int card_query_written(struct sd_card *card, uint32_t *num_written) cmd.opcode = SD_APP_SEND_NUM_WRITTEN_BLK; cmd.arg = 0; cmd.response_type = (SD_RSP_TYPE_R1 | SD_SPI_RSP_TYPE_R1); + cmd.retries = CONFIG_SD_CMD_RETRIES; cmd.timeout_ms = CONFIG_SD_CMD_TIMEOUT; data.block_size = 4U; @@ -660,8 +668,8 @@ static int card_write(struct sd_card *card, const uint8_t *wbuf, uint32_t start_ cmd.arg = start_block; } cmd.response_type = (SD_RSP_TYPE_R1 | SD_SPI_RSP_TYPE_R1); - cmd.timeout_ms = CONFIG_SD_CMD_TIMEOUT; cmd.retries = CONFIG_SD_DATA_RETRIES; + cmd.timeout_ms = CONFIG_SD_CMD_TIMEOUT; data.block_addr = start_block; data.block_size = card->block_size; From 8534c38232b587c33e0802580dcedca84f6fe7ae Mon Sep 17 00:00:00 2001 From: Pisit Sawangvonganan Date: Wed, 24 Jan 2024 01:37:39 +0700 Subject: [PATCH 2857/3723] sd: omit zero-initialization for sdhc_command and sdhc_data structures The decision to omit zero-initialization is driven by a desire to enhance Zephyr's compactness and efficiency. This is achieved by omitting zero-initialization, thereby reducing the instruction count and, as a byproduct, the code size. After a thorough review of the usage of struct sdhc_command and sdhc_data, it has been determined that zero-initialization can be omitted. Only a portion of the fields need to be manually initialized. (e.g. cmd.retries, data.block_addr) For the uninitialized fields, it can be expected from successful operations that data will be appropriately written back from the underlying layer. Signed-off-by: Pisit Sawangvonganan --- subsys/sd/sd.c | 6 +++--- subsys/sd/sd_ops.c | 31 +++++++++++++++++-------------- subsys/sd/sd_ops.h | 2 +- 3 files changed, 21 insertions(+), 18 deletions(-) diff --git a/subsys/sd/sd.c b/subsys/sd/sd.c index f4859b25a43..f075203601d 100644 --- a/subsys/sd/sd.c +++ b/subsys/sd/sd.c @@ -21,7 +21,7 @@ LOG_MODULE_REGISTER(sd, CONFIG_SD_LOG_LEVEL); /* Idle all cards on bus. Can be used to clear errors on cards */ static inline int sd_idle(struct sd_card *card) { - struct sdhc_command cmd = {0}; + struct sdhc_command cmd; /* Reset card with CMD0 */ cmd.opcode = SD_GO_IDLE_STATE; @@ -35,7 +35,7 @@ static inline int sd_idle(struct sd_card *card) /* Sends CMD8 during SD initialization */ static int sd_send_interface_condition(struct sd_card *card) { - struct sdhc_command cmd = {0}; + struct sdhc_command cmd; int ret; uint32_t resp; @@ -72,7 +72,7 @@ static int sd_send_interface_condition(struct sd_card *card) /* Sends CMD59 to enable CRC checking for SD card in SPI mode */ static int sd_enable_crc(struct sd_card *card) { - struct sdhc_command cmd = {0}; + struct sdhc_command cmd; /* CMD59 for CRC mode is only valid for SPI hosts */ __ASSERT_NO_MSG(card->host_props.is_spi); diff --git a/subsys/sd/sd_ops.c b/subsys/sd/sd_ops.c index bf804679d68..cf8bd01c146 100644 --- a/subsys/sd/sd_ops.c +++ b/subsys/sd/sd_ops.c @@ -19,10 +19,11 @@ LOG_MODULE_DECLARE(sd, CONFIG_SD_LOG_LEVEL); /* Read card status. Return 0 if card is inactive */ int sdmmc_read_status(struct sd_card *card) { - struct sdhc_command cmd = {0}; + struct sdhc_command cmd; int ret; cmd.opcode = SD_SEND_STATUS; + cmd.arg = 0; if (!card->host_props.is_spi) { cmd.arg = (card->relative_addr << 16U); } @@ -203,8 +204,8 @@ static inline void sdmmc_decode_cid(struct sd_cid *cid, uint32_t *raw_cid) /* Reads card id/csd register (in SPI mode) */ static int sdmmc_spi_read_cxd(struct sd_card *card, uint32_t opcode, uint32_t *cxd) { - struct sdhc_command cmd = {0}; - struct sdhc_data data = {0}; + struct sdhc_command cmd; + struct sdhc_data data; int ret, i; /* Use internal card buffer for data transfer */ uint32_t *cxd_be = (uint32_t *)card->card_buffer; @@ -216,6 +217,7 @@ static int sdmmc_spi_read_cxd(struct sd_card *card, uint32_t opcode, uint32_t *c cmd.timeout_ms = CONFIG_SD_CMD_TIMEOUT; /* CID/CSD is 16 bytes */ + data.block_addr = 0; /* Unused set to 0 */ data.block_size = 16; data.blocks = 1U; data.data = cxd_be; @@ -235,7 +237,7 @@ static int sdmmc_spi_read_cxd(struct sd_card *card, uint32_t opcode, uint32_t *c /* Reads card id/csd register (native SD mode */ static int sdmmc_read_cxd(struct sd_card *card, uint32_t opcode, uint32_t rca, uint32_t *cxd) { - struct sdhc_command cmd = {0}; + struct sdhc_command cmd; int ret; cmd.opcode = opcode; @@ -323,7 +325,7 @@ int card_read_cid(struct sd_card *card) int sdmmc_switch_voltage(struct sd_card *card) { int ret, sd_clock; - struct sdhc_command cmd = {0}; + struct sdhc_command cmd; /* Check to make sure card supports 1.8V */ if (!(card->flags & SD_1800MV_FLAG)) { @@ -408,7 +410,7 @@ int sdmmc_switch_voltage(struct sd_card *card) */ int sdmmc_request_rca(struct sd_card *card) { - struct sdhc_command cmd = {0}; + struct sdhc_command cmd; int ret; cmd.opcode = SD_SEND_RELATIVE_ADDR; @@ -435,7 +437,7 @@ int sdmmc_request_rca(struct sd_card *card) */ int sdmmc_select_card(struct sd_card *card) { - struct sdhc_command cmd = {0}; + struct sdhc_command cmd; int ret; cmd.opcode = SD_SELECT_CARD; @@ -460,7 +462,7 @@ int sdmmc_select_card(struct sd_card *card) /* Helper to send SD app command */ int card_app_command(struct sd_card *card, int relative_card_address) { - struct sdhc_command cmd = {0}; + struct sdhc_command cmd; int ret; cmd.opcode = SD_APP_CMD; @@ -489,8 +491,8 @@ int card_app_command(struct sd_card *card, int relative_card_address) static int card_read(struct sd_card *card, uint8_t *rbuf, uint32_t start_block, uint32_t num_blocks) { int ret; - struct sdhc_command cmd = {0}; - struct sdhc_data data = {0}; + struct sdhc_command cmd; + struct sdhc_data data; /* * Note: The SD specification allows for CMD23 to be sent before a @@ -611,8 +613,8 @@ int card_read_blocks(struct sd_card *card, uint8_t *rbuf, uint32_t start_block, static int card_query_written(struct sd_card *card, uint32_t *num_written) { int ret; - struct sdhc_command cmd = {0}; - struct sdhc_data data = {0}; + struct sdhc_command cmd; + struct sdhc_data data; uint32_t *blocks = (uint32_t *)card->card_buffer; ret = card_app_command(card, card->relative_addr); @@ -627,6 +629,7 @@ static int card_query_written(struct sd_card *card, uint32_t *num_written) cmd.retries = CONFIG_SD_CMD_RETRIES; cmd.timeout_ms = CONFIG_SD_CMD_TIMEOUT; + data.block_addr = 0; /* Unused set to 0 */ data.block_size = 4U; data.blocks = 1U; data.data = blocks; @@ -653,8 +656,8 @@ static int card_write(struct sd_card *card, const uint8_t *wbuf, uint32_t start_ { int ret; uint32_t blocks; - struct sdhc_command cmd = {0}; - struct sdhc_data data = {0}; + struct sdhc_command cmd; + struct sdhc_data data; /* * See the note in card_read() above. We will not issue CMD23 diff --git a/subsys/sd/sd_ops.h b/subsys/sd/sd_ops.h index ecd04f48a62..f6c382244ef 100644 --- a/subsys/sd/sd_ops.h +++ b/subsys/sd/sd_ops.h @@ -10,7 +10,7 @@ /* * Switches voltage of SD card to 1.8V, as described by - * "Signal volatage switch procedure" in section 3.6.1 of SD specification. + * "Signal voltage switch procedure" in section 3.6.1 of SD specification. */ int sdmmc_switch_voltage(struct sd_card *card); From 1829fc33cb3dd55b41b1ca1ef3642df9d2ac6bbf Mon Sep 17 00:00:00 2001 From: Pisit Sawangvonganan Date: Wed, 24 Jan 2024 01:40:26 +0700 Subject: [PATCH 2858/3723] sd: omit zero-initialization for csd[4] and cid[4] After a review of the usage of csd[4] and cid[4], it has been determined that zero-initialization can be omitted. It can be expected from successful operations that data will be appropriately written back from the underlying layer. Signed-off-by: Pisit Sawangvonganan --- subsys/sd/sd_ops.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/subsys/sd/sd_ops.c b/subsys/sd/sd_ops.c index cf8bd01c146..27e64c32dc8 100644 --- a/subsys/sd/sd_ops.c +++ b/subsys/sd/sd_ops.c @@ -260,7 +260,7 @@ static int sdmmc_read_cxd(struct sd_card *card, uint32_t opcode, uint32_t rca, u int sdmmc_read_csd(struct sd_card *card) { int ret; - uint32_t csd[4] = {0}; + uint32_t csd[4]; /* Keep CSD on stack for reduced RAM usage */ struct sd_csd card_csd = {0}; @@ -283,7 +283,7 @@ int sdmmc_read_csd(struct sd_card *card) /* Reads card identification register, and decodes it */ int card_read_cid(struct sd_card *card) { - uint32_t cid[4] = {0}; + uint32_t cid[4]; int ret; #if defined(CONFIG_SDMMC_STACK) || defined(CONFIG_SDIO_STACK) /* Keep CID on stack for reduced RAM usage */ From 4889c9ca176750341bbaad7c73103608445e4ade Mon Sep 17 00:00:00 2001 From: Pisit Sawangvonganan Date: Thu, 25 Jan 2024 01:41:19 +0700 Subject: [PATCH 2859/3723] sd: update comment to reference 'SD host controller specification' In the code comments referring to section 3.6.1, changed the reference from 'SD specification' to 'SD host controller specification' for a clearer and more accurate context. Signed-off-by: Pisit Sawangvonganan --- subsys/sd/sd_ops.c | 2 +- subsys/sd/sd_ops.h | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/subsys/sd/sd_ops.c b/subsys/sd/sd_ops.c index 27e64c32dc8..7d4ebf11dd3 100644 --- a/subsys/sd/sd_ops.c +++ b/subsys/sd/sd_ops.c @@ -320,7 +320,7 @@ int card_read_cid(struct sd_card *card) /* * Implements signal voltage switch procedure described in section 3.6.1 of - * SD specification. + * SD host controller specification. */ int sdmmc_switch_voltage(struct sd_card *card) { diff --git a/subsys/sd/sd_ops.h b/subsys/sd/sd_ops.h index f6c382244ef..c12a020a018 100644 --- a/subsys/sd/sd_ops.h +++ b/subsys/sd/sd_ops.h @@ -10,7 +10,7 @@ /* * Switches voltage of SD card to 1.8V, as described by - * "Signal voltage switch procedure" in section 3.6.1 of SD specification. + * "Signal voltage switch procedure" in section 3.6.1 of SD host controller specification. */ int sdmmc_switch_voltage(struct sd_card *card); From f51c8ee73906e7414c7ff1c30e71978437616e71 Mon Sep 17 00:00:00 2001 From: Pisit Sawangvonganan Date: Fri, 26 Jan 2024 00:29:05 +0700 Subject: [PATCH 2860/3723] doc: releases: fix typo Utilize a code spell-checking tool to scan for and correct spelling errors in all files within the doc/releases directory. The typo in the 'Issue Related Items' section will be left unchanged. Signed-off-by: Pisit Sawangvonganan --- doc/releases/migration-guide-3.5.rst | 2 +- doc/releases/release-notes-2.2.rst | 4 ++-- doc/releases/release-notes-2.4.rst | 8 ++++---- doc/releases/release-notes-2.5.rst | 4 ++-- doc/releases/release-notes-2.6.rst | 6 +++--- doc/releases/release-notes-2.7.rst | 2 +- doc/releases/release-notes-3.0.rst | 6 +++--- doc/releases/release-notes-3.1.rst | 4 ++-- doc/releases/release-notes-3.2.rst | 12 ++++++------ doc/releases/release-notes-3.3.rst | 2 +- doc/releases/release-notes-3.4.rst | 2 +- doc/releases/release-notes-3.5.rst | 6 +++--- doc/releases/release-notes-3.6.rst | 2 +- 13 files changed, 30 insertions(+), 30 deletions(-) diff --git a/doc/releases/migration-guide-3.5.rst b/doc/releases/migration-guide-3.5.rst index cda3602f19f..86d0fa51fcb 100644 --- a/doc/releases/migration-guide-3.5.rst +++ b/doc/releases/migration-guide-3.5.rst @@ -73,7 +73,7 @@ C Library * Picolibc has four different printf/scanf variants supported in Zephyr, 'double', 'long long', 'integer', and 'minimal. 'double' offers a complete printf implementation with exact floating point in decimal and - hexidecimal formats, full integer support including long long, C99 + hexadecimal formats, full integer support including long long, C99 integer size specifiers (j, z, t) and POSIX positional arguments. 'long long' mode removes float support, 'integer' removes long long support while 'minimal' mode also removes support for format modifiers and diff --git a/doc/releases/release-notes-2.2.rst b/doc/releases/release-notes-2.2.rst index 097d0674999..3a9922f4f00 100644 --- a/doc/releases/release-notes-2.2.rst +++ b/doc/releases/release-notes-2.2.rst @@ -197,7 +197,7 @@ Kernel * Propagate a distinct error code if a workqueue item is submitted that has already been completed * Disable preemption when handing fatal errors -* Fix an issue with the sytsem call stack frame if the system call is +* Fix an issue with the system call stack frame if the system call is preempted and then later tries to Z_OOPS() * add k_thread_stack_space_get() system call for analyzing thread stack space. Older methods which had problems in some cases or on some @@ -636,7 +636,7 @@ Bluetooth address resolution support * Added dynamic TX power control, including a set of vendor-specific commands to read and write the TX power - * Added a Kconfig option, BT_CTLR_PARAM_CHECK, to enable addtional parameter + * Added a Kconfig option, BT_CTLR_PARAM_CHECK, to enable additional parameter checking * Added basic support for SMI (Stable Modulation Index) * Ticker: Implemented dynamic rescheduling diff --git a/doc/releases/release-notes-2.4.rst b/doc/releases/release-notes-2.4.rst index b2b22f8fae0..ca5f82561f6 100644 --- a/doc/releases/release-notes-2.4.rst +++ b/doc/releases/release-notes-2.4.rst @@ -73,7 +73,7 @@ API Changes * ```` has seen its callback normalized. It had its signature changed to add a struct device pointer as first parameter. Such callback - signature has been generalized throuh the addition of dma_callback_t. + signature has been generalized through the addition of dma_callback_t. 'callback_arg' argument has been renamed to 'user_data. All user code have been modified accordingly. @@ -98,7 +98,7 @@ API Changes * All device instances got a const qualifier. So this applies to all APIs manipulating ``struct device *`` (ADC, GPIO, I2C, ...). In order to avoid const qualifier loss on ISRs, all ISRs now take a ``const *void`` as a - paremeter as well. + parameter as well. * The ``_gatt_`` and ``_GATT_`` infixes have been removed for the HRS, DIS and BAS APIs and the Kconfig options. @@ -400,7 +400,7 @@ Drivers and Sensors * DMA - * STM32: Number of changes including k_malloc removal, driver piority init + * STM32: Number of changes including k_malloc removal, driver priority init increase, get_status API addition and various cleanups. * Added MCUX EDMA driver for i.MX RT and Kinetis K6x SoCs. * Added MCUX LPC driver for LPC and i.MX RT6xx SoCs. @@ -634,7 +634,7 @@ Networking * Added support for IPv6 multicast packet routing. * Added support to SOCK_DGRAM type sockets for AF_PACKET family. * Added support for using TLS sockets when using socket offloading. -* Added additonal checks in IPv6 to ensure that multicasts are only passed to the +* Added additional checks in IPv6 to ensure that multicasts are only passed to the upper layer if the originating interface actually joined the destination multicast group. * Allow user to specify TCP port number in HTTP request. diff --git a/doc/releases/release-notes-2.5.rst b/doc/releases/release-notes-2.5.rst index af2f414d7bb..5f4e7feaa11 100644 --- a/doc/releases/release-notes-2.5.rst +++ b/doc/releases/release-notes-2.5.rst @@ -453,7 +453,7 @@ Drivers and Sensors * I2C - * Added driver support for lmx6x, it8xxx2, and npcx7 plaforms. + * Added driver support for lmx6x, it8xxx2, and npcx7 platforms. * Added Atmel SAM4L TWIM driver. * Added I2C slave support in the microchip i2c driver. * Reversed 2.4 decision to downgrade I2C eeprom slave driver to a @@ -900,7 +900,7 @@ MCUBoot * Renamed single-image mode to single-slot mode, see ``CONFIG_SINGLE_APPLICATION_SLOT``. * Added patch for turning off cache for Cortex M7 before chain-loading. - * Fixed boostrapping in swap-move mode. + * Fixed bootstrapping in swap-move mode. * Fixed issue causing that interrupted swap-move operation might brick device if the primary image was padded. * Fixed issue causing that HW stack protection catches the chain-loaded diff --git a/doc/releases/release-notes-2.6.rst b/doc/releases/release-notes-2.6.rst index c4ad995f281..53864fa2508 100644 --- a/doc/releases/release-notes-2.6.rst +++ b/doc/releases/release-notes-2.6.rst @@ -259,7 +259,7 @@ Bluetooth * Added the ability to send HCI monitor traces over RTT. * Refactored the Bluetooth buffer configuration for simplicity. See the commit message of 6483e12a8ac4f495b28279a6b84014f633b0d374 for more info. - Note however that the aformentioned commit message has two typos; + Note however that the aforementioned commit message has two typos; * ``BT_CTLR_TX_BUFFER`` should be ``BT_CTLR_TX_BUFFERS`` * ``BT_CTLR_TX_BUFFERS_SIZE`` should be ``BT_CTLR_TX_BUFFER_SIZE`` @@ -611,7 +611,7 @@ Drivers and Sensors * Sensor * Added support for STM32 internal (CPU) temperature sensor. - * Refactored mulitple ST sensor drivers to use gpio_dt_spec macros and common + * Refactored multiple ST sensor drivers to use gpio_dt_spec macros and common stmemc routines, support multiple instances, and configure ODR/range properties in device tree. * Added SBS 1.1 compliant fuel gauge driver. @@ -1038,7 +1038,7 @@ Tests and Samples filter: dt_enabled_alias_with_parent_compat("led0", "gpio-leds") * Add a feature which handles pytest script in twister and provide an example. -* Provide test excution time per ztest testcase. +* Provide test execution time per ztest testcase. * Added and refined some testcases, most of them are negative testcases, to improve the test code coverage: diff --git a/doc/releases/release-notes-2.7.rst b/doc/releases/release-notes-2.7.rst index c7e80d3d83f..91f6393197a 100644 --- a/doc/releases/release-notes-2.7.rst +++ b/doc/releases/release-notes-2.7.rst @@ -730,7 +730,7 @@ USB * Added new header file where all defines and structures from Chapter 9 (USB Device Framework) should be included. -* Revised configuraiton of USB device support. +* Revised configuration of USB device support. Removed Kconfig option ``CONFIG_USB`` and introduced Kconfig option ``CONFIG_USB_DEVICE_DRIVER`` to enable USB device controller drivers, which is selected when option ``CONFIG_USB_DEVICE_STACK`` is enabled. diff --git a/doc/releases/release-notes-3.0.rst b/doc/releases/release-notes-3.0.rst index 42280613749..a03beb7d0d5 100644 --- a/doc/releases/release-notes-3.0.rst +++ b/doc/releases/release-notes-3.0.rst @@ -380,7 +380,7 @@ Bluetooth * Updated the supported Bluetooth HCI version to 5.3 * Added support for Periodic Advertiser List * Added support for Periodic Advertising Synchronization Receive Enable - * Added support for filter access list filtering for exended scanning + * Added support for filter access list filtering for extended scanning * Added support for Advertising Extensions dynamic TX power control * Added handling of direct address type in extended adv reports * Implemented auxiliary PDU device address matching @@ -660,7 +660,7 @@ Networking * Added support for multiple LwM2M Firmware Update object instances. * Improved error handling in LwM2M content writers. * Added unit tests for LwM2M content writers. - * Implmented LwM2M Security, Server, Connection Monitor objects in version 1.1. + * Implemented LwM2M Security, Server, Connection Monitor objects in version 1.1. * Multiple minor bugfixes in the LwM2M stack. * Added support for the following objects: @@ -678,7 +678,7 @@ Networking unaliged access warnings from gcc. * Added automatic loopback addresses registration to loopback interface. * Fixed source address selection for ARP. - * Allow to implment a custom IEEE802154 L2 on top of existing drivers. + * Allow to implement a custom IEEE802154 L2 on top of existing drivers. * Introduced a network packet filtering framework. * MQTT: diff --git a/doc/releases/release-notes-3.1.rst b/doc/releases/release-notes-3.1.rst index 517ef1c6e3c..fe631d3c766 100644 --- a/doc/releases/release-notes-3.1.rst +++ b/doc/releases/release-notes-3.1.rst @@ -620,7 +620,7 @@ Networking * Added a :kconfig:option:`CONFIG_NET_ETHERNET_FORWARD_UNRECOGNISED_ETHERTYPE` option, which allows to forward frames with unrecognised EtherType to the - netowrk stack. + network stack. * HTTP: @@ -1721,7 +1721,7 @@ Addressed issues * :github:`43344` - intel_adsp_cavs25: samples/subsys/logging/syst is failing with a timeout when the sample is enabled to run on intel_adsp_cavs25 * :github:`43333` - RFC: Bring zcbor as CBOR decoder/encoder in replacement for TinyCBOR * :github:`43326` - Unstable SD Card performance on Teensy 4.1 -* :github:`43319` - Hardware reset cause api sets reset pin bit everytime the api is called +* :github:`43319` - Hardware reset cause api sets reset pin bit every time the api is called * :github:`43316` - stm32wl55 cannot enable PLL source as MSI * :github:`43314` - LE Audio: BAP ``sent`` callback missing * :github:`43310` - disco_l475_iot1: BLE not working diff --git a/doc/releases/release-notes-3.2.rst b/doc/releases/release-notes-3.2.rst index cf27f017fcb..11e923b0f8e 100644 --- a/doc/releases/release-notes-3.2.rst +++ b/doc/releases/release-notes-3.2.rst @@ -165,7 +165,7 @@ Deprecated in this release * Flash Map API macros :c:macro:`FLASH_MAP_`, which have been using DTS node label property to reference partitions, have been deprecated and replaced with - :c:macro:`FIXED_PARTITION_` whch use DTS node label instead. + :c:macro:`FIXED_PARTITION_` which use DTS node label instead. Replacement list: .. table:: @@ -270,7 +270,7 @@ Architectures * Reduced callee-saved registers for RV32E. * Introduced Zicsr, Zifencei and BitManip as separate extensions. * Introduced :kconfig:option:`CONFIG_RISCV_ALWAYS_SWITCH_THROUGH_ECALL` for - plaforms that require every ``mret`` to be balanced by ``ecall``. + platforms that require every ``mret`` to be balanced by ``ecall``. * IRQ vector table is now used for vectored mode. * Disabled :kconfig:option:`CONFIG_IRQ_VECTOR_TABLE_JUMP_BY_CODE` for CLIC. * ``STRINGIFY`` macro is now used for CSR helpers. @@ -511,7 +511,7 @@ Drivers and Sensors * The STM32 CAN-FD CAN driver clock configuration has been moved from Kconfig to :ref:`devicetree `. See the :dtcompatible:`st,stm32-fdcan` devicetree binding for more information. * The filter handling of STM32 bxCAN driver has been simplified and made more reliable. - * The STM32 bxCAN driver now supports dual intances. + * The STM32 bxCAN driver now supports dual instances. * The CAN loopback driver now supports CAN-FD. * The CAN shell module has been rewritten to properly support the additions and changes to the CAN controller API. @@ -543,7 +543,7 @@ Drivers and Sensors * DFU - * Fixed fetch of the flash write block size from incorect device by + * Fixed fetch of the flash write block size from incorrect device by ``flash_img``. * Fixed possible build failure in the image manager for mcuboot on redefinitions of :c:macro:`BOOT_MAX_ALIGN` and :c:macro:`BOOT_MAGIC_SZ`. @@ -757,7 +757,7 @@ Drivers and Sensors for various drivers. * Various fixes on ``lpuart``. * Added a workaround on bytes dropping on ``nrfx_uarte``. - * Fixed compilation error on ``uart_pl011`` when interrupt is diabled. + * Fixed compilation error on ``uart_pl011`` when interrupt is disabled. * Added power management support on ``stm32``. * ``xlnx_ps`` has moved to using ``DEVICE_MMIO`` API. * ``gd32`` now supports using reset API to reset hardware and clock @@ -1398,7 +1398,7 @@ Libraries / Subsystems response is now only used for mcumgr errors, shell command execution result codes are instead returned in the ``ret`` variable instead, see :ref:`mcumgr_smp_group_9` for updated - information. Legacy bahaviour can be restored by enabling + information. Legacy behaviour can be restored by enabling :kconfig:option:`CONFIG_MCUMGR_CMD_SHELL_MGMT_LEGACY_RC_RETURN_CODE`. * MCUMGR img_mgmt erase command now accepts an optional slot number to select which image will be erased, using the ``slot`` input diff --git a/doc/releases/release-notes-3.3.rst b/doc/releases/release-notes-3.3.rst index 312ad1e4754..b1590a5ee1d 100644 --- a/doc/releases/release-notes-3.3.rst +++ b/doc/releases/release-notes-3.3.rst @@ -742,7 +742,7 @@ Drivers and Sensors * STM32 OSPI: Now supports DMA transfer on STM32U5. - * STM32: Flash driver was revisited to simplify re-use of driver for new series, taking + * STM32: Flash driver was revisited to simplify reuse of driver for new series, taking advantage of device tree compatibles. * FPGA diff --git a/doc/releases/release-notes-3.4.rst b/doc/releases/release-notes-3.4.rst index 092fa251c6f..3b96c3e8bb8 100644 --- a/doc/releases/release-notes-3.4.rst +++ b/doc/releases/release-notes-3.4.rst @@ -776,7 +776,7 @@ Drivers and Sensors channel(s) to link a software channel configuration to. * MCUX LPADC driver ``voltage-ref`` and ``power-level`` devicetree properties were shifted to match the hardware as described in reference manual instead - of matching the NXP SDK enum identifers. + of matching the NXP SDK enum identifiers. * Added support for STM32C0 and STM32H5. * Added DMA support for STM32H7. * STM32: Resolutions are now listed in the device tree for each ADC instance diff --git a/doc/releases/release-notes-3.5.rst b/doc/releases/release-notes-3.5.rst index d7993bd7804..0ae90dd5c3e 100644 --- a/doc/releases/release-notes-3.5.rst +++ b/doc/releases/release-notes-3.5.rst @@ -260,7 +260,7 @@ Bluetooth * Fixed BIS payload sliding window overrun check * Fixed CIS Central FT calculation * Fixed CIS Central error handling - * Fixed CIS assymmetric PHY usage + * Fixed CIS asymmetric PHY usage * Fixed CIS encryption when DF support enabled * Fixed ISO-AL for quality tests and time stamps * Fixed PHY value in HCI LE CIS Established Event @@ -840,7 +840,7 @@ Networking When :kconfig:option:`CONFIG_LWM2M_COAP_BLOCK_TRANSFER` is enabled, any content that is larger than :kconfig:option:`CONFIG_LWM2M_COAP_MAX_MSG_SIZE` is split into a block-wise transfer. * Block-wise transfers don't require tokens to match anymore as this was not in line - with CoAP specification (CoAP doesn't require tokens re-use). + with CoAP specification (CoAP doesn't require tokens reuse). * Various fixes to bootstrap. Now client ensures that Bootstrap-Finish command is sent, before closing the DTLS pipe. Also allows Bootstrap server to close the DTLS pipe. Added timeout when waiting for bootstrap commands. @@ -2115,7 +2115,7 @@ Libraries / Subsystems * Added support of mounting littlefs on the block device from the shell/fs. * Added alignment parameter to FS_LITTLEFS_DECLARE_CUSTOM_CONFIG macro, it can speed up read/write operation for SDMMC devices in case when we align buffers on CONFIG_SDHC_BUFFER_ALIGNMENT, - because we can avoid extra copy of data from card bffer to read/prog buffer. + because we can avoid extra copy of data from card buffer to read/prog buffer. * Random diff --git a/doc/releases/release-notes-3.6.rst b/doc/releases/release-notes-3.6.rst index ad3bfc01703..7510a53f547 100644 --- a/doc/releases/release-notes-3.6.rst +++ b/doc/releases/release-notes-3.6.rst @@ -74,7 +74,7 @@ Boards & SoC Support * Made these changes in other SoC series: * Nordic SoCs now imply :kconfig:option:`CONFIG_XIP` instead of selecting it, this allows for - creating RAM-based applicatins by disabling it. + creating RAM-based applications by disabling it. * Added support for these ARC boards: From 3ff78288a6408e1fe5002fa4d1281bbf459483ee Mon Sep 17 00:00:00 2001 From: David Leach Date: Tue, 23 Jan 2024 10:11:59 -0600 Subject: [PATCH 2861/3723] manifest: update hal_nxp HAL update removes unneeded files to reduce the size of the NXP HAL. Signed-off-by: David Leach --- west.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/west.yml b/west.yml index 79af241f523..3534498609c 100644 --- a/west.yml +++ b/west.yml @@ -193,7 +193,7 @@ manifest: groups: - hal - name: hal_nxp - revision: 3d4be32141dd8605515d95f8d1a2340974190cff + revision: e6b0d96d865da1bdda357073570a13ae95e08d9c path: modules/hal/nxp groups: - hal From dcedb649cadd956d5d7162435fa49e3e7f021cd6 Mon Sep 17 00:00:00 2001 From: Declan Snyder Date: Tue, 23 Jan 2024 17:20:04 -0600 Subject: [PATCH 2862/3723] drivers: nxp_enet: Fix build error with PTP on Fix build errors in nxp enet driver during case where PTP on, and add coverage to CI. Signed-off-by: Declan Snyder --- drivers/ethernet/eth_nxp_enet.c | 9 ++++++--- drivers/ptp_clock/ptp_clock_nxp_enet.c | 6 +++--- samples/net/gptp/sample.yaml | 7 +++++++ 3 files changed, 16 insertions(+), 6 deletions(-) diff --git a/drivers/ethernet/eth_nxp_enet.c b/drivers/ethernet/eth_nxp_enet.c index e85edf46b82..244867dddf6 100644 --- a/drivers/ethernet/eth_nxp_enet.c +++ b/drivers/ethernet/eth_nxp_enet.c @@ -39,6 +39,7 @@ LOG_MODULE_REGISTER(LOG_MODULE_NAME); #include #include #include +#include #if defined(CONFIG_NET_DSA) #include #endif @@ -351,7 +352,7 @@ static int eth_nxp_enet_rx(const struct device *dev) uint16_t vlan_tag = NET_VLAN_TAG_UNSPEC; uint32_t frame_length = 0U; struct net_if *iface; - struct net_pkt *pkt; + struct net_pkt *pkt = NULL; status_t status; uint32_t ts; @@ -420,7 +421,7 @@ static int eth_nxp_enet_rx(const struct device *dev) if (eth_get_ptp_data(get_iface(data, vlan_tag), pkt)) { struct net_ptp_time ptp_time; - ptp_clock_nxp_enet_get(config->ptp_clock, &ptp_time); + ptp_clock_get(config->ptp_clock, &ptp_time); /* If latest timestamp reloads after getting from Rx BD, * then second - 1 to make sure the actual Rx timestamp is accurate @@ -453,7 +454,9 @@ static int eth_nxp_enet_rx(const struct device *dev) 0, RING_ID, NULL); __ASSERT_NO_MSG(status == kStatus_Success); error: - net_pkt_unref(pkt); + if (pkt) { + net_pkt_unref(pkt); + } eth_stats_update_errors_rx(get_iface(data, vlan_tag)); return -EIO; } diff --git a/drivers/ptp_clock/ptp_clock_nxp_enet.c b/drivers/ptp_clock/ptp_clock_nxp_enet.c index 821557cf79d..943ff6ca4ea 100644 --- a/drivers/ptp_clock/ptp_clock_nxp_enet.c +++ b/drivers/ptp_clock/ptp_clock_nxp_enet.c @@ -153,7 +153,7 @@ static int ptp_clock_nxp_enet_rate_adjust(const struct device *dev, void nxp_enet_ptp_clock_callback(const struct device *dev, enum nxp_enet_callback_reason event, - void *data) + void *cb_data) { const struct ptp_clock_nxp_enet_config *config = dev->config; struct ptp_clock_nxp_enet_data *data = dev->data; @@ -181,9 +181,9 @@ void nxp_enet_ptp_clock_callback(const struct device *dev, &ptp_config); } - if (data != NULL) { + if (cb_data != NULL) { /* Share the mutex with mac driver */ - *(struct k_mutex *)data = &data->ptp_mutex; + *(uintptr_t *)cb_data = (uintptr_t)&data->ptp_mutex; } } diff --git a/samples/net/gptp/sample.yaml b/samples/net/gptp/sample.yaml index a668d6325a5..e65327ef47a 100644 --- a/samples/net/gptp/sample.yaml +++ b/samples/net/gptp/sample.yaml @@ -21,3 +21,10 @@ tests: depends_on: netif integration_platforms: - frdm_k64f + sample.net.gpt.nxp_enet_experimental: + extra_args: EXTRA_DTC_OVERLAY_FILE="nxp,enet-experimental.overlay" + platform_allow: + - mimxrt1050_evk + - mimxrt1060_evk + - mimxrt1064_evk + - mimxrt1024_evk From 0d27dd5dd3a245df5482d34ccce6a78df5a874b7 Mon Sep 17 00:00:00 2001 From: Magdalena Kasenberg Date: Tue, 28 Nov 2023 08:44:30 +0100 Subject: [PATCH 2863/3723] bluetooth: tester: Add support for CAP Add support for CAP test cases. Split btp_bap.c for better maintenance into unicast and broadcast. Signed-off-by: Magdalena Kasenberg --- tests/bluetooth/tester/CMakeLists.txt | 21 +- tests/bluetooth/tester/overlay-le-audio.conf | 10 +- tests/bluetooth/tester/src/btp/btp.h | 6 +- tests/bluetooth/tester/src/btp/btp_ascs.h | 14 +- tests/bluetooth/tester/src/btp/btp_cap.h | 165 + tests/bluetooth/tester/src/btp/btp_csip.h | 24 + tests/bluetooth/tester/src/btp/bttester.h | 6 + tests/bluetooth/tester/src/btp_bap.c | 3067 +---------------- .../tester/src/btp_bap_audio_stream.c | 183 + .../tester/src/btp_bap_audio_stream.h | 23 + .../bluetooth/tester/src/btp_bap_broadcast.c | 1571 +++++++++ .../bluetooth/tester/src/btp_bap_broadcast.h | 100 + tests/bluetooth/tester/src/btp_bap_unicast.c | 1649 +++++++++ tests/bluetooth/tester/src/btp_bap_unicast.h | 71 + tests/bluetooth/tester/src/btp_cap.c | 905 +++++ tests/bluetooth/tester/src/btp_core.c | 20 + tests/bluetooth/tester/src/btp_csip.c | 204 ++ tests/bluetooth/tester/src/btp_gap.c | 15 +- 18 files changed, 5042 insertions(+), 3012 deletions(-) create mode 100644 tests/bluetooth/tester/src/btp/btp_cap.h create mode 100644 tests/bluetooth/tester/src/btp/btp_csip.h create mode 100644 tests/bluetooth/tester/src/btp_bap_audio_stream.c create mode 100644 tests/bluetooth/tester/src/btp_bap_audio_stream.h create mode 100644 tests/bluetooth/tester/src/btp_bap_broadcast.c create mode 100644 tests/bluetooth/tester/src/btp_bap_broadcast.h create mode 100644 tests/bluetooth/tester/src/btp_bap_unicast.c create mode 100644 tests/bluetooth/tester/src/btp_bap_unicast.h create mode 100644 tests/bluetooth/tester/src/btp_cap.c create mode 100644 tests/bluetooth/tester/src/btp_csip.c diff --git a/tests/bluetooth/tester/CMakeLists.txt b/tests/bluetooth/tester/CMakeLists.txt index 6ec469dc0fd..ace7b33162e 100644 --- a/tests/bluetooth/tester/CMakeLists.txt +++ b/tests/bluetooth/tester/CMakeLists.txt @@ -32,8 +32,19 @@ if(CONFIG_BT_IAS OR CONFIG_BT_IAS_CLIENT) target_sources(app PRIVATE src/btp_ias.c) endif() +if(CONFIG_BT_BAP_UNICAST OR BT_BAP_BROADCAST_SOURCE OR BT_BAP_BROADCAST_SINK) + target_sources(app PRIVATE + src/btp_bap_audio_stream.c + src/btp_bap.c + ) +endif() + if(CONFIG_BT_BAP_UNICAST) - target_sources(app PRIVATE src/btp_bap.c) + target_sources(app PRIVATE src/btp_bap_unicast.c) +endif() + +if(CONFIG_BT_BAP_BROADCAST_SOURCE OR CONFIG_BT_BAP_BROADCAST_SOURCE) + target_sources(app PRIVATE src/btp_bap_broadcast.c) endif() if(CONFIG_BT_HAS) @@ -44,6 +55,10 @@ if (CONFIG_BT_CSIP_SET_MEMBER) target_sources(app PRIVATE src/btp_csis.c) endif() +if (CONFIG_BT_CSIP_SET_COORDINATOR) + target_sources(app PRIVATE src/btp_csip.c) +endif() + if(CONFIG_BT_MICP_MIC_DEV) target_sources(app PRIVATE src/btp_micp.c) endif() @@ -67,3 +82,7 @@ endif() if(CONFIG_BT_HAS) target_sources(app PRIVATE src/btp_hap.c) endif() + +if(CONFIG_BT_CAP_INITIATOR) + target_sources(app PRIVATE src/btp_cap.c) +endif() diff --git a/tests/bluetooth/tester/overlay-le-audio.conf b/tests/bluetooth/tester/overlay-le-audio.conf index eb2abbf1a68..5cc54e841b6 100644 --- a/tests/bluetooth/tester/overlay-le-audio.conf +++ b/tests/bluetooth/tester/overlay-le-audio.conf @@ -5,7 +5,7 @@ CONFIG_BT_BAP_UNICAST_CLIENT=y CONFIG_BT_BAP_UNICAST_CLIENT_ASE_SNK_COUNT=2 CONFIG_BT_BAP_UNICAST_CLIENT_ASE_SRC_COUNT=2 CONFIG_BT_BAP_UNICAST_CLIENT_GROUP_STREAM_COUNT=4 -CONFIG_BT_AUDIO_CODEC_CFG_MAX_METADATA_SIZE=16 +CONFIG_BT_AUDIO_CODEC_CFG_MAX_METADATA_SIZE=22 # Ring buffer for streaming ISO data CONFIG_RING_BUFFER=y @@ -20,6 +20,11 @@ CONFIG_BT_BUF_CMD_TX_SIZE=255 # were freed too slow. The bt_bap_stream_ops.configured callback comes earlier. CONFIG_BT_L2CAP_TX_BUF_COUNT=4 +# CAP +CONFIG_BT_CAP_INITIATOR=y +# To have multiple CCIDs +CONFIG_BT_TBS=y + # MICP CONFIG_BT_MICP_MIC_DEV=y CONFIG_BT_MICP_MIC_DEV_AICS_INSTANCE_COUNT=1 @@ -95,6 +100,9 @@ CONFIG_BT_HAS_CLIENT=y # CSIS CONFIG_BT_CSIP_SET_MEMBER=y +# CSIP +CONFIG_BT_CSIP_SET_COORDINATOR=y + # CCP CONFIG_BT_ATT_TX_COUNT=12 CONFIG_BT_TBS_CLIENT_GTBS=y diff --git a/tests/bluetooth/tester/src/btp/btp.h b/tests/bluetooth/tester/src/btp/btp.h index e9c6f5ce65f..3d8a7dc93fb 100644 --- a/tests/bluetooth/tester/src/btp/btp.h +++ b/tests/bluetooth/tester/src/btp/btp.h @@ -33,6 +33,8 @@ #include "btp_mcp.h" #include "btp_mcs.h" #include "btp_hap.h" +#include "btp_csip.h" +#include "btp_cap.h" #define BTP_MTU 1024 #define BTP_DATA_MAX_SIZE (BTP_MTU - sizeof(struct btp_hdr)) @@ -65,8 +67,10 @@ #define BTP_SERVICE_ID_MCP 22 #define BTP_SERVICE_ID_GMCS 23 #define BTP_SERVICE_ID_HAP 24 +#define BTP_SERVICE_ID_CSIP 25 +#define BTP_SERVICE_ID_CAP 26 -#define BTP_SERVICE_ID_MAX BTP_SERVICE_ID_HAP +#define BTP_SERVICE_ID_MAX BTP_SERVICE_ID_CAP #define BTP_STATUS_SUCCESS 0x00 #define BTP_STATUS_FAILED 0x01 diff --git a/tests/bluetooth/tester/src/btp/btp_ascs.h b/tests/bluetooth/tester/src/btp/btp_ascs.h index 739e8c7d824..f1734991291 100644 --- a/tests/bluetooth/tester/src/btp/btp_ascs.h +++ b/tests/bluetooth/tester/src/btp/btp_ascs.h @@ -73,7 +73,7 @@ struct btp_ascs_update_metadata_cmd { uint8_t ase_id; } __packed; -#define BTP_ASCS_ADD_ASE_TO_CIS 0x0a +#define BTP_ASCS_ADD_ASE_TO_CIS 0x0a struct btp_ascs_add_ase_to_cis { bt_addr_le_t address; uint8_t ase_id; @@ -81,6 +81,18 @@ struct btp_ascs_add_ase_to_cis { uint8_t cis_id; } __packed; +#define BTP_ASCS_PRECONFIGURE_QOS 0x0b +struct btp_ascs_preconfigure_qos_cmd { + uint8_t cig_id; + uint8_t cis_id; + uint8_t sdu_interval[3]; + uint8_t framing; + uint16_t max_sdu; + uint8_t retransmission_num; + uint16_t max_transport_latency; + uint8_t presentation_delay[3]; +} __packed; + /* ASCS events */ #define BTP_ASCS_EV_OPERATION_COMPLETED 0x80 struct btp_ascs_operation_completed_ev { diff --git a/tests/bluetooth/tester/src/btp/btp_cap.h b/tests/bluetooth/tester/src/btp/btp_cap.h new file mode 100644 index 00000000000..4369e87536a --- /dev/null +++ b/tests/bluetooth/tester/src/btp/btp_cap.h @@ -0,0 +1,165 @@ +/* btp_cap.h - Bluetooth tester headers */ + +/* + * Copyright (c) 2023 Codecoup + * + * SPDX-License-Identifier: Apache-2.0 + */ + +/* CAP commands */ +#define BTP_CAP_READ_SUPPORTED_COMMANDS 0x01 +struct btp_cap_read_supported_commands_rp { + uint8_t data[0]; +} __packed; + +#define BTP_CAP_DISCOVER 0x02 +struct btp_cap_discover_cmd { + bt_addr_le_t address; +} __packed; + +#define BTP_CAP_UNICAST_SETUP_ASE 0x03 +struct btp_cap_unicast_setup_ase_cmd { + bt_addr_le_t address; + uint8_t ase_id; + uint8_t cis_id; + uint8_t cig_id; + uint8_t coding_format; + uint16_t vid; + uint16_t cid; + uint8_t sdu_interval[3]; + uint8_t framing; + uint16_t max_sdu; + uint8_t retransmission_num; + uint16_t max_transport_latency; + uint8_t presentation_delay[3]; + uint8_t cc_ltvs_len; + uint8_t metadata_ltvs_len; + uint8_t ltvs[0]; +} __packed; + +#define BTP_CAP_UNICAST_AUDIO_START 0x04 +struct btp_cap_unicast_audio_start_cmd { + uint8_t cig_id; + uint8_t set_type; +} __packed; +#define BTP_CAP_UNICAST_AUDIO_START_SET_TYPE_AD_HOC 0x00 +#define BTP_CAP_UNICAST_AUDIO_START_SET_TYPE_CSIP 0x01 + +#define BTP_CAP_UNICAST_AUDIO_UPDATE 0x05 +struct btp_cap_unicast_audio_update_cmd { + uint8_t stream_count; + uint8_t update_data[0]; +} __packed; +struct btp_cap_unicast_audio_update_data { + bt_addr_le_t address; + uint8_t ase_id; + uint8_t metadata_ltvs_len; + uint8_t metadata_ltvs[0]; +} __packed; + +#define BTP_CAP_UNICAST_AUDIO_STOP 0x06 +struct btp_cap_unicast_audio_stop_cmd { + uint8_t cig_id; +} __packed; + +#define BTP_CAP_BROADCAST_SOURCE_SETUP_STREAM 0x07 +struct btp_cap_broadcast_source_setup_stream_cmd { + uint8_t source_id; + uint8_t subgroup_id; + uint8_t coding_format; + uint16_t vid; + uint16_t cid; + uint8_t cc_ltvs_len; + uint8_t metadata_ltvs_len; + uint8_t ltvs[0]; +} __packed; + +#define BTP_CAP_BROADCAST_SOURCE_SETUP_SUBGROUP 0x08 +struct btp_cap_broadcast_source_setup_subgroup_cmd { + uint8_t source_id; + uint8_t subgroup_id; + uint8_t coding_format; + uint16_t vid; + uint16_t cid; + uint8_t cc_ltvs_len; + uint8_t metadata_ltvs_len; + uint8_t ltvs[0]; +} __packed; + +#define BTP_CAP_BROADCAST_SOURCE_SETUP 0x09 +struct btp_cap_broadcast_source_setup_cmd { + uint8_t source_id; + uint8_t broadcast_id[3]; + uint8_t sdu_interval[3]; + uint8_t framing; + uint16_t max_sdu; + uint8_t retransmission_num; + uint16_t max_transport_latency; + uint8_t presentation_delay[3]; + uint8_t flags; + uint8_t broadcast_code[BT_AUDIO_BROADCAST_CODE_SIZE]; +} __packed; +struct btp_cap_broadcast_source_setup_rp { + uint8_t source_id; + uint32_t gap_settings; + uint8_t broadcast_id[BT_AUDIO_BROADCAST_ID_SIZE]; +} __packed; +#define BTP_CAP_BROADCAST_SOURCE_SETUP_FLAG_ENCRYPTION BIT(0) +#define BTP_CAP_BROADCAST_SOURCE_SETUP_FLAG_SUBGROUP_CODEC BIT(1) + +#define BTP_CAP_BROADCAST_SOURCE_RELEASE 0x0a +struct btp_cap_broadcast_source_release_cmd { + uint8_t source_id; +} __packed; + +#define BTP_CAP_BROADCAST_ADV_START 0x0b +struct btp_cap_broadcast_adv_start_cmd { + uint8_t source_id; +} __packed; + +#define BTP_CAP_BROADCAST_ADV_STOP 0x0c +struct btp_cap_broadcast_adv_stop_cmd { + uint8_t source_id; +} __packed; + +#define BTP_CAP_BROADCAST_SOURCE_START 0x0d +struct btp_cap_broadcast_source_start_cmd { + uint8_t source_id; +} __packed; + +#define BTP_CAP_BROADCAST_SOURCE_STOP 0x0e +struct btp_cap_broadcast_source_stop_cmd { + uint8_t source_id; +} __packed; + +#define BTP_CAP_BROADCAST_SOURCE_UPDATE 0x0f +struct btp_cap_broadcast_source_update_cmd { + uint8_t source_id; + uint8_t metadata_ltvs_len; + uint8_t metadata_ltvs[0]; +} __packed; + +/* CAP events */ +#define BTP_CAP_EV_DISCOVERY_COMPLETED 0x80 +struct btp_cap_discovery_completed_ev { + bt_addr_le_t address; + uint8_t status; +} __packed; +#define BTP_CAP_DISCOVERY_STATUS_SUCCESS 0x00 +#define BTP_CAP_DISCOVERY_STATUS_FAILED 0x01 + +#define BTP_CAP_EV_UNICAST_START_COMPLETED 0x81 +struct btp_cap_unicast_start_completed_ev { + uint8_t cig_id; + uint8_t status; +} __packed; +#define BTP_CAP_UNICAST_START_STATUS_SUCCESS 0x00 +#define BTP_CAP_UNICAST_START_STATUS_FAILED 0x01 + +#define BTP_CAP_EV_UNICAST_STOP_COMPLETED 0x82 +struct btp_cap_unicast_stop_completed_ev { + uint8_t cig_id; + uint8_t status; +} __packed; +#define BTP_CAP_UNICAST_STOP_STATUS_SUCCESS 0x00 +#define BTP_CAP_UNICAST_STOP_STATUS_FAILED 0x01 diff --git a/tests/bluetooth/tester/src/btp/btp_csip.h b/tests/bluetooth/tester/src/btp/btp_csip.h new file mode 100644 index 00000000000..ee546206c59 --- /dev/null +++ b/tests/bluetooth/tester/src/btp/btp_csip.h @@ -0,0 +1,24 @@ +/* btp_csip.h - Bluetooth tester headers */ + +/* + * Copyright (c) 2023 Codecoup + * + * SPDX-License-Identifier: Apache-2.0 + */ +#include + +/* CSIP commands */ +#define BTP_CSIP_READ_SUPPORTED_COMMANDS 0x01 +struct btp_csip_read_supported_commands_rp { + uint8_t data[0]; +} __packed; + +#define BTP_CSIP_DISCOVER 0x02 +struct btp_csip_discover_cmd { + bt_addr_le_t address; +} __packed; + +#define BTP_CSIP_START_ORDERED_ACCESS 0x03 +struct btp_csip_start_ordered_access_cmd { + uint8_t flags; +} __packed; diff --git a/tests/bluetooth/tester/src/btp/bttester.h b/tests/bluetooth/tester/src/btp/bttester.h index c4e6397bebb..bce0e10ed97 100644 --- a/tests/bluetooth/tester/src/btp/bttester.h +++ b/tests/bluetooth/tester/src/btp/bttester.h @@ -100,6 +100,9 @@ uint8_t tester_unregister_has(void); uint8_t tester_init_csis(void); uint8_t tester_unregister_csis(void); +uint8_t tester_init_csip(void); +uint8_t tester_unregister_csip(void); + uint8_t tester_init_micp(void); uint8_t tester_unregister_micp(void); @@ -115,6 +118,9 @@ uint8_t tester_unregister_vcp(void); uint8_t tester_init_cas(void); uint8_t tester_unregister_cas(void); +uint8_t tester_init_cap(void); +uint8_t tester_unregister_cap(void); + uint8_t tester_init_mcp(void); uint8_t tester_unregister_mcp(void); diff --git a/tests/bluetooth/tester/src/btp_bap.c b/tests/bluetooth/tester/src/btp_bap.c index 73f4b0f5547..e69f2ce314f 100644 --- a/tests/bluetooth/tester/src/btp_bap.c +++ b/tests/bluetooth/tester/src/btp_bap.c @@ -13,19 +13,18 @@ #include #include #include - -#include -#include #include #include #include -#include "bap_endpoint.h" #include #include #define LOG_MODULE_NAME bttester_bap LOG_MODULE_REGISTER(LOG_MODULE_NAME, CONFIG_BTTESTER_LOG_LEVEL); #include "btp/btp.h" +#include "btp_bap_audio_stream.h" +#include "btp_bap_unicast.h" +#include "btp_bap_broadcast.h" #define SUPPORTED_SINK_CONTEXT BT_AUDIO_CONTEXT_TYPE_ANY #define SUPPORTED_SOURCE_CONTEXT BT_AUDIO_CONTEXT_TYPE_ANY @@ -36,2372 +35,13 @@ LOG_MODULE_REGISTER(LOG_MODULE_NAME, CONFIG_BTTESTER_LOG_LEVEL); static const struct bt_audio_codec_cap default_codec_cap = BT_AUDIO_CODEC_CAP_LC3( BT_AUDIO_CODEC_LC3_FREQ_ANY, BT_AUDIO_CODEC_LC3_DURATION_7_5 | BT_AUDIO_CODEC_LC3_DURATION_10, BT_AUDIO_CODEC_LC3_CHAN_COUNT_SUPPORT(1, 2), 26u, 155u, 1u, - BT_AUDIO_CONTEXT_TYPE_ANY); - -static const struct bt_audio_codec_cap vendor_codec_cap = BT_AUDIO_CODEC_CAP( - 0xff, 0xffff, 0xffff, BT_AUDIO_CODEC_CAP_LC3_DATA(BT_AUDIO_CODEC_LC3_FREQ_ANY, - BT_AUDIO_CODEC_LC3_DURATION_7_5 | BT_AUDIO_CODEC_LC3_DURATION_10, - BT_AUDIO_CODEC_LC3_CHAN_COUNT_SUPPORT(1, 2), 26u, 155, 1u), - BT_AUDIO_CODEC_CAP_LC3_META(BT_AUDIO_CONTEXT_TYPE_ANY)); - -struct audio_stream { - struct bt_bap_stream stream; - atomic_t seq_num; - uint16_t last_req_seq_num; - uint16_t last_sent_seq_num; - uint16_t max_sdu; - size_t len_to_send; - struct k_work_delayable audio_clock_work; - struct k_work_delayable audio_send_work; - bool already_sent; - bool broadcast; - - union { - /* Unicast */ - struct { - uint8_t ase_id; - uint8_t conn_id; - uint8_t cig_id; - uint8_t cis_id; - struct bt_bap_unicast_group **cig; - }; - - /* Broadcast */ - struct { - uint8_t bis_id; - bool bis_synced; - }; - }; -}; - -#define MAX_STREAMS_COUNT MAX(CONFIG_BT_BAP_UNICAST_CLIENT_ASE_SNK_COUNT, \ - CONFIG_BT_ASCS_ASE_SNK_COUNT) + MAX(CONFIG_BT_ASCS_ASE_SRC_COUNT,\ - CONFIG_BT_BAP_UNICAST_CLIENT_ASE_SRC_COUNT) -#define MAX_END_POINTS_COUNT CONFIG_BT_BAP_UNICAST_CLIENT_ASE_SRC_COUNT + \ - CONFIG_BT_BAP_UNICAST_CLIENT_ASE_SNK_COUNT -struct audio_connection { - struct audio_stream streams[MAX_STREAMS_COUNT]; - size_t configured_sink_stream_count; - size_t configured_source_stream_count; - struct bt_audio_codec_cfg codec_cfg; - struct bt_audio_codec_qos qos; - struct bt_bap_ep *end_points[MAX_END_POINTS_COUNT]; - size_t end_points_count; -} connections[CONFIG_BT_MAX_CONN], broadcast_connection; - -static struct bt_bap_unicast_group *cigs[CONFIG_BT_ISO_MAX_CIG]; - -static struct bt_audio_codec_qos_pref qos_pref = - BT_AUDIO_CODEC_QOS_PREF(true, BT_GAP_LE_PHY_2M, 0x02, 10, 10000, 40000, 10000, 40000); - -NET_BUF_POOL_FIXED_DEFINE(tx_pool, MAX(CONFIG_BT_ASCS_ASE_SRC_COUNT, - CONFIG_BT_BAP_UNICAST_CLIENT_ASE_SRC_COUNT), - BT_ISO_SDU_BUF_SIZE(CONFIG_BT_ISO_TX_MTU), 8, NULL); - -static struct net_buf_simple *rx_ev_buf = NET_BUF_SIMPLE(CONFIG_BT_ISO_RX_MTU + - sizeof(struct btp_bap_stream_received_ev)); - -RING_BUF_DECLARE(audio_ring_buf, CONFIG_BT_ISO_TX_MTU); -static void audio_clock_timeout(struct k_work *work); -static void audio_send_timeout(struct k_work *work); - -#define ISO_DATA_THREAD_STACK_SIZE 512 -#define ISO_DATA_THREAD_PRIORITY -7 -K_THREAD_STACK_DEFINE(iso_data_thread_stack_area, ISO_DATA_THREAD_STACK_SIZE); -static struct k_work_q iso_data_work_q; - -static struct bt_bap_broadcast_source *broadcast_source; -static struct audio_connection *broadcaster; -static struct bt_bap_broadcast_sink *broadcast_sink; -static bt_addr_le_t broadcaster_addr; -static uint32_t broadcaster_broadcast_id; -static struct bt_bap_stream *sink_streams[MAX_STREAMS_COUNT]; -/* A mask for the maximum BIS we can sync to. +1 since the BIS indexes start from 1. */ -static const uint32_t bis_index_mask = BIT_MASK(MAX_STREAMS_COUNT + 1); -static uint32_t bis_index_bitfield; -static uint32_t requested_bis_sync; -#define INVALID_BROADCAST_ID (BT_AUDIO_BROADCAST_ID_MAX + 1) -#define SYNC_RETRY_COUNT 6 /* similar to retries for connections */ -#define PA_SYNC_SKIP 5 -/* Sample assumes that we only have a single Scan Delegator receive state */ -static const struct bt_bap_scan_delegator_recv_state *sink_recv_state; -static const struct bt_bap_scan_delegator_recv_state *broadcast_recv_state; -static uint8_t sink_broadcast_code[BT_AUDIO_BROADCAST_CODE_SIZE]; -static struct bt_bap_scan_delegator_subgroup - delegator_subgroups[BT_BAP_SCAN_DELEGATOR_MAX_SUBGROUPS]; - -static bool print_cb(struct bt_data *data, void *user_data) -{ - const char *str = (const char *)user_data; - - LOG_DBG("%s: type 0x%02x value_len %u", str, data->type, data->data_len); - LOG_HEXDUMP_DBG(data->data, data->data_len, ""); - - return true; -} - -static void print_codec_cfg(const struct bt_audio_codec_cfg *codec_cfg) -{ - LOG_DBG("codec_cfg 0x%02x cid 0x%04x vid 0x%04x count %u", codec_cfg->id, codec_cfg->cid, - codec_cfg->vid, codec_cfg->data_len); - - if (codec_cfg->id == BT_HCI_CODING_FORMAT_LC3) { - enum bt_audio_location chan_allocation; - int ret; - - /* LC3 uses the generic LTV format - other codecs might do as well */ - - bt_audio_data_parse(codec_cfg->data, codec_cfg->data_len, print_cb, "data"); - - ret = bt_audio_codec_cfg_get_freq(codec_cfg); - if (ret > 0) { - LOG_DBG(" Frequency: %d Hz", bt_audio_codec_cfg_freq_to_freq_hz(ret)); - } - - ret = bt_audio_codec_cfg_get_frame_dur(codec_cfg); - if (ret > 0) { - LOG_DBG(" Frame Duration: %d us", - bt_audio_codec_cfg_frame_dur_to_frame_dur_us(ret)); - } - - if (bt_audio_codec_cfg_get_chan_allocation(codec_cfg, &chan_allocation) == 0) { - LOG_DBG(" Channel allocation: 0x%x", chan_allocation); - } - - LOG_DBG(" Octets per frame: %d (negative means value not pressent)", - bt_audio_codec_cfg_get_octets_per_frame(codec_cfg)); - LOG_DBG(" Frames per SDU: %d", - bt_audio_codec_cfg_get_frame_blocks_per_sdu(codec_cfg, true)); - } else { - LOG_HEXDUMP_DBG(codec_cfg->data, codec_cfg->data_len, "data"); - } - - bt_audio_data_parse(codec_cfg->meta, codec_cfg->meta_len, print_cb, "meta"); -} - -static void print_codec_cap(const struct bt_audio_codec_cap *codec_cap) -{ - LOG_DBG("codec_cap 0x%02x cid 0x%04x vid 0x%04x count %zu", codec_cap->id, codec_cap->cid, - codec_cap->vid, codec_cap->data_len); - - if (codec_cap->id == BT_HCI_CODING_FORMAT_LC3) { - bt_audio_data_parse(codec_cap->data, codec_cap->data_len, print_cb, "data"); - } else { - LOG_HEXDUMP_DBG(codec_cap->data, codec_cap->data_len, "data"); - } - - bt_audio_data_parse(codec_cap->meta, codec_cap->meta_len, print_cb, "meta"); -} - -static inline void print_qos(const struct bt_audio_codec_qos *qos) -{ - LOG_DBG("QoS: interval %u framing 0x%02x phy 0x%02x sdu %u rtn %u latency %u pd %u", - qos->interval, qos->framing, qos->phy, qos->sdu, qos->rtn, qos->latency, qos->pd); -} - -static struct audio_stream *stream_alloc(struct audio_connection *conn) -{ - for (size_t i = 0; i < ARRAY_SIZE(conn->streams); i++) { - struct audio_stream *stream = &conn->streams[i]; - - if (!stream->stream.conn) { - return stream; - } - } - - return NULL; -} - -static void stream_free(struct audio_stream *stream) -{ - (void)memset(stream, 0, sizeof(*stream)); -} - -static struct audio_stream *stream_find(struct audio_connection *conn, uint8_t ase_id) -{ - for (size_t i = 0; i < ARRAY_SIZE(conn->streams); i++) { - struct bt_bap_stream *stream = &conn->streams[i].stream; - - if (stream->ep != NULL && stream->ep->status.id == ase_id) { - return &conn->streams[i]; - } - } - - return NULL; -} - -static struct bt_bap_ep *end_point_find(struct audio_connection *conn, uint8_t ase_id) -{ - for (size_t i = 0; i < ARRAY_SIZE(conn->end_points); i++) { - struct bt_bap_ep *ep = conn->end_points[i]; - - if (ep->status.id == ase_id) { - return ep; - } - } - - return NULL; -} - -static void btp_send_ascs_operation_completed_ev(struct bt_conn *conn, uint8_t ase_id, - uint8_t opcode, uint8_t status) -{ - struct btp_ascs_operation_completed_ev ev; - - bt_addr_le_copy(&ev.address, bt_conn_get_dst(conn)); - ev.ase_id = ase_id; - ev.opcode = opcode; - ev.status = status; - ev.flags = 0; - - tester_event(BTP_SERVICE_ID_ASCS, BTP_ASCS_EV_OPERATION_COMPLETED, &ev, sizeof(ev)); -} - -static void btp_send_ascs_ase_state_changed_ev(struct bt_conn *conn, uint8_t ase_id, uint8_t state) -{ - struct btp_ascs_ase_state_changed_ev ev; - - bt_addr_le_copy(&ev.address, bt_conn_get_dst(conn)); - ev.ase_id = ase_id; - ev.state = state; - - tester_event(BTP_SERVICE_ID_ASCS, BTP_ASCS_EV_ASE_STATE_CHANGED, &ev, sizeof(ev)); -} - -static int validate_codec_parameters(const struct bt_audio_codec_cfg *codec_cfg) -{ - int frames_per_sdu; - int octets_per_frame; - int chan_allocation_err; - enum bt_audio_location chan_allocation; - int ret; - - chan_allocation_err = - bt_audio_codec_cfg_get_chan_allocation(codec_cfg, &chan_allocation); - octets_per_frame = bt_audio_codec_cfg_get_octets_per_frame(codec_cfg); - frames_per_sdu = bt_audio_codec_cfg_get_frame_blocks_per_sdu(codec_cfg, true); - - ret = bt_audio_codec_cfg_get_freq(codec_cfg); - if (ret < 0) { - LOG_DBG("Error: Invalid codec frequency: %d", ret); - return -EINVAL; - } - - ret = bt_audio_codec_cfg_get_frame_dur(codec_cfg); - if (ret < 0) { - LOG_DBG("Error: Invalid frame duration: %d", ret); - return -EINVAL; - } - - if (octets_per_frame < 0) { - LOG_DBG("Error: Invalid octets per frame."); - return -EINVAL; - } - - if (frames_per_sdu < 0) { - /* The absence of the Codec_Frame_Blocks_Per_SDU LTV structure shall be - * interpreted as equivalent to a Codec_Frame_Blocks_Per_SDU value of 0x01 - */ - LOG_DBG("Codec_Frame_Blocks_Per_SDU LTV structure not defined."); - } - - if (chan_allocation_err < 0) { - /* The absence of the Audio_Channel_Allocation LTV structure shall be - * interpreted as a single channel with no specified Audio Location. - */ - LOG_DBG("Audio_Channel_Allocation LTV structure not defined."); - } - - return 0; -} - -static int lc3_config(struct bt_conn *conn, const struct bt_bap_ep *ep, enum bt_audio_dir dir, - const struct bt_audio_codec_cfg *codec_cfg, struct bt_bap_stream **stream, - struct bt_audio_codec_qos_pref *const pref, struct bt_bap_ascs_rsp *rsp) -{ - struct audio_connection *audio_conn; - struct audio_stream *stream_wrap; - - LOG_DBG("ASE Codec Config: ep %p dir %u", ep, dir); - - print_codec_cfg(codec_cfg); - - if (validate_codec_parameters(codec_cfg)) { - *rsp = BT_BAP_ASCS_RSP(BT_BAP_ASCS_RSP_CODE_CONF_REJECTED, - BT_BAP_ASCS_REASON_CODEC_DATA); - - btp_send_ascs_operation_completed_ev(conn, ep->status.id, BT_ASCS_CONFIG_OP, - BTP_ASCS_STATUS_FAILED); - - return -ENOTSUP; - } - - audio_conn = &connections[bt_conn_index(conn)]; - stream_wrap = stream_alloc(audio_conn); - - if (stream_wrap == NULL) { - LOG_DBG("No free stream available"); - *rsp = BT_BAP_ASCS_RSP(BT_BAP_ASCS_RSP_CODE_NO_MEM, BT_BAP_ASCS_REASON_NONE); - - btp_send_ascs_operation_completed_ev(conn, ep->status.id, BT_ASCS_CONFIG_OP, - BTP_ASCS_STATUS_FAILED); - - return -ENOMEM; - } - - *stream = &stream_wrap->stream; - LOG_DBG("ASE Codec Config stream %p", *stream); - - if (dir == BT_AUDIO_DIR_SOURCE) { - audio_conn->configured_source_stream_count++; - } else { - audio_conn->configured_sink_stream_count++; - } - - *pref = qos_pref; - - return 0; -} - -static int lc3_reconfig(struct bt_bap_stream *stream, enum bt_audio_dir dir, - const struct bt_audio_codec_cfg *codec_cfg, - struct bt_audio_codec_qos_pref *const pref, struct bt_bap_ascs_rsp *rsp) -{ - LOG_DBG("ASE Codec Reconfig: stream %p", stream); - - print_codec_cfg(codec_cfg); - - return 0; -} - -static int lc3_qos(struct bt_bap_stream *stream, const struct bt_audio_codec_qos *qos, - struct bt_bap_ascs_rsp *rsp) -{ - LOG_DBG("QoS: stream %p qos %p", stream, qos); - - print_qos(qos); - - return 0; -} - -static bool valid_metadata_type(uint8_t type, uint8_t len, const uint8_t *data) -{ - /* PTS checks if we are able to reject unsupported metadata type or RFU vale. - * The only RFU value PTS seems to check for now is the streaming context. - */ - if (!BT_AUDIO_METADATA_TYPE_IS_KNOWN(type)) { - return false; - } - - if (type == BT_AUDIO_METADATA_TYPE_PREF_CONTEXT || - type == BT_AUDIO_METADATA_TYPE_STREAM_CONTEXT) { - /* PTS wants us to reject the parameter if reserved bits are set */ - if ((sys_get_le16(data) & ~(uint16_t)(BT_AUDIO_CONTEXT_TYPE_ANY)) > 0) { - return false; - } - } - - return true; -} - -static bool data_func_cb(struct bt_data *data, void *user_data) -{ - struct bt_bap_ascs_rsp *rsp = (struct bt_bap_ascs_rsp *)user_data; - - if (!valid_metadata_type(data->type, data->data_len, data->data)) { - LOG_DBG("Invalid metadata type %u or length %u", data->type, data->data_len); - *rsp = BT_BAP_ASCS_RSP(BT_BAP_ASCS_RSP_CODE_METADATA_REJECTED, data->type); - return false; - } - - return true; -} - -static int lc3_enable(struct bt_bap_stream *stream, const uint8_t meta[], size_t meta_len, - struct bt_bap_ascs_rsp *rsp) -{ - int err; - - LOG_DBG("Metadata: stream %p meta_len %zu", stream, meta_len); - - err = bt_audio_data_parse(meta, meta_len, data_func_cb, rsp); - if (err != 0) { - btp_send_ascs_operation_completed_ev(stream->conn, stream->ep->status.id, - BT_ASCS_ENABLE_OP, BTP_ASCS_STATUS_FAILED); - } - - return err; -} - -static int lc3_start(struct bt_bap_stream *stream, struct bt_bap_ascs_rsp *rsp) -{ - LOG_DBG("Start: stream %p", stream); - - return 0; -} - -static int lc3_metadata(struct bt_bap_stream *stream, const uint8_t meta[], size_t meta_len, - struct bt_bap_ascs_rsp *rsp) -{ - int err; - - LOG_DBG("Metadata: stream %p meta_count %zu", stream, meta_len); - - err = bt_audio_data_parse(meta, meta_len, data_func_cb, rsp); - if (err != 0) { - btp_send_ascs_operation_completed_ev(stream->conn, stream->ep->status.id, - BT_ASCS_METADATA_OP, BTP_ASCS_STATUS_FAILED); - } - - return err; -} - -static int lc3_disable(struct bt_bap_stream *stream, struct bt_bap_ascs_rsp *rsp) -{ - LOG_DBG("Disable: stream %p", stream); - - return 0; -} - -static int lc3_stop(struct bt_bap_stream *stream, struct bt_bap_ascs_rsp *rsp) -{ - LOG_DBG("Stop: stream %p", stream); - - return 0; -} - -static int lc3_release(struct bt_bap_stream *stream, struct bt_bap_ascs_rsp *rsp) -{ - LOG_DBG("Release: stream %p", stream); - - return 0; -} - -static const struct bt_bap_unicast_server_cb unicast_server_cb = { - .config = lc3_config, - .reconfig = lc3_reconfig, - .qos = lc3_qos, - .enable = lc3_enable, - .start = lc3_start, - .metadata = lc3_metadata, - .disable = lc3_disable, - .stop = lc3_stop, - .release = lc3_release, -}; - -static void btp_send_stream_received_ev(struct bt_conn *conn, struct bt_bap_ep *ep, - uint8_t data_len, uint8_t *data) -{ - struct btp_bap_stream_received_ev *ev; - - LOG_DBG("Stream received, ep %d, dir %d, len %d", ep->status.id, ep->dir, - data_len); - - net_buf_simple_init(rx_ev_buf, 0); - - ev = net_buf_simple_add(rx_ev_buf, sizeof(*ev)); - - bt_addr_le_copy(&ev->address, bt_conn_get_dst(conn)); - - ev->ase_id = ep->status.id; - ev->data_len = data_len; - memcpy(ev->data, data, data_len); - - tester_event(BTP_SERVICE_ID_BAP, BTP_BAP_EV_STREAM_RECEIVED, ev, sizeof(*ev) + data_len); -} - -static void btp_send_bis_syced_ev(const bt_addr_le_t *address, uint32_t broadcast_id, - uint8_t bis_id) -{ - struct btp_bap_bis_syned_ev ev; - - bt_addr_le_copy(&ev.address, address); - sys_put_le24(broadcast_id, ev.broadcast_id); - ev.bis_id = bis_id; - - tester_event(BTP_SERVICE_ID_BAP, BTP_BAP_EV_BIS_SYNCED, &ev, sizeof(ev)); -} - -static void btp_send_bis_stream_received_ev(const bt_addr_le_t *address, uint32_t broadcast_id, - uint8_t bis_id, uint8_t data_len, uint8_t *data) -{ - struct btp_bap_bis_stream_received_ev *ev; - - LOG_DBG("Stream received, len %d", data_len); - - net_buf_simple_init(rx_ev_buf, 0); - - ev = net_buf_simple_add(rx_ev_buf, sizeof(*ev)); - - bt_addr_le_copy(&ev->address, address); - sys_put_le24(broadcast_id, ev->broadcast_id); - ev->bis_id = bis_id; - ev->data_len = data_len; - memcpy(ev->data, data, data_len); - - tester_event(BTP_SERVICE_ID_BAP, BTP_BAP_EV_BIS_STREAM_RECEIVED, ev, - sizeof(*ev) + data_len); -} - -static void stream_configured(struct bt_bap_stream *stream, - const struct bt_audio_codec_qos_pref *pref) -{ - struct audio_connection *audio_conn; - struct audio_stream *a_stream = CONTAINER_OF(stream, struct audio_stream, stream); - - LOG_DBG("Configured stream %p, ep %u, dir %u", stream, stream->ep->status.id, - stream->ep->dir); - a_stream->conn_id = bt_conn_index(stream->conn); - audio_conn = &connections[a_stream->conn_id]; - a_stream->ase_id = stream->ep->status.id; - - btp_send_ascs_operation_completed_ev(stream->conn, a_stream->ase_id, - BT_ASCS_CONFIG_OP, BTP_ASCS_STATUS_SUCCESS); -} - -static void stream_qos_set(struct bt_bap_stream *stream) -{ - struct audio_stream *a_stream = CONTAINER_OF(stream, struct audio_stream, stream); - - LOG_DBG("QoS set stream %p", stream); - btp_send_ascs_operation_completed_ev(stream->conn, a_stream->ase_id, - BT_ASCS_QOS_OP, BTP_ASCS_STATUS_SUCCESS); -} - -static void stream_enabled(struct bt_bap_stream *stream) -{ - struct audio_stream *a_stream = CONTAINER_OF(stream, struct audio_stream, stream); - struct bt_bap_ep_info info; - struct bt_conn_info conn_info; - int err; - - LOG_DBG("Enabled stream %p", stream); - - (void)bt_bap_ep_get_info(stream->ep, &info); - (void)bt_conn_get_info(stream->conn, &conn_info); - if (conn_info.role == BT_HCI_ROLE_PERIPHERAL && info.dir == BT_AUDIO_DIR_SINK) { - /* Automatically do the receiver start ready operation */ - err = bt_bap_stream_start(&a_stream->stream); - if (err != 0) { - LOG_DBG("Failed to start stream %p", stream); - btp_send_ascs_operation_completed_ev(stream->conn, a_stream->ase_id, - BT_ASCS_ENABLE_OP, - BTP_ASCS_STATUS_FAILED); - - return; - } - } - - btp_send_ascs_operation_completed_ev(stream->conn, a_stream->ase_id, - BT_ASCS_ENABLE_OP, BTP_ASCS_STATUS_SUCCESS); -} - -static void stream_metadata_updated(struct bt_bap_stream *stream) -{ - struct audio_stream *a_stream = CONTAINER_OF(stream, struct audio_stream, stream); - - LOG_DBG("Metadata updated stream %p", stream); - btp_send_ascs_operation_completed_ev(stream->conn, a_stream->ase_id, - BT_ASCS_METADATA_OP, BTP_ASCS_STATUS_SUCCESS); -} - -static void stream_disabled(struct bt_bap_stream *stream) -{ - struct audio_stream *a_stream = CONTAINER_OF(stream, struct audio_stream, stream); - - LOG_DBG("Disabled stream %p", stream); - - /* Stop send timer */ - k_work_cancel_delayable(&a_stream->audio_clock_work); - k_work_cancel_delayable(&a_stream->audio_send_work); - - btp_send_ascs_operation_completed_ev(stream->conn, a_stream->ase_id, - BT_ASCS_DISABLE_OP, BTP_ASCS_STATUS_SUCCESS); -} - -static void stream_released(struct bt_bap_stream *stream) -{ - struct audio_connection *audio_conn; - struct audio_stream *a_stream = CONTAINER_OF(stream, struct audio_stream, stream); - - LOG_DBG("Released stream %p", stream); - - audio_conn = &connections[a_stream->conn_id]; - - /* Stop send timer */ - k_work_cancel_delayable(&a_stream->audio_clock_work); - k_work_cancel_delayable(&a_stream->audio_send_work); - - if (cigs[stream->ep->cig_id] != NULL) { - /* The unicast group will be deleted only at release of the last stream */ - LOG_DBG("Deleting unicast group"); - - int err = bt_bap_unicast_group_delete(cigs[stream->ep->cig_id]); - - if (err != 0) { - LOG_DBG("Unable to delete unicast group: %d", err); - - return; - } - - cigs[stream->ep->cig_id] = NULL; - } - - if (stream->ep->dir == BT_AUDIO_DIR_SINK) { - audio_conn->configured_sink_stream_count--; - } else { - audio_conn->configured_source_stream_count--; - } - - stream_free(a_stream); -} - -static void stream_started(struct bt_bap_stream *stream) -{ - struct audio_stream *a_stream = CONTAINER_OF(stream, struct audio_stream, stream); - struct bt_bap_ep_info info; - - /* Callback called on transition to Streaming state */ - - LOG_DBG("Started stream %p", stream); - - (void)bt_bap_ep_get_info(stream->ep, &info); - if (info.can_send == true) { - /* Schedule first TX ISO data at seq_num 1 instead of 0 to ensure - * we are in sync with the controller at start of streaming. - */ - a_stream->seq_num = 1; - - /* Run audio clock work in system work queue */ - k_work_init_delayable(&a_stream->audio_clock_work, audio_clock_timeout); - k_work_schedule(&a_stream->audio_clock_work, K_NO_WAIT); - - /* Run audio send work in user defined work queue */ - k_work_init_delayable(&a_stream->audio_send_work, audio_send_timeout); - k_work_schedule_for_queue(&iso_data_work_q, &a_stream->audio_send_work, - K_USEC(a_stream->stream.qos->interval)); - } - - if (a_stream->broadcast) { - a_stream->bis_synced = true; - btp_send_bis_syced_ev(&broadcaster_addr, broadcaster_broadcast_id, - a_stream->bis_id); - } else { - btp_send_ascs_ase_state_changed_ev(stream->conn, a_stream->ase_id, - stream->ep->status.state); - } -} - -static void stream_stopped(struct bt_bap_stream *stream, uint8_t reason) -{ - struct audio_stream *a_stream = CONTAINER_OF(stream, struct audio_stream, stream); - - LOG_DBG("Stopped stream %p with reason 0x%02X", stream, reason); - - /* Stop send timer */ - k_work_cancel_delayable(&a_stream->audio_clock_work); - k_work_cancel_delayable(&a_stream->audio_send_work); - - if (!a_stream->broadcast) { - btp_send_ascs_operation_completed_ev(stream->conn, a_stream->ase_id, - BT_ASCS_STOP_OP, BTP_STATUS_SUCCESS); - } else { - a_stream->bis_synced = false; - } -} - -static void stream_recv(struct bt_bap_stream *stream, - const struct bt_iso_recv_info *info, - struct net_buf *buf) -{ - struct audio_stream *a_stream = CONTAINER_OF(stream, struct audio_stream, stream); - - if (a_stream->already_sent == false) { - /* For now, send just a first packet, to limit the number - * of logs and not unnecessarily spam through btp. - */ - LOG_DBG("Incoming audio on stream %p len %u", stream, buf->len); - a_stream->already_sent = true; - - if (a_stream->broadcast) { - btp_send_bis_stream_received_ev(&broadcaster_addr, broadcaster_broadcast_id, - a_stream->bis_id, buf->len, buf->data); - } else { - btp_send_stream_received_ev(stream->conn, stream->ep, buf->len, buf->data); - } - } -} - -static void stream_sent(struct bt_bap_stream *stream) -{ - LOG_DBG("Stream %p sent", stream); -} - -static struct bt_bap_stream_ops stream_ops = { - .configured = stream_configured, - .qos_set = stream_qos_set, - .enabled = stream_enabled, - .metadata_updated = stream_metadata_updated, - .disabled = stream_disabled, - .released = stream_released, - .started = stream_started, - .stopped = stream_stopped, - .recv = stream_recv, - .sent = stream_sent, -}; - -static void btp_send_discovery_completed_ev(struct bt_conn *conn, uint8_t status) -{ - struct btp_bap_discovery_completed_ev ev; - - bt_addr_le_copy(&ev.address, bt_conn_get_dst(conn)); - ev.status = status; - - tester_event(BTP_SERVICE_ID_BAP, BTP_BAP_EV_DISCOVERY_COMPLETED, &ev, sizeof(ev)); -} - -struct search_type_param { - uint8_t type; - const uint8_t *data; -}; - -static bool data_type_search_cb(struct bt_data *data, void *user_data) -{ - struct search_type_param *param = (struct search_type_param *)user_data; - - if (param->type == data->type) { - param->data = data->data; - - return false; - } - - return true; -} - -static bool codec_cap_get_val(const struct bt_audio_codec_cap *codec_cap, uint8_t type, - const uint8_t **data) -{ - struct search_type_param param = { - .type = type, - .data = NULL, - }; - int err; - - err = bt_audio_data_parse(codec_cap->data, codec_cap->data_len, data_type_search_cb, - ¶m); - if (err != 0 && err != -ECANCELED) { - LOG_DBG("Could not parse the data: %d", err); - - return false; - } - - if (param.data == NULL) { - LOG_DBG("Could not find the type %u", type); - - return false; - } - - *data = param.data; - - return true; -} - -static void btp_send_pac_codec_found_ev(struct bt_conn *conn, - const struct bt_audio_codec_cap *codec_cap, - enum bt_audio_dir dir) -{ - struct btp_bap_codec_cap_found_ev ev; - const uint8_t *data; - - bt_addr_le_copy(&ev.address, bt_conn_get_dst(conn)); - - ev.dir = dir; - ev.coding_format = codec_cap->id; - - if (codec_cap_get_val(codec_cap, BT_AUDIO_CODEC_LC3_FREQ, &data)) { - memcpy(&ev.frequencies, data, sizeof(ev.frequencies)); - } - - if (codec_cap_get_val(codec_cap, BT_AUDIO_CODEC_LC3_DURATION, &data)) { - memcpy(&ev.frame_durations, data, sizeof(ev.frame_durations)); - } - - if (codec_cap_get_val(codec_cap, BT_AUDIO_CODEC_LC3_FRAME_LEN, &data)) { - memcpy(&ev.octets_per_frame, data, sizeof(ev.octets_per_frame)); - } - - if (codec_cap_get_val(codec_cap, BT_AUDIO_CODEC_LC3_CHAN_COUNT, &data)) { - memcpy(&ev.channel_counts, data, sizeof(ev.channel_counts)); - } - - tester_event(BTP_SERVICE_ID_BAP, BTP_BAP_EV_CODEC_CAP_FOUND, &ev, sizeof(ev)); -} - -static void btp_send_ase_found_ev(struct bt_conn *conn, struct bt_bap_ep *ep) -{ - struct btp_ascs_ase_found_ev ev; - - bt_addr_le_copy(&ev.address, bt_conn_get_dst(conn)); - - ev.ase_id = ep->status.id; - ev.dir = ep->dir; - - tester_event(BTP_SERVICE_ID_BAP, BTP_BAP_EV_ASE_FOUND, &ev, sizeof(ev)); -} - -static void unicast_client_location_cb(struct bt_conn *conn, - enum bt_audio_dir dir, - enum bt_audio_location loc) -{ - LOG_DBG("dir %u loc %X", dir, loc); -} - -static void available_contexts_cb(struct bt_conn *conn, - enum bt_audio_context snk_ctx, - enum bt_audio_context src_ctx) -{ - LOG_DBG("snk ctx %u src ctx %u", snk_ctx, src_ctx); -} - - -static void config_cb(struct bt_bap_stream *stream, enum bt_bap_ascs_rsp_code rsp_code, - enum bt_bap_ascs_reason reason) -{ - LOG_DBG("stream %p config operation rsp_code %u reason %u", stream, rsp_code, reason); -} - -static void qos_cb(struct bt_bap_stream *stream, enum bt_bap_ascs_rsp_code rsp_code, - enum bt_bap_ascs_reason reason) -{ - LOG_DBG("stream %p qos operation rsp_code %u reason %u", stream, rsp_code, reason); -} - -static void enable_cb(struct bt_bap_stream *stream, enum bt_bap_ascs_rsp_code rsp_code, - enum bt_bap_ascs_reason reason) -{ - LOG_DBG("stream %p enable operation rsp_code %u reason %u", stream, rsp_code, reason); -} - -static void start_cb(struct bt_bap_stream *stream, enum bt_bap_ascs_rsp_code rsp_code, - enum bt_bap_ascs_reason reason) -{ - struct audio_stream *a_stream = CONTAINER_OF(stream, struct audio_stream, stream); - - /* Callback called on Receiver Start Ready notification from ASE Control Point */ - - LOG_DBG("stream %p start operation rsp_code %u reason %u", stream, rsp_code, reason); - a_stream->already_sent = false; - - btp_send_ascs_operation_completed_ev(stream->conn, a_stream->ase_id, - BT_ASCS_START_OP, BTP_STATUS_SUCCESS); -} - -static void stop_cb(struct bt_bap_stream *stream, enum bt_bap_ascs_rsp_code rsp_code, - enum bt_bap_ascs_reason reason) -{ - LOG_DBG("stream %p stop operation rsp_code %u reason %u", stream, rsp_code, reason); -} - -static void disable_cb(struct bt_bap_stream *stream, enum bt_bap_ascs_rsp_code rsp_code, - enum bt_bap_ascs_reason reason) -{ - LOG_DBG("stream %p disable operation rsp_code %u reason %u", stream, rsp_code, reason); -} - -static void metadata_cb(struct bt_bap_stream *stream, enum bt_bap_ascs_rsp_code rsp_code, - enum bt_bap_ascs_reason reason) -{ - LOG_DBG("stream %p metadata operation rsp_code %u reason %u", stream, rsp_code, reason); -} - -static void release_cb(struct bt_bap_stream *stream, enum bt_bap_ascs_rsp_code rsp_code, - enum bt_bap_ascs_reason reason) -{ - LOG_DBG("stream %p release operation rsp_code %u reason %u", stream, rsp_code, reason); -} - -static void pac_record_cb(struct bt_conn *conn, enum bt_audio_dir dir, - const struct bt_audio_codec_cap *codec_cap) -{ - LOG_DBG(""); - - if (codec_cap != NULL) { - LOG_DBG("Discovered codec capabilities %p", codec_cap); - print_codec_cap(codec_cap); - btp_send_pac_codec_found_ev(conn, codec_cap, dir); - } -} - -static void endpoint_cb(struct bt_conn *conn, enum bt_audio_dir dir, struct bt_bap_ep *ep) -{ - struct audio_connection *audio_conn; - - LOG_DBG(""); - - if (ep != NULL) { - LOG_DBG("Discovered ASE %p, id %u, dir 0x%02x", ep, ep->status.id, ep->dir); - - audio_conn = &connections[bt_conn_index(conn)]; - - if (audio_conn->end_points_count >= CONFIG_BT_BAP_UNICAST_CLIENT_ASE_SNK_COUNT + - CONFIG_BT_BAP_UNICAST_CLIENT_ASE_SRC_COUNT) { - LOG_DBG("Failed to cache ep %p due to configured limit: %zu", ep, - audio_conn->end_points_count); - - btp_send_discovery_completed_ev(conn, BTP_BAP_DISCOVERY_STATUS_FAILED); - - return; - } - - audio_conn->end_points[audio_conn->end_points_count++] = ep; - btp_send_ase_found_ev(conn, ep); - - return; - } -} - -static void discover_cb(struct bt_conn *conn, int err, enum bt_audio_dir dir) -{ - LOG_DBG(""); - - if (err != 0 && err != BT_ATT_ERR_ATTRIBUTE_NOT_FOUND) { - LOG_DBG("Discover remote ASEs failed: %d", err); - btp_send_discovery_completed_ev(conn, BTP_BAP_DISCOVERY_STATUS_FAILED); - return; - } - - LOG_DBG("Discover complete"); - - if (err == BT_ATT_ERR_ATTRIBUTE_NOT_FOUND) { - LOG_DBG("Discover remote ASEs completed without finding any source ASEs"); - } else { - LOG_DBG("Discover remote ASEs complete: err %d", err); - } - - if (dir == BT_AUDIO_DIR_SINK) { - err = bt_bap_unicast_client_discover(conn, BT_AUDIO_DIR_SOURCE); - - if (err != 0) { - LOG_DBG("Failed to discover source ASEs: %d", err); - btp_send_discovery_completed_ev(conn, BTP_BAP_DISCOVERY_STATUS_FAILED); - } - - return; - } - - btp_send_discovery_completed_ev(conn, BTP_BAP_DISCOVERY_STATUS_SUCCESS); -} - -static struct bt_bap_unicast_client_cb unicast_client_cbs = { - .location = unicast_client_location_cb, - .available_contexts = available_contexts_cb, - .config = config_cb, - .qos = qos_cb, - .enable = enable_cb, - .start = start_cb, - .stop = stop_cb, - .disable = disable_cb, - .metadata = metadata_cb, - .release = release_cb, - .pac_record = pac_record_cb, - .endpoint = endpoint_cb, - .discover = discover_cb, -}; - -static uint8_t bap_discover(const void *cmd, uint16_t cmd_len, - void *rsp, uint16_t *rsp_len) -{ - const struct btp_bap_discover_cmd *cp = cmd; - struct bt_conn *conn; - struct audio_connection *audio_conn; - struct bt_conn_info conn_info; - int err; - - conn = bt_conn_lookup_addr_le(BT_ID_DEFAULT, &cp->address); - if (!conn) { - LOG_ERR("Unknown connection"); - return BTP_STATUS_FAILED; - } - - audio_conn = &connections[bt_conn_index(conn)]; - (void)bt_conn_get_info(conn, &conn_info); - - if (audio_conn->end_points_count > 0 || conn_info.role != BT_HCI_ROLE_CENTRAL) { - bt_conn_unref(conn); - - return BTP_STATUS_FAILED; - } - - err = bt_bap_unicast_client_discover(conn, BT_AUDIO_DIR_SINK); - if (err != 0) { - LOG_DBG("Failed to discover remote ASEs: %d", err); - bt_conn_unref(conn); - - return BTP_STATUS_FAILED; - } - - bt_conn_unref(conn); - - return BTP_STATUS_SUCCESS; -} - -static void audio_clock_timeout(struct k_work *work) -{ - struct audio_stream *stream; - struct k_work_delayable *dwork; - - dwork = k_work_delayable_from_work(work); - stream = CONTAINER_OF(dwork, struct audio_stream, audio_clock_work); - atomic_inc(&stream->seq_num); - - k_work_schedule(dwork, K_USEC(stream->stream.qos->interval)); -} - -static void audio_send_timeout(struct k_work *work) -{ - struct bt_iso_tx_info info; - struct audio_stream *stream; - struct k_work_delayable *dwork; - struct net_buf *buf; - uint32_t size; - uint8_t *data; - int err; - - dwork = k_work_delayable_from_work(work); - stream = CONTAINER_OF(dwork, struct audio_stream, audio_send_work); - - if (stream->last_req_seq_num % 201 == 200) { - err = bt_bap_stream_get_tx_sync(&stream->stream, &info); - if (err != 0) { - LOG_DBG("Failed to get last seq num: err %d", err); - } else if (stream->last_req_seq_num > info.seq_num) { - LOG_DBG("Previous TX request rejected by the controller: requested seq %u," - " last accepted seq %u", stream->last_req_seq_num, info.seq_num); - stream->last_sent_seq_num = info.seq_num; - } else { - LOG_DBG("Host and Controller sequence number is in sync."); - stream->last_sent_seq_num = info.seq_num; - } - /* TODO: Synchronize the Host clock with the Controller clock */ - } - - /* Get buffer within a ring buffer memory */ - size = ring_buf_get_claim(&audio_ring_buf, &data, stream->stream.qos->sdu); - if (size > 0) { - buf = net_buf_alloc(&tx_pool, K_NO_WAIT); - if (!buf) { - LOG_ERR("Cannot allocate net_buf. Dropping data."); - } else { - net_buf_reserve(buf, BT_ISO_CHAN_SEND_RESERVE); - net_buf_add_mem(buf, data, size); - - /* Because the seq_num field of the audio_stream struct is atomic_val_t - * (4 bytes), let's allow an overflow and just cast it to uint16_t. - */ - stream->last_req_seq_num = (uint16_t)atomic_get(&stream->seq_num); - - LOG_DBG("Sending data to stream %p len %d seq %d", &stream->stream, size, - stream->last_req_seq_num); - - err = bt_bap_stream_send(&stream->stream, buf, 0, BT_ISO_TIMESTAMP_NONE); - if (err != 0) { - LOG_ERR("Failed to send audio data to stream %p, err %d", - &stream->stream, err); - net_buf_unref(buf); - } - } - - /* Free ring buffer memory */ - err = ring_buf_get_finish(&audio_ring_buf, size); - if (err != 0) { - LOG_ERR("Error freeing ring buffer memory: %d", err); - } - } - - k_work_schedule_for_queue(&iso_data_work_q, dwork, - K_USEC(stream->stream.qos->interval)); -} - -static uint8_t bap_send(const void *cmd, uint16_t cmd_len, - void *rsp, uint16_t *rsp_len) -{ - struct btp_bap_send_rp *rp = rsp; - const struct btp_bap_send_cmd *cp = cmd; - struct audio_connection *audio_conn; - struct audio_stream *stream; - struct bt_conn *conn; - struct bt_bap_ep_info info; - uint32_t ret; - - conn = bt_conn_lookup_addr_le(BT_ID_DEFAULT, &cp->address); - if (!conn) { - LOG_ERR("Unknown connection"); - return BTP_STATUS_FAILED; - } - - audio_conn = &connections[bt_conn_index(conn)]; - - stream = stream_find(audio_conn, cp->ase_id); - if (stream == NULL) { - return BTP_STATUS_FAILED; - } - - (void)bt_bap_ep_get_info(stream->stream.ep, &info); - if (info.can_send == false) { - return BTP_STATUS_FAILED; - } - - ret = ring_buf_put(&audio_ring_buf, cp->data, cp->data_len); - - rp->data_len = ret; - *rsp_len = sizeof(*rp) + 1; - - return BTP_STATUS_SUCCESS; -} - -static int setup_broadcast_source(uint8_t streams_per_subgroup, uint8_t subgroups, - struct bt_bap_broadcast_source **source) -{ - int err; - struct bt_bap_broadcast_source_stream_param - stream_params[CONFIG_BT_BAP_BROADCAST_SRC_STREAM_COUNT]; - struct bt_bap_broadcast_source_subgroup_param - subgroup_param[CONFIG_BT_BAP_BROADCAST_SRC_SUBGROUP_COUNT]; - struct bt_bap_broadcast_source_param create_param; - - if (streams_per_subgroup * subgroups > CONFIG_BT_BAP_BROADCAST_SRC_STREAM_COUNT || - subgroups > CONFIG_BT_BAP_BROADCAST_SRC_SUBGROUP_COUNT) { - return -EINVAL; - } - - for (size_t i = 0U; i < subgroups; i++) { - subgroup_param[i].params_count = streams_per_subgroup; - subgroup_param[i].params = stream_params + i * streams_per_subgroup; - subgroup_param[i].codec_cfg = &broadcaster->codec_cfg; - } - - for (size_t j = 0U; j < streams_per_subgroup; j++) { - broadcaster->streams[j].broadcast = true; - stream_params[j].stream = &broadcaster->streams[j].stream; - stream_params[j].data = NULL; - stream_params[j].data_len = 0U; - bt_bap_stream_cb_register(stream_params[j].stream, &stream_ops); - } - - create_param.params_count = subgroups; - create_param.params = subgroup_param; - create_param.qos = &broadcaster->qos; - create_param.encryption = false; - create_param.packing = BT_ISO_PACKING_SEQUENTIAL; - - LOG_DBG("Creating broadcast source with %zu subgroups with %zu streams", - subgroups, subgroups * streams_per_subgroup); - - if (*source == NULL) { - err = bt_bap_broadcast_source_create(&create_param, source); - if (err != 0) { - LOG_DBG("Unable to create broadcast source: %d", err); - - return err; - } - } else { - err = bt_bap_broadcast_source_reconfig(*source, &create_param); - if (err != 0) { - LOG_DBG("Unable to reconfig broadcast source: %d", err); - - return err; - } - } - - return 0; -} - -static uint8_t broadcast_source_setup(const void *cmd, uint16_t cmd_len, - void *rsp, uint16_t *rsp_len) -{ - int err; - const struct btp_bap_broadcast_source_setup_cmd *cp = cmd; - struct btp_bap_broadcast_source_setup_rp *rp = rsp; - struct bt_le_adv_param *param = BT_LE_EXT_ADV_NCONN_NAME; - uint32_t broadcast_id; - uint32_t gap_settings = BIT(BTP_GAP_SETTINGS_DISCOVERABLE) | - BIT(BTP_GAP_SETTINGS_EXTENDED_ADVERTISING); - - NET_BUF_SIMPLE_DEFINE(ad_buf, BT_UUID_SIZE_16 + BT_AUDIO_BROADCAST_ID_SIZE); - NET_BUF_SIMPLE_DEFINE(base_buf, 128); - - /* Broadcast Audio Streaming Endpoint advertising data */ - struct bt_data base_ad; - struct bt_data per_ad; - - LOG_DBG(""); - - broadcaster->codec_cfg.id = cp->coding_format; - broadcaster->codec_cfg.vid = cp->vid; - broadcaster->codec_cfg.cid = cp->cid; - broadcaster->codec_cfg.data_len = cp->cc_ltvs_len; - memcpy(broadcaster->codec_cfg.data, cp->cc_ltvs, cp->cc_ltvs_len); - - broadcaster->qos.phy = BT_AUDIO_CODEC_QOS_2M; - broadcaster->qos.framing = cp->framing; - broadcaster->qos.rtn = cp->retransmission_num; - broadcaster->qos.latency = sys_le16_to_cpu(cp->max_transport_latency); - broadcaster->qos.interval = sys_get_le24(cp->sdu_interval); - broadcaster->qos.pd = sys_get_le24(cp->presentation_delay); - broadcaster->qos.sdu = sys_le16_to_cpu(cp->max_sdu); - - err = setup_broadcast_source(cp->streams_per_subgroup, cp->subgroups, &broadcast_source); - if (err != 0) { - LOG_DBG("Unable to setup broadcast source: %d", err); - - return BTP_STATUS_FAILED; - } - - err = bt_bap_broadcast_source_get_id(broadcast_source, &broadcast_id); - if (err != 0) { - LOG_DBG("Unable to get broadcast ID: %d", err); - - return BTP_STATUS_FAILED; - } - - /* Setup extended advertising data */ - net_buf_simple_add_le16(&ad_buf, BT_UUID_BROADCAST_AUDIO_VAL); - net_buf_simple_add_le24(&ad_buf, broadcast_id); - base_ad.type = BT_DATA_SVC_DATA16; - base_ad.data_len = ad_buf.len; - base_ad.data = ad_buf.data; - err = tester_gap_create_adv_instance(param, BTP_GAP_ADDR_TYPE_IDENTITY, &base_ad, 1, NULL, - 0, &gap_settings); - if (err != 0) { - LOG_DBG("Failed to create extended advertising instance: %d", err); - - return BTP_STATUS_FAILED; - } - - err = tester_gap_padv_configure(BT_LE_PER_ADV_PARAM(BT_GAP_PER_ADV_FAST_INT_MIN_2, - BT_GAP_PER_ADV_FAST_INT_MAX_2, - BT_LE_PER_ADV_OPT_USE_TX_POWER)); - if (err != 0) { - LOG_DBG("Failed to configure periodic advertising: %d", err); - - return BTP_STATUS_FAILED; - } - - err = bt_bap_broadcast_source_get_base(broadcast_source, &base_buf); - if (err != 0) { - LOG_DBG("Failed to get encoded BASE: %d\n", err); - - return BTP_STATUS_FAILED; - } - - per_ad.type = BT_DATA_SVC_DATA16; - per_ad.data_len = base_buf.len; - per_ad.data = base_buf.data; - err = tester_gap_padv_set_data(&per_ad, 1); - if (err != 0) { - return BTP_STATUS_FAILED; - } - - rp->gap_settings = gap_settings; - sys_put_le24(broadcast_id, rp->broadcast_id); - *rsp_len = sizeof(*rp) + 1; - - return BTP_STATUS_SUCCESS; -} - -static uint8_t broadcast_source_release(const void *cmd, uint16_t cmd_len, - void *rsp, uint16_t *rsp_len) -{ - int err; - - LOG_DBG(""); - - err = bt_bap_broadcast_source_delete(broadcast_source); - if (err != 0) { - LOG_DBG("Unable to delete broadcast source: %d", err); - - return BTP_STATUS_FAILED; - } - - memset(broadcaster, 0, sizeof(*broadcaster)); - broadcast_source = NULL; - - return BTP_STATUS_SUCCESS; -} - -static uint8_t broadcast_adv_start(const void *cmd, uint16_t cmd_len, - void *rsp, uint16_t *rsp_len) -{ - int err; - struct bt_le_ext_adv *ext_adv = tester_gap_ext_adv_get(); - - LOG_DBG(""); - - if (ext_adv == NULL) { - return BTP_STATUS_FAILED; - } - - err = tester_gap_start_ext_adv(); - if (err != 0) { - return BTP_STATUS_FAILED; - } - - err = tester_gap_padv_start(); - if (err != 0) { - LOG_DBG("Unable to start periodic advertising: %d", err); - - return BTP_STATUS_FAILED; - } - - return BTP_STATUS_SUCCESS; -} - -static uint8_t broadcast_adv_stop(const void *cmd, uint16_t cmd_len, - void *rsp, uint16_t *rsp_len) -{ - int err; - - LOG_DBG(""); - - err = tester_gap_padv_stop(); - if (err != 0) { - return BTP_STATUS_FAILED; - } - - err = tester_gap_stop_ext_adv(); - if (err != 0) { - return BTP_STATUS_FAILED; - } - - return BTP_STATUS_SUCCESS; -} - -static uint8_t broadcast_source_start(const void *cmd, uint16_t cmd_len, - void *rsp, uint16_t *rsp_len) -{ - int err; - struct bt_le_ext_adv *ext_adv = tester_gap_ext_adv_get(); - - LOG_DBG(""); - - if (ext_adv == NULL) { - return BTP_STATUS_FAILED; - } - - err = bt_bap_broadcast_source_start(broadcast_source, ext_adv); - if (err != 0) { - LOG_DBG("Unable to start broadcast source: %d", err); - - return BTP_STATUS_FAILED; - } - - return BTP_STATUS_SUCCESS; -} - -static uint8_t broadcast_source_stop(const void *cmd, uint16_t cmd_len, - void *rsp, uint16_t *rsp_len) -{ - int err; - - LOG_DBG(""); - - err = bt_bap_broadcast_source_stop(broadcast_source); - if (err != 0) { - LOG_DBG("Unable to stop broadcast source: %d", err); - - return BTP_STATUS_FAILED; - } - - return BTP_STATUS_SUCCESS; -} - -static int broadcast_sink_reset(void) -{ - bis_index_bitfield = 0U; - sink_recv_state = NULL; - (void)memset(sink_broadcast_code, 0, sizeof(sink_broadcast_code)); - (void)memset(&broadcaster_addr, 0, sizeof(broadcaster_addr)); - (void)memset(broadcaster, 0, sizeof(*broadcaster)); - broadcaster_broadcast_id = INVALID_BROADCAST_ID; - - return 0; -} - -static void btp_send_baa_found_ev(const bt_addr_le_t *address, uint32_t broadcast_id, - uint8_t sid, uint16_t interval) -{ - struct btp_bap_baa_found_ev ev; - - bt_addr_le_copy(&ev.address, address); - sys_put_le24(broadcast_id, ev.broadcast_id); - ev.advertiser_sid = sid; - ev.padv_interval = sys_cpu_to_le16(interval); - - tester_event(BTP_SERVICE_ID_BAP, BTP_BAP_EV_BAA_FOUND, &ev, sizeof(ev)); -} - -static bool baa_check(struct bt_data *data, void *user_data) -{ - const struct bt_le_scan_recv_info *info = user_data; - char le_addr[BT_ADDR_LE_STR_LEN]; - struct bt_uuid_16 adv_uuid; - uint32_t broadcast_id; - - /* Parse the scanned Broadcast Audio Announcement */ - - if (data->type != BT_DATA_SVC_DATA16) { - return true; - } - - if (data->data_len < BT_UUID_SIZE_16 + BT_AUDIO_BROADCAST_ID_SIZE) { - return true; - } - - if (!bt_uuid_create(&adv_uuid.uuid, data->data, BT_UUID_SIZE_16)) { - return true; - } - - if (bt_uuid_cmp(&adv_uuid.uuid, BT_UUID_BROADCAST_AUDIO)) { - return true; - } - - broadcast_id = sys_get_le24(data->data + BT_UUID_SIZE_16); - - bt_addr_le_to_str(info->addr, le_addr, sizeof(le_addr)); - - LOG_DBG("Found BAA with ID 0x%06X, addr %s, sid 0x%02X, interval 0x%04X", - broadcast_id, le_addr, info->sid, info->interval); - - btp_send_baa_found_ev(info->addr, broadcast_id, info->sid, info->interval); - - /* Stop parsing */ - return false; -} - -static void broadcast_scan_recv(const struct bt_le_scan_recv_info *info, struct net_buf_simple *ad) -{ - /* If 0 there is no periodic advertising. */ - if (info->interval != 0U) { - bt_data_parse(ad, baa_check, (void *)info); - } -} - -static struct bt_le_scan_cb bap_scan_cb = { - .recv = broadcast_scan_recv, -}; - -static void btp_send_bis_found_ev(const bt_addr_le_t *address, uint32_t broadcast_id, uint32_t pd, - uint8_t subgroup_index, uint8_t bis_index, - const struct bt_audio_codec_cfg *codec_cfg) -{ - struct btp_bap_bis_found_ev *ev; - - tester_rsp_buffer_lock(); - tester_rsp_buffer_allocate(sizeof(*ev) + codec_cfg->data_len, (uint8_t **)&ev); - - bt_addr_le_copy(&ev->address, address); - sys_put_le24(broadcast_id, ev->broadcast_id); - sys_put_le24(pd, ev->presentation_delay); - ev->subgroup_id = subgroup_index; - ev->bis_id = bis_index; - ev->coding_format = codec_cfg->id; - ev->vid = sys_cpu_to_le16(codec_cfg->vid); - ev->cid = sys_cpu_to_le16(codec_cfg->cid); - - ev->cc_ltvs_len = codec_cfg->data_len; - memcpy(ev->cc_ltvs, codec_cfg->data, ev->cc_ltvs_len); - - tester_event(BTP_SERVICE_ID_BAP, BTP_BAP_EV_BIS_FOUND, ev, - sizeof(*ev) + ev->cc_ltvs_len); - - tester_rsp_buffer_free(); - tester_rsp_buffer_unlock(); -} - -struct base_parse_data { - uint32_t broadcast_id; - uint32_t pd; - struct bt_audio_codec_cfg codec_cfg; - uint8_t subgroup_cnt; - uint32_t bis_bitfield; - size_t stream_cnt; -}; - -static bool base_subgroup_bis_cb(const struct bt_bap_base_subgroup_bis *bis, void *user_data) -{ - struct base_parse_data *parse_data = user_data; - struct bt_audio_codec_cfg *codec_cfg = &parse_data->codec_cfg; - - parse_data->bis_bitfield |= BIT(bis->index); - - if (parse_data->stream_cnt < MAX_STREAMS_COUNT) { - broadcaster->streams[parse_data->stream_cnt++].bis_id = bis->index; - } - - btp_send_bis_found_ev(&broadcaster_addr, parse_data->broadcast_id, parse_data->pd, - parse_data->subgroup_cnt, bis->index, codec_cfg); - - return true; -} - -static bool base_subgroup_cb(const struct bt_bap_base_subgroup *subgroup, void *user_data) -{ - struct base_parse_data *parse_data = user_data; - int err; - - err = bt_bap_base_subgroup_codec_to_codec_cfg(subgroup, &parse_data->codec_cfg); - if (err != 0) { - LOG_DBG("Failed to retrieve codec config: %d", err); - return false; - } - - err = bt_bap_base_subgroup_foreach_bis(subgroup, base_subgroup_bis_cb, user_data); - if (err != 0) { - LOG_DBG("Failed to parse all BIS: %d", err); - return false; - } - - return true; -} - -static void base_recv_cb(struct bt_bap_broadcast_sink *sink, const struct bt_bap_base *base, - size_t base_size) -{ - struct base_parse_data parse_data = {0}; - int ret; - - LOG_DBG(""); - - if (broadcaster_broadcast_id != sink->broadcast_id) { - return; - } - - LOG_DBG("Received BASE: broadcast sink %p subgroups %u", - sink, bt_bap_base_get_subgroup_count(base)); - - ret = bt_bap_base_get_pres_delay(base); - if (ret < 0) { - LOG_ERR("Failed to get presentation delay: %d", ret); - return; - } - - parse_data.broadcast_id = sink->broadcast_id; - parse_data.pd = (uint32_t)ret; - - ret = bt_bap_base_foreach_subgroup(base, base_subgroup_cb, &parse_data); - if (ret != 0) { - LOG_ERR("Failed to parse subgroups: %d", ret); - return; - } - - bis_index_bitfield = parse_data.bis_bitfield & bis_index_mask; - LOG_DBG("bis_index_bitfield 0x%08x", bis_index_bitfield); -} - -static void syncable_cb(struct bt_bap_broadcast_sink *sink, bool encrypted) -{ - int err; - uint32_t index_bitfield; - - LOG_DBG("PA found, encrypted %d, requested_bis_sync %d", encrypted, requested_bis_sync); - - if (encrypted) { - /* Wait for Set Broadcast Code and start sync at broadcast_code_cb */ - return; - } - - if (!requested_bis_sync) { - /* No sync with any BIS was requested yet */ - return; - } - - index_bitfield = bis_index_bitfield & requested_bis_sync; - err = bt_bap_broadcast_sink_sync(broadcast_sink, index_bitfield, sink_streams, - sink_broadcast_code); - if (err != 0) { - LOG_DBG("Unable to sync to broadcast source: %d", err); - } -} - -static struct bt_bap_broadcast_sink_cb broadcast_sink_cbs = { - .base_recv = base_recv_cb, - .syncable = syncable_cb, -}; - -static void pa_timer_handler(struct k_work *work) -{ - if (broadcast_recv_state != NULL) { - enum bt_bap_pa_state pa_state; - - if (broadcast_recv_state->pa_sync_state == BT_BAP_PA_STATE_INFO_REQ) { - pa_state = BT_BAP_PA_STATE_NO_PAST; - } else { - pa_state = BT_BAP_PA_STATE_FAILED; - } - - bt_bap_scan_delegator_set_pa_state(broadcast_recv_state->src_id, - pa_state); - } - - LOG_DBG("PA timeout"); -} - -static K_WORK_DELAYABLE_DEFINE(pa_timer, pa_timer_handler); - -static void bap_pa_sync_synced_cb(struct bt_le_per_adv_sync *sync, - struct bt_le_per_adv_sync_synced_info *info) -{ - int err; - - LOG_DBG("Sync info: service_data 0x%04X", info->service_data); - - k_work_cancel_delayable(&pa_timer); - - err = bt_bap_broadcast_sink_create(sync, broadcaster_broadcast_id, &broadcast_sink); - if (err != 0) { - LOG_DBG("Failed to create broadcast sink: ID 0x%06X, err %d", - broadcaster_broadcast_id, err); - } -} - -static struct bt_le_per_adv_sync_cb bap_pa_sync_cb = { - .synced = bap_pa_sync_synced_cb, -}; - -static void btp_send_pas_sync_req_ev(struct bt_conn *conn, uint8_t src_id, - uint8_t advertiser_sid, uint32_t broadcast_id, - bool past_avail, uint16_t pa_interval) -{ - struct btp_bap_pa_sync_req_ev ev; - - bt_addr_le_copy(&ev.address, bt_conn_get_dst(conn)); - ev.src_id = src_id; - ev.advertiser_sid = advertiser_sid; - sys_put_le24(broadcast_id, ev.broadcast_id); - ev.past_avail = past_avail; - ev.pa_interval = sys_cpu_to_le16(pa_interval); - - tester_event(BTP_SERVICE_ID_BAP, BTP_BAP_EV_PA_SYNC_REQ, &ev, sizeof(ev)); -} - -static void btp_send_scan_delegator_found_ev(struct bt_conn *conn) -{ - struct btp_bap_scan_delegator_found_ev ev; - - bt_addr_le_copy(&ev.address, bt_conn_get_dst(conn)); - - tester_event(BTP_SERVICE_ID_BAP, BTP_BAP_EV_SCAN_DELEGATOR_FOUND, &ev, sizeof(ev)); -} - -static void btp_send_broadcast_receive_state_ev(struct bt_conn *conn, - const struct bt_bap_scan_delegator_recv_state *state) -{ - struct btp_bap_broadcast_receive_state_ev *ev; - size_t len; - uint8_t *ptr; - - tester_rsp_buffer_lock(); - tester_rsp_buffer_allocate(sizeof(*ev) + BT_BAP_SCAN_DELEGATOR_MAX_SUBGROUPS * - sizeof(struct bt_bap_scan_delegator_subgroup), (uint8_t **)&ev); - - if (conn) { - bt_addr_le_copy(&ev->address, bt_conn_get_dst(conn)); - } else { - (void)memset(&ev->address, 0, sizeof(ev->address)); - } - - ev->src_id = state->src_id; - bt_addr_le_copy(&ev->broadcaster_address, &state->addr); - ev->advertiser_sid = state->adv_sid; - sys_put_le24(state->broadcast_id, ev->broadcast_id); - ev->pa_sync_state = state->pa_sync_state; - ev->big_encryption = state->encrypt_state; - ev->num_subgroups = state->num_subgroups; - - ptr = ev->subgroups; - for (uint8_t i = 0; i < ev->num_subgroups; i++) { - const struct bt_bap_scan_delegator_subgroup *subgroup = &state->subgroups[i]; - - sys_put_le32(subgroup->bis_sync >> 1, ptr); - ptr += sizeof(subgroup->bis_sync); - *ptr = subgroup->metadata_len; - ptr += sizeof(subgroup->metadata_len); - memcpy(ptr, subgroup->metadata, subgroup->metadata_len); - ptr += subgroup->metadata_len; - } - - len = sizeof(*ev) + ptr - ev->subgroups; - tester_event(BTP_SERVICE_ID_BAP, BTP_BAP_EV_BROADCAST_RECEIVE_STATE, ev, len); - - tester_rsp_buffer_free(); - tester_rsp_buffer_unlock(); -} - -static int pa_sync_past(struct bt_conn *conn, uint16_t sync_timeout) -{ - struct bt_le_per_adv_sync_transfer_param param = { 0 }; - int err; - - param.skip = PA_SYNC_SKIP; - param.timeout = sync_timeout; - - err = bt_le_per_adv_sync_transfer_subscribe(conn, ¶m); - if (err != 0) { - LOG_DBG("Could not do PAST subscribe: %d", err); - } else { - LOG_DBG("Syncing with PAST: %d", err); - (void)k_work_reschedule(&pa_timer, K_MSEC(param.timeout * 10)); - } - - return err; -} - -static int pa_sync_req_cb(struct bt_conn *conn, - const struct bt_bap_scan_delegator_recv_state *recv_state, - bool past_avail, uint16_t pa_interval) -{ - LOG_DBG("sync state %d ", recv_state->pa_sync_state); - - sink_recv_state = recv_state; - broadcast_recv_state = recv_state; - - btp_send_pas_sync_req_ev(conn, recv_state->src_id, recv_state->adv_sid, - recv_state->broadcast_id, past_avail, pa_interval); - - return 0; -} - -static int pa_sync_term_req_cb(struct bt_conn *conn, - const struct bt_bap_scan_delegator_recv_state *recv_state) -{ - LOG_DBG(""); - - sink_recv_state = recv_state; - - tester_gap_padv_stop_sync(); - - return 0; -} - -static void broadcast_code_cb(struct bt_conn *conn, - const struct bt_bap_scan_delegator_recv_state *recv_state, - const uint8_t broadcast_code[BT_AUDIO_BROADCAST_CODE_SIZE]) -{ - int err; - uint32_t index_bitfield; - - LOG_DBG("Broadcast code received for %p", recv_state); - - sink_recv_state = recv_state; - - (void)memcpy(sink_broadcast_code, broadcast_code, BT_AUDIO_BROADCAST_CODE_SIZE); - - if (!requested_bis_sync) { - return; - } - - index_bitfield = bis_index_bitfield & requested_bis_sync; - err = bt_bap_broadcast_sink_sync(broadcast_sink, index_bitfield, sink_streams, - sink_broadcast_code); - if (err != 0) { - LOG_DBG("Unable to sync to broadcast source: %d", err); - } -} - -static int bis_sync_req_cb(struct bt_conn *conn, - const struct bt_bap_scan_delegator_recv_state *recv_state, - const uint32_t bis_sync_req[BT_BAP_SCAN_DELEGATOR_MAX_SUBGROUPS]) -{ - bool bis_synced = false; - - LOG_DBG("BIS sync request received for %p: 0x%08x", recv_state, bis_sync_req[0]); - - for (int i = 0; i < MAX_STREAMS_COUNT; i++) { - if (broadcaster->streams[i].bis_synced) { - bis_synced = true; - break; - } - } - - /* We only care about a single subgroup in this sample */ - if (bis_synced) { - /* If the BIS sync request is received while we are already - * synced, it means that the requested BIS sync has changed. - */ - int err; - - /* The stream stopped callback will be called as part of this, - * and we do not need to wait for any events from the - * controller. Thus, when this returns, the `bis_synced` - * is back to false. - */ - err = bt_bap_broadcast_sink_stop(broadcast_sink); - if (err != 0) { - LOG_DBG("Failed to stop Broadcast Sink: %d", err); - - return err; - } - } - - requested_bis_sync = bis_sync_req[0]; - broadcaster_broadcast_id = recv_state->broadcast_id; - - return 0; -} - -static void recv_state_updated_cb(struct bt_conn *conn, - const struct bt_bap_scan_delegator_recv_state *recv_state) -{ - LOG_DBG("Receive state with ID %u updated", recv_state->src_id); - - btp_send_broadcast_receive_state_ev(conn, recv_state); -} - -static struct bt_bap_scan_delegator_cb scan_delegator_cbs = { - .recv_state_updated = recv_state_updated_cb, - .pa_sync_req = pa_sync_req_cb, - .pa_sync_term_req = pa_sync_term_req_cb, - .broadcast_code = broadcast_code_cb, - .bis_sync_req = bis_sync_req_cb, -}; - -static uint8_t broadcast_sink_setup(const void *cmd, uint16_t cmd_len, - void *rsp, uint16_t *rsp_len) -{ - int err; - - LOG_DBG(""); - - err = broadcast_sink_reset(); - if (err != 0) { - return BTP_STATUS_FAILED; - } - - for (size_t i = 0U; i < MAX_STREAMS_COUNT; i++) { - broadcaster->streams[i].broadcast = true; - sink_streams[i] = &broadcaster->streams[i].stream; - sink_streams[i]->ops = &stream_ops; - } - - /* For Scan Delegator role */ - bt_bap_scan_delegator_register_cb(&scan_delegator_cbs); - - /* For Broadcast Sink role */ - bt_bap_broadcast_sink_register_cb(&broadcast_sink_cbs); - bt_le_per_adv_sync_cb_register(&bap_pa_sync_cb); - - /* For Broadcast Sink or Broadcast Assistant role */ - bt_le_scan_cb_register(&bap_scan_cb); - - return BTP_STATUS_SUCCESS; -} - -static uint8_t broadcast_sink_release(const void *cmd, uint16_t cmd_len, - void *rsp, uint16_t *rsp_len) -{ - int err; - - LOG_DBG(""); - - err = broadcast_sink_reset(); - if (err != 0) { - return BTP_STATUS_FAILED; - } - - return BTP_STATUS_SUCCESS; -} - -static uint8_t broadcast_scan_start(const void *cmd, uint16_t cmd_len, - void *rsp, uint16_t *rsp_len) -{ - int err; - - LOG_DBG(""); - - err = bt_le_scan_start(BT_LE_SCAN_ACTIVE, NULL); - if (err != 0 && err != -EALREADY) { - LOG_DBG("Unable to start scan for broadcast sources: %d", err); - - return BTP_STATUS_FAILED; - } - - return BTP_STATUS_SUCCESS; -} - -static uint8_t broadcast_scan_stop(const void *cmd, uint16_t cmd_len, - void *rsp, uint16_t *rsp_len) -{ - int err; - - LOG_DBG(""); - - err = bt_le_scan_stop(); - if (err != 0) { - LOG_DBG("Failed to stop scan, %d", err); - - return BTP_STATUS_FAILED; - } - - return BTP_STATUS_SUCCESS; -} - -static uint8_t broadcast_sink_sync(const void *cmd, uint16_t cmd_len, - void *rsp, uint16_t *rsp_len) -{ - int err; - struct bt_conn *conn; - const struct btp_bap_broadcast_sink_sync_cmd *cp = cmd; - struct bt_le_per_adv_sync_param create_params = {0}; - - LOG_DBG(""); - - broadcaster_broadcast_id = sys_get_le24(cp->broadcast_id); - bt_addr_le_copy(&broadcaster_addr, &cp->address); - - if (IS_ENABLED(CONFIG_BT_PER_ADV_SYNC_TRANSFER_RECEIVER) && cp->past_avail) { - conn = bt_conn_lookup_addr_le(BT_ID_DEFAULT, &cp->address); - if (!conn) { - return BTP_STATUS_FAILED; - } - - err = bt_bap_scan_delegator_set_pa_state(cp->src_id, BT_BAP_PA_STATE_INFO_REQ); - if (err != 0) { - LOG_DBG("Failed to set INFO_REQ state: %d", err); - } - - err = pa_sync_past(conn, cp->sync_timeout); - } else { - bt_addr_le_copy(&create_params.addr, &cp->address); - create_params.options = 0; - create_params.sid = cp->advertiser_sid; - create_params.skip = cp->skip; - create_params.timeout = cp->sync_timeout; - err = tester_gap_padv_create_sync(&create_params); - } - - if (err != 0) { - return BTP_STATUS_FAILED; - } - - return BTP_STATUS_SUCCESS; -} - -static uint8_t broadcast_sink_stop(const void *cmd, uint16_t cmd_len, - void *rsp, uint16_t *rsp_len) -{ - int err; - - LOG_DBG(""); - - requested_bis_sync = 0; - - err = bt_bap_broadcast_sink_stop(broadcast_sink); - if (err != 0) { - LOG_DBG("Unable to sync to broadcast source: %d", err); - - return BTP_STATUS_FAILED; - } - - err = tester_gap_padv_stop_sync(); - if (err != 0) { - LOG_DBG("Failed to stop PA sync, %d", err); - - return BTP_STATUS_FAILED; - } - - return BTP_STATUS_SUCCESS; -} - -static uint8_t broadcast_sink_bis_sync(const void *cmd, uint16_t cmd_len, - void *rsp, uint16_t *rsp_len) -{ - int err; - const struct btp_bap_broadcast_sink_bis_sync_cmd *cp = cmd; - - LOG_DBG(""); - - if (cp->requested_bis_sync == BT_BAP_BIS_SYNC_NO_PREF) { - requested_bis_sync = sys_le32_to_cpu(cp->requested_bis_sync); - } else { - /* For semantic purposes Zephyr API uses BIS Index bitfield - * where BIT(1) means BIS Index 1 - */ - requested_bis_sync = sys_le32_to_cpu(cp->requested_bis_sync) << 1; - } - - err = bt_bap_broadcast_sink_sync(broadcast_sink, requested_bis_sync, sink_streams, - sink_broadcast_code); - if (err != 0) { - LOG_DBG("Unable to sync to BISes, req_bis_sync %d, err %d", requested_bis_sync, - err); - - return BTP_STATUS_FAILED; - } - - return BTP_STATUS_SUCCESS; -} - -static void bap_broadcast_assistant_discover_cb(struct bt_conn *conn, int err, - uint8_t recv_state_count) -{ - LOG_DBG("err %d", err); - - if (err != 0) { - LOG_DBG("BASS discover failed (%d)", err); - } else { - LOG_DBG("BASS discover done with %u recv states", recv_state_count); - - btp_send_scan_delegator_found_ev(conn); - } -} - -static void bap_broadcast_assistant_scan_cb(const struct bt_le_scan_recv_info *info, - uint32_t broadcast_id) -{ - char le_addr[BT_ADDR_LE_STR_LEN]; - - bt_addr_le_to_str(info->addr, le_addr, sizeof(le_addr)); - LOG_DBG("[DEVICE]: %s, broadcast_id 0x%06X, interval (ms) %u), SID 0x%x, RSSI %i", le_addr, - broadcast_id, BT_GAP_PER_ADV_INTERVAL_TO_MS(info->interval), info->sid, info->rssi); -} - -static void bap_broadcast_assistant_recv_state_cb(struct bt_conn *conn, int err, - const struct bt_bap_scan_delegator_recv_state *state) -{ - LOG_DBG("err: %d", err); - - if (err != 0 || state == NULL) { - return; - } - - btp_send_broadcast_receive_state_ev(conn, state); -} - -static void bap_broadcast_assistant_recv_state_removed_cb(struct bt_conn *conn, int err, - uint8_t src_id) -{ - LOG_DBG("err: %d", err); -} - -static void bap_broadcast_assistant_scan_start_cb(struct bt_conn *conn, int err) -{ - LOG_DBG("err: %d", err); -} - -static void bap_broadcast_assistant_scan_stop_cb(struct bt_conn *conn, int err) -{ - LOG_DBG("err: %d", err); -} - -static void bap_broadcast_assistant_add_src_cb(struct bt_conn *conn, int err) -{ - LOG_DBG("err: %d", err); -} - -static void bap_broadcast_assistant_mod_src_cb(struct bt_conn *conn, int err) -{ - LOG_DBG("err: %d", err); -} - -static void bap_broadcast_assistant_broadcast_code_cb(struct bt_conn *conn, int err) -{ - LOG_DBG("err: %d", err); -} - -static void bap_broadcast_assistant_rem_src_cb(struct bt_conn *conn, int err) -{ - LOG_DBG("err: %d", err); -} - -static struct bt_bap_broadcast_assistant_cb broadcast_assistant_cb = { - .discover = bap_broadcast_assistant_discover_cb, - .scan = bap_broadcast_assistant_scan_cb, - .recv_state = bap_broadcast_assistant_recv_state_cb, - .recv_state_removed = bap_broadcast_assistant_recv_state_removed_cb, - .scan_start = bap_broadcast_assistant_scan_start_cb, - .scan_stop = bap_broadcast_assistant_scan_stop_cb, - .add_src = bap_broadcast_assistant_add_src_cb, - .mod_src = bap_broadcast_assistant_mod_src_cb, - .broadcast_code = bap_broadcast_assistant_broadcast_code_cb, - .rem_src = bap_broadcast_assistant_rem_src_cb, -}; - -static uint8_t broadcast_discover_scan_delegators(const void *cmd, uint16_t cmd_len, - void *rsp, uint16_t *rsp_len) -{ - int err; - struct bt_conn *conn; - const struct btp_bap_discover_scan_delegators_cmd *cp = cmd; - - LOG_DBG(""); - - conn = bt_conn_lookup_addr_le(BT_ID_DEFAULT, &cp->address); - if (!conn) { - return BTP_STATUS_FAILED; - } - - err = bt_bap_broadcast_assistant_discover(conn); - if (err != 0) { - return BTP_STATUS_FAILED; - } - - return BTP_STATUS_SUCCESS; -} - -static uint8_t broadcast_assistant_scan_start(const void *cmd, uint16_t cmd_len, - void *rsp, uint16_t *rsp_len) -{ - int err; - struct bt_conn *conn; - const struct btp_bap_broadcast_assistant_scan_start_cmd *cp = cmd; - - LOG_DBG(""); - - conn = bt_conn_lookup_addr_le(BT_ID_DEFAULT, &cp->address); - if (!conn) { - return BTP_STATUS_FAILED; - } - - err = bt_bap_broadcast_assistant_scan_start(conn, true); - if (err != 0) { - return BTP_STATUS_FAILED; - } - - return BTP_STATUS_SUCCESS; -} - -static uint8_t broadcast_assistant_scan_stop(const void *cmd, uint16_t cmd_len, - void *rsp, uint16_t *rsp_len) -{ - int err; - struct bt_conn *conn; - const struct btp_bap_broadcast_assistant_scan_stop_cmd *cp = cmd; - - LOG_DBG(""); - - conn = bt_conn_lookup_addr_le(BT_ID_DEFAULT, &cp->address); - if (!conn) { - return BTP_STATUS_FAILED; - } - - err = bt_bap_broadcast_assistant_scan_stop(conn); - if (err != 0) { - return BTP_STATUS_FAILED; - } - - return BTP_STATUS_SUCCESS; -} - -static uint8_t broadcast_assistant_add_src(const void *cmd, uint16_t cmd_len, - void *rsp, uint16_t *rsp_len) -{ - int err; - const uint8_t *ptr; - struct bt_conn *conn; - const struct btp_bap_add_broadcast_src_cmd *cp = cmd; - struct bt_bap_broadcast_assistant_add_src_param param = { 0 }; - - LOG_DBG(""); - - conn = bt_conn_lookup_addr_le(BT_ID_DEFAULT, &cp->address); - if (!conn) { - return BTP_STATUS_FAILED; - } - - memset(delegator_subgroups, 0, sizeof(delegator_subgroups)); - bt_addr_le_copy(¶m.addr, &cp->broadcaster_address); - param.adv_sid = cp->advertiser_sid; - param.pa_sync = cp->padv_sync > 0 ? true : false; - param.broadcast_id = sys_get_le24(cp->broadcast_id); - param.pa_interval = sys_le16_to_cpu(cp->padv_interval); - param.num_subgroups = MIN(cp->num_subgroups, BT_BAP_SCAN_DELEGATOR_MAX_SUBGROUPS); - param.subgroups = delegator_subgroups; - - ptr = cp->subgroups; - for (uint8_t i = 0; i < param.num_subgroups; i++) { - struct bt_bap_scan_delegator_subgroup *subgroup = &delegator_subgroups[i]; - - subgroup->bis_sync = sys_get_le32(ptr); - ptr += sizeof(subgroup->bis_sync); - subgroup->metadata_len = *ptr; - ptr += sizeof(subgroup->metadata_len); - memcpy(subgroup->metadata, ptr, subgroup->metadata_len); - ptr += subgroup->metadata_len; - } - - err = bt_bap_broadcast_assistant_add_src(conn, ¶m); - if (err != 0) { - LOG_DBG("err %d", err); - - return BTP_STATUS_FAILED; - } - - return BTP_STATUS_SUCCESS; -} - -static uint8_t broadcast_assistant_remove_src(const void *cmd, uint16_t cmd_len, - void *rsp, uint16_t *rsp_len) -{ - int err; - struct bt_conn *conn; - const struct btp_bap_remove_broadcast_src_cmd *cp = cmd; - - LOG_DBG(""); - - conn = bt_conn_lookup_addr_le(BT_ID_DEFAULT, &cp->address); - if (!conn) { - return BTP_STATUS_FAILED; - } - - err = bt_bap_broadcast_assistant_rem_src(conn, cp->src_id); - if (err != 0) { - return BTP_STATUS_FAILED; - } - - return BTP_STATUS_SUCCESS; -} - -static uint8_t broadcast_assistant_modify_src(const void *cmd, uint16_t cmd_len, - void *rsp, uint16_t *rsp_len) -{ - int err; - const uint8_t *ptr; - struct bt_conn *conn; - const struct btp_bap_modify_broadcast_src_cmd *cp = cmd; - struct bt_bap_broadcast_assistant_mod_src_param param = { 0 }; - - LOG_DBG(""); - - conn = bt_conn_lookup_addr_le(BT_ID_DEFAULT, &cp->address); - if (!conn) { - return BTP_STATUS_FAILED; - } - - memset(delegator_subgroups, 0, sizeof(delegator_subgroups)); - param.src_id = cp->src_id; - param.pa_sync = cp->padv_sync > 0 ? true : false; - param.pa_interval = sys_le16_to_cpu(cp->padv_interval); - param.num_subgroups = MIN(cp->num_subgroups, BT_BAP_SCAN_DELEGATOR_MAX_SUBGROUPS); - param.subgroups = delegator_subgroups; - - ptr = cp->subgroups; - for (uint8_t i = 0; i < param.num_subgroups; i++) { - struct bt_bap_scan_delegator_subgroup *subgroup = &delegator_subgroups[i]; - - subgroup->bis_sync = sys_get_le32(ptr); - ptr += sizeof(subgroup->bis_sync); - subgroup->metadata_len = *ptr; - ptr += sizeof(subgroup->metadata_len); - memcpy(subgroup->metadata, ptr, subgroup->metadata_len); - ptr += subgroup->metadata_len; - } - - err = bt_bap_broadcast_assistant_mod_src(conn, ¶m); - if (err != 0) { - return BTP_STATUS_FAILED; - } - - return BTP_STATUS_SUCCESS; -} - -static uint8_t broadcast_assistant_set_broadcast_code(const void *cmd, uint16_t cmd_len, - void *rsp, uint16_t *rsp_len) -{ - int err; - struct bt_conn *conn; - const struct btp_bap_set_broadcast_code_cmd *cp = cmd; - - LOG_DBG(""); - - conn = bt_conn_lookup_addr_le(BT_ID_DEFAULT, &cp->address); - if (!conn) { - return BTP_STATUS_FAILED; - } - - err = bt_bap_broadcast_assistant_set_broadcast_code(conn, cp->src_id, cp->broadcast_code); - if (err != 0) { - LOG_DBG("err %d", err); - return BTP_STATUS_FAILED; - } - - return BTP_STATUS_SUCCESS; -} - -static uint8_t broadcast_assistant_send_past(const void *cmd, uint16_t cmd_len, - void *rsp, uint16_t *rsp_len) -{ - int err; - uint16_t service_data; - struct bt_conn *conn; - struct bt_le_per_adv_sync *pa_sync; - const struct btp_bap_send_past_cmd *cp = cmd; - - LOG_DBG(""); - - conn = bt_conn_lookup_addr_le(BT_ID_DEFAULT, &cp->address); - if (!conn) { - return BTP_STATUS_FAILED; - } - - pa_sync = tester_gap_padv_get(); - if (!pa_sync) { - LOG_DBG("Could not send PAST to Scan Delegator"); - - return BTP_STATUS_FAILED; - } - - LOG_DBG("Sending PAST"); - - /* If octet 0 is set to 0, it means AdvA in PAST matches AdvA in ADV_EXT_IND. - * Octet 1 shall be set to Source_ID. - */ - service_data = cp->src_id << 8; - - err = bt_le_per_adv_sync_transfer(pa_sync, conn, service_data); - if (err != 0) { - LOG_DBG("Could not transfer periodic adv sync: %d", err); - - return BTP_STATUS_FAILED; - } - - return BTP_STATUS_SUCCESS; -} - -static void connected(struct bt_conn *conn, uint8_t err) -{ - struct audio_connection *audio_conn; - char addr[BT_ADDR_LE_STR_LEN]; - - bt_addr_le_to_str(bt_conn_get_dst(conn), addr, sizeof(addr)); - - if (err != 0) { - LOG_DBG("Failed to connect to %s (%u)", addr, err); - return; - } - - LOG_DBG("Connected: %s", addr); - - audio_conn = &connections[bt_conn_index(conn)]; - memset(audio_conn, 0, sizeof(*audio_conn)); - - for (size_t i = 0; i < ARRAY_SIZE(audio_conn->streams); i++) { - bt_bap_stream_cb_register(&audio_conn->streams[i].stream, &stream_ops); - } -} - -static void disconnected(struct bt_conn *conn, uint8_t reason) -{ - char addr[BT_ADDR_LE_STR_LEN]; - - bt_addr_le_to_str(bt_conn_get_dst(conn), addr, sizeof(addr)); - - LOG_DBG("Disconnected: %s (reason 0x%02x)", addr, reason); -} + BT_AUDIO_CONTEXT_TYPE_ANY); -static struct bt_conn_cb conn_callbacks = { - .connected = connected, - .disconnected = disconnected, -}; +static const struct bt_audio_codec_cap vendor_codec_cap = BT_AUDIO_CODEC_CAP( + 0xff, 0xffff, 0xffff, BT_AUDIO_CODEC_CAP_LC3_DATA(BT_AUDIO_CODEC_LC3_FREQ_ANY, + BT_AUDIO_CODEC_LC3_DURATION_7_5 | BT_AUDIO_CODEC_LC3_DURATION_10, + BT_AUDIO_CODEC_LC3_CHAN_COUNT_SUPPORT(1, 2), 26u, 155, 1u), + BT_AUDIO_CODEC_CAP_LC3_META(BT_AUDIO_CONTEXT_TYPE_ANY)); static struct bt_pacs_cap cap_sink = { .codec_cap = &default_codec_cap, @@ -2419,7 +59,7 @@ static struct bt_pacs_cap vendor_cap_source = { .codec_cap = &vendor_codec_cap, }; -static uint8_t ascs_supported_commands(const void *cmd, uint16_t cmd_len, +static uint8_t btp_ascs_supported_commands(const void *cmd, uint16_t cmd_len, void *rsp, uint16_t *rsp_len) { struct btp_ascs_read_supported_commands_rp *rp = rsp; @@ -2432,628 +72,62 @@ static uint8_t ascs_supported_commands(const void *cmd, uint16_t cmd_len, return BTP_STATUS_SUCCESS; } -static int server_stream_config(struct bt_conn *conn, struct bt_bap_stream *stream, - struct bt_audio_codec_cfg *codec_cfg, - struct bt_audio_codec_qos_pref *qos) -{ - int err; - struct bt_bap_ep *ep; - - err = bt_bap_unicast_server_config_ase(conn, stream, codec_cfg, qos); - if (err != 0) { - return err; - } - - print_codec_cfg(codec_cfg); - - ep = stream->ep; - LOG_DBG("ASE Codec Config: ase_id %u dir %u", ep->status.id, ep->dir); - LOG_DBG("ASE Codec Config stream %p", stream); - - return 0; -} - -static uint8_t client_add_ase_to_cis(struct audio_connection *audio_conn, uint8_t ase_id, - uint8_t cis_id, uint8_t cig_id) -{ - struct audio_stream *stream; - - if (cig_id >= CONFIG_BT_ISO_MAX_CIG || cis_id >= UNICAST_GROUP_STREAM_CNT) { - return BTP_STATUS_FAILED; - } - - stream = stream_find(audio_conn, ase_id); - if (stream == NULL) { - return BTP_STATUS_FAILED; - } - - LOG_DBG("Added ASE %u to CIS %u at CIG %u", ase_id, cis_id, cig_id); - - stream->cig = &cigs[cig_id]; - stream->cig_id = cig_id; - stream->cis_id = cis_id; - - return 0; -} - -static int client_create_unicast_group(struct audio_connection *audio_conn, uint8_t ase_id, - uint8_t cig_id) -{ - int err; - struct bt_bap_unicast_group_stream_pair_param pair_params[MAX_STREAMS_COUNT]; - struct bt_bap_unicast_group_stream_param stream_params[MAX_STREAMS_COUNT]; - struct bt_bap_unicast_group_param param; - size_t stream_cnt = 0; - size_t src_cnt = 0; - size_t sink_cnt = 0; - size_t cis_cnt = 0; - - (void)memset(pair_params, 0, sizeof(pair_params)); - (void)memset(stream_params, 0, sizeof(stream_params)); - - if (cig_id >= CONFIG_BT_ISO_MAX_CIG) { - return -EINVAL; - } - - /* API does not allow to assign a CIG ID freely, so ensure we create groups - * in the right order. - */ - for (uint8_t i = 0; i < cig_id; i++) { - if (cigs[i] == NULL) { - return -EINVAL; - } - } - - /* Assign end points to CISes */ - for (size_t i = 0; i < MAX_STREAMS_COUNT; i++) { - struct audio_stream *a_stream = &audio_conn->streams[i]; - struct bt_bap_stream *stream = &a_stream->stream; - - if (stream == NULL || stream->ep == NULL || a_stream->cig == NULL || - a_stream->cig_id != cig_id) { - continue; - } - - stream_params[stream_cnt].stream = stream; - stream_params[stream_cnt].qos = &audio_conn->qos; - - if (stream->ep->dir == BT_AUDIO_DIR_SOURCE) { - if (pair_params[a_stream->cis_id].rx_param != NULL) { - return -EINVAL; - } - - pair_params[a_stream->cis_id].rx_param = &stream_params[stream_cnt]; - src_cnt++; - } else { - if (pair_params[a_stream->cis_id].tx_param != NULL) { - return -EINVAL; - } - - pair_params[a_stream->cis_id].tx_param = &stream_params[stream_cnt]; - sink_cnt++; - } - - stream_cnt++; - } - - /* Count CISes to be established */ - for (size_t i = 0; i < MAX_STREAMS_COUNT; i++) { - if (pair_params[i].tx_param == NULL && pair_params[i].rx_param == NULL) { - /* No gaps allowed */ - break; - } - - cis_cnt++; - } - - /* Make sure there are no gaps in the pair_params */ - if (cis_cnt == 0 || cis_cnt < MAX(sink_cnt, src_cnt)) { - return -EINVAL; - } - - param.params = pair_params; - param.params_count = cis_cnt; - param.packing = BT_ISO_PACKING_SEQUENTIAL; - - LOG_DBG("Creating unicast group"); - err = bt_bap_unicast_group_create(¶m, &cigs[cig_id]); - if (err != 0) { - LOG_DBG("Could not create unicast group (err %d)", err); - return -EINVAL; - } - - return 0; -} - -static int client_configure_codec(struct audio_connection *audio_conn, struct bt_conn *conn, - uint8_t ase_id, struct bt_audio_codec_cfg *codec_cfg) -{ - int err; - struct bt_bap_ep *ep; - struct audio_stream *stream; - - stream = stream_find(audio_conn, ase_id); - if (stream == NULL) { - /* Configure a new stream */ - stream = stream_alloc(audio_conn); - if (stream == NULL) { - LOG_DBG("No streams available"); - - return -ENOMEM; - } - - if (audio_conn->end_points_count == 0) { - return -EINVAL; - } - - ep = end_point_find(audio_conn, ase_id); - if (ep == NULL) { - return -EINVAL; - } - - err = bt_bap_stream_config(conn, &stream->stream, ep, codec_cfg); - } else { - /* Reconfigure a stream */ - err = bt_bap_stream_reconfig(&stream->stream, codec_cfg); - } - - return err; -} - -static int server_configure_codec(struct audio_connection *audio_conn, struct bt_conn *conn, - uint8_t ase_id, struct bt_audio_codec_cfg *codec_cfg) -{ - struct audio_stream *stream; - int err = 0; - - stream = stream_find(audio_conn, ase_id); - if (stream == NULL) { - /* Zephyr allocates ASE instances for remote clients dynamically. - * To initiate Codec Config operation autonomously in server the role, - * we have to initialize all ASEs with a smaller ID first. - * Fortunately, the PTS has nothing against such behavior. - */ - for (uint8_t i = 1; i <= ase_id; i++) { - stream = stream_find(audio_conn, i); - if (stream != NULL) { - continue; - } - - /* Configure a new stream */ - stream = stream_alloc(audio_conn); - if (stream == NULL) { - LOG_DBG("No streams available"); - - return -ENOMEM; - } - - err = server_stream_config(conn, &stream->stream, codec_cfg, &qos_pref); - } - } else { - /* Reconfigure a stream */ - err = bt_bap_stream_reconfig(&stream->stream, codec_cfg); - } - - return err; -} - -static uint8_t ascs_configure_codec(const void *cmd, uint16_t cmd_len, - void *rsp, uint16_t *rsp_len) -{ - int err; - const struct btp_ascs_configure_codec_cmd *cp = cmd; - struct bt_conn *conn; - struct bt_conn_info conn_info; - struct audio_connection *audio_conn; - struct bt_audio_codec_cfg *codec_cfg; - - conn = bt_conn_lookup_addr_le(BT_ID_DEFAULT, &cp->address); - if (!conn) { - LOG_ERR("Unknown connection"); - return BTP_STATUS_FAILED; - } - - audio_conn = &connections[bt_conn_index(conn)]; - - (void)bt_conn_get_info(conn, &conn_info); - - codec_cfg = &audio_conn->codec_cfg; - memset(codec_cfg, 0, sizeof(*codec_cfg)); - - codec_cfg->id = cp->coding_format; - codec_cfg->vid = cp->vid; - codec_cfg->cid = cp->cid; - - if (cp->cc_ltvs_len != 0) { - codec_cfg->data_len = cp->cc_ltvs_len; - memcpy(codec_cfg->data, cp->cc_ltvs, cp->cc_ltvs_len); - } - - if (conn_info.role == BT_HCI_ROLE_CENTRAL) { - err = client_configure_codec(audio_conn, conn, cp->ase_id, codec_cfg); - } else { - err = server_configure_codec(audio_conn, conn, cp->ase_id, codec_cfg); - } - - bt_conn_unref(conn); - - if (err) { - LOG_DBG("Failed to configure stream (err %d)", err); - return BTP_STATUS_FAILED; - } - - return BTP_STATUS_SUCCESS; -} - -static uint8_t ascs_configure_qos(const void *cmd, uint16_t cmd_len, - void *rsp, uint16_t *rsp_len) -{ - int err; - const struct btp_ascs_configure_qos_cmd *cp = cmd; - struct bt_conn_info conn_info; - struct audio_connection *audio_conn; - struct bt_audio_codec_qos *qos; - struct bt_conn *conn; - - conn = bt_conn_lookup_addr_le(BT_ID_DEFAULT, &cp->address); - if (!conn) { - LOG_ERR("Unknown connection"); - return BTP_STATUS_FAILED; - } - - (void)bt_conn_get_info(conn, &conn_info); - if (conn_info.role == BT_HCI_ROLE_PERIPHERAL) { - bt_conn_unref(conn); - - return BTP_STATUS_FAILED; - } - - audio_conn = &connections[bt_conn_index(conn)]; - - if (cigs[cp->cig_id] != NULL) { - err = bt_bap_unicast_group_delete(cigs[cp->cig_id]); - if (err != 0) { - LOG_DBG("Failed to delete the unicast group, err %d", err); - bt_conn_unref(conn); - - return BTP_STATUS_FAILED; - } - cigs[cp->cig_id] = NULL; - } - - err = client_add_ase_to_cis(audio_conn, cp->ase_id, cp->cis_id, cp->cig_id); - if (err != 0) { - return BTP_STATUS_FAILED; - } - - qos = &audio_conn->qos; - qos->phy = BT_AUDIO_CODEC_QOS_2M; - qos->framing = cp->framing; - qos->rtn = cp->retransmission_num; - qos->sdu = cp->max_sdu; - qos->latency = cp->max_transport_latency; - qos->interval = sys_get_le24(cp->sdu_interval); - qos->pd = sys_get_le24(cp->presentation_delay); - - err = client_create_unicast_group(audio_conn, cp->ase_id, cp->cig_id); - if (err != 0) { - LOG_DBG("Unable to create unicast group, err %d", err); - bt_conn_unref(conn); - - return BTP_STATUS_FAILED; - } - - LOG_DBG("QoS configuring streams"); - err = bt_bap_stream_qos(conn, cigs[cp->cig_id]); - bt_conn_unref(conn); - - if (err != 0) { - LOG_DBG("Unable to QoS configure streams: %d", err); - return BTP_STATUS_FAILED; - } - - return BTP_STATUS_SUCCESS; -} - -static uint8_t ascs_enable(const void *cmd, uint16_t cmd_len, - void *rsp, uint16_t *rsp_len) -{ - int err; - const struct btp_ascs_enable_cmd *cp = cmd; - struct audio_connection *audio_conn; - struct audio_stream *stream; - struct bt_conn *conn; - - conn = bt_conn_lookup_addr_le(BT_ID_DEFAULT, &cp->address); - if (!conn) { - LOG_ERR("Unknown connection"); - return BTP_STATUS_FAILED; - } - - audio_conn = &connections[bt_conn_index(conn)]; - bt_conn_unref(conn); - - stream = stream_find(audio_conn, cp->ase_id); - if (stream == NULL) { - return BTP_STATUS_FAILED; - } - - LOG_DBG("Enabling stream"); - err = bt_bap_stream_enable(&stream->stream, NULL, 0); - if (err != 0) { - LOG_DBG("Could not enable stream: %d", err); - return BTP_STATUS_FAILED; - } - - return BTP_STATUS_SUCCESS; -} - -static uint8_t ascs_disable(const void *cmd, uint16_t cmd_len, - void *rsp, uint16_t *rsp_len) -{ - int err; - const struct btp_ascs_disable_cmd *cp = cmd; - struct audio_connection *audio_conn; - struct audio_stream *stream; - struct bt_conn *conn; - - conn = bt_conn_lookup_addr_le(BT_ID_DEFAULT, &cp->address); - if (!conn) { - LOG_ERR("Unknown connection"); - return BTP_STATUS_FAILED; - } - - audio_conn = &connections[bt_conn_index(conn)]; - bt_conn_unref(conn); - - stream = stream_find(audio_conn, cp->ase_id); - if (stream == NULL) { - return BTP_STATUS_FAILED; - } - - LOG_DBG("Disabling stream"); - err = bt_bap_stream_disable(&stream->stream); - - if (err != 0) { - LOG_DBG("Could not disable stream: %d", err); - return BTP_STATUS_FAILED; - } - - return BTP_STATUS_SUCCESS; -} - -static uint8_t ascs_receiver_start_ready(const void *cmd, uint16_t cmd_len, - void *rsp, uint16_t *rsp_len) -{ - int err; - const struct btp_ascs_receiver_start_ready_cmd *cp = cmd; - struct audio_connection *audio_conn; - struct audio_stream *stream; - struct bt_conn *conn; - - conn = bt_conn_lookup_addr_le(BT_ID_DEFAULT, &cp->address); - if (!conn) { - LOG_ERR("Unknown connection"); - return BTP_STATUS_FAILED; - } - - audio_conn = &connections[bt_conn_index(conn)]; - bt_conn_unref(conn); - - stream = stream_find(audio_conn, cp->ase_id); - if (stream == NULL) { - return BTP_STATUS_FAILED; - } - - LOG_DBG("Starting stream %p, ep %u, dir %u", &stream->stream, cp->ase_id, - stream->stream.ep->dir); - - while (true) { - err = bt_bap_stream_start(&stream->stream); - if (err == -EBUSY) { - /* TODO: How to determine if a controller is ready again after - * bt_bap_stream_start? In AC 6(i) tests the PTS sends Receiver Start Ready - * only after all CISes are established. - */ - k_sleep(K_MSEC(1000)); - continue; - } else if (err != 0) { - LOG_DBG("Could not start stream: %d", err); - return BTP_STATUS_FAILED; - } - - break; - }; - - return BTP_STATUS_SUCCESS; -} - -static uint8_t ascs_receiver_stop_ready(const void *cmd, uint16_t cmd_len, - void *rsp, uint16_t *rsp_len) -{ - int err; - const struct btp_ascs_receiver_stop_ready_cmd *cp = cmd; - struct audio_connection *audio_conn; - struct audio_stream *stream; - struct bt_conn *conn; - - conn = bt_conn_lookup_addr_le(BT_ID_DEFAULT, &cp->address); - if (!conn) { - LOG_ERR("Unknown connection"); - return BTP_STATUS_FAILED; - } - - audio_conn = &connections[bt_conn_index(conn)]; - bt_conn_unref(conn); - - stream = stream_find(audio_conn, cp->ase_id); - if (stream == NULL) { - return BTP_STATUS_FAILED; - } - - LOG_DBG("Stopping stream"); - err = bt_bap_stream_stop(&stream->stream); - if (err != 0) { - LOG_DBG("Could not stop stream: %d", err); - return BTP_STATUS_FAILED; - } - - return BTP_STATUS_SUCCESS; -} - -static uint8_t ascs_release(const void *cmd, uint16_t cmd_len, - void *rsp, uint16_t *rsp_len) -{ - int err; - const struct btp_ascs_release_cmd *cp = cmd; - struct audio_connection *audio_conn; - struct audio_stream *stream; - struct bt_conn *conn; - - conn = bt_conn_lookup_addr_le(BT_ID_DEFAULT, &cp->address); - if (!conn) { - LOG_ERR("Unknown connection"); - return BTP_STATUS_FAILED; - } - - audio_conn = &connections[bt_conn_index(conn)]; - bt_conn_unref(conn); - - stream = stream_find(audio_conn, cp->ase_id); - if (stream == NULL) { - return BTP_STATUS_FAILED; - } - - LOG_DBG("Releasing stream"); - err = bt_bap_stream_release(&stream->stream); - if (err != 0) { - LOG_DBG("Unable to release stream %p, err %d", stream, err); - return BTP_STATUS_FAILED; - } - - return BTP_STATUS_SUCCESS; -} - -static uint8_t ascs_update_metadata(const void *cmd, uint16_t cmd_len, void *rsp, uint16_t *rsp_len) -{ - const uint8_t meta[] = { - BT_AUDIO_CODEC_DATA(BT_AUDIO_METADATA_TYPE_STREAM_CONTEXT, - BT_BYTES_LIST_LE16(BT_AUDIO_CONTEXT_TYPE_ANY)), - }; - const struct btp_ascs_update_metadata_cmd *cp = cmd; - struct audio_connection *audio_conn; - struct audio_stream *stream; - struct bt_conn *conn; - int err; - - conn = bt_conn_lookup_addr_le(BT_ID_DEFAULT, &cp->address); - if (!conn) { - LOG_ERR("Unknown connection"); - return BTP_STATUS_FAILED; - } - - audio_conn = &connections[bt_conn_index(conn)]; - bt_conn_unref(conn); - - stream = stream_find(audio_conn, cp->ase_id); - if (stream == NULL) { - return BTP_STATUS_FAILED; - } - - LOG_DBG("Updating stream metadata"); - err = bt_bap_stream_metadata(&stream->stream, meta, ARRAY_SIZE(meta)); - if (err != 0) { - LOG_DBG("Failed to update stream metadata, err %d", err); - return BTP_STATUS_FAILED; - } - - return BTP_STATUS_SUCCESS; -} - -static uint8_t ascs_add_ase_to_cis(const void *cmd, uint16_t cmd_len, void *rsp, uint16_t *rsp_len) -{ - int err; - struct bt_conn *conn; - struct audio_connection *audio_conn; - struct bt_conn_info conn_info; - const struct btp_ascs_add_ase_to_cis *cp = cmd; - - conn = bt_conn_lookup_addr_le(BT_ID_DEFAULT, &cp->address); - if (!conn) { - LOG_ERR("Unknown connection"); - - return BTP_STATUS_FAILED; - } - - (void)bt_conn_get_info(conn, &conn_info); - if (conn_info.role == BT_HCI_ROLE_PERIPHERAL) { - bt_conn_unref(conn); - - return BTP_STATUS_FAILED; - } - - audio_conn = &connections[bt_conn_index(conn)]; - bt_conn_unref(conn); - - err = client_add_ase_to_cis(audio_conn, cp->ase_id, cp->cis_id, cp->cig_id); - if (err != 0) { - return BTP_STATUS_FAILED; - } - - return BTP_STATUS_SUCCESS; -} - static const struct btp_handler ascs_handlers[] = { { .opcode = BTP_ASCS_READ_SUPPORTED_COMMANDS, .index = BTP_INDEX_NONE, .expect_len = 0, - .func = ascs_supported_commands, + .func = btp_ascs_supported_commands, }, { .opcode = BTP_ASCS_CONFIGURE_CODEC, .expect_len = BTP_HANDLER_LENGTH_VARIABLE, - .func = ascs_configure_codec, + .func = btp_ascs_configure_codec, }, { .opcode = BTP_ASCS_CONFIGURE_QOS, .expect_len = sizeof(struct btp_ascs_configure_qos_cmd), - .func = ascs_configure_qos, + .func = btp_ascs_configure_qos, }, { .opcode = BTP_ASCS_ENABLE, .expect_len = sizeof(struct btp_ascs_enable_cmd), - .func = ascs_enable, + .func = btp_ascs_enable, }, { .opcode = BTP_ASCS_RECEIVER_START_READY, .expect_len = sizeof(struct btp_ascs_receiver_start_ready_cmd), - .func = ascs_receiver_start_ready, + .func = btp_ascs_receiver_start_ready, }, { .opcode = BTP_ASCS_RECEIVER_STOP_READY, .expect_len = sizeof(struct btp_ascs_receiver_stop_ready_cmd), - .func = ascs_receiver_stop_ready, + .func = btp_ascs_receiver_stop_ready, }, { .opcode = BTP_ASCS_DISABLE, .expect_len = sizeof(struct btp_ascs_disable_cmd), - .func = ascs_disable, + .func = btp_ascs_disable, }, { .opcode = BTP_ASCS_RELEASE, .expect_len = sizeof(struct btp_ascs_release_cmd), - .func = ascs_release, + .func = btp_ascs_release, }, { .opcode = BTP_ASCS_UPDATE_METADATA, .expect_len = sizeof(struct btp_ascs_update_metadata_cmd), - .func = ascs_update_metadata, + .func = btp_ascs_update_metadata, }, { .opcode = BTP_ASCS_ADD_ASE_TO_CIS, .expect_len = sizeof(struct btp_ascs_add_ase_to_cis), - .func = ascs_add_ase_to_cis, + .func = btp_ascs_add_ase_to_cis, + }, + { + .opcode = BTP_ASCS_PRECONFIGURE_QOS, + .expect_len = sizeof(struct btp_ascs_preconfigure_qos_cmd), + .func = btp_ascs_preconfigure_qos, }, }; @@ -3172,11 +246,7 @@ static uint8_t pacs_update_characteristic(const void *cmd, uint16_t cmd_len, return BTP_STATUS_FAILED; } - if (err != 0) { - return BTP_STATUS_FAILED; - } - - return BTP_STATUS_SUCCESS; + return BTP_STATUS_VAL(err); } static uint8_t pacs_set_location(const void *cmd, uint16_t cmd_len, @@ -3254,8 +324,8 @@ static const struct btp_handler pacs_handlers[] = { } }; -static uint8_t bap_supported_commands(const void *cmd, uint16_t cmd_len, - void *rsp, uint16_t *rsp_len) +static uint8_t btp_bap_supported_commands(const void *cmd, uint16_t cmd_len, + void *rsp, uint16_t *rsp_len) { struct btp_bap_read_supported_commands_rp *rp = rsp; @@ -3272,130 +342,132 @@ static const struct btp_handler bap_handlers[] = { .opcode = BTP_BAP_READ_SUPPORTED_COMMANDS, .index = BTP_INDEX_NONE, .expect_len = 0, - .func = bap_supported_commands, + .func = btp_bap_supported_commands, }, { .opcode = BTP_BAP_DISCOVER, .expect_len = sizeof(struct btp_bap_discover_cmd), - .func = bap_discover, + .func = btp_bap_discover, }, { .opcode = BTP_BAP_SEND, .expect_len = BTP_HANDLER_LENGTH_VARIABLE, - .func = bap_send, + .func = btp_bap_audio_stream_send, }, +#if defined(CONFIG_BT_BAP_BROADCAST_SINK) || defined(CONFIG_BT_BAP_BROADCAST_SINK) { .opcode = BTP_BAP_BROADCAST_SOURCE_SETUP, .expect_len = BTP_HANDLER_LENGTH_VARIABLE, - .func = broadcast_source_setup, + .func = btp_bap_broadcast_source_setup, }, { .opcode = BTP_BAP_BROADCAST_SOURCE_RELEASE, .expect_len = sizeof(struct btp_bap_broadcast_source_release_cmd), - .func = broadcast_source_release, + .func = btp_bap_broadcast_source_release, }, { .opcode = BTP_BAP_BROADCAST_ADV_START, .expect_len = sizeof(struct btp_bap_broadcast_adv_start_cmd), - .func = broadcast_adv_start, + .func = btp_bap_broadcast_adv_start, }, { .opcode = BTP_BAP_BROADCAST_ADV_STOP, .expect_len = sizeof(struct btp_bap_broadcast_adv_stop_cmd), - .func = broadcast_adv_stop, + .func = btp_bap_broadcast_adv_stop, }, { .opcode = BTP_BAP_BROADCAST_SOURCE_START, .expect_len = sizeof(struct btp_bap_broadcast_source_start_cmd), - .func = broadcast_source_start, + .func = btp_bap_broadcast_source_start, }, { .opcode = BTP_BAP_BROADCAST_SOURCE_STOP, .expect_len = sizeof(struct btp_bap_broadcast_source_stop_cmd), - .func = broadcast_source_stop, + .func = btp_bap_broadcast_source_stop, }, { .opcode = BTP_BAP_BROADCAST_SINK_SETUP, .expect_len = BTP_HANDLER_LENGTH_VARIABLE, - .func = broadcast_sink_setup, + .func = btp_bap_broadcast_sink_setup, }, { .opcode = BTP_BAP_BROADCAST_SINK_RELEASE, .expect_len = sizeof(struct btp_bap_broadcast_sink_release_cmd), - .func = broadcast_sink_release, + .func = btp_bap_broadcast_sink_release, }, { .opcode = BTP_BAP_BROADCAST_SCAN_START, .expect_len = sizeof(struct btp_bap_broadcast_scan_start_cmd), - .func = broadcast_scan_start, + .func = btp_bap_broadcast_scan_start, }, { .opcode = BTP_BAP_BROADCAST_SCAN_STOP, .expect_len = sizeof(struct btp_bap_broadcast_scan_stop_cmd), - .func = broadcast_scan_stop, + .func = btp_bap_broadcast_scan_stop, }, { .opcode = BTP_BAP_BROADCAST_SINK_SYNC, .expect_len = sizeof(struct btp_bap_broadcast_sink_sync_cmd), - .func = broadcast_sink_sync, + .func = btp_bap_broadcast_sink_sync, }, { .opcode = BTP_BAP_BROADCAST_SINK_STOP, .expect_len = sizeof(struct btp_bap_broadcast_sink_stop_cmd), - .func = broadcast_sink_stop, + .func = btp_bap_broadcast_sink_stop, }, { .opcode = BTP_BAP_BROADCAST_SINK_BIS_SYNC, .expect_len = sizeof(struct btp_bap_broadcast_sink_bis_sync_cmd), - .func = broadcast_sink_bis_sync, + .func = btp_bap_broadcast_sink_bis_sync, }, { .opcode = BTP_BAP_DISCOVER_SCAN_DELEGATORS, .expect_len = sizeof(struct btp_bap_discover_scan_delegators_cmd), - .func = broadcast_discover_scan_delegators, + .func = btp_bap_broadcast_discover_scan_delegators, }, { .opcode = BTP_BAP_BROADCAST_ASSISTANT_SCAN_START, .expect_len = sizeof(struct btp_bap_broadcast_assistant_scan_start_cmd), - .func = broadcast_assistant_scan_start, + .func = btp_bap_broadcast_assistant_scan_start, }, { .opcode = BTP_BAP_BROADCAST_ASSISTANT_SCAN_STOP, .expect_len = sizeof(struct btp_bap_broadcast_assistant_scan_stop_cmd), - .func = broadcast_assistant_scan_stop, + .func = btp_bap_broadcast_assistant_scan_stop, }, { .opcode = BTP_BAP_ADD_BROADCAST_SRC, .expect_len = BTP_HANDLER_LENGTH_VARIABLE, - .func = broadcast_assistant_add_src, + .func = btp_bap_broadcast_assistant_add_src, }, { .opcode = BTP_BAP_REMOVE_BROADCAST_SRC, .expect_len = sizeof(struct btp_bap_remove_broadcast_src_cmd), - .func = broadcast_assistant_remove_src, + .func = btp_bap_broadcast_assistant_remove_src, }, { .opcode = BTP_BAP_MODIFY_BROADCAST_SRC, .expect_len = BTP_HANDLER_LENGTH_VARIABLE, - .func = broadcast_assistant_modify_src, + .func = btp_bap_broadcast_assistant_modify_src, }, { .opcode = BTP_BAP_SET_BROADCAST_CODE, .expect_len = sizeof(struct btp_bap_set_broadcast_code_cmd), - .func = broadcast_assistant_set_broadcast_code, + .func = btp_bap_broadcast_assistant_set_broadcast_code, }, { .opcode = BTP_BAP_SEND_PAST, .expect_len = sizeof(struct btp_bap_send_past_cmd), - .func = broadcast_assistant_send_past, + .func = btp_bap_broadcast_assistant_send_past, }, +#endif /* CONFIG_BT_BAP_BROADCAST_SINK || CONFIG_BT_BAP_BROADCAST_SINK */ }; uint8_t tester_init_pacs(void) { int err; - bt_bap_unicast_server_register_cb(&unicast_server_cb); + btp_bap_unicast_init(); bt_pacs_cap_register(BT_AUDIO_DIR_SINK, &cap_sink); bt_pacs_cap_register(BT_AUDIO_DIR_SOURCE, &cap_source); @@ -3430,7 +502,12 @@ uint8_t tester_unregister_pacs(void) uint8_t tester_init_ascs(void) { - bt_conn_cb_register(&conn_callbacks); + int err; + + err = btp_bap_unicast_init(); + if (err != 0) { + return BTP_STATUS_FAILED; + } tester_register_command_handlers(BTP_SERVICE_ID_ASCS, ascs_handlers, ARRAY_SIZE(ascs_handlers)); @@ -3447,24 +524,17 @@ uint8_t tester_init_bap(void) { int err; - /* reset data */ - (void)memset(connections, 0, sizeof(connections)); - - broadcaster = &broadcast_connection; - - err = bt_bap_unicast_client_register_cb(&unicast_client_cbs); + err = btp_bap_unicast_init(); if (err != 0) { - LOG_DBG("Failed to register client callbacks: %d", err); return BTP_STATUS_FAILED; } - /* For Broadcast Assistant role */ - bt_bap_broadcast_assistant_register_cb(&broadcast_assistant_cb); + err = btp_bap_broadcast_init(); + if (err != 0) { + return BTP_STATUS_FAILED; + } - k_work_queue_init(&iso_data_work_q); - k_work_queue_start(&iso_data_work_q, iso_data_thread_stack_area, - K_THREAD_STACK_SIZEOF(iso_data_thread_stack_area), - ISO_DATA_THREAD_PRIORITY, NULL); + btp_bap_audio_stream_init_send_worker(); tester_register_command_handlers(BTP_SERVICE_ID_BAP, bap_handlers, ARRAY_SIZE(bap_handlers)); @@ -3474,8 +544,5 @@ uint8_t tester_init_bap(void) uint8_t tester_unregister_bap(void) { - /* reset data */ - (void)memset(connections, 0, sizeof(connections)); - return BTP_STATUS_SUCCESS; } diff --git a/tests/bluetooth/tester/src/btp_bap_audio_stream.c b/tests/bluetooth/tester/src/btp_bap_audio_stream.c new file mode 100644 index 00000000000..753cc659e70 --- /dev/null +++ b/tests/bluetooth/tester/src/btp_bap_audio_stream.c @@ -0,0 +1,183 @@ +/* btp_bap_audio_stream.c - Bluetooth BAP Tester */ + +/* + * Copyright (c) 2023 Codecoup + * + * SPDX-License-Identifier: Apache-2.0 + */ + + +#include +#include + +#include +#include +#include + +#include +#include +#define LOG_MODULE_NAME bttester_bap_audio_stream +LOG_MODULE_REGISTER(LOG_MODULE_NAME, CONFIG_BTTESTER_LOG_LEVEL); +#include "btp/btp.h" +#include "btp_bap_audio_stream.h" + +NET_BUF_POOL_FIXED_DEFINE(tx_pool, MAX(CONFIG_BT_ASCS_ASE_SRC_COUNT, + CONFIG_BT_BAP_UNICAST_CLIENT_ASE_SRC_COUNT), + BT_ISO_SDU_BUF_SIZE(CONFIG_BT_ISO_TX_MTU), 8, NULL); + +RING_BUF_DECLARE(audio_ring_buf, CONFIG_BT_ISO_TX_MTU); + +#define ISO_DATA_THREAD_STACK_SIZE 512 +#define ISO_DATA_THREAD_PRIORITY -7 +K_THREAD_STACK_DEFINE(iso_data_thread_stack_area, ISO_DATA_THREAD_STACK_SIZE); +static struct k_work_q iso_data_work_q; +static bool send_worker_inited; + +static inline struct bt_bap_stream *audio_stream_to_bap_stream(struct btp_bap_audio_stream *stream) +{ + return &stream->cap_stream.bap_stream; +} + +static void audio_clock_timeout(struct k_work *work) +{ + struct btp_bap_audio_stream *stream; + struct k_work_delayable *dwork; + + dwork = k_work_delayable_from_work(work); + stream = CONTAINER_OF(dwork, struct btp_bap_audio_stream, audio_clock_work); + atomic_inc(&stream->seq_num); + + k_work_schedule(dwork, K_USEC(audio_stream_to_bap_stream(stream)->qos->interval)); +} + +static void audio_send_timeout(struct k_work *work) +{ + struct bt_iso_tx_info info; + struct btp_bap_audio_stream *stream; + struct bt_bap_stream *bap_stream; + struct k_work_delayable *dwork; + struct net_buf *buf; + uint32_t size; + uint8_t *data; + int err; + + dwork = k_work_delayable_from_work(work); + stream = CONTAINER_OF(dwork, struct btp_bap_audio_stream, audio_send_work); + bap_stream = audio_stream_to_bap_stream(stream); + + if (stream->last_req_seq_num % 201 == 200) { + err = bt_bap_stream_get_tx_sync(bap_stream, &info); + if (err != 0) { + LOG_DBG("Failed to get last seq num: err %d", err); + } else if (stream->last_req_seq_num > info.seq_num) { + LOG_DBG("Previous TX request rejected by the controller: requested seq %u," + " last accepted seq %u", stream->last_req_seq_num, info.seq_num); + stream->last_sent_seq_num = info.seq_num; + } else { + LOG_DBG("Host and Controller sequence number is in sync."); + stream->last_sent_seq_num = info.seq_num; + } + /* TODO: Synchronize the Host clock with the Controller clock */ + } + + /* Get buffer within a ring buffer memory */ + size = ring_buf_get_claim(&audio_ring_buf, &data, bap_stream->qos->sdu); + if (size > 0) { + buf = net_buf_alloc(&tx_pool, K_NO_WAIT); + if (!buf) { + LOG_ERR("Cannot allocate net_buf. Dropping data."); + } else { + net_buf_reserve(buf, BT_ISO_CHAN_SEND_RESERVE); + net_buf_add_mem(buf, data, size); + + /* Because the seq_num field of the audio_stream struct is atomic_val_t + * (4 bytes), let's allow an overflow and just cast it to uint16_t. + */ + stream->last_req_seq_num = (uint16_t)atomic_get(&stream->seq_num); + + LOG_DBG("Sending data to stream %p len %d seq %d", bap_stream, size, + stream->last_req_seq_num); + + err = bt_bap_stream_send(bap_stream, buf, 0, BT_ISO_TIMESTAMP_NONE); + if (err != 0) { + LOG_ERR("Failed to send audio data to stream %p, err %d", + bap_stream, err); + net_buf_unref(buf); + } + } + + /* Free ring buffer memory */ + err = ring_buf_get_finish(&audio_ring_buf, size); + if (err != 0) { + LOG_ERR("Error freeing ring buffer memory: %d", err); + } + } + + k_work_schedule_for_queue(&iso_data_work_q, dwork, + K_USEC(bap_stream->qos->interval)); +} + +void btp_bap_audio_stream_started(struct btp_bap_audio_stream *a_stream) +{ + struct bt_bap_ep_info info; + struct bt_bap_stream *bap_stream = audio_stream_to_bap_stream(a_stream); + + /* Callback called on transition to Streaming state */ + + LOG_DBG("Started stream %p", bap_stream); + + (void)bt_bap_ep_get_info(bap_stream->ep, &info); + if (info.can_send == true) { + /* Schedule first TX ISO data at seq_num 1 instead of 0 to ensure + * we are in sync with the controller at start of streaming. + */ + a_stream->seq_num = 1; + + /* Run audio clock work in system work queue */ + k_work_init_delayable(&a_stream->audio_clock_work, audio_clock_timeout); + k_work_schedule(&a_stream->audio_clock_work, K_NO_WAIT); + + /* Run audio send work in user defined work queue */ + k_work_init_delayable(&a_stream->audio_send_work, audio_send_timeout); + k_work_schedule_for_queue(&iso_data_work_q, &a_stream->audio_send_work, + K_USEC(bap_stream->qos->interval)); + } +} + +void btp_bap_audio_stream_stopped(struct btp_bap_audio_stream *a_stream) +{ + /* Stop send timer */ + k_work_cancel_delayable(&a_stream->audio_clock_work); + k_work_cancel_delayable(&a_stream->audio_send_work); +} + +uint8_t btp_bap_audio_stream_send(const void *cmd, uint16_t cmd_len, + void *rsp, uint16_t *rsp_len) +{ + struct btp_bap_send_rp *rp = rsp; + const struct btp_bap_send_cmd *cp = cmd; + uint32_t ret; + + ret = ring_buf_put(&audio_ring_buf, cp->data, cp->data_len); + + rp->data_len = ret; + *rsp_len = sizeof(*rp) + 1; + + return BTP_STATUS_SUCCESS; +} + +int btp_bap_audio_stream_init_send_worker(void) +{ + if (send_worker_inited) { + return 0; + } + + k_work_queue_init(&iso_data_work_q); + k_work_queue_start(&iso_data_work_q, iso_data_thread_stack_area, + K_THREAD_STACK_SIZEOF(iso_data_thread_stack_area), + ISO_DATA_THREAD_PRIORITY, NULL); + + send_worker_inited = true; + + return 0; +} diff --git a/tests/bluetooth/tester/src/btp_bap_audio_stream.h b/tests/bluetooth/tester/src/btp_bap_audio_stream.h new file mode 100644 index 00000000000..902a8f909be --- /dev/null +++ b/tests/bluetooth/tester/src/btp_bap_audio_stream.h @@ -0,0 +1,23 @@ +/* btp_bap_audio_stream.h - Bluetooth BAP Tester */ + +/* + * Copyright (c) 2023 Codecoup + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include + +struct btp_bap_audio_stream { + struct bt_cap_stream cap_stream; + atomic_t seq_num; + uint16_t last_req_seq_num; + uint16_t last_sent_seq_num; + struct k_work_delayable audio_clock_work; + struct k_work_delayable audio_send_work; +}; + +int btp_bap_audio_stream_init_send_worker(void); +void btp_bap_audio_stream_started(struct btp_bap_audio_stream *stream); +void btp_bap_audio_stream_stopped(struct btp_bap_audio_stream *a_stream); +uint8_t btp_bap_audio_stream_send(const void *cmd, uint16_t cmd_len, void *rsp, uint16_t *rsp_len); diff --git a/tests/bluetooth/tester/src/btp_bap_broadcast.c b/tests/bluetooth/tester/src/btp_bap_broadcast.c new file mode 100644 index 00000000000..bd0549e24cb --- /dev/null +++ b/tests/bluetooth/tester/src/btp_bap_broadcast.c @@ -0,0 +1,1571 @@ +/* btp_bap_broadcast.c - Bluetooth BAP Tester */ + +/* + * Copyright (c) 2023 Codecoup + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include +#include + +#include +#include +#include +#include + +#include "bap_endpoint.h" +#include +#include +#define LOG_MODULE_NAME bttester_bap_broadcast +LOG_MODULE_REGISTER(LOG_MODULE_NAME, CONFIG_BTTESTER_LOG_LEVEL); +#include "btp/btp.h" +#include "btp_bap_audio_stream.h" +#include "btp_bap_broadcast.h" + +static struct btp_bap_broadcast_remote_source remote_broadcast_sources[1]; +static struct btp_bap_broadcast_local_source local_source; +/* Only one PA sync supported for now. */ +static struct btp_bap_broadcast_remote_source *broadcast_source_to_sync; +/* A mask for the maximum BIS we can sync to. +1 since the BIS indexes start from 1. */ +static const uint32_t bis_index_mask = BIT_MASK(CONFIG_BT_BAP_BROADCAST_SNK_STREAM_COUNT + 1); +#define INVALID_BROADCAST_ID (BT_AUDIO_BROADCAST_ID_MAX + 1) +#define SYNC_RETRY_COUNT 6 /* similar to retries for connections */ +#define PA_SYNC_SKIP 5 +static struct bt_bap_scan_delegator_subgroup + delegator_subgroups[BT_BAP_SCAN_DELEGATOR_MAX_SUBGROUPS]; + +static inline struct btp_bap_broadcast_stream *stream_bap_to_broadcast(struct bt_bap_stream *stream) +{ + return CONTAINER_OF(CONTAINER_OF(CONTAINER_OF(stream, struct bt_cap_stream, bap_stream), + struct btp_bap_audio_stream, cap_stream), struct btp_bap_broadcast_stream, + audio_stream); +} + +static inline struct bt_bap_stream *stream_broadcast_to_bap(struct btp_bap_broadcast_stream *stream) +{ + return &stream->audio_stream.cap_stream.bap_stream; +} + +struct btp_bap_broadcast_local_source *btp_bap_broadcast_local_source_get(uint8_t source_id) +{ + /* Only one local broadcast source supported for now */ + (void) source_id; + + return &local_source; +} + +static struct btp_bap_broadcast_remote_source *remote_broadcaster_alloc(void) +{ + for (size_t i = 0; i < ARRAY_SIZE(remote_broadcast_sources); i++) { + struct btp_bap_broadcast_remote_source *broadcaster = &remote_broadcast_sources[i]; + + if (broadcaster->broadcast_id == INVALID_BROADCAST_ID) { + return broadcaster; + } + } + + return NULL; +} + +static struct btp_bap_broadcast_remote_source *remote_broadcaster_find(const bt_addr_le_t *addr, + uint32_t broadcast_id) +{ + for (size_t i = 0; i < ARRAY_SIZE(remote_broadcast_sources); i++) { + struct btp_bap_broadcast_remote_source *broadcaster = &remote_broadcast_sources[i]; + + if (broadcaster->broadcast_id == broadcast_id && + bt_addr_le_cmp(addr, &broadcaster->address) == 0) { + return broadcaster; + } + } + + return NULL; +} + +static struct btp_bap_broadcast_remote_source *remote_broadcaster_find_by_sink( + struct bt_bap_broadcast_sink *sink) +{ + for (size_t i = 0; i < ARRAY_SIZE(remote_broadcast_sources); i++) { + struct btp_bap_broadcast_remote_source *broadcaster = &remote_broadcast_sources[i]; + + if (broadcaster->sink == sink) { + return broadcaster; + } + } + + return NULL; +} + +static void btp_send_bis_syced_ev(const bt_addr_le_t *address, uint32_t broadcast_id, + uint8_t bis_id) +{ + struct btp_bap_bis_syned_ev ev; + + bt_addr_le_copy(&ev.address, address); + sys_put_le24(broadcast_id, ev.broadcast_id); + ev.bis_id = bis_id; + + tester_event(BTP_SERVICE_ID_BAP, BTP_BAP_EV_BIS_SYNCED, &ev, sizeof(ev)); +} + +static void stream_started(struct bt_bap_stream *stream) +{ + struct btp_bap_broadcast_remote_source *broadcaster; + struct btp_bap_broadcast_stream *b_stream = stream_bap_to_broadcast(stream); + + /* Callback called on transition to Streaming state */ + + LOG_DBG("Started stream %p", stream); + + btp_bap_audio_stream_started(&b_stream->audio_stream); + b_stream->bis_synced = true; + broadcaster = &remote_broadcast_sources[b_stream->source_id]; + + btp_send_bis_syced_ev(&broadcaster->address, broadcaster->broadcast_id, b_stream->bis_id); +} + +static void stream_stopped(struct bt_bap_stream *stream, uint8_t reason) +{ + struct btp_bap_broadcast_stream *b_stream = stream_bap_to_broadcast(stream); + + LOG_DBG("Stopped stream %p with reason 0x%02X", stream, reason); + + btp_bap_audio_stream_stopped(&b_stream->audio_stream); + + b_stream->bis_synced = false; +} + +static void send_bis_stream_received_ev(const bt_addr_le_t *address, uint32_t broadcast_id, + uint8_t bis_id, uint8_t data_len, uint8_t *data) +{ + struct btp_bap_bis_stream_received_ev *ev; + + tester_rsp_buffer_lock(); + tester_rsp_buffer_allocate(sizeof(*ev) + data_len, (uint8_t **)&ev); + + LOG_DBG("Stream received, len %d", data_len); + + bt_addr_le_copy(&ev->address, address); + sys_put_le24(broadcast_id, ev->broadcast_id); + ev->bis_id = bis_id; + ev->data_len = data_len; + memcpy(ev->data, data, data_len); + + tester_event(BTP_SERVICE_ID_BAP, BTP_BAP_EV_BIS_STREAM_RECEIVED, ev, + sizeof(*ev) + data_len); + + tester_rsp_buffer_free(); + tester_rsp_buffer_unlock(); +} + +static void stream_recv(struct bt_bap_stream *stream, + const struct bt_iso_recv_info *info, + struct net_buf *buf) +{ + struct btp_bap_broadcast_remote_source *broadcaster; + struct btp_bap_broadcast_stream *b_stream = stream_bap_to_broadcast(stream); + + if (b_stream->already_sent == false) { + /* For now, send just a first packet, to limit the number + * of logs and not unnecessarily spam through btp. + */ + LOG_DBG("Incoming audio on stream %p len %u", stream, buf->len); + b_stream->already_sent = true; + broadcaster = &remote_broadcast_sources[b_stream->source_id]; + send_bis_stream_received_ev(&broadcaster->address, broadcaster->broadcast_id, + b_stream->bis_id, buf->len, buf->data); + } +} + +static void stream_sent(struct bt_bap_stream *stream) +{ + LOG_DBG("Stream %p sent", stream); +} + +static struct bt_bap_stream_ops stream_ops = { + .started = stream_started, + .stopped = stream_stopped, + .recv = stream_recv, + .sent = stream_sent, +}; + +struct btp_bap_broadcast_stream *btp_bap_broadcast_stream_alloc( + struct btp_bap_broadcast_local_source *source) +{ + for (size_t i = 0; i < ARRAY_SIZE(source->streams); i++) { + struct btp_bap_broadcast_stream *stream = &source->streams[i]; + + if (stream->in_use == false) { + bt_bap_stream_cb_register(stream_broadcast_to_bap(stream), &stream_ops); + stream->in_use = true; + + return stream; + } + } + + return NULL; +} + +static void remote_broadcaster_free(struct btp_bap_broadcast_remote_source *broadcaster) +{ + (void)memset(broadcaster, 0, sizeof(*broadcaster)); + + broadcaster->broadcast_id = INVALID_BROADCAST_ID; + + for (size_t i = 0U; i < ARRAY_SIZE(broadcaster->sink_streams); i++) { + broadcaster->sink_streams[i] = stream_broadcast_to_bap(&broadcaster->streams[i]); + broadcaster->sink_streams[i]->ops = &stream_ops; + } +} + +static int setup_broadcast_source(uint8_t streams_per_subgroup, uint8_t subgroups, + struct btp_bap_broadcast_local_source *source, + struct bt_audio_codec_cfg *codec_cfg) +{ + int err; + struct bt_bap_broadcast_source_stream_param + stream_params[CONFIG_BT_BAP_BROADCAST_SRC_STREAM_COUNT]; + struct bt_bap_broadcast_source_subgroup_param + subgroup_param[CONFIG_BT_BAP_BROADCAST_SRC_SUBGROUP_COUNT]; + struct bt_bap_broadcast_source_param create_param; + + if (streams_per_subgroup * subgroups > CONFIG_BT_BAP_BROADCAST_SRC_STREAM_COUNT || + subgroups > CONFIG_BT_BAP_BROADCAST_SRC_SUBGROUP_COUNT) { + return -EINVAL; + } + + /* BIS Codec Specific Configuration will be specified on subgroup level, + * with a pointer, so let's store the codec_cfg in the first stream instance. + */ + memcpy(&source->streams[0].codec_cfg, codec_cfg, sizeof(*codec_cfg)); + + for (size_t i = 0U; i < subgroups; i++) { + subgroup_param[i].params_count = streams_per_subgroup; + subgroup_param[i].params = stream_params + i * streams_per_subgroup; + subgroup_param[i].codec_cfg = &source->streams[0].codec_cfg; + } + + for (size_t j = 0U; j < streams_per_subgroup; j++) { + struct btp_bap_broadcast_stream *b_stream = &source->streams[j]; + struct bt_bap_stream *stream = stream_broadcast_to_bap(b_stream); + + stream_params[j].stream = stream; + bt_bap_stream_cb_register(stream, &stream_ops); + + /* BIS Codec Specific Configuration specified on subgroup level */ + stream_params[j].data = NULL; + stream_params[j].data_len = 0U; + } + + create_param.params_count = subgroups; + create_param.params = subgroup_param; + create_param.qos = &source->qos; + create_param.encryption = false; + create_param.packing = BT_ISO_PACKING_SEQUENTIAL; + + LOG_DBG("Creating broadcast source with %zu subgroups with %zu streams", + subgroups, subgroups * streams_per_subgroup); + + if (source->bap_broadcast == NULL) { + err = bt_bap_broadcast_source_create(&create_param, + &source->bap_broadcast); + if (err != 0) { + LOG_DBG("Unable to create broadcast source: %d", err); + + return err; + } + } else { + err = bt_bap_broadcast_source_reconfig(source->bap_broadcast, + &create_param); + if (err != 0) { + LOG_DBG("Unable to reconfig broadcast source: %d", err); + + return err; + } + } + + return 0; +} + +uint8_t btp_bap_broadcast_source_setup(const void *cmd, uint16_t cmd_len, + void *rsp, uint16_t *rsp_len) +{ + int err; + struct bt_audio_codec_cfg codec_cfg; + const struct btp_bap_broadcast_source_setup_cmd *cp = cmd; + struct btp_bap_broadcast_source_setup_rp *rp = rsp; + struct bt_le_adv_param *param = BT_LE_EXT_ADV_NCONN_NAME; + + /* Only one local source/BIG supported for now */ + struct btp_bap_broadcast_local_source *source = &local_source; + + uint32_t gap_settings = BIT(BTP_GAP_SETTINGS_DISCOVERABLE) | + BIT(BTP_GAP_SETTINGS_EXTENDED_ADVERTISING); + + NET_BUF_SIMPLE_DEFINE(ad_buf, BT_UUID_SIZE_16 + BT_AUDIO_BROADCAST_ID_SIZE); + NET_BUF_SIMPLE_DEFINE(base_buf, 128); + + /* Broadcast Audio Streaming Endpoint advertising data */ + struct bt_data base_ad; + struct bt_data per_ad; + + LOG_DBG(""); + + memset(&codec_cfg, 0, sizeof(codec_cfg)); + codec_cfg.id = cp->coding_format; + codec_cfg.vid = cp->vid; + codec_cfg.cid = cp->cid; + codec_cfg.data_len = cp->cc_ltvs_len; + memcpy(codec_cfg.data, cp->cc_ltvs, cp->cc_ltvs_len); + + source->qos.phy = BT_AUDIO_CODEC_QOS_2M; + source->qos.framing = cp->framing; + source->qos.rtn = cp->retransmission_num; + source->qos.latency = sys_le16_to_cpu(cp->max_transport_latency); + source->qos.interval = sys_get_le24(cp->sdu_interval); + source->qos.pd = sys_get_le24(cp->presentation_delay); + source->qos.sdu = sys_le16_to_cpu(cp->max_sdu); + + err = setup_broadcast_source(cp->streams_per_subgroup, cp->subgroups, source, &codec_cfg); + if (err != 0) { + LOG_DBG("Unable to setup broadcast source: %d", err); + + return BTP_STATUS_FAILED; + } + + err = bt_bap_broadcast_source_get_id(source->bap_broadcast, &source->broadcast_id); + if (err != 0) { + LOG_DBG("Unable to get broadcast ID: %d", err); + + return BTP_STATUS_FAILED; + } + + /* Setup extended advertising data */ + net_buf_simple_add_le16(&ad_buf, BT_UUID_BROADCAST_AUDIO_VAL); + net_buf_simple_add_le24(&ad_buf, source->broadcast_id); + base_ad.type = BT_DATA_SVC_DATA16; + base_ad.data_len = ad_buf.len; + base_ad.data = ad_buf.data; + err = tester_gap_create_adv_instance(param, BTP_GAP_ADDR_TYPE_IDENTITY, &base_ad, 1, NULL, + 0, &gap_settings); + if (err != 0) { + LOG_DBG("Failed to create extended advertising instance: %d", err); + + return BTP_STATUS_FAILED; + } + + err = tester_gap_padv_configure(BT_LE_PER_ADV_PARAM(BT_GAP_PER_ADV_FAST_INT_MIN_2, + BT_GAP_PER_ADV_FAST_INT_MAX_2, + BT_LE_PER_ADV_OPT_USE_TX_POWER)); + if (err != 0) { + LOG_DBG("Failed to configure periodic advertising: %d", err); + + return BTP_STATUS_FAILED; + } + + err = bt_bap_broadcast_source_get_base(source->bap_broadcast, &base_buf); + if (err != 0) { + LOG_DBG("Failed to get encoded BASE: %d\n", err); + + return BTP_STATUS_FAILED; + } + + per_ad.type = BT_DATA_SVC_DATA16; + per_ad.data_len = base_buf.len; + per_ad.data = base_buf.data; + err = tester_gap_padv_set_data(&per_ad, 1); + if (err != 0) { + return BTP_STATUS_FAILED; + } + + rp->gap_settings = gap_settings; + sys_put_le24(source->broadcast_id, rp->broadcast_id); + *rsp_len = sizeof(*rp) + 1; + + return BTP_STATUS_SUCCESS; +} + +uint8_t btp_bap_broadcast_source_release(const void *cmd, uint16_t cmd_len, + void *rsp, uint16_t *rsp_len) +{ + int err; + struct btp_bap_broadcast_local_source *source = &local_source; + + LOG_DBG(""); + + err = bt_bap_broadcast_source_delete(source->bap_broadcast); + if (err != 0) { + LOG_DBG("Unable to delete broadcast source: %d", err); + + return BTP_STATUS_FAILED; + } + + memset(source, 0, sizeof(*source)); + + return BTP_STATUS_SUCCESS; +} + +uint8_t btp_bap_broadcast_adv_start(const void *cmd, uint16_t cmd_len, + void *rsp, uint16_t *rsp_len) +{ + int err; + struct bt_le_ext_adv *ext_adv = tester_gap_ext_adv_get(); + + LOG_DBG(""); + + if (ext_adv == NULL) { + return BTP_STATUS_FAILED; + } + + err = tester_gap_start_ext_adv(); + if (err != 0) { + return BTP_STATUS_FAILED; + } + + err = tester_gap_padv_start(); + if (err != 0) { + LOG_DBG("Unable to start periodic advertising: %d", err); + + return BTP_STATUS_FAILED; + } + + return BTP_STATUS_SUCCESS; +} + +uint8_t btp_bap_broadcast_adv_stop(const void *cmd, uint16_t cmd_len, + void *rsp, uint16_t *rsp_len) +{ + int err; + + LOG_DBG(""); + + err = tester_gap_padv_stop(); + if (err != 0) { + return BTP_STATUS_FAILED; + } + + err = tester_gap_stop_ext_adv(); + + return BTP_STATUS_VAL(err); +} + +uint8_t btp_bap_broadcast_source_start(const void *cmd, uint16_t cmd_len, + void *rsp, uint16_t *rsp_len) +{ + int err; + struct btp_bap_broadcast_local_source *source = &local_source; + struct bt_le_ext_adv *ext_adv = tester_gap_ext_adv_get(); + + LOG_DBG(""); + + if (ext_adv == NULL) { + return BTP_STATUS_FAILED; + } + + err = bt_bap_broadcast_source_start(source->bap_broadcast, ext_adv); + if (err != 0) { + LOG_DBG("Unable to start broadcast source: %d", err); + + return BTP_STATUS_FAILED; + } + + return BTP_STATUS_SUCCESS; +} + +uint8_t btp_bap_broadcast_source_stop(const void *cmd, uint16_t cmd_len, + void *rsp, uint16_t *rsp_len) +{ + int err; + struct btp_bap_broadcast_local_source *source = &local_source; + + LOG_DBG(""); + + err = bt_bap_broadcast_source_stop(source->bap_broadcast); + if (err != 0) { + LOG_DBG("Unable to stop broadcast source: %d", err); + + return BTP_STATUS_FAILED; + } + + return BTP_STATUS_SUCCESS; +} + +static int broadcast_sink_reset(void) +{ + for (size_t i = 0; i < ARRAY_SIZE(remote_broadcast_sources); i++) { + remote_broadcaster_free(&remote_broadcast_sources[i]); + } + + return 0; +} + +static void btp_send_baa_found_ev(const bt_addr_le_t *address, uint32_t broadcast_id, + uint8_t sid, uint16_t interval) +{ + struct btp_bap_baa_found_ev ev; + + bt_addr_le_copy(&ev.address, address); + sys_put_le24(broadcast_id, ev.broadcast_id); + ev.advertiser_sid = sid; + ev.padv_interval = sys_cpu_to_le16(interval); + + tester_event(BTP_SERVICE_ID_BAP, BTP_BAP_EV_BAA_FOUND, &ev, sizeof(ev)); +} + +static bool baa_check(struct bt_data *data, void *user_data) +{ + const struct bt_le_scan_recv_info *info = user_data; + char le_addr[BT_ADDR_LE_STR_LEN]; + struct bt_uuid_16 adv_uuid; + uint32_t broadcast_id; + + /* Parse the scanned Broadcast Audio Announcement */ + + if (data->type != BT_DATA_SVC_DATA16) { + return true; + } + + if (data->data_len < BT_UUID_SIZE_16 + BT_AUDIO_BROADCAST_ID_SIZE) { + return true; + } + + if (!bt_uuid_create(&adv_uuid.uuid, data->data, BT_UUID_SIZE_16)) { + return true; + } + + if (bt_uuid_cmp(&adv_uuid.uuid, BT_UUID_BROADCAST_AUDIO)) { + return true; + } + + broadcast_id = sys_get_le24(data->data + BT_UUID_SIZE_16); + + bt_addr_le_to_str(info->addr, le_addr, sizeof(le_addr)); + + LOG_DBG("Found BAA with ID 0x%06X, addr %s, sid 0x%02X, interval 0x%04X", + broadcast_id, le_addr, info->sid, info->interval); + + btp_send_baa_found_ev(info->addr, broadcast_id, info->sid, info->interval); + + /* Stop parsing */ + return false; +} + +static void broadcast_scan_recv(const struct bt_le_scan_recv_info *info, struct net_buf_simple *ad) +{ + /* If 0 there is no periodic advertising. */ + if (info->interval != 0U) { + bt_data_parse(ad, baa_check, (void *)info); + } +} + +static struct bt_le_scan_cb bap_scan_cb = { + .recv = broadcast_scan_recv, +}; + +static void btp_send_bis_found_ev(const bt_addr_le_t *address, uint32_t broadcast_id, uint32_t pd, + uint8_t subgroup_index, uint8_t bis_index, + const struct bt_audio_codec_cfg *codec_cfg) +{ + struct btp_bap_bis_found_ev *ev; + + tester_rsp_buffer_lock(); + tester_rsp_buffer_allocate(sizeof(*ev) + codec_cfg->data_len, (uint8_t **)&ev); + + bt_addr_le_copy(&ev->address, address); + sys_put_le24(broadcast_id, ev->broadcast_id); + sys_put_le24(pd, ev->presentation_delay); + ev->subgroup_id = subgroup_index; + ev->bis_id = bis_index; + ev->coding_format = codec_cfg->id; + ev->vid = sys_cpu_to_le16(codec_cfg->vid); + ev->cid = sys_cpu_to_le16(codec_cfg->cid); + + ev->cc_ltvs_len = codec_cfg->data_len; + memcpy(ev->cc_ltvs, codec_cfg->data, ev->cc_ltvs_len); + + tester_event(BTP_SERVICE_ID_BAP, BTP_BAP_EV_BIS_FOUND, ev, + sizeof(*ev) + ev->cc_ltvs_len); + + tester_rsp_buffer_free(); + tester_rsp_buffer_unlock(); +} + +struct base_parse_data { + struct btp_bap_broadcast_remote_source *broadcaster; + uint32_t pd; + struct bt_audio_codec_cfg codec_cfg; + uint8_t subgroup_cnt; + uint32_t bis_bitfield; + size_t stream_cnt; +}; + +static bool base_subgroup_bis_cb(const struct bt_bap_base_subgroup_bis *bis, void *user_data) +{ + struct base_parse_data *parse_data = user_data; + struct bt_audio_codec_cfg *codec_cfg = &parse_data->codec_cfg; + struct btp_bap_broadcast_remote_source *broadcaster = parse_data->broadcaster; + + parse_data->bis_bitfield |= BIT(bis->index); + + if (parse_data->stream_cnt < ARRAY_SIZE(broadcaster->streams)) { + struct btp_bap_broadcast_stream *stream = + &broadcaster->streams[parse_data->stream_cnt++]; + + stream->bis_id = bis->index; + memcpy(&stream->codec_cfg, codec_cfg, sizeof(*codec_cfg)); + } + + btp_send_bis_found_ev(&broadcaster->address, broadcaster->broadcast_id, parse_data->pd, + parse_data->subgroup_cnt, bis->index, codec_cfg); + + return true; +} + +static bool base_subgroup_cb(const struct bt_bap_base_subgroup *subgroup, void *user_data) +{ + struct base_parse_data *parse_data = user_data; + int err; + + err = bt_bap_base_subgroup_codec_to_codec_cfg(subgroup, &parse_data->codec_cfg); + if (err != 0) { + LOG_DBG("Failed to retrieve codec config: %d", err); + return false; + } + + err = bt_bap_base_subgroup_foreach_bis(subgroup, base_subgroup_bis_cb, user_data); + if (err != 0) { + LOG_DBG("Failed to parse all BIS: %d", err); + return false; + } + + return true; +} + +static void base_recv_cb(struct bt_bap_broadcast_sink *sink, const struct bt_bap_base *base, + size_t base_size) +{ + struct btp_bap_broadcast_remote_source *broadcaster; + struct base_parse_data parse_data = {0}; + int ret; + + LOG_DBG(""); + + broadcaster = remote_broadcaster_find_by_sink(sink); + if (broadcaster == NULL) { + LOG_ERR("Failed to find broadcaster"); + + return; + } + + LOG_DBG("Received BASE: broadcast sink %p subgroups %u", + sink, bt_bap_base_get_subgroup_count(base)); + + ret = bt_bap_base_get_pres_delay(base); + if (ret < 0) { + LOG_ERR("Failed to get presentation delay: %d", ret); + return; + } + + parse_data.broadcaster = broadcaster; + parse_data.pd = (uint32_t)ret; + + ret = bt_bap_base_foreach_subgroup(base, base_subgroup_cb, &parse_data); + if (ret != 0) { + LOG_ERR("Failed to parse subgroups: %d", ret); + return; + } + + broadcaster->bis_index_bitfield = parse_data.bis_bitfield & bis_index_mask; + LOG_DBG("bis_index_bitfield 0x%08x", broadcaster->bis_index_bitfield); +} + +static void syncable_cb(struct bt_bap_broadcast_sink *sink, bool encrypted) +{ + int err; + uint32_t index_bitfield; + struct btp_bap_broadcast_remote_source *broadcaster = remote_broadcaster_find_by_sink(sink); + + if (broadcaster == NULL) { + LOG_ERR("remote_broadcaster_find_by_sink failed, %p", sink); + + return; + } + + LOG_DBG("Broadcaster PA found, encrypted %d, requested_bis_sync %d", encrypted, + broadcaster->requested_bis_sync); + + if (encrypted) { + /* Wait for Set Broadcast Code and start sync at broadcast_code_cb */ + return; + } + + if (!broadcaster->assistant_request || !broadcaster->requested_bis_sync) { + /* No sync with any BIS was requested yet */ + return; + } + + index_bitfield = broadcaster->bis_index_bitfield & broadcaster->requested_bis_sync; + err = bt_bap_broadcast_sink_sync(broadcaster->sink, index_bitfield, + broadcaster->sink_streams, + broadcaster->sink_broadcast_code); + if (err != 0) { + LOG_DBG("Unable to sync to broadcast source: %d", err); + } + + broadcaster->assistant_request = false; +} + +static struct bt_bap_broadcast_sink_cb broadcast_sink_cbs = { + .base_recv = base_recv_cb, + .syncable = syncable_cb, +}; + +static void pa_timer_handler(struct k_work *work) +{ + if (broadcast_source_to_sync != NULL) { + enum bt_bap_pa_state pa_state; + const struct bt_bap_scan_delegator_recv_state *recv_state = + broadcast_source_to_sync->sink_recv_state; + + if (recv_state->pa_sync_state == BT_BAP_PA_STATE_INFO_REQ) { + pa_state = BT_BAP_PA_STATE_NO_PAST; + } else { + pa_state = BT_BAP_PA_STATE_FAILED; + } + + bt_bap_scan_delegator_set_pa_state(recv_state->src_id, pa_state); + } + + LOG_DBG("PA timeout"); +} + +static K_WORK_DELAYABLE_DEFINE(pa_timer, pa_timer_handler); + +static void bap_pa_sync_synced_cb(struct bt_le_per_adv_sync *sync, + struct bt_le_per_adv_sync_synced_info *info) +{ + int err; + + LOG_DBG("Sync info: service_data 0x%04X", info->service_data); + + k_work_cancel_delayable(&pa_timer); + + /* We are synced to a PA. We know that this is the Broadcaster PA we wanted + * to sync to, because we support only one sync for now. + */ + if (broadcast_source_to_sync == NULL) { + LOG_DBG("Failed to create broadcast sink, NULL ptr"); + + return; + } + + /* In order to parse the BASE and BIG Info from the Broadcast PA, we have to create + * a Broadcast Sink instance. From now on callbacks of the broadcast_sink_cbs will be used. + */ + err = bt_bap_broadcast_sink_create(sync, broadcast_source_to_sync->broadcast_id, + &broadcast_source_to_sync->sink); + if (err != 0) { + LOG_DBG("Failed to create broadcast sink: ID 0x%06X, err %d", + broadcast_source_to_sync->broadcast_id, err); + } + + broadcast_source_to_sync = NULL; +} + +static struct bt_le_per_adv_sync_cb bap_pa_sync_cb = { + .synced = bap_pa_sync_synced_cb, +}; + +static void btp_send_pas_sync_req_ev(struct bt_conn *conn, uint8_t src_id, + uint8_t advertiser_sid, uint32_t broadcast_id, + bool past_avail, uint16_t pa_interval) +{ + struct btp_bap_pa_sync_req_ev ev; + + bt_addr_le_copy(&ev.address, bt_conn_get_dst(conn)); + ev.src_id = src_id; + ev.advertiser_sid = advertiser_sid; + sys_put_le24(broadcast_id, ev.broadcast_id); + ev.past_avail = past_avail; + ev.pa_interval = sys_cpu_to_le16(pa_interval); + + tester_event(BTP_SERVICE_ID_BAP, BTP_BAP_EV_PA_SYNC_REQ, &ev, sizeof(ev)); +} + +static void btp_send_scan_delegator_found_ev(struct bt_conn *conn) +{ + struct btp_bap_scan_delegator_found_ev ev; + + bt_addr_le_copy(&ev.address, bt_conn_get_dst(conn)); + + tester_event(BTP_SERVICE_ID_BAP, BTP_BAP_EV_SCAN_DELEGATOR_FOUND, &ev, sizeof(ev)); +} + +static void btp_send_broadcast_receive_state_ev(struct bt_conn *conn, + const struct bt_bap_scan_delegator_recv_state *state) +{ + struct btp_bap_broadcast_receive_state_ev *ev; + size_t len; + uint8_t *ptr; + + tester_rsp_buffer_lock(); + tester_rsp_buffer_allocate(sizeof(*ev) + BT_BAP_SCAN_DELEGATOR_MAX_SUBGROUPS * + sizeof(struct bt_bap_scan_delegator_subgroup), (uint8_t **)&ev); + + if (conn) { + bt_addr_le_copy(&ev->address, bt_conn_get_dst(conn)); + } else { + (void)memset(&ev->address, 0, sizeof(ev->address)); + } + + ev->src_id = state->src_id; + bt_addr_le_copy(&ev->broadcaster_address, &state->addr); + ev->advertiser_sid = state->adv_sid; + sys_put_le24(state->broadcast_id, ev->broadcast_id); + ev->pa_sync_state = state->pa_sync_state; + ev->big_encryption = state->encrypt_state; + ev->num_subgroups = state->num_subgroups; + + ptr = ev->subgroups; + for (uint8_t i = 0; i < ev->num_subgroups; i++) { + const struct bt_bap_scan_delegator_subgroup *subgroup = &state->subgroups[i]; + + sys_put_le32(subgroup->bis_sync >> 1, ptr); + ptr += sizeof(subgroup->bis_sync); + *ptr = subgroup->metadata_len; + ptr += sizeof(subgroup->metadata_len); + memcpy(ptr, subgroup->metadata, subgroup->metadata_len); + ptr += subgroup->metadata_len; + } + + len = sizeof(*ev) + ptr - ev->subgroups; + tester_event(BTP_SERVICE_ID_BAP, BTP_BAP_EV_BROADCAST_RECEIVE_STATE, ev, len); + + tester_rsp_buffer_free(); + tester_rsp_buffer_unlock(); +} + +static int pa_sync_past(struct bt_conn *conn, uint16_t sync_timeout) +{ + struct bt_le_per_adv_sync_transfer_param param = { 0 }; + int err; + + param.skip = PA_SYNC_SKIP; + param.timeout = sync_timeout; + + err = bt_le_per_adv_sync_transfer_subscribe(conn, ¶m); + if (err != 0) { + LOG_DBG("Could not do PAST subscribe: %d", err); + } else { + LOG_DBG("Syncing with PAST: %d", err); + (void)k_work_reschedule(&pa_timer, K_MSEC(param.timeout * 10)); + } + + return err; +} + +static int pa_sync_req_cb(struct bt_conn *conn, + const struct bt_bap_scan_delegator_recv_state *recv_state, + bool past_avail, uint16_t pa_interval) +{ + struct btp_bap_broadcast_remote_source *broadcaster; + + LOG_DBG("sync state %d ", recv_state->pa_sync_state); + + broadcaster = remote_broadcaster_find(&recv_state->addr, recv_state->broadcast_id); + if (broadcaster == NULL) { + /* The Broadcast Assistant gave us the info about the Broadcaster, we have not + * scanned this Broadcaster before. The Broadcast Sink does not exist yet. + */ + + broadcaster = remote_broadcaster_alloc(); + if (broadcaster == NULL) { + LOG_ERR("Failed to allocate broadcast source"); + return -EINVAL; + } + + broadcaster->broadcast_id = recv_state->broadcast_id; + bt_addr_le_copy(&broadcaster->address, &recv_state->addr); + } + + broadcaster->sink_recv_state = recv_state; + + btp_send_pas_sync_req_ev(conn, recv_state->src_id, recv_state->adv_sid, + recv_state->broadcast_id, past_avail, pa_interval); + + return 0; +} + +static int pa_sync_term_req_cb(struct bt_conn *conn, + const struct bt_bap_scan_delegator_recv_state *recv_state) +{ + struct btp_bap_broadcast_remote_source *broadcaster; + + LOG_DBG(""); + + broadcaster = remote_broadcaster_find(&recv_state->addr, recv_state->broadcast_id); + if (broadcaster == NULL) { + LOG_ERR("Failed to find broadcaster"); + + return -EINVAL; + } + + broadcaster->sink_recv_state = recv_state; + + tester_gap_padv_stop_sync(); + + return 0; +} + +static void broadcast_code_cb(struct bt_conn *conn, + const struct bt_bap_scan_delegator_recv_state *recv_state, + const uint8_t broadcast_code[BT_AUDIO_BROADCAST_CODE_SIZE]) +{ + int err; + uint32_t index_bitfield; + struct btp_bap_broadcast_remote_source *broadcaster; + + LOG_DBG("Broadcast code received for %p", recv_state); + + broadcaster = remote_broadcaster_find(&recv_state->addr, recv_state->broadcast_id); + if (broadcaster == NULL) { + LOG_ERR("Failed to find broadcaster"); + + return; + } + + broadcaster->sink_recv_state = recv_state; + (void)memcpy(broadcaster->sink_broadcast_code, broadcast_code, + BT_AUDIO_BROADCAST_CODE_SIZE); + + if (!broadcaster->requested_bis_sync) { + return; + } + + index_bitfield = broadcaster->bis_index_bitfield & broadcaster->requested_bis_sync; + err = bt_bap_broadcast_sink_sync(broadcaster->sink, index_bitfield, + broadcaster->sink_streams, + broadcaster->sink_broadcast_code); + if (err != 0) { + LOG_DBG("Unable to sync to broadcast source: %d", err); + } +} + +static int bis_sync_req_cb(struct bt_conn *conn, + const struct bt_bap_scan_delegator_recv_state *recv_state, + const uint32_t bis_sync_req[BT_BAP_SCAN_DELEGATOR_MAX_SUBGROUPS]) +{ + struct btp_bap_broadcast_remote_source *broadcaster; + bool bis_synced = false; + + LOG_DBG("BIS sync request received for %p: 0x%08x", recv_state, bis_sync_req[0]); + + broadcaster = remote_broadcaster_find(&recv_state->addr, recv_state->broadcast_id); + if (broadcaster == NULL) { + LOG_ERR("Failed to find broadcaster"); + + return -EINVAL; + } + + broadcaster->requested_bis_sync = bis_sync_req[0]; + broadcaster->assistant_request = true; + + for (int i = 0; i < ARRAY_SIZE(broadcaster->streams); i++) { + if (broadcaster->streams[i].bis_synced) { + bis_synced = true; + break; + } + } + + /* We only care about a single subgroup in this sample */ + if (bis_synced) { + /* If the BIS sync request is received while we are already + * synced, it means that the requested BIS sync has changed. + */ + int err; + + /* The stream stopped callback will be called as part of this, + * and we do not need to wait for any events from the + * controller. Thus, when this returns, the `bis_synced` + * is back to false. + */ + err = bt_bap_broadcast_sink_stop(broadcaster->sink); + if (err != 0) { + LOG_DBG("Failed to stop Broadcast Sink: %d", err); + + return err; + } + } + + return 0; +} + +static void recv_state_updated_cb(struct bt_conn *conn, + const struct bt_bap_scan_delegator_recv_state *recv_state) +{ + LOG_DBG("Receive state with ID %u updated", recv_state->src_id); + + btp_send_broadcast_receive_state_ev(conn, recv_state); +} + +static struct bt_bap_scan_delegator_cb scan_delegator_cbs = { + .recv_state_updated = recv_state_updated_cb, + .pa_sync_req = pa_sync_req_cb, + .pa_sync_term_req = pa_sync_term_req_cb, + .broadcast_code = broadcast_code_cb, + .bis_sync_req = bis_sync_req_cb, +}; + +uint8_t btp_bap_broadcast_sink_setup(const void *cmd, uint16_t cmd_len, + void *rsp, uint16_t *rsp_len) +{ + int err; + + LOG_DBG(""); + + err = broadcast_sink_reset(); + if (err != 0) { + return BTP_STATUS_FAILED; + } + + /* For Scan Delegator role */ + bt_bap_scan_delegator_register_cb(&scan_delegator_cbs); + + /* For Broadcast Sink role */ + bt_bap_broadcast_sink_register_cb(&broadcast_sink_cbs); + bt_le_per_adv_sync_cb_register(&bap_pa_sync_cb); + + /* For Broadcast Sink or Broadcast Assistant role */ + bt_le_scan_cb_register(&bap_scan_cb); + + return BTP_STATUS_SUCCESS; +} + +uint8_t btp_bap_broadcast_sink_release(const void *cmd, uint16_t cmd_len, + void *rsp, uint16_t *rsp_len) +{ + int err; + + LOG_DBG(""); + + err = broadcast_sink_reset(); + + return BTP_STATUS_VAL(err); +} + +uint8_t btp_bap_broadcast_scan_start(const void *cmd, uint16_t cmd_len, + void *rsp, uint16_t *rsp_len) +{ + int err; + + LOG_DBG(""); + + err = bt_le_scan_start(BT_LE_SCAN_ACTIVE, NULL); + if (err != 0 && err != -EALREADY) { + LOG_DBG("Unable to start scan for broadcast sources: %d", err); + + return BTP_STATUS_FAILED; + } + + return BTP_STATUS_SUCCESS; +} + +uint8_t btp_bap_broadcast_scan_stop(const void *cmd, uint16_t cmd_len, + void *rsp, uint16_t *rsp_len) +{ + int err; + + LOG_DBG(""); + + err = bt_le_scan_stop(); + if (err != 0) { + LOG_DBG("Failed to stop scan, %d", err); + + return BTP_STATUS_FAILED; + } + + return BTP_STATUS_SUCCESS; +} + +uint8_t btp_bap_broadcast_sink_sync(const void *cmd, uint16_t cmd_len, + void *rsp, uint16_t *rsp_len) +{ + int err; + struct bt_conn *conn; + struct btp_bap_broadcast_remote_source *broadcaster; + const struct btp_bap_broadcast_sink_sync_cmd *cp = cmd; + struct bt_le_per_adv_sync_param create_params = {0}; + uint32_t broadcast_id = sys_get_le24(cp->broadcast_id); + + LOG_DBG(""); + + broadcaster = remote_broadcaster_find(&cp->address, broadcast_id); + if (broadcaster == NULL) { + broadcaster = remote_broadcaster_alloc(); + if (broadcaster == NULL) { + LOG_ERR("Failed to allocate broadcast source"); + return BTP_STATUS_FAILED; + } + + broadcaster->broadcast_id = broadcast_id; + bt_addr_le_copy(&broadcaster->address, &cp->address); + } + + broadcast_source_to_sync = broadcaster; + + if (IS_ENABLED(CONFIG_BT_PER_ADV_SYNC_TRANSFER_RECEIVER) && cp->past_avail) { + /* The Broadcast Assistant supports PAST transfer, and it has found + * a Broadcaster for us. Let's sync to the Broadcaster PA with the PAST. + */ + + conn = bt_conn_lookup_addr_le(BT_ID_DEFAULT, &cp->address); + if (!conn) { + broadcast_source_to_sync = NULL; + + return BTP_STATUS_FAILED; + } + + err = bt_bap_scan_delegator_set_pa_state(cp->src_id, BT_BAP_PA_STATE_INFO_REQ); + if (err != 0) { + LOG_DBG("Failed to set INFO_REQ state: %d", err); + } + + err = pa_sync_past(conn, cp->sync_timeout); + } else { + /* We scanned on our own or the Broadcast Assistant does not support PAST transfer. + * Let's sync to the Broadcaster PA without PAST. + */ + bt_addr_le_copy(&create_params.addr, &cp->address); + create_params.options = 0; + create_params.sid = cp->advertiser_sid; + create_params.skip = cp->skip; + create_params.timeout = cp->sync_timeout; + err = tester_gap_padv_create_sync(&create_params); + } + + if (err != 0) { + broadcast_source_to_sync = NULL; + + return BTP_STATUS_FAILED; + } + + return BTP_STATUS_SUCCESS; +} + +uint8_t btp_bap_broadcast_sink_stop(const void *cmd, uint16_t cmd_len, + void *rsp, uint16_t *rsp_len) +{ + int err; + struct btp_bap_broadcast_remote_source *broadcaster; + const struct btp_bap_broadcast_sink_stop_cmd *cp = cmd; + uint32_t broadcast_id = sys_get_le24(cp->broadcast_id); + + LOG_DBG(""); + + broadcaster = remote_broadcaster_find(&cp->address, broadcast_id); + if (broadcaster == NULL) { + LOG_ERR("Failed to find broadcaster"); + + return BTP_STATUS_FAILED; + } + + broadcaster->requested_bis_sync = 0; + + err = bt_bap_broadcast_sink_stop(broadcaster->sink); + if (err != 0) { + LOG_DBG("Unable to sync to broadcast source: %d", err); + + return BTP_STATUS_FAILED; + } + + err = tester_gap_padv_stop_sync(); + if (err != 0) { + LOG_DBG("Failed to stop PA sync, %d", err); + + return BTP_STATUS_FAILED; + } + + return BTP_STATUS_SUCCESS; +} + +uint8_t btp_bap_broadcast_sink_bis_sync(const void *cmd, uint16_t cmd_len, + void *rsp, uint16_t *rsp_len) +{ + int err; + struct btp_bap_broadcast_remote_source *broadcaster; + const struct btp_bap_broadcast_sink_bis_sync_cmd *cp = cmd; + + LOG_DBG(""); + + broadcaster = remote_broadcaster_find(&cp->address, sys_get_le24(cp->broadcast_id)); + if (broadcaster == NULL) { + LOG_ERR("Failed to find broadcaster"); + + return BTP_STATUS_FAILED; + } + + if (cp->requested_bis_sync == BT_BAP_BIS_SYNC_NO_PREF) { + broadcaster->requested_bis_sync = sys_le32_to_cpu(cp->requested_bis_sync); + } else { + /* For semantic purposes Zephyr API uses BIS Index bitfield + * where BIT(1) means BIS Index 1 + */ + broadcaster->requested_bis_sync = sys_le32_to_cpu(cp->requested_bis_sync) << 1; + } + + err = bt_bap_broadcast_sink_sync(broadcaster->sink, broadcaster->requested_bis_sync, + broadcaster->sink_streams, + broadcaster->sink_broadcast_code); + if (err != 0) { + LOG_DBG("Unable to sync to BISes, req_bis_sync %d, err %d", + broadcaster->requested_bis_sync, err); + + return BTP_STATUS_FAILED; + } + + return BTP_STATUS_SUCCESS; +} + +static void bap_broadcast_assistant_discover_cb(struct bt_conn *conn, int err, + uint8_t recv_state_count) +{ + LOG_DBG("err %d", err); + + if (err != 0) { + LOG_DBG("BASS discover failed (%d)", err); + } else { + LOG_DBG("BASS discover done with %u recv states", recv_state_count); + + btp_send_scan_delegator_found_ev(conn); + } +} + +static void bap_broadcast_assistant_scan_cb(const struct bt_le_scan_recv_info *info, + uint32_t broadcast_id) +{ + char le_addr[BT_ADDR_LE_STR_LEN]; + + bt_addr_le_to_str(info->addr, le_addr, sizeof(le_addr)); + LOG_DBG("[DEVICE]: %s, broadcast_id 0x%06X, interval (ms) %u), SID 0x%x, RSSI %i", le_addr, + broadcast_id, BT_GAP_PER_ADV_INTERVAL_TO_MS(info->interval), info->sid, info->rssi); +} + +static void bap_broadcast_assistant_recv_state_cb(struct bt_conn *conn, int err, + const struct bt_bap_scan_delegator_recv_state *state) +{ + LOG_DBG("err: %d", err); + + if (err != 0 || state == NULL) { + return; + } + + btp_send_broadcast_receive_state_ev(conn, state); +} + +static void bap_broadcast_assistant_recv_state_removed_cb(struct bt_conn *conn, int err, + uint8_t src_id) +{ + LOG_DBG("err: %d", err); +} + +static void bap_broadcast_assistant_scan_start_cb(struct bt_conn *conn, int err) +{ + LOG_DBG("err: %d", err); +} + +static void bap_broadcast_assistant_scan_stop_cb(struct bt_conn *conn, int err) +{ + LOG_DBG("err: %d", err); +} + +static void bap_broadcast_assistant_add_src_cb(struct bt_conn *conn, int err) +{ + LOG_DBG("err: %d", err); +} + +static void bap_broadcast_assistant_mod_src_cb(struct bt_conn *conn, int err) +{ + LOG_DBG("err: %d", err); +} + +static void bap_broadcast_assistant_broadcast_code_cb(struct bt_conn *conn, int err) +{ + LOG_DBG("err: %d", err); +} + +static void bap_broadcast_assistant_rem_src_cb(struct bt_conn *conn, int err) +{ + LOG_DBG("err: %d", err); +} + +static struct bt_bap_broadcast_assistant_cb broadcast_assistant_cb = { + .discover = bap_broadcast_assistant_discover_cb, + .scan = bap_broadcast_assistant_scan_cb, + .recv_state = bap_broadcast_assistant_recv_state_cb, + .recv_state_removed = bap_broadcast_assistant_recv_state_removed_cb, + .scan_start = bap_broadcast_assistant_scan_start_cb, + .scan_stop = bap_broadcast_assistant_scan_stop_cb, + .add_src = bap_broadcast_assistant_add_src_cb, + .mod_src = bap_broadcast_assistant_mod_src_cb, + .broadcast_code = bap_broadcast_assistant_broadcast_code_cb, + .rem_src = bap_broadcast_assistant_rem_src_cb, +}; + +uint8_t btp_bap_broadcast_discover_scan_delegators(const void *cmd, uint16_t cmd_len, + void *rsp, uint16_t *rsp_len) +{ + int err; + struct bt_conn *conn; + const struct btp_bap_discover_scan_delegators_cmd *cp = cmd; + + LOG_DBG(""); + + conn = bt_conn_lookup_addr_le(BT_ID_DEFAULT, &cp->address); + if (!conn) { + return BTP_STATUS_FAILED; + } + + err = bt_bap_broadcast_assistant_discover(conn); + + return BTP_STATUS_VAL(err); +} + +uint8_t btp_bap_broadcast_assistant_scan_start(const void *cmd, uint16_t cmd_len, + void *rsp, uint16_t *rsp_len) +{ + int err; + struct bt_conn *conn; + const struct btp_bap_broadcast_assistant_scan_start_cmd *cp = cmd; + + LOG_DBG(""); + + conn = bt_conn_lookup_addr_le(BT_ID_DEFAULT, &cp->address); + if (!conn) { + return BTP_STATUS_FAILED; + } + + err = bt_bap_broadcast_assistant_scan_start(conn, true); + + return BTP_STATUS_VAL(err); +} + +uint8_t btp_bap_broadcast_assistant_scan_stop(const void *cmd, uint16_t cmd_len, + void *rsp, uint16_t *rsp_len) +{ + int err; + struct bt_conn *conn; + const struct btp_bap_broadcast_assistant_scan_stop_cmd *cp = cmd; + + LOG_DBG(""); + + conn = bt_conn_lookup_addr_le(BT_ID_DEFAULT, &cp->address); + if (!conn) { + return BTP_STATUS_FAILED; + } + + err = bt_bap_broadcast_assistant_scan_stop(conn); + + return BTP_STATUS_VAL(err); +} + +uint8_t btp_bap_broadcast_assistant_add_src(const void *cmd, uint16_t cmd_len, + void *rsp, uint16_t *rsp_len) +{ + int err; + const uint8_t *ptr; + struct bt_conn *conn; + const struct btp_bap_add_broadcast_src_cmd *cp = cmd; + struct bt_bap_broadcast_assistant_add_src_param param = { 0 }; + + LOG_DBG(""); + + conn = bt_conn_lookup_addr_le(BT_ID_DEFAULT, &cp->address); + if (!conn) { + return BTP_STATUS_FAILED; + } + + memset(delegator_subgroups, 0, sizeof(delegator_subgroups)); + bt_addr_le_copy(¶m.addr, &cp->broadcaster_address); + param.adv_sid = cp->advertiser_sid; + param.pa_sync = cp->padv_sync > 0 ? true : false; + param.broadcast_id = sys_get_le24(cp->broadcast_id); + param.pa_interval = sys_le16_to_cpu(cp->padv_interval); + param.num_subgroups = MIN(cp->num_subgroups, BT_BAP_SCAN_DELEGATOR_MAX_SUBGROUPS); + param.subgroups = delegator_subgroups; + + ptr = cp->subgroups; + for (uint8_t i = 0; i < param.num_subgroups; i++) { + struct bt_bap_scan_delegator_subgroup *subgroup = &delegator_subgroups[i]; + + subgroup->bis_sync = sys_get_le32(ptr); + if (subgroup->bis_sync != BT_BAP_BIS_SYNC_NO_PREF) { + /* For semantic purposes Zephyr API uses BIS Index bitfield + * where BIT(1) means BIS Index 1 + */ + subgroup->bis_sync <<= 1; + } + + ptr += sizeof(subgroup->bis_sync); + subgroup->metadata_len = *ptr; + ptr += sizeof(subgroup->metadata_len); + memcpy(subgroup->metadata, ptr, subgroup->metadata_len); + ptr += subgroup->metadata_len; + } + + err = bt_bap_broadcast_assistant_add_src(conn, ¶m); + if (err != 0) { + LOG_DBG("err %d", err); + + return BTP_STATUS_FAILED; + } + + return BTP_STATUS_SUCCESS; +} + +uint8_t btp_bap_broadcast_assistant_remove_src(const void *cmd, uint16_t cmd_len, + void *rsp, uint16_t *rsp_len) +{ + int err; + struct bt_conn *conn; + const struct btp_bap_remove_broadcast_src_cmd *cp = cmd; + + LOG_DBG(""); + + conn = bt_conn_lookup_addr_le(BT_ID_DEFAULT, &cp->address); + if (!conn) { + return BTP_STATUS_FAILED; + } + + err = bt_bap_broadcast_assistant_rem_src(conn, cp->src_id); + + return BTP_STATUS_VAL(err); +} + +uint8_t btp_bap_broadcast_assistant_modify_src(const void *cmd, uint16_t cmd_len, + void *rsp, uint16_t *rsp_len) +{ + int err; + const uint8_t *ptr; + struct bt_conn *conn; + const struct btp_bap_modify_broadcast_src_cmd *cp = cmd; + struct bt_bap_broadcast_assistant_mod_src_param param = { 0 }; + + LOG_DBG(""); + + conn = bt_conn_lookup_addr_le(BT_ID_DEFAULT, &cp->address); + if (!conn) { + return BTP_STATUS_FAILED; + } + + memset(delegator_subgroups, 0, sizeof(delegator_subgroups)); + param.src_id = cp->src_id; + param.pa_sync = cp->padv_sync > 0 ? true : false; + param.pa_interval = sys_le16_to_cpu(cp->padv_interval); + param.num_subgroups = MIN(cp->num_subgroups, BT_BAP_SCAN_DELEGATOR_MAX_SUBGROUPS); + param.subgroups = delegator_subgroups; + + ptr = cp->subgroups; + for (uint8_t i = 0; i < param.num_subgroups; i++) { + struct bt_bap_scan_delegator_subgroup *subgroup = &delegator_subgroups[i]; + + subgroup->bis_sync = sys_get_le32(ptr); + if (subgroup->bis_sync != BT_BAP_BIS_SYNC_NO_PREF) { + /* For semantic purposes Zephyr API uses BIS Index bitfield + * where BIT(1) means BIS Index 1 + */ + subgroup->bis_sync <<= 1; + } + + ptr += sizeof(subgroup->bis_sync); + subgroup->metadata_len = *ptr; + ptr += sizeof(subgroup->metadata_len); + memcpy(subgroup->metadata, ptr, subgroup->metadata_len); + ptr += subgroup->metadata_len; + } + + err = bt_bap_broadcast_assistant_mod_src(conn, ¶m); + + return BTP_STATUS_VAL(err); +} + +uint8_t btp_bap_broadcast_assistant_set_broadcast_code(const void *cmd, uint16_t cmd_len, + void *rsp, uint16_t *rsp_len) +{ + int err; + struct bt_conn *conn; + const struct btp_bap_set_broadcast_code_cmd *cp = cmd; + + LOG_DBG(""); + + conn = bt_conn_lookup_addr_le(BT_ID_DEFAULT, &cp->address); + if (!conn) { + return BTP_STATUS_FAILED; + } + + err = bt_bap_broadcast_assistant_set_broadcast_code(conn, cp->src_id, cp->broadcast_code); + if (err != 0) { + LOG_DBG("err %d", err); + return BTP_STATUS_FAILED; + } + + return BTP_STATUS_SUCCESS; +} + +uint8_t btp_bap_broadcast_assistant_send_past(const void *cmd, uint16_t cmd_len, + void *rsp, uint16_t *rsp_len) +{ + int err; + uint16_t service_data; + struct bt_conn *conn; + struct bt_le_per_adv_sync *pa_sync; + const struct btp_bap_send_past_cmd *cp = cmd; + + LOG_DBG(""); + + conn = bt_conn_lookup_addr_le(BT_ID_DEFAULT, &cp->address); + if (!conn) { + return BTP_STATUS_FAILED; + } + + pa_sync = tester_gap_padv_get(); + if (!pa_sync) { + LOG_DBG("Could not send PAST to Scan Delegator"); + + return BTP_STATUS_FAILED; + } + + LOG_DBG("Sending PAST"); + + /* If octet 0 is set to 0, it means AdvA in PAST matches AdvA in ADV_EXT_IND. + * Octet 1 shall be set to Source_ID. + */ + service_data = cp->src_id << 8; + + err = bt_le_per_adv_sync_transfer(pa_sync, conn, service_data); + if (err != 0) { + LOG_DBG("Could not transfer periodic adv sync: %d", err); + + return BTP_STATUS_FAILED; + } + + return BTP_STATUS_SUCCESS; +} + +static bool broadcast_inited; + +int btp_bap_broadcast_init(void) +{ + if (broadcast_inited) { + return 0; + } + + broadcast_sink_reset(); + + /* For Broadcast Assistant role */ + bt_bap_broadcast_assistant_register_cb(&broadcast_assistant_cb); + + broadcast_inited = true; + + return 0; +} diff --git a/tests/bluetooth/tester/src/btp_bap_broadcast.h b/tests/bluetooth/tester/src/btp_bap_broadcast.h new file mode 100644 index 00000000000..cbecb446b3a --- /dev/null +++ b/tests/bluetooth/tester/src/btp_bap_broadcast.h @@ -0,0 +1,100 @@ +/* btp_bap_broadcast.h - Bluetooth BAP Tester */ + +/* + * Copyright (c) 2023 Codecoup + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include + +struct btp_bap_broadcast_stream { + struct btp_bap_audio_stream audio_stream; + struct bt_audio_codec_cfg codec_cfg; + uint8_t bis_id; + uint8_t subgroup_id; + bool bis_synced; + uint8_t source_id; + bool in_use; + bool already_sent; +}; + +/* According to BT spec, a Broadcast Source can configure and establish one or more BIGs, + * each containing one or more BISes that are used to transport broadcast Audio Streams. + * For each BIG, the Broadcast Source shall generate a Broadcast_ID. + * For the time being, let's treat broadcast source as one BIG. + */ +struct btp_bap_broadcast_remote_source { + bt_addr_le_t address; + uint32_t broadcast_id; + struct btp_bap_broadcast_stream streams[CONFIG_BT_BAP_BROADCAST_SNK_STREAM_COUNT]; + struct bt_bap_stream *sink_streams[CONFIG_BT_BAP_BROADCAST_SNK_STREAM_COUNT]; + struct bt_bap_broadcast_sink *sink; + struct bt_audio_codec_qos qos; + /* BIS Index bitfield read from Base */ + uint32_t bis_index_bitfield; + /* BIS Index bitfield read from sync request */ + uint32_t requested_bis_sync; + bool assistant_request; + uint8_t sink_broadcast_code[BT_AUDIO_BROADCAST_CODE_SIZE]; + const struct bt_bap_scan_delegator_recv_state *sink_recv_state; +}; + +struct btp_bap_broadcast_local_source { + uint32_t broadcast_id; + struct bt_audio_codec_qos qos; + struct btp_bap_broadcast_stream streams[CONFIG_BT_BAP_BROADCAST_SRC_STREAM_COUNT]; + struct bt_audio_codec_cfg subgroup_codec_cfg[CONFIG_BT_BAP_BROADCAST_SRC_SUBGROUP_COUNT]; + /* Only for BTP BAP commands */ + struct bt_bap_broadcast_source *bap_broadcast; + /* Only for BTP CAP commands */ + struct bt_cap_broadcast_source *cap_broadcast; +}; + +int btp_bap_broadcast_init(void); +struct btp_bap_broadcast_local_source *btp_bap_broadcast_local_source_get(uint8_t source_id); +struct btp_bap_broadcast_stream *btp_bap_broadcast_stream_alloc( + struct btp_bap_broadcast_local_source *source); + +uint8_t btp_bap_broadcast_source_setup(const void *cmd, uint16_t cmd_len, + void *rsp, uint16_t *rsp_len); +uint8_t btp_bap_broadcast_source_release(const void *cmd, uint16_t cmd_len, + void *rsp, uint16_t *rsp_len); +uint8_t btp_bap_broadcast_adv_start(const void *cmd, uint16_t cmd_len, + void *rsp, uint16_t *rsp_len); +uint8_t btp_bap_broadcast_adv_stop(const void *cmd, uint16_t cmd_len, + void *rsp, uint16_t *rsp_len); +uint8_t btp_bap_broadcast_source_start(const void *cmd, uint16_t cmd_len, + void *rsp, uint16_t *rsp_len); +uint8_t btp_bap_broadcast_source_stop(const void *cmd, uint16_t cmd_len, + void *rsp, uint16_t *rsp_len); +uint8_t btp_bap_broadcast_sink_setup(const void *cmd, uint16_t cmd_len, + void *rsp, uint16_t *rsp_len); +uint8_t btp_bap_broadcast_sink_release(const void *cmd, uint16_t cmd_len, + void *rsp, uint16_t *rsp_len); +uint8_t btp_bap_broadcast_scan_start(const void *cmd, uint16_t cmd_len, + void *rsp, uint16_t *rsp_len); +uint8_t btp_bap_broadcast_scan_stop(const void *cmd, uint16_t cmd_len, + void *rsp, uint16_t *rsp_len); +uint8_t btp_bap_broadcast_sink_sync(const void *cmd, uint16_t cmd_len, + void *rsp, uint16_t *rsp_len); +uint8_t btp_bap_broadcast_sink_stop(const void *cmd, uint16_t cmd_len, + void *rsp, uint16_t *rsp_len); +uint8_t btp_bap_broadcast_sink_bis_sync(const void *cmd, uint16_t cmd_len, + void *rsp, uint16_t *rsp_len); +uint8_t btp_bap_broadcast_discover_scan_delegators(const void *cmd, uint16_t cmd_len, + void *rsp, uint16_t *rsp_len); +uint8_t btp_bap_broadcast_assistant_scan_start(const void *cmd, uint16_t cmd_len, + void *rsp, uint16_t *rsp_len); +uint8_t btp_bap_broadcast_assistant_scan_stop(const void *cmd, uint16_t cmd_len, + void *rsp, uint16_t *rsp_len); +uint8_t btp_bap_broadcast_assistant_add_src(const void *cmd, uint16_t cmd_len, + void *rsp, uint16_t *rsp_len); +uint8_t btp_bap_broadcast_assistant_remove_src(const void *cmd, uint16_t cmd_len, + void *rsp, uint16_t *rsp_len); +uint8_t btp_bap_broadcast_assistant_modify_src(const void *cmd, uint16_t cmd_len, + void *rsp, uint16_t *rsp_len); +uint8_t btp_bap_broadcast_assistant_set_broadcast_code(const void *cmd, uint16_t cmd_len, + void *rsp, uint16_t *rsp_len); +uint8_t btp_bap_broadcast_assistant_send_past(const void *cmd, uint16_t cmd_len, + void *rsp, uint16_t *rsp_len); diff --git a/tests/bluetooth/tester/src/btp_bap_unicast.c b/tests/bluetooth/tester/src/btp_bap_unicast.c new file mode 100644 index 00000000000..725ee3cf071 --- /dev/null +++ b/tests/bluetooth/tester/src/btp_bap_unicast.c @@ -0,0 +1,1649 @@ +/* btp_bap_unicast.c - Bluetooth BAP Tester */ + +/* + * Copyright (c) 2023 Codecoup + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include +#include + +#include +#include +#include +#include +#include + +#include "bap_endpoint.h" +#include +#include +#define LOG_MODULE_NAME bttester_bap_unicast +LOG_MODULE_REGISTER(LOG_MODULE_NAME, CONFIG_BTTESTER_LOG_LEVEL); +#include "btp/btp.h" +#include "btp_bap_audio_stream.h" +#include "btp_bap_unicast.h" + +static struct bt_audio_codec_qos_pref qos_pref = + BT_AUDIO_CODEC_QOS_PREF(true, BT_GAP_LE_PHY_2M, 0x02, 10, 10000, 40000, 10000, 40000); + +static struct btp_bap_unicast_connection connections[CONFIG_BT_MAX_CONN]; +static struct btp_bap_unicast_group cigs[CONFIG_BT_ISO_MAX_CIG]; + +static inline struct btp_bap_unicast_stream *stream_bap_to_unicast(struct bt_bap_stream *stream) +{ + return CONTAINER_OF(CONTAINER_OF(CONTAINER_OF(stream, struct bt_cap_stream, bap_stream), + struct btp_bap_audio_stream, cap_stream), + struct btp_bap_unicast_stream, audio_stream); +} + +static inline struct bt_bap_stream *stream_unicast_to_bap(struct btp_bap_unicast_stream *stream) +{ + return &stream->audio_stream.cap_stream.bap_stream; +} + +static bool print_cb(struct bt_data *data, void *user_data) +{ + const char *str = (const char *)user_data; + + LOG_DBG("%s: type 0x%02x value_len %u", str, data->type, data->data_len); + LOG_HEXDUMP_DBG(data->data, data->data_len, ""); + + return true; +} + +static void print_codec_cfg(const struct bt_audio_codec_cfg *codec_cfg) +{ + LOG_DBG("codec_cfg 0x%02x cid 0x%04x vid 0x%04x count %u", codec_cfg->id, codec_cfg->cid, + codec_cfg->vid, codec_cfg->data_len); + + if (codec_cfg->id == BT_HCI_CODING_FORMAT_LC3) { + enum bt_audio_location chan_allocation; + int ret; + + /* LC3 uses the generic LTV format - other codecs might do as well */ + + bt_audio_data_parse(codec_cfg->data, codec_cfg->data_len, print_cb, "data"); + + ret = bt_audio_codec_cfg_get_freq(codec_cfg); + if (ret > 0) { + LOG_DBG(" Frequency: %d Hz", bt_audio_codec_cfg_freq_to_freq_hz(ret)); + } + + ret = bt_audio_codec_cfg_get_frame_dur(codec_cfg); + if (ret > 0) { + LOG_DBG(" Frame Duration: %d us", + bt_audio_codec_cfg_frame_dur_to_frame_dur_us(ret)); + } + + if (bt_audio_codec_cfg_get_chan_allocation(codec_cfg, &chan_allocation) == 0) { + LOG_DBG(" Channel allocation: 0x%x", chan_allocation); + } + + LOG_DBG(" Octets per frame: %d (negative means value not pressent)", + bt_audio_codec_cfg_get_octets_per_frame(codec_cfg)); + LOG_DBG(" Frames per SDU: %d", + bt_audio_codec_cfg_get_frame_blocks_per_sdu(codec_cfg, true)); + } else { + LOG_HEXDUMP_DBG(codec_cfg->data, codec_cfg->data_len, "data"); + } + + bt_audio_data_parse(codec_cfg->meta, codec_cfg->meta_len, print_cb, "meta"); +} + +static void print_codec_cap(const struct bt_audio_codec_cap *codec_cap) +{ + LOG_DBG("codec_cap 0x%02x cid 0x%04x vid 0x%04x count %zu", codec_cap->id, codec_cap->cid, + codec_cap->vid, codec_cap->data_len); + + if (codec_cap->id == BT_HCI_CODING_FORMAT_LC3) { + bt_audio_data_parse(codec_cap->data, codec_cap->data_len, print_cb, "data"); + } else { + LOG_HEXDUMP_DBG(codec_cap->data, codec_cap->data_len, "data"); + } + + bt_audio_data_parse(codec_cap->meta, codec_cap->meta_len, print_cb, "meta"); +} + +void btp_bap_unicast_stream_free(struct btp_bap_unicast_stream *stream) +{ + (void)memset(stream, 0, sizeof(*stream)); +} + +struct btp_bap_unicast_stream *btp_bap_unicast_stream_find( + struct btp_bap_unicast_connection *conn, uint8_t ase_id) +{ + for (size_t i = 0; i < ARRAY_SIZE(conn->streams); i++) { + struct bt_bap_stream *stream = stream_unicast_to_bap(&conn->streams[i]); + struct bt_bap_ep_info info; + + if (stream->ep == NULL) { + continue; + } + + (void)bt_bap_ep_get_info(stream->ep, &info); + if (info.id == ase_id) { + return &conn->streams[i]; + } + } + + return NULL; +} + +struct bt_bap_ep *btp_bap_unicast_end_point_find(struct btp_bap_unicast_connection *conn, + uint8_t ase_id) +{ + for (size_t i = 0; i < ARRAY_SIZE(conn->end_points); i++) { + struct bt_bap_ep_info info; + struct bt_bap_ep *ep = conn->end_points[i]; + + if (ep == NULL) { + continue; + } + + (void)bt_bap_ep_get_info(ep, &info); + if (info.id == ase_id) { + return ep; + } + } + + return NULL; +} + +static void btp_send_ascs_ase_state_changed_ev(struct bt_conn *conn, uint8_t ase_id, uint8_t state) +{ + struct btp_ascs_ase_state_changed_ev ev; + + bt_addr_le_copy(&ev.address, bt_conn_get_dst(conn)); + ev.ase_id = ase_id; + ev.state = state; + + tester_event(BTP_SERVICE_ID_ASCS, BTP_ASCS_EV_ASE_STATE_CHANGED, &ev, sizeof(ev)); +} + +static void btp_send_ascs_operation_completed_ev(struct bt_conn *conn, uint8_t ase_id, + uint8_t opcode, uint8_t status) +{ + struct btp_ascs_operation_completed_ev ev; + + bt_addr_le_copy(&ev.address, bt_conn_get_dst(conn)); + ev.ase_id = ase_id; + ev.opcode = opcode; + ev.status = status; + ev.flags = 0; + + tester_event(BTP_SERVICE_ID_ASCS, BTP_ASCS_EV_OPERATION_COMPLETED, &ev, sizeof(ev)); +} + +struct search_type_param { + uint8_t type; + const uint8_t *data; +}; + +static bool data_type_search_cb(struct bt_data *data, void *user_data) +{ + struct search_type_param *param = (struct search_type_param *)user_data; + + if (param->type == data->type) { + param->data = data->data; + + return false; + } + + return true; +} + +static bool codec_cap_get_val(const struct bt_audio_codec_cap *codec_cap, uint8_t type, + const uint8_t **data) +{ + struct search_type_param param = { + .type = type, + .data = NULL, + }; + int err; + + err = bt_audio_data_parse(codec_cap->data, codec_cap->data_len, data_type_search_cb, + ¶m); + if (err != 0 && err != -ECANCELED) { + LOG_DBG("Could not parse the data: %d", err); + + return false; + } + + if (param.data == NULL) { + LOG_DBG("Could not find the type %u", type); + + return false; + } + + *data = param.data; + + return true; +} + +static void btp_send_pac_codec_found_ev(struct bt_conn *conn, + const struct bt_audio_codec_cap *codec_cap, + enum bt_audio_dir dir) +{ + struct btp_bap_codec_cap_found_ev ev; + const uint8_t *data; + + bt_addr_le_copy(&ev.address, bt_conn_get_dst(conn)); + + ev.dir = dir; + ev.coding_format = codec_cap->id; + + if (codec_cap_get_val(codec_cap, BT_AUDIO_CODEC_LC3_FREQ, &data)) { + memcpy(&ev.frequencies, data, sizeof(ev.frequencies)); + } + + if (codec_cap_get_val(codec_cap, BT_AUDIO_CODEC_LC3_DURATION, &data)) { + memcpy(&ev.frame_durations, data, sizeof(ev.frame_durations)); + } + + if (codec_cap_get_val(codec_cap, BT_AUDIO_CODEC_LC3_FRAME_LEN, &data)) { + memcpy(&ev.octets_per_frame, data, sizeof(ev.octets_per_frame)); + } + + if (codec_cap_get_val(codec_cap, BT_AUDIO_CODEC_LC3_CHAN_COUNT, &data)) { + memcpy(&ev.channel_counts, data, sizeof(ev.channel_counts)); + } + + tester_event(BTP_SERVICE_ID_BAP, BTP_BAP_EV_CODEC_CAP_FOUND, &ev, sizeof(ev)); +} + +static void btp_send_ase_found_ev(struct bt_conn *conn, struct bt_bap_ep *ep) +{ + struct bt_bap_ep_info info; + struct btp_ascs_ase_found_ev ev; + + bt_addr_le_copy(&ev.address, bt_conn_get_dst(conn)); + + (void)bt_bap_ep_get_info(ep, &info); + ev.ase_id = info.id; + ev.dir = info.dir; + + tester_event(BTP_SERVICE_ID_BAP, BTP_BAP_EV_ASE_FOUND, &ev, sizeof(ev)); +} + +static inline void print_qos(const struct bt_audio_codec_qos *qos) +{ + LOG_DBG("QoS: interval %u framing 0x%02x phy 0x%02x sdu %u rtn %u latency %u pd %u", + qos->interval, qos->framing, qos->phy, qos->sdu, qos->rtn, qos->latency, qos->pd); +} + +static int validate_codec_parameters(const struct bt_audio_codec_cfg *codec_cfg) +{ + int frames_per_sdu; + int octets_per_frame; + int chan_allocation_err; + enum bt_audio_location chan_allocation; + int ret; + + chan_allocation_err = + bt_audio_codec_cfg_get_chan_allocation(codec_cfg, &chan_allocation); + octets_per_frame = bt_audio_codec_cfg_get_octets_per_frame(codec_cfg); + frames_per_sdu = bt_audio_codec_cfg_get_frame_blocks_per_sdu(codec_cfg, true); + + ret = bt_audio_codec_cfg_get_freq(codec_cfg); + if (ret < 0) { + LOG_DBG("Error: Invalid codec frequency: %d", ret); + return -EINVAL; + } + + ret = bt_audio_codec_cfg_get_frame_dur(codec_cfg); + if (ret < 0) { + LOG_DBG("Error: Invalid frame duration: %d", ret); + return -EINVAL; + } + + if (octets_per_frame < 0) { + LOG_DBG("Error: Invalid octets per frame."); + return -EINVAL; + } + + if (frames_per_sdu < 0) { + /* The absence of the Codec_Frame_Blocks_Per_SDU LTV structure shall be + * interpreted as equivalent to a Codec_Frame_Blocks_Per_SDU value of 0x01 + */ + LOG_DBG("Codec_Frame_Blocks_Per_SDU LTV structure not defined."); + } + + if (chan_allocation_err < 0) { + /* The absence of the Audio_Channel_Allocation LTV structure shall be + * interpreted as a single channel with no specified Audio Location. + */ + LOG_DBG("Audio_Channel_Allocation LTV structure not defined."); + } + + return 0; +} + +static int lc3_config(struct bt_conn *conn, const struct bt_bap_ep *ep, enum bt_audio_dir dir, + const struct bt_audio_codec_cfg *codec_cfg, struct bt_bap_stream **stream, + struct bt_audio_codec_qos_pref *const pref, struct bt_bap_ascs_rsp *rsp) +{ + struct bt_bap_ep_info info; + struct btp_bap_unicast_connection *u_conn; + struct btp_bap_unicast_stream *u_stream; + + LOG_DBG("ASE Codec Config: ep %p dir %u", ep, dir); + + print_codec_cfg(codec_cfg); + (void)bt_bap_ep_get_info(ep, &info); + + if (validate_codec_parameters(codec_cfg)) { + *rsp = BT_BAP_ASCS_RSP(BT_BAP_ASCS_RSP_CODE_CONF_REJECTED, + BT_BAP_ASCS_REASON_CODEC_DATA); + + btp_send_ascs_operation_completed_ev(conn, info.id, BT_ASCS_CONFIG_OP, + BTP_ASCS_STATUS_FAILED); + + return -ENOTSUP; + } + + u_conn = &connections[bt_conn_index(conn)]; + u_stream = btp_bap_unicast_stream_alloc(u_conn); + if (u_stream == NULL) { + LOG_DBG("No free stream available"); + *rsp = BT_BAP_ASCS_RSP(BT_BAP_ASCS_RSP_CODE_NO_MEM, BT_BAP_ASCS_REASON_NONE); + + btp_send_ascs_operation_completed_ev(conn, info.id, BT_ASCS_CONFIG_OP, + BTP_ASCS_STATUS_FAILED); + + return -ENOMEM; + } + + *stream = stream_unicast_to_bap(u_stream); + LOG_DBG("ASE Codec Config stream %p", *stream); + + if (dir == BT_AUDIO_DIR_SOURCE) { + u_conn->configured_source_stream_count++; + } else { + u_conn->configured_sink_stream_count++; + } + + *pref = qos_pref; + + return 0; +} + +static int lc3_reconfig(struct bt_bap_stream *stream, enum bt_audio_dir dir, + const struct bt_audio_codec_cfg *codec_cfg, + struct bt_audio_codec_qos_pref *const pref, struct bt_bap_ascs_rsp *rsp) +{ + LOG_DBG("ASE Codec Reconfig: stream %p", stream); + + print_codec_cfg(codec_cfg); + + return 0; +} + +static int lc3_qos(struct bt_bap_stream *stream, const struct bt_audio_codec_qos *qos, + struct bt_bap_ascs_rsp *rsp) +{ + LOG_DBG("QoS: stream %p qos %p", stream, qos); + + print_qos(qos); + + return 0; +} + +static bool valid_metadata_type(uint8_t type, uint8_t len, const uint8_t *data) +{ + /* PTS checks if we are able to reject unsupported metadata type or RFU vale. + * The only RFU value PTS seems to check for now is the streaming context. + */ + if (!BT_AUDIO_METADATA_TYPE_IS_KNOWN(type)) { + return false; + } + + if (type == BT_AUDIO_METADATA_TYPE_PREF_CONTEXT || + type == BT_AUDIO_METADATA_TYPE_STREAM_CONTEXT) { + /* PTS wants us to reject the parameter if reserved bits are set */ + if ((sys_get_le16(data) & ~(uint16_t)(BT_AUDIO_CONTEXT_TYPE_ANY)) > 0) { + return false; + } + } + + return true; +} + +static bool data_func_cb(struct bt_data *data, void *user_data) +{ + struct bt_bap_ascs_rsp *rsp = (struct bt_bap_ascs_rsp *)user_data; + + if (!valid_metadata_type(data->type, data->data_len, data->data)) { + LOG_DBG("Invalid metadata type %u or length %u", data->type, data->data_len); + *rsp = BT_BAP_ASCS_RSP(BT_BAP_ASCS_RSP_CODE_METADATA_REJECTED, data->type); + return false; + } + + return true; +} + +static int lc3_enable(struct bt_bap_stream *stream, const uint8_t meta[], size_t meta_len, + struct bt_bap_ascs_rsp *rsp) +{ + int err; + struct bt_bap_ep_info info; + + LOG_DBG("Metadata: stream %p meta_len %zu", stream, meta_len); + + err = bt_audio_data_parse(meta, meta_len, data_func_cb, rsp); + if (err != 0) { + (void)bt_bap_ep_get_info(stream->ep, &info); + btp_send_ascs_operation_completed_ev(stream->conn, info.id, + BT_ASCS_ENABLE_OP, BTP_ASCS_STATUS_FAILED); + } + + return err; +} + +static int lc3_start(struct bt_bap_stream *stream, struct bt_bap_ascs_rsp *rsp) +{ + LOG_DBG("Start: stream %p", stream); + + return 0; +} + +static int lc3_metadata(struct bt_bap_stream *stream, const uint8_t meta[], size_t meta_len, + struct bt_bap_ascs_rsp *rsp) +{ + int err; + struct bt_bap_ep_info info; + + LOG_DBG("Metadata: stream %p meta_count %zu", stream, meta_len); + + err = bt_audio_data_parse(meta, meta_len, data_func_cb, rsp); + if (err != 0) { + (void)bt_bap_ep_get_info(stream->ep, &info); + btp_send_ascs_operation_completed_ev(stream->conn, info.id, + BT_ASCS_METADATA_OP, BTP_ASCS_STATUS_FAILED); + } + + return err; +} + +static int lc3_disable(struct bt_bap_stream *stream, struct bt_bap_ascs_rsp *rsp) +{ + LOG_DBG("Disable: stream %p", stream); + + return 0; +} + +static int lc3_stop(struct bt_bap_stream *stream, struct bt_bap_ascs_rsp *rsp) +{ + LOG_DBG("Stop: stream %p", stream); + + return 0; +} + +static int lc3_release(struct bt_bap_stream *stream, struct bt_bap_ascs_rsp *rsp) +{ + LOG_DBG("Release: stream %p", stream); + + return 0; +} + +static const struct bt_bap_unicast_server_cb unicast_server_cb = { + .config = lc3_config, + .reconfig = lc3_reconfig, + .qos = lc3_qos, + .enable = lc3_enable, + .start = lc3_start, + .metadata = lc3_metadata, + .disable = lc3_disable, + .stop = lc3_stop, + .release = lc3_release, +}; + +static void stream_configured(struct bt_bap_stream *stream, + const struct bt_audio_codec_qos_pref *pref) +{ + struct bt_bap_ep_info info; + struct btp_bap_unicast_connection *u_conn; + struct btp_bap_unicast_stream *u_stream = stream_bap_to_unicast(stream); + + (void)bt_bap_ep_get_info(stream->ep, &info); + LOG_DBG("Configured stream %p, ep %u, dir %u", stream, info.id, info.dir); + + u_stream->conn_id = bt_conn_index(stream->conn); + u_conn = &connections[u_stream->conn_id]; + u_stream->ase_id = info.id; + + btp_send_ascs_operation_completed_ev(stream->conn, u_stream->ase_id, + BT_ASCS_CONFIG_OP, BTP_ASCS_STATUS_SUCCESS); +} + +static void stream_qos_set(struct bt_bap_stream *stream) +{ + struct btp_bap_unicast_stream *u_stream = stream_bap_to_unicast(stream); + + LOG_DBG("QoS set stream %p", stream); + btp_send_ascs_operation_completed_ev(stream->conn, u_stream->ase_id, + BT_ASCS_QOS_OP, BTP_ASCS_STATUS_SUCCESS); +} + +static void stream_enabled(struct bt_bap_stream *stream) +{ + struct btp_bap_unicast_stream *u_stream = stream_bap_to_unicast(stream); + struct bt_bap_ep_info info; + struct bt_conn_info conn_info; + int err; + + LOG_DBG("Enabled stream %p", stream); + + (void)bt_bap_ep_get_info(stream->ep, &info); + (void)bt_conn_get_info(stream->conn, &conn_info); + if (conn_info.role == BT_HCI_ROLE_PERIPHERAL && info.dir == BT_AUDIO_DIR_SINK) { + /* Automatically do the receiver start ready operation */ + err = bt_bap_stream_start(stream); + if (err != 0) { + LOG_DBG("Failed to start stream %p", stream); + btp_send_ascs_operation_completed_ev(stream->conn, u_stream->ase_id, + BT_ASCS_ENABLE_OP, + BTP_ASCS_STATUS_FAILED); + + return; + } + } + + btp_send_ascs_operation_completed_ev(stream->conn, u_stream->ase_id, + BT_ASCS_ENABLE_OP, BTP_ASCS_STATUS_SUCCESS); +} + +static void stream_metadata_updated(struct bt_bap_stream *stream) +{ + struct btp_bap_unicast_stream *u_stream = stream_bap_to_unicast(stream); + + LOG_DBG("Metadata updated stream %p", stream); + btp_send_ascs_operation_completed_ev(stream->conn, u_stream->ase_id, + BT_ASCS_METADATA_OP, BTP_ASCS_STATUS_SUCCESS); +} + +static void stream_disabled(struct bt_bap_stream *stream) +{ + struct btp_bap_unicast_stream *u_stream = stream_bap_to_unicast(stream); + + LOG_DBG("Disabled stream %p", stream); + + /* Stop send timer */ + btp_bap_audio_stream_stopped(&u_stream->audio_stream); + + btp_send_ascs_operation_completed_ev(stream->conn, u_stream->ase_id, + BT_ASCS_DISABLE_OP, BTP_ASCS_STATUS_SUCCESS); +} + +static void stream_released(struct bt_bap_stream *stream) +{ + uint8_t cig_id; + struct bt_bap_ep_info info; + struct btp_bap_unicast_connection *u_conn; + struct btp_bap_unicast_stream *u_stream = stream_bap_to_unicast(stream); + + LOG_DBG("Released stream %p", stream); + + u_conn = &connections[u_stream->conn_id]; + + /* Stop send timer */ + btp_bap_audio_stream_stopped(&u_stream->audio_stream); + + if (stream->ep != NULL) { + (void)bt_bap_ep_get_info(stream->ep, &info); + if (info.dir == BT_AUDIO_DIR_SINK) { + u_conn->configured_sink_stream_count--; + } else { + u_conn->configured_source_stream_count--; + } + } + + cig_id = u_stream->cig_id; + btp_bap_unicast_stream_free(u_stream); + + if (cigs[cig_id].in_use == true && + u_conn->configured_sink_stream_count == 0 && + u_conn->configured_source_stream_count == 0) { + struct btp_bap_unicast_group *u_cig = &cigs[cig_id]; + + /* The unicast group will be deleted only at release of the last stream */ + LOG_DBG("Deleting unicast group"); + + int err = bt_bap_unicast_group_delete(u_cig->cig); + + if (err != 0) { + LOG_DBG("Unable to delete unicast group: %d", err); + + return; + } + + memset(u_cig, 0, sizeof(*u_cig)); + } +} + +static void stream_started(struct bt_bap_stream *stream) +{ + struct btp_bap_unicast_stream *u_stream = stream_bap_to_unicast(stream); + struct bt_bap_ep_info info; + + /* Callback called on transition to Streaming state */ + + LOG_DBG("Started stream %p", stream); + + btp_bap_audio_stream_started(&u_stream->audio_stream); + + (void)bt_bap_ep_get_info(stream->ep, &info); + btp_send_ascs_ase_state_changed_ev(stream->conn, u_stream->ase_id, info.state); +} + +static void stream_stopped(struct bt_bap_stream *stream, uint8_t reason) +{ + struct btp_bap_unicast_stream *u_stream = stream_bap_to_unicast(stream); + + LOG_DBG("Stopped stream %p with reason 0x%02X", stream, reason); + + btp_bap_audio_stream_stopped(&u_stream->audio_stream); + + btp_send_ascs_operation_completed_ev(stream->conn, u_stream->ase_id, + BT_ASCS_STOP_OP, BTP_STATUS_SUCCESS); +} + +static void send_stream_received_ev(struct bt_conn *conn, struct bt_bap_ep *ep, + uint8_t data_len, uint8_t *data) +{ + struct btp_bap_stream_received_ev *ev; + + tester_rsp_buffer_lock(); + tester_rsp_buffer_allocate(sizeof(*ev) + data_len, (uint8_t **)&ev); + + LOG_DBG("Stream received, ep %d, dir %d, len %d", ep->status.id, ep->dir, + data_len); + + bt_addr_le_copy(&ev->address, bt_conn_get_dst(conn)); + + ev->ase_id = ep->status.id; + ev->data_len = data_len; + memcpy(ev->data, data, data_len); + + tester_event(BTP_SERVICE_ID_BAP, BTP_BAP_EV_STREAM_RECEIVED, ev, sizeof(*ev) + data_len); + + tester_rsp_buffer_free(); + tester_rsp_buffer_unlock(); +} + +static void stream_recv(struct bt_bap_stream *stream, + const struct bt_iso_recv_info *info, + struct net_buf *buf) +{ + struct btp_bap_unicast_stream *u_stream = stream_bap_to_unicast(stream); + + if (u_stream->already_sent == false) { + /* For now, send just a first packet, to limit the number + * of logs and not unnecessarily spam through btp. + */ + LOG_DBG("Incoming audio on stream %p len %u", stream, buf->len); + u_stream->already_sent = true; + send_stream_received_ev(stream->conn, stream->ep, buf->len, buf->data); + } +} + +static void stream_sent(struct bt_bap_stream *stream) +{ + LOG_DBG("Stream %p sent", stream); +} + +static struct bt_bap_stream_ops stream_ops = { + .configured = stream_configured, + .qos_set = stream_qos_set, + .enabled = stream_enabled, + .metadata_updated = stream_metadata_updated, + .disabled = stream_disabled, + .released = stream_released, + .started = stream_started, + .stopped = stream_stopped, + .recv = stream_recv, + .sent = stream_sent, +}; + +struct btp_bap_unicast_stream *btp_bap_unicast_stream_alloc( + struct btp_bap_unicast_connection *conn) +{ + for (size_t i = 0; i < ARRAY_SIZE(conn->streams); i++) { + struct btp_bap_unicast_stream *stream = &conn->streams[i]; + + if (stream->in_use == false) { + bt_bap_stream_cb_register(stream_unicast_to_bap(stream), &stream_ops); + stream->in_use = true; + + return stream; + } + } + + return NULL; +} + +static void unicast_client_location_cb(struct bt_conn *conn, + enum bt_audio_dir dir, + enum bt_audio_location loc) +{ + LOG_DBG("dir %u loc %X", dir, loc); +} + +static void available_contexts_cb(struct bt_conn *conn, + enum bt_audio_context snk_ctx, + enum bt_audio_context src_ctx) +{ + LOG_DBG("snk ctx %u src ctx %u", snk_ctx, src_ctx); +} + +static void config_cb(struct bt_bap_stream *stream, enum bt_bap_ascs_rsp_code rsp_code, + enum bt_bap_ascs_reason reason) +{ + LOG_DBG("stream %p config operation rsp_code %u reason %u", stream, rsp_code, reason); +} + +static void qos_cb(struct bt_bap_stream *stream, enum bt_bap_ascs_rsp_code rsp_code, + enum bt_bap_ascs_reason reason) +{ + LOG_DBG("stream %p qos operation rsp_code %u reason %u", stream, rsp_code, reason); +} + +static void enable_cb(struct bt_bap_stream *stream, enum bt_bap_ascs_rsp_code rsp_code, + enum bt_bap_ascs_reason reason) +{ + LOG_DBG("stream %p enable operation rsp_code %u reason %u", stream, rsp_code, reason); +} + +static void start_cb(struct bt_bap_stream *stream, enum bt_bap_ascs_rsp_code rsp_code, + enum bt_bap_ascs_reason reason) +{ + struct btp_bap_unicast_stream *u_stream = stream_bap_to_unicast(stream); + + /* Callback called on Receiver Start Ready notification from ASE Control Point */ + + LOG_DBG("stream %p start operation rsp_code %u reason %u", stream, rsp_code, reason); + u_stream->already_sent = false; + + btp_send_ascs_operation_completed_ev(stream->conn, u_stream->ase_id, + BT_ASCS_START_OP, BTP_STATUS_SUCCESS); +} + +static void stop_cb(struct bt_bap_stream *stream, enum bt_bap_ascs_rsp_code rsp_code, + enum bt_bap_ascs_reason reason) +{ + LOG_DBG("stream %p stop operation rsp_code %u reason %u", stream, rsp_code, reason); +} + +static void disable_cb(struct bt_bap_stream *stream, enum bt_bap_ascs_rsp_code rsp_code, + enum bt_bap_ascs_reason reason) +{ + LOG_DBG("stream %p disable operation rsp_code %u reason %u", stream, rsp_code, reason); +} + +static void metadata_cb(struct bt_bap_stream *stream, enum bt_bap_ascs_rsp_code rsp_code, + enum bt_bap_ascs_reason reason) +{ + LOG_DBG("stream %p metadata operation rsp_code %u reason %u", stream, rsp_code, reason); +} + +static void release_cb(struct bt_bap_stream *stream, enum bt_bap_ascs_rsp_code rsp_code, + enum bt_bap_ascs_reason reason) +{ + LOG_DBG("stream %p release operation rsp_code %u reason %u", stream, rsp_code, reason); +} + +static void pac_record_cb(struct bt_conn *conn, enum bt_audio_dir dir, + const struct bt_audio_codec_cap *codec_cap) +{ + LOG_DBG(""); + + if (codec_cap != NULL) { + LOG_DBG("Discovered codec capabilities %p", codec_cap); + print_codec_cap(codec_cap); + btp_send_pac_codec_found_ev(conn, codec_cap, dir); + } +} + +static void btp_send_discovery_completed_ev(struct bt_conn *conn, uint8_t status) +{ + struct btp_bap_discovery_completed_ev ev; + + bt_addr_le_copy(&ev.address, bt_conn_get_dst(conn)); + ev.status = status; + + tester_event(BTP_SERVICE_ID_BAP, BTP_BAP_EV_DISCOVERY_COMPLETED, &ev, sizeof(ev)); +} + +static void endpoint_cb(struct bt_conn *conn, enum bt_audio_dir dir, struct bt_bap_ep *ep) +{ + struct btp_bap_unicast_connection *u_conn; + + LOG_DBG(""); + + if (ep != NULL) { + LOG_DBG("Discovered ASE %p, id %u, dir 0x%02x", ep, ep->status.id, ep->dir); + + u_conn = &connections[bt_conn_index(conn)]; + + if (u_conn->end_points_count >= CONFIG_BT_BAP_UNICAST_CLIENT_ASE_SNK_COUNT + + CONFIG_BT_BAP_UNICAST_CLIENT_ASE_SRC_COUNT) { + LOG_DBG("Failed to cache ep %p due to configured limit: %zu", ep, + u_conn->end_points_count); + + btp_send_discovery_completed_ev(conn, BTP_BAP_DISCOVERY_STATUS_FAILED); + + return; + } + + u_conn->end_points[u_conn->end_points_count++] = ep; + btp_send_ase_found_ev(conn, ep); + + return; + } +} + +static void discover_cb(struct bt_conn *conn, int err, enum bt_audio_dir dir) +{ + LOG_DBG(""); + + if (err != 0 && err != BT_ATT_ERR_ATTRIBUTE_NOT_FOUND) { + LOG_DBG("Discover remote ASEs failed: %d", err); + btp_send_discovery_completed_ev(conn, BTP_BAP_DISCOVERY_STATUS_FAILED); + return; + } + + LOG_DBG("Discover complete"); + + if (err == BT_ATT_ERR_ATTRIBUTE_NOT_FOUND) { + LOG_DBG("Discover remote ASEs completed without finding any source ASEs"); + } else { + LOG_DBG("Discover remote ASEs complete: err %d", err); + } + + if (dir == BT_AUDIO_DIR_SINK) { + err = bt_bap_unicast_client_discover(conn, BT_AUDIO_DIR_SOURCE); + + if (err != 0) { + LOG_DBG("Failed to discover source ASEs: %d", err); + btp_send_discovery_completed_ev(conn, BTP_BAP_DISCOVERY_STATUS_FAILED); + } + + return; + } + + btp_send_discovery_completed_ev(conn, BTP_BAP_DISCOVERY_STATUS_SUCCESS); +} + +static struct bt_bap_unicast_client_cb unicast_client_cbs = { + .location = unicast_client_location_cb, + .available_contexts = available_contexts_cb, + .config = config_cb, + .qos = qos_cb, + .enable = enable_cb, + .start = start_cb, + .stop = stop_cb, + .disable = disable_cb, + .metadata = metadata_cb, + .release = release_cb, + .pac_record = pac_record_cb, + .endpoint = endpoint_cb, + .discover = discover_cb, +}; + +uint8_t btp_bap_discover(const void *cmd, uint16_t cmd_len, + void *rsp, uint16_t *rsp_len) +{ + const struct btp_bap_discover_cmd *cp = cmd; + struct bt_conn *conn; + struct btp_bap_unicast_connection *u_conn; + struct bt_conn_info conn_info; + int err; + + conn = bt_conn_lookup_addr_le(BT_ID_DEFAULT, &cp->address); + if (!conn) { + LOG_ERR("Unknown connection"); + return BTP_STATUS_FAILED; + } + + u_conn = &connections[bt_conn_index(conn)]; + (void)bt_conn_get_info(conn, &conn_info); + + if (u_conn->end_points_count > 0 || conn_info.role != BT_HCI_ROLE_CENTRAL) { + bt_conn_unref(conn); + + return BTP_STATUS_FAILED; + } + + err = bt_bap_unicast_client_discover(conn, BT_AUDIO_DIR_SINK); + if (err != 0) { + LOG_DBG("Failed to discover remote ASEs: %d", err); + bt_conn_unref(conn); + + return BTP_STATUS_FAILED; + } + + bt_conn_unref(conn); + + return BTP_STATUS_SUCCESS; +} + +static int server_stream_config(struct bt_conn *conn, struct bt_bap_stream *stream, + struct bt_audio_codec_cfg *codec_cfg, + struct bt_audio_codec_qos_pref *qos) +{ + int err; + struct bt_bap_ep_info info; + + err = bt_bap_unicast_server_config_ase(conn, stream, codec_cfg, qos); + if (err != 0) { + return err; + } + + print_codec_cfg(codec_cfg); + (void)bt_bap_ep_get_info(stream->ep, &info); + + LOG_DBG("ASE Codec Config: ase_id %u dir %u", info.id, info.dir); + LOG_DBG("ASE Codec Config stream %p", stream); + + return 0; +} + +static uint8_t client_add_ase_to_cis(struct btp_bap_unicast_connection *u_conn, uint8_t ase_id, + uint8_t cis_id, uint8_t cig_id) +{ + struct btp_bap_unicast_stream *stream; + + if (cig_id >= CONFIG_BT_ISO_MAX_CIG || + cis_id >= CONFIG_BT_BAP_UNICAST_CLIENT_GROUP_STREAM_COUNT) { + return -EINVAL; + } + + stream = btp_bap_unicast_stream_find(u_conn, ase_id); + if (stream == NULL) { + return -EINVAL; + } + + LOG_DBG("Added ASE %u to CIS %u at CIG %u", ase_id, cis_id, cig_id); + + stream->cig_id = cig_id; + stream->cis_id = cis_id; + + return 0; +} + +static int client_unicast_group_param_set(struct btp_bap_unicast_connection *u_conn, uint8_t cig_id, + struct bt_bap_unicast_group_stream_pair_param *pair_params, + struct bt_bap_unicast_group_stream_param **stream_param_ptr) +{ + struct bt_bap_unicast_group_stream_param *stream_params = *stream_param_ptr; + + for (size_t i = 0; i < ARRAY_SIZE(u_conn->streams); i++) { + struct bt_bap_ep_info info; + struct bt_bap_ep *ep; + struct btp_bap_unicast_stream *u_stream = &u_conn->streams[i]; + struct bt_bap_stream *stream = stream_unicast_to_bap(u_stream); + + if (u_stream->in_use == false || u_stream->cig_id != cig_id) { + continue; + } + + ep = btp_bap_unicast_end_point_find(u_conn, u_stream->ase_id); + if (ep == NULL) { + return -EINVAL; + } + + stream_params->stream = stream; + stream_params->qos = &cigs[u_stream->cig_id].qos[u_stream->cis_id]; + + (void)bt_bap_ep_get_info(ep, &info); + if (info.dir == BT_AUDIO_DIR_SOURCE) { + if (pair_params[u_stream->cis_id].rx_param != NULL) { + return -EINVAL; + } + + pair_params[u_stream->cis_id].rx_param = stream_params; + } else { + if (pair_params[u_stream->cis_id].tx_param != NULL) { + return -EINVAL; + } + + pair_params[u_stream->cis_id].tx_param = stream_params; + } + + stream_params++; + } + + *stream_param_ptr = stream_params; + + return 0; +} + +int btp_bap_unicast_group_create(uint8_t cig_id, + struct btp_bap_unicast_group **out_unicast_group) +{ + int err; + struct bt_bap_unicast_group_stream_pair_param + pair_params[BTP_BAP_UNICAST_MAX_STREAMS_COUNT]; + struct bt_bap_unicast_group_stream_param stream_params[BTP_BAP_UNICAST_MAX_STREAMS_COUNT]; + struct bt_bap_unicast_group_stream_param *stream_param_ptr; + struct bt_bap_unicast_group_param param; + size_t cis_cnt = 0; + + (void)memset(pair_params, 0, sizeof(pair_params)); + (void)memset(stream_params, 0, sizeof(stream_params)); + *out_unicast_group = NULL; + + if (cig_id >= CONFIG_BT_ISO_MAX_CIG) { + return -EINVAL; + } + + /* API does not allow to assign a CIG ID freely, so ensure we create groups + * in the right order. + */ + for (uint8_t i = 0; i < cig_id; i++) { + if (cigs[i].in_use == false) { + return -EINVAL; + } + } + + if (cigs[cig_id].in_use == true) { + struct btp_bap_unicast_group *u_cig = &cigs[cig_id]; + + err = bt_bap_unicast_group_delete(u_cig->cig); + if (err != 0) { + LOG_DBG("Failed to delete the unicast group, err %d", err); + + return BTP_STATUS_FAILED; + } + + memset(u_cig, 0, sizeof(*u_cig)); + } + + stream_param_ptr = stream_params; + for (size_t i = 0; i < CONFIG_BT_MAX_CONN; i++) { + struct btp_bap_unicast_connection *unicast_conn = &connections[i]; + + if (unicast_conn->end_points_count == 0) { + continue; + } + + /* CISes have been assigned earlier to CIGs with client_add_ase_to_cis() */ + err = client_unicast_group_param_set(unicast_conn, cig_id, pair_params, + &stream_param_ptr); + if (err != 0) { + return err; + } + } + + /* Count CISes to be established */ + for (size_t count = ARRAY_SIZE(pair_params); count > 0; --count) { + size_t i = count - 1; + + if (pair_params[i].tx_param != NULL || pair_params[i].rx_param != NULL) { + cis_cnt++; + + continue; + } + + if (cis_cnt > 0) { + /* No gaps allowed */ + return -EINVAL; + } + } + + param.params = pair_params; + param.params_count = cis_cnt; + param.packing = BT_ISO_PACKING_SEQUENTIAL; + + LOG_DBG("Creating unicast group"); + err = bt_bap_unicast_group_create(¶m, &cigs[cig_id].cig); + if (err != 0) { + LOG_DBG("Could not create unicast group (err %d)", err); + return -EINVAL; + } + + cigs[cig_id].in_use = true; + *out_unicast_group = &cigs[cig_id]; + + return 0; +} + +struct btp_bap_unicast_group *btp_bap_unicast_group_find(uint8_t cig_id) +{ + if (cig_id >= CONFIG_BT_ISO_MAX_CIG) { + return NULL; + } + + return &cigs[cig_id]; +} + +static int client_configure_codec(struct btp_bap_unicast_connection *u_conn, struct bt_conn *conn, + uint8_t ase_id, struct bt_audio_codec_cfg *codec_cfg) +{ + int err; + struct bt_bap_ep *ep; + struct btp_bap_unicast_stream *stream; + + stream = btp_bap_unicast_stream_find(u_conn, ase_id); + if (stream == NULL) { + /* Configure a new stream */ + stream = btp_bap_unicast_stream_alloc(u_conn); + if (stream == NULL) { + LOG_DBG("No streams available"); + + return -ENOMEM; + } + + if (u_conn->end_points_count == 0) { + return -EINVAL; + } + + ep = btp_bap_unicast_end_point_find(u_conn, ase_id); + if (ep == NULL) { + return -EINVAL; + } + + memcpy(&stream->codec_cfg, codec_cfg, sizeof(*codec_cfg)); + err = bt_bap_stream_config(conn, stream_unicast_to_bap(stream), ep, + &stream->codec_cfg); + } else { + /* Reconfigure a stream */ + memcpy(&stream->codec_cfg, codec_cfg, sizeof(*codec_cfg)); + err = bt_bap_stream_reconfig(stream_unicast_to_bap(stream), + &stream->codec_cfg); + } + + return err; +} + +static int server_configure_codec(struct btp_bap_unicast_connection *u_conn, struct bt_conn *conn, + uint8_t ase_id, struct bt_audio_codec_cfg *codec_cfg) +{ + struct btp_bap_unicast_stream *stream; + int err = 0; + + stream = btp_bap_unicast_stream_find(u_conn, ase_id); + if (stream == NULL) { + /* Zephyr allocates ASE instances for remote clients dynamically. + * To initiate Codec Config operation autonomously in server the role, + * we have to initialize all ASEs with a smaller ID first. + * Fortunately, the PTS has nothing against such behavior. + */ + for (uint8_t i = 1; i <= ase_id; i++) { + stream = btp_bap_unicast_stream_find(u_conn, i); + if (stream != NULL) { + continue; + } + + /* Configure a new stream */ + stream = btp_bap_unicast_stream_alloc(u_conn); + if (stream == NULL) { + LOG_DBG("No streams available"); + + return -ENOMEM; + } + + memcpy(&stream->codec_cfg, codec_cfg, sizeof(*codec_cfg)); + err = server_stream_config(conn, stream_unicast_to_bap(stream), + &stream->codec_cfg, &qos_pref); + } + } else { + /* Reconfigure a stream */ + memcpy(&stream->codec_cfg, codec_cfg, sizeof(*codec_cfg)); + err = bt_bap_stream_reconfig(stream_unicast_to_bap(stream), &stream->codec_cfg); + } + + return err; +} + +uint8_t btp_ascs_configure_codec(const void *cmd, uint16_t cmd_len, void *rsp, uint16_t *rsp_len) +{ + int err; + const struct btp_ascs_configure_codec_cmd *cp = cmd; + struct bt_conn *conn; + struct bt_conn_info conn_info; + struct btp_bap_unicast_connection *u_conn; + struct bt_audio_codec_cfg codec_cfg; + + LOG_DBG(""); + + conn = bt_conn_lookup_addr_le(BT_ID_DEFAULT, &cp->address); + if (!conn) { + LOG_ERR("Unknown connection"); + return BTP_STATUS_FAILED; + } + + u_conn = &connections[bt_conn_index(conn)]; + + (void)bt_conn_get_info(conn, &conn_info); + + memset(&codec_cfg, 0, sizeof(codec_cfg)); + + codec_cfg.id = cp->coding_format; + codec_cfg.vid = cp->vid; + codec_cfg.cid = cp->cid; + + if (cp->cc_ltvs_len != 0) { + codec_cfg.data_len = cp->cc_ltvs_len; + memcpy(codec_cfg.data, cp->cc_ltvs, cp->cc_ltvs_len); + } + + if (conn_info.role == BT_HCI_ROLE_CENTRAL) { + err = client_configure_codec(u_conn, conn, cp->ase_id, &codec_cfg); + } else { + err = server_configure_codec(u_conn, conn, cp->ase_id, &codec_cfg); + } + + bt_conn_unref(conn); + + if (err) { + LOG_DBG("Failed to configure stream (err %d)", err); + return BTP_STATUS_FAILED; + } + + return BTP_STATUS_SUCCESS; +} + +uint8_t btp_ascs_preconfigure_qos(const void *cmd, uint16_t cmd_len, + void *rsp, uint16_t *rsp_len) +{ + const struct btp_ascs_preconfigure_qos_cmd *cp = cmd; + struct bt_audio_codec_qos *qos; + + LOG_DBG(""); + + qos = &cigs[cp->cig_id].qos[cp->cis_id]; + memset(qos, 0, sizeof(*qos)); + + qos->phy = BT_AUDIO_CODEC_QOS_2M; + qos->framing = cp->framing; + qos->rtn = cp->retransmission_num; + qos->sdu = sys_le16_to_cpu(cp->max_sdu); + qos->latency = sys_le16_to_cpu(cp->max_transport_latency); + qos->interval = sys_get_le24(cp->sdu_interval); + qos->pd = sys_get_le24(cp->presentation_delay); + + return BTP_STATUS_SUCCESS; +} + +uint8_t btp_ascs_configure_qos(const void *cmd, uint16_t cmd_len, void *rsp, uint16_t *rsp_len) +{ + int err; + const struct btp_ascs_configure_qos_cmd *cp = cmd; + struct bt_conn_info conn_info; + struct bt_conn *conn; + struct btp_bap_unicast_group *out_unicast_group; + + LOG_DBG(""); + + conn = bt_conn_lookup_addr_le(BT_ID_DEFAULT, &cp->address); + if (!conn) { + LOG_ERR("Unknown connection"); + + return BTP_STATUS_FAILED; + } + + (void)bt_conn_get_info(conn, &conn_info); + if (conn_info.role == BT_HCI_ROLE_PERIPHERAL) { + bt_conn_unref(conn); + + return BTP_STATUS_FAILED; + } + + if (cigs[cp->cig_id].in_use == false) { + err = btp_bap_unicast_group_create(cp->cig_id, &out_unicast_group); + if (err != 0) { + LOG_DBG("Unable to create unicast group, err %d", err); + bt_conn_unref(conn); + + return BTP_STATUS_FAILED; + } + } + + LOG_DBG("QoS configuring streams"); + err = bt_bap_stream_qos(conn, cigs[cp->cig_id].cig); + bt_conn_unref(conn); + + if (err != 0) { + LOG_DBG("Unable to QoS configure streams: %d", err); + + return BTP_STATUS_FAILED; + } + + return BTP_STATUS_SUCCESS; +} + +uint8_t btp_ascs_enable(const void *cmd, uint16_t cmd_len, void *rsp, uint16_t *rsp_len) +{ + int err; + const struct btp_ascs_enable_cmd *cp = cmd; + struct btp_bap_unicast_connection *u_conn; + struct btp_bap_unicast_stream *stream; + struct bt_conn *conn; + + LOG_DBG(""); + + conn = bt_conn_lookup_addr_le(BT_ID_DEFAULT, &cp->address); + if (!conn) { + LOG_ERR("Unknown connection"); + return BTP_STATUS_FAILED; + } + + u_conn = &connections[bt_conn_index(conn)]; + bt_conn_unref(conn); + + stream = btp_bap_unicast_stream_find(u_conn, cp->ase_id); + if (stream == NULL) { + return BTP_STATUS_FAILED; + } + + LOG_DBG("Enabling stream"); + err = bt_bap_stream_enable(stream_unicast_to_bap(stream), NULL, 0); + if (err != 0) { + LOG_DBG("Could not enable stream: %d", err); + return BTP_STATUS_FAILED; + } + + return BTP_STATUS_SUCCESS; +} + +uint8_t btp_ascs_disable(const void *cmd, uint16_t cmd_len, void *rsp, uint16_t *rsp_len) +{ + int err; + const struct btp_ascs_disable_cmd *cp = cmd; + struct btp_bap_unicast_connection *u_conn; + struct btp_bap_unicast_stream *stream; + struct bt_conn *conn; + + LOG_DBG(""); + + conn = bt_conn_lookup_addr_le(BT_ID_DEFAULT, &cp->address); + if (!conn) { + LOG_ERR("Unknown connection"); + return BTP_STATUS_FAILED; + } + + u_conn = &connections[bt_conn_index(conn)]; + bt_conn_unref(conn); + + stream = btp_bap_unicast_stream_find(u_conn, cp->ase_id); + if (stream == NULL) { + return BTP_STATUS_FAILED; + } + + LOG_DBG("Disabling stream"); + + err = bt_bap_stream_disable(stream_unicast_to_bap(stream)); + if (err != 0) { + LOG_DBG("Could not disable stream: %d", err); + return BTP_STATUS_FAILED; + } + + return BTP_STATUS_SUCCESS; +} + +uint8_t btp_ascs_receiver_start_ready(const void *cmd, uint16_t cmd_len, + void *rsp, uint16_t *rsp_len) +{ + int err; + const struct btp_ascs_receiver_start_ready_cmd *cp = cmd; + struct btp_bap_unicast_connection *u_conn; + struct btp_bap_unicast_stream *stream; + struct bt_bap_stream *bap_stream; + struct bt_bap_ep_info info; + struct bt_conn *conn; + + LOG_DBG(""); + + conn = bt_conn_lookup_addr_le(BT_ID_DEFAULT, &cp->address); + if (!conn) { + LOG_ERR("Unknown connection"); + return BTP_STATUS_FAILED; + } + + u_conn = &connections[bt_conn_index(conn)]; + bt_conn_unref(conn); + + stream = btp_bap_unicast_stream_find(u_conn, cp->ase_id); + if (stream == NULL) { + return BTP_STATUS_FAILED; + } + + bap_stream = stream_unicast_to_bap(stream); + (void)bt_bap_ep_get_info(bap_stream->ep, &info); + if (info.state == BT_BAP_EP_STATE_STREAMING) { + /* Already started */ + return BTP_STATUS_SUCCESS; + } + + LOG_DBG("Starting stream %p, ep %u, dir %u", bap_stream, cp->ase_id, info.dir); + + while (true) { + err = bt_bap_stream_start(bap_stream); + if (err == -EBUSY) { + /* TODO: How to determine if a controller is ready again after + * bt_bap_stream_start? In AC 6(i) tests the PTS sends Receiver Start Ready + * only after all CISes are established. + */ + k_sleep(K_MSEC(1000)); + continue; + } else if (err != 0) { + LOG_DBG("Could not start stream: %d", err); + return BTP_STATUS_FAILED; + } + + break; + }; + + return BTP_STATUS_SUCCESS; +} + +uint8_t btp_ascs_receiver_stop_ready(const void *cmd, uint16_t cmd_len, + void *rsp, uint16_t *rsp_len) +{ + int err; + const struct btp_ascs_receiver_stop_ready_cmd *cp = cmd; + struct btp_bap_unicast_connection *u_conn; + struct btp_bap_unicast_stream *stream; + struct bt_conn *conn; + + LOG_DBG(""); + + conn = bt_conn_lookup_addr_le(BT_ID_DEFAULT, &cp->address); + if (!conn) { + LOG_ERR("Unknown connection"); + return BTP_STATUS_FAILED; + } + + u_conn = &connections[bt_conn_index(conn)]; + bt_conn_unref(conn); + + stream = btp_bap_unicast_stream_find(u_conn, cp->ase_id); + if (stream == NULL) { + return BTP_STATUS_FAILED; + } + + LOG_DBG("Stopping stream"); + err = bt_bap_stream_stop(stream_unicast_to_bap(stream)); + if (err != 0) { + LOG_DBG("Could not stop stream: %d", err); + return BTP_STATUS_FAILED; + } + + return BTP_STATUS_SUCCESS; +} + +uint8_t btp_ascs_release(const void *cmd, uint16_t cmd_len, void *rsp, uint16_t *rsp_len) +{ + int err; + const struct btp_ascs_release_cmd *cp = cmd; + struct btp_bap_unicast_connection *u_conn; + struct btp_bap_unicast_stream *stream; + struct bt_conn *conn; + + LOG_DBG(""); + + conn = bt_conn_lookup_addr_le(BT_ID_DEFAULT, &cp->address); + if (!conn) { + LOG_ERR("Unknown connection"); + return BTP_STATUS_FAILED; + } + + u_conn = &connections[bt_conn_index(conn)]; + bt_conn_unref(conn); + + stream = btp_bap_unicast_stream_find(u_conn, cp->ase_id); + if (stream == NULL) { + return BTP_STATUS_FAILED; + } + + LOG_DBG("Releasing stream"); + err = bt_bap_stream_release(stream_unicast_to_bap(stream)); + if (err != 0) { + LOG_DBG("Unable to release stream, err %d", err); + return BTP_STATUS_FAILED; + } + + return BTP_STATUS_SUCCESS; +} + +uint8_t btp_ascs_update_metadata(const void *cmd, uint16_t cmd_len, + void *rsp, uint16_t *rsp_len) +{ + const uint8_t meta[] = { + BT_AUDIO_CODEC_DATA(BT_AUDIO_METADATA_TYPE_STREAM_CONTEXT, + BT_BYTES_LIST_LE16(BT_AUDIO_CONTEXT_TYPE_ANY)), + }; + const struct btp_ascs_update_metadata_cmd *cp = cmd; + struct btp_bap_unicast_connection *u_conn; + struct btp_bap_unicast_stream *stream; + struct bt_conn *conn; + int err; + + LOG_DBG(""); + + conn = bt_conn_lookup_addr_le(BT_ID_DEFAULT, &cp->address); + if (!conn) { + LOG_ERR("Unknown connection"); + return BTP_STATUS_FAILED; + } + + u_conn = &connections[bt_conn_index(conn)]; + bt_conn_unref(conn); + + stream = btp_bap_unicast_stream_find(u_conn, cp->ase_id); + if (stream == NULL) { + return BTP_STATUS_FAILED; + } + + LOG_DBG("Updating stream metadata"); + err = bt_bap_stream_metadata(stream_unicast_to_bap(stream), meta, ARRAY_SIZE(meta)); + if (err != 0) { + LOG_DBG("Failed to update stream metadata, err %d", err); + return BTP_STATUS_FAILED; + } + + return BTP_STATUS_SUCCESS; +} + +uint8_t btp_ascs_add_ase_to_cis(const void *cmd, uint16_t cmd_len, + void *rsp, uint16_t *rsp_len) +{ + int err; + struct bt_conn *conn; + struct btp_bap_unicast_connection *u_conn; + struct bt_conn_info conn_info; + const struct btp_ascs_add_ase_to_cis *cp = cmd; + + LOG_DBG(""); + + conn = bt_conn_lookup_addr_le(BT_ID_DEFAULT, &cp->address); + if (!conn) { + LOG_ERR("Unknown connection"); + + return BTP_STATUS_FAILED; + } + + (void)bt_conn_get_info(conn, &conn_info); + if (conn_info.role == BT_HCI_ROLE_PERIPHERAL) { + bt_conn_unref(conn); + + return BTP_STATUS_FAILED; + } + + u_conn = &connections[bt_conn_index(conn)]; + bt_conn_unref(conn); + + err = client_add_ase_to_cis(u_conn, cp->ase_id, cp->cis_id, cp->cig_id); + + return BTP_STATUS_VAL(err); +} + +struct btp_bap_unicast_connection *btp_bap_unicast_conn_get(size_t conn_index) +{ + return &connections[conn_index]; +} + +static void connected(struct bt_conn *conn, uint8_t err) +{ + struct btp_bap_unicast_connection *u_conn; + char addr[BT_ADDR_LE_STR_LEN]; + + bt_addr_le_to_str(bt_conn_get_dst(conn), addr, sizeof(addr)); + + if (err != 0) { + LOG_DBG("Failed to connect to %s (%u)", addr, err); + return; + } + + LOG_DBG("Connected: %s", addr); + + u_conn = &connections[bt_conn_index(conn)]; + memset(u_conn, 0, sizeof(*u_conn)); + bt_addr_le_copy(&u_conn->address, bt_conn_get_dst(conn)); +} + +static void disconnected(struct bt_conn *conn, uint8_t reason) +{ + char addr[BT_ADDR_LE_STR_LEN]; + + bt_addr_le_to_str(bt_conn_get_dst(conn), addr, sizeof(addr)); + + LOG_DBG("Disconnected: %s (reason 0x%02x)", addr, reason); +} + +static struct bt_conn_cb conn_callbacks = { + .connected = connected, + .disconnected = disconnected, +}; + +static bool unicast_inited; + +int btp_bap_unicast_init(void) +{ + int err; + + if (unicast_inited) { + return 0; + } + + (void)memset(connections, 0, sizeof(connections)); + + err = bt_bap_unicast_server_register_cb(&unicast_server_cb); + if (err != 0) { + LOG_DBG("Failed to register client callbacks: %d", err); + return err; + } + + err = bt_bap_unicast_client_register_cb(&unicast_client_cbs); + if (err != 0) { + LOG_DBG("Failed to register client callbacks: %d", err); + return err; + } + + bt_conn_cb_register(&conn_callbacks); + + unicast_inited = true; + + return 0; +} diff --git a/tests/bluetooth/tester/src/btp_bap_unicast.h b/tests/bluetooth/tester/src/btp_bap_unicast.h new file mode 100644 index 00000000000..e4111289da8 --- /dev/null +++ b/tests/bluetooth/tester/src/btp_bap_unicast.h @@ -0,0 +1,71 @@ +/* btp_bap_unicast.h - Bluetooth BAP Tester */ + +/* + * Copyright (c) 2023 Codecoup + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include + +#define BTP_BAP_UNICAST_MAX_SNK_STREAMS_COUNT MIN(CONFIG_BT_BAP_UNICAST_CLIENT_ASE_SNK_COUNT, \ + CONFIG_BT_ASCS_ASE_SNK_COUNT) +#define BTP_BAP_UNICAST_MAX_SRC_STREAMS_COUNT MIN(CONFIG_BT_BAP_UNICAST_CLIENT_ASE_SRC_COUNT, \ + CONFIG_BT_ASCS_ASE_SRC_COUNT) +#define BTP_BAP_UNICAST_MAX_STREAMS_COUNT BTP_BAP_UNICAST_MAX_SNK_STREAMS_COUNT + \ + BTP_BAP_UNICAST_MAX_SRC_STREAMS_COUNT +#define BTP_BAP_UNICAST_MAX_END_POINTS_COUNT CONFIG_BT_BAP_UNICAST_CLIENT_ASE_SNK_COUNT + \ + CONFIG_BT_BAP_UNICAST_CLIENT_ASE_SRC_COUNT + +struct btp_bap_unicast_group { + struct bt_audio_codec_qos qos[CONFIG_BT_BAP_UNICAST_CLIENT_GROUP_STREAM_COUNT]; + struct bt_bap_unicast_group *cig; + bool in_use; +}; + +struct btp_bap_unicast_stream { + struct btp_bap_audio_stream audio_stream; + uint8_t ase_id; + uint8_t conn_id; + uint8_t cig_id; + uint8_t cis_id; + struct bt_audio_codec_cfg codec_cfg; + bool already_sent; + bool in_use; +}; + +struct btp_bap_unicast_connection { + bt_addr_le_t address; + struct btp_bap_unicast_stream streams[BTP_BAP_UNICAST_MAX_STREAMS_COUNT]; + size_t configured_sink_stream_count; + size_t configured_source_stream_count; + struct bt_bap_ep *end_points[BTP_BAP_UNICAST_MAX_END_POINTS_COUNT]; + size_t end_points_count; +}; + +int btp_bap_unicast_init(void); +struct btp_bap_unicast_connection *btp_bap_unicast_conn_get(size_t conn_index); +int btp_bap_unicast_group_create(uint8_t cig_id, struct btp_bap_unicast_group **out_unicast_group); +struct btp_bap_unicast_group *btp_bap_unicast_group_find(uint8_t cig_id); +struct bt_bap_ep *btp_bap_unicast_end_point_find(struct btp_bap_unicast_connection *conn, + uint8_t ase_id); +struct btp_bap_unicast_stream *btp_bap_unicast_stream_find(struct btp_bap_unicast_connection *conn, + uint8_t ase_id); +struct btp_bap_unicast_stream *btp_bap_unicast_stream_alloc( + struct btp_bap_unicast_connection *conn); +void btp_bap_unicast_stream_free(struct btp_bap_unicast_stream *stream); + +uint8_t btp_bap_discover(const void *cmd, uint16_t cmd_len, void *rsp, uint16_t *rsp_len); + +uint8_t btp_ascs_configure_codec(const void *cmd, uint16_t cmd_len, void *rsp, uint16_t *rsp_len); +uint8_t btp_ascs_configure_qos(const void *cmd, uint16_t cmd_len, void *rsp, uint16_t *rsp_len); +uint8_t btp_ascs_enable(const void *cmd, uint16_t cmd_len, void *rsp, uint16_t *rsp_len); +uint8_t btp_ascs_receiver_start_ready(const void *cmd, uint16_t cmd_len, + void *rsp, uint16_t *rsp_len); +uint8_t btp_ascs_receiver_stop_ready(const void *cmd, uint16_t cmd_len, + void *rsp, uint16_t *rsp_len); +uint8_t btp_ascs_disable(const void *cmd, uint16_t cmd_len, void *rsp, uint16_t *rsp_len); +uint8_t btp_ascs_release(const void *cmd, uint16_t cmd_len, void *rsp, uint16_t *rsp_len); +uint8_t btp_ascs_update_metadata(const void *cmd, uint16_t cmd_len, void *rsp, uint16_t *rsp_len); +uint8_t btp_ascs_add_ase_to_cis(const void *cmd, uint16_t cmd_len, void *rsp, uint16_t *rsp_len); +uint8_t btp_ascs_preconfigure_qos(const void *cmd, uint16_t cmd_len, void *rsp, uint16_t *rsp_len); diff --git a/tests/bluetooth/tester/src/btp_cap.c b/tests/bluetooth/tester/src/btp_cap.c new file mode 100644 index 00000000000..0220b838143 --- /dev/null +++ b/tests/bluetooth/tester/src/btp_cap.c @@ -0,0 +1,905 @@ +/* btp_cap.c - Bluetooth CAP Tester */ + +/* + * Copyright (c) 2023 Codecoup + * + * SPDX-License-Identifier: Apache-2.0 + */ +#include + +#include "btp/btp.h" +#include "btp_bap_audio_stream.h" +#include "bap_endpoint.h" +#include "zephyr/sys/byteorder.h" +#include + +#include +#define LOG_MODULE_NAME bttester_cap +LOG_MODULE_REGISTER(LOG_MODULE_NAME, CONFIG_BTTESTER_LOG_LEVEL); + +#include "btp_bap_unicast.h" +#include "btp_bap_broadcast.h" + +extern struct bt_csip_set_coordinator_set_member *btp_csip_set_members[CONFIG_BT_MAX_CONN]; + +static struct bt_bap_stream *stream_unicast_to_bap(struct btp_bap_unicast_stream *stream) +{ + return &stream->audio_stream.cap_stream.bap_stream; +} + +static struct bt_cap_stream *stream_unicast_to_cap(struct btp_bap_unicast_stream *stream) +{ + return &stream->audio_stream.cap_stream; +} + +static struct bt_cap_stream *stream_broadcast_to_cap(struct btp_bap_broadcast_stream *stream) +{ + return &stream->audio_stream.cap_stream; +} + +static void btp_send_discovery_completed_ev(struct bt_conn *conn, uint8_t status) +{ + struct btp_cap_discovery_completed_ev ev; + + bt_addr_le_copy(&ev.address, bt_conn_get_dst(conn)); + ev.status = status; + + tester_event(BTP_SERVICE_ID_CAP, BTP_CAP_EV_DISCOVERY_COMPLETED, &ev, sizeof(ev)); +} + +static void cap_discovery_complete_cb(struct bt_conn *conn, int err, + const struct bt_csip_set_coordinator_csis_inst *csis_inst) +{ + LOG_DBG(""); + + if (err != 0) { + LOG_DBG("Failed to discover CAS: %d", err); + btp_send_discovery_completed_ev(conn, BTP_CAP_DISCOVERY_STATUS_FAILED); + + return; + } + + if (IS_ENABLED(CONFIG_BT_CAP_ACCEPTOR_SET_MEMBER)) { + if (csis_inst == NULL) { + LOG_DBG("Failed to discover CAS CSIS"); + btp_send_discovery_completed_ev(conn, BTP_CAP_DISCOVERY_STATUS_FAILED); + + return; + } + + LOG_DBG("Found CAS with CSIS %p", csis_inst); + } else { + LOG_DBG("Found CAS"); + } + + btp_send_discovery_completed_ev(conn, BTP_CAP_DISCOVERY_STATUS_SUCCESS); +} + +static void btp_send_cap_unicast_start_completed_ev(uint8_t cig_id, uint8_t status) +{ + struct btp_cap_unicast_start_completed_ev ev; + + ev.cig_id = cig_id; + ev.status = status; + + tester_event(BTP_SERVICE_ID_CAP, BTP_CAP_EV_UNICAST_START_COMPLETED, &ev, sizeof(ev)); +} + +static void btp_send_cap_unicast_stop_completed_ev(uint8_t cig_id, uint8_t status) +{ + struct btp_cap_unicast_stop_completed_ev ev; + + ev.cig_id = cig_id; + ev.status = status; + + tester_event(BTP_SERVICE_ID_CAP, BTP_CAP_EV_UNICAST_STOP_COMPLETED, &ev, sizeof(ev)); +} + +static void unicast_start_complete_cb(struct bt_bap_unicast_group *group, + int err, struct bt_conn *conn) +{ + LOG_DBG(""); + + if (err != 0) { + LOG_DBG("Failed to unicast-start, err %d", err); + btp_send_cap_unicast_start_completed_ev(group->index, + BTP_CAP_UNICAST_START_STATUS_FAILED); + + return; + } + + btp_send_cap_unicast_start_completed_ev(group->index, + BTP_CAP_UNICAST_START_STATUS_SUCCESS); +} + +static void unicast_update_complete_cb(int err, struct bt_conn *conn) +{ + LOG_DBG(""); + + if (err != 0) { + LOG_DBG("Failed to unicast-update, err %d", err); + } +} + +static void unicast_stop_complete_cb(struct bt_bap_unicast_group *group, int err, + struct bt_conn *conn) +{ + LOG_DBG(""); + + if (err != 0) { + LOG_DBG("Failed to unicast-stop, err %d", err); + btp_send_cap_unicast_stop_completed_ev(group->index, + BTP_CAP_UNICAST_START_STATUS_FAILED); + + return; + } + + btp_send_cap_unicast_stop_completed_ev(group->index, + BTP_CAP_UNICAST_START_STATUS_SUCCESS); +} + +static struct bt_cap_initiator_cb cap_cb = { + .unicast_discovery_complete = cap_discovery_complete_cb, + .unicast_start_complete = unicast_start_complete_cb, + .unicast_update_complete = unicast_update_complete_cb, + .unicast_stop_complete = unicast_stop_complete_cb, +}; + +static uint8_t btp_cap_supported_commands(const void *cmd, uint16_t cmd_len, + void *rsp, uint16_t *rsp_len) +{ + struct btp_cap_read_supported_commands_rp *rp = rsp; + + /* octet 0 */ + tester_set_bit(rp->data, BTP_CAP_READ_SUPPORTED_COMMANDS); + tester_set_bit(rp->data, BTP_CAP_DISCOVER); + + *rsp_len = sizeof(*rp) + 1; + + return BTP_STATUS_SUCCESS; +} + +static uint8_t btp_cap_discover(const void *cmd, uint16_t cmd_len, + void *rsp, uint16_t *rsp_len) +{ + const struct btp_cap_discover_cmd *cp = cmd; + struct bt_conn *conn; + int err; + + LOG_DBG(""); + + conn = bt_conn_lookup_addr_le(BT_ID_DEFAULT, &cp->address); + if (!conn) { + LOG_ERR("Unknown connection"); + return BTP_STATUS_FAILED; + } + + err = bt_cap_initiator_unicast_discover(conn); + if (err != 0) { + LOG_DBG("Failed to discover remote ASEs: %d", err); + bt_conn_unref(conn); + + return BTP_STATUS_FAILED; + } + + bt_conn_unref(conn); + + return BTP_STATUS_SUCCESS; +} + +static int cap_unicast_setup_ase(struct bt_conn *conn, uint8_t ase_id, uint8_t cis_id, + uint8_t cig_id, struct bt_audio_codec_cfg *codec_cfg, + struct bt_audio_codec_qos *qos) +{ + struct btp_bap_unicast_group *group; + struct btp_bap_unicast_stream *u_stream; + struct bt_bap_stream *stream; + struct btp_bap_unicast_connection *u_conn = btp_bap_unicast_conn_get(bt_conn_index(conn)); + + u_stream = btp_bap_unicast_stream_find(u_conn, ase_id); + if (u_stream == NULL) { + /* Configure a new u_stream */ + u_stream = btp_bap_unicast_stream_alloc(u_conn); + if (u_stream == NULL) { + LOG_DBG("No streams available"); + + return -ENOMEM; + } + } + + stream = stream_unicast_to_bap(u_stream); + bt_cap_stream_ops_register(&u_stream->audio_stream.cap_stream, stream->ops); + + u_stream->conn_id = bt_conn_index(conn); + u_stream->ase_id = ase_id; + u_stream->cig_id = cig_id; + u_stream->cis_id = cis_id; + memcpy(&u_stream->codec_cfg, codec_cfg, sizeof(*codec_cfg)); + + group = btp_bap_unicast_group_find(cig_id); + if (group == NULL) { + return -EINVAL; + } + + memcpy(&group->qos[cis_id], qos, sizeof(*qos)); + + return 0; +} + +static uint8_t btp_cap_unicast_setup_ase(const void *cmd, uint16_t cmd_len, + void *rsp, uint16_t *rsp_len) +{ + const struct btp_cap_unicast_setup_ase_cmd *cp = cmd; + struct bt_audio_codec_cfg codec_cfg; + struct bt_audio_codec_qos qos; + struct bt_conn *conn; + const uint8_t *ltv_ptr; + int err; + + LOG_DBG(""); + + conn = bt_conn_lookup_addr_le(BT_ID_DEFAULT, &cp->address); + if (!conn) { + LOG_ERR("Unknown connection"); + + return BTP_STATUS_FAILED; + } + + memset(&qos, 0, sizeof(qos)); + qos.phy = BT_AUDIO_CODEC_QOS_2M; + qos.framing = cp->framing; + qos.rtn = cp->retransmission_num; + qos.sdu = sys_le16_to_cpu(cp->max_sdu); + qos.latency = sys_le16_to_cpu(cp->max_transport_latency); + qos.interval = sys_get_le24(cp->sdu_interval); + qos.pd = sys_get_le24(cp->presentation_delay); + + memset(&codec_cfg, 0, sizeof(codec_cfg)); + codec_cfg.id = cp->coding_format; + codec_cfg.vid = cp->vid; + codec_cfg.cid = cp->cid; + + ltv_ptr = cp->ltvs; + if (cp->cc_ltvs_len != 0) { + codec_cfg.data_len = cp->cc_ltvs_len; + memcpy(codec_cfg.data, ltv_ptr, cp->cc_ltvs_len); + ltv_ptr += cp->cc_ltvs_len; + } + + if (cp->metadata_ltvs_len != 0) { + codec_cfg.meta_len = cp->metadata_ltvs_len; + memcpy(codec_cfg.meta, ltv_ptr, cp->metadata_ltvs_len); + } + + err = cap_unicast_setup_ase(conn, cp->ase_id, cp->cis_id, cp->cig_id, &codec_cfg, &qos); + bt_conn_unref(conn); + + return BTP_STATUS_VAL(err); +} + +static uint8_t btp_cap_unicast_audio_start(const void *cmd, uint16_t cmd_len, + void *rsp, uint16_t *rsp_len) +{ + int err; + size_t stream_count = 0; + struct btp_bap_unicast_group *u_group; + const struct btp_cap_unicast_audio_start_cmd *cp = cmd; + struct bt_cap_unicast_audio_start_param start_param; + struct bt_cap_unicast_audio_start_stream_param stream_params[ + ARRAY_SIZE(btp_csip_set_members) * BTP_BAP_UNICAST_MAX_STREAMS_COUNT]; + + LOG_DBG(""); + + err = btp_bap_unicast_group_create(cp->cig_id, &u_group); + if (err != 0) { + LOG_ERR("Failed to create unicast group"); + + return BTP_STATUS_FAILED; + } + + for (size_t conn_index = 0; conn_index < ARRAY_SIZE(btp_csip_set_members); conn_index++) { + struct btp_bap_unicast_connection *u_conn = btp_bap_unicast_conn_get(conn_index); + + if (u_conn->end_points_count == 0) { + /* Connection not initialized */ + continue; + } + + for (size_t i = 0; i < ARRAY_SIZE(u_conn->streams); i++) { + struct bt_cap_unicast_audio_start_stream_param *stream_param; + struct btp_bap_unicast_stream *u_stream = &u_conn->streams[i]; + + if (!u_stream->in_use || u_stream->cig_id != cp->cig_id) { + continue; + } + + stream_param = &stream_params[stream_count++]; + stream_param->stream = stream_unicast_to_cap(u_stream); + stream_param->codec_cfg = &u_stream->codec_cfg; + stream_param->member.member = bt_conn_lookup_addr_le(BT_ID_DEFAULT, + &u_conn->address); + stream_param->ep = btp_bap_unicast_end_point_find(u_conn, u_stream->ase_id); + } + } + + start_param.type = cp->set_type; + start_param.count = stream_count; + start_param.stream_params = stream_params; + + err = bt_cap_initiator_unicast_audio_start(&start_param, u_group->cig); + if (err != 0) { + LOG_ERR("Failed to start unicast audio: %d", err); + + return BTP_STATUS_FAILED; + } + + return BTP_STATUS_SUCCESS; +} + +static uint8_t btp_cap_unicast_audio_update(const void *cmd, uint16_t cmd_len, + void *rsp, uint16_t *rsp_len) +{ + int err; + const uint8_t *data_ptr; + const struct btp_cap_unicast_audio_update_cmd *cp = cmd; + struct bt_cap_unicast_audio_update_param stream_params[ + ARRAY_SIZE(btp_csip_set_members) * BTP_BAP_UNICAST_MAX_STREAMS_COUNT]; + + LOG_DBG(""); + + if (cp->stream_count == 0) { + return BTP_STATUS_FAILED; + } + + data_ptr = cp->update_data; + for (size_t i = 0; i < cp->stream_count; i++) { + struct btp_bap_unicast_connection *u_conn; + struct btp_bap_unicast_stream *u_stream; + struct bt_conn *conn; + struct btp_cap_unicast_audio_update_data *update_data = + (struct btp_cap_unicast_audio_update_data *)data_ptr; + struct bt_cap_unicast_audio_update_param *param = &stream_params[i]; + + conn = bt_conn_lookup_addr_le(BT_ID_DEFAULT, &update_data->address); + if (!conn) { + LOG_ERR("Unknown connection"); + + return BTP_STATUS_FAILED; + } + + u_conn = btp_bap_unicast_conn_get(bt_conn_index(conn)); + bt_conn_unref(conn); + if (u_conn->end_points_count == 0) { + /* Connection not initialized */ + + return BTP_STATUS_FAILED; + } + + u_stream = btp_bap_unicast_stream_find(u_conn, update_data->ase_id); + if (u_stream == NULL) { + return BTP_STATUS_FAILED; + } + + param->stream = &u_stream->audio_stream.cap_stream; + param->meta_len = update_data->metadata_ltvs_len; + param->meta = update_data->metadata_ltvs; + + data_ptr = ((uint8_t *)update_data) + param->meta_len + + sizeof(struct btp_cap_unicast_audio_update_data); + } + + err = bt_cap_initiator_unicast_audio_update(stream_params, cp->stream_count); + if (err != 0) { + LOG_ERR("Failed to start unicast audio: %d", err); + + return BTP_STATUS_FAILED; + } + + return BTP_STATUS_SUCCESS; +} + +static uint8_t btp_cap_unicast_audio_stop(const void *cmd, uint16_t cmd_len, + void *rsp, uint16_t *rsp_len) +{ + + int err; + const struct btp_cap_unicast_audio_stop_cmd *cp = cmd; + struct btp_bap_unicast_group *group; + + LOG_DBG(""); + + group = btp_bap_unicast_group_find(cp->cig_id); + + err = bt_cap_initiator_unicast_audio_stop(group->cig); + if (err != 0) { + LOG_ERR("Failed to start unicast audio: %d", err); + + return BTP_STATUS_FAILED; + } + + return BTP_STATUS_SUCCESS; +} + +static struct bt_cap_initiator_broadcast_subgroup_param + cap_subgroup_params[CONFIG_BT_BAP_BROADCAST_SRC_SUBGROUP_COUNT]; +static struct bt_cap_initiator_broadcast_stream_param + cap_stream_params[CONFIG_BT_BAP_BROADCAST_SRC_SUBGROUP_COUNT] + [CONFIG_BT_BAP_BROADCAST_SRC_STREAM_COUNT]; + +static uint8_t btp_cap_broadcast_source_setup_stream(const void *cmd, uint16_t cmd_len, + void *rsp, uint16_t *rsp_len) +{ + const uint8_t *ltv_ptr; + struct btp_bap_broadcast_stream *stream; + const struct btp_cap_broadcast_source_setup_stream_cmd *cp = cmd; + struct btp_bap_broadcast_local_source *source = + btp_bap_broadcast_local_source_get(cp->source_id); + struct bt_audio_codec_cfg *codec_cfg; + + stream = btp_bap_broadcast_stream_alloc(source); + if (stream == NULL) { + return BTP_STATUS_FAILED; + } + + stream->subgroup_id = cp->subgroup_id; + codec_cfg = &stream->codec_cfg; + memset(codec_cfg, 0, sizeof(*codec_cfg)); + codec_cfg->id = cp->coding_format; + codec_cfg->vid = cp->vid; + codec_cfg->cid = cp->cid; + + ltv_ptr = cp->ltvs; + if (cp->cc_ltvs_len != 0) { + codec_cfg->data_len = cp->cc_ltvs_len; + memcpy(codec_cfg->data, ltv_ptr, cp->cc_ltvs_len); + ltv_ptr += cp->cc_ltvs_len; + } + + if (cp->metadata_ltvs_len != 0) { + codec_cfg->meta_len = cp->metadata_ltvs_len; + memcpy(codec_cfg->meta, ltv_ptr, cp->metadata_ltvs_len); + } + + return BTP_STATUS_SUCCESS; +} + +static uint8_t btp_cap_broadcast_source_setup_subgroup(const void *cmd, uint16_t cmd_len, + void *rsp, uint16_t *rsp_len) +{ + const uint8_t *ltv_ptr; + struct bt_audio_codec_cfg *codec_cfg; + const struct btp_cap_broadcast_source_setup_subgroup_cmd *cp = cmd; + struct btp_bap_broadcast_local_source *source = + btp_bap_broadcast_local_source_get(cp->source_id); + + if (cp->subgroup_id >= sizeof(cap_subgroup_params)) { + return BTP_STATUS_FAILED; + } + + cap_subgroup_params[cp->subgroup_id].codec_cfg = + &source->subgroup_codec_cfg[cp->subgroup_id]; + codec_cfg = cap_subgroup_params[cp->subgroup_id].codec_cfg; + memset(codec_cfg, 0, sizeof(*codec_cfg)); + codec_cfg->id = cp->coding_format; + codec_cfg->vid = cp->vid; + codec_cfg->cid = cp->cid; + + ltv_ptr = cp->ltvs; + if (cp->cc_ltvs_len != 0) { + codec_cfg->data_len = cp->cc_ltvs_len; + memcpy(codec_cfg->data, ltv_ptr, cp->cc_ltvs_len); + ltv_ptr += cp->cc_ltvs_len; + } + + if (cp->metadata_ltvs_len != 0) { + codec_cfg->meta_len = cp->metadata_ltvs_len; + memcpy(codec_cfg->meta, ltv_ptr, cp->metadata_ltvs_len); + } + + return BTP_STATUS_SUCCESS; +} + +static int cap_broadcast_source_adv_setup(struct btp_bap_broadcast_local_source *source, + uint32_t *gap_settings) +{ + int err; + struct bt_le_adv_param *param = BT_LE_EXT_ADV_NCONN_NAME; + + NET_BUF_SIMPLE_DEFINE(ad_buf, BT_UUID_SIZE_16 + BT_AUDIO_BROADCAST_ID_SIZE); + NET_BUF_SIMPLE_DEFINE(base_buf, 128); + + /* Broadcast Audio Streaming Endpoint advertising data */ + struct bt_data base_ad; + struct bt_data per_ad; + + err = bt_cap_initiator_broadcast_get_id(source->cap_broadcast, &source->broadcast_id); + if (err != 0) { + LOG_DBG("Unable to get broadcast ID: %d", err); + + return -EINVAL; + } + + *gap_settings = BIT(BTP_GAP_SETTINGS_DISCOVERABLE) | + BIT(BTP_GAP_SETTINGS_EXTENDED_ADVERTISING); + /* Setup extended advertising data */ + net_buf_simple_add_le16(&ad_buf, BT_UUID_BROADCAST_AUDIO_VAL); + net_buf_simple_add_le24(&ad_buf, source->broadcast_id); + base_ad.type = BT_DATA_SVC_DATA16; + base_ad.data_len = ad_buf.len; + base_ad.data = ad_buf.data; + err = tester_gap_create_adv_instance(param, BTP_GAP_ADDR_TYPE_IDENTITY, &base_ad, 1, NULL, + 0, gap_settings); + if (err != 0) { + LOG_DBG("Failed to create extended advertising instance: %d", err); + + return -EINVAL; + } + + err = tester_gap_padv_configure(BT_LE_PER_ADV_PARAM(BT_GAP_PER_ADV_FAST_INT_MIN_2, + BT_GAP_PER_ADV_FAST_INT_MAX_2, + BT_LE_PER_ADV_OPT_USE_TX_POWER)); + if (err != 0) { + LOG_DBG("Failed to configure periodic advertising: %d", err); + + return -EINVAL; + } + + err = bt_cap_initiator_broadcast_get_base(source->cap_broadcast, &base_buf); + if (err != 0) { + LOG_DBG("Failed to get encoded BASE: %d\n", err); + + return -EINVAL; + } + + per_ad.type = BT_DATA_SVC_DATA16; + per_ad.data_len = base_buf.len; + per_ad.data = base_buf.data; + err = tester_gap_padv_set_data(&per_ad, 1); + if (err != 0) { + return -EINVAL; + } + + return 0; +} + +static uint8_t btp_cap_broadcast_source_setup(const void *cmd, uint16_t cmd_len, + void *rsp, uint16_t *rsp_len) +{ + int err; + uint32_t gap_settings; + static struct bt_cap_initiator_broadcast_create_param create_param; + const struct btp_cap_broadcast_source_setup_cmd *cp = cmd; + struct btp_cap_broadcast_source_setup_rp *rp = rsp; + struct btp_bap_broadcast_local_source *source = + btp_bap_broadcast_local_source_get(cp->source_id); + struct bt_audio_codec_qos *qos = &source->qos; + + LOG_DBG(""); + + memset(&create_param, 0, sizeof(create_param)); + + for (size_t i = 0; i < ARRAY_SIZE(source->streams); i++) { + struct btp_bap_broadcast_stream *stream = &source->streams[i]; + struct bt_cap_initiator_broadcast_stream_param *stream_param; + struct bt_cap_initiator_broadcast_subgroup_param *subgroup_param; + uint8_t bis_id; + + if (!stream->in_use) { + /* No more streams set up */ + break; + } + + subgroup_param = &cap_subgroup_params[stream->subgroup_id]; + bis_id = subgroup_param->stream_count++; + stream_param = &cap_stream_params[stream->subgroup_id][bis_id]; + stream_param->stream = stream_broadcast_to_cap(stream); + + if (cp->flags & BTP_CAP_BROADCAST_SOURCE_SETUP_FLAG_SUBGROUP_CODEC) { + stream_param->data_len = 0; + stream_param->data = NULL; + } else { + stream_param->data_len = stream->codec_cfg.data_len; + stream_param->data = stream->codec_cfg.data; + } + } + + for (size_t i = 0; i < ARRAY_SIZE(cap_subgroup_params); i++) { + if (cap_subgroup_params[i].stream_count == 0) { + /* No gaps allowed */ + break; + } + + cap_subgroup_params[i].stream_params = cap_stream_params[i]; + create_param.subgroup_count++; + } + + if (create_param.subgroup_count == 0) { + return BTP_STATUS_FAILED; + } + + memset(qos, 0, sizeof(*qos)); + qos->phy = BT_AUDIO_CODEC_QOS_2M; + qos->framing = cp->framing; + qos->rtn = cp->retransmission_num; + qos->sdu = sys_le16_to_cpu(cp->max_sdu); + qos->latency = sys_le16_to_cpu(cp->max_transport_latency); + qos->interval = sys_get_le24(cp->sdu_interval); + qos->pd = sys_get_le24(cp->presentation_delay); + + create_param.subgroup_params = cap_subgroup_params; + create_param.qos = qos; + create_param.packing = BT_ISO_PACKING_SEQUENTIAL; + create_param.encryption = cp->flags & BTP_CAP_BROADCAST_SOURCE_SETUP_FLAG_ENCRYPTION; + memcpy(create_param.broadcast_code, cp->broadcast_code, sizeof(cp->broadcast_code)); + + err = bt_cap_initiator_broadcast_audio_create(&create_param, &source->cap_broadcast); + memset(cap_subgroup_params, 0, sizeof(cap_subgroup_params)); + memset(&create_param, 0, sizeof(create_param)); + if (err != 0) { + LOG_ERR("Failed to create audio source: %d", err); + + return BTP_STATUS_FAILED; + } + + err = cap_broadcast_source_adv_setup(source, &gap_settings); + if (err != 0) { + return BTP_STATUS_FAILED; + } + + rp->gap_settings = gap_settings; + sys_put_le24(source->broadcast_id, rp->broadcast_id); + *rsp_len = sizeof(*rp) + 1; + + return BTP_STATUS_SUCCESS; +} + +static uint8_t btp_cap_broadcast_source_release(const void *cmd, uint16_t cmd_len, + void *rsp, uint16_t *rsp_len) +{ + int err; + const struct btp_cap_broadcast_source_release_cmd *cp = cmd; + struct btp_bap_broadcast_local_source *source = + btp_bap_broadcast_local_source_get(cp->source_id); + + LOG_DBG(""); + + err = bt_cap_initiator_broadcast_audio_delete(source->cap_broadcast); + if (err != 0) { + LOG_DBG("Unable to delete broadcast source: %d", err); + + return BTP_STATUS_FAILED; + } + + memset(source, 0, sizeof(*source)); + + return BTP_STATUS_SUCCESS; +} + +static uint8_t btp_cap_broadcast_adv_start(const void *cmd, uint16_t cmd_len, + void *rsp, uint16_t *rsp_len) +{ + int err; + struct bt_le_ext_adv *ext_adv = tester_gap_ext_adv_get(); + + LOG_DBG(""); + + if (ext_adv == NULL) { + return BTP_STATUS_FAILED; + } + + err = tester_gap_start_ext_adv(); + if (err != 0) { + return BTP_STATUS_FAILED; + } + + err = tester_gap_padv_start(); + if (err != 0) { + LOG_DBG("Unable to start periodic advertising: %d", err); + + return BTP_STATUS_FAILED; + } + + return BTP_STATUS_SUCCESS; +} + +static uint8_t btp_cap_broadcast_adv_stop(const void *cmd, uint16_t cmd_len, + void *rsp, uint16_t *rsp_len) +{ + int err; + + LOG_DBG(""); + + err = tester_gap_padv_stop(); + if (err != 0) { + return BTP_STATUS_FAILED; + } + + err = tester_gap_stop_ext_adv(); + + return BTP_STATUS_VAL(err); +} + +static uint8_t btp_cap_broadcast_source_start(const void *cmd, uint16_t cmd_len, + void *rsp, uint16_t *rsp_len) +{ + int err; + const struct btp_cap_broadcast_source_start_cmd *cp = cmd; + struct btp_bap_broadcast_local_source *source = + btp_bap_broadcast_local_source_get(cp->source_id); + struct bt_le_ext_adv *ext_adv = tester_gap_ext_adv_get(); + + LOG_DBG(""); + + if (ext_adv == NULL) { + return BTP_STATUS_FAILED; + } + + err = bt_cap_initiator_broadcast_audio_start(source->cap_broadcast, ext_adv); + if (err != 0) { + LOG_ERR("Failed to start audio source: %d", err); + + return BTP_STATUS_FAILED; + } + + return BTP_STATUS_SUCCESS; +} + +static uint8_t btp_cap_broadcast_source_stop(const void *cmd, uint16_t cmd_len, + void *rsp, uint16_t *rsp_len) +{ + int err; + const struct btp_cap_broadcast_source_stop_cmd *cp = cmd; + struct btp_bap_broadcast_local_source *source = + btp_bap_broadcast_local_source_get(cp->source_id); + + err = bt_cap_initiator_broadcast_audio_stop(source->cap_broadcast); + if (err != 0) { + LOG_ERR("Failed to stop audio source: %d", err); + + return BTP_STATUS_FAILED; + } + + return BTP_STATUS_SUCCESS; +} + +static uint8_t btp_cap_broadcast_source_update(const void *cmd, uint16_t cmd_len, + void *rsp, uint16_t *rsp_len) +{ + int err; + struct bt_data per_ad; + const struct btp_cap_broadcast_source_update_cmd *cp = cmd; + struct btp_bap_broadcast_local_source *source = + btp_bap_broadcast_local_source_get(cp->source_id); + NET_BUF_SIMPLE_DEFINE(base_buf, 128); + + LOG_DBG(""); + + if (cp->metadata_ltvs_len == 0) { + return BTP_STATUS_FAILED; + } + + err = bt_cap_initiator_broadcast_audio_update(source->cap_broadcast, cp->metadata_ltvs, + cp->metadata_ltvs_len); + if (err != 0) { + LOG_ERR("Failed to update audio source: %d", err); + + return BTP_STATUS_FAILED; + } + + err = bt_cap_initiator_broadcast_get_base(source->cap_broadcast, &base_buf); + if (err != 0) { + LOG_DBG("Failed to get encoded BASE: %d\n", err); + + return -EINVAL; + } + + per_ad.type = BT_DATA_SVC_DATA16; + per_ad.data_len = base_buf.len; + per_ad.data = base_buf.data; + err = tester_gap_padv_set_data(&per_ad, 1); + if (err != 0) { + return -EINVAL; + } + + return BTP_STATUS_SUCCESS; +} + +static const struct btp_handler cap_handlers[] = { + { + .opcode = BTP_CAP_READ_SUPPORTED_COMMANDS, + .index = BTP_INDEX_NONE, + .expect_len = 0, + .func = btp_cap_supported_commands + }, + { + .opcode = BTP_CAP_DISCOVER, + .expect_len = sizeof(struct btp_cap_discover_cmd), + .func = btp_cap_discover + }, + { + .opcode = BTP_CAP_UNICAST_SETUP_ASE, + .expect_len = BTP_HANDLER_LENGTH_VARIABLE, + .func = btp_cap_unicast_setup_ase + }, + { + .opcode = BTP_CAP_UNICAST_AUDIO_START, + .expect_len = sizeof(struct btp_cap_unicast_audio_start_cmd), + .func = btp_cap_unicast_audio_start + }, + { + .opcode = BTP_CAP_UNICAST_AUDIO_UPDATE, + .expect_len = BTP_HANDLER_LENGTH_VARIABLE, + .func = btp_cap_unicast_audio_update + }, + { + .opcode = BTP_CAP_UNICAST_AUDIO_STOP, + .expect_len = sizeof(struct btp_cap_unicast_audio_stop_cmd), + .func = btp_cap_unicast_audio_stop + }, + { + .opcode = BTP_CAP_BROADCAST_SOURCE_SETUP_STREAM, + .expect_len = BTP_HANDLER_LENGTH_VARIABLE, + .func = btp_cap_broadcast_source_setup_stream + }, + { + .opcode = BTP_CAP_BROADCAST_SOURCE_SETUP_SUBGROUP, + .expect_len = BTP_HANDLER_LENGTH_VARIABLE, + .func = btp_cap_broadcast_source_setup_subgroup + }, + { + .opcode = BTP_CAP_BROADCAST_SOURCE_SETUP, + .expect_len = sizeof(struct btp_cap_broadcast_source_setup_cmd), + .func = btp_cap_broadcast_source_setup + }, + { + .opcode = BTP_CAP_BROADCAST_SOURCE_RELEASE, + .expect_len = sizeof(struct btp_cap_broadcast_source_release_cmd), + .func = btp_cap_broadcast_source_release + }, + { + .opcode = BTP_CAP_BROADCAST_ADV_START, + .expect_len = sizeof(struct btp_cap_broadcast_adv_start_cmd), + .func = btp_cap_broadcast_adv_start + }, + { + .opcode = BTP_CAP_BROADCAST_ADV_STOP, + .expect_len = sizeof(struct btp_cap_broadcast_adv_stop_cmd), + .func = btp_cap_broadcast_adv_stop + }, + { + .opcode = BTP_CAP_BROADCAST_SOURCE_START, + .expect_len = sizeof(struct btp_cap_broadcast_source_start_cmd), + .func = btp_cap_broadcast_source_start + }, + { + .opcode = BTP_CAP_BROADCAST_SOURCE_STOP, + .expect_len = sizeof(struct btp_cap_broadcast_source_stop_cmd), + .func = btp_cap_broadcast_source_stop + }, + { + .opcode = BTP_CAP_BROADCAST_SOURCE_UPDATE, + .expect_len = BTP_HANDLER_LENGTH_VARIABLE, + .func = btp_cap_broadcast_source_update + }, +}; + +uint8_t tester_init_cap(void) +{ + int err; + + err = bt_cap_initiator_register_cb(&cap_cb); + if (err != 0) { + LOG_DBG("Failed to register CAP callbacks (err %d)", err); + return err; + } + + tester_register_command_handlers(BTP_SERVICE_ID_CAP, cap_handlers, + ARRAY_SIZE(cap_handlers)); + + return BTP_STATUS_SUCCESS; +} + +uint8_t tester_unregister_cap(void) +{ + return BTP_STATUS_SUCCESS; +} diff --git a/tests/bluetooth/tester/src/btp_core.c b/tests/bluetooth/tester/src/btp_core.c index b76bd884105..60a47d34bda 100644 --- a/tests/bluetooth/tester/src/btp_core.c +++ b/tests/bluetooth/tester/src/btp_core.c @@ -194,6 +194,11 @@ static uint8_t register_service(const void *cmd, uint16_t cmd_len, status = tester_init_csis(); break; #endif /* CONFIG_BT_CSIP_SET_MEMBER */ +#if defined(CONFIG_BT_CSIP_SET_COORDINATOR) + case BTP_SERVICE_ID_CSIP: + status = tester_init_csip(); + break; +#endif /* CONFIG_BT_CSIP_SET_COORDINATOR */ #if defined(CONFIG_BT_TBS_CLIENT) case BTP_SERVICE_ID_CCP: status = tester_init_ccp(); @@ -204,6 +209,11 @@ static uint8_t register_service(const void *cmd, uint16_t cmd_len, status = tester_init_cas(); break; #endif /* CONFIG_BT_CAP_ACCEPTOR */ +#if defined(CONFIG_BT_CAP_INITIATOR) + case BTP_SERVICE_ID_CAP: + status = tester_init_cap(); + break; +#endif /* CONFIG_BT_CAP_INITIATOR */ #if defined(CONFIG_BT_MCC) case BTP_SERVICE_ID_MCP: status = tester_init_mcp(); @@ -316,6 +326,11 @@ static uint8_t unregister_service(const void *cmd, uint16_t cmd_len, status = tester_unregister_csis(); break; #endif /* CONFIG_BT_CSIP_SET_MEMBER */ +#if defined(CONFIG_BT_CSIP_SET_COORDINATOR) + case BTP_SERVICE_ID_CSIP: + status = tester_unregister_csip(); + break; +#endif /* CONFIG_BT_CSIP_SET_COORDINATOR */ #if defined(CONFIG_BT_TBS_CLIENT) case BTP_SERVICE_ID_CCP: status = tester_unregister_ccp(); @@ -326,6 +341,11 @@ static uint8_t unregister_service(const void *cmd, uint16_t cmd_len, status = tester_unregister_cas(); break; #endif /* CONFIG_BT_CAP_ACCEPTOR */ +#if defined(CONFIG_BT_CAP_INITIATOR) + case BTP_SERVICE_ID_CAP: + status = tester_unregister_cap(); + break; +#endif /* CONFIG_BT_CAP_INITIATOR */ #if defined(CONFIG_BT_MCC) case BTP_SERVICE_ID_MCP: status = tester_unregister_mcp(); diff --git a/tests/bluetooth/tester/src/btp_csip.c b/tests/bluetooth/tester/src/btp_csip.c new file mode 100644 index 00000000000..307d007ba55 --- /dev/null +++ b/tests/bluetooth/tester/src/btp_csip.c @@ -0,0 +1,204 @@ +/* btp_csip.c - Bluetooth CSIP Tester */ + +/* + * Copyright (c) 2023 Codecoup + * + * SPDX-License-Identifier: Apache-2.0 + */ +#include "btp/btp.h" +#include + +#include +#define LOG_MODULE_NAME bttester_csip +LOG_MODULE_REGISTER(LOG_MODULE_NAME, CONFIG_BTTESTER_LOG_LEVEL); + +const struct bt_csip_set_coordinator_set_member *btp_csip_set_members[CONFIG_BT_MAX_CONN]; +static const struct bt_csip_set_coordinator_csis_inst *cur_csis_inst; + +static uint8_t btp_csip_supported_commands(const void *cmd, uint16_t cmd_len, + void *rsp, uint16_t *rsp_len) +{ + struct btp_csip_read_supported_commands_rp *rp = rsp; + + /* octet 0 */ + tester_set_bit(rp->data, BTP_CSIP_READ_SUPPORTED_COMMANDS); + tester_set_bit(rp->data, BTP_CSIP_START_ORDERED_ACCESS); + + *rsp_len = sizeof(*rp) + 1; + + return BTP_STATUS_SUCCESS; +} + +static void csip_set_coordinator_lock_set_cb(int err) +{ + LOG_DBG(""); +} + +static void csip_set_coordinator_lock_release_cb(int err) +{ + LOG_DBG(""); +} + +static void csip_discover_cb(struct bt_conn *conn, + const struct bt_csip_set_coordinator_set_member *member, + int err, size_t set_count) +{ + LOG_DBG(""); + + uint8_t conn_index; + + if (err != 0) { + LOG_DBG("discover failed (%d)", err); + return; + } + + if (set_count == 0) { + LOG_DBG("Device has no sets"); + return; + } + + conn_index = bt_conn_index(conn); + + LOG_DBG("Found %zu sets on member[%u]", set_count, conn_index); + + for (size_t i = 0U; i < set_count; i++) { + LOG_DBG("CSIS[%zu]: %p", i, &member->insts[i]); + LOG_DBG("Rank: %u", member->insts[i].info.rank); + LOG_DBG("Set Size: %u", member->insts[i].info.set_size); + LOG_DBG("Lockable: %u", member->insts[i].info.lockable); + } + + cur_csis_inst = &member->insts[0]; + btp_csip_set_members[conn_index] = member; +} + +static void csip_lock_changed_cb(struct bt_csip_set_coordinator_csis_inst *inst, + bool locked) +{ + LOG_DBG(""); +} + +static void csip_set_coordinator_ordered_access_cb( + const struct bt_csip_set_coordinator_set_info *set_info, int err, + bool locked, struct bt_csip_set_coordinator_set_member *member) +{ + LOG_DBG(""); + + if (err) { + LOG_ERR("Ordered access failed with err %d", err); + } else if (locked) { + LOG_DBG("Ordered access procedure locked member %p", member); + } else { + LOG_DBG("Ordered access procedure finished"); + } +} + +static struct bt_csip_set_coordinator_cb set_coordinator_cbs = { + .lock_set = csip_set_coordinator_lock_set_cb, + .release_set = csip_set_coordinator_lock_release_cb, + .discover = csip_discover_cb, + .lock_changed = csip_lock_changed_cb, + .ordered_access = csip_set_coordinator_ordered_access_cb +}; + +static bool csip_set_coordinator_oap_cb(const struct bt_csip_set_coordinator_set_info *set_info, + struct bt_csip_set_coordinator_set_member *members[], + size_t count) +{ + for (size_t i = 0; i < count; i++) { + LOG_DBG("Ordered access for members[%zu]: %p", i, members[i]); + } + + return true; +} + +static uint8_t btp_csip_discover(const void *cmd, uint16_t cmd_len, + void *rsp, uint16_t *rsp_len) +{ + int err; + struct bt_conn *conn; + const struct btp_csip_discover_cmd *cp = cmd; + + conn = bt_conn_lookup_addr_le(BT_ID_DEFAULT, &cp->address); + if (!conn) { + LOG_ERR("Unknown connection"); + + return BTP_STATUS_FAILED; + } + + err = bt_csip_set_coordinator_discover(conn); + bt_conn_unref(conn); + + return BTP_STATUS_VAL(err); +} + +static uint8_t btp_csip_start_ordered_access(const void *cmd, uint16_t cmd_len, + void *rsp, uint16_t *rsp_len) +{ + const struct bt_csip_set_coordinator_set_member *members[ARRAY_SIZE(btp_csip_set_members)]; + unsigned long member_count = 0; + int err; + + LOG_DBG(""); + + if (cur_csis_inst == NULL) { + LOG_ERR("No CISP instance available"); + + return BTP_STATUS_FAILED; + } + + for (size_t i = 0; i < (size_t)ARRAY_SIZE(btp_csip_set_members); i++) { + if (btp_csip_set_members[i] == NULL) { + continue; + } + + members[member_count++] = btp_csip_set_members[i]; + } + + if (member_count == 0) { + LOG_ERR("No set members available"); + + return BTP_STATUS_FAILED; + } + + err = bt_csip_set_coordinator_ordered_access(members, + member_count, + &cur_csis_inst->info, + csip_set_coordinator_oap_cb); + + return BTP_STATUS_VAL(err); +} + +static const struct btp_handler csip_handlers[] = { + { + .opcode = BTP_CSIP_READ_SUPPORTED_COMMANDS, + .index = BTP_INDEX_NONE, + .expect_len = 0, + .func = btp_csip_supported_commands + }, + { + .opcode = BTP_CSIP_DISCOVER, + .expect_len = sizeof(struct btp_csip_discover_cmd), + .func = btp_csip_discover + }, + { + .opcode = BTP_CSIP_START_ORDERED_ACCESS, + .expect_len = sizeof(struct btp_csip_start_ordered_access_cmd), + .func = btp_csip_start_ordered_access + }, +}; + +uint8_t tester_init_csip(void) +{ + bt_csip_set_coordinator_register_cb(&set_coordinator_cbs); + + tester_register_command_handlers(BTP_SERVICE_ID_CSIP, csip_handlers, + ARRAY_SIZE(csip_handlers)); + + return BTP_STATUS_SUCCESS; +} + +uint8_t tester_unregister_csip(void) +{ + return BTP_STATUS_SUCCESS; +} diff --git a/tests/bluetooth/tester/src/btp_gap.c b/tests/bluetooth/tester/src/btp_gap.c index 93958720d30..76d725a57ac 100644 --- a/tests/bluetooth/tester/src/btp_gap.c +++ b/tests/bluetooth/tester/src/btp_gap.c @@ -616,6 +616,11 @@ int tester_gap_create_adv_instance(struct bt_le_adv_param *param, uint8_t own_ad BTP_GAP_SETTINGS_EXTENDED_ADVERTISING)) { param->options |= BT_LE_ADV_OPT_EXT_ADV; if (ext_adv != NULL) { + err = bt_le_ext_adv_stop(ext_adv); + if (err != 0) { + return err; + } + err = bt_le_ext_adv_delete(ext_adv); if (err != 0) { return err; @@ -1563,11 +1568,8 @@ static uint8_t padv_set_data(const void *cmd, uint16_t cmd_len, } err = tester_gap_padv_set_data(padv, padv_len); - if (err != 0) { - return BTP_STATUS_FAILED; - } - return BTP_STATUS_SUCCESS; + return BTP_STATUS_VAL(err); } int tester_gap_padv_create_sync(struct bt_le_per_adv_sync_param *create_params) @@ -1625,11 +1627,8 @@ static uint8_t padv_create_sync(const void *cmd, uint16_t cmd_len, } err = tester_gap_padv_create_sync(&create_params); - if (err != 0) { - return BTP_STATUS_FAILED; - } - return BTP_STATUS_SUCCESS; + return BTP_STATUS_VAL(err); } static uint8_t padv_sync_transfer_set_info(const void *cmd, uint16_t cmd_len, From 2b0e39dfa5cbddf801c8adf8de79ee4e900bb402 Mon Sep 17 00:00:00 2001 From: Emil Gydesen Date: Mon, 2 Oct 2023 16:59:43 +0200 Subject: [PATCH 2864/3723] Bluetooth: Audio: Add bt_audio_codec unset functions Add functions to unset, or remove, specific codec LTV structure from codec_cfgs or codec_caps. Signed-off-by: Emil Gydesen --- include/zephyr/bluetooth/audio/audio.h | 55 ++++ subsys/bluetooth/audio/codec.c | 133 ++++++++ tests/bluetooth/audio/codec/src/main.c | 416 +++++++++++++++++++++++++ 3 files changed, 604 insertions(+) diff --git a/include/zephyr/bluetooth/audio/audio.h b/include/zephyr/bluetooth/audio/audio.h index f6885c41a83..772e93588fa 100644 --- a/include/zephyr/bluetooth/audio/audio.h +++ b/include/zephyr/bluetooth/audio/audio.h @@ -823,6 +823,20 @@ int bt_audio_codec_cfg_set_val(struct bt_audio_codec_cfg *codec_cfg, enum bt_audio_codec_config_type type, const uint8_t *data, size_t data_len); +/** + * @brief Unset a specific codec configuration value + * + * The type and the value will be removed from the codec configuration. + * + * @param codec_cfg The codec data to set the value in. + * @param type The type id to unset. + * + * @retval The data_len of @p codec_cfg on success + * @retval -EINVAL if arguments are invalid + */ +int bt_audio_codec_cfg_unset_val(struct bt_audio_codec_cfg *codec_cfg, + enum bt_audio_codec_config_type type); + /** @brief Lookup a specific metadata value based on type * * @@ -853,6 +867,19 @@ int bt_audio_codec_cfg_meta_set_val(struct bt_audio_codec_cfg *codec_cfg, enum bt_audio_metadata_type type, const uint8_t *data, size_t data_len); +/** + * @brief Unset a specific codec configuration metadata value + * + * The type and the value will be removed from the codec configuration metadata. + * + * @param codec_cfg The codec data to set the value in. + * @param type The type id to unset. + * + * @retval The meta_len of @p codec_cfg on success + * @retval -EINVAL if arguments are invalid + */ +int bt_audio_codec_cfg_meta_unset_val(struct bt_audio_codec_cfg *codec_cfg, + enum bt_audio_metadata_type type); /** @brief Extract preferred contexts * * See @ref BT_AUDIO_METADATA_TYPE_PREF_CONTEXT for more information about this value. @@ -1188,6 +1215,20 @@ int bt_audio_codec_cap_set_val(struct bt_audio_codec_cap *codec_cap, enum bt_audio_codec_capability_type type, const uint8_t *data, size_t data_len); +/** + * @brief Unset a specific codec capability value + * + * The type and the value will be removed from the codec capability. + * + * @param codec_cap The codec data to set the value in. + * @param type The type id to unset. + * + * @retval The data_len of @p codec_cap on success + * @retval -EINVAL if arguments are invalid + */ +int bt_audio_codec_cap_unset_val(struct bt_audio_codec_cap *codec_cap, + enum bt_audio_codec_capability_type type); + /** * @brief Extract the frequency from a codec capability. * @@ -1346,6 +1387,20 @@ int bt_audio_codec_cap_meta_set_val(struct bt_audio_codec_cap *codec_cap, enum bt_audio_metadata_type type, const uint8_t *data, size_t data_len); +/** + * @brief Unset a specific codec capability metadata value + * + * The type and the value will be removed from the codec capability metadata. + * + * @param codec_cap The codec data to set the value in. + * @param type The type id to unset. + * + * @retval The meta_len of @p codec_cap on success + * @retval -EINVAL if arguments are invalid + */ +int bt_audio_codec_cap_meta_unset_val(struct bt_audio_codec_cap *codec_cap, + enum bt_audio_metadata_type type); + /** @brief Extract preferred contexts * * See @ref BT_AUDIO_METADATA_TYPE_PREF_CONTEXT for more information about this value. diff --git a/subsys/bluetooth/audio/codec.c b/subsys/bluetooth/audio/codec.c index 3f5f2b56629..6eec848a9b4 100644 --- a/subsys/bluetooth/audio/codec.c +++ b/subsys/bluetooth/audio/codec.c @@ -224,6 +224,44 @@ static int ltv_set_val(struct net_buf_simple *buf, uint8_t type, const uint8_t * return buf->len; } + +static int ltv_unset_val(struct net_buf_simple *buf, uint8_t type) +{ + for (uint16_t i = 0U; i < buf->len;) { + uint8_t *ltv_start = &buf->data[i]; + const uint8_t len = buf->data[i++]; + const uint8_t data_type = buf->data[i++]; + const uint8_t value_len = len - sizeof(data_type); + + if (data_type == type) { + const uint8_t ltv_size = value_len + sizeof(data_type) + sizeof(len); + uint8_t *value = &buf->data[i]; + + /* Check if this is not the last value in the buffer */ + if (value + value_len != buf->data + buf->len) { + uint8_t *next_data_start; + uint8_t data_len_to_move; + + next_data_start = value + value_len; + data_len_to_move = buf->len - (next_data_start - buf->data); + memmove(ltv_start, next_data_start, data_len_to_move); + + LOG_ERR("buf->data %p, ltv_start %p, value_len %u next_data_start " + "%p data_len_to_move %u", + buf->data, ltv_start, value_len, next_data_start, + data_len_to_move); + } /* else just reduce the length of the buffer */ + + buf->len -= ltv_size; + + return buf->len; + } + + i += value_len; + } + + return buf->len; +} #endif /* CONFIG_BT_AUDIO_CODEC_CFG_MAX_DATA_SIZE > 0 || \ * CONFIG_BT_AUDIO_CODEC_CFG_MAX_METADATA_SIZE > 0 || \ * CONFIG_BT_AUDIO_CODEC_CAP_MAX_DATA_SIZE > 0 || \ @@ -310,6 +348,27 @@ int bt_audio_codec_cfg_set_val(struct bt_audio_codec_cfg *codec_cfg, return ret; } +int bt_audio_codec_cfg_unset_val(struct bt_audio_codec_cfg *codec_cfg, + enum bt_audio_codec_config_type type) +{ + struct net_buf_simple buf; + int ret; + + CHECKIF(codec_cfg == NULL) { + LOG_DBG("codec_cfg is NULL"); + return -EINVAL; + } + + init_net_buf_simple_from_codec_cfg(&buf, codec_cfg); + + ret = ltv_unset_val(&buf, type); + if (ret >= 0) { + codec_cfg->data_len = ret; + } + + return ret; +} + int bt_audio_codec_cfg_get_freq(const struct bt_audio_codec_cfg *codec_cfg) { enum bt_audio_codec_config_freq freq; @@ -595,6 +654,21 @@ static int codec_meta_set_val(uint8_t meta[], size_t meta_len, size_t meta_size, return ltv_set_val(&buf, (uint8_t)type, data, data_len); } +static int codec_meta_unset_val(uint8_t meta[], size_t meta_len, size_t meta_size, + enum bt_audio_metadata_type type) +{ + struct net_buf_simple buf; + + CHECKIF(meta == NULL) { + LOG_DBG("meta is NULL"); + return -EINVAL; + } + + init_net_buf_simple_from_meta(&buf, meta, meta_len, meta_size); + + return ltv_unset_val(&buf, type); +} + static int codec_meta_get_pref_context(const uint8_t meta[], size_t meta_len) { const uint8_t *data; @@ -1083,6 +1157,25 @@ int bt_audio_codec_cfg_meta_set_val(struct bt_audio_codec_cfg *codec_cfg, return ret; } +int bt_audio_codec_cfg_meta_unset_val(struct bt_audio_codec_cfg *codec_cfg, + enum bt_audio_metadata_type type) +{ + int ret; + + CHECKIF(codec_cfg == NULL) { + LOG_DBG("codec_cfg is NULL"); + return -EINVAL; + } + + ret = codec_meta_unset_val(codec_cfg->meta, codec_cfg->meta_len, + ARRAY_SIZE(codec_cfg->meta), type); + if (ret >= 0) { + codec_cfg->meta_len = ret; + } + + return ret; +} + int bt_audio_codec_cfg_meta_get_pref_context(const struct bt_audio_codec_cfg *codec_cfg) { CHECKIF(codec_cfg == NULL) { @@ -1391,6 +1484,25 @@ int bt_audio_codec_cap_meta_set_val(struct bt_audio_codec_cap *codec_cap, return ret; } +int bt_audio_codec_cap_meta_unset_val(struct bt_audio_codec_cap *codec_cap, + enum bt_audio_metadata_type type) +{ + int ret; + + CHECKIF(codec_cap == NULL) { + LOG_DBG("codec_cap is NULL"); + return -EINVAL; + } + + ret = codec_meta_unset_val(codec_cap->meta, codec_cap->meta_len, + ARRAY_SIZE(codec_cap->meta), type); + if (ret >= 0) { + codec_cap->meta_len = ret; + } + + return ret; +} + int bt_audio_codec_cap_meta_get_pref_context(const struct bt_audio_codec_cap *codec_cap) { CHECKIF(codec_cap == NULL) { @@ -1750,6 +1862,27 @@ int bt_audio_codec_cap_set_val(struct bt_audio_codec_cap *codec_cap, return ret; } +int bt_audio_codec_cap_unset_val(struct bt_audio_codec_cap *codec_cap, + enum bt_audio_codec_capability_type type) +{ + struct net_buf_simple buf; + int ret; + + CHECKIF(codec_cap == NULL) { + LOG_DBG("codec_cap is NULL"); + return -EINVAL; + } + + init_net_buf_simple_from_codec_cap(&buf, codec_cap); + + ret = ltv_unset_val(&buf, type); + if (ret >= 0) { + codec_cap->data_len = ret; + } + + return ret; +} + int bt_audio_codec_cap_get_freq(const struct bt_audio_codec_cap *codec_cap) { const uint8_t *data; diff --git a/tests/bluetooth/audio/codec/src/main.c b/tests/bluetooth/audio/codec/src/main.c index 3b909e4582f..73d1362956a 100644 --- a/tests/bluetooth/audio/codec/src/main.c +++ b/tests/bluetooth/audio/codec/src/main.c @@ -15,6 +15,89 @@ DEFINE_FFF_GLOBALS; ZTEST_SUITE(audio_codec_test_suite, NULL, NULL, NULL, NULL, NULL); +ZTEST(audio_codec_test_suite, test_bt_audio_codec_cfg_get_val) +{ + struct bt_audio_codec_cfg codec_cfg = + BT_AUDIO_CODEC_CFG(BT_HCI_CODING_FORMAT_LC3, 0x0000, 0x0000, + {BT_AUDIO_CODEC_DATA(BT_AUDIO_CODEC_CONFIG_LC3_FREQ, + BT_AUDIO_CODEC_CONFIG_LC3_FREQ_16KHZ)}, + {}); + const uint8_t expected_data = BT_AUDIO_CODEC_CONFIG_LC3_FREQ_16KHZ; + const uint8_t *data; + int ret; + + ret = bt_audio_codec_cfg_get_val(&codec_cfg, BT_AUDIO_CODEC_CONFIG_LC3_FREQ, &data); + zassert_equal(ret, sizeof(expected_data), "Unexpected return value %d", ret); + zassert_equal(data[0], expected_data, "Unexpected return value %d", ret); +} + +ZTEST(audio_codec_test_suite, test_bt_audio_codec_cfg_set_val) +{ + struct bt_audio_codec_cfg codec_cfg = + BT_AUDIO_CODEC_CFG(BT_HCI_CODING_FORMAT_LC3, 0x0000, 0x0000, + {BT_AUDIO_CODEC_DATA(BT_AUDIO_CODEC_CONFIG_LC3_FREQ, + BT_AUDIO_CODEC_CONFIG_LC3_FREQ_16KHZ)}, + {}); + const uint8_t new_expected_data = BT_AUDIO_CODEC_CONFIG_LC3_FREQ_48KHZ; + const uint8_t expected_data = BT_AUDIO_CODEC_CONFIG_LC3_FREQ_16KHZ; + const uint8_t *data; + int ret; + + ret = bt_audio_codec_cfg_get_val(&codec_cfg, BT_AUDIO_CODEC_CONFIG_LC3_FREQ, &data); + zassert_equal(ret, sizeof(expected_data), "Unexpected return value %d", ret); + zassert_equal(data[0], expected_data, "Unexpected return value %d", ret); + + ret = bt_audio_codec_cfg_set_val(&codec_cfg, BT_AUDIO_CODEC_CONFIG_LC3_FREQ, + &new_expected_data, sizeof(new_expected_data)); + zassert_true(ret > 0, "Unexpected return value %d", ret); + + ret = bt_audio_codec_cfg_get_val(&codec_cfg, BT_AUDIO_CODEC_CONFIG_LC3_FREQ, &data); + zassert_equal(ret, sizeof(new_expected_data), "Unexpected return value %d", ret); + zassert_equal(data[0], new_expected_data, "Unexpected data value %u", data[0]); +} + +ZTEST(audio_codec_test_suite, test_bt_audio_codec_cfg_set_val_new_value) +{ + struct bt_audio_codec_cfg codec_cfg = + BT_AUDIO_CODEC_CFG(BT_HCI_CODING_FORMAT_LC3, 0x0000, 0x0000, {}, {}); + const uint8_t new_expected_data = BT_AUDIO_CODEC_CONFIG_LC3_FREQ_48KHZ; + const uint8_t *data; + int ret; + + ret = bt_audio_codec_cfg_get_val(&codec_cfg, BT_AUDIO_CODEC_CONFIG_LC3_FREQ, &data); + zassert_equal(ret, 0, "Unexpected return value %d", ret); + + ret = bt_audio_codec_cfg_set_val(&codec_cfg, BT_AUDIO_CODEC_CONFIG_LC3_FREQ, + &new_expected_data, sizeof(new_expected_data)); + zassert_true(ret > 0, "Unexpected return value %d", ret); + + ret = bt_audio_codec_cfg_get_val(&codec_cfg, BT_AUDIO_CODEC_CONFIG_LC3_FREQ, &data); + zassert_equal(ret, sizeof(new_expected_data), "Unexpected return value %d", ret); + zassert_equal(data[0], new_expected_data, "Unexpected return value %d", ret); +} + +ZTEST(audio_codec_test_suite, test_bt_audio_codec_cfg_unset_val) +{ + struct bt_audio_codec_cfg codec_cfg = + BT_AUDIO_CODEC_CFG(BT_HCI_CODING_FORMAT_LC3, 0x0000, 0x0000, + {BT_AUDIO_CODEC_DATA(BT_AUDIO_CODEC_CONFIG_LC3_FREQ, + BT_AUDIO_CODEC_CONFIG_LC3_FREQ_16KHZ)}, + {}); + const uint8_t expected_data = BT_AUDIO_CODEC_CONFIG_LC3_FREQ_16KHZ; + const uint8_t *data; + int ret; + + ret = bt_audio_codec_cfg_get_val(&codec_cfg, BT_AUDIO_CODEC_CONFIG_LC3_FREQ, &data); + zassert_equal(ret, sizeof(expected_data), "Unexpected return value %d", ret); + zassert_equal(data[0], expected_data, "Unexpected return value %d", ret); + + ret = bt_audio_codec_cfg_unset_val(&codec_cfg, BT_AUDIO_CODEC_CONFIG_LC3_FREQ); + zassert_true(ret >= 0, "Unexpected return value %d", ret); + + ret = bt_audio_codec_cfg_get_val(&codec_cfg, BT_AUDIO_CODEC_CONFIG_LC3_FREQ, &data); + zassert_equal(ret, 0, "Unexpected return value %d", ret); +} + ZTEST(audio_codec_test_suite, test_bt_audio_codec_cfg_freq_to_freq_hz) { const struct freq_test_input { @@ -234,6 +317,93 @@ ZTEST(audio_codec_test_suite, test_bt_audio_codec_cfg_set_frame_blocks_per_sdu) zassert_equal(ret, 2, "Unexpected return value %d", ret); } +ZTEST(audio_codec_test_suite, test_bt_audio_codec_cfg_meta_get_val) +{ + struct bt_audio_codec_cfg codec_cfg = + BT_AUDIO_CODEC_CFG(BT_HCI_CODING_FORMAT_LC3, 0x0000, 0x0000, {}, + {BT_AUDIO_CODEC_DATA(BT_AUDIO_METADATA_TYPE_PARENTAL_RATING, + BT_AUDIO_PARENTAL_RATING_AGE_10_OR_ABOVE)}); + const uint8_t expected_data = BT_AUDIO_PARENTAL_RATING_AGE_10_OR_ABOVE; + const uint8_t *data; + int ret; + + ret = bt_audio_codec_cfg_meta_get_val(&codec_cfg, BT_AUDIO_METADATA_TYPE_PARENTAL_RATING, + &data); + zassert_equal(ret, sizeof(expected_data), "Unexpected return value %d", ret); + zassert_equal(data[0], expected_data, "Unexpected return value %d", ret); +} + +ZTEST(audio_codec_test_suite, test_bt_audio_codec_cfg_meta_set_val) +{ + struct bt_audio_codec_cfg codec_cfg = + BT_AUDIO_CODEC_CFG(BT_HCI_CODING_FORMAT_LC3, 0x0000, 0x0000, {}, + {BT_AUDIO_CODEC_DATA(BT_AUDIO_METADATA_TYPE_PARENTAL_RATING, + BT_AUDIO_PARENTAL_RATING_AGE_10_OR_ABOVE)}); + const uint8_t new_expected_data = BT_AUDIO_PARENTAL_RATING_AGE_13_OR_ABOVE; + const uint8_t expected_data = BT_AUDIO_PARENTAL_RATING_AGE_10_OR_ABOVE; + const uint8_t *data; + int ret; + + ret = bt_audio_codec_cfg_meta_get_val(&codec_cfg, BT_AUDIO_METADATA_TYPE_PARENTAL_RATING, + &data); + zassert_equal(ret, sizeof(expected_data), "Unexpected return value %d", ret); + zassert_equal(data[0], expected_data, "Unexpected return value %d", ret); + + ret = bt_audio_codec_cfg_meta_set_val(&codec_cfg, BT_AUDIO_METADATA_TYPE_PARENTAL_RATING, + &new_expected_data, sizeof(new_expected_data)); + zassert_true(ret > 0, "Unexpected return value %d", ret); + + ret = bt_audio_codec_cfg_meta_get_val(&codec_cfg, BT_AUDIO_METADATA_TYPE_PARENTAL_RATING, + &data); + zassert_equal(ret, sizeof(new_expected_data), "Unexpected return value %d", ret); + zassert_equal(data[0], new_expected_data, "Unexpected data value %u", data[0]); +} + +ZTEST(audio_codec_test_suite, test_bt_audio_codec_cfg_meta_set_val_new) +{ + struct bt_audio_codec_cfg codec_cfg = + BT_AUDIO_CODEC_CFG(BT_HCI_CODING_FORMAT_LC3, 0x0000, 0x0000, {}, {}); + const uint8_t new_expected_data = BT_AUDIO_PARENTAL_RATING_AGE_13_OR_ABOVE; + const uint8_t *data; + int ret; + + ret = bt_audio_codec_cfg_meta_get_val(&codec_cfg, BT_AUDIO_METADATA_TYPE_PARENTAL_RATING, + &data); + zassert_equal(ret, -ENODATA, "Unexpected return value %d", ret); + + ret = bt_audio_codec_cfg_meta_set_val(&codec_cfg, BT_AUDIO_METADATA_TYPE_PARENTAL_RATING, + &new_expected_data, sizeof(new_expected_data)); + zassert_true(ret > 0, "Unexpected return value %d", ret); + + ret = bt_audio_codec_cfg_meta_get_val(&codec_cfg, BT_AUDIO_METADATA_TYPE_PARENTAL_RATING, + &data); + zassert_equal(ret, sizeof(new_expected_data), "Unexpected return value %d", ret); + zassert_equal(data[0], new_expected_data, "Unexpected return value %d", ret); +} + +ZTEST(audio_codec_test_suite, test_bt_audio_codec_cfg_meta_unset_val) +{ + struct bt_audio_codec_cfg codec_cfg = + BT_AUDIO_CODEC_CFG(BT_HCI_CODING_FORMAT_LC3, 0x0000, 0x0000, {}, + {BT_AUDIO_CODEC_DATA(BT_AUDIO_METADATA_TYPE_PARENTAL_RATING, + BT_AUDIO_PARENTAL_RATING_AGE_10_OR_ABOVE)}); + const uint8_t expected_data = BT_AUDIO_PARENTAL_RATING_AGE_10_OR_ABOVE; + const uint8_t *data; + int ret; + + ret = bt_audio_codec_cfg_meta_get_val(&codec_cfg, BT_AUDIO_METADATA_TYPE_PARENTAL_RATING, + &data); + zassert_equal(ret, sizeof(expected_data), "Unexpected return value %d", ret); + zassert_equal(data[0], expected_data, "Unexpected return value %d", ret); + + ret = bt_audio_codec_cfg_meta_unset_val(&codec_cfg, BT_AUDIO_METADATA_TYPE_PARENTAL_RATING); + zassert_true(ret >= 0, "Unexpected return value %d", ret); + + ret = bt_audio_codec_cfg_meta_get_val(&codec_cfg, BT_AUDIO_METADATA_TYPE_PARENTAL_RATING, + &data); + zassert_equal(ret, -ENODATA, "Unexpected return value %d", ret); +} + ZTEST(audio_codec_test_suite, test_bt_audio_codec_cfg_meta_get_pref_context) { const enum bt_audio_context ctx = @@ -705,6 +875,89 @@ ZTEST(audio_codec_test_suite, test_bt_audio_codec_cfg_meta_set_vendor) zassert_mem_equal(new_expected_data, extended_meta, ARRAY_SIZE(new_expected_data)); } +ZTEST(audio_codec_test_suite, test_bt_audio_codec_cap_get_val) +{ + struct bt_audio_codec_cap codec_cap = + BT_AUDIO_CODEC_CAP(BT_HCI_CODING_FORMAT_LC3, 0x0000, 0x0000, + {BT_AUDIO_CODEC_DATA(BT_AUDIO_CODEC_CONFIG_LC3_FREQ, + BT_AUDIO_CODEC_CONFIG_LC3_FREQ_16KHZ)}, + {}); + const uint8_t expected_data = BT_AUDIO_CODEC_CONFIG_LC3_FREQ_16KHZ; + const uint8_t *data; + int ret; + + ret = bt_audio_codec_cap_get_val(&codec_cap, BT_AUDIO_CODEC_CONFIG_LC3_FREQ, &data); + zassert_equal(ret, sizeof(expected_data), "Unexpected return value %d", ret); + zassert_equal(data[0], expected_data, "Unexpected return value %d", ret); +} + +ZTEST(audio_codec_test_suite, test_bt_audio_codec_cap_set_val) +{ + struct bt_audio_codec_cap codec_cap = + BT_AUDIO_CODEC_CAP(BT_HCI_CODING_FORMAT_LC3, 0x0000, 0x0000, + {BT_AUDIO_CODEC_DATA(BT_AUDIO_CODEC_CONFIG_LC3_FREQ, + BT_AUDIO_CODEC_CONFIG_LC3_FREQ_16KHZ)}, + {}); + const uint8_t new_expected_data = BT_AUDIO_CODEC_CONFIG_LC3_FREQ_48KHZ; + const uint8_t expected_data = BT_AUDIO_CODEC_CONFIG_LC3_FREQ_16KHZ; + const uint8_t *data; + int ret; + + ret = bt_audio_codec_cap_get_val(&codec_cap, BT_AUDIO_CODEC_CONFIG_LC3_FREQ, &data); + zassert_equal(ret, sizeof(expected_data), "Unexpected return value %d", ret); + zassert_equal(data[0], expected_data, "Unexpected return value %d", ret); + + ret = bt_audio_codec_cap_set_val(&codec_cap, BT_AUDIO_CODEC_CONFIG_LC3_FREQ, + &new_expected_data, sizeof(new_expected_data)); + zassert_true(ret > 0, "Unexpected return value %d", ret); + + ret = bt_audio_codec_cap_get_val(&codec_cap, BT_AUDIO_CODEC_CONFIG_LC3_FREQ, &data); + zassert_equal(ret, sizeof(new_expected_data), "Unexpected return value %d", ret); + zassert_equal(data[0], new_expected_data, "Unexpected data value %u", data[0]); +} + +ZTEST(audio_codec_test_suite, test_bt_audio_codec_cap_set_val_new) +{ + struct bt_audio_codec_cap codec_cap = + BT_AUDIO_CODEC_CAP(BT_HCI_CODING_FORMAT_LC3, 0x0000, 0x0000, {}, {}); + const uint8_t new_expected_data = BT_AUDIO_CODEC_CONFIG_LC3_FREQ_48KHZ; + const uint8_t *data; + int ret; + + ret = bt_audio_codec_cap_get_val(&codec_cap, BT_AUDIO_CODEC_CONFIG_LC3_FREQ, &data); + zassert_equal(ret, 0, "Unexpected return value %d", ret); + + ret = bt_audio_codec_cap_set_val(&codec_cap, BT_AUDIO_CODEC_CONFIG_LC3_FREQ, + &new_expected_data, sizeof(new_expected_data)); + zassert_true(ret > 0, "Unexpected return value %d", ret); + + ret = bt_audio_codec_cap_get_val(&codec_cap, BT_AUDIO_CODEC_CONFIG_LC3_FREQ, &data); + zassert_equal(ret, sizeof(new_expected_data), "Unexpected return value %d", ret); + zassert_equal(data[0], new_expected_data, "Unexpected return value %d", ret); +} + +ZTEST(audio_codec_test_suite, test_bt_audio_codec_cap_unset_val) +{ + struct bt_audio_codec_cap codec_cap = + BT_AUDIO_CODEC_CAP(BT_HCI_CODING_FORMAT_LC3, 0x0000, 0x0000, + {BT_AUDIO_CODEC_DATA(BT_AUDIO_CODEC_CONFIG_LC3_FREQ, + BT_AUDIO_CODEC_CONFIG_LC3_FREQ_16KHZ)}, + {}); + const uint8_t expected_data = BT_AUDIO_CODEC_CONFIG_LC3_FREQ_16KHZ; + const uint8_t *data; + int ret; + + ret = bt_audio_codec_cap_get_val(&codec_cap, BT_AUDIO_CODEC_CONFIG_LC3_FREQ, &data); + zassert_equal(ret, sizeof(expected_data), "Unexpected return value %d", ret); + zassert_equal(data[0], expected_data, "Unexpected return value %d", ret); + + ret = bt_audio_codec_cap_unset_val(&codec_cap, BT_AUDIO_CODEC_CONFIG_LC3_FREQ); + zassert_true(ret >= 0, "Unexpected return value %d", ret); + + ret = bt_audio_codec_cap_get_val(&codec_cap, BT_AUDIO_CODEC_CONFIG_LC3_FREQ, &data); + zassert_equal(ret, 0, "Unexpected return value %d", ret); +} + ZTEST(audio_codec_test_suite, test_bt_audio_codec_cap_get_freq) { const struct bt_audio_codec_cap codec_cap = BT_AUDIO_CODEC_CAP_LC3( @@ -881,6 +1134,169 @@ ZTEST(audio_codec_test_suite, test_bt_audio_codec_cap_set_max_codec_frames_per_s zassert_equal(ret, 4, "Unexpected return value %d", ret); } +ZTEST(audio_codec_test_suite, test_bt_audio_codec_cap_meta_get_val) +{ + struct bt_audio_codec_cap codec_cap = + BT_AUDIO_CODEC_CAP(BT_HCI_CODING_FORMAT_LC3, 0x0000, 0x0000, {}, + {BT_AUDIO_CODEC_DATA(BT_AUDIO_METADATA_TYPE_PARENTAL_RATING, + BT_AUDIO_PARENTAL_RATING_AGE_10_OR_ABOVE)}); + const uint8_t expected_data = BT_AUDIO_PARENTAL_RATING_AGE_10_OR_ABOVE; + const uint8_t *data; + int ret; + + ret = bt_audio_codec_cap_meta_get_val(&codec_cap, BT_AUDIO_METADATA_TYPE_PARENTAL_RATING, + &data); + zassert_equal(ret, sizeof(expected_data), "Unexpected return value %d", ret); + zassert_equal(data[0], expected_data, "Unexpected return value %d", ret); +} + +ZTEST(audio_codec_test_suite, test_bt_audio_codec_cap_meta_set_val) +{ + struct bt_audio_codec_cap codec_cap = + BT_AUDIO_CODEC_CAP(BT_HCI_CODING_FORMAT_LC3, 0x0000, 0x0000, {}, + {BT_AUDIO_CODEC_DATA(BT_AUDIO_METADATA_TYPE_PARENTAL_RATING, + BT_AUDIO_PARENTAL_RATING_AGE_10_OR_ABOVE)}); + const uint8_t new_expected_data = BT_AUDIO_PARENTAL_RATING_AGE_13_OR_ABOVE; + const uint8_t expected_data = BT_AUDIO_PARENTAL_RATING_AGE_10_OR_ABOVE; + const uint8_t *data; + int ret; + + ret = bt_audio_codec_cap_meta_get_val(&codec_cap, BT_AUDIO_METADATA_TYPE_PARENTAL_RATING, + &data); + zassert_equal(ret, sizeof(expected_data), "Unexpected return value %d", ret); + zassert_equal(data[0], expected_data, "Unexpected return value %d", ret); + + ret = bt_audio_codec_cap_meta_set_val(&codec_cap, BT_AUDIO_METADATA_TYPE_PARENTAL_RATING, + &new_expected_data, sizeof(new_expected_data)); + zassert_true(ret > 0, "Unexpected return value %d", ret); + + ret = bt_audio_codec_cap_meta_get_val(&codec_cap, BT_AUDIO_METADATA_TYPE_PARENTAL_RATING, + &data); + zassert_equal(ret, sizeof(new_expected_data), "Unexpected return value %d", ret); + zassert_equal(data[0], new_expected_data, "Unexpected data value %u", data[0]); +} + +ZTEST(audio_codec_test_suite, test_bt_audio_codec_cap_meta_set_val_new) +{ + struct bt_audio_codec_cap codec_cap = + BT_AUDIO_CODEC_CAP(BT_HCI_CODING_FORMAT_LC3, 0x0000, 0x0000, {}, {}); + const uint8_t new_expected_data = BT_AUDIO_PARENTAL_RATING_AGE_13_OR_ABOVE; + const uint8_t *data; + int ret; + + ret = bt_audio_codec_cap_meta_get_val(&codec_cap, BT_AUDIO_METADATA_TYPE_PARENTAL_RATING, + &data); + zassert_equal(ret, -ENODATA, "Unexpected return value %d", ret); + + ret = bt_audio_codec_cap_meta_set_val(&codec_cap, BT_AUDIO_METADATA_TYPE_PARENTAL_RATING, + &new_expected_data, sizeof(new_expected_data)); + zassert_true(ret > 0, "Unexpected return value %d", ret); + + ret = bt_audio_codec_cap_meta_get_val(&codec_cap, BT_AUDIO_METADATA_TYPE_PARENTAL_RATING, + &data); + zassert_equal(ret, sizeof(new_expected_data), "Unexpected return value %d", ret); + zassert_equal(data[0], new_expected_data, "Unexpected return value %d", ret); +} + +ZTEST(audio_codec_test_suite, test_bt_audio_codec_cap_meta_unset_val_only) +{ + struct bt_audio_codec_cap codec_cap = + BT_AUDIO_CODEC_CAP(BT_HCI_CODING_FORMAT_LC3, 0x0000, 0x0000, {}, + {BT_AUDIO_CODEC_DATA(BT_AUDIO_METADATA_TYPE_PARENTAL_RATING, + BT_AUDIO_PARENTAL_RATING_AGE_10_OR_ABOVE)}); + const uint8_t expected_data = BT_AUDIO_PARENTAL_RATING_AGE_10_OR_ABOVE; + const uint8_t *data; + int ret; + + ret = bt_audio_codec_cap_meta_get_val(&codec_cap, BT_AUDIO_METADATA_TYPE_PARENTAL_RATING, + &data); + zassert_equal(ret, sizeof(expected_data), "Unexpected return value %d", ret); + zassert_equal(data[0], expected_data, "Unexpected return value %d", ret); + + ret = bt_audio_codec_cap_meta_unset_val(&codec_cap, BT_AUDIO_METADATA_TYPE_PARENTAL_RATING); + zassert_true(ret >= 0, "Unexpected return value %d", ret); + + ret = bt_audio_codec_cap_meta_get_val(&codec_cap, BT_AUDIO_METADATA_TYPE_PARENTAL_RATING, + &data); + zassert_equal(ret, -ENODATA, "Unexpected return value %d", ret); +} + +/* Providing multiple BT_AUDIO_CODEC_DATA to BT_AUDIO_CODEC_CAP without packing it in a macro + * cause compile issue, so define a macro to denote 3 types of metadata for the meta_unset tests + */ +#define TRIPLE_META_DATA \ + { \ + BT_AUDIO_CODEC_DATA(BT_AUDIO_METADATA_TYPE_PARENTAL_RATING, \ + BT_AUDIO_PARENTAL_RATING_AGE_10_OR_ABOVE), \ + BT_AUDIO_CODEC_DATA(BT_AUDIO_METADATA_TYPE_PREF_CONTEXT, \ + BT_BYTES_LIST_LE16(BT_AUDIO_CONTEXT_TYPE_UNSPECIFIED)), \ + BT_AUDIO_CODEC_DATA(BT_AUDIO_METADATA_TYPE_STREAM_CONTEXT, \ + BT_BYTES_LIST_LE16(BT_AUDIO_CONTEXT_TYPE_UNSPECIFIED)) \ + } + +ZTEST(audio_codec_test_suite, test_bt_audio_codec_cap_meta_unset_val_first) +{ + struct bt_audio_codec_cap codec_cap = + BT_AUDIO_CODEC_CAP(BT_HCI_CODING_FORMAT_LC3, 0x0000, 0x0000, {}, TRIPLE_META_DATA); + const uint8_t expected_data = BT_AUDIO_PARENTAL_RATING_AGE_10_OR_ABOVE; + const uint8_t *data; + int ret; + + ret = bt_audio_codec_cap_meta_get_val(&codec_cap, BT_AUDIO_METADATA_TYPE_PARENTAL_RATING, + &data); + zassert_equal(ret, sizeof(expected_data), "Unexpected return value %d", ret); + zassert_equal(data[0], expected_data, "Unexpected return value %d", ret); + + ret = bt_audio_codec_cap_meta_unset_val(&codec_cap, BT_AUDIO_METADATA_TYPE_PARENTAL_RATING); + zassert_true(ret >= 0, "Unexpected return value %d", ret); + + ret = bt_audio_codec_cap_meta_get_val(&codec_cap, BT_AUDIO_METADATA_TYPE_PARENTAL_RATING, + &data); + zassert_equal(ret, -ENODATA, "Unexpected return value %d", ret); +} + +ZTEST(audio_codec_test_suite, test_bt_audio_codec_cap_meta_unset_val_middle) +{ + struct bt_audio_codec_cap codec_cap = + BT_AUDIO_CODEC_CAP(BT_HCI_CODING_FORMAT_LC3, 0x0000, 0x0000, {}, TRIPLE_META_DATA); + const uint16_t expected_data = BT_AUDIO_CONTEXT_TYPE_UNSPECIFIED; + const uint8_t *data; + int ret; + + ret = bt_audio_codec_cap_meta_get_val(&codec_cap, BT_AUDIO_METADATA_TYPE_PREF_CONTEXT, + &data); + zassert_equal(ret, sizeof(expected_data), "Unexpected return value %d", ret); + zassert_equal(sys_get_le16(data), expected_data, "Unexpected return value %d", ret); + + ret = bt_audio_codec_cap_meta_unset_val(&codec_cap, BT_AUDIO_METADATA_TYPE_PREF_CONTEXT); + zassert_true(ret >= 0, "Unexpected return value %d", ret); + + ret = bt_audio_codec_cap_meta_get_val(&codec_cap, BT_AUDIO_METADATA_TYPE_PREF_CONTEXT, + &data); + zassert_equal(ret, -ENODATA, "Unexpected return value %d", ret); +} + +ZTEST(audio_codec_test_suite, test_bt_audio_codec_cap_meta_unset_val_last) +{ + struct bt_audio_codec_cap codec_cap = + BT_AUDIO_CODEC_CAP(BT_HCI_CODING_FORMAT_LC3, 0x0000, 0x0000, {}, TRIPLE_META_DATA); + const uint16_t expected_data = BT_AUDIO_CONTEXT_TYPE_UNSPECIFIED; + const uint8_t *data; + int ret; + + ret = bt_audio_codec_cap_meta_get_val(&codec_cap, BT_AUDIO_METADATA_TYPE_STREAM_CONTEXT, + &data); + zassert_equal(ret, sizeof(expected_data), "Unexpected return value %d", ret); + zassert_equal(sys_get_le16(data), expected_data, "Unexpected return value %d", ret); + + ret = bt_audio_codec_cap_meta_unset_val(&codec_cap, BT_AUDIO_METADATA_TYPE_STREAM_CONTEXT); + zassert_true(ret >= 0, "Unexpected return value %d", ret); + + ret = bt_audio_codec_cap_meta_get_val(&codec_cap, BT_AUDIO_METADATA_TYPE_STREAM_CONTEXT, + &data); + zassert_equal(ret, -ENODATA, "Unexpected return value %d", ret); +} + ZTEST(audio_codec_test_suite, test_bt_audio_codec_cap_meta_get_pref_context) { const enum bt_audio_context ctx = From 9194a93d87555aff25d32dd3d9425b5135ac9840 Mon Sep 17 00:00:00 2001 From: Anas Nashif Date: Wed, 24 Jan 2024 01:59:52 +0000 Subject: [PATCH 2865/3723] ci: compliance: exclude optional modules during compliance check We should not have any dependencies on optional modules, for example on Kconfigs from optional modules. Compliance has to pass without any optional modules enabled. Signed-off-by: Anas Nashif --- .github/workflows/compliance.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/compliance.yml b/.github/workflows/compliance.yml index de1decb2cc6..95414359c85 100644 --- a/.github/workflows/compliance.yml +++ b/.github/workflows/compliance.yml @@ -44,7 +44,7 @@ jobs: # debug git log --pretty=oneline | head -n 10 west init -l . || true - west config manifest.group-filter -- +ci,+optional + west config manifest.group-filter -- +ci,-optional west update -o=--depth=1 -n 2>&1 1> west.update.log || west update -o=--depth=1 -n 2>&1 1> west.update2.log - name: Run Compliance Tests From 19a33c7884134070ab9a13cf8112f5c8f81c5b94 Mon Sep 17 00:00:00 2001 From: Kai Vehmanen Date: Thu, 25 Jan 2024 17:47:03 +0200 Subject: [PATCH 2866/3723] init: adjust the SYS_INIT dev field init to play nice with older compilers MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Fix a build error with certain older Cadence XCC toolchains. These are used e.g. for Intel Tiger Lake products for the audio DSP (thhe oldest platform supported in Zephyr upstream for the audio DSP). To keep all compilers happy, use C89 style initializers. Error: lib/os/p4wq.c:216: error: unknown field ‘dev’ specified in initializer lib/os/p4wq.c:216: warning: missing braces around initializer lib/os/p4wq.c:216: warning: (near initialization for ‘__init_static_init.’) Compiler version XCC RG-2017.8-linux (xt-xcc version 12.0.8) Fixes: 2438dbb613731f ("init: add missing initialization of dev pointer in SYS_INIT macro") Signed-off-by: Kai Vehmanen --- include/zephyr/init.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/include/zephyr/init.h b/include/zephyr/init.h index 0e33223fdce..2788dc01afd 100644 --- a/include/zephyr/init.h +++ b/include/zephyr/init.h @@ -205,7 +205,7 @@ struct init_entry { #define SYS_INIT_NAMED(name, init_fn_, level, prio) \ static const Z_DECL_ALIGN(struct init_entry) \ Z_INIT_ENTRY_SECTION(level, prio, 0) __used __noasan \ - Z_INIT_ENTRY_NAME(name) = {.init_fn = {.sys = (init_fn_)}, .dev = NULL} + Z_INIT_ENTRY_NAME(name) = {{ (init_fn_) }, { NULL } } /** @} */ From 9ca7e4e4879ec984d19cb0d063d946a95fae7a0e Mon Sep 17 00:00:00 2001 From: Declan Snyder Date: Thu, 25 Jan 2024 16:22:52 -0600 Subject: [PATCH 2867/3723] drivers: mdio: Include errno in header MDIO driver header (mdio.h)is using errno values without including errno header, this causes build errors depending on the order of inclusion of this mdio header in other files, fix by including the errno header in this mdio.h file. Signed-off-by: Declan Snyder --- include/zephyr/drivers/mdio.h | 1 + 1 file changed, 1 insertion(+) diff --git a/include/zephyr/drivers/mdio.h b/include/zephyr/drivers/mdio.h index 1d030c0f586..9ee8deebd41 100644 --- a/include/zephyr/drivers/mdio.h +++ b/include/zephyr/drivers/mdio.h @@ -21,6 +21,7 @@ */ #include #include +#include #ifdef __cplusplus extern "C" { From 818ae7acb0d4136a52d8876d20d702010383225e Mon Sep 17 00:00:00 2001 From: Vinayak Kariappa Chettimada Date: Tue, 9 Jan 2024 16:17:27 +0100 Subject: [PATCH 2868/3723] Bluetooth: Controller: Fix incorrect HCI ISO Data length check Fix incorrect HCI ISO data length check for Broadcast ISO transmissions. Removed initially added code when preliminary support for Broadcast ISO was implemented. Signed-off-by: Vinayak Kariappa Chettimada --- subsys/bluetooth/controller/hci/hci.c | 10 ---------- 1 file changed, 10 deletions(-) diff --git a/subsys/bluetooth/controller/hci/hci.c b/subsys/bluetooth/controller/hci/hci.c index 2fd7dc41a9e..66d68471305 100644 --- a/subsys/bluetooth/controller/hci/hci.c +++ b/subsys/bluetooth/controller/hci/hci.c @@ -5868,16 +5868,6 @@ int hci_iso_handle(struct net_buf *buf, struct net_buf **evt) struct ll_adv_iso_set *adv_iso; struct lll_adv_iso *lll_iso; uint16_t stream_handle; - uint16_t slen; - - /* FIXME: Code only expects header present */ - slen = iso_data_hdr ? iso_data_hdr->slen : 0; - - /* Check invalid BIS PDU length */ - if (slen > LL_BIS_OCTETS_TX_MAX) { - LOG_ERR("Invalid HCI ISO Data length"); - return -EINVAL; - } /* Get BIS stream handle and stream context */ stream_handle = LL_BIS_ADV_IDX_FROM_HANDLE(handle); From 653d2852105cc1828d6d9c28b592a5e3587c8afb Mon Sep 17 00:00:00 2001 From: Vinayak Kariappa Chettimada Date: Tue, 9 Jan 2024 16:17:27 +0100 Subject: [PATCH 2869/3723] Bluetooth: Controller: Fix Broadcast ISO Create Scheduling Fix Broadcast ISO Create Scheduling to consider reducing Host requested RTN value. And also use maximum overhead calculation when Extended Advertising and Periodic Advertising have not been started before BIG create. Signed-off-by: Vinayak Kariappa Chettimada --- .../bluetooth/controller/ll_sw/ull_adv_iso.c | 135 +++++++++++------- 1 file changed, 83 insertions(+), 52 deletions(-) diff --git a/subsys/bluetooth/controller/ll_sw/ull_adv_iso.c b/subsys/bluetooth/controller/ll_sw/ull_adv_iso.c index 6191f811311..6072ebc788b 100644 --- a/subsys/bluetooth/controller/ll_sw/ull_adv_iso.c +++ b/subsys/bluetooth/controller/ll_sw/ull_adv_iso.c @@ -202,8 +202,73 @@ uint8_t ll_big_create(uint8_t big_handle, uint8_t adv_handle, uint8_t num_bis, return BT_HCI_ERR_MEM_CAPACITY_EXCEEDED; } + /* Check if aux context allocated before we are creating ISO */ + if (adv->lll.aux) { + aux = HDR_LLL2ULL(adv->lll.aux); + } else { + aux = NULL; + } + + /* Calculate overheads due to extended advertising. */ + if (aux && aux->is_started) { + ticks_slot_aux = aux->ull.ticks_slot; + if (IS_ENABLED(CONFIG_BT_CTLR_LOW_LAT)) { + ticks_slot_overhead = + MAX(aux->ull.ticks_active_to_start, + aux->ull.ticks_prepare_to_start); + } else { + ticks_slot_overhead = 0U; + } + } else { + uint32_t time_us; + + time_us = PDU_AC_US(PDU_AC_PAYLOAD_SIZE_MAX, adv->lll.phy_s, + adv->lll.phy_flags) + + EVENT_OVERHEAD_START_US + EVENT_OVERHEAD_END_US; + ticks_slot_aux = HAL_TICKER_US_TO_TICKS_CEIL(time_us); + if (IS_ENABLED(CONFIG_BT_CTLR_LOW_LAT)) { + /* Assume primary overheads may be inherited by aux */ + ticks_slot_overhead = + MAX(adv->ull.ticks_active_to_start, + adv->ull.ticks_prepare_to_start); + } else { + ticks_slot_overhead = 0U; + } + } + ticks_slot_aux += ticks_slot_overhead; + + /* Calculate overheads due to periodic advertising. */ + sync = HDR_LLL2ULL(lll_adv_sync); + if (sync->is_started) { + ticks_slot_sync = sync->ull.ticks_slot; + } else { + uint32_t time_us; + + time_us = PDU_AC_US(PDU_AC_PAYLOAD_SIZE_MAX, + sync->lll.adv->phy_s, + sync->lll.adv->phy_flags) + + EVENT_OVERHEAD_START_US + EVENT_OVERHEAD_END_US; + ticks_slot_sync = HAL_TICKER_US_TO_TICKS_CEIL(time_us); + } + + if (IS_ENABLED(CONFIG_BT_CTLR_LOW_LAT)) { + ticks_slot_overhead = MAX(sync->ull.ticks_active_to_start, + sync->ull.ticks_prepare_to_start); + } else { + ticks_slot_overhead = 0U; + } + + ticks_slot_sync += ticks_slot_overhead; + + /* Calculate total overheads due to extended and periodic advertising */ + if (CONFIG_BT_CTLR_ADV_AUX_SYNC_OFFSET > 0U) { + ticks_slot_overhead = MAX(ticks_slot_aux, ticks_slot_sync); + } else { + ticks_slot_overhead = ticks_slot_aux + ticks_slot_sync; + } + /* Store parameters in LLL context */ - /* TODO: parameters to ULL if only accessed by ULL */ + /* TODO: Move parameters to ULL if only accessed by ULL */ lll_adv_iso = &adv_iso->lll; lll_adv_iso->handle = big_handle; lll_adv_iso->max_pdu = MIN(LL_BIS_OCTETS_TX_MAX, max_sdu); @@ -260,6 +325,15 @@ uint8_t ll_big_create(uint8_t big_handle, uint8_t adv_handle, uint8_t num_bis, (bn * PERIODIC_INT_UNIT_US)) * PERIODIC_INT_UNIT_US; lll_adv_iso->iso_interval = iso_interval_us / PERIODIC_INT_UNIT_US; + /* Calculate max available ISO event spacing */ + slot_overhead = HAL_TICKER_TICKS_TO_US(ticks_slot_overhead); + if (slot_overhead < iso_interval_us) { + event_spacing_max = iso_interval_us - slot_overhead; + } else { + event_spacing_max = 0U; + } + +ll_big_create_rtn_retry: /* Immediate Repetition Count (IRC), Mandatory IRC = 1 */ lll_adv_iso->irc = rtn + 1U; @@ -283,61 +357,18 @@ uint8_t ll_big_create(uint8_t big_handle, uint8_t adv_handle, uint8_t num_bis, event_spacing = latency_packing + ctrl_spacing + EVENT_OVERHEAD_START_US + EVENT_OVERHEAD_END_US; - /* Check if aux context allocated before we are creating ISO */ - if (adv->lll.aux) { - aux = HDR_LLL2ULL(adv->lll.aux); - } else { - aux = NULL; - } - - /* Calculate overheads due to extended advertising. */ - if (aux && aux->is_started) { - ticks_slot_aux = aux->ull.ticks_slot; - if (IS_ENABLED(CONFIG_BT_CTLR_LOW_LAT)) { - ticks_slot_overhead = MAX(aux->ull.ticks_active_to_start, - aux->ull.ticks_prepare_to_start); - } else { - ticks_slot_overhead = 0U; - } - ticks_slot_aux += ticks_slot_overhead; - } else { - ticks_slot_aux = 0U; - } - - /* Calculate overheads due to periodic advertising. */ - sync = HDR_LLL2ULL(lll_adv_sync); - if (sync->is_started) { - ticks_slot_sync = sync->ull.ticks_slot; - if (IS_ENABLED(CONFIG_BT_CTLR_LOW_LAT)) { - ticks_slot_overhead = MAX(sync->ull.ticks_active_to_start, - sync->ull.ticks_prepare_to_start); - } else { - ticks_slot_overhead = 0U; - } - ticks_slot_sync += ticks_slot_overhead; - } else { - ticks_slot_sync = 0U; - } - - /* Calculate total overheads due to extended and periodic advertising */ - if (CONFIG_BT_CTLR_ADV_AUX_SYNC_OFFSET > 0U) { - ticks_slot_overhead = MAX(ticks_slot_aux, ticks_slot_sync); - } else { - ticks_slot_overhead = ticks_slot_aux + ticks_slot_sync; - } - - /* Calculate max available ISO event spacing */ - slot_overhead = HAL_TICKER_TICKS_TO_US(ticks_slot_overhead); - if (slot_overhead < iso_interval_us) { - event_spacing_max = iso_interval_us - slot_overhead; - } else { - event_spacing_max = 0U; - } - /* Check if ISO interval too small to fit the calculated BIG event * timing required for the supplied BIG create parameters. */ if (event_spacing > event_spacing_max) { + + /* Check if we can reduce RTN to meet eventing spacing */ + if (rtn) { + rtn--; + + goto ll_big_create_rtn_retry; + } + /* Release allocated link buffers */ ll_rx_link_release(link_cmplt); ll_rx_link_release(link_term); From 4192f8a844f197efbc7b9e4faffc8c61f86f96c8 Mon Sep 17 00:00:00 2001 From: Vinayak Kariappa Chettimada Date: Thu, 11 Jan 2024 13:03:55 +0100 Subject: [PATCH 2870/3723] Bluetooth: Controller: Fix ISO Sync Receiver sequential BIS PDU drop Fix ISO Synchronized Receiver sequential packing BIS PDU being dropped in the first repetation just after previous BIS subevents where skipped. Signed-off-by: Vinayak Kariappa Chettimada --- subsys/bluetooth/controller/ll_sw/nordic/lll/lll_sync_iso.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/subsys/bluetooth/controller/ll_sw/nordic/lll/lll_sync_iso.c b/subsys/bluetooth/controller/ll_sw/nordic/lll/lll_sync_iso.c index 8ac45f9a84f..2c1125e02d4 100644 --- a/subsys/bluetooth/controller/ll_sw/nordic/lll/lll_sync_iso.c +++ b/subsys/bluetooth/controller/ll_sw/nordic/lll/lll_sync_iso.c @@ -803,6 +803,9 @@ static void isr_rx(void *param) ((lll->bn * lll->irc) + lll->ptc)) + 1U; + /* BIS index */ + bis_idx = lll->bis_curr - 1U; + /* Find the missing (bn_curr)th Rx PDU * of bis_curr */ From 87aa53ccaee80f24a5c65222aaa6e691f2f53b3c Mon Sep 17 00:00:00 2001 From: Vinayak Kariappa Chettimada Date: Thu, 25 Jan 2024 12:11:36 +0100 Subject: [PATCH 2871/3723] Bluetooth: Controller: Fix BIS Encryption for first subevent PDU empty Fix radio packet length configuration when first subevent has empty PDU in the BIG event. Signed-off-by: Vinayak Kariappa Chettimada --- .../controller/ll_sw/nordic/lll/lll_adv_iso.c | 26 ++++++++++--------- 1 file changed, 14 insertions(+), 12 deletions(-) diff --git a/subsys/bluetooth/controller/ll_sw/nordic/lll/lll_adv_iso.c b/subsys/bluetooth/controller/ll_sw/nordic/lll/lll_adv_iso.c index f5e566a7bcc..60f8967738f 100644 --- a/subsys/bluetooth/controller/ll_sw/nordic/lll/lll_adv_iso.c +++ b/subsys/bluetooth/controller/ll_sw/nordic/lll/lll_adv_iso.c @@ -189,6 +189,7 @@ static int prepare_cb_common(struct lll_prepare_param *p) struct ull_hdr *ull; uint32_t remainder; uint32_t start_us; + uint8_t pkt_flags; uint32_t ret; uint8_t phy; @@ -348,31 +349,32 @@ static int prepare_cb_common(struct lll_prepare_param *p) } pdu->cssn = lll->cssn; - /* Encryption */ + /* Radio packet configuration */ + pkt_flags = RADIO_PKT_CONF_FLAGS(RADIO_PKT_CONF_PDU_TYPE_BIS, phy, + RADIO_PKT_CONF_CTE_DISABLED); if (pdu->len && lll->enc) { - uint8_t pkt_flags; - + /* Encryption */ lll->ccm_tx.counter = payload_count; (void)memcpy(lll->ccm_tx.iv, lll->giv, 4U); mem_xor_32(lll->ccm_tx.iv, lll->ccm_tx.iv, access_addr); - pkt_flags = RADIO_PKT_CONF_FLAGS(RADIO_PKT_CONF_PDU_TYPE_BIS, - phy, - RADIO_PKT_CONF_CTE_DISABLED); radio_pkt_configure(RADIO_PKT_CONF_LENGTH_8BIT, (lll->max_pdu + PDU_MIC_SIZE), pkt_flags); + radio_pkt_tx_set(radio_ccm_iso_tx_pkt_set(&lll->ccm_tx, RADIO_PKT_CONF_PDU_TYPE_BIS, pdu)); } else { - uint8_t pkt_flags; + if (lll->enc) { + radio_pkt_configure(RADIO_PKT_CONF_LENGTH_8BIT, + (lll->max_pdu + PDU_MIC_SIZE), + pkt_flags); + } else { + radio_pkt_configure(RADIO_PKT_CONF_LENGTH_8BIT, + lll->max_pdu, pkt_flags); + } - pkt_flags = RADIO_PKT_CONF_FLAGS(RADIO_PKT_CONF_PDU_TYPE_BIS, - phy, - RADIO_PKT_CONF_CTE_DISABLED); - radio_pkt_configure(RADIO_PKT_CONF_LENGTH_8BIT, lll->max_pdu, - pkt_flags); radio_pkt_tx_set(pdu); } From a4f004e654cac92051c7d72ceada5162e3049b7d Mon Sep 17 00:00:00 2001 From: Bartosz Bilas Date: Fri, 19 Jan 2024 21:30:14 +0100 Subject: [PATCH 2872/3723] drivers: adc: ad5592: add missing static keyword Add the missing static keyword for driver data structure. Signed-off-by: Bartosz Bilas --- drivers/adc/adc_ad5592.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/adc/adc_ad5592.c b/drivers/adc/adc_ad5592.c index 422fd549868..69f7b773258 100644 --- a/drivers/adc/adc_ad5592.c +++ b/drivers/adc/adc_ad5592.c @@ -245,7 +245,7 @@ static const struct adc_driver_api adc_ad5592_api = { .mfd_dev = DEVICE_DT_GET(DT_INST_PARENT(inst)), \ }; \ \ - struct adc_ad5592_data adc_ad5592_data##inst; \ + static struct adc_ad5592_data adc_ad5592_data##inst; \ \ DEVICE_DT_INST_DEFINE(inst, adc_ad5592_init, NULL, \ &adc_ad5592_data##inst, &adc_ad5592_config##inst, \ From 8ff447700ba0647404821ad8f7f8bfbd114b227e Mon Sep 17 00:00:00 2001 From: Dawid Niedzwiecki Date: Wed, 24 Jan 2024 08:48:21 +0100 Subject: [PATCH 2873/3723] arm: mpu: clear mpu regions before initialization Disabling the MPU doesn't clear regions configuration. There is a risk in multi-image environment that there are some old region setting e.g. stack guard. This may cause a memory fault, because of different images layout e.g. RO/RW. Just clear and disable all regions configuration before the new initialization. Signed-off-by: Dawid Niedzwiecki --- arch/arm/core/mpu/arm_mpu.c | 5 +++++ arch/arm/core/mpu/arm_mpu_v7_internal.h | 5 +++++ 2 files changed, 10 insertions(+) diff --git a/arch/arm/core/mpu/arm_mpu.c b/arch/arm/core/mpu/arm_mpu.c index 94c92edbc5c..cd4c8ccd7a0 100644 --- a/arch/arm/core/mpu/arm_mpu.c +++ b/arch/arm/core/mpu/arm_mpu.c @@ -459,6 +459,11 @@ int z_arm_mpu_init(void) return -EINVAL; } + /* Clear all regions before enabling MPU */ + for (int i = static_regions_num; i < get_num_regions(); i++) { + mpu_clear_region(i); + } + arm_core_mpu_enable(); /* Program additional fixed flash region for null-pointer diff --git a/arch/arm/core/mpu/arm_mpu_v7_internal.h b/arch/arm/core/mpu/arm_mpu_v7_internal.h index 508d1b67600..1fe3417901e 100644 --- a/arch/arm/core/mpu/arm_mpu_v7_internal.h +++ b/arch/arm/core/mpu/arm_mpu_v7_internal.h @@ -269,4 +269,9 @@ static int mpu_configure_dynamic_mpu_regions(const struct z_arm_mpu_partition return mpu_reg_index; } +static inline void mpu_clear_region(uint32_t rnr) +{ + ARM_MPU_ClrRegion(rnr); +} + #endif /* ZEPHYR_ARCH_ARM_CORE_AARCH32_MPU_ARM_MPU_V7_INTERNAL_H_ */ From d76bcd346ce7b9ede5144114fc357859e6a5d610 Mon Sep 17 00:00:00 2001 From: Maciej Baczmanski Date: Tue, 23 Jan 2024 14:36:55 +0100 Subject: [PATCH 2874/3723] drivers: ieee802154: fix ACK header IE implementation - In `set_vendor_ie_header_lm`, case when `link_metrics_data_len == 0` has been ignored. This commit fixes that by setting `header_ie->length = 0` before returning. - current implementation of enh ACK header IE returns `-ENOTSUP` when `ack_ie.header_ie == NULL` or `ack_ie.header_ie->length == 0`. This commit fixes that by refactoring checks in `nrf5_configure`. Co-authored-by: Przemyslaw Bida Signed-off-by: Maciej Baczmanski --- drivers/ieee802154/ieee802154_nrf5.c | 38 ++++++++++++++-------------- modules/openthread/platform/radio.c | 13 ++++------ 2 files changed, 24 insertions(+), 27 deletions(-) diff --git a/drivers/ieee802154/ieee802154_nrf5.c b/drivers/ieee802154/ieee802154_nrf5.c index 715fa665df2..768e6159a60 100644 --- a/drivers/ieee802154/ieee802154_nrf5.c +++ b/drivers/ieee802154/ieee802154_nrf5.c @@ -899,35 +899,38 @@ static int nrf5_configure(const struct device *dev, uint8_t ext_addr_le[EXTENDED_ADDRESS_SIZE]; uint8_t short_addr_le[SHORT_ADDRESS_SIZE]; uint8_t element_id; + bool valid_vendor_specific_ie = false; if (config->ack_ie.short_addr == IEEE802154_BROADCAST_ADDRESS || config->ack_ie.ext_addr == NULL) { return -ENOTSUP; } - element_id = ieee802154_header_ie_get_element_id(config->ack_ie.header_ie); + sys_put_le16(config->ack_ie.short_addr, short_addr_le); + sys_memcpy_swap(ext_addr_le, config->ack_ie.ext_addr, EXTENDED_ADDRESS_SIZE); - if (element_id != IEEE802154_HEADER_IE_ELEMENT_ID_CSL_IE && - (!IS_ENABLED(CONFIG_NET_L2_OPENTHREAD) || - element_id != IEEE802154_HEADER_IE_ELEMENT_ID_VENDOR_SPECIFIC_IE)) { - return -ENOTSUP; - } + if (config->ack_ie.header_ie == NULL || config->ack_ie.header_ie->length == 0) { + nrf_802154_ack_data_clear(short_addr_le, false, NRF_802154_ACK_DATA_IE); + nrf_802154_ack_data_clear(ext_addr_le, true, NRF_802154_ACK_DATA_IE); + } else { + element_id = ieee802154_header_ie_get_element_id(config->ack_ie.header_ie); #if defined(CONFIG_NET_L2_OPENTHREAD) - uint8_t vendor_oui_le[IEEE802154_OPENTHREAD_VENDOR_OUI_LEN] = - IEEE802154_OPENTHREAD_THREAD_IE_VENDOR_OUI; + uint8_t vendor_oui_le[IEEE802154_OPENTHREAD_VENDOR_OUI_LEN] = + IEEE802154_OPENTHREAD_THREAD_IE_VENDOR_OUI; - if (element_id == IEEE802154_HEADER_IE_ELEMENT_ID_VENDOR_SPECIFIC_IE && - memcmp(config->ack_ie.header_ie->content.vendor_specific.vendor_oui, - vendor_oui_le, sizeof(vendor_oui_le))) { - return -ENOTSUP; - } + if (element_id == IEEE802154_HEADER_IE_ELEMENT_ID_VENDOR_SPECIFIC_IE && + memcmp(config->ack_ie.header_ie->content.vendor_specific.vendor_oui, + vendor_oui_le, sizeof(vendor_oui_le)) == 0) { + valid_vendor_specific_ie = true; + } #endif - sys_put_le16(config->ack_ie.short_addr, short_addr_le); - sys_memcpy_swap(ext_addr_le, config->ack_ie.ext_addr, EXTENDED_ADDRESS_SIZE); + if (element_id != IEEE802154_HEADER_IE_ELEMENT_ID_CSL_IE && + !valid_vendor_specific_ie) { + return -ENOTSUP; + } - if (config->ack_ie.header_ie && config->ack_ie.header_ie->length > 0) { nrf_802154_ack_data_set(short_addr_le, false, config->ack_ie.header_ie, config->ack_ie.header_ie->length + IEEE802154_HEADER_IE_HEADER_LENGTH, @@ -936,9 +939,6 @@ static int nrf5_configure(const struct device *dev, config->ack_ie.header_ie->length + IEEE802154_HEADER_IE_HEADER_LENGTH, NRF_802154_ACK_DATA_IE); - } else { - nrf_802154_ack_data_clear(short_addr_le, false, NRF_802154_ACK_DATA_IE); - nrf_802154_ack_data_clear(ext_addr_le, true, NRF_802154_ACK_DATA_IE); } } break; diff --git a/modules/openthread/platform/radio.c b/modules/openthread/platform/radio.c index e6b4e2617ed..ad33e6e4e77 100644 --- a/modules/openthread/platform/radio.c +++ b/modules/openthread/platform/radio.c @@ -1350,7 +1350,7 @@ uint8_t otPlatRadioGetCslUncertainty(otInstance *aInstance) * | IE_VENDOR_THREAD_ACK_PROBING_ID | LINK_METRIC_TOKEN | LINK_METRIC_TOKEN| * |---------------------------------|-------------------|------------------| */ -static uint8_t set_vendor_ie_header_lm(bool lqi, bool link_margin, bool rssi, uint8_t *ie_header) +static void set_vendor_ie_header_lm(bool lqi, bool link_margin, bool rssi, uint8_t *ie_header) { /* Vendor-specific IE identifier */ const uint8_t ie_vendor_id = 0x00; @@ -1364,7 +1364,6 @@ static uint8_t set_vendor_ie_header_lm(bool lqi, bool link_margin, bool rssi, ui const uint8_t ie_vendor_thread_margin_token = 0x02; /* Thread Vendor-specific ACK Probing IE LQI value placeholder */ const uint8_t ie_vendor_thread_lqi_token = 0x03; - const uint8_t ie_header_size = 2; const uint8_t oui_size = 3; const uint8_t sub_type = 1; const uint8_t id_offset = 7; @@ -1382,7 +1381,8 @@ static uint8_t set_vendor_ie_header_lm(bool lqi, bool link_margin, bool rssi, ui __ASSERT(ie_header, "Invalid argument"); if (link_metrics_data_len == 0) { - return 0; + ie_header[0] = 0; + return; } /* Set Element ID */ @@ -1417,8 +1417,6 @@ static uint8_t set_vendor_ie_header_lm(bool lqi, bool link_margin, bool rssi, ui if (rssi) { ie_header[link_metrics_idx++] = ie_vendor_thread_rssi_token; } - - return ie_header_size + content_len; } otError otPlatRadioConfigureEnhAckProbing(otInstance *aInstance, otLinkMetrics aLinkMetrics, @@ -1430,13 +1428,12 @@ otError otPlatRadioConfigureEnhAckProbing(otInstance *aInstance, otLinkMetrics a .ack_ie.ext_addr = aExtAddress->m8, }; uint8_t header_ie_buf[OT_ACK_IE_MAX_SIZE]; - uint16_t header_ie_len; int result; ARG_UNUSED(aInstance); - header_ie_len = set_vendor_ie_header_lm(aLinkMetrics.mLqi, aLinkMetrics.mLinkMargin, - aLinkMetrics.mRssi, header_ie_buf); + set_vendor_ie_header_lm(aLinkMetrics.mLqi, aLinkMetrics.mLinkMargin, + aLinkMetrics.mRssi, header_ie_buf); config.ack_ie.header_ie = (struct ieee802154_header_ie *)header_ie_buf; result = radio_api->configure(radio_dev, IEEE802154_CONFIG_ENH_ACK_HEADER_IE, &config); From 36b7f44c1d37e842048773f3ad11af59f7b465bb Mon Sep 17 00:00:00 2001 From: Maciej Baczmanski Date: Tue, 23 Jan 2024 14:55:09 +0100 Subject: [PATCH 2875/3723] drivers: ieee802154: fix handling of `struct ieee802154_config` `struct ieee802154_config config` is a struct containing an union. Members of `config` were accessed incorrectly in `otPlatRadioEnableCsl`. Fix by initializing `config` with `0` and accessing one member at a time. Signed-off-by: Maciej Baczmanski --- modules/openthread/platform/radio.c | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/modules/openthread/platform/radio.c b/modules/openthread/platform/radio.c index ad33e6e4e77..631ff4d4eb1 100644 --- a/modules/openthread/platform/radio.c +++ b/modules/openthread/platform/radio.c @@ -1257,10 +1257,7 @@ void otPlatRadioSetMacFrameCounterIfLarger(otInstance *aInstance, uint32_t aMacF otError otPlatRadioEnableCsl(otInstance *aInstance, uint32_t aCslPeriod, otShortAddress aShortAddr, const otExtAddress *aExtAddr) { - struct ieee802154_config config = { - .ack_ie.short_addr = aShortAddr, - .ack_ie.ext_addr = aExtAddr->m8, - }; + struct ieee802154_config config = { 0 }; int result; ARG_UNUSED(aInstance); @@ -1273,6 +1270,8 @@ otError otPlatRadioEnableCsl(otInstance *aInstance, uint32_t aCslPeriod, otShort if (result) { return OT_ERROR_FAILED; } + config.ack_ie.short_addr = aShortAddr; + config.ack_ie.ext_addr = aExtAddr != NULL ? aExtAddr->m8 : NULL; /* Configure the CSL IE. */ if (aCslPeriod > 0) { From 0f1747e4e73fa1db67f65dfb251d202e8d552db6 Mon Sep 17 00:00:00 2001 From: Maciej Baczmanski Date: Tue, 23 Jan 2024 14:56:03 +0100 Subject: [PATCH 2876/3723] net: openthread: upmerge to `7761b81` additionaly, implement `otPlatRadioResetCsl` functionality Signed-off-by: Maciej Baczmanski --- drivers/ieee802154/ieee802154_nrf5.c | 6 ++++++ include/zephyr/net/ieee802154_radio.h | 9 +++++++++ modules/openthread/platform/radio.c | 16 ++++++++++++++++ west.yml | 2 +- 4 files changed, 32 insertions(+), 1 deletion(-) diff --git a/drivers/ieee802154/ieee802154_nrf5.c b/drivers/ieee802154/ieee802154_nrf5.c index 768e6159a60..0643d6051b6 100644 --- a/drivers/ieee802154/ieee802154_nrf5.c +++ b/drivers/ieee802154/ieee802154_nrf5.c @@ -901,6 +901,12 @@ static int nrf5_configure(const struct device *dev, uint8_t element_id; bool valid_vendor_specific_ie = false; + if (config->ack_ie.purge_ie) { + nrf_802154_ack_data_remove_all(false, NRF_802154_ACK_DATA_IE); + nrf_802154_ack_data_remove_all(true, NRF_802154_ACK_DATA_IE); + break; + } + if (config->ack_ie.short_addr == IEEE802154_BROADCAST_ADDRESS || config->ack_ie.ext_addr == NULL) { return -ENOTSUP; diff --git a/include/zephyr/net/ieee802154_radio.h b/include/zephyr/net/ieee802154_radio.h index de0cf89da4c..259d67b4321 100644 --- a/include/zephyr/net/ieee802154_radio.h +++ b/include/zephyr/net/ieee802154_radio.h @@ -1241,6 +1241,15 @@ struct ieee802154_config { * in CPU byte order */ uint16_t short_addr; + + /** + * Flag for purging enh ACK header IEs. + * When flag is set to true, driver should remove all existing + * header IEs, and all other entries in config should be ignored. + * This means that purging current header IEs and + * configuring a new one in the same call is not allowed. + */ + bool purge_ie; } ack_ie; }; }; diff --git a/modules/openthread/platform/radio.c b/modules/openthread/platform/radio.c index 631ff4d4eb1..64effaef337 100644 --- a/modules/openthread/platform/radio.c +++ b/modules/openthread/platform/radio.c @@ -1296,6 +1296,22 @@ otError otPlatRadioEnableCsl(otInstance *aInstance, uint32_t aCslPeriod, otShort return result ? OT_ERROR_FAILED : OT_ERROR_NONE; } +otError otPlatRadioResetCsl(otInstance *aInstance) +{ + struct ieee802154_config config = { 0 }; + int result; + + result = radio_api->configure(radio_dev, IEEE802154_CONFIG_CSL_PERIOD, &config); + if (result) { + return OT_ERROR_FAILED; + } + + config.ack_ie.purge_ie = true; + result = radio_api->configure(radio_dev, IEEE802154_CONFIG_ENH_ACK_HEADER_IE, &config); + + return result ? OT_ERROR_FAILED : OT_ERROR_NONE; +} + void otPlatRadioUpdateCslSampleTime(otInstance *aInstance, uint32_t aCslSampleTime) { ARG_UNUSED(aInstance); diff --git a/west.yml b/west.yml index 3534498609c..0c4693ddf4f 100644 --- a/west.yml +++ b/west.yml @@ -301,7 +301,7 @@ manifest: revision: da78aea63159771956fe0c9263f2e6985b66e9d5 path: modules/lib/open-amp - name: openthread - revision: 00076aff3ae571db7c90509ec9dc293457098c35 + revision: 7761b81d23b10b3d5ee21b8504c67535cde10896 path: modules/lib/openthread - name: percepio path: modules/debug/percepio From 85bc24eb0731cef2275529633c6f4a915ae8f6ed Mon Sep 17 00:00:00 2001 From: Maciej Baczmanski Date: Wed, 24 Jan 2024 10:44:53 +0100 Subject: [PATCH 2877/3723] net: openthread: Add PSA implementation for PBDKF2 genkey Add implementation of openthread pbkdf2 generate key using PSA functions. Co-authored-by: Joakim Andersson Signed-off-by: Maciej Baczmanski --- modules/openthread/platform/crypto_psa.c | 62 ++++++++++++++++++++++++ 1 file changed, 62 insertions(+) diff --git a/modules/openthread/platform/crypto_psa.c b/modules/openthread/platform/crypto_psa.c index c818c5695a3..6ad286f3734 100644 --- a/modules/openthread/platform/crypto_psa.c +++ b/modules/openthread/platform/crypto_psa.c @@ -603,4 +603,66 @@ otError otPlatCryptoEcdsaGenerateAndImportKey(otCryptoKeyRef aKeyRef) return psaToOtError(status); } +otError otPlatCryptoPbkdf2GenerateKey(const uint8_t *aPassword, + uint16_t aPasswordLen, + const uint8_t *aSalt, + uint16_t aSaltLen, + uint32_t aIterationCounter, + uint16_t aKeyLen, + uint8_t *aKey) +{ + psa_status_t status = PSA_SUCCESS; + psa_key_id_t key_id = PSA_KEY_ID_NULL; + psa_key_attributes_t attributes = PSA_KEY_ATTRIBUTES_INIT; + psa_algorithm_t algorithm = PSA_ALG_PBKDF2_AES_CMAC_PRF_128; + psa_key_derivation_operation_t operation = PSA_KEY_DERIVATION_OPERATION_INIT; + + psa_set_key_usage_flags(&attributes, PSA_KEY_USAGE_DERIVE); + psa_set_key_lifetime(&attributes, PSA_KEY_LIFETIME_VOLATILE); + psa_set_key_algorithm(&attributes, algorithm); + psa_set_key_type(&attributes, PSA_KEY_TYPE_PASSWORD); + psa_set_key_bits(&attributes, PSA_BYTES_TO_BITS(aPasswordLen)); + + status = psa_import_key(&attributes, aPassword, aPasswordLen, &key_id); + if (status != PSA_SUCCESS) { + goto out; + } + + status = psa_key_derivation_setup(&operation, algorithm); + if (status != PSA_SUCCESS) { + goto out; + } + + status = psa_key_derivation_input_integer(&operation, PSA_KEY_DERIVATION_INPUT_COST, + aIterationCounter); + if (status != PSA_SUCCESS) { + goto out; + } + + status = psa_key_derivation_input_bytes(&operation, PSA_KEY_DERIVATION_INPUT_SALT, + aSalt, aSaltLen); + if (status != PSA_SUCCESS) { + goto out; + } + + status = psa_key_derivation_input_key(&operation, PSA_KEY_DERIVATION_INPUT_PASSWORD, + key_id); + if (status != PSA_SUCCESS) { + goto out; + } + + status = psa_key_derivation_output_bytes(&operation, aKey, aKeyLen); + if (status != PSA_SUCCESS) { + goto out; + } + +out: + psa_reset_key_attributes(&attributes); + psa_key_derivation_abort(&operation); + psa_destroy_key(key_id); + + __ASSERT_NO_MSG(status == PSA_SUCCESS); + return psaToOtError(status); +} + #endif /* #if CONFIG_OPENTHREAD_ECDSA */ From 499edcdbc92dd2c1973903960b615403d86a6ddd Mon Sep 17 00:00:00 2001 From: Marcin Niestroj Date: Thu, 25 Jan 2024 17:12:03 +0100 Subject: [PATCH 2878/3723] drivers: display: uc81xx: fix 16-bit 'tres' Use 'struct uc81xx_tres16' for 16-bit 'tres' setup, instead of 'struct uc81xx_tres8'. This fixes a regression when support for 'uc8175' was added and 'struct uc81xx_tres' was replaced with 'struct uc81xx_tres16'. Fixes: 7c46b0b8984e ("drivers: display: uc81xx: add support for uc8175") Signed-off-by: Marcin Niestroj --- drivers/display/uc81xx.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/display/uc81xx.c b/drivers/display/uc81xx.c index 38a68cdfaf0..3aafe933750 100644 --- a/drivers/display/uc81xx.c +++ b/drivers/display/uc81xx.c @@ -677,7 +677,7 @@ static inline int uc81xx_set_ptl_8(const struct device *dev, uint16_t x, uint16_ static int uc81xx_set_tres_16(const struct device *dev) { const struct uc81xx_config *config = dev->config; - const struct uc81xx_tres8 tres = { + const struct uc81xx_tres16 tres = { .hres = sys_cpu_to_be16(config->width), .vres = sys_cpu_to_be16(config->height), }; From e78aacdf29f8d23c1d2a4f70e0925fb68236f238 Mon Sep 17 00:00:00 2001 From: Greter Raffael Date: Fri, 22 Dec 2023 12:58:51 +0000 Subject: [PATCH 2879/3723] cmake: zephyr_linker_sources: Link each file only once If an ld file is included multiple times using `zephyr_linker_sources`, only the last occurrence is actually used. Everything else is removed again from the generated snippet files. This allows to relocate certain blocks, e.g. the vector table, in an application-specific CMakeLists.txt (or for an arch or soc). Fixes: #66315 Signed-off-by: Greter Raffael --- cmake/modules/extensions.cmake | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/cmake/modules/extensions.cmake b/cmake/modules/extensions.cmake index 1c3e7d5abf1..4a96b50bb20 100644 --- a/cmake/modules/extensions.cmake +++ b/cmake/modules/extensions.cmake @@ -1159,6 +1159,8 @@ endfunction(zephyr_check_compiler_flag_hardcoded) # copied/included verbatim into the given in the global linker.ld. # Preprocessor directives work inside . Relative paths are resolved # relative to the calling file, like zephyr_sources(). +# Subsequent calls to zephyr_linker_sources with the same file(s) will remove +# these from the original location. Only the last call is considered. # is one of # NOINIT Inside the noinit output section. # RWDATA Inside the data output section. @@ -1319,6 +1321,16 @@ function(zephyr_linker_sources location) # Create strings to be written into the file set (include_str "/* Sort key: \"${SORT_KEY}\" */#include \"${relpath}\"") + # Remove line from other snippet file, if already used + get_property(old_path GLOBAL PROPERTY "snippet_files_used_${relpath}") + if (DEFINED old_path) + file(STRINGS ${old_path} lines) + list(FILTER lines EXCLUDE REGEX ${relpath}) + string(REPLACE ";" "\n;" lines "${lines}") # Add newline to each line. + file(WRITE ${old_path} ${lines} "\n") + endif() + set_property(GLOBAL PROPERTY "snippet_files_used_${relpath}" ${snippet_path}) + # Add new line to existing lines, sort them, and write them back. file(STRINGS ${snippet_path} lines) # Get current lines (without newlines). list(APPEND lines ${include_str}) From d07d8082c92a88cb77b66a6d20590a43deafca0c Mon Sep 17 00:00:00 2001 From: Yong Cong Sin Date: Thu, 25 Jan 2024 23:37:19 +0800 Subject: [PATCH 2880/3723] doc: touch-up multi-level interrupt documentation Some very minor touch-ups for multi-level interrupt wordings and documentations to better reflects its current state. Signed-off-by: Yong Cong Sin --- doc/kernel/services/interrupts.rst | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/doc/kernel/services/interrupts.rst b/doc/kernel/services/interrupts.rst index a388bc13a0f..b1f7421ed01 100644 --- a/doc/kernel/services/interrupts.rst +++ b/doc/kernel/services/interrupts.rst @@ -59,7 +59,7 @@ nesting support is enabled. .. _multi_level_interrupts: -Multi-level Interrupt handling +Multi-level Interrupt Handling ============================== A hardware platform can support more interrupt lines than natively-provided @@ -68,7 +68,7 @@ hardware interrupts are combined into one line that is then routed to the parent controller. If nested interrupt controllers are supported, :kconfig:option:`CONFIG_MULTI_LEVEL_INTERRUPTS` -should be set to 1, and :kconfig:option:`CONFIG_2ND_LEVEL_INTERRUPTS` and +should be enabled, and :kconfig:option:`CONFIG_2ND_LEVEL_INTERRUPTS` and :kconfig:option:`CONFIG_3RD_LEVEL_INTERRUPTS` configured as well, based on the hardware architecture. @@ -608,7 +608,7 @@ connected. Going Beyond the Default Supported Number of Interrupts ------------------------------------------------------- -When generating interrupts in the multilevel configuration, 8-bits per level is the default +When generating interrupts in the multi-level configuration, 8-bits per level is the default mask used when determining which level a given interrupt code belongs to. This can become a problem when dealing with CPUs that support more than 255 interrupts per single aggregator. In this case it may be desirable to override these defaults and use a custom @@ -616,11 +616,11 @@ number of bits per level. Regardless of how many bits used for each level, the s the total bits used between all levels must sum to be less than or equal to 32-bits, fitting into a single 32-bit integer. To modify the bit total per level, override the default 8 in `Kconfig.multilevel` by setting :kconfig:option:`CONFIG_1ST_LEVEL_INTERRUPT_BITS` -for the first level, :kconfig:option:`CONFIG_2ND_LEVEL_INTERRUPT_BITS` for the second tier and -:kconfig:option:`CONFIG_3RD_LEVEL_INTERRUPT_BITS` for the third tier. These masks control the +for the first level, :kconfig:option:`CONFIG_2ND_LEVEL_INTERRUPT_BITS` for the second level and +:kconfig:option:`CONFIG_3RD_LEVEL_INTERRUPT_BITS` for the third level. These masks control the length of the bit masks and shift to apply when generating interrupt values, when checking the interrupts level and converting interrupts to a different level. The logic controlling -this can be found in `irq.h` +this can be found in :file:`irq_multilevel.h` Suggested Uses ************** From 37696829a9836bf6e9bf11a63fa0fb185d5312c1 Mon Sep 17 00:00:00 2001 From: cyliang tw Date: Fri, 26 Jan 2024 10:38:14 +0800 Subject: [PATCH 2881/3723] drivers: watchdog: andes atcwdt200 remove soc.h soc\riscv\andes_v5\ae350\soc.h was empty and deleted,so revise wdt_andes_atcwdt200.c to resolve 'fatal error: soc.h: No such file or directory'. Signed-off-by: cyliang tw --- drivers/watchdog/wdt_andes_atcwdt200.c | 1 - 1 file changed, 1 deletion(-) diff --git a/drivers/watchdog/wdt_andes_atcwdt200.c b/drivers/watchdog/wdt_andes_atcwdt200.c index 62a9677b96d..5fca0026805 100644 --- a/drivers/watchdog/wdt_andes_atcwdt200.c +++ b/drivers/watchdog/wdt_andes_atcwdt200.c @@ -7,7 +7,6 @@ #define DT_DRV_COMPAT andestech_atcwdt200 #include -#include #include #define LOG_LEVEL CONFIG_WDT_LOG_LEVEL From 5f2c6e58b04d450c4a2e544ef3d705eeea885087 Mon Sep 17 00:00:00 2001 From: Luca Burelli Date: Tue, 9 Jan 2024 15:50:31 +0100 Subject: [PATCH 2882/3723] ztest: export ztest_test_* symbols to llexts Export the minimal set of ztest_test_* symbols to llexts so that the zassert_* macros can be used by the extension code to affect test execution. Calling these also requires vprintk() to be exported. Signed-off-by: Luca Burelli --- lib/os/printk.c | 1 + subsys/testsuite/ztest/src/ztest.c | 8 ++++++++ subsys/testsuite/ztest/src/ztest_defaults.c | 2 ++ 3 files changed, 11 insertions(+) diff --git a/lib/os/printk.c b/lib/os/printk.c index f46b950ffe4..ac19e9e38fc 100644 --- a/lib/os/printk.c +++ b/lib/os/printk.c @@ -154,6 +154,7 @@ void vprintk(const char *fmt, va_list ap) #endif } } +EXPORT_SYMBOL(vprintk); void z_impl_k_str_out(char *c, size_t n) { diff --git a/subsys/testsuite/ztest/src/ztest.c b/subsys/testsuite/ztest/src/ztest.c index 5c44829acd4..f887948b755 100644 --- a/subsys/testsuite/ztest/src/ztest.c +++ b/subsys/testsuite/ztest/src/ztest.c @@ -13,6 +13,8 @@ #include #include +#include + #ifdef KERNEL static struct k_thread ztest_thread; #endif @@ -324,6 +326,7 @@ void ztest_test_fail(void) longjmp(stack_fail, 1); } } +EXPORT_SYMBOL(ztest_test_fail); void ztest_test_pass(void) { @@ -334,6 +337,7 @@ void ztest_test_pass(void) get_friendly_phase_name(cur_phase)); longjmp(stack_fail, 1); } +EXPORT_SYMBOL(ztest_test_pass); void ztest_test_skip(void) { @@ -348,6 +352,7 @@ void ztest_test_skip(void) longjmp(stack_fail, 1); } } +EXPORT_SYMBOL(ztest_test_skip); void ztest_test_expect_fail(void) { @@ -471,6 +476,7 @@ void ztest_test_fail(void) break; } } +EXPORT_SYMBOL(ztest_test_fail); void ztest_test_pass(void) { @@ -488,6 +494,7 @@ void ztest_test_pass(void) } } } +EXPORT_SYMBOL(ztest_test_pass); void ztest_test_skip(void) { @@ -507,6 +514,7 @@ void ztest_test_skip(void) break; } } +EXPORT_SYMBOL(ztest_test_skip); void ztest_test_expect_fail(void) { diff --git a/subsys/testsuite/ztest/src/ztest_defaults.c b/subsys/testsuite/ztest/src/ztest_defaults.c index 12569d4126a..1655d21eff6 100644 --- a/subsys/testsuite/ztest/src/ztest_defaults.c +++ b/subsys/testsuite/ztest/src/ztest_defaults.c @@ -5,6 +5,7 @@ */ #include +#include /** * @brief Try to shorten a filename by removing the current directory @@ -21,6 +22,7 @@ const char *ztest_relative_filename(const char *file) { return file; } +EXPORT_SYMBOL(ztest_relative_filename); /** * Default entry point for running registered unit tests. From d2e090d1b1f6d74462b50513292b7d1083afe232 Mon Sep 17 00:00:00 2001 From: Jordan Yates Date: Wed, 17 Jan 2024 10:13:28 +1000 Subject: [PATCH 2883/3723] boards: remove `LOG_BUFFER_SIZE` low defaults Setting an extremely low value by default on two boards doesn't seem like the right thing to do. The defaults were added with the v1 logging subsystem in https://github.com/zephyrproject-rtos/zephyr/pull/8023. Signed-off-by: Jordan Yates --- boards/arm/bbc_microbit/Kconfig.defconfig | 3 --- boards/arm/qemu_cortex_m0/Kconfig.defconfig | 3 --- 2 files changed, 6 deletions(-) diff --git a/boards/arm/bbc_microbit/Kconfig.defconfig b/boards/arm/bbc_microbit/Kconfig.defconfig index 5bf0c28c9cf..17decdb0abe 100644 --- a/boards/arm/bbc_microbit/Kconfig.defconfig +++ b/boards/arm/bbc_microbit/Kconfig.defconfig @@ -11,9 +11,6 @@ config BOARD config BT_CTLR default BT -config LOG_BUFFER_SIZE - default 128 if LOG - if FXOS8700 choice FXOS8700_MODE diff --git a/boards/arm/qemu_cortex_m0/Kconfig.defconfig b/boards/arm/qemu_cortex_m0/Kconfig.defconfig index 8aa63a89a57..3f203f2adbc 100644 --- a/boards/arm/qemu_cortex_m0/Kconfig.defconfig +++ b/boards/arm/qemu_cortex_m0/Kconfig.defconfig @@ -17,7 +17,4 @@ config SYS_CLOCK_HW_CYCLES_PER_SEC config SYS_CLOCK_TICKS_PER_SEC default 100 -config LOG_BUFFER_SIZE - default 128 if LOG - endif # BOARD_QEMU_CORTEX_M0 From c6f21b2017cf2c79a1750fe6dbe004a4a3077606 Mon Sep 17 00:00:00 2001 From: Richard Wheatley Date: Mon, 22 Jan 2024 08:39:07 -0600 Subject: [PATCH 2884/3723] boards: arm: apollo4p_evb Shield Support Correct pinctrl for rev2 board. Rename IOM properly in ambiq_apollo4p.dtsi Signed-off-by: Richard Wheatley --- .../apollo4p_evb/apollo4p_evb-pinctrl.dtsi | 1 + boards/arm/apollo4p_evb/apollo4p_evb.dts | 16 +++- .../apollo4p_evb/apollo4p_evb_connector.dtsi | 2 +- dts/arm/ambiq/ambiq_apollo4p.dtsi | 89 +++++++++++++++++-- 4 files changed, 97 insertions(+), 11 deletions(-) diff --git a/boards/arm/apollo4p_evb/apollo4p_evb-pinctrl.dtsi b/boards/arm/apollo4p_evb/apollo4p_evb-pinctrl.dtsi index 941c6271e22..b7b285d6ad8 100644 --- a/boards/arm/apollo4p_evb/apollo4p_evb-pinctrl.dtsi +++ b/boards/arm/apollo4p_evb/apollo4p_evb-pinctrl.dtsi @@ -98,6 +98,7 @@ }; group2 { pinmux = ; + drive-strength = "0.5"; drive-push-pull; ambiq,iom-nce-module = <4>; }; diff --git a/boards/arm/apollo4p_evb/apollo4p_evb.dts b/boards/arm/apollo4p_evb/apollo4p_evb.dts index 077262c49ab..8b87f96ac68 100644 --- a/boards/arm/apollo4p_evb/apollo4p_evb.dts +++ b/boards/arm/apollo4p_evb/apollo4p_evb.dts @@ -69,7 +69,7 @@ status = "okay"; }; -&iom0 { +&iom0_i2c { compatible = "ambiq,i2c"; pinctrl-0 = <&i2c0_default>; pinctrl-names = "default"; @@ -77,7 +77,7 @@ status = "okay"; }; -&iom1 { +&iom1_spi { compatible = "ambiq,spi"; pinctrl-0 = <&spi1_default>; pinctrl-names = "default"; @@ -91,6 +91,18 @@ status = "okay"; }; +&mspi1 { + pinctrl-0 = <&mspi1_default>; + pinctrl-names = "default"; + status = "okay"; +}; + +&mspi2 { + pinctrl-0 = <&mspi2_default>; + pinctrl-names = "default"; + status = "okay"; +}; + &gpio0_31 { status = "okay"; }; diff --git a/boards/arm/apollo4p_evb/apollo4p_evb_connector.dtsi b/boards/arm/apollo4p_evb/apollo4p_evb_connector.dtsi index b3cafd9587e..e083db991e2 100644 --- a/boards/arm/apollo4p_evb/apollo4p_evb_connector.dtsi +++ b/boards/arm/apollo4p_evb/apollo4p_evb_connector.dtsi @@ -118,4 +118,4 @@ }; }; -ambiq_spi: &iom1 {}; +spi1: &iom1_spi {}; diff --git a/dts/arm/ambiq/ambiq_apollo4p.dtsi b/dts/arm/ambiq/ambiq_apollo4p.dtsi index 390a0b3358a..a3abd1093e9 100644 --- a/dts/arm/ambiq/ambiq_apollo4p.dtsi +++ b/dts/arm/ambiq/ambiq_apollo4p.dtsi @@ -106,7 +106,7 @@ ambiq,pwrcfg = <&pwrcfg 0x4 0x1000>; }; - iom0: iom@40050000 { + iom0_spi: spi@40050000 { reg = <0x40050000 0x1000>; #address-cells = <1>; #size-cells = <0>; @@ -115,7 +115,16 @@ ambiq,pwrcfg = <&pwrcfg 0x4 0x2>; }; - iom1: iom@40051000 { + iom0_i2c: i2c@40050000 { + reg = <0x40050000 0x1000>; + #address-cells = <1>; + #size-cells = <0>; + interrupts = <6 0>; + status = "disabled"; + ambiq,pwrcfg = <&pwrcfg 0x4 0x2>; + }; + + iom1_spi: spi@40051000 { reg = <0x40051000 0x1000>; #address-cells = <1>; #size-cells = <0>; @@ -124,7 +133,16 @@ ambiq,pwrcfg = <&pwrcfg 0x4 0x4>; }; - iom2: iom@40052000 { + iom1_i2c: i2c@40051000 { + reg = <0x40051000 0x1000>; + #address-cells = <1>; + #size-cells = <0>; + interrupts = <7 0>; + status = "disabled"; + ambiq,pwrcfg = <&pwrcfg 0x4 0x4>; + }; + + iom2_spi: spi@40052000 { reg = <0x40052000 0x1000>; #address-cells = <1>; #size-cells = <0>; @@ -133,7 +151,25 @@ ambiq,pwrcfg = <&pwrcfg 0x4 0x8>; }; - iom3: iom@40053000 { + iom2_i2c: i2c@40052000 { + reg = <0x40052000 0x1000>; + #address-cells = <1>; + #size-cells = <0>; + interrupts = <8 0>; + status = "disabled"; + ambiq,pwrcfg = <&pwrcfg 0x4 0x8>; + }; + + iom3_spi: spi@40053000 { + reg = <0x40053000 0x1000>; + #address-cells = <1>; + #size-cells = <0>; + interrupts = <9 0>; + status = "disabled"; + ambiq,pwrcfg = <&pwrcfg 0x4 0x10>; + }; + + iom3_i2c: i2c@40053000 { reg = <0x40053000 0x1000>; #address-cells = <1>; #size-cells = <0>; @@ -141,7 +177,8 @@ status = "disabled"; ambiq,pwrcfg = <&pwrcfg 0x4 0x10>; }; - iom4: iom@40054000 { + + iom4_spi: spi@40054000 { reg = <0x40054000 0x1000>; #address-cells = <1>; #size-cells = <0>; @@ -150,7 +187,25 @@ ambiq,pwrcfg = <&pwrcfg 0x4 0x20>; }; - iom5: iom@40055000 { + iom4_i2c: i2c@40054000 { + reg = <0x40054000 0x1000>; + #address-cells = <1>; + #size-cells = <0>; + interrupts = <10 0>; + status = "disabled"; + ambiq,pwrcfg = <&pwrcfg 0x4 0x20>; + }; + + iom5_spi: spi@40055000 { + reg = <0x40055000 0x1000>; + #address-cells = <1>; + #size-cells = <0>; + interrupts = <11 0>; + status = "disabled"; + ambiq,pwrcfg = <&pwrcfg 0x4 0x40>; + }; + + iom5_i2c: i2c@40055000 { reg = <0x40055000 0x1000>; #address-cells = <1>; #size-cells = <0>; @@ -159,7 +214,7 @@ ambiq,pwrcfg = <&pwrcfg 0x4 0x40>; }; - iom6: iom@40056000 { + iom6_spi: spi@40056000 { reg = <0x40056000 0x1000>; #address-cells = <1>; #size-cells = <0>; @@ -168,7 +223,25 @@ ambiq,pwrcfg = <&pwrcfg 0x4 0x80>; }; - iom7: iom@40057000 { + iom6_i2c: i2c@40056000 { + reg = <0x40056000 0x1000>; + #address-cells = <1>; + #size-cells = <0>; + interrupts = <12 0>; + status = "disabled"; + ambiq,pwrcfg = <&pwrcfg 0x4 0x80>; + }; + + iom7_spi: spi@40057000 { + reg = <0x40057000 0x1000>; + #address-cells = <1>; + #size-cells = <0>; + interrupts = <13 0>; + status = "disabled"; + ambiq,pwrcfg = <&pwrcfg 0x4 0x100>; + }; + + iom7_i2c: i2c@40057000 { reg = <0x40057000 0x1000>; #address-cells = <1>; #size-cells = <0>; From 6400e3f4376bd3d0c38901dbcc9c4e1591c9404b Mon Sep 17 00:00:00 2001 From: Jan Bylicki Date: Fri, 15 Dec 2023 17:27:05 +0100 Subject: [PATCH 2885/3723] drivers: pinctrl: Add ZynqMP / Mercury XU pinctrl support Add a pinctrl driver for the ZynqMP SoC and the Mercury XU board powered by it. Signed-off-by: Jan Bylicki --- drivers/pinctrl/CMakeLists.txt | 1 + drivers/pinctrl/Kconfig | 1 + drivers/pinctrl/Kconfig.zynqmp | 9 ++++ drivers/pinctrl/pinctrl_xlnx_zynqmp.c | 38 +++++++++++++ dts/arm/xilinx/zynqmp.dtsi | 5 ++ dts/bindings/pinctrl/xlnx,pinctrl-zynqmp.yaml | 27 ++++++++++ .../dt-bindings/pinctrl/pinctrl-zynqmp.h | 16 ++++++ soc/arm/xilinx_zynqmp/pinctrl_soc.h | 54 +++++++++++++++++++ 8 files changed, 151 insertions(+) create mode 100644 drivers/pinctrl/Kconfig.zynqmp create mode 100644 drivers/pinctrl/pinctrl_xlnx_zynqmp.c create mode 100644 dts/bindings/pinctrl/xlnx,pinctrl-zynqmp.yaml create mode 100644 include/zephyr/dt-bindings/pinctrl/pinctrl-zynqmp.h create mode 100644 soc/arm/xilinx_zynqmp/pinctrl_soc.h diff --git a/drivers/pinctrl/CMakeLists.txt b/drivers/pinctrl/CMakeLists.txt index 9455b6e7c78..9ef54940b46 100644 --- a/drivers/pinctrl/CMakeLists.txt +++ b/drivers/pinctrl/CMakeLists.txt @@ -26,6 +26,7 @@ zephyr_library_sources_ifdef(CONFIG_PINCTRL_ESP32 pinctrl_esp32.c) zephyr_library_sources_ifdef(CONFIG_PINCTRL_RV32M1 pinctrl_rv32m1.c) zephyr_library_sources_ifdef(CONFIG_PINCTRL_INFINEON_CAT1 pinctrl_ifx_cat1.c) zephyr_library_sources_ifdef(CONFIG_PINCTRL_XLNX_ZYNQ pinctrl_xlnx_zynq.c) +zephyr_library_sources_ifdef(CONFIG_PINCTRL_XLNX_ZYNQMP pinctrl_xlnx_zynqmp.c) zephyr_library_sources_ifdef(CONFIG_PINCTRL_SMARTBOND pinctrl_smartbond.c) zephyr_library_sources_ifdef(CONFIG_PINCTRL_XMC4XXX pinctrl_xmc4xxx.c) zephyr_library_sources_ifdef(CONFIG_PINCTRL_NXP_S32 pinctrl_nxp_s32.c) diff --git a/drivers/pinctrl/Kconfig b/drivers/pinctrl/Kconfig index 8a165725e4d..d549622b3db 100644 --- a/drivers/pinctrl/Kconfig +++ b/drivers/pinctrl/Kconfig @@ -66,5 +66,6 @@ source "drivers/pinctrl/Kconfig.numaker" source "drivers/pinctrl/Kconfig.eos_s3" source "drivers/pinctrl/Kconfig.ra" source "drivers/pinctrl/Kconfig.rzt2m" +source "drivers/pinctrl/Kconfig.zynqmp" endif # PINCTRL diff --git a/drivers/pinctrl/Kconfig.zynqmp b/drivers/pinctrl/Kconfig.zynqmp new file mode 100644 index 00000000000..10e9b110584 --- /dev/null +++ b/drivers/pinctrl/Kconfig.zynqmp @@ -0,0 +1,9 @@ +# Copyright (c) 2024 Antmicro +# SPDX-License-Identifier: Apache-2.0 + +config PINCTRL_XLNX_ZYNQMP + bool "Xilinx ZynqMP pin controller driver" + default y + depends on DT_HAS_XLNX_PINCTRL_ZYNQMP_ENABLED + help + Enable the Xilinx ZynqMP processor system MIO pin controller driver. diff --git a/drivers/pinctrl/pinctrl_xlnx_zynqmp.c b/drivers/pinctrl/pinctrl_xlnx_zynqmp.c new file mode 100644 index 00000000000..6d874801c51 --- /dev/null +++ b/drivers/pinctrl/pinctrl_xlnx_zynqmp.c @@ -0,0 +1,38 @@ +/* + * Copyright (c) 2024 Antmicro + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include +#include +#include "pinctrl_soc.h" + +LOG_MODULE_REGISTER(pinctrl_xlnx_zynqmp, CONFIG_PINCTRL_LOG_LEVEL); + +#define DT_DRV_COMPAT xlnx_pinctrl_zynqmp + +static mm_reg_t base = DT_INST_REG_ADDR(0); +static uint8_t mio_pin_offset = 0x04; + +int pinctrl_configure_pins(const pinctrl_soc_pin_t *pins, uint8_t pin_cnt, uintptr_t reg) +{ + for (uint8_t i = 0U; i < pin_cnt; i++) { + uint32_t sel = 0; + + switch (pins[i].func) { + case UART_FUNCTION: { + sel = UARTX_SEL; + break; + } + + default: { + LOG_ERR("Unsupported function enum was selected"); + break; + } + } + sys_write32(sel, base + mio_pin_offset * pins[i].pin); + } + + return 0; +} diff --git a/dts/arm/xilinx/zynqmp.dtsi b/dts/arm/xilinx/zynqmp.dtsi index 84c1c574d22..65abc450543 100644 --- a/dts/arm/xilinx/zynqmp.dtsi +++ b/dts/arm/xilinx/zynqmp.dtsi @@ -11,6 +11,10 @@ / { soc { + pinctrl: pinctrl@ff180000 { + reg = <0xff180000 0xc80>; + compatible = "xlnx,pinctrl-zynqmp"; + }; flash0: flash@c0000000 { compatible = "soc-nv-flash"; reg = <0xc0000000 DT_SIZE_M(32)>; @@ -271,4 +275,5 @@ }; }; }; + }; diff --git a/dts/bindings/pinctrl/xlnx,pinctrl-zynqmp.yaml b/dts/bindings/pinctrl/xlnx,pinctrl-zynqmp.yaml new file mode 100644 index 00000000000..7a5af3a2b7d --- /dev/null +++ b/dts/bindings/pinctrl/xlnx,pinctrl-zynqmp.yaml @@ -0,0 +1,27 @@ +# Copyright (c) 2024 Antmicro +# SPDX-License-Identifier: Apache-2.0 + +description: | + Xilinx ZynqMP SoC pinctrl node. It allows configuration of pin assignments + for the supported peripherals. + + See Zynq UltraScale+ Devices Register Reference (UG1087) for details regarding + valid pin assignments +compatible: "xlnx,pinctrl-zynqmp" + +include: base.yaml + +child-binding: + description: | + Definitions for a pinctrl state. + child-binding: + + include: + - name: pincfg-node.yaml + + properties: + pinmux: + required: true + type: array + description: | + Pin assignments for the selected group diff --git a/include/zephyr/dt-bindings/pinctrl/pinctrl-zynqmp.h b/include/zephyr/dt-bindings/pinctrl/pinctrl-zynqmp.h new file mode 100644 index 00000000000..1dede9b2530 --- /dev/null +++ b/include/zephyr/dt-bindings/pinctrl/pinctrl-zynqmp.h @@ -0,0 +1,16 @@ +/* + * Copyright (c) 2024 Antmicro + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#ifndef ZEPHYR_INCLUDE_DT_BINDINGS_PINCTRL_ZYNQMP_PINCTRL_H_ +#define ZEPHYR_INCLUDE_DT_BINDINGS_PINCTRL_ZYNQMP_PINCTRL_H_ + +#define UART_FUNCTION 0x1 + +#define UART0_RX_38 (38U | (UART_FUNCTION << 8)) +#define UART0_TX_39 (39U | (UART_FUNCTION << 8)) + + +#endif diff --git a/soc/arm/xilinx_zynqmp/pinctrl_soc.h b/soc/arm/xilinx_zynqmp/pinctrl_soc.h new file mode 100644 index 00000000000..90b6d2acac3 --- /dev/null +++ b/soc/arm/xilinx_zynqmp/pinctrl_soc.h @@ -0,0 +1,54 @@ +/* + * Copyright (c) 2024 Antmicro + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#ifndef ZEPHYR_SOC_ARM_XLNX_ZYNQMP_SOC_PINCTRL_H_ +#define ZEPHYR_SOC_ARM_XLNX_ZYNQMP_SOC_PINCTRL_H_ + +#include +#include +#include + +#define MIO_L0_SEL BIT(1) +#define MIO_L1_SEL BIT(2) +#define MIO_L2_SEL GENMASK(4, 3) +#define MIO_L3_SEL GENMASK(7, 5) + +/* All other selectors should be zeroed and FIELD_PREP does that */ +#define UARTX_SEL FIELD_PREP(MIO_L3_SEL, 6) + +/* + * Each peripheral PINCTRL mask is defined as such: + * [7 ... 0] MIO register number + * [15 ... 8] Function, mapped as: + * 1 - UART + * + * The function numbers serve as an enumerator in the pinctrl driver + * and the defines controling those are listed in `pinctrl-zynqmp.h`. + * Currently, one function for UART is specified and subsequent ones + * can be added when the need arises. + */ + +typedef struct pinctrl_soc_pin_t { + uint32_t pin; + uint32_t func; +} pinctrl_soc_pin_t; + + +#define ZYNQMP_GET_PIN(pinctrl) (pinctrl & 0xff) +#define ZYNQMP_GET_FUNC(pinctrl) ((pinctrl >> 8) & 0xff) + +#define Z_PINCTRL_STATE_PIN_INIT(node_id, prop, idx) \ + { \ + .pin = ZYNQMP_GET_PIN(DT_PROP_BY_IDX(node_id, prop, idx)), \ + .func = ZYNQMP_GET_FUNC(DT_PROP_BY_IDX(node_id, prop, idx)), \ + }, + +#define Z_PINCTRL_STATE_PINS_INIT(node_id, prop) { \ + DT_FOREACH_CHILD_VARGS(DT_PHANDLE(node_id, prop), \ + DT_FOREACH_PROP_ELEM, pinmux, \ + Z_PINCTRL_STATE_PIN_INIT)} + +#endif From 3042cb877a5337e791d25a83a20c2480430a8bd8 Mon Sep 17 00:00:00 2001 From: Jan Bylicki Date: Fri, 12 Jan 2024 11:12:19 +0100 Subject: [PATCH 2886/3723] boards: arm: mercury_xu: Define the pinctrl instance Define the pinctrl-based pin controller instance for the Mercury XU board and remove the old implementation Signed-off-by: Jan Bylicki --- boards/arm/mercury_xu/board.c | 15 --------------- boards/arm/mercury_xu/mercury_xu-pinctrl.dtsi | 18 ++++++++++++++++++ boards/arm/mercury_xu/mercury_xu.dts | 3 +++ boards/arm/mercury_xu/mercury_xu_defconfig | 2 ++ 4 files changed, 23 insertions(+), 15 deletions(-) create mode 100644 boards/arm/mercury_xu/mercury_xu-pinctrl.dtsi diff --git a/boards/arm/mercury_xu/board.c b/boards/arm/mercury_xu/board.c index 8204b29ae90..db436299a9c 100644 --- a/boards/arm/mercury_xu/board.c +++ b/boards/arm/mercury_xu/board.c @@ -6,24 +6,9 @@ #include #include -#define MIO_PIN_18 0xff180048 -#define MIO_PIN_19 0xff18004c -#define MIO_PIN_38 0xff180098 -#define MIO_PIN_39 0xff18009c - -#define MIO_DEFAULT 0x0 -#define MIO_UART0 0xc0 static int mercury_xu_init(void) { - /* pinmux settings for uart */ - sys_write32(MIO_UART0, MIO_PIN_38); - sys_write32(MIO_UART0, MIO_PIN_39); - - /* disable misleading pinmux */ - sys_write32(MIO_DEFAULT, MIO_PIN_18); - sys_write32(MIO_DEFAULT, MIO_PIN_19); - return 0; } diff --git a/boards/arm/mercury_xu/mercury_xu-pinctrl.dtsi b/boards/arm/mercury_xu/mercury_xu-pinctrl.dtsi new file mode 100644 index 00000000000..9fdf4a09f83 --- /dev/null +++ b/boards/arm/mercury_xu/mercury_xu-pinctrl.dtsi @@ -0,0 +1,18 @@ +/* + * Copyright (c) 2024 Antmicro + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include + +&pinctrl { + uart0_default: uart0_default { + group1 { + pinmux = ; + }; + group2 { + pinmux = ; + }; + }; +}; diff --git a/boards/arm/mercury_xu/mercury_xu.dts b/boards/arm/mercury_xu/mercury_xu.dts index f6af2ca3018..7e2b7e80c85 100644 --- a/boards/arm/mercury_xu/mercury_xu.dts +++ b/boards/arm/mercury_xu/mercury_xu.dts @@ -6,6 +6,7 @@ /dts-v1/; #include +#include "mercury_xu-pinctrl.dtsi" / { model = "Mercury XU"; @@ -28,6 +29,8 @@ status = "okay"; current-speed = <115200>; clock-frequency = <99999901>; + pinctrl-0 = <&uart0_default>; + pinctrl-names = "default"; }; &ttc0 { diff --git a/boards/arm/mercury_xu/mercury_xu_defconfig b/boards/arm/mercury_xu/mercury_xu_defconfig index 6655cf9a442..d01d7082f94 100644 --- a/boards/arm/mercury_xu/mercury_xu_defconfig +++ b/boards/arm/mercury_xu/mercury_xu_defconfig @@ -11,3 +11,5 @@ CONFIG_UART_CONSOLE=y # enable timer CONFIG_SYS_CLOCK_TICKS_PER_SEC=100 + +CONFIG_PINCTRL=y From 3ef7f2a5116f77817c459464c75b65f1b822474e Mon Sep 17 00:00:00 2001 From: Jan Bylicki Date: Thu, 4 Jan 2024 15:14:55 +0100 Subject: [PATCH 2887/3723] boards: arm: mercury_xu: Add remaining UART pin definitions Add remaining UART0 pin definitions and migrate UART1 to utilize the pinmux api Signed-off-by: Jan Bylicki --- boards/arm/mercury_xu/mercury_xu-pinctrl.dtsi | 9 ++ boards/arm/mercury_xu/mercury_xu.dts | 9 ++ .../dt-bindings/pinctrl/pinctrl-zynqmp.h | 92 ++++++++++++++++++- 3 files changed, 108 insertions(+), 2 deletions(-) diff --git a/boards/arm/mercury_xu/mercury_xu-pinctrl.dtsi b/boards/arm/mercury_xu/mercury_xu-pinctrl.dtsi index 9fdf4a09f83..3bc31ad3c74 100644 --- a/boards/arm/mercury_xu/mercury_xu-pinctrl.dtsi +++ b/boards/arm/mercury_xu/mercury_xu-pinctrl.dtsi @@ -15,4 +15,13 @@ pinmux = ; }; }; + uart1_default: uart1_default { + group1 { + pinmux = ; + }; + group2 { + pinmux = ; + }; + }; + }; diff --git a/boards/arm/mercury_xu/mercury_xu.dts b/boards/arm/mercury_xu/mercury_xu.dts index 7e2b7e80c85..df51ab470c5 100644 --- a/boards/arm/mercury_xu/mercury_xu.dts +++ b/boards/arm/mercury_xu/mercury_xu.dts @@ -33,7 +33,16 @@ pinctrl-names = "default"; }; +&uart1 { + pinctrl-0 = <&uart1_default>; + pinctrl-names = "default"; +}; + &ttc0 { status = "okay"; clock-frequency = <5000000>; }; + +&psgpio { + status = "okay"; +}; diff --git a/include/zephyr/dt-bindings/pinctrl/pinctrl-zynqmp.h b/include/zephyr/dt-bindings/pinctrl/pinctrl-zynqmp.h index 1dede9b2530..3fb83a3a7a4 100644 --- a/include/zephyr/dt-bindings/pinctrl/pinctrl-zynqmp.h +++ b/include/zephyr/dt-bindings/pinctrl/pinctrl-zynqmp.h @@ -7,10 +7,98 @@ #ifndef ZEPHYR_INCLUDE_DT_BINDINGS_PINCTRL_ZYNQMP_PINCTRL_H_ #define ZEPHYR_INCLUDE_DT_BINDINGS_PINCTRL_ZYNQMP_PINCTRL_H_ +/* + * The offset is defined at `pictrl_soc.h` for the ZynqMP platform + */ +#define FUNCTION_OFFSET 8 #define UART_FUNCTION 0x1 -#define UART0_RX_38 (38U | (UART_FUNCTION << 8)) -#define UART0_TX_39 (39U | (UART_FUNCTION << 8)) +/* + * For functions that can be selected for a subset of MIO pins, + * specific macro identifiers were generated to avoid complex checking + * logic at compile time. For more generalized applications existing on + * every pin (eg. GPIO), a generic macro function to generate a driver-compliant + * selector value can be used. + */ + +#define UART0_RX_2 (2U | (UART_FUNCTION << FUNCTION_OFFSET)) +#define UART0_RX_6 (6U | (UART_FUNCTION << FUNCTION_OFFSET)) +#define UART0_RX_10 (10U | (UART_FUNCTION << FUNCTION_OFFSET)) +#define UART0_RX_14 (14U | (UART_FUNCTION << FUNCTION_OFFSET)) +#define UART0_RX_18 (18U | (UART_FUNCTION << FUNCTION_OFFSET)) +#define UART0_RX_22 (22U | (UART_FUNCTION << FUNCTION_OFFSET)) +#define UART0_RX_26 (26U | (UART_FUNCTION << FUNCTION_OFFSET)) +#define UART0_RX_30 (30U | (UART_FUNCTION << FUNCTION_OFFSET)) +#define UART0_RX_34 (34U | (UART_FUNCTION << FUNCTION_OFFSET)) +#define UART0_RX_38 (38U | (UART_FUNCTION << FUNCTION_OFFSET)) +#define UART0_RX_42 (42U | (UART_FUNCTION << FUNCTION_OFFSET)) +#define UART0_RX_46 (46U | (UART_FUNCTION << FUNCTION_OFFSET)) +#define UART0_RX_50 (50U | (UART_FUNCTION << FUNCTION_OFFSET)) +#define UART0_RX_54 (54U | (UART_FUNCTION << FUNCTION_OFFSET)) +#define UART0_RX_58 (58U | (UART_FUNCTION << FUNCTION_OFFSET)) +#define UART0_RX_62 (62U | (UART_FUNCTION << FUNCTION_OFFSET)) +#define UART0_RX_66 (66U | (UART_FUNCTION << FUNCTION_OFFSET)) +#define UART0_RX_70 (70U | (UART_FUNCTION << FUNCTION_OFFSET)) +#define UART0_RX_74 (74U | (UART_FUNCTION << FUNCTION_OFFSET)) + +#define UART0_TX_3 (3U | (UART_FUNCTION << FUNCTION_OFFSET)) +#define UART0_TX_7 (7U | (UART_FUNCTION << FUNCTION_OFFSET)) +#define UART0_TX_11 (11U | (UART_FUNCTION << FUNCTION_OFFSET)) +#define UART0_TX_15 (15U | (UART_FUNCTION << FUNCTION_OFFSET)) +#define UART0_TX_19 (19U | (UART_FUNCTION << FUNCTION_OFFSET)) +#define UART0_TX_23 (23U | (UART_FUNCTION << FUNCTION_OFFSET)) +#define UART0_TX_27 (27U | (UART_FUNCTION << FUNCTION_OFFSET)) +#define UART0_TX_31 (31U | (UART_FUNCTION << FUNCTION_OFFSET)) +#define UART0_TX_35 (35U | (UART_FUNCTION << FUNCTION_OFFSET)) +#define UART0_TX_39 (39U | (UART_FUNCTION << FUNCTION_OFFSET)) +#define UART0_TX_43 (43U | (UART_FUNCTION << FUNCTION_OFFSET)) +#define UART0_TX_47 (47U | (UART_FUNCTION << FUNCTION_OFFSET)) +#define UART0_TX_51 (51U | (UART_FUNCTION << FUNCTION_OFFSET)) +#define UART0_TX_55 (55U | (UART_FUNCTION << FUNCTION_OFFSET)) +#define UART0_TX_59 (59U | (UART_FUNCTION << FUNCTION_OFFSET)) +#define UART0_TX_63 (63U | (UART_FUNCTION << FUNCTION_OFFSET)) +#define UART0_TX_67 (67U | (UART_FUNCTION << FUNCTION_OFFSET)) +#define UART0_TX_71 (71U | (UART_FUNCTION << FUNCTION_OFFSET)) +#define UART0_TX_75 (75U | (UART_FUNCTION << FUNCTION_OFFSET)) + +#define UART1_RX_1 (1U | (UART_FUNCTION << FUNCTION_OFFSET)) +#define UART1_RX_5 (5U | (UART_FUNCTION << FUNCTION_OFFSET)) +#define UART1_RX_9 (9U | (UART_FUNCTION << FUNCTION_OFFSET)) +#define UART1_RX_13 (13U | (UART_FUNCTION << FUNCTION_OFFSET)) +#define UART1_RX_17 (17U | (UART_FUNCTION << FUNCTION_OFFSET)) +#define UART1_RX_21 (21U | (UART_FUNCTION << FUNCTION_OFFSET)) +#define UART1_RX_25 (25U | (UART_FUNCTION << FUNCTION_OFFSET)) +#define UART1_RX_29 (29U | (UART_FUNCTION << FUNCTION_OFFSET)) +#define UART1_RX_33 (33U | (UART_FUNCTION << FUNCTION_OFFSET)) +#define UART1_RX_37 (37U | (UART_FUNCTION << FUNCTION_OFFSET)) +#define UART1_RX_41 (41U | (UART_FUNCTION << FUNCTION_OFFSET)) +#define UART1_RX_45 (45U | (UART_FUNCTION << FUNCTION_OFFSET)) +#define UART1_RX_49 (49U | (UART_FUNCTION << FUNCTION_OFFSET)) +#define UART1_RX_53 (53U | (UART_FUNCTION << FUNCTION_OFFSET)) +#define UART1_RX_57 (57U | (UART_FUNCTION << FUNCTION_OFFSET)) +#define UART1_RX_61 (61U | (UART_FUNCTION << FUNCTION_OFFSET)) +#define UART1_RX_65 (65U | (UART_FUNCTION << FUNCTION_OFFSET)) +#define UART1_RX_69 (69U | (UART_FUNCTION << FUNCTION_OFFSET)) +#define UART1_RX_73 (73U | (UART_FUNCTION << FUNCTION_OFFSET)) +#define UART1_TX_0 (0U | (UART_FUNCTION << FUNCTION_OFFSET)) +#define UART1_TX_4 (4U | (UART_FUNCTION << FUNCTION_OFFSET)) +#define UART1_TX_8 (8U | (UART_FUNCTION << FUNCTION_OFFSET)) +#define UART1_TX_12 (12U | (UART_FUNCTION << FUNCTION_OFFSET)) +#define UART1_TX_16 (16U | (UART_FUNCTION << FUNCTION_OFFSET)) +#define UART1_TX_20 (20U | (UART_FUNCTION << FUNCTION_OFFSET)) +#define UART1_TX_24 (24U | (UART_FUNCTION << FUNCTION_OFFSET)) +#define UART1_TX_28 (28U | (UART_FUNCTION << FUNCTION_OFFSET)) +#define UART1_TX_32 (32U | (UART_FUNCTION << FUNCTION_OFFSET)) +#define UART1_TX_36 (36U | (UART_FUNCTION << FUNCTION_OFFSET)) +#define UART1_TX_40 (40U | (UART_FUNCTION << FUNCTION_OFFSET)) +#define UART1_TX_44 (44U | (UART_FUNCTION << FUNCTION_OFFSET)) +#define UART1_TX_48 (28U | (UART_FUNCTION << FUNCTION_OFFSET)) +#define UART1_TX_52 (52U | (UART_FUNCTION << FUNCTION_OFFSET)) +#define UART1_TX_56 (56U | (UART_FUNCTION << FUNCTION_OFFSET)) +#define UART1_TX_60 (60U | (UART_FUNCTION << FUNCTION_OFFSET)) +#define UART1_TX_64 (64U | (UART_FUNCTION << FUNCTION_OFFSET)) +#define UART1_TX_68 (28U | (UART_FUNCTION << FUNCTION_OFFSET)) +#define UART1_TX_72 (72U | (UART_FUNCTION << FUNCTION_OFFSET)) #endif From 5eb0bbeb54e7d733f272cf6ae52f37f88b60fb03 Mon Sep 17 00:00:00 2001 From: Christopher Friedt Date: Tue, 23 Jan 2024 15:09:23 -0500 Subject: [PATCH 2888/3723] tests: posix: pthread_attr: skip when large stack allocation fails Rather than fail when attempting to set an extraordinarily large pthread stack size (much larger than most Zephyr platforms have) consider the test non-fatal and skip it. Signed-off-by: Christopher Friedt --- tests/posix/common/src/pthread_attr.c | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/tests/posix/common/src/pthread_attr.c b/tests/posix/common/src/pthread_attr.c index f2a9b2da22f..99568a85298 100644 --- a/tests/posix/common/src/pthread_attr.c +++ b/tests/posix/common/src/pthread_attr.c @@ -444,7 +444,12 @@ ZTEST(pthread_attr, test_pthread_attr_large_stacksize) size_t actual_size; const size_t expect_size = BIT(CONFIG_POSIX_PTHREAD_ATTR_STACKSIZE_BITS); - zassert_ok(pthread_attr_setstacksize(&attr, expect_size)); + if (pthread_attr_setstacksize(&attr, expect_size) != 0) { + TC_PRINT("Unable to allocate large stack of size %zu (skipping)\n", expect_size); + ztest_test_skip(); + return; + } + zassert_ok(pthread_attr_getstacksize(&attr, &actual_size)); zassert_equal(actual_size, expect_size); } From 5ca0f28bb214a4b2e8dd7522e3c124811e3f7e00 Mon Sep 17 00:00:00 2001 From: Christopher Friedt Date: Wed, 24 Jan 2024 15:49:41 -0500 Subject: [PATCH 2889/3723] tests: posix: common: dedicated config for static thread stacks The testsuite has been shifted to use dynamic thread stacks (either statically allocated via a pool, or dynamically allocated via the heap). However, we definitely still need coverage for manually specified thread stacks - but lets avoid duplicating tests unnecessarily. Signed-off-by: Christopher Friedt --- tests/posix/common/src/key.c | 12 +++++++++++- tests/posix/common/src/mqueue.c | 12 +++++++++++- tests/posix/common/src/mutex.c | 12 +++++++++++- tests/posix/common/src/pthread.c | 12 +++++++++++- tests/posix/common/src/rwlock.c | 12 +++++++++++- tests/posix/common/src/semaphore.c | 12 +++++++++++- tests/posix/common/src/signal.c | 12 +++++++++++- tests/posix/common/src/timer.c | 12 +++++++++++- tests/posix/common/testcase.yaml | 7 +++++++ 9 files changed, 95 insertions(+), 8 deletions(-) diff --git a/tests/posix/common/src/key.c b/tests/posix/common/src/key.c index 4c6d9be16ef..e7486c5327c 100644 --- a/tests/posix/common/src/key.c +++ b/tests/posix/common/src/key.c @@ -144,4 +144,14 @@ ZTEST(key, test_correct_key_is_deleted) } } -ZTEST_SUITE(key, NULL, NULL, NULL, NULL, NULL); +static void before(void *arg) +{ + ARG_UNUSED(arg); + + if (!IS_ENABLED(CONFIG_DYNAMIC_THREAD)) { + /* skip redundant testing if there is no thread pool / heap allocation */ + ztest_test_skip(); + } +} + +ZTEST_SUITE(key, NULL, NULL, before, NULL, NULL); diff --git a/tests/posix/common/src/mqueue.c b/tests/posix/common/src/mqueue.c index 45229ba9d13..a9c1f9423c4 100644 --- a/tests/posix/common/src/mqueue.c +++ b/tests/posix/common/src/mqueue.c @@ -276,4 +276,14 @@ ZTEST(mqueue, test_mqueue_notify_errors) zassert_ok(mq_unlink(queue), "Unable to unlink queue"); } -ZTEST_SUITE(mqueue, NULL, NULL, NULL, NULL, NULL); +static void before(void *arg) +{ + ARG_UNUSED(arg); + + if (!IS_ENABLED(CONFIG_DYNAMIC_THREAD)) { + /* skip redundant testing if there is no thread pool / heap allocation */ + ztest_test_skip(); + } +} + +ZTEST_SUITE(mqueue, NULL, NULL, before, NULL, NULL); diff --git a/tests/posix/common/src/mutex.c b/tests/posix/common/src/mutex.c index a296d41e8e0..0968facfb0c 100644 --- a/tests/posix/common/src/mutex.c +++ b/tests/posix/common/src/mutex.c @@ -195,4 +195,14 @@ ZTEST(mutex, test_mutex_timedlock) zassert_ok(pthread_mutex_destroy(&mutex)); } -ZTEST_SUITE(mutex, NULL, NULL, NULL, NULL, NULL); +static void before(void *arg) +{ + ARG_UNUSED(arg); + + if (!IS_ENABLED(CONFIG_DYNAMIC_THREAD)) { + /* skip redundant testing if there is no thread pool / heap allocation */ + ztest_test_skip(); + } +} + +ZTEST_SUITE(mutex, NULL, NULL, before, NULL, NULL); diff --git a/tests/posix/common/src/pthread.c b/tests/posix/common/src/pthread.c index d4038eba629..0977a25633f 100644 --- a/tests/posix/common/src/pthread.c +++ b/tests/posix/common/src/pthread.c @@ -461,4 +461,14 @@ ZTEST(pthread, test_pthread_cleanup) zassert_ok(pthread_join(th, NULL)); } -ZTEST_SUITE(pthread, NULL, NULL, NULL, NULL, NULL); +static void before(void *arg) +{ + ARG_UNUSED(arg); + + if (!IS_ENABLED(CONFIG_DYNAMIC_THREAD)) { + /* skip redundant testing if there is no thread pool / heap allocation */ + ztest_test_skip(); + } +} + +ZTEST_SUITE(pthread, NULL, NULL, before, NULL, NULL); diff --git a/tests/posix/common/src/rwlock.c b/tests/posix/common/src/rwlock.c index ffba9956a7e..44d3cce2971 100644 --- a/tests/posix/common/src/rwlock.c +++ b/tests/posix/common/src/rwlock.c @@ -117,4 +117,14 @@ ZTEST(rwlock, test_rw_lock) zassert_ok(pthread_rwlock_destroy(&rwlock), "Failed to destroy rwlock"); } -ZTEST_SUITE(rwlock, NULL, NULL, NULL, NULL, NULL); +static void before(void *arg) +{ + ARG_UNUSED(arg); + + if (!IS_ENABLED(CONFIG_DYNAMIC_THREAD)) { + /* skip redundant testing if there is no thread pool / heap allocation */ + ztest_test_skip(); + } +} + +ZTEST_SUITE(rwlock, NULL, NULL, before, NULL, NULL); diff --git a/tests/posix/common/src/semaphore.c b/tests/posix/common/src/semaphore.c index f445c5ce2f4..a1f15cf5c5d 100644 --- a/tests/posix/common/src/semaphore.c +++ b/tests/posix/common/src/semaphore.c @@ -311,4 +311,14 @@ ZTEST(semaphore, test_named_semaphore) zassert_equal(nsem_get_list_len(), 0); } -ZTEST_SUITE(semaphore, NULL, NULL, NULL, NULL, NULL); +static void before(void *arg) +{ + ARG_UNUSED(arg); + + if (!IS_ENABLED(CONFIG_DYNAMIC_THREAD)) { + /* skip redundant testing if there is no thread pool / heap allocation */ + ztest_test_skip(); + } +} + +ZTEST_SUITE(semaphore, NULL, NULL, before, NULL, NULL); diff --git a/tests/posix/common/src/signal.c b/tests/posix/common/src/signal.c index 11db9575f8b..ddfba977c76 100644 --- a/tests/posix/common/src/signal.c +++ b/tests/posix/common/src/signal.c @@ -320,4 +320,14 @@ ZTEST(signal, test_sigprocmask) } } -ZTEST_SUITE(signal, NULL, NULL, NULL, NULL, NULL); +static void before(void *arg) +{ + ARG_UNUSED(arg); + + if (!IS_ENABLED(CONFIG_DYNAMIC_THREAD)) { + /* skip redundant testing if there is no thread pool / heap allocation */ + ztest_test_skip(); + } +} + +ZTEST_SUITE(signal, NULL, NULL, before, NULL, NULL); diff --git a/tests/posix/common/src/timer.c b/tests/posix/common/src/timer.c index ffb94e93618..e4903839f8d 100644 --- a/tests/posix/common/src/timer.c +++ b/tests/posix/common/src/timer.c @@ -132,4 +132,14 @@ static void after(void *arg) } } -ZTEST_SUITE(timer, NULL, NULL, NULL, after, NULL); +static void before(void *arg) +{ + ARG_UNUSED(arg); + + if (!IS_ENABLED(CONFIG_DYNAMIC_THREAD)) { + /* skip redundant testing if there is no thread pool / heap allocation */ + ztest_test_skip(); + } +} + +ZTEST_SUITE(timer, NULL, NULL, before, after, NULL); diff --git a/tests/posix/common/testcase.yaml b/tests/posix/common/testcase.yaml index 40c24f08d0e..225ec292adf 100644 --- a/tests/posix/common/testcase.yaml +++ b/tests/posix/common/testcase.yaml @@ -97,3 +97,10 @@ tests: - CONFIG_THREAD_STACK_INFO=y - CONFIG_DYNAMIC_THREAD_POOL_SIZE=5 - CONFIG_HEAP_MEM_POOL_SIZE=16384 + portability.posix.common.static_stack: + integration_platforms: + - qemu_x86 + - qemu_riscv64 + extra_configs: + - CONFIG_DYNAMIC_THREAD=n + - CONFIG_THREAD_STACK_INFO=n From 9f3d7776abe58b674744a2888dc4e627418107c6 Mon Sep 17 00:00:00 2001 From: Christopher Friedt Date: Mon, 1 Jan 2024 13:01:35 -0500 Subject: [PATCH 2890/3723] kernel: dynamic: reduce verbosity in degenerate case k_thread_stack_free() is designed to be called with any pointer value. We return -EINVAL when an attempt is made to free an invalid stack pointer. This change reduces the verbosity in the degenerate case, when the pointer is not obtained via k_thread_stack_alloc(), but otherwise does not affect functionality. If debug log verbosity is not enabled, we save a few bytes in .text / .rodata / .strtab. Signed-off-by: Christopher Friedt --- kernel/dynamic.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/kernel/dynamic.c b/kernel/dynamic.c index df94aaaaefa..b9d34cbb52c 100644 --- a/kernel/dynamic.c +++ b/kernel/dynamic.c @@ -156,7 +156,7 @@ int z_impl_k_thread_stack_free(k_thread_stack_t *stack) k_free(stack); #endif } else { - LOG_ERR("Invalid stack %p", stack); + LOG_DBG("Invalid stack %p", stack); return -EINVAL; } From 301581a89219ef0017496349830fb767a9dcb3ec Mon Sep 17 00:00:00 2001 From: Christopher Friedt Date: Tue, 23 Jan 2024 18:31:15 -0500 Subject: [PATCH 2891/3723] posix: pthread: wrapper to check attribute initialization Add a small wrapper to check if a pthread_attr_t has been properly initialized (i.e. ready to pass to pthread_create()). Signed-off-by: Christopher Friedt --- lib/posix/pthread.c | 62 +++++++++++++++++++++++++-------------------- 1 file changed, 35 insertions(+), 27 deletions(-) diff --git a/lib/posix/pthread.c b/lib/posix/pthread.c index 7b46fd7f4f9..913c81389d4 100644 --- a/lib/posix/pthread.c +++ b/lib/posix/pthread.c @@ -253,6 +253,11 @@ int posix_to_zephyr_priority(int priority, int policy) return POSIX_TO_ZEPHYR_PRIORITY(priority, policy); } +static bool __attr_is_initialized(const struct posix_thread_attr *attr) +{ + return attr != NULL && attr->initialized; +} + /** * @brief Set scheduling parameter attributes in thread attributes object. * @@ -262,7 +267,7 @@ int pthread_attr_setschedparam(pthread_attr_t *_attr, const struct sched_param * { struct posix_thread_attr *attr = (struct posix_thread_attr *)_attr; - if (attr == NULL || !attr->initialized || schedparam == NULL || + if (!__attr_is_initialized(attr) || schedparam == NULL || !is_posix_policy_prio_valid(schedparam->sched_priority, attr->schedpolicy)) { LOG_ERR("Invalid pthread_attr_t or sched_param"); return EINVAL; @@ -286,7 +291,8 @@ int pthread_attr_setstack(pthread_attr_t *_attr, void *stackaddr, size_t stacksi return EACCES; } - if (stacksize == 0 || stacksize < PTHREAD_STACK_MIN || stacksize > PTHREAD_STACK_MAX) { + if (!__attr_is_initialized(attr) || stacksize < PTHREAD_STACK_MIN || + stacksize > PTHREAD_STACK_MAX) { LOG_ERR("Invalid stacksize %zu", stacksize); return EINVAL; } @@ -298,15 +304,22 @@ int pthread_attr_setstack(pthread_attr_t *_attr, void *stackaddr, size_t stacksi static bool pthread_attr_is_valid(const struct posix_thread_attr *attr) { + size_t stacksize; + /* auto-alloc thread stack */ if (attr == NULL) { return true; } - /* caller-provided thread stack */ - if (!attr->initialized || attr->stack == NULL || attr->stacksize == 0 || - __get_attr_stacksize(attr) < PTHREAD_STACK_MIN) { - LOG_ERR("pthread_attr_t is not initialized, has a NULL stack, or invalid size"); + if (!__attr_is_initialized(attr) || attr->stack == NULL) { + LOG_DBG("attr %p is not initialized", attr); + return false; + } + + stacksize = __get_attr_stacksize(attr); + if (stacksize < PTHREAD_STACK_MIN) { + LOG_DBG("attr %p has stacksize %zu is smaller than PTHREAD_STACK_MIN (%zu)", attr, + stacksize, (size_t)PTHREAD_STACK_MIN); return false; } @@ -888,7 +901,7 @@ int pthread_attr_getdetachstate(const pthread_attr_t *_attr, int *detachstate) { const struct posix_thread_attr *attr = (const struct posix_thread_attr *)_attr; - if ((attr == NULL) || (attr->initialized == false) || (detachstate == NULL)) { + if (!__attr_is_initialized(attr) || (detachstate == NULL)) { return EINVAL; } @@ -905,9 +918,8 @@ int pthread_attr_setdetachstate(pthread_attr_t *_attr, int detachstate) { struct posix_thread_attr *attr = (struct posix_thread_attr *)_attr; - if ((attr == NULL) || (attr->initialized == false) || - ((detachstate != PTHREAD_CREATE_DETACHED) && - (detachstate != PTHREAD_CREATE_JOINABLE))) { + if (!__attr_is_initialized(attr) || ((detachstate != PTHREAD_CREATE_DETACHED) && + (detachstate != PTHREAD_CREATE_JOINABLE))) { return EINVAL; } @@ -924,7 +936,7 @@ int pthread_attr_getschedpolicy(const pthread_attr_t *_attr, int *policy) { const struct posix_thread_attr *attr = (const struct posix_thread_attr *)_attr; - if ((attr == NULL) || (attr->initialized == 0U) || (policy == NULL)) { + if (!__attr_is_initialized(attr) || (policy == NULL)) { return EINVAL; } @@ -941,7 +953,7 @@ int pthread_attr_setschedpolicy(pthread_attr_t *_attr, int policy) { struct posix_thread_attr *attr = (struct posix_thread_attr *)_attr; - if ((attr == NULL) || (attr->initialized == 0U) || !valid_posix_policy(policy)) { + if (!__attr_is_initialized(attr) || !valid_posix_policy(policy)) { return EINVAL; } @@ -958,7 +970,7 @@ int pthread_attr_getstacksize(const pthread_attr_t *_attr, size_t *stacksize) { const struct posix_thread_attr *attr = (const struct posix_thread_attr *)_attr; - if ((attr == NULL) || (attr->initialized == false) || (stacksize == NULL)) { + if (!__attr_is_initialized(attr) || (stacksize == NULL)) { return EINVAL; } @@ -973,13 +985,11 @@ int pthread_attr_getstacksize(const pthread_attr_t *_attr, size_t *stacksize) */ int pthread_attr_setstacksize(pthread_attr_t *_attr, size_t stacksize) { + int ret; struct posix_thread_attr *attr = (struct posix_thread_attr *)_attr; - if ((attr == NULL) || (attr->initialized == 0U)) { - return EINVAL; - } - - if (stacksize == 0 || stacksize < PTHREAD_STACK_MIN || stacksize > PTHREAD_STACK_MAX) { + if (!__attr_is_initialized(attr) || stacksize < PTHREAD_STACK_MIN || + stacksize > PTHREAD_STACK_MAX) { return EINVAL; } @@ -996,8 +1006,7 @@ int pthread_attr_getstack(const pthread_attr_t *_attr, void **stackaddr, size_t { const struct posix_thread_attr *attr = (const struct posix_thread_attr *)_attr; - if ((attr == NULL) || (attr->initialized == false) || (stackaddr == NULL) || - (stacksize == NULL)) { + if (!__attr_is_initialized(attr) || (stackaddr == NULL) || (stacksize == NULL)) { return EINVAL; } @@ -1010,7 +1019,7 @@ int pthread_attr_getguardsize(const pthread_attr_t *ZRESTRICT _attr, size_t *ZRE { struct posix_thread_attr *const attr = (struct posix_thread_attr *)_attr; - if (attr == NULL || guardsize == NULL || !attr->initialized) { + if (!__attr_is_initialized(attr) || guardsize == NULL) { return EINVAL; } @@ -1023,7 +1032,7 @@ int pthread_attr_setguardsize(pthread_attr_t *_attr, size_t guardsize) { struct posix_thread_attr *const attr = (struct posix_thread_attr *)_attr; - if (attr == NULL || !attr->initialized || guardsize > PTHREAD_GUARD_MAX) { + if (!__attr_is_initialized(attr) || guardsize > PTHREAD_GUARD_MAX) { return EINVAL; } @@ -1041,7 +1050,7 @@ int pthread_attr_getschedparam(const pthread_attr_t *_attr, struct sched_param * { struct posix_thread_attr *attr = (struct posix_thread_attr *)_attr; - if ((attr == NULL) || (attr->initialized == false) || (schedparam == NULL)) { + if (!__attr_is_initialized(attr) || (schedparam == NULL)) { return EINVAL; } @@ -1058,12 +1067,11 @@ int pthread_attr_destroy(pthread_attr_t *_attr) { struct posix_thread_attr *attr = (struct posix_thread_attr *)_attr; - if ((attr != NULL) && (attr->initialized != 0U)) { - attr->initialized = false; - return 0; + if (!__attr_is_initialized(attr)) { + return EINVAL; } - return EINVAL; + return 0; } int pthread_setname_np(pthread_t thread, const char *name) From dbcba2f46c0d4eadfbbef727ab1f684d5357e2ca Mon Sep 17 00:00:00 2001 From: Christopher Friedt Date: Wed, 24 Jan 2024 16:39:08 -0500 Subject: [PATCH 2892/3723] posix: pthread: check canceltype before async cancel The default pthread cancellation type is deferred. Check that the canceltype is asynchronous (with respect to cancellation points) before cancelling a thread. Signed-off-by: Christopher Friedt --- lib/posix/pthread.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/lib/posix/pthread.c b/lib/posix/pthread.c index 913c81389d4..00431c37ff5 100644 --- a/lib/posix/pthread.c +++ b/lib/posix/pthread.c @@ -638,6 +638,7 @@ int pthread_setcanceltype(int type, int *oldtype) int pthread_cancel(pthread_t pthread) { int cancel_state; + int cancel_type; k_spinlock_key_t key; struct posix_thread *t; @@ -649,9 +650,11 @@ int pthread_cancel(pthread_t pthread) key = k_spin_lock(&pthread_pool_lock); t->cancel_pending = true; cancel_state = t->cancel_state; + cancel_type = t->cancel_type; k_spin_unlock(&pthread_pool_lock, key); - if (cancel_state == PTHREAD_CANCEL_ENABLE) { + if (cancel_state == PTHREAD_CANCEL_ENABLE && + cancel_type == PTHREAD_CANCEL_ASYNCHRONOUS) { posix_thread_finalize(t, PTHREAD_CANCELED); } From 77135fcbc6167580b5bcf55787882e4790e5fa98 Mon Sep 17 00:00:00 2001 From: Christopher Friedt Date: Tue, 26 Dec 2023 10:12:20 -0500 Subject: [PATCH 2893/3723] posix: pthread: embed posix_thread_attr inside of posix_thread Rather than shadowing most of the fields from pthread_attr_t (struct posix_thread_attr) inside of struct posix_thread, just embed the structure itself. Additionally, use pthread_attr_init() to allocate a thread stack and pthread_attr_destroy() to destroy a thread stack, dramatically simplifying pthread_create(). A fair bit of rework was needed already to mitigate bitrot issues in the testsuite. More should probably be done later. Signed-off-by: Christopher Friedt --- lib/posix/posix_internal.h | 19 +- lib/posix/pthread.c | 328 +++++++++++++++++++------------ tests/posix/common/prj.conf | 6 +- tests/posix/common/testcase.yaml | 1 - 4 files changed, 215 insertions(+), 139 deletions(-) diff --git a/lib/posix/posix_internal.h b/lib/posix/posix_internal.h index 1e6bb0aeb33..837349b4d32 100644 --- a/lib/posix/posix_internal.h +++ b/lib/posix/posix_internal.h @@ -29,8 +29,13 @@ struct posix_thread_attr { uint16_t guardsize : CONFIG_POSIX_PTHREAD_ATTR_GUARDSIZE_BITS; int8_t priority; uint8_t schedpolicy: 2; - bool initialized: 1; + union { + bool caller_destroys: 1; + bool initialized: 1; + }; + bool cancelpending: 1; bool cancelstate: 1; + bool canceltype: 1; bool detachstate: 1; }; @@ -46,8 +51,8 @@ struct posix_thread { /* List of keys that thread has called pthread_setspecific() on */ sys_slist_t key_list; - /* Dynamic stack */ - k_thread_stack_t *dynamic_stack; + /* pthread_attr_t */ + struct posix_thread_attr attr; /* Exit status */ void *retval; @@ -55,14 +60,6 @@ struct posix_thread { /* Signal mask */ sigset_t sigset; - /* Pthread cancellation */ - uint8_t cancel_state; - uint8_t cancel_type; - bool cancel_pending; - - /* Detach state */ - uint8_t detachstate; - /* Queue ID (internal-only) */ uint8_t qid; }; diff --git a/lib/posix/pthread.c b/lib/posix/pthread.c index 00431c37ff5..5c3d2b46520 100644 --- a/lib/posix/pthread.c +++ b/lib/posix/pthread.c @@ -130,9 +130,9 @@ struct posix_thread *to_posix_thread(pthread_t pthread) * This differs from other posix object allocation strategies because they use * a bitarray to indicate whether an object has been allocated. */ - actually_initialized = - !(t->qid == POSIX_THREAD_READY_Q || - (t->qid == POSIX_THREAD_DONE_Q && t->detachstate == PTHREAD_CREATE_DETACHED)); + actually_initialized = !( + t->qid == POSIX_THREAD_READY_Q || + (t->qid == POSIX_THREAD_DONE_Q && t->attr.detachstate == PTHREAD_CREATE_DETACHED)); k_spin_unlock(&pthread_pool_lock, key); if (!actually_initialized) { @@ -253,9 +253,43 @@ int posix_to_zephyr_priority(int priority, int policy) return POSIX_TO_ZEPHYR_PRIORITY(priority, policy); } +static bool __attr_is_runnable(const struct posix_thread_attr *attr) +{ + size_t stacksize; + + if (attr == NULL || attr->stack == NULL) { + LOG_DBG("attr %p is not initialized", attr); + return false; + } + + stacksize = __get_attr_stacksize(attr); + if (stacksize < PTHREAD_STACK_MIN) { + LOG_DBG("attr %p has stacksize %zu is smaller than PTHREAD_STACK_MIN (%zu)", attr, + stacksize, (size_t)PTHREAD_STACK_MIN); + return false; + } + + /* require a valid scheduler policy */ + if (!valid_posix_policy(attr->schedpolicy)) { + LOG_ERR("Invalid scheduler policy %d", attr->schedpolicy); + return false; + } + + return true; +} + static bool __attr_is_initialized(const struct posix_thread_attr *attr) { - return attr != NULL && attr->initialized; + if (IS_ENABLED(CONFIG_DYNAMIC_THREAD)) { + return __attr_is_runnable(attr); + } + + if (attr == NULL || !attr->initialized) { + LOG_DBG("attr %p is not initialized", attr); + return false; + } + + return true; } /** @@ -284,6 +318,7 @@ int pthread_attr_setschedparam(pthread_attr_t *_attr, const struct sched_param * */ int pthread_attr_setstack(pthread_attr_t *_attr, void *stackaddr, size_t stacksize) { + int ret; struct posix_thread_attr *attr = (struct posix_thread_attr *)_attr; if (stackaddr == NULL) { @@ -291,45 +326,27 @@ int pthread_attr_setstack(pthread_attr_t *_attr, void *stackaddr, size_t stacksi return EACCES; } - if (!__attr_is_initialized(attr) || stacksize < PTHREAD_STACK_MIN || + if (!__attr_is_initialized(attr) || stacksize == 0 || stacksize < PTHREAD_STACK_MIN || stacksize > PTHREAD_STACK_MAX) { LOG_ERR("Invalid stacksize %zu", stacksize); return EINVAL; } - attr->stack = stackaddr; - __set_attr_stacksize(attr, stacksize); - return 0; -} - -static bool pthread_attr_is_valid(const struct posix_thread_attr *attr) -{ - size_t stacksize; - - /* auto-alloc thread stack */ - if (attr == NULL) { - return true; - } - - if (!__attr_is_initialized(attr) || attr->stack == NULL) { - LOG_DBG("attr %p is not initialized", attr); - return false; + if (attr->stack != NULL) { + ret = k_thread_stack_free(attr->stack); + if (ret == 0) { + LOG_DBG("Freed attr %p thread stack %zu@%p", _attr, + __get_attr_stacksize(attr), attr->stack); + } } - stacksize = __get_attr_stacksize(attr); - if (stacksize < PTHREAD_STACK_MIN) { - LOG_DBG("attr %p has stacksize %zu is smaller than PTHREAD_STACK_MIN (%zu)", attr, - stacksize, (size_t)PTHREAD_STACK_MIN); - return false; - } + attr->stack = stackaddr; + __set_attr_stacksize(attr, stacksize); - /* require a valid scheduler policy */ - if (!valid_posix_policy(attr->schedpolicy)) { - LOG_ERR("Invalid scheduler policy %d", attr->schedpolicy); - return false; - } + LOG_DBG("Assigned thread stack %zu@%p to attr %p", __get_attr_stacksize(attr), attr->stack, + _attr); - return true; + return 0; } static void posix_thread_recycle_work_handler(struct k_work *work) @@ -400,7 +417,7 @@ static void posix_thread_recycle(void) key = k_spin_lock(&pthread_pool_lock); SYS_DLIST_FOR_EACH_CONTAINER_SAFE(&done_q, t, safe_t, q_node) { - if (t->detachstate == PTHREAD_CREATE_JOINABLE) { + if (t->attr.detachstate == PTHREAD_CREATE_JOINABLE) { /* thread has not been joined yet */ continue; } @@ -416,19 +433,19 @@ static void posix_thread_recycle(void) LOG_DBG("Recycling %zu threads", sys_dlist_len(&recyclables)); - if (IS_ENABLED(CONFIG_DYNAMIC_THREAD)) { - SYS_DLIST_FOR_EACH_CONTAINER(&recyclables, t, q_node) { - if (t->dynamic_stack != NULL) { - LOG_DBG("Freeing thread stack %p", t->dynamic_stack); - (void)k_thread_stack_free(t->dynamic_stack); - t->dynamic_stack = NULL; - } + SYS_DLIST_FOR_EACH_CONTAINER(&recyclables, t, q_node) { + if (t->attr.caller_destroys) { + t->attr = (struct posix_thread_attr){0}; + } else { + (void)pthread_attr_destroy((pthread_attr_t *)&t->attr); } } key = k_spin_lock(&pthread_pool_lock); while (!sys_dlist_is_empty(&recyclables)) { - sys_dlist_append(&ready_q, sys_dlist_get(&recyclables)); + t = CONTAINER_OF(sys_dlist_get(&recyclables), struct posix_thread, q_node); + t->qid = POSIX_THREAD_READY_Q; + sys_dlist_append(&ready_q, &t->q_node); } k_spin_unlock(&pthread_pool_lock, key); } @@ -445,50 +462,40 @@ int pthread_create(pthread_t *th, const pthread_attr_t *_attr, void *(*threadrou void *arg) { int err; - k_spinlock_key_t key; pthread_barrier_t barrier; struct posix_thread *t = NULL; - struct posix_thread_attr attr_storage; - struct posix_thread_attr *attr = (struct posix_thread_attr *)_attr; - if (!pthread_attr_is_valid(attr)) { + if (!(_attr == NULL || __attr_is_runnable((struct posix_thread_attr *)_attr))) { return EINVAL; } - if (attr == NULL) { - attr = &attr_storage; - (void)pthread_attr_init((pthread_attr_t *)attr); - BUILD_ASSERT(DYNAMIC_STACK_SIZE <= PTHREAD_STACK_MAX); - __set_attr_stacksize(attr, DYNAMIC_STACK_SIZE); - attr->stack = k_thread_stack_alloc(__get_attr_stacksize(attr) + attr->guardsize, - k_is_user_context() ? K_USER : 0); - if (attr->stack == NULL) { - LOG_ERR("Unable to allocate stack of size %u", DYNAMIC_STACK_SIZE); - return EAGAIN; - } - LOG_DBG("Allocated thread stack %p", attr->stack); - } else { - __ASSERT_NO_MSG(attr != &attr_storage); - } - /* reclaim resources greedily */ posix_thread_recycle(); - key = k_spin_lock(&pthread_pool_lock); - if (!sys_dlist_is_empty(&ready_q)) { - t = CONTAINER_OF(sys_dlist_get(&ready_q), struct posix_thread, q_node); - - /* initialize thread state */ - sys_dlist_append(&run_q, &t->q_node); - t->qid = POSIX_THREAD_RUN_Q; - t->detachstate = attr->detachstate; - t->cancel_state = attr->cancelstate; - t->cancel_pending = false; - sys_slist_init(&t->key_list); - sys_slist_init(&t->cleanup_list); - t->dynamic_stack = _attr == NULL ? attr->stack : NULL; + K_SPINLOCK(&pthread_pool_lock) { + if (!sys_dlist_is_empty(&ready_q)) { + t = CONTAINER_OF(sys_dlist_get(&ready_q), struct posix_thread, q_node); + + /* initialize thread state */ + sys_dlist_append(&run_q, &t->q_node); + t->qid = POSIX_THREAD_RUN_Q; + sys_slist_init(&t->key_list); + sys_slist_init(&t->cleanup_list); + } + } + + if (t != NULL && IS_ENABLED(CONFIG_PTHREAD_CREATE_BARRIER)) { + err = pthread_barrier_init(&barrier, NULL, 2); + if (err != 0) { + /* cannot allocate barrier. move thread back to ready_q */ + K_SPINLOCK(&pthread_pool_lock) { + sys_dlist_remove(&t->q_node); + sys_dlist_append(&ready_q, &t->q_node); + t->qid = POSIX_THREAD_READY_Q; + } + t = NULL; + } } - k_spin_unlock(&pthread_pool_lock, key); if (t == NULL) { /* no threads are ready */ @@ -496,29 +503,34 @@ int pthread_create(pthread_t *th, const pthread_attr_t *_attr, void *(*threadrou return EAGAIN; } - if (IS_ENABLED(CONFIG_PTHREAD_CREATE_BARRIER)) { - err = pthread_barrier_init(&barrier, NULL, 2); + if (_attr == NULL) { + err = pthread_attr_init((pthread_attr_t *)&t->attr); + if (err == 0 && !__attr_is_runnable(&t->attr)) { + (void)pthread_attr_destroy((pthread_attr_t *)&t->attr); + err = EINVAL; + } if (err != 0) { - if (t->dynamic_stack != NULL) { - LOG_DBG("freeing thread stack at %p", attr->stack); - (void)k_thread_stack_free(attr->stack); + /* cannot allocate pthread attributes (e.g. stack) */ + K_SPINLOCK(&pthread_pool_lock) { + sys_dlist_remove(&t->q_node); + sys_dlist_append(&ready_q, &t->q_node); + t->qid = POSIX_THREAD_READY_Q; } - - /* cannot allocate barrier. move thread back to ready_q */ - key = k_spin_lock(&pthread_pool_lock); - sys_dlist_remove(&t->q_node); - sys_dlist_append(&ready_q, &t->q_node); - t->qid = POSIX_THREAD_READY_Q; - k_spin_unlock(&pthread_pool_lock, key); - t = NULL; + return err; } + /* caller not responsible for destroying attr */ + t->attr.caller_destroys = false; + } else { + /* copy user-provided attr into thread, caller must destroy attr at a later time */ + t->attr = *(struct posix_thread_attr *)_attr; } /* spawn the thread */ - k_thread_create(&t->thread, attr->stack, __get_attr_stacksize(attr), zephyr_thread_wrapper, - (void *)arg, threadroutine, - IS_ENABLED(CONFIG_PTHREAD_CREATE_BARRIER) ? UINT_TO_POINTER(barrier) : NULL, - posix_to_zephyr_priority(attr->priority, attr->schedpolicy), 0, K_NO_WAIT); + k_thread_create( + &t->thread, t->attr.stack, __get_attr_stacksize(&t->attr) + t->attr.guardsize, + zephyr_thread_wrapper, (void *)arg, threadroutine, + IS_ENABLED(CONFIG_PTHREAD_CREATE_BARRIER) ? UINT_TO_POINTER(barrier) : NULL, + posix_to_zephyr_priority(t->attr.priority, t->attr.schedpolicy), 0, K_NO_WAIT); if (IS_ENABLED(CONFIG_PTHREAD_CREATE_BARRIER)) { /* wait for the spawned thread to cross our barrier */ @@ -571,8 +583,8 @@ int pthread_setconcurrency(int new_level) */ int pthread_setcancelstate(int state, int *oldstate) { + bool cancel_type; bool cancel_pending; - k_spinlock_key_t key; struct posix_thread *t; if (state != PTHREAD_CANCEL_ENABLE && state != PTHREAD_CANCEL_DISABLE) { @@ -585,15 +597,16 @@ int pthread_setcancelstate(int state, int *oldstate) return EINVAL; } - key = k_spin_lock(&pthread_pool_lock); - if (oldstate != NULL) { - *oldstate = t->cancel_state; + K_SPINLOCK(&pthread_pool_lock) { + if (oldstate != NULL) { + *oldstate = t->attr.cancelstate; + } + cancel_pending = t->attr.cancelpending; + cancel_type = t->attr.canceltype; } - t->cancel_state = state; - cancel_pending = t->cancel_pending; - k_spin_unlock(&pthread_pool_lock, key); - if (state == PTHREAD_CANCEL_ENABLE && cancel_pending) { + if (state == PTHREAD_CANCEL_ENABLE && cancel_type == PTHREAD_CANCEL_ASYNCHRONOUS && + cancel_pending) { posix_thread_finalize(t, PTHREAD_CANCELED); } @@ -607,7 +620,6 @@ int pthread_setcancelstate(int state, int *oldstate) */ int pthread_setcanceltype(int type, int *oldtype) { - k_spinlock_key_t key; struct posix_thread *t; if (type != PTHREAD_CANCEL_DEFERRED && type != PTHREAD_CANCEL_ASYNCHRONOUS) { @@ -620,12 +632,12 @@ int pthread_setcanceltype(int type, int *oldtype) return EINVAL; } - key = k_spin_lock(&pthread_pool_lock); - if (oldtype != NULL) { - *oldtype = t->cancel_type; + K_SPINLOCK(&pthread_pool_lock) { + if (oldtype != NULL) { + *oldtype = t->cancel_type; + } + t->attr.canceltype = type; } - t->cancel_type = type; - k_spin_unlock(&pthread_pool_lock, key); return 0; } @@ -648,9 +660,9 @@ int pthread_cancel(pthread_t pthread) } key = k_spin_lock(&pthread_pool_lock); - t->cancel_pending = true; - cancel_state = t->cancel_state; - cancel_type = t->cancel_type; + t->attr.cancelpending = true; + cancel_state = t->attr.cancelstate; + cancel_type = t->attr.canceltype; k_spin_unlock(&pthread_pool_lock, key); if (cancel_state == PTHREAD_CANCEL_ENABLE && @@ -704,10 +716,29 @@ int pthread_attr_init(pthread_attr_t *_attr) return ENOMEM; } + BUILD_ASSERT(DYNAMIC_STACK_SIZE <= PTHREAD_STACK_MAX); + *attr = (struct posix_thread_attr){0}; attr->guardsize = CONFIG_POSIX_PTHREAD_ATTR_GUARDSIZE_DEFAULT; + + if (DYNAMIC_STACK_SIZE > 0) { + attr->stack = k_thread_stack_alloc(DYNAMIC_STACK_SIZE + attr->guardsize, + k_is_user_context() ? K_USER : 0); + if (attr->stack == NULL) { + LOG_DBG("Did not auto-allocate thread stack"); + } else { + __set_attr_stacksize(attr, DYNAMIC_STACK_SIZE); + __ASSERT_NO_MSG(__attr_is_initialized(attr)); + LOG_DBG("Allocated thread stack %zu@%p", __get_attr_stacksize(attr), + attr->stack); + } + } + + /* caller responsible for destroying attr */ attr->initialized = true; + LOG_DBG("Initialized attr %p", _attr); + return 0; } @@ -718,18 +749,30 @@ int pthread_attr_init(pthread_attr_t *_attr) */ int pthread_getschedparam(pthread_t pthread, int *policy, struct sched_param *param) { - int priority; + int ret = 0; + uint32_t priority; struct posix_thread *t; + if (policy == NULL || param == NULL) { + return EINVAL; + } + t = to_posix_thread(pthread); if (t == NULL) { return ESRCH; } - priority = k_thread_priority_get(&t->thread); + K_SPINLOCK(&pthread_pool_lock) { + if (__attr_is_initialized(&t->attr)) { + priority = k_thread_priority_get(&t->thread); + param->sched_priority = zephyr_to_posix_priority(priority, policy); + ret = 0; + } else { + ret = ESRCH; + } + } - param->sched_priority = zephyr_to_posix_priority(priority, policy); - return 0; + return ret; } /** @@ -783,7 +826,7 @@ void pthread_exit(void *retval) /* Mark a thread as cancellable before exiting */ key = k_spin_lock(&pthread_pool_lock); - self->cancel_state = PTHREAD_CANCEL_ENABLE; + self->attr.cancelstate = PTHREAD_CANCEL_ENABLE; k_spin_unlock(&pthread_pool_lock, key); posix_thread_finalize(self, retval); @@ -813,9 +856,9 @@ int pthread_join(pthread_t pthread, void **status) LOG_DBG("Pthread %p joining..", &t->thread); ret = 0; - K_SPINLOCK(&pthread_pool_lock) - { - if (t->detachstate != PTHREAD_CREATE_JOINABLE) { + K_SPINLOCK(&pthread_pool_lock) { + if (t->attr.detachstate != PTHREAD_CREATE_JOINABLE) { + /* undefined behaviour */ ret = EINVAL; K_SPINLOCK_BREAK; } @@ -830,7 +873,7 @@ int pthread_join(pthread_t pthread, void **status) * thread is joinable and is in run_q or done_q. * let's ensure that the thread cannot be joined again after this point. */ - t->detachstate = PTHREAD_CREATE_DETACHED; + t->attr.detachstate = PTHREAD_CREATE_DETACHED; } switch (ret) { @@ -879,12 +922,12 @@ int pthread_detach(pthread_t pthread) key = k_spin_lock(&pthread_pool_lock); qid = t->qid; - if (qid == POSIX_THREAD_READY_Q || t->detachstate != PTHREAD_CREATE_JOINABLE) { + if (qid == POSIX_THREAD_READY_Q || t->attr.detachstate != PTHREAD_CREATE_JOINABLE) { LOG_ERR("Pthread %p cannot be detached", &t->thread); ret = EINVAL; } else { ret = 0; - t->detachstate = PTHREAD_CREATE_DETACHED; + t->attr.detachstate = PTHREAD_CREATE_DETACHED; } k_spin_unlock(&pthread_pool_lock, key); @@ -989,14 +1032,43 @@ int pthread_attr_getstacksize(const pthread_attr_t *_attr, size_t *stacksize) int pthread_attr_setstacksize(pthread_attr_t *_attr, size_t stacksize) { int ret; + void *new_stack; struct posix_thread_attr *attr = (struct posix_thread_attr *)_attr; - if (!__attr_is_initialized(attr) || stacksize < PTHREAD_STACK_MIN || + if (!__attr_is_initialized(attr) || stacksize == 0 || stacksize < PTHREAD_STACK_MIN || stacksize > PTHREAD_STACK_MAX) { return EINVAL; } + if (__get_attr_stacksize(attr) == stacksize) { + return 0; + } + + new_stack = + k_thread_stack_alloc(stacksize + attr->guardsize, k_is_user_context() ? K_USER : 0); + if (new_stack == NULL) { + if (stacksize < __get_attr_stacksize(attr)) { + __set_attr_stacksize(attr, stacksize); + return 0; + } + + LOG_DBG("k_thread_stack_alloc(%zu) failed", + __get_attr_stacksize(attr) + attr->guardsize); + return ENOMEM; + } + LOG_DBG("Allocated thread stack %zu@%p", stacksize + attr->guardsize, attr->stack); + + if (attr->stack != NULL) { + ret = k_thread_stack_free(attr->stack); + if (ret == 0) { + LOG_DBG("Freed attr %p thread stack %zu@%p", _attr, + __get_attr_stacksize(attr), attr->stack); + } + } + __set_attr_stacksize(attr, stacksize); + attr->stack = new_stack; + return 0; } @@ -1068,12 +1140,22 @@ int pthread_attr_getschedparam(const pthread_attr_t *_attr, struct sched_param * */ int pthread_attr_destroy(pthread_attr_t *_attr) { + int ret; struct posix_thread_attr *attr = (struct posix_thread_attr *)_attr; if (!__attr_is_initialized(attr)) { return EINVAL; } + ret = k_thread_stack_free(attr->stack); + if (ret == 0) { + LOG_DBG("Freed attr %p thread stack %zu@%p", _attr, __get_attr_stacksize(attr), + attr->stack); + } + + *attr = (struct posix_thread_attr){0}; + LOG_DBG("Destroyed attr %p", _attr); + return 0; } diff --git a/tests/posix/common/prj.conf b/tests/posix/common/prj.conf index 67dab816dc7..bc92bed8fbf 100644 --- a/tests/posix/common/prj.conf +++ b/tests/posix/common/prj.conf @@ -1,14 +1,12 @@ CONFIG_PTHREAD_IPC=y CONFIG_POSIX_API=y -CONFIG_MAX_PTHREAD_COUNT=10 +CONFIG_MAX_PTHREAD_COUNT=6 CONFIG_ZTEST=y CONFIG_SEM_VALUE_MAX=32767 CONFIG_POSIX_MQUEUE=y CONFIG_POSIX_PRIORITY_SCHEDULING=y CONFIG_HEAP_MEM_POOL_SIZE=4096 -CONFIG_MAX_THREAD_BYTES=4 CONFIG_THREAD_NAME=y -CONFIG_MAIN_STACK_SIZE=2048 CONFIG_DYNAMIC_THREAD=y CONFIG_THREAD_STACK_INFO=y -CONFIG_DYNAMIC_THREAD_POOL_SIZE=4 +CONFIG_DYNAMIC_THREAD_POOL_SIZE=6 diff --git a/tests/posix/common/testcase.yaml b/tests/posix/common/testcase.yaml index 225ec292adf..9617cd8e08f 100644 --- a/tests/posix/common/testcase.yaml +++ b/tests/posix/common/testcase.yaml @@ -95,7 +95,6 @@ tests: extra_configs: - CONFIG_DYNAMIC_THREAD=y - CONFIG_THREAD_STACK_INFO=y - - CONFIG_DYNAMIC_THREAD_POOL_SIZE=5 - CONFIG_HEAP_MEM_POOL_SIZE=16384 portability.posix.common.static_stack: integration_platforms: From 81f3777be1c02298c7b3718eebc4f2b561eec8d6 Mon Sep 17 00:00:00 2001 From: Christopher Friedt Date: Thu, 18 Jan 2024 13:19:53 -0500 Subject: [PATCH 2894/3723] posix: pthread: hold pool lock when calling to_posix_thread() There may be race conditions when calling to_posix_thread() from multiple threads. Ensuing that the pthread pool lock is held when to_posix_thread() is called will prevent those races. Signed-off-by: Christopher Friedt --- lib/posix/pthread.c | 235 ++++++++++++++++++++++++-------------------- 1 file changed, 129 insertions(+), 106 deletions(-) diff --git a/lib/posix/pthread.c b/lib/posix/pthread.c index 5c3d2b46520..abd30ee1f72 100644 --- a/lib/posix/pthread.c +++ b/lib/posix/pthread.c @@ -106,7 +106,6 @@ static inline size_t get_posix_thread_idx(pthread_t pth) struct posix_thread *to_posix_thread(pthread_t pthread) { - k_spinlock_key_t key; struct posix_thread *t; bool actually_initialized; size_t bit = get_posix_thread_idx(pthread); @@ -124,7 +123,6 @@ struct posix_thread *to_posix_thread(pthread_t pthread) t = &posix_thread_pool[bit]; - key = k_spin_lock(&pthread_pool_lock); /* * Denote a pthread as "initialized" (i.e. allocated) if it is not in ready_q. * This differs from other posix object allocation strategies because they use @@ -133,7 +131,6 @@ struct posix_thread *to_posix_thread(pthread_t pthread) actually_initialized = !( t->qid == POSIX_THREAD_READY_Q || (t->qid == POSIX_THREAD_DONE_Q && t->attr.detachstate == PTHREAD_CREATE_DETACHED)); - k_spin_unlock(&pthread_pool_lock, key); if (!actually_initialized) { LOG_ERR("Pthread claims to be initialized (%x)", pthread); @@ -187,29 +184,35 @@ static inline void __z_pthread_cleanup_init(struct __pthread_cleanup *c, void (* void __z_pthread_cleanup_push(void *cleanup[3], void (*routine)(void *arg), void *arg) { - struct posix_thread *const t = to_posix_thread(pthread_self()); + struct posix_thread *t; struct __pthread_cleanup *const c = (struct __pthread_cleanup *)cleanup; - BUILD_ASSERT(3 * sizeof(void *) == sizeof(*c)); - __ASSERT_NO_MSG(t != NULL); - __ASSERT_NO_MSG(c != NULL); - __ASSERT_NO_MSG(routine != NULL); - __z_pthread_cleanup_init(c, routine, arg); - sys_slist_prepend(&t->cleanup_list, &c->node); + K_SPINLOCK(&pthread_pool_lock) { + t = to_posix_thread(pthread_self()); + BUILD_ASSERT(3 * sizeof(void *) == sizeof(*c)); + __ASSERT_NO_MSG(t != NULL); + __ASSERT_NO_MSG(c != NULL); + __ASSERT_NO_MSG(routine != NULL); + __z_pthread_cleanup_init(c, routine, arg); + sys_slist_prepend(&t->cleanup_list, &c->node); + } } void __z_pthread_cleanup_pop(int execute) { sys_snode_t *node; struct __pthread_cleanup *c; - struct posix_thread *const t = to_posix_thread(pthread_self()); - - __ASSERT_NO_MSG(t != NULL); - node = sys_slist_get(&t->cleanup_list); - __ASSERT_NO_MSG(node != NULL); - c = CONTAINER_OF(node, struct __pthread_cleanup, node); - __ASSERT_NO_MSG(c != NULL); - __ASSERT_NO_MSG(c->routine != NULL); + struct posix_thread *t; + + K_SPINLOCK(&pthread_pool_lock) { + t = to_posix_thread(pthread_self()); + __ASSERT_NO_MSG(t != NULL); + node = sys_slist_get(&t->cleanup_list); + __ASSERT_NO_MSG(node != NULL); + c = CONTAINER_OF(node, struct __pthread_cleanup, node); + __ASSERT_NO_MSG(c != NULL); + __ASSERT_NO_MSG(c->routine != NULL); + } if (execute) { c->routine(c->arg); } @@ -583,24 +586,28 @@ int pthread_setconcurrency(int new_level) */ int pthread_setcancelstate(int state, int *oldstate) { - bool cancel_type; - bool cancel_pending; + int ret = 0; struct posix_thread *t; + bool cancel_pending = false; + bool cancel_type = PTHREAD_CANCEL_ENABLE; if (state != PTHREAD_CANCEL_ENABLE && state != PTHREAD_CANCEL_DISABLE) { LOG_ERR("Invalid pthread state %d", state); return EINVAL; } - t = to_posix_thread(pthread_self()); - if (t == NULL) { - return EINVAL; - } - K_SPINLOCK(&pthread_pool_lock) { + t = to_posix_thread(pthread_self()); + if (t == NULL) { + ret = EINVAL; + K_SPINLOCK_BREAK; + } + if (oldstate != NULL) { *oldstate = t->attr.cancelstate; } + + t->attr.cancelstate = state; cancel_pending = t->attr.cancelpending; cancel_type = t->attr.canceltype; } @@ -620,6 +627,7 @@ int pthread_setcancelstate(int state, int *oldstate) */ int pthread_setcanceltype(int type, int *oldtype) { + int ret = 0; struct posix_thread *t; if (type != PTHREAD_CANCEL_DEFERRED && type != PTHREAD_CANCEL_ASYNCHRONOUS) { @@ -627,19 +635,20 @@ int pthread_setcanceltype(int type, int *oldtype) return EINVAL; } - t = to_posix_thread(pthread_self()); - if (t == NULL) { - return EINVAL; - } - K_SPINLOCK(&pthread_pool_lock) { + t = to_posix_thread(pthread_self()); + if (t == NULL) { + ret = EINVAL; + K_SPINLOCK_BREAK; + } + if (oldtype != NULL) { - *oldtype = t->cancel_type; + *oldtype = t->attr.canceltype; } t->attr.canceltype = type; } - return 0; + return ret; } /** @@ -649,28 +658,35 @@ int pthread_setcanceltype(int type, int *oldtype) */ int pthread_cancel(pthread_t pthread) { - int cancel_state; - int cancel_type; - k_spinlock_key_t key; + int ret = 0; + bool cancel_state = PTHREAD_CANCEL_ENABLE; + bool cancel_type = PTHREAD_CANCEL_DEFERRED; struct posix_thread *t; - t = to_posix_thread(pthread); - if (t == NULL) { - return ESRCH; - } + K_SPINLOCK(&pthread_pool_lock) { + t = to_posix_thread(pthread); + if (t == NULL) { + ret = ESRCH; + K_SPINLOCK_BREAK; + } - key = k_spin_lock(&pthread_pool_lock); - t->attr.cancelpending = true; - cancel_state = t->attr.cancelstate; - cancel_type = t->attr.canceltype; - k_spin_unlock(&pthread_pool_lock, key); + if (!__attr_is_initialized(&t->attr)) { + /* thread has already terminated */ + ret = ESRCH; + K_SPINLOCK_BREAK; + } + + t->attr.cancelpending = true; + cancel_state = t->attr.cancelstate; + cancel_type = t->attr.canceltype; + } if (cancel_state == PTHREAD_CANCEL_ENABLE && cancel_type == PTHREAD_CANCEL_ASYNCHRONOUS) { posix_thread_finalize(t, PTHREAD_CANCELED); } - return 0; + return ret; } /** @@ -680,26 +696,30 @@ int pthread_cancel(pthread_t pthread) */ int pthread_setschedparam(pthread_t pthread, int policy, const struct sched_param *param) { - struct posix_thread *t = to_posix_thread(pthread); + int ret = 0; int new_prio; + struct posix_thread *t; - if (t == NULL) { - return ESRCH; - } - - if (!valid_posix_policy(policy)) { - LOG_ERR("Invalid scheduler policy %d", policy); + if (param == NULL || !valid_posix_policy(policy) || + !is_posix_policy_prio_valid(param->sched_priority, policy)) { return EINVAL; } - if (is_posix_policy_prio_valid(param->sched_priority, policy) == false) { - return EINVAL; + K_SPINLOCK(&pthread_pool_lock) { + t = to_posix_thread(pthread); + if (t == NULL) { + ret = ESRCH; + K_SPINLOCK_BREAK; + } + + new_prio = posix_to_zephyr_priority(param->sched_priority, policy); } - new_prio = posix_to_zephyr_priority(param->sched_priority, policy); + if (ret == 0) { + k_thread_priority_set(&t->thread, new_prio); + } - k_thread_priority_set(&t->thread, new_prio); - return 0; + return ret; } /** @@ -750,26 +770,26 @@ int pthread_attr_init(pthread_attr_t *_attr) int pthread_getschedparam(pthread_t pthread, int *policy, struct sched_param *param) { int ret = 0; - uint32_t priority; struct posix_thread *t; if (policy == NULL || param == NULL) { return EINVAL; } - t = to_posix_thread(pthread); - if (t == NULL) { - return ESRCH; - } - K_SPINLOCK(&pthread_pool_lock) { - if (__attr_is_initialized(&t->attr)) { - priority = k_thread_priority_get(&t->thread); - param->sched_priority = zephyr_to_posix_priority(priority, policy); - ret = 0; - } else { + t = to_posix_thread(pthread); + if (t == NULL) { ret = ESRCH; + K_SPINLOCK_BREAK; + } + + if (!__attr_is_initialized(&t->attr)) { + ret = ESRCH; + K_SPINLOCK_BREAK; } + + param->sched_priority = + zephyr_to_posix_priority(k_thread_priority_get(&t->thread), policy); } return ret; @@ -812,10 +832,18 @@ int pthread_once(pthread_once_t *once, void (*init_func)(void)) FUNC_NORETURN void pthread_exit(void *retval) { - k_spinlock_key_t key; - struct posix_thread *self; + struct posix_thread *self = NULL; + + K_SPINLOCK(&pthread_pool_lock) { + self = to_posix_thread(pthread_self()); + if (self == NULL) { + K_SPINLOCK_BREAK; + } + + /* Mark a thread as cancellable before exiting */ + self->attr.cancelstate = PTHREAD_CANCEL_ENABLE; + } - self = to_posix_thread(pthread_self()); if (self == NULL) { /* not a valid posix_thread */ LOG_DBG("Aborting non-pthread %p", k_current_get()); @@ -824,11 +852,6 @@ void pthread_exit(void *retval) CODE_UNREACHABLE; } - /* Mark a thread as cancellable before exiting */ - key = k_spin_lock(&pthread_pool_lock); - self->attr.cancelstate = PTHREAD_CANCEL_ENABLE; - k_spin_unlock(&pthread_pool_lock, key); - posix_thread_finalize(self, retval); CODE_UNREACHABLE; } @@ -840,23 +863,23 @@ void pthread_exit(void *retval) */ int pthread_join(pthread_t pthread, void **status) { + int ret = 0; struct posix_thread *t; - int ret; if (pthread == pthread_self()) { LOG_ERR("Pthread attempted to join itself (%x)", pthread); return EDEADLK; } - t = to_posix_thread(pthread); - if (t == NULL) { - return ESRCH; - } + K_SPINLOCK(&pthread_pool_lock) { + t = to_posix_thread(pthread); + if (t == NULL) { + ret = ESRCH; + K_SPINLOCK_BREAK; + } - LOG_DBG("Pthread %p joining..", &t->thread); + LOG_DBG("Pthread %p joining..", &t->thread); - ret = 0; - K_SPINLOCK(&pthread_pool_lock) { if (t->attr.detachstate != PTHREAD_CREATE_JOINABLE) { /* undefined behaviour */ ret = EINVAL; @@ -864,7 +887,6 @@ int pthread_join(pthread_t pthread, void **status) } if (t->qid == POSIX_THREAD_READY_Q) { - /* in case thread has moved to ready_q between to_posix_thread() and here */ ret = ESRCH; K_SPINLOCK_BREAK; } @@ -910,26 +932,25 @@ int pthread_join(pthread_t pthread, void **status) */ int pthread_detach(pthread_t pthread) { - int ret; - k_spinlock_key_t key; + int ret = 0; struct posix_thread *t; - enum posix_thread_qid qid; - t = to_posix_thread(pthread); - if (t == NULL) { - return ESRCH; - } + K_SPINLOCK(&pthread_pool_lock) { + t = to_posix_thread(pthread); + if (t == NULL) { + ret = ESRCH; + K_SPINLOCK_BREAK; + } + + if (t->qid == POSIX_THREAD_READY_Q || + t->attr.detachstate != PTHREAD_CREATE_JOINABLE) { + LOG_ERR("Pthread %p cannot be detached", &t->thread); + ret = EINVAL; + K_SPINLOCK_BREAK; + } - key = k_spin_lock(&pthread_pool_lock); - qid = t->qid; - if (qid == POSIX_THREAD_READY_Q || t->attr.detachstate != PTHREAD_CREATE_JOINABLE) { - LOG_ERR("Pthread %p cannot be detached", &t->thread); - ret = EINVAL; - } else { - ret = 0; t->attr.detachstate = PTHREAD_CREATE_DETACHED; } - k_spin_unlock(&pthread_pool_lock, key); if (ret == 0) { LOG_DBG("Pthread %p detached", &t->thread); @@ -1220,18 +1241,20 @@ int pthread_atfork(void (*prepare)(void), void (*parent)(void), void (*child)(vo /* this should probably go into signal.c but we need access to the lock */ int pthread_sigmask(int how, const sigset_t *ZRESTRICT set, sigset_t *ZRESTRICT oset) { + int ret = 0; struct posix_thread *t; if (!(how == SIG_BLOCK || how == SIG_SETMASK || how == SIG_UNBLOCK)) { return EINVAL; } - t = to_posix_thread(pthread_self()); - if (t == NULL) { - return ESRCH; - } - K_SPINLOCK(&pthread_pool_lock) { + t = to_posix_thread(pthread_self()); + if (t == NULL) { + ret = ESRCH; + K_SPINLOCK_BREAK; + } + if (oset != NULL) { *oset = t->sigset; } @@ -1257,7 +1280,7 @@ int pthread_sigmask(int how, const sigset_t *ZRESTRICT set, sigset_t *ZRESTRICT } } - return 0; + return ret; } static int posix_thread_pool_init(void) From 23016f4589cc9fd69d0514669067b9b02660d69a Mon Sep 17 00:00:00 2001 From: Christopher Friedt Date: Thu, 18 Jan 2024 13:28:01 -0500 Subject: [PATCH 2895/3723] posix: pthread: posix_thread_q_set() and posix_thread_q_get() Create getter and setter functions for setting internal pthread states to READY, RUN, or DONE queues. Signed-off-by: Christopher Friedt --- lib/posix/pthread.c | 72 +++++++++++++++++++++++++++++++-------------- 1 file changed, 50 insertions(+), 22 deletions(-) diff --git a/lib/posix/pthread.c b/lib/posix/pthread.c index abd30ee1f72..99441694fe9 100644 --- a/lib/posix/pthread.c +++ b/lib/posix/pthread.c @@ -64,6 +64,8 @@ enum posix_thread_qid { POSIX_THREAD_RUN_Q, /* exited (either joinable or detached) */ POSIX_THREAD_DONE_Q, + /* invalid */ + POSIX_THREAD_INVALID_Q, }; /* only 2 bits in struct posix_thread_attr for schedpolicy */ @@ -79,13 +81,43 @@ BUILD_ASSERT(CONFIG_POSIX_PTHREAD_ATTR_STACKSIZE_BITS + CONFIG_POSIX_PTHREAD_ATT 32); static void posix_thread_recycle(void); -static sys_dlist_t ready_q = SYS_DLIST_STATIC_INIT(&ready_q); -static sys_dlist_t run_q = SYS_DLIST_STATIC_INIT(&run_q); -static sys_dlist_t done_q = SYS_DLIST_STATIC_INIT(&done_q); +static sys_dlist_t posix_thread_q[] = { + SYS_DLIST_STATIC_INIT(&posix_thread_q[POSIX_THREAD_READY_Q]), + SYS_DLIST_STATIC_INIT(&posix_thread_q[POSIX_THREAD_RUN_Q]), + SYS_DLIST_STATIC_INIT(&posix_thread_q[POSIX_THREAD_DONE_Q]), +}; static struct posix_thread posix_thread_pool[CONFIG_MAX_PTHREAD_COUNT]; static struct k_spinlock pthread_pool_lock; static int pthread_concurrency; +static inline void posix_thread_q_set(struct posix_thread *t, enum posix_thread_qid qid) +{ + switch (qid) { + case POSIX_THREAD_READY_Q: + case POSIX_THREAD_RUN_Q: + case POSIX_THREAD_DONE_Q: + sys_dlist_append(&posix_thread_q[qid], &t->q_node); + t->qid = qid; + break; + default: + __ASSERT(false, "cannot set invalid qid %d for posix thread %p", qid, t); + break; + } +} + +static inline enum posix_thread_qid posix_thread_q_get(struct posix_thread *t) +{ + switch (t->qid) { + case POSIX_THREAD_READY_Q: + case POSIX_THREAD_RUN_Q: + case POSIX_THREAD_DONE_Q: + return t->qid; + default: + __ASSERT(false, "posix thread %p has invalid qid: %d", t, t->qid); + return POSIX_THREAD_INVALID_Q; + } +} + /* * We reserve the MSB to mark a pthread_t as initialized (from the * perspective of the application). With a linear space, this means that @@ -128,9 +160,9 @@ struct posix_thread *to_posix_thread(pthread_t pthread) * This differs from other posix object allocation strategies because they use * a bitarray to indicate whether an object has been allocated. */ - actually_initialized = !( - t->qid == POSIX_THREAD_READY_Q || - (t->qid == POSIX_THREAD_DONE_Q && t->attr.detachstate == PTHREAD_CREATE_DETACHED)); + actually_initialized = !(posix_thread_q_get(t) == POSIX_THREAD_READY_Q || + (posix_thread_q_get(t) == POSIX_THREAD_DONE_Q && + t->attr.detachstate == PTHREAD_CREATE_DETACHED)); if (!actually_initialized) { LOG_ERR("Pthread claims to be initialized (%x)", pthread); @@ -379,8 +411,7 @@ static void posix_thread_finalize(struct posix_thread *t, void *retval) /* move thread from run_q to done_q */ key = k_spin_lock(&pthread_pool_lock); sys_dlist_remove(&t->q_node); - sys_dlist_append(&done_q, &t->q_node); - t->qid = POSIX_THREAD_DONE_Q; + posix_thread_q_set(t, POSIX_THREAD_DONE_Q); t->retval = retval; k_spin_unlock(&pthread_pool_lock, key); @@ -419,7 +450,7 @@ static void posix_thread_recycle(void) sys_dlist_t recyclables = SYS_DLIST_STATIC_INIT(&recyclables); key = k_spin_lock(&pthread_pool_lock); - SYS_DLIST_FOR_EACH_CONTAINER_SAFE(&done_q, t, safe_t, q_node) { + SYS_DLIST_FOR_EACH_CONTAINER_SAFE(&posix_thread_q[POSIX_THREAD_DONE_Q], t, safe_t, q_node) { if (t->attr.detachstate == PTHREAD_CREATE_JOINABLE) { /* thread has not been joined yet */ continue; @@ -447,8 +478,7 @@ static void posix_thread_recycle(void) key = k_spin_lock(&pthread_pool_lock); while (!sys_dlist_is_empty(&recyclables)) { t = CONTAINER_OF(sys_dlist_get(&recyclables), struct posix_thread, q_node); - t->qid = POSIX_THREAD_READY_Q; - sys_dlist_append(&ready_q, &t->q_node); + posix_thread_q_set(t, POSIX_THREAD_READY_Q); } k_spin_unlock(&pthread_pool_lock, key); } @@ -476,12 +506,12 @@ int pthread_create(pthread_t *th, const pthread_attr_t *_attr, void *(*threadrou posix_thread_recycle(); K_SPINLOCK(&pthread_pool_lock) { - if (!sys_dlist_is_empty(&ready_q)) { - t = CONTAINER_OF(sys_dlist_get(&ready_q), struct posix_thread, q_node); + if (!sys_dlist_is_empty(&posix_thread_q[POSIX_THREAD_READY_Q])) { + t = CONTAINER_OF(sys_dlist_get(&posix_thread_q[POSIX_THREAD_READY_Q]), + struct posix_thread, q_node); /* initialize thread state */ - sys_dlist_append(&run_q, &t->q_node); - t->qid = POSIX_THREAD_RUN_Q; + posix_thread_q_set(t, POSIX_THREAD_RUN_Q); sys_slist_init(&t->key_list); sys_slist_init(&t->cleanup_list); } @@ -493,8 +523,7 @@ int pthread_create(pthread_t *th, const pthread_attr_t *_attr, void *(*threadrou /* cannot allocate barrier. move thread back to ready_q */ K_SPINLOCK(&pthread_pool_lock) { sys_dlist_remove(&t->q_node); - sys_dlist_append(&ready_q, &t->q_node); - t->qid = POSIX_THREAD_READY_Q; + posix_thread_q_set(t, POSIX_THREAD_READY_Q); } t = NULL; } @@ -516,8 +545,7 @@ int pthread_create(pthread_t *th, const pthread_attr_t *_attr, void *(*threadrou /* cannot allocate pthread attributes (e.g. stack) */ K_SPINLOCK(&pthread_pool_lock) { sys_dlist_remove(&t->q_node); - sys_dlist_append(&ready_q, &t->q_node); - t->qid = POSIX_THREAD_READY_Q; + posix_thread_q_set(t, POSIX_THREAD_READY_Q); } return err; } @@ -886,7 +914,7 @@ int pthread_join(pthread_t pthread, void **status) K_SPINLOCK_BREAK; } - if (t->qid == POSIX_THREAD_READY_Q) { + if (posix_thread_q_get(t) == POSIX_THREAD_READY_Q) { ret = ESRCH; K_SPINLOCK_BREAK; } @@ -942,7 +970,7 @@ int pthread_detach(pthread_t pthread) K_SPINLOCK_BREAK; } - if (t->qid == POSIX_THREAD_READY_Q || + if (posix_thread_q_get(t) == POSIX_THREAD_READY_Q || t->attr.detachstate != PTHREAD_CREATE_JOINABLE) { LOG_ERR("Pthread %p cannot be detached", &t->thread); ret = EINVAL; @@ -1288,7 +1316,7 @@ static int posix_thread_pool_init(void) size_t i; for (i = 0; i < CONFIG_MAX_PTHREAD_COUNT; ++i) { - sys_dlist_append(&ready_q, &posix_thread_pool[i].q_node); + posix_thread_q_set(&posix_thread_pool[i], POSIX_THREAD_READY_Q); } return 0; From dbf700316269b1617ceff36ebdf607bbd2a205a4 Mon Sep 17 00:00:00 2001 From: Christopher Friedt Date: Fri, 19 Jan 2024 08:25:27 -0500 Subject: [PATCH 2896/3723] tests: posix + libc: qemu_x86*: use dynamic stack size of 4096 For qemu_x86 and qemu_x86_64, it would seem that heap-allocated thread stacks, as well as thread stacks defined via K_THREAD_STACK_ARRAY_DEFINE(), must be at least 4096 bytes in size. Using those sizes will ensure that these tests do not fail with stack overflows or MMU faults. Signed-off-by: Christopher Friedt --- tests/lib/c_lib/thrd/boards/qemu_x86.conf | 1 + tests/lib/c_lib/thrd/boards/qemu_x86_64.conf | 1 + tests/posix/common/boards/qemu_x86.conf | 1 + tests/posix/common/boards/qemu_x86_64.conf | 1 + 4 files changed, 4 insertions(+) create mode 100644 tests/lib/c_lib/thrd/boards/qemu_x86.conf create mode 100644 tests/lib/c_lib/thrd/boards/qemu_x86_64.conf create mode 100644 tests/posix/common/boards/qemu_x86.conf create mode 100644 tests/posix/common/boards/qemu_x86_64.conf diff --git a/tests/lib/c_lib/thrd/boards/qemu_x86.conf b/tests/lib/c_lib/thrd/boards/qemu_x86.conf new file mode 100644 index 00000000000..2fa43926ee4 --- /dev/null +++ b/tests/lib/c_lib/thrd/boards/qemu_x86.conf @@ -0,0 +1 @@ +CONFIG_DYNAMIC_THREAD_STACK_SIZE=4096 diff --git a/tests/lib/c_lib/thrd/boards/qemu_x86_64.conf b/tests/lib/c_lib/thrd/boards/qemu_x86_64.conf new file mode 100644 index 00000000000..2fa43926ee4 --- /dev/null +++ b/tests/lib/c_lib/thrd/boards/qemu_x86_64.conf @@ -0,0 +1 @@ +CONFIG_DYNAMIC_THREAD_STACK_SIZE=4096 diff --git a/tests/posix/common/boards/qemu_x86.conf b/tests/posix/common/boards/qemu_x86.conf new file mode 100644 index 00000000000..2fa43926ee4 --- /dev/null +++ b/tests/posix/common/boards/qemu_x86.conf @@ -0,0 +1 @@ +CONFIG_DYNAMIC_THREAD_STACK_SIZE=4096 diff --git a/tests/posix/common/boards/qemu_x86_64.conf b/tests/posix/common/boards/qemu_x86_64.conf new file mode 100644 index 00000000000..2fa43926ee4 --- /dev/null +++ b/tests/posix/common/boards/qemu_x86_64.conf @@ -0,0 +1 @@ +CONFIG_DYNAMIC_THREAD_STACK_SIZE=4096 From e4b3df53dd7d5a0c5455236b4755e46460b38dd4 Mon Sep 17 00:00:00 2001 From: Christopher Friedt Date: Tue, 23 Jan 2024 14:27:43 -0500 Subject: [PATCH 2897/3723] tests: posix: pthread: identify thread ids of detached threads Previously, the number 2 seemed to be somewhat magical. This removes some of the mystery by labeling it. So threads >= DETACH_THR_ID will be detached (we should not attempt to join detached threads). Signed-off-by: Christopher Friedt --- tests/posix/common/src/pthread.c | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/tests/posix/common/src/pthread.c b/tests/posix/common/src/pthread.c index 0977a25633f..730e6664d7a 100644 --- a/tests/posix/common/src/pthread.c +++ b/tests/posix/common/src/pthread.c @@ -10,6 +10,8 @@ #include #include +#define DETACH_THR_ID 2 + #define N_THR_E 3 #define N_THR_T 4 #define BOUNCES 64 @@ -202,7 +204,7 @@ static void *thread_top_term(void *p1) zassert_false(ret, "Unable to set cancel state!"); } - if (id >= 2) { + if (id >= DETACH_THR_ID) { zassert_ok(pthread_detach(self), "failed to set detach state"); zassert_equal(pthread_detach(self), EINVAL, "re-detached thread!"); } @@ -355,7 +357,9 @@ ZTEST(pthread, test_pthread_termination) zassert_equal(ret, EINVAL, "invalid cancel state set!"); for (i = 0; i < N_THR_T; i++) { - pthread_join(newthread[i], &retval); + if (i < DETACH_THR_ID) { + zassert_ok(pthread_join(newthread[i], &retval)); + } } /* TESTPOINT: Test for deadlock */ @@ -363,7 +367,7 @@ ZTEST(pthread, test_pthread_termination) zassert_equal(ret, EDEADLK, "thread joined with self inexplicably!"); /* TESTPOINT: Try canceling a terminated thread */ - ret = pthread_cancel(newthread[N_THR_T/2]); + ret = pthread_cancel(newthread[0]); zassert_equal(ret, ESRCH, "cancelled a terminated thread!"); } From 68952095a50bdf0e3b877d06e152a3cb5e0b4a00 Mon Sep 17 00:00:00 2001 From: Daniel DeGrasse Date: Tue, 11 Jul 2023 20:38:14 +0000 Subject: [PATCH 2898/3723] samples: net: zperf: allow networking code to be relocated to RAM Enable relocation of key networking stack functions to RAM when running the zperf example. This will enable better performance on platforms with fast code RAM. Signed-off-by: Daniel DeGrasse --- samples/net/zperf/CMakeLists.txt | 14 ++++++++++++++ samples/net/zperf/Kconfig | 22 ++++++++++++++++++++++ 2 files changed, 36 insertions(+) create mode 100644 samples/net/zperf/Kconfig diff --git a/samples/net/zperf/CMakeLists.txt b/samples/net/zperf/CMakeLists.txt index ae9b46dadc0..c4552f97141 100644 --- a/samples/net/zperf/CMakeLists.txt +++ b/samples/net/zperf/CMakeLists.txt @@ -8,3 +8,17 @@ project(zperf) target_sources(app PRIVATE src/main.c ) + +if (CONFIG_NET_SAMPLE_CODE_RELOCATE) + # Relocate key networking stack components and L2 layer to RAM + zephyr_code_relocate(LIBRARY subsys__net__ip + LOCATION "${CONFIG_NET_SAMPLE_CODE_RAM_NAME}_TEXT" NOKEEP) + zephyr_code_relocate(LIBRARY subsys__net + LOCATION "${CONFIG_NET_SAMPLE_CODE_RAM_NAME}_TEXT" NOKEEP) +if (CONFIG_NET_L2_ETHERNET) + zephyr_code_relocate(LIBRARY drivers__ethernet + LOCATION "${CONFIG_NET_SAMPLE_CODE_RAM_NAME}_TEXT" NOKEEP) + zephyr_code_relocate(LIBRARY subsys__net__l2__ethernet + LOCATION "${CONFIG_NET_SAMPLE_CODE_RAM_NAME}_TEXT" NOKEEP) +endif() +endif() diff --git a/samples/net/zperf/Kconfig b/samples/net/zperf/Kconfig new file mode 100644 index 00000000000..a56cd6b9416 --- /dev/null +++ b/samples/net/zperf/Kconfig @@ -0,0 +1,22 @@ +# Copyright 2023 NXP +# SPDX-License-Identifier: Apache-2.0 + +source "Kconfig.zephyr" + +config NET_SAMPLE_CODE_RELOCATE + bool "Relocate networking code into RAM" + select CODE_DATA_RELOCATION + help + Relocate networking code into RAM when running the zperf + sample. Can improve performance on platforms with fast code + RAM. + +if NET_SAMPLE_CODE_RELOCATE + +config NET_SAMPLE_CODE_RAM_NAME + string "Networking code RAM location" + default "RAM" + help + Region to relocate networking code to + +endif # NET_SAMPLE_CODE_RELOCATE From 664e710b1c50056a00d9fde2ee099d511c71a27f Mon Sep 17 00:00:00 2001 From: Daniel DeGrasse Date: Tue, 11 Jul 2023 20:39:32 +0000 Subject: [PATCH 2899/3723] samples: net: zperf: relocate stack to RAM for iMX RT boards Relocate network stack to RAM for iMX RT boards when running the zperf sample. Relocating the network stack to ITCM greatly improves performance on these platforms. Also, remove overlays for the RT1050 and RT1060 setting the system timer to systick. This is no longer required as this is the default timer for these boards. Signed-off-by: Daniel DeGrasse --- samples/net/zperf/boards/mimxrt1050_evk.conf | 2 ++ samples/net/zperf/boards/mimxrt1050_evk.overlay | 14 -------------- samples/net/zperf/boards/mimxrt1060_evk.conf | 2 ++ samples/net/zperf/boards/mimxrt1060_evk.overlay | 14 -------------- samples/net/zperf/boards/mimxrt1064_evk.conf | 4 ++++ samples/net/zperf/boards/mimxrt1170_evk_cm7.conf | 4 ++++ 6 files changed, 12 insertions(+), 28 deletions(-) delete mode 100644 samples/net/zperf/boards/mimxrt1050_evk.overlay delete mode 100644 samples/net/zperf/boards/mimxrt1060_evk.overlay create mode 100644 samples/net/zperf/boards/mimxrt1064_evk.conf create mode 100644 samples/net/zperf/boards/mimxrt1170_evk_cm7.conf diff --git a/samples/net/zperf/boards/mimxrt1050_evk.conf b/samples/net/zperf/boards/mimxrt1050_evk.conf index 8f90b5bd833..287d55db122 100644 --- a/samples/net/zperf/boards/mimxrt1050_evk.conf +++ b/samples/net/zperf/boards/mimxrt1050_evk.conf @@ -1,2 +1,4 @@ # Note: HW accleration does not support IPV6 CONFIG_ETH_MCUX_HW_ACCELERATION=y +CONFIG_NET_SAMPLE_CODE_RELOCATE=y +CONFIG_NET_SAMPLE_CODE_RAM_NAME="ITCM" diff --git a/samples/net/zperf/boards/mimxrt1050_evk.overlay b/samples/net/zperf/boards/mimxrt1050_evk.overlay deleted file mode 100644 index 4340caf2abc..00000000000 --- a/samples/net/zperf/boards/mimxrt1050_evk.overlay +++ /dev/null @@ -1,14 +0,0 @@ -/* - * Copyright 2022 NXP - * - * SPDX-License-Identifier: Apache-2.0 - */ - -/* Use cortex systick as hardware timer */ -&systick { - status = "okay"; -}; - -&gpt_hw_timer { - status = "disabled"; -}; diff --git a/samples/net/zperf/boards/mimxrt1060_evk.conf b/samples/net/zperf/boards/mimxrt1060_evk.conf index 8f90b5bd833..287d55db122 100644 --- a/samples/net/zperf/boards/mimxrt1060_evk.conf +++ b/samples/net/zperf/boards/mimxrt1060_evk.conf @@ -1,2 +1,4 @@ # Note: HW accleration does not support IPV6 CONFIG_ETH_MCUX_HW_ACCELERATION=y +CONFIG_NET_SAMPLE_CODE_RELOCATE=y +CONFIG_NET_SAMPLE_CODE_RAM_NAME="ITCM" diff --git a/samples/net/zperf/boards/mimxrt1060_evk.overlay b/samples/net/zperf/boards/mimxrt1060_evk.overlay deleted file mode 100644 index 4340caf2abc..00000000000 --- a/samples/net/zperf/boards/mimxrt1060_evk.overlay +++ /dev/null @@ -1,14 +0,0 @@ -/* - * Copyright 2022 NXP - * - * SPDX-License-Identifier: Apache-2.0 - */ - -/* Use cortex systick as hardware timer */ -&systick { - status = "okay"; -}; - -&gpt_hw_timer { - status = "disabled"; -}; diff --git a/samples/net/zperf/boards/mimxrt1064_evk.conf b/samples/net/zperf/boards/mimxrt1064_evk.conf new file mode 100644 index 00000000000..287d55db122 --- /dev/null +++ b/samples/net/zperf/boards/mimxrt1064_evk.conf @@ -0,0 +1,4 @@ +# Note: HW accleration does not support IPV6 +CONFIG_ETH_MCUX_HW_ACCELERATION=y +CONFIG_NET_SAMPLE_CODE_RELOCATE=y +CONFIG_NET_SAMPLE_CODE_RAM_NAME="ITCM" diff --git a/samples/net/zperf/boards/mimxrt1170_evk_cm7.conf b/samples/net/zperf/boards/mimxrt1170_evk_cm7.conf new file mode 100644 index 00000000000..287d55db122 --- /dev/null +++ b/samples/net/zperf/boards/mimxrt1170_evk_cm7.conf @@ -0,0 +1,4 @@ +# Note: HW accleration does not support IPV6 +CONFIG_ETH_MCUX_HW_ACCELERATION=y +CONFIG_NET_SAMPLE_CODE_RELOCATE=y +CONFIG_NET_SAMPLE_CODE_RAM_NAME="ITCM" From 9a59e03225e1bc24605198e66f9c5416daec8d7f Mon Sep 17 00:00:00 2001 From: Pisit Sawangvonganan Date: Fri, 26 Jan 2024 00:35:22 +0700 Subject: [PATCH 2900/3723] doc: connectivity: bluetooth: fix typo Utilize a code spell-checking tool to scan for and correct spelling errors in all files within the doc/connectivity/bluetooth directory. Signed-off-by: Pisit Sawangvonganan --- doc/connectivity/bluetooth/api/mesh/access.rst | 2 +- doc/connectivity/bluetooth/api/mesh/dfu.rst | 2 +- doc/connectivity/bluetooth/api/mesh/shell.rst | 2 +- doc/connectivity/bluetooth/img/cap_proc.svg | 2 +- 4 files changed, 4 insertions(+), 4 deletions(-) diff --git a/doc/connectivity/bluetooth/api/mesh/access.rst b/doc/connectivity/bluetooth/api/mesh/access.rst index 7af8ca7ec68..aa6082f5df4 100644 --- a/doc/connectivity/bluetooth/api/mesh/access.rst +++ b/doc/connectivity/bluetooth/api/mesh/access.rst @@ -179,7 +179,7 @@ the :ref:`bluetooth_mesh_lcd_srv` model. Composition Data Page 0 ----------------------- -Composition Data Page 0 provides the fundemental information about a device, and +Composition Data Page 0 provides the fundamental information about a device, and is mandatory for all mesh devices. It contains the element and model composition, the supported features, and manufacturer information. diff --git a/doc/connectivity/bluetooth/api/mesh/dfu.rst b/doc/connectivity/bluetooth/api/mesh/dfu.rst index 6718b3ea0ce..d2bf4ced2ce 100644 --- a/doc/connectivity/bluetooth/api/mesh/dfu.rst +++ b/doc/connectivity/bluetooth/api/mesh/dfu.rst @@ -164,7 +164,7 @@ Firmware metadata | | | in the New firmware core type field. | +------------------------+--------------+----------------------------------------+ | Application-specific | | Application-specific data to allow | -| data for new firmware | (Optional) | application to execut some | +| data for new firmware | (Optional) | application to execute some | | | | vendor-specific behaviors using | | | | this data before it can respond | | | | with a status message. | diff --git a/doc/connectivity/bluetooth/api/mesh/shell.rst b/doc/connectivity/bluetooth/api/mesh/shell.rst index 3d925f29a3e..366e5d9ebad 100644 --- a/doc/connectivity/bluetooth/api/mesh/shell.rst +++ b/doc/connectivity/bluetooth/api/mesh/shell.rst @@ -944,7 +944,7 @@ application. This shell module can be used to trigger interaction between Health on devices in a Mesh network. By default, the module will choose the first Health Client instance in the model composition when -using the Health Client commands. To choose a spesific Health Client instance the user can utilize +using the Health Client commands. To choose a specific Health Client instance the user can utilize the commands ``mesh models health instance set`` and ``mesh models health instance get-all``. The Health Client may use the general messages parameters set by ``mesh target dst``, diff --git a/doc/connectivity/bluetooth/img/cap_proc.svg b/doc/connectivity/bluetooth/img/cap_proc.svg index ef476096ad2..70e56eebc25 100644 --- a/doc/connectivity/bluetooth/img/cap_proc.svg +++ b/doc/connectivity/bluetooth/img/cap_proc.svg @@ -1,3 +1,3 @@ -
CSIP
CSIP
BAP
BAP
VCP
VCP
MICP
MICP
CCP
CCP
MCP
MCP
CAP
CAP
Unicast Audio Start
Unicast Audio Start
Unicast Audio Update
Unicast Audio Update
Unicast Audio Stop
Unicast Audio Stop
Broadcast Audio Start
Broadcast Audio Start
Broadcast Audio Update
Broadcast Audio Update
Broadcast Audio Stop
Broadcast Audio Stop
Change Volume
Change Volume
Change Volume Offset
Change Volume Offset
Change Volume Mute
Change Volume Mute
Microphone Mute State
Microphone Mute State
Change Microphone Gain Setting
Change Microphone Gain Setting
Find Content Control Service
Find Content Control Service
Discovery
Discovery
Discovery
Discovery
Coordinated Set Dsicovery
Coordinated Set Dsicovery
Set Members Discovery
Set Members Discovery
Lock Request
Lock Request
Lock Release
Lock Release
For all connected procedures for CSIP sets
F...
Ordered Access
Ordered Access
Audio Role Discovery
Audio Role Discovery
Audio Capability Discovery
Audio Capability Discovery
ASE ID Discovery
ASE ID Discovery
Supported Audio Context Discovery
Supported Audio Context Discovery
Available Audio Context Discovery
Available Audio Context Discovery
Codec Configuration
Codec Configuration
QoS Configuration
QoS Configuration
Enabling ASE
Enabling ASE
Updating unicast metadata
Updating unicast metadata
Disabling ASE
Disabling ASE
Releasing ASE
Releasing ASE
Configure broadcast source
Configure broadcast source
Reconfigure broadcast source
Reconfigure broadcast source
Broadcast audio establishment
Broadcast audio establishment
Broadcast Audio Metadata update
Broadcast Audio Metadata update
Broadcast Audio Disable
Broadcast Audio Disable
Broadcast Audio Release
Broadcast Audio Release
Broadcast Audio Synchronization
Broadcast Audio Synchronization
Configure volume state notifications
Configure volume state notifications
Read Volume State
Read Volume State
Configure Volume flag notifications
Configure Volume flag notifications
Read Volume Flags
Read Volume Flags
Set Initial Volume
Set Initial Volume
Relative Volume Down
Relative Volume Down
Relative Volume Up
Relative Volume Up
Unmute and Relative Volume Down
Unmute and Relative Volume Down
Unmute and Relative volume Up
Unmute and Relative volume Up
Set Absolute Volume
Set Absolute Volume
Unmute
Unmute
Mute
Mute
Configure volume offset state notifications
Configure volume offset state notifications
Read Volume Offset State
Read Volume Offset State
Configure Audio Locaiton notifications
Configure Audio Locaiton notifications
Read Audio Location
Read Audio Location
Set Volume Offset
Set Volume Offset
Configure audio output description notifications
Configure audio output description notifications
Read Audio Output Description
Read Audio Output Description
Set Audio Output Description
Set Audio Output Description
Configure Audio input state notifications
Configure Audio input state notifications
Read Audio Input State
Read Audio Input State
Read Gain Setting Properties
Read Gain Setting Properties
Read Audio Input Type
Read Audio Input Type
Configure Audio Input Status Notifications
Configure Audio Input Status Notifications
Read Audio Input Status
Read Audio Input Status
Set Gain Setting
Set Gain Setting
Unmute
Unmute
Mute
Mute
Set Manual Gain Mode
Set Manual Gain Mode
Set Automatic Gain Mode
Set Automatic Gain Mode
Configure Audio Input Description
Configure Audio Input Description
Read Audio Input Description
Read Audio Input Description
Set Audio Input Description
Set Audio Input Description
Discovery
Discovery
Configure mute notifications
Configure mute notifications
Read Mute State
Read Mute State
Set Mute State
Set Mute State
Configure Audio input state notifications
Configure Audio input state notifications
Read Audio Input State
Read Audio Input State
Read Gain Setting Properties
Read Gain Setting Properties
Read Audio Input Type
Read Audio Input Type
Configure Audio Input Status Notifications
Configure Audio Input Status Notifications
Read Audio Input Status
Read Audio Input Status
Set Gain Setting
Set Gain Setting
Unmute
Unmute
Mute
Mute
Set Manual Gain Mode
Set Manual Gain Mode
Set Automatic Gain Mode
Set Automatic Gain Mode
Configure Audio Input Description
Configure Audio Input Description
Read Audio Input Description
Read Audio Input Description
Set Audio Input Description
Set Audio Input Description
Discovery
Discovery
Discovery
Discovery
Read Bearer Provide Name
Read Bearer Provide Name
Read Bearer UCI
Read Bearer UCI
Read Bearer Technology
Read Bearer Technology
Read Bearer URI Schemes Supported List
Read Bearer URI Schemes Supported List
Read Bearer Signal Strength
Read Bearer Signal Strength
Read Bearer Signal Strength Reporting Interval
Read Bearer Signal Strength Reporting Interval
Set Bearer Signal Strength Reporting Interval
Set Bearer Signal Strength Reporting Interval
Reader List Current Calls
Reader List Current Calls
Read Content Control ID
Read Content Control ID
Read Incoming Clal Target Bearer URI
Read Incoming Clal Target Bearer URI
Read Status Flags
Read Status Flags
Read Call State
Read Call State
Answer Incoming Call
Answer Incoming Call
Terminate Call
Terminate Call
Move Call To Local Hold
Move Call To Local Hold
Move Locally Held Call To Active Call
Move Locally Held Call To Active Call
Move Locally And Remotely Held Call To Remotely Held Call
Move Locally And Remotely Held Call To Remotely Held Ca...
Originate Call
Originate Call
Join Calls
Join Calls
Read Call Control Point Optional Opcodes
Read Call Control Point Optional Opcodes
Read Incoming Call
Read Incoming Call
Read Call Friendly Name
Read Call Friendly Name
Discovery
Discovery
Read Media Information
Read Media Information
Read Media Player Icon Object Information
Read Media Player Icon Object Information
Read Track Title
Read Track Title
Set Absolute Track Position
Set Absolute Track Position
Set Relative Track Position 
Set Relative Track Position 
Read Playback Speed
Read Playback Speed
Read Track Duration
Read Track Duration
Read Track Position
Read Track Position
Set Playback Speed
Set Playback Speed
Read Seeking Speek
Read Seeking Speek
Read Current Track Segments Object Information
Read Current Track Segments Object Information
Read Current Track Object Information
Read Current Track Object Information
Set Current Track Object ID
Set Current Track Object ID
Read Next Track Object Information
Read Next Track Object Information
Set Next Track Object ID
Set Next Track Object ID
Track Discovery – Discover by Current Group Object ID
Track Discovery – Discover by Current Group Object ID
Set Current Group Object ID
Set Current Group Object ID
Read Parent Group Object Information
Read Parent Group Object Information
Read Playing Order
Read Playing Order
Set Playing Order
Set Playing Order
Read Playing Order Supported
Read Playing Order Supported
Read Media State
Read Media State
Play Current Track
Play Current Track
Pause Current Track
Pause Current Track
Fast Forward Fast Rewind
Fast Forward Fast Rewind
Stop Current Track
Stop Current Track
Move to Previous Segment
Move to Previous Segment
Move to Previous Segment
Move to Previous Segment
Move to Next Segment
Move to Next Segment
Move to First Segment
Move to First Segment
Move to Last Segment
Move to Last Segment
Move to Segment Number
Move to Segment Number
Move to Previous Track
Move to Previous Track
Move to Next Track
Move to Next Track
Move to First Track
Move to First Track
Move to Last Track
Move to Last Track
Move to Previous Group
Move to Previous Group
Move to Next Group
Move to Next Group
Move to First Group
Move to First Group
Move to Last Group
Move to Last Group
Move to Group Number
Move to Group Number
Read Media Control Point Opcodes Supported
Read Media Control Point Opcodes Supported
Search
Search
Read Content Control ID
Read Content Control ID
C
C
I
I
I
I
A
A
I
I
A
A
I
I
A
A
I
I
I
I
I
I
C
C
C
C
C
C
C
C
C
C
C
C
Broadcast Audio Reception Start
Broadcast Audio Reception Start
Adding Broadcast Sources
Adding Broadcast Sources
Modifying Broadcast Sources
Modifying Broadcast Sources
SyncInfo Transfer
SyncInfo Transfer
Setting Broadcast Code
Setting Broadcast Code
Removing Broadcast Sources
Removing Broadcast Sources
Broadcast Audio Reception Stop
Broadcast Audio Reception Stop
Broadcast to Unicast Audio Handover
Broadcast to Unicast Audio Handover
Unicast to Broadcast Audio Handover
Unicast to Broadcast Audio Handover
C
C
C
C
I
I
I
I
Distribute Broadcast_Code
Distribute Broadcast_Code
C
C
A
A
A
A
Text is not SVG - cannot display
\ No newline at end of file +
CSIP
CSIP
BAP
BAP
VCP
VCP
MICP
MICP
CCP
CCP
MCP
MCP
CAP
CAP
Unicast Audio Start
Unicast Audio Start
Unicast Audio Update
Unicast Audio Update
Unicast Audio Stop
Unicast Audio Stop
Broadcast Audio Start
Broadcast Audio Start
Broadcast Audio Update
Broadcast Audio Update
Broadcast Audio Stop
Broadcast Audio Stop
Change Volume
Change Volume
Change Volume Offset
Change Volume Offset
Change Volume Mute
Change Volume Mute
Microphone Mute State
Microphone Mute State
Change Microphone Gain Setting
Change Microphone Gain Setting
Find Content Control Service
Find Content Control Service
Discovery
Discovery
Discovery
Discovery
Coordinated Set Dsicovery
Coordinated Set Dsicovery
Set Members Discovery
Set Members Discovery
Lock Request
Lock Request
Lock Release
Lock Release
For all connected procedures for CSIP sets
F...
Ordered Access
Ordered Access
Audio Role Discovery
Audio Role Discovery
Audio Capability Discovery
Audio Capability Discovery
ASE ID Discovery
ASE ID Discovery
Supported Audio Context Discovery
Supported Audio Context Discovery
Available Audio Context Discovery
Available Audio Context Discovery
Codec Configuration
Codec Configuration
QoS Configuration
QoS Configuration
Enabling ASE
Enabling ASE
Updating unicast metadata
Updating unicast metadata
Disabling ASE
Disabling ASE
Releasing ASE
Releasing ASE
Configure broadcast source
Configure broadcast source
Reconfigure broadcast source
Reconfigure broadcast source
Broadcast audio establishment
Broadcast audio establishment
Broadcast Audio Metadata update
Broadcast Audio Metadata update
Broadcast Audio Disable
Broadcast Audio Disable
Broadcast Audio Release
Broadcast Audio Release
Broadcast Audio Synchronization
Broadcast Audio Synchronization
Configure volume state notifications
Configure volume state notifications
Read Volume State
Read Volume State
Configure Volume flag notifications
Configure Volume flag notifications
Read Volume Flags
Read Volume Flags
Set Initial Volume
Set Initial Volume
Relative Volume Down
Relative Volume Down
Relative Volume Up
Relative Volume Up
Unmute and Relative Volume Down
Unmute and Relative Volume Down
Unmute and Relative volume Up
Unmute and Relative volume Up
Set Absolute Volume
Set Absolute Volume
Unmute
Unmute
Mute
Mute
Configure volume offset state notifications
Configure volume offset state notifications
Read Volume Offset State
Read Volume Offset State
Configure Audio Location notifications
Configure Audio Location notifications
Read Audio Location
Read Audio Location
Set Volume Offset
Set Volume Offset
Configure audio output description notifications
Configure audio output description notifications
Read Audio Output Description
Read Audio Output Description
Set Audio Output Description
Set Audio Output Description
Configure Audio input state notifications
Configure Audio input state notifications
Read Audio Input State
Read Audio Input State
Read Gain Setting Properties
Read Gain Setting Properties
Read Audio Input Type
Read Audio Input Type
Configure Audio Input Status Notifications
Configure Audio Input Status Notifications
Read Audio Input Status
Read Audio Input Status
Set Gain Setting
Set Gain Setting
Unmute
Unmute
Mute
Mute
Set Manual Gain Mode
Set Manual Gain Mode
Set Automatic Gain Mode
Set Automatic Gain Mode
Configure Audio Input Description
Configure Audio Input Description
Read Audio Input Description
Read Audio Input Description
Set Audio Input Description
Set Audio Input Description
Discovery
Discovery
Configure mute notifications
Configure mute notifications
Read Mute State
Read Mute State
Set Mute State
Set Mute State
Configure Audio input state notifications
Configure Audio input state notifications
Read Audio Input State
Read Audio Input State
Read Gain Setting Properties
Read Gain Setting Properties
Read Audio Input Type
Read Audio Input Type
Configure Audio Input Status Notifications
Configure Audio Input Status Notifications
Read Audio Input Status
Read Audio Input Status
Set Gain Setting
Set Gain Setting
Unmute
Unmute
Mute
Mute
Set Manual Gain Mode
Set Manual Gain Mode
Set Automatic Gain Mode
Set Automatic Gain Mode
Configure Audio Input Description
Configure Audio Input Description
Read Audio Input Description
Read Audio Input Description
Set Audio Input Description
Set Audio Input Description
Discovery
Discovery
Discovery
Discovery
Read Bearer Provide Name
Read Bearer Provide Name
Read Bearer UCI
Read Bearer UCI
Read Bearer Technology
Read Bearer Technology
Read Bearer URI Schemes Supported List
Read Bearer URI Schemes Supported List
Read Bearer Signal Strength
Read Bearer Signal Strength
Read Bearer Signal Strength Reporting Interval
Read Bearer Signal Strength Reporting Interval
Set Bearer Signal Strength Reporting Interval
Set Bearer Signal Strength Reporting Interval
Reader List Current Calls
Reader List Current Calls
Read Content Control ID
Read Content Control ID
Read Incoming Clal Target Bearer URI
Read Incoming Clal Target Bearer URI
Read Status Flags
Read Status Flags
Read Call State
Read Call State
Answer Incoming Call
Answer Incoming Call
Terminate Call
Terminate Call
Move Call To Local Hold
Move Call To Local Hold
Move Locally Held Call To Active Call
Move Locally Held Call To Active Call
Move Locally And Remotely Held Call To Remotely Held Call
Move Locally And Remotely Held Call To Remotely Held Ca...
Originate Call
Originate Call
Join Calls
Join Calls
Read Call Control Point Optional Opcodes
Read Call Control Point Optional Opcodes
Read Incoming Call
Read Incoming Call
Read Call Friendly Name
Read Call Friendly Name
Discovery
Discovery
Read Media Information
Read Media Information
Read Media Player Icon Object Information
Read Media Player Icon Object Information
Read Track Title
Read Track Title
Set Absolute Track Position
Set Absolute Track Position
Set Relative Track Position 
Set Relative Track Position 
Read Playback Speed
Read Playback Speed
Read Track Duration
Read Track Duration
Read Track Position
Read Track Position
Set Playback Speed
Set Playback Speed
Read Seeking Speek
Read Seeking Speek
Read Current Track Segments Object Information
Read Current Track Segments Object Information
Read Current Track Object Information
Read Current Track Object Information
Set Current Track Object ID
Set Current Track Object ID
Read Next Track Object Information
Read Next Track Object Information
Set Next Track Object ID
Set Next Track Object ID
Track Discovery – Discover by Current Group Object ID
Track Discovery – Discover by Current Group Object ID
Set Current Group Object ID
Set Current Group Object ID
Read Parent Group Object Information
Read Parent Group Object Information
Read Playing Order
Read Playing Order
Set Playing Order
Set Playing Order
Read Playing Order Supported
Read Playing Order Supported
Read Media State
Read Media State
Play Current Track
Play Current Track
Pause Current Track
Pause Current Track
Fast Forward Fast Rewind
Fast Forward Fast Rewind
Stop Current Track
Stop Current Track
Move to Previous Segment
Move to Previous Segment
Move to Previous Segment
Move to Previous Segment
Move to Next Segment
Move to Next Segment
Move to First Segment
Move to First Segment
Move to Last Segment
Move to Last Segment
Move to Segment Number
Move to Segment Number
Move to Previous Track
Move to Previous Track
Move to Next Track
Move to Next Track
Move to First Track
Move to First Track
Move to Last Track
Move to Last Track
Move to Previous Group
Move to Previous Group
Move to Next Group
Move to Next Group
Move to First Group
Move to First Group
Move to Last Group
Move to Last Group
Move to Group Number
Move to Group Number
Read Media Control Point Opcodes Supported
Read Media Control Point Opcodes Supported
Search
Search
Read Content Control ID
Read Content Control ID
C
C
I
I
I
I
A
A
I
I
A
A
I
I
A
A
I
I
I
I
I
I
C
C
C
C
C
C
C
C
C
C
C
C
Broadcast Audio Reception Start
Broadcast Audio Reception Start
Adding Broadcast Sources
Adding Broadcast Sources
Modifying Broadcast Sources
Modifying Broadcast Sources
SyncInfo Transfer
SyncInfo Transfer
Setting Broadcast Code
Setting Broadcast Code
Removing Broadcast Sources
Removing Broadcast Sources
Broadcast Audio Reception Stop
Broadcast Audio Reception Stop
Broadcast to Unicast Audio Handover
Broadcast to Unicast Audio Handover
Unicast to Broadcast Audio Handover
Unicast to Broadcast Audio Handover
C
C
C
C
I
I
I
I
Distribute Broadcast_Code
Distribute Broadcast_Code
C
C
A
A
A
A
Text is not SVG - cannot display
\ No newline at end of file From 679cea1c061201b8d28a706d95c074dad15d31e4 Mon Sep 17 00:00:00 2001 From: Pisit Sawangvonganan Date: Fri, 26 Jan 2024 00:39:22 +0700 Subject: [PATCH 2901/3723] doc: connectivity: networking: fix typo Utilize a code spell-checking tool to scan for and correct spelling errors in all files within the doc/connectivity/networking directory. Signed-off-by: Pisit Sawangvonganan --- doc/connectivity/networking/api/coap_server.rst | 2 +- .../networking/api/images/lwm2m_engine_state_machine.svg | 2 +- doc/connectivity/networking/api/mqtt_sn.rst | 2 +- doc/connectivity/networking/api/tls_credentials_shell.rst | 2 +- doc/connectivity/networking/api/websocket.rst | 2 +- doc/connectivity/networking/conn_mgr/implementation.rst | 2 +- doc/connectivity/networking/conn_mgr/main.rst | 4 ++-- 7 files changed, 8 insertions(+), 8 deletions(-) diff --git a/doc/connectivity/networking/api/coap_server.rst b/doc/connectivity/networking/api/coap_server.rst index ac330c8d01e..1666880f2fc 100644 --- a/doc/connectivity/networking/api/coap_server.rst +++ b/doc/connectivity/networking/api/coap_server.rst @@ -27,7 +27,7 @@ Some configuration is required to make sure services can be started using the Co All services are added to a predefined linker section and all resources for each service also get their respective linker sections. If you would have a service ``my_service`` it has to be -prefixed wth ``coap_resource_`` and added to a linker file: +prefixed with ``coap_resource_`` and added to a linker file: .. code-block:: c :caption: ``sections-ram.ld`` diff --git a/doc/connectivity/networking/api/images/lwm2m_engine_state_machine.svg b/doc/connectivity/networking/api/images/lwm2m_engine_state_machine.svg index 9cb203be9e0..c9da075b2a3 100644 --- a/doc/connectivity/networking/api/images/lwm2m_engine_state_machine.svg +++ b/doc/connectivity/networking/api/images/lwm2m_engine_state_machine.svg @@ -1,4 +1,4 @@ -
lwm2m_rd_client_start()
lwm2m_rd_client_start()
IDLE
IDLE
INIT
INIT
LwM2M engine state machine
LwM2M engine state machine
DO
REGISTRATION
DO...
if bootstrap needed
if bootstrap needed
Send bootstrap registration message
Send bootstrap registration message
DO
BOOTSTRAP REG
DO...
Send registration message
Send registration message
REGISTRATION
SENT
REGISTRATION...
Succesful registration response
Emit event 5
Succesful registration response...
REGISTRATION
DONE
REGISTRATION...
Only in queue mode
after idle period.
Emit event 10
Only in queue mode...
RX OFF
IDLE
RX OFF...
UPDATE SENT
UPDATE SENT
Update
Update
Update
Update
Succesful update
Emit event 7
Succesful update...
Send deregistration message
Send deregistration message
DEREGISTER
DEREGISTER
acknowledged
acknowledged
DEREGISTRATION
SENT
DEREGISTRATION...
stop requested
Emit event 9
stop requested...
Server
is disabled
Server...
DEREGISTERED
DEREGISTERED
lwm2m_rd_client_stop()
lwm2m_rd_...
NETWORK
ERROR
NETWORK...
Messsage transmisison
failed
Messsage...
Succesful bootstrap registration response
Emit event 2
Succesful bootstrap registration response...
BOOTSTRAP REQ SENT
BOOTSTRAP REQ SENT
Bootstrap finish from server
Bootstrap finish from server
BOOTSTRAP REQ DONE
BOOTSTRAP REQ DONE
BOOTSTRAP TRANS DONE
BOOTSTRAP TRANS DONE
Emit event 3
Emit event 3
Emit event 11
Emit event 11
Timeout while sending message
If not bootstrap, emit event 6
Timeout while sending message...
Failure code in response
or timeout
Emit event 6
Failure code in response...
Registration failed,
emit event 4
Registration failed,...
Failure
Event 8
Failure...
UPDATE REGISTRATION
UPDATE REGISTRATION
Send update registration
message 
Send update registration...
Registration lifetime
is not yet expired
Registration lifetime...
fallback
fallback
Suspending
Suspending
lwm2m_engine_pause()
lwm2m_engine_pause()
lwm2m_engine_resume()
lwm2m_engine_resume()
ANY
STATE
ANY...
SUSPENDED
SUSPENDED
DO
REGISTRATION
DO...

state was
UPDATE_SENT?

state was...

Y

Y

N

N
REGISTRATION
DONE
REGISTRATION...

N

N

Y

Y

time for
update?

time for...
Bootstrap failed,
emit event 1
Bootstrap...

SERVER
DISABLED
SERVER...
Server disabled,
emit event 12
Server disabled,...
Cannot recover,
emit event 13
Cannot recover,...
Disable timer
expired
Disable timer...
connecting
connecting
connected
connected
stopped
stopped
Disconnected
for a perdiod
Disconnected...
Disconnecting
or stopping
Disconnecting...
Color coding
Color coding
recovering
recovering
Text is not SVG - cannot display
\ No newline at end of file +
lwm2m_rd_client_start()
lwm2m_rd_client_start()
IDLE
IDLE
INIT
INIT
LwM2M engine state machine
LwM2M engine state machine
DO
REGISTRATION
DO...
if bootstrap needed
if bootstrap needed
Send bootstrap registration message
Send bootstrap registration message
DO
BOOTSTRAP REG
DO...
Send registration message
Send registration message
REGISTRATION
SENT
REGISTRATION...
Successful registration response
Emit event 5
Successful registration response...
REGISTRATION
DONE
REGISTRATION...
Only in queue mode
after idle period.
Emit event 10
Only in queue mode...
RX OFF
IDLE
RX OFF...
UPDATE SENT
UPDATE SENT
Update
Update
Update
Update
Successful update
Emit event 7
Successful update...
Send deregistration message
Send deregistration message
DEREGISTER
DEREGISTER
acknowledged
acknowledged
DEREGISTRATION
SENT
DEREGISTRATION...
stop requested
Emit event 9
stop requested...
Server
is disabled
Server...
DEREGISTERED
DEREGISTERED
lwm2m_rd_client_stop()
lwm2m_rd_...
NETWORK
ERROR
NETWORK...
Message transmisison
failed
Message...
Successful bootstrap registration response
Emit event 2
Successful bootstrap registration response...
BOOTSTRAP REQ SENT
BOOTSTRAP REQ SENT
Bootstrap finish from server
Bootstrap finish from server
BOOTSTRAP REQ DONE
BOOTSTRAP REQ DONE
BOOTSTRAP TRANS DONE
BOOTSTRAP TRANS DONE
Emit event 3
Emit event 3
Emit event 11
Emit event 11
Timeout while sending message
If not bootstrap, emit event 6
Timeout while sending message...
Failure code in response
or timeout
Emit event 6
Failure code in response...
Registration failed,
emit event 4
Registration failed,...
Failure
Event 8
Failure...
UPDATE REGISTRATION
UPDATE REGISTRATION
Send update registration
message 
Send update registration...
Registration lifetime
is not yet expired
Registration lifetime...
fallback
fallback
Suspending
Suspending
lwm2m_engine_pause()
lwm2m_engine_pause()
lwm2m_engine_resume()
lwm2m_engine_resume()
ANY
STATE
ANY...
SUSPENDED
SUSPENDED
DO
REGISTRATION
DO...

state was
UPDATE_SENT?

state was...

Y

Y

N

N
REGISTRATION
DONE
REGISTRATION...

N

N

Y

Y

time for
update?

time for...
Bootstrap failed,
emit event 1
Bootstrap...

SERVER
DISABLED
SERVER...
Server disabled,
emit event 12
Server disabled,...
Cannot recover,
emit event 13
Cannot recover,...
Disable timer
expired
Disable timer...
connecting
connecting
connected
connected
stopped
stopped
Disconnected
for a perdiod
Disconnected...
Disconnecting
or stopping
Disconnecting...
Color coding
Color coding
recovering
recovering
Text is not SVG - cannot display
\ No newline at end of file diff --git a/doc/connectivity/networking/api/mqtt_sn.rst b/doc/connectivity/networking/api/mqtt_sn.rst index 318073bbe22..3235725f2e3 100644 --- a/doc/connectivity/networking/api/mqtt_sn.rst +++ b/doc/connectivity/networking/api/mqtt_sn.rst @@ -90,7 +90,7 @@ advertisement mechanism, this is not implemented yet in the library. Call the ``mqtt_sn_connect`` function, which will send a ``CONNECT`` message. The application should periodically call the ``mqtt_sn_input`` function to process -the response received. The appliation does not have to call ``mqtt_sn_input`` if it +the response received. The application does not have to call ``mqtt_sn_input`` if it knows that no data has been received (e.g. when using Bluetooth). Note that ``mqtt_sn_input`` is a non-blocking function, if the transport struct contains a ``poll`` compatible function pointer. diff --git a/doc/connectivity/networking/api/tls_credentials_shell.rst b/doc/connectivity/networking/api/tls_credentials_shell.rst index 69749a8f972..76c074ae67d 100644 --- a/doc/connectivity/networking/api/tls_credentials_shell.rst +++ b/doc/connectivity/networking/api/tls_credentials_shell.rst @@ -13,7 +13,7 @@ Commands Buffer Credential (``buf``) =========================== -Buffer data incrementaly into the credential buffer so that it can be added using the :ref:`tls_credentials_shell_add_cred` command. +Buffer data incrementally into the credential buffer so that it can be added using the :ref:`tls_credentials_shell_add_cred` command. Alternatively, clear the credential buffer. diff --git a/doc/connectivity/networking/api/websocket.rst b/doc/connectivity/networking/api/websocket.rst index f803e7b2ef8..b1450ae8f90 100644 --- a/doc/connectivity/networking/api/websocket.rst +++ b/doc/connectivity/networking/api/websocket.rst @@ -63,7 +63,7 @@ is supported. In order to send BINARY data, the :c:func:`websocket_send_msg()` must be used. When done, the Websocket transport socket must be closed. User should handle -the lifecycle(close/re-use) of tcp socket after websocket_disconnect. +the lifecycle(close/reuse) of tcp socket after websocket_disconnect. .. code-block:: c diff --git a/doc/connectivity/networking/conn_mgr/implementation.rst b/doc/connectivity/networking/conn_mgr/implementation.rst index 932ec7668d2..f598d571d5e 100644 --- a/doc/connectivity/networking/conn_mgr/implementation.rst +++ b/doc/connectivity/networking/conn_mgr/implementation.rst @@ -281,7 +281,7 @@ If exceptions to this are absolutely necessary, they should be constrained to sp While connectivity implementations must not break, it is acceptable for implementations to have potentially unexpected behavior if applications attempt to directly control the association state. - For instance, if an application directly instructs an underlying technology to dissassociate, it would be acceptable for the connectivity implementation to interpret this as an unexpected connection loss and immediately attempt to re-associate. + For instance, if an application directly instructs an underlying technology to disassociate, it would be acceptable for the connectivity implementation to interpret this as an unexpected connection loss and immediately attempt to re-associate. .. _conn_mgr_impl_guidelines_non_blocking: diff --git a/doc/connectivity/networking/conn_mgr/main.rst b/doc/connectivity/networking/conn_mgr/main.rst index 675be831418..fd7a8bf87ee 100644 --- a/doc/connectivity/networking/conn_mgr/main.rst +++ b/doc/connectivity/networking/conn_mgr/main.rst @@ -197,7 +197,7 @@ Connectivity control Many network interfaces require a network association procedure to be completed before being usable. -For such ifaces, connectivity control can provide a generic API to request network association (:c:func:`conn_mgr_if_connect`) and dissasociation (:c:func:`conn_mgr_if_disconnect`). +For such ifaces, connectivity control can provide a generic API to request network association (:c:func:`conn_mgr_if_connect`) and disassociation (:c:func:`conn_mgr_if_disconnect`). Network interfaces implement support for this API by :ref:`binding themselves to a connectivity implementation `. Using this API, applications can associate with networks with minimal technology-specific boilerplate. @@ -220,7 +220,7 @@ The following sections outline the basic operation of Connection Manager's conne Binding ------- -Before an iface can be commanded to associate or dissasociate using Connection Manager, it must first be bound to a :ref:`connectivity implementation `. +Before an iface can be commanded to associate or disassociate using Connection Manager, it must first be bound to a :ref:`connectivity implementation `. Binding is performed by the provider of the iface, not by the application (see :ref:`conn_mgr_impl_binding`), and can be thought of as an extension of the iface declaration. Once an iface is bound, all connectivity commands passed to it (such as :c:func:`conn_mgr_if_connect` or :c:func:`conn_mgr_if_disconnect`) will be routed to the corresponding implementation function in the connectivity implementation. From 0ee2927c328d2a5d79b2480afd04e938999444df Mon Sep 17 00:00:00 2001 From: Pisit Sawangvonganan Date: Fri, 26 Jan 2024 00:42:08 +0700 Subject: [PATCH 2902/3723] doc: develop: fix typo Utilize a code spell-checking tool to scan for and correct spelling errors in all files within the doc/develop directory. Signed-off-by: Pisit Sawangvonganan --- doc/develop/beyond-GSG.rst | 4 ++-- doc/develop/sca/index.rst | 2 +- doc/develop/toolchains/host.rst | 2 +- doc/develop/west/build-flash-debug.rst | 2 +- 4 files changed, 5 insertions(+), 5 deletions(-) diff --git a/doc/develop/beyond-GSG.rst b/doc/develop/beyond-GSG.rst index 1b9aab82644..d9336af5381 100644 --- a/doc/develop/beyond-GSG.rst +++ b/doc/develop/beyond-GSG.rst @@ -215,7 +215,7 @@ depending on your board. The other sample applications in the :zephyr_file:`samples` folder are documented in :ref:`samples-and-demos`. -.. note:: If you want to re-use an +.. note:: If you want to reuse an existing build directory for another board or application, you need to add the parameter ``-p=auto`` to ``west build`` to clean out settings and artifacts from the previous build. @@ -330,7 +330,7 @@ valgrind. .. [#pip] pip is Python's package installer. Its ``install`` command first tries to - re-use packages and package dependencies already installed on your computer. + reuse packages and package dependencies already installed on your computer. If that is not possible, ``pip install`` downloads them from the Python Package Index (PyPI) on the Internet. diff --git a/doc/develop/sca/index.rst b/doc/develop/sca/index.rst index b0896f566b9..44a9ee42615 100644 --- a/doc/develop/sca/index.rst +++ b/doc/develop/sca/index.rst @@ -31,7 +31,7 @@ structure: └── cmake/ └── sca/ └── / # Name of SCA tool, this is the value given to ZEPHYR_SCA_VARIANT - └── sca.cmake # CMake code that confgures the tool to be used with Zephyr + └── sca.cmake # CMake code that configures the tool to be used with Zephyr To add ``foo`` under ``/path/to/my_tools/cmake/sca`` create the following structure: diff --git a/doc/develop/toolchains/host.rst b/doc/develop/toolchains/host.rst index adfd41cef9e..900601c97d3 100644 --- a/doc/develop/toolchains/host.rst +++ b/doc/develop/toolchains/host.rst @@ -4,7 +4,7 @@ Host Toolchains ############### In some specific configurations, like when building for non-MCU x86 targets on -a Linux host, you may be able to re-use the native development tools provided +a Linux host, you may be able to reuse the native development tools provided by your operating system. To use your host gcc, set the :envvar:`ZEPHYR_TOOLCHAIN_VARIANT` diff --git a/doc/develop/west/build-flash-debug.rst b/doc/develop/west/build-flash-debug.rst index 0f9f15ef9d7..8356d95cade 100644 --- a/doc/develop/west/build-flash-debug.rst +++ b/doc/develop/west/build-flash-debug.rst @@ -179,7 +179,7 @@ it the value ``always``. For example, these commands are equivalent:: By default, ``west build`` makes no attempt to detect if the build directory needs to be made pristine. This can lead to errors if you do something like -try to re-use a build directory for a different ``--board``. +try to reuse a build directory for a different ``--board``. Using ``--pristine=auto`` makes ``west build`` detect some of these situations and make the build directory pristine before trying the build. From accea5eb69e514d0375c1ea010d35dcc49587b2c Mon Sep 17 00:00:00 2001 From: Pisit Sawangvonganan Date: Fri, 26 Jan 2024 00:54:53 +0700 Subject: [PATCH 2903/3723] doc: services: fix typo Utilize a code spell-checking tool to scan for and correct spelling errors in all files within the doc/services directory. Signed-off-by: Pisit Sawangvonganan --- doc/services/binary_descriptors/index.rst | 4 ++-- doc/services/debugging/debugmon.rst | 2 +- doc/services/ipc/ipc_service/ipc_service.rst | 8 ++++---- doc/services/shell/index.rst | 2 +- doc/services/storage/disk/nvme.rst | 2 +- doc/services/zbus/index.rst | 2 +- 6 files changed, 10 insertions(+), 10 deletions(-) diff --git a/doc/services/binary_descriptors/index.rst b/doc/services/binary_descriptors/index.rst index ef44b8265af..9cd6f8fe2cc 100644 --- a/doc/services/binary_descriptors/index.rst +++ b/doc/services/binary_descriptors/index.rst @@ -5,7 +5,7 @@ Binary Descriptors Binary Descriptors are constant data objects storing information about the binary executable. Unlike "regular" constants, binary descriptors are linked to a known offset in the binary, making -them accesible to other programs, such as a different image running on the same device or a host tool. +them accessible to other programs, such as a different image running on the same device or a host tool. A few examples of constants that would make useful binary descriptors are: kernel version, app version, build time, compiler version, environment variables, compiling host name, etc. @@ -105,7 +105,7 @@ configs should be enabled: CONFIG_BINDESC_DEFINE_BUILD_TIME=y CONFIG_BINDESC_BUILD_DATE_TIME_STRING=y -To avoid collisions with user defined descriptors, the standard descriptors were alloted +To avoid collisions with user defined descriptors, the standard descriptors were allotted the range between ``0x800-0xfff``. This leaves ``0x000-0x7ff`` to users. For more information read the ``help`` sections of these Kconfig symbols. By convention, each Kconfig symbol corresponds to a binary descriptor whose diff --git a/doc/services/debugging/debugmon.rst b/doc/services/debugging/debugmon.rst index f39f8335cf3..ccf5325d135 100644 --- a/doc/services/debugging/debugmon.rst +++ b/doc/services/debugging/debugmon.rst @@ -33,7 +33,7 @@ of the interrupt. Usage ***** -When monitor mode debuging is enabled, entering a breakpoint will not halt the +When monitor mode debugging is enabled, entering a breakpoint will not halt the processor, but rather generate an interrupt with ISR implemented under ``z_arm_debug_monitor`` symbol. :kconfig:option:`CONFIG_CORTEX_M_DEBUG_MONITOR_HOOK` config configures this interrupt to be the lowest available priority, which will allow other interrupts to execute diff --git a/doc/services/ipc/ipc_service/ipc_service.rst b/doc/services/ipc/ipc_service/ipc_service.rst index 286ded75801..ec8551fe9ce 100644 --- a/doc/services/ipc/ipc_service/ipc_service.rst +++ b/doc/services/ipc/ipc_service/ipc_service.rst @@ -67,7 +67,7 @@ See the following example: static void bound_cb(void *priv) { - /* Endpint bounded */ + /* Endpoint bounded */ } static void recv_cb(const void *data, size_t len, void *priv) @@ -93,7 +93,7 @@ See the following example: ret = ipc_service_open_instance(inst0); ret = ipc_service_register_endpoint(inst0, &ept0, &ept0_cfg); - /* Wait for endpint bound (bound_cb called) */ + /* Wait for endpoint bound (bound_cb called) */ unsigned char message[] = "hello world"; ret = ipc_service_send(&ept0, &message, sizeof(message)); @@ -117,7 +117,7 @@ See the following example: static void bound_cb(void *priv) { - /* Endpint bounded */ + /* Endpoint bounded */ } static void recv_cb_nocopy(const void *data, size_t len, void *priv) @@ -146,7 +146,7 @@ See the following example: ret = ipc_service_open_instance(inst0); ret = ipc_service_register_endpoint(inst0, &ept0, &ept0_cfg); - /* Wait for endpint bound (bound_cb called) */ + /* Wait for endpoint bound (bound_cb called) */ void *data; unsigned char message[] = "hello world"; uint32_t len = sizeof(message); diff --git a/doc/services/shell/index.rst b/doc/services/shell/index.rst index 7f8f6f0fd57..504bef139fe 100644 --- a/doc/services/shell/index.rst +++ b/doc/services/shell/index.rst @@ -654,7 +654,7 @@ RTT Backend Channel Selection ***************************** Instead of using the shell as a logger backend, RTT shell backend and RTT log -backend can also be used simulatenously, but over different channels. By +backend can also be used simultaneously, but over different channels. By separating them, the log can be captured or monitored without shell output or the shell may be scripted without log interference. Enabling both the Shell RTT backend and the Log RTT backend does not work by default, because both default diff --git a/doc/services/storage/disk/nvme.rst b/doc/services/storage/disk/nvme.rst index 4f8f94818f2..f9a2e935f34 100644 --- a/doc/services/storage/disk/nvme.rst +++ b/doc/services/storage/disk/nvme.rst @@ -36,7 +36,7 @@ NVMe configuration DTS === -Any board exposing an NVMe disk should provide a DTS overlay to enable its use whitin Zephyr +Any board exposing an NVMe disk should provide a DTS overlay to enable its use within Zephyr .. code-block:: devicetree diff --git a/doc/services/zbus/index.rst b/doc/services/zbus/index.rst index 909c3f9be10..7d69835c954 100644 --- a/doc/services/zbus/index.rst +++ b/doc/services/zbus/index.rst @@ -402,7 +402,7 @@ rate by following design tips: subscribers. So, chose carefully the configurations :kconfig:option:`CONFIG_ZBUS_MSG_SUBSCRIBER_NET_BUF_POOL_SIZE` and :kconfig:option:`CONFIG_HEAP_MEM_POOL_SIZE`. They are crucial to a proper VDED execution - (delivery garantee) considering message subscribers. + (delivery guarantee) considering message subscribers. .. warning:: Subscribers will receive only the reference of the changing channel. A data loss may be perceived From 512dc9ff38d8dad84b340712e71a20185fe59819 Mon Sep 17 00:00:00 2001 From: Pisit Sawangvonganan Date: Fri, 26 Jan 2024 00:52:04 +0700 Subject: [PATCH 2904/3723] doc: fix typo in multiple directories (build, hardware, kernel, project) Utilize a code spell-checking tool to scan for and correct spelling errors in all files within the doc/build, hardware, kernel, project directory. Signed-off-by: Pisit Sawangvonganan --- doc/hardware/peripherals/gnss.rst | 2 +- doc/hardware/peripherals/i3c.rst | 2 +- doc/kernel/drivers/device_driver_model.svg | 2 +- doc/kernel/memory_management/heap.rst | 2 +- doc/kernel/services/smp/smp.rst | 2 +- doc/project/dev_env_and_tools.rst | 2 +- 6 files changed, 6 insertions(+), 6 deletions(-) diff --git a/doc/hardware/peripherals/gnss.rst b/doc/hardware/peripherals/gnss.rst index fb750358dc3..bcc40e540ab 100644 --- a/doc/hardware/peripherals/gnss.rst +++ b/doc/hardware/peripherals/gnss.rst @@ -27,7 +27,7 @@ requires little more than implementing power management and configuration for the specific GNSS modem. Adding support for GNSS modems which use other protocols and/or -busses than the usual NMEA0183 over UART is possible, but will +buses than the usual NMEA0183 over UART is possible, but will require a bit more work from the driver developer. Configuration Options diff --git a/doc/hardware/peripherals/i3c.rst b/doc/hardware/peripherals/i3c.rst index 4ffb6dd45e4..347d8944ef1 100644 --- a/doc/hardware/peripherals/i3c.rst +++ b/doc/hardware/peripherals/i3c.rst @@ -303,7 +303,7 @@ the controller. I\ :sup:`2`\ C Devices under I3C Bus ==================================== -Since I3C is backware compatible with I\ :sup:`2`\ C, the I3C controller +Since I3C is backward compatible with I\ :sup:`2`\ C, the I3C controller API can accommodate I2C API calls without modifications if the controller device driver implements the I2C API. This has the advantage of using existing I2C devices without any modifications to their device drivers. diff --git a/doc/kernel/drivers/device_driver_model.svg b/doc/kernel/drivers/device_driver_model.svg index 9ace8badffc..fe779232eec 100644 --- a/doc/kernel/drivers/device_driver_model.svg +++ b/doc/kernel/drivers/device_driver_model.svg @@ -1,3 +1,3 @@ -
struct device {
    const struct config *config;
    const void *api;
    void * const data;
};

struct config {...};
[Not supported by viewer]
Instance 2 of Device Driver 1
Instance 2 of Device Driver 1
Instance 1 of Device Driver 1
Instance 1 of Device Driver 1
struct device {
    const struct config *config;
    const void *api;
    void * const data;
};

struct config {...};
[Not supported by viewer]
Generic
Type API
[Not supported by viewer]
API 1
API 1
API 2
API 2
API 3
API 3
Device Driver 1
[Not supported by viewer]
API Impl 1
API Impl 1
API Impl 2
API Impl 2
API Impl 3
API Impl 3
Subsytem 1
Subsytem 1
Device Driver APIs
Device Driver APIs
Device Driver Instances
Device Driver Instances
Device Driver Implementations
Device Driver Implementations
Device Driver 2
[Not supported by viewer]
API Impl 1
API Impl 1
API Impl 2
API Impl 2
API Impl 3
API Impl 3
Subsytem 2
[Not supported by viewer]
Device Driver 3
[Not supported by viewer]
API Impl 1
API Impl 1
API Impl 2
API Impl 2
API Impl 3
API Impl 3
Generic
Type API
[Not supported by viewer]
API 1
API 1
API 2
API 2
API 3
API 3
Instance 1 of Device Driver 2
Instance 1 of Device Driver 2
struct device {
    const struct config *config;
    const void *api;
    void * const data;
};

struct config {...};
[Not supported by viewer]
struct device {
    const struct config *config;
    const void *api;
    void * const data;
};

struct config {...};
[Not supported by viewer]
Instance 1 of Device Driver 3
Instance 1 of Device Driver 3
Application
Application
+
struct device {
    const struct config *config;
    const void *api;
    void * const data;
};

struct config {...};
[Not supported by viewer]
Instance 2 of Device Driver 1
Instance 2 of Device Driver 1
Instance 1 of Device Driver 1
Instance 1 of Device Driver 1
struct device {
    const struct config *config;
    const void *api;
    void * const data;
};

struct config {...};
[Not supported by viewer]
Generic
Type API
[Not supported by viewer]
API 1
API 1
API 2
API 2
API 3
API 3
Device Driver 1
[Not supported by viewer]
API Impl 1
API Impl 1
API Impl 2
API Impl 2
API Impl 3
API Impl 3
Subsystem 1
Subsystem 1
Device Driver APIs
Device Driver APIs
Device Driver Instances
Device Driver Instances
Device Driver Implementations
Device Driver Implementations
Device Driver 2
[Not supported by viewer]
API Impl 1
API Impl 1
API Impl 2
API Impl 2
API Impl 3
API Impl 3
Subsystem 2
[Not supported by viewer]
Device Driver 3
[Not supported by viewer]
API Impl 1
API Impl 1
API Impl 2
API Impl 2
API Impl 3
API Impl 3
Generic
Type API
[Not supported by viewer]
API 1
API 1
API 2
API 2
API 3
API 3
Instance 1 of Device Driver 2
Instance 1 of Device Driver 2
struct device {
    const struct config *config;
    const void *api;
    void * const data;
};

struct config {...};
[Not supported by viewer]
struct device {
    const struct config *config;
    const void *api;
    void * const data;
};

struct config {...};
[Not supported by viewer]
Instance 1 of Device Driver 3
Instance 1 of Device Driver 3
Application
Application
diff --git a/doc/kernel/memory_management/heap.rst b/doc/kernel/memory_management/heap.rst index 7dd332464d2..a52c5ff77c6 100644 --- a/doc/kernel/memory_management/heap.rst +++ b/doc/kernel/memory_management/heap.rst @@ -175,7 +175,7 @@ will be ignored and the minimum value will be used instead. To force a smaller than minimum value to be used, the application may enable the :kconfig:option:`CONFIG_HEAP_MEM_POOL_IGNORE_MIN` option. This can be useful when optimizing the heap size and the minimum requirement can be more accurately -determined for a speficic application. +determined for a specific application. Allocating Memory ================= diff --git a/doc/kernel/services/smp/smp.rst b/doc/kernel/services/smp/smp.rst index 0f1e29c9f12..0a94ed022b0 100644 --- a/doc/kernel/services/smp/smp.rst +++ b/doc/kernel/services/smp/smp.rst @@ -302,7 +302,7 @@ registers only when :c:func:`arch_switch` is called to minimize context switching latency. Such architectures must use NULL as the argument to :c:func:`z_get_next_switch_handle` to determine if there is a new thread to schedule, and follow through with their own :c:func:`arch_switch` or -derrivative if so, or directly leave interrupt mode otherwise. +derivative if so, or directly leave interrupt mode otherwise. In the former case it is up to that switch code to store the handle resulting from the thread that is being switched out in that thread's "switch_handle" field after its context has fully been saved. diff --git a/doc/project/dev_env_and_tools.rst b/doc/project/dev_env_and_tools.rst index 3d7e5fd4bbd..1678a455f17 100644 --- a/doc/project/dev_env_and_tools.rst +++ b/doc/project/dev_env_and_tools.rst @@ -323,7 +323,7 @@ Fix for an issue blocking development. * *Maintainer* -Maintainer review reqiured. +Maintainer review required. * *Security Review* From 07943eae868a4677703fa42458eebe0000237888 Mon Sep 17 00:00:00 2001 From: Keith Packard Date: Thu, 28 Dec 2023 11:06:10 -0800 Subject: [PATCH 2905/3723] drivers/wifi/esp32: Remove _POSIX_C_SOURCE define as unneeded This driver doesn't use any APIs outside of the Zephyr C library list, so it doesn't need this _POSIX_C_SOURCE define. Signed-off-by: Keith Packard --- drivers/wifi/esp32/src/esp_wifi_drv.c | 2 -- 1 file changed, 2 deletions(-) diff --git a/drivers/wifi/esp32/src/esp_wifi_drv.c b/drivers/wifi/esp32/src/esp_wifi_drv.c index dcd3139e437..24266a9abad 100644 --- a/drivers/wifi/esp32/src/esp_wifi_drv.c +++ b/drivers/wifi/esp32/src/esp_wifi_drv.c @@ -6,8 +6,6 @@ #define DT_DRV_COMPAT espressif_esp32_wifi -#define _POSIX_C_SOURCE 200809 - #include LOG_MODULE_REGISTER(esp32_wifi, CONFIG_WIFI_LOG_LEVEL); From 2417599dc004de0242ccde84c28d33c3c336cef3 Mon Sep 17 00:00:00 2001 From: Alberto Escolar Piedras Date: Thu, 28 Dec 2023 11:22:52 +0100 Subject: [PATCH 2906/3723] ztest native extensions: Set standard source macro appropriately This file uses strtok_r which is an extension to the the std C library. Let's explicity select one of the extensions which includes it instead of relaying on somebody having set it for this file somewhere else. Signed-off-by: Alberto Escolar Piedras --- subsys/testsuite/ztest/src/ztest_posix.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/subsys/testsuite/ztest/src/ztest_posix.c b/subsys/testsuite/ztest/src/ztest_posix.c index 585bbeb9837..fe6280c552f 100644 --- a/subsys/testsuite/ztest/src/ztest_posix.c +++ b/subsys/testsuite/ztest/src/ztest_posix.c @@ -4,6 +4,9 @@ * SPDX-License-Identifier: Apache-2.0 */ +#undef _POSIX_C_SOURCE +#define _POSIX_C_SOURCE 200809L + #include #include #include "cmdline.h" /* native_posix command line options header */ From 318f824d76cbbd2283e63f503c599a04c0b2acd5 Mon Sep 17 00:00:00 2001 From: Alberto Escolar Piedras Date: Thu, 28 Dec 2023 11:44:36 +0100 Subject: [PATCH 2907/3723] drivers flash_simulator: Set standard source macro appropriately This file uses several functions which are extensions to the the std C library. Let's explicity select one of the extensions which includes it instead of relaying on somebody having set it for this file somewhere else. Signed-off-by: Alberto Escolar Piedras --- drivers/flash/flash_simulator_native.c | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/drivers/flash/flash_simulator_native.c b/drivers/flash/flash_simulator_native.c index b31e42c05e0..44eebeba650 100644 --- a/drivers/flash/flash_simulator_native.c +++ b/drivers/flash/flash_simulator_native.c @@ -9,6 +9,12 @@ * native simulator runner/host context, and not in Zephyr/embedded context. */ +#undef _POSIX_C_SOURCE +/* Note: This is used only for interaction with the host C library, and is therefore exempt of + * coding guidelines rule A.4&5 which applies to the embedded code using embedded libraries + */ +#define _POSIX_C_SOURCE 200809L + #include #include #include From 1b94864a87f0017d0c709225e556efec161bd1e8 Mon Sep 17 00:00:00 2001 From: Alberto Escolar Piedras Date: Thu, 28 Dec 2023 11:45:30 +0100 Subject: [PATCH 2908/3723] drivers epprom_simulator: Set standard source macro appropriately This file uses several functions which are extensions to the the std C library. Let's explicity select one of the extensions which includes it instead of relaying on somebody having set it for this file somewhere else. Signed-off-by: Alberto Escolar Piedras --- drivers/eeprom/eeprom_simulator.c | 23 ++++++++++++++--------- 1 file changed, 14 insertions(+), 9 deletions(-) diff --git a/drivers/eeprom/eeprom_simulator.c b/drivers/eeprom/eeprom_simulator.c index 2e8d0ca6650..19efa5b3d9d 100644 --- a/drivers/eeprom/eeprom_simulator.c +++ b/drivers/eeprom/eeprom_simulator.c @@ -7,6 +7,20 @@ #define DT_DRV_COMPAT zephyr_sim_eeprom +#ifdef CONFIG_ARCH_POSIX +#undef _POSIX_C_SOURCE +/* Note: This is used only for interaction with the host C library, and is therefore exempt of + * coding guidelines rule A.4&5 which applies to the embedded code using embedded libraries + */ +#define _POSIX_C_SOURCE 200809L +#include +#include +#include +#include +#include "cmdline.h" +#include "soc.h" +#endif + #include #include @@ -17,15 +31,6 @@ #include #include -#ifdef CONFIG_ARCH_POSIX -#include -#include -#include -#include -#include "cmdline.h" -#include "soc.h" -#endif - #define LOG_LEVEL CONFIG_EEPROM_LOG_LEVEL #include LOG_MODULE_REGISTER(eeprom_simulator); From eb38e8db31a6dabd822be3ae43c4d240135b73f6 Mon Sep 17 00:00:00 2001 From: Alberto Escolar Piedras Date: Thu, 28 Dec 2023 11:46:18 +0100 Subject: [PATCH 2909/3723] drivers uart_native_ptty: Set standard source macro appropriately This file uses several functions which are extensions to the the std C library. Let's explicity select one of the extensions which includes it instead of relaying on somebody having set it for this file somewhere else. Signed-off-by: Alberto Escolar Piedras --- drivers/serial/uart_native_ptty_bottom.c | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/drivers/serial/uart_native_ptty_bottom.c b/drivers/serial/uart_native_ptty_bottom.c index 51348423cc9..7c44ccf68cc 100644 --- a/drivers/serial/uart_native_ptty_bottom.c +++ b/drivers/serial/uart_native_ptty_bottom.c @@ -5,6 +5,12 @@ * SPDX-License-Identifier: Apache-2.0 */ +#undef _XOPEN_SOURCE +/* Note: This is used only for interaction with the host C library, and is therefore exempt of + * coding guidelines rule A.4&5 which applies to the embedded code using embedded libraries + */ +#define _XOPEN_SOURCE 600 + #include #include #include From 3cc4c5eb7aaee2c64f7dbb4f26ed407b85b1a4d1 Mon Sep 17 00:00:00 2001 From: Keith Packard Date: Thu, 28 Dec 2023 10:09:06 -0800 Subject: [PATCH 2910/3723] posix: Use _POSIX_C_SOURCE=200809L instead of 200809 This constant is supposed to be defined as a long instead of an int, presumably to support systems where int isn't large enough. Signed-off-by: Keith Packard --- arch/posix/CMakeLists.txt | 2 +- boards/posix/native_posix/hw_models_top.c | 2 +- scripts/native_simulator/Makefile | 2 +- scripts/native_simulator/common/src/nsi_hw_scheduler.c | 2 +- tests/lib/c_lib/common/src/main.c | 2 +- 5 files changed, 5 insertions(+), 5 deletions(-) diff --git a/arch/posix/CMakeLists.txt b/arch/posix/CMakeLists.txt index dc83cecc610..9393a041b02 100644 --- a/arch/posix/CMakeLists.txt +++ b/arch/posix/CMakeLists.txt @@ -133,7 +133,7 @@ if (CONFIG_GPROF) target_link_options(native_simulator INTERFACE "-pg") endif() -zephyr_compile_definitions(_POSIX_C_SOURCE=200809 _XOPEN_SOURCE=600 _XOPEN_SOURCE_EXTENDED) +zephyr_compile_definitions(_POSIX_C_SOURCE=200809L _XOPEN_SOURCE=600 _XOPEN_SOURCE_EXTENDED) if (CONFIG_NATIVE_APPLICATION) zephyr_ld_options( diff --git a/boards/posix/native_posix/hw_models_top.c b/boards/posix/native_posix/hw_models_top.c index ebd582fb0b9..ba2f7d6584c 100644 --- a/boards/posix/native_posix/hw_models_top.c +++ b/boards/posix/native_posix/hw_models_top.c @@ -71,7 +71,7 @@ void hwm_signal_end_handler(int sig) * Therefore we set SA_RESETHAND: This way, the 2nd time the signal is received * the default handler would be called to terminate the program no matter what. * - * Note that SA_RESETHAND requires either _POSIX_C_SOURCE>=200809 or + * Note that SA_RESETHAND requires either _POSIX_C_SOURCE>=200809L or * _XOPEN_SOURCE>=500 */ void hwm_set_sig_handler(void) diff --git a/scripts/native_simulator/Makefile b/scripts/native_simulator/Makefile index e74b1c7bc69..a60218f45e9 100644 --- a/scripts/native_simulator/Makefile +++ b/scripts/native_simulator/Makefile @@ -60,7 +60,7 @@ NSI_OPT?=-O0 # Warnings switches (for the runner itself) NSI_WARNINGS?=-Wall -Wpedantic # Preprocessor flags -NSI_CPPFLAGS?=-D_POSIX_C_SOURCE=200809 -D_XOPEN_SOURCE=600 -D_XOPEN_SOURCE_EXTENDED +NSI_CPPFLAGS?=-D_POSIX_C_SOURCE=200809L -D_XOPEN_SOURCE=600 -D_XOPEN_SOURCE_EXTENDED NO_PIE_CO:=-fno-pie -fno-pic DEPENDFLAGS:=-MMD -MP diff --git a/scripts/native_simulator/common/src/nsi_hw_scheduler.c b/scripts/native_simulator/common/src/nsi_hw_scheduler.c index 230befcd6f9..c936961bd0f 100644 --- a/scripts/native_simulator/common/src/nsi_hw_scheduler.c +++ b/scripts/native_simulator/common/src/nsi_hw_scheduler.c @@ -55,7 +55,7 @@ static void nsi_hws_signal_end_handler(int sig) * Therefore we set SA_RESETHAND: This way, the 2nd time the signal is received * the default handler would be called to terminate the program no matter what. * - * Note that SA_RESETHAND requires either _POSIX_C_SOURCE>=200809 or + * Note that SA_RESETHAND requires either _POSIX_C_SOURCE>=200809L or * _XOPEN_SOURCE>=500 */ static void nsi_hws_set_sig_handler(void) diff --git a/tests/lib/c_lib/common/src/main.c b/tests/lib/c_lib/common/src/main.c index 986dba55f8e..ace92539d2e 100644 --- a/tests/lib/c_lib/common/src/main.c +++ b/tests/lib/c_lib/common/src/main.c @@ -16,7 +16,7 @@ */ #ifdef CONFIG_NEWLIB_LIBC -#define _POSIX_C_SOURCE 200809 +#define _POSIX_C_SOURCE 200809L #endif #include From d4967b086a8c2a76daf948b980dc9e3acf714702 Mon Sep 17 00:00:00 2001 From: Alberto Escolar Piedras Date: Thu, 28 Dec 2023 11:39:22 +0100 Subject: [PATCH 2911/3723] tests rtc_api: Define _POSIX_C_SOURCE This test uses functions which are extensions to the C library. Let's explicity select one of the extensions which includes it instead of relaying on somebody having set it for this file somewhere else. Signed-off-by: Alberto Escolar Piedras --- tests/drivers/rtc/rtc_api/CMakeLists.txt | 2 ++ 1 file changed, 2 insertions(+) diff --git a/tests/drivers/rtc/rtc_api/CMakeLists.txt b/tests/drivers/rtc/rtc_api/CMakeLists.txt index 69f8bfbf1e4..1ca800c1314 100644 --- a/tests/drivers/rtc/rtc_api/CMakeLists.txt +++ b/tests/drivers/rtc/rtc_api/CMakeLists.txt @@ -34,3 +34,5 @@ if(DEFINED CONFIG_RTC_CALIBRATION) endif() target_include_directories(app PRIVATE inc) + +target_compile_definitions(app PRIVATE _POSIX_C_SOURCE=200809L) From 06f15fcc365ff55a3c1e9ef92cb4793b70d830e0 Mon Sep 17 00:00:00 2001 From: Alberto Escolar Piedras Date: Thu, 28 Dec 2023 12:11:32 +0100 Subject: [PATCH 2912/3723] subsys shell devmem_service: Fix includes * The include for the host libC should be guarded with using the host libC instead of the POSIX arch, as this supports other C libraries. * This code uses getopt, which is an extension to the C library. Let's explicity select one of the extensions which includes it instead of relaying on somebody having set it for this file somewhere else. Signed-off-by: Alberto Escolar Piedras --- subsys/shell/modules/devmem_service.c | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/subsys/shell/modules/devmem_service.c b/subsys/shell/modules/devmem_service.c index 60c51d07fae..e5a7a06f35b 100644 --- a/subsys/shell/modules/devmem_service.c +++ b/subsys/shell/modules/devmem_service.c @@ -6,15 +6,18 @@ * SPDX-License-Identifier: Apache-2.0 */ +#undef _POSIX_C_SOURCE +#define _POSIX_C_SOURCE 200809L + #include -#include -#include -#include -#ifdef CONFIG_ARCH_POSIX +#ifdef CONFIG_NATIVE_LIBC #include #else #include #endif +#include +#include +#include static inline bool is_ascii(uint8_t data) { From 7369bb56e308c7b8a156d62c5ca5993f10a26074 Mon Sep 17 00:00:00 2001 From: Alberto Escolar Piedras Date: Thu, 28 Dec 2023 12:21:00 +0100 Subject: [PATCH 2913/3723] drivers rtc: Do not treat the host libC differently This code was using strptime from the C library in some cases, but this function is an extension which many embedded libCs do not provide, and which is not provided by default unless _XOPEN_SOURCE or a similar macro is defined before the system headers are included. We could define _XOPEN_SOURCE for the libraries that provide it, but instead of treating the host C library differently than embedded libraries, let's just build the provided version always, as that should provide better coverage of this code. Note: It seems picolibc's strptime is broken, until this very recent patch: https://github.com/picolibc/picolibc/pull/657 so we should not select it when building for this library for a while either. Signed-off-by: Alberto Escolar Piedras --- drivers/rtc/rtc_shell.c | 4 ---- 1 file changed, 4 deletions(-) diff --git a/drivers/rtc/rtc_shell.c b/drivers/rtc/rtc_shell.c index 8dcaf46f875..bc9980d20af 100644 --- a/drivers/rtc/rtc_shell.c +++ b/drivers/rtc/rtc_shell.c @@ -16,8 +16,6 @@ static const char format_iso8601[] = "%FT%T"; static const char format_time[] = "%T"; /* hh:mm:ss */ static const char format_date[] = " %F"; /* yyyy-mm-dd */ -#if !defined CONFIG_BOARD_NATIVE_POSIX - static const char *consume_chars(const char *s, char *dest, unsigned int cnt) { if (strlen(s) < cnt) { @@ -148,8 +146,6 @@ static char *strptime(const char *s, const char *format, struct tm *tm_time) } } -#endif - static int cmd_set(const struct shell *sh, size_t argc, char **argv) { const struct device *dev = device_get_binding(argv[1]); From f53cf8f54c2342e8bd1e97980f18280e592d3337 Mon Sep 17 00:00:00 2001 From: Alberto Escolar Piedras Date: Thu, 28 Dec 2023 17:23:50 +0100 Subject: [PATCH 2914/3723] tests/lib/c_lib: Set standard source macro appropriately strnlen() and strtok_r() are tested in this files which are extensions to the the std C library. Let's explicity select one of the extensions also when building with the host C library, instead of relaying on somebody having set it for this file somewhere else. Also, let's be nice and undefine them first in case they had been defined somewhere else in the build scripts. Signed-off-by: Alberto Escolar Piedras --- tests/lib/c_lib/common/src/main.c | 3 ++- tests/lib/c_lib/strerror/src/main.c | 4 ---- 2 files changed, 2 insertions(+), 5 deletions(-) diff --git a/tests/lib/c_lib/common/src/main.c b/tests/lib/c_lib/common/src/main.c index ace92539d2e..1995693cad4 100644 --- a/tests/lib/c_lib/common/src/main.c +++ b/tests/lib/c_lib/common/src/main.c @@ -15,7 +15,8 @@ * it guarantee that ALL functionality provided is working correctly. */ -#ifdef CONFIG_NEWLIB_LIBC +#if defined(CONFIG_NEWLIB_LIBC) || defined(CONFIG_NATIVE_LIBC) +#undef _POSIX_C_SOURCE #define _POSIX_C_SOURCE 200809L #endif diff --git a/tests/lib/c_lib/strerror/src/main.c b/tests/lib/c_lib/strerror/src/main.c index 494902b019c..3761c58dd99 100644 --- a/tests/lib/c_lib/strerror/src/main.c +++ b/tests/lib/c_lib/strerror/src/main.c @@ -4,10 +4,6 @@ * SPDX-License-Identifier: Apache-2.0 */ -#ifdef CONFIG_NEWLIB_LIBC -#define _POSIX_C_SOURCE 200809 -#endif - #include #include From 68c3a9ba4618698233578469c07fb35f0fa41841 Mon Sep 17 00:00:00 2001 From: Alberto Escolar Piedras Date: Thu, 28 Dec 2023 17:31:10 +0100 Subject: [PATCH 2915/3723] tests modem/backends/tty: Define _XOPEN_SOURCE This test uses functions which are extensions to the C library. Let's explicity select one of the extensions which includes it instead of relaying on somebody having set it for this file somewhere else. (Note this test is exclusive to native targets) Signed-off-by: Alberto Escolar Piedras --- tests/subsys/modem/backends/tty/CMakeLists.txt | 1 + 1 file changed, 1 insertion(+) diff --git a/tests/subsys/modem/backends/tty/CMakeLists.txt b/tests/subsys/modem/backends/tty/CMakeLists.txt index e692be0de90..44597d8ae95 100644 --- a/tests/subsys/modem/backends/tty/CMakeLists.txt +++ b/tests/subsys/modem/backends/tty/CMakeLists.txt @@ -6,3 +6,4 @@ find_package(Zephyr REQUIRED HINTS $ENV{ZEPHYR_BASE}) project(modem_backend_tty_test) target_sources(app PRIVATE src/main.c) +target_compile_definitions(app PRIVATE _XOPEN_SOURCE=600) From 10060c8891efebcc43ee3589239f776e8f62c5b7 Mon Sep 17 00:00:00 2001 From: Alberto Escolar Piedras Date: Thu, 28 Dec 2023 17:47:53 +0100 Subject: [PATCH 2916/3723] tests/benchmarks/footprints: Define required source standard macros strnlen is not a C standard API, but an extension. Instead of relaying that the SOURCE macro was set somewhere else of that the C library provides a prototype anyhow let's explicitly define it for this library. Signed-off-by: Alberto Escolar Piedras --- tests/benchmarks/footprints/src/libc.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/tests/benchmarks/footprints/src/libc.c b/tests/benchmarks/footprints/src/libc.c index 48b8eb823cf..7cf71239f4c 100644 --- a/tests/benchmarks/footprints/src/libc.c +++ b/tests/benchmarks/footprints/src/libc.c @@ -4,6 +4,9 @@ * SPDX-License-Identifier: Apache-2.0 */ +#undef _POSIX_C_SOURCE +#define _POSIX_C_SOURCE 200809L + #include #include From 4e869ad9f83a6c9236918bf303088ed2568e815f Mon Sep 17 00:00:00 2001 From: Alberto Escolar Piedras Date: Thu, 28 Dec 2023 17:48:22 +0100 Subject: [PATCH 2917/3723] tests/bluetooth/uuid: Define required source standard macros strnlen is not a C standard API, but an extension. Instead of relaying that the SOURCE macro was set somewhere else of that the C library provides a prototype anyhow let's explicitly define it for this library. Signed-off-by: Alberto Escolar Piedras --- tests/bluetooth/uuid/src/test_bt_uuid_to_str.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/tests/bluetooth/uuid/src/test_bt_uuid_to_str.c b/tests/bluetooth/uuid/src/test_bt_uuid_to_str.c index ed922ce1dc9..5bb20adac10 100644 --- a/tests/bluetooth/uuid/src/test_bt_uuid_to_str.c +++ b/tests/bluetooth/uuid/src/test_bt_uuid_to_str.c @@ -2,6 +2,9 @@ * SPDX-License-Identifier: Apache-2.0 */ +#undef _POSIX_C_SOURCE +#define _POSIX_C_SOURCE 200809L + #include #include From c9a1c25dcbe8aa3c21ad21c0c15781e6a8716156 Mon Sep 17 00:00:00 2001 From: Alberto Escolar Piedras Date: Thu, 28 Dec 2023 17:53:47 +0100 Subject: [PATCH 2918/3723] tests/net coap_client: Define _POSIX_C_SOURCE This test uses functions and types which are extensions to the C library. Let's explicity select one of the extensions which includes it instead of relaying on somebody having set it for this file somewhere else. Signed-off-by: Alberto Escolar Piedras --- tests/net/lib/coap_client/CMakeLists.txt | 2 ++ 1 file changed, 2 insertions(+) diff --git a/tests/net/lib/coap_client/CMakeLists.txt b/tests/net/lib/coap_client/CMakeLists.txt index cb86d78f611..d99bb3145f9 100644 --- a/tests/net/lib/coap_client/CMakeLists.txt +++ b/tests/net/lib/coap_client/CMakeLists.txt @@ -16,6 +16,8 @@ target_sources(app PRIVATE ${ZEPHYR_BASE}/subsys/net/lib/coap/coap.c) target_include_directories(app PRIVATE ${CMAKE_CURRENT_SOURCE_DIR}/src) target_include_directories(app PRIVATE ${ZEPHYR_BASE}/include/) +target_compile_definitions(app PRIVATE _POSIX_C_SOURCE=200809L) + add_compile_definitions(CONFIG_NET_SOCKETS_POLL_MAX=3) add_compile_definitions(CONFIG_COAP_CLIENT=y) add_compile_definitions(CONFIG_COAP_CLIENT_BLOCK_SIZE=256) From 4ff79cb74ac7c68957ce9a41847da4955dcb2721 Mon Sep 17 00:00:00 2001 From: Alberto Escolar Piedras Date: Thu, 28 Dec 2023 17:58:05 +0100 Subject: [PATCH 2919/3723] subsys/net/lib/lwm2m: Define required source standard macros Instead of relaying on those macros having been defined somewhere else let's define them for this file. Signed-off-by: Alberto Escolar Piedras --- subsys/net/lib/lwm2m/lwm2m_rw_cbor.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/subsys/net/lib/lwm2m/lwm2m_rw_cbor.c b/subsys/net/lib/lwm2m/lwm2m_rw_cbor.c index 3b35d579569..ef009162ca0 100644 --- a/subsys/net/lib/lwm2m/lwm2m_rw_cbor.c +++ b/subsys/net/lib/lwm2m/lwm2m_rw_cbor.c @@ -7,6 +7,9 @@ #define LOG_MODULE_NAME net_lwm2m_cbor #define LOG_LEVEL CONFIG_LWM2M_LOG_LEVEL +#undef _POSIX_C_SOURCE +#define _POSIX_C_SOURCE 200809L /* Required for gmtime_r */ + #include #include #include From 9dcbfa8bf23fb73a0d4ab14f93e1f14fb07022c8 Mon Sep 17 00:00:00 2001 From: Keith Packard Date: Wed, 27 Dec 2023 22:08:48 -0800 Subject: [PATCH 2920/3723] libc/picolibc: Remove the global definition of _POSIX_C_SOURCE This was necessary to get Picolibc to expose the whole Zephyr C library API, but current versions of the SDK use a version of Picolibc with built-in Zephyr support. Signed-off-by: Keith Packard --- lib/libc/picolibc/CMakeLists.txt | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/lib/libc/picolibc/CMakeLists.txt b/lib/libc/picolibc/CMakeLists.txt index 232e4ba8fc1..23e84231e2a 100644 --- a/lib/libc/picolibc/CMakeLists.txt +++ b/lib/libc/picolibc/CMakeLists.txt @@ -9,10 +9,11 @@ zephyr_compile_definitions(__LINUX_ERRNO_EXTENSIONS__) if(NOT CONFIG_PICOLIBC_USE_MODULE) - # Use picolibc provided with the toolchain + # Use picolibc provided with the toolchain. This requires a new enough + # toolchain so that the version of picolibc supports auto-detecting a + # Zephyr build (via the __ZEPHYR__ macro) to expose the Zephyr C API zephyr_compile_options(--specs=picolibc.specs) - zephyr_compile_definitions(_POSIX_C_SOURCE=200809) zephyr_libc_link_libraries(--specs=picolibc.specs c -lgcc) if(CONFIG_PICOLIBC_IO_FLOAT) zephyr_compile_definitions(PICOLIBC_DOUBLE_PRINTF_SCANF) From cc1364318619a1ed3b6279586b5dbbd974a6b969 Mon Sep 17 00:00:00 2001 From: Alberto Escolar Piedras Date: Thu, 28 Dec 2023 11:56:44 +0100 Subject: [PATCH 2921/3723] board native_posix: Define required source standard macros Instead of relaying on those macros having been defined somewhere else let's define them for this library. Signed-off-by: Alberto Escolar Piedras --- boards/posix/native_posix/CMakeLists.txt | 1 + 1 file changed, 1 insertion(+) diff --git a/boards/posix/native_posix/CMakeLists.txt b/boards/posix/native_posix/CMakeLists.txt index d9b37953e77..20210a46a81 100644 --- a/boards/posix/native_posix/CMakeLists.txt +++ b/boards/posix/native_posix/CMakeLists.txt @@ -3,6 +3,7 @@ zephyr_library() zephyr_library_compile_definitions(NO_POSIX_CHEATS) +zephyr_library_compile_definitions(_POSIX_C_SOURCE=200809L _XOPEN_SOURCE=600 _XOPEN_SOURCE_EXTENDED) zephyr_library_sources( hw_models_top.c From 404db20877d9f9b67546c96f25bd9a8954131b3d Mon Sep 17 00:00:00 2001 From: Alberto Escolar Piedras Date: Thu, 25 Jan 2024 20:06:22 +0100 Subject: [PATCH 2922/3723] drivers/entropy/native: Define required SOURCE macro The srandom function is not available unless _XOPEN_SOURCE is set > 500 or an equivalent declaration is done. Let's set it. Signed-off-by: Alberto Escolar Piedras --- drivers/entropy/fake_entropy_native_bottom.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/drivers/entropy/fake_entropy_native_bottom.c b/drivers/entropy/fake_entropy_native_bottom.c index ccfb7974e34..f456b978d99 100644 --- a/drivers/entropy/fake_entropy_native_bottom.c +++ b/drivers/entropy/fake_entropy_native_bottom.c @@ -7,6 +7,9 @@ * ARCH_POSIX architecture */ +#undef _XOPEN_SOURCE +#define _XOPEN_SOURCE 700 + #include #include #include From ca68ef7e5aae16a3c847b4a96ca45cb404647ea8 Mon Sep 17 00:00:00 2001 From: Alberto Escolar Piedras Date: Thu, 28 Dec 2023 11:57:42 +0100 Subject: [PATCH 2923/3723] arch posix: Do not define standard SOURCE macros globally Do not define these macros globally, but instead define them only for this library and when needed. Signed-off-by: Alberto Escolar Piedras --- arch/posix/CMakeLists.txt | 2 -- arch/posix/core/CMakeLists.txt | 2 ++ 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/arch/posix/CMakeLists.txt b/arch/posix/CMakeLists.txt index 9393a041b02..7001e54e75f 100644 --- a/arch/posix/CMakeLists.txt +++ b/arch/posix/CMakeLists.txt @@ -133,8 +133,6 @@ if (CONFIG_GPROF) target_link_options(native_simulator INTERFACE "-pg") endif() -zephyr_compile_definitions(_POSIX_C_SOURCE=200809L _XOPEN_SOURCE=600 _XOPEN_SOURCE_EXTENDED) - if (CONFIG_NATIVE_APPLICATION) zephyr_ld_options( -ldl diff --git a/arch/posix/core/CMakeLists.txt b/arch/posix/core/CMakeLists.txt index 3cf83c9fdda..12ec5261635 100644 --- a/arch/posix/core/CMakeLists.txt +++ b/arch/posix/core/CMakeLists.txt @@ -28,6 +28,8 @@ if(CONFIG_NATIVE_APPLICATION) ${ZEPHYR_BASE}/scripts/native_simulator/common/src/nce.c ${ZEPHYR_BASE}/scripts/native_simulator/common/src/nsi_host_trampolines.c ) + + zephyr_library_compile_definitions(_POSIX_C_SOURCE=200809L _XOPEN_SOURCE=600 _XOPEN_SOURCE_EXTENDED) else() zephyr_library_sources( posix_core_nsi.c From 1b90d29c8984a98ac75f26b569cf324d556ca1b2 Mon Sep 17 00:00:00 2001 From: Alberto Escolar Piedras Date: Thu, 25 Jan 2024 17:42:45 +0100 Subject: [PATCH 2924/3723] modules/zcbor: Fix implicit function declaration warning MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Both zcbor_encode.c & zcbor_decode.c use strnlen() In general these 2 functions are only exposed by the C library if _POSIX_C_SOURCE is set 200809L. But neither of these files (or their build scripts), are setting this macro, causing build warnings Implicit declaration of function ‘strnlen’ which turn into failures in CI with some libCs. Let's set this macro to avoid this issue. Signed-off-by: Alberto Escolar Piedras --- modules/zcbor/CMakeLists.txt | 2 ++ 1 file changed, 2 insertions(+) diff --git a/modules/zcbor/CMakeLists.txt b/modules/zcbor/CMakeLists.txt index 33b60bdfbcb..45535fc8594 100644 --- a/modules/zcbor/CMakeLists.txt +++ b/modules/zcbor/CMakeLists.txt @@ -10,6 +10,8 @@ if(CONFIG_ZCBOR) ${ZEPHYR_ZCBOR_MODULE_DIR}/src/zcbor_encode.c ) + zephyr_library_compile_definitions(_POSIX_C_SOURCE=200809L) + zephyr_compile_definitions_ifdef(CONFIG_ZCBOR_CANONICAL ZCBOR_CANONICAL) zephyr_compile_definitions_ifdef(CONFIG_ZCBOR_STOP_ON_ERROR ZCBOR_STOP_ON_ERROR) zephyr_compile_definitions_ifdef(CONFIG_ZCBOR_VERBOSE ZCBOR_VERBOSE) From bc8d69caa6156a3020d2fac5be47dd2bcd2d9de1 Mon Sep 17 00:00:00 2001 From: Henrik Brix Andersen Date: Wed, 24 Jan 2024 12:56:06 +0100 Subject: [PATCH 2925/3723] drivers: can: stm32: bxcan: store current operation mode Store the current operation mode in the can_driver_data structure. Fixes: 9051824fa3f1b2d22163e27abef8061c6242464e Signed-off-by: Henrik Brix Andersen --- drivers/can/can_stm32_bxcan.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/drivers/can/can_stm32_bxcan.c b/drivers/can/can_stm32_bxcan.c index 0f2a121e790..5f3d3a25c3b 100644 --- a/drivers/can/can_stm32_bxcan.c +++ b/drivers/can/can_stm32_bxcan.c @@ -532,6 +532,8 @@ static int can_stm32_set_mode(const struct device *dev, can_mode_t mode) can->MCR &= ~CAN_MCR_NART; } + data->common.mode = mode; + k_mutex_unlock(&data->inst_mutex); return 0; From 69d072ad2fde1ada057bd0564a40c3c1603c700e Mon Sep 17 00:00:00 2001 From: Henrik Brix Andersen Date: Wed, 24 Jan 2024 11:28:24 +0100 Subject: [PATCH 2926/3723] drivers: can: add can_get_mode() system call Add system call can_get_mode() for getting the current operation mode of a CAN controller. Signed-off-by: Henrik Brix Andersen --- drivers/can/can_handlers.c | 8 ++++++++ include/zephyr/drivers/can.h | 16 ++++++++++++++++ 2 files changed, 24 insertions(+) diff --git a/drivers/can/can_handlers.c b/drivers/can/can_handlers.c index 6113f149541..bda5fb28948 100644 --- a/drivers/can/can_handlers.c +++ b/drivers/can/can_handlers.c @@ -170,6 +170,14 @@ static inline int z_vrfy_can_set_mode(const struct device *dev, can_mode_t mode) } #include +static inline can_mode_t z_vrfy_can_get_mode(const struct device *dev) +{ + K_OOPS(K_SYSCALL_OBJ(dev, K_OBJ_DRIVER_CAN)); + + return z_impl_can_get_mode(dev); +} +#include + static inline int z_vrfy_can_set_bitrate(const struct device *dev, uint32_t bitrate) { K_OOPS(K_SYSCALL_DRIVER_CAN(dev, set_timing)); diff --git a/include/zephyr/drivers/can.h b/include/zephyr/drivers/can.h index ce97a15e832..67498a90d4b 100644 --- a/include/zephyr/drivers/can.h +++ b/include/zephyr/drivers/can.h @@ -1130,6 +1130,22 @@ static inline int z_impl_can_set_mode(const struct device *dev, can_mode_t mode) return api->set_mode(dev, mode); } +/** + * @brief Get the operation mode of the CAN controller + * + * @param dev Pointer to the device structure for the driver instance. + * + * @return Current operation mode. + */ +__syscall can_mode_t can_get_mode(const struct device *dev); + +static inline can_mode_t z_impl_can_get_mode(const struct device *dev) +{ + const struct can_driver_data *common = (const struct can_driver_data *)dev->data; + + return common->mode; +} + /** * @brief Set the bitrate of the CAN controller * From 156c294c6fc6e6292e2ae3543d1187487ca7bc60 Mon Sep 17 00:00:00 2001 From: Henrik Brix Andersen Date: Wed, 24 Jan 2024 11:30:04 +0100 Subject: [PATCH 2927/3723] tests: drivers: can: api: verify operation mode changes Verify changes in operation mode throughout the API tests using can_get_mode(). Signed-off-by: Henrik Brix Andersen --- tests/drivers/can/api/src/canfd.c | 4 ++++ tests/drivers/can/api/src/classic.c | 3 +++ 2 files changed, 7 insertions(+) diff --git a/tests/drivers/can/api/src/canfd.c b/tests/drivers/can/api/src/canfd.c index b0f6cb8a2d1..be0f235cc7b 100644 --- a/tests/drivers/can/api/src/canfd.c +++ b/tests/drivers/can/api/src/canfd.c @@ -286,6 +286,7 @@ static void check_filters_preserved_between_modes(can_mode_t first, can_mode_t s err = can_set_mode(can_dev, first | CAN_MODE_LOOPBACK); zassert_equal(err, 0, "failed to set first loopback mode (err %d)", err); + zassert_equal(first | CAN_MODE_LOOPBACK, can_get_mode(can_dev)); err = can_start(can_dev); zassert_equal(err, 0, "failed to start CAN controller (err %d)", err); @@ -318,6 +319,7 @@ static void check_filters_preserved_between_modes(can_mode_t first, can_mode_t s err = can_set_mode(can_dev, second | CAN_MODE_LOOPBACK); zassert_equal(err, 0, "failed to set second loopback mode (err %d)", err); + zassert_equal(second | CAN_MODE_LOOPBACK, can_get_mode(can_dev)); err = can_start(can_dev); zassert_equal(err, 0, "failed to start CAN controller (err %d)", err); @@ -346,6 +348,7 @@ static void check_filters_preserved_between_modes(can_mode_t first, can_mode_t s err = can_set_mode(can_dev, CAN_MODE_FD | CAN_MODE_LOOPBACK); zassert_equal(err, 0, "failed to set loopback-mode (err %d)", err); + zassert_equal(CAN_MODE_FD | CAN_MODE_LOOPBACK, can_get_mode(can_dev)); err = can_start(can_dev); zassert_equal(err, 0, "failed to start CAN controller (err %d)", err); @@ -433,6 +436,7 @@ void *canfd_setup(void) err = can_set_mode(can_dev, CAN_MODE_LOOPBACK | CAN_MODE_FD); zassert_equal(err, 0, "failed to set CAN FD loopback mode (err %d)", err); + zassert_equal(CAN_MODE_LOOPBACK | CAN_MODE_FD, can_get_mode(can_dev)); err = can_start(can_dev); zassert_equal(err, 0, "failed to start CAN controller (err %d)", err); diff --git a/tests/drivers/can/api/src/classic.c b/tests/drivers/can/api/src/classic.c index b70ff7e1003..ccb93753673 100644 --- a/tests/drivers/can/api/src/classic.c +++ b/tests/drivers/can/api/src/classic.c @@ -915,9 +915,11 @@ ZTEST_USER(can_classic, test_filters_preserved_through_mode_change) err = can_set_mode(can_dev, CAN_MODE_NORMAL); zassert_equal(err, 0, "failed to set normal mode (err %d)", err); + zassert_equal(CAN_MODE_NORMAL, can_get_mode(can_dev)); err = can_set_mode(can_dev, CAN_MODE_LOOPBACK); zassert_equal(err, 0, "failed to set loopback-mode (err %d)", err); + zassert_equal(CAN_MODE_LOOPBACK, can_get_mode(can_dev)); err = can_start(can_dev); zassert_equal(err, 0, "failed to start CAN controller (err %d)", err); @@ -1121,6 +1123,7 @@ void *can_classic_setup(void) err = can_set_mode(can_dev, CAN_MODE_LOOPBACK); zassert_equal(err, 0, "failed to set loopback mode (err %d)", err); + zassert_equal(CAN_MODE_LOOPBACK, can_get_mode(can_dev)); err = can_start(can_dev); zassert_equal(err, 0, "failed to start CAN controller (err %d)", err); From 336d7ef7b4caa92e2733a74efa7900afabf2a641 Mon Sep 17 00:00:00 2001 From: Henrik Brix Andersen Date: Wed, 24 Jan 2024 11:31:42 +0100 Subject: [PATCH 2928/3723] drivers: can: shell: print current operation mode in show subcommand Print the current operation mode in the "can show" shell subcommand. Signed-off-by: Henrik Brix Andersen --- doc/hardware/peripherals/can/shell.rst | 4 +++- drivers/can/can_shell.c | 8 ++++++-- 2 files changed, 9 insertions(+), 3 deletions(-) diff --git a/doc/hardware/peripherals/can/shell.rst b/doc/hardware/peripherals/can/shell.rst index cfd016843d0..bb164dec327 100644 --- a/doc/hardware/peripherals/can/shell.rst +++ b/doc/hardware/peripherals/can/shell.rst @@ -62,7 +62,8 @@ Inspection The properties of a given CAN controller can be inspected using the ``can show`` subcommand as shown below. The properties include the core CAN clock rate, the maximum supported bitrate, the number of -RX filters supported, capabilities, current state, error counters, timing limits, and more: +RX filters supported, capabilities, current mode, current state, error counters, timing limits, and +more: .. code-block:: console @@ -72,6 +73,7 @@ RX filters supported, capabilities, current state, error counters, timing limits max std filters: 15 max ext filters: 15 capabilities: normal loopback listen-only fd + mode: normal state: stopped rx errors: 0 tx errors: 0 diff --git a/drivers/can/can_shell.c b/drivers/can/can_shell.c index 3f193ae9497..c7397869f85 100644 --- a/drivers/can/can_shell.c +++ b/drivers/can/can_shell.c @@ -202,7 +202,7 @@ static const char *can_shell_state_to_string(enum can_state state) } } -static void can_shell_print_capabilities(const struct shell *sh, can_mode_t cap) +static void can_shell_print_extended_modes(const struct shell *sh, can_mode_t cap) { int bit; int i; @@ -331,7 +331,11 @@ static int cmd_can_show(const struct shell *sh, size_t argc, char **argv) shell_print(sh, "max ext filters: %d", max_ext_filters); shell_fprintf(sh, SHELL_NORMAL, "capabilities: normal "); - can_shell_print_capabilities(sh, cap); + can_shell_print_extended_modes(sh, cap); + shell_fprintf(sh, SHELL_NORMAL, "\n"); + + shell_fprintf(sh, SHELL_NORMAL, "mode: normal "); + can_shell_print_extended_modes(sh, can_get_mode(dev)); shell_fprintf(sh, SHELL_NORMAL, "\n"); shell_print(sh, "state: %s", can_shell_state_to_string(state)); From 583d44d7d5ea95052511f70bd2066af154bff0e5 Mon Sep 17 00:00:00 2001 From: Henrik Brix Andersen Date: Wed, 24 Jan 2024 12:13:30 +0100 Subject: [PATCH 2929/3723] drivers: can: add can_get_transceiver() system call Add system call can_get_transceiver() for getting the CAN transceiver associated with a CAN controller. Signed-off-by: Henrik Brix Andersen --- drivers/can/can_handlers.c | 8 ++++++++ include/zephyr/drivers/can.h | 18 ++++++++++++++++++ 2 files changed, 26 insertions(+) diff --git a/drivers/can/can_handlers.c b/drivers/can/can_handlers.c index bda5fb28948..aa0a62674cb 100644 --- a/drivers/can/can_handlers.c +++ b/drivers/can/can_handlers.c @@ -146,6 +146,14 @@ static inline int z_vrfy_can_get_capabilities(const struct device *dev, can_mode } #include +static inline const struct device *z_vrfy_can_get_transceiver(const struct device *dev) +{ + K_OOPS(K_SYSCALL_OBJ(dev, K_OBJ_DRIVER_CAN)); + + return z_impl_can_get_transceiver(dev); +} +#include + static inline int z_vrfy_can_start(const struct device *dev) { K_OOPS(K_SYSCALL_DRIVER_CAN(dev, start)); diff --git a/include/zephyr/drivers/can.h b/include/zephyr/drivers/can.h index 67498a90d4b..59be684fd38 100644 --- a/include/zephyr/drivers/can.h +++ b/include/zephyr/drivers/can.h @@ -1061,6 +1061,24 @@ static inline int z_impl_can_get_capabilities(const struct device *dev, can_mode return api->get_capabilities(dev, cap); } +/** + * @brief Get the CAN transceiver associated with the CAN controller + * + * Get a pointer to the device structure for the CAN transceiver associated with the CAN controller. + * + * @param dev Pointer to the device structure for the driver instance. + * @return Pointer to the device structure for the associated CAN transceiver driver instance, or + * NULL if no transceiver is associated. + */ +__syscall const struct device *can_get_transceiver(const struct device *dev); + +static const struct device *z_impl_can_get_transceiver(const struct device *dev) +{ + const struct can_driver_config *common = (const struct can_driver_config *)dev->config; + + return common->phy; +} + /** * @brief Start the CAN controller * From 6237e0482bd0818562bb8bef23941f6b4497947d Mon Sep 17 00:00:00 2001 From: Henrik Brix Andersen Date: Wed, 24 Jan 2024 12:18:55 +0100 Subject: [PATCH 2930/3723] tests: drivers: can: api: add test for can_get_transceiver() Add test for the can_get_transceiver() system call. Signed-off-by: Henrik Brix Andersen --- tests/drivers/can/api/CMakeLists.txt | 1 + tests/drivers/can/api/src/common.c | 2 + tests/drivers/can/api/src/common.h | 1 + tests/drivers/can/api/src/transceiver.c | 57 +++++++++++++++++++++++++ 4 files changed, 61 insertions(+) create mode 100644 tests/drivers/can/api/src/transceiver.c diff --git a/tests/drivers/can/api/CMakeLists.txt b/tests/drivers/can/api/CMakeLists.txt index fb936332e04..cf0ed366512 100644 --- a/tests/drivers/can/api/CMakeLists.txt +++ b/tests/drivers/can/api/CMakeLists.txt @@ -6,6 +6,7 @@ project(integration) target_sources(app PRIVATE src/common.c) target_sources(app PRIVATE src/classic.c) +target_sources(app PRIVATE src/transceiver.c) target_sources(app PRIVATE src/utilities.c) target_sources_ifdef(CONFIG_CAN_FD_MODE app PRIVATE src/canfd.c) target_sources_ifdef(CONFIG_CAN_STATS app PRIVATE src/stats.c) diff --git a/tests/drivers/can/api/src/common.c b/tests/drivers/can/api/src/common.c index 22c2bce192d..1854ef8fb11 100644 --- a/tests/drivers/can/api/src/common.c +++ b/tests/drivers/can/api/src/common.c @@ -15,6 +15,8 @@ * @brief Global variables. */ ZTEST_DMEM const struct device *const can_dev = DEVICE_DT_GET(DT_CHOSEN(zephyr_canbus)); +ZTEST_DMEM const struct device *const can_phy = + DEVICE_DT_GET_OR_NULL(DT_PHANDLE(DT_CHOSEN(zephyr_canbus), phys)); struct k_sem rx_callback_sem; struct k_sem tx_callback_sem; diff --git a/tests/drivers/can/api/src/common.h b/tests/drivers/can/api/src/common.h index ff328d156a0..92d5352e3e6 100644 --- a/tests/drivers/can/api/src/common.h +++ b/tests/drivers/can/api/src/common.h @@ -52,6 +52,7 @@ * @brief Common variables. */ extern ZTEST_DMEM const struct device *const can_dev; +extern ZTEST_DMEM const struct device *const can_phy; extern struct k_sem rx_callback_sem; extern struct k_sem tx_callback_sem; extern struct k_msgq can_msgq; diff --git a/tests/drivers/can/api/src/transceiver.c b/tests/drivers/can/api/src/transceiver.c new file mode 100644 index 00000000000..aac8cf85dba --- /dev/null +++ b/tests/drivers/can/api/src/transceiver.c @@ -0,0 +1,57 @@ +/* + * Copyright (c) 2024 Vestas Wind Systems A/S + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include +#include + +#include "common.h" + +/** + * @addtogroup t_can_driver + * @{ + * @defgroup t_can_transceiver test_can_transceiver + * @} + */ + +/** + * @brief Test getting CAN transceiver device pointer. + */ +ZTEST_USER(can_transceiver, test_get_transceiver) +{ + const struct device *phy = can_get_transceiver(can_dev); + + zassert_equal(phy, can_phy, "wrong CAN transceiver device pointer returned"); +} + +static bool can_transceiver_predicate(const void *state) +{ + ARG_UNUSED(state); + + if (!device_is_ready(can_dev)) { + TC_PRINT("CAN device not ready"); + return false; + } + + if (!device_is_ready(can_phy)) { + TC_PRINT("CAN transceiver device not ready"); + return false; + } + + return true; +} + +void *can_transceiver_setup(void) +{ + k_object_access_grant(can_dev, k_current_get()); + k_object_access_grant(can_phy, k_current_get()); + + zassert_true(device_is_ready(can_dev), "CAN device not ready"); + zassert_true(device_is_ready(can_phy), "CAN transceiver device not ready"); + + return NULL; +} + +ZTEST_SUITE(can_transceiver, can_transceiver_predicate, can_transceiver_setup, NULL, NULL, NULL); From bde074714e62d3e1f8346a9b9179c7e6a1608814 Mon Sep 17 00:00:00 2001 From: Henrik Brix Andersen Date: Wed, 24 Jan 2024 12:22:33 +0100 Subject: [PATCH 2931/3723] drivers: can: shell: print name of associated CAN transceiver if present Print the name of the associated CAN transceiver in the "can show" shell subcommand. Signed-off-by: Henrik Brix Andersen --- doc/hardware/peripherals/can/shell.rst | 1 + drivers/can/can_shell.c | 4 ++++ 2 files changed, 5 insertions(+) diff --git a/doc/hardware/peripherals/can/shell.rst b/doc/hardware/peripherals/can/shell.rst index bb164dec327..5b161fde5d6 100644 --- a/doc/hardware/peripherals/can/shell.rst +++ b/doc/hardware/peripherals/can/shell.rst @@ -79,6 +79,7 @@ more: tx errors: 0 timing: sjw 1..128, prop_seg 0..0, phase_seg1 2..256, phase_seg2 2..128, prescaler 1..512 timing data: sjw 1..16, prop_seg 0..0, phase_seg1 1..32, phase_seg2 1..16, prescaler 1..32 + transceiver: passive/none statistics: bit errors: 0 bit0 errors: 0 diff --git a/drivers/can/can_shell.c b/drivers/can/can_shell.c index c7397869f85..3bb74f9552c 100644 --- a/drivers/can/can_shell.c +++ b/drivers/can/can_shell.c @@ -273,6 +273,7 @@ static int cmd_can_stop(const struct shell *sh, size_t argc, char **argv) static int cmd_can_show(const struct shell *sh, size_t argc, char **argv) { const struct device *dev = device_get_binding(argv[1]); + const struct device *phy; const struct can_timing *timing_min; const struct can_timing *timing_max; struct can_bus_err_cnt err_cnt; @@ -366,6 +367,9 @@ static int cmd_can_show(const struct shell *sh, size_t argc, char **argv) timing_min->prescaler, timing_max->prescaler); } + phy = can_get_transceiver(dev); + shell_print(sh, "transceiver: %s", phy != NULL ? phy->name : "passive/none"); + #ifdef CONFIG_CAN_STATS shell_print(sh, "statistics:"); shell_print(sh, " bit errors: %u", can_stats_get_bit_errors(dev)); From 6cfbb544de052ecf4dc3c8f14952874eb4fffab2 Mon Sep 17 00:00:00 2001 From: Henrik Brix Andersen Date: Wed, 24 Jan 2024 12:32:42 +0100 Subject: [PATCH 2932/3723] doc: release-notes: 3.6: mention new CAN controller API system calls Mention the new CAN controller API system calls in the release notes. Signed-off-by: Henrik Brix Andersen --- doc/releases/release-notes-3.6.rst | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/doc/releases/release-notes-3.6.rst b/doc/releases/release-notes-3.6.rst index 7510a53f547..95cfd3e9824 100644 --- a/doc/releases/release-notes-3.6.rst +++ b/doc/releases/release-notes-3.6.rst @@ -154,6 +154,12 @@ Drivers and Sensors * CAN + * Added system call :c:func:`can_get_mode()` for getting the current operation mode of a CAN + controller. + + * Add system call :c:func:`can_get_transceiver()` for getting the CAN transceiver associated with + a CAN controller. + * Clock control * Renesas R-Car clock control driver now supports Gen4 SoCs From 4c7eb600c694a46b0039970ba0bd0ebe3992cd81 Mon Sep 17 00:00:00 2001 From: Sandip Dalvi Date: Sat, 20 Jan 2024 10:25:47 +0530 Subject: [PATCH 2933/3723] net: wifi: add wifi driver version API Add command to query to WiFi driver/firmware revision. The API is expected to return the firmware revision and driver version as a string, and can be used by the user to determine what revision of the WiFi driver is in use. Signed-off-by: Sandip Dalvi --- include/zephyr/net/wifi_mgmt.h | 28 ++++++++++++++++++++++++++++ subsys/net/l2/wifi/wifi_mgmt.c | 16 ++++++++++++++++ subsys/net/l2/wifi/wifi_shell.c | 24 ++++++++++++++++++++++++ 3 files changed, 68 insertions(+) diff --git a/include/zephyr/net/wifi_mgmt.h b/include/zephyr/net/wifi_mgmt.h index 982184a103b..c287db650cb 100644 --- a/include/zephyr/net/wifi_mgmt.h +++ b/include/zephyr/net/wifi_mgmt.h @@ -83,6 +83,8 @@ enum net_request_wifi_cmd { NET_REQUEST_WIFI_CMD_CHANNEL, /** Disconnect a STA from AP */ NET_REQUEST_WIFI_CMD_AP_STA_DISCONNECT, + /** Get Wi-Fi driver and Firmware versions */ + NET_REQUEST_WIFI_CMD_VERSION, NET_REQUEST_WIFI_CMD_MAX }; @@ -165,6 +167,11 @@ NET_MGMT_DEFINE_REQUEST_HANDLER(NET_REQUEST_WIFI_CHANNEL); NET_MGMT_DEFINE_REQUEST_HANDLER(NET_REQUEST_WIFI_AP_STA_DISCONNECT); +#define NET_REQUEST_WIFI_VERSION \ + (_NET_WIFI_BASE | NET_REQUEST_WIFI_CMD_VERSION) + +NET_MGMT_DEFINE_REQUEST_HANDLER(NET_REQUEST_WIFI_VERSION); + /** Wi-Fi management events */ enum net_event_wifi_cmd { /** Scan results available */ @@ -236,6 +243,14 @@ enum net_event_wifi_cmd { #define NET_EVENT_WIFI_AP_STA_DISCONNECTED \ (_NET_WIFI_EVENT | NET_EVENT_WIFI_CMD_AP_STA_DISCONNECTED) +/** Wi-Fi version */ +struct wifi_version { + /** Driver version */ + const char *drv_version; + /** Firmware version */ + const char *fw_version; +}; + /** * @brief Wi-Fi structure to uniquely identify a band-channel pair */ @@ -824,6 +839,19 @@ struct wifi_mgmt_ops { * @return 0 if ok, < 0 if error */ int (*channel)(const struct device *dev, struct wifi_channel_info *channel); + /** Get Version of WiFi driver and Firmware + * + * The driver that implements the get_version function must not use stack to allocate the + * version information pointers that are returned as params struct members. + * The version pointer parameters should point to a static memory either in ROM (preferred) + * or in RAM. + * + * @param dev Pointer to the device structure for the driver instance + * @param params Version parameters + * + * @return 0 if ok, < 0 if error + */ + int (*get_version)(const struct device *dev, struct wifi_version *params); }; /** Wi-Fi management offload API */ diff --git a/subsys/net/l2/wifi/wifi_mgmt.c b/subsys/net/l2/wifi/wifi_mgmt.c index 2cfe8e25d89..bc844016fa5 100644 --- a/subsys/net/l2/wifi/wifi_mgmt.c +++ b/subsys/net/l2/wifi/wifi_mgmt.c @@ -703,6 +703,22 @@ static int wifi_channel(uint32_t mgmt_request, struct net_if *iface, NET_MGMT_REGISTER_REQUEST_HANDLER(NET_REQUEST_WIFI_CHANNEL, wifi_channel); +static int wifi_get_version(uint32_t mgmt_request, struct net_if *iface, + void *data, size_t len) +{ + const struct device *dev = net_if_get_device(iface); + const struct wifi_mgmt_ops *const wifi_mgmt_api = get_wifi_api(iface); + struct wifi_version *ver_params = data; + + if (wifi_mgmt_api == NULL || wifi_mgmt_api->get_version == NULL) { + return -ENOTSUP; + } + + return wifi_mgmt_api->get_version(dev, ver_params); +} + +NET_MGMT_REGISTER_REQUEST_HANDLER(NET_REQUEST_WIFI_VERSION, wifi_get_version); + #ifdef CONFIG_WIFI_MGMT_RAW_SCAN_RESULTS void wifi_mgmt_raise_raw_scan_result_event(struct net_if *iface, struct wifi_raw_scan_result *raw_scan_result) diff --git a/subsys/net/l2/wifi/wifi_shell.c b/subsys/net/l2/wifi/wifi_shell.c index 75dc59d4fc5..7d56952ecbd 100644 --- a/subsys/net/l2/wifi/wifi_shell.c +++ b/subsys/net/l2/wifi/wifi_shell.c @@ -1818,6 +1818,27 @@ static int cmd_wifi_packet_filter(const struct shell *sh, size_t argc, char *arg return 0; } +static int cmd_wifi_version(const struct shell *sh, size_t argc, char *argv[]) +{ + struct net_if *iface = net_if_get_first_wifi(); + struct wifi_version version = {0}; + + if (argc > 1) { + shell_fprintf(sh, SHELL_WARNING, "Invalid number of arguments\n"); + return -ENOEXEC; + } + + if (net_mgmt(NET_REQUEST_WIFI_VERSION, iface, &version, sizeof(version))) { + shell_fprintf(sh, SHELL_WARNING, "Failed to get Wi-Fi versions\n"); + return -ENOEXEC; + } + + shell_fprintf(sh, SHELL_NORMAL, "Wi-Fi Driver Version: %s\n", version.drv_version); + shell_fprintf(sh, SHELL_NORMAL, "Wi-Fi Firmware Version: %s\n", version.fw_version); + + return 0; +} + SHELL_STATIC_SUBCMD_SET_CREATE(wifi_cmd_ap, SHELL_CMD_ARG(disable, NULL, "Disable Access Point mode.\n", @@ -1871,6 +1892,9 @@ SHELL_STATIC_SUBCMD_SET_CREATE(wifi_twt_ops, ); SHELL_STATIC_SUBCMD_SET_CREATE(wifi_commands, + SHELL_CMD_ARG(version, NULL, "Print Wi-Fi Driver and Firmware versions\n", + cmd_wifi_version, + 1, 0), SHELL_CMD(ap, &wifi_cmd_ap, "Access Point mode commands.\n", NULL), SHELL_CMD_ARG(connect, NULL, "Connect to a Wi-Fi AP\n" From 0d42006dd0f8f42855240eecb0cdc1e9f5708f33 Mon Sep 17 00:00:00 2001 From: Jukka Rissanen Date: Thu, 18 Jan 2024 14:58:30 +0200 Subject: [PATCH 2934/3723] boards: mps2_an385: Re-enable networking tests This reverts commit 6a3612666eb35223d2732d495e3f40e9e182535d "boards: mps2_an385: Exclude platform from networking tests" This would have found the issue described in #67762 where a network test was failing because of wrong section placement. All the simulated environments (qemu_x86 and native_sim) used in network testing missed this problem, but could have easily found if network tests would have been run in mps2_an385. Signed-off-by: Jukka Rissanen --- boards/arm/mps2_an385/mps2_an385.yaml | 2 -- 1 file changed, 2 deletions(-) diff --git a/boards/arm/mps2_an385/mps2_an385.yaml b/boards/arm/mps2_an385/mps2_an385.yaml index fec9dfc0fa8..0236f2a137d 100644 --- a/boards/arm/mps2_an385/mps2_an385.yaml +++ b/boards/arm/mps2_an385/mps2_an385.yaml @@ -13,6 +13,4 @@ supported: - gpio testing: default: true - ignore_tags: - - net vendor: arm From 032451994a31437f357debd52ec5a7e64acdbb04 Mon Sep 17 00:00:00 2001 From: Patryk Kuniecki Date: Mon, 4 Dec 2023 22:08:21 +0100 Subject: [PATCH 2935/3723] scripts: tests: Harness Adding more tests for twister harness. Signed-off-by: Patryk Kuniecki --- scripts/tests/twister/test_harness.py | 405 ++++++++++++++++++++++++++ 1 file changed, 405 insertions(+) diff --git a/scripts/tests/twister/test_harness.py b/scripts/tests/twister/test_harness.py index f0697efc43d..925a738b8bc 100644 --- a/scripts/tests/twister/test_harness.py +++ b/scripts/tests/twister/test_harness.py @@ -10,12 +10,21 @@ import sys import os import pytest +import re +import logging as logger ZEPHYR_BASE = os.getenv("ZEPHYR_BASE") sys.path.insert(0, os.path.join(ZEPHYR_BASE, "scripts/pylib/twister")) from twisterlib.harness import Gtest, Bsim +from twisterlib.harness import Harness +from twisterlib.harness import Robot +from twisterlib.harness import Test from twisterlib.testinstance import TestInstance +from twisterlib.harness import Console +from twisterlib.harness import Pytest +from twisterlib.harness import PytestHarnessException +from twisterlib.harness import HarnessImporter GTEST_START_STATE = " RUN " GTEST_PASS_STATE = " OK " @@ -34,6 +43,402 @@ def process_logs(harness, logs): harness.handle(line) +TEST_DATA_1 = [('RunID: 12345', False, False, False, None, True), + ('PROJECT EXECUTION SUCCESSFUL', False, False, False, 'passed', False), + ('PROJECT EXECUTION SUCCESSFUL', True, False, False, 'failed', False), + ('PROJECT EXECUTION FAILED', False, False, False, 'failed', False), + ('ZEPHYR FATAL ERROR', False, True, False, None, False), + ('GCOV_COVERAGE_DUMP_START', None, None, True, None, False), + ('GCOV_COVERAGE_DUMP_END', None, None, False, None, False),] +@pytest.mark.parametrize( + "line, fault, fail_on_fault, cap_cov, exp_stat, exp_id", + TEST_DATA_1, + ids=["match id", "passed passed", "passed failed", "failed failed", "fail on fault", "GCOV START", "GCOV END"] +) +def test_harness_process_test(line, fault, fail_on_fault, cap_cov, exp_stat, exp_id): + #Arrange + harness = Harness() + harness.run_id = 12345 + harness.state = None + harness.fault = fault + harness.fail_on_fault = fail_on_fault + + #Act + harness.process_test(line) + + #Assert + assert harness.matched_run_id == exp_id + assert harness.state == exp_stat + assert harness.capture_coverage == cap_cov + + +def test_robot_configure(): + #Arrange + mock_platform = mock.Mock() + mock_platform.name = "mock_platform" + + mock_testsuite = mock.Mock(id = 'id', testcases = []) + mock_testsuite.name = "mock_testsuite" + mock_testsuite.harness_config = {} + + instance = TestInstance(testsuite=mock_testsuite, platform=mock_platform, outdir="") + instance.testsuite.harness_config = { + 'robot_test_path': '/path/to/robot/test' + } + robot_harness = Robot() + + #Act + robot_harness.configure(instance) + + #Assert + assert robot_harness.instance == instance + assert robot_harness.path == '/path/to/robot/test' + + +def test_robot_handle(): + #Arrange + mock_platform = mock.Mock() + mock_platform.name = "mock_platform" + + mock_testsuite = mock.Mock(id = 'id', testcases = []) + mock_testsuite.name = "mock_testsuite" + mock_testsuite.harness_config = {} + + instance = TestInstance(testsuite=mock_testsuite, platform=mock_platform, outdir="") + + handler = Robot() + handler.instance = instance + handler.id = 'test_case_1' + + line = 'Test case passed' + + #Act + handler.handle(line) + tc = instance.get_case_or_create('test_case_1') + + #Assert + assert instance.state == "passed" + assert tc.status == "passed" + + +TEST_DATA_2 = [("", 0, "passed"), ("Robot test failure: sourcedir for mock_platform", 1, "failed"),] +@pytest.mark.parametrize( + "exp_out, returncode, expected_status", + TEST_DATA_2, + ids=["passed", "failed"] +) +def test_robot_run_robot_test(caplog, exp_out, returncode, expected_status): + # Arrange + command = "command" + + handler = mock.Mock() + handler.sourcedir = "sourcedir" + handler.log = "handler.log" + + path = "path" + + mock_platform = mock.Mock() + mock_platform.name = "mock_platform" + + mock_testsuite = mock.Mock(id = 'id', testcases = [mock.Mock()]) + mock_testsuite.name = "mock_testsuite" + mock_testsuite.harness_config = {} + + instance = TestInstance(testsuite=mock_testsuite, platform=mock_platform, outdir="") + instance.build_dir = "build_dir" + + open_mock = mock.mock_open() + + robot = Robot() + robot.path = path + robot.instance = instance + proc_mock = mock.Mock( + returncode = returncode, + communicate = mock.Mock(return_value=(b"output", None)) + ) + popen_mock = mock.Mock(return_value = mock.Mock( + __enter__ = mock.Mock(return_value = proc_mock), + __exit__ = mock.Mock() + )) + + # Act + with mock.patch("subprocess.Popen", popen_mock) as mock.mock_popen, \ + mock.patch("builtins.open", open_mock): + robot.run_robot_test(command,handler) + + + # Assert + assert instance.status == expected_status + open_mock().write.assert_called_once_with("output") + assert exp_out in caplog.text + + +TEST_DATA_3 = [('one_line', None), ('multi_line', 2),] +@pytest.mark.parametrize( + "type, num_patterns", + TEST_DATA_3, + ids=["one line", "multi line"] +) +def test_console_configure(type, num_patterns): + #Arrange + mock_platform = mock.Mock() + mock_platform.name = "mock_platform" + + mock_testsuite = mock.Mock(id = 'id', testcases = []) + mock_testsuite.name = "mock_testsuite" + mock_testsuite.harness_config = {} + + instance = TestInstance(testsuite=mock_testsuite, platform=mock_platform, outdir="") + instance.testsuite.harness_config = { + 'type': type, + 'regex': ['pattern1', 'pattern2'] + } + console = Console() + + #Act + console.configure(instance) + + #Assert + if num_patterns == 2: + assert len(console.patterns) == num_patterns + assert [pattern.pattern for pattern in console.patterns] == ['pattern1', 'pattern2'] + else: + assert console.pattern.pattern == 'pattern1' + + +TEST_DATA_4 = [("one_line", True, "passed", "line", False, False), + ("multi_line", True, "passed", "line", False, False), + ("multi_line", False, "passed", "line", False, False), + ("invalid_type", False, None, "line", False, False), + ("invalid_type", False, None, "ERROR", True, False), + ("invalid_type", False, None, "COVERAGE_START", False, True), + ("invalid_type", False, None, "COVERAGE_END", False, False)] +@pytest.mark.parametrize( + "line_type, ordered_val, exp_state, line, exp_fault, exp_capture", + TEST_DATA_4, + ids=["one line", "multi line ordered", "multi line not ordered", "logger error", "fail on fault", "GCOV START", "GCOV END"] +) +def test_console_handle(line_type, ordered_val, exp_state, line, exp_fault, exp_capture): + mock_platform = mock.Mock() + mock_platform.name = "mock_platform" + + mock_testsuite = mock.Mock(id = 'id', testcases = []) + mock_testsuite.name = "mock_testsuite" + mock_testsuite.harness_config = {} + + instance = TestInstance(testsuite=mock_testsuite, platform=mock_platform, outdir="") + + console = Console() + console.instance = instance + console.type = line_type + console.patterns = [re.compile("pattern1"), re.compile("pattern2")] + console.pattern = re.compile("pattern") + console.patterns_expected = 0 + console.state = None + console.fail_on_fault = True + console.FAULT = "ERROR" + console.GCOV_START = "COVERAGE_START" + console.GCOV_END = "COVERAGE_END" + console.record = {"regex": "RESULT: (.*)"} + console.fieldnames = [] + console.recording = [] + console.regex = ["regex1", "regex2"] + console.id = "test_case_1" + + instance.get_case_or_create('test_case_1') + instance.testsuite.id = "test_suite_1" + + console.next_pattern = 0 + console.ordered = ordered_val + line = line + console.handle(line) + + line1 = "pattern1" + line2 = "pattern2" + console.handle(line1) + console.handle(line2) + assert console.state == exp_state + with pytest.raises(Exception): + console.handle(line) + assert logger.error.called + assert console.fault == exp_fault + assert console.capture_coverage == exp_capture + + +TEST_DATA_5 = [("serial_pty", 0), (None, 0),(None, 1)] +@pytest.mark.parametrize( + "pty_value, hardware_value", + TEST_DATA_5, + ids=["hardware pty", "hardware", "non hardware"] +) + +def test_pytest__generate_parameters_for_hardware(pty_value, hardware_value): + #Arrange + mock_platform = mock.Mock() + mock_platform.name = "mock_platform" + + mock_testsuite = mock.Mock(id = 'id', testcases = []) + mock_testsuite.name = "mock_testsuite" + mock_testsuite.harness_config = {} + + instance = TestInstance(testsuite=mock_testsuite, platform=mock_platform, outdir="") + + handler = mock.Mock() + handler.instance = instance + + hardware = mock.Mock() + hardware.serial_pty = pty_value + hardware.serial = 'serial' + hardware.baud = 115200 + hardware.runner = "runner" + + options = handler.options + options.west_flash = "args" + + hardware.probe_id = '123' + hardware.product = 'product' + hardware.pre_script = 'pre_script' + hardware.post_flash_script = 'post_flash_script' + hardware.post_script = 'post_script' + + pytest_test = Pytest() + + #Act + if hardware_value == 0: + handler.get_hardware.return_value = hardware + command = pytest_test._generate_parameters_for_hardware(handler) + else: + handler.get_hardware.return_value = None + + #Assert + if hardware_value == 1: + with pytest.raises(PytestHarnessException) as exinfo: + pytest_test._generate_parameters_for_hardware(handler) + assert str(exinfo.value) == 'Hardware is not available' + else: + assert '--device-type=hardware' in command + if pty_value == "serial_pty": + assert '--device-serial-pty=serial_pty' in command + else: + assert '--device-serial=serial' in command + assert '--device-serial-baud=115200' in command + assert '--runner=runner' in command + assert '--west-flash-extra-args=args' in command + assert '--device-id=123' in command + assert '--device-product=product' in command + assert '--pre-script=pre_script' in command + assert '--post-flash-script=post_flash_script' in command + assert '--post-script=post_script' in command + + +def test__update_command_with_env_dependencies(): + cmd = ['cmd'] + pytest_test = Pytest() + mock.patch.object(Pytest, 'PYTEST_PLUGIN_INSTALLED', False) + + # Act + result_cmd, _ = pytest_test._update_command_with_env_dependencies(cmd) + + # Assert + assert result_cmd == ['cmd', '-p', 'twister_harness.plugin'] + + +def test_pytest_run(caplog): + # Arrange + timeout = 10 + cmd=['command'] + exp_out = 'Handling of handler handler_type not implemented yet' + + harness = Pytest() + harness = mock.create_autospec(harness) + + mock.patch.object(Pytest, 'generate_command', return_value=cmd) + mock.patch.object(Pytest, 'run_command') + + mock_platform = mock.Mock() + mock_platform.name = "mock_platform" + + mock_testsuite = mock.Mock(id = 'id', testcases = [], source_dir = 'source_dir', harness_config = {}) + mock_testsuite.name = "mock_testsuite" + mock_testsuite.harness_config = {} + + handler = mock.Mock( + options = mock.Mock(verbose= 0), + type_str = 'handler_type' + ) + instance = TestInstance(testsuite=mock_testsuite, platform=mock_platform, outdir="") + instance.handler = handler + + test_obj = Pytest() + test_obj.configure(instance) + + # Act + test_obj.pytest_run(timeout) + # Assert + assert test_obj.state == 'failed' + assert exp_out in caplog.text + + +TEST_DATA_6 = [(None), ('Test')] +@pytest.mark.parametrize( + "name", + TEST_DATA_6, + ids=["no name", "provided name"] +) +def test_get_harness(name): + #Arrange + harnessimporter = HarnessImporter() + harness_name = name + + #Act + harness_class = harnessimporter.get_harness(harness_name) + + #Assert + assert isinstance(harness_class, Test) + + +TEST_DATA_7 = [("", "Running TESTSUITE suite_name", ['suite_name'], None, True, None), + ("", "START - test_testcase", [], "started", True, None), + ("", "PASS - test_example in 0 seconds", [], "passed", True, None), + ("", "SKIP - test_example in 0 seconds", [], "skipped", True, None), + ("", "FAIL - test_example in 0 seconds", [], "failed", True, None), + ("not a ztest and no state for test_id", "START - test_testcase", [], "passed", False, "passed"), + ("not a ztest and no state for test_id", "START - test_testcase", [], "failed", False, "failed")] +@pytest.mark.parametrize( + "exp_out, line, exp_suite_name, exp_status, ztest, state", + TEST_DATA_7, + ids=['testsuite', 'testcase', 'pass', 'skip', 'failed', 'ztest pass', 'ztest fail'] +) +def test_test_handle(caplog, exp_out, line, exp_suite_name, exp_status, ztest, state): + # Arrange + line = line + mock_platform = mock.Mock() + mock_platform.name = "mock_platform" + + mock_testsuite = mock.Mock(id = 'id', testcases = []) + mock_testsuite.name = "mock_testsuite" + mock_testsuite.harness_config = {} + + instance = TestInstance(testsuite=mock_testsuite, platform=mock_platform, outdir="") + + test_obj = Test() + test_obj.configure(instance) + test_obj.id = "test_id" + test_obj.ztest = ztest + test_obj.state = state + test_obj.id = 'test_id' + #Act + test_obj.handle(line) + + # Assert + assert test_obj.detected_suite_names == exp_suite_name + assert exp_out in caplog.text + if not "Running" in line and exp_out == "": + assert test_obj.instance.testcases[0].status == exp_status + if "ztest" in exp_out: + assert test_obj.instance.testcases[1].status == exp_status + + @pytest.fixture def gtest(tmp_path): mock_platform = mock.Mock() From fc26fd5a15391e137a14c1485af19cb10261ad25 Mon Sep 17 00:00:00 2001 From: Christopher Friedt Date: Fri, 26 Jan 2024 09:02:17 -0500 Subject: [PATCH 2936/3723] posix: pthread: initialize t and c pointers to NULL * initialize posix_thread and __pthread_cleanup ptrs to NULL * check ret is zero before finalizing a thread in pthread_cancel() Signed-off-by: Christopher Friedt --- lib/posix/pthread.c | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/lib/posix/pthread.c b/lib/posix/pthread.c index 99441694fe9..c4a1e490a33 100644 --- a/lib/posix/pthread.c +++ b/lib/posix/pthread.c @@ -216,7 +216,7 @@ static inline void __z_pthread_cleanup_init(struct __pthread_cleanup *c, void (* void __z_pthread_cleanup_push(void *cleanup[3], void (*routine)(void *arg), void *arg) { - struct posix_thread *t; + struct posix_thread *t = NULL; struct __pthread_cleanup *const c = (struct __pthread_cleanup *)cleanup; K_SPINLOCK(&pthread_pool_lock) { @@ -233,8 +233,8 @@ void __z_pthread_cleanup_push(void *cleanup[3], void (*routine)(void *arg), void void __z_pthread_cleanup_pop(int execute) { sys_snode_t *node; - struct __pthread_cleanup *c; - struct posix_thread *t; + struct __pthread_cleanup *c = NULL; + struct posix_thread *t = NULL; K_SPINLOCK(&pthread_pool_lock) { t = to_posix_thread(pthread_self()); @@ -689,7 +689,7 @@ int pthread_cancel(pthread_t pthread) int ret = 0; bool cancel_state = PTHREAD_CANCEL_ENABLE; bool cancel_type = PTHREAD_CANCEL_DEFERRED; - struct posix_thread *t; + struct posix_thread *t = NULL; K_SPINLOCK(&pthread_pool_lock) { t = to_posix_thread(pthread); @@ -709,7 +709,7 @@ int pthread_cancel(pthread_t pthread) cancel_type = t->attr.canceltype; } - if (cancel_state == PTHREAD_CANCEL_ENABLE && + if (ret == 0 && cancel_state == PTHREAD_CANCEL_ENABLE && cancel_type == PTHREAD_CANCEL_ASYNCHRONOUS) { posix_thread_finalize(t, PTHREAD_CANCELED); } @@ -725,8 +725,8 @@ int pthread_cancel(pthread_t pthread) int pthread_setschedparam(pthread_t pthread, int policy, const struct sched_param *param) { int ret = 0; - int new_prio; - struct posix_thread *t; + int new_prio = K_LOWEST_APPLICATION_THREAD_PRIO; + struct posix_thread *t = NULL; if (param == NULL || !valid_posix_policy(policy) || !is_posix_policy_prio_valid(param->sched_priority, policy)) { @@ -892,7 +892,7 @@ void pthread_exit(void *retval) int pthread_join(pthread_t pthread, void **status) { int ret = 0; - struct posix_thread *t; + struct posix_thread *t = NULL; if (pthread == pthread_self()) { LOG_ERR("Pthread attempted to join itself (%x)", pthread); From c9c9054bfdf814f446c074dbb6c503cf7445d57e Mon Sep 17 00:00:00 2001 From: Erwan Gouriou Date: Thu, 11 May 2023 11:22:41 +0200 Subject: [PATCH 2937/3723] boards: nucleo_wba52cg: Enable flash and debug using OpenOCD OpenOCD can now be used to flash and debug nucleo_wba52cg. However it required use of STMicroelectronics OpenOCD fork. Add instructions on how to use it. Signed-off-by: Erwan Gouriou --- boards/arm/nucleo_wba52cg/board.cmake | 4 ++++ boards/arm/nucleo_wba52cg/support/openocd.cfg | 2 -- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/boards/arm/nucleo_wba52cg/board.cmake b/boards/arm/nucleo_wba52cg/board.cmake index 50f543d4e6a..27c19f19b00 100644 --- a/boards/arm/nucleo_wba52cg/board.cmake +++ b/boards/arm/nucleo_wba52cg/board.cmake @@ -1,3 +1,7 @@ board_runner_args(stm32cubeprogrammer "--port=swd" "--reset-mode=hw") +set(OPENOCD "/local/mcu/tools/openocd/src/openocd" CACHE FILEPATH "" FORCE) +set(OPENOCD_DEFAULT_PATH /local/mcu/tools/openocd/tcl) + include(${ZEPHYR_BASE}/boards/common/stm32cubeprogrammer.board.cmake) +include(${ZEPHYR_BASE}/boards/common/openocd.board.cmake) diff --git a/boards/arm/nucleo_wba52cg/support/openocd.cfg b/boards/arm/nucleo_wba52cg/support/openocd.cfg index 10647e20ad8..7c785bec412 100644 --- a/boards/arm/nucleo_wba52cg/support/openocd.cfg +++ b/boards/arm/nucleo_wba52cg/support/openocd.cfg @@ -22,5 +22,3 @@ set CLOCK_FREQ 8000 reset_config srst_only srst_nogate source [find target/stm32wbax.cfg] - -gdb_memory_map disable From 9c7c63eb136018a5ae7b05dd6e45cf6d0553ab4b Mon Sep 17 00:00:00 2001 From: Erwan Gouriou Date: Fri, 6 Oct 2023 14:22:09 +0200 Subject: [PATCH 2938/3723] west.yml: hal_stm32: Use SW/JTAG signals description SW/JTAG signals description are useful when we don't need them. Signed-off-by: Erwan Gouriou --- west.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/west.yml b/west.yml index 0c4693ddf4f..548d063351c 100644 --- a/west.yml +++ b/west.yml @@ -229,7 +229,7 @@ manifest: groups: - hal - name: hal_stm32 - revision: 22925907a6faeb601fc9a0d8cbb65c4b26d38043 + revision: 60c9634f61c697e1c310ec648d33529712806069 path: modules/hal/stm32 groups: - hal From 3d0c391ff223d3ce55ec3f8057d08a82008bcd65 Mon Sep 17 00:00:00 2001 From: Erwan Gouriou Date: Wed, 27 Sep 2023 17:58:43 +0200 Subject: [PATCH 2939/3723] soc: stm32: PM: Disable jtag port pins if no debug At chip startup, jtag pins are configured by default to enable debug. This configuration adds consumption and when using PM profile, we can save ~40uA by resetting this configuration and setting pins to analog mode. Signed-off-by: Erwan Gouriou --- dts/bindings/gpio/swj-connector.yaml | 5 ++++ soc/arm/st_stm32/common/CMakeLists.txt | 4 +++ soc/arm/st_stm32/common/Kconfig.soc | 8 ++++++ soc/arm/st_stm32/common/pm_debug_swj.c | 40 ++++++++++++++++++++++++++ 4 files changed, 57 insertions(+) create mode 100644 dts/bindings/gpio/swj-connector.yaml create mode 100644 soc/arm/st_stm32/common/pm_debug_swj.c diff --git a/dts/bindings/gpio/swj-connector.yaml b/dts/bindings/gpio/swj-connector.yaml new file mode 100644 index 00000000000..1ced649632b --- /dev/null +++ b/dts/bindings/gpio/swj-connector.yaml @@ -0,0 +1,5 @@ +description: Serial Wire - JTAG Connector + +compatible: "swj-connector" + +include: pinctrl-device.yaml diff --git a/soc/arm/st_stm32/common/CMakeLists.txt b/soc/arm/st_stm32/common/CMakeLists.txt index 70dd8c865c9..af898951cc5 100644 --- a/soc/arm/st_stm32/common/CMakeLists.txt +++ b/soc/arm/st_stm32/common/CMakeLists.txt @@ -8,3 +8,7 @@ zephyr_sources_ifdef(CONFIG_STM32_BACKUP_SRAM stm32_backup_sram.c) zephyr_linker_sources_ifdef(CONFIG_STM32_BACKUP_SRAM SECTIONS stm32_backup_sram.ld) zephyr_sources(soc_config.c) + +if (NOT CONFIG_DEBUG AND CONFIG_PM) + zephyr_sources_ifdef(CONFIG_DT_HAS_SWJ_CONNECTOR_ENABLED pm_debug_swj.c) +endif() diff --git a/soc/arm/st_stm32/common/Kconfig.soc b/soc/arm/st_stm32/common/Kconfig.soc index 8e98514a79e..2fd9084cc55 100644 --- a/soc/arm/st_stm32/common/Kconfig.soc +++ b/soc/arm/st_stm32/common/Kconfig.soc @@ -21,6 +21,14 @@ config USE_STM32_ASSERT help Enable asserts in STM32Cube HAL and LL drivers. +config SWJ_ANALOG_PRIORITY + int "SWJ DP port to analog routine initialization priority" + default 49 + help + Initialization priority of the routine within the PRE_KERNEL1 level. + This priority must be greater than GPIO_INIT_PRIORITY and lower than + UART_INIT_PRIORITY. + choice POWER_SUPPLY_CHOICE prompt "STM32 power supply configuration" default POWER_SUPPLY_LDO diff --git a/soc/arm/st_stm32/common/pm_debug_swj.c b/soc/arm/st_stm32/common/pm_debug_swj.c new file mode 100644 index 00000000000..5897670e5f6 --- /dev/null +++ b/soc/arm/st_stm32/common/pm_debug_swj.c @@ -0,0 +1,40 @@ +/* + * Copyright (c) 2023 STMicroelectronics + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include +#include + +#define SWJ_NODE DT_NODELABEL(swj_port) + +PINCTRL_DT_DEFINE(SWJ_NODE); + +const struct pinctrl_dev_config *swj_pcfg = PINCTRL_DT_DEV_CONFIG_GET(SWJ_NODE); + +/* + * Serial Wire / JTAG port pins are enabled as part of SoC default configuration. + * When debug access is not needed and in case power consumption performance is + * expected, configure matching pins to analog in order to save power. + */ + +static int swj_to_analog(void) +{ + int err; + + /* Set Serial Wire / JTAG port pins to analog mode */ + err = pinctrl_apply_state(swj_pcfg, PINCTRL_STATE_SLEEP); + if (err < 0) { + __ASSERT(0, "SWJ pinctrl setup failed"); + return err; + } + + return 0; +} + +/* Run this routine as the earliest pin configuration in the target, + * to avoid potential conflicts with devices accessing SWJ-DG pins for + * their own needs. + */ +SYS_INIT(swj_to_analog, PRE_KERNEL_1, CONFIG_SWJ_ANALOG_PRIORITY); From b772e366c9a416b9f892c3c933181fa92e0edd18 Mon Sep 17 00:00:00 2001 From: Erwan Gouriou Date: Wed, 4 Oct 2023 09:27:47 +0200 Subject: [PATCH 2940/3723] dts: stm32u5: Add SW/JTAG debug port node Provide jtag port pins description, so they can be used to be set in analog mode when not required to save power (around 40uA saved in total). Signed-off-by: Erwan Gouriou --- dts/arm/st/u5/stm32u5.dtsi | 11 +++++++++++ dts/arm/st/wba/stm32wba.dtsi | 10 ++++++++++ 2 files changed, 21 insertions(+) diff --git a/dts/arm/st/u5/stm32u5.dtsi b/dts/arm/st/u5/stm32u5.dtsi index f721617ef5b..43f4830bf72 100644 --- a/dts/arm/st/u5/stm32u5.dtsi +++ b/dts/arm/st/u5/stm32u5.dtsi @@ -840,6 +840,17 @@ status = "disabled"; }; }; + + }; + + swj_port: swj_port { + compatible = "swj-connector"; + pinctrl-0 = <&debug_jtms_swdio_pa13 &debug_jtck_swclk_pa14 + &debug_jtdi_pa15 &debug_jtdo_swo_pb3 + &debug_jtrst_pb4>; + pinctrl-1 = <&analog_pa13 &analog_pa14 &analog_pa15 + &analog_pb3 &analog_pb4>; + pinctrl-names = "default", "sleep"; }; die_temp: dietemp { diff --git a/dts/arm/st/wba/stm32wba.dtsi b/dts/arm/st/wba/stm32wba.dtsi index 6946f23f64e..2d00be8ef53 100644 --- a/dts/arm/st/wba/stm32wba.dtsi +++ b/dts/arm/st/wba/stm32wba.dtsi @@ -462,6 +462,16 @@ }; }; + swj_port: swj_port { + compatible = "swj-connector"; + pinctrl-0 = <&debug_jtms_swdio_pa13 &debug_jtck_swclk_pa14 + &debug_jtdi_pa15 &debug_jtdo_swo_pb3 + &debug_jtrst_pb4>; + pinctrl-1 = <&analog_pa13 &analog_pa14 &analog_pa15 + &analog_pb3 &analog_pb4>; + pinctrl-names = "default", "sleep"; + }; + smbus1: smbus1 { compatible = "st,stm32-smbus"; #address-cells = <1>; From e2f471162973381ffe8c1dd451e2e95e14026a73 Mon Sep 17 00:00:00 2001 From: Chaitanya Tata Date: Mon, 18 Sep 2023 15:48:45 +0530 Subject: [PATCH 2941/3723] hostap: Add Zephyr support Add new files from hostap to Zephyr build. Add wifi mgmt thread that communicates with supplicant. Signed-off-by: Chaitanya Tata Signed-off-by: Jukka Rissanen --- modules/hostap/CMakeLists.txt | 293 ++++++++++++++++- modules/hostap/Kconfig | 129 +++++++- modules/hostap/src/supp_api.c | 549 +++++++++++++++++++++++++++++++ modules/hostap/src/supp_api.h | 111 +++++++ modules/hostap/src/supp_events.c | 214 ++++++++++++ modules/hostap/src/supp_events.h | 142 ++++++++ modules/hostap/src/supp_main.c | 546 ++++++++++++++++++++++++++++++ modules/hostap/src/supp_main.h | 19 ++ modules/hostap/src/wpa_cli.c | 38 +++ 9 files changed, 2031 insertions(+), 10 deletions(-) create mode 100644 modules/hostap/src/supp_api.c create mode 100644 modules/hostap/src/supp_api.h create mode 100644 modules/hostap/src/supp_events.c create mode 100644 modules/hostap/src/supp_events.h create mode 100644 modules/hostap/src/supp_main.c create mode 100644 modules/hostap/src/supp_main.h create mode 100644 modules/hostap/src/wpa_cli.c diff --git a/modules/hostap/CMakeLists.txt b/modules/hostap/CMakeLists.txt index ed6b8185873..aefb9acda9a 100644 --- a/modules/hostap/CMakeLists.txt +++ b/modules/hostap/CMakeLists.txt @@ -15,10 +15,6 @@ set(HOSTAP_SRC_BASE ${HOSTAP_BASE}/src) set(CMAKE_EXE_LINKER_FLAGS "--specs=nosys.specs -lnosys") set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -DMISSING_SYSCALL_NAMES") -zephyr_compile_definitions( - CONFIG_ZEPHYR -) - zephyr_include_directories( ${HOSTAP_BASE}/ ${WIFI_NM_WPA_SUPPLICANT_BASE}/ @@ -34,6 +30,12 @@ zephyr_library_compile_definitions( CONFIG_NO_RANDOM_POOL CONFIG_NO_WPA CONFIG_NO_PBKDF2 + CONFIG_SHA256 + CONFIG_WPA_S_ZEPHYR_L2_WIFI_MGMT + CONFIG_CTRL_IFACE_ZEPHYR +# CONFIG_MBO +# CONFIG_WNM + CONFIG_SUITEB192 ) zephyr_library_include_directories( @@ -44,6 +46,14 @@ zephyr_library_include_directories( ${HOSTAP_BASE}/src ${ZEPHYR_BASE}/include ${ZEPHYR_BASE}/include/net + ) + +zephyr_library_compile_definitions_ifndef(CONFIG_WIFI_NM_WPA_SUPPLICANT_CRYPTO + CONFIG_NO_PBKDF2 +) + +zephyr_library_compile_definitions_ifdef(CONFIG_WIFI_NM_WPA_SUPPLICANT_NO_DEBUG + CONFIG_NO_STDOUT_DEBUG ) zephyr_library_sources( @@ -64,6 +74,8 @@ zephyr_library_sources( ${HOSTAP_SRC_BASE}/utils/wpa_debug_zephyr.c ${HOSTAP_SRC_BASE}/crypto/crypto_none.c ${HOSTAP_SRC_BASE}/crypto/tls_none.c + ${HOSTAP_SRC_BASE}/l2_packet/l2_packet_zephyr.c + ${HOSTAP_SRC_BASE}/drivers/driver_zephyr.c ${WIFI_NM_WPA_SUPPLICANT_BASE}/config.c ${WIFI_NM_WPA_SUPPLICANT_BASE}/notify.c @@ -77,8 +89,279 @@ zephyr_library_sources( ${WIFI_NM_WPA_SUPPLICANT_BASE}/scan.c ${WIFI_NM_WPA_SUPPLICANT_BASE}/ctrl_iface.c + ${WIFI_NM_WPA_SUPPLICANT_BASE}/bss.c + ${WIFI_NM_WPA_SUPPLICANT_BASE}/sme.c + ${WIFI_NM_WPA_SUPPLICANT_BASE}/wpa_supplicant.c + ${WIFI_NM_WPA_SUPPLICANT_BASE}/events.c + ${WIFI_NM_WPA_SUPPLICANT_BASE}/robust_av.c +# ${WIFI_NM_WPA_SUPPLICANT_BASE}/mbo.c +# ${WIFI_NM_WPA_SUPPLICANT_BASE}/wnm_sta.c + ${WIFI_NM_WPA_SUPPLICANT_BASE}/wpa_cli_cmds.c + ${WIFI_NM_WPA_SUPPLICANT_BASE}/ctrl_iface_zephyr.c + ${WIFI_NM_WPA_SUPPLICANT_BASE}/wpa_cli_zephyr.c + # Zephyr specific files (glue code) - # TBD + src/supp_main.c + src/supp_api.c + src/supp_events.c +) + +zephyr_library_sources_ifdef(CONFIG_WPA_CLI + src/wpa_cli.c +) + +zephyr_library_sources_ifdef(CONFIG_WIFI_NM_WPA_SUPPLICANT_AP + ${WIFI_NM_WPA_SUPPLICANT_BASE}/ap.c + ${HOSTAP_SRC_BASE}/ap/ap_config.c + ${HOSTAP_SRC_BASE}/ap/ap_drv_ops.c + ${HOSTAP_SRC_BASE}/ap/ap_list.c + ${HOSTAP_SRC_BASE}/ap/ap_mlme.c + ${HOSTAP_SRC_BASE}/ap/authsrv.c + ${HOSTAP_SRC_BASE}/ap/beacon.c + ${HOSTAP_SRC_BASE}/ap/bss_load.c + ${HOSTAP_SRC_BASE}/ap/dfs.c + ${HOSTAP_SRC_BASE}/ap/drv_callbacks.c + ${HOSTAP_SRC_BASE}/ap/eap_user_db.c + ${HOSTAP_SRC_BASE}/ap/hostapd.c + ${HOSTAP_SRC_BASE}/ap/hw_features.c + ${HOSTAP_SRC_BASE}/ap/ieee802_11_auth.c + ${HOSTAP_SRC_BASE}/ap/ieee802_11.c + ${HOSTAP_SRC_BASE}/ap/ieee802_11_he.c + ${HOSTAP_SRC_BASE}/ap/ieee802_11_ht.c + ${HOSTAP_SRC_BASE}/ap/ieee802_11_shared.c + ${HOSTAP_SRC_BASE}/ap/ieee802_11_vht.c + ${HOSTAP_SRC_BASE}/ap/ieee802_1x.c + ${HOSTAP_SRC_BASE}/ap/neighbor_db.c + ${HOSTAP_SRC_BASE}/ap/p2p_hostapd.c + ${HOSTAP_SRC_BASE}/ap/pmksa_cache_auth.c + ${HOSTAP_SRC_BASE}/ap/preauth_auth.c + ${HOSTAP_SRC_BASE}/ap/rrm.c + ${HOSTAP_SRC_BASE}/ap/sta_info.c + ${HOSTAP_SRC_BASE}/ap/tkip_countermeasures.c + ${HOSTAP_SRC_BASE}/ap/utils.c + ${HOSTAP_SRC_BASE}/ap/wmm.c + + ${HOSTAP_SRC_BASE}/ap/wpa_auth.c + ${HOSTAP_SRC_BASE}/ap/wpa_auth_ie.c + ${HOSTAP_SRC_BASE}/ap/wpa_auth_ft.c + ${HOSTAP_SRC_BASE}/ap/wpa_auth_glue.c + + ${HOSTAP_SRC_BASE}/eap_common/eap_common.c + ${HOSTAP_SRC_BASE}/eap_server/eap_server.c + ${HOSTAP_SRC_BASE}/eap_server/eap_server_identity.c + ${HOSTAP_SRC_BASE}/eap_server/eap_server_methods.c + ${HOSTAP_SRC_BASE}/eapol_auth/eapol_auth_sm.c +) + +zephyr_library_compile_definitions_ifdef(CONFIG_WIFI_NM_WPA_SUPPLICANT_AP + CONFIG_AP + CONFIG_NO_RADIUS + CONFIG_NO_VLAN + CONFIG_NO_ACCOUNTING + CONFIG_NEED_AP_MLME + CONFIG_IEEE80211AX + CONFIG_EAP_SERVER + CONFIG_EAP_SERVER_IDENTITY +) + + +zephyr_library_sources_ifndef(CONFIG_WIFI_NM_WPA_SUPPLICANT_CRYPTO + ${HOSTAP_SRC_BASE}/crypto/crypto_none.c + ${HOSTAP_SRC_BASE}/crypto/tls_none.c +) + +zephyr_library_compile_definitions_ifndef(CONFIG_WIFI_NM_WPA_SUPPLICANT_CRYPTO + CONFIG_NO_WPA + CONFIG_CRYPTO_INTERNAL +) + +zephyr_library_compile_definitions_ifdef(CONFIG_WIFI_NM_WPA_SUPPLICANT_CRYPTO + CONFIG_WEP +) + +zephyr_library_sources_ifdef(CONFIG_WIFI_NM_WPA_SUPPLICANT_CRYPTO + ${HOSTAP_SRC_BASE}/common/wpa_common.c + ${HOSTAP_SRC_BASE}/rsn_supp/wpa.c + ${HOSTAP_SRC_BASE}/rsn_supp/preauth.c + ${HOSTAP_SRC_BASE}/rsn_supp/wpa_ie.c + +# ${HOSTAP_SRC_BASE}/crypto/crypto_mbedtls-bignum.c +# ${HOSTAP_SRC_BASE}/crypto/crypto_mbedtls-ec.c +# ${HOSTAP_SRC_BASE}/crypto/crypto_mbedtls.c +# ${HOSTAP_SRC_BASE}/crypto/tls_mbedtls.c + ${HOSTAP_SRC_BASE}/crypto/aes-wrap.c + ${HOSTAP_SRC_BASE}/crypto/aes-unwrap.c + ${HOSTAP_SRC_BASE}/crypto/rc4.c + ${HOSTAP_SRC_BASE}/crypto/sha1-prf.c + ${HOSTAP_SRC_BASE}/crypto/sha256-prf.c + ${HOSTAP_SRC_BASE}/crypto/sha256-prf.c + ${HOSTAP_SRC_BASE}/crypto/sha384-prf.c +) + + +zephyr_library_sources_ifdef(CONFIG_WIFI_NM_WPA_SUPPLICANT_WPA3 + ${HOSTAP_SRC_BASE}/common/sae.c + ${HOSTAP_SRC_BASE}/common/dragonfly.c + + ${HOSTAP_SRC_BASE}/crypto/dh_groups.c + ${HOSTAP_SRC_BASE}/crypto/sha256-kdf.c ) +zephyr_library_compile_definitions_ifdef(CONFIG_WIFI_NM_WPA_SUPPLICANT_WPA3 + CONFIG_SAE + CONFIG_ECC +) + +zephyr_library_include_directories_ifdef(CONFIG_WIFI_NM_WPA_SUPPLICANT_CRYPTO + ${CMAKE_SOURCE_DIR} +) + +zephyr_library_sources_ifdef(CONFIG_WIFI_NM_WPA_SUPPLICANT_P2P + ${WIFI_NM_WPA_SUPPLICANT_BASE}/p2p_supplicant.c + ${WIFI_NM_WPA_SUPPLICANT_BASE}/p2p_supplicant_sd.c + ${HOSTAP_SRC_BASE}/p2p/p2p.c + ${HOSTAP_SRC_BASE}/p2p/p2p_utils.c + ${HOSTAP_SRC_BASE}/p2p/p2p_parse.c + ${HOSTAP_SRC_BASE}/p2p/p2p_build.c + ${HOSTAP_SRC_BASE}/p2p/p2p_go_neg.c + ${HOSTAP_SRC_BASE}/p2p/p2p_sd.c + ${HOSTAP_SRC_BASE}/p2p/p2p_pd.c + ${HOSTAP_SRC_BASE}/p2p/p2p_invitation.c + ${HOSTAP_SRC_BASE}/p2p/p2p_dev_disc.c + ${HOSTAP_SRC_BASE}/p2p/p2p_group.c + ${HOSTAP_SRC_BASE}/ap/p2p_hostapd.c + ${HOSTAP_SRC_BASE}/common/gas.c + ${WIFI_NM_WPA_SUPPLICANT_BASE}/gas_query.c + ${WIFI_NM_WPA_SUPPLICANT_BASE}/offchannel.c +) +zephyr_library_sources_ifdef(CONFIG_WIFI_NM_WPA_SUPPLICANT_WPS + ${WIFI_NM_WPA_SUPPLICANT_BASE}/wps_supplicant.c + ${HOSTAP_SRC_BASE}/utils/uuid.c + ${HOSTAP_SRC_BASE}/eap_peer/eap_wsc.c + ${HOSTAP_SRC_BASE}/eap_common/eap_wsc_common.c + ${HOSTAP_SRC_BASE}/wps/wps.c + ${HOSTAP_SRC_BASE}/ap/wps_hostapd.c + ${HOSTAP_SRC_BASE}/wps/wps_common.c + ${HOSTAP_SRC_BASE}/wps/wps_attr_parse.c + ${HOSTAP_SRC_BASE}/wps/wps_attr_build.c + ${HOSTAP_SRC_BASE}/wps/wps_attr_process.c + ${HOSTAP_SRC_BASE}/wps/wps_dev_attr.c + ${HOSTAP_SRC_BASE}/wps/wps_enrollee.c + ${HOSTAP_SRC_BASE}/wps/wps_registrar.c + ${HOSTAP_SRC_BASE}/crypto/dh_groups.c + ${HOSTAP_SRC_BASE}/crypto/dh_group5.c +) + +zephyr_library_compile_definitions_ifdef(CONFIG_WIFI_NM_WPA_SUPPLICANT_P2P + CONFIG_P2P + CONFIG_GAS + CONFIG_OFFCHANNEL +) + +zephyr_library_compile_definitions_ifdef(CONFIG_WIFI_NM_WPA_SUPPLICANT_WPS + CONFIG_WPS + EAP_WSC +) + +zephyr_library_sources_ifndef(CONFIG_WIFI_NM_WPA_SUPPLICANT_CRYPTO_NONE + ${HOSTAP_SRC_BASE}/common/wpa_common.c + ${HOSTAP_SRC_BASE}/rsn_supp/wpa.c + ${HOSTAP_SRC_BASE}/rsn_supp/preauth.c + ${HOSTAP_SRC_BASE}/rsn_supp/wpa_ie.c + +# ${HOSTAP_SRC_BASE}/crypto/crypto_mbedtls-bignum.c +# ${HOSTAP_SRC_BASE}/crypto/crypto_mbedtls-ec.c +# ${HOSTAP_SRC_BASE}/crypto/crypto_mbedtls.c + ${HOSTAP_SRC_BASE}/crypto/aes-wrap.c + ${HOSTAP_SRC_BASE}/crypto/aes-unwrap.c + ${HOSTAP_SRC_BASE}/crypto/rc4.c + ${HOSTAP_SRC_BASE}/crypto/sha1-prf.c + ${HOSTAP_SRC_BASE}/crypto/sha256-prf.c + ${HOSTAP_SRC_BASE}/crypto/sha256-prf.c + ${HOSTAP_SRC_BASE}/crypto/sha384-prf.c +) + +zephyr_library_sources_ifdef(CONFIG_WIFI_NM_WPA_SUPPLICANT_CRYPTO_ENTERPRISE + ${HOSTAP_SRC_BASE}/eap_peer/eap_tls.c + ${HOSTAP_SRC_BASE}/eap_peer/eap_tls_common.c + + + ${HOSTAP_SRC_BASE}/eap_peer/eap_peap.c + ${HOSTAP_SRC_BASE}/eap_common/eap_peap_common.c + ${HOSTAP_SRC_BASE}/eap_peer/eap_ttls.c + ${HOSTAP_SRC_BASE}/eap_peer/eap_md5.c + ${HOSTAP_SRC_BASE}/eap_peer/eap_mschapv2.c + ${HOSTAP_SRC_BASE}/eap_common/chap.c + ${HOSTAP_SRC_BASE}/eap_peer/mschapv2.c + ${HOSTAP_SRC_BASE}/eap_peer/eap_leap.c + + ${HOSTAP_SRC_BASE}/eap_peer/eap_psk.c + ${HOSTAP_SRC_BASE}/eap_common/eap_psk_common.c + + ${HOSTAP_SRC_BASE}/eap_peer/eap_fast.c + ${HOSTAP_SRC_BASE}/eap_peer/eap_fast_pac.c + ${HOSTAP_SRC_BASE}/eap_common/eap_fast_common.c + + ${HOSTAP_SRC_BASE}/eap_peer/eap_pax.c + ${HOSTAP_SRC_BASE}/eap_common/eap_pax_common.c + + ${HOSTAP_SRC_BASE}/eap_peer/eap_sake.c + ${HOSTAP_SRC_BASE}/eap_common/eap_sake_common.c + + ${HOSTAP_SRC_BASE}/eap_peer/eap_gpsk.c + ${HOSTAP_SRC_BASE}/eap_common/eap_gpsk_common.c + + ${HOSTAP_SRC_BASE}/eap_peer/eap_pwd.c + ${HOSTAP_SRC_BASE}/eap_common/eap_pwd_common.c + + ${HOSTAP_SRC_BASE}/eap_peer/eap_eke.c + ${HOSTAP_SRC_BASE}/eap_common/eap_eke_common.c + + ${HOSTAP_SRC_BASE}/eap_peer/eap_ikev2.c + ${HOSTAP_SRC_BASE}/eap_peer/ikev2.c + ${HOSTAP_SRC_BASE}/eap_common/eap_ikev2_common.c + ${HOSTAP_SRC_BASE}/eap_common/ikev2_common.c + + # common + ${HOSTAP_SRC_BASE}/crypto/sha384-tlsprf.c + ${HOSTAP_SRC_BASE}/crypto/sha256-tlsprf.c + ${HOSTAP_SRC_BASE}/crypto/sha1-tlsprf.c + ${HOSTAP_SRC_BASE}/crypto/sha1-tprf.c + ${HOSTAP_SRC_BASE}/crypto/ms_funcs.c + ${HOSTAP_SRC_BASE}/crypto/aes-eax.c + # MD4 removed from MbedTLS + ${HOSTAP_SRC_BASE}/crypto/md4-internal + ${HOSTAP_SRC_BASE}/crypto/aes-encblock.c + +) + +zephyr_library_compile_definitions_ifdef(CONFIG_WIFI_NM_WPA_SUPPLICANT_CRYPTO_ENTERPRISE + CONFIG_EAP_TLS + CONFIG_IEEE8021X_EAPOL + CONFIG_EAP_PEAP + CONFIG_EAP_TTLS + CONFIG_EAP_MD5 + CONFIG_EAP_MSCHAPv2 + CONFIG_EAP_LEAP + CONFIG_EAP_PSK + CONFIG_EAP_FAST + CONFIG_EAP_PAX + CONFIG_EAP_SAKE + CONFIG_EAP_GPSK + CONFIG_EAP_PWD + CONFIG_EAP_EKE + CONFIG_EAP_IKEv2 +) + +zephyr_library_sources_ifdef(CONFIG_WIFI_NM_WPA_SUPPLICANT_EAPOL + ${HOSTAP_SRC_BASE}/eapol_supp/eapol_supp_sm.c + ${HOSTAP_SRC_BASE}/eap_peer/eap.c + ${HOSTAP_SRC_BASE}/eap_peer/eap_methods.c + ${HOSTAP_SRC_BASE}/eap_common/eap_common.c + ${HOSTAP_SRC_BASE}/rsn_supp/pmksa_cache.c +) + +zephyr_library_compile_definitions_ifdef(CONFIG_WIFI_NM_WPA_SUPPLICANT_EAPOL + IEEE8021X_EAPOL +) endif() diff --git a/modules/hostap/Kconfig b/modules/hostap/Kconfig index 5ff3c13a494..8dbe18d7967 100644 --- a/modules/hostap/Kconfig +++ b/modules/hostap/Kconfig @@ -8,7 +8,11 @@ config WIFI_NM_WPA_SUPPLICANT bool "WPA Suplicant from hostap project [EXPERIMENTAL]" select POSIX_CLOCK + select POSIX_SIGNAL + select POSIX_API +# depends on !POSIX_API select NET_SOCKETS +# select NET_SOCKETS_POSIX_NAMES select NET_SOCKETS_PACKET select NET_SOCKETPAIR select NET_L2_WIFI_MGMT @@ -21,6 +25,10 @@ config WIFI_NM_WPA_SUPPLICANT_THREAD_STACK_SIZE int "Stack size for wpa_supplicant thread" default 8192 +config WIFI_NM_WPA_SUPPLICANT_WQ_STACK_SIZE + int "Stack size for wpa_supplicant iface workqueue" + default 4096 + # Currently we default POSIX_MAX_FDS to 16 in lib/posix/Kconfig # l2_packet - 1 # ctrl_iface - 2 * socketpairs = 4(local and global) @@ -51,6 +59,114 @@ config WIFI_NM_WPA_SUPPLICANT_DEBUG_LEVEL if WIFI_NM_WPA_SUPPLICANT +config WIFI_NM_WPA_SUPPLICANT_WEP + bool "WEP (Legacy crypto) support" + +choice WIFI_NM_WPA_SUPPLICANT_CRYPTO_BACKEND + prompt "WPA supplicant crypto implementation" + default WIFI_NM_WPA_SUPPLICANT_CRYPTO_NONE + default WIFI_NM_WPA_SUPPLICANT_CRYPTO_PSA if BUILD_WITH_TFM + default WIFI_NM_WPA_SUPPLICANT_CRYPTO if !BUILD_WITH_TFM + help + Select the crypto implementation to use for WPA supplicant. + +# To easily manage the crypto dependencies we separate the crypto +# implementations into two Kconfig options. One for the legacy crypto +# and one for the PSA crypto. +config WIFI_NM_WPA_SUPPLICANT_CRYPTO_PSA + bool "PSA Crypto support for WiFi" + select WIFI_NM_WPA_SUPPLICANT_WEP + select PSA_WANT_KEY_TYPE_AES + select PSA_WANT_ALG_CMAC + select PSA_WANT_ALG_CBC_PKCS7 + select PSA_WANT_ALG_CTR + select PSA_WANT_ALG_ECDSA + select PSA_WANT_GENERATE_RANDOM + select PSA_WANT_ALG_RSA_PSS + select PSA_WANT_ALG_DETERMINISTIC_ECDSA + select PSA_WANT_ALG_SHA_512 + select PSA_WANT_ALG_SHA_1 + select PSA_WANT_KEY_TYPE_RSA_KEY_PAIR + select PSA_WANT_ECC_SECP_R1_256 + # Legacy crypto, still needed + #select MBEDTLS + #select MBEDTLS_CMAC_C + #select MBEDTLS_GCM_C + #select MBEDTLS_TLS_LIBRARY + #select MBEDTLS_PK_WRITE_C + #select MBEDTLS_X509_LIBRARY + #select MBEDTLS_X509_CRT_PARSE_C + #select MBEDTLS_CIPHER_C + #select MBEDTLS_CIPHER_MODE_CTR + #select MBEDTLS_CIPHER_MODE_CBC + #select MBEDTLS_SSL_TLS_C + #select MBEDTLS_KEY_EXCHANGE_ALL_ENABLED + #select MBEDTLS_KEY_EXCHANGE_ECDHE_PSK_ENABLED + #select MBEDTLS_KEY_EXCHANGE_ECDHE_RSA_ENABLED + +config WIFI_NM_WPA_SUPPLICANT_CRYPTO + bool "Legacy Crypto support for WiFi" + select WIFI_NM_WPA_SUPPLICANT_WEP + #select MBEDTLS + #select MBEDTLS_CIPHER_MODE_CBC + #select MBEDTLS_CIPHER_MODE_CTR + #select MBEDTLS_LEGACY_CRYPTO_C + #select MBEDTLS_ECP_C + #select MBEDTLS_CTR_DRBG_C + #select MBEDTLS_PK_WRITE_C + #select MBEDTLS_KEY_EXCHANGE_ALL_ENABLED + #select MBEDTLS_KEY_EXCHANGE_ECDHE_PSK_ENABLED + #select MBEDTLS_KEY_EXCHANGE_ECDHE_RSA_ENABLED + +config WIFI_NM_WPA_SUPPLICANT_CRYPTO_NONE + bool "No Crypto support for WiFi" + +endchoice + +config WIFI_NM_WPA_SUPPLICANT_CRYPTO_ENTERPRISE + bool "Enterprise Crypto support for WiFi" + depends on !WIFI_NM_WPA_SUPPLICANT_CRYPTO_NONE + +config WIFI_NM_WPA_SUPPLICANT_WPA3 + bool "WPA3 support" + depends on !WIFI_NM_WPA_SUPPLICANT_CRYPTO_NONE + default y + +config WIFI_NM_WPA_SUPPLICANT_AP + bool "AP mode support" + +config WIFI_NM_WPA_SUPPLICANT_WPS + bool "WPS support" + depends on !WIFI_NM_WPA_SUPPLICANT_CRYPTO_NONE + +config WIFI_NM_WPA_SUPPLICANT_P2P + bool "P2P mode support" + select WIFI_NM_WPA_SUPPLICANT_AP + select WIFI_NM_WPA_SUPPLICANT_WPS + +config WIFI_NM_WPA_SUPPLICANT_EAPOL + bool "Enable EAPoL supplicant" + +config WIFI_NM_WPA_SUPPLICANT_CLI + bool "CLI support for wpa_supplicant" + default n + +config WIFI_NM_WPA_SUPPLICANT_BSS_MAX_IDLE_TIME + int "BSS max idle timeout in seconds" + range 0 64000 + default 300 + help + BSS max idle timeout is the period for which AP may keep a client + in associated state while there is no traffic from that particular + client. Set 0 to disable inclusion of BSS max idle time tag in + association request. If a non-zero value is set, STA can suggest a + timeout by including BSS max idle period in the association request. + AP may choose to consider or ignore the STA's preferred value. + Ref: Sec 11.21.13 of IEEE Std 802.11™-2020 + +config WIFI_NM_WPA_SUPPLICANT_NO_DEBUG + bool "Disable printing of debug messages, saves code size significantly" + # Create hidden config options that are used in hostap. This way we do not need # to mark them as allowed for CI checks, and also someone else cannot use the # same name options. @@ -71,19 +187,22 @@ config CTRL_IFACE bool default y -config NO_RANDOM_POOL +config CTRL_IFACE_ZEPHYR bool default y -config NO_WPA +config NO_RANDOM_POOL bool default y -config NO_PBKDF2 +config WNM bool - default y -config ZEPHYR +config NO_WPA + bool + default y if WIFI_NM_WPA_SUPPLICANT_CRYPTO_NONE + +config NO_PBKDF2 bool default y diff --git a/modules/hostap/src/supp_api.c b/modules/hostap/src/supp_api.c new file mode 100644 index 00000000000..0f07db37387 --- /dev/null +++ b/modules/hostap/src/supp_api.c @@ -0,0 +1,549 @@ +/** + * Copyright (c) 2023 Nordic Semiconductor ASA + * + * SPDX-License-Identifier: Apache-2.0 + */ +#include + +#include +#include + +#include "includes.h" +#include "common.h" +#include "common/defs.h" +#include "wpa_supplicant/config.h" +#include "wpa_supplicant_i.h" +#include "driver_i.h" + +#include "supp_main.h" +#include "supp_api.h" +#include "wpa_cli_zephyr.h" +#include "supp_events.h" + +extern struct k_sem wpa_supplicant_ready_sem; +extern struct wpa_global *global; + +enum requested_ops { + CONNECT = 0, + DISCONNECT +}; + +enum status_thread_state { + STATUS_THREAD_STOPPED = 0, + STATUS_THREAD_RUNNING, +}; + +#define OP_STATUS_POLLING_INTERVAL 1 + +#define CONNECTION_SUCCESS 0 +#define CONNECTION_FAILURE 1 +#define CONNECTION_TERMINATED 2 + +#define DISCONNECT_TIMEOUT_MS 5000 + +#define _wpa_cli_cmd_v(cmd, ...) \ + do { \ + if (z_wpa_cli_cmd_v(cmd, ##__VA_ARGS__) < 0) { \ + wpa_printf(MSG_ERROR, "Failed to execute wpa_cli command: %s", cmd); \ + goto out; \ + } \ + } while (0) + +K_MUTEX_DEFINE(wpa_supplicant_mutex); + + +struct wpa_supp_api_ctrl { + const struct device *dev; + enum requested_ops requested_op; + enum status_thread_state status_thread_state; + int connection_timeout; /* in seconds */ + struct k_work_sync sync; + bool terminate; +}; + +static struct wpa_supp_api_ctrl wpa_supp_api_ctrl; + +static void supp_shell_connect_status(struct k_work *work); + +static K_WORK_DELAYABLE_DEFINE(wpa_supp_status_work, + supp_shell_connect_status); + +static inline struct wpa_supplicant *get_wpa_s_handle(const struct device *dev) +{ + return z_wpas_get_handle_by_ifname(dev->name); +} + +static int wait_for_disconnect_complete(const struct device *dev) +{ + int ret = 0; + int timeout = 0; + struct wpa_supplicant *wpa_s = get_wpa_s_handle(dev); + + if (!wpa_s) { + ret = -ENODEV; + wpa_printf(MSG_ERROR, "Failed to get wpa_s handle"); + goto out; + } + + while (wpa_s->wpa_state != WPA_DISCONNECTED) { + if (timeout > DISCONNECT_TIMEOUT_MS) { + ret = -ETIMEDOUT; + wpa_printf(MSG_WARNING, "Failed to disconnect from network"); + break; + } + k_sleep(K_MSEC(10)); + timeout++; + } +out: + return ret; +} + +static void supp_shell_connect_status(struct k_work *work) +{ + static int seconds_counter; + int status = CONNECTION_SUCCESS; + int conn_result = CONNECTION_FAILURE; + struct wpa_supplicant *wpa_s; + struct wpa_supp_api_ctrl *ctrl = &wpa_supp_api_ctrl; + + k_mutex_lock(&wpa_supplicant_mutex, K_FOREVER); + + if (ctrl->status_thread_state == STATUS_THREAD_RUNNING && ctrl->terminate) { + status = CONNECTION_TERMINATED; + goto out; + } + + wpa_s = get_wpa_s_handle(ctrl->dev); + if (!wpa_s) { + status = CONNECTION_FAILURE; + goto out; + } + + if (ctrl->requested_op == CONNECT && wpa_s->wpa_state != WPA_COMPLETED) { + if (ctrl->connection_timeout > 0 && seconds_counter++ > ctrl->connection_timeout) { + _wpa_cli_cmd_v("disconnect"); + conn_result = -ETIMEDOUT; + send_wifi_mgmt_event(wpa_s->ifname, NET_EVENT_WIFI_CMD_CONNECT_RESULT, + (void *)&conn_result, sizeof(int)); + status = CONNECTION_FAILURE; + goto out; + } + + k_work_reschedule(&wpa_supp_status_work, K_SECONDS(OP_STATUS_POLLING_INTERVAL)); + ctrl->status_thread_state = STATUS_THREAD_RUNNING; + k_mutex_unlock(&wpa_supplicant_mutex); + return; + } +out: + seconds_counter = 0; + + ctrl->status_thread_state = STATUS_THREAD_STOPPED; + k_mutex_unlock(&wpa_supplicant_mutex); +} + +static inline void wpa_supp_restart_status_work(void) +{ + /* Terminate synchronously */ + wpa_supp_api_ctrl.terminate = 1; + k_work_flush_delayable(&wpa_supp_status_work, + &wpa_supp_api_ctrl.sync); + wpa_supp_api_ctrl.terminate = 0; + + /* Start afresh */ + k_work_reschedule(&wpa_supp_status_work, + K_MSEC(10)); +} + +static inline int chan_to_freq(int chan) +{ + /* We use global channel list here and also use the widest + * op_class for 5GHz channels as there is no user input + * for these (yet). + */ + int freq = ieee80211_chan_to_freq(NULL, 81, chan); + + if (freq <= 0) { + freq = ieee80211_chan_to_freq(NULL, 128, chan); + } + + if (freq <= 0) { + wpa_printf(MSG_ERROR, "Invalid channel %d", chan); + return -1; + } + + return freq; +} + +static inline enum wifi_frequency_bands wpas_band_to_zephyr(enum wpa_radio_work_band band) +{ + switch (band) { + case BAND_2_4_GHZ: + return WIFI_FREQ_BAND_2_4_GHZ; + case BAND_5_GHZ: + return WIFI_FREQ_BAND_5_GHZ; + default: + return WIFI_FREQ_BAND_UNKNOWN; + } +} + +static inline enum wifi_security_type wpas_key_mgmt_to_zephyr(int key_mgmt) +{ + switch (key_mgmt) { + case WPA_KEY_MGMT_NONE: + return WIFI_SECURITY_TYPE_NONE; + case WPA_KEY_MGMT_PSK: + return WIFI_SECURITY_TYPE_PSK; + case WPA_KEY_MGMT_PSK_SHA256: + return WIFI_SECURITY_TYPE_PSK_SHA256; + case WPA_KEY_MGMT_SAE: + return WIFI_SECURITY_TYPE_SAE; + default: + return WIFI_SECURITY_TYPE_UNKNOWN; + } +} + +/* Public API */ +int z_wpa_supplicant_connect(const struct device *dev, + struct wifi_connect_req_params *params) +{ + struct wpa_supplicant *wpa_s; + int ret = 0; + struct add_network_resp resp = {0}; + + if (!net_if_is_admin_up(net_if_lookup_by_dev(dev))) { + wpa_printf(MSG_ERROR, + "Interface %s is down, dropping connect", + dev->name); + return -1; + } + + k_mutex_lock(&wpa_supplicant_mutex, K_FOREVER); + + wpa_s = get_wpa_s_handle(dev); + if (!wpa_s) { + ret = -1; + wpa_printf(MSG_ERROR, "Interface %s not found", dev->name); + goto out; + } + + _wpa_cli_cmd_v("remove_network all"); + ret = z_wpa_ctrl_add_network(&resp); + if (ret) { + wpa_printf(MSG_ERROR, "Failed to add network"); + goto out; + } + + wpa_printf(MSG_DEBUG, "NET added: %d\n", resp.network_id); + + _wpa_cli_cmd_v("set_network %d ssid \"%s\"", resp.network_id, params->ssid); + _wpa_cli_cmd_v("set_network %d scan_ssid 1", resp.network_id); + _wpa_cli_cmd_v("set_network %d key_mgmt NONE", resp.network_id); + _wpa_cli_cmd_v("set_network %d ieee80211w 0", resp.network_id); + if (params->security != WIFI_SECURITY_TYPE_NONE) { + if (params->security == WIFI_SECURITY_TYPE_SAE) { + if (params->sae_password) { + _wpa_cli_cmd_v("set_network %d sae_password \"%s\"", + resp.network_id, params->sae_password); + } else { + _wpa_cli_cmd_v("set_network %d sae_password \"%s\"", + resp.network_id, params->psk); + } + _wpa_cli_cmd_v("set_network %d key_mgmt SAE", + resp.network_id); + } else if (params->security == WIFI_SECURITY_TYPE_PSK_SHA256) { + _wpa_cli_cmd_v("set_network %d psk \"%s\"", + resp.network_id, params->psk); + _wpa_cli_cmd_v("set_network %d key_mgmt WPA-PSK-SHA256", + resp.network_id); + } else if (params->security == WIFI_SECURITY_TYPE_PSK) { + _wpa_cli_cmd_v("set_network %d psk \"%s\"", + resp.network_id, params->psk); + _wpa_cli_cmd_v("set_network %d key_mgmt WPA-PSK", + resp.network_id); + } else { + ret = -1; + wpa_printf(MSG_ERROR, "Unsupported security type: %d", + params->security); + goto out; + } + + if (params->mfp) { + _wpa_cli_cmd_v("set_network %d ieee80211w %d", + resp.network_id, params->mfp); + } + } + + /* enable and select network */ + _wpa_cli_cmd_v("enable_network %d", resp.network_id); + + if (params->channel != WIFI_CHANNEL_ANY) { + int freq = chan_to_freq(params->channel); + + if (freq < 0) { + ret = -1; + wpa_printf(MSG_ERROR, "Invalid channel %d", + params->channel); + goto out; + } + z_wpa_cli_cmd_v("set_network %d scan_freq %d", + resp.network_id, freq); + } + _wpa_cli_cmd_v("select_network %d", resp.network_id); + + z_wpa_cli_cmd_v("select_network %d", resp.network_id); + wpa_supp_api_ctrl.dev = dev; + wpa_supp_api_ctrl.requested_op = CONNECT; + wpa_supp_api_ctrl.connection_timeout = params->timeout; + +out: + k_mutex_unlock(&wpa_supplicant_mutex); + + if (!ret) { + wpa_supp_restart_status_work(); + } + + return ret; +} + +int z_wpa_supplicant_disconnect(const struct device *dev) +{ + struct wpa_supplicant *wpa_s; + int ret = 0; + struct net_if *iface = net_if_lookup_by_dev(dev); + + if (!iface) { + ret = -EINVAL; + wpa_printf(MSG_ERROR, "Device %s not found", dev->name); + goto out; + } + + k_mutex_lock(&wpa_supplicant_mutex, K_FOREVER); + + wpa_s = get_wpa_s_handle(dev); + if (!wpa_s) { + ret = -EINVAL; + wpa_printf(MSG_ERROR, "Interface %s not found", dev->name); + goto out; + } + wpa_supp_api_ctrl.dev = dev; + wpa_supp_api_ctrl.requested_op = DISCONNECT; + _wpa_cli_cmd_v("disconnect"); + +out: + k_mutex_unlock(&wpa_supplicant_mutex); + + if (ret) { + wpa_printf(MSG_ERROR, "Disconnect failed: %s", + strerror(-ret)); + return ret; + } + + wpa_supp_restart_status_work(); + + ret = wait_for_disconnect_complete(dev); + + wifi_mgmt_raise_disconnect_complete_event(iface, ret); + + return ret; +} + +int z_wpa_supplicant_status(const struct device *dev, + struct wifi_iface_status *status) +{ + struct wpa_supplicant *wpa_s; + int ret = -1; + struct wpa_signal_info *si = NULL; + struct wpa_conn_info *conn_info = NULL; + + k_mutex_lock(&wpa_supplicant_mutex, K_FOREVER); + + wpa_s = get_wpa_s_handle(dev); + if (!wpa_s) { + wpa_printf(MSG_ERROR, "Interface %s not found", dev->name); + goto out; + } + + si = os_zalloc(sizeof(struct wpa_signal_info)); + if (!si) { + wpa_printf(MSG_ERROR, "Failed to allocate memory for signal info"); + goto out; + } + + status->state = wpa_s->wpa_state; /* 1-1 Mapping */ + + if (wpa_s->wpa_state >= WPA_ASSOCIATED) { + struct wpa_ssid *ssid = wpa_s->current_ssid; + u8 channel; + struct signal_poll_resp signal_poll; + + os_memcpy(status->bssid, wpa_s->bssid, WIFI_MAC_ADDR_LEN); + status->band = wpas_band_to_zephyr(wpas_freq_to_band(wpa_s->assoc_freq)); + status->security = wpas_key_mgmt_to_zephyr(wpa_s->key_mgmt); + status->mfp = ssid->ieee80211w; /* Same mapping */ + ieee80211_freq_to_chan(wpa_s->assoc_freq, &channel); + status->channel = channel; + + if (ssid) { + u8 *_ssid = ssid->ssid; + size_t ssid_len = ssid->ssid_len; + struct status_resp cli_status; + + if (ssid_len == 0) { + int _res = z_wpa_ctrl_status(&cli_status); + + if (_res < 0) + ssid_len = 0; + else + ssid_len = cli_status.ssid_len; + _ssid = cli_status.ssid; + } + os_memcpy(status->ssid, _ssid, ssid_len); + status->ssid_len = ssid_len; + status->iface_mode = ssid->mode; + if (wpa_s->connection_set == 1) { + status->link_mode = wpa_s->connection_he ? WIFI_6 : + wpa_s->connection_vht ? WIFI_5 : + wpa_s->connection_ht ? WIFI_4 : + wpa_s->connection_g ? WIFI_3 : + wpa_s->connection_a ? WIFI_2 : + wpa_s->connection_b ? WIFI_1 : + WIFI_0; + } else { + status->link_mode = WIFI_LINK_MODE_UNKNOWN; + } + } + ret = z_wpa_ctrl_signal_poll(&signal_poll); + if (!ret) { + status->rssi = signal_poll.rssi; + } else { + wpa_printf(MSG_WARNING, "%s:Failed to read RSSI\n", + __func__); + status->rssi = -WPA_INVALID_NOISE; + ret = 0; + } + + conn_info = os_zalloc(sizeof(struct wpa_conn_info)); + if (!conn_info) { + wpa_printf(MSG_ERROR, "%s:Failed to allocate memory\n", + __func__); + ret = -ENOMEM; + goto out; + } + ret = wpa_drv_get_conn_info(wpa_s, conn_info); + if (!ret) { + status->beacon_interval = conn_info->beacon_interval; + status->dtim_period = conn_info->dtim_period; + status->twt_capable = conn_info->twt_capable; + } else { + wpa_printf(MSG_WARNING, "%s: Failed to get connection info\n", + __func__); + status->beacon_interval = 0; + status->dtim_period = 0; + status->twt_capable = false; + ret = 0; + } + os_free(conn_info); + } else { + ret = 0; + } +out: + os_free(si); + k_mutex_unlock(&wpa_supplicant_mutex); + return ret; +} + +/* Below APIs are not natively supported by WPA supplicant, so, + * these are just wrappers around driver offload APIs. But it is + * transparent to the user. + * + * In the future these might be implemented natively by the WPA + * supplicant. + */ + +static const struct wifi_mgmt_ops *const get_wifi_mgmt_api(const struct device *dev) +{ + struct net_wifi_mgmt_offload *off_api = + (struct net_wifi_mgmt_offload *) dev->api; + + return off_api ? off_api->wifi_mgmt_api : NULL; +} + +int z_wpa_supplicant_scan(const struct device *dev, struct wifi_scan_params *params, + scan_result_cb_t cb) +{ + const struct wifi_mgmt_ops *const wifi_mgmt_api = get_wifi_mgmt_api(dev); + + if (!wifi_mgmt_api || !wifi_mgmt_api->scan) { + wpa_printf(MSG_ERROR, "Scan not supported"); + return -ENOTSUP; + } + + return wifi_mgmt_api->scan(dev, params, cb); +} + +#ifdef CONFIG_NET_STATISTICS_WIFI +int z_wpa_supplicant_get_stats(const struct device *dev, + struct net_stats_wifi *stats) +{ + const struct wifi_mgmt_ops *const wifi_mgmt_api = get_wifi_mgmt_api(dev); + + if (!wifi_mgmt_api || !wifi_mgmt_api->get_stats) { + wpa_printf(MSG_ERROR, "Get stats not supported"); + return -ENOTSUP; + } + + return wifi_mgmt_api->get_stats(dev, stats); +} +#endif /* CONFIG_NET_STATISTICS_WIFI */ + +int z_wpa_supplicant_set_power_save(const struct device *dev, + struct wifi_ps_params *params) +{ + const struct wifi_mgmt_ops *const wifi_mgmt_api = get_wifi_mgmt_api(dev); + + if (!wifi_mgmt_api || !wifi_mgmt_api->set_power_save) { + wpa_printf(MSG_ERROR, "Set power save not supported"); + return -ENOTSUP; + } + + return wifi_mgmt_api->set_power_save(dev, params); +} + +int z_wpa_supplicant_set_twt(const struct device *dev, + struct wifi_twt_params *params) +{ + const struct wifi_mgmt_ops *const wifi_mgmt_api = get_wifi_mgmt_api(dev); + + if (!wifi_mgmt_api || !wifi_mgmt_api->set_twt) { + wpa_printf(MSG_ERROR, "Set TWT not supported"); + return -ENOTSUP; + } + + return wifi_mgmt_api->set_twt(dev, params); +} + +int z_wpa_supplicant_get_power_save_config(const struct device *dev, + struct wifi_ps_config *config) +{ + const struct wifi_mgmt_ops *const wifi_mgmt_api = get_wifi_mgmt_api(dev); + + if (!wifi_mgmt_api || !wifi_mgmt_api->get_power_save_config) { + wpa_printf(MSG_ERROR, "Get power save config not supported"); + return -ENOTSUP; + } + + return wifi_mgmt_api->get_power_save_config(dev, config); +} + +int z_wpa_supplicant_reg_domain(const struct device *dev, + struct wifi_reg_domain *reg_domain) +{ + const struct wifi_mgmt_ops *const wifi_mgmt_api = get_wifi_mgmt_api(dev); + + if (!wifi_mgmt_api || !wifi_mgmt_api->reg_domain) { + wpa_printf(MSG_ERROR, "Regulatory domain not supported"); + return -ENOTSUP; + } + + return wifi_mgmt_api->reg_domain(dev, reg_domain); +} diff --git a/modules/hostap/src/supp_api.h b/modules/hostap/src/supp_api.h new file mode 100644 index 00000000000..29e3d0717e5 --- /dev/null +++ b/modules/hostap/src/supp_api.h @@ -0,0 +1,111 @@ +/* + * Copyright (c) 2023 Nordic Semiconductor ASA + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#ifndef ZEPHYR_SUPP_MGMT_H +#define ZEPHYR_SUPP_MGMT_H + +#include + +#define MAX_SSID_LEN 32 +#define MAC_ADDR_LEN 6 + +/** + * @brief Request a connection + * + * @param dev: Wi-Fi interface name to use + * @param params: Connection details + * + * @return: 0 for OK; -1 for ERROR + */ +int z_wpa_supplicant_connect(const struct device *dev, + struct wifi_connect_req_params *params); +/** + * @brief Forces station to disconnect and stops any subsequent scan + * or connection attempts + * + * @param dev: Wi-Fi interface name to use + * + * @return: 0 for OK; -1 for ERROR + */ +int z_wpa_supplicant_disconnect(const struct device *dev); + +/** + * @brief + * + * @param dev: Wi-Fi interface name to use + * @param status: Status structure to fill + * + * @return: 0 for OK; -1 for ERROR + */ +int z_wpa_supplicant_status(const struct device *dev, + struct wifi_iface_status *status); + +/** + * @brief Request a scan + * + * @param dev Wi-Fi interface name to use + * @param params Scan parameters + * @param cb Callback to be called for each scan result + * + * @return 0 for OK; -1 for ERROR + */ +int z_wpa_supplicant_scan(const struct device *dev, struct wifi_scan_params *params, + scan_result_cb_t cb); + +#if defined(CONFIG_NET_STATISTICS_WIFI) || defined(__DOXYGEN__) +/** + * @brief Get Wi-Fi statistics + * + * @param dev Wi-Fi interface name to use + * @param stats Pointer to stats structure to fill + * + * @return 0 for OK; -1 for ERROR + */ +int z_wpa_supplicant_get_stats(const struct device *dev, + struct net_stats_wifi *stats); +#endif /* CONFIG_NET_STATISTICS_WIFI || __DOXYGEN__ */ + +/** + * @brief Set Wi-Fi power save configuration + * + * @param dev Wi-Fi interface name to use + * @param params Power save parameters to set + * + * @return 0 for OK; -1 for ERROR + */ +int z_wpa_supplicant_set_power_save(const struct device *dev, + struct wifi_ps_params *params); + +/** + * @brief Set Wi-Fi TWT parameters + * + * @param dev Wi-Fi interface name to use + * @param params TWT parameters to set + * @return 0 for OK; -1 for ERROR + */ +int z_wpa_supplicant_set_twt(const struct device *dev, + struct wifi_twt_params *params); + +/** + * @brief Get Wi-Fi power save configuration + * + * @param dev Wi-Fi interface name to use + * @param config Address of power save configuration to fill + * @return 0 for OK; -1 for ERROR + */ +int z_wpa_supplicant_get_power_save_config(const struct device *dev, + struct wifi_ps_config *config); + +/** + * @brief Set Wi-Fi Regulatory domain + * + * @param dev Wi-Fi interface name to use + * @param reg_domain Regulatory domain to set + * @return 0 for OK; -1 for ERROR + */ +int z_wpa_supplicant_reg_domain(const struct device *dev, + struct wifi_reg_domain *reg_domain); +#endif /* ZEPHYR_SUPP_MGMT_H */ diff --git a/modules/hostap/src/supp_events.c b/modules/hostap/src/supp_events.c new file mode 100644 index 00000000000..542944e1039 --- /dev/null +++ b/modules/hostap/src/supp_events.c @@ -0,0 +1,214 @@ +/* + * Copyright (c) 2023 Nordic Semiconductor ASA + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include "supp_events.h" + +#include "includes.h" +#include "common.h" + +#define MAC_STR_FORMAT "%2hhx:%2hhx:%2hhx:%2hhx:%2hhx:%2hhx" + +static char *wpa_supp_event_map[] = { + "CTRL-EVENT-CONNECTED", + "CTRL-EVENT-DISCONNECTED", + "CTRL-EVENT-ASSOC-REJECT", + "CTRL-EVENT-AUTH-REJECT", + "CTRL-EVENT-TERMINATING", + "CTRL-EVENT-SSID-TEMP-DISABLED", + "CTRL-EVENT-SSID-REENABLED", + "CTRL-EVENT-SCAN-STARTED", + "CTRL-EVENT-SCAN-RESULTS", + "CTRL-EVENT-SCAN-FAILED", + "CTRL-EVENT-BSS-ADDED", + "CTRL-EVENT-BSS-REMOVED", + "CTRL-EVENT-NETWORK-NOT-FOUND", + "CTRL-EVENT-NETWORK-ADDED", + "CTRL-EVENT-NETWORK-REMOVED", + "CTRL-EVENT-DSCP-POLICY", +}; + +static int wpa_supp_process_status(struct supp_int_event_data *event_data, char *wpa_supp_status) +{ + int ret = 1; /* For cases where parsing is not being done*/ + int event = -1; + int i; + unsigned char *mac; + union supp_event_data *data; + + data = (union supp_event_data *)event_data->data; + + for (i = 0; i < ARRAY_SIZE(wpa_supp_event_map); i++) { + if (strncmp(wpa_supp_status, wpa_supp_event_map[i], + strlen(wpa_supp_event_map[i])) == 0) { + event = i; + break; + } + } + + if (i >= ARRAY_SIZE(wpa_supp_event_map)) { + wpa_printf(MSG_ERROR, "Event not supported: %s\n", wpa_supp_status); + return -ENOTSUP; + } + + event_data->event = event; + + switch (event_data->event) { + case WPA_SUPP_EVENT_CONNECTED: + mac = data->connected.bssid; + ret = sscanf(wpa_supp_status + strlen("CTRL-EVENT-CONNECTED - Connection to"), + MAC_STR_FORMAT, &mac[0], &mac[1], &mac[2], &mac[3], &mac[4], &mac[5]); + event_data->data_len = sizeof(data->connected); + break; + case WPA_SUPP_EVENT_DISCONNECTED: + mac = data->disconnected.bssid; + ret = sscanf(wpa_supp_status + strlen("CTRL-EVENT-DISCONNECTED bssid="), + MAC_STR_FORMAT" reason=%d", &mac[0], &mac[1], &mac[2], + &mac[3], &mac[4], &mac[5], &data->disconnected.reason_code); + event_data->data_len = sizeof(data->disconnected); + break; + case WPA_SUPP_EVENT_ASSOC_REJECT: + /* TODO */ + break; + case WPA_SUPP_EVENT_AUTH_REJECT: + mac = data->auth_reject.bssid; + ret = sscanf(wpa_supp_status + strlen("CTRL-EVENT-AUTH-REJECT "), MAC_STR_FORMAT + " auth_type=%u auth_transaction=%u status_code=%u", + &mac[0], &mac[1], &mac[2], &mac[3], &mac[4], &mac[5], + &data->auth_reject.auth_type, + &data->auth_reject.auth_transaction, + &data->auth_reject.status_code); + event_data->data_len = sizeof(data->auth_reject); + break; + case WPA_SUPP_EVENT_SSID_TEMP_DISABLED: + ret = sscanf(wpa_supp_status + strlen("CTRL-EVENT-SSID-TEMP-DISABLED "), + "id=%d ssid=%s auth_failures=%u duration=%d reason=%s", + &data->temp_disabled.id, data->temp_disabled.ssid, + &data->temp_disabled.auth_failures, + &data->temp_disabled.duration, + data->temp_disabled.reason_code); + event_data->data_len = sizeof(data->temp_disabled); + break; + case WPA_SUPP_EVENT_SSID_REENABLED: + ret = sscanf(wpa_supp_status + strlen("CTRL-EVENT-SSID-REENABLED "), + "id=%d ssid=%s", &data->reenabled.id, + data->reenabled.ssid); + event_data->data_len = sizeof(data->reenabled); + break; + case WPA_SUPP_EVENT_BSS_ADDED: + mac = data->bss_added.bssid; + ret = sscanf(wpa_supp_status + strlen("CTRL-EVENT-BSS-ADDED "), "%u "MAC_STR_FORMAT, + &data->bss_added.id, + &mac[0], &mac[1], &mac[2], &mac[3], &mac[4], &mac[5]); + event_data->data_len = sizeof(data->bss_added); + break; + case WPA_SUPP_EVENT_BSS_REMOVED: + mac = data->bss_removed.bssid; + ret = sscanf(wpa_supp_status + strlen("CTRL-EVENT-BSS-REMOVED "), + "%u "MAC_STR_FORMAT, + &data->bss_removed.id, + &mac[0], &mac[1], &mac[2], &mac[3], &mac[4], &mac[5]); + event_data->data_len = sizeof(data->bss_removed); + break; + case WPA_SUPP_EVENT_TERMINATING: + case WPA_SUPP_EVENT_SCAN_STARTED: + case WPA_SUPP_EVENT_SCAN_FAILED: + case WPA_SUPP_EVENT_NETWORK_NOT_FOUND: + case WPA_SUPP_EVENT_NETWORK_ADDED: + case WPA_SUPP_EVENT_NETWORK_REMOVED: + strncpy(data->supp_event_str, wpa_supp_event_map[event], + sizeof(data->supp_event_str)); + event_data->data_len = strlen(data->supp_event_str) + 1; + case WPA_SUPP_EVENT_DSCP_POLICY: + /* TODO */ + break; + default: + break; + } + + if (ret <= 0) { + wpa_printf(MSG_ERROR, "%s Parse failed: %s", + wpa_supp_event_map[event_data->event], strerror(errno)); + } + + return ret; +} + +int send_wifi_mgmt_event(const char *ifname, enum net_event_wifi_cmd event, + void *wpa_supp_status, size_t len) +{ + const struct device *dev = device_get_binding(ifname); + struct net_if *iface = net_if_lookup_by_dev(dev); + union supp_event_data data; + struct supp_int_event_data event_data; + + if (!iface) { + wpa_printf(MSG_ERROR, "Could not find iface for %s", ifname); + return -ENODEV; + } + + switch (event) { + case NET_EVENT_WIFI_CMD_CONNECT_RESULT: + wifi_mgmt_raise_connect_result_event(iface, *(int *)wpa_supp_status); + break; + case NET_EVENT_WIFI_CMD_DISCONNECT_RESULT: + wifi_mgmt_raise_disconnect_result_event(iface, *(int *)wpa_supp_status); + break; + case NET_EVENT_WPA_SUPP_CMD_INT_EVENT: + event_data.data = &data; + if (wpa_supp_process_status(&event_data, (char *)wpa_supp_status) > 0) { + net_mgmt_event_notify_with_info(NET_EVENT_WPA_SUPP_INT_EVENT, + iface, &event_data, sizeof(event_data)); + } + break; + default: + wpa_printf(MSG_ERROR, "Unsupported event %d", event); + return -EINVAL; + } + + return 0; +} + +int generate_supp_state_event(const char *ifname, enum net_event_wpa_supp_cmd event, int status) +{ + /* TODO: Replace device_get_binding. */ + const struct device *dev = device_get_binding(ifname); + + if (!dev) { + wpa_printf(MSG_ERROR, "Could not find device for %s", ifname); + return -ENODEV; + } + + struct net_if *iface = net_if_lookup_by_dev(dev); + + if (!iface) { + wpa_printf(MSG_ERROR, "Could not find iface for %s", ifname); + return -ENODEV; + } + + switch (event) { + case NET_EVENT_WPA_SUPP_CMD_READY: + net_mgmt_event_notify(NET_EVENT_WPA_SUPP_READY, iface); + break; + case NET_EVENT_WPA_SUPP_CMD_NOT_READY: + net_mgmt_event_notify(NET_EVENT_WPA_SUPP_NOT_READY, iface); + break; + case NET_EVENT_WPA_SUPP_CMD_IFACE_ADDED: + net_mgmt_event_notify(NET_EVENT_WPA_SUPP_IFACE_ADDED, iface); + break; + case NET_EVENT_WPA_SUPP_CMD_IFACE_REMOVING: + net_mgmt_event_notify(NET_EVENT_WPA_SUPP_IFACE_REMOVING, iface); + break; + case NET_EVENT_WPA_SUPP_CMD_IFACE_REMOVED: + net_mgmt_event_notify_with_info(NET_EVENT_WPA_SUPP_IFACE_REMOVED, + iface, &status, sizeof(status)); + break; + default: + wpa_printf(MSG_ERROR, "Unsupported event %d", event); + return -EINVAL; + } + + return 0; +} diff --git a/modules/hostap/src/supp_events.h b/modules/hostap/src/supp_events.h new file mode 100644 index 00000000000..5296aad2da3 --- /dev/null +++ b/modules/hostap/src/supp_events.h @@ -0,0 +1,142 @@ +/* + * Copyright (c) 2023 Nordic Semiconductor ASA + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#ifndef __SUPP_EVENTS_H__ +#define __SUPP_EVENTS_H__ + +#include + +/* Connectivity Events */ +#define _NET_MGMT_WPA_SUPP_LAYER NET_MGMT_LAYER_L2 +#define _NET_MGMT_WPA_SUPP_CODE 0x157 +#define _NET_MGMT_WPA_SUPP_BASE (NET_MGMT_LAYER(_NET_MGMT_WPA_SUPP_LAYER) | \ + NET_MGMT_LAYER_CODE(_NET_MGMT_WPA_SUPP_CODE) | \ + NET_MGMT_IFACE_BIT) +#define _NET_MGMT_WPA_SUPP_EVENT (NET_MGMT_EVENT_BIT | _NET_MGMT_WPA_SUPP_BASE) + +enum net_event_wpa_supp_cmd { + NET_EVENT_WPA_SUPP_CMD_READY = 1, + NET_EVENT_WPA_SUPP_CMD_NOT_READY, + NET_EVENT_WPA_SUPP_CMD_IFACE_ADDED, + NET_EVENT_WPA_SUPP_CMD_IFACE_REMOVING, + NET_EVENT_WPA_SUPP_CMD_IFACE_REMOVED, + NET_EVENT_WPA_SUPP_CMD_INT_EVENT, + NET_EVENT_WPA_SUPP_CMD_MAX +}; + +#define NET_EVENT_WPA_SUPP_READY \ + (_NET_MGMT_WPA_SUPP_EVENT | NET_EVENT_WPA_SUPP_CMD_READY) + +#define NET_EVENT_WPA_SUPP_NOT_READY \ + (_NET_MGMT_WPA_SUPP_EVENT | NET_EVENT_WPA_SUPP_CMD_NOT_READY) + +#define NET_EVENT_WPA_SUPP_IFACE_ADDED \ + (_NET_MGMT_WPA_SUPP_EVENT | NET_EVENT_WPA_SUPP_CMD_IFACE_ADDED) + +#define NET_EVENT_WPA_SUPP_IFACE_REMOVED \ + (_NET_MGMT_WPA_SUPP_EVENT | NET_EVENT_WPA_SUPP_CMD_IFACE_REMOVED) + +#define NET_EVENT_WPA_SUPP_IFACE_REMOVING \ + (_NET_MGMT_WPA_SUPP_EVENT | NET_EVENT_WPA_SUPP_CMD_IFACE_REMOVING) + +#define NET_EVENT_WPA_SUPP_INT_EVENT \ + (_NET_MGMT_WPA_SUPP_EVENT | NET_EVENT_WPA_SUPP_CMD_INT_EVENT) + +int send_wifi_mgmt_event(const char *ifname, enum net_event_wifi_cmd event, void *status, + size_t len); +int generate_supp_state_event(const char *ifname, enum net_event_wpa_supp_cmd event, int status); + +#define REASON_CODE_LEN 18 +#define NM_WIFI_EVENT_STR_LEN 64 +#define ETH_ALEN 6 + +union supp_event_data { + struct supp_event_auth_reject { + int auth_type; + int auth_transaction; + int status_code; + uint8_t bssid[ETH_ALEN]; + } auth_reject; + + struct supp_event_connected { + uint8_t bssid[ETH_ALEN]; + char ssid[WIFI_SSID_MAX_LEN]; + int id; + } connected; + + struct supp_event_disconnected { + uint8_t bssid[ETH_ALEN]; + int reason_code; + int locally_generated; + } disconnected; + + struct supp_event_assoc_reject { + int status_code; + int reason_code; + } assoc_reject; + + struct supp_event_temp_disabled { + int id; + char ssid[WIFI_SSID_MAX_LEN]; + unsigned int auth_failures; + unsigned int duration; + char reason_code[REASON_CODE_LEN]; + } temp_disabled; + + struct supp_event_reenabled { + int id; + char ssid[WIFI_SSID_MAX_LEN]; + } reenabled; + + struct supp_event_bss_added { + unsigned int id; + uint8_t bssid[ETH_ALEN]; + } bss_added; + + struct supp_event_bss_removed { + unsigned int id; + uint8_t bssid[ETH_ALEN]; + } bss_removed; + + struct supp_event_network_added { + unsigned int id; + } network_added; + + struct supp_event_network_removed { + unsigned int id; + } network_removed; + + char supp_event_str[NM_WIFI_EVENT_STR_LEN]; +}; + +enum supp_event_num { + WPA_SUPP_EVENT_CONNECTED, + WPA_SUPP_EVENT_DISCONNECTED, + WPA_SUPP_EVENT_ASSOC_REJECT, + WPA_SUPP_EVENT_AUTH_REJECT, + WPA_SUPP_EVENT_TERMINATING, + WPA_SUPP_EVENT_SSID_TEMP_DISABLED, + WPA_SUPP_EVENT_SSID_REENABLED, + WPA_SUPP_EVENT_SCAN_STARTED, + WPA_SUPP_EVENT_SCAN_RESULTS, + WPA_SUPP_EVENT_SCAN_FAILED, + WPA_SUPP_EVENT_BSS_ADDED, + WPA_SUPP_EVENT_BSS_REMOVED, + WPA_SUPP_EVENT_NETWORK_NOT_FOUND, + WPA_SUPP_EVENT_NETWORK_ADDED, + WPA_SUPP_EVENT_NETWORK_REMOVED, + WPA_SUPP_EVENT_DSCP_POLICY, +}; + + + +struct supp_int_event_data { + enum supp_event_num event; + void *data; + size_t data_len; +}; + +#endif /* __SUPP_EVENTS_H__ */ diff --git a/modules/hostap/src/supp_main.c b/modules/hostap/src/supp_main.c new file mode 100644 index 00000000000..2de8d3ab085 --- /dev/null +++ b/modules/hostap/src/supp_main.c @@ -0,0 +1,546 @@ +/* + * Copyright (c) 2023 Nordic Semiconductor ASA + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include +#include +LOG_MODULE_REGISTER(wpa_supplicant, LOG_LEVEL_DBG); + +#if defined(CONFIG_WPA_SUPP_CRYPTO) && !defined(CONFIG_MBEDTLS_ENABLE_HEAP) +#include +#endif /* CONFIG_WPA_SUPP_CRYPTO */ + +#include +#include +#include + +#include "includes.h" +#include "common.h" +#include "eloop.h" +#include "wpa_supplicant/config.h" +#include "wpa_supplicant_i.h" + +#include "fst/fst.h" +#include "includes.h" +#include "p2p_supplicant.h" +#include "driver_i.h" + +#include "supp_main.h" +#include "supp_events.h" +#include "wpa_cli_zephyr.h" + +#include "supp_api.h" + +K_SEM_DEFINE(z_wpas_ready_sem, 0, 1); +#include + +/* Should match with the driver name */ +#define DEFAULT_IFACE_NAME "wlan0" +#define IFACE_MATCHING_PREFIX "wlan" + +static struct net_mgmt_event_callback cb; +struct k_mutex iface_up_mutex; + +struct wpa_global *global; + +static int z_wpas_event_sockpair[2]; + +static void z_wpas_start(void); +static void z_wpas_iface_work_handler(struct k_work *item); + +static K_THREAD_STACK_DEFINE(z_wpa_s_thread_stack, + CONFIG_WIFI_NM_WPA_SUPPLICANT_THREAD_STACK_SIZE); +static struct k_thread z_wpa_s_tid; + +static K_THREAD_STACK_DEFINE(z_wpas_iface_wq_stack, + CONFIG_WIFI_NM_WPA_SUPPLICANT_WQ_STACK_SIZE); + +/* TODO: Debug why wsing system workqueue blocks the driver dedicated + * workqueue? + */ +static struct k_work_q z_wpas_iface_wq; +static K_WORK_DEFINE(z_wpas_iface_work, + z_wpas_iface_work_handler); + +K_MUTEX_DEFINE(z_wpas_event_mutex); + +static const struct wifi_mgmt_ops wpa_supp_ops = { + .scan = z_wpa_supplicant_scan, + .connect = z_wpa_supplicant_connect, + .disconnect = z_wpa_supplicant_disconnect, + .iface_status = z_wpa_supplicant_status, +#ifdef CONFIG_NET_STATISTICS_WIFI + .get_stats = z_wpa_supplicant_get_stats, +#endif + .set_power_save = z_wpa_supplicant_set_power_save, + .set_twt = z_wpa_supplicant_set_twt, + .get_power_save_config = z_wpa_supplicant_get_power_save_config, + .reg_domain = z_wpa_supplicant_reg_domain, +}; + +DEFINE_WIFI_NM_INSTANCE(wpa_supplicant, &wpa_supp_ops); + +#ifdef CONFIG_MATCH_IFACE +static int z_wpas_init_match(struct wpa_global *global) +{ + /* + * The assumption is that the first driver is the primary driver and + * will handle the arrival / departure of interfaces. + */ + if (wpa_drivers[0]->global_init && !global->drv_priv[0]) { + global->drv_priv[0] = wpa_drivers[0]->global_init(global); + if (!global->drv_priv[0]) { + wpa_printf(MSG_ERROR, + "Failed to initialize driver '%s'", + wpa_drivers[0]->name); + return -1; + } + } + + return 0; +} +#endif /* CONFIG_MATCH_IFACE */ + +struct wpa_supplicant *z_wpas_get_handle_by_ifname(const char *ifname) +{ + struct wpa_supplicant *wpa_s = NULL; + int ret = k_sem_take(&z_wpas_ready_sem, K_SECONDS(2)); + + if (ret) { + wpa_printf(MSG_ERROR, "%s: WPA supplicant not ready: %d", __func__, ret); + return NULL; + } + + k_sem_give(&z_wpas_ready_sem); + + wpa_s = wpa_supplicant_get_iface(global, ifname); + if (!wpa_s) { + wpa_printf(MSG_ERROR, + "%s: Unable to get wpa_s handle for %s\n", __func__, ifname); + return NULL; + } + + return wpa_s; +} + +static int z_wpas_get_iface_count(void) +{ + struct wpa_supplicant *wpa_s; + unsigned int count = 0; + + for (wpa_s = global->ifaces; wpa_s; wpa_s = wpa_s->next) { + count += 1; + } + return count; +} + +#define Z_WPA_S_IFACE_NOTIFY_TIMEOUT_MS 1000 +#define Z_WPA_S_IFACE_NOTIFY_RETRY_MS 10 + +static int z_wpas_add_interface(const char *ifname) +{ + struct wpa_supplicant *wpa_s; + struct net_if *iface; + int ret = -1; + int retry = 0, count = Z_WPA_S_IFACE_NOTIFY_TIMEOUT_MS / Z_WPA_S_IFACE_NOTIFY_RETRY_MS; + + wpa_printf(MSG_DEBUG, "Adding interface %s\n", ifname); + + iface = net_if_lookup_by_dev(device_get_binding(ifname)); + if (!iface) { + wpa_printf(MSG_ERROR, "Failed to get net_if handle for %s", ifname); + goto err; + } + + ret = z_wpa_cli_global_cmd_v("interface_add %s %s %s %s", + ifname, "zephyr", "zephyr", "zephyr"); + if (ret) { + wpa_printf(MSG_ERROR, "Failed to add interface: %s", ifname); + goto err; + } + + /* This cannot be through control interface as need the handle */ + while (retry++ < count && !wpa_supplicant_get_iface(global, ifname)) { + k_sleep(K_MSEC(Z_WPA_S_IFACE_NOTIFY_RETRY_MS)); + } + + wpa_s = wpa_supplicant_get_iface(global, ifname); + if (wpa_s == NULL) { + wpa_printf(MSG_ERROR, "Failed to add iface: %s", ifname); + goto err; + } + + wpa_s->conf->filter_ssids = 1; + wpa_s->conf->ap_scan = 1; + + /* Default interface, kick start wpa_supplicant */ + if (z_wpas_get_iface_count() == 1) { + k_mutex_unlock(&iface_up_mutex); + } + + ret = z_wpa_ctrl_init(wpa_s); + if (ret) { + wpa_printf(MSG_ERROR, "Failed to initialize control interface"); + goto err; + } + + ret = wifi_nm_register_mgd_iface(wifi_nm_get_instance("wifi_supplicant"), iface); + + if (ret) { + wpa_printf(MSG_ERROR, "Failed to register mgd iface with native stack: %s (%d)", + ifname, ret); + goto err; + } + + generate_supp_state_event(ifname, NET_EVENT_WPA_SUPP_CMD_IFACE_ADDED, 0); + + if (z_wpas_get_iface_count() == 1) { + generate_supp_state_event(ifname, NET_EVENT_WPA_SUPP_CMD_READY, 0); + } + + return 0; +err: + return ret; +} + +static int z_wpas_remove_interface(const char *ifname) +{ + int ret = -1; + union wpa_event_data *event = os_zalloc(sizeof(*event)); + struct wpa_supplicant *wpa_s = wpa_supplicant_get_iface(global, ifname); + struct net_if *iface = net_if_lookup_by_dev(device_get_binding(ifname)); + + int retry = 0, count = Z_WPA_S_IFACE_NOTIFY_TIMEOUT_MS / Z_WPA_S_IFACE_NOTIFY_RETRY_MS; + + if (!event) { + wpa_printf(MSG_ERROR, "Failed to allocate event data"); + goto err; + } + + if (!wpa_s) { + wpa_printf(MSG_ERROR, "Failed to get wpa_s handle for %s", ifname); + goto err; + } + + if (!iface) { + wpa_printf(MSG_ERROR, "Failed to get net_if handle for %s", ifname); + goto err; + } + + generate_supp_state_event(ifname, NET_EVENT_WPA_SUPP_CMD_IFACE_REMOVING, 0); + wpa_printf(MSG_DEBUG, "Remove interface %s\n", ifname); + + os_memcpy(event->interface_status.ifname, ifname, IFNAMSIZ); + event->interface_status.ievent = EVENT_INTERFACE_REMOVED; + + struct wpa_supplicant_event_msg msg = { + .global = true, + .ctx = global, + .event = EVENT_INTERFACE_STATUS, + .data = event, + }; + + z_wpas_send_event(&msg); + + while (retry++ < count && + wpa_s->wpa_state != WPA_INTERFACE_DISABLED) { + k_sleep(K_MSEC(Z_WPA_S_IFACE_NOTIFY_RETRY_MS)); + } + + if (wpa_s->wpa_state != WPA_INTERFACE_DISABLED) { + wpa_printf(MSG_ERROR, "Failed to notify remove interface: %s", ifname); + generate_supp_state_event(ifname, NET_EVENT_WPA_SUPP_CMD_IFACE_REMOVED, + -1); + goto err; + } + + z_wpa_ctrl_deinit(wpa_s); + + ret = z_wpa_cli_global_cmd_v("interface_remove %s", ifname); + if (ret) { + wpa_printf(MSG_ERROR, "Failed to remove interface: %s", ifname); + generate_supp_state_event(ifname, NET_EVENT_WPA_SUPP_CMD_IFACE_REMOVED, + -EINVAL); + goto err; + } + + ret = wifi_nm_unregister_mgd_iface(wifi_nm_get_instance("wpa_supplicant"), iface); + if (ret) { + wpa_printf(MSG_ERROR, "Failed to unregister mgd iface with native stack: %s (%d)", + ifname, ret); + goto err; + } + + + if (z_wpas_get_iface_count() == 0) { + generate_supp_state_event(ifname, NET_EVENT_WPA_SUPP_CMD_NOT_READY, 0); + } + + generate_supp_state_event(ifname, NET_EVENT_WPA_SUPP_CMD_IFACE_REMOVED, 0); + + return 0; +err: + if (event) { + os_free(event); + } + return ret; +} + +static void iface_event_handler(struct net_mgmt_event_callback *cb, + uint32_t mgmt_event, struct net_if *iface) +{ + const char *ifname = iface->if_dev->dev->name; + + if (strncmp(ifname, IFACE_MATCHING_PREFIX, sizeof(IFACE_MATCHING_PREFIX) - 1) != 0) { + return; + } + + wpa_printf(MSG_DEBUG, "Event: %d", mgmt_event); + if (mgmt_event == NET_EVENT_IF_ADMIN_UP) { + z_wpas_add_interface(ifname); + } else if (mgmt_event == NET_EVENT_IF_ADMIN_DOWN) { + z_wpas_remove_interface(ifname); + } +} + +static void register_iface_events(void) +{ + k_mutex_init(&iface_up_mutex); + + k_mutex_lock(&iface_up_mutex, K_FOREVER); + net_mgmt_init_event_callback(&cb, iface_event_handler, + NET_EVENT_IF_ADMIN_UP | NET_EVENT_IF_ADMIN_DOWN); + net_mgmt_add_event_callback(&cb); +} + +static void wait_for_interface_up(const char *iface_name) +{ + if (z_wpas_get_iface_count() == 0) { + k_mutex_lock(&iface_up_mutex, K_FOREVER); + } +} + +#include "config.h" +static void iface_cb(struct net_if *iface, void *user_data) +{ + const char *ifname = iface->if_dev->dev->name; + + if (ifname == NULL) { + return; + } + + if (strncmp(ifname, DEFAULT_IFACE_NAME, strlen(ifname)) != 0) { + return; + } + + /* Check default interface */ + if (net_if_is_admin_up(iface)) { + z_wpas_add_interface(ifname); + } + + register_iface_events(); +} + + +static void z_wpas_iface_work_handler(struct k_work *item) +{ + ARG_UNUSED(item); + + int ret = k_sem_take(&z_wpas_ready_sem, K_SECONDS(5)); + + if (ret) { + wpa_printf(MSG_ERROR, "Timed out waiting for wpa_supplicant"); + return; + } + + net_if_foreach(iface_cb, NULL); + wait_for_interface_up(DEFAULT_IFACE_NAME); + + k_sem_give(&z_wpas_ready_sem); +} + +static void z_wpas_event_sock_handler(int sock, void *eloop_ctx, void *sock_ctx) +{ + int ret; + + ARG_UNUSED(eloop_ctx); + ARG_UNUSED(sock_ctx); + struct wpa_supplicant_event_msg msg; + + ret = recv(sock, &msg, sizeof(msg), 0); + + if (ret < 0) { + wpa_printf(MSG_ERROR, "Failed to recv the message: %s", strerror(errno)); + return; + } + + if (ret != sizeof(msg)) { + wpa_printf(MSG_ERROR, "Received incomplete message: got: %d, expected:%d", + ret, sizeof(msg)); + return; + } + + wpa_printf(MSG_DEBUG, "Passing message %d to wpa_supplicant", msg.event); + + if (msg.global) { + wpa_supplicant_event_global(msg.ctx, msg.event, msg.data); + } else { + wpa_supplicant_event(msg.ctx, msg.event, msg.data); + } + + if (msg.data) { + if (msg.event == EVENT_AUTH) { + union wpa_event_data *data = msg.data; + + os_free((char *)data->auth.ies); + } + os_free(msg.data); + } +} + +static int register_wpa_event_sock(void) +{ + int ret; + + ret = socketpair(AF_UNIX, SOCK_STREAM, 0, z_wpas_event_sockpair); + + if (ret != 0) { + wpa_printf(MSG_ERROR, "Failed to initialize socket: %s", strerror(errno)); + return -1; + } + + eloop_register_read_sock(z_wpas_event_sockpair[0], z_wpas_event_sock_handler, NULL, NULL); + + return 0; +} + +int z_wpas_send_event(const struct wpa_supplicant_event_msg *msg) +{ + int ret; + unsigned int retry = 0; + + k_mutex_lock(&z_wpas_event_mutex, K_FOREVER); + + if (z_wpas_event_sockpair[1] < 0) { + goto err; + } + +retry_send: + ret = send(z_wpas_event_sockpair[1], msg, sizeof(*msg), 0); + if (ret < 0) { + if (errno == EINTR || errno == EAGAIN || errno == EBUSY || errno == EWOULDBLOCK) { + k_msleep(2); + if (retry++ < 3) { + goto retry_send; + } else { + wpa_printf(MSG_WARNING, "Event send fail (max retries): %s", + strerror(errno)); + goto err; + } + } else { + wpa_printf(MSG_WARNING, "Event send fail: %s", + strerror(errno)); + goto err; + } + } + + ret = 0; +err: + k_mutex_unlock(&z_wpas_event_mutex); + return -1; +} + +static void z_wpas_start(void) +{ + struct wpa_params params; + int exitcode = -1; + +#if defined(CONFIG_WPA_SUPP_CRYPTO) && !defined(CONFIG_MBEDTLS_ENABLE_HEAP) + /* Needed for crypto operation as default is no-op and fails */ + mbedtls_platform_set_calloc_free(calloc, free); +#endif /* CONFIG_WPA_CRYPTO */ + + k_work_queue_init(&z_wpas_iface_wq); + + k_work_queue_start(&z_wpas_iface_wq, + z_wpas_iface_wq_stack, + K_THREAD_STACK_SIZEOF(z_wpas_iface_wq_stack), + 7, + NULL); + + os_memset(¶ms, 0, sizeof(params)); + params.wpa_debug_level = CONFIG_WIFI_NM_WPA_SUPPLICANT_DEBUG_LEVEL; + + exitcode = 0; + global = wpa_supplicant_init(¶ms); + if (global == NULL) { + wpa_printf(MSG_ERROR, "Failed to initialize wpa_supplicant"); + exitcode = -1; + goto out; + } else { + wpa_printf(MSG_INFO, "Successfully initialized " + "wpa_supplicant"); + } + + if (fst_global_init()) { + wpa_printf(MSG_ERROR, "Failed to initialize FST"); + exitcode = -1; + goto out; + } + +#if defined(CONFIG_FST) && defined(CONFIG_CTRL_IFACE) + if (!fst_global_add_ctrl(fst_ctrl_cli)) { + wpa_printf(MSG_WARNING, "Failed to add CLI FST ctrl"); + } +#endif + z_global_wpa_ctrl_init(); + + register_wpa_event_sock(); + + k_work_submit_to_queue(&z_wpas_iface_wq, &z_wpas_iface_work); + +#ifdef CONFIG_MATCH_IFACE + if (exitcode == 0) { + exitcode = z_wpas_init_match(global); + } +#endif /* CONFIG_MATCH_IFACE */ + + if (exitcode == 0) { + k_sem_give(&z_wpas_ready_sem); + exitcode = wpa_supplicant_run(global); + } + + generate_supp_state_event(DEFAULT_IFACE_NAME, NET_EVENT_WPA_SUPP_CMD_NOT_READY, 0); + eloop_unregister_read_sock(z_wpas_event_sockpair[0]); + + z_global_wpa_ctrl_deinit(); + wpa_supplicant_deinit(global); + + fst_global_deinit(); + + close(z_wpas_event_sockpair[0]); + close(z_wpas_event_sockpair[1]); + +out: +#ifdef CONFIG_MATCH_IFACE + os_free(params.match_ifaces); +#endif /* CONFIG_MATCH_IFACE */ + os_free(params.pid_file); + + wpa_printf(MSG_INFO, "z_wpas_start: exitcode %d", exitcode); +} + +static int z_wpas_init(void) +{ + k_thread_create(&z_wpa_s_tid, z_wpa_s_thread_stack, + CONFIG_WIFI_NM_WPA_SUPPLICANT_THREAD_STACK_SIZE, + (k_thread_entry_t)z_wpas_start, + NULL, NULL, NULL, + 0, 0, K_NO_WAIT); + + return 0; +} + +SYS_INIT(z_wpas_init, APPLICATION, 0); diff --git a/modules/hostap/src/supp_main.h b/modules/hostap/src/supp_main.h new file mode 100644 index 00000000000..bd002025750 --- /dev/null +++ b/modules/hostap/src/supp_main.h @@ -0,0 +1,19 @@ +/* + * Copyright (c) 2023 Nordic Semiconductor ASA + * + * SPDX-License-Identifier: Apache-2.0 + */ +#ifndef __SUPP_MAIN_H_ +#define __SUPP_MAIN_H_ + +#include "wpa_supplicant_i.h" + +struct wpa_supplicant *z_wpas_get_handle_by_ifname(const char *ifname); +struct wpa_supplicant_event_msg { + bool global; + void *ctx; + unsigned int event; + void *data; +}; +int z_wpas_send_event(const struct wpa_supplicant_event_msg *msg); +#endif /* __SUPP_MAIN_H_ */ diff --git a/modules/hostap/src/wpa_cli.c b/modules/hostap/src/wpa_cli.c new file mode 100644 index 00000000000..2a61d274e33 --- /dev/null +++ b/modules/hostap/src/wpa_cli.c @@ -0,0 +1,38 @@ +/* + * Copyright (c) 2023 Nordic Semiconductor ASA + * + * SPDX-License-Identifier: Apache-2.0 + */ + +/* @file + * @brief wpa_cli implementation for Zephyr OS + */ + +#include +#include +#include + +#include "wpa_cli_zephyr.h" + +static int cmd_wpa_cli(const struct shell *sh, + size_t argc, + const char *argv[]) +{ + ARG_UNUSED(sh); + + if (argc == 1) { + shell_error(sh, "Missing argument"); + return -EINVAL; + } + + /* Remove wpa_cli from the argument list */ + return z_wpa_ctrl_zephyr_cmd(argc - 1, &argv[1]); +} + +/* Persisting with "wpa_cli" naming for compatibility with Wi-Fi + * certification applications and scripts. + */ +SHELL_CMD_REGISTER(wpa_cli, + NULL, + "wpa_cli commands (only for internal use)", + cmd_wpa_cli); From 9ef7ed0a7918dc8c7b34b0062079f75fb80b7eef Mon Sep 17 00:00:00 2001 From: Jukka Rissanen Date: Fri, 27 Oct 2023 14:31:53 +0300 Subject: [PATCH 2942/3723] manifest: Update hostap information New hostap version available. Signed-off-by: Jukka Rissanen --- west.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/west.yml b/west.yml index 548d063351c..7a25afd58da 100644 --- a/west.yml +++ b/west.yml @@ -256,7 +256,7 @@ manifest: - name: hostap repo-path: hostap path: modules/lib/hostap - revision: 7adaff26baa48e26a32c576125e0a749a5239b12 + revision: dee924caf7218d0ee2c2698c217559b1292a46d0 - name: libmetal revision: 243eed541b9c211a2ce8841c788e62ddce84425e path: modules/hal/libmetal From e352a6e8e9acdaf682b50119605cae3c62773186 Mon Sep 17 00:00:00 2001 From: Jukka Rissanen Date: Mon, 30 Oct 2023 16:29:05 +0200 Subject: [PATCH 2943/3723] wifi: Have a separate wifi_drv_ops in wifi_mgmt_offload struct There is no need to hide the wpa_supplicant interface struct so add it directly to net_wifi_mgmt_offload struct. Signed-off-by: Jukka Rissanen --- include/zephyr/net/wifi_mgmt.h | 11 +++++++++++ modules/hostap/src/supp_api.c | 5 ++--- 2 files changed, 13 insertions(+), 3 deletions(-) diff --git a/include/zephyr/net/wifi_mgmt.h b/include/zephyr/net/wifi_mgmt.h index c287db650cb..e0930d2f106 100644 --- a/include/zephyr/net/wifi_mgmt.h +++ b/include/zephyr/net/wifi_mgmt.h @@ -871,8 +871,19 @@ struct net_wifi_mgmt_offload { #endif /** Wi-Fi management API */ const struct wifi_mgmt_ops *const wifi_mgmt_api; + +#if defined(CONFIG_WIFI_NM_WPA_SUPPLICANT) || defined(__DOXYGEN__) + /** Wi-Fi supplicant driver API */ + void *wifi_drv_ops; +#endif }; +#if defined(CONFIG_WIFI_NM_WPA_SUPPLICANT) +/* Make sure wifi_drv_ops is after wifi_mgmt_api */ +BUILD_ASSERT(offsetof(struct net_wifi_mgmt_offload, wifi_mgmt_api) < + offsetof(struct net_wifi_mgmt_offload, wifi_drv_ops)); +#endif + /* Make sure that the network interface API is properly setup inside * Wifi mgmt offload API struct (it is the first one). */ diff --git a/modules/hostap/src/supp_api.c b/modules/hostap/src/supp_api.c index 0f07db37387..62e84686f8d 100644 --- a/modules/hostap/src/supp_api.c +++ b/modules/hostap/src/supp_api.c @@ -462,10 +462,9 @@ int z_wpa_supplicant_status(const struct device *dev, static const struct wifi_mgmt_ops *const get_wifi_mgmt_api(const struct device *dev) { - struct net_wifi_mgmt_offload *off_api = - (struct net_wifi_mgmt_offload *) dev->api; + struct net_wifi_mgmt_offload *api = (struct net_wifi_mgmt_offload *)dev->api; - return off_api ? off_api->wifi_mgmt_api : NULL; + return api ? api->wifi_mgmt_api : NULL; } int z_wpa_supplicant_scan(const struct device *dev, struct wifi_scan_params *params, From 1f79c110a77f2b6ab51ff3ba74f42111fb35d2ff Mon Sep 17 00:00:00 2001 From: Jukka Rissanen Date: Tue, 31 Oct 2023 15:14:41 +0200 Subject: [PATCH 2944/3723] hostap: Various changes to the API to wpa_supplicant Changed the names of the API functions between wpa_supplicant and Zephyr upper layers. For example replaced the z_ prefix by zephyr_ as the z_ is only meant for internal kernel functions. Changed the wpa_supplicant startup so that we do not poll but wait the network interface add event which then adds the network interfaces to the supplicant. Signed-off-by: Jukka Rissanen --- modules/hostap/Kconfig | 25 +- modules/hostap/src/supp_api.c | 181 +++++---- modules/hostap/src/supp_api.h | 33 +- modules/hostap/src/supp_events.c | 171 +++++---- modules/hostap/src/supp_events.h | 128 +++---- modules/hostap/src/supp_main.c | 608 +++++++++++++++---------------- modules/hostap/src/supp_main.h | 7 +- 7 files changed, 585 insertions(+), 568 deletions(-) diff --git a/modules/hostap/Kconfig b/modules/hostap/Kconfig index 8dbe18d7967..5e25c2718b8 100644 --- a/modules/hostap/Kconfig +++ b/modules/hostap/Kconfig @@ -29,6 +29,10 @@ config WIFI_NM_WPA_SUPPLICANT_WQ_STACK_SIZE int "Stack size for wpa_supplicant iface workqueue" default 4096 +config WIFI_NM_WPA_SUPPLICANT_WQ_PRIO + int "Thread priority of wpa_supplicant iface workqueue" + default 7 + # Currently we default POSIX_MAX_FDS to 16 in lib/posix/Kconfig # l2_packet - 1 # ctrl_iface - 2 * socketpairs = 4(local and global) @@ -76,18 +80,6 @@ choice WIFI_NM_WPA_SUPPLICANT_CRYPTO_BACKEND config WIFI_NM_WPA_SUPPLICANT_CRYPTO_PSA bool "PSA Crypto support for WiFi" select WIFI_NM_WPA_SUPPLICANT_WEP - select PSA_WANT_KEY_TYPE_AES - select PSA_WANT_ALG_CMAC - select PSA_WANT_ALG_CBC_PKCS7 - select PSA_WANT_ALG_CTR - select PSA_WANT_ALG_ECDSA - select PSA_WANT_GENERATE_RANDOM - select PSA_WANT_ALG_RSA_PSS - select PSA_WANT_ALG_DETERMINISTIC_ECDSA - select PSA_WANT_ALG_SHA_512 - select PSA_WANT_ALG_SHA_1 - select PSA_WANT_KEY_TYPE_RSA_KEY_PAIR - select PSA_WANT_ECC_SECP_R1_256 # Legacy crypto, still needed #select MBEDTLS #select MBEDTLS_CMAC_C @@ -206,4 +198,13 @@ config NO_PBKDF2 bool default y +config SAE_PK + bool + +config FST + bool + +config TESTING_OPTIONS + bool + endif # WIFI_NM_WPA_SUPPLICANT diff --git a/modules/hostap/src/supp_api.c b/modules/hostap/src/supp_api.c index 62e84686f8d..e7896af919f 100644 --- a/modules/hostap/src/supp_api.c +++ b/modules/hostap/src/supp_api.c @@ -41,13 +41,11 @@ enum status_thread_state { #define DISCONNECT_TIMEOUT_MS 5000 -#define _wpa_cli_cmd_v(cmd, ...) \ - do { \ - if (z_wpa_cli_cmd_v(cmd, ##__VA_ARGS__) < 0) { \ - wpa_printf(MSG_ERROR, "Failed to execute wpa_cli command: %s", cmd); \ - goto out; \ - } \ - } while (0) +#define __wpa_cli_cmd_v(cmd, ...) \ + if (zephyr_wpa_cli_cmd_v(cmd, ##__VA_ARGS__) < 0) { \ + wpa_printf(MSG_ERROR, "Failed to execute wpa_cli command: %s", cmd); \ + goto out; \ + } \ K_MUTEX_DEFINE(wpa_supplicant_mutex); @@ -68,9 +66,31 @@ static void supp_shell_connect_status(struct k_work *work); static K_WORK_DELAYABLE_DEFINE(wpa_supp_status_work, supp_shell_connect_status); -static inline struct wpa_supplicant *get_wpa_s_handle(const struct device *dev) +static struct wpa_supplicant *get_wpa_s_handle(const struct device *dev) { - return z_wpas_get_handle_by_ifname(dev->name); + struct net_if *iface = net_if_lookup_by_dev(dev); + char if_name[CONFIG_NET_INTERFACE_NAME_LEN + 1]; + struct wpa_supplicant *wpa_s; + int ret; + + if (!iface) { + wpa_printf(MSG_ERROR, "Interface for device %s not found", dev->name); + return NULL; + } + + ret = net_if_get_name(iface, if_name, sizeof(if_name)); + if (!ret) { + wpa_printf(MSG_ERROR, "Cannot get interface name (%d)", ret); + return NULL; + } + + wpa_s = zephyr_get_handle_by_ifname(if_name); + if (!wpa_s) { + wpa_printf(MSG_ERROR, "Interface %s not found", if_name); + return NULL; + } + + return wpa_s; } static int wait_for_disconnect_complete(const struct device *dev) @@ -120,11 +140,13 @@ static void supp_shell_connect_status(struct k_work *work) } if (ctrl->requested_op == CONNECT && wpa_s->wpa_state != WPA_COMPLETED) { - if (ctrl->connection_timeout > 0 && seconds_counter++ > ctrl->connection_timeout) { - _wpa_cli_cmd_v("disconnect"); + if (ctrl->connection_timeout > 0 && + seconds_counter++ > ctrl->connection_timeout) { + __wpa_cli_cmd_v("disconnect"); conn_result = -ETIMEDOUT; - send_wifi_mgmt_event(wpa_s->ifname, NET_EVENT_WIFI_CMD_CONNECT_RESULT, - (void *)&conn_result, sizeof(int)); + supplicant_send_wifi_mgmt_event(wpa_s->ifname, + NET_EVENT_WIFI_CMD_CONNECT_RESULT, + (void *)&conn_result, sizeof(int)); status = CONNECTION_FAILURE; goto out; } @@ -145,13 +167,11 @@ static inline void wpa_supp_restart_status_work(void) { /* Terminate synchronously */ wpa_supp_api_ctrl.terminate = 1; - k_work_flush_delayable(&wpa_supp_status_work, - &wpa_supp_api_ctrl.sync); + k_work_flush_delayable(&wpa_supp_status_work, &wpa_supp_api_ctrl.sync); wpa_supp_api_ctrl.terminate = 0; /* Start afresh */ - k_work_reschedule(&wpa_supp_status_work, - K_MSEC(10)); + k_work_reschedule(&wpa_supp_status_work, K_MSEC(10)); } static inline int chan_to_freq(int chan) @@ -203,12 +223,11 @@ static inline enum wifi_security_type wpas_key_mgmt_to_zephyr(int key_mgmt) } /* Public API */ -int z_wpa_supplicant_connect(const struct device *dev, - struct wifi_connect_req_params *params) +int supplicant_connect(const struct device *dev, struct wifi_connect_req_params *params) { + struct add_network_resp resp = {0}; struct wpa_supplicant *wpa_s; int ret = 0; - struct add_network_resp resp = {0}; if (!net_if_is_admin_up(net_if_lookup_by_dev(dev))) { wpa_printf(MSG_ERROR, @@ -222,11 +241,11 @@ int z_wpa_supplicant_connect(const struct device *dev, wpa_s = get_wpa_s_handle(dev); if (!wpa_s) { ret = -1; - wpa_printf(MSG_ERROR, "Interface %s not found", dev->name); + wpa_printf(MSG_ERROR, "Device %s not found", dev->name); goto out; } - _wpa_cli_cmd_v("remove_network all"); + __wpa_cli_cmd_v("remove_network all"); ret = z_wpa_ctrl_add_network(&resp); if (ret) { wpa_printf(MSG_ERROR, "Failed to add network"); @@ -235,31 +254,30 @@ int z_wpa_supplicant_connect(const struct device *dev, wpa_printf(MSG_DEBUG, "NET added: %d\n", resp.network_id); - _wpa_cli_cmd_v("set_network %d ssid \"%s\"", resp.network_id, params->ssid); - _wpa_cli_cmd_v("set_network %d scan_ssid 1", resp.network_id); - _wpa_cli_cmd_v("set_network %d key_mgmt NONE", resp.network_id); - _wpa_cli_cmd_v("set_network %d ieee80211w 0", resp.network_id); + __wpa_cli_cmd_v("set_network %d ssid \"%s\"", resp.network_id, params->ssid); + __wpa_cli_cmd_v("set_network %d scan_ssid 1", resp.network_id); + __wpa_cli_cmd_v("set_network %d key_mgmt NONE", resp.network_id); + __wpa_cli_cmd_v("set_network %d ieee80211w 0", resp.network_id); if (params->security != WIFI_SECURITY_TYPE_NONE) { if (params->security == WIFI_SECURITY_TYPE_SAE) { if (params->sae_password) { - _wpa_cli_cmd_v("set_network %d sae_password \"%s\"", - resp.network_id, params->sae_password); + __wpa_cli_cmd_v("set_network %d sae_password \"%s\"", + resp.network_id, params->sae_password); } else { - _wpa_cli_cmd_v("set_network %d sae_password \"%s\"", - resp.network_id, params->psk); + __wpa_cli_cmd_v("set_network %d sae_password \"%s\"", + resp.network_id, params->psk); } - _wpa_cli_cmd_v("set_network %d key_mgmt SAE", - resp.network_id); + + __wpa_cli_cmd_v("set_network %d key_mgmt SAE", resp.network_id); } else if (params->security == WIFI_SECURITY_TYPE_PSK_SHA256) { - _wpa_cli_cmd_v("set_network %d psk \"%s\"", - resp.network_id, params->psk); - _wpa_cli_cmd_v("set_network %d key_mgmt WPA-PSK-SHA256", - resp.network_id); + __wpa_cli_cmd_v("set_network %d psk \"%s\"", + resp.network_id, params->psk); + __wpa_cli_cmd_v("set_network %d key_mgmt WPA-PSK-SHA256", + resp.network_id); } else if (params->security == WIFI_SECURITY_TYPE_PSK) { - _wpa_cli_cmd_v("set_network %d psk \"%s\"", + __wpa_cli_cmd_v("set_network %d psk \"%s\"", resp.network_id, params->psk); - _wpa_cli_cmd_v("set_network %d key_mgmt WPA-PSK", - resp.network_id); + __wpa_cli_cmd_v("set_network %d key_mgmt WPA-PSK", resp.network_id); } else { ret = -1; wpa_printf(MSG_ERROR, "Unsupported security type: %d", @@ -268,13 +286,13 @@ int z_wpa_supplicant_connect(const struct device *dev, } if (params->mfp) { - _wpa_cli_cmd_v("set_network %d ieee80211w %d", - resp.network_id, params->mfp); + __wpa_cli_cmd_v("set_network %d ieee80211w %d", + resp.network_id, params->mfp); } } /* enable and select network */ - _wpa_cli_cmd_v("enable_network %d", resp.network_id); + __wpa_cli_cmd_v("enable_network %d", resp.network_id); if (params->channel != WIFI_CHANNEL_ANY) { int freq = chan_to_freq(params->channel); @@ -285,12 +303,12 @@ int z_wpa_supplicant_connect(const struct device *dev, params->channel); goto out; } - z_wpa_cli_cmd_v("set_network %d scan_freq %d", - resp.network_id, freq); + zephyr_wpa_cli_cmd_v("set_network %d scan_freq %d", + resp.network_id, freq); } - _wpa_cli_cmd_v("select_network %d", resp.network_id); + __wpa_cli_cmd_v("select_network %d", resp.network_id); - z_wpa_cli_cmd_v("select_network %d", resp.network_id); + zephyr_wpa_cli_cmd_v("select_network %d", resp.network_id); wpa_supp_api_ctrl.dev = dev; wpa_supp_api_ctrl.requested_op = CONNECT; wpa_supp_api_ctrl.connection_timeout = params->timeout; @@ -305,16 +323,16 @@ int z_wpa_supplicant_connect(const struct device *dev, return ret; } -int z_wpa_supplicant_disconnect(const struct device *dev) +int supplicant_disconnect(const struct device *dev) { - struct wpa_supplicant *wpa_s; - int ret = 0; struct net_if *iface = net_if_lookup_by_dev(dev); + struct wpa_supplicant *wpa_s; + int ret; if (!iface) { - ret = -EINVAL; - wpa_printf(MSG_ERROR, "Device %s not found", dev->name); - goto out; + ret = -ENOENT; + wpa_printf(MSG_ERROR, "Interface for device %s not found", dev->name); + return ret; } k_mutex_lock(&wpa_supplicant_mutex, K_FOREVER); @@ -322,19 +340,18 @@ int z_wpa_supplicant_disconnect(const struct device *dev) wpa_s = get_wpa_s_handle(dev); if (!wpa_s) { ret = -EINVAL; - wpa_printf(MSG_ERROR, "Interface %s not found", dev->name); + wpa_printf(MSG_ERROR, "Device %s not found", dev->name); goto out; } wpa_supp_api_ctrl.dev = dev; wpa_supp_api_ctrl.requested_op = DISCONNECT; - _wpa_cli_cmd_v("disconnect"); + __wpa_cli_cmd_v("disconnect"); out: k_mutex_unlock(&wpa_supplicant_mutex); if (ret) { - wpa_printf(MSG_ERROR, "Disconnect failed: %s", - strerror(-ret)); + wpa_printf(MSG_ERROR, "Disconnect failed: %s", strerror(-ret)); return ret; } @@ -347,19 +364,25 @@ int z_wpa_supplicant_disconnect(const struct device *dev) return ret; } -int z_wpa_supplicant_status(const struct device *dev, - struct wifi_iface_status *status) +int supplicant_status(const struct device *dev, struct wifi_iface_status *status) { + struct net_if *iface = net_if_lookup_by_dev(dev); struct wpa_supplicant *wpa_s; int ret = -1; struct wpa_signal_info *si = NULL; struct wpa_conn_info *conn_info = NULL; + if (!iface) { + ret = -ENOENT; + wpa_printf(MSG_ERROR, "Interface for device %s not found", dev->name); + return ret; + } + k_mutex_lock(&wpa_supplicant_mutex, K_FOREVER); wpa_s = get_wpa_s_handle(dev); if (!wpa_s) { - wpa_printf(MSG_ERROR, "Interface %s not found", dev->name); + wpa_printf(MSG_ERROR, "Device %s not found", dev->name); goto out; } @@ -401,17 +424,19 @@ int z_wpa_supplicant_status(const struct device *dev, status->ssid_len = ssid_len; status->iface_mode = ssid->mode; if (wpa_s->connection_set == 1) { - status->link_mode = wpa_s->connection_he ? WIFI_6 : - wpa_s->connection_vht ? WIFI_5 : - wpa_s->connection_ht ? WIFI_4 : - wpa_s->connection_g ? WIFI_3 : - wpa_s->connection_a ? WIFI_2 : - wpa_s->connection_b ? WIFI_1 : - WIFI_0; + status->link_mode = + wpa_s->connection_he ? WIFI_6 : + wpa_s->connection_vht ? WIFI_5 : + wpa_s->connection_ht ? WIFI_4 : + wpa_s->connection_g ? WIFI_3 : + wpa_s->connection_a ? WIFI_2 : + wpa_s->connection_b ? WIFI_1 : + WIFI_0; } else { status->link_mode = WIFI_LINK_MODE_UNKNOWN; } } + ret = z_wpa_ctrl_signal_poll(&signal_poll); if (!ret) { status->rssi = signal_poll.rssi; @@ -429,6 +454,7 @@ int z_wpa_supplicant_status(const struct device *dev, ret = -ENOMEM; goto out; } + ret = wpa_drv_get_conn_info(wpa_s, conn_info); if (!ret) { status->beacon_interval = conn_info->beacon_interval; @@ -442,10 +468,12 @@ int z_wpa_supplicant_status(const struct device *dev, status->twt_capable = false; ret = 0; } + os_free(conn_info); } else { ret = 0; } + out: os_free(si); k_mutex_unlock(&wpa_supplicant_mutex); @@ -467,8 +495,8 @@ static const struct wifi_mgmt_ops *const get_wifi_mgmt_api(const struct device * return api ? api->wifi_mgmt_api : NULL; } -int z_wpa_supplicant_scan(const struct device *dev, struct wifi_scan_params *params, - scan_result_cb_t cb) +int supplicant_scan(const struct device *dev, struct wifi_scan_params *params, + scan_result_cb_t cb) { const struct wifi_mgmt_ops *const wifi_mgmt_api = get_wifi_mgmt_api(dev); @@ -481,8 +509,7 @@ int z_wpa_supplicant_scan(const struct device *dev, struct wifi_scan_params *par } #ifdef CONFIG_NET_STATISTICS_WIFI -int z_wpa_supplicant_get_stats(const struct device *dev, - struct net_stats_wifi *stats) +int supplicant_get_stats(const struct device *dev, struct net_stats_wifi *stats) { const struct wifi_mgmt_ops *const wifi_mgmt_api = get_wifi_mgmt_api(dev); @@ -495,8 +522,7 @@ int z_wpa_supplicant_get_stats(const struct device *dev, } #endif /* CONFIG_NET_STATISTICS_WIFI */ -int z_wpa_supplicant_set_power_save(const struct device *dev, - struct wifi_ps_params *params) +int supplicant_set_power_save(const struct device *dev, struct wifi_ps_params *params) { const struct wifi_mgmt_ops *const wifi_mgmt_api = get_wifi_mgmt_api(dev); @@ -508,8 +534,7 @@ int z_wpa_supplicant_set_power_save(const struct device *dev, return wifi_mgmt_api->set_power_save(dev, params); } -int z_wpa_supplicant_set_twt(const struct device *dev, - struct wifi_twt_params *params) +int supplicant_set_twt(const struct device *dev, struct wifi_twt_params *params) { const struct wifi_mgmt_ops *const wifi_mgmt_api = get_wifi_mgmt_api(dev); @@ -521,8 +546,8 @@ int z_wpa_supplicant_set_twt(const struct device *dev, return wifi_mgmt_api->set_twt(dev, params); } -int z_wpa_supplicant_get_power_save_config(const struct device *dev, - struct wifi_ps_config *config) +int supplicant_get_power_save_config(const struct device *dev, + struct wifi_ps_config *config) { const struct wifi_mgmt_ops *const wifi_mgmt_api = get_wifi_mgmt_api(dev); @@ -534,8 +559,8 @@ int z_wpa_supplicant_get_power_save_config(const struct device *dev, return wifi_mgmt_api->get_power_save_config(dev, config); } -int z_wpa_supplicant_reg_domain(const struct device *dev, - struct wifi_reg_domain *reg_domain) +int supplicant_reg_domain(const struct device *dev, + struct wifi_reg_domain *reg_domain) { const struct wifi_mgmt_ops *const wifi_mgmt_api = get_wifi_mgmt_api(dev); diff --git a/modules/hostap/src/supp_api.h b/modules/hostap/src/supp_api.h index 29e3d0717e5..9be68e59d6e 100644 --- a/modules/hostap/src/supp_api.h +++ b/modules/hostap/src/supp_api.h @@ -9,8 +9,12 @@ #include +#ifndef MAX_SSID_LEN #define MAX_SSID_LEN 32 +#endif +#ifndef MAC_ADDR_LEN #define MAC_ADDR_LEN 6 +#endif /** * @brief Request a connection @@ -20,8 +24,8 @@ * * @return: 0 for OK; -1 for ERROR */ -int z_wpa_supplicant_connect(const struct device *dev, - struct wifi_connect_req_params *params); +int supplicant_connect(const struct device *dev, struct wifi_connect_req_params *params); + /** * @brief Forces station to disconnect and stops any subsequent scan * or connection attempts @@ -30,7 +34,7 @@ int z_wpa_supplicant_connect(const struct device *dev, * * @return: 0 for OK; -1 for ERROR */ -int z_wpa_supplicant_disconnect(const struct device *dev); +int supplicant_disconnect(const struct device *dev); /** * @brief @@ -40,8 +44,7 @@ int z_wpa_supplicant_disconnect(const struct device *dev); * * @return: 0 for OK; -1 for ERROR */ -int z_wpa_supplicant_status(const struct device *dev, - struct wifi_iface_status *status); +int supplicant_status(const struct device *dev, struct wifi_iface_status *status); /** * @brief Request a scan @@ -52,8 +55,8 @@ int z_wpa_supplicant_status(const struct device *dev, * * @return 0 for OK; -1 for ERROR */ -int z_wpa_supplicant_scan(const struct device *dev, struct wifi_scan_params *params, - scan_result_cb_t cb); +int supplicant_scan(const struct device *dev, struct wifi_scan_params *params, + scan_result_cb_t cb); #if defined(CONFIG_NET_STATISTICS_WIFI) || defined(__DOXYGEN__) /** @@ -64,8 +67,7 @@ int z_wpa_supplicant_scan(const struct device *dev, struct wifi_scan_params *par * * @return 0 for OK; -1 for ERROR */ -int z_wpa_supplicant_get_stats(const struct device *dev, - struct net_stats_wifi *stats); +int supplicant_get_stats(const struct device *dev, struct net_stats_wifi *stats); #endif /* CONFIG_NET_STATISTICS_WIFI || __DOXYGEN__ */ /** @@ -76,8 +78,7 @@ int z_wpa_supplicant_get_stats(const struct device *dev, * * @return 0 for OK; -1 for ERROR */ -int z_wpa_supplicant_set_power_save(const struct device *dev, - struct wifi_ps_params *params); +int supplicant_set_power_save(const struct device *dev, struct wifi_ps_params *params); /** * @brief Set Wi-Fi TWT parameters @@ -86,8 +87,7 @@ int z_wpa_supplicant_set_power_save(const struct device *dev, * @param params TWT parameters to set * @return 0 for OK; -1 for ERROR */ -int z_wpa_supplicant_set_twt(const struct device *dev, - struct wifi_twt_params *params); +int supplicant_set_twt(const struct device *dev, struct wifi_twt_params *params); /** * @brief Get Wi-Fi power save configuration @@ -96,8 +96,7 @@ int z_wpa_supplicant_set_twt(const struct device *dev, * @param config Address of power save configuration to fill * @return 0 for OK; -1 for ERROR */ -int z_wpa_supplicant_get_power_save_config(const struct device *dev, - struct wifi_ps_config *config); +int supplicant_get_power_save_config(const struct device *dev, struct wifi_ps_config *config); /** * @brief Set Wi-Fi Regulatory domain @@ -106,6 +105,6 @@ int z_wpa_supplicant_get_power_save_config(const struct device *dev, * @param reg_domain Regulatory domain to set * @return 0 for OK; -1 for ERROR */ -int z_wpa_supplicant_reg_domain(const struct device *dev, - struct wifi_reg_domain *reg_domain); +int supplicant_reg_domain(const struct device *dev, struct wifi_reg_domain *reg_domain); + #endif /* ZEPHYR_SUPP_MGMT_H */ diff --git a/modules/hostap/src/supp_events.c b/modules/hostap/src/supp_events.c index 542944e1039..3fd6c2cb700 100644 --- a/modules/hostap/src/supp_events.c +++ b/modules/hostap/src/supp_events.c @@ -11,7 +11,7 @@ #define MAC_STR_FORMAT "%2hhx:%2hhx:%2hhx:%2hhx:%2hhx:%2hhx" -static char *wpa_supp_event_map[] = { +static const char * const supplicant_event_map[] = { "CTRL-EVENT-CONNECTED", "CTRL-EVENT-DISCONNECTED", "CTRL-EVENT-ASSOC-REJECT", @@ -30,98 +30,103 @@ static char *wpa_supp_event_map[] = { "CTRL-EVENT-DSCP-POLICY", }; -static int wpa_supp_process_status(struct supp_int_event_data *event_data, char *wpa_supp_status) +static int supplicant_process_status(struct supplicant_int_event_data *event_data, + char *supplicant_status) { int ret = 1; /* For cases where parsing is not being done*/ int event = -1; int i; unsigned char *mac; - union supp_event_data *data; + union supplicant_event_data *data; - data = (union supp_event_data *)event_data->data; + data = (union supplicant_event_data *)event_data->data; - for (i = 0; i < ARRAY_SIZE(wpa_supp_event_map); i++) { - if (strncmp(wpa_supp_status, wpa_supp_event_map[i], - strlen(wpa_supp_event_map[i])) == 0) { + for (i = 0; i < ARRAY_SIZE(supplicant_event_map); i++) { + if (strncmp(supplicant_status, supplicant_event_map[i], + strlen(supplicant_event_map[i])) == 0) { event = i; break; } } - if (i >= ARRAY_SIZE(wpa_supp_event_map)) { - wpa_printf(MSG_ERROR, "Event not supported: %s\n", wpa_supp_status); + if (i >= ARRAY_SIZE(supplicant_event_map)) { + wpa_printf(MSG_ERROR, "Event not supported: %s\n", supplicant_status); return -ENOTSUP; } event_data->event = event; switch (event_data->event) { - case WPA_SUPP_EVENT_CONNECTED: + case SUPPLICANT_EVENT_CONNECTED: mac = data->connected.bssid; - ret = sscanf(wpa_supp_status + strlen("CTRL-EVENT-CONNECTED - Connection to"), - MAC_STR_FORMAT, &mac[0], &mac[1], &mac[2], &mac[3], &mac[4], &mac[5]); + ret = sscanf(supplicant_status + + sizeof("CTRL-EVENT-CONNECTED - Connection to") - 1, + MAC_STR_FORMAT, + &mac[0], &mac[1], &mac[2], &mac[3], &mac[4], &mac[5]); event_data->data_len = sizeof(data->connected); break; - case WPA_SUPP_EVENT_DISCONNECTED: + case SUPPLICANT_EVENT_DISCONNECTED: mac = data->disconnected.bssid; - ret = sscanf(wpa_supp_status + strlen("CTRL-EVENT-DISCONNECTED bssid="), - MAC_STR_FORMAT" reason=%d", &mac[0], &mac[1], &mac[2], - &mac[3], &mac[4], &mac[5], &data->disconnected.reason_code); + ret = sscanf(supplicant_status + sizeof("CTRL-EVENT-DISCONNECTED bssid=") - 1, + MAC_STR_FORMAT" reason=%d", &mac[0], &mac[1], &mac[2], + &mac[3], &mac[4], &mac[5], &data->disconnected.reason_code); event_data->data_len = sizeof(data->disconnected); break; - case WPA_SUPP_EVENT_ASSOC_REJECT: + case SUPPLICANT_EVENT_ASSOC_REJECT: /* TODO */ break; - case WPA_SUPP_EVENT_AUTH_REJECT: + case SUPPLICANT_EVENT_AUTH_REJECT: mac = data->auth_reject.bssid; - ret = sscanf(wpa_supp_status + strlen("CTRL-EVENT-AUTH-REJECT "), MAC_STR_FORMAT - " auth_type=%u auth_transaction=%u status_code=%u", - &mac[0], &mac[1], &mac[2], &mac[3], &mac[4], &mac[5], - &data->auth_reject.auth_type, - &data->auth_reject.auth_transaction, - &data->auth_reject.status_code); + ret = sscanf(supplicant_status + sizeof("CTRL-EVENT-AUTH-REJECT ") - 1, + MAC_STR_FORMAT + " auth_type=%u auth_transaction=%u status_code=%u", + &mac[0], &mac[1], &mac[2], &mac[3], &mac[4], &mac[5], + &data->auth_reject.auth_type, + &data->auth_reject.auth_transaction, + &data->auth_reject.status_code); event_data->data_len = sizeof(data->auth_reject); break; - case WPA_SUPP_EVENT_SSID_TEMP_DISABLED: - ret = sscanf(wpa_supp_status + strlen("CTRL-EVENT-SSID-TEMP-DISABLED "), - "id=%d ssid=%s auth_failures=%u duration=%d reason=%s", - &data->temp_disabled.id, data->temp_disabled.ssid, - &data->temp_disabled.auth_failures, - &data->temp_disabled.duration, - data->temp_disabled.reason_code); + case SUPPLICANT_EVENT_SSID_TEMP_DISABLED: + ret = sscanf(supplicant_status + sizeof("CTRL-EVENT-SSID-TEMP-DISABLED ") - 1, + "id=%d ssid=%s auth_failures=%u duration=%d reason=%s", + &data->temp_disabled.id, data->temp_disabled.ssid, + &data->temp_disabled.auth_failures, + &data->temp_disabled.duration, + data->temp_disabled.reason_code); event_data->data_len = sizeof(data->temp_disabled); break; - case WPA_SUPP_EVENT_SSID_REENABLED: - ret = sscanf(wpa_supp_status + strlen("CTRL-EVENT-SSID-REENABLED "), - "id=%d ssid=%s", &data->reenabled.id, - data->reenabled.ssid); + case SUPPLICANT_EVENT_SSID_REENABLED: + ret = sscanf(supplicant_status + sizeof("CTRL-EVENT-SSID-REENABLED ") - 1, + "id=%d ssid=%s", &data->reenabled.id, + data->reenabled.ssid); event_data->data_len = sizeof(data->reenabled); break; - case WPA_SUPP_EVENT_BSS_ADDED: + case SUPPLICANT_EVENT_BSS_ADDED: mac = data->bss_added.bssid; - ret = sscanf(wpa_supp_status + strlen("CTRL-EVENT-BSS-ADDED "), "%u "MAC_STR_FORMAT, - &data->bss_added.id, - &mac[0], &mac[1], &mac[2], &mac[3], &mac[4], &mac[5]); + ret = sscanf(supplicant_status + sizeof("CTRL-EVENT-BSS-ADDED ") - 1, + "%u "MAC_STR_FORMAT, + &data->bss_added.id, + &mac[0], &mac[1], &mac[2], &mac[3], &mac[4], &mac[5]); event_data->data_len = sizeof(data->bss_added); break; - case WPA_SUPP_EVENT_BSS_REMOVED: + case SUPPLICANT_EVENT_BSS_REMOVED: mac = data->bss_removed.bssid; - ret = sscanf(wpa_supp_status + strlen("CTRL-EVENT-BSS-REMOVED "), - "%u "MAC_STR_FORMAT, - &data->bss_removed.id, - &mac[0], &mac[1], &mac[2], &mac[3], &mac[4], &mac[5]); + ret = sscanf(supplicant_status + sizeof("CTRL-EVENT-BSS-REMOVED ") - 1, + "%u "MAC_STR_FORMAT, + &data->bss_removed.id, + &mac[0], &mac[1], &mac[2], &mac[3], &mac[4], &mac[5]); event_data->data_len = sizeof(data->bss_removed); break; - case WPA_SUPP_EVENT_TERMINATING: - case WPA_SUPP_EVENT_SCAN_STARTED: - case WPA_SUPP_EVENT_SCAN_FAILED: - case WPA_SUPP_EVENT_NETWORK_NOT_FOUND: - case WPA_SUPP_EVENT_NETWORK_ADDED: - case WPA_SUPP_EVENT_NETWORK_REMOVED: - strncpy(data->supp_event_str, wpa_supp_event_map[event], - sizeof(data->supp_event_str)); - event_data->data_len = strlen(data->supp_event_str) + 1; - case WPA_SUPP_EVENT_DSCP_POLICY: + case SUPPLICANT_EVENT_TERMINATING: + case SUPPLICANT_EVENT_SCAN_STARTED: + case SUPPLICANT_EVENT_SCAN_FAILED: + case SUPPLICANT_EVENT_NETWORK_NOT_FOUND: + case SUPPLICANT_EVENT_NETWORK_ADDED: + case SUPPLICANT_EVENT_NETWORK_REMOVED: + strncpy(data->supplicant_event_str, supplicant_event_map[event], + sizeof(data->supplicant_event_str)); + event_data->data_len = strlen(data->supplicant_event_str) + 1; + case SUPPLICANT_EVENT_DSCP_POLICY: /* TODO */ break; default: @@ -130,19 +135,18 @@ static int wpa_supp_process_status(struct supp_int_event_data *event_data, char if (ret <= 0) { wpa_printf(MSG_ERROR, "%s Parse failed: %s", - wpa_supp_event_map[event_data->event], strerror(errno)); + supplicant_event_map[event_data->event], strerror(errno)); } return ret; } -int send_wifi_mgmt_event(const char *ifname, enum net_event_wifi_cmd event, - void *wpa_supp_status, size_t len) +int supplicant_send_wifi_mgmt_event(const char *ifname, enum net_event_wifi_cmd event, + void *supplicant_status, size_t len) { - const struct device *dev = device_get_binding(ifname); - struct net_if *iface = net_if_lookup_by_dev(dev); - union supp_event_data data; - struct supp_int_event_data event_data; + struct net_if *iface = net_if_get_by_index(net_if_get_by_name(ifname)); + union supplicant_event_data data; + struct supplicant_int_event_data event_data; if (!iface) { wpa_printf(MSG_ERROR, "Could not find iface for %s", ifname); @@ -151,15 +155,15 @@ int send_wifi_mgmt_event(const char *ifname, enum net_event_wifi_cmd event, switch (event) { case NET_EVENT_WIFI_CMD_CONNECT_RESULT: - wifi_mgmt_raise_connect_result_event(iface, *(int *)wpa_supp_status); + wifi_mgmt_raise_connect_result_event(iface, *(int *)supplicant_status); break; case NET_EVENT_WIFI_CMD_DISCONNECT_RESULT: - wifi_mgmt_raise_disconnect_result_event(iface, *(int *)wpa_supp_status); + wifi_mgmt_raise_disconnect_result_event(iface, *(int *)supplicant_status); break; - case NET_EVENT_WPA_SUPP_CMD_INT_EVENT: + case NET_EVENT_SUPPLICANT_CMD_INT_EVENT: event_data.data = &data; - if (wpa_supp_process_status(&event_data, (char *)wpa_supp_status) > 0) { - net_mgmt_event_notify_with_info(NET_EVENT_WPA_SUPP_INT_EVENT, + if (supplicant_process_status(&event_data, (char *)supplicant_status) > 0) { + net_mgmt_event_notify_with_info(NET_EVENT_SUPPLICANT_INT_EVENT, iface, &event_data, sizeof(event_data)); } break; @@ -171,38 +175,33 @@ int send_wifi_mgmt_event(const char *ifname, enum net_event_wifi_cmd event, return 0; } -int generate_supp_state_event(const char *ifname, enum net_event_wpa_supp_cmd event, int status) +int supplicant_generate_state_event(const char *ifname, + enum net_event_supplicant_cmd event, + int status) { - /* TODO: Replace device_get_binding. */ - const struct device *dev = device_get_binding(ifname); - - if (!dev) { - wpa_printf(MSG_ERROR, "Could not find device for %s", ifname); - return -ENODEV; - } - - struct net_if *iface = net_if_lookup_by_dev(dev); + struct net_if *iface; + iface = net_if_get_by_index(net_if_get_by_name(ifname)); if (!iface) { wpa_printf(MSG_ERROR, "Could not find iface for %s", ifname); return -ENODEV; } switch (event) { - case NET_EVENT_WPA_SUPP_CMD_READY: - net_mgmt_event_notify(NET_EVENT_WPA_SUPP_READY, iface); + case NET_EVENT_SUPPLICANT_CMD_READY: + net_mgmt_event_notify(NET_EVENT_SUPPLICANT_READY, iface); break; - case NET_EVENT_WPA_SUPP_CMD_NOT_READY: - net_mgmt_event_notify(NET_EVENT_WPA_SUPP_NOT_READY, iface); + case NET_EVENT_SUPPLICANT_CMD_NOT_READY: + net_mgmt_event_notify(NET_EVENT_SUPPLICANT_NOT_READY, iface); break; - case NET_EVENT_WPA_SUPP_CMD_IFACE_ADDED: - net_mgmt_event_notify(NET_EVENT_WPA_SUPP_IFACE_ADDED, iface); + case NET_EVENT_SUPPLICANT_CMD_IFACE_ADDED: + net_mgmt_event_notify(NET_EVENT_SUPPLICANT_IFACE_ADDED, iface); break; - case NET_EVENT_WPA_SUPP_CMD_IFACE_REMOVING: - net_mgmt_event_notify(NET_EVENT_WPA_SUPP_IFACE_REMOVING, iface); + case NET_EVENT_SUPPLICANT_CMD_IFACE_REMOVING: + net_mgmt_event_notify(NET_EVENT_SUPPLICANT_IFACE_REMOVING, iface); break; - case NET_EVENT_WPA_SUPP_CMD_IFACE_REMOVED: - net_mgmt_event_notify_with_info(NET_EVENT_WPA_SUPP_IFACE_REMOVED, + case NET_EVENT_SUPPLICANT_CMD_IFACE_REMOVED: + net_mgmt_event_notify_with_info(NET_EVENT_SUPPLICANT_IFACE_REMOVED, iface, &status, sizeof(status)); break; default: diff --git a/modules/hostap/src/supp_events.h b/modules/hostap/src/supp_events.h index 5296aad2da3..41e64d57f54 100644 --- a/modules/hostap/src/supp_events.h +++ b/modules/hostap/src/supp_events.h @@ -10,75 +10,79 @@ #include /* Connectivity Events */ -#define _NET_MGMT_WPA_SUPP_LAYER NET_MGMT_LAYER_L2 -#define _NET_MGMT_WPA_SUPP_CODE 0x157 -#define _NET_MGMT_WPA_SUPP_BASE (NET_MGMT_LAYER(_NET_MGMT_WPA_SUPP_LAYER) | \ - NET_MGMT_LAYER_CODE(_NET_MGMT_WPA_SUPP_CODE) | \ - NET_MGMT_IFACE_BIT) -#define _NET_MGMT_WPA_SUPP_EVENT (NET_MGMT_EVENT_BIT | _NET_MGMT_WPA_SUPP_BASE) - -enum net_event_wpa_supp_cmd { - NET_EVENT_WPA_SUPP_CMD_READY = 1, - NET_EVENT_WPA_SUPP_CMD_NOT_READY, - NET_EVENT_WPA_SUPP_CMD_IFACE_ADDED, - NET_EVENT_WPA_SUPP_CMD_IFACE_REMOVING, - NET_EVENT_WPA_SUPP_CMD_IFACE_REMOVED, - NET_EVENT_WPA_SUPP_CMD_INT_EVENT, - NET_EVENT_WPA_SUPP_CMD_MAX +#define _NET_MGMT_SUPPLICANT_LAYER NET_MGMT_LAYER_L3 +#define _NET_MGMT_SUPPLICANT_CODE 0x157 +#define _NET_MGMT_SUPPLICANT_BASE (NET_MGMT_LAYER(_NET_MGMT_SUPPLICANT_LAYER) | \ + NET_MGMT_LAYER_CODE(_NET_MGMT_SUPPLICANT_CODE) | \ + NET_MGMT_IFACE_BIT) +#define _NET_MGMT_SUPPLICANT_EVENT (NET_MGMT_EVENT_BIT | _NET_MGMT_SUPPLICANT_BASE) + +enum net_event_supplicant_cmd { + NET_EVENT_SUPPLICANT_CMD_READY = 1, + NET_EVENT_SUPPLICANT_CMD_NOT_READY, + NET_EVENT_SUPPLICANT_CMD_IFACE_ADDED, + NET_EVENT_SUPPLICANT_CMD_IFACE_REMOVING, + NET_EVENT_SUPPLICANT_CMD_IFACE_REMOVED, + NET_EVENT_SUPPLICANT_CMD_INT_EVENT, + NET_EVENT_WIFI_CMD_MAX }; -#define NET_EVENT_WPA_SUPP_READY \ - (_NET_MGMT_WPA_SUPP_EVENT | NET_EVENT_WPA_SUPP_CMD_READY) +#define NET_EVENT_SUPPLICANT_READY \ + (_NET_MGMT_SUPPLICANT_EVENT | NET_EVENT_SUPPLICANT_CMD_READY) -#define NET_EVENT_WPA_SUPP_NOT_READY \ - (_NET_MGMT_WPA_SUPP_EVENT | NET_EVENT_WPA_SUPP_CMD_NOT_READY) +#define NET_EVENT_SUPPLICANT_NOT_READY \ + (_NET_MGMT_SUPPLICANT_EVENT | NET_EVENT_SUPPLICANT_CMD_NOT_READY) -#define NET_EVENT_WPA_SUPP_IFACE_ADDED \ - (_NET_MGMT_WPA_SUPP_EVENT | NET_EVENT_WPA_SUPP_CMD_IFACE_ADDED) +#define NET_EVENT_SUPPLICANT_IFACE_ADDED \ + (_NET_MGMT_SUPPLICANT_EVENT | NET_EVENT_SUPPLICANT_CMD_IFACE_ADDED) -#define NET_EVENT_WPA_SUPP_IFACE_REMOVED \ - (_NET_MGMT_WPA_SUPP_EVENT | NET_EVENT_WPA_SUPP_CMD_IFACE_REMOVED) +#define NET_EVENT_SUPPLICANT_IFACE_REMOVED \ + (_NET_MGMT_SUPPLICANT_EVENT | NET_EVENT_SUPPLICANT_CMD_IFACE_REMOVED) -#define NET_EVENT_WPA_SUPP_IFACE_REMOVING \ - (_NET_MGMT_WPA_SUPP_EVENT | NET_EVENT_WPA_SUPP_CMD_IFACE_REMOVING) +#define NET_EVENT_SUPPLICANT_IFACE_REMOVING \ + (_NET_MGMT_SUPPLICANT_EVENT | NET_EVENT_SUPPLICANT_CMD_IFACE_REMOVING) -#define NET_EVENT_WPA_SUPP_INT_EVENT \ - (_NET_MGMT_WPA_SUPP_EVENT | NET_EVENT_WPA_SUPP_CMD_INT_EVENT) +#define NET_EVENT_SUPPLICANT_INT_EVENT \ + (_NET_MGMT_SUPPLICANT_EVENT | NET_EVENT_SUPPLICANT_CMD_INT_EVENT) -int send_wifi_mgmt_event(const char *ifname, enum net_event_wifi_cmd event, void *status, - size_t len); -int generate_supp_state_event(const char *ifname, enum net_event_wpa_supp_cmd event, int status); +int supplicant_send_wifi_mgmt_event(const char *ifname, + enum net_event_wifi_cmd event, + void *status, + size_t len); +int supplicant_generate_state_event(const char *ifname, + enum net_event_supplicant_cmd event, + int status); #define REASON_CODE_LEN 18 #define NM_WIFI_EVENT_STR_LEN 64 #define ETH_ALEN 6 -union supp_event_data { - struct supp_event_auth_reject { +union supplicant_event_data { + struct supplicant_event_auth_reject { int auth_type; int auth_transaction; int status_code; uint8_t bssid[ETH_ALEN]; } auth_reject; - struct supp_event_connected { + struct supplicant_event_connected { uint8_t bssid[ETH_ALEN]; char ssid[WIFI_SSID_MAX_LEN]; int id; } connected; - struct supp_event_disconnected { + struct supplicant_event_disconnected { uint8_t bssid[ETH_ALEN]; int reason_code; int locally_generated; } disconnected; - struct supp_event_assoc_reject { + struct supplicant_event_assoc_reject { int status_code; int reason_code; } assoc_reject; - struct supp_event_temp_disabled { + struct supplicant_event_temp_disabled { int id; char ssid[WIFI_SSID_MAX_LEN]; unsigned int auth_failures; @@ -86,55 +90,53 @@ union supp_event_data { char reason_code[REASON_CODE_LEN]; } temp_disabled; - struct supp_event_reenabled { + struct supplicant_event_reenabled { int id; char ssid[WIFI_SSID_MAX_LEN]; } reenabled; - struct supp_event_bss_added { + struct supplicant_event_bss_added { unsigned int id; uint8_t bssid[ETH_ALEN]; } bss_added; - struct supp_event_bss_removed { + struct supplicant_event_bss_removed { unsigned int id; uint8_t bssid[ETH_ALEN]; } bss_removed; - struct supp_event_network_added { + struct supplicant_event_network_added { unsigned int id; } network_added; - struct supp_event_network_removed { + struct supplicant_event_network_removed { unsigned int id; } network_removed; - char supp_event_str[NM_WIFI_EVENT_STR_LEN]; + char supplicant_event_str[NM_WIFI_EVENT_STR_LEN]; }; -enum supp_event_num { - WPA_SUPP_EVENT_CONNECTED, - WPA_SUPP_EVENT_DISCONNECTED, - WPA_SUPP_EVENT_ASSOC_REJECT, - WPA_SUPP_EVENT_AUTH_REJECT, - WPA_SUPP_EVENT_TERMINATING, - WPA_SUPP_EVENT_SSID_TEMP_DISABLED, - WPA_SUPP_EVENT_SSID_REENABLED, - WPA_SUPP_EVENT_SCAN_STARTED, - WPA_SUPP_EVENT_SCAN_RESULTS, - WPA_SUPP_EVENT_SCAN_FAILED, - WPA_SUPP_EVENT_BSS_ADDED, - WPA_SUPP_EVENT_BSS_REMOVED, - WPA_SUPP_EVENT_NETWORK_NOT_FOUND, - WPA_SUPP_EVENT_NETWORK_ADDED, - WPA_SUPP_EVENT_NETWORK_REMOVED, - WPA_SUPP_EVENT_DSCP_POLICY, +enum supplicant_event_num { + SUPPLICANT_EVENT_CONNECTED, + SUPPLICANT_EVENT_DISCONNECTED, + SUPPLICANT_EVENT_ASSOC_REJECT, + SUPPLICANT_EVENT_AUTH_REJECT, + SUPPLICANT_EVENT_TERMINATING, + SUPPLICANT_EVENT_SSID_TEMP_DISABLED, + SUPPLICANT_EVENT_SSID_REENABLED, + SUPPLICANT_EVENT_SCAN_STARTED, + SUPPLICANT_EVENT_SCAN_RESULTS, + SUPPLICANT_EVENT_SCAN_FAILED, + SUPPLICANT_EVENT_BSS_ADDED, + SUPPLICANT_EVENT_BSS_REMOVED, + SUPPLICANT_EVENT_NETWORK_NOT_FOUND, + SUPPLICANT_EVENT_NETWORK_ADDED, + SUPPLICANT_EVENT_NETWORK_REMOVED, + SUPPLICANT_EVENT_DSCP_POLICY, }; - - -struct supp_int_event_data { - enum supp_event_num event; +struct supplicant_int_event_data { + enum supplicant_event_num event; void *data; size_t data_len; }; diff --git a/modules/hostap/src/supp_main.c b/modules/hostap/src/supp_main.c index 2de8d3ab085..f2e348bba34 100644 --- a/modules/hostap/src/supp_main.c +++ b/modules/hostap/src/supp_main.c @@ -1,388 +1,427 @@ /* - * Copyright (c) 2023 Nordic Semiconductor ASA + * Copyright (c) 2023 Nordic Semiconductor ASA. * * SPDX-License-Identifier: Apache-2.0 */ #include -#include -LOG_MODULE_REGISTER(wpa_supplicant, LOG_LEVEL_DBG); +LOG_MODULE_REGISTER(wifi_supplicant, CONFIG_WIFI_NM_WPA_SUPPLICANT_LOG_LEVEL); -#if defined(CONFIG_WPA_SUPP_CRYPTO) && !defined(CONFIG_MBEDTLS_ENABLE_HEAP) -#include -#endif /* CONFIG_WPA_SUPP_CRYPTO */ +#include +#include +#include -#include -#include +#include #include +#include + +static K_THREAD_STACK_DEFINE(supplicant_thread_stack, + CONFIG_WIFI_NM_WPA_SUPPLICANT_THREAD_STACK_SIZE); +static struct k_thread tid; + +static K_THREAD_STACK_DEFINE(iface_wq_stack, CONFIG_WIFI_NM_WPA_SUPPLICANT_WQ_STACK_SIZE); + +#define IFACE_NOTIFY_TIMEOUT_MS 1000 +#define IFACE_NOTIFY_RETRY_MS 10 + +#include "supp_main.h" +#include "supp_api.h" +#include "supp_events.h" #include "includes.h" #include "common.h" #include "eloop.h" #include "wpa_supplicant/config.h" #include "wpa_supplicant_i.h" - #include "fst/fst.h" #include "includes.h" -#include "p2p_supplicant.h" -#include "driver_i.h" - -#include "supp_main.h" -#include "supp_events.h" #include "wpa_cli_zephyr.h" -#include "supp_api.h" +static const struct wifi_mgmt_ops mgmt_ops = { + .scan = supplicant_scan, + .connect = supplicant_connect, + .disconnect = supplicant_disconnect, + .iface_status = supplicant_status, +#ifdef CONFIG_NET_STATISTICS_WIFI + .get_stats = supplicant_get_stats, +#endif + .set_power_save = supplicant_set_power_save, + .set_twt = supplicant_set_twt, + .get_power_save_config = supplicant_get_power_save_config, + .reg_domain = supplicant_reg_domain, +}; -K_SEM_DEFINE(z_wpas_ready_sem, 0, 1); -#include +DEFINE_WIFI_NM_INSTANCE(wifi_supplicant, &mgmt_ops); -/* Should match with the driver name */ -#define DEFAULT_IFACE_NAME "wlan0" -#define IFACE_MATCHING_PREFIX "wlan" +#define WRITE_TIMEOUT 100 /* ms */ +#define INTERFACE_EVENT_MASK (NET_EVENT_IF_ADMIN_UP | NET_EVENT_IF_ADMIN_DOWN) -static struct net_mgmt_event_callback cb; -struct k_mutex iface_up_mutex; +struct supplicant_context { + struct wpa_global *supplicant; + struct net_mgmt_event_callback cb; + struct net_if *iface; + char if_name[CONFIG_NET_INTERFACE_NAME_LEN + 1]; + int event_socketpair[2]; + struct k_work iface_work; + struct k_work_q iface_wq; + int (*iface_handler)(struct supplicant_context *ctx, struct net_if *iface); +}; -struct wpa_global *global; +static struct supplicant_context *get_default_context(void) +{ + static struct supplicant_context ctx; -static int z_wpas_event_sockpair[2]; + return &ctx; +} -static void z_wpas_start(void); -static void z_wpas_iface_work_handler(struct k_work *item); +struct wpa_global *zephyr_get_default_supplicant_context(void) +{ + return get_default_context()->supplicant; +} -static K_THREAD_STACK_DEFINE(z_wpa_s_thread_stack, - CONFIG_WIFI_NM_WPA_SUPPLICANT_THREAD_STACK_SIZE); -static struct k_thread z_wpa_s_tid; +int zephyr_wifi_send_event(const struct wpa_supplicant_event_msg *msg) +{ + struct supplicant_context *ctx; + struct pollfd fds[1]; + int ret; -static K_THREAD_STACK_DEFINE(z_wpas_iface_wq_stack, - CONFIG_WIFI_NM_WPA_SUPPLICANT_WQ_STACK_SIZE); + /* TODO: Fix this to get the correct container */ + ctx = get_default_context(); -/* TODO: Debug why wsing system workqueue blocks the driver dedicated - * workqueue? - */ -static struct k_work_q z_wpas_iface_wq; -static K_WORK_DEFINE(z_wpas_iface_work, - z_wpas_iface_work_handler); + if (ctx->event_socketpair[1] < 0) { + ret = -ENOENT; + goto out; + } -K_MUTEX_DEFINE(z_wpas_event_mutex); + fds[0].fd = ctx->event_socketpair[0]; + fds[0].events = POLLOUT; + fds[0].revents = 0; -static const struct wifi_mgmt_ops wpa_supp_ops = { - .scan = z_wpa_supplicant_scan, - .connect = z_wpa_supplicant_connect, - .disconnect = z_wpa_supplicant_disconnect, - .iface_status = z_wpa_supplicant_status, -#ifdef CONFIG_NET_STATISTICS_WIFI - .get_stats = z_wpa_supplicant_get_stats, -#endif - .set_power_save = z_wpa_supplicant_set_power_save, - .set_twt = z_wpa_supplicant_set_twt, - .get_power_save_config = z_wpa_supplicant_get_power_save_config, - .reg_domain = z_wpa_supplicant_reg_domain, -}; + ret = zsock_poll(fds, 1, WRITE_TIMEOUT); + if (ret < 0) { + ret = -errno; + LOG_ERR("Cannot write event (%d)", ret); + goto out; + } -DEFINE_WIFI_NM_INSTANCE(wpa_supplicant, &wpa_supp_ops); + ret = zsock_send(ctx->event_socketpair[1], msg, sizeof(*msg), 0); + if (ret < 0) { + ret = -errno; + LOG_WRN("Event send failed (%d)", ret); + goto out; + } -#ifdef CONFIG_MATCH_IFACE -static int z_wpas_init_match(struct wpa_global *global) -{ - /* - * The assumption is that the first driver is the primary driver and - * will handle the arrival / departure of interfaces. - */ - if (wpa_drivers[0]->global_init && !global->drv_priv[0]) { - global->drv_priv[0] = wpa_drivers[0]->global_init(global); - if (!global->drv_priv[0]) { - wpa_printf(MSG_ERROR, - "Failed to initialize driver '%s'", - wpa_drivers[0]->name); - return -1; - } + if (ret != sizeof(*msg)) { + ret = -EMSGSIZE; + LOG_WRN("Event partial send (%d)", ret); + goto out; } - return 0; + ret = 0; + +out: + return ret; } -#endif /* CONFIG_MATCH_IFACE */ -struct wpa_supplicant *z_wpas_get_handle_by_ifname(const char *ifname) +static int send_event(const struct wpa_supplicant_event_msg *msg) { - struct wpa_supplicant *wpa_s = NULL; - int ret = k_sem_take(&z_wpas_ready_sem, K_SECONDS(2)); + return zephyr_wifi_send_event(msg); +} - if (ret) { - wpa_printf(MSG_ERROR, "%s: WPA supplicant not ready: %d", __func__, ret); - return NULL; +static bool is_wanted_interface(struct net_if *iface) +{ + if (!net_if_is_wifi(iface)) { + return false; } - k_sem_give(&z_wpas_ready_sem); + /* TODO: check against a list of valid interfaces */ - wpa_s = wpa_supplicant_get_iface(global, ifname); + return true; +} + +struct wpa_supplicant *zephyr_get_handle_by_ifname(const char *ifname) +{ + struct wpa_supplicant *wpa_s = NULL; + struct supplicant_context *ctx = get_default_context(); + int ret; + + wpa_s = wpa_supplicant_get_iface(ctx->supplicant, ifname); if (!wpa_s) { - wpa_printf(MSG_ERROR, - "%s: Unable to get wpa_s handle for %s\n", __func__, ifname); + wpa_printf(MSG_ERROR, "%s: Unable to get wpa_s handle for %s\n", __func__, ifname); return NULL; } return wpa_s; } -static int z_wpas_get_iface_count(void) +static int get_iface_count(struct supplicant_context *ctx) { + /* FIXME, should not access ifaces as it is supplicant internal data */ struct wpa_supplicant *wpa_s; unsigned int count = 0; - for (wpa_s = global->ifaces; wpa_s; wpa_s = wpa_s->next) { + for (wpa_s = ctx->supplicant->ifaces; wpa_s; wpa_s = wpa_s->next) { count += 1; } + return count; } -#define Z_WPA_S_IFACE_NOTIFY_TIMEOUT_MS 1000 -#define Z_WPA_S_IFACE_NOTIFY_RETRY_MS 10 - -static int z_wpas_add_interface(const char *ifname) +static int add_interface(struct supplicant_context *ctx, struct net_if *iface) { struct wpa_supplicant *wpa_s; - struct net_if *iface; - int ret = -1; - int retry = 0, count = Z_WPA_S_IFACE_NOTIFY_TIMEOUT_MS / Z_WPA_S_IFACE_NOTIFY_RETRY_MS; - - wpa_printf(MSG_DEBUG, "Adding interface %s\n", ifname); + char ifname[IFNAMSIZ + 1] = { 0 }; + int ret, retry = 0, count = IFACE_NOTIFY_TIMEOUT_MS / IFACE_NOTIFY_RETRY_MS; - iface = net_if_lookup_by_dev(device_get_binding(ifname)); - if (!iface) { - wpa_printf(MSG_ERROR, "Failed to get net_if handle for %s", ifname); - goto err; + ret = net_if_get_name(iface, ifname, sizeof(ifname) - 1); + if (ret < 0) { + LOG_ERR("Cannot get interface %d (%p) name", net_if_get_by_iface(iface), iface); + goto out; } - ret = z_wpa_cli_global_cmd_v("interface_add %s %s %s %s", - ifname, "zephyr", "zephyr", "zephyr"); + LOG_DBG("Adding interface %s [%d] (%p)", ifname, net_if_get_by_iface(iface), iface); + + ret = zephyr_wpa_cli_global_cmd_v("interface_add %s %s %s %s", + ifname, "zephyr", "zephyr", "zephyr"); if (ret) { - wpa_printf(MSG_ERROR, "Failed to add interface: %s", ifname); - goto err; + LOG_ERR("Failed to add interface %s", ifname); + goto out; } - /* This cannot be through control interface as need the handle */ - while (retry++ < count && !wpa_supplicant_get_iface(global, ifname)) { - k_sleep(K_MSEC(Z_WPA_S_IFACE_NOTIFY_RETRY_MS)); + while (retry++ < count && !wpa_supplicant_get_iface(ctx->supplicant, ifname)) { + k_sleep(K_MSEC(IFACE_NOTIFY_RETRY_MS)); } - wpa_s = wpa_supplicant_get_iface(global, ifname); + wpa_s = wpa_supplicant_get_iface(ctx->supplicant, ifname); if (wpa_s == NULL) { - wpa_printf(MSG_ERROR, "Failed to add iface: %s", ifname); - goto err; + LOG_ERR("Failed to add iface %s", ifname); + goto out; } wpa_s->conf->filter_ssids = 1; wpa_s->conf->ap_scan = 1; - /* Default interface, kick start wpa_supplicant */ - if (z_wpas_get_iface_count() == 1) { - k_mutex_unlock(&iface_up_mutex); + /* Default interface, kick start supplicant */ + if (get_iface_count(ctx) > 0) { + ctx->iface = iface; + net_if_get_name(iface, ctx->if_name, CONFIG_NET_INTERFACE_NAME_LEN); } - ret = z_wpa_ctrl_init(wpa_s); + ret = zephyr_wpa_ctrl_init(wpa_s); if (ret) { - wpa_printf(MSG_ERROR, "Failed to initialize control interface"); - goto err; + LOG_ERR("Failed to initialize supplicant control interface"); + goto out; } ret = wifi_nm_register_mgd_iface(wifi_nm_get_instance("wifi_supplicant"), iface); - if (ret) { - wpa_printf(MSG_ERROR, "Failed to register mgd iface with native stack: %s (%d)", + LOG_ERR("Failed to register mgd iface with native stack %s (%d)", ifname, ret); - goto err; + goto out; } - generate_supp_state_event(ifname, NET_EVENT_WPA_SUPP_CMD_IFACE_ADDED, 0); + supplicant_generate_state_event(ifname, NET_EVENT_SUPPLICANT_CMD_IFACE_ADDED, 0); - if (z_wpas_get_iface_count() == 1) { - generate_supp_state_event(ifname, NET_EVENT_WPA_SUPP_CMD_READY, 0); + if (get_iface_count(ctx) == 1) { + supplicant_generate_state_event(ifname, NET_EVENT_SUPPLICANT_CMD_READY, 0); } - return 0; -err: + ret = 0; + +out: return ret; } -static int z_wpas_remove_interface(const char *ifname) +static int del_interface(struct supplicant_context *ctx, struct net_if *iface) { - int ret = -1; - union wpa_event_data *event = os_zalloc(sizeof(*event)); - struct wpa_supplicant *wpa_s = wpa_supplicant_get_iface(global, ifname); - struct net_if *iface = net_if_lookup_by_dev(device_get_binding(ifname)); + struct wpa_supplicant_event_msg msg; + struct wpa_supplicant *wpa_s; + union wpa_event_data *event = NULL; + int ret, retry = 0, count = IFACE_NOTIFY_TIMEOUT_MS / IFACE_NOTIFY_RETRY_MS; + char ifname[IFNAMSIZ + 1] = { 0 }; + + ret = net_if_get_name(iface, ifname, sizeof(ifname) - 1); + if (ret < 0) { + LOG_ERR("Cannot get interface %d (%p) name", net_if_get_by_iface(iface), iface); + goto out; + } - int retry = 0, count = Z_WPA_S_IFACE_NOTIFY_TIMEOUT_MS / Z_WPA_S_IFACE_NOTIFY_RETRY_MS; + LOG_DBG("Removing interface %s %d (%p)", ifname, net_if_get_by_iface(iface), iface); + event = os_zalloc(sizeof(*event)); if (!event) { - wpa_printf(MSG_ERROR, "Failed to allocate event data"); - goto err; + ret = -ENOMEM; + LOG_ERR("Failed to allocate event data"); + goto out; } + wpa_s = wpa_supplicant_get_iface(ctx->supplicant, ifname); if (!wpa_s) { - wpa_printf(MSG_ERROR, "Failed to get wpa_s handle for %s", ifname); - goto err; - } - - if (!iface) { - wpa_printf(MSG_ERROR, "Failed to get net_if handle for %s", ifname); - goto err; + ret = -ENOENT; + LOG_ERR("Failed to get wpa_s handle for %s", ifname); + goto out; } - generate_supp_state_event(ifname, NET_EVENT_WPA_SUPP_CMD_IFACE_REMOVING, 0); - wpa_printf(MSG_DEBUG, "Remove interface %s\n", ifname); + supplicant_generate_state_event(ifname, NET_EVENT_SUPPLICANT_CMD_IFACE_REMOVING, 0); os_memcpy(event->interface_status.ifname, ifname, IFNAMSIZ); event->interface_status.ievent = EVENT_INTERFACE_REMOVED; - struct wpa_supplicant_event_msg msg = { - .global = true, - .ctx = global, - .event = EVENT_INTERFACE_STATUS, - .data = event, - }; + msg.global = true; + msg.ctx = ctx->supplicant; + msg.event = EVENT_INTERFACE_STATUS; + msg.data = event; - z_wpas_send_event(&msg); + send_event(&msg); - while (retry++ < count && - wpa_s->wpa_state != WPA_INTERFACE_DISABLED) { - k_sleep(K_MSEC(Z_WPA_S_IFACE_NOTIFY_RETRY_MS)); + while (retry++ < count && wpa_s->wpa_state != WPA_INTERFACE_DISABLED) { + k_sleep(K_MSEC(IFACE_NOTIFY_RETRY_MS)); } if (wpa_s->wpa_state != WPA_INTERFACE_DISABLED) { - wpa_printf(MSG_ERROR, "Failed to notify remove interface: %s", ifname); - generate_supp_state_event(ifname, NET_EVENT_WPA_SUPP_CMD_IFACE_REMOVED, - -1); - goto err; + LOG_ERR("Failed to notify remove interface %s", ifname); + supplicant_generate_state_event(ifname, NET_EVENT_SUPPLICANT_CMD_IFACE_REMOVED, -1); + goto out; } - z_wpa_ctrl_deinit(wpa_s); - - ret = z_wpa_cli_global_cmd_v("interface_remove %s", ifname); + ret = zephyr_wpa_cli_global_cmd_v("interface_remove %s", ifname); if (ret) { - wpa_printf(MSG_ERROR, "Failed to remove interface: %s", ifname); - generate_supp_state_event(ifname, NET_EVENT_WPA_SUPP_CMD_IFACE_REMOVED, - -EINVAL); - goto err; + LOG_ERR("Failed to remove interface %s", ifname); + supplicant_generate_state_event(ifname, NET_EVENT_SUPPLICANT_CMD_IFACE_REMOVED, + -EINVAL); + goto out; } ret = wifi_nm_unregister_mgd_iface(wifi_nm_get_instance("wpa_supplicant"), iface); if (ret) { - wpa_printf(MSG_ERROR, "Failed to unregister mgd iface with native stack: %s (%d)", + LOG_ERR("Failed to unregister mgd iface %s with native stack (%d)", ifname, ret); - goto err; + goto out; } - - if (z_wpas_get_iface_count() == 0) { - generate_supp_state_event(ifname, NET_EVENT_WPA_SUPP_CMD_NOT_READY, 0); + if (get_iface_count(ctx) == 0) { + supplicant_generate_state_event(ifname, NET_EVENT_SUPPLICANT_CMD_NOT_READY, 0); } - generate_supp_state_event(ifname, NET_EVENT_WPA_SUPP_CMD_IFACE_REMOVED, 0); + supplicant_generate_state_event(ifname, NET_EVENT_SUPPLICANT_CMD_IFACE_REMOVED, 0); - return 0; -err: +out: if (event) { os_free(event); } + return ret; } -static void iface_event_handler(struct net_mgmt_event_callback *cb, - uint32_t mgmt_event, struct net_if *iface) +static void iface_work_handler(struct k_work *work) { - const char *ifname = iface->if_dev->dev->name; - - if (strncmp(ifname, IFACE_MATCHING_PREFIX, sizeof(IFACE_MATCHING_PREFIX) - 1) != 0) { - return; - } + struct supplicant_context *ctx = CONTAINER_OF(work, struct supplicant_context, + iface_work); + int ret; - wpa_printf(MSG_DEBUG, "Event: %d", mgmt_event); - if (mgmt_event == NET_EVENT_IF_ADMIN_UP) { - z_wpas_add_interface(ifname); - } else if (mgmt_event == NET_EVENT_IF_ADMIN_DOWN) { - z_wpas_remove_interface(ifname); + ret = (*ctx->iface_handler)(ctx, ctx->iface); + if (ret < 0) { + LOG_ERR("Interface %d (%p) handler failed (%d)", + net_if_get_by_iface(ctx->iface), ctx->iface, ret); } } -static void register_iface_events(void) +/* As the mgmt thread stack is limited, use a separate work queue for any network + * interface add/delete. + */ +static void submit_iface_work(struct supplicant_context *ctx, + struct net_if *iface, + int (*handler)(struct supplicant_context *ctx, + struct net_if *iface)) { - k_mutex_init(&iface_up_mutex); + ctx->iface_handler = handler; - k_mutex_lock(&iface_up_mutex, K_FOREVER); - net_mgmt_init_event_callback(&cb, iface_event_handler, - NET_EVENT_IF_ADMIN_UP | NET_EVENT_IF_ADMIN_DOWN); - net_mgmt_add_event_callback(&cb); + k_work_submit_to_queue(&ctx->iface_wq, &ctx->iface_work); } -static void wait_for_interface_up(const char *iface_name) +static void interface_handler(struct net_mgmt_event_callback *cb, + uint32_t mgmt_event, struct net_if *iface) { - if (z_wpas_get_iface_count() == 0) { - k_mutex_lock(&iface_up_mutex, K_FOREVER); + struct supplicant_context *ctx = CONTAINER_OF(cb, struct supplicant_context, + cb); + + if ((mgmt_event & INTERFACE_EVENT_MASK) != mgmt_event) { + return; + } + + if (!is_wanted_interface(iface)) { + LOG_DBG("Ignoring event (0x%02x) from interface %d (%p)", + mgmt_event, net_if_get_by_iface(iface), iface); + return; + } + + if (mgmt_event == NET_EVENT_IF_ADMIN_UP) { + LOG_INF("Network interface %d (%p) up", net_if_get_by_iface(iface), iface); + submit_iface_work(ctx, iface, add_interface); + return; + } + + if (mgmt_event == NET_EVENT_IF_ADMIN_DOWN) { + LOG_INF("Network interface %d (%p) down", net_if_get_by_iface(iface), iface); + submit_iface_work(ctx, iface, del_interface); + return; } } -#include "config.h" static void iface_cb(struct net_if *iface, void *user_data) { - const char *ifname = iface->if_dev->dev->name; + struct supplicant_context *ctx = user_data; + int ret; - if (ifname == NULL) { + if (!net_if_is_wifi(iface)) { return; } - if (strncmp(ifname, DEFAULT_IFACE_NAME, strlen(ifname)) != 0) { + if (!net_if_is_up(iface)) { return; } - /* Check default interface */ - if (net_if_is_admin_up(iface)) { - z_wpas_add_interface(ifname); + ret = add_interface(ctx, iface); + if (ret < 0) { + return; } - - register_iface_events(); } - -static void z_wpas_iface_work_handler(struct k_work *item) +static int setup_interface_monitoring(struct supplicant_context *ctx, struct net_if *iface) { - ARG_UNUSED(item); + ARG_UNUSED(iface); - int ret = k_sem_take(&z_wpas_ready_sem, K_SECONDS(5)); + net_mgmt_init_event_callback(&ctx->cb, interface_handler, + INTERFACE_EVENT_MASK); + net_mgmt_add_event_callback(&ctx->cb); - if (ret) { - wpa_printf(MSG_ERROR, "Timed out waiting for wpa_supplicant"); - return; - } - - net_if_foreach(iface_cb, NULL); - wait_for_interface_up(DEFAULT_IFACE_NAME); + net_if_foreach(iface_cb, ctx); - k_sem_give(&z_wpas_ready_sem); + return 0; } -static void z_wpas_event_sock_handler(int sock, void *eloop_ctx, void *sock_ctx) +static void event_socket_handler(int sock, void *eloop_ctx, void *user_data) { + struct supplicant_context *ctx = user_data; + struct wpa_supplicant_event_msg msg; int ret; ARG_UNUSED(eloop_ctx); - ARG_UNUSED(sock_ctx); - struct wpa_supplicant_event_msg msg; - - ret = recv(sock, &msg, sizeof(msg), 0); + ARG_UNUSED(ctx); + ret = zsock_recv(sock, &msg, sizeof(msg), 0); if (ret < 0) { - wpa_printf(MSG_ERROR, "Failed to recv the message: %s", strerror(errno)); + LOG_ERR("Failed to recv the message (%d)", -errno); return; } if (ret != sizeof(msg)) { - wpa_printf(MSG_ERROR, "Received incomplete message: got: %d, expected:%d", + LOG_ERR("Received incomplete message: got: %d, expected:%d", ret, sizeof(msg)); return; } - wpa_printf(MSG_DEBUG, "Passing message %d to wpa_supplicant", msg.event); + LOG_DBG("Passing message %d to wpa_supplicant", msg.event); if (msg.global) { wpa_supplicant_event_global(msg.ctx, msg.event, msg.data); @@ -396,151 +435,104 @@ static void z_wpas_event_sock_handler(int sock, void *eloop_ctx, void *sock_ctx) os_free((char *)data->auth.ies); } + os_free(msg.data); } } -static int register_wpa_event_sock(void) +static int register_supplicant_event_socket(struct supplicant_context *ctx) { int ret; - ret = socketpair(AF_UNIX, SOCK_STREAM, 0, z_wpas_event_sockpair); - - if (ret != 0) { - wpa_printf(MSG_ERROR, "Failed to initialize socket: %s", strerror(errno)); - return -1; + ret = socketpair(AF_UNIX, SOCK_STREAM, 0, ctx->event_socketpair); + if (ret < 0) { + ret = -errno; + LOG_ERR("Failed to initialize socket (%d)", ret); + return ret; } - eloop_register_read_sock(z_wpas_event_sockpair[0], z_wpas_event_sock_handler, NULL, NULL); + eloop_register_read_sock(ctx->event_socketpair[0], event_socket_handler, NULL, ctx); return 0; } -int z_wpas_send_event(const struct wpa_supplicant_event_msg *msg) -{ - int ret; - unsigned int retry = 0; - - k_mutex_lock(&z_wpas_event_mutex, K_FOREVER); - - if (z_wpas_event_sockpair[1] < 0) { - goto err; - } - -retry_send: - ret = send(z_wpas_event_sockpair[1], msg, sizeof(*msg), 0); - if (ret < 0) { - if (errno == EINTR || errno == EAGAIN || errno == EBUSY || errno == EWOULDBLOCK) { - k_msleep(2); - if (retry++ < 3) { - goto retry_send; - } else { - wpa_printf(MSG_WARNING, "Event send fail (max retries): %s", - strerror(errno)); - goto err; - } - } else { - wpa_printf(MSG_WARNING, "Event send fail: %s", - strerror(errno)); - goto err; - } - } - - ret = 0; -err: - k_mutex_unlock(&z_wpas_event_mutex); - return -1; -} - -static void z_wpas_start(void) +static void handler(void) { + struct supplicant_context *ctx; struct wpa_params params; - int exitcode = -1; #if defined(CONFIG_WPA_SUPP_CRYPTO) && !defined(CONFIG_MBEDTLS_ENABLE_HEAP) /* Needed for crypto operation as default is no-op and fails */ mbedtls_platform_set_calloc_free(calloc, free); #endif /* CONFIG_WPA_CRYPTO */ - k_work_queue_init(&z_wpas_iface_wq); + ctx = get_default_context(); - k_work_queue_start(&z_wpas_iface_wq, - z_wpas_iface_wq_stack, - K_THREAD_STACK_SIZEOF(z_wpas_iface_wq_stack), - 7, - NULL); + k_work_queue_init(&ctx->iface_wq); + k_work_queue_start(&ctx->iface_wq, iface_wq_stack, + K_THREAD_STACK_SIZEOF(iface_wq_stack), + CONFIG_WIFI_NM_WPA_SUPPLICANT_WQ_PRIO, + NULL); - os_memset(¶ms, 0, sizeof(params)); + k_work_init(&ctx->iface_work, iface_work_handler); + + memset(¶ms, 0, sizeof(params)); params.wpa_debug_level = CONFIG_WIFI_NM_WPA_SUPPLICANT_DEBUG_LEVEL; - exitcode = 0; - global = wpa_supplicant_init(¶ms); - if (global == NULL) { - wpa_printf(MSG_ERROR, "Failed to initialize wpa_supplicant"); - exitcode = -1; - goto out; - } else { - wpa_printf(MSG_INFO, "Successfully initialized " - "wpa_supplicant"); + ctx->supplicant = wpa_supplicant_init(¶ms); + if (ctx->supplicant == NULL) { + LOG_ERR("Failed to initialize %s", "wpa_supplicant"); + goto err; } + LOG_INF("%s initialized", "wpa_supplicant"); + if (fst_global_init()) { - wpa_printf(MSG_ERROR, "Failed to initialize FST"); - exitcode = -1; + LOG_ERR("Failed to initialize %s", "FST"); goto out; } #if defined(CONFIG_FST) && defined(CONFIG_CTRL_IFACE) if (!fst_global_add_ctrl(fst_ctrl_cli)) { - wpa_printf(MSG_WARNING, "Failed to add CLI FST ctrl"); + LOG_WRN("Failed to add CLI FST ctrl"); } #endif - z_global_wpa_ctrl_init(); + zephyr_global_wpa_ctrl_init(); - register_wpa_event_sock(); + register_supplicant_event_socket(ctx); - k_work_submit_to_queue(&z_wpas_iface_wq, &z_wpas_iface_work); + submit_iface_work(ctx, NULL, setup_interface_monitoring); -#ifdef CONFIG_MATCH_IFACE - if (exitcode == 0) { - exitcode = z_wpas_init_match(global); - } -#endif /* CONFIG_MATCH_IFACE */ + (void)wpa_supplicant_run(ctx->supplicant); - if (exitcode == 0) { - k_sem_give(&z_wpas_ready_sem); - exitcode = wpa_supplicant_run(global); - } + supplicant_generate_state_event(ctx->if_name, NET_EVENT_SUPPLICANT_CMD_NOT_READY, 0); - generate_supp_state_event(DEFAULT_IFACE_NAME, NET_EVENT_WPA_SUPP_CMD_NOT_READY, 0); - eloop_unregister_read_sock(z_wpas_event_sockpair[0]); + eloop_unregister_read_sock(ctx->event_socketpair[0]); - z_global_wpa_ctrl_deinit(); - wpa_supplicant_deinit(global); + zephyr_wpa_ctrl_deinit(ctx->supplicant); + zephyr_global_wpa_ctrl_deinit(); fst_global_deinit(); - close(z_wpas_event_sockpair[0]); - close(z_wpas_event_sockpair[1]); - out: -#ifdef CONFIG_MATCH_IFACE - os_free(params.match_ifaces); -#endif /* CONFIG_MATCH_IFACE */ - os_free(params.pid_file); + wpa_supplicant_deinit(ctx->supplicant); + + zsock_close(ctx->event_socketpair[0]); + zsock_close(ctx->event_socketpair[1]); - wpa_printf(MSG_INFO, "z_wpas_start: exitcode %d", exitcode); +err: + os_free(params.pid_file); } -static int z_wpas_init(void) +static int init(void) { - k_thread_create(&z_wpa_s_tid, z_wpa_s_thread_stack, - CONFIG_WIFI_NM_WPA_SUPPLICANT_THREAD_STACK_SIZE, - (k_thread_entry_t)z_wpas_start, - NULL, NULL, NULL, + /* We create a thread that handles all supplicant connections */ + k_thread_create(&tid, supplicant_thread_stack, + K_THREAD_STACK_SIZEOF(supplicant_thread_stack), + (k_thread_entry_t)handler, NULL, NULL, NULL, 0, 0, K_NO_WAIT); return 0; } -SYS_INIT(z_wpas_init, APPLICATION, 0); +SYS_INIT(init, APPLICATION, 0); diff --git a/modules/hostap/src/supp_main.h b/modules/hostap/src/supp_main.h index bd002025750..4ee64d00712 100644 --- a/modules/hostap/src/supp_main.h +++ b/modules/hostap/src/supp_main.h @@ -6,14 +6,13 @@ #ifndef __SUPP_MAIN_H_ #define __SUPP_MAIN_H_ -#include "wpa_supplicant_i.h" - -struct wpa_supplicant *z_wpas_get_handle_by_ifname(const char *ifname); +struct wpa_global *zephyr_get_default_supplicant_context(void); +struct wpa_supplicant *zephyr_get_handle_by_ifname(const char *ifname); struct wpa_supplicant_event_msg { bool global; void *ctx; unsigned int event; void *data; }; -int z_wpas_send_event(const struct wpa_supplicant_event_msg *msg); +int zephyr_wifi_send_event(const struct wpa_supplicant_event_msg *msg); #endif /* __SUPP_MAIN_H_ */ From d5ba20b9bef710f0cd31f99e8239d7e16ddf8c34 Mon Sep 17 00:00:00 2001 From: Jukka Rissanen Date: Thu, 2 Nov 2023 11:50:52 +0200 Subject: [PATCH 2945/3723] hostap: Align to Zephyr coding style Tweaked the code to be more readable and align to Zephyr coding style. Signed-off-by: Jukka Rissanen --- modules/hostap/src/supp_api.c | 30 ++++++++++++++++++++---------- 1 file changed, 20 insertions(+), 10 deletions(-) diff --git a/modules/hostap/src/supp_api.c b/modules/hostap/src/supp_api.c index e7896af919f..13b517069ad 100644 --- a/modules/hostap/src/supp_api.c +++ b/modules/hostap/src/supp_api.c @@ -111,6 +111,7 @@ static int wait_for_disconnect_complete(const struct device *dev) wpa_printf(MSG_WARNING, "Failed to disconnect from network"); break; } + k_sleep(K_MSEC(10)); timeout++; } @@ -180,10 +181,11 @@ static inline int chan_to_freq(int chan) * op_class for 5GHz channels as there is no user input * for these (yet). */ - int freq = ieee80211_chan_to_freq(NULL, 81, chan); + int freq; + freq = ieee80211_chan_to_freq(NULL, 81, chan); if (freq <= 0) { - freq = ieee80211_chan_to_freq(NULL, 128, chan); + freq = ieee80211_chan_to_freq(NULL, 128, chan); } if (freq <= 0) { @@ -246,6 +248,7 @@ int supplicant_connect(const struct device *dev, struct wifi_connect_req_params } __wpa_cli_cmd_v("remove_network all"); + ret = z_wpa_ctrl_add_network(&resp); if (ret) { wpa_printf(MSG_ERROR, "Failed to add network"); @@ -258,6 +261,7 @@ int supplicant_connect(const struct device *dev, struct wifi_connect_req_params __wpa_cli_cmd_v("set_network %d scan_ssid 1", resp.network_id); __wpa_cli_cmd_v("set_network %d key_mgmt NONE", resp.network_id); __wpa_cli_cmd_v("set_network %d ieee80211w 0", resp.network_id); + if (params->security != WIFI_SECURITY_TYPE_NONE) { if (params->security == WIFI_SECURITY_TYPE_SAE) { if (params->sae_password) { @@ -299,16 +303,17 @@ int supplicant_connect(const struct device *dev, struct wifi_connect_req_params if (freq < 0) { ret = -1; - wpa_printf(MSG_ERROR, "Invalid channel %d", - params->channel); + wpa_printf(MSG_ERROR, "Invalid channel %d", params->channel); goto out; } + zephyr_wpa_cli_cmd_v("set_network %d scan_freq %d", resp.network_id, freq); } __wpa_cli_cmd_v("select_network %d", resp.network_id); zephyr_wpa_cli_cmd_v("select_network %d", resp.network_id); + wpa_supp_api_ctrl.dev = dev; wpa_supp_api_ctrl.requested_op = CONNECT; wpa_supp_api_ctrl.connection_timeout = params->timeout; @@ -343,8 +348,10 @@ int supplicant_disconnect(const struct device *dev) wpa_printf(MSG_ERROR, "Device %s not found", dev->name); goto out; } + wpa_supp_api_ctrl.dev = dev; wpa_supp_api_ctrl.requested_op = DISCONNECT; + __wpa_cli_cmd_v("disconnect"); out: @@ -414,10 +421,12 @@ int supplicant_status(const struct device *dev, struct wifi_iface_status *status if (ssid_len == 0) { int _res = z_wpa_ctrl_status(&cli_status); - if (_res < 0) + if (_res < 0) { ssid_len = 0; - else + } else { ssid_len = cli_status.ssid_len; + } + _ssid = cli_status.ssid; } os_memcpy(status->ssid, _ssid, ssid_len); @@ -463,10 +472,11 @@ int supplicant_status(const struct device *dev, struct wifi_iface_status *status } else { wpa_printf(MSG_WARNING, "%s: Failed to get connection info\n", __func__); - status->beacon_interval = 0; - status->dtim_period = 0; - status->twt_capable = false; - ret = 0; + + status->beacon_interval = 0; + status->dtim_period = 0; + status->twt_capable = false; + ret = 0; } os_free(conn_info); From 7fad50fe4c81c1505738cd9d7fbd7ca912eb1a78 Mon Sep 17 00:00:00 2001 From: Jukka Rissanen Date: Thu, 11 Jan 2024 13:47:07 +0200 Subject: [PATCH 2946/3723] hostap: Avoid DHCPv4 related warnings if DHCPv4 is disabled If the DHCPv4 is disabled, then avoid linking warning about missing DHCPv4 functions. Also include dhcpv4.h so that the DHCPv4 function prototypes are found by the zephyr supplicant driver. Signed-off-by: Jukka Rissanen --- modules/hostap/src/supp_main.h | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/modules/hostap/src/supp_main.h b/modules/hostap/src/supp_main.h index 4ee64d00712..24d9796d276 100644 --- a/modules/hostap/src/supp_main.h +++ b/modules/hostap/src/supp_main.h @@ -6,6 +6,19 @@ #ifndef __SUPP_MAIN_H_ #define __SUPP_MAIN_H_ +#if !defined(CONFIG_NET_DHCPV4) +static inline void net_dhcpv4_start(struct net_if *iface) +{ + ARG_UNUSED(iface); +} +static inline void net_dhcpv4_stop(struct net_if *iface) +{ + ARG_UNUSED(iface); +} +#else +#include +#endif + struct wpa_global *zephyr_get_default_supplicant_context(void); struct wpa_supplicant *zephyr_get_handle_by_ifname(const char *ifname); struct wpa_supplicant_event_msg { From bf58765b6ce28f2b1c9dfa6a0e6d90383345fdde Mon Sep 17 00:00:00 2001 From: Jukka Rissanen Date: Thu, 11 Jan 2024 13:52:51 +0200 Subject: [PATCH 2947/3723] hostap: Change the name of the control api struct Zephyr requires that the name of the variable is not the same as the struct as seen by this warning: modules/hostap/src/supp_api.c:64:WARNING: Violation to rule 5.7 (Tag name should be unique) tag: wpa_supp_api_ctrl Signed-off-by: Jukka Rissanen --- modules/hostap/src/supp_api.c | 20 ++++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/modules/hostap/src/supp_api.c b/modules/hostap/src/supp_api.c index 13b517069ad..e911025834f 100644 --- a/modules/hostap/src/supp_api.c +++ b/modules/hostap/src/supp_api.c @@ -59,7 +59,7 @@ struct wpa_supp_api_ctrl { bool terminate; }; -static struct wpa_supp_api_ctrl wpa_supp_api_ctrl; +static struct wpa_supp_api_ctrl wpas_api_ctrl; static void supp_shell_connect_status(struct k_work *work); @@ -125,7 +125,7 @@ static void supp_shell_connect_status(struct k_work *work) int status = CONNECTION_SUCCESS; int conn_result = CONNECTION_FAILURE; struct wpa_supplicant *wpa_s; - struct wpa_supp_api_ctrl *ctrl = &wpa_supp_api_ctrl; + struct wpa_supp_api_ctrl *ctrl = &wpas_api_ctrl; k_mutex_lock(&wpa_supplicant_mutex, K_FOREVER); @@ -167,9 +167,9 @@ static void supp_shell_connect_status(struct k_work *work) static inline void wpa_supp_restart_status_work(void) { /* Terminate synchronously */ - wpa_supp_api_ctrl.terminate = 1; - k_work_flush_delayable(&wpa_supp_status_work, &wpa_supp_api_ctrl.sync); - wpa_supp_api_ctrl.terminate = 0; + wpas_api_ctrl.terminate = 1; + k_work_flush_delayable(&wpa_supp_status_work, &wpas_api_ctrl.sync); + wpas_api_ctrl.terminate = 0; /* Start afresh */ k_work_reschedule(&wpa_supp_status_work, K_MSEC(10)); @@ -314,9 +314,9 @@ int supplicant_connect(const struct device *dev, struct wifi_connect_req_params zephyr_wpa_cli_cmd_v("select_network %d", resp.network_id); - wpa_supp_api_ctrl.dev = dev; - wpa_supp_api_ctrl.requested_op = CONNECT; - wpa_supp_api_ctrl.connection_timeout = params->timeout; + wpas_api_ctrl.dev = dev; + wpas_api_ctrl.requested_op = CONNECT; + wpas_api_ctrl.connection_timeout = params->timeout; out: k_mutex_unlock(&wpa_supplicant_mutex); @@ -349,8 +349,8 @@ int supplicant_disconnect(const struct device *dev) goto out; } - wpa_supp_api_ctrl.dev = dev; - wpa_supp_api_ctrl.requested_op = DISCONNECT; + wpas_api_ctrl.dev = dev; + wpas_api_ctrl.requested_op = DISCONNECT; __wpa_cli_cmd_v("disconnect"); From 6fdb6d5169f7d45ac28a6d12c81eda1b99e89bc6 Mon Sep 17 00:00:00 2001 From: Jukka Rissanen Date: Thu, 11 Jan 2024 15:02:32 +0200 Subject: [PATCH 2948/3723] hostap: Replace the command line cmd macro Zephyr compliance checker does not like macros that have control structures like goto. So change the macro to align with this rule. Also rename the macro and remove the __ prefix as it not needed. Signed-off-by: Jukka Rissanen --- modules/hostap/src/supp_api.c | 110 +++++++++++++++++++++++++--------- 1 file changed, 81 insertions(+), 29 deletions(-) diff --git a/modules/hostap/src/supp_api.c b/modules/hostap/src/supp_api.c index e911025834f..3b78940a4f5 100644 --- a/modules/hostap/src/supp_api.c +++ b/modules/hostap/src/supp_api.c @@ -41,12 +41,6 @@ enum status_thread_state { #define DISCONNECT_TIMEOUT_MS 5000 -#define __wpa_cli_cmd_v(cmd, ...) \ - if (zephyr_wpa_cli_cmd_v(cmd, ##__VA_ARGS__) < 0) { \ - wpa_printf(MSG_ERROR, "Failed to execute wpa_cli command: %s", cmd); \ - goto out; \ - } \ - K_MUTEX_DEFINE(wpa_supplicant_mutex); @@ -66,6 +60,21 @@ static void supp_shell_connect_status(struct k_work *work); static K_WORK_DELAYABLE_DEFINE(wpa_supp_status_work, supp_shell_connect_status); +#define wpa_cli_cmd_v(cmd, ...) ({ \ + bool status; \ + \ + if (zephyr_wpa_cli_cmd_v(cmd, ##__VA_ARGS__) < 0) { \ + wpa_printf(MSG_ERROR, \ + "Failed to execute wpa_cli command: %s", \ + cmd); \ + status = false; \ + } else { \ + status = true; \ + } \ + \ + status; \ +}) + static struct wpa_supplicant *get_wpa_s_handle(const struct device *dev) { struct net_if *iface = net_if_lookup_by_dev(dev); @@ -143,7 +152,10 @@ static void supp_shell_connect_status(struct k_work *work) if (ctrl->requested_op == CONNECT && wpa_s->wpa_state != WPA_COMPLETED) { if (ctrl->connection_timeout > 0 && seconds_counter++ > ctrl->connection_timeout) { - __wpa_cli_cmd_v("disconnect"); + if (!wpa_cli_cmd_v("disconnect")) { + goto out; + } + conn_result = -ETIMEDOUT; supplicant_send_wifi_mgmt_event(wpa_s->ifname, NET_EVENT_WIFI_CMD_CONNECT_RESULT, @@ -247,7 +259,9 @@ int supplicant_connect(const struct device *dev, struct wifi_connect_req_params goto out; } - __wpa_cli_cmd_v("remove_network all"); + if (!wpa_cli_cmd_v("remove_network all")) { + goto out; + } ret = z_wpa_ctrl_add_network(&resp); if (ret) { @@ -257,31 +271,60 @@ int supplicant_connect(const struct device *dev, struct wifi_connect_req_params wpa_printf(MSG_DEBUG, "NET added: %d\n", resp.network_id); - __wpa_cli_cmd_v("set_network %d ssid \"%s\"", resp.network_id, params->ssid); - __wpa_cli_cmd_v("set_network %d scan_ssid 1", resp.network_id); - __wpa_cli_cmd_v("set_network %d key_mgmt NONE", resp.network_id); - __wpa_cli_cmd_v("set_network %d ieee80211w 0", resp.network_id); + if (!wpa_cli_cmd_v("set_network %d ssid \"%s\"", + resp.network_id, params->ssid)) { + goto out; + } + + if (!wpa_cli_cmd_v("set_network %d scan_ssid 1", resp.network_id)) { + goto out; + } + + if (!wpa_cli_cmd_v("set_network %d key_mgmt NONE", resp.network_id)) { + goto out; + } + + if (!wpa_cli_cmd_v("set_network %d ieee80211w 0", resp.network_id)) { + goto out; + } if (params->security != WIFI_SECURITY_TYPE_NONE) { if (params->security == WIFI_SECURITY_TYPE_SAE) { if (params->sae_password) { - __wpa_cli_cmd_v("set_network %d sae_password \"%s\"", - resp.network_id, params->sae_password); + if (!wpa_cli_cmd_v("set_network %d sae_password \"%s\"", + resp.network_id, params->sae_password)) { + goto out; + } } else { - __wpa_cli_cmd_v("set_network %d sae_password \"%s\"", - resp.network_id, params->psk); + if (!wpa_cli_cmd_v("set_network %d sae_password \"%s\"", + resp.network_id, params->psk)) { + goto out; + } } - __wpa_cli_cmd_v("set_network %d key_mgmt SAE", resp.network_id); + if (!wpa_cli_cmd_v("set_network %d key_mgmt SAE", resp.network_id)) { + goto out; + } } else if (params->security == WIFI_SECURITY_TYPE_PSK_SHA256) { - __wpa_cli_cmd_v("set_network %d psk \"%s\"", - resp.network_id, params->psk); - __wpa_cli_cmd_v("set_network %d key_mgmt WPA-PSK-SHA256", - resp.network_id); + if (!wpa_cli_cmd_v("set_network %d psk \"%s\"", + resp.network_id, params->psk)) { + goto out; + } + + if (!wpa_cli_cmd_v("set_network %d key_mgmt WPA-PSK-SHA256", + resp.network_id)) { + goto out; + } } else if (params->security == WIFI_SECURITY_TYPE_PSK) { - __wpa_cli_cmd_v("set_network %d psk \"%s\"", - resp.network_id, params->psk); - __wpa_cli_cmd_v("set_network %d key_mgmt WPA-PSK", resp.network_id); + if (!wpa_cli_cmd_v("set_network %d psk \"%s\"", + resp.network_id, params->psk)) { + goto out; + } + + if (!wpa_cli_cmd_v("set_network %d key_mgmt WPA-PSK", + resp.network_id)) { + goto out; + } } else { ret = -1; wpa_printf(MSG_ERROR, "Unsupported security type: %d", @@ -290,13 +333,17 @@ int supplicant_connect(const struct device *dev, struct wifi_connect_req_params } if (params->mfp) { - __wpa_cli_cmd_v("set_network %d ieee80211w %d", - resp.network_id, params->mfp); + if (!wpa_cli_cmd_v("set_network %d ieee80211w %d", + resp.network_id, params->mfp)) { + goto out; + } } } /* enable and select network */ - __wpa_cli_cmd_v("enable_network %d", resp.network_id); + if (!wpa_cli_cmd_v("enable_network %d", resp.network_id)) { + goto out; + } if (params->channel != WIFI_CHANNEL_ANY) { int freq = chan_to_freq(params->channel); @@ -310,7 +357,10 @@ int supplicant_connect(const struct device *dev, struct wifi_connect_req_params zephyr_wpa_cli_cmd_v("set_network %d scan_freq %d", resp.network_id, freq); } - __wpa_cli_cmd_v("select_network %d", resp.network_id); + + if (!wpa_cli_cmd_v("select_network %d", resp.network_id)) { + goto out; + } zephyr_wpa_cli_cmd_v("select_network %d", resp.network_id); @@ -352,7 +402,9 @@ int supplicant_disconnect(const struct device *dev) wpas_api_ctrl.dev = dev; wpas_api_ctrl.requested_op = DISCONNECT; - __wpa_cli_cmd_v("disconnect"); + if (!wpa_cli_cmd_v("disconnect")) { + goto out; + } out: k_mutex_unlock(&wpa_supplicant_mutex); From 0e51913a1830c1ff116168ea8fef9f53d64d7613 Mon Sep 17 00:00:00 2001 From: Jukka Rissanen Date: Thu, 11 Jan 2024 15:23:10 +0200 Subject: [PATCH 2949/3723] hostap: Temporary kconfig options to pass the compliance checker Compliance checker does not allow compile definitions without a Kconfig option. So add dummy values for time being. These should be removed at some point and replaced with properly namespaced options. Signed-off-by: Jukka Rissanen --- modules/hostap/CMakeLists.txt | 3 +- modules/hostap/Kconfig | 123 ++++++++++++++++++++++++++++++++- modules/hostap/src/supp_main.c | 2 +- 3 files changed, 124 insertions(+), 4 deletions(-) diff --git a/modules/hostap/CMakeLists.txt b/modules/hostap/CMakeLists.txt index aefb9acda9a..b24320acec5 100644 --- a/modules/hostap/CMakeLists.txt +++ b/modules/hostap/CMakeLists.txt @@ -31,7 +31,6 @@ zephyr_library_compile_definitions( CONFIG_NO_WPA CONFIG_NO_PBKDF2 CONFIG_SHA256 - CONFIG_WPA_S_ZEPHYR_L2_WIFI_MGMT CONFIG_CTRL_IFACE_ZEPHYR # CONFIG_MBO # CONFIG_WNM @@ -362,6 +361,6 @@ zephyr_library_sources_ifdef(CONFIG_WIFI_NM_WPA_SUPPLICANT_EAPOL ) zephyr_library_compile_definitions_ifdef(CONFIG_WIFI_NM_WPA_SUPPLICANT_EAPOL - IEEE8021X_EAPOL + CONFIG_IEEE8021X_EAPOL ) endif() diff --git a/modules/hostap/Kconfig b/modules/hostap/Kconfig index 5e25c2718b8..a24763b4da1 100644 --- a/modules/hostap/Kconfig +++ b/modules/hostap/Kconfig @@ -137,7 +137,7 @@ config WIFI_NM_WPA_SUPPLICANT_P2P select WIFI_NM_WPA_SUPPLICANT_WPS config WIFI_NM_WPA_SUPPLICANT_EAPOL - bool "Enable EAPoL supplicant" + bool "EAPoL supplicant" config WIFI_NM_WPA_SUPPLICANT_CLI bool "CLI support for wpa_supplicant" @@ -207,4 +207,125 @@ config FST config TESTING_OPTIONS bool +config AP + bool + +config NO_RADIUS + bool + +config NO_VLAN + bool + +config NO_ACCOUNTING + bool + +config NEED_AP_MLME + bool + +config IEEE80211AX + bool + +config EAP_SERVER + bool + +config EAP_SERVER_IDENTITY + bool + +config P2P + bool + +config GAS + bool + +config OFFCHANNEL + bool + +config WPS + bool + +config WSC + bool + +config EAP_TLS + bool + +config IEEE8021X_EAPOL + bool + +config EAP_PEAP + bool + +config EAP_TTLS + bool + +config EAP_MD5 + bool + +config EAP_MSCHAPv2 + bool + +config EAP_LEAP + bool + +config EAP_PSK + bool + +config EAP_FAST + bool + +config EAP_PAX + bool + +config EAP_SAKE + bool + +config EAP_GPSK + bool + +config EAP_PWD + bool + +config EAP_EKE + bool + +config EAP_IKEv2 + bool + +config IEEE8021X_EAPOL + bool + +config CRYPTO_INTERNAL + bool + +config ECC + bool + +config MBO + bool + +config NO_STDOUT_DEBUG + bool + +config SAE + bool + +config SHA256 + bool + +config SUITEB192 + bool + +config WEP + bool + default y if WIFI_NM_WPA_SUPPLICANT_WEP + +config WPA_CLI + bool + +config WPA_CRYPTO + bool + +config WPA_SUPP_CRYPTO + bool + endif # WIFI_NM_WPA_SUPPLICANT diff --git a/modules/hostap/src/supp_main.c b/modules/hostap/src/supp_main.c index f2e348bba34..34b91b65ed6 100644 --- a/modules/hostap/src/supp_main.c +++ b/modules/hostap/src/supp_main.c @@ -464,7 +464,7 @@ static void handler(void) #if defined(CONFIG_WPA_SUPP_CRYPTO) && !defined(CONFIG_MBEDTLS_ENABLE_HEAP) /* Needed for crypto operation as default is no-op and fails */ mbedtls_platform_set_calloc_free(calloc, free); -#endif /* CONFIG_WPA_CRYPTO */ +#endif /* CONFIG_WPA_SUPP_CRYPTO */ ctx = get_default_context(); From 64423e269ec92406c61af6b83298966d755ca4c8 Mon Sep 17 00:00:00 2001 From: Jukka Rissanen Date: Thu, 18 Jan 2024 16:15:55 +0200 Subject: [PATCH 2950/3723] hostap: Remove commented Kconfig options Some crypto Kconfig options were commented out, so remove them. These will be re-introduced later when adding crypto support properly. Signed-off-by: Jukka Rissanen --- modules/hostap/Kconfig | 27 --------------------------- 1 file changed, 27 deletions(-) diff --git a/modules/hostap/Kconfig b/modules/hostap/Kconfig index a24763b4da1..61e21bee34e 100644 --- a/modules/hostap/Kconfig +++ b/modules/hostap/Kconfig @@ -10,9 +10,7 @@ config WIFI_NM_WPA_SUPPLICANT select POSIX_CLOCK select POSIX_SIGNAL select POSIX_API -# depends on !POSIX_API select NET_SOCKETS -# select NET_SOCKETS_POSIX_NAMES select NET_SOCKETS_PACKET select NET_SOCKETPAIR select NET_L2_WIFI_MGMT @@ -80,35 +78,10 @@ choice WIFI_NM_WPA_SUPPLICANT_CRYPTO_BACKEND config WIFI_NM_WPA_SUPPLICANT_CRYPTO_PSA bool "PSA Crypto support for WiFi" select WIFI_NM_WPA_SUPPLICANT_WEP - # Legacy crypto, still needed - #select MBEDTLS - #select MBEDTLS_CMAC_C - #select MBEDTLS_GCM_C - #select MBEDTLS_TLS_LIBRARY - #select MBEDTLS_PK_WRITE_C - #select MBEDTLS_X509_LIBRARY - #select MBEDTLS_X509_CRT_PARSE_C - #select MBEDTLS_CIPHER_C - #select MBEDTLS_CIPHER_MODE_CTR - #select MBEDTLS_CIPHER_MODE_CBC - #select MBEDTLS_SSL_TLS_C - #select MBEDTLS_KEY_EXCHANGE_ALL_ENABLED - #select MBEDTLS_KEY_EXCHANGE_ECDHE_PSK_ENABLED - #select MBEDTLS_KEY_EXCHANGE_ECDHE_RSA_ENABLED config WIFI_NM_WPA_SUPPLICANT_CRYPTO bool "Legacy Crypto support for WiFi" select WIFI_NM_WPA_SUPPLICANT_WEP - #select MBEDTLS - #select MBEDTLS_CIPHER_MODE_CBC - #select MBEDTLS_CIPHER_MODE_CTR - #select MBEDTLS_LEGACY_CRYPTO_C - #select MBEDTLS_ECP_C - #select MBEDTLS_CTR_DRBG_C - #select MBEDTLS_PK_WRITE_C - #select MBEDTLS_KEY_EXCHANGE_ALL_ENABLED - #select MBEDTLS_KEY_EXCHANGE_ECDHE_PSK_ENABLED - #select MBEDTLS_KEY_EXCHANGE_ECDHE_RSA_ENABLED config WIFI_NM_WPA_SUPPLICANT_CRYPTO_NONE bool "No Crypto support for WiFi" From 0e2f19a5646f7f10f135e68eb6611a3a1cad9d1c Mon Sep 17 00:00:00 2001 From: Paszkiet Kamil Date: Fri, 15 Dec 2023 14:30:34 +0100 Subject: [PATCH 2951/3723] scripts: tests: twister_blackbox: Add more tests to test_report.py add tests to test_report.py: - log-file - coverage - enable-coverage Signed-off-by: Paszkiet Kamil --- scripts/tests/twister_blackbox/test_report.py | 111 ++++++++++++++++++ 1 file changed, 111 insertions(+) diff --git a/scripts/tests/twister_blackbox/test_report.py b/scripts/tests/twister_blackbox/test_report.py index 1a076f97b19..56d1bc3e098 100644 --- a/scripts/tests/twister_blackbox/test_report.py +++ b/scripts/tests/twister_blackbox/test_report.py @@ -7,6 +7,8 @@ """ import importlib +import re + import mock import os import shutil @@ -98,6 +100,32 @@ class TestReport: "OUT_DIR" ), ] + TESTDATA_6 = [ + ( + os.path.join(TEST_DATA, 'tests', 'dummy', 'agnostic'), + ['qemu_x86'], + "TEST_LOG_FILE.log" + ), + ] + TESTDATA_7 = [ + ( + os.path.join(TEST_DATA, 'tests', 'dummy', 'agnostic'), + ['qemu_x86'], + [ + 'coverage.log', 'coverage.json', + 'coverage' + ], + ), + ] + TESTDATA_8 = [ + ( + os.path.join(TEST_DATA, 'tests', 'dummy', 'agnostic'), + ['qemu_x86'], + [ + 'GCOV_COVERAGE_DUMP_START', 'GCOV_COVERAGE_DUMP_END' + ], + ), + ] @classmethod def setup_class(cls): @@ -294,3 +322,86 @@ def test_outdir(self, capfd, test_path, test_platforms, file_name, dir_name): twister_path = os.path.join(ZEPHYR_BASE, dir_name) if os.path.exists(twister_path): shutil.rmtree(twister_path) + + @pytest.mark.parametrize( + 'test_path, test_platforms, file_name', + TESTDATA_6, + ids=[ + 'log_file', + ] + ) + def test_log_file(self, capfd, test_path, test_platforms, out_path, file_name): + args = ['-i','--outdir', out_path, '-T', test_path, "--log-file", file_name] + \ + [val for pair in zip( + ['-p'] * len(test_platforms), test_platforms + ) for val in pair] + + file_path = os.path.join(ZEPHYR_BASE, file_name) + if os.path.exists(file_path): + os.remove(file_path) + + with mock.patch.object(sys, 'argv', [sys.argv[0]] + args), \ + pytest.raises(SystemExit) as sys_exit: + self.loader.exec_module(self.twister_module) + + out, err = capfd.readouterr() + sys.stdout.write(out) + sys.stderr.write(err) + + assert os.path.exists(file_path), 'file not found {f_name}' + + assert str(sys_exit.value) == '0' + + @pytest.mark.parametrize( + 'test_path, test_platforms, file_name', + TESTDATA_7, + ids=[ + 'coverage', + ] + ) + def test_coverage(self, capfd, test_path, test_platforms, out_path, file_name): + args = ['-i','--outdir', out_path, '-T', test_path, '--coverage', '--coverage-tool', 'gcovr'] + \ + [val for pair in zip( + ['-p'] * len(test_platforms), test_platforms + ) for val in pair] + + with mock.patch.object(sys, 'argv', [sys.argv[0]] + args), \ + pytest.raises(SystemExit) as sys_exit: + self.loader.exec_module(self.twister_module) + + out, err = capfd.readouterr() + sys.stdout.write(out) + sys.stderr.write(err) + + for f_name in file_name: + path = os.path.join(out_path, f_name) + assert os.path.exists(path), f'file not found {f_name}' + + assert str(sys_exit.value) == '0' + + @pytest.mark.parametrize( + 'test_path, test_platforms, expected', + TESTDATA_8, + ids=[ + 'enable_coverage', + ] + ) + def test_enable_coverage(self, capfd, test_path, test_platforms, out_path, expected): + args = ['-i','--outdir', out_path, '-T', test_path, '--enable-coverage', '-vv'] + \ + [val for pair in zip( + ['-p'] * len(test_platforms), test_platforms + ) for val in pair] + + with mock.patch.object(sys, 'argv', [sys.argv[0]] + args), \ + pytest.raises(SystemExit) as sys_exit: + self.loader.exec_module(self.twister_module) + + out, err = capfd.readouterr() + sys.stdout.write(out) + sys.stderr.write(err) + + for line in expected: + match = re.search(line, err) + assert match, f'line not found: {line}' + + assert str(sys_exit.value) == '0' From 413059df8420aa9da167787dd21d078bf61260ef Mon Sep 17 00:00:00 2001 From: Mykola Kvach Date: Wed, 10 Jan 2024 10:58:24 +0200 Subject: [PATCH 2952/3723] drivers: pinctrl: pfc_rcar: add mapping of memory for Spider ARM64 Add mapping of PFC device memory for Spider ARM64. Make mapping code common for all RCar boards. Signed-off-by: Mykola Kvach --- drivers/pinctrl/pfc_rcar.c | 25 +++++++++++++++---------- 1 file changed, 15 insertions(+), 10 deletions(-) diff --git a/drivers/pinctrl/pfc_rcar.c b/drivers/pinctrl/pfc_rcar.c index 17e4146bbaa..ad10b03fda0 100644 --- a/drivers/pinctrl/pfc_rcar.c +++ b/drivers/pinctrl/pfc_rcar.c @@ -21,20 +21,24 @@ #if defined(CONFIG_SOC_SERIES_RCAR_GEN3) #define PFC_RCAR_GPSR 0x100 #define PFC_RCAR_IPSR 0x200 -DEVICE_MMIO_TOPLEVEL_STATIC(pfc, DT_DRV_INST(0)); -static uintptr_t reg_base[1]; #elif defined(CONFIG_SOC_SERIES_RCAR_GEN4) #define PFC_RCAR_GPSR 0x040 #define PFC_RCAR_IPSR 0x060 -/* swap both arguments */ -#define PFC_REG_ADDRESS(idx, node_id) DT_REG_ADDR_BY_IDX(node_id, idx) -static const uintptr_t reg_base[] = { - LISTIFY(DT_NUM_REGS(DT_DRV_INST(0)), PFC_REG_ADDRESS, (,), DT_DRV_INST(0)) -}; #else #error Unsupported SoC Series #endif +/* swap both arguments */ +#define PFC_REG_ADDRESS(idx, inst) DT_INST_REG_ADDR_BY_IDX(inst, idx) +static uintptr_t reg_base[] = { + LISTIFY(DT_NUM_REGS(DT_DRV_INST(0)), PFC_REG_ADDRESS, (,), 0) +}; + +#define PFC_REG_SIZE(idx, inst) DT_INST_REG_SIZE_BY_IDX(inst, idx) +static const uintptr_t __maybe_unused reg_sizes[] = { + LISTIFY(DT_NUM_REGS(DT_DRV_INST(0)), PFC_REG_SIZE, (,), 0) +}; + #ifdef CONFIG_PINCTRL_RCAR_VOLTAGE_CONTROL /* POC Control Register can control IO voltage level that is supplied to the pin */ struct pfc_pocctrl_reg { @@ -372,11 +376,12 @@ int pinctrl_configure_pins(const pinctrl_soc_pin_t *pins, uint8_t pin_cnt, return ret; } -#if defined(CONFIG_SOC_SERIES_RCAR_GEN3) +#if defined(DEVICE_MMIO_IS_IN_RAM) __boot_func static int pfc_rcar_driver_init(void) { - DEVICE_MMIO_TOPLEVEL_MAP(pfc, K_MEM_CACHE_NONE); - reg_base[0] = DEVICE_MMIO_TOPLEVEL_GET(pfc); + for (unsigned int i = 0; i < ARRAY_SIZE(reg_base); i++) { + device_map(reg_base + i, reg_base[i], reg_sizes[i], K_MEM_CACHE_NONE); + } return 0; } From 67caa1c5ab9ca34a5b7f778cc794af94bf3afe5c Mon Sep 17 00:00:00 2001 From: Javad Rahimipetroudi Date: Fri, 12 Jan 2024 08:28:50 +0100 Subject: [PATCH 2953/3723] boards: arm: stm32wb5mmg: add Bluetooth support This patch introduces the Bluetooth Low Energy (BLE) feature to the board. The board utilizes the STM32WB5MMG as the BLE module. However, As there was no BLE controller available for this module. Therefore, a board support package has been added to enable the STM32WB5MMG module to act as a BLE controller. This is achieved by running Zephyr's hci_uart example on the STM32WB5MMG module which enables communication with the main microcontroller over the H:4 HCI transport protocol. So, users must first build the BLE controller for the BLE module and upload it via on board ST-Link,then they can uses Zephyr Bluetooth demos on the development board Note that there was no hardware flow control wiring available on the board, which is why it has been disabled in the both main board and BLE module Device Tree. Signed-off-by: Javad Rahimipetroudi --- boards/arm/stm32wb5mmg/Kconfig.board | 8 + boards/arm/stm32wb5mmg/Kconfig.defconfig | 16 + boards/arm/stm32wb5mmg/board.cmake | 7 + .../arm/stm32wb5mmg/doc/img/STM32WB5MMG.jpg | Bin 0 -> 36107 bytes boards/arm/stm32wb5mmg/doc/stm32wb5mmg.rst | 304 ++++++++++++++++++ boards/arm/stm32wb5mmg/stm32wb5mmg.dts | 106 ++++++ boards/arm/stm32wb5mmg/stm32wb5mmg.yaml | 16 + boards/arm/stm32wb5mmg/stm32wb5mmg_defconfig | 24 ++ boards/arm/stm32wb5mmg/support/openocd.cfg | 7 + 9 files changed, 488 insertions(+) create mode 100644 boards/arm/stm32wb5mmg/Kconfig.board create mode 100644 boards/arm/stm32wb5mmg/Kconfig.defconfig create mode 100644 boards/arm/stm32wb5mmg/board.cmake create mode 100644 boards/arm/stm32wb5mmg/doc/img/STM32WB5MMG.jpg create mode 100644 boards/arm/stm32wb5mmg/doc/stm32wb5mmg.rst create mode 100644 boards/arm/stm32wb5mmg/stm32wb5mmg.dts create mode 100644 boards/arm/stm32wb5mmg/stm32wb5mmg.yaml create mode 100644 boards/arm/stm32wb5mmg/stm32wb5mmg_defconfig create mode 100644 boards/arm/stm32wb5mmg/support/openocd.cfg diff --git a/boards/arm/stm32wb5mmg/Kconfig.board b/boards/arm/stm32wb5mmg/Kconfig.board new file mode 100644 index 00000000000..4fe8c22fd7c --- /dev/null +++ b/boards/arm/stm32wb5mmg/Kconfig.board @@ -0,0 +1,8 @@ +# STM32WB5MMG Bluetooth module board configuration + +# Copyright (c) 2024 Javad Rahimipetroudi +# SPDX-License-Identifier: Apache-2.0 + +config BOARD_STM32WB5MMG + bool "stm32wb5mmg ultra low power Bluetooth module" + depends on SOC_STM32WB55XX diff --git a/boards/arm/stm32wb5mmg/Kconfig.defconfig b/boards/arm/stm32wb5mmg/Kconfig.defconfig new file mode 100644 index 00000000000..cedb62395be --- /dev/null +++ b/boards/arm/stm32wb5mmg/Kconfig.defconfig @@ -0,0 +1,16 @@ +# STM32WB5MMG Bluetooth module board configuration + +# Copyright (c) 2024 Javad Rahimipetroudi +# SPDX-License-Identifier: Apache-2.0 + +if BOARD_STM32WB5MMG + +config BOARD + default "stm32wb5mmg" + +choice BT_HCI_BUS_TYPE + default BT_STM32_IPM + depends on BT +endchoice + +endif # BOARD_STM32WB5MMG diff --git a/boards/arm/stm32wb5mmg/board.cmake b/boards/arm/stm32wb5mmg/board.cmake new file mode 100644 index 00000000000..47fc12f1308 --- /dev/null +++ b/boards/arm/stm32wb5mmg/board.cmake @@ -0,0 +1,7 @@ +# SPDX-License-Identifier: Apache-2.0 +board_runner_args(pyocd "--target=stm32wb55vgyx") +board_runner_args(stm32cubeprogrammer "--port=swd" "--reset-mode=hw") + +include(${ZEPHYR_BASE}/boards/common/stm32cubeprogrammer.board.cmake) +include(${ZEPHYR_BASE}/boards/common/openocd.board.cmake) +include(${ZEPHYR_BASE}/boards/common/pyocd.board.cmake) diff --git a/boards/arm/stm32wb5mmg/doc/img/STM32WB5MMG.jpg b/boards/arm/stm32wb5mmg/doc/img/STM32WB5MMG.jpg new file mode 100644 index 0000000000000000000000000000000000000000..6def853b748ae2cbf2820418be7f227b2615f00f GIT binary patch literal 36107 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

\t\t" - "\t\t\n"); + PR("Wi-Fi Regulatory domain is: %c%c\n", + regd.country_code[0], regd.country_code[1]); + PR("\t
\t\t" + "\t\t\n"); for (chan_idx = 0; chan_idx < regd.num_channels; chan_idx++) { - shell_fprintf(sh, SHELL_NORMAL, - " %d\t\t\t\%d\t\t\t\%s\t\t\t%d\t\t\t%s\t\t\t\t%s\n", - wifi_freq_to_channel(chan_info[chan_idx].center_frequency), - chan_info[chan_idx].center_frequency, - chan_info[chan_idx].supported ? "y" : "n", - chan_info[chan_idx].max_power, - chan_info[chan_idx].passive_only ? "y" : "n", - chan_info[chan_idx].dfs ? "y" : "n"); + PR(" %d\t\t\t\%d\t\t\t\%s\t\t\t%d\t\t\t%s\t\t\t\t%s\n", + wifi_freq_to_channel(chan_info[chan_idx].center_frequency), + chan_info[chan_idx].center_frequency, + chan_info[chan_idx].supported ? "y" : "n", + chan_info[chan_idx].max_power, + chan_info[chan_idx].passive_only ? "y" : "n", + chan_info[chan_idx].dfs ? "y" : "n"); } } else { - shell_fprintf(sh, SHELL_NORMAL, "Wi-Fi Regulatory domain set to: %c%c\n", - regd.country_code[0], regd.country_code[1]); + PR("Wi-Fi Regulatory domain set to: %c%c\n", + regd.country_code[0], regd.country_code[1]); } return 0; @@ -1487,21 +1462,17 @@ static int cmd_wifi_listen_interval(const struct shell *sh, size_t argc, char *a if (net_mgmt(NET_REQUEST_WIFI_PS, iface, ¶ms, sizeof(params))) { if (params.fail_reason == WIFI_PS_PARAM_LISTEN_INTERVAL_RANGE_INVALID) { - shell_fprintf(sh, SHELL_WARNING, - "Setting listen interval failed. Reason :%s\n", - wifi_ps_get_config_err_code_str(params.fail_reason)); - shell_fprintf(sh, SHELL_WARNING, - "Hardware support valid range : 3 - 65535\n"); - } else { - shell_fprintf(sh, SHELL_WARNING, - "Setting listen interval failed. Reason :%s\n", - wifi_ps_get_config_err_code_str(params.fail_reason)); + PR_WARNING("Setting listen interval failed. Reason :%s\n", + wifi_ps_get_config_err_code_str(params.fail_reason)); + PR_WARNING("Hardware support valid range : 3 - 65535\n"); + } else { + PR_WARNING("Setting listen interval failed. Reason :%s\n", + wifi_ps_get_config_err_code_str(params.fail_reason)); } return -ENOEXEC; } - shell_fprintf(sh, SHELL_NORMAL, - "Listen interval %hu\n", params.listen_interval); + PR("Listen interval %hu\n", params.listen_interval); return 0; } @@ -1518,24 +1489,21 @@ static int cmd_wifi_ps_wakeup_mode(const struct shell *sh, size_t argc, char *ar } else if (!strncasecmp(argv[1], "listen_interval", 15)) { params.wakeup_mode = WIFI_PS_WAKEUP_MODE_LISTEN_INTERVAL; } else { - shell_fprintf(sh, SHELL_WARNING, "Invalid argument\n"); - shell_fprintf(sh, SHELL_INFO, - "Valid argument : / \n"); + PR_WARNING("Invalid argument\n"); + PR_INFO("Valid argument : / \n"); return -ENOEXEC; } params.type = WIFI_PS_PARAM_WAKEUP_MODE; if (net_mgmt(NET_REQUEST_WIFI_PS, iface, ¶ms, sizeof(params))) { - shell_fprintf(sh, SHELL_WARNING, - "Setting PS wake up mode to %s failed..Reason :%s\n", - params.wakeup_mode ? "Listen interval" : "DTIM interval", - wifi_ps_get_config_err_code_str(params.fail_reason)); + PR_WARNING("Setting PS wake up mode to %s failed..Reason :%s\n", + params.wakeup_mode ? "Listen interval" : "DTIM interval", + wifi_ps_get_config_err_code_str(params.fail_reason)); return -ENOEXEC; } - shell_fprintf(sh, SHELL_NORMAL, "%s\n", - wifi_ps_wakeup_mode_txt(params.wakeup_mode)); + PR("%s\n", wifi_ps_wakeup_mode_txt(params.wakeup_mode)); return 0; } @@ -1598,7 +1566,7 @@ static int cmd_wifi_mode(const struct shell *sh, size_t argc, char *argv[]) mode_info.oper = WIFI_MGMT_SET; parse_mode_args_to_params(sh, argc, argv, &mode_info, &do_mode_oper); } else { - shell_fprintf(sh, SHELL_ERROR, "Invalid number of arguments\n"); + PR_ERROR("Invalid number of arguments\n"); return -EINVAL; } @@ -1609,17 +1577,15 @@ static int cmd_wifi_mode(const struct shell *sh, size_t argc, char *argv[]) if (mode_info.if_index == 0) { iface = net_if_get_first_wifi(); if (iface == NULL) { - shell_fprintf(sh, SHELL_ERROR, - "Cannot find the default wifi interface\n"); + PR_ERROR("Cannot find the default wifi interface\n"); return -ENOEXEC; } mode_info.if_index = net_if_get_by_iface(iface); } else { iface = net_if_get_by_index(mode_info.if_index); if (iface == NULL) { - shell_fprintf(sh, SHELL_ERROR, - "Cannot find interface for if_index %d\n", - mode_info.if_index); + PR_ERROR("Cannot find interface for if_index %d\n", + mode_info.if_index); return -ENOEXEC; } } @@ -1627,16 +1593,15 @@ static int cmd_wifi_mode(const struct shell *sh, size_t argc, char *argv[]) ret = net_mgmt(NET_REQUEST_WIFI_MODE, iface, &mode_info, sizeof(mode_info)); if (ret) { - shell_fprintf(sh, SHELL_ERROR, "mode %s operation failed with reason %d\n", - mode_info.oper == WIFI_MGMT_GET ? "get" : "set", ret); + PR_ERROR("mode %s operation failed with reason %d\n", + mode_info.oper == WIFI_MGMT_GET ? "get" : "set", ret); return -ENOEXEC; } if (mode_info.oper == WIFI_MGMT_GET) { - shell_fprintf(sh, SHELL_NORMAL, "Wi-Fi current mode is %x\n", - mode_info.mode); + PR("Wi-Fi current mode is %x\n", mode_info.mode); } else { - shell_fprintf(sh, SHELL_NORMAL, "Wi-Fi mode set to %x\n", mode_info.mode); + PR("Wi-Fi mode set to %x\n", mode_info.mode); } } return 0; @@ -1655,7 +1620,7 @@ void parse_channel_args_to_params(const struct shell *sh, int argc, {"help", no_argument, 0, 'h'}, {0, 0, 0, 0}}; - while ((opt = getopt_long(argc, argv, "i:c:gh", long_options, &option_index)) != -1) { + while ((opt = getopt_long(argc, argv, "i:c:gh", long_options, &option_index)) != -1) { switch (opt) { case 'c': channel->channel = (uint16_t)atoi(optarg); @@ -1698,17 +1663,15 @@ static int cmd_wifi_channel(const struct shell *sh, size_t argc, char *argv[]) if (channel_info.if_index == 0) { iface = net_if_get_first_wifi(); if (iface == NULL) { - shell_fprintf(sh, SHELL_ERROR, - "Cannot find the default wifi interface\n"); + PR_ERROR("Cannot find the default wifi interface\n"); return -ENOEXEC; } channel_info.if_index = net_if_get_by_iface(iface); } else { iface = net_if_get_by_index(channel_info.if_index); if (iface == NULL) { - shell_fprintf(sh, SHELL_ERROR, - "Cannot find interface for if_index %d\n", - channel_info.if_index); + PR_ERROR("Cannot find interface for if_index %d\n", + channel_info.if_index); return -ENOEXEC; } } @@ -1716,28 +1679,24 @@ static int cmd_wifi_channel(const struct shell *sh, size_t argc, char *argv[]) if (channel_info.oper == WIFI_MGMT_SET) { if ((channel_info.channel < WIFI_CHANNEL_MIN) || (channel_info.channel > WIFI_CHANNEL_MAX)) { - shell_fprintf(sh, SHELL_ERROR, - "Invalid channel number. Range is (1-233)\n"); + PR_ERROR("Invalid channel number. Range is (1-233)\n"); return -ENOEXEC; } } - ret = net_mgmt(NET_REQUEST_WIFI_CHANNEL, iface, - &channel_info, sizeof(channel_info)); + ret = net_mgmt(NET_REQUEST_WIFI_CHANNEL, iface, &channel_info, + sizeof(channel_info)); if (ret) { - shell_fprintf(sh, SHELL_ERROR, - "channel %s operation failed with reason %d\n", - channel_info.oper == WIFI_MGMT_GET ? "get" : "set", ret); + PR_ERROR("channel %s operation failed with reason %d\n", + channel_info.oper == WIFI_MGMT_GET ? "get" : "set", ret); return -ENOEXEC; } if (channel_info.oper == WIFI_MGMT_GET) { - shell_fprintf(sh, SHELL_NORMAL, "Wi-Fi current channel is: %d\n", - channel_info.channel); + PR("Wi-Fi current channel is: %d\n", channel_info.channel); } else { - shell_fprintf(sh, SHELL_NORMAL, "Wi-Fi channel set to %d\n", - channel_info.channel); + PR("Wi-Fi channel set to %d\n", channel_info.channel); } } return 0; @@ -1760,7 +1719,7 @@ void parse_filter_args_to_params(const struct shell *sh, int argc, {"help", no_argument, 0, 'h'}, {0, 0, 0, 0}}; - while ((opt = getopt_long(argc, argv, "i:b:amcdgh", long_options, &option_index)) != -1) { + while ((opt = getopt_long(argc, argv, "i:b:amcdgh", long_options, &option_index)) != -1) { switch (opt) { case 'a': filter->filter |= WIFI_PACKET_FILTER_ALL; @@ -1815,37 +1774,34 @@ static int cmd_wifi_packet_filter(const struct shell *sh, size_t argc, char *arg if (packet_filter.if_index == 0) { iface = net_if_get_first_wifi(); if (iface == NULL) { - shell_fprintf(sh, SHELL_ERROR, - "Cannot find the default wifi interface\n"); + PR_ERROR("Cannot find the default wifi interface\n"); return -ENOEXEC; } packet_filter.if_index = net_if_get_by_iface(iface); } else { iface = net_if_get_by_index(packet_filter.if_index); if (iface == NULL) { - shell_fprintf(sh, SHELL_ERROR, - "Cannot find interface for if_index %d\n", - packet_filter.if_index); + PR_ERROR("Cannot find interface for if_index %d\n", + packet_filter.if_index); return -ENOEXEC; } } - ret = net_mgmt(NET_REQUEST_WIFI_PACKET_FILTER, iface, - &packet_filter, sizeof(packet_filter)); + ret = net_mgmt(NET_REQUEST_WIFI_PACKET_FILTER, iface, &packet_filter, + sizeof(packet_filter)); if (ret) { - shell_fprintf(sh, SHELL_ERROR, - "Wi-Fi packet filter %s operation failed with reason %d\n", - packet_filter.oper == WIFI_MGMT_GET ? "get" : "set", ret); + PR_ERROR("Wi-Fi packet filter %s operation failed with reason %d\n", + packet_filter.oper == WIFI_MGMT_GET ? "get" : "set", ret); return -ENOEXEC; } if (packet_filter.oper == WIFI_MGMT_GET) { - shell_fprintf(sh, SHELL_NORMAL, "Wi-Fi current mode packet filter is %d\n", - packet_filter.filter); + PR("Wi-Fi current mode packet filter is %d\n", + packet_filter.filter); } else { - shell_fprintf(sh, SHELL_NORMAL, "Wi-Fi mode packet filter set to %d\n", - packet_filter.filter); + PR("Wi-Fi mode packet filter set to %d\n", + packet_filter.filter); } } return 0; @@ -1857,17 +1813,17 @@ static int cmd_wifi_version(const struct shell *sh, size_t argc, char *argv[]) struct wifi_version version = {0}; if (argc > 1) { - shell_fprintf(sh, SHELL_WARNING, "Invalid number of arguments\n"); + PR_WARNING("Invalid number of arguments\n"); return -ENOEXEC; } if (net_mgmt(NET_REQUEST_WIFI_VERSION, iface, &version, sizeof(version))) { - shell_fprintf(sh, SHELL_WARNING, "Failed to get Wi-Fi versions\n"); + PR_WARNING("Failed to get Wi-Fi versions\n"); return -ENOEXEC; } - shell_fprintf(sh, SHELL_NORMAL, "Wi-Fi Driver Version: %s\n", version.drv_version); - shell_fprintf(sh, SHELL_NORMAL, "Wi-Fi Firmware Version: %s\n", version.fw_version); + PR("Wi-Fi Driver Version: %s\n", version.drv_version); + PR("Wi-Fi Firmware Version: %s\n", version.fw_version); return 0; } From 055ac615427fd55fa347cd1744280734e730a42a Mon Sep 17 00:00:00 2001 From: Pisit Sawangvonganan Date: Wed, 31 Jan 2024 21:37:07 +0700 Subject: [PATCH 3246/3723] wifi: shell: replace print(...) with PR(...) Additionally, replace the local print(sh, level, fmt, ...) macros with PR, PR_ERROR, and PR_WARNING macros. Then remove the print(sh, level, fmt, ...) macros. Signed-off-by: Pisit Sawangvonganan --- subsys/net/l2/wifi/wifi_shell.c | 193 ++++++++++++++------------------ 1 file changed, 86 insertions(+), 107 deletions(-) diff --git a/subsys/net/l2/wifi/wifi_shell.c b/subsys/net/l2/wifi/wifi_shell.c index 9d24473e5cc..9e32db5c3d8 100644 --- a/subsys/net/l2/wifi/wifi_shell.c +++ b/subsys/net/l2/wifi/wifi_shell.c @@ -75,15 +75,6 @@ struct wifi_ap_sta_node { }; static struct wifi_ap_sta_node sta_list[CONFIG_WIFI_SHELL_MAX_AP_STA]; -#define print(sh, level, fmt, ...) \ - do { \ - if (sh) { \ - shell_fprintf(sh, level, fmt, ##__VA_ARGS__); \ - } else { \ - printk(fmt, ##__VA_ARGS__); \ - } \ - } while (false) - static bool parse_number(const struct shell *sh, long *param, char *str, long min, long max) { char *endptr; @@ -98,12 +89,12 @@ static bool parse_number(const struct shell *sh, long *param, char *str, long mi } if (*endptr != '\0') { - print(sh, SHELL_ERROR, "Invalid number: %s", str_tmp); + PR_ERROR("Invalid number: %s", str_tmp); return false; } if ((num) < (min) || (num) > (max)) { - print(sh, SHELL_WARNING, "Value out of range: %s, (%ld-%ld)", str_tmp, min, max); + PR_WARNING("Value out of range: %s, (%ld-%ld)", str_tmp, min, max); return false; } *param = num; @@ -115,26 +106,25 @@ static void handle_wifi_scan_result(struct net_mgmt_event_callback *cb) const struct wifi_scan_result *entry = (const struct wifi_scan_result *)cb->info; uint8_t mac_string_buf[sizeof("xx:xx:xx:xx:xx:xx")]; + const struct shell *sh = context.sh; context.scan_result++; if (context.scan_result == 1U) { - print(context.sh, SHELL_NORMAL, - "\n%-4s | %-32s %-5s | %-13s | %-4s | %-15s | %-17s | %-8s\n", - "Num", "SSID", "(len)", "Chan (Band)", "RSSI", "Security", "BSSID", "MFP"); - } - - print(context.sh, SHELL_NORMAL, - "%-4d | %-32s %-5u | %-4u (%-6s) | %-4d | %-15s | %-17s | %-8s\n", - context.scan_result, entry->ssid, entry->ssid_length, entry->channel, - wifi_band_txt(entry->band), - entry->rssi, - wifi_security_txt(entry->security), - ((entry->mac_length) ? - net_sprint_ll_addr_buf(entry->mac, WIFI_MAC_ADDR_LEN, - mac_string_buf, - sizeof(mac_string_buf)) : ""), - wifi_mfp_txt(entry->mfp)); + PR("\n%-4s | %-32s %-5s | %-13s | %-4s | %-15s | %-17s | %-8s\n", + "Num", "SSID", "(len)", "Chan (Band)", "RSSI", "Security", "BSSID", "MFP"); + } + + PR("%-4d | %-32s %-5u | %-4u (%-6s) | %-4d | %-15s | %-17s | %-8s\n", + context.scan_result, entry->ssid, entry->ssid_length, entry->channel, + wifi_band_txt(entry->band), + entry->rssi, + wifi_security_txt(entry->security), + ((entry->mac_length) ? + net_sprint_ll_addr_buf(entry->mac, WIFI_MAC_ADDR_LEN, + mac_string_buf, + sizeof(mac_string_buf)) : ""), + wifi_mfp_txt(entry->mfp)); } static int wifi_freq_to_channel(int frequency) @@ -188,28 +178,27 @@ static void handle_wifi_raw_scan_result(struct net_mgmt_event_callback *cb) context.scan_result++; if (context.scan_result == 1U) { - print(sh, SHELL_NORMAL, - "\n%-4s | %-13s | %-4s | %-15s | %-15s | %-32s\n", - "Num", "Channel (Band)", "RSSI", "BSSID", "Frame length", "Frame Body"); + PR("\n%-4s | %-13s | %-4s | %-15s | %-15s | %-32s\n", + "Num", "Channel (Band)", "RSSI", "BSSID", "Frame length", "Frame Body"); } rssi = raw->rssi; channel = wifi_freq_to_channel(raw->frequency); band = wifi_freq_to_band(raw->frequency); - print(sh, SHELL_NORMAL, "%-4d | %-4u (%-6s) | %-4d | %s | %-4d ", - context.scan_result, - channel, - wifi_band_txt(band), - rssi, - net_sprint_ll_addr_buf(raw->data + 10, WIFI_MAC_ADDR_LEN, mac_string_buf, - sizeof(mac_string_buf)), raw->frame_length); + PR("%-4d | %-4u (%-6s) | %-4d | %s | %-4d ", + context.scan_result, + channel, + wifi_band_txt(band), + rssi, + net_sprint_ll_addr_buf(raw->data + 10, WIFI_MAC_ADDR_LEN, mac_string_buf, + sizeof(mac_string_buf)), raw->frame_length); for (i = 0; i < 32; i++) { - print(sh, SHELL_NORMAL, "%02X ", *(raw->data + i)); + PR("%02X ", *(raw->data + i)); } - print(sh, SHELL_NORMAL, "\n"); + PR("\n"); } #endif /* CONFIG_WIFI_MGMT_RAW_SCAN_RESULTS */ @@ -220,10 +209,9 @@ static void handle_wifi_scan_done(struct net_mgmt_event_callback *cb) const struct shell *sh = context.sh; if (status->status) { - print(sh, SHELL_WARNING, - "Scan request failed (%d)\n", status->status); + PR_WARNING("Scan request failed (%d)\n", status->status); } else { - print(sh, SHELL_NORMAL, "Scan request done\n"); + PR("Scan request done\n"); } context.scan_result = 0U; @@ -233,12 +221,12 @@ static void handle_wifi_connect_result(struct net_mgmt_event_callback *cb) { const struct wifi_status *status = (const struct wifi_status *) cb->info; + const struct shell *sh = context.sh; if (status->status) { - print(context.sh, SHELL_WARNING, - "Connection request failed (%d)\n", status->status); + PR_WARNING("Connection request failed (%d)\n", status->status); } else { - print(context.sh, SHELL_NORMAL, "Connected\n"); + PR("Connected\n"); } context.connecting = false; @@ -248,16 +236,17 @@ static void handle_wifi_disconnect_result(struct net_mgmt_event_callback *cb) { const struct wifi_status *status = (const struct wifi_status *) cb->info; + const struct shell *sh = context.sh; if (context.disconnecting) { - print(context.sh, - status->status ? SHELL_WARNING : SHELL_NORMAL, - "Disconnection request %s (%d)\n", - status->status ? "failed" : "done", - status->status); + if (status->status) { + PR_WARNING("Disconnection request failed (%d)\n", status->status); + } else { + PR("Disconnection request done (%d)\n", status->status); + } context.disconnecting = false; } else { - print(context.sh, SHELL_NORMAL, "Disconnected\n"); + PR("Disconnected\n"); } } @@ -269,25 +258,25 @@ static void print_twt_params(uint8_t dialog_token, uint8_t flow_id, { const struct shell *sh = context.sh; - print(sh, SHELL_NORMAL, "TWT Dialog token: %d\n", + PR("TWT Dialog token: %d\n", dialog_token); - print(sh, SHELL_NORMAL, "TWT flow ID: %d\n", + PR("TWT flow ID: %d\n", flow_id); - print(sh, SHELL_NORMAL, "TWT negotiation type: %s\n", + PR("TWT negotiation type: %s\n", wifi_twt_negotiation_type_txt(negotiation_type)); - print(sh, SHELL_NORMAL, "TWT responder: %s\n", + PR("TWT responder: %s\n", responder ? "true" : "false"); - print(sh, SHELL_NORMAL, "TWT implicit: %s\n", + PR("TWT implicit: %s\n", implicit ? "true" : "false"); - print(sh, SHELL_NORMAL, "TWT announce: %s\n", + PR("TWT announce: %s\n", announce ? "true" : "false"); - print(sh, SHELL_NORMAL, "TWT trigger: %s\n", + PR("TWT trigger: %s\n", trigger ? "true" : "false"); - print(sh, SHELL_NORMAL, "TWT wake interval: %d us\n", + PR("TWT wake interval: %d us\n", twt_wake_interval); - print(sh, SHELL_NORMAL, "TWT interval: %lld us\n", + PR("TWT interval: %lld us\n", twt_interval); - print(sh, SHELL_NORMAL, "========================\n"); + PR("========================\n"); } static void handle_wifi_twt_event(struct net_mgmt_event_callback *cb) @@ -298,19 +287,19 @@ static void handle_wifi_twt_event(struct net_mgmt_event_callback *cb) if (resp->operation == WIFI_TWT_TEARDOWN) { if (resp->teardown_status == WIFI_TWT_TEARDOWN_SUCCESS) { - print(sh, SHELL_NORMAL, "TWT teardown succeeded for flow ID %d\n", + PR("TWT teardown succeeded for flow ID %d\n", resp->flow_id); } else { - print(sh, SHELL_NORMAL, "TWT teardown failed for flow ID %d\n", + PR("TWT teardown failed for flow ID %d\n", resp->flow_id); } return; } if (resp->resp_status == WIFI_TWT_RESP_RECEIVED) { - print(sh, SHELL_NORMAL, "TWT response: %s\n", + PR("TWT response: %s\n", wifi_twt_setup_cmd_txt(resp->setup_cmd)); - print(sh, SHELL_NORMAL, "== TWT negotiated parameters ==\n"); + PR("== TWT negotiated parameters ==\n"); print_twt_params(resp->dialog_token, resp->flow_id, resp->negotiation_type, @@ -321,7 +310,7 @@ static void handle_wifi_twt_event(struct net_mgmt_event_callback *cb) resp->setup.twt_wake_interval, resp->setup.twt_interval); } else { - print(sh, SHELL_NORMAL, "TWT response timed out\n"); + PR("TWT response timed out\n"); } } @@ -332,10 +321,9 @@ static void handle_wifi_ap_enable_result(struct net_mgmt_event_callback *cb) const struct shell *sh = context.sh; if (status->status) { - print(sh, SHELL_WARNING, - "AP enable request failed (%d)\n", status->status); + PR_WARNING("AP enable request failed (%d)\n", status->status); } else { - print(sh, SHELL_NORMAL, "AP enabled\n"); + PR("AP enabled\n"); } } @@ -346,10 +334,9 @@ static void handle_wifi_ap_disable_result(struct net_mgmt_event_callback *cb) const struct shell *sh = context.sh; if (status->status) { - print(sh, SHELL_WARNING, - "AP disable request failed (%d)\n", status->status); + PR_WARNING("AP disable request failed (%d)\n", status->status); } else { - print(sh, SHELL_NORMAL, "AP disabled\n"); + PR("AP disabled\n"); } k_mutex_lock(&wifi_ap_sta_list_lock, K_FOREVER); @@ -365,9 +352,9 @@ static void handle_wifi_ap_sta_connected(struct net_mgmt_event_callback *cb) uint8_t mac_string_buf[sizeof("xx:xx:xx:xx:xx:xx")]; int i; - print(sh, SHELL_NORMAL, "Station connected: %s\n", - net_sprint_ll_addr_buf(sta_info->mac, WIFI_MAC_ADDR_LEN, - mac_string_buf, sizeof(mac_string_buf))); + PR("Station connected: %s\n", + net_sprint_ll_addr_buf(sta_info->mac, WIFI_MAC_ADDR_LEN, + mac_string_buf, sizeof(mac_string_buf))); k_mutex_lock(&wifi_ap_sta_list_lock, K_FOREVER); for (i = 0; i < CONFIG_WIFI_SHELL_MAX_AP_STA; i++) { @@ -378,8 +365,8 @@ static void handle_wifi_ap_sta_connected(struct net_mgmt_event_callback *cb) } } if (i == CONFIG_WIFI_SHELL_MAX_AP_STA) { - print(sh, SHELL_WARNING, "No space to store station info: " - "Increase CONFIG_WIFI_SHELL_MAX_AP_STA\n"); + PR_WARNING("No space to store station info: " + "Increase CONFIG_WIFI_SHELL_MAX_AP_STA\n"); } k_mutex_unlock(&wifi_ap_sta_list_lock); } @@ -391,9 +378,9 @@ static void handle_wifi_ap_sta_disconnected(struct net_mgmt_event_callback *cb) const struct shell *sh = context.sh; uint8_t mac_string_buf[sizeof("xx:xx:xx:xx:xx:xx")]; - print(sh, SHELL_NORMAL, "Station disconnected: %s\n", - net_sprint_ll_addr_buf(sta_info->mac, WIFI_MAC_ADDR_LEN, - mac_string_buf, sizeof(mac_string_buf))); + PR("Station disconnected: %s\n", + net_sprint_ll_addr_buf(sta_info->mac, WIFI_MAC_ADDR_LEN, + mac_string_buf, sizeof(mac_string_buf))); k_mutex_lock(&wifi_ap_sta_list_lock, K_FOREVER); for (int i = 0; i < CONFIG_WIFI_SHELL_MAX_AP_STA; i++) { @@ -468,9 +455,8 @@ static int __wifi_args_to_params(size_t argc, char *argv[], params->ssid = argv[0]; params->ssid_length = strlen(params->ssid); if (params->ssid_length > WIFI_SSID_MAX_LEN) { - print(sh, SHELL_WARNING, - "SSID too long (max %d characters)\n", - WIFI_SSID_MAX_LEN); + PR_WARNING("SSID too long (max %d characters)\n", + WIFI_SSID_MAX_LEN); return -EINVAL; } @@ -486,11 +472,10 @@ static int __wifi_args_to_params(size_t argc, char *argv[], size_t offset = 0; if (*endptr != '\0') { - print(sh, SHELL_ERROR, - "Failed to parse channel: %s: endp: %s, err: %s\n", - argv[idx], - endptr, - strerror(errno)); + PR_ERROR("Failed to parse channel: %s: endp: %s, err: %s\n", + argv[idx], + endptr, + strerror(errno)); return -EINVAL; } @@ -508,15 +493,13 @@ static int __wifi_args_to_params(size_t argc, char *argv[], params->band = WIFI_FREQ_BAND_6_GHZ; break; default: - print(sh, SHELL_ERROR, - "Invalid band: %ld\n", channel); + PR_ERROR("Invalid band: %ld\n", channel); return -EINVAL; } } } else { if (channel < 0) { - print(sh, SHELL_ERROR, - "Invalid channel: %ld\n", channel); + PR_ERROR("Invalid channel: %ld\n", channel); return -EINVAL; } } @@ -529,10 +512,9 @@ static int __wifi_args_to_params(size_t argc, char *argv[], band ? "," : "", wifi_band_txt(all_bands[band])); if (offset >= sizeof(bands_str)) { - print(sh, SHELL_ERROR, - "Failed to parse channel: %s: " - "band string too long\n", - argv[idx]); + PR_ERROR("Failed to parse channel: %s: " + "band string too long\n", + argv[idx]); return -EINVAL; } @@ -544,10 +526,9 @@ static int __wifi_args_to_params(size_t argc, char *argv[], } if (!found) { - print(sh, SHELL_ERROR, - "Invalid channel: %ld, checked bands: %s\n", - channel, - bands_str); + PR_ERROR("Invalid channel: %ld, checked bands: %s\n", + channel, + bands_str); return -EINVAL; } @@ -580,9 +561,8 @@ static int __wifi_args_to_params(size_t argc, char *argv[], if (security == WIFI_SECURITY_TYPE_NONE || security == WIFI_SECURITY_TYPE_WPA_PSK) { - print(sh, SHELL_ERROR, - "MFP not supported for security type %s\n", - wifi_security_txt(security)); + PR_ERROR("MFP not supported for security type %s\n", + wifi_security_txt(security)); return -EINVAL; } @@ -598,10 +578,9 @@ static int __wifi_args_to_params(size_t argc, char *argv[], params->psk_length > WIFI_PSK_MAX_LEN) || (params->security == WIFI_SECURITY_TYPE_SAE && params->psk_length > WIFI_SAE_PSWD_MAX_LEN)) { - print(sh, SHELL_ERROR, - "Invalid PSK length (%d) for security type %s\n", - params->psk_length, - wifi_security_txt(params->security)); + PR_ERROR("Invalid PSK length (%d) for security type %s\n", + params->psk_length, + wifi_security_txt(params->security)); return -EINVAL; } } From 8b8569e1da447978bc44e57d085f750415fe3efa Mon Sep 17 00:00:00 2001 From: Emil Gydesen Date: Mon, 22 Jan 2024 08:47:27 +0100 Subject: [PATCH 3247/3723] Bluetooth: BAP: Add missing reset of client on disconnected If we disconnect in the middle of e.g. a discovery, then client-busy (and other values) were not correctly reset, which effectively rendered the client useless. Signed-off-by: Emil Gydesen --- subsys/bluetooth/audio/bap_unicast_client.c | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/subsys/bluetooth/audio/bap_unicast_client.c b/subsys/bluetooth/audio/bap_unicast_client.c index 29d185b9df7..1bc2191a9c9 100644 --- a/subsys/bluetooth/audio/bap_unicast_client.c +++ b/subsys/bluetooth/audio/bap_unicast_client.c @@ -2086,6 +2086,7 @@ static void unicast_client_reset(struct bt_bap_ep *ep, uint8_t reason) static void unicast_client_ep_reset(struct bt_conn *conn, uint8_t reason) { + struct unicast_client *client; uint8_t index; LOG_DBG("conn %p", conn); @@ -2107,6 +2108,11 @@ static void unicast_client_ep_reset(struct bt_conn *conn, uint8_t reason) unicast_client_reset(ep, reason); } #endif /* CONFIG_BT_BAP_UNICAST_CLIENT_ASE_SRC_COUNT > 0 */ + + client = &uni_cli_insts[index]; + client->busy = false; + client->dir = 0U; + reset_att_buf(client); } static void bt_audio_codec_qos_to_cig_param(struct bt_iso_cig_param *cig_param, From 13a357b0198defde8f5c34920bec25b9ea2a0855 Mon Sep 17 00:00:00 2001 From: Emil Gydesen Date: Wed, 31 Jan 2024 11:05:28 +0100 Subject: [PATCH 3248/3723] Bluetooth: BAP: Update log for unicast iso recv without endpoint Since we always set up the ISO data path for endpoints in both directions (due to limitations in the ISO API), we can actually receive valid (empty) SDUs on a CIS in a direction that has not been configured. This is not the ideal solution, but prevents unncessary LOG_ERR. The ideal solution is to modify the ISO API to provide the flexibility that BAP needs w.r.t. ISO data paths, but that is a larger change for later. Signed-off-by: Emil Gydesen --- subsys/bluetooth/audio/ascs.c | 3 ++- subsys/bluetooth/audio/bap_unicast_client.c | 3 ++- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/subsys/bluetooth/audio/ascs.c b/subsys/bluetooth/audio/ascs.c index 229eb90edb8..40f673166a6 100644 --- a/subsys/bluetooth/audio/ascs.c +++ b/subsys/bluetooth/audio/ascs.c @@ -853,7 +853,8 @@ static void ascs_iso_recv(struct bt_iso_chan *chan, * host as HCI ISO data packets, which we should just ignore */ if ((info->flags & BT_ISO_FLAGS_VALID) != 0) { - LOG_ERR("iso %p not bound with ep", chan); + LOG_DBG("Valid ISO packet of len %zu received for iso %p not bound with ep", + net_buf_frags_len(buf), chan); } return; diff --git a/subsys/bluetooth/audio/bap_unicast_client.c b/subsys/bluetooth/audio/bap_unicast_client.c index 1bc2191a9c9..13adf0421a4 100644 --- a/subsys/bluetooth/audio/bap_unicast_client.c +++ b/subsys/bluetooth/audio/bap_unicast_client.c @@ -231,7 +231,8 @@ static void unicast_client_ep_iso_recv(struct bt_iso_chan *chan, * host as HCI ISO data packets, which we should just ignore */ if ((info->flags & BT_ISO_FLAGS_VALID) != 0) { - LOG_ERR("iso %p not bound with ep", chan); + LOG_DBG("Valid ISO packet of len %zu received for iso %p not bound with ep", + net_buf_frags_len(buf), chan); } return; From 63cdde10d388f1223970206d646a5fb6b2e1548a Mon Sep 17 00:00:00 2001 From: Fabio Baltieri Date: Fri, 5 Jan 2024 20:49:42 +0000 Subject: [PATCH 3249/3723] charger: bq25180: reuse bq25180_set_charge_current for the initial set Reuse bq25180_set_charge_current for the initial setting of the charging current. Signed-off-by: Fabio Baltieri --- drivers/charger/charger_bq25180.c | 8 +------- 1 file changed, 1 insertion(+), 7 deletions(-) diff --git a/drivers/charger/charger_bq25180.c b/drivers/charger/charger_bq25180.c index 7063377c589..3df881d812e 100644 --- a/drivers/charger/charger_bq25180.c +++ b/drivers/charger/charger_bq25180.c @@ -188,13 +188,7 @@ static int bq25180_init(const struct device *dev) } if (cfg->initial_current_microamp > 0) { - ret = bq25180_ma_to_ichg(cfg->initial_current_microamp / 1000, &val); - if (ret < 0) { - return ret; - } - - ret = i2c_reg_update_byte_dt(&cfg->i2c, BQ25180_ICHG_CTRL, - BQ25180_ICHG_MSK, val); + bq25180_set_charge_current(dev, cfg->initial_current_microamp); if (ret < 0) { return ret; } From 044529d0cd06c9bcaf64a78ade7a123e7fb8c9a3 Mon Sep 17 00:00:00 2001 From: Fabio Baltieri Date: Mon, 29 Jan 2024 18:32:47 +0000 Subject: [PATCH 3250/3723] charger: bq25180: implement online and status properties Implement CHARGER_PROP_ONLINE and CHARGER_PROP_STATUS for the bq25180 driver. Signed-off-by: Fabio Baltieri --- drivers/charger/charger_bq25180.c | 75 +++++++++++++++++++++++++++++++ 1 file changed, 75 insertions(+) diff --git a/drivers/charger/charger_bq25180.c b/drivers/charger/charger_bq25180.c index 3df881d812e..dbc20b30b06 100644 --- a/drivers/charger/charger_bq25180.c +++ b/drivers/charger/charger_bq25180.c @@ -26,6 +26,12 @@ LOG_MODULE_REGISTER(bq25180, CONFIG_CHARGER_LOG_LEVEL); #define BQ25180_SHIP_RST 0x09 #define BQ25180_MASK_ID 0x0c +#define BQ25180_STAT0_CHG_STAT_MASK GENMASK(6, 5) +#define BQ25180_STAT0_CHG_STAT_NOT_CHARGING 0x00 +#define BQ25180_STAT0_CHG_STAT_CONSTANT_CURRENT 0x01 +#define BQ25180_STAT0_CHG_STAT_CONSTANT_VOLTAGE 0x02 +#define BQ25180_STAT0_CHG_STAT_DONE 0x03 +#define BQ25180_STAT0_VIN_PGOOD_STAT BIT(0) #define BQ25180_ICHG_CHG_DIS BIT(7) #define BQ25180_ICHG_MSK GENMASK(6, 0) #define BQ25180_WATCHDOG_SEL_1_MSK GENMASK(1, 0) @@ -134,10 +140,79 @@ static int bq25180_get_charge_current(const struct device *dev, return 0; } +static int bq25180_get_online(const struct device *dev, + enum charger_online *online) +{ + const struct bq25180_config *cfg = dev->config; + uint8_t val; + int ret; + + ret = i2c_reg_read_byte_dt(&cfg->i2c, BQ25180_STAT0, &val); + if (ret < 0) { + return ret; + } + + if ((val & BQ25180_STAT0_VIN_PGOOD_STAT) != 0x00) { + *online = CHARGER_ONLINE_FIXED; + } else { + *online = CHARGER_ONLINE_OFFLINE; + } + + return 0; +} + +static int bq25180_get_status(const struct device *dev, + enum charger_status *status) +{ + const struct bq25180_config *cfg = dev->config; + uint8_t stat0; + uint8_t ichg_ctrl; + int ret; + + ret = i2c_reg_read_byte_dt(&cfg->i2c, BQ25180_STAT0, &stat0); + if (ret < 0) { + return ret; + } + + if ((stat0 & BQ25180_STAT0_VIN_PGOOD_STAT) == 0x00) { + *status = CHARGER_STATUS_DISCHARGING; + return 0; + } + + ret = i2c_reg_read_byte_dt(&cfg->i2c, BQ25180_ICHG_CTRL, &ichg_ctrl); + if (ret < 0) { + return ret; + } + + if ((ichg_ctrl & BQ25180_ICHG_CHG_DIS) != 0x00) { + *status = CHARGER_STATUS_NOT_CHARGING; + return 0; + } + + switch (FIELD_GET(BQ25180_STAT0_CHG_STAT_MASK, stat0)) { + case BQ25180_STAT0_CHG_STAT_NOT_CHARGING: + *status = CHARGER_STATUS_NOT_CHARGING; + break; + case BQ25180_STAT0_CHG_STAT_CONSTANT_CURRENT: + case BQ25180_STAT0_CHG_STAT_CONSTANT_VOLTAGE: + *status = CHARGER_STATUS_CHARGING; + break; + case BQ25180_STAT0_CHG_STAT_DONE: + *status = CHARGER_STATUS_FULL; + break; + } + + return 0; +} + static int bq25180_get_prop(const struct device *dev, charger_prop_t prop, union charger_propval *val) { switch (prop) { + case CHARGER_PROP_ONLINE: + return bq25180_get_online(dev, &val->online); + case CHARGER_PROP_STATUS: + return bq25180_get_status(dev, &val->status); case CHARGER_PROP_CONSTANT_CHARGE_CURRENT_UA: return bq25180_get_charge_current(dev, &val->const_charge_current_ua); default: From 01d0f1a56624121f8d453d40ab8f7dba77150ff4 Mon Sep 17 00:00:00 2001 From: Emil Gydesen Date: Mon, 22 Jan 2024 10:15:49 +0100 Subject: [PATCH 3251/3723] Bluetooth: PBP: Fix parsing and return issue with bt_pbp_parse_announcement bt_pbp_parse_announcement was defined as uint8_t return value function, but returned errno values, so it was modified to return an int instead. The return values are also now more granular and documented. The function also triggered a coverity issue with the way that it parsed the data->data, as it would be marked as tainted. This should be fixed by using the net_buf_simple API, which also improves on some other parts of the code. Finally the meta argument for the function was changed from an unknown sized buffer, where the caller somehow had to know the size of the metadata before calling the parsing function, to an output pointer. This also omits the requirement for the caller to always copy the metadata, where now it just gets a pointer to the metadata in the bt_data struct. The application can now always decide whether to continue to parse the metadata or to copy it, using the pointer and the return value of the function. Signed-off-by: Emil Gydesen --- include/zephyr/bluetooth/audio/pbp.h | 18 ++++++---- .../public_broadcast_sink/src/main.c | 19 +++++----- subsys/bluetooth/audio/pbp.c | 36 +++++++++++-------- .../src/pbp_public_broadcast_sink_test.c | 14 ++++---- 4 files changed, 49 insertions(+), 38 deletions(-) diff --git a/include/zephyr/bluetooth/audio/pbp.h b/include/zephyr/bluetooth/audio/pbp.h index 2ea85564fa7..acc53adb5ad 100644 --- a/include/zephyr/bluetooth/audio/pbp.h +++ b/include/zephyr/bluetooth/audio/pbp.h @@ -59,15 +59,19 @@ int bt_pbp_get_announcement(const uint8_t meta[], size_t meta_len, * @brief Parses the received advertising data corresponding to a Public Broadcast * Announcement. Returns the advertised Public Broadcast Announcement features and metadata. * - * @param data Advertising data to be checked - * @param features Public broadcast source features - * @param meta Pointer to copy the metadata present in the advertising data + * @param[in] data Advertising data to be checked + * @param[out] features Pointer to public broadcast source features to store the parsed features in + * @param[out] meta Pointer to the metadata present in the advertising data * - * @return parsed metadata length on success or an appropriate error code + * @return parsed metadata length on success. + * @retval -EINVAL if @p data, @p features or @p meta are NULL. + * @retval -ENOENT if @p data is not of type @ref BT_DATA_SVC_DATA16 or if the UUID in the service + * data is not @ref BT_UUID_PBA. + * @retval -EMSGSIZE if @p data is not large enough to contain a PBP announcement. + * @retval -EBADMSG if the @p data contains invalid data. */ -uint8_t bt_pbp_parse_announcement(struct bt_data *data, - enum bt_pbp_announcement_feature *features, - uint8_t *meta); +int bt_pbp_parse_announcement(struct bt_data *data, enum bt_pbp_announcement_feature *features, + uint8_t **meta); #ifdef __cplusplus } diff --git a/samples/bluetooth/public_broadcast_sink/src/main.c b/samples/bluetooth/public_broadcast_sink/src/main.c index 1331ffbeded..52d1cadbad7 100644 --- a/samples/bluetooth/public_broadcast_sink/src/main.c +++ b/samples/bluetooth/public_broadcast_sink/src/main.c @@ -29,7 +29,6 @@ #define INVALID_BROADCAST_ID 0xFFFFFFFF static bool pbs_found; -static uint8_t meta[CONFIG_BT_AUDIO_CODEC_CAP_MAX_METADATA_SIZE]; static K_SEM_DEFINE(sem_pa_synced, 0U, 1U); static K_SEM_DEFINE(sem_base_received, 0U, 1U); @@ -160,11 +159,11 @@ static void sync_broadcast_pa(const struct bt_le_scan_recv_info *info, static bool scan_check_and_sync_broadcast(struct bt_data *data, void *user_data) { + enum bt_pbp_announcement_feature source_features; uint32_t *broadcast_id = user_data; struct bt_uuid_16 adv_uuid; - enum bt_pbp_announcement_feature source_features = 0U; - - memset(meta, 0, ARRAY_SIZE(meta)); + uint8_t *tmp_meta = NULL; + int ret; if (data->type != BT_DATA_SVC_DATA16) { return true; @@ -179,16 +178,18 @@ static bool scan_check_and_sync_broadcast(struct bt_data *data, void *user_data) return true; } - if (!bt_uuid_cmp(&adv_uuid.uuid, BT_UUID_PBA)) { - bt_pbp_parse_announcement(data, &source_features, meta); + ret = bt_pbp_parse_announcement(data, &source_features, &tmp_meta); + if (ret >= 0) { if (!(source_features & BT_PBP_ANNOUNCEMENT_FEATURE_HIGH_QUALITY)) { /* This is a Standard Quality Public Broadcast Audio stream */ printk("This is a Standard Quality Public Broadcast Audio stream\n"); pbs_found = false; - return true; + return false; } - printk("Found Suitable Public Broadcast Announcement\n"); + + printk("Found Suitable Public Broadcast Announcement with %d octets of metadata\n", + ret); pbs_found = true; /** @@ -198,8 +199,6 @@ static bool scan_check_and_sync_broadcast(struct bt_data *data, void *user_data) if (*broadcast_id == INVALID_BROADCAST_ID) { return true; } - - return false; } return true; diff --git a/subsys/bluetooth/audio/pbp.c b/subsys/bluetooth/audio/pbp.c index 9cb589c9095..3b624045de2 100644 --- a/subsys/bluetooth/audio/pbp.c +++ b/subsys/bluetooth/audio/pbp.c @@ -45,37 +45,43 @@ int bt_pbp_get_announcement(const uint8_t meta[], size_t meta_len, return 0; } -uint8_t bt_pbp_parse_announcement(struct bt_data *data, - enum bt_pbp_announcement_feature *features, - uint8_t *meta) +int bt_pbp_parse_announcement(struct bt_data *data, enum bt_pbp_announcement_feature *features, + uint8_t **meta) { - uint8_t meta_len = 0; struct bt_uuid_16 adv_uuid; + struct net_buf_simple buf; + uint8_t meta_len = 0; + void *uuid; CHECKIF(!data || !features || !meta) { return -EINVAL; } - if (data->data_len < BT_PBP_MIN_PBA_SIZE) { - return -EBADMSG; - } - if (data->type != BT_DATA_SVC_DATA16) { - return -EINVAL; + return -ENOENT; } - if (!bt_uuid_create(&adv_uuid.uuid, data->data, BT_UUID_SIZE_16)) { - return -EINVAL; + if (data->data_len < BT_PBP_MIN_PBA_SIZE) { + return -EMSGSIZE; } + net_buf_simple_init_with_data(&buf, (void *)data->data, data->data_len); + uuid = net_buf_simple_pull_mem(&buf, BT_UUID_SIZE_16); + + (void)bt_uuid_create(&adv_uuid.uuid, uuid, BT_UUID_SIZE_16); /* cannot fail */ + if (bt_uuid_cmp(&adv_uuid.uuid, BT_UUID_PBA)) { - return -EBADMSG; + return -ENOENT; } /* Copy source features, metadata length and metadata from the Announcement */ - *features = data->data[BT_UUID_SIZE_16]; - meta_len = data->data[BT_UUID_SIZE_16 + sizeof(uint8_t)]; - memcpy(meta, data->data + BT_PBP_MIN_PBA_SIZE, meta_len); + *features = net_buf_simple_pull_u8(&buf); + meta_len = net_buf_simple_pull_u8(&buf); + if (buf.len < meta_len) { + return -EBADMSG; + } + + *meta = (uint8_t *)net_buf_simple_pull_mem(&buf, meta_len); return meta_len; } diff --git a/tests/bsim/bluetooth/audio/src/pbp_public_broadcast_sink_test.c b/tests/bsim/bluetooth/audio/src/pbp_public_broadcast_sink_test.c index 6154fae570e..c1e0a0f2e00 100644 --- a/tests/bsim/bluetooth/audio/src/pbp_public_broadcast_sink_test.c +++ b/tests/bsim/bluetooth/audio/src/pbp_public_broadcast_sink_test.c @@ -264,9 +264,10 @@ static void sync_broadcast_pa(const struct bt_le_scan_recv_info *info) static bool scan_check_and_sync_broadcast(struct bt_data *data, void *user_data) { + enum bt_pbp_announcement_feature source_features; struct bt_uuid_16 adv_uuid; - uint8_t source_features = 0U; - uint8_t meta[50]; + uint8_t *tmp_meta; + int ret; if (data->type != BT_DATA_SVC_DATA16) { return true; @@ -288,17 +289,18 @@ static bool scan_check_and_sync_broadcast(struct bt_data *data, void *user_data) } } - if (!bt_uuid_cmp(&adv_uuid.uuid, BT_UUID_PBA)) { - bt_pbp_parse_announcement(data, &source_features, meta); + ret = bt_pbp_parse_announcement(data, &source_features, &tmp_meta); + if (ret >= 0) { if (!(source_features & BT_PBP_ANNOUNCEMENT_FEATURE_HIGH_QUALITY)) { /* This is a Standard Quality Public Broadcast Audio stream - do not sync */ printk("This is a Standard Quality Public Broadcast Audio stream\n"); pbs_found = false; - return true; + return false; } - printk("Found Suitable Public Broadcast Announcement\n"); + printk("Found Suitable Public Broadcast Announcement with %d octets of metadata\n", + ret); pbs_found = true; /* Continue parsing if Broadcast Audio Announcement Service was not found */ From 1da84e99aaa6d555729efca02d5b64f64e89c797 Mon Sep 17 00:00:00 2001 From: Emil Gydesen Date: Wed, 17 Jan 2024 14:32:23 +0100 Subject: [PATCH 3252/3723] Bluetooth: MPL: Fix track position in playing and stopped state In the playing state, we should still increment the track position, but just avoid notifying it. If the track is stopped, then we set the track position to 0, which we should always notify, regardless of whether the current track position is 0. Signed-off-by: Emil Gydesen --- subsys/bluetooth/audio/mpl.c | 36 +++++++++++++++++++++++++----------- 1 file changed, 25 insertions(+), 11 deletions(-) diff --git a/subsys/bluetooth/audio/mpl.c b/subsys/bluetooth/audio/mpl.c index 94e15071d2c..111482b3e04 100644 --- a/subsys/bluetooth/audio/mpl.c +++ b/subsys/bluetooth/audio/mpl.c @@ -2026,10 +2026,23 @@ static void set_track_position(int32_t position) LOG_DBG("Pos. given: %d, resulting pos.: %d (duration is %d)", position, new_pos, media_player.group->track->duration); - if (new_pos != old_pos) { + /* Notify when the position changes when not in the playing state, or if the position is set + * to 0 which is a special value that typically indicates that the track has stopped or + * changed. Since this might occur when media_player.group->track->duration is still 0, we + * should always notify this value. + */ + if (new_pos != old_pos || new_pos == 0) { /* Set new position and notify it */ media_player.track_pos = new_pos; - media_proxy_pl_track_position_cb(new_pos); + + /* MCS 1.0, section 3.7.1, states: + * to avoid an excessive number of notifications, the Track Position should + * not be notified when the Media State is set to “Playing” and playback happens + * at a constant speed. + */ + if (media_player.state != MEDIA_PROXY_STATE_PLAYING) { + media_proxy_pl_track_position_cb(new_pos); + } } } @@ -2300,20 +2313,21 @@ static uint8_t get_content_ctrl_id(void) static void pos_work_cb(struct k_work *work) { - if (media_player.state == MEDIA_PROXY_STATE_SEEKING) { - const int32_t pos_diff_cs = - TRACK_POS_WORK_DELAY_MS / 10; /* position is in centiseconds*/ + const int32_t pos_diff_cs = TRACK_POS_WORK_DELAY_MS / 10; /* position is in centiseconds*/ + if (media_player.state == MEDIA_PROXY_STATE_SEEKING) { /* When seeking, apply the seeking speed factor */ set_relative_track_position(pos_diff_cs * media_player.seeking_speed_factor); + } else if (media_player.state == MEDIA_PROXY_STATE_PLAYING) { + set_relative_track_position(pos_diff_cs); + } - if (media_player.track_pos == media_player.group->track->duration) { - /* Go to next track */ - do_next_track(&media_player); - } - - (void)k_work_schedule(&media_player.pos_work, TRACK_POS_WORK_DELAY); + if (media_player.track_pos == media_player.group->track->duration) { + /* Go to next track */ + do_next_track(&media_player); } + + (void)k_work_schedule(&media_player.pos_work, TRACK_POS_WORK_DELAY); } int media_proxy_pl_init(void) From 029afad6c1114a852d7b6c484a6636af2ab96e3b Mon Sep 17 00:00:00 2001 From: Emil Gydesen Date: Mon, 8 Jan 2024 15:51:16 +0100 Subject: [PATCH 3253/3723] Bluetooth: CSIP: Add bt_csip_set_member_unregister Add support for unregistering a CSIS as the CSIP set member. Signed-off-by: Emil Gydesen --- include/zephyr/bluetooth/audio/csip.h | 11 +++++ subsys/bluetooth/audio/cap_acceptor.c | 8 ++++ subsys/bluetooth/audio/csip_set_member.c | 35 ++++++++++++++-- .../audio/src/csip_set_member_test.c | 40 +++++++++++-------- 4 files changed, 74 insertions(+), 20 deletions(-) diff --git a/include/zephyr/bluetooth/audio/csip.h b/include/zephyr/bluetooth/audio/csip.h index 9e96ef58748..a8b04dcb440 100644 --- a/include/zephyr/bluetooth/audio/csip.h +++ b/include/zephyr/bluetooth/audio/csip.h @@ -186,6 +186,17 @@ void *bt_csip_set_member_svc_decl_get(const struct bt_csip_set_member_svc_inst * int bt_csip_set_member_register(const struct bt_csip_set_member_register_param *param, struct bt_csip_set_member_svc_inst **svc_inst); +/** + * @brief Unregister a Coordinated Set Identification Service instance. + * + * This will unregister and disable the service instance. + * + * @param svc_inst Pointer to the registered Coordinated Set Identification Service. + * + * @return 0 if success, errno on failure. + */ +int bt_csip_set_member_unregister(struct bt_csip_set_member_svc_inst *svc_inst); + /** * @brief Print the SIRK to the debug output * diff --git a/subsys/bluetooth/audio/cap_acceptor.c b/subsys/bluetooth/audio/cap_acceptor.c index 56ed5fa2daa..d84fad1e8fb 100644 --- a/subsys/bluetooth/audio/cap_acceptor.c +++ b/subsys/bluetooth/audio/cap_acceptor.c @@ -50,7 +50,15 @@ int bt_cap_acceptor_register(const struct bt_csip_set_member_register_param *par err = bt_gatt_service_register(&cas); if (err) { + const int csip_err = bt_csip_set_member_unregister(*svc_inst); + + if (csip_err) { + LOG_ERR("Failed to unregister CSIS: %d", csip_err); + } + + cas.attrs[1].user_data = NULL; LOG_DBG("Failed to register CAS"); + return err; } diff --git a/subsys/bluetooth/audio/csip_set_member.c b/subsys/bluetooth/audio/csip_set_member.c index d738cf05f4c..a3eb14241c9 100644 --- a/subsys/bluetooth/audio/csip_set_member.c +++ b/subsys/bluetooth/audio/csip_set_member.c @@ -144,9 +144,13 @@ static int notify_lock_value(const struct bt_csip_set_member_svc_inst *svc_inst, struct bt_conn *conn) { LOG_DBG(""); - return csip_gatt_notify_set_lock(conn, svc_inst->service_p->attrs, - &svc_inst->set_lock, - sizeof(svc_inst->set_lock)); + + if (svc_inst->service_p != NULL) { + return csip_gatt_notify_set_lock(conn, svc_inst->service_p->attrs, + &svc_inst->set_lock, sizeof(svc_inst->set_lock)); + } else { + return -EINVAL; + } } static void notify_client(struct bt_conn *conn, void *data) @@ -727,6 +731,10 @@ BT_GATT_SERVICE_INSTANCE_DEFINE(csip_set_member_service_list, svc_insts, /****************************** Public API ******************************/ void *bt_csip_set_member_svc_decl_get(const struct bt_csip_set_member_svc_inst *svc_inst) { + if (svc_inst == NULL || svc_inst->service_p == NULL) { + return NULL; + } + return svc_inst->service_p->attrs; } @@ -944,6 +952,27 @@ int bt_csip_set_member_register(const struct bt_csip_set_member_register_param * return 0; } +int bt_csip_set_member_unregister(struct bt_csip_set_member_svc_inst *svc_inst) +{ + int err; + + CHECKIF(svc_inst == NULL) { + LOG_DBG("NULL svc_inst"); + return -EINVAL; + } + + err = bt_gatt_service_unregister(svc_inst->service_p); + if (err != 0) { + LOG_DBG("CSIS service unregister failed: %d", err); + return err; + } + + (void)k_work_cancel_delayable(&svc_inst->set_lock_timer); + memset(svc_inst, 0, sizeof(*svc_inst)); + + return 0; +} + int bt_csip_set_member_lock(struct bt_csip_set_member_svc_inst *svc_inst, bool lock, bool force) { diff --git a/tests/bsim/bluetooth/audio/src/csip_set_member_test.c b/tests/bsim/bluetooth/audio/src/csip_set_member_test.c index 1c0d6373cc8..795c94ddf35 100644 --- a/tests/bsim/bluetooth/audio/src/csip_set_member_test.c +++ b/tests/bsim/bluetooth/audio/src/csip_set_member_test.c @@ -22,17 +22,6 @@ struct bt_csip_set_member_register_param param = { 0x22, 0xfd, 0xa1, 0x21, 0x09, 0x7d, 0x7d, 0x45 }, }; -static void csip_disconnected(struct bt_conn *conn, uint8_t reason) -{ - printk("Disconnected (reason %u)\n", reason); - - if (reason == BT_HCI_ERR_REMOTE_USER_TERM_CONN) { - PASS("Client successfully disconnected\n"); - } else { - FAIL("Client disconnected unexpectedly (0x%02x)\n", reason); - } -} - static void csip_lock_changed_cb(struct bt_conn *conn, struct bt_csip_set_member_svc_inst *svc_inst, bool locked) @@ -87,10 +76,6 @@ static void bt_ready(int err) } } -static struct bt_conn_cb conn_callbacks = { - .disconnected = csip_disconnected, -}; - static void test_main(void) { int err; @@ -102,7 +87,17 @@ static void test_main(void) return; } - bt_conn_cb_register(&conn_callbacks); + WAIT_FOR_FLAG(flag_connected); + WAIT_FOR_UNSET_FLAG(flag_connected); + + err = bt_csip_set_member_unregister(svc_inst); + if (err != 0) { + FAIL("Could not unregister CSIP (err %d)\n", err); + return; + } + svc_inst = NULL; + + PASS("CSIP Set member passed: Client successfully disconnected\n"); } static void test_force_release(void) @@ -116,11 +111,22 @@ static void test_force_release(void) return; } - bt_conn_cb_register(&conn_callbacks); + WAIT_FOR_FLAG(flag_connected); WAIT_FOR_COND(g_locked); printk("Force releasing set\n"); bt_csip_set_member_lock(svc_inst, false, true); + + WAIT_FOR_UNSET_FLAG(flag_connected); + + err = bt_csip_set_member_unregister(svc_inst); + if (err != 0) { + FAIL("Could not unregister CSIP (err %d)\n", err); + return; + } + svc_inst = NULL; + + PASS("CSIP Set member passed: Client successfully disconnected\n"); } static void test_csip_enc(void) From b3c643b7eebbf84151e38fb70674ea9c91e10b0d Mon Sep 17 00:00:00 2001 From: Aaron Massey Date: Wed, 31 Jan 2024 13:28:25 -0700 Subject: [PATCH 3254/3723] MAINTAINERS: Remove aaronemassey add GRobertZieba Aaron Massey (aaronemassey - Google) doesn't have the cycles to remain a maintainer on the charger subsystem. Robert Zieba (GRobertZieba - Google) has been participating as a collaborator for the charger subsystem. Remove aaronemassey as a maintainer of the charger subsystem and add GRobertZieba as a collaborator. Signed-off-by: Aaron Massey --- MAINTAINERS.yml | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/MAINTAINERS.yml b/MAINTAINERS.yml index 1ef80d8f7c4..5265cd5debe 100644 --- a/MAINTAINERS.yml +++ b/MAINTAINERS.yml @@ -1000,8 +1000,9 @@ Release Notes: "Drivers: Charger": status: maintained maintainers: - - aaronemassey - rriveramcrus + collaborators: + - GRobertZieba files: - drivers/charger/ - dts/bindings/charger/ From 562166b685b3a0c49f32cd1b0d58b99ec907d9a1 Mon Sep 17 00:00:00 2001 From: Emil Gydesen Date: Wed, 20 Dec 2023 11:02:20 +0100 Subject: [PATCH 3255/3723] Bluetooth: MICP: Allow for multiple mic_ctrl cb registers Modify the MICP microphone controller callbacks to support multiple registers by making it into a linked list. This allow for multiple applications to get the information from procedures or notifications. Signed-off-by: Emil Gydesen --- include/zephyr/bluetooth/audio/micp.h | 3 + subsys/bluetooth/audio/micp_mic_ctlr.c | 303 ++++++++++++++++++------- 2 files changed, 219 insertions(+), 87 deletions(-) diff --git a/include/zephyr/bluetooth/audio/micp.h b/include/zephyr/bluetooth/audio/micp.h index f33d1d8ebef..27359ca7ffa 100644 --- a/include/zephyr/bluetooth/audio/micp.h +++ b/include/zephyr/bluetooth/audio/micp.h @@ -185,6 +185,9 @@ struct bt_micp_mic_ctlr_cb { /** Audio Input Control Service client callback */ struct bt_aics_cb aics_cb; #endif /* CONFIG_BT_MICP_MIC_CTLR_AICS */ + + /** Internally used field for list handling */ + sys_snode_t _node; }; /** diff --git a/subsys/bluetooth/audio/micp_mic_ctlr.c b/subsys/bluetooth/audio/micp_mic_ctlr.c index 0bceb26d189..71cec1ef9b6 100644 --- a/subsys/bluetooth/audio/micp_mic_ctlr.c +++ b/subsys/bluetooth/audio/micp_mic_ctlr.c @@ -2,7 +2,7 @@ /* * Copyright (c) 2020 Bose Corporation - * Copyright (c) 2020-2022 Nordic Semiconductor ASA + * Copyright (c) 2020-2023 Nordic Semiconductor ASA * * SPDX-License-Identifier: Apache-2.0 */ @@ -28,7 +28,7 @@ LOG_MODULE_REGISTER(bt_micp_mic_ctlr, CONFIG_BT_MICP_MIC_CTLR_LOG_LEVEL); #include "common/bt_str.h" /* Callback functions */ -static struct bt_micp_mic_ctlr_cb *micp_mic_ctlr_cb; +static sys_slist_t micp_mic_ctlr_cbs = SYS_SLIST_STATIC_INIT(&micp_mic_ctlr_cbs); static struct bt_micp_mic_ctlr mic_ctlrs[CONFIG_BT_MAX_CONN]; static const struct bt_uuid *mics_uuid = BT_UUID_MICS; @@ -38,8 +38,46 @@ static struct bt_micp_mic_ctlr *mic_ctlr_get_by_conn(const struct bt_conn *conn) return &mic_ctlrs[bt_conn_index(conn)]; } -static uint8_t mute_notify_handler(struct bt_conn *conn, - struct bt_gatt_subscribe_params *params, +static void micp_mic_ctlr_mute_changed(struct bt_micp_mic_ctlr *mic_ctlr, int err, uint8_t mute_val) +{ + struct bt_micp_mic_ctlr_cb *listener, *next; + + SYS_SLIST_FOR_EACH_CONTAINER_SAFE(&micp_mic_ctlr_cbs, listener, next, _node) { + if (listener->mute) { + listener->mute(mic_ctlr, err, mute_val); + } + } +} + +static void micp_mic_ctlr_mute_written(struct bt_micp_mic_ctlr *mic_ctlr, int err, uint8_t mute_val) +{ + struct bt_micp_mic_ctlr_cb *listener, *next; + + SYS_SLIST_FOR_EACH_CONTAINER_SAFE(&micp_mic_ctlr_cbs, listener, next, _node) { + if (mute_val == BT_MICP_MUTE_UNMUTED) { + if (listener->unmute_written) { + listener->unmute_written(mic_ctlr, err); + } + } else { + if (listener->mute_written) { + listener->mute_written(mic_ctlr, err); + } + } + } +} + +static void micp_mic_ctlr_discover_complete(struct bt_micp_mic_ctlr *mic_ctlr, int err) +{ + struct bt_micp_mic_ctlr_cb *listener, *next; + + SYS_SLIST_FOR_EACH_CONTAINER_SAFE(&micp_mic_ctlr_cbs, listener, next, _node) { + if (listener->discover) { + listener->discover(mic_ctlr, err, err == 0 ? mic_ctlr->aics_inst_cnt : 0U); + } + } +} + +static uint8_t mute_notify_handler(struct bt_conn *conn, struct bt_gatt_subscribe_params *params, const void *data, uint16_t length) { uint8_t *mute_val; @@ -55,13 +93,10 @@ static uint8_t mute_notify_handler(struct bt_conn *conn, if (length == sizeof(*mute_val)) { mute_val = (uint8_t *)data; LOG_DBG("Mute %u", *mute_val); - if (micp_mic_ctlr_cb != NULL && - micp_mic_ctlr_cb->mute != NULL) { - micp_mic_ctlr_cb->mute(mic_ctlr, 0, *mute_val); - } - } else { - LOG_DBG("Invalid length %u (expected %zu)", length, sizeof(*mute_val)); + micp_mic_ctlr_mute_changed(mic_ctlr, 0, *mute_val); } + } else { + LOG_DBG("Invalid length %u (expected %zu)", length, sizeof(*mute_val)); } return BT_GATT_ITER_CONTINUE; @@ -89,9 +124,7 @@ static uint8_t micp_mic_ctlr_read_mute_cb(struct bt_conn *conn, uint8_t err, } } - if (micp_mic_ctlr_cb != NULL && micp_mic_ctlr_cb->mute != NULL) { - micp_mic_ctlr_cb->mute(mic_ctlr, cb_err, mute_val); - } + micp_mic_ctlr_mute_changed(mic_ctlr, cb_err, mute_val); return BT_GATT_ITER_STOP; } @@ -106,18 +139,7 @@ static void micp_mic_ctlr_write_mics_mute_cb(struct bt_conn *conn, uint8_t err, mic_ctlr->busy = false; - if (mute_val == BT_MICP_MUTE_UNMUTED) { - if (micp_mic_ctlr_cb != NULL && - micp_mic_ctlr_cb->unmute_written != NULL) { - micp_mic_ctlr_cb->unmute_written(mic_ctlr, err); - } - - } else { - if (micp_mic_ctlr_cb != NULL && - micp_mic_ctlr_cb->mute_written != NULL) { - micp_mic_ctlr_cb->mute_written(mic_ctlr, err); - } - } + micp_mic_ctlr_mute_written(mic_ctlr, err, mute_val); } #if defined(CONFIG_BT_MICP_MIC_CTLR_AICS) @@ -136,21 +158,143 @@ static struct bt_micp_mic_ctlr *lookup_micp_by_aics(const struct bt_aics *aics) return NULL; } -static void aics_discover_cb(struct bt_aics *inst, int err) +static void micp_mic_ctlr_aics_state_cb(struct bt_aics *inst, int err, int8_t gain, uint8_t mute, + uint8_t mode) +{ + struct bt_micp_mic_ctlr_cb *listener, *next; + + SYS_SLIST_FOR_EACH_CONTAINER_SAFE(&micp_mic_ctlr_cbs, listener, next, _node) { + if (listener->aics_cb.state) { + listener->aics_cb.state(inst, err, gain, mute, mode); + } + } +} + +static void micp_mic_ctlr_aics_gain_setting_cb(struct bt_aics *inst, int err, uint8_t units, + int8_t minimum, int8_t maximum) +{ + struct bt_micp_mic_ctlr_cb *listener, *next; + + SYS_SLIST_FOR_EACH_CONTAINER_SAFE(&micp_mic_ctlr_cbs, listener, next, _node) { + if (listener->aics_cb.gain_setting) { + listener->aics_cb.gain_setting(inst, err, units, minimum, maximum); + } + } +} + +static void micp_mic_ctlr_aics_type_cb(struct bt_aics *inst, int err, uint8_t type) +{ + struct bt_micp_mic_ctlr_cb *listener, *next; + + SYS_SLIST_FOR_EACH_CONTAINER_SAFE(&micp_mic_ctlr_cbs, listener, next, _node) { + if (listener->aics_cb.type) { + listener->aics_cb.type(inst, err, type); + } + } +} + +static void micp_mic_ctlr_aics_status_cb(struct bt_aics *inst, int err, bool active) +{ + struct bt_micp_mic_ctlr_cb *listener, *next; + + SYS_SLIST_FOR_EACH_CONTAINER_SAFE(&micp_mic_ctlr_cbs, listener, next, _node) { + if (listener->aics_cb.status) { + listener->aics_cb.status(inst, err, active); + } + } +} + +static void micp_mic_ctlr_aics_description_cb(struct bt_aics *inst, int err, char *description) +{ + struct bt_micp_mic_ctlr_cb *listener, *next; + + SYS_SLIST_FOR_EACH_CONTAINER_SAFE(&micp_mic_ctlr_cbs, listener, next, _node) { + if (listener->aics_cb.description) { + listener->aics_cb.description(inst, err, description); + } + } +} + +static void micp_mic_ctlr_aics_discover_cb(struct bt_aics *inst, int err) { struct bt_micp_mic_ctlr *mic_ctlr = lookup_micp_by_aics(inst); + struct bt_micp_mic_ctlr_cb *listener, *next; + + if (mic_ctlr == NULL) { + LOG_ERR("Could not lookup mic_ctlr from aics"); + micp_mic_ctlr_discover_complete(mic_ctlr, BT_GATT_ERR(BT_ATT_ERR_UNLIKELY)); + + return; + } if (err == 0) { /* Continue discovery of included services */ - err = bt_gatt_discover(mic_ctlr->conn, - &mic_ctlr->discover_params); + err = bt_gatt_discover(mic_ctlr->conn, &mic_ctlr->discover_params); } if (err != 0) { LOG_DBG("Discover failed (err %d)", err); - if (micp_mic_ctlr_cb != NULL && - micp_mic_ctlr_cb->discover != NULL) { - micp_mic_ctlr_cb->discover(mic_ctlr, err, 0); + micp_mic_ctlr_discover_complete(mic_ctlr, err); + } + + SYS_SLIST_FOR_EACH_CONTAINER_SAFE(&micp_mic_ctlr_cbs, listener, next, _node) { + if (listener->aics_cb.discover) { + listener->aics_cb.discover(inst, err); + } + } +} + +static void micp_mic_ctlr_aics_set_gain_cb(struct bt_aics *inst, int err) +{ + struct bt_micp_mic_ctlr_cb *listener, *next; + + SYS_SLIST_FOR_EACH_CONTAINER_SAFE(&micp_mic_ctlr_cbs, listener, next, _node) { + if (listener->aics_cb.set_gain) { + listener->aics_cb.set_gain(inst, err); + } + } +} + +static void micp_mic_ctlr_aics_unmute_cb(struct bt_aics *inst, int err) +{ + struct bt_micp_mic_ctlr_cb *listener, *next; + + SYS_SLIST_FOR_EACH_CONTAINER_SAFE(&micp_mic_ctlr_cbs, listener, next, _node) { + if (listener->aics_cb.unmute) { + listener->aics_cb.unmute(inst, err); + } + } +} + +static void micp_mic_ctlr_aics_mute_cb(struct bt_aics *inst, int err) +{ + struct bt_micp_mic_ctlr_cb *listener, *next; + + SYS_SLIST_FOR_EACH_CONTAINER_SAFE(&micp_mic_ctlr_cbs, listener, next, _node) { + if (listener->aics_cb.mute) { + listener->aics_cb.mute(inst, err); + } + } +} + +static void micp_mic_ctlr_aics_set_manual_mode_cb(struct bt_aics *inst, int err) +{ + struct bt_micp_mic_ctlr_cb *listener, *next; + + SYS_SLIST_FOR_EACH_CONTAINER_SAFE(&micp_mic_ctlr_cbs, listener, next, _node) { + if (listener->aics_cb.set_manual_mode) { + listener->aics_cb.set_manual_mode(inst, err); + } + } +} + +static void micp_mic_ctlr_aics_set_auto_mode_cb(struct bt_aics *inst, int err) +{ + struct bt_micp_mic_ctlr_cb *listener, *next; + + SYS_SLIST_FOR_EACH_CONTAINER_SAFE(&micp_mic_ctlr_cbs, listener, next, _node) { + if (listener->aics_cb.set_auto_mode) { + listener->aics_cb.set_auto_mode(inst, err); } } } @@ -166,11 +310,7 @@ static uint8_t micp_discover_include_func( LOG_DBG("Discover include complete for MICS: %u AICS", mic_ctlr->aics_inst_cnt); (void)memset(params, 0, sizeof(*params)); - if (micp_mic_ctlr_cb != NULL && - micp_mic_ctlr_cb->discover != NULL) { - micp_mic_ctlr_cb->discover(mic_ctlr, 0, - mic_ctlr->aics_inst_cnt); - } + micp_mic_ctlr_discover_complete(mic_ctlr, 0); return BT_GATT_ITER_STOP; } @@ -201,12 +341,9 @@ static uint8_t micp_discover_include_func( ¶m); if (err != 0) { LOG_DBG("AICS Discover failed (err %d)", err); - if (micp_mic_ctlr_cb != NULL && - micp_mic_ctlr_cb->discover != NULL) { - micp_mic_ctlr_cb->discover(mic_ctlr, err, - 0); - } + micp_mic_ctlr_discover_complete(mic_ctlr, err); } + return BT_GATT_ITER_STOP; } } @@ -241,17 +378,12 @@ static uint8_t micp_discover_func(struct bt_conn *conn, &mic_ctlr->discover_params); if (err != 0) { LOG_DBG("Discover AICS failed (err %d)", err); - if (micp_mic_ctlr_cb != NULL && - micp_mic_ctlr_cb->discover != NULL) { - micp_mic_ctlr_cb->discover(mic_ctlr, err, 0); - } + micp_mic_ctlr_discover_complete(mic_ctlr, err); } } else { - if (micp_mic_ctlr_cb != NULL && - micp_mic_ctlr_cb->discover != NULL) { - micp_mic_ctlr_cb->discover(mic_ctlr, err, 0); - } + micp_mic_ctlr_discover_complete(mic_ctlr, err); } + return BT_GATT_ITER_STOP; } @@ -299,10 +431,8 @@ static uint8_t primary_discover_func(struct bt_conn *conn, if (attr == NULL) { LOG_DBG("Could not find a MICS instance on the server"); - if (micp_mic_ctlr_cb != NULL && - micp_mic_ctlr_cb->discover != NULL) { - micp_mic_ctlr_cb->discover(mic_ctlr, -ENODATA, 0); - } + micp_mic_ctlr_discover_complete(mic_ctlr, -ENODATA); + return BT_GATT_ITER_STOP; } @@ -327,10 +457,7 @@ static uint8_t primary_discover_func(struct bt_conn *conn, err = bt_gatt_discover(conn, &mic_ctlr->discover_params); if (err != 0) { LOG_DBG("Discover failed (err %d)", err); - if (micp_mic_ctlr_cb != NULL && - micp_mic_ctlr_cb->discover != NULL) { - micp_mic_ctlr_cb->discover(mic_ctlr, err, 0); - } + micp_mic_ctlr_discover_complete(mic_ctlr, err); } return BT_GATT_ITER_STOP; @@ -405,19 +532,34 @@ int bt_micp_mic_ctlr_discover(struct bt_conn *conn, struct bt_micp_mic_ctlr **mi static bool initialized; if (!initialized) { - for (int i = 0; i < ARRAY_SIZE(mic_ctlr->aics); i++) { - mic_ctlr->aics[i] = bt_aics_client_free_instance_get(); + for (size_t i = 0U; i < ARRAY_SIZE(mic_ctlrs); i++) { + for (size_t j = 0U; j < ARRAY_SIZE(mic_ctlr->aics); j++) { + static struct bt_aics_cb aics_cb = { + .state = micp_mic_ctlr_aics_state_cb, + .gain_setting = micp_mic_ctlr_aics_gain_setting_cb, + .type = micp_mic_ctlr_aics_type_cb, + .status = micp_mic_ctlr_aics_status_cb, + .description = micp_mic_ctlr_aics_description_cb, + .discover = micp_mic_ctlr_aics_discover_cb, + .set_gain = micp_mic_ctlr_aics_set_gain_cb, + .unmute = micp_mic_ctlr_aics_unmute_cb, + .mute = micp_mic_ctlr_aics_mute_cb, + .set_manual_mode = micp_mic_ctlr_aics_set_manual_mode_cb, + .set_auto_mode = micp_mic_ctlr_aics_set_auto_mode_cb, + }; + + mic_ctlrs[i].aics[j] = bt_aics_client_free_instance_get(); + + if (mic_ctlrs[i].aics[j] == NULL) { + return -ENOMEM; + } - if (mic_ctlr->aics[i] == NULL) { - return -ENOMEM; + bt_aics_client_cb_register(mic_ctlrs[i].aics[j], &aics_cb); } - - bt_aics_client_cb_register(mic_ctlr->aics[i], - &micp_mic_ctlr_cb->aics_cb); } - } - initialized = true; + initialized = true; + } #endif /* CONFIG_BT_MICP_MIC_CTLR_AICS */ mic_ctlr->conn = bt_conn_ref(conn); @@ -437,33 +579,20 @@ int bt_micp_mic_ctlr_discover(struct bt_conn *conn, struct bt_micp_mic_ctlr **mi int bt_micp_mic_ctlr_cb_register(struct bt_micp_mic_ctlr_cb *cb) { -#if defined(CONFIG_BT_MICP_MIC_CTLR_AICS) - struct bt_aics_cb *aics_cb = NULL; - - if (cb != NULL) { - /* Ensure that the cb->aics_cb.discover is the aics_discover_cb */ - CHECKIF(cb->aics_cb.discover != NULL && - cb->aics_cb.discover != aics_discover_cb) { - LOG_ERR("AICS discover callback shall not be set"); - return -EINVAL; - } - cb->aics_cb.discover = aics_discover_cb; + struct bt_micp_mic_ctlr_cb *tmp; - aics_cb = &cb->aics_cb; + CHECKIF(cb == NULL) { + return -EINVAL; } - for (int i = 0; i < ARRAY_SIZE(mic_ctlrs); i++) { - for (int j = 0; j < ARRAY_SIZE(mic_ctlrs[i].aics); j++) { - struct bt_aics *aics = mic_ctlrs[i].aics[j]; - - if (aics != NULL) { - bt_aics_client_cb_register(aics, aics_cb); - } + SYS_SLIST_FOR_EACH_CONTAINER(&micp_mic_ctlr_cbs, tmp, _node) { + if (tmp == cb) { + LOG_DBG("Already registered"); + return -EALREADY; } } -#endif /* CONFIG_BT_MICP_MIC_CTLR_AICS */ - micp_mic_ctlr_cb = cb; + sys_slist_append(&micp_mic_ctlr_cbs, &cb->_node); return 0; } From 4be42784eaa7a2c1f0851f6cc46532543786b035 Mon Sep 17 00:00:00 2001 From: Emil Gydesen Date: Wed, 29 Nov 2023 11:24:15 +0100 Subject: [PATCH 3256/3723] Bluetooth: CAP: Commander change volume offset procedure Adds the CAP Commander Change Volume Offset procedure. This procedure changes the volume offset on one or more CAP Acceptors, but not to the same value (unlike the volume change procedure). Signed-off-by: Emil Gydesen --- include/zephyr/bluetooth/audio/cap.h | 14 ++ subsys/bluetooth/audio/cap_commander.c | 284 +++++++++++++++++++++---- subsys/bluetooth/audio/cap_common.c | 37 +++- subsys/bluetooth/audio/cap_initiator.c | 51 +---- subsys/bluetooth/audio/cap_internal.h | 11 +- 5 files changed, 310 insertions(+), 87 deletions(-) diff --git a/include/zephyr/bluetooth/audio/cap.h b/include/zephyr/bluetooth/audio/cap.h index a9370251d3d..8a0ab5d5666 100644 --- a/include/zephyr/bluetooth/audio/cap.h +++ b/include/zephyr/bluetooth/audio/cap.h @@ -668,6 +668,20 @@ struct bt_cap_commander_cb { * by bt_cap_commander_cancel(). */ void (*volume_changed)(struct bt_conn *conn, int err); + +#if defined(CONFIG_BT_VCP_VOL_CTLR_VOCS) + /** + * @brief Callback for bt_cap_commander_change_volume_offset(). + * + * @param conn Pointer to the connection where the error + * occurred. NULL if @p err is 0 or if cancelled by + * bt_cap_initiator_unicast_audio_cancel() + * @param err 0 on success, BT_GATT_ERR() with a + * specific ATT (BT_ATT_ERR_*) error code or -ECANCELED if cancelled + * by bt_cap_initiator_unicast_audio_cancel(). + */ + void (*volume_offset_changed)(struct bt_conn *conn, int err); +#endif /* CONFIG_BT_VCP_VOL_CTLR_VOCS */ #endif /* CONFIG_BT_VCP_VOL_CTLR */ }; diff --git a/subsys/bluetooth/audio/cap_commander.c b/subsys/bluetooth/audio/cap_commander.c index 93567f34038..90490ebaa7f 100644 --- a/subsys/bluetooth/audio/cap_commander.c +++ b/subsys/bluetooth/audio/cap_commander.c @@ -9,6 +9,7 @@ #include #include #include +#include #include "cap_internal.h" #include "ccid_internal.h" #include "csip_internal.h" @@ -109,6 +110,13 @@ static void cap_commander_unicast_audio_proc_complete(void) cap_cb->volume_changed(failed_conn, err); } break; +#if defined(CONFIG_BT_VCP_VOL_CTLR_VOCS) + case BT_CAP_COMMON_PROC_TYPE_VOLUME_OFFSET_CHANGE: + if (cap_cb->volume_offset_changed != NULL) { + cap_cb->volume_offset_changed(failed_conn, err); + } + break; +#endif /* CONFIG_BT_VCP_VOL_CTLR_VOCS */ #endif /* CONFIG_BT_VCP_VOL_CTLR */ case BT_CAP_COMMON_PROC_TYPE_NONE: default: @@ -131,6 +139,25 @@ int bt_cap_commander_cancel(void) } #if defined(CONFIG_BT_VCP_VOL_CTLR) +static struct bt_vcp_vol_ctlr_cb vol_ctlr_cb; +static bool vcp_cb_registered; + +static int cap_commander_register_vcp_cb(void) +{ + int err; + + err = bt_vcp_vol_ctlr_cb_register(&vol_ctlr_cb); + if (err != 0) { + LOG_DBG("Failed to register VCP callbacks: %d", err); + + return -ENOEXEC; + } + + vcp_cb_registered = true; + + return 0; +} + static bool valid_change_volume_param(const struct bt_cap_commander_change_volume_param *param) { CHECKIF(param == NULL) { @@ -156,35 +183,11 @@ static bool valid_change_volume_param(const struct bt_cap_commander_change_volum for (size_t i = 0U; i < param->count; i++) { const union bt_cap_set_member *member = ¶m->members[i]; - struct bt_cap_common_client *client = NULL; + const struct bt_cap_common_client *client = + bt_cap_common_get_client(param->type, member); - if (param->type == BT_CAP_SET_TYPE_AD_HOC) { - - CHECKIF(member->member == NULL) { - LOG_DBG("param->members[%zu].member is NULL", i); - return false; - } - - client = bt_cap_common_get_client_by_acl(member->member); - if (client == NULL || !client->cas_found) { - LOG_DBG("CAS was not found for param->members[%zu]", i); - return false; - } - } else if (param->type == BT_CAP_SET_TYPE_CSIP) { - CHECKIF(member->csip == NULL) { - LOG_DBG("param->members[%zu].csip is NULL", i); - return false; - } - - client = bt_cap_common_get_client_by_csis(member->csip); - if (client == NULL) { - LOG_DBG("CSIS was not found for param->members[%zu]", i); - return false; - } - } - - if (client == NULL || !client->cas_found) { - LOG_DBG("CAS was not found for param->members[%zu]", i); + if (client == NULL) { + LOG_DBG("Invalid param->members[%zu]", i); return false; } @@ -269,11 +272,7 @@ static void cap_commander_vcp_vol_set_cb(struct bt_vcp_vol_ctlr *vol_ctlr, int e int bt_cap_commander_change_volume(const struct bt_cap_commander_change_volume_param *param) { const struct bt_cap_commander_proc_param *proc_param; - static struct bt_vcp_vol_ctlr_cb vol_ctlr_cb = { - .vol_set = cap_commander_vcp_vol_set_cb, - }; struct bt_cap_common_proc *active_proc; - static bool cb_registered; struct bt_conn *conn; int err; @@ -289,16 +288,11 @@ int bt_cap_commander_change_volume(const struct bt_cap_commander_change_volume_p bt_cap_common_start_proc(BT_CAP_COMMON_PROC_TYPE_VOLUME_CHANGE, param->count); - if (!cb_registered) { - /* Ensure that ops are registered before any procedures are started */ - err = bt_vcp_vol_ctlr_cb_register(&vol_ctlr_cb); - if (err != 0) { - LOG_DBG("Failed to register VCP callbacks: %d", err); + vol_ctlr_cb.vol_set = cap_commander_vcp_vol_set_cb; + if (!vcp_cb_registered && cap_commander_register_vcp_cb() != 0) { + LOG_DBG("Failed to register VCP callbacks"); - return -ENOEXEC; - } - - cb_registered = true; + return -ENOEXEC; } active_proc = bt_cap_common_get_active_proc(); @@ -332,11 +326,217 @@ int bt_cap_commander_change_volume(const struct bt_cap_commander_change_volume_p return 0; } +#if defined(CONFIG_BT_VCP_VOL_CTLR_VOCS) +static bool +valid_change_offset_param(const struct bt_cap_commander_change_volume_offset_param *param) +{ + CHECKIF(param == NULL) { + LOG_DBG("param is NULL"); + return false; + } + + CHECKIF(param->count == 0) { + LOG_DBG("Invalid param->count: %u", param->count); + return false; + } + + CHECKIF(param->param == NULL) { + LOG_DBG("param->param is NULL"); + return false; + } + + CHECKIF(param->count > CONFIG_BT_MAX_CONN) { + LOG_DBG("param->count (%zu) is larger than CONFIG_BT_MAX_CONN (%d)", param->count, + CONFIG_BT_MAX_CONN); + return false; + } + + for (size_t i = 0U; i < param->count; i++) { + const struct bt_cap_commander_change_volume_offset_member_param *member_param = + ¶m->param[i]; + const union bt_cap_set_member *member = &member_param->member; + const struct bt_cap_common_client *client = + bt_cap_common_get_client(param->type, member); + struct bt_vcp_vol_ctlr *vol_ctlr; + struct bt_vcp_included included; + int err; + + if (client == NULL) { + LOG_DBG("Invalid param->param[%zu].member", i); + return false; + } + + vol_ctlr = bt_vcp_vol_ctlr_get_by_conn(client->conn); + if (vol_ctlr == NULL) { + LOG_DBG("Volume control not available for param->param[%zu].member", i); + return false; + } + + err = bt_vcp_vol_ctlr_included_get(vol_ctlr, &included); + if (err != 0 || included.vocs_cnt == 0) { + LOG_DBG("Volume offset control not available for param->param[%zu].member", + i); + return -ENOEXEC; + } + + if (!IN_RANGE(member_param->offset, BT_VOCS_MIN_OFFSET, BT_VOCS_MAX_OFFSET)) { + LOG_DBG("Invalid offset %d for param->param[%zu].offset", + member_param->offset, i); + return false; + } + + for (size_t j = 0U; j < i; j++) { + const union bt_cap_set_member *other = ¶m->param[j].member; + + if (other == member) { + LOG_DBG("param->param[%zu].member (%p) is duplicated by " + "param->param[%zu].member (%p)", + j, other, i, member); + return false; + } + } + } + + return true; +} + +static void cap_commander_vcp_set_offset_cb(struct bt_vocs *inst, int err) +{ + struct bt_cap_common_proc *active_proc = bt_cap_common_get_active_proc(); + struct bt_conn *conn; + int vocs_err; + + LOG_DBG("bt_vocs %p", (void *)inst); + + vocs_err = bt_vocs_client_conn_get(inst, &conn); + if (vocs_err != 0) { + LOG_ERR("Failed to get conn by inst: %d", vocs_err); + return; + } + + LOG_DBG("conn %p", (void *)conn); + if (!bt_cap_common_conn_in_active_proc(conn)) { + /* State change happened outside of a procedure; ignore */ + return; + } + + if (err != 0) { + LOG_DBG("Failed to set offset: %d", err); + bt_cap_common_abort_proc(conn, err); + } else { + active_proc->proc_done_cnt++; + + LOG_DBG("Conn %p offset updated (%zu/%zu streams done)", (void *)conn, + active_proc->proc_done_cnt, active_proc->proc_cnt); + } + + if (bt_cap_common_proc_is_aborted()) { + LOG_DBG("Proc is aborted"); + if (bt_cap_common_proc_all_handled()) { + LOG_DBG("All handled"); + cap_commander_unicast_audio_proc_complete(); + } + + return; + } + + if (!bt_cap_common_proc_is_done()) { + const struct bt_cap_commander_proc_param *proc_param; + + proc_param = &active_proc->proc_param.commander[active_proc->proc_done_cnt]; + conn = proc_param->conn; + active_proc->proc_initiated_cnt++; + + err = bt_vocs_state_set(proc_param->change_offset.vocs, + proc_param->change_offset.offset); + if (err != 0) { + LOG_DBG("Failed to set offset for conn %p: %d", (void *)conn, err); + bt_cap_common_abort_proc(conn, err); + cap_commander_unicast_audio_proc_complete(); + } + } else { + cap_commander_unicast_audio_proc_complete(); + } +} + int bt_cap_commander_change_volume_offset( const struct bt_cap_commander_change_volume_offset_param *param) { - return -ENOSYS; + const struct bt_cap_commander_proc_param *proc_param; + struct bt_cap_common_proc *active_proc; + struct bt_vcp_vol_ctlr *vol_ctlr; + struct bt_conn *conn; + int err; + + if (bt_cap_common_proc_is_active()) { + LOG_DBG("A CAP procedure is already in progress"); + + return -EBUSY; + } + + if (!valid_change_offset_param(param)) { + return -EINVAL; + } + + bt_cap_common_start_proc(BT_CAP_COMMON_PROC_TYPE_VOLUME_OFFSET_CHANGE, param->count); + + vol_ctlr_cb.vocs_cb.set_offset = cap_commander_vcp_set_offset_cb; + if (!vcp_cb_registered && cap_commander_register_vcp_cb() != 0) { + LOG_DBG("Failed to register VCP callbacks"); + + return -ENOEXEC; + } + + active_proc = bt_cap_common_get_active_proc(); + + for (size_t i = 0U; i < param->count; i++) { + const struct bt_cap_commander_change_volume_offset_member_param *member_param = + ¶m->param[i]; + struct bt_conn *member_conn = + bt_cap_common_get_member_conn(param->type, &member_param->member); + struct bt_vcp_included included; + + if (member_conn == NULL) { + LOG_DBG("Invalid param->members[%zu]", i); + return -EINVAL; + } + + vol_ctlr = bt_vcp_vol_ctlr_get_by_conn(member_conn); + if (vol_ctlr == NULL) { + LOG_DBG("Invalid param->members[%zu] vol_ctlr", i); + return -EINVAL; + } + + err = bt_vcp_vol_ctlr_included_get(vol_ctlr, &included); + if (err != 0 || included.vocs_cnt == 0) { + LOG_DBG("Invalid param->members[%zu] vocs", i); + return -EINVAL; + } + + /* Store the necessary parameters as we cannot assume that the supplied parameters + * are kept valid + */ + active_proc->proc_param.commander[i].conn = member_conn; + active_proc->proc_param.commander[i].change_offset.offset = member_param->offset; + /* TODO: For now we just use the first VOCS instance + * - How should we handle multiple? + */ + active_proc->proc_param.commander[i].change_offset.vocs = included.vocs[0]; + } + + proc_param = &active_proc->proc_param.commander[0]; + conn = proc_param->conn; + active_proc->proc_initiated_cnt++; + + err = bt_vocs_state_set(proc_param->change_offset.vocs, proc_param->change_offset.offset); + if (err != 0) { + LOG_DBG("Failed to set volume for conn %p: %d", (void *)conn, err); + return -ENOEXEC; + } + + return 0; } +#endif /* CONFIG_BT_VCP_VOL_CTLR_VOCS */ int bt_cap_commander_change_volume_mute_state( const struct bt_cap_commander_change_volume_mute_state_param *param) diff --git a/subsys/bluetooth/audio/cap_common.c b/subsys/bluetooth/audio/cap_common.c index 62ffbc7b874..bf166fffd0c 100644 --- a/subsys/bluetooth/audio/cap_common.c +++ b/subsys/bluetooth/audio/cap_common.c @@ -5,6 +5,7 @@ */ #include +#include #include "cap_internal.h" #include "csip_internal.h" @@ -52,7 +53,7 @@ bool bt_cap_common_subproc_is_type(enum bt_cap_common_subproc_type subproc_type) #endif /* CONFIG_BT_CAP_INITIATOR_UNICAST */ struct bt_conn *bt_cap_common_get_member_conn(enum bt_cap_set_type type, - union bt_cap_set_member *member) + const union bt_cap_set_member *member) { if (type == BT_CAP_SET_TYPE_CSIP) { struct bt_cap_common_client *client; @@ -120,6 +121,7 @@ static bool active_proc_is_commander(void) { switch (active_proc.proc_type) { case BT_CAP_COMMON_PROC_TYPE_VOLUME_CHANGE: + case BT_CAP_COMMON_PROC_TYPE_VOLUME_OFFSET_CHANGE: return true; default: return false; @@ -217,6 +219,39 @@ bt_cap_common_get_client_by_csis(const struct bt_csip_set_coordinator_csis_inst return NULL; } +struct bt_cap_common_client *bt_cap_common_get_client(enum bt_cap_set_type type, + const union bt_cap_set_member *member) +{ + struct bt_cap_common_client *client = NULL; + + if (type == BT_CAP_SET_TYPE_AD_HOC) { + CHECKIF(member->member == NULL) { + LOG_DBG("member->member is NULL"); + return NULL; + } + + client = bt_cap_common_get_client_by_acl(member->member); + } else if (type == BT_CAP_SET_TYPE_CSIP) { + CHECKIF(member->csip == NULL) { + LOG_DBG("member->csip is NULL"); + return NULL; + } + + client = bt_cap_common_get_client_by_csis(member->csip); + if (client == NULL) { + LOG_DBG("CSIS was not found for member"); + return NULL; + } + } + + if (client == NULL || !client->cas_found) { + LOG_DBG("CAS was not found for member %p", member); + return NULL; + } + + return client; +} + static void cap_common_discover_complete(struct bt_conn *conn, int err, const struct bt_csip_set_coordinator_csis_inst *csis_inst) { diff --git a/subsys/bluetooth/audio/cap_initiator.c b/subsys/bluetooth/audio/cap_initiator.c index 32d86b726a1..1a51638af3f 100644 --- a/subsys/bluetooth/audio/cap_initiator.c +++ b/subsys/bluetooth/audio/cap_initiator.c @@ -365,6 +365,13 @@ static bool valid_unicast_audio_start_param(const struct bt_cap_unicast_audio_st const struct bt_cap_stream *cap_stream = stream_param->stream; const struct bt_audio_codec_cfg *codec_cfg = stream_param->codec_cfg; const struct bt_bap_stream *bap_stream; + const struct bt_cap_common_client *client = + bt_cap_common_get_client(param->type, member); + + if (client == NULL) { + LOG_DBG("Invalid param->members[%zu]", i); + return false; + } CHECKIF(stream_param->codec_cfg == NULL) { LOG_DBG("param->stream_params[%zu].codec_cfg is NULL", i); @@ -386,37 +393,6 @@ static bool valid_unicast_audio_start_param(const struct bt_cap_unicast_audio_st return false; } - if (param->type == BT_CAP_SET_TYPE_AD_HOC) { - struct bt_cap_common_client *client; - - CHECKIF(member->member == NULL) { - LOG_DBG("param->members[%zu] is NULL", i); - return false; - } - - client = bt_cap_common_get_client_by_acl(member->member); - - if (!client->cas_found) { - LOG_DBG("CAS was not found for param->members[%zu]", i); - return false; - } - } - - if (param->type == BT_CAP_SET_TYPE_CSIP) { - struct bt_cap_common_client *client; - - CHECKIF(member->csip == NULL) { - LOG_DBG("param->csip.set[%zu] is NULL", i); - return false; - } - - client = bt_cap_common_get_client_by_csis(member->csip); - if (client == NULL) { - LOG_DBG("CSIS was not found for param->members[%zu]", i); - return false; - } - } - CHECKIF(cap_stream == NULL) { LOG_DBG("param->streams[%zu] is NULL", i); return false; @@ -515,18 +491,7 @@ static int cap_initiator_unicast_audio_configure( union bt_cap_set_member *member = &stream_param->member; struct bt_cap_stream *cap_stream = stream_param->stream; - if (param->type == BT_CAP_SET_TYPE_AD_HOC) { - conn = member->member; - } else { - struct bt_cap_common_client *client; - - /* We have verified that `client` wont be NULL in - * `valid_unicast_audio_start_param`. - */ - client = bt_cap_common_get_client_by_csis(member->csip); - __ASSERT(client != NULL, "client is NULL"); - conn = client->conn; - } + conn = bt_cap_common_get_member_conn(param->type, member); /* Ensure that ops are registered before any procedures are started */ bt_cap_stream_ops_register_bap(cap_stream); diff --git a/subsys/bluetooth/audio/cap_internal.h b/subsys/bluetooth/audio/cap_internal.h index 4c833a1d8e5..942f0985ac8 100644 --- a/subsys/bluetooth/audio/cap_internal.h +++ b/subsys/bluetooth/audio/cap_internal.h @@ -37,6 +37,7 @@ enum bt_cap_common_proc_type { BT_CAP_COMMON_PROC_TYPE_UPDATE, BT_CAP_COMMON_PROC_TYPE_STOP, BT_CAP_COMMON_PROC_TYPE_VOLUME_CHANGE, + BT_CAP_COMMON_PROC_TYPE_VOLUME_OFFSET_CHANGE, }; enum bt_cap_common_subproc_type { @@ -74,6 +75,12 @@ struct bt_cap_commander_proc_param { uint8_t volume; } change_volume; #endif /* CONFIG_BT_VCP_VOL_CTLR */ +#if defined(CONFIG_BT_VCP_VOL_CTLR_VOCS) + struct { + int16_t offset; + struct bt_vocs *vocs; + } change_offset; +#endif /* CONFIG_BT_VCP_VOL_CTLR_VOCS */ /* TODO Add other procedures */ }; @@ -123,7 +130,7 @@ void bt_cap_common_start_proc(enum bt_cap_common_proc_type proc_type, size_t pro void bt_cap_common_set_subproc(enum bt_cap_common_subproc_type subproc_type); bool bt_cap_common_subproc_is_type(enum bt_cap_common_subproc_type subproc_type); struct bt_conn *bt_cap_common_get_member_conn(enum bt_cap_set_type type, - union bt_cap_set_member *member); + const union bt_cap_set_member *member); bool bt_cap_common_proc_is_active(void); bool bt_cap_common_proc_is_aborted(void); bool bt_cap_common_proc_all_handled(void); @@ -135,6 +142,8 @@ void bt_cap_common_disconnected(struct bt_conn *conn, uint8_t reason); struct bt_cap_common_client *bt_cap_common_get_client_by_acl(const struct bt_conn *acl); struct bt_cap_common_client * bt_cap_common_get_client_by_csis(const struct bt_csip_set_coordinator_csis_inst *csis_inst); +struct bt_cap_common_client *bt_cap_common_get_client(enum bt_cap_set_type type, + const union bt_cap_set_member *member); typedef void (*bt_cap_common_discover_func_t)( struct bt_conn *conn, int err, const struct bt_csip_set_coordinator_csis_inst *csis_inst); From 8459560448219c4aa387b1eaaffe0f4f7b73acb3 Mon Sep 17 00:00:00 2001 From: Emil Gydesen Date: Wed, 29 Nov 2023 11:25:56 +0100 Subject: [PATCH 3257/3723] tests: bsim: Bluetooth: CAP Commander Change Volume Offset Adds bsim test of the CAP Commander Change Volume Offset procedure. Signed-off-by: Emil Gydesen --- .../bluetooth/audio/src/cap_commander_test.c | 45 +++++++++++++++++++ 1 file changed, 45 insertions(+) diff --git a/tests/bsim/bluetooth/audio/src/cap_commander_test.c b/tests/bsim/bluetooth/audio/src/cap_commander_test.c index e45b93bd333..9de329d29ca 100644 --- a/tests/bsim/bluetooth/audio/src/cap_commander_test.c +++ b/tests/bsim/bluetooth/audio/src/cap_commander_test.c @@ -24,6 +24,7 @@ CREATE_FLAG(flag_cas_discovered); CREATE_FLAG(flag_vcs_discovered); CREATE_FLAG(flag_mtu_exchanged); CREATE_FLAG(flag_volume_changed); +CREATE_FLAG(flag_volume_offset_changed); static void cap_discovery_complete_cb(struct bt_conn *conn, int err, const struct bt_csip_set_coordinator_csis_inst *csis_inst) @@ -59,9 +60,20 @@ static void cap_volume_changed_cb(struct bt_conn *conn, int err) SET_FLAG(flag_volume_changed); } +static void cap_volume_offset_changed_cb(struct bt_conn *conn, int err) +{ + if (err != 0) { + FAIL("Failed to change volume for conn %p: %d\n", conn, err); + return; + } + + SET_FLAG(flag_volume_offset_changed); +} + static struct bt_cap_commander_cb cap_cb = { .discovery_complete = cap_discovery_complete_cb, .volume_changed = cap_volume_changed_cb, + .volume_offset_changed = cap_volume_offset_changed_cb, }; static void cap_vcp_discover_cb(struct bt_vcp_vol_ctlr *vol_ctlr, int err, uint8_t vocs_count, @@ -242,6 +254,7 @@ static void test_change_volume(void) int err; printk("Changing volume to %u\n", param.volume); + UNSET_FLAG(flag_volume_changed); for (size_t i = 0U; i < param.count; i++) { param.members[i].member = connected_conns[i]; @@ -257,6 +270,34 @@ static void test_change_volume(void) printk("Volume changed to %u\n", param.volume); } +static void test_change_volume_offset(void) +{ + struct bt_cap_commander_change_volume_offset_member_param member_params[CONFIG_BT_MAX_CONN]; + const struct bt_cap_commander_change_volume_offset_param param = { + .type = BT_CAP_SET_TYPE_AD_HOC, + .param = member_params, + .count = connected_conn_cnt, + }; + int err; + + printk("Changing volume offset\n"); + UNSET_FLAG(flag_volume_offset_changed); + + for (size_t i = 0U; i < param.count; i++) { + member_params[i].member.member = connected_conns[i]; + member_params[i].offset = 100 + i; + } + + err = bt_cap_commander_change_volume_offset(¶m); + if (err != 0) { + FAIL("Failed to change volume: %d\n", err); + return; + } + + WAIT_FOR_FLAG(flag_volume_offset_changed); + printk("Volume offset changed\n"); +} + static void test_main_cap_commander_capture_and_render(void) { init(); @@ -278,6 +319,10 @@ static void test_main_cap_commander_capture_and_render(void) if (IS_ENABLED(CONFIG_BT_CSIP_SET_COORDINATOR)) { if (IS_ENABLED(CONFIG_BT_VCP_VOL_CTLR)) { test_change_volume(); + + if (IS_ENABLED(CONFIG_BT_VCP_VOL_CTLR_VOCS)) { + test_change_volume_offset(); + } } /* TODO: Add test of offset (VOCS), Mic (MICP) and gain (AICS) */ } From e0f3524e3d9cb742303359af7e6acabfdace210a Mon Sep 17 00:00:00 2001 From: Emil Gydesen Date: Wed, 29 Nov 2023 11:27:00 +0100 Subject: [PATCH 3258/3723] tests: Bluetooth: CAP Commander Change Volume Offset unittests Adds unittests for the CAP COmmander Change Volume Offset procedure. Signed-off-by: Emil Gydesen --- include/zephyr/bluetooth/audio/vocs.h | 2 + .../audio/cap_commander/include/cap_mocks.h | 2 + tests/bluetooth/audio/cap_commander/prj.conf | 2 + .../bluetooth/audio/cap_commander/src/main.c | 261 ++++++++++++++++++ .../audio/cap_commander/uut/CMakeLists.txt | 1 + .../bluetooth/audio/cap_commander/uut/csip.c | 2 +- tests/bluetooth/audio/cap_commander/uut/vcp.c | 42 ++- .../bluetooth/audio/cap_commander/uut/vocs.c | 76 +++++ .../audio/mocks/include/cap_commander.h | 1 + .../bluetooth/audio/mocks/src/cap_commander.c | 7 +- 10 files changed, 393 insertions(+), 3 deletions(-) create mode 100644 tests/bluetooth/audio/cap_commander/uut/vocs.c diff --git a/include/zephyr/bluetooth/audio/vocs.h b/include/zephyr/bluetooth/audio/vocs.h index eee5c43533a..d34e6bcd16e 100644 --- a/include/zephyr/bluetooth/audio/vocs.h +++ b/include/zephyr/bluetooth/audio/vocs.h @@ -29,6 +29,8 @@ #include #include +#include + #ifdef __cplusplus extern "C" { #endif diff --git a/tests/bluetooth/audio/cap_commander/include/cap_mocks.h b/tests/bluetooth/audio/cap_commander/include/cap_mocks.h index 5c7751bf37a..a907ab2b42c 100644 --- a/tests/bluetooth/audio/cap_commander/include/cap_mocks.h +++ b/tests/bluetooth/audio/cap_commander/include/cap_mocks.h @@ -8,3 +8,5 @@ void mock_bt_csip_init(void); void mock_bt_csip_cleanup(void); void mock_bt_vcp_init(void); void mock_bt_vcp_cleanup(void); +void mock_bt_vocs_init(void); +void mock_bt_vocs_cleanup(void); diff --git a/tests/bluetooth/audio/cap_commander/prj.conf b/tests/bluetooth/audio/cap_commander/prj.conf index fd805ec06a1..247cffed78a 100644 --- a/tests/bluetooth/audio/cap_commander/prj.conf +++ b/tests/bluetooth/audio/cap_commander/prj.conf @@ -7,6 +7,8 @@ CONFIG_BT_AUDIO=y # Requirements for CAP commander CONFIG_BT_VCP_VOL_CTLR=y +CONFIG_BT_VOCS_CLIENT_MAX_INSTANCE_COUNT=1 +CONFIG_BT_VCP_VOL_CTLR_MAX_VOCS_INST=1 CONFIG_BT_CSIP_SET_COORDINATOR=y CONFIG_BT_CAP_COMMANDER=y diff --git a/tests/bluetooth/audio/cap_commander/src/main.c b/tests/bluetooth/audio/cap_commander/src/main.c index 1cabbce134c..d4709f68851 100644 --- a/tests/bluetooth/audio/cap_commander/src/main.c +++ b/tests/bluetooth/audio/cap_commander/src/main.c @@ -25,6 +25,7 @@ static void mock_init_rule_before(const struct ztest_unit_test *test, void *fixt mock_cap_commander_init(); mock_bt_csip_init(); mock_bt_vcp_init(); + mock_bt_vocs_init(); } static void mock_destroy_rule_after(const struct ztest_unit_test *test, void *fixture) @@ -32,6 +33,7 @@ static void mock_destroy_rule_after(const struct ztest_unit_test *test, void *fi mock_cap_commander_cleanup(); mock_bt_csip_cleanup(); mock_bt_vcp_cleanup(); + mock_bt_vocs_cleanup(); } ZTEST_RULE(mock_rule, mock_init_rule_before, mock_destroy_rule_after); @@ -393,3 +395,262 @@ ZTEST_F(cap_commander_test_suite, test_commander_change_volume_inval_param_inval err = bt_cap_commander_change_volume(¶m); zassert_equal(-EINVAL, err, "Unexpected return value %d", err); } + +ZTEST_F(cap_commander_test_suite, test_commander_change_volume_offset) +{ + struct bt_cap_commander_change_volume_offset_member_param + member_params[ARRAY_SIZE(fixture->conns)]; + const struct bt_cap_commander_change_volume_offset_param param = { + .type = BT_CAP_SET_TYPE_AD_HOC, + .param = member_params, + .count = ARRAY_SIZE(member_params), + }; + int err; + + for (size_t i = 0U; i < ARRAY_SIZE(member_params); i++) { + member_params[i].member.member = &fixture->conns[i]; + member_params[i].offset = 100 + i; + } + + err = bt_cap_commander_register_cb(&mock_cap_commander_cb); + zassert_equal(0, err, "Unexpected return value %d", err); + + for (size_t i = 0; i < ARRAY_SIZE(fixture->conns); i++) { + struct bt_vcp_vol_ctlr *vol_ctlr; /* We don't care about this */ + + err = bt_cap_commander_discover(&fixture->conns[i]); + zassert_equal(0, err, "Unexpected return value %d", err); + + err = bt_vcp_vol_ctlr_discover(&fixture->conns[i], &vol_ctlr); + zassert_equal(0, err, "Unexpected return value %d", err); + } + + err = bt_cap_commander_change_volume_offset(¶m); + zassert_equal(0, err, "Unexpected return value %d", err); + + zexpect_call_count("bt_cap_commander_cb.volume_offset_changed", 1, + mock_cap_commander_volume_offset_changed_cb_fake.call_count); +} + +ZTEST_F(cap_commander_test_suite, test_commander_change_volume_offset_double) +{ + struct bt_cap_commander_change_volume_offset_member_param + member_params[ARRAY_SIZE(fixture->conns)]; + const struct bt_cap_commander_change_volume_offset_param param = { + .type = BT_CAP_SET_TYPE_AD_HOC, + .param = member_params, + .count = ARRAY_SIZE(member_params), + }; + int err; + + for (size_t i = 0U; i < ARRAY_SIZE(member_params); i++) { + member_params[i].member.member = &fixture->conns[i]; + member_params[i].offset = 100 + i; + } + + err = bt_cap_commander_register_cb(&mock_cap_commander_cb); + zassert_equal(0, err, "Unexpected return value %d", err); + + for (size_t i = 0; i < ARRAY_SIZE(fixture->conns); i++) { + struct bt_vcp_vol_ctlr *vol_ctlr; /* We don't care about this */ + + err = bt_cap_commander_discover(&fixture->conns[i]); + zassert_equal(0, err, "Unexpected return value %d", err); + + err = bt_vcp_vol_ctlr_discover(&fixture->conns[i], &vol_ctlr); + zassert_equal(0, err, "Unexpected return value %d", err); + } + + err = bt_cap_commander_change_volume_offset(¶m); + zassert_equal(0, err, "Unexpected return value %d", err); + + zexpect_call_count("bt_cap_commander_cb.volume_offset_changed", 1, + mock_cap_commander_volume_offset_changed_cb_fake.call_count); + + /* Verify that it still works as expected if we set the same value twice */ + err = bt_cap_commander_change_volume_offset(¶m); + zassert_equal(0, err, "Unexpected return value %d", err); + + zexpect_call_count("bt_cap_commander_cb.volume_offset_changed", 2, + mock_cap_commander_volume_offset_changed_cb_fake.call_count); +} + +ZTEST_F(cap_commander_test_suite, test_commander_change_volume_offset_inval_param_null) +{ + int err; + + err = bt_cap_commander_change_volume_offset(NULL); + zassert_equal(-EINVAL, err, "Unexpected return value %d", err); +} + +ZTEST_F(cap_commander_test_suite, test_commander_change_volume_offset_inval_param_null_param) +{ + const struct bt_cap_commander_change_volume_offset_param param = { + .type = BT_CAP_SET_TYPE_AD_HOC, + .param = NULL, + .count = ARRAY_SIZE(fixture->conns), + }; + int err; + + err = bt_cap_commander_change_volume_offset(¶m); + zassert_equal(-EINVAL, err, "Unexpected return value %d", err); +} + +ZTEST_F(cap_commander_test_suite, test_commander_change_volume_offset_inval_param_null_member) +{ + struct bt_cap_commander_change_volume_offset_member_param + member_params[ARRAY_SIZE(fixture->conns)]; + const struct bt_cap_commander_change_volume_offset_param param = { + .type = BT_CAP_SET_TYPE_AD_HOC, + .param = member_params, + .count = ARRAY_SIZE(member_params), + }; + int err; + + for (size_t i = 0U; i < ARRAY_SIZE(member_params); i++) { + member_params[i].member.member = &fixture->conns[i]; + member_params[i].offset = 100 + i; + } + member_params[ARRAY_SIZE(member_params) - 1].member.member = NULL; + + err = bt_cap_commander_change_volume_offset(¶m); + zassert_equal(-EINVAL, err, "Unexpected return value %d", err); +} + +ZTEST_F(cap_commander_test_suite, test_commander_change_volume_offset_inval_missing_cas) +{ + struct bt_cap_commander_change_volume_offset_member_param + member_params[ARRAY_SIZE(fixture->conns)]; + const struct bt_cap_commander_change_volume_offset_param param = { + .type = BT_CAP_SET_TYPE_AD_HOC, + .param = member_params, + .count = ARRAY_SIZE(member_params), + }; + int err; + + for (size_t i = 0U; i < ARRAY_SIZE(member_params); i++) { + member_params[i].member.member = &fixture->conns[i]; + member_params[i].offset = 100 + i; + } + + err = bt_cap_commander_register_cb(&mock_cap_commander_cb); + zassert_equal(0, err, "Unexpected return value %d", err); + + for (size_t i = 0; i < ARRAY_SIZE(fixture->conns); i++) { + struct bt_vcp_vol_ctlr *vol_ctlr; /* We don't care about this */ + + err = bt_vcp_vol_ctlr_discover(&fixture->conns[i], &vol_ctlr); + zassert_equal(0, err, "Unexpected return value %d", err); + } + + err = bt_cap_commander_change_volume_offset(¶m); + zassert_equal(-EINVAL, err, "Unexpected return value %d", err); +} + +ZTEST_F(cap_commander_test_suite, test_commander_change_volume_offset_inval_missing_vocs) +{ + struct bt_cap_commander_change_volume_offset_member_param + member_params[ARRAY_SIZE(fixture->conns)]; + const struct bt_cap_commander_change_volume_offset_param param = { + .type = BT_CAP_SET_TYPE_AD_HOC, + .param = member_params, + .count = ARRAY_SIZE(member_params), + }; + int err; + + for (size_t i = 0U; i < ARRAY_SIZE(member_params); i++) { + member_params[i].member.member = &fixture->conns[i]; + member_params[i].offset = 100 + i; + } + + err = bt_cap_commander_register_cb(&mock_cap_commander_cb); + zassert_equal(0, err, "Unexpected return value %d", err); + + for (size_t i = 0; i < ARRAY_SIZE(fixture->conns); i++) { + err = bt_cap_commander_discover(&fixture->conns[i]); + zassert_equal(0, err, "Unexpected return value %d", err); + } + + err = bt_cap_commander_change_volume_offset(¶m); + zassert_equal(-EINVAL, err, "Unexpected return value %d", err); +} + +ZTEST_F(cap_commander_test_suite, test_commander_change_volume_offset_inval_param_zero_count) +{ + struct bt_cap_commander_change_volume_offset_member_param + member_params[ARRAY_SIZE(fixture->conns)]; + const struct bt_cap_commander_change_volume_offset_param param = { + .type = BT_CAP_SET_TYPE_AD_HOC, + .param = member_params, + .count = 0U, + }; + int err; + + for (size_t i = 0U; i < ARRAY_SIZE(member_params); i++) { + member_params[i].member.member = &fixture->conns[i]; + member_params[i].offset = 100 + i; + } + + err = bt_cap_commander_change_volume_offset(¶m); + zassert_equal(-EINVAL, err, "Unexpected return value %d", err); +} + +ZTEST_F(cap_commander_test_suite, test_commander_change_volume_offset_inval_param_inval_count) +{ + struct bt_cap_commander_change_volume_offset_member_param + member_params[ARRAY_SIZE(fixture->conns)]; + const struct bt_cap_commander_change_volume_offset_param param = { + .type = BT_CAP_SET_TYPE_AD_HOC, + .param = member_params, + .count = CONFIG_BT_MAX_CONN + 1, + }; + int err; + + for (size_t i = 0U; i < ARRAY_SIZE(member_params); i++) { + member_params[i].member.member = &fixture->conns[i]; + member_params[i].offset = 100 + i; + } + + err = bt_cap_commander_change_volume_offset(¶m); + zassert_equal(-EINVAL, err, "Unexpected return value %d", err); +} + +ZTEST_F(cap_commander_test_suite, test_commander_change_volume_offset_inval_param_inval_offset_max) +{ + struct bt_cap_commander_change_volume_offset_member_param + member_params[ARRAY_SIZE(fixture->conns)]; + const struct bt_cap_commander_change_volume_offset_param param = { + .type = BT_CAP_SET_TYPE_AD_HOC, + .param = member_params, + .count = ARRAY_SIZE(member_params), + }; + int err; + + for (size_t i = 0U; i < ARRAY_SIZE(member_params); i++) { + member_params[i].member.member = &fixture->conns[i]; + member_params[i].offset = BT_VOCS_MAX_OFFSET + 1; + } + + err = bt_cap_commander_change_volume_offset(¶m); + zassert_equal(-EINVAL, err, "Unexpected return value %d", err); +} + +ZTEST_F(cap_commander_test_suite, test_commander_change_volume_offset_inval_param_inval_offset_min) +{ + struct bt_cap_commander_change_volume_offset_member_param + member_params[ARRAY_SIZE(fixture->conns)]; + const struct bt_cap_commander_change_volume_offset_param param = { + .type = BT_CAP_SET_TYPE_AD_HOC, + .param = member_params, + .count = ARRAY_SIZE(member_params), + }; + int err; + + for (size_t i = 0U; i < ARRAY_SIZE(member_params); i++) { + member_params[i].member.member = &fixture->conns[i]; + member_params[i].offset = BT_VOCS_MIN_OFFSET - 1; + } + + err = bt_cap_commander_change_volume_offset(¶m); + zassert_equal(-EINVAL, err, "Unexpected return value %d", err); +} diff --git a/tests/bluetooth/audio/cap_commander/uut/CMakeLists.txt b/tests/bluetooth/audio/cap_commander/uut/CMakeLists.txt index 8a0774a3182..d91bfbcbe7a 100644 --- a/tests/bluetooth/audio/cap_commander/uut/CMakeLists.txt +++ b/tests/bluetooth/audio/cap_commander/uut/CMakeLists.txt @@ -13,6 +13,7 @@ add_library(uut STATIC ${ZEPHYR_BASE}/subsys/net/buf_simple.c csip.c vcp.c + vocs.c ) add_subdirectory(${ZEPHYR_BASE}/tests/bluetooth/audio/mocks mocks) diff --git a/tests/bluetooth/audio/cap_commander/uut/csip.c b/tests/bluetooth/audio/cap_commander/uut/csip.c index 348b1ac9146..c6e910e8c0b 100644 --- a/tests/bluetooth/audio/cap_commander/uut/csip.c +++ b/tests/bluetooth/audio/cap_commander/uut/csip.c @@ -54,9 +54,9 @@ int bt_csip_set_coordinator_discover(struct bt_conn *conn) void mock_bt_csip_init(void) { - csip_cb = NULL; } void mock_bt_csip_cleanup(void) { + csip_cb = NULL; } diff --git a/tests/bluetooth/audio/cap_commander/uut/vcp.c b/tests/bluetooth/audio/cap_commander/uut/vcp.c index b6dc66afde5..c3390c21f2d 100644 --- a/tests/bluetooth/audio/cap_commander/uut/vcp.c +++ b/tests/bluetooth/audio/cap_commander/uut/vcp.c @@ -12,6 +12,8 @@ static struct bt_vcp_vol_ctlr_cb *vcp_cb; static struct bt_vcp_vol_ctlr { struct bt_conn *conn; + struct bt_vocs *vocs[CONFIG_BT_VCP_VOL_CTLR_MAX_VOCS_INST]; + struct bt_aics *aics[CONFIG_BT_VCP_VOL_CTLR_MAX_AICS_INST]; } vol_ctlrs[CONFIG_BT_MAX_CONN]; struct bt_vcp_vol_ctlr *bt_vcp_vol_ctlr_get_by_conn(const struct bt_conn *conn) @@ -45,8 +47,17 @@ int bt_vcp_vol_ctlr_discover(struct bt_conn *conn, struct bt_vcp_vol_ctlr **vol_ { for (size_t i = 0; i < ARRAY_SIZE(vol_ctlrs); i++) { if (vol_ctlrs[i].conn == NULL) { + for (size_t j = 0U; j < ARRAY_SIZE(vol_ctlrs[i].vocs); j++) { + const int err = bt_vocs_discover(conn, vol_ctlrs[i].vocs[j], NULL); + + if (err != 0) { + return err; + } + } + vol_ctlrs[i].conn = conn; *vol_ctlr = &vol_ctlrs[i]; + return 0; } } @@ -58,14 +69,43 @@ int bt_vcp_vol_ctlr_cb_register(struct bt_vcp_vol_ctlr_cb *cb) { vcp_cb = cb; + if (IS_ENABLED(CONFIG_BT_VCP_VOL_CTLR_VOCS)) { + for (size_t i = 0U; i < ARRAY_SIZE(vol_ctlrs); i++) { + for (size_t j = 0U; j < ARRAY_SIZE(vol_ctlrs[i].vocs); j++) { + bt_vocs_client_cb_register(vol_ctlrs[i].vocs[j], &cb->vocs_cb); + } + } + } + + return 0; +} + +int bt_vcp_vol_ctlr_included_get(struct bt_vcp_vol_ctlr *vol_ctlr, struct bt_vcp_included *included) +{ + included->vocs_cnt = ARRAY_SIZE(vol_ctlr->vocs); + included->vocs = vol_ctlr->vocs; + + included->aics_cnt = ARRAY_SIZE(vol_ctlr->aics); + included->aics = vol_ctlr->aics; + return 0; } void mock_bt_vcp_init(void) { - memset(vol_ctlrs, 0, sizeof(vol_ctlrs)); + if (IS_ENABLED(CONFIG_BT_VCP_VOL_CTLR_VOCS)) { + for (size_t i = 0U; i < ARRAY_SIZE(vol_ctlrs); i++) { + for (size_t j = 0U; j < ARRAY_SIZE(vol_ctlrs[i].vocs); j++) { + vol_ctlrs[i].vocs[j] = bt_vocs_client_free_instance_get(); + + __ASSERT(vol_ctlrs[i].vocs[j], + "Could not allocate VOCS client instance"); + } + } + } } void mock_bt_vcp_cleanup(void) { + memset(vol_ctlrs, 0, sizeof(vol_ctlrs)); } diff --git a/tests/bluetooth/audio/cap_commander/uut/vocs.c b/tests/bluetooth/audio/cap_commander/uut/vocs.c new file mode 100644 index 00000000000..075bd69b825 --- /dev/null +++ b/tests/bluetooth/audio/cap_commander/uut/vocs.c @@ -0,0 +1,76 @@ +/* csip.c - CAP Commander specific VOCS mocks */ + +/* + * Copyright (c) 2023 Nordic Semiconductor ASA + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include + +static struct bt_vocs { + bool active; + struct bt_conn *conn; + struct bt_vocs_cb *cb; +} vocs_clients[CONFIG_BT_MAX_CONN * CONFIG_BT_VOCS_CLIENT_MAX_INSTANCE_COUNT]; + +int bt_vocs_client_conn_get(const struct bt_vocs *vocs, struct bt_conn **conn) +{ + *conn = vocs->conn; + + return 0; +} + +int bt_vocs_state_set(struct bt_vocs *vocs, int16_t offset) +{ + if (vocs != NULL && vocs->cb != NULL && vocs->cb->set_offset != NULL) { + vocs->cb->set_offset(vocs, 0); + } + + return 0; +} + +void bt_vocs_client_cb_register(struct bt_vocs *vocs, struct bt_vocs_cb *cb) +{ + vocs->cb = cb; +} + +struct bt_vocs *bt_vocs_client_free_instance_get(void) +{ + for (size_t i = 0U; i < ARRAY_SIZE(vocs_clients); i++) { + if (!vocs_clients[i].active) { + vocs_clients[i].active = true; + + return &vocs_clients[i]; + } + } + + return NULL; +} + +int bt_vocs_discover(struct bt_conn *conn, struct bt_vocs *vocs, + const struct bt_vocs_discover_param *param) +{ + vocs->conn = conn; + + if (vocs != NULL && vocs->cb != NULL && vocs->cb->discover != NULL) { + vocs->cb->discover(vocs, 0); + } + + return 0; +} + +void mock_bt_vocs_init(void) +{ +} + +void mock_bt_vocs_cleanup(void) +{ + /* Reset everything but the callbacks, as they will not be registered again between each + * test + */ + for (size_t i = 0U; i < ARRAY_SIZE(vocs_clients); i++) { + vocs_clients[i].active = false; + vocs_clients[i].conn = NULL; + } +} diff --git a/tests/bluetooth/audio/mocks/include/cap_commander.h b/tests/bluetooth/audio/mocks/include/cap_commander.h index 86be0119671..73fab99c2b4 100644 --- a/tests/bluetooth/audio/mocks/include/cap_commander.h +++ b/tests/bluetooth/audio/mocks/include/cap_commander.h @@ -18,5 +18,6 @@ void mock_cap_commander_cleanup(void); DECLARE_FAKE_VOID_FUNC(mock_cap_commander_discovery_complete_cb, struct bt_conn *, int, const struct bt_csip_set_coordinator_csis_inst *); DECLARE_FAKE_VOID_FUNC(mock_cap_commander_volume_changed_cb, struct bt_conn *, int); +DECLARE_FAKE_VOID_FUNC(mock_cap_commander_volume_offset_changed_cb, struct bt_conn *, int); #endif /* MOCKS_CAP_COMMANDER_H_ */ diff --git a/tests/bluetooth/audio/mocks/src/cap_commander.c b/tests/bluetooth/audio/mocks/src/cap_commander.c index de0e309ecbd..c4ba4b522c4 100644 --- a/tests/bluetooth/audio/mocks/src/cap_commander.c +++ b/tests/bluetooth/audio/mocks/src/cap_commander.c @@ -11,17 +11,22 @@ /* List of fakes used by this unit tester */ #define FFF_FAKES_LIST(FAKE) \ FAKE(mock_cap_commander_discovery_complete_cb) \ - FAKE(mock_cap_commander_volume_changed_cb) + FAKE(mock_cap_commander_volume_changed_cb) \ + FAKE(mock_cap_commander_volume_offset_changed_cb) DEFINE_FAKE_VOID_FUNC(mock_cap_commander_discovery_complete_cb, struct bt_conn *, int, const struct bt_csip_set_coordinator_csis_inst *); DEFINE_FAKE_VOID_FUNC(mock_cap_commander_volume_changed_cb, struct bt_conn *, int); +DEFINE_FAKE_VOID_FUNC(mock_cap_commander_volume_offset_changed_cb, struct bt_conn *, int); const struct bt_cap_commander_cb mock_cap_commander_cb = { .discovery_complete = mock_cap_commander_discovery_complete_cb, #if defined(CONFIG_BT_VCP_VOL_CTLR) .volume_changed = mock_cap_commander_volume_changed_cb, +#if defined(CONFIG_BT_VCP_VOL_CTLR_VOCS) + .volume_offset_changed = mock_cap_commander_volume_offset_changed_cb, +#endif /* CONFIG_BT_VCP_VOL_CTLR */ #endif /* CONFIG_BT_VCP_VOL_CTLR */ }; From 6c403da3cd167f0850fb83c04251a2cae52ea99e Mon Sep 17 00:00:00 2001 From: Emil Gydesen Date: Mon, 4 Dec 2023 11:12:33 +0100 Subject: [PATCH 3259/3723] Bluetooth: Audio: Shell: CAP change volume offset command Add sthe change volume offset command to the CAP commander shell. Signed-off-by: Emil Gydesen --- doc/connectivity/bluetooth/api/shell/cap.rst | 39 ++++++- subsys/bluetooth/audio/shell/cap_commander.c | 102 ++++++++++++++++++- 2 files changed, 135 insertions(+), 6 deletions(-) diff --git a/doc/connectivity/bluetooth/api/shell/cap.rst b/doc/connectivity/bluetooth/api/shell/cap.rst index 32d752d71fc..51a42c90260 100644 --- a/doc/connectivity/bluetooth/api/shell/cap.rst +++ b/doc/connectivity/bluetooth/api/shell/cap.rst @@ -159,8 +159,10 @@ the optionally included CSIS instance by calling (:code:`cap_commander discover` cap_commander --help cap_commander - Bluetooth CAP commander shell commands Subcommands: - discover :Discover CAS - change_volume :Change volume on all connections + discover :Discover CAS + change_volume :Change volume on all connections + change_volume_offset :Change volume offset per connection Before being able to perform any stream operation, the device must also perform the @@ -193,3 +195,36 @@ Setting the volume on all connected devices: VCP flags 0x01 VCP vol_set done Volume change completed + + +Setting the volume offset on one or more connected devices. The offsets are set by connection index, +so connection index 0 gets the first offset, and index 1 gets the second offset, etc.: + +.. code-block:: console + + uart:~$ bt connect + Connected: + uart:~$ cap_commander discover + discovery completed with CSIS + uart:~$ vcp_vol_ctlr discover + VCP discover done with 1 VOCS and 1 AICS + uart:~$ + uart:~$ bt connect + Connected: + uart:~$ cap_commander discover + discovery completed with CSIS + uart:~$ vcp_vol_ctlr discover + VCP discover done with 1 VOCS and 1 AICS + uart:~$ + uart:~$ cap_commander change_volume_offset 10 + Setting volume offset on 1 connections + VOCS inst 0x200140a4 offset 10 + Offset set for inst 0x200140a4 + Volume offset change completed + uart:~$ + uart:~$ cap_commander change_volume_offset 10 15 + Setting volume offset on 2 connections + Offset set for inst 0x200140a4 + VOCS inst 0x20014188 offset 15 + Offset set for inst 0x20014188 + Volume offset change completed diff --git a/subsys/bluetooth/audio/shell/cap_commander.c b/subsys/bluetooth/audio/shell/cap_commander.c index 01675f8fc6c..6e4f85eba01 100644 --- a/subsys/bluetooth/audio/shell/cap_commander.c +++ b/subsys/bluetooth/audio/shell/cap_commander.c @@ -8,10 +8,12 @@ */ #include -#include -#include #include #include +#include +#include +#include +#include #include "shell/bt.h" #include "audio.h" @@ -37,12 +39,27 @@ static void cap_volume_changed_cb(struct bt_conn *conn, int err) shell_print(ctx_shell, "Volume change completed"); } + +#if defined(CONFIG_BT_VCP_VOL_CTLR_VOCS) +static void cap_volume_offset_changed_cb(struct bt_conn *conn, int err) +{ + if (err != 0) { + shell_error(ctx_shell, "Volume offset change failed (%d)", err); + return; + } + + shell_print(ctx_shell, "Volume offset change completed"); +} +#endif /* CONFIG_BT_VCP_VOL_CTLR_VOCS */ #endif /* CONFIG_BT_VCP_VOL_CTLR */ static struct bt_cap_commander_cb cbs = { .discovery_complete = cap_discover_cb, #if defined(CONFIG_BT_VCP_VOL_CTLR) .volume_changed = cap_volume_changed_cb, +#if defined(CONFIG_BT_VCP_VOL_CTLR_VOCS) + .volume_offset_changed = cap_volume_offset_changed_cb, +#endif /* CONFIG_BT_VCP_VOL_CTLR_VOCS */ #endif /* CONFIG_BT_VCP_VOL_CTLR */ }; @@ -145,6 +162,79 @@ static int cmd_cap_commander_change_volume(const struct shell *sh, size_t argc, return 0; } + +#if defined(CONFIG_BT_VCP_VOL_CTLR_VOCS) +static int cmd_cap_commander_change_volume_offset(const struct shell *sh, size_t argc, char *argv[]) +{ + struct bt_cap_commander_change_volume_offset_member_param member_params[CONFIG_BT_MAX_CONN]; + const size_t cap_args = argc - 1; /* First argument is the command itself */ + struct bt_cap_commander_change_volume_offset_param param = { + .type = BT_CAP_SET_TYPE_AD_HOC, + .param = member_params, + }; + struct bt_conn *connected_conns[CONFIG_BT_MAX_CONN] = {0}; + size_t conn_cnt = 0U; + int err = 0; + + if (default_conn == NULL) { + shell_error(sh, "Not connected"); + return -ENOEXEC; + } + + /* Populate the array of connected connections */ + bt_conn_foreach(BT_CONN_TYPE_LE, populate_connected_conns, (void *)connected_conns); + for (size_t i = 0; i < ARRAY_SIZE(connected_conns); i++) { + struct bt_conn *conn = connected_conns[i]; + + if (conn == NULL) { + break; + } + + conn_cnt++; + } + + if (cap_args > conn_cnt) { + shell_error(sh, "Cannot use %zu arguments for %zu connections", argc, conn_cnt); + + return -ENOEXEC; + } + + /* TODO: Add support for coordinated sets */ + + for (size_t i = 0U; i < cap_args; i++) { + const char *arg = argv[i + 1]; + long volume_offset; + + volume_offset = shell_strtol(arg, 10, &err); + if (err != 0) { + shell_error(sh, "Failed to parse volume offset from %s", arg); + + return -ENOEXEC; + } + + if (!IN_RANGE(volume_offset, BT_VOCS_MIN_OFFSET, BT_VOCS_MAX_OFFSET)) { + shell_error(sh, "Invalid volume_offset %lu", volume_offset); + + return -ENOEXEC; + } + + member_params[i].offset = (int16_t)volume_offset; + member_params[i].member.member = connected_conns[i]; + param.count++; + } + + shell_print(sh, "Setting volume offset on %zu connections", param.count); + + err = bt_cap_commander_change_volume_offset(¶m); + if (err != 0) { + shell_print(sh, "Failed to change volume offset: %d", err); + + return -ENOEXEC; + } + + return 0; +} +#endif /* CONFIG_BT_VCP_VOL_CTLR_VOCS */ #endif /* CONFIG_BT_VCP_VOL_CTLR */ static int cmd_cap_commander(const struct shell *sh, size_t argc, char **argv) @@ -164,9 +254,13 @@ SHELL_STATIC_SUBCMD_SET_CREATE( #if defined(CONFIG_BT_VCP_VOL_CTLR) SHELL_CMD_ARG(change_volume, NULL, "Change volume on all connections ", cmd_cap_commander_change_volume, 2, 0), +#if defined(CONFIG_BT_VCP_VOL_CTLR_VOCS) + SHELL_CMD_ARG(change_volume_offset, NULL, + "Change volume offset per connection ", + cmd_cap_commander_change_volume_offset, 2, CONFIG_BT_MAX_CONN - 1), +#endif /* CONFIG_BT_VCP_VOL_CTLR_VOCS */ #endif /* CONFIG_BT_VCP_VOL_CTLR */ - SHELL_SUBCMD_SET_END -); + SHELL_SUBCMD_SET_END); SHELL_CMD_ARG_REGISTER(cap_commander, &cap_commander_cmds, "Bluetooth CAP commander shell commands", cmd_cap_commander, 1, 1); From 03a2dcf4b1ac8469525b640aad5a90120a2750a7 Mon Sep 17 00:00:00 2001 From: Kevin Wang Date: Tue, 30 Jan 2024 11:01:21 +0800 Subject: [PATCH 3260/3723] drivers: dma: atcdmac300: Update driver for bug 68129 1. Remove redundant include, is not needed. 2. Fix some wrong MACRO defined Signed-off-by: Kevin Wang --- drivers/dma/dma_andes_atcdmac300.c | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/drivers/dma/dma_andes_atcdmac300.c b/drivers/dma/dma_andes_atcdmac300.c index 8132dd1749c..2f817242fbe 100644 --- a/drivers/dma/dma_andes_atcdmac300.c +++ b/drivers/dma/dma_andes_atcdmac300.c @@ -71,18 +71,18 @@ LOG_MODULE_REGISTER(dma_andes_atcdmac300); #define DMA_CH_CTRL_SBINF_MASK BIT(31) #define DMA_CH_CTRL_DBINF_MASK BIT(30) #define DMA_CH_CTRL_PRIORITY_HIGH BIT(29) -#define DMA_CH_CTRL_SBSIZE_MASK BIT(24) +#define DMA_CH_CTRL_SBSIZE_MASK GENMASK(27, 24) #define DMA_CH_CTRL_SBSIZE(n) FIELD_PREP(DMA_CH_CTRL_SBSIZE_MASK, (n)) #define DMA_CH_CTRL_SWIDTH_MASK GENMASK(23, 21) #define DMA_CH_CTRL_SWIDTH(n) FIELD_PREP(DMA_CH_CTRL_SWIDTH_MASK, (n)) #define DMA_CH_CTRL_DWIDTH_MASK GENMASK(20, 18) #define DMA_CH_CTRL_DWIDTH(n) FIELD_PREP(DMA_CH_CTRL_DWIDTH_MASK, (n)) #define DMA_CH_CTRL_SMODE_HANDSHAKE BIT(17) -#define DMA_CH_CTRL_DMODE_HANDSHAKE BIT(17) +#define DMA_CH_CTRL_DMODE_HANDSHAKE BIT(16) #define DMA_CH_CTRL_SRCADDRCTRL_MASK GENMASK(15, 14) -#define DMA_CH_CTRL_SRCADDR_INC FIELD_PREP(DMA_CH_CTRL_DWIDTH_MASK, (0)) -#define DMA_CH_CTRL_SRCADDR_DEC FIELD_PREP(DMA_CH_CTRL_DWIDTH_MASK, (1)) -#define DMA_CH_CTRL_SRCADDR_FIX FIELD_PREP(DMA_CH_CTRL_DWIDTH_MASK, (2)) +#define DMA_CH_CTRL_SRCADDR_INC FIELD_PREP(DMA_CH_CTRL_SRCADDRCTRL_MASK, (0)) +#define DMA_CH_CTRL_SRCADDR_DEC FIELD_PREP(DMA_CH_CTRL_SRCADDRCTRL_MASK, (1)) +#define DMA_CH_CTRL_SRCADDR_FIX FIELD_PREP(DMA_CH_CTRL_SRCADDRCTRL_MASK, (2)) #define DMA_CH_CTRL_DSTADDRCTRL_MASK GENMASK(13, 12) #define DMA_CH_CTRL_DSTADDR_INC FIELD_PREP(DMA_CH_CTRL_DSTADDRCTRL_MASK, (0)) #define DMA_CH_CTRL_DSTADDR_DEC FIELD_PREP(DMA_CH_CTRL_DSTADDRCTRL_MASK, (1)) From a053c55c402c69c451f6cf93a6bae29a6a58b216 Mon Sep 17 00:00:00 2001 From: Daniel Leung Date: Wed, 31 Jan 2024 09:16:33 -0800 Subject: [PATCH 3261/3723] boards: x86: more stack space for qemu_x86_tiny@768 qemu_x86_tiny@768 has coverage enabled by default. Because of this, it requires more stack space for running tests. The increases needed are verified via twister. Fixes #68272 Signed-off-by: Daniel Leung --- boards/x86/qemu_x86/qemu_x86_tiny_768.conf | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/boards/x86/qemu_x86/qemu_x86_tiny_768.conf b/boards/x86/qemu_x86/qemu_x86_tiny_768.conf index 4601be10f38..583d6a85451 100644 --- a/boards/x86/qemu_x86/qemu_x86_tiny_768.conf +++ b/boards/x86/qemu_x86/qemu_x86_tiny_768.conf @@ -3,3 +3,7 @@ # Enable coverage regardless since this config for coverage only. CONFIG_COVERAGE=y + +# Need more stack space due to coverage being enabled. +CONFIG_MAIN_STACK_SIZE=4096 +CONFIG_IDLE_STACK_SIZE=1024 From 417c18c974da78dcc77ace77e0b3db4dbc6d2314 Mon Sep 17 00:00:00 2001 From: Flavio Ceolin Date: Wed, 31 Jan 2024 06:25:17 -0800 Subject: [PATCH 3262/3723] tests: posis/fs: close only valid descriptor Only call close() if open() has not returned a negative value. Fixes CID 211585 Signed-off-by: Flavio Ceolin --- tests/posix/fs/src/test_fs_open_flags.c | 16 ++++++++++++---- 1 file changed, 12 insertions(+), 4 deletions(-) diff --git a/tests/posix/fs/src/test_fs_open_flags.c b/tests/posix/fs/src/test_fs_open_flags.c index e12101a7f29..1187b1c3e57 100644 --- a/tests/posix/fs/src/test_fs_open_flags.c +++ b/tests/posix/fs/src/test_fs_open_flags.c @@ -22,7 +22,9 @@ static int test_file_open_flags(void) fd = open(THE_FILE, 0); if (fd >= 0 || errno != ENOENT) { TC_PRINT("Expected fail; fd = %d, errno = %d\n", fd, errno); - close(fd); + if (fd >= 0) { + close(fd); + } return TC_FAIL; } @@ -30,14 +32,18 @@ static int test_file_open_flags(void) fd = open(THE_FILE, O_RDONLY); if (fd >= 0 || errno != ENOENT) { TC_PRINT("Expected fail; fd = %d, errno = %d\n", fd, errno); - close(fd); + if (fd >= 0) { + close(fd); + } return TC_FAIL; } TC_PRINT("Open on non-existent file, flags = O_WRONLY\n"); fd = open(THE_FILE, O_WRONLY); if (fd >= 0 || errno != ENOENT) { TC_PRINT("Expected fail; fd = %d, errno = %d\n", fd, errno); - close(fd); + if (fd >= 0) { + close(fd); + } return TC_FAIL; } @@ -45,7 +51,9 @@ static int test_file_open_flags(void) fd = open(THE_FILE, O_RDWR); if (fd >= 0 || errno != ENOENT) { TC_PRINT("Expected fail; fd = %d, errno = %d\n", fd, errno); - close(fd); + if (fd >= 0) { + close(fd); + } return TC_FAIL; } /* end 1 */ From ccb2a0df044d1bfa66be07d41250952c90e8e97d Mon Sep 17 00:00:00 2001 From: Harshit Agarwal Date: Wed, 10 Jan 2024 23:21:42 +0530 Subject: [PATCH 3263/3723] dts: riscv: add PolarFire SoC system controller QSPI interface Add support for Microchip's PolarFire SoC system controller QSPI interface. Signed-off-by: Harshit Agarwal --- dts/riscv/microchip/mpfs.dtsi | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/dts/riscv/microchip/mpfs.dtsi b/dts/riscv/microchip/mpfs.dtsi index 0ab207b28a3..f45e575b0de 100644 --- a/dts/riscv/microchip/mpfs.dtsi +++ b/dts/riscv/microchip/mpfs.dtsi @@ -206,6 +206,17 @@ clock-frequency = <150000000>; }; + syscontroller_qspi: spi@37020100 { + compatible = "microchip,mpfs-qspi"; + #address-cells = <1>; + #size-cells = <0>; + reg = <0x37020100 0x1000>; + interrupt-parent = <&plic>; + interrupts = <110 1>; + status = "disabled"; + clock-frequency = <150000000>; + }; + gpio0: gpio@20120000 { compatible = "microchip,mpfs-gpio"; reg = <0x20120000 0x1000>; From f4a8ec3f930f2c56da1db860f3af67a109af2157 Mon Sep 17 00:00:00 2001 From: Harshit Agarwal Date: Thu, 25 Jan 2024 08:08:16 +0530 Subject: [PATCH 3264/3723] dts: mbox: add PolarFire SoC mailbox interface Add Microchip's PolarFire SoC mailbox node. Signed-off-by: Harshit Agarwal --- dts/bindings/mbox/microchip,mpfs-mailbox.yaml | 45 +++++++++++++++++++ dts/riscv/microchip/mpfs.dtsi | 10 +++++ 2 files changed, 55 insertions(+) create mode 100644 dts/bindings/mbox/microchip,mpfs-mailbox.yaml diff --git a/dts/bindings/mbox/microchip,mpfs-mailbox.yaml b/dts/bindings/mbox/microchip,mpfs-mailbox.yaml new file mode 100644 index 00000000000..8a7d9bff2eb --- /dev/null +++ b/dts/bindings/mbox/microchip,mpfs-mailbox.yaml @@ -0,0 +1,45 @@ +# +# Copyright (c) 2024 Microchip Technology Inc. +# +# SPDX-License-Identifier: Apache-2.0 +# +include: [base.yaml, mailbox-controller.yaml] + +properties: + compatible: + const: microchip,mpfs-mailbox + + reg: + - items: + - description: mailbox control registers + - description: mailbox interrupt registers + - description: mailbox data registers + + interrupts: + maxItems: 1 + + "#mbox-cells": + const: 1 + +required: + - compatible + - reg + - interrupts + - "#mbox-cells" + +additionalProperties: false + +examples: + - | + soc { + #address-cells = <2>; + #size-cells = <2>; + mbox: mailbox@37020000 { + compatible = "microchip,mpfs-mailbox"; + reg = <0x37020000 0x58>, <0x2000318C 0x40>, + <0x37020800 0x100>; + interrupt-parent = <&L1>; + interrupts = <96>; + #mbox-cells = <1>; + }; + }; diff --git a/dts/riscv/microchip/mpfs.dtsi b/dts/riscv/microchip/mpfs.dtsi index f45e575b0de..f22c7604bb3 100644 --- a/dts/riscv/microchip/mpfs.dtsi +++ b/dts/riscv/microchip/mpfs.dtsi @@ -129,6 +129,16 @@ riscv,ndev = <186>; }; + mbox: mailbox@37020000 { + compatible = "microchip,mpfs-mailbox"; + reg = <0x37020000 0x58>, <0x2000318C 0x40>, + <0x37020800 0x100>; + interrupt-parent = <&plic>; + interrupts = <96 1>; + #mbox-cells = <1>; + status = "disabled"; + }; + uart0: uart@20000000 { compatible = "ns16550"; reg = <0x20000000 0x1000>; From 785d349de2d0129fe085d4a7e5f0920bde124dd1 Mon Sep 17 00:00:00 2001 From: Harshit Agarwal Date: Thu, 11 Jan 2024 04:45:24 +0530 Subject: [PATCH 3265/3723] drivers: fpga: add Microchip PolarFire SoC FPGA driver Add FPGA driver support for Microchip PolarFire SoC. Signed-off-by: Harshit Agarwal --- drivers/fpga/CMakeLists.txt | 1 + drivers/fpga/Kconfig | 1 + drivers/fpga/Kconfig.mpfs | 10 + drivers/fpga/fpga_mpfs.c | 413 ++++++++++++++++++++++++++++++++++++ 4 files changed, 425 insertions(+) create mode 100644 drivers/fpga/Kconfig.mpfs create mode 100644 drivers/fpga/fpga_mpfs.c diff --git a/drivers/fpga/CMakeLists.txt b/drivers/fpga/CMakeLists.txt index 3db822ad0d0..e7a16193c4c 100644 --- a/drivers/fpga/CMakeLists.txt +++ b/drivers/fpga/CMakeLists.txt @@ -6,4 +6,5 @@ zephyr_library_sources_ifdef(CONFIG_FPGA_SHELL fpga_shell.c) zephyr_library_sources_ifdef(CONFIG_EOS_S3_FPGA fpga_eos_s3.c) zephyr_library_sources_ifdef(CONFIG_ICE40_FPGA fpga_ice40.c) +zephyr_library_sources_ifdef(CONFIG_MPFS_FPGA fpga_mpfs.c) zephyr_library_sources_ifdef(CONFIG_ZYNQMP_FPGA fpga_zynqmp.c) diff --git a/drivers/fpga/Kconfig b/drivers/fpga/Kconfig index a9573137be1..6041a164f18 100644 --- a/drivers/fpga/Kconfig +++ b/drivers/fpga/Kconfig @@ -28,6 +28,7 @@ config FPGA_SHELL source "drivers/fpga/Kconfig.eos_s3" source "drivers/fpga/Kconfig.ice40" +source "drivers/fpga/Kconfig.mpfs" source "drivers/fpga/Kconfig.zynqmp" endif # FPGA diff --git a/drivers/fpga/Kconfig.mpfs b/drivers/fpga/Kconfig.mpfs new file mode 100644 index 00000000000..197921015ed --- /dev/null +++ b/drivers/fpga/Kconfig.mpfs @@ -0,0 +1,10 @@ +# FPGA Microchip PolarFire SOC driver configuration options + +# Copyright (c) 2023 Microchip Technology Inc. +# SPDX-License-Identifier: Apache-2.0 + +config MPFS_FPGA + bool "Microchip PolarFire SOC FPGA driver" + depends on SPI + help + Enable support for the Microchip PolarFire SOC FPGA driver. diff --git a/drivers/fpga/fpga_mpfs.c b/drivers/fpga/fpga_mpfs.c new file mode 100644 index 00000000000..d8c777a4501 --- /dev/null +++ b/drivers/fpga/fpga_mpfs.c @@ -0,0 +1,413 @@ +/* + * Copyright (c) 2024 Microchip Technology Inc. + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#define DT_DRV_COMPAT microchip_mpfs_mailbox +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +LOG_MODULE_REGISTER(fpga_mpfs); + +#define SPI_FLASH_DIRECTORY_OFFSET 0x00000000 +#define SPI_FLASH_GOLDEN_IMAGE_OFFSET 0x00100400 +#define SPI_FLASH_NEW_IMAGE_OFFSET 0x01500400 +#define SPI_FLASH_SECTOR_SIZE 4096 +#define SPI_FLASH_PAGE_SIZE 256 + +#define SERVICES_CR_OFFSET 0x50u +#define SERVICES_SR_OFFSET 0x54u + +#define SCBCTRL_SERVICESCR_REQ (0u) +#define SCBCTRL_SERVICESCR_REQ_MASK BIT(SCBCTRL_SERVICESCR_REQ) + +#define SCBCTRL_SERVICESSR_BUSY (1u) +#define SCBCTRL_SERVICESSR_BUSY_MASK BIT(SCBCTRL_SERVICESSR_BUSY) + +#define SCBCTRL_SERVICESSR_STATUS (16u) +#define SCBCTRL_SERVICESSR_STATUS_MASK_WIDTH (16u) +#define SCBCTRL_SERVICESSR_STATUS_MASK \ + GENMASK(SCBCTRL_SERVICESSR_STATUS + SCBCTRL_SERVICESSR_STATUS_MASK_WIDTH - 1, \ + SCBCTRL_SERVICESSR_STATUS) + +#define MSS_DESIGN_INFO_CMD (0x02) +#define MSS_SYS_BITSTREAM_AUTHENTICATE_CMD 0x23u +#define MSS_SYS_IAP_PROGRAM_BY_SPIIDX_CMD 0x42u + +struct mpfs_fpga_config { + mm_reg_t base; + mm_reg_t mailbox; +}; + +struct mpfs_fpga_data { + char FPGA_design_ver[30]; +}; + +static inline uint32_t scb_read(mm_reg_t add, mm_reg_t offset) +{ + return sys_read32(add + offset); +} + +static inline void scb_write(mm_reg_t add, mm_reg_t offset, uint32_t val) +{ + return sys_write32(val, add + offset); +} + +/*This function add the index of new image into the spi directory at offset 0x004. + * Note: In the Flash directory first four pages(each page of 256 Bytes) have either + * a valid image address or zeros. The other remaining 12 pages are all filled with 0xFFs. + * + * |------------------------------| 0x000 + * | Golden Image Address: | + * | 0x0100400 | + * |------------------------------| 0x004 + * | Update Image Address | + * | 0x1500400 | + * |------------------------------| 0x008 + * | Empty | + * | 0x000000 | + * |------------------------------| 0x00C + * | Unused for re-programming | + * | | + * |------------------------------| 0x400 + */ +static uint8_t update_spi_flash_directory(const struct device *flash_dev) +{ + size_t len = SPI_FLASH_PAGE_SIZE; + uint8_t buf[SPI_FLASH_PAGE_SIZE]; + uint8_t rc, k; + + memset(buf, 0, len); + + rc = flash_read(flash_dev, SPI_FLASH_DIRECTORY_OFFSET, buf, len); + if (rc != 0) { + LOG_ERR("Flash read failed! %d", rc); + return rc; + } + + /* New image address(0x1500400) entry at offset 0x004 */ + buf[4] = 0x00; + buf[5] = 0x04; + buf[6] = 0x50; + buf[7] = 0x01; + + /* Erase SPI flash directory */ + + rc = flash_erase(flash_dev, SPI_FLASH_DIRECTORY_OFFSET, SPI_FLASH_SECTOR_SIZE); + if (rc != 0) { + LOG_ERR("erase failed! %d", rc); + } + + /* Write the first page with updated address entry */ + rc = flash_write(flash_dev, SPI_FLASH_DIRECTORY_OFFSET, buf, len); + if (rc != 0) { + LOG_ERR("Flash write failed! %d", rc); + return rc; + } + + /* Fill page number second, third and fourth with zeros */ + memset(buf, 0, len); + k = 1; + while (k < 4) { + rc = flash_write(flash_dev, (SPI_FLASH_DIRECTORY_OFFSET + k * 0x100), buf, len); + if (rc != 0) { + LOG_ERR("Flash write failed! %d", rc); + return rc; + } + k++; + } + + return rc; +} + +/* This function Program a new FPGA design image into the SPI Flash at location + * 0x1500400. + * Note: The source location of new image is _bin_start symbol value and the size of + * new image is _bim_size symbol value. + */ +static uint8_t program_new_image(const struct device *flash_dev, uint8_t *image_start, + uint32_t image_size) +{ + size_t len = SPI_FLASH_PAGE_SIZE; + uint8_t buf[SPI_FLASH_PAGE_SIZE]; + uint8_t rc; + uint32_t i, count, k; + uint8_t *temp; + + temp = image_start; + + if (image_size > 0x1400000) { + LOG_ERR("Image is larger than 20Mb"); + return 1; + } + + /* Find the sectors to erase */ + count = (uint32_t)(image_size / SPI_FLASH_SECTOR_SIZE) + 1; + + LOG_INF("Erasing."); + i = 0; + while (i < count) { + rc = flash_erase( + flash_dev, + ((SPI_FLASH_NEW_IMAGE_OFFSET - 0x400) + (i * SPI_FLASH_SECTOR_SIZE)), + SPI_FLASH_SECTOR_SIZE); + if (rc != 0) { + LOG_ERR("erase failed! %d", rc); + } + + if (i % 0x100 == 0) { + LOG_DBG("."); + } + + i++; + } + /* Erase completed and ready to program new image */ + + /* Find the pages to program */ + count = (uint32_t)(image_size / SPI_FLASH_PAGE_SIZE) + 1; + + LOG_INF("Programming."); + i = 0; + while (i < count) { + temp = (image_start + i * SPI_FLASH_PAGE_SIZE); + memset(buf, 0, len); + for (k = 0; k < 256; k++) { + buf[k] = *temp; + temp = temp + 1; + } + + rc = flash_write(flash_dev, (SPI_FLASH_NEW_IMAGE_OFFSET + i * SPI_FLASH_PAGE_SIZE), + buf, len); + if (rc != 0) { + LOG_ERR("Flash write failed! %d", rc); + return rc; + } + + if (i % 0x100 == 0) { + LOG_DBG("."); + } + + i++; + } + + LOG_INF("Programming completed."); + + return rc; +} + +static int8_t verify_image(const struct device *dev) +{ + const struct mpfs_fpga_config *cfg = dev->config; + int8_t status = EINVAL; + uint32_t value = 0; + + LOG_INF("Image verification started..."); + + /* Once system controller starts processing command The busy bit will + * go 1. Make sure that service is complete i.e. BUSY bit is gone 0 + */ + while (scb_read(cfg->base, SERVICES_SR_OFFSET) & SCBCTRL_SERVICESSR_BUSY_MASK) { + ; + } + + /* Form the SS command: bit 0 to 6 is the opcode, bit 7 to 15 is the Mailbox + * offset For some services this field has another meaning. + * (e.g. for IAP bit-stream auth. it means spi_idx) + */ + scb_write(cfg->mailbox, 0, 0x1500400); + + value = (MSS_SYS_BITSTREAM_AUTHENTICATE_CMD << 16) | 0x1; + scb_write(cfg->base, SERVICES_CR_OFFSET, value); + + /* REQ bit will remain set till the system controller starts + * processing command. Since DRI is slow interface, we are waiting + * here to make sure System controller has started processing + * command + */ + while (scb_read(cfg->base, SERVICES_CR_OFFSET) & SCBCTRL_SERVICESCR_REQ_MASK) { + ; + } + + /* Once system controller starts processing command The busy bit will + * go 1. Make sure that service is complete i.e. BUSY bit is gone 0 + */ + while (scb_read(cfg->base, SERVICES_SR_OFFSET) & SCBCTRL_SERVICESSR_BUSY_MASK) { + ; + } + + /* Read the status returned by System Controller */ + status = ((scb_read(cfg->base, SERVICES_SR_OFFSET) & SCBCTRL_SERVICESSR_STATUS_MASK) >> + SCBCTRL_SERVICESSR_STATUS); + LOG_INF("Image verification status : %x ", status); + + return status; +} + +static void activate_image(const struct device *dev) +{ + const struct mpfs_fpga_config *cfg = dev->config; + int8_t status = EINVAL; + uint32_t value = 0; + + LOG_INF("Image activation started..."); + + /* Once system controller starts processing command The busy bit will + * go 1. Make sure that service is complete i.e. BUSY bit is gone 0 + */ + while (scb_read(cfg->base, SERVICES_SR_OFFSET) & SCBCTRL_SERVICESSR_BUSY_MASK) { + ; + } + + /* Form the SS command: bit 0 to 6 is the opcode, bit 7 to 15 is the Mailbox + * offset For some services this field has another meaning. + * (e.g. for IAP bit-stream auth. it means spi_idx) + */ + value = (MSS_SYS_IAP_PROGRAM_BY_SPIIDX_CMD << 16) | BIT(23) | 0x1; + scb_write(cfg->base, SERVICES_CR_OFFSET, value); + + /* REQ bit will remain set till the system controller starts + * processing command. Since DRI is slow interface, we are waiting + * here to make sure System controller has started processing + * command + */ + while (scb_read(cfg->base, SERVICES_CR_OFFSET) & SCBCTRL_SERVICESCR_REQ_MASK) { + ; + } + + /* Once system controller starts processing command The busy bit will + * go 1. Make sure that service is complete i.e. BUSY bit is gone 0 + */ + while (scb_read(cfg->base, SERVICES_SR_OFFSET) & SCBCTRL_SERVICESSR_BUSY_MASK) { + ; + } + + /* Read the status returned by System Controller */ + status = ((scb_read(cfg->base, SERVICES_SR_OFFSET) & SCBCTRL_SERVICESSR_STATUS_MASK) >> + SCBCTRL_SERVICESSR_STATUS); + LOG_INF("Image activation status : %x ", status); +} + +static int mpfs_fpga_reset(const struct device *dev) +{ + int8_t status = EINVAL; + + status = verify_image(dev); + if (status == 0) { + activate_image(dev); + } + return 0; +} + +static int mpfs_fpga_load(const struct device *dev, uint32_t *image_ptr, uint32_t img_size) +{ + const struct device *flash_dev = DEVICE_DT_GET_OR_NULL(DT_ALIAS(bitstream_flash)); + + if (flash_dev == NULL) { + LOG_ERR("Device not found"); + return -ENOENT; + } + + if (!device_is_ready(flash_dev)) { + LOG_ERR("%s: device not ready.", flash_dev->name); + return 1; + } + + if (img_size == 0) { + LOG_ERR("Image size is zero."); + return -EINVAL; + } + + if (image_ptr == NULL) { + LOG_ERR("Failed to read FPGA image"); + return -EINVAL; + } + + update_spi_flash_directory(flash_dev); + program_new_image(flash_dev, (uint8_t *)image_ptr, img_size); + return 0; +} + +static const char *mpfs_fpga_get_info(const struct device *dev) +{ + struct mpfs_fpga_data *data = dev->data; + const struct mpfs_fpga_config *cfg = dev->config; + uint32_t value = 0; + uint16_t design_version = 0; + + /* Once system controller starts processing command The busy bit will + * go 1. Make sure that service is complete i.e. BUSY bit is gone 0 + */ + while (scb_read(cfg->base, SERVICES_SR_OFFSET) & SCBCTRL_SERVICESSR_BUSY_MASK) { + ; + } + + /* Form the SS command: bit 0 to 6 is the opcode, bit 7 to 15 is the Mailbox + * offset For some services this field has another meaning. + * (e.g. for IAP bit-stream auth. it means spi_idx) + */ + + value = (MSS_DESIGN_INFO_CMD << 16) | 0x1; + scb_write(cfg->base, SERVICES_CR_OFFSET, value); + + /* REQ bit will remain set till the system controller starts + * processing command. Since DRI is slow interface, we are waiting + * here to make sure System controller has started processing + * command + */ + while (scb_read(cfg->base, SERVICES_CR_OFFSET) & SCBCTRL_SERVICESCR_REQ_MASK) { + ; + } + + /* Once system controller starts processing command The busy bit will + * go 1. Make sure that service is complete i.e. BUSY bit is gone 0 + */ + while (scb_read(cfg->base, SERVICES_SR_OFFSET) & SCBCTRL_SERVICESSR_BUSY_MASK) { + ; + } + + design_version = scb_read(cfg->mailbox, 32); + sprintf(data->FPGA_design_ver, (uint8_t *)"Design Version : 0x%x", design_version); + + return data->FPGA_design_ver; +} + +static enum FPGA_status mpfs_fpga_get_status(const struct device *dev) +{ + const struct mpfs_fpga_config *cfg = dev->config; + + if (scb_read(cfg->base, SERVICES_SR_OFFSET) & SCBCTRL_SERVICESSR_BUSY_MASK) { + return FPGA_STATUS_INACTIVE; + } else { + return FPGA_STATUS_ACTIVE; + } +} + +static int mpfs_fpga_init(const struct device *dev) +{ + return 0; +} + +static struct mpfs_fpga_data fpga_data; + +static struct mpfs_fpga_config fpga_config = { + .base = DT_INST_REG_ADDR_BY_IDX(0, 0), + .mailbox = DT_INST_REG_ADDR_BY_IDX(0, 2), +}; + +static const struct fpga_driver_api mpfs_fpga_api = { + .reset = mpfs_fpga_reset, + .load = mpfs_fpga_load, + .get_info = mpfs_fpga_get_info, + .get_status = mpfs_fpga_get_status, +}; + +DEVICE_DT_INST_DEFINE(0, &mpfs_fpga_init, NULL, &fpga_data, &fpga_config, POST_KERNEL, + CONFIG_KERNEL_INIT_PRIORITY_DEVICE, &mpfs_fpga_api); From 15b49753864b086f755de19ae4b6feb813a4a30c Mon Sep 17 00:00:00 2001 From: Harshit Agarwal Date: Thu, 11 Jan 2024 04:29:47 +0530 Subject: [PATCH 3266/3723] boards: riscv: mpfs_icicle: enable system-controller spi flash Microchip's PolarFire SoC interface with on-board spi nor flash via system controller. This on-board spi nor flash can be used to store FPGA design bitstream's. Signed-off-by: Harshit Agarwal --- boards/riscv/mpfs_icicle/mpfs_icicle.dts | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/boards/riscv/mpfs_icicle/mpfs_icicle.dts b/boards/riscv/mpfs_icicle/mpfs_icicle.dts index 3eb8077f902..902180c0a14 100644 --- a/boards/riscv/mpfs_icicle/mpfs_icicle.dts +++ b/boards/riscv/mpfs_icicle/mpfs_icicle.dts @@ -65,6 +65,15 @@ status = "okay"; }; +&syscontroller_qspi { + status = "okay"; + sys_ctrl_flash: spi-nor-flash@0 { + compatible = "jedec,spi-nor"; + reg = <0>; + spi-max-frequency = <5000000>; + }; +}; + &gpio2 { status = "okay"; }; From 9cd0ad0ae47879d00d0d028860a1f0646500c832 Mon Sep 17 00:00:00 2001 From: Arkadiusz Cholewinski Date: Thu, 1 Feb 2024 10:19:17 +0100 Subject: [PATCH 3267/3723] ci: codecov: stick with gcovr 6.0 for now gcovr 7.0 has some incompatible format, stick with 6.0 for now. Signed-off-by: Arkadiusz Cholewinski --- .github/workflows/codecov.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/codecov.yaml b/.github/workflows/codecov.yaml index 230fa28efae..832f9873a5e 100644 --- a/.github/workflows/codecov.yaml +++ b/.github/workflows/codecov.yaml @@ -160,7 +160,7 @@ jobs: - name: Merge coverage files run: | cd ./coverage/reports - pip3 install gcovr + pip3 install gcovr==6.0 gcovr ${{ steps.get-coverage-files.outputs.mergefiles }} --merge-mode-functions=separate --json merged.json gcovr ${{ steps.get-coverage-files.outputs.mergefiles }} --merge-mode-functions=separate --cobertura merged.xml From b77df76e98ed7e2189ccb5395c5c05dd53a87c7e Mon Sep 17 00:00:00 2001 From: Lars Knudsen Date: Mon, 29 Jan 2024 14:21:12 +0100 Subject: [PATCH 3268/3723] samples: Add Broadcast Assistant sample First version of Broadcast Assistant sample with hard coded selection of sink and source. Signed-off-by: Lars Knudsen --- .../broadcast_audio_assistant/CMakeLists.txt | 11 + .../broadcast_audio_assistant/Kconfig | 24 + .../broadcast_audio_assistant/README.rst | 56 ++ .../broadcast_audio_assistant/prj.conf | 18 + .../broadcast_audio_assistant/sample.yaml | 11 + .../broadcast_audio_assistant/src/main.c | 520 ++++++++++++++++++ 6 files changed, 640 insertions(+) create mode 100644 samples/bluetooth/broadcast_audio_assistant/CMakeLists.txt create mode 100644 samples/bluetooth/broadcast_audio_assistant/Kconfig create mode 100644 samples/bluetooth/broadcast_audio_assistant/README.rst create mode 100644 samples/bluetooth/broadcast_audio_assistant/prj.conf create mode 100644 samples/bluetooth/broadcast_audio_assistant/sample.yaml create mode 100644 samples/bluetooth/broadcast_audio_assistant/src/main.c diff --git a/samples/bluetooth/broadcast_audio_assistant/CMakeLists.txt b/samples/bluetooth/broadcast_audio_assistant/CMakeLists.txt new file mode 100644 index 00000000000..770ad7912f3 --- /dev/null +++ b/samples/bluetooth/broadcast_audio_assistant/CMakeLists.txt @@ -0,0 +1,11 @@ +# SPDX-License-Identifier: Apache-2.0 + +cmake_minimum_required(VERSION 3.20.0) +find_package(Zephyr REQUIRED HINTS $ENV{ZEPHYR_BASE}) +project(broadcast_audio_assistant) + +target_sources(app PRIVATE + src/main.c +) + +zephyr_library_include_directories(${ZEPHYR_BASE}/samples/bluetooth) diff --git a/samples/bluetooth/broadcast_audio_assistant/Kconfig b/samples/bluetooth/broadcast_audio_assistant/Kconfig new file mode 100644 index 00000000000..9e01743a101 --- /dev/null +++ b/samples/bluetooth/broadcast_audio_assistant/Kconfig @@ -0,0 +1,24 @@ +# Copyright (c) 2024 Demant A/S +# SPDX-License-Identifier: Apache-2.0 + +mainmenu "Bluetooth: Broadcast Audio Assistant" + +config SELECT_SOURCE_NAME + string "Selected Broadcast Source name" + default "" + help + Name of broadcast source device to select. This will be used as a + substring matched against both BT device name and broadcast name. + If empty, the first broadcast source found will be chosen. + Matching is not case sensitive. + +config SELECT_SINK_NAME + string "Selected Broadcast Sink name" + default "" + help + Name of broadcast sink device to select. This will be used as a + substring matched against the BT device name. + If empty, the first broadcast sink found will be chosen. + Matching is not case sensitive. + +source "Kconfig.zephyr" diff --git a/samples/bluetooth/broadcast_audio_assistant/README.rst b/samples/bluetooth/broadcast_audio_assistant/README.rst new file mode 100644 index 00000000000..faff37a6e22 --- /dev/null +++ b/samples/bluetooth/broadcast_audio_assistant/README.rst @@ -0,0 +1,56 @@ +.. zephyr:code-sample:: bluetooth_broadcast_audio_assistant + :name: Bluetooth: Broadcast Audio Assistant + :relevant-api: bt_bap + + Use LE Audio Broadcast Assistant functionality + +Overview +******** + +Application demonstrating the LE Audio broadcast assistant functionality. + +The sample will automatically try to connect to a device in the BAP Scan Delegator +role (advertising support for the Broadcast Audio Scan Service (BASS)). +It will then search for a broadcast source and (if found) add the broadcast ID to +the BAP Scan Delegator. + +Practical use of this sample requires a sink (e.g. the Broadcast Audio Sink sample or +a set of LE Audio Broadcast capable earbuds) and a source (e.g. the Broadcast Audio +Source sample). + +This sample can be found under +:zephyr_file:`samples/bluetooth/broadcast_audio_assistant` in the Zephyr tree. + +Check the :ref:`bluetooth samples section ` for general information. + +Requirements +************ + +* BlueZ running on the host, or +* A board with Bluetooth Low Energy 5.2 support +* Broadcast Audio Source and Sink devices + +Building and Running +******************** + +The application will act as a broadcast assistant with optionally preconfigured +filtering of broadcast sink and broadcast source names. By default, the application will +search for and connect to the first broadcast audio sink found (advertising PACS and +BASS UUIDs) and then search for and select the first broadcast audio source found +(advertising a broadcast ID). + +Filter these by modifying the following configs: + +``CONFIG_SELECT_SINK_NAME``: Substring of BT name of the sink. + +and + +``CONFIG_SELECT_SOURCE_NAME``: Substring of BT name or broadcast name of the source. + +Building for an nrf52840dk +-------------------------- + +.. zephyr-app-commands:: + :zephyr-app: samples/bluetooth/broadcast_audio_assistant/ + :board: nrf52840dk_nrf52840 + :goals: build diff --git a/samples/bluetooth/broadcast_audio_assistant/prj.conf b/samples/bluetooth/broadcast_audio_assistant/prj.conf new file mode 100644 index 00000000000..df902e7917d --- /dev/null +++ b/samples/bluetooth/broadcast_audio_assistant/prj.conf @@ -0,0 +1,18 @@ +CONFIG_BT=y +CONFIG_LOG=y +CONFIG_BT_CENTRAL=y +CONFIG_BT_AUDIO=y +CONFIG_BT_SMP=y +CONFIG_BT_BONDABLE=n +CONFIG_BT_BUF_ACL_RX_SIZE=255 +CONFIG_BT_BUF_ACL_TX_SIZE=251 +CONFIG_BT_CTLR_SCAN_DATA_LEN_MAX=191 + +CONFIG_BT_TINYCRYPT_ECC=y + +CONFIG_BT_EXT_ADV=y +CONFIG_BT_BAP_BROADCAST_ASSISTANT=y + +# CONFIG_BT_BAP_SCAN_DELEGATOR=y is required until the following +# bug is fixed: https://github.com/zephyrproject-rtos/zephyr/issues/68338 +CONFIG_BT_BAP_SCAN_DELEGATOR=y diff --git a/samples/bluetooth/broadcast_audio_assistant/sample.yaml b/samples/bluetooth/broadcast_audio_assistant/sample.yaml new file mode 100644 index 00000000000..8481ebeeeb4 --- /dev/null +++ b/samples/bluetooth/broadcast_audio_assistant/sample.yaml @@ -0,0 +1,11 @@ +sample: + description: Bluetooth Low Energy Broadcast Assistant sample + name: Bluetooth Low Energy Broadcast Assistant sample +tests: + sample.bluetooth.broadcast_audio_assistant: + harness: bluetooth + platform_allow: + - nrf52840dk_nrf52840 + integration_platforms: + - nrf52840dk_nrf52840 + tags: bluetooth diff --git a/samples/bluetooth/broadcast_audio_assistant/src/main.c b/samples/bluetooth/broadcast_audio_assistant/src/main.c new file mode 100644 index 00000000000..1712255c3f3 --- /dev/null +++ b/samples/bluetooth/broadcast_audio_assistant/src/main.c @@ -0,0 +1,520 @@ +/* + * Copyright (c) 2024 Demant A/S + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include + +#define NAME_LEN 30 + +/* Broadcast IDs are 24bit, so this is out of valid range */ +#define INVALID_BROADCAST_ID 0xFFFFFFFFU + +static void scan_for_broadcast_sink(void); + +/* Struct to collect information from scanning + * for Broadcast Source or Sink + */ +struct scan_recv_info { + char bt_name[NAME_LEN]; + char broadcast_name[NAME_LEN]; + uint32_t broadcast_id; + bool has_bass; + bool has_pacs; +}; + +static struct bt_conn *broadcast_sink_conn; +static uint32_t selected_broadcast_id; +static uint8_t selected_sid; +static uint16_t selected_pa_interval; +static bt_addr_le_t selected_addr; + +static bool scanning_for_broadcast_source; + +static K_SEM_DEFINE(sem_source_discovered, 0, 1); +static K_SEM_DEFINE(sem_sink_discovered, 0, 1); +static K_SEM_DEFINE(sem_sink_connected, 0, 1); +static K_SEM_DEFINE(sem_sink_disconnected, 0, 1); +static K_SEM_DEFINE(sem_security_updated, 0, 1); +static K_SEM_DEFINE(sem_bass_discovered, 0, 1); + +static bool device_found(struct bt_data *data, void *user_data) +{ + struct scan_recv_info *sr_info = (struct scan_recv_info *)user_data; + struct bt_uuid_16 adv_uuid; + + switch (data->type) { + case BT_DATA_NAME_SHORTENED: + case BT_DATA_NAME_COMPLETE: + memcpy(sr_info->bt_name, data->data, MIN(data->data_len, NAME_LEN - 1)); + return true; + case BT_DATA_BROADCAST_NAME: + memcpy(sr_info->broadcast_name, data->data, MIN(data->data_len, NAME_LEN - 1)); + return true; + case BT_DATA_SVC_DATA16: + /* Check for Broadcast ID */ + if (data->data_len < BT_UUID_SIZE_16 + BT_AUDIO_BROADCAST_ID_SIZE) { + return true; + } + + if (!bt_uuid_create(&adv_uuid.uuid, data->data, BT_UUID_SIZE_16)) { + return true; + } + + if (bt_uuid_cmp(&adv_uuid.uuid, BT_UUID_BROADCAST_AUDIO) != 0) { + return true; + } + + sr_info->broadcast_id = sys_get_le24(data->data + BT_UUID_SIZE_16); + return true; + case BT_DATA_UUID16_SOME: + case BT_DATA_UUID16_ALL: + /* NOTE: According to the BAP 1.0.1 Spec, + * Section 3.9.2. Additional Broadcast Audio Scan Service requirements, + * If the Scan Delegator implements a Broadcast Sink, it should also + * advertise a Service Data field containing the Broadcast Audio + * Scan Service (BASS) UUID. + * + * However, it seems that this is not the case with the sinks available + * while developing this sample application. Therefore, we instead, + * search for the existence of BASS and PACS in the list of service UUIDs, + * which does seem to exist in the sinks available. + */ + + /* Check for BASS and PACS */ + if (data->data_len % sizeof(uint16_t) != 0U) { + printk("UUID16 AD malformed\n"); + return true; + } + + for (size_t i = 0; i < data->data_len; i += sizeof(uint16_t)) { + const struct bt_uuid *uuid; + uint16_t u16; + + memcpy(&u16, &data->data[i], sizeof(u16)); + uuid = BT_UUID_DECLARE_16(sys_le16_to_cpu(u16)); + + if (bt_uuid_cmp(uuid, BT_UUID_BASS)) { + sr_info->has_bass = true; + continue; + } + + if (bt_uuid_cmp(uuid, BT_UUID_PACS)) { + sr_info->has_pacs = true; + continue; + } + } + return true; + default: + return true; + } +} + +static bool is_substring(const char *substr, const char *str) +{ + const size_t str_len = strlen(str); + const size_t sub_str_len = strlen(substr); + + if (sub_str_len > str_len) { + return false; + } + + for (size_t pos = 0; pos < str_len; pos++) { + if (pos + sub_str_len > str_len) { + return false; + } + + if (strncasecmp(substr, &str[pos], sub_str_len) == 0) { + return true; + } + } + + return false; +} + +static void scan_recv_cb(const struct bt_le_scan_recv_info *info, + struct net_buf_simple *ad) +{ + int err; + struct scan_recv_info sr_info = {0}; + + if (scanning_for_broadcast_source) { + /* Scan for and select Broadcast Source */ + + sr_info.broadcast_id = INVALID_BROADCAST_ID; + + /* We are only interested in non-connectable periodic advertisers */ + if ((info->adv_props & BT_GAP_ADV_PROP_CONNECTABLE) != 0 || + info->interval == 0) { + return; + } + + bt_data_parse(ad, device_found, (void *)&sr_info); + + if (sr_info.broadcast_id != INVALID_BROADCAST_ID) { + printk("Broadcast Source Found:\n"); + printk(" BT Name: %s\n", sr_info.bt_name); + printk(" Broadcast Name: %s\n", sr_info.broadcast_name); + printk(" Broadcast ID: 0x%06x\n\n", sr_info.broadcast_id); + + if (strlen(CONFIG_SELECT_SOURCE_NAME) > 0U) { + /* Compare names with CONFIG_SELECT_SOURCE_NAME */ + if (is_substring(CONFIG_SELECT_SOURCE_NAME, sr_info.bt_name) || + is_substring(CONFIG_SELECT_SOURCE_NAME, + sr_info.broadcast_name)) { + printk("Match found for '%s'\n", CONFIG_SELECT_SOURCE_NAME); + } else { + printk("'%s' not found in names\n\n", + CONFIG_SELECT_SOURCE_NAME); + return; + } + } + + err = bt_le_scan_stop(); + if (err != 0) { + printk("bt_le_scan_stop failed with %d\n", err); + } + + /* TODO: Add support for syncing to the PA and parsing the BASE + * in order to obtain the right subgroup information to send to + * the sink when adding a broadcast source (see in main function below). + */ + + printk("Selecting Broadcast ID: 0x%06x\n", sr_info.broadcast_id); + + selected_broadcast_id = sr_info.broadcast_id; + selected_sid = info->sid; + selected_pa_interval = info->interval; + bt_addr_le_copy(&selected_addr, info->addr); + + k_sem_give(&sem_source_discovered); + } + } else { + /* Scan for and connect to Broadcast Sink */ + + /* We are only interested in connectable advertisers */ + if ((info->adv_props & BT_GAP_ADV_PROP_CONNECTABLE) == 0) { + return; + } + + bt_data_parse(ad, device_found, (void *)&sr_info); + + if (sr_info.has_bass && sr_info.has_pacs) { + printk("Broadcast Sink Found:\n"); + printk(" BT Name: %s\n", sr_info.bt_name); + + if (strlen(CONFIG_SELECT_SINK_NAME) > 0U) { + /* Compare names with CONFIG_SELECT_SINK_NAME */ + if (is_substring(CONFIG_SELECT_SINK_NAME, sr_info.bt_name)) { + printk("Match found for '%s'\n", CONFIG_SELECT_SINK_NAME); + } else { + printk("'%s' not found in names\n\n", + CONFIG_SELECT_SINK_NAME); + return; + } + } + + err = bt_le_scan_stop(); + if (err != 0) { + printk("bt_le_scan_stop failed with %d\n", err); + } + + printk("Connecting to Broadcast Sink: %s\n", sr_info.bt_name); + + err = bt_conn_le_create(info->addr, BT_CONN_LE_CREATE_CONN, + BT_LE_CONN_PARAM_DEFAULT, + &broadcast_sink_conn); + if (err != 0) { + printk("Failed creating connection (err=%u)\n", err); + scan_for_broadcast_sink(); + } + + k_sem_give(&sem_sink_discovered); + } + } +} + +static void scan_timeout_cb(void) +{ + printk("Scan timeout\n"); +} + +static struct bt_le_scan_cb scan_callbacks = { + .recv = scan_recv_cb, + .timeout = scan_timeout_cb, +}; + +static void scan_for_broadcast_source(void) +{ + int err; + + scanning_for_broadcast_source = true; + + err = bt_le_scan_start(BT_LE_SCAN_PASSIVE, NULL); + if (err) { + printk("Scanning failed to start (err %d)\n", err); + return; + } + + printk("Scanning for Broadcast Source successfully started\n"); + + err = k_sem_take(&sem_source_discovered, K_FOREVER); + if (err != 0) { + printk("Failed to take sem_source_discovered (err %d)\n", err); + } +} + +static void scan_for_broadcast_sink(void) +{ + int err; + + scanning_for_broadcast_source = false; + + err = bt_le_scan_start(BT_LE_SCAN_PASSIVE, NULL); + if (err) { + printk("Scanning failed to start (err %d)\n", err); + return; + } + + printk("Scanning for Broadcast Sink successfully started\n"); + + err = k_sem_take(&sem_sink_discovered, K_FOREVER); + if (err != 0) { + printk("Failed to take sem_sink_discovered (err %d)\n", err); + } +} + +static void connected(struct bt_conn *conn, uint8_t err) +{ + char addr[BT_ADDR_LE_STR_LEN]; + + (void)bt_addr_le_to_str(bt_conn_get_dst(conn), addr, sizeof(addr)); + + if (err != 0) { + printk("Failed to connect to %s (%u)\n", addr, err); + + bt_conn_unref(broadcast_sink_conn); + broadcast_sink_conn = NULL; + + scan_for_broadcast_sink(); + return; + } + + if (conn != broadcast_sink_conn) { + return; + } + + printk("Connected: %s\n", addr); + k_sem_give(&sem_sink_connected); +} + +static void disconnected(struct bt_conn *conn, uint8_t reason) +{ + char addr[BT_ADDR_LE_STR_LEN]; + + if (conn != broadcast_sink_conn) { + return; + } + + (void)bt_addr_le_to_str(bt_conn_get_dst(conn), addr, sizeof(addr)); + + printk("Disconnected: %s (reason 0x%02x)\n", addr, reason); + + bt_conn_unref(broadcast_sink_conn); + broadcast_sink_conn = NULL; + + k_sem_give(&sem_sink_disconnected); +} + +static void security_changed_cb(struct bt_conn *conn, bt_security_t level, + enum bt_security_err err) +{ + if (err == 0) { + printk("Security level changed: %u\n", level); + k_sem_give(&sem_security_updated); + } else { + printk("Failed to set security level: %u\n", err); + } +} + +static void bap_broadcast_assistant_discover_cb(struct bt_conn *conn, int err, + uint8_t recv_state_count) +{ + if (err == 0) { + printk("BASS discover done with %u recv states\n", + recv_state_count); + k_sem_give(&sem_bass_discovered); + } else { + printk("BASS discover failed (%d)\n", err); + } +} + +static void bap_broadcast_assistant_add_src_cb(struct bt_conn *conn, int err) +{ + if (err == 0) { + printk("BASS add source successful\n"); + } else { + printk("BASS add source failed (%d)\n", err); + } +} + +static struct bt_bap_broadcast_assistant_cb ba_cbs = { + .discover = bap_broadcast_assistant_discover_cb, + .add_src = bap_broadcast_assistant_add_src_cb, +}; + +static void reset(void) +{ + printk("\n\nReset...\n\n"); + + broadcast_sink_conn = NULL; + selected_broadcast_id = INVALID_BROADCAST_ID; + selected_sid = 0; + selected_pa_interval = 0; + (void)memset(&selected_addr, 0, sizeof(selected_addr)); + + k_sem_reset(&sem_source_discovered); + k_sem_reset(&sem_sink_discovered); + k_sem_reset(&sem_sink_connected); + k_sem_reset(&sem_sink_disconnected); + k_sem_reset(&sem_security_updated); + k_sem_reset(&sem_bass_discovered); +} + +BT_CONN_CB_DEFINE(conn_callbacks) = { + .connected = connected, + .disconnected = disconnected, + .security_changed = security_changed_cb +}; + +int main(void) +{ + int err; + struct bt_bap_scan_delegator_subgroup subgroup = { 0 }; + struct bt_bap_broadcast_assistant_add_src_param param = { 0 }; + + err = bt_enable(NULL); + if (err) { + printk("Bluetooth init failed (err %d)\n", err); + return 0; + } + + printk("Bluetooth initialized\n"); + + bt_le_scan_cb_register(&scan_callbacks); + bt_bap_broadcast_assistant_register_cb(&ba_cbs); + + while (true) { + scan_for_broadcast_sink(); + + err = k_sem_take(&sem_sink_connected, K_FOREVER); + if (err != 0) { + printk("Failed to take sem_sink_connected (err %d)\n", err); + } + + err = bt_bap_broadcast_assistant_discover(broadcast_sink_conn); + if (err != 0) { + printk("Failed to discover BASS on the sink (err %d)\n", err); + } + + err = k_sem_take(&sem_security_updated, K_SECONDS(10)); + if (err != 0) { + printk("Failed to take sem_security_updated (err %d), resetting\n", err); + bt_conn_disconnect(broadcast_sink_conn, BT_HCI_ERR_AUTH_FAIL); + + if (k_sem_take(&sem_sink_disconnected, K_SECONDS(10)) != 0) { + /* This should not happen */ + return -ETIMEDOUT; + } + + reset(); + continue; + } + + err = k_sem_take(&sem_bass_discovered, K_SECONDS(10)); + if (err != 0) { + if (err == -EAGAIN) { + printk("Failed to take sem_bass_discovered (err %d)\n", err); + } + bt_conn_disconnect(broadcast_sink_conn, BT_HCI_ERR_UNSUPP_REMOTE_FEATURE); + + if (k_sem_take(&sem_sink_disconnected, K_SECONDS(10)) != 0) { + /* This should not happen */ + return -ETIMEDOUT; + } + + reset(); + continue; + } + + /* TODO: Discover and parse the PACS on the sink and use the information + * when discovering and adding a source to the sink. + * Also, before populating the parameters to sync to the broadcast source + * first, parse the source BASE and determine if the sink supports the source. + * If not, then look for another source. + */ + + scan_for_broadcast_source(); + + /* FIX NEEDED: It should be valid to assign BT_BAP_BIS_SYNC_NO_PREF + * to bis_sync, but currently (2024-01-30), the broadcast_audio_sink + * sample seems to reject it (err=19) while other sinks don't. + * + * Also, if the source contains more than one stream (e.g. stereo), + * some sinks have been observed to have issues. In this case, + * set only one bit in bis_sync, e.g. subgroup.bis_sync = BIT(1). + * + * When PA sync and BASE is parsed (see note in the scan_recv_cb function), + * the available bits can be used for proper selection. + */ + subgroup.bis_sync = BT_BAP_BIS_SYNC_NO_PREF; + + bt_addr_le_copy(¶m.addr, &selected_addr); + param.adv_sid = selected_sid; + param.pa_interval = selected_pa_interval; + param.broadcast_id = selected_broadcast_id; + param.pa_sync = true; + + /* TODO: Obtain the and set the correct subgroup information. + * See above in the broadcast audio source discovery part + * of the scan_recv_cb function. + */ + param.num_subgroups = 1; + param.subgroups = &subgroup; + + err = bt_bap_broadcast_assistant_add_src(broadcast_sink_conn, ¶m); + if (err) { + printk("Failed to add source: %d\n", err); + bt_conn_disconnect(broadcast_sink_conn, BT_HCI_ERR_UNSUPP_REMOTE_FEATURE); + + if (k_sem_take(&sem_sink_disconnected, K_SECONDS(10)) != 0) { + /* This should not happen */ + return -ETIMEDOUT; + } + + reset(); + continue; + } + + /* Reset if the sink disconnects */ + err = k_sem_take(&sem_sink_disconnected, K_FOREVER); + if (err != 0) { + printk("Failed to take sem_sink_disconnected (err %d)\n", err); + } + + reset(); + } + + return 0; +} From 6d387b3fd51e25728a0e3eb7da47083719b6fd81 Mon Sep 17 00:00:00 2001 From: Angelo Dureghello Date: Wed, 24 Jan 2024 11:21:32 +0100 Subject: [PATCH 3269/3723] boards: add support for eval-adin1110ebz Add support for ADI EVAL-ADIN1110EBZ. Tested samples: * hello_world * blinky * dhcpv4_client * adt7420 Tested proper SPI detection of the ADIN1110 chip. Co-developed-by: Philip Molloy Signed-off-by: Philip Molloy Signed-off-by: Angelo Dureghello --- boards/arm/adi_eval_adin1110ebz/Kconfig.board | 8 + .../adi_eval_adin1110ebz/Kconfig.defconfig | 33 ++ .../adi_eval_adin1110ebz.dts | 321 ++++++++++++++++++ .../adi_eval_adin1110ebz.yaml | 21 ++ .../adi_eval_adin1110ebz_defconfig | 21 ++ .../arduino_r3_connector.dtsi | 40 +++ boards/arm/adi_eval_adin1110ebz/board.cmake | 6 + .../doc/img/adi_eval_adin1110ebz.webp | Bin 0 -> 71108 bytes boards/arm/adi_eval_adin1110ebz/doc/index.rst | 183 ++++++++++ .../adi_eval_adin1110ebz/pre_dt_board.cmake | 2 + .../adi_eval_adin1110ebz/support/openocd.cfg | 12 + 11 files changed, 647 insertions(+) create mode 100644 boards/arm/adi_eval_adin1110ebz/Kconfig.board create mode 100644 boards/arm/adi_eval_adin1110ebz/Kconfig.defconfig create mode 100644 boards/arm/adi_eval_adin1110ebz/adi_eval_adin1110ebz.dts create mode 100644 boards/arm/adi_eval_adin1110ebz/adi_eval_adin1110ebz.yaml create mode 100644 boards/arm/adi_eval_adin1110ebz/adi_eval_adin1110ebz_defconfig create mode 100644 boards/arm/adi_eval_adin1110ebz/arduino_r3_connector.dtsi create mode 100644 boards/arm/adi_eval_adin1110ebz/board.cmake create mode 100644 boards/arm/adi_eval_adin1110ebz/doc/img/adi_eval_adin1110ebz.webp create mode 100644 boards/arm/adi_eval_adin1110ebz/doc/index.rst create mode 100644 boards/arm/adi_eval_adin1110ebz/pre_dt_board.cmake create mode 100644 boards/arm/adi_eval_adin1110ebz/support/openocd.cfg diff --git a/boards/arm/adi_eval_adin1110ebz/Kconfig.board b/boards/arm/adi_eval_adin1110ebz/Kconfig.board new file mode 100644 index 00000000000..29f1e3b8dbc --- /dev/null +++ b/boards/arm/adi_eval_adin1110ebz/Kconfig.board @@ -0,0 +1,8 @@ +# ADI EVAL-ADIN1110EBZ board configuration + +# Copyright (c) 2024 BayLibre +# SPDX-License-Identifier: Apache-2.0 + +config BOARD_ADI_EVAL_ADIN1110EBZ + bool "ADI EVAL-ADIN1110EBZ evaulation board" + depends on SOC_STM32L4S5XX diff --git a/boards/arm/adi_eval_adin1110ebz/Kconfig.defconfig b/boards/arm/adi_eval_adin1110ebz/Kconfig.defconfig new file mode 100644 index 00000000000..79e309af4cd --- /dev/null +++ b/boards/arm/adi_eval_adin1110ebz/Kconfig.defconfig @@ -0,0 +1,33 @@ +# ADI EVAL-ADIN1110EBZ board configuration + +# Copyright (c) 2024 BayLibre +# SPDX-License-Identifier: Apache-2.0 + +if BOARD_ADI_EVAL_ADIN1110EBZ + +config BOARD + default "adi_eval_adin1110ebz" + +config SPI_STM32_INTERRUPT + default y + depends on SPI + +config MDIO_INIT_PRIORITY + default 81 + depends on MDIO + +config PHY_INIT_PRIORITY + default 82 + depends on NET_L2_ETHERNET && ETH_DRIVER + +config MEMC + default y + +if NETWORKING + +config NET_L2_ETHERNET + default y + +endif # NETWORKING + +endif # BOARD_ADI_EVAL_ADIN1110EBZ diff --git a/boards/arm/adi_eval_adin1110ebz/adi_eval_adin1110ebz.dts b/boards/arm/adi_eval_adin1110ebz/adi_eval_adin1110ebz.dts new file mode 100644 index 00000000000..d87eefa0619 --- /dev/null +++ b/boards/arm/adi_eval_adin1110ebz/adi_eval_adin1110ebz.dts @@ -0,0 +1,321 @@ +/* + * Copyright (c) 2024 BayLibre + * + * SPDX-License-Identifier: Apache-2.0 + */ + +/dts-v1/; + +#include +#include +#include "arduino_r3_connector.dtsi" +#include + +/ { + model = "Analog Devices Inc. EVAL-ADIN1110EBZ board"; + compatible = "adi,eval-adin1110ebz"; + + chosen { + zephyr,console = &usart1; + zephyr,shell-uart = &usart1; + zephyr,sram = &sram0; + zephyr,flash = &flash0; + zephyr,code-partition = &slot0_partition; + zephyr,flash-controller = &mx25r6435f; + }; + + ram0: psram@60000000 { + compatible = "zephyr,memory-region", "mmio-sram"; + device_type = "memory"; + reg = <0x60000000 DT_SIZE_M(8)>; + zephyr,memory-region = "RAM0"; + }; + + leds { /* Respecting pcb silkscreen naming */ + compatible = "gpio-leds"; + green_led: led_uC0 { + gpios = <&gpioc 13 GPIO_ACTIVE_HIGH>; + label = "Status uC0"; + }; + red_led: led_uC1 { + gpios = <&gpioe 2 GPIO_ACTIVE_HIGH>; + label = "Status uC1 "; + }; + yellow_led: led_uC2 { + gpios = <&gpioe 6 GPIO_ACTIVE_HIGH>; + label = "Status uC2"; + }; + blue_led: led_uC3 { + gpios = <&gpiog 15 GPIO_ACTIVE_HIGH>; + label = "Status uC3"; + }; + }; + + aliases { + led0 = &green_led; + watchdog0 = &iwdg; + spi-flash0 = &mx25r6435f; + }; + + soc { + fmc: memory-controller@a0000000 { + compatible = "st,stm32-fmc"; + reg = <0xa0000000 0x400>; + clocks = <&rcc STM32_CLOCK_BUS_AHB3 0x00000001>; + + sram { + compatible = "st,stm32-fmc-nor-psram"; + + #address-cells = <1>; + #size-cells = <0>; + }; + }; + }; +}; + +&clk_lsi { + status = "okay"; +}; + +&clk_hsi48 { + status = "okay"; +}; + +&clk_hsi { + status = "okay"; +}; + +&pll { + div-m = <4>; + mul-n = <40>; + div-q = <2>; + div-r = <2>; + clocks = <&clk_hsi>; + status = "okay"; +}; + +&rcc { + clocks = <&pll>; + clock-frequency = ; + ahb-prescaler = <1>; + apb1-prescaler = <1>; + apb2-prescaler = <1>; +}; + +&flash0 { + partitions { + compatible = "fixed-partitions"; + #address-cells = <1>; + #size-cells = <1>; + + boot_partition: partition@0 { + label = "mcuboot"; + reg = <0x00000000 DT_SIZE_K(64)>; + read-only; + }; + + /* + * The flash starting at offset 0x10000 and ending at + * offset 0x1ffff is reserved for use by the application. + */ + + slot0_partition: partition@20000 { + label = "image-0"; + reg = <0x00020000 DT_SIZE_K(432)>; + }; + slot1_partition: partition@8c000 { + label = "image-1"; + reg = <0x0008C000 DT_SIZE_K(432)>; + }; + scratch_partition: partition@f8000 { + label = "image-scratch"; + reg = <0x000F8000 DT_SIZE_K(16)>; + }; + + storage_partition: partition@fc000 { + label = "storage"; + reg = <0x000fc000 DT_SIZE_K(16)>; + }; + }; +}; + +&iwdg { + status = "okay"; +}; + +&rng { + status = "okay"; +}; + +&dma1 { + status = "okay"; +}; + +&dmamux1 { + status = "okay"; +}; + +&usart1 { /* USB FT232 */ + pinctrl-0 = <&usart1_tx_pa9 &usart1_rx_pa10>; + pinctrl-names = "default"; + current-speed = <115200>; + status = "okay"; +}; + +&uart4 { /* ARDUINO P405 1 & 2 */ + pinctrl-0 = <&uart4_tx_pa0 &uart4_rx_pa1>; + pinctrl-names = "default"; + current-speed = <115200>; +}; + +&i2c1 { + pinctrl-0 = <&i2c1_scl_pg14 &i2c1_sda_pg13>; + pinctrl-names = "default"; + status = "okay"; + clock-frequency = ; +}; + +&i2c3 { + pinctrl-0 = <&i2c3_scl_pg7 &i2c3_sda_pg8>; + pinctrl-names = "default"; + status = "okay"; + clock-frequency = ; + + adt7420@48 { + compatible = "adi,adt7420"; + reg = <0x48>; + }; +}; + +&spi1 { + pinctrl-0 = <&spi1_sck_pa5 &spi1_miso_pa6 &spi1_mosi_pa7>; + pinctrl-names = "default"; + cs-gpios = <&gpioa 2 (GPIO_ACTIVE_LOW | GPIO_PULL_UP)>; +}; + +&spi2 { + pinctrl-0 = <&spi2_sck_pb13 &spi2_miso_pb14 &spi2_mosi_pb15>; + pinctrl-names = "default"; + cs-gpios = <&gpiob 12 (GPIO_ACTIVE_LOW | GPIO_PULL_UP)>; + status = "okay"; + + adin1110: adin1110@0 { + compatible = "adi,adin1110"; + reg = <0x0>; + spi-max-frequency = <25000000>; + int-gpios = <&gpiob 11 GPIO_ACTIVE_LOW>; + reset-gpios = <&gpioc 7 GPIO_ACTIVE_LOW>; + + port1 { + local-mac-address = [ 00 E0 22 FE DA C8 ]; + }; + mdio { + compatible = "adi,adin2111-mdio"; + #address-cells = <1>; + #size-cells = <0>; + + ethernet-phy@1 { + reg = <0x1>; + compatible = "adi,adin2111-phy"; + }; + }; + }; +}; + +&spi3 { + pinctrl-0 = <&spi3_sck_pc10 &spi3_miso_pc11 &spi3_mosi_pc12>; + pinctrl-names = "default"; + status = "okay"; +}; + +&timers2 { + status = "okay"; + + pwm2: pwm { + status = "okay"; + pinctrl-0 = <&tim2_ch1_pa15>; + pinctrl-names = "default"; + }; +}; + +&rtc { + clocks = <&rcc STM32_CLOCK_BUS_APB1 0x10000000>, + <&rcc STM32_SRC_LSI RTC_SEL(2)>; + status = "okay"; +}; + +zephyr_udc0: &usbotg_fs { + pinctrl-0 = <&usb_otg_fs_dm_pa11 &usb_otg_fs_dp_pa12 + &usb_otg_fs_id_pa10>; + pinctrl-names = "default"; + status = "okay"; +}; + +&octospi1 { + pinctrl-0 = <&octospim_p1_clk_pa3 &octospim_p1_ncs_pa4 + &octospim_p1_io0_pb1 &octospim_p1_io1_pb0 + &octospim_p1_io2_pa7 &octospim_p1_io3_pa6>; + pinctrl-names = "default"; + dmas = <&dma1 0 40 0x480>; /* request 40 for OCTOSPI1 */ + dma-names = "tx_rx"; + + status = "okay"; + + mx25r6435f: ospi-nor-flash@0 { + compatible = "st,stm32-ospi-nor"; + reg = <0>; + ospi-max-frequency = ; /* for Voltage Range 2 */ + size = ; /* 64 Megabits */ + spi-bus-width = ; + data-rate = ; + writeoc="PP_1_4_4"; + + partitions { + compatible = "fixed-partitions"; + #address-cells = <1>; + #size-cells = <1>; + + store_partition: partition@0 { + label = "store"; + reg = <0x00000000 DT_SIZE_M(8)>; + }; + }; + }; +}; + +&fmc { + pinctrl-0 = <&fmc_nbl0_pe0 &fmc_nbl1_pe1 + &fmc_nce_pd7 &fmc_nwe_pd5 &fmc_noe_pd4 + &fmc_a0_pf0 &fmc_a1_pf1 &fmc_a2_pf2 &fmc_a3_pf3 + &fmc_a4_pf4 &fmc_a5_pf5 &fmc_a6_pf12 &fmc_a7_pf13 + &fmc_a8_pf14 &fmc_a9_pf15 &fmc_a10_pg0 &fmc_a11_pg1 + &fmc_a12_pg2 &fmc_a13_pg3 &fmc_a14_pg4 &fmc_a15_pg5 + &fmc_a16_pd11 &fmc_a17_pd12 &fmc_a18_pd13 &fmc_a19_pe3 + &fmc_a20_pe4 &fmc_a21_pe5 + &fmc_d0_pd14 &fmc_d1_pd15 &fmc_d2_pd0 &fmc_d3_pd1 + &fmc_d4_pe7 &fmc_d5_pe8 &fmc_d6_pe9 &fmc_d7_pe10 + &fmc_d8_pe11 &fmc_d9_pe12 &fmc_d10_pe13 &fmc_d11_pe14 + &fmc_d12_pe15 &fmc_d13_pd8 &fmc_d14_pd9 &fmc_d15_pd10>; + pinctrl-names = "default"; + + sram { + bank@0 { + reg = <0x0>; + st,control = ; + st,timing = <4 2 3 0 16 17 STM32_FMC_ACCESS_MODE_A>; + }; + }; +}; diff --git a/boards/arm/adi_eval_adin1110ebz/adi_eval_adin1110ebz.yaml b/boards/arm/adi_eval_adin1110ebz/adi_eval_adin1110ebz.yaml new file mode 100644 index 00000000000..c7e9a79567a --- /dev/null +++ b/boards/arm/adi_eval_adin1110ebz/adi_eval_adin1110ebz.yaml @@ -0,0 +1,21 @@ +identifier: adi_eval_adin1110ebz +name: ADI EVAL-ADIN1110EBZ evaulation board +type: mcu +arch: arm +toolchain: + - zephyr + - gnuarmemb + - xtools +ram: 640 +flash: 2048 +supported: + - arduino_gpio + - arduino_i2c + - arduino_spi + - gpio + - i2c + - spi + - watchdog + - memc + - octospi +vendor: adi diff --git a/boards/arm/adi_eval_adin1110ebz/adi_eval_adin1110ebz_defconfig b/boards/arm/adi_eval_adin1110ebz/adi_eval_adin1110ebz_defconfig new file mode 100644 index 00000000000..15174238c66 --- /dev/null +++ b/boards/arm/adi_eval_adin1110ebz/adi_eval_adin1110ebz_defconfig @@ -0,0 +1,21 @@ +# SPDX-License-Identifier: Apache-2.0 + +CONFIG_BOARD_ADI_EVAL_ADIN1110EBZ=y +CONFIG_SOC_SERIES_STM32L4X=y +CONFIG_SOC_STM32L4S5XX=y + +# enable uart driver +CONFIG_SERIAL=y + +# console +CONFIG_CONSOLE=y +CONFIG_UART_CONSOLE=y + +# enable GPIO +CONFIG_GPIO=y + +# Enable Clocks +CONFIG_CLOCK_CONTROL=y + +# enable pin controller +CONFIG_PINCTRL=y diff --git a/boards/arm/adi_eval_adin1110ebz/arduino_r3_connector.dtsi b/boards/arm/adi_eval_adin1110ebz/arduino_r3_connector.dtsi new file mode 100644 index 00000000000..ffea9d90e48 --- /dev/null +++ b/boards/arm/adi_eval_adin1110ebz/arduino_r3_connector.dtsi @@ -0,0 +1,40 @@ +/* + * Copyright (c) 2024 BayLibre + * + * SPDX-License-Identifier: Apache-2.0 + */ + +/ { + arduino_header: connector { + compatible = "arduino-header-r3"; + #gpio-cells = <2>; + gpio-map-mask = <0xffffffff 0xffffffc0>; + gpio-map-pass-thru = <0 0x3f>; + gpio-map = <0 0 &gpioc 0 0>, /* A0/D14 */ + <1 0 &gpioc 1 0>, /* A1/D15 */ + <2 0 &gpioc 2 0>, /* A2/D16 */ + <3 0 &gpioc 3 0>, /* A3/D17 */ + <4 0 &gpioc 4 0>, /* A4/D18 */ + <5 0 &gpioc 5 0>, /* A5/D19 */ + <6 0 &gpioa 0 0>, /* D0 */ + <7 0 &gpioa 1 0>, /* D1 */ + <8 0 &gpioa 2 0>, /* D2 */ + <9 0 &gpiod 2 0>, /* D3 */ + <10 0 &gpiod 6 0>, /* D4 */ + <11 0 &gpiob 7 0>, /* D5 */ + <12 0 &gpiob 8 0>, /* D6 */ + <13 0 &gpiob 9 0>, /* D7 */ + <14 0 &gpiob 6 0>, /* D8 */ + <15 0 &gpiob 5 0>, /* D9 */ + <16 0 &gpiog 12 0>, /* D10 */ + <17 0 &gpioc 12 0>, /* D11 */ + <18 0 &gpioc 11 0>, /* D12 */ + <19 0 &gpioc 10 0>, /* D13 */ + <20 0 &gpioc 0 0>, /* D14 */ + <21 0 &gpioc 1 0>; /* D15 */ + }; +}; + +arduino_i2c: &i2c1 {}; +arduino_spi: &spi3 {}; +arduino_serial: &uart4 {}; diff --git a/boards/arm/adi_eval_adin1110ebz/board.cmake b/boards/arm/adi_eval_adin1110ebz/board.cmake new file mode 100644 index 00000000000..4e81b2fb988 --- /dev/null +++ b/boards/arm/adi_eval_adin1110ebz/board.cmake @@ -0,0 +1,6 @@ +# SPDX-License-Identifier: Apache-2.0 + +board_runner_args(jlink "--device=STM32L4S5QI" "--speed=4000") + +include(${ZEPHYR_BASE}/boards/common/openocd.board.cmake) +include(${ZEPHYR_BASE}/boards/common/jlink.board.cmake) diff --git a/boards/arm/adi_eval_adin1110ebz/doc/img/adi_eval_adin1110ebz.webp b/boards/arm/adi_eval_adin1110ebz/doc/img/adi_eval_adin1110ebz.webp new file mode 100644 index 0000000000000000000000000000000000000000..e999019268deb9b97ac0ffab3d4d275003c240f6 GIT binary patch literal 71108 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 literal 0 HcmV?d00001 diff --git a/boards/arm/adi_eval_adin1110ebz/doc/index.rst b/boards/arm/adi_eval_adin1110ebz/doc/index.rst new file mode 100644 index 00000000000..3bcc3167596 --- /dev/null +++ b/boards/arm/adi_eval_adin1110ebz/doc/index.rst @@ -0,0 +1,183 @@ +.. _adi_eval_adin1110ebz: + +ADI EVAL-ADIN1110EVB Evaluation board +##################################### + +Overview +******** + +The EVAL-ADIN1110EBZ is a flexible platform enabling quick evaluation of the ADIN1110, robust, +low power 10BASE-T1L MAC-PHY. It provides 10Mbit per second Single Pair Ethernet (SPE) connections +with devices across 1.7km of cable. + +The evaluation board offers two modes of operation for maximum flexibility. Connected to a PC +via USB port, the full set of ADIN1110 register settings and features such as link quality +monitoring and diagnostics can be accessed over the USB using serial command interface. +The board also provides an Arduino interface. + +Alternatively, the board can operate in stand-alone mode where it is configured by setting hardware +configuration links and switches. On-board LEDs provide status indication. + +The SPI interface provides configuration and data access to the ADIN1110. + +A small prototyping area and test points are provided for experimentation with alternative cable +connection topologies including isolation transformers and/or power coupling inductors. + +.. figure:: img/adi_eval_adin1110ebz.webp + :align: center + :alt: ADI EVAL-ADIN1110EBZ + + ADI EVAL-ADIN1110EBZ (Credit: Analog Devices, Inc.) + +.. important:: + + S201 DIP switches are shipped in Open Alliance SPI mode. The current Zephyr + default board configuration is set to work as "Generic SPI, CRC enabled", + so the S201 DIP switches must be set as ``SPI_CFG0 OFF`` and ``SPI_CFG1 ON``. + An inconsistent S201 DIP switches configuration will halt the boot. + +Hardware +******** + +The ADI EVAL-ADIN1110EBZ hardware features list is available here: + +https://wiki.analog.com/resources/eval/user-guides/eval-adin1110ebz-user-guide + + +Supported Features +================== + +The ADI adi_eval_adin1110ebz board configuration supports the +following hardware features: + ++--------------+------------+-------------------------------------+ +| Interface | Controller | Driver/Component | ++==============+============+=====================================+ +| NVIC | on-chip | nested vector interrupt controller | ++--------------+------------+-------------------------------------+ +| UART | on-chip | serial port-polling; | +| | | serial port-interrupt | ++--------------+------------+-------------------------------------+ +| PINMUX | on-chip | pinmux | ++--------------+------------+-------------------------------------+ +| GPIO | on-chip | gpio | ++--------------+------------+-------------------------------------+ +| I2C | on-chip | i2c | ++--------------+------------+-------------------------------------+ +| SPI | on-chip | spi | ++--------------+------------+-------------------------------------+ +| PWM | on-chip | pwm | ++--------------+------------+-------------------------------------+ +| WATCHDOG | on-chip | independent watchdog | ++--------------+------------+-------------------------------------+ +| ADIN1110 | spi | adin1110 10BASE-T1L mac/phy | ++--------------+------------+-------------------------------------+ +| FT232 | uart | usb-uart | ++--------------+------------+-------------------------------------+ +| ADT7422 | i2c | temperature sensor | ++--------------+------------+-------------------------------------+ +| ISS66WVE4M16 | fmc | 8MB PSRAM | ++--------------+------------+-------------------------------------+ + + +The default configuration can be found in the defconfig file: + + ``boards/arm/adi_eval_adin1110ebz/adi_eval_adin1110ebz_defconfig`` + + +Connections and IOs +=================== + +ADI ADIN1110EBZ evaluation board has 7 GPIO controllers (from A to G). These controllers are +responsible for pin muxing, input/output, pull-up, etc. + +For mode details please refer to `EVAL-ADIN1110EBZ User Guide `_. + +Default Zephyr Peripheral Mapping: +---------------------------------- + +- UART_1 TX/RX : PA9/PA10 (UART to FT232) +- UART_4 TX/RX : PA0/PA1 (Arduino Serial) +- I2C1 SCL/SDA : PG14/PG13 (Arduino I2C) +- I2C3 SCL/SDA : PG7/PG8 (Sensor I2C bus) +- SPI1 SCK/MISO/MOSI : PA5/PA6/PA7 (Simple SPI to nor Flash) +- SPI2 SCK/MISO/MOSI : PB13/PB14/PB15 (ADIN1110) +- SPI3 SCK/MISO/MOSI : PC10/PC11/PC12 (Arduino SPI) +- LD1 : PC13 (Green LED) +- LD2 : PE2 (Red LED) +- LD3 : PE6 (Yellow LED) +- LD4 : PG15 (Blue LED) +- PSRAM : PE0/PE1/PF0-PF15/PG0-PG5/PD11-PD13/PE3/PE4 + PD14/PD15/PD9/PD1/PE7-PE15/PD8-PD10 + + +System Clock +------------ + +EVAL-ADIN1110EBZ System Clock could be driven by an internal or external oscillator, as well as +the main PLL clock. By default the System clock is driven by the PLL clock at 80MHz, driven by the +16MHz high speed internal oscillator. + +Serial Port +----------- + +EVAL-ADIN1110EBZ has 2 U(S)ARTs. The Zephyr console output is assigned to UART1 that is connected +to a FT232, so available through Micro USB connector. Default settings are 115200 8N1. + + +Programming and Debugging +************************* + +Flashing +======== + +EVAL-ADIN1110EBZ includes an ST-LINK/V2-1 JTAG/SWD 10 or 20 pin connector. This interface is +supported by the openocd version included in Zephyr SDK. + +Flashing an application to Discovery kit +----------------------------------------- + +Connect the EVAL-ADIN1110EBZ to your host computer using the USB port, then run a serial host +program to connect with your ADI board. For example: + +.. code-block:: console + + $ minicom -D /dev/serial/by-id/usb-ADI_EVAL-ADIN1110EBZ_AVAS_XXXXXX-if00-port0 + +where XXXXXX is the serial number of the connected device. +Then, build and flash in the usual way. Here is an example for the :ref:`hello_world` application. + +.. zephyr-app-commands:: + :zephyr-app: samples/hello_world + :board: adi_eval_adin1110ebz + :goals: build flash + +You should see the following message on the console: + +.. code-block:: console + + Hello World! adi_eval_adin1110ebz + +Debugging +========= + +You can debug an application in the usual way. Here is an example for the :ref:`hello_world` +application. + +.. zephyr-app-commands:: + :zephyr-app: samples/hello_world + :board: adi_eval_adin1110ebz + :maybe-skip-config: + :goals: debug + +.. _EVAL-ADIN1110EBZ evaluation board website: + https://www.analog.com/en/design-center/evaluation-hardware-and-software/evaluation-boards-kits/eval-adin1110.html + +.. _EVAL-ADIN1110EBZ board User Guide: + https://wiki.analog.com/resources/eval/user-guides/eval-adin1110ebz-user-guide + +.. _ADIN1110 Datasheet: + https://www.analog.com/media/en/technical-documentation/data-sheets/adin1110.pdf + +.. _STM32L4S5QII3P reference manual: + https://www.st.com/resource/en/reference_manual/rm0432-stm32l4-series-advanced-armbased-32bit-mcus-stmicroelectronics.pdf diff --git a/boards/arm/adi_eval_adin1110ebz/pre_dt_board.cmake b/boards/arm/adi_eval_adin1110ebz/pre_dt_board.cmake new file mode 100644 index 00000000000..394b73d0d23 --- /dev/null +++ b/boards/arm/adi_eval_adin1110ebz/pre_dt_board.cmake @@ -0,0 +1,2 @@ +list(APPEND EXTRA_DTC_FLAGS "-Wno-spi_bus_bridge") +list(APPEND EXTRA_DTC_FLAGS "-Wno-simple_bus_reg") diff --git a/boards/arm/adi_eval_adin1110ebz/support/openocd.cfg b/boards/arm/adi_eval_adin1110ebz/support/openocd.cfg new file mode 100644 index 00000000000..295299f2fbe --- /dev/null +++ b/boards/arm/adi_eval_adin1110ebz/support/openocd.cfg @@ -0,0 +1,12 @@ +source [find board/stm32l4discovery.cfg] + +$_TARGETNAME configure -event gdb-attach { + echo "Debugger attaching: halting execution" + reset halt + gdb_breakpoint_override hard +} + +$_TARGETNAME configure -event gdb-detach { + echo "Debugger detaching: resuming execution" + resume +} From 4fe3a8827fd58a7cf08e3923af8826960c64a971 Mon Sep 17 00:00:00 2001 From: Angelo Dureghello Date: Wed, 24 Jan 2024 14:50:34 +0100 Subject: [PATCH 3270/3723] boards: add support for eval-adin2111ebz Add support for ADI EVAL-ADIN2111EBZ. Tested samples: * hello_world * blinky * dhcpv4_client Co-developed-by: Philip Molloy Signed-off-by: Philip Molloy Signed-off-by: Angelo Dureghello --- boards/arm/adi_eval_adin2111ebz/Kconfig.board | 8 + .../adi_eval_adin2111ebz/Kconfig.defconfig | 37 ++++ .../adi_eval_adin2111ebz.dts | 197 ++++++++++++++++++ .../adi_eval_adin2111ebz.yaml | 15 ++ .../adi_eval_adin2111ebz_defconfig | 21 ++ boards/arm/adi_eval_adin2111ebz/board.cmake | 6 + .../doc/img/adi_eval_adin2111ebz.webp | Bin 0 -> 84454 bytes boards/arm/adi_eval_adin2111ebz/doc/index.rst | 184 ++++++++++++++++ .../adi_eval_adin2111ebz/pre_dt_board.cmake | 1 + .../adi_eval_adin2111ebz/support/openocd.cfg | 12 ++ 10 files changed, 481 insertions(+) create mode 100644 boards/arm/adi_eval_adin2111ebz/Kconfig.board create mode 100644 boards/arm/adi_eval_adin2111ebz/Kconfig.defconfig create mode 100644 boards/arm/adi_eval_adin2111ebz/adi_eval_adin2111ebz.dts create mode 100644 boards/arm/adi_eval_adin2111ebz/adi_eval_adin2111ebz.yaml create mode 100644 boards/arm/adi_eval_adin2111ebz/adi_eval_adin2111ebz_defconfig create mode 100644 boards/arm/adi_eval_adin2111ebz/board.cmake create mode 100644 boards/arm/adi_eval_adin2111ebz/doc/img/adi_eval_adin2111ebz.webp create mode 100644 boards/arm/adi_eval_adin2111ebz/doc/index.rst create mode 100644 boards/arm/adi_eval_adin2111ebz/pre_dt_board.cmake create mode 100644 boards/arm/adi_eval_adin2111ebz/support/openocd.cfg diff --git a/boards/arm/adi_eval_adin2111ebz/Kconfig.board b/boards/arm/adi_eval_adin2111ebz/Kconfig.board new file mode 100644 index 00000000000..f173947c39b --- /dev/null +++ b/boards/arm/adi_eval_adin2111ebz/Kconfig.board @@ -0,0 +1,8 @@ +# ADI EVAL-ADIN2111EBZ board configuration + +# Copyright (c) 2024 BayLibre +# SPDX-License-Identifier: Apache-2.0 + +config BOARD_ADI_EVAL_ADIN2111EBZ + bool "ADI EVAL-ADIN2111EBZ evaulation board" + depends on SOC_STM32L4S5XX diff --git a/boards/arm/adi_eval_adin2111ebz/Kconfig.defconfig b/boards/arm/adi_eval_adin2111ebz/Kconfig.defconfig new file mode 100644 index 00000000000..41dd579738c --- /dev/null +++ b/boards/arm/adi_eval_adin2111ebz/Kconfig.defconfig @@ -0,0 +1,37 @@ +# ADI EVAL-ADIN2111EBZ board configuration + +# Copyright (c) 2024 BayLibre +# SPDX-License-Identifier: Apache-2.0 + +if BOARD_ADI_EVAL_ADIN2111EBZ + +config BOARD + default "adi_eval_adin2111ebz" + +config SPI_STM32_INTERRUPT + default y + depends on SPI + +config MDIO_INIT_PRIORITY + default 81 + depends on MDIO + +config PHY_INIT_PRIORITY + default 82 + depends on NET_L2_ETHERNET && ETH_DRIVER + +if NETWORKING + +config NET_L2_ETHERNET + default y + +if ETH_ADIN2111 + +config NET_IF_MAX_IPV4_COUNT + default 2 + +endif # ETH_ADIN2111 + +endif # NETWORKING + +endif # BOARD_ADI_EVAL_ADIN2111EBZ diff --git a/boards/arm/adi_eval_adin2111ebz/adi_eval_adin2111ebz.dts b/boards/arm/adi_eval_adin2111ebz/adi_eval_adin2111ebz.dts new file mode 100644 index 00000000000..5602afab008 --- /dev/null +++ b/boards/arm/adi_eval_adin2111ebz/adi_eval_adin2111ebz.dts @@ -0,0 +1,197 @@ +/* + * Copyright (c) 2024 BayLibre + * + * SPDX-License-Identifier: Apache-2.0 + */ + +/dts-v1/; + +#include +#include + +/ { + model = "Analog Devices Inc. EVAL-ADIN2111EBZ board"; + compatible = "adi,eval-adin2111ebz"; + + chosen { + zephyr,console = &usart1; + zephyr,shell-uart = &usart1; + zephyr,sram = &sram0; + zephyr,flash = &flash0; + zephyr,code-partition = &slot0_partition; + }; + + leds { + compatible = "gpio-leds"; + blue_led: uC_led1 { + gpios = <&gpiob 6 GPIO_ACTIVE_HIGH>; + label = "Debug led uC1"; + }; + net_red_led: led_NET1 { + gpios = <&gpiob 10 GPIO_ACTIVE_HIGH>; + label = "NET led 1"; + }; + net_green_led: led_NET2 { + gpios = <&gpiob 11 GPIO_ACTIVE_HIGH>; + label = "NET led 2"; + }; + mod_red_led: led_MOD1 { + gpios = <&gpioe 2 GPIO_ACTIVE_HIGH>; + label = "Mod led 1"; + }; + mod_green_led: led_MOD2 { + gpios = <&gpioe 6 GPIO_ACTIVE_HIGH>; + label = "Mod led 2"; + }; + }; + + aliases { + led0 = &blue_led; + watchdog0 = &iwdg; + spi-flash0 = &flash_ext; + }; +}; + +&clk_lsi { + status = "okay"; +}; + +&clk_hsi48 { + status = "okay"; +}; + +&clk_hsi { + status = "okay"; +}; + +&pll { + div-m = <4>; + mul-n = <40>; + div-q = <2>; + div-r = <2>; + clocks = <&clk_hsi>; + status = "okay"; +}; + +&rcc { + clocks = <&pll>; + clock-frequency = ; + ahb-prescaler = <1>; + apb1-prescaler = <1>; + apb2-prescaler = <1>; +}; + +&flash0 { + partitions { + compatible = "fixed-partitions"; + #address-cells = <1>; + #size-cells = <1>; + + boot_partition: partition@0 { + label = "mcuboot"; + reg = <0x00000000 DT_SIZE_K(64)>; + read-only; + }; + + /* + * The flash starting at offset 0x10000 and ending at + * offset 0x1ffff is reserved for use by the application. + */ + + slot0_partition: partition@20000 { + label = "image-0"; + reg = <0x00020000 DT_SIZE_K(432)>; + }; + slot1_partition: partition@8c000 { + label = "image-1"; + reg = <0x0008C000 DT_SIZE_K(432)>; + }; + scratch_partition: partition@f8000 { + label = "image-scratch"; + reg = <0x000F8000 DT_SIZE_K(16)>; + }; + + storage_partition: partition@fc000 { + label = "storage"; + reg = <0x000fc000 DT_SIZE_K(16)>; + }; + }; +}; + +&iwdg { + status = "okay"; +}; + +&rng { + status = "okay"; +}; + +&dma1 { + status = "okay"; +}; + +&dmamux1 { + status = "okay"; +}; + +&usart1 { /* USB FT232 */ + pinctrl-0 = <&usart1_tx_pa9 &usart1_rx_pa10>; + pinctrl-names = "default"; + current-speed = <115200>; + status = "okay"; +}; + +&spi1 { + pinctrl-0 = <&spi1_sck_pa5 &spi1_miso_pa6 &spi1_mosi_pa7>; + pinctrl-names = "default"; + cs-gpios = <&gpioa 4 (GPIO_ACTIVE_LOW | GPIO_PULL_UP)>; + status = "okay"; + + flash_ext: flash@0 { + compatible = "issi,is25lp128", "jedec,spi-nor"; + size = <134217728>; + jedec-id = [96 60 18]; + reg = <0>; + spi-max-frequency = <133000000>; + status = "okay"; + }; +}; + +&spi2 { + pinctrl-0 = <&spi2_sck_pb13 &spi2_miso_pb14 &spi2_mosi_pb15>; + pinctrl-names = "default"; + cs-gpios = <&gpiob 12 (GPIO_ACTIVE_LOW | GPIO_PULL_UP)>; + status = "okay"; + + adin2111: adin2111@0 { + compatible = "adi,adin2111"; + reg = <0x0>; + spi-max-frequency = <25000000>; + int-gpios = <&gpioa 12 GPIO_ACTIVE_LOW>; + status = "okay"; + + port1 { + local-mac-address = [ 00 E0 22 FE DA C9 ]; + }; + port2 { + local-mac-address = [ 00 E0 22 FE DA D9 ]; + }; + mdio { + compatible = "adi,adin2111-mdio"; + #address-cells = <1>; + #size-cells = <0>; + status = "okay"; + + ethernet-phy@1 { + reg = <0x1>; + compatible = "adi,adin2111-phy"; + status = "okay"; + }; + ethernet-phy@2 { + reg = <0x2>; + compatible = "adi,adin2111-phy"; + status = "okay"; + }; + }; + }; +}; diff --git a/boards/arm/adi_eval_adin2111ebz/adi_eval_adin2111ebz.yaml b/boards/arm/adi_eval_adin2111ebz/adi_eval_adin2111ebz.yaml new file mode 100644 index 00000000000..bddea6e4a76 --- /dev/null +++ b/boards/arm/adi_eval_adin2111ebz/adi_eval_adin2111ebz.yaml @@ -0,0 +1,15 @@ +identifier: adi_eval_adin2111ebz +name: ADI EVAL-ADIN2111EBZ evaulation board +type: mcu +arch: arm +toolchain: + - zephyr + - gnuarmemb + - xtools +ram: 640 +flash: 2048 +supported: + - gpio + - spi + - watchdog +vendor: adi diff --git a/boards/arm/adi_eval_adin2111ebz/adi_eval_adin2111ebz_defconfig b/boards/arm/adi_eval_adin2111ebz/adi_eval_adin2111ebz_defconfig new file mode 100644 index 00000000000..f7e4d9c4ab3 --- /dev/null +++ b/boards/arm/adi_eval_adin2111ebz/adi_eval_adin2111ebz_defconfig @@ -0,0 +1,21 @@ +# SPDX-License-Identifier: Apache-2.0 + +CONFIG_BOARD_ADI_EVAL_ADIN2111EBZ=y +CONFIG_SOC_SERIES_STM32L4X=y +CONFIG_SOC_STM32L4S5XX=y + +# enable uart driver +CONFIG_SERIAL=y + +# console +CONFIG_CONSOLE=y +CONFIG_UART_CONSOLE=y + +# enable GPIO +CONFIG_GPIO=y + +# Enable Clocks +CONFIG_CLOCK_CONTROL=y + +# enable pin controller +CONFIG_PINCTRL=y diff --git a/boards/arm/adi_eval_adin2111ebz/board.cmake b/boards/arm/adi_eval_adin2111ebz/board.cmake new file mode 100644 index 00000000000..4e81b2fb988 --- /dev/null +++ b/boards/arm/adi_eval_adin2111ebz/board.cmake @@ -0,0 +1,6 @@ +# SPDX-License-Identifier: Apache-2.0 + +board_runner_args(jlink "--device=STM32L4S5QI" "--speed=4000") + +include(${ZEPHYR_BASE}/boards/common/openocd.board.cmake) +include(${ZEPHYR_BASE}/boards/common/jlink.board.cmake) diff --git a/boards/arm/adi_eval_adin2111ebz/doc/img/adi_eval_adin2111ebz.webp b/boards/arm/adi_eval_adin2111ebz/doc/img/adi_eval_adin2111ebz.webp new file mode 100644 index 0000000000000000000000000000000000000000..0b37432ac8427d665d78e37a048ba4bf5350061b GIT binary patch literal 84454 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 Q0000000000000000Fu2}@&Et; literal 0 HcmV?d00001 diff --git a/boards/arm/adi_eval_adin2111ebz/doc/index.rst b/boards/arm/adi_eval_adin2111ebz/doc/index.rst new file mode 100644 index 00000000000..ac9d33aa285 --- /dev/null +++ b/boards/arm/adi_eval_adin2111ebz/doc/index.rst @@ -0,0 +1,184 @@ +.. _adi_eval_adin2111ebz: + +ADI EVAL-ADIN2111EVB Evaluation board +##################################### + +Overview +******** + +The EVAL-ADIN2111EBZ is a flexible platform enabling quick evaluation of the ADIN2111, robust, +low power 10BASE-T1L 2-Port Ethernet switch. The evaluation board provides 2 10BASE-T1L channels +with 10Mbit per second Single Pair Ethernet (SPE) connections reaching up to 1.7km of link distance. + +The ADIN2111 internal switch can be configured in store and forward mode between the two 10BASE-T1L +channels and the SPI host. Cut through mode is also available between Port 1 and Port 2 and can +be used without the need of the SPI host (unmanaged configuration). + +The evaluation board offers two modes of operation for maximum flexibility: Connected to a PC +via USB port, the full set of ADIN2111 register settings and features such as link quality +monitoring and diagnostics can be accessed over the USB using the serial command interface +implemented in the evaluation firmware. + +Alternatively, the board can operate in cut-through mode between Port 1 and Port 2 (unmanaged +configuration without firmware) where the EVAL-ADIN2111EBZ acts as a network switch forwarding +packets between the 2x 10BASE-T1L ports. The 2x links are configured by setting the ADIN2111 +hardware configuration pins jumper and switches. The 2x On-board Activity LEDs provide Link +activity status indication for each port. + +Custom firmware can also be developed and the ADIN2111 driver support package includes simple +project examples to start a custom implementation. + +The SPI interface provides access to the management registers required for the switch configuration, +the 2 PHYs configuration and data exchange between SPI host and ports. + +.. important:: + + S1 DIP switches are shipped in Open Alliance SPI mode. The current Zephyr + default board configuration is set to work as "Generic SPI, CRC enabled", + so the S1 DIP switches must be set as ``SPI_CFG0 OFF and SPI_CFG1 OFF``. + An inconsistent S1 DIP switches configuration will halt the boot. + +.. figure:: img/adi_eval_adin2111ebz.webp + :align: center + :alt: ADI EVAL-ADIN2111EBZ + + ADI EVAL-ADIN2111EBZ (Credit: Analog Devices, Inc.) + +Hardware +******** + +The ADI EVAL-ADIN2111EBZ hardware features list is available here: + +https://wiki.analog.com/resources/eval/user-guides/eval-adin2111ebz-user-guide + + +Supported Features +================== + +The ADI adi_eval_adin2111ebz board configuration supports the +following hardware features: + ++--------------+------------+-------------------------------------+ +| Interface | Controller | Driver/Component | ++==============+============+=====================================+ +| NVIC | on-chip | nested vector interrupt controller | ++--------------+------------+-------------------------------------+ +| UART | on-chip | serial port-polling; | +| | | serial port-interrupt | ++--------------+------------+-------------------------------------+ +| PINMUX | on-chip | pinmux | ++--------------+------------+-------------------------------------+ +| GPIO | on-chip | gpio | ++--------------+------------+-------------------------------------+ +| I2C | on-chip | i2c | ++--------------+------------+-------------------------------------+ +| SPI | on-chip | spi | ++--------------+------------+-------------------------------------+ +| PWM | on-chip | pwm | ++--------------+------------+-------------------------------------+ +| WATCHDOG | on-chip | independent watchdog | ++--------------+------------+-------------------------------------+ +| ADIN2111 | spi | adin2111 10BASE-T1L mac/phy | ++--------------+------------+-------------------------------------+ +| FT232 | uart | usb-uart | ++--------------+------------+-------------------------------------+ + + +The default configuration can be found in the defconfig file: + + ``boards/arm/adi_eval_adin2111ebz/adi_eval_adin2111ebz_defconfig`` + + +Connections and IOs +=================== + +ADI ADIN2111EBZ evaluation board has 7 GPIO controllers (from A to G). +These controllers are responsible for pin muxing, input/output, pull-up, etc. + +For mode details please refer to `EVAL-ADIN2111EBZ User Guide `_. + +Default Zephyr Peripheral Mapping: +---------------------------------- + +- UART_1 TX/RX : PA9/PA10 (UART to FT232, console) +- SPI1 SCK/MISO/MOSI : PA5/PA6/PA7 (SPI to external nor flash IS25LP128) +- SPI2 SCK/MISO/MOSI : PB13/PB14/PB15 (SPI to external ADIN2111) +- LED1 : POWER (Green LED) +- UC_LED1 : PB6 (Blue LED) +- MOD LED1 : PE2 (SR LED) +- MOD LED2 : PE6 (BG LED) +- NET LED1 : PB10 (SR LED) +- NET LED2 : PB11 (BG LED) + + +System Clock +------------ + +EVAL-ADIN2111EBZ System Clock could be driven by an internal or external oscillator, as well as the +main PLL clock. By default the System clock is driven by the PLL clock at 80MHz, driven by the +16MHz high speed internal oscillator. + +Serial Port +----------- + +EVAL-ADIN2111EBZ has 1 U(S)ART. The Zephyr console output is assigned to UART1 that is connected +to a FT232, available through Micro USB connector. Default settings are 115200 8N1. +Same UART1 TX and RX cmos signals are available before the FT232, at P9 connector. + + +Programming and Debugging +************************* + +Flashing +======== + +EVAL-ADIN2111EBZ includes an ST-LINK/V2-1 JTAG/SWD 10 or 20 pin connector. This interface is +supported by the openocd version included in Zephyr SDK. + +Flashing an application to Discovery kit +----------------------------------------- + +Connect the EVAL-ADIN2111EBZ to your host computer using the USB port, then run a serial host +program to connect with your ADI board. For example: + +.. code-block:: console + + $ minicom -D /dev/serial/by-id/usb-ADI_EVAL-ADIN2111EBZ_XXXXXX-12-if00-port0 + +where XXXXXX is the serial number of the connected device. +Then, build and flash in the usual way. Here is an example for the :ref:`hello_world` application. + +.. zephyr-app-commands:: + :zephyr-app: samples/hello_world + :board: adi_eval_adin2111ebz + :goals: build flash + +You should see the following message on the console: + +.. code-block:: console + + Hello World! adi_eval_adin2111ebz + +Debugging +========= + +You can debug an application in the usual way. Here is an example for the :ref:`hello_world` +application. + +.. zephyr-app-commands:: + :zephyr-app: samples/hello_world + :board: adi_eval_adin2111ebz + :maybe-skip-config: + :goals: debug + +.. _EVAL-ADIN2111EBZ evaluation board website: + https://www.analog.com/en/design-center/evaluation-hardware-and-software/evaluation-boards-kits/eval-adin2111.html + +.. _EVAL-ADIN2111EBZ board User Guide: + https://wiki.analog.com/resources/eval/user-guides/eval-adin2111ebz-user-guide + +.. _ADIN2111 Datasheet: + https://www.analog.com/media/en/technical-documentation/data-sheets/adin2111.pdf + +.. _STM32L4S5QII3P reference manual: + https://www.st.com/resource/en/reference_manual/rm0432-stm32l4-series-advanced-armbased-32bit-mcus-stmicroelectronics.pdf diff --git a/boards/arm/adi_eval_adin2111ebz/pre_dt_board.cmake b/boards/arm/adi_eval_adin2111ebz/pre_dt_board.cmake new file mode 100644 index 00000000000..44653c797ad --- /dev/null +++ b/boards/arm/adi_eval_adin2111ebz/pre_dt_board.cmake @@ -0,0 +1 @@ +list(APPEND EXTRA_DTC_FLAGS "-Wno-simple_bus_reg") diff --git a/boards/arm/adi_eval_adin2111ebz/support/openocd.cfg b/boards/arm/adi_eval_adin2111ebz/support/openocd.cfg new file mode 100644 index 00000000000..295299f2fbe --- /dev/null +++ b/boards/arm/adi_eval_adin2111ebz/support/openocd.cfg @@ -0,0 +1,12 @@ +source [find board/stm32l4discovery.cfg] + +$_TARGETNAME configure -event gdb-attach { + echo "Debugger attaching: halting execution" + reset halt + gdb_breakpoint_override hard +} + +$_TARGETNAME configure -event gdb-detach { + echo "Debugger detaching: resuming execution" + resume +} From c948f831e0b6f90c0373d48e763490029bc3de2d Mon Sep 17 00:00:00 2001 From: Fredrik Danebjer Date: Wed, 24 Jan 2024 08:59:12 +0100 Subject: [PATCH 3271/3723] Bluetooth samples: Add USB Audio to Broadcast Sink sample Added USB Audio output for the Broadcast Sink sample. In addition offloading of the LC3 codec was also made. The sample supports only mono, and a KConfig option was added to configure which audio location to sync to. Signed-off-by: Fredrik Danebjer --- .../bluetooth/broadcast_audio_sink/Kconfig | 21 + .../nrf5340_audio_dk_nrf5340_cpuapp.conf | 4 + .../bluetooth/broadcast_audio_sink/src/main.c | 425 ++++++++++++++---- 3 files changed, 368 insertions(+), 82 deletions(-) diff --git a/samples/bluetooth/broadcast_audio_sink/Kconfig b/samples/bluetooth/broadcast_audio_sink/Kconfig index b70a42e2d99..e24193fccad 100644 --- a/samples/bluetooth/broadcast_audio_sink/Kconfig +++ b/samples/bluetooth/broadcast_audio_sink/Kconfig @@ -43,4 +43,25 @@ config ENABLE_LC3 select LIBLC3 select FPU +config USE_USB_AUDIO_OUTPUT + bool "Use USB Audio as output" + depends on ENABLE_LC3 + select USB_DEVICE_STACK + select USB_DEVICE_AUDIO + select RING_BUFFER + help + Enables USB audio as output as a USB peripheral. This does not support providing USB + audio to e.g. speakers that are also USB peripherals, but can be connected to e.g. a + phone or PC as a USB-in device (such as a USB microphone). + USB audio only supports a single audio channel. + +config TARGET_BROADCAST_CHANNEL + int "Broadcast Channel Audio Location to sync to" + range 0 2 + default 1 + depends on USE_USB_AUDIO_OUTPUT + help + Channel Audio Location to sync to. These corresponds to the bt_audio_location, + supporting mono, left and right channels + source "Kconfig.zephyr" diff --git a/samples/bluetooth/broadcast_audio_sink/boards/nrf5340_audio_dk_nrf5340_cpuapp.conf b/samples/bluetooth/broadcast_audio_sink/boards/nrf5340_audio_dk_nrf5340_cpuapp.conf index 8ab7a163fb6..f8f7db343e8 100644 --- a/samples/bluetooth/broadcast_audio_sink/boards/nrf5340_audio_dk_nrf5340_cpuapp.conf +++ b/samples/bluetooth/broadcast_audio_sink/boards/nrf5340_audio_dk_nrf5340_cpuapp.conf @@ -1,3 +1,7 @@ # The LC3 codec uses a large amount of stack. This app runs the codec in the work-queue, hence # inctease stack size for that thread. CONFIG_SYSTEM_WORKQUEUE_STACK_SIZE=4096 +CONFIG_ENABLE_LC3=y +CONFIG_TARGET_BROADCAST_CHANNEL=1 +CONFIG_USE_USB_AUDIO_OUTPUT=y +CONFIG_USB_DEVICE_PRODUCT="USB Broadcast Sink" diff --git a/samples/bluetooth/broadcast_audio_sink/src/main.c b/samples/bluetooth/broadcast_audio_sink/src/main.c index 587cb59dc51..f2f1b2c646a 100644 --- a/samples/bluetooth/broadcast_audio_sink/src/main.c +++ b/samples/bluetooth/broadcast_audio_sink/src/main.c @@ -1,5 +1,6 @@ /* * Copyright (c) 2022-2023 Nordic Semiconductor ASA + * Copyright (c) 2024 Demant A/S * * SPDX-License-Identifier: Apache-2.0 */ @@ -12,6 +13,15 @@ #include #include #include +#if defined(CONFIG_LIBLC3) +#include "lc3.h" +#endif /* defined(CONFIG_LIBLC3) */ +#if defined(CONFIG_USB_DEVICE_AUDIO) +#include +#include +#include +#endif /* defined(CONFIG_USB_DEVICE_AUDIO) */ + BUILD_ASSERT(IS_ENABLED(CONFIG_SCAN_SELF) || IS_ENABLED(CONFIG_SCAN_OFFLOAD), "Either SCAN_SELF or SCAN_OFFLOAD must be enabled"); @@ -30,6 +40,28 @@ BUILD_ASSERT(IS_ENABLED(CONFIG_SCAN_SELF) || IS_ENABLED(CONFIG_SCAN_OFFLOAD), #define PA_SYNC_SKIP 5 #define NAME_LEN sizeof(CONFIG_TARGET_BROADCAST_NAME) + 1 +#if defined(CONFIG_LIBLC3) +#define MAX_SAMPLE_RATE 48000U +#define MAX_FRAME_DURATION_US 10000U +#define MAX_NUM_SAMPLES_MONO ((MAX_FRAME_DURATION_US * MAX_SAMPLE_RATE) / USEC_PER_SEC) +#define MAX_NUM_SAMPLES_STEREO (MAX_NUM_SAMPLES_MONO * 2) + +#define LC3_ENCODER_STACK_SIZE 4096 +#define LC3_ENCODER_PRIORITY 5 +#endif /* defined(CONFIG_LIBLC3) */ + +#if defined(CONFIG_USB_DEVICE_AUDIO) +#define USB_SAMPLE_RATE 48000U +#define USB_FRAME_DURATION_US 1000U +#define USB_TX_BUF_NUM 10U +#define BROADCAST_DATA_ELEMENT_SIZE sizeof(int16_t) +#define BROADCAST_MONO_SAMPLE_SIZE (MAX_NUM_SAMPLES_MONO * BROADCAST_DATA_ELEMENT_SIZE) +#define BROADCAST_STEREO_SAMPLE_SIZE (BROADCAST_MONO_SAMPLE_SIZE * BROADCAST_DATA_ELEMENT_SIZE) +#define USB_STEREO_SAMPLE_SIZE ((USB_FRAME_DURATION_US * USB_SAMPLE_RATE * \ + BROADCAST_DATA_ELEMENT_SIZE * 2) / USEC_PER_SEC) +#define AUDIO_RING_BUF_SIZE 10000U +#endif /* defined(CONFIG_USB_DEVICE_AUDIO) */ + static K_SEM_DEFINE(sem_connected, 0U, 1U); static K_SEM_DEFINE(sem_disconnected, 0U, 1U); static K_SEM_DEFINE(sem_broadcaster_found, 0U, 1U); @@ -52,6 +84,7 @@ static struct bt_le_per_adv_sync *pa_sync; static uint32_t broadcaster_broadcast_id; static struct broadcast_sink_stream { struct bt_bap_stream stream; + bool has_data; size_t recv_cnt; size_t loss_cnt; size_t error_cnt; @@ -61,7 +94,14 @@ static struct broadcast_sink_stream { struct k_work_delayable lc3_decode_work; /* Internal lock for protecting net_buf from multiple access */ struct k_mutex lc3_decoder_mutex; + lc3_decoder_t lc3_decoder; + lc3_decoder_mem_48k_t lc3_decoder_mem; #endif /* defined(CONFIG_LIBLC3) */ +#if defined(CONFIG_USB_DEVICE_AUDIO) + struct ring_buf audio_ring_buf; + uint8_t _ring_buffer[AUDIO_RING_BUF_SIZE]; +#endif /* defined(CONFIG_USB_DEVICE_AUDIO) */ + } streams[CONFIG_BT_BAP_BROADCAST_SNK_STREAM_COUNT]; static struct bt_bap_stream *streams_p[ARRAY_SIZE(streams)]; static struct bt_conn *broadcast_assistant_conn; @@ -83,70 +123,77 @@ static uint8_t sink_broadcast_code[BT_AUDIO_BROADCAST_CODE_SIZE]; uint64_t total_rx_iso_packet_count; /* This value is exposed to test code */ -#if defined(CONFIG_LIBLC3) +#if defined(CONFIG_USB_DEVICE_AUDIO) +static int16_t usb_audio_data[MAX_NUM_SAMPLES_STEREO] = {0}; +static int16_t usb_audio_data_stereo[MAX_NUM_SAMPLES_STEREO] = {0}; -#include "lc3.h" +RING_BUF_DECLARE(ring_buf_usb, AUDIO_RING_BUF_SIZE); +NET_BUF_POOL_DEFINE(usb_tx_buf_pool, USB_TX_BUF_NUM, BROADCAST_STEREO_SAMPLE_SIZE, 0, + net_buf_destroy); -#define MAX_SAMPLE_RATE 16000 -#define MAX_FRAME_DURATION_US 10000 -#define MAX_NUM_SAMPLES ((MAX_FRAME_DURATION_US * MAX_SAMPLE_RATE) / USEC_PER_SEC) +static void mix_mono_to_stereo(enum bt_audio_location channels); +#endif /* defined(CONFIG_USB_DEVICE_AUDIO) */ -static int16_t audio_buf[MAX_NUM_SAMPLES]; -static lc3_decoder_t lc3_decoder; -static lc3_decoder_mem_16k_t lc3_decoder_mem; +#if defined(CONFIG_LIBLC3) +static int16_t audio_buf[MAX_NUM_SAMPLES_MONO]; static int frames_per_sdu; +static K_SEM_DEFINE(lc3_decoder_sem, 0, 1); -static int lc3_enable(const struct bt_audio_codec_cfg *codec_cfg) -{ - int ret; - int freq_hz; - int frame_duration_us; +static void do_lc3_decode(struct broadcast_sink_stream *sink_stream); +static void lc3_decoder_thread(void *arg1, void *arg2, void *arg3); +K_THREAD_DEFINE(decoder_tid, LC3_ENCODER_STACK_SIZE, lc3_decoder_thread, + NULL, NULL, NULL, LC3_ENCODER_PRIORITY, 0, -1); - printk("Enable: stream with codec %p\n", codec_cfg); +/* Consumer thread of the decoded stream data */ +static void lc3_decoder_thread(void *arg1, void *arg2, void *arg3) +{ + while (true) { + k_sem_take(&lc3_decoder_sem, K_FOREVER); +#if defined(CONFIG_USB_DEVICE_AUDIO) + int err = 0; + enum bt_audio_location channels; + struct broadcast_sink_stream *stream_for_usb = &streams[0]; + + /* For now we only handle one BIS, so always only decode the first element in + * streams. + */ + do_lc3_decode(&streams[0]); - ret = bt_audio_codec_cfg_get_freq(codec_cfg); - if (ret > 0) { - freq_hz = bt_audio_codec_cfg_freq_to_freq_hz(ret); - } else { - printk("Error: Codec frequency not set, cannot start codec."); - return -1; - } + err = bt_audio_codec_cfg_get_chan_allocation(stream_for_usb->stream.codec_cfg, + &channels); + if (err != 0) { + printk("Could not get channel allocation (err=%d)\n", err); + continue; + } - ret = bt_audio_codec_cfg_get_frame_dur(codec_cfg); - if (ret > 0) { - frame_duration_us = bt_audio_codec_cfg_frame_dur_to_frame_dur_us(ret); - } else { - printk("Error: Frame duration not set, cannot start codec."); - return ret; + /* If the ring buffer usage is larger than zero, then there is data to process */ + if (ring_buf_space_get(&stream_for_usb->audio_ring_buf)) { + mix_mono_to_stereo(channels); + } +#else + for (size_t i = 0; i < ARRAY_SIZE(streams); i++) { + if (streams[i].has_data) { + do_lc3_decode(&streams[i]); + } } - frames_per_sdu = bt_audio_codec_cfg_get_frame_blocks_per_sdu(codec_cfg, true); - - lc3_decoder = lc3_setup_decoder(frame_duration_us, freq_hz, 0, /* No resampling */ - &lc3_decoder_mem); - - if (lc3_decoder == NULL) { - printk("ERROR: Failed to setup LC3 decoder - wrong parameters?\n"); - return -1; +#endif /* #if defined(CONFIG_USB_DEVICE_AUDIO) */ } - - return 0; } -static void lc3_decode_handler(struct k_work *work) +static void do_lc3_decode(struct broadcast_sink_stream *sink_stream) { int err = 0; int offset = 0; uint8_t *buf_data; struct net_buf *ptr_net_buf; int octets_per_frame; - struct broadcast_sink_stream *sink_stream = CONTAINER_OF( - k_work_delayable_from_work(work), struct broadcast_sink_stream, lc3_decode_work); k_mutex_lock(&sink_stream->lc3_decoder_mutex, K_FOREVER); + sink_stream->has_data = false; + if (sink_stream->in_buf == NULL) { - printk("buf data is NULL, nothing to be docoded\n"); k_mutex_unlock(&sink_stream->lc3_decoder_mutex); return; } @@ -160,23 +207,182 @@ static void lc3_decode_handler(struct k_work *work) octets_per_frame = ptr_net_buf->len / frames_per_sdu; for (int i = 0; i < frames_per_sdu; i++) { - err = lc3_decode(lc3_decoder, buf_data + offset, octets_per_frame, - LC3_PCM_FORMAT_S16, audio_buf, 1); + err = lc3_decode(sink_stream->lc3_decoder, buf_data + offset, octets_per_frame, + LC3_PCM_FORMAT_S16, audio_buf, 1); if (err == 1) { printk(" decoder performed PLC\n"); } else if (err < 0) { - printk(" decoder failed - wrong parameters?\n"); + printk(" decoder failed - wrong parameters? (err = %d)\n", err); } offset += octets_per_frame; } net_buf_unref(ptr_net_buf); + +#if defined(CONFIG_USB_DEVICE_AUDIO) + uint32_t rbret; + + if (ring_buf_space_get(&sink_stream->audio_ring_buf) == 0) { + /* Since the data in the buffer is old by now, and we add enough data for many + * request to consume at a time, just erase what is already in the buffer. + */ + ring_buf_reset(&sink_stream->audio_ring_buf); + } + + /* Put in ring-buffer to be consumed */ + rbret = ring_buf_put(&sink_stream->audio_ring_buf, (uint8_t *)audio_buf, + BROADCAST_MONO_SAMPLE_SIZE); + if (rbret != BROADCAST_MONO_SAMPLE_SIZE) { + static int rb_add_failures; + + rb_add_failures++; + if (rb_add_failures % 1000 == 0) { + printk("Failure to add to ring buffer %d, %u\n", rb_add_failures, rbret); + } + return; + } +#endif /*#if defined(CONFIG_USB_DEVICE_AUDIO)*/ } +static int lc3_enable(struct broadcast_sink_stream *sink_stream) +{ + int ret; + int freq_hz; + int frame_duration_us; + + printk("Enable: stream with codec %p\n", sink_stream->stream.codec_cfg); + + ret = bt_audio_codec_cfg_get_freq(sink_stream->stream.codec_cfg); + if (ret > 0) { + freq_hz = bt_audio_codec_cfg_freq_to_freq_hz(ret); + } else { + printk("Error: Codec frequency not set, cannot start codec."); + return -1; + } + + ret = bt_audio_codec_cfg_get_frame_dur(sink_stream->stream.codec_cfg); + if (ret > 0) { + frame_duration_us = bt_audio_codec_cfg_frame_dur_to_frame_dur_us(ret); + } else { + printk("Error: Frame duration not set, cannot start codec."); + return ret; + } + + frames_per_sdu = bt_audio_codec_cfg_get_frame_blocks_per_sdu(sink_stream->stream.codec_cfg, + true); + +#if defined(CONFIG_USB_DEVICE_AUDIO) + sink_stream->lc3_decoder = lc3_setup_decoder(frame_duration_us, freq_hz, USB_SAMPLE_RATE, + &sink_stream->lc3_decoder_mem); +#else + sink_stream->lc3_decoder = lc3_setup_decoder(frame_duration_us, freq_hz, 0, + &sink_stream->lc3_decoder_mem); +#endif /* defined(CONFIG_USB_DEVICE_AUDIO) */ + + if (sink_stream->lc3_decoder == NULL) { + printk("ERROR: Failed to setup LC3 decoder - wrong parameters?\n"); + return -1; + } + + k_thread_start(decoder_tid); + + return 0; +} #endif /* defined(CONFIG_LIBLC3) */ +#if defined(CONFIG_USB_DEVICE_AUDIO) +static uint8_t get_channel_index(const enum bt_audio_location allocated_channels, + const enum bt_audio_location channel) +{ + /* If we are looking for the right channel, and left channel is present, then the index is + * 1. For all other combinations the index has to be 0, since it would mean that it is the + * lowest possible bit enumeration + */ + if (channel == BT_AUDIO_LOCATION_FRONT_RIGHT && + allocated_channels & BT_AUDIO_LOCATION_FRONT_LEFT) { + return 1; + } + + return 0; +} + +/* Duplicate the audio from one channel and put it in both channels */ +static void mix_mono_to_stereo(enum bt_audio_location channels) +{ + uint32_t size; + uint8_t cidx; + + size = ring_buf_get(&streams[0].audio_ring_buf, (uint8_t *)usb_audio_data, + MAX_NUM_SAMPLES_STEREO); + if (size != MAX_NUM_SAMPLES_STEREO) { + memset(&((uint8_t *)usb_audio_data)[size], 0, sizeof(usb_audio_data) - size); + } + + cidx = get_channel_index(channels, CONFIG_TARGET_BROADCAST_CHANNEL); + + /* Interleave the channel sample */ + for (size_t i = 0U; i < MAX_NUM_SAMPLES_MONO; i++) { + usb_audio_data_stereo[i * 2] = usb_audio_data[MAX_NUM_SAMPLES_MONO * cidx + i]; + usb_audio_data_stereo[i * 2 + 1] = usb_audio_data[MAX_NUM_SAMPLES_MONO * cidx + i]; + } + + size = ring_buf_put(&ring_buf_usb, (uint8_t *)usb_audio_data_stereo, + BROADCAST_STEREO_SAMPLE_SIZE); + if (size != BROADCAST_STEREO_SAMPLE_SIZE) { + static int rb_put_failures; + + rb_put_failures++; + if (rb_put_failures == 1000) { + printk("%s: Failure to add to ring buffer %d, %u\n", __func__, + rb_put_failures, size); + rb_put_failures = 0; + } + } +} + +/* USB consumer callback, called every 1ms, consumes data from ring-buffer */ +static void data_request(const struct device *dev) +{ + static struct net_buf *pcm_buf; + int err; + uint32_t size; + void *out; + int16_t usb_audio_data[USB_STEREO_SAMPLE_SIZE] = {0}; + + size = ring_buf_get(&ring_buf_usb, (uint8_t *)usb_audio_data, USB_STEREO_SAMPLE_SIZE); + if (size != USB_STEREO_SAMPLE_SIZE) { + memset(&((uint8_t *)usb_audio_data)[size], 0, USB_STEREO_SAMPLE_SIZE); + } + + pcm_buf = net_buf_alloc(&usb_tx_buf_pool, K_NO_WAIT); + if (pcm_buf == NULL) { + printk("Couldnt allocate pcm_buf\n"); + return; + } + + out = net_buf_add(pcm_buf, USB_STEREO_SAMPLE_SIZE); + memcpy(out, usb_audio_data, USB_STEREO_SAMPLE_SIZE); + + err = usb_audio_send(dev, pcm_buf, USB_STEREO_SAMPLE_SIZE); + if (err) { + net_buf_unref(pcm_buf); + } +} + +static void data_written(const struct device *dev, struct net_buf *buf, size_t size) +{ + /* Unreference the buffer now that the USB is done with it */ + net_buf_unref(buf); +} + +static const struct usb_audio_ops ops = { + .data_request_cb = data_request, + .data_written_cb = data_written, +}; +#endif /* defined(CONFIG_USB_DEVICE_AUDIO) */ + static void stream_started_cb(struct bt_bap_stream *stream) { struct broadcast_sink_stream *sink_stream = @@ -190,9 +396,23 @@ static void stream_started_cb(struct bt_bap_stream *stream) sink_stream->valid_cnt = 0U; sink_stream->error_cnt = 0U; + #if defined(CONFIG_LIBLC3) - k_work_init_delayable(&sink_stream->lc3_decode_work, lc3_decode_handler); -#endif /* defined(CONFIG_LIBLC3) */ + int err; + + if (stream->codec_cfg != 0 && stream->codec_cfg->id != BT_HCI_CODING_FORMAT_LC3) { + /* No subgroups with LC3 was found */ + printk("Did not parse an LC3 codec\n"); + return; + } + + err = lc3_enable(sink_stream); + if (err < 0) { + printk("Error: cannot enable LC3 codec: %d", err); + return; + } +#endif /* CONFIG_LIBLC3 */ + k_sem_give(&sem_bis_synced); } @@ -233,7 +453,8 @@ static void stream_recv_cb(struct bt_bap_stream *stream, const struct bt_iso_rec sink_stream->in_buf = net_buf_ref(buf); k_mutex_unlock(&sink_stream->lc3_decoder_mutex); - k_work_schedule(&sink_stream->lc3_decode_work, K_NO_WAIT); + sink_stream->has_data = true; + k_sem_give(&lc3_decoder_sem); #endif /* defined(CONFIG_LIBLC3) */ } @@ -252,33 +473,62 @@ static struct bt_bap_stream_ops stream_ops = { .recv = stream_recv_cb, }; -#if defined(CONFIG_LIBLC3) -static bool base_subgroup_cb(const struct bt_bap_base_subgroup *subgroup, void *user_data) +#if defined(CONFIG_TARGET_BROADCAST_CHANNEL) +static bool find_valid_bis_cb(const struct bt_bap_base_subgroup_bis *bis, + void *user_data) { - struct bt_audio_codec_cfg *codec_cfg = user_data; - struct bt_bap_base_codec_id codec_id; - int ret; + int err; + struct bt_audio_codec_cfg codec_cfg = {0}; + enum bt_audio_location chan_allocation; + uint8_t *bis_index = user_data; - ret = bt_bap_base_get_subgroup_codec_id(subgroup, &codec_id); - if (ret < 0) { - printk("Could not get codec id for subgroup %p: %d", subgroup, ret); + err = bt_bap_base_subgroup_bis_codec_to_codec_cfg(bis, &codec_cfg); + if (err != 0) { + printk("Could not find codec configuration (err=%d)\n", err); return true; } - if (codec_id.id != BT_HCI_CODING_FORMAT_LC3) { - printk("Unsupported codec for subgroup %p: 0x%02x", subgroup, codec_id.id); - return true; /* parse next subgroup */ + err = bt_audio_codec_cfg_get_chan_allocation(&codec_cfg, &chan_allocation); + if (err != 0) { + printk("Could not find channel allocation (err=%d)\n", err); + return true; } - ret = bt_bap_base_subgroup_codec_to_codec_cfg(subgroup, codec_cfg); - if (ret < 0) { - printk("Could convert subgroup %p to codec_cfg: %d", subgroup, ret); - return true; + if (((CONFIG_TARGET_BROADCAST_CHANNEL) == BT_AUDIO_LOCATION_MONO_AUDIO && + chan_allocation == BT_AUDIO_LOCATION_MONO_AUDIO) || + chan_allocation & CONFIG_TARGET_BROADCAST_CHANNEL) { + *bis_index = bis->index; + + return false; } - return false; /* We only care about the first subgroup with LC3 */ + return true; +} + +static bool find_valid_bis_in_subgroup_cb(const struct bt_bap_base_subgroup *subgroup, + void *user_data) +{ + return bt_bap_base_subgroup_foreach_bis(subgroup, find_valid_bis_cb, user_data) + == -ECANCELED ? false : true; } -#endif /* CONFIG_LIBLC3 */ + +static int base_get_first_valid_bis(const struct bt_bap_base *base, uint32_t *bis_index) +{ + int err; + uint8_t valid_bis_index = 0U; + + err = bt_bap_base_foreach_subgroup(base, find_valid_bis_in_subgroup_cb, &valid_bis_index); + if (err != -ECANCELED) { + printk("Failed to parse subgroups: %d\n", err); + return err != 0 ? err : -ENOENT; + } + + *bis_index = 0; + *bis_index |= ((uint8_t)1 << valid_bis_index); + + return 0; +} +#endif /* CONFIG_TARGET_BROADCAST_CHANNEL */ static void base_recv_cb(struct bt_bap_broadcast_sink *sink, const struct bt_bap_base *base, size_t base_size) @@ -293,31 +543,19 @@ static void base_recv_cb(struct bt_bap_broadcast_sink *sink, const struct bt_bap printk("Received BASE with %d subgroups from broadcast sink %p\n", bt_bap_base_get_subgroup_count(base), sink); -#if defined(CONFIG_LIBLC3) - struct bt_audio_codec_cfg codec_cfg = {0}; - - err = bt_bap_base_foreach_subgroup(base, base_subgroup_cb, &codec_cfg); - if (err != 0 && err != -ECANCELED) { - printk("Failed to parse subgroups: %d\n", err); - return; - } else if (codec_cfg.id != BT_HCI_CODING_FORMAT_LC3) { - /* No subgroups with LC3 was found */ - printk("Did not parse an LC3 codec\n"); - return; - } - - err = lc3_enable(&codec_cfg); - if (err < 0) { - printk("Error: cannot enable LC3 codec: %d", err); +#if defined(CONFIG_TARGET_BROADCAST_CHANNEL) + err = base_get_first_valid_bis(base, &base_bis_index_bitfield); + if (err != 0) { + printk("Failed to find a valid BIS\n"); return; } -#endif /* CONFIG_LIBLC3 */ - +#else err = bt_bap_base_get_bis_indexes(base, &base_bis_index_bitfield); if (err != 0) { printk("Failed to BIS indexes: %d\n", err); return; } +#endif /* CONFIG_TARGET_BROADCAST_CHANNEL */ bis_index_bitfield = base_bis_index_bitfield & bis_index_mask; @@ -721,6 +959,29 @@ static int init(void) streams[i].stream.ops = &stream_ops; } + /* Initialize ring buffers and USB */ +#if defined(CONFIG_USB_DEVICE_AUDIO) + int ret; + const struct device *hs_dev = DEVICE_DT_GET(DT_NODELABEL(hs_0)); + + for (int i = 0U; i < CONFIG_BT_BAP_BROADCAST_SNK_STREAM_COUNT; i++) { + ring_buf_init(&streams[i].audio_ring_buf, AUDIO_RING_BUF_SIZE, + streams[i]._ring_buffer); + } + + if (!device_is_ready(hs_dev)) { + printk("Cannot get USB Headset Device\n"); + return -EIO; + } + + usb_audio_register(hs_dev, &ops); + ret = usb_enable(NULL); + if (ret != 0) { + printk("Failed to enable USB\n"); + return err; + } +#endif /* defined(CONFIG_USB_DEVICE_AUDIO) */ + return 0; } From e92e4c249daf8d073c30a4b2fc6473a34d933e0b Mon Sep 17 00:00:00 2001 From: Emil Gydesen Date: Tue, 3 Oct 2023 10:36:33 +0200 Subject: [PATCH 3272/3723] Bluetooth: Audio: Update return value of {cfg,cap}_get_val The get_val functions will now return -ENODATA in case that a value isn't found, instead of 0. This makes them more similar to the meta_get_val functions. Signed-off-by: Emil Gydesen --- include/zephyr/bluetooth/audio/audio.h | 17 ++++++++----- subsys/bluetooth/audio/codec.c | 34 +++++++++++++------------- tests/bluetooth/audio/codec/src/main.c | 8 +++--- 3 files changed, 32 insertions(+), 27 deletions(-) diff --git a/include/zephyr/bluetooth/audio/audio.h b/include/zephyr/bluetooth/audio/audio.h index 772e93588fa..e6ad69e58ce 100644 --- a/include/zephyr/bluetooth/audio/audio.h +++ b/include/zephyr/bluetooth/audio/audio.h @@ -802,10 +802,13 @@ int bt_audio_codec_cfg_set_frame_blocks_per_sdu(struct bt_audio_codec_cfg *codec * @param[in] codec_cfg The codec data to search in. * @param[in] type The type id to look for * @param[out] data Pointer to the data-pointer to update when item is found - * @return Length of found @p data or 0 if not found + * + * @retval Length of found @p data (may be 0) + * @retval -EINVAL if arguments are invalid + * @retval -ENODATA if not found */ -uint8_t bt_audio_codec_cfg_get_val(const struct bt_audio_codec_cfg *codec_cfg, - enum bt_audio_codec_config_type type, const uint8_t **data); +int bt_audio_codec_cfg_get_val(const struct bt_audio_codec_cfg *codec_cfg, + enum bt_audio_codec_config_type type, const uint8_t **data); /** * @brief Set or add a specific codec configuration value @@ -1194,10 +1197,12 @@ int bt_audio_codec_cfg_meta_set_vendor(struct bt_audio_codec_cfg *codec_cfg, * @param[in] type The type id to look for * @param[out] data Pointer to the data-pointer to update when item is found * - * @return Length of found @p data or 0 if not found + * @retval Length of found @p data (may be 0) + * @retval -EINVAL if arguments are invalid + * @retval -ENODATA if not found */ -uint8_t bt_audio_codec_cap_get_val(const struct bt_audio_codec_cap *codec_cap, - enum bt_audio_codec_capability_type type, const uint8_t **data); +int bt_audio_codec_cap_get_val(const struct bt_audio_codec_cap *codec_cap, + enum bt_audio_codec_capability_type type, const uint8_t **data); /** * @brief Set or add a specific codec capability value diff --git a/subsys/bluetooth/audio/codec.c b/subsys/bluetooth/audio/codec.c index 6eec848a9b4..c62a48b95c0 100644 --- a/subsys/bluetooth/audio/codec.c +++ b/subsys/bluetooth/audio/codec.c @@ -279,8 +279,8 @@ static void init_net_buf_simple_from_codec_cfg(struct net_buf_simple *buf, buf->len = codec_cfg->data_len; } -uint8_t bt_audio_codec_cfg_get_val(const struct bt_audio_codec_cfg *codec_cfg, - enum bt_audio_codec_config_type type, const uint8_t **data) +int bt_audio_codec_cfg_get_val(const struct bt_audio_codec_cfg *codec_cfg, + enum bt_audio_codec_config_type type, const uint8_t **data) { struct search_type_param param = { .found = false, @@ -292,12 +292,12 @@ uint8_t bt_audio_codec_cfg_get_val(const struct bt_audio_codec_cfg *codec_cfg, CHECKIF(codec_cfg == NULL) { LOG_DBG("codec is NULL"); - return 0; + return -EINVAL; } CHECKIF(data == NULL) { LOG_DBG("data is NULL"); - return 0; + return -EINVAL; } *data = NULL; @@ -305,12 +305,12 @@ uint8_t bt_audio_codec_cfg_get_val(const struct bt_audio_codec_cfg *codec_cfg, err = bt_audio_data_parse(codec_cfg->data, codec_cfg->data_len, parse_cb, ¶m); if (err != 0 && err != -ECANCELED) { LOG_DBG("Could not parse the data: %d", err); - return 0; + return err; } - if (param.data == NULL) { + if (!param.found) { LOG_DBG("Could not find the type %u", type); - return 0; + return -ENODATA; } return param.data_len; @@ -591,12 +591,12 @@ static void init_net_buf_simple_from_meta(struct net_buf_simple *buf, uint8_t me buf->len = meta_len; } -static int codec_meta_get_val(const uint8_t meta[], size_t meta_len, uint8_t type, - const uint8_t **data) +static int codec_meta_get_val(const uint8_t meta[], size_t meta_len, + enum bt_audio_metadata_type type, const uint8_t **data) { struct search_type_param param = { .found = false, - .type = type, + .type = (uint8_t)type, .data_len = 0, .data = data, }; @@ -1793,8 +1793,8 @@ static void init_net_buf_simple_from_codec_cap(struct net_buf_simple *buf, buf->len = codec_cap->data_len; } -uint8_t bt_audio_codec_cap_get_val(const struct bt_audio_codec_cap *codec_cap, - enum bt_audio_codec_capability_type type, const uint8_t **data) +int bt_audio_codec_cap_get_val(const struct bt_audio_codec_cap *codec_cap, + enum bt_audio_codec_capability_type type, const uint8_t **data) { struct search_type_param param = { .found = false, @@ -1806,12 +1806,12 @@ uint8_t bt_audio_codec_cap_get_val(const struct bt_audio_codec_cap *codec_cap, CHECKIF(codec_cap == NULL) { LOG_DBG("codec_cap is NULL"); - return 0; + return -EINVAL; } CHECKIF(data == NULL) { LOG_DBG("data is NULL"); - return 0; + return -EINVAL; } *data = NULL; @@ -1819,12 +1819,12 @@ uint8_t bt_audio_codec_cap_get_val(const struct bt_audio_codec_cap *codec_cap, err = bt_audio_data_parse(codec_cap->data, codec_cap->data_len, parse_cb, ¶m); if (err != 0 && err != -ECANCELED) { LOG_DBG("Could not parse the data: %d", err); - return 0; + return err; } - if (param.data == NULL) { + if (!param.found) { LOG_DBG("Could not find the type %u", type); - return 0; + return -ENODATA; } return param.data_len; diff --git a/tests/bluetooth/audio/codec/src/main.c b/tests/bluetooth/audio/codec/src/main.c index 73d1362956a..9ab17d02d9a 100644 --- a/tests/bluetooth/audio/codec/src/main.c +++ b/tests/bluetooth/audio/codec/src/main.c @@ -65,7 +65,7 @@ ZTEST(audio_codec_test_suite, test_bt_audio_codec_cfg_set_val_new_value) int ret; ret = bt_audio_codec_cfg_get_val(&codec_cfg, BT_AUDIO_CODEC_CONFIG_LC3_FREQ, &data); - zassert_equal(ret, 0, "Unexpected return value %d", ret); + zassert_equal(ret, -ENODATA, "Unexpected return value %d", ret); ret = bt_audio_codec_cfg_set_val(&codec_cfg, BT_AUDIO_CODEC_CONFIG_LC3_FREQ, &new_expected_data, sizeof(new_expected_data)); @@ -95,7 +95,7 @@ ZTEST(audio_codec_test_suite, test_bt_audio_codec_cfg_unset_val) zassert_true(ret >= 0, "Unexpected return value %d", ret); ret = bt_audio_codec_cfg_get_val(&codec_cfg, BT_AUDIO_CODEC_CONFIG_LC3_FREQ, &data); - zassert_equal(ret, 0, "Unexpected return value %d", ret); + zassert_equal(ret, -ENODATA, "Unexpected return value %d", ret); } ZTEST(audio_codec_test_suite, test_bt_audio_codec_cfg_freq_to_freq_hz) @@ -925,7 +925,7 @@ ZTEST(audio_codec_test_suite, test_bt_audio_codec_cap_set_val_new) int ret; ret = bt_audio_codec_cap_get_val(&codec_cap, BT_AUDIO_CODEC_CONFIG_LC3_FREQ, &data); - zassert_equal(ret, 0, "Unexpected return value %d", ret); + zassert_equal(ret, -ENODATA, "Unexpected return value %d", ret); ret = bt_audio_codec_cap_set_val(&codec_cap, BT_AUDIO_CODEC_CONFIG_LC3_FREQ, &new_expected_data, sizeof(new_expected_data)); @@ -955,7 +955,7 @@ ZTEST(audio_codec_test_suite, test_bt_audio_codec_cap_unset_val) zassert_true(ret >= 0, "Unexpected return value %d", ret); ret = bt_audio_codec_cap_get_val(&codec_cap, BT_AUDIO_CODEC_CONFIG_LC3_FREQ, &data); - zassert_equal(ret, 0, "Unexpected return value %d", ret); + zassert_equal(ret, -ENODATA, "Unexpected return value %d", ret); } ZTEST(audio_codec_test_suite, test_bt_audio_codec_cap_get_freq) From f81113e94811e2e7381f9a6c78dc5f0e29bc6bd7 Mon Sep 17 00:00:00 2001 From: Daniel DeGrasse Date: Thu, 24 Aug 2023 12:30:32 -0500 Subject: [PATCH 3273/3723] drivers: clock_control: add support for FlexSPI reclock on NXP iMX RT10XX Add support for reclocking the FlexSPI on NXP iMX RT10XX. This functionality requires an SOC specific clock function to set the clock rate, since the FlexSPI must be reset directly before applying the new clock frequency. Note that all clock constants are defined in this commit, since the memc flexspi driver now depends on a clock node being present. Signed-off-by: Daniel DeGrasse --- .../clock_control/clock_control_mcux_ccm.c | 48 +++++++++++ drivers/flash/flash_mcux_flexspi_hyperflash.c | 6 +- drivers/memc/memc_mcux_flexspi.c | 52 +++++++++--- drivers/memc/memc_mcux_flexspi.h | 13 +-- dts/arm/nxp/nxp_rt10xx.dtsi | 2 + dts/arm/nxp/nxp_rt11xx.dtsi | 2 + dts/arm/nxp/nxp_rt5xx_common.dtsi | 2 + dts/arm/nxp/nxp_rt6xx_common.dtsi | 1 + include/zephyr/dt-bindings/clock/imx_ccm.h | 3 + .../zephyr/dt-bindings/clock/imx_ccm_rev2.h | 3 + .../dt-bindings/clock/mcux_lpc_syscon_clock.h | 3 + soc/arm/nxp_imx/rt/CMakeLists.txt | 6 +- soc/arm/nxp_imx/rt/flexspi_rt10xx.c | 79 +++++++++++-------- soc/arm/nxp_imx/rt/soc.h | 5 +- 14 files changed, 166 insertions(+), 59 deletions(-) diff --git a/drivers/clock_control/clock_control_mcux_ccm.c b/drivers/clock_control/clock_control_mcux_ccm.c index 355f85dfc3e..6245788961c 100644 --- a/drivers/clock_control/clock_control_mcux_ccm.c +++ b/drivers/clock_control/clock_control_mcux_ccm.c @@ -316,16 +316,64 @@ static int mcux_ccm_get_subsys_rate(const struct device *dev, / (CLOCK_GetDiv(kCLOCK_Sai3PreDiv) + 1) / (CLOCK_GetDiv(kCLOCK_Sai3Div) + 1); break; +#endif +#if DT_NODE_HAS_STATUS(DT_NODELABEL(flexspi), okay) + case IMX_CCM_FLEXSPI_CLK: + *rate = CLOCK_GetClockRootFreq(kCLOCK_FlexspiClkRoot); + break; +#endif +#if DT_NODE_HAS_STATUS(DT_NODELABEL(flexspi2), okay) + case IMX_CCM_FLEXSPI2_CLK: + *rate = CLOCK_GetClockRootFreq(kCLOCK_Flexspi2ClkRoot); + break; #endif } return 0; } +/* + * Since this function is used to reclock the FlexSPI when running in + * XIP, it must be located in RAM when MEMC Flexspi driver is enabled. + */ +#ifdef CONFIG_MEMC_MCUX_FLEXSPI +#define CCM_SET_FUNC_ATTR __ramfunc +#else +#define CCM_SET_FUNC_ATTR +#endif + +static int CCM_SET_FUNC_ATTR mcux_ccm_set_subsys_rate(const struct device *dev, + clock_control_subsys_t subsys, + clock_control_subsys_rate_t rate) +{ + uint32_t clock_name = (uintptr_t)subsys; + uint32_t clock_rate = (uintptr_t)rate; + + switch (clock_name) { + case IMX_CCM_FLEXSPI_CLK: + __fallthrough; + case IMX_CCM_FLEXSPI2_CLK: +#if defined(CONFIG_SOC_SERIES_IMX_RT10XX) && defined(CONFIG_MEMC_MCUX_FLEXSPI) + /* The SOC is using the FlexSPI for XIP. Therefore, + * the FlexSPI itself must be managed within the function, + * which is SOC specific. + */ + return flexspi_clock_set_freq(clock_name, clock_rate); +#endif + default: + /* Silence unused variable warning */ + ARG_UNUSED(clock_rate); + return -ENOTSUP; + } +} + + + static const struct clock_control_driver_api mcux_ccm_driver_api = { .on = mcux_ccm_on, .off = mcux_ccm_off, .get_rate = mcux_ccm_get_subsys_rate, + .set_rate = mcux_ccm_set_subsys_rate, }; static int mcux_ccm_init(const struct device *dev) diff --git a/drivers/flash/flash_mcux_flexspi_hyperflash.c b/drivers/flash/flash_mcux_flexspi_hyperflash.c index b0a04ee63ed..5c03febc29a 100644 --- a/drivers/flash/flash_mcux_flexspi_hyperflash.c +++ b/drivers/flash/flash_mcux_flexspi_hyperflash.c @@ -433,8 +433,9 @@ static int flash_flexspi_hyperflash_write(const struct device *dev, off_t offset key = irq_lock(); } + /* Clock FlexSPI at 84 MHZ (42MHz SCLK in DDR mode) */ (void)memc_flexspi_update_clock(&data->controller, &data->config, - data->port, MEMC_FLEXSPI_CLOCK_42M); + data->port, MHZ(84)); while (len) { /* Writing between two page sizes crashes the platform so we @@ -477,8 +478,9 @@ static int flash_flexspi_hyperflash_write(const struct device *dev, off_t offset len -= i; } + /* Clock FlexSPI at 332 MHZ (166 MHz SCLK in DDR mode) */ (void)memc_flexspi_update_clock(&data->controller, &data->config, - data->port, MEMC_FLEXSPI_CLOCK_166M); + data->port, MHZ(332)); #ifdef CONFIG_HAS_MCUX_CACHE DCACHE_InvalidateByRange((uint32_t) dst, size); diff --git a/drivers/memc/memc_mcux_flexspi.c b/drivers/memc/memc_mcux_flexspi.c index 84ab86a793a..e0c8f6faf96 100644 --- a/drivers/memc/memc_mcux_flexspi.c +++ b/drivers/memc/memc_mcux_flexspi.c @@ -9,6 +9,7 @@ #include #include #include +#include #include #include @@ -60,6 +61,8 @@ struct memc_flexspi_data { struct port_lut port_luts[kFLEXSPI_PortCount]; struct memc_flexspi_buf_cfg *buf_cfg; uint8_t buf_cfg_cnt; + const struct device *clock_dev; + clock_control_subsys_t clock_subsys; }; void memc_flexspi_wait_bus_idle(const struct device *dev) @@ -79,30 +82,56 @@ bool memc_flexspi_is_running_xip(const struct device *dev) int memc_flexspi_update_clock(const struct device *dev, flexspi_device_config_t *device_config, - flexspi_port_t port, enum memc_flexspi_clock_t clock) + flexspi_port_t port, uint32_t freq_hz) { -#if CONFIG_SOC_SERIES_IMX_RT10XX struct memc_flexspi_data *data = dev->data; + uint32_t rate; + uint32_t key; + int ret; + /* To reclock the FlexSPI, we should: + * - disable the module + * - set the new clock + * - reenable the module + * - reset the module + * We CANNOT XIP at any point during this process + */ + key = irq_lock(); memc_flexspi_wait_bus_idle(dev); - FLEXSPI_Enable(data->base, false); + ret = clock_control_set_rate(data->clock_dev, data->clock_subsys, + (clock_control_subsys_rate_t)freq_hz); + if (ret < 0) { + irq_unlock(key); + return ret; + } - flexspi_clock_set_div(clock == MEMC_FLEXSPI_CLOCK_166M ? 0 : 3); + /* + * We need to update the DLL value before we call clock_control_get_rate, + * because this will cause XIP (flash reads) to occur. Although the + * true flash clock is not known, assume the set_rate function programmed + * a value close to what we requested. + */ + device_config->flexspiRootClk = freq_hz; + FLEXSPI_UpdateDllValue(data->base, device_config, port); + memc_flexspi_reset(dev); - FLEXSPI_Enable(data->base, true); + memc_flexspi_wait_bus_idle(dev); + ret = clock_control_get_rate(data->clock_dev, data->clock_subsys, &rate); + if (ret < 0) { + irq_unlock(key); + return ret; + } - memc_flexspi_reset(dev); - device_config->flexspiRootClk = flexspi_clock_get_freq(); + device_config->flexspiRootClk = rate; FLEXSPI_UpdateDllValue(data->base, device_config, port); memc_flexspi_reset(dev); + irq_unlock(key); + return 0; -#else - return -ENOTSUP; -#endif } int memc_flexspi_set_device_config(const struct device *dev, @@ -332,6 +361,9 @@ static int memc_flexspi_pm_action(const struct device *dev, enum pm_device_actio .buf_cfg_cnt = sizeof(buf_cfg_##n) / \ sizeof(struct memc_flexspi_buf_cfg), \ .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), \ }; \ \ PM_DEVICE_DT_INST_DEFINE(n, memc_flexspi_pm_action); \ diff --git a/drivers/memc/memc_mcux_flexspi.h b/drivers/memc/memc_mcux_flexspi.h index a8495fc9289..ee9fa463655 100644 --- a/drivers/memc/memc_mcux_flexspi.h +++ b/drivers/memc/memc_mcux_flexspi.h @@ -8,13 +8,6 @@ #include #include -enum memc_flexspi_clock_t { - /* Flexspi clock 332M, DDR mode, internal clock 166M. */ - MEMC_FLEXSPI_CLOCK_166M, - /* Flexspi clock 83M, DDR mode, internal clock 42M. */ - MEMC_FLEXSPI_CLOCK_42M, -}; - /* Size of a command in the LUT table */ #define MEMC_FLEXSPI_CMD_SIZE 4U @@ -43,17 +36,17 @@ bool memc_flexspi_is_running_xip(const struct device *dev); /** * @brief Update clock selection of the FlexSPI device * - * Updates clock selection of the FlexSPI device to a new clock speed. + * Updates clock frequency of FlexSPI to new clock speed. * * @param dev: FlexSPI device * @param device_config: External device configuration. * @param port: FlexSPI port to use for this external device - * @param clock: new clock selection to apply + * @param freq_hz: new clock frequency to apply * @return 0 on success, negative value on failure */ int memc_flexspi_update_clock(const struct device *dev, flexspi_device_config_t *device_config, - flexspi_port_t port, enum memc_flexspi_clock_t clock); + flexspi_port_t port, uint32_t freq_hz); /** * @brief configure new FlexSPI device diff --git a/dts/arm/nxp/nxp_rt10xx.dtsi b/dts/arm/nxp/nxp_rt10xx.dtsi index 73e108f1005..3bc5749f271 100644 --- a/dts/arm/nxp/nxp_rt10xx.dtsi +++ b/dts/arm/nxp/nxp_rt10xx.dtsi @@ -126,6 +126,7 @@ ahb-bufferable; ahb-cacheable; status = "disabled"; + clocks = <&ccm IMX_CCM_FLEXSPI_CLK 0x0 0x0>; }; flexspi2: spi@402a4000 { @@ -137,6 +138,7 @@ ahb-bufferable; ahb-cacheable; status = "disabled"; + clocks = <&ccm IMX_CCM_FLEXSPI2_CLK 0x0 0x0>; }; semc: semc0@402f0000 { diff --git a/dts/arm/nxp/nxp_rt11xx.dtsi b/dts/arm/nxp/nxp_rt11xx.dtsi index 9e92a3e0226..6216b32cb46 100644 --- a/dts/arm/nxp/nxp_rt11xx.dtsi +++ b/dts/arm/nxp/nxp_rt11xx.dtsi @@ -95,6 +95,7 @@ #address-cells = <1>; #size-cells = <0>; status = "disabled"; + clocks = <&ccm IMX_CCM_FLEXSPI_CLK 0x0 0>; }; flexspi2: spi@400d0000 { @@ -104,6 +105,7 @@ #address-cells = <1>; #size-cells = <0>; status = "disabled"; + clocks = <&ccm IMX_CCM_FLEXSPI2_CLK 0x0 0>; }; semc: semc0@400d4000 { diff --git a/dts/arm/nxp/nxp_rt5xx_common.dtsi b/dts/arm/nxp/nxp_rt5xx_common.dtsi index d84d89b8528..867d30cc8ee 100644 --- a/dts/arm/nxp/nxp_rt5xx_common.dtsi +++ b/dts/arm/nxp/nxp_rt5xx_common.dtsi @@ -687,6 +687,7 @@ interrupts = <42 0>; #address-cells = <1>; #size-cells = <0>; + clocks = <&clkctl1 MCUX_FLEXSPI_CLK>; }; &flexspi2 { @@ -695,6 +696,7 @@ interrupts = <42 0>; #address-cells = <1>; #size-cells = <0>; + clocks = <&clkctl1 MCUX_FLEXSPI2_CLK>; }; &nvic { diff --git a/dts/arm/nxp/nxp_rt6xx_common.dtsi b/dts/arm/nxp/nxp_rt6xx_common.dtsi index 62e8865b731..170622b068c 100644 --- a/dts/arm/nxp/nxp_rt6xx_common.dtsi +++ b/dts/arm/nxp/nxp_rt6xx_common.dtsi @@ -501,6 +501,7 @@ #address-cells = <1>; #size-cells = <0>; status = "disabled"; + clocks = <&clkctl1 MCUX_FLEXSPI_CLK>; }; &nvic { diff --git a/include/zephyr/dt-bindings/clock/imx_ccm.h b/include/zephyr/dt-bindings/clock/imx_ccm.h index 3535c06935e..b20d1e5aecb 100644 --- a/include/zephyr/dt-bindings/clock/imx_ccm.h +++ b/include/zephyr/dt-bindings/clock/imx_ccm.h @@ -58,4 +58,7 @@ #define IMX_CCM_ENET_CLK 0x0E00UL #define IMX_CCM_ENET_PLL 0x0E01UL +#define IMX_CCM_FLEXSPI_CLK 0x0F00UL +#define IMX_CCM_FLEXSPI2_CLK 0x0F01UL + #endif /* ZEPHYR_INCLUDE_DT_BINDINGS_CLOCK_IMX_CCM_H_ */ diff --git a/include/zephyr/dt-bindings/clock/imx_ccm_rev2.h b/include/zephyr/dt-bindings/clock/imx_ccm_rev2.h index fe011525846..c36d140b534 100644 --- a/include/zephyr/dt-bindings/clock/imx_ccm_rev2.h +++ b/include/zephyr/dt-bindings/clock/imx_ccm_rev2.h @@ -92,5 +92,8 @@ #define IMX_CCM_ENET_CLK 0x3000UL #define IMX_CCM_ENET_PLL 0x3001UL +/* FLEXSPI */ +#define IMX_CCM_FLEXSPI_CLK 0x4000UL +#define IMX_CCM_FLEXSPI2_CLK 0x4001UL #endif /* ZEPHYR_INCLUDE_DT_BINDINGS_CLOCK_IMX_CCM_REV2_H_ */ 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 e273288a37e..404ba96de96 100644 --- a/include/zephyr/dt-bindings/clock/mcux_lpc_syscon_clock.h +++ b/include/zephyr/dt-bindings/clock/mcux_lpc_syscon_clock.h @@ -53,6 +53,9 @@ #define MCUX_DMIC_CLK 35 +#define MCUX_FLEXSPI_CLK 36 +#define MCUX_FLEXSPI2_CLK 37 + #define MCUX_MRT_CLK 40 #endif /* ZEPHYR_INCLUDE_DT_BINDINGS_CLOCK_MCUX_LPC_SYSCON_H_ */ diff --git a/soc/arm/nxp_imx/rt/CMakeLists.txt b/soc/arm/nxp_imx/rt/CMakeLists.txt index 92ab665a0ef..e88fc46e28e 100644 --- a/soc/arm/nxp_imx/rt/CMakeLists.txt +++ b/soc/arm/nxp_imx/rt/CMakeLists.txt @@ -28,9 +28,11 @@ if(CONFIG_PM) zephyr_sources_ifdef(CONFIG_SOC_SERIES_IMX_RT11XX power_rt11xx.c) endif() -if (CONFIG_FLASH_MCUX_FLEXSPI_XIP AND CONFIG_SOC_SERIES_IMX_RT10XX AND CONFIG_MEMC) +if (CONFIG_SOC_SERIES_IMX_RT10XX AND CONFIG_MEMC_MCUX_FLEXSPI) zephyr_sources(flexspi_rt10xx.c) - zephyr_code_relocate(FILES flexspi_rt10xx.c LOCATION ITCM_TEXT) + if (CONFIG_FLASH_MCUX_FLEXSPI_XIP) + zephyr_code_relocate(FILES flexspi_rt10xx.c LOCATION ITCM_TEXT) + endif() endif () if (CONFIG_PM AND CONFIG_SOC_SERIES_IMX_RT10XX) diff --git a/soc/arm/nxp_imx/rt/flexspi_rt10xx.c b/soc/arm/nxp_imx/rt/flexspi_rt10xx.c index b6335f0c256..a6a6239e9e7 100644 --- a/soc/arm/nxp_imx/rt/flexspi_rt10xx.c +++ b/soc/arm/nxp_imx/rt/flexspi_rt10xx.c @@ -5,50 +5,63 @@ */ #include +#include #include +#include +#include +#include -/* reimplementation of non-inline CLOCK_GetFreq(kCLOCK_Usb1PllPfd0Clk) */ -static uint32_t clock_get_usb1_pll_pfd0_clk(void) +uint32_t flexspi_clock_set_freq(uint32_t clock_name, uint32_t rate) { - uint32_t freq; + uint8_t divider; + uint32_t root_rate; + FLEXSPI_Type *flexspi; + clock_div_t div_sel; + clock_ip_name_t clk_name; - if (!CLOCK_IsPllEnabled(CCM_ANALOG, kCLOCK_PllUsb1)) { - return 0; + switch (clock_name) { + case IMX_CCM_FLEXSPI_CLK: + /* Get clock root frequency */ + root_rate = CLOCK_GetClockRootFreq(kCLOCK_FlexspiClkRoot) * + (CLOCK_GetDiv(kCLOCK_FlexspiDiv) + 1); + flexspi = (FLEXSPI_Type *)DT_REG_ADDR(DT_NODELABEL(flexspi)); + div_sel = kCLOCK_FlexspiDiv; + clk_name = kCLOCK_FlexSpi; + break; +#if DT_NODE_HAS_STATUS(DT_NODELABEL(flexspi2), okay) + case IMX_CCM_FLEXSPI2_CLK: + /* Get clock root frequency */ + root_rate = CLOCK_GetClockRootFreq(kCLOCK_Flexspi2ClkRoot) * + (CLOCK_GetDiv(kCLOCK_Flexspi2Div) + 1); + flexspi = (FLEXSPI_Type *)DT_REG_ADDR(DT_NODELABEL(flexspi2)); + div_sel = kCLOCK_Flexspi2Div; + clk_name = kCLOCK_FlexSpi2; + break; +#endif + default: + return -ENOTSUP; } + /* Select a divider based on root frequency. + * if we can't get an exact divider, round down + */ + divider = ((root_rate + (rate - 1)) / rate) - 1; + /* Cap divider to max value */ + divider = MIN(divider, kCLOCK_FlexspiDivBy8); - freq = CLOCK_GetPllBypassRefClk(CCM_ANALOG, kCLOCK_PllUsb1); - - if (CLOCK_IsPllBypassed(CCM_ANALOG, kCLOCK_PllUsb1)) { - return freq; + while (FLEXSPI_GetBusIdleStatus(flexspi) == false) { + /* Spin */ } + FLEXSPI_Enable(flexspi, false); - freq *= ((CCM_ANALOG->PLL_USB1 & CCM_ANALOG_PLL_USB1_DIV_SELECT_MASK) != 0) ? 22 : 20; - - /* get current USB1 PLL PFD output frequency */ - freq /= (CCM_ANALOG->PFD_480 & CCM_ANALOG_PFD_480_PFD0_FRAC_MASK) >> - CCM_ANALOG_PFD_480_PFD0_FRAC_SHIFT; - freq *= 18; + CLOCK_DisableClock(clk_name); - return freq; -} - -void flexspi_clock_set_div(uint32_t value) -{ - CLOCK_DisableClock(kCLOCK_FlexSpi); + CLOCK_SetDiv(div_sel, divider); - CLOCK_SetDiv(kCLOCK_FlexspiDiv, value); - - CLOCK_EnableClock(kCLOCK_FlexSpi); -} - -uint32_t flexspi_clock_get_freq(void) -{ - uint32_t divider; - uint32_t frequency; + CLOCK_EnableClock(clk_name); - divider = CLOCK_GetDiv(kCLOCK_FlexspiDiv); + FLEXSPI_Enable(flexspi, true); - frequency = clock_get_usb1_pll_pfd0_clk() / (divider + 1); + FLEXSPI_SoftwareReset(flexspi); - return frequency; + return 0; } diff --git a/soc/arm/nxp_imx/rt/soc.h b/soc/arm/nxp_imx/rt/soc.h index d7e52ba751d..e5129c947d0 100644 --- a/soc/arm/nxp_imx/rt/soc.h +++ b/soc/arm/nxp_imx/rt/soc.h @@ -32,8 +32,9 @@ void imxrt_pre_init_display_interface(void); void imxrt_post_init_display_interface(void); #endif -void flexspi_clock_set_div(uint32_t value); -uint32_t flexspi_clock_get_freq(void); +#ifdef CONFIG_MEMC +uint32_t flexspi_clock_set_freq(uint32_t clock_name, uint32_t rate); +#endif #ifdef __cplusplus } From a10fee2d5e99282799fac8d36506feb05cbbf540 Mon Sep 17 00:00:00 2001 From: Daniel DeGrasse Date: Thu, 24 Aug 2023 14:55:30 -0500 Subject: [PATCH 3274/3723] drivers: clock_control: ccm_rev2: add support for reclocking FlexSPI Add support for reclocking flexspi in ccm_rev2 driver. Clock update functions are provided for the RT11xx. Signed-off-by: Daniel DeGrasse --- .../clock_control_mcux_ccm_rev2.c | 44 ++++++++++++++ soc/arm/nxp_imx/rt/CMakeLists.txt | 8 +++ soc/arm/nxp_imx/rt/flexspi_rt11xx.c | 60 +++++++++++++++++++ 3 files changed, 112 insertions(+) create mode 100644 soc/arm/nxp_imx/rt/flexspi_rt11xx.c diff --git a/drivers/clock_control/clock_control_mcux_ccm_rev2.c b/drivers/clock_control/clock_control_mcux_ccm_rev2.c index 8edb33e3798..c99741a78f2 100644 --- a/drivers/clock_control/clock_control_mcux_ccm_rev2.c +++ b/drivers/clock_control/clock_control_mcux_ccm_rev2.c @@ -132,6 +132,14 @@ static int mcux_ccm_get_subsys_rate(const struct device *dev, *rate = 393216000 / divider; return 0; +#endif +#ifdef CONFIG_MEMC_MCUX_FLEXSPI + case IMX_CCM_FLEXSPI_CLK: + clock_root = kCLOCK_Root_Flexspi1; + break; + case IMX_CCM_FLEXSPI2_CLK: + clock_root = kCLOCK_Root_Flexspi2; + break; #endif default: return -EINVAL; @@ -144,10 +152,46 @@ static int mcux_ccm_get_subsys_rate(const struct device *dev, return 0; } +/* + * Since this function is used to reclock the FlexSPI when running in + * XIP, it must be located in RAM when MEMC driver is enabled. + */ +#ifdef CONFIG_MEMC_MCUX_FLEXSPI +#define CCM_SET_FUNC_ATTR __ramfunc +#else +#define CCM_SET_FUNC_ATTR +#endif + +static int CCM_SET_FUNC_ATTR mcux_ccm_set_subsys_rate(const struct device *dev, + clock_control_subsys_t subsys, + clock_control_subsys_rate_t rate) +{ + uint32_t clock_name = (uintptr_t)subsys; + uint32_t clock_rate = (uintptr_t)rate; + + switch (clock_name) { + case IMX_CCM_FLEXSPI_CLK: + __fallthrough; + case IMX_CCM_FLEXSPI2_CLK: +#if defined(CONFIG_SOC_SERIES_IMX_RT11XX) && defined(CONFIG_MEMC_MCUX_FLEXSPI) + /* The SOC is using the FlexSPI for XIP. Therefore, + * the FlexSPI itself must be managed within the function, + * which is SOC specific. + */ + return flexspi_clock_set_freq(clock_name, clock_rate); +#endif + default: + /* Silence unused variable warning */ + ARG_UNUSED(clock_rate); + return -ENOTSUP; + } +} + static const struct clock_control_driver_api mcux_ccm_driver_api = { .on = mcux_ccm_on, .off = mcux_ccm_off, .get_rate = mcux_ccm_get_subsys_rate, + .set_rate = mcux_ccm_set_subsys_rate, }; DEVICE_DT_INST_DEFINE(0, NULL, NULL, NULL, NULL, PRE_KERNEL_1, diff --git a/soc/arm/nxp_imx/rt/CMakeLists.txt b/soc/arm/nxp_imx/rt/CMakeLists.txt index e88fc46e28e..a8f1d00765a 100644 --- a/soc/arm/nxp_imx/rt/CMakeLists.txt +++ b/soc/arm/nxp_imx/rt/CMakeLists.txt @@ -35,6 +35,14 @@ if (CONFIG_SOC_SERIES_IMX_RT10XX AND CONFIG_MEMC_MCUX_FLEXSPI) endif() endif () + +if (CONFIG_SOC_SERIES_IMX_RT11XX AND CONFIG_MEMC_MCUX_FLEXSPI) + zephyr_sources(flexspi_rt11xx.c) + if (CONFIG_FLASH_MCUX_FLEXSPI_XIP) + zephyr_code_relocate(FILES flexspi_rt11xx.c LOCATION ITCM_TEXT) + endif() +endif () + if (CONFIG_PM AND CONFIG_SOC_SERIES_IMX_RT10XX) zephyr_sources(power_rt10xx.c) zephyr_code_relocate(FILES power_rt10xx.c LOCATION ITCM_TEXT) diff --git a/soc/arm/nxp_imx/rt/flexspi_rt11xx.c b/soc/arm/nxp_imx/rt/flexspi_rt11xx.c new file mode 100644 index 00000000000..8b8b34d8682 --- /dev/null +++ b/soc/arm/nxp_imx/rt/flexspi_rt11xx.c @@ -0,0 +1,60 @@ +/* + * Copyright (c) 2023, NXP + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include +#include +#include +#include +#include +#include + +uint32_t flexspi_clock_set_freq(uint32_t clock_name, uint32_t rate) +{ + clock_name_t root; + uint32_t root_rate; + FLEXSPI_Type *flexspi; + clock_root_t flexspi_clk; + clock_ip_name_t clk_gate; + uint32_t divider; + + switch (clock_name) { + case IMX_CCM_FLEXSPI_CLK: + flexspi_clk = kCLOCK_Root_Flexspi1; + flexspi = (FLEXSPI_Type *)DT_REG_ADDR(DT_NODELABEL(flexspi)); + clk_gate = kCLOCK_Flexspi1; + break; + case IMX_CCM_FLEXSPI2_CLK: + flexspi_clk = kCLOCK_Root_Flexspi2; + flexspi = (FLEXSPI_Type *)DT_REG_ADDR(DT_NODELABEL(flexspi2)); + clk_gate = kCLOCK_Flexspi2; + break; + default: + return -ENOTSUP; + } + root = CLOCK_GetRootClockSource(flexspi_clk, + CLOCK_GetRootClockMux(flexspi_clk)); + /* Get clock root frequency */ + root_rate = CLOCK_GetFreq(root); + /* Select a divider based on root frequency */ + divider = MIN((root_rate / rate), CCM_CLOCK_ROOT_CONTROL_DIV_MASK); + + while (FLEXSPI_GetBusIdleStatus(flexspi) == false) { + /* Spin */ + } + FLEXSPI_Enable(flexspi, false); + + CLOCK_DisableClock(clk_gate); + + CLOCK_SetRootClockDiv(flexspi_clk, divider); + + CLOCK_EnableClock(clk_gate); + + FLEXSPI_Enable(flexspi, true); + + FLEXSPI_SoftwareReset(flexspi); + + return 0; +} From 9d7a3fb647e8ab7472ab67bb00f52e1cd918966f Mon Sep 17 00:00:00 2001 From: Daniel DeGrasse Date: Fri, 18 Aug 2023 20:29:54 +0000 Subject: [PATCH 3275/3723] drivers: flash: flash_flexspi_nor: support SFDP probe Support SFDP probe in flexspi nor driver. This probe will allow the flash driver to dynamically configure quad spi flashes for 1-4-4 mode, expanding the flash chips supported with this driver. The following data is read from the SFDP header: - quad enable method - fast read command (1-4-4 is maximum supported) Fixes #55379 Signed-off-by: Daniel DeGrasse --- drivers/flash/CMakeLists.txt | 1 + drivers/flash/Kconfig.mcux | 1 + drivers/flash/flash_mcux_flexspi_nor.c | 796 +++++++++++++++++++++---- drivers/memc/memc_mcux_flexspi.h | 2 + 4 files changed, 675 insertions(+), 125 deletions(-) diff --git a/drivers/flash/CMakeLists.txt b/drivers/flash/CMakeLists.txt index 6b896288d14..46694eb4792 100644 --- a/drivers/flash/CMakeLists.txt +++ b/drivers/flash/CMakeLists.txt @@ -59,6 +59,7 @@ if(CONFIG_FLASH_MCUX_FLEXSPI_XIP) dt_prop(compat_flash PATH ${chosen_flash} PROPERTY compatible) if(compat_flash MATCHES "nxp,imx-flexspi-nor") zephyr_code_relocate(FILES flash_mcux_flexspi_nor.c LOCATION ${CONFIG_FLASH_MCUX_FLEXSPI_XIP_MEM}_TEXT) + zephyr_code_relocate(FILES jesd216.c LOCATION ${CONFIG_FLASH_MCUX_FLEXSPI_XIP_MEM}_TEXT) elseif(compat_flash MATCHES "nxp,imx-flexspi-mx25um51345g") zephyr_code_relocate(FILES flash_mcux_flexspi_mx25um51345g.c LOCATION ${CONFIG_FLASH_MCUX_FLEXSPI_XIP_MEM}_TEXT) elseif(compat_flash MATCHES "nxp,imx-flexspi-hyperflash") diff --git a/drivers/flash/Kconfig.mcux b/drivers/flash/Kconfig.mcux index 89d411f064b..ec7f5be22b2 100644 --- a/drivers/flash/Kconfig.mcux +++ b/drivers/flash/Kconfig.mcux @@ -40,6 +40,7 @@ config FLASH_MCUX_FLEXSPI_NOR depends on DT_HAS_NXP_IMX_FLEXSPI_NOR_ENABLED select FLASH_HAS_PAGE_LAYOUT select FLASH_HAS_DRIVER_ENABLED + select FLASH_JESD216 select MEMC select MEMC_MCUX_FLEXSPI diff --git a/drivers/flash/flash_mcux_flexspi_nor.c b/drivers/flash/flash_mcux_flexspi_nor.c index 8a9c4f182ad..bfcef6daebd 100644 --- a/drivers/flash/flash_mcux_flexspi_nor.c +++ b/drivers/flash/flash_mcux_flexspi_nor.c @@ -6,11 +6,13 @@ #define DT_DRV_COMPAT nxp_imx_flexspi_nor +#include #include #include #include #include #include "spi_nor.h" +#include "jesd216.h" #include "memc_mcux_flexspi.h" #ifdef CONFIG_HAS_MCUX_CACHE @@ -40,22 +42,21 @@ static uint8_t nor_write_buf[SPI_NOR_PAGE_SIZE]; LOG_MODULE_REGISTER(flash_flexspi_nor, CONFIG_FLASH_LOG_LEVEL); enum { - /* Instructions matching with XIP layout */ - READ_FAST_QUAD_OUTPUT, - READ_FAST_OUTPUT, - READ_NORMAL_OUTPUT, + READ, + PAGE_PROGRAM, READ_STATUS, WRITE_ENABLE, ERASE_SECTOR, ERASE_BLOCK, - PAGE_PROGRAM_INPUT, - PAGE_PROGRAM_QUAD_INPUT, READ_ID, - WRITE_STATUS_REG, - ENTER_QPI, - EXIT_QPI, READ_STATUS_REG, ERASE_CHIP, + READ_JESD216, + /* Used for temporary commands during initialization */ + SCRATCH_CMD, + SCRATCH_CMD2, + /* Must be last entry */ + FLEXSPI_INSTR_END, }; struct flash_flexspi_nor_config { @@ -71,98 +72,70 @@ struct flash_flexspi_nor_data { struct device controller; flexspi_device_config_t config; flexspi_port_t port; + bool legacy_poll; struct flash_pages_layout layout; struct flash_parameters flash_parameters; }; -static const uint32_t flash_flexspi_nor_lut[][4] = { - [READ_ID] = { - FLEXSPI_LUT_SEQ(kFLEXSPI_Command_SDR, kFLEXSPI_1PAD, SPI_NOR_CMD_RDID, - kFLEXSPI_Command_READ_SDR, kFLEXSPI_1PAD, 0x04), +/* Initial LUT table */ +static const uint32_t flash_flexspi_nor_base_lut[][MEMC_FLEXSPI_CMD_PER_SEQ] = { + /* 1S-1S-1S flash read command, should be compatible with all SPI nor flashes */ + [READ] = { + FLEXSPI_LUT_SEQ(kFLEXSPI_Command_SDR, kFLEXSPI_1PAD, SPI_NOR_CMD_READ, + kFLEXSPI_Command_RADDR_SDR, kFLEXSPI_1PAD, 24), + FLEXSPI_LUT_SEQ(kFLEXSPI_Command_READ_SDR, kFLEXSPI_1PAD, 0x1, + kFLEXSPI_Command_STOP, kFLEXSPI_1PAD, 0x0), }, - - [READ_STATUS_REG] = { - FLEXSPI_LUT_SEQ(kFLEXSPI_Command_SDR, kFLEXSPI_1PAD, SPI_NOR_CMD_RDSR, - kFLEXSPI_Command_READ_SDR, kFLEXSPI_1PAD, 0x04), + [READ_JESD216] = { + /* Install read SFDP command */ + FLEXSPI_LUT_SEQ(kFLEXSPI_Command_SDR, kFLEXSPI_1PAD, JESD216_CMD_READ_SFDP, + kFLEXSPI_Command_RADDR_SDR, kFLEXSPI_1PAD, 24), + FLEXSPI_LUT_SEQ(kFLEXSPI_Command_DUMMY_SDR, kFLEXSPI_1PAD, 8, + kFLEXSPI_Command_READ_SDR, kFLEXSPI_1PAD, 0x4), + FLEXSPI_LUT_SEQ(kFLEXSPI_Command_STOP, kFLEXSPI_1PAD, 0x0, + kFLEXSPI_Command_STOP, kFLEXSPI_1PAD, 0x0), }, - - [WRITE_STATUS_REG] = { - FLEXSPI_LUT_SEQ(kFLEXSPI_Command_SDR, kFLEXSPI_1PAD, SPI_NOR_CMD_WRSR, - kFLEXSPI_Command_WRITE_SDR, kFLEXSPI_1PAD, 0x04), + /* Standard 1S-1S-1S flash write command, can be switched to 1S-1S-4S when QE is set */ + [PAGE_PROGRAM] = { + FLEXSPI_LUT_SEQ(kFLEXSPI_Command_SDR, kFLEXSPI_1PAD, SPI_NOR_CMD_PP, + kFLEXSPI_Command_RADDR_SDR, kFLEXSPI_1PAD, 0x18), + FLEXSPI_LUT_SEQ(kFLEXSPI_Command_WRITE_SDR, kFLEXSPI_1PAD, 0x04, + kFLEXSPI_Command_STOP, kFLEXSPI_1PAD, 0), }, [WRITE_ENABLE] = { - FLEXSPI_LUT_SEQ(kFLEXSPI_Command_SDR, kFLEXSPI_1PAD, SPI_NOR_CMD_WREN, - kFLEXSPI_Command_STOP, kFLEXSPI_1PAD, 0), + FLEXSPI_LUT_SEQ(kFLEXSPI_Command_SDR, kFLEXSPI_1PAD, SPI_NOR_CMD_WREN, + kFLEXSPI_Command_STOP, kFLEXSPI_1PAD, 0), }, [ERASE_SECTOR] = { - FLEXSPI_LUT_SEQ(kFLEXSPI_Command_SDR, kFLEXSPI_1PAD, SPI_NOR_CMD_SE, + FLEXSPI_LUT_SEQ(kFLEXSPI_Command_SDR, kFLEXSPI_1PAD, SPI_NOR_CMD_SE, kFLEXSPI_Command_RADDR_SDR, kFLEXSPI_1PAD, 0x18), }, [ERASE_BLOCK] = { - FLEXSPI_LUT_SEQ(kFLEXSPI_Command_SDR, kFLEXSPI_1PAD, SPI_NOR_CMD_BE, + FLEXSPI_LUT_SEQ(kFLEXSPI_Command_SDR, kFLEXSPI_1PAD, SPI_NOR_CMD_BE, kFLEXSPI_Command_RADDR_SDR, kFLEXSPI_1PAD, 0x18), }, [ERASE_CHIP] = { - FLEXSPI_LUT_SEQ(kFLEXSPI_Command_SDR, kFLEXSPI_1PAD, SPI_NOR_CMD_CE, - kFLEXSPI_Command_STOP, kFLEXSPI_1PAD, 0), - }, - - [READ_FAST_QUAD_OUTPUT] = { - FLEXSPI_LUT_SEQ(kFLEXSPI_Command_SDR, kFLEXSPI_1PAD, 0x6B, - kFLEXSPI_Command_RADDR_SDR, kFLEXSPI_1PAD, 0x18), - FLEXSPI_LUT_SEQ(kFLEXSPI_Command_DUMMY_SDR, kFLEXSPI_4PAD, 0x08, - kFLEXSPI_Command_READ_SDR, kFLEXSPI_4PAD, 0x04), + FLEXSPI_LUT_SEQ(kFLEXSPI_Command_SDR, kFLEXSPI_1PAD, SPI_NOR_CMD_CE, + kFLEXSPI_Command_STOP, kFLEXSPI_1PAD, 0), }, - [READ_FAST_OUTPUT] = { - FLEXSPI_LUT_SEQ(kFLEXSPI_Command_SDR, kFLEXSPI_1PAD, 0x0B, - kFLEXSPI_Command_RADDR_SDR, kFLEXSPI_1PAD, 0x18), - FLEXSPI_LUT_SEQ(kFLEXSPI_Command_DUMMY_SDR, kFLEXSPI_1PAD, 0x08, - kFLEXSPI_Command_READ_SDR, kFLEXSPI_1PAD, 0x04), - }, - - [READ_NORMAL_OUTPUT] = { - FLEXSPI_LUT_SEQ(kFLEXSPI_Command_SDR, kFLEXSPI_1PAD, SPI_NOR_CMD_READ, - kFLEXSPI_Command_RADDR_SDR, kFLEXSPI_1PAD, 0x18), - FLEXSPI_LUT_SEQ(kFLEXSPI_Command_READ_SDR, kFLEXSPI_1PAD, 0x04, - kFLEXSPI_Command_STOP, kFLEXSPI_1PAD, 0), - }, - - [READ_STATUS] = { - FLEXSPI_LUT_SEQ(kFLEXSPI_Command_SDR, kFLEXSPI_1PAD, 0x81, - kFLEXSPI_Command_READ_SDR, kFLEXSPI_1PAD, 0x04), - }, - - [PAGE_PROGRAM_INPUT] = { - FLEXSPI_LUT_SEQ(kFLEXSPI_Command_SDR, kFLEXSPI_1PAD, SPI_NOR_CMD_PP, - kFLEXSPI_Command_RADDR_SDR, kFLEXSPI_1PAD, 0x18), - FLEXSPI_LUT_SEQ(kFLEXSPI_Command_WRITE_SDR, kFLEXSPI_1PAD, 0x04, - kFLEXSPI_Command_STOP, kFLEXSPI_1PAD, 0), - }, - - [PAGE_PROGRAM_QUAD_INPUT] = { - FLEXSPI_LUT_SEQ(kFLEXSPI_Command_SDR, kFLEXSPI_1PAD, 0x32, - kFLEXSPI_Command_RADDR_SDR, kFLEXSPI_1PAD, 0x18), - FLEXSPI_LUT_SEQ(kFLEXSPI_Command_WRITE_SDR, kFLEXSPI_4PAD, 0x04, - kFLEXSPI_Command_STOP, kFLEXSPI_1PAD, 0), - }, - - [ENTER_QPI] = { - FLEXSPI_LUT_SEQ(kFLEXSPI_Command_SDR, kFLEXSPI_1PAD, 0x35, - kFLEXSPI_Command_STOP, kFLEXSPI_1PAD, 0), + [READ_ID] = { + FLEXSPI_LUT_SEQ(kFLEXSPI_Command_SDR, kFLEXSPI_1PAD, SPI_NOR_CMD_RDID, + kFLEXSPI_Command_READ_SDR, kFLEXSPI_1PAD, 0x01), }, - [EXIT_QPI] = { - FLEXSPI_LUT_SEQ(kFLEXSPI_Command_SDR, kFLEXSPI_4PAD, 0xF5, - kFLEXSPI_Command_STOP, kFLEXSPI_1PAD, 0), + [READ_STATUS_REG] = { + FLEXSPI_LUT_SEQ(kFLEXSPI_Command_SDR, kFLEXSPI_1PAD, SPI_NOR_CMD_RDSR, + kFLEXSPI_Command_READ_SDR, kFLEXSPI_1PAD, 0x01), }, }; -static int flash_flexspi_nor_get_vendor_id(struct flash_flexspi_nor_data *data, +/* Helper so we can read flash ID without flash access for XIP */ +static int flash_flexspi_nor_read_id_helper(struct flash_flexspi_nor_data *data, uint8_t *vendor_id) { uint32_t buffer = 0; @@ -175,49 +148,42 @@ static int flash_flexspi_nor_get_vendor_id(struct flash_flexspi_nor_data *data, .SeqNumber = 1, .seqIndex = READ_ID, .data = &buffer, - .dataSize = 1, + .dataSize = 3, }; LOG_DBG("Reading id"); ret = memc_flexspi_transfer(&data->controller, &transfer); - *vendor_id = buffer; + if (ret < 0) { + return ret; + } + + memcpy(vendor_id, &buffer, 3); return ret; } -static int flash_flexspi_nor_read_status(struct flash_flexspi_nor_data *data, - uint32_t *status) +static int flash_flexspi_nor_read_id(const struct device *dev, uint8_t *vendor_id) { - flexspi_transfer_t transfer = { - .deviceAddress = 0, - .port = data->port, - .cmdType = kFLEXSPI_Read, - .SeqNumber = 1, - .seqIndex = READ_STATUS_REG, - .data = status, - .dataSize = 1, - }; - - LOG_DBG("Reading status register"); + struct flash_flexspi_nor_data *data = dev->data; - return memc_flexspi_transfer(&data->controller, &transfer); + return flash_flexspi_nor_read_id_helper(data, vendor_id); } -static int flash_flexspi_nor_write_status(struct flash_flexspi_nor_data *data, +static int flash_flexspi_nor_read_status(struct flash_flexspi_nor_data *data, uint32_t *status) { flexspi_transfer_t transfer = { .deviceAddress = 0, .port = data->port, - .cmdType = kFLEXSPI_Write, + .cmdType = kFLEXSPI_Read, .SeqNumber = 1, - .seqIndex = WRITE_STATUS_REG, + .seqIndex = READ_STATUS_REG, .data = status, .dataSize = 1, }; - LOG_DBG("Writing status register"); + LOG_DBG("Reading status register"); return memc_flexspi_transfer(&data->controller, &transfer); } @@ -300,7 +266,7 @@ static int flash_flexspi_nor_page_program(struct flash_flexspi_nor_data *data, .port = data->port, .cmdType = kFLEXSPI_Write, .SeqNumber = 1, - .seqIndex = PAGE_PROGRAM_QUAD_INPUT, + .seqIndex = PAGE_PROGRAM, .data = (uint32_t *) buffer, .dataSize = len, }; @@ -315,25 +281,24 @@ static int flash_flexspi_nor_wait_bus_busy(struct flash_flexspi_nor_data *data) uint32_t status = 0; int ret; - do { + while (1) { ret = flash_flexspi_nor_read_status(data, &status); LOG_DBG("status: 0x%x", status); if (ret) { LOG_ERR("Could not read status"); return ret; } - } while (status & BIT(0)); - - return 0; -} -static int flash_flexspi_nor_enable_quad_mode(struct flash_flexspi_nor_data *data) -{ - uint32_t status = 0x40; - - flash_flexspi_nor_write_status(data, &status); - flash_flexspi_nor_wait_bus_busy(data); - memc_flexspi_reset(&data->controller); + if (data->legacy_poll) { + if ((status & BIT(0)) == 0) { + break; + } + } else { + if (status & BIT(7)) { + break; + } + } + } return 0; } @@ -494,11 +459,583 @@ static void flash_flexspi_nor_pages_layout(const struct device *dev, } #endif /* CONFIG_FLASH_PAGE_LAYOUT */ + +/* + * This function enables quad mode, when supported. Otherwise it + * returns an error. + * @param dev: Flexspi device + * @param flexspi_lut: flexspi lut table, useful if instruction writes are needed + * @param qer: DW15 quad enable parameter + * @return 0 if quad mode was entered, or -ENOTSUP if quad mode is not supported + */ +static int flash_flexspi_nor_quad_enable(struct flash_flexspi_nor_data *data, + uint32_t (*flexspi_lut)[MEMC_FLEXSPI_CMD_PER_SEQ], + uint8_t qer) +{ + int ret; + uint32_t buffer = 0; + uint16_t bit = 0; + uint8_t rd_size, wr_size; + flexspi_transfer_t transfer = { + .deviceAddress = 0, + .port = data->port, + .SeqNumber = 1, + .data = &buffer, + }; + flexspi_device_config_t config = { + .flexspiRootClk = MHZ(50), + .flashSize = FLEXSPI_FLSHCR0_FLSHSZ_MASK, /* Max flash size */ + .ARDSeqNumber = 1, + .ARDSeqIndex = READ, + }; + + switch (qer) { + case JESD216_DW15_QER_VAL_NONE: + /* No init needed */ + return 0; + case JESD216_DW15_QER_VAL_S2B1v1: + case JESD216_DW15_QER_VAL_S2B1v4: + /* Install read and write status command */ + flexspi_lut[SCRATCH_CMD][0] = FLEXSPI_LUT_SEQ( + kFLEXSPI_Command_SDR, kFLEXSPI_1PAD, SPI_NOR_CMD_RDSR, + kFLEXSPI_Command_READ_SDR, kFLEXSPI_1PAD, 0x1); + flexspi_lut[SCRATCH_CMD2][0] = FLEXSPI_LUT_SEQ( + kFLEXSPI_Command_SDR, kFLEXSPI_1PAD, SPI_NOR_CMD_WRSR, + kFLEXSPI_Command_WRITE_SDR, kFLEXSPI_1PAD, 0x1); + + /* Set bit 1 of status register 2 */ + bit = BIT(9); + rd_size = 2; + wr_size = 2; + break; + case JESD216_DW15_QER_VAL_S1B6: + /* Install read and write status command */ + flexspi_lut[SCRATCH_CMD][0] = FLEXSPI_LUT_SEQ( + kFLEXSPI_Command_SDR, kFLEXSPI_1PAD, SPI_NOR_CMD_RDSR, + kFLEXSPI_Command_READ_SDR, kFLEXSPI_1PAD, 0x1); + flexspi_lut[SCRATCH_CMD2][0] = FLEXSPI_LUT_SEQ( + kFLEXSPI_Command_SDR, kFLEXSPI_1PAD, SPI_NOR_CMD_WRSR, + kFLEXSPI_Command_WRITE_SDR, kFLEXSPI_1PAD, 0x1); + + /* Set bit 6 of status register 1 */ + bit = BIT(6); + rd_size = 1; + wr_size = 1; + break; + case JESD216_DW15_QER_VAL_S2B7: + /* Install read and write status command */ + flexspi_lut[SCRATCH_CMD][0] = FLEXSPI_LUT_SEQ( + kFLEXSPI_Command_SDR, kFLEXSPI_1PAD, 0x3F, + kFLEXSPI_Command_READ_SDR, kFLEXSPI_1PAD, 0x1); + flexspi_lut[SCRATCH_CMD2][0] = FLEXSPI_LUT_SEQ( + kFLEXSPI_Command_SDR, kFLEXSPI_1PAD, 0x3E, + kFLEXSPI_Command_WRITE_SDR, kFLEXSPI_1PAD, 0x1); + + /* Set bit 7 of status register 2 */ + bit = BIT(7); + rd_size = 1; + wr_size = 1; + break; + case JESD216_DW15_QER_VAL_S2B1v5: + /* Install read and write status command */ + flexspi_lut[SCRATCH_CMD][0] = FLEXSPI_LUT_SEQ( + kFLEXSPI_Command_SDR, kFLEXSPI_1PAD, SPI_NOR_CMD_RDSR2, + kFLEXSPI_Command_READ_SDR, kFLEXSPI_1PAD, 0x1); + flexspi_lut[SCRATCH_CMD2][0] = FLEXSPI_LUT_SEQ( + kFLEXSPI_Command_SDR, kFLEXSPI_1PAD, SPI_NOR_CMD_WRSR, + kFLEXSPI_Command_WRITE_SDR, kFLEXSPI_1PAD, 0x1); + + /* Set bit 1 of status register 2 */ + bit = BIT(9); + rd_size = 1; + wr_size = 2; + break; + case JESD216_DW15_QER_VAL_S2B1v6: + /* Install read and write status command */ + flexspi_lut[SCRATCH_CMD][0] = FLEXSPI_LUT_SEQ( + kFLEXSPI_Command_SDR, kFLEXSPI_1PAD, SPI_NOR_CMD_RDSR2, + kFLEXSPI_Command_READ_SDR, kFLEXSPI_1PAD, 0x1); + flexspi_lut[SCRATCH_CMD2][0] = FLEXSPI_LUT_SEQ( + kFLEXSPI_Command_SDR, kFLEXSPI_1PAD, SPI_NOR_CMD_WRSR2, + kFLEXSPI_Command_WRITE_SDR, kFLEXSPI_1PAD, 0x1); + + /* Set bit 7 of status register 2 */ + bit = BIT(7); + rd_size = 1; + wr_size = 1; + break; + default: + return -ENOTSUP; + } + ret = memc_flexspi_set_device_config(&data->controller, + &config, + (uint32_t *)flexspi_lut, + FLEXSPI_INSTR_END * MEMC_FLEXSPI_CMD_PER_SEQ, + data->port); + if (ret < 0) { + return ret; + } + transfer.dataSize = rd_size; + transfer.seqIndex = SCRATCH_CMD; + transfer.cmdType = kFLEXSPI_Read; + /* Read status register */ + ret = memc_flexspi_transfer(&data->controller, &transfer); + if (ret < 0) { + return ret; + } + buffer |= bit; + transfer.dataSize = wr_size; + transfer.seqIndex = SCRATCH_CMD2; + transfer.cmdType = kFLEXSPI_Write; + return memc_flexspi_transfer(&data->controller, &transfer); +} + +/* + * This function enables 4 byte addressing, when supported. Otherwise it + * returns an error. + * @param dev: Flexspi device + * @param flexspi_lut: flexspi lut table, useful if instruction writes are needed + * @param en4b: DW16 enable 4 byte mode parameter + * @return 0 if 4 byte mode was entered, or -ENOTSUP if 4 byte mode was not supported + */ +static int flash_flexspi_nor_4byte_enable(struct flash_flexspi_nor_data *data, + uint32_t (*flexspi_lut)[MEMC_FLEXSPI_CMD_PER_SEQ], + uint32_t en4b) +{ + int ret; + uint32_t buffer = 0; + flexspi_transfer_t transfer = { + .deviceAddress = 0, + .port = data->port, + .SeqNumber = 1, + .data = &buffer, + }; + flexspi_device_config_t config = { + .flexspiRootClk = MHZ(50), + .flashSize = FLEXSPI_FLSHCR0_FLSHSZ_MASK, /* Max flash size */ + .ARDSeqNumber = 1, + .ARDSeqIndex = READ, + }; + if (en4b & BIT(6)) { + /* Flash is always in 4 byte mode. We just need to configure LUT */ + return 0; + } else if (en4b & BIT(5)) { + /* Dedicated vendor instruction set, which we don't support. Exit here */ + return -ENOTSUP; + } else if (en4b & BIT(4)) { + /* Set bit 0 of 16 bit configuration register */ + flexspi_lut[SCRATCH_CMD][0] = FLEXSPI_LUT_SEQ( + kFLEXSPI_Command_SDR, kFLEXSPI_1PAD, 0xB5, + kFLEXSPI_Command_READ_SDR, kFLEXSPI_1PAD, 0x1); + flexspi_lut[SCRATCH_CMD2][0] = FLEXSPI_LUT_SEQ( + kFLEXSPI_Command_SDR, kFLEXSPI_1PAD, 0xB1, + kFLEXSPI_Command_WRITE_SDR, kFLEXSPI_1PAD, 0x1); + ret = memc_flexspi_set_device_config(&data->controller, + &config, + (uint32_t *)flexspi_lut, + FLEXSPI_INSTR_END * MEMC_FLEXSPI_CMD_PER_SEQ, + data->port); + if (ret < 0) { + return ret; + } + transfer.dataSize = 2; + transfer.seqIndex = SCRATCH_CMD; + transfer.cmdType = kFLEXSPI_Read; + /* Read config register */ + ret = memc_flexspi_transfer(&data->controller, &transfer); + if (ret < 0) { + return ret; + } + buffer |= BIT(0); + /* Set config register */ + transfer.seqIndex = SCRATCH_CMD2; + transfer.cmdType = kFLEXSPI_Read; + return memc_flexspi_transfer(&data->controller, &transfer); + } else if (en4b & BIT(1)) { + /* Issue write enable, then instruction 0xB7 */ + flash_flexspi_nor_write_enable(data); + flexspi_lut[SCRATCH_CMD][0] = FLEXSPI_LUT_SEQ( + kFLEXSPI_Command_SDR, kFLEXSPI_1PAD, 0xB7, + kFLEXSPI_Command_STOP, kFLEXSPI_1PAD, 0x0); + ret = memc_flexspi_set_device_config(&data->controller, + &config, + (uint32_t *)flexspi_lut, + FLEXSPI_INSTR_END * MEMC_FLEXSPI_CMD_PER_SEQ, + data->port); + if (ret < 0) { + return ret; + } + transfer.dataSize = 0; + transfer.seqIndex = SCRATCH_CMD; + transfer.cmdType = kFLEXSPI_Command; + return memc_flexspi_transfer(&data->controller, &transfer); + } else if (en4b & BIT(0)) { + /* Issue instruction 0xB7 */ + flexspi_lut[SCRATCH_CMD][0] = FLEXSPI_LUT_SEQ( + kFLEXSPI_Command_SDR, kFLEXSPI_1PAD, 0xB7, + kFLEXSPI_Command_STOP, kFLEXSPI_1PAD, 0x0); + ret = memc_flexspi_set_device_config(&data->controller, + &config, + (uint32_t *)flexspi_lut, + FLEXSPI_INSTR_END * MEMC_FLEXSPI_CMD_PER_SEQ, + data->port); + if (ret < 0) { + return ret; + } + transfer.dataSize = 0; + transfer.seqIndex = SCRATCH_CMD; + transfer.cmdType = kFLEXSPI_Command; + return memc_flexspi_transfer(&data->controller, &transfer); + } + /* Other methods not supported */ + return -ENOTSUP; +} + +/* + * This function configures the FlexSPI to manage the flash device + * based on values in SFDP header + * @param data: Flexspi device data + * @param header: SFDP header for flash + * @param bfp: basic flash parameters for flash + * @param flexspi_lut: LUT table, filled with READ LUT command + * @return 0 on success, or negative value on error + */ +static int flash_flexspi_nor_config_flash(struct flash_flexspi_nor_data *data, + struct jesd216_sfdp_header *header, + struct jesd216_bfp *bfp, + uint32_t (*flexspi_lut)[MEMC_FLEXSPI_CMD_PER_SEQ]) +{ + struct jesd216_instr instr; + struct jesd216_bfp_dw16 dw16; + struct jesd216_bfp_dw15 dw15; + struct jesd216_bfp_dw14 dw14; + uint8_t addr_width; + uint8_t mode_cmd; + int ret; + + addr_width = jesd216_bfp_addrbytes(bfp) == + JESD216_SFDP_BFP_DW1_ADDRBYTES_VAL_4B ? 32 : 24; + + /* Check to see if we can enable 4 byte addressing */ + ret = jesd216_bfp_decode_dw16(&header->phdr[0], bfp, &dw16); + if (ret < 0) { + return ret; + } + + /* Attempt to enable 4 byte addressing */ + ret = flash_flexspi_nor_4byte_enable(data, flexspi_lut, dw16.enter_4ba); + if (ret == 0) { + /* Use 4 byte address width */ + addr_width = 32; + /* Update LUT for ERASE_SECTOR and ERASE_BLOCK to use 32 bit addr */ + flexspi_lut[ERASE_SECTOR][0] = FLEXSPI_LUT_SEQ( + kFLEXSPI_Command_SDR, kFLEXSPI_1PAD, SPI_NOR_CMD_SE, + kFLEXSPI_Command_RADDR_SDR, kFLEXSPI_1PAD, addr_width); + flexspi_lut[ERASE_BLOCK][0] = FLEXSPI_LUT_SEQ( + kFLEXSPI_Command_SDR, kFLEXSPI_1PAD, SPI_NOR_CMD_BE, + kFLEXSPI_Command_RADDR_SDR, kFLEXSPI_1PAD, addr_width); + } + /* Extract the read command. + * Note- enhanced XIP not currently supported, nor is 4-4-4 mode. + */ + if (jesd216_bfp_read_support(&header->phdr[0], bfp, + JESD216_MODE_144, &instr) > 0) { + LOG_DBG("Enable 144 mode"); + /* Configure for 144 QUAD read mode */ + if (instr.mode_clocks == 2) { + mode_cmd = kFLEXSPI_Command_MODE8_SDR; + } else if (instr.mode_clocks == 1) { + mode_cmd = kFLEXSPI_Command_MODE4_SDR; + } else if (instr.mode_clocks == 0) { + /* Just send dummy cycles during mode clock period */ + mode_cmd = kFLEXSPI_Command_DUMMY_SDR; + } else { + return -ENOTSUP; + } + flexspi_lut[READ][0] = FLEXSPI_LUT_SEQ( + kFLEXSPI_Command_SDR, kFLEXSPI_1PAD, instr.instr, + kFLEXSPI_Command_RADDR_SDR, kFLEXSPI_4PAD, addr_width); + /* Note- we always set mode bits to 0x0 */ + flexspi_lut[READ][1] = FLEXSPI_LUT_SEQ( + mode_cmd, kFLEXSPI_4PAD, 0x00, + kFLEXSPI_Command_DUMMY_SDR, kFLEXSPI_4PAD, instr.wait_states); + flexspi_lut[READ][2] = FLEXSPI_LUT_SEQ( + kFLEXSPI_Command_READ_SDR, kFLEXSPI_4PAD, 0x04, + kFLEXSPI_Command_STOP, kFLEXSPI_1PAD, 0x0); + /* Read 1S-4S-4S enable method */ + ret = jesd216_bfp_decode_dw15(&header->phdr[0], bfp, &dw15); + if (ret < 0) { + return ret; + } + ret = flash_flexspi_nor_quad_enable(data, flexspi_lut, dw15.qer); + if (ret < 0) { + return ret; + } + /* Now, install 1S-1S-4S page program command */ + flexspi_lut[PAGE_PROGRAM][0] = FLEXSPI_LUT_SEQ( + kFLEXSPI_Command_SDR, kFLEXSPI_1PAD, SPI_NOR_CMD_PP_1_1_4, + kFLEXSPI_Command_RADDR_SDR, kFLEXSPI_1PAD, addr_width); + flexspi_lut[PAGE_PROGRAM][1] = FLEXSPI_LUT_SEQ( + kFLEXSPI_Command_WRITE_SDR, kFLEXSPI_4PAD, 0x4, + kFLEXSPI_Command_STOP, kFLEXSPI_1PAD, 0x0); + + } else if (jesd216_bfp_read_support(&header->phdr[0], bfp, + JESD216_MODE_122, &instr) > 0) { + LOG_DBG("Enable 122 mode"); + if (instr.mode_clocks == 4) { + mode_cmd = kFLEXSPI_Command_MODE8_SDR; + } else if (instr.mode_clocks == 2) { + mode_cmd = kFLEXSPI_Command_MODE4_SDR; + } else if (instr.mode_clocks == 1) { + mode_cmd = kFLEXSPI_Command_MODE2_SDR; + } else if (instr.mode_clocks == 0) { + /* Just send dummy cycles during mode clock period */ + mode_cmd = kFLEXSPI_Command_DUMMY_SDR; + } else { + return -ENOTSUP; + } + flexspi_lut[READ][0] = FLEXSPI_LUT_SEQ( + kFLEXSPI_Command_SDR, kFLEXSPI_1PAD, instr.instr, + kFLEXSPI_Command_RADDR_SDR, kFLEXSPI_2PAD, addr_width); + /* Note- we always set mode bits to 0x0 */ + flexspi_lut[READ][1] = FLEXSPI_LUT_SEQ( + mode_cmd, kFLEXSPI_2PAD, 0x0, + kFLEXSPI_Command_DUMMY_SDR, kFLEXSPI_2PAD, instr.wait_states); + flexspi_lut[READ][2] = FLEXSPI_LUT_SEQ( + kFLEXSPI_Command_READ_SDR, kFLEXSPI_2PAD, 0x02, + kFLEXSPI_Command_STOP, kFLEXSPI_1PAD, 0x0); + /* Now, install 1S-1S-2S page program command */ + flexspi_lut[PAGE_PROGRAM][0] = FLEXSPI_LUT_SEQ( + kFLEXSPI_Command_SDR, kFLEXSPI_1PAD, SPI_NOR_CMD_PP_1_1_2, + kFLEXSPI_Command_RADDR_SDR, kFLEXSPI_1PAD, addr_width); + flexspi_lut[PAGE_PROGRAM][1] = FLEXSPI_LUT_SEQ( + kFLEXSPI_Command_WRITE_SDR, kFLEXSPI_2PAD, 0x4, + kFLEXSPI_Command_STOP, kFLEXSPI_1PAD, 0x0); + } + /* Default to 111 mode if no support exists, leave READ/WRITE untouched */ + + /* Now, read DW14 to determine the polling method we should use while programming */ + ret = jesd216_bfp_decode_dw14(&header->phdr[0], bfp, &dw14); + if (ret < 0) { + return ret; + } + if (dw14.poll_options & BIT(1)) { + /* Read instruction used for polling is 0x70 */ + data->legacy_poll = false; + flexspi_lut[READ_STATUS_REG][0] = FLEXSPI_LUT_SEQ( + kFLEXSPI_Command_SDR, kFLEXSPI_1PAD, 0x70, + kFLEXSPI_Command_READ_SDR, kFLEXSPI_1PAD, 0x01); + } else { + /* Read instruction used for polling is 0x05 */ + data->legacy_poll = true; + flexspi_lut[READ_STATUS_REG][0] = FLEXSPI_LUT_SEQ( + kFLEXSPI_Command_SDR, kFLEXSPI_1PAD, SPI_NOR_CMD_RDSR, + kFLEXSPI_Command_READ_SDR, kFLEXSPI_1PAD, 0x01); + } + + return 0; +} + +/* Helper so we can avoid flash access while performing SFDP probe */ +static int flash_flexspi_nor_sfdp_read_helper(struct flash_flexspi_nor_data *dev_data, + off_t offset, void *data, size_t len) +{ + flexspi_transfer_t transfer = { + .deviceAddress = offset, + .port = dev_data->port, + .cmdType = kFLEXSPI_Read, + .seqIndex = READ_JESD216, + .SeqNumber = 1, + .data = (uint32_t *)data, + .dataSize = len, + }; + + /* Get SFDP data */ + return memc_flexspi_transfer(&dev_data->controller, &transfer); +} + + +#if defined(CONFIG_FLASH_JESD216_API) + +static int flash_flexspi_nor_sfdp_read(const struct device *dev, + off_t offset, void *data, size_t len) +{ + struct flash_flexspi_nor_data *dev_data = dev->data; + + return flash_flexspi_nor_sfdp_read_helper(dev_data, offset, data, len); +} + +#endif + +/* Checks JEDEC ID of flash. If supported, installs custom LUT table */ +static int flash_flexspi_nor_check_jedec(struct flash_flexspi_nor_data *data, + uint32_t (*flexspi_lut)[MEMC_FLEXSPI_CMD_PER_SEQ]) +{ + int ret; + uint32_t vendor_id; + + ret = flash_flexspi_nor_read_id_helper(data, (uint8_t *)&vendor_id); + if (ret < 0) { + return ret; + } + + /* Switch on manufacturer and vendor ID */ + switch (vendor_id & 0xFFFF) { + case 0x25C2: + /* MX25 flash, use 4 byte read/write */ + flexspi_lut[READ][0] = FLEXSPI_LUT_SEQ( + kFLEXSPI_Command_SDR, kFLEXSPI_1PAD, SPI_NOR_CMD_4READ_4B, + kFLEXSPI_Command_RADDR_SDR, kFLEXSPI_4PAD, 32); + /* Flash needs 10 dummy cycles */ + flexspi_lut[READ][1] = FLEXSPI_LUT_SEQ( + kFLEXSPI_Command_DUMMY_SDR, kFLEXSPI_4PAD, 10, + kFLEXSPI_Command_READ_SDR, kFLEXSPI_4PAD, 0x04); + /* Only 1S-4S-4S page program supported */ + flexspi_lut[PAGE_PROGRAM][0] = FLEXSPI_LUT_SEQ( + kFLEXSPI_Command_SDR, kFLEXSPI_1PAD, SPI_NOR_CMD_PP_1_4_4_4B, + kFLEXSPI_Command_RADDR_SDR, kFLEXSPI_4PAD, 32); + flexspi_lut[PAGE_PROGRAM][1] = FLEXSPI_LUT_SEQ( + kFLEXSPI_Command_WRITE_SDR, kFLEXSPI_4PAD, 0x4, + kFLEXSPI_Command_STOP, kFLEXSPI_1PAD, 0x0); + /* Update ERASE commands for 4 byte mode */ + flexspi_lut[ERASE_SECTOR][0] = FLEXSPI_LUT_SEQ( + kFLEXSPI_Command_SDR, kFLEXSPI_1PAD, SPI_NOR_CMD_SE_4B, + kFLEXSPI_Command_RADDR_SDR, kFLEXSPI_1PAD, 32); + flexspi_lut[ERASE_BLOCK][0] = FLEXSPI_LUT_SEQ( + kFLEXSPI_Command_SDR, kFLEXSPI_1PAD, 0xDC, + kFLEXSPI_Command_RADDR_SDR, kFLEXSPI_1PAD, 32), + /* Read instruction used for polling is 0x05 */ + data->legacy_poll = true; + flexspi_lut[READ_STATUS_REG][0] = FLEXSPI_LUT_SEQ( + kFLEXSPI_Command_SDR, kFLEXSPI_1PAD, SPI_NOR_CMD_RDSR, + kFLEXSPI_Command_READ_SDR, kFLEXSPI_1PAD, 0x01); + /* Device uses bit 6 of status reg 1 for QE */ + return flash_flexspi_nor_quad_enable(data, flexspi_lut, JESD216_DW15_QER_VAL_S1B6); + default: + return -ENOTSUP; + } +} + +/* Probe parameters from flash SFDP header, and use them to configure the FlexSPI */ +static int flash_flexspi_nor_probe(struct flash_flexspi_nor_data *data) +{ + uint32_t flexspi_lut[FLEXSPI_INSTR_END][MEMC_FLEXSPI_CMD_PER_SEQ] = {0}; + /* JESD216B defines up to 23 basic flash parameters */ + uint32_t param_buf[23]; + /* Space to store SFDP header and first parameter header */ + uint8_t sfdp_buf[JESD216_SFDP_SIZE(1)] __aligned(4); + struct jesd216_bfp *bfp = (struct jesd216_bfp *)param_buf; + struct jesd216_sfdp_header *header = (struct jesd216_sfdp_header *)sfdp_buf; + int ret; + unsigned int key = 0U; + + flexspi_device_config_t config = { + .flexspiRootClk = MHZ(50), + .flashSize = FLEXSPI_FLSHCR0_FLSHSZ_MASK, /* Max flash size */ + .ARDSeqNumber = 1, + .ARDSeqIndex = READ, + }; + + if (memc_flexspi_is_running_xip(&data->controller)) { + /* + * ==== ENTER CRITICAL SECTION ==== + * No flash access should be performed in critical section. All + * code and data accessed must reside in ram. + */ + key = irq_lock(); + memc_flexspi_wait_bus_idle(&data->controller); + } + + /* SFDP spec requires that we downclock the FlexSPI to 50MHz or less */ + ret = memc_flexspi_update_clock(&data->controller, &config, + data->port, MHZ(50)); + if (ret < 0) { + goto _exit; + } + + /* Setup initial LUT table and FlexSPI configuration */ + memcpy(flexspi_lut, flash_flexspi_nor_base_lut, sizeof(flash_flexspi_nor_base_lut)); + + ret = memc_flexspi_set_device_config(&data->controller, &config, + (uint32_t *)flexspi_lut, + FLEXSPI_INSTR_END * MEMC_FLEXSPI_CMD_PER_SEQ, + data->port); + if (ret < 0) { + goto _exit; + } + + /* First, check if the JEDEC ID of this flash has explicit support + * in this driver + */ + ret = flash_flexspi_nor_check_jedec(data, flexspi_lut); + if (ret == 0) { + /* Flash was supported, SFDP probe not needed */ + goto _program_lut; + } + + ret = flash_flexspi_nor_sfdp_read_helper(data, 0, sfdp_buf, sizeof(sfdp_buf)); + if (ret < 0) { + goto _exit; + } + + LOG_DBG("SFDP header magic: 0x%x", header->magic); + if (jesd216_sfdp_magic(header) != JESD216_SFDP_MAGIC) { + /* Header was read incorrectly */ + LOG_WRN("Invalid header, using legacy SPI mode"); + data->legacy_poll = true; + goto _program_lut; + } + + if (header->phdr[0].len_dw > ARRAY_SIZE(param_buf)) { + /* Not enough space to read parameter table */ + ret = -ENOBUFS; + goto _exit; + } + + /* Read basic flash parameter table */ + ret = flash_flexspi_nor_sfdp_read_helper(data, + jesd216_param_addr(&header->phdr[0]), + param_buf, + sizeof(uint32_t) * header->phdr[0].len_dw); + if (ret < 0) { + goto _exit; + } + + /* Configure flash */ + ret = flash_flexspi_nor_config_flash(data, header, bfp, flexspi_lut); + if (ret < 0) { + goto _exit; + } + +_program_lut: + /* + * Update the FlexSPI with the config structure provided + * from devicetree and the configured LUT + */ + ret = memc_flexspi_set_device_config(&data->controller, &data->config, + (uint32_t *)flexspi_lut, + FLEXSPI_INSTR_END * MEMC_FLEXSPI_CMD_PER_SEQ, + data->port); + if (ret < 0) { + return ret; + } + +_exit: + memc_flexspi_reset(&data->controller); + + if (memc_flexspi_is_running_xip(&data->controller)) { + /* ==== EXIT CRITICAL SECTION ==== */ + irq_unlock(key); + } + + return ret; +} + static int flash_flexspi_nor_init(const struct device *dev) { const struct flash_flexspi_nor_config *config = dev->config; struct flash_flexspi_nor_data *data = dev->data; - uint8_t vendor_id; + uint32_t vendor_id; /* First step- use ROM pointer to controller device to create * a copy of the device structure in RAM we can use while in @@ -511,31 +1048,36 @@ static int flash_flexspi_nor_init(const struct device *dev) return -ENODEV; } - if (memc_flexspi_is_running_xip(&data->controller)) { - /* Wait for bus idle before configuring */ - memc_flexspi_wait_bus_idle(&data->controller); + if (flash_flexspi_nor_probe(data)) { + if (memc_flexspi_is_running_xip(&data->controller)) { + /* We can't continue from here- the LUT stored in + * the FlexSPI will be invalid so we cannot XIP. + * Instead, spin here + */ + while (1) { + /* Spin */ + } + } + LOG_ERR("SFDP probe failed"); + return -EIO; } - if (memc_flexspi_set_device_config(&data->controller, &data->config, - (const uint32_t *)flash_flexspi_nor_lut, - sizeof(flash_flexspi_nor_lut) / MEMC_FLEXSPI_CMD_SIZE, - data->port)) { - LOG_ERR("Could not set device configuration"); - return -EINVAL; + + /* Set the FlexSPI to full clock speed */ + if (memc_flexspi_update_clock(&data->controller, &data->config, + data->port, data->config.flexspiRootClk)) { + LOG_ERR("Could not set flexspi clock speed"); + return -ENOTSUP; } + memc_flexspi_reset(&data->controller); - if (flash_flexspi_nor_get_vendor_id(data, &vendor_id)) { + if (flash_flexspi_nor_read_id(dev, (uint8_t *)&vendor_id)) { LOG_ERR("Could not read vendor id"); return -EIO; } LOG_DBG("Vendor id: 0x%0x", vendor_id); - if (flash_flexspi_nor_enable_quad_mode(data)) { - LOG_ERR("Could not enable quad mode"); - return -EIO; - } - return 0; } @@ -547,6 +1089,10 @@ static const struct flash_driver_api flash_flexspi_nor_api = { #if defined(CONFIG_FLASH_PAGE_LAYOUT) .page_layout = flash_flexspi_nor_pages_layout, #endif +#if defined(CONFIG_FLASH_JESD216_API) + .sfdp_read = flash_flexspi_nor_sfdp_read, + .read_jedec_id = flash_flexspi_nor_read_id, +#endif }; #define CONCAT3(x, y, z) x ## y ## z @@ -559,7 +1105,7 @@ static const struct flash_driver_api flash_flexspi_nor_api = { #define FLASH_FLEXSPI_DEVICE_CONFIG(n) \ { \ - .flexspiRootClk = MHZ(120), \ + .flexspiRootClk = DT_INST_PROP(n, spi_max_frequency), \ .flashSize = DT_INST_PROP(n, size) / 8 / KB(1), \ .CSIntervalUnit = \ CS_INTERVAL_UNIT( \ @@ -572,7 +1118,7 @@ static const struct flash_driver_api flash_flexspi_nor_api = { .enableWordAddress = DT_INST_PROP(n, word_addressable), \ .AWRSeqIndex = 0, \ .AWRSeqNumber = 0, \ - .ARDSeqIndex = READ_FAST_QUAD_OUTPUT, \ + .ARDSeqIndex = READ, \ .ARDSeqNumber = 1, \ .AHBWriteWaitUnit = \ AHB_WRITE_WAIT_UNIT( \ diff --git a/drivers/memc/memc_mcux_flexspi.h b/drivers/memc/memc_mcux_flexspi.h index ee9fa463655..707d9f088cc 100644 --- a/drivers/memc/memc_mcux_flexspi.h +++ b/drivers/memc/memc_mcux_flexspi.h @@ -10,6 +10,8 @@ /* Size of a command in the LUT table */ #define MEMC_FLEXSPI_CMD_SIZE 4U +/* Number of commands in an instruction sequence */ +#define MEMC_FLEXSPI_CMD_PER_SEQ 4U /** * @brief Wait for the FlexSPI bus to be idle From b83d8b0707545d2ace40fb426d166f315a4310cc Mon Sep 17 00:00:00 2001 From: Daniel DeGrasse Date: Fri, 25 Aug 2023 18:14:28 +0000 Subject: [PATCH 3276/3723] samples: drivers: jesd216: support NXP FlexSPI NOR driver Support NXP FlexSPI nor driver with jesd216 sample. Signed-off-by: Daniel DeGrasse --- samples/drivers/jesd216/src/main.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/samples/drivers/jesd216/src/main.c b/samples/drivers/jesd216/src/main.c index 795bd515212..92dd10208dd 100644 --- a/samples/drivers/jesd216/src/main.c +++ b/samples/drivers/jesd216/src/main.c @@ -22,6 +22,8 @@ #define FLASH_NODE DT_COMPAT_GET_ANY_STATUS_OKAY(st_stm32_ospi_nor) #elif DT_HAS_COMPAT_STATUS_OKAY(nxp_s32_qspi_nor) #define FLASH_NODE DT_COMPAT_GET_ANY_STATUS_OKAY(nxp_s32_qspi_nor) +#elif DT_HAS_COMPAT_STATUS_OKAY(nxp_imx_flexspi_nor) +#define FLASH_NODE DT_COMPAT_GET_ANY_STATUS_OKAY(nxp_imx_flexspi_nor) #else #error Unsupported flash driver #define FLASH_NODE DT_INVALID_NODE From 5957da58301bb05d58e5bbaee98b22be55e937d2 Mon Sep 17 00:00:00 2001 From: Daniel DeGrasse Date: Thu, 2 Nov 2023 12:08:32 -0500 Subject: [PATCH 3277/3723] dts: arm: nxp: rt1064: setup rx-clock-source for XIP flash Setup rx-clock-source for XIP flash. When running from RAM, the FLEXSPI2 attached SIP flash will be reconfigured, so we must ensure the configuration used for it is valid. Signed-off-by: Daniel DeGrasse --- dts/arm/nxp/nxp_rt1064.dtsi | 1 + 1 file changed, 1 insertion(+) diff --git a/dts/arm/nxp/nxp_rt1064.dtsi b/dts/arm/nxp/nxp_rt1064.dtsi index 73ed8827738..02ea70d40f9 100644 --- a/dts/arm/nxp/nxp_rt1064.dtsi +++ b/dts/arm/nxp/nxp_rt1064.dtsi @@ -31,6 +31,7 @@ &flexspi2 { status = "okay"; reg = <0x402a4000 0x4000>, <0x70000000 DT_SIZE_M(4)>; + rx-clock-source = <1>; /* WINBOND */ w25q32jvwj0: w25q32jvwj@0 { compatible = "nxp,imx-flexspi-nor"; From 855b8bc6caadfa2b9ae81477822924cc3afa1a38 Mon Sep 17 00:00:00 2001 From: Christopher Friedt Date: Tue, 30 Jan 2024 23:05:44 -0500 Subject: [PATCH 3278/3723] posix: separate shell utilities and posix api implementation Previously, the POSIX shell utilities were intermixed with the POSIX API implementation. The POSIX shell utilities only depend on the public POSIX API, so it makes sense to keep them in a separate subdirectory. Signed-off-by: Christopher Friedt --- lib/posix/CMakeLists.txt | 69 +---------------- lib/posix/Kconfig | 76 +------------------ lib/posix/Kconfig.limits | 13 ---- lib/posix/options/CMakeLists.txt | 68 +++++++++++++++++ lib/posix/options/Kconfig | 58 ++++++++++++++ lib/posix/{ => options}/Kconfig.barrier | 2 +- lib/posix/{ => options}/Kconfig.clock | 2 +- lib/posix/{ => options}/Kconfig.cond | 2 +- lib/posix/{ => options}/Kconfig.eventfd | 2 +- lib/posix/options/Kconfig.fdtable | 16 ++++ lib/posix/{ => options}/Kconfig.fnmatch | 0 lib/posix/{ => options}/Kconfig.fs | 2 +- lib/posix/{ => options}/Kconfig.getopt | 2 +- lib/posix/{ => options}/Kconfig.key | 2 +- lib/posix/{ => options}/Kconfig.mqueue | 4 +- lib/posix/{ => options}/Kconfig.mutex | 2 +- lib/posix/{ => options}/Kconfig.pthread | 2 +- lib/posix/{ => options}/Kconfig.rwlock | 2 +- lib/posix/{ => options}/Kconfig.sched | 2 +- lib/posix/{ => options}/Kconfig.semaphore | 4 + lib/posix/{ => options}/Kconfig.signal | 27 +++++-- lib/posix/{ => options}/Kconfig.spinlock | 2 +- lib/posix/{ => options}/Kconfig.stropts | 0 lib/posix/options/Kconfig.sysconf | 24 ++++++ .../Kconfig.template.pooled_ipc_type | 15 ++-- .../Kconfig.template.pooled_type | 15 ++-- .../Kconfig.template.with_logging | 0 .../{ => options}/Kconfig.template.with_url | 0 lib/posix/{ => options}/Kconfig.timer | 6 +- lib/posix/{ => options}/Kconfig.uname | 2 +- lib/posix/{ => options}/_common.c | 0 lib/posix/{ => options}/barrier.c | 0 lib/posix/{ => options}/clock.c | 0 lib/posix/{ => options}/cond.c | 0 lib/posix/{ => options}/eventfd.c | 0 lib/posix/{ => options}/fnmatch.c | 0 lib/posix/{ => options}/fs.c | 0 lib/posix/{ => options}/getopt/CMakeLists.txt | 0 lib/posix/{ => options}/getopt/Kconfig | 0 lib/posix/{ => options}/getopt/README | 0 lib/posix/{ => options}/getopt/getopt.c | 0 lib/posix/{ => options}/getopt/getopt.h | 0 .../{ => options}/getopt/getopt_common.c | 0 .../{ => options}/getopt/getopt_common.h | 0 lib/posix/{ => options}/getopt/getopt_long.c | 0 lib/posix/{ => options}/key.c | 0 lib/posix/{ => options}/mqueue.c | 0 lib/posix/{ => options}/mutex.c | 0 lib/posix/{ => options}/nanosleep.c | 0 lib/posix/{ => options}/perror.c | 0 lib/posix/{ => options}/posix_clock.h | 0 lib/posix/{ => options}/posix_internal.h | 0 lib/posix/{ => options}/pthread.c | 0 lib/posix/{ => options}/pthread_sched.h | 0 lib/posix/{ => options}/rwlock.c | 0 lib/posix/{ => options}/sched.c | 0 lib/posix/{ => options}/semaphore.c | 0 lib/posix/{ => options}/signal.c | 0 lib/posix/{ => options}/sleep.c | 0 lib/posix/{ => options}/spinlock.c | 0 lib/posix/{ => options}/stropts.c | 0 lib/posix/{ => options}/timer.c | 0 lib/posix/{ => options}/uname.c | 0 lib/posix/shell/Kconfig | 4 + samples/posix/philosophers/CMakeLists.txt | 2 +- 65 files changed, 238 insertions(+), 189 deletions(-) delete mode 100644 lib/posix/Kconfig.limits create mode 100644 lib/posix/options/CMakeLists.txt create mode 100644 lib/posix/options/Kconfig rename lib/posix/{ => options}/Kconfig.barrier (92%) rename lib/posix/{ => options}/Kconfig.clock (86%) rename lib/posix/{ => options}/Kconfig.cond (77%) rename lib/posix/{ => options}/Kconfig.eventfd (96%) create mode 100644 lib/posix/options/Kconfig.fdtable rename lib/posix/{ => options}/Kconfig.fnmatch (100%) rename lib/posix/{ => options}/Kconfig.fs (95%) rename lib/posix/{ => options}/Kconfig.getopt (71%) rename lib/posix/{ => options}/Kconfig.key (77%) rename lib/posix/{ => options}/Kconfig.mqueue (92%) rename lib/posix/{ => options}/Kconfig.mutex (78%) rename lib/posix/{ => options}/Kconfig.pthread (97%) rename lib/posix/{ => options}/Kconfig.rwlock (75%) rename lib/posix/{ => options}/Kconfig.sched (84%) rename lib/posix/{ => options}/Kconfig.semaphore (89%) rename lib/posix/{ => options}/Kconfig.signal (75%) rename lib/posix/{ => options}/Kconfig.spinlock (74%) rename lib/posix/{ => options}/Kconfig.stropts (100%) create mode 100644 lib/posix/options/Kconfig.sysconf rename lib/posix/{ => options}/Kconfig.template.pooled_ipc_type (67%) rename lib/posix/{ => options}/Kconfig.template.pooled_type (63%) rename lib/posix/{ => options}/Kconfig.template.with_logging (100%) rename lib/posix/{ => options}/Kconfig.template.with_url (100%) rename lib/posix/{ => options}/Kconfig.timer (90%) rename lib/posix/{ => options}/Kconfig.uname (96%) rename lib/posix/{ => options}/_common.c (100%) rename lib/posix/{ => options}/barrier.c (100%) rename lib/posix/{ => options}/clock.c (100%) rename lib/posix/{ => options}/cond.c (100%) rename lib/posix/{ => options}/eventfd.c (100%) rename lib/posix/{ => options}/fnmatch.c (100%) rename lib/posix/{ => options}/fs.c (100%) rename lib/posix/{ => options}/getopt/CMakeLists.txt (100%) rename lib/posix/{ => options}/getopt/Kconfig (100%) rename lib/posix/{ => options}/getopt/README (100%) rename lib/posix/{ => options}/getopt/getopt.c (100%) rename lib/posix/{ => options}/getopt/getopt.h (100%) rename lib/posix/{ => options}/getopt/getopt_common.c (100%) rename lib/posix/{ => options}/getopt/getopt_common.h (100%) rename lib/posix/{ => options}/getopt/getopt_long.c (100%) rename lib/posix/{ => options}/key.c (100%) rename lib/posix/{ => options}/mqueue.c (100%) rename lib/posix/{ => options}/mutex.c (100%) rename lib/posix/{ => options}/nanosleep.c (100%) rename lib/posix/{ => options}/perror.c (100%) rename lib/posix/{ => options}/posix_clock.h (100%) rename lib/posix/{ => options}/posix_internal.h (100%) rename lib/posix/{ => options}/pthread.c (100%) rename lib/posix/{ => options}/pthread_sched.h (100%) rename lib/posix/{ => options}/rwlock.c (100%) rename lib/posix/{ => options}/sched.c (100%) rename lib/posix/{ => options}/semaphore.c (100%) rename lib/posix/{ => options}/signal.c (100%) rename lib/posix/{ => options}/sleep.c (100%) rename lib/posix/{ => options}/spinlock.c (100%) rename lib/posix/{ => options}/stropts.c (100%) rename lib/posix/{ => options}/timer.c (100%) rename lib/posix/{ => options}/uname.c (100%) diff --git a/lib/posix/CMakeLists.txt b/lib/posix/CMakeLists.txt index c8d836f5846..fed728c17ba 100644 --- a/lib/posix/CMakeLists.txt +++ b/lib/posix/CMakeLists.txt @@ -1,69 +1,4 @@ # SPDX-License-Identifier: Apache-2.0 -set(GEN_DIR ${ZEPHYR_BINARY_DIR}/include/generated) - -zephyr_syscall_header( - posix_clock.h -) - -zephyr_interface_library_named(posix_subsys) - -if(CONFIG_POSIX_API) - zephyr_include_directories(${ZEPHYR_BASE}/include/zephyr/posix) -endif() - -if(CONFIG_POSIX_SIGNAL) - set(STRSIGNAL_TABLE_H ${GEN_DIR}/posix/strsignal_table.h) - - add_custom_command( - OUTPUT ${STRSIGNAL_TABLE_H} - COMMAND - ${PYTHON_EXECUTABLE} - ${ZEPHYR_BASE}/scripts/build/gen_strsignal_table.py - -i ${ZEPHYR_BASE}/include/zephyr/posix/signal.h - -o ${STRSIGNAL_TABLE_H} - DEPENDS ${ZEPHYR_BASE}/include/zephyr/posix/signal.h - ) -endif() - -if(CONFIG_POSIX_API OR CONFIG_PTHREAD_IPC OR CONFIG_POSIX_CLOCK OR - CONFIG_POSIX_MQUEUE OR CONFIG_POSIX_FS OR CONFIG_EVENTFD OR CONFIG_GETOPT) - # This is a temporary workaround so that Newlib declares the appropriate - # types for us. POSIX features to be formalized as part of #51211 - zephyr_compile_options($<$:-D_POSIX_THREADS>) - zephyr_compile_options($<$:-D_POSIX_THREADS>) -endif() - -zephyr_library() -add_subdirectory_ifdef(CONFIG_GETOPT getopt) -add_subdirectory_ifdef(CONFIG_SHELL shell) -zephyr_library_sources_ifdef(CONFIG_EVENTFD eventfd.c) -zephyr_library_sources_ifdef(CONFIG_FNMATCH fnmatch.c) -zephyr_library_sources_ifdef(CONFIG_POSIX_API perror.c) -zephyr_library_sources_ifdef(CONFIG_POSIX_CLOCK clock.c) -zephyr_library_sources_ifdef(CONFIG_POSIX_CLOCK nanosleep.c) -zephyr_library_sources_ifdef(CONFIG_POSIX_CLOCK sleep.c) -zephyr_library_sources_ifdef(CONFIG_POSIX_FS fs.c) -zephyr_library_sources_ifdef(CONFIG_POSIX_MQUEUE mqueue.c) -zephyr_library_sources_ifdef(CONFIG_POSIX_SIGNAL signal.c ${STRSIGNAL_TABLE_H}) -zephyr_library_sources_ifdef(CONFIG_POSIX_UNAME uname.c) -zephyr_library_sources_ifdef(CONFIG_PTHREAD_IPC _common.c) -zephyr_library_sources_ifdef(CONFIG_PTHREAD_BARRIER barrier.c) -zephyr_library_sources_ifdef(CONFIG_PTHREAD_COND cond.c) -zephyr_library_sources_ifdef(CONFIG_PTHREAD_KEY key.c) -zephyr_library_sources_ifdef(CONFIG_PTHREAD_MUTEX mutex.c) -zephyr_library_sources_ifdef(CONFIG_PTHREAD pthread.c) -zephyr_library_sources_ifdef(CONFIG_PTHREAD_RWLOCK rwlock.c) -zephyr_library_sources_ifdef(CONFIG_POSIX_PRIORITY_SCHEDULING sched.c) -zephyr_library_sources_ifdef(CONFIG_PTHREAD_IPC semaphore.c) -zephyr_library_sources_ifdef(CONFIG_PTHREAD_SPINLOCK spinlock.c) -zephyr_library_sources_ifdef(CONFIG_TIMER timer.c) -zephyr_library_sources_ifdef(CONFIG_POSIX_PUTMSG stropts.c) - -zephyr_library_include_directories( - ${ZEPHYR_BASE}/kernel/include - ${ARCH_DIR}/${ARCH}/include -) - -zephyr_library_link_libraries(posix_subsys) -zephyr_library_property(ALLOW_EMPTY TRUE) +add_subdirectory(options) +add_subdirectory(shell) diff --git a/lib/posix/Kconfig b/lib/posix/Kconfig index b2f379be8d1..534baf08cd2 100644 --- a/lib/posix/Kconfig +++ b/lib/posix/Kconfig @@ -1,82 +1,10 @@ -# Copyright (c) 2018 Intel Corporation -# Copyright (c) 2023 Meta +# Copyright (c) 2024 Meta # # SPDX-License-Identifier: Apache-2.0 menu "POSIX API Support" -config POSIX_MAX_FDS - int "Maximum number of open file descriptors" - default 16 if WIFI_NM_WPA_SUPPLICANT - default 16 if POSIX_API - default 4 - help - Maximum number of open file descriptors, this includes - files, sockets, special devices, etc. - -config POSIX_API - depends on !NATIVE_APPLICATION - bool "POSIX APIs" - help - Enable mostly-standards-compliant implementations of - various POSIX (IEEE 1003.1) APIs. - -# The name of this option is mandated by zephyr_interface_library_named -# cmake directive. -config APP_LINK_WITH_POSIX_SUBSYS - bool "Make POSIX headers available to application" - default y - depends on POSIX_API - help - Add POSIX subsystem header files to the 'app' include path. - -config PTHREAD_IPC - bool "POSIX pthread IPC API" - default y if POSIX_API - depends on POSIX_CLOCK - help - This enables a mostly-standards-compliant implementation of - the pthread mutex, condition variable and barrier IPC - mechanisms. - -config POSIX_SYSCONF - bool "Support for sysconf" - default y if POSIX_API - help - The sysconf() function provides a method for the application to determine - the current value of a configurable system limit or option (variable). - -config POSIX_PAGE_SIZE_BITS - int "Number of bits to use for PAGE_SIZE" - range 6 16 - default 12 if POSIX_API - default 6 - help - Define PAGE_SIZE as BIT(n), where n is the value configured here. - PAGE_SIZE is supported in the range [64, 65536] - If CONFIG_POSIX_API=y, PAGE_SIZE defaults to 4096, otherwise, it is 64 bytes. - -source "lib/posix/Kconfig.barrier" -source "lib/posix/Kconfig.clock" -source "lib/posix/Kconfig.cond" -source "lib/posix/Kconfig.eventfd" -source "lib/posix/Kconfig.fnmatch" -source "lib/posix/Kconfig.fs" -source "lib/posix/Kconfig.getopt" -source "lib/posix/Kconfig.key" -source "lib/posix/Kconfig.limits" -source "lib/posix/Kconfig.mqueue" -source "lib/posix/Kconfig.mutex" -source "lib/posix/Kconfig.pthread" -source "lib/posix/Kconfig.rwlock" -source "lib/posix/Kconfig.sched" -source "lib/posix/Kconfig.semaphore" -source "lib/posix/Kconfig.signal" -source "lib/posix/Kconfig.spinlock" -source "lib/posix/Kconfig.timer" -source "lib/posix/Kconfig.uname" -source "lib/posix/Kconfig.stropts" - +rsource "options/Kconfig" rsource "shell/Kconfig" endmenu # "POSIX API Support" diff --git a/lib/posix/Kconfig.limits b/lib/posix/Kconfig.limits deleted file mode 100644 index cc651203961..00000000000 --- a/lib/posix/Kconfig.limits +++ /dev/null @@ -1,13 +0,0 @@ -# Copyright (c) 2023 Meta -# -# SPDX-License-Identifier: Apache-2.0 - -if POSIX_SIGNAL -config POSIX_LIMITS_RTSIG_MAX - int "_POSIX_RTSIG_MAX value in limits.h" - default 8 - help - Define the _POSIX_RTSIG_MAX value in limits.h. - IEEE 1003.1 defines this to be 8. - -endif diff --git a/lib/posix/options/CMakeLists.txt b/lib/posix/options/CMakeLists.txt new file mode 100644 index 00000000000..b523e859e86 --- /dev/null +++ b/lib/posix/options/CMakeLists.txt @@ -0,0 +1,68 @@ +# SPDX-License-Identifier: Apache-2.0 + +set(GEN_DIR ${ZEPHYR_BINARY_DIR}/include/generated) + +zephyr_syscall_header( + posix_clock.h +) + +zephyr_interface_library_named(posix_subsys) + +if(CONFIG_POSIX_API) + zephyr_include_directories(${ZEPHYR_BASE}/include/zephyr/posix) +endif() + +if(CONFIG_POSIX_SIGNAL) + set(STRSIGNAL_TABLE_H ${GEN_DIR}/posix/strsignal_table.h) + + add_custom_command( + OUTPUT ${STRSIGNAL_TABLE_H} + COMMAND + ${PYTHON_EXECUTABLE} + ${ZEPHYR_BASE}/scripts/build/gen_strsignal_table.py + -i ${ZEPHYR_BASE}/include/zephyr/posix/signal.h + -o ${STRSIGNAL_TABLE_H} + DEPENDS ${ZEPHYR_BASE}/include/zephyr/posix/signal.h + ) +endif() + +if(CONFIG_POSIX_API OR CONFIG_PTHREAD_IPC OR CONFIG_POSIX_CLOCK OR + CONFIG_POSIX_MQUEUE OR CONFIG_POSIX_FS OR CONFIG_EVENTFD OR CONFIG_GETOPT) + # This is a temporary workaround so that Newlib declares the appropriate + # types for us. POSIX features to be formalized as part of #51211 + zephyr_compile_options($<$:-D_POSIX_THREADS>) + zephyr_compile_options($<$:-D_POSIX_THREADS>) +endif() + +zephyr_library() +add_subdirectory_ifdef(CONFIG_GETOPT getopt) +zephyr_library_sources_ifdef(CONFIG_EVENTFD eventfd.c) +zephyr_library_sources_ifdef(CONFIG_FNMATCH fnmatch.c) +zephyr_library_sources_ifdef(CONFIG_POSIX_API perror.c) +zephyr_library_sources_ifdef(CONFIG_POSIX_CLOCK clock.c) +zephyr_library_sources_ifdef(CONFIG_POSIX_CLOCK nanosleep.c) +zephyr_library_sources_ifdef(CONFIG_POSIX_CLOCK sleep.c) +zephyr_library_sources_ifdef(CONFIG_POSIX_FS fs.c) +zephyr_library_sources_ifdef(CONFIG_POSIX_MQUEUE mqueue.c) +zephyr_library_sources_ifdef(CONFIG_POSIX_PUTMSG stropts.c) +zephyr_library_sources_ifdef(CONFIG_POSIX_SIGNAL signal.c ${STRSIGNAL_TABLE_H}) +zephyr_library_sources_ifdef(CONFIG_POSIX_UNAME uname.c) +zephyr_library_sources_ifdef(CONFIG_PTHREAD_IPC _common.c) +zephyr_library_sources_ifdef(CONFIG_PTHREAD_BARRIER barrier.c) +zephyr_library_sources_ifdef(CONFIG_PTHREAD_COND cond.c) +zephyr_library_sources_ifdef(CONFIG_PTHREAD_KEY key.c) +zephyr_library_sources_ifdef(CONFIG_PTHREAD_MUTEX mutex.c) +zephyr_library_sources_ifdef(CONFIG_PTHREAD pthread.c) +zephyr_library_sources_ifdef(CONFIG_PTHREAD_RWLOCK rwlock.c) +zephyr_library_sources_ifdef(CONFIG_POSIX_PRIORITY_SCHEDULING sched.c) +zephyr_library_sources_ifdef(CONFIG_PTHREAD_IPC semaphore.c) +zephyr_library_sources_ifdef(CONFIG_PTHREAD_SPINLOCK spinlock.c) +zephyr_library_sources_ifdef(CONFIG_TIMER timer.c) + +zephyr_library_include_directories( + ${ZEPHYR_BASE}/kernel/include + ${ARCH_DIR}/${ARCH}/include +) + +zephyr_library_link_libraries(posix_subsys) +zephyr_library_property(ALLOW_EMPTY TRUE) diff --git a/lib/posix/options/Kconfig b/lib/posix/options/Kconfig new file mode 100644 index 00000000000..9b738c9bdba --- /dev/null +++ b/lib/posix/options/Kconfig @@ -0,0 +1,58 @@ +# Copyright (c) 2018 Intel Corporation +# Copyright (c) 2023 Meta +# +# SPDX-License-Identifier: Apache-2.0 + +menu "POSIX Options" + +config POSIX_API + depends on !NATIVE_APPLICATION + bool "POSIX APIs" + help + Enable mostly-standards-compliant implementations of + various POSIX (IEEE 1003.1) APIs. + +# The name of this option is mandated by zephyr_interface_library_named +# cmake directive. +config APP_LINK_WITH_POSIX_SUBSYS + bool "Make POSIX headers available to application" + default y + depends on POSIX_API + help + Add POSIX subsystem header files to the 'app' include path. + +if POSIX_CLOCK + +config PTHREAD_IPC + bool "POSIX pthread IPC API" + default y if POSIX_API + help + This enables a mostly-standards-compliant implementation of + the pthread mutex, condition variable and barrier IPC + mechanisms. + +endif # POSIX_CLOCK + +rsource "Kconfig.barrier" +rsource "Kconfig.clock" +rsource "Kconfig.cond" +rsource "Kconfig.eventfd" +rsource "Kconfig.fdtable" +rsource "Kconfig.fnmatch" +rsource "Kconfig.fs" +rsource "Kconfig.getopt" +rsource "Kconfig.key" +rsource "Kconfig.mqueue" +rsource "Kconfig.mutex" +rsource "Kconfig.pthread" +rsource "Kconfig.rwlock" +rsource "Kconfig.sched" +rsource "Kconfig.semaphore" +rsource "Kconfig.signal" +rsource "Kconfig.spinlock" +rsource "Kconfig.stropts" +rsource "Kconfig.sysconf" +rsource "Kconfig.timer" +rsource "Kconfig.uname" + +endmenu # "POSIX Options" diff --git a/lib/posix/Kconfig.barrier b/lib/posix/options/Kconfig.barrier similarity index 92% rename from lib/posix/Kconfig.barrier rename to lib/posix/options/Kconfig.barrier index e14b39c5b08..72dd8148277 100644 --- a/lib/posix/Kconfig.barrier +++ b/lib/posix/options/Kconfig.barrier @@ -6,7 +6,7 @@ TYPE = PTHREAD_BARRIER type = pthread_barrier_t type-function = pthread_barrier_wait -source "lib/posix/Kconfig.template.pooled_ipc_type" +rsource "Kconfig.template.pooled_ipc_type" if PTHREAD_BARRIER diff --git a/lib/posix/Kconfig.clock b/lib/posix/options/Kconfig.clock similarity index 86% rename from lib/posix/Kconfig.clock rename to lib/posix/options/Kconfig.clock index e306e691b44..0d541c9f32f 100644 --- a/lib/posix/Kconfig.clock +++ b/lib/posix/options/Kconfig.clock @@ -3,7 +3,7 @@ # SPDX-License-Identifier: Apache-2.0 config POSIX_CLOCK - bool "POSIX clock and sleep APIs" + bool "clock and sleep APIs" default y if POSIX_API imply TIMER depends on !NATIVE_LIBC diff --git a/lib/posix/Kconfig.cond b/lib/posix/options/Kconfig.cond similarity index 77% rename from lib/posix/Kconfig.cond rename to lib/posix/options/Kconfig.cond index fcdf842a602..b69b35dece6 100644 --- a/lib/posix/Kconfig.cond +++ b/lib/posix/options/Kconfig.cond @@ -6,4 +6,4 @@ TYPE = PTHREAD_COND type = pthread_cond_t type-function = pthread_cond_wait -source "lib/posix/Kconfig.template.pooled_ipc_type" +rsource "Kconfig.template.pooled_ipc_type" diff --git a/lib/posix/Kconfig.eventfd b/lib/posix/options/Kconfig.eventfd similarity index 96% rename from lib/posix/Kconfig.eventfd rename to lib/posix/options/Kconfig.eventfd index 0b6fa171741..eadf8f80916 100644 --- a/lib/posix/Kconfig.eventfd +++ b/lib/posix/options/Kconfig.eventfd @@ -3,7 +3,7 @@ # # SPDX-License-Identifier: Apache-2.0 -config EVENTFD +menuconfig EVENTFD bool "Support for eventfd" depends on !NATIVE_APPLICATION select POLL diff --git a/lib/posix/options/Kconfig.fdtable b/lib/posix/options/Kconfig.fdtable new file mode 100644 index 00000000000..214e4a04ae9 --- /dev/null +++ b/lib/posix/options/Kconfig.fdtable @@ -0,0 +1,16 @@ +# Copyright (c) 2018 Linaro +# +# SPDX-License-Identifier: Apache-2.0 + +menu "File descriptor table options" + +config POSIX_MAX_FDS + int "Maximum number of open file descriptors" + default 16 if WIFI_NM_WPA_SUPPLICANT + default 16 if POSIX_API + default 4 + help + Maximum number of open file descriptors, this includes + files, sockets, special devices, etc. + +endmenu # "File descriptor table options" diff --git a/lib/posix/Kconfig.fnmatch b/lib/posix/options/Kconfig.fnmatch similarity index 100% rename from lib/posix/Kconfig.fnmatch rename to lib/posix/options/Kconfig.fnmatch diff --git a/lib/posix/Kconfig.fs b/lib/posix/options/Kconfig.fs similarity index 95% rename from lib/posix/Kconfig.fs rename to lib/posix/options/Kconfig.fs index 1d032910539..e4d5f1dea6e 100644 --- a/lib/posix/Kconfig.fs +++ b/lib/posix/options/Kconfig.fs @@ -2,7 +2,7 @@ # # SPDX-License-Identifier: Apache-2.0 -config POSIX_FS +menuconfig POSIX_FS bool "POSIX file system API support" default y if POSIX_API depends on FILE_SYSTEM diff --git a/lib/posix/Kconfig.getopt b/lib/posix/options/Kconfig.getopt similarity index 71% rename from lib/posix/Kconfig.getopt rename to lib/posix/options/Kconfig.getopt index ccd2c37ed56..4d3559cd855 100644 --- a/lib/posix/Kconfig.getopt +++ b/lib/posix/options/Kconfig.getopt @@ -2,4 +2,4 @@ # # SPDX-License-Identifier: Apache-2.0 -source "lib/posix/getopt/Kconfig" +rsource "getopt/Kconfig" diff --git a/lib/posix/Kconfig.key b/lib/posix/options/Kconfig.key similarity index 77% rename from lib/posix/Kconfig.key rename to lib/posix/options/Kconfig.key index 6e8538233eb..671cce10373 100644 --- a/lib/posix/Kconfig.key +++ b/lib/posix/options/Kconfig.key @@ -6,4 +6,4 @@ TYPE = PTHREAD_KEY type = pthread_key_t type-function = pthread_setspecific -source "lib/posix/Kconfig.template.pooled_ipc_type" +rsource "Kconfig.template.pooled_ipc_type" diff --git a/lib/posix/Kconfig.mqueue b/lib/posix/options/Kconfig.mqueue similarity index 92% rename from lib/posix/Kconfig.mqueue rename to lib/posix/options/Kconfig.mqueue index 7c49aee6c21..3688455d781 100644 --- a/lib/posix/Kconfig.mqueue +++ b/lib/posix/options/Kconfig.mqueue @@ -2,8 +2,8 @@ # # SPDX-License-Identifier: Apache-2.0 -config POSIX_MQUEUE - bool "POSIX message queue" +menuconfig POSIX_MQUEUE + bool "Message queue support" default y if POSIX_API help This enabled POSIX message queue related APIs. diff --git a/lib/posix/Kconfig.mutex b/lib/posix/options/Kconfig.mutex similarity index 78% rename from lib/posix/Kconfig.mutex rename to lib/posix/options/Kconfig.mutex index c34881017e5..6d5729e80aa 100644 --- a/lib/posix/Kconfig.mutex +++ b/lib/posix/options/Kconfig.mutex @@ -6,4 +6,4 @@ TYPE = PTHREAD_MUTEX type = pthread_mutex_t type-function = pthread_mutex_lock -source "lib/posix/Kconfig.template.pooled_ipc_type" +rsource "Kconfig.template.pooled_ipc_type" diff --git a/lib/posix/Kconfig.pthread b/lib/posix/options/Kconfig.pthread similarity index 97% rename from lib/posix/Kconfig.pthread rename to lib/posix/options/Kconfig.pthread index 8870b725109..f0c65836b60 100644 --- a/lib/posix/Kconfig.pthread +++ b/lib/posix/options/Kconfig.pthread @@ -6,7 +6,7 @@ TYPE = PTHREAD type = pthread_t type-function = pthread_create -source "lib/posix/Kconfig.template.pooled_ipc_type" +rsource "Kconfig.template.pooled_ipc_type" if PTHREAD diff --git a/lib/posix/Kconfig.rwlock b/lib/posix/options/Kconfig.rwlock similarity index 75% rename from lib/posix/Kconfig.rwlock rename to lib/posix/options/Kconfig.rwlock index 6bd89a0a9f5..fea61551ec3 100644 --- a/lib/posix/Kconfig.rwlock +++ b/lib/posix/options/Kconfig.rwlock @@ -5,4 +5,4 @@ TYPE = PTHREAD_RWLOCK type = pthread_rwlock_t type-function = pthread_rwlock_timedrdlock -source "lib/posix/Kconfig.template.pooled_ipc_type" +rsource "Kconfig.template.pooled_ipc_type" diff --git a/lib/posix/Kconfig.sched b/lib/posix/options/Kconfig.sched similarity index 84% rename from lib/posix/Kconfig.sched rename to lib/posix/options/Kconfig.sched index 62e7541c8e1..b5fb3a5dcb1 100644 --- a/lib/posix/Kconfig.sched +++ b/lib/posix/options/Kconfig.sched @@ -3,7 +3,7 @@ # SPDX-License-Identifier: Apache-2.0 config POSIX_PRIORITY_SCHEDULING - bool "_POSIX_PRIORITY_SCHEDULING API support" + bool "Priority scheduling" default y if PTHREAD default y if POSIX_API depends on PTHREAD diff --git a/lib/posix/Kconfig.semaphore b/lib/posix/options/Kconfig.semaphore similarity index 89% rename from lib/posix/Kconfig.semaphore rename to lib/posix/options/Kconfig.semaphore index aa3468fea76..53fb030736b 100644 --- a/lib/posix/Kconfig.semaphore +++ b/lib/posix/options/Kconfig.semaphore @@ -2,6 +2,8 @@ # # SPDX-License-Identifier: Apache-2.0 +menu "sem_t support" + config SEM_VALUE_MAX int "Maximum semaphore limit" default 32767 @@ -16,3 +18,5 @@ config SEM_NAMELEN_MAX help Maximum length of name for a named semaphore. The max value of 255 corresponds to {NAME_MAX}. + +endmenu # "sem_t support" diff --git a/lib/posix/Kconfig.signal b/lib/posix/options/Kconfig.signal similarity index 75% rename from lib/posix/Kconfig.signal rename to lib/posix/options/Kconfig.signal index 1df8cf3ab16..99c225564c7 100644 --- a/lib/posix/Kconfig.signal +++ b/lib/posix/options/Kconfig.signal @@ -2,6 +2,17 @@ # # SPDX-License-Identifier: Apache-2.0 +menu "Signal support" + +# needed outside of if clause above to define constants & types in signal.h +config POSIX_RTSIG_MAX + int "Maximum number of realtime signals" + default 31 if POSIX_SIGNAL + default 0 + help + Define the maximum number of realtime signals (RTSIG_MAX). + The range of realtime signals is [SIGRTMIN .. (SIGRTMIN+RTSIG_MAX)] + config POSIX_SIGNAL bool "Support for POSIX signal APIs" default y if POSIX_API @@ -17,13 +28,13 @@ config POSIX_SIGNAL_STRING_DESC Use full description for the strsignal API. Will use 256 bytes of ROM. +config POSIX_LIMITS_RTSIG_MAX + int "_POSIX_RTSIG_MAX value in limits.h" + default 8 + help + Define the _POSIX_RTSIG_MAX value in limits.h. + IEEE 1003.1 defines this to be 8. + endif -# needed outside of if clause above to define constants & types in signal.h -config POSIX_RTSIG_MAX - int "Maximum number of realtime signals" - default 31 if POSIX_SIGNAL - default 0 - help - Define the maximum number of realtime signals (RTSIG_MAX). - The range of realtime signals is [SIGRTMIN .. (SIGRTMIN+RTSIG_MAX)] +endmenu # "Signal support" diff --git a/lib/posix/Kconfig.spinlock b/lib/posix/options/Kconfig.spinlock similarity index 74% rename from lib/posix/Kconfig.spinlock rename to lib/posix/options/Kconfig.spinlock index 83a95d77ed0..8374aadfd6d 100644 --- a/lib/posix/Kconfig.spinlock +++ b/lib/posix/options/Kconfig.spinlock @@ -5,4 +5,4 @@ TYPE = PTHREAD_SPINLOCK type = pthread_spinlock_t type-function = pthread_spin_lock -source "lib/posix/Kconfig.template.pooled_ipc_type" +rsource "Kconfig.template.pooled_ipc_type" diff --git a/lib/posix/Kconfig.stropts b/lib/posix/options/Kconfig.stropts similarity index 100% rename from lib/posix/Kconfig.stropts rename to lib/posix/options/Kconfig.stropts diff --git a/lib/posix/options/Kconfig.sysconf b/lib/posix/options/Kconfig.sysconf new file mode 100644 index 00000000000..32f37f1c29d --- /dev/null +++ b/lib/posix/options/Kconfig.sysconf @@ -0,0 +1,24 @@ +# Copyright (c) 2024 BayLibre SAS +# +# SPDX-License-Identifier: Apache-2.0 + +menu "Sysconf support" + +config POSIX_SYSCONF + bool "Support for sysconf" + default y if POSIX_API + help + The sysconf() function provides a method for the application to determine + the current value of a configurable system limit or option (variable). + +config POSIX_PAGE_SIZE_BITS + int "Number of bits to use for PAGE_SIZE" + range 6 16 + default 12 if POSIX_API + default 6 + help + Define PAGE_SIZE as BIT(n), where n is the value configured here. + PAGE_SIZE is supported in the range [64, 65536] + If CONFIG_POSIX_API=y, PAGE_SIZE defaults to 4096, otherwise, it is 64 bytes. + +endmenu # "Sysconf support" diff --git a/lib/posix/Kconfig.template.pooled_ipc_type b/lib/posix/options/Kconfig.template.pooled_ipc_type similarity index 67% rename from lib/posix/Kconfig.template.pooled_ipc_type rename to lib/posix/options/Kconfig.template.pooled_ipc_type index d28ed345b6a..08d804382e8 100644 --- a/lib/posix/Kconfig.template.pooled_ipc_type +++ b/lib/posix/options/Kconfig.template.pooled_ipc_type @@ -2,12 +2,11 @@ # # SPDX-License-Identifier: Apache-2.0 -source "lib/posix/Kconfig.template.with_url" -source "lib/posix/Kconfig.template.with_logging" +rsource "Kconfig.template.with_url" # Not user configurable (i.e. private for now) -config $(TYPE) - bool "POSIX $(type) support" +menuconfig $(TYPE) + bool "$(type) support" depends on PTHREAD_IPC default y help @@ -15,10 +14,16 @@ config $(TYPE) For more info, see $(posix-url-base)/$(type-function).html +if $(TYPE) + # eventually, this size should be defaulted to 0 config MAX_$(TYPE)_COUNT - int "Maximum simultaneously active $(type) in POSIX application" + int "Maximum number of $(type)" default 5 depends on $(TYPE) help Maximum simultaneously active $(type) in a POSIX application. + +rsource "Kconfig.template.with_logging" + +endif # $(TYPE) diff --git a/lib/posix/Kconfig.template.pooled_type b/lib/posix/options/Kconfig.template.pooled_type similarity index 63% rename from lib/posix/Kconfig.template.pooled_type rename to lib/posix/options/Kconfig.template.pooled_type index a30686043a1..5a75c2ee890 100644 --- a/lib/posix/Kconfig.template.pooled_type +++ b/lib/posix/options/Kconfig.template.pooled_type @@ -2,19 +2,24 @@ # # SPDX-License-Identifier: Apache-2.0 -source "lib/posix/Kconfig.template.with_url" -source "lib/posix/Kconfig.template.with_logging" +rsource "Kconfig.template.with_url" # This is mainly for TIMER currently. -config $(TYPE) - bool "POSIX $(type) support" +menuconfig $(TYPE) + bool "$(type) support" help For more info, see $(posix-url-base)/$(type-function).html +if $(TYPE) + # eventually, this size should be defaulted to 0 as a safe value config MAX_$(TYPE)_COUNT - int "Maximum simultaneously active $(type) in POSIX application" + int "Maximum number of $(type)" default 5 help Maximum simultaneously active $(type) in a POSIX application. + +rsource "Kconfig.template.with_logging" + +endif # $(TYPE) diff --git a/lib/posix/Kconfig.template.with_logging b/lib/posix/options/Kconfig.template.with_logging similarity index 100% rename from lib/posix/Kconfig.template.with_logging rename to lib/posix/options/Kconfig.template.with_logging diff --git a/lib/posix/Kconfig.template.with_url b/lib/posix/options/Kconfig.template.with_url similarity index 100% rename from lib/posix/Kconfig.template.with_url rename to lib/posix/options/Kconfig.template.with_url diff --git a/lib/posix/Kconfig.timer b/lib/posix/options/Kconfig.timer similarity index 90% rename from lib/posix/Kconfig.timer rename to lib/posix/options/Kconfig.timer index 28173692e0c..10905e9c21d 100644 --- a/lib/posix/Kconfig.timer +++ b/lib/posix/options/Kconfig.timer @@ -5,7 +5,9 @@ TYPE = TIMER type = timer_t type-function = timer_create -source "lib/posix/Kconfig.template.pooled_type" +rsource "Kconfig.template.pooled_type" + +if TIMER config TIMER_CREATE_WAIT int "Time to wait for timer availability (in msec) in POSIX application" @@ -21,3 +23,5 @@ config TIMER_DELAYTIMER_MAX help This controls the maximum number of times a timer can overrun before timer_getoverrun() in POSIX compliant application. + +endif # TIMER diff --git a/lib/posix/Kconfig.uname b/lib/posix/options/Kconfig.uname similarity index 96% rename from lib/posix/Kconfig.uname rename to lib/posix/options/Kconfig.uname index d8c29479986..09b52602db1 100644 --- a/lib/posix/Kconfig.uname +++ b/lib/posix/options/Kconfig.uname @@ -2,7 +2,7 @@ # # SPDX-License-Identifier: Apache-2.0 -config POSIX_UNAME +menuconfig POSIX_UNAME bool "Support for uname" default y if POSIX_API help diff --git a/lib/posix/_common.c b/lib/posix/options/_common.c similarity index 100% rename from lib/posix/_common.c rename to lib/posix/options/_common.c diff --git a/lib/posix/barrier.c b/lib/posix/options/barrier.c similarity index 100% rename from lib/posix/barrier.c rename to lib/posix/options/barrier.c diff --git a/lib/posix/clock.c b/lib/posix/options/clock.c similarity index 100% rename from lib/posix/clock.c rename to lib/posix/options/clock.c diff --git a/lib/posix/cond.c b/lib/posix/options/cond.c similarity index 100% rename from lib/posix/cond.c rename to lib/posix/options/cond.c diff --git a/lib/posix/eventfd.c b/lib/posix/options/eventfd.c similarity index 100% rename from lib/posix/eventfd.c rename to lib/posix/options/eventfd.c diff --git a/lib/posix/fnmatch.c b/lib/posix/options/fnmatch.c similarity index 100% rename from lib/posix/fnmatch.c rename to lib/posix/options/fnmatch.c diff --git a/lib/posix/fs.c b/lib/posix/options/fs.c similarity index 100% rename from lib/posix/fs.c rename to lib/posix/options/fs.c diff --git a/lib/posix/getopt/CMakeLists.txt b/lib/posix/options/getopt/CMakeLists.txt similarity index 100% rename from lib/posix/getopt/CMakeLists.txt rename to lib/posix/options/getopt/CMakeLists.txt diff --git a/lib/posix/getopt/Kconfig b/lib/posix/options/getopt/Kconfig similarity index 100% rename from lib/posix/getopt/Kconfig rename to lib/posix/options/getopt/Kconfig diff --git a/lib/posix/getopt/README b/lib/posix/options/getopt/README similarity index 100% rename from lib/posix/getopt/README rename to lib/posix/options/getopt/README diff --git a/lib/posix/getopt/getopt.c b/lib/posix/options/getopt/getopt.c similarity index 100% rename from lib/posix/getopt/getopt.c rename to lib/posix/options/getopt/getopt.c diff --git a/lib/posix/getopt/getopt.h b/lib/posix/options/getopt/getopt.h similarity index 100% rename from lib/posix/getopt/getopt.h rename to lib/posix/options/getopt/getopt.h diff --git a/lib/posix/getopt/getopt_common.c b/lib/posix/options/getopt/getopt_common.c similarity index 100% rename from lib/posix/getopt/getopt_common.c rename to lib/posix/options/getopt/getopt_common.c diff --git a/lib/posix/getopt/getopt_common.h b/lib/posix/options/getopt/getopt_common.h similarity index 100% rename from lib/posix/getopt/getopt_common.h rename to lib/posix/options/getopt/getopt_common.h diff --git a/lib/posix/getopt/getopt_long.c b/lib/posix/options/getopt/getopt_long.c similarity index 100% rename from lib/posix/getopt/getopt_long.c rename to lib/posix/options/getopt/getopt_long.c diff --git a/lib/posix/key.c b/lib/posix/options/key.c similarity index 100% rename from lib/posix/key.c rename to lib/posix/options/key.c diff --git a/lib/posix/mqueue.c b/lib/posix/options/mqueue.c similarity index 100% rename from lib/posix/mqueue.c rename to lib/posix/options/mqueue.c diff --git a/lib/posix/mutex.c b/lib/posix/options/mutex.c similarity index 100% rename from lib/posix/mutex.c rename to lib/posix/options/mutex.c diff --git a/lib/posix/nanosleep.c b/lib/posix/options/nanosleep.c similarity index 100% rename from lib/posix/nanosleep.c rename to lib/posix/options/nanosleep.c diff --git a/lib/posix/perror.c b/lib/posix/options/perror.c similarity index 100% rename from lib/posix/perror.c rename to lib/posix/options/perror.c diff --git a/lib/posix/posix_clock.h b/lib/posix/options/posix_clock.h similarity index 100% rename from lib/posix/posix_clock.h rename to lib/posix/options/posix_clock.h diff --git a/lib/posix/posix_internal.h b/lib/posix/options/posix_internal.h similarity index 100% rename from lib/posix/posix_internal.h rename to lib/posix/options/posix_internal.h diff --git a/lib/posix/pthread.c b/lib/posix/options/pthread.c similarity index 100% rename from lib/posix/pthread.c rename to lib/posix/options/pthread.c diff --git a/lib/posix/pthread_sched.h b/lib/posix/options/pthread_sched.h similarity index 100% rename from lib/posix/pthread_sched.h rename to lib/posix/options/pthread_sched.h diff --git a/lib/posix/rwlock.c b/lib/posix/options/rwlock.c similarity index 100% rename from lib/posix/rwlock.c rename to lib/posix/options/rwlock.c diff --git a/lib/posix/sched.c b/lib/posix/options/sched.c similarity index 100% rename from lib/posix/sched.c rename to lib/posix/options/sched.c diff --git a/lib/posix/semaphore.c b/lib/posix/options/semaphore.c similarity index 100% rename from lib/posix/semaphore.c rename to lib/posix/options/semaphore.c diff --git a/lib/posix/signal.c b/lib/posix/options/signal.c similarity index 100% rename from lib/posix/signal.c rename to lib/posix/options/signal.c diff --git a/lib/posix/sleep.c b/lib/posix/options/sleep.c similarity index 100% rename from lib/posix/sleep.c rename to lib/posix/options/sleep.c diff --git a/lib/posix/spinlock.c b/lib/posix/options/spinlock.c similarity index 100% rename from lib/posix/spinlock.c rename to lib/posix/options/spinlock.c diff --git a/lib/posix/stropts.c b/lib/posix/options/stropts.c similarity index 100% rename from lib/posix/stropts.c rename to lib/posix/options/stropts.c diff --git a/lib/posix/timer.c b/lib/posix/options/timer.c similarity index 100% rename from lib/posix/timer.c rename to lib/posix/options/timer.c diff --git a/lib/posix/uname.c b/lib/posix/options/uname.c similarity index 100% rename from lib/posix/uname.c rename to lib/posix/options/uname.c diff --git a/lib/posix/shell/Kconfig b/lib/posix/shell/Kconfig index 1ce4ae5a959..d7116b492a8 100644 --- a/lib/posix/shell/Kconfig +++ b/lib/posix/shell/Kconfig @@ -1,6 +1,8 @@ # Copyright (c) 2024 Meta # SPDX-License-Identifier: Apache-2.0 +menu "POSIX Shell Utilities" + if SHELL config POSIX_SHELL @@ -11,3 +13,5 @@ config POSIX_SHELL rsource "Kconfig.uname" endif # SHELL + +endmenu # "POSIX Shell Utilities" diff --git a/samples/posix/philosophers/CMakeLists.txt b/samples/posix/philosophers/CMakeLists.txt index e8a6a207987..2f19561d195 100644 --- a/samples/posix/philosophers/CMakeLists.txt +++ b/samples/posix/philosophers/CMakeLists.txt @@ -7,4 +7,4 @@ project(posix_philosophers) target_sources(app PRIVATE src/main.c) # For translating POSIX scheduler policies and priorities to # Zephyr priorities. -target_include_directories(app PRIVATE ${ZEPHYR_BASE}/lib/posix) +target_include_directories(app PRIVATE ${ZEPHYR_BASE}/lib/posix/options) From e8b178411c7ede4279da03aa2c6d0402811480bd Mon Sep 17 00:00:00 2001 From: Christopher Friedt Date: Tue, 30 Jan 2024 23:58:30 -0500 Subject: [PATCH 3279/3723] posix: remove unneeded option to link with posix subsys The CONFIG_APP_LINK_WITH_POSIX_SUBSYS option was originally present so that internal POSIX implementation headers would be on the include path. There is no implicit need for any app or library to include private POSIX headers. Instead, the standard POSIX API should be used. Signed-off-by: Christopher Friedt --- doc/services/portability/posix/kconfig/index.rst | 1 - lib/posix/options/CMakeLists.txt | 5 ----- lib/posix/options/Kconfig | 9 --------- 3 files changed, 15 deletions(-) diff --git a/doc/services/portability/posix/kconfig/index.rst b/doc/services/portability/posix/kconfig/index.rst index c1599dd5506..0ce0e5bb4b4 100644 --- a/doc/services/portability/posix/kconfig/index.rst +++ b/doc/services/portability/posix/kconfig/index.rst @@ -6,7 +6,6 @@ Configuration Options This is a non-exhaustive list of specific :ref:`kconfig` options relating to Zephyr's implementation of the POSIX API. -* :kconfig:option:`CONFIG_APP_LINK_WITH_POSIX_SUBSYS` * :kconfig:option:`CONFIG_EVENTFD` * :kconfig:option:`CONFIG_EVENTFD_MAX` * :kconfig:option:`CONFIG_FDTABLE` diff --git a/lib/posix/options/CMakeLists.txt b/lib/posix/options/CMakeLists.txt index b523e859e86..a0c1722df6a 100644 --- a/lib/posix/options/CMakeLists.txt +++ b/lib/posix/options/CMakeLists.txt @@ -6,8 +6,6 @@ zephyr_syscall_header( posix_clock.h ) -zephyr_interface_library_named(posix_subsys) - if(CONFIG_POSIX_API) zephyr_include_directories(${ZEPHYR_BASE}/include/zephyr/posix) endif() @@ -63,6 +61,3 @@ zephyr_library_include_directories( ${ZEPHYR_BASE}/kernel/include ${ARCH_DIR}/${ARCH}/include ) - -zephyr_library_link_libraries(posix_subsys) -zephyr_library_property(ALLOW_EMPTY TRUE) diff --git a/lib/posix/options/Kconfig b/lib/posix/options/Kconfig index 9b738c9bdba..c2673e164dd 100644 --- a/lib/posix/options/Kconfig +++ b/lib/posix/options/Kconfig @@ -12,15 +12,6 @@ config POSIX_API Enable mostly-standards-compliant implementations of various POSIX (IEEE 1003.1) APIs. -# The name of this option is mandated by zephyr_interface_library_named -# cmake directive. -config APP_LINK_WITH_POSIX_SUBSYS - bool "Make POSIX headers available to application" - default y - depends on POSIX_API - help - Add POSIX subsystem header files to the 'app' include path. - if POSIX_CLOCK config PTHREAD_IPC From 52b619cd2b17496e31a4d377adc56b6a621bd289 Mon Sep 17 00:00:00 2001 From: Christopher Friedt Date: Wed, 31 Jan 2024 00:19:29 -0500 Subject: [PATCH 3280/3723] samples: philosophers correct misspelled introduction tag The tag 'introduction' was misspelled 'inroduction'. Correct it both the samples/philosophers and the samples/posix/philosophers directories. Signed-off-by: Christopher Friedt --- samples/philosophers/sample.yaml | 2 +- samples/posix/philosophers/sample.yaml | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/samples/philosophers/sample.yaml b/samples/philosophers/sample.yaml index 2db2c1563f4..5ca2a2d8340 100644 --- a/samples/philosophers/sample.yaml +++ b/samples/philosophers/sample.yaml @@ -3,7 +3,7 @@ sample: common: extra_args: DEBUG_PRINTF=1 tags: - - inroduction + - introduction - kernel harness: console min_ram: 16 diff --git a/samples/posix/philosophers/sample.yaml b/samples/posix/philosophers/sample.yaml index 1e3a6a2cb36..08e0c1d970a 100644 --- a/samples/posix/philosophers/sample.yaml +++ b/samples/posix/philosophers/sample.yaml @@ -2,7 +2,7 @@ sample: name: POSIX Philosophers common: tags: - - inroduction + - introduction - posix harness: console min_ram: 16 From 9122e8530fce9235bfb71f23b65cb48baf9df582 Mon Sep 17 00:00:00 2001 From: Christopher Friedt Date: Wed, 31 Jan 2024 00:24:09 -0500 Subject: [PATCH 3281/3723] samples: posix: philosophers: minor spacing corrections Fix spacing and wrapping in the README.rst file. Signed-off-by: Christopher Friedt --- samples/posix/philosophers/README.rst | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/samples/posix/philosophers/README.rst b/samples/posix/philosophers/README.rst index e7e1b958e5c..a480d4398a7 100644 --- a/samples/posix/philosophers/README.rst +++ b/samples/posix/philosophers/README.rst @@ -13,8 +13,7 @@ This sample implements Zephyr's :ref:`Dining Philosophers Sample Date: Wed, 31 Jan 2024 00:40:01 -0500 Subject: [PATCH 3282/3723] samples: posix: philosophers: fix off-by-one error The number of forks should match the number of philophers, and that is encoded via NUM_PHIL. Change the build assert to match. Signed-off-by: Christopher Friedt --- samples/posix/philosophers/src/main.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/samples/posix/philosophers/src/main.c b/samples/posix/philosophers/src/main.c index bf1db7d707f..29861803aab 100644 --- a/samples/posix/philosophers/src/main.c +++ b/samples/posix/philosophers/src/main.c @@ -25,7 +25,7 @@ #define obj_init_type "POSIX" #define fork_type_str "mutexes" -BUILD_ASSERT(CONFIG_MAX_PTHREAD_COUNT == CONFIG_MAX_PTHREAD_MUTEX_COUNT - 1); +BUILD_ASSERT(CONFIG_MAX_PTHREAD_COUNT == CONFIG_MAX_PTHREAD_MUTEX_COUNT); BUILD_ASSERT(CONFIG_DYNAMIC_THREAD_POOL_SIZE == CONFIG_MAX_PTHREAD_COUNT); typedef pthread_mutex_t *fork_t; From dd33a8152a36db9e624859a08ae5eb1676274b78 Mon Sep 17 00:00:00 2001 From: Christopher Friedt Date: Wed, 31 Jan 2024 00:35:10 -0500 Subject: [PATCH 3283/3723] samples: philosophers: remove redundant items in prj.conf The normal and posix philosophers samples seemed to have a number of redundant choices in prj.conf. Let's reduce to the minimum required for the sample. The CONFIG_DEBUG_THREAD_INFO option is part of the documentation, so leave it as-is. Signed-off-by: Christopher Friedt --- samples/philosophers/prj.conf | 5 ----- samples/posix/philosophers/prj.conf | 14 +------------- 2 files changed, 1 insertion(+), 18 deletions(-) diff --git a/samples/philosophers/prj.conf b/samples/philosophers/prj.conf index 8db50d11529..05e25c210d7 100644 --- a/samples/philosophers/prj.conf +++ b/samples/philosophers/prj.conf @@ -1,9 +1,4 @@ CONFIG_STDOUT_CONSOLE=n -CONFIG_ASSERT=y -CONFIG_ASSERT_LEVEL=2 -CONFIG_NUM_COOP_PRIORITIES=29 -CONFIG_NUM_PREEMPT_PRIORITIES=40 -CONFIG_SCHED_SCALABLE=y CONFIG_MP_MAX_NUM_CPUS=1 #Enable thread awareness for debugging tools supporting it diff --git a/samples/posix/philosophers/prj.conf b/samples/posix/philosophers/prj.conf index ccee021cdf7..0934325aea6 100644 --- a/samples/posix/philosophers/prj.conf +++ b/samples/posix/philosophers/prj.conf @@ -1,25 +1,13 @@ CONFIG_STDOUT_CONSOLE=n -CONFIG_ASSERT=y -CONFIG_ASSERT_LEVEL=2 -CONFIG_NUM_COOP_PRIORITIES=29 -CONFIG_NUM_PREEMPT_PRIORITIES=40 -CONFIG_SCHED_SCALABLE=y CONFIG_MP_MAX_NUM_CPUS=1 -CONFIG_LOG=y -CONFIG_LOG_MODE_MINIMAL=y - CONFIG_POSIX_API=y CONFIG_THREAD_STACK_INFO=y CONFIG_DYNAMIC_THREAD=y CONFIG_DYNAMIC_THREAD_POOL_SIZE=6 CONFIG_MAX_PTHREAD_COUNT=6 -CONFIG_MAX_PTHREAD_MUTEX_COUNT=7 +CONFIG_MAX_PTHREAD_MUTEX_COUNT=6 #Enable thread awareness for debugging tools supporting it CONFIG_DEBUG_THREAD_INFO=y - -# CONFIG_SAMPLE_ERROR_CHECKING=y -# CONFIG_PTHREAD_MUTEX_LOG_LEVEL_DBG=y -# CONFIG_PTHREAD_LOG_LEVEL_DBG=y From 738999e191297c737fda647b5ba73e9897a581a8 Mon Sep 17 00:00:00 2001 From: Torsten Rasmussen Date: Fri, 26 Jan 2024 11:18:09 +0100 Subject: [PATCH 3284/3723] version: export tweak version in version.h The commit export TWEAK version to code through version.h. This aligns the symbols available in code with those available in CMake and Kconfig. The new define is available for both KERNEL, APP, and custom version types (such as MCUBOOT). Signed-off-by: Torsten Rasmussen --- doc/build/version/index.rst | 2 ++ version.h.in | 1 + 2 files changed, 3 insertions(+) diff --git a/doc/build/version/index.rst b/doc/build/version/index.rst index 8d169a85bf5..ef702c7ac2c 100644 --- a/doc/build/version/index.rst +++ b/doc/build/version/index.rst @@ -91,6 +91,8 @@ following defines are available: +--------------------+-------------------+------------------------------------------------------+-------------------------+ | APP_PATCHLEVEL | Numerical | ``PATCHLEVEL`` | 3 | +--------------------+-------------------+------------------------------------------------------+-------------------------+ +| APP_VERSION_TWEAK | Numerical | ``VERSION_TWEAK`` | 4 | ++--------------------+-------------------+------------------------------------------------------+-------------------------+ | APP_VERSION_STRING | String (quoted) | ``VERSION_MAJOR``, |br| | "1.2.3-unstable" | | | | ``VERSION_MINOR``, |br| | | | | | ``PATCHLEVEL``, |br| | | diff --git a/version.h.in b/version.h.in index c60fb721804..476d97eabbb 100644 --- a/version.h.in +++ b/version.h.in @@ -14,6 +14,7 @@ #define @VERSION_TYPE@_VERSION_MAJOR @@VERSION_TYPE@_VERSION_MAJOR@ #define @VERSION_TYPE@_VERSION_MINOR @@VERSION_TYPE@_VERSION_MINOR@ #define @VERSION_TYPE@_PATCHLEVEL @@VERSION_TYPE@_PATCHLEVEL@ +#define @VERSION_TYPE@_TWEAK @@VERSION_TYPE@_VERSION_TWEAK@ #define @VERSION_TYPE@_VERSION_STRING "@@VERSION_TYPE@_VERSION_STRING@" #define @BUILD_VERSION_NAME@ @@BUILD_VERSION_NAME@@ From a306397818d2644e5b2a5222bf5cc3a4a81da0d4 Mon Sep 17 00:00:00 2001 From: Torsten Rasmussen Date: Fri, 26 Jan 2024 12:19:29 +0100 Subject: [PATCH 3285/3723] version: cmake: kconfig: introduce extra _VERSION__STRING Fixes: #68360 This commit introduces _VERSION_TWEAK_STRING which includes the tweak field in the string, but without the extra version. This format is used by MCUboot / imgtool, and thus makes it easier to align code to the format used by MCUboot. This commit also introduces _VERSION_EXTENDED_STRING which includes the tweak field in the string in addition to the extra version field. The new defines / variables is available in code, CMake, and Kconfig, and it defined for KERNEL, APP, and custom types, such as MCUBOOT. Signed-off-by: Torsten Rasmussen Signed-off-by: Jamie McCrae --- cmake/modules/kconfig.cmake | 2 + cmake/modules/version.cmake | 14 ++- doc/build/version/index.rst | 174 +++++++++++++++++++++--------------- version.h.in | 16 ++-- 4 files changed, 123 insertions(+), 83 deletions(-) diff --git a/cmake/modules/kconfig.cmake b/cmake/modules/kconfig.cmake index 632e9a72422..2077dc926e7 100644 --- a/cmake/modules/kconfig.cmake +++ b/cmake/modules/kconfig.cmake @@ -133,6 +133,8 @@ set(COMMON_KCONFIG_ENV_SETTINGS srctree=${ZEPHYR_BASE} KERNELVERSION=${KERNELVERSION} APPVERSION=${APP_VERSION_STRING} + APP_VERSION_EXTENDED_STRING=${APP_VERSION_EXTENDED_STRING} + APP_VERSION_TWEAK_STRING=${APP_VERSION_TWEAK_STRING} CONFIG_=${KCONFIG_NAMESPACE}_ KCONFIG_CONFIG=${DOTCONFIG} # Set environment variables so that Kconfig can prune Kconfig source diff --git a/cmake/modules/version.cmake b/cmake/modules/version.cmake index 34f2cf99d68..72c0424031a 100644 --- a/cmake/modules/version.cmake +++ b/cmake/modules/version.cmake @@ -11,8 +11,10 @@ # # Outputs with examples:: # -# PROJECT_VERSION 1.14.99.07 -# KERNEL_VERSION_STRING "1.14.99-extraver" +# PROJECT_VERSION 1.14.99.07 +# KERNEL_VERSION_STRING "1.14.99-extraver" +# KERNEL_VERSION_EXTENDED_STRING "1.14.99-extraver+7" +# KERNEL_VERSION_TWEAK_STRING "1.14.99+7" # # KERNEL_VERSION_MAJOR 1 # KERNEL_VERSION_MINOR 14 @@ -60,9 +62,9 @@ foreach(type file IN ZIP_LISTS VERSION_TYPE VERSION_FILE) string(REGEX MATCH "EXTRAVERSION = ([a-z0-9]*)" _ ${ver}) set(${type}_VERSION_EXTRA ${CMAKE_MATCH_1}) - # Temporary convenience variable + # Temporary convenience variables set(${type}_VERSION_WITHOUT_TWEAK ${${type}_VERSION_MAJOR}.${${type}_VERSION_MINOR}.${${type}_PATCHLEVEL}) - + set(${type}_VERSION_WITH_TWEAK ${${type}_VERSION_MAJOR}.${${type}_VERSION_MINOR}.${${type}_PATCHLEVEL}+${${type}_VERSION_TWEAK}) set(MAJOR ${${type}_VERSION_MAJOR}) # Temporary convenience variable set(MINOR ${${type}_VERSION_MINOR}) # Temporary convenience variable @@ -80,6 +82,8 @@ foreach(type file IN ZIP_LISTS VERSION_TYPE VERSION_FILE) else() set(${type}_VERSION_STRING "${${type}_VERSION_WITHOUT_TWEAK}") endif() + set(${type}_VERSION_TWEAK_STRING "${${type}_VERSION_WITH_TWEAK}") + set(${type}_VERSION_EXTENDED_STRING "${${type}_VERSION_STRING}+${${type}_VERSION_TWEAK}") if(type STREQUAL KERNEL) set(PROJECT_VERSION_MAJOR ${${type}_VERSION_MAJOR}) @@ -116,5 +120,7 @@ foreach(type file IN ZIP_LISTS VERSION_TYPE VERSION_FILE) unset(MAJOR) unset(MINOR) unset(PATCH) + unset(TWEAK) unset(${type}_VERSION_WITHOUT_TWEAK) + unset(${type}_VERSION_WITH_TWEAK) endforeach() diff --git a/doc/build/version/index.rst b/doc/build/version/index.rst index ef702c7ac2c..2106a65e169 100644 --- a/doc/build/version/index.rst +++ b/doc/build/version/index.rst @@ -73,87 +73,120 @@ To use the version information in application code, the version file must be inc fields can be freely used. The include file name is :file:`app_version.h` (no path is needed), the following defines are available: -+--------------------+-------------------+------------------------------------------------------+-------------------------+ -| Define | Type | Field(s) | Example | -+--------------------+-------------------+------------------------------------------------------+-------------------------+ -| APPVERSION | Numerical | ``VERSION_MAJOR`` (left shifted by 24 bits), |br| | 0x1020304 | -| | | ``VERSION_MINOR`` (left shifted by 16 bits), |br| | | -| | | ``PATCHLEVEL`` (left shifted by 8 bits), |br| | | -| | | ``VERSION_TWEAK`` | | -+--------------------+-------------------+------------------------------------------------------+-------------------------+ -| APP_VERSION_NUMBER | Numerical | ``VERSION_MAJOR`` (left shifted by 16 bits), |br| | 0x10203 | -| | | ``VERSION_MINOR`` (left shifted by 8 bits), |br| | | -| | | ``PATCHLEVEL`` | | -+--------------------+-------------------+------------------------------------------------------+-------------------------+ -| APP_VERSION_MAJOR | Numerical | ``VERSION_MAJOR`` | 1 | -+--------------------+-------------------+------------------------------------------------------+-------------------------+ -| APP_VERSION_MINOR | Numerical | ``VERSION_MINOR`` | 2 | -+--------------------+-------------------+------------------------------------------------------+-------------------------+ -| APP_PATCHLEVEL | Numerical | ``PATCHLEVEL`` | 3 | -+--------------------+-------------------+------------------------------------------------------+-------------------------+ -| APP_VERSION_TWEAK | Numerical | ``VERSION_TWEAK`` | 4 | -+--------------------+-------------------+------------------------------------------------------+-------------------------+ -| APP_VERSION_STRING | String (quoted) | ``VERSION_MAJOR``, |br| | "1.2.3-unstable" | -| | | ``VERSION_MINOR``, |br| | | -| | | ``PATCHLEVEL``, |br| | | -| | | ``EXTRAVERSION`` |br| | | -+--------------------+-------------------+------------------------------------------------------+-------------------------+ -| APP_BUILD_VERSION | String (unquoted) | None (value of ``git describe --abbrev=12 --always`` | v3.3.0-18-g2c85d9224fca | -| | | from application repository) | | -+--------------------+-------------------+------------------------------------------------------+-------------------------+ ++-----------------------------+-------------------+------------------------------------------------------+-------------------------+ +| Define | Type | Field(s) | Example | ++-----------------------------+-------------------+------------------------------------------------------+-------------------------+ +| APPVERSION | Numerical | ``VERSION_MAJOR`` (left shifted by 24 bits), |br| | 0x1020304 | +| | | ``VERSION_MINOR`` (left shifted by 16 bits), |br| | | +| | | ``PATCHLEVEL`` (left shifted by 8 bits), |br| | | +| | | ``VERSION_TWEAK`` | | ++-----------------------------+-------------------+------------------------------------------------------+-------------------------+ +| APP_VERSION_NUMBER | Numerical | ``VERSION_MAJOR`` (left shifted by 16 bits), |br| | 0x10203 | +| | | ``VERSION_MINOR`` (left shifted by 8 bits), |br| | | +| | | ``PATCHLEVEL`` | | ++-----------------------------+-------------------+------------------------------------------------------+-------------------------+ +| APP_VERSION_MAJOR | Numerical | ``VERSION_MAJOR`` | 1 | ++-----------------------------+-------------------+------------------------------------------------------+-------------------------+ +| APP_VERSION_MINOR | Numerical | ``VERSION_MINOR`` | 2 | ++-----------------------------+-------------------+------------------------------------------------------+-------------------------+ +| APP_PATCHLEVEL | Numerical | ``PATCHLEVEL`` | 3 | ++-----------------------------+-------------------+------------------------------------------------------+-------------------------+ +| APP_VERSION_TWEAK | Numerical | ``VERSION_TWEAK`` | 4 | ++-----------------------------+-------------------+------------------------------------------------------+-------------------------+ +| APP_VERSION_STRING | String (quoted) | ``VERSION_MAJOR``, |br| | "1.2.3-unstable" | +| | | ``VERSION_MINOR``, |br| | | +| | | ``PATCHLEVEL``, |br| | | +| | | ``EXTRAVERSION`` |br| | | ++-----------------------------+-------------------+------------------------------------------------------+-------------------------+ +| APP_VERSION_EXTENDED_STRING | String (quoted) | ``VERSION_MAJOR``, |br| | "1.2.3-unstable+4" | +| | | ``VERSION_MINOR``, |br| | | +| | | ``PATCHLEVEL``, |br| | | +| | | ``EXTRAVERSION`` |br| | | +| | | ``VERSION_TWEAK`` |br| | | ++-----------------------------+-------------------+------------------------------------------------------+-------------------------+ +| APP_VERSION_TWEAK_STRING | String (quoted) | ``VERSION_MAJOR``, |br| | "1.2.3+4" | +| | | ``VERSION_MINOR``, |br| | | +| | | ``PATCHLEVEL``, |br| | | +| | | ``VERSION_TWEAK`` |br| | | ++-----------------------------+-------------------+------------------------------------------------------+-------------------------+ +| APP_BUILD_VERSION | String (unquoted) | None (value of ``git describe --abbrev=12 --always`` | v3.3.0-18-g2c85d9224fca | +| | | from application repository) | | ++-----------------------------+-------------------+------------------------------------------------------+-------------------------+ Use in Kconfig ============== The following variables are available for usage in Kconfig files: -+------------------+-----------+-------------------------+----------------+ -| Variable | Type | Field(s) | Example | -+------------------+-----------+-------------------------+----------------+ -| $(VERSION_MAJOR) | Numerical | ``VERSION_MAJOR`` | 1 | -+------------------+-----------+-------------------------+----------------+ -| $(VERSION_MINOR) | Numerical | ``VERSION_MINOR`` | 2 | -+------------------+-----------+-------------------------+----------------+ -| $(PATCHLEVEL) | Numerical | ``PATCHLEVEL`` | 3 | -+------------------+-----------+-------------------------+----------------+ -| $(VERSION_TWEAK) | Numerical | ``VERSION_TWEAK`` | 4 | -+------------------+-----------+-------------------------+----------------+ -| $(APPVERSION) | String | ``VERSION_MAJOR``, |br| | 1.2.3-unstable | -| | | ``VERSION_MINOR``, |br| | | -| | | ``PATCHLEVEL``, |br| | | -| | | ``EXTRAVERSION`` | | -+------------------+-----------+-------------------------+----------------+ ++--------------------------------+-----------+--------------------------+------------------+ +| Variable | Type | Field(s) | Example | ++--------------------------------+-----------+--------------------------+------------------+ +| $(VERSION_MAJOR) | Numerical | ``VERSION_MAJOR`` | 1 | ++--------------------------------+-----------+--------------------------+------------------+ +| $(VERSION_MINOR) | Numerical | ``VERSION_MINOR`` | 2 | ++--------------------------------+-----------+--------------------------+------------------+ +| $(PATCHLEVEL) | Numerical | ``PATCHLEVEL`` | 3 | ++--------------------------------+-----------+--------------------------+------------------+ +| $(VERSION_TWEAK) | Numerical | ``VERSION_TWEAK`` | 4 | ++--------------------------------+-----------+--------------------------+------------------+ +| $(APPVERSION) | String | ``VERSION_MAJOR``, |br| | 1.2.3-unstable | +| | | ``VERSION_MINOR``, |br| | | +| | | ``PATCHLEVEL``, |br| | | +| | | ``EXTRAVERSION`` | | ++--------------------------------+-----------+--------------------------+------------------+ +| $(APP_VERSION_EXTENDED_STRING) | String | ``VERSION_MAJOR``, |br| | 1.2.3-unstable+4 | +| | | ``VERSION_MINOR``, |br| | | +| | | ``PATCHLEVEL``, |br| | | +| | | ``EXTRAVERSION``, |br| | | +| | | ``VERSION_TWEAK`` | | ++--------------------------------+-----------+--------------------------+------------------+ +| $(APP_VERSION_TWEAK_STRING) | String | ``VERSION_MAJOR``, |br| | 1.2.3+4 | +| | | ``VERSION_MINOR``, |br| | | +| | | ``PATCHLEVEL``, |br| | | +| | | ``VERSION_TWEAK`` | | ++--------------------------------+-----------+--------------------------+------------------+ Use in CMake ============ The following variable are available for usage in CMake files: -+--------------------+-----------------+---------------------------------------------------+----------------+ -| Variable | Type | Field(s) | Example | -+--------------------+-----------------+---------------------------------------------------+----------------+ -| APPVERSION | Numerical (hex) | ``VERSION_MAJOR`` (left shifted by 24 bits), |br| | 0x1020304 | -| | | ``VERSION_MINOR`` (left shifted by 16 bits), |br| | | -| | | ``PATCHLEVEL`` (left shifted by 8 bits), |br| | | -| | | ``VERSION_TWEAK`` | | -+--------------------+-----------------+---------------------------------------------------+----------------+ -| APP_VERSION_NUMBER | Numerical (hex) | ``VERSION_MAJOR`` (left shifted by 16 bits), |br| | 0x10203 | -| | | ``VERSION_MINOR`` (left shifted by 8 bits), |br| | | -| | | ``PATCHLEVEL`` | | -+--------------------+-----------------+---------------------------------------------------+----------------+ -| APP_VERSION_MAJOR | Numerical | ``VERSION_MAJOR`` | 1 | -+--------------------+-----------------+---------------------------------------------------+----------------+ -| APP_VERSION_MINOR | Numerical | ``VERSION_MINOR`` | 2 | -+--------------------+-----------------+---------------------------------------------------+----------------+ -| APP_PATCHLEVEL | Numerical | ``PATCHLEVEL`` | 3 | -+--------------------+-----------------+---------------------------------------------------+----------------+ -| APP_VERSION_TWEAK | Numerical | ``VERSION_TWEAK`` | 4 | -+--------------------+-----------------+---------------------------------------------------+----------------+ -| APP_VERSION_STRING | String | ``VERSION_MAJOR``, |br| | 1.2.3-unstable | -| | | ``VERSION_MINOR``, |br| | | -| | | ``PATCHLEVEL``, |br| | | -| | | ``EXTRAVERSION`` | | -+--------------------+-----------------+---------------------------------------------------+----------------+ ++-----------------------------+-----------------+---------------------------------------------------+------------------+ +| Variable | Type | Field(s) | Example | ++-----------------------------+-----------------+---------------------------------------------------+------------------+ +| APPVERSION | Numerical (hex) | ``VERSION_MAJOR`` (left shifted by 24 bits), |br| | 0x1020304 | +| | | ``VERSION_MINOR`` (left shifted by 16 bits), |br| | | +| | | ``PATCHLEVEL`` (left shifted by 8 bits), |br| | | +| | | ``VERSION_TWEAK`` | | ++-----------------------------+-----------------+---------------------------------------------------+------------------+ +| APP_VERSION_NUMBER | Numerical (hex) | ``VERSION_MAJOR`` (left shifted by 16 bits), |br| | 0x10203 | +| | | ``VERSION_MINOR`` (left shifted by 8 bits), |br| | | +| | | ``PATCHLEVEL`` | | ++-----------------------------+-----------------+---------------------------------------------------+------------------+ +| APP_VERSION_MAJOR | Numerical | ``VERSION_MAJOR`` | 1 | ++-----------------------------+-----------------+---------------------------------------------------+------------------+ +| APP_VERSION_MINOR | Numerical | ``VERSION_MINOR`` | 2 | ++-----------------------------+-----------------+---------------------------------------------------+------------------+ +| APP_PATCHLEVEL | Numerical | ``PATCHLEVEL`` | 3 | ++-----------------------------+-----------------+---------------------------------------------------+------------------+ +| APP_VERSION_TWEAK | Numerical | ``VERSION_TWEAK`` | 4 | ++-----------------------------+-----------------+---------------------------------------------------+------------------+ +| APP_VERSION_STRING | String | ``VERSION_MAJOR``, |br| | 1.2.3-unstable | +| | | ``VERSION_MINOR``, |br| | | +| | | ``PATCHLEVEL``, |br| | | +| | | ``EXTRAVERSION`` | | ++-----------------------------+-----------------+---------------------------------------------------+------------------+ +| APP_VERSION_EXTENDED_STRING | String | ``VERSION_MAJOR``, |br| | 1.2.3-unstable+4 | +| | | ``VERSION_MINOR``, |br| | | +| | | ``PATCHLEVEL``, |br| | | +| | | ``EXTRAVERSION``, |br| | | +| | | ``VERSION_TWEAK`` | | ++-----------------------------+-----------------+---------------------------------------------------+------------------+ +| APP_VERSION_TWEAK_STRING | String | ``VERSION_MAJOR``, |br| | 1.2.3+4 | +| | | ``VERSION_MINOR``, |br| | | +| | | ``PATCHLEVEL``, |br| | | +| | | ``VERSION_TWEAK`` | | ++-----------------------------+-----------------+---------------------------------------------------+------------------+ Use in MCUboot-supported applications ===================================== @@ -161,6 +194,3 @@ Use in MCUboot-supported applications No additional configuration needs to be done to the target application so long as it is configured to support MCUboot and a signed image is generated, the version information will be automatically included in the image data. - -The format used for signing is ``VERSION_MAJOR`` . ``VERSION_MINOR`` . ``PATCHLEVEL``, the tweak -version field is not currently used. diff --git a/version.h.in b/version.h.in index 476d97eabbb..bfb2eb3edb7 100644 --- a/version.h.in +++ b/version.h.in @@ -9,13 +9,15 @@ #cmakedefine ZEPHYR_VERSION_CODE @ZEPHYR_VERSION_CODE@ #cmakedefine ZEPHYR_VERSION(a,b,c) (((a) << 16) + ((b) << 8) + (c)) -#define @VERSION_TYPE@VERSION @@VERSION_TYPE@VERSION@ -#define @VERSION_TYPE@_VERSION_NUMBER @@VERSION_TYPE@_VERSION_NUMBER@ -#define @VERSION_TYPE@_VERSION_MAJOR @@VERSION_TYPE@_VERSION_MAJOR@ -#define @VERSION_TYPE@_VERSION_MINOR @@VERSION_TYPE@_VERSION_MINOR@ -#define @VERSION_TYPE@_PATCHLEVEL @@VERSION_TYPE@_PATCHLEVEL@ -#define @VERSION_TYPE@_TWEAK @@VERSION_TYPE@_VERSION_TWEAK@ -#define @VERSION_TYPE@_VERSION_STRING "@@VERSION_TYPE@_VERSION_STRING@" +#define @VERSION_TYPE@VERSION @@VERSION_TYPE@VERSION@ +#define @VERSION_TYPE@_VERSION_NUMBER @@VERSION_TYPE@_VERSION_NUMBER@ +#define @VERSION_TYPE@_VERSION_MAJOR @@VERSION_TYPE@_VERSION_MAJOR@ +#define @VERSION_TYPE@_VERSION_MINOR @@VERSION_TYPE@_VERSION_MINOR@ +#define @VERSION_TYPE@_PATCHLEVEL @@VERSION_TYPE@_PATCHLEVEL@ +#define @VERSION_TYPE@_TWEAK @@VERSION_TYPE@_VERSION_TWEAK@ +#define @VERSION_TYPE@_VERSION_STRING "@@VERSION_TYPE@_VERSION_STRING@" +#define @VERSION_TYPE@_VERSION_EXTENDED_STRING "@@VERSION_TYPE@_VERSION_EXTENDED_STRING@" +#define @VERSION_TYPE@_VERSION_TWEAK_STRING "@@VERSION_TYPE@_VERSION_TWEAK_STRING@" #define @BUILD_VERSION_NAME@ @@BUILD_VERSION_NAME@@ @@VERSION_TYPE@_VERSION_CUSTOMIZATION@ From 835d78ec59e185705238acc46cfaaefaa1ea7024 Mon Sep 17 00:00:00 2001 From: Jamie McCrae Date: Thu, 1 Feb 2024 08:24:59 +0000 Subject: [PATCH 3286/3723] mcuboot: Use tweak version string Replaces the default with a shorter variable of equal value Signed-off-by: Jamie McCrae --- modules/Kconfig.mcuboot | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/Kconfig.mcuboot b/modules/Kconfig.mcuboot index b9b842b0a36..a2e1803b138 100644 --- a/modules/Kconfig.mcuboot +++ b/modules/Kconfig.mcuboot @@ -103,7 +103,7 @@ config MCUBOOT_ENCRYPTION_KEY_FILE config MCUBOOT_IMGTOOL_SIGN_VERSION string "Version to pass to imgtool when signing" - default "$(VERSION_MAJOR).$(VERSION_MINOR).$(PATCHLEVEL)+$(VERSION_TWEAK)" if "$(VERSION_MAJOR)" != "" + default "$(APP_VERSION_TWEAK_STRING)" if "$(VERSION_MAJOR)" != "" default "0.0.0+0" help When signing with imgtool then this setting will be passed as version From fcb8fa7b022b87177d16e3c97008f9a20bfdde90 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Stine=20=C3=85kredalen?= Date: Tue, 30 Jan 2024 00:53:01 -0800 Subject: [PATCH 3287/3723] tests: bluetooth: mesh: blob test bugfix MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Added missing end marker to test instance Signed-off-by: Stine Åkredalen --- tests/bsim/bluetooth/mesh/src/test_blob.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/tests/bsim/bluetooth/mesh/src/test_blob.c b/tests/bsim/bluetooth/mesh/src/test_blob.c index 0d3a69da2fc..36d816d3558 100644 --- a/tests/bsim/bluetooth/mesh/src/test_blob.c +++ b/tests/bsim/bluetooth/mesh/src/test_blob.c @@ -1715,6 +1715,8 @@ static const struct bst_test_instance test_blob_pst[] = { TEST_CASE(cli, stop, "Client expecting server to stop after reaching configured phase and continuing"), TEST_CASE(srv, stop, "Server stopping after reaching configured xfer phase"), + + BSTEST_END_MARKER }; struct bst_test_list *test_blob_pst_install(struct bst_test_list *tests) From 476a224dfa280416d74a7304fda8a14d0fa2fc5c Mon Sep 17 00:00:00 2001 From: Alexander Kaiser Date: Wed, 15 Nov 2023 10:05:24 -0700 Subject: [PATCH 3288/3723] usb: host: use uint16_t for Language ID usbh_req_desc() truncates the descriptor id. This problem is most visible with string descriptor requests, as only then can wIndex be greater than 0xFF. In particular, this affects commonly used language IDs such as English (United States), which is 0x0409. Signed-off-by: Alexander Kaiser --- subsys/usb/host/usbh_ch9.c | 2 +- subsys/usb/host/usbh_ch9.h | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/subsys/usb/host/usbh_ch9.c b/subsys/usb/host/usbh_ch9.c index f8f587a43c3..e3f55e95eb1 100644 --- a/subsys/usb/host/usbh_ch9.c +++ b/subsys/usb/host/usbh_ch9.c @@ -85,7 +85,7 @@ int usbh_req_setup(struct usb_device *const udev, int usbh_req_desc(struct usb_device *const udev, const uint8_t type, const uint8_t index, - const uint8_t id, + const uint16_t id, const uint16_t len, struct net_buf *const buf) { diff --git a/subsys/usb/host/usbh_ch9.h b/subsys/usb/host/usbh_ch9.h index 26c21c83715..a60dc86527b 100644 --- a/subsys/usb/host/usbh_ch9.h +++ b/subsys/usb/host/usbh_ch9.h @@ -22,7 +22,7 @@ int usbh_req_setup(struct usb_device *const udev, int usbh_req_desc(struct usb_device *const udev, const uint8_t type, const uint8_t index, - const uint8_t id, + const uint16_t id, const uint16_t len, struct net_buf *const data); From 8aea0e75d2358dc9f6efd27a05c8741d6902f4f9 Mon Sep 17 00:00:00 2001 From: Eve Redero Date: Thu, 1 Feb 2024 08:59:35 +0100 Subject: [PATCH 3289/3723] fix: samples: lvgl: modules: add missing test case Add missing test case for LVGL demo app "widgets". Signed-off-by: Eve Redero --- samples/modules/lvgl/demos/sample.yaml | 3 +++ 1 file changed, 3 insertions(+) diff --git a/samples/modules/lvgl/demos/sample.yaml b/samples/modules/lvgl/demos/sample.yaml index 2b9939eb4fd..bd7461dd46c 100644 --- a/samples/modules/lvgl/demos/sample.yaml +++ b/samples/modules/lvgl/demos/sample.yaml @@ -21,6 +21,9 @@ tests: sample.modules.lvgl.demo_stress: extra_configs: - CONFIG_LV_Z_DEMO_STRESS=y + sample.modules.lvgl.demo_widgets: + extra_configs: + - CONFIG_LV_Z_DEMO_WIDGETS=y sample.modules.lvgl.demos.st_b_lcd40_dsi1_mb1166: platform_allow: stm32h747i_disco_m7 extra_args: SHIELD=st_b_lcd40_dsi1_mb1166 From d4ba37739f9326ac0570400c84f474c49bce5dc9 Mon Sep 17 00:00:00 2001 From: Flavio Ceolin Date: Wed, 31 Jan 2024 08:32:45 -0800 Subject: [PATCH 3290/3723] drivers: modem/simcom: Unused variable Make coverity happy and mark a variable as unused. Fixes CID-248325 Fixes #58572 Signed-off-by: Flavio Ceolin --- drivers/modem/simcom-sim7080.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/modem/simcom-sim7080.c b/drivers/modem/simcom-sim7080.c index f0b31a1d1b6..266558469fc 100644 --- a/drivers/modem/simcom-sim7080.c +++ b/drivers/modem/simcom-sim7080.c @@ -750,7 +750,7 @@ static int offload_getaddrinfo(const char *node, const char *service, static void offload_freeaddrinfo(struct zsock_addrinfo *res) { /* No need to free static memory. */ - res = NULL; + ARG_UNUSED(res); } /* From e13d4a14df18a9e40b50cfbbde66dec38e6ac844 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Martin=20=C3=85berg?= Date: Fri, 5 Feb 2021 13:46:07 +0100 Subject: [PATCH 3291/3723] drivers/spi: Add support for GRLIB SPIMCTRL MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This adds support for the GRLIB SPIMCTRL SPI controller used in LEON and NOEL-V systems. SPIMCTRL can operate in two different modes: In the default mode it allows memory-mapped read access to the flash data. When set in the user mode, it can be used to generate SPI bus transactions. Signed-off-by: Martin Åberg --- drivers/spi/CMakeLists.txt | 1 + drivers/spi/Kconfig | 2 + drivers/spi/Kconfig.grlib_spimctrl | 8 + drivers/spi/spi_grlib_spimctrl.c | 244 +++++++++++++++++++++++++ dts/bindings/spi/gaisler,spimctrl.yaml | 15 ++ 5 files changed, 270 insertions(+) create mode 100644 drivers/spi/Kconfig.grlib_spimctrl create mode 100644 drivers/spi/spi_grlib_spimctrl.c create mode 100644 dts/bindings/spi/gaisler,spimctrl.yaml diff --git a/drivers/spi/CMakeLists.txt b/drivers/spi/CMakeLists.txt index de004d6aa5f..cd4699850f2 100644 --- a/drivers/spi/CMakeLists.txt +++ b/drivers/spi/CMakeLists.txt @@ -51,3 +51,4 @@ zephyr_library_sources_ifdef(CONFIG_USERSPACE spi_handlers.c) zephyr_library_sources_ifdef(CONFIG_SPI_INFINEON_CAT1 spi_ifx_cat1.c) zephyr_library_sources_ifdef(CONFIG_SPI_SEDI spi_sedi.c) zephyr_library_sources_ifdef(CONFIG_SPI_NPCX_SPIP spi_npcx_spip.c) +zephyr_library_sources_ifdef(CONFIG_SPI_GRLIB_SPIMCTRL spi_grlib_spimctrl.c) diff --git a/drivers/spi/Kconfig b/drivers/spi/Kconfig index f5d49328fa6..2cb7c83bd1c 100644 --- a/drivers/spi/Kconfig +++ b/drivers/spi/Kconfig @@ -141,4 +141,6 @@ source "drivers/spi/Kconfig.npcx" source "drivers/spi/Kconfig.mchp_mss" +source "drivers/spi/Kconfig.grlib_spimctrl" + endif # SPI diff --git a/drivers/spi/Kconfig.grlib_spimctrl b/drivers/spi/Kconfig.grlib_spimctrl new file mode 100644 index 00000000000..faea0ff1038 --- /dev/null +++ b/drivers/spi/Kconfig.grlib_spimctrl @@ -0,0 +1,8 @@ +# Copyright (c) 2023 Frontgrade Gaisler AB +# SPDX-License-Identifier: Apache-2.0 + +config SPI_GRLIB_SPIMCTRL + bool "GRLIB SPI memory controller" + depends on SOC_SPARC_LEON + help + Enable the GRLIB SPIMCTRL diff --git a/drivers/spi/spi_grlib_spimctrl.c b/drivers/spi/spi_grlib_spimctrl.c new file mode 100644 index 00000000000..788ffa888fd --- /dev/null +++ b/drivers/spi/spi_grlib_spimctrl.c @@ -0,0 +1,244 @@ +/* + * Copyright (c) 2023 Frontgrade Gaisler AB + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#define DT_DRV_COMPAT gaisler_spimctrl + +#include + +#include +LOG_MODULE_REGISTER(spi_spimctrl); +#include "spi_context.h" + + +struct spimctrl_regs { + uint32_t conf; + uint32_t ctrl; + uint32_t stat; + uint32_t rx; + uint32_t tx; +}; + +#define CONF_READCMD 0x0000007f +#define CTRL_RST 0x00000010 +#define CTRL_CSN 0x00000008 +#define CTRL_EAS 0x00000004 +#define CTRL_IEN 0x00000002 +#define CTRL_USRC 0x00000001 +#define STAT_INIT 0x00000004 +#define STAT_BUSY 0x00000002 +#define STAT_DONE 0x00000001 + +#define SPI_DATA(dev) ((struct data *) ((dev)->data)) + +struct cfg { + volatile struct spimctrl_regs *regs; + int interrupt; +}; + +struct data { + struct spi_context ctx; +}; + +static int spi_config(struct spi_context *ctx, const struct spi_config *config) +{ + if (config->slave != 0) { + LOG_ERR("More slaves than supported"); + return -ENOTSUP; + } + + if (SPI_WORD_SIZE_GET(config->operation) != 8) { + LOG_ERR("Word size must be 8"); + return -ENOTSUP; + } + + if (config->operation & SPI_CS_ACTIVE_HIGH) { + LOG_ERR("CS active high not supported"); + return -ENOTSUP; + } + + if (config->operation & SPI_LOCK_ON) { + LOG_ERR("Lock On not supported"); + return -ENOTSUP; + } + + if ((config->operation & SPI_LINES_MASK) != SPI_LINES_SINGLE) { + LOG_ERR("Only supports single mode"); + return -ENOTSUP; + } + + if (config->operation & SPI_TRANSFER_LSB) { + LOG_ERR("LSB first not supported"); + return -ENOTSUP; + } + + if (config->operation & (SPI_MODE_CPOL | SPI_MODE_CPHA)) { + LOG_ERR("Only supports CPOL=CPHA=0"); + return -ENOTSUP; + } + + if (config->operation & SPI_OP_MODE_SLAVE) { + LOG_ERR("Slave mode not supported"); + return -ENOTSUP; + } + + if (config->operation & SPI_MODE_LOOP) { + LOG_ERR("Loopback not supported"); + return -ENOTSUP; + } + + ctx->config = config; + + return 0; +} + +static int transceive(const struct device *dev, + const struct spi_config *config, + const struct spi_buf_set *tx_bufs, + const struct spi_buf_set *rx_bufs) +{ + const struct cfg *const cfg = dev->config; + volatile struct spimctrl_regs *const regs = cfg->regs; + struct spi_context *ctx = &SPI_DATA(dev)->ctx; + uint8_t txval; + int rc; + + spi_context_lock(ctx, false, NULL, NULL, config); + + rc = spi_config(ctx, config); + if (rc) { + LOG_ERR("%s: config", __func__); + spi_context_release(ctx, rc); + return rc; + } + + spi_context_buffers_setup(ctx, tx_bufs, rx_bufs, 1); + + regs->ctrl |= (CTRL_USRC | CTRL_IEN); + regs->ctrl &= ~CTRL_CSN; + + if (spi_context_tx_buf_on(ctx)) { + txval = *ctx->tx_buf; + spi_context_update_tx(ctx, 1, 1); + } else { + txval = 0; + } + /* This will eventually trig the interrupt */ + regs->tx = txval; + + rc = spi_context_wait_for_completion(ctx); + + regs->ctrl |= CTRL_CSN; + regs->ctrl &= ~CTRL_USRC; + spi_context_release(ctx, rc); + + return 0; +} + +#ifdef CONFIG_SPI_ASYNC +static int transceive_async(const struct device *dev, + const struct spi_config *config, + const struct spi_buf_set *tx_bufs, + const struct spi_buf_set *rx_bufs, + struct k_poll_signal *async) +{ + return -ENOTSUP; +} +#endif /* CONFIG_SPI_ASYNC */ + +static int release(const struct device *dev, const struct spi_config *config) +{ + spi_context_unlock_unconditionally(&SPI_DATA(dev)->ctx); + return 0; +} + +static void spim_isr(struct device *dev) +{ + const struct cfg *const cfg = dev->config; + volatile struct spimctrl_regs *const regs = cfg->regs; + struct spi_context *ctx = &SPI_DATA(dev)->ctx; + uint8_t rx_byte; + uint8_t val; + + if ((regs->stat & STAT_DONE) == 0) { + return; + } + + regs->stat = STAT_DONE; + + /* Always read register and maybe write mem. */ + rx_byte = regs->rx; + if (spi_context_rx_on(ctx)) { + *ctx->rx_buf = rx_byte; + spi_context_update_rx(ctx, 1, 1); + } + + if (spi_context_tx_buf_on(ctx) == false && spi_context_rx_buf_on(ctx) == false) { + regs->ctrl &= ~CTRL_IEN; + spi_context_complete(ctx, dev, 0); + return; + } + + val = 0; + if (spi_context_tx_buf_on(ctx)) { + val = *ctx->tx_buf; + spi_context_update_tx(ctx, 1, 1); + } + regs->tx = val; +} + +static int init(const struct device *dev) +{ + const struct cfg *const cfg = dev->config; + volatile struct spimctrl_regs *const regs = cfg->regs; + + regs->ctrl = CTRL_CSN; + while (regs->stat & STAT_BUSY) { + ; + } + regs->stat = STAT_DONE; + + irq_connect_dynamic( + cfg->interrupt, + 0, + (void (*)(const void *)) spim_isr, + dev, + 0 + ); + irq_enable(cfg->interrupt); + + spi_context_unlock_unconditionally(&SPI_DATA(dev)->ctx); + + return 0; +} + +static struct spi_driver_api api = { + .transceive = transceive, +#ifdef CONFIG_SPI_ASYNC + .transceive_async = transceive_async, +#endif /* CONFIG_SPI_ASYNC */ + .release = release, +}; + +#define SPI_INIT(n) \ + static const struct cfg cfg_##n = { \ + .regs = (struct spimctrl_regs *) \ + DT_INST_REG_ADDR(n), \ + .interrupt = DT_INST_IRQN(n), \ + }; \ + static struct data data_##n = { \ + SPI_CONTEXT_INIT_LOCK(data_##n, ctx), \ + SPI_CONTEXT_INIT_SYNC(data_##n, ctx), \ + }; \ + DEVICE_DT_INST_DEFINE(n, \ + init, \ + NULL, \ + &data_##n, \ + &cfg_##n, \ + POST_KERNEL, \ + CONFIG_SPI_INIT_PRIORITY, \ + &api); + +DT_INST_FOREACH_STATUS_OKAY(SPI_INIT) diff --git a/dts/bindings/spi/gaisler,spimctrl.yaml b/dts/bindings/spi/gaisler,spimctrl.yaml new file mode 100644 index 00000000000..51dfb4960c1 --- /dev/null +++ b/dts/bindings/spi/gaisler,spimctrl.yaml @@ -0,0 +1,15 @@ +# Copyright (c) 2023 Frontgrade Gaisler AB +# SPDX-License-Identifier: Apache-2.0 + +description: GRLIB SPIMCTRL + +compatible: "gaisler,spimctrl" + +include: spi-controller.yaml + +properties: + reg: + required: true + + interrupts: + required: true From f033f3172831fb19abe2f9b59ef1567629e8d2b5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Martin=20=C3=85berg?= Date: Wed, 3 Mar 2021 18:54:27 +0100 Subject: [PATCH 3292/3723] soc/gr716a: Enable SPIMCTRL support on LEON GR716A MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit GR716A has two SPIMCTRL SPI controllers. This adds the SPIMCTRL description to the DTS and makes the SPI option available in the kernel configuration. Signed-off-by: Martin Åberg --- boards/sparc/gr716a_mini/gr716a_mini.dts | 16 ++++++++++++++++ boards/sparc/gr716a_mini/gr716a_mini.yaml | 1 + dts/sparc/gaisler/gr716a.dtsi | 18 ++++++++++++++++++ soc/sparc/gr716a/Kconfig.defconfig | 13 +++++++++++++ 4 files changed, 48 insertions(+) diff --git a/boards/sparc/gr716a_mini/gr716a_mini.dts b/boards/sparc/gr716a_mini/gr716a_mini.dts index 551caba6b8a..745caa64f67 100644 --- a/boards/sparc/gr716a_mini/gr716a_mini.dts +++ b/boards/sparc/gr716a_mini/gr716a_mini.dts @@ -6,11 +6,15 @@ /dts-v1/; +#include #include / { model = "GR716-MINI Development Board"; compatible = "gaisler,gr716a-mini"; + aliases { + spi-flash0 = &flash0; + }; chosen { zephyr,console = &uart0; zephyr,shell-uart = &uart0; @@ -21,3 +25,15 @@ &uart0 { status = "okay"; }; + +&spim0 { + status = "okay"; + /* 256 Mbit SPI flash MX25L25635FZ2I-10G in 8 pin WSON package */ + flash0: flash@0 { + compatible = "jedec,spi-nor"; + reg = <0>; + spi-max-frequency = <50000000>; + size = ; + jedec-id = [c2 20 19]; + }; +}; diff --git a/boards/sparc/gr716a_mini/gr716a_mini.yaml b/boards/sparc/gr716a_mini/gr716a_mini.yaml index 4107097aab5..8b673cebfa6 100644 --- a/boards/sparc/gr716a_mini/gr716a_mini.yaml +++ b/boards/sparc/gr716a_mini/gr716a_mini.yaml @@ -9,6 +9,7 @@ toolchain: - xtools supported: - netif + - spi testing: ignore_tags: - net diff --git a/dts/sparc/gaisler/gr716a.dtsi b/dts/sparc/gaisler/gr716a.dtsi index 78b9c806bbe..a3c79e1eaa9 100644 --- a/dts/sparc/gaisler/gr716a.dtsi +++ b/dts/sparc/gaisler/gr716a.dtsi @@ -89,5 +89,23 @@ reg = <0x80305000 0x100>; status = "disabled"; }; + + spim0: spi@fff00100 { + compatible = "gaisler,spimctrl"; + reg = <0xfff00100 0x100>; + interrupts = <2 0>; + #address-cells = <1>; + #size-cells = <0>; + status = "disabled"; + }; + + spim1: spi@fff00200 { + compatible = "gaisler,spimctrl"; + reg = <0xfff00200 0x100>; + interrupts = <2 0>; + #address-cells = <1>; + #size-cells = <0>; + status = "disabled"; + }; }; }; diff --git a/soc/sparc/gr716a/Kconfig.defconfig b/soc/sparc/gr716a/Kconfig.defconfig index 6feb4ff3d6a..ef9bf0ca778 100644 --- a/soc/sparc/gr716a/Kconfig.defconfig +++ b/soc/sparc/gr716a/Kconfig.defconfig @@ -13,4 +13,17 @@ config SYS_CLOCK_HW_CYCLES_PER_SEC int default 50000000 +if FLASH + +config SPI + default y + +config SPI_NOR + default y + +config SPI_GRLIB_SPIMCTRL + default y + +endif + endif From 516fc76f842c72fa898968e8d43bdbfb74d56cd5 Mon Sep 17 00:00:00 2001 From: Mateusz Holenko Date: Tue, 30 Jan 2024 18:47:31 +0100 Subject: [PATCH 3293/3723] drivers: eth_stm32_hal: Fix compilation warnings MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Promote clk_ratio_adj to double for internal calculations related to ratio to avoid compilation warnings related to implicit conversion from float to double. Signed-off-by: Mateusz Hołenko --- drivers/ethernet/eth_stm32_hal.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/drivers/ethernet/eth_stm32_hal.c b/drivers/ethernet/eth_stm32_hal.c index 1808b59f23b..b9d4c19186d 100644 --- a/drivers/ethernet/eth_stm32_hal.c +++ b/drivers/ethernet/eth_stm32_hal.c @@ -1844,13 +1844,13 @@ static int ptp_clock_stm32_rate_adjust(const struct device *dev, double ratio) uint32_t addend_val; /* No change needed */ - if (ratio == 1.0f) { + if (ratio == 1.0L) { return 0; } key = irq_lock(); - ratio *= eth_dev_data->clk_ratio_adj; + ratio *= (double)eth_dev_data->clk_ratio_adj; /* Limit possible ratio */ if (ratio * 100 < CONFIG_ETH_STM32_HAL_PTP_CLOCK_ADJ_MIN_PCT || @@ -1863,7 +1863,7 @@ static int ptp_clock_stm32_rate_adjust(const struct device *dev, double ratio) eth_dev_data->clk_ratio_adj = ratio; /* Update addend register */ - addend_val = UINT32_MAX * eth_dev_data->clk_ratio * ratio; + addend_val = UINT32_MAX * (double)eth_dev_data->clk_ratio * ratio; #if defined(CONFIG_SOC_SERIES_STM32H7X) || defined(CONFIG_SOC_SERIES_STM32H5X) heth->Instance->MACTSAR = addend_val; From 927c7ba1934225a081e64c3c9aa2636fc2a4c2bd Mon Sep 17 00:00:00 2001 From: Henrik Brix Andersen Date: Wed, 31 Jan 2024 16:05:58 +0100 Subject: [PATCH 3294/3723] drivers: can: fake: use delegate for reporting core clock rate Use a delegate for reporting the core clock rate of the fake CAN driver. This allows overriding the delegate at run-time and inspecting its call count. Signed-off-by: Henrik Brix Andersen --- drivers/can/can_fake.c | 24 +++++++++++++++--------- include/zephyr/drivers/can/can_fake.h | 2 ++ 2 files changed, 17 insertions(+), 9 deletions(-) diff --git a/drivers/can/can_fake.c b/drivers/can/can_fake.c index f2845bbee9b..097a614a35e 100644 --- a/drivers/can/can_fake.c +++ b/drivers/can/can_fake.c @@ -54,6 +54,17 @@ DEFINE_FAKE_VOID_FUNC(fake_can_set_state_change_callback, const struct device *, DEFINE_FAKE_VALUE_FUNC(int, fake_can_get_max_filters, const struct device *, bool); +DEFINE_FAKE_VALUE_FUNC(int, fake_can_get_core_clock, const struct device *, uint32_t *); + +static int fake_can_get_core_clock_delegate(const struct device *dev, uint32_t *rate) +{ + ARG_UNUSED(dev); + + *rate = 16000000; + + return 0; +} + #ifdef CONFIG_ZTEST static void fake_can_reset_rule_before(const struct ztest_unit_test *test, void *fixture) { @@ -73,20 +84,15 @@ static void fake_can_reset_rule_before(const struct ztest_unit_test *test, void RESET_FAKE(fake_can_recover); RESET_FAKE(fake_can_set_state_change_callback); RESET_FAKE(fake_can_get_max_filters); + RESET_FAKE(fake_can_get_core_clock); + + /* Re-install default delegate for reporting the core clock */ + fake_can_get_core_clock_fake.custom_fake = fake_can_get_core_clock_delegate; } ZTEST_RULE(fake_can_reset_rule, fake_can_reset_rule_before, NULL); #endif /* CONFIG_ZTEST */ -static int fake_can_get_core_clock(const struct device *dev, uint32_t *rate) -{ - ARG_UNUSED(dev); - - *rate = 16000000; - - return 0; -} - static const struct can_driver_api fake_can_driver_api = { .start = fake_can_start, .stop = fake_can_stop, diff --git a/include/zephyr/drivers/can/can_fake.h b/include/zephyr/drivers/can/can_fake.h index ac2e000d6d1..1f66a9852fc 100644 --- a/include/zephyr/drivers/can/can_fake.h +++ b/include/zephyr/drivers/can/can_fake.h @@ -45,6 +45,8 @@ DECLARE_FAKE_VOID_FUNC(fake_can_set_state_change_callback, const struct device * DECLARE_FAKE_VALUE_FUNC(int, fake_can_get_max_filters, const struct device *, bool); +DECLARE_FAKE_VALUE_FUNC(int, fake_can_get_core_clock, const struct device *, uint32_t *); + #ifdef __cplusplus } #endif From 1e6083383692267d31d5f5c733b622e46976057f Mon Sep 17 00:00:00 2001 From: Henrik Brix Andersen Date: Wed, 31 Jan 2024 16:07:25 +0100 Subject: [PATCH 3295/3723] tests: drivers: can: shell: verify can_get_core_clock() call count Verify the call count of can_get_core_clock() after executing "can show" shell subcommand. Signed-off-by: Henrik Brix Andersen --- tests/drivers/can/shell/src/main.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/tests/drivers/can/shell/src/main.c b/tests/drivers/can/shell/src/main.c index 35681839bd2..bcd54bc36d7 100644 --- a/tests/drivers/can/shell/src/main.c +++ b/tests/drivers/can/shell/src/main.c @@ -120,6 +120,8 @@ ZTEST(can_shell, test_can_show) zassert_equal(fake_can_get_capabilities_fake.call_count, 1, "get_capabilities function not called"); zassert_equal(fake_can_get_state_fake.call_count, 1, "get_state function not called"); + zassert_equal(fake_can_get_core_clock_fake.call_count, 1, + "get_core_clock function not called"); } ZTEST(can_shell, test_can_bitrate_missing_value) From 5df4e513f7dbe6298a63190cc19a493e4b89219e Mon Sep 17 00:00:00 2001 From: Daniel DeGrasse Date: Wed, 31 Jan 2024 10:18:41 -0600 Subject: [PATCH 3296/3723] drivers: mipi_dbi: mipi_dbi_spi: cleanup pin checks Add cleanups to pin presence checks within the mipi_dbi SPI driver. The cleanups now verify that GPIO and RESET pin devices are ready, if they are present for the device instance. Signed-off-by: Daniel DeGrasse --- drivers/mipi_dbi/mipi_dbi_spi.c | 17 ++++++++++++++--- 1 file changed, 14 insertions(+), 3 deletions(-) diff --git a/drivers/mipi_dbi/mipi_dbi_spi.c b/drivers/mipi_dbi/mipi_dbi_spi.c index 6bc05dc2baf..bf1c1388e19 100644 --- a/drivers/mipi_dbi/mipi_dbi_spi.c +++ b/drivers/mipi_dbi/mipi_dbi_spi.c @@ -237,12 +237,17 @@ static int mipi_dbi_spi_command_read(const struct device *dev, #endif /* MIPI_DBI_SPI_READ_REQUIRED */ +static inline bool mipi_dbi_has_pin(const struct gpio_dt_spec *spec) +{ + return spec->port != NULL; +} + static int mipi_dbi_spi_reset(const struct device *dev, uint32_t delay) { const struct mipi_dbi_spi_config *config = dev->config; int ret; - if (config->reset.port == NULL) { + if (!mipi_dbi_has_pin(&config->reset)) { return -ENOTSUP; } @@ -264,7 +269,10 @@ static int mipi_dbi_spi_init(const struct device *dev) return -ENODEV; } - if (config->cmd_data.port) { + if (mipi_dbi_has_pin(&config->cmd_data)) { + if (!gpio_is_ready_dt(&config->cmd_data)) { + return -ENODEV; + } ret = gpio_pin_configure_dt(&config->cmd_data, GPIO_OUTPUT); if (ret < 0) { LOG_ERR("Could not configure command/data GPIO (%d)", ret); @@ -272,7 +280,10 @@ static int mipi_dbi_spi_init(const struct device *dev) } } - if (config->reset.port) { + if (mipi_dbi_has_pin(&config->reset)) { + if (!gpio_is_ready_dt(&config->reset)) { + return -ENODEV; + } ret = gpio_pin_configure_dt(&config->reset, GPIO_OUTPUT_INACTIVE); if (ret < 0) { LOG_ERR("Could not configure reset GPIO (%d)", ret); From 9887ebf4716077a817b9e0091d862c7eedae4a6c Mon Sep 17 00:00:00 2001 From: Andries Kruithof Date: Tue, 19 Dec 2023 14:29:08 +0100 Subject: [PATCH 3297/3723] Bluetooth: audio: bap: long write Increase the buffer size to allow for long writes Signed-off-by: Andries Kruithof --- subsys/bluetooth/audio/bap_broadcast_assistant.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/subsys/bluetooth/audio/bap_broadcast_assistant.c b/subsys/bluetooth/audio/bap_broadcast_assistant.c index 07f83bd7c13..8f9a7732841 100644 --- a/subsys/bluetooth/audio/bap_broadcast_assistant.c +++ b/subsys/bluetooth/audio/bap_broadcast_assistant.c @@ -16,6 +16,7 @@ #include #include #include +#include #include #include #include @@ -64,7 +65,8 @@ static struct bt_bap_broadcast_assistant_cb *broadcast_assistant_cbs; static struct bap_broadcast_assistant_instance broadcast_assistant; static struct bt_uuid_16 uuid = BT_UUID_INIT_16(0); -NET_BUF_SIMPLE_DEFINE_STATIC(cp_buf, CONFIG_BT_L2CAP_TX_MTU); +#define CP_BUF_SIZE MAX(CONFIG_BT_L2CAP_TX_MTU, BT_ATT_MAX_ATTRIBUTE_LEN) +NET_BUF_SIMPLE_DEFINE_STATIC(cp_buf, CP_BUF_SIZE); static int16_t lookup_index_by_handle(uint16_t handle) { @@ -973,6 +975,7 @@ int bt_bap_broadcast_assistant_read_recv_state(struct bt_conn *conn, broadcast_assistant.read_params.single.handle = broadcast_assistant.recv_state_handles[idx]; + /* we do not need a semaphore for the read_params long read I think */ err = bt_gatt_read(conn, &broadcast_assistant.read_params); if (err != 0) { (void)memset(&broadcast_assistant.read_params, 0, From 90a5d02710759a2fbee9535019fabe0c4c6dcfad Mon Sep 17 00:00:00 2001 From: Andries Kruithof Date: Fri, 22 Dec 2023 08:42:04 +0100 Subject: [PATCH 3298/3723] Bluetooth: audio: bap: add support for long read Make sure that buffers are large enough and add semaphores so that we can do long reads Signed-off-by: Andries Kruithof --- subsys/bluetooth/audio/Kconfig.bap | 9 +++ subsys/bluetooth/audio/bap_scan_delegator.c | 71 ++++++++++++++++++--- 2 files changed, 72 insertions(+), 8 deletions(-) diff --git a/subsys/bluetooth/audio/Kconfig.bap b/subsys/bluetooth/audio/Kconfig.bap index 6921cf2c8c0..e34428eb85b 100644 --- a/subsys/bluetooth/audio/Kconfig.bap +++ b/subsys/bluetooth/audio/Kconfig.bap @@ -235,6 +235,15 @@ config BT_BAP_SCAN_DELEGATOR_MAX_SUBGROUPS help The maximum number of BIS subgroups supported. +config BT_BAP_SCAN_DELEGATOR_BUF_TIMEOUT + int "Milliseconds of timeout when handle concurrent access to the long read ASE buffer" + range 0 1000 + default 50 + help + The number of milliseconds that the scan delegator implementation will maximum wait + before rejecting a ASE read or dropping a notification if the scan delegator state is + being accessed by another thread. + endif # BT_BAP_SCAN_DELEGATOR config BT_BAP_BROADCAST_ASSISTANT diff --git a/subsys/bluetooth/audio/bap_scan_delegator.c b/subsys/bluetooth/audio/bap_scan_delegator.c index 03ebe87275f..96689c09b43 100644 --- a/subsys/bluetooth/audio/bap_scan_delegator.c +++ b/subsys/bluetooth/audio/bap_scan_delegator.c @@ -17,6 +17,7 @@ #include #include #include +#include #include #include @@ -32,6 +33,8 @@ LOG_MODULE_REGISTER(bt_bap_scan_delegator, CONFIG_BT_BAP_SCAN_DELEGATOR_LOG_LEVE #define PAST_TIMEOUT K_SECONDS(10) +#define SCAN_DELEGATOR_BUF_SEM_TIMEOUT K_MSEC(CONFIG_BT_BAP_SCAN_DELEGATOR_BUF_TIMEOUT) +static K_SEM_DEFINE(read_buf_sem, 1, 1); NET_BUF_SIMPLE_DEFINE_STATIC(read_buf, BT_ATT_MAX_ATTRIBUTE_LEN); enum bass_recv_state_internal_flag { @@ -137,11 +140,29 @@ static void bt_debug_dump_recv_state(const struct bass_recv_state_internal *recv } } -static void bass_notify_receive_state(const struct bass_recv_state_internal *internal_state) +static void bass_notify_receive_state(struct bt_conn *conn, + const struct bass_recv_state_internal *internal_state) { - int err = bt_gatt_notify_uuid(NULL, BT_UUID_BASS_RECV_STATE, + const uint8_t att_ntf_header_size = 3; /* opcode (1) + handle (2) */ + uint16_t max_ntf_size; + uint16_t ntf_size; + int err; + + if (conn != NULL) { + max_ntf_size = bt_gatt_get_mtu(conn) - att_ntf_header_size; + } else { + max_ntf_size = MIN(BT_L2CAP_RX_MTU, BT_L2CAP_TX_MTU) - att_ntf_header_size; + } + + ntf_size = MIN(max_ntf_size, read_buf.len); + if (ntf_size < read_buf.len) { + LOG_DBG("Sending truncated notification (%u/%u)", ntf_size, read_buf.len); + } + + LOG_DBG("Sending bytes %d", ntf_size); + err = bt_gatt_notify_uuid(NULL, BT_UUID_BASS_RECV_STATE, internal_state->attr, read_buf.data, - read_buf.len); + ntf_size); if (err != 0 && err != -ENOTCONN) { LOG_DBG("Could not notify receive state: %d", err); @@ -158,6 +179,7 @@ static void net_buf_put_recv_state(const struct bass_recv_state_internal *recv_s if (!recv_state->active) { /* Notify empty */ + return; } @@ -187,21 +209,31 @@ static void net_buf_put_recv_state(const struct bass_recv_state_internal *recv_s static void receive_state_updated(struct bt_conn *conn, const struct bass_recv_state_internal *internal_state) { + int err; + /* If something is holding the NOTIFY_PEND flag we should not notify now */ if (atomic_test_bit(internal_state->flags, BASS_RECV_STATE_INTERNAL_FLAG_NOTIFY_PEND)) { return; } + err = k_sem_take(&read_buf_sem, SCAN_DELEGATOR_BUF_SEM_TIMEOUT); + if (err != 0) { + LOG_DBG("Failed to take read_buf_sem: %d", err); + + return; + } + bt_debug_dump_recv_state(internal_state); net_buf_put_recv_state(internal_state); - bass_notify_receive_state(internal_state); - + bass_notify_receive_state(conn, internal_state); if (scan_delegator_cbs != NULL && scan_delegator_cbs->recv_state_updated != NULL) { scan_delegator_cbs->recv_state_updated(conn, &internal_state->state); } + + k_sem_give(&read_buf_sem); } static void bis_sync_request_updated(struct bt_conn *conn, @@ -254,11 +286,21 @@ static void scan_delegator_security_changed(struct bt_conn *conn, continue; } + err = k_sem_take(&read_buf_sem, SCAN_DELEGATOR_BUF_SEM_TIMEOUT); + if (err != 0) { + LOG_DBG("Failed to take read_buf_sem: %d", err); + + return; + } + net_buf_put_recv_state(internal_state); gatt_err = bt_gatt_notify_uuid(conn, BT_UUID_BASS_RECV_STATE, internal_state->attr, read_buf.data, read_buf.len); + + k_sem_give(&read_buf_sem); + if (gatt_err != 0) { LOG_WRN("Could not notify receive state[%d] to reconnecting assistant: %d", i, gatt_err); @@ -1025,14 +1067,27 @@ static ssize_t read_recv_state(struct bt_conn *conn, struct bt_bap_scan_delegator_recv_state *state = &recv_state->state; if (recv_state->active) { + ssize_t ret_val; + int err; + LOG_DBG("Index %u: Source ID 0x%02x", idx, state->src_id); - bt_debug_dump_recv_state(recv_state); + err = k_sem_take(&read_buf_sem, SCAN_DELEGATOR_BUF_SEM_TIMEOUT); + if (err != 0) { + LOG_DBG("Failed to take read_buf_sem: %d", err); + + return err; + } + bt_debug_dump_recv_state(recv_state); net_buf_put_recv_state(recv_state); - return bt_gatt_attr_read(conn, attr, buf, len, offset, - read_buf.data, read_buf.len); + ret_val = bt_gatt_attr_read(conn, attr, buf, len, offset, + read_buf.data, read_buf.len); + + k_sem_give(&read_buf_sem); + + return ret_val; } else { LOG_DBG("Index %u: Not active", idx); From c5dcc1a4ce9f516936af790131d16d0224bac5c3 Mon Sep 17 00:00:00 2001 From: Andries Kruithof Date: Thu, 18 Jan 2024 15:13:08 +0100 Subject: [PATCH 3299/3723] Bluetooth: audio: bap: add support for long notifications Add support for sending long notifications, coming from a long read, back to the application Signed-off-by: Andries Kruithof --- .../bluetooth/audio/bap_broadcast_assistant.c | 289 +++++++++++++++--- 1 file changed, 243 insertions(+), 46 deletions(-) diff --git a/subsys/bluetooth/audio/bap_broadcast_assistant.c b/subsys/bluetooth/audio/bap_broadcast_assistant.c index 8f9a7732841..c96462db8ab 100644 --- a/subsys/bluetooth/audio/bap_broadcast_assistant.c +++ b/subsys/bluetooth/audio/bap_broadcast_assistant.c @@ -17,6 +17,7 @@ #include #include #include +#include #include #include #include @@ -58,6 +59,10 @@ struct bap_broadcast_assistant_instance { struct bt_gatt_read_params read_params; struct bt_gatt_write_params write_params; struct bt_gatt_discover_params disc_params; + + struct k_work_delayable bap_read_work; + struct bt_conn *conn; + uint16_t long_read_handle; }; static struct bt_bap_broadcast_assistant_cb *broadcast_assistant_cbs; @@ -65,8 +70,8 @@ static struct bt_bap_broadcast_assistant_cb *broadcast_assistant_cbs; static struct bap_broadcast_assistant_instance broadcast_assistant; static struct bt_uuid_16 uuid = BT_UUID_INIT_16(0); -#define CP_BUF_SIZE MAX(CONFIG_BT_L2CAP_TX_MTU, BT_ATT_MAX_ATTRIBUTE_LEN) -NET_BUF_SIMPLE_DEFINE_STATIC(cp_buf, CP_BUF_SIZE); +#define ATT_BUF_SIZE BT_ATT_MAX_ATTRIBUTE_LEN +NET_BUF_SIMPLE_DEFINE_STATIC(att_buf, ATT_BUF_SIZE); static int16_t lookup_index_by_handle(uint16_t handle) { @@ -186,6 +191,144 @@ static int parse_recv_state(const void *data, uint16_t length, return 0; } +static void bap_long_op_reset(void) +{ + broadcast_assistant.busy = false; + broadcast_assistant.long_read_handle = 0; + net_buf_simple_reset(&att_buf); +} + +static uint8_t parse_and_send_recv_state(struct bt_conn *conn, uint16_t handle, + const void *data, uint16_t length, + struct bt_bap_scan_delegator_recv_state *recv_state) +{ + int err; + int16_t index; + + err = parse_recv_state(data, length, recv_state); + if (err != 0) { + LOG_WRN("Invalid receive state received"); + + return BT_GATT_ITER_STOP; + } + + index = lookup_index_by_handle(handle); + if (index < 0) { + LOG_DBG("Invalid index"); + + return BT_GATT_ITER_STOP; + } + + broadcast_assistant.src_ids[index] = recv_state->src_id; + broadcast_assistant.past_avail[index] = past_available(conn, + &recv_state->addr, + recv_state->adv_sid); + + if (broadcast_assistant_cbs != NULL && + broadcast_assistant_cbs->recv_state != NULL) { + broadcast_assistant_cbs->recv_state(conn, 0, recv_state); + } + + return BT_GATT_ITER_CONTINUE; +} + +static uint8_t broadcast_assistant_bap_ntf_read_func(struct bt_conn *conn, uint8_t err, + struct bt_gatt_read_params *read, + const void *data, uint16_t length) +{ + struct bt_bap_scan_delegator_recv_state recv_state; + uint16_t handle = read->single.handle; + uint16_t data_length; + + LOG_DBG("conn %p err 0x%02x len %u", conn, err, length); + + if (err) { + LOG_DBG("Failed to read: %u", err); + memset(read, 0, sizeof(*read)); + bap_long_op_reset(); + + return BT_GATT_ITER_STOP; + } + + LOG_DBG("handle 0x%04x", handle); + + if (data != NULL) { + if (net_buf_simple_tailroom(&att_buf) < length) { + LOG_DBG("Buffer full, invalid server response of size %u", + length + att_buf.len); + memset(read, 0, sizeof(*read)); + bap_long_op_reset(); + + return BT_GATT_ITER_STOP; + } + + /* store data*/ + net_buf_simple_add_mem(&att_buf, data, length); + + return BT_GATT_ITER_CONTINUE; + } + + /* we reset the buffer so that it is ready for new data */ + memset(read, 0, sizeof(*read)); + data_length = att_buf.len; + bap_long_op_reset(); + + /* do the parse and callback to send notify to application*/ + parse_and_send_recv_state(conn, handle, + att_buf.data, data_length, &recv_state); + + return BT_GATT_ITER_STOP; +} + +static void long_bap_read(struct bt_conn *conn, uint16_t handle) +{ + int err; + + LOG_DBG("conn %p busy %u", conn, broadcast_assistant.busy); + + if (broadcast_assistant.busy) { + /* If the client is busy reading or writing something else, reschedule the + * long read. + */ + struct bt_conn_info conn_info; + + err = bt_conn_get_info(conn, &conn_info); + if (err != 0) { + LOG_DBG("Failed to get conn info, use default interval"); + + conn_info.le.interval = BT_GAP_INIT_CONN_INT_MIN; + } + + /* Wait a connection interval to retry */ + err = k_work_reschedule(&broadcast_assistant.bap_read_work, + K_USEC(BT_CONN_INTERVAL_TO_US(conn_info.le.interval))); + if (err < 0) { + LOG_DBG("Failed to reschedule read work: %d", err); + bap_long_op_reset(); + } + + return; + } + + broadcast_assistant.read_params.func = broadcast_assistant_bap_ntf_read_func; + broadcast_assistant.read_params.handle_count = 1U; + broadcast_assistant.read_params.single.handle = handle; + broadcast_assistant.read_params.single.offset = att_buf.len; + + err = bt_gatt_read(conn, &broadcast_assistant.read_params); + if (err != 0) { + LOG_DBG("Failed to read: %d", err); + bap_long_op_reset(); + } else { + broadcast_assistant.busy = true; + } +} + +static void delayed_bap_read_handler(struct k_work *work) +{ + long_bap_read(broadcast_assistant.conn, broadcast_assistant.long_read_handle); +} + /** @brief Handles notifications and indications from the server */ static uint8_t notify_handler(struct bt_conn *conn, struct bt_gatt_subscribe_params *params, @@ -193,7 +336,6 @@ static uint8_t notify_handler(struct bt_conn *conn, { uint16_t handle = params->value_handle; struct bt_bap_scan_delegator_recv_state recv_state; - int err; int16_t index; if (data == NULL) { @@ -208,30 +350,37 @@ static uint8_t notify_handler(struct bt_conn *conn, index = lookup_index_by_handle(handle); if (index < 0) { LOG_DBG("Invalid index"); + return BT_GATT_ITER_STOP; } if (length != 0) { - err = parse_recv_state(data, length, &recv_state); + const uint8_t att_ntf_header_size = 3; /* opcode (1) + handle (2) */ + uint16_t max_ntf_size; - if (err != 0) { - /* TODO: Likely due to the length. - * Start a read autonomously - */ - LOG_WRN("Invalid receive state received"); + /* Cancel any pending long reads containing now obsolete information */ + (void)k_work_cancel_delayable(&broadcast_assistant.bap_read_work); - return BT_GATT_ITER_STOP; + if (conn != NULL) { + max_ntf_size = bt_gatt_get_mtu(conn) - att_ntf_header_size; + } else { + max_ntf_size = MIN(BT_L2CAP_RX_MTU, BT_L2CAP_TX_MTU) - att_ntf_header_size; } - broadcast_assistant.src_ids[index] = recv_state.src_id; - broadcast_assistant.past_avail[index] = past_available(conn, - &recv_state.addr, - recv_state.adv_sid); + if (length == max_ntf_size) { + /* TODO: if we are busy we should not overwrite the long_read_handle, + * we'll have to keep track of the handle and parameters separately + * for each characteristic, similar to the bt_bap_unicast_client_ep + * struct for the unicast client + */ + broadcast_assistant.long_read_handle = handle; - if (broadcast_assistant_cbs != NULL && - broadcast_assistant_cbs->recv_state != NULL) { - broadcast_assistant_cbs->recv_state(conn, 0, & - recv_state); + if (!broadcast_assistant.busy) { + net_buf_simple_add_mem(&att_buf, data, length); + } + long_bap_read(conn, handle); + } else { + return parse_and_send_recv_state(conn, handle, data, length, &recv_state); } } else if (broadcast_assistant_cbs != NULL && broadcast_assistant_cbs->recv_state_removed != NULL) { @@ -335,6 +484,15 @@ static uint8_t read_recv_state_cb(struct bt_conn *conn, uint8_t err, return BT_GATT_ITER_STOP; } +static void discover_init(void) +{ + (void)memset(&broadcast_assistant, 0, sizeof(broadcast_assistant)); + + k_work_init_delayable(&broadcast_assistant.bap_read_work, delayed_bap_read_handler); + + net_buf_simple_reset(&att_buf); +} + /** * @brief This will discover all characteristics on the server, retrieving the * handles of the writeable characteristics and subscribing to all notify and @@ -469,7 +627,7 @@ static uint8_t service_discover_func(struct bt_conn *conn, static void bap_broadcast_assistant_write_cp_cb(struct bt_conn *conn, uint8_t err, struct bt_gatt_write_params *params) { - uint8_t opcode = net_buf_simple_pull_u8(&cp_buf); + uint8_t opcode = net_buf_simple_pull_u8(&att_buf); broadcast_assistant.busy = false; @@ -477,6 +635,9 @@ static void bap_broadcast_assistant_write_cp_cb(struct bt_conn *conn, uint8_t er return; } + /* we reset the buffer, so that we are ready for new notifications and writes */ + net_buf_simple_reset(&att_buf); + switch (opcode) { case BT_BAP_BASS_OP_SCAN_STOP: if (broadcast_assistant_cbs->scan_stop != NULL) { @@ -596,6 +757,30 @@ static struct bt_le_scan_cb scan_cb = { /****************************** PUBLIC API ******************************/ +static int broadcast_assistant_reset(struct bap_broadcast_assistant_instance *inst) +{ + broadcast_assistant.long_read_handle = 0; + (void)k_work_cancel_delayable(&broadcast_assistant.bap_read_work); + + if (inst->conn != NULL) { + struct bt_conn *conn = inst->conn; + + bt_conn_unref(conn); + inst->conn = NULL; + } + + return 0; +} + +static void disconnected_cb(struct bt_conn *conn, uint8_t reason) +{ + (void)broadcast_assistant_reset(&broadcast_assistant); +} + +BT_CONN_CB_DEFINE(conn_callbacks) = { + .disconnected = disconnected_cb, +}; + int bt_bap_broadcast_assistant_discover(struct bt_conn *conn) { int err; @@ -606,21 +791,34 @@ int bt_bap_broadcast_assistant_discover(struct bt_conn *conn) return -EINVAL; } + if (broadcast_assistant.busy) { + LOG_DBG("Instance is busy"); + return -EBUSY; + } + + err = broadcast_assistant_reset(&broadcast_assistant); + if (err != 0) { + LOG_DBG("Failed to reset broadcast assistant: %d", err); + + return err; + } + /* Discover BASS on peer, setup handles and notify */ - (void)memset(&broadcast_assistant, 0, sizeof(broadcast_assistant)); + discover_init(); + (void)memcpy(&uuid, BT_UUID_BASS, sizeof(uuid)); broadcast_assistant.disc_params.func = service_discover_func; broadcast_assistant.disc_params.uuid = &uuid.uuid; broadcast_assistant.disc_params.type = BT_GATT_DISCOVER_PRIMARY; broadcast_assistant.disc_params.start_handle = BT_ATT_FIRST_ATTRIBUTE_HANDLE; broadcast_assistant.disc_params.end_handle = BT_ATT_LAST_ATTRIBUTE_HANDLE; - err = bt_gatt_discover(conn, &broadcast_assistant.disc_params); if (err != 0) { return err; } broadcast_assistant.discovering = true; + broadcast_assistant.conn = bt_conn_ref(conn); return 0; } @@ -668,12 +866,12 @@ int bt_bap_broadcast_assistant_scan_start(struct bt_conn *conn, bool start_scan) } /* Reset buffer before using */ - net_buf_simple_reset(&cp_buf); - cp = net_buf_simple_add(&cp_buf, sizeof(*cp)); + net_buf_simple_reset(&att_buf); + cp = net_buf_simple_add(&att_buf, sizeof(*cp)); cp->opcode = BT_BAP_BASS_OP_SCAN_START; - return bt_bap_broadcast_assistant_common_cp(conn, &cp_buf); + return bt_bap_broadcast_assistant_common_cp(conn, &att_buf); } int bt_bap_broadcast_assistant_scan_stop(struct bt_conn *conn) @@ -707,12 +905,12 @@ int bt_bap_broadcast_assistant_scan_stop(struct bt_conn *conn) } /* Reset buffer before using */ - net_buf_simple_reset(&cp_buf); - cp = net_buf_simple_add(&cp_buf, sizeof(*cp)); + net_buf_simple_reset(&att_buf); + cp = net_buf_simple_add(&att_buf, sizeof(*cp)); cp->opcode = BT_BAP_BASS_OP_SCAN_STOP; - return bt_bap_broadcast_assistant_common_cp(conn, &cp_buf); + return bt_bap_broadcast_assistant_common_cp(conn, &att_buf); } int bt_bap_broadcast_assistant_add_src(struct bt_conn *conn, @@ -735,8 +933,8 @@ int bt_bap_broadcast_assistant_add_src(struct bt_conn *conn, } /* Reset buffer before using */ - net_buf_simple_reset(&cp_buf); - cp = net_buf_simple_add(&cp_buf, sizeof(*cp)); + net_buf_simple_reset(&att_buf); + cp = net_buf_simple_add(&att_buf, sizeof(*cp)); cp->opcode = BT_BAP_BASS_OP_ADD_SRC; cp->adv_sid = param->adv_sid; @@ -762,13 +960,13 @@ int bt_bap_broadcast_assistant_add_src(struct bt_conn *conn, sizeof(subgroup->metadata_len) + param->subgroups[i].metadata_len; - if (cp_buf.len + subgroup_size > cp_buf.size) { - LOG_DBG("MTU is too small to send %zu octets", cp_buf.len + subgroup_size); + if (att_buf.len + subgroup_size > att_buf.size) { + LOG_DBG("MTU is too small to send %zu octets", att_buf.len + subgroup_size); return -EINVAL; } - subgroup = net_buf_simple_add(&cp_buf, subgroup_size); + subgroup = net_buf_simple_add(&att_buf, subgroup_size); /* The BIS Index bitfield to be sent must use BIT(0) for BIS Index 1 */ subgroup->bis_sync = param->subgroups[i].bis_sync >> 1; @@ -789,7 +987,7 @@ int bt_bap_broadcast_assistant_add_src(struct bt_conn *conn, } - return bt_bap_broadcast_assistant_common_cp(conn, &cp_buf); + return bt_bap_broadcast_assistant_common_cp(conn, &att_buf); } int bt_bap_broadcast_assistant_mod_src(struct bt_conn *conn, @@ -814,8 +1012,8 @@ int bt_bap_broadcast_assistant_mod_src(struct bt_conn *conn, } /* Reset buffer before using */ - net_buf_simple_reset(&cp_buf); - cp = net_buf_simple_add(&cp_buf, sizeof(*cp)); + net_buf_simple_reset(&att_buf); + cp = net_buf_simple_add(&att_buf, sizeof(*cp)); cp->opcode = BT_BAP_BASS_OP_MOD_SRC; cp->src_id = param->src_id; @@ -857,11 +1055,11 @@ int bt_bap_broadcast_assistant_mod_src(struct bt_conn *conn, sizeof(subgroup->metadata_len) + param->subgroups[i].metadata_len; - if (cp_buf.len + subgroup_size > cp_buf.size) { - LOG_DBG("MTU is too small to send %zu octets", cp_buf.len + subgroup_size); + if (att_buf.len + subgroup_size > att_buf.size) { + LOG_DBG("MTU is too small to send %zu octets", att_buf.len + subgroup_size); return -EINVAL; } - subgroup = net_buf_simple_add(&cp_buf, subgroup_size); + subgroup = net_buf_simple_add(&att_buf, subgroup_size); /* The BIS Index bitfield to be sent must use BIT(0) for BIS Index 1 */ subgroup->bis_sync = param->subgroups[i].bis_sync >> 1; @@ -881,7 +1079,7 @@ int bt_bap_broadcast_assistant_mod_src(struct bt_conn *conn, } } - return bt_bap_broadcast_assistant_common_cp(conn, &cp_buf); + return bt_bap_broadcast_assistant_common_cp(conn, &att_buf); } int bt_bap_broadcast_assistant_set_broadcast_code( @@ -905,8 +1103,8 @@ int bt_bap_broadcast_assistant_set_broadcast_code( } /* Reset buffer before using */ - net_buf_simple_reset(&cp_buf); - cp = net_buf_simple_add(&cp_buf, sizeof(*cp)); + net_buf_simple_reset(&att_buf); + cp = net_buf_simple_add(&att_buf, sizeof(*cp)); cp->opcode = BT_BAP_BASS_OP_BROADCAST_CODE; cp->src_id = src_id; @@ -916,7 +1114,7 @@ int bt_bap_broadcast_assistant_set_broadcast_code( LOG_HEXDUMP_DBG(cp->broadcast_code, BT_AUDIO_BROADCAST_CODE_SIZE, "broadcast code:"); - return bt_bap_broadcast_assistant_common_cp(conn, &cp_buf); + return bt_bap_broadcast_assistant_common_cp(conn, &att_buf); } int bt_bap_broadcast_assistant_rem_src(struct bt_conn *conn, uint8_t src_id) @@ -938,13 +1136,13 @@ int bt_bap_broadcast_assistant_rem_src(struct bt_conn *conn, uint8_t src_id) } /* Reset buffer before using */ - net_buf_simple_reset(&cp_buf); - cp = net_buf_simple_add(&cp_buf, sizeof(*cp)); + net_buf_simple_reset(&att_buf); + cp = net_buf_simple_add(&att_buf, sizeof(*cp)); cp->opcode = BT_BAP_BASS_OP_REM_SRC; cp->src_id = src_id; - return bt_bap_broadcast_assistant_common_cp(conn, &cp_buf); + return bt_bap_broadcast_assistant_common_cp(conn, &att_buf); } int bt_bap_broadcast_assistant_read_recv_state(struct bt_conn *conn, @@ -975,7 +1173,6 @@ int bt_bap_broadcast_assistant_read_recv_state(struct bt_conn *conn, broadcast_assistant.read_params.single.handle = broadcast_assistant.recv_state_handles[idx]; - /* we do not need a semaphore for the read_params long read I think */ err = bt_gatt_read(conn, &broadcast_assistant.read_params); if (err != 0) { (void)memset(&broadcast_assistant.read_params, 0, From 3ef1b045ce0a9f8923a72081ff625e940e5825ab Mon Sep 17 00:00:00 2001 From: Andries Kruithof Date: Tue, 23 Jan 2024 11:03:17 +0100 Subject: [PATCH 3300/3723] Bluetooth: audio: fix bug in scan delegator sync In the scan delegator when modifying the source we only want to send a sync request to the upper layers if we are not yet synced, and not also on a state change Note that without this change the babblesim test for long writes will fail Signed-off-by: Andries Kruithof Scan del bugfix Signed-off-by: Andries Kruithof --- subsys/bluetooth/audio/bap_scan_delegator.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/subsys/bluetooth/audio/bap_scan_delegator.c b/subsys/bluetooth/audio/bap_scan_delegator.c index 96689c09b43..79901fd3c46 100644 --- a/subsys/bluetooth/audio/bap_scan_delegator.c +++ b/subsys/bluetooth/audio/bap_scan_delegator.c @@ -161,8 +161,8 @@ static void bass_notify_receive_state(struct bt_conn *conn, LOG_DBG("Sending bytes %d", ntf_size); err = bt_gatt_notify_uuid(NULL, BT_UUID_BASS_RECV_STATE, - internal_state->attr, read_buf.data, - ntf_size); + internal_state->attr, read_buf.data, + ntf_size); if (err != 0 && err != -ENOTCONN) { LOG_DBG("Could not notify receive state: %d", err); @@ -807,7 +807,7 @@ static int scan_delegator_mod_src(struct bt_conn *conn, * we are not already synced to the device */ if (pa_sync != BT_BAP_BASS_PA_REQ_NO_SYNC && - (state_changed || state->pa_sync_state != BT_BAP_PA_STATE_SYNCED)) { + state->pa_sync_state != BT_BAP_PA_STATE_SYNCED) { const int err = pa_sync_request(conn, state, pa_sync, pa_interval); From b7078286d26d4e18b44d33316a41e646a091d5e8 Mon Sep 17 00:00:00 2001 From: Andries Kruithof Date: Tue, 19 Dec 2023 14:46:40 +0100 Subject: [PATCH 3301/3723] Bluetooth: audio: test: add test for long write Added a test for long write, long read, and notifications Signed-off-by: Andries Kruithof --- tests/bsim/bluetooth/audio/prj.conf | 1 + .../audio/src/bap_broadcast_assistant_test.c | 36 +++++++++++++++++++ tests/bsim/bluetooth/audio/src/bap_common.h | 3 +- 3 files changed, 39 insertions(+), 1 deletion(-) diff --git a/tests/bsim/bluetooth/audio/prj.conf b/tests/bsim/bluetooth/audio/prj.conf index 9414077e031..a00f49142a5 100644 --- a/tests/bsim/bluetooth/audio/prj.conf +++ b/tests/bsim/bluetooth/audio/prj.conf @@ -113,6 +113,7 @@ CONFIG_BT_OTS_CLIENT=y # Broadcast Audio Scan Service and client CONFIG_BT_BAP_SCAN_DELEGATOR=y +CONFIG_BT_BAP_SCAN_DELEGATOR_MAX_METADATA_LEN=255 CONFIG_BT_BAP_BROADCAST_ASSISTANT=y # Hearing Access diff --git a/tests/bsim/bluetooth/audio/src/bap_broadcast_assistant_test.c b/tests/bsim/bluetooth/audio/src/bap_broadcast_assistant_test.c index 94b67b13493..3980fe963ab 100644 --- a/tests/bsim/bluetooth/audio/src/bap_broadcast_assistant_test.c +++ b/tests/bsim/bluetooth/audio/src/bap_broadcast_assistant_test.c @@ -11,6 +11,7 @@ #include #include "../../../../../subsys/bluetooth/host/hci_core.h" #include "common.h" +#include "bap_common.h" extern enum bst_result_t bst_result; @@ -36,6 +37,8 @@ static bt_addr_le_t g_broadcaster_addr; static struct bt_le_scan_recv_info g_broadcaster_info; static struct bt_le_per_adv_sync *g_pa_sync; +static uint8_t metadata[] = {BT_AUDIO_CODEC_DATA(BT_AUDIO_METADATA_TYPE_VENDOR, LONG_META)}; + static const char *phy2str(uint8_t phy) { switch (phy) { @@ -424,6 +427,38 @@ static void test_bass_mod_source(void) mod_src_param.pa_interval = g_broadcaster_info.interval; subgroup.bis_sync = BIT(1) | BIT(2); /* Indexes 1 and 2 */ subgroup.metadata_len = 0; + + err = bt_bap_broadcast_assistant_mod_src(default_conn, &mod_src_param); + if (err != 0) { + FAIL("Could not modify source (err %d)\n", err); + return; + } + + WAIT_FOR_FLAG(flag_cb_called); + WAIT_FOR_FLAG(flag_write_complete); + printk("Source added, waiting for server to PA sync\n"); + WAIT_FOR_FLAG(flag_state_synced) + printk("Server PA synced\n"); +} + +static void test_bass_mod_source_long_meta(void) +{ + int err; + struct bt_bap_broadcast_assistant_mod_src_param mod_src_param = { 0 }; + struct bt_bap_scan_delegator_subgroup subgroup = { 0 }; + + printk("Long write\n"); + UNSET_FLAG(flag_cb_called); + UNSET_FLAG(flag_write_complete); + mod_src_param.src_id = g_src_id; + mod_src_param.num_subgroups = 1; + mod_src_param.pa_sync = true; + mod_src_param.subgroups = &subgroup; + mod_src_param.pa_interval = g_broadcaster_info.interval; + subgroup.bis_sync = BIT(1) | BIT(2); + + subgroup.metadata_len = sizeof(metadata); + memcpy(subgroup.metadata, metadata, sizeof(metadata)); err = bt_bap_broadcast_assistant_mod_src(default_conn, &mod_src_param); if (err != 0) { FAIL("Could not modify source (err %d)\n", err); @@ -525,6 +560,7 @@ static void test_main_client_sync(void) test_bass_create_pa_sync(); test_bass_add_source(); test_bass_mod_source(); + test_bass_mod_source_long_meta(); test_bass_broadcast_code(); printk("Waiting for receive state with BIS sync\n"); diff --git a/tests/bsim/bluetooth/audio/src/bap_common.h b/tests/bsim/bluetooth/audio/src/bap_common.h index 4bf98bf46da..7b75f465eb7 100644 --- a/tests/bsim/bluetooth/audio/src/bap_common.h +++ b/tests/bsim/bluetooth/audio/src/bap_common.h @@ -29,7 +29,8 @@ 0x60, 0x61, 0x62, 0x63, 0x64, 0x65, 0x66, 0x67, \ 0x68, 0x69, 0x6a, 0x6b, 0x6c, 0x6d, 0x6e, 0x6f, \ 0x70, 0x71, 0x72, 0x73, 0x74, 0x75, 0x76, 0x77, \ - 0x78, 0x79, 0x7a, 0x7b, 0x7c, 0x7d, 0x7e, 0x7f + 0x78, 0x79, 0x7a, 0x7b, 0x7c, 0x7d, 0x7e, 0x7f, \ + 0x80, 0x81, 0x82, 0x83, 0x84, 0x85, 0x86, 0x87 #define LONG_META_LEN (sizeof((uint8_t []){LONG_META}) + 1U) /* Size of data + type */ From 25173f71cda630d4fb0c860d4e45e6f93c0995dd Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Krzysztof=20Chru=C5=9Bci=C5=84ski?= Date: Wed, 10 Jan 2024 11:01:11 +0100 Subject: [PATCH 3302/3723] pm: device_runtime: Extend with synchronous runtime PM MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit In many cases suspending or resuming of a device is limited to just a few register writes. Current solution assumes that those operations may be blocking, asynchronous and take a lot of time. Due to this assumption runtime PM API cannot be effectively used from the interrupt context. Zephyr has few driver APIs which can be used from an interrupt context and now use of runtime PM is limited in those cases. Patch introduces a new type of PM device - synchronous PM. If device is specified as capable of synchronous PM operations then device runtime getting and putting is executed in the critical section. In that case, runtime API can be used from an interrupt context. Additionally, this approach reduces RAM needed for PM device (104 -> 20 bytes of RAM on ARM Cortex-M). Signed-off-by: Krzysztof Chruściński --- drivers/power_domain/power_domain_gpio.c | 2 +- .../power_domain/power_domain_gpio_monitor.c | 2 +- include/zephyr/device.h | 16 +- include/zephyr/pm/device.h | 184 ++++++++--- kernel/include/kernel_offsets.h | 2 +- subsys/pm/device.c | 36 +-- subsys/pm/device_runtime.c | 285 ++++++++++++++---- 7 files changed, 410 insertions(+), 117 deletions(-) diff --git a/drivers/power_domain/power_domain_gpio.c b/drivers/power_domain/power_domain_gpio.c index 82d9a17ef9e..c5517d42f11 100644 --- a/drivers/power_domain/power_domain_gpio.c +++ b/drivers/power_domain/power_domain_gpio.c @@ -37,7 +37,7 @@ static int pd_on_domain_visitor(const struct device *dev, void *context) struct pd_visitor_context *visitor_context = context; /* Only run action if the device is on the specified domain */ - if (!dev->pm || (dev->pm->domain != visitor_context->domain)) { + if (!dev->pm || (dev->pm_base->domain != visitor_context->domain)) { return 0; } diff --git a/drivers/power_domain/power_domain_gpio_monitor.c b/drivers/power_domain/power_domain_gpio_monitor.c index 40c03bb8dd7..62dfd60855b 100644 --- a/drivers/power_domain/power_domain_gpio_monitor.c +++ b/drivers/power_domain/power_domain_gpio_monitor.c @@ -35,7 +35,7 @@ static int pd_on_domain_visitor(const struct device *dev, void *context) struct pd_visitor_context *visitor_context = context; /* Only run action if the device is on the specified domain */ - if (!dev->pm || (dev->pm->domain != visitor_context->domain)) { + if (!dev->pm || (dev->pm_base->domain != visitor_context->domain)) { return 0; } diff --git a/include/zephyr/device.h b/include/zephyr/device.h index c55958924ff..e581fe74d38 100644 --- a/include/zephyr/device.h +++ b/include/zephyr/device.h @@ -371,7 +371,9 @@ struct device_state { bool initialized : 1; }; +struct pm_device_base; struct pm_device; +struct pm_device_isr; #ifdef CONFIG_DEVICE_DEPS_DYNAMIC #define Z_DEVICE_DEPS_CONST @@ -409,7 +411,11 @@ struct device { * Reference to the device PM resources (only available if * @kconfig{CONFIG_PM_DEVICE} is enabled). */ - struct pm_device *pm; + union { + struct pm_device_base *pm_base; + struct pm_device *pm; + struct pm_device_isr *pm_isr; + }; #endif }; @@ -885,7 +891,7 @@ static inline bool z_impl_device_is_ready(const struct device *dev) * @brief Initializer for @ref device. * * @param name_ Name of the device. - * @param pm_ Reference to @ref pm_device (optional). + * @param pm_ Reference to @ref pm_device_base (optional). * @param data_ Reference to device data. * @param config_ Reference to device config. * @param api_ Reference to device API ops. @@ -900,7 +906,7 @@ static inline bool z_impl_device_is_ready(const struct device *dev) .state = (state_), \ .data = (data_), \ IF_ENABLED(CONFIG_DEVICE_DEPS, (.deps = (deps_),)) /**/ \ - IF_ENABLED(CONFIG_PM_DEVICE, (.pm = (pm_),)) /**/ \ + IF_ENABLED(CONFIG_PM_DEVICE, (.pm_base = (pm_),)) /**/ \ } /** @@ -919,7 +925,7 @@ static inline bool z_impl_device_is_ready(const struct device *dev) * software device). * @param dev_id Device identifier (used to name the defined @ref device). * @param name Name of the device. - * @param pm Reference to @ref pm_device associated with the device. + * @param pm Reference to @ref pm_device_base associated with the device. * (optional). * @param data Reference to device data. * @param config Reference to device config. @@ -991,7 +997,7 @@ static inline bool z_impl_device_is_ready(const struct device *dev) * @param dev_id Device identifier (used to name the defined @ref device). * @param name Name of the device. * @param init_fn Device init function. - * @param pm Reference to @ref pm_device associated with the device. + * @param pm Reference to @ref pm_device_base associated with the device. * (optional). * @param data Reference to device data. * @param config Reference to device config. diff --git a/include/zephyr/pm/device.h b/include/zephyr/pm/device.h index ab54fd677fe..d34a84c3911 100644 --- a/include/zephyr/pm/device.h +++ b/include/zephyr/pm/device.h @@ -50,6 +50,8 @@ enum pm_device_flag { PM_DEVICE_FLAG_PD, /** Indicates if device runtime PM should be automatically enabled */ PM_DEVICE_FLAG_RUNTIME_AUTO, + /** Indicates that device runtime PM supports suspending and resuming from any context. */ + PM_DEVICE_FLAG_ISR_SAFE, }; /** @endcond */ @@ -122,8 +124,37 @@ typedef bool (*pm_device_action_failed_cb_t)(const struct device *dev, /** * @brief Device PM info + * + * Structure holds fields which are common for two PM devices: generic and + * synchronous. + */ +struct pm_device_base { + /** Device PM status flags. */ + atomic_t flags; + /** Device power state */ + enum pm_device_state state; + /** Device PM action callback */ + pm_device_action_cb_t action_cb; +#if defined(CONFIG_PM_DEVICE_RUNTIME) || defined(__DOXYGEN__) + /** Device usage count */ + uint32_t usage; +#endif /* CONFIG_PM_DEVICE_RUNTIME */ +#ifdef CONFIG_PM_DEVICE_POWER_DOMAIN + /** Power Domain it belongs */ + const struct device *domain; +#endif /* CONFIG_PM_DEVICE_POWER_DOMAIN */ +}; + +/** + * @brief Runtime PM info for device with generic PM. + * + * Generic PM involves suspending and resuming operations which can be blocking, + * long lasting or asynchronous. Runtime PM API is limited when used from + * interrupt context. */ struct pm_device { + /** Base info. */ + struct pm_device_base base; #if defined(CONFIG_PM_DEVICE_RUNTIME) || defined(__DOXYGEN__) /** Pointer to the device */ const struct device *dev; @@ -131,23 +162,31 @@ struct pm_device { struct k_sem lock; /** Event var to listen to the sync request events */ struct k_event event; - /** Device usage count */ - uint32_t usage; /** Work object for asynchronous calls */ struct k_work_delayable work; #endif /* CONFIG_PM_DEVICE_RUNTIME */ -#ifdef CONFIG_PM_DEVICE_POWER_DOMAIN - /** Power Domain it belongs */ - const struct device *domain; -#endif /* CONFIG_PM_DEVICE_POWER_DOMAIN */ - /* Device PM status flags. */ - atomic_t flags; - /** Device power state */ - enum pm_device_state state; - /** Device PM action callback */ - pm_device_action_cb_t action_cb; }; +/** + * @brief Runtime PM info for device with synchronous PM. + * + * Synchronous PM can be used with devices which suspend and resume operations can + * be performed in the critical section as they are short and non-blocking. + * Runtime PM API can be used from any context in that case. + */ +struct pm_device_isr { + /** Base info. */ + struct pm_device_base base; +#if defined(CONFIG_PM_DEVICE_RUNTIME) || defined(__DOXYGEN__) + /** Lock to synchronize the synchronous get/put operations */ + struct k_spinlock lock; +#endif +}; + +/* Base part must be the first element. */ +BUILD_ASSERT(offsetof(struct pm_device, base) == 0); +BUILD_ASSERT(offsetof(struct pm_device_isr, base) == 0); + /** @cond INTERNAL_HIDDEN */ #ifdef CONFIG_PM_DEVICE_RUNTIME @@ -167,7 +206,7 @@ struct pm_device { #endif /* CONFIG_PM_DEVICE_POWER_DOMAIN */ /** - * @brief Utility macro to initialize #pm_device flags + * @brief Utility macro to initialize #pm_device_base flags * * @param node_id Devicetree node for the initialized device (can be invalid). */ @@ -188,17 +227,34 @@ struct pm_device { * @note #DT_PROP_OR is used to retrieve the wakeup_source property because * it may not be defined on all devices. * - * @param obj Name of the #pm_device structure being initialized. + * @param obj Name of the #pm_device_base structure being initialized. + * @param node_id Devicetree node for the initialized device (can be invalid). + * @param pm_action_cb Device PM control callback function. + * @param _flags Additional flags passed to the structure. + */ +#define Z_PM_DEVICE_BASE_INIT(obj, node_id, pm_action_cb, _flags) \ + { \ + .action_cb = pm_action_cb, \ + .state = PM_DEVICE_STATE_ACTIVE, \ + .flags = ATOMIC_INIT(Z_PM_DEVICE_FLAGS(node_id) | (_flags)), \ + Z_PM_DEVICE_POWER_DOMAIN_INIT(node_id) \ + } + +/** + * @brief Utility macro to initialize #pm_device_rt. + * + * @note #DT_PROP_OR is used to retrieve the wakeup_source property because + * it may not be defined on all devices. + * + * @param obj Name of the #pm_device_base structure being initialized. * @param node_id Devicetree node for the initialized device (can be invalid). * @param pm_action_cb Device PM control callback function. */ -#define Z_PM_DEVICE_INIT(obj, node_id, pm_action_cb) \ - { \ - Z_PM_DEVICE_RUNTIME_INIT(obj) \ - .action_cb = pm_action_cb, \ - .state = PM_DEVICE_STATE_ACTIVE, \ - .flags = ATOMIC_INIT(Z_PM_DEVICE_FLAGS(node_id)), \ - Z_PM_DEVICE_POWER_DOMAIN_INIT(node_id) \ +#define Z_PM_DEVICE_INIT(obj, node_id, pm_action_cb, isr_safe) \ + { \ + .base = Z_PM_DEVICE_BASE_INIT(obj, node_id, pm_action_cb, \ + isr_safe ? BIT(PM_DEVICE_FLAG_ISR_SAFE) : 0), \ + COND_CODE_1(isr_safe, (), (Z_PM_DEVICE_RUNTIME_INIT(obj))) \ } /** @@ -231,21 +287,22 @@ struct pm_device { * @param dev_id Device id. * @param pm_action_cb PM control callback. */ -#define Z_PM_DEVICE_DEFINE(node_id, dev_id, pm_action_cb) \ - Z_PM_DEVICE_DEFINE_SLOT(dev_id); \ - static struct pm_device Z_PM_DEVICE_NAME(dev_id) = \ - Z_PM_DEVICE_INIT(Z_PM_DEVICE_NAME(dev_id), node_id, \ - pm_action_cb) +#define Z_PM_DEVICE_DEFINE(node_id, dev_id, pm_action_cb, isr_safe) \ + Z_PM_DEVICE_DEFINE_SLOT(dev_id); \ + static struct COND_CODE_1(isr_safe, (pm_device_isr), (pm_device)) \ + Z_PM_DEVICE_NAME(dev_id) = \ + Z_PM_DEVICE_INIT(Z_PM_DEVICE_NAME(dev_id), node_id, \ + pm_action_cb, isr_safe) /** * Get a reference to the device PM resources. * * @param dev_id Device id. */ -#define Z_PM_DEVICE_GET(dev_id) (&Z_PM_DEVICE_NAME(dev_id)) +#define Z_PM_DEVICE_GET(dev_id) ((struct pm_device_base *)&Z_PM_DEVICE_NAME(dev_id)) #else -#define Z_PM_DEVICE_DEFINE(node_id, dev_id, pm_action_cb) +#define Z_PM_DEVICE_DEFINE(node_id, dev_id, pm_action_cb, isr_safe) #define Z_PM_DEVICE_GET(dev_id) NULL #endif /* CONFIG_PM_DEVICE */ @@ -262,8 +319,26 @@ struct pm_device { * @see #PM_DEVICE_DT_DEFINE, #PM_DEVICE_DT_INST_DEFINE */ #define PM_DEVICE_DEFINE(dev_id, pm_action_cb) \ - Z_PM_DEVICE_DEFINE(DT_INVALID_NODE, dev_id, pm_action_cb) + Z_PM_DEVICE_DEFINE(DT_INVALID_NODE, dev_id, pm_action_cb, 0) +/** + * Define device PM resources for the given device name. + * + * PM actions are synchronous and can be executed from any context. This approach + * can be used for cases where suspending and resuming is short as it is + * executed in the critical section. This mode requires less resources (~80 byte + * less RAM) and allows to use device runtime PM from any context (including + * interrupts). + * + * @note This macro is a no-op if @kconfig{CONFIG_PM_DEVICE} is not enabled. + * + * @param dev_id Device id. + * @param pm_action_cb PM control callback. + * + * @see #PM_DEVICE_DT_DEFINE, #PM_DEVICE_DT_INST_DEFINE + */ +#define PM_DEVICE_ISR_SYNC_DEFINE(dev_id, pm_action_cb) \ + Z_PM_DEVICE_DEFINE(DT_INVALID_NODE, dev_id, pm_action_cb, 1) /** * Define device PM resources for the given node identifier. * @@ -274,9 +349,27 @@ struct pm_device { * * @see #PM_DEVICE_DT_INST_DEFINE, #PM_DEVICE_DEFINE */ -#define PM_DEVICE_DT_DEFINE(node_id, pm_action_cb) \ - Z_PM_DEVICE_DEFINE(node_id, Z_DEVICE_DT_DEV_ID(node_id), \ - pm_action_cb) +#define PM_DEVICE_DT_DEFINE(node_id, pm_action_cb) \ + Z_PM_DEVICE_DEFINE(node_id, Z_DEVICE_DT_DEV_ID(node_id), pm_action_cb, 0) + +/** + * Define device PM resources for the given node identifier. + * + * PM actions are synchronous and can be executed from any context. This approach + * can be used for cases where suspending and resuming is short as it is + * executed in the critical section. This mode requires less resources (~80 byte + * less RAM) and allows to use device runtime PM from any context (including + * interrupts). + * + * @note This macro is a no-op if @kconfig{CONFIG_PM_DEVICE} is not enabled. + * + * @param node_id Node identifier. + * @param pm_action_cb PM control callback. + * + * @see #PM_DEVICE_DT_INST_DEFINE, #PM_DEVICE_DEFINE + */ +#define PM_DEVICE_ISR_SAFE_DT_DEFINE(node_id, pm_action_cb) \ + Z_PM_DEVICE_DEFINE(node_id, Z_DEVICE_DT_DEV_ID(node_id), pm_action_cb, 1) /** * Define device PM resources for the given instance. @@ -291,7 +384,28 @@ struct pm_device { #define PM_DEVICE_DT_INST_DEFINE(idx, pm_action_cb) \ Z_PM_DEVICE_DEFINE(DT_DRV_INST(idx), \ Z_DEVICE_DT_DEV_ID(DT_DRV_INST(idx)), \ - pm_action_cb) + pm_action_cb, 0) + +/** + * Define device PM resources for the given instance. + * + * PM actions are synchronous and can be executed from any context. This approach + * can be used for cases where suspending and resuming is short as it is + * executed in the critical section. This mode requires less resources (~80 byte + * less RAM) and allows to use device runtime PM from any context (including + * interrupts). + * + * @note This macro is a no-op if @kconfig{CONFIG_PM_DEVICE} is not enabled. + * + * @param idx Instance index. + * @param pm_action_cb PM control callback. + * + * @see #PM_DEVICE_DT_DEFINE, #PM_DEVICE_DEFINE + */ +#define PM_DEVICE_ISR_SAFE_DT_INST_DEFINE(idx, pm_action_cb) \ + Z_PM_DEVICE_DEFINE(DT_DRV_INST(idx), \ + Z_DEVICE_DT_DEV_ID(DT_DRV_INST(idx)), \ + pm_action_cb, 1) /** * @brief Obtain a reference to the device PM resources for the given device. @@ -393,7 +507,7 @@ int pm_device_state_get(const struct device *dev, */ static inline void pm_device_init_suspended(const struct device *dev) { - struct pm_device *pm = dev->pm; + struct pm_device_base *pm = dev->pm_base; pm->state = PM_DEVICE_STATE_SUSPENDED; } @@ -413,7 +527,7 @@ static inline void pm_device_init_suspended(const struct device *dev) */ static inline void pm_device_init_off(const struct device *dev) { - struct pm_device *pm = dev->pm; + struct pm_device_base *pm = dev->pm_base; pm->state = PM_DEVICE_STATE_OFF; } diff --git a/kernel/include/kernel_offsets.h b/kernel/include/kernel_offsets.h index f7676438d9e..5644dbb1575 100644 --- a/kernel/include/kernel_offsets.h +++ b/kernel/include/kernel_offsets.h @@ -86,7 +86,7 @@ GEN_ABSOLUTE_SYM(_DEVICE_STRUCT_PM_OFFSET, /* member offsets in the pm_device structure. Used in image post-processing */ GEN_ABSOLUTE_SYM(_PM_DEVICE_STRUCT_FLAGS_OFFSET, - offsetof(struct pm_device, flags)); + offsetof(struct pm_device_base, flags)); GEN_ABSOLUTE_SYM(_PM_DEVICE_FLAG_PD, PM_DEVICE_FLAG_PD); diff --git a/subsys/pm/device.c b/subsys/pm/device.c index 15e8085773b..ca3816fa93b 100644 --- a/subsys/pm/device.c +++ b/subsys/pm/device.c @@ -42,7 +42,7 @@ const char *pm_device_state_str(enum pm_device_state state) int pm_device_action_run(const struct device *dev, enum pm_device_action action) { - struct pm_device *pm = dev->pm; + struct pm_device_base *pm = dev->pm_base; int ret; if (pm == NULL) { @@ -139,13 +139,13 @@ static int power_domain_add_or_remove(const struct device *dev, while (rv[i] != Z_DEVICE_DEPS_ENDS) { if (add == false) { if (rv[i] == dev_handle) { - dev->pm->domain = NULL; + dev->pm_base->domain = NULL; rv[i] = DEVICE_HANDLE_NULL; return 0; } } else { if (rv[i] == DEVICE_HANDLE_NULL) { - dev->pm->domain = domain; + dev->pm_base->domain = domain; rv[i] = dev_handle; return 0; } @@ -212,7 +212,7 @@ void pm_device_children_action_run(const struct device *dev, int pm_device_state_get(const struct device *dev, enum pm_device_state *state) { - struct pm_device *pm = dev->pm; + struct pm_device_base *pm = dev->pm_base; if (pm == NULL) { return -ENOSYS; @@ -231,7 +231,7 @@ bool pm_device_is_any_busy(void) devc = z_device_get_all_static(&devs); for (const struct device *dev = devs; dev < (devs + devc); dev++) { - struct pm_device *pm = dev->pm; + struct pm_device_base *pm = dev->pm_base; if (pm == NULL) { continue; @@ -247,7 +247,7 @@ bool pm_device_is_any_busy(void) bool pm_device_is_busy(const struct device *dev) { - struct pm_device *pm = dev->pm; + struct pm_device_base *pm = dev->pm_base; if (pm == NULL) { return false; @@ -258,7 +258,7 @@ bool pm_device_is_busy(const struct device *dev) void pm_device_busy_set(const struct device *dev) { - struct pm_device *pm = dev->pm; + struct pm_device_base *pm = dev->pm_base; if (pm == NULL) { return; @@ -269,7 +269,7 @@ void pm_device_busy_set(const struct device *dev) void pm_device_busy_clear(const struct device *dev) { - struct pm_device *pm = dev->pm; + struct pm_device_base *pm = dev->pm_base; if (pm == NULL) { return; @@ -281,7 +281,7 @@ void pm_device_busy_clear(const struct device *dev) bool pm_device_wakeup_enable(const struct device *dev, bool enable) { atomic_val_t flags, new_flags; - struct pm_device *pm = dev->pm; + struct pm_device_base *pm = dev->pm_base; if (pm == NULL) { return false; @@ -305,7 +305,7 @@ bool pm_device_wakeup_enable(const struct device *dev, bool enable) bool pm_device_wakeup_is_enabled(const struct device *dev) { - struct pm_device *pm = dev->pm; + struct pm_device_base *pm = dev->pm_base; if (pm == NULL) { return false; @@ -317,7 +317,7 @@ bool pm_device_wakeup_is_enabled(const struct device *dev) bool pm_device_wakeup_is_capable(const struct device *dev) { - struct pm_device *pm = dev->pm; + struct pm_device_base *pm = dev->pm_base; if (pm == NULL) { return false; @@ -329,7 +329,7 @@ bool pm_device_wakeup_is_capable(const struct device *dev) void pm_device_state_lock(const struct device *dev) { - struct pm_device *pm = dev->pm; + struct pm_device_base *pm = dev->pm_base; if ((pm != NULL) && !pm_device_runtime_is_enabled(dev)) { atomic_set_bit(&pm->flags, PM_DEVICE_FLAG_STATE_LOCKED); @@ -338,7 +338,7 @@ void pm_device_state_lock(const struct device *dev) void pm_device_state_unlock(const struct device *dev) { - struct pm_device *pm = dev->pm; + struct pm_device_base *pm = dev->pm_base; if (pm != NULL) { atomic_clear_bit(&pm->flags, PM_DEVICE_FLAG_STATE_LOCKED); @@ -347,7 +347,7 @@ void pm_device_state_unlock(const struct device *dev) bool pm_device_state_is_locked(const struct device *dev) { - struct pm_device *pm = dev->pm; + struct pm_device_base *pm = dev->pm_base; if (pm == NULL) { return false; @@ -360,7 +360,7 @@ bool pm_device_state_is_locked(const struct device *dev) bool pm_device_on_power_domain(const struct device *dev) { #ifdef CONFIG_PM_DEVICE_POWER_DOMAIN - struct pm_device *pm = dev->pm; + struct pm_device_base *pm = dev->pm_base; if (pm == NULL) { return false; @@ -375,14 +375,14 @@ bool pm_device_on_power_domain(const struct device *dev) bool pm_device_is_powered(const struct device *dev) { #ifdef CONFIG_PM_DEVICE_POWER_DOMAIN - struct pm_device *pm = dev->pm; + struct pm_device_base *pm = dev->pm_base; /* If a device doesn't support PM or is not under a PM domain, * assume it is always powered on. */ return (pm == NULL) || (pm->domain == NULL) || - (pm->domain->pm->state == PM_DEVICE_STATE_ACTIVE); + (pm->domain->pm_base->state == PM_DEVICE_STATE_ACTIVE); #else ARG_UNUSED(dev); return true; @@ -392,7 +392,7 @@ bool pm_device_is_powered(const struct device *dev) int pm_device_driver_init(const struct device *dev, pm_device_action_cb_t action_cb) { - struct pm_device *pm = dev->pm; + struct pm_device_base *pm = dev->pm_base; int rc = 0; /* Work only needs to be performed if the device is powered */ diff --git a/subsys/pm/device_runtime.c b/subsys/pm/device_runtime.c index b6d3091e71d..37cd7b85ba9 100644 --- a/subsys/pm/device_runtime.c +++ b/subsys/pm/device_runtime.c @@ -52,7 +52,7 @@ static int runtime_suspend(const struct device *dev, bool async, /* * Early return if device runtime is not enabled. */ - if (!atomic_test_bit(&pm->flags, PM_DEVICE_FLAG_RUNTIME_ENABLED)) { + if (!atomic_test_bit(&pm->base.flags, PM_DEVICE_FLAG_RUNTIME_ENABLED)) { return 0; } @@ -65,30 +65,30 @@ static int runtime_suspend(const struct device *dev, bool async, } } - if (pm->usage == 0U) { + if (pm->base.usage == 0U) { LOG_WRN("Unbalanced suspend"); ret = -EALREADY; goto unlock; } - pm->usage--; - if (pm->usage > 0U) { + pm->base.usage--; + if (pm->base.usage > 0U) { goto unlock; } if (async) { /* queue suspend */ - pm->state = PM_DEVICE_STATE_SUSPENDING; + pm->base.state = PM_DEVICE_STATE_SUSPENDING; (void)k_work_schedule(&pm->work, delay); } else { /* suspend now */ - ret = pm->action_cb(pm->dev, PM_DEVICE_ACTION_SUSPEND); + ret = pm->base.action_cb(pm->dev, PM_DEVICE_ACTION_SUSPEND); if (ret < 0) { - pm->usage++; + pm->base.usage++; goto unlock; } - pm->state = PM_DEVICE_STATE_SUSPENDED; + pm->base.state = PM_DEVICE_STATE_SUSPENDED; } unlock: @@ -105,16 +105,16 @@ static void runtime_suspend_work(struct k_work *work) struct k_work_delayable *dwork = k_work_delayable_from_work(work); struct pm_device *pm = CONTAINER_OF(dwork, struct pm_device, work); - ret = pm->action_cb(pm->dev, PM_DEVICE_ACTION_SUSPEND); + ret = pm->base.action_cb(pm->dev, PM_DEVICE_ACTION_SUSPEND); (void)k_sem_take(&pm->lock, K_FOREVER); if (ret < 0) { - pm->usage++; - pm->state = PM_DEVICE_STATE_ACTIVE; + pm->base.usage++; + pm->base.state = PM_DEVICE_STATE_ACTIVE; } else { - pm->state = PM_DEVICE_STATE_SUSPENDED; + pm->base.state = PM_DEVICE_STATE_SUSPENDED; } - k_event_set(&pm->event, BIT(pm->state)); + k_event_set(&pm->event, BIT(pm->base.state)); k_sem_give(&pm->lock); /* @@ -122,13 +122,47 @@ static void runtime_suspend_work(struct k_work *work) * finishes its operation */ if ((ret == 0) && - atomic_test_bit(&pm->flags, PM_DEVICE_FLAG_PD_CLAIMED)) { - (void)pm_device_runtime_put(PM_DOMAIN(pm)); + atomic_test_bit(&pm->base.flags, PM_DEVICE_FLAG_PD_CLAIMED)) { + (void)pm_device_runtime_put(PM_DOMAIN(&pm->base)); } __ASSERT(ret == 0, "Could not suspend device (%d)", ret); } +static int get_sync_locked(const struct device *dev) +{ + int ret; + struct pm_device_isr *pm = dev->pm_isr; + uint32_t flags = pm->base.flags; + + if (pm->base.usage == 0) { + if (flags & BIT(PM_DEVICE_FLAG_PD_CLAIMED)) { + const struct device *domain = PM_DOMAIN(&pm->base); + + if (domain->pm_base->flags & PM_DEVICE_FLAG_ISR_SAFE) { + ret = pm_device_runtime_get(domain); + if (ret < 0) { + return ret; + } + } else { + return -EWOULDBLOCK; + } + } + + ret = pm->base.action_cb(dev, PM_DEVICE_ACTION_RESUME); + if (ret < 0) { + return ret; + } + pm->base.state = PM_DEVICE_STATE_ACTIVE; + } else { + ret = 0; + } + + pm->base.usage++; + + return ret; +} + int pm_device_runtime_get(const struct device *dev) { int ret = 0; @@ -143,10 +177,19 @@ int pm_device_runtime_get(const struct device *dev) /* * Early return if device runtime is not enabled. */ - if (!atomic_test_bit(&pm->flags, PM_DEVICE_FLAG_RUNTIME_ENABLED)) { + if (!atomic_test_bit(&pm->base.flags, PM_DEVICE_FLAG_RUNTIME_ENABLED)) { return 0; } + if (atomic_test_bit(&dev->pm_base->flags, PM_DEVICE_FLAG_ISR_SAFE)) { + struct pm_device_isr *pm_sync = dev->pm_isr; + k_spinlock_key_t k = k_spin_lock(&pm_sync->lock); + + ret = get_sync_locked(dev); + k_spin_unlock(&pm_sync->lock, k); + goto end; + } + if (!k_is_pre_kernel()) { ret = k_sem_take(&pm->lock, k_is_in_isr() ? K_NO_WAIT : K_FOREVER); if (ret < 0) { @@ -154,7 +197,7 @@ int pm_device_runtime_get(const struct device *dev) } } - if (k_is_in_isr() && (pm->state == PM_DEVICE_STATE_SUSPENDING)) { + if (k_is_in_isr() && (pm->base.state == PM_DEVICE_STATE_SUSPENDING)) { ret = -EWOULDBLOCK; goto unlock; } @@ -163,31 +206,33 @@ int pm_device_runtime_get(const struct device *dev) * If the device is under a power domain, the domain has to be get * first. */ - if (PM_DOMAIN(pm) != NULL) { - ret = pm_device_runtime_get(PM_DOMAIN(pm)); + const struct device *domain = PM_DOMAIN(&pm->base); + + if (domain != NULL) { + ret = pm_device_runtime_get(domain); if (ret != 0) { goto unlock; } /* Check if powering up this device failed */ - if (atomic_test_bit(&pm->flags, PM_DEVICE_FLAG_TURN_ON_FAILED)) { - (void)pm_device_runtime_put(PM_DOMAIN(pm)); + if (atomic_test_bit(&pm->base.flags, PM_DEVICE_FLAG_TURN_ON_FAILED)) { + (void)pm_device_runtime_put(domain); ret = -EAGAIN; goto unlock; } /* Power domain successfully claimed */ - atomic_set_bit(&pm->flags, PM_DEVICE_FLAG_PD_CLAIMED); + atomic_set_bit(&pm->base.flags, PM_DEVICE_FLAG_PD_CLAIMED); } - pm->usage++; + pm->base.usage++; /* * Check if the device has a pending suspend operation (not started * yet) and cancel it. This way we avoid unnecessary operations because * the device is actually active. */ - if ((pm->state == PM_DEVICE_STATE_SUSPENDING) && + if ((pm->base.state == PM_DEVICE_STATE_SUSPENDING) && ((k_work_cancel_delayable(&pm->work) & K_WORK_RUNNING) == 0)) { - pm->state = PM_DEVICE_STATE_ACTIVE; + pm->base.state = PM_DEVICE_STATE_ACTIVE; goto unlock; } @@ -196,7 +241,7 @@ int pm_device_runtime_get(const struct device *dev) * If the device is already suspending there is * nothing else we can do but wait until it finishes. */ - while (pm->state == PM_DEVICE_STATE_SUSPENDING) { + while (pm->base.state == PM_DEVICE_STATE_SUSPENDING) { k_sem_give(&pm->lock); k_event_wait(&pm->event, EVENT_MASK, true, K_FOREVER); @@ -205,45 +250,95 @@ int pm_device_runtime_get(const struct device *dev) } } - if (pm->usage > 1U) { + if (pm->base.usage > 1U) { goto unlock; } - ret = pm->action_cb(pm->dev, PM_DEVICE_ACTION_RESUME); + ret = pm->base.action_cb(pm->dev, PM_DEVICE_ACTION_RESUME); if (ret < 0) { - pm->usage--; + pm->base.usage--; goto unlock; } - pm->state = PM_DEVICE_STATE_ACTIVE; + pm->base.state = PM_DEVICE_STATE_ACTIVE; unlock: if (!k_is_pre_kernel()) { k_sem_give(&pm->lock); } +end: SYS_PORT_TRACING_FUNC_EXIT(pm, device_runtime_get, dev, ret); return ret; } + +static int put_sync_locked(const struct device *dev) +{ + int ret; + struct pm_device_isr *pm = dev->pm_isr; + uint32_t flags = pm->base.flags; + + if (!(flags & BIT(PM_DEVICE_FLAG_RUNTIME_ENABLED))) { + return 0; + } + + if (pm->base.usage == 0U) { + return -EALREADY; + } + + pm->base.usage--; + if (pm->base.usage == 0U) { + ret = pm->base.action_cb(dev, PM_DEVICE_ACTION_SUSPEND); + if (ret < 0) { + return ret; + } + pm->base.state = PM_DEVICE_STATE_SUSPENDED; + + if (flags & BIT(PM_DEVICE_FLAG_PD_CLAIMED)) { + const struct device *domain = PM_DOMAIN(&pm->base); + + if (domain->pm_base->flags & PM_DEVICE_FLAG_ISR_SAFE) { + ret = put_sync_locked(domain); + } else { + ret = -EWOULDBLOCK; + } + } + } else { + ret = 0; + } + + return ret; +} + int pm_device_runtime_put(const struct device *dev) { int ret; - if (dev->pm == NULL) { + if (dev->pm_base == NULL) { return 0; } SYS_PORT_TRACING_FUNC_ENTER(pm, device_runtime_put, dev); - ret = runtime_suspend(dev, false, K_NO_WAIT); - /* - * Now put the domain - */ - if ((ret == 0) && - atomic_test_bit(&dev->pm->flags, PM_DEVICE_FLAG_PD_CLAIMED)) { - ret = pm_device_runtime_put(PM_DOMAIN(dev->pm)); + if (atomic_test_bit(&dev->pm_base->flags, PM_DEVICE_FLAG_ISR_SAFE)) { + struct pm_device_isr *pm_sync = dev->pm_isr; + k_spinlock_key_t k = k_spin_lock(&pm_sync->lock); + + ret = put_sync_locked(dev); + + k_spin_unlock(&pm_sync->lock, k); + } else { + ret = runtime_suspend(dev, false, K_NO_WAIT); + + /* + * Now put the domain + */ + if ((ret == 0) && + atomic_test_bit(&dev->pm_base->flags, PM_DEVICE_FLAG_PD_CLAIMED)) { + ret = pm_device_runtime_put(PM_DOMAIN(dev->pm_base)); + } } SYS_PORT_TRACING_FUNC_EXIT(pm, device_runtime_put, dev, ret); @@ -254,12 +349,21 @@ int pm_device_runtime_put_async(const struct device *dev, k_timeout_t delay) { int ret; - if (dev->pm == NULL) { + if (dev->pm_base == NULL) { return 0; } SYS_PORT_TRACING_FUNC_ENTER(pm, device_runtime_put_async, dev, delay); - ret = runtime_suspend(dev, true, delay); + if (atomic_test_bit(&dev->pm_base->flags, PM_DEVICE_FLAG_ISR_SAFE)) { + struct pm_device_isr *pm_sync = dev->pm_isr; + k_spinlock_key_t k = k_spin_lock(&pm_sync->lock); + + ret = put_sync_locked(dev); + + k_spin_unlock(&pm_sync->lock, k); + } else { + ret = runtime_suspend(dev, true, delay); + } SYS_PORT_TRACING_FUNC_EXIT(pm, device_runtime_put_async, dev, delay, ret); return ret; @@ -268,7 +372,7 @@ int pm_device_runtime_put_async(const struct device *dev, k_timeout_t delay) __boot_func int pm_device_runtime_auto_enable(const struct device *dev) { - struct pm_device *pm = dev->pm; + struct pm_device_base *pm = dev->pm_base; /* No action needed if PM_DEVICE_FLAG_RUNTIME_AUTO is not enabled */ if (!pm || !atomic_test_bit(&pm->flags, PM_DEVICE_FLAG_RUNTIME_AUTO)) { @@ -277,6 +381,36 @@ int pm_device_runtime_auto_enable(const struct device *dev) return pm_device_runtime_enable(dev); } +static int runtime_enable_sync(const struct device *dev) +{ + int ret; + struct pm_device_isr *pm = dev->pm_isr; + k_spinlock_key_t k = k_spin_lock(&pm->lock); + + /* Because context is locked we can access flags directly. */ + if (pm->base.flags & BIT(PM_DEVICE_FLAG_RUNTIME_ENABLED)) { + ret = 0; + goto unlock; + } + + if (pm->base.state == PM_DEVICE_STATE_ACTIVE) { + ret = pm->base.action_cb(dev, PM_DEVICE_ACTION_SUSPEND); + if (ret < 0) { + goto unlock; + } + + pm->base.state = PM_DEVICE_STATE_SUSPENDED; + } else { + ret = 0; + } + + pm->base.flags |= BIT(PM_DEVICE_FLAG_RUNTIME_ENABLED); + pm->base.usage = 0U; +unlock: + k_spin_unlock(&pm->lock, k); + return ret; +} + int pm_device_runtime_enable(const struct device *dev) { int ret = 0; @@ -293,11 +427,16 @@ int pm_device_runtime_enable(const struct device *dev) goto end; } + if (atomic_test_bit(&dev->pm_base->flags, PM_DEVICE_FLAG_ISR_SAFE)) { + ret = runtime_enable_sync(dev); + goto end; + } + if (!k_is_pre_kernel()) { (void)k_sem_take(&pm->lock, K_FOREVER); } - if (atomic_test_bit(&pm->flags, PM_DEVICE_FLAG_RUNTIME_ENABLED)) { + if (atomic_test_bit(&pm->base.flags, PM_DEVICE_FLAG_RUNTIME_ENABLED)) { goto unlock; } @@ -307,17 +446,17 @@ int pm_device_runtime_enable(const struct device *dev) k_work_init_delayable(&pm->work, runtime_suspend_work); } - if (pm->state == PM_DEVICE_STATE_ACTIVE) { - ret = pm->action_cb(pm->dev, PM_DEVICE_ACTION_SUSPEND); + if (pm->base.state == PM_DEVICE_STATE_ACTIVE) { + ret = pm->base.action_cb(pm->dev, PM_DEVICE_ACTION_SUSPEND); if (ret < 0) { goto unlock; } - pm->state = PM_DEVICE_STATE_SUSPENDED; + pm->base.state = PM_DEVICE_STATE_SUSPENDED; } - pm->usage = 0U; + pm->base.usage = 0U; - atomic_set_bit(&pm->flags, PM_DEVICE_FLAG_RUNTIME_ENABLED); + atomic_set_bit(&pm->base.flags, PM_DEVICE_FLAG_RUNTIME_ENABLED); unlock: if (!k_is_pre_kernel()) { @@ -329,6 +468,34 @@ int pm_device_runtime_enable(const struct device *dev) return ret; } +static int runtime_disable_sync(const struct device *dev) +{ + struct pm_device_isr *pm = dev->pm_isr; + int ret; + k_spinlock_key_t k = k_spin_lock(&pm->lock); + + if (!(pm->base.flags & BIT(PM_DEVICE_FLAG_RUNTIME_ENABLED))) { + ret = 0; + goto unlock; + } + + if (pm->base.state == PM_DEVICE_STATE_SUSPENDED) { + ret = pm->base.action_cb(dev, PM_DEVICE_ACTION_RESUME); + if (ret < 0) { + goto unlock; + } + + pm->base.state = PM_DEVICE_STATE_ACTIVE; + } else { + ret = 0; + } + + pm->base.flags &= ~BIT(PM_DEVICE_FLAG_RUNTIME_ENABLED); +unlock: + k_spin_unlock(&pm->lock, k); + return ret; +} + int pm_device_runtime_disable(const struct device *dev) { int ret = 0; @@ -340,23 +507,28 @@ int pm_device_runtime_disable(const struct device *dev) SYS_PORT_TRACING_FUNC_ENTER(pm, device_runtime_disable, dev); + if (atomic_test_bit(&dev->pm_base->flags, PM_DEVICE_FLAG_ISR_SAFE)) { + ret = runtime_disable_sync(dev); + goto end; + } + if (!k_is_pre_kernel()) { (void)k_sem_take(&pm->lock, K_FOREVER); } - if (!atomic_test_bit(&pm->flags, PM_DEVICE_FLAG_RUNTIME_ENABLED)) { + if (!atomic_test_bit(&pm->base.flags, PM_DEVICE_FLAG_RUNTIME_ENABLED)) { goto unlock; } if (!k_is_pre_kernel()) { - if ((pm->state == PM_DEVICE_STATE_SUSPENDING) && + if ((pm->base.state == PM_DEVICE_STATE_SUSPENDING) && ((k_work_cancel_delayable(&pm->work) & K_WORK_RUNNING) == 0)) { - pm->state = PM_DEVICE_STATE_ACTIVE; + pm->base.state = PM_DEVICE_STATE_ACTIVE; goto clear_bit; } /* wait until possible async suspend is completed */ - while (pm->state == PM_DEVICE_STATE_SUSPENDING) { + while (pm->base.state == PM_DEVICE_STATE_SUSPENDING) { k_sem_give(&pm->lock); k_event_wait(&pm->event, EVENT_MASK, true, K_FOREVER); @@ -366,23 +538,24 @@ int pm_device_runtime_disable(const struct device *dev) } /* wake up the device if suspended */ - if (pm->state == PM_DEVICE_STATE_SUSPENDED) { - ret = pm->action_cb(pm->dev, PM_DEVICE_ACTION_RESUME); + if (pm->base.state == PM_DEVICE_STATE_SUSPENDED) { + ret = pm->base.action_cb(dev, PM_DEVICE_ACTION_RESUME); if (ret < 0) { goto unlock; } - pm->state = PM_DEVICE_STATE_ACTIVE; + pm->base.state = PM_DEVICE_STATE_ACTIVE; } clear_bit: - atomic_clear_bit(&pm->flags, PM_DEVICE_FLAG_RUNTIME_ENABLED); + atomic_clear_bit(&pm->base.flags, PM_DEVICE_FLAG_RUNTIME_ENABLED); unlock: if (!k_is_pre_kernel()) { k_sem_give(&pm->lock); } +end: SYS_PORT_TRACING_FUNC_EXIT(pm, device_runtime_disable, dev, ret); return ret; @@ -390,7 +563,7 @@ int pm_device_runtime_disable(const struct device *dev) bool pm_device_runtime_is_enabled(const struct device *dev) { - struct pm_device *pm = dev->pm; + struct pm_device_base *pm = dev->pm_base; return pm && atomic_test_bit(&pm->flags, PM_DEVICE_FLAG_RUNTIME_ENABLED); } From 5ce4348311f7ee022ebeafbe5958df9d15793521 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Krzysztof=20Chru=C5=9Bci=C5=84ski?= Date: Wed, 10 Jan 2024 11:03:03 +0100 Subject: [PATCH 3303/3723] tests: pm: device_runtime_api: Extend with synchronous device MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Extended test to support case when PM device is defined as synchronous. Signed-off-by: Krzysztof Chruściński --- tests/subsys/pm/device_runtime_api/Kconfig | 8 + tests/subsys/pm/device_runtime_api/src/main.c | 160 +++++++++--------- .../pm/device_runtime_api/src/test_driver.c | 18 +- .../pm/device_runtime_api/testcase.yaml | 6 + 4 files changed, 109 insertions(+), 83 deletions(-) create mode 100644 tests/subsys/pm/device_runtime_api/Kconfig diff --git a/tests/subsys/pm/device_runtime_api/Kconfig b/tests/subsys/pm/device_runtime_api/Kconfig new file mode 100644 index 00000000000..a116921810f --- /dev/null +++ b/tests/subsys/pm/device_runtime_api/Kconfig @@ -0,0 +1,8 @@ +# Copyright 2024 Nordic Semiconductor ASA +# +# SPDX-License-Identifier: Apache-2.0 + +source "Kconfig.zephyr" + +config TEST_PM_DEVICE_ISR_SAFE + bool "Use ISR safe PM for the test" diff --git a/tests/subsys/pm/device_runtime_api/src/main.c b/tests/subsys/pm/device_runtime_api/src/main.c index 186ad7e6c78..623aa20b612 100644 --- a/tests/subsys/pm/device_runtime_api/src/main.c +++ b/tests/subsys/pm/device_runtime_api/src/main.c @@ -141,105 +141,111 @@ ZTEST(device_runtime_api, test_api) ret = pm_device_runtime_put_async(test_dev, K_NO_WAIT); zassert_equal(ret, 0); - (void)pm_device_state_get(test_dev, &state); - zassert_equal(state, PM_DEVICE_STATE_SUSPENDING); - - /* usage: 0, -1, suspend: no (unbalanced call) */ - ret = pm_device_runtime_put(test_dev); - zassert_equal(ret, -EALREADY); - - /* usage: 0, -1, suspend: no (unbalanced call) */ - ret = pm_device_runtime_put_async(test_dev, K_NO_WAIT); - zassert_equal(ret, -EALREADY); + if (IS_ENABLED(CONFIG_TEST_PM_DEVICE_ISR_SAFE)) { + /* In sync mode async put is equivalent as normal put. */ + (void)pm_device_state_get(test_dev, &state); + zassert_equal(state, PM_DEVICE_STATE_SUSPENDED); + } else { + (void)pm_device_state_get(test_dev, &state); + zassert_equal(state, PM_DEVICE_STATE_SUSPENDING); + + /* usage: 0, -1, suspend: no (unbalanced call) */ + ret = pm_device_runtime_put(test_dev); + zassert_equal(ret, -EALREADY); + + /* usage: 0, -1, suspend: no (unbalanced call) */ + ret = pm_device_runtime_put_async(test_dev, K_NO_WAIT); + zassert_equal(ret, -EALREADY); + + /* unblock test driver and let it finish */ + test_driver_pm_done(test_dev); + k_yield(); - /* unblock test driver and let it finish */ - test_driver_pm_done(test_dev); - k_yield(); + (void)pm_device_state_get(test_dev, &state); + zassert_equal(state, PM_DEVICE_STATE_SUSPENDED); - (void)pm_device_state_get(test_dev, &state); - zassert_equal(state, PM_DEVICE_STATE_SUSPENDED); + /*** get + asynchronous put + get (while suspend still ongoing) ***/ - /*** get + asynchronous put + get (while suspend still ongoing) ***/ + /* usage: 0, +1, resume: yes */ + ret = pm_device_runtime_get(test_dev); + zassert_equal(ret, 0); - /* usage: 0, +1, resume: yes */ - ret = pm_device_runtime_get(test_dev); - zassert_equal(ret, 0); + (void)pm_device_state_get(test_dev, &state); + zassert_equal(state, PM_DEVICE_STATE_ACTIVE); - (void)pm_device_state_get(test_dev, &state); - zassert_equal(state, PM_DEVICE_STATE_ACTIVE); + test_driver_pm_async(test_dev); - test_driver_pm_async(test_dev); + /* usage: 1, -1, suspend: yes (queued) */ + ret = pm_device_runtime_put_async(test_dev, K_NO_WAIT); + zassert_equal(ret, 0); - /* usage: 1, -1, suspend: yes (queued) */ - ret = pm_device_runtime_put_async(test_dev, K_NO_WAIT); - zassert_equal(ret, 0); + (void)pm_device_state_get(test_dev, &state); + zassert_equal(state, PM_DEVICE_STATE_SUSPENDING); - (void)pm_device_state_get(test_dev, &state); - zassert_equal(state, PM_DEVICE_STATE_SUSPENDING); + /* let suspension start */ + k_yield(); - /* let suspension start */ - k_yield(); + /* create and start get_runner thread + * get_runner thread is used to test synchronous path while asynchronous + * is ongoing. It is important to set its priority >= to the system work + * queue to make sure sync path run by the thread is forced to wait. + */ + k_thread_create(&get_runner_td, get_runner_stack, + K_THREAD_STACK_SIZEOF(get_runner_stack), get_runner, + NULL, NULL, NULL, CONFIG_SYSTEM_WORKQUEUE_PRIORITY, 0, + K_NO_WAIT); + k_yield(); - /* create and start get_runner thread - * get_runner thread is used to test synchronous path while asynchronous - * is ongoing. It is important to set its priority >= to the system work - * queue to make sure sync path run by the thread is forced to wait. - */ - k_thread_create(&get_runner_td, get_runner_stack, - K_THREAD_STACK_SIZEOF(get_runner_stack), get_runner, - NULL, NULL, NULL, CONFIG_SYSTEM_WORKQUEUE_PRIORITY, 0, - K_NO_WAIT); - k_yield(); - - /* let driver suspend to finish and wait until get_runner finishes - * resuming the driver - */ - test_driver_pm_done(test_dev); - k_thread_join(&get_runner_td, K_FOREVER); + /* let driver suspend to finish and wait until get_runner finishes + * resuming the driver + */ + test_driver_pm_done(test_dev); + k_thread_join(&get_runner_td, K_FOREVER); - (void)pm_device_state_get(test_dev, &state); - zassert_equal(state, PM_DEVICE_STATE_ACTIVE); + (void)pm_device_state_get(test_dev, &state); + zassert_equal(state, PM_DEVICE_STATE_ACTIVE); - /* Test if getting a device before an async operation starts does - * not trigger any device pm action. - */ - size_t count = test_driver_pm_count(test_dev); + /* Test if getting a device before an async operation starts does + * not trigger any device pm action. + */ + size_t count = test_driver_pm_count(test_dev); - ret = pm_device_runtime_put_async(test_dev, K_MSEC(10)); - zassert_equal(ret, 0); + ret = pm_device_runtime_put_async(test_dev, K_MSEC(10)); + zassert_equal(ret, 0); - (void)pm_device_state_get(test_dev, &state); - zassert_equal(state, PM_DEVICE_STATE_SUSPENDING); + (void)pm_device_state_get(test_dev, &state); + zassert_equal(state, PM_DEVICE_STATE_SUSPENDING); - ret = pm_device_runtime_get(test_dev); - zassert_equal(ret, 0); + ret = pm_device_runtime_get(test_dev); + zassert_equal(ret, 0); - /* Now lets check if the calls above have triggered a device - * pm action - */ - zassert_equal(count, test_driver_pm_count(test_dev)); + /* Now lets check if the calls above have triggered a device + * pm action + */ + zassert_equal(count, test_driver_pm_count(test_dev)); - /* - * test if async put with a delay respects the given time. - */ - ret = pm_device_runtime_put_async(test_dev, K_MSEC(100)); + /* + * test if async put with a delay respects the given time. + */ + ret = pm_device_runtime_put_async(test_dev, K_MSEC(100)); - (void)pm_device_state_get(test_dev, &state); - zassert_equal(state, PM_DEVICE_STATE_SUSPENDING); + (void)pm_device_state_get(test_dev, &state); + zassert_equal(state, PM_DEVICE_STATE_SUSPENDING); - k_sleep(K_MSEC(80)); + k_sleep(K_MSEC(80)); - /* It should still be suspending since we have waited less than - * the delay we've set. - */ - (void)pm_device_state_get(test_dev, &state); - zassert_equal(state, PM_DEVICE_STATE_SUSPENDING); + /* It should still be suspending since we have waited less than + * the delay we've set. + */ + (void)pm_device_state_get(test_dev, &state); + zassert_equal(state, PM_DEVICE_STATE_SUSPENDING); - k_sleep(K_MSEC(30)); + k_sleep(K_MSEC(30)); - /* Now it should be already suspended */ - (void)pm_device_state_get(test_dev, &state); - zassert_equal(state, PM_DEVICE_STATE_SUSPENDED); + /* Now it should be already suspended */ + (void)pm_device_state_get(test_dev, &state); + zassert_equal(state, PM_DEVICE_STATE_SUSPENDED); + } /* Put operation should fail due the state be locked. */ ret = pm_device_runtime_disable(test_dev); diff --git a/tests/subsys/pm/device_runtime_api/src/test_driver.c b/tests/subsys/pm/device_runtime_api/src/test_driver.c index d7c06f9cddb..957351167b9 100644 --- a/tests/subsys/pm/device_runtime_api/src/test_driver.c +++ b/tests/subsys/pm/device_runtime_api/src/test_driver.c @@ -21,14 +21,16 @@ static int test_driver_action(const struct device *dev, { struct test_driver_data *data = dev->data; - data->ongoing = true; + if (!IS_ENABLED(CONFIG_TEST_PM_DEVICE_ISR_SAFE)) { + data->ongoing = true; - if (data->async) { - k_sem_take(&data->sync, K_FOREVER); - data->async = false; - } + if (data->async) { + k_sem_take(&data->sync, K_FOREVER); + data->async = false; + } - data->ongoing = false; + data->ongoing = false; + } data->count++; @@ -72,7 +74,11 @@ int test_driver_init(const struct device *dev) return 0; } +#if CONFIG_TEST_PM_DEVICE_ISR_SAFE +PM_DEVICE_ISR_SAFE_DEFINE(test_driver, test_driver_action); +#else PM_DEVICE_DEFINE(test_driver, test_driver_action); +#endif static struct test_driver_data data; diff --git a/tests/subsys/pm/device_runtime_api/testcase.yaml b/tests/subsys/pm/device_runtime_api/testcase.yaml index 72c9c512942..d86f1ba95d8 100644 --- a/tests/subsys/pm/device_runtime_api/testcase.yaml +++ b/tests/subsys/pm/device_runtime_api/testcase.yaml @@ -3,3 +3,9 @@ tests: tags: pm integration_platforms: - native_sim + pm.device_runtime.isr_safe.api: + tags: pm + integration_platforms: + - native_sim + extra_configs: + - CONFIG_TEST_PM_DEVICE_ISR_SAFE=y From ee13631362ded9e1abc61ef483c5532423f4e806 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Krzysztof=20Chru=C5=9Bci=C5=84ski?= Date: Mon, 29 Jan 2024 09:04:03 +0100 Subject: [PATCH 3304/3723] pm: device_runtime: Extend existing API with ISR_SAFE mode MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Extend macros from creating a PM device with an optional argument which indicate whether type of device is ISR_SAFE or not. Signed-off-by: Krzysztof Chruściński --- include/zephyr/pm/device.h | 86 +++++-------------- .../pm/device_runtime_api/src/test_driver.c | 8 +- 2 files changed, 25 insertions(+), 69 deletions(-) diff --git a/include/zephyr/pm/device.h b/include/zephyr/pm/device.h index d34a84c3911..5b6cf0cb33c 100644 --- a/include/zephyr/pm/device.h +++ b/include/zephyr/pm/device.h @@ -56,6 +56,16 @@ enum pm_device_flag { /** @endcond */ +/** @brief Flag indicating that runtime PM API for the device can be called from any context. + * + * If @ref PM_DEVICE_ISR_SAFE flag is used for device definition, it indicates that PM actions + * are synchronous and can be executed from any context. This approach can be used for cases where + * suspending and resuming is short as it is executed in the critical section. This mode requires + * less resources (~80 byte less RAM) and allows to use device runtime PM from any context + * (including interrupts). + */ +#define PM_DEVICE_ISR_SAFE 1 + /** @brief Device power states. */ enum pm_device_state { /** Device is in active or regular state. */ @@ -315,61 +325,28 @@ BUILD_ASSERT(offsetof(struct pm_device_isr, base) == 0); * * @param dev_id Device id. * @param pm_action_cb PM control callback. + * @param ... Optional flag to indicate that ISR safe. Use @ref PM_DEVICE_ISR_SAFE or 0. * * @see #PM_DEVICE_DT_DEFINE, #PM_DEVICE_DT_INST_DEFINE */ -#define PM_DEVICE_DEFINE(dev_id, pm_action_cb) \ - Z_PM_DEVICE_DEFINE(DT_INVALID_NODE, dev_id, pm_action_cb, 0) - -/** - * Define device PM resources for the given device name. - * - * PM actions are synchronous and can be executed from any context. This approach - * can be used for cases where suspending and resuming is short as it is - * executed in the critical section. This mode requires less resources (~80 byte - * less RAM) and allows to use device runtime PM from any context (including - * interrupts). - * - * @note This macro is a no-op if @kconfig{CONFIG_PM_DEVICE} is not enabled. - * - * @param dev_id Device id. - * @param pm_action_cb PM control callback. - * - * @see #PM_DEVICE_DT_DEFINE, #PM_DEVICE_DT_INST_DEFINE - */ -#define PM_DEVICE_ISR_SYNC_DEFINE(dev_id, pm_action_cb) \ - Z_PM_DEVICE_DEFINE(DT_INVALID_NODE, dev_id, pm_action_cb, 1) -/** - * Define device PM resources for the given node identifier. - * - * @note This macro is a no-op if @kconfig{CONFIG_PM_DEVICE} is not enabled. - * - * @param node_id Node identifier. - * @param pm_action_cb PM control callback. - * - * @see #PM_DEVICE_DT_INST_DEFINE, #PM_DEVICE_DEFINE - */ -#define PM_DEVICE_DT_DEFINE(node_id, pm_action_cb) \ - Z_PM_DEVICE_DEFINE(node_id, Z_DEVICE_DT_DEV_ID(node_id), pm_action_cb, 0) +#define PM_DEVICE_DEFINE(dev_id, pm_action_cb, ...) \ + Z_PM_DEVICE_DEFINE(DT_INVALID_NODE, dev_id, pm_action_cb, \ + COND_CODE_1(IS_EMPTY(__VA_ARGS__), (0), (__VA_ARGS__))) /** * Define device PM resources for the given node identifier. * - * PM actions are synchronous and can be executed from any context. This approach - * can be used for cases where suspending and resuming is short as it is - * executed in the critical section. This mode requires less resources (~80 byte - * less RAM) and allows to use device runtime PM from any context (including - * interrupts). - * * @note This macro is a no-op if @kconfig{CONFIG_PM_DEVICE} is not enabled. * * @param node_id Node identifier. * @param pm_action_cb PM control callback. + * @param ... Optional flag to indicate that device is isr_ok. Use @ref PM_DEVICE_ISR_SAFE or 0. * * @see #PM_DEVICE_DT_INST_DEFINE, #PM_DEVICE_DEFINE */ -#define PM_DEVICE_ISR_SAFE_DT_DEFINE(node_id, pm_action_cb) \ - Z_PM_DEVICE_DEFINE(node_id, Z_DEVICE_DT_DEV_ID(node_id), pm_action_cb, 1) +#define PM_DEVICE_DT_DEFINE(node_id, pm_action_cb, ...) \ + Z_PM_DEVICE_DEFINE(node_id, Z_DEVICE_DT_DEV_ID(node_id), pm_action_cb, \ + COND_CODE_1(IS_EMPTY(__VA_ARGS__), (0), (__VA_ARGS__))) /** * Define device PM resources for the given instance. @@ -378,34 +355,15 @@ BUILD_ASSERT(offsetof(struct pm_device_isr, base) == 0); * * @param idx Instance index. * @param pm_action_cb PM control callback. + * @param ... Optional flag to indicate that device is isr_ok. Use @ref PM_DEVICE_ISR_SAFE or 0. * * @see #PM_DEVICE_DT_DEFINE, #PM_DEVICE_DEFINE */ -#define PM_DEVICE_DT_INST_DEFINE(idx, pm_action_cb) \ +#define PM_DEVICE_DT_INST_DEFINE(idx, pm_action_cb, ...) \ Z_PM_DEVICE_DEFINE(DT_DRV_INST(idx), \ Z_DEVICE_DT_DEV_ID(DT_DRV_INST(idx)), \ - pm_action_cb, 0) - -/** - * Define device PM resources for the given instance. - * - * PM actions are synchronous and can be executed from any context. This approach - * can be used for cases where suspending and resuming is short as it is - * executed in the critical section. This mode requires less resources (~80 byte - * less RAM) and allows to use device runtime PM from any context (including - * interrupts). - * - * @note This macro is a no-op if @kconfig{CONFIG_PM_DEVICE} is not enabled. - * - * @param idx Instance index. - * @param pm_action_cb PM control callback. - * - * @see #PM_DEVICE_DT_DEFINE, #PM_DEVICE_DEFINE - */ -#define PM_DEVICE_ISR_SAFE_DT_INST_DEFINE(idx, pm_action_cb) \ - Z_PM_DEVICE_DEFINE(DT_DRV_INST(idx), \ - Z_DEVICE_DT_DEV_ID(DT_DRV_INST(idx)), \ - pm_action_cb, 1) + pm_action_cb, \ + COND_CODE_1(IS_EMPTY(__VA_ARGS__), (0), (__VA_ARGS__))) /** * @brief Obtain a reference to the device PM resources for the given device. diff --git a/tests/subsys/pm/device_runtime_api/src/test_driver.c b/tests/subsys/pm/device_runtime_api/src/test_driver.c index 957351167b9..48dd4385cbc 100644 --- a/tests/subsys/pm/device_runtime_api/src/test_driver.c +++ b/tests/subsys/pm/device_runtime_api/src/test_driver.c @@ -74,11 +74,9 @@ int test_driver_init(const struct device *dev) return 0; } -#if CONFIG_TEST_PM_DEVICE_ISR_SAFE -PM_DEVICE_ISR_SAFE_DEFINE(test_driver, test_driver_action); -#else -PM_DEVICE_DEFINE(test_driver, test_driver_action); -#endif +#define PM_DEVICE_TYPE COND_CODE_1(CONFIG_TEST_PM_DEVICE_ISR_SAFE, (PM_DEVICE_ISR_SAFE), (0)) + +PM_DEVICE_DEFINE(test_driver, test_driver_action, PM_DEVICE_TYPE); static struct test_driver_data data; From 31de122ec0fcb3d9227058a6fe95cd99e8396e9d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tomasz=20Mo=C5=84?= Date: Fri, 8 Dec 2023 13:04:44 +0100 Subject: [PATCH 3305/3723] usb: device_next: broadcast SOF to classes MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Start of Frame is not relevant for most classes, but it is crucial for isochronous operation. The most prominent example where SOF is necessary is USB Audio class. Signed-off-by: Tomasz Moń --- include/zephyr/usb/usbd.h | 3 +++ subsys/usb/device_next/usbd_class_api.h | 16 ++++++++++++++++ subsys/usb/device_next/usbd_core.c | 3 +++ 3 files changed, 22 insertions(+) diff --git a/include/zephyr/usb/usbd.h b/include/zephyr/usb/usbd.h index 28d27f10723..7d9798b90fb 100644 --- a/include/zephyr/usb/usbd.h +++ b/include/zephyr/usb/usbd.h @@ -226,6 +226,9 @@ struct usbd_class_api { /** USB power management handler resumed */ void (*resumed)(struct usbd_class_node *const node); + /** Start of Frame */ + void (*sof)(struct usbd_class_node *const node); + /** Class associated configuration is selected */ void (*enable)(struct usbd_class_node *const node); diff --git a/subsys/usb/device_next/usbd_class_api.h b/subsys/usb/device_next/usbd_class_api.h index ccff5243cac..7fa95d69feb 100644 --- a/subsys/usb/device_next/usbd_class_api.h +++ b/subsys/usb/device_next/usbd_class_api.h @@ -189,6 +189,22 @@ static inline void usbd_class_resumed(struct usbd_class_node *const node) } } +/** + * @brief USB Start of Frame handler + * + * @note The execution of the handler must not block. + * + * @param[in] node Pointer to USB device class node + */ +static inline void usbd_class_sof(struct usbd_class_node *const node) +{ + const struct usbd_class_api *api = node->api; + + if (api->sof != NULL) { + api->sof(node); + } +} + /** * @brief Class associated configuration active handler * diff --git a/subsys/usb/device_next/usbd_core.c b/subsys/usb/device_next/usbd_core.c index 655f86cb4b2..d7f483036a5 100644 --- a/subsys/usb/device_next/usbd_core.c +++ b/subsys/usb/device_next/usbd_core.c @@ -84,6 +84,9 @@ static void usbd_class_bcast_event(struct usbd_contex *const uds_ctx, case UDC_EVT_RESUME: usbd_class_resumed(c_nd); break; + case UDC_EVT_SOF: + usbd_class_sof(c_nd); + break; default: break; } From c83ad53442723a7412e8ae060f5d8bdf142f0274 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tomasz=20Mo=C5=84?= Date: Wed, 6 Dec 2023 09:44:06 +0100 Subject: [PATCH 3306/3723] usb: device_next: new USB Audio 2 implementation MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Introduce new USB Audio 2 implementation written from scratch. Main goal behind new implementation was to perform entity configuration with devicetree bindings, hiding the descriptor complexity from application. Initial implementation is working at Full-Speed only. High-Speed support will come later, but even at Full-Speed only this is viable replacement for old stack USB Audio 1 class (USB Audio 1 is limited to Full-Speed by specification, i.e. it is explicitly forbidden for USB Audio 1 device to work at High-Speed). Implemented is only absolute minimum set of features required for basic implicit and explicit feedback samples. Only one sample frequency is currently supported. Optional interrupt notifications are not supported. Signed-off-by: Tomasz Moń --- include/zephyr/usb/class/usbd_uac2.h | 139 +++ samples/subsys/usb/common/sample_usbd_init.c | 3 +- subsys/usb/device_next/CMakeLists.txt | 5 + subsys/usb/device_next/class/Kconfig | 1 + subsys/usb/device_next/class/Kconfig.uac2 | 16 + subsys/usb/device_next/class/usbd_uac2.c | 800 ++++++++++++++++++ .../usb/device_next/class/usbd_uac2_macros.h | 11 + 7 files changed, 974 insertions(+), 1 deletion(-) create mode 100644 include/zephyr/usb/class/usbd_uac2.h create mode 100644 subsys/usb/device_next/class/Kconfig.uac2 create mode 100644 subsys/usb/device_next/class/usbd_uac2.c diff --git a/include/zephyr/usb/class/usbd_uac2.h b/include/zephyr/usb/class/usbd_uac2.h new file mode 100644 index 00000000000..477f8465266 --- /dev/null +++ b/include/zephyr/usb/class/usbd_uac2.h @@ -0,0 +1,139 @@ +/* + * Copyright (c) 2023-2024 Nordic Semiconductor ASA + * + * SPDX-License-Identifier: Apache-2.0 + */ + +/** + * @file + * @brief USB Audio Class 2 device public header + * + * This header describes only class API interaction with application. + * The audio device itself is modelled with devicetree zephyr,uac2 compatible. + * + * This API is currently considered experimental. + */ + +#ifndef ZEPHYR_INCLUDE_USB_CLASS_USBD_UAC2_H_ +#define ZEPHYR_INCLUDE_USB_CLASS_USBD_UAC2_H_ + +#include + +#define UAC2_ENTITY_ID(node) \ + ({ \ + BUILD_ASSERT(DT_NODE_HAS_COMPAT(DT_PARENT(node), zephyr_uac2)); \ + UTIL_INC(DT_NODE_CHILD_IDX(node)); \ + }) + +/** + * @brief USB Audio 2 application event handlers + */ +struct uac2_ops { + /** + * @brief Start of Frame callback + * + * Notifies application about SOF event on the bus. + * + * @param dev USB Audio 2 device + * @param user_data Opaque user data pointer + */ + void (*sof_cb)(const struct device *dev, void *user_data); + /** + * @brief Terminal update callback + * + * Notifies application that host has enabled or disabled a terminal. + * + * @param dev USB Audio 2 device + * @param terminal Terminal ID linked to AudioStreaming interface + * @param enabled True if host enabled terminal, False otherwise + * @param microframes True if USB connection speed uses microframes + * @param user_data Opaque user data pointer + */ + void (*terminal_update_cb)(const struct device *dev, uint8_t terminal, + bool enabled, bool microframes, + void *user_data); + /** + * @brief Get receive buffer address + * + * USB stack calls this function to obtain receive buffer address for + * AudioStreaming interface. The buffer is owned by USB stack until + * @ref data_recv_cb callback is called. The buffer must be sufficiently + * aligned for use by UDC driver. + * + * @param dev USB Audio 2 device + * @param terminal Input Terminal ID linked to AudioStreaming interface + * @param size Maximum number of bytes USB stack will write to buffer. + * @param user_data Opaque user data pointer + */ + void *(*get_recv_buf)(const struct device *dev, uint8_t terminal, + uint16_t size, void *user_data); + /** + * @brief Data received + * + * This function releases buffer obtained in @ref get_recv_buf after USB + * has written data to the buffer and/or no longer needs it. + * + * @param dev USB Audio 2 device + * @param terminal Input Terminal ID linked to AudioStreaming interface + * @param buf Buffer previously obtained via @ref get_recv_buf + * @param size Number of bytes written to buffer + * @param user_data Opaque user data pointer + */ + void (*data_recv_cb)(const struct device *dev, uint8_t terminal, + void *buf, uint16_t size, void *user_data); + /** + * @brief Transmit buffer release callback + * + * This function releases buffer provided in @ref usbd_uac2_send when + * the class no longer needs it. + * + * @param dev USB Audio 2 device + * @param terminal Output Terminal ID linked to AudioStreaming interface + * @param buf Buffer previously provided via @ref usbd_uac2_send + * @param user_data Opaque user data pointer + */ + void (*buf_release_cb)(const struct device *dev, uint8_t terminal, + void *buf, void *user_data); + /** + * @brief Get Explicit Feedback value + * + * Explicit feedback value format depends terminal connection speed. + * If device is High-Speed capable, it must use Q16.16 format if and + * only if the @ref terminal_update_cb was called with microframes + * parameter set to true. On Full-Speed only devices, or if High-Speed + * capable device is operating at Full-Speed (microframes was false), + * the format is Q10.14 stored on 24 least significant bits (i.e. 8 most + * significant bits are ignored). + * + * @param dev USB Audio 2 device + * @param terminal Input Terminal ID whose feedback should be returned + * @param user_data Opaque user data pointer + */ + uint32_t (*feedback_cb)(const struct device *dev, uint8_t terminal, + void *user_data); +}; + +/** + * @brief Register USB Audio 2 application callbacks. + * + * @param dev USB Audio 2 device instance + * @param ops USB Audio 2 callback structure + * @param user_data Opaque user data to pass to ops callbacks + */ +void usbd_uac2_set_ops(const struct device *dev, + const struct uac2_ops *ops, void *user_data); + +/** + * @brief Send audio data to output terminal + * + * @param dev USB Audio 2 device + * @param terminal Output Terminal ID linked to AudioStreaming interface + * @param data Buffer containing outgoing data + * @param size Number of bytes to send + * + * @return 0 on success, negative value on error + */ +int usbd_uac2_send(const struct device *dev, uint8_t terminal, + void *data, uint16_t size); + +#endif /* ZEPHYR_INCLUDE_USB_CLASS_USBD_UAC2_H_ */ diff --git a/samples/subsys/usb/common/sample_usbd_init.c b/samples/subsys/usb/common/sample_usbd_init.c index ce4d5ce7fc9..75809b06d30 100644 --- a/samples/subsys/usb/common/sample_usbd_init.c +++ b/samples/subsys/usb/common/sample_usbd_init.c @@ -80,7 +80,8 @@ struct usbd_contex *sample_usbd_init_device(void) /* Always use class code information from Interface Descriptors */ if (IS_ENABLED(CONFIG_USBD_CDC_ACM_CLASS) || - IS_ENABLED(CONFIG_USBD_CDC_ECM_CLASS)) { + IS_ENABLED(CONFIG_USBD_CDC_ECM_CLASS) || + IS_ENABLED(CONFIG_USBD_AUDIO2_CLASS)) { /* * Class with multiple interfaces have an Interface * Association Descriptor available, use an appropriate triple diff --git a/subsys/usb/device_next/CMakeLists.txt b/subsys/usb/device_next/CMakeLists.txt index 426e3a23a60..3b87af1de6e 100644 --- a/subsys/usb/device_next/CMakeLists.txt +++ b/subsys/usb/device_next/CMakeLists.txt @@ -56,4 +56,9 @@ zephyr_linker_sources_ifdef( SECTIONS class/usbd_msc.ld ) +zephyr_library_sources_ifdef( + CONFIG_USBD_AUDIO2_CLASS + class/usbd_uac2.c +) + zephyr_linker_sources(DATA_SECTIONS usbd_data.ld) diff --git a/subsys/usb/device_next/class/Kconfig b/subsys/usb/device_next/class/Kconfig index 51141aa1dc6..19fe3cceb8c 100644 --- a/subsys/usb/device_next/class/Kconfig +++ b/subsys/usb/device_next/class/Kconfig @@ -7,3 +7,4 @@ rsource "Kconfig.cdc_acm" rsource "Kconfig.cdc_ecm" rsource "Kconfig.bt" rsource "Kconfig.msc" +rsource "Kconfig.uac2" diff --git a/subsys/usb/device_next/class/Kconfig.uac2 b/subsys/usb/device_next/class/Kconfig.uac2 new file mode 100644 index 00000000000..ad6fb54b38a --- /dev/null +++ b/subsys/usb/device_next/class/Kconfig.uac2 @@ -0,0 +1,16 @@ +# Copyright (c) 2022 Nordic Semiconductor ASA +# +# SPDX-License-Identifier: Apache-2.0 + +config USBD_AUDIO2_CLASS + bool "USB Audio 2 class support [EXPERIMENTAL]" + help + USB Audio 2 device class support. + +if USBD_AUDIO2_CLASS + +module = USBD_UAC2 +module-str = usbd uac2 +source "subsys/logging/Kconfig.template.log_config" + +endif diff --git a/subsys/usb/device_next/class/usbd_uac2.c b/subsys/usb/device_next/class/usbd_uac2.c new file mode 100644 index 00000000000..b04ac2e7f14 --- /dev/null +++ b/subsys/usb/device_next/class/usbd_uac2.c @@ -0,0 +1,800 @@ +/* + * Copyright (c) 2023-2024 Nordic Semiconductor ASA + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include +#include +#include + +#include +#include +#include +#include + +#include "usbd_uac2_macros.h" + +#include +LOG_MODULE_REGISTER(usbd_uac2, CONFIG_USBD_UAC2_LOG_LEVEL); + +#define DT_DRV_COMPAT zephyr_uac2 + +#define COUNT_UAC2_AS_ENDPOINTS(node) \ + IF_ENABLED(DT_NODE_HAS_COMPAT(node, zephyr_uac2_audio_streaming), ( \ + + AS_HAS_ISOCHRONOUS_DATA_ENDPOINT(node) + \ + AS_HAS_EXPLICIT_FEEDBACK_ENDPOINT(node))) +#define COUNT_UAC2_ENDPOINTS(i) \ + + DT_PROP(DT_DRV_INST(i), interrupt_endpoint) \ + DT_INST_FOREACH_CHILD(i, COUNT_UAC2_AS_ENDPOINTS) +#define UAC2_NUM_ENDPOINTS DT_INST_FOREACH_STATUS_OKAY(COUNT_UAC2_ENDPOINTS) + +/* Net buf is used mostly with external data. The main reason behind external + * data is avoiding unnecessary isochronous data copy operations. + * + * Allow up to 6 bytes per item to facilitate optional interrupt endpoint (which + * requires 6 bytes) and feedback endpoint (4 bytes on High-Speed, 3 bytes on + * Full-Speed). Because the total number of endpoints is really small (typically + * there will be just 2 isochronous endpoints; the upper bound originating from + * the USB specification itself is 30 non-control endpoints). Therefore, the + * "wasted memory" here is likely to be smaller than the memory overhead for + * more complex "only as much as needed" schemes (e.g. heap). + */ +NET_BUF_POOL_DEFINE(uac2_pool, UAC2_NUM_ENDPOINTS, 6, + sizeof(struct udc_buf_info), NULL); + +/* 5.2.2 Control Request Layout */ +#define SET_CLASS_REQUEST_TYPE 0x21 +#define GET_CLASS_REQUEST_TYPE 0xA1 + +/* A.14 Audio Class-Specific Request Codes */ +#define CUR 0x01 +#define RANGE 0x02 +#define MEM 0x03 + +/* A.17.1 Clock Source Control Selectors */ +#define CS_SAM_FREQ_CONTROL 0x01 +#define CS_CLOCK_VALID_CONTROL 0x02 + +#define CONTROL_ATTRIBUTE(setup) (setup->bRequest) +#define CONTROL_ENTITY_ID(setup) ((setup->wIndex & 0xFF00) >> 8) +#define CONTROL_SELECTOR(setup) ((setup->wValue & 0xFF00) >> 8) +#define CONTROL_CHANNEL_NUMBER(setup) (setup->wValue & 0x00FF) + +typedef enum { + ENTITY_TYPE_INVALID, + ENTITY_TYPE_CLOCK_SOURCE, + ENTITY_TYPE_INPUT_TERMINAL, + ENTITY_TYPE_OUTPUT_TERMINAL, +} entity_type_t; + +static size_t clock_frequencies(struct usbd_class_node *const node, + const uint8_t id, const uint32_t **frequencies); + +/* UAC2 device runtime data */ +struct uac2_ctx { + const struct uac2_ops *ops; + void *user_data; + /* Bit set indicates the AudioStreaming interface has non-zero bandwidth + * alternate setting active. + */ + atomic_t as_active; + atomic_t as_queued; + uint32_t fb_queued; +}; + +/* UAC2 device constant data */ +struct uac2_cfg { + struct usbd_class_node *const node; + /* Entity 1 type is at entity_types[0] */ + const entity_type_t *entity_types; + /* Array of offsets to data endpoint bEndpointAddress in descriptors. + * First AudioStreaming interface is at ep_offsets[0]. Offset is 0 if + * the interface is external interface (Type IV), i.e. no endpoint. + */ + const uint16_t *ep_offsets; + /* Same as ep_offsets, but for explicit feedback endpoints. */ + const uint16_t *fb_offsets; + /* First AudioStreaming interface Terminal ID is at as_terminals[0]. */ + const uint8_t *as_terminals; + /* Number of interfaces (ep_offsets, fb_offset and as_terminals size) */ + uint8_t num_ifaces; + /* Number of entities (entity_type array size) */ + uint8_t num_entities; +}; + +static entity_type_t id_type(struct usbd_class_node *const node, uint8_t id) +{ + const struct device *dev = node->data->priv; + const struct uac2_cfg *cfg = dev->config; + + if ((id - 1) < cfg->num_entities) { + return cfg->entity_types[id - 1]; + } + + return ENTITY_TYPE_INVALID; +} + +static const struct usb_ep_descriptor * +get_as_data_ep(struct usbd_class_node *const node, int as_idx) +{ + const struct device *dev = node->data->priv; + const struct uac2_cfg *cfg = dev->config; + const uint8_t *desc = node->data->desc; + + if ((as_idx < cfg->num_ifaces) && cfg->ep_offsets[as_idx]) { + return CONTAINER_OF(&desc[cfg->ep_offsets[as_idx]], + const struct usb_ep_descriptor, + bEndpointAddress); + } + + return NULL; +} + +static const struct usb_ep_descriptor * +get_as_feedback_ep(struct usbd_class_node *const node, int as_idx) +{ + const struct device *dev = node->data->priv; + const struct uac2_cfg *cfg = dev->config; + const uint8_t *desc = node->data->desc; + + if ((as_idx < cfg->num_ifaces) && cfg->fb_offsets[as_idx]) { + return CONTAINER_OF(&desc[cfg->fb_offsets[as_idx]], + const struct usb_ep_descriptor, + bEndpointAddress); + } + + return NULL; +} + +static int ep_to_as_interface(const struct device *dev, uint8_t ep, bool *fb) +{ + const struct uac2_cfg *cfg = dev->config; + const uint8_t *desc = cfg->node->data->desc; + + for (int i = 0; i < cfg->num_ifaces; i++) { + if (!cfg->ep_offsets[i]) { + /* If there is no data endpoint there cannot be feedback + * endpoint. Simply skip external interfaces. + */ + continue; + } + + if (ep == desc[cfg->ep_offsets[i]]) { + *fb = false; + return i; + } + + if (cfg->fb_offsets[i] && (ep == desc[cfg->fb_offsets[i]])) { + *fb = true; + return i; + } + } + + *fb = false; + return -ENOENT; +} + +static int terminal_to_as_interface(const struct device *dev, uint8_t terminal) +{ + const struct uac2_cfg *cfg = dev->config; + + for (int as_idx = 0; as_idx < cfg->num_ifaces; as_idx++) { + if (terminal == cfg->as_terminals[as_idx]) { + return as_idx; + } + } + + return -ENOENT; +} + +void usbd_uac2_set_ops(const struct device *dev, + const struct uac2_ops *ops, void *user_data) +{ + struct uac2_ctx *ctx = dev->data; + + __ASSERT(ops->sof_cb, "SOF callback is mandatory"); + + ctx->ops = ops; + ctx->user_data = user_data; +} + +static struct net_buf * +uac2_buf_alloc(const uint8_t ep, void *data, uint16_t size) +{ + struct net_buf *buf = NULL; + struct udc_buf_info *bi; + + buf = net_buf_alloc_with_data(&uac2_pool, data, size, K_NO_WAIT); + if (!buf) { + return NULL; + } + + bi = udc_get_buf_info(buf); + memset(bi, 0, sizeof(struct udc_buf_info)); + bi->ep = ep; + + if (USB_EP_DIR_IS_OUT(ep)) { + /* Buffer is empty, USB stack will write data from host */ + buf->len = 0; + } + + return buf; +} + +int usbd_uac2_send(const struct device *dev, uint8_t terminal, + void *data, uint16_t size) +{ + const struct uac2_cfg *cfg = dev->config; + const uint8_t *desc = cfg->node->data->desc; + struct uac2_ctx *ctx = dev->data; + struct net_buf *buf; + uint8_t ep = 0; + int as_idx = terminal_to_as_interface(dev, terminal); + int ret; + + if ((as_idx >= 0) && cfg->ep_offsets[as_idx]) { + ep = desc[cfg->ep_offsets[as_idx]]; + } + + if (!ep) { + LOG_ERR("No endpoint for terminal %d", terminal); + return -ENOENT; + } + + if (!atomic_test_bit(&ctx->as_active, as_idx)) { + /* Host is not interested in the data */ + ctx->ops->buf_release_cb(dev, terminal, data, ctx->user_data); + return 0; + } + + if (atomic_test_and_set_bit(&ctx->as_queued, as_idx)) { + LOG_ERR("Previous send not finished yet on 0x%02x", ep); + return -EAGAIN; + } + + buf = uac2_buf_alloc(ep, data, size); + if (!buf) { + /* This shouldn't really happen because netbuf should be large + * enough, but if it does all we loose is just single packet. + */ + LOG_ERR("No netbuf for send"); + atomic_clear_bit(&ctx->as_queued, as_idx); + ctx->ops->buf_release_cb(dev, terminal, data, ctx->user_data); + return -ENOMEM; + } + + ret = usbd_ep_enqueue(cfg->node, buf); + if (ret) { + LOG_ERR("Failed to enqueue net_buf for 0x%02x", ep); + net_buf_unref(buf); + atomic_clear_bit(&ctx->as_queued, as_idx); + ctx->ops->buf_release_cb(dev, terminal, data, ctx->user_data); + } + + return ret; +} + +static void schedule_iso_out_read(struct usbd_class_node *const node, + uint8_t ep, uint16_t mps, uint8_t terminal) +{ + struct device *dev = node->data->priv; + const struct uac2_cfg *cfg = dev->config; + struct uac2_ctx *ctx = dev->data; + struct net_buf *buf; + void *data_buf; + int as_idx = terminal_to_as_interface(dev, terminal); + int ret; + + /* All calls to this function are internal to class, if terminal is not + * associated with interface there is a bug in class implementation. + */ + __ASSERT_NO_MSG((as_idx >= 0) && (as_idx < cfg->num_ifaces)); + /* Silence warning if asserts are not enabled */ + ARG_UNUSED(cfg); + + if (!((as_idx >= 0) && atomic_test_bit(&ctx->as_active, as_idx))) { + /* Host won't send data */ + return; + } + + if (atomic_test_and_set_bit(&ctx->as_queued, as_idx)) { + /* Transfer already queued - do not requeue */ + return; + } + + /* Prepare transfer to read audio OUT data from host */ + data_buf = ctx->ops->get_recv_buf(dev, terminal, mps, ctx->user_data); + if (!data_buf) { + LOG_ERR("No data buffer for terminal %d", terminal); + atomic_clear_bit(&ctx->as_queued, as_idx); + return; + } + + buf = uac2_buf_alloc(ep, data_buf, mps); + if (!buf) { + LOG_ERR("No netbuf for read"); + /* Netbuf pool should be large enough, but if for some reason + * we are out of netbuf, there's nothing better to do than to + * pass the buffer back to application. + */ + ctx->ops->data_recv_cb(dev, terminal, + data_buf, 0, ctx->user_data); + atomic_clear_bit(&ctx->as_queued, as_idx); + return; + } + + ret = usbd_ep_enqueue(node, buf); + if (ret) { + LOG_ERR("Failed to enqueue net_buf for 0x%02x", ep); + net_buf_unref(buf); + atomic_clear_bit(&ctx->as_queued, as_idx); + } +} + +static void write_explicit_feedback(struct usbd_class_node *const node, + uint8_t ep, uint8_t terminal) +{ + struct device *dev = node->data->priv; + struct uac2_ctx *ctx = dev->data; + struct net_buf *buf; + struct udc_buf_info *bi; + uint32_t fb_value; + int as_idx = terminal_to_as_interface(dev, terminal); + int ret; + + buf = net_buf_alloc(&uac2_pool, K_NO_WAIT); + if (!buf) { + LOG_ERR("No buf for feedback"); + return; + } + + bi = udc_get_buf_info(buf); + memset(bi, 0, sizeof(struct udc_buf_info)); + bi->ep = ep; + + fb_value = ctx->ops->feedback_cb(dev, terminal, ctx->user_data); + + /* REVISE: How to determine operating speed? Should we have separate + * class instances for high-speed and full-speed (because high-speed + * allows more sampling rates and/or bit depths)? + */ + if (udc_device_speed(node->data->uds_ctx->dev) == UDC_BUS_SPEED_FS) { + net_buf_add_le24(buf, fb_value); + } else { + net_buf_add_le32(buf, fb_value); + } + + ret = usbd_ep_enqueue(node, buf); + if (ret) { + LOG_ERR("Failed to enqueue net_buf for 0x%02x", ep); + net_buf_unref(buf); + } else { + ctx->fb_queued |= BIT(as_idx); + } +} + +void uac2_update(struct usbd_class_node *const node, + uint8_t iface, uint8_t alternate) +{ + struct device *dev = node->data->priv; + const struct uac2_cfg *cfg = dev->config; + struct uac2_ctx *ctx = dev->data; + const struct usb_association_descriptor *iad; + const struct usb_ep_descriptor *data_ep, *fb_ep; + uint8_t as_idx; + bool microframes; + + LOG_DBG("iface %d alt %d", iface, alternate); + + iad = (const struct usb_association_descriptor *)node->data->desc; + + /* AudioControl interface (bFirstInterface) doesn't have alternate + * configurations, therefore the iface must be AudioStreaming. + */ + __ASSERT_NO_MSG((iface > iad->bFirstInterface) && + (iface < iad->bFirstInterface + iad->bInterfaceCount)); + as_idx = iface - iad->bFirstInterface - 1; + + /* Audio class is forbidden on Low-Speed, therefore the only possibility + * for not using microframes is when device operates at Full-Speed. + */ + if (udc_device_speed(node->data->uds_ctx->dev) == UDC_BUS_SPEED_FS) { + microframes = false; + } else { + microframes = true; + } + + /* Notify application about terminal state change */ + ctx->ops->terminal_update_cb(dev, cfg->as_terminals[as_idx], alternate, + microframes, ctx->user_data); + + if (alternate == 0) { + /* Mark interface as inactive, any pending endpoint transfers + * were already cancelled by the USB stack. + */ + atomic_clear_bit(&ctx->as_active, as_idx); + return; + } + + atomic_set_bit(&ctx->as_active, as_idx); + + data_ep = get_as_data_ep(node, as_idx); + /* External interfaces (i.e. NULL data_ep) do not have alternate + * configuration and therefore data_ep must be valid here. + */ + __ASSERT_NO_MSG(data_ep); + + if (USB_EP_DIR_IS_OUT(data_ep->bEndpointAddress)) { + schedule_iso_out_read(node, data_ep->bEndpointAddress, + sys_le16_to_cpu(data_ep->wMaxPacketSize), + cfg->as_terminals[as_idx]); + + fb_ep = get_as_feedback_ep(node, as_idx); + if (fb_ep) { + write_explicit_feedback(node, fb_ep->bEndpointAddress, + cfg->as_terminals[as_idx]); + } + } +} + +/* Table 5-6: 4-byte Control CUR Parameter Block */ +static void layout3_cur_response(struct net_buf *const buf, uint16_t length, + const uint32_t value) +{ + uint8_t tmp[4]; + + /* dCUR */ + sys_put_le32(value, tmp); + net_buf_add_mem(buf, tmp, MIN(length, 4)); +} + +/* Table 5-7: 4-byte Control RANGE Parameter Block */ +static void layout3_range_response(struct net_buf *const buf, uint16_t length, + const uint32_t *min, const uint32_t *max, + const uint32_t *res, int n) +{ + uint16_t to_add; + uint8_t tmp[4]; + int i; + int item; + + /* wNumSubRanges */ + sys_put_le16(n, tmp); + to_add = MIN(length, 2); + net_buf_add_mem(buf, tmp, to_add); + length -= to_add; + + /* Keep adding dMIN, dMAX, dRES as long as we have entries to add and + * we didn't reach wLength response limit. + */ + i = item = 0; + while ((length > 0) && (i < n)) { + to_add = MIN(length, 4); + if (item == 0) { + sys_put_le32(min[i], tmp); + } else if (item == 1) { + sys_put_le32(max[i], tmp); + } else if (item == 2) { + if (res) { + sys_put_le32(res[i], tmp); + } else { + memset(tmp, 0, 4); + } + } + net_buf_add_mem(buf, tmp, to_add); + length -= to_add; + + if (++item == 3) { + item = 0; + i++; + } + } +} + +static int get_clock_source_request(struct usbd_class_node *const node, + const struct usb_setup_packet *const setup, + struct net_buf *const buf) +{ + const uint32_t *frequencies; + size_t count; + + /* Channel Number must be zero */ + if (CONTROL_CHANNEL_NUMBER(setup) != 0) { + LOG_DBG("Clock source control with channel %d", + CONTROL_CHANNEL_NUMBER(setup)); + errno = -EINVAL; + return 0; + } + + count = clock_frequencies(node, CONTROL_ENTITY_ID(setup), &frequencies); + + if (CONTROL_SELECTOR(setup) == CS_SAM_FREQ_CONTROL) { + if (CONTROL_ATTRIBUTE(setup) == CUR) { + if (count == 1) { + layout3_cur_response(buf, setup->wLength, + frequencies[0]); + return 0; + } + /* TODO: If there is more than one frequency supported, + * call registered application API to determine active + * sample rate. + */ + } else if (CONTROL_ATTRIBUTE(setup) == RANGE) { + layout3_range_response(buf, setup->wLength, frequencies, + frequencies, NULL, count); + return 0; + } + } else { + LOG_DBG("Unhandled clock control selector 0x%02x", + CONTROL_SELECTOR(setup)); + } + + errno = -ENOTSUP; + return 0; +} + +static int uac2_control_to_host(struct usbd_class_node *const node, + const struct usb_setup_packet *const setup, + struct net_buf *const buf) +{ + entity_type_t entity_type; + + if ((CONTROL_ATTRIBUTE(setup) != CUR) && + (CONTROL_ATTRIBUTE(setup) != RANGE)) { + errno = -ENOTSUP; + return 0; + } + + if (setup->bmRequestType == GET_CLASS_REQUEST_TYPE) { + entity_type = id_type(node, CONTROL_ENTITY_ID(setup)); + if (entity_type == ENTITY_TYPE_CLOCK_SOURCE) { + return get_clock_source_request(node, setup, buf); + } + } + + errno = -ENOTSUP; + return 0; +} + +static int uac2_request(struct usbd_class_node *const node, struct net_buf *buf, + int err) +{ + struct device *dev = node->data->priv; + const struct uac2_cfg *cfg = dev->config; + struct uac2_ctx *ctx = dev->data; + struct usbd_contex *uds_ctx = node->data->uds_ctx; + struct udc_buf_info *bi; + uint8_t ep, terminal; + uint16_t mps; + int as_idx; + bool is_feedback; + + bi = udc_get_buf_info(buf); + 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); + } + } + + mps = buf->size; + ep = bi->ep; + as_idx = ep_to_as_interface(dev, ep, &is_feedback); + __ASSERT_NO_MSG((as_idx >= 0) && (as_idx < cfg->num_ifaces)); + terminal = cfg->as_terminals[as_idx]; + + if (is_feedback) { + ctx->fb_queued &= ~BIT(as_idx); + } else { + atomic_clear_bit(&ctx->as_queued, as_idx); + } + + if (USB_EP_DIR_IS_OUT(ep)) { + ctx->ops->data_recv_cb(dev, terminal, buf->__buf, buf->len, + ctx->user_data); + } else if (!is_feedback) { + ctx->ops->buf_release_cb(dev, terminal, buf->__buf, ctx->user_data); + } + + usbd_ep_buf_free(uds_ctx, buf); + if (err) { + return 0; + } + + /* Reschedule the read or explicit feedback write */ + if (USB_EP_DIR_IS_OUT(ep)) { + schedule_iso_out_read(node, ep, mps, terminal); + } + + return 0; +} + +static void uac2_sof(struct usbd_class_node *const node) +{ + struct device *dev = node->data->priv; + const struct usb_ep_descriptor *data_ep; + const struct uac2_cfg *cfg = dev->config; + const uint8_t *desc = node->data->desc; + struct uac2_ctx *ctx = dev->data; + int as_idx; + + ctx->ops->sof_cb(dev, ctx->user_data); + + for (as_idx = 0; as_idx < cfg->num_ifaces; as_idx++) { + /* Make sure OUT endpoint has read request pending. The request + * won't be pending only if there was buffer underrun, i.e. the + * application failed to supply receive buffer. + */ + data_ep = get_as_data_ep(node, as_idx); + if (data_ep && USB_EP_DIR_IS_OUT(data_ep->bEndpointAddress)) { + schedule_iso_out_read(node, data_ep->bEndpointAddress, + sys_le16_to_cpu(data_ep->wMaxPacketSize), + cfg->as_terminals[as_idx]); + } + + /* Skip interfaces without explicit feedback endpoint */ + if (cfg->fb_offsets[as_idx] == 0) { + continue; + } + + /* We didn't get feedback write request callback yet, skip it + * for now to allow faster recovery (i.e. reduce workload to be + * done during this frame). + */ + if (ctx->fb_queued & BIT(as_idx)) { + continue; + } + + /* Only send feedback if host has enabled alternate interface */ + if (!atomic_test_bit(&ctx->as_active, as_idx)) { + continue; + } + + /* Make feedback available on every frame (value "sent" in + * previous SOF is "gone" even if USB host did not attempt to + * read it). + */ + write_explicit_feedback(node, desc[cfg->fb_offsets[as_idx]], + cfg->as_terminals[as_idx]); + } +} + +static int uac2_init(struct usbd_class_node *const node) +{ + struct device *dev = node->data->priv; + struct uac2_ctx *ctx = dev->data; + + if (ctx->ops == NULL) { + LOG_ERR("Application did not register UAC2 ops"); + return -EINVAL; + } + + return 0; +} + +struct usbd_class_api uac2_api = { + .update = uac2_update, + .control_to_host = uac2_control_to_host, + .request = uac2_request, + .sof = uac2_sof, + .init = uac2_init, +}; + +#define DEFINE_ENTITY_TYPES(node) \ + IF_ENABLED(DT_NODE_HAS_COMPAT(node, zephyr_uac2_clock_source), ( \ + ENTITY_TYPE_CLOCK_SOURCE \ + )) \ + IF_ENABLED(DT_NODE_HAS_COMPAT(node, zephyr_uac2_input_terminal), ( \ + ENTITY_TYPE_INPUT_TERMINAL \ + )) \ + IF_ENABLED(DT_NODE_HAS_COMPAT(node, zephyr_uac2_output_terminal), ( \ + ENTITY_TYPE_OUTPUT_TERMINAL \ + )) \ + IF_ENABLED(DT_NODE_HAS_COMPAT(node, zephyr_uac2_audio_streaming), ( \ + ENTITY_TYPE_INVALID \ + )) \ + , /* Comma here causes unknown types to fail at compile time */ +#define DEFINE_AS_EP_OFFSETS(node) \ + IF_ENABLED(DT_NODE_HAS_COMPAT(node, zephyr_uac2_audio_streaming), ( \ + COND_CODE_1(AS_HAS_ISOCHRONOUS_DATA_ENDPOINT(node), \ + (UAC2_DESCRIPTOR_AS_DATA_EP_OFFSET(node),), (0,)) \ + )) +#define DEFINE_AS_FB_OFFSETS(node) \ + IF_ENABLED(DT_NODE_HAS_COMPAT(node, zephyr_uac2_audio_streaming), ( \ + COND_CODE_1(AS_HAS_EXPLICIT_FEEDBACK_ENDPOINT(node), \ + (UAC2_DESCRIPTOR_AS_FEEDBACK_EP_OFFSET(node),), (0,)) \ + )) +#define DEFINE_AS_TERMINALS(node) \ + IF_ENABLED(DT_NODE_HAS_COMPAT(node, zephyr_uac2_audio_streaming), ( \ + ENTITY_ID(DT_PROP(node, linked_terminal)), \ + )) + +#define FREQUENCY_TABLE_NAME(node, i) \ + UTIL_CAT(frequencies_##i##_, ENTITY_ID(node)) +#define DEFINE_CLOCK_SOURCES(node, i) \ + IF_ENABLED(DT_NODE_HAS_COMPAT(node, zephyr_uac2_clock_source), ( \ + static const uint32_t FREQUENCY_TABLE_NAME(node, i)[] = \ + DT_PROP(node, sampling_frequencies); \ + )) + +#define DEFINE_LOOKUP_TABLES(i) \ + static const entity_type_t entity_types_##i[] = { \ + DT_INST_FOREACH_CHILD_STATUS_OKAY(i, DEFINE_ENTITY_TYPES) \ + }; \ + static const uint16_t ep_offsets_##i[] = { \ + DT_INST_FOREACH_CHILD_STATUS_OKAY(i, DEFINE_AS_EP_OFFSETS) \ + }; \ + static const uint16_t fb_offsets_##i[] = { \ + DT_INST_FOREACH_CHILD_STATUS_OKAY(i, DEFINE_AS_FB_OFFSETS) \ + }; \ + static const uint8_t as_terminals_##i[] = { \ + DT_INST_FOREACH_CHILD_STATUS_OKAY(i, DEFINE_AS_TERMINALS) \ + }; \ + DT_INST_FOREACH_CHILD_STATUS_OKAY_VARGS(i, DEFINE_CLOCK_SOURCES, i) + +#define DEFINE_UAC2_CLASS_DATA(inst) \ + DT_INST_FOREACH_CHILD(inst, VALIDATE_NODE) \ + static struct uac2_ctx uac2_ctx_##inst; \ + static uint8_t uac2_descriptor_##inst[] = { \ + UAC2_DESCRIPTORS(DT_DRV_INST(inst)) \ + 0x00, 0x00 /* terminator required by USBD stack */ \ + }; \ + static struct usbd_class_data uac2_class_##inst = { \ + .desc = (struct usb_desc_header *)uac2_descriptor_##inst, \ + .priv = (void *)DEVICE_DT_GET(DT_DRV_INST(inst)), \ + }; \ + USBD_DEFINE_CLASS(uac2_##inst, &uac2_api, &uac2_class_##inst); \ + DEFINE_LOOKUP_TABLES(inst) \ + static const struct uac2_cfg uac2_cfg_##inst = { \ + .node = &uac2_##inst, \ + .entity_types = entity_types_##inst, \ + .ep_offsets = ep_offsets_##inst, \ + .fb_offsets = fb_offsets_##inst, \ + .as_terminals = as_terminals_##inst, \ + .num_ifaces = ARRAY_SIZE(ep_offsets_##inst), \ + .num_entities = ARRAY_SIZE(entity_types_##inst), \ + }; \ + BUILD_ASSERT(ARRAY_SIZE(ep_offsets_##inst) <= 32, \ + "UAC2 implementation supports up to 32 AS interfaces"); \ + BUILD_ASSERT(ARRAY_SIZE(entity_types_##inst) <= 255, \ + "UAC2 supports up to 255 entities"); \ + DEVICE_DT_DEFINE(DT_DRV_INST(inst), NULL, NULL, \ + &uac2_ctx_##inst, &uac2_cfg_##inst, \ + POST_KERNEL, CONFIG_KERNEL_INIT_PRIORITY_DEVICE, \ + NULL); +DT_INST_FOREACH_STATUS_OKAY(DEFINE_UAC2_CLASS_DATA) + +static size_t clock_frequencies(struct usbd_class_node *const node, + const uint8_t id, const uint32_t **frequencies) +{ + const struct device *dev = node->data->priv; + size_t count; + +#define GET_FREQUENCY_TABLE(node, i) \ + IF_ENABLED(DT_NODE_HAS_COMPAT(node, zephyr_uac2_clock_source), ( \ + } else if (id == ENTITY_ID(node)) { \ + *frequencies = FREQUENCY_TABLE_NAME(node, i); \ + count = ARRAY_SIZE(FREQUENCY_TABLE_NAME(node, i)); \ + )) + + if (0) { +#define SELECT_FREQUENCY_TABLE(i) \ + } else if (dev == DEVICE_DT_GET(DT_DRV_INST(i))) { \ + if (0) { \ + DT_INST_FOREACH_CHILD_VARGS(i, GET_FREQUENCY_TABLE, i) \ + } else { \ + *frequencies = NULL; \ + count = 0; \ + } +DT_INST_FOREACH_STATUS_OKAY(SELECT_FREQUENCY_TABLE) + } else { + *frequencies = NULL; + count = 0; + } + + return count; +} diff --git a/subsys/usb/device_next/class/usbd_uac2_macros.h b/subsys/usb/device_next/class/usbd_uac2_macros.h index 3160dd13433..743ecaf2900 100644 --- a/subsys/usb/device_next/class/usbd_uac2_macros.h +++ b/subsys/usb/device_next/class/usbd_uac2_macros.h @@ -640,6 +640,17 @@ - AS_ISOCHRONOUS_DATA_ENDPOINT_DESCRIPTORS_SIZE(node) \ + offsetof(struct usb_ep_descriptor, bEndpointAddress) +/* Return offset inside UAC2_DESCRIPTORS(DT_PARENT(node)) poiting to feedback + * endpoint address belonging to given AudioStreaming interface node. + * + * It is programmer error to call this macro with node other than AudioStreaming + * or when AS_HAS_EXPLICIT_FEEDBACK_ENDPOINT(node) is 0. + */ +#define UAC2_DESCRIPTOR_AS_FEEDBACK_EP_OFFSET(node) \ + UAC2_DESCRIPTOR_AS_DESC_END_OFFSET(node) \ + - AS_EXPLICIT_FEEDBACK_ENDPOINT_DESCRIPTOR_SIZE(node) \ + + offsetof(struct usb_ep_descriptor, bEndpointAddress) + /* Helper macros to validate USB Audio Class 2 devicetree entries. * Macros above do rely on the assumptions checked below. */ From f00f846fe35cfd640d5085726ee65ac583904888 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tomasz=20Mo=C5=84?= Date: Wed, 20 Dec 2023 09:40:56 +0100 Subject: [PATCH 3307/3723] samples: usb: add UAC2 explicit feedback sample MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The sample illustrates how to calculate feedback value based on I2S sample clock measurement or indirect I2S FRAMESTART and USBD SOF. The sample is currently only supported on nrf5340dk_nrf5340_cpuapp target because the feedback measurement uses target specific peripherals. While it should be possible to perform feedback value calculation entirely in software (possibly with some additional filtering due to software scheduling jitter), the I2S API does not provide necessary timestamps. Signed-off-by: Tomasz Moń --- doc/connectivity/usb/device/usb_device.rst | 2 + .../usb/uac2_explicit_feedback/CMakeLists.txt | 14 + .../subsys/usb/uac2_explicit_feedback/Kconfig | 19 + .../usb/uac2_explicit_feedback/README.rst | 64 +++ .../usb/uac2_explicit_feedback/app.overlay | 44 ++ .../boards/nrf5340dk_nrf5340_cpuapp.conf | 2 + .../boards/nrf5340dk_nrf5340_cpuapp.overlay | 28 ++ .../usb/uac2_explicit_feedback/prj.conf | 12 + .../usb/uac2_explicit_feedback/sample.yaml | 6 + .../usb/uac2_explicit_feedback/src/feedback.h | 23 + .../src/feedback_dummy.c | 39 ++ .../src/feedback_nrf53.c | 398 ++++++++++++++++++ .../usb/uac2_explicit_feedback/src/main.c | 299 +++++++++++++ 13 files changed, 950 insertions(+) create mode 100644 samples/subsys/usb/uac2_explicit_feedback/CMakeLists.txt create mode 100644 samples/subsys/usb/uac2_explicit_feedback/Kconfig create mode 100644 samples/subsys/usb/uac2_explicit_feedback/README.rst create mode 100644 samples/subsys/usb/uac2_explicit_feedback/app.overlay create mode 100644 samples/subsys/usb/uac2_explicit_feedback/boards/nrf5340dk_nrf5340_cpuapp.conf create mode 100644 samples/subsys/usb/uac2_explicit_feedback/boards/nrf5340dk_nrf5340_cpuapp.overlay create mode 100644 samples/subsys/usb/uac2_explicit_feedback/prj.conf create mode 100644 samples/subsys/usb/uac2_explicit_feedback/sample.yaml create mode 100644 samples/subsys/usb/uac2_explicit_feedback/src/feedback.h create mode 100644 samples/subsys/usb/uac2_explicit_feedback/src/feedback_dummy.c create mode 100644 samples/subsys/usb/uac2_explicit_feedback/src/feedback_nrf53.c create mode 100644 samples/subsys/usb/uac2_explicit_feedback/src/main.c diff --git a/doc/connectivity/usb/device/usb_device.rst b/doc/connectivity/usb/device/usb_device.rst index 134ec5972cd..bf446ae7524 100644 --- a/doc/connectivity/usb/device/usb_device.rst +++ b/doc/connectivity/usb/device/usb_device.rst @@ -537,6 +537,8 @@ The following Product IDs are currently used: +----------------------------------------------------+--------+ | :zephyr:code-sample:`wpan-usb` | 0x000D | +----------------------------------------------------+--------+ +| :zephyr:code-sample:`uac2-explicit-feedback` | 0x000E | ++----------------------------------------------------+--------+ The USB device descriptor field ``bcdDevice`` (Device Release Number) represents the Zephyr kernel major and minor versions as a binary coded decimal value. diff --git a/samples/subsys/usb/uac2_explicit_feedback/CMakeLists.txt b/samples/subsys/usb/uac2_explicit_feedback/CMakeLists.txt new file mode 100644 index 00000000000..26ce264c421 --- /dev/null +++ b/samples/subsys/usb/uac2_explicit_feedback/CMakeLists.txt @@ -0,0 +1,14 @@ +# SPDX-License-Identifier: Apache-2.0 + +cmake_minimum_required(VERSION 3.20.0) +find_package(Zephyr REQUIRED HINTS $ENV{ZEPHYR_BASE}) +project(usb_audio_async_i2s) + +include(${ZEPHYR_BASE}/samples/subsys/usb/common/common.cmake) +target_sources(app PRIVATE src/main.c) + +if (CONFIG_SOC_COMPATIBLE_NRF5340_CPUAPP) + target_sources(app PRIVATE src/feedback_nrf53.c) +else() + target_sources(app PRIVATE src/feedback_dummy.c) +endif() diff --git a/samples/subsys/usb/uac2_explicit_feedback/Kconfig b/samples/subsys/usb/uac2_explicit_feedback/Kconfig new file mode 100644 index 00000000000..bee6118a00d --- /dev/null +++ b/samples/subsys/usb/uac2_explicit_feedback/Kconfig @@ -0,0 +1,19 @@ +# Copyright (c) 2023-2024 Nordic Semiconductor ASA +# SPDX-License-Identifier: Apache-2.0 + +menu "UAC2 external feedback sample options" + +config APP_USE_I2S_LRCLK_EDGES_COUNTER + bool "Measure I2S LRCLK edges directly" + help + Use this to use I2S LRCLK edge counting for calculating feedback. + On nRF53 this option requires externally connecting I2S LRCLK back to + separate GPIOTE input pin (P1.09). +endmenu + +# 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/usb/uac2_explicit_feedback/README.rst b/samples/subsys/usb/uac2_explicit_feedback/README.rst new file mode 100644 index 00000000000..8d9ff40dc7a --- /dev/null +++ b/samples/subsys/usb/uac2_explicit_feedback/README.rst @@ -0,0 +1,64 @@ +.. zephyr:code-sample:: uac2-explicit-feedback + :name: USB Audio asynchronous explicit feedback sample + :relevant-api: _usb_device_core_api i2s_interface + + USB Audio 2 explicit feedback sample playing audio on I2S. + +Overview +******** + +This sample demonstrates how to implement USB asynchronous audio playback with +explicit feedback. It can run on any board with USB and I2S support, but the +feedback calculation is currently only implemented for the Nordic nRF5340 IC. + +The device running this sample presents itself to the host as a Full-Speed +Asynchronous USB Audio 2 class device supporting 48 kHz 16-bit 2-channel +(stereo) playback. + +Explicit Feedback +***************** + +Asynchronous USB Audio is used when the actual sample clock is not controlled by +USB host. Because the sample clock is independent from USB SOF it is inevitable +that 1 ms according to audio sink (I2S) will be either slightly longer or +shorter than 1 ms according to audio source (USB host). In the long run, this +discrepancy leads to overruns or underruns. By providing explicit feedback to +host, the device can tell host how many samples on average it needs every frame. +The host achieves the average by sending either nominal or nominal ±1 sample +packets every frame. + +The dummy feedback implementation, used when there is no target-specific +feedback code available, returns a feedback value that results in host sending +nominal number of samples every frame. Theoretically it should be possible to +obtain the timing information based on I2S and USB interrupts, but currently +neither subsystem provides the necessary timestamp information. + +Explcit Feedback on nRF5340 +*************************** + +The nRF5340 is capable of counting both edges of I2S LRCLK relative to USB SOF +with the use of DPPI, TIMER and GPIOTE input. Alternatively, if the GPIOTE input +is not available, the DPPI and TIMER peripherals on nRF5340 can be configured to +provide relative timing information between I2S FRAMESTART and USB SOF. + +This sample in both modes (direct sample counting and indirect I2S buffer output +to USB SOF offset) has been tested on :ref:`nrf5340dk_nrf5340`. + +The sample defaults to indirect feedback calculation because direct sample +counting requires external connection between I2S LRCLK output pin to GPIOTE +input pin (hardcoded to P1.09) on :ref:`nrf5340dk_nrf5340`. In the indirect mode +no extra connections are necessary and the sample can even be used without any +I2S device connected where I2S signals can be checked e.g. on logic analyzer. + +Building and Running +******************** + +The code can be found in :zephyr_file:`samples/subsys/usb/uac2_explicit_feedback`. + +To build and flash the application: + +.. zephyr-app-commands:: + :zephyr-app: samples/subsys/usb/uac2_explicit_feedback + :board: nrf5340dk_nrf5340_cpuapp + :goals: build flash + :compact: diff --git a/samples/subsys/usb/uac2_explicit_feedback/app.overlay b/samples/subsys/usb/uac2_explicit_feedback/app.overlay new file mode 100644 index 00000000000..08044d529f5 --- /dev/null +++ b/samples/subsys/usb/uac2_explicit_feedback/app.overlay @@ -0,0 +1,44 @@ +/* + * Copyright (c) 2023 Nordic Semiconductor ASA + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include + +/ { + uac2_headphones: usb_audio2 { + compatible = "zephyr,uac2"; + status = "okay"; + audio-function = ; + + uac_aclk: aclk { + compatible = "zephyr,uac2-clock-source"; + clock-type = "internal-programmable"; + frequency-control = "host-programmable"; + sampling-frequencies = <48000>; + }; + + out_terminal: out_terminal { + compatible = "zephyr,uac2-input-terminal"; + clock-source = <&uac_aclk>; + terminal-type = ; + front-left; + front-right; + }; + + headphones_output: headphones { + compatible = "zephyr,uac2-output-terminal"; + data-source = <&out_terminal>; + clock-source = <&uac_aclk>; + terminal-type = ; + }; + + as_iso_out: out_interface { + compatible = "zephyr,uac2-audio-streaming"; + linked-terminal = <&out_terminal>; + subslot-size = <2>; + bit-resolution = <16>; + }; + }; +}; diff --git a/samples/subsys/usb/uac2_explicit_feedback/boards/nrf5340dk_nrf5340_cpuapp.conf b/samples/subsys/usb/uac2_explicit_feedback/boards/nrf5340dk_nrf5340_cpuapp.conf new file mode 100644 index 00000000000..ce67033381a --- /dev/null +++ b/samples/subsys/usb/uac2_explicit_feedback/boards/nrf5340dk_nrf5340_cpuapp.conf @@ -0,0 +1,2 @@ +#Enable timer for asynchronous feedback +CONFIG_NRFX_TIMER2=y diff --git a/samples/subsys/usb/uac2_explicit_feedback/boards/nrf5340dk_nrf5340_cpuapp.overlay b/samples/subsys/usb/uac2_explicit_feedback/boards/nrf5340dk_nrf5340_cpuapp.overlay new file mode 100644 index 00000000000..47205e2ed61 --- /dev/null +++ b/samples/subsys/usb/uac2_explicit_feedback/boards/nrf5340dk_nrf5340_cpuapp.overlay @@ -0,0 +1,28 @@ +/* + * Copyright (c) 2023 Nordic Semiconductor ASA + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include "../app.overlay" + +&pinctrl { + i2s0_default_alt: i2s0_default_alt { + group1 { + psels = , + , + ; + }; + }; +}; + +&clock { + hfclkaudio-frequency = <12288000>; +}; + +i2s_tx: &i2s0 { + status = "okay"; + pinctrl-0 = <&i2s0_default_alt>; + pinctrl-names = "default"; + clock-source = "ACLK"; +}; diff --git a/samples/subsys/usb/uac2_explicit_feedback/prj.conf b/samples/subsys/usb/uac2_explicit_feedback/prj.conf new file mode 100644 index 00000000000..3979a5190e6 --- /dev/null +++ b/samples/subsys/usb/uac2_explicit_feedback/prj.conf @@ -0,0 +1,12 @@ +CONFIG_I2S=y + +#USB related configs +CONFIG_USB_DEVICE_STACK_NEXT=y +CONFIG_USBD_AUDIO2_CLASS=y +CONFIG_SAMPLE_USBD_PID=0x000E +CONFIG_SAMPLE_USBD_PRODUCT="UAC2 explicit feedback sample" + +#LOG subsystem related configs +CONFIG_LOG=y +CONFIG_USBD_LOG_LEVEL_WRN=y +CONFIG_UDC_DRIVER_LOG_LEVEL_WRN=y diff --git a/samples/subsys/usb/uac2_explicit_feedback/sample.yaml b/samples/subsys/usb/uac2_explicit_feedback/sample.yaml new file mode 100644 index 00000000000..7fa75c76127 --- /dev/null +++ b/samples/subsys/usb/uac2_explicit_feedback/sample.yaml @@ -0,0 +1,6 @@ +sample: + name: USB Audio 2 asynchronous explicit feedback sample +tests: + sample.subsys.usb.uac2_explicit_feedback: + tags: usb i2s + platform_allow: nrf5340dk_nrf5340_cpuapp diff --git a/samples/subsys/usb/uac2_explicit_feedback/src/feedback.h b/samples/subsys/usb/uac2_explicit_feedback/src/feedback.h new file mode 100644 index 00000000000..7f5bf2027d8 --- /dev/null +++ b/samples/subsys/usb/uac2_explicit_feedback/src/feedback.h @@ -0,0 +1,23 @@ +/* + * Copyright (c) 2024 Nordic Semiconductor ASA + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#ifndef FEEDBACK_H_ +#define FEEDBACK_H_ + +#include + +/* Nominal number of samples received on each SOF. This sample is currently + * supporting only 48 kHz sample rate. + */ +#define SAMPLES_PER_SOF 48 + +struct feedback_ctx *feedback_init(void); +void feedback_reset_ctx(struct feedback_ctx *ctx); +void feedback_process(struct feedback_ctx *ctx); +void feedback_start(struct feedback_ctx *ctx, int i2s_blocks_queued); +uint32_t feedback_value(struct feedback_ctx *ctx); + +#endif /* FEEDBACK_H_ */ diff --git a/samples/subsys/usb/uac2_explicit_feedback/src/feedback_dummy.c b/samples/subsys/usb/uac2_explicit_feedback/src/feedback_dummy.c new file mode 100644 index 00000000000..7e274ca2ed0 --- /dev/null +++ b/samples/subsys/usb/uac2_explicit_feedback/src/feedback_dummy.c @@ -0,0 +1,39 @@ +/* + * Copyright (c) 2024 Nordic Semiconductor ASA + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include +#include "feedback.h" + +#warning "No target specific feedback code, overruns/underruns will occur" + +#define FEEDBACK_K 10 + +struct feedback_ctx *feedback_init(void) +{ + return NULL; +} + +void feedback_process(struct feedback_ctx *ctx) +{ + ARG_UNUSED(ctx); +} + +void feedback_reset_ctx(struct feedback_ctx *ctx) +{ + ARG_UNUSED(ctx); +} + +void feedback_start(struct feedback_ctx *ctx, int i2s_blocks_queued) +{ + ARG_UNUSED(ctx); + ARG_UNUSED(i2s_blocks_queued); +} + +uint32_t feedback_value(struct feedback_ctx *ctx) +{ + /* Always request nominal number of samples */ + return SAMPLES_PER_SOF << FEEDBACK_K; +} diff --git a/samples/subsys/usb/uac2_explicit_feedback/src/feedback_nrf53.c b/samples/subsys/usb/uac2_explicit_feedback/src/feedback_nrf53.c new file mode 100644 index 00000000000..e5f93a846fd --- /dev/null +++ b/samples/subsys/usb/uac2_explicit_feedback/src/feedback_nrf53.c @@ -0,0 +1,398 @@ +/* + * Copyright (c) 2024 Nordic Semiconductor ASA + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include +#include +#include "feedback.h" + +#include +#include +#include +#include +#include +#include +#include + +LOG_MODULE_REGISTER(feedback, LOG_LEVEL_INF); + +static const nrfx_gpiote_t gpiote = NRFX_GPIOTE_INSTANCE(0); + +#define FEEDBACK_PIN NRF_GPIO_PIN_MAP(1, 9) +#define FEEDBACK_TIMER_INSTANCE_NUMBER 2 +#define FEEDBACK_TIMER_USBD_SOF_CAPTURE 0 +#define FEEDBACK_TIMER_I2S_FRAMESTART_CAPTURE 1 + +static const nrfx_timer_t feedback_timer_instance = + NRFX_TIMER_INSTANCE(FEEDBACK_TIMER_INSTANCE_NUMBER); + +/* See 5.12.4.2 Feedback in Universal Serial Bus Specification Revision 2.0 for + * more information about the feedback. There is a direct implementation of the + * specification where P=1 when @kconfig{CONFIG_APP_USE_I2S_LRCLK_EDGES_COUNTER} + * is enabled, because I2S LRCLK edges (and not the clock) are being counted by + * a timer. Otherwise, when @kconfig{CONFIG_APP_USE_I2S_LRCLK_EDGES_COUNTER} is + * disabled, we are faking P=5 value using indirect offset measurements and + * we use such estimate on PI controller updated on every SOF. + * + * While it might be possible to determine I2S FRAMESTART to USB SOF offset + * entirely in software, the I2S API lacks appropriate timestamping. Therefore + * this sample uses target-specific code to perform the measurements. Note that + * the use of dedicated target-specific peripheral essentially eliminates + * software scheduling jitter and it is likely that a pure software only + * solution would require additional filtering in indirect offset measurements. + * + * Full-Speed isochronous feedback is Q10.10 unsigned integer left-justified in + * the 24-bits so it has Q10.14 format. This sample application puts zeroes to + * the 4 least significant bits (does not use the bits for extra precision). + */ +#define FEEDBACK_K 10 +#if IS_ENABLED(CONFIG_APP_USE_I2S_LRCLK_EDGES_COUNTER) +#define FEEDBACK_P 1 +#else +#define FEEDBACK_P 5 +#endif + +#define FEEDBACK_FS_SHIFT 4 + +static struct feedback_ctx { + uint32_t fb_value; + int32_t rel_sof_offset; + int32_t base_sof_offset; + union { + /* For edge counting */ + struct { + uint32_t fb_counter; + uint16_t fb_periods; + }; + /* For PI controller */ + int32_t integrator; + }; +} fb_ctx; + +static nrfx_err_t feedback_edge_counter_setup(void) +{ + nrfx_err_t err; + uint8_t feedback_gpiote_channel; + uint8_t feedback_gppi_channel; + nrfx_gpiote_trigger_config_t trigger_config = { + .trigger = NRFX_GPIOTE_TRIGGER_TOGGLE, + .p_in_channel = &feedback_gpiote_channel, + }; + nrfx_gpiote_input_pin_config_t input_pin_config = { + .p_trigger_config = &trigger_config, + }; + + /* App core is using feedback pin */ + nrf_gpio_pin_control_select(FEEDBACK_PIN, NRF_GPIO_PIN_SEL_APP); + + err = nrfx_gpiote_channel_alloc(&gpiote, &feedback_gpiote_channel); + if (err != NRFX_SUCCESS) { + return err; + } + + nrfx_gpiote_input_configure(&gpiote, FEEDBACK_PIN, &input_pin_config); + nrfx_gpiote_trigger_enable(&gpiote, FEEDBACK_PIN, false); + + /* Configure TIMER in COUNTER mode */ + const nrfx_timer_config_t cfg = { + .frequency = NRFX_MHZ_TO_HZ(1UL), + .mode = NRF_TIMER_MODE_COUNTER, + .bit_width = NRF_TIMER_BIT_WIDTH_32, + .interrupt_priority = NRFX_TIMER_DEFAULT_CONFIG_IRQ_PRIORITY, + .p_context = NULL, + }; + + err = nrfx_timer_init(&feedback_timer_instance, &cfg, NULL); + if (err != NRFX_SUCCESS) { + LOG_ERR("nrfx timer init error (sample clk feedback) - Return value: %d", err); + return err; + } + + /* Subscribe TIMER COUNT task to GPIOTE IN event */ + err = nrfx_gppi_channel_alloc(&feedback_gppi_channel); + if (err != NRFX_SUCCESS) { + LOG_ERR("gppi_channel_alloc failed with: %d\n", err); + return err; + } + + nrfx_gppi_channel_endpoints_setup(feedback_gppi_channel, + nrfx_gpiote_in_event_address_get(&gpiote, FEEDBACK_PIN), + nrfx_timer_task_address_get(&feedback_timer_instance, NRF_TIMER_TASK_COUNT)); + + nrfx_gppi_channels_enable(BIT(feedback_gppi_channel)); + + return NRFX_SUCCESS; +} + +static nrfx_err_t feedback_relative_timer_setup(void) +{ + nrfx_err_t err; + const nrfx_timer_config_t cfg = { + .frequency = NRFX_MHZ_TO_HZ(16UL), + .mode = NRF_TIMER_MODE_TIMER, + .bit_width = NRF_TIMER_BIT_WIDTH_32, + .interrupt_priority = NRFX_TIMER_DEFAULT_CONFIG_IRQ_PRIORITY, + .p_context = NULL, + }; + + err = nrfx_timer_init(&feedback_timer_instance, &cfg, NULL); + if (err != NRFX_SUCCESS) { + LOG_ERR("nrfx timer init error (relative timer) - Return value: %d", err); + } + + return err; +} + +struct feedback_ctx *feedback_init(void) +{ + nrfx_err_t err; + uint8_t usbd_sof_gppi_channel; + uint8_t i2s_framestart_gppi_channel; + + feedback_reset_ctx(&fb_ctx); + + if (IS_ENABLED(CONFIG_APP_USE_I2S_LRCLK_EDGES_COUNTER)) { + err = feedback_edge_counter_setup(); + } else { + err = feedback_relative_timer_setup(); + } + + if (err != NRFX_SUCCESS) { + return &fb_ctx; + } + + /* Subscribe TIMER CAPTURE task to USBD SOF event */ + err = nrfx_gppi_channel_alloc(&usbd_sof_gppi_channel); + if (err != NRFX_SUCCESS) { + LOG_ERR("gppi_channel_alloc failed with: %d\n", err); + return &fb_ctx; + } + + nrfx_gppi_channel_endpoints_setup(usbd_sof_gppi_channel, + nrf_usbd_event_address_get(NRF_USBD, NRF_USBD_EVENT_SOF), + nrfx_timer_capture_task_address_get(&feedback_timer_instance, + FEEDBACK_TIMER_USBD_SOF_CAPTURE)); + nrfx_gppi_fork_endpoint_setup(usbd_sof_gppi_channel, + nrfx_timer_task_address_get(&feedback_timer_instance, + NRF_TIMER_TASK_CLEAR)); + + nrfx_gppi_channels_enable(BIT(usbd_sof_gppi_channel)); + + /* Subscribe TIMER CAPTURE task to I2S FRAMESTART event */ + err = nrfx_gppi_channel_alloc(&i2s_framestart_gppi_channel); + if (err != NRFX_SUCCESS) { + LOG_ERR("gppi_channel_alloc failed with: %d\n", err); + return &fb_ctx; + } + + nrfx_gppi_channel_endpoints_setup(i2s_framestart_gppi_channel, + nrf_i2s_event_address_get(NRF_I2S0, NRF_I2S_EVENT_FRAMESTART), + nrfx_timer_capture_task_address_get(&feedback_timer_instance, + FEEDBACK_TIMER_I2S_FRAMESTART_CAPTURE)); + + nrfx_gppi_channels_enable(BIT(i2s_framestart_gppi_channel)); + + /* Enable feedback timer */ + nrfx_timer_enable(&feedback_timer_instance); + + return &fb_ctx; +} + +static void update_sof_offset(struct feedback_ctx *ctx, uint32_t sof_cc, + uint32_t framestart_cc) +{ + int sof_offset; + + if (!IS_ENABLED(CONFIG_APP_USE_I2S_LRCLK_EDGES_COUNTER)) { + uint32_t clks_per_edge; + + /* Convert timer clock (independent from both Audio clock and + * USB host SOF clock) to fake sample clock shifted by P values. + * This works fine because the regulator cares only about error + * (SOF offset is both error and regulator input) and achieves + * its goal by adjusting feedback value. SOF offset is around 0 + * when regulated and therefore the relative clock frequency + * discrepancies are essentially negligible. + */ + clks_per_edge = sof_cc / (SAMPLES_PER_SOF << FEEDBACK_P); + sof_cc /= MAX(clks_per_edge, 1); + framestart_cc /= MAX(clks_per_edge, 1); + } + + /* /2 because we treat the middle as a turning point from being + * "too late" to "too early". + */ + if (framestart_cc > (SAMPLES_PER_SOF << FEEDBACK_P)/2) { + sof_offset = framestart_cc - (SAMPLES_PER_SOF << FEEDBACK_P); + } else { + sof_offset = framestart_cc; + } + + /* The heuristic above is not enough when the offset gets too large. + * If the sign of the simple heuristic changes, check whether the offset + * crossed through the zero or the outer bound. + */ + if ((ctx->rel_sof_offset >= 0) != (sof_offset >= 0)) { + uint32_t abs_diff; + int32_t base_change; + + if (sof_offset >= 0) { + abs_diff = sof_offset - ctx->rel_sof_offset; + base_change = -(SAMPLES_PER_SOF << FEEDBACK_P); + } else { + abs_diff = ctx->rel_sof_offset - sof_offset; + base_change = SAMPLES_PER_SOF << FEEDBACK_P; + } + + /* Adjust base offset only if the change happened through the + * outer bound. The actual changes should be significantly lower + * than the threshold here. + */ + if (abs_diff > (SAMPLES_PER_SOF << FEEDBACK_P)/2) { + ctx->base_sof_offset += base_change; + } + } + + ctx->rel_sof_offset = sof_offset; +} + +static inline int32_t offset_to_correction(int32_t offset) +{ + return -(offset / BIT(FEEDBACK_P)) * BIT(FEEDBACK_FS_SHIFT); +} + +static int32_t pi_update(struct feedback_ctx *ctx) +{ + int32_t sof_offset = ctx->rel_sof_offset + ctx->base_sof_offset; + /* SOF offset is measured in pow(2, -FEEDBACK_P) samples, i.e. when + * FEEDBACK_P is 0, offset is in samples, and for 1 -> half-samples, + * 2 -> quarter-samples, 3 -> eightth-samples and so on. + * In order to simplify the PI controller description here, normalize + * the offset to 1/1024 samples (alternatively it can be treated as + * samples in Q10 fixed point format) and use it as Process Variable. + */ + int32_t PV = BIT(10 - FEEDBACK_P) * sof_offset; + /* The control goal is to keep I2S FRAMESTART as close as possible to + * USB SOF and therefore Set Point is 0. + */ + int32_t SP = 0; + int32_t error = SP - PV; + + /* + * With above normalization at Full-Speed, when data received during + * SOF n appears on I2S during SOF n+3, the Ziegler Nichols Ultimate + * Gain is around 1.15 and the oscillation period is around 90 SOF. + * (much nicer oscillations with 204.8 SOF period can be observed with + * gain 0.5 when the delay is not n+3, but n+33 - surprisingly the + * resulting PI coefficients after power of two rounding are the same). + * + * Ziegler-Nichols rule with applied stability margin of 2 results in: + * Kc = 0.22 * Ku = 0.22 * 1.15 = 0.253 + * Ti = 0.83 * tu = 0.83 * 80 = 66.4 + * + * Converting the rules above to parallel PI gives: + * Kp = Kc = 0.253 + * Ki = Kc/Ti = 0.254/66.4 ~= 0.0038253 + * + * Because we want fixed-point optimized non-tunable implementation, + * the parameters can be conveniently expressed with power of two: + * Kp ~= pow(2, -2) = 0.25 (divide by 4) + * Ki ~= pow(2, -8) = 0.0039 (divide by 256) + * + * This can be implemented as: + * ctx->integrator += error; + * return (error + (ctx->integrator / 64)) / 4; + * but unfortunately such regulator is pretty aggressive and keeps + * oscillating rather quickly around the setpoint (within +-1 sample). + * + * Manually tweaking the constants so the regulator output is shifted + * down by 4 bits (i.e. change /64 to /2048 and /4 to /128) yields + * really good results (the outcome is similar, even slightly better, + * than using I2S LRCLK edge counting directly). + */ + ctx->integrator += error; + return (error + (ctx->integrator / 2048)) / 128; +} + +void feedback_process(struct feedback_ctx *ctx) +{ + uint32_t sof_cc; + uint32_t framestart_cc; + uint32_t fb; + + sof_cc = nrfx_timer_capture_get(&feedback_timer_instance, + FEEDBACK_TIMER_USBD_SOF_CAPTURE); + framestart_cc = nrfx_timer_capture_get(&feedback_timer_instance, + FEEDBACK_TIMER_I2S_FRAMESTART_CAPTURE); + + update_sof_offset(ctx, sof_cc, framestart_cc); + + if (IS_ENABLED(CONFIG_APP_USE_I2S_LRCLK_EDGES_COUNTER)) { + int32_t offset = ctx->rel_sof_offset + ctx->base_sof_offset; + + ctx->fb_counter += sof_cc; + ctx->fb_periods++; + + if (ctx->fb_periods == BIT(FEEDBACK_K - FEEDBACK_P)) { + + /* fb_counter holds Q10.10 value, left-justify it */ + fb = ctx->fb_counter << FEEDBACK_FS_SHIFT; + + /* Align I2S FRAMESTART to USB SOF by adjusting reported + * feedback value. This is endpoint specific correction + * mentioned but not specified in USB 2.0 Specification. + */ + if (abs(offset) > BIT(FEEDBACK_P)) { + fb += offset_to_correction(offset); + } + + ctx->fb_value = fb; + ctx->fb_counter = 0; + ctx->fb_periods = 0; + } + } else { + /* Use PI controller to generate required feedback deviation + * from nominal feedback value. + */ + fb = SAMPLES_PER_SOF << (FEEDBACK_K + FEEDBACK_FS_SHIFT); + /* Clear the additional LSB bits in feedback value, i.e. do not + * use the optional extra resolution. + */ + fb += pi_update(ctx) & ~0xF; + ctx->fb_value = fb; + } +} + +void feedback_reset_ctx(struct feedback_ctx *ctx) +{ + /* Reset feedback to nominal value */ + ctx->fb_value = SAMPLES_PER_SOF << (FEEDBACK_K + FEEDBACK_FS_SHIFT); + if (IS_ENABLED(CONFIG_APP_USE_I2S_LRCLK_EDGES_COUNTER)) { + ctx->fb_counter = 0; + ctx->fb_periods = 0; + } else { + ctx->integrator = 0; + } +} + +void feedback_start(struct feedback_ctx *ctx, int i2s_blocks_queued) +{ + /* I2S data was supposed to go out at SOF, but it is inevitably + * delayed due to triggering I2S start by software. Set relative + * SOF offset value in a way that ensures that values past "half + * frame" are treated as "too late" instead of "too early" + */ + ctx->rel_sof_offset = (SAMPLES_PER_SOF << FEEDBACK_P) / 2; + /* If there are more than 2 I2S blocks queued, use feedback regulator + * to correct the situation. + */ + ctx->base_sof_offset = (i2s_blocks_queued - 2) * + (SAMPLES_PER_SOF << FEEDBACK_P); +} + +uint32_t feedback_value(struct feedback_ctx *ctx) +{ + return ctx->fb_value; +} diff --git a/samples/subsys/usb/uac2_explicit_feedback/src/main.c b/samples/subsys/usb/uac2_explicit_feedback/src/main.c new file mode 100644 index 00000000000..69dc731833d --- /dev/null +++ b/samples/subsys/usb/uac2_explicit_feedback/src/main.c @@ -0,0 +1,299 @@ +/* + * Copyright (c) 2023-2024 Nordic Semiconductor ASA + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include +#include + +#include +#include "feedback.h" + +#include +#include +#include +#include +#include +#include + +LOG_MODULE_REGISTER(uac2_sample, LOG_LEVEL_INF); + +#define HEADPHONES_OUT_TERMINAL_ID UAC2_ENTITY_ID(DT_NODELABEL(out_terminal)) + +#define SAMPLE_FREQUENCY (SAMPLES_PER_SOF * 1000) +#define SAMPLE_BIT_WIDTH 16 +#define NUMBER_OF_CHANNELS 2 +#define BYTES_PER_SAMPLE DIV_ROUND_UP(SAMPLE_BIT_WIDTH, 8) +#define BYTES_PER_SLOT (BYTES_PER_SAMPLE * NUMBER_OF_CHANNELS) +#define MIN_BLOCK_SIZE ((SAMPLES_PER_SOF - 1) * BYTES_PER_SLOT) +#define BLOCK_SIZE (SAMPLES_PER_SOF * BYTES_PER_SLOT) +#define MAX_BLOCK_SIZE ((SAMPLES_PER_SOF + 1) * BYTES_PER_SLOT) + +/* Absolute minimum is 5 buffers (1 actively consumed by I2S, 2nd queued as next + * buffer, 3rd acquired by USB stack to receive data to, and 2 to handle SOF/I2S + * offset errors), but add 2 additional buffers to prevent out of memory errors + * when USB host decides to perform rapid terminal enable/disable cycles. + */ +#define I2S_BUFFERS_COUNT 7 +K_MEM_SLAB_DEFINE_STATIC(i2s_tx_slab, MAX_BLOCK_SIZE, I2S_BUFFERS_COUNT, 4); + +struct usb_i2s_ctx { + const struct device *i2s_dev; + bool terminal_enabled; + bool i2s_started; + /* Number of blocks written, used to determine when to start I2S. + * Overflows are not a problem becuse this variable is not necessary + * after I2S is started. + */ + uint8_t i2s_blocks_written; + struct feedback_ctx *fb; +}; + +static void uac2_terminal_update_cb(const struct device *dev, uint8_t terminal, + bool enabled, bool microframes, + void *user_data) +{ + struct usb_i2s_ctx *ctx = user_data; + + /* This sample has only one terminal therefore the callback can simply + * ignore the terminal variable. + */ + __ASSERT_NO_MSG(terminal == HEADPHONES_OUT_TERMINAL_ID); + /* This sample is for Full-Speed only devices. */ + __ASSERT_NO_MSG(microframes == false); + + ctx->terminal_enabled = enabled; + if (ctx->i2s_started && !enabled) { + i2s_trigger(ctx->i2s_dev, I2S_DIR_TX, I2S_TRIGGER_DROP); + ctx->i2s_started = false; + ctx->i2s_blocks_written = 0; + feedback_reset_ctx(ctx->fb); + } +} + +static void *uac2_get_recv_buf(const struct device *dev, uint8_t terminal, + uint16_t size, void *user_data) +{ + ARG_UNUSED(dev); + struct usb_i2s_ctx *ctx = user_data; + void *buf = NULL; + int ret; + + if (terminal == HEADPHONES_OUT_TERMINAL_ID) { + __ASSERT_NO_MSG(size <= MAX_BLOCK_SIZE); + + if (!ctx->terminal_enabled) { + LOG_ERR("Buffer request on disabled terminal"); + return NULL; + } + + ret = k_mem_slab_alloc(&i2s_tx_slab, &buf, K_NO_WAIT); + if (ret != 0) { + buf = NULL; + } + } + + return buf; +} + +static void uac2_data_recv_cb(const struct device *dev, uint8_t terminal, + void *buf, uint16_t size, void *user_data) +{ + struct usb_i2s_ctx *ctx = user_data; + int ret; + + if (!ctx->terminal_enabled) { + k_mem_slab_free(&i2s_tx_slab, buf); + return; + } + + if (!size) { + /* Zero fill to keep I2S going. If this is transient error, then + * this is probably best we can do. Otherwise, host will likely + * either disable terminal (or the cable will be disconnected) + * which will stop I2S. + */ + size = BLOCK_SIZE; + memset(buf, 0, size); + sys_cache_data_flush_range(buf, size); + } + + LOG_DBG("Received %d data to input terminal %d", size, terminal); + + ret = i2s_write(ctx->i2s_dev, buf, size); + if (ret < 0) { + ctx->i2s_started = false; + ctx->i2s_blocks_written = 0; + feedback_reset_ctx(ctx->fb); + + /* Most likely underrun occurred, prepare I2S restart */ + i2s_trigger(ctx->i2s_dev, I2S_DIR_TX, I2S_TRIGGER_PREPARE); + + ret = i2s_write(ctx->i2s_dev, buf, size); + if (ret < 0) { + /* Drop data block, will try again on next frame */ + k_mem_slab_free(&i2s_tx_slab, buf); + } + } + + if (ret == 0) { + ctx->i2s_blocks_written++; + } +} + +static void uac2_buf_release_cb(const struct device *dev, uint8_t terminal, + void *buf, void *user_data) +{ + /* This sample does not send audio data so this won't be called */ +} + +/* Variables for debug use to facilitate simple how feedback value affects + * audio data rate experiments. These debug variables can also be used to + * determine how well the feedback regulator deals with errors. The values + * are supposed to be modified by debugger. + * + * Setting use_hardcoded_feedback to true, essentially bypasses the feedback + * regulator and makes host send hardcoded_feedback samples every 16384 SOFs + * (when operating at Full-Speed). + * + * The feedback at Full-Speed is Q10.14 value. For 48 kHz audio sample rate, + * there are nominally 48 samples every SOF. The corresponding value is thus + * 48 << 14. Such feedback value would result in host sending always 48 samples. + * Now, if we want to receive more samples (because 1 ms according to audio + * sink is shorter than 1 ms according to USB Host 500 ppm SOF timer), then + * the feedback value has to be increased. The fractional part is 14-bit wide + * and therefore increment by 1 means 1 additional sample every 2**14 SOFs. + * (48 << 14) + 1 therefore results in host sending 48 samples 16383 times and + * 49 samples 1 time during every 16384 SOFs. + * + * Similarly, if we want to receive less samples (because 1 ms according to + * audio signk is longer than 1 ms according to USB Host), then the feedback + * value has to be decreased. (48 << 14) - 1 therefore results in host sending + * 48 samples 16383 times and 47 samples 1 time during every 16384 SOFs. + * + * If the feedback value differs by more than 1 (i.e. LSB), then the +1/-1 + * samples packets are generally evenly distributed. For example feedback value + * (48 << 14) + (1 << 5) results in 48 samples 511 times and 49 samples 1 time + * during every 512 SOFs. + * + * For High-Speed above changes slightly, because the feedback format is Q16.16 + * and microframes are used. The 48 kHz audio sample rate is achieved by sending + * 6 samples every SOF (microframe). The nominal value is the average number of + * samples to send every microframe and therefore for 48 kHz the nominal value + * is (6 << 16). + */ +static volatile bool use_hardcoded_feedback; +static volatile uint32_t hardcoded_feedback = (48 << 14) + 1; + +static uint32_t uac2_feedback_cb(const struct device *dev, uint8_t terminal, + void *user_data) +{ + /* Sample has only one UAC2 instance with one terminal so both can be + * ignored here. + */ + ARG_UNUSED(dev); + ARG_UNUSED(terminal); + struct usb_i2s_ctx *ctx = user_data; + + if (use_hardcoded_feedback) { + return hardcoded_feedback; + } else { + return feedback_value(ctx->fb); + } +} + +static void uac2_sof(const struct device *dev, void *user_data) +{ + ARG_UNUSED(dev); + struct usb_i2s_ctx *ctx = user_data; + + if (ctx->i2s_started) { + feedback_process(ctx->fb); + } + + /* We want to maintain 3 SOFs delay, i.e. samples received during SOF n + * should be on I2S during SOF n+3. This provides enough wiggle room + * for software scheduling that effectively eliminates "buffers not + * provided in time" problem. + * + * ">= 2" translates into 3 SOFs delay because the timeline is: + * USB SOF n + * OUT DATA0 n received from host + * USB SOF n+1 + * DATA0 n is available to UDC driver (See Universal Serial Bus + * Specification Revision 2.0 5.12.5 Data Prebuffering) and copied + * to I2S buffer before SOF n+2; i2s_blocks_written = 1 + * OUT DATA0 n+1 received from host + * USB SOF n+2 + * DATA0 n+1 is copied; i2s_block_written = 2 + * OUT DATA0 n+2 received from host + * USB SOF n+3 + * This function triggers I2S start + * DATA0 n+2 is copied; i2s_block_written is no longer relevant + * OUT DATA0 n+3 received from host + */ + if (!ctx->i2s_started && ctx->terminal_enabled && + ctx->i2s_blocks_written >= 2) { + i2s_trigger(ctx->i2s_dev, I2S_DIR_TX, I2S_TRIGGER_START); + ctx->i2s_started = true; + feedback_start(ctx->fb, ctx->i2s_blocks_written); + } +} + +static struct uac2_ops usb_audio_ops = { + .sof_cb = uac2_sof, + .terminal_update_cb = uac2_terminal_update_cb, + .get_recv_buf = uac2_get_recv_buf, + .data_recv_cb = uac2_data_recv_cb, + .buf_release_cb = uac2_buf_release_cb, + .feedback_cb = uac2_feedback_cb, +}; + +static struct usb_i2s_ctx main_ctx; + +int main(void) +{ + const struct device *dev = DEVICE_DT_GET(DT_NODELABEL(uac2_headphones)); + struct usbd_contex *sample_usbd; + struct i2s_config config; + int ret; + + main_ctx.i2s_dev = DEVICE_DT_GET(DT_NODELABEL(i2s_tx)); + + if (!device_is_ready(main_ctx.i2s_dev)) { + printk("%s is not ready\n", main_ctx.i2s_dev->name); + return 0; + } + + config.word_size = SAMPLE_BIT_WIDTH; + config.channels = NUMBER_OF_CHANNELS; + config.format = I2S_FMT_DATA_FORMAT_I2S; + config.options = I2S_OPT_BIT_CLK_MASTER | I2S_OPT_FRAME_CLK_MASTER; + config.frame_clk_freq = SAMPLE_FREQUENCY; + config.mem_slab = &i2s_tx_slab; + config.block_size = MAX_BLOCK_SIZE; + config.timeout = 0; + + ret = i2s_configure(main_ctx.i2s_dev, I2S_DIR_TX, &config); + if (ret < 0) { + printk("Failed to configure TX stream: %d\n", ret); + return 0; + } + + main_ctx.fb = feedback_init(); + + usbd_uac2_set_ops(dev, &usb_audio_ops, &main_ctx); + + sample_usbd = sample_usbd_init_device(); + if (sample_usbd == NULL) { + return -ENODEV; + } + + ret = usbd_enable(sample_usbd); + if (ret) { + return ret; + } + + return 0; +} From 9cd7564ab0432faf19316efcbe7caaa5223510c9 Mon Sep 17 00:00:00 2001 From: Gaetan Perrot Date: Wed, 27 Dec 2023 17:10:41 +0900 Subject: [PATCH 3308/3723] posix: pthread_testcancel zephyrproject-rtos#59946 Implement posix pthread_testcancel() signed-off-by: Gaetan Perrot --- include/zephyr/posix/pthread.h | 1 + lib/posix/options/pthread.c | 29 +++++++++++++++++++++++++++++ 2 files changed, 30 insertions(+) diff --git a/include/zephyr/posix/pthread.h b/include/zephyr/posix/pthread.h index 4cf6dcbe3d4..9b34c319b57 100644 --- a/include/zephyr/posix/pthread.h +++ b/include/zephyr/posix/pthread.h @@ -440,6 +440,7 @@ int pthread_create(pthread_t *newthread, const pthread_attr_t *attr, void *(*threadroutine)(void *), void *arg); int pthread_setcancelstate(int state, int *oldstate); int pthread_setcanceltype(int type, int *oldtype); +void pthread_testcancel(void); int pthread_attr_setschedparam(pthread_attr_t *attr, const struct sched_param *schedparam); int pthread_setschedparam(pthread_t pthread, int policy, diff --git a/lib/posix/options/pthread.c b/lib/posix/options/pthread.c index c4a1e490a33..98761f74064 100644 --- a/lib/posix/options/pthread.c +++ b/lib/posix/options/pthread.c @@ -679,6 +679,35 @@ int pthread_setcanceltype(int type, int *oldtype) return ret; } +/** + * @brief Create a cancellation point in the calling thread. + * + * See IEEE 1003.1 + */ +void pthread_testcancel(void) +{ + struct posix_thread *t; + bool cancel_pended = false; + + K_SPINLOCK(&pthread_pool_lock) { + t = to_posix_thread(pthread_self()); + if (t == NULL) { + K_SPINLOCK_BREAK; + } + if (t->attr.cancelstate != PTHREAD_CANCEL_ENABLE) { + K_SPINLOCK_BREAK; + } + if (t->attr.cancelpending) { + cancel_pended = true; + t->attr.cancelstate = PTHREAD_CANCEL_DISABLE; + } + } + + if (cancel_pended) { + posix_thread_finalize(t, PTHREAD_CANCELED); + } +} + /** * @brief Cancel execution of a thread. * From fe5806aff039f87e9a2c23a4f45fffd0bf1860f7 Mon Sep 17 00:00:00 2001 From: Gaetan Perrot Date: Tue, 9 Jan 2024 13:53:14 +0900 Subject: [PATCH 3309/3723] doc: posix: mark pthread_testcancel as supported `pthread_testcancel()` is now implemented, mark it so. signed-off-by: Gaetan Perrot --- doc/services/portability/posix/option_groups/index.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/doc/services/portability/posix/option_groups/index.rst b/doc/services/portability/posix/option_groups/index.rst index 729bd0c5803..7dd47616abb 100644 --- a/doc/services/portability/posix/option_groups/index.rst +++ b/doc/services/portability/posix/option_groups/index.rst @@ -64,7 +64,7 @@ multiple processes. pthread_setcanceltype(),yes pthread_setspecific(),yes pthread_sigmask(),yes - pthread_testcancel(), + pthread_testcancel(),yes .. _posix_option_group_posix_threads_ext: From 042b52250677d737eac5828411f50c43219311ea Mon Sep 17 00:00:00 2001 From: Gaetan Perrot Date: Sun, 28 Jan 2024 19:47:31 +0900 Subject: [PATCH 3310/3723] tests: posix: add tests for pthread_testcancel() Add tests for pthread_testcancel() signed-off-by: Gaetan Perrot --- tests/posix/common/src/pthread.c | 40 +++++++++++++++++++++++++++++ tests/posix/headers/src/pthread_h.c | 2 +- 2 files changed, 41 insertions(+), 1 deletion(-) diff --git a/tests/posix/common/src/pthread.c b/tests/posix/common/src/pthread.c index ffc408d9da4..184cb77e54f 100644 --- a/tests/posix/common/src/pthread.c +++ b/tests/posix/common/src/pthread.c @@ -487,6 +487,46 @@ ZTEST(pthread, test_pthread_cleanup) zassert_ok(pthread_join(th, NULL)); } +static bool testcancel_ignored; +static bool testcancel_failed; + +static void *test_pthread_cancel_fn(void *arg) +{ + zassert_ok(pthread_setcancelstate(PTHREAD_CANCEL_DISABLE, NULL)); + + testcancel_ignored = false; + + /* this should be ignored */ + pthread_testcancel(); + + testcancel_ignored = true; + + /* this will mark it pending */ + zassert_ok(pthread_cancel(pthread_self())); + + /* enable the thread to be cancelled */ + zassert_ok(pthread_setcancelstate(PTHREAD_CANCEL_ENABLE, NULL)); + + testcancel_failed = false; + + /* this should terminate the thread */ + pthread_testcancel(); + + testcancel_failed = true; + + return NULL; +} + +ZTEST(pthread, test_pthread_testcancel) +{ + pthread_t th; + + zassert_ok(pthread_create(&th, NULL, test_pthread_cancel_fn, NULL)); + zassert_ok(pthread_join(th, NULL)); + zassert_true(testcancel_ignored); + zassert_false(testcancel_failed); +} + static void before(void *arg) { ARG_UNUSED(arg); diff --git a/tests/posix/headers/src/pthread_h.c b/tests/posix/headers/src/pthread_h.c index 82e71c5c216..73467d14bf9 100644 --- a/tests/posix/headers/src/pthread_h.c +++ b/tests/posix/headers/src/pthread_h.c @@ -158,7 +158,7 @@ ZTEST(posix_headers, test_pthread_h) zassert_not_null(pthread_spin_lock); zassert_not_null(pthread_spin_trylock); zassert_not_null(pthread_spin_unlock); - /* zassert_not_null(pthread_testcancel); */ /* not implemented */ + zassert_not_null(pthread_testcancel); } } #pragma GCC diagnostic pop From cc9c90c7675ea976497b3ae566a7d0885aeb28fc Mon Sep 17 00:00:00 2001 From: Daniel Gaston Ochoa Date: Wed, 27 Dec 2023 22:10:26 +0000 Subject: [PATCH 3311/3723] devicetree: spi: stm32h7: Allow to enable SPI FIFO from DT Allow to enable/disable the STM32 SPI FIFO usage from devicetree. Signed-off-by: Daniel Gaston Ochoa --- drivers/spi/spi_ll_stm32.c | 5 ++++- drivers/spi/spi_ll_stm32.h | 1 + dts/bindings/spi/st,stm32h7-spi.yaml | 4 ++++ 3 files changed, 9 insertions(+), 1 deletion(-) diff --git a/drivers/spi/spi_ll_stm32.c b/drivers/spi/spi_ll_stm32.c index c222a624434..64bd6b1f093 100644 --- a/drivers/spi/spi_ll_stm32.c +++ b/drivers/spi/spi_ll_stm32.c @@ -1146,7 +1146,9 @@ static void spi_stm32_irq_config_func_##id(const struct device *dev) \ #define SPI_DMA_STATUS_SEM(id) #endif - +#define SPI_SUPPORTS_FIFO(id) DT_INST_NODE_HAS_PROP(id, fifo_enable) +#define SPI_GET_FIFO_PROP(id) DT_INST_PROP(id, fifo_enable) +#define SPI_FIFO_ENABLED(id) COND_CODE_1(SPI_SUPPORTS_FIFO(id), (SPI_GET_FIFO_PROP(id)), (0)) #define STM32_SPI_INIT(id) \ STM32_SPI_IRQ_HANDLER_DECL(id); \ @@ -1161,6 +1163,7 @@ static const struct spi_stm32_config spi_stm32_cfg_##id = { \ .pclken = pclken_##id, \ .pclk_len = DT_INST_NUM_CLOCKS(id), \ .pcfg = PINCTRL_DT_INST_DEV_CONFIG_GET(id), \ + .fifo_enabled = SPI_FIFO_ENABLED(id), \ STM32_SPI_IRQ_HANDLER_FUNC(id) \ IF_ENABLED(DT_HAS_COMPAT_STATUS_OKAY(st_stm32_spi_subghz), \ (.use_subghzspi_nss = \ diff --git a/drivers/spi/spi_ll_stm32.h b/drivers/spi/spi_ll_stm32.h index c241750c63e..23a08e24208 100644 --- a/drivers/spi/spi_ll_stm32.h +++ b/drivers/spi/spi_ll_stm32.h @@ -34,6 +34,7 @@ struct spi_stm32_config { #endif size_t pclk_len; const struct stm32_pclken *pclken; + bool fifo_enabled; }; #ifdef CONFIG_SPI_STM32_DMA diff --git a/dts/bindings/spi/st,stm32h7-spi.yaml b/dts/bindings/spi/st,stm32h7-spi.yaml index a1082fff7c4..69f1a8c52ae 100644 --- a/dts/bindings/spi/st,stm32h7-spi.yaml +++ b/dts/bindings/spi/st,stm32h7-spi.yaml @@ -27,3 +27,7 @@ properties: description: | (Master SS Idleness) minimum clock inserted between start and first data transaction. + + fifo-enable: + type: boolean + description: Enable the SPI FIFO usage for performance improvement. From eb78d4dfdeae7888c7a37137cb4d8486a86abe72 Mon Sep 17 00:00:00 2001 From: Daniel Gaston Ochoa Date: Thu, 16 Nov 2023 10:47:49 +0000 Subject: [PATCH 3312/3723] drivers: spi: stm32h7: Use transferSize and EOT Set the transfer size in SPI H7 and check EOT instead of TXC to be sure the transaction has finished. This is required to enable the use of the SPI FIFO, as otherwise SPI seems to operate in "continuous mode", which produces several SCK cycles after the last frame has been sent/received. More details in the PR. Signed-off-by: Daniel Gaston Ochoa --- drivers/spi/spi_ll_stm32.c | 82 ++++++++++++++++++++++++++++++++++++++ 1 file changed, 82 insertions(+) diff --git a/drivers/spi/spi_ll_stm32.c b/drivers/spi/spi_ll_stm32.c index 64bd6b1f093..62e3f030196 100644 --- a/drivers/spi/spi_ll_stm32.c +++ b/drivers/spi/spi_ll_stm32.c @@ -437,6 +437,13 @@ static void spi_stm32_complete(const struct device *dev, int status) ll_func_disable_int_tx_empty(spi); ll_func_disable_int_rx_not_empty(spi); ll_func_disable_int_errors(spi); + +#if DT_HAS_COMPAT_STATUS_OKAY(st_stm32h7_spi) + if (cfg->fifo_enabled) { + LL_SPI_DisableIT_EOT(spi); + } +#endif /* DT_HAS_COMPAT_STATUS_OKAY(st_stm32h7_spi) */ + #endif @@ -460,6 +467,15 @@ static void spi_stm32_complete(const struct device *dev, int status) LL_SPI_ClearFlag_MODF(spi); } +#if DT_HAS_COMPAT_STATUS_OKAY(st_stm32h7_spi) + if (cfg->fifo_enabled) { + LL_SPI_ClearFlag_TXTF(spi); + LL_SPI_ClearFlag_OVR(spi); + LL_SPI_ClearFlag_EOT(spi); + LL_SPI_SetTransferSize(spi, 0); + } +#endif /* DT_HAS_COMPAT_STATUS_OKAY(st_stm32h7_spi) */ + ll_func_disable_spi(spi); #ifdef CONFIG_SPI_STM32_INTERRUPT @@ -651,6 +667,52 @@ static int spi_stm32_release(const struct device *dev, return 0; } +#if DT_HAS_COMPAT_STATUS_OKAY(st_stm32h7_spi) +static int32_t spi_stm32_count_bufset_frames(const struct spi_config *config, + const struct spi_buf_set *bufs) +{ + if (bufs == NULL) { + return 0; + } + + uint32_t num_bytes = 0; + + for (size_t i = 0; i < bufs->count; i++) { + num_bytes += bufs->buffers[i].len; + } + + uint8_t bytes_per_frame = SPI_WORD_SIZE_GET(config->operation) / 8; + + if ((num_bytes % bytes_per_frame) != 0) { + return -EINVAL; + } + return num_bytes / bytes_per_frame; +} + +static int32_t spi_stm32_count_total_frames(const struct spi_config *config, + const struct spi_buf_set *tx_bufs, + const struct spi_buf_set *rx_bufs) +{ + int tx_frames = spi_stm32_count_bufset_frames(config, tx_bufs); + + if (tx_frames < 0) { + return tx_frames; + } + + int rx_frames = spi_stm32_count_bufset_frames(config, rx_bufs); + + if (rx_frames < 0) { + return rx_frames; + } + + if (tx_frames > UINT16_MAX || rx_frames > UINT16_MAX) { + return -EMSGSIZE; + } + + return MAX(rx_frames, tx_frames); +} +#endif /* DT_HAS_COMPAT_STATUS_OKAY(st_stm32h7_spi) */ + static int transceive(const struct device *dev, const struct spi_config *config, const struct spi_buf_set *tx_bufs, @@ -688,6 +750,19 @@ static int transceive(const struct device *dev, spi_context_buffers_setup(&data->ctx, tx_bufs, rx_bufs, 2); } +#if DT_HAS_COMPAT_STATUS_OKAY(st_stm32h7_spi) + if (cfg->fifo_enabled && SPI_OP_MODE_GET(config->operation) == SPI_OP_MODE_MASTER) { + int total_frames = spi_stm32_count_total_frames( + config, tx_bufs, rx_bufs); + if (total_frames < 0) { + ret = total_frames; + goto end; + } + LL_SPI_SetTransferSize(spi, (uint32_t)total_frames); + } + +#endif /* DT_HAS_COMPAT_STATUS_OKAY(st_stm32h7_spi) */ + #if DT_HAS_COMPAT_STATUS_OKAY(st_stm32_spi_fifo) /* Flush RX buffer */ while (ll_func_rx_is_not_empty(spi)) { @@ -723,6 +798,13 @@ static int transceive(const struct device *dev, spi_stm32_cs_control(dev, true); #ifdef CONFIG_SPI_STM32_INTERRUPT + +#if DT_HAS_COMPAT_STATUS_OKAY(st_stm32h7_spi) + if (cfg->fifo_enabled) { + LL_SPI_EnableIT_EOT(spi); + } +#endif /* DT_HAS_COMPAT_STATUS_OKAY(st_stm32h7_spi) */ + ll_func_enable_int_errors(spi); if (rx_bufs) { From 9991d2ba656ddbf9186badb9c454778354660488 Mon Sep 17 00:00:00 2001 From: Daniel Gaston Ochoa Date: Wed, 27 Dec 2023 21:25:39 +0000 Subject: [PATCH 3313/3723] drivers: spi: stm32h7: Use SPI FIFO Allow to use H7 SPI FIFO to improve performance. SPI FIFO usage can be enabled/disabled from devicetree. Signed-off-by: Daniel Gaston Ochoa --- drivers/spi/spi_ll_stm32.c | 53 +++++++++++++++++++++++++------------- 1 file changed, 35 insertions(+), 18 deletions(-) diff --git a/drivers/spi/spi_ll_stm32.c b/drivers/spi/spi_ll_stm32.c index 62e3f030196..7e1d7faf18e 100644 --- a/drivers/spi/spi_ll_stm32.c +++ b/drivers/spi/spi_ll_stm32.c @@ -338,20 +338,36 @@ static int spi_stm32_get_err(SPI_TypeDef *spi) return 0; } -/* Shift a SPI frame as master. */ -static void spi_stm32_shift_m(SPI_TypeDef *spi, struct spi_stm32_data *data) +static void spi_stm32_shift_fifo(SPI_TypeDef *spi, struct spi_stm32_data *data) { - while (!ll_func_tx_is_not_full(spi)) { - /* NOP */ + if (ll_func_rx_is_not_empty(spi)) { + spi_stm32_read_next_frame(spi, data); } - spi_stm32_send_next_frame(spi, data); - - while (!ll_func_rx_is_not_empty(spi)) { - /* NOP */ + if (ll_func_tx_is_not_full(spi)) { + spi_stm32_send_next_frame(spi, data); } +} - spi_stm32_read_next_frame(spi, data); +/* Shift a SPI frame as master. */ +static void spi_stm32_shift_m(const struct spi_stm32_config *cfg, + struct spi_stm32_data *data) +{ + if (cfg->fifo_enabled) { + spi_stm32_shift_fifo(cfg->spi, data); + } else { + while (!ll_func_tx_is_not_full(cfg->spi)) { + /* NOP */ + } + + spi_stm32_send_next_frame(cfg->spi, data); + + while (!ll_func_rx_is_not_empty(cfg->spi)) { + /* NOP */ + } + + spi_stm32_read_next_frame(cfg->spi, data); + } } /* Shift a SPI frame as slave. */ @@ -395,17 +411,18 @@ static void spi_stm32_shift_s(SPI_TypeDef *spi, struct spi_stm32_data *data) * * TODO: support 16-bit data frames. */ -static int spi_stm32_shift_frames(SPI_TypeDef *spi, struct spi_stm32_data *data) +static int spi_stm32_shift_frames(const struct spi_stm32_config *cfg, + struct spi_stm32_data *data) { uint16_t operation = data->ctx.config->operation; if (SPI_OP_MODE_GET(operation) == SPI_OP_MODE_MASTER) { - spi_stm32_shift_m(spi, data); + spi_stm32_shift_m(cfg, data); } else { - spi_stm32_shift_s(spi, data); + spi_stm32_shift_s(cfg->spi, data); } - return spi_stm32_get_err(spi); + return spi_stm32_get_err(cfg->spi); } static void spi_stm32_cs_control(const struct device *dev, bool on) @@ -498,7 +515,7 @@ static void spi_stm32_isr(const struct device *dev) } if (spi_stm32_transfer_ongoing(data)) { - err = spi_stm32_shift_frames(spi, data); + err = spi_stm32_shift_frames(cfg, data); } if (err || !spi_stm32_transfer_ongoing(data)) { @@ -669,7 +686,7 @@ static int spi_stm32_release(const struct device *dev, #if DT_HAS_COMPAT_STATUS_OKAY(st_stm32h7_spi) static int32_t spi_stm32_count_bufset_frames(const struct spi_config *config, - const struct spi_buf_set *bufs) + const struct spi_buf_set *bufs) { if (bufs == NULL) { return 0; @@ -690,8 +707,8 @@ static int32_t spi_stm32_count_bufset_frames(const struct spi_config *config, } static int32_t spi_stm32_count_total_frames(const struct spi_config *config, - const struct spi_buf_set *tx_bufs, - const struct spi_buf_set *rx_bufs) + const struct spi_buf_set *tx_bufs, + const struct spi_buf_set *rx_bufs) { int tx_frames = spi_stm32_count_bufset_frames(config, tx_bufs); @@ -816,7 +833,7 @@ static int transceive(const struct device *dev, ret = spi_context_wait_for_completion(&data->ctx); #else do { - ret = spi_stm32_shift_frames(spi, data); + ret = spi_stm32_shift_frames(cfg, data); } while (!ret && spi_stm32_transfer_ongoing(data)); spi_stm32_complete(dev, ret); From 4c88deaa82424024d64f4e58aae59dca91f467ac Mon Sep 17 00:00:00 2001 From: Daniel Gaston Ochoa Date: Sun, 28 Jan 2024 11:18:42 +0000 Subject: [PATCH 3314/3723] drivers: spi: stm32h7: Ignore spurious interrupts Supurious interrupts can be generated when the SPI device is disabled. Ignore them within the SPI IRQ handler. Co-authored-by: Georgij Cernysiov Signed-off-by: Daniel Gaston Ochoa --- drivers/spi/spi_ll_stm32.c | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/drivers/spi/spi_ll_stm32.c b/drivers/spi/spi_ll_stm32.c index 7e1d7faf18e..7f444f664ba 100644 --- a/drivers/spi/spi_ll_stm32.c +++ b/drivers/spi/spi_ll_stm32.c @@ -508,6 +508,15 @@ static void spi_stm32_isr(const struct device *dev) SPI_TypeDef *spi = cfg->spi; int err; + /* Some spurious interrupts are triggered when SPI is not enabled; ignore them. + * Do it only when fifo is enabled to leave non-fifo functionality untouched for now + */ + if (cfg->fifo_enabled) { + if (!LL_SPI_IsEnabled(spi)) { + return; + } + } + err = spi_stm32_get_err(spi); if (err) { spi_stm32_complete(dev, err); From efb5d8372d7583340c91d70fc4973d1b33780331 Mon Sep 17 00:00:00 2001 From: Luis Ubieda Date: Mon, 29 Jan 2024 16:31:50 -0500 Subject: [PATCH 3315/3723] Bluetooth: Host: Added Recycled evt notifying conn object is available - Which allow listeners to attempt to use the freed connection object to perform actions as e.g: start connectable advertisements. - Refactored bt_conn_unref() so it does not access conn struct after decrementing its reference count. Signed-off-by: Luis Ubieda --- include/zephyr/bluetooth/conn.h | 14 ++++++++++ subsys/bluetooth/host/conn.c | 48 ++++++++++++++++++++++++++++++--- 2 files changed, 59 insertions(+), 3 deletions(-) diff --git a/include/zephyr/bluetooth/conn.h b/include/zephyr/bluetooth/conn.h index df79a8967f9..f934ea54162 100644 --- a/include/zephyr/bluetooth/conn.h +++ b/include/zephyr/bluetooth/conn.h @@ -1000,6 +1000,20 @@ struct bt_conn_cb { */ void (*disconnected)(struct bt_conn *conn, uint8_t reason); + /** @brief A connection object has been returned to the pool. + * + * This callback notifies the application that it might be able to + * allocate a connection object. No guarantee, first come, first serve. + * + * Use this to e.g. re-start connectable advertising or scanning. + * + * Treat this callback as an ISR, as it originates from + * @ref bt_conn_unref which is used by the BT stack. Making + * Bluetooth API calls in this context is error-prone and strongly + * discouraged. + */ + void (*recycled)(void); + /** @brief LE connection parameter update request. * * This callback notifies the application that a remote device diff --git a/subsys/bluetooth/host/conn.c b/subsys/bluetooth/host/conn.c index 58c39136ef9..cad3cf32f23 100644 --- a/subsys/bluetooth/host/conn.c +++ b/subsys/bluetooth/host/conn.c @@ -85,6 +85,8 @@ static void conn_tx_destroy(struct bt_conn *conn, struct bt_conn_tx *tx) static void tx_complete_work(struct k_work *work); #endif /* CONFIG_BT_CONN_TX */ +static void notify_recycled_conn_slot(void); + /* Group Connected BT_CONN only in this */ #if defined(CONFIG_BT_CONN) /* Peripheral timeout to initialize Connection Parameter Update procedure */ @@ -1311,15 +1313,38 @@ struct bt_conn *bt_conn_ref(struct bt_conn *conn) void bt_conn_unref(struct bt_conn *conn) { atomic_val_t old; + bool deallocated; + enum bt_conn_type conn_type; + uint8_t conn_role; + uint16_t conn_handle; + + __ASSERT(conn, "Invalid connection reference"); + + /* Storing parameters of interest so we don't access the object + * after decrementing its ref-count + */ + conn_type = conn->type; + conn_role = conn->role; + conn_handle = conn->handle; old = atomic_dec(&conn->ref); + /* Prevent from accessing connection object */ + conn = NULL; + deallocated = (atomic_get(&old) == 1); - LOG_DBG("handle %u ref %ld -> %ld", conn->handle, old, atomic_get(&conn->ref)); + LOG_DBG("handle %u ref %ld -> %ld", conn_handle, old, (old - 1)); __ASSERT(old > 0, "Conn reference counter is 0"); - if (IS_ENABLED(CONFIG_BT_PERIPHERAL) && conn->type == BT_CONN_TYPE_LE && - conn->role == BT_CONN_ROLE_PERIPHERAL && atomic_get(&conn->ref) == 0) { + /* Slot has been freed and can be taken. No guarantees are made on requests + * to claim connection object as only the first claim will be served. + */ + if (deallocated) { + notify_recycled_conn_slot(); + } + + if (IS_ENABLED(CONFIG_BT_PERIPHERAL) && conn_type == BT_CONN_TYPE_LE && + conn_role == BT_CONN_ROLE_PERIPHERAL && deallocated) { bt_le_adv_resume(); } } @@ -1431,6 +1456,23 @@ static void tx_complete_work(struct k_work *work) } #endif /* CONFIG_BT_CONN_TX */ +static void notify_recycled_conn_slot(void) +{ +#if defined(CONFIG_BT_CONN) + for (struct bt_conn_cb *cb = callback_list; cb; cb = cb->_next) { + if (cb->recycled) { + cb->recycled(); + } + } + + STRUCT_SECTION_FOREACH(bt_conn_cb, cb) { + if (cb->recycled) { + cb->recycled(); + } + } +#endif +} + /* Group Connected BT_CONN only in this */ #if defined(CONFIG_BT_CONN) From 56e2e7608dae0cee9b5d4c1df631d4b2a7d53007 Mon Sep 17 00:00:00 2001 From: Luis Ubieda Date: Mon, 29 Jan 2024 22:22:33 -0500 Subject: [PATCH 3316/3723] doc: releases: release-notes: 3.6: bt: Added recycled cb info Added on the bt_conn_cb set, used to notify listeners that a previously allocated connection object has been freed. Used for e.g: restart extended advertisements. Signed-off-by: Luis Ubieda --- doc/releases/release-notes-3.6.rst | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/doc/releases/release-notes-3.6.rst b/doc/releases/release-notes-3.6.rst index 243a56a4179..4885510387f 100644 --- a/doc/releases/release-notes-3.6.rst +++ b/doc/releases/release-notes-3.6.rst @@ -52,6 +52,10 @@ Bluetooth * Host + * Added ``recycled()`` callback to :c:struct:`bt_conn_cb`, which notifies listeners when a + connection object has been freed, so it can be utilized for different purposes. No guarantees + are made to what listener will be granted the object, as only the first claim is served. + * Mesh * Added the delayable messages functionality to apply random delays for From 7e5b2a79fc55a7aaf5813441f07fef6d5e22d7c4 Mon Sep 17 00:00:00 2001 From: Luis Ubieda Date: Mon, 29 Jan 2024 22:31:38 -0500 Subject: [PATCH 3317/3723] Tests: Bluetooth: Host: Added Test for extended Advertisements Where extended advertising is restablished through the use of recycled() callback, registers over bt_conn_cb_register(). Signed-off-by: Luis Ubieda --- .../host/adv/extended/CMakeLists.txt | 18 ++ .../bsim/bluetooth/host/adv/extended/prj.conf | 5 + .../bluetooth/host/adv/extended/src/common.h | 53 ++++ .../adv/extended/src/ext_adv_advertiser.c | 233 ++++++++++++++++++ .../host/adv/extended/src/ext_adv_scanner.c | 201 +++++++++++++++ .../bluetooth/host/adv/extended/src/main.c | 39 +++ .../adv/extended/tests_scripts/ext_adv.sh | 29 +++ .../extended/tests_scripts/ext_adv_conn.sh | 31 +++ tests/bsim/bluetooth/host/compile.sh | 1 + 9 files changed, 610 insertions(+) create mode 100644 tests/bsim/bluetooth/host/adv/extended/CMakeLists.txt create mode 100644 tests/bsim/bluetooth/host/adv/extended/prj.conf create mode 100644 tests/bsim/bluetooth/host/adv/extended/src/common.h create mode 100644 tests/bsim/bluetooth/host/adv/extended/src/ext_adv_advertiser.c create mode 100644 tests/bsim/bluetooth/host/adv/extended/src/ext_adv_scanner.c create mode 100644 tests/bsim/bluetooth/host/adv/extended/src/main.c create mode 100755 tests/bsim/bluetooth/host/adv/extended/tests_scripts/ext_adv.sh create mode 100755 tests/bsim/bluetooth/host/adv/extended/tests_scripts/ext_adv_conn.sh diff --git a/tests/bsim/bluetooth/host/adv/extended/CMakeLists.txt b/tests/bsim/bluetooth/host/adv/extended/CMakeLists.txt new file mode 100644 index 00000000000..a2eb1e0e071 --- /dev/null +++ b/tests/bsim/bluetooth/host/adv/extended/CMakeLists.txt @@ -0,0 +1,18 @@ +# Copyright 2024 Croxel, Inc. +# SPDX-License-Identifier: Apache-2.0 + +cmake_minimum_required(VERSION 3.20.0) + +find_package(Zephyr REQUIRED HINTS $ENV{ZEPHYR_BASE}) +project(bsim_test_ext_adv) + +target_sources(app PRIVATE + src/main.c + src/ext_adv_advertiser.c + src/ext_adv_scanner.c +) + +zephyr_include_directories( + ${BSIM_COMPONENTS_PATH}/libUtilv1/src/ + ${BSIM_COMPONENTS_PATH}/libPhyComv1/src/ +) diff --git a/tests/bsim/bluetooth/host/adv/extended/prj.conf b/tests/bsim/bluetooth/host/adv/extended/prj.conf new file mode 100644 index 00000000000..495cb730daf --- /dev/null +++ b/tests/bsim/bluetooth/host/adv/extended/prj.conf @@ -0,0 +1,5 @@ +CONFIG_BT=y +CONFIG_BT_DEVICE_NAME="test_ext_adv" +CONFIG_BT_PERIPHERAL=y +CONFIG_BT_CENTRAL=y +CONFIG_BT_EXT_ADV=y diff --git a/tests/bsim/bluetooth/host/adv/extended/src/common.h b/tests/bsim/bluetooth/host/adv/extended/src/common.h new file mode 100644 index 00000000000..658613892e1 --- /dev/null +++ b/tests/bsim/bluetooth/host/adv/extended/src/common.h @@ -0,0 +1,53 @@ +/** + * Copyright (c) 2024 Croxel, Inc. + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#ifndef ZEPHYR_TEST_BSIM_BT_EXT_ADV_TEST_ +#define ZEPHYR_TEST_BSIM_BT_EXT_ADV_TEST_ + +#include + +#include "bs_types.h" +#include "bs_tracing.h" +#include "time_machine.h" +#include "bstests.h" + +#define WAIT_SECONDS 30 /* seconds */ +#define WAIT_TIME (WAIT_SECONDS * USEC_PER_SEC) /* microseconds*/ + +#define CREATE_FLAG(flag) static atomic_t flag = (atomic_t)false +#define SET_FLAG(flag) (void)atomic_set(&flag, (atomic_t) true) +#define TEST_FLAG(flag) (atomic_get(&flag) == (atomic_t)true) +#define UNSET_FLAG(flag) (void)atomic_set(&flag, (atomic_t) false) +#define WAIT_FOR_FLAG(flag) \ + while (!(bool)atomic_get(&flag)) { \ + (void)k_sleep(K_MSEC(1)); \ + } +#define WAIT_FOR_FLAG_UNSET(flag) \ + while ((bool)atomic_get(&flag)) { \ + (void)k_sleep(K_MSEC(1)); \ + } +#define TAKE_FLAG(flag) \ + while (!(bool)atomic_cas(&flag, true, false)) { \ + (void)k_sleep(K_MSEC(1)); \ + } + + +#define FAIL(...) \ + do { \ + bst_result = Failed; \ + bs_trace_error_time_line(__VA_ARGS__); \ + } while (0) + +#define PASS(...) \ + do { \ + bst_result = Passed; \ + bs_trace_info_time(1, "PASSED: " __VA_ARGS__); \ + } while (0) + +void test_tick(bs_time_t HW_device_time); +void test_init(void); + +#endif /* ZEPHYR_TEST_BSIM_BT_EXT_ADV_TEST_ */ diff --git a/tests/bsim/bluetooth/host/adv/extended/src/ext_adv_advertiser.c b/tests/bsim/bluetooth/host/adv/extended/src/ext_adv_advertiser.c new file mode 100644 index 00000000000..8c5332bdc67 --- /dev/null +++ b/tests/bsim/bluetooth/host/adv/extended/src/ext_adv_advertiser.c @@ -0,0 +1,233 @@ +/** + * Copyright (c) 2024 Croxel, Inc. + * + * SPDX-License-Identifier: Apache-2.0 + */ +#include + +#include "common.h" + +#include "bs_types.h" +#include "bs_tracing.h" +#include "time_machine.h" +#include "bstests.h" + +#include +#include + +#include +#include + +extern enum bst_result_t bst_result; + +static struct bt_conn *g_conn; + +CREATE_FLAG(flag_connected); +CREATE_FLAG(flag_conn_recycled); + +static void common_init(void) +{ + int err; + + err = bt_enable(NULL); + + if (err) { + FAIL("Bluetooth init failed: %d\n", err); + return; + } + printk("Bluetooth initialized\n"); +} + +static void create_ext_adv_set(struct bt_le_ext_adv **adv, bool connectable) +{ + int err; + + printk("Creating extended advertising set..."); + + const struct bt_le_adv_param *adv_param = connectable ? + BT_LE_EXT_ADV_CONN_NAME : BT_LE_EXT_ADV_NCONN_NAME; + + err = bt_le_ext_adv_create(adv_param, NULL, adv); + if (err) { + printk("Failed to create advertising set: %d\n", err); + return; + } + printk("done.\n"); +} + +static void start_ext_adv_set(struct bt_le_ext_adv *adv) +{ + int err; + + printk("Starting Extended Advertising..."); + err = bt_le_ext_adv_start(adv, BT_LE_EXT_ADV_START_DEFAULT); + if (err) { + printk("Failed to start extended advertising: %d\n", err); + return; + } + printk("done.\n"); +} + +static void stop_ext_adv_set(struct bt_le_ext_adv *adv) +{ + int err; + + printk("Stopping Extended Advertising..."); + err = bt_le_ext_adv_stop(adv); + if (err) { + printk("Failed to stop extended advertising: %d\n", + err); + return; + } + printk("done.\n"); +} + +static void delete_adv_set(struct bt_le_ext_adv *adv) +{ + int err; + + printk("Delete extended advertising set..."); + err = bt_le_ext_adv_delete(adv); + if (err) { + printk("Failed Delete extended advertising set: %d\n", err); + return; + } + printk("done.\n"); +} + +static void disconnect_from_target(void) +{ + int err; + + printk("Disconnecting...\n"); + + err = bt_conn_disconnect(g_conn, BT_HCI_ERR_REMOTE_USER_TERM_CONN); + if (err) { + FAIL("BT Disconnect failed: %d\n", err); + return; + } +} + +static void connected(struct bt_conn *conn, uint8_t err) +{ + char addr[BT_ADDR_LE_STR_LEN]; + + bt_addr_le_to_str(bt_conn_get_dst(conn), addr, sizeof(addr)); + + if (err != BT_HCI_ERR_SUCCESS) { + FAIL("Failed to connect to %s: %u\n", addr, err); + return; + } + + printk("Connected to %s\n", addr); + if (g_conn != NULL) { + FAIL("Attempt to override connection object without clean-up\n"); + return; + } + g_conn = bt_conn_ref(conn); + SET_FLAG(flag_connected); +} + +static void disconnected(struct bt_conn *conn, uint8_t reason) +{ + char addr[BT_ADDR_LE_STR_LEN]; + + bt_addr_le_to_str(bt_conn_get_dst(conn), addr, sizeof(addr)); + + printk("Disconnected: %s (reason %u)\n", addr, reason); + + bt_conn_unref(g_conn); + g_conn = NULL; +} + +static void recycled(void) +{ + SET_FLAG(flag_conn_recycled); +} + +static struct bt_conn_cb conn_cbs = { + .connected = connected, + .disconnected = disconnected, + .recycled = recycled, +}; + +static void main_ext_adv_advertiser(void) +{ + struct bt_le_ext_adv *ext_adv; + + common_init(); + + create_ext_adv_set(&ext_adv, false); + start_ext_adv_set(ext_adv); + + /* Advertise for a bit */ + k_sleep(K_SECONDS(5)); + + stop_ext_adv_set(ext_adv); + delete_adv_set(ext_adv); + + ext_adv = NULL; + + PASS("Extended advertiser passed\n"); +} + +static void main_ext_conn_adv_advertiser(void) +{ + struct bt_le_ext_adv *ext_adv; + + common_init(); + + bt_conn_cb_register(&conn_cbs); + + create_ext_adv_set(&ext_adv, true); + start_ext_adv_set(ext_adv); + + printk("Waiting for connection...\n"); + WAIT_FOR_FLAG(flag_connected); + + disconnect_from_target(); + + printk("Waiting for Connection object to be recycled...\n"); + WAIT_FOR_FLAG(flag_conn_recycled); + + stop_ext_adv_set(ext_adv); + delete_adv_set(ext_adv); + + create_ext_adv_set(&ext_adv, false); + start_ext_adv_set(ext_adv); + + /* Advertise for a bit */ + k_sleep(K_SECONDS(5)); + + stop_ext_adv_set(ext_adv); + delete_adv_set(ext_adv); + + ext_adv = NULL; + + PASS("Extended advertiser passed\n"); +} + +static const struct bst_test_instance ext_adv_advertiser[] = { + { + .test_id = "ext_adv_advertiser", + .test_descr = "Basic extended advertising test. " + "Will just start extended advertising.", + .test_post_init_f = test_init, + .test_tick_f = test_tick, + .test_main_f = main_ext_adv_advertiser + }, + { + .test_id = "ext_adv_conn_advertiser", + .test_descr = "Basic connectable extended advertising test. " + "Starts extended advertising, and restarts it after disconnecting", + .test_post_init_f = test_init, + .test_tick_f = test_tick, + .test_main_f = main_ext_conn_adv_advertiser + }, + BSTEST_END_MARKER +}; + +struct bst_test_list *test_ext_adv_advertiser(struct bst_test_list *tests) +{ + return bst_add_tests(tests, ext_adv_advertiser); +} diff --git a/tests/bsim/bluetooth/host/adv/extended/src/ext_adv_scanner.c b/tests/bsim/bluetooth/host/adv/extended/src/ext_adv_scanner.c new file mode 100644 index 00000000000..17b37f31dc1 --- /dev/null +++ b/tests/bsim/bluetooth/host/adv/extended/src/ext_adv_scanner.c @@ -0,0 +1,201 @@ +/** + * Copyright (c) 2024 Croxel, Inc. + * + * SPDX-License-Identifier: Apache-2.0 + */ +#include + +#include "common.h" + +#include "bs_types.h" +#include "bs_tracing.h" +#include "time_machine.h" +#include "bstests.h" + +#include +#include + +#include +#include + +extern enum bst_result_t bst_result; + +static struct bt_conn *g_conn; + +CREATE_FLAG(flag_ext_adv_seen); +CREATE_FLAG(flag_connected); +CREATE_FLAG(flag_conn_recycled); + +static void connected(struct bt_conn *conn, uint8_t err) +{ + char addr[BT_ADDR_LE_STR_LEN]; + + bt_addr_le_to_str(bt_conn_get_dst(conn), addr, sizeof(addr)); + + if (err != BT_HCI_ERR_SUCCESS) { + FAIL("Failed to connect to %s: %u\n", addr, err); + bt_conn_unref(g_conn); + g_conn = NULL; + return; + } + + printk("Connected to %s\n", addr); + SET_FLAG(flag_connected); +} + +static void disconnected(struct bt_conn *conn, uint8_t reason) +{ + char addr[BT_ADDR_LE_STR_LEN]; + + bt_addr_le_to_str(bt_conn_get_dst(conn), addr, sizeof(addr)); + + printk("Disconnected: %s (reason %u)\n", addr, reason); + + bt_conn_unref(g_conn); + g_conn = NULL; + + UNSET_FLAG(flag_connected); +} + +static void recycled(void) +{ + SET_FLAG(flag_conn_recycled); +} + +static struct bt_conn_cb conn_cbs = { + .connected = connected, + .disconnected = disconnected, + .recycled = recycled, +}; + + +static void scan_recv(const struct bt_le_scan_recv_info *info, + struct net_buf_simple *buf) +{ + printk("Found advertisement. Adv-type: 0x%02x, Adv-prop: 0x%02x\n", + info->adv_type, info->adv_props); + + if (info->adv_type & BT_GAP_ADV_TYPE_EXT_ADV && + info->adv_props & BT_GAP_ADV_PROP_EXT_ADV) { + printk("Found extended advertisement!\n"); + SET_FLAG(flag_ext_adv_seen); + } + + if (!TEST_FLAG(flag_connected) && + info->adv_props & BT_GAP_ADV_PROP_CONNECTABLE) { + int err; + + printk("Stopping scan\n"); + err = bt_le_scan_stop(); + if (err) { + FAIL("Failed to stop scan: %d", err); + return; + } + + err = bt_conn_le_create(info->addr, BT_CONN_LE_CREATE_CONN, + BT_LE_CONN_PARAM_DEFAULT, &g_conn); + if (err) { + FAIL("Could not connect to peer: %d", err); + return; + } + } +} + +static struct bt_le_scan_cb scan_callbacks = { + .recv = scan_recv, +}; + +static void common_init(void) +{ + int err = 0; + + err = bt_enable(NULL); + + if (err) { + FAIL("Bluetooth init failed: %d\n", err); + return; + } + + bt_conn_cb_register(&conn_cbs); + bt_le_scan_cb_register(&scan_callbacks); + + printk("Bluetooth initialized\n"); +} + +static void start_scan(void) +{ + int err; + + printk("Start scanning..."); + err = bt_le_scan_start(BT_LE_SCAN_PASSIVE, NULL); + if (err) { + FAIL("Failed to start scan: %d\n", err); + return; + } + printk("done.\n"); +} + +static void main_ext_adv_scanner(void) +{ + common_init(); + start_scan(); + + printk("Waiting for extended advertisements...\n"); + + WAIT_FOR_FLAG(flag_ext_adv_seen); + + PASS("Extended adv scanner passed\n"); +} + +static void main_ext_adv_conn_scanner(void) +{ + common_init(); + start_scan(); + + printk("Waiting for extended advertisements...\n"); + WAIT_FOR_FLAG(flag_ext_adv_seen); + + printk("Waiting for connection with device...\n"); + WAIT_FOR_FLAG(flag_connected); + + printk("Waiting for device disconnection...\n"); + WAIT_FOR_FLAG_UNSET(flag_connected); + + printk("Waiting for Connection object to be recycled...\n"); + WAIT_FOR_FLAG(flag_conn_recycled); + + printk("Clearing flag for seen extended advertisements...\n"); + UNSET_FLAG(flag_ext_adv_seen); + + start_scan(); + + printk("Waiting to extended advertisements (again)...\n"); + WAIT_FOR_FLAG(flag_ext_adv_seen); + + PASS("Extended adv scanner passed\n"); +} + +static const struct bst_test_instance ext_adv_scanner[] = { + { + .test_id = "ext_adv_scanner", + .test_descr = "Basic extended advertising scanning test. " + "Will just scan an extended advertiser.", + .test_post_init_f = test_init, + .test_tick_f = test_tick, + .test_main_f = main_ext_adv_scanner + }, + { + .test_id = "ext_adv_conn_scanner", + .test_descr = "Basic extended advertising scanning test. " + "Will just scan an extended advertiser.", + .test_post_init_f = test_init, + .test_tick_f = test_tick, + .test_main_f = main_ext_adv_conn_scanner + }, + BSTEST_END_MARKER +}; + +struct bst_test_list *test_ext_adv_scanner(struct bst_test_list *tests) +{ + return bst_add_tests(tests, ext_adv_scanner); +} diff --git a/tests/bsim/bluetooth/host/adv/extended/src/main.c b/tests/bsim/bluetooth/host/adv/extended/src/main.c new file mode 100644 index 00000000000..d5390cba7a8 --- /dev/null +++ b/tests/bsim/bluetooth/host/adv/extended/src/main.c @@ -0,0 +1,39 @@ +/** + * Copyright (c) 2024 Croxel, Inc. + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include +#include "bstests.h" +#include "common.h" + +extern enum bst_result_t bst_result; + +void test_tick(bs_time_t HW_device_time) +{ + if (bst_result != Passed) { + FAIL("test failed (not passed after %i seconds)\n", WAIT_SECONDS); + } +} + +void test_init(void) +{ + bst_ticker_set_next_tick_absolute(WAIT_TIME); + bst_result = In_progress; +} + +extern struct bst_test_list *test_ext_adv_advertiser(struct bst_test_list *tests); +extern struct bst_test_list *test_ext_adv_scanner(struct bst_test_list *tests); + +bst_test_install_t test_installers[] = { + test_ext_adv_advertiser, + test_ext_adv_scanner, + NULL +}; + +int main(void) +{ + bst_main(); + return 0; +} diff --git a/tests/bsim/bluetooth/host/adv/extended/tests_scripts/ext_adv.sh b/tests/bsim/bluetooth/host/adv/extended/tests_scripts/ext_adv.sh new file mode 100755 index 00000000000..f7d7832840c --- /dev/null +++ b/tests/bsim/bluetooth/host/adv/extended/tests_scripts/ext_adv.sh @@ -0,0 +1,29 @@ +#!/usr/bin/env bash +# Copyright (c) 2024 Croxel, Inc. +# SPDX-License-Identifier: Apache-2.0 + +# Extended advertising test: +# +# - Broadcasting Only: a BLE broadcaster advertises with extended +# advertising, and a scanner scans the extended advertisement packets. + +source ${ZEPHYR_BASE}/tests/bsim/sh_common.source + +simulation_id="ext_adv" +verbosity_level=2 +EXECUTE_TIMEOUT=10 + +cd ${BSIM_OUT_PATH}/bin + +Execute ./bs_${BOARD}_tests_bsim_bluetooth_host_adv_extended_prj_conf \ + -v=${verbosity_level} -s=${simulation_id} -d=0 -RealEncryption=0 \ + -testid=ext_adv_advertiser -rs=23 + +Execute ./bs_${BOARD}_tests_bsim_bluetooth_host_adv_extended_prj_conf \ + -v=${verbosity_level} -s=${simulation_id} -d=1 -RealEncryption=0 \ + -testid=ext_adv_scanner -rs=6 + +Execute ./bs_2G4_phy_v1 -v=${verbosity_level} -s=${simulation_id} \ + -D=2 -sim_length=10e6 $@ + +wait_for_background_jobs diff --git a/tests/bsim/bluetooth/host/adv/extended/tests_scripts/ext_adv_conn.sh b/tests/bsim/bluetooth/host/adv/extended/tests_scripts/ext_adv_conn.sh new file mode 100755 index 00000000000..5642c29f33e --- /dev/null +++ b/tests/bsim/bluetooth/host/adv/extended/tests_scripts/ext_adv_conn.sh @@ -0,0 +1,31 @@ +#!/usr/bin/env bash +# Copyright (c) 2024 Croxel, Inc. +# SPDX-License-Identifier: Apache-2.0 + +# Extended advertising test: +# +# - Connectable: In addition to broadcasting advertisements, it is connectable +# and restarts advertisements once disconnected. The scanner/central scans +# for the packets and establishes the connection, to then disconnect +# shortly-after. + +source ${ZEPHYR_BASE}/tests/bsim/sh_common.source + +simulation_id="ext_adv_conn" +verbosity_level=2 +EXECUTE_TIMEOUT=10 + +cd ${BSIM_OUT_PATH}/bin + +Execute ./bs_${BOARD}_tests_bsim_bluetooth_host_adv_extended_prj_conf \ + -v=${verbosity_level} -s=${simulation_id} -d=0 -RealEncryption=0 \ + -testid=ext_adv_conn_advertiser -rs=23 + +Execute ./bs_${BOARD}_tests_bsim_bluetooth_host_adv_extended_prj_conf \ + -v=${verbosity_level} -s=${simulation_id} -d=1 -RealEncryption=0 \ + -testid=ext_adv_conn_scanner -rs=6 + +Execute ./bs_2G4_phy_v1 -v=${verbosity_level} -s=${simulation_id} \ + -D=2 -sim_length=10e6 $@ + +wait_for_background_jobs diff --git a/tests/bsim/bluetooth/host/compile.sh b/tests/bsim/bluetooth/host/compile.sh index 11ee242f12c..36387ef5dd0 100755 --- a/tests/bsim/bluetooth/host/compile.sh +++ b/tests/bsim/bluetooth/host/compile.sh @@ -22,6 +22,7 @@ source ${ZEPHYR_BASE}/tests/bsim/compile.source app=tests/bsim/bluetooth/host/adv/resume compile app=tests/bsim/bluetooth/host/adv/resume conf_file=prj_2.conf compile app=tests/bsim/bluetooth/host/adv/chain compile +app=tests/bsim/bluetooth/host/adv/extended compile app=tests/bsim/bluetooth/host/adv/periodic compile app=tests/bsim/bluetooth/host/adv/periodic conf_file=prj_long_data.conf compile app=tests/bsim/bluetooth/host/adv/encrypted/css_sample_data compile From 2745f6a8850c6a42031006e872e926c25cef2365 Mon Sep 17 00:00:00 2001 From: Luis Ubieda Date: Mon, 29 Jan 2024 22:36:17 -0500 Subject: [PATCH 3318/3723] samples: bluetooth: Added sample for Extended Advertisements Both advertiser and scanner demonstrate the use of extended advertising and scanning, and how to gracefully restart the extended advertisements through the use of recycle() callback. In the sample, the advertiser initiates a connectable advertisement set, which prompts the scanner to connect. After the connection is established, the advertiser waits for 5 seconds to disconnect. After the connection is dropped, the advertiser immediately restarts broadcasting, while the scanner cools-down for 5 seconds to restart its process. Signed-off-by: Luis Ubieda --- samples/bluetooth/extended_adv/README.rst | 96 +++++++++ .../extended_adv/advertiser/CMakeLists.txt | 8 + .../extended_adv/advertiser/prj.conf | 6 + .../extended_adv/advertiser/sample.yaml | 7 + .../extended_adv/advertiser/src/main.c | 144 +++++++++++++ .../extended_adv/scanner/CMakeLists.txt | 8 + .../bluetooth/extended_adv/scanner/prj.conf | 5 + .../extended_adv/scanner/sample.yaml | 7 + .../bluetooth/extended_adv/scanner/src/main.c | 195 ++++++++++++++++++ 9 files changed, 476 insertions(+) create mode 100644 samples/bluetooth/extended_adv/README.rst create mode 100644 samples/bluetooth/extended_adv/advertiser/CMakeLists.txt create mode 100644 samples/bluetooth/extended_adv/advertiser/prj.conf create mode 100644 samples/bluetooth/extended_adv/advertiser/sample.yaml create mode 100644 samples/bluetooth/extended_adv/advertiser/src/main.c create mode 100644 samples/bluetooth/extended_adv/scanner/CMakeLists.txt create mode 100644 samples/bluetooth/extended_adv/scanner/prj.conf create mode 100644 samples/bluetooth/extended_adv/scanner/sample.yaml create mode 100644 samples/bluetooth/extended_adv/scanner/src/main.c diff --git a/samples/bluetooth/extended_adv/README.rst b/samples/bluetooth/extended_adv/README.rst new file mode 100644 index 00000000000..c5c402818e6 --- /dev/null +++ b/samples/bluetooth/extended_adv/README.rst @@ -0,0 +1,96 @@ +.. _bluetooth_extended_advertising_sample: + +Bluetooth: Extended Advertising +################################ + +Overview +******** + +This sample demonstrates the use of the extended advertising feature, by: + +- Outlining the steps required to initialize an extended advertising application. +- Demo how to gracefully restart the functionality, after a disconnect. + +The sample consists of the advertiser initiating a connectable advertisement set, +which prompts the scanner to connect after scanning for extended advertisements. +Once the connection is established, the advertiser waits for 5 seconds to disconnect. +After the connection is dropped, the advertiser immediately restarts broadcasting, +while the scanner cools-down for 5 seconds to restart its process. + +This sample handles all actions in a separate thread, to promote good design +practices. Even though it is not strictly required, scheduling from another context is +strongly recommended (e.g. using a work item), as re-starting an advertiser or +scanner from within the `recycled` callback exposes the application to deadlocking. + +Requirements +************ + +* Two boards with Bluetooth Low Energy support + +Building and Running +******************** + +This sample can be found under +:zephyr_file:`samples/bluetooth/extended_adv` in the Zephyr tree. + +See :ref:`bluetooth samples section ` for details. + +This sample uses two applications, so two devices need to be setup. +Flash one device with the scanner application, and another device with the +advertiser application. + +The two devices should automatically connect if they are close enough. + +Here are the outputs you should get by default: + +Advertiser: + +.. code-block:: console + + *** Booting Zephyr OS build zephyr-v3.5.0-4935-gfc7972183da5 *** + Starting Extended Advertising Demo + Starting Extended Advertising + Connected (err 0x00) + Connected state! + Initiating disconnect within 5 seconds... + Disconnected (reason 0x16) + Connection object available from previous conn. Disconnect is complete! + Disconnected state! Restarting advertising + Starting Extended Advertising + Connected (err 0x00) + Connected state! + Initiating disconnect within 5 seconds... + Disconnected (reason 0x16) + Connection object available from previous conn. Disconnect is complete! + Disconnected state! Restarting advertising + Starting Extended Advertising + +Scanner: + +.. code-block:: console + + *** Booting Zephyr OS build zephyr-v3.5.0-4935-ge3308caf97bc *** + Starting Extended Advertising Demo [Scanner] + Found extended advertisement packet! + Stopping scan + Connected (err 0x00) + Connected state! + Disconnected (reason 0x13) + Recycled cb called! + Disconnected, cooldown for 5 seconds! + Starting to scan for extended adv + Found extended advertisement packet! + Stopping scan + Connected (err 0x00) + Connected state! + Disconnected (reason 0x13) + Recycled cb called! + Disconnected, cooldown for 5 seconds! + Starting to scan for extended adv + Found extended advertisement packet! + Stopping scan + Connected (err 0x00) + Connected state! + Disconnected (reason 0x13) + Recycled cb called! + Disconnected, cooldown for 5 seconds! diff --git a/samples/bluetooth/extended_adv/advertiser/CMakeLists.txt b/samples/bluetooth/extended_adv/advertiser/CMakeLists.txt new file mode 100644 index 00000000000..b710615679e --- /dev/null +++ b/samples/bluetooth/extended_adv/advertiser/CMakeLists.txt @@ -0,0 +1,8 @@ +# Copyright 2024 Croxel, Inc. +# SPDX-License-Identifier: Apache-2.0 + +cmake_minimum_required(VERSION 3.20.0) +find_package(Zephyr REQUIRED HINTS $ENV{ZEPHYR_BASE}) +project(extended_adv) + +target_sources(app PRIVATE src/main.c) diff --git a/samples/bluetooth/extended_adv/advertiser/prj.conf b/samples/bluetooth/extended_adv/advertiser/prj.conf new file mode 100644 index 00000000000..0c352e3950f --- /dev/null +++ b/samples/bluetooth/extended_adv/advertiser/prj.conf @@ -0,0 +1,6 @@ +CONFIG_BT=y +CONFIG_BT_DEVICE_NAME="test_ext_adv" +CONFIG_BT_PERIPHERAL=y +CONFIG_BT_EXT_ADV=y + +CONFIG_ASSERT=y diff --git a/samples/bluetooth/extended_adv/advertiser/sample.yaml b/samples/bluetooth/extended_adv/advertiser/sample.yaml new file mode 100644 index 00000000000..06b723062ce --- /dev/null +++ b/samples/bluetooth/extended_adv/advertiser/sample.yaml @@ -0,0 +1,7 @@ +sample: + name: Bluetooth Extended Advertising Advertiser +tests: + sample.bluetooth.extended_advertising.advertiser: + harness: bluetooth + platform_allow: nrf52840dk_nrf52840 + tags: bluetooth diff --git a/samples/bluetooth/extended_adv/advertiser/src/main.c b/samples/bluetooth/extended_adv/advertiser/src/main.c new file mode 100644 index 00000000000..915e61b9366 --- /dev/null +++ b/samples/bluetooth/extended_adv/advertiser/src/main.c @@ -0,0 +1,144 @@ +/** + * Copyright (c) 2024 Croxel, Inc. + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include +#include +#include + +static struct bt_conn *default_conn; + +enum bt_sample_adv_evt { + BT_SAMPLE_EVT_CONNECTED, + BT_SAMPLE_EVT_DISCONNECTED, + BT_SAMPLE_EVT_MAX, +}; + +enum bt_sample_adv_st { + BT_SAMPLE_ST_ADV, + BT_SAMPLE_ST_CONNECTED, +}; + +static ATOMIC_DEFINE(evt_bitmask, BT_SAMPLE_EVT_MAX); + +static volatile enum bt_sample_adv_st app_st = BT_SAMPLE_ST_ADV; + +static struct k_poll_signal poll_sig = K_POLL_SIGNAL_INITIALIZER(poll_sig); +static struct k_poll_event poll_evt = K_POLL_EVENT_INITIALIZER(K_POLL_TYPE_SIGNAL, + K_POLL_MODE_NOTIFY_ONLY, &poll_sig); + +static void raise_evt(enum bt_sample_adv_evt evt) +{ + (void)atomic_set_bit(evt_bitmask, evt); + k_poll_signal_raise(poll_evt.signal, 1); +} + +static void connected_cb(struct bt_conn *conn, uint8_t err) +{ + printk("Connected (err 0x%02X)\n", err); + + if (err) { + return; + } + + __ASSERT(!default_conn, "Attempting to override existing connection object!"); + default_conn = bt_conn_ref(conn); + + raise_evt(BT_SAMPLE_EVT_CONNECTED); +} + +static void disconnected_cb(struct bt_conn *conn, uint8_t reason) +{ + printk("Disconnected (reason 0x%02X)\n", reason); + + __ASSERT(conn == default_conn, "Unexpected disconnected callback"); + + bt_conn_unref(default_conn); + default_conn = NULL; +} + +static void recycled_cb(void) +{ + printk("Connection object available from previous conn. Disconnect is complete!\n"); + raise_evt(BT_SAMPLE_EVT_DISCONNECTED); +} + +BT_CONN_CB_DEFINE(conn_cb) = { + .connected = connected_cb, + .disconnected = disconnected_cb, + .recycled = recycled_cb, +}; + +static int start_advertising(struct bt_le_ext_adv *adv) +{ + int err; + + printk("Starting Extended Advertising\n"); + err = bt_le_ext_adv_start(adv, BT_LE_EXT_ADV_START_DEFAULT); + if (err) { + printk("Failed to start extended advertising (err %d)\n", err); + } + + return err; +} + +int main(void) +{ + int err; + struct bt_le_ext_adv *adv; + + printk("Starting Extended Advertising Demo\n"); + + /* Initialize the Bluetooth Subsystem */ + err = bt_enable(NULL); + if (err) { + printk("Bluetooth init failed (err %d)\n", err); + return err; + } + + /* Create a non-connectable non-scannable advertising set */ + err = bt_le_ext_adv_create(BT_LE_EXT_ADV_CONN_NAME, NULL, &adv); + if (err) { + printk("Failed to create advertising set (err %d)\n", err); + return err; + } + + err = start_advertising(adv); + if (err) { + return err; + } + + while (true) { + k_poll(&poll_evt, 1, K_FOREVER); + + k_poll_signal_reset(poll_evt.signal); + poll_evt.state = K_POLL_STATE_NOT_READY; + + /* Identify event and act upon if applicable */ + if (atomic_test_and_clear_bit(evt_bitmask, BT_SAMPLE_EVT_CONNECTED) && + app_st == BT_SAMPLE_ST_ADV) { + + printk("Connected state!\n"); + app_st = BT_SAMPLE_ST_CONNECTED; + + printk("Initiating disconnect within 5 seconds...\n"); + k_sleep(K_SECONDS(5)); + + bt_conn_disconnect(default_conn, BT_HCI_ERR_REMOTE_USER_TERM_CONN); + + } else if (atomic_test_and_clear_bit(evt_bitmask, BT_SAMPLE_EVT_DISCONNECTED) && + app_st == BT_SAMPLE_ST_CONNECTED) { + + printk("Disconnected state! Restarting advertising\n"); + app_st = BT_SAMPLE_ST_ADV; + err = start_advertising(adv); + if (err) { + return err; + } + } + } + + return err; +} diff --git a/samples/bluetooth/extended_adv/scanner/CMakeLists.txt b/samples/bluetooth/extended_adv/scanner/CMakeLists.txt new file mode 100644 index 00000000000..0c31cebb89b --- /dev/null +++ b/samples/bluetooth/extended_adv/scanner/CMakeLists.txt @@ -0,0 +1,8 @@ +# Copyright 2024 Croxel, Inc. +# SPDX-License-Identifier: Apache-2.0 + +cmake_minimum_required(VERSION 3.20.0) +find_package(Zephyr REQUIRED HINTS $ENV{ZEPHYR_BASE}) +project(extended_adv_scanner) + +target_sources(app PRIVATE src/main.c) diff --git a/samples/bluetooth/extended_adv/scanner/prj.conf b/samples/bluetooth/extended_adv/scanner/prj.conf new file mode 100644 index 00000000000..0b8fe5716d9 --- /dev/null +++ b/samples/bluetooth/extended_adv/scanner/prj.conf @@ -0,0 +1,5 @@ +CONFIG_BT=y +CONFIG_BT_CENTRAL=y +CONFIG_BT_EXT_ADV=y + +CONFIG_ASSERT=y diff --git a/samples/bluetooth/extended_adv/scanner/sample.yaml b/samples/bluetooth/extended_adv/scanner/sample.yaml new file mode 100644 index 00000000000..7cb06719dff --- /dev/null +++ b/samples/bluetooth/extended_adv/scanner/sample.yaml @@ -0,0 +1,7 @@ +sample: + name: Bluetooth Extended Advertising Scanner +tests: + sample.bluetooth.extended_advertising.scanner: + harness: bluetooth + platform_allow: nrf52840dk_nrf52840 + tags: bluetooth diff --git a/samples/bluetooth/extended_adv/scanner/src/main.c b/samples/bluetooth/extended_adv/scanner/src/main.c new file mode 100644 index 00000000000..a4773830fc3 --- /dev/null +++ b/samples/bluetooth/extended_adv/scanner/src/main.c @@ -0,0 +1,195 @@ +/** + * Copyright (c) 2024 Croxel, Inc. + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include +#include +#include + +#define NAME_LEN 30 + +static struct bt_conn *default_conn; +bt_addr_le_t ext_addr; + +enum bt_sample_scan_evt { + BT_SAMPLE_EVT_EXT_ADV_FOUND, + BT_SAMPLE_EVT_CONNECTED, + BT_SAMPLE_EVT_DISCONNECTED, + BT_SAMPLE_EVT_SCAN_DUE, + BT_SAMPLE_EVT_MAX, +}; + +enum bt_sample_scan_st { + BT_SAMPLE_ST_SCANNING, + BT_SAMPLE_ST_CONNECTING, + BT_SAMPLE_ST_CONNECTED, + BT_SAMPLE_ST_COOLDOWN, +}; + +static volatile enum bt_sample_scan_st app_st = BT_SAMPLE_ST_SCANNING; + +static ATOMIC_DEFINE(evt_bitmask, BT_SAMPLE_EVT_MAX); + +static struct k_poll_signal poll_sig = K_POLL_SIGNAL_INITIALIZER(poll_sig); +static struct k_poll_event poll_evt = K_POLL_EVENT_INITIALIZER(K_POLL_TYPE_SIGNAL, + K_POLL_MODE_NOTIFY_ONLY, &poll_sig); + +static void raise_evt(enum bt_sample_scan_evt evt) +{ + (void)atomic_set_bit(evt_bitmask, evt); + k_poll_signal_raise(poll_evt.signal, 1); +} + +static void connected_cb(struct bt_conn *conn, uint8_t err) +{ + printk("Connected (err 0x%02X)\n", err); + + if (err) { + bt_conn_unref(default_conn); + default_conn = NULL; + return; + } + + raise_evt(BT_SAMPLE_EVT_CONNECTED); +} + +static void disconnected_cb(struct bt_conn *conn, uint8_t reason) +{ + bt_conn_unref(default_conn); + default_conn = NULL; + + printk("Disconnected (reason 0x%02X)\n", reason); +} + +static void recycled_cb(void) +{ + printk("Connection object available from previous conn. Disconnect is complete!\n"); + raise_evt(BT_SAMPLE_EVT_DISCONNECTED); +} + +BT_CONN_CB_DEFINE(conn_cb) = { + .connected = connected_cb, + .disconnected = disconnected_cb, + .recycled = recycled_cb, +}; + + +static void scan_recv(const struct bt_le_scan_recv_info *info, struct net_buf_simple *buf) +{ + if (info->adv_type & BT_GAP_ADV_TYPE_EXT_ADV && + info->adv_props & BT_GAP_ADV_PROP_EXT_ADV && + info->adv_props & BT_GAP_ADV_PROP_CONNECTABLE) { + /* Attempt connection request for device with extended advertisements */ + memcpy(&ext_addr, info->addr, sizeof(ext_addr)); + raise_evt(BT_SAMPLE_EVT_EXT_ADV_FOUND); + } +} + +static struct bt_le_scan_cb scan_callbacks = { + .recv = scan_recv, +}; + +static inline int attempt_connection(void) +{ + int err; + + printk("Stopping scan\n"); + err = bt_le_scan_stop(); + if (err) { + printk("Failed to stop scan: %d\n", err); + return err; + } + + err = bt_conn_le_create(&ext_addr, BT_CONN_LE_CREATE_CONN, + BT_LE_CONN_PARAM_DEFAULT, &default_conn); + if (err) { + printk("Failed to establish conn: %d\n", err); + return err; + } + + return 0; +} + +static inline int start_scanning(void) +{ + int err; + + err = bt_le_scan_start(BT_LE_SCAN_PASSIVE, NULL); + if (err) { + printk("failed (err %d)\n", err); + } + + return err; +} + +int main(void) +{ + int err; + + printk("Starting Extended Advertising Demo [Scanner]\n"); + + /* Initialize the Bluetooth Subsystem */ + err = bt_enable(NULL); + if (err) { + printk("Bluetooth init failed (err %d)\n", err); + return 0; + } + + bt_le_scan_cb_register(&scan_callbacks); + + err = start_scanning(); + if (err) { + return err; + } + + while (true) { + (void)k_poll(&poll_evt, 1, K_FOREVER); + + k_poll_signal_reset(poll_evt.signal); + poll_evt.state = K_POLL_STATE_NOT_READY; + + /* Identify event and act upon if applicable */ + if (atomic_test_and_clear_bit(evt_bitmask, BT_SAMPLE_EVT_EXT_ADV_FOUND) && + app_st == BT_SAMPLE_ST_SCANNING) { + + printk("Found extended advertisement packet!\n"); + app_st = BT_SAMPLE_ST_CONNECTING; + err = attempt_connection(); + if (err) { + return err; + } + + } else if (atomic_test_and_clear_bit(evt_bitmask, BT_SAMPLE_EVT_CONNECTED) && + (app_st == BT_SAMPLE_ST_CONNECTING)) { + + printk("Connected state!\n"); + app_st = BT_SAMPLE_ST_CONNECTED; + + } else if (atomic_test_and_clear_bit(evt_bitmask, BT_SAMPLE_EVT_DISCONNECTED) && + (app_st == BT_SAMPLE_ST_CONNECTED)) { + + printk("Disconnected, cooldown for 5 seconds!\n"); + app_st = BT_SAMPLE_ST_COOLDOWN; + + /* Wait a few seconds before starting to re-scan again... */ + k_sleep(K_SECONDS(5)); + + raise_evt(BT_SAMPLE_EVT_SCAN_DUE); + + } else if (atomic_test_and_clear_bit(evt_bitmask, BT_SAMPLE_EVT_SCAN_DUE) && + (app_st == BT_SAMPLE_ST_COOLDOWN)) { + + printk("Starting to scan for extended adv\n"); + app_st = BT_SAMPLE_ST_SCANNING; + err = start_scanning(); + if (err) { + return err; + } + + } + } + + return 0; +} From 86568638faad7ff7ce9c3998120d9990d948ba3b Mon Sep 17 00:00:00 2001 From: Fabio Baltieri Date: Thu, 1 Feb 2024 09:43:05 +0000 Subject: [PATCH 3319/3723] github: hello_world_multiplatform: run on SDK_VERSION changes Add the SDK_VERSION file to the pathlist for running the workflow on pull requests. Signed-off-by: Fabio Baltieri --- .github/workflows/hello_world_multiplatform.yaml | 1 + 1 file changed, 1 insertion(+) diff --git a/.github/workflows/hello_world_multiplatform.yaml b/.github/workflows/hello_world_multiplatform.yaml index efa75ef88d7..af839415360 100644 --- a/.github/workflows/hello_world_multiplatform.yaml +++ b/.github/workflows/hello_world_multiplatform.yaml @@ -15,6 +15,7 @@ on: - 'scripts/build/**' - 'scripts/requirements*.txt' - '.github/workflows/hello_world_multiplatform.yaml' + - 'SDK_VERSION' concurrency: group: ${{ github.workflow }}-${{ github.event_name }}-${{ github.head_ref || github.ref }} From 9c038c6c3414f12af59590a3534e04f15a4960b0 Mon Sep 17 00:00:00 2001 From: Fabio Baltieri Date: Thu, 1 Feb 2024 09:46:38 +0000 Subject: [PATCH 3320/3723] github: hello_world_multiplatform: update standard action version Align the standard action versions with the other workflows, those have been updated in 0dcb0518be but this file was merged after. Signed-off-by: Fabio Baltieri --- .github/workflows/hello_world_multiplatform.yaml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/hello_world_multiplatform.yaml b/.github/workflows/hello_world_multiplatform.yaml index af839415360..418c42a5307 100644 --- a/.github/workflows/hello_world_multiplatform.yaml +++ b/.github/workflows/hello_world_multiplatform.yaml @@ -30,7 +30,7 @@ jobs: runs-on: ${{ matrix.os }} steps: - name: Checkout - uses: actions/checkout@v3 + uses: actions/checkout@v4 with: path: zephyr fetch-depth: 0 @@ -72,7 +72,7 @@ jobs: - name: Upload artifacts if: failure() - uses: actions/upload-artifact@v3 + uses: actions/upload-artifact@v4 with: if-no-files-found: ignore path: From 7f5b332b58a9bfbbc6ed7b91e1bfc03f5f0ca7f7 Mon Sep 17 00:00:00 2001 From: Eve Redero Date: Thu, 1 Feb 2024 11:17:31 +0100 Subject: [PATCH 3321/3723] doc: fix index typo in sdl bindings Label "key1" is used twice in the exemple, renaming to "key2". Signed-off-by: Eve Redero --- dts/bindings/gpio/zephyr,gpio-emul-sdl.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/dts/bindings/gpio/zephyr,gpio-emul-sdl.yaml b/dts/bindings/gpio/zephyr,gpio-emul-sdl.yaml index 892b208e026..a6c56733444 100644 --- a/dts/bindings/gpio/zephyr,gpio-emul-sdl.yaml +++ b/dts/bindings/gpio/zephyr,gpio-emul-sdl.yaml @@ -28,7 +28,7 @@ description: | key1: key1 { gpios = <&gpio0 0 GPIO_ACTIVE_HIGH>; }; - key1: key2 { + key2: key2 { gpios = <&gpio0 1 GPIO_ACTIVE_HIGH>; }; key3: key3 { From 3d9f76b8e5e8a8f80e107aee4e86aa4cf85ed9ec Mon Sep 17 00:00:00 2001 From: huajiang zheng Date: Tue, 31 Oct 2023 15:01:49 +0800 Subject: [PATCH 3322/3723] Bluetooth: Host: add unregister connection callback function [Description] tests: shell: Restart bt will register the same connection callback twice. Callback next node point to itself, when link established callback function loop infinitely. [Fix] Unregister the previous callback to avoid register repeatedly. [Test] After bt init/disable times, create connection successfully. Signed-off-by: huajiang zheng --- include/zephyr/bluetooth/conn.h | 13 + subsys/bluetooth/host/conn.c | 27 ++ subsys/bluetooth/shell/bt.c | 2 + tests/bsim/bluetooth/host/compile.sh | 1 + .../misc/unregister_conn_cb/CMakeLists.txt | 14 + .../host/misc/unregister_conn_cb/prj.conf | 4 + .../host/misc/unregister_conn_cb/src/common.c | 20 ++ .../host/misc/unregister_conn_cb/src/common.h | 55 ++++ .../host/misc/unregister_conn_cb/src/main.c | 240 ++++++++++++++++++ .../tests_scripts/_compile.sh | 17 ++ .../tests_scripts/unregister_conn_cb.sh | 26 ++ 11 files changed, 419 insertions(+) create mode 100644 tests/bsim/bluetooth/host/misc/unregister_conn_cb/CMakeLists.txt create mode 100644 tests/bsim/bluetooth/host/misc/unregister_conn_cb/prj.conf create mode 100644 tests/bsim/bluetooth/host/misc/unregister_conn_cb/src/common.c create mode 100644 tests/bsim/bluetooth/host/misc/unregister_conn_cb/src/common.h create mode 100644 tests/bsim/bluetooth/host/misc/unregister_conn_cb/src/main.c create mode 100755 tests/bsim/bluetooth/host/misc/unregister_conn_cb/tests_scripts/_compile.sh create mode 100755 tests/bsim/bluetooth/host/misc/unregister_conn_cb/tests_scripts/unregister_conn_cb.sh diff --git a/include/zephyr/bluetooth/conn.h b/include/zephyr/bluetooth/conn.h index f934ea54162..edd37bde31e 100644 --- a/include/zephyr/bluetooth/conn.h +++ b/include/zephyr/bluetooth/conn.h @@ -1165,6 +1165,19 @@ struct bt_conn_cb { */ void bt_conn_cb_register(struct bt_conn_cb *cb); +/** + * @brief Unregister connection callbacks. + * + * Unregister the state of connections callbacks. + * + * @param cb Callback struct point to memory that remains valid. + * + * @retval 0 Success + * @retval -EINVAL If @p cb is NULL + * @retval -ENOENT if @p cb was not registered + */ +int bt_conn_cb_unregister(struct bt_conn_cb *cb); + /** * @brief Register a callback structure for connection events. * diff --git a/subsys/bluetooth/host/conn.c b/subsys/bluetooth/host/conn.c index cad3cf32f23..36b2692ee9d 100644 --- a/subsys/bluetooth/host/conn.c +++ b/subsys/bluetooth/host/conn.c @@ -2381,6 +2381,33 @@ void bt_conn_cb_register(struct bt_conn_cb *cb) callback_list = cb; } +int bt_conn_cb_unregister(struct bt_conn_cb *cb) +{ + struct bt_conn_cb *previous_callback; + + CHECKIF(cb == NULL) { + return -EINVAL; + } + + if (callback_list == cb) { + callback_list = callback_list->_next; + return 0; + } + + previous_callback = callback_list; + + while (previous_callback->_next) { + if (previous_callback->_next == cb) { + previous_callback->_next = previous_callback->_next->_next; + return 0; + } + + previous_callback = previous_callback->_next; + } + + return -ENOENT; +} + bool bt_conn_exists_le(uint8_t id, const bt_addr_le_t *peer) { struct bt_conn *conn = bt_conn_lookup_addr_le(id, peer); diff --git a/subsys/bluetooth/shell/bt.c b/subsys/bluetooth/shell/bt.c index e65e85262a7..bbe794969d7 100644 --- a/subsys/bluetooth/shell/bt.c +++ b/subsys/bluetooth/shell/bt.c @@ -1061,6 +1061,8 @@ static void bt_ready(int err) #if defined(CONFIG_BT_CONN) default_conn = NULL; + /* Unregister to avoid register repeatedly */ + bt_conn_cb_unregister(&conn_callbacks); bt_conn_cb_register(&conn_callbacks); #endif /* CONFIG_BT_CONN */ diff --git a/tests/bsim/bluetooth/host/compile.sh b/tests/bsim/bluetooth/host/compile.sh index 36387ef5dd0..1500ba66b5e 100755 --- a/tests/bsim/bluetooth/host/compile.sh +++ b/tests/bsim/bluetooth/host/compile.sh @@ -76,6 +76,7 @@ app=tests/bsim/bluetooth/host/misc/disconnect/dut compile app=tests/bsim/bluetooth/host/misc/disconnect/tester compile app=tests/bsim/bluetooth/host/misc/conn_stress/central compile app=tests/bsim/bluetooth/host/misc/conn_stress/peripheral compile +app=tests/bsim/bluetooth/host/misc/unregister_conn_cb compile app=tests/bsim/bluetooth/host/privacy/central compile app=tests/bsim/bluetooth/host/privacy/peripheral compile diff --git a/tests/bsim/bluetooth/host/misc/unregister_conn_cb/CMakeLists.txt b/tests/bsim/bluetooth/host/misc/unregister_conn_cb/CMakeLists.txt new file mode 100644 index 00000000000..65762a174c2 --- /dev/null +++ b/tests/bsim/bluetooth/host/misc/unregister_conn_cb/CMakeLists.txt @@ -0,0 +1,14 @@ +# SPDX-License-Identifier: Apache-2.0 + +cmake_minimum_required(VERSION 3.20.0) + +find_package(Zephyr REQUIRED HINTS $ENV{ZEPHYR_BASE}) +project(bsim_test_unregister_conn_cb) + +FILE(GLOB app_sources src/*.c) +target_sources(app PRIVATE ${app_sources} ) + +zephyr_include_directories( + ${BSIM_COMPONENTS_PATH}/libUtilv1/src/ + ${BSIM_COMPONENTS_PATH}/libPhyComv1/src/ + ) diff --git a/tests/bsim/bluetooth/host/misc/unregister_conn_cb/prj.conf b/tests/bsim/bluetooth/host/misc/unregister_conn_cb/prj.conf new file mode 100644 index 00000000000..2d054ed9031 --- /dev/null +++ b/tests/bsim/bluetooth/host/misc/unregister_conn_cb/prj.conf @@ -0,0 +1,4 @@ +CONFIG_BT=y +CONFIG_BT_DEVICE_NAME="conn tester" +CONFIG_BT_PERIPHERAL=y +CONFIG_BT_CENTRAL=y diff --git a/tests/bsim/bluetooth/host/misc/unregister_conn_cb/src/common.c b/tests/bsim/bluetooth/host/misc/unregister_conn_cb/src/common.c new file mode 100644 index 00000000000..df438607c5f --- /dev/null +++ b/tests/bsim/bluetooth/host/misc/unregister_conn_cb/src/common.c @@ -0,0 +1,20 @@ +/* + * Copyright (c) 2022 Nordic Semiconductor ASA + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include "common.h" + +void test_tick(bs_time_t HW_device_time) +{ + if (bst_result != Passed) { + FAIL("test failed (not passed after %i seconds)\n", WAIT_TIME); + } +} + +void test_init(void) +{ + bst_ticker_set_next_tick_absolute(WAIT_TIME); + bst_result = In_progress; +} diff --git a/tests/bsim/bluetooth/host/misc/unregister_conn_cb/src/common.h b/tests/bsim/bluetooth/host/misc/unregister_conn_cb/src/common.h new file mode 100644 index 00000000000..159f27a8a21 --- /dev/null +++ b/tests/bsim/bluetooth/host/misc/unregister_conn_cb/src/common.h @@ -0,0 +1,55 @@ +/** + * Common functions and helpers for unregister connection callback tests + * + * Copyright (c) 2024 NXP + * Copyright (c) 2022 Nordic Semiconductor ASA + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include + +#include "bs_types.h" +#include "bs_tracing.h" +#include "time_machine.h" +#include "bstests.h" + +#include +#include +#include + +#include +#include +#include + +extern enum bst_result_t bst_result; + +#define WAIT_SECONDS (30) /*seconds*/ +#define WAIT_TIME (WAIT_SECONDS * USEC_PER_SEC) /*microseconds*/ + +#define CREATE_FLAG(flag) static atomic_t flag = (atomic_t) false +#define SET_FLAG(flag) (void)atomic_set(&flag, (atomic_t) true) +#define UNSET_FLAG(flag) (void)atomic_set(&flag, (atomic_t) false) +#define WAIT_FOR_FLAG(flag) \ + while (!(bool)atomic_get(&flag)) { \ + (void)k_sleep(K_MSEC(1)); \ + } +#define WAIT_FOR_FLAG_UNSET(flag) \ + while ((bool)atomic_get(&flag)) { \ + (void)k_sleep(K_MSEC(1)); \ + } + +#define FAIL(...) \ + do { \ + bst_result = Failed; \ + bs_trace_error_time_line(__VA_ARGS__); \ + } while (0) + +#define PASS(...) \ + do { \ + bst_result = Passed; \ + bs_trace_info_time(1, __VA_ARGS__); \ + } while (0) + +void test_tick(bs_time_t HW_device_time); +void test_init(void); diff --git a/tests/bsim/bluetooth/host/misc/unregister_conn_cb/src/main.c b/tests/bsim/bluetooth/host/misc/unregister_conn_cb/src/main.c new file mode 100644 index 00000000000..f11b179ee34 --- /dev/null +++ b/tests/bsim/bluetooth/host/misc/unregister_conn_cb/src/main.c @@ -0,0 +1,240 @@ +/* + * The goal of this test is to verify the bt_conn_cb_unregister() API works as expected + * + * Copyright (c) 2024 NXP + * Copyright (c) 2022 Nordic Semiconductor ASA + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include "bstests.h" +#include + +#include "common.h" + +CREATE_FLAG(flag_is_connected); + +static struct bt_conn *g_conn; + +static void connected(struct bt_conn *conn, uint8_t err) +{ + char addr[BT_ADDR_LE_STR_LEN]; + + bt_addr_le_to_str(bt_conn_get_dst(conn), addr, sizeof(addr)); + + if (err != 0) { + FAIL("Failed to connect to %s (%u)\n", addr, err); + return; + } + + printk("conn_callback:Connected to %s\n", addr); + + g_conn = conn; + SET_FLAG(flag_is_connected); +} + +static void disconnected(struct bt_conn *conn, uint8_t reason) +{ + char addr[BT_ADDR_LE_STR_LEN]; + + if (conn != g_conn) { + return; + } + + bt_addr_le_to_str(bt_conn_get_dst(conn), addr, sizeof(addr)); + + printk("conn_callback:Disconnected: %s (reason 0x%02x)\n", addr, reason); + + bt_conn_unref(g_conn); + + g_conn = NULL; + UNSET_FLAG(flag_is_connected); +} + +static struct bt_conn_cb conn_callbacks = { + .connected = connected, + .disconnected = disconnected, +}; + +void device_found(const bt_addr_le_t *addr, int8_t rssi, uint8_t type, struct net_buf_simple *ad) +{ + char addr_str[BT_ADDR_LE_STR_LEN]; + int err; + + if (g_conn != NULL) { + printk("g_conn != NULL\n"); + return; + } + + /* We're only interested in connectable events */ + if (type != BT_HCI_ADV_IND && type != BT_HCI_ADV_DIRECT_IND) { + printk("type not connectable\n"); + return; + } + + bt_addr_le_to_str(addr, addr_str, sizeof(addr_str)); + printk("Device found: %s (RSSI %d)\n", addr_str, rssi); + + printk("Stopping scan\n"); + err = bt_le_scan_stop(); + if (err != 0) { + FAIL("Could not stop scan: %d"); + return; + } + + err = bt_conn_le_create(addr, BT_CONN_LE_CREATE_CONN, BT_LE_CONN_PARAM_DEFAULT, &g_conn); + if (err != 0) { + FAIL("Could not connect to peer: %d", err); + } + printk("%s: connected to found device\n", __func__); +} + +static void connection_info(struct bt_conn *conn, void *user_data) +{ + char addr[BT_ADDR_LE_STR_LEN]; + int *conn_count = user_data; + struct bt_conn_info info; + + if (bt_conn_get_info(conn, &info) < 0) { + printk("Unable to get info: conn %p", conn); + return; + } + + switch (info.type) { + case BT_CONN_TYPE_LE: + (*conn_count)++; + bt_addr_le_to_str(bt_conn_get_dst(conn), addr, sizeof(addr)); + printk("%s: Connected to %s\n", __func__, addr); + break; + default: + break; + } +} + +static void test_peripheral_main(void) +{ + int err; + const struct bt_data ad[] = { + BT_DATA_BYTES(BT_DATA_FLAGS, (BT_LE_AD_GENERAL | BT_LE_AD_NO_BREDR))}; + + err = bt_enable(NULL); + if (err != 0) { + FAIL("Bluetooth init failed (err %d)\n", err); + return; + } + + printk("Bluetooth initialized\n"); + + bt_conn_cb_register(&conn_callbacks); + + err = bt_le_adv_start(BT_LE_ADV_CONN_NAME, ad, ARRAY_SIZE(ad), NULL, 0); + if (err != 0) { + FAIL("Advertising failed to start (err %d)\n", err); + return; + } + + printk("Advertising successfully started\n"); + + WAIT_FOR_FLAG(flag_is_connected); + + WAIT_FOR_FLAG_UNSET(flag_is_connected); + + bt_conn_cb_unregister(&conn_callbacks); + + k_sleep(K_SECONDS(1)); + + err = bt_disable(); + if (err != 0) { + FAIL("Bluetooth disable failed (err %d)\n", err); + return; + } + + printk("Bluetooth successfully disabled\n"); + + PASS("Peripheral device passed\n"); +} + +static void test_central_main(void) +{ + int err; + int conn_count = 0; + + err = bt_enable(NULL); + if (err != 0) { + FAIL("Bluetooth discover failed (err %d)\n", err); + } + printk("Bluetooth initialized\n"); + bt_conn_cb_register(&conn_callbacks); + /* Connect to peer device after conn_callbacks registered*/ + err = bt_le_scan_start(BT_LE_SCAN_PASSIVE, device_found); + if (err != 0) { + FAIL("Scanning failed to start (err %d)\n", err); + } + + printk("Scanning successfully started\n"); + + WAIT_FOR_FLAG(flag_is_connected); + + err = bt_conn_disconnect(g_conn, 0x13); + + if (err != 0) { + FAIL("Disconnect failed (err %d)\n", err); + return; + } + + WAIT_FOR_FLAG_UNSET(flag_is_connected); + bt_conn_cb_unregister(&conn_callbacks); + /* Reconnect to the device after conn_callbacks unregistered */ + err = bt_le_scan_start(BT_LE_SCAN_PASSIVE, device_found); + if (err != 0) { + FAIL("Scanning failed to start (err %d)\n", err); + } + printk("Scanning successfully started\n"); + + k_sleep(K_SECONDS(1)); + bt_conn_foreach(BT_CONN_TYPE_LE, connection_info, &conn_count); + if (!conn_count) { + FAIL("Reconnect to peer device failed!"); + } + + /* flag_is_connected not set means no conn_callbacks being called */ + if (flag_is_connected) { + FAIL("Unregister conn_callback didn't work"); + } + printk("Unregister connection callbacks succeed!\n"); + + err = bt_disable(); + if (err != 0) { + FAIL("Bluetooth disable failed (err %d)\n", err); + } + printk("Bluetooth successfully disabled\n"); + + PASS("Central device passed\n"); +} + +static const struct bst_test_instance test_def[] = {{.test_id = "peripheral", + .test_descr = "Peripheral device", + .test_post_init_f = test_init, + .test_tick_f = test_tick, + .test_main_f = test_peripheral_main}, + {.test_id = "central", + .test_descr = "Central device", + .test_post_init_f = test_init, + .test_tick_f = test_tick, + .test_main_f = test_central_main}, + BSTEST_END_MARKER}; + +struct bst_test_list *test_unregister_conn_cb_install(struct bst_test_list *tests) +{ + return bst_add_tests(tests, test_def); +} + +extern struct bst_test_list *test_unregister_conn_cb_install(struct bst_test_list *tests); + +bst_test_install_t test_installers[] = {test_unregister_conn_cb_install, NULL}; + +int main(void) +{ + bst_main(); + return 0; +} diff --git a/tests/bsim/bluetooth/host/misc/unregister_conn_cb/tests_scripts/_compile.sh b/tests/bsim/bluetooth/host/misc/unregister_conn_cb/tests_scripts/_compile.sh new file mode 100755 index 00000000000..b6b361b86d4 --- /dev/null +++ b/tests/bsim/bluetooth/host/misc/unregister_conn_cb/tests_scripts/_compile.sh @@ -0,0 +1,17 @@ +#!/usr/bin/env bash +#Copyright (c) 2024 NXP +#Copyright (c) 2024 Nordic Semiconductor ASA +# SPDX-License-Identifier: Apache-2.0 + +# Path checks, etc +source ${ZEPHYR_BASE}/tests/bsim/sh_common.source + +# Place yourself in the test's root (i.e. ./../) +rm -rf ${BSIM_OUT_PATH}/bin/bs_nrf52_bsim_tests* + +# terminate running simulations (if any) +${BSIM_COMPONENTS_PATH}/common/stop_bsim.sh + +bsim_exe=bs_nrf52_bsim_tests_bsim_bluetooth_host_misc_unregister_conn_cb_prj_conf +west build -b nrf52_bsim && \ + cp build/zephyr/zephyr.exe ${BSIM_OUT_PATH}/bin/${bsim_exe} diff --git a/tests/bsim/bluetooth/host/misc/unregister_conn_cb/tests_scripts/unregister_conn_cb.sh b/tests/bsim/bluetooth/host/misc/unregister_conn_cb/tests_scripts/unregister_conn_cb.sh new file mode 100755 index 00000000000..8fc8bcafaf7 --- /dev/null +++ b/tests/bsim/bluetooth/host/misc/unregister_conn_cb/tests_scripts/unregister_conn_cb.sh @@ -0,0 +1,26 @@ +#!/usr/bin/env bash +# Copyright (c) 2024 NXP +# Copyright (c) 2024 Nordic Semiconductor +# SPDX-License-Identifier: Apache-2.0 + +source ${ZEPHYR_BASE}/tests/bsim/sh_common.source + +#Unregister connection callbacks : A central device scans for and connects to a peripheral +#after registered connection callbacks.When the connection state changes, few printing +#will be printed and the flag_is_connected will be changed by the callback function. +#After unregister the connection callbacks, reconnect to peer device, then no printing +#neither flag change can be found, callback function was unregistered as expected +simulation_id="unregister_conn_cb" +verbosity_level=2 +EXECUTE_TIMEOUT=20 + +cd ${BSIM_OUT_PATH}/bin + +bsim_exe=./bs_nrf52_bsim_tests_bsim_bluetooth_host_misc_unregister_conn_cb_prj_conf + +Execute "${bsim_exe}" -v=${verbosity_level} -s=${simulation_id} -d=0 -testid=central -rs=420 +Execute "${bsim_exe}" -v=${verbosity_level} -s=${simulation_id} -d=1 -testid=peripheral -rs=100 + +Execute ./bs_2G4_phy_v1 -v=${verbosity_level} -s=${simulation_id} -D=2 -sim_length=30e6 $@ + +wait_for_background_jobs From 81a1826e13818a3e5c45860bc6b261d1fcb392d7 Mon Sep 17 00:00:00 2001 From: Emil Gydesen Date: Mon, 15 Jan 2024 10:44:56 +0100 Subject: [PATCH 3323/3723] tests: bsim: Bluetooth: CSIP: Increase EXECUTE_TIMEOUT to 30 Some of the CSIP tests take a while to run given the number of devices, and some of them started to fail in CI because of a timeout, so we increase the EXECUTE_TIMEOUT a bit. Signed-off-by: Emil Gydesen --- tests/bsim/bluetooth/audio/test_scripts/csip.sh | 4 ++-- .../bsim/bluetooth/audio/test_scripts/csip_encrypted_sirk.sh | 4 ++-- .../bsim/bluetooth/audio/test_scripts/csip_forced_release.sh | 4 ++-- tests/bsim/bluetooth/audio/test_scripts/csip_no_lock.sh | 4 ++-- tests/bsim/bluetooth/audio/test_scripts/csip_no_rank.sh | 4 ++-- tests/bsim/bluetooth/audio/test_scripts/csip_no_size.sh | 4 ++-- tests/bsim/bluetooth/audio/test_scripts/csip_notify.sh | 2 +- 7 files changed, 13 insertions(+), 13 deletions(-) diff --git a/tests/bsim/bluetooth/audio/test_scripts/csip.sh b/tests/bsim/bluetooth/audio/test_scripts/csip.sh index 82f929a9779..40c7f8e3fc8 100755 --- a/tests/bsim/bluetooth/audio/test_scripts/csip.sh +++ b/tests/bsim/bluetooth/audio/test_scripts/csip.sh @@ -1,6 +1,6 @@ #!/usr/bin/env bash # -# Copyright (c) 2020-2023 Nordic Semiconductor ASA +# Copyright (c) 2020-2024 Nordic Semiconductor ASA # # SPDX-License-Identifier: Apache-2.0 @@ -10,7 +10,7 @@ source ${ZEPHYR_BASE}/tests/bsim/sh_common.source VERBOSITY_LEVEL=2 -EXECUTE_TIMEOUT=20 +EXECUTE_TIMEOUT=30 cd ${BSIM_OUT_PATH}/bin diff --git a/tests/bsim/bluetooth/audio/test_scripts/csip_encrypted_sirk.sh b/tests/bsim/bluetooth/audio/test_scripts/csip_encrypted_sirk.sh index 96b5c511913..b0bdd21f932 100755 --- a/tests/bsim/bluetooth/audio/test_scripts/csip_encrypted_sirk.sh +++ b/tests/bsim/bluetooth/audio/test_scripts/csip_encrypted_sirk.sh @@ -1,6 +1,6 @@ #!/usr/bin/env bash # -# Copyright (c) 2023 Nordic Semiconductor ASA +# Copyright (c) 2023-2024 Nordic Semiconductor ASA # # SPDX-License-Identifier: Apache-2.0 @@ -9,7 +9,7 @@ source ${ZEPHYR_BASE}/tests/bsim/sh_common.source VERBOSITY_LEVEL=2 -EXECUTE_TIMEOUT=20 +EXECUTE_TIMEOUT=30 cd ${BSIM_OUT_PATH}/bin diff --git a/tests/bsim/bluetooth/audio/test_scripts/csip_forced_release.sh b/tests/bsim/bluetooth/audio/test_scripts/csip_forced_release.sh index 93f945027cf..ee901496a64 100755 --- a/tests/bsim/bluetooth/audio/test_scripts/csip_forced_release.sh +++ b/tests/bsim/bluetooth/audio/test_scripts/csip_forced_release.sh @@ -1,6 +1,6 @@ #!/usr/bin/env bash # -# Copyright (c) 2023 Nordic Semiconductor ASA +# Copyright (c) 2023-2024 Nordic Semiconductor ASA # # SPDX-License-Identifier: Apache-2.0 @@ -9,7 +9,7 @@ source ${ZEPHYR_BASE}/tests/bsim/sh_common.source VERBOSITY_LEVEL=2 -EXECUTE_TIMEOUT=20 +EXECUTE_TIMEOUT=30 cd ${BSIM_OUT_PATH}/bin diff --git a/tests/bsim/bluetooth/audio/test_scripts/csip_no_lock.sh b/tests/bsim/bluetooth/audio/test_scripts/csip_no_lock.sh index 22484600c85..bd078ca35d5 100755 --- a/tests/bsim/bluetooth/audio/test_scripts/csip_no_lock.sh +++ b/tests/bsim/bluetooth/audio/test_scripts/csip_no_lock.sh @@ -1,6 +1,6 @@ #!/usr/bin/env bash # -# Copyright (c) 2023 Nordic Semiconductor ASA +# Copyright (c) 2023-2024 Nordic Semiconductor ASA # # SPDX-License-Identifier: Apache-2.0 @@ -9,7 +9,7 @@ source ${ZEPHYR_BASE}/tests/bsim/sh_common.source VERBOSITY_LEVEL=2 -EXECUTE_TIMEOUT=20 +EXECUTE_TIMEOUT=30 cd ${BSIM_OUT_PATH}/bin diff --git a/tests/bsim/bluetooth/audio/test_scripts/csip_no_rank.sh b/tests/bsim/bluetooth/audio/test_scripts/csip_no_rank.sh index 5eebc7759ec..64127a93ebe 100755 --- a/tests/bsim/bluetooth/audio/test_scripts/csip_no_rank.sh +++ b/tests/bsim/bluetooth/audio/test_scripts/csip_no_rank.sh @@ -1,6 +1,6 @@ #!/usr/bin/env bash # -# Copyright (c) 2023 Nordic Semiconductor ASA +# Copyright (c) 2023-2024 Nordic Semiconductor ASA # # SPDX-License-Identifier: Apache-2.0 @@ -9,7 +9,7 @@ source ${ZEPHYR_BASE}/tests/bsim/sh_common.source VERBOSITY_LEVEL=2 -EXECUTE_TIMEOUT=20 +EXECUTE_TIMEOUT=30 cd ${BSIM_OUT_PATH}/bin diff --git a/tests/bsim/bluetooth/audio/test_scripts/csip_no_size.sh b/tests/bsim/bluetooth/audio/test_scripts/csip_no_size.sh index c586fde9205..0334d36470f 100755 --- a/tests/bsim/bluetooth/audio/test_scripts/csip_no_size.sh +++ b/tests/bsim/bluetooth/audio/test_scripts/csip_no_size.sh @@ -1,6 +1,6 @@ #!/usr/bin/env bash # -# Copyright (c) 2023 Nordic Semiconductor ASA +# Copyright (c) 2023-2024 Nordic Semiconductor ASA # # SPDX-License-Identifier: Apache-2.0 @@ -9,7 +9,7 @@ source ${ZEPHYR_BASE}/tests/bsim/sh_common.source VERBOSITY_LEVEL=2 -EXECUTE_TIMEOUT=20 +EXECUTE_TIMEOUT=30 cd ${BSIM_OUT_PATH}/bin diff --git a/tests/bsim/bluetooth/audio/test_scripts/csip_notify.sh b/tests/bsim/bluetooth/audio/test_scripts/csip_notify.sh index ceaf984d037..e5ada46b6c2 100755 --- a/tests/bsim/bluetooth/audio/test_scripts/csip_notify.sh +++ b/tests/bsim/bluetooth/audio/test_scripts/csip_notify.sh @@ -8,7 +8,7 @@ source ${ZEPHYR_BASE}/tests/bsim/sh_common.source SIMULATION_ID="csip_notify" VERBOSITY_LEVEL=2 -EXECUTE_TIMEOUT=200 +EXECUTE_TIMEOUT=30 cd ${BSIM_OUT_PATH}/bin From 508a261286198c529c4161b114a5ee55ded33082 Mon Sep 17 00:00:00 2001 From: Jukka Rissanen Date: Tue, 30 Jan 2024 17:37:45 +0200 Subject: [PATCH 3324/3723] log: net: Convert syslog network transmitter to use sockets Convert the network log backend to use socket API instead of net_context API. This allows the backend to be used also with socket offloading network drivers. Signed-off-by: Jukka Rissanen --- samples/net/syslog_net/prj.conf | 3 +- subsys/logging/backends/Kconfig.net | 10 --- subsys/logging/backends/log_backend_net.c | 86 +++++++++++------------ 3 files changed, 44 insertions(+), 55 deletions(-) diff --git a/samples/net/syslog_net/prj.conf b/samples/net/syslog_net/prj.conf index b0ae6043cef..7bd3870b431 100644 --- a/samples/net/syslog_net/prj.conf +++ b/samples/net/syslog_net/prj.conf @@ -7,6 +7,7 @@ CONFIG_NET_PKT_RX_COUNT=32 CONFIG_NET_PKT_TX_COUNT=32 CONFIG_NET_BUF_RX_COUNT=32 CONFIG_NET_BUF_TX_COUNT=32 +CONFIG_NET_SOCKETS=y CONFIG_NET_IF_UNICAST_IPV6_ADDR_COUNT=3 CONFIG_NET_IF_MCAST_IPV6_ADDR_COUNT=5 @@ -36,5 +37,5 @@ CONFIG_NET_CONFIG_PEER_IPV4_ADDR="192.0.2.2" CONFIG_LOG_BACKEND_NET=y CONFIG_LOG_BACKEND_NET_SERVER="[2001:db8::2]:514" -# Get newlib by default as it has proper time function support +# Get a proper libc by default in order to get working time function support CONFIG_REQUIRES_FULL_LIBC=y diff --git a/subsys/logging/backends/Kconfig.net b/subsys/logging/backends/Kconfig.net index 6823c760ba7..36a5096235b 100644 --- a/subsys/logging/backends/Kconfig.net +++ b/subsys/logging/backends/Kconfig.net @@ -6,7 +6,6 @@ config LOG_BACKEND_NET bool "Networking backend" depends on NETWORKING && NET_UDP && !LOG_MODE_IMMEDIATE - select NET_CONTEXT_NET_PKT_POOL select LOG_OUTPUT help Send syslog messages to network server. @@ -27,15 +26,6 @@ config LOG_BACKEND_NET_SERVER [2001:db8::2] 2001:db::42 -config LOG_BACKEND_NET_MAX_BUF - int "How many network buffers to allocate for sending messages" - range 3 256 - default 3 - help - Each syslog message should fit into a network packet that will be - sent to server. This number tells how many syslog messages can be - in transit to the server. - config LOG_BACKEND_NET_MAX_BUF_SIZE int "Max syslog message size" range 64 1180 diff --git a/subsys/logging/backends/log_backend_net.c b/subsys/logging/backends/log_backend_net.c index 405bb563b65..53fe78f243b 100644 --- a/subsys/logging/backends/log_backend_net.c +++ b/subsys/logging/backends/log_backend_net.c @@ -11,8 +11,7 @@ LOG_MODULE_REGISTER(log_backend_net, CONFIG_LOG_DEFAULT_LEVEL); #include #include #include -#include -#include +#include /* Set this to 1 if you want to see what is being sent to server */ #define DEBUG_PRINTING 0 @@ -37,34 +36,24 @@ struct sockaddr server_addr; static bool panic_mode; static uint32_t log_format_current = CONFIG_LOG_BACKEND_NET_OUTPUT_DEFAULT; -const struct log_backend *log_backend_net_get(void); - -NET_PKT_SLAB_DEFINE(syslog_tx_pkts, CONFIG_LOG_BACKEND_NET_MAX_BUF); -NET_PKT_DATA_POOL_DEFINE(syslog_tx_bufs, - ROUND_UP(CONFIG_LOG_BACKEND_NET_MAX_BUF_SIZE / - CONFIG_NET_BUF_DATA_SIZE, 1) * - CONFIG_LOG_BACKEND_NET_MAX_BUF); - -static struct k_mem_slab *get_tx_slab(void) -{ - return &syslog_tx_pkts; -} +static struct log_backend_net_ctx { + int sock; +} ctx = { + .sock = -1, +}; -struct net_buf_pool *get_data_pool(void) -{ - return &syslog_tx_bufs; -} +const struct log_backend *log_backend_net_get(void); static int line_out(uint8_t *data, size_t length, void *output_ctx) { - struct net_context *ctx = (struct net_context *)output_ctx; + struct log_backend_net_ctx *ctx = (struct log_backend_net_ctx *)output_ctx; int ret = -ENOMEM; if (ctx == NULL) { return length; } - ret = net_context_send(ctx, data, length, NULL, K_NO_WAIT, NULL); + ret = zsock_send(ctx->sock, data, length, ZSOCK_MSG_DONTWAIT); if (ret < 0) { goto fail; } @@ -76,13 +65,12 @@ static int line_out(uint8_t *data, size_t length, void *output_ctx) LOG_OUTPUT_DEFINE(log_output_net, line_out, output_buf, sizeof(output_buf)); -static int do_net_init(void) +static int do_net_init(struct log_backend_net_ctx *ctx) { struct sockaddr *local_addr = NULL; struct sockaddr_in6 local_addr6 = {0}; struct sockaddr_in local_addr4 = {0}; socklen_t server_addr_len; - struct net_context *ctx; int ret; if (IS_ENABLED(CONFIG_NET_IPV4) && server_addr.sa_family == AF_INET) { @@ -104,13 +92,15 @@ static int do_net_init(void) local_addr->sa_family = server_addr.sa_family; - ret = net_context_get(server_addr.sa_family, SOCK_DGRAM, IPPROTO_UDP, - &ctx); + ret = zsock_socket(server_addr.sa_family, SOCK_DGRAM, IPPROTO_UDP); if (ret < 0) { - DBG("Cannot get context (%d)\n", ret); + ret = -errno; + DBG("Cannot get socket (%d)\n", ret); return ret; } + ctx->sock = ret; + if (IS_ENABLED(CONFIG_NET_HOSTNAME_ENABLE)) { (void)strncpy(dev_hostname, net_hostname_get(), MAX_HOSTNAME_LEN); @@ -147,30 +137,35 @@ static int do_net_init(void) } else { unknown: - DBG("Cannot setup local context\n"); - return -EINVAL; + DBG("Cannot setup local socket\n"); + ret = -EINVAL; + goto err; } - ret = net_context_bind(ctx, local_addr, server_addr_len); + ret = zsock_bind(ctx->sock, local_addr, server_addr_len); if (ret < 0) { - DBG("Cannot bind context (%d)\n", ret); - return ret; + ret = -errno; + DBG("Cannot bind socket (%d)\n", ret); + goto err; } - (void)net_context_connect(ctx, &server_addr, server_addr_len, - NULL, K_NO_WAIT, NULL); - - /* We do not care about return value for this UDP connect call that - * basically does nothing. Calling the connect is only useful so that - * we can see the syslog connection in net-shell. - */ - - net_context_setup_pools(ctx, get_tx_slab, get_data_pool); + ret = zsock_connect(ctx->sock, &server_addr, server_addr_len); + if (ret < 0) { + ret = -errno; + DBG("Cannot connect socket (%d)\n", ret); + goto err; + } log_output_ctx_set(&log_output_net, ctx); log_output_hostname_set(&log_output_net, dev_hostname); return 0; + +err: + (void)zsock_close(ctx->sock); + ctx->sock = -1; + + return ret; } static void process(const struct log_backend *const backend, @@ -182,7 +177,7 @@ static void process(const struct log_backend *const backend, return; } - if (!net_init_done && do_net_init() == 0) { + if (!net_init_done && do_net_init(&ctx) == 0) { net_init_done = true; } @@ -205,19 +200,23 @@ bool log_backend_net_set_addr(const char *addr) /* Release context so it can be recreated with the specified ip address * next time process() is called */ - int released = net_context_put(log_output_net.control_block->ctx); + struct log_backend_net_ctx *ctx = log_output_net.control_block->ctx; + int released; + released = zsock_close(ctx->sock); if (released < 0) { - LOG_ERR("Cannot release context (%d)", ret); + LOG_ERR("Cannot release socket (%d)", ret); ret = false; } else { - /* The context is successfully released so we flag it + /* The socket is successfully closed so we flag it * to be recreated with the new ip address */ net_init_done = false; ret = true; } + ctx->sock = -1; + if (!ret) { return ret; } @@ -226,7 +225,6 @@ bool log_backend_net_set_addr(const char *addr) net_sin(&server_addr)->sin_port = htons(514); ret = net_ipaddr_parse(addr, strlen(addr), &server_addr); - if (!ret) { LOG_ERR("Cannot parse syslog server address"); return ret; From de5586d7ec105d62b093c8bb95dc4bb45cd692eb Mon Sep 17 00:00:00 2001 From: Derek Snell Date: Thu, 25 Jan 2024 10:23:52 -0500 Subject: [PATCH 3325/3723] boards: arm: lpcxpresso55s69_cpu0: enable DMA The DMA is already enabled for this board, but updating the board doc page to make that clear, and enabling the DMA loop_transfer test. Signed-off-by: Derek Snell --- boards/arm/lpcxpresso55s69/doc/index.rst | 2 ++ .../dma/loop_transfer/boards/lpcxpresso55s69_cpu0.overlay | 7 +++++++ 2 files changed, 9 insertions(+) create mode 100644 tests/drivers/dma/loop_transfer/boards/lpcxpresso55s69_cpu0.overlay diff --git a/boards/arm/lpcxpresso55s69/doc/index.rst b/boards/arm/lpcxpresso55s69/doc/index.rst index d6c16095f53..1f8d46cef48 100644 --- a/boards/arm/lpcxpresso55s69/doc/index.rst +++ b/boards/arm/lpcxpresso55s69/doc/index.rst @@ -101,6 +101,8 @@ configuration supports the following hardware features: +-----------+------------+-------------------------------------+ | SDIF | on-chip | sdhc | +-----------+------------+-------------------------------------+ +| DMA | on-chip | dma (on CPU0) | ++-----------+------------+-------------------------------------+ Targets available ================== diff --git a/tests/drivers/dma/loop_transfer/boards/lpcxpresso55s69_cpu0.overlay b/tests/drivers/dma/loop_transfer/boards/lpcxpresso55s69_cpu0.overlay new file mode 100644 index 00000000000..1b3d3f8bbae --- /dev/null +++ b/tests/drivers/dma/loop_transfer/boards/lpcxpresso55s69_cpu0.overlay @@ -0,0 +1,7 @@ +/* + * Copyright 2024 NXP + * + * SPDX-License-Identifier: Apache-2.0 + */ + +test_dma0: &dma0 { }; From 8bc61e2b518b4efc88ccceb21b621ef60d3094fc Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Krzysztof=20Chru=C5=9Bci=C5=84ski?= Date: Fri, 19 Jan 2024 09:22:39 +0100 Subject: [PATCH 3326/3723] drivers: spi: Add missing retval to spi_read calls MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit spi_transceive returns number of received frames for slave mode. This information was missing for spi_read type of functions. Signed-off-by: Krzysztof Chruściński --- include/zephyr/drivers/spi.h | 2 ++ 1 file changed, 2 insertions(+) diff --git a/include/zephyr/drivers/spi.h b/include/zephyr/drivers/spi.h index 44863f49acd..7042c73be0a 100644 --- a/include/zephyr/drivers/spi.h +++ b/include/zephyr/drivers/spi.h @@ -799,6 +799,7 @@ static inline int spi_transceive_dt(const struct spi_dt_spec *spec, * previous operations. * @param rx_bufs Buffer array where data to be read will be written to. * + * @retval frames Positive number of frames received in slave mode. * @retval 0 If successful. * @retval -errno Negative errno code on failure. */ @@ -987,6 +988,7 @@ __deprecated static inline int spi_transceive_async(const struct device *dev, * notify the end of the transaction, and whether it went * successfully or not). * + * @retval frames Positive number of frames received in slave mode. * @retval 0 If successful * @retval -errno Negative errno code on failure. */ From 38e0e6e5556575b2e1e4c072ae2add075181a1c5 Mon Sep 17 00:00:00 2001 From: Andries Kruithof Date: Thu, 1 Feb 2024 14:32:26 +0100 Subject: [PATCH 3327/3723] Bluetooth: audio: BAP: fix Kconfig description The description for BT_BAP_SCAN_DELEGATOR_BUF_TIMEOUT is a bit misleading. Rewriting this to be more accurate Signed-off-by: Andries Kruithof --- subsys/bluetooth/audio/Kconfig.bap | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/subsys/bluetooth/audio/Kconfig.bap b/subsys/bluetooth/audio/Kconfig.bap index e34428eb85b..ae3b6c8d5fa 100644 --- a/subsys/bluetooth/audio/Kconfig.bap +++ b/subsys/bluetooth/audio/Kconfig.bap @@ -240,8 +240,8 @@ config BT_BAP_SCAN_DELEGATOR_BUF_TIMEOUT range 0 1000 default 50 help - The number of milliseconds that the scan delegator implementation will maximum wait - before rejecting a ASE read or dropping a notification if the scan delegator state is + The maximum number of milliseconds that the scan delegator implementation will wait + before rejecting a read or dropping a notification if the scan delegator state is being accessed by another thread. endif # BT_BAP_SCAN_DELEGATOR From 545cf8cd2f8be85948bf8a15cee343a10e86a9b6 Mon Sep 17 00:00:00 2001 From: Daniel Leung Date: Fri, 26 Jan 2024 15:18:55 -0800 Subject: [PATCH 3328/3723] xtensa: print THREADPTR when dumping stack Print THREADPTR when dumping stack just like other registers. There is no need to guard that behind CONFIG_USERSPACE. Signed-off-by: Daniel Leung --- arch/xtensa/core/vector_handlers.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/arch/xtensa/core/vector_handlers.c b/arch/xtensa/core/vector_handlers.c index 3334af67b7b..0a99ec5dd09 100644 --- a/arch/xtensa/core/vector_handlers.c +++ b/arch/xtensa/core/vector_handlers.c @@ -89,6 +89,10 @@ void xtensa_dump_stack(const z_arch_esf_t *stack) #endif LOG_ERR(" ** SAR %p", (void *)bsa->sar); + +#if XCHAL_HAVE_THREADPTR + LOG_ERR(" ** THREADPTR %p", (void *)bsa->threadptr); +#endif } static inline unsigned int get_bits(int offset, int num_bits, unsigned int val) @@ -122,10 +126,6 @@ static void print_fatal_exception(void *print_stack, int cause, LOG_ERR(" ** DEPC %p", (void *)depc); } -#ifdef CONFIG_USERSPACE - LOG_ERR(" ** THREADPTR %p", (void *)bsa->threadptr); -#endif /* CONFIG_USERSPACE */ - LOG_ERR(" ** PS %p", (void *)bsa->ps); LOG_ERR(" ** (INTLEVEL:%d EXCM: %d UM:%d RING:%d WOE:%d OWB:%d CALLINC:%d)", get_bits(0, 4, ps), get_bits(4, 1, ps), From 5d8b43feffc55ebcbb2aa7cbb3a75f6d704812ac Mon Sep 17 00:00:00 2001 From: Daniel Leung Date: Fri, 26 Jan 2024 15:42:03 -0800 Subject: [PATCH 3329/3723] xtensa: only need ZSR_FLUSH if CONFIG_KERNEL_COHERENCE The ZSR_FLUSH scratch register is only needed if kconfig CONFIG_KERNEL_COHERENCE is enabled. So update gen_zsr.py for that. Signed-off-by: Daniel Leung --- arch/xtensa/core/CMakeLists.txt | 1 + arch/xtensa/core/gen_zsr.py | 6 +++++- 2 files changed, 6 insertions(+), 1 deletion(-) diff --git a/arch/xtensa/core/CMakeLists.txt b/arch/xtensa/core/CMakeLists.txt index f1f82dc3834..db0909bb4f8 100644 --- a/arch/xtensa/core/CMakeLists.txt +++ b/arch/xtensa/core/CMakeLists.txt @@ -61,6 +61,7 @@ set(ZSR_H ${CMAKE_BINARY_DIR}/zephyr/include/generated/zsr.h) add_custom_command(OUTPUT ${ZSR_H} DEPENDS ${CORE_ISA_DM} COMMAND ${PYTHON_EXECUTABLE} ${CMAKE_CURRENT_SOURCE_DIR}/gen_zsr.py $<$:--mmu> + $<$:--coherence> ${CORE_ISA_DM} ${ZSR_H}) add_custom_target(zsr_h DEPENDS ${ZSR_H}) add_dependencies(zephyr_interface zsr_h) diff --git a/arch/xtensa/core/gen_zsr.py b/arch/xtensa/core/gen_zsr.py index 0e3069a4c45..7f0ec46b8e9 100755 --- a/arch/xtensa/core/gen_zsr.py +++ b/arch/xtensa/core/gen_zsr.py @@ -14,6 +14,8 @@ def parse_args(): parser = argparse.ArgumentParser(allow_abbrev=False) + parser.add_argument("--coherence", action="store_true", + help="Enable scratch registers for CONFIG_KERNEL_COHERENCE") parser.add_argument("--mmu", action="store_true", help="Enable scratch registers for MMU usage") parser.add_argument("coreisa", @@ -25,9 +27,11 @@ def parse_args(): args = parse_args() -NEEDED = ["A0SAVE", "CPU", "FLUSH"] +NEEDED = ["A0SAVE", "CPU"] if args.mmu: NEEDED += ["MMU_0", "MMU_1", "DBLEXC"] +if args.coherence: + NEEDED += ["FLUSH"] coreisa = args.coreisa outfile = args.outfile From 39d9d0a2fc6883b4b1f1caab9f4f0f9a61652d56 Mon Sep 17 00:00:00 2001 From: Daniel Leung Date: Mon, 29 Jan 2024 12:05:16 -0800 Subject: [PATCH 3330/3723] xtensa: remove ARG_UNUSED from arch_syscall_oops ssf is being passed to xtensa_arch_kernel_oops() so there is no need to mark ssf with ARG_UNUSED. Signed-off-by: Daniel Leung --- arch/xtensa/core/fatal.c | 2 -- 1 file changed, 2 deletions(-) diff --git a/arch/xtensa/core/fatal.c b/arch/xtensa/core/fatal.c index faf6c38a33f..c6bd07c2b44 100644 --- a/arch/xtensa/core/fatal.c +++ b/arch/xtensa/core/fatal.c @@ -132,8 +132,6 @@ FUNC_NORETURN void z_system_halt(unsigned int reason) FUNC_NORETURN void arch_syscall_oops(void *ssf) { - ARG_UNUSED(ssf); - xtensa_arch_kernel_oops(K_ERR_KERNEL_OOPS, ssf); CODE_UNREACHABLE; From 02baa658d2f7e3d0e6005bf28d0adec16829b45b Mon Sep 17 00:00:00 2001 From: Daniel Leung Date: Mon, 29 Jan 2024 15:45:47 -0800 Subject: [PATCH 3331/3723] xtensa: remove unneeded addi in xtensa_userspace_enter There is no need to do a addi to a1 because it is immediately overwritten anyway. Signed-off-by: Daniel Leung --- arch/xtensa/core/userspace.S | 2 -- 1 file changed, 2 deletions(-) diff --git a/arch/xtensa/core/userspace.S b/arch/xtensa/core/userspace.S index f385d7223ea..f840aec6c04 100644 --- a/arch/xtensa/core/userspace.S +++ b/arch/xtensa/core/userspace.S @@ -265,8 +265,6 @@ xtensa_userspace_enter: /* stash user stack */ l32i a0, a1, 4 - addi a1, a1, 28 - /* Go back to user stack */ mov a1, a0 From f61bbad625e0f23ee354512c177c8545f8594393 Mon Sep 17 00:00:00 2001 From: Patrick Wildt Date: Tue, 3 Oct 2023 11:43:10 +0000 Subject: [PATCH 3332/3723] spsc_pbuf: fix cache invalidation in spsc_pbuf_free In case the read index points to the end of the packet buffer and thus wraps around, we must not invalidate the cache, otherwise we draw outside of the lines and purge data outside of our responsibility. Signed-off-by: Patrick Wildt --- lib/os/spsc_pbuf.c | 24 ++++++++++++------------ 1 file changed, 12 insertions(+), 12 deletions(-) diff --git a/lib/os/spsc_pbuf.c b/lib/os/spsc_pbuf.c index 50e63c639ed..748be9fc1be 100644 --- a/lib/os/spsc_pbuf.c +++ b/lib/os/spsc_pbuf.c @@ -327,21 +327,21 @@ void spsc_pbuf_free(struct spsc_pbuf *pb, uint16_t len) uint8_t *data_loc = get_data_loc(pb, flags); rd_idx = ROUND_UP(rd_idx, sizeof(uint32_t)); - cache_inv(&data_loc[rd_idx], sizeof(uint8_t), flags); /* Handle wrapping or the fact that next packet is a padding. */ - if (rd_idx == pblen) { - rd_idx = 0; - } else if (data_loc[rd_idx] == PADDING_MARK) { - cache_inv(wr_idx_loc, sizeof(*wr_idx_loc), flags); - /* We may hit the case when producer is in the middle of adding - * a padding (which happens in 2 steps: writing padding, resetting - * write index) and in that case we cannot consume this padding. - */ - if (rd_idx != *wr_idx_loc) { - rd_idx = 0; + if (rd_idx != pblen) { + cache_inv(&data_loc[rd_idx], sizeof(uint8_t), flags); + if (data_loc[rd_idx] == PADDING_MARK) { + cache_inv(wr_idx_loc, sizeof(*wr_idx_loc), flags); + /* We may hit the case when producer is in the middle of adding + * a padding (which happens in 2 steps: writing padding, resetting + * write index) and in that case we cannot consume this padding. + */ + if (rd_idx != *wr_idx_loc) { + rd_idx = 0; + } } } else { - /* empty */ + rd_idx = 0; } *rd_idx_loc = rd_idx; From 83283a04a167ed6d89aba2a305691c51b06448a8 Mon Sep 17 00:00:00 2001 From: Laurentiu Mihalcea Date: Mon, 29 Jan 2024 14:05:10 +0200 Subject: [PATCH 3333/3723] manifest: update hal_nxp Update hal_nxp revision to contain the fix for build error when trying to use dma_nxp_edma.c DMA driver. Signed-off-by: Laurentiu Mihalcea --- west.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/west.yml b/west.yml index 70a8d7781fa..92dcff0d456 100644 --- a/west.yml +++ b/west.yml @@ -193,7 +193,7 @@ manifest: groups: - hal - name: hal_nxp - revision: e6b0d96d865da1bdda357073570a13ae95e08d9c + revision: ae438701d6029f4f989fe036abe4b91be51e6258 path: modules/hal/nxp groups: - hal From 6644fa9104ce9da1ef521a68cf873d75ddccfd66 Mon Sep 17 00:00:00 2001 From: Laurentiu Mihalcea Date: Mon, 22 Jan 2024 13:14:46 +0200 Subject: [PATCH 3334/3723] dai: nxp: sai: Disable data line on pause trigger Currently, whenever performing TRIGGER_PAUSE operation, the data line is not disabled. This works well if TX and RX don't operate at the same time or they operate in ASYNC-ASYNC mode. This is because sai_tx_rx_disable() will disable transmitter/receiver all the time since there's no dependencies to take into consideration. However, in the ASYNC-SYNC mode, sai_tx_rx_disable() may not disable the current asynchronous side if the synchronous side is still enabled. As a consequence, the asynchronous side will remain enabled, thus leading to an underrun/overrun. To fix this issue, sai_trigger_pause() should disable the data line each time it's called. This way, even if sai_tx_rx_disable() doesn't disable the current direction, the data line will be disabled, thus stopping the consumption/production of frames. Signed-off-by: Laurentiu Mihalcea --- drivers/dai/nxp/sai/sai.c | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/drivers/dai/nxp/sai/sai.c b/drivers/dai/nxp/sai/sai.c index 3addb5670f2..9146c2c67ae 100644 --- a/drivers/dai/nxp/sai/sai.c +++ b/drivers/dai/nxp/sai/sai.c @@ -563,6 +563,9 @@ static int sai_trigger_pause(const struct device *dev, return ret; } + /* disable TX/RX data line */ + sai_tx_rx_set_dline_mask(dir, data->regmap, 0x0); + /* update the software state of TX/RX */ sai_tx_rx_sw_enable_disable(dir, data, false); @@ -601,7 +604,7 @@ static int sai_trigger_stop(const struct device *dev, * left to do is disable the DMA requests and * the data line. */ - goto out_dline_disable; + goto out_dmareq_disable; } ret = sai_tx_rx_disable(data, cfg, dir); @@ -612,10 +615,10 @@ static int sai_trigger_stop(const struct device *dev, /* update the software state of TX/RX */ sai_tx_rx_sw_enable_disable(dir, data, false); -out_dline_disable: /* disable TX/RX data line */ sai_tx_rx_set_dline_mask(dir, data->regmap, 0x0); +out_dmareq_disable: /* disable DMA requests */ SAI_TX_RX_DMA_ENABLE_DISABLE(dir, data->regmap, false); @@ -719,7 +722,7 @@ static int sai_trigger_start(const struct device *dev, * skip this part and go directly to the TX/RX * enablement. */ - goto out_enable_tx_rx; + goto out_enable_dline; } LOG_DBG("start on direction %d", dir); @@ -735,6 +738,7 @@ static int sai_trigger_start(const struct device *dev, /* TODO: for now, only DMA mode is supported */ SAI_TX_RX_DMA_ENABLE_DISABLE(dir, data->regmap, true); +out_enable_dline: /* enable TX/RX data line. This translates to TX_DLINE0/RX_DLINE0 * being enabled. * @@ -742,7 +746,6 @@ static int sai_trigger_start(const struct device *dev, */ sai_tx_rx_set_dline_mask(dir, data->regmap, 0x1); -out_enable_tx_rx: /* this will also enable the async side */ SAI_TX_RX_ENABLE_DISABLE(dir, data->regmap, true); From bbc1087e83866d109803e7b45313bed91b03de54 Mon Sep 17 00:00:00 2001 From: Sumit Batra Date: Tue, 30 Jan 2024 12:06:27 +0530 Subject: [PATCH 3335/3723] drivers: eth: s32 gmac: Handle link change These changes enable - 1. S32 gmac driver to gracefully handle net iface down and up net shell commands and 2. Link connect or disconnect events between Ethernet PHY and its link partner. Signed-off-by: Sumit Batra --- drivers/ethernet/eth_nxp_s32_gmac.c | 132 +++++++++++++++++++++++++++- 1 file changed, 129 insertions(+), 3 deletions(-) diff --git a/drivers/ethernet/eth_nxp_s32_gmac.c b/drivers/ethernet/eth_nxp_s32_gmac.c index 71e3e94c176..67a725d1fc5 100644 --- a/drivers/ethernet/eth_nxp_s32_gmac.c +++ b/drivers/ethernet/eth_nxp_s32_gmac.c @@ -15,6 +15,7 @@ LOG_MODULE_REGISTER(nxp_s32_eth, CONFIG_ETHERNET_LOG_LEVEL); #include #include #include +#include #include #include @@ -42,6 +43,7 @@ struct eth_nxp_s32_config { uint32_t tx_irq; void (*do_config)(void); const struct pinctrl_dev_config *pincfg; + const struct device *phy_dev; const Gmac_CtrlConfigType ctrl_cfg; GMAC_Type *base; @@ -50,6 +52,7 @@ struct eth_nxp_s32_config { struct eth_nxp_s32_data { struct net_if *iface; uint8_t mac_addr[ETH_NXP_S32_MAC_ADDR_LEN]; + uint8_t if_suspended; struct k_mutex tx_mutex; struct k_sem rx_sem; struct k_sem tx_sem; @@ -78,6 +81,72 @@ static inline struct net_if *get_iface(struct eth_nxp_s32_data *ctx, uint16_t vl #endif } +static void convert_phy_to_mac_config(Gmac_Ip_ConfigType *gmac_cfg, enum phy_link_speed phy_speed) +{ + switch (phy_speed) { + case LINK_HALF_10BASE_T: + gmac_cfg->Speed = GMAC_SPEED_10M; + gmac_cfg->Duplex = GMAC_HALF_DUPLEX; + break; + case LINK_FULL_10BASE_T: + gmac_cfg->Speed = GMAC_SPEED_10M; + gmac_cfg->Duplex = GMAC_FULL_DUPLEX; + break; + case LINK_HALF_100BASE_T: + gmac_cfg->Speed = GMAC_SPEED_100M; + gmac_cfg->Duplex = GMAC_HALF_DUPLEX; + break; + case LINK_FULL_100BASE_T: + gmac_cfg->Speed = GMAC_SPEED_100M; + gmac_cfg->Duplex = GMAC_FULL_DUPLEX; + break; + case LINK_HALF_1000BASE_T: + gmac_cfg->Speed = GMAC_SPEED_1G; + gmac_cfg->Duplex = GMAC_HALF_DUPLEX; + break; + case LINK_FULL_1000BASE_T: + __fallthrough; + default: + gmac_cfg->Speed = GMAC_SPEED_1G; + gmac_cfg->Duplex = GMAC_FULL_DUPLEX; + break; + } +} + +static void phy_link_state_changed(const struct device *pdev, + struct phy_link_state *state, + void *user_data) +{ + const struct device *dev = (struct device *)user_data; + const struct eth_nxp_s32_config *cfg = dev->config; + struct eth_nxp_s32_data *ctx = dev->data; + Gmac_Ip_ConfigType gmac_cfg; + + ARG_UNUSED(pdev); + + if (state->is_up) { + /* Porting phy link config to mac */ + convert_phy_to_mac_config(&gmac_cfg, state->speed); + /* Set MAC configuration */ + Gmac_Ip_SetSpeed(cfg->instance, gmac_cfg.Speed); + + cfg->base->MAC_CONFIGURATION |= GMAC_MAC_CONFIGURATION_DM(gmac_cfg.Duplex); + + /* net iface should be down even if PHY link state is up + * till the upper network layers have suspended the iface. + */ + if (ctx->if_suspended) { + return; + } + + LOG_DBG("Link up"); + net_eth_carrier_on(ctx->iface); + } else { + LOG_DBG("Link down"); + net_eth_carrier_off(ctx->iface); + } +} + #if defined(CONFIG_SOC_SERIES_S32K3XX) static int select_phy_interface(Gmac_Ip_MiiModeType mode) { @@ -167,12 +236,33 @@ static int eth_nxp_s32_init(const struct device *dev) static int eth_nxp_s32_start(const struct device *dev) { const struct eth_nxp_s32_config *cfg = dev->config; + struct eth_nxp_s32_data *ctx = dev->data; + struct phy_link_state state; Gmac_Ip_EnableController(cfg->instance); irq_enable(cfg->rx_irq); irq_enable(cfg->tx_irq); + /* If upper layers enable the net iface then mark it as + * not suspended so that PHY Link changes can have the impact + */ + ctx->if_suspended = false; + + if (cfg->phy_dev) { + phy_get_link_state(cfg->phy_dev, &state); + + /* Enable net_iface only when Ethernet PHY link is up or else + * if net_iface is enabled when link is down and tx happens + * in this state then the used tx buffers will never be recovered back. + */ + if (state.is_up == true) { + net_eth_carrier_on(ctx->iface); + } + } else { + net_eth_carrier_on(ctx->iface); + } + LOG_DBG("GMAC%d started", cfg->instance); return 0; @@ -181,11 +271,19 @@ static int eth_nxp_s32_start(const struct device *dev) static int eth_nxp_s32_stop(const struct device *dev) { const struct eth_nxp_s32_config *cfg = dev->config; + struct eth_nxp_s32_data *ctx = dev->data; Gmac_Ip_StatusType status; int err = 0; - irq_enable(cfg->rx_irq); - irq_enable(cfg->tx_irq); + irq_disable(cfg->rx_irq); + irq_disable(cfg->tx_irq); + + /* If upper layers disable the net iface then mark it as suspended + * in order to save it from the PHY link state changes + */ + ctx->if_suspended = true; + + net_eth_carrier_off(ctx->iface); status = Gmac_Ip_DisableController(cfg->instance); if (status != GMAC_STATUS_SUCCESS) { @@ -250,12 +348,34 @@ static void eth_nxp_s32_iface_init(struct net_if *iface) ethernet_init(iface); net_if_set_link_addr(iface, ctx->mac_addr, sizeof(ctx->mac_addr), NET_LINK_ETHERNET); + LOG_INF("GMAC%d MAC address %02x:%02x:%02x:%02x:%02x:%02x", cfg->instance, ctx->mac_addr[0], ctx->mac_addr[1], ctx->mac_addr[2], ctx->mac_addr[3], ctx->mac_addr[4], ctx->mac_addr[5]); + /* Make sure that the net iface state is not suspended unless + * upper layers explicitly stop the iface + */ + ctx->if_suspended = false; + /* No PHY available, link is always up and MAC speed/duplex settings are fixed */ - net_eth_carrier_on(ctx->iface); + if (cfg->phy_dev == NULL) { + net_if_carrier_on(iface); + return; + } + + /* + * GMAC controls the PHY. If PHY is configured either as fixed + * link or autoneg, the callback is executed at least once + * immediately after setting it. + */ + if (!device_is_ready(cfg->phy_dev)) { + LOG_ERR("PHY device (%p) is not ready, cannot init iface", + cfg->phy_dev); + return; + } + + phy_link_callback_set(cfg->phy_dev, &phy_link_state_changed, (void *)dev); } static int eth_nxp_s32_tx(const struct device *dev, struct net_pkt *pkt) @@ -737,6 +857,11 @@ BUILD_ASSERT((CONFIG_ETH_NXP_S32_TX_RING_BUF_SIZE % FEATURE_GMAC_DATA_BUS_WIDTH_ LISTIFY(__DEBRACKET FEATURE_GMAC_NUM_INSTANCES, \ ETH_NXP_S32_HW_INSTANCE_CHECK, (|), n) +#define ETH_NXP_S32_PHY_DEV(n) \ + COND_CODE_1(ETH_NXP_S32_IS_FIXED_LINK(n), NULL, \ + (COND_CODE_1(DT_INST_NODE_HAS_PROP(n, phy_handle), \ + (DEVICE_DT_GET(DT_INST_PHANDLE(n, phy_handle))), NULL))) + #define ETH_NXP_S32_DEVICE(n) \ ETH_NXP_S32_TX_CALLBACK(n) \ ETH_NXP_S32_RX_CALLBACK(n) \ @@ -757,6 +882,7 @@ BUILD_ASSERT((CONFIG_ETH_NXP_S32_TX_RING_BUF_SIZE % FEATURE_GMAC_DATA_BUS_WIDTH_ .ctrl_cfg = ETH_NXP_S32_CTRL_CONFIG(n), \ .do_config = eth_nxp_s32_init_config_##n, \ .pincfg = PINCTRL_DT_INST_DEV_CONFIG_GET(n), \ + .phy_dev = ETH_NXP_S32_PHY_DEV(n), \ .rx_irq = DT_INST_IRQ_BY_NAME(n, rx, irq), \ .tx_irq = DT_INST_IRQ_BY_NAME(n, tx, irq), \ .tx_ring_idx = 0U, \ From 286a3ce37f77c223f14e7fb09ca73b3d7de2eadf Mon Sep 17 00:00:00 2001 From: Sumit Batra Date: Tue, 30 Jan 2024 12:07:40 +0530 Subject: [PATCH 3336/3723] drivers: eth: phy: tja1103: Handle link change drivers: eth: phy: tja1103: Handle link change These changes enable - TJA1103 driver to gracefully handle Link connect or disconnect events between Ethernet PHY and its link partner and notify it to the upper network layers Signed-off-by: Sumit Batra --- .../arm/mr_canhubk3/mr_canhubk3-pinctrl.dtsi | 2 +- boards/arm/mr_canhubk3/mr_canhubk3.dts | 2 + drivers/ethernet/phy/Kconfig | 9 +- drivers/ethernet/phy/Kconfig.tja1103 | 30 +++ drivers/ethernet/phy/phy_tja1103.c | 242 +++++++++++++++++- dts/bindings/ethernet/nxp,tja1103.yaml | 5 + 6 files changed, 267 insertions(+), 23 deletions(-) create mode 100644 drivers/ethernet/phy/Kconfig.tja1103 diff --git a/boards/arm/mr_canhubk3/mr_canhubk3-pinctrl.dtsi b/boards/arm/mr_canhubk3/mr_canhubk3-pinctrl.dtsi index e057aeb1ef6..49c4d164c81 100644 --- a/boards/arm/mr_canhubk3/mr_canhubk3-pinctrl.dtsi +++ b/boards/arm/mr_canhubk3/mr_canhubk3-pinctrl.dtsi @@ -9,7 +9,7 @@ &pinctrl { eirq0_default: eirq0_default { group1 { - pinmux = , , ; + pinmux = , , , ; input-enable; }; }; diff --git a/boards/arm/mr_canhubk3/mr_canhubk3.dts b/boards/arm/mr_canhubk3/mr_canhubk3.dts index 97bca1402b4..b0866f7073a 100644 --- a/boards/arm/mr_canhubk3/mr_canhubk3.dts +++ b/boards/arm/mr_canhubk3/mr_canhubk3.dts @@ -443,6 +443,7 @@ pinctrl-names = "default"; phy-connection-type = "rmii"; local-mac-address = [02 04 9f aa bb cc]; + phy-handle = <&phy>; status = "okay"; }; @@ -455,6 +456,7 @@ compatible = "nxp,tja1103"; status = "okay"; reg = <0x12>; + int-gpios = <&gpiod_l 5 GPIO_ACTIVE_LOW>; master-slave = "slave"; }; }; diff --git a/drivers/ethernet/phy/Kconfig b/drivers/ethernet/phy/Kconfig index ad7cef7bc17..e14a27a398d 100644 --- a/drivers/ethernet/phy/Kconfig +++ b/drivers/ethernet/phy/Kconfig @@ -11,6 +11,7 @@ module-dep = LOG module-str = Log level for Ethernet PHY driver module-help = Sets log level for Ethernet PHY Device Drivers. source "subsys/net/Kconfig.template.log_config.net" +source "drivers/ethernet/phy/Kconfig.tja1103" config PHY_INIT_PRIORITY int "Ethernet PHY driver init priority" @@ -38,14 +39,6 @@ config PHY_ADIN2111 help Enable ADIN2111 PHY driver. -config PHY_TJA1103 - bool "TJA1103 PHY driver" - default y - depends on DT_HAS_NXP_TJA1103_ENABLED - depends on MDIO - help - Enable TJA1103 PHY driver. - config PHY_MICROCHIP_KSZ8081 bool "Microchip KSZ8081 Phy Driver" default y diff --git a/drivers/ethernet/phy/Kconfig.tja1103 b/drivers/ethernet/phy/Kconfig.tja1103 new file mode 100644 index 00000000000..e0a00955ce7 --- /dev/null +++ b/drivers/ethernet/phy/Kconfig.tja1103 @@ -0,0 +1,30 @@ +# NXP PHY TJA1103 driver configuration options + +# Copyright 2024 NXP +# SPDX-License-Identifier: Apache-2.0 + +menuconfig PHY_TJA1103 + bool "TJA1103 PHY driver" + default y + depends on DT_HAS_NXP_TJA1103_ENABLED + depends on MDIO + help + Enable TJA1103 PHY driver. + +if PHY_TJA1103 + +config PHY_TJA1103_IRQ_THREAD_STACK_SIZE + int "Stack size for a thread that processes TJA1103 IRQ" + default 2048 + help + Size of the stack used for internal thread which is ran to + process raised INT IRQ. + +config PHY_TJA1103_IRQ_THREAD_PRIO + int "Priority for internal incoming packet handler" + default 2 + help + Priority level for internal thread which is ran for TJA1103 + INT IRQ processing. + +endif # PHY_TJA1103 diff --git a/drivers/ethernet/phy/phy_tja1103.c b/drivers/ethernet/phy/phy_tja1103.c index 946a4d16200..659fdbf80aa 100644 --- a/drivers/ethernet/phy/phy_tja1103.c +++ b/drivers/ethernet/phy/phy_tja1103.c @@ -16,6 +16,7 @@ #include #include #include +#include #include #include @@ -40,15 +41,39 @@ LOG_MODULE_REGISTER(phy_tja1103, CONFIG_PHY_LOG_LEVEL); #define TJA1103_PHY_STATUS (0x8102U) #define TJA1103_PHY_STATUS_LINK_STAT BIT(2) +/* Shared - PHY functional IRQ masked status register */ +#define TJA1103_PHY_FUNC_IRQ_MSTATUS (0x80A2) +#define TJA1103_PHY_FUNC_IRQ_LINK_EVENT BIT(1) +#define TJA1103_PHY_FUNC_IRQ_LINK_AVAIL BIT(2) +/* Shared -PHY functional IRQ source & enable registers */ +#define TJA1103_PHY_FUNC_IRQ_ACK (0x80A0) +#define TJA1103_PHY_FUNC_IRQ_EN (0x80A1) +#define TJA1103_PHY_FUNC_IRQ_LINK_EVENT_EN BIT(1) +#define TJA1103_PHY_FUNC_IRQ_LINK_AVAIL_EN BIT(2) +/* Always accessible reg for NMIs */ +#define TJA1103_ALWAYS_ACCESSIBLE (0x801F) +#define TJA1103_ALWAYS_ACCESSIBLE_FUSA_PASS_IRQ BIT(4) + struct phy_tja1103_config { const struct device *mdio; + struct gpio_dt_spec gpio_interrupt; uint8_t phy_addr; uint8_t master_slave; }; struct phy_tja1103_data { + const struct device *dev; struct phy_link_state state; struct k_sem sem; + struct k_sem offload_sem; + phy_callback_t cb; + struct gpio_callback phy_tja1103_int_callback; + void *cb_data; + + K_KERNEL_STACK_MEMBER(irq_thread_stack, CONFIG_PHY_TJA1103_IRQ_THREAD_STACK_SIZE); + struct k_thread irq_thread; + + struct k_work_delayable monitor_work; }; static inline int phy_tja1103_c22_read(const struct device *dev, uint16_t reg, uint16_t *val) @@ -128,23 +153,189 @@ static int phy_tja1103_id(const struct device *dev, uint32_t *phy_id) return 0; } -static int phy_tja1103_get_link_state(const struct device *dev, struct phy_link_state *state) +static int update_link_state(const struct device *dev) { struct phy_tja1103_data *const data = dev->data; + bool link_up; uint16_t val; + if (phy_tja1103_c45_read(dev, MDIO_MMD_VENDOR_SPECIFIC1, TJA1103_PHY_STATUS, &val) < 0) { + return -EIO; + } + + link_up = (val & TJA1103_PHY_STATUS_LINK_STAT) != 0; + + /* Let workqueue re-schedule and re-check if the + * link status is unchanged this time + */ + if (data->state.is_up == link_up) { + return -EAGAIN; + } + + data->state.is_up = link_up; + + return 0; +} + +static int phy_tja1103_get_link_state(const struct device *dev, struct phy_link_state *state) +{ + struct phy_tja1103_data *const data = dev->data; + const struct phy_tja1103_config *const cfg = dev->config; + int rc = 0; + k_sem_take(&data->sem, K_FOREVER); - if (phy_tja1103_c45_read(dev, MDIO_MMD_VENDOR_SPECIFIC1, TJA1103_PHY_STATUS, &val) >= 0) { + /* If Interrupt is configured then the workqueue will not + * update the link state periodically so do it explicitly + */ + if (cfg->gpio_interrupt.port != NULL) { + rc = update_link_state(dev); + } + + memcpy(state, &data->state, sizeof(struct phy_link_state)); + + k_sem_give(&data->sem); + + return rc; +} + +static void invoke_link_cb(const struct device *dev) +{ + struct phy_tja1103_data *const data = dev->data; + struct phy_link_state state; - data->state.is_up = (val & TJA1103_PHY_STATUS_LINK_STAT) != 0; + if (data->cb == NULL) { + return; + } - memcpy(state, &data->state, sizeof(struct phy_link_state)); + /* Send callback only on link state change */ + if (phy_tja1103_get_link_state(dev, &state) != 0) { + return; } + data->cb(dev, &state, data->cb_data); +} + +static void monitor_work_handler(struct k_work *work) +{ + struct k_work_delayable *dwork = k_work_delayable_from_work(work); + struct phy_tja1103_data *const data = + CONTAINER_OF(dwork, struct phy_tja1103_data, monitor_work); + const struct device *dev = data->dev; + int rc; + + k_sem_take(&data->sem, K_FOREVER); + + rc = update_link_state(dev); + k_sem_give(&data->sem); - return 0; + /* If link state has changed and a callback is set, invoke callback */ + if (rc == 0) { + invoke_link_cb(dev); + } + + /* Submit delayed work */ + k_work_reschedule(&data->monitor_work, K_MSEC(CONFIG_PHY_MONITOR_PERIOD)); +} + +static void phy_tja1103_irq_offload_thread(void *p1, void *p2, void *p3) +{ + ARG_UNUSED(p2); + ARG_UNUSED(p3); + + const struct device *dev = p1; + struct phy_tja1103_data *const data = dev->data; + uint16_t irq; + + for (;;) { + /* await trigger from ISR */ + k_sem_take(&data->offload_sem, K_FOREVER); + + if (phy_tja1103_c45_read(dev, MDIO_MMD_VENDOR_SPECIFIC1, + TJA1103_PHY_FUNC_IRQ_MSTATUS, &irq) < 0) { + return; + } + + /* Handling Link related Functional IRQs */ + if (irq & (TJA1103_PHY_FUNC_IRQ_LINK_EVENT | TJA1103_PHY_FUNC_IRQ_LINK_AVAIL)) { + /* Send callback to MAC on link status changed */ + invoke_link_cb(dev); + + /* Ack the assered link related interrupts */ + phy_tja1103_c45_write(dev, MDIO_MMD_VENDOR_SPECIFIC1, + TJA1103_PHY_FUNC_IRQ_ACK, irq); + } + } +} + +static void phy_tja1103_handle_irq(const struct device *port, struct gpio_callback *cb, + uint32_t pins) +{ + ARG_UNUSED(pins); + ARG_UNUSED(port); + + struct phy_tja1103_data *const data = + CONTAINER_OF(cb, struct phy_tja1103_data, phy_tja1103_int_callback); + + /* Trigger BH before leaving the ISR */ + k_sem_give(&data->offload_sem); +} + +static void phy_tja1103_cfg_irq_poll(const struct device *dev) +{ + struct phy_tja1103_data *const data = dev->data; + const struct phy_tja1103_config *const cfg = dev->config; + int ret; + + if (cfg->gpio_interrupt.port != NULL) { + if (!gpio_is_ready_dt(&cfg->gpio_interrupt)) { + LOG_ERR("Interrupt GPIO device %s is not ready", + cfg->gpio_interrupt.port->name); + return; + } + + ret = gpio_pin_configure_dt(&cfg->gpio_interrupt, GPIO_INPUT); + if (ret < 0) { + LOG_ERR("Failed to configure interrupt GPIO, %d", ret); + return; + } + + gpio_init_callback(&(data->phy_tja1103_int_callback), phy_tja1103_handle_irq, + BIT(cfg->gpio_interrupt.pin)); + + /* Add callback structure to global syslist */ + ret = gpio_add_callback(cfg->gpio_interrupt.port, &data->phy_tja1103_int_callback); + if (ret < 0) { + LOG_ERR("Failed to add INT callback, %d", ret); + return; + } + + ret = phy_tja1103_c45_write( + dev, MDIO_MMD_VENDOR_SPECIFIC1, TJA1103_PHY_FUNC_IRQ_EN, + (TJA1103_PHY_FUNC_IRQ_LINK_EVENT_EN | TJA1103_PHY_FUNC_IRQ_LINK_AVAIL_EN)); + if (ret < 0) { + return; + } + + ret = gpio_pin_interrupt_configure_dt(&cfg->gpio_interrupt, GPIO_INT_EDGE_FALLING); + if (ret < 0) { + LOG_ERR("Failed to enable INT, %d", ret); + return; + } + + /* PHY initialized, IRQ configured, now initialize the BH handler */ + k_thread_create(&data->irq_thread, data->irq_thread_stack, + CONFIG_PHY_TJA1103_IRQ_THREAD_STACK_SIZE, + phy_tja1103_irq_offload_thread, (void *)dev, NULL, NULL, + CONFIG_PHY_TJA1103_IRQ_THREAD_PRIO, K_ESSENTIAL, K_NO_WAIT); + k_thread_name_set(&data->irq_thread, "phy_tja1103_irq_offload"); + + } else { + k_work_init_delayable(&data->monitor_work, monitor_work_handler); + + monitor_work_handler(&data->monitor_work.work); + } } static int phy_tja1103_cfg_link(const struct device *dev, enum phy_link_speed adv_speeds) @@ -166,12 +357,14 @@ static int phy_tja1103_init(const struct device *dev) uint16_t val; int ret; + data->dev = dev; + data->cb = NULL; data->state.is_up = false; data->state.speed = LINK_FULL_100BASE_T; ret = WAIT_FOR(!phy_tja1103_id(dev, &phy_id) && phy_id == TJA1103_ID, - TJA1103_AWAIT_RETRY_COUNT * TJA1103_AWAIT_DELAY_POLL_US, - k_sleep(K_USEC(TJA1103_AWAIT_DELAY_POLL_US))); + TJA1103_AWAIT_RETRY_COUNT * TJA1103_AWAIT_DELAY_POLL_US, + k_sleep(K_USEC(TJA1103_AWAIT_DELAY_POLL_US))); if (ret < 0) { LOG_ERR("Unable to obtain PHY ID for device 0x%x", cfg->phy_addr); return -ENODEV; @@ -208,19 +401,38 @@ static int phy_tja1103_init(const struct device *dev) return ret; } - /* Wait for settings to go in affect before checking link */ - k_sleep(K_MSEC(400)); + /* Check always accesible register for handling NMIs */ + ret = phy_tja1103_c45_read(dev, MDIO_MMD_VENDOR_SPECIFIC1, TJA1103_ALWAYS_ACCESSIBLE, &val); + if (ret < 0) { + return ret; + } + + /* Ack Fusa Pass Interrupt if Startup Self Test Passed successfully */ + if (val & TJA1103_ALWAYS_ACCESSIBLE_FUSA_PASS_IRQ) { + ret = phy_tja1103_c45_write(dev, MDIO_MMD_VENDOR_SPECIFIC1, + TJA1103_ALWAYS_ACCESSIBLE, + TJA1103_ALWAYS_ACCESSIBLE_FUSA_PASS_IRQ); + } + + /* Configure interrupt or poll mode for reporting link changes */ + phy_tja1103_cfg_irq_poll(dev); - phy_tja1103_get_link_state(dev, &data->state); return ret; } static int phy_tja1103_link_cb_set(const struct device *dev, phy_callback_t cb, void *user_data) { - ARG_UNUSED(dev); - ARG_UNUSED(cb); - ARG_UNUSED(user_data); - return -ENOTSUP; + struct phy_tja1103_data *const data = dev->data; + + data->cb = cb; + data->cb_data = user_data; + + /* Invoke the callback to notify the caller of the current + * link status. + */ + invoke_link_cb(dev); + + return 0; } static const struct ethphy_driver_api phy_tja1103_api = { @@ -235,10 +447,12 @@ static const struct ethphy_driver_api phy_tja1103_api = { static const struct phy_tja1103_config phy_tja1103_config_##n = { \ .phy_addr = DT_INST_REG_ADDR(n), \ .mdio = DEVICE_DT_GET(DT_INST_BUS(n)), \ + .gpio_interrupt = GPIO_DT_SPEC_INST_GET_OR(n, int_gpios, {0}), \ .master_slave = DT_INST_ENUM_IDX(n, master_slave), \ }; \ static struct phy_tja1103_data phy_tja1103_data_##n = { \ .sem = Z_SEM_INITIALIZER(phy_tja1103_data_##n.sem, 1, 1), \ + .offload_sem = Z_SEM_INITIALIZER(phy_tja1103_data_##n.offload_sem, 0, 1), \ }; \ DEVICE_DT_INST_DEFINE(n, &phy_tja1103_init, NULL, &phy_tja1103_data_##n, \ &phy_tja1103_config_##n, POST_KERNEL, CONFIG_PHY_INIT_PRIORITY, \ diff --git a/dts/bindings/ethernet/nxp,tja1103.yaml b/dts/bindings/ethernet/nxp,tja1103.yaml index a15c9be3aba..514dec3d376 100644 --- a/dts/bindings/ethernet/nxp,tja1103.yaml +++ b/dts/bindings/ethernet/nxp,tja1103.yaml @@ -12,6 +12,11 @@ properties: required: true description: PHY address + int-gpios: + type: phandle-array + description: + interrupt GPIO for PHY. Will be pulled high in its default state. + master-slave: type: string required: true From 2a260a84c8bcd1807541cea500af864c5c8d6b16 Mon Sep 17 00:00:00 2001 From: Anas Nashif Date: Tue, 30 Jan 2024 12:39:42 -0500 Subject: [PATCH 3337/3723] tests: CAN: change duplicate test name: get_capabilities In twister, we do not include the ZTEST testsuite as part of the identifier, something we should start doing especially for tests with multiple suites. The issue happens with same testcase name in different suites, where results get messed up. Work around this for now by making the testcase names unqiue until we have a better solution twister. Signed-off-by: Anas Nashif --- tests/drivers/can/api/src/canfd.c | 2 +- tests/drivers/can/api/src/classic.c | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/tests/drivers/can/api/src/canfd.c b/tests/drivers/can/api/src/canfd.c index be0f235cc7b..4a7f3704e19 100644 --- a/tests/drivers/can/api/src/canfd.c +++ b/tests/drivers/can/api/src/canfd.c @@ -227,7 +227,7 @@ static void send_receive(const struct can_filter *filter1, /** * @brief Test getting the CAN controller capabilities. */ -ZTEST(canfd, test_get_capabilities) +ZTEST(canfd, test_canfd_get_capabilities) { can_mode_t cap; int err; diff --git a/tests/drivers/can/api/src/classic.c b/tests/drivers/can/api/src/classic.c index ccb93753673..4a871ebd9aa 100644 --- a/tests/drivers/can/api/src/classic.c +++ b/tests/drivers/can/api/src/classic.c @@ -443,7 +443,7 @@ ZTEST_USER(can_classic, test_get_core_clock) /** * @brief Test getting the CAN controller capabilities. */ -ZTEST_USER(can_classic, test_get_capabilities) +ZTEST_USER(can_classic, test_classic_get_capabilities) { can_mode_t cap; int err; From b64af4008f144b2fd82ad1a7e2d68511b1c3ee1c Mon Sep 17 00:00:00 2001 From: Anas Nashif Date: Tue, 30 Jan 2024 11:12:31 -0500 Subject: [PATCH 3338/3723] twister: deal with predicates and skipped tests Using ztest predicate feature, testcases are skipped, however, the skip is only reported as part of the summary and not through normal execution. Until now such tests were reported as blocked or had a null status in the twister json output. This changes will look into summary results and use them to confirm parsed results and add any missing results that either were not reported or not captured through the serial console. The issue can be observed with the drivers.can.api test for example on the frdm_k64f board. Signed-off-by: Anas Nashif --- scripts/pylib/twister/twisterlib/harness.py | 20 ++++++++++++++++++++ 1 file changed, 20 insertions(+) diff --git a/scripts/pylib/twister/twisterlib/harness.py b/scripts/pylib/twister/twisterlib/harness.py index bfdcb107ec8..2acec462fa6 100644 --- a/scripts/pylib/twister/twisterlib/harness.py +++ b/scripts/pylib/twister/twisterlib/harness.py @@ -624,6 +624,12 @@ def handle(self, line): self._match = True result_match = result_re.match(line) + # some testcases are skipped based on predicates and do not show up + # during test execution, however they are listed in the summary. Parse + # the summary for status and use that status instead. + + summary_re = re.compile(r"- (PASS|FAIL|SKIP) - \[([^\.]*).(test_)?(\S*)\] duration = (\d*[.,]?\d*) seconds") + summary_match = summary_re.match(line) if result_match: matched_status = result_match.group(1) @@ -638,6 +644,20 @@ def handle(self, line): self.testcase_output = "" self._match = False self.ztest = True + elif summary_match: + matched_status = summary_match.group(1) + self.detected_suite_names.append(summary_match.group(2)) + name = "{}.{}".format(self.id, summary_match.group(4)) + tc = self.instance.get_case_or_create(name) + tc.status = self.ztest_to_status[matched_status] + if tc.status == "skipped": + tc.reason = "ztest skip" + tc.duration = float(summary_match.group(5)) + if tc.status == "failed": + tc.output = self.testcase_output + self.testcase_output = "" + self._match = False + self.ztest = True self.process_test(line) From 5c849f8e2eb6a502e99803dfbdeda7d6386261fc Mon Sep 17 00:00:00 2001 From: Jordan Yates Date: Fri, 24 Nov 2023 16:01:53 +1000 Subject: [PATCH 3339/3723] modules: cmsis-dsp: re-add compilation control Re-add finer grained compilation control that was lost in the CMSIS split (#56957). CMSIS DSP is several hundred files and has a measurable effect on compile times. Only compiling features that are required improves this. Signed-off-by: Jordan Yates --- modules/cmsis-dsp/CMakeLists.txt | 1530 +++++++++++++++--------------- modules/cmsis-dsp/Kconfig | 244 +++++ 2 files changed, 1022 insertions(+), 752 deletions(-) diff --git a/modules/cmsis-dsp/CMakeLists.txt b/modules/cmsis-dsp/CMakeLists.txt index 9afaa32b89d..b4f2b8edd00 100644 --- a/modules/cmsis-dsp/CMakeLists.txt +++ b/modules/cmsis-dsp/CMakeLists.txt @@ -52,112 +52,115 @@ if(CONFIG_CMSIS_DSP) zephyr_compile_definitions_ifndef(CONFIG_ARM __GNUC_PYTHON__) # BasicMathFunctions + if(CONFIG_CMSIS_DSP_BASICMATH) + set(SRCF64 ${CMSIS_DSP_DIR}/Source/BasicMathFunctions/arm_abs_f64.c + ${CMSIS_DSP_DIR}/Source/BasicMathFunctions/arm_add_f64.c + ${CMSIS_DSP_DIR}/Source/BasicMathFunctions/arm_dot_prod_f64.c + ${CMSIS_DSP_DIR}/Source/BasicMathFunctions/arm_mult_f64.c + ${CMSIS_DSP_DIR}/Source/BasicMathFunctions/arm_negate_f64.c + ${CMSIS_DSP_DIR}/Source/BasicMathFunctions/arm_offset_f64.c + ${CMSIS_DSP_DIR}/Source/BasicMathFunctions/arm_scale_f64.c + ${CMSIS_DSP_DIR}/Source/BasicMathFunctions/arm_sub_f64.c + ) - set(SRCF64 ${CMSIS_DSP_DIR}/Source/BasicMathFunctions/arm_abs_f64.c - ${CMSIS_DSP_DIR}/Source/BasicMathFunctions/arm_add_f64.c - ${CMSIS_DSP_DIR}/Source/BasicMathFunctions/arm_dot_prod_f64.c - ${CMSIS_DSP_DIR}/Source/BasicMathFunctions/arm_mult_f64.c - ${CMSIS_DSP_DIR}/Source/BasicMathFunctions/arm_negate_f64.c - ${CMSIS_DSP_DIR}/Source/BasicMathFunctions/arm_offset_f64.c - ${CMSIS_DSP_DIR}/Source/BasicMathFunctions/arm_scale_f64.c - ${CMSIS_DSP_DIR}/Source/BasicMathFunctions/arm_sub_f64.c - ) - - set(SRCF32 ${CMSIS_DSP_DIR}/Source/BasicMathFunctions/arm_abs_f32.c - ${CMSIS_DSP_DIR}/Source/BasicMathFunctions/arm_add_f32.c - ${CMSIS_DSP_DIR}/Source/BasicMathFunctions/arm_clip_f32.c - ${CMSIS_DSP_DIR}/Source/BasicMathFunctions/arm_dot_prod_f32.c - ${CMSIS_DSP_DIR}/Source/BasicMathFunctions/arm_mult_f32.c - ${CMSIS_DSP_DIR}/Source/BasicMathFunctions/arm_negate_f32.c - ${CMSIS_DSP_DIR}/Source/BasicMathFunctions/arm_offset_f32.c - ${CMSIS_DSP_DIR}/Source/BasicMathFunctions/arm_scale_f32.c - ${CMSIS_DSP_DIR}/Source/BasicMathFunctions/arm_sub_f32.c - ) + set(SRCF32 ${CMSIS_DSP_DIR}/Source/BasicMathFunctions/arm_abs_f32.c + ${CMSIS_DSP_DIR}/Source/BasicMathFunctions/arm_add_f32.c + ${CMSIS_DSP_DIR}/Source/BasicMathFunctions/arm_clip_f32.c + ${CMSIS_DSP_DIR}/Source/BasicMathFunctions/arm_dot_prod_f32.c + ${CMSIS_DSP_DIR}/Source/BasicMathFunctions/arm_mult_f32.c + ${CMSIS_DSP_DIR}/Source/BasicMathFunctions/arm_negate_f32.c + ${CMSIS_DSP_DIR}/Source/BasicMathFunctions/arm_offset_f32.c + ${CMSIS_DSP_DIR}/Source/BasicMathFunctions/arm_scale_f32.c + ${CMSIS_DSP_DIR}/Source/BasicMathFunctions/arm_sub_f32.c + ) - set(SRCF16 ${CMSIS_DSP_DIR}/Source/BasicMathFunctions/arm_abs_f16.c - ${CMSIS_DSP_DIR}/Source/BasicMathFunctions/arm_add_f16.c - ${CMSIS_DSP_DIR}/Source/BasicMathFunctions/arm_clip_f16.c - ${CMSIS_DSP_DIR}/Source/BasicMathFunctions/arm_dot_prod_f16.c - ${CMSIS_DSP_DIR}/Source/BasicMathFunctions/arm_mult_f16.c - ${CMSIS_DSP_DIR}/Source/BasicMathFunctions/arm_negate_f16.c - ${CMSIS_DSP_DIR}/Source/BasicMathFunctions/arm_offset_f16.c - ${CMSIS_DSP_DIR}/Source/BasicMathFunctions/arm_scale_f16.c - ${CMSIS_DSP_DIR}/Source/BasicMathFunctions/arm_sub_f16.c - ) + set(SRCF16 ${CMSIS_DSP_DIR}/Source/BasicMathFunctions/arm_abs_f16.c + ${CMSIS_DSP_DIR}/Source/BasicMathFunctions/arm_add_f16.c + ${CMSIS_DSP_DIR}/Source/BasicMathFunctions/arm_clip_f16.c + ${CMSIS_DSP_DIR}/Source/BasicMathFunctions/arm_dot_prod_f16.c + ${CMSIS_DSP_DIR}/Source/BasicMathFunctions/arm_mult_f16.c + ${CMSIS_DSP_DIR}/Source/BasicMathFunctions/arm_negate_f16.c + ${CMSIS_DSP_DIR}/Source/BasicMathFunctions/arm_offset_f16.c + ${CMSIS_DSP_DIR}/Source/BasicMathFunctions/arm_scale_f16.c + ${CMSIS_DSP_DIR}/Source/BasicMathFunctions/arm_sub_f16.c + ) - set(SRCQ31 ${CMSIS_DSP_DIR}/Source/BasicMathFunctions/arm_abs_q31.c - ${CMSIS_DSP_DIR}/Source/BasicMathFunctions/arm_add_q31.c - ${CMSIS_DSP_DIR}/Source/BasicMathFunctions/arm_clip_q31.c - ${CMSIS_DSP_DIR}/Source/BasicMathFunctions/arm_dot_prod_q31.c - ${CMSIS_DSP_DIR}/Source/BasicMathFunctions/arm_mult_q31.c - ${CMSIS_DSP_DIR}/Source/BasicMathFunctions/arm_negate_q31.c - ${CMSIS_DSP_DIR}/Source/BasicMathFunctions/arm_offset_q31.c - ${CMSIS_DSP_DIR}/Source/BasicMathFunctions/arm_scale_q31.c - ${CMSIS_DSP_DIR}/Source/BasicMathFunctions/arm_shift_q31.c - ${CMSIS_DSP_DIR}/Source/BasicMathFunctions/arm_sub_q31.c - ) + set(SRCQ31 ${CMSIS_DSP_DIR}/Source/BasicMathFunctions/arm_abs_q31.c + ${CMSIS_DSP_DIR}/Source/BasicMathFunctions/arm_add_q31.c + ${CMSIS_DSP_DIR}/Source/BasicMathFunctions/arm_clip_q31.c + ${CMSIS_DSP_DIR}/Source/BasicMathFunctions/arm_dot_prod_q31.c + ${CMSIS_DSP_DIR}/Source/BasicMathFunctions/arm_mult_q31.c + ${CMSIS_DSP_DIR}/Source/BasicMathFunctions/arm_negate_q31.c + ${CMSIS_DSP_DIR}/Source/BasicMathFunctions/arm_offset_q31.c + ${CMSIS_DSP_DIR}/Source/BasicMathFunctions/arm_scale_q31.c + ${CMSIS_DSP_DIR}/Source/BasicMathFunctions/arm_shift_q31.c + ${CMSIS_DSP_DIR}/Source/BasicMathFunctions/arm_sub_q31.c + ) - set(SRCQ15 ${CMSIS_DSP_DIR}/Source/BasicMathFunctions/arm_abs_q15.c - ${CMSIS_DSP_DIR}/Source/BasicMathFunctions/arm_add_q15.c - ${CMSIS_DSP_DIR}/Source/BasicMathFunctions/arm_clip_q15.c - ${CMSIS_DSP_DIR}/Source/BasicMathFunctions/arm_dot_prod_q15.c - ${CMSIS_DSP_DIR}/Source/BasicMathFunctions/arm_mult_q15.c - ${CMSIS_DSP_DIR}/Source/BasicMathFunctions/arm_negate_q15.c - ${CMSIS_DSP_DIR}/Source/BasicMathFunctions/arm_offset_q15.c - ${CMSIS_DSP_DIR}/Source/BasicMathFunctions/arm_scale_q15.c - ${CMSIS_DSP_DIR}/Source/BasicMathFunctions/arm_shift_q15.c - ${CMSIS_DSP_DIR}/Source/BasicMathFunctions/arm_sub_q15.c - ) + set(SRCQ15 ${CMSIS_DSP_DIR}/Source/BasicMathFunctions/arm_abs_q15.c + ${CMSIS_DSP_DIR}/Source/BasicMathFunctions/arm_add_q15.c + ${CMSIS_DSP_DIR}/Source/BasicMathFunctions/arm_clip_q15.c + ${CMSIS_DSP_DIR}/Source/BasicMathFunctions/arm_dot_prod_q15.c + ${CMSIS_DSP_DIR}/Source/BasicMathFunctions/arm_mult_q15.c + ${CMSIS_DSP_DIR}/Source/BasicMathFunctions/arm_negate_q15.c + ${CMSIS_DSP_DIR}/Source/BasicMathFunctions/arm_offset_q15.c + ${CMSIS_DSP_DIR}/Source/BasicMathFunctions/arm_scale_q15.c + ${CMSIS_DSP_DIR}/Source/BasicMathFunctions/arm_shift_q15.c + ${CMSIS_DSP_DIR}/Source/BasicMathFunctions/arm_sub_q15.c + ) - set(SRCQ7 ${CMSIS_DSP_DIR}/Source/BasicMathFunctions/arm_abs_q7.c - ${CMSIS_DSP_DIR}/Source/BasicMathFunctions/arm_add_q7.c - ${CMSIS_DSP_DIR}/Source/BasicMathFunctions/arm_clip_q7.c - ${CMSIS_DSP_DIR}/Source/BasicMathFunctions/arm_dot_prod_q7.c - ${CMSIS_DSP_DIR}/Source/BasicMathFunctions/arm_mult_q7.c - ${CMSIS_DSP_DIR}/Source/BasicMathFunctions/arm_negate_q7.c - ${CMSIS_DSP_DIR}/Source/BasicMathFunctions/arm_offset_q7.c - ${CMSIS_DSP_DIR}/Source/BasicMathFunctions/arm_scale_q7.c - ${CMSIS_DSP_DIR}/Source/BasicMathFunctions/arm_shift_q7.c - ${CMSIS_DSP_DIR}/Source/BasicMathFunctions/arm_sub_q7.c - ) + set(SRCQ7 ${CMSIS_DSP_DIR}/Source/BasicMathFunctions/arm_abs_q7.c + ${CMSIS_DSP_DIR}/Source/BasicMathFunctions/arm_add_q7.c + ${CMSIS_DSP_DIR}/Source/BasicMathFunctions/arm_clip_q7.c + ${CMSIS_DSP_DIR}/Source/BasicMathFunctions/arm_dot_prod_q7.c + ${CMSIS_DSP_DIR}/Source/BasicMathFunctions/arm_mult_q7.c + ${CMSIS_DSP_DIR}/Source/BasicMathFunctions/arm_negate_q7.c + ${CMSIS_DSP_DIR}/Source/BasicMathFunctions/arm_offset_q7.c + ${CMSIS_DSP_DIR}/Source/BasicMathFunctions/arm_scale_q7.c + ${CMSIS_DSP_DIR}/Source/BasicMathFunctions/arm_shift_q7.c + ${CMSIS_DSP_DIR}/Source/BasicMathFunctions/arm_sub_q7.c + ) - set(SRCU32 ${CMSIS_DSP_DIR}/Source/BasicMathFunctions/arm_and_u32.c - ${CMSIS_DSP_DIR}/Source/BasicMathFunctions/arm_not_u32.c - ${CMSIS_DSP_DIR}/Source/BasicMathFunctions/arm_or_u32.c - ${CMSIS_DSP_DIR}/Source/BasicMathFunctions/arm_xor_u32.c - ) + set(SRCU32 ${CMSIS_DSP_DIR}/Source/BasicMathFunctions/arm_and_u32.c + ${CMSIS_DSP_DIR}/Source/BasicMathFunctions/arm_not_u32.c + ${CMSIS_DSP_DIR}/Source/BasicMathFunctions/arm_or_u32.c + ${CMSIS_DSP_DIR}/Source/BasicMathFunctions/arm_xor_u32.c + ) - set(SRCU16 ${CMSIS_DSP_DIR}/Source/BasicMathFunctions/arm_and_u16.c - ${CMSIS_DSP_DIR}/Source/BasicMathFunctions/arm_not_u16.c - ${CMSIS_DSP_DIR}/Source/BasicMathFunctions/arm_or_u16.c - ${CMSIS_DSP_DIR}/Source/BasicMathFunctions/arm_xor_u16.c - ) + set(SRCU16 ${CMSIS_DSP_DIR}/Source/BasicMathFunctions/arm_and_u16.c + ${CMSIS_DSP_DIR}/Source/BasicMathFunctions/arm_not_u16.c + ${CMSIS_DSP_DIR}/Source/BasicMathFunctions/arm_or_u16.c + ${CMSIS_DSP_DIR}/Source/BasicMathFunctions/arm_xor_u16.c + ) - set(SRCU8 ${CMSIS_DSP_DIR}/Source/BasicMathFunctions/arm_and_u8.c - ${CMSIS_DSP_DIR}/Source/BasicMathFunctions/arm_or_u8.c - ${CMSIS_DSP_DIR}/Source/BasicMathFunctions/arm_not_u8.c - ${CMSIS_DSP_DIR}/Source/BasicMathFunctions/arm_xor_u8.c) + set(SRCU8 ${CMSIS_DSP_DIR}/Source/BasicMathFunctions/arm_and_u8.c + ${CMSIS_DSP_DIR}/Source/BasicMathFunctions/arm_or_u8.c + ${CMSIS_DSP_DIR}/Source/BasicMathFunctions/arm_not_u8.c + ${CMSIS_DSP_DIR}/Source/BasicMathFunctions/arm_xor_u8.c) - zephyr_library_sources(${SRCF64}) - zephyr_library_sources(${SRCF32}) + zephyr_library_sources(${SRCF64}) + zephyr_library_sources(${SRCF32}) - if ((NOT ARMAC5) AND (NOT DISABLEFLOAT16)) - zephyr_library_sources(${SRCF16}) - endif() + if ((NOT ARMAC5) AND (NOT DISABLEFLOAT16)) + zephyr_library_sources(${SRCF16}) + endif() - zephyr_library_sources(${SRCQ31}) - zephyr_library_sources(${SRCQ15}) - zephyr_library_sources(${SRCQ7}) + zephyr_library_sources(${SRCQ31}) + zephyr_library_sources(${SRCQ15}) + zephyr_library_sources(${SRCQ7}) - zephyr_library_sources(${SRCU32}) - zephyr_library_sources(${SRCU16}) - zephyr_library_sources(${SRCU8}) + zephyr_library_sources(${SRCU32}) + zephyr_library_sources(${SRCU16}) + zephyr_library_sources(${SRCU8}) + endif() # BayesFunctions - zephyr_library_sources(${CMSIS_DSP_DIR}/Source/BayesFunctions/arm_gaussian_naive_bayes_predict_f32.c) + if (CONFIG_CMSIS_DSP_BAYES) + zephyr_library_sources(${CMSIS_DSP_DIR}/Source/BayesFunctions/arm_gaussian_naive_bayes_predict_f32.c) - if ((NOT ARMAC5) AND (NOT DISABLEFLOAT16)) - zephyr_library_sources(${CMSIS_DSP_DIR}/Source/BayesFunctions/arm_gaussian_naive_bayes_predict_f16.c) + if ((NOT ARMAC5) AND (NOT DISABLEFLOAT16)) + zephyr_library_sources(${CMSIS_DSP_DIR}/Source/BayesFunctions/arm_gaussian_naive_bayes_predict_f16.c) + endif() endif() # Common Tables @@ -193,739 +196,762 @@ if(CONFIG_CMSIS_DSP) # MVE code is using a table for computing the fast sqrt arm_cmplx_mag_q31 # There is the possibility of not compiling this function and not including # the table. - zephyr_library_sources(${CMSIS_DSP_DIR}/Source/ComplexMathFunctions/arm_cmplx_mag_q31.c) - - zephyr_library_sources(${CMSIS_DSP_DIR}/Source/ComplexMathFunctions/arm_cmplx_mag_q15.c) - - zephyr_library_sources(${CMSIS_DSP_DIR}/Source/ComplexMathFunctions/arm_cmplx_mag_fast_q15.c) - - zephyr_library_sources(${CMSIS_DSP_DIR}/Source/ComplexMathFunctions/arm_cmplx_conj_f32.c) - zephyr_library_sources(${CMSIS_DSP_DIR}/Source/ComplexMathFunctions/arm_cmplx_conj_q15.c) - zephyr_library_sources(${CMSIS_DSP_DIR}/Source/ComplexMathFunctions/arm_cmplx_conj_q31.c) - zephyr_library_sources(${CMSIS_DSP_DIR}/Source/ComplexMathFunctions/arm_cmplx_dot_prod_f32.c) - zephyr_library_sources(${CMSIS_DSP_DIR}/Source/ComplexMathFunctions/arm_cmplx_dot_prod_q15.c) - zephyr_library_sources(${CMSIS_DSP_DIR}/Source/ComplexMathFunctions/arm_cmplx_dot_prod_q31.c) - zephyr_library_sources(${CMSIS_DSP_DIR}/Source/ComplexMathFunctions/arm_cmplx_mag_f32.c) - zephyr_library_sources(${CMSIS_DSP_DIR}/Source/ComplexMathFunctions/arm_cmplx_mag_f64.c) - zephyr_library_sources(${CMSIS_DSP_DIR}/Source/ComplexMathFunctions/arm_cmplx_mag_squared_f32.c) - zephyr_library_sources(${CMSIS_DSP_DIR}/Source/ComplexMathFunctions/arm_cmplx_mag_squared_f64.c) - zephyr_library_sources(${CMSIS_DSP_DIR}/Source/ComplexMathFunctions/arm_cmplx_mag_squared_q15.c) - zephyr_library_sources(${CMSIS_DSP_DIR}/Source/ComplexMathFunctions/arm_cmplx_mag_squared_q31.c) - zephyr_library_sources(${CMSIS_DSP_DIR}/Source/ComplexMathFunctions/arm_cmplx_mult_cmplx_f32.c) - zephyr_library_sources(${CMSIS_DSP_DIR}/Source/ComplexMathFunctions/arm_cmplx_mult_cmplx_f64.c) - zephyr_library_sources(${CMSIS_DSP_DIR}/Source/ComplexMathFunctions/arm_cmplx_mult_cmplx_q15.c) - zephyr_library_sources(${CMSIS_DSP_DIR}/Source/ComplexMathFunctions/arm_cmplx_mult_cmplx_q31.c) - zephyr_library_sources(${CMSIS_DSP_DIR}/Source/ComplexMathFunctions/arm_cmplx_mult_real_f32.c) - zephyr_library_sources(${CMSIS_DSP_DIR}/Source/ComplexMathFunctions/arm_cmplx_mult_real_q15.c) - zephyr_library_sources(${CMSIS_DSP_DIR}/Source/ComplexMathFunctions/arm_cmplx_mult_real_q31.c) - - if ((NOT ARMAC5) AND (NOT DISABLEFLOAT16)) - zephyr_library_sources(${CMSIS_DSP_DIR}/Source/ComplexMathFunctions/arm_cmplx_conj_f16.c) - zephyr_library_sources(${CMSIS_DSP_DIR}/Source/ComplexMathFunctions/arm_cmplx_dot_prod_f16.c) - zephyr_library_sources(${CMSIS_DSP_DIR}/Source/ComplexMathFunctions/arm_cmplx_mag_f16.c) - zephyr_library_sources(${CMSIS_DSP_DIR}/Source/ComplexMathFunctions/arm_cmplx_mag_squared_f16.c) - zephyr_library_sources(${CMSIS_DSP_DIR}/Source/ComplexMathFunctions/arm_cmplx_mult_cmplx_f16.c) - zephyr_library_sources(${CMSIS_DSP_DIR}/Source/ComplexMathFunctions/arm_cmplx_mult_real_f16.c) + if (CONFIG_CMSIS_DSP_COMPLEXMATH) + zephyr_library_sources(${CMSIS_DSP_DIR}/Source/ComplexMathFunctions/arm_cmplx_mag_q31.c) + + zephyr_library_sources(${CMSIS_DSP_DIR}/Source/ComplexMathFunctions/arm_cmplx_mag_q15.c) + + zephyr_library_sources(${CMSIS_DSP_DIR}/Source/ComplexMathFunctions/arm_cmplx_mag_fast_q15.c) + + zephyr_library_sources(${CMSIS_DSP_DIR}/Source/ComplexMathFunctions/arm_cmplx_conj_f32.c) + zephyr_library_sources(${CMSIS_DSP_DIR}/Source/ComplexMathFunctions/arm_cmplx_conj_q15.c) + zephyr_library_sources(${CMSIS_DSP_DIR}/Source/ComplexMathFunctions/arm_cmplx_conj_q31.c) + zephyr_library_sources(${CMSIS_DSP_DIR}/Source/ComplexMathFunctions/arm_cmplx_dot_prod_f32.c) + zephyr_library_sources(${CMSIS_DSP_DIR}/Source/ComplexMathFunctions/arm_cmplx_dot_prod_q15.c) + zephyr_library_sources(${CMSIS_DSP_DIR}/Source/ComplexMathFunctions/arm_cmplx_dot_prod_q31.c) + zephyr_library_sources(${CMSIS_DSP_DIR}/Source/ComplexMathFunctions/arm_cmplx_mag_f32.c) + zephyr_library_sources(${CMSIS_DSP_DIR}/Source/ComplexMathFunctions/arm_cmplx_mag_f64.c) + zephyr_library_sources(${CMSIS_DSP_DIR}/Source/ComplexMathFunctions/arm_cmplx_mag_squared_f32.c) + zephyr_library_sources(${CMSIS_DSP_DIR}/Source/ComplexMathFunctions/arm_cmplx_mag_squared_f64.c) + zephyr_library_sources(${CMSIS_DSP_DIR}/Source/ComplexMathFunctions/arm_cmplx_mag_squared_q15.c) + zephyr_library_sources(${CMSIS_DSP_DIR}/Source/ComplexMathFunctions/arm_cmplx_mag_squared_q31.c) + zephyr_library_sources(${CMSIS_DSP_DIR}/Source/ComplexMathFunctions/arm_cmplx_mult_cmplx_f32.c) + zephyr_library_sources(${CMSIS_DSP_DIR}/Source/ComplexMathFunctions/arm_cmplx_mult_cmplx_f64.c) + zephyr_library_sources(${CMSIS_DSP_DIR}/Source/ComplexMathFunctions/arm_cmplx_mult_cmplx_q15.c) + zephyr_library_sources(${CMSIS_DSP_DIR}/Source/ComplexMathFunctions/arm_cmplx_mult_cmplx_q31.c) + zephyr_library_sources(${CMSIS_DSP_DIR}/Source/ComplexMathFunctions/arm_cmplx_mult_real_f32.c) + zephyr_library_sources(${CMSIS_DSP_DIR}/Source/ComplexMathFunctions/arm_cmplx_mult_real_q15.c) + zephyr_library_sources(${CMSIS_DSP_DIR}/Source/ComplexMathFunctions/arm_cmplx_mult_real_q31.c) + + if ((NOT ARMAC5) AND (NOT DISABLEFLOAT16)) + zephyr_library_sources(${CMSIS_DSP_DIR}/Source/ComplexMathFunctions/arm_cmplx_conj_f16.c) + zephyr_library_sources(${CMSIS_DSP_DIR}/Source/ComplexMathFunctions/arm_cmplx_dot_prod_f16.c) + zephyr_library_sources(${CMSIS_DSP_DIR}/Source/ComplexMathFunctions/arm_cmplx_mag_f16.c) + zephyr_library_sources(${CMSIS_DSP_DIR}/Source/ComplexMathFunctions/arm_cmplx_mag_squared_f16.c) + zephyr_library_sources(${CMSIS_DSP_DIR}/Source/ComplexMathFunctions/arm_cmplx_mult_cmplx_f16.c) + zephyr_library_sources(${CMSIS_DSP_DIR}/Source/ComplexMathFunctions/arm_cmplx_mult_real_f16.c) + endif() endif() # Controller Functions - zephyr_library_sources(${CMSIS_DSP_DIR}/Source/ControllerFunctions/arm_pid_init_f32.c) - zephyr_library_sources(${CMSIS_DSP_DIR}/Source/ControllerFunctions/arm_pid_init_q15.c) - zephyr_library_sources(${CMSIS_DSP_DIR}/Source/ControllerFunctions/arm_pid_init_q31.c) - zephyr_library_sources(${CMSIS_DSP_DIR}/Source/ControllerFunctions/arm_pid_reset_f32.c) - zephyr_library_sources(${CMSIS_DSP_DIR}/Source/ControllerFunctions/arm_pid_reset_q15.c) - zephyr_library_sources(${CMSIS_DSP_DIR}/Source/ControllerFunctions/arm_pid_reset_q31.c) + if (CONFIG_CMSIS_DSP_CONTROLLER) + zephyr_library_sources(${CMSIS_DSP_DIR}/Source/ControllerFunctions/arm_pid_init_f32.c) + zephyr_library_sources(${CMSIS_DSP_DIR}/Source/ControllerFunctions/arm_pid_init_q15.c) + zephyr_library_sources(${CMSIS_DSP_DIR}/Source/ControllerFunctions/arm_pid_init_q31.c) + zephyr_library_sources(${CMSIS_DSP_DIR}/Source/ControllerFunctions/arm_pid_reset_f32.c) + zephyr_library_sources(${CMSIS_DSP_DIR}/Source/ControllerFunctions/arm_pid_reset_q15.c) + zephyr_library_sources(${CMSIS_DSP_DIR}/Source/ControllerFunctions/arm_pid_reset_q31.c) - zephyr_library_sources(${CMSIS_DSP_DIR}/Source/ControllerFunctions/arm_sin_cos_f32.c) + zephyr_library_sources(${CMSIS_DSP_DIR}/Source/ControllerFunctions/arm_sin_cos_f32.c) - zephyr_library_sources(${CMSIS_DSP_DIR}/Source/ControllerFunctions/arm_sin_cos_q31.c) + zephyr_library_sources(${CMSIS_DSP_DIR}/Source/ControllerFunctions/arm_sin_cos_q31.c) + endif() # Distance Functions - zephyr_library_sources(${CMSIS_DSP_DIR}/Source/DistanceFunctions/arm_boolean_distance.c) - zephyr_library_sources(${CMSIS_DSP_DIR}/Source/DistanceFunctions/arm_braycurtis_distance_f32.c) - zephyr_library_sources(${CMSIS_DSP_DIR}/Source/DistanceFunctions/arm_canberra_distance_f32.c) - zephyr_library_sources(${CMSIS_DSP_DIR}/Source/DistanceFunctions/arm_chebyshev_distance_f32.c) - zephyr_library_sources(${CMSIS_DSP_DIR}/Source/DistanceFunctions/arm_chebyshev_distance_f64.c) - zephyr_library_sources(${CMSIS_DSP_DIR}/Source/DistanceFunctions/arm_cityblock_distance_f32.c) - zephyr_library_sources(${CMSIS_DSP_DIR}/Source/DistanceFunctions/arm_cityblock_distance_f64.c) - zephyr_library_sources(${CMSIS_DSP_DIR}/Source/DistanceFunctions/arm_correlation_distance_f32.c) - zephyr_library_sources(${CMSIS_DSP_DIR}/Source/DistanceFunctions/arm_cosine_distance_f32.c) - zephyr_library_sources(${CMSIS_DSP_DIR}/Source/DistanceFunctions/arm_cosine_distance_f64.c) - zephyr_library_sources(${CMSIS_DSP_DIR}/Source/DistanceFunctions/arm_dice_distance.c) - zephyr_library_sources(${CMSIS_DSP_DIR}/Source/DistanceFunctions/arm_euclidean_distance_f32.c) - zephyr_library_sources(${CMSIS_DSP_DIR}/Source/DistanceFunctions/arm_euclidean_distance_f64.c) - zephyr_library_sources(${CMSIS_DSP_DIR}/Source/DistanceFunctions/arm_hamming_distance.c) - zephyr_library_sources(${CMSIS_DSP_DIR}/Source/DistanceFunctions/arm_jaccard_distance.c) - zephyr_library_sources(${CMSIS_DSP_DIR}/Source/DistanceFunctions/arm_jensenshannon_distance_f32.c) - zephyr_library_sources(${CMSIS_DSP_DIR}/Source/DistanceFunctions/arm_kulsinski_distance.c) - zephyr_library_sources(${CMSIS_DSP_DIR}/Source/DistanceFunctions/arm_minkowski_distance_f32.c) - zephyr_library_sources(${CMSIS_DSP_DIR}/Source/DistanceFunctions/arm_rogerstanimoto_distance.c) - zephyr_library_sources(${CMSIS_DSP_DIR}/Source/DistanceFunctions/arm_russellrao_distance.c) - zephyr_library_sources(${CMSIS_DSP_DIR}/Source/DistanceFunctions/arm_sokalmichener_distance.c) - zephyr_library_sources(${CMSIS_DSP_DIR}/Source/DistanceFunctions/arm_sokalsneath_distance.c) - zephyr_library_sources(${CMSIS_DSP_DIR}/Source/DistanceFunctions/arm_yule_distance.c) - zephyr_library_sources(${CMSIS_DSP_DIR}/Source/DistanceFunctions/arm_dtw_distance_f32.c) - zephyr_library_sources(${CMSIS_DSP_DIR}/Source/DistanceFunctions/arm_dtw_path_f32.c) - zephyr_library_sources(${CMSIS_DSP_DIR}/Source/DistanceFunctions/arm_dtw_init_window_q7.c) - - - zephyr_library_include_directories("${CMSIS_DSP_DIR}/Source/DistanceFunctions") - - if ((NOT ARMAC5) AND (NOT DISABLEFLOAT16)) - zephyr_library_sources(${CMSIS_DSP_DIR}/Source/DistanceFunctions/arm_braycurtis_distance_f16.c) - zephyr_library_sources(${CMSIS_DSP_DIR}/Source/DistanceFunctions/arm_canberra_distance_f16.c) - zephyr_library_sources(${CMSIS_DSP_DIR}/Source/DistanceFunctions/arm_chebyshev_distance_f16.c) - zephyr_library_sources(${CMSIS_DSP_DIR}/Source/DistanceFunctions/arm_cityblock_distance_f16.c) - zephyr_library_sources(${CMSIS_DSP_DIR}/Source/DistanceFunctions/arm_correlation_distance_f16.c) - zephyr_library_sources(${CMSIS_DSP_DIR}/Source/DistanceFunctions/arm_cosine_distance_f16.c) - zephyr_library_sources(${CMSIS_DSP_DIR}/Source/DistanceFunctions/arm_euclidean_distance_f16.c) - zephyr_library_sources(${CMSIS_DSP_DIR}/Source/DistanceFunctions/arm_jensenshannon_distance_f16.c) - zephyr_library_sources(${CMSIS_DSP_DIR}/Source/DistanceFunctions/arm_minkowski_distance_f16.c) + if (CONFIG_CMSIS_DSP_DISTANCE) + zephyr_library_sources(${CMSIS_DSP_DIR}/Source/DistanceFunctions/arm_boolean_distance.c) + zephyr_library_sources(${CMSIS_DSP_DIR}/Source/DistanceFunctions/arm_braycurtis_distance_f32.c) + zephyr_library_sources(${CMSIS_DSP_DIR}/Source/DistanceFunctions/arm_canberra_distance_f32.c) + zephyr_library_sources(${CMSIS_DSP_DIR}/Source/DistanceFunctions/arm_chebyshev_distance_f32.c) + zephyr_library_sources(${CMSIS_DSP_DIR}/Source/DistanceFunctions/arm_chebyshev_distance_f64.c) + zephyr_library_sources(${CMSIS_DSP_DIR}/Source/DistanceFunctions/arm_cityblock_distance_f32.c) + zephyr_library_sources(${CMSIS_DSP_DIR}/Source/DistanceFunctions/arm_cityblock_distance_f64.c) + zephyr_library_sources(${CMSIS_DSP_DIR}/Source/DistanceFunctions/arm_correlation_distance_f32.c) + zephyr_library_sources(${CMSIS_DSP_DIR}/Source/DistanceFunctions/arm_cosine_distance_f32.c) + zephyr_library_sources(${CMSIS_DSP_DIR}/Source/DistanceFunctions/arm_cosine_distance_f64.c) + zephyr_library_sources(${CMSIS_DSP_DIR}/Source/DistanceFunctions/arm_dice_distance.c) + zephyr_library_sources(${CMSIS_DSP_DIR}/Source/DistanceFunctions/arm_euclidean_distance_f32.c) + zephyr_library_sources(${CMSIS_DSP_DIR}/Source/DistanceFunctions/arm_euclidean_distance_f64.c) + zephyr_library_sources(${CMSIS_DSP_DIR}/Source/DistanceFunctions/arm_hamming_distance.c) + zephyr_library_sources(${CMSIS_DSP_DIR}/Source/DistanceFunctions/arm_jaccard_distance.c) + zephyr_library_sources(${CMSIS_DSP_DIR}/Source/DistanceFunctions/arm_jensenshannon_distance_f32.c) + zephyr_library_sources(${CMSIS_DSP_DIR}/Source/DistanceFunctions/arm_kulsinski_distance.c) + zephyr_library_sources(${CMSIS_DSP_DIR}/Source/DistanceFunctions/arm_minkowski_distance_f32.c) + zephyr_library_sources(${CMSIS_DSP_DIR}/Source/DistanceFunctions/arm_rogerstanimoto_distance.c) + zephyr_library_sources(${CMSIS_DSP_DIR}/Source/DistanceFunctions/arm_russellrao_distance.c) + zephyr_library_sources(${CMSIS_DSP_DIR}/Source/DistanceFunctions/arm_sokalmichener_distance.c) + zephyr_library_sources(${CMSIS_DSP_DIR}/Source/DistanceFunctions/arm_sokalsneath_distance.c) + zephyr_library_sources(${CMSIS_DSP_DIR}/Source/DistanceFunctions/arm_yule_distance.c) + zephyr_library_sources(${CMSIS_DSP_DIR}/Source/DistanceFunctions/arm_dtw_distance_f32.c) + zephyr_library_sources(${CMSIS_DSP_DIR}/Source/DistanceFunctions/arm_dtw_path_f32.c) + zephyr_library_sources(${CMSIS_DSP_DIR}/Source/DistanceFunctions/arm_dtw_init_window_q7.c) + + + zephyr_library_include_directories("${CMSIS_DSP_DIR}/Source/DistanceFunctions") + + if ((NOT ARMAC5) AND (NOT DISABLEFLOAT16)) + zephyr_library_sources(${CMSIS_DSP_DIR}/Source/DistanceFunctions/arm_braycurtis_distance_f16.c) + zephyr_library_sources(${CMSIS_DSP_DIR}/Source/DistanceFunctions/arm_canberra_distance_f16.c) + zephyr_library_sources(${CMSIS_DSP_DIR}/Source/DistanceFunctions/arm_chebyshev_distance_f16.c) + zephyr_library_sources(${CMSIS_DSP_DIR}/Source/DistanceFunctions/arm_cityblock_distance_f16.c) + zephyr_library_sources(${CMSIS_DSP_DIR}/Source/DistanceFunctions/arm_correlation_distance_f16.c) + zephyr_library_sources(${CMSIS_DSP_DIR}/Source/DistanceFunctions/arm_cosine_distance_f16.c) + zephyr_library_sources(${CMSIS_DSP_DIR}/Source/DistanceFunctions/arm_euclidean_distance_f16.c) + zephyr_library_sources(${CMSIS_DSP_DIR}/Source/DistanceFunctions/arm_jensenshannon_distance_f16.c) + zephyr_library_sources(${CMSIS_DSP_DIR}/Source/DistanceFunctions/arm_minkowski_distance_f16.c) + endif() endif() # Fast Math Functions - zephyr_library_sources(${CMSIS_DSP_DIR}/Source/FastMathFunctions/arm_cos_f32.c) + if (CONFIG_CMSIS_DSP_FASTMATH) + zephyr_library_sources(${CMSIS_DSP_DIR}/Source/FastMathFunctions/arm_cos_f32.c) - zephyr_library_sources(${CMSIS_DSP_DIR}/Source/FastMathFunctions/arm_cos_q15.c) + zephyr_library_sources(${CMSIS_DSP_DIR}/Source/FastMathFunctions/arm_cos_q15.c) - zephyr_library_sources(${CMSIS_DSP_DIR}/Source/FastMathFunctions/arm_cos_q31.c) + zephyr_library_sources(${CMSIS_DSP_DIR}/Source/FastMathFunctions/arm_cos_q31.c) - zephyr_library_sources(${CMSIS_DSP_DIR}/Source/FastMathFunctions/arm_sin_f32.c) + zephyr_library_sources(${CMSIS_DSP_DIR}/Source/FastMathFunctions/arm_sin_f32.c) - zephyr_library_sources(${CMSIS_DSP_DIR}/Source/FastMathFunctions/arm_sin_q15.c) + zephyr_library_sources(${CMSIS_DSP_DIR}/Source/FastMathFunctions/arm_sin_q15.c) - zephyr_library_sources(${CMSIS_DSP_DIR}/Source/FastMathFunctions/arm_sin_q31.c) + zephyr_library_sources(${CMSIS_DSP_DIR}/Source/FastMathFunctions/arm_sin_q31.c) - zephyr_library_sources(${CMSIS_DSP_DIR}/Source/FastMathFunctions/arm_sqrt_q31.c) + zephyr_library_sources(${CMSIS_DSP_DIR}/Source/FastMathFunctions/arm_sqrt_q31.c) - zephyr_library_sources(${CMSIS_DSP_DIR}/Source/FastMathFunctions/arm_sqrt_q15.c) + zephyr_library_sources(${CMSIS_DSP_DIR}/Source/FastMathFunctions/arm_sqrt_q15.c) - zephyr_library_sources(${CMSIS_DSP_DIR}/Source/FastMathFunctions/arm_vlog_f32.c) - zephyr_library_sources(${CMSIS_DSP_DIR}/Source/FastMathFunctions/arm_vlog_f64.c) - zephyr_library_sources(${CMSIS_DSP_DIR}/Source/FastMathFunctions/arm_vexp_f32.c) - zephyr_library_sources(${CMSIS_DSP_DIR}/Source/FastMathFunctions/arm_vexp_f64.c) + zephyr_library_sources(${CMSIS_DSP_DIR}/Source/FastMathFunctions/arm_vlog_f32.c) + zephyr_library_sources(${CMSIS_DSP_DIR}/Source/FastMathFunctions/arm_vlog_f64.c) + zephyr_library_sources(${CMSIS_DSP_DIR}/Source/FastMathFunctions/arm_vexp_f32.c) + zephyr_library_sources(${CMSIS_DSP_DIR}/Source/FastMathFunctions/arm_vexp_f64.c) - zephyr_library_sources(${CMSIS_DSP_DIR}/Source/FastMathFunctions/arm_vlog_q31.c) - zephyr_library_sources(${CMSIS_DSP_DIR}/Source/FastMathFunctions/arm_vlog_q15.c) + zephyr_library_sources(${CMSIS_DSP_DIR}/Source/FastMathFunctions/arm_vlog_q31.c) + zephyr_library_sources(${CMSIS_DSP_DIR}/Source/FastMathFunctions/arm_vlog_q15.c) - if ((NOT ARMAC5) AND (NOT DISABLEFLOAT16)) - zephyr_library_sources(${CMSIS_DSP_DIR}/Source/FastMathFunctions/arm_vlog_f16.c) - zephyr_library_sources(${CMSIS_DSP_DIR}/Source/FastMathFunctions/arm_vexp_f16.c) - zephyr_library_sources(${CMSIS_DSP_DIR}/Source/FastMathFunctions/arm_vinverse_f16.c) - zephyr_library_sources(${CMSIS_DSP_DIR}/Source/FastMathFunctions/arm_atan2_f16.c) - endif() + if ((NOT ARMAC5) AND (NOT DISABLEFLOAT16)) + zephyr_library_sources(${CMSIS_DSP_DIR}/Source/FastMathFunctions/arm_vlog_f16.c) + zephyr_library_sources(${CMSIS_DSP_DIR}/Source/FastMathFunctions/arm_vexp_f16.c) + zephyr_library_sources(${CMSIS_DSP_DIR}/Source/FastMathFunctions/arm_vinverse_f16.c) + zephyr_library_sources(${CMSIS_DSP_DIR}/Source/FastMathFunctions/arm_atan2_f16.c) + endif() - zephyr_library_sources(${CMSIS_DSP_DIR}/Source/FastMathFunctions/arm_divide_q15.c) - zephyr_library_sources(${CMSIS_DSP_DIR}/Source/FastMathFunctions/arm_divide_q31.c) + zephyr_library_sources(${CMSIS_DSP_DIR}/Source/FastMathFunctions/arm_divide_q15.c) + zephyr_library_sources(${CMSIS_DSP_DIR}/Source/FastMathFunctions/arm_divide_q31.c) - zephyr_library_sources(${CMSIS_DSP_DIR}/Source/FastMathFunctions/arm_atan2_f32.c) - zephyr_library_sources(${CMSIS_DSP_DIR}/Source/FastMathFunctions/arm_atan2_q31.c) - zephyr_library_sources(${CMSIS_DSP_DIR}/Source/FastMathFunctions/arm_atan2_q15.c) + zephyr_library_sources(${CMSIS_DSP_DIR}/Source/FastMathFunctions/arm_atan2_f32.c) + zephyr_library_sources(${CMSIS_DSP_DIR}/Source/FastMathFunctions/arm_atan2_q31.c) + zephyr_library_sources(${CMSIS_DSP_DIR}/Source/FastMathFunctions/arm_atan2_q15.c) + endif() # Filtering Functions - zephyr_library_sources(${CMSIS_DSP_DIR}/Source/FilteringFunctions/arm_lms_norm_init_q31.c) - - zephyr_library_sources(${CMSIS_DSP_DIR}/Source/FilteringFunctions/arm_lms_norm_init_q15.c) - - zephyr_library_sources(${CMSIS_DSP_DIR}/Source/FilteringFunctions/arm_biquad_cascade_df1_32x64_init_q31.c) - zephyr_library_sources(${CMSIS_DSP_DIR}/Source/FilteringFunctions/arm_biquad_cascade_df1_32x64_q31.c) - zephyr_library_sources(${CMSIS_DSP_DIR}/Source/FilteringFunctions/arm_biquad_cascade_df1_f32.c) - zephyr_library_sources(${CMSIS_DSP_DIR}/Source/FilteringFunctions/arm_biquad_cascade_df1_fast_q15.c) - zephyr_library_sources(${CMSIS_DSP_DIR}/Source/FilteringFunctions/arm_biquad_cascade_df1_fast_q31.c) - zephyr_library_sources(${CMSIS_DSP_DIR}/Source/FilteringFunctions/arm_biquad_cascade_df1_init_f32.c) - zephyr_library_sources(${CMSIS_DSP_DIR}/Source/FilteringFunctions/arm_biquad_cascade_df1_init_q15.c) - zephyr_library_sources(${CMSIS_DSP_DIR}/Source/FilteringFunctions/arm_biquad_cascade_df1_init_q31.c) - zephyr_library_sources(${CMSIS_DSP_DIR}/Source/FilteringFunctions/arm_biquad_cascade_df1_q15.c) - zephyr_library_sources(${CMSIS_DSP_DIR}/Source/FilteringFunctions/arm_biquad_cascade_df1_q31.c) - zephyr_library_sources(${CMSIS_DSP_DIR}/Source/FilteringFunctions/arm_biquad_cascade_df2T_f32.c) - zephyr_library_sources(${CMSIS_DSP_DIR}/Source/FilteringFunctions/arm_biquad_cascade_df2T_f64.c) - zephyr_library_sources(${CMSIS_DSP_DIR}/Source/FilteringFunctions/arm_biquad_cascade_df2T_init_f32.c) - zephyr_library_sources(${CMSIS_DSP_DIR}/Source/FilteringFunctions/arm_biquad_cascade_df2T_init_f64.c) - zephyr_library_sources(${CMSIS_DSP_DIR}/Source/FilteringFunctions/arm_biquad_cascade_stereo_df2T_f32.c) - zephyr_library_sources(${CMSIS_DSP_DIR}/Source/FilteringFunctions/arm_biquad_cascade_stereo_df2T_init_f32.c) - zephyr_library_sources(${CMSIS_DSP_DIR}/Source/FilteringFunctions/arm_conv_f32.c) - zephyr_library_sources(${CMSIS_DSP_DIR}/Source/FilteringFunctions/arm_conv_fast_opt_q15.c) - zephyr_library_sources(${CMSIS_DSP_DIR}/Source/FilteringFunctions/arm_conv_fast_q15.c) - zephyr_library_sources(${CMSIS_DSP_DIR}/Source/FilteringFunctions/arm_conv_fast_q31.c) - zephyr_library_sources(${CMSIS_DSP_DIR}/Source/FilteringFunctions/arm_conv_opt_q15.c) - zephyr_library_sources(${CMSIS_DSP_DIR}/Source/FilteringFunctions/arm_conv_opt_q7.c) - zephyr_library_sources(${CMSIS_DSP_DIR}/Source/FilteringFunctions/arm_conv_partial_f32.c) - zephyr_library_sources(${CMSIS_DSP_DIR}/Source/FilteringFunctions/arm_conv_partial_fast_opt_q15.c) - zephyr_library_sources(${CMSIS_DSP_DIR}/Source/FilteringFunctions/arm_conv_partial_fast_q15.c) - zephyr_library_sources(${CMSIS_DSP_DIR}/Source/FilteringFunctions/arm_conv_partial_fast_q31.c) - zephyr_library_sources(${CMSIS_DSP_DIR}/Source/FilteringFunctions/arm_conv_partial_opt_q15.c) - zephyr_library_sources(${CMSIS_DSP_DIR}/Source/FilteringFunctions/arm_conv_partial_opt_q7.c) - zephyr_library_sources(${CMSIS_DSP_DIR}/Source/FilteringFunctions/arm_conv_partial_q15.c) - zephyr_library_sources(${CMSIS_DSP_DIR}/Source/FilteringFunctions/arm_conv_partial_q31.c) - zephyr_library_sources(${CMSIS_DSP_DIR}/Source/FilteringFunctions/arm_conv_partial_q7.c) - zephyr_library_sources(${CMSIS_DSP_DIR}/Source/FilteringFunctions/arm_conv_q15.c) - zephyr_library_sources(${CMSIS_DSP_DIR}/Source/FilteringFunctions/arm_conv_q31.c) - zephyr_library_sources(${CMSIS_DSP_DIR}/Source/FilteringFunctions/arm_conv_q7.c) - zephyr_library_sources(${CMSIS_DSP_DIR}/Source/FilteringFunctions/arm_correlate_f32.c) - zephyr_library_sources(${CMSIS_DSP_DIR}/Source/FilteringFunctions/arm_correlate_f64.c) - zephyr_library_sources(${CMSIS_DSP_DIR}/Source/FilteringFunctions/arm_correlate_fast_opt_q15.c) - zephyr_library_sources(${CMSIS_DSP_DIR}/Source/FilteringFunctions/arm_correlate_fast_q15.c) - zephyr_library_sources(${CMSIS_DSP_DIR}/Source/FilteringFunctions/arm_correlate_fast_q31.c) - zephyr_library_sources(${CMSIS_DSP_DIR}/Source/FilteringFunctions/arm_correlate_opt_q15.c) - zephyr_library_sources(${CMSIS_DSP_DIR}/Source/FilteringFunctions/arm_correlate_opt_q7.c) - zephyr_library_sources(${CMSIS_DSP_DIR}/Source/FilteringFunctions/arm_correlate_q15.c) - zephyr_library_sources(${CMSIS_DSP_DIR}/Source/FilteringFunctions/arm_correlate_q31.c) - zephyr_library_sources(${CMSIS_DSP_DIR}/Source/FilteringFunctions/arm_correlate_q7.c) - zephyr_library_sources(${CMSIS_DSP_DIR}/Source/FilteringFunctions/arm_fir_decimate_f32.c) - zephyr_library_sources(${CMSIS_DSP_DIR}/Source/FilteringFunctions/arm_fir_decimate_fast_q15.c) - zephyr_library_sources(${CMSIS_DSP_DIR}/Source/FilteringFunctions/arm_fir_decimate_fast_q31.c) - zephyr_library_sources(${CMSIS_DSP_DIR}/Source/FilteringFunctions/arm_fir_decimate_init_f32.c) - zephyr_library_sources(${CMSIS_DSP_DIR}/Source/FilteringFunctions/arm_fir_decimate_init_q15.c) - zephyr_library_sources(${CMSIS_DSP_DIR}/Source/FilteringFunctions/arm_fir_decimate_init_q31.c) - zephyr_library_sources(${CMSIS_DSP_DIR}/Source/FilteringFunctions/arm_fir_decimate_q15.c) - zephyr_library_sources(${CMSIS_DSP_DIR}/Source/FilteringFunctions/arm_fir_decimate_q31.c) - zephyr_library_sources(${CMSIS_DSP_DIR}/Source/FilteringFunctions/arm_fir_f32.c) - zephyr_library_sources(${CMSIS_DSP_DIR}/Source/FilteringFunctions/arm_fir_f64.c) - zephyr_library_sources(${CMSIS_DSP_DIR}/Source/FilteringFunctions/arm_fir_fast_q15.c) - zephyr_library_sources(${CMSIS_DSP_DIR}/Source/FilteringFunctions/arm_fir_fast_q31.c) - zephyr_library_sources(${CMSIS_DSP_DIR}/Source/FilteringFunctions/arm_fir_init_f32.c) - zephyr_library_sources(${CMSIS_DSP_DIR}/Source/FilteringFunctions/arm_fir_init_f64.c) - zephyr_library_sources(${CMSIS_DSP_DIR}/Source/FilteringFunctions/arm_fir_init_q15.c) - zephyr_library_sources(${CMSIS_DSP_DIR}/Source/FilteringFunctions/arm_fir_init_q31.c) - zephyr_library_sources(${CMSIS_DSP_DIR}/Source/FilteringFunctions/arm_fir_init_q7.c) - zephyr_library_sources(${CMSIS_DSP_DIR}/Source/FilteringFunctions/arm_fir_interpolate_f32.c) - zephyr_library_sources(${CMSIS_DSP_DIR}/Source/FilteringFunctions/arm_fir_interpolate_init_f32.c) - zephyr_library_sources(${CMSIS_DSP_DIR}/Source/FilteringFunctions/arm_fir_interpolate_init_q15.c) - zephyr_library_sources(${CMSIS_DSP_DIR}/Source/FilteringFunctions/arm_fir_interpolate_init_q31.c) - zephyr_library_sources(${CMSIS_DSP_DIR}/Source/FilteringFunctions/arm_fir_interpolate_q15.c) - zephyr_library_sources(${CMSIS_DSP_DIR}/Source/FilteringFunctions/arm_fir_interpolate_q31.c) - zephyr_library_sources(${CMSIS_DSP_DIR}/Source/FilteringFunctions/arm_fir_lattice_f32.c) - zephyr_library_sources(${CMSIS_DSP_DIR}/Source/FilteringFunctions/arm_fir_lattice_init_f32.c) - zephyr_library_sources(${CMSIS_DSP_DIR}/Source/FilteringFunctions/arm_fir_lattice_init_q15.c) - zephyr_library_sources(${CMSIS_DSP_DIR}/Source/FilteringFunctions/arm_fir_lattice_init_q31.c) - zephyr_library_sources(${CMSIS_DSP_DIR}/Source/FilteringFunctions/arm_fir_lattice_q15.c) - zephyr_library_sources(${CMSIS_DSP_DIR}/Source/FilteringFunctions/arm_fir_lattice_q31.c) - zephyr_library_sources(${CMSIS_DSP_DIR}/Source/FilteringFunctions/arm_fir_q15.c) - zephyr_library_sources(${CMSIS_DSP_DIR}/Source/FilteringFunctions/arm_fir_q31.c) - zephyr_library_sources(${CMSIS_DSP_DIR}/Source/FilteringFunctions/arm_fir_q7.c) - zephyr_library_sources(${CMSIS_DSP_DIR}/Source/FilteringFunctions/arm_fir_sparse_f32.c) - zephyr_library_sources(${CMSIS_DSP_DIR}/Source/FilteringFunctions/arm_fir_sparse_init_f32.c) - zephyr_library_sources(${CMSIS_DSP_DIR}/Source/FilteringFunctions/arm_fir_sparse_init_q15.c) - zephyr_library_sources(${CMSIS_DSP_DIR}/Source/FilteringFunctions/arm_fir_sparse_init_q31.c) - zephyr_library_sources(${CMSIS_DSP_DIR}/Source/FilteringFunctions/arm_fir_sparse_init_q7.c) - zephyr_library_sources(${CMSIS_DSP_DIR}/Source/FilteringFunctions/arm_fir_sparse_q15.c) - zephyr_library_sources(${CMSIS_DSP_DIR}/Source/FilteringFunctions/arm_fir_sparse_q31.c) - zephyr_library_sources(${CMSIS_DSP_DIR}/Source/FilteringFunctions/arm_fir_sparse_q7.c) - zephyr_library_sources(${CMSIS_DSP_DIR}/Source/FilteringFunctions/arm_iir_lattice_f32.c) - zephyr_library_sources(${CMSIS_DSP_DIR}/Source/FilteringFunctions/arm_iir_lattice_init_f32.c) - zephyr_library_sources(${CMSIS_DSP_DIR}/Source/FilteringFunctions/arm_iir_lattice_init_q15.c) - zephyr_library_sources(${CMSIS_DSP_DIR}/Source/FilteringFunctions/arm_iir_lattice_init_q31.c) - zephyr_library_sources(${CMSIS_DSP_DIR}/Source/FilteringFunctions/arm_iir_lattice_q15.c) - zephyr_library_sources(${CMSIS_DSP_DIR}/Source/FilteringFunctions/arm_iir_lattice_q31.c) - zephyr_library_sources(${CMSIS_DSP_DIR}/Source/FilteringFunctions/arm_lms_f32.c) - zephyr_library_sources(${CMSIS_DSP_DIR}/Source/FilteringFunctions/arm_lms_init_f32.c) - zephyr_library_sources(${CMSIS_DSP_DIR}/Source/FilteringFunctions/arm_lms_init_q15.c) - zephyr_library_sources(${CMSIS_DSP_DIR}/Source/FilteringFunctions/arm_lms_init_q31.c) - zephyr_library_sources(${CMSIS_DSP_DIR}/Source/FilteringFunctions/arm_lms_norm_f32.c) - zephyr_library_sources(${CMSIS_DSP_DIR}/Source/FilteringFunctions/arm_lms_norm_init_f32.c) - zephyr_library_sources(${CMSIS_DSP_DIR}/Source/FilteringFunctions/arm_lms_norm_q15.c) - zephyr_library_sources(${CMSIS_DSP_DIR}/Source/FilteringFunctions/arm_lms_norm_q31.c) - zephyr_library_sources(${CMSIS_DSP_DIR}/Source/FilteringFunctions/arm_lms_q15.c) - zephyr_library_sources(${CMSIS_DSP_DIR}/Source/FilteringFunctions/arm_lms_q31.c) - zephyr_library_sources(${CMSIS_DSP_DIR}/Source/FilteringFunctions/arm_levinson_durbin_f32.c) - zephyr_library_sources(${CMSIS_DSP_DIR}/Source/FilteringFunctions/arm_levinson_durbin_q31.c) - - if ((NOT ARMAC5) AND (NOT DISABLEFLOAT16)) - zephyr_library_sources(${CMSIS_DSP_DIR}/Source/FilteringFunctions/arm_fir_f16.c) - zephyr_library_sources(${CMSIS_DSP_DIR}/Source/FilteringFunctions/arm_fir_init_f16.c) - zephyr_library_sources(${CMSIS_DSP_DIR}/Source/FilteringFunctions/arm_biquad_cascade_df1_f16.c) - zephyr_library_sources(${CMSIS_DSP_DIR}/Source/FilteringFunctions/arm_biquad_cascade_df1_init_f16.c) - zephyr_library_sources(${CMSIS_DSP_DIR}/Source/FilteringFunctions/arm_biquad_cascade_df2T_f16.c) - zephyr_library_sources(${CMSIS_DSP_DIR}/Source/FilteringFunctions/arm_biquad_cascade_df2T_init_f16.c) - zephyr_library_sources(${CMSIS_DSP_DIR}/Source/FilteringFunctions/arm_biquad_cascade_stereo_df2T_f16.c) - zephyr_library_sources(${CMSIS_DSP_DIR}/Source/FilteringFunctions/arm_biquad_cascade_stereo_df2T_init_f16.c) - zephyr_library_sources(${CMSIS_DSP_DIR}/Source/FilteringFunctions/arm_correlate_f16.c) - zephyr_library_sources(${CMSIS_DSP_DIR}/Source/FilteringFunctions/arm_levinson_durbin_f16.c) + if (CONFIG_CMSIS_DSP_FILTERING) + zephyr_library_sources(${CMSIS_DSP_DIR}/Source/FilteringFunctions/arm_lms_norm_init_q31.c) + + zephyr_library_sources(${CMSIS_DSP_DIR}/Source/FilteringFunctions/arm_lms_norm_init_q15.c) + + zephyr_library_sources(${CMSIS_DSP_DIR}/Source/FilteringFunctions/arm_biquad_cascade_df1_32x64_init_q31.c) + zephyr_library_sources(${CMSIS_DSP_DIR}/Source/FilteringFunctions/arm_biquad_cascade_df1_32x64_q31.c) + zephyr_library_sources(${CMSIS_DSP_DIR}/Source/FilteringFunctions/arm_biquad_cascade_df1_f32.c) + zephyr_library_sources(${CMSIS_DSP_DIR}/Source/FilteringFunctions/arm_biquad_cascade_df1_fast_q15.c) + zephyr_library_sources(${CMSIS_DSP_DIR}/Source/FilteringFunctions/arm_biquad_cascade_df1_fast_q31.c) + zephyr_library_sources(${CMSIS_DSP_DIR}/Source/FilteringFunctions/arm_biquad_cascade_df1_init_f32.c) + zephyr_library_sources(${CMSIS_DSP_DIR}/Source/FilteringFunctions/arm_biquad_cascade_df1_init_q15.c) + zephyr_library_sources(${CMSIS_DSP_DIR}/Source/FilteringFunctions/arm_biquad_cascade_df1_init_q31.c) + zephyr_library_sources(${CMSIS_DSP_DIR}/Source/FilteringFunctions/arm_biquad_cascade_df1_q15.c) + zephyr_library_sources(${CMSIS_DSP_DIR}/Source/FilteringFunctions/arm_biquad_cascade_df1_q31.c) + zephyr_library_sources(${CMSIS_DSP_DIR}/Source/FilteringFunctions/arm_biquad_cascade_df2T_f32.c) + zephyr_library_sources(${CMSIS_DSP_DIR}/Source/FilteringFunctions/arm_biquad_cascade_df2T_f64.c) + zephyr_library_sources(${CMSIS_DSP_DIR}/Source/FilteringFunctions/arm_biquad_cascade_df2T_init_f32.c) + zephyr_library_sources(${CMSIS_DSP_DIR}/Source/FilteringFunctions/arm_biquad_cascade_df2T_init_f64.c) + zephyr_library_sources(${CMSIS_DSP_DIR}/Source/FilteringFunctions/arm_biquad_cascade_stereo_df2T_f32.c) + zephyr_library_sources(${CMSIS_DSP_DIR}/Source/FilteringFunctions/arm_biquad_cascade_stereo_df2T_init_f32.c) + zephyr_library_sources(${CMSIS_DSP_DIR}/Source/FilteringFunctions/arm_conv_f32.c) + zephyr_library_sources(${CMSIS_DSP_DIR}/Source/FilteringFunctions/arm_conv_fast_opt_q15.c) + zephyr_library_sources(${CMSIS_DSP_DIR}/Source/FilteringFunctions/arm_conv_fast_q15.c) + zephyr_library_sources(${CMSIS_DSP_DIR}/Source/FilteringFunctions/arm_conv_fast_q31.c) + zephyr_library_sources(${CMSIS_DSP_DIR}/Source/FilteringFunctions/arm_conv_opt_q15.c) + zephyr_library_sources(${CMSIS_DSP_DIR}/Source/FilteringFunctions/arm_conv_opt_q7.c) + zephyr_library_sources(${CMSIS_DSP_DIR}/Source/FilteringFunctions/arm_conv_partial_f32.c) + zephyr_library_sources(${CMSIS_DSP_DIR}/Source/FilteringFunctions/arm_conv_partial_fast_opt_q15.c) + zephyr_library_sources(${CMSIS_DSP_DIR}/Source/FilteringFunctions/arm_conv_partial_fast_q15.c) + zephyr_library_sources(${CMSIS_DSP_DIR}/Source/FilteringFunctions/arm_conv_partial_fast_q31.c) + zephyr_library_sources(${CMSIS_DSP_DIR}/Source/FilteringFunctions/arm_conv_partial_opt_q15.c) + zephyr_library_sources(${CMSIS_DSP_DIR}/Source/FilteringFunctions/arm_conv_partial_opt_q7.c) + zephyr_library_sources(${CMSIS_DSP_DIR}/Source/FilteringFunctions/arm_conv_partial_q15.c) + zephyr_library_sources(${CMSIS_DSP_DIR}/Source/FilteringFunctions/arm_conv_partial_q31.c) + zephyr_library_sources(${CMSIS_DSP_DIR}/Source/FilteringFunctions/arm_conv_partial_q7.c) + zephyr_library_sources(${CMSIS_DSP_DIR}/Source/FilteringFunctions/arm_conv_q15.c) + zephyr_library_sources(${CMSIS_DSP_DIR}/Source/FilteringFunctions/arm_conv_q31.c) + zephyr_library_sources(${CMSIS_DSP_DIR}/Source/FilteringFunctions/arm_conv_q7.c) + zephyr_library_sources(${CMSIS_DSP_DIR}/Source/FilteringFunctions/arm_correlate_f32.c) + zephyr_library_sources(${CMSIS_DSP_DIR}/Source/FilteringFunctions/arm_correlate_f64.c) + zephyr_library_sources(${CMSIS_DSP_DIR}/Source/FilteringFunctions/arm_correlate_fast_opt_q15.c) + zephyr_library_sources(${CMSIS_DSP_DIR}/Source/FilteringFunctions/arm_correlate_fast_q15.c) + zephyr_library_sources(${CMSIS_DSP_DIR}/Source/FilteringFunctions/arm_correlate_fast_q31.c) + zephyr_library_sources(${CMSIS_DSP_DIR}/Source/FilteringFunctions/arm_correlate_opt_q15.c) + zephyr_library_sources(${CMSIS_DSP_DIR}/Source/FilteringFunctions/arm_correlate_opt_q7.c) + zephyr_library_sources(${CMSIS_DSP_DIR}/Source/FilteringFunctions/arm_correlate_q15.c) + zephyr_library_sources(${CMSIS_DSP_DIR}/Source/FilteringFunctions/arm_correlate_q31.c) + zephyr_library_sources(${CMSIS_DSP_DIR}/Source/FilteringFunctions/arm_correlate_q7.c) + zephyr_library_sources(${CMSIS_DSP_DIR}/Source/FilteringFunctions/arm_fir_decimate_f32.c) + zephyr_library_sources(${CMSIS_DSP_DIR}/Source/FilteringFunctions/arm_fir_decimate_fast_q15.c) + zephyr_library_sources(${CMSIS_DSP_DIR}/Source/FilteringFunctions/arm_fir_decimate_fast_q31.c) + zephyr_library_sources(${CMSIS_DSP_DIR}/Source/FilteringFunctions/arm_fir_decimate_init_f32.c) + zephyr_library_sources(${CMSIS_DSP_DIR}/Source/FilteringFunctions/arm_fir_decimate_init_q15.c) + zephyr_library_sources(${CMSIS_DSP_DIR}/Source/FilteringFunctions/arm_fir_decimate_init_q31.c) + zephyr_library_sources(${CMSIS_DSP_DIR}/Source/FilteringFunctions/arm_fir_decimate_q15.c) + zephyr_library_sources(${CMSIS_DSP_DIR}/Source/FilteringFunctions/arm_fir_decimate_q31.c) + zephyr_library_sources(${CMSIS_DSP_DIR}/Source/FilteringFunctions/arm_fir_f32.c) + zephyr_library_sources(${CMSIS_DSP_DIR}/Source/FilteringFunctions/arm_fir_f64.c) + zephyr_library_sources(${CMSIS_DSP_DIR}/Source/FilteringFunctions/arm_fir_fast_q15.c) + zephyr_library_sources(${CMSIS_DSP_DIR}/Source/FilteringFunctions/arm_fir_fast_q31.c) + zephyr_library_sources(${CMSIS_DSP_DIR}/Source/FilteringFunctions/arm_fir_init_f32.c) + zephyr_library_sources(${CMSIS_DSP_DIR}/Source/FilteringFunctions/arm_fir_init_f64.c) + zephyr_library_sources(${CMSIS_DSP_DIR}/Source/FilteringFunctions/arm_fir_init_q15.c) + zephyr_library_sources(${CMSIS_DSP_DIR}/Source/FilteringFunctions/arm_fir_init_q31.c) + zephyr_library_sources(${CMSIS_DSP_DIR}/Source/FilteringFunctions/arm_fir_init_q7.c) + zephyr_library_sources(${CMSIS_DSP_DIR}/Source/FilteringFunctions/arm_fir_interpolate_f32.c) + zephyr_library_sources(${CMSIS_DSP_DIR}/Source/FilteringFunctions/arm_fir_interpolate_init_f32.c) + zephyr_library_sources(${CMSIS_DSP_DIR}/Source/FilteringFunctions/arm_fir_interpolate_init_q15.c) + zephyr_library_sources(${CMSIS_DSP_DIR}/Source/FilteringFunctions/arm_fir_interpolate_init_q31.c) + zephyr_library_sources(${CMSIS_DSP_DIR}/Source/FilteringFunctions/arm_fir_interpolate_q15.c) + zephyr_library_sources(${CMSIS_DSP_DIR}/Source/FilteringFunctions/arm_fir_interpolate_q31.c) + zephyr_library_sources(${CMSIS_DSP_DIR}/Source/FilteringFunctions/arm_fir_lattice_f32.c) + zephyr_library_sources(${CMSIS_DSP_DIR}/Source/FilteringFunctions/arm_fir_lattice_init_f32.c) + zephyr_library_sources(${CMSIS_DSP_DIR}/Source/FilteringFunctions/arm_fir_lattice_init_q15.c) + zephyr_library_sources(${CMSIS_DSP_DIR}/Source/FilteringFunctions/arm_fir_lattice_init_q31.c) + zephyr_library_sources(${CMSIS_DSP_DIR}/Source/FilteringFunctions/arm_fir_lattice_q15.c) + zephyr_library_sources(${CMSIS_DSP_DIR}/Source/FilteringFunctions/arm_fir_lattice_q31.c) + zephyr_library_sources(${CMSIS_DSP_DIR}/Source/FilteringFunctions/arm_fir_q15.c) + zephyr_library_sources(${CMSIS_DSP_DIR}/Source/FilteringFunctions/arm_fir_q31.c) + zephyr_library_sources(${CMSIS_DSP_DIR}/Source/FilteringFunctions/arm_fir_q7.c) + zephyr_library_sources(${CMSIS_DSP_DIR}/Source/FilteringFunctions/arm_fir_sparse_f32.c) + zephyr_library_sources(${CMSIS_DSP_DIR}/Source/FilteringFunctions/arm_fir_sparse_init_f32.c) + zephyr_library_sources(${CMSIS_DSP_DIR}/Source/FilteringFunctions/arm_fir_sparse_init_q15.c) + zephyr_library_sources(${CMSIS_DSP_DIR}/Source/FilteringFunctions/arm_fir_sparse_init_q31.c) + zephyr_library_sources(${CMSIS_DSP_DIR}/Source/FilteringFunctions/arm_fir_sparse_init_q7.c) + zephyr_library_sources(${CMSIS_DSP_DIR}/Source/FilteringFunctions/arm_fir_sparse_q15.c) + zephyr_library_sources(${CMSIS_DSP_DIR}/Source/FilteringFunctions/arm_fir_sparse_q31.c) + zephyr_library_sources(${CMSIS_DSP_DIR}/Source/FilteringFunctions/arm_fir_sparse_q7.c) + zephyr_library_sources(${CMSIS_DSP_DIR}/Source/FilteringFunctions/arm_iir_lattice_f32.c) + zephyr_library_sources(${CMSIS_DSP_DIR}/Source/FilteringFunctions/arm_iir_lattice_init_f32.c) + zephyr_library_sources(${CMSIS_DSP_DIR}/Source/FilteringFunctions/arm_iir_lattice_init_q15.c) + zephyr_library_sources(${CMSIS_DSP_DIR}/Source/FilteringFunctions/arm_iir_lattice_init_q31.c) + zephyr_library_sources(${CMSIS_DSP_DIR}/Source/FilteringFunctions/arm_iir_lattice_q15.c) + zephyr_library_sources(${CMSIS_DSP_DIR}/Source/FilteringFunctions/arm_iir_lattice_q31.c) + zephyr_library_sources(${CMSIS_DSP_DIR}/Source/FilteringFunctions/arm_lms_f32.c) + zephyr_library_sources(${CMSIS_DSP_DIR}/Source/FilteringFunctions/arm_lms_init_f32.c) + zephyr_library_sources(${CMSIS_DSP_DIR}/Source/FilteringFunctions/arm_lms_init_q15.c) + zephyr_library_sources(${CMSIS_DSP_DIR}/Source/FilteringFunctions/arm_lms_init_q31.c) + zephyr_library_sources(${CMSIS_DSP_DIR}/Source/FilteringFunctions/arm_lms_norm_f32.c) + zephyr_library_sources(${CMSIS_DSP_DIR}/Source/FilteringFunctions/arm_lms_norm_init_f32.c) + zephyr_library_sources(${CMSIS_DSP_DIR}/Source/FilteringFunctions/arm_lms_norm_q15.c) + zephyr_library_sources(${CMSIS_DSP_DIR}/Source/FilteringFunctions/arm_lms_norm_q31.c) + zephyr_library_sources(${CMSIS_DSP_DIR}/Source/FilteringFunctions/arm_lms_q15.c) + zephyr_library_sources(${CMSIS_DSP_DIR}/Source/FilteringFunctions/arm_lms_q31.c) + zephyr_library_sources(${CMSIS_DSP_DIR}/Source/FilteringFunctions/arm_levinson_durbin_f32.c) + zephyr_library_sources(${CMSIS_DSP_DIR}/Source/FilteringFunctions/arm_levinson_durbin_q31.c) + + if ((NOT ARMAC5) AND (NOT DISABLEFLOAT16)) + zephyr_library_sources(${CMSIS_DSP_DIR}/Source/FilteringFunctions/arm_fir_f16.c) + zephyr_library_sources(${CMSIS_DSP_DIR}/Source/FilteringFunctions/arm_fir_init_f16.c) + zephyr_library_sources(${CMSIS_DSP_DIR}/Source/FilteringFunctions/arm_biquad_cascade_df1_f16.c) + zephyr_library_sources(${CMSIS_DSP_DIR}/Source/FilteringFunctions/arm_biquad_cascade_df1_init_f16.c) + zephyr_library_sources(${CMSIS_DSP_DIR}/Source/FilteringFunctions/arm_biquad_cascade_df2T_f16.c) + zephyr_library_sources(${CMSIS_DSP_DIR}/Source/FilteringFunctions/arm_biquad_cascade_df2T_init_f16.c) + zephyr_library_sources(${CMSIS_DSP_DIR}/Source/FilteringFunctions/arm_biquad_cascade_stereo_df2T_f16.c) + zephyr_library_sources(${CMSIS_DSP_DIR}/Source/FilteringFunctions/arm_biquad_cascade_stereo_df2T_init_f16.c) + zephyr_library_sources(${CMSIS_DSP_DIR}/Source/FilteringFunctions/arm_correlate_f16.c) + zephyr_library_sources(${CMSIS_DSP_DIR}/Source/FilteringFunctions/arm_levinson_durbin_f16.c) + endif() endif() # Interpolation Functions - zephyr_library_sources(${CMSIS_DSP_DIR}/Source/InterpolationFunctions/arm_bilinear_interp_f32.c) - zephyr_library_sources(${CMSIS_DSP_DIR}/Source/InterpolationFunctions/arm_bilinear_interp_q15.c) - zephyr_library_sources(${CMSIS_DSP_DIR}/Source/InterpolationFunctions/arm_bilinear_interp_q31.c) - zephyr_library_sources(${CMSIS_DSP_DIR}/Source/InterpolationFunctions/arm_bilinear_interp_q7.c) - zephyr_library_sources(${CMSIS_DSP_DIR}/Source/InterpolationFunctions/arm_linear_interp_f32.c) - zephyr_library_sources(${CMSIS_DSP_DIR}/Source/InterpolationFunctions/arm_linear_interp_q15.c) - zephyr_library_sources(${CMSIS_DSP_DIR}/Source/InterpolationFunctions/arm_linear_interp_q31.c) - zephyr_library_sources(${CMSIS_DSP_DIR}/Source/InterpolationFunctions/arm_linear_interp_q7.c) - zephyr_library_sources(${CMSIS_DSP_DIR}/Source/InterpolationFunctions/arm_spline_interp_f32.c) - zephyr_library_sources(${CMSIS_DSP_DIR}/Source/InterpolationFunctions/arm_spline_interp_init_f32.c) - - - - if ((NOT ARMAC5) AND (NOT DISABLEFLOAT16)) - zephyr_library_sources(${CMSIS_DSP_DIR}/Source/InterpolationFunctions/arm_bilinear_interp_f16.c) - zephyr_library_sources(${CMSIS_DSP_DIR}/Source/InterpolationFunctions/arm_linear_interp_f16.c) + if (CONFIG_CMSIS_DSP_INTERPOLATION) + zephyr_library_sources(${CMSIS_DSP_DIR}/Source/InterpolationFunctions/arm_bilinear_interp_f32.c) + zephyr_library_sources(${CMSIS_DSP_DIR}/Source/InterpolationFunctions/arm_bilinear_interp_q15.c) + zephyr_library_sources(${CMSIS_DSP_DIR}/Source/InterpolationFunctions/arm_bilinear_interp_q31.c) + zephyr_library_sources(${CMSIS_DSP_DIR}/Source/InterpolationFunctions/arm_bilinear_interp_q7.c) + zephyr_library_sources(${CMSIS_DSP_DIR}/Source/InterpolationFunctions/arm_linear_interp_f32.c) + zephyr_library_sources(${CMSIS_DSP_DIR}/Source/InterpolationFunctions/arm_linear_interp_q15.c) + zephyr_library_sources(${CMSIS_DSP_DIR}/Source/InterpolationFunctions/arm_linear_interp_q31.c) + zephyr_library_sources(${CMSIS_DSP_DIR}/Source/InterpolationFunctions/arm_linear_interp_q7.c) + zephyr_library_sources(${CMSIS_DSP_DIR}/Source/InterpolationFunctions/arm_spline_interp_f32.c) + zephyr_library_sources(${CMSIS_DSP_DIR}/Source/InterpolationFunctions/arm_spline_interp_init_f32.c) + + + if ((NOT ARMAC5) AND (NOT DISABLEFLOAT16)) + zephyr_library_sources(${CMSIS_DSP_DIR}/Source/InterpolationFunctions/arm_bilinear_interp_f16.c) + zephyr_library_sources(${CMSIS_DSP_DIR}/Source/InterpolationFunctions/arm_linear_interp_f16.c) + endif() endif() # Matrix Functions - set(SRCF64 ${CMSIS_DSP_DIR}/Source/MatrixFunctions/arm_mat_cholesky_f64.c - ${CMSIS_DSP_DIR}/Source/MatrixFunctions/arm_mat_inverse_f64.c - ${CMSIS_DSP_DIR}/Source/MatrixFunctions/arm_mat_ldlt_f64.c - ${CMSIS_DSP_DIR}/Source/MatrixFunctions/arm_mat_mult_f64.c - ${CMSIS_DSP_DIR}/Source/MatrixFunctions/arm_mat_solve_lower_triangular_f64.c - ${CMSIS_DSP_DIR}/Source/MatrixFunctions/arm_mat_solve_upper_triangular_f64.c - ${CMSIS_DSP_DIR}/Source/MatrixFunctions/arm_mat_sub_f64.c - ${CMSIS_DSP_DIR}/Source/MatrixFunctions/arm_mat_trans_f64.c - ${CMSIS_DSP_DIR}/Source/MatrixFunctions/arm_mat_qr_f64.c - ${CMSIS_DSP_DIR}/Source/MatrixFunctions/arm_householder_f64.c - ) + if (CONFIG_CMSIS_DSP_MATRIX) + set(SRCF64 ${CMSIS_DSP_DIR}/Source/MatrixFunctions/arm_mat_cholesky_f64.c + ${CMSIS_DSP_DIR}/Source/MatrixFunctions/arm_mat_inverse_f64.c + ${CMSIS_DSP_DIR}/Source/MatrixFunctions/arm_mat_ldlt_f64.c + ${CMSIS_DSP_DIR}/Source/MatrixFunctions/arm_mat_mult_f64.c + ${CMSIS_DSP_DIR}/Source/MatrixFunctions/arm_mat_solve_lower_triangular_f64.c + ${CMSIS_DSP_DIR}/Source/MatrixFunctions/arm_mat_solve_upper_triangular_f64.c + ${CMSIS_DSP_DIR}/Source/MatrixFunctions/arm_mat_sub_f64.c + ${CMSIS_DSP_DIR}/Source/MatrixFunctions/arm_mat_trans_f64.c + ${CMSIS_DSP_DIR}/Source/MatrixFunctions/arm_mat_qr_f64.c + ${CMSIS_DSP_DIR}/Source/MatrixFunctions/arm_householder_f64.c + ) - set(SRCF32 ${CMSIS_DSP_DIR}/Source/MatrixFunctions/arm_mat_add_f32.c - ${CMSIS_DSP_DIR}/Source/MatrixFunctions/arm_mat_cholesky_f32.c - ${CMSIS_DSP_DIR}/Source/MatrixFunctions/arm_mat_cmplx_mult_f32.c - ${CMSIS_DSP_DIR}/Source/MatrixFunctions/arm_mat_cmplx_trans_f32.c - ${CMSIS_DSP_DIR}/Source/MatrixFunctions/arm_mat_init_f32.c - ${CMSIS_DSP_DIR}/Source/MatrixFunctions/arm_mat_inverse_f32.c - ${CMSIS_DSP_DIR}/Source/MatrixFunctions/arm_mat_ldlt_f32.c - ${CMSIS_DSP_DIR}/Source/MatrixFunctions/arm_mat_mult_f32.c - ${CMSIS_DSP_DIR}/Source/MatrixFunctions/arm_mat_scale_f32.c - ${CMSIS_DSP_DIR}/Source/MatrixFunctions/arm_mat_solve_lower_triangular_f32.c - ${CMSIS_DSP_DIR}/Source/MatrixFunctions/arm_mat_solve_upper_triangular_f32.c - ${CMSIS_DSP_DIR}/Source/MatrixFunctions/arm_mat_sub_f32.c - ${CMSIS_DSP_DIR}/Source/MatrixFunctions/arm_mat_trans_f32.c - ${CMSIS_DSP_DIR}/Source/MatrixFunctions/arm_mat_vec_mult_f32.c - ${CMSIS_DSP_DIR}/Source/MatrixFunctions/arm_mat_qr_f32.c - ${CMSIS_DSP_DIR}/Source/MatrixFunctions/arm_householder_f32.c - ) + set(SRCF32 ${CMSIS_DSP_DIR}/Source/MatrixFunctions/arm_mat_add_f32.c + ${CMSIS_DSP_DIR}/Source/MatrixFunctions/arm_mat_cholesky_f32.c + ${CMSIS_DSP_DIR}/Source/MatrixFunctions/arm_mat_cmplx_mult_f32.c + ${CMSIS_DSP_DIR}/Source/MatrixFunctions/arm_mat_cmplx_trans_f32.c + ${CMSIS_DSP_DIR}/Source/MatrixFunctions/arm_mat_init_f32.c + ${CMSIS_DSP_DIR}/Source/MatrixFunctions/arm_mat_inverse_f32.c + ${CMSIS_DSP_DIR}/Source/MatrixFunctions/arm_mat_ldlt_f32.c + ${CMSIS_DSP_DIR}/Source/MatrixFunctions/arm_mat_mult_f32.c + ${CMSIS_DSP_DIR}/Source/MatrixFunctions/arm_mat_scale_f32.c + ${CMSIS_DSP_DIR}/Source/MatrixFunctions/arm_mat_solve_lower_triangular_f32.c + ${CMSIS_DSP_DIR}/Source/MatrixFunctions/arm_mat_solve_upper_triangular_f32.c + ${CMSIS_DSP_DIR}/Source/MatrixFunctions/arm_mat_sub_f32.c + ${CMSIS_DSP_DIR}/Source/MatrixFunctions/arm_mat_trans_f32.c + ${CMSIS_DSP_DIR}/Source/MatrixFunctions/arm_mat_vec_mult_f32.c + ${CMSIS_DSP_DIR}/Source/MatrixFunctions/arm_mat_qr_f32.c + ${CMSIS_DSP_DIR}/Source/MatrixFunctions/arm_householder_f32.c + ) - set(SRCQ31 ${CMSIS_DSP_DIR}/Source/MatrixFunctions/arm_mat_add_q31.c - ${CMSIS_DSP_DIR}/Source/MatrixFunctions/arm_mat_cmplx_mult_q31.c - ${CMSIS_DSP_DIR}/Source/MatrixFunctions/arm_mat_cmplx_trans_q31.c - ${CMSIS_DSP_DIR}/Source/MatrixFunctions/arm_mat_init_q31.c - ${CMSIS_DSP_DIR}/Source/MatrixFunctions/arm_mat_mult_fast_q31.c - ${CMSIS_DSP_DIR}/Source/MatrixFunctions/arm_mat_mult_opt_q31.c - ${CMSIS_DSP_DIR}/Source/MatrixFunctions/arm_mat_mult_q31.c - ${CMSIS_DSP_DIR}/Source/MatrixFunctions/arm_mat_scale_q31.c - ${CMSIS_DSP_DIR}/Source/MatrixFunctions/arm_mat_sub_q31.c - ${CMSIS_DSP_DIR}/Source/MatrixFunctions/arm_mat_trans_q31.c - ${CMSIS_DSP_DIR}/Source/MatrixFunctions/arm_mat_vec_mult_q31.c - ) + set(SRCQ31 ${CMSIS_DSP_DIR}/Source/MatrixFunctions/arm_mat_add_q31.c + ${CMSIS_DSP_DIR}/Source/MatrixFunctions/arm_mat_cmplx_mult_q31.c + ${CMSIS_DSP_DIR}/Source/MatrixFunctions/arm_mat_cmplx_trans_q31.c + ${CMSIS_DSP_DIR}/Source/MatrixFunctions/arm_mat_init_q31.c + ${CMSIS_DSP_DIR}/Source/MatrixFunctions/arm_mat_mult_fast_q31.c + ${CMSIS_DSP_DIR}/Source/MatrixFunctions/arm_mat_mult_opt_q31.c + ${CMSIS_DSP_DIR}/Source/MatrixFunctions/arm_mat_mult_q31.c + ${CMSIS_DSP_DIR}/Source/MatrixFunctions/arm_mat_scale_q31.c + ${CMSIS_DSP_DIR}/Source/MatrixFunctions/arm_mat_sub_q31.c + ${CMSIS_DSP_DIR}/Source/MatrixFunctions/arm_mat_trans_q31.c + ${CMSIS_DSP_DIR}/Source/MatrixFunctions/arm_mat_vec_mult_q31.c + ) - set(SRCQ15 ${CMSIS_DSP_DIR}/Source/MatrixFunctions/arm_mat_add_q15.c - ${CMSIS_DSP_DIR}/Source/MatrixFunctions/arm_mat_cmplx_mult_q15.c - ${CMSIS_DSP_DIR}/Source/MatrixFunctions/arm_mat_cmplx_trans_q15.c - ${CMSIS_DSP_DIR}/Source/MatrixFunctions/arm_mat_init_q15.c - ${CMSIS_DSP_DIR}/Source/MatrixFunctions/arm_mat_mult_fast_q15.c - ${CMSIS_DSP_DIR}/Source/MatrixFunctions/arm_mat_mult_q15.c - ${CMSIS_DSP_DIR}/Source/MatrixFunctions/arm_mat_scale_q15.c - ${CMSIS_DSP_DIR}/Source/MatrixFunctions/arm_mat_sub_q15.c - ${CMSIS_DSP_DIR}/Source/MatrixFunctions/arm_mat_trans_q15.c - ${CMSIS_DSP_DIR}/Source/MatrixFunctions/arm_mat_vec_mult_q15.c - ) + set(SRCQ15 ${CMSIS_DSP_DIR}/Source/MatrixFunctions/arm_mat_add_q15.c + ${CMSIS_DSP_DIR}/Source/MatrixFunctions/arm_mat_cmplx_mult_q15.c + ${CMSIS_DSP_DIR}/Source/MatrixFunctions/arm_mat_cmplx_trans_q15.c + ${CMSIS_DSP_DIR}/Source/MatrixFunctions/arm_mat_init_q15.c + ${CMSIS_DSP_DIR}/Source/MatrixFunctions/arm_mat_mult_fast_q15.c + ${CMSIS_DSP_DIR}/Source/MatrixFunctions/arm_mat_mult_q15.c + ${CMSIS_DSP_DIR}/Source/MatrixFunctions/arm_mat_scale_q15.c + ${CMSIS_DSP_DIR}/Source/MatrixFunctions/arm_mat_sub_q15.c + ${CMSIS_DSP_DIR}/Source/MatrixFunctions/arm_mat_trans_q15.c + ${CMSIS_DSP_DIR}/Source/MatrixFunctions/arm_mat_vec_mult_q15.c + ) - set(SRCQ7 ${CMSIS_DSP_DIR}/Source/MatrixFunctions/arm_mat_mult_q7.c - ${CMSIS_DSP_DIR}/Source/MatrixFunctions/arm_mat_vec_mult_q7.c - ${CMSIS_DSP_DIR}/Source/MatrixFunctions/arm_mat_trans_q7.c - ) + set(SRCQ7 ${CMSIS_DSP_DIR}/Source/MatrixFunctions/arm_mat_mult_q7.c + ${CMSIS_DSP_DIR}/Source/MatrixFunctions/arm_mat_vec_mult_q7.c + ${CMSIS_DSP_DIR}/Source/MatrixFunctions/arm_mat_trans_q7.c + ) + zephyr_library_sources(${SRCF64}) + zephyr_library_sources(${SRCF32}) - zephyr_library_sources(${SRCF64}) - zephyr_library_sources(${SRCF32}) - - zephyr_library_sources(${SRCQ31}) - zephyr_library_sources(${SRCQ15}) - zephyr_library_sources(${SRCQ7}) - - - if ((NOT ARMAC5) AND (NOT DISABLEFLOAT16)) - zephyr_library_sources(${CMSIS_DSP_DIR}/Source/MatrixFunctions/arm_mat_add_f16.c - ${CMSIS_DSP_DIR}/Source/MatrixFunctions/arm_mat_cholesky_f16.c - ${CMSIS_DSP_DIR}/Source/MatrixFunctions/arm_mat_cmplx_mult_f16.c - ${CMSIS_DSP_DIR}/Source/MatrixFunctions/arm_mat_cmplx_trans_f16.c - ${CMSIS_DSP_DIR}/Source/MatrixFunctions/arm_mat_init_f16.c - ${CMSIS_DSP_DIR}/Source/MatrixFunctions/arm_mat_inverse_f16.c - ${CMSIS_DSP_DIR}/Source/MatrixFunctions/arm_mat_mult_f16.c - ${CMSIS_DSP_DIR}/Source/MatrixFunctions/arm_mat_scale_f16.c - ${CMSIS_DSP_DIR}/Source/MatrixFunctions/arm_mat_solve_lower_triangular_f16.c - ${CMSIS_DSP_DIR}/Source/MatrixFunctions/arm_mat_solve_upper_triangular_f16.c - ${CMSIS_DSP_DIR}/Source/MatrixFunctions/arm_mat_sub_f16.c - ${CMSIS_DSP_DIR}/Source/MatrixFunctions/arm_mat_trans_f16.c - ${CMSIS_DSP_DIR}/Source/MatrixFunctions/arm_mat_vec_mult_f16.c - ${CMSIS_DSP_DIR}/Source/MatrixFunctions/arm_mat_qr_f16.c - ${CMSIS_DSP_DIR}/Source/MatrixFunctions/arm_householder_f16.c - ) + zephyr_library_sources(${SRCQ31}) + zephyr_library_sources(${SRCQ15}) + zephyr_library_sources(${SRCQ7}) + + + if ((NOT ARMAC5) AND (NOT DISABLEFLOAT16)) + zephyr_library_sources(${CMSIS_DSP_DIR}/Source/MatrixFunctions/arm_mat_add_f16.c + ${CMSIS_DSP_DIR}/Source/MatrixFunctions/arm_mat_cholesky_f16.c + ${CMSIS_DSP_DIR}/Source/MatrixFunctions/arm_mat_cmplx_mult_f16.c + ${CMSIS_DSP_DIR}/Source/MatrixFunctions/arm_mat_cmplx_trans_f16.c + ${CMSIS_DSP_DIR}/Source/MatrixFunctions/arm_mat_init_f16.c + ${CMSIS_DSP_DIR}/Source/MatrixFunctions/arm_mat_inverse_f16.c + ${CMSIS_DSP_DIR}/Source/MatrixFunctions/arm_mat_mult_f16.c + ${CMSIS_DSP_DIR}/Source/MatrixFunctions/arm_mat_scale_f16.c + ${CMSIS_DSP_DIR}/Source/MatrixFunctions/arm_mat_solve_lower_triangular_f16.c + ${CMSIS_DSP_DIR}/Source/MatrixFunctions/arm_mat_solve_upper_triangular_f16.c + ${CMSIS_DSP_DIR}/Source/MatrixFunctions/arm_mat_sub_f16.c + ${CMSIS_DSP_DIR}/Source/MatrixFunctions/arm_mat_trans_f16.c + ${CMSIS_DSP_DIR}/Source/MatrixFunctions/arm_mat_vec_mult_f16.c + ${CMSIS_DSP_DIR}/Source/MatrixFunctions/arm_mat_qr_f16.c + ${CMSIS_DSP_DIR}/Source/MatrixFunctions/arm_householder_f16.c + ) + endif() endif() # Quaternion Math Functions - zephyr_library_sources(${CMSIS_DSP_DIR}/Source/QuaternionMathFunctions/arm_quaternion_norm_f32.c) - zephyr_library_sources(${CMSIS_DSP_DIR}/Source/QuaternionMathFunctions/arm_quaternion_inverse_f32.c) - zephyr_library_sources(${CMSIS_DSP_DIR}/Source/QuaternionMathFunctions/arm_quaternion_conjugate_f32.c) - zephyr_library_sources(${CMSIS_DSP_DIR}/Source/QuaternionMathFunctions/arm_quaternion_normalize_f32.c) - zephyr_library_sources(${CMSIS_DSP_DIR}/Source/QuaternionMathFunctions/arm_quaternion_product_single_f32.c) - zephyr_library_sources(${CMSIS_DSP_DIR}/Source/QuaternionMathFunctions/arm_quaternion_product_f32.c) - zephyr_library_sources(${CMSIS_DSP_DIR}/Source/QuaternionMathFunctions/arm_quaternion2rotation_f32.c) - zephyr_library_sources(${CMSIS_DSP_DIR}/Source/QuaternionMathFunctions/arm_rotation2quaternion_f32.c) + if (CONFIG_CMSIS_DSP_QUATERNIONMATH) + zephyr_library_sources(${CMSIS_DSP_DIR}/Source/QuaternionMathFunctions/arm_quaternion_norm_f32.c) + zephyr_library_sources(${CMSIS_DSP_DIR}/Source/QuaternionMathFunctions/arm_quaternion_inverse_f32.c) + zephyr_library_sources(${CMSIS_DSP_DIR}/Source/QuaternionMathFunctions/arm_quaternion_conjugate_f32.c) + zephyr_library_sources(${CMSIS_DSP_DIR}/Source/QuaternionMathFunctions/arm_quaternion_normalize_f32.c) + zephyr_library_sources(${CMSIS_DSP_DIR}/Source/QuaternionMathFunctions/arm_quaternion_product_single_f32.c) + zephyr_library_sources(${CMSIS_DSP_DIR}/Source/QuaternionMathFunctions/arm_quaternion_product_f32.c) + zephyr_library_sources(${CMSIS_DSP_DIR}/Source/QuaternionMathFunctions/arm_quaternion2rotation_f32.c) + zephyr_library_sources(${CMSIS_DSP_DIR}/Source/QuaternionMathFunctions/arm_rotation2quaternion_f32.c) + endif() # Statistics Functions - zephyr_library_sources(${CMSIS_DSP_DIR}/Source/StatisticsFunctions/arm_entropy_f32.c) - zephyr_library_sources(${CMSIS_DSP_DIR}/Source/StatisticsFunctions/arm_entropy_f64.c) - zephyr_library_sources(${CMSIS_DSP_DIR}/Source/StatisticsFunctions/arm_kullback_leibler_f32.c) - zephyr_library_sources(${CMSIS_DSP_DIR}/Source/StatisticsFunctions/arm_kullback_leibler_f64.c) - zephyr_library_sources(${CMSIS_DSP_DIR}/Source/StatisticsFunctions/arm_logsumexp_dot_prod_f32.c) - zephyr_library_sources(${CMSIS_DSP_DIR}/Source/StatisticsFunctions/arm_logsumexp_f32.c) - zephyr_library_sources(${CMSIS_DSP_DIR}/Source/StatisticsFunctions/arm_max_f32.c) - zephyr_library_sources(${CMSIS_DSP_DIR}/Source/StatisticsFunctions/arm_max_f64.c) - zephyr_library_sources(${CMSIS_DSP_DIR}/Source/StatisticsFunctions/arm_max_no_idx_f32.c) - zephyr_library_sources(${CMSIS_DSP_DIR}/Source/StatisticsFunctions/arm_max_no_idx_f64.c) - zephyr_library_sources(${CMSIS_DSP_DIR}/Source/StatisticsFunctions/arm_min_no_idx_f32.c) - zephyr_library_sources(${CMSIS_DSP_DIR}/Source/StatisticsFunctions/arm_min_no_idx_f64.c) - zephyr_library_sources(${CMSIS_DSP_DIR}/Source/StatisticsFunctions/arm_max_q15.c) - zephyr_library_sources(${CMSIS_DSP_DIR}/Source/StatisticsFunctions/arm_max_q31.c) - zephyr_library_sources(${CMSIS_DSP_DIR}/Source/StatisticsFunctions/arm_max_q7.c) - zephyr_library_sources(${CMSIS_DSP_DIR}/Source/StatisticsFunctions/arm_max_no_idx_q31.c) - zephyr_library_sources(${CMSIS_DSP_DIR}/Source/StatisticsFunctions/arm_max_no_idx_q15.c) - zephyr_library_sources(${CMSIS_DSP_DIR}/Source/StatisticsFunctions/arm_max_no_idx_q7.c) - zephyr_library_sources(${CMSIS_DSP_DIR}/Source/StatisticsFunctions/arm_mean_f32.c) - zephyr_library_sources(${CMSIS_DSP_DIR}/Source/StatisticsFunctions/arm_mean_f64.c) - zephyr_library_sources(${CMSIS_DSP_DIR}/Source/StatisticsFunctions/arm_mean_q15.c) - zephyr_library_sources(${CMSIS_DSP_DIR}/Source/StatisticsFunctions/arm_mean_q31.c) - zephyr_library_sources(${CMSIS_DSP_DIR}/Source/StatisticsFunctions/arm_mean_q7.c) - zephyr_library_sources(${CMSIS_DSP_DIR}/Source/StatisticsFunctions/arm_min_f32.c) - zephyr_library_sources(${CMSIS_DSP_DIR}/Source/StatisticsFunctions/arm_min_f64.c) - zephyr_library_sources(${CMSIS_DSP_DIR}/Source/StatisticsFunctions/arm_min_q15.c) - zephyr_library_sources(${CMSIS_DSP_DIR}/Source/StatisticsFunctions/arm_min_q31.c) - zephyr_library_sources(${CMSIS_DSP_DIR}/Source/StatisticsFunctions/arm_min_q7.c) - zephyr_library_sources(${CMSIS_DSP_DIR}/Source/StatisticsFunctions/arm_min_no_idx_q31.c) - zephyr_library_sources(${CMSIS_DSP_DIR}/Source/StatisticsFunctions/arm_min_no_idx_q15.c) - zephyr_library_sources(${CMSIS_DSP_DIR}/Source/StatisticsFunctions/arm_min_no_idx_q7.c) - zephyr_library_sources(${CMSIS_DSP_DIR}/Source/StatisticsFunctions/arm_power_f32.c) - zephyr_library_sources(${CMSIS_DSP_DIR}/Source/StatisticsFunctions/arm_power_f64.c) - zephyr_library_sources(${CMSIS_DSP_DIR}/Source/StatisticsFunctions/arm_power_q15.c) - zephyr_library_sources(${CMSIS_DSP_DIR}/Source/StatisticsFunctions/arm_power_q31.c) - zephyr_library_sources(${CMSIS_DSP_DIR}/Source/StatisticsFunctions/arm_power_q7.c) - zephyr_library_sources(${CMSIS_DSP_DIR}/Source/StatisticsFunctions/arm_rms_f32.c) - zephyr_library_sources(${CMSIS_DSP_DIR}/Source/StatisticsFunctions/arm_rms_q15.c) - zephyr_library_sources(${CMSIS_DSP_DIR}/Source/StatisticsFunctions/arm_rms_q31.c) - zephyr_library_sources(${CMSIS_DSP_DIR}/Source/StatisticsFunctions/arm_std_f32.c) - zephyr_library_sources(${CMSIS_DSP_DIR}/Source/StatisticsFunctions/arm_std_f64.c) - zephyr_library_sources(${CMSIS_DSP_DIR}/Source/StatisticsFunctions/arm_std_q15.c) - zephyr_library_sources(${CMSIS_DSP_DIR}/Source/StatisticsFunctions/arm_std_q31.c) - zephyr_library_sources(${CMSIS_DSP_DIR}/Source/StatisticsFunctions/arm_var_f32.c) - zephyr_library_sources(${CMSIS_DSP_DIR}/Source/StatisticsFunctions/arm_var_f64.c) - zephyr_library_sources(${CMSIS_DSP_DIR}/Source/StatisticsFunctions/arm_var_q15.c) - zephyr_library_sources(${CMSIS_DSP_DIR}/Source/StatisticsFunctions/arm_var_q31.c) - - zephyr_library_sources(${CMSIS_DSP_DIR}/Source/StatisticsFunctions/arm_absmax_f32.c) - zephyr_library_sources(${CMSIS_DSP_DIR}/Source/StatisticsFunctions/arm_absmax_f64.c) - zephyr_library_sources(${CMSIS_DSP_DIR}/Source/StatisticsFunctions/arm_absmax_q15.c) - zephyr_library_sources(${CMSIS_DSP_DIR}/Source/StatisticsFunctions/arm_absmax_q31.c) - zephyr_library_sources(${CMSIS_DSP_DIR}/Source/StatisticsFunctions/arm_absmax_q7.c) - - zephyr_library_sources(${CMSIS_DSP_DIR}/Source/StatisticsFunctions/arm_absmin_f32.c) - zephyr_library_sources(${CMSIS_DSP_DIR}/Source/StatisticsFunctions/arm_absmin_f64.c) - zephyr_library_sources(${CMSIS_DSP_DIR}/Source/StatisticsFunctions/arm_absmin_q15.c) - zephyr_library_sources(${CMSIS_DSP_DIR}/Source/StatisticsFunctions/arm_absmin_q31.c) - zephyr_library_sources(${CMSIS_DSP_DIR}/Source/StatisticsFunctions/arm_absmin_q7.c) - - zephyr_library_sources(${CMSIS_DSP_DIR}/Source/StatisticsFunctions/arm_absmax_no_idx_f32.c) - zephyr_library_sources(${CMSIS_DSP_DIR}/Source/StatisticsFunctions/arm_absmax_no_idx_f64.c) - zephyr_library_sources(${CMSIS_DSP_DIR}/Source/StatisticsFunctions/arm_absmax_no_idx_q15.c) - zephyr_library_sources(${CMSIS_DSP_DIR}/Source/StatisticsFunctions/arm_absmax_no_idx_q31.c) - zephyr_library_sources(${CMSIS_DSP_DIR}/Source/StatisticsFunctions/arm_absmax_no_idx_q7.c) - - zephyr_library_sources(${CMSIS_DSP_DIR}/Source/StatisticsFunctions/arm_absmin_no_idx_f32.c) - zephyr_library_sources(${CMSIS_DSP_DIR}/Source/StatisticsFunctions/arm_absmin_no_idx_f64.c) - zephyr_library_sources(${CMSIS_DSP_DIR}/Source/StatisticsFunctions/arm_absmin_no_idx_q15.c) - zephyr_library_sources(${CMSIS_DSP_DIR}/Source/StatisticsFunctions/arm_absmin_no_idx_q31.c) - zephyr_library_sources(${CMSIS_DSP_DIR}/Source/StatisticsFunctions/arm_absmin_no_idx_q7.c) - zephyr_library_sources(${CMSIS_DSP_DIR}/Source/StatisticsFunctions/arm_mse_q7.c) - zephyr_library_sources(${CMSIS_DSP_DIR}/Source/StatisticsFunctions/arm_mse_q15.c) - zephyr_library_sources(${CMSIS_DSP_DIR}/Source/StatisticsFunctions/arm_mse_q31.c) - zephyr_library_sources(${CMSIS_DSP_DIR}/Source/StatisticsFunctions/arm_mse_f16.c) - zephyr_library_sources(${CMSIS_DSP_DIR}/Source/StatisticsFunctions/arm_mse_f32.c) - zephyr_library_sources(${CMSIS_DSP_DIR}/Source/StatisticsFunctions/arm_mse_f64.c) - zephyr_library_sources(${CMSIS_DSP_DIR}/Source/StatisticsFunctions/arm_accumulate_f64.c) - zephyr_library_sources(${CMSIS_DSP_DIR}/Source/StatisticsFunctions/arm_accumulate_f32.c) - - - if ((NOT ARMAC5) AND (NOT DISABLEFLOAT16)) - zephyr_library_sources(${CMSIS_DSP_DIR}/Source/StatisticsFunctions/arm_max_f16.c) - zephyr_library_sources(${CMSIS_DSP_DIR}/Source/StatisticsFunctions/arm_min_f16.c) - zephyr_library_sources(${CMSIS_DSP_DIR}/Source/StatisticsFunctions/arm_mean_f16.c) - zephyr_library_sources(${CMSIS_DSP_DIR}/Source/StatisticsFunctions/arm_power_f16.c) - zephyr_library_sources(${CMSIS_DSP_DIR}/Source/StatisticsFunctions/arm_rms_f16.c) - zephyr_library_sources(${CMSIS_DSP_DIR}/Source/StatisticsFunctions/arm_std_f16.c) - zephyr_library_sources(${CMSIS_DSP_DIR}/Source/StatisticsFunctions/arm_var_f16.c) - zephyr_library_sources(${CMSIS_DSP_DIR}/Source/StatisticsFunctions/arm_entropy_f16.c) - zephyr_library_sources(${CMSIS_DSP_DIR}/Source/StatisticsFunctions/arm_kullback_leibler_f16.c) - zephyr_library_sources(${CMSIS_DSP_DIR}/Source/StatisticsFunctions/arm_logsumexp_dot_prod_f16.c) - zephyr_library_sources(${CMSIS_DSP_DIR}/Source/StatisticsFunctions/arm_logsumexp_f16.c) - zephyr_library_sources(${CMSIS_DSP_DIR}/Source/StatisticsFunctions/arm_max_no_idx_f16.c) - zephyr_library_sources(${CMSIS_DSP_DIR}/Source/StatisticsFunctions/arm_min_no_idx_f16.c) - - zephyr_library_sources(${CMSIS_DSP_DIR}/Source/StatisticsFunctions/arm_absmax_f16.c) - zephyr_library_sources(${CMSIS_DSP_DIR}/Source/StatisticsFunctions/arm_absmin_f16.c) - zephyr_library_sources(${CMSIS_DSP_DIR}/Source/StatisticsFunctions/arm_absmax_no_idx_f16.c) - zephyr_library_sources(${CMSIS_DSP_DIR}/Source/StatisticsFunctions/arm_absmin_no_idx_f16.c) - zephyr_library_sources(${CMSIS_DSP_DIR}/Source/StatisticsFunctions/arm_accumulate_f16.c) + if (CONFIG_CMSIS_DSP_STATISTICS) + zephyr_library_sources(${CMSIS_DSP_DIR}/Source/StatisticsFunctions/arm_entropy_f32.c) + zephyr_library_sources(${CMSIS_DSP_DIR}/Source/StatisticsFunctions/arm_entropy_f64.c) + zephyr_library_sources(${CMSIS_DSP_DIR}/Source/StatisticsFunctions/arm_kullback_leibler_f32.c) + zephyr_library_sources(${CMSIS_DSP_DIR}/Source/StatisticsFunctions/arm_kullback_leibler_f64.c) + zephyr_library_sources(${CMSIS_DSP_DIR}/Source/StatisticsFunctions/arm_logsumexp_dot_prod_f32.c) + zephyr_library_sources(${CMSIS_DSP_DIR}/Source/StatisticsFunctions/arm_logsumexp_f32.c) + zephyr_library_sources(${CMSIS_DSP_DIR}/Source/StatisticsFunctions/arm_max_f32.c) + zephyr_library_sources(${CMSIS_DSP_DIR}/Source/StatisticsFunctions/arm_max_f64.c) + zephyr_library_sources(${CMSIS_DSP_DIR}/Source/StatisticsFunctions/arm_max_no_idx_f32.c) + zephyr_library_sources(${CMSIS_DSP_DIR}/Source/StatisticsFunctions/arm_max_no_idx_f64.c) + zephyr_library_sources(${CMSIS_DSP_DIR}/Source/StatisticsFunctions/arm_min_no_idx_f32.c) + zephyr_library_sources(${CMSIS_DSP_DIR}/Source/StatisticsFunctions/arm_min_no_idx_f64.c) + zephyr_library_sources(${CMSIS_DSP_DIR}/Source/StatisticsFunctions/arm_max_q15.c) + zephyr_library_sources(${CMSIS_DSP_DIR}/Source/StatisticsFunctions/arm_max_q31.c) + zephyr_library_sources(${CMSIS_DSP_DIR}/Source/StatisticsFunctions/arm_max_q7.c) + zephyr_library_sources(${CMSIS_DSP_DIR}/Source/StatisticsFunctions/arm_max_no_idx_q31.c) + zephyr_library_sources(${CMSIS_DSP_DIR}/Source/StatisticsFunctions/arm_max_no_idx_q15.c) + zephyr_library_sources(${CMSIS_DSP_DIR}/Source/StatisticsFunctions/arm_max_no_idx_q7.c) + zephyr_library_sources(${CMSIS_DSP_DIR}/Source/StatisticsFunctions/arm_mean_f32.c) + zephyr_library_sources(${CMSIS_DSP_DIR}/Source/StatisticsFunctions/arm_mean_f64.c) + zephyr_library_sources(${CMSIS_DSP_DIR}/Source/StatisticsFunctions/arm_mean_q15.c) + zephyr_library_sources(${CMSIS_DSP_DIR}/Source/StatisticsFunctions/arm_mean_q31.c) + zephyr_library_sources(${CMSIS_DSP_DIR}/Source/StatisticsFunctions/arm_mean_q7.c) + zephyr_library_sources(${CMSIS_DSP_DIR}/Source/StatisticsFunctions/arm_min_f32.c) + zephyr_library_sources(${CMSIS_DSP_DIR}/Source/StatisticsFunctions/arm_min_f64.c) + zephyr_library_sources(${CMSIS_DSP_DIR}/Source/StatisticsFunctions/arm_min_q15.c) + zephyr_library_sources(${CMSIS_DSP_DIR}/Source/StatisticsFunctions/arm_min_q31.c) + zephyr_library_sources(${CMSIS_DSP_DIR}/Source/StatisticsFunctions/arm_min_q7.c) + zephyr_library_sources(${CMSIS_DSP_DIR}/Source/StatisticsFunctions/arm_min_no_idx_q31.c) + zephyr_library_sources(${CMSIS_DSP_DIR}/Source/StatisticsFunctions/arm_min_no_idx_q15.c) + zephyr_library_sources(${CMSIS_DSP_DIR}/Source/StatisticsFunctions/arm_min_no_idx_q7.c) + zephyr_library_sources(${CMSIS_DSP_DIR}/Source/StatisticsFunctions/arm_power_f32.c) + zephyr_library_sources(${CMSIS_DSP_DIR}/Source/StatisticsFunctions/arm_power_f64.c) + zephyr_library_sources(${CMSIS_DSP_DIR}/Source/StatisticsFunctions/arm_power_q15.c) + zephyr_library_sources(${CMSIS_DSP_DIR}/Source/StatisticsFunctions/arm_power_q31.c) + zephyr_library_sources(${CMSIS_DSP_DIR}/Source/StatisticsFunctions/arm_power_q7.c) + zephyr_library_sources(${CMSIS_DSP_DIR}/Source/StatisticsFunctions/arm_rms_f32.c) + zephyr_library_sources(${CMSIS_DSP_DIR}/Source/StatisticsFunctions/arm_rms_q15.c) + zephyr_library_sources(${CMSIS_DSP_DIR}/Source/StatisticsFunctions/arm_rms_q31.c) + zephyr_library_sources(${CMSIS_DSP_DIR}/Source/StatisticsFunctions/arm_std_f32.c) + zephyr_library_sources(${CMSIS_DSP_DIR}/Source/StatisticsFunctions/arm_std_f64.c) + zephyr_library_sources(${CMSIS_DSP_DIR}/Source/StatisticsFunctions/arm_std_q15.c) + zephyr_library_sources(${CMSIS_DSP_DIR}/Source/StatisticsFunctions/arm_std_q31.c) + zephyr_library_sources(${CMSIS_DSP_DIR}/Source/StatisticsFunctions/arm_var_f32.c) + zephyr_library_sources(${CMSIS_DSP_DIR}/Source/StatisticsFunctions/arm_var_f64.c) + zephyr_library_sources(${CMSIS_DSP_DIR}/Source/StatisticsFunctions/arm_var_q15.c) + zephyr_library_sources(${CMSIS_DSP_DIR}/Source/StatisticsFunctions/arm_var_q31.c) + + zephyr_library_sources(${CMSIS_DSP_DIR}/Source/StatisticsFunctions/arm_absmax_f32.c) + zephyr_library_sources(${CMSIS_DSP_DIR}/Source/StatisticsFunctions/arm_absmax_f64.c) + zephyr_library_sources(${CMSIS_DSP_DIR}/Source/StatisticsFunctions/arm_absmax_q15.c) + zephyr_library_sources(${CMSIS_DSP_DIR}/Source/StatisticsFunctions/arm_absmax_q31.c) + zephyr_library_sources(${CMSIS_DSP_DIR}/Source/StatisticsFunctions/arm_absmax_q7.c) + + zephyr_library_sources(${CMSIS_DSP_DIR}/Source/StatisticsFunctions/arm_absmin_f32.c) + zephyr_library_sources(${CMSIS_DSP_DIR}/Source/StatisticsFunctions/arm_absmin_f64.c) + zephyr_library_sources(${CMSIS_DSP_DIR}/Source/StatisticsFunctions/arm_absmin_q15.c) + zephyr_library_sources(${CMSIS_DSP_DIR}/Source/StatisticsFunctions/arm_absmin_q31.c) + zephyr_library_sources(${CMSIS_DSP_DIR}/Source/StatisticsFunctions/arm_absmin_q7.c) + + zephyr_library_sources(${CMSIS_DSP_DIR}/Source/StatisticsFunctions/arm_absmax_no_idx_f32.c) + zephyr_library_sources(${CMSIS_DSP_DIR}/Source/StatisticsFunctions/arm_absmax_no_idx_f64.c) + zephyr_library_sources(${CMSIS_DSP_DIR}/Source/StatisticsFunctions/arm_absmax_no_idx_q15.c) + zephyr_library_sources(${CMSIS_DSP_DIR}/Source/StatisticsFunctions/arm_absmax_no_idx_q31.c) + zephyr_library_sources(${CMSIS_DSP_DIR}/Source/StatisticsFunctions/arm_absmax_no_idx_q7.c) + + zephyr_library_sources(${CMSIS_DSP_DIR}/Source/StatisticsFunctions/arm_absmin_no_idx_f32.c) + zephyr_library_sources(${CMSIS_DSP_DIR}/Source/StatisticsFunctions/arm_absmin_no_idx_f64.c) + zephyr_library_sources(${CMSIS_DSP_DIR}/Source/StatisticsFunctions/arm_absmin_no_idx_q15.c) + zephyr_library_sources(${CMSIS_DSP_DIR}/Source/StatisticsFunctions/arm_absmin_no_idx_q31.c) + zephyr_library_sources(${CMSIS_DSP_DIR}/Source/StatisticsFunctions/arm_absmin_no_idx_q7.c) + zephyr_library_sources(${CMSIS_DSP_DIR}/Source/StatisticsFunctions/arm_mse_q7.c) + zephyr_library_sources(${CMSIS_DSP_DIR}/Source/StatisticsFunctions/arm_mse_q15.c) + zephyr_library_sources(${CMSIS_DSP_DIR}/Source/StatisticsFunctions/arm_mse_q31.c) + zephyr_library_sources(${CMSIS_DSP_DIR}/Source/StatisticsFunctions/arm_mse_f16.c) + zephyr_library_sources(${CMSIS_DSP_DIR}/Source/StatisticsFunctions/arm_mse_f32.c) + zephyr_library_sources(${CMSIS_DSP_DIR}/Source/StatisticsFunctions/arm_mse_f64.c) + zephyr_library_sources(${CMSIS_DSP_DIR}/Source/StatisticsFunctions/arm_accumulate_f64.c) + zephyr_library_sources(${CMSIS_DSP_DIR}/Source/StatisticsFunctions/arm_accumulate_f32.c) + + + if ((NOT ARMAC5) AND (NOT DISABLEFLOAT16)) + zephyr_library_sources(${CMSIS_DSP_DIR}/Source/StatisticsFunctions/arm_max_f16.c) + zephyr_library_sources(${CMSIS_DSP_DIR}/Source/StatisticsFunctions/arm_min_f16.c) + zephyr_library_sources(${CMSIS_DSP_DIR}/Source/StatisticsFunctions/arm_mean_f16.c) + zephyr_library_sources(${CMSIS_DSP_DIR}/Source/StatisticsFunctions/arm_power_f16.c) + zephyr_library_sources(${CMSIS_DSP_DIR}/Source/StatisticsFunctions/arm_rms_f16.c) + zephyr_library_sources(${CMSIS_DSP_DIR}/Source/StatisticsFunctions/arm_std_f16.c) + zephyr_library_sources(${CMSIS_DSP_DIR}/Source/StatisticsFunctions/arm_var_f16.c) + zephyr_library_sources(${CMSIS_DSP_DIR}/Source/StatisticsFunctions/arm_entropy_f16.c) + zephyr_library_sources(${CMSIS_DSP_DIR}/Source/StatisticsFunctions/arm_kullback_leibler_f16.c) + zephyr_library_sources(${CMSIS_DSP_DIR}/Source/StatisticsFunctions/arm_logsumexp_dot_prod_f16.c) + zephyr_library_sources(${CMSIS_DSP_DIR}/Source/StatisticsFunctions/arm_logsumexp_f16.c) + zephyr_library_sources(${CMSIS_DSP_DIR}/Source/StatisticsFunctions/arm_max_no_idx_f16.c) + zephyr_library_sources(${CMSIS_DSP_DIR}/Source/StatisticsFunctions/arm_min_no_idx_f16.c) + + zephyr_library_sources(${CMSIS_DSP_DIR}/Source/StatisticsFunctions/arm_absmax_f16.c) + zephyr_library_sources(${CMSIS_DSP_DIR}/Source/StatisticsFunctions/arm_absmin_f16.c) + zephyr_library_sources(${CMSIS_DSP_DIR}/Source/StatisticsFunctions/arm_absmax_no_idx_f16.c) + zephyr_library_sources(${CMSIS_DSP_DIR}/Source/StatisticsFunctions/arm_absmin_no_idx_f16.c) + zephyr_library_sources(${CMSIS_DSP_DIR}/Source/StatisticsFunctions/arm_accumulate_f16.c) + endif() endif() # Support Functions - zephyr_library_sources(${CMSIS_DSP_DIR}/Source/SupportFunctions/arm_barycenter_f32.c - ${CMSIS_DSP_DIR}/Source/SupportFunctions/arm_bitonic_sort_f32.c - ${CMSIS_DSP_DIR}/Source/SupportFunctions/arm_bubble_sort_f32.c - ${CMSIS_DSP_DIR}/Source/SupportFunctions/arm_copy_f32.c - ${CMSIS_DSP_DIR}/Source/SupportFunctions/arm_copy_f64.c - ${CMSIS_DSP_DIR}/Source/SupportFunctions/arm_copy_q15.c - ${CMSIS_DSP_DIR}/Source/SupportFunctions/arm_copy_q31.c - ${CMSIS_DSP_DIR}/Source/SupportFunctions/arm_copy_q7.c - ${CMSIS_DSP_DIR}/Source/SupportFunctions/arm_f16_to_float.c - ${CMSIS_DSP_DIR}/Source/SupportFunctions/arm_f16_to_q15.c - ${CMSIS_DSP_DIR}/Source/SupportFunctions/arm_fill_f32.c - ${CMSIS_DSP_DIR}/Source/SupportFunctions/arm_fill_f64.c - ${CMSIS_DSP_DIR}/Source/SupportFunctions/arm_fill_q15.c - ${CMSIS_DSP_DIR}/Source/SupportFunctions/arm_fill_q31.c - ${CMSIS_DSP_DIR}/Source/SupportFunctions/arm_fill_q7.c - ${CMSIS_DSP_DIR}/Source/SupportFunctions/arm_f64_to_float.c - ${CMSIS_DSP_DIR}/Source/SupportFunctions/arm_f64_to_q31.c - ${CMSIS_DSP_DIR}/Source/SupportFunctions/arm_f64_to_q15.c - ${CMSIS_DSP_DIR}/Source/SupportFunctions/arm_f64_to_q7.c - ${CMSIS_DSP_DIR}/Source/SupportFunctions/arm_float_to_f64.c - ${CMSIS_DSP_DIR}/Source/SupportFunctions/arm_float_to_q15.c - ${CMSIS_DSP_DIR}/Source/SupportFunctions/arm_float_to_q31.c - ${CMSIS_DSP_DIR}/Source/SupportFunctions/arm_float_to_q7.c - ${CMSIS_DSP_DIR}/Source/SupportFunctions/arm_heap_sort_f32.c - ${CMSIS_DSP_DIR}/Source/SupportFunctions/arm_insertion_sort_f32.c - ${CMSIS_DSP_DIR}/Source/SupportFunctions/arm_merge_sort_f32.c - ${CMSIS_DSP_DIR}/Source/SupportFunctions/arm_merge_sort_init_f32.c - ${CMSIS_DSP_DIR}/Source/SupportFunctions/arm_q15_to_f64.c - ${CMSIS_DSP_DIR}/Source/SupportFunctions/arm_q15_to_float.c - ${CMSIS_DSP_DIR}/Source/SupportFunctions/arm_q15_to_q31.c - ${CMSIS_DSP_DIR}/Source/SupportFunctions/arm_q15_to_q7.c - ${CMSIS_DSP_DIR}/Source/SupportFunctions/arm_q31_to_f64.c - ${CMSIS_DSP_DIR}/Source/SupportFunctions/arm_q31_to_float.c - ${CMSIS_DSP_DIR}/Source/SupportFunctions/arm_q31_to_q15.c - ${CMSIS_DSP_DIR}/Source/SupportFunctions/arm_q31_to_q7.c - ${CMSIS_DSP_DIR}/Source/SupportFunctions/arm_q7_to_f64.c - ${CMSIS_DSP_DIR}/Source/SupportFunctions/arm_q7_to_float.c - ${CMSIS_DSP_DIR}/Source/SupportFunctions/arm_q7_to_q15.c - ${CMSIS_DSP_DIR}/Source/SupportFunctions/arm_q7_to_q31.c - ${CMSIS_DSP_DIR}/Source/SupportFunctions/arm_quick_sort_f32.c - ${CMSIS_DSP_DIR}/Source/SupportFunctions/arm_selection_sort_f32.c - ${CMSIS_DSP_DIR}/Source/SupportFunctions/arm_sort_f32.c - ${CMSIS_DSP_DIR}/Source/SupportFunctions/arm_sort_init_f32.c - ${CMSIS_DSP_DIR}/Source/SupportFunctions/arm_weighted_sum_f32.c - ) + if (CONFIG_CMSIS_DSP_SUPPORT) + zephyr_library_sources(${CMSIS_DSP_DIR}/Source/SupportFunctions/arm_barycenter_f32.c + ${CMSIS_DSP_DIR}/Source/SupportFunctions/arm_bitonic_sort_f32.c + ${CMSIS_DSP_DIR}/Source/SupportFunctions/arm_bubble_sort_f32.c + ${CMSIS_DSP_DIR}/Source/SupportFunctions/arm_copy_f32.c + ${CMSIS_DSP_DIR}/Source/SupportFunctions/arm_copy_f64.c + ${CMSIS_DSP_DIR}/Source/SupportFunctions/arm_copy_q15.c + ${CMSIS_DSP_DIR}/Source/SupportFunctions/arm_copy_q31.c + ${CMSIS_DSP_DIR}/Source/SupportFunctions/arm_copy_q7.c + ${CMSIS_DSP_DIR}/Source/SupportFunctions/arm_f16_to_float.c + ${CMSIS_DSP_DIR}/Source/SupportFunctions/arm_f16_to_q15.c + ${CMSIS_DSP_DIR}/Source/SupportFunctions/arm_fill_f32.c + ${CMSIS_DSP_DIR}/Source/SupportFunctions/arm_fill_f64.c + ${CMSIS_DSP_DIR}/Source/SupportFunctions/arm_fill_q15.c + ${CMSIS_DSP_DIR}/Source/SupportFunctions/arm_fill_q31.c + ${CMSIS_DSP_DIR}/Source/SupportFunctions/arm_fill_q7.c + ${CMSIS_DSP_DIR}/Source/SupportFunctions/arm_f64_to_float.c + ${CMSIS_DSP_DIR}/Source/SupportFunctions/arm_f64_to_q31.c + ${CMSIS_DSP_DIR}/Source/SupportFunctions/arm_f64_to_q15.c + ${CMSIS_DSP_DIR}/Source/SupportFunctions/arm_f64_to_q7.c + ${CMSIS_DSP_DIR}/Source/SupportFunctions/arm_float_to_f64.c + ${CMSIS_DSP_DIR}/Source/SupportFunctions/arm_float_to_q15.c + ${CMSIS_DSP_DIR}/Source/SupportFunctions/arm_float_to_q31.c + ${CMSIS_DSP_DIR}/Source/SupportFunctions/arm_float_to_q7.c + ${CMSIS_DSP_DIR}/Source/SupportFunctions/arm_heap_sort_f32.c + ${CMSIS_DSP_DIR}/Source/SupportFunctions/arm_insertion_sort_f32.c + ${CMSIS_DSP_DIR}/Source/SupportFunctions/arm_merge_sort_f32.c + ${CMSIS_DSP_DIR}/Source/SupportFunctions/arm_merge_sort_init_f32.c + ${CMSIS_DSP_DIR}/Source/SupportFunctions/arm_q15_to_f64.c + ${CMSIS_DSP_DIR}/Source/SupportFunctions/arm_q15_to_float.c + ${CMSIS_DSP_DIR}/Source/SupportFunctions/arm_q15_to_q31.c + ${CMSIS_DSP_DIR}/Source/SupportFunctions/arm_q15_to_q7.c + ${CMSIS_DSP_DIR}/Source/SupportFunctions/arm_q31_to_f64.c + ${CMSIS_DSP_DIR}/Source/SupportFunctions/arm_q31_to_float.c + ${CMSIS_DSP_DIR}/Source/SupportFunctions/arm_q31_to_q15.c + ${CMSIS_DSP_DIR}/Source/SupportFunctions/arm_q31_to_q7.c + ${CMSIS_DSP_DIR}/Source/SupportFunctions/arm_q7_to_f64.c + ${CMSIS_DSP_DIR}/Source/SupportFunctions/arm_q7_to_float.c + ${CMSIS_DSP_DIR}/Source/SupportFunctions/arm_q7_to_q15.c + ${CMSIS_DSP_DIR}/Source/SupportFunctions/arm_q7_to_q31.c + ${CMSIS_DSP_DIR}/Source/SupportFunctions/arm_quick_sort_f32.c + ${CMSIS_DSP_DIR}/Source/SupportFunctions/arm_selection_sort_f32.c + ${CMSIS_DSP_DIR}/Source/SupportFunctions/arm_sort_f32.c + ${CMSIS_DSP_DIR}/Source/SupportFunctions/arm_sort_init_f32.c + ${CMSIS_DSP_DIR}/Source/SupportFunctions/arm_weighted_sum_f32.c + ) - if ((NOT ARMAC5) AND (NOT DISABLEFLOAT16)) - zephyr_library_sources(${CMSIS_DSP_DIR}/Source/SupportFunctions/arm_copy_f16.c) - zephyr_library_sources(${CMSIS_DSP_DIR}/Source/SupportFunctions/arm_fill_f16.c) - zephyr_library_sources(${CMSIS_DSP_DIR}/Source/SupportFunctions/arm_f16_to_q15.c) - zephyr_library_sources(${CMSIS_DSP_DIR}/Source/SupportFunctions/arm_q15_to_f16.c) - zephyr_library_sources(${CMSIS_DSP_DIR}/Source/SupportFunctions/arm_float_to_f16.c) - zephyr_library_sources(${CMSIS_DSP_DIR}/Source/SupportFunctions/arm_f16_to_float.c) - zephyr_library_sources(${CMSIS_DSP_DIR}/Source/SupportFunctions/arm_weighted_sum_f16.c) - zephyr_library_sources(${CMSIS_DSP_DIR}/Source/SupportFunctions/arm_barycenter_f16.c) - zephyr_library_sources(${CMSIS_DSP_DIR}/Source/SupportFunctions/arm_f16_to_f64.c) - zephyr_library_sources(${CMSIS_DSP_DIR}/Source/SupportFunctions/arm_f64_to_f16.c) + if ((NOT ARMAC5) AND (NOT DISABLEFLOAT16)) + zephyr_library_sources(${CMSIS_DSP_DIR}/Source/SupportFunctions/arm_copy_f16.c) + zephyr_library_sources(${CMSIS_DSP_DIR}/Source/SupportFunctions/arm_fill_f16.c) + zephyr_library_sources(${CMSIS_DSP_DIR}/Source/SupportFunctions/arm_f16_to_q15.c) + zephyr_library_sources(${CMSIS_DSP_DIR}/Source/SupportFunctions/arm_q15_to_f16.c) + zephyr_library_sources(${CMSIS_DSP_DIR}/Source/SupportFunctions/arm_float_to_f16.c) + zephyr_library_sources(${CMSIS_DSP_DIR}/Source/SupportFunctions/arm_f16_to_float.c) + zephyr_library_sources(${CMSIS_DSP_DIR}/Source/SupportFunctions/arm_weighted_sum_f16.c) + zephyr_library_sources(${CMSIS_DSP_DIR}/Source/SupportFunctions/arm_barycenter_f16.c) + zephyr_library_sources(${CMSIS_DSP_DIR}/Source/SupportFunctions/arm_f16_to_f64.c) + zephyr_library_sources(${CMSIS_DSP_DIR}/Source/SupportFunctions/arm_f64_to_f16.c) + endif() endif() # SVM Functions - zephyr_library_sources(${CMSIS_DSP_DIR}/Source/SVMFunctions/arm_svm_linear_init_f32.c) - zephyr_library_sources(${CMSIS_DSP_DIR}/Source/SVMFunctions/arm_svm_rbf_init_f32.c) - zephyr_library_sources(${CMSIS_DSP_DIR}/Source/SVMFunctions/arm_svm_linear_predict_f32.c) - zephyr_library_sources(${CMSIS_DSP_DIR}/Source/SVMFunctions/arm_svm_rbf_predict_f32.c) - zephyr_library_sources(${CMSIS_DSP_DIR}/Source/SVMFunctions/arm_svm_polynomial_init_f32.c) - zephyr_library_sources(${CMSIS_DSP_DIR}/Source/SVMFunctions/arm_svm_sigmoid_init_f32.c) - zephyr_library_sources(${CMSIS_DSP_DIR}/Source/SVMFunctions/arm_svm_polynomial_predict_f32.c) - zephyr_library_sources(${CMSIS_DSP_DIR}/Source/SVMFunctions/arm_svm_sigmoid_predict_f32.c) - - if ((NOT ARMAC5) AND (NOT DISABLEFLOAT16)) - zephyr_library_sources(${CMSIS_DSP_DIR}/Source/SVMFunctions/arm_svm_linear_init_f16.c) - zephyr_library_sources(${CMSIS_DSP_DIR}/Source/SVMFunctions/arm_svm_rbf_init_f16.c) - zephyr_library_sources(${CMSIS_DSP_DIR}/Source/SVMFunctions/arm_svm_linear_predict_f16.c) - zephyr_library_sources(${CMSIS_DSP_DIR}/Source/SVMFunctions/arm_svm_rbf_predict_f16.c) - zephyr_library_sources(${CMSIS_DSP_DIR}/Source/SVMFunctions/arm_svm_polynomial_init_f16.c) - zephyr_library_sources(${CMSIS_DSP_DIR}/Source/SVMFunctions/arm_svm_sigmoid_init_f16.c) - zephyr_library_sources(${CMSIS_DSP_DIR}/Source/SVMFunctions/arm_svm_polynomial_predict_f16.c) - zephyr_library_sources(${CMSIS_DSP_DIR}/Source/SVMFunctions/arm_svm_sigmoid_predict_f16.c) + if (CONFIG_CMSIS_DSP_SVM) + zephyr_library_sources(${CMSIS_DSP_DIR}/Source/SVMFunctions/arm_svm_linear_init_f32.c) + zephyr_library_sources(${CMSIS_DSP_DIR}/Source/SVMFunctions/arm_svm_rbf_init_f32.c) + zephyr_library_sources(${CMSIS_DSP_DIR}/Source/SVMFunctions/arm_svm_linear_predict_f32.c) + zephyr_library_sources(${CMSIS_DSP_DIR}/Source/SVMFunctions/arm_svm_rbf_predict_f32.c) + zephyr_library_sources(${CMSIS_DSP_DIR}/Source/SVMFunctions/arm_svm_polynomial_init_f32.c) + zephyr_library_sources(${CMSIS_DSP_DIR}/Source/SVMFunctions/arm_svm_sigmoid_init_f32.c) + zephyr_library_sources(${CMSIS_DSP_DIR}/Source/SVMFunctions/arm_svm_polynomial_predict_f32.c) + zephyr_library_sources(${CMSIS_DSP_DIR}/Source/SVMFunctions/arm_svm_sigmoid_predict_f32.c) + + if ((NOT ARMAC5) AND (NOT DISABLEFLOAT16)) + zephyr_library_sources(${CMSIS_DSP_DIR}/Source/SVMFunctions/arm_svm_linear_init_f16.c) + zephyr_library_sources(${CMSIS_DSP_DIR}/Source/SVMFunctions/arm_svm_rbf_init_f16.c) + zephyr_library_sources(${CMSIS_DSP_DIR}/Source/SVMFunctions/arm_svm_linear_predict_f16.c) + zephyr_library_sources(${CMSIS_DSP_DIR}/Source/SVMFunctions/arm_svm_rbf_predict_f16.c) + zephyr_library_sources(${CMSIS_DSP_DIR}/Source/SVMFunctions/arm_svm_polynomial_init_f16.c) + zephyr_library_sources(${CMSIS_DSP_DIR}/Source/SVMFunctions/arm_svm_sigmoid_init_f16.c) + zephyr_library_sources(${CMSIS_DSP_DIR}/Source/SVMFunctions/arm_svm_polynomial_predict_f16.c) + zephyr_library_sources(${CMSIS_DSP_DIR}/Source/SVMFunctions/arm_svm_sigmoid_predict_f16.c) + endif() endif() # Transform Functions - zephyr_library_sources(${CMSIS_DSP_DIR}/Source/TransformFunctions/arm_bitreversal.c) - zephyr_library_sources(${CMSIS_DSP_DIR}/Source/TransformFunctions/arm_bitreversal2.c) + if (CONFIG_CMSIS_DSP_TRANSFORM) + zephyr_library_sources(${CMSIS_DSP_DIR}/Source/TransformFunctions/arm_bitreversal.c) + zephyr_library_sources(${CMSIS_DSP_DIR}/Source/TransformFunctions/arm_bitreversal2.c) - if ((NOT ARMAC5) AND (NOT DISABLEFLOAT16)) - zephyr_library_sources(${CMSIS_DSP_DIR}/Source/TransformFunctions/arm_bitreversal_f16.c) - endif() + if ((NOT ARMAC5) AND (NOT DISABLEFLOAT16)) + zephyr_library_sources(${CMSIS_DSP_DIR}/Source/TransformFunctions/arm_bitreversal_f16.c) + endif() - zephyr_library_sources(${CMSIS_DSP_DIR}/Source/TransformFunctions/arm_cfft_radix2_f32.c) - zephyr_library_sources(${CMSIS_DSP_DIR}/Source/TransformFunctions/arm_cfft_radix4_f32.c) - zephyr_library_sources(${CMSIS_DSP_DIR}/Source/TransformFunctions/arm_cfft_radix8_f32.c) - zephyr_library_sources(${CMSIS_DSP_DIR}/Source/TransformFunctions/arm_cfft_f32.c) - zephyr_library_sources(${CMSIS_DSP_DIR}/Source/TransformFunctions/arm_cfft_init_f32.c) - - if ((NOT ARMAC5) AND (NOT DISABLEFLOAT16)) - zephyr_library_sources(${CMSIS_DSP_DIR}/Source/TransformFunctions/arm_cfft_radix2_f16.c) - zephyr_library_sources(${CMSIS_DSP_DIR}/Source/TransformFunctions/arm_cfft_radix4_f16.c) - zephyr_library_sources(${CMSIS_DSP_DIR}/Source/TransformFunctions/arm_cfft_f16.c) - zephyr_library_sources(${CMSIS_DSP_DIR}/Source/TransformFunctions/arm_cfft_init_f16.c) - endif() + zephyr_library_sources(${CMSIS_DSP_DIR}/Source/TransformFunctions/arm_cfft_radix2_f32.c) + zephyr_library_sources(${CMSIS_DSP_DIR}/Source/TransformFunctions/arm_cfft_radix4_f32.c) + zephyr_library_sources(${CMSIS_DSP_DIR}/Source/TransformFunctions/arm_cfft_radix8_f32.c) + zephyr_library_sources(${CMSIS_DSP_DIR}/Source/TransformFunctions/arm_cfft_f32.c) + zephyr_library_sources(${CMSIS_DSP_DIR}/Source/TransformFunctions/arm_cfft_init_f32.c) - if ((NOT ARMAC5) AND (NOT DISABLEFLOAT16)) - zephyr_library_sources(${CMSIS_DSP_DIR}/Source/TransformFunctions/arm_cfft_radix4_init_f16.c) - zephyr_library_sources(${CMSIS_DSP_DIR}/Source/TransformFunctions/arm_cfft_radix4_f16.c) - endif() + if ((NOT ARMAC5) AND (NOT DISABLEFLOAT16)) + zephyr_library_sources(${CMSIS_DSP_DIR}/Source/TransformFunctions/arm_cfft_radix2_f16.c) + zephyr_library_sources(${CMSIS_DSP_DIR}/Source/TransformFunctions/arm_cfft_radix4_f16.c) + zephyr_library_sources(${CMSIS_DSP_DIR}/Source/TransformFunctions/arm_cfft_f16.c) + zephyr_library_sources(${CMSIS_DSP_DIR}/Source/TransformFunctions/arm_cfft_init_f16.c) + endif() - zephyr_library_sources(${CMSIS_DSP_DIR}/Source/TransformFunctions/arm_cfft_f64.c) - zephyr_library_sources(${CMSIS_DSP_DIR}/Source/TransformFunctions/arm_cfft_init_f64.c) - - zephyr_library_sources(${CMSIS_DSP_DIR}/Source/TransformFunctions/arm_cfft_radix2_q15.c) - zephyr_library_sources(${CMSIS_DSP_DIR}/Source/TransformFunctions/arm_cfft_radix4_q15.c) - zephyr_library_sources(${CMSIS_DSP_DIR}/Source/TransformFunctions/arm_cfft_q15.c) - zephyr_library_sources(${CMSIS_DSP_DIR}/Source/TransformFunctions/arm_cfft_init_q15.c) - - zephyr_library_sources(${CMSIS_DSP_DIR}/Source/TransformFunctions/arm_cfft_radix2_q31.c) - zephyr_library_sources(${CMSIS_DSP_DIR}/Source/TransformFunctions/arm_cfft_radix4_q31.c) - zephyr_library_sources(${CMSIS_DSP_DIR}/Source/TransformFunctions/arm_cfft_q31.c) - zephyr_library_sources(${CMSIS_DSP_DIR}/Source/TransformFunctions/arm_cfft_init_q31.c) - - - zephyr_library_sources(${CMSIS_DSP_DIR}/Source/TransformFunctions/arm_dct4_f32.c) - zephyr_library_sources(${CMSIS_DSP_DIR}/Source/TransformFunctions/arm_dct4_init_f32.c) - - zephyr_library_sources(${CMSIS_DSP_DIR}/Source/TransformFunctions/arm_rfft_init_f32.c) - zephyr_library_sources(${CMSIS_DSP_DIR}/Source/TransformFunctions/arm_rfft_f32.c) - zephyr_library_sources(${CMSIS_DSP_DIR}/Source/TransformFunctions/arm_cfft_radix4_init_f32.c) - zephyr_library_sources(${CMSIS_DSP_DIR}/Source/TransformFunctions/arm_cfft_radix4_f32.c) - - zephyr_library_sources(${CMSIS_DSP_DIR}/Source/TransformFunctions/arm_dct4_q31.c) - zephyr_library_sources(${CMSIS_DSP_DIR}/Source/TransformFunctions/arm_dct4_init_q31.c) - - zephyr_library_sources(${CMSIS_DSP_DIR}/Source/TransformFunctions/arm_rfft_init_q31.c) - zephyr_library_sources(${CMSIS_DSP_DIR}/Source/TransformFunctions/arm_rfft_q31.c) - zephyr_library_sources(${CMSIS_DSP_DIR}/Source/TransformFunctions/arm_cfft_q31.c) - zephyr_library_sources(${CMSIS_DSP_DIR}/Source/TransformFunctions/arm_cfft_init_q31.c) - zephyr_library_sources(${CMSIS_DSP_DIR}/Source/TransformFunctions/arm_cfft_radix4_init_q31.c) - zephyr_library_sources(${CMSIS_DSP_DIR}/Source/TransformFunctions/arm_cfft_radix4_q31.c) - - zephyr_library_sources(${CMSIS_DSP_DIR}/Source/TransformFunctions/arm_dct4_init_q15.c) - zephyr_library_sources(${CMSIS_DSP_DIR}/Source/TransformFunctions/arm_dct4_q15.c) - - zephyr_library_sources(${CMSIS_DSP_DIR}/Source/TransformFunctions/arm_rfft_init_q15.c) - zephyr_library_sources(${CMSIS_DSP_DIR}/Source/TransformFunctions/arm_rfft_q15.c) - zephyr_library_sources(${CMSIS_DSP_DIR}/Source/TransformFunctions/arm_cfft_q15.c) - zephyr_library_sources(${CMSIS_DSP_DIR}/Source/TransformFunctions/arm_cfft_init_q15.c) - zephyr_library_sources(${CMSIS_DSP_DIR}/Source/TransformFunctions/arm_cfft_radix4_init_q15.c) - zephyr_library_sources(${CMSIS_DSP_DIR}/Source/TransformFunctions/arm_cfft_radix4_q15.c) - - zephyr_library_sources(${CMSIS_DSP_DIR}/Source/TransformFunctions/arm_rfft_fast_f32.c) - zephyr_library_sources(${CMSIS_DSP_DIR}/Source/TransformFunctions/arm_rfft_fast_init_f32.c) - zephyr_library_sources(${CMSIS_DSP_DIR}/Source/TransformFunctions/arm_cfft_f32.c) - zephyr_library_sources(${CMSIS_DSP_DIR}/Source/TransformFunctions/arm_cfft_init_f32.c) - zephyr_library_sources(${CMSIS_DSP_DIR}/Source/TransformFunctions/arm_cfft_radix8_f32.c) - - zephyr_library_sources(${CMSIS_DSP_DIR}/Source/TransformFunctions/arm_rfft_fast_f64.c) - zephyr_library_sources(${CMSIS_DSP_DIR}/Source/TransformFunctions/arm_rfft_fast_init_f64.c) - - if ((NOT ARMAC5) AND (NOT DISABLEFLOAT16)) - zephyr_library_sources(${CMSIS_DSP_DIR}/Source/TransformFunctions/arm_rfft_fast_f16.c) - zephyr_library_sources(${CMSIS_DSP_DIR}/Source/TransformFunctions/arm_rfft_fast_init_f16.c) - zephyr_library_sources(${CMSIS_DSP_DIR}/Source/TransformFunctions/arm_cfft_f16.c) - zephyr_library_sources(${CMSIS_DSP_DIR}/Source/TransformFunctions/arm_cfft_init_f16.c) - zephyr_library_sources(${CMSIS_DSP_DIR}/Source/TransformFunctions/arm_cfft_radix8_f16.c) - endif() + if ((NOT ARMAC5) AND (NOT DISABLEFLOAT16)) + zephyr_library_sources(${CMSIS_DSP_DIR}/Source/TransformFunctions/arm_cfft_radix4_init_f16.c) + zephyr_library_sources(${CMSIS_DSP_DIR}/Source/TransformFunctions/arm_cfft_radix4_f16.c) + endif() - zephyr_library_sources(${CMSIS_DSP_DIR}/Source/TransformFunctions/arm_rfft_init_f32.c) - zephyr_library_sources(${CMSIS_DSP_DIR}/Source/TransformFunctions/arm_rfft_f32.c) - zephyr_library_sources(${CMSIS_DSP_DIR}/Source/TransformFunctions/arm_cfft_radix4_init_f32.c) - zephyr_library_sources(${CMSIS_DSP_DIR}/Source/TransformFunctions/arm_cfft_radix4_f32.c) + zephyr_library_sources(${CMSIS_DSP_DIR}/Source/TransformFunctions/arm_cfft_f64.c) + zephyr_library_sources(${CMSIS_DSP_DIR}/Source/TransformFunctions/arm_cfft_init_f64.c) - zephyr_library_sources(${CMSIS_DSP_DIR}/Source/TransformFunctions/arm_rfft_init_q15.c) - zephyr_library_sources(${CMSIS_DSP_DIR}/Source/TransformFunctions/arm_rfft_q15.c) - zephyr_library_sources(${CMSIS_DSP_DIR}/Source/TransformFunctions/arm_cfft_q15.c) - zephyr_library_sources(${CMSIS_DSP_DIR}/Source/TransformFunctions/arm_cfft_init_q15.c) - zephyr_library_sources(${CMSIS_DSP_DIR}/Source/TransformFunctions/arm_cfft_radix4_q15.c) + zephyr_library_sources(${CMSIS_DSP_DIR}/Source/TransformFunctions/arm_cfft_radix2_q15.c) + zephyr_library_sources(${CMSIS_DSP_DIR}/Source/TransformFunctions/arm_cfft_radix4_q15.c) + zephyr_library_sources(${CMSIS_DSP_DIR}/Source/TransformFunctions/arm_cfft_q15.c) + zephyr_library_sources(${CMSIS_DSP_DIR}/Source/TransformFunctions/arm_cfft_init_q15.c) - zephyr_library_sources(${CMSIS_DSP_DIR}/Source/TransformFunctions/arm_rfft_init_q31.c) - zephyr_library_sources(${CMSIS_DSP_DIR}/Source/TransformFunctions/arm_rfft_q31.c) - zephyr_library_sources(${CMSIS_DSP_DIR}/Source/TransformFunctions/arm_cfft_q31.c) - zephyr_library_sources(${CMSIS_DSP_DIR}/Source/TransformFunctions/arm_cfft_init_q31.c) - zephyr_library_sources(${CMSIS_DSP_DIR}/Source/TransformFunctions/arm_cfft_radix4_q31.c) + zephyr_library_sources(${CMSIS_DSP_DIR}/Source/TransformFunctions/arm_cfft_radix2_q31.c) + zephyr_library_sources(${CMSIS_DSP_DIR}/Source/TransformFunctions/arm_cfft_radix4_q31.c) + zephyr_library_sources(${CMSIS_DSP_DIR}/Source/TransformFunctions/arm_cfft_q31.c) + zephyr_library_sources(${CMSIS_DSP_DIR}/Source/TransformFunctions/arm_cfft_init_q31.c) - if (WRAPPER) - zephyr_library_sources(${CMSIS_DSP_DIR}/Source/TransformFunctions/arm_cfft_radix2_init_q15.c) - zephyr_library_sources(${CMSIS_DSP_DIR}/Source/TransformFunctions/arm_cfft_radix2_init_q31.c) - endif() - zephyr_library_sources(${CMSIS_DSP_DIR}/Source/TransformFunctions/arm_cfft_radix4_init_q15.c) - zephyr_library_sources(${CMSIS_DSP_DIR}/Source/TransformFunctions/arm_cfft_radix4_init_q31.c) + zephyr_library_sources(${CMSIS_DSP_DIR}/Source/TransformFunctions/arm_dct4_f32.c) + zephyr_library_sources(${CMSIS_DSP_DIR}/Source/TransformFunctions/arm_dct4_init_f32.c) + zephyr_library_sources(${CMSIS_DSP_DIR}/Source/TransformFunctions/arm_rfft_init_f32.c) + zephyr_library_sources(${CMSIS_DSP_DIR}/Source/TransformFunctions/arm_rfft_f32.c) + zephyr_library_sources(${CMSIS_DSP_DIR}/Source/TransformFunctions/arm_cfft_radix4_init_f32.c) + zephyr_library_sources(${CMSIS_DSP_DIR}/Source/TransformFunctions/arm_cfft_radix4_f32.c) + + zephyr_library_sources(${CMSIS_DSP_DIR}/Source/TransformFunctions/arm_dct4_q31.c) + zephyr_library_sources(${CMSIS_DSP_DIR}/Source/TransformFunctions/arm_dct4_init_q31.c) + + zephyr_library_sources(${CMSIS_DSP_DIR}/Source/TransformFunctions/arm_rfft_init_q31.c) + zephyr_library_sources(${CMSIS_DSP_DIR}/Source/TransformFunctions/arm_rfft_q31.c) + zephyr_library_sources(${CMSIS_DSP_DIR}/Source/TransformFunctions/arm_cfft_q31.c) + zephyr_library_sources(${CMSIS_DSP_DIR}/Source/TransformFunctions/arm_cfft_init_q31.c) + zephyr_library_sources(${CMSIS_DSP_DIR}/Source/TransformFunctions/arm_cfft_radix4_init_q31.c) + zephyr_library_sources(${CMSIS_DSP_DIR}/Source/TransformFunctions/arm_cfft_radix4_q31.c) + + zephyr_library_sources(${CMSIS_DSP_DIR}/Source/TransformFunctions/arm_dct4_init_q15.c) + zephyr_library_sources(${CMSIS_DSP_DIR}/Source/TransformFunctions/arm_dct4_q15.c) + + zephyr_library_sources(${CMSIS_DSP_DIR}/Source/TransformFunctions/arm_rfft_init_q15.c) + zephyr_library_sources(${CMSIS_DSP_DIR}/Source/TransformFunctions/arm_rfft_q15.c) + zephyr_library_sources(${CMSIS_DSP_DIR}/Source/TransformFunctions/arm_cfft_q15.c) + zephyr_library_sources(${CMSIS_DSP_DIR}/Source/TransformFunctions/arm_cfft_init_q15.c) + zephyr_library_sources(${CMSIS_DSP_DIR}/Source/TransformFunctions/arm_cfft_radix4_init_q15.c) + zephyr_library_sources(${CMSIS_DSP_DIR}/Source/TransformFunctions/arm_cfft_radix4_q15.c) + + zephyr_library_sources(${CMSIS_DSP_DIR}/Source/TransformFunctions/arm_rfft_fast_f32.c) + zephyr_library_sources(${CMSIS_DSP_DIR}/Source/TransformFunctions/arm_rfft_fast_init_f32.c) + zephyr_library_sources(${CMSIS_DSP_DIR}/Source/TransformFunctions/arm_cfft_f32.c) + zephyr_library_sources(${CMSIS_DSP_DIR}/Source/TransformFunctions/arm_cfft_init_f32.c) + zephyr_library_sources(${CMSIS_DSP_DIR}/Source/TransformFunctions/arm_cfft_radix8_f32.c) + + zephyr_library_sources(${CMSIS_DSP_DIR}/Source/TransformFunctions/arm_rfft_fast_f64.c) + zephyr_library_sources(${CMSIS_DSP_DIR}/Source/TransformFunctions/arm_rfft_fast_init_f64.c) - # For scipy or wrappers or benchmarks - if (WRAPPER) - zephyr_library_sources(${CMSIS_DSP_DIR}/Source/TransformFunctions/arm_cfft_radix2_init_f32.c) if ((NOT ARMAC5) AND (NOT DISABLEFLOAT16)) - zephyr_library_sources(${CMSIS_DSP_DIR}/Source/TransformFunctions/arm_cfft_radix2_init_f16.c) + zephyr_library_sources(${CMSIS_DSP_DIR}/Source/TransformFunctions/arm_rfft_fast_f16.c) + zephyr_library_sources(${CMSIS_DSP_DIR}/Source/TransformFunctions/arm_rfft_fast_init_f16.c) + zephyr_library_sources(${CMSIS_DSP_DIR}/Source/TransformFunctions/arm_cfft_f16.c) + zephyr_library_sources(${CMSIS_DSP_DIR}/Source/TransformFunctions/arm_cfft_init_f16.c) + zephyr_library_sources(${CMSIS_DSP_DIR}/Source/TransformFunctions/arm_cfft_radix8_f16.c) endif() - endif() - zephyr_library_sources(${CMSIS_DSP_DIR}/Source/TransformFunctions/arm_mfcc_init_f32.c) - zephyr_library_sources(${CMSIS_DSP_DIR}/Source/TransformFunctions/arm_mfcc_f32.c) + zephyr_library_sources(${CMSIS_DSP_DIR}/Source/TransformFunctions/arm_rfft_init_f32.c) + zephyr_library_sources(${CMSIS_DSP_DIR}/Source/TransformFunctions/arm_rfft_f32.c) + zephyr_library_sources(${CMSIS_DSP_DIR}/Source/TransformFunctions/arm_cfft_radix4_init_f32.c) + zephyr_library_sources(${CMSIS_DSP_DIR}/Source/TransformFunctions/arm_cfft_radix4_f32.c) + + zephyr_library_sources(${CMSIS_DSP_DIR}/Source/TransformFunctions/arm_rfft_init_q15.c) + zephyr_library_sources(${CMSIS_DSP_DIR}/Source/TransformFunctions/arm_rfft_q15.c) + zephyr_library_sources(${CMSIS_DSP_DIR}/Source/TransformFunctions/arm_cfft_q15.c) + zephyr_library_sources(${CMSIS_DSP_DIR}/Source/TransformFunctions/arm_cfft_init_q15.c) + zephyr_library_sources(${CMSIS_DSP_DIR}/Source/TransformFunctions/arm_cfft_radix4_q15.c) + + zephyr_library_sources(${CMSIS_DSP_DIR}/Source/TransformFunctions/arm_rfft_init_q31.c) + zephyr_library_sources(${CMSIS_DSP_DIR}/Source/TransformFunctions/arm_rfft_q31.c) + zephyr_library_sources(${CMSIS_DSP_DIR}/Source/TransformFunctions/arm_cfft_q31.c) + zephyr_library_sources(${CMSIS_DSP_DIR}/Source/TransformFunctions/arm_cfft_init_q31.c) + zephyr_library_sources(${CMSIS_DSP_DIR}/Source/TransformFunctions/arm_cfft_radix4_q31.c) + + if (WRAPPER) + zephyr_library_sources(${CMSIS_DSP_DIR}/Source/TransformFunctions/arm_cfft_radix2_init_q15.c) + zephyr_library_sources(${CMSIS_DSP_DIR}/Source/TransformFunctions/arm_cfft_radix2_init_q31.c) + endif() - zephyr_library_sources(${CMSIS_DSP_DIR}/Source/TransformFunctions/arm_mfcc_init_q31.c) - zephyr_library_sources(${CMSIS_DSP_DIR}/Source/TransformFunctions/arm_mfcc_q31.c) + zephyr_library_sources(${CMSIS_DSP_DIR}/Source/TransformFunctions/arm_cfft_radix4_init_q15.c) + zephyr_library_sources(${CMSIS_DSP_DIR}/Source/TransformFunctions/arm_cfft_radix4_init_q31.c) - zephyr_library_sources(${CMSIS_DSP_DIR}/Source/TransformFunctions/arm_mfcc_init_q15.c) - zephyr_library_sources(${CMSIS_DSP_DIR}/Source/TransformFunctions/arm_mfcc_q15.c) - if ((NOT ARMAC5) AND (NOT DISABLEFLOAT16)) - zephyr_library_sources(${CMSIS_DSP_DIR}/Source/TransformFunctions/arm_mfcc_init_f16.c) - zephyr_library_sources(${CMSIS_DSP_DIR}/Source/TransformFunctions/arm_mfcc_f16.c) + # For scipy or wrappers or benchmarks + if (WRAPPER) + zephyr_library_sources(${CMSIS_DSP_DIR}/Source/TransformFunctions/arm_cfft_radix2_init_f32.c) + if ((NOT ARMAC5) AND (NOT DISABLEFLOAT16)) + zephyr_library_sources(${CMSIS_DSP_DIR}/Source/TransformFunctions/arm_cfft_radix2_init_f16.c) + endif() + endif() + + zephyr_library_sources(${CMSIS_DSP_DIR}/Source/TransformFunctions/arm_mfcc_init_f32.c) + zephyr_library_sources(${CMSIS_DSP_DIR}/Source/TransformFunctions/arm_mfcc_f32.c) + + zephyr_library_sources(${CMSIS_DSP_DIR}/Source/TransformFunctions/arm_mfcc_init_q31.c) + zephyr_library_sources(${CMSIS_DSP_DIR}/Source/TransformFunctions/arm_mfcc_q31.c) + + zephyr_library_sources(${CMSIS_DSP_DIR}/Source/TransformFunctions/arm_mfcc_init_q15.c) + zephyr_library_sources(${CMSIS_DSP_DIR}/Source/TransformFunctions/arm_mfcc_q15.c) + + if ((NOT ARMAC5) AND (NOT DISABLEFLOAT16)) + zephyr_library_sources(${CMSIS_DSP_DIR}/Source/TransformFunctions/arm_mfcc_init_f16.c) + zephyr_library_sources(${CMSIS_DSP_DIR}/Source/TransformFunctions/arm_mfcc_f16.c) + endif() endif() # Window Functions - set(SRCF64 ${CMSIS_DSP_DIR}/Source/WindowFunctions/arm_welch_f64.c - ${CMSIS_DSP_DIR}/Source/WindowFunctions/arm_bartlett_f64.c - ${CMSIS_DSP_DIR}/Source/WindowFunctions/arm_hamming_f64.c - ${CMSIS_DSP_DIR}/Source/WindowFunctions/arm_hanning_f64.c - ${CMSIS_DSP_DIR}/Source/WindowFunctions/arm_nuttall3_f64.c - ${CMSIS_DSP_DIR}/Source/WindowFunctions/arm_nuttall4_f64.c - ${CMSIS_DSP_DIR}/Source/WindowFunctions/arm_nuttall3a_f64.c - ${CMSIS_DSP_DIR}/Source/WindowFunctions/arm_nuttall3b_f64.c - ${CMSIS_DSP_DIR}/Source/WindowFunctions/arm_nuttall4a_f64.c - ${CMSIS_DSP_DIR}/Source/WindowFunctions/arm_blackman_harris_92db_f64.c - ${CMSIS_DSP_DIR}/Source/WindowFunctions/arm_nuttall4b_f64.c - ${CMSIS_DSP_DIR}/Source/WindowFunctions/arm_nuttall4c_f64.c - ${CMSIS_DSP_DIR}/Source/WindowFunctions/arm_hft90d_f64.c - ${CMSIS_DSP_DIR}/Source/WindowFunctions/arm_hft95_f64.c - ${CMSIS_DSP_DIR}/Source/WindowFunctions/arm_hft116d_f64.c - ${CMSIS_DSP_DIR}/Source/WindowFunctions/arm_hft144d_f64.c - ${CMSIS_DSP_DIR}/Source/WindowFunctions/arm_hft169d_f64.c - ${CMSIS_DSP_DIR}/Source/WindowFunctions/arm_hft196d_f64.c - ${CMSIS_DSP_DIR}/Source/WindowFunctions/arm_hft223d_f64.c - ${CMSIS_DSP_DIR}/Source/WindowFunctions/arm_hft248d_f64.c - ) - - set(SRCF32 ${CMSIS_DSP_DIR}/Source/WindowFunctions/arm_welch_f32.c - ${CMSIS_DSP_DIR}/Source/WindowFunctions/arm_bartlett_f32.c - ${CMSIS_DSP_DIR}/Source/WindowFunctions/arm_hamming_f32.c - ${CMSIS_DSP_DIR}/Source/WindowFunctions/arm_hanning_f32.c - ${CMSIS_DSP_DIR}/Source/WindowFunctions/arm_nuttall3_f32.c - ${CMSIS_DSP_DIR}/Source/WindowFunctions/arm_nuttall4_f32.c - ${CMSIS_DSP_DIR}/Source/WindowFunctions/arm_nuttall3a_f32.c - ${CMSIS_DSP_DIR}/Source/WindowFunctions/arm_nuttall3b_f32.c - ${CMSIS_DSP_DIR}/Source/WindowFunctions/arm_nuttall4a_f32.c - ${CMSIS_DSP_DIR}/Source/WindowFunctions/arm_blackman_harris_92db_f32.c - ${CMSIS_DSP_DIR}/Source/WindowFunctions/arm_nuttall4b_f32.c - ${CMSIS_DSP_DIR}/Source/WindowFunctions/arm_nuttall4c_f32.c - ${CMSIS_DSP_DIR}/Source/WindowFunctions/arm_hft90d_f32.c - ${CMSIS_DSP_DIR}/Source/WindowFunctions/arm_hft95_f32.c - ${CMSIS_DSP_DIR}/Source/WindowFunctions/arm_hft116d_f32.c - ${CMSIS_DSP_DIR}/Source/WindowFunctions/arm_hft144d_f32.c - ${CMSIS_DSP_DIR}/Source/WindowFunctions/arm_hft169d_f32.c - ${CMSIS_DSP_DIR}/Source/WindowFunctions/arm_hft196d_f32.c - ${CMSIS_DSP_DIR}/Source/WindowFunctions/arm_hft223d_f32.c - ${CMSIS_DSP_DIR}/Source/WindowFunctions/arm_hft248d_f32.c - ) + if (CONFIG_CMSIS_DSP_WINDOW) + set(SRCF64 ${CMSIS_DSP_DIR}/Source/WindowFunctions/arm_welch_f64.c + ${CMSIS_DSP_DIR}/Source/WindowFunctions/arm_bartlett_f64.c + ${CMSIS_DSP_DIR}/Source/WindowFunctions/arm_hamming_f64.c + ${CMSIS_DSP_DIR}/Source/WindowFunctions/arm_hanning_f64.c + ${CMSIS_DSP_DIR}/Source/WindowFunctions/arm_nuttall3_f64.c + ${CMSIS_DSP_DIR}/Source/WindowFunctions/arm_nuttall4_f64.c + ${CMSIS_DSP_DIR}/Source/WindowFunctions/arm_nuttall3a_f64.c + ${CMSIS_DSP_DIR}/Source/WindowFunctions/arm_nuttall3b_f64.c + ${CMSIS_DSP_DIR}/Source/WindowFunctions/arm_nuttall4a_f64.c + ${CMSIS_DSP_DIR}/Source/WindowFunctions/arm_blackman_harris_92db_f64.c + ${CMSIS_DSP_DIR}/Source/WindowFunctions/arm_nuttall4b_f64.c + ${CMSIS_DSP_DIR}/Source/WindowFunctions/arm_nuttall4c_f64.c + ${CMSIS_DSP_DIR}/Source/WindowFunctions/arm_hft90d_f64.c + ${CMSIS_DSP_DIR}/Source/WindowFunctions/arm_hft95_f64.c + ${CMSIS_DSP_DIR}/Source/WindowFunctions/arm_hft116d_f64.c + ${CMSIS_DSP_DIR}/Source/WindowFunctions/arm_hft144d_f64.c + ${CMSIS_DSP_DIR}/Source/WindowFunctions/arm_hft169d_f64.c + ${CMSIS_DSP_DIR}/Source/WindowFunctions/arm_hft196d_f64.c + ${CMSIS_DSP_DIR}/Source/WindowFunctions/arm_hft223d_f64.c + ${CMSIS_DSP_DIR}/Source/WindowFunctions/arm_hft248d_f64.c + ) - zephyr_library_sources(${SRCF64}) - zephyr_library_sources(${SRCF32}) + set(SRCF32 ${CMSIS_DSP_DIR}/Source/WindowFunctions/arm_welch_f32.c + ${CMSIS_DSP_DIR}/Source/WindowFunctions/arm_bartlett_f32.c + ${CMSIS_DSP_DIR}/Source/WindowFunctions/arm_hamming_f32.c + ${CMSIS_DSP_DIR}/Source/WindowFunctions/arm_hanning_f32.c + ${CMSIS_DSP_DIR}/Source/WindowFunctions/arm_nuttall3_f32.c + ${CMSIS_DSP_DIR}/Source/WindowFunctions/arm_nuttall4_f32.c + ${CMSIS_DSP_DIR}/Source/WindowFunctions/arm_nuttall3a_f32.c + ${CMSIS_DSP_DIR}/Source/WindowFunctions/arm_nuttall3b_f32.c + ${CMSIS_DSP_DIR}/Source/WindowFunctions/arm_nuttall4a_f32.c + ${CMSIS_DSP_DIR}/Source/WindowFunctions/arm_blackman_harris_92db_f32.c + ${CMSIS_DSP_DIR}/Source/WindowFunctions/arm_nuttall4b_f32.c + ${CMSIS_DSP_DIR}/Source/WindowFunctions/arm_nuttall4c_f32.c + ${CMSIS_DSP_DIR}/Source/WindowFunctions/arm_hft90d_f32.c + ${CMSIS_DSP_DIR}/Source/WindowFunctions/arm_hft95_f32.c + ${CMSIS_DSP_DIR}/Source/WindowFunctions/arm_hft116d_f32.c + ${CMSIS_DSP_DIR}/Source/WindowFunctions/arm_hft144d_f32.c + ${CMSIS_DSP_DIR}/Source/WindowFunctions/arm_hft169d_f32.c + ${CMSIS_DSP_DIR}/Source/WindowFunctions/arm_hft196d_f32.c + ${CMSIS_DSP_DIR}/Source/WindowFunctions/arm_hft223d_f32.c + ${CMSIS_DSP_DIR}/Source/WindowFunctions/arm_hft248d_f32.c + ) + zephyr_library_sources(${SRCF64}) + zephyr_library_sources(${SRCF32}) + endif() endif() diff --git a/modules/cmsis-dsp/Kconfig b/modules/cmsis-dsp/Kconfig index 2159f1f6c2e..b25e77ce9c7 100644 --- a/modules/cmsis-dsp/Kconfig +++ b/modules/cmsis-dsp/Kconfig @@ -11,6 +11,250 @@ menuconfig CMSIS_DSP if CMSIS_DSP +comment "Components" +config CMSIS_DSP_BASICMATH + bool "Basic Math Functions" + help + This option enables the Basic Math Functions, which support the + following operations: + + * Elementwise Clipping + * Vector Absolute Value + * Vector Addition + * Vector Subtraction + * Vector Multiplication + * Vector Dot Product + * Vector Absolute Value + * Vector Negate + * Vector Offset + * Vector Scale + * Vector Shift + * Vector Bitwise AND + * Vector Bitwise OR + * Vector Bitwise Exclusive OR + * Vector Bitwise NOT + +config CMSIS_DSP_COMPLEXMATH + bool "Complex Math Functions" + imply CMSIS_DSP_FASTMATH + help + This option enables the Complex Math Functions, which support the + following operations: + + * Complex-by-Complex Multiplication + * Complex-by-Real Multiplication + * Complex Dot Product + * Complex Magnitude + * Complex Magnitude Squared + * Complex Conjugate + +config CMSIS_DSP_CONTROLLER + bool "Controller Functions" + help + This option enables the Controller Functions, which support the + following operations: + + * PID Control + * Vector Clarke Transform + * Vector Inverse Clarke Transform + * Vector Park Transform + * Vector Inverse Park Transform + * Sine-Cosine + + These functions can be used to implement a generic PID controller, as + well as field oriented motor control using Space Vector Modulation + algorithm. + +config CMSIS_DSP_FASTMATH + bool "Fast Math Functions" + imply CMSIS_DSP_BASICMATH + help + This option enables the Fast Math Functions, which support the + following operations: + + * Fixed-Point Division + * Sine + * Cosine + * Square Root + +config CMSIS_DSP_FILTERING + bool "Filtering Functions" + imply CMSIS_DSP_BASICMATH + imply CMSIS_DSP_FASTMATH + imply CMSIS_DSP_SUPPORT + help + This option enables the Filtering Functions, which support the + following operations: + + * Convolution + * Partial Convolution + * Correlation + * Levinson-Durbin Algorithm + + The following filter types are supported: + + * FIR (finite impulse response) Filter + * FIR Lattice Filter + * FIR Sparse Filter + * FIR Filter with Decimator + * FIR Filter with Interpolator + * IIR (infinite impulse response) Lattice Filter + * Biquad Cascade IIR Filter, Direct Form I Structure + * Biquad Cascade IIR Filter, Direct Form II Transposed Structure + * High Precision Q31 Biquad Cascade Filter + * LMS (least mean square) Filter + * Normalized LMS Filter + +config CMSIS_DSP_INTERPOLATION + bool "Interpolation Functions" + help + This option enables the Interpolation Functions, which support the + following operations: + + * Bilinear Interpolation + * Linear Interpolation + * Cubic Spline Interpolation + +config CMSIS_DSP_MATRIX + bool "Matrix Functions" + help + This option enables the Matrix Functions, which support the following + operations: + + * Matrix Initialization + * Matrix Addition + * Matrix Subtraction + * Matrix Multiplication + * Complex Matrix Multiplication + * Matrix Vector Multiplication + * Matrix Inverse + * Matrix Scale + * Matrix Transpose + * Complex Matrix Transpose + * Cholesky and LDLT Decompositions + +config CMSIS_DSP_QUATERNIONMATH + bool "Quaternion Math Functions" + help + This option enables the Quaternion Math Functions, which support the + following operations: + + * Quaternion Conversions + * Quaternion Conjugate + * Quaternion Inverse + * Quaternion Norm + * Quaternion Normalization + * Quaternion Product + +config CMSIS_DSP_STATISTICS + bool "Statistics Functions" + imply CMSIS_DSP_BASICMATH + imply CMSIS_DSP_FASTMATH + help + This option enables the Statistics Functions, which support the + following operations: + + * Minimum + * Absolute Minimum + * Maximum + * Absolute Maximum + * Mean + * Root Mean Square (RMS) + * Variance + * Standard Deviation + * Power + * Entropy + * Kullback-Leibler Divergence + * LogSumExp (LSE) + +config CMSIS_DSP_SUPPORT + bool "Support Functions" + help + This option enables the Support Functions, which support the + following operations: + + * Vector 8-bit Integer Value Conversion + * Vector 16-bit Integer Value Conversion + * Vector 32-bit Integer Value Conversion + * Vector 16-bit Floating-Point Value Conversion + * Vector 32-bit Floating-Point Value Conversion + * Vector Copy + * Vector Fill + * Vector Sorting + * Weighted Sum + * Barycenter + +config CMSIS_DSP_TRANSFORM + bool "Transform Functions" + imply CMSIS_DSP_BASICMATH + help + This option enables the Transform Functions, which support the + following transformations: + + * Real Fast Fourier Transform (RFFT) + * Complex Fast Fourier Transform (CFFT) + * Type IV Discrete Cosine Transform (DCT4) + +config CMSIS_DSP_SVM + bool "Support Vector Machine Functions" + help + This option enables the Support Vector Machine Functions, which + support the following algorithms: + + * Linear + * Polynomial + * Sigmoid + * Radial Basis Function (RBF) + +config CMSIS_DSP_BAYES + bool "Bayesian Estimators" + imply CMSIS_DSP_STATISTICS + help + This option enables the Bayesian Estimator Functions, which + implements the naive gaussian Bayes estimator. + +config CMSIS_DSP_DISTANCE + bool "Distance Functions" + imply CMSIS_DSP_STATISTICS + help + This option enables the Distance Functions, which support the + following distance computation algorithms: + + * Boolean Vectors + * Hamming + * Jaccard + * Kulsinski + * Rogers-Tanimoto + * Russell-Rao + * Sokal-Michener + * Sokal-Sneath + * Yule + * Dice + + * Floating-Point Vectors + * Canberra + * Chebyshev + * Cityblock + * Correlation + * Cosine + * Euclidean + * Jensen-Shannon + * Minkowski + * Bray-Curtis + +config CMSIS_DSP_WINDOW + bool "Windowing Functions" + help + This option enabled the Window Functions, which support the + following windowing functions: + + * Bartlett + * Hamming + * Hanning + * Nuttall + * Blackman Harris + * HFT + comment "Instruction Set" # NOTE: These configurations should eventually be derived from the arch ISA and # FP support configurations. From 84ce10658c84b2d50c020aaa602d82230162c9f7 Mon Sep 17 00:00:00 2001 From: Jordan Yates Date: Fri, 24 Nov 2023 16:04:58 +1000 Subject: [PATCH 3340/3723] tests: cmsis-dsp: request required features Request the CMSIS DSP features required for each test. Signed-off-by: Jordan Yates --- tests/benchmarks/cmsis_dsp/basicmath/prj.conf | 1 + tests/lib/cmsis_dsp/bayes/prj.conf | 1 + tests/lib/cmsis_dsp/complexmath/prj.conf | 1 + tests/lib/cmsis_dsp/distance/prj.conf | 1 + tests/lib/cmsis_dsp/fastmath/prj.conf | 1 + tests/lib/cmsis_dsp/filtering/prj.conf | 1 + tests/lib/cmsis_dsp/filtering/prj_base.conf | 1 + tests/lib/cmsis_dsp/interpolation/prj.conf | 1 + tests/lib/cmsis_dsp/matrix/prj.conf | 1 + tests/lib/cmsis_dsp/matrix/prj_base.conf | 1 + tests/lib/cmsis_dsp/quaternionmath/prj.conf | 1 + tests/lib/cmsis_dsp/statistics/prj.conf | 1 + tests/lib/cmsis_dsp/support/prj.conf | 1 + tests/lib/cmsis_dsp/svm/prj.conf | 1 + tests/lib/cmsis_dsp/transform/prj.conf | 1 + tests/lib/cmsis_dsp/transform/prj_base.conf | 1 + tests/subsys/dsp/basicmath/prj.conf | 1 + tests/subsys/dsp/basicmath/prj_arc.conf | 1 + 18 files changed, 18 insertions(+) diff --git a/tests/benchmarks/cmsis_dsp/basicmath/prj.conf b/tests/benchmarks/cmsis_dsp/basicmath/prj.conf index b2e3d9799b8..7c10ca48e91 100644 --- a/tests/benchmarks/cmsis_dsp/basicmath/prj.conf +++ b/tests/benchmarks/cmsis_dsp/basicmath/prj.conf @@ -1,3 +1,4 @@ CONFIG_ZTEST=y CONFIG_REQUIRES_FULL_LIBC=y CONFIG_CMSIS_DSP=y +CONFIG_CMSIS_DSP_BASICMATH=y diff --git a/tests/lib/cmsis_dsp/bayes/prj.conf b/tests/lib/cmsis_dsp/bayes/prj.conf index b2e3d9799b8..04e2feebae6 100644 --- a/tests/lib/cmsis_dsp/bayes/prj.conf +++ b/tests/lib/cmsis_dsp/bayes/prj.conf @@ -1,3 +1,4 @@ CONFIG_ZTEST=y CONFIG_REQUIRES_FULL_LIBC=y CONFIG_CMSIS_DSP=y +CONFIG_CMSIS_DSP_BAYES=y diff --git a/tests/lib/cmsis_dsp/complexmath/prj.conf b/tests/lib/cmsis_dsp/complexmath/prj.conf index b2e3d9799b8..2380cbe9cd0 100644 --- a/tests/lib/cmsis_dsp/complexmath/prj.conf +++ b/tests/lib/cmsis_dsp/complexmath/prj.conf @@ -1,3 +1,4 @@ CONFIG_ZTEST=y CONFIG_REQUIRES_FULL_LIBC=y CONFIG_CMSIS_DSP=y +CONFIG_CMSIS_DSP_COMPLEXMATH=y diff --git a/tests/lib/cmsis_dsp/distance/prj.conf b/tests/lib/cmsis_dsp/distance/prj.conf index b2e3d9799b8..08dbbadf360 100644 --- a/tests/lib/cmsis_dsp/distance/prj.conf +++ b/tests/lib/cmsis_dsp/distance/prj.conf @@ -1,3 +1,4 @@ CONFIG_ZTEST=y CONFIG_REQUIRES_FULL_LIBC=y CONFIG_CMSIS_DSP=y +CONFIG_CMSIS_DSP_DISTANCE=y diff --git a/tests/lib/cmsis_dsp/fastmath/prj.conf b/tests/lib/cmsis_dsp/fastmath/prj.conf index b2e3d9799b8..77f5632450a 100644 --- a/tests/lib/cmsis_dsp/fastmath/prj.conf +++ b/tests/lib/cmsis_dsp/fastmath/prj.conf @@ -1,3 +1,4 @@ CONFIG_ZTEST=y CONFIG_REQUIRES_FULL_LIBC=y CONFIG_CMSIS_DSP=y +CONFIG_CMSIS_DSP_FASTMATH=y diff --git a/tests/lib/cmsis_dsp/filtering/prj.conf b/tests/lib/cmsis_dsp/filtering/prj.conf index 4b0e8a8121d..4688643a943 100644 --- a/tests/lib/cmsis_dsp/filtering/prj.conf +++ b/tests/lib/cmsis_dsp/filtering/prj.conf @@ -1,6 +1,7 @@ CONFIG_ZTEST=y CONFIG_REQUIRES_FULL_LIBC=y CONFIG_CMSIS_DSP=y +CONFIG_CMSIS_DSP_FILTERING=y # Test Options CONFIG_CMSIS_DSP_TEST_FILTERING_BIQUAD=y diff --git a/tests/lib/cmsis_dsp/filtering/prj_base.conf b/tests/lib/cmsis_dsp/filtering/prj_base.conf index b2e3d9799b8..73c249bd78c 100644 --- a/tests/lib/cmsis_dsp/filtering/prj_base.conf +++ b/tests/lib/cmsis_dsp/filtering/prj_base.conf @@ -1,3 +1,4 @@ CONFIG_ZTEST=y CONFIG_REQUIRES_FULL_LIBC=y CONFIG_CMSIS_DSP=y +CONFIG_CMSIS_DSP_FILTERING=y diff --git a/tests/lib/cmsis_dsp/interpolation/prj.conf b/tests/lib/cmsis_dsp/interpolation/prj.conf index b2e3d9799b8..3d6f08ddf2e 100644 --- a/tests/lib/cmsis_dsp/interpolation/prj.conf +++ b/tests/lib/cmsis_dsp/interpolation/prj.conf @@ -1,3 +1,4 @@ CONFIG_ZTEST=y CONFIG_REQUIRES_FULL_LIBC=y CONFIG_CMSIS_DSP=y +CONFIG_CMSIS_DSP_INTERPOLATION=y diff --git a/tests/lib/cmsis_dsp/matrix/prj.conf b/tests/lib/cmsis_dsp/matrix/prj.conf index e6cfe7a6774..35481e35168 100644 --- a/tests/lib/cmsis_dsp/matrix/prj.conf +++ b/tests/lib/cmsis_dsp/matrix/prj.conf @@ -1,6 +1,7 @@ CONFIG_ZTEST=y CONFIG_REQUIRES_FULL_LIBC=y CONFIG_CMSIS_DSP=y +CONFIG_CMSIS_DSP_MATRIX=y # Test Options CONFIG_CMSIS_DSP_TEST_MATRIX_UNARY_Q7=y diff --git a/tests/lib/cmsis_dsp/matrix/prj_base.conf b/tests/lib/cmsis_dsp/matrix/prj_base.conf index b2e3d9799b8..0d01efd6f2d 100644 --- a/tests/lib/cmsis_dsp/matrix/prj_base.conf +++ b/tests/lib/cmsis_dsp/matrix/prj_base.conf @@ -1,3 +1,4 @@ CONFIG_ZTEST=y CONFIG_REQUIRES_FULL_LIBC=y CONFIG_CMSIS_DSP=y +CONFIG_CMSIS_DSP_MATRIX=y diff --git a/tests/lib/cmsis_dsp/quaternionmath/prj.conf b/tests/lib/cmsis_dsp/quaternionmath/prj.conf index b2e3d9799b8..a9855fa53bd 100644 --- a/tests/lib/cmsis_dsp/quaternionmath/prj.conf +++ b/tests/lib/cmsis_dsp/quaternionmath/prj.conf @@ -1,3 +1,4 @@ CONFIG_ZTEST=y CONFIG_REQUIRES_FULL_LIBC=y CONFIG_CMSIS_DSP=y +CONFIG_CMSIS_DSP_QUATERNIONMATH=y diff --git a/tests/lib/cmsis_dsp/statistics/prj.conf b/tests/lib/cmsis_dsp/statistics/prj.conf index b2e3d9799b8..88e7298100c 100644 --- a/tests/lib/cmsis_dsp/statistics/prj.conf +++ b/tests/lib/cmsis_dsp/statistics/prj.conf @@ -1,3 +1,4 @@ CONFIG_ZTEST=y CONFIG_REQUIRES_FULL_LIBC=y CONFIG_CMSIS_DSP=y +CONFIG_CMSIS_DSP_STATISTICS=y diff --git a/tests/lib/cmsis_dsp/support/prj.conf b/tests/lib/cmsis_dsp/support/prj.conf index b2e3d9799b8..964df212500 100644 --- a/tests/lib/cmsis_dsp/support/prj.conf +++ b/tests/lib/cmsis_dsp/support/prj.conf @@ -1,3 +1,4 @@ CONFIG_ZTEST=y CONFIG_REQUIRES_FULL_LIBC=y CONFIG_CMSIS_DSP=y +CONFIG_CMSIS_DSP_SUPPORT=y diff --git a/tests/lib/cmsis_dsp/svm/prj.conf b/tests/lib/cmsis_dsp/svm/prj.conf index b2e3d9799b8..c42421ae7ff 100644 --- a/tests/lib/cmsis_dsp/svm/prj.conf +++ b/tests/lib/cmsis_dsp/svm/prj.conf @@ -1,3 +1,4 @@ CONFIG_ZTEST=y CONFIG_REQUIRES_FULL_LIBC=y CONFIG_CMSIS_DSP=y +CONFIG_CMSIS_DSP_SVM=y diff --git a/tests/lib/cmsis_dsp/transform/prj.conf b/tests/lib/cmsis_dsp/transform/prj.conf index 5eaeb1a352f..713a480a0ff 100644 --- a/tests/lib/cmsis_dsp/transform/prj.conf +++ b/tests/lib/cmsis_dsp/transform/prj.conf @@ -1,6 +1,7 @@ CONFIG_ZTEST=y CONFIG_REQUIRES_FULL_LIBC=y CONFIG_CMSIS_DSP=y +CONFIG_CMSIS_DSP_TRANSFORM=y # Test Options CONFIG_CMSIS_DSP_TEST_TRANSFORM_CQ15=y diff --git a/tests/lib/cmsis_dsp/transform/prj_base.conf b/tests/lib/cmsis_dsp/transform/prj_base.conf index b2e3d9799b8..52d74930324 100644 --- a/tests/lib/cmsis_dsp/transform/prj_base.conf +++ b/tests/lib/cmsis_dsp/transform/prj_base.conf @@ -1,3 +1,4 @@ CONFIG_ZTEST=y CONFIG_REQUIRES_FULL_LIBC=y CONFIG_CMSIS_DSP=y +CONFIG_CMSIS_DSP_TRANSFORM=y diff --git a/tests/subsys/dsp/basicmath/prj.conf b/tests/subsys/dsp/basicmath/prj.conf index 11333398dee..3921b18d87a 100644 --- a/tests/subsys/dsp/basicmath/prj.conf +++ b/tests/subsys/dsp/basicmath/prj.conf @@ -2,4 +2,5 @@ CONFIG_ZTEST=y CONFIG_REQUIRES_FULL_LIBC=y CONFIG_DSP=y CONFIG_CMSIS_DSP=y +CONFIG_CMSIS_DSP_BASICMATH=y CONFIG_DSP_BACKEND_CMSIS=y diff --git a/tests/subsys/dsp/basicmath/prj_arc.conf b/tests/subsys/dsp/basicmath/prj_arc.conf index e0558196361..14ec2e835c9 100644 --- a/tests/subsys/dsp/basicmath/prj_arc.conf +++ b/tests/subsys/dsp/basicmath/prj_arc.conf @@ -3,4 +3,5 @@ CONFIG_ARCMWDT_LIBC=y CONFIG_CPLUSPLUS=y CONFIG_DSP=y CONFIG_CMSIS_DSP=y +CONFIG_CMSIS_DSP_BASICMATH=y CONFIG_DSP_BACKEND_ARCMWDT=y From a8a0eb52439caccf51c66f845b2c29ceef0da39e Mon Sep 17 00:00:00 2001 From: Daniel DeGrasse Date: Wed, 31 Jan 2024 09:34:47 -0600 Subject: [PATCH 3341/3723] MAINTAINERS: add danieldegrasse to display collaborators Add myself to display collaborators list to aid in reviewing PRs, as I have been working with SPI based and parallel displays within Zephyr Signed-off-by: Daniel DeGrasse --- MAINTAINERS.yml | 1 + 1 file changed, 1 insertion(+) diff --git a/MAINTAINERS.yml b/MAINTAINERS.yml index 5265cd5debe..ae4698ccbe8 100644 --- a/MAINTAINERS.yml +++ b/MAINTAINERS.yml @@ -819,6 +819,7 @@ Display drivers: status: odd fixes collaborators: - jfischer-no + - danieldegrasse files: - drivers/display/ - dts/bindings/display/ From 24ebebdcc955e05493ee8f63bd7c6e84812db561 Mon Sep 17 00:00:00 2001 From: Kshitij Shah Date: Wed, 25 Oct 2023 10:53:53 +0000 Subject: [PATCH 3342/3723] drivers: sensor: bma4xx: Add bma4xx emulator Add emulator for bma4xx sensor. Signed-off-by: Kshitij Shah --- drivers/sensor/bma4xx/bma4xx.h | 15 +- drivers/sensor/bma4xx/bma4xx_emul.c | 324 ++++++++++++++++++++++++++++ drivers/sensor/bma4xx/bma4xx_emul.h | 33 +++ 3 files changed, 371 insertions(+), 1 deletion(-) create mode 100644 drivers/sensor/bma4xx/bma4xx_emul.c create mode 100644 drivers/sensor/bma4xx/bma4xx_emul.h diff --git a/drivers/sensor/bma4xx/bma4xx.h b/drivers/sensor/bma4xx/bma4xx.h index 0badd51b951..6184e40b062 100644 --- a/drivers/sensor/bma4xx/bma4xx.h +++ b/drivers/sensor/bma4xx/bma4xx.h @@ -47,6 +47,7 @@ #define BMA4XX_REG_HIGH_G_OUT (0x1F) #define BMA4XX_REG_TEMPERATURE (0x22) #define BMA4XX_REG_FIFO_LENGTH_0 (0x24) +#define BMA4XX_REG_FIFO_LENGTH_1 (0x25) #define BMA4XX_REG_FIFO_DATA (0x26) #define BMA4XX_REG_ACTIVITY_OUT (0x27) #define BMA4XX_REG_ORIENTATION_OUT (0x28) @@ -64,7 +65,7 @@ #define BMA4XX_REG_AUX_WR_DATA (0x4F) #define BMA4XX_REG_INT1_IO_CTRL (0x53) #define BMA4XX_REG_INT2_IO_CTRL (0x54) -#define BMA4XX_REG_INTR_LATCH (0x55) +#define BMA4XX_REG_INT_LATCH (0x55) #define BMA4XX_REG_INT_MAP_1 (0x56) #define BMA4XX_REG_INT_MAP_2 (0x57) #define BMA4XX_REG_INT_MAP_DATA (0x58) @@ -98,6 +99,15 @@ #define BMA4XX_BIT_ACC_EN BIT(2) +/* INT_STATUS_1 accelerometer data ready to interrupt */ +#define BMA4XX_ACC_DRDY_INT BIT(7) + +/* CMD: Clears all data in FIFO, does not change FIFO_CONFIG and FIFO_DOWNS register */ +#define BMA4XX_CMD_FIFO_FLUSH (0xB0) + +/* FIFO_CONFIG_1 enable: Store Accelerometer data in FIFO (all 3 axes) */ +#define BMA4XX_FIFO_ACC_EN BIT(6) + /* Bandwidth parameters */ #define BMA4XX_BWP_OSR4_AVG1 (0x0) #define BMA4XX_BWP_OSR2_AVG2 (0x1) @@ -153,6 +163,9 @@ /* Range is -104C to 150C. Use shift of 8 (+/-256) */ #define BMA4XX_TEMP_SHIFT (8) +/* The total number of used registers specified in bma422 datasheet is 7E */ +#define BMA4XX_NUM_REGS 0x7E + /* * Types */ diff --git a/drivers/sensor/bma4xx/bma4xx_emul.c b/drivers/sensor/bma4xx/bma4xx_emul.c new file mode 100644 index 00000000000..b5c96d29817 --- /dev/null +++ b/drivers/sensor/bma4xx/bma4xx_emul.c @@ -0,0 +1,324 @@ +/* + * Copyright (c) 2024 Google LLC + * SPDX-License-Identifier: Apache-2.0 + */ +#include "bma4xx.h" +#include "bma4xx_emul.h" + +#include "zephyr/sys/util.h" + +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include + +#define DT_DRV_COMPAT bosch_bma4xx + +LOG_MODULE_REGISTER(bma4xx_emul, CONFIG_SENSOR_LOG_LEVEL); + +struct bma4xx_emul_data { + /* Holds register data. */ + uint8_t regs[BMA4XX_NUM_REGS]; +}; + +struct bma4xx_emul_cfg { +}; + +void bma4xx_emul_set_reg(const struct emul *target, uint8_t reg_addr, const uint8_t *val, + size_t count) +{ + struct bma4xx_emul_data *data = target->data; + + __ASSERT_NO_MSG(reg_addr + count <= BMA4XX_NUM_REGS); + memcpy(data->regs + reg_addr, val, count); +} + +void bma4xx_emul_get_reg(const struct emul *target, uint8_t reg_addr, uint8_t *val, size_t count) +{ + struct bma4xx_emul_data *data = target->data; + + __ASSERT_NO_MSG(reg_addr + count <= BMA4XX_NUM_REGS); + memcpy(val, data->regs + reg_addr, count); +} + +uint8_t bma4xx_emul_get_interrupt_config(const struct emul *target, uint8_t *int1_io_ctrl, + bool *latched_mode) +{ + struct bma4xx_emul_data *data = target->data; + + *int1_io_ctrl = data->regs[BMA4XX_REG_INT1_IO_CTRL]; + *latched_mode = data->regs[BMA4XX_REG_INT_LATCH]; + return data->regs[BMA4XX_REG_INT_MAP_DATA]; +} + +static int bma4xx_emul_read_byte(const struct emul *target, int reg, uint8_t *val, int bytes) +{ + bma4xx_emul_get_reg(target, reg, val, bytes); + + return 0; +} + +static int bma4xx_emul_write_byte(const struct emul *target, int reg, uint8_t val, int bytes) +{ + struct bma4xx_emul_data *data = target->data; + + if (bytes != 1) { + LOG_ERR("multi-byte writes are not supported"); + return -ENOTSUP; + } + + switch (reg) { + case BMA4XX_REG_ACCEL_CONFIG: + if ((val & 0xF0) != 0xA0) { + LOG_ERR("unsupported acc_bwp/acc_perf_mode: %#x", val); + return -EINVAL; + } + data->regs[reg] = val & GENMASK(1, 0); + return 0; + case BMA4XX_REG_ACCEL_RANGE: + if ((val & GENMASK(1, 0)) != val) { + LOG_ERR("reserved bits set in ACC_RANGE write: %#x", val); + return -EINVAL; + } + data->regs[reg] = val; + return 0; + case BMA4XX_REG_FIFO_CONFIG_1: + if (val & ~BMA4XX_FIFO_ACC_EN) { + LOG_ERR("unsupported bits set in FIFO_CONFIG_1" + " write: %#x", + val); + return -EINVAL; + } + data->regs[reg] = (val & BMA4XX_FIFO_ACC_EN) != 0; + return 0; + case BMA4XX_REG_INT1_IO_CTRL: + data->regs[reg] = val; + return 0; + case BMA4XX_REG_INT_LATCH: + if ((val & ~1) != 0) { + LOG_ERR("reserved bits set in INT_LATCH: %#x", val); + return -EINVAL; + } + data->regs[reg] = (val & 1) == 1; + return 0; + case BMA4XX_REG_INT_MAP_DATA: + data->regs[reg] = val; + return 0; + case BMA4XX_REG_NV_CONFIG: + if (val & GENMASK(7, 4)) { + LOG_ERR("reserved bits set in NV_CONF write: %#x", val); + return -EINVAL; + } + data->regs[reg] = val; + return 0; + case BMA4XX_REG_OFFSET_0: + case BMA4XX_REG_OFFSET_1: + case BMA4XX_REG_OFFSET_2: + data->regs[reg] = val; + return 0; + case BMA4XX_REG_POWER_CTRL: + if ((val & ~BMA4XX_BIT_ACC_EN) != 0) { + LOG_ERR("unhandled bits in POWER_CTRL write: %#x", val); + return -ENOTSUP; + } + data->regs[reg] = (val & BMA4XX_BIT_ACC_EN) != 0; + return 0; + case BMA4XX_REG_CMD: + if (val == BMA4XX_CMD_FIFO_FLUSH) { /* fifo_flush */ + data->regs[BMA4XX_REG_FIFO_DATA] = 0; + data->regs[BMA4XX_REG_FIFO_LENGTH_0] = 0; + data->regs[BMA4XX_REG_FIFO_LENGTH_1] = 0; + return 0; + } + break; + } + + LOG_WRN("unhandled I2C write to register %#x", reg); + return -ENOTSUP; +} + +static int bma4xx_emul_init(const struct emul *target, const struct device *parent) +{ + struct bma4xx_emul_data *data = target->data; + + data->regs[BMA4XX_REG_CHIP_ID] = BMA4XX_CHIP_ID_BMA422; + data->regs[BMA4XX_REG_ACCEL_RANGE] = BMA4XX_RANGE_4G; + + return 0; +} + +static int bma4xx_emul_transfer_i2c(const struct emul *target, struct i2c_msg *msgs, int num_msgs, + int addr) +{ + __ASSERT_NO_MSG(msgs && num_msgs); + if (num_msgs != 2) { + return 0; + } + + i2c_dump_msgs_rw(target->dev, msgs, num_msgs, addr, false); + + if (msgs->flags & I2C_MSG_READ) { + LOG_ERR("Unexpected read"); + return -EIO; + } + if (msgs->len != 1) { + LOG_ERR("Unexpected msg0 length %d", msgs->len); + return -EIO; + } + + uint32_t reg = msgs->buf[0]; + + msgs++; + if (msgs->flags & I2C_MSG_READ) { + /* Reads from regs in target->data to msgs->buf */ + bma4xx_emul_read_byte(target, reg, msgs->buf, msgs->len); + } else { + /* Writes msgs->buf[0] to regs in target->data */ + bma4xx_emul_write_byte(target, reg, msgs->buf[0], msgs->len); + } + + return 0; +}; + +void bma4xx_emul_set_accel_data(const struct emul *target, q31_t value, int8_t shift, int8_t reg) +{ + + struct bma4xx_emul_data *data = target->data; + + /* floor(9.80665 * 2^(31−4)) q31_t in (-2^4, 2^4) => range_g = shift of 4 */ + int64_t g = 1316226282; + int64_t range_g = 4; + + int64_t intermediate, unshifted; + int16_t reg_val; + + /* 0x00 -> +/-2g; 0x01 -> +/-4g; 0x02 -> +/-8g; 0x03 -> +/- 16g; */ + int64_t accel_range = (2 << data->regs[BMA4XX_REG_ACCEL_RANGE]); + + unshifted = shift < 0 ? ((int64_t)value >> -shift) : ((int64_t)value << shift); + + intermediate = (unshifted * BIT(11)) / (g << range_g); + + intermediate /= accel_range; + + reg_val = CLAMP(intermediate, -2048, 2047); + + /* lsb register uses top 12 of 16 bits to hold value so shift by 4 to fill it */ + data->regs[reg] = FIELD_GET(GENMASK(3, 0), reg_val) << 4; + data->regs[reg + 1] = FIELD_GET(GENMASK(11, 4), reg_val); +} + +static int bma4xx_emul_backend_set_channel(const struct emul *target, enum sensor_channel ch, + const q31_t *value, int8_t shift) +{ + + if (!target || !target->data) { + return -EINVAL; + } + + struct bma4xx_emul_data *data = target->data; + + switch (ch) { + case SENSOR_CHAN_ACCEL_X: + bma4xx_emul_set_accel_data(target, value[0], shift, BMA4XX_REG_DATA_8); + break; + case SENSOR_CHAN_ACCEL_Y: + bma4xx_emul_set_accel_data(target, value[0], shift, BMA4XX_REG_DATA_10); + break; + case SENSOR_CHAN_ACCEL_Z: + bma4xx_emul_set_accel_data(target, value[0], shift, BMA4XX_REG_DATA_12); + break; + case SENSOR_CHAN_ACCEL_XYZ: + bma4xx_emul_set_accel_data(target, value[0], shift, BMA4XX_REG_DATA_8); + bma4xx_emul_set_accel_data(target, value[1], shift, BMA4XX_REG_DATA_10); + bma4xx_emul_set_accel_data(target, value[2], shift, BMA4XX_REG_DATA_12); + default: + return -ENOTSUP; + } + + /* Set data ready flag */ + data->regs[BMA4XX_REG_INT_STAT_1] |= BMA4XX_ACC_DRDY_INT; + + return 0; +} + +static int bma4xx_emul_backend_get_sample_range(const struct emul *target, enum sensor_channel ch, + q31_t *lower, q31_t *upper, q31_t *epsilon, + int8_t *shift) +{ + if (!lower || !upper || !epsilon || !shift) { + return -EINVAL; + } + + switch (ch) { + case SENSOR_CHAN_ACCEL_X: + case SENSOR_CHAN_ACCEL_Y: + case SENSOR_CHAN_ACCEL_Z: + case SENSOR_CHAN_ACCEL_XYZ: + break; + default: + return -ENOTSUP; + } + + struct bma4xx_emul_data *data = target->data; + + switch (data->regs[BMA4XX_REG_ACCEL_RANGE]) { + case BMA4XX_RANGE_2G: + *shift = 5; + *upper = (q31_t)(2 * 9.80665 * BIT(31 - 5)); + *lower = -*upper; + /* (1 << (31 - shift) >> 12) * 2 (where 2 comes from 2g range) */ + *epsilon = BIT(31 - 5 - 12 + 1); + break; + case BMA4XX_RANGE_4G: + *shift = 6; + *upper = (q31_t)(4 * 9.80665 * BIT(31 - 6)); + *lower = -*upper; + /* (1 << (31 - shift) >> 12) * 4 (where 4 comes from 4g range) */ + *epsilon = BIT(31 - 6 - 12 + 2); + break; + case BMA4XX_RANGE_8G: + *shift = 7; + *upper = (q31_t)(8 * 9.80665 * BIT(31 - 7)); + *lower = -*upper; + /* (1 << (31 - shift) >> 12) * 8 (where 8 comes from 8g range) */ + *epsilon = BIT(31 - 7 - 12 + 3); + break; + case BMA4XX_RANGE_16G: + *shift = 8; + *upper = (q31_t)(16 * 9.80665 * BIT(31 - 8)); + *lower = -*upper; + /* (1 << (31 - shift) >> 12) * 16 (where 16 comes from 16g range) */ + *epsilon = BIT(31 - 8 - 12 + 4); + break; + default: + return -ENOTSUP; + } + + return 0; +} + +static const struct emul_sensor_backend_api bma4xx_emul_sensor_backend_api = { + .set_channel = bma4xx_emul_backend_set_channel, + .get_sample_range = bma4xx_emul_backend_get_sample_range, +}; + +static struct i2c_emul_api bma4xx_emul_api_i2c = { + .transfer = bma4xx_emul_transfer_i2c, +}; + +#define INIT_BMA4XX(n) \ + static struct bma4xx_emul_data bma4xx_emul_data_##n = {}; \ + static const struct bma4xx_emul_cfg bma4xx_emul_cfg_##n = {}; \ + EMUL_DT_INST_DEFINE(n, bma4xx_emul_init, &bma4xx_emul_data_##n, &bma4xx_emul_cfg_##n, \ + &bma4xx_emul_api_i2c, &bma4xx_emul_sensor_backend_api); + +DT_INST_FOREACH_STATUS_OKAY(INIT_BMA4XX) diff --git a/drivers/sensor/bma4xx/bma4xx_emul.h b/drivers/sensor/bma4xx/bma4xx_emul.h new file mode 100644 index 00000000000..2ea8c6f7fcb --- /dev/null +++ b/drivers/sensor/bma4xx/bma4xx_emul.h @@ -0,0 +1,33 @@ +/* + * Copyright (c) 2024 Google LLC + * SPDX-License-Identifier: Apache-2.0 + */ + +#ifndef ZEPHYR_DRIVERS_SENSOR_BMA4XX_BMA4XX_EMUL_H_ +#define ZEPHYR_DRIVERS_SENSOR_BMA4XX_BMA4XX_EMUL_H_ + +#include +#include "zephyr/dsp/types.h" + +#ifdef __cplusplus +extern "C" { +#endif + +/** Set the sensor's current acceleration reading. */ +void bma4xx_emul_set_accel_data(const struct emul *target, q31_t value, int8_t shift, int8_t reg); + +/** + * Return the current interrupt configuration. + * + * Provided pointers are out-parameters for the INT1_IO_CTRL register and + * whether interrupts are in latched mode. The return value is the current value + * of the INT_MAP_DATA register. + */ +uint8_t bma4xx_emul_get_interrupt_config(const struct emul *emul, uint8_t *int1_io_ctrl, + bool *latched_mode); + +#ifdef __cplusplus +} +#endif + +#endif /* ZEPHYR_DRIVERS_SENSOR_BMA4XX_BMA4XX_EMUL_H_ */ From 9260c5b6b284cb69a3a2786de1e9bacce764d072 Mon Sep 17 00:00:00 2001 From: Derek Snell Date: Thu, 1 Feb 2024 16:38:59 -0500 Subject: [PATCH 3343/3723] doc: linkserver: update PATH Added details to update PATH environment variable for linkserver Signed-off-by: Derek Snell --- doc/develop/flash_debug/host-tools.rst | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) diff --git a/doc/develop/flash_debug/host-tools.rst b/doc/develop/flash_debug/host-tools.rst index dff685ba7da..1fcf7fa1d8b 100644 --- a/doc/develop/flash_debug/host-tools.rst +++ b/doc/develop/flash_debug/host-tools.rst @@ -221,6 +221,24 @@ LinkServer is compatible with the following debug probes: - :ref:`mcu-link-cmsis-onboard-debug-probe` - :ref:`opensda-daplink-onboard-debug-probe` +To use LinkServer with West commands, the install folder should be added to the +:envvar:`PATH` :ref:`environment variable `. The default installation +path to add is: + +.. tabs:: + + .. group-tab:: Linux + + .. code-block:: console + + /usr/local/LinkServer + + .. group-tab:: Windows + + .. code-block:: console + + c:\nxp\LinkServer_ + Supported west commands: 1. flash From bc1a988f9d6d3b8366d7d823ae80b88b65632f82 Mon Sep 17 00:00:00 2001 From: Chun-Chieh Li Date: Tue, 28 Nov 2023 10:47:17 +0800 Subject: [PATCH 3344/3723] drivers: usb: device: support Nuvoton NuMaker series USBD controller driver 1. Configure 'core-clock' to 192MHz to generate necessary 48MHz 2. Support workaround to disallowing ISO IN/OUT EPs to be assigned the same EP numbers Signed-off-by: Chun-Chieh Li --- .../numaker_pfm_m467-pinctrl.dtsi | 10 + .../arm/numaker_pfm_m467/numaker_pfm_m467.dts | 7 + drivers/usb/device/CMakeLists.txt | 1 + drivers/usb/device/Kconfig | 25 + drivers/usb/device/usb_dc_numaker.c | 2007 +++++++++++++++++ dts/arm/nuvoton/m46x.dtsi | 13 + dts/bindings/usb/nuvoton,numaker-usbd.yaml | 33 + 7 files changed, 2096 insertions(+) create mode 100644 drivers/usb/device/usb_dc_numaker.c create mode 100644 dts/bindings/usb/nuvoton,numaker-usbd.yaml diff --git a/boards/arm/numaker_pfm_m467/numaker_pfm_m467-pinctrl.dtsi b/boards/arm/numaker_pfm_m467/numaker_pfm_m467-pinctrl.dtsi index b6b8f3eb508..48d1bf58b81 100644 --- a/boards/arm/numaker_pfm_m467/numaker_pfm_m467-pinctrl.dtsi +++ b/boards/arm/numaker_pfm_m467/numaker_pfm_m467-pinctrl.dtsi @@ -49,4 +49,14 @@ ; }; }; + + /* USBD multi-function pins for VBUS, D+, D-, and ID pins */ + usbd_default: usbd_default { + group0 { + pinmux = , + , + , + ; + }; + }; }; diff --git a/boards/arm/numaker_pfm_m467/numaker_pfm_m467.dts b/boards/arm/numaker_pfm_m467/numaker_pfm_m467.dts index da3350d9494..28db9b9265a 100644 --- a/boards/arm/numaker_pfm_m467/numaker_pfm_m467.dts +++ b/boards/arm/numaker_pfm_m467/numaker_pfm_m467.dts @@ -123,3 +123,10 @@ pinctrl-names = "default"; status = "okay"; }; + +/* On enabled, 'core-clock', as above, is required to to be 192MHz. */ +zephyr_udc0: &usbd { + pinctrl-0 = <&usbd_default>; + pinctrl-names = "default"; + status = "okay"; +}; diff --git a/drivers/usb/device/CMakeLists.txt b/drivers/usb/device/CMakeLists.txt index a66e5091f1a..6763b3c7f88 100644 --- a/drivers/usb/device/CMakeLists.txt +++ b/drivers/usb/device/CMakeLists.txt @@ -20,5 +20,6 @@ zephyr_library_sources_ifdef(CONFIG_USB_NRFX usb_dc_nrfx.c) zephyr_library_sources_ifdef(CONFIG_USB_MCUX usb_dc_mcux.c) zephyr_library_sources_ifdef(CONFIG_USB_DC_SMARTBOND usb_dc_smartbond.c) zephyr_library_sources_ifdef(CONFIG_USB_DC_IT82XX2 usb_dc_it82xx2.c) +zephyr_library_sources_ifdef(CONFIG_USB_DC_NUMAKER usb_dc_numaker.c) endif() diff --git a/drivers/usb/device/Kconfig b/drivers/usb/device/Kconfig index 91db896eede..3dc1a365bea 100644 --- a/drivers/usb/device/Kconfig +++ b/drivers/usb/device/Kconfig @@ -197,6 +197,31 @@ config USB_DC_IT82XX2 help ITE IT82XX2 USB Device Controller Driver +config USB_DC_NUMAKER + bool "Nuvoton NuMaker USB 1.1 device controller" + default y + depends on DT_HAS_NUVOTON_NUMAKER_USBD_ENABLED + help + Enable Nuvoton NuMaker USB 1.1 device controller driver + +if USB_DC_NUMAKER + +config USB_DC_NUMAKER_MSG_QUEUE_SIZE + int "USB DC message queue size" + default 32 + help + Maximum number of messages the driver can queue for interrupt bottom half processing + +config USB_DC_NUMAKER_MSG_HANDLER_THREAD_STACK_SIZE + int "USB DC message handler thread stack size" + default 1536 + help + Size of the stack for the message handler thread that is used in the driver + for handling messages from the USB DC ISR, i.e. interrupt bottom half processing, + including callbacks to the USB device stack. + +endif # USB_DC_NUMAKER + config USB_NATIVE_POSIX bool "Native Posix USB Device Controller Driver" depends on ARCH_POSIX && EXTERNAL_LIBC diff --git a/drivers/usb/device/usb_dc_numaker.c b/drivers/usb/device/usb_dc_numaker.c new file mode 100644 index 00000000000..0f52b165a13 --- /dev/null +++ b/drivers/usb/device/usb_dc_numaker.c @@ -0,0 +1,2007 @@ +/* + * Copyright (c) 2023 Nuvoton Technology Corporation. + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#define DT_DRV_COMPAT nuvoton_numaker_usbd + +#include +#include +#include +#include +#include +#include +#include +#include + +#include +LOG_MODULE_REGISTER(usb_dc_numaker, CONFIG_USB_DRIVER_LOG_LEVEL); + +#include +#include + +/* USBD notes + * + * 1. Require 48MHz clock source + * (1) Not support HIRC48 as clock source. It involves trim with USB SOF packets + * and isn't suitable in HAL. + * (2) Instead of HICR48, core clock is required to be multiple of 48MHz e.g. 192MHz, + * to generate necessary 48MHz. + */ + +/* For bus reset, keep 'SE0' (USB spec: SE0 >= 2.5 ms) */ +#define NUMAKER_USBD_BUS_RESET_DRV_SE0_US 3000 + +/* For bus resume, generate 'K' (USB spec: 'K' >= 1 ms) */ +#define NUMAKER_USBD_BUS_RESUME_DRV_K_US 1500 + +/* Reserve DMA buffer for Setup/CTRL OUT/CTRL IN, required to be 8-byte aligned */ +#define NUMAKER_USBD_DMABUF_SIZE_SETUP 8 +#define NUMAKER_USBD_DMABUF_SIZE_CTRLOUT 64 +#define NUMAKER_USBD_DMABUF_SIZE_CTRLIN 64 + +/* Maximum number of EP contexts across all instances + * This is to static-allocate EP contexts which can accommodate all instances. + * The number of effective EP contexts per instance is passed on through its + * num_bidir_endpoints, which must not be larger than this. + */ +#define NUMAKER_USBD_EP_MAXNUM 25ul + +/* Message type */ +#define NUMAKER_USBD_MSG_TYPE_SW_RECONN 0 /* S/W reconnect */ +#define NUMAKER_USBD_MSG_TYPE_CB_STATE 1 /* Callback for usb_dc_status_code */ +#define NUMAKER_USBD_MSG_TYPE_CB_EP 2 /* Callback for usb_dc_ep_cb_status_code */ + +/* Message structure */ +struct numaker_usbd_msg { + uint32_t type; + union { + struct { + enum usb_dc_status_code status_code; + } cb_device; + struct { + uint8_t ep; + enum usb_dc_ep_cb_status_code status_code; + } cb_ep; + }; +}; + +/* Immutable device context */ +struct numaker_usbd_config { + USBD_T *base; + const struct reset_dt_spec reset; + uint32_t clk_modidx; + uint32_t clk_src; + uint32_t clk_div; + const struct device *clkctrl_dev; + void (*irq_config_func)(const struct device *dev); + void (*irq_unconfig_func)(const struct device *dev); + const struct pinctrl_dev_config *pincfg; + uint32_t num_bidir_endpoints; + uint32_t dmabuf_size; + bool disallow_iso_inout_same; +}; + +/* EP context */ +struct numaker_usbd_ep { + bool valid; + + bool nak_clr; /* NAK cleared (ACK next transaction) */ + + const struct device *dev; /* Pointer to the containing device */ + + uint8_t ep_hw_idx; /* BSP USBD driver EP index EP0, EP1, EP2, etc */ + uint32_t ep_hw_cfg; /* BSP USBD driver EP configuration */ + + /* EP DMA buffer */ + bool dmabuf_valid; + uint32_t dmabuf_base; + uint32_t dmabuf_size; + + /* On USBD, no H/W FIFO. Simulate based on above DMA buffer with + * one-shot implementation + */ + uint32_t read_fifo_pos; + uint32_t read_fifo_used; + uint32_t write_fifo_pos; + uint32_t write_fifo_free; + + /* NOTE: On USBD, Setup and CTRL OUT are not completely separated. CTRL OUT MXPLD + * can be overridden to 8 by next Setup. To overcome it, we make one copy of CTRL + * OUT MXPLD immediately on its interrupt. + */ + uint32_t mxpld_ctrlout; + + /* EP address */ + bool addr_valid; + uint8_t addr; + + /* EP MPS */ + bool mps_valid; + uint16_t mps; + + usb_dc_ep_callback cb; /* EP callback function */ +}; + +/* EP context manager */ +struct numaker_usbd_ep_mgmt { + /* EP context management + * + * Allocate-only, and de-allocate all on re-initialize in usb_dc_attach(). + */ + uint8_t ep_idx; + + /* DMA buffer management + * + * Allocate-only, and de-allocate all on re-initialize in usb_dc_attach(). + */ + uint32_t dmabuf_pos; + + /* Pass Setup packet from ISR to thread */ + bool new_setup; + struct usb_setup_packet setup_packet; + + struct numaker_usbd_ep ep_pool[NUMAKER_USBD_EP_MAXNUM]; +}; + +/* Mutable device context */ +struct numaker_usbd_data { + uint8_t addr; /* Host assigned USB device address */ + + struct k_mutex sync_mutex; + + /* Enable interrupt top/bottom halves processing + * + * Registered callbacks may use mutex or other kernel functions which are not supported + * in interrupt context + */ + struct k_msgq msgq; + struct numaker_usbd_msg msgq_buf[CONFIG_USB_DC_NUMAKER_MSG_QUEUE_SIZE]; + + K_KERNEL_STACK_MEMBER(msg_hdlr_thread_stack, + CONFIG_USB_DC_NUMAKER_MSG_HANDLER_THREAD_STACK_SIZE); + struct k_thread msg_hdlr_thread; + + usb_dc_status_callback status_cb; /* Status callback function */ + + struct numaker_usbd_ep_mgmt ep_mgmt; /* EP management */ +}; + +static inline const struct device *numaker_usbd_device_get(void); + +static inline void numaker_usbd_lock(const struct device *dev) +{ + struct numaker_usbd_data *data = dev->data; + + k_mutex_lock(&data->sync_mutex, K_FOREVER); +} + +static inline void numaker_usbd_unlock(const struct device *dev) +{ + struct numaker_usbd_data *data = dev->data; + + k_mutex_unlock(&data->sync_mutex); +} + +static inline void numaker_usbd_sw_connect(const struct device *dev) +{ + const struct numaker_usbd_config *config = dev->config; + USBD_T *const base = config->base; + + /* Clear all interrupts first for clean */ + base->INTSTS = base->INTSTS; + + /* Enable relevant interrupts */ + base->INTEN = USBD_INT_BUS | USBD_INT_USB | USBD_INT_FLDET | USBD_INT_WAKEUP | USBD_INT_SOF; + + /* Clear SE0 for connect */ + base->SE0 &= ~USBD_DRVSE0; +} + +static inline void numaker_usbd_sw_disconnect(const struct device *dev) +{ + const struct numaker_usbd_config *config = dev->config; + USBD_T *const base = config->base; + + /* Set SE0 for disconnect */ + base->SE0 |= USBD_DRVSE0; +} + +static inline void numaker_usbd_sw_reconnect(const struct device *dev) +{ + /* Keep SE0 to trigger bus reset */ + numaker_usbd_sw_disconnect(dev); + k_sleep(K_USEC(NUMAKER_USBD_BUS_RESET_DRV_SE0_US)); + numaker_usbd_sw_connect(dev); +} + +static inline void numaker_usbd_reset_addr(const struct device *dev) +{ + const struct numaker_usbd_config *config = dev->config; + struct numaker_usbd_data *data = dev->data; + USBD_T *const base = config->base; + + base->FADDR = 0; + data->addr = 0; +} + +static inline void numaker_usbd_set_addr(const struct device *dev) +{ + const struct numaker_usbd_config *config = dev->config; + struct numaker_usbd_data *data = dev->data; + USBD_T *const base = config->base; + + if (base->FADDR != data->addr) { + base->FADDR = data->addr; + } +} + +/* USBD EP base by e.g. EP0, EP1, ... */ +static inline USBD_EP_T *numaker_usbd_ep_base(const struct device *dev, uint32_t ep_hw_idx) +{ + const struct numaker_usbd_config *config = dev->config; + USBD_T *const base = config->base; + + return base->EP + ep_hw_idx; +} + +static inline uint32_t numaker_usbd_ep_fifo_max(struct numaker_usbd_ep *ep_cur) +{ + /* NOTE: For one-shot implementation, effective size of EP FIFO is limited to EP MPS */ + __ASSERT_NO_MSG(ep_cur->dmabuf_valid); + __ASSERT_NO_MSG(ep_cur->mps_valid); + __ASSERT_NO_MSG(ep_cur->mps <= ep_cur->dmabuf_size); + return ep_cur->mps; +} + +static inline uint32_t numaker_usbd_ep_fifo_used(struct numaker_usbd_ep *ep_cur) +{ + __ASSERT_NO_MSG(ep_cur->dmabuf_valid); + + return USB_EP_DIR_IS_OUT(ep_cur->addr) + ? ep_cur->read_fifo_used + : numaker_usbd_ep_fifo_max(ep_cur) - ep_cur->write_fifo_free; +} + +/* Reset EP FIFO + * + * NOTE: EP FIFO is based on EP DMA buffer, which may not be configured yet. + */ +static void numaker_usbd_ep_fifo_reset(struct numaker_usbd_ep *ep_cur) +{ + if (ep_cur->dmabuf_valid && ep_cur->mps_valid) { + if (USB_EP_DIR_IS_OUT(ep_cur->addr)) { + /* Read FIFO */ + ep_cur->read_fifo_pos = ep_cur->dmabuf_base; + ep_cur->read_fifo_used = 0; + } else { + /* Write FIFO */ + ep_cur->write_fifo_pos = ep_cur->dmabuf_base; + ep_cur->write_fifo_free = numaker_usbd_ep_fifo_max(ep_cur); + } + } +} + +static inline void numaker_usbd_ep_set_stall(struct numaker_usbd_ep *ep_cur) +{ + const struct device *dev = ep_cur->dev; + USBD_EP_T *ep_base = numaker_usbd_ep_base(dev, ep_cur->ep_hw_idx); + + /* Set EP to stalled */ + ep_base->CFGP |= USBD_CFGP_SSTALL_Msk; +} + +/* Reset EP to unstalled and data toggle bit to 0 */ +static inline void numaker_usbd_ep_clear_stall_n_data_toggle(struct numaker_usbd_ep *ep_cur) +{ + const struct device *dev = ep_cur->dev; + USBD_EP_T *ep_base = numaker_usbd_ep_base(dev, ep_cur->ep_hw_idx); + + /* Reset EP to unstalled */ + ep_base->CFGP &= ~USBD_CFGP_SSTALL_Msk; + + /* Reset EP data toggle bit to 0 */ + ep_base->CFG &= ~USBD_CFG_DSQSYNC_Msk; +} + +static inline bool numaker_usbd_ep_is_stalled(struct numaker_usbd_ep *ep_cur) +{ + const struct device *dev = ep_cur->dev; + USBD_EP_T *ep_base = numaker_usbd_ep_base(dev, ep_cur->ep_hw_idx); + + return ep_base->CFGP & USBD_CFGP_SSTALL_Msk; +} + +static int numaker_usbd_send_msg(const struct device *dev, const struct numaker_usbd_msg *msg) +{ + struct numaker_usbd_data *data = dev->data; + int rc; + + rc = k_msgq_put(&data->msgq, msg, K_NO_WAIT); + if (rc < 0) { + /* Try to recover by S/W reconnect */ + struct numaker_usbd_msg msg_reconn = { + .type = NUMAKER_USBD_MSG_TYPE_SW_RECONN, + }; + + LOG_ERR("Message queue overflow"); + + /* Discard all not yet received messages for error recovery below */ + k_msgq_purge(&data->msgq); + + rc = k_msgq_put(&data->msgq, &msg_reconn, K_NO_WAIT); + if (rc < 0) { + LOG_ERR("Message queue overflow again"); + } + } + + return rc; +} + +static int numaker_usbd_hw_setup(const struct device *dev) +{ + const struct numaker_usbd_config *config = dev->config; + USBD_T *const base = config->base; + int rc; + struct numaker_scc_subsys scc_subsys; + + /* Reset controller ready? */ + if (!device_is_ready(config->reset.dev)) { + LOG_ERR("Reset controller not ready"); + return -ENODEV; + } + + SYS_UnlockReg(); + + /* Configure USB PHY for USBD */ + SYS->USBPHY = (SYS->USBPHY & ~SYS_USBPHY_USBROLE_Msk) | + (SYS_USBPHY_USBROLE_STD_USBD | SYS_USBPHY_USBEN_Msk | SYS_USBPHY_SBO_Msk); + + /* Invoke Clock controller to enable module clock */ + memset(&scc_subsys, 0x00, sizeof(scc_subsys)); + scc_subsys.subsys_id = NUMAKER_SCC_SUBSYS_ID_PCC; + scc_subsys.pcc.clk_modidx = config->clk_modidx; + scc_subsys.pcc.clk_src = config->clk_src; + scc_subsys.pcc.clk_div = config->clk_div; + + /* Equivalent to CLK_EnableModuleClock() */ + rc = clock_control_on(config->clkctrl_dev, (clock_control_subsys_t)&scc_subsys); + if (rc < 0) { + goto cleanup; + } + /* Equivalent to CLK_SetModuleClock() */ + rc = clock_control_configure(config->clkctrl_dev, (clock_control_subsys_t)&scc_subsys, + NULL); + if (rc < 0) { + goto cleanup; + } + + /* Configure pinmux (NuMaker's SYS MFP) */ + rc = pinctrl_apply_state(config->pincfg, PINCTRL_STATE_DEFAULT); + if (rc < 0) { + goto cleanup; + } + + /* Invoke Reset controller to reset module to default state */ + /* Equivalent to SYS_ResetModule() + */ + reset_line_toggle_dt(&config->reset); + + /* Initialize USBD engine */ + /* NOTE: BSP USBD driver: ATTR = 0x7D0 */ + base->ATTR = USBD_ATTR_BYTEM_Msk | BIT(9) | USBD_ATTR_DPPUEN_Msk | USBD_ATTR_USBEN_Msk | + BIT(6) | USBD_ATTR_PHYEN_Msk; + + /* Set SE0 for S/W disconnect */ + numaker_usbd_sw_disconnect(dev); + + /* NOTE: Ignore DT maximum-speed with USBD fixed to full-speed */ + + /* Initialize IRQ */ + config->irq_config_func(dev); + +cleanup: + + SYS_LockReg(); + + return rc; +} + +static void numaker_usbd_hw_shutdown(const struct device *dev) +{ + const struct numaker_usbd_config *config = dev->config; + USBD_T *const base = config->base; + struct numaker_scc_subsys scc_subsys; + + SYS_UnlockReg(); + + /* Uninitialize IRQ */ + config->irq_unconfig_func(dev); + + /* Set SE0 for S/W disconnect */ + numaker_usbd_sw_disconnect(dev); + + /* Disable USB PHY */ + base->ATTR &= ~USBD_PHY_EN; + + /* Invoke Clock controller to disable module clock */ + memset(&scc_subsys, 0x00, sizeof(scc_subsys)); + scc_subsys.subsys_id = NUMAKER_SCC_SUBSYS_ID_PCC; + scc_subsys.pcc.clk_modidx = config->clk_modidx; + + /* Equivalent to CLK_DisableModuleClock() */ + clock_control_off(config->clkctrl_dev, (clock_control_subsys_t)&scc_subsys); + + /* Invoke Reset controller to reset module to default state */ + /* Equivalent to SYS_ResetModule() */ + reset_line_toggle_dt(&config->reset); + + SYS_LockReg(); +} + +/* Interrupt top half processing for bus reset */ +static void numaker_usbd_bus_reset_th(const struct device *dev) +{ + const struct numaker_usbd_config *config = dev->config; + USBD_EP_T *ep_base; + + for (uint32_t i = 0ul; i < config->num_bidir_endpoints; i++) { + ep_base = numaker_usbd_ep_base(dev, EP0 + i); + + /* Cancel EP on-going transaction */ + ep_base->CFGP |= USBD_CFGP_CLRRDY_Msk; + + /* Reset EP to unstalled */ + ep_base->CFGP &= ~USBD_CFGP_SSTALL_Msk; + + /* Reset EP data toggle bit to 0 */ + ep_base->CFG &= ~USBD_CFG_DSQSYNC_Msk; + + /* Except EP0/EP1 kept resident for CTRL OUT/IN, disable all other EPs */ + if (i >= 2) { + ep_base->CFG = 0; + } + } + + numaker_usbd_reset_addr(dev); +} + +static void numaker_usbd_remote_wakeup(const struct device *dev) +{ + const struct numaker_usbd_config *config = dev->config; + USBD_T *const base = config->base; + + /* Enable back USB/PHY first */ + base->ATTR |= USBD_ATTR_USBEN_Msk | USBD_ATTR_PHYEN_Msk; + + /* Then generate 'K' */ + base->ATTR |= USBD_ATTR_RWAKEUP_Msk; + k_sleep(K_USEC(NUMAKER_USBD_BUS_RESUME_DRV_K_US)); + base->ATTR ^= USBD_ATTR_RWAKEUP_Msk; +} + +/* USBD SRAM base for DMA */ +static inline uint32_t numaker_usbd_buf_base(const struct device *dev) +{ + const struct numaker_usbd_config *config = dev->config; + USBD_T *const base = config->base; + + return ((uint32_t)base + 0x800ul); +} + +/* Copy to user buffer from Setup FIFO */ +static void numaker_usbd_setup_fifo_copy_to_user(const struct device *dev, uint8_t *usrbuf) +{ + const struct numaker_usbd_config *config = dev->config; + USBD_T *const base = config->base; + uint32_t dmabuf_addr; + + dmabuf_addr = numaker_usbd_buf_base(dev) + (base->STBUFSEG & USBD_STBUFSEG_STBUFSEG_Msk); + + bytecpy(usrbuf, (uint8_t *)dmabuf_addr, 8ul); +} + +/* Copy data to user buffer from EP FIFO + * + * size_p holds size to copy/copied on input/output + */ +static int numaker_usbd_ep_fifo_copy_to_user(struct numaker_usbd_ep *ep_cur, uint8_t *usrbuf, + uint32_t *size_p) +{ + const struct device *dev = ep_cur->dev; + uint32_t dmabuf_addr; + + __ASSERT_NO_MSG(size_p); + __ASSERT_NO_MSG(ep_cur->dmabuf_valid); + + dmabuf_addr = numaker_usbd_buf_base(dev) + ep_cur->read_fifo_pos; + + /* Clamp to read FIFO used count */ + *size_p = MIN(*size_p, numaker_usbd_ep_fifo_used(ep_cur)); + + bytecpy(usrbuf, (uint8_t *)dmabuf_addr, *size_p); + + /* Advance read FIFO */ + ep_cur->read_fifo_pos += *size_p; + ep_cur->read_fifo_used -= *size_p; + if (ep_cur->read_fifo_used == 0) { + ep_cur->read_fifo_pos = ep_cur->dmabuf_base; + } + + return 0; +} + +/* Copy data from user buffer to EP FIFO + * + * size_p holds size to copy/copied on input/output + */ +static int numaker_usbd_ep_fifo_copy_from_user(struct numaker_usbd_ep *ep_cur, + const uint8_t *usrbuf, uint32_t *size_p) +{ + const struct device *dev = ep_cur->dev; + USBD_EP_T *ep_base = numaker_usbd_ep_base(dev, ep_cur->ep_hw_idx); + uint32_t dmabuf_addr; + uint32_t fifo_free; + + __ASSERT_NO_MSG(size_p); + __ASSERT_NO_MSG(ep_cur->dmabuf_valid); + __ASSERT_NO_MSG(ep_cur->mps_valid); + __ASSERT_NO_MSG(ep_cur->mps <= ep_cur->dmabuf_size); + + dmabuf_addr = numaker_usbd_buf_base(dev) + ep_base->BUFSEG; + fifo_free = numaker_usbd_ep_fifo_max(ep_cur) - numaker_usbd_ep_fifo_used(ep_cur); + + *size_p = MIN(*size_p, fifo_free); + + bytecpy((uint8_t *)dmabuf_addr, (uint8_t *)usrbuf, *size_p); + + /* Advance write FIFO */ + ep_cur->write_fifo_pos += *size_p; + ep_cur->write_fifo_free -= *size_p; + if (ep_cur->write_fifo_free == 0) { + ep_cur->write_fifo_pos = ep_cur->dmabuf_base; + } + + return 0; +} + +/* Update EP read/write FIFO on DATA OUT/IN completed */ +static void numaker_usbd_ep_fifo_update(struct numaker_usbd_ep *ep_cur) +{ + const struct device *dev = ep_cur->dev; + USBD_EP_T *ep_base = numaker_usbd_ep_base(dev, ep_cur->ep_hw_idx); + + __ASSERT_NO_MSG(ep_cur->addr_valid); + __ASSERT_NO_MSG(ep_cur->dmabuf_valid); + + if (USB_EP_DIR_IS_OUT(ep_cur->addr)) { + /* Read FIFO */ + /* NOTE: For one-shot implementation, FIFO gets updated from empty. */ + ep_cur->read_fifo_pos = ep_cur->dmabuf_base; + /* NOTE: See comment on mxpld_ctrlout for why make one copy of CTRL OUT's MXPLD */ + if (USB_EP_GET_IDX(ep_cur->addr) == 0) { + ep_cur->read_fifo_used = ep_cur->mxpld_ctrlout; + } else { + ep_cur->read_fifo_used = ep_base->MXPLD; + } + } else { + /* Write FIFO */ + /* NOTE: For one-shot implementation, FIFO gets to empty. */ + ep_cur->write_fifo_pos = ep_cur->dmabuf_base; + ep_cur->write_fifo_free = numaker_usbd_ep_fifo_max(ep_cur); + } +} + +static void numaker_usbd_ep_config_dmabuf(struct numaker_usbd_ep *ep_cur, uint32_t dmabuf_base, + uint32_t dmabuf_size) +{ + const struct device *dev = ep_cur->dev; + USBD_EP_T *ep_base = numaker_usbd_ep_base(dev, ep_cur->ep_hw_idx); + + ep_base->BUFSEG = dmabuf_base; + + ep_cur->dmabuf_valid = true; + ep_cur->dmabuf_base = dmabuf_base; + ep_cur->dmabuf_size = dmabuf_size; +} + +static void numaker_usbd_ep_abort(struct numaker_usbd_ep *ep_cur) +{ + const struct device *dev = ep_cur->dev; + USBD_EP_T *ep_base = numaker_usbd_ep_base(dev, ep_cur->ep_hw_idx); + + /* Abort EP on-going transaction */ + ep_base->CFGP |= USBD_CFGP_CLRRDY_Msk; + + /* Need to clear NAK for next transaction */ + ep_cur->nak_clr = false; +} + +/* Configure EP major common parts */ +static void numaker_usbd_ep_config_major(struct numaker_usbd_ep *ep_cur, + const struct usb_dc_ep_cfg_data *const ep_cfg) +{ + const struct device *dev = ep_cur->dev; + USBD_EP_T *ep_base = numaker_usbd_ep_base(dev, ep_cur->ep_hw_idx); + + ep_cur->mps_valid = true; + ep_cur->mps = ep_cfg->ep_mps; + + /* Configure EP transfer type, DATA0/1 toggle, direction, number, etc. */ + ep_cur->ep_hw_cfg = 0; + + /* Clear STALL Response in Setup stage */ + if (ep_cfg->ep_type == USB_DC_EP_CONTROL) { + ep_cur->ep_hw_cfg |= USBD_CFG_CSTALL; + } + + /* Default to DATA0 */ + ep_cur->ep_hw_cfg &= ~USBD_CFG_DSQSYNC_Msk; + + /* Endpoint IN/OUT, though, default to disabled */ + ep_cur->ep_hw_cfg |= USBD_CFG_EPMODE_DISABLE; + + /* Isochronous or not */ + if (ep_cfg->ep_type == USB_DC_EP_ISOCHRONOUS) { + ep_cur->ep_hw_cfg |= USBD_CFG_TYPE_ISO; + } + + /* Endpoint index */ + ep_cur->ep_hw_cfg |= + (USB_EP_GET_IDX(ep_cfg->ep_addr) << USBD_CFG_EPNUM_Pos) & USBD_CFG_EPNUM_Msk; + + ep_base->CFG = ep_cur->ep_hw_cfg; +} + +static void numaker_usbd_ep_enable(struct numaker_usbd_ep *ep_cur) +{ + const struct device *dev = ep_cur->dev; + USBD_EP_T *ep_base = numaker_usbd_ep_base(dev, ep_cur->ep_hw_idx); + + /* For safe, EP (re-)enable from clean state */ + numaker_usbd_ep_abort(ep_cur); + numaker_usbd_ep_clear_stall_n_data_toggle(ep_cur); + numaker_usbd_ep_fifo_reset(ep_cur); + + /* Enable EP to IN/OUT */ + ep_cur->ep_hw_cfg &= ~USBD_CFG_STATE_Msk; + if (USB_EP_DIR_IS_IN(ep_cur->addr)) { + ep_cur->ep_hw_cfg |= USBD_CFG_EPMODE_IN; + } else { + ep_cur->ep_hw_cfg |= USBD_CFG_EPMODE_OUT; + } + + ep_base->CFG = ep_cur->ep_hw_cfg; + + /* For USBD, no separate EP interrupt control */ +} + +static void numaker_usbd_ep_disable(struct numaker_usbd_ep *ep_cur) +{ + const struct device *dev = ep_cur->dev; + USBD_EP_T *ep_base = numaker_usbd_ep_base(dev, ep_cur->ep_hw_idx); + + /* For USBD, no separate EP interrupt control */ + + /* Disable EP */ + ep_cur->ep_hw_cfg = (ep_cur->ep_hw_cfg & ~USBD_CFG_STATE_Msk) | USBD_CFG_EPMODE_DISABLE; + ep_base->CFG = ep_cur->ep_hw_cfg; +} + +/* Start EP data transaction */ +static void numaker_usbd_ep_trigger(struct numaker_usbd_ep *ep_cur, uint32_t len) +{ + const struct device *dev = ep_cur->dev; + USBD_EP_T *ep_base = numaker_usbd_ep_base(dev, ep_cur->ep_hw_idx); + + ep_base->MXPLD = len; +} + +static struct numaker_usbd_ep *numaker_usbd_ep_mgmt_alloc_ep(const struct device *dev) +{ + const struct numaker_usbd_config *config = dev->config; + struct numaker_usbd_data *data = dev->data; + struct numaker_usbd_ep_mgmt *ep_mgmt = &data->ep_mgmt; + struct numaker_usbd_ep *ep_cur = NULL; + + if (ep_mgmt->ep_idx < config->num_bidir_endpoints) { + ep_cur = ep_mgmt->ep_pool + ep_mgmt->ep_idx; + ep_mgmt->ep_idx++; + + __ASSERT_NO_MSG(!ep_cur->valid); + + /* Indicate this EP context is allocated */ + ep_cur->valid = true; + } + + return ep_cur; +} + +/* Allocate DMA buffer + * + * Return -ENOMEM on OOM error, or 0 on success with DMA buffer base/size (rounded up) allocated + */ +static int numaker_usbd_ep_mgmt_alloc_dmabuf(const struct device *dev, uint32_t size, + uint32_t *dmabuf_base_p, uint32_t *dmabuf_size_p) +{ + const struct numaker_usbd_config *config = dev->config; + struct numaker_usbd_data *data = dev->data; + struct numaker_usbd_ep_mgmt *ep_mgmt = &data->ep_mgmt; + + __ASSERT_NO_MSG(dmabuf_base_p); + __ASSERT_NO_MSG(dmabuf_size_p); + + /* Required to be 8-byte aligned */ + size = ROUND_UP(size, 8); + + ep_mgmt->dmabuf_pos += size; + if (ep_mgmt->dmabuf_pos > config->dmabuf_size) { + ep_mgmt->dmabuf_pos -= size; + return -ENOMEM; + } + + *dmabuf_base_p = ep_mgmt->dmabuf_pos - size; + *dmabuf_size_p = size; + return 0; +} + +/* Initialize all endpoint-related */ +static void numaker_usbd_ep_mgmt_init(const struct device *dev) +{ + const struct numaker_usbd_config *config = dev->config; + struct numaker_usbd_data *data = dev->data; + USBD_T *const base = config->base; + struct numaker_usbd_ep_mgmt *ep_mgmt = &data->ep_mgmt; + + struct numaker_usbd_ep *ep_cur; + struct numaker_usbd_ep *ep_end; + + /* Initialize all fields to zero except persistent */ + memset(ep_mgmt, 0x00, sizeof(*ep_mgmt)); + + ep_cur = ep_mgmt->ep_pool; + ep_end = ep_mgmt->ep_pool + config->num_bidir_endpoints; + + /* Initialize all EP contexts */ + for (; ep_cur != ep_end; ep_cur++) { + /* Pointer to the containing device */ + ep_cur->dev = dev; + + /* BSP USBD driver EP handle */ + ep_cur->ep_hw_idx = EP0 + (ep_cur - ep_mgmt->ep_pool); + } + + /* Reserve 1st/2nd EP contexts (BSP USBD driver EP0/EP1) for CTRL OUT/IN */ + ep_mgmt->ep_idx = 2; + + /* Reserve DMA buffer for Setup/CTRL OUT/CTRL IN, starting from 0 */ + ep_mgmt->dmabuf_pos = 0; + + /* Configure DMA buffer for Setup packet */ + base->STBUFSEG = ep_mgmt->dmabuf_pos; + ep_mgmt->dmabuf_pos += NUMAKER_USBD_DMABUF_SIZE_SETUP; + + /* Reserve 1st EP context (BSP USBD driver EP0) for CTRL OUT */ + ep_cur = ep_mgmt->ep_pool + 0; + ep_cur->valid = true; + ep_cur->addr_valid = true; + ep_cur->addr = USB_EP_GET_ADDR(0, USB_EP_DIR_OUT); + numaker_usbd_ep_config_dmabuf(ep_cur, ep_mgmt->dmabuf_pos, + NUMAKER_USBD_DMABUF_SIZE_CTRLOUT); + ep_mgmt->dmabuf_pos += NUMAKER_USBD_DMABUF_SIZE_CTRLOUT; + ep_cur->mps_valid = true; + ep_cur->mps = NUMAKER_USBD_DMABUF_SIZE_CTRLOUT; + + /* Reserve 2nd EP context (BSP USBD driver EP1) for CTRL IN */ + ep_cur = ep_mgmt->ep_pool + 1; + ep_cur->valid = true; + ep_cur->addr_valid = true; + ep_cur->addr = USB_EP_GET_ADDR(0, USB_EP_DIR_IN); + numaker_usbd_ep_config_dmabuf(ep_cur, ep_mgmt->dmabuf_pos, NUMAKER_USBD_DMABUF_SIZE_CTRLIN); + ep_mgmt->dmabuf_pos += NUMAKER_USBD_DMABUF_SIZE_CTRLIN; + ep_cur->mps_valid = true; + ep_cur->mps = NUMAKER_USBD_DMABUF_SIZE_CTRLIN; +} + +/* Find EP context by EP address */ +static struct numaker_usbd_ep *numaker_usbd_ep_mgmt_find_ep(const struct device *dev, + const uint8_t ep) +{ + const struct numaker_usbd_config *config = dev->config; + struct numaker_usbd_data *data = dev->data; + struct numaker_usbd_ep_mgmt *ep_mgmt = &data->ep_mgmt; + struct numaker_usbd_ep *ep_cur = ep_mgmt->ep_pool; + struct numaker_usbd_ep *ep_end = ep_mgmt->ep_pool + config->num_bidir_endpoints; + + for (; ep_cur != ep_end; ep_cur++) { + if (!ep_cur->valid) { + continue; + } + + if (!ep_cur->addr_valid) { + continue; + } + + if (ep == ep_cur->addr) { + return ep_cur; + } + } + + return NULL; +} + +/* Bind EP context to EP address */ +static struct numaker_usbd_ep *numaker_usbd_ep_mgmt_bind_ep(const struct device *dev, + const uint8_t ep) +{ + struct numaker_usbd_ep *ep_cur = numaker_usbd_ep_mgmt_find_ep(dev, ep); + + if (!ep_cur) { + ep_cur = numaker_usbd_ep_mgmt_alloc_ep(dev); + + if (!ep_cur) { + return NULL; + } + + /* Bind EP context to EP address */ + ep_cur->addr = ep; + ep_cur->addr_valid = true; + } + + /* Assert EP context bound to EP address */ + __ASSERT_NO_MSG(ep_cur->valid); + __ASSERT_NO_MSG(ep_cur->addr_valid); + __ASSERT_NO_MSG(ep_cur->addr == ep); + + return ep_cur; +} + +/* Interrupt bottom half processing for bus reset */ +static void numaker_usbd_bus_reset_bh(const struct device *dev) +{ + const struct numaker_usbd_config *config = dev->config; + struct numaker_usbd_data *data = dev->data; + struct numaker_usbd_ep_mgmt *ep_mgmt = &data->ep_mgmt; + + struct numaker_usbd_ep *ep_cur = ep_mgmt->ep_pool; + struct numaker_usbd_ep *ep_end = ep_mgmt->ep_pool + config->num_bidir_endpoints; + + for (; ep_cur != ep_end; ep_cur++) { + /* Reset EP FIFO */ + numaker_usbd_ep_fifo_reset(ep_cur); + + /* Abort EP on-going transaction and signal H/W relinquishes DMA buffer ownership */ + numaker_usbd_ep_abort(ep_cur); + + /* Reset EP to unstalled and data toggle bit to 0 */ + numaker_usbd_ep_clear_stall_n_data_toggle(ep_cur); + } + + numaker_usbd_reset_addr(dev); +} + +/* Interrupt bottom half processing for Setup/EP data transaction */ +static void numaker_usbd_ep_bh(struct numaker_usbd_ep *ep_cur, + enum usb_dc_ep_cb_status_code status_code) +{ + const struct device *dev = ep_cur->dev; + struct numaker_usbd_data *data = dev->data; + struct numaker_usbd_ep_mgmt *ep_mgmt = &data->ep_mgmt; + + if (status_code == USB_DC_EP_SETUP) { + /* Zephyr USB device stack passes Setup packet via CTRL OUT EP. */ + __ASSERT_NO_MSG(ep_cur->addr == USB_EP_GET_ADDR(0, USB_EP_DIR_OUT)); + + if (numaker_usbd_ep_fifo_used(ep_cur)) { + LOG_WRN("New Setup will override previous Control OUT data"); + } + + /* We should have reserved 1st/2nd EP contexts for CTRL OUT/IN */ + __ASSERT_NO_MSG(ep_cur->addr == USB_EP_GET_ADDR(0, USB_EP_DIR_OUT)); + __ASSERT_NO_MSG((ep_cur + 1)->addr == USB_EP_GET_ADDR(0, USB_EP_DIR_IN)); + + /* Reset CTRL OUT/IN FIFO due to new Setup packet */ + numaker_usbd_ep_fifo_reset(ep_cur); + numaker_usbd_ep_fifo_reset(ep_cur + 1); + + /* Relinquish CTRL OUT/IN DMA buffer ownership on behalf of H/W */ + numaker_usbd_ep_abort(ep_cur); + numaker_usbd_ep_abort(ep_cur + 1); + + /* Mark new Setup packet for read */ + numaker_usbd_setup_fifo_copy_to_user(dev, (uint8_t *)&ep_mgmt->setup_packet); + ep_mgmt->new_setup = true; + } else if (status_code == USB_DC_EP_DATA_OUT) { + __ASSERT_NO_MSG(USB_EP_DIR_IS_OUT(ep_cur->addr)); + + /* Update EP read FIFO */ + numaker_usbd_ep_fifo_update(ep_cur); + + /* Need to clear NAK for next transaction */ + ep_cur->nak_clr = false; + } else if (status_code == USB_DC_EP_DATA_IN) { + __ASSERT_NO_MSG(USB_EP_DIR_IS_IN(ep_cur->addr)); + + /* Update EP write FIFO */ + numaker_usbd_ep_fifo_update(ep_cur); + + /* Need to clear NAK for next transaction */ + ep_cur->nak_clr = false; + } +} + +/* Message handler for S/W reconnect */ +static void numaker_usbd_msg_sw_reconn(const struct device *dev, struct numaker_usbd_msg *msg) +{ + __ASSERT_NO_MSG(msg->type == NUMAKER_USBD_MSG_TYPE_SW_RECONN); + + /* S/W reconnect for error recovery */ + numaker_usbd_lock(dev); + numaker_usbd_sw_reconnect(dev); + numaker_usbd_unlock(dev); +} + +/* Message handler for callback for usb_dc_status_code */ +static void numaker_usbd_msg_cb_state(const struct device *dev, struct numaker_usbd_msg *msg) +{ + struct numaker_usbd_data *data = dev->data; + + __ASSERT_NO_MSG(msg->type == NUMAKER_USBD_MSG_TYPE_CB_STATE); + + /* Interrupt bottom half processing for bus reset */ + if (msg->cb_device.status_code == USB_DC_RESET) { + numaker_usbd_lock(dev); + numaker_usbd_bus_reset_bh(dev); + numaker_usbd_unlock(dev); + } + + /* NOTE: Don't run callback with our mutex locked, or we may encounter + * deadlock because the Zephyr USB device stack can have its own + * synchronization. + */ + if (data->status_cb) { + data->status_cb(msg->cb_device.status_code, NULL); + } else { + LOG_WRN("No status callback: status_code=%d", msg->cb_device.status_code); + } +} + +/* Message handler for callback for usb_dc_ep_cb_status_code */ +static void numaker_usbd_msg_cb_ep(const struct device *dev, struct numaker_usbd_msg *msg) +{ + uint8_t ep; + struct numaker_usbd_ep *ep_cur; + + __ASSERT_NO_MSG(msg->type == NUMAKER_USBD_MSG_TYPE_CB_EP); + + ep = msg->cb_ep.ep; + + /* Bind EP context to EP address */ + ep_cur = numaker_usbd_ep_mgmt_bind_ep(dev, ep); + + if (!ep_cur) { + LOG_ERR("Bind EP context: ep=0x%02x", ep); + return; + } + + /* Interrupt bottom half processing for EP */ + numaker_usbd_lock(dev); + numaker_usbd_ep_bh(ep_cur, msg->cb_ep.status_code); + numaker_usbd_unlock(dev); + + /* NOTE: Same as above, don't run callback with our mutex locked */ + if (ep_cur->cb) { + ep_cur->cb(ep, msg->cb_ep.status_code); + } else { + LOG_WRN("No EP callback: ep=0x%02x, status_code=%d", ep, msg->cb_ep.status_code); + } +} + +/* Interrupt bottom half processing + * + * This thread is used to not run Zephyr USB device stack and callbacks in interrupt + * context. This is because callbacks from this stack may use mutex or other kernel functions + * which are not supported in interrupt context. + */ +static void numaker_usbd_msg_hdlr_thread_main(void *arg1, void *arg2, void *arg3) +{ + const struct device *dev = (const struct device *)arg1; + struct numaker_usbd_data *data = dev->data; + + struct numaker_usbd_msg msg; + + __ASSERT_NO_MSG(arg1); + ARG_UNUSED(arg2); + ARG_UNUSED(arg3); + + while (true) { + if (k_msgq_get(&data->msgq, &msg, K_FOREVER)) { + continue; + } + + switch (msg.type) { + case NUMAKER_USBD_MSG_TYPE_SW_RECONN: + numaker_usbd_msg_sw_reconn(dev, &msg); + break; + + case NUMAKER_USBD_MSG_TYPE_CB_STATE: + numaker_usbd_msg_cb_state(dev, &msg); + break; + + case NUMAKER_USBD_MSG_TYPE_CB_EP: + numaker_usbd_msg_cb_ep(dev, &msg); + break; + + default: + __ASSERT_NO_MSG(false); + } + } +} + +static void numaker_udbd_isr(const struct device *dev) +{ + const struct numaker_usbd_config *config = dev->config; + struct numaker_usbd_data *data = dev->data; + USBD_T *const base = config->base; + struct numaker_usbd_ep_mgmt *ep_mgmt = &data->ep_mgmt; + + struct numaker_usbd_msg msg = {0}; + + uint32_t volatile usbd_intsts = base->INTSTS; + uint32_t volatile usbd_bus_state = base->ATTR; + + /* USB plug-in/unplug */ + if (usbd_intsts & USBD_INTSTS_FLDET) { + /* Floating detect */ + base->INTSTS = USBD_INTSTS_FLDET; + + if (base->VBUSDET & USBD_VBUSDET_VBUSDET_Msk) { + /* USB plug-in */ + + /* Enable back USB/PHY */ + base->ATTR |= USBD_ATTR_USBEN_Msk | USBD_ATTR_PHYEN_Msk; + + /* Message for bottom-half processing */ + msg.type = NUMAKER_USBD_MSG_TYPE_CB_STATE; + msg.cb_device.status_code = USB_DC_CONNECTED; + numaker_usbd_send_msg(dev, &msg); + + LOG_DBG("USB plug-in"); + } else { + /* USB unplug */ + + /* Disable USB */ + base->ATTR &= ~USBD_USB_EN; + + /* Message for bottom-half processing */ + msg.type = NUMAKER_USBD_MSG_TYPE_CB_STATE; + msg.cb_device.status_code = USB_DC_DISCONNECTED; + numaker_usbd_send_msg(dev, &msg); + + LOG_DBG("USB unplug"); + } + } + + /* USB wake-up */ + if (usbd_intsts & USBD_INTSTS_WAKEUP) { + /* Clear event flag */ + base->INTSTS = USBD_INTSTS_WAKEUP; + + LOG_DBG("USB wake-up"); + } + + /* USB reset/suspend/resume */ + if (usbd_intsts & USBD_INTSTS_BUS) { + /* Clear event flag */ + base->INTSTS = USBD_INTSTS_BUS; + + if (usbd_bus_state & USBD_STATE_USBRST) { + /* Bus reset */ + + /* Enable back USB/PHY */ + base->ATTR |= USBD_ATTR_USBEN_Msk | USBD_ATTR_PHYEN_Msk; + + /* Bus reset top half */ + numaker_usbd_bus_reset_th(dev); + + /* Message for bottom-half processing */ + msg.type = NUMAKER_USBD_MSG_TYPE_CB_STATE; + msg.cb_device.status_code = USB_DC_RESET; + numaker_usbd_send_msg(dev, &msg); + + LOG_DBG("USB reset"); + } + if (usbd_bus_state & USBD_STATE_SUSPEND) { + /* Enable USB but disable PHY */ + base->ATTR &= ~USBD_PHY_EN; + + /* Message for bottom-half processing */ + msg.type = NUMAKER_USBD_MSG_TYPE_CB_STATE; + msg.cb_device.status_code = USB_DC_SUSPEND; + numaker_usbd_send_msg(dev, &msg); + + LOG_DBG("USB suspend"); + } + if (usbd_bus_state & USBD_STATE_RESUME) { + /* Enable back USB/PHY */ + base->ATTR |= USBD_ATTR_USBEN_Msk | USBD_ATTR_PHYEN_Msk; + + /* Message for bottom-half processing */ + msg.type = NUMAKER_USBD_MSG_TYPE_CB_STATE; + msg.cb_device.status_code = USB_DC_RESUME; + numaker_usbd_send_msg(dev, &msg); + + LOG_DBG("USB resume"); + } + } + + /* USB SOF */ + if (usbd_intsts & USBD_INTSTS_SOFIF_Msk) { + /* Clear event flag */ + base->INTSTS = USBD_INTSTS_SOFIF_Msk; + + /* Message for bottom-half processing */ + msg.type = NUMAKER_USBD_MSG_TYPE_CB_STATE; + msg.cb_device.status_code = USB_DC_SOF; + numaker_usbd_send_msg(dev, &msg); + } + + /* USB Setup/EP */ + if (usbd_intsts & USBD_INTSTS_USB) { + uint32_t epintsts; + + /* Setup event */ + if (usbd_intsts & USBD_INTSTS_SETUP) { + USBD_EP_T *ep0_base = numaker_usbd_ep_base(dev, EP0); + USBD_EP_T *ep1_base = numaker_usbd_ep_base(dev, EP1); + + /* Clear event flag */ + base->INTSTS = USBD_INTSTS_SETUP; + + /* Clear the data IN/OUT ready flag of control endpoints */ + ep0_base->CFGP |= USBD_CFGP_CLRRDY_Msk; + ep1_base->CFGP |= USBD_CFGP_CLRRDY_Msk; + + /* By USB spec, following transactions, regardless of Data/Status stage, + * will always be DATA1 + */ + ep0_base->CFG |= USBD_CFG_DSQSYNC_Msk; + ep1_base->CFG |= USBD_CFG_DSQSYNC_Msk; + + /* Message for bottom-half processing */ + /* NOTE: In Zephyr USB device stack, Setup packet is passed via + * CTRL OUT EP + */ + msg.type = NUMAKER_USBD_MSG_TYPE_CB_EP; + msg.cb_ep.ep = USB_EP_GET_ADDR(0, USB_EP_DIR_OUT); + msg.cb_ep.status_code = USB_DC_EP_SETUP; + numaker_usbd_send_msg(dev, &msg); + } + + /* EP events */ + epintsts = base->EPINTSTS; + + base->EPINTSTS = epintsts; + + while (epintsts) { + uint32_t ep_hw_idx = u32_count_trailing_zeros(epintsts); + USBD_EP_T *ep_base = numaker_usbd_ep_base(dev, ep_hw_idx); + uint8_t ep_dir; + uint8_t ep_idx; + uint8_t ep; + + /* We don't enable INNAKEN interrupt, so as long as EP event occurs, + * we can just regard one data transaction has completed (ACK for + * CTRL/BULK/INT or no-ACK for Iso), that is, no need to check EPSTS0, + * EPSTS1, etc. + */ + + /* EP direction, number, and address */ + ep_dir = ((ep_base->CFG & USBD_CFG_STATE_Msk) == USBD_CFG_EPMODE_IN) + ? USB_EP_DIR_IN + : USB_EP_DIR_OUT; + ep_idx = (ep_base->CFG & USBD_CFG_EPNUM_Msk) >> USBD_CFG_EPNUM_Pos; + ep = USB_EP_GET_ADDR(ep_idx, ep_dir); + + /* NOTE: See comment in usb_dc_set_address()'s implementation + * for safe place to change USB device address + */ + if (ep == USB_EP_GET_ADDR(0, USB_EP_DIR_IN)) { + numaker_usbd_set_addr(dev); + } + + /* NOTE: See comment on mxpld_ctrlout for why make one copy of + * CTRL OUT's MXPLD + */ + if (ep == USB_EP_GET_ADDR(0, USB_EP_DIR_OUT)) { + struct numaker_usbd_ep *ep_ctrlout = ep_mgmt->ep_pool + 0; + USBD_EP_T *ep_ctrlout_base = + numaker_usbd_ep_base(dev, ep_ctrlout->ep_hw_idx); + + ep_ctrlout->mxpld_ctrlout = ep_ctrlout_base->MXPLD; + } + + /* Message for bottom-half processing */ + msg.type = NUMAKER_USBD_MSG_TYPE_CB_EP; + msg.cb_ep.ep = ep; + msg.cb_ep.status_code = + USB_EP_DIR_IS_IN(ep) ? USB_DC_EP_DATA_IN : USB_DC_EP_DATA_OUT; + numaker_usbd_send_msg(dev, &msg); + + /* Have handled this EP and go next */ + epintsts &= ~BIT(ep_hw_idx); + } + } +} + +/* Zephyr USB device controller API implementation */ + +int usb_dc_attach(void) +{ + const struct device *dev = numaker_usbd_device_get(); + int rc; + + numaker_usbd_lock(dev); + + /* Initialize USB DC H/W */ + rc = numaker_usbd_hw_setup(dev); + if (rc < 0) { + LOG_ERR("Set up H/W"); + goto cleanup; + } + + /* USB device address defaults to 0 */ + numaker_usbd_reset_addr(dev); + + /* Initialize all EPs */ + numaker_usbd_ep_mgmt_init(dev); + + /* S/W connect */ + numaker_usbd_sw_connect(dev); + + LOG_DBG("attached"); + +cleanup: + + if (rc < 0) { + usb_dc_detach(); + } + + numaker_usbd_unlock(dev); + + return rc; +} + +int usb_dc_detach(void) +{ + const struct device *dev = numaker_usbd_device_get(); + struct numaker_usbd_data *data = dev->data; + + LOG_DBG("detached"); + + numaker_usbd_lock(dev); + + /* S/W disconnect */ + numaker_usbd_sw_disconnect(dev); + + /* Uninitialize USB DC H/W */ + numaker_usbd_hw_shutdown(numaker_usbd_device_get()); + + /* Purge message queue */ + k_msgq_purge(&data->msgq); + + numaker_usbd_unlock(dev); + + return 0; +} + +int usb_dc_reset(void) +{ + const struct device *dev = numaker_usbd_device_get(); + + LOG_DBG("usb_dc_reset"); + + numaker_usbd_lock(dev); + + usb_dc_detach(); + usb_dc_attach(); + + numaker_usbd_unlock(dev); + + return 0; +} + +int usb_dc_set_address(const uint8_t addr) +{ + const struct device *dev = numaker_usbd_device_get(); + struct numaker_usbd_data *data = dev->data; + + LOG_DBG("USB device address=%u (0x%02x)", addr, addr); + + numaker_usbd_lock(dev); + + /* NOTE: Timing for configuring USB device address into H/W is critical. It must be done + * in-between SET_ADDRESS control transfer and next transfer. For this, it is done in + * IN ACK ISR of SET_ADDRESS control transfer. + */ + data->addr = addr; + + numaker_usbd_unlock(dev); + + return 0; +} + +void usb_dc_set_status_callback(const usb_dc_status_callback cb) +{ + const struct device *dev = numaker_usbd_device_get(); + struct numaker_usbd_data *data = dev->data; + + numaker_usbd_lock(dev); + + data->status_cb = cb; + + numaker_usbd_unlock(dev); +} + +int usb_dc_ep_check_cap(const struct usb_dc_ep_cfg_data *const ep_cfg) +{ + const struct device *dev = numaker_usbd_device_get(); + const struct numaker_usbd_config *config = dev->config; + int rc = 0; + struct numaker_usbd_ep *ep_cur; + + numaker_usbd_lock(dev); + + /* For safe, require EP number for control transfer to be 0 */ + if ((ep_cfg->ep_type == USB_DC_EP_CONTROL) && USB_EP_GET_IDX(ep_cfg->ep_addr) != 0) { + LOG_ERR("EP number for control transfer must be 0"); + rc = -ENOTSUP; + goto cleanup; + } + + /* Some soc series don't allow ISO IN/OUT to be assigned the same EP number. + * This is addressed by limiting all OUT/IN EP addresses in top/bottom halves, + * except CTRL OUT/IN. + */ + if (config->disallow_iso_inout_same && ep_cfg->ep_type != USB_DC_EP_CONTROL) { + /* Limit all OUT EP addresses in top-half, except CTRL OUT */ + if (USB_EP_DIR_IS_OUT(ep_cfg->ep_addr) && USB_EP_GET_IDX(ep_cfg->ep_addr) >= 8) { + LOG_DBG("Support only ISO OUT EP address 0x01~0x07: 0x%02x", + ep_cfg->ep_addr); + rc = -ENOTSUP; + goto cleanup; + } + + /* Limit all IN EP addresses in bottom-half , except CTRL IN */ + if (USB_EP_DIR_IS_IN(ep_cfg->ep_addr) && USB_EP_GET_IDX(ep_cfg->ep_addr) < 8) { + LOG_DBG("Support only ISO IN EP address 0x88~0x8F: 0x%02x", + ep_cfg->ep_addr); + rc = -ENOTSUP; + goto cleanup; + } + } + + /* To respect this capability check, pre-bind EP context to EP address, + * and pre-determined its type + */ + ep_cur = numaker_usbd_ep_mgmt_bind_ep(dev, ep_cfg->ep_addr); + if (!ep_cur) { + LOG_ERR("Bind EP context: ep=0x%02x", ep_cfg->ep_addr); + rc = -ENOMEM; + goto cleanup; + } + +cleanup: + + numaker_usbd_unlock(dev); + + return rc; +} + +int usb_dc_ep_set_callback(const uint8_t ep, const usb_dc_ep_callback cb) +{ + const struct device *dev = numaker_usbd_device_get(); + int rc = 0; + struct numaker_usbd_ep *ep_cur; + + numaker_usbd_lock(dev); + + /* Bind EP context to EP address */ + ep_cur = numaker_usbd_ep_mgmt_bind_ep(dev, ep); + + if (!ep_cur) { + LOG_ERR("Bind EP context: ep=0x%02x", ep); + rc = -ENOMEM; + goto cleanup; + } + + ep_cur->cb = cb; + +cleanup: + + numaker_usbd_unlock(dev); + + return rc; +} + +int usb_dc_ep_configure(const struct usb_dc_ep_cfg_data *const ep_cfg) +{ + const struct device *dev = numaker_usbd_device_get(); + int rc = 0; + uint32_t dmabuf_base; + uint32_t dmabuf_size; + struct numaker_usbd_ep *ep_cur; + + LOG_DBG("EP=0x%02x, MPS=%d, Type=%d", ep_cfg->ep_addr, ep_cfg->ep_mps, ep_cfg->ep_type); + + numaker_usbd_lock(dev); + + /* Bind EP context to EP address */ + ep_cur = numaker_usbd_ep_mgmt_bind_ep(dev, ep_cfg->ep_addr); + + if (!ep_cur) { + LOG_ERR("Bind EP context: ep=0x%02x", ep_cfg->ep_addr); + rc = -ENOMEM; + goto cleanup; + } + + /* Configure EP DMA buffer */ + if (!ep_cur->dmabuf_valid || ep_cur->dmabuf_size < ep_cfg->ep_mps) { + /* Allocate DMA buffer */ + rc = numaker_usbd_ep_mgmt_alloc_dmabuf(dev, ep_cfg->ep_mps, &dmabuf_base, + &dmabuf_size); + if (rc < 0) { + LOG_ERR("Allocate DMA buffer failed"); + goto cleanup; + } + + /* Configure EP DMA buffer */ + numaker_usbd_ep_config_dmabuf(ep_cur, dmabuf_base, dmabuf_size); + } + + /* Configure EP majorly */ + numaker_usbd_ep_config_major(ep_cur, ep_cfg); + +cleanup: + + numaker_usbd_unlock(dev); + + return rc; +} + +int usb_dc_ep_set_stall(const uint8_t ep) +{ + const struct device *dev = numaker_usbd_device_get(); + int rc = 0; + struct numaker_usbd_ep *ep_cur; + + LOG_DBG("Set stall: ep=0x%02x", ep); + + numaker_usbd_lock(dev); + + /* Bind EP context to EP address */ + ep_cur = numaker_usbd_ep_mgmt_bind_ep(dev, ep); + + if (!ep_cur) { + LOG_ERR("Bind EP context: ep=0x%02x", ep); + rc = -ENOMEM; + goto cleanup; + } + + /* Set EP to stalled */ + numaker_usbd_ep_set_stall(ep_cur); + +cleanup: + + numaker_usbd_unlock(dev); + + return rc; +} + +int usb_dc_ep_clear_stall(const uint8_t ep) +{ + const struct device *dev = numaker_usbd_device_get(); + int rc = 0; + struct numaker_usbd_ep *ep_cur; + + LOG_DBG("Clear stall: ep=0x%02x", ep); + + numaker_usbd_lock(dev); + + /* Bind EP context to EP address */ + ep_cur = numaker_usbd_ep_mgmt_bind_ep(dev, ep); + + if (!ep_cur) { + LOG_ERR("Bind EP context: ep=0x%02x", ep); + rc = -ENOMEM; + goto cleanup; + } + + /* Reset EP to unstalled and data toggle bit to 0 */ + numaker_usbd_ep_clear_stall_n_data_toggle(ep_cur); + +cleanup: + + numaker_usbd_unlock(dev); + + return rc; +} + +int usb_dc_ep_is_stalled(const uint8_t ep, uint8_t *const stalled) +{ + const struct device *dev = numaker_usbd_device_get(); + int rc = 0; + struct numaker_usbd_ep *ep_cur; + + if (!stalled) { + return -EINVAL; + } + + numaker_usbd_lock(dev); + + /* Bind EP context to EP address */ + ep_cur = numaker_usbd_ep_mgmt_bind_ep(dev, ep); + + if (!ep_cur) { + LOG_ERR("Bind EP context: ep=0x%02x", ep); + rc = -ENOMEM; + goto cleanup; + } + + *stalled = numaker_usbd_ep_is_stalled(ep_cur); + +cleanup: + + numaker_usbd_unlock(dev); + + return rc; +} + +int usb_dc_ep_halt(const uint8_t ep) +{ + return usb_dc_ep_set_stall(ep); +} + +int usb_dc_ep_enable(const uint8_t ep) +{ + const struct device *dev = numaker_usbd_device_get(); + int rc = 0; + struct numaker_usbd_ep *ep_cur; + + LOG_DBG("Enable: ep=0x%02x", ep); + + numaker_usbd_lock(dev); + + /* Bind EP context to EP address */ + ep_cur = numaker_usbd_ep_mgmt_bind_ep(dev, ep); + + if (!ep_cur) { + LOG_ERR("Bind EP context: ep=0x%02x", ep); + rc = -ENOMEM; + goto cleanup; + } + + numaker_usbd_ep_enable(ep_cur); + + /* Trigger OUT transaction manually, or H/W will continue to reply NAK because + * Zephyr USB device stack is unclear on kicking off by invoking usb_dc_ep_read() + * or friends. We needn't do this for CTRL OUT because Setup sequence will involve + * this. + */ + if (USB_EP_DIR_IS_OUT(ep) && USB_EP_GET_IDX(ep) != 0) { + rc = usb_dc_ep_read_continue(ep); + if (rc < 0) { + goto cleanup; + } + } + +cleanup: + + numaker_usbd_unlock(dev); + + return rc; +} + +int usb_dc_ep_disable(const uint8_t ep) +{ + const struct device *dev = numaker_usbd_device_get(); + int rc = 0; + struct numaker_usbd_ep *ep_cur; + + LOG_DBG("Disable: ep=0x%02x", ep); + + numaker_usbd_lock(dev); + + /* Bind EP context to EP address */ + ep_cur = numaker_usbd_ep_mgmt_bind_ep(dev, ep); + + if (!ep_cur) { + LOG_ERR("Bind EP context: ep=0x%02x", ep); + rc = -ENOMEM; + goto cleanup; + } + + numaker_usbd_ep_disable(ep_cur); + +cleanup: + + numaker_usbd_unlock(dev); + + return rc; +} + +int usb_dc_ep_flush(const uint8_t ep) +{ + const struct device *dev = numaker_usbd_device_get(); + int rc = 0; + struct numaker_usbd_ep *ep_cur; + + LOG_DBG("ep=0x%02x", ep); + + numaker_usbd_lock(dev); + + /* Bind EP context to EP address */ + ep_cur = numaker_usbd_ep_mgmt_bind_ep(dev, ep); + + if (!ep_cur) { + LOG_ERR("Bind EP context: ep=0x%02x", ep); + rc = -ENOMEM; + goto cleanup; + } + + numaker_usbd_ep_fifo_reset(ep_cur); + +cleanup: + + numaker_usbd_unlock(dev); + + return rc; +} + +int usb_dc_ep_write(const uint8_t ep, const uint8_t *const data_buf, const uint32_t data_len, + uint32_t *const ret_bytes) +{ + const struct device *dev = numaker_usbd_device_get(); + int rc = 0; + struct numaker_usbd_ep *ep_cur; + uint32_t data_len_act; + + numaker_usbd_lock(dev); + + /* Bind EP context to EP address */ + ep_cur = numaker_usbd_ep_mgmt_bind_ep(dev, ep); + + if (!ep_cur) { + LOG_ERR("ep=0x%02x", ep); + rc = -ENOMEM; + goto cleanup; + } + + if (!USB_EP_DIR_IS_IN(ep)) { + LOG_ERR("Invalid EP address 0x%02x for write", ep); + rc = -EINVAL; + goto cleanup; + } + + /* For USBD, avoid duplicate NAK clear */ + if (ep_cur->nak_clr) { + LOG_WRN("ep 0x%02x busy", ep); + rc = -EAGAIN; + goto cleanup; + } + + /* For one-shot implementation, don't trigger next DATA IN with write FIFO not empty. */ + if (numaker_usbd_ep_fifo_used(ep_cur)) { + LOG_WRN("ep 0x%02x: Write FIFO not empty for one-shot implementation", ep); + rc = -EAGAIN; + goto cleanup; + } + + /* NOTE: Null data or zero data length are valid, used for ZLP */ + if (data_buf && data_len) { + data_len_act = data_len; + rc = numaker_usbd_ep_fifo_copy_from_user(ep_cur, data_buf, &data_len_act); + if (rc < 0) { + LOG_ERR("Copy to FIFO from user buffer"); + goto cleanup; + } + } else { + data_len_act = 0; + } + + /* Now H/W actually owns EP DMA buffer */ + numaker_usbd_ep_trigger(ep_cur, data_len_act); + + /* NOTE: For one-shot implementation, at most MPS size can be written, though, + * null 'ret_bytes' requires all data written. + */ + if (ret_bytes) { + *ret_bytes = data_len_act; + } else if (data_len_act != data_len) { + LOG_ERR("Expected write all %d bytes, but actual %d bytes written", data_len, + data_len_act); + rc = -EIO; + goto cleanup; + } + +cleanup: + + numaker_usbd_unlock(dev); + + return rc; +} + +int usb_dc_ep_read(const uint8_t ep, uint8_t *const data, const uint32_t max_data_len, + uint32_t *const read_bytes) +{ + const struct device *dev = numaker_usbd_device_get(); + int rc = 0; + + numaker_usbd_lock(dev); + + rc = usb_dc_ep_read_wait(ep, data, max_data_len, read_bytes); + if (rc < 0) { + goto cleanup; + } + + rc = usb_dc_ep_read_continue(ep); + if (rc < 0) { + goto cleanup; + } + +cleanup: + + numaker_usbd_unlock(dev); + + return rc; +} + +int usb_dc_ep_read_wait(uint8_t ep, uint8_t *data_buf, uint32_t max_data_len, uint32_t *read_bytes) +{ + const struct device *dev = numaker_usbd_device_get(); + struct numaker_usbd_data *data = dev->data; + int rc = 0; + struct numaker_usbd_ep_mgmt *ep_mgmt = &data->ep_mgmt; + struct numaker_usbd_ep *ep_cur; + uint32_t data_len_act = 0; + + numaker_usbd_lock(dev); + + /* Bind EP context to EP address */ + ep_cur = numaker_usbd_ep_mgmt_bind_ep(dev, ep); + + if (!ep_cur) { + LOG_ERR("Bind EP context: ep=0x%02x", ep); + rc = -ENOMEM; + goto cleanup; + } + + if (!USB_EP_DIR_IS_OUT(ep)) { + LOG_ERR("Invalid EP address 0x%02x for read", ep); + rc = -EINVAL; + goto cleanup; + } + + /* Special handling for USB_CONTROL_EP_OUT on Setup packet */ + if (ep == USB_CONTROL_EP_OUT && ep_mgmt->new_setup) { + if (!data_buf || max_data_len != 8) { + LOG_ERR("Invalid parameter for reading Setup packet"); + rc = -EINVAL; + goto cleanup; + } + + memcpy(data_buf, &ep_mgmt->setup_packet, 8); + ep_mgmt->new_setup = false; + + if (read_bytes) { + *read_bytes = 8; + } + + goto cleanup; + } + + /* For one-shot implementation, don't read FIFO with EP busy. */ + if (ep_cur->nak_clr) { + LOG_WRN("ep 0x%02x busy", ep); + rc = -EAGAIN; + goto cleanup; + } + + /* NOTE: Null data and zero data length is valid, used for returning number of + * available bytes for read + */ + if (data_buf) { + data_len_act = max_data_len; + rc = numaker_usbd_ep_fifo_copy_to_user(ep_cur, data_buf, &data_len_act); + if (rc < 0) { + LOG_ERR("Copy from FIFO to user buffer"); + goto cleanup; + } + + if (read_bytes) { + *read_bytes = data_len_act; + } + } else if (max_data_len) { + LOG_ERR("Null data but non-zero data length"); + rc = -EINVAL; + goto cleanup; + } else { + if (read_bytes) { + *read_bytes = numaker_usbd_ep_fifo_used(ep_cur); + } + } + + /* Suppress further USB_DC_EP_DATA_OUT events by replying NAK or disabling interrupt + * + * For USBD, further control is unnecessary because NAK is automatically replied until + * next USBD_SET_PAYLOAD_LEN(). + */ + +cleanup: + + numaker_usbd_unlock(dev); + + return rc; +} + +int usb_dc_ep_read_continue(uint8_t ep) +{ + const struct device *dev = numaker_usbd_device_get(); + int rc = 0; + struct numaker_usbd_ep *ep_cur; + + numaker_usbd_lock(dev); + + /* Bind EP context to EP address */ + ep_cur = numaker_usbd_ep_mgmt_bind_ep(dev, ep); + + if (!ep_cur) { + LOG_ERR("Bind EP context: ep=0x%02x", ep); + rc = -ENOMEM; + goto cleanup; + } + + if (!USB_EP_DIR_IS_OUT(ep)) { + LOG_ERR("Invalid EP address 0x%02x for read", ep); + rc = -EINVAL; + goto cleanup; + } + + /* Avoid duplicate NAK clear */ + if (ep_cur->nak_clr) { + rc = 0; + goto cleanup; + } + + /* For one-shot implementation, don't trigger next DATA OUT, or overwrite. */ + if (numaker_usbd_ep_fifo_used(ep_cur)) { + goto cleanup; + } + + __ASSERT_NO_MSG(ep_cur->mps_valid); + numaker_usbd_ep_trigger(ep_cur, ep_cur->mps); + +cleanup: + + numaker_usbd_unlock(dev); + + return rc; +} + +int usb_dc_ep_mps(const uint8_t ep) +{ + const struct device *dev = numaker_usbd_device_get(); + int rc = 0; + struct numaker_usbd_ep *ep_cur; + uint16_t ep_mps = 0; + + numaker_usbd_lock(dev); + + /* Bind EP context to EP address */ + ep_cur = numaker_usbd_ep_mgmt_bind_ep(dev, ep); + + if (!ep_cur) { + LOG_ERR("Bind EP context: ep=0x%02x", ep); + rc = -ENOMEM; + goto cleanup; + } + + __ASSERT_NO_MSG(ep_cur->mps_valid); + ep_mps = ep_cur->mps; + +cleanup: + + numaker_usbd_unlock(dev); + + return rc == 0 ? ep_mps : rc; +} + +int usb_dc_wakeup_request(void) +{ + const struct device *dev = numaker_usbd_device_get(); + int rc = 0; + + LOG_DBG("Remote wakeup"); + + numaker_usbd_lock(dev); + + numaker_usbd_remote_wakeup(dev); + + numaker_usbd_unlock(dev); + + return rc; +} + +static int numaker_udbd_init(const struct device *dev) +{ + struct numaker_usbd_data *data = dev->data; + int rc = 0; + + /* Initialize all fields to zero */ + memset(data, 0x00, sizeof(*data)); + + k_mutex_init(&data->sync_mutex); + + /* Set up interrupt top/bottom halves processing */ + + k_msgq_init(&data->msgq, (char *)data->msgq_buf, sizeof(struct numaker_usbd_msg), + CONFIG_USB_DC_NUMAKER_MSG_QUEUE_SIZE); + + k_thread_create(&data->msg_hdlr_thread, data->msg_hdlr_thread_stack, + CONFIG_USB_DC_NUMAKER_MSG_HANDLER_THREAD_STACK_SIZE, + numaker_usbd_msg_hdlr_thread_main, (void *)dev, NULL, NULL, K_PRIO_COOP(2), + 0, K_NO_WAIT); + + k_thread_name_set(&data->msg_hdlr_thread, "numaker_usbd"); + + return rc; +} + +#define USB_DC_NUMAKER_INIT(inst) \ + PINCTRL_DT_INST_DEFINE(inst); \ + \ + static void numaker_usbd_irq_config_func_##inst(const struct device *dev) \ + { \ + IRQ_CONNECT(DT_INST_IRQN(inst), DT_INST_IRQ(inst, priority), numaker_udbd_isr, \ + DEVICE_DT_INST_GET(inst), 0); \ + \ + irq_enable(DT_INST_IRQN(inst)); \ + } \ + \ + static void numaker_uusbd_irq_unconfig_func_##inst(const struct device *dev) \ + { \ + irq_disable(DT_INST_IRQN(inst)); \ + } \ + \ + static const struct numaker_usbd_config numaker_usbd_config_##inst = { \ + .base = (USBD_T *)DT_INST_REG_ADDR(inst), \ + .reset = RESET_DT_SPEC_INST_GET(inst), \ + .clk_modidx = DT_INST_CLOCKS_CELL(inst, clock_module_index), \ + .clk_src = DT_INST_CLOCKS_CELL(inst, clock_source), \ + .clk_div = DT_INST_CLOCKS_CELL(inst, clock_divider), \ + .clkctrl_dev = DEVICE_DT_GET(DT_PARENT(DT_INST_CLOCKS_CTLR(inst))), \ + .irq_config_func = numaker_usbd_irq_config_func_##inst, \ + .irq_unconfig_func = numaker_uusbd_irq_unconfig_func_##inst, \ + .pincfg = PINCTRL_DT_INST_DEV_CONFIG_GET(inst), \ + .num_bidir_endpoints = DT_INST_PROP(inst, num_bidir_endpoints), \ + .dmabuf_size = DT_INST_PROP(inst, dma_buffer_size), \ + .disallow_iso_inout_same = DT_INST_PROP(inst, disallow_iso_in_out_same_number), \ + }; \ + \ + static struct numaker_usbd_data numaker_usbd_data_##inst; \ + \ + BUILD_ASSERT(DT_INST_PROP(inst, num_bidir_endpoints) <= NUMAKER_USBD_EP_MAXNUM, \ + "num_bidir_endpoints exceeds support limit by USBD driver"); \ + \ + DEVICE_DT_INST_DEFINE(inst, numaker_udbd_init, NULL, &numaker_usbd_data_##inst, \ + &numaker_usbd_config_##inst, POST_KERNEL, \ + CONFIG_KERNEL_INIT_PRIORITY_DEVICE, NULL); + +USB_DC_NUMAKER_INIT(0); + +/* Get USB DC device context instance 0 */ +static inline const struct device *numaker_usbd_device_get(void) +{ + return DEVICE_DT_INST_GET(0); +} diff --git a/dts/arm/nuvoton/m46x.dtsi b/dts/arm/nuvoton/m46x.dtsi index d73a888d21b..9e0014f2597 100644 --- a/dts/arm/nuvoton/m46x.dtsi +++ b/dts/arm/nuvoton/m46x.dtsi @@ -603,6 +603,19 @@ status = "disabled"; #io-channel-cells = <1>; }; + + usbd: usbd@400c0000 { + compatible = "nuvoton,numaker-usbd"; + reg = <0x400c0000 0x1000>; + interrupts = <53 0>; + resets = <&rst NUMAKER_USBD_RST>; + clocks = <&pcc NUMAKER_USBD_MODULE NUMAKER_CLK_CLKSEL0_USBSEL_PLL_DIV2 + NUMAKER_CLK_CLKDIV0_USB(2)>; + dma-buffer-size = <1536>; + status = "disabled"; + num-bidir-endpoints = <25>; + disallow-iso-in-out-same-number; + }; }; }; diff --git a/dts/bindings/usb/nuvoton,numaker-usbd.yaml b/dts/bindings/usb/nuvoton,numaker-usbd.yaml new file mode 100644 index 00000000000..3e688212213 --- /dev/null +++ b/dts/bindings/usb/nuvoton,numaker-usbd.yaml @@ -0,0 +1,33 @@ +# Copyright (c) 2022 Nuvoton Technology Corporation +# SPDX-License-Identifier: Apache-2.0 + +description: Nuvoton NuMaker USB 1.1 device controller + +compatible: "nuvoton,numaker-usbd" + +include: [usb-ep.yaml, reset-device.yaml, pinctrl-device.yaml] + +properties: + reg: + required: true + + interrupts: + required: true + + resets: + required: true + + clocks: + required: true + + dma-buffer-size: + type: int + required: true + description: | + Size of DMA buffer in bytes + + disallow-iso-in-out-same-number: + type: boolean + description: | + Some soc series don't allow Isochronous IN/OUT endpoints to be assigned the same numbers, + for example, 0x82 (for Isochronous IN) and 0x02 (for Isochronous OUT) are disallowed. From a97c825d649f3b353cfb1676a3c31eed05820a29 Mon Sep 17 00:00:00 2001 From: Petr Hlineny Date: Fri, 22 Sep 2023 15:25:11 +0200 Subject: [PATCH 3345/3723] drivers: i2c: stm32: Disable suspend to idle during transaction Suspend-to-idle stops I2C module clocks, which must remain active during transaction Signed-off-by: Petr Hlineny --- drivers/i2c/i2c_ll_stm32.c | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/drivers/i2c/i2c_ll_stm32.c b/drivers/i2c/i2c_ll_stm32.c index f834aa658f7..29f5a5ae08f 100644 --- a/drivers/i2c/i2c_ll_stm32.c +++ b/drivers/i2c/i2c_ll_stm32.c @@ -9,6 +9,7 @@ #include #include #include +#include #include #include #include @@ -173,10 +174,11 @@ static int i2c_stm32_transfer(const struct device *dev, struct i2c_msg *msg, /* Prevent driver from being suspended by PM until I2C transaction is complete */ #ifdef CONFIG_PM_DEVICE_RUNTIME (void)pm_device_runtime_get(dev); -#else - pm_device_busy_set(dev); #endif + /* Prevent the clocks to be stopped during the i2c transaction */ + pm_policy_state_lock_get(PM_STATE_SUSPEND_TO_IDLE, PM_ALL_SUBSTATES); + current = msg; while (num_msgs > 0) { @@ -194,10 +196,10 @@ static int i2c_stm32_transfer(const struct device *dev, struct i2c_msg *msg, num_msgs--; } + pm_policy_state_lock_put(PM_STATE_SUSPEND_TO_IDLE, PM_ALL_SUBSTATES); + #ifdef CONFIG_PM_DEVICE_RUNTIME (void)pm_device_runtime_put(dev); -#else - pm_device_busy_clear(dev); #endif k_sem_give(&data->bus_mutex); From 0bc1a2b3147d364b5cf6d73c85e629693c9c6b5f Mon Sep 17 00:00:00 2001 From: Pieter De Gendt Date: Wed, 31 Jan 2024 10:17:01 +0100 Subject: [PATCH 3346/3723] net: lib: coap: Reduce CoAP server stack usage Declare the CoAP server receiving buffer as static to lower the stack usage. Signed-off-by: Pieter De Gendt --- subsys/net/lib/coap/coap_server.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/subsys/net/lib/coap/coap_server.c b/subsys/net/lib/coap/coap_server.c index 28d5b8de47f..e8298506c4a 100644 --- a/subsys/net/lib/coap/coap_server.c +++ b/subsys/net/lib/coap/coap_server.c @@ -127,7 +127,8 @@ static int coap_service_remove_observer(const struct coap_service *service, static int coap_server_process(int sock_fd) { - uint8_t buf[CONFIG_COAP_SERVER_MESSAGE_SIZE]; + static uint8_t buf[CONFIG_COAP_SERVER_MESSAGE_SIZE]; + struct sockaddr client_addr; socklen_t client_addr_len = sizeof(client_addr); struct coap_service *service = NULL; From 5529241bc96afdb7f15b6839304d9235405f2951 Mon Sep 17 00:00:00 2001 From: Anas Nashif Date: Thu, 1 Feb 2024 11:57:23 -0500 Subject: [PATCH 3347/3723] ci: pr stats: deal with trivial+hotfix PRs deal wit the case of Trivial+Hotifx and mark it correctly in PR dashboard. Signed-off-by: Anas Nashif --- scripts/ci/stats/merged_prs.py | 14 ++++++++------ 1 file changed, 8 insertions(+), 6 deletions(-) diff --git a/scripts/ci/stats/merged_prs.py b/scripts/ci/stats/merged_prs.py index 9daaa560c2d..3111912cc63 100755 --- a/scripts/ci/stats/merged_prs.py +++ b/scripts/ci/stats/merged_prs.py @@ -92,12 +92,14 @@ def process_pr(pr): business_days = sum(1 for day in dates if day.weekday() < 5) prj['business_days_open'] = business_days - # less than 2 business days ... - if business_days < 2 and not ('Trivial' in labels or 'Hotfix' in labels) or \ - deltah < 4 and 'Trivial' in labels: - prj['time_rule'] = "no" - else: - prj['time_rule'] = "yes" + trivial = 'Trivial' in labels + hotfix = 'Hotfix' in labels + min_review_time_rule = "no" + + if hotfix or (trivial and deltah >= 4) or business_days >= 2: + min_review_time_rule = "yes" + + prj['time_rule'] = min_review_time_rule # This is all data we get easily though the Github API and serves as the basis # for displaying some trends and metrics. From d1c887e20d3266b339bb4284cc59b6543e3ba5ea Mon Sep 17 00:00:00 2001 From: Sateesh Kotapati Date: Mon, 29 Jan 2024 11:21:17 +0530 Subject: [PATCH 3348/3723] gecko: doc: Update the copyright line in Licence | Update to GSDK 4.4.0 Update the copyright line in files to latest version as per gecko_sdk 4.4.0 Correction in location of se_manager in gecko/README Signed-off-by: Sateesh Kotapati --- west.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/west.yml b/west.yml index 92dcff0d456..065c2b617b1 100644 --- a/west.yml +++ b/west.yml @@ -219,7 +219,7 @@ manifest: groups: - hal - name: hal_silabs - revision: 20024164aa2a79c186aedc721cf51d667eecb35a + revision: b11b29167f3f9a0fd0c34a8eeeb36b0c1d218917 path: modules/hal/silabs groups: - hal From 131b97956fdb2388f6e6bc92ffa722a292931a13 Mon Sep 17 00:00:00 2001 From: Fabio Baltieri Date: Thu, 1 Feb 2024 14:54:42 +0000 Subject: [PATCH 3349/3723] github: hello_world_multiplatform: run on macOS ARM Seems like GitHub introduced a macOS on ARM runner, add it to the multiplatform test, with this we are running all the SDKs minus the Linux ARM64 one. Signed-off-by: Fabio Baltieri --- .github/workflows/hello_world_multiplatform.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/hello_world_multiplatform.yaml b/.github/workflows/hello_world_multiplatform.yaml index 418c42a5307..e30b09af51d 100644 --- a/.github/workflows/hello_world_multiplatform.yaml +++ b/.github/workflows/hello_world_multiplatform.yaml @@ -26,7 +26,7 @@ jobs: strategy: fail-fast: false matrix: - os: [ubuntu-22.04, macos-12, windows-2022] + os: [ubuntu-22.04, macos-12, macos-14, windows-2022] runs-on: ${{ matrix.os }} steps: - name: Checkout From 3c76ff9a8c41d217bf6c28d930f2620cb5cd26a2 Mon Sep 17 00:00:00 2001 From: Robert Lubos Date: Fri, 26 Jan 2024 14:39:22 +0100 Subject: [PATCH 3350/3723] net: dhcpv4_server: Implement ICMP probing of offered addresses DHCPv4 server will send an ICMP probe (echo request) for the requested address before replying with DHCP Offer, unless probing is disabled in Kconfig. Signed-off-by: Robert Lubos --- subsys/net/lib/dhcpv4/Kconfig | 8 + subsys/net/lib/dhcpv4/dhcpv4_server.c | 251 ++++++++++++++++++++++++-- 2 files changed, 241 insertions(+), 18 deletions(-) diff --git a/subsys/net/lib/dhcpv4/Kconfig b/subsys/net/lib/dhcpv4/Kconfig index 3d909ccd6fe..2f8f331f2de 100644 --- a/subsys/net/lib/dhcpv4/Kconfig +++ b/subsys/net/lib/dhcpv4/Kconfig @@ -85,4 +85,12 @@ config NET_DHCPV4_SERVER_ADDR_LEASE_TIME The lease time determines when the IPv4 address lease expires if the client does not renew it. +config NET_DHCPV4_SERVER_ICMP_PROBE_TIMEOUT + int "Timeout for ICMP probes sent by the server (miliseconds)" + default 1000 + help + DHCPv4 server will probe the offered IP address (send ICMP echo + request) and wait for the time specific by this config before offering + the address. If set to 0, ICMP probing will be disabled. + endif # NET_DHCPV4_SERVER diff --git a/subsys/net/lib/dhcpv4/dhcpv4_server.c b/subsys/net/lib/dhcpv4/dhcpv4_server.c index 91daaafd4d9..f8a7e56f64a 100644 --- a/subsys/net/lib/dhcpv4/dhcpv4_server.c +++ b/subsys/net/lib/dhcpv4/dhcpv4_server.c @@ -14,6 +14,7 @@ #include #include #include +#include #include #include #include @@ -31,10 +32,29 @@ LOG_MODULE_REGISTER(net_dhcpv4_server, CONFIG_NET_DHCPV4_SERVER_LOG_LEVEL); #define DHCPV4_OPTIONS_CLIENT_ID_MIN_SIZE 2 #define ADDRESS_RESERVED_TIMEOUT K_SECONDS(5) +#define ADDRESS_PROBE_TIMEOUT K_MSEC(CONFIG_NET_DHCPV4_SERVER_ICMP_PROBE_TIMEOUT) + +#if (CONFIG_NET_DHCPV4_SERVER_ICMP_PROBE_TIMEOUT > 0) +#define DHCPV4_SERVER_ICMP_PROBE 1 +#endif /* RFC 1497 [17] */ static const uint8_t magic_cookie[4] = { 0x63, 0x82, 0x53, 0x63 }; +#define DHCPV4_MAX_PARAMETERS_REQUEST_LEN 16 + +struct dhcpv4_parameter_request_list { + uint8_t list[DHCPV4_MAX_PARAMETERS_REQUEST_LEN]; + uint8_t count; +}; + +struct dhcpv4_server_probe_ctx { + struct net_icmp_ctx icmp_ctx; + struct dhcp_msg discovery; + struct dhcpv4_parameter_request_list params; + struct dhcpv4_addr_slot *slot; +}; + struct dhcpv4_server_ctx { struct net_if *iface; int sock; @@ -42,19 +62,15 @@ struct dhcpv4_server_ctx { struct dhcpv4_addr_slot addr_pool[CONFIG_NET_DHCPV4_SERVER_ADDR_COUNT]; struct in_addr server_addr; struct in_addr netmask; +#if defined(DHCPV4_SERVER_ICMP_PROBE) + struct dhcpv4_server_probe_ctx probe_ctx; +#endif }; static struct dhcpv4_server_ctx server_ctx[CONFIG_NET_DHCPV4_SERVER_INSTANCES]; static struct zsock_pollfd fds[CONFIG_NET_DHCPV4_SERVER_INSTANCES]; static K_MUTEX_DEFINE(server_lock); -#define DHCPV4_MAX_PARAMETERS_REQUEST_LEN 16 - -struct dhcpv4_parameter_request_list { - uint8_t list[DHCPV4_MAX_PARAMETERS_REQUEST_LEN]; - uint8_t count; -}; - static void dhcpv4_server_timeout_recalc(struct dhcpv4_server_ctx *ctx) { k_timepoint_t next = sys_timepoint_calc(K_FOREVER); @@ -667,6 +683,167 @@ static uint32_t dhcpv4_get_lease_time(uint8_t *options, uint8_t optlen) return CONFIG_NET_DHCPV4_SERVER_ADDR_LEASE_TIME; } +#if defined(DHCPV4_SERVER_ICMP_PROBE) +static int dhcpv4_probe_address(struct dhcpv4_server_ctx *ctx, + struct dhcpv4_addr_slot *slot) +{ + struct sockaddr_in dest_addr = { + .sin_family = AF_INET, + .sin_addr = slot->addr, + }; + int ret; + + ret = net_icmp_send_echo_request(&ctx->probe_ctx.icmp_ctx, ctx->iface, + (struct sockaddr *)&dest_addr, + NULL, ctx); + if (ret < 0) { + LOG_ERR("Failed to send ICMP probe"); + } + + return ret; +} + +static int echo_reply_handler(struct net_icmp_ctx *icmp_ctx, + struct net_pkt *pkt, + struct net_icmp_ip_hdr *ip_hdr, + struct net_icmp_hdr *icmp_hdr, + void *user_data) +{ + struct dhcpv4_server_ctx *ctx = user_data; + struct dhcpv4_server_probe_ctx *probe_ctx = &ctx->probe_ctx; + struct dhcpv4_addr_slot *new_slot = NULL; + struct in_addr peer_addr; + + ARG_UNUSED(icmp_ctx); + ARG_UNUSED(pkt); + ARG_UNUSED(ip_hdr); + ARG_UNUSED(icmp_hdr); + + k_mutex_lock(&server_lock, K_FOREVER); + + if (probe_ctx->slot == NULL) { + goto out; + } + + if (ip_hdr->family != AF_INET) { + goto out; + } + + net_ipv4_addr_copy_raw((uint8_t *)&peer_addr, ip_hdr->ipv4->src); + if (!net_ipv4_addr_cmp(&peer_addr, &probe_ctx->slot->addr)) { + goto out; + } + + LOG_DBG("Got ICMP probe response, blocking address %s", + net_sprint_ipv4_addr(&probe_ctx->slot->addr)); + + probe_ctx->slot->state = DHCPV4_SERVER_ADDR_DECLINED; + + /* Try to find next free address */ + for (int i = 0; i < ARRAY_SIZE(ctx->addr_pool); i++) { + struct dhcpv4_addr_slot *slot = &ctx->addr_pool[i]; + + if (slot->state == DHCPV4_SERVER_ADDR_FREE) { + new_slot = slot; + break; + } + } + + if (new_slot == NULL) { + LOG_DBG("No more free addresses to assign, ICMP probing stopped"); + probe_ctx->slot = NULL; + dhcpv4_server_timeout_recalc(ctx); + goto out; + } + + if (dhcpv4_probe_address(ctx, new_slot) < 0) { + probe_ctx->slot = NULL; + dhcpv4_server_timeout_recalc(ctx); + goto out; + } + + new_slot->state = DHCPV4_SERVER_ADDR_RESERVED; + new_slot->expiry = sys_timepoint_calc(ADDRESS_PROBE_TIMEOUT); + new_slot->client_id.len = probe_ctx->slot->client_id.len; + memcpy(new_slot->client_id.buf, probe_ctx->slot->client_id.buf, + new_slot->client_id.len); + new_slot->lease_time = probe_ctx->slot->lease_time; + + probe_ctx->slot = new_slot; + + dhcpv4_server_timeout_recalc(ctx); + +out: + k_mutex_unlock(&server_lock); + + return 0; +} + +static int dhcpv4_server_probing_init(struct dhcpv4_server_ctx *ctx) +{ + return net_icmp_init_ctx(&ctx->probe_ctx.icmp_ctx, + NET_ICMPV4_ECHO_REPLY, 0, + echo_reply_handler); +} + +static void dhcpv4_server_probing_deinit(struct dhcpv4_server_ctx *ctx) +{ + (void)net_icmp_cleanup_ctx(&ctx->probe_ctx.icmp_ctx); +} + +static int dhcpv4_server_probe_setup(struct dhcpv4_server_ctx *ctx, + struct dhcpv4_addr_slot *slot, + struct dhcp_msg *msg, + struct dhcpv4_parameter_request_list *params) +{ + int ret; + + if (ctx->probe_ctx.slot != NULL) { + return -EBUSY; + } + + ret = dhcpv4_probe_address(ctx, slot); + if (ret < 0) { + return ret; + } + + ctx->probe_ctx.slot = slot; + ctx->probe_ctx.discovery = *msg; + ctx->probe_ctx.params = *params; + + return 0; +} + +static void dhcpv4_server_probe_timeout(struct dhcpv4_server_ctx *ctx, + struct dhcpv4_addr_slot *slot) +{ + /* Probe timer expired, send offer. */ + ctx->probe_ctx.slot = NULL; + + (void)net_arp_clear_pending(ctx->iface, &slot->addr); + + if (dhcpv4_send_offer(ctx, &ctx->probe_ctx.discovery, &slot->addr, + slot->lease_time, &ctx->probe_ctx.params) < 0) { + slot->state = DHCPV4_SERVER_ADDR_FREE; + return; + } + + slot->expiry = sys_timepoint_calc(ADDRESS_RESERVED_TIMEOUT); +} + +static bool dhcpv4_server_is_slot_probed(struct dhcpv4_server_ctx *ctx, + struct dhcpv4_addr_slot *slot) +{ + return (ctx->probe_ctx.slot == slot); +} +#else /* defined(DHCPV4_SERVER_ICMP_PROBE) */ +#define dhcpv4_server_probing_init(...) (0) +#define dhcpv4_server_probing_deinit(...) +#define dhcpv4_server_probe_setup(...) (-ENOTSUP) +#define dhcpv4_server_probe_timeout(...) +#define dhcpv4_server_is_slot_probed(...) (false) +#endif /* defined(DHCPV4_SERVER_ICMP_PROBE) */ + static void dhcpv4_handle_discover(struct dhcpv4_server_ctx *ctx, struct dhcp_msg *msg, uint8_t *options, uint8_t optlen) @@ -674,6 +851,7 @@ static void dhcpv4_handle_discover(struct dhcpv4_server_ctx *ctx, struct dhcpv4_parameter_request_list params = { 0 }; struct dhcpv4_addr_slot *selected = NULL; struct dhcpv4_client_id client_id; + bool probe = false; int ret; ret = dhcpv4_get_client_id(msg, options, optlen, &client_id); @@ -696,6 +874,12 @@ static void dhcpv4_handle_discover(struct dhcpv4_server_ctx *ctx, slot->client_id.len == client_id.len && memcmp(slot->client_id.buf, client_id.buf, client_id.len) == 0) { + if (slot->state == DHCPV4_SERVER_ADDR_RESERVED && + dhcpv4_server_is_slot_probed(ctx, slot)) { + LOG_DBG("ICMP probing in progress, ignore Discovery"); + return; + } + /* Got match in current bindings. */ selected = slot; break; @@ -720,6 +904,7 @@ static void dhcpv4_handle_discover(struct dhcpv4_server_ctx *ctx, slot->state == DHCPV4_SERVER_ADDR_FREE) { /* Requested address is free. */ selected = slot; + probe = true; break; } } @@ -742,6 +927,7 @@ static void dhcpv4_handle_discover(struct dhcpv4_server_ctx *ctx, if (slot->state == DHCPV4_SERVER_ADDR_FREE) { /* Requested address is free. */ selected = slot; + probe = true; break; } } @@ -752,9 +938,26 @@ static void dhcpv4_handle_discover(struct dhcpv4_server_ctx *ctx, } else { uint32_t lease_time = dhcpv4_get_lease_time(options, optlen); - if (dhcpv4_send_offer(ctx, msg, &selected->addr, lease_time, - ¶ms) < 0) { - return; + if (IS_ENABLED(DHCPV4_SERVER_ICMP_PROBE) && probe) { + if (dhcpv4_server_probe_setup(ctx, selected, + msg, ¶ms) < 0) { + /* Probing context already in use or failed to + * send probe, ignore Discovery for now and wait + * for retransmission. + */ + return; + } + + selected->expiry = + sys_timepoint_calc(ADDRESS_PROBE_TIMEOUT); + } else { + if (dhcpv4_send_offer(ctx, msg, &selected->addr, + lease_time, ¶ms) < 0) { + return; + } + + selected->expiry = + sys_timepoint_calc(ADDRESS_RESERVED_TIMEOUT); } LOG_DBG("DHCPv4 processing Discover - reserved %s", @@ -764,7 +967,6 @@ static void dhcpv4_handle_discover(struct dhcpv4_server_ctx *ctx, selected->client_id.len = client_id.len; memcpy(selected->client_id.buf, client_id.buf, client_id.len); selected->lease_time = lease_time; - selected->expiry = sys_timepoint_calc(ADDRESS_RESERVED_TIMEOUT); dhcpv4_server_timeout_recalc(ctx); } } @@ -1061,15 +1263,18 @@ static void dhcpv4_server_timeout(struct k_work *work) struct dhcpv4_server_ctx *ctx = CONTAINER_OF(dwork, struct dhcpv4_server_ctx, timeout_work); - k_mutex_lock(&server_lock, K_FOREVER); for (int i = 0; i < ARRAY_SIZE(ctx->addr_pool); i++) { struct dhcpv4_addr_slot *slot = &ctx->addr_pool[i]; - if (slot->state == DHCPV4_SERVER_ADDR_RESERVED || - slot->state == DHCPV4_SERVER_ADDR_ALLOCATED) { - if (sys_timepoint_expired(slot->expiry)) { + if ((slot->state == DHCPV4_SERVER_ADDR_RESERVED || + slot->state == DHCPV4_SERVER_ADDR_ALLOCATED) && + sys_timepoint_expired(slot->expiry)) { + if (slot->state == DHCPV4_SERVER_ADDR_RESERVED && + dhcpv4_server_is_slot_probed(ctx, slot)) { + dhcpv4_server_probe_timeout(ctx, slot); + } else { LOG_DBG("Address %s expired", net_sprint_ipv4_addr(&slot->addr)); slot->state = DHCPV4_SERVER_ADDR_FREE; @@ -1310,19 +1515,28 @@ int net_dhcpv4_server_start(struct net_if *iface, struct in_addr *base_addr) &server_ctx[slot].addr_pool[i].addr)); } + ret = dhcpv4_server_probing_init(&server_ctx[slot]); + if (ret < 0) { + LOG_ERR("Failed to register probe handler, %d", ret); + goto cleanup; + } + ret = net_socket_service_register(&dhcpv4_server, fds, ARRAY_SIZE(fds), NULL); if (ret < 0) { LOG_ERR("Failed to register socket service, %d", ret); - memset(&server_ctx[slot], 0, sizeof(server_ctx[slot])); - fds[slot].fd = -1; - goto error; + dhcpv4_server_probing_deinit(&server_ctx[slot]); + goto cleanup; } k_mutex_unlock(&server_lock); return 0; +cleanup: + memset(&server_ctx[slot], 0, sizeof(server_ctx[slot])); + fds[slot].fd = -1; + error: if (sock >= 0) { (void)zsock_close(sock); @@ -1361,6 +1575,7 @@ int net_dhcpv4_server_stop(struct net_if *iface) fds[slot].fd = -1; (void)zsock_close(server_ctx[slot].sock); + dhcpv4_server_probing_deinit(&server_ctx[slot]); k_work_cancel_delayable_sync(&server_ctx[slot].timeout_work, &sync); memset(&server_ctx[slot], 0, sizeof(server_ctx[slot])); From 6d6d5b438db265be67dbf383a370eea19d086dd5 Mon Sep 17 00:00:00 2001 From: Robert Lubos Date: Tue, 30 Jan 2024 17:31:13 +0100 Subject: [PATCH 3351/3723] tests: net: dhcpv4_server: Add test case for ICMP probing Add test case which verifies that ICMP probing work as expected for the DHCPv4 server. Make sure we build tests with both, probing enabled (default) and disabled (enforced in testcase.yml) to make sure the server is functional regardless of the probing feature. Signed-off-by: Robert Lubos --- tests/net/dhcpv4/server/prj.conf | 3 + tests/net/dhcpv4/server/src/main.c | 95 +++++++++++++++++++++++++++ tests/net/dhcpv4/server/testcase.yaml | 3 + 3 files changed, 101 insertions(+) diff --git a/tests/net/dhcpv4/server/prj.conf b/tests/net/dhcpv4/server/prj.conf index d29050e4baf..b8e30a9ee7a 100644 --- a/tests/net/dhcpv4/server/prj.conf +++ b/tests/net/dhcpv4/server/prj.conf @@ -3,6 +3,7 @@ CONFIG_ZTEST=y CONFIG_ENTROPY_GENERATOR=y CONFIG_TEST_RANDOM_GENERATOR=y +CONFIG_SYSTEM_WORKQUEUE_STACK_SIZE=2048 CONFIG_NETWORKING=y CONFIG_NET_L2_DUMMY=y @@ -10,6 +11,8 @@ CONFIG_NET_IPV4=y CONFIG_NET_IPV6=n CONFIG_NET_UDP=y CONFIG_NET_DHCPV4_SERVER=y +# Reduce probe timeout to speed up tests +CONFIG_NET_DHCPV4_SERVER_ICMP_PROBE_TIMEOUT=10 # We need to set POSIX_API and use picolibc for eventfd to work CONFIG_POSIX_API=y diff --git a/tests/net/dhcpv4/server/src/main.c b/tests/net/dhcpv4/server/src/main.c index cfaa8561606..1111784210a 100644 --- a/tests/net/dhcpv4/server/src/main.c +++ b/tests/net/dhcpv4/server/src/main.c @@ -7,11 +7,13 @@ #include #include #include +#include #include #include #include #include "dhcpv4/dhcpv4_internal.h" +#include "icmpv4.h" #include "ipv4.h" #include "udp_internal.h" @@ -35,11 +37,13 @@ static struct test_dhcpv4_server_ctx { struct k_sem test_proceed; struct net_pkt *pkt; struct in_addr assigned_ip; + struct in_addr declined_ip; /* Request params */ const char *client_id; int lease_time; bool broadcast; + bool send_echo_reply; } test_ctx; struct test_lease_count { @@ -66,8 +70,51 @@ static void server_iface_init(struct net_if *iface) (void)net_if_ipv4_set_netmask(iface, &netmask); } +static void send_icmp_echo_reply(struct net_pkt *pkt, + struct net_ipv4_hdr *ipv4_hdr) +{ + struct net_pkt *reply; + size_t payload_len = net_pkt_get_len(pkt) - net_pkt_ip_hdr_len(pkt) - + NET_ICMPH_LEN; + + reply = net_pkt_alloc_with_buffer(net_pkt_iface(pkt), payload_len, + AF_INET, IPPROTO_ICMP, K_FOREVER); + zassert_not_null(reply, "Failed to allocate echo reply"); + + zassert_ok(net_ipv4_create(reply, (struct in_addr *)ipv4_hdr->dst, + (struct in_addr *)ipv4_hdr->src), + "Failed to create IPv4 header"); + + zassert_ok(net_icmpv4_create(reply, NET_ICMPV4_ECHO_REPLY, 0), + "Failed to create ICMP header"); + zassert_ok(net_pkt_copy(reply, pkt, payload_len), + "Failed to copy payload"); + + net_pkt_cursor_init(reply); + net_ipv4_finalize(reply, IPPROTO_ICMP); + + zassert_ok(net_recv_data(test_ctx.iface, reply), "Failed to receive data"); +} + static int server_send(const struct device *dev, struct net_pkt *pkt) { + NET_PKT_DATA_ACCESS_DEFINE(ipv4_access, struct net_ipv4_hdr); + struct net_ipv4_hdr *ipv4_hdr; + + ipv4_hdr = (struct net_ipv4_hdr *)net_pkt_get_data(pkt, &ipv4_access); + zassert_not_null(ipv4_hdr, "Failed to access IPv4 header."); + + if (ipv4_hdr->proto == IPPROTO_ICMP) { + if (test_ctx.send_echo_reply) { + test_ctx.send_echo_reply = false; + memcpy(&test_ctx.declined_ip, ipv4_hdr->dst, + sizeof(struct in_addr)); + send_icmp_echo_reply(pkt, ipv4_hdr); + } + + return 0; + } + test_ctx.pkt = pkt; net_pkt_ref(pkt); @@ -840,6 +887,53 @@ ZTEST(dhcpv4_server_tests, test_inform) verify_lease_count(0, 0, 0); } +static void after_probe_address_cb(struct net_if *iface, + struct dhcpv4_addr_slot *lease, + void *user_data) +{ + if (lease->state == DHCPV4_SERVER_ADDR_DECLINED) { + zassert_equal(test_ctx.declined_ip.s_addr, lease->addr.s_addr, + "Declined wrong address"); + } + + if (lease->state == DHCPV4_SERVER_ADDR_RESERVED) { + zassert_equal(test_ctx.assigned_ip.s_addr, lease->addr.s_addr, + "Reserved wrong address"); + } +} + +static void verify_address_after_probe(void) +{ + int ret; + + ret = net_dhcpv4_server_foreach_lease(test_ctx.iface, + after_probe_address_cb, + NULL); + zassert_ok(ret, "Failed to verify address after probe"); +} + +/* Verify that if the server detects conflict with ICMP probe, it assigns + * different address. + */ +ZTEST(dhcpv4_server_tests, test_icmp_probe) +{ + if (CONFIG_NET_DHCPV4_SERVER_ICMP_PROBE_TIMEOUT == 0) { + ztest_test_skip(); + } + + test_ctx.send_echo_reply = true; + + client_send_discover(); + verify_offer(false); + test_pkt_free(); + + verify_lease_count(1, 0, 1); + zassert_not_equal(test_ctx.assigned_ip.s_addr, + test_ctx.declined_ip.s_addr, + "DHCPv4 srever offered conflicted address"); + verify_address_after_probe(); +} + /* Verify that the DHCP server can start and validate input properly. */ ZTEST(dhcpv4_server_tests_no_init, test_initialization) { @@ -868,6 +962,7 @@ static void dhcpv4_server_tests_before(void *fixture) test_ctx.broadcast = false; test_ctx.pkt = NULL; test_ctx.lease_time = NO_LEASE_TIME; + test_ctx.send_echo_reply = false; memset(&test_ctx.assigned_ip, 0, sizeof(test_ctx.assigned_ip)); net_dhcpv4_server_start(test_ctx.iface, &test_base_addr); diff --git a/tests/net/dhcpv4/server/testcase.yaml b/tests/net/dhcpv4/server/testcase.yaml index 13919e42b13..3b1c23d6048 100644 --- a/tests/net/dhcpv4/server/testcase.yaml +++ b/tests/net/dhcpv4/server/testcase.yaml @@ -12,3 +12,6 @@ tests: net.dhcpv4_server.preempt: extra_configs: - CONFIG_NET_TC_THREAD_PREEMPTIVE=y + net.dhcpv4_server.no_probe: + extra_configs: + - CONFIG_NET_DHCPV4_SERVER_ICMP_PROBE_TIMEOUT=0 From a897c1c7d940bd37ae93bd545de03b6471e876fa Mon Sep 17 00:00:00 2001 From: Gaetan Perrot Date: Wed, 31 Jan 2024 22:42:10 +0900 Subject: [PATCH 3352/3723] posix: sched: Implement sched_rr_get_interval Implement `sched_rr_get_interval()` POSIX APIs as a part of PSE53 `_POSIX_PRIORITY_SCHEDULING` option group. Functions is actually placeholders and just return `ENOSYS` since Zephyr does not yet support processes or process scheduling. signed-off-by: Gaetan Perrot --- include/zephyr/posix/sched.h | 3 +++ lib/posix/options/sched.c | 10 ++++++++++ 2 files changed, 13 insertions(+) diff --git a/include/zephyr/posix/sched.h b/include/zephyr/posix/sched.h index 03b568fadea..b337cc2c022 100644 --- a/include/zephyr/posix/sched.h +++ b/include/zephyr/posix/sched.h @@ -10,6 +10,8 @@ #include "posix_types.h" +#include + #ifdef __cplusplus extern "C" { #endif @@ -53,6 +55,7 @@ int sched_getscheduler(pid_t pid); int sched_setparam(pid_t pid, const struct sched_param *param); int sched_setscheduler(pid_t pid, int policy, const struct sched_param *param); +int sched_rr_get_interval(pid_t pid, struct timespec *interval); #ifdef __cplusplus } diff --git a/lib/posix/options/sched.c b/lib/posix/options/sched.c index 195c5895752..be174d92cd6 100644 --- a/lib/posix/options/sched.c +++ b/lib/posix/options/sched.c @@ -101,3 +101,13 @@ int sched_setscheduler(pid_t pid, int policy, const struct sched_param *param) return -1; } + +int sched_rr_get_interval(pid_t pid, struct timespec *interval) +{ + ARG_UNUSED(pid); + ARG_UNUSED(interval); + + errno = ENOSYS; + + return -1; +} From 3ded1c3c03dde8ba2d2200835c02b3fa9f2e1814 Mon Sep 17 00:00:00 2001 From: Gaetan Perrot Date: Wed, 31 Jan 2024 08:55:26 +0900 Subject: [PATCH 3353/3723] doc: posix: mark sched_rr_get_interval as supported `sched_rr_get_interval()` is now implemented,mark it so. signed-off-by: Gaetan Perrot --- doc/services/portability/posix/option_groups/index.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/doc/services/portability/posix/option_groups/index.rst b/doc/services/portability/posix/option_groups/index.rst index 7dd47616abb..efdb2917d65 100644 --- a/doc/services/portability/posix/option_groups/index.rst +++ b/doc/services/portability/posix/option_groups/index.rst @@ -379,7 +379,7 @@ _POSIX_PRIORITY_SCHEDULING sched_get_priority_min(),yes sched_getparam(), sched_getscheduler(), - sched_rr_get_interval(), + sched_rr_get_interval(),yes sched_setparam(),yes sched_setscheduler(),yes sched_yield(),yes From 6fe676f4e8b00fab326b06e03306a1789d4a5006 Mon Sep 17 00:00:00 2001 From: Gaetan Perrot Date: Wed, 31 Jan 2024 09:04:03 +0900 Subject: [PATCH 3354/3723] posix: sched: Implement tests for sched_rr_get_interval Implement tests for `sched_rr_get_interval()` . Function is actually placeholders and just return `ENOSYS` since Zephyr does not yet support processes or process scheduling. signed-off-by: Gaetan Perrot --- tests/posix/common/src/pthread.c | 12 ++++++++++++ tests/posix/headers/src/sched_h.c | 2 +- 2 files changed, 13 insertions(+), 1 deletion(-) diff --git a/tests/posix/common/src/pthread.c b/tests/posix/common/src/pthread.c index 184cb77e54f..f3facdf8686 100644 --- a/tests/posix/common/src/pthread.c +++ b/tests/posix/common/src/pthread.c @@ -428,6 +428,18 @@ ZTEST(pthread, test_sched_setscheduler) zassert_true((rc == -1 && err == ENOSYS)); } +ZTEST(pthread, test_sched_rr_get_interval) +{ + struct timespec interval = { + .tv_sec = 0, + .tv_nsec = 0, + }; + int rc = sched_rr_get_interval(0, &interval); + int err = errno; + + zassert_true((rc == -1 && err == ENOSYS)); +} + ZTEST(pthread, test_pthread_equal) { zassert_true(pthread_equal(pthread_self(), pthread_self())); diff --git a/tests/posix/headers/src/sched_h.c b/tests/posix/headers/src/sched_h.c index e96e529de81..b04a5627775 100644 --- a/tests/posix/headers/src/sched_h.c +++ b/tests/posix/headers/src/sched_h.c @@ -33,7 +33,7 @@ ZTEST(posix_headers, test_sched_h) zassert_not_null(sched_getparam); zassert_not_null(sched_getscheduler); - /* zassert_not_null(sched_rr_get_interval); */ /* not implemented */ + zassert_not_null(sched_rr_get_interval); zassert_not_null(sched_setparam); zassert_not_null(sched_setscheduler); From 2f138fad5f9beaa28c95c5ccf04ae44e174c1bc4 Mon Sep 17 00:00:00 2001 From: Ping Wang Date: Tue, 30 Jan 2024 07:38:35 +0100 Subject: [PATCH 3355/3723] Bluetooth: Audio: MCC optional procedures actually optional This change makes the optional procedures in the Media Control Client optional and configurable through Kconfig. Signed-off-by: Ping Wang --- include/zephyr/bluetooth/audio/mcc.h | 66 +++++++----- subsys/bluetooth/audio/Kconfig.mcs | 102 +++++++++++++++++++ subsys/bluetooth/audio/mcc.c | 140 ++++++++++++++++++++++++++ subsys/bluetooth/audio/mcc_internal.h | 39 +++++++ subsys/bluetooth/audio/media_proxy.c | 124 +++++++++++++++++------ subsys/bluetooth/audio/shell/mcc.c | 120 ++++++++++++++++++++++ tests/bluetooth/shell/testcase.yaml | 6 ++ 7 files changed, 543 insertions(+), 54 deletions(-) diff --git a/include/zephyr/bluetooth/audio/mcc.h b/include/zephyr/bluetooth/audio/mcc.h index 9744bb05863..f67eb768318 100644 --- a/include/zephyr/bluetooth/audio/mcc.h +++ b/include/zephyr/bluetooth/audio/mcc.h @@ -54,7 +54,6 @@ typedef void (*bt_mcc_discover_mcs_cb)(struct bt_conn *conn, int err); */ typedef void (*bt_mcc_read_player_name_cb)(struct bt_conn *conn, int err, const char *name); -#ifdef CONFIG_BT_OTS_CLIENT /** * @brief Callback function for bt_mcc_read_icon_obj_id() * @@ -64,8 +63,7 @@ typedef void (*bt_mcc_read_player_name_cb)(struct bt_conn *conn, int err, const * @param err Error value. 0 on success, GATT error or errno on fail * @param icon_id The ID of the Icon Object. This is a UINT48 in a uint64_t */ -typedef void (*bt_mcc_read_icon_obj_id_cb)(struct bt_conn *conn, int err, uint64_t id); -#endif /* CONFIG_BT_OTS_CLIENT */ +typedef void (*bt_mcc_read_icon_obj_id_cb)(struct bt_conn *conn, int err, uint64_t icon_id); /** * @brief Callback function for bt_mcc_read_icon_url() @@ -169,7 +167,6 @@ typedef void (*bt_mcc_set_playback_speed_cb)(struct bt_conn *conn, int err, int8 */ typedef void (*bt_mcc_read_seeking_speed_cb)(struct bt_conn *conn, int err, int8_t speed); -#ifdef CONFIG_BT_OTS_CLIENT /** * @brief Callback function for bt_mcc_read_segments_obj_id() * @@ -254,12 +251,10 @@ typedef void (*bt_mcc_read_current_group_obj_id_cb)(struct bt_conn *conn, int er * * @param conn The connection that was used to initialise the media control client * @param err Error value. 0 on success, GATT error or errno on fail - * @param id The Object ID (UINT48) set (or attempted to set) + * @param obj_id The Object ID (UINT48) set (or attempted to set) */ typedef void (*bt_mcc_set_current_group_obj_id_cb)(struct bt_conn *conn, int err, uint64_t obj_id); -#endif /* CONFIG_BT_OTS_CLIENT */ - /** * @brief Callback function for bt_mcc_read_playing_order() * @@ -343,7 +338,6 @@ typedef void (*bt_mcc_cmd_ntf_cb)(struct bt_conn *conn, int err, const struct mp typedef void (*bt_mcc_read_opcodes_supported_cb)(struct bt_conn *conn, int err, uint32_t opcodes); -#ifdef CONFIG_BT_OTS_CLIENT /** * @brief Callback function for bt_mcc_send_search() * @@ -367,7 +361,7 @@ typedef void (*bt_mcc_send_search_cb)(struct bt_conn *conn, int err, * * @param conn The connection that was used to initialise the media control client * @param err Error value. 0 on success, GATT error or errno on fail - * @param ntf The search notification + * @param result_code The search notification */ typedef void (*bt_mcc_search_ntf_cb)(struct bt_conn *conn, int err, uint8_t result_code); @@ -387,7 +381,6 @@ typedef void (*bt_mcc_search_ntf_cb)(struct bt_conn *conn, int err, */ typedef void (*bt_mcc_read_search_results_obj_id_cb)(struct bt_conn *conn, int err, uint64_t id); -#endif /* CONFIG_BT_OTS_CLIENT */ /** * @brief Callback function for bt_mcc_read_content_control_id() @@ -400,7 +393,7 @@ typedef void (*bt_mcc_read_search_results_obj_id_cb)(struct bt_conn *conn, */ typedef void (*bt_mcc_read_content_control_id_cb)(struct bt_conn *conn, int err, uint8_t ccid); -#ifdef CONFIG_BT_OTS_CLIENT + /**** Callback functions for the included Object Transfer service *************/ /** @@ -507,8 +500,6 @@ typedef void (*bt_mcc_otc_read_parent_group_object_cb)(struct bt_conn *conn, int typedef void (*bt_mcc_otc_read_current_group_object_cb)(struct bt_conn *conn, int err, struct net_buf_simple *buf); -#endif /* CONFIG_BT_OTS_CLIENT */ - /** * @brief Media control client callbacks @@ -519,15 +510,31 @@ struct bt_mcc_cb { #ifdef CONFIG_BT_OTS_CLIENT bt_mcc_read_icon_obj_id_cb read_icon_obj_id; #endif /* CONFIG_BT_OTS_CLIENT */ +#if defined(CONFIG_BT_MCC_READ_MEDIA_PLAYER_ICON_URL) bt_mcc_read_icon_url_cb read_icon_url; +#endif /* defined(CONFIG_BT_MCC_READ_MEDIA_PLAYER_ICON_URL) */ bt_mcc_track_changed_ntf_cb track_changed_ntf; +#if defined(CONFIG_BT_MCC_READ_TRACK_TITLE) bt_mcc_read_track_title_cb read_track_title; +#endif /* defined(CONFIG_BT_MCC_READ_TRACK_TITLE) */ +#if defined(CONFIG_BT_MCC_READ_TRACK_DURATION) bt_mcc_read_track_duration_cb read_track_duration; +#endif /* defined(CONFIG_BT_MCC_READ_TRACK_DURATION) */ +#if defined(CONFIG_BT_MCC_READ_TRACK_POSITION) bt_mcc_read_track_position_cb read_track_position; +#endif /* defined(CONFIG_BT_MCC_READ_TRACK_POSITION) */ +#if defined(CONFIG_BT_MCC_SET_TRACK_POSITION) bt_mcc_set_track_position_cb set_track_position; +#endif /* defined(CONFIG_BT_MCC_SET_TRACK_POSITION) */ +#if defined(CONFIG_BT_MCC_READ_PLAYBACK_SPEED) bt_mcc_read_playback_speed_cb read_playback_speed; +#endif /* defined (CONFIG_BT_MCC_READ_PLAYBACK_SPEED) */ +#if defined(CONFIG_BT_MCC_SET_PLAYBACK_SPEED) bt_mcc_set_playback_speed_cb set_playback_speed; +#endif /* defined (CONFIG_BT_MCC_SET_PLAYBACK_SPEED) */ +#if defined(CONFIG_BT_MCC_READ_SEEKING_SPEED) bt_mcc_read_seeking_speed_cb read_seeking_speed; +#endif /* defined (CONFIG_BT_MCC_READ_SEEKING_SPEED) */ #ifdef CONFIG_BT_OTS_CLIENT bt_mcc_read_segments_obj_id_cb read_segments_obj_id; bt_mcc_read_current_track_obj_id_cb read_current_track_obj_id; @@ -538,19 +545,33 @@ struct bt_mcc_cb { bt_mcc_set_current_group_obj_id_cb set_current_group_obj_id; bt_mcc_read_parent_group_obj_id_cb read_parent_group_obj_id; #endif /* CONFIG_BT_OTS_CLIENT */ +#if defined(CONFIG_BT_MCC_READ_PLAYING_ORDER) bt_mcc_read_playing_order_cb read_playing_order; +#endif /* defined(CONFIG_BT_MCC_READ_PLAYING_ORDER) */ +#if defined(CONFIG_BT_MCC_SET_PLAYING_ORDER) bt_mcc_set_playing_order_cb set_playing_order; +#endif /* defined(CONFIG_BT_MCC_SET_PLAYING_ORDER) */ +#if defined(CONFIG_BT_MCC_READ_PLAYING_ORDER_SUPPORTED) bt_mcc_read_playing_orders_supported_cb read_playing_orders_supported; +#endif /* defined(CONFIG_BT_MCC_READ_PLAYING_ORDER_SUPPORTED) */ +#if defined(CONFIG_BT_MCC_READ_MEDIA_STATE) bt_mcc_read_media_state_cb read_media_state; +#endif /* defined(CONFIG_BT_MCC_READ_MEDIA_STATE) */ +#if defined(CONFIG_BT_MCC_SET_MEDIA_CONTROL_POINT) bt_mcc_send_cmd_cb send_cmd; +#endif /* defined(CONFIG_BT_MCC_SET_MEDIA_CONTROL_POINT) */ bt_mcc_cmd_ntf_cb cmd_ntf; +#if defined(CONFIG_BT_MCC_READ_MEDIA_CONTROL_POINT_OPCODES_SUPPORTED) bt_mcc_read_opcodes_supported_cb read_opcodes_supported; +#endif /* defined(CONFIG_BT_MCC_READ_MEDIA_CONTROL_POINT_OPCODES_SUPPORTED) */ #ifdef CONFIG_BT_OTS_CLIENT bt_mcc_send_search_cb send_search; bt_mcc_search_ntf_cb search_ntf; bt_mcc_read_search_results_obj_id_cb read_search_results_obj_id; #endif /* CONFIG_BT_OTS_CLIENT */ +#if defined(CONFIG_BT_MCC_READ_CONTENT_CONTROL_ID) bt_mcc_read_content_control_id_cb read_content_control_id; +#endif /* defined(CONFIG_BT_MCC_READ_CONTENT_CONTROL_ID) */ #ifdef CONFIG_BT_OTS_CLIENT bt_mcc_otc_obj_selected_cb otc_obj_selected; bt_mcc_otc_obj_metadata_cb otc_obj_metadata; @@ -600,7 +621,6 @@ int bt_mcc_discover_mcs(struct bt_conn *conn, bool subscribe); */ int bt_mcc_read_player_name(struct bt_conn *conn); -#ifdef CONFIG_BT_OTS_CLIENT /** * @brief Read Icon Object ID * @@ -609,7 +629,6 @@ int bt_mcc_read_player_name(struct bt_conn *conn); * @return 0 if success, errno on failure. */ int bt_mcc_read_icon_obj_id(struct bt_conn *conn); -#endif /* CONFIG_BT_OTS_CLIENT */ /** * @brief Read Icon Object URL @@ -685,7 +704,6 @@ int bt_mcc_set_playback_speed(struct bt_conn *conn, int8_t speed); */ int bt_mcc_read_seeking_speed(struct bt_conn *conn); -#ifdef CONFIG_BT_OTS_CLIENT /** * @brief Read Track Segments Object ID * @@ -720,7 +738,6 @@ int bt_mcc_set_current_track_obj_id(struct bt_conn *conn, uint64_t id); * @brief Read Next Track Object ID * * @param conn Connection to the peer device - * @param id Object Transfer Service ID (UINT48) of the track to set as the current track * * @return 0 if success, errno on failure. */ @@ -767,7 +784,6 @@ int bt_mcc_set_current_group_obj_id(struct bt_conn *conn, uint64_t id); * @return 0 if success, errno on failure. */ int bt_mcc_read_parent_group_obj_id(struct bt_conn *conn); -#endif /* CONFIG_BT_OTS_CLIENT */ /** * @brief Read Playing Order @@ -827,7 +843,6 @@ int bt_mcc_send_cmd(struct bt_conn *conn, const struct mpl_cmd *cmd); */ int bt_mcc_read_opcodes_supported(struct bt_conn *conn); -#ifdef CONFIG_BT_OTS_CLIENT /** * @brief Send a Search command * @@ -848,7 +863,6 @@ int bt_mcc_send_search(struct bt_conn *conn, const struct mpl_search *search); * @return 0 if success, errno on failure. */ int bt_mcc_read_search_results_obj_id(struct bt_conn *conn); -#endif /* CONFIG_BT_OTS_CLIENT */ /** * @brief Read Content Control ID @@ -859,7 +873,6 @@ int bt_mcc_read_search_results_obj_id(struct bt_conn *conn); */ int bt_mcc_read_content_control_id(struct bt_conn *conn); -#ifdef CONFIG_BT_OTS_CLIENT /** * @brief Read the current object metadata * @@ -923,10 +936,15 @@ int bt_mcc_otc_read_current_group_object(struct bt_conn *conn); */ int bt_mcc_otc_read_parent_group_object(struct bt_conn *conn); -#if defined(CONFIG_BT_MCC_SHELL) +/** + * @brief Look up MCC OTC instance + * + * @param conn The connection to the MCC server. + * + * @return Pointer to a MCC OTC instance if found else NULL. + * + */ struct bt_ots_client *bt_mcc_otc_inst(struct bt_conn *conn); -#endif /* defined(CONFIG_BT_MCC_SHELL) */ -#endif /* CONFIG_BT_OTS_CLIENT */ #ifdef __cplusplus } diff --git a/subsys/bluetooth/audio/Kconfig.mcs b/subsys/bluetooth/audio/Kconfig.mcs index 50f6064d44e..d0b139e90b1 100644 --- a/subsys/bluetooth/audio/Kconfig.mcs +++ b/subsys/bluetooth/audio/Kconfig.mcs @@ -121,4 +121,106 @@ config BT_MCC_SHELL help This option enables shell support for the Media Control Client. +config BT_MCC_MINIMAL + bool "Minimal Media Control Client without optional procedures" + help + This option disables all optional procedures in the Media Control Client. + +config BT_MCC_READ_MEDIA_PLAYER_ICON_URL + bool "Support reading Media Player Icon URL" + default !BT_MCC_MINIMAL + help + This option enables support for Read Media Information procedure + optionally read the Media Player Icon URL. + +config BT_MCC_READ_TRACK_TITLE + bool "Support reading Track Title" + default !BT_MCC_MINIMAL + help + This option enables support for reading Track Title. + +config BT_MCC_READ_TRACK_TITLE_ENABLE_SUBSCRIPTION + bool "Support to enable or disable the subscription of Track Title" + default !BT_MCC_MINIMAL + help + This option enables support for the subscription of Track Title. + +config BT_MCC_READ_TRACK_DURATION + bool "Support reading Track Duration" + default !BT_MCC_MINIMAL + help + This option enables support for reading Track Duration. + +config BT_MCC_READ_TRACK_POSITION + bool "Support reading Track Position" + default !BT_MCC_MINIMAL + help + This option enables support for reading Track Position. + +config BT_MCC_SET_TRACK_POSITION + bool "Support setting Track Position" + default !BT_MCC_MINIMAL + help + This option enables support for setting Track Position. + +config BT_MCC_READ_PLAYBACK_SPEED + bool "Support reading Playback Speed" + default !BT_MCC_MINIMAL + help + This option enables support for reading Playback Speed. + +config BT_MCC_SET_PLAYBACK_SPEED + bool "Support setting Playback Speed" + default !BT_MCC_MINIMAL + help + This option enables support for setting Playback Speed. + +config BT_MCC_READ_SEEKING_SPEED + bool "Support reading Seeking Speed" + default !BT_MCC_MINIMAL + help + This option enables support for reading Seeking Speed. + +config BT_MCC_READ_PLAYING_ORDER + bool "Support reading Playing Order" + default !BT_MCC_MINIMAL + help + This option enables support for reading Playing Order. + +config BT_MCC_SET_PLAYING_ORDER + bool "Support setting Playing Order" + default !BT_MCC_MINIMAL + help + This option enables support for setting Playing Order. + +config BT_MCC_READ_PLAYING_ORDER_SUPPORTED + bool "Support reading Playing Order Supported" + default !BT_MCC_MINIMAL + help + This option enables support for reading Playing Order Supported. + +config BT_MCC_READ_MEDIA_STATE + bool "Support reading Media State" + default !BT_MCC_MINIMAL + help + This option enables support for reading Media State. + +config BT_MCC_SET_MEDIA_CONTROL_POINT + bool "Support setting Media Control Point" + default !BT_MCC_MINIMAL + help + This option enables support for setting Media Control Point. + +config BT_MCC_READ_MEDIA_CONTROL_POINT_OPCODES_SUPPORTED + bool "Support reading Media Control Point Opcodes Supported" + default !BT_MCC_MINIMAL + help + This option enables support for reading Media Control Point Opcodes Supported. + +config BT_MCC_READ_CONTENT_CONTROL_ID + bool "Support reading Content Control ID" + default !BT_MCC_MINIMAL + help + This option enables support for reading Content Control ID. + endif # BT_MCC diff --git a/subsys/bluetooth/audio/mcc.c b/subsys/bluetooth/audio/mcc.c index 560ac41b11d..4a763bc0d3e 100644 --- a/subsys/bluetooth/audio/mcc.c +++ b/subsys/bluetooth/audio/mcc.c @@ -156,6 +156,7 @@ static uint8_t mcc_read_icon_obj_id_cb(struct bt_conn *conn, uint8_t err, } #endif /* CONFIG_BT_MCC_OTS */ +#if defined(CONFIG_BT_MCC_READ_MEDIA_PLAYER_ICON_URL) static uint8_t mcc_read_icon_url_cb(struct bt_conn *conn, uint8_t err, struct bt_gatt_read_params *params, const void *data, uint16_t length) @@ -185,7 +186,9 @@ static uint8_t mcc_read_icon_url_cb(struct bt_conn *conn, uint8_t err, return BT_GATT_ITER_STOP; } +#endif /* defined(CONFIG_BT_MCC_READ_MEDIA_PLAYER_ICON_URL) */ +#if defined(CONFIG_BT_MCC_READ_TRACK_TITLE) static void mcc_track_title_cb(struct bt_conn *conn, uint8_t err, const void *data, uint16_t length) { int cb_err = err; @@ -222,7 +225,9 @@ static uint8_t mcc_read_track_title_cb(struct bt_conn *conn, uint8_t err, return BT_GATT_ITER_STOP; } +#endif /* defined(CONFIG_BT_MCC_READ_TRACK_TITLE)*/ +#if defined(CONFIG_BT_MCC_READ_TRACK_DURATION) static void mcc_track_duration_cb(struct bt_conn *conn, uint8_t err, const void *data, uint16_t length) { @@ -256,7 +261,9 @@ static uint8_t mcc_read_track_duration_cb(struct bt_conn *conn, uint8_t err, return BT_GATT_ITER_STOP; } +#endif /* defined(CONFIG_BT_MCC_READ_TRACK_DURATION) */ +#if defined(CONFIG_BT_MCC_READ_TRACK_POSITION) static void mcc_track_position_cb(struct bt_conn *conn, uint8_t err, const void *data, uint16_t length) { @@ -290,7 +297,9 @@ static uint8_t mcc_read_track_position_cb(struct bt_conn *conn, uint8_t err, return BT_GATT_ITER_STOP; } +#endif /* defined(CONFIG_BT_MCC_READ_TRACK_POSITION) */ +#if defined(CONFIG_BT_MCC_SET_TRACK_POSITION) static void mcs_write_track_position_cb(struct bt_conn *conn, uint8_t err, struct bt_gatt_write_params *params) { @@ -314,7 +323,9 @@ static void mcs_write_track_position_cb(struct bt_conn *conn, uint8_t err, mcc_cb->set_track_position(conn, cb_err, pos); } } +#endif /* defined(CONFIG_BT_MCC_SET_TRACK_POSITION) */ +#if defined(CONFIG_BT_MCC_READ_PLAYBACK_SPEED) static void mcc_playback_speed_cb(struct bt_conn *conn, uint8_t err, const void *data, uint16_t length) { @@ -348,7 +359,9 @@ static uint8_t mcc_read_playback_speed_cb(struct bt_conn *conn, uint8_t err, return BT_GATT_ITER_STOP; } +#endif /* defined (CONFIG_BT_MCC_READ_PLAYBACK_SPEED) */ +#if defined(CONFIG_BT_MCC_SET_PLAYBACK_SPEED) static void mcs_write_playback_speed_cb(struct bt_conn *conn, uint8_t err, struct bt_gatt_write_params *params) { @@ -371,7 +384,9 @@ static void mcs_write_playback_speed_cb(struct bt_conn *conn, uint8_t err, mcc_cb->set_playback_speed(conn, cb_err, speed); } } +#endif /* defined (CONFIG_BT_MCC_SET_PLAYBACK_SPEED) */ +#if defined(CONFIG_BT_MCC_READ_SEEKING_SPEED) static void mcc_seeking_speed_cb(struct bt_conn *conn, uint8_t err, const void *data, uint16_t length) { @@ -405,6 +420,7 @@ static uint8_t mcc_read_seeking_speed_cb(struct bt_conn *conn, uint8_t err, return BT_GATT_ITER_STOP; } +#endif /* defined (CONFIG_BT_MCC_READ_SEEKING_SPEED) */ #ifdef CONFIG_BT_MCC_OTS static uint8_t mcc_read_segments_obj_id_cb(struct bt_conn *conn, uint8_t err, @@ -679,6 +695,7 @@ static void mcs_write_current_group_obj_id_cb(struct bt_conn *conn, uint8_t err, } #endif /* CONFIG_BT_MCC_OTS */ +#if defined(CONFIG_BT_MCC_READ_PLAYING_ORDER) static void mcc_playing_order_cb(struct bt_conn *conn, uint8_t err, const void *data, uint16_t length) { @@ -712,7 +729,9 @@ static uint8_t mcc_read_playing_order_cb(struct bt_conn *conn, uint8_t err, return BT_GATT_ITER_STOP; } +#endif /* defined(CONFIG_BT_MCC_READ_PLAYING_ORDER) */ +#if defined(CONFIG_BT_MCC_SET_PLAYING_ORDER) static void mcs_write_playing_order_cb(struct bt_conn *conn, uint8_t err, struct bt_gatt_write_params *params) { @@ -735,7 +754,9 @@ static void mcs_write_playing_order_cb(struct bt_conn *conn, uint8_t err, mcc_cb->set_playing_order(conn, cb_err, order); } } +#endif /* defined(CONFIG_BT_MCC_SET_PLAYING_ORDER) */ +#if defined(CONFIG_BT_MCC_READ_PLAYING_ORDER_SUPPORTED) static uint8_t mcc_read_playing_orders_supported_cb(struct bt_conn *conn, uint8_t err, struct bt_gatt_read_params *params, const void *data, uint16_t length) @@ -762,7 +783,9 @@ static uint8_t mcc_read_playing_orders_supported_cb(struct bt_conn *conn, uint8_ return BT_GATT_ITER_STOP; } +#endif /* defined(CONFIG_BT_MCC_READ_PLAYING_ORDER_SUPPORTED) */ +#if defined(CONFIG_BT_MCC_READ_MEDIA_STATE) static void mcc_media_state_cb(struct bt_conn *conn, uint8_t err, const void *data, uint16_t length) { int cb_err = err; @@ -795,7 +818,9 @@ static uint8_t mcc_read_media_state_cb(struct bt_conn *conn, uint8_t err, return BT_GATT_ITER_STOP; } +#endif /* defined(CONFIG_BT_MCC_READ_MEDIA_STATE) */ +#if defined(CONFIG_BT_MCC_SET_MEDIA_CONTROL_POINT) static void mcs_write_cp_cb(struct bt_conn *conn, uint8_t err, struct bt_gatt_write_params *params) { @@ -829,7 +854,9 @@ static void mcs_write_cp_cb(struct bt_conn *conn, uint8_t err, mcc_cb->send_cmd(conn, cb_err, &cmd); } } +#endif /* defined(CONFIG_BT_MCC_SET_MEDIA_CONTROL_POINT) */ +#if defined(CONFIG_BT_MCC_READ_MEDIA_CONTROL_POINT_OPCODES_SUPPORTED) static void mcc_opcodes_supported_cb(struct bt_conn *conn, uint8_t err, const void *data, uint16_t length) { @@ -864,6 +891,7 @@ static uint8_t mcc_read_opcodes_supported_cb(struct bt_conn *conn, uint8_t err, return BT_GATT_ITER_STOP; } +#endif /* defined(CONFIG_BT_MCC_READ_MEDIA_CONTROL_POINT_OPCODES_SUPPORTED) */ #ifdef CONFIG_BT_MCC_OTS static void mcs_write_scp_cb(struct bt_conn *conn, uint8_t err, @@ -935,6 +963,7 @@ static uint8_t mcc_read_search_results_obj_id_cb(struct bt_conn *conn, uint8_t e } #endif /* CONFIG_BT_MCC_OTS */ +#if defined(CONFIG_BT_MCC_READ_CONTENT_CONTROL_ID) static uint8_t mcc_read_content_control_id_cb(struct bt_conn *conn, uint8_t err, struct bt_gatt_read_params *params, const void *data, uint16_t length) @@ -962,6 +991,7 @@ static uint8_t mcc_read_content_control_id_cb(struct bt_conn *conn, uint8_t err, return BT_GATT_ITER_STOP; } +#endif /* defined(CONFIG_BT_MCC_READ_CONTENT_CONTROL_ID) */ static uint8_t mcs_notify_handler(struct bt_conn *conn, struct bt_gatt_subscribe_params *params, @@ -1007,25 +1037,35 @@ static uint8_t mcs_notify_handler(struct bt_conn *conn, mcc_cb->track_changed_ntf(conn, cb_err); } +#if defined(CONFIG_BT_MCC_READ_TRACK_TITLE_ENABLE_SUBSCRIPTION) } else if (handle == mcs_inst->track_title_handle) { LOG_DBG("Track Title notification"); mcc_track_title_cb(conn, 0, data, length); +#endif /* defined(CONFIG_BT_MCC_READ_TRACK_TITLE_ENABLE_SUBSCRIPTION) */ +#if defined(CONFIG_BT_MCC_READ_TRACK_DURATION) } else if (handle == mcs_inst->track_duration_handle) { LOG_DBG("Track Duration notification"); mcc_track_duration_cb(conn, 0, data, length); +#endif /* defined(CONFIG_BT_MCC_READ_TRACK_DURATION) */ +#if defined(CONFIG_BT_MCC_READ_TRACK_POSITION) } else if (handle == mcs_inst->track_position_handle) { LOG_DBG("Track Position notification"); mcc_track_position_cb(conn, 0, data, length); +#endif /* defined(CONFIG_BT_MCC_READ_TRACK_POSITION) */ +#if defined(CONFIG_BT_MCC_READ_PLAYBACK_SPEED) } else if (handle == mcs_inst->playback_speed_handle) { LOG_DBG("Playback Speed notification"); mcc_playback_speed_cb(conn, 0, data, length); +#endif /* defined (CONFIG_BT_MCC_READ_PLAYBACK_SPEED) */ +#if defined(CONFIG_BT_MCC_READ_SEEKING_SPEED) } else if (handle == mcs_inst->seeking_speed_handle) { LOG_DBG("Seeking Speed notification"); mcc_seeking_speed_cb(conn, 0, data, length); +#endif /* defined (CONFIG_BT_MCC_READ_SEEKING_SPEED) */ #ifdef CONFIG_BT_MCC_OTS } else if (handle == mcs_inst->current_track_obj_id_handle) { @@ -1045,13 +1085,17 @@ static uint8_t mcs_notify_handler(struct bt_conn *conn, mcc_current_group_obj_id_cb(conn, 0, data, length); #endif /* CONFIG_BT_MCC_OTS */ +#if defined(CONFIG_BT_MCC_READ_PLAYING_ORDER) } else if (handle == mcs_inst->playing_order_handle) { LOG_DBG("Playing Order notification"); mcc_playing_order_cb(conn, 0, data, length); +#endif /* defined(CONFIG_BT_MCC_READ_PLAYING_ORDER) */ +#if defined(CONFIG_BT_MCC_READ_MEDIA_STATE) } else if (handle == mcs_inst->media_state_handle) { LOG_DBG("Media State notification"); mcc_media_state_cb(conn, 0, data, length); +#endif /* defined(CONFIG_BT_MCC_READ_MEDIA_STATE) */ } else if (handle == mcs_inst->cp_handle) { /* The control point is is a special case - only */ @@ -1075,9 +1119,11 @@ static uint8_t mcs_notify_handler(struct bt_conn *conn, mcc_cb->cmd_ntf(conn, cb_err, &ntf); } +#if defined(CONFIG_BT_MCC_READ_MEDIA_CONTROL_POINT_OPCODES_SUPPORTED) } else if (handle == mcs_inst->opcodes_supported_handle) { LOG_DBG("Opcodes Supported notification"); mcc_opcodes_supported_cb(conn, 0, data, length); +#endif /* defined(CONFIG_BT_MCC_READ_MEDIA_CONTROL_POINT_OPCODES_SUPPORTED) */ #ifdef CONFIG_BT_MCC_OTS } else if (handle == mcs_inst->scp_handle) { @@ -1122,21 +1168,37 @@ static void reset_mcs_inst(struct mcs_instance_t *mcs_inst, struct bt_conn *conn */ (void)bt_gatt_unsubscribe(conn, &mcs_inst->player_name_sub_params); (void)bt_gatt_unsubscribe(conn, &mcs_inst->track_changed_sub_params); +#if defined(CONFIG_BT_MCC_READ_TRACK_TITLE_ENABLE_SUBSCRIPTION) (void)bt_gatt_unsubscribe(conn, &mcs_inst->track_title_sub_params); +#endif /* defined(CONFIG_BT_MCC_READ_TRACK_TITLE_ENABLE_SUBSCRIPTION) */ +#if defined(CONFIG_BT_MCC_READ_TRACK_DURATION) (void)bt_gatt_unsubscribe(conn, &mcs_inst->track_duration_sub_params); +#endif /* defined(CONFIG_BT_MCC_READ_TRACK_DURATION) */ +#if defined(CONFIG_BT_MCC_READ_TRACK_POSITION) (void)bt_gatt_unsubscribe(conn, &mcs_inst->track_position_sub_params); +#endif /* defined(CONFIG_BT_MCC_READ_TRACK_POSITION) */ +#if defined(CONFIG_BT_MCC_READ_PLAYBACK_SPEED) (void)bt_gatt_unsubscribe(conn, &mcs_inst->playback_speed_sub_params); +#endif /* defined (CONFIG_BT_MCC_READ_PLAYBACK_SPEED) */ +#if defined(CONFIG_BT_MCC_READ_SEEKING_SPEED) (void)bt_gatt_unsubscribe(conn, &mcs_inst->seeking_speed_sub_params); +#endif /* defined (CONFIG_BT_MCC_READ_SEEKING_SPEED) */ #ifdef CONFIG_BT_MCC_OTS (void)bt_gatt_unsubscribe(conn, &mcs_inst->current_track_obj_sub_params); (void)bt_gatt_unsubscribe(conn, &mcs_inst->next_track_obj_sub_params); (void)bt_gatt_unsubscribe(conn, &mcs_inst->parent_group_obj_sub_params); (void)bt_gatt_unsubscribe(conn, &mcs_inst->current_group_obj_sub_params); #endif /* CONFIG_BT_MCC_OTS */ +#if defined(CONFIG_BT_MCC_READ_PLAYING_ORDER) (void)bt_gatt_unsubscribe(conn, &mcs_inst->playing_order_sub_params); +#endif /* defined(CONFIG_BT_MCC_READ_PLAYING_ORDER) */ +#if defined(CONFIG_BT_MCC_READ_MEDIA_STATE) (void)bt_gatt_unsubscribe(conn, &mcs_inst->media_state_sub_params); +#endif /* defined(CONFIG_BT_MCC_READ_MEDIA_STATE) */ (void)bt_gatt_unsubscribe(conn, &mcs_inst->cp_sub_params); +#if defined(CONFIG_BT_MCC_READ_MEDIA_CONTROL_POINT_OPCODES_SUPPORTED) (void)bt_gatt_unsubscribe(conn, &mcs_inst->opcodes_supported_sub_params); +#endif /* defined(CONFIG_BT_MCC_READ_MEDIA_CONTROL_POINT_OPCODES_SUPPORTED) */ #ifdef CONFIG_BT_MCC_OTS (void)bt_gatt_unsubscribe(conn, &mcs_inst->scp_sub_params); (void)bt_gatt_unsubscribe(conn, &mcs_inst->search_results_obj_sub_params); @@ -1428,31 +1490,41 @@ static bool subscribe_next_mcs_char(struct mcs_instance_t *mcs_inst, mcs_inst->track_changed_sub_params.disc_params == NULL) { sub_params = &mcs_inst->track_changed_sub_params; handle = mcs_inst->track_changed_handle; +#if defined(CONFIG_BT_MCC_READ_TRACK_TITLE_ENABLE_SUBSCRIPTION) } else if (mcs_inst->track_title_handle && mcs_inst->track_title_sub_params.value && mcs_inst->track_title_sub_params.disc_params == NULL) { sub_params = &mcs_inst->track_title_sub_params; handle = mcs_inst->track_title_handle; +#endif /* defined(CONFIG_BT_MCC_READ_TRACK_TITLE_ENABLE_SUBSCRIPTION) */ +#if defined(CONFIG_BT_MCC_READ_TRACK_DURATION) } else if (mcs_inst->track_duration_handle && mcs_inst->track_duration_sub_params.value && mcs_inst->track_duration_sub_params.disc_params == NULL) { sub_params = &mcs_inst->track_duration_sub_params; handle = mcs_inst->track_duration_handle; +#endif /* defined(CONFIG_BT_MCC_READ_TRACK_DURATION) */ +#if defined(CONFIG_BT_MCC_READ_TRACK_POSITION) } else if (mcs_inst->track_position_handle && mcs_inst->track_position_sub_params.value && mcs_inst->track_position_sub_params.disc_params == NULL) { sub_params = &mcs_inst->track_position_sub_params; handle = mcs_inst->track_position_handle; +#endif /* defined(CONFIG_BT_MCC_READ_TRACK_POSITION) */ +#if defined(CONFIG_BT_MCC_READ_PLAYBACK_SPEED) } else if (mcs_inst->playback_speed_handle && mcs_inst->playback_speed_sub_params.value && mcs_inst->playback_speed_sub_params.disc_params == NULL) { sub_params = &mcs_inst->playback_speed_sub_params; handle = mcs_inst->playback_speed_handle; +#endif /* defined (CONFIG_BT_MCC_READ_PLAYBACK_SPEED) */ +#if defined(CONFIG_BT_MCC_READ_SEEKING_SPEED) } else if (mcs_inst->seeking_speed_handle && mcs_inst->seeking_speed_sub_params.value && mcs_inst->seeking_speed_sub_params.disc_params == NULL) { sub_params = &mcs_inst->seeking_speed_sub_params; handle = mcs_inst->seeking_speed_handle; +#endif /* defined (CONFIG_BT_MCC_READ_SEEKING_SPEED) */ #ifdef CONFIG_BT_MCC_OTS } else if (mcs_inst->current_track_obj_id_handle && mcs_inst->current_track_obj_sub_params.value && @@ -1475,26 +1547,32 @@ static bool subscribe_next_mcs_char(struct mcs_instance_t *mcs_inst, sub_params = &mcs_inst->current_group_obj_sub_params; handle = mcs_inst->current_group_obj_id_handle; #endif /* CONFIG_BT_MCC_OTS */ +#if defined(CONFIG_BT_MCC_READ_PLAYING_ORDER) } else if (mcs_inst->playing_order_handle && mcs_inst->playing_order_sub_params.value && mcs_inst->playing_order_sub_params.disc_params == NULL) { sub_params = &mcs_inst->playing_order_sub_params; handle = mcs_inst->playing_order_handle; +#endif /* defined(CONFIG_BT_MCC_READ_PLAYING_ORDER) */ +#if defined(CONFIG_BT_MCC_READ_MEDIA_STATE) } else if (mcs_inst->media_state_handle && mcs_inst->media_state_sub_params.value && mcs_inst->media_state_sub_params.disc_params == NULL) { sub_params = &mcs_inst->media_state_sub_params; handle = mcs_inst->media_state_handle; +#endif /* defined(CONFIG_BT_MCC_READ_MEDIA_STATE) */ } else if (mcs_inst->cp_handle && mcs_inst->cp_sub_params.value && mcs_inst->cp_sub_params.disc_params == NULL) { sub_params = &mcs_inst->cp_sub_params; handle = mcs_inst->cp_handle; +#if defined(CONFIG_BT_MCC_READ_MEDIA_CONTROL_POINT_OPCODES_SUPPORTED) } else if (mcs_inst->opcodes_supported_handle && mcs_inst->opcodes_supported_sub_params.value && mcs_inst->opcodes_supported_sub_params.disc_params == NULL) { sub_params = &mcs_inst->opcodes_supported_sub_params; handle = mcs_inst->opcodes_supported_handle; +#endif /* defined(CONFIG_BT_MCC_READ_MEDIA_CONTROL_POINT_OPCODES_SUPPORTED) */ #ifdef CONFIG_BT_MCC_OTS } else if (mcs_inst->scp_handle && mcs_inst->scp_sub_params.value && @@ -1567,9 +1645,11 @@ static uint8_t discover_mcs_char_func(struct bt_conn *conn, LOG_DBG("Icon Object, UUID: %s", bt_uuid_str(chrc->uuid)); mcs_inst->icon_obj_id_handle = chrc->value_handle; #endif /* CONFIG_BT_MCC_OTS */ +#if defined(CONFIG_BT_MCC_READ_MEDIA_PLAYER_ICON_URL) } else if (!bt_uuid_cmp(chrc->uuid, BT_UUID_MCS_ICON_URL)) { LOG_DBG("Icon URL, UUID: %s", bt_uuid_str(chrc->uuid)); mcs_inst->icon_url_handle = chrc->value_handle; +#endif /* defined(CONFIG_BT_MCC_READ_MEDIA_PLAYER_ICON_URL) */ } else if (!bt_uuid_cmp(chrc->uuid, BT_UUID_MCS_TRACK_CHANGED)) { LOG_DBG("Track Changed, UUID: %s", bt_uuid_str(chrc->uuid)); mcs_inst->track_changed_handle = chrc->value_handle; @@ -1577,13 +1657,18 @@ static uint8_t discover_mcs_char_func(struct bt_conn *conn, if (chrc->properties & BT_GATT_CHRC_NOTIFY) { mcs_inst->track_changed_sub_params.value = BT_GATT_CCC_NOTIFY; } +#if defined(CONFIG_BT_MCC_READ_TRACK_TITLE) } else if (!bt_uuid_cmp(chrc->uuid, BT_UUID_MCS_TRACK_TITLE)) { LOG_DBG("Track Title, UUID: %s", bt_uuid_str(chrc->uuid)); mcs_inst->track_title_handle = chrc->value_handle; +#if defined(BT_MCC_READ_TRACK_TITLE_ENABLE_SUBSCRIPTION) mcs_inst->track_title_sub_params.disc_params = NULL; if (chrc->properties & BT_GATT_CHRC_NOTIFY) { mcs_inst->track_title_sub_params.value = BT_GATT_CCC_NOTIFY; } +#endif /* defined(BT_MCC_READ_TRACK_TITLE_ENABLE_SUBSCRIPTION) */ +#endif /* defined(CONFIG_BT_MCC_READ_TRACK_TITLE) */ +#if defined(CONFIG_BT_MCC_READ_TRACK_DURATION) } else if (!bt_uuid_cmp(chrc->uuid, BT_UUID_MCS_TRACK_DURATION)) { LOG_DBG("Track Duration, UUID: %s", bt_uuid_str(chrc->uuid)); mcs_inst->track_duration_handle = chrc->value_handle; @@ -1591,20 +1676,32 @@ static uint8_t discover_mcs_char_func(struct bt_conn *conn, if (chrc->properties & BT_GATT_CHRC_NOTIFY) { mcs_inst->track_duration_sub_params.value = BT_GATT_CCC_NOTIFY; } +#endif /* defined(CONFIG_BT_MCC_READ_TRACK_DURATION) */ +#if defined(CONFIG_BT_MCC_READ_TRACK_POSITION) || defined(CONFIG_BT_MCC_SET_TRACK_POSITION) } else if (!bt_uuid_cmp(chrc->uuid, BT_UUID_MCS_TRACK_POSITION)) { LOG_DBG("Track Position, UUID: %s", bt_uuid_str(chrc->uuid)); mcs_inst->track_position_handle = chrc->value_handle; +#if defined(CONFIG_BT_MCC_READ_TRACK_POSITION) mcs_inst->track_position_sub_params.disc_params = NULL; if (chrc->properties & BT_GATT_CHRC_NOTIFY) { mcs_inst->track_position_sub_params.value = BT_GATT_CCC_NOTIFY; } +#endif /* defined(CONFIG_BT_MCC_READ_TRACK_POSITION) */ +#endif /* defined(CONFIG_BT_MCC_READ_TRACK_POSITION) || defined(CONFIG_BT_MCC_SET_TRACK_POSITION) */ +#if defined(CONFIG_BT_MCC_READ_PLAYBACK_SPEED) || defined(CONFIG_BT_MCC_SET_PLAYBACK_SPEED) } else if (!bt_uuid_cmp(chrc->uuid, BT_UUID_MCS_PLAYBACK_SPEED)) { LOG_DBG("Playback Speed, UUID: %s", bt_uuid_str(chrc->uuid)); mcs_inst->playback_speed_handle = chrc->value_handle; +#if defined(CONFIG_BT_MCC_READ_PLAYBACK_SPEED) mcs_inst->playback_speed_sub_params.disc_params = NULL; if (chrc->properties & BT_GATT_CHRC_NOTIFY) { mcs_inst->playback_speed_sub_params.value = BT_GATT_CCC_NOTIFY; } +#endif /* defined (CONFIG_BT_MCC_READ_PLAYBACK_SPEED) */ +#endif /* defined (CONFIG_BT_MCC_READ_PLAYBACK_SPEED) || + * defined (CONFIG_BT_MCC_SET_PLAYBACK_SPEED) + */ +#if defined(CONFIG_BT_MCC_READ_SEEKING_SPEED) } else if (!bt_uuid_cmp(chrc->uuid, BT_UUID_MCS_SEEKING_SPEED)) { LOG_DBG("Seeking Speed, UUID: %s", bt_uuid_str(chrc->uuid)); mcs_inst->seeking_speed_handle = chrc->value_handle; @@ -1612,6 +1709,7 @@ static uint8_t discover_mcs_char_func(struct bt_conn *conn, if (chrc->properties & BT_GATT_CHRC_NOTIFY) { mcs_inst->seeking_speed_sub_params.value = BT_GATT_CCC_NOTIFY; } +#endif /* defined (CONFIG_BT_MCC_READ_SEEKING_SPEED) */ #ifdef CONFIG_BT_MCC_OTS } else if (!bt_uuid_cmp(chrc->uuid, BT_UUID_MCS_TRACK_SEGMENTS_OBJ_ID)) { LOG_DBG("Track Segments Object, UUID: %s", bt_uuid_str(chrc->uuid)); @@ -1648,16 +1746,23 @@ static uint8_t discover_mcs_char_func(struct bt_conn *conn, BT_GATT_CCC_NOTIFY; } #endif /* CONFIG_BT_MCC_OTS */ +#if defined(CONFIG_BT_MCC_READ_PLAYING_ORDER) || defined(CONFIG_BT_MCC_SET_PLAYING_ORDER) } else if (!bt_uuid_cmp(chrc->uuid, BT_UUID_MCS_PLAYING_ORDER)) { LOG_DBG("Playing Order, UUID: %s", bt_uuid_str(chrc->uuid)); mcs_inst->playing_order_handle = chrc->value_handle; +#if defined(CONFIG_BT_MCC_READ_PLAYING_ORDER) mcs_inst->playing_order_sub_params.disc_params = NULL; if (chrc->properties & BT_GATT_CHRC_NOTIFY) { mcs_inst->playing_order_sub_params.value = BT_GATT_CCC_NOTIFY; } +#endif /* defined(CONFIG_BT_MCC_READ_PLAYING_ORDER) */ +#endif /* defined(CONFIG_BT_MCC_READ_PLAYING_ORDER) || defined(CONFIG_BT_MCC_SET_PLAYING_ORDER) */ +#if defined(CONFIG_BT_MCC_READ_PLAYING_ORDER_SUPPORTED) } else if (!bt_uuid_cmp(chrc->uuid, BT_UUID_MCS_PLAYING_ORDERS)) { LOG_DBG("Playing Orders supported, UUID: %s", bt_uuid_str(chrc->uuid)); mcs_inst->playing_orders_supported_handle = chrc->value_handle; +#endif /* defined(CONFIG_BT_MCC_READ_PLAYING_ORDER_SUPPORTED) */ +#if defined(CONFIG_BT_MCC_READ_MEDIA_STATE) } else if (!bt_uuid_cmp(chrc->uuid, BT_UUID_MCS_MEDIA_STATE)) { LOG_DBG("Media State, UUID: %s", bt_uuid_str(chrc->uuid)); mcs_inst->media_state_handle = chrc->value_handle; @@ -1665,6 +1770,7 @@ static uint8_t discover_mcs_char_func(struct bt_conn *conn, if (chrc->properties & BT_GATT_CHRC_NOTIFY) { mcs_inst->media_state_sub_params.value = BT_GATT_CCC_NOTIFY; } +#endif /* defined(CONFIG_BT_MCC_READ_MEDIA_STATE) */ } else if (!bt_uuid_cmp(chrc->uuid, BT_UUID_MCS_MEDIA_CONTROL_POINT)) { LOG_DBG("Media Control Point, UUID: %s", bt_uuid_str(chrc->uuid)); mcs_inst->cp_handle = chrc->value_handle; @@ -1672,6 +1778,7 @@ static uint8_t discover_mcs_char_func(struct bt_conn *conn, if (chrc->properties & BT_GATT_CHRC_NOTIFY) { mcs_inst->cp_sub_params.value = BT_GATT_CCC_NOTIFY; } +#if defined(CONFIG_BT_MCC_READ_MEDIA_CONTROL_POINT_OPCODES_SUPPORTED) } else if (!bt_uuid_cmp(chrc->uuid, BT_UUID_MCS_MEDIA_CONTROL_OPCODES)) { LOG_DBG("Media control opcodes supported, UUID: %s", bt_uuid_str(chrc->uuid)); @@ -1681,6 +1788,7 @@ static uint8_t discover_mcs_char_func(struct bt_conn *conn, mcs_inst->opcodes_supported_sub_params.value = BT_GATT_CCC_NOTIFY; } +#endif /* defined(CONFIG_BT_MCC_READ_MEDIA_CONTROL_POINT_OPCODES_SUPPORTED) */ #ifdef CONFIG_BT_MCC_OTS } else if (!bt_uuid_cmp(chrc->uuid, BT_UUID_MCS_SEARCH_CONTROL_POINT)) { LOG_DBG("Search control point, UUID: %s", bt_uuid_str(chrc->uuid)); @@ -1698,9 +1806,11 @@ static uint8_t discover_mcs_char_func(struct bt_conn *conn, BT_GATT_CCC_NOTIFY; } #endif /* CONFIG_BT_MCC_OTS */ +#if defined(CONFIG_BT_MCC_READ_CONTENT_CONTROL_ID) } else if (!bt_uuid_cmp(chrc->uuid, BT_UUID_CCID)) { LOG_DBG("Content Control ID, UUID: %s", bt_uuid_str(chrc->uuid)); mcs_inst->content_control_id_handle = chrc->value_handle; +#endif /* defined(CONFIG_BT_MCC_READ_CONTENT_CONTROL_ID) */ } @@ -1937,6 +2047,7 @@ int bt_mcc_read_icon_obj_id(struct bt_conn *conn) } #endif /* CONFIG_BT_MCC_OTS */ +#if defined(CONFIG_BT_MCC_READ_MEDIA_PLAYER_ICON_URL) int bt_mcc_read_icon_url(struct bt_conn *conn) { struct mcs_instance_t *mcs_inst; @@ -1974,7 +2085,9 @@ int bt_mcc_read_icon_url(struct bt_conn *conn) } return err; } +#endif /* defined(CONFIG_BT_MCC_READ_MEDIA_PLAYER_ICON_URL) */ +#if defined(CONFIG_BT_MCC_READ_TRACK_TITLE) int bt_mcc_read_track_title(struct bt_conn *conn) { struct mcs_instance_t *mcs_inst; @@ -2012,7 +2125,9 @@ int bt_mcc_read_track_title(struct bt_conn *conn) } return err; } +#endif /* defined(CONFIG_BT_MCC_READ_TRACK_TITLE) */ +#if defined(CONFIG_BT_MCC_READ_TRACK_DURATION) int bt_mcc_read_track_duration(struct bt_conn *conn) { struct mcs_instance_t *mcs_inst; @@ -2050,7 +2165,9 @@ int bt_mcc_read_track_duration(struct bt_conn *conn) } return err; } +#endif /* defined(CONFIG_BT_MCC_READ_TRACK_DURATION) */ +#if defined(CONFIG_BT_MCC_READ_TRACK_POSITION) int bt_mcc_read_track_position(struct bt_conn *conn) { struct mcs_instance_t *mcs_inst; @@ -2088,7 +2205,9 @@ int bt_mcc_read_track_position(struct bt_conn *conn) } return err; } +#endif /* defined(CONFIG_BT_MCC_READ_TRACK_POSITION) */ +#if defined(CONFIG_BT_MCC_SET_TRACK_POSITION) int bt_mcc_set_track_position(struct bt_conn *conn, int32_t pos) { struct mcs_instance_t *mcs_inst; @@ -2131,7 +2250,9 @@ int bt_mcc_set_track_position(struct bt_conn *conn, int32_t pos) } return err; } +#endif /* defined(CONFIG_BT_MCC_SET_TRACK_POSITION) */ +#if defined(CONFIG_BT_MCC_READ_PLAYBACK_SPEED) int bt_mcc_read_playback_speed(struct bt_conn *conn) { struct mcs_instance_t *mcs_inst; @@ -2169,7 +2290,9 @@ int bt_mcc_read_playback_speed(struct bt_conn *conn) } return err; } +#endif /* defined (CONFIG_BT_MCC_READ_PLAYBACK_SPEED) */ +#if defined(CONFIG_BT_MCC_SET_PLAYBACK_SPEED) int bt_mcc_set_playback_speed(struct bt_conn *conn, int8_t speed) { struct mcs_instance_t *mcs_inst; @@ -2212,7 +2335,9 @@ int bt_mcc_set_playback_speed(struct bt_conn *conn, int8_t speed) } return err; } +#endif /* defined (CONFIG_BT_MCC_SET_PLAYBACK_SPEED) */ +#if defined(CONFIG_BT_MCC_READ_SEEKING_SPEED) int bt_mcc_read_seeking_speed(struct bt_conn *conn) { struct mcs_instance_t *mcs_inst; @@ -2250,6 +2375,7 @@ int bt_mcc_read_seeking_speed(struct bt_conn *conn) } return err; } +#endif /* defined (CONFIG_BT_MCC_READ_SEEKING_SPEED) */ #ifdef CONFIG_BT_MCC_OTS int bt_mcc_read_segments_obj_id(struct bt_conn *conn) @@ -2584,6 +2710,7 @@ int bt_mcc_set_current_group_obj_id(struct bt_conn *conn, uint64_t obj_id) } #endif /* CONFIG_BT_MCC_OTS */ +#if defined(CONFIG_BT_MCC_READ_PLAYING_ORDER) int bt_mcc_read_playing_order(struct bt_conn *conn) { struct mcs_instance_t *mcs_inst; @@ -2621,7 +2748,9 @@ int bt_mcc_read_playing_order(struct bt_conn *conn) } return err; } +#endif /* defined(CONFIG_BT_MCC_READ_PLAYING_ORDER) */ +#if defined(CONFIG_BT_MCC_SET_PLAYING_ORDER) int bt_mcc_set_playing_order(struct bt_conn *conn, uint8_t order) { struct mcs_instance_t *mcs_inst; @@ -2672,7 +2801,9 @@ int bt_mcc_set_playing_order(struct bt_conn *conn, uint8_t order) } return err; } +#endif /* defined(CONFIG_BT_MCC_SET_PLAYING_ORDER) */ +#if defined(CONFIG_BT_MCC_READ_PLAYING_ORDER_SUPPORTED) int bt_mcc_read_playing_orders_supported(struct bt_conn *conn) { struct mcs_instance_t *mcs_inst; @@ -2710,7 +2841,9 @@ int bt_mcc_read_playing_orders_supported(struct bt_conn *conn) } return err; } +#endif /* defined(CONFIG_BT_MCC_READ_PLAYING_ORDER_SUPPORTED) */ +#if defined(CONFIG_BT_MCC_READ_MEDIA_STATE) int bt_mcc_read_media_state(struct bt_conn *conn) { struct mcs_instance_t *mcs_inst; @@ -2748,7 +2881,9 @@ int bt_mcc_read_media_state(struct bt_conn *conn) } return err; } +#endif /* defined(CONFIG_BT_MCC_READ_MEDIA_STATE) */ +#if defined(CONFIG_BT_MCC_SET_MEDIA_CONTROL_POINT) int bt_mcc_send_cmd(struct bt_conn *conn, const struct mpl_cmd *cmd) { struct mcs_instance_t *mcs_inst; @@ -2810,7 +2945,9 @@ int bt_mcc_send_cmd(struct bt_conn *conn, const struct mpl_cmd *cmd) } return err; } +#endif /* defined(CONFIG_BT_MCC_SET_MEDIA_CONTROL_POINT) */ +#if defined(CONFIG_BT_MCC_READ_MEDIA_CONTROL_POINT_OPCODES_SUPPORTED) int bt_mcc_read_opcodes_supported(struct bt_conn *conn) { struct mcs_instance_t *mcs_inst; @@ -2848,6 +2985,7 @@ int bt_mcc_read_opcodes_supported(struct bt_conn *conn) } return err; } +#endif /* defined(CONFIG_BT_MCC_READ_MEDIA_CONTROL_POINT_OPCODES_SUPPORTED) */ #ifdef CONFIG_BT_MCC_OTS int bt_mcc_send_search(struct bt_conn *conn, const struct mpl_search *search) @@ -2944,6 +3082,7 @@ int bt_mcc_read_search_results_obj_id(struct bt_conn *conn) } #endif /* CONFIG_BT_MCC_OTS */ +#if defined(CONFIG_BT_MCC_READ_CONTENT_CONTROL_ID) int bt_mcc_read_content_control_id(struct bt_conn *conn) { struct mcs_instance_t *mcs_inst; @@ -2981,6 +3120,7 @@ int bt_mcc_read_content_control_id(struct bt_conn *conn) } return err; } +#endif /* defined(CONFIG_BT_MCC_READ_CONTENT_CONTROL_ID) */ #ifdef CONFIG_BT_MCC_OTS diff --git a/subsys/bluetooth/audio/mcc_internal.h b/subsys/bluetooth/audio/mcc_internal.h index 61c954d47af..2d005d1fbee 100644 --- a/subsys/bluetooth/audio/mcc_internal.h +++ b/subsys/bluetooth/audio/mcc_internal.h @@ -25,13 +25,26 @@ struct mcs_instance_t { #ifdef CONFIG_BT_MCC_OTS uint16_t icon_obj_id_handle; #endif /* CONFIG_BT_MCC_OTS */ +#if defined(CONFIG_BT_MCC_READ_MEDIA_PLAYER_ICON_URL) uint16_t icon_url_handle; +#endif /* defined(CONFIG_BT_MCC_READ_MEDIA_PLAYER_ICON_URL) */ uint16_t track_changed_handle; +#if defined(CONFIG_BT_MCC_READ_TRACK_TITLE) uint16_t track_title_handle; +#endif /* defined(CONFIG_BT_MCC_READ_TRACK_TITLE) */ +#if defined(CONFIG_BT_MCC_READ_TRACK_DURATION) uint16_t track_duration_handle; +#endif /* defined(CONFIG_BT_MCC_READ_TRACK_DURATION) */ +#if defined(CONFIG_BT_MCC_READ_TRACK_POSITION) || defined(CONFIG_BT_MCC_SET_TRACK_POSITION) uint16_t track_position_handle; +#endif /* defined(CONFIG_BT_MCC_READ_TRACK_POSITION) || defined(CONFIG_BT_MCC_SET_TRACK_POSITION) */ +#if defined(CONFIG_BT_MCC_READ_PLAYBACK_SPEED) || defined(CONFIG_BT_MCC_SET_PLAYBACK_SPEED) uint16_t playback_speed_handle; +#endif /* defined (CONFIG_BT_MCC_READ_PLAYBACK_SPEED) || */ + /* defined (CONFIG_BT_MCC_SET_PLAYBACK_SPEED) */ +#if defined(CONFIG_BT_MCC_READ_SEEKING_SPEED) uint16_t seeking_speed_handle; +#endif /* defined (CONFIG_BT_MCC_READ_SEEKING_SPEED) */ #ifdef CONFIG_BT_MCC_OTS uint16_t segments_obj_id_handle; uint16_t current_track_obj_id_handle; @@ -39,16 +52,26 @@ struct mcs_instance_t { uint16_t current_group_obj_id_handle; uint16_t parent_group_obj_id_handle; #endif /* CONFIG_BT_MCC_OTS */ +#if defined(CONFIG_BT_MCC_READ_PLAYING_ORDER) || defined(CONFIG_BT_MCC_SET_PLAYING_ORDER) uint16_t playing_order_handle; +#endif /* defined(CONFIG_BT_MCC_READ_PLAYING_ORDER) || defined(CONFIG_BT_MCC_SET_PLAYING_ORDER) */ +#if defined(CONFIG_BT_MCC_READ_PLAYING_ORDER_SUPPORTED) uint16_t playing_orders_supported_handle; +#endif /* defined(CONFIG_BT_MCC_READ_PLAYING_ORDER_SUPPORTED) */ +#if defined(CONFIG_BT_MCC_READ_MEDIA_STATE) uint16_t media_state_handle; +#endif /* defined(CONFIG_BT_MCC_READ_MEDIA_STATE) */ uint16_t cp_handle; +#if defined(CONFIG_BT_MCC_READ_MEDIA_CONTROL_POINT_OPCODES_SUPPORTED) uint16_t opcodes_supported_handle; +#endif /* defined(CONFIG_BT_MCC_READ_MEDIA_CONTROL_POINT_OPCODES_SUPPORTED) */ #ifdef CONFIG_BT_MCC_OTS uint16_t scp_handle; uint16_t search_results_obj_id_handle; #endif /* CONFIG_BT_MCC_OTS */ +#if defined(CONFIG_BT_MCC_READ_CONTENT_CONTROL_ID) uint16_t content_control_id_handle; +#endif /* defined(CONFIG_BT_MCC_READ_CONTENT_CONTROL_ID) */ /* The write buffer is used for @@ -84,21 +107,37 @@ struct mcs_instance_t { struct bt_gatt_subscribe_params player_name_sub_params; struct bt_gatt_subscribe_params track_changed_sub_params; +#if defined(CONFIG_BT_MCC_READ_TRACK_TITLE_ENABLE_SUBSCRIPTION) struct bt_gatt_subscribe_params track_title_sub_params; +#endif /* defined(CONFIG_BT_MCC_READ_TRACK_TITLE_ENABLE_SUBSCRIPTION) */ +#if defined(CONFIG_BT_MCC_READ_TRACK_DURATION) struct bt_gatt_subscribe_params track_duration_sub_params; +#endif /* defined(CONFIG_BT_MCC_READ_TRACK_DURATION) */ +#if defined(CONFIG_BT_MCC_READ_TRACK_POSITION) struct bt_gatt_subscribe_params track_position_sub_params; +#endif /* defined(CONFIG_BT_MCC_READ_TRACK_POSITION)*/ +#if defined(CONFIG_BT_MCC_READ_PLAYBACK_SPEED) struct bt_gatt_subscribe_params playback_speed_sub_params; +#endif /* defined (CONFIG_BT_MCC_READ_PLAYBACK_SPEED) */ +#if defined(CONFIG_BT_MCC_READ_SEEKING_SPEED) struct bt_gatt_subscribe_params seeking_speed_sub_params; +#endif /* defined (CONFIG_BT_MCC_READ_SEEKING_SPEED) */ #ifdef CONFIG_BT_MCC_OTS struct bt_gatt_subscribe_params current_track_obj_sub_params; struct bt_gatt_subscribe_params next_track_obj_sub_params; struct bt_gatt_subscribe_params parent_group_obj_sub_params; struct bt_gatt_subscribe_params current_group_obj_sub_params; #endif /* CONFIG_BT_MCC_OTS */ +#if defined(CONFIG_BT_MCC_READ_PLAYING_ORDER) struct bt_gatt_subscribe_params playing_order_sub_params; +#endif /* defined(CONFIG_BT_MCC_READ_PLAYING_ORDER) */ +#if defined(CONFIG_BT_MCC_READ_MEDIA_STATE) struct bt_gatt_subscribe_params media_state_sub_params; +#endif /* defined(CONFIG_BT_MCC_READ_MEDIA_STATE) */ struct bt_gatt_subscribe_params cp_sub_params; +#if defined(CONFIG_BT_MCC_READ_MEDIA_CONTROL_POINT_OPCODES_SUPPORTED) struct bt_gatt_subscribe_params opcodes_supported_sub_params; +#endif /* defined(CONFIG_BT_MCC_READ_MEDIA_CONTROL_POINT_OPCODES_SUPPORTED) */ #ifdef CONFIG_BT_MCC_OTS struct bt_gatt_subscribe_params scp_sub_params; struct bt_gatt_subscribe_params search_results_obj_sub_params; diff --git a/subsys/bluetooth/audio/media_proxy.c b/subsys/bluetooth/audio/media_proxy.c index 3fcf35fc37a..e816b1f20a0 100644 --- a/subsys/bluetooth/audio/media_proxy.c +++ b/subsys/bluetooth/audio/media_proxy.c @@ -278,6 +278,7 @@ static void mcc_read_icon_obj_id_cb(struct bt_conn *conn, int err, uint64_t id) } #endif /* CONFIG_MCTL_REMOTE_PLAYER_CONTROL_OBJECTS */ +#if defined(CONFIG_BT_MCC_READ_MEDIA_PLAYER_ICON_URL) static void mcc_read_icon_url_cb(struct bt_conn *conn, int err, const char *url) { if (err) { @@ -290,6 +291,7 @@ static void mcc_read_icon_url_cb(struct bt_conn *conn, int err, const char *url) LOG_DBG("No callback"); } } +#endif /* defined(CONFIG_BT_MCC_READ_MEDIA_PLAYER_ICON_URL) */ static void mcc_track_changed_ntf_cb(struct bt_conn *conn, int err) { @@ -305,6 +307,7 @@ static void mcc_track_changed_ntf_cb(struct bt_conn *conn, int err) } } +#if defined(CONFIG_BT_MCC_READ_TRACK_TITLE) static void mcc_read_track_title_cb(struct bt_conn *conn, int err, const char *title) { if (err) { @@ -317,7 +320,9 @@ static void mcc_read_track_title_cb(struct bt_conn *conn, int err, const char *t LOG_DBG("No callback"); } } +#endif /* defined(CONFIG_BT_MCC_READ_TRACK_TITLE) */ +#if defined(CONFIG_BT_MCC_READ_TRACK_DURATION) static void mcc_read_track_duration_cb(struct bt_conn *conn, int err, int32_t dur) { if (err) { @@ -330,7 +335,9 @@ static void mcc_read_track_duration_cb(struct bt_conn *conn, int err, int32_t du LOG_DBG("No callback"); } } +#endif /* defined(CONFIG_BT_MCC_READ_TRACK_DURATION) */ +#if defined(CONFIG_BT_MCC_READ_TRACK_POSITION) static void mcc_read_track_position_cb(struct bt_conn *conn, int err, int32_t pos) { if (err) { @@ -343,7 +350,9 @@ static void mcc_read_track_position_cb(struct bt_conn *conn, int err, int32_t po LOG_DBG("No callback"); } } +#endif /* defined(CONFIG_BT_MCC_READ_TRACK_POSITION) */ +#if defined(CONFIG_BT_MCC_SET_TRACK_POSITION) static void mcc_set_track_position_cb(struct bt_conn *conn, int err, int32_t pos) { if (err) { @@ -356,7 +365,9 @@ static void mcc_set_track_position_cb(struct bt_conn *conn, int err, int32_t pos LOG_DBG("No callback"); } } +#endif /* defined(CONFIG_BT_MCC_SET_TRACK_POSITION) */ +#if defined(CONFIG_BT_MCC_READ_PLAYBACK_SPEED) static void mcc_read_playback_speed_cb(struct bt_conn *conn, int err, int8_t speed) { if (err) { @@ -369,7 +380,9 @@ static void mcc_read_playback_speed_cb(struct bt_conn *conn, int err, int8_t spe LOG_DBG("No callback"); } } +#endif /* defined (CONFIG_BT_MCC_READ_PLAYBACK_SPEED) */ +#if defined(CONFIG_BT_MCC_SET_PLAYBACK_SPEED) static void mcc_set_playback_speed_cb(struct bt_conn *conn, int err, int8_t speed) { if (err) { @@ -382,7 +395,9 @@ static void mcc_set_playback_speed_cb(struct bt_conn *conn, int err, int8_t spee LOG_DBG("No callback"); } } +#endif /* defined (CONFIG_BT_MCC_SET_PLAYBACK_SPEED) */ +#if defined(CONFIG_BT_MCC_READ_SEEKING_SPEED) static void mcc_read_seeking_speed_cb(struct bt_conn *conn, int err, int8_t speed) { if (err) { @@ -395,6 +410,7 @@ static void mcc_read_seeking_speed_cb(struct bt_conn *conn, int err, int8_t spee LOG_DBG("No callback"); } } +#endif /* defined (CONFIG_BT_MCC_READ_SEEKING_SPEED) */ #ifdef CONFIG_MCTL_REMOTE_PLAYER_CONTROL_OBJECTS static void mcc_read_segments_obj_id_cb(struct bt_conn *conn, int err, uint64_t id) @@ -470,6 +486,7 @@ static void mcc_read_current_group_obj_id_cb(struct bt_conn *conn, int err, uint #endif /* CONFIG_MCTL_REMOTE_PLAYER_CONTROL_OBJECTS */ +#if defined(CONFIG_BT_MCC_READ_PLAYING_ORDER) static void mcc_read_playing_order_cb(struct bt_conn *conn, int err, uint8_t order) { if (err) { @@ -482,7 +499,9 @@ static void mcc_read_playing_order_cb(struct bt_conn *conn, int err, uint8_t ord LOG_DBG("No callback"); } } +#endif /* defined(CONFIG_BT_MCC_READ_PLAYING_ORDER) */ +#if defined(CONFIG_BT_MCC_SET_PLAYING_ORDER) static void mcc_set_playing_order_cb(struct bt_conn *conn, int err, uint8_t order) { if (err) { @@ -495,7 +514,9 @@ static void mcc_set_playing_order_cb(struct bt_conn *conn, int err, uint8_t orde LOG_DBG("No callback"); } } +#endif /* defined(CONFIG_BT_MCC_SET_PLAYING_ORDER) */ +#if defined(CONFIG_BT_MCC_READ_PLAYING_ORDER_SUPPORTED) static void mcc_read_playing_orders_supported_cb(struct bt_conn *conn, int err, uint16_t orders) { if (err) { @@ -508,7 +529,9 @@ static void mcc_read_playing_orders_supported_cb(struct bt_conn *conn, int err, LOG_DBG("No callback"); } } +#endif /* defined(CONFIG_BT_MCC_READ_PLAYING_ORDER_SUPPORTED) */ +#if defined(CONFIG_BT_MCC_READ_MEDIA_STATE) static void mcc_read_media_state_cb(struct bt_conn *conn, int err, uint8_t state) { if (err) { @@ -521,7 +544,9 @@ static void mcc_read_media_state_cb(struct bt_conn *conn, int err, uint8_t state LOG_DBG("No callback"); } } +#endif /* defined(CONFIG_BT_MCC_READ_MEDIA_STATE) */ +#if defined(CONFIG_BT_MCC_SET_MEDIA_CONTROL_POINT) static void mcc_send_cmd_cb(struct bt_conn *conn, int err, const struct mpl_cmd *cmd) { if (err) { @@ -535,6 +560,7 @@ static void mcc_send_cmd_cb(struct bt_conn *conn, int err, const struct mpl_cmd LOG_DBG("No callback"); } } +#endif /* defined(CONFIG_BT_MCC_SET_MEDIA_CONTROL_POINT) */ static void mcc_cmd_ntf_cb(struct bt_conn *conn, int err, const struct mpl_cmd_ntf *ntf) @@ -551,6 +577,7 @@ static void mcc_cmd_ntf_cb(struct bt_conn *conn, int err, } } +#if defined(CONFIG_BT_MCC_READ_MEDIA_CONTROL_POINT_OPCODES_SUPPORTED) static void mcc_read_opcodes_supported_cb(struct bt_conn *conn, int err, uint32_t opcodes) { if (err) { @@ -563,6 +590,7 @@ static void mcc_read_opcodes_supported_cb(struct bt_conn *conn, int err, uint32_ LOG_DBG("No callback"); } } +#endif /* defined(CONFIG_BT_MCC_READ_MEDIA_CONTROL_POINT_OPCODES_SUPPORTED) */ #ifdef CONFIG_MCTL_REMOTE_PLAYER_CONTROL_OBJECTS static void mcc_send_search_cb(struct bt_conn *conn, int err, const struct mpl_search *search) @@ -605,6 +633,7 @@ static void mcc_read_search_results_obj_id_cb(struct bt_conn *conn, int err, uin } #endif /* CONFIG_MCTL_REMOTE_PLAYER_CONTROL_OBJECTS */ +#if defined(CONFIG_BT_MCC_READ_CONTENT_CONTROL_ID) static void mcc_read_content_control_id_cb(struct bt_conn *conn, int err, uint8_t ccid) { if (err) { @@ -617,6 +646,7 @@ static void mcc_read_content_control_id_cb(struct bt_conn *conn, int err, uint8_ LOG_DBG("No callback"); } } +#endif /* defined(CONFIG_BT_MCC_READ_CONTENT_CONTROL_ID) */ #endif /* CONFIG_MCTL_REMOTE_PLAYER_CONTROL */ @@ -672,15 +702,31 @@ int media_proxy_ctrl_discover_player(struct bt_conn *conn) #ifdef CONFIG_MCTL_REMOTE_PLAYER_CONTROL_OBJECTS mprx.mcc_cbs.read_icon_obj_id = mcc_read_icon_obj_id_cb; #endif /* CONFIG_MCTL_REMOTE_PLAYER_CONTROL_OBJECTS */ +#if defined(CONFIG_BT_MCC_READ_MEDIA_PLAYER_ICON_URL) mprx.mcc_cbs.read_icon_url = mcc_read_icon_url_cb; +#endif /* defined(CONFIG_BT_MCC_READ_MEDIA_PLAYER_ICON_URL) */ mprx.mcc_cbs.track_changed_ntf = mcc_track_changed_ntf_cb; +#if defined(CONFIG_BT_MCC_READ_TRACK_TITLE) mprx.mcc_cbs.read_track_title = mcc_read_track_title_cb; +#endif /* defined(CONFIG_BT_MCC_READ_TRACK_TITLE) */ +#if defined(CONFIG_BT_MCC_READ_TRACK_DURATION) mprx.mcc_cbs.read_track_duration = mcc_read_track_duration_cb; +#endif /* defined(CONFIG_BT_MCC_READ_TRACK_DURATION) */ +#if defined(CONFIG_BT_MCC_READ_TRACK_POSITION) mprx.mcc_cbs.read_track_position = mcc_read_track_position_cb; +#endif /* defined(CONFIG_BT_MCC_READ_TRACK_POSITION) */ +#if defined(CONFIG_BT_MCC_SET_TRACK_POSITION) mprx.mcc_cbs.set_track_position = mcc_set_track_position_cb; +#endif /* defined(CONFIG_BT_MCC_SET_TRACK_POSITION) */ +#if defined(CONFIG_BT_MCC_READ_PLAYBACK_SPEED) mprx.mcc_cbs.read_playback_speed = mcc_read_playback_speed_cb; +#endif /* defined (CONFIG_BT_MCC_READ_PLAYBACK_SPEED) */ +#if defined(CONFIG_BT_MCC_SET_PLAYBACK_SPEED) mprx.mcc_cbs.set_playback_speed = mcc_set_playback_speed_cb; +#endif /* defined (CONFIG_BT_MCC_SET_PLAYBACK_SPEED) */ +#if defined(CONFIG_BT_MCC_READ_SEEKING_SPEED) mprx.mcc_cbs.read_seeking_speed = mcc_read_seeking_speed_cb; +#endif /* defined (CONFIG_BT_MCC_READ_SEEKING_SPEED) */ #ifdef CONFIG_MCTL_REMOTE_PLAYER_CONTROL_OBJECTS mprx.mcc_cbs.read_segments_obj_id = mcc_read_segments_obj_id_cb; mprx.mcc_cbs.read_current_track_obj_id = mcc_read_current_track_obj_id_cb; @@ -688,19 +734,33 @@ int media_proxy_ctrl_discover_player(struct bt_conn *conn) mprx.mcc_cbs.read_parent_group_obj_id = mcc_read_parent_group_obj_id_cb; mprx.mcc_cbs.read_current_group_obj_id = mcc_read_current_group_obj_id_cb; #endif /* CONFIG_MCTL_REMOTE_PLAYER_CONTROL_OBJECTS */ +#if defined(CONFIG_BT_MCC_READ_PLAYING_ORDER) mprx.mcc_cbs.read_playing_order = mcc_read_playing_order_cb; +#endif /* defined(CONFIG_BT_MCC_READ_PLAYING_ORDER) */ +#if defined(CONFIG_BT_MCC_SET_PLAYING_ORDER) mprx.mcc_cbs.set_playing_order = mcc_set_playing_order_cb; +#endif /* defined(CONFIG_BT_MCC_SET_PLAYING_ORDER) */ +#if defined(CONFIG_BT_MCC_READ_PLAYING_ORDER_SUPPORTED) mprx.mcc_cbs.read_playing_orders_supported = mcc_read_playing_orders_supported_cb; +#endif /* defined(CONFIG_BT_MCC_READ_PLAYING_ORDER_SUPPORTED) */ +#if defined(CONFIG_BT_MCC_READ_MEDIA_STATE) mprx.mcc_cbs.read_media_state = mcc_read_media_state_cb; +#endif /* defined(CONFIG_BT_MCC_READ_MEDIA_STATE) */ +#if defined(CONFIG_BT_MCC_SET_MEDIA_CONTROL_POINT) mprx.mcc_cbs.send_cmd = mcc_send_cmd_cb; +#endif /* defined(CONFIG_BT_MCC_SET_MEDIA_CONTROL_POINT) */ mprx.mcc_cbs.cmd_ntf = mcc_cmd_ntf_cb; +#if defined(CONFIG_BT_MCC_READ_MEDIA_CONTROL_POINT_OPCODES_SUPPORTED) mprx.mcc_cbs.read_opcodes_supported = mcc_read_opcodes_supported_cb; +#endif /* defined(CONFIG_BT_MCC_READ_MEDIA_CONTROL_POINT_OPCODES_SUPPORTED) */ #ifdef CONFIG_MCTL_REMOTE_PLAYER_CONTROL_OBJECTS mprx.mcc_cbs.send_search = mcc_send_search_cb; mprx.mcc_cbs.search_ntf = mcc_search_ntf_cb; mprx.mcc_cbs.read_search_results_obj_id = mcc_read_search_results_obj_id_cb; #endif /* CONFIG_MCTL_REMOTE_PLAYER_CONTROL_OBJECTS */ +#if defined(CONFIG_BT_MCC_READ_CONTENT_CONTROL_ID) mprx.mcc_cbs.read_content_control_id = mcc_read_content_control_id_cb; +#endif /* defined(CONFIG_BT_MCC_READ_CONTENT_CONTROL_ID) */ err = bt_mcc_init(&mprx.mcc_cbs); if (err) { @@ -825,11 +885,11 @@ int media_proxy_ctrl_get_icon_url(struct media_player *player) } #endif /* CONFIG_MCTL_LOCAL_PLAYER_LOCAL_CONTROL */ -#if defined(CONFIG_MCTL_REMOTE_PLAYER_CONTROL) +#if defined(CONFIG_MCTL_REMOTE_PLAYER_CONTROL) && defined(CONFIG_BT_MCC_READ_MEDIA_PLAYER_ICON_URL) if (mprx.remote_player.registered && player == &mprx.remote_player) { return bt_mcc_read_icon_url(mprx.remote_player.conn); } -#endif /* CONFIG_MCTL_REMOTE_PLAYER_CONTROL */ +#endif /* CONFIG_MCTL_REMOTE_PLAYER_CONTROL && CONFIG_BT_MCC_READ_MEDIA_PLAYER_ICON_URL */ return -EINVAL; } @@ -860,11 +920,11 @@ int media_proxy_ctrl_get_track_title(struct media_player *player) } #endif /* CONFIG_MCTL_LOCAL_PLAYER_LOCAL_CONTROL */ -#if defined(CONFIG_MCTL_REMOTE_PLAYER_CONTROL) +#if defined(CONFIG_MCTL_REMOTE_PLAYER_CONTROL) && defined(CONFIG_BT_MCC_READ_TRACK_TITLE) if (mprx.remote_player.registered && player == &mprx.remote_player) { return bt_mcc_read_track_title(mprx.remote_player.conn); } -#endif /* CONFIG_MCTL_REMOTE_PLAYER_CONTROL */ +#endif /* CONFIG_MCTL_REMOTE_PLAYER_CONTROL && CONFIG_BT_MCC_READ_TRACK_TITLE */ return -EINVAL; } @@ -896,11 +956,11 @@ int media_proxy_ctrl_get_track_duration(struct media_player *player) } #endif /* CONFIG_MCTL_LOCAL_PLAYER_LOCAL_CONTROL */ -#if defined(CONFIG_MCTL_REMOTE_PLAYER_CONTROL) +#if defined(CONFIG_MCTL_REMOTE_PLAYER_CONTROL) && defined(CONFIG_BT_MCC_READ_TRACK_DURATION) if (mprx.remote_player.registered && player == &mprx.remote_player) { return bt_mcc_read_track_duration(mprx.remote_player.conn); } -#endif /* CONFIG_MCTL_REMOTE_PLAYER_CONTROL */ +#endif /* CONFIG_MCTL_REMOTE_PLAYER_CONTROL && CONFIG_BT_MCC_READ_TRACK_DURATION */ return -EINVAL; } @@ -932,11 +992,11 @@ int media_proxy_ctrl_get_track_position(struct media_player *player) } #endif /* CONFIG_MCTL_LOCAL_PLAYER_LOCAL_CONTROL */ -#if defined(CONFIG_MCTL_REMOTE_PLAYER_CONTROL) +#if defined(CONFIG_MCTL_REMOTE_PLAYER_CONTROL) && defined(CONFIG_BT_MCC_READ_TRACK_POSITION) if (mprx.remote_player.registered && player == &mprx.remote_player) { return bt_mcc_read_track_position(mprx.remote_player.conn); } -#endif /* CONFIG_MCTL_REMOTE_PLAYER_CONTROL */ +#endif /* CONFIG_MCTL_REMOTE_PLAYER_CONTROL && CONFIG_BT_MCC_READ_TRACK_POSITION */ return -EINVAL; } @@ -967,11 +1027,11 @@ int media_proxy_ctrl_set_track_position(struct media_player *player, int32_t pos } #endif /* CONFIG_MCTL_LOCAL_PLAYER_LOCAL_CONTROL */ -#if defined(CONFIG_MCTL_REMOTE_PLAYER_CONTROL) +#if defined(CONFIG_MCTL_REMOTE_PLAYER_CONTROL) && CONFIG_BT_MCC_SET_TRACK_POSITION if (mprx.remote_player.registered && player == &mprx.remote_player) { return bt_mcc_set_track_position(mprx.remote_player.conn, position); } -#endif /* CONFIG_MCTL_REMOTE_PLAYER_CONTROL */ +#endif /* CONFIG_MCTL_REMOTE_PLAYER_CONTROL && CONFIG_BT_MCC_SET_TRACK_POSITION */ return -EINVAL; } @@ -1002,11 +1062,11 @@ int media_proxy_ctrl_get_playback_speed(struct media_player *player) } #endif /* CONFIG_MCTL_LOCAL_PLAYER_LOCAL_CONTROL */ -#if defined(CONFIG_MCTL_REMOTE_PLAYER_CONTROL) +#if defined(CONFIG_MCTL_REMOTE_PLAYER_CONTROL) && defined(CONFIG_BT_MCC_READ_PLAYBACK_SPEED) if (mprx.remote_player.registered && player == &mprx.remote_player) { return bt_mcc_read_playback_speed(mprx.remote_player.conn); } -#endif /* CONFIG_MCTL_REMOTE_PLAYER_CONTROL */ +#endif /* CONFIG_MCTL_REMOTE_PLAYER_CONTROL && CONFIG_BT_MCC_READ_PLAYBACK_SPEED */ return -EINVAL; } @@ -1037,11 +1097,11 @@ int media_proxy_ctrl_set_playback_speed(struct media_player *player, int8_t spee } #endif /* CONFIG_MCTL_LOCAL_PLAYER_LOCAL_CONTROL */ -#if defined(CONFIG_MCTL_REMOTE_PLAYER_CONTROL) +#if defined(CONFIG_MCTL_REMOTE_PLAYER_CONTROL) && defined(CONFIG_BT_MCC_SET_PLAYBACK_SPEED) if (mprx.remote_player.registered && player == &mprx.remote_player) { return bt_mcc_set_playback_speed(mprx.remote_player.conn, speed); } -#endif /* CONFIG_MCTL_REMOTE_PLAYER_CONTROL */ +#endif /* CONFIG_MCTL_REMOTE_PLAYER_CONTROL && CONFIG_BT_MCC_SET_PLAYBACK_SPEED */ return -EINVAL; } @@ -1072,11 +1132,11 @@ int media_proxy_ctrl_get_seeking_speed(struct media_player *player) } #endif /* CONFIG_MCTL_LOCAL_PLAYER_LOCAL_CONTROL */ -#if defined(CONFIG_MCTL_REMOTE_PLAYER_CONTROL) +#if defined(CONFIG_MCTL_REMOTE_PLAYER_CONTROL) && defined(CONFIG_BT_MCC_READ_SEEKING_SPEED) if (mprx.remote_player.registered && player == &mprx.remote_player) { return bt_mcc_read_seeking_speed(mprx.remote_player.conn); } -#endif /* CONFIG_MCTL_REMOTE_PLAYER_CONTROL */ +#endif /* CONFIG_MCTL_REMOTE_PLAYER_CONTROL && CONFIG_BT_MCC_READ_SEEKING_SPEED */ return -EINVAL; } @@ -1409,12 +1469,12 @@ int media_proxy_ctrl_get_playing_order(struct media_player *player) } #endif /* CONFIG_MCTL_LOCAL_PLAYER_LOCAL_CONTROL */ -#if defined(CONFIG_MCTL_REMOTE_PLAYER_CONTROL) +#if defined(CONFIG_MCTL_REMOTE_PLAYER_CONTROL) && defined(CONFIG_BT_MCC_READ_PLAYING_ORDER) if (mprx.remote_player.registered && player == &mprx.remote_player) { LOG_DBG("Remote player"); return bt_mcc_read_playing_order(mprx.remote_player.conn); } -#endif /* CONFIG_MCTL_REMOTE_PLAYER_CONTROL */ +#endif /* CONFIG_MCTL_REMOTE_PLAYER_CONTROL && CONFIG_BT_MCC_READ_PLAYING_ORDER */ return -EINVAL; } @@ -1445,11 +1505,11 @@ int media_proxy_ctrl_set_playing_order(struct media_player *player, uint8_t orde } #endif /* CONFIG_MCTL_LOCAL_PLAYER_LOCAL_CONTROL */ -#if defined(CONFIG_MCTL_REMOTE_PLAYER_CONTROL) +#if defined(CONFIG_MCTL_REMOTE_PLAYER_CONTROL) && defined(CONFIG_BT_MCC_SET_PLAYING_ORDER) if (mprx.remote_player.registered && player == &mprx.remote_player) { return bt_mcc_set_playing_order(mprx.remote_player.conn, order); } -#endif /* CONFIG_MCTL_REMOTE_PLAYER_CONTROL */ +#endif /* CONFIG_MCTL_REMOTE_PLAYER_CONTROL && CONFIG_BT_MCC_SET_PLAYING_ORDER */ return -EINVAL; } @@ -1481,11 +1541,12 @@ int media_proxy_ctrl_get_playing_orders_supported(struct media_player *player) } #endif /* CONFIG_MCTL_LOCAL_PLAYER_LOCAL_CONTROL */ -#if defined(CONFIG_MCTL_REMOTE_PLAYER_CONTROL) +#if defined(CONFIG_MCTL_REMOTE_PLAYER_CONTROL) && \ + defined(CONFIG_BT_MCC_READ_PLAYING_ORDER_SUPPORTED) if (mprx.remote_player.registered && player == &mprx.remote_player) { return bt_mcc_read_playing_orders_supported(mprx.remote_player.conn); } -#endif /* CONFIG_MCTL_REMOTE_PLAYER_CONTROL */ +#endif /* CONFIG_MCTL_REMOTE_PLAYER_CONTROL && CONFIG_BT_MCC_READ_PLAYING_ORDER_SUPPORTED */ return -EINVAL; } @@ -1516,11 +1577,11 @@ int media_proxy_ctrl_get_media_state(struct media_player *player) } #endif /* CONFIG_MCTL_LOCAL_PLAYER_LOCAL_CONTROL */ -#if defined(CONFIG_MCTL_REMOTE_PLAYER_CONTROL) +#if defined(CONFIG_MCTL_REMOTE_PLAYER_CONTROL) && defined(CONFIG_BT_MCC_READ_MEDIA_STATE) if (mprx.remote_player.registered && player == &mprx.remote_player) { return bt_mcc_read_media_state(mprx.remote_player.conn); } -#endif /* CONFIG_MCTL_REMOTE_PLAYER_CONTROL */ +#endif /* CONFIG_MCTL_REMOTE_PLAYER_CONTROL && CONFIG_BT_MCC_READ_MEDIA_STATE */ return -EINVAL; } @@ -1551,11 +1612,11 @@ int media_proxy_ctrl_send_command(struct media_player *player, const struct mpl_ } #endif /* CONFIG_MCTL_LOCAL_PLAYER_LOCAL_CONTROL */ -#if defined(CONFIG_MCTL_REMOTE_PLAYER_CONTROL) +#if defined(CONFIG_MCTL_REMOTE_PLAYER_CONTROL) && defined(CONFIG_BT_MCC_SET_MEDIA_CONTROL_POINT) if (mprx.remote_player.registered && player == &mprx.remote_player) { return bt_mcc_send_cmd(mprx.remote_player.conn, cmd); } -#endif /* CONFIG_MCTL_REMOTE_PLAYER_CONTROL */ +#endif /* CONFIG_MCTL_REMOTE_PLAYER_CONTROL && CONFIG_BT_MCC_SET_MEDIA_CONTROL_POINT */ return -EINVAL; } @@ -1587,11 +1648,14 @@ int media_proxy_ctrl_get_commands_supported(struct media_player *player) } #endif /* CONFIG_MCTL_LOCAL_PLAYER_LOCAL_CONTROL */ -#if defined(CONFIG_MCTL_REMOTE_PLAYER_CONTROL) +#if defined(CONFIG_MCTL_REMOTE_PLAYER_CONTROL) && \ + defined(CONFIG_BT_MCC_READ_MEDIA_CONTROL_POINT_OPCODES_SUPPORTED) if (mprx.remote_player.registered && player == &mprx.remote_player) { return bt_mcc_read_opcodes_supported(mprx.remote_player.conn); } -#endif /* CONFIG_MCTL_REMOTE_PLAYER_CONTROL */ +#endif /* CONFIG_MCTL_REMOTE_PLAYER_CONTROL && + * CONFIG_BT_MCC_READ_MEDIA_CONTROL_POINT_OPCODES_SUPPORTED + */ return -EINVAL; } @@ -1693,11 +1757,11 @@ uint8_t media_proxy_ctrl_get_content_ctrl_id(struct media_player *player) } #endif /* CONFIG_MCTL_LOCAL_PLAYER_LOCAL_CONTROL */ -#if defined(CONFIG_MCTL_REMOTE_PLAYER_CONTROL) +#if defined(CONFIG_MCTL_REMOTE_PLAYER_CONTROL) && defined(CONFIG_BT_MCC_READ_CONTENT_CONTROL_ID) if (mprx.remote_player.registered && player == &mprx.remote_player) { return bt_mcc_read_content_control_id(mprx.remote_player.conn); } -#endif /* CONFIG_MCTL_REMOTE_PLAYER_CONTROL */ +#endif /* CONFIG_MCTL_REMOTE_PLAYER_CONTROL && CONFIG_BT_MCC_READ_CONTENT_CONTROL_ID */ return -EINVAL; } diff --git a/subsys/bluetooth/audio/shell/mcc.c b/subsys/bluetooth/audio/shell/mcc.c index 34e1e0aee71..86412596850 100644 --- a/subsys/bluetooth/audio/shell/mcc.c +++ b/subsys/bluetooth/audio/shell/mcc.c @@ -78,6 +78,7 @@ static void mcc_read_icon_obj_id_cb(struct bt_conn *conn, int err, uint64_t id) } #endif /* CONFIG_BT_MCC_OTS */ +#if defined(CONFIG_BT_MCC_READ_MEDIA_PLAYER_ICON_URL) static void mcc_read_icon_url_cb(struct bt_conn *conn, int err, const char *url) { if (err) { @@ -87,7 +88,9 @@ static void mcc_read_icon_url_cb(struct bt_conn *conn, int err, const char *url) shell_print(ctx_shell, "Icon URL: 0x%s", url); } +#endif /* defined(CONFIG_BT_MCC_READ_MEDIA_PLAYER_ICON_URL) */ +#if defined(CONFIG_BT_MCC_READ_TRACK_TITLE) static void mcc_read_track_title_cb(struct bt_conn *conn, int err, const char *title) { if (err) { @@ -97,6 +100,7 @@ static void mcc_read_track_title_cb(struct bt_conn *conn, int err, const char *t shell_print(ctx_shell, "Track title: %s", title); } +#endif /* defined(CONFIG_BT_MCC_READ_TRACK_TITLE) */ static void mcc_track_changed_ntf_cb(struct bt_conn *conn, int err) { @@ -108,6 +112,7 @@ static void mcc_track_changed_ntf_cb(struct bt_conn *conn, int err) shell_print(ctx_shell, "Track changed"); } +#if defined(CONFIG_BT_MCC_READ_TRACK_DURATION) static void mcc_read_track_duration_cb(struct bt_conn *conn, int err, int32_t dur) { if (err) { @@ -117,7 +122,9 @@ static void mcc_read_track_duration_cb(struct bt_conn *conn, int err, int32_t du shell_print(ctx_shell, "Track duration: %d", dur); } +#endif /* defined(CONFIG_BT_MCC_READ_TRACK_DURATION) */ +#if defined(CONFIG_BT_MCC_READ_TRACK_POSITION) static void mcc_read_track_position_cb(struct bt_conn *conn, int err, int32_t pos) { if (err) { @@ -127,7 +134,9 @@ static void mcc_read_track_position_cb(struct bt_conn *conn, int err, int32_t po shell_print(ctx_shell, "Track Position: %d", pos); } +#endif /* defined(CONFIG_BT_MCC_READ_TRACK_POSITION) */ +#if defined(CONFIG_BT_MCC_SET_TRACK_POSITION) static void mcc_set_track_position_cb(struct bt_conn *conn, int err, int32_t pos) { if (err) { @@ -137,7 +146,9 @@ static void mcc_set_track_position_cb(struct bt_conn *conn, int err, int32_t pos shell_print(ctx_shell, "Track Position: %d", pos); } +#endif /* defined(CONFIG_BT_MCC_SET_TRACK_POSITION) */ +#if defined(CONFIG_BT_MCC_READ_PLAYBACK_SPEED) static void mcc_read_playback_speed_cb(struct bt_conn *conn, int err, int8_t speed) { @@ -148,7 +159,9 @@ static void mcc_read_playback_speed_cb(struct bt_conn *conn, int err, shell_print(ctx_shell, "Playback speed: %d", speed); } +#endif /* defined (CONFIG_BT_MCC_READ_PLAYBACK_SPEED) */ +#if defined(CONFIG_BT_MCC_SET_PLAYBACK_SPEED) static void mcc_set_playback_speed_cb(struct bt_conn *conn, int err, int8_t speed) { if (err) { @@ -158,7 +171,9 @@ static void mcc_set_playback_speed_cb(struct bt_conn *conn, int err, int8_t spee shell_print(ctx_shell, "Playback speed: %d", speed); } +#endif /* defined (CONFIG_BT_MCC_SET_PLAYBACK_SPEED) */ +#if defined(CONFIG_BT_MCC_READ_SEEKING_SPEED) static void mcc_read_seeking_speed_cb(struct bt_conn *conn, int err, int8_t speed) { @@ -169,6 +184,7 @@ static void mcc_read_seeking_speed_cb(struct bt_conn *conn, int err, shell_print(ctx_shell, "Seeking speed: %d", speed); } +#endif /* defined (CONFIG_BT_MCC_READ_SEEKING_SPEED) */ #ifdef CONFIG_BT_MCC_OTS @@ -311,6 +327,7 @@ static void mcc_set_current_group_obj_id_cb(struct bt_conn *conn, int err, #endif /* CONFIG_BT_MCC_OTS */ +#if defined(CONFIG_BT_MCC_READ_PLAYING_ORDER) static void mcc_read_playing_order_cb(struct bt_conn *conn, int err, uint8_t order) { if (err) { @@ -320,7 +337,9 @@ static void mcc_read_playing_order_cb(struct bt_conn *conn, int err, uint8_t ord shell_print(ctx_shell, "Playing order: %d", order); } +#endif /* defined(CONFIG_BT_MCC_READ_PLAYING_ORDER) */ +#if defined(CONFIG_BT_MCC_SET_PLAYING_ORDER) static void mcc_set_playing_order_cb(struct bt_conn *conn, int err, uint8_t order) { if (err) { @@ -330,7 +349,9 @@ static void mcc_set_playing_order_cb(struct bt_conn *conn, int err, uint8_t orde shell_print(ctx_shell, "Playing order: %d", order); } +#endif /* defined(CONFIG_BT_MCC_SET_PLAYING_ORDER) */ +#if defined(CONFIG_BT_MCC_READ_PLAYING_ORDER_SUPPORTED) static void mcc_read_playing_orders_supported_cb(struct bt_conn *conn, int err, uint16_t orders) { @@ -342,7 +363,9 @@ static void mcc_read_playing_orders_supported_cb(struct bt_conn *conn, int err, shell_print(ctx_shell, "Playing orders supported: %d", orders); } +#endif /* defined(CONFIG_BT_MCC_READ_PLAYING_ORDER_SUPPORTED) */ +#if defined(CONFIG_BT_MCC_READ_MEDIA_STATE) static void mcc_read_media_state_cb(struct bt_conn *conn, int err, uint8_t state) { if (err) { @@ -352,7 +375,9 @@ static void mcc_read_media_state_cb(struct bt_conn *conn, int err, uint8_t state shell_print(ctx_shell, "Media State: %d", state); } +#endif /* defined(CONFIG_BT_MCC_READ_MEDIA_STATE) */ +#if defined(CONFIG_BT_MCC_SET_MEDIA_CONTROL_POINT) static void mcc_send_cmd_cb(struct bt_conn *conn, int err, const struct mpl_cmd *cmd) { if (err) { @@ -364,6 +389,7 @@ static void mcc_send_cmd_cb(struct bt_conn *conn, int err, const struct mpl_cmd shell_print(ctx_shell, "Command opcode: %d, param: %d", cmd->opcode, cmd->param); } +#endif /* defined(CONFIG_BT_MCC_SET_MEDIA_CONTROL_POINT) */ static void mcc_cmd_ntf_cb(struct bt_conn *conn, int err, const struct mpl_cmd_ntf *ntf) @@ -379,6 +405,7 @@ static void mcc_cmd_ntf_cb(struct bt_conn *conn, int err, ntf->requested_opcode, ntf->result_code); } +#if defined(CONFIG_BT_MCC_READ_MEDIA_CONTROL_POINT_OPCODES_SUPPORTED) static void mcc_read_opcodes_supported_cb(struct bt_conn *conn, int err, uint32_t opcodes) { @@ -390,6 +417,7 @@ static void mcc_read_opcodes_supported_cb(struct bt_conn *conn, int err, shell_print(ctx_shell, "Opcodes supported: %d", opcodes); } +#endif /* defined(CONFIG_BT_MCC_READ_MEDIA_CONTROL_POINT_OPCODES_SUPPORTED) */ #ifdef CONFIG_BT_MCC_OTS static void mcc_send_search_cb(struct bt_conn *conn, int err, @@ -439,6 +467,7 @@ static void mcc_read_search_results_obj_id_cb(struct bt_conn *conn, int err, } #endif /* CONFIG_BT_MCC_OTS */ +#if defined(CONFIG_BT_MCC_READ_CONTENT_CONTROL_ID) static void mcc_read_content_control_id_cb(struct bt_conn *conn, int err, uint8_t ccid) { if (err) { @@ -448,6 +477,7 @@ static void mcc_read_content_control_id_cb(struct bt_conn *conn, int err, uint8_ shell_print(ctx_shell, "Content Control ID: %d", ccid); } +#endif /* defined(CONFIG_BT_MCC_READ_CONTENT_CONTROL_ID) */ #ifdef CONFIG_BT_MCC_OTS /**** Callback functions for the included Object Transfer service *************/ @@ -569,15 +599,31 @@ static int cmd_mcc_init(const struct shell *sh, size_t argc, char **argv) #ifdef CONFIG_BT_MCC_OTS cb.read_icon_obj_id = mcc_read_icon_obj_id_cb; #endif /* CONFIG_BT_MCC_OTS */ +#if defined(CONFIG_BT_MCC_READ_MEDIA_PLAYER_ICON_URL) cb.read_icon_url = mcc_read_icon_url_cb; +#endif /* defined(CONFIG_BT_MCC_READ_MEDIA_PLAYER_ICON_URL) */ cb.track_changed_ntf = mcc_track_changed_ntf_cb; +#if defined(CONFIG_BT_MCC_READ_TRACK_TITLE) cb.read_track_title = mcc_read_track_title_cb; +#endif /* defined(CONFIG_BT_MCC_READ_TRACK_TITLE) */ +#if defined(CONFIG_BT_MCC_READ_TRACK_DURATION) cb.read_track_duration = mcc_read_track_duration_cb; +#endif /* defined(CONFIG_BT_MCC_READ_TRACK_DURATION) */ +#if defined(CONFIG_BT_MCC_READ_TRACK_POSITION) cb.read_track_position = mcc_read_track_position_cb; +#endif /* defined(CONFIG_BT_MCC_READ_TRACK_POSITION) */ +#if defined(CONFIG_BT_MCC_SET_TRACK_POSITION) cb.set_track_position = mcc_set_track_position_cb; +#endif /* defined(CONFIG_BT_MCC_SET_TRACK_POSITION) */ +#if defined(CONFIG_BT_MCC_READ_PLAYBACK_SPEED) cb.read_playback_speed = mcc_read_playback_speed_cb; +#endif /* defined (CONFIG_BT_MCC_READ_PLAYBACK_SPEED) */ +#if defined(CONFIG_BT_MCC_SET_PLAYBACK_SPEED) cb.set_playback_speed = mcc_set_playback_speed_cb; +#endif /* defined (CONFIG_BT_MCC_SET_PLAYBACK_SPEED) */ +#if defined(CONFIG_BT_MCC_READ_SEEKING_SPEED) cb.read_seeking_speed = mcc_read_seeking_speed_cb; +#endif /* defined (CONFIG_BT_MCC_READ_SEEKING_SPEED) */ #ifdef CONFIG_BT_MCC_OTS cb.read_segments_obj_id = mcc_read_segments_obj_id_cb; cb.read_current_track_obj_id = mcc_read_current_track_obj_id_cb; @@ -588,19 +634,33 @@ static int cmd_mcc_init(const struct shell *sh, size_t argc, char **argv) cb.read_current_group_obj_id = mcc_read_current_group_obj_id_cb; cb.set_current_group_obj_id = mcc_set_current_group_obj_id_cb; #endif /* CONFIG_BT_MCC_OTS */ +#if defined(CONFIG_BT_MCC_READ_PLAYING_ORDER) cb.read_playing_order = mcc_read_playing_order_cb; +#endif /* defined(CONFIG_BT_MCC_READ_PLAYING_ORDER) */ +#if defined(CONFIG_BT_MCC_SET_PLAYING_ORDER) cb.set_playing_order = mcc_set_playing_order_cb; +#endif /* defined(CONFIG_BT_MCC_SET_PLAYING_ORDER) */ +#if defined(CONFIG_BT_MCC_READ_PLAYING_ORDER_SUPPORTED) cb.read_playing_orders_supported = mcc_read_playing_orders_supported_cb; +#endif /* defined(CONFIG_BT_MCC_READ_PLAYING_ORDER_SUPPORTED) */ +#if defined(CONFIG_BT_MCC_READ_MEDIA_STATE) cb.read_media_state = mcc_read_media_state_cb; +#endif /* defined(CONFIG_BT_MCC_READ_MEDIA_STATE) */ +#if defined(CONFIG_BT_MCC_SET_MEDIA_CONTROL_POINT) cb.send_cmd = mcc_send_cmd_cb; +#endif /* defined(CONFIG_BT_MCC_SET_MEDIA_CONTROL_POINT) */ cb.cmd_ntf = mcc_cmd_ntf_cb; +#if defined(CONFIG_BT_MCC_READ_MEDIA_CONTROL_POINT_OPCODES_SUPPORTED) cb.read_opcodes_supported = mcc_read_opcodes_supported_cb; +#endif /* defined(CONFIG_BT_MCC_READ_MEDIA_CONTROL_POINT_OPCODES_SUPPORTED) */ #ifdef CONFIG_BT_MCC_OTS cb.send_search = mcc_send_search_cb; cb.search_ntf = mcc_search_ntf_cb; cb.read_search_results_obj_id = mcc_read_search_results_obj_id_cb; #endif /* CONFIG_BT_MCC_OTS */ +#if defined(CONFIG_BT_MCC_READ_CONTENT_CONTROL_ID) cb.read_content_control_id = mcc_read_content_control_id_cb; +#endif /* defined(CONFIG_BT_MCC_READ_CONTENT_CONTROL_ID) */ #ifdef CONFIG_BT_MCC_OTS cb.otc_obj_selected = mcc_otc_obj_selected_cb; cb.otc_obj_metadata = mcc_otc_obj_metadata_cb; @@ -670,6 +730,7 @@ static int cmd_mcc_read_icon_obj_id(const struct shell *sh, size_t argc, } #endif /* CONFIG_BT_MCC_OTS */ +#if defined(CONFIG_BT_MCC_READ_MEDIA_PLAYER_ICON_URL) static int cmd_mcc_read_icon_url(const struct shell *sh, size_t argc, char *argv[]) { @@ -681,7 +742,9 @@ static int cmd_mcc_read_icon_url(const struct shell *sh, size_t argc, } return result; } +#endif /* defined(CONFIG_BT_MCC_READ_MEDIA_PLAYER_ICON_URL) */ +#if defined(CONFIG_BT_MCC_READ_TRACK_TITLE) static int cmd_mcc_read_track_title(const struct shell *sh, size_t argc, char *argv[]) { @@ -693,7 +756,9 @@ static int cmd_mcc_read_track_title(const struct shell *sh, size_t argc, } return result; } +#endif /* defined(CONFIG_BT_MCC_READ_TRACK_TITLE) */ +#if defined(CONFIG_BT_MCC_READ_TRACK_DURATION) static int cmd_mcc_read_track_duration(const struct shell *sh, size_t argc, char *argv[]) { @@ -705,7 +770,9 @@ static int cmd_mcc_read_track_duration(const struct shell *sh, size_t argc, } return result; } +#endif /* defined(CONFIG_BT_MCC_READ_TRACK_DURATION) */ +#if defined(CONFIG_BT_MCC_READ_TRACK_POSITION) static int cmd_mcc_read_track_position(const struct shell *sh, size_t argc, char *argv[]) { @@ -717,7 +784,9 @@ static int cmd_mcc_read_track_position(const struct shell *sh, size_t argc, } return result; } +#endif /* defined(CONFIG_BT_MCC_READ_TRACK_POSITION) */ +#if defined(CONFIG_BT_MCC_SET_TRACK_POSITION) static int cmd_mcc_set_track_position(const struct shell *sh, size_t argc, char *argv[]) { @@ -743,8 +812,10 @@ static int cmd_mcc_set_track_position(const struct shell *sh, size_t argc, } return result; } +#endif /* defined(CONFIG_BT_MCC_SET_TRACK_POSITION) */ +#if defined(CONFIG_BT_MCC_READ_PLAYBACK_SPEED) static int cmd_mcc_read_playback_speed(const struct shell *sh, size_t argc, char *argv[]) { @@ -756,8 +827,10 @@ static int cmd_mcc_read_playback_speed(const struct shell *sh, size_t argc, } return result; } +#endif /* defined (CONFIG_BT_MCC_READ_PLAYBACK_SPEED) */ +#if defined(CONFIG_BT_MCC_SET_PLAYBACK_SPEED) static int cmd_mcc_set_playback_speed(const struct shell *sh, size_t argc, char *argv[]) { @@ -783,7 +856,9 @@ static int cmd_mcc_set_playback_speed(const struct shell *sh, size_t argc, } return result; } +#endif /* defined (CONFIG_BT_MCC_SET_PLAYBACK_SPEED) */ +#if defined(CONFIG_BT_MCC_READ_SEEKING_SPEED) static int cmd_mcc_read_seeking_speed(const struct shell *sh, size_t argc, char *argv[]) { @@ -795,6 +870,7 @@ static int cmd_mcc_read_seeking_speed(const struct shell *sh, size_t argc, } return result; } +#endif /* defined (CONFIG_BT_MCC_READ_SEEKING_SPEED) */ #ifdef CONFIG_BT_MCC_OTS @@ -938,6 +1014,7 @@ static int cmd_mcc_set_current_group_obj_id(const struct shell *sh, size_t argc, } #endif /* CONFIG_BT_MCC_OTS */ +#if defined(CONFIG_BT_MCC_READ_PLAYING_ORDER) static int cmd_mcc_read_playing_order(const struct shell *sh, size_t argc, char *argv[]) { @@ -949,7 +1026,9 @@ static int cmd_mcc_read_playing_order(const struct shell *sh, size_t argc, } return result; } +#endif /* defined(CONFIG_BT_MCC_READ_PLAYING_ORDER) */ +#if defined(CONFIG_BT_MCC_SET_PLAYING_ORDER) static int cmd_mcc_set_playing_order(const struct shell *sh, size_t argc, char *argv[]) { @@ -975,7 +1054,9 @@ static int cmd_mcc_set_playing_order(const struct shell *sh, size_t argc, } return result; } +#endif /* defined(CONFIG_BT_MCC_SET_PLAYING_ORDER) */ +#if defined(CONFIG_BT_MCC_READ_PLAYING_ORDER_SUPPORTED) static int cmd_mcc_read_playing_orders_supported(const struct shell *sh, size_t argc, char *argv[]) { @@ -987,7 +1068,9 @@ static int cmd_mcc_read_playing_orders_supported(const struct shell *sh, } return result; } +#endif /* defined(CONFIG_BT_MCC_READ_PLAYING_ORDER_SUPPORTED) */ +#if defined(CONFIG_BT_MCC_READ_MEDIA_STATE) static int cmd_mcc_read_media_state(const struct shell *sh, size_t argc, char *argv[]) { @@ -999,7 +1082,9 @@ static int cmd_mcc_read_media_state(const struct shell *sh, size_t argc, } return result; } +#endif /* defined(CONFIG_BT_MCC_READ_MEDIA_STATE) */ +#if defined(CONFIG_BT_MCC_SET_MEDIA_CONTROL_POINT) static int cmd_mcc_play(const struct shell *sh, size_t argc, char *argv[]) { const struct mpl_cmd cmd = { @@ -1430,7 +1515,9 @@ static int cmd_mcc_goto_group(const struct shell *sh, size_t argc, char *argv[]) return err; } +#endif /* defined(CONFIG_BT_MCC_SET_MEDIA_CONTROL_POINT) */ +#if defined(CONFIG_BT_MCC_READ_MEDIA_CONTROL_POINT_OPCODES_SUPPORTED) static int cmd_mcc_read_opcodes_supported(const struct shell *sh, size_t argc, char *argv[]) { @@ -1442,6 +1529,7 @@ static int cmd_mcc_read_opcodes_supported(const struct shell *sh, size_t argc, } return result; } +#endif /* defined(CONFIG_BT_MCC_READ_MEDIA_CONTROL_POINT_OPCODES_SUPPORTED) */ #ifdef CONFIG_BT_MCC_OTS static int cmd_mcc_send_search_raw(const struct shell *sh, size_t argc, @@ -1632,6 +1720,7 @@ static int cmd_mcc_read_search_results_obj_id(const struct shell *sh, } #endif /* CONFIG_BT_MCC_OTS */ +#if defined(CONFIG_BT_MCC_READ_CONTENT_CONTROL_ID) static int cmd_mcc_read_content_control_id(const struct shell *sh, size_t argc, char *argv[]) { @@ -1643,6 +1732,7 @@ static int cmd_mcc_read_content_control_id(const struct shell *sh, size_t argc, } return result; } +#endif /* defined(CONFIG_BT_MCC_READ_CONTENT_CONTROL_ID) */ #ifdef CONFIG_BT_MCC_OTS @@ -1867,22 +1957,38 @@ SHELL_STATIC_SUBCMD_SET_CREATE(mcc_cmds, SHELL_CMD_ARG(read_icon_obj_id, NULL, "Read Icon Object ID", cmd_mcc_read_icon_obj_id, 1, 0), #endif /* CONFIG_BT_MCC_OTS */ +#if defined(CONFIG_BT_MCC_READ_MEDIA_PLAYER_ICON_URL) SHELL_CMD_ARG(read_icon_url, NULL, "Read Icon URL", cmd_mcc_read_icon_url, 1, 0), +#endif /* defined(CONFIG_BT_MCC_READ_MEDIA_PLAYER_ICON_URL) */ +#if defined(CONFIG_BT_MCC_READ_TRACK_TITLE) SHELL_CMD_ARG(read_track_title, NULL, "Read Track Title", cmd_mcc_read_track_title, 1, 0), +#endif /* defined(CONFIG_BT_MCC_READ_TRACK_TITLE) */ +#if defined(CONFIG_BT_MCC_READ_TRACK_DURATION) SHELL_CMD_ARG(read_track_duration, NULL, "Read Track Duration", cmd_mcc_read_track_duration, 1, 0), +#endif /* defined(CONFIG_BT_MCC_READ_TRACK_DURATION) */ +#if defined(CONFIG_BT_MCC_READ_TRACK_POSITION) SHELL_CMD_ARG(read_track_position, NULL, "Read Track Position", cmd_mcc_read_track_position, 1, 0), +#endif /* defined(CONFIG_BT_MCC_READ_TRACK_POSITION) */ +#if defined(CONFIG_BT_MCC_SET_TRACK_POSITION) SHELL_CMD_ARG(set_track_position, NULL, "Set Track position ", cmd_mcc_set_track_position, 2, 0), +#endif /* defined(CONFIG_BT_MCC_SET_TRACK_POSITION) */ +#if defined(CONFIG_BT_MCC_READ_PLAYBACK_SPEED) SHELL_CMD_ARG(read_playback_speed, NULL, "Read Playback Speed", cmd_mcc_read_playback_speed, 1, 0), +#endif /* defined (CONFIG_BT_MCC_READ_PLAYBACK_SPEED */ +#if defined(CONFIG_BT_MCC_SET_PLAYBACK_SPEED) SHELL_CMD_ARG(set_playback_speed, NULL, "Set Playback Speed ", cmd_mcc_set_playback_speed, 2, 0), +#endif /* defined (CONFIG_BT_MCC_SET_PLAYBACK_SPEED) */ +#if defined(CONFIG_BT_MCC_READ_SEEKING_SPEED) SHELL_CMD_ARG(read_seeking_speed, NULL, "Read Seeking Speed", cmd_mcc_read_seeking_speed, 1, 0), +#endif /* defined (CONFIG_BT_MCC_READ_SEEKING_SPEED) */ #ifdef CONFIG_BT_MCC_OTS SHELL_CMD_ARG(read_track_segments_obj_id, NULL, "Read Track Segments Object ID", @@ -1909,15 +2015,24 @@ SHELL_STATIC_SUBCMD_SET_CREATE(mcc_cmds, "Set Current Group Object ID ", cmd_mcc_set_current_group_obj_id, 2, 0), #endif /* CONFIG_BT_MCC_OTS */ +#if defined(CONFIG_BT_MCC_READ_PLAYING_ORDER) SHELL_CMD_ARG(read_playing_order, NULL, "Read Playing Order", cmd_mcc_read_playing_order, 1, 0), +#endif /* defined(CONFIG_BT_MCC_READ_PLAYING_ORDER) */ +#if defined(CONFIG_BT_MCC_SET_PLAYING_ORDER) SHELL_CMD_ARG(set_playing_order, NULL, "Set Playing Order ", cmd_mcc_set_playing_order, 2, 0), +#endif /* defined(CONFIG_BT_MCC_SET_PLAYING_ORDER) */ +#if defined(CONFIG_BT_MCC_READ_PLAYING_ORDER_SUPPORTED) SHELL_CMD_ARG(read_playing_orders_supported, NULL, "Read Playing Orders Supported", cmd_mcc_read_playing_orders_supported, 1, 0), +#endif /* defined(CONFIG_BT_MCC_READ_PLAYING_ORDER_SUPPORTED) */ +#if defined(CONFIG_BT_MCC_READ_MEDIA_STATE) SHELL_CMD_ARG(read_media_state, NULL, "Read Media State", cmd_mcc_read_media_state, 1, 0), +#endif /* defined(CONFIG_BT_MCC_READ_MEDIA_STATE) */ +#if defined(CONFIG_BT_MCC_SET_MEDIA_CONTROL_POINT) SHELL_CMD_ARG(play, NULL, "Send the play command", cmd_mcc_play, 1, 0), SHELL_CMD_ARG(pause, NULL, "Send the pause command", cmd_mcc_pause, 1, 0), @@ -1962,8 +2077,11 @@ SHELL_STATIC_SUBCMD_SET_CREATE(mcc_cmds, SHELL_CMD_ARG(goto_group, NULL, "Send the goto group command ", cmd_mcc_goto_group, 2, 0), +#endif /* defined(CONFIG_BT_MCC_SET_MEDIA_CONTROL_POINT) */ +#if defined(CONFIG_BT_MCC_READ_MEDIA_CONTROL_POINT_OPCODES_SUPPORTED) SHELL_CMD_ARG(read_opcodes_supported, NULL, "Send the Read Opcodes Supported", cmd_mcc_read_opcodes_supported, 1, 0), +#endif /* defined(CONFIG_BT_MCC_READ_MEDIA_CONTROL_POINT_OPCODES_SUPPORTED) */ #ifdef CONFIG_BT_MCC_OTS SHELL_CMD_ARG(send_search_raw, NULL, "Send search ", cmd_mcc_send_search_raw, 2, 0), @@ -1982,8 +2100,10 @@ SHELL_STATIC_SUBCMD_SET_CREATE(mcc_cmds, "Read Search Results Object ID", cmd_mcc_read_search_results_obj_id, 1, 0), #endif /* CONFIG_BT_MCC_OTS */ +#if defined(CONFIG_BT_MCC_READ_CONTENT_CONTROL_ID) SHELL_CMD_ARG(read_content_control_id, NULL, "Read Content Control ID", cmd_mcc_read_content_control_id, 1, 0), +#endif /* defined(CONFIG_BT_MCC_READ_CONTENT_CONTROL_ID) */ #ifdef CONFIG_BT_MCC_OTS SHELL_CMD_ARG(ots_read_features, NULL, "Read OTC Features", cmd_mcc_otc_read_features, 1, 0), diff --git a/tests/bluetooth/shell/testcase.yaml b/tests/bluetooth/shell/testcase.yaml index a20abfbdda8..c47b845a5dc 100644 --- a/tests/bluetooth/shell/testcase.yaml +++ b/tests/bluetooth/shell/testcase.yaml @@ -181,6 +181,12 @@ tests: extra_configs: - CONFIG_BT_MCC_OTS=n tags: bluetooth + bluetooth.shell.audio.mcc_minimal: + extra_args: CONF_FILE="audio.conf" + build_only: true + extra_configs: + - CONFIG_BT_MCC_MINIMAL=y + tags: bluetooth bluetooth.shell.audio.no_otsc: extra_args: CONF_FILE="audio.conf" build_only: true From ce647d17b4af8d75132f336773d6ce591058a579 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Manuel=20Arg=C3=BCelles?= Date: Sun, 28 Jan 2024 16:43:41 +0700 Subject: [PATCH 3356/3723] drivers: counter: mcux_rtc: enable oscillator if supported MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Some devices like S32K1xx don't feature an internal 32.768 KHz oscillator. Also, updated the code to use the existing HAL API for this purpose. Signed-off-by: Manuel Argüelles --- drivers/counter/counter_mcux_rtc.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/drivers/counter/counter_mcux_rtc.c b/drivers/counter/counter_mcux_rtc.c index bd0c0e9512e..39f2b7064f5 100644 --- a/drivers/counter/counter_mcux_rtc.c +++ b/drivers/counter/counter_mcux_rtc.c @@ -1,6 +1,6 @@ /* * Copyright (c) 2018 blik GmbH - * Copyright (c) 2018, NXP + * Copyright (c) 2018,2024 NXP * * SPDX-License-Identifier: Apache-2.0 */ @@ -236,9 +236,11 @@ static int mcux_rtc_init(const struct device *dev) RTC_GetDefaultConfig(&rtc_config); RTC_Init(config->base, &rtc_config); +#if !(defined(FSL_FEATURE_RTC_HAS_NO_CR_OSCE) && FSL_FEATURE_RTC_HAS_NO_CR_OSCE) /* Enable 32kHz oscillator and wait for 1ms to settle */ - config->base->CR |= 0x100; + RTC_SetClockSource(config->base); k_busy_wait(USEC_PER_MSEC); +#endif /* !FSL_FEATURE_RTC_HAS_NO_CR_OSCE */ config->irq_config_func(dev); From 1b302f51ea75f44b199e3175dcef6662f6c08a9c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Manuel=20Arg=C3=BCelles?= Date: Sun, 28 Jan 2024 16:51:12 +0700 Subject: [PATCH 3357/3723] soc: arm: nxp_s32: s32k1: add support for RTC MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Add support for the Real Time Clock (RTC) counter. Signed-off-by: Manuel Argüelles --- dts/arm/nxp/nxp_s32k1xx.dtsi | 9 +++++++++ soc/arm/nxp_s32/s32k1/Kconfig.series | 1 + 2 files changed, 10 insertions(+) diff --git a/dts/arm/nxp/nxp_s32k1xx.dtsi b/dts/arm/nxp/nxp_s32k1xx.dtsi index 10c3d207bf7..d6c63c5db5d 100644 --- a/dts/arm/nxp/nxp_s32k1xx.dtsi +++ b/dts/arm/nxp/nxp_s32k1xx.dtsi @@ -317,5 +317,14 @@ prescaler = <1>; status = "disabled"; }; + + rtc: rtc@4003d000 { + compatible = "nxp,kinetis-rtc"; + reg = <0x4003d000 0x1000>; + interrupts = <46 0>, <47 0>; + interrupt-names = "alarm", "seconds"; + clock-frequency = <32768>; + prescaler = <32768>; + }; }; }; diff --git a/soc/arm/nxp_s32/s32k1/Kconfig.series b/soc/arm/nxp_s32/s32k1/Kconfig.series index 07fe41bda9e..31102f347fd 100644 --- a/soc/arm/nxp_s32/s32k1/Kconfig.series +++ b/soc/arm/nxp_s32/s32k1/Kconfig.series @@ -19,5 +19,6 @@ config SOC_SERIES_S32K1XX select HAS_MCUX_FTM select HAS_MCUX_FLEXCAN select HAS_MCUX_WDOG32 + select HAS_MCUX_RTC help Enable support for NXP S32K1XX MCU series. From 3dd014ef55eed7e5fcd498279dc8f3fd95c84419 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Manuel=20Arg=C3=BCelles?= Date: Sun, 28 Jan 2024 17:11:12 +0700 Subject: [PATCH 3358/3723] boards: arm: ucans32k1sic: enable RTC counter MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Enable the Real Time Clock (RTC) counter on ucans32k1sic. Signed-off-by: Manuel Argüelles --- boards/arm/ucans32k1sic/doc/index.rst | 1 + boards/arm/ucans32k1sic/ucans32k1sic.yaml | 1 + 2 files changed, 2 insertions(+) diff --git a/boards/arm/ucans32k1sic/doc/index.rst b/boards/arm/ucans32k1sic/doc/index.rst index e89daf9c324..66138b44a00 100644 --- a/boards/arm/ucans32k1sic/doc/index.rst +++ b/boards/arm/ucans32k1sic/doc/index.rst @@ -52,6 +52,7 @@ LPSPI on-chip spi FTM on-chip pwm FlexCAN on-chip can Watchdog on-chip watchdog +RTC on-chip counter ============ ========== ================================ The default configuration can be found in the Kconfig file diff --git a/boards/arm/ucans32k1sic/ucans32k1sic.yaml b/boards/arm/ucans32k1sic/ucans32k1sic.yaml index 96926263e21..798c1096409 100644 --- a/boards/arm/ucans32k1sic/ucans32k1sic.yaml +++ b/boards/arm/ucans32k1sic/ucans32k1sic.yaml @@ -20,3 +20,4 @@ supported: - pwm - can - watchdog + - counter From 550b16a04e6eb72d9071cf29475789ff780e1182 Mon Sep 17 00:00:00 2001 From: Vinayak Kariappa Chettimada Date: Sat, 27 Jan 2024 07:54:28 +0100 Subject: [PATCH 3359/3723] Bluetooth: Controller: Fix missing ull_chan_reset call Fix missing call to ull_chan_reset(), this fixes uninitialized channel map being used after LL reset. Signed-off-by: Vinayak Kariappa Chettimada --- subsys/bluetooth/controller/ll_sw/ull.c | 13 +++++++++++++ subsys/bluetooth/controller/ll_sw/ull_chan.c | 13 +++++-------- .../bluetooth/controller/ll_sw/ull_chan_internal.h | 2 +- 3 files changed, 19 insertions(+), 9 deletions(-) diff --git a/subsys/bluetooth/controller/ll_sw/ull.c b/subsys/bluetooth/controller/ll_sw/ull.c index 1a44dfc0b12..93efa905513 100644 --- a/subsys/bluetooth/controller/ll_sw/ull.c +++ b/subsys/bluetooth/controller/ll_sw/ull.c @@ -63,6 +63,7 @@ #include "isoal.h" #include "ll_feat_internal.h" #include "ull_internal.h" +#include "ull_chan_internal.h" #include "ull_iso_internal.h" #include "ull_adv_internal.h" #include "ull_scan_internal.h" @@ -2285,6 +2286,18 @@ static inline int init_reset(void) mem_link_rx.quota_pdu = RX_CNT; rx_replenish_all(); +#if (defined(CONFIG_BT_BROADCASTER) && defined(CONFIG_BT_CTLR_ADV_EXT)) || \ + defined(CONFIG_BT_CTLR_ADV_PERIODIC) || \ + defined(CONFIG_BT_CTLR_SYNC_PERIODIC) || \ + defined(CONFIG_BT_CONN) + /* Initialize channel map */ + ull_chan_reset(); +#endif /* (CONFIG_BT_BROADCASTER && CONFIG_BT_CTLR_ADV_EXT) || + * CONFIG_BT_CTLR_ADV_PERIODIC || + * CONFIG_BT_CTLR_SYNC_PERIODIC || + * CONFIG_BT_CONN + */ + return 0; } diff --git a/subsys/bluetooth/controller/ll_sw/ull_chan.c b/subsys/bluetooth/controller/ll_sw/ull_chan.c index dab2be06350..a986f9bbab9 100644 --- a/subsys/bluetooth/controller/ll_sw/ull_chan.c +++ b/subsys/bluetooth/controller/ll_sw/ull_chan.c @@ -34,13 +34,12 @@ #include "ull_adv_internal.h" #include "ull_central_internal.h" -/* Initial channel map indicating Used and Unused data channels. - * The HCI LE Set Host Channel Classification command allows the Host to +/* The HCI LE Set Host Channel Classification command allows the Host to * specify a channel classification for the data, secondary advertising, * periodic, and isochronous physical channels based on its local information. */ -static uint8_t map[5] = {0xFF, 0xFF, 0xFF, 0xFF, 0x1F}; -static uint8_t count = 37U; +static uint8_t map[5]; +static uint8_t count; static void chan_map_set(uint8_t const *const chan_map); @@ -70,17 +69,15 @@ uint8_t ll_chm_update(uint8_t const *const chm) return 0; } -int ull_chan_reset(void) +void ull_chan_reset(void) { - /* initialise connection channel map */ + /* Initial channel map indicating Used and Unused data channels. */ map[0] = 0xFF; map[1] = 0xFF; map[2] = 0xFF; map[3] = 0xFF; map[4] = 0x1F; count = 37U; - - return 0; } uint8_t ull_chan_map_get(uint8_t *const chan_map) diff --git a/subsys/bluetooth/controller/ll_sw/ull_chan_internal.h b/subsys/bluetooth/controller/ll_sw/ull_chan_internal.h index bcef535b4fe..3f63f7c93eb 100644 --- a/subsys/bluetooth/controller/ll_sw/ull_chan_internal.h +++ b/subsys/bluetooth/controller/ll_sw/ull_chan_internal.h @@ -4,6 +4,6 @@ * SPDX-License-Identifier: Apache-2.0 */ -int ull_chan_reset(void); +void ull_chan_reset(void); uint8_t ull_chan_map_get(uint8_t *const chan_map); void ull_chan_map_set(uint8_t const *const chan_map); From 01be4aff40bcf9a61fb26495ca6559e13990f60f Mon Sep 17 00:00:00 2001 From: Fabio Baltieri Date: Fri, 15 Dec 2023 14:42:48 +0000 Subject: [PATCH 3360/3723] input: gpio_qdec: add power management support Add power management support to the gpio-qdec driver. This is a bit complicated by the fact that the driver has two modes of operation and the interrupt, timer and idle work ineract with each other. The suspend sequence is: - set the suspended bit (inhibits the poll timer so that it does not resubmit the idle work) - cancel the idle work (so that it does not schedule and re-set the interrupt or timers) - disable interrupts (if used) - stop the sampling timer - disconnect the pins The resume sequence is more or less the opposite. Signed-off-by: Fabio Baltieri --- drivers/input/input_gpio_qdec.c | 88 ++++++++++++++++++++++++++++++++- 1 file changed, 87 insertions(+), 1 deletion(-) diff --git a/drivers/input/input_gpio_qdec.c b/drivers/input/input_gpio_qdec.c index 66066d32acc..4a9b524f461 100644 --- a/drivers/input/input_gpio_qdec.c +++ b/drivers/input/input_gpio_qdec.c @@ -13,6 +13,8 @@ #include #include #include +#include +#include #include #include @@ -42,6 +44,9 @@ struct gpio_qdec_data { struct k_work_delayable idle_work; struct gpio_callback gpio_cb; atomic_t polling; +#ifdef CONFIG_PM_DEVICE + atomic_t suspended; +#endif }; /* Positive transitions */ @@ -157,6 +162,12 @@ static void gpio_qdec_sample_timer_timeout(struct k_timer *timer) unsigned int key; uint8_t step; +#ifdef CONFIG_PM_DEVICE + if (atomic_get(&data->suspended) == 1) { + return; + } +#endif + step = gpio_qdec_get_step(dev); if (data->prev_step == step) { @@ -301,11 +312,84 @@ static int gpio_qdec_init(const struct device *dev) gpio_qdec_idle_mode(dev); + ret = pm_device_runtime_enable(dev); + if (ret < 0) { + LOG_ERR("Failed to enable runtime power management"); + return ret; + } + LOG_DBG("Device %s initialized", dev->name); return 0; } +#ifdef CONFIG_PM_DEVICE +static void gpio_qdec_pin_suspend(const struct device *dev, bool suspend) +{ + const struct gpio_qdec_config *cfg = dev->config; + gpio_flags_t mode = suspend ? GPIO_DISCONNECTED : GPIO_INPUT; + int ret; + + for (int i = 0; i < GPIO_QDEC_GPIO_NUM; i++) { + const struct gpio_dt_spec *gpio = &cfg->ab_gpio[i]; + + ret = gpio_pin_configure_dt(gpio, mode); + if (ret != 0) { + LOG_ERR("Pin %d configuration failed: %d", i, ret); + return; + } + } + + for (int i = 0; i < cfg->led_gpio_count; i++) { + if (suspend) { + gpio_pin_set_dt(&cfg->led_gpio[i], 0); + } else if (!gpio_qdec_idle_polling_mode(dev)) { + gpio_pin_set_dt(&cfg->led_gpio[i], 1); + } + } +} + +static int gpio_qdec_pm_action(const struct device *dev, + enum pm_device_action action) +{ + struct gpio_qdec_data *data = dev->data; + + switch (action) { + case PM_DEVICE_ACTION_SUSPEND: + struct k_work_sync sync; + + atomic_set(&data->suspended, 1); + + k_work_cancel_delayable_sync(&data->idle_work, &sync); + + if (!gpio_qdec_idle_polling_mode(dev)) { + gpio_qdec_irq_setup(dev, false); + } + + k_timer_stop(&data->sample_timer); + + gpio_qdec_pin_suspend(dev, true); + + break; + case PM_DEVICE_ACTION_RESUME: + atomic_set(&data->suspended, 0); + + gpio_qdec_pin_suspend(dev, false); + + data->prev_step = gpio_qdec_get_step(dev); + data->acc = 0; + + gpio_qdec_idle_mode(dev); + + break; + default: + return -ENOTSUP; + } + + return 0; +} +#endif + #define QDEC_GPIO_INIT(n) \ BUILD_ASSERT(DT_INST_PROP_LEN(n, gpios) == GPIO_QDEC_GPIO_NUM, \ "input_gpio_qdec: gpios must have exactly two entries"); \ @@ -342,7 +426,9 @@ static int gpio_qdec_init(const struct device *dev) \ static struct gpio_qdec_data gpio_qdec_data_##n; \ \ - DEVICE_DT_INST_DEFINE(n, gpio_qdec_init, NULL, \ + PM_DEVICE_DT_INST_DEFINE(n, gpio_qdec_pm_action); \ + \ + DEVICE_DT_INST_DEFINE(n, gpio_qdec_init, PM_DEVICE_DT_INST_GET(n), \ &gpio_qdec_data_##n, \ &gpio_qdec_cfg_##n, \ POST_KERNEL, CONFIG_INPUT_INIT_PRIORITY, \ From 8e5c9c3b8a05febd091752e0a7b1f97da247cc98 Mon Sep 17 00:00:00 2001 From: Vinayak Kariappa Chettimada Date: Fri, 26 Jan 2024 13:41:48 +0100 Subject: [PATCH 3361/3723] Bluetooth: Controller: Fix MFIFO_DEFINE to reduce FLASH usage Fix MFIFO_DEFINE to reduce FLASH usage by moving the pool outside the struct that is static initialized. Signed-off-by: Vinayak Kariappa Chettimada --- subsys/bluetooth/controller/ll_sw/ull.c | 20 ++-- subsys/bluetooth/controller/ll_sw/ull_conn.c | 8 +- .../bluetooth/controller/ll_sw/ull_internal.h | 13 +-- subsys/bluetooth/controller/util/mfifo.h | 101 +++++++++--------- 4 files changed, 73 insertions(+), 69 deletions(-) diff --git a/subsys/bluetooth/controller/ll_sw/ull.c b/subsys/bluetooth/controller/ll_sw/ull.c index 93efa905513..8caaa29b62c 100644 --- a/subsys/bluetooth/controller/ll_sw/ull.c +++ b/subsys/bluetooth/controller/ll_sw/ull.c @@ -939,17 +939,18 @@ uint8_t ll_rx_get(void **node_rx, uint16_t *handle) link = memq_peek(memq_ll_rx.head, memq_ll_rx.tail, (void **)&rx); if (link) { #if defined(CONFIG_BT_CONN) || defined(CONFIG_BT_CTLR_ADV_ISO) - cmplt = tx_cmplt_get(handle, &mfifo_tx_ack.f, rx->ack_last); + cmplt = tx_cmplt_get(handle, &mfifo_fifo_tx_ack.f, + rx->ack_last); if (!cmplt) { uint8_t f, cmplt_prev, cmplt_curr; uint16_t h; cmplt_curr = 0U; - f = mfifo_tx_ack.f; + f = mfifo_fifo_tx_ack.f; do { cmplt_prev = cmplt_curr; cmplt_curr = tx_cmplt_get(&h, &f, - mfifo_tx_ack.l); + mfifo_fifo_tx_ack.l); } while ((cmplt_prev != 0U) || (cmplt_prev != cmplt_curr)); #endif /* CONFIG_BT_CONN || CONFIG_BT_CTLR_ADV_ISO */ @@ -1016,7 +1017,8 @@ uint8_t ll_rx_get(void **node_rx, uint16_t *handle) #if defined(CONFIG_BT_CONN) || defined(CONFIG_BT_CTLR_ADV_ISO) } } else { - cmplt = tx_cmplt_get(handle, &mfifo_tx_ack.f, mfifo_tx_ack.l); + cmplt = tx_cmplt_get(handle, &mfifo_fifo_tx_ack.f, + mfifo_fifo_tx_ack.l); #endif /* CONFIG_BT_CONN || CONFIG_BT_CTLR_ADV_ISO */ } @@ -1714,7 +1716,7 @@ void ll_rx_put(memq_link_t *link, void *rx) /* Serialize Tx ack with Rx enqueue by storing reference to * last element index in Tx ack FIFO. */ - rx_hdr->ack_last = mfifo_tx_ack.l; + rx_hdr->ack_last = mfifo_fifo_tx_ack.l; #endif /* CONFIG_BT_CONN || CONFIG_BT_CTLR_ADV_ISO */ /* Enqueue the Rx object */ @@ -2560,8 +2562,8 @@ static uint8_t tx_cmplt_get(uint16_t *handle, uint8_t *first, uint8_t last) uint8_t next; next = *first; - tx = mfifo_dequeue_iter_get(mfifo_tx_ack.m, mfifo_tx_ack.s, - mfifo_tx_ack.n, mfifo_tx_ack.f, last, + tx = mfifo_dequeue_iter_get(mfifo_fifo_tx_ack.m, mfifo_tx_ack.s, + mfifo_tx_ack.n, mfifo_fifo_tx_ack.f, last, &next); if (!tx) { return 0; @@ -2676,8 +2678,8 @@ static uint8_t tx_cmplt_get(uint16_t *handle, uint8_t *first, uint8_t last) #endif /* CONFIG_BT_CTLR_ADV_ISO || CONFIG_BT_CTLR_CONN_ISO */ *first = next; - tx = mfifo_dequeue_iter_get(mfifo_tx_ack.m, mfifo_tx_ack.s, - mfifo_tx_ack.n, mfifo_tx_ack.f, + tx = mfifo_dequeue_iter_get(mfifo_fifo_tx_ack.m, mfifo_tx_ack.s, + mfifo_tx_ack.n, mfifo_fifo_tx_ack.f, last, &next); } while (tx && tx->handle == *handle); diff --git a/subsys/bluetooth/controller/ll_sw/ull_conn.c b/subsys/bluetooth/controller/ll_sw/ull_conn.c index 193483b6379..ddb9459c3dc 100644 --- a/subsys/bluetooth/controller/ll_sw/ull_conn.c +++ b/subsys/bluetooth/controller/ll_sw/ull_conn.c @@ -1384,7 +1384,7 @@ void ull_conn_link_tx_release(void *link) uint8_t ull_conn_ack_last_idx_get(void) { - return mfifo_conn_ack.l; + return mfifo_fifo_conn_ack.l; } memq_link_t *ull_conn_ack_peek(uint8_t *ack_last, uint16_t *handle, @@ -1397,7 +1397,7 @@ memq_link_t *ull_conn_ack_peek(uint8_t *ack_last, uint16_t *handle, return NULL; } - *ack_last = mfifo_conn_ack.l; + *ack_last = mfifo_fifo_conn_ack.l; *handle = lll_tx->handle; *tx = lll_tx->node; @@ -1410,8 +1410,8 @@ memq_link_t *ull_conn_ack_by_last_peek(uint8_t last, uint16_t *handle, { struct lll_tx *lll_tx; - lll_tx = mfifo_dequeue_get(mfifo_conn_ack.m, mfifo_conn_ack.s, - mfifo_conn_ack.f, last); + lll_tx = mfifo_dequeue_get(mfifo_fifo_conn_ack.m, mfifo_conn_ack.s, + mfifo_fifo_conn_ack.f, last); if (!lll_tx) { return NULL; } diff --git a/subsys/bluetooth/controller/ll_sw/ull_internal.h b/subsys/bluetooth/controller/ll_sw/ull_internal.h index 02d078e93cf..5df17a74f17 100644 --- a/subsys/bluetooth/controller/ll_sw/ull_internal.h +++ b/subsys/bluetooth/controller/ll_sw/ull_internal.h @@ -144,10 +144,10 @@ void ull_drift_ticks_get(struct node_rx_event_done *done, * enqueuing pointers to memory elements with associated memq links. */ #define RXFIFO_ALLOC(_name, _count) \ - ull_rxfifo_alloc(mfifo_##_name.s, mfifo_##_name.n, mfifo_##_name.f, \ - &mfifo_##_name.l, mfifo_##_name.m, \ - &mem_pool_##_name.free, &mem_link_##_name.free, \ - _count) + ull_rxfifo_alloc(mfifo_##_name.s, mfifo_##_name.n, \ + mfifo_fifo_##_name.f, &mfifo_fifo_##_name.l, \ + mfifo_fifo_##_name.m, &mem_pool_##_name.free, \ + &mem_link_##_name.free, _count) /** * @brief Initialize and allocate MFIFO and pools @@ -161,8 +161,9 @@ void ull_drift_ticks_get(struct node_rx_event_done *done, * @details Enqueues an RX node back into the FIFO. */ #define RXFIFO_RELEASE(_name, _link, _rx) \ - ull_rxfifo_release(mfifo_##_name.s, mfifo_##_name.n, mfifo_##_name.f, \ - &mfifo_##_name.l, mfifo_##_name.m, _link, \ + ull_rxfifo_release(mfifo_##_name.s, mfifo_##_name.n, \ + mfifo_fifo_##_name.f, &mfifo_fifo_##_name.l, \ + mfifo_fifo_##_name.m, _link, \ (struct node_rx_hdr *)_rx) void ull_rxfifo_alloc(uint8_t s, uint8_t n, uint8_t f, uint8_t *l, uint8_t *m, diff --git a/subsys/bluetooth/controller/util/mfifo.h b/subsys/bluetooth/controller/util/mfifo.h index 664edf77c15..1ceadf43155 100644 --- a/subsys/bluetooth/controller/util/mfifo.h +++ b/subsys/bluetooth/controller/util/mfifo.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2018-2019 Nordic Semiconductor ASA + * Copyright (c) 2018-2024 Nordic Semiconductor ASA * * SPDX-License-Identifier: Apache-2.0 */ @@ -41,28 +41,26 @@ * different, but it is trailing and sizeof is not applied here, so it can * be a flexible array member. */ -#define MFIFO_DEFINE(name, sz, cnt) \ - struct { \ - /* TODO: const, optimise RAM use */ \ - /* TODO: Separate s,n,f,l out into common struct */ \ - uint16_t const s; /* Stride between elements */ \ - uint16_t const n; /* Number of buffers */ \ - uint8_t f; /* First. Read index */ \ - uint8_t l; /* Last. Write index */ \ - uint8_t MALIGN(4) m[MROUND(sz) * ((cnt) + 1)]; \ - } mfifo_##name = { \ - .n = ((cnt) + 1), \ - .s = MROUND(sz), \ - .f = 0, \ - .l = 0, \ - } +#define MFIFO_DEFINE(name, sz, cnt) \ + const struct { \ + uint16_t s; /* Stride between elements */ \ + uint16_t n; /* Number of buffers */ \ + } mfifo_##name = { \ + .s = MROUND(sz), \ + .n = ((cnt) + 1), \ + }; \ + static struct { \ + uint8_t MALIGN(4) m[MROUND(sz) * ((cnt) + 1)]; \ + uint8_t f; /* First. Read index */ \ + uint8_t l; /* Last. Write index */ \ + } mfifo_fifo_##name; /** * @brief Initialize an MFIFO to be empty * @details API 1 and 2. An MFIFO is empty if first == last */ #define MFIFO_INIT(name) \ - mfifo_##name.f = mfifo_##name.l = 0 + mfifo_fifo_##name.f = mfifo_fifo_##name.l = 0 /** * @brief Non-destructive: Allocate buffer from the queue's tail, by index @@ -79,8 +77,8 @@ * @param idx[out] Index of newly allocated buffer * @return True if buffer could be allocated; otherwise false */ -static inline bool mfifo_enqueue_idx_get(uint8_t count, uint8_t first, uint8_t last, - uint8_t *idx) +static inline bool mfifo_enqueue_idx_get(uint8_t count, uint8_t first, + uint8_t last, uint8_t *idx) { /* Non-destructive: Advance write-index modulo 'count' */ last = last + 1; @@ -109,15 +107,15 @@ static inline bool mfifo_enqueue_idx_get(uint8_t count, uint8_t first, uint8_t l * @return True if buffer could be allocated; otherwise false */ #define MFIFO_ENQUEUE_IDX_GET(name, i) \ - mfifo_enqueue_idx_get(mfifo_##name.n, mfifo_##name.f, \ - mfifo_##name.l, (i)) + mfifo_enqueue_idx_get(mfifo_##name.n, mfifo_fifo_##name.f, \ + mfifo_fifo_##name.l, (i)) /** * @brief Commit a previously allocated buffer (=void-ptr) * @details API 2 */ -static inline void mfifo_by_idx_enqueue(uint8_t *fifo, uint8_t size, uint8_t idx, - void *mem, uint8_t *last) +static inline void mfifo_by_idx_enqueue(uint8_t *fifo, uint8_t size, + uint8_t idx, void *mem, uint8_t *last) { /* API 2: fifo is array of void-ptrs */ void **p = (void **)(fifo + (*last) * size); /* buffer preceding idx */ @@ -132,8 +130,8 @@ static inline void mfifo_by_idx_enqueue(uint8_t *fifo, uint8_t size, uint8_t idx * @details API 2 */ #define MFIFO_BY_IDX_ENQUEUE(name, i, mem) \ - mfifo_by_idx_enqueue(mfifo_##name.m, mfifo_##name.s, (i), \ - (mem), &mfifo_##name.l) + mfifo_by_idx_enqueue(mfifo_fifo_##name.m, mfifo_##name.s, (i), \ + (mem), &mfifo_fifo_##name.l) /** * @brief Non-destructive: Allocate buffer from named queue @@ -142,8 +140,9 @@ static inline void mfifo_by_idx_enqueue(uint8_t *fifo, uint8_t size, uint8_t idx * To commit the enqueue process, mfifo_enqueue() must be called afterwards * @return Index of newly allocated buffer; only valid if mem != NULL */ -static inline uint8_t mfifo_enqueue_get(uint8_t *fifo, uint8_t size, uint8_t count, - uint8_t first, uint8_t last, void **mem) +static inline uint8_t mfifo_enqueue_get(uint8_t *fifo, uint8_t size, + uint8_t count, uint8_t first, + uint8_t last, void **mem) { uint8_t idx; @@ -172,9 +171,9 @@ static inline uint8_t mfifo_enqueue_get(uint8_t *fifo, uint8_t size, uint8_t cou * @return Index to the buffer one-ahead of allocated buffer */ #define MFIFO_ENQUEUE_GET(name, mem) \ - mfifo_enqueue_get(mfifo_##name.m, mfifo_##name.s, \ - mfifo_##name.n, mfifo_##name.f, \ - mfifo_##name.l, (mem)) + mfifo_enqueue_get(mfifo_fifo_##name.m, mfifo_##name.s, \ + mfifo_##name.n, mfifo_fifo_##name.f, \ + mfifo_fifo_##name.l, (mem)) /** * @brief Atomically commit a previously allocated buffer @@ -201,14 +200,15 @@ static inline void mfifo_enqueue(uint8_t idx, uint8_t *last) * @param idx[in] Index one-ahead of previously allocated buffer */ #define MFIFO_ENQUEUE(name, idx) \ - mfifo_enqueue((idx), &mfifo_##name.l) + mfifo_enqueue((idx), &mfifo_fifo_##name.l) /** * @brief Number of available buffers * @details API 1 and 2 * Empty if first == last */ -static inline uint8_t mfifo_avail_count_get(uint8_t count, uint8_t first, uint8_t last) +static inline uint8_t mfifo_avail_count_get(uint8_t count, uint8_t first, + uint8_t last) { if (last >= first) { return last - first; @@ -222,15 +222,15 @@ static inline uint8_t mfifo_avail_count_get(uint8_t count, uint8_t first, uint8_ * @details API 1 and 2 */ #define MFIFO_AVAIL_COUNT_GET(name) \ - mfifo_avail_count_get(mfifo_##name.n, mfifo_##name.f, \ - mfifo_##name.l) + mfifo_avail_count_get(mfifo_##name.n, mfifo_fifo_##name.f, \ + mfifo_fifo_##name.l) /** * @brief Non-destructive peek * @details API 1 */ -static inline void *mfifo_dequeue_get(uint8_t *fifo, uint8_t size, uint8_t first, - uint8_t last) +static inline void *mfifo_dequeue_get(uint8_t *fifo, uint8_t size, + uint8_t first, uint8_t last) { if (first == last) { return NULL; @@ -244,15 +244,15 @@ static inline void *mfifo_dequeue_get(uint8_t *fifo, uint8_t size, uint8_t first * @details API 1 */ #define MFIFO_DEQUEUE_GET(name) \ - mfifo_dequeue_get(mfifo_##name.m, mfifo_##name.s, \ - mfifo_##name.f, mfifo_##name.l) + mfifo_dequeue_get(mfifo_fifo_##name.m, mfifo_##name.s, \ + mfifo_fifo_##name.f, mfifo_fifo_##name.l) /** * @brief Non-destructive: Peek at head (oldest) buffer * @details API 2 */ -static inline void *mfifo_dequeue_peek(uint8_t *fifo, uint8_t size, uint8_t first, - uint8_t last) +static inline void *mfifo_dequeue_peek(uint8_t *fifo, uint8_t size, + uint8_t first, uint8_t last) { if (first == last) { return NULL; /* Queue is empty */ @@ -267,11 +267,12 @@ static inline void *mfifo_dequeue_peek(uint8_t *fifo, uint8_t size, uint8_t firs * @details API 2 */ #define MFIFO_DEQUEUE_PEEK(name) \ - mfifo_dequeue_peek(mfifo_##name.m, mfifo_##name.s, \ - mfifo_##name.f, mfifo_##name.l) + mfifo_dequeue_peek(mfifo_fifo_##name.m, mfifo_##name.s, \ + mfifo_fifo_##name.f, mfifo_fifo_##name.l) -static inline void *mfifo_dequeue_iter_get(uint8_t *fifo, uint8_t size, uint8_t count, - uint8_t first, uint8_t last, uint8_t *idx) +static inline void *mfifo_dequeue_iter_get(uint8_t *fifo, uint8_t size, + uint8_t count, uint8_t first, + uint8_t last, uint8_t *idx) { void *p; uint8_t i; @@ -297,9 +298,9 @@ static inline void *mfifo_dequeue_iter_get(uint8_t *fifo, uint8_t size, uint8_t } #define MFIFO_DEQUEUE_ITER_GET(name, idx) \ - mfifo_dequeue_iter_get(mfifo_##name.m, mfifo_##name.s, \ - mfifo_##name.n, mfifo_##name.f, \ - mfifo_##name.l, (idx)) + mfifo_dequeue_iter_get(mfifo_fifo_##name.m, mfifo_##name.s, \ + mfifo_##name.n, mfifo_fifo_##name.f, \ + mfifo_fifo_##name.l, (idx)) /** * @brief Dequeue head-buffer from queue of buffers @@ -345,6 +346,6 @@ static inline void *mfifo_dequeue(uint8_t *fifo, uint8_t size, uint8_t count, * @return Head buffer; or NULL if queue was empty */ #define MFIFO_DEQUEUE(name) \ - mfifo_dequeue(mfifo_##name.m, mfifo_##name.s, \ - mfifo_##name.n, mfifo_##name.l, \ - &mfifo_##name.f) + mfifo_dequeue(mfifo_fifo_##name.m, mfifo_##name.s, \ + mfifo_##name.n, mfifo_fifo_##name.l, \ + &mfifo_fifo_##name.f) From f358243b2671727d13d492a693c5331d1361092e Mon Sep 17 00:00:00 2001 From: Vinayak Kariappa Chettimada Date: Thu, 1 Feb 2024 12:08:39 +0100 Subject: [PATCH 3362/3723] Bluetooth: Controller: Enforce range for BT_CTLR_ADV_AUX_SYNC_OFFSET Enfore a range for BT_CTLR_ADV_AUX_SYNC_OFFSET such that it does not take negative integer values. Signed-off-by: Vinayak Kariappa Chettimada --- subsys/bluetooth/controller/Kconfig.ll_sw_split | 3 +++ 1 file changed, 3 insertions(+) diff --git a/subsys/bluetooth/controller/Kconfig.ll_sw_split b/subsys/bluetooth/controller/Kconfig.ll_sw_split index 3ff4eb222bb..b3cd1e9f8f8 100644 --- a/subsys/bluetooth/controller/Kconfig.ll_sw_split +++ b/subsys/bluetooth/controller/Kconfig.ll_sw_split @@ -428,6 +428,7 @@ config BT_CTLR_ADV_ISO_RESERVE_MAX config BT_CTLR_ADV_AUX_SYNC_OFFSET int "Pre-defined offset between AUX_ADV_IND and AUX_SYNC_IND" depends on BT_CTLR_ADV_PERIODIC + range 0 4000000 default 0 help Define an offset between AUX_ADV_IND and AUX_SYNC_IND when using @@ -439,6 +440,8 @@ config BT_CTLR_ADV_AUX_SYNC_OFFSET PDUs are scheduled as periodic events of Extended Advertising Interval plus 10 milliseconds (Advertising Random Delay) as the periodic interval. + The offset is in microseconds, limited to an experimental maximum + value of 4 seconds. config BT_CTLR_ADV_DATA_BUF_MAX int "Advertising Data Maximum Buffers" From f214913e16d1ad867d6ae36911d44608ecec2036 Mon Sep 17 00:00:00 2001 From: Vinayak Kariappa Chettimada Date: Mon, 29 Jan 2024 12:17:18 +0100 Subject: [PATCH 3363/3723] Bluetooth: Controller: Fix coverity issue 330043 Fix coverity issue 330043, Unsigned compared against 0. Signed-off-by: Vinayak Kariappa Chettimada --- subsys/bluetooth/controller/ll_sw/ull_adv_iso.c | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/subsys/bluetooth/controller/ll_sw/ull_adv_iso.c b/subsys/bluetooth/controller/ll_sw/ull_adv_iso.c index 6072ebc788b..af2bf66b911 100644 --- a/subsys/bluetooth/controller/ll_sw/ull_adv_iso.c +++ b/subsys/bluetooth/controller/ll_sw/ull_adv_iso.c @@ -261,8 +261,13 @@ uint8_t ll_big_create(uint8_t big_handle, uint8_t adv_handle, uint8_t num_bis, ticks_slot_sync += ticks_slot_overhead; /* Calculate total overheads due to extended and periodic advertising */ - if (CONFIG_BT_CTLR_ADV_AUX_SYNC_OFFSET > 0U) { + if (false) { + +#if defined(CONFIG_BT_CTLR_ADV_AUX_SYNC_OFFSET) + } else if (CONFIG_BT_CTLR_ADV_AUX_SYNC_OFFSET > 0U) { ticks_slot_overhead = MAX(ticks_slot_aux, ticks_slot_sync); +#endif /* CONFIG_BT_CTLR_ADV_AUX_SYNC_OFFSET */ + } else { ticks_slot_overhead = ticks_slot_aux + ticks_slot_sync; } From 054dc35542369d47712e86f8f8a49951c2e9f993 Mon Sep 17 00:00:00 2001 From: Vinayak Kariappa Chettimada Date: Mon, 29 Jan 2024 12:17:18 +0100 Subject: [PATCH 3364/3723] Bluetooth: Controller: Fix coverity issue 330027 Fix coverity issue 330027, Structurally dead code. Signed-off-by: Vinayak Kariappa Chettimada --- subsys/bluetooth/controller/ll_sw/ull_central_iso.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/subsys/bluetooth/controller/ll_sw/ull_central_iso.c b/subsys/bluetooth/controller/ll_sw/ull_central_iso.c index b0eac97a80c..7c1c59e4e4c 100644 --- a/subsys/bluetooth/controller/ll_sw/ull_central_iso.c +++ b/subsys/bluetooth/controller/ll_sw/ull_central_iso.c @@ -971,7 +971,7 @@ int ull_central_iso_cis_offset_get(uint16_t cis_handle, } return -EBUSY; -#endif /* CONFIG_BT_CTLR_CENTRAL_SPACING != 0 */ +#else /* CONFIG_BT_CTLR_CENTRAL_SPACING != 0 */ *cis_offset_min = HAL_TICKER_TICKS_TO_US(conn->ull.ticks_slot) + (EVENT_TICKER_RES_MARGIN_US << 1U); @@ -979,6 +979,7 @@ int ull_central_iso_cis_offset_get(uint16_t cis_handle, *cis_offset_min += cig->sync_delay - cis->sync_delay; return 0; +#endif /* CONFIG_BT_CTLR_CENTRAL_SPACING != 0 */ } #if (CONFIG_BT_CTLR_CENTRAL_SPACING == 0) From c5474085db207d2c1664a78ba9a95fbda9cb3a8e Mon Sep 17 00:00:00 2001 From: Vinayak Kariappa Chettimada Date: Mon, 29 Jan 2024 12:17:18 +0100 Subject: [PATCH 3365/3723] Bluetooth: Controller: Fix coverity issue 340845 Fix coverity issue 340845, Uninitialized pointer read. Signed-off-by: Vinayak Kariappa Chettimada --- subsys/bluetooth/controller/ll_sw/ull_df.c | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/subsys/bluetooth/controller/ll_sw/ull_df.c b/subsys/bluetooth/controller/ll_sw/ull_df.c index 6d29d10fcd9..06fd25fb653 100644 --- a/subsys/bluetooth/controller/ll_sw/ull_df.c +++ b/subsys/bluetooth/controller/ll_sw/ull_df.c @@ -865,14 +865,17 @@ static uint8_t cte_info_set(struct ll_adv_set *adv, struct lll_df_adv_cfg *df_cf /* Note: ULL_ADV_PDU_EXTRA_DATA_ALLOC_ALWAYS is just information that extra_data * is required in case of this ull_adv_sync_pdu_alloc. */ + extra_data = NULL; err = ull_adv_sync_pdu_alloc(adv, ULL_ADV_PDU_EXTRA_DATA_ALLOC_ALWAYS, &pdu_prev, &pdu, NULL, &extra_data, ter_idx); if (err != BT_HCI_ERR_SUCCESS) { return err; } - ull_adv_sync_extra_data_set_clear(NULL, extra_data, ULL_ADV_PDU_HDR_FIELD_CTE_INFO, 0, - df_cfg); + if (extra_data) { + ull_adv_sync_extra_data_set_clear(NULL, extra_data, ULL_ADV_PDU_HDR_FIELD_CTE_INFO, + 0, df_cfg); + } #if (CONFIG_BT_CTLR_DF_PER_ADV_CTE_NUM_MAX > 1) if (df_cfg->cte_count > 1) { From 83321eed4131f2b7e88d80fd6c7546a34237a724 Mon Sep 17 00:00:00 2001 From: Vinayak Kariappa Chettimada Date: Mon, 29 Jan 2024 12:17:18 +0100 Subject: [PATCH 3366/3723] Bluetooth: Controller: Fix coverity issue 340844 Fix coverity issue 340844, Uninitialized pointer read. Signed-off-by: Vinayak Kariappa Chettimada --- subsys/bluetooth/controller/ll_sw/ull_df.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/subsys/bluetooth/controller/ll_sw/ull_df.c b/subsys/bluetooth/controller/ll_sw/ull_df.c index 06fd25fb653..5f34f563cf4 100644 --- a/subsys/bluetooth/controller/ll_sw/ull_df.c +++ b/subsys/bluetooth/controller/ll_sw/ull_df.c @@ -1073,13 +1073,15 @@ static uint8_t cte_info_clear(struct ll_adv_set *adv, struct lll_df_adv_cfg *df_ /* NOTE: ULL_ADV_PDU_EXTRA_DATA_ALLOC_NEVER is just information that extra_data * should be removed in case of this call ull_adv_sync_pdu_alloc. */ + extra_data_prev = NULL; + extra_data = NULL; err = ull_adv_sync_pdu_alloc(adv, ULL_ADV_PDU_EXTRA_DATA_ALLOC_NEVER, &pdu_prev, &pdu, &extra_data_prev, &extra_data, ter_idx); if (err != BT_HCI_ERR_SUCCESS) { return err; } - if (extra_data) { + if (extra_data_prev && extra_data) { ull_adv_sync_extra_data_set_clear(extra_data_prev, extra_data, 0, ULL_ADV_PDU_HDR_FIELD_CTE_INFO, NULL); } From 10fece0c1e420efa85e6d4443b5be3502616caa1 Mon Sep 17 00:00:00 2001 From: Vinayak Kariappa Chettimada Date: Fri, 2 Feb 2024 10:48:34 +0100 Subject: [PATCH 3367/3723] Bluetooth: Controller: Fix PA sync-ed ACL supervision timeout Fix Periodic Advertising Synchronization leading to Peripheral ACL connection supervision timeout, due to direction finding related radio hardware registers being updated in the implementation that is not built for direction finding feature support. Signed-off-by: Vinayak Kariappa Chettimada --- subsys/bluetooth/controller/ll_sw/nordic/lll/lll_sync.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/subsys/bluetooth/controller/ll_sw/nordic/lll/lll_sync.c b/subsys/bluetooth/controller/ll_sw/nordic/lll/lll_sync.c index 1ecec8d0f60..05b10cf994a 100644 --- a/subsys/bluetooth/controller/ll_sw/nordic/lll/lll_sync.c +++ b/subsys/bluetooth/controller/ll_sw/nordic/lll/lll_sync.c @@ -328,7 +328,7 @@ static int create_prepare_cb(struct lll_prepare_param *p) #else } else { #endif /* CONFIG_BT_CTLR_DF_SCAN_CTE_RX */ - if (IS_ENABLED(CONFIG_BT_CTLR_DF_SUPPORT)) { + if (IS_ENABLED(CONFIG_BT_CTLR_DF)) { /* Disable CTE reception and sampling in Radio */ radio_df_cte_inline_set_enabled(false); } From 79bbe8f4b09876cbb23f11cc4ef1f8fd4c69e4ca Mon Sep 17 00:00:00 2001 From: Ben Marsh Date: Wed, 31 Jan 2024 11:35:09 +0000 Subject: [PATCH 3368/3723] doc: kernel: Add message queue & pipe to poll docs The polling API can be used to wait on data in a FIFO, message queue, or pipe, but the docs were not clear that message queues and pipes are supported. Add to the docs to make it clear message queues and pipes can be used with the polling API. Signed-off-by: Ben Marsh --- doc/kernel/services/polling.rst | 37 ++++++++++++++++++++++++++++++--- 1 file changed, 34 insertions(+), 3 deletions(-) diff --git a/doc/kernel/services/polling.rst b/doc/kernel/services/polling.rst index 84f7dbf4b6f..71937648a93 100644 --- a/doc/kernel/services/polling.rst +++ b/doc/kernel/services/polling.rst @@ -24,6 +24,8 @@ There is a limited set of such conditions: - a semaphore becomes available - a kernel FIFO contains data ready to be retrieved +- a kernel message queue contains data ready to be retrieved +- a kernel pipe contains data ready to be retrieved - a poll signal is raised A thread that wants to wait on multiple conditions must define an array of @@ -87,20 +89,26 @@ ignored, most likely temporarily, its type can be set to K_POLL_TYPE_IGNORE. .. code-block:: c - struct k_poll_event events[2] = { + struct k_poll_event events[4] = { K_POLL_EVENT_STATIC_INITIALIZER(K_POLL_TYPE_SEM_AVAILABLE, K_POLL_MODE_NOTIFY_ONLY, &my_sem, 0), K_POLL_EVENT_STATIC_INITIALIZER(K_POLL_TYPE_FIFO_DATA_AVAILABLE, K_POLL_MODE_NOTIFY_ONLY, &my_fifo, 0), + K_POLL_EVENT_STATIC_INITIALIZER(K_POLL_TYPE_MSGQ_DATA_AVAILABLE, + K_POLL_MODE_NOTIFY_ONLY, + &my_msgq, 0), + K_POLL_EVENT_STATIC_INITIALIZER(K_POLL_TYPE_PIPE_DATA_AVAILABLE, + K_POLL_MODE_NOTIFY_ONLY, + &my_pipe, 0), }; or at runtime .. code-block:: c - struct k_poll_event events[2]; + struct k_poll_event events[4]; void some_init(void) { k_poll_event_init(&events[0], @@ -113,6 +121,16 @@ or at runtime K_POLL_MODE_NOTIFY_ONLY, &my_fifo); + k_poll_event_init(&events[2], + K_POLL_TYPE_MSGQ_DATA_AVAILABLE, + K_POLL_MODE_NOTIFY_ONLY, + &my_msgq); + + k_poll_event_init(&events[3], + K_POLL_TYPE_PIPE_DATA_AVAILABLE, + K_POLL_MODE_NOTIFY_ONLY, + &my_pipe); + // tags are left uninitialized if unused } @@ -145,6 +163,12 @@ In case of success, :c:func:`k_poll` returns 0. If it times out, it returns } else if (events[1].state == K_POLL_STATE_FIFO_DATA_AVAILABLE) { data = k_fifo_get(events[1].fifo, 0); // handle data + } else if (events[2].state == K_POLL_STATE_MSGQ_DATA_AVAILABLE) { + ret = k_msgq_get(events[2].msgq, buf, K_NO_WAIT); + // handle data + } else if (events[3].state == K_POLL_STATE_PIPE_DATA_AVAILABLE) { + ret = k_pipe_get(events[3].pipe, buf, bytes_to_read, &bytes_read, min_xfer, K_NO_WAIT); + // handle data } } else { // handle timeout @@ -165,9 +189,16 @@ to :c:macro:`K_POLL_STATE_NOT_READY` by the user. } else if (events[1].state == K_POLL_STATE_FIFO_DATA_AVAILABLE) { data = k_fifo_get(events[1].fifo, 0); // handle data - } + } else if (events[2].state == K_POLL_STATE_MSGQ_DATA_AVAILABLE) { + ret = k_msgq_get(events[2].msgq, buf, K_NO_WAIT); + // handle data + } else if (events[3].state == K_POLL_STATE_PIPE_DATA_AVAILABLE) { + ret = k_pipe_get(events[3].pipe, buf, bytes_to_read, &bytes_read, min_xfer, K_NO_WAIT); + // handle data events[0].state = K_POLL_STATE_NOT_READY; events[1].state = K_POLL_STATE_NOT_READY; + events[2].state = K_POLL_STATE_NOT_READY; + events[3].state = K_POLL_STATE_NOT_READY; } } From 078e32fa377aac1b4ef46f319bffbf70efa78efa Mon Sep 17 00:00:00 2001 From: Francois Ramu Date: Tue, 30 Jan 2024 09:10:25 +0100 Subject: [PATCH 3369/3723] dts: bindings: flash controller stm32 ospi nor flash reg property Address and size are given by the DTS register property of the ospi nor. The size Property becomes useless Signed-off-by: Francois Ramu --- dts/bindings/flash_controller/st,stm32-ospi-nor.yaml | 9 +++------ 1 file changed, 3 insertions(+), 6 deletions(-) diff --git a/dts/bindings/flash_controller/st,stm32-ospi-nor.yaml b/dts/bindings/flash_controller/st,stm32-ospi-nor.yaml index f8f84020f6a..cdcb0b9d800 100644 --- a/dts/bindings/flash_controller/st,stm32-ospi-nor.yaml +++ b/dts/bindings/flash_controller/st,stm32-ospi-nor.yaml @@ -6,13 +6,12 @@ description: | Representation of a serial flash on a octospi bus: - mx25lm51245: ospi-nor-flash@0 { + mx25lm51245: ospi-nor-flash@70000000 { compatible = "st,stm32-ospi-nor"; - reg = <0>; + reg = <0x70000000 DT_SIZE_M(64)>; /* 512 Mbits */ data-mode = ; /* access on 8 data lines */ data-rate = ; /* access in DTR */ ospi-max-frequency = ; - size = ; /* 512 Mbit */ status = "okay"; }; @@ -25,13 +24,11 @@ on-bus: ospi properties: reg: required: true + description: Flash Memory base address and size in bytes ospi-max-frequency: type: int required: true description: Maximum clock frequency of device's OSPI interface in Hz - size: - required: true - description: Flash Memory size in bits reset-gpios: type: phandle-array description: RESETn pin From 0bbd7bf977b288c225a73b260f3bca8ac1b2da0f Mon Sep 17 00:00:00 2001 From: Francois Ramu Date: Thu, 1 Jun 2023 15:39:02 +0200 Subject: [PATCH 3370/3723] drivers: flash: stm32 ospi drivers gets address and size from DTS Address and size are given by the DTS register property of the ospi nor : to be used by the ospi driver. Signed-off-by: Francois Ramu --- drivers/flash/flash_stm32_ospi.c | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/drivers/flash/flash_stm32_ospi.c b/drivers/flash/flash_stm32_ospi.c index 9d2ed2412dc..2f8d1ec3f96 100644 --- a/drivers/flash/flash_stm32_ospi.c +++ b/drivers/flash/flash_stm32_ospi.c @@ -36,6 +36,9 @@ LOG_MODULE_REGISTER(flash_stm32_ospi, CONFIG_FLASH_LOG_LEVEL); (_CONCAT(HAL_OSPIM_, DT_STRING_TOKEN(STM32_OSPI_NODE, prop))), \ ((default_value))) +/* Get the base address of the flash from the DTS node */ +#define STM32_OSPI_BASE_ADDRESS DT_INST_REG_ADDR(0) + #define STM32_OSPI_RESET_GPIO DT_INST_NODE_HAS_PROP(0, reset_gpios) #define STM32_OSPI_DLYB_BYPASSED DT_PROP(STM32_OSPI_NODE, dlyb_bypass) @@ -2235,6 +2238,10 @@ static int flash_stm32_ospi_init(const struct device *dev) } #endif /* CONFIG_FLASH_PAGE_LAYOUT */ + LOG_INF("NOR octo-flash at 0x%lx (0x%x bytes)", + (long)(STM32_OSPI_BASE_ADDRESS), + dev_cfg->flash_size); + return 0; } @@ -2300,7 +2307,7 @@ static const struct flash_stm32_ospi_config flash_stm32_ospi_cfg = { .enr = DT_CLOCKS_CELL_BY_NAME(STM32_OSPI_NODE, ospi_mgr, bits)}, #endif .irq_config = flash_stm32_ospi_irq_config_func, - .flash_size = DT_INST_PROP(0, size) / 8U, + .flash_size = DT_INST_REG_ADDR_BY_IDX(0, 1), .max_frequency = DT_INST_PROP(0, ospi_max_frequency), .data_mode = DT_INST_PROP(0, spi_bus_width), /* SPI or OPI */ .data_rate = DT_INST_PROP(0, data_rate), /* DTR or STR */ From 1567627f9c17a6fc3ab2c1735ed5107de82cdebe Mon Sep 17 00:00:00 2001 From: Francois Ramu Date: Thu, 25 Jan 2024 14:35:48 +0100 Subject: [PATCH 3371/3723] boards: arm: stm32 disco kit has ospi nor flash node Define the reg and size property for the stm32u585 and stm32l562 disco kit. Refer to the dts/bindings/flash_controller/st,stm32-ospi-nor.yaml. The stm32l562 reads the sfdp table from the flash itself. Signed-off-by: Francois Ramu --- boards/arm/b_u585i_iot02a/b_u585i_iot02a-common.dtsi | 5 ++--- boards/arm/stm32l562e_dk/stm32l562e_dk_common.dtsi | 5 ++--- 2 files changed, 4 insertions(+), 6 deletions(-) diff --git a/boards/arm/b_u585i_iot02a/b_u585i_iot02a-common.dtsi b/boards/arm/b_u585i_iot02a/b_u585i_iot02a-common.dtsi index f2dd82f9ad1..ccbb4cea402 100644 --- a/boards/arm/b_u585i_iot02a/b_u585i_iot02a-common.dtsi +++ b/boards/arm/b_u585i_iot02a/b_u585i_iot02a-common.dtsi @@ -131,11 +131,10 @@ stm32_lp_tick_source: &lptim1 { status = "okay"; - mx25lm51245: ospi-nor-flash@0 { + mx25lm51245: ospi-nor-flash@70000000 { compatible = "st,stm32-ospi-nor"; - reg = <0>; + reg = <0x70000000 DT_SIZE_M(64)>; /* 512 Mbits */ ospi-max-frequency = ; - size = ; /* 64 MBytes */ spi-bus-width = ; data-rate = ; four-byte-opcodes; diff --git a/boards/arm/stm32l562e_dk/stm32l562e_dk_common.dtsi b/boards/arm/stm32l562e_dk/stm32l562e_dk_common.dtsi index 7c91d04cbb5..ccd74b46ece 100644 --- a/boards/arm/stm32l562e_dk/stm32l562e_dk_common.dtsi +++ b/boards/arm/stm32l562e_dk/stm32l562e_dk_common.dtsi @@ -135,11 +135,10 @@ stm32_lp_tick_source: &lptim1 { status = "okay"; - mx25lm51245: ospi-nor-flash@0 { + mx25lm51245: ospi-nor-flash@90000000 { compatible = "st,stm32-ospi-nor"; - reg = <0>; + reg = <0x90000000 DT_SIZE_M(64)>; /* 512 Mbits */ ospi-max-frequency = ; - size = ; /* 64 MBytes */ spi-bus-width = ; data-rate = ; four-byte-opcodes; From cd239bf8f114e2ae832ba59955f1a797312bf610 Mon Sep 17 00:00:00 2001 From: Francois Ramu Date: Thu, 25 Jan 2024 16:06:50 +0100 Subject: [PATCH 3372/3723] dts: bindings: flash controller stm32 qspi nor flash reg property Address and size are given by the DTS register property of the qspi nor. The size Property becomes useless. Signed-off-by: Francois Ramu --- dts/bindings/flash_controller/st,stm32-qspi-nor.yaml | 9 +++------ 1 file changed, 3 insertions(+), 6 deletions(-) diff --git a/dts/bindings/flash_controller/st,stm32-qspi-nor.yaml b/dts/bindings/flash_controller/st,stm32-qspi-nor.yaml index 6d7bf5105e6..3f990f4a125 100644 --- a/dts/bindings/flash_controller/st,stm32-qspi-nor.yaml +++ b/dts/bindings/flash_controller/st,stm32-qspi-nor.yaml @@ -6,11 +6,10 @@ description: | Representation of a serial flash on a quadspi bus: - mx25r6435f: qspi-nor-flash@0 { + mx25r6435f: qspi-nor-flash@90000000 { compatible = "st,stm32-qspi-nor"; - reg = <0>; + reg = <0x90000000 DT_SIZE_M(8)>; /* 64 Mbits */ qspi-max-frequency = <80000000>; - size = <0x4000000>; reset-gpios = <&gpiod 3 GPIO_ACTIVE_LOW>; reset-gpios-duration = <1>; spi-bus-width = <4>; @@ -26,13 +25,11 @@ on-bus: qspi properties: reg: required: true + description: Flash Memory base address and size in bytes qspi-max-frequency: type: int required: true description: Maximum clock frequency of device's QSPI interface in Hz - size: - required: true - description: Flash Memory size in bits reset-gpios: type: phandle-array description: RESETn pin From b44f558059e08a83727b5c0bbd74f62e03837275 Mon Sep 17 00:00:00 2001 From: Francois Ramu Date: Tue, 30 Jan 2024 09:15:52 +0100 Subject: [PATCH 3373/3723] drivers: flash: stm32 qspi drivers gets address and size from DTS Address and size are given by the DTS register property of the qspi nor : to be used by the qspi driver. Signed-off-by: Francois Ramu --- drivers/flash/flash_stm32_qspi.c | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/drivers/flash/flash_stm32_qspi.c b/drivers/flash/flash_stm32_qspi.c index 6a9f8a58557..326c1129a36 100644 --- a/drivers/flash/flash_stm32_qspi.c +++ b/drivers/flash/flash_stm32_qspi.c @@ -29,6 +29,9 @@ #define STM32_QSPI_USE_QUAD_IO 0 #endif +/* Get the base address of the flash from the DTS node */ +#define STM32_QSPI_BASE_ADDRESS DT_INST_REG_ADDR(0) + #define STM32_QSPI_RESET_GPIO DT_INST_NODE_HAS_PROP(0, reset_gpios) #define STM32_QSPI_RESET_CMD DT_INST_NODE_HAS_PROP(0, reset_cmd) @@ -1364,6 +1367,10 @@ static int flash_stm32_qspi_init(const struct device *dev) } #endif /* CONFIG_FLASH_PAGE_LAYOUT */ + LOG_INF("NOR quad-flash at 0x%lx (0x%x bytes)", + (long)(STM32_QSPI_BASE_ADDRESS), + dev_cfg->flash_size); + return 0; } @@ -1420,7 +1427,7 @@ static const struct flash_stm32_qspi_config flash_stm32_qspi_cfg = { .bus = DT_CLOCKS_CELL(STM32_QSPI_NODE, bus) }, .irq_config = flash_stm32_qspi_irq_config_func, - .flash_size = DT_INST_PROP(0, size) / 8U, + .flash_size = DT_INST_REG_ADDR_BY_IDX(0, 1), .max_frequency = DT_INST_PROP(0, qspi_max_frequency), .pcfg = PINCTRL_DT_DEV_CONFIG_GET(STM32_QSPI_NODE), #if STM32_QSPI_RESET_GPIO From 9e13290f8be8fb5c2c8e719fddb06d558064a2a0 Mon Sep 17 00:00:00 2001 From: Francois Ramu Date: Thu, 25 Jan 2024 16:08:11 +0100 Subject: [PATCH 3374/3723] boards: arm: stm32 boards has qspi nor flash node Define the reg and size property for the stm32 boards with qspi inside Refer to the dts/bindings/flash_controller/st,stm32-ospi-nor.yaml. Signed-off-by: Francois Ramu --- boards/arm/arduino_giga_r1/arduino_giga_r1_m7.dts | 5 ++--- boards/arm/disco_l475_iot1/disco_l475_iot1.dts | 6 ++---- boards/arm/pandora_stm32l475/pandora_stm32l475.dts | 5 ++--- boards/arm/stm32f412g_disco/stm32f412g_disco.dts | 5 ++--- boards/arm/stm32f723e_disco/stm32f723e_disco.dts | 5 ++--- boards/arm/stm32f746g_disco/stm32f746g_disco.dts | 5 ++--- boards/arm/stm32f7508_dk/stm32f7508_dk.dts | 5 ++--- boards/arm/stm32f769i_disco/stm32f769i_disco.dts | 7 +++---- boards/arm/stm32h747i_disco/stm32h747i_disco_m7.dts | 10 ++++------ boards/arm/stm32h750b_dk/stm32h750b_dk.dts | 9 ++++----- boards/arm/stm32l496g_disco/stm32l496g_disco.dts | 5 ++--- .../subsys/fs/littlefs/boards/nucleo_h743zi.overlay | 5 ++--- 12 files changed, 29 insertions(+), 43 deletions(-) diff --git a/boards/arm/arduino_giga_r1/arduino_giga_r1_m7.dts b/boards/arm/arduino_giga_r1/arduino_giga_r1_m7.dts index 9cc042ff0d3..4459780243b 100644 --- a/boards/arm/arduino_giga_r1/arduino_giga_r1_m7.dts +++ b/boards/arm/arduino_giga_r1/arduino_giga_r1_m7.dts @@ -171,11 +171,10 @@ pinctrl-names = "default"; status = "okay"; - n25q128a1: qspi-nor-flash@0 { + n25q128a1: qspi-nor-flash@90000000 { compatible = "st,stm32-qspi-nor"; - reg = <0>; + reg = <0x90000000 DT_SIZE_M(16)>; /* 128 Mbits */ qspi-max-frequency = <72000000>; - size = ; status = "okay"; partitions { diff --git a/boards/arm/disco_l475_iot1/disco_l475_iot1.dts b/boards/arm/disco_l475_iot1/disco_l475_iot1.dts index 9ae6399e62e..81beca8e7c0 100644 --- a/boards/arm/disco_l475_iot1/disco_l475_iot1.dts +++ b/boards/arm/disco_l475_iot1/disco_l475_iot1.dts @@ -321,12 +321,10 @@ zephyr_udc0: &usbotg_fs { status = "okay"; - mx25r6435f: qspi-nor-flash@0 { + mx25r6435f: qspi-nor-flash@90000000 { compatible = "st,stm32-qspi-nor"; - reg = <0>; + reg = <0x90000000 DT_SIZE_M(8)>; /* 64 Mbits */ qspi-max-frequency = <50000000>; - /* 64 Megabits = 8 Megabytes */ - size = <0x4000000>; status = "okay"; partitions { diff --git a/boards/arm/pandora_stm32l475/pandora_stm32l475.dts b/boards/arm/pandora_stm32l475/pandora_stm32l475.dts index 67d7124dcb0..1c28f6c8176 100644 --- a/boards/arm/pandora_stm32l475/pandora_stm32l475.dts +++ b/boards/arm/pandora_stm32l475/pandora_stm32l475.dts @@ -79,11 +79,10 @@ pinctrl-names = "default"; status = "okay"; - w25q128jv: qspi-nor-flash@0 { + w25q128jv: qspi-nor-flash@90000000 { compatible = "st,stm32-qspi-nor"; - reg = <0>; + reg = <0x90000000 DT_SIZE_M(16)>; /* 128 Mbits */ qspi-max-frequency = <80000000>; - size = <0x8000000>; jedec-id = [ef 40 18]; spi-bus-width = <4>; status = "okay"; diff --git a/boards/arm/stm32f412g_disco/stm32f412g_disco.dts b/boards/arm/stm32f412g_disco/stm32f412g_disco.dts index e3089dc9d39..a929e3ebe09 100644 --- a/boards/arm/stm32f412g_disco/stm32f412g_disco.dts +++ b/boards/arm/stm32f412g_disco/stm32f412g_disco.dts @@ -147,11 +147,10 @@ pinctrl-names = "default"; status = "okay"; - n25q128a1: qspi-nor-flash@0 { + n25q128a1: qspi-nor-flash@90000000 { compatible = "st,stm32-qspi-nor"; - reg = <0>; + reg = <0x90000000 DT_SIZE_M(16)>; /* 128 Mbits */ qspi-max-frequency = <72000000>; - size = ; status = "okay"; }; }; diff --git a/boards/arm/stm32f723e_disco/stm32f723e_disco.dts b/boards/arm/stm32f723e_disco/stm32f723e_disco.dts index eed706057f8..4c6641c7f2c 100644 --- a/boards/arm/stm32f723e_disco/stm32f723e_disco.dts +++ b/boards/arm/stm32f723e_disco/stm32f723e_disco.dts @@ -124,11 +124,10 @@ flash-id = <1>; status = "okay"; - mx25r512: qspi-nor-flash@0 { + mx25r512: qspi-nor-flash@90000000 { compatible = "st,stm32-qspi-nor"; - reg = <0>; + reg = <0x90000000 DT_SIZE_M(64)>; /* 512 Mbits */ qspi-max-frequency = <8000000>; - size = ; /* 64 MBytes */ status = "okay"; spi-bus-width = <4>; writeoc = "PP_1_4_4"; diff --git a/boards/arm/stm32f746g_disco/stm32f746g_disco.dts b/boards/arm/stm32f746g_disco/stm32f746g_disco.dts index e81172d381b..6250c4e8e80 100644 --- a/boards/arm/stm32f746g_disco/stm32f746g_disco.dts +++ b/boards/arm/stm32f746g_disco/stm32f746g_disco.dts @@ -187,11 +187,10 @@ zephyr_udc0: &usbotg_fs { pinctrl-names = "default"; status = "okay"; - n25q128a1: qspi-nor-flash@0 { + n25q128a1: qspi-nor-flash@90000000 { compatible = "st,stm32-qspi-nor"; - reg = <0>; + reg = <0x90000000 DT_SIZE_M(16)>; /* 128 Mbits */ qspi-max-frequency = <72000000>; - size = ; status = "okay"; partitions { diff --git a/boards/arm/stm32f7508_dk/stm32f7508_dk.dts b/boards/arm/stm32f7508_dk/stm32f7508_dk.dts index 8102e002863..b98cf5aeed9 100644 --- a/boards/arm/stm32f7508_dk/stm32f7508_dk.dts +++ b/boards/arm/stm32f7508_dk/stm32f7508_dk.dts @@ -183,11 +183,10 @@ zephyr_udc0: &usbotg_fs { pinctrl-names = "default"; status = "okay"; - n25q128a1: qspi-nor-flash@0 { + n25q128a1: qspi-nor-flash@90000000 { compatible = "st,stm32-qspi-nor"; - reg = <0>; + reg = <0x90000000 DT_SIZE_M(16)>; /* 128 Mbits */ qspi-max-frequency = <72000000>; - size = ; status = "okay"; partitions { diff --git a/boards/arm/stm32f769i_disco/stm32f769i_disco.dts b/boards/arm/stm32f769i_disco/stm32f769i_disco.dts index 0548cf06bd8..feb0f2f11a2 100644 --- a/boards/arm/stm32f769i_disco/stm32f769i_disco.dts +++ b/boards/arm/stm32f769i_disco/stm32f769i_disco.dts @@ -172,11 +172,10 @@ arduino_serial: &usart6 {}; pinctrl-names = "default"; status = "okay"; - mx25l51245g: qspi-nor-flash@0 { + mx25l51245g: qspi-nor-flash@90000000 { compatible = "st,stm32-qspi-nor"; - reg = <0>; + reg = <0x90000000 DT_SIZE_M(64)>; /* 512 Mbits */ qspi-max-frequency = <72000000>; - size = ; status = "okay"; partitions { @@ -186,7 +185,7 @@ arduino_serial: &usart6 {}; slot1_partition: partition@0 { label = "image-1"; - reg = <0x00000000 DT_SIZE_K(1664)>; + reg = <0x00000000 DT_SIZE_K(16)>; }; storage_partition: partition@1a0000 { diff --git a/boards/arm/stm32h747i_disco/stm32h747i_disco_m7.dts b/boards/arm/stm32h747i_disco/stm32h747i_disco_m7.dts index 514047c8a55..8f27eb0f836 100644 --- a/boards/arm/stm32h747i_disco/stm32h747i_disco_m7.dts +++ b/boards/arm/stm32h747i_disco/stm32h747i_disco_m7.dts @@ -232,11 +232,10 @@ zephyr_udc0: &usbotg_hs { pinctrl-names = "default"; status = "okay"; - mt25ql512ab1: qspi-nor-flash-1@0 { + mt25ql512ab1: qspi-nor-flash-1@90000000 { compatible = "st,stm32-qspi-nor"; - reg = <0>; + reg = <0x90000000 DT_SIZE_M(64)>; /* 512 Mbits */ qspi-max-frequency = <72000000>; - size = ; /* 64 MBytes */ spi-bus-width = <4>; status = "okay"; @@ -251,11 +250,10 @@ zephyr_udc0: &usbotg_hs { }; }; - mt25ql512ab2: qspi-nor-flash-2@0 { + mt25ql512ab2: qspi-nor-flash-2@90000000 { compatible = "st,stm32-qspi-nor"; - reg = <0>; + reg = <0x90000000 DT_SIZE_M(64)>; /* 512 Mbits */ qspi-max-frequency = <72000000>; - size = ; /* 64 MBytes */ status = "okay"; }; }; diff --git a/boards/arm/stm32h750b_dk/stm32h750b_dk.dts b/boards/arm/stm32h750b_dk/stm32h750b_dk.dts index efe4b7b2743..143b4b8416b 100644 --- a/boards/arm/stm32h750b_dk/stm32h750b_dk.dts +++ b/boards/arm/stm32h750b_dk/stm32h750b_dk.dts @@ -102,11 +102,10 @@ flash-id = <1>; status = "okay"; - mt25ql512ab1: qspi-nor-flash-1@0 { + mt25ql512ab1: qspi-nor-flash-1@90000000 { compatible = "st,stm32-qspi-nor"; - reg = <0>; + reg = <0x90000000 DT_SIZE_M(64)>; /* 512 Mbits */ qspi-max-frequency = <72000000>; - size = ; /* 64 MBytes */ spi-bus-width = <4>; status = "okay"; @@ -121,9 +120,9 @@ }; }; - mt25ql512ab2: qspi-nor-flash-2@1 { + mt25ql512ab2: qspi-nor-flash-2@90000000 { compatible = "st,stm32-qspi-nor"; - reg = <1>; + reg = <0x90000000 DT_SIZE_M(64)>; /* 512 Mbits */ qspi-max-frequency = <72000000>; size = ; /* 64 MBytes */ status = "okay"; diff --git a/boards/arm/stm32l496g_disco/stm32l496g_disco.dts b/boards/arm/stm32l496g_disco/stm32l496g_disco.dts index 977e70142ef..e2a70f6163d 100644 --- a/boards/arm/stm32l496g_disco/stm32l496g_disco.dts +++ b/boards/arm/stm32l496g_disco/stm32l496g_disco.dts @@ -201,11 +201,10 @@ zephyr_udc0: &usbotg_fs { flash-id = <1>; status = "okay"; - mx25r6435: qspi-nor-flash@0 { + mx25r6435: qspi-nor-flash@90000000 { compatible = "st,stm32-qspi-nor"; - reg = <0>; + reg = <0x90000000 DT_SIZE_M(8)>; /* 64 Mbits */ qspi-max-frequency = <8000000>; - size = ; /* 8 MBytes */ status = "okay"; spi-bus-width = <4>; writeoc = "PP_1_4_4"; diff --git a/samples/subsys/fs/littlefs/boards/nucleo_h743zi.overlay b/samples/subsys/fs/littlefs/boards/nucleo_h743zi.overlay index c8baceee06b..b7a8c63fed6 100644 --- a/samples/subsys/fs/littlefs/boards/nucleo_h743zi.overlay +++ b/samples/subsys/fs/littlefs/boards/nucleo_h743zi.overlay @@ -23,11 +23,10 @@ flash-id = <2>; status = "okay"; - mx25l25645g: qspi-nor-flash@0 { + mx25l25645g: qspi-nor-flash@90000000 { compatible = "st,stm32-qspi-nor"; - reg = <0>; + reg = <0x90000000 DT_SIZE_M(32)>; /* 256 Mbits */ qspi-max-frequency = <50000000>; - size = ; reset-gpios = <&gpiod 3 GPIO_ACTIVE_LOW>; reset-gpios-duration = <1>; spi-bus-width = <4>; From 9059b6a62d1fa3d3776ee49ede6cf26f47f9c9f7 Mon Sep 17 00:00:00 2001 From: Francois Ramu Date: Tue, 30 Jan 2024 16:28:00 +0100 Subject: [PATCH 3375/3723] doc: releases:; migration guide updated Update the migration guide for release v3.6 to detail the change about the bindings of `st,stm32-ospi-nor` and `st,stm32-qspi-nor` compatible Signed-off-by: Francois Ramu --- doc/releases/migration-guide-3.6.rst | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/doc/releases/migration-guide-3.6.rst b/doc/releases/migration-guide-3.6.rst index 46587dea64e..a45117ef9b0 100644 --- a/doc/releases/migration-guide-3.6.rst +++ b/doc/releases/migration-guide-3.6.rst @@ -177,6 +177,18 @@ Device Drivers and Device Tree status = "okay"; }; + +* The :dtcompatible:`st,stm32-ospi-nor` and :dtcompatible:`st,stm32-qspi-nor` give the nor flash + base address and size (in Bytes) with the **reg** property as follows. + The property is not used anymore. + + .. code-block:: devicetree + + mx25lm51245: ospi-nor-flash@70000000 { + compatible = "st,stm32-ospi-nor"; + reg = <0x70000000 DT_SIZE_M(64)>; /* 512 Mbits*/ + }; + * The native Linux SocketCAN driver, which can now be used in both :ref:`native_posix` and :ref:`native_sim` with or without an embedded C-library, has been renamed to reflect this: From 0ac2a0fce96d403bd42ae78c1764e97f845e371a Mon Sep 17 00:00:00 2001 From: Yasushi SHOJI Date: Thu, 25 Jan 2024 13:06:47 +0900 Subject: [PATCH 3376/3723] cmake: sca: Add "SCA" to the Found messages This commit enhances the clarity of the build log by adding the "SCA" prefix to the "Found" messages generated by sca/*/sca.cmake. This change improves the readability of the `west build` log for users who may not be familiar with these tools, providing more informative and understandable output. Signed-off-by: Yasushi SHOJI --- cmake/sca/codechecker/sca.cmake | 2 +- cmake/sca/sparse/sca.cmake | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/cmake/sca/codechecker/sca.cmake b/cmake/sca/codechecker/sca.cmake index c7cf6325c40..87b6015ae84 100644 --- a/cmake/sca/codechecker/sca.cmake +++ b/cmake/sca/codechecker/sca.cmake @@ -3,7 +3,7 @@ # Copyright (c) 2023, Basalte bv find_program(CODECHECKER_EXE CodeChecker REQUIRED) -message(STATUS "Found CodeChecker: ${CODECHECKER_EXE}") +message(STATUS "Found SCA: CodeChecker (${CODECHECKER_EXE})") # CodeChecker uses the compile_commands.json as input set(CMAKE_EXPORT_COMPILE_COMMANDS ON) diff --git a/cmake/sca/sparse/sca.cmake b/cmake/sca/sparse/sca.cmake index 21511b07baa..356364997e6 100644 --- a/cmake/sca/sparse/sca.cmake +++ b/cmake/sca/sparse/sca.cmake @@ -3,7 +3,7 @@ # Copyright (c) 2022, Nordic Semiconductor ASA find_program(SPARSE_COMPILER cgcc REQUIRED) -message(STATUS "Found sparse: ${SPARSE_COMPILER}") +message(STATUS "Found SCA: sparse (${SPARSE_COMPILER})") # Create sparse.cmake which will be called as compiler launcher. # sparse.cmake will ensure that REAL_CC is set correctly in environment before From 6a069e14e7c1a124e7469eed14f1239874918596 Mon Sep 17 00:00:00 2001 From: Yasushi SHOJI Date: Sun, 21 Jan 2024 17:27:25 +0900 Subject: [PATCH 3377/3723] cmake: sca: Add Parasoft C++test This commit adds Parasoft C++test as a Static Analyser using Zephyr's SCA framework. By specifing -DZEPHYR_SCA_VARIANT=cpptest to west build, a cpptestscan.bdf file will be generated under builddir/sca/cpptest/. Signed-off-by: Yasushi SHOJI --- cmake/sca/cpptest/sca.cmake | 15 +++++++++++++++ 1 file changed, 15 insertions(+) create mode 100644 cmake/sca/cpptest/sca.cmake diff --git a/cmake/sca/cpptest/sca.cmake b/cmake/sca/cpptest/sca.cmake new file mode 100644 index 00000000000..cc226345d1c --- /dev/null +++ b/cmake/sca/cpptest/sca.cmake @@ -0,0 +1,15 @@ +# SPDX-License-Identifier: Apache-2.0 +# +# Copyright (c) 2024, Space Cubics, LLC. + +find_program(CPPTESTSCAN cpptestscan REQUIRED) +message(STATUS "Found SCA: Parasoft C/C++test (${CPPTESTSCAN})") + +set(output_dir ${CMAKE_BINARY_DIR}/sca/cpptest) +file(MAKE_DIRECTORY ${output_dir}) + +set(output_file ${output_dir}/cpptestscan.bdf) +set(output_arg --cpptestscanOutputFile=${output_file}) + +set(CMAKE_C_COMPILER_LAUNCHER ${CPPTESTSCAN} ${output_arg} CACHE INTERNAL "") +set(CMAKE_CXX_COMPILER_LAUNCHER ${CPPTESTSCAN} ${output_arg} CACHE INTERNAL "") From 50d8cd4c98197a37afcfeae7dde99e71c5108861 Mon Sep 17 00:00:00 2001 From: Yasushi SHOJI Date: Sun, 28 Jan 2024 10:36:08 +0900 Subject: [PATCH 3378/3723] doc: develop: sca: Add Parasoft C/C++test Add documentation for Parasoft C/C++test for Static Code Analysis. Signed-off-by: Yasushi SHOJI --- doc/develop/sca/cpptest.rst | 40 +++++++++++++++++++++++++++++++++++++ doc/develop/sca/index.rst | 1 + 2 files changed, 41 insertions(+) create mode 100644 doc/develop/sca/cpptest.rst diff --git a/doc/develop/sca/cpptest.rst b/doc/develop/sca/cpptest.rst new file mode 100644 index 00000000000..a9f02fc09f5 --- /dev/null +++ b/doc/develop/sca/cpptest.rst @@ -0,0 +1,40 @@ +.. _cpptest: + +Parasoft C/C++test support +########################## + +Parasoft `C/C++test `__ is a software testing +and static analysis tool for C and C++. It is a commercial software and you must acquire a +commercial license to use it. + +Documentation of C/C++test can be found at https://docs.parasoft.com/. Please refer to the +documentation for how to use it. + +Generating Build Data Files +*************************** + +To use C/C++test, ``cpptestscan`` must be found in your :envvar:`PATH` environment variable. And +:ref:`west build ` should be called with a ``-DZEPHYR_SCA_VARIANT=cpptest`` +parameter, e.g. + +.. code-block:: shell + + west build -b qemu_cortex_m3 zephyr/samples/hello_world -- -DZEPHYR_SCA_VARIANT=cpptest + + +A ``.bdf`` file will be generated as :file:`build/sca/cpptest/cpptestscan.bdf`. + +Generating a report file +************************ + +Please refer to Parasoft C/C++test documentation for more details. + +To import and generate a report file, something like the following should work. + +.. code-block:: shell + + cpptestcli -data out -localsettings local.conf -bdf build/sca/cpptest/cpptestscan.bdf -config "builtin://Recommended Rules" -report out/report + + +You might need to set ``bdf.import.c.compiler.exec``, ``bdf.import.cpp.compiler.exec``, and +``bdf.import.linker.exec`` to the toolchain :ref:`west build ` used. diff --git a/doc/develop/sca/index.rst b/doc/develop/sca/index.rst index 44a9ee42615..0a471439235 100644 --- a/doc/develop/sca/index.rst +++ b/doc/develop/sca/index.rst @@ -64,3 +64,4 @@ The following is a list of SCA tools natively supported by Zephyr build system. codechecker sparse gcc + cpptest From d7328eac67e60827e8e3cf1a61c38fbc33212f58 Mon Sep 17 00:00:00 2001 From: Lyle Zhu Date: Thu, 1 Feb 2024 22:16:54 +0800 Subject: [PATCH 3379/3723] Bluetooth: Host: Set user data size for hfp tx pool The user data size of hfp tx pool is zero. There is not enough space to put tx_mate. Use CONFIG_BT_CONN_TX_USER_DATA_SIZE to set data size of hfp tx pool. Signed-off-by: Lyle Zhu --- subsys/bluetooth/host/hfp_hf.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/subsys/bluetooth/host/hfp_hf.c b/subsys/bluetooth/host/hfp_hf.c index e6cc10c8f7c..0bb2398e537 100644 --- a/subsys/bluetooth/host/hfp_hf.c +++ b/subsys/bluetooth/host/hfp_hf.c @@ -35,7 +35,8 @@ LOG_MODULE_REGISTER(bt_hfp_hf); struct bt_hfp_hf_cb *bt_hf; NET_BUF_POOL_FIXED_DEFINE(hf_pool, CONFIG_BT_MAX_CONN + 1, - BT_RFCOMM_BUF_SIZE(BT_HF_CLIENT_MAX_PDU), 0, NULL); + BT_RFCOMM_BUF_SIZE(BT_HF_CLIENT_MAX_PDU), + CONFIG_BT_CONN_TX_USER_DATA_SIZE, NULL); static struct bt_hfp_hf bt_hfp_hf_pool[CONFIG_BT_MAX_CONN]; From eb144c05feb8c23e20e505ec2c5870e5fdcb8440 Mon Sep 17 00:00:00 2001 From: Stephanos Ioannidis Date: Thu, 1 Feb 2024 02:22:08 +0000 Subject: [PATCH 3380/3723] ci: Switch to CI image v0.26.7 This commit updates the CI workflows to use the CI image v0.26.7, in order to pull in the Zephyr SDK 0.16.5 release. Signed-off-by: Stephanos Ioannidis --- .github/workflows/bsim-tests.yaml | 2 +- .github/workflows/clang.yaml | 2 +- .github/workflows/codecov.yaml | 2 +- .github/workflows/errno.yml | 2 +- .github/workflows/footprint-tracking.yml | 2 +- .github/workflows/footprint.yml | 2 +- .github/workflows/twister.yaml | 4 ++-- .github/workflows/twister_tests_blackbox.yml | 2 +- 8 files changed, 9 insertions(+), 9 deletions(-) diff --git a/.github/workflows/bsim-tests.yaml b/.github/workflows/bsim-tests.yaml index b8b34315772..402ae686593 100644 --- a/.github/workflows/bsim-tests.yaml +++ b/.github/workflows/bsim-tests.yaml @@ -32,7 +32,7 @@ jobs: if: github.repository_owner == 'zephyrproject-rtos' runs-on: zephyr-runner-linux-x64-4xlarge container: - image: ghcr.io/zephyrproject-rtos/ci:v0.26.6 + image: ghcr.io/zephyrproject-rtos/ci:v0.26.7 options: '--entrypoint /bin/bash' volumes: - /repo-cache/zephyrproject:/github/cache/zephyrproject diff --git a/.github/workflows/clang.yaml b/.github/workflows/clang.yaml index caebd7feda1..17fbc1c72bd 100644 --- a/.github/workflows/clang.yaml +++ b/.github/workflows/clang.yaml @@ -11,7 +11,7 @@ jobs: if: github.repository_owner == 'zephyrproject-rtos' runs-on: zephyr-runner-linux-x64-4xlarge container: - image: ghcr.io/zephyrproject-rtos/ci:v0.26.6 + image: ghcr.io/zephyrproject-rtos/ci:v0.26.7 options: '--entrypoint /bin/bash' volumes: - /repo-cache/zephyrproject:/github/cache/zephyrproject diff --git a/.github/workflows/codecov.yaml b/.github/workflows/codecov.yaml index 832f9873a5e..7888529ee40 100644 --- a/.github/workflows/codecov.yaml +++ b/.github/workflows/codecov.yaml @@ -13,7 +13,7 @@ jobs: if: github.repository == 'zephyrproject-rtos/zephyr' runs-on: zephyr-runner-linux-x64-4xlarge container: - image: ghcr.io/zephyrproject-rtos/ci:v0.26.6 + image: ghcr.io/zephyrproject-rtos/ci:v0.26.7 options: '--entrypoint /bin/bash' volumes: - /repo-cache/zephyrproject:/github/cache/zephyrproject diff --git a/.github/workflows/errno.yml b/.github/workflows/errno.yml index 78e8b8e8ed6..e6bea7dca4a 100644 --- a/.github/workflows/errno.yml +++ b/.github/workflows/errno.yml @@ -10,7 +10,7 @@ jobs: check-errno: runs-on: ubuntu-22.04 container: - image: ghcr.io/zephyrproject-rtos/ci:v0.26.6 + image: ghcr.io/zephyrproject-rtos/ci:v0.26.7 steps: - name: Apply container owner mismatch workaround diff --git a/.github/workflows/footprint-tracking.yml b/.github/workflows/footprint-tracking.yml index 9b90cff1f9e..e028ddd5329 100644 --- a/.github/workflows/footprint-tracking.yml +++ b/.github/workflows/footprint-tracking.yml @@ -25,7 +25,7 @@ jobs: runs-on: zephyr-runner-linux-x64-4xlarge if: github.repository_owner == 'zephyrproject-rtos' container: - image: ghcr.io/zephyrproject-rtos/ci:v0.26.6 + image: ghcr.io/zephyrproject-rtos/ci:v0.26.7 options: '--entrypoint /bin/bash' strategy: fail-fast: false diff --git a/.github/workflows/footprint.yml b/.github/workflows/footprint.yml index 2b907618082..e25ef7f4652 100644 --- a/.github/workflows/footprint.yml +++ b/.github/workflows/footprint.yml @@ -11,7 +11,7 @@ jobs: runs-on: zephyr-runner-linux-x64-4xlarge if: github.repository == 'zephyrproject-rtos/zephyr' container: - image: ghcr.io/zephyrproject-rtos/ci:v0.26.6 + image: ghcr.io/zephyrproject-rtos/ci:v0.26.7 options: '--entrypoint /bin/bash' strategy: fail-fast: false diff --git a/.github/workflows/twister.yaml b/.github/workflows/twister.yaml index 7f65178e103..a56ce93c42d 100644 --- a/.github/workflows/twister.yaml +++ b/.github/workflows/twister.yaml @@ -24,7 +24,7 @@ jobs: if: github.repository_owner == 'zephyrproject-rtos' runs-on: zephyr-runner-linux-x64-4xlarge container: - image: ghcr.io/zephyrproject-rtos/ci:v0.26.6 + image: ghcr.io/zephyrproject-rtos/ci:v0.26.7 options: '--entrypoint /bin/bash' volumes: - /repo-cache/zephyrproject:/github/cache/zephyrproject @@ -123,7 +123,7 @@ jobs: needs: twister-build-prep if: needs.twister-build-prep.outputs.size != 0 container: - image: ghcr.io/zephyrproject-rtos/ci:v0.26.6 + image: ghcr.io/zephyrproject-rtos/ci:v0.26.7 options: '--entrypoint /bin/bash' volumes: - /repo-cache/zephyrproject:/github/cache/zephyrproject diff --git a/.github/workflows/twister_tests_blackbox.yml b/.github/workflows/twister_tests_blackbox.yml index 3811b9b3fb8..cdb11d95286 100644 --- a/.github/workflows/twister_tests_blackbox.yml +++ b/.github/workflows/twister_tests_blackbox.yml @@ -22,7 +22,7 @@ jobs: python-version: [3.8, 3.9, '3.10', '3.11', '3.12'] os: [ubuntu-22.04] container: - image: ghcr.io/zephyrproject-rtos/ci:v0.26.6 + image: ghcr.io/zephyrproject-rtos/ci:v0.26.7 steps: - name: Apply Container Owner Mismatch Workaround From 36a593b29c82a35b71c85fdb843fcf2f7a6e6a82 Mon Sep 17 00:00:00 2001 From: Stephanos Ioannidis Date: Thu, 1 Feb 2024 02:22:56 +0000 Subject: [PATCH 3381/3723] SDK_VERSION: Use Zephyr SDK 0.16.5 This commit updates SDK_VERSION to point to the Zephyr SDK 0.16.5 release. Signed-off-by: Stephanos Ioannidis --- SDK_VERSION | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/SDK_VERSION b/SDK_VERSION index 5f2491c5adc..19270385eaf 100644 --- a/SDK_VERSION +++ b/SDK_VERSION @@ -1 +1 @@ -0.16.4 +0.16.5 From 23d3114db3607cdc41a2d2a5dc0467778a90d69d Mon Sep 17 00:00:00 2001 From: Linus Isberg Martinsson Date: Wed, 31 Jan 2024 14:08:55 +0100 Subject: [PATCH 3382/3723] dts: boards: stm32h562: Add missing UART7 and UART8 UART7 and UART8 instances were missing in the device tree for STM32H562. Signed-off-by: Linus Isberg Martinsson --- dts/arm/st/h5/stm32h562.dtsi | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) diff --git a/dts/arm/st/h5/stm32h562.dtsi b/dts/arm/st/h5/stm32h562.dtsi index 1285f10b1eb..0e407a02be0 100644 --- a/dts/arm/st/h5/stm32h562.dtsi +++ b/dts/arm/st/h5/stm32h562.dtsi @@ -72,6 +72,24 @@ status = "disabled"; }; + uart7: serial@40007800 { + compatible = "st,stm32-uart"; + reg = <0x40007800 0x400>; + clocks = <&rcc STM32_CLOCK_BUS_APB1 0x40000000>; + resets = <&rctl STM32_RESET(APB1L, 30U)>; + interrupts = <98 0>; + status = "disabled"; + }; + + uart8: serial@40007c00 { + compatible = "st,stm32-uart"; + reg = <0x40007c00 0x400>; + clocks = <&rcc STM32_CLOCK_BUS_APB1 0x80000000>; + resets = <&rctl STM32_RESET(APB1L, 31U)>; + interrupts = <99 0>; + status = "disabled"; + }; + uart9: serial@40008000 { compatible = "st,stm32-uart"; reg = <0x40008000 0x400>; From 89ce3566c056b9a647f08d13cf16f9e4baeaf824 Mon Sep 17 00:00:00 2001 From: Troels Nilsson Date: Wed, 31 Jan 2024 11:07:30 +0100 Subject: [PATCH 3383/3723] Bluetooth: Controller: Fix handling of CTEInfo in le_ext_adv_report() Handling of CTEInfo being present was missing; Fixes test failure of LL/DDI/SCN/BV-89-C Signed-off-by: Troels Nilsson --- subsys/bluetooth/controller/hci/hci.c | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/subsys/bluetooth/controller/hci/hci.c b/subsys/bluetooth/controller/hci/hci.c index 66d68471305..6b15e721978 100644 --- a/subsys/bluetooth/controller/hci/hci.c +++ b/subsys/bluetooth/controller/hci/hci.c @@ -7002,6 +7002,11 @@ static void le_ext_adv_report(struct pdu_data *pdu_data, ptr += BDADDR_SIZE; } + if (h->cte_info) { + /* CTEInfo is RFU */ + ptr += 1; + } + if (h->adi) { adi_curr = (void *)ptr; From 069bcbcb7f0ed3a757a816c39768b916f9feba54 Mon Sep 17 00:00:00 2001 From: Tomas Galbicka Date: Tue, 30 Jan 2024 17:00:00 +0100 Subject: [PATCH 3384/3723] drivers: mbox: Add NXP Mailbox driver for mbox This adds new NXP mailbox driver for MBOX device. NXP mailbox IP driver supports sending data between cores. It uses 32 bit register to trigger irq to other core. This driver implementation uses 4 bits for channel selection of triggering mode, 4 bits for channel selection of data transfer and rest 24 bits for data. NXP mailbox IP Reference Manual UM11126, Chapter 52. https://www.nxp.com/webapp/Download?colCode=UM11126 Signed-off-by: Tomas Galbicka --- drivers/mbox/CMakeLists.txt | 1 + drivers/mbox/Kconfig | 2 + drivers/mbox/Kconfig.nxp_mailbox | 9 + drivers/mbox/mbox_nxp_mailbox.c | 210 ++++++++++++++++++++++++ dts/bindings/mbox/nxp,mbox-mailbox.yaml | 37 +++++ 5 files changed, 259 insertions(+) create mode 100644 drivers/mbox/Kconfig.nxp_mailbox create mode 100644 drivers/mbox/mbox_nxp_mailbox.c create mode 100644 dts/bindings/mbox/nxp,mbox-mailbox.yaml diff --git a/drivers/mbox/CMakeLists.txt b/drivers/mbox/CMakeLists.txt index b81a3bb679f..89e5d58e65c 100644 --- a/drivers/mbox/CMakeLists.txt +++ b/drivers/mbox/CMakeLists.txt @@ -8,4 +8,5 @@ zephyr_library_sources_ifdef(CONFIG_USERSPACE mbox_handlers.c) zephyr_library_sources_ifdef(CONFIG_MBOX_NRFX_IPC mbox_nrfx_ipc.c) zephyr_library_sources_ifdef(CONFIG_MBOX_NXP_S32_MRU mbox_nxp_s32_mru.c) zephyr_library_sources_ifdef(CONFIG_MBOX_NXP_IMX_MU mbox_nxp_imx_mu.c) +zephyr_library_sources_ifdef(CONFIG_MBOX_NXP_MAILBOX mbox_nxp_mailbox.c) zephyr_library_sources_ifdef(CONFIG_MBOX_ANDES_PLIC_SW mbox_andes_plic_sw.c) diff --git a/drivers/mbox/Kconfig b/drivers/mbox/Kconfig index 0668c9aab8b..67041e91f59 100644 --- a/drivers/mbox/Kconfig +++ b/drivers/mbox/Kconfig @@ -1,4 +1,5 @@ # Copyright (c) 2021 Carlo Caione +# Copyright 2024 NXP # SPDX-License-Identifier: Apache-2.0 menuconfig MBOX @@ -14,6 +15,7 @@ if MBOX source "drivers/mbox/Kconfig.nrfx" source "drivers/mbox/Kconfig.nxp_s32" source "drivers/mbox/Kconfig.nxp_imx" +source "drivers/mbox/Kconfig.nxp_mailbox" source "drivers/mbox/Kconfig.andes" config MBOX_INIT_PRIORITY diff --git a/drivers/mbox/Kconfig.nxp_mailbox b/drivers/mbox/Kconfig.nxp_mailbox new file mode 100644 index 00000000000..fa1c2dc79d1 --- /dev/null +++ b/drivers/mbox/Kconfig.nxp_mailbox @@ -0,0 +1,9 @@ +# Copyright 2024 NXP +# SPDX-License-Identifier: Apache-2.0 + +config MBOX_NXP_MAILBOX + bool "NXP Mailbox driver for MBOX" + default y + depends on DT_HAS_NXP_LPC_MAILBOX_ENABLED + help + Driver for NXP Mailbox Unit around MBOX. diff --git a/drivers/mbox/mbox_nxp_mailbox.c b/drivers/mbox/mbox_nxp_mailbox.c new file mode 100644 index 00000000000..7c2818f0ffe --- /dev/null +++ b/drivers/mbox/mbox_nxp_mailbox.c @@ -0,0 +1,210 @@ +/* + * Copyright 2024 NXP + * + * SPDX-License-Identifier: Apache-2.0 + * + * Wrapper of NXP Mailbox driver for Zephyr's MBOX model. + */ + +#include +#include +#include +#include + +#define LOG_LEVEL CONFIG_MBOX_LOG_LEVEL +#include +LOG_MODULE_REGISTER(nxp_mbox_mailbox); + +#define DT_DRV_COMPAT nxp_mbox_mailbox + +#define MAILBOX_MAX_CHANNELS 4 +#define MAILBOX_MBOX_SIZE 3 + +#if (defined(LPC55S69_cm33_core0_SERIES) || defined(LPC55S69_cm33_core1_SERIES)) +#ifdef LPC55S69_cm33_core0_SERIES +#define MAILBOX_ID_THIS_CPU kMAILBOX_CM33_Core0 +#define MAILBOX_ID_OTHER_CPU kMAILBOX_CM33_Core1 +#else +#define MAILBOX_ID_THIS_CPU kMAILBOX_CM33_Core1 +#define MAILBOX_ID_OTHER_CPU kMAILBOX_CM33_Core0 +#endif +#else +#if defined(__CM4_CMSIS_VERSION) +#define MAILBOX_ID_THIS_CPU kMAILBOX_CM4 +#define MAILBOX_ID_OTHER_CPU kMAILBOX_CM0Plus +#else +#define MAILBOX_ID_THIS_CPU kMAILBOX_CM0Plus +#define MAILBOX_ID_OTHER_CPU kMAILBOX_CM4 +#endif +#endif + +#define GENIRQ_SHIFT (28U) +#define GEN0_IRQ_TRIGGER BIT(GENIRQ_SHIFT + 3U) /*!< General interrupt 3. */ +#define GEN1_IRQ_TRIGGER BIT(GENIRQ_SHIFT + 2U) /*!< General interrupt 2. */ +#define GEN2_IRQ_TRIGGER BIT(GENIRQ_SHIFT + 1U) /*!< General interrupt 1. */ +#define GEN3_IRQ_TRIGGER BIT(GENIRQ_SHIFT + 0U) /*!< General interrupt 0. */ + +#define DATA_MASK BIT_MASK(24U) +#define DATAIRQ_SHIFT (24U) +#define DATA0_IRQ_TRIGGER BIT(DATAIRQ_SHIFT + 3U) /*!< Data interrupt 3. */ +#define DATA1_IRQ_TRIGGER BIT(DATAIRQ_SHIFT + 2U) /*!< Data interrupt 2. */ +#define DATA2_IRQ_TRIGGER BIT(DATAIRQ_SHIFT + 1U) /*!< Data interrupt 1. */ +#define DATA3_IRQ_TRIGGER BIT(DATAIRQ_SHIFT + 0U) /*!< Data interrupt 0. */ + +struct nxp_mailbox_data { + mbox_callback_t cb[MAILBOX_MAX_CHANNELS]; + void *user_data[MAILBOX_MAX_CHANNELS]; + bool channel_enable[MAILBOX_MAX_CHANNELS]; + uint32_t received_data; +}; + +struct nxp_mailbox_config { + MAILBOX_Type *base; +}; + +static void mailbox_isr(const struct device *dev) +{ + struct nxp_mailbox_data *data = dev->data; + const struct nxp_mailbox_config *config = dev->config; + mailbox_cpu_id_t cpu_id; + + cpu_id = MAILBOX_ID_THIS_CPU; + + volatile uint32_t mailbox_value = MAILBOX_GetValue(config->base, cpu_id); + uint32_t flags = mailbox_value & (~DATA_MASK); + + /* Clear or the interrupt gets called intermittently */ + MAILBOX_ClearValueBits(config->base, cpu_id, mailbox_value); + + for (int i_channel = 0; i_channel < MAILBOX_MAX_CHANNELS; i_channel++) { + /* Continue to next channel if channel is not enabled */ + if (!data->channel_enable[i_channel]) { + continue; + } + + if ((flags & (DATA0_IRQ_TRIGGER >> i_channel))) { + data->received_data = mailbox_value & DATA_MASK; + struct mbox_msg msg = {(const void *)&data->received_data, + MAILBOX_MBOX_SIZE}; + + if (data->cb[i_channel]) { + data->cb[i_channel](dev, i_channel, data->user_data[i_channel], + &msg); + } + } else if ((flags & (GEN0_IRQ_TRIGGER >> i_channel))) { + if (data->cb[i_channel]) { + data->cb[i_channel](dev, i_channel, data->user_data[i_channel], + NULL); + } + } + } + + /* Add for ARM errata 838869, affects Cortex-M4, Cortex-M4F + * Store immediate overlapping exception return operation + * might vector to incorrect interrupt + */ +#if defined __CORTEX_M && (__CORTEX_M == 4U) + barrier_dsync_fence_full(); +#endif +} + +static int nxp_mailbox_send(const struct device *dev, uint32_t channel, const struct mbox_msg *msg) +{ + uint32_t __aligned(4) data32; + const struct nxp_mailbox_config *cfg = dev->config; + + if (channel >= MAILBOX_MAX_CHANNELS) { + return -EINVAL; + } + + /* Signalling mode. */ + if (msg == NULL) { + MAILBOX_SetValueBits(cfg->base, MAILBOX_ID_OTHER_CPU, GEN0_IRQ_TRIGGER >> channel); + return 0; + } + + /* Data transfer mode. */ + if (msg->size != MAILBOX_MBOX_SIZE) { + /* We can only send this many bytes at a time. */ + return -EMSGSIZE; + } + + /* memcpy to avoid issues when msg->data is not word-aligned. */ + memcpy(&data32, msg->data, msg->size); + + MAILBOX_SetValueBits(cfg->base, MAILBOX_ID_OTHER_CPU, + (DATA0_IRQ_TRIGGER >> channel) | (data32 & DATA_MASK)); + + return 0; +} + +static int nxp_mailbox_register_callback(const struct device *dev, uint32_t channel, + mbox_callback_t cb, void *user_data) +{ + struct nxp_mailbox_data *data = dev->data; + + if (channel >= MAILBOX_MAX_CHANNELS) { + return -EINVAL; + } + + data->cb[channel] = cb; + data->user_data[channel] = user_data; + + return 0; +} + +static int nxp_mailbox_mtu_get(const struct device *dev) +{ + ARG_UNUSED(dev); + + return MAILBOX_MBOX_SIZE; +} + +static uint32_t nxp_mailbox_max_channels_get(const struct device *dev) +{ + ARG_UNUSED(dev); + return MAILBOX_MAX_CHANNELS; +} + +static int nxp_mailbox_set_enabled(const struct device *dev, uint32_t channel, bool enable) +{ + struct nxp_mailbox_data *data = dev->data; + + if (channel >= MAILBOX_MAX_CHANNELS) { + return -EINVAL; + } + + data->channel_enable[channel] = enable; + + return 0; +} + +static const struct mbox_driver_api nxp_mailbox_driver_api = { + .send = nxp_mailbox_send, + .register_callback = nxp_mailbox_register_callback, + .mtu_get = nxp_mailbox_mtu_get, + .max_channels_get = nxp_mailbox_max_channels_get, + .set_enabled = nxp_mailbox_set_enabled, +}; + +#define MAILBOX_INSTANCE_DEFINE(idx) \ + static struct nxp_mailbox_data nxp_mailbox_##idx##_data; \ + const static struct nxp_mailbox_config nxp_mailbox_##idx##_config = { \ + .base = (MAILBOX_Type *)DT_INST_REG_ADDR(idx), \ + }; \ + static int nxp_mailbox_##idx##_init(const struct device *dev) \ + { \ + ARG_UNUSED(dev); \ + MAILBOX_Init(nxp_mailbox_##idx##_config.base); \ + IRQ_CONNECT(DT_INST_IRQN(idx), DT_INST_IRQ(idx, priority), mailbox_isr, \ + DEVICE_DT_INST_GET(idx), 0); \ + irq_enable(DT_INST_IRQN(idx)); \ + return 0; \ + } \ + DEVICE_DT_INST_DEFINE(idx, nxp_mailbox_##idx##_init, NULL, &nxp_mailbox_##idx##_data, \ + &nxp_mailbox_##idx##_config, POST_KERNEL, CONFIG_MBOX_INIT_PRIORITY, \ + &nxp_mailbox_driver_api) + +#define MAILBOX_INST(idx) MAILBOX_INSTANCE_DEFINE(idx); + +DT_INST_FOREACH_STATUS_OKAY(MAILBOX_INST) diff --git a/dts/bindings/mbox/nxp,mbox-mailbox.yaml b/dts/bindings/mbox/nxp,mbox-mailbox.yaml new file mode 100644 index 00000000000..9a98aae9231 --- /dev/null +++ b/dts/bindings/mbox/nxp,mbox-mailbox.yaml @@ -0,0 +1,37 @@ +description: | + NXP Mailbox Unit as Zephyr MBOX. + + This NXP Mailbox driver implements Multi-Channel Inter-Processor Mailbox (MBOX) API + around NXP Inter-CPU Mailbox peripheral IP block. + + The NXP Inter-CPU Mailbox provides up to thirty-two user defined interrupts. + This driver uses 4 interrupts for mbox signalling mode per each channel, + 4 interrupts for mxbox data transfer mode per each channel and 24 as 3 bytes + for data. + +compatible: "nxp,mbox-mailbox" + +include: [base.yaml, mailbox-controller.yaml] + +properties: + interrupts: + required: true + + rx-channels: + type: int + enum: [1, 2, 3, 4] + description: | + Number of receive channels enabled on this instance. + Setting this value to N, will enable channels 0 to N-1, consecutively. + It should be set by the receiver core coupled with this Mailbox instance. + + For example, if receiver A wants to Rx on channels 0 to 3, then A must + set rx-channels of mailbox as follows: + + mbox { + rx-channels = <4>; + status = "okay"; + }; + +mbox-cells: + - channel From 73d6c336cad7e6fd739ab397dabbe5748d274a82 Mon Sep 17 00:00:00 2001 From: Tomas Galbicka Date: Tue, 30 Jan 2024 17:12:34 +0100 Subject: [PATCH 3385/3723] samples: tests: mbox: Add lpcpresso55s69 support This commit adds support for NXP board LPCXpresso55S69 for mbox. - samples/drivers/mbox/ - mbox signaling mode - samples/drivers/mbox_data/ - mbox data transfer mode - tests/drivers/mbox/mbox_data/ - mbox test to verify functionality. Signed-off-by: Tomas Galbicka --- samples/drivers/mbox/CMakeLists.txt | 5 ++- samples/drivers/mbox/Kconfig.sysbuild | 3 +- .../mbox/boards/lpcxpresso55s69_cpu0.conf | 3 ++ .../mbox/boards/lpcxpresso55s69_cpu0.overlay | 29 +++++++++++++ samples/drivers/mbox/remote/CMakeLists.txt | 3 +- .../remote/boards/lpcxpresso55s69_cpu1.conf | 10 +++++ .../boards/lpcxpresso55s69_cpu1.overlay | 43 +++++++++++++++++++ samples/drivers/mbox/sample.yaml | 1 + samples/drivers/mbox/sysbuild.cmake | 5 ++- samples/drivers/mbox_data/CMakeLists.txt | 3 +- samples/drivers/mbox_data/Kconfig.sysbuild | 1 + samples/drivers/mbox_data/README.rst | 11 ++++- .../boards/lpcxpresso55s69_cpu0.conf | 3 ++ .../boards/lpcxpresso55s69_cpu0.overlay | 29 +++++++++++++ .../drivers/mbox_data/remote/CMakeLists.txt | 3 +- .../remote/boards/lpcxpresso55s69_cpu1.conf | 3 ++ .../boards/lpcxpresso55s69_cpu1.overlay | 29 +++++++++++++ samples/drivers/mbox_data/remote/src/main.c | 10 ++++- samples/drivers/mbox_data/sample.yaml | 2 + samples/drivers/mbox_data/src/main.c | 10 ++++- tests/drivers/mbox/mbox_data/CMakeLists.txt | 3 +- tests/drivers/mbox/mbox_data/Kconfig.sysbuild | 1 + .../boards/lpcxpresso55s69_cpu0.conf | 3 ++ .../boards/lpcxpresso55s69_cpu0.overlay | 29 +++++++++++++ .../mbox/mbox_data/remote/CMakeLists.txt | 3 +- .../remote/boards/lpcxpresso55s69_cpu1.conf | 3 ++ .../boards/lpcxpresso55s69_cpu1.overlay | 29 +++++++++++++ .../drivers/mbox/mbox_data/remote/src/main.c | 10 ++++- tests/drivers/mbox/mbox_data/src/main.c | 19 ++++++-- tests/drivers/mbox/mbox_data/testcase.yaml | 2 + west.yml | 2 +- 31 files changed, 292 insertions(+), 18 deletions(-) create mode 100644 samples/drivers/mbox/boards/lpcxpresso55s69_cpu0.conf create mode 100644 samples/drivers/mbox/boards/lpcxpresso55s69_cpu0.overlay create mode 100644 samples/drivers/mbox/remote/boards/lpcxpresso55s69_cpu1.conf create mode 100644 samples/drivers/mbox/remote/boards/lpcxpresso55s69_cpu1.overlay create mode 100644 samples/drivers/mbox_data/boards/lpcxpresso55s69_cpu0.conf create mode 100644 samples/drivers/mbox_data/boards/lpcxpresso55s69_cpu0.overlay create mode 100644 samples/drivers/mbox_data/remote/boards/lpcxpresso55s69_cpu1.conf create mode 100644 samples/drivers/mbox_data/remote/boards/lpcxpresso55s69_cpu1.overlay create mode 100644 tests/drivers/mbox/mbox_data/boards/lpcxpresso55s69_cpu0.conf create mode 100644 tests/drivers/mbox/mbox_data/boards/lpcxpresso55s69_cpu0.overlay create mode 100644 tests/drivers/mbox/mbox_data/remote/boards/lpcxpresso55s69_cpu1.conf create mode 100644 tests/drivers/mbox/mbox_data/remote/boards/lpcxpresso55s69_cpu1.overlay diff --git a/samples/drivers/mbox/CMakeLists.txt b/samples/drivers/mbox/CMakeLists.txt index 4344f4f3ce9..ca6513822a8 100644 --- a/samples/drivers/mbox/CMakeLists.txt +++ b/samples/drivers/mbox/CMakeLists.txt @@ -1,6 +1,6 @@ # # Copyright (c) 2021 Carlo Caione -# Copyright 2023 NXP +# Copyright 2023-2024 NXP # # SPDX-License-Identifier: Apache-2.0 # @@ -17,7 +17,8 @@ if(("${BOARD}" STREQUAL "nrf5340dk_nrf5340_cpuapp") OR ("${BOARD}" STREQUAL "mimxrt1170_evkb_cm7") OR ("${BOARD}" STREQUAL "mimxrt1170_evk_cm7") OR ("${BOARD}" STREQUAL "mimxrt1160_evk_cm7") OR - ("${BOARD}" STREQUAL "mimxrt595_evk_cm33")) + ("${BOARD}" STREQUAL "mimxrt595_evk_cm33") OR + ("${BOARD}" STREQUAL "lpcxpresso55s69_cpu0")) message(STATUS "${BOARD} compile as Main in this sample") else() message(FATAL_ERROR "${BOARD} is not supported for this sample") diff --git a/samples/drivers/mbox/Kconfig.sysbuild b/samples/drivers/mbox/Kconfig.sysbuild index f472576df82..20903872c34 100644 --- a/samples/drivers/mbox/Kconfig.sysbuild +++ b/samples/drivers/mbox/Kconfig.sysbuild @@ -1,5 +1,5 @@ # Copyright 2023 Nordic Semiconductor ASA -# Copyright 2023 NXP +# Copyright 2023-2024 NXP # # SPDX-License-Identifier: Apache-2.0 @@ -14,3 +14,4 @@ string default "mimxrt1170_evkb_cm4" if $(BOARD) = "mimxrt1170_evkb_cm7" default "mimxrt1170_evk_cm4" if $(BOARD) = "mimxrt1170_evk_cm7" default "mimxrt1160_evk_cm4" if $(BOARD) = "mimxrt1160_evk_cm7" + default "lpcxpresso55s69_cpu1" if $(BOARD) = "lpcxpresso55s69_cpu0" diff --git a/samples/drivers/mbox/boards/lpcxpresso55s69_cpu0.conf b/samples/drivers/mbox/boards/lpcxpresso55s69_cpu0.conf new file mode 100644 index 00000000000..5077d775881 --- /dev/null +++ b/samples/drivers/mbox/boards/lpcxpresso55s69_cpu0.conf @@ -0,0 +1,3 @@ +CONFIG_SECOND_CORE_MCUX=y +CONFIG_MBOX_NXP_MAILBOX=y +CONFIG_BUILD_OUTPUT_HEX=y diff --git a/samples/drivers/mbox/boards/lpcxpresso55s69_cpu0.overlay b/samples/drivers/mbox/boards/lpcxpresso55s69_cpu0.overlay new file mode 100644 index 00000000000..b5919c4fd72 --- /dev/null +++ b/samples/drivers/mbox/boards/lpcxpresso55s69_cpu0.overlay @@ -0,0 +1,29 @@ +/* + * Copyright 2024 NXP + * + * SPDX-License-Identifier: Apache-2.0 + */ + +/ { + chosen { + /* Delete ipc chosen property where old IPM mailbox driver bellow is + * configured. + */ + /delete-property/ zephyr,ipc; + }; + + soc { + /* Delete IPM Driver node nxp,lpc-mailbox */ + /delete-node/ mailbox@8b000; + + /* Attach MBOX driver to Mailbox Unit */ + mbox:mailbox0@5008b000 { + compatible = "nxp,mbox-mailbox"; + reg = <0x5008b000 0xEC>; + interrupts = <31 0>; + rx-channels = <4>; + #mbox-cells = <1>; + status = "okay"; + }; + }; +}; diff --git a/samples/drivers/mbox/remote/CMakeLists.txt b/samples/drivers/mbox/remote/CMakeLists.txt index e7db9b8cadf..2c7c8fff29e 100644 --- a/samples/drivers/mbox/remote/CMakeLists.txt +++ b/samples/drivers/mbox/remote/CMakeLists.txt @@ -1,6 +1,6 @@ # # Copyright (c) 2021 Carlo Caione -# Copyright 2023 NXP +# Copyright 2023-2024 NXP # # SPDX-License-Identifier: Apache-2.0 # @@ -14,6 +14,7 @@ if(("${BOARD}" STREQUAL "nrf5340dk_nrf5340_cpunet") OR ("${BOARD}" STREQUAL "mimxrt1170_evkb_cm4") OR ("${BOARD}" STREQUAL "mimxrt1170_evk_cm4") OR ("${BOARD}" STREQUAL "mimxrt1160_evk_cm4") OR + ("${BOARD}" STREQUAL "lpcxpresso55s69_cpu1") OR ("${BOARD}" STREQUAL "adp_xc7k_ae350")) message(STATUS "${BOARD} compile as remote in this sample") else() diff --git a/samples/drivers/mbox/remote/boards/lpcxpresso55s69_cpu1.conf b/samples/drivers/mbox/remote/boards/lpcxpresso55s69_cpu1.conf new file mode 100644 index 00000000000..b499f5da051 --- /dev/null +++ b/samples/drivers/mbox/remote/boards/lpcxpresso55s69_cpu1.conf @@ -0,0 +1,10 @@ +CONFIG_SECOND_CORE_MCUX=y +CONFIG_BUILD_OUTPUT_HEX=y +CONFIG_MBOX_NXP_MAILBOX=y + +# For purpose of sample enable UART Console on CPU1 +CONFIG_CONSOLE=y +CONFIG_UART_CONSOLE=y +CONFIG_SERIAL=y +CONFIG_UART_INTERRUPT_DRIVEN=y +CONFIG_CLOCK_CONTROL=y diff --git a/samples/drivers/mbox/remote/boards/lpcxpresso55s69_cpu1.overlay b/samples/drivers/mbox/remote/boards/lpcxpresso55s69_cpu1.overlay new file mode 100644 index 00000000000..36e6f0ff267 --- /dev/null +++ b/samples/drivers/mbox/remote/boards/lpcxpresso55s69_cpu1.overlay @@ -0,0 +1,43 @@ +/* + * Copyright 2024 NXP + * + * SPDX-License-Identifier: Apache-2.0 + */ + +/ { + chosen { + /* Delete ipc chosen property where old IPM mailbox driver bellow is + * configured. + */ + /delete-property/ zephyr,ipc; + zephyr,console = &flexcomm0; + zephyr,shell-uart = &flexcomm0; + }; + + soc { + /* Delete IPM Driver node nxp,lpc-mailbox */ + /delete-node/ mailbox@8b000; + + /* Attach MBOX driver to Mailbox Unit */ + mbox:mbox@5008b000 { + compatible = "nxp,mbox-mailbox"; + reg = <0x5008b000 0xEC>; + interrupts = <31 0>; + rx-channels = <4>; + #mbox-cells = <1>; + status = "okay"; + }; + }; +}; + +&flexcomm0 { + status = "okay"; +}; + +&dma0 { + status = "okay"; +}; + +&syscon { + status = "okay"; +}; diff --git a/samples/drivers/mbox/sample.yaml b/samples/drivers/mbox/sample.yaml index e8015cf7c25..d646b241e9e 100644 --- a/samples/drivers/mbox/sample.yaml +++ b/samples/drivers/mbox/sample.yaml @@ -12,6 +12,7 @@ tests: - mimxrt1170_evkb_cm7 - mimxrt1170_evk_cm7 - mimxrt1160_evk_cm7 + - lpcxpresso55s69_cpu0 integration_platforms: - nrf5340dk_nrf5340_cpuapp harness: console diff --git a/samples/drivers/mbox/sysbuild.cmake b/samples/drivers/mbox/sysbuild.cmake index 7a5d32d4c74..063f6157ddb 100644 --- a/samples/drivers/mbox/sysbuild.cmake +++ b/samples/drivers/mbox/sysbuild.cmake @@ -1,5 +1,5 @@ # Copyright (c) 2023 Nordic Semiconductor ASA -# Copyright 2023 NXP +# Copyright 2023-2024 NXP # SPDX-License-Identifier: Apache-2.0 if("${SB_CONFIG_REMOTE_BOARD}" STREQUAL "") @@ -22,7 +22,8 @@ native_simulator_set_final_executable(${DEFAULT_IMAGE}) if ("${BOARD}" STREQUAL "mimxrt1170_evkb_cm7" OR "${BOARD}" STREQUAL "mimxrt1170_evk_cm7" OR - "${BOARD}" STREQUAL "mimxrt1160_evk_cm7" + "${BOARD}" STREQUAL "mimxrt1160_evk_cm7" OR + "${BOARD}" STREQUAL "lpcxpresso55s69_cpu0" ) # For these NXP boards the main core application is dependent on # 'zephyr_image_info.h' generated by remote application. diff --git a/samples/drivers/mbox_data/CMakeLists.txt b/samples/drivers/mbox_data/CMakeLists.txt index a67552bf52e..a410ac3d214 100644 --- a/samples/drivers/mbox_data/CMakeLists.txt +++ b/samples/drivers/mbox_data/CMakeLists.txt @@ -11,7 +11,8 @@ set(REMOTE_ZEPHYR_DIR ${CMAKE_CURRENT_BINARY_DIR}/../remote/zephyr) if(("${BOARD}" STREQUAL "mimxrt1170_evkb_cm7") OR ("${BOARD}" STREQUAL "mimxrt1170_evk_cm7") OR - ("${BOARD}" STREQUAL "mimxrt1160_evk_cm7")) + ("${BOARD}" STREQUAL "mimxrt1160_evk_cm7") OR + ("${BOARD}" STREQUAL "lpcxpresso55s69_cpu0")) message(STATUS "${BOARD} compile as Main in this sample") else() message(FATAL_ERROR "${BOARD} is not supported for this sample") diff --git a/samples/drivers/mbox_data/Kconfig.sysbuild b/samples/drivers/mbox_data/Kconfig.sysbuild index e355713e714..2ddab228177 100644 --- a/samples/drivers/mbox_data/Kconfig.sysbuild +++ b/samples/drivers/mbox_data/Kconfig.sysbuild @@ -9,3 +9,4 @@ string default "mimxrt1170_evkb_cm4" if $(BOARD) = "mimxrt1170_evkb_cm7" default "mimxrt1170_evk_cm4" if $(BOARD) = "mimxrt1170_evk_cm7" default "mimxrt1160_evk_cm4" if $(BOARD) = "mimxrt1160_evk_cm7" + default "lpcxpresso55s69_cpu1" if $(BOARD) = "lpcxpresso55s69_cpu0" diff --git a/samples/drivers/mbox_data/README.rst b/samples/drivers/mbox_data/README.rst index 3ead1ec3b87..1f8b1615f8e 100644 --- a/samples/drivers/mbox_data/README.rst +++ b/samples/drivers/mbox_data/README.rst @@ -10,7 +10,7 @@ Overview This sample demonstrates how to use the :ref:`MBOX API ` in data transfer mode. It can be used only with mbox driver which supports data transfer mode. -Sample will ping-pong 4 bytes of data between two cores via two mbox channels. +Sample will ping-pong up to 4 bytes of data between two cores via two mbox channels. After each core receives data, it increments it by one and sends it back to other core. Building and Running @@ -45,6 +45,15 @@ Building the application for mimxrt1170_evkb_cm7 :goals: debug :west-args: --sysbuild +Building the application for lpcxpresso55s69_cpu1 +================================================= + +.. zephyr-app-commands:: + :zephyr-app: samples/drivers/mbox_data/ + :board: lpcxpresso55s69_cpu1 + :goals: debug + :west-args: --sysbuild + Sample Output ============= diff --git a/samples/drivers/mbox_data/boards/lpcxpresso55s69_cpu0.conf b/samples/drivers/mbox_data/boards/lpcxpresso55s69_cpu0.conf new file mode 100644 index 00000000000..5077d775881 --- /dev/null +++ b/samples/drivers/mbox_data/boards/lpcxpresso55s69_cpu0.conf @@ -0,0 +1,3 @@ +CONFIG_SECOND_CORE_MCUX=y +CONFIG_MBOX_NXP_MAILBOX=y +CONFIG_BUILD_OUTPUT_HEX=y diff --git a/samples/drivers/mbox_data/boards/lpcxpresso55s69_cpu0.overlay b/samples/drivers/mbox_data/boards/lpcxpresso55s69_cpu0.overlay new file mode 100644 index 00000000000..b5919c4fd72 --- /dev/null +++ b/samples/drivers/mbox_data/boards/lpcxpresso55s69_cpu0.overlay @@ -0,0 +1,29 @@ +/* + * Copyright 2024 NXP + * + * SPDX-License-Identifier: Apache-2.0 + */ + +/ { + chosen { + /* Delete ipc chosen property where old IPM mailbox driver bellow is + * configured. + */ + /delete-property/ zephyr,ipc; + }; + + soc { + /* Delete IPM Driver node nxp,lpc-mailbox */ + /delete-node/ mailbox@8b000; + + /* Attach MBOX driver to Mailbox Unit */ + mbox:mailbox0@5008b000 { + compatible = "nxp,mbox-mailbox"; + reg = <0x5008b000 0xEC>; + interrupts = <31 0>; + rx-channels = <4>; + #mbox-cells = <1>; + status = "okay"; + }; + }; +}; diff --git a/samples/drivers/mbox_data/remote/CMakeLists.txt b/samples/drivers/mbox_data/remote/CMakeLists.txt index 31f6db9b641..47e1cae8628 100644 --- a/samples/drivers/mbox_data/remote/CMakeLists.txt +++ b/samples/drivers/mbox_data/remote/CMakeLists.txt @@ -9,7 +9,8 @@ find_package(Zephyr REQUIRED HINTS $ENV{ZEPHYR_BASE}) if(("${BOARD}" STREQUAL "mimxrt1170_evkb_cm4") OR ("${BOARD}" STREQUAL "mimxrt1170_evk_cm4") OR - ("${BOARD}" STREQUAL "mimxrt1160_evk_cm4")) + ("${BOARD}" STREQUAL "mimxrt1160_evk_cm4") OR + ("${BOARD}" STREQUAL "lpcxpresso55s69_cpu1")) message(STATUS "${BOARD} compile as remote in this sample") else() message(FATAL_ERROR "${BOARD} is not supported for this sample") diff --git a/samples/drivers/mbox_data/remote/boards/lpcxpresso55s69_cpu1.conf b/samples/drivers/mbox_data/remote/boards/lpcxpresso55s69_cpu1.conf new file mode 100644 index 00000000000..14ed92ba8f4 --- /dev/null +++ b/samples/drivers/mbox_data/remote/boards/lpcxpresso55s69_cpu1.conf @@ -0,0 +1,3 @@ +CONFIG_SECOND_CORE_MCUX=y +CONFIG_BUILD_OUTPUT_HEX=y +CONFIG_MBOX_NXP_MAILBOX=y diff --git a/samples/drivers/mbox_data/remote/boards/lpcxpresso55s69_cpu1.overlay b/samples/drivers/mbox_data/remote/boards/lpcxpresso55s69_cpu1.overlay new file mode 100644 index 00000000000..96bd5aa1c3a --- /dev/null +++ b/samples/drivers/mbox_data/remote/boards/lpcxpresso55s69_cpu1.overlay @@ -0,0 +1,29 @@ +/* + * Copyright 2024 NXP + * + * SPDX-License-Identifier: Apache-2.0 + */ + +/ { + chosen { + /* Delete ipc chosen property where old IPM mailbox driver bellow is + * configured. + */ + /delete-property/ zephyr,ipc; + }; + + soc { + /* Delete IPM Driver node nxp,lpc-mailbox */ + /delete-node/ mailbox@8b000; + + /* Attach MBOX driver to Mailbox Unit */ + mbox:mbox@5008b000 { + compatible = "nxp,mbox-mailbox"; + reg = <0x5008b000 0xEC>; + interrupts = <31 0>; + rx-channels = <4>; + #mbox-cells = <1>; + status = "okay"; + }; + }; +}; diff --git a/samples/drivers/mbox_data/remote/src/main.c b/samples/drivers/mbox_data/remote/src/main.c index 9fccf155c23..0f3ad77a4d0 100644 --- a/samples/drivers/mbox_data/remote/src/main.c +++ b/samples/drivers/mbox_data/remote/src/main.c @@ -6,6 +6,7 @@ #include #include +#include #include #include @@ -41,6 +42,13 @@ int main(void) mbox_init_channel(&tx_channel, dev, TX_ID); mbox_init_channel(&rx_channel, dev, RX_ID); + const int max_transfer_size_bytes = mbox_mtu_get(dev); + /* Sample currently supports only transfer size up to 4 bytes */ + if ((max_transfer_size_bytes <= 0) || (max_transfer_size_bytes > 4)) { + printk("mbox_mtu_get() error\n"); + return 0; + } + if (mbox_register_callback(&rx_channel, callback, NULL)) { printk("mbox_register_callback() error\n"); return 0; @@ -61,7 +69,7 @@ int main(void) message++; msg.data = &message; - msg.size = 4; + msg.size = max_transfer_size_bytes; printk("Server send (on channel %d) value: %d\n", tx_channel.id, message); if (mbox_send(&tx_channel, &msg) < 0) { diff --git a/samples/drivers/mbox_data/sample.yaml b/samples/drivers/mbox_data/sample.yaml index 5484233b2e8..b4a1e23a9bc 100644 --- a/samples/drivers/mbox_data/sample.yaml +++ b/samples/drivers/mbox_data/sample.yaml @@ -9,8 +9,10 @@ tests: - mimxrt1170_evkb_cm7 - mimxrt1170_evk_cm7 - mimxrt1160_evk_cm7 + - lpcxpresso55s69_cpu0 integration_platforms: - mimxrt1160_evk_cm7 + - lpcxpresso55s69_cpu0 harness: console harness_config: type: multi_line diff --git a/samples/drivers/mbox_data/src/main.c b/samples/drivers/mbox_data/src/main.c index 27c29b07554..85df24940c4 100644 --- a/samples/drivers/mbox_data/src/main.c +++ b/samples/drivers/mbox_data/src/main.c @@ -6,6 +6,7 @@ #include #include +#include #include #include @@ -41,6 +42,13 @@ int main(void) mbox_init_channel(&tx_channel, dev, TX_ID); mbox_init_channel(&rx_channel, dev, RX_ID); + const int max_transfer_size_bytes = mbox_mtu_get(dev); + /* Sample currently supports only transfer size up to 4 bytes */ + if ((max_transfer_size_bytes < 0) || (max_transfer_size_bytes > 4)) { + printk("mbox_mtu_get() error\n"); + return 0; + } + if (mbox_register_callback(&rx_channel, callback, NULL)) { printk("mbox_register_callback() error\n"); return 0; @@ -53,7 +61,7 @@ int main(void) while (message < 100) { msg.data = &message; - msg.size = 4; + msg.size = max_transfer_size_bytes; printk("Client send (on channel %d) value: %d\n", tx_channel.id, message); if (mbox_send(&tx_channel, &msg) < 0) { diff --git a/tests/drivers/mbox/mbox_data/CMakeLists.txt b/tests/drivers/mbox/mbox_data/CMakeLists.txt index a67552bf52e..a410ac3d214 100644 --- a/tests/drivers/mbox/mbox_data/CMakeLists.txt +++ b/tests/drivers/mbox/mbox_data/CMakeLists.txt @@ -11,7 +11,8 @@ set(REMOTE_ZEPHYR_DIR ${CMAKE_CURRENT_BINARY_DIR}/../remote/zephyr) if(("${BOARD}" STREQUAL "mimxrt1170_evkb_cm7") OR ("${BOARD}" STREQUAL "mimxrt1170_evk_cm7") OR - ("${BOARD}" STREQUAL "mimxrt1160_evk_cm7")) + ("${BOARD}" STREQUAL "mimxrt1160_evk_cm7") OR + ("${BOARD}" STREQUAL "lpcxpresso55s69_cpu0")) message(STATUS "${BOARD} compile as Main in this sample") else() message(FATAL_ERROR "${BOARD} is not supported for this sample") diff --git a/tests/drivers/mbox/mbox_data/Kconfig.sysbuild b/tests/drivers/mbox/mbox_data/Kconfig.sysbuild index e355713e714..2ddab228177 100644 --- a/tests/drivers/mbox/mbox_data/Kconfig.sysbuild +++ b/tests/drivers/mbox/mbox_data/Kconfig.sysbuild @@ -9,3 +9,4 @@ string default "mimxrt1170_evkb_cm4" if $(BOARD) = "mimxrt1170_evkb_cm7" default "mimxrt1170_evk_cm4" if $(BOARD) = "mimxrt1170_evk_cm7" default "mimxrt1160_evk_cm4" if $(BOARD) = "mimxrt1160_evk_cm7" + default "lpcxpresso55s69_cpu1" if $(BOARD) = "lpcxpresso55s69_cpu0" diff --git a/tests/drivers/mbox/mbox_data/boards/lpcxpresso55s69_cpu0.conf b/tests/drivers/mbox/mbox_data/boards/lpcxpresso55s69_cpu0.conf new file mode 100644 index 00000000000..5077d775881 --- /dev/null +++ b/tests/drivers/mbox/mbox_data/boards/lpcxpresso55s69_cpu0.conf @@ -0,0 +1,3 @@ +CONFIG_SECOND_CORE_MCUX=y +CONFIG_MBOX_NXP_MAILBOX=y +CONFIG_BUILD_OUTPUT_HEX=y diff --git a/tests/drivers/mbox/mbox_data/boards/lpcxpresso55s69_cpu0.overlay b/tests/drivers/mbox/mbox_data/boards/lpcxpresso55s69_cpu0.overlay new file mode 100644 index 00000000000..b5919c4fd72 --- /dev/null +++ b/tests/drivers/mbox/mbox_data/boards/lpcxpresso55s69_cpu0.overlay @@ -0,0 +1,29 @@ +/* + * Copyright 2024 NXP + * + * SPDX-License-Identifier: Apache-2.0 + */ + +/ { + chosen { + /* Delete ipc chosen property where old IPM mailbox driver bellow is + * configured. + */ + /delete-property/ zephyr,ipc; + }; + + soc { + /* Delete IPM Driver node nxp,lpc-mailbox */ + /delete-node/ mailbox@8b000; + + /* Attach MBOX driver to Mailbox Unit */ + mbox:mailbox0@5008b000 { + compatible = "nxp,mbox-mailbox"; + reg = <0x5008b000 0xEC>; + interrupts = <31 0>; + rx-channels = <4>; + #mbox-cells = <1>; + status = "okay"; + }; + }; +}; diff --git a/tests/drivers/mbox/mbox_data/remote/CMakeLists.txt b/tests/drivers/mbox/mbox_data/remote/CMakeLists.txt index 31f6db9b641..47e1cae8628 100644 --- a/tests/drivers/mbox/mbox_data/remote/CMakeLists.txt +++ b/tests/drivers/mbox/mbox_data/remote/CMakeLists.txt @@ -9,7 +9,8 @@ find_package(Zephyr REQUIRED HINTS $ENV{ZEPHYR_BASE}) if(("${BOARD}" STREQUAL "mimxrt1170_evkb_cm4") OR ("${BOARD}" STREQUAL "mimxrt1170_evk_cm4") OR - ("${BOARD}" STREQUAL "mimxrt1160_evk_cm4")) + ("${BOARD}" STREQUAL "mimxrt1160_evk_cm4") OR + ("${BOARD}" STREQUAL "lpcxpresso55s69_cpu1")) message(STATUS "${BOARD} compile as remote in this sample") else() message(FATAL_ERROR "${BOARD} is not supported for this sample") diff --git a/tests/drivers/mbox/mbox_data/remote/boards/lpcxpresso55s69_cpu1.conf b/tests/drivers/mbox/mbox_data/remote/boards/lpcxpresso55s69_cpu1.conf new file mode 100644 index 00000000000..14ed92ba8f4 --- /dev/null +++ b/tests/drivers/mbox/mbox_data/remote/boards/lpcxpresso55s69_cpu1.conf @@ -0,0 +1,3 @@ +CONFIG_SECOND_CORE_MCUX=y +CONFIG_BUILD_OUTPUT_HEX=y +CONFIG_MBOX_NXP_MAILBOX=y diff --git a/tests/drivers/mbox/mbox_data/remote/boards/lpcxpresso55s69_cpu1.overlay b/tests/drivers/mbox/mbox_data/remote/boards/lpcxpresso55s69_cpu1.overlay new file mode 100644 index 00000000000..96bd5aa1c3a --- /dev/null +++ b/tests/drivers/mbox/mbox_data/remote/boards/lpcxpresso55s69_cpu1.overlay @@ -0,0 +1,29 @@ +/* + * Copyright 2024 NXP + * + * SPDX-License-Identifier: Apache-2.0 + */ + +/ { + chosen { + /* Delete ipc chosen property where old IPM mailbox driver bellow is + * configured. + */ + /delete-property/ zephyr,ipc; + }; + + soc { + /* Delete IPM Driver node nxp,lpc-mailbox */ + /delete-node/ mailbox@8b000; + + /* Attach MBOX driver to Mailbox Unit */ + mbox:mbox@5008b000 { + compatible = "nxp,mbox-mailbox"; + reg = <0x5008b000 0xEC>; + interrupts = <31 0>; + rx-channels = <4>; + #mbox-cells = <1>; + status = "okay"; + }; + }; +}; diff --git a/tests/drivers/mbox/mbox_data/remote/src/main.c b/tests/drivers/mbox/mbox_data/remote/src/main.c index 7bbc1c2efd0..d9eba4d3b7c 100644 --- a/tests/drivers/mbox/mbox_data/remote/src/main.c +++ b/tests/drivers/mbox/mbox_data/remote/src/main.c @@ -6,6 +6,7 @@ #include #include +#include #include #include @@ -50,6 +51,13 @@ int main(void) dev = DEVICE_DT_GET(DT_NODELABEL(mbox)); + const int max_transfer_size_bytes = mbox_mtu_get(dev); + /* Sample currently supports only transfer size up to 4 bytes */ + if ((max_transfer_size_bytes <= 0) || (max_transfer_size_bytes > 4)) { + printk("mbox_mtu_get() error\n"); + return 0; + } + for (int i_test_channel = 0; i_test_channel < CHANNELS_TO_TEST; i_test_channel++) { mbox_init_channel(&tx_channel, dev, TEST_CHANNELS[i_test_channel][TX_CHANNEL_INDEX]); @@ -77,7 +85,7 @@ int main(void) message++; msg.data = &message; - msg.size = 4; + msg.size = max_transfer_size_bytes; if (mbox_send(&tx_channel, &msg) < 0) { printk("mbox_send() error\n"); diff --git a/tests/drivers/mbox/mbox_data/src/main.c b/tests/drivers/mbox/mbox_data/src/main.c index 1cdfb0ca43e..82cce00ae7f 100644 --- a/tests/drivers/mbox/mbox_data/src/main.c +++ b/tests/drivers/mbox/mbox_data/src/main.c @@ -6,6 +6,7 @@ #include #include +#include #include #include @@ -20,6 +21,7 @@ static uint32_t g_mbox_expected_channel; static bool g_received_size_error; static size_t g_received_size; +static int g_max_transfer_size_bytes; static struct mbox_channel g_tx_channel; static struct mbox_channel g_rx_channel; @@ -65,6 +67,14 @@ static void mbox_data_tests_before(void *f) dev = DEVICE_DT_GET(DT_NODELABEL(mbox)); + g_max_transfer_size_bytes = mbox_mtu_get(dev); + /* Test currently supports only transfer size up to 4 bytes */ + if ((g_max_transfer_size_bytes < 0) || (g_max_transfer_size_bytes > 4)) { + printk("mbox_mtu_get() error\n"); + zassert_false(1, "mbox invalid maximum transfer unit: %d", + g_max_transfer_size_bytes); + } + mbox_init_channel(&g_tx_channel, dev, TEST_CHANNELS[current_channel_index][TX_CHANNEL_INDEX]); mbox_init_channel(&g_rx_channel, dev, @@ -98,14 +108,17 @@ static void mbox_test(const uint32_t data) while (test_count < 100) { /* Main core prepare test data */ msg.data = &test_data; - msg.size = 4; + msg.size = g_max_transfer_size_bytes; /* Main core send test data */ ret_val = mbox_send(&g_tx_channel, &msg); zassert_false(ret_val < 0, "mbox failed to send. ret_val: %d", ret_val); - /* Expect next received data will be incremented by one */ - g_mbox_expected_data = test_data; + /* Expect next received data will be incremented by one. + * And based on Maximum Transfer Unit determine expected data. + * Currently supported MTU's are 1, 2, 3, and 4 bytes. + */ + g_mbox_expected_data = test_data & ~(0xFFFFFFFF << (g_max_transfer_size_bytes * 8)); g_mbox_expected_data++; k_sem_take(&g_mbox_data_rx_sem, K_FOREVER); diff --git a/tests/drivers/mbox/mbox_data/testcase.yaml b/tests/drivers/mbox/mbox_data/testcase.yaml index d4890ff7c55..72aff63ac3a 100644 --- a/tests/drivers/mbox/mbox_data/testcase.yaml +++ b/tests/drivers/mbox/mbox_data/testcase.yaml @@ -8,5 +8,7 @@ tests: - mimxrt1170_evkb_cm7 - mimxrt1170_evk_cm7 - mimxrt1160_evk_cm7 + - lpcxpresso55s69_cpu0 integration_platforms: - mimxrt1170_evkb_cm7 + - lpcxpresso55s69_cpu0 diff --git a/west.yml b/west.yml index 065c2b617b1..0f130ef20d5 100644 --- a/west.yml +++ b/west.yml @@ -193,7 +193,7 @@ manifest: groups: - hal - name: hal_nxp - revision: ae438701d6029f4f989fe036abe4b91be51e6258 + revision: 0463d6aa0de62761fb9ae56e3521c61b0e490374 path: modules/hal/nxp groups: - hal From ad89bf377dc063b81bf9f4b88c6b14fa0c2e15e7 Mon Sep 17 00:00:00 2001 From: Mateusz Holenko Date: Mon, 29 Jan 2024 13:41:44 +0100 Subject: [PATCH 3386/3723] boards: arm: Enable mailbox in selected ARM boards MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The mailbox peripheral is actively accessed by stm32_hsem functions, so mark the device as enabled in DTS. Signed-off-by: Mateusz Hołenko --- boards/arm/arduino_giga_r1/arduino_giga_r1.dtsi | 4 ++++ boards/arm/nucleo_h745zi_q/nucleo_h745zi_q.dtsi | 4 ++++ boards/arm/stm32h747i_disco/stm32h747i_disco.dtsi | 4 ++++ 3 files changed, 12 insertions(+) diff --git a/boards/arm/arduino_giga_r1/arduino_giga_r1.dtsi b/boards/arm/arduino_giga_r1/arduino_giga_r1.dtsi index ee7eb1229fc..d0e8863967e 100644 --- a/boards/arm/arduino_giga_r1/arduino_giga_r1.dtsi +++ b/boards/arm/arduino_giga_r1/arduino_giga_r1.dtsi @@ -38,3 +38,7 @@ d2ppre2 = <2>; d3ppre = <2>; }; + +&mailbox { + status = "okay"; +}; diff --git a/boards/arm/nucleo_h745zi_q/nucleo_h745zi_q.dtsi b/boards/arm/nucleo_h745zi_q/nucleo_h745zi_q.dtsi index 93d42155499..b9a0407bf47 100644 --- a/boards/arm/nucleo_h745zi_q/nucleo_h745zi_q.dtsi +++ b/boards/arm/nucleo_h745zi_q/nucleo_h745zi_q.dtsi @@ -39,3 +39,7 @@ d2ppre2 = <2>; d3ppre = <2>; }; + +&mailbox { + status = "okay"; +}; diff --git a/boards/arm/stm32h747i_disco/stm32h747i_disco.dtsi b/boards/arm/stm32h747i_disco/stm32h747i_disco.dtsi index fb620065c34..f27b2503873 100644 --- a/boards/arm/stm32h747i_disco/stm32h747i_disco.dtsi +++ b/boards/arm/stm32h747i_disco/stm32h747i_disco.dtsi @@ -118,3 +118,7 @@ &spi5_miso_pj11 &spi5_mosi_pj10>; pinctrl-names = "default"; }; + +&mailbox { + status = "okay"; +}; From 922ac3c7c1ca8843c3e2c64c4252e3edb2c2517f Mon Sep 17 00:00:00 2001 From: Emil Gydesen Date: Mon, 15 Jan 2024 17:49:10 +0100 Subject: [PATCH 3387/3723] Bluetooth: Audio: Add missing error checks for calls to bt_gatt_subscribe Several places the LE Audio clients called bt_gatt_subscribe without checking the return value, which could cause some issues in the worst case, and in the best case, cause some unexpected behavior. Some implementations had a bit more updating to handle the new behavior. Signed-off-by: Emil Gydesen --- subsys/bluetooth/audio/aics_client.c | 13 +++++++- subsys/bluetooth/audio/bap_unicast_client.c | 32 +++++++++++-------- subsys/bluetooth/audio/csip_set_coordinator.c | 16 ++++++++-- subsys/bluetooth/audio/mcc.c | 8 ++++- subsys/bluetooth/audio/micp_mic_ctlr.c | 4 +++ subsys/bluetooth/audio/tbs_client.c | 3 ++ subsys/bluetooth/audio/vcp_vol_ctlr.c | 7 ++-- .../audio/src/csip_notify_client_test.c | 2 +- 8 files changed, 65 insertions(+), 20 deletions(-) diff --git a/subsys/bluetooth/audio/aics_client.c b/subsys/bluetooth/audio/aics_client.c index 3f160ed0d13..412bdbcb741 100644 --- a/subsys/bluetooth/audio/aics_client.c +++ b/subsys/bluetooth/audio/aics_client.c @@ -608,6 +608,8 @@ static uint8_t aics_discover_func(struct bt_conn *conn, const struct bt_gatt_att } if (sub_params) { + int err; + sub_params->value = BT_GATT_CCC_NOTIFY; sub_params->value_handle = chrc->value_handle; /* @@ -616,7 +618,16 @@ static uint8_t aics_discover_func(struct bt_conn *conn, const struct bt_gatt_att */ sub_params->ccc_handle = attr->handle + 2; sub_params->notify = aics_client_notify_handler; - bt_gatt_subscribe(conn, sub_params); + err = bt_gatt_subscribe(conn, sub_params); + if (err != 0 && err != -EALREADY) { + LOG_ERR("Failed to subscribe: %d", err); + + if (inst->cli.cb && inst->cli.cb->discover) { + inst->cli.cb->discover(inst, err); + } + + return BT_GATT_ITER_STOP; + } } } diff --git a/subsys/bluetooth/audio/bap_unicast_client.c b/subsys/bluetooth/audio/bap_unicast_client.c index 13adf0421a4..e27725ec2c5 100644 --- a/subsys/bluetooth/audio/bap_unicast_client.c +++ b/subsys/bluetooth/audio/bap_unicast_client.c @@ -1721,7 +1721,7 @@ static void unicast_client_ep_set_cp(struct bt_conn *conn, uint16_t handle) if (err != 0) { LOG_DBG("Failed to subscribe: %d", err); - discover_cb(conn, BT_ATT_ERR_UNLIKELY); + discover_cb(conn, err); return; } @@ -3229,10 +3229,12 @@ static uint8_t unicast_client_ase_read_func(struct bt_conn *conn, uint8_t err, struct unicast_client *client; struct net_buf_simple *buf; struct bt_bap_ep *ep; + int cb_err; LOG_DBG("conn %p err 0x%02x len %u", conn, err, length); if (err) { + cb_err = err; goto fail; } @@ -3246,7 +3248,7 @@ static uint8_t unicast_client_ase_read_func(struct bt_conn *conn, uint8_t err, LOG_DBG("Buffer full, invalid server response of size %u", length + client->net_buf.len); - err = BT_ATT_ERR_INVALID_ATTRIBUTE_LEN; + cb_err = BT_ATT_ERR_INVALID_ATTRIBUTE_LEN; goto fail; } @@ -3262,7 +3264,7 @@ static uint8_t unicast_client_ase_read_func(struct bt_conn *conn, uint8_t err, if (buf->len < sizeof(struct bt_ascs_ase_status)) { LOG_DBG("Read response too small (%u)", buf->len); - err = BT_ATT_ERR_INVALID_ATTRIBUTE_LEN; + cb_err = BT_ATT_ERR_INVALID_ATTRIBUTE_LEN; goto fail; } @@ -3274,28 +3276,32 @@ static uint8_t unicast_client_ase_read_func(struct bt_conn *conn, uint8_t err, * consider the discovery procedure as failing. */ LOG_WRN("No space left to parse ASE"); - err = -ENOMEM; + cb_err = -ENOMEM; goto fail; } unicast_client_ep_set_status(ep, buf); - unicast_client_ep_subscribe(conn, ep); + cb_err = unicast_client_ep_subscribe(conn, ep); + if (cb_err != 0) { + LOG_DBG("Failed to subcribe to ep %p: %d", ep, cb_err); + goto fail; + } + reset_att_buf(client); endpoint_cb(conn, ep); - err = unicast_client_ase_discover(conn, handle); - if (err != 0) { - LOG_DBG("Failed to read ASE: %d", err); - - discover_cb(conn, err); + cb_err = unicast_client_ase_discover(conn, handle); + if (cb_err != 0) { + LOG_DBG("Failed to read ASE: %d", cb_err); + goto fail; } return BT_GATT_ITER_STOP; fail: - discover_cb(conn, err); + discover_cb(conn, cb_err); return BT_GATT_ITER_STOP; } @@ -3313,7 +3319,7 @@ static uint8_t unicast_client_ase_discover_cb(struct bt_conn *conn, if (err != 0) { LOG_ERR("Unable to discover ASE Control Point"); - discover_cb(conn, BT_ATT_ERR_UNLIKELY); + discover_cb(conn, err); } return BT_GATT_ITER_STOP; @@ -3404,7 +3410,7 @@ static uint8_t unicast_client_pacs_avail_ctx_read_func(struct bt_conn *conn, uin if (cb_err != 0) { LOG_ERR("Unable to read ASE: %d", cb_err); - discover_cb(conn, err); + discover_cb(conn, cb_err); } return BT_GATT_ITER_STOP; diff --git a/subsys/bluetooth/audio/csip_set_coordinator.c b/subsys/bluetooth/audio/csip_set_coordinator.c index 36e5803b45c..4c5faefd13a 100644 --- a/subsys/bluetooth/audio/csip_set_coordinator.c +++ b/subsys/bluetooth/audio/csip_set_coordinator.c @@ -740,12 +740,21 @@ static uint8_t discover_func(struct bt_conn *conn, } if (sub_params->value != 0) { + int err; + /* With ccc_handle == 0 it will use auto discovery */ sub_params->ccc_handle = 0; sub_params->end_handle = cur_inst->end_handle; sub_params->value_handle = chrc->value_handle; sub_params->notify = notify_handler; - bt_gatt_subscribe(conn, sub_params); + + err = bt_gatt_subscribe(conn, sub_params); + if (err != 0 && err != -EALREADY) { + LOG_DBG("Failed to subscribe (err %d)", err); + discover_complete(client, err); + + return BT_GATT_ITER_STOP; + } } } } @@ -1315,6 +1324,9 @@ static int csip_set_coordinator_read_set_lock(struct bt_csip_set_coordinator_svc static void csip_set_coordinator_reset(struct bt_csip_set_coordinator_inst *inst) { + inst->inst_count = 0U; + memset(&inst->set_member, 0, sizeof(inst->set_member)); + for (size_t i = 0; i < ARRAY_SIZE(inst->svc_insts); i++) { struct bt_csip_set_coordinator_svc_inst *svc_inst = &inst->svc_insts[i]; @@ -1433,7 +1445,7 @@ int bt_csip_set_coordinator_discover(struct bt_conn *conn) client = &client_insts[bt_conn_index(conn)]; - (void)memset(client, 0, sizeof(*client)); + csip_set_coordinator_reset(client); /* Discover CSIS on peer, setup handles and notify */ (void)memset(&discover_params, 0, sizeof(discover_params)); diff --git a/subsys/bluetooth/audio/mcc.c b/subsys/bluetooth/audio/mcc.c index 4a763bc0d3e..909ce19a3cb 100644 --- a/subsys/bluetooth/audio/mcc.c +++ b/subsys/bluetooth/audio/mcc.c @@ -1297,7 +1297,13 @@ static uint8_t discover_otc_char_func(struct bt_conn *conn, sub_params->value_handle = chrc->value_handle; sub_params->notify = bt_ots_client_indicate_handler; - bt_gatt_subscribe(conn, sub_params); + err = bt_gatt_subscribe(conn, sub_params); + if (err != 0) { + LOG_DBG("Failed to subscribe (err %d)", err); + discovery_complete(conn, err); + + return BT_GATT_ITER_STOP; + } } return BT_GATT_ITER_CONTINUE; diff --git a/subsys/bluetooth/audio/micp_mic_ctlr.c b/subsys/bluetooth/audio/micp_mic_ctlr.c index 71cec1ef9b6..974c1ba8124 100644 --- a/subsys/bluetooth/audio/micp_mic_ctlr.c +++ b/subsys/bluetooth/audio/micp_mic_ctlr.c @@ -416,6 +416,10 @@ static uint8_t micp_discover_func(struct bt_conn *conn, } else { LOG_DBG("Could not subscribe to handle 0x%04X: %d", attr->handle, err); + + micp_mic_ctlr_discover_complete(mic_ctlr, err); + + return BT_GATT_ITER_STOP; } } } diff --git a/subsys/bluetooth/audio/tbs_client.c b/subsys/bluetooth/audio/tbs_client.c index 475544f7b20..9ef759c3c1e 100644 --- a/subsys/bluetooth/audio/tbs_client.c +++ b/subsys/bluetooth/audio/tbs_client.c @@ -1545,6 +1545,9 @@ static uint8_t discover_func(struct bt_conn *conn, "characterstic at handle 0x%04X" "(%d)", sub_params->value_handle, err); + tbs_client_discover_complete(conn, err); + + return BT_GATT_ITER_STOP; } else { LOG_DBG("Subscribed to characterstic at " "handle 0x%04X", diff --git a/subsys/bluetooth/audio/vcp_vol_ctlr.c b/subsys/bluetooth/audio/vcp_vol_ctlr.c index 4cc2af2762d..6f41f61ec90 100644 --- a/subsys/bluetooth/audio/vcp_vol_ctlr.c +++ b/subsys/bluetooth/audio/vcp_vol_ctlr.c @@ -454,8 +454,11 @@ static uint8_t vcs_discover_func(struct bt_conn *conn, LOG_DBG("Subscribed to handle 0x%04X", attr->handle); } else { - LOG_DBG("Could not subscribe to handle 0x%04X", - attr->handle); + LOG_DBG("Could not subscribe to handle 0x%04X (%d)", attr->handle, + err); + vcp_vol_ctlr_discover_complete(vol_ctlr, err); + + return BT_GATT_ITER_STOP; } } } diff --git a/tests/bsim/bluetooth/audio/src/csip_notify_client_test.c b/tests/bsim/bluetooth/audio/src/csip_notify_client_test.c index 2ccad4046ba..088477888da 100644 --- a/tests/bsim/bluetooth/audio/src/csip_notify_client_test.c +++ b/tests/bsim/bluetooth/audio/src/csip_notify_client_test.c @@ -21,7 +21,7 @@ static void csip_discover_cb(struct bt_conn *conn, int err, size_t set_count) { if (err != 0) { - printk("CSIP Lock Discover failed (err = %d)\n", err); + FAIL("CSIP Lock Discover failed (err = %d)\n", err); return; } From ec41dd9ba6eb9e0bf323e1eedac276408c7dd660 Mon Sep 17 00:00:00 2001 From: Emil Gydesen Date: Tue, 16 Jan 2024 11:23:24 +0100 Subject: [PATCH 3388/3723] Bluetooth: Audio: Use BT_GATT_SUBSCRIBE_FLAG_VOLATILE The LE Audio implementations do not really support bonding yet, and removing subs on disconnect is the most effective (and correct) way of ensuring that we do not subscribe more than once when we re-discover after reconnection. The broadcast assistant and the media control client does not support multiple connections as of this commit, so they needed special treatment. In the case that we do discovery on multiple ACL connections, it is important that the existing subscriptions are removed correctly by calling bt_gatt_unsubscribe. In order to implement this change properly on some of the clients, thet had no proper connection references or support for clearing the data on disconnects, they had to be updated as well. The csip_notify.sh test has been disabled, as that expected a notification in the client, but since this commit removes that (until bonding is properly supported in the clients), then the test will fail. Signed-off-by: Emil Gydesen --- subsys/bluetooth/audio/aics_client.c | 14 +- .../bluetooth/audio/bap_broadcast_assistant.c | 72 ++++-- subsys/bluetooth/audio/bap_unicast_client.c | 12 +- subsys/bluetooth/audio/csip_set_coordinator.c | 15 +- subsys/bluetooth/audio/has_client.c | 27 +- subsys/bluetooth/audio/mcc.c | 237 ++++++++++++++---- subsys/bluetooth/audio/mcc_internal.h | 1 + subsys/bluetooth/audio/micp_mic_ctlr.c | 11 +- subsys/bluetooth/audio/tbs_client.c | 3 +- subsys/bluetooth/audio/vcp_vol_ctlr.c | 13 +- subsys/bluetooth/audio/vocs_client.c | 18 +- .../audio/src/bap_broadcast_assistant_test.c | 10 + .../bluetooth/audio/src/vcp_vol_ctlr_test.c | 10 + .../{csip_notify.sh => _csip_notify.sh} | 0 14 files changed, 323 insertions(+), 120 deletions(-) rename tests/bsim/bluetooth/audio/test_scripts/{csip_notify.sh => _csip_notify.sh} (100%) diff --git a/subsys/bluetooth/audio/aics_client.c b/subsys/bluetooth/audio/aics_client.c index 412bdbcb741..943f6475a38 100644 --- a/subsys/bluetooth/audio/aics_client.c +++ b/subsys/bluetooth/audio/aics_client.c @@ -618,6 +618,8 @@ static uint8_t aics_discover_func(struct bt_conn *conn, const struct bt_gatt_att */ sub_params->ccc_handle = attr->handle + 2; sub_params->notify = aics_client_notify_handler; + atomic_set_bit(sub_params->flags, BT_GATT_SUBSCRIBE_FLAG_VOLATILE); + err = bt_gatt_subscribe(conn, sub_params); if (err != 0 && err != -EALREADY) { LOG_ERR("Failed to subscribe: %d", err); @@ -651,16 +653,6 @@ static void aics_client_reset(struct bt_aics *inst) if (inst->cli.conn != NULL) { struct bt_conn *conn = inst->cli.conn; - /* It's okay if these fail. In case of disconnect, we can't - * unsubscribe and they will just fail. - * In case that we reset due to another call of the discover - * function, we will unsubscribe (regardless of bonding state) - * to accommodate the new discovery values. - */ - (void)bt_gatt_unsubscribe(conn, &inst->cli.state_sub_params); - (void)bt_gatt_unsubscribe(conn, &inst->cli.status_sub_params); - (void)bt_gatt_unsubscribe(conn, &inst->cli.desc_sub_params); - bt_conn_unref(conn); inst->cli.conn = NULL; } @@ -711,7 +703,6 @@ int bt_aics_discover(struct bt_conn *conn, struct bt_aics *inst, (void)memset(&inst->cli.discover_params, 0, sizeof(inst->cli.discover_params)); - inst->cli.conn = bt_conn_ref(conn); inst->cli.discover_params.start_handle = param->start_handle; inst->cli.discover_params.end_handle = param->end_handle; inst->cli.discover_params.type = BT_GATT_DISCOVER_CHARACTERISTIC; @@ -722,6 +713,7 @@ int bt_aics_discover(struct bt_conn *conn, struct bt_aics *inst, LOG_DBG("Discover failed (err %d)", err); } else { inst->cli.busy = true; + inst->cli.conn = bt_conn_ref(conn); } return err; diff --git a/subsys/bluetooth/audio/bap_broadcast_assistant.c b/subsys/bluetooth/audio/bap_broadcast_assistant.c index c96462db8ab..b2047998ce8 100644 --- a/subsys/bluetooth/audio/bap_broadcast_assistant.c +++ b/subsys/bluetooth/audio/bap_broadcast_assistant.c @@ -35,7 +35,7 @@ LOG_MODULE_REGISTER(bt_bap_broadcast_assistant, CONFIG_BT_BAP_BROADCAST_ASSISTAN #define MINIMUM_RECV_STATE_LEN 15 struct bap_broadcast_assistant_instance { - bool discovering; + struct bt_conn *conn; bool scanning; uint8_t pa_sync; uint8_t recv_state_cnt; @@ -61,7 +61,6 @@ struct bap_broadcast_assistant_instance { struct bt_gatt_discover_params disc_params; struct k_work_delayable bap_read_work; - struct bt_conn *conn; uint16_t long_read_handle; }; @@ -431,8 +430,8 @@ static uint8_t read_recv_state_cb(struct bt_conn *conn, uint8_t err, if (cb_err != 0) { LOG_DBG("err: %d", cb_err); - if (broadcast_assistant.discovering) { - broadcast_assistant.discovering = false; + if (broadcast_assistant.busy) { + broadcast_assistant.busy = false; if (broadcast_assistant_cbs != NULL && broadcast_assistant_cbs->discover != NULL) { broadcast_assistant_cbs->discover(conn, @@ -447,8 +446,8 @@ static uint8_t read_recv_state_cb(struct bt_conn *conn, uint8_t err, } } } else if (handle == last_handle) { - if (broadcast_assistant.discovering) { - broadcast_assistant.discovering = false; + if (broadcast_assistant.busy) { + broadcast_assistant.busy = false; if (broadcast_assistant_cbs != NULL && broadcast_assistant_cbs->discover != NULL) { broadcast_assistant_cbs->discover( @@ -486,8 +485,6 @@ static uint8_t read_recv_state_cb(struct bt_conn *conn, uint8_t err, static void discover_init(void) { - (void)memset(&broadcast_assistant, 0, sizeof(broadcast_assistant)); - k_work_init_delayable(&broadcast_assistant.bap_read_work, delayed_bap_read_handler); net_buf_simple_reset(&att_buf); @@ -512,7 +509,7 @@ static uint8_t char_discover_func(struct bt_conn *conn, err = bt_bap_broadcast_assistant_read_recv_state(conn, 0); if (err != 0) { - broadcast_assistant.discovering = false; + broadcast_assistant.busy = false; if (broadcast_assistant_cbs != NULL && broadcast_assistant_cbs->discover != NULL) { broadcast_assistant_cbs->discover(conn, err, 0); @@ -552,13 +549,14 @@ static uint8_t char_discover_func(struct bt_conn *conn, sub_params->value = BT_GATT_CCC_NOTIFY; sub_params->value_handle = attr->handle + 1; sub_params->notify = notify_handler; - err = bt_gatt_subscribe(conn, sub_params); + atomic_set_bit(sub_params->flags, BT_GATT_SUBSCRIBE_FLAG_VOLATILE); - if (err != 0 && err != -EALREADY) { + err = bt_gatt_subscribe(conn, sub_params); + if (err != 0) { LOG_DBG("Could not subscribe to handle 0x%04x: %d", sub_params->value_handle, err); - broadcast_assistant.discovering = false; + broadcast_assistant.busy = false; if (broadcast_assistant_cbs != NULL && broadcast_assistant_cbs->discover != NULL) { broadcast_assistant_cbs->discover(conn, @@ -585,7 +583,7 @@ static uint8_t service_discover_func(struct bt_conn *conn, LOG_DBG("Could not discover BASS"); (void)memset(params, 0, sizeof(*params)); - broadcast_assistant.discovering = false; + broadcast_assistant.busy = false; if (broadcast_assistant_cbs != NULL && broadcast_assistant_cbs->discover != NULL) { @@ -612,7 +610,7 @@ static uint8_t service_discover_func(struct bt_conn *conn, err = bt_gatt_discover(conn, &broadcast_assistant.disc_params); if (err != 0) { LOG_DBG("Discover failed (err %d)", err); - broadcast_assistant.discovering = false; + broadcast_assistant.busy = false; if (broadcast_assistant_cbs != NULL && broadcast_assistant_cbs->discover != NULL) { @@ -759,16 +757,56 @@ static struct bt_le_scan_cb scan_cb = { static int broadcast_assistant_reset(struct bap_broadcast_assistant_instance *inst) { - broadcast_assistant.long_read_handle = 0; - (void)k_work_cancel_delayable(&broadcast_assistant.bap_read_work); + inst->busy = false; + inst->scanning = false; + inst->pa_sync = 0U; + inst->recv_state_cnt = 0U; + inst->start_handle = 0U; + inst->end_handle = 0U; + inst->cp_handle = 0U; + inst->long_read_handle = 0; + (void)k_work_cancel_delayable(&inst->bap_read_work); + + for (int i = 0U; i < CONFIG_BT_BAP_BROADCAST_ASSISTANT_RECV_STATE_COUNT; i++) { + inst->src_ids[i] = 0U; + inst->past_avail[i] = false; + inst->recv_state_handles[i] = 0U; + } if (inst->conn != NULL) { struct bt_conn *conn = inst->conn; + struct bt_conn_info info; + int err; + + err = bt_conn_get_info(conn, &info); + if (err != 0) { + return err; + } + + if (info.state == BT_CONN_STATE_CONNECTED) { + for (size_t i = 0U; i < ARRAY_SIZE(inst->recv_state_sub_params); i++) { + /* It's okay if this fail with -EINVAL as that means that they are + * not currently subscribed + */ + err = bt_gatt_unsubscribe(conn, &inst->recv_state_sub_params[i]); + if (err != 0 && err != -EINVAL) { + LOG_DBG("Failed to unsubscribe to state: %d", err); + + return err; + } + } + } bt_conn_unref(conn); inst->conn = NULL; } + /* The subscribe parameters must remain instact so they can get cleaned up by GATT */ + memset(&inst->disc_params, 0, sizeof(inst->disc_params)); + memset(&inst->recv_state_disc_params, 0, sizeof(inst->recv_state_disc_params)); + memset(&inst->read_params, 0, sizeof(inst->read_params)); + memset(&inst->write_params, 0, sizeof(inst->write_params)); + return 0; } @@ -817,7 +855,7 @@ int bt_bap_broadcast_assistant_discover(struct bt_conn *conn) return err; } - broadcast_assistant.discovering = true; + broadcast_assistant.busy = true; broadcast_assistant.conn = bt_conn_ref(conn); return 0; diff --git a/subsys/bluetooth/audio/bap_unicast_client.c b/subsys/bluetooth/audio/bap_unicast_client.c index e27725ec2c5..14e89b4da60 100644 --- a/subsys/bluetooth/audio/bap_unicast_client.c +++ b/subsys/bluetooth/audio/bap_unicast_client.c @@ -1611,6 +1611,7 @@ static uint8_t unicast_client_ep_notify(struct bt_conn *conn, static int unicast_client_ep_subscribe(struct bt_conn *conn, struct bt_bap_ep *ep) { struct bt_bap_unicast_client_ep *client_ep; + int err; client_ep = CONTAINER_OF(ep, struct bt_bap_unicast_client_ep, ep); @@ -1628,7 +1629,12 @@ static int unicast_client_ep_subscribe(struct bt_conn *conn, struct bt_bap_ep *e client_ep->subscribe.value = BT_GATT_CCC_NOTIFY; atomic_set_bit(client_ep->subscribe.flags, BT_GATT_SUBSCRIBE_FLAG_VOLATILE); - return bt_gatt_subscribe(conn, &client_ep->subscribe); + err = bt_gatt_subscribe(conn, &client_ep->subscribe); + if (err != 0 && err != -EALREADY) { + return err; + } + + return 0; } static void pac_record_cb(struct bt_conn *conn, const struct bt_audio_codec_cap *codec_cap) @@ -1718,7 +1724,7 @@ static void unicast_client_ep_set_cp(struct bt_conn *conn, uint16_t handle) atomic_set_bit(client->cp_subscribe.flags, BT_GATT_SUBSCRIBE_FLAG_VOLATILE); err = bt_gatt_subscribe(conn, &client->cp_subscribe); - if (err != 0) { + if (err != 0 && err != -EALREADY) { LOG_DBG("Failed to subscribe: %d", err); discover_cb(conn, err); @@ -3510,6 +3516,7 @@ static uint8_t unicast_client_pacs_avail_ctx_discover_cb(struct bt_conn *conn, sub_params->disc_params = &uni_cli_insts[index].avail_ctx_cc_disc; sub_params->notify = unicast_client_pacs_avail_ctx_notify_cb; sub_params->value = BT_GATT_CCC_NOTIFY; + atomic_set_bit(sub_params->flags, BT_GATT_SUBSCRIBE_FLAG_VOLATILE); err = bt_gatt_subscribe(conn, sub_params); if (err != 0 && err != -EALREADY) { @@ -3708,6 +3715,7 @@ static uint8_t unicast_client_pacs_location_discover_cb(struct bt_conn *conn, sub_params->disc_params = &uni_cli_insts[index].loc_cc_disc; sub_params->notify = unicast_client_pacs_location_notify_cb; sub_params->value = BT_GATT_CCC_NOTIFY; + atomic_set_bit(sub_params->flags, BT_GATT_SUBSCRIBE_FLAG_VOLATILE); err = bt_gatt_subscribe(conn, sub_params); if (err != 0 && err != -EALREADY) { diff --git a/subsys/bluetooth/audio/csip_set_coordinator.c b/subsys/bluetooth/audio/csip_set_coordinator.c index 4c5faefd13a..e0fdb8a6084 100644 --- a/subsys/bluetooth/audio/csip_set_coordinator.c +++ b/subsys/bluetooth/audio/csip_set_coordinator.c @@ -747,6 +747,7 @@ static uint8_t discover_func(struct bt_conn *conn, sub_params->end_handle = cur_inst->end_handle; sub_params->value_handle = chrc->value_handle; sub_params->notify = notify_handler; + atomic_set_bit(sub_params->flags, BT_GATT_SUBSCRIBE_FLAG_VOLATILE); err = bt_gatt_subscribe(conn, sub_params); if (err != 0 && err != -EALREADY) { @@ -1342,20 +1343,6 @@ static void csip_set_coordinator_reset(struct bt_csip_set_coordinator_inst *inst if (svc_inst->conn != NULL) { struct bt_conn *conn = svc_inst->conn; - /* It's okay if these fail. In case of disconnect, - * we can't unsubscribe and they will just fail. - * In case that we reset due to another call of the - * discover function, we will unsubscribe (regardless of - * bonding state) to accommodate the new discovery - * values. - */ - (void)bt_gatt_unsubscribe(conn, - &svc_inst->sirk_sub_params); - (void)bt_gatt_unsubscribe(conn, - &svc_inst->size_sub_params); - (void)bt_gatt_unsubscribe(conn, - &svc_inst->lock_sub_params); - bt_conn_unref(conn); svc_inst->conn = NULL; } diff --git a/subsys/bluetooth/audio/has_client.c b/subsys/bluetooth/audio/has_client.c index 437fa425e21..9ac33139a96 100644 --- a/subsys/bluetooth/audio/has_client.c +++ b/subsys/bluetooth/audio/has_client.c @@ -425,6 +425,8 @@ static void active_index_subscribe_cb(struct bt_conn *conn, uint8_t att_err, static int active_index_subscribe(struct bt_has_client *inst, uint16_t value_handle) { + int err; + LOG_DBG("conn %p handle 0x%04x", (void *)inst->conn, value_handle); inst->active_index_subscription.notify = active_preset_notify_cb; @@ -436,7 +438,12 @@ static int active_index_subscribe(struct bt_has_client *inst, uint16_t value_han inst->active_index_subscription.value = BT_GATT_CCC_NOTIFY; atomic_set_bit(inst->active_index_subscription.flags, BT_GATT_SUBSCRIBE_FLAG_VOLATILE); - return bt_gatt_subscribe(inst->conn, &inst->active_index_subscription); + err = bt_gatt_subscribe(inst->conn, &inst->active_index_subscription); + if (err != 0 && err != -EALREADY) { + return err; + } + + return 0; } static uint8_t active_index_read_cb(struct bt_conn *conn, uint8_t att_err, @@ -520,6 +527,8 @@ static void control_point_subscribe_cb(struct bt_conn *conn, uint8_t att_err, static int control_point_subscribe(struct bt_has_client *inst, uint16_t value_handle, uint8_t properties) { + int err; + LOG_DBG("conn %p handle 0x%04x", (void *)inst->conn, value_handle); inst->control_point_subscription.notify = control_point_notify_cb; @@ -536,7 +545,12 @@ static int control_point_subscribe(struct bt_has_client *inst, uint16_t value_ha inst->control_point_subscription.value = BT_GATT_CCC_INDICATE; } - return bt_gatt_subscribe(inst->conn, &inst->control_point_subscription); + err = bt_gatt_subscribe(inst->conn, &inst->control_point_subscription); + if (err != 0 && err != -EALREADY) { + return err; + } + + return 0; } static uint8_t control_point_discover_cb(struct bt_conn *conn, const struct bt_gatt_attr *attr, @@ -709,6 +723,8 @@ static uint8_t features_notify_cb(struct bt_conn *conn, struct bt_gatt_subscribe static int features_subscribe(struct bt_has_client *inst, uint16_t value_handle) { + int err; + LOG_DBG("conn %p handle 0x%04x", (void *)inst->conn, value_handle); inst->features_subscription.notify = features_notify_cb; @@ -720,7 +736,12 @@ static int features_subscribe(struct bt_has_client *inst, uint16_t value_handle) inst->features_subscription.value = BT_GATT_CCC_NOTIFY; atomic_set_bit(inst->features_subscription.flags, BT_GATT_SUBSCRIBE_FLAG_VOLATILE); - return bt_gatt_subscribe(inst->conn, &inst->features_subscription); + err = bt_gatt_subscribe(inst->conn, &inst->features_subscription); + if (err != 0 && err != -EALREADY) { + return err; + } + + return 0; } static uint8_t features_discover_cb(struct bt_conn *conn, const struct bt_gatt_attr *attr, diff --git a/subsys/bluetooth/audio/mcc.c b/subsys/bluetooth/audio/mcc.c index 909ce19a3cb..e192c0352db 100644 --- a/subsys/bluetooth/audio/mcc.c +++ b/subsys/bluetooth/audio/mcc.c @@ -1156,77 +1156,215 @@ static uint8_t mcs_notify_handler(struct bt_conn *conn, return BT_GATT_ITER_CONTINUE; } -static void reset_mcs_inst(struct mcs_instance_t *mcs_inst, struct bt_conn *conn) +static int reset_mcs_inst(struct mcs_instance_t *mcs_inst) { - (void)memset(mcs_inst, 0, offsetof(struct mcs_instance_t, busy)); + if (mcs_inst->conn != NULL) { + struct bt_conn *conn = mcs_inst->conn; + struct bt_conn_info info; + int err; + + err = bt_conn_get_info(conn, &info); + if (err != 0) { + return err; + } + + if (info.state == BT_CONN_STATE_CONNECTED) { + /* It's okay if these fail with -EINVAL as that means that they are + * not currently subscribed + */ + err = bt_gatt_unsubscribe(conn, &mcs_inst->player_name_sub_params); + if (err != 0 && err != -EINVAL) { + LOG_DBG("Failed to unsubscribe to name: %d", err); + + return err; + } + + err = bt_gatt_unsubscribe(conn, &mcs_inst->track_changed_sub_params); + if (err != 0 && err != -EINVAL) { + LOG_DBG("Failed to unsubscribe to track change: %d", err); + + return err; + } - /* It's okay if these fail. In case of disconnect, we can't - * unsubscribe and they will just fail. - * In case that we reset due to another call of the discover - * function, we will unsubscribe (regardless of bonding state) - * to accommodate the new discovery values. - */ - (void)bt_gatt_unsubscribe(conn, &mcs_inst->player_name_sub_params); - (void)bt_gatt_unsubscribe(conn, &mcs_inst->track_changed_sub_params); #if defined(CONFIG_BT_MCC_READ_TRACK_TITLE_ENABLE_SUBSCRIPTION) - (void)bt_gatt_unsubscribe(conn, &mcs_inst->track_title_sub_params); + err = bt_gatt_unsubscribe(conn, &mcs_inst->track_title_sub_params); + if (err != 0 && err != -EINVAL) { + LOG_DBG("Failed to unsubscribe to track title: %d", err); + + return err; + } #endif /* defined(CONFIG_BT_MCC_READ_TRACK_TITLE_ENABLE_SUBSCRIPTION) */ + #if defined(CONFIG_BT_MCC_READ_TRACK_DURATION) - (void)bt_gatt_unsubscribe(conn, &mcs_inst->track_duration_sub_params); + err = bt_gatt_unsubscribe(conn, &mcs_inst->track_duration_sub_params); + if (err != 0 && err != -EINVAL) { + LOG_DBG("Failed to unsubscribe to track duration: %d", err); + + return err; + } #endif /* defined(CONFIG_BT_MCC_READ_TRACK_DURATION) */ + #if defined(CONFIG_BT_MCC_READ_TRACK_POSITION) - (void)bt_gatt_unsubscribe(conn, &mcs_inst->track_position_sub_params); + err = bt_gatt_unsubscribe(conn, &mcs_inst->track_position_sub_params); + if (err != 0 && err != -EINVAL) { + LOG_DBG("Failed to unsubscribe to track position: %d", err); + + return err; + } #endif /* defined(CONFIG_BT_MCC_READ_TRACK_POSITION) */ + #if defined(CONFIG_BT_MCC_READ_PLAYBACK_SPEED) - (void)bt_gatt_unsubscribe(conn, &mcs_inst->playback_speed_sub_params); + err = bt_gatt_unsubscribe(conn, &mcs_inst->playback_speed_sub_params); + if (err != 0 && err != -EINVAL) { + LOG_DBG("Failed to unsubscribe to playback speed: %d", err); + + return err; + } #endif /* defined (CONFIG_BT_MCC_READ_PLAYBACK_SPEED) */ + #if defined(CONFIG_BT_MCC_READ_SEEKING_SPEED) - (void)bt_gatt_unsubscribe(conn, &mcs_inst->seeking_speed_sub_params); + err = bt_gatt_unsubscribe(conn, &mcs_inst->seeking_speed_sub_params); + if (err != 0 && err != -EINVAL) { + LOG_DBG("Failed to unsubscribe to seeking speed: %d", err); + + return err; + } #endif /* defined (CONFIG_BT_MCC_READ_SEEKING_SPEED) */ + #ifdef CONFIG_BT_MCC_OTS - (void)bt_gatt_unsubscribe(conn, &mcs_inst->current_track_obj_sub_params); - (void)bt_gatt_unsubscribe(conn, &mcs_inst->next_track_obj_sub_params); - (void)bt_gatt_unsubscribe(conn, &mcs_inst->parent_group_obj_sub_params); - (void)bt_gatt_unsubscribe(conn, &mcs_inst->current_group_obj_sub_params); + err = bt_gatt_unsubscribe(conn, &mcs_inst->current_track_obj_sub_params); + if (err != 0 && err != -EINVAL) { + LOG_DBG("Failed to unsubscribe to current track object: %d", err); + + return err; + } + + err = bt_gatt_unsubscribe(conn, &mcs_inst->next_track_obj_sub_params); + if (err != 0 && err != -EINVAL) { + LOG_DBG("Failed to unsubscribe to next track object: %d", err); + + return err; + } + + err = bt_gatt_unsubscribe(conn, &mcs_inst->parent_group_obj_sub_params); + if (err != 0 && err != -EINVAL) { + LOG_DBG("Failed to unsubscribe to parent group object: %d", err); + + return err; + } + + err = bt_gatt_unsubscribe(conn, &mcs_inst->current_group_obj_sub_params); + if (err != 0 && err != -EINVAL) { + LOG_DBG("Failed to unsubscribe to current group object: %d", err); + + return err; + } + #endif /* CONFIG_BT_MCC_OTS */ #if defined(CONFIG_BT_MCC_READ_PLAYING_ORDER) - (void)bt_gatt_unsubscribe(conn, &mcs_inst->playing_order_sub_params); + err = bt_gatt_unsubscribe(conn, &mcs_inst->playing_order_sub_params); + if (err != 0 && err != -EINVAL) { + LOG_DBG("Failed to unsubscribe to playing order: %d", err); + + return err; + } #endif /* defined(CONFIG_BT_MCC_READ_PLAYING_ORDER) */ + #if defined(CONFIG_BT_MCC_READ_MEDIA_STATE) - (void)bt_gatt_unsubscribe(conn, &mcs_inst->media_state_sub_params); + err = bt_gatt_unsubscribe(conn, &mcs_inst->media_state_sub_params); + if (err != 0 && err != -EINVAL) { + LOG_DBG("Failed to unsubscribe to media state: %d", err); + + return err; + } #endif /* defined(CONFIG_BT_MCC_READ_MEDIA_STATE) */ - (void)bt_gatt_unsubscribe(conn, &mcs_inst->cp_sub_params); + + err = bt_gatt_unsubscribe(conn, &mcs_inst->cp_sub_params); + if (err != 0 && err != -EINVAL) { + LOG_DBG("Failed to unsubscribe to control point: %d", err); + + return err; + } + #if defined(CONFIG_BT_MCC_READ_MEDIA_CONTROL_POINT_OPCODES_SUPPORTED) - (void)bt_gatt_unsubscribe(conn, &mcs_inst->opcodes_supported_sub_params); + err = bt_gatt_unsubscribe(conn, &mcs_inst->opcodes_supported_sub_params); + if (err != 0 && err != -EINVAL) { + LOG_DBG("Failed to unsubscribe to supported opcodes: %d", err); + + return err; + } #endif /* defined(CONFIG_BT_MCC_READ_MEDIA_CONTROL_POINT_OPCODES_SUPPORTED) */ + #ifdef CONFIG_BT_MCC_OTS - (void)bt_gatt_unsubscribe(conn, &mcs_inst->scp_sub_params); - (void)bt_gatt_unsubscribe(conn, &mcs_inst->search_results_obj_sub_params); + err = bt_gatt_unsubscribe(conn, &mcs_inst->scp_sub_params); + if (err != 0 && err != -EINVAL) { + LOG_DBG("Failed to unsubscribe to search control point: %d", err); + + return err; + } + + err = bt_gatt_unsubscribe(conn, &mcs_inst->search_results_obj_sub_params); + if (err != 0 && err != -EINVAL) { + LOG_DBG("Failed to unsubscribe to search results: %d", err); + + return err; + } + + err = bt_gatt_unsubscribe(conn, &mcs_inst->otc.oacp_sub_params); + if (err != 0 && err != -EINVAL) { + LOG_DBG("Failed to unsubscribe to oacp: %d", err); + + return err; + } + + err = bt_gatt_unsubscribe(conn, &mcs_inst->otc.olcp_sub_params); + if (err != 0 && err != -EINVAL) { + LOG_DBG("Failed to unsubscribe to olcp: %d", err); + + return err; + } #endif /* CONFIG_BT_MCC_OTS */ + } - /* Reset OTC instance as well if supported */ + bt_conn_unref(conn); + mcs_inst->conn = NULL; + } + + (void)memset(mcs_inst, 0, offsetof(struct mcs_instance_t, busy)); #ifdef CONFIG_BT_MCC_OTS - (void)memset(&mcs_inst->otc, 0, - offsetof(struct bt_ots_client, oacp_sub_params)); - (void)bt_gatt_unsubscribe(conn, &mcs_inst->otc.oacp_sub_params); - (void)bt_gatt_unsubscribe(conn, &mcs_inst->otc.olcp_sub_params); + /* Reset OTC instance as well if supported */ + (void)memset(&mcs_inst->otc, 0, offsetof(struct bt_ots_client, oacp_sub_params)); #endif /* CONFIG_BT_MCC_OTS */ + + return 0; } +static void disconnected_cb(struct bt_conn *conn, uint8_t reason) +{ + struct mcs_instance_t *mcs_inst; + + mcs_inst = lookup_inst_by_conn(conn); + if (mcs_inst != NULL) { + (void)reset_mcs_inst(mcs_inst); + } +} + +BT_CONN_CB_DEFINE(conn_callbacks) = { + .disconnected = disconnected_cb, +}; + /* Called when discovery is completed - successfully or with error */ static void discovery_complete(struct bt_conn *conn, int err) { - LOG_DBG("Discovery completed, err: %d", err); + struct mcs_instance_t *mcs_inst; - /* TODO: Handle resets of instance, and re-discovery. - * For now, reset instance on error. - */ - if (err) { - struct mcs_instance_t *mcs_inst; + LOG_DBG("Discovery completed, err: %d", err); - mcs_inst = lookup_inst_by_conn(conn); - if (mcs_inst != NULL) { - reset_mcs_inst(mcs_inst, conn); + mcs_inst = lookup_inst_by_conn(conn); + if (mcs_inst != NULL) { + mcs_inst->busy = false; + if (err != 0) { + (void)reset_mcs_inst(mcs_inst); } } @@ -1296,6 +1434,7 @@ static uint8_t discover_otc_char_func(struct bt_conn *conn, sub_params->value = BT_GATT_CCC_INDICATE; sub_params->value_handle = chrc->value_handle; sub_params->notify = bt_ots_client_indicate_handler; + atomic_set_bit(sub_params->flags, BT_GATT_SUBSCRIBE_FLAG_VOLATILE); err = bt_gatt_subscribe(conn, sub_params); if (err != 0) { @@ -1463,7 +1602,7 @@ static int do_subscribe(struct mcs_instance_t *mcs_inst, struct bt_conn *conn, sub_params->subscribe = subscribe_mcs_char_func; /* disc_params pointer is also used as subscription flag */ sub_params->disc_params = &mcs_inst->discover_params; - atomic_set_bit(sub_params->flags, BT_GATT_SUBSCRIBE_FLAG_NO_RESUB); + atomic_set_bit(sub_params->flags, BT_GATT_SUBSCRIBE_FLAG_VOLATILE); LOG_DBG("Subscring to handle %d", handle); return bt_gatt_subscribe(conn, sub_params); @@ -1945,6 +2084,7 @@ int bt_mcc_init(struct bt_mcc_cb *cb) int bt_mcc_discover_mcs(struct bt_conn *conn, bool subscribe) { struct mcs_instance_t *mcs_inst; + int err; CHECKIF(!conn) { return -EINVAL; @@ -1961,7 +2101,12 @@ int bt_mcc_discover_mcs(struct bt_conn *conn, bool subscribe) } subscribe_all = subscribe; - reset_mcs_inst(mcs_inst, conn); + err = reset_mcs_inst(mcs_inst); + if (err != 0) { + LOG_DBG("Failed to reset MCS instance %p: %d", mcs_inst, err); + + return err; + } (void)memcpy(&uuid, BT_UUID_GMCS, sizeof(uuid)); mcs_inst->discover_params.func = discover_primary_func; @@ -1971,7 +2116,15 @@ int bt_mcc_discover_mcs(struct bt_conn *conn, bool subscribe) mcs_inst->discover_params.end_handle = BT_ATT_LAST_ATTRIBUTE_HANDLE; LOG_DBG("start discovery of GMCS primary service"); - return bt_gatt_discover(conn, &mcs_inst->discover_params); + err = bt_gatt_discover(conn, &mcs_inst->discover_params); + if (err != 0) { + return err; + } + + mcs_inst->conn = bt_conn_ref(conn); + mcs_inst->busy = true; + + return 0; } int bt_mcc_read_player_name(struct bt_conn *conn) diff --git a/subsys/bluetooth/audio/mcc_internal.h b/subsys/bluetooth/audio/mcc_internal.h index 2d005d1fbee..2838e53ba35 100644 --- a/subsys/bluetooth/audio/mcc_internal.h +++ b/subsys/bluetooth/audio/mcc_internal.h @@ -19,6 +19,7 @@ struct mcs_instance_t *lookup_inst_by_conn(struct bt_conn *conn); struct mcs_instance_t { + struct bt_conn *conn; uint16_t start_handle; uint16_t end_handle; uint16_t player_name_handle; diff --git a/subsys/bluetooth/audio/micp_mic_ctlr.c b/subsys/bluetooth/audio/micp_mic_ctlr.c index 974c1ba8124..8232d664dce 100644 --- a/subsys/bluetooth/audio/micp_mic_ctlr.c +++ b/subsys/bluetooth/audio/micp_mic_ctlr.c @@ -409,9 +409,10 @@ static uint8_t micp_discover_func(struct bt_conn *conn, sub_params->value = BT_GATT_CCC_NOTIFY; sub_params->value_handle = chrc->value_handle; sub_params->notify = mute_notify_handler; + atomic_set_bit(sub_params->flags, BT_GATT_SUBSCRIBE_FLAG_VOLATILE); err = bt_gatt_subscribe(conn, sub_params); - if (err == 0) { + if (err == 0 || err == -EALREADY) { LOG_DBG("Subscribed to handle 0x%04X", attr->handle); } else { LOG_DBG("Could not subscribe to handle 0x%04X: %d", attr->handle, @@ -480,14 +481,6 @@ static void micp_mic_ctlr_reset(struct bt_micp_mic_ctlr *mic_ctlr) if (mic_ctlr->conn != NULL) { struct bt_conn *conn = mic_ctlr->conn; - /* It's okay if this fails. In case of disconnect, we can't - * unsubscribe and it will just fail. - * In case that we reset due to another call of the discover - * function, we will unsubscribe (regardless of bonding state) - * to accommodate the new discovery values. - */ - (void)bt_gatt_unsubscribe(conn, &mic_ctlr->mute_sub_params); - bt_conn_unref(conn); mic_ctlr->conn = NULL; } diff --git a/subsys/bluetooth/audio/tbs_client.c b/subsys/bluetooth/audio/tbs_client.c index 9ef759c3c1e..564db2a667c 100644 --- a/subsys/bluetooth/audio/tbs_client.c +++ b/subsys/bluetooth/audio/tbs_client.c @@ -1539,8 +1539,9 @@ static uint8_t discover_func(struct bt_conn *conn, sub_params->end_handle = current_inst->end_handle; sub_params->notify = notify_handler; atomic_set_bit(sub_params->flags, BT_GATT_SUBSCRIBE_FLAG_VOLATILE); + err = bt_gatt_subscribe(conn, sub_params); - if (err != 0) { + if (err != 0 && err != -EALREADY) { LOG_DBG("Could not subscribe to " "characterstic at handle 0x%04X" "(%d)", diff --git a/subsys/bluetooth/audio/vcp_vol_ctlr.c b/subsys/bluetooth/audio/vcp_vol_ctlr.c index 6f41f61ec90..d0f9075dafe 100644 --- a/subsys/bluetooth/audio/vcp_vol_ctlr.c +++ b/subsys/bluetooth/audio/vcp_vol_ctlr.c @@ -449,8 +449,10 @@ static uint8_t vcs_discover_func(struct bt_conn *conn, sub_params->ccc_handle = 0; sub_params->end_handle = vol_ctlr->end_handle; sub_params->notify = vcp_vol_ctlr_notify_handler; + atomic_set_bit(sub_params->flags, BT_GATT_SUBSCRIBE_FLAG_VOLATILE); + err = bt_gatt_subscribe(conn, sub_params); - if (err == 0) { + if (err == 0 || err == -EALREADY) { LOG_DBG("Subscribed to handle 0x%04X", attr->handle); } else { @@ -817,15 +819,6 @@ static void vcp_vol_ctlr_reset(struct bt_vcp_vol_ctlr *vol_ctlr) if (vol_ctlr->conn != NULL) { struct bt_conn *conn = vol_ctlr->conn; - /* It's okay if these fail. In case of disconnect, we can't - * unsubscribe and they will just fail. - * In case that we reset due to another call of the discover - * function, we will unsubscribe (regardless of bonding state) - * to accommodate the new discovery values. - */ - (void)bt_gatt_unsubscribe(conn, &vol_ctlr->state_sub_params); - (void)bt_gatt_unsubscribe(conn, &vol_ctlr->flag_sub_params); - bt_conn_unref(conn); vol_ctlr->conn = NULL; } diff --git a/subsys/bluetooth/audio/vocs_client.c b/subsys/bluetooth/audio/vocs_client.c index 4f88d647ad8..e39b8ac69f6 100644 --- a/subsys/bluetooth/audio/vocs_client.c +++ b/subsys/bluetooth/audio/vocs_client.c @@ -411,9 +411,15 @@ static uint8_t vocs_discover_func(struct bt_conn *conn, const struct bt_gatt_att */ sub_params->ccc_handle = attr->handle + 2; sub_params->notify = vocs_client_notify_handler; + atomic_set_bit(sub_params->flags, BT_GATT_SUBSCRIBE_FLAG_VOLATILE); + err = bt_gatt_subscribe(conn, sub_params); - if (err) { + if (err != 0 && err != -EALREADY) { LOG_WRN("Could not subscribe to handle %u", sub_params->ccc_handle); + + inst->cb->discover(&inst->vocs, err); + + return BT_GATT_ITER_STOP; } } } @@ -687,16 +693,6 @@ static void vocs_client_reset(struct bt_vocs_client *inst) if (inst->conn != NULL) { struct bt_conn *conn = inst->conn; - /* It's okay if these fail. In case of disconnect, we can't - * unsubscribe and they will just fail. - * In case that we reset due to another call of the discover - * function, we will unsubscribe (regardless of bonding state) - * to accommodate the new discovery values. - */ - (void)bt_gatt_unsubscribe(conn, &inst->state_sub_params); - (void)bt_gatt_unsubscribe(conn, &inst->location_sub_params); - (void)bt_gatt_unsubscribe(conn, &inst->desc_sub_params); - bt_conn_unref(conn); inst->conn = NULL; } diff --git a/tests/bsim/bluetooth/audio/src/bap_broadcast_assistant_test.c b/tests/bsim/bluetooth/audio/src/bap_broadcast_assistant_test.c index 3980fe963ab..32b68af76ff 100644 --- a/tests/bsim/bluetooth/audio/src/bap_broadcast_assistant_test.c +++ b/tests/bsim/bluetooth/audio/src/bap_broadcast_assistant_test.c @@ -307,6 +307,16 @@ static void test_bass_discover(void) return; } + WAIT_FOR_FLAG(flag_discovery_complete); + + /* Verify that we can discover again */ + flag_discovery_complete = false; + err = bt_bap_broadcast_assistant_discover(default_conn); + if (err != 0) { + FAIL("Failed to discover BASS for the second time: %d\n", err); + return; + } + WAIT_FOR_FLAG(flag_discovery_complete); printk("Discovery complete\n"); } diff --git a/tests/bsim/bluetooth/audio/src/vcp_vol_ctlr_test.c b/tests/bsim/bluetooth/audio/src/vcp_vol_ctlr_test.c index 8be4a3e34c5..9a4e69d5625 100644 --- a/tests/bsim/bluetooth/audio/src/vcp_vol_ctlr_test.c +++ b/tests/bsim/bluetooth/audio/src/vcp_vol_ctlr_test.c @@ -832,6 +832,16 @@ static void test_discover(void) } WAIT_FOR_COND(g_discovery_complete); + + /* Verify that we can discover again */ + g_discovery_complete = false; + err = bt_vcp_vol_ctlr_discover(default_conn, &vol_ctlr); + if (err != 0) { + FAIL("Failed to discover VCP for the second time: %d\n", err); + return; + } + + WAIT_FOR_COND(g_discovery_complete); } static void test_included_get(void) diff --git a/tests/bsim/bluetooth/audio/test_scripts/csip_notify.sh b/tests/bsim/bluetooth/audio/test_scripts/_csip_notify.sh similarity index 100% rename from tests/bsim/bluetooth/audio/test_scripts/csip_notify.sh rename to tests/bsim/bluetooth/audio/test_scripts/_csip_notify.sh From 954f2a09fbc7dff7415c9c280fda8554c09fbf0f Mon Sep 17 00:00:00 2001 From: Emil Gydesen Date: Wed, 17 Jan 2024 13:38:06 +0100 Subject: [PATCH 3389/3723] tests: bsim: Bluetooth: Audio: Add additional testing of discovery Expand the babblesim tests for LE audio to verify that all the discovery functions can be called multiple times without error. HAS is an exception as that has an existing separate check that disallows discovery multiple times. Signed-off-by: Emil Gydesen --- .../audio/src/bap_unicast_client_test.c | 2 + .../bluetooth/audio/src/cap_commander_test.c | 1 + .../audio/src/cap_initiator_unicast_test.c | 1 + .../audio/src/csip_set_coordinator_test.c | 89 ++++++++++--------- .../bsim/bluetooth/audio/src/gmap_ugg_test.c | 1 + .../bsim/bluetooth/audio/src/gmap_ugt_test.c | 1 + .../bluetooth/audio/src/has_client_test.c | 23 +++-- .../bluetooth/audio/src/ias_client_test.c | 24 +++-- tests/bsim/bluetooth/audio/src/mcc_test.c | 1 + .../bluetooth/audio/src/micp_mic_ctlr_test.c | 22 +++-- .../bluetooth/audio/src/tbs_client_test.c | 24 +++-- .../bluetooth/audio/src/tmap_client_test.c | 27 ++++-- .../bluetooth/audio/src/vcp_vol_ctlr_test.c | 13 +-- 13 files changed, 143 insertions(+), 86 deletions(-) diff --git a/tests/bsim/bluetooth/audio/src/bap_unicast_client_test.c b/tests/bsim/bluetooth/audio/src/bap_unicast_client_test.c index 3386986e568..2eab6057e69 100644 --- a/tests/bsim/bluetooth/audio/src/bap_unicast_client_test.c +++ b/tests/bsim/bluetooth/audio/src/bap_unicast_client_test.c @@ -1022,8 +1022,10 @@ static void test_main(void) exchange_mtu(); discover_sinks(); + discover_sinks(); /* test that we can discover twice */ discover_sources(); + discover_sources(); /* test that we can discover twice */ /* Run the stream setup multiple time to ensure states are properly * set and reset diff --git a/tests/bsim/bluetooth/audio/src/cap_commander_test.c b/tests/bsim/bluetooth/audio/src/cap_commander_test.c index 9de329d29ca..1d4582e54d5 100644 --- a/tests/bsim/bluetooth/audio/src/cap_commander_test.c +++ b/tests/bsim/bluetooth/audio/src/cap_commander_test.c @@ -310,6 +310,7 @@ static void test_main_cap_commander_capture_and_render(void) /* TODO: We should use CSIP to find set members */ discover_cas(connected_conns[i]); + discover_cas(connected_conns[i]); /* test that we can discover twice */ if (IS_ENABLED(CONFIG_BT_VCP_VOL_CTLR)) { discover_vcs(connected_conns[i]); diff --git a/tests/bsim/bluetooth/audio/src/cap_initiator_unicast_test.c b/tests/bsim/bluetooth/audio/src/cap_initiator_unicast_test.c index fd079122a53..adfbf2416a1 100644 --- a/tests/bsim/bluetooth/audio/src/cap_initiator_unicast_test.c +++ b/tests/bsim/bluetooth/audio/src/cap_initiator_unicast_test.c @@ -822,6 +822,7 @@ static void test_main_cap_initiator_unicast(void) WAIT_FOR_FLAG(flag_mtu_exchanged); discover_cas(default_conn); + discover_cas(default_conn); /* test that we can discover twice */ discover_sink(default_conn); discover_source(default_conn); diff --git a/tests/bsim/bluetooth/audio/src/csip_set_coordinator_test.c b/tests/bsim/bluetooth/audio/src/csip_set_coordinator_test.c index b821829ed94..7bbc3200d35 100644 --- a/tests/bsim/bluetooth/audio/src/csip_set_coordinator_test.c +++ b/tests/bsim/bluetooth/audio/src/csip_set_coordinator_test.c @@ -21,7 +21,7 @@ static volatile bool set_locked; static volatile bool set_unlocked; static volatile bool ordered_access_locked; static volatile bool ordered_access_unlocked; -static const struct bt_csip_set_coordinator_csis_inst *inst; +static const struct bt_csip_set_coordinator_csis_inst *primary_inst; static uint8_t members_found; static struct k_work_delayable discover_members_timer; @@ -99,7 +99,10 @@ static void csip_discover_cb(struct bt_conn *conn, } } - inst = &member->insts[0]; + if (primary_inst == NULL) { + primary_inst = &member->insts[0]; + } + set_members[conn_index] = member; discovered = true; } @@ -107,7 +110,7 @@ static void csip_discover_cb(struct bt_conn *conn, static void csip_lock_changed_cb(struct bt_csip_set_coordinator_csis_inst *inst, bool locked) { - printk("Inst %p %s\n", inst, locked ? "locked" : "released"); + printk("inst %p %s\n", inst, locked ? "locked" : "released"); } static void csip_set_coordinator_ordered_access_cb( @@ -156,7 +159,7 @@ static bool is_discovered(const bt_addr_le_t *addr) static bool csip_found(struct bt_data *data, void *user_data) { - if (bt_csip_set_coordinator_is_set_member(inst->info.set_sirk, data)) { + if (bt_csip_set_coordinator_is_set_member(primary_inst->info.set_sirk, data)) { const bt_addr_le_t *addr = user_data; char addr_str[BT_ADDR_LE_STR_LEN]; @@ -171,10 +174,11 @@ static bool csip_found(struct bt_data *data, void *user_data) bt_addr_le_copy(&addr_found[members_found++], addr); - if (inst->info.set_size == 0) { + if (primary_inst->info.set_size == 0) { printk("Found member %u\n", members_found); } else { - printk("Found member (%u / %u)\n", members_found, inst->info.set_size); + printk("Found member (%u / %u)\n", members_found, + primary_inst->info.set_size); } /* Stop parsing */ @@ -189,7 +193,7 @@ static void csip_set_coordinator_scan_recv(const struct bt_le_scan_recv_info *in { /* We're only interested in connectable events */ if (info->adv_props & BT_GAP_ADV_PROP_CONNECTABLE) { - if (inst == NULL) { + if (primary_inst == NULL) { /* Scanning for the first device */ if (members_found == 0) { bt_addr_le_copy(&addr_found[members_found++], @@ -207,8 +211,9 @@ static struct bt_le_scan_cb csip_set_coordinator_scan_callbacks = { static void discover_members_timer_handler(struct k_work *work) { - if (inst->info.set_size > 0) { - FAIL("Could not find all members (%u / %u)\n", members_found, inst->info.set_size); + if (primary_inst->info.set_size > 0) { + FAIL("Could not find all members (%u / %u)\n", members_found, + primary_inst->info.set_size); } else { discover_timed_out = true; } @@ -228,8 +233,7 @@ static void ordered_access(const struct bt_csip_set_coordinator_set_member **mem ordered_access_unlocked = false; } - err = bt_csip_set_coordinator_ordered_access(members, count, - &inst->info, + err = bt_csip_set_coordinator_ordered_access(members, count, &primary_inst->info, csip_set_coordinator_oap_cb); if (err != 0) { FAIL("Failed to do CSIP set coordinator ordered access (%d)", @@ -244,6 +248,21 @@ static void ordered_access(const struct bt_csip_set_coordinator_set_member **mem } } +static void discover_csis(struct bt_conn *conn) +{ + int err; + + discovered = false; + + err = bt_csip_set_coordinator_discover(conns[bt_conn_index(conn)]); + if (err != 0) { + FAIL("Failed to initialize set coordinator for connection %d\n", err); + return; + } + + WAIT_FOR_COND(discovered); +} + static void test_main(void) { int err; @@ -293,14 +312,8 @@ static void test_main(void) WAIT_FOR_FLAG(flag_connected); connected_member_count++; - err = bt_csip_set_coordinator_discover(conns[0]); - if (err != 0) { - FAIL("Failed to initialize set coordinator for connection %d\n", - err); - return; - } - - WAIT_FOR_COND(discovered); + discover_csis(conns[0]); + discover_csis(conns[0]); /* test that we can discover twice */ err = bt_le_scan_start(BT_LE_SCAN_ACTIVE, NULL); if (err != 0) { @@ -315,8 +328,8 @@ static void test_main(void) return; } - if (inst->info.set_size > 0) { - WAIT_FOR_COND(members_found == inst->info.set_size); + if (primary_inst->info.set_size > 0) { + WAIT_FOR_COND(members_found == primary_inst->info.set_size); (void)k_work_cancel_delayable(&discover_members_timer); } else { @@ -347,30 +360,22 @@ static void test_main(void) WAIT_FOR_FLAG(flag_connected); connected_member_count++; - discovered = false; printk("Doing discovery on member[%u]", i); - err = bt_csip_set_coordinator_discover(conns[i]); - if (err != 0) { - FAIL("Failed to initialize set coordinator for connection %d\n", - err); - return; - } - - WAIT_FOR_COND(discovered); + discover_csis(conns[i]); } for (size_t i = 0; i < ARRAY_SIZE(locked_members); i++) { locked_members[i] = set_members[i]; } - if (inst->info.rank != 0U) { + if (primary_inst->info.rank != 0U) { ordered_access(locked_members, connected_member_count, false); } - if (inst->info.lockable) { + if (primary_inst->info.lockable) { printk("Locking set\n"); err = bt_csip_set_coordinator_lock(locked_members, connected_member_count, - &inst->info); + &primary_inst->info); if (err != 0) { FAIL("Failed to do set coordinator lock (%d)", err); return; @@ -379,16 +384,16 @@ static void test_main(void) WAIT_FOR_COND(set_locked); } - if (inst->info.rank != 0U) { - ordered_access(locked_members, connected_member_count, inst->info.lockable); + if (primary_inst->info.rank != 0U) { + ordered_access(locked_members, connected_member_count, primary_inst->info.lockable); } k_sleep(K_MSEC(1000)); /* Simulate doing stuff */ - if (inst->info.lockable) { + if (primary_inst->info.lockable) { printk("Releasing set\n"); err = bt_csip_set_coordinator_release(locked_members, connected_member_count, - &inst->info); + &primary_inst->info); if (err != 0) { FAIL("Failed to do set coordinator release (%d)", err); return; @@ -397,18 +402,18 @@ static void test_main(void) WAIT_FOR_COND(set_unlocked); } - if (inst->info.rank != 0U) { + if (primary_inst->info.rank != 0U) { ordered_access(locked_members, connected_member_count, false); } - if (inst->info.lockable) { + if (primary_inst->info.lockable) { /* Lock and unlock again */ set_locked = false; set_unlocked = false; printk("Locking set\n"); err = bt_csip_set_coordinator_lock(locked_members, connected_member_count, - &inst->info); + &primary_inst->info); if (err != 0) { FAIL("Failed to do set coordinator lock (%d)", err); return; @@ -419,10 +424,10 @@ static void test_main(void) k_sleep(K_MSEC(1000)); /* Simulate doing stuff */ - if (inst->info.lockable) { + if (primary_inst->info.lockable) { printk("Releasing set\n"); err = bt_csip_set_coordinator_release(locked_members, connected_member_count, - &inst->info); + &primary_inst->info); if (err != 0) { FAIL("Failed to do set coordinator release (%d)", err); return; diff --git a/tests/bsim/bluetooth/audio/src/gmap_ugg_test.c b/tests/bsim/bluetooth/audio/src/gmap_ugg_test.c index d48b0c18ffc..1e5713f08ad 100644 --- a/tests/bsim/bluetooth/audio/src/gmap_ugg_test.c +++ b/tests/bsim/bluetooth/audio/src/gmap_ugg_test.c @@ -957,6 +957,7 @@ static void test_gmap_ugg_unicast_ac(const struct gmap_unicast_ac_param *param) } discover_gmas(connected_conns[i]); + discover_gmas(connected_conns[i]); /* test that we can discover twice */ } gmap_ac_unicast(param, &unicast_group); diff --git a/tests/bsim/bluetooth/audio/src/gmap_ugt_test.c b/tests/bsim/bluetooth/audio/src/gmap_ugt_test.c index c4a02a0a67e..fd7bf7290b7 100644 --- a/tests/bsim/bluetooth/audio/src/gmap_ugt_test.c +++ b/tests/bsim/bluetooth/audio/src/gmap_ugt_test.c @@ -426,6 +426,7 @@ static void test_main(void) WAIT_FOR_FLAG(flag_connected); discover_gmas(default_conn); + discover_gmas(default_conn); /* test that we can discover twice */ WAIT_FOR_FLAG(flag_disconnected); diff --git a/tests/bsim/bluetooth/audio/src/has_client_test.c b/tests/bsim/bluetooth/audio/src/has_client_test.c index a56808af997..c6312b2bb63 100644 --- a/tests/bsim/bluetooth/audio/src/has_client_test.c +++ b/tests/bsim/bluetooth/audio/src/has_client_test.c @@ -158,6 +158,21 @@ static bool test_preset_prev(uint8_t active_index_expected) return g_active_index == active_index_expected; } +static void discover_has(void) +{ + int err; + + g_service_discovered = false; + + err = bt_has_client_discover(default_conn); + if (err < 0) { + FAIL("Failed to discover HAS (err %d)\n", err); + return; + } + + WAIT_FOR_COND(g_service_discovered); +} + static void test_main(void) { int err; @@ -188,13 +203,7 @@ static void test_main(void) WAIT_FOR_FLAG(flag_connected); - err = bt_has_client_discover(default_conn); - if (err < 0) { - FAIL("Failed to discover HAS (err %d)\n", err); - return; - } - - WAIT_FOR_COND(g_service_discovered); + discover_has(); WAIT_FOR_COND(g_preset_switched); err = bt_has_client_presets_read(g_has, BT_HAS_PRESET_INDEX_FIRST, 255); diff --git a/tests/bsim/bluetooth/audio/src/ias_client_test.c b/tests/bsim/bluetooth/audio/src/ias_client_test.c index 0966d899306..1bad6456798 100644 --- a/tests/bsim/bluetooth/audio/src/ias_client_test.c +++ b/tests/bsim/bluetooth/audio/src/ias_client_test.c @@ -65,6 +65,21 @@ static void test_alert_stop(struct bt_conn *conn) } } +static void discover_ias(void) +{ + int err; + + UNSET_FLAG(g_service_discovered); + + err = bt_ias_discover(default_conn); + if (err < 0) { + FAIL("Failed to discover IAS (err %d)\n", err); + return; + } + + WAIT_FOR_FLAG(g_service_discovered); +} + static void test_main(void) { int err; @@ -95,13 +110,8 @@ static void test_main(void) WAIT_FOR_FLAG(flag_connected); - err = bt_ias_discover(default_conn); - if (err < 0) { - FAIL("Failed to discover IAS (err %d)\n", err); - return; - } - - WAIT_FOR_FLAG(g_service_discovered); + discover_ias(); + discover_ias(); /* test that we can discover twice */ /* Set alert levels with a delay to let the server handle any changes it want */ test_alert_high(default_conn); diff --git a/tests/bsim/bluetooth/audio/src/mcc_test.c b/tests/bsim/bluetooth/audio/src/mcc_test.c index 3be3d5beaf9..29c75ab6163 100644 --- a/tests/bsim/bluetooth/audio/src/mcc_test.c +++ b/tests/bsim/bluetooth/audio/src/mcc_test.c @@ -2454,6 +2454,7 @@ void test_main(void) WAIT_FOR_FLAG(flag_conn_updated); test_discover(); + test_discover(); /* test that we can discover twice */ reset_test_iteration(i); diff --git a/tests/bsim/bluetooth/audio/src/micp_mic_ctlr_test.c b/tests/bsim/bluetooth/audio/src/micp_mic_ctlr_test.c index 5cefd31d099..a77dd9979b1 100644 --- a/tests/bsim/bluetooth/audio/src/micp_mic_ctlr_test.c +++ b/tests/bsim/bluetooth/audio/src/micp_mic_ctlr_test.c @@ -344,6 +344,21 @@ static int test_aics(void) return 0; } +static void discover_mics(struct bt_micp_mic_ctlr **mic_ctlr) +{ + int err; + + g_discovery_complete = false; + + err = bt_micp_mic_ctlr_discover(default_conn, mic_ctlr); + if (err != 0) { + FAIL("Failed to discover MICS %d", err); + return; + } + + WAIT_FOR_COND(g_discovery_complete); +} + static void test_main(void) { int err; @@ -371,11 +386,8 @@ static void test_main(void) printk("Scanning successfully started\n"); WAIT_FOR_FLAG(flag_connected); - err = bt_micp_mic_ctlr_discover(default_conn, &mic_ctlr); - if (err != 0) { - FAIL("Failed to discover MICS %d", err); - } - WAIT_FOR_COND(g_discovery_complete); + discover_mics(&mic_ctlr); + discover_mics(&mic_ctlr); /* test that we can discover twice */ err = bt_micp_mic_ctlr_included_get(mic_ctlr, &micp_included); if (err != 0) { diff --git a/tests/bsim/bluetooth/audio/src/tbs_client_test.c b/tests/bsim/bluetooth/audio/src/tbs_client_test.c index 35a7f6f6083..398a44db2fd 100644 --- a/tests/bsim/bluetooth/audio/src/tbs_client_test.c +++ b/tests/bsim/bluetooth/audio/src/tbs_client_test.c @@ -460,11 +460,25 @@ static void test_signal_interval(uint8_t index) printk("Client signal interval test success\n"); } +static void discover_tbs(void) +{ + int err; + + discovery_complete = false; + + err = bt_tbs_client_discover(default_conn); + if (err) { + FAIL("Failed to discover TBS: %d", err); + return; + } + + WAIT_FOR_COND(discovery_complete); +} + static void test_main(void) { int err; int index = 0; - int tbs_client_err; err = bt_enable(bt_ready); @@ -490,12 +504,8 @@ static void test_main(void) WAIT_FOR_COND(is_connected); - tbs_client_err = bt_tbs_client_discover(default_conn); - if (tbs_client_err) { - FAIL("Failed to discover TBS_CLIENT for connection %d", tbs_client_err); - } - - WAIT_FOR_COND(discovery_complete); + discover_tbs(); + discover_tbs(); /* test that we can discover twice */ printk("GTBS %sfound\n", is_gtbs_found ? "" : "not "); diff --git a/tests/bsim/bluetooth/audio/src/tmap_client_test.c b/tests/bsim/bluetooth/audio/src/tmap_client_test.c index 4dbd8b9c5be..d99cc1d5440 100644 --- a/tests/bsim/bluetooth/audio/src/tmap_client_test.c +++ b/tests/bsim/bluetooth/audio/src/tmap_client_test.c @@ -113,6 +113,23 @@ static struct bt_le_scan_cb scan_callbacks = { .recv = scan_recv, }; +static void discover_tmas(void) +{ + int err; + + UNSET_FLAG(flag_tmap_discovered); + + /* Discover TMAS service on peer */ + err = bt_tmap_discover(default_conn, &tmap_callbacks); + if (err != 0) { + FAIL("Failed to initiate TMAS discovery: %d\n", err); + return; + } + + printk("TMAP Central Starting Service Discovery...\n"); + WAIT_FOR_FLAG(flag_tmap_discovered); +} + static void test_main(void) { int err; @@ -141,15 +158,9 @@ static void test_main(void) printk("Scanning successfully started\n"); WAIT_FOR_FLAG(flag_connected); - /* Discover TMAS service on peer */ - err = bt_tmap_discover(default_conn, &tmap_callbacks); - if (err != 0) { - FAIL("Failed to initiate TMAS discovery: %d\n", err); - return; - } - printk("TMAP Central Starting Service Discovery...\n"); - WAIT_FOR_FLAG(flag_tmap_discovered); + discover_tmas(); + discover_tmas(); /* test that we can discover twice */ PASS("TMAP Client test passed\n"); } diff --git a/tests/bsim/bluetooth/audio/src/vcp_vol_ctlr_test.c b/tests/bsim/bluetooth/audio/src/vcp_vol_ctlr_test.c index 9a4e69d5625..a90b4c46f2f 100644 --- a/tests/bsim/bluetooth/audio/src/vcp_vol_ctlr_test.c +++ b/tests/bsim/bluetooth/audio/src/vcp_vol_ctlr_test.c @@ -811,6 +811,8 @@ static void test_discover(void) { int err; + g_discovery_complete = false; + /* Invalid behavior */ err = bt_vcp_vol_ctlr_discover(NULL, &vol_ctlr); if (err == 0) { @@ -832,16 +834,6 @@ static void test_discover(void) } WAIT_FOR_COND(g_discovery_complete); - - /* Verify that we can discover again */ - g_discovery_complete = false; - err = bt_vcp_vol_ctlr_discover(default_conn, &vol_ctlr); - if (err != 0) { - FAIL("Failed to discover VCP for the second time: %d\n", err); - return; - } - - WAIT_FOR_COND(g_discovery_complete); } static void test_included_get(void) @@ -1169,6 +1161,7 @@ static void test_main(void) WAIT_FOR_FLAG(flag_connected); test_discover(); + test_discover(); /* test that we can discover twice */ test_included_get(); test_conn_get(); test_read_state(); From de56f0cce2c307fbeb9ede450e96d2ba45422ddb Mon Sep 17 00:00:00 2001 From: Gerson Fernando Budke Date: Sun, 26 Nov 2023 14:24:28 +0100 Subject: [PATCH 3390/3723] samples: net: echo_server: Decrease SRAM for atsamr21_xpro In the Zephyr v3.5 to build the net samples pair echo-server/client the SRAM requirements increased for the atsamr21_xpro board when passing -DEXTRA_CONF_FILE=overlay-802154.conf argument. This adjusts example features to free necessary SRAM to build and run the example. Signed-off-by: Gerson Fernando Budke --- .../echo_server/boards/atsamr21_xpro.conf | 28 +++++++++++++------ 1 file changed, 19 insertions(+), 9 deletions(-) diff --git a/samples/net/sockets/echo_server/boards/atsamr21_xpro.conf b/samples/net/sockets/echo_server/boards/atsamr21_xpro.conf index 5426e8ba625..085594463e1 100644 --- a/samples/net/sockets/echo_server/boards/atsamr21_xpro.conf +++ b/samples/net/sockets/echo_server/boards/atsamr21_xpro.conf @@ -1,23 +1,33 @@ # -# Copyright (c) 2020-2021, Gerson Fernando Budke # Copyright (c) 2019, Benjamin Valentin +# Copyright (c) 2020-2024, Gerson Fernando Budke # # SPDX-License-Identifier: Apache-2.0 # -# Reduced buffers to fit into SAMR21 SoC +# Reduced configs to fit into SAMR21 SoC CONFIG_CPP=n -CONFIG_NET_PKT_RX_COUNT=6 -CONFIG_NET_PKT_TX_COUNT=6 -CONFIG_NET_BUF_RX_COUNT=6 -CONFIG_NET_BUF_TX_COUNT=6 -CONFIG_NET_MAX_CONTEXTS=4 +CONFIG_NET_PKT_RX_COUNT=5 +CONFIG_NET_PKT_TX_COUNT=5 +CONFIG_NET_BUF_RX_COUNT=5 +CONFIG_NET_BUF_TX_COUNT=5 +CONFIG_NET_MAX_CONTEXTS=2 CONFIG_NET_MAX_CONN=1 CONFIG_NET_MAX_ROUTES=1 CONFIG_NET_MAX_NEXTHOPS=1 CONFIG_SHELL_STACK_SIZE=768 -CONFIG_SHELL_CMD_BUFF_SIZE=64 +CONFIG_SHELL_CMD_BUFF_SIZE=32 CONFIG_SHELL_ARGC_MAX=6 -CONFIG_SHELL_HISTORY_BUFFER=64 +CONFIG_SHELL_HISTORY_BUFFER=4 + +CONFIG_LOG_MODE_MINIMAL=y +CONFIG_NET_IP_DSCP_ECN=n +CONFIG_NET_STATISTICS=n +CONFIG_NET_MGMT_EVENT_STACK_SIZE=512 +CONFIG_IEEE802154_RF2XX_RX_STACK_SIZE=512 + +CONFIG_UART_USE_RUNTIME_CONFIGURE=n +CONFIG_NET_CONTEXT_REUSEADDR=n +CONFIG_NET_CONTEXT_REUSEPORT=n From 78ee5b1d05b0c0e8d790ee33d115645e9314e904 Mon Sep 17 00:00:00 2001 From: Gerson Fernando Budke Date: Sun, 26 Nov 2023 14:30:05 +0100 Subject: [PATCH 3391/3723] samples: net: echo_client: Decrease SRAM for atsamr21_xpro This update the echo_client configurations for the atsamr21_xpro board to match same configs defined at echo_server. Signed-off-by: Gerson Fernando Budke --- .../echo_client/boards/atsamr21_xpro.conf | 28 +++++++++++++------ 1 file changed, 19 insertions(+), 9 deletions(-) diff --git a/samples/net/sockets/echo_client/boards/atsamr21_xpro.conf b/samples/net/sockets/echo_client/boards/atsamr21_xpro.conf index 5426e8ba625..085594463e1 100644 --- a/samples/net/sockets/echo_client/boards/atsamr21_xpro.conf +++ b/samples/net/sockets/echo_client/boards/atsamr21_xpro.conf @@ -1,23 +1,33 @@ # -# Copyright (c) 2020-2021, Gerson Fernando Budke # Copyright (c) 2019, Benjamin Valentin +# Copyright (c) 2020-2024, Gerson Fernando Budke # # SPDX-License-Identifier: Apache-2.0 # -# Reduced buffers to fit into SAMR21 SoC +# Reduced configs to fit into SAMR21 SoC CONFIG_CPP=n -CONFIG_NET_PKT_RX_COUNT=6 -CONFIG_NET_PKT_TX_COUNT=6 -CONFIG_NET_BUF_RX_COUNT=6 -CONFIG_NET_BUF_TX_COUNT=6 -CONFIG_NET_MAX_CONTEXTS=4 +CONFIG_NET_PKT_RX_COUNT=5 +CONFIG_NET_PKT_TX_COUNT=5 +CONFIG_NET_BUF_RX_COUNT=5 +CONFIG_NET_BUF_TX_COUNT=5 +CONFIG_NET_MAX_CONTEXTS=2 CONFIG_NET_MAX_CONN=1 CONFIG_NET_MAX_ROUTES=1 CONFIG_NET_MAX_NEXTHOPS=1 CONFIG_SHELL_STACK_SIZE=768 -CONFIG_SHELL_CMD_BUFF_SIZE=64 +CONFIG_SHELL_CMD_BUFF_SIZE=32 CONFIG_SHELL_ARGC_MAX=6 -CONFIG_SHELL_HISTORY_BUFFER=64 +CONFIG_SHELL_HISTORY_BUFFER=4 + +CONFIG_LOG_MODE_MINIMAL=y +CONFIG_NET_IP_DSCP_ECN=n +CONFIG_NET_STATISTICS=n +CONFIG_NET_MGMT_EVENT_STACK_SIZE=512 +CONFIG_IEEE802154_RF2XX_RX_STACK_SIZE=512 + +CONFIG_UART_USE_RUNTIME_CONFIGURE=n +CONFIG_NET_CONTEXT_REUSEADDR=n +CONFIG_NET_CONTEXT_REUSEPORT=n From 3cfa2296a6aed2e326166d521a3fd1978abb29a9 Mon Sep 17 00:00:00 2001 From: Grzegorz Swiderski Date: Fri, 19 Jan 2024 10:10:08 +0100 Subject: [PATCH 3392/3723] dts: Move nrf_common.dtsi to the common directory MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit ... so that it can be included by ARM and RISC-V cores. For the same reason, SysTick can no longer be disabled in this common file. Signed-off-by: Grzegorz Swiderski Signed-off-by: Andrzej Głąbek --- dts/arm/nordic/nrf51822.dtsi | 2 +- dts/arm/nordic/nrf52805.dtsi | 7 ++++++- dts/arm/nordic/nrf52810.dtsi | 7 ++++++- dts/arm/nordic/nrf52811.dtsi | 7 ++++++- dts/arm/nordic/nrf52820.dtsi | 7 ++++++- dts/arm/nordic/nrf52832.dtsi | 7 ++++++- dts/arm/nordic/nrf52833.dtsi | 7 ++++++- dts/arm/nordic/nrf52840.dtsi | 7 ++++++- dts/arm/nordic/nrf5340_cpuapp.dtsi | 7 ++++++- dts/arm/nordic/nrf5340_cpuappns.dtsi | 7 ++++++- dts/arm/nordic/nrf5340_cpunet.dtsi | 7 ++++++- dts/arm/nordic/nrf54l_common.dtsi | 2 +- dts/arm/nordic/nrf91.dtsi | 7 ++++++- dts/arm/nordic/nrf91ns.dtsi | 7 ++++++- dts/{arm => common}/nordic/nrf_common.dtsi | 8 -------- 15 files changed, 74 insertions(+), 22 deletions(-) rename dts/{arm => common}/nordic/nrf_common.dtsi (86%) diff --git a/dts/arm/nordic/nrf51822.dtsi b/dts/arm/nordic/nrf51822.dtsi index 499140a0fb8..b64de1d4985 100644 --- a/dts/arm/nordic/nrf51822.dtsi +++ b/dts/arm/nordic/nrf51822.dtsi @@ -1,7 +1,7 @@ /* SPDX-License-Identifier: Apache-2.0 */ #include -#include "nrf_common.dtsi" +#include / { chosen { diff --git a/dts/arm/nordic/nrf52805.dtsi b/dts/arm/nordic/nrf52805.dtsi index c8839897f3c..c5a184d5e28 100644 --- a/dts/arm/nordic/nrf52805.dtsi +++ b/dts/arm/nordic/nrf52805.dtsi @@ -5,7 +5,7 @@ */ #include -#include "nrf_common.dtsi" +#include / { chosen { @@ -321,3 +321,8 @@ &nvic { arm,num-irq-priority-bits = <3>; }; + +&systick { + /* Use RTC for system clock, instead of SysTick. */ + status = "disabled"; +}; diff --git a/dts/arm/nordic/nrf52810.dtsi b/dts/arm/nordic/nrf52810.dtsi index cd2543ce511..1ca4a9ea378 100644 --- a/dts/arm/nordic/nrf52810.dtsi +++ b/dts/arm/nordic/nrf52810.dtsi @@ -1,7 +1,7 @@ /* SPDX-License-Identifier: Apache-2.0 */ #include -#include "nrf_common.dtsi" +#include / { chosen { @@ -347,3 +347,8 @@ &nvic { arm,num-irq-priority-bits = <3>; }; + +&systick { + /* Use RTC for system clock, instead of SysTick. */ + status = "disabled"; +}; diff --git a/dts/arm/nordic/nrf52811.dtsi b/dts/arm/nordic/nrf52811.dtsi index 4034b4958e7..63b85676587 100644 --- a/dts/arm/nordic/nrf52811.dtsi +++ b/dts/arm/nordic/nrf52811.dtsi @@ -5,7 +5,7 @@ */ #include -#include "nrf_common.dtsi" +#include / { chosen { @@ -382,3 +382,8 @@ &nvic { arm,num-irq-priority-bits = <3>; }; + +&systick { + /* Use RTC for system clock, instead of SysTick. */ + status = "disabled"; +}; diff --git a/dts/arm/nordic/nrf52820.dtsi b/dts/arm/nordic/nrf52820.dtsi index c702cd45227..f93e449b0b2 100644 --- a/dts/arm/nordic/nrf52820.dtsi +++ b/dts/arm/nordic/nrf52820.dtsi @@ -5,7 +5,7 @@ */ #include -#include "nrf_common.dtsi" +#include / { @@ -399,3 +399,8 @@ &nvic { arm,num-irq-priority-bits = <3>; }; + +&systick { + /* Use RTC for system clock, instead of SysTick. */ + status = "disabled"; +}; diff --git a/dts/arm/nordic/nrf52832.dtsi b/dts/arm/nordic/nrf52832.dtsi index d3fb288f449..ed5a21b9935 100644 --- a/dts/arm/nordic/nrf52832.dtsi +++ b/dts/arm/nordic/nrf52832.dtsi @@ -1,7 +1,7 @@ /* SPDX-License-Identifier: Apache-2.0 */ #include -#include "nrf_common.dtsi" +#include / { chosen { @@ -475,3 +475,8 @@ &nvic { arm,num-irq-priority-bits = <3>; }; + +&systick { + /* Use RTC for system clock, instead of SysTick. */ + status = "disabled"; +}; diff --git a/dts/arm/nordic/nrf52833.dtsi b/dts/arm/nordic/nrf52833.dtsi index 9ba7a85ad4a..5ac9cb2d2f8 100644 --- a/dts/arm/nordic/nrf52833.dtsi +++ b/dts/arm/nordic/nrf52833.dtsi @@ -5,7 +5,7 @@ */ #include -#include "nrf_common.dtsi" +#include / { chosen { @@ -543,3 +543,8 @@ &nvic { arm,num-irq-priority-bits = <3>; }; + +&systick { + /* Use RTC for system clock, instead of SysTick. */ + status = "disabled"; +}; diff --git a/dts/arm/nordic/nrf52840.dtsi b/dts/arm/nordic/nrf52840.dtsi index ae7a0b58ae9..20c18cf3d84 100644 --- a/dts/arm/nordic/nrf52840.dtsi +++ b/dts/arm/nordic/nrf52840.dtsi @@ -1,7 +1,7 @@ /* SPDX-License-Identifier: Apache-2.0 */ #include -#include "nrf_common.dtsi" +#include / { chosen { @@ -555,3 +555,8 @@ &nvic { arm,num-irq-priority-bits = <3>; }; + +&systick { + /* Use RTC for system clock, instead of SysTick. */ + status = "disabled"; +}; diff --git a/dts/arm/nordic/nrf5340_cpuapp.dtsi b/dts/arm/nordic/nrf5340_cpuapp.dtsi index 02b115b3cfe..e40f6241d91 100644 --- a/dts/arm/nordic/nrf5340_cpuapp.dtsi +++ b/dts/arm/nordic/nrf5340_cpuapp.dtsi @@ -5,7 +5,7 @@ */ #include -#include "nrf_common.dtsi" +#include / { cpus { @@ -115,3 +115,8 @@ &nvic { arm,num-irq-priority-bits = <3>; }; + +&systick { + /* Use RTC for system clock, instead of SysTick. */ + status = "disabled"; +}; diff --git a/dts/arm/nordic/nrf5340_cpuappns.dtsi b/dts/arm/nordic/nrf5340_cpuappns.dtsi index aa97c337067..6df1be54b34 100644 --- a/dts/arm/nordic/nrf5340_cpuappns.dtsi +++ b/dts/arm/nordic/nrf5340_cpuappns.dtsi @@ -7,7 +7,7 @@ /* .dtsi header for nRF5340 CPUAPP (Application MCU), Non-Secure domain */ #include -#include "nrf_common.dtsi" +#include / { cpus { @@ -77,3 +77,8 @@ &nvic { arm,num-irq-priority-bits = <3>; }; + +&systick { + /* Use RTC for system clock, instead of SysTick. */ + status = "disabled"; +}; diff --git a/dts/arm/nordic/nrf5340_cpunet.dtsi b/dts/arm/nordic/nrf5340_cpunet.dtsi index ae819dfb64f..8a95b3e9985 100644 --- a/dts/arm/nordic/nrf5340_cpunet.dtsi +++ b/dts/arm/nordic/nrf5340_cpunet.dtsi @@ -5,7 +5,7 @@ */ #include -#include "nrf_common.dtsi" +#include / { chosen { @@ -351,3 +351,8 @@ &nvic { arm,num-irq-priority-bits = <3>; }; + +&systick { + /* Use RTC for system clock, instead of SysTick. */ + status = "disabled"; +}; diff --git a/dts/arm/nordic/nrf54l_common.dtsi b/dts/arm/nordic/nrf54l_common.dtsi index 4fb7768bd3f..415f2471174 100644 --- a/dts/arm/nordic/nrf54l_common.dtsi +++ b/dts/arm/nordic/nrf54l_common.dtsi @@ -5,7 +5,7 @@ */ #include -#include "nrf_common.dtsi" +#include / { soc { diff --git a/dts/arm/nordic/nrf91.dtsi b/dts/arm/nordic/nrf91.dtsi index 4ed7451bb61..78502d3f086 100644 --- a/dts/arm/nordic/nrf91.dtsi +++ b/dts/arm/nordic/nrf91.dtsi @@ -5,7 +5,7 @@ */ #include -#include "nrf_common.dtsi" +#include / { cpus { @@ -106,3 +106,8 @@ &nvic { arm,num-irq-priority-bits = <3>; }; + +&systick { + /* Use RTC for system clock, instead of SysTick. */ + status = "disabled"; +}; diff --git a/dts/arm/nordic/nrf91ns.dtsi b/dts/arm/nordic/nrf91ns.dtsi index 22510b0cfac..13a82c442e0 100644 --- a/dts/arm/nordic/nrf91ns.dtsi +++ b/dts/arm/nordic/nrf91ns.dtsi @@ -5,7 +5,7 @@ */ #include -#include "nrf_common.dtsi" +#include / { cpus { @@ -68,3 +68,8 @@ &nvic { arm,num-irq-priority-bits = <3>; }; + +&systick { + /* Use RTC for system clock, instead of SysTick. */ + status = "disabled"; +}; diff --git a/dts/arm/nordic/nrf_common.dtsi b/dts/common/nordic/nrf_common.dtsi similarity index 86% rename from dts/arm/nordic/nrf_common.dtsi rename to dts/common/nordic/nrf_common.dtsi index 8aec8dd0c89..f09557b23de 100644 --- a/dts/arm/nordic/nrf_common.dtsi +++ b/dts/common/nordic/nrf_common.dtsi @@ -43,11 +43,3 @@ #pwm-cells = <3>; }; }; - -&systick { - /* - * Nordic SoCs rely by default on the RTC for system clock - * implementation, so the SysTick node is not to be enabled. - */ - status = "disabled"; -}; From 928dbb58c2c4a9d3283a6856e3728b6a77f4e22e Mon Sep 17 00:00:00 2001 From: Gerard Marull-Paretas Date: Wed, 24 Jan 2024 15:58:47 +0100 Subject: [PATCH 3393/3723] dt-bindings: misc: add nordic,nrf-ficr helper definitions Add definitions to access all FICR fields in the nRF54H20 EngA SoC. Signed-off-by: Gerard Marull-Paretas --- .../misc/nordic-nrf-ficr-nrf54h20-enga.h | 96 +++++++++++++++++++ 1 file changed, 96 insertions(+) create mode 100644 include/zephyr/dt-bindings/misc/nordic-nrf-ficr-nrf54h20-enga.h diff --git a/include/zephyr/dt-bindings/misc/nordic-nrf-ficr-nrf54h20-enga.h b/include/zephyr/dt-bindings/misc/nordic-nrf-ficr-nrf54h20-enga.h new file mode 100644 index 00000000000..60b788a3516 --- /dev/null +++ b/include/zephyr/dt-bindings/misc/nordic-nrf-ficr-nrf54h20-enga.h @@ -0,0 +1,96 @@ +/* + * Copyright (c) 2024 Nordic Semiconductor ASA + * SPDX-License-Identifier: Apache-2.0 + */ + +/* autogenerated using Nordic HAL utils/gen_offsets.py script */ + +#ifndef ZEPHYR_INCLUDE_DT_BINDINGS_MISC_NORDIC_NRF_FICR_NRF54H20_ENGA_H_ +#define ZEPHYR_INCLUDE_DT_BINDINGS_MISC_NORDIC_NRF_FICR_NRF54H20_ENGA_H_ + +#define NRF_FICR_BLE_ADDRTYPE 0x00CU +#define NRF_FICR_BLE_ADDR_0 0x010U +#define NRF_FICR_BLE_ADDR_1 0x014U +#define NRF_FICR_BLE_ER_0 0x018U +#define NRF_FICR_BLE_ER_1 0x01CU +#define NRF_FICR_BLE_ER_2 0x020U +#define NRF_FICR_BLE_ER_3 0x024U +#define NRF_FICR_BLE_IR_0 0x028U +#define NRF_FICR_BLE_IR_1 0x02CU +#define NRF_FICR_BLE_IR_2 0x030U +#define NRF_FICR_BLE_IR_3 0x034U +#define NRF_FICR_NFC_TAGHEADER_0 0x040U +#define NRF_FICR_NFC_TAGHEADER_1 0x044U +#define NRF_FICR_NFC_TAGHEADER_2 0x048U +#define NRF_FICR_NFC_TAGHEADER_3 0x04CU +#define NRF_FICR_INFO_CONFIGID 0x050U +#define NRF_FICR_INFO_PART 0x054U +#define NRF_FICR_INFO_VARIANT 0x058U +#define NRF_FICR_INFO_PACKAGE 0x05CU +#define NRF_FICR_INFO_RAM 0x060U +#define NRF_FICR_INFO_MRAM 0x064U +#define NRF_FICR_INFO_CODEPAGESIZE 0x068U +#define NRF_FICR_INFO_CODESIZE 0x06CU +#define NRF_FICR_INFO_DEVICETYPE 0x070U +#define NRF_FICR_TRIM_GLOBAL_SAADC_CALVREF 0x384U +#define NRF_FICR_TRIM_GLOBAL_SAADC_CALGAIN_0 0x388U +#define NRF_FICR_TRIM_GLOBAL_SAADC_CALGAIN_1 0x38CU +#define NRF_FICR_TRIM_GLOBAL_SAADC_CALGAIN_2 0x390U +#define NRF_FICR_TRIM_GLOBAL_SAADC_CALOFFSET 0x394U +#define NRF_FICR_TRIM_GLOBAL_SAADC_LINCALCOEFF_0 0x398U +#define NRF_FICR_TRIM_GLOBAL_SAADC_LINCALCOEFF_1 0x39CU +#define NRF_FICR_TRIM_GLOBAL_SAADC_LINCALCOEFF_2 0x3A0U +#define NRF_FICR_TRIM_GLOBAL_SAADC_LINCALCOEFF_3 0x3A4U +#define NRF_FICR_TRIM_GLOBAL_SAADC_LINCALCOEFF_4 0x3A8U +#define NRF_FICR_TRIM_GLOBAL_SAADC_LINCALCOEFF_5 0x3ACU +#define NRF_FICR_TRIM_GLOBAL_SAADC_CALIREF 0x3B0U +#define NRF_FICR_TRIM_GLOBAL_SAADC_CALVREFTC 0x3B4U +#define NRF_FICR_TRIM_GLOBAL_NFCT_BIASCFG 0x3BCU +#define NRF_FICR_TRIM_GLOBAL_CANPLL_TRIM_CTUNE 0x3C0U +#define NRF_FICR_TRIM_GLOBAL_COMP_REFTRIM 0x3D0U +#define NRF_FICR_TRIM_GLOBAL_COMP_RCALTRIM 0x3D4U +#define NRF_FICR_TRIM_APPLICATION_HSFLL_TRIM_VSUP 0x3D8U +#define NRF_FICR_TRIM_APPLICATION_HSFLL_TRIM_COARSE_0 0x3DCU +#define NRF_FICR_TRIM_APPLICATION_HSFLL_TRIM_COARSE_1 0x3E0U +#define NRF_FICR_TRIM_APPLICATION_HSFLL_TRIM_COARSE_2 0x3E4U +#define NRF_FICR_TRIM_APPLICATION_HSFLL_TRIM_COARSE_3 0x3E8U +#define NRF_FICR_TRIM_APPLICATION_HSFLL_TRIM_COARSE_4 0x3ECU +#define NRF_FICR_TRIM_APPLICATION_HSFLL_TRIM_COARSE_5 0x3F0U +#define NRF_FICR_TRIM_APPLICATION_HSFLL_TRIM_FINE_0 0x3F4U +#define NRF_FICR_TRIM_APPLICATION_HSFLL_TRIM_FINE_1 0x3F8U +#define NRF_FICR_TRIM_APPLICATION_HSFLL_TRIM_FINE_2 0x3FCU +#define NRF_FICR_TRIM_APPLICATION_HSFLL_TRIM_FINE_3 0x400U +#define NRF_FICR_TRIM_APPLICATION_HSFLL_TRIM_FINE_4 0x404U +#define NRF_FICR_TRIM_APPLICATION_HSFLL_TRIM_FINE_5 0x408U +#define NRF_FICR_TRIM_APPLICATION_MEMCONF_BLOCKTYPE_0_TRIM 0x40CU +#define NRF_FICR_TRIM_APPLICATION_MEMCONF_BLOCKTYPE_1_TRIM 0x410U +#define NRF_FICR_TRIM_APPLICATION_MEMCONF_BLOCKTYPE_2_TRIM 0x414U +#define NRF_FICR_TRIM_RADIOCORE_HSFLL_TRIM_VSUP 0x418U +#define NRF_FICR_TRIM_RADIOCORE_HSFLL_TRIM_COARSE_0 0x41CU +#define NRF_FICR_TRIM_RADIOCORE_HSFLL_TRIM_COARSE_1 0x420U +#define NRF_FICR_TRIM_RADIOCORE_HSFLL_TRIM_COARSE_2 0x424U +#define NRF_FICR_TRIM_RADIOCORE_HSFLL_TRIM_COARSE_3 0x428U +#define NRF_FICR_TRIM_RADIOCORE_HSFLL_TRIM_COARSE_4 0x42CU +#define NRF_FICR_TRIM_RADIOCORE_HSFLL_TRIM_COARSE_5 0x430U +#define NRF_FICR_TRIM_RADIOCORE_HSFLL_TRIM_FINE_0 0x434U +#define NRF_FICR_TRIM_RADIOCORE_HSFLL_TRIM_FINE_1 0x438U +#define NRF_FICR_TRIM_RADIOCORE_HSFLL_TRIM_FINE_2 0x43CU +#define NRF_FICR_TRIM_RADIOCORE_HSFLL_TRIM_FINE_3 0x440U +#define NRF_FICR_TRIM_RADIOCORE_HSFLL_TRIM_FINE_4 0x444U +#define NRF_FICR_TRIM_RADIOCORE_HSFLL_TRIM_FINE_5 0x448U +#define NRF_FICR_TRIM_RADIOCORE_MEMCONF_BLOCKTYPE_0_TRIM 0x44CU +#define NRF_FICR_TRIM_RADIOCORE_MEMCONF_BLOCKTYPE_1_TRIM 0x450U +#define NRF_FICR_TRIM_RADIOCORE_MEMCONF_BLOCKTYPE_2_TRIM 0x454U +#define NRF_FICR_TRIM_RADIOCORE_RADIO_SPHYNXANA_FSCTRL0 0x458U +#define NRF_FICR_TRIM_RADIOCORE_RADIO_SPHYNXANA_FSCTRL1 0x45CU +#define NRF_FICR_TRIM_RADIOCORE_RADIO_SPHYNXANA_FSCTRL2 0x460U +#define NRF_FICR_TRIM_RADIOCORE_RADIO_SPHYNXANA_RXCTRL 0x464U +#define NRF_FICR_TRIM_RADIOCORE_RADIO_SPHYNXANA_OVRRXTRIMCODE 0x468U +#define NRF_FICR_TRIM_RADIOCORE_RADIO_RXAGC_CALIBRATION 0x46CU +#define NRF_FICR_TRIM_RADIOCORE_RADIO_PVTTOT 0x470U +#define NRF_FICR_TRIM_RADIOCORE_RADIO_KDTC 0x474U +#define NRF_FICR_TRIM_RADIOCORE_RADIO_TXHFGAIN 0x478U +#define NRF_FICR_TRIM_RADIOCORE_RADIO_PVTTOFIX 0x47CU +#define NRF_FICR_TRIM_RADIOCORE_RADIO_LOOPGAIN 0x480U + +#endif /* ZEPHYR_INCLUDE_DT_BINDINGS_MISC_NORDIC_NRF_FICR_NRF54H20_ENGA_H_ */ From 6bce7898291b86d8d5b1ea929e49fd7bd7a3988e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andrzej=20G=C5=82=C4=85bek?= Date: Wed, 31 Jan 2024 18:10:55 +0100 Subject: [PATCH 3394/3723] dts: Add and extend Nordic bindings needed for nRF54H20 MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Add a set of bindings that will be used in the nRF54H20 SoC definition. Extend the existing GPIOTE binding with properties needed for this SoC. Also do a tiny clean-up in the bindings added recently for nRF54L15 (HFXO and LFXO). Signed-off-by: Grzegorz Swiderski Signed-off-by: Gerard Marull-Paretas Signed-off-by: Andrzej Głąbek --- dts/bindings/arm/nordic,nrf-uicr-v2.yaml | 26 ++++++ dts/bindings/clock/nordic,nrf-hfxo.yaml | 2 +- dts/bindings/clock/nordic,nrf-hsfll.yaml | 65 ++++++++++++++ dts/bindings/clock/nordic,nrf-lfxo.yaml | 2 +- dts/bindings/cpu/nordic,vpr.yaml | 18 ++++ dts/bindings/gpio/nordic,nrf-gpiote.yaml | 4 +- .../interrupt-controller/nordic,nrf-clic.yaml | 19 ++++ dts/bindings/mtd/nordic,mram.yaml | 12 +++ dts/bindings/mtd/nordic,owned-partitions.yaml | 89 +++++++++++++++++++ .../reserved-memory/nordic,owned-memory.yaml | 46 ++++++++++ .../riscv/nordic,nrf-vpr-coprocessor.yaml | 29 ++++++ 11 files changed, 309 insertions(+), 3 deletions(-) create mode 100644 dts/bindings/arm/nordic,nrf-uicr-v2.yaml create mode 100644 dts/bindings/clock/nordic,nrf-hsfll.yaml create mode 100644 dts/bindings/cpu/nordic,vpr.yaml create mode 100644 dts/bindings/interrupt-controller/nordic,nrf-clic.yaml create mode 100644 dts/bindings/mtd/nordic,mram.yaml create mode 100644 dts/bindings/mtd/nordic,owned-partitions.yaml create mode 100644 dts/bindings/reserved-memory/nordic,owned-memory.yaml create mode 100644 dts/bindings/riscv/nordic,nrf-vpr-coprocessor.yaml diff --git a/dts/bindings/arm/nordic,nrf-uicr-v2.yaml b/dts/bindings/arm/nordic,nrf-uicr-v2.yaml new file mode 100644 index 00000000000..f509fdf4061 --- /dev/null +++ b/dts/bindings/arm/nordic,nrf-uicr-v2.yaml @@ -0,0 +1,26 @@ +# Copyright (c) 2024 Nordic Semiconductor ASA +# SPDX-License-Identifier: Apache-2.0 + +description: Nordic UICR v2 (User Information Configuration Registers) + +compatible: "nordic,nrf-uicr-v2" + +include: base.yaml + +properties: + reg: + required: true + + domain: + type: int + required: true + description: | + Domain ID of the domain associated with this UICR instance. Must be unique + across all UICR instances in the system. + + ptr-ext-uicr: + type: phandle + required: true + description: | + Handle of a memory region reserved to contain an Extended UICR instance. + The address of that node will be stored in the UICR.PTREXTUICR register. diff --git a/dts/bindings/clock/nordic,nrf-hfxo.yaml b/dts/bindings/clock/nordic,nrf-hfxo.yaml index dc99c67e5cc..cd82e1c34d3 100644 --- a/dts/bindings/clock/nordic,nrf-hfxo.yaml +++ b/dts/bindings/clock/nordic,nrf-hfxo.yaml @@ -5,7 +5,7 @@ description: Nordic nRF high-frequency crystal oscillator compatible: "nordic,nrf-hfxo" -include: [fixed-clock.yaml] +include: fixed-clock.yaml properties: clock-frequency: diff --git a/dts/bindings/clock/nordic,nrf-hsfll.yaml b/dts/bindings/clock/nordic,nrf-hsfll.yaml new file mode 100644 index 00000000000..3614d80870f --- /dev/null +++ b/dts/bindings/clock/nordic,nrf-hsfll.yaml @@ -0,0 +1,65 @@ +# Copyright (c) 2024 Nordic Semiconductor ASA +# SPDX-License-Identifier: Apache-2.0 + +description: | + Nordic nRF HSFLL + + The HSFLL mixed-mode IP generates several clock frequencies in the range from + 64 MHz to 400 MHz (in steps of 16 MHz). + + Usage example: + + hsfll: clock@deadbeef { + compatible = "nordic,nrf-hsfll"; + reg = <0xdeadbeef 0x1000>; + clocks = <&fll16m>; + clock-frequency = ; + nordic,ficrs = <&ficr NRF_FICR_TRIM_APPLICATION_HSFLL_TRIM_VSUP>, + <&ficr NRF_FICR_TRIM_APPLICATION_HSFLL_TRIM_COARSE_0>, + <&ficr NRF_FICR_TRIM_APPLICATION_HSFLL_TRIM_FINE_0>; + nordic,ficr-names = "vsup", "coarse", "fine"; + }; + + Required FICR entries are for VSUP, COARSE and FINE trim values. + +compatible: "nordic,nrf-hsfll" + +include: [base.yaml, fixed-clock.yaml, nordic-nrf-ficr-client.yaml] + +properties: + reg: + required: true + + clocks: + required: true + + clock-frequency: + enum: + - 64000000 + - 80000000 + - 96000000 + - 112000000 + - 128000000 + - 144000000 + - 160000000 + - 176000000 + - 192000000 + - 208000000 + - 224000000 + - 240000000 + - 256000000 + - 272000000 + - 288000000 + - 304000000 + - 320000000 + - 336000000 + - 352000000 + - 368000000 + - 384000000 + - 400000000 + + nordic,ficrs: + required: true + + nordic,ficr-names: + required: true diff --git a/dts/bindings/clock/nordic,nrf-lfxo.yaml b/dts/bindings/clock/nordic,nrf-lfxo.yaml index f0090ff4a81..328c374769c 100644 --- a/dts/bindings/clock/nordic,nrf-lfxo.yaml +++ b/dts/bindings/clock/nordic,nrf-lfxo.yaml @@ -5,7 +5,7 @@ description: Nordic nRF low-frequency crystal oscillator compatible: "nordic,nrf-lfxo" -include: [fixed-clock.yaml] +include: fixed-clock.yaml properties: clock-frequency: diff --git a/dts/bindings/cpu/nordic,vpr.yaml b/dts/bindings/cpu/nordic,vpr.yaml new file mode 100644 index 00000000000..11146f89c51 --- /dev/null +++ b/dts/bindings/cpu/nordic,vpr.yaml @@ -0,0 +1,18 @@ +# Copyright (c) 2024 Nordic Semiconductor ASA +# SPDX-License-Identifier: Apache-2.0 + +description: Nordic Semiconductor RISC-V VPR CPU + +compatible: "nordic,vpr" + +include: riscv,cpus.yaml + +properties: + nordic,bus-width: + type: int + enum: + - 32 + - 64 + required: true + description: + Bus width of the CPU. diff --git a/dts/bindings/gpio/nordic,nrf-gpiote.yaml b/dts/bindings/gpio/nordic,nrf-gpiote.yaml index cefc3385afe..4bb09574e9b 100644 --- a/dts/bindings/gpio/nordic,nrf-gpiote.yaml +++ b/dts/bindings/gpio/nordic,nrf-gpiote.yaml @@ -5,7 +5,9 @@ description: NRF5 GPIOTE node compatible: "nordic,nrf-gpiote" -include: base.yaml +include: + - base.yaml + - nordic,split-channels.yaml properties: reg: diff --git a/dts/bindings/interrupt-controller/nordic,nrf-clic.yaml b/dts/bindings/interrupt-controller/nordic,nrf-clic.yaml new file mode 100644 index 00000000000..f570e668ea5 --- /dev/null +++ b/dts/bindings/interrupt-controller/nordic,nrf-clic.yaml @@ -0,0 +1,19 @@ +# Copyright (c) 2024 Nordic Semiconductor ASA +# SPDX-License-Identifier: Apache-2.0 + +description: Nordic VPR CLIC + +compatible: "nordic,nrf-clic" + +include: [interrupt-controller.yaml, base.yaml] + +properties: + reg: + required: true + + "#interrupt-cells": + const: 2 + +interrupt-cells: + - irq + - priority diff --git a/dts/bindings/mtd/nordic,mram.yaml b/dts/bindings/mtd/nordic,mram.yaml new file mode 100644 index 00000000000..dac7d14305d --- /dev/null +++ b/dts/bindings/mtd/nordic,mram.yaml @@ -0,0 +1,12 @@ +# Copyright (c) 2024 Nordic Semiconductor ASA +# SPDX-License-Identifier: Apache-2.0 + +description: Nordic MRAM + +compatible: nordic,mram + +include: soc-nv-flash.yaml + +properties: + reg: + required: true diff --git a/dts/bindings/mtd/nordic,owned-partitions.yaml b/dts/bindings/mtd/nordic,owned-partitions.yaml new file mode 100644 index 00000000000..bf42c13346a --- /dev/null +++ b/dts/bindings/mtd/nordic,owned-partitions.yaml @@ -0,0 +1,89 @@ +# Copyright (c) 2024 Nordic Semiconductor ASA +# SPDX-License-Identifier: Apache-2.0 + +description: | + Nordic Owned Partitions + + Memory partition table with permission attributes common to its partitions. + This is a special case of the Nordic Owned Memory binding. + + Every compatible node is expected to be a child of a memory node, where the + listed partitions belong. + + A single memory node can contain multiple partition tables, each with a + different set of permissions. For each such table, the smallest memory region + spanning the contained partitions will be recorded in the UICR. These regions + are allowed to contain gaps between the partitions, but this is discouraged. + + Example: + + mram1x: mram@e000000 { + compatible = "nordic,mram"; + reg = <0xe000000 0x200000>; + ... + + rx-partitions { + compatible = "nordic,owned-partitions"; + perm-read; + perm-execute; + #address-cells = <1>; + #size-cells = <1>; + + slot0_partition: partition@c0000 { + label = "image-0"; + reg = <0xc0000 0x40000>; + }; + }; + + rw-partitions { + compatible = "nordic,owned-partitions"; + perm-read; + perm-write; + #address-cells = <1>; + #size-cells = <1>; + + slot1_partition: partition@100000 { + label = "image-1"; + reg = <0x100000 0x50000>; + }; + storage_partition: partition@150000 { + label = "storage"; + reg = <0x150000 0x6000>; + }; + }; + }; + + From this example, two memory regions will be inferred: + + - 0x0E0C0000--0x0E100000, with read & execute permissions, containing the + partition labeled "image-0". + - 0x0E100000--0x0E156000, with read & write permissions, containing the + partitions labeled "image-1" and "storage". + +compatible: "nordic,owned-partitions" + +include: + - name: nordic,owned-memory.yaml + property-blocklist: + - reg + +properties: + "#address-cells": + required: true + + "#size-cells": + required: true + +child-binding: + description: | + Partitions in the table are defined as subnodes. Each partition must have a + size and an offset relative to the base address of the parent memory node. + + include: + - name: base.yaml + property-blocklist: + - compatible + + properties: + reg: + required: true diff --git a/dts/bindings/reserved-memory/nordic,owned-memory.yaml b/dts/bindings/reserved-memory/nordic,owned-memory.yaml new file mode 100644 index 00000000000..9b13c965ac8 --- /dev/null +++ b/dts/bindings/reserved-memory/nordic,owned-memory.yaml @@ -0,0 +1,46 @@ +# Copyright (c) 2024 Nordic Semiconductor ASA +# SPDX-License-Identifier: Apache-2.0 + +description: | + Nordic Owned Memory + + Memory region with permission attributes. Each enabled region of this kind + will be recorded in the UICR of the compiled domain. Memory ownership and + access is then configured for the domain at boot time, based on the UICR. + +compatible: "nordic,owned-memory" + +include: base.yaml + +properties: + reg: + required: true + + owner-id: + type: int + description: | + Owner ID of the domain that will own this memory region. If not defined, + the ownership will default to the domain being compiled. + + Note: owner ID is not the same as domain ID; see the product specification + for details. + + perm-read: + type: boolean + description: Owner has read access to the region. + + perm-write: + type: boolean + description: Owner has write access to the region. + + perm-execute: + type: boolean + description: Owner can execute code from the region. + + perm-secure: + type: boolean + description: Owner has secure-only access to the region. + + non-secure-callable: + type: boolean + description: Memory region is used for non-secure-callable code. diff --git a/dts/bindings/riscv/nordic,nrf-vpr-coprocessor.yaml b/dts/bindings/riscv/nordic,nrf-vpr-coprocessor.yaml new file mode 100644 index 00000000000..6be94dce25d --- /dev/null +++ b/dts/bindings/riscv/nordic,nrf-vpr-coprocessor.yaml @@ -0,0 +1,29 @@ +# Copyright (c) 2024 Nordic Semiconductor ASA +# SPDX-License-Identifier: Apache-2.0 + +compatible: "nordic,nrf-vpr-coprocessor" + +description: | + VPR coprocessor + + VPR is a RISC-V CPU implementation. VPR instances are exposed to other CPUs as + peripherals. + +include: base.yaml + +properties: + cpu: + type: int + description: | + Processor ID of the VPR core. + + execution-memory: + type: phandle + required: true + description: | + Memory area from which the VPR core will execute. + + source-memory: + type: phandle + description: | + Memory area or partition from which the VPR code will be loaded. From 50d56c9503cfcd1c75d83f095d04c8b221d9076f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andrzej=20G=C5=82=C4=85bek?= Date: Wed, 31 Jan 2024 18:22:59 +0100 Subject: [PATCH 3395/3723] dts: Add initial support for nRF54H20 EngA SoC MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Add definition of the nRF54H20 SoC revision EngA with its Application, Radio, and Peripheral Processor (PPR) cores and basic peripherals: GRTC, GPIOs, GPIOTE, and UARTs. Signed-off-by: Grzegorz Swiderski Signed-off-by: Gerard Marull-Paretas Signed-off-by: Andrzej Głąbek --- dts/arm/nordic/nrf54h20_enga_cpuapp.dtsi | 38 +++ dts/arm/nordic/nrf54h20_enga_cpurad.dtsi | 38 +++ dts/common/nordic/nrf54h20_enga.dtsi | 310 +++++++++++++++++++++ dts/riscv/nordic/nrf54h20_enga_cpuppr.dtsi | 35 +++ 4 files changed, 421 insertions(+) create mode 100644 dts/arm/nordic/nrf54h20_enga_cpuapp.dtsi create mode 100644 dts/arm/nordic/nrf54h20_enga_cpurad.dtsi create mode 100644 dts/common/nordic/nrf54h20_enga.dtsi create mode 100644 dts/riscv/nordic/nrf54h20_enga_cpuppr.dtsi diff --git a/dts/arm/nordic/nrf54h20_enga_cpuapp.dtsi b/dts/arm/nordic/nrf54h20_enga_cpuapp.dtsi new file mode 100644 index 00000000000..f51528d5733 --- /dev/null +++ b/dts/arm/nordic/nrf54h20_enga_cpuapp.dtsi @@ -0,0 +1,38 @@ +/* + * Copyright (c) 2024 Nordic Semiconductor ASA + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include + +cpu: &cpuapp {}; +systick: &cpuapp_systick {}; +nvic: &cpuapp_nvic {}; + +/delete-node/ &cpuppr; +/delete-node/ &cpurad; +/delete-node/ &cpurad_peripherals; +/delete-node/ &cpurad_ppb; +/delete-node/ &cpurad_ram0; + +/ { + soc { + compatible = "simple-bus"; + interrupt-parent = <&cpuapp_nvic>; + ranges; + }; +}; + +&cpuapp_ppb { + compatible = "simple-bus"; + ranges; +}; + +&gpiote130 { + interrupts = <105 NRF_DEFAULT_IRQ_PRIORITY>; +}; + +&grtc { + interrupts = <109 NRF_DEFAULT_IRQ_PRIORITY>; +}; diff --git a/dts/arm/nordic/nrf54h20_enga_cpurad.dtsi b/dts/arm/nordic/nrf54h20_enga_cpurad.dtsi new file mode 100644 index 00000000000..cb2767381da --- /dev/null +++ b/dts/arm/nordic/nrf54h20_enga_cpurad.dtsi @@ -0,0 +1,38 @@ +/* + * Copyright (c) 2024 Nordic Semiconductor ASA + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include + +cpu: &cpurad {}; +systick: &cpurad_systick {}; +nvic: &cpurad_nvic {}; + +/delete-node/ &cpuapp; +/delete-node/ &cpuapp_peripherals; +/delete-node/ &cpuapp_ppb; +/delete-node/ &cpuapp_ram0; +/delete-node/ &cpuppr; + +/ { + soc { + compatible = "simple-bus"; + interrupt-parent = <&cpurad_nvic>; + ranges; + }; +}; + +&cpurad_ppb { + compatible = "simple-bus"; + ranges; +}; + +&gpiote130 { + interrupts = <105 NRF_DEFAULT_IRQ_PRIORITY>; +}; + +&grtc { + interrupts = <109 NRF_DEFAULT_IRQ_PRIORITY>; +}; diff --git a/dts/common/nordic/nrf54h20_enga.dtsi b/dts/common/nordic/nrf54h20_enga.dtsi new file mode 100644 index 00000000000..1b8f7b6f9e8 --- /dev/null +++ b/dts/common/nordic/nrf54h20_enga.dtsi @@ -0,0 +1,310 @@ +/* + * Copyright (c) 2024 Nordic Semiconductor ASA + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include +#include + +#include + +/delete-node/ &sw_pwm; + +/ { + #address-cells = <1>; + #size-cells = <1>; + + cpus { + #address-cells = <1>; + #size-cells = <0>; + + cpuapp: cpu@2 { + compatible = "arm,cortex-m33"; + reg = <2>; + device_type = "cpu"; + clock-frequency = ; + }; + + cpurad: cpu@3 { + compatible = "arm,cortex-m33"; + reg = <3>; + device_type = "cpu"; + clock-frequency = ; + }; + + cpuppr: cpu@d { + compatible = "nordic,vpr"; + reg = <13>; + device_type = "cpu"; + clock-frequency = ; + riscv,isa = "rv32emc"; + nordic,bus-width = <32>; + }; + }; + + reserved-memory { + #address-cells = <1>; + #size-cells = <1>; + + cpurad_uicr_ext: memory@e1ff000 { + reg = <0xe1ff000 DT_SIZE_K(2)>; + }; + + cpuapp_uicr_ext: memory@e1ff800 { + reg = <0xe1ff800 DT_SIZE_K(2)>; + }; + }; + + clocks { + fll16m: fll16m { + compatible = "fixed-clock"; + #clock-cells = <0>; + clock-frequency = ; + }; + }; + + soc { + #address-cells = <1>; + #size-cells = <1>; + + mram1x: mram@e000000 { + compatible = "nordic,mram"; + reg = <0xe000000 DT_SIZE_K(2048)>; + write-block-size = <16>; + }; + + cpuapp_uicr: uicr@fff8000 { + compatible = "nordic,nrf-uicr-v2"; + reg = <0xfff8000 DT_SIZE_K(2)>; + domain = <2>; + ptr-ext-uicr = <&cpuapp_uicr_ext>; + }; + + cpurad_uicr: uicr@fffa000 { + compatible = "nordic,nrf-uicr-v2"; + reg = <0xfffa000 DT_SIZE_K(2)>; + domain = <3>; + ptr-ext-uicr = <&cpurad_uicr_ext>; + }; + + ficr: ficr@fffe000 { + compatible = "nordic,nrf-ficr"; + reg = <0xfffe000 DT_SIZE_K(2)>; + #nordic,ficr-cells = <1>; + }; + + cpuapp_ram0: sram@22000000 { + compatible = "mmio-sram"; + reg = <0x22000000 DT_SIZE_K(32)>; + #address-cells = <1>; + #size-cells = <1>; + ranges = <0x0 0x22000000 0x8000>; + }; + + cpurad_ram0: sram@23000000 { + compatible = "mmio-sram"; + reg = <0x23000000 DT_SIZE_K(64)>; + #address-cells = <1>; + #size-cells = <1>; + ranges = <0x0 0x23000000 0x10000>; + }; + + cpuapp_peripherals: peripheral@52000000 { + #address-cells = <1>; + #size-cells = <1>; + ranges = <0x0 0x52000000 0x1000000>; + + cpuapp_hsfll: clock@d000 { + compatible = "nordic,nrf-hsfll"; + #clock-cells = <0>; + reg = <0xd000 0x1000>; + clocks = <&fll16m>; + clock-frequency = ; + nordic,ficrs = + <&ficr NRF_FICR_TRIM_APPLICATION_HSFLL_TRIM_VSUP>, + <&ficr NRF_FICR_TRIM_APPLICATION_HSFLL_TRIM_COARSE_0>, + <&ficr NRF_FICR_TRIM_APPLICATION_HSFLL_TRIM_FINE_0>; + nordic,ficr-names = "vsup", "coarse", "fine"; + }; + }; + + cpurad_peripherals: peripheral@53000000 { + #address-cells = <1>; + #size-cells = <1>; + ranges = <0x0 0x53000000 0x1000000>; + + cpurad_hsfll: clock@d000 { + compatible = "nordic,nrf-hsfll"; + #clock-cells = <0>; + reg = <0xd000 0x1000>; + clocks = <&fll16m>; + clock-frequency = ; + nordic,ficrs = + <&ficr NRF_FICR_TRIM_RADIOCORE_HSFLL_TRIM_VSUP>, + <&ficr NRF_FICR_TRIM_RADIOCORE_HSFLL_TRIM_COARSE_1>, + <&ficr NRF_FICR_TRIM_RADIOCORE_HSFLL_TRIM_FINE_1>; + nordic,ficr-names = "vsup", "coarse", "fine"; + }; + }; + + global_peripherals: peripheral@5f000000 { + #address-cells = <1>; + #size-cells = <1>; + ranges = <0x0 0x5f000000 0x1000000>; + + cpuppr_vpr: vpr@908000 { + compatible = "nordic,nrf-vpr-coprocessor"; + reg = <0x908000 0x1000>; + status = "disabled"; + cpu = <13>; + #address-cells = <1>; + #size-cells = <1>; + ranges = <0x0 0x908000 0x4000>; + + cpuppr_clic: interrupt-controller@1000 { + compatible = "nordic,nrf-clic"; + reg = <0x1000 0x3000>; + status = "disabled"; + #interrupt-cells = <2>; + interrupt-controller; + #address-cells = <1>; + }; + }; + + gpiote130: gpiote@934000 { + compatible = "nordic,nrf-gpiote"; + reg = <0x934000 0x1000>; + status = "disabled"; + instance = <130>; + }; + + gpio0: gpio@938000 { + compatible = "nordic,nrf-gpio"; + reg = <0x938000 0x200>; + status = "disabled"; + #gpio-cells = <2>; + gpio-controller; + gpiote-instance = <&gpiote130>; + ngpios = <12>; + port = <0>; + }; + + gpio1: gpio@938200 { + compatible = "nordic,nrf-gpio"; + reg = <0x938200 0x200>; + status = "disabled"; + #gpio-cells = <2>; + gpio-controller; + gpiote-instance = <&gpiote130>; + ngpios = <12>; + port = <1>; + }; + + gpio2: gpio@938400 { + compatible = "nordic,nrf-gpio"; + reg = <0x938400 0x200>; + status = "disabled"; + #gpio-cells = <2>; + gpio-controller; + gpiote-instance = <&gpiote130>; + ngpios = <12>; + port = <2>; + }; + + gpio6: gpio@938c00 { + compatible = "nordic,nrf-gpio"; + reg = <0x938c00 0x200>; + status = "disabled"; + #gpio-cells = <2>; + gpio-controller; + ngpios = <14>; + port = <6>; + }; + + gpio7: gpio@938e00 { + compatible = "nordic,nrf-gpio"; + reg = <0x938e00 0x200>; + status = "disabled"; + #gpio-cells = <2>; + gpio-controller; + ngpios = <8>; + port = <7>; + }; + + gpio9: gpio@939200 { + compatible = "nordic,nrf-gpio"; + reg = <0x939200 0x200>; + status = "disabled"; + #gpio-cells = <2>; + gpio-controller; + gpiote-instance = <&gpiote130>; + ngpios = <6>; + port = <9>; + }; + + grtc: grtc@99c000 { + compatible = "nordic,nrf-grtc"; + reg = <0x99c000 0x1000>; + status = "disabled"; + cc-num = <16>; + }; + + uart135: uart@9c6000 { + compatible = "nordic,nrf-uarte"; + reg = <0x9c6000 0x1000>; + status = "disabled"; + current-speed = <115200>; + interrupts = <454 NRF_DEFAULT_IRQ_PRIORITY>; + }; + + uart136: uart@9d5000 { + compatible = "nordic,nrf-uarte"; + reg = <0x9d5000 0x1000>; + status = "disabled"; + current-speed = <115200>; + interrupts = <469 NRF_DEFAULT_IRQ_PRIORITY>; + }; + }; + }; + + cpuapp_ppb: cpuapp-ppb-bus { + #address-cells = <1>; + #size-cells = <1>; + + cpuapp_systick: timer@e000e010 { + compatible = "arm,armv8m-systick"; + reg = <0xe000e010 0x10>; + status = "disabled"; + }; + + cpuapp_nvic: interrupt-controller@e000e100 { + compatible = "arm,v8m-nvic"; + reg = <0xe000e100 0xc00>; + arm,num-irq-priority-bits = <3>; + #interrupt-cells = <2>; + interrupt-controller; + #address-cells = <1>; + }; + }; + + cpurad_ppb: cpurad-ppb-bus { + #address-cells = <1>; + #size-cells = <1>; + + cpurad_systick: timer@e000e010 { + compatible = "arm,armv8m-systick"; + reg = <0xe000e010 0x10>; + status = "disabled"; + }; + + cpurad_nvic: interrupt-controller@e000e100 { + compatible = "arm,v8m-nvic"; + reg = <0xe000e100 0xc00>; + arm,num-irq-priority-bits = <3>; + #interrupt-cells = <2>; + interrupt-controller; + #address-cells = <1>; + }; + }; +}; diff --git a/dts/riscv/nordic/nrf54h20_enga_cpuppr.dtsi b/dts/riscv/nordic/nrf54h20_enga_cpuppr.dtsi new file mode 100644 index 00000000000..d42a815a4b2 --- /dev/null +++ b/dts/riscv/nordic/nrf54h20_enga_cpuppr.dtsi @@ -0,0 +1,35 @@ +/* + * Copyright (c) 2024 Nordic Semiconductor ASA + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include + +cpu: &cpuppr {}; +clic: &cpuppr_clic {}; + +/delete-node/ &cpuapp; +/delete-node/ &cpuapp_peripherals; +/delete-node/ &cpuapp_ppb; +/delete-node/ &cpuapp_ram0; +/delete-node/ &cpurad; +/delete-node/ &cpurad_peripherals; +/delete-node/ &cpurad_ppb; +/delete-node/ &cpurad_ram0; + +/ { + soc { + compatible = "simple-bus"; + interrupt-parent = <&cpuppr_clic>; + ranges; + }; +}; + +&gpiote130 { + interrupts = <104 NRF_DEFAULT_IRQ_PRIORITY>; +}; + +&grtc { + interrupts = <108 NRF_DEFAULT_IRQ_PRIORITY>; +}; From 2efd34bda32febd07d9618ebb0683a445d3abb62 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andrzej=20G=C5=82=C4=85bek?= Date: Wed, 31 Jan 2024 18:34:10 +0100 Subject: [PATCH 3396/3723] modules: hal_nordic: nrfx_glue: Include cmsis_core_m_defaults.h MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit ... to cover missing __ICACHE_PRESENT and __DCACHE_PRESENT symbols that should be defined in MDK files. Signed-off-by: Andrzej Głąbek --- modules/hal_nordic/nrfx/nrfx_glue.h | 7 +++++++ soc/arm/nordic_nrf/nrf54l/soc.h | 2 -- 2 files changed, 7 insertions(+), 2 deletions(-) diff --git a/modules/hal_nordic/nrfx/nrfx_glue.h b/modules/hal_nordic/nrfx/nrfx_glue.h index 2257ea879a3..851cb8a9614 100644 --- a/modules/hal_nordic/nrfx/nrfx_glue.h +++ b/modules/hal_nordic/nrfx/nrfx_glue.h @@ -7,6 +7,13 @@ #ifndef NRFX_GLUE_H__ #define NRFX_GLUE_H__ +#if defined(CONFIG_CPU_CORTEX_M) +/* Workaround for missing __ICACHE_PRESENT and __DCACHE_PRESENT symbols in MDK + * SoC definitions. To be removed when this is fixed. + */ +#include +#endif + #include #include #include diff --git a/soc/arm/nordic_nrf/nrf54l/soc.h b/soc/arm/nordic_nrf/nrf54l/soc.h index 721e9336989..b775fa9d0f3 100644 --- a/soc/arm/nordic_nrf/nrf54l/soc.h +++ b/soc/arm/nordic_nrf/nrf54l/soc.h @@ -11,8 +11,6 @@ #ifndef _NORDICSEMI_NRF54L_SOC_H_ #define _NORDICSEMI_NRF54L_SOC_H_ -#define __ICACHE_PRESENT 1 - #include #define FLASH_PAGE_ERASE_MAX_TIME_US 8000UL From 139b97a64af4414963cbe5de1f0fea3bc7a4f969 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andrzej=20G=C5=82=C4=85bek?= Date: Thu, 1 Feb 2024 09:40:57 +0100 Subject: [PATCH 3397/3723] modules: hal_nordic: Use common nrfx_config section for GRTC MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Move code that prepares `NRFX_CONFIG_GRTC_*` definitions based on information from devicetree from the nRF54L15 nrfx_config header to the global one, so that the code can be used by nRF54H20, too. The checks that validate owned-channels and child-owned-channels DT properties are moved to the nrf_grtc_timer driver so that the global nrfx_config is not polluted unnecessarily. The default values in nrfx_config_nrf54l15_enga_application.h are restored to those from the corresponding template file. Signed-off-by: Andrzej Głąbek --- drivers/timer/nrf_grtc_timer.c | 14 ++++++- modules/hal_nordic/nrfx/nrfx_config.h | 21 ++++++++++ .../nrfx_config_nrf54l15_enga_application.h | 38 ++++++------------- 3 files changed, 44 insertions(+), 29 deletions(-) diff --git a/drivers/timer/nrf_grtc_timer.c b/drivers/timer/nrf_grtc_timer.c index dc6ac410905..a706c04bae0 100644 --- a/drivers/timer/nrf_grtc_timer.c +++ b/drivers/timer/nrf_grtc_timer.c @@ -13,6 +13,18 @@ #include #include +#define GRTC_NODE DT_NODELABEL(grtc) + +/* Ensure that GRTC properties in devicetree are defined correctly. */ +#if !DT_NODE_HAS_PROP(GRTC_NODE, owned_channels) +#error GRTC owned-channels DT property is not defined +#endif +#define OWNED_CHANNELS_MASK NRFX_CONFIG_GRTC_MASK_DT(owned_channels) +#define CHILD_OWNED_CHANNELS_MASK NRFX_CONFIG_GRTC_MASK_DT(child_owned_channels) +#if ((OWNED_CHANNELS_MASK | CHILD_OWNED_CHANNELS_MASK) != OWNED_CHANNELS_MASK) +#error GRTC child-owned-channels DT property must be a subset of owned-channels +#endif + #define CHAN_COUNT NRFX_GRTC_CONFIG_NUM_OF_CC_CHANNELS #define EXT_CHAN_COUNT (CHAN_COUNT - 1) /* The reset value of waketime is 1, which doesn't seem to work. @@ -22,8 +34,6 @@ #define WAKETIME (4) #define TIMEOUT (WAKETIME + 1) -#define GRTC_NODE DT_NODELABEL(grtc) - #ifndef GRTC_SYSCOUNTERL_VALUE_Msk #define GRTC_SYSCOUNTERL_VALUE_Msk GRTC_SYSCOUNTER_SYSCOUNTERL_VALUE_Msk #endif diff --git a/modules/hal_nordic/nrfx/nrfx_config.h b/modules/hal_nordic/nrfx/nrfx_config.h index 543329b4a30..d315fd2622c 100644 --- a/modules/hal_nordic/nrfx/nrfx_config.h +++ b/modules/hal_nordic/nrfx/nrfx_config.h @@ -675,6 +675,27 @@ #define NRF_PERIPH(P) P##_S #endif +/* If the GRTC system timer driver is to be used, prepare definitions required + * by the nrfx_grtc driver (NRFX_GRTC_CONFIG_ALLOWED_CC_CHANNELS_MASK and + * NRFX_GRTC_CONFIG_NUM_OF_CC_CHANNELS) based on information from devicetree. + */ +#if DT_HAS_COMPAT_STATUS_OKAY(nordic_nrf_grtc) +#define NRFX_CONFIG_BIT_DT(node_id, prop, idx) \ + BIT(DT_PROP_BY_IDX(node_id, prop, idx)) +#define NRFX_CONFIG_GRTC_MASK_DT(prop) \ + (COND_CODE_1(DT_NODE_HAS_PROP(DT_INST(0, nordic_nrf_grtc), prop), \ + (DT_FOREACH_PROP_ELEM_SEP(DT_INST(0, nordic_nrf_grtc), prop, \ + NRFX_CONFIG_BIT_DT, (|))), \ + (0))) + +#define NRFX_GRTC_CONFIG_ALLOWED_CC_CHANNELS_MASK \ + (NRFX_CONFIG_GRTC_MASK_DT(owned_channels) & \ + ~NRFX_CONFIG_GRTC_MASK_DT(child_owned_channels)) +#define NRFX_GRTC_CONFIG_NUM_OF_CC_CHANNELS \ + (DT_PROP_LEN_OR(DT_INST(0, nordic_nrf_grtc), owned_channels, 0) - \ + DT_PROP_LEN_OR(DT_INST(0, nordic_nrf_grtc), child_owned_channels, 0)) +#endif /* DT_HAS_COMPAT_STATUS_OKAY(nordic_nrf_grtc) */ + #include #if defined(NRF51) #include diff --git a/modules/hal_nordic/nrfx/nrfx_config_nrf54l15_enga_application.h b/modules/hal_nordic/nrfx/nrfx_config_nrf54l15_enga_application.h index 46b0aa0eff7..a694a07955d 100644 --- a/modules/hal_nordic/nrfx/nrfx_config_nrf54l15_enga_application.h +++ b/modules/hal_nordic/nrfx/nrfx_config_nrf54l15_enga_application.h @@ -249,37 +249,21 @@ #define NRFX_GRTC_ENABLED 0 #endif +/** + * @brief NRFX_GRTC_CONFIG_NUM_OF_CC_CHANNELS + * + * Integer value. + */ +#ifndef NRFX_GRTC_CONFIG_NUM_OF_CC_CHANNELS +#define NRFX_GRTC_CONFIG_NUM_OF_CC_CHANNELS 11 +#endif + /** * @brief GRTC CC channels ownership mask. */ #ifndef NRFX_GRTC_CONFIG_ALLOWED_CC_CHANNELS_MASK -#if DT_HAS_COMPAT_STATUS_OKAY(nordic_nrf_grtc) -#if DT_NODE_HAS_PROP(DT_INST(0, nordic_nrf_grtc), owned_channels) -#define NRFX_CONFIG_BIT_DT(node_id, prop, idx) \ - BIT(DT_PROP_BY_IDX(node_id, prop, idx)) -#define NRFX_CONFIG_GRTC_MASK_DT(prop) \ - (COND_CODE_1(DT_NODE_HAS_PROP(DT_INST(0, nordic_nrf_grtc), prop), \ - (DT_FOREACH_PROP_ELEM_SEP(DT_INST(0, nordic_nrf_grtc), prop, \ - NRFX_CONFIG_BIT_DT, (|))), \ - (0))) - -#define NRFX_GRTC_CONFIG_ALLOWED_CC_CHANNELS_MASK \ - (NRFX_CONFIG_GRTC_MASK_DT(owned_channels) & \ - ~NRFX_CONFIG_GRTC_MASK_DT(child_owned_channels)) -#define NRFX_GRTC_CONFIG_NUM_OF_CC_CHANNELS \ - (DT_PROP_LEN_OR(DT_INST(0, nordic_nrf_grtc), owned_channels, 0) - \ - DT_PROP_LEN_OR(DT_INST(0, nordic_nrf_grtc), child_owned_channels, 0)) - -#if ((NRFX_CONFIG_GRTC_MASK_DT(owned_channels) | \ - NRFX_CONFIG_GRTC_MASK_DT(child_owned_channels)) != NRFX_CONFIG_GRTC_MASK_DT(owned_channels)) -#error "`child-owned-channels` property must be a subset of `owned-channels` property" -#endif -#else -#error "property `owned-channels` does not exist" -#endif /* DT_NODE_HAS_PROP(DT_INST(0, nordic_nrf_grtc), owned_channels) */ -#endif /* DT_HAS_COMPAT_STATUS_OKAY(nordic_nrf_grtc) */ - -#endif /* NRFX_GRTC_CONFIG_ALLOWED_CC_CHANNELS_MASK */ +#define NRFX_GRTC_CONFIG_ALLOWED_CC_CHANNELS_MASK 0x000007ff +#endif /** * @brief NRFX_GRTC_DEFAULT_CONFIG_IRQ_PRIORITY From abb0934deffa16d6a11dd58559faaf2984f90285 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andrzej=20G=C5=82=C4=85bek?= Date: Tue, 23 Jan 2024 17:54:21 +0100 Subject: [PATCH 3398/3723] soc: nordic: Add initial support for nRF54H20 EngA MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Add nrfx and Kconfig related infrastructure plus SoC initialization code to allow building for nRF54H20 targets (Application and Radio cores). Signed-off-by: Gerard Marull-Paretas Signed-off-by: Andrzej Głąbek --- modules/hal_nordic/nrfx/CMakeLists.txt | 6 + modules/hal_nordic/nrfx/nrfx_config.h | 4 + .../nrfx_config_nrf54h20_enga_application.h | 1935 ++++++++++++++++ .../nrfx_config_nrf54h20_enga_radiocore.h | 2016 +++++++++++++++++ soc/arm/nordic_nrf/Kconfig | 1 + soc/arm/nordic_nrf/Kconfig.defconfig | 2 +- soc/arm/nordic_nrf/nrf54h/CMakeLists.txt | 7 + .../nrf54h/Kconfig.defconfig.nrf54h20_cpuapp | 14 + .../nrf54h/Kconfig.defconfig.nrf54h20_cpurad | 14 + .../nrf54h/Kconfig.defconfig.series | 16 + soc/arm/nordic_nrf/nrf54h/Kconfig.series | 16 + soc/arm/nordic_nrf/nrf54h/Kconfig.soc | 37 + soc/arm/nordic_nrf/nrf54h/align.ld | 10 + soc/arm/nordic_nrf/nrf54h/soc.c | 104 + soc/arm/nordic_nrf/nrf54h/soc.h | 12 + 15 files changed, 4193 insertions(+), 1 deletion(-) create mode 100644 modules/hal_nordic/nrfx/nrfx_config_nrf54h20_enga_application.h create mode 100644 modules/hal_nordic/nrfx/nrfx_config_nrf54h20_enga_radiocore.h create mode 100644 soc/arm/nordic_nrf/nrf54h/CMakeLists.txt create mode 100644 soc/arm/nordic_nrf/nrf54h/Kconfig.defconfig.nrf54h20_cpuapp create mode 100644 soc/arm/nordic_nrf/nrf54h/Kconfig.defconfig.nrf54h20_cpurad create mode 100644 soc/arm/nordic_nrf/nrf54h/Kconfig.defconfig.series create mode 100644 soc/arm/nordic_nrf/nrf54h/Kconfig.series create mode 100644 soc/arm/nordic_nrf/nrf54h/Kconfig.soc create mode 100644 soc/arm/nordic_nrf/nrf54h/align.ld create mode 100644 soc/arm/nordic_nrf/nrf54h/soc.c create mode 100644 soc/arm/nordic_nrf/nrf54h/soc.h diff --git a/modules/hal_nordic/nrfx/CMakeLists.txt b/modules/hal_nordic/nrfx/CMakeLists.txt index cee9540c1e5..d1c13837d58 100644 --- a/modules/hal_nordic/nrfx/CMakeLists.txt +++ b/modules/hal_nordic/nrfx/CMakeLists.txt @@ -41,6 +41,11 @@ zephyr_compile_definitions_ifdef(CONFIG_SOC_NRF54L15_ENGA_CPUAPP NRF_APPLICATION zephyr_compile_definitions_ifdef(CONFIG_SOC_NRF9120 NRF9120_XXAA) zephyr_compile_definitions_ifdef(CONFIG_SOC_NRF9160 NRF9160_XXAA) +zephyr_compile_definitions_ifdef(CONFIG_SOC_NRF54H20_ENGA_CPUAPP NRF54H20_ENGA_XXAA + NRF_APPLICATION) +zephyr_compile_definitions_ifdef(CONFIG_SOC_NRF54H20_ENGA_CPURAD NRF54H20_ENGA_XXAA + NRF_RADIOCORE) + zephyr_compile_definitions_ifdef(CONFIG_NRF_APPROTECT_LOCK ENABLE_APPROTECT) zephyr_compile_definitions_ifdef(CONFIG_NRF_APPROTECT_USER_HANDLING @@ -71,6 +76,7 @@ zephyr_library_sources_ifdef(CONFIG_SOC_NRF52833 ${MDK_DIR}/system_nrf5283 zephyr_library_sources_ifdef(CONFIG_SOC_NRF52840 ${MDK_DIR}/system_nrf52840.c) zephyr_library_sources_ifdef(CONFIG_SOC_NRF5340_CPUAPP ${MDK_DIR}/system_nrf5340_application.c) zephyr_library_sources_ifdef(CONFIG_SOC_NRF5340_CPUNET ${MDK_DIR}/system_nrf5340_network.c) +zephyr_library_sources_ifdef(CONFIG_SOC_SERIES_NRF54HX ${MDK_DIR}/system_nrf54h.c) zephyr_library_sources_ifdef(CONFIG_SOC_SERIES_NRF54LX ${MDK_DIR}/system_nrf54l.c) zephyr_library_sources_ifdef(CONFIG_SOC_SERIES_NRF91X ${MDK_DIR}/system_nrf91.c) diff --git a/modules/hal_nordic/nrfx/nrfx_config.h b/modules/hal_nordic/nrfx/nrfx_config.h index d315fd2622c..215eff5bfcd 100644 --- a/modules/hal_nordic/nrfx/nrfx_config.h +++ b/modules/hal_nordic/nrfx/nrfx_config.h @@ -717,6 +717,10 @@ #include #elif defined(NRF5340_XXAA_NETWORK) #include +#elif defined(NRF54H20_ENGA_XXAA) && defined(NRF_APPLICATION) + #include +#elif defined(NRF54H20_ENGA_XXAA) && defined(NRF_RADIOCORE) + #include #elif defined(NRF9120_XXAA) || defined(NRF9160_XXAA) #include #elif defined(NRF54L15_ENGA_XXAA) && defined(NRF_APPLICATION) diff --git a/modules/hal_nordic/nrfx/nrfx_config_nrf54h20_enga_application.h b/modules/hal_nordic/nrfx/nrfx_config_nrf54h20_enga_application.h new file mode 100644 index 00000000000..e6c79341b9a --- /dev/null +++ b/modules/hal_nordic/nrfx/nrfx_config_nrf54h20_enga_application.h @@ -0,0 +1,1935 @@ +/* + * Copyright (c) 2024, Nordic Semiconductor ASA + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#ifndef NRFX_CONFIG_NRF54H20_ENGA_APPLICATION_H__ +#define NRFX_CONFIG_NRF54H20_ENGA_APPLICATION_H__ + +#ifndef NRFX_CONFIG_H__ +#error "This file should not be included directly. Include nrfx_config.h instead." +#endif + + +/** + * @brief NRFX_DEFAULT_IRQ_PRIORITY + * + * Integer value. Minimum: 0. Maximum: 7. + */ +#ifndef NRFX_DEFAULT_IRQ_PRIORITY +#define NRFX_DEFAULT_IRQ_PRIORITY 7 +#endif + +/** + * @brief NRFX_BELLBOARD_ENABLED + * + * Boolean. Accepted values: 0 and 1. + */ +#ifndef NRFX_BELLBOARD_ENABLED +#define NRFX_BELLBOARD_ENABLED 0 +#endif + +/** + * @brief NRFX_BELLBOARD_DEFAULT_CONFIG_IRQ_PRIORITY + * + * Integer value. Minimum: 0. Maximum: 7. + */ +#ifndef NRFX_BELLBOARD_DEFAULT_CONFIG_IRQ_PRIORITY +#define NRFX_BELLBOARD_DEFAULT_CONFIG_IRQ_PRIORITY NRFX_DEFAULT_IRQ_PRIORITY +#endif + +/** + * @brief NRFX_BELLBOARD0_ENABLED + * + * Boolean. Accepted values: 0 and 1. + */ +#ifndef NRFX_BELLBOARD0_ENABLED +#define NRFX_BELLBOARD0_ENABLED 0 +#endif + +/** + * @brief NRFX_BELLBOARD1_ENABLED + * + * Boolean. Accepted values: 0 and 1. + */ +#ifndef NRFX_BELLBOARD1_ENABLED +#define NRFX_BELLBOARD1_ENABLED 0 +#endif + +/** + * @brief NRFX_BELLBOARD2_ENABLED + * + * Boolean. Accepted values: 0 and 1. + */ +#ifndef NRFX_BELLBOARD2_ENABLED +#define NRFX_BELLBOARD2_ENABLED 0 +#endif + +/** + * @brief NRFX_BELLBOARD3_ENABLED + * + * Boolean. Accepted values: 0 and 1. + */ +#ifndef NRFX_BELLBOARD3_ENABLED +#define NRFX_BELLBOARD3_ENABLED 0 +#endif + +/** + * @brief NRFX_COMP_ENABLED + * + * Boolean. Accepted values: 0 and 1. + */ +#ifndef NRFX_COMP_ENABLED +#define NRFX_COMP_ENABLED 0 +#endif + +/** + * @brief NRFX_COMP_DEFAULT_CONFIG_IRQ_PRIORITY + * + * Integer value. Minimum: 0. Maximum: 7. + */ +#ifndef NRFX_COMP_DEFAULT_CONFIG_IRQ_PRIORITY +#define NRFX_COMP_DEFAULT_CONFIG_IRQ_PRIORITY NRFX_DEFAULT_IRQ_PRIORITY +#endif + +/** + * @brief NRFX_COMP_CONFIG_LOG_ENABLED + * + * Boolean. Accepted values: 0 and 1. + */ +#ifndef NRFX_COMP_CONFIG_LOG_ENABLED +#define NRFX_COMP_CONFIG_LOG_ENABLED 0 +#endif + +/** + * @brief NRFX_COMP_CONFIG_LOG_LEVEL + * + * Integer value. + * Supported values: + * - Off = 0 + * - Error = 1 + * - Warning = 2 + * - Info = 3 + * - Debug = 4 + */ +#ifndef NRFX_COMP_CONFIG_LOG_LEVEL +#define NRFX_COMP_CONFIG_LOG_LEVEL 3 +#endif + +/** + * @brief NRFX_DPPI_ENABLED + * + * Boolean. Accepted values: 0 and 1. + */ +#ifndef NRFX_DPPI_ENABLED +#define NRFX_DPPI_ENABLED 0 +#endif + +/** + * @brief NRFX_DPPI_CONFIG_LOG_ENABLED + * + * Boolean. Accepted values: 0 and 1. + */ +#ifndef NRFX_DPPI_CONFIG_LOG_ENABLED +#define NRFX_DPPI_CONFIG_LOG_ENABLED 0 +#endif + +/** + * @brief NRFX_DPPI_CONFIG_LOG_LEVEL + * + * Integer value. + * Supported values: + * - Off = 0 + * - Error = 1 + * - Warning = 2 + * - Info = 3 + * - Debug = 4 + */ +#ifndef NRFX_DPPI_CONFIG_LOG_LEVEL +#define NRFX_DPPI_CONFIG_LOG_LEVEL 3 +#endif + +/** + * @brief NRFX_DPPI120_PUB_CONFIG_ALLOWED_CHANNELS_MASK + */ +#ifndef NRFX_DPPI120_PUB_CONFIG_ALLOWED_CHANNELS_MASK +#define NRFX_DPPI120_PUB_CONFIG_ALLOWED_CHANNELS_MASK 0x000000f0 +#endif + +/** + * @brief NRFX_DPPI130_PUB_CONFIG_ALLOWED_CHANNELS_MASK + */ +#ifndef NRFX_DPPI130_PUB_CONFIG_ALLOWED_CHANNELS_MASK +#define NRFX_DPPI130_PUB_CONFIG_ALLOWED_CHANNELS_MASK 0x000000ff +#endif + +/** + * @brief NRFX_DPPI131_PUB_CONFIG_ALLOWED_CHANNELS_MASK + */ +#ifndef NRFX_DPPI131_PUB_CONFIG_ALLOWED_CHANNELS_MASK +#define NRFX_DPPI131_PUB_CONFIG_ALLOWED_CHANNELS_MASK 0 +#endif + +/** + * @brief NRFX_DPPI132_PUB_CONFIG_ALLOWED_CHANNELS_MASK + */ +#ifndef NRFX_DPPI132_PUB_CONFIG_ALLOWED_CHANNELS_MASK +#define NRFX_DPPI132_PUB_CONFIG_ALLOWED_CHANNELS_MASK 0 +#endif + +/** + * @brief NRFX_DPPI133_PUB_CONFIG_ALLOWED_CHANNELS_MASK + */ +#ifndef NRFX_DPPI133_PUB_CONFIG_ALLOWED_CHANNELS_MASK +#define NRFX_DPPI133_PUB_CONFIG_ALLOWED_CHANNELS_MASK 0x0000001e +#endif + +/** + * @brief NRFX_DPPI134_PUB_CONFIG_ALLOWED_CHANNELS_MASK + */ +#ifndef NRFX_DPPI134_PUB_CONFIG_ALLOWED_CHANNELS_MASK +#define NRFX_DPPI134_PUB_CONFIG_ALLOWED_CHANNELS_MASK 0x00000020 +#endif + +/** + * @brief NRFX_DPPI135_PUB_CONFIG_ALLOWED_CHANNELS_MASK + */ +#ifndef NRFX_DPPI135_PUB_CONFIG_ALLOWED_CHANNELS_MASK +#define NRFX_DPPI135_PUB_CONFIG_ALLOWED_CHANNELS_MASK 0x00000040 +#endif + +/** + * @brief NRFX_DPPI136_PUB_CONFIG_ALLOWED_CHANNELS_MASK + */ +#ifndef NRFX_DPPI136_PUB_CONFIG_ALLOWED_CHANNELS_MASK +#define NRFX_DPPI136_PUB_CONFIG_ALLOWED_CHANNELS_MASK 0x00000081 +#endif + +/** + * @brief NRFX_DPPI120_SUB_CONFIG_ALLOWED_CHANNELS_MASK + */ +#ifndef NRFX_DPPI120_SUB_CONFIG_ALLOWED_CHANNELS_MASK +#define NRFX_DPPI120_SUB_CONFIG_ALLOWED_CHANNELS_MASK 0x0000000f +#endif + +/** + * @brief NRFX_DPPI130_SUB_CONFIG_ALLOWED_CHANNELS_MASK + */ +#ifndef NRFX_DPPI130_SUB_CONFIG_ALLOWED_CHANNELS_MASK +#define NRFX_DPPI130_SUB_CONFIG_ALLOWED_CHANNELS_MASK 0x000000ff +#endif + +/** + * @brief NRFX_DPPI131_SUB_CONFIG_ALLOWED_CHANNELS_MASK + */ +#ifndef NRFX_DPPI131_SUB_CONFIG_ALLOWED_CHANNELS_MASK +#define NRFX_DPPI131_SUB_CONFIG_ALLOWED_CHANNELS_MASK 0x000000ff +#endif + +/** + * @brief NRFX_DPPI132_SUB_CONFIG_ALLOWED_CHANNELS_MASK + */ +#ifndef NRFX_DPPI132_SUB_CONFIG_ALLOWED_CHANNELS_MASK +#define NRFX_DPPI132_SUB_CONFIG_ALLOWED_CHANNELS_MASK 0 +#endif + +/** + * @brief NRFX_DPPI133_SUB_CONFIG_ALLOWED_CHANNELS_MASK + */ +#ifndef NRFX_DPPI133_SUB_CONFIG_ALLOWED_CHANNELS_MASK +#define NRFX_DPPI133_SUB_CONFIG_ALLOWED_CHANNELS_MASK 0x000000e1 +#endif + +/** + * @brief NRFX_DPPI134_SUB_CONFIG_ALLOWED_CHANNELS_MASK + */ +#ifndef NRFX_DPPI134_SUB_CONFIG_ALLOWED_CHANNELS_MASK +#define NRFX_DPPI134_SUB_CONFIG_ALLOWED_CHANNELS_MASK 0x000000df +#endif + +/** + * @brief NRFX_DPPI135_SUB_CONFIG_ALLOWED_CHANNELS_MASK + */ +#ifndef NRFX_DPPI135_SUB_CONFIG_ALLOWED_CHANNELS_MASK +#define NRFX_DPPI135_SUB_CONFIG_ALLOWED_CHANNELS_MASK 0x000000bf +#endif + +/** + * @brief NRFX_DPPI136_SUB_CONFIG_ALLOWED_CHANNELS_MASK + */ +#ifndef NRFX_DPPI136_SUB_CONFIG_ALLOWED_CHANNELS_MASK +#define NRFX_DPPI136_SUB_CONFIG_ALLOWED_CHANNELS_MASK 0x0000007e +#endif + +/** + * @brief NRFX_GPIOTE_ENABLED + * + * Boolean. Accepted values: 0 and 1. + */ +#ifndef NRFX_GPIOTE_ENABLED +#define NRFX_GPIOTE_ENABLED 0 +#endif + +/** + * @brief NRFX_GPIOTE_DEFAULT_CONFIG_IRQ_PRIORITY + * + * Integer value. Minimum: 0. Maximum: 7. + */ +#ifndef NRFX_GPIOTE_DEFAULT_CONFIG_IRQ_PRIORITY +#define NRFX_GPIOTE_DEFAULT_CONFIG_IRQ_PRIORITY NRFX_DEFAULT_IRQ_PRIORITY +#endif + +/** + * @brief NRFX_GPIOTE_CONFIG_NUM_OF_EVT_HANDLERS + * + * Integer value. Minimum: 0. Maximum: 15. + */ +#ifndef NRFX_GPIOTE_CONFIG_NUM_OF_EVT_HANDLERS +#define NRFX_GPIOTE_CONFIG_NUM_OF_EVT_HANDLERS 1 +#endif + +/** + * @brief NRFX_GPIOTE_CONFIG_LOG_ENABLED + * + * Boolean. Accepted values: 0 and 1. + */ +#ifndef NRFX_GPIOTE_CONFIG_LOG_ENABLED +#define NRFX_GPIOTE_CONFIG_LOG_ENABLED 0 +#endif + +/** + * @brief NRFX_GPIOTE_CONFIG_LOG_LEVEL + * + * Integer value. + * Supported values: + * - Off = 0 + * - Error = 1 + * - Warning = 2 + * - Info = 3 + * - Debug = 4 + */ +#ifndef NRFX_GPIOTE_CONFIG_LOG_LEVEL +#define NRFX_GPIOTE_CONFIG_LOG_LEVEL 3 +#endif + +/** + * @brief NRFX_GPIOTE130_ENABLED + * + * Boolean. Accepted values: 0 and 1. + */ +#ifndef NRFX_GPIOTE130_ENABLED +#define NRFX_GPIOTE130_ENABLED 0 +#endif + +/** + * @brief NRFX_GRTC_ENABLED + * + * Boolean. Accepted values: 0 and 1. + */ +#ifndef NRFX_GRTC_ENABLED +#define NRFX_GRTC_ENABLED 0 +#endif + +/** + * @brief NRFX_GRTC_CONFIG_NUM_OF_CC_CHANNELS + * + * Integer value. + */ +#ifndef NRFX_GRTC_CONFIG_NUM_OF_CC_CHANNELS +#define NRFX_GRTC_CONFIG_NUM_OF_CC_CHANNELS 4 +#endif + +/** + * @brief NRFX_GRTC_CONFIG_ALLOWED_CC_CHANNELS_MASK + */ +#ifndef NRFX_GRTC_CONFIG_ALLOWED_CC_CHANNELS_MASK +#define NRFX_GRTC_CONFIG_ALLOWED_CC_CHANNELS_MASK 0x000000f0 +#endif + +/** + * @brief NRFX_GRTC_DEFAULT_CONFIG_IRQ_PRIORITY + * + * Integer value. Minimum: 0. Maximum: 7. + */ +#ifndef NRFX_GRTC_DEFAULT_CONFIG_IRQ_PRIORITY +#define NRFX_GRTC_DEFAULT_CONFIG_IRQ_PRIORITY NRFX_DEFAULT_IRQ_PRIORITY +#endif + +/** + * @brief NRFX_GRTC_CONFIG_LOG_ENABLED + * + * Boolean. Accepted values: 0 and 1. + */ +#ifndef NRFX_GRTC_CONFIG_LOG_ENABLED +#define NRFX_GRTC_CONFIG_LOG_ENABLED 0 +#endif + +/** + * @brief NRFX_GRTC_CONFIG_LOG_LEVEL + * + * Integer value. + * Supported values: + * - Off = 0 + * - Error = 1 + * - Warning = 2 + * - Info = 3 + * - Debug = 4 + */ +#ifndef NRFX_GRTC_CONFIG_LOG_LEVEL +#define NRFX_GRTC_CONFIG_LOG_LEVEL 3 +#endif + +/** + * @brief NRFX_I2S_ENABLED + * + * Boolean. Accepted values: 0 and 1. + */ +#ifndef NRFX_I2S_ENABLED +#define NRFX_I2S_ENABLED 0 +#endif + +/** + * @brief NRFX_I2S_DEFAULT_CONFIG_IRQ_PRIORITY + * + * Integer value. Minimum: 0. Maximum: 7. + */ +#ifndef NRFX_I2S_DEFAULT_CONFIG_IRQ_PRIORITY +#define NRFX_I2S_DEFAULT_CONFIG_IRQ_PRIORITY NRFX_DEFAULT_IRQ_PRIORITY +#endif + +/** + * @brief NRFX_I2S_CONFIG_LOG_ENABLED + * + * Boolean. Accepted values: 0 and 1. + */ +#ifndef NRFX_I2S_CONFIG_LOG_ENABLED +#define NRFX_I2S_CONFIG_LOG_ENABLED 0 +#endif + +/** + * @brief NRFX_I2S_CONFIG_LOG_LEVEL + * + * Integer value. + * Supported values: + * - Off = 0 + * - Error = 1 + * - Warning = 2 + * - Info = 3 + * - Debug = 4 + */ +#ifndef NRFX_I2S_CONFIG_LOG_LEVEL +#define NRFX_I2S_CONFIG_LOG_LEVEL 3 +#endif + +/** + * @brief NRFX_I2S130_ENABLED + * + * Boolean. Accepted values: 0 and 1. + */ +#ifndef NRFX_I2S130_ENABLED +#define NRFX_I2S130_ENABLED 0 +#endif + +/** + * @brief NRFX_I2S131_ENABLED + * + * Boolean. Accepted values: 0 and 1. + */ +#ifndef NRFX_I2S131_ENABLED +#define NRFX_I2S131_ENABLED 0 +#endif + +/** + * @brief NRFX_IPCT_PUB_CONFIG_ALLOWED_CHANNELS_MASK + */ +#ifndef NRFX_IPCT_PUB_CONFIG_ALLOWED_CHANNELS_MASK +#define NRFX_IPCT_PUB_CONFIG_ALLOWED_CHANNELS_MASK 0x00000003 +#endif + +/** + * @brief NRFX_IPCT120_PUB_CONFIG_ALLOWED_CHANNELS_MASK + */ +#ifndef NRFX_IPCT120_PUB_CONFIG_ALLOWED_CHANNELS_MASK +#define NRFX_IPCT120_PUB_CONFIG_ALLOWED_CHANNELS_MASK 0 +#endif + +/** + * @brief NRFX_IPCT130_PUB_CONFIG_ALLOWED_CHANNELS_MASK + */ +#ifndef NRFX_IPCT130_PUB_CONFIG_ALLOWED_CHANNELS_MASK +#define NRFX_IPCT130_PUB_CONFIG_ALLOWED_CHANNELS_MASK 0x0000000c +#endif + +/** + * @brief NRFX_IPCT_SUB_CONFIG_ALLOWED_CHANNELS_MASK + */ +#ifndef NRFX_IPCT_SUB_CONFIG_ALLOWED_CHANNELS_MASK +#define NRFX_IPCT_SUB_CONFIG_ALLOWED_CHANNELS_MASK 0x0000000c +#endif + +/** + * @brief NRFX_IPCT120_SUB_CONFIG_ALLOWED_CHANNELS_MASK + */ +#ifndef NRFX_IPCT120_SUB_CONFIG_ALLOWED_CHANNELS_MASK +#define NRFX_IPCT120_SUB_CONFIG_ALLOWED_CHANNELS_MASK 0 +#endif + +/** + * @brief NRFX_IPCT130_SUB_CONFIG_ALLOWED_CHANNELS_MASK + */ +#ifndef NRFX_IPCT130_SUB_CONFIG_ALLOWED_CHANNELS_MASK +#define NRFX_IPCT130_SUB_CONFIG_ALLOWED_CHANNELS_MASK 0x00000003 +#endif + +/** + * @brief NRFX_LPCOMP_ENABLED + * + * Boolean. Accepted values: 0 and 1. + */ +#ifndef NRFX_LPCOMP_ENABLED +#define NRFX_LPCOMP_ENABLED 0 +#endif + +/** + * @brief NRFX_LPCOMP_DEFAULT_CONFIG_IRQ_PRIORITY + * + * Integer value. Minimum: 0. Maximum: 7. + */ +#ifndef NRFX_LPCOMP_DEFAULT_CONFIG_IRQ_PRIORITY +#define NRFX_LPCOMP_DEFAULT_CONFIG_IRQ_PRIORITY NRFX_DEFAULT_IRQ_PRIORITY +#endif + +/** + * @brief NRFX_LPCOMP_CONFIG_LOG_ENABLED + * + * Boolean. Accepted values: 0 and 1. + */ +#ifndef NRFX_LPCOMP_CONFIG_LOG_ENABLED +#define NRFX_LPCOMP_CONFIG_LOG_ENABLED 0 +#endif + +/** + * @brief NRFX_LPCOMP_CONFIG_LOG_LEVEL + * + * Integer value. + * Supported values: + * - Off = 0 + * - Error = 1 + * - Warning = 2 + * - Info = 3 + * - Debug = 4 + */ +#ifndef NRFX_LPCOMP_CONFIG_LOG_LEVEL +#define NRFX_LPCOMP_CONFIG_LOG_LEVEL 3 +#endif + +/** + * @brief NRFX_MVDMA_ENABLED + * + * Boolean. Accepted values: 0 and 1. + */ +#ifndef NRFX_MVDMA_ENABLED +#define NRFX_MVDMA_ENABLED 0 +#endif + +/** + * @brief NRFX_NFCT_ENABLED + * + * Boolean. Accepted values: 0 and 1. + */ +#ifndef NRFX_NFCT_ENABLED +#define NRFX_NFCT_ENABLED 0 +#endif + +/** + * @brief NRFX_NFCT_DEFAULT_CONFIG_IRQ_PRIORITY + * + * Integer value. Minimum: 0. Maximum: 7. + */ +#ifndef NRFX_NFCT_DEFAULT_CONFIG_IRQ_PRIORITY +#define NRFX_NFCT_DEFAULT_CONFIG_IRQ_PRIORITY NRFX_DEFAULT_IRQ_PRIORITY +#endif + +/** + * @brief NRFX_NFCT_CONFIG_TIMER_INSTANCE_ID - Timer instance used for workarounds in the driver. + * + * Integer value. Minimum: 0. Maximum: 5. + */ +#ifndef NRFX_NFCT_CONFIG_TIMER_INSTANCE_ID +#define NRFX_NFCT_CONFIG_TIMER_INSTANCE_ID 0 +#endif + +/** + * @brief NRFX_NFCT_CONFIG_LOG_ENABLED + * + * Boolean. Accepted values: 0 and 1. + */ +#ifndef NRFX_NFCT_CONFIG_LOG_ENABLED +#define NRFX_NFCT_CONFIG_LOG_ENABLED 0 +#endif + +/** + * @brief NRFX_NFCT_CONFIG_LOG_LEVEL + * + * Integer value. + * Supported values: + * - Off = 0 + * - Error = 1 + * - Warning = 2 + * - Info = 3 + * - Debug = 4 + */ +#ifndef NRFX_NFCT_CONFIG_LOG_LEVEL +#define NRFX_NFCT_CONFIG_LOG_LEVEL 3 +#endif + +/** + * @brief NRFX_PDM_ENABLED + * + * Boolean. Accepted values: 0 and 1. + */ +#ifndef NRFX_PDM_ENABLED +#define NRFX_PDM_ENABLED 0 +#endif + +/** + * @brief NRFX_PDM_DEFAULT_CONFIG_IRQ_PRIORITY + * + * Integer value. Minimum: 0. Maximum: 7. + */ +#ifndef NRFX_PDM_DEFAULT_CONFIG_IRQ_PRIORITY +#define NRFX_PDM_DEFAULT_CONFIG_IRQ_PRIORITY NRFX_DEFAULT_IRQ_PRIORITY +#endif + +/** + * @brief NRFX_PDM_CONFIG_LOG_ENABLED + * + * Boolean. Accepted values: 0 and 1. + */ +#ifndef NRFX_PDM_CONFIG_LOG_ENABLED +#define NRFX_PDM_CONFIG_LOG_ENABLED 0 +#endif + +/** + * @brief NRFX_PDM_CONFIG_LOG_LEVEL + * + * Integer value. + * Supported values: + * - Off = 0 + * - Error = 1 + * - Warning = 2 + * - Info = 3 + * - Debug = 4 + */ +#ifndef NRFX_PDM_CONFIG_LOG_LEVEL +#define NRFX_PDM_CONFIG_LOG_LEVEL 3 +#endif + +/** + * @brief NRFX_PRS_ENABLED + * + * Boolean. Accepted values: 0 and 1. + */ +#ifndef NRFX_PRS_ENABLED +#define NRFX_PRS_ENABLED 0 +#endif + +/** + * @brief NRFX_PRS_CONFIG_LOG_ENABLED + * + * Boolean. Accepted values: 0 and 1. + */ +#ifndef NRFX_PRS_CONFIG_LOG_ENABLED +#define NRFX_PRS_CONFIG_LOG_ENABLED 0 +#endif + +/** + * @brief NRFX_PRS_CONFIG_LOG_LEVEL + * + * Integer value. + * Supported values: + * - Off = 0 + * - Error = 1 + * - Warning = 2 + * - Info = 3 + * - Debug = 4 + */ +#ifndef NRFX_PRS_CONFIG_LOG_LEVEL +#define NRFX_PRS_CONFIG_LOG_LEVEL 3 +#endif + +/** + * @brief NRFX_PRS_BOX_0_ENABLED + * + * Boolean. Accepted values: 0 and 1. + */ +#ifndef NRFX_PRS_BOX_0_ENABLED +#define NRFX_PRS_BOX_0_ENABLED 0 +#endif + +/** + * @brief NRFX_PRS_BOX_1_ENABLED + * + * Boolean. Accepted values: 0 and 1. + */ +#ifndef NRFX_PRS_BOX_1_ENABLED +#define NRFX_PRS_BOX_1_ENABLED 0 +#endif + +/** + * @brief NRFX_PRS_BOX_2_ENABLED + * + * Boolean. Accepted values: 0 and 1. + */ +#ifndef NRFX_PRS_BOX_2_ENABLED +#define NRFX_PRS_BOX_2_ENABLED 0 +#endif + +/** + * @brief NRFX_PRS_BOX_3_ENABLED + * + * Boolean. Accepted values: 0 and 1. + */ +#ifndef NRFX_PRS_BOX_3_ENABLED +#define NRFX_PRS_BOX_3_ENABLED 0 +#endif + +/** + * @brief NRFX_PRS_BOX_4_ENABLED + * + * Boolean. Accepted values: 0 and 1. + */ +#ifndef NRFX_PRS_BOX_4_ENABLED +#define NRFX_PRS_BOX_4_ENABLED 0 +#endif + +/** + * @brief NRFX_PRS_BOX_5_ENABLED + * + * Boolean. Accepted values: 0 and 1. + */ +#ifndef NRFX_PRS_BOX_5_ENABLED +#define NRFX_PRS_BOX_5_ENABLED 0 +#endif + +/** + * @brief NRFX_PRS_BOX_6_ENABLED + * + * Boolean. Accepted values: 0 and 1. + */ +#ifndef NRFX_PRS_BOX_6_ENABLED +#define NRFX_PRS_BOX_6_ENABLED 0 +#endif + +/** + * @brief NRFX_PRS_BOX_7_ENABLED + * + * Boolean. Accepted values: 0 and 1. + */ +#ifndef NRFX_PRS_BOX_7_ENABLED +#define NRFX_PRS_BOX_7_ENABLED 0 +#endif + +/** + * @brief NRFX_PRS_BOX_8_ENABLED + * + * Boolean. Accepted values: 0 and 1. + */ +#ifndef NRFX_PRS_BOX_8_ENABLED +#define NRFX_PRS_BOX_8_ENABLED 0 +#endif + +/** + * @brief NRFX_PRS_BOX_9_ENABLED + * + * Boolean. Accepted values: 0 and 1. + */ +#ifndef NRFX_PRS_BOX_9_ENABLED +#define NRFX_PRS_BOX_9_ENABLED 0 +#endif + +/** + * @brief NRFX_PWM_ENABLED + * + * Boolean. Accepted values: 0 and 1. + */ +#ifndef NRFX_PWM_ENABLED +#define NRFX_PWM_ENABLED 0 +#endif + +/** + * @brief NRFX_PWM_DEFAULT_CONFIG_IRQ_PRIORITY + * + * Integer value. Minimum: 0. Maximum: 7. + */ +#ifndef NRFX_PWM_DEFAULT_CONFIG_IRQ_PRIORITY +#define NRFX_PWM_DEFAULT_CONFIG_IRQ_PRIORITY NRFX_DEFAULT_IRQ_PRIORITY +#endif + +/** + * @brief NRFX_PWM_CONFIG_LOG_ENABLED + * + * Boolean. Accepted values: 0 and 1. + */ +#ifndef NRFX_PWM_CONFIG_LOG_ENABLED +#define NRFX_PWM_CONFIG_LOG_ENABLED 0 +#endif + +/** + * @brief NRFX_PWM_CONFIG_LOG_LEVEL + * + * Integer value. + * Supported values: + * - Off = 0 + * - Error = 1 + * - Warning = 2 + * - Info = 3 + * - Debug = 4 + */ +#ifndef NRFX_PWM_CONFIG_LOG_LEVEL +#define NRFX_PWM_CONFIG_LOG_LEVEL 3 +#endif + +/** + * @brief NRFX_PWM120_ENABLED + * + * Boolean. Accepted values: 0 and 1. + */ +#ifndef NRFX_PWM120_ENABLED +#define NRFX_PWM120_ENABLED 0 +#endif + +/** + * @brief NRFX_PWM130_ENABLED + * + * Boolean. Accepted values: 0 and 1. + */ +#ifndef NRFX_PWM130_ENABLED +#define NRFX_PWM130_ENABLED 0 +#endif + +/** + * @brief NRFX_PWM131_ENABLED + * + * Boolean. Accepted values: 0 and 1. + */ +#ifndef NRFX_PWM131_ENABLED +#define NRFX_PWM131_ENABLED 0 +#endif + +/** + * @brief NRFX_PWM132_ENABLED + * + * Boolean. Accepted values: 0 and 1. + */ +#ifndef NRFX_PWM132_ENABLED +#define NRFX_PWM132_ENABLED 0 +#endif + +/** + * @brief NRFX_PWM133_ENABLED + * + * Boolean. Accepted values: 0 and 1. + */ +#ifndef NRFX_PWM133_ENABLED +#define NRFX_PWM133_ENABLED 0 +#endif + +/** + * @brief NRFX_QDEC_ENABLED + * + * Boolean. Accepted values: 0 and 1. + */ +#ifndef NRFX_QDEC_ENABLED +#define NRFX_QDEC_ENABLED 0 +#endif + +/** + * @brief NRFX_QDEC_DEFAULT_CONFIG_IRQ_PRIORITY + * + * Integer value. Minimum: 0. Maximum: 7. + */ +#ifndef NRFX_QDEC_DEFAULT_CONFIG_IRQ_PRIORITY +#define NRFX_QDEC_DEFAULT_CONFIG_IRQ_PRIORITY NRFX_DEFAULT_IRQ_PRIORITY +#endif + +/** + * @brief NRFX_QDEC_CONFIG_LOG_ENABLED + * + * Boolean. Accepted values: 0 and 1. + */ +#ifndef NRFX_QDEC_CONFIG_LOG_ENABLED +#define NRFX_QDEC_CONFIG_LOG_ENABLED 0 +#endif + +/** + * @brief NRFX_QDEC_CONFIG_LOG_LEVEL + * + * Integer value. + * Supported values: + * - Off = 0 + * - Error = 1 + * - Warning = 2 + * - Info = 3 + * - Debug = 4 + */ +#ifndef NRFX_QDEC_CONFIG_LOG_LEVEL +#define NRFX_QDEC_CONFIG_LOG_LEVEL 3 +#endif + +/** + * @brief NRFX_QDEC130_ENABLED + * + * Boolean. Accepted values: 0 and 1. + */ +#ifndef NRFX_QDEC130_ENABLED +#define NRFX_QDEC130_ENABLED 0 +#endif + +/** + * @brief NRFX_QDEC131_ENABLED + * + * Boolean. Accepted values: 0 and 1. + */ +#ifndef NRFX_QDEC131_ENABLED +#define NRFX_QDEC131_ENABLED 0 +#endif + +/** + * @brief NRFX_RTC_ENABLED + * + * Boolean. Accepted values: 0 and 1. + */ +#ifndef NRFX_RTC_ENABLED +#define NRFX_RTC_ENABLED 0 +#endif + +/** + * @brief NRFX_RTC_DEFAULT_CONFIG_IRQ_PRIORITY + * + * Integer value. Minimum: 0. Maximum: 7. + */ +#ifndef NRFX_RTC_DEFAULT_CONFIG_IRQ_PRIORITY +#define NRFX_RTC_DEFAULT_CONFIG_IRQ_PRIORITY NRFX_DEFAULT_IRQ_PRIORITY +#endif + +/** + * @brief NRFX_RTC_CONFIG_LOG_ENABLED + * + * Boolean. Accepted values: 0 and 1. + */ +#ifndef NRFX_RTC_CONFIG_LOG_ENABLED +#define NRFX_RTC_CONFIG_LOG_ENABLED 0 +#endif + +/** + * @brief NRFX_RTC_CONFIG_LOG_LEVEL + * + * Integer value. + * Supported values: + * - Off = 0 + * - Error = 1 + * - Warning = 2 + * - Info = 3 + * - Debug = 4 + */ +#ifndef NRFX_RTC_CONFIG_LOG_LEVEL +#define NRFX_RTC_CONFIG_LOG_LEVEL 3 +#endif + +/** + * @brief NRFX_RTC130_ENABLED + * + * Boolean. Accepted values: 0 and 1. + */ +#ifndef NRFX_RTC130_ENABLED +#define NRFX_RTC130_ENABLED 0 +#endif + +/** + * @brief NRFX_RTC131_ENABLED + * + * Boolean. Accepted values: 0 and 1. + */ +#ifndef NRFX_RTC131_ENABLED +#define NRFX_RTC131_ENABLED 0 +#endif + +/** + * @brief NRFX_SAADC_ENABLED + * + * Boolean. Accepted values: 0 and 1. + */ +#ifndef NRFX_SAADC_ENABLED +#define NRFX_SAADC_ENABLED 0 +#endif + +/** + * @brief NRFX_SAADC_DEFAULT_CONFIG_IRQ_PRIORITY + * + * Integer value. Minimum: 0. Maximum: 7. + */ +#ifndef NRFX_SAADC_DEFAULT_CONFIG_IRQ_PRIORITY +#define NRFX_SAADC_DEFAULT_CONFIG_IRQ_PRIORITY NRFX_DEFAULT_IRQ_PRIORITY +#endif + +/** + * @brief NRFX_SAADC_CONFIG_LOG_ENABLED + * + * Boolean. Accepted values: 0 and 1. + */ +#ifndef NRFX_SAADC_CONFIG_LOG_ENABLED +#define NRFX_SAADC_CONFIG_LOG_ENABLED 0 +#endif + +/** + * @brief NRFX_SAADC_CONFIG_LOG_LEVEL + * + * Integer value. + * Supported values: + * - Off = 0 + * - Error = 1 + * - Warning = 2 + * - Info = 3 + * - Debug = 4 + */ +#ifndef NRFX_SAADC_CONFIG_LOG_LEVEL +#define NRFX_SAADC_CONFIG_LOG_LEVEL 3 +#endif + +/** + * @brief NRFX_SPIM_ENABLED + * + * Boolean. Accepted values: 0 and 1. + */ +#ifndef NRFX_SPIM_ENABLED +#define NRFX_SPIM_ENABLED 0 +#endif + +/** + * @brief NRFX_SPIM_DEFAULT_CONFIG_IRQ_PRIORITY + * + * Integer value. Minimum: 0. Maximum: 7. + */ +#ifndef NRFX_SPIM_DEFAULT_CONFIG_IRQ_PRIORITY +#define NRFX_SPIM_DEFAULT_CONFIG_IRQ_PRIORITY NRFX_DEFAULT_IRQ_PRIORITY +#endif + +/** + * @brief NRFX_SPIM_CONFIG_LOG_ENABLED + * + * Boolean. Accepted values: 0 and 1. + */ +#ifndef NRFX_SPIM_CONFIG_LOG_ENABLED +#define NRFX_SPIM_CONFIG_LOG_ENABLED 0 +#endif + +/** + * @brief NRFX_SPIM_CONFIG_LOG_LEVEL + * + * Integer value. + * Supported values: + * - Off = 0 + * - Error = 1 + * - Warning = 2 + * - Info = 3 + * - Debug = 4 + */ +#ifndef NRFX_SPIM_CONFIG_LOG_LEVEL +#define NRFX_SPIM_CONFIG_LOG_LEVEL 3 +#endif + +/** + * @brief NRFX_SPIM120_ENABLED + * + * Boolean. Accepted values: 0 and 1. + */ +#ifndef NRFX_SPIM120_ENABLED +#define NRFX_SPIM120_ENABLED 0 +#endif + +/** + * @brief NRFX_SPIM121_ENABLED + * + * Boolean. Accepted values: 0 and 1. + */ +#ifndef NRFX_SPIM121_ENABLED +#define NRFX_SPIM121_ENABLED 0 +#endif + +/** + * @brief NRFX_SPIM130_ENABLED + * + * Boolean. Accepted values: 0 and 1. + */ +#ifndef NRFX_SPIM130_ENABLED +#define NRFX_SPIM130_ENABLED 0 +#endif + +/** + * @brief NRFX_SPIM131_ENABLED + * + * Boolean. Accepted values: 0 and 1. + */ +#ifndef NRFX_SPIM131_ENABLED +#define NRFX_SPIM131_ENABLED 0 +#endif + +/** + * @brief NRFX_SPIM132_ENABLED + * + * Boolean. Accepted values: 0 and 1. + */ +#ifndef NRFX_SPIM132_ENABLED +#define NRFX_SPIM132_ENABLED 0 +#endif + +/** + * @brief NRFX_SPIM133_ENABLED + * + * Boolean. Accepted values: 0 and 1. + */ +#ifndef NRFX_SPIM133_ENABLED +#define NRFX_SPIM133_ENABLED 0 +#endif + +/** + * @brief NRFX_SPIM134_ENABLED + * + * Boolean. Accepted values: 0 and 1. + */ +#ifndef NRFX_SPIM134_ENABLED +#define NRFX_SPIM134_ENABLED 0 +#endif + +/** + * @brief NRFX_SPIM135_ENABLED + * + * Boolean. Accepted values: 0 and 1. + */ +#ifndef NRFX_SPIM135_ENABLED +#define NRFX_SPIM135_ENABLED 0 +#endif + +/** + * @brief NRFX_SPIM136_ENABLED + * + * Boolean. Accepted values: 0 and 1. + */ +#ifndef NRFX_SPIM136_ENABLED +#define NRFX_SPIM136_ENABLED 0 +#endif + +/** + * @brief NRFX_SPIM137_ENABLED + * + * Boolean. Accepted values: 0 and 1. + */ +#ifndef NRFX_SPIM137_ENABLED +#define NRFX_SPIM137_ENABLED 0 +#endif + +/** + * @brief NRFX_SPIS_ENABLED + * + * Boolean. Accepted values: 0 and 1. + */ +#ifndef NRFX_SPIS_ENABLED +#define NRFX_SPIS_ENABLED 0 +#endif + +/** + * @brief NRFX_SPIS_DEFAULT_CONFIG_IRQ_PRIORITY + * + * Integer value. Minimum: 0. Maximum: 7. + */ +#ifndef NRFX_SPIS_DEFAULT_CONFIG_IRQ_PRIORITY +#define NRFX_SPIS_DEFAULT_CONFIG_IRQ_PRIORITY NRFX_DEFAULT_IRQ_PRIORITY +#endif + +/** + * @brief NRFX_SPIS_CONFIG_LOG_ENABLED + * + * Boolean. Accepted values: 0 and 1. + */ +#ifndef NRFX_SPIS_CONFIG_LOG_ENABLED +#define NRFX_SPIS_CONFIG_LOG_ENABLED 0 +#endif + +/** + * @brief NRFX_SPIS_CONFIG_LOG_LEVEL + * + * Integer value. + * Supported values: + * - Off = 0 + * - Error = 1 + * - Warning = 2 + * - Info = 3 + * - Debug = 4 + */ +#ifndef NRFX_SPIS_CONFIG_LOG_LEVEL +#define NRFX_SPIS_CONFIG_LOG_LEVEL 3 +#endif + +/** + * @brief NRFX_SPIS120_ENABLED + * + * Boolean. Accepted values: 0 and 1. + */ +#ifndef NRFX_SPIS120_ENABLED +#define NRFX_SPIS120_ENABLED 0 +#endif + +/** + * @brief NRFX_SPIS130_ENABLED + * + * Boolean. Accepted values: 0 and 1. + */ +#ifndef NRFX_SPIS130_ENABLED +#define NRFX_SPIS130_ENABLED 0 +#endif + +/** + * @brief NRFX_SPIS131_ENABLED + * + * Boolean. Accepted values: 0 and 1. + */ +#ifndef NRFX_SPIS131_ENABLED +#define NRFX_SPIS131_ENABLED 0 +#endif + +/** + * @brief NRFX_SPIS132_ENABLED + * + * Boolean. Accepted values: 0 and 1. + */ +#ifndef NRFX_SPIS132_ENABLED +#define NRFX_SPIS132_ENABLED 0 +#endif + +/** + * @brief NRFX_SPIS133_ENABLED + * + * Boolean. Accepted values: 0 and 1. + */ +#ifndef NRFX_SPIS133_ENABLED +#define NRFX_SPIS133_ENABLED 0 +#endif + +/** + * @brief NRFX_SPIS134_ENABLED + * + * Boolean. Accepted values: 0 and 1. + */ +#ifndef NRFX_SPIS134_ENABLED +#define NRFX_SPIS134_ENABLED 0 +#endif + +/** + * @brief NRFX_SPIS135_ENABLED + * + * Boolean. Accepted values: 0 and 1. + */ +#ifndef NRFX_SPIS135_ENABLED +#define NRFX_SPIS135_ENABLED 0 +#endif + +/** + * @brief NRFX_SPIS136_ENABLED + * + * Boolean. Accepted values: 0 and 1. + */ +#ifndef NRFX_SPIS136_ENABLED +#define NRFX_SPIS136_ENABLED 0 +#endif + +/** + * @brief NRFX_SPIS137_ENABLED + * + * Boolean. Accepted values: 0 and 1. + */ +#ifndef NRFX_SPIS137_ENABLED +#define NRFX_SPIS137_ENABLED 0 +#endif + +/** + * @brief NRFX_SYSTICK_ENABLED + * + * Boolean. Accepted values: 0 and 1. + */ +#ifndef NRFX_SYSTICK_ENABLED +#define NRFX_SYSTICK_ENABLED 0 +#endif + +/** + * @brief NRFX_TEMP_ENABLED + * + * Boolean. Accepted values: 0 and 1. + */ +#ifndef NRFX_TEMP_ENABLED +#define NRFX_TEMP_ENABLED 0 +#endif + +/** + * @brief NRFX_TEMP_DEFAULT_CONFIG_IRQ_PRIORITY + * + * Integer value. Minimum: 0. Maximum: 7. + */ +#ifndef NRFX_TEMP_DEFAULT_CONFIG_IRQ_PRIORITY +#define NRFX_TEMP_DEFAULT_CONFIG_IRQ_PRIORITY NRFX_DEFAULT_IRQ_PRIORITY +#endif + +/** + * @brief NRFX_TEMP_CONFIG_LOG_ENABLED + * + * Boolean. Accepted values: 0 and 1. + */ +#ifndef NRFX_TEMP_CONFIG_LOG_ENABLED +#define NRFX_TEMP_CONFIG_LOG_ENABLED 0 +#endif + +/** + * @brief NRFX_TEMP_CONFIG_LOG_LEVEL + * + * Integer value. + * Supported values: + * - Off = 0 + * - Error = 1 + * - Warning = 2 + * - Info = 3 + * - Debug = 4 + */ +#ifndef NRFX_TEMP_CONFIG_LOG_LEVEL +#define NRFX_TEMP_CONFIG_LOG_LEVEL 3 +#endif + +/** + * @brief NRFX_TIMER_ENABLED + * + * Boolean. Accepted values: 0 and 1. + */ +#ifndef NRFX_TIMER_ENABLED +#define NRFX_TIMER_ENABLED 0 +#endif + +/** + * @brief NRFX_TIMER_DEFAULT_CONFIG_IRQ_PRIORITY + * + * Integer value. Minimum: 0. Maximum: 7. + */ +#ifndef NRFX_TIMER_DEFAULT_CONFIG_IRQ_PRIORITY +#define NRFX_TIMER_DEFAULT_CONFIG_IRQ_PRIORITY NRFX_DEFAULT_IRQ_PRIORITY +#endif + +/** + * @brief NRFX_TIMER_CONFIG_LOG_ENABLED + * + * Boolean. Accepted values: 0 and 1. + */ +#ifndef NRFX_TIMER_CONFIG_LOG_ENABLED +#define NRFX_TIMER_CONFIG_LOG_ENABLED 0 +#endif + +/** + * @brief NRFX_TIMER_CONFIG_LOG_LEVEL + * + * Integer value. + * Supported values: + * - Off = 0 + * - Error = 1 + * - Warning = 2 + * - Info = 3 + * - Debug = 4 + */ +#ifndef NRFX_TIMER_CONFIG_LOG_LEVEL +#define NRFX_TIMER_CONFIG_LOG_LEVEL 3 +#endif + +/** + * @brief NRFX_TIMER120_ENABLED + * + * Boolean. Accepted values: 0 and 1. + */ +#ifndef NRFX_TIMER120_ENABLED +#define NRFX_TIMER120_ENABLED 0 +#endif + +/** + * @brief NRFX_TIMER121_ENABLED + * + * Boolean. Accepted values: 0 and 1. + */ +#ifndef NRFX_TIMER121_ENABLED +#define NRFX_TIMER121_ENABLED 0 +#endif + +/** + * @brief NRFX_TIMER130_ENABLED + * + * Boolean. Accepted values: 0 and 1. + */ +#ifndef NRFX_TIMER130_ENABLED +#define NRFX_TIMER130_ENABLED 0 +#endif + +/** + * @brief NRFX_TIMER131_ENABLED + * + * Boolean. Accepted values: 0 and 1. + */ +#ifndef NRFX_TIMER131_ENABLED +#define NRFX_TIMER131_ENABLED 0 +#endif + +/** + * @brief NRFX_TIMER132_ENABLED + * + * Boolean. Accepted values: 0 and 1. + */ +#ifndef NRFX_TIMER132_ENABLED +#define NRFX_TIMER132_ENABLED 0 +#endif + +/** + * @brief NRFX_TIMER133_ENABLED + * + * Boolean. Accepted values: 0 and 1. + */ +#ifndef NRFX_TIMER133_ENABLED +#define NRFX_TIMER133_ENABLED 0 +#endif + +/** + * @brief NRFX_TIMER134_ENABLED + * + * Boolean. Accepted values: 0 and 1. + */ +#ifndef NRFX_TIMER134_ENABLED +#define NRFX_TIMER134_ENABLED 0 +#endif + +/** + * @brief NRFX_TIMER135_ENABLED + * + * Boolean. Accepted values: 0 and 1. + */ +#ifndef NRFX_TIMER135_ENABLED +#define NRFX_TIMER135_ENABLED 0 +#endif + +/** + * @brief NRFX_TIMER136_ENABLED + * + * Boolean. Accepted values: 0 and 1. + */ +#ifndef NRFX_TIMER136_ENABLED +#define NRFX_TIMER136_ENABLED 0 +#endif + +/** + * @brief NRFX_TIMER137_ENABLED + * + * Boolean. Accepted values: 0 and 1. + */ +#ifndef NRFX_TIMER137_ENABLED +#define NRFX_TIMER137_ENABLED 0 +#endif + +/** + * @brief NRFX_TWIM_ENABLED + * + * Boolean. Accepted values: 0 and 1. + */ +#ifndef NRFX_TWIM_ENABLED +#define NRFX_TWIM_ENABLED 0 +#endif + +/** + * @brief NRFX_TWIM_DEFAULT_CONFIG_IRQ_PRIORITY + * + * Integer value. Minimum: 0. Maximum: 7. + */ +#ifndef NRFX_TWIM_DEFAULT_CONFIG_IRQ_PRIORITY +#define NRFX_TWIM_DEFAULT_CONFIG_IRQ_PRIORITY NRFX_DEFAULT_IRQ_PRIORITY +#endif + +/** + * @brief NRFX_TWIM_CONFIG_LOG_ENABLED + * + * Boolean. Accepted values: 0 and 1. + */ +#ifndef NRFX_TWIM_CONFIG_LOG_ENABLED +#define NRFX_TWIM_CONFIG_LOG_ENABLED 0 +#endif + +/** + * @brief NRFX_TWIM_CONFIG_LOG_LEVEL + * + * Integer value. + * Supported values: + * - Off = 0 + * - Error = 1 + * - Warning = 2 + * - Info = 3 + * - Debug = 4 + */ +#ifndef NRFX_TWIM_CONFIG_LOG_LEVEL +#define NRFX_TWIM_CONFIG_LOG_LEVEL 3 +#endif + +/** + * @brief NRFX_TWIM130_ENABLED + * + * Boolean. Accepted values: 0 and 1. + */ +#ifndef NRFX_TWIM130_ENABLED +#define NRFX_TWIM130_ENABLED 0 +#endif + +/** + * @brief NRFX_TWIM131_ENABLED + * + * Boolean. Accepted values: 0 and 1. + */ +#ifndef NRFX_TWIM131_ENABLED +#define NRFX_TWIM131_ENABLED 0 +#endif + +/** + * @brief NRFX_TWIM132_ENABLED + * + * Boolean. Accepted values: 0 and 1. + */ +#ifndef NRFX_TWIM132_ENABLED +#define NRFX_TWIM132_ENABLED 0 +#endif + +/** + * @brief NRFX_TWIM133_ENABLED + * + * Boolean. Accepted values: 0 and 1. + */ +#ifndef NRFX_TWIM133_ENABLED +#define NRFX_TWIM133_ENABLED 0 +#endif + +/** + * @brief NRFX_TWIM134_ENABLED + * + * Boolean. Accepted values: 0 and 1. + */ +#ifndef NRFX_TWIM134_ENABLED +#define NRFX_TWIM134_ENABLED 0 +#endif + +/** + * @brief NRFX_TWIM135_ENABLED + * + * Boolean. Accepted values: 0 and 1. + */ +#ifndef NRFX_TWIM135_ENABLED +#define NRFX_TWIM135_ENABLED 0 +#endif + +/** + * @brief NRFX_TWIM136_ENABLED + * + * Boolean. Accepted values: 0 and 1. + */ +#ifndef NRFX_TWIM136_ENABLED +#define NRFX_TWIM136_ENABLED 0 +#endif + +/** + * @brief NRFX_TWIM137_ENABLED + * + * Boolean. Accepted values: 0 and 1. + */ +#ifndef NRFX_TWIM137_ENABLED +#define NRFX_TWIM137_ENABLED 0 +#endif + +/** + * @brief NRFX_TWIS_ENABLED + * + * Boolean. Accepted values: 0 and 1. + */ +#ifndef NRFX_TWIS_ENABLED +#define NRFX_TWIS_ENABLED 0 +#endif + +/** + * @brief NRFX_TWIS_DEFAULT_CONFIG_IRQ_PRIORITY + * + * Integer value. Minimum: 0. Maximum: 7. + */ +#ifndef NRFX_TWIS_DEFAULT_CONFIG_IRQ_PRIORITY +#define NRFX_TWIS_DEFAULT_CONFIG_IRQ_PRIORITY NRFX_DEFAULT_IRQ_PRIORITY +#endif + +/** + * @brief NRFX_TWIS_CONFIG_LOG_ENABLED + * + * Boolean. Accepted values: 0 and 1. + */ +#ifndef NRFX_TWIS_CONFIG_LOG_ENABLED +#define NRFX_TWIS_CONFIG_LOG_ENABLED 0 +#endif + +/** + * @brief NRFX_TWIS_ASSUME_INIT_AFTER_RESET_ONLY - Assume that any instance + * would be initialized only once. + * + * Boolean. Accepted values: 0 and 1. + */ +#ifndef NRFX_TWIS_ASSUME_INIT_AFTER_RESET_ONLY +#define NRFX_TWIS_ASSUME_INIT_AFTER_RESET_ONLY 0 +#endif + +/** + * @brief NRFX_TWIS_NO_SYNC_MODE - Remove support for synchronous mode. + * + * Boolean. Accepted values: 0 and 1. + */ +#ifndef NRFX_TWIS_NO_SYNC_MODE +#define NRFX_TWIS_NO_SYNC_MODE 0 +#endif + +/** + * @brief NRFX_TWIS_CONFIG_LOG_LEVEL + * + * Integer value. + * Supported values: + * - Off = 0 + * - Error = 1 + * - Warning = 2 + * - Info = 3 + * - Debug = 4 + */ +#ifndef NRFX_TWIS_CONFIG_LOG_LEVEL +#define NRFX_TWIS_CONFIG_LOG_LEVEL 3 +#endif + +/** + * @brief NRFX_TWIS130_ENABLED + * + * Boolean. Accepted values: 0 and 1. + */ +#ifndef NRFX_TWIS130_ENABLED +#define NRFX_TWIS130_ENABLED 0 +#endif + +/** + * @brief NRFX_TWIS131_ENABLED + * + * Boolean. Accepted values: 0 and 1. + */ +#ifndef NRFX_TWIS131_ENABLED +#define NRFX_TWIS131_ENABLED 0 +#endif + +/** + * @brief NRFX_TWIS132_ENABLED + * + * Boolean. Accepted values: 0 and 1. + */ +#ifndef NRFX_TWIS132_ENABLED +#define NRFX_TWIS132_ENABLED 0 +#endif + +/** + * @brief NRFX_TWIS133_ENABLED + * + * Boolean. Accepted values: 0 and 1. + */ +#ifndef NRFX_TWIS133_ENABLED +#define NRFX_TWIS133_ENABLED 0 +#endif + +/** + * @brief NRFX_TWIS134_ENABLED + * + * Boolean. Accepted values: 0 and 1. + */ +#ifndef NRFX_TWIS134_ENABLED +#define NRFX_TWIS134_ENABLED 0 +#endif + +/** + * @brief NRFX_TWIS135_ENABLED + * + * Boolean. Accepted values: 0 and 1. + */ +#ifndef NRFX_TWIS135_ENABLED +#define NRFX_TWIS135_ENABLED 0 +#endif + +/** + * @brief NRFX_TWIS136_ENABLED + * + * Boolean. Accepted values: 0 and 1. + */ +#ifndef NRFX_TWIS136_ENABLED +#define NRFX_TWIS136_ENABLED 0 +#endif + +/** + * @brief NRFX_TWIS137_ENABLED + * + * Boolean. Accepted values: 0 and 1. + */ +#ifndef NRFX_TWIS137_ENABLED +#define NRFX_TWIS137_ENABLED 0 +#endif + +/** + * @brief NRFX_UARTE_ENABLED + * + * Boolean. Accepted values: 0 and 1. + */ +#ifndef NRFX_UARTE_ENABLED +#define NRFX_UARTE_ENABLED 0 +#endif + +/** + * @brief NRFX_UARTE_CONFIG_SKIP_GPIO_CONFIG - If enabled, support for + * configuring GPIO pins is removed from the driver + * + * Boolean. Accepted values: 0 and 1. + */ +#ifndef NRFX_UARTE_CONFIG_SKIP_GPIO_CONFIG +#define NRFX_UARTE_CONFIG_SKIP_GPIO_CONFIG 0 +#endif + +/** + * @brief NRFX_UARTE_CONFIG_SKIP_PSEL_CONFIG - If enabled, support for + * configuring PSEL registers is removed from the driver + * + * Boolean. Accepted values: 0 and 1. + */ +#ifndef NRFX_UARTE_CONFIG_SKIP_PSEL_CONFIG +#define NRFX_UARTE_CONFIG_SKIP_PSEL_CONFIG 0 +#endif + +/** + * @brief NRFX_UARTE_CONFIG_TX_LINK - If enabled, driver supports linking + * of TX transfers. + * + * Boolean. Accepted values: 0 and 1. + */ +#ifndef NRFX_UARTE_CONFIG_TX_LINK +#define NRFX_UARTE_CONFIG_TX_LINK 1 +#endif + +/** + * @brief NRFX_UARTE_CONFIG_RX_CACHE_ENABLED + * + * Boolean. Accepted values: 0 and 1. + */ +#ifndef NRFX_UARTE_CONFIG_RX_CACHE_ENABLED +#define NRFX_UARTE_CONFIG_RX_CACHE_ENABLED 1 +#endif + +/** + * @brief NRFX_UARTE_DEFAULT_CONFIG_IRQ_PRIORITY + * + * Integer value. Minimum: 0. Maximum: 7. + */ +#ifndef NRFX_UARTE_DEFAULT_CONFIG_IRQ_PRIORITY +#define NRFX_UARTE_DEFAULT_CONFIG_IRQ_PRIORITY NRFX_DEFAULT_IRQ_PRIORITY +#endif + +/** + * @brief NRFX_UARTE_CONFIG_LOG_ENABLED + * + * Boolean. Accepted values: 0 and 1. + */ +#ifndef NRFX_UARTE_CONFIG_LOG_ENABLED +#define NRFX_UARTE_CONFIG_LOG_ENABLED 0 +#endif + +/** + * @brief NRFX_UARTE_CONFIG_LOG_LEVEL + * + * Integer value. + * Supported values: + * - Off = 0 + * - Error = 1 + * - Warning = 2 + * - Info = 3 + * - Debug = 4 + */ +#ifndef NRFX_UARTE_CONFIG_LOG_LEVEL +#define NRFX_UARTE_CONFIG_LOG_LEVEL 3 +#endif + +/** + * @brief NRFX_UARTE120_ENABLED + * + * Boolean. Accepted values: 0 and 1. + */ +#ifndef NRFX_UARTE120_ENABLED +#define NRFX_UARTE120_ENABLED 0 +#endif + +/** + * @brief NRFX_UARTE130_ENABLED + * + * Boolean. Accepted values: 0 and 1. + */ +#ifndef NRFX_UARTE130_ENABLED +#define NRFX_UARTE130_ENABLED 0 +#endif + +/** + * @brief NRFX_UARTE131_ENABLED + * + * Boolean. Accepted values: 0 and 1. + */ +#ifndef NRFX_UARTE131_ENABLED +#define NRFX_UARTE131_ENABLED 0 +#endif + +/** + * @brief NRFX_UARTE132_ENABLED + * + * Boolean. Accepted values: 0 and 1. + */ +#ifndef NRFX_UARTE132_ENABLED +#define NRFX_UARTE132_ENABLED 0 +#endif + +/** + * @brief NRFX_UARTE133_ENABLED + * + * Boolean. Accepted values: 0 and 1. + */ +#ifndef NRFX_UARTE133_ENABLED +#define NRFX_UARTE133_ENABLED 0 +#endif + +/** + * @brief NRFX_UARTE134_ENABLED + * + * Boolean. Accepted values: 0 and 1. + */ +#ifndef NRFX_UARTE134_ENABLED +#define NRFX_UARTE134_ENABLED 0 +#endif + +/** + * @brief NRFX_UARTE135_ENABLED + * + * Boolean. Accepted values: 0 and 1. + */ +#ifndef NRFX_UARTE135_ENABLED +#define NRFX_UARTE135_ENABLED 0 +#endif + +/** + * @brief NRFX_UARTE136_ENABLED + * + * Boolean. Accepted values: 0 and 1. + */ +#ifndef NRFX_UARTE136_ENABLED +#define NRFX_UARTE136_ENABLED 0 +#endif + +/** + * @brief NRFX_UARTE137_ENABLED + * + * Boolean. Accepted values: 0 and 1. + */ +#ifndef NRFX_UARTE137_ENABLED +#define NRFX_UARTE137_ENABLED 0 +#endif + +/** + * @brief NRFX_WDT_ENABLED + * + * Boolean. Accepted values: 0 and 1. + */ +#ifndef NRFX_WDT_ENABLED +#define NRFX_WDT_ENABLED 0 +#endif + +/** + * @brief NRFX_WDT_DEFAULT_CONFIG_IRQ_PRIORITY + * + * Integer value. Minimum: 0. Maximum: 7. + */ +#ifndef NRFX_WDT_DEFAULT_CONFIG_IRQ_PRIORITY +#define NRFX_WDT_DEFAULT_CONFIG_IRQ_PRIORITY NRFX_DEFAULT_IRQ_PRIORITY +#endif + +/** + * @brief NRFX_WDT_CONFIG_NO_IRQ - Remove WDT IRQ handling from WDT driver + * + * Boolean. Accepted values: 0 and 1. + */ +#ifndef NRFX_WDT_CONFIG_NO_IRQ +#define NRFX_WDT_CONFIG_NO_IRQ 0 +#endif + +/** + * @brief NRFX_WDT_CONFIG_LOG_ENABLED + * + * Boolean. Accepted values: 0 and 1. + */ +#ifndef NRFX_WDT_CONFIG_LOG_ENABLED +#define NRFX_WDT_CONFIG_LOG_ENABLED 0 +#endif + +/** + * @brief NRFX_WDT_CONFIG_LOG_LEVEL + * + * Integer value. + * Supported values: + * - Off = 0 + * - Error = 1 + * - Warning = 2 + * - Info = 3 + * - Debug = 4 + */ +#ifndef NRFX_WDT_CONFIG_LOG_LEVEL +#define NRFX_WDT_CONFIG_LOG_LEVEL 3 +#endif + +/** + * @brief NRFX_WDT010_ENABLED + * + * Boolean. Accepted values: 0 and 1. + */ +#ifndef NRFX_WDT010_ENABLED +#define NRFX_WDT010_ENABLED 0 +#endif + +/** + * @brief NRFX_WDT011_ENABLED + * + * Boolean. Accepted values: 0 and 1. + */ +#ifndef NRFX_WDT011_ENABLED +#define NRFX_WDT011_ENABLED 0 +#endif + +/** + * @brief NRFX_WDT131_ENABLED + * + * Boolean. Accepted values: 0 and 1. + */ +#ifndef NRFX_WDT131_ENABLED +#define NRFX_WDT131_ENABLED 0 +#endif + +/** + * @brief NRFX_WDT132_ENABLED + * + * Boolean. Accepted values: 0 and 1. + */ +#ifndef NRFX_WDT132_ENABLED +#define NRFX_WDT132_ENABLED 0 +#endif + +#endif /* NRFX_CONFIG_NRF54H20_ENGA_APPLICATION_H__ */ diff --git a/modules/hal_nordic/nrfx/nrfx_config_nrf54h20_enga_radiocore.h b/modules/hal_nordic/nrfx/nrfx_config_nrf54h20_enga_radiocore.h new file mode 100644 index 00000000000..7b9a1c4b733 --- /dev/null +++ b/modules/hal_nordic/nrfx/nrfx_config_nrf54h20_enga_radiocore.h @@ -0,0 +1,2016 @@ +/* + * Copyright (c) 2024, Nordic Semiconductor ASA + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#ifndef NRFX_CONFIG_NRF54H20_ENGA_RADIOCORE_H__ +#define NRFX_CONFIG_NRF54H20_ENGA_RADIOCORE_H__ + +#ifndef NRFX_CONFIG_H__ +#error "This file should not be included directly. Include nrfx_config.h instead." +#endif + +/** + * @brief NRFX_DEFAULT_IRQ_PRIORITY + * + * Integer value. Minimum: 0. Maximum: 7. + */ +#ifndef NRFX_DEFAULT_IRQ_PRIORITY +#define NRFX_DEFAULT_IRQ_PRIORITY 7 +#endif + +/** + * @brief NRFX_BELLBOARD_ENABLED + * + * Boolean. Accepted values: 0 and 1. + */ +#ifndef NRFX_BELLBOARD_ENABLED +#define NRFX_BELLBOARD_ENABLED 0 +#endif + +/** + * @brief NRFX_BELLBOARD_DEFAULT_CONFIG_IRQ_PRIORITY + * + * Integer value. Minimum: 0. Maximum: 7. + */ +#ifndef NRFX_BELLBOARD_DEFAULT_CONFIG_IRQ_PRIORITY +#define NRFX_BELLBOARD_DEFAULT_CONFIG_IRQ_PRIORITY NRFX_DEFAULT_IRQ_PRIORITY +#endif + +/** + * @brief NRFX_BELLBOARD0_ENABLED + * + * Boolean. Accepted values: 0 and 1. + */ +#ifndef NRFX_BELLBOARD0_ENABLED +#define NRFX_BELLBOARD0_ENABLED 0 +#endif + +/** + * @brief NRFX_BELLBOARD1_ENABLED + * + * Boolean. Accepted values: 0 and 1. + */ +#ifndef NRFX_BELLBOARD1_ENABLED +#define NRFX_BELLBOARD1_ENABLED 0 +#endif + +/** + * @brief NRFX_BELLBOARD2_ENABLED + * + * Boolean. Accepted values: 0 and 1. + */ +#ifndef NRFX_BELLBOARD2_ENABLED +#define NRFX_BELLBOARD2_ENABLED 0 +#endif + +/** + * @brief NRFX_BELLBOARD3_ENABLED + * + * Boolean. Accepted values: 0 and 1. + */ +#ifndef NRFX_BELLBOARD3_ENABLED +#define NRFX_BELLBOARD3_ENABLED 0 +#endif + +/** + * @brief NRFX_COMP_ENABLED + * + * Boolean. Accepted values: 0 and 1. + */ +#ifndef NRFX_COMP_ENABLED +#define NRFX_COMP_ENABLED 0 +#endif + +/** + * @brief NRFX_COMP_DEFAULT_CONFIG_IRQ_PRIORITY + * + * Integer value. Minimum: 0. Maximum: 7. + */ +#ifndef NRFX_COMP_DEFAULT_CONFIG_IRQ_PRIORITY +#define NRFX_COMP_DEFAULT_CONFIG_IRQ_PRIORITY NRFX_DEFAULT_IRQ_PRIORITY +#endif + +/** + * @brief NRFX_COMP_CONFIG_LOG_ENABLED + * + * Boolean. Accepted values: 0 and 1. + */ +#ifndef NRFX_COMP_CONFIG_LOG_ENABLED +#define NRFX_COMP_CONFIG_LOG_ENABLED 0 +#endif + +/** + * @brief NRFX_COMP_CONFIG_LOG_LEVEL + * + * Integer value. + * Supported values: + * - Off = 0 + * - Error = 1 + * - Warning = 2 + * - Info = 3 + * - Debug = 4 + */ +#ifndef NRFX_COMP_CONFIG_LOG_LEVEL +#define NRFX_COMP_CONFIG_LOG_LEVEL 3 +#endif + +/** + * @brief NRFX_DPPI_ENABLED + * + * Boolean. Accepted values: 0 and 1. + */ +#ifndef NRFX_DPPI_ENABLED +#define NRFX_DPPI_ENABLED 0 +#endif + +/** + * @brief NRFX_DPPI_CONFIG_LOG_ENABLED + * + * Boolean. Accepted values: 0 and 1. + */ +#ifndef NRFX_DPPI_CONFIG_LOG_ENABLED +#define NRFX_DPPI_CONFIG_LOG_ENABLED 0 +#endif + +/** + * @brief NRFX_DPPI_CONFIG_LOG_LEVEL + * + * Integer value. + * Supported values: + * - Off = 0 + * - Error = 1 + * - Warning = 2 + * - Info = 3 + * - Debug = 4 + */ +#ifndef NRFX_DPPI_CONFIG_LOG_LEVEL +#define NRFX_DPPI_CONFIG_LOG_LEVEL 3 +#endif + +/** + * @brief NRFX_DPPI020_PUB_CONFIG_ALLOWED_CHANNELS_MASK + */ +#ifndef NRFX_DPPI020_PUB_CONFIG_ALLOWED_CHANNELS_MASK +#define NRFX_DPPI020_PUB_CONFIG_ALLOWED_CHANNELS_MASK 0x00000003 +#endif + +/** + * @brief NRFX_DPPI030_PUB_CONFIG_ALLOWED_CHANNELS_MASK + */ +#ifndef NRFX_DPPI030_PUB_CONFIG_ALLOWED_CHANNELS_MASK +#define NRFX_DPPI030_PUB_CONFIG_ALLOWED_CHANNELS_MASK 0x00000003 +#endif + +/** + * @brief NRFX_DPPI120_PUB_CONFIG_ALLOWED_CHANNELS_MASK + */ +#ifndef NRFX_DPPI120_PUB_CONFIG_ALLOWED_CHANNELS_MASK +#define NRFX_DPPI120_PUB_CONFIG_ALLOWED_CHANNELS_MASK 0x000000f0 +#endif + +/** + * @brief NRFX_DPPI130_PUB_CONFIG_ALLOWED_CHANNELS_MASK + */ +#ifndef NRFX_DPPI130_PUB_CONFIG_ALLOWED_CHANNELS_MASK +#define NRFX_DPPI130_PUB_CONFIG_ALLOWED_CHANNELS_MASK 0x000000ff +#endif + +/** + * @brief NRFX_DPPI131_PUB_CONFIG_ALLOWED_CHANNELS_MASK + */ +#ifndef NRFX_DPPI131_PUB_CONFIG_ALLOWED_CHANNELS_MASK +#define NRFX_DPPI131_PUB_CONFIG_ALLOWED_CHANNELS_MASK 0 +#endif + +/** + * @brief NRFX_DPPI132_PUB_CONFIG_ALLOWED_CHANNELS_MASK + */ +#ifndef NRFX_DPPI132_PUB_CONFIG_ALLOWED_CHANNELS_MASK +#define NRFX_DPPI132_PUB_CONFIG_ALLOWED_CHANNELS_MASK 0 +#endif + +/** + * @brief NRFX_DPPI133_PUB_CONFIG_ALLOWED_CHANNELS_MASK + */ +#ifndef NRFX_DPPI133_PUB_CONFIG_ALLOWED_CHANNELS_MASK +#define NRFX_DPPI133_PUB_CONFIG_ALLOWED_CHANNELS_MASK 0x0000001e +#endif + +/** + * @brief NRFX_DPPI134_PUB_CONFIG_ALLOWED_CHANNELS_MASK + */ +#ifndef NRFX_DPPI134_PUB_CONFIG_ALLOWED_CHANNELS_MASK +#define NRFX_DPPI134_PUB_CONFIG_ALLOWED_CHANNELS_MASK 0x00000020 +#endif + +/** + * @brief NRFX_DPPI135_PUB_CONFIG_ALLOWED_CHANNELS_MASK + */ +#ifndef NRFX_DPPI135_PUB_CONFIG_ALLOWED_CHANNELS_MASK +#define NRFX_DPPI135_PUB_CONFIG_ALLOWED_CHANNELS_MASK 0x00000040 +#endif + +/** + * @brief NRFX_DPPI136_PUB_CONFIG_ALLOWED_CHANNELS_MASK + */ +#ifndef NRFX_DPPI136_PUB_CONFIG_ALLOWED_CHANNELS_MASK +#define NRFX_DPPI136_PUB_CONFIG_ALLOWED_CHANNELS_MASK 0x00000081 +#endif + +/** + * @brief NRFX_DPPI020_SUB_CONFIG_ALLOWED_CHANNELS_MASK + */ +#ifndef NRFX_DPPI020_SUB_CONFIG_ALLOWED_CHANNELS_MASK +#define NRFX_DPPI020_SUB_CONFIG_ALLOWED_CHANNELS_MASK 0x0000000c +#endif + +/** + * @brief NRFX_DPPI030_SUB_CONFIG_ALLOWED_CHANNELS_MASK + */ +#ifndef NRFX_DPPI030_SUB_CONFIG_ALLOWED_CHANNELS_MASK +#define NRFX_DPPI030_SUB_CONFIG_ALLOWED_CHANNELS_MASK 0x0000000c +#endif + +/** + * @brief NRFX_DPPI120_SUB_CONFIG_ALLOWED_CHANNELS_MASK + */ +#ifndef NRFX_DPPI120_SUB_CONFIG_ALLOWED_CHANNELS_MASK +#define NRFX_DPPI120_SUB_CONFIG_ALLOWED_CHANNELS_MASK 0x0000000f +#endif + +/** + * @brief NRFX_DPPI130_SUB_CONFIG_ALLOWED_CHANNELS_MASK + */ +#ifndef NRFX_DPPI130_SUB_CONFIG_ALLOWED_CHANNELS_MASK +#define NRFX_DPPI130_SUB_CONFIG_ALLOWED_CHANNELS_MASK 0x000000ff +#endif + +/** + * @brief NRFX_DPPI131_SUB_CONFIG_ALLOWED_CHANNELS_MASK + */ +#ifndef NRFX_DPPI131_SUB_CONFIG_ALLOWED_CHANNELS_MASK +#define NRFX_DPPI131_SUB_CONFIG_ALLOWED_CHANNELS_MASK 0x000000ff +#endif + +/** + * @brief NRFX_DPPI132_SUB_CONFIG_ALLOWED_CHANNELS_MASK + */ +#ifndef NRFX_DPPI132_SUB_CONFIG_ALLOWED_CHANNELS_MASK +#define NRFX_DPPI132_SUB_CONFIG_ALLOWED_CHANNELS_MASK 0 +#endif + +/** + * @brief NRFX_DPPI133_SUB_CONFIG_ALLOWED_CHANNELS_MASK + */ +#ifndef NRFX_DPPI133_SUB_CONFIG_ALLOWED_CHANNELS_MASK +#define NRFX_DPPI133_SUB_CONFIG_ALLOWED_CHANNELS_MASK 0x000000e1 +#endif + +/** + * @brief NRFX_DPPI134_SUB_CONFIG_ALLOWED_CHANNELS_MASK + */ +#ifndef NRFX_DPPI134_SUB_CONFIG_ALLOWED_CHANNELS_MASK +#define NRFX_DPPI134_SUB_CONFIG_ALLOWED_CHANNELS_MASK 0x000000df +#endif + +/** + * @brief NRFX_DPPI135_SUB_CONFIG_ALLOWED_CHANNELS_MASK + */ +#ifndef NRFX_DPPI135_SUB_CONFIG_ALLOWED_CHANNELS_MASK +#define NRFX_DPPI135_SUB_CONFIG_ALLOWED_CHANNELS_MASK 0x000000bf +#endif + +/** + * @brief NRFX_DPPI136_SUB_CONFIG_ALLOWED_CHANNELS_MASK + */ +#ifndef NRFX_DPPI136_SUB_CONFIG_ALLOWED_CHANNELS_MASK +#define NRFX_DPPI136_SUB_CONFIG_ALLOWED_CHANNELS_MASK 0x0000007e +#endif + +/** + * @brief NRFX_EGU_ENABLED + * + * Boolean. Accepted values: 0 and 1. + */ +#ifndef NRFX_EGU_ENABLED +#define NRFX_EGU_ENABLED 0 +#endif + +/** + * @brief NRFX_EGU_DEFAULT_CONFIG_IRQ_PRIORITY + * + * Integer value. Minimum: 0. Maximum: 7. + */ +#ifndef NRFX_EGU_DEFAULT_CONFIG_IRQ_PRIORITY +#define NRFX_EGU_DEFAULT_CONFIG_IRQ_PRIORITY NRFX_DEFAULT_IRQ_PRIORITY +#endif + +/** + * @brief NRFX_EGU020_ENABLED + * + * Boolean. Accepted values: 0 and 1. + */ +#ifndef NRFX_EGU020_ENABLED +#define NRFX_EGU020_ENABLED 0 +#endif + +/** + * @brief NRFX_GPIOTE_ENABLED + * + * Boolean. Accepted values: 0 and 1. + */ +#ifndef NRFX_GPIOTE_ENABLED +#define NRFX_GPIOTE_ENABLED 0 +#endif + +/** + * @brief NRFX_GPIOTE_DEFAULT_CONFIG_IRQ_PRIORITY + * + * Integer value. Minimum: 0. Maximum: 7. + */ +#ifndef NRFX_GPIOTE_DEFAULT_CONFIG_IRQ_PRIORITY +#define NRFX_GPIOTE_DEFAULT_CONFIG_IRQ_PRIORITY NRFX_DEFAULT_IRQ_PRIORITY +#endif + +/** + * @brief NRFX_GPIOTE_CONFIG_NUM_OF_EVT_HANDLERS + * + * Integer value. Minimum: 0. Maximum: 15. + */ +#ifndef NRFX_GPIOTE_CONFIG_NUM_OF_EVT_HANDLERS +#define NRFX_GPIOTE_CONFIG_NUM_OF_EVT_HANDLERS 1 +#endif + +/** + * @brief NRFX_GPIOTE_CONFIG_LOG_ENABLED + * + * Boolean. Accepted values: 0 and 1. + */ +#ifndef NRFX_GPIOTE_CONFIG_LOG_ENABLED +#define NRFX_GPIOTE_CONFIG_LOG_ENABLED 0 +#endif + +/** + * @brief NRFX_GPIOTE_CONFIG_LOG_LEVEL + * + * Integer value. + * Supported values: + * - Off = 0 + * - Error = 1 + * - Warning = 2 + * - Info = 3 + * - Debug = 4 + */ +#ifndef NRFX_GPIOTE_CONFIG_LOG_LEVEL +#define NRFX_GPIOTE_CONFIG_LOG_LEVEL 3 +#endif + +/** + * @brief NRFX_GPIOTE130_ENABLED + * + * Boolean. Accepted values: 0 and 1. + */ +#ifndef NRFX_GPIOTE130_ENABLED +#define NRFX_GPIOTE130_ENABLED 0 +#endif + +/** + * @brief NRFX_GRTC_ENABLED + * + * Boolean. Accepted values: 0 and 1. + */ +#ifndef NRFX_GRTC_ENABLED +#define NRFX_GRTC_ENABLED 0 +#endif + +/** + * @brief NRFX_GRTC_CONFIG_NUM_OF_CC_CHANNELS + * + * Integer value. + */ +#ifndef NRFX_GRTC_CONFIG_NUM_OF_CC_CHANNELS +#define NRFX_GRTC_CONFIG_NUM_OF_CC_CHANNELS 4 +#endif + +/** + * @brief NRFX_GRTC_CONFIG_ALLOWED_CC_CHANNELS_MASK + */ +#ifndef NRFX_GRTC_CONFIG_ALLOWED_CC_CHANNELS_MASK +#define NRFX_GRTC_CONFIG_ALLOWED_CC_CHANNELS_MASK 0x00000f00 +#endif + +/** + * @brief NRFX_GRTC_DEFAULT_CONFIG_IRQ_PRIORITY + * + * Integer value. Minimum: 0. Maximum: 7. + */ +#ifndef NRFX_GRTC_DEFAULT_CONFIG_IRQ_PRIORITY +#define NRFX_GRTC_DEFAULT_CONFIG_IRQ_PRIORITY NRFX_DEFAULT_IRQ_PRIORITY +#endif + +/** + * @brief NRFX_GRTC_CONFIG_LOG_ENABLED + * + * Boolean. Accepted values: 0 and 1. + */ +#ifndef NRFX_GRTC_CONFIG_LOG_ENABLED +#define NRFX_GRTC_CONFIG_LOG_ENABLED 0 +#endif + +/** + * @brief NRFX_GRTC_CONFIG_LOG_LEVEL + * + * Integer value. + * Supported values: + * - Off = 0 + * - Error = 1 + * - Warning = 2 + * - Info = 3 + * - Debug = 4 + */ +#ifndef NRFX_GRTC_CONFIG_LOG_LEVEL +#define NRFX_GRTC_CONFIG_LOG_LEVEL 3 +#endif + +/** + * @brief NRFX_I2S_ENABLED + * + * Boolean. Accepted values: 0 and 1. + */ +#ifndef NRFX_I2S_ENABLED +#define NRFX_I2S_ENABLED 0 +#endif + +/** + * @brief NRFX_I2S_DEFAULT_CONFIG_IRQ_PRIORITY + * + * Integer value. Minimum: 0. Maximum: 7. + */ +#ifndef NRFX_I2S_DEFAULT_CONFIG_IRQ_PRIORITY +#define NRFX_I2S_DEFAULT_CONFIG_IRQ_PRIORITY NRFX_DEFAULT_IRQ_PRIORITY +#endif + +/** + * @brief NRFX_I2S_CONFIG_LOG_ENABLED + * + * Boolean. Accepted values: 0 and 1. + */ +#ifndef NRFX_I2S_CONFIG_LOG_ENABLED +#define NRFX_I2S_CONFIG_LOG_ENABLED 0 +#endif + +/** + * @brief NRFX_I2S_CONFIG_LOG_LEVEL + * + * Integer value. + * Supported values: + * - Off = 0 + * - Error = 1 + * - Warning = 2 + * - Info = 3 + * - Debug = 4 + */ +#ifndef NRFX_I2S_CONFIG_LOG_LEVEL +#define NRFX_I2S_CONFIG_LOG_LEVEL 3 +#endif + +/** + * @brief NRFX_I2S130_ENABLED + * + * Boolean. Accepted values: 0 and 1. + */ +#ifndef NRFX_I2S130_ENABLED +#define NRFX_I2S130_ENABLED 0 +#endif + +/** + * @brief NRFX_I2S131_ENABLED + * + * Boolean. Accepted values: 0 and 1. + */ +#ifndef NRFX_I2S131_ENABLED +#define NRFX_I2S131_ENABLED 0 +#endif + +/** + * @brief NRFX_IPCT_PUB_CONFIG_ALLOWED_CHANNELS_MASK + */ +#ifndef NRFX_IPCT_PUB_CONFIG_ALLOWED_CHANNELS_MASK +#define NRFX_IPCT_PUB_CONFIG_ALLOWED_CHANNELS_MASK 0x00000030 +#endif + +/** + * @brief NRFX_IPCT120_PUB_CONFIG_ALLOWED_CHANNELS_MASK + */ +#ifndef NRFX_IPCT120_PUB_CONFIG_ALLOWED_CHANNELS_MASK +#define NRFX_IPCT120_PUB_CONFIG_ALLOWED_CHANNELS_MASK 0 +#endif + +/** + * @brief NRFX_IPCT130_PUB_CONFIG_ALLOWED_CHANNELS_MASK + */ +#ifndef NRFX_IPCT130_PUB_CONFIG_ALLOWED_CHANNELS_MASK +#define NRFX_IPCT130_PUB_CONFIG_ALLOWED_CHANNELS_MASK 0x0000000c +#endif + +/** + * @brief NRFX_IPCT_SUB_CONFIG_ALLOWED_CHANNELS_MASK + */ +#ifndef NRFX_IPCT_SUB_CONFIG_ALLOWED_CHANNELS_MASK +#define NRFX_IPCT_SUB_CONFIG_ALLOWED_CHANNELS_MASK 0x000000c0 +#endif + +/** + * @brief NRFX_IPCT120_SUB_CONFIG_ALLOWED_CHANNELS_MASK + */ +#ifndef NRFX_IPCT120_SUB_CONFIG_ALLOWED_CHANNELS_MASK +#define NRFX_IPCT120_SUB_CONFIG_ALLOWED_CHANNELS_MASK 0 +#endif + +/** + * @brief NRFX_IPCT130_SUB_CONFIG_ALLOWED_CHANNELS_MASK + */ +#ifndef NRFX_IPCT130_SUB_CONFIG_ALLOWED_CHANNELS_MASK +#define NRFX_IPCT130_SUB_CONFIG_ALLOWED_CHANNELS_MASK 0x00000003 +#endif + +/** + * @brief NRFX_LPCOMP_ENABLED + * + * Boolean. Accepted values: 0 and 1. + */ +#ifndef NRFX_LPCOMP_ENABLED +#define NRFX_LPCOMP_ENABLED 0 +#endif + +/** + * @brief NRFX_LPCOMP_DEFAULT_CONFIG_IRQ_PRIORITY + * + * Integer value. Minimum: 0. Maximum: 7. + */ +#ifndef NRFX_LPCOMP_DEFAULT_CONFIG_IRQ_PRIORITY +#define NRFX_LPCOMP_DEFAULT_CONFIG_IRQ_PRIORITY NRFX_DEFAULT_IRQ_PRIORITY +#endif + +/** + * @brief NRFX_LPCOMP_CONFIG_LOG_ENABLED + * + * Boolean. Accepted values: 0 and 1. + */ +#ifndef NRFX_LPCOMP_CONFIG_LOG_ENABLED +#define NRFX_LPCOMP_CONFIG_LOG_ENABLED 0 +#endif + +/** + * @brief NRFX_LPCOMP_CONFIG_LOG_LEVEL + * + * Integer value. + * Supported values: + * - Off = 0 + * - Error = 1 + * - Warning = 2 + * - Info = 3 + * - Debug = 4 + */ +#ifndef NRFX_LPCOMP_CONFIG_LOG_LEVEL +#define NRFX_LPCOMP_CONFIG_LOG_LEVEL 3 +#endif + +/** + * @brief NRFX_MVDMA_ENABLED + * + * Boolean. Accepted values: 0 and 1. + */ +#ifndef NRFX_MVDMA_ENABLED +#define NRFX_MVDMA_ENABLED 0 +#endif + +/** + * @brief NRFX_NFCT_ENABLED + * + * Boolean. Accepted values: 0 and 1. + */ +#ifndef NRFX_NFCT_ENABLED +#define NRFX_NFCT_ENABLED 0 +#endif + +/** + * @brief NRFX_NFCT_DEFAULT_CONFIG_IRQ_PRIORITY + * + * Integer value. Minimum: 0. Maximum: 7. + */ +#ifndef NRFX_NFCT_DEFAULT_CONFIG_IRQ_PRIORITY +#define NRFX_NFCT_DEFAULT_CONFIG_IRQ_PRIORITY NRFX_DEFAULT_IRQ_PRIORITY +#endif + +/** + * @brief NRFX_NFCT_CONFIG_TIMER_INSTANCE_ID - Timer instance used for workarounds in the driver. + * + * Integer value. Minimum: 0. Maximum: 5. + */ +#ifndef NRFX_NFCT_CONFIG_TIMER_INSTANCE_ID +#define NRFX_NFCT_CONFIG_TIMER_INSTANCE_ID 0 +#endif + +/** + * @brief NRFX_NFCT_CONFIG_LOG_ENABLED + * + * Boolean. Accepted values: 0 and 1. + */ +#ifndef NRFX_NFCT_CONFIG_LOG_ENABLED +#define NRFX_NFCT_CONFIG_LOG_ENABLED 0 +#endif + +/** + * @brief NRFX_NFCT_CONFIG_LOG_LEVEL + * + * Integer value. + * Supported values: + * - Off = 0 + * - Error = 1 + * - Warning = 2 + * - Info = 3 + * - Debug = 4 + */ +#ifndef NRFX_NFCT_CONFIG_LOG_LEVEL +#define NRFX_NFCT_CONFIG_LOG_LEVEL 3 +#endif + +/** + * @brief NRFX_PDM_ENABLED + * + * Boolean. Accepted values: 0 and 1. + */ +#ifndef NRFX_PDM_ENABLED +#define NRFX_PDM_ENABLED 0 +#endif + +/** + * @brief NRFX_PDM_DEFAULT_CONFIG_IRQ_PRIORITY + * + * Integer value. Minimum: 0. Maximum: 7. + */ +#ifndef NRFX_PDM_DEFAULT_CONFIG_IRQ_PRIORITY +#define NRFX_PDM_DEFAULT_CONFIG_IRQ_PRIORITY NRFX_DEFAULT_IRQ_PRIORITY +#endif + +/** + * @brief NRFX_PDM_CONFIG_LOG_ENABLED + * + * Boolean. Accepted values: 0 and 1. + */ +#ifndef NRFX_PDM_CONFIG_LOG_ENABLED +#define NRFX_PDM_CONFIG_LOG_ENABLED 0 +#endif + +/** + * @brief NRFX_PDM_CONFIG_LOG_LEVEL + * + * Integer value. + * Supported values: + * - Off = 0 + * - Error = 1 + * - Warning = 2 + * - Info = 3 + * - Debug = 4 + */ +#ifndef NRFX_PDM_CONFIG_LOG_LEVEL +#define NRFX_PDM_CONFIG_LOG_LEVEL 3 +#endif + +/** + * @brief NRFX_PRS_ENABLED + * + * Boolean. Accepted values: 0 and 1. + */ +#ifndef NRFX_PRS_ENABLED +#define NRFX_PRS_ENABLED 0 +#endif + +/** + * @brief NRFX_PRS_CONFIG_LOG_ENABLED + * + * Boolean. Accepted values: 0 and 1. + */ +#ifndef NRFX_PRS_CONFIG_LOG_ENABLED +#define NRFX_PRS_CONFIG_LOG_ENABLED 0 +#endif + +/** + * @brief NRFX_PRS_CONFIG_LOG_LEVEL + * + * Integer value. + * Supported values: + * - Off = 0 + * - Error = 1 + * - Warning = 2 + * - Info = 3 + * - Debug = 4 + */ +#ifndef NRFX_PRS_CONFIG_LOG_LEVEL +#define NRFX_PRS_CONFIG_LOG_LEVEL 3 +#endif + +/** + * @brief NRFX_PRS_BOX_0_ENABLED + * + * Boolean. Accepted values: 0 and 1. + */ +#ifndef NRFX_PRS_BOX_0_ENABLED +#define NRFX_PRS_BOX_0_ENABLED 0 +#endif + +/** + * @brief NRFX_PRS_BOX_1_ENABLED + * + * Boolean. Accepted values: 0 and 1. + */ +#ifndef NRFX_PRS_BOX_1_ENABLED +#define NRFX_PRS_BOX_1_ENABLED 0 +#endif + +/** + * @brief NRFX_PRS_BOX_2_ENABLED + * + * Boolean. Accepted values: 0 and 1. + */ +#ifndef NRFX_PRS_BOX_2_ENABLED +#define NRFX_PRS_BOX_2_ENABLED 0 +#endif + +/** + * @brief NRFX_PRS_BOX_3_ENABLED + * + * Boolean. Accepted values: 0 and 1. + */ +#ifndef NRFX_PRS_BOX_3_ENABLED +#define NRFX_PRS_BOX_3_ENABLED 0 +#endif + +/** + * @brief NRFX_PRS_BOX_4_ENABLED + * + * Boolean. Accepted values: 0 and 1. + */ +#ifndef NRFX_PRS_BOX_4_ENABLED +#define NRFX_PRS_BOX_4_ENABLED 0 +#endif + +/** + * @brief NRFX_PRS_BOX_5_ENABLED + * + * Boolean. Accepted values: 0 and 1. + */ +#ifndef NRFX_PRS_BOX_5_ENABLED +#define NRFX_PRS_BOX_5_ENABLED 0 +#endif + +/** + * @brief NRFX_PRS_BOX_6_ENABLED + * + * Boolean. Accepted values: 0 and 1. + */ +#ifndef NRFX_PRS_BOX_6_ENABLED +#define NRFX_PRS_BOX_6_ENABLED 0 +#endif + +/** + * @brief NRFX_PRS_BOX_7_ENABLED + * + * Boolean. Accepted values: 0 and 1. + */ +#ifndef NRFX_PRS_BOX_7_ENABLED +#define NRFX_PRS_BOX_7_ENABLED 0 +#endif + +/** + * @brief NRFX_PRS_BOX_8_ENABLED + * + * Boolean. Accepted values: 0 and 1. + */ +#ifndef NRFX_PRS_BOX_8_ENABLED +#define NRFX_PRS_BOX_8_ENABLED 0 +#endif + +/** + * @brief NRFX_PRS_BOX_9_ENABLED + * + * Boolean. Accepted values: 0 and 1. + */ +#ifndef NRFX_PRS_BOX_9_ENABLED +#define NRFX_PRS_BOX_9_ENABLED 0 +#endif + +/** + * @brief NRFX_PWM_ENABLED + * + * Boolean. Accepted values: 0 and 1. + */ +#ifndef NRFX_PWM_ENABLED +#define NRFX_PWM_ENABLED 0 +#endif + +/** + * @brief NRFX_PWM_DEFAULT_CONFIG_IRQ_PRIORITY + * + * Integer value. Minimum: 0. Maximum: 7. + */ +#ifndef NRFX_PWM_DEFAULT_CONFIG_IRQ_PRIORITY +#define NRFX_PWM_DEFAULT_CONFIG_IRQ_PRIORITY NRFX_DEFAULT_IRQ_PRIORITY +#endif + +/** + * @brief NRFX_PWM_CONFIG_LOG_ENABLED + * + * Boolean. Accepted values: 0 and 1. + */ +#ifndef NRFX_PWM_CONFIG_LOG_ENABLED +#define NRFX_PWM_CONFIG_LOG_ENABLED 0 +#endif + +/** + * @brief NRFX_PWM_CONFIG_LOG_LEVEL + * + * Integer value. + * Supported values: + * - Off = 0 + * - Error = 1 + * - Warning = 2 + * - Info = 3 + * - Debug = 4 + */ +#ifndef NRFX_PWM_CONFIG_LOG_LEVEL +#define NRFX_PWM_CONFIG_LOG_LEVEL 3 +#endif + +/** + * @brief NRFX_PWM120_ENABLED + * + * Boolean. Accepted values: 0 and 1. + */ +#ifndef NRFX_PWM120_ENABLED +#define NRFX_PWM120_ENABLED 0 +#endif + +/** + * @brief NRFX_PWM130_ENABLED + * + * Boolean. Accepted values: 0 and 1. + */ +#ifndef NRFX_PWM130_ENABLED +#define NRFX_PWM130_ENABLED 0 +#endif + +/** + * @brief NRFX_PWM131_ENABLED + * + * Boolean. Accepted values: 0 and 1. + */ +#ifndef NRFX_PWM131_ENABLED +#define NRFX_PWM131_ENABLED 0 +#endif + +/** + * @brief NRFX_PWM132_ENABLED + * + * Boolean. Accepted values: 0 and 1. + */ +#ifndef NRFX_PWM132_ENABLED +#define NRFX_PWM132_ENABLED 0 +#endif + +/** + * @brief NRFX_PWM133_ENABLED + * + * Boolean. Accepted values: 0 and 1. + */ +#ifndef NRFX_PWM133_ENABLED +#define NRFX_PWM133_ENABLED 0 +#endif + +/** + * @brief NRFX_QDEC_ENABLED + * + * Boolean. Accepted values: 0 and 1. + */ +#ifndef NRFX_QDEC_ENABLED +#define NRFX_QDEC_ENABLED 0 +#endif + +/** + * @brief NRFX_QDEC_DEFAULT_CONFIG_IRQ_PRIORITY + * + * Integer value. Minimum: 0. Maximum: 7. + */ +#ifndef NRFX_QDEC_DEFAULT_CONFIG_IRQ_PRIORITY +#define NRFX_QDEC_DEFAULT_CONFIG_IRQ_PRIORITY NRFX_DEFAULT_IRQ_PRIORITY +#endif + +/** + * @brief NRFX_QDEC_CONFIG_LOG_ENABLED + * + * Boolean. Accepted values: 0 and 1. + */ +#ifndef NRFX_QDEC_CONFIG_LOG_ENABLED +#define NRFX_QDEC_CONFIG_LOG_ENABLED 0 +#endif + +/** + * @brief NRFX_QDEC_CONFIG_LOG_LEVEL + * + * Integer value. + * Supported values: + * - Off = 0 + * - Error = 1 + * - Warning = 2 + * - Info = 3 + * - Debug = 4 + */ +#ifndef NRFX_QDEC_CONFIG_LOG_LEVEL +#define NRFX_QDEC_CONFIG_LOG_LEVEL 3 +#endif + +/** + * @brief NRFX_QDEC130_ENABLED + * + * Boolean. Accepted values: 0 and 1. + */ +#ifndef NRFX_QDEC130_ENABLED +#define NRFX_QDEC130_ENABLED 0 +#endif + +/** + * @brief NRFX_QDEC131_ENABLED + * + * Boolean. Accepted values: 0 and 1. + */ +#ifndef NRFX_QDEC131_ENABLED +#define NRFX_QDEC131_ENABLED 0 +#endif + +/** + * @brief NRFX_RTC_ENABLED + * + * Boolean. Accepted values: 0 and 1. + */ +#ifndef NRFX_RTC_ENABLED +#define NRFX_RTC_ENABLED 0 +#endif + +/** + * @brief NRFX_RTC_DEFAULT_CONFIG_IRQ_PRIORITY + * + * Integer value. Minimum: 0. Maximum: 7. + */ +#ifndef NRFX_RTC_DEFAULT_CONFIG_IRQ_PRIORITY +#define NRFX_RTC_DEFAULT_CONFIG_IRQ_PRIORITY NRFX_DEFAULT_IRQ_PRIORITY +#endif + +/** + * @brief NRFX_RTC_CONFIG_LOG_ENABLED + * + * Boolean. Accepted values: 0 and 1. + */ +#ifndef NRFX_RTC_CONFIG_LOG_ENABLED +#define NRFX_RTC_CONFIG_LOG_ENABLED 0 +#endif + +/** + * @brief NRFX_RTC_CONFIG_LOG_LEVEL + * + * Integer value. + * Supported values: + * - Off = 0 + * - Error = 1 + * - Warning = 2 + * - Info = 3 + * - Debug = 4 + */ +#ifndef NRFX_RTC_CONFIG_LOG_LEVEL +#define NRFX_RTC_CONFIG_LOG_LEVEL 3 +#endif + +/** + * @brief NRFX_RTC130_ENABLED + * + * Boolean. Accepted values: 0 and 1. + */ +#ifndef NRFX_RTC130_ENABLED +#define NRFX_RTC130_ENABLED 0 +#endif + +/** + * @brief NRFX_RTC131_ENABLED + * + * Boolean. Accepted values: 0 and 1. + */ +#ifndef NRFX_RTC131_ENABLED +#define NRFX_RTC131_ENABLED 0 +#endif + +/** + * @brief NRFX_SAADC_ENABLED + * + * Boolean. Accepted values: 0 and 1. + */ +#ifndef NRFX_SAADC_ENABLED +#define NRFX_SAADC_ENABLED 0 +#endif + +/** + * @brief NRFX_SAADC_DEFAULT_CONFIG_IRQ_PRIORITY + * + * Integer value. Minimum: 0. Maximum: 7. + */ +#ifndef NRFX_SAADC_DEFAULT_CONFIG_IRQ_PRIORITY +#define NRFX_SAADC_DEFAULT_CONFIG_IRQ_PRIORITY NRFX_DEFAULT_IRQ_PRIORITY +#endif + +/** + * @brief NRFX_SAADC_CONFIG_LOG_ENABLED + * + * Boolean. Accepted values: 0 and 1. + */ +#ifndef NRFX_SAADC_CONFIG_LOG_ENABLED +#define NRFX_SAADC_CONFIG_LOG_ENABLED 0 +#endif + +/** + * @brief NRFX_SAADC_CONFIG_LOG_LEVEL + * + * Integer value. + * Supported values: + * - Off = 0 + * - Error = 1 + * - Warning = 2 + * - Info = 3 + * - Debug = 4 + */ +#ifndef NRFX_SAADC_CONFIG_LOG_LEVEL +#define NRFX_SAADC_CONFIG_LOG_LEVEL 3 +#endif + +/** + * @brief NRFX_SPIM_ENABLED + * + * Boolean. Accepted values: 0 and 1. + */ +#ifndef NRFX_SPIM_ENABLED +#define NRFX_SPIM_ENABLED 0 +#endif + +/** + * @brief NRFX_SPIM_DEFAULT_CONFIG_IRQ_PRIORITY + * + * Integer value. Minimum: 0. Maximum: 7. + */ +#ifndef NRFX_SPIM_DEFAULT_CONFIG_IRQ_PRIORITY +#define NRFX_SPIM_DEFAULT_CONFIG_IRQ_PRIORITY NRFX_DEFAULT_IRQ_PRIORITY +#endif + +/** + * @brief NRFX_SPIM_CONFIG_LOG_ENABLED + * + * Boolean. Accepted values: 0 and 1. + */ +#ifndef NRFX_SPIM_CONFIG_LOG_ENABLED +#define NRFX_SPIM_CONFIG_LOG_ENABLED 0 +#endif + +/** + * @brief NRFX_SPIM_CONFIG_LOG_LEVEL + * + * Integer value. + * Supported values: + * - Off = 0 + * - Error = 1 + * - Warning = 2 + * - Info = 3 + * - Debug = 4 + */ +#ifndef NRFX_SPIM_CONFIG_LOG_LEVEL +#define NRFX_SPIM_CONFIG_LOG_LEVEL 3 +#endif + +/** + * @brief NRFX_SPIM120_ENABLED + * + * Boolean. Accepted values: 0 and 1. + */ +#ifndef NRFX_SPIM120_ENABLED +#define NRFX_SPIM120_ENABLED 0 +#endif + +/** + * @brief NRFX_SPIM121_ENABLED + * + * Boolean. Accepted values: 0 and 1. + */ +#ifndef NRFX_SPIM121_ENABLED +#define NRFX_SPIM121_ENABLED 0 +#endif + +/** + * @brief NRFX_SPIM130_ENABLED + * + * Boolean. Accepted values: 0 and 1. + */ +#ifndef NRFX_SPIM130_ENABLED +#define NRFX_SPIM130_ENABLED 0 +#endif + +/** + * @brief NRFX_SPIM131_ENABLED + * + * Boolean. Accepted values: 0 and 1. + */ +#ifndef NRFX_SPIM131_ENABLED +#define NRFX_SPIM131_ENABLED 0 +#endif + +/** + * @brief NRFX_SPIM132_ENABLED + * + * Boolean. Accepted values: 0 and 1. + */ +#ifndef NRFX_SPIM132_ENABLED +#define NRFX_SPIM132_ENABLED 0 +#endif + +/** + * @brief NRFX_SPIM133_ENABLED + * + * Boolean. Accepted values: 0 and 1. + */ +#ifndef NRFX_SPIM133_ENABLED +#define NRFX_SPIM133_ENABLED 0 +#endif + +/** + * @brief NRFX_SPIM134_ENABLED + * + * Boolean. Accepted values: 0 and 1. + */ +#ifndef NRFX_SPIM134_ENABLED +#define NRFX_SPIM134_ENABLED 0 +#endif + +/** + * @brief NRFX_SPIM135_ENABLED + * + * Boolean. Accepted values: 0 and 1. + */ +#ifndef NRFX_SPIM135_ENABLED +#define NRFX_SPIM135_ENABLED 0 +#endif + +/** + * @brief NRFX_SPIM136_ENABLED + * + * Boolean. Accepted values: 0 and 1. + */ +#ifndef NRFX_SPIM136_ENABLED +#define NRFX_SPIM136_ENABLED 0 +#endif + +/** + * @brief NRFX_SPIM137_ENABLED + * + * Boolean. Accepted values: 0 and 1. + */ +#ifndef NRFX_SPIM137_ENABLED +#define NRFX_SPIM137_ENABLED 0 +#endif + +/** + * @brief NRFX_SPIS_ENABLED + * + * Boolean. Accepted values: 0 and 1. + */ +#ifndef NRFX_SPIS_ENABLED +#define NRFX_SPIS_ENABLED 0 +#endif + +/** + * @brief NRFX_SPIS_DEFAULT_CONFIG_IRQ_PRIORITY + * + * Integer value. Minimum: 0. Maximum: 7. + */ +#ifndef NRFX_SPIS_DEFAULT_CONFIG_IRQ_PRIORITY +#define NRFX_SPIS_DEFAULT_CONFIG_IRQ_PRIORITY NRFX_DEFAULT_IRQ_PRIORITY +#endif + +/** + * @brief NRFX_SPIS_CONFIG_LOG_ENABLED + * + * Boolean. Accepted values: 0 and 1. + */ +#ifndef NRFX_SPIS_CONFIG_LOG_ENABLED +#define NRFX_SPIS_CONFIG_LOG_ENABLED 0 +#endif + +/** + * @brief NRFX_SPIS_CONFIG_LOG_LEVEL + * + * Integer value. + * Supported values: + * - Off = 0 + * - Error = 1 + * - Warning = 2 + * - Info = 3 + * - Debug = 4 + */ +#ifndef NRFX_SPIS_CONFIG_LOG_LEVEL +#define NRFX_SPIS_CONFIG_LOG_LEVEL 3 +#endif + +/** + * @brief NRFX_SPIS120_ENABLED + * + * Boolean. Accepted values: 0 and 1. + */ +#ifndef NRFX_SPIS120_ENABLED +#define NRFX_SPIS120_ENABLED 0 +#endif + +/** + * @brief NRFX_SPIS130_ENABLED + * + * Boolean. Accepted values: 0 and 1. + */ +#ifndef NRFX_SPIS130_ENABLED +#define NRFX_SPIS130_ENABLED 0 +#endif + +/** + * @brief NRFX_SPIS131_ENABLED + * + * Boolean. Accepted values: 0 and 1. + */ +#ifndef NRFX_SPIS131_ENABLED +#define NRFX_SPIS131_ENABLED 0 +#endif + +/** + * @brief NRFX_SPIS132_ENABLED + * + * Boolean. Accepted values: 0 and 1. + */ +#ifndef NRFX_SPIS132_ENABLED +#define NRFX_SPIS132_ENABLED 0 +#endif + +/** + * @brief NRFX_SPIS133_ENABLED + * + * Boolean. Accepted values: 0 and 1. + */ +#ifndef NRFX_SPIS133_ENABLED +#define NRFX_SPIS133_ENABLED 0 +#endif + +/** + * @brief NRFX_SPIS134_ENABLED + * + * Boolean. Accepted values: 0 and 1. + */ +#ifndef NRFX_SPIS134_ENABLED +#define NRFX_SPIS134_ENABLED 0 +#endif + +/** + * @brief NRFX_SPIS135_ENABLED + * + * Boolean. Accepted values: 0 and 1. + */ +#ifndef NRFX_SPIS135_ENABLED +#define NRFX_SPIS135_ENABLED 0 +#endif + +/** + * @brief NRFX_SPIS136_ENABLED + * + * Boolean. Accepted values: 0 and 1. + */ +#ifndef NRFX_SPIS136_ENABLED +#define NRFX_SPIS136_ENABLED 0 +#endif + +/** + * @brief NRFX_SPIS137_ENABLED + * + * Boolean. Accepted values: 0 and 1. + */ +#ifndef NRFX_SPIS137_ENABLED +#define NRFX_SPIS137_ENABLED 0 +#endif + +/** + * @brief NRFX_SYSTICK_ENABLED + * + * Boolean. Accepted values: 0 and 1. + */ +#ifndef NRFX_SYSTICK_ENABLED +#define NRFX_SYSTICK_ENABLED 0 +#endif + +/** + * @brief NRFX_TEMP_ENABLED + * + * Boolean. Accepted values: 0 and 1. + */ +#ifndef NRFX_TEMP_ENABLED +#define NRFX_TEMP_ENABLED 0 +#endif + +/** + * @brief NRFX_TEMP_DEFAULT_CONFIG_IRQ_PRIORITY + * + * Integer value. Minimum: 0. Maximum: 7. + */ +#ifndef NRFX_TEMP_DEFAULT_CONFIG_IRQ_PRIORITY +#define NRFX_TEMP_DEFAULT_CONFIG_IRQ_PRIORITY NRFX_DEFAULT_IRQ_PRIORITY +#endif + +/** + * @brief NRFX_TEMP_CONFIG_LOG_ENABLED + * + * Boolean. Accepted values: 0 and 1. + */ +#ifndef NRFX_TEMP_CONFIG_LOG_ENABLED +#define NRFX_TEMP_CONFIG_LOG_ENABLED 0 +#endif + +/** + * @brief NRFX_TEMP_CONFIG_LOG_LEVEL + * + * Integer value. + * Supported values: + * - Off = 0 + * - Error = 1 + * - Warning = 2 + * - Info = 3 + * - Debug = 4 + */ +#ifndef NRFX_TEMP_CONFIG_LOG_LEVEL +#define NRFX_TEMP_CONFIG_LOG_LEVEL 3 +#endif + +/** + * @brief NRFX_TIMER_ENABLED + * + * Boolean. Accepted values: 0 and 1. + */ +#ifndef NRFX_TIMER_ENABLED +#define NRFX_TIMER_ENABLED 0 +#endif + +/** + * @brief NRFX_TIMER_DEFAULT_CONFIG_IRQ_PRIORITY + * + * Integer value. Minimum: 0. Maximum: 7. + */ +#ifndef NRFX_TIMER_DEFAULT_CONFIG_IRQ_PRIORITY +#define NRFX_TIMER_DEFAULT_CONFIG_IRQ_PRIORITY NRFX_DEFAULT_IRQ_PRIORITY +#endif + +/** + * @brief NRFX_TIMER_CONFIG_LOG_ENABLED + * + * Boolean. Accepted values: 0 and 1. + */ +#ifndef NRFX_TIMER_CONFIG_LOG_ENABLED +#define NRFX_TIMER_CONFIG_LOG_ENABLED 0 +#endif + +/** + * @brief NRFX_TIMER_CONFIG_LOG_LEVEL + * + * Integer value. + * Supported values: + * - Off = 0 + * - Error = 1 + * - Warning = 2 + * - Info = 3 + * - Debug = 4 + */ +#ifndef NRFX_TIMER_CONFIG_LOG_LEVEL +#define NRFX_TIMER_CONFIG_LOG_LEVEL 3 +#endif + +/** + * @brief NRFX_TIMER020_ENABLED + * + * Boolean. Accepted values: 0 and 1. + */ +#ifndef NRFX_TIMER020_ENABLED +#define NRFX_TIMER020_ENABLED 0 +#endif + +/** + * @brief NRFX_TIMER021_ENABLED + * + * Boolean. Accepted values: 0 and 1. + */ +#ifndef NRFX_TIMER021_ENABLED +#define NRFX_TIMER021_ENABLED 0 +#endif + +/** + * @brief NRFX_TIMER022_ENABLED + * + * Boolean. Accepted values: 0 and 1. + */ +#ifndef NRFX_TIMER022_ENABLED +#define NRFX_TIMER022_ENABLED 0 +#endif + +/** + * @brief NRFX_TIMER120_ENABLED + * + * Boolean. Accepted values: 0 and 1. + */ +#ifndef NRFX_TIMER120_ENABLED +#define NRFX_TIMER120_ENABLED 0 +#endif + +/** + * @brief NRFX_TIMER121_ENABLED + * + * Boolean. Accepted values: 0 and 1. + */ +#ifndef NRFX_TIMER121_ENABLED +#define NRFX_TIMER121_ENABLED 0 +#endif + +/** + * @brief NRFX_TIMER130_ENABLED + * + * Boolean. Accepted values: 0 and 1. + */ +#ifndef NRFX_TIMER130_ENABLED +#define NRFX_TIMER130_ENABLED 0 +#endif + +/** + * @brief NRFX_TIMER131_ENABLED + * + * Boolean. Accepted values: 0 and 1. + */ +#ifndef NRFX_TIMER131_ENABLED +#define NRFX_TIMER131_ENABLED 0 +#endif + +/** + * @brief NRFX_TIMER132_ENABLED + * + * Boolean. Accepted values: 0 and 1. + */ +#ifndef NRFX_TIMER132_ENABLED +#define NRFX_TIMER132_ENABLED 0 +#endif + +/** + * @brief NRFX_TIMER133_ENABLED + * + * Boolean. Accepted values: 0 and 1. + */ +#ifndef NRFX_TIMER133_ENABLED +#define NRFX_TIMER133_ENABLED 0 +#endif + +/** + * @brief NRFX_TIMER134_ENABLED + * + * Boolean. Accepted values: 0 and 1. + */ +#ifndef NRFX_TIMER134_ENABLED +#define NRFX_TIMER134_ENABLED 0 +#endif + +/** + * @brief NRFX_TIMER135_ENABLED + * + * Boolean. Accepted values: 0 and 1. + */ +#ifndef NRFX_TIMER135_ENABLED +#define NRFX_TIMER135_ENABLED 0 +#endif + +/** + * @brief NRFX_TIMER136_ENABLED + * + * Boolean. Accepted values: 0 and 1. + */ +#ifndef NRFX_TIMER136_ENABLED +#define NRFX_TIMER136_ENABLED 0 +#endif + +/** + * @brief NRFX_TIMER137_ENABLED + * + * Boolean. Accepted values: 0 and 1. + */ +#ifndef NRFX_TIMER137_ENABLED +#define NRFX_TIMER137_ENABLED 0 +#endif + +/** + * @brief NRFX_TWIM_ENABLED + * + * Boolean. Accepted values: 0 and 1. + */ +#ifndef NRFX_TWIM_ENABLED +#define NRFX_TWIM_ENABLED 0 +#endif + +/** + * @brief NRFX_TWIM_DEFAULT_CONFIG_IRQ_PRIORITY + * + * Integer value. Minimum: 0. Maximum: 7. + */ +#ifndef NRFX_TWIM_DEFAULT_CONFIG_IRQ_PRIORITY +#define NRFX_TWIM_DEFAULT_CONFIG_IRQ_PRIORITY NRFX_DEFAULT_IRQ_PRIORITY +#endif + +/** + * @brief NRFX_TWIM_CONFIG_LOG_ENABLED + * + * Boolean. Accepted values: 0 and 1. + */ +#ifndef NRFX_TWIM_CONFIG_LOG_ENABLED +#define NRFX_TWIM_CONFIG_LOG_ENABLED 0 +#endif + +/** + * @brief NRFX_TWIM_CONFIG_LOG_LEVEL + * + * Integer value. + * Supported values: + * - Off = 0 + * - Error = 1 + * - Warning = 2 + * - Info = 3 + * - Debug = 4 + */ +#ifndef NRFX_TWIM_CONFIG_LOG_LEVEL +#define NRFX_TWIM_CONFIG_LOG_LEVEL 3 +#endif + +/** + * @brief NRFX_TWIM130_ENABLED + * + * Boolean. Accepted values: 0 and 1. + */ +#ifndef NRFX_TWIM130_ENABLED +#define NRFX_TWIM130_ENABLED 0 +#endif + +/** + * @brief NRFX_TWIM131_ENABLED + * + * Boolean. Accepted values: 0 and 1. + */ +#ifndef NRFX_TWIM131_ENABLED +#define NRFX_TWIM131_ENABLED 0 +#endif + +/** + * @brief NRFX_TWIM132_ENABLED + * + * Boolean. Accepted values: 0 and 1. + */ +#ifndef NRFX_TWIM132_ENABLED +#define NRFX_TWIM132_ENABLED 0 +#endif + +/** + * @brief NRFX_TWIM133_ENABLED + * + * Boolean. Accepted values: 0 and 1. + */ +#ifndef NRFX_TWIM133_ENABLED +#define NRFX_TWIM133_ENABLED 0 +#endif + +/** + * @brief NRFX_TWIM134_ENABLED + * + * Boolean. Accepted values: 0 and 1. + */ +#ifndef NRFX_TWIM134_ENABLED +#define NRFX_TWIM134_ENABLED 0 +#endif + +/** + * @brief NRFX_TWIM135_ENABLED + * + * Boolean. Accepted values: 0 and 1. + */ +#ifndef NRFX_TWIM135_ENABLED +#define NRFX_TWIM135_ENABLED 0 +#endif + +/** + * @brief NRFX_TWIM136_ENABLED + * + * Boolean. Accepted values: 0 and 1. + */ +#ifndef NRFX_TWIM136_ENABLED +#define NRFX_TWIM136_ENABLED 0 +#endif + +/** + * @brief NRFX_TWIM137_ENABLED + * + * Boolean. Accepted values: 0 and 1. + */ +#ifndef NRFX_TWIM137_ENABLED +#define NRFX_TWIM137_ENABLED 0 +#endif + +/** + * @brief NRFX_TWIS_ENABLED + * + * Boolean. Accepted values: 0 and 1. + */ +#ifndef NRFX_TWIS_ENABLED +#define NRFX_TWIS_ENABLED 0 +#endif + +/** + * @brief NRFX_TWIS_DEFAULT_CONFIG_IRQ_PRIORITY + * + * Integer value. Minimum: 0. Maximum: 7. + */ +#ifndef NRFX_TWIS_DEFAULT_CONFIG_IRQ_PRIORITY +#define NRFX_TWIS_DEFAULT_CONFIG_IRQ_PRIORITY NRFX_DEFAULT_IRQ_PRIORITY +#endif + +/** + * @brief NRFX_TWIS_CONFIG_LOG_ENABLED + * + * Boolean. Accepted values: 0 and 1. + */ +#ifndef NRFX_TWIS_CONFIG_LOG_ENABLED +#define NRFX_TWIS_CONFIG_LOG_ENABLED 0 +#endif + +/** + * @brief NRFX_TWIS_ASSUME_INIT_AFTER_RESET_ONLY - Assume that any instance + * would be initialized only once. + * + * Boolean. Accepted values: 0 and 1. + */ +#ifndef NRFX_TWIS_ASSUME_INIT_AFTER_RESET_ONLY +#define NRFX_TWIS_ASSUME_INIT_AFTER_RESET_ONLY 0 +#endif + +/** + * @brief NRFX_TWIS_NO_SYNC_MODE - Remove support for synchronous mode. + * + * Boolean. Accepted values: 0 and 1. + */ +#ifndef NRFX_TWIS_NO_SYNC_MODE +#define NRFX_TWIS_NO_SYNC_MODE 0 +#endif + +/** + * @brief NRFX_TWIS_CONFIG_LOG_LEVEL + * + * Integer value. + * Supported values: + * - Off = 0 + * - Error = 1 + * - Warning = 2 + * - Info = 3 + * - Debug = 4 + */ +#ifndef NRFX_TWIS_CONFIG_LOG_LEVEL +#define NRFX_TWIS_CONFIG_LOG_LEVEL 3 +#endif + +/** + * @brief NRFX_TWIS130_ENABLED + * + * Boolean. Accepted values: 0 and 1. + */ +#ifndef NRFX_TWIS130_ENABLED +#define NRFX_TWIS130_ENABLED 0 +#endif + +/** + * @brief NRFX_TWIS131_ENABLED + * + * Boolean. Accepted values: 0 and 1. + */ +#ifndef NRFX_TWIS131_ENABLED +#define NRFX_TWIS131_ENABLED 0 +#endif + +/** + * @brief NRFX_TWIS132_ENABLED + * + * Boolean. Accepted values: 0 and 1. + */ +#ifndef NRFX_TWIS132_ENABLED +#define NRFX_TWIS132_ENABLED 0 +#endif + +/** + * @brief NRFX_TWIS133_ENABLED + * + * Boolean. Accepted values: 0 and 1. + */ +#ifndef NRFX_TWIS133_ENABLED +#define NRFX_TWIS133_ENABLED 0 +#endif + +/** + * @brief NRFX_TWIS134_ENABLED + * + * Boolean. Accepted values: 0 and 1. + */ +#ifndef NRFX_TWIS134_ENABLED +#define NRFX_TWIS134_ENABLED 0 +#endif + +/** + * @brief NRFX_TWIS135_ENABLED + * + * Boolean. Accepted values: 0 and 1. + */ +#ifndef NRFX_TWIS135_ENABLED +#define NRFX_TWIS135_ENABLED 0 +#endif + +/** + * @brief NRFX_TWIS136_ENABLED + * + * Boolean. Accepted values: 0 and 1. + */ +#ifndef NRFX_TWIS136_ENABLED +#define NRFX_TWIS136_ENABLED 0 +#endif + +/** + * @brief NRFX_TWIS137_ENABLED + * + * Boolean. Accepted values: 0 and 1. + */ +#ifndef NRFX_TWIS137_ENABLED +#define NRFX_TWIS137_ENABLED 0 +#endif + +/** + * @brief NRFX_UARTE_ENABLED + * + * Boolean. Accepted values: 0 and 1. + */ +#ifndef NRFX_UARTE_ENABLED +#define NRFX_UARTE_ENABLED 0 +#endif + +/** + * @brief NRFX_UARTE_CONFIG_SKIP_GPIO_CONFIG - If enabled, support for + * configuring GPIO pins is removed from the driver + * + * Boolean. Accepted values: 0 and 1. + */ +#ifndef NRFX_UARTE_CONFIG_SKIP_GPIO_CONFIG +#define NRFX_UARTE_CONFIG_SKIP_GPIO_CONFIG 0 +#endif + +/** + * @brief NRFX_UARTE_CONFIG_SKIP_PSEL_CONFIG - If enabled, support for + * configuring PSEL registers is removed from the driver + * + * Boolean. Accepted values: 0 and 1. + */ +#ifndef NRFX_UARTE_CONFIG_SKIP_PSEL_CONFIG +#define NRFX_UARTE_CONFIG_SKIP_PSEL_CONFIG 0 +#endif + +/** + * @brief NRFX_UARTE_CONFIG_TX_LINK - If enabled, driver supports linking + * of TX transfers. + * + * Boolean. Accepted values: 0 and 1. + */ +#ifndef NRFX_UARTE_CONFIG_TX_LINK +#define NRFX_UARTE_CONFIG_TX_LINK 1 +#endif + +/** + * @brief NRFX_UARTE_CONFIG_RX_CACHE_ENABLED + * + * Boolean. Accepted values: 0 and 1. + */ +#ifndef NRFX_UARTE_CONFIG_RX_CACHE_ENABLED +#define NRFX_UARTE_CONFIG_RX_CACHE_ENABLED 1 +#endif + +/** + * @brief NRFX_UARTE_DEFAULT_CONFIG_IRQ_PRIORITY + * + * Integer value. Minimum: 0. Maximum: 7. + */ +#ifndef NRFX_UARTE_DEFAULT_CONFIG_IRQ_PRIORITY +#define NRFX_UARTE_DEFAULT_CONFIG_IRQ_PRIORITY NRFX_DEFAULT_IRQ_PRIORITY +#endif + +/** + * @brief NRFX_UARTE_CONFIG_LOG_ENABLED + * + * Boolean. Accepted values: 0 and 1. + */ +#ifndef NRFX_UARTE_CONFIG_LOG_ENABLED +#define NRFX_UARTE_CONFIG_LOG_ENABLED 0 +#endif + +/** + * @brief NRFX_UARTE_CONFIG_LOG_LEVEL + * + * Integer value. + * Supported values: + * - Off = 0 + * - Error = 1 + * - Warning = 2 + * - Info = 3 + * - Debug = 4 + */ +#ifndef NRFX_UARTE_CONFIG_LOG_LEVEL +#define NRFX_UARTE_CONFIG_LOG_LEVEL 3 +#endif + +/** + * @brief NRFX_UARTE120_ENABLED + * + * Boolean. Accepted values: 0 and 1. + */ +#ifndef NRFX_UARTE120_ENABLED +#define NRFX_UARTE120_ENABLED 0 +#endif + +/** + * @brief NRFX_UARTE130_ENABLED + * + * Boolean. Accepted values: 0 and 1. + */ +#ifndef NRFX_UARTE130_ENABLED +#define NRFX_UARTE130_ENABLED 0 +#endif + +/** + * @brief NRFX_UARTE131_ENABLED + * + * Boolean. Accepted values: 0 and 1. + */ +#ifndef NRFX_UARTE131_ENABLED +#define NRFX_UARTE131_ENABLED 0 +#endif + +/** + * @brief NRFX_UARTE132_ENABLED + * + * Boolean. Accepted values: 0 and 1. + */ +#ifndef NRFX_UARTE132_ENABLED +#define NRFX_UARTE132_ENABLED 0 +#endif + +/** + * @brief NRFX_UARTE133_ENABLED + * + * Boolean. Accepted values: 0 and 1. + */ +#ifndef NRFX_UARTE133_ENABLED +#define NRFX_UARTE133_ENABLED 0 +#endif + +/** + * @brief NRFX_UARTE134_ENABLED + * + * Boolean. Accepted values: 0 and 1. + */ +#ifndef NRFX_UARTE134_ENABLED +#define NRFX_UARTE134_ENABLED 0 +#endif + +/** + * @brief NRFX_UARTE135_ENABLED + * + * Boolean. Accepted values: 0 and 1. + */ +#ifndef NRFX_UARTE135_ENABLED +#define NRFX_UARTE135_ENABLED 0 +#endif + +/** + * @brief NRFX_UARTE136_ENABLED + * + * Boolean. Accepted values: 0 and 1. + */ +#ifndef NRFX_UARTE136_ENABLED +#define NRFX_UARTE136_ENABLED 0 +#endif + +/** + * @brief NRFX_UARTE137_ENABLED + * + * Boolean. Accepted values: 0 and 1. + */ +#ifndef NRFX_UARTE137_ENABLED +#define NRFX_UARTE137_ENABLED 0 +#endif + +/** + * @brief NRFX_WDT_ENABLED + * + * Boolean. Accepted values: 0 and 1. + */ +#ifndef NRFX_WDT_ENABLED +#define NRFX_WDT_ENABLED 0 +#endif + +/** + * @brief NRFX_WDT_DEFAULT_CONFIG_IRQ_PRIORITY + * + * Integer value. Minimum: 0. Maximum: 7. + */ +#ifndef NRFX_WDT_DEFAULT_CONFIG_IRQ_PRIORITY +#define NRFX_WDT_DEFAULT_CONFIG_IRQ_PRIORITY NRFX_DEFAULT_IRQ_PRIORITY +#endif + +/** + * @brief NRFX_WDT_CONFIG_NO_IRQ - Remove WDT IRQ handling from WDT driver + * + * Boolean. Accepted values: 0 and 1. + */ +#ifndef NRFX_WDT_CONFIG_NO_IRQ +#define NRFX_WDT_CONFIG_NO_IRQ 0 +#endif + +/** + * @brief NRFX_WDT_CONFIG_LOG_ENABLED + * + * Boolean. Accepted values: 0 and 1. + */ +#ifndef NRFX_WDT_CONFIG_LOG_ENABLED +#define NRFX_WDT_CONFIG_LOG_ENABLED 0 +#endif + +/** + * @brief NRFX_WDT_CONFIG_LOG_LEVEL + * + * Integer value. + * Supported values: + * - Off = 0 + * - Error = 1 + * - Warning = 2 + * - Info = 3 + * - Debug = 4 + */ +#ifndef NRFX_WDT_CONFIG_LOG_LEVEL +#define NRFX_WDT_CONFIG_LOG_LEVEL 3 +#endif + +/** + * @brief NRFX_WDT010_ENABLED + * + * Boolean. Accepted values: 0 and 1. + */ +#ifndef NRFX_WDT010_ENABLED +#define NRFX_WDT010_ENABLED 0 +#endif + +/** + * @brief NRFX_WDT011_ENABLED + * + * Boolean. Accepted values: 0 and 1. + */ +#ifndef NRFX_WDT011_ENABLED +#define NRFX_WDT011_ENABLED 0 +#endif + +/** + * @brief NRFX_WDT131_ENABLED + * + * Boolean. Accepted values: 0 and 1. + */ +#ifndef NRFX_WDT131_ENABLED +#define NRFX_WDT131_ENABLED 0 +#endif + +/** + * @brief NRFX_WDT132_ENABLED + * + * Boolean. Accepted values: 0 and 1. + */ +#ifndef NRFX_WDT132_ENABLED +#define NRFX_WDT132_ENABLED 0 +#endif + +#endif /* NRFX_CONFIG_NRF54H20_ENGA_RADIOCORE_H__ */ diff --git a/soc/arm/nordic_nrf/Kconfig b/soc/arm/nordic_nrf/Kconfig index f2a20321d6b..589c1b59735 100644 --- a/soc/arm/nordic_nrf/Kconfig +++ b/soc/arm/nordic_nrf/Kconfig @@ -18,6 +18,7 @@ source "soc/arm/nordic_nrf/*/Kconfig.soc" config NRF_SOC_SECURE_SUPPORTED def_bool !TRUSTED_EXECUTION_NONSECURE || (BUILD_WITH_TFM && TFM_PARTITION_PLATFORM) + depends on !SOC_SERIES_NRF54HX help Hidden function to indicate that that the soc_secure functions are available. diff --git a/soc/arm/nordic_nrf/Kconfig.defconfig b/soc/arm/nordic_nrf/Kconfig.defconfig index 879217a92fe..ad3c97443ff 100644 --- a/soc/arm/nordic_nrf/Kconfig.defconfig +++ b/soc/arm/nordic_nrf/Kconfig.defconfig @@ -11,7 +11,7 @@ source "soc/arm/nordic_nrf/*/Kconfig.defconfig.series" if SYS_CLOCK_EXISTS config CLOCK_CONTROL - default y + default y if !SOC_SERIES_NRF54HX endif # SYS_CLOCK_EXISTS diff --git a/soc/arm/nordic_nrf/nrf54h/CMakeLists.txt b/soc/arm/nordic_nrf/nrf54h/CMakeLists.txt new file mode 100644 index 00000000000..8b4df42fa55 --- /dev/null +++ b/soc/arm/nordic_nrf/nrf54h/CMakeLists.txt @@ -0,0 +1,7 @@ +# SPDX-License-Identifier: Apache-2.0 + +zephyr_library_sources(soc.c) + +# Ensure that image size aligns with 16 bytes so that MRAMC finalizes all writes +# for the image correctly +zephyr_linker_sources(SECTIONS SORT_KEY zzz_place_align_at_end align.ld) diff --git a/soc/arm/nordic_nrf/nrf54h/Kconfig.defconfig.nrf54h20_cpuapp b/soc/arm/nordic_nrf/nrf54h/Kconfig.defconfig.nrf54h20_cpuapp new file mode 100644 index 00000000000..eb56b8c369e --- /dev/null +++ b/soc/arm/nordic_nrf/nrf54h/Kconfig.defconfig.nrf54h20_cpuapp @@ -0,0 +1,14 @@ +# Nordic Semiconductor nRF54H20 Application MCU + +# Copyright (c) 2024 Nordic Semiconductor ASA +# SPDX-License-Identifier: Apache-2.0 + +if SOC_NRF54H20_ENGA_CPUAPP + +config SOC + default "nrf54h20_enga_cpuapp" + +config NUM_IRQS + default 471 + +endif # SOC_NRF54H20_ENGA_CPUAPP diff --git a/soc/arm/nordic_nrf/nrf54h/Kconfig.defconfig.nrf54h20_cpurad b/soc/arm/nordic_nrf/nrf54h/Kconfig.defconfig.nrf54h20_cpurad new file mode 100644 index 00000000000..f63b9437775 --- /dev/null +++ b/soc/arm/nordic_nrf/nrf54h/Kconfig.defconfig.nrf54h20_cpurad @@ -0,0 +1,14 @@ +# Nordic Semiconductor nRF54H20 Radio MCU + +# Copyright (c) 2024 Nordic Semiconductor ASA +# SPDX-License-Identifier: Apache-2.0 + +if SOC_NRF54H20_ENGA_CPURAD + +config SOC + default "nrf54h20_enga_cpurad" + +config NUM_IRQS + default 471 + +endif # SOC_NRF54H20_ENGA_CPURAD diff --git a/soc/arm/nordic_nrf/nrf54h/Kconfig.defconfig.series b/soc/arm/nordic_nrf/nrf54h/Kconfig.defconfig.series new file mode 100644 index 00000000000..ddc902d213e --- /dev/null +++ b/soc/arm/nordic_nrf/nrf54h/Kconfig.defconfig.series @@ -0,0 +1,16 @@ +# Nordic Semiconductor nRF54H MCU line + +# Copyright (c) 2024 Nordic Semiconductor ASA +# SPDX-License-Identifier: Apache-2.0 + +if SOC_SERIES_NRF54HX + +rsource "Kconfig.defconfig.nrf54h*" + +config SOC_SERIES + default "nrf54h" + +config CACHE_NRF_CACHE + default y if EXTERNAL_CACHE + +endif # SOC_SERIES_NRF54HX diff --git a/soc/arm/nordic_nrf/nrf54h/Kconfig.series b/soc/arm/nordic_nrf/nrf54h/Kconfig.series new file mode 100644 index 00000000000..0b896f477ac --- /dev/null +++ b/soc/arm/nordic_nrf/nrf54h/Kconfig.series @@ -0,0 +1,16 @@ +# Nordic Semiconductor nRF54H MCU line + +# Copyright (c) 2024 Nordic Semiconductor ASA +# SPDX-License-Identifier: Apache-2.0 + +config SOC_SERIES_NRF54HX + bool "Nordic Semiconductor nRF54H series MCU" + select ARM + select ARMV8_M_DSP + select CPU_CORTEX_M33 + select SOC_FAMILY_NRF + select HAS_NRFX + select HAS_NORDIC_DRIVERS + select HAS_SEGGER_RTT if ZEPHYR_SEGGER_MODULE + help + Enable support for nRF54H MCU series diff --git a/soc/arm/nordic_nrf/nrf54h/Kconfig.soc b/soc/arm/nordic_nrf/nrf54h/Kconfig.soc new file mode 100644 index 00000000000..9c065e79eaf --- /dev/null +++ b/soc/arm/nordic_nrf/nrf54h/Kconfig.soc @@ -0,0 +1,37 @@ +# Nordic Semiconductor nRF54H MCU line + +# Copyright (c) 2024 Nordic Semiconductor ASA +# SPDX-License-Identifier: Apache-2.0 + +config SOC_NRF54H20 + bool "nRF54H20" + depends on SOC_SERIES_NRF54HX + +if SOC_NRF54H20 + +choice + prompt "nRF54H20 MCU Selection" + +config SOC_NRF54H20_ENGA_CPUAPP + bool "nRF54H20 ENGA CPUAPP" + select CPU_HAS_ARM_MPU + select CPU_HAS_ARM_SAU + select CPU_HAS_DCACHE + select CPU_HAS_ICACHE + select CPU_HAS_FPU + +config SOC_NRF54H20_ENGA_CPURAD + bool "nRF54H20 ENGA CPURAD" + select CPU_HAS_ARM_MPU + select CPU_HAS_ARM_SAU + select CPU_HAS_DCACHE + select CPU_HAS_ICACHE + select CPU_HAS_FPU + +endchoice + +config NRF_ENABLE_ICACHE + bool "Instruction cache (I-Cache)" + default y + +endif # SOC_NRF54H20 diff --git a/soc/arm/nordic_nrf/nrf54h/align.ld b/soc/arm/nordic_nrf/nrf54h/align.ld new file mode 100644 index 00000000000..0905aa7f7bc --- /dev/null +++ b/soc/arm/nordic_nrf/nrf54h/align.ld @@ -0,0 +1,10 @@ +/* + * Copyright (c) 2024 Nordic Semiconductor ASA. + * SPDX-License-Identifier: Apache-2.0 + */ + +SECTION_PROLOGUE(.align16,,) +{ + . = (ALIGN(16) > 0 ? ALIGN(16) : 16) - 1; + BYTE(0); +} GROUP_LINK_IN(ROMABLE_REGION) diff --git a/soc/arm/nordic_nrf/nrf54h/soc.c b/soc/arm/nordic_nrf/nrf54h/soc.c new file mode 100644 index 00000000000..9fefd414152 --- /dev/null +++ b/soc/arm/nordic_nrf/nrf54h/soc.c @@ -0,0 +1,104 @@ +/* + * Copyright (c) 2024 Nordic Semiconductor ASA. + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include +#include +#include +#include +#include + +#include +#include +#include + +LOG_MODULE_REGISTER(soc, CONFIG_SOC_LOG_LEVEL); + +#if defined(NRF_APPLICATION) +#define HSFLL_NODE DT_NODELABEL(cpuapp_hsfll) +#elif defined(NRF_RADIOCORE) +#define HSFLL_NODE DT_NODELABEL(cpurad_hsfll) +#endif + +#define FICR_ADDR_GET(node_id, name) \ + DT_REG_ADDR(DT_PHANDLE_BY_NAME(node_id, nordic_ficrs, name)) + \ + DT_PHA_BY_NAME(node_id, nordic_ficrs, name, offset) + +static void power_domain_init(void) +{ + /* + * Set: + * - LRCCONF010.POWERON.MAIN: 1 + * - LRCCONF010.POWERON.ACT: 1 + * - LRCCONF010.RETAIN.MAIN: 1 + * - LRCCONF010.RETAIN.ACT: 1 + * + * This is done here at boot so that when the idle routine will hit + * WFI the power domain will be correctly retained. + */ + + nrf_lrcconf_poweron_force_set(NRF_LRCCONF010, NRF_LRCCONF_POWER_MAIN, true); + nrf_lrcconf_poweron_force_set(NRF_LRCCONF010, NRF_LRCCONF_POWER_DOMAIN_0, true); + + nrf_lrcconf_retain_set(NRF_LRCCONF010, NRF_LRCCONF_POWER_MAIN, true); + nrf_lrcconf_retain_set(NRF_LRCCONF010, NRF_LRCCONF_POWER_DOMAIN_0, true); + +#if defined(CONFIG_SOC_NRF54H20_ENGA_CPUAPP) + nrf_lrcconf_poweron_force_set(NRF_LRCCONF000, NRF_LRCCONF_POWER_DOMAIN_0, true); +#endif +} + +static int trim_hsfll(void) +{ + NRF_HSFLL_Type *hsfll = (NRF_HSFLL_Type *)DT_REG_ADDR(HSFLL_NODE); + nrf_hsfll_trim_t trim = { + .vsup = sys_read32(FICR_ADDR_GET(HSFLL_NODE, vsup)), + .coarse = sys_read32(FICR_ADDR_GET(HSFLL_NODE, coarse)), + .fine = sys_read32(FICR_ADDR_GET(HSFLL_NODE, fine)) + }; + + LOG_DBG("Trim: HSFLL VSUP: 0x%.8x", trim.vsup); + LOG_DBG("Trim: HSFLL COARSE: 0x%.8x", trim.coarse); + LOG_DBG("Trim: HSFLL FINE: 0x%.8x", trim.fine); + + nrf_hsfll_clkctrl_mult_set(hsfll, + DT_PROP(HSFLL_NODE, clock_frequency) / + DT_PROP(DT_CLOCKS_CTLR(HSFLL_NODE), clock_frequency)); + nrf_hsfll_trim_set(hsfll, &trim); + + nrf_hsfll_task_trigger(hsfll, NRF_HSFLL_TASK_FREQ_CHANGE); +#if defined(CONFIG_SOC_NRF54H20_ENGA_CPUAPP) || defined(CONFIG_SOC_NRF54H20_ENGA_CPURAD) + /* In this HW revision, HSFLL task frequency change needs to be + * triggered additional time to take effect. + */ + nrf_hsfll_task_trigger(hsfll, NRF_HSFLL_TASK_FREQ_CHANGE); +#endif + + LOG_DBG("NRF_HSFLL->TRIM.VSUP = %d", hsfll->TRIM.VSUP); + LOG_DBG("NRF_HSFLL->TRIM.COARSE = %d", hsfll->TRIM.COARSE); + LOG_DBG("NRF_HSFLL->TRIM.FINE = %d", hsfll->TRIM.FINE); + + return 0; +} + +static int nordicsemi_nrf54h_init(void) +{ +#if defined(CONFIG_NRF_ENABLE_ICACHE) + sys_cache_instr_enable(); +#endif + + power_domain_init(); + + trim_hsfll(); + + return 0; +} + +void arch_busy_wait(uint32_t time_us) +{ + nrfx_coredep_delay_us(time_us); +} + +SYS_INIT(nordicsemi_nrf54h_init, PRE_KERNEL_1, 0); diff --git a/soc/arm/nordic_nrf/nrf54h/soc.h b/soc/arm/nordic_nrf/nrf54h/soc.h new file mode 100644 index 00000000000..9a44ab24982 --- /dev/null +++ b/soc/arm/nordic_nrf/nrf54h/soc.h @@ -0,0 +1,12 @@ +/* + * Copyright (c) 2024 Nordic Semiconductor ASA + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#ifndef SOC_ARM_NORDIC_NRF_NRF54H_SOC_H_ +#define SOC_ARM_NORDIC_NRF_NRF54H_SOC_H_ + +#include + +#endif /* SOC_ARM_NORDIC_NRF_NRF54H_SOC_H_ */ From 7740bcf670595cbf83d6c9f59159da7b7b057cb6 Mon Sep 17 00:00:00 2001 From: Grzegorz Swiderski Date: Tue, 30 Jan 2024 14:30:20 +0100 Subject: [PATCH 3399/3723] modules: hal_nordic: Set SOC_SVD_FILE This CMake variable contains a path to a CMSIS-SVD file from nRF MDK, which describes the selected Nordic SoC. Initially, this will be used as an argument to nrf-regtool. Signed-off-by: Grzegorz Swiderski --- modules/hal_nordic/nrfx/CMakeLists.txt | 22 ++++++++++++++++++++++ 1 file changed, 22 insertions(+) diff --git a/modules/hal_nordic/nrfx/CMakeLists.txt b/modules/hal_nordic/nrfx/CMakeLists.txt index d1c13837d58..9b8bd0caff4 100644 --- a/modules/hal_nordic/nrfx/CMakeLists.txt +++ b/modules/hal_nordic/nrfx/CMakeLists.txt @@ -159,3 +159,25 @@ zephyr_compile_definitions_ifdef(CONFIG_SOC_NRF54LX_SKIP_CLOCK_CONFIG NRF_SKIP_C if(CONFIG_SOC_SERIES_NRF54LX AND CONFIG_NRFX_DPPI) zephyr_library_sources(${HELPERS_DIR}/nrfx_gppi_dppi_ppib_lumos.c) endif() + +# Get the SVD file for the current SoC +macro(mdk_svd_ifdef feature_toggle filename) + if(${feature_toggle}) + set(SOC_SVD_FILE ${MDK_DIR}/${filename} CACHE FILEPATH "Path to a CMSIS-SVD file") + endif() +endmacro() + +mdk_svd_ifdef(CONFIG_SOC_SERIES_NRF51X nrf51.svd) +mdk_svd_ifdef(CONFIG_SOC_NRF52805 nrf52805.svd) +mdk_svd_ifdef(CONFIG_SOC_NRF52810 nrf52810.svd) +mdk_svd_ifdef(CONFIG_SOC_NRF52811 nrf52811.svd) +mdk_svd_ifdef(CONFIG_SOC_NRF52820 nrf52820.svd) +mdk_svd_ifdef(CONFIG_SOC_NRF52832 nrf52.svd) +mdk_svd_ifdef(CONFIG_SOC_NRF52833 nrf52833.svd) +mdk_svd_ifdef(CONFIG_SOC_NRF52840 nrf52840.svd) +mdk_svd_ifdef(CONFIG_SOC_NRF5340_CPUAPP nrf5340_application.svd) +mdk_svd_ifdef(CONFIG_SOC_NRF5340_CPUNET nrf5340_network.svd) +mdk_svd_ifdef(CONFIG_SOC_NRF54H20_ENGA_CPUAPP nrf54h20_enga_application.svd) +mdk_svd_ifdef(CONFIG_SOC_NRF54H20_ENGA_CPURAD nrf54h20_enga_radiocore.svd) +mdk_svd_ifdef(CONFIG_SOC_NRF9120 nrf9120.svd) +mdk_svd_ifdef(CONFIG_SOC_NRF9160 nrf9160.svd) From be8b2663c6cd52b6d263de93e9ea1d92d6a5d215 Mon Sep 17 00:00:00 2001 From: Grzegorz Swiderski Date: Tue, 30 Jan 2024 14:30:20 +0100 Subject: [PATCH 3400/3723] modules: hal_nordic: Integrate nrf-regtool nrf-regtool is a Python utility from Nordic Semiconductor, which is used for generating binary files with register values for given peripherals. It sources the descriptions of peripheral registers from CMSIS-SVD files (typically ones bundled with nRF MDK). For some peripherals, such as UICR, nrf-regtool supports parsing values from devicetree as well, based on the bindings already found in Zephyr. Currently, this tool is not submitted as a script to Zephyr, but it can be installed from PyPI. Having nrf-regtool installed is recommended when working with nRF54H20. Booting the Application or Radiocore CPU requires flashing not only its firmware, but also its respective UICR instance. On this SoC, the UICR is used to assign ownership of global hardware resources, including memory and peripherals, to individual cores. The Zephyr build system can call nrf-regtool to generate the UICR based on devicetree, to reflect the boot-time hardware configuration required for a given application. The generated `uicr.hex` is then merged with `zephyr.hex`, so that they can be flashed together using west. The build system integration takes the form of a CMake package, which includes a version check and reusable components; over time, some of these components can be reused by sysbuild. This package is located in the `hal_nordic` module, because it depends on the `SOC_SVD_FILE` CMake variable, which is defined there as well. Signed-off-by: Grzegorz Swiderski --- modules/hal_nordic/CMakeLists.txt | 16 +++++++ modules/hal_nordic/Kconfig | 1 + modules/hal_nordic/Kconfig.nrf_regtool | 36 ++++++++++++++ .../nrf-regtool/nrf-regtoolConfig.cmake | 48 +++++++++++++++++++ .../nrf-regtoolConfigVersion.cmake | 32 +++++++++++++ .../nrf54h/Kconfig.defconfig.nrf54h20_cpuapp | 3 ++ .../nrf54h/Kconfig.defconfig.nrf54h20_cpurad | 3 ++ 7 files changed, 139 insertions(+) create mode 100644 modules/hal_nordic/Kconfig.nrf_regtool create mode 100644 modules/hal_nordic/nrf-regtool/nrf-regtoolConfig.cmake create mode 100644 modules/hal_nordic/nrf-regtool/nrf-regtoolConfigVersion.cmake diff --git a/modules/hal_nordic/CMakeLists.txt b/modules/hal_nordic/CMakeLists.txt index 693400aba76..6f5364ac8de 100644 --- a/modules/hal_nordic/CMakeLists.txt +++ b/modules/hal_nordic/CMakeLists.txt @@ -6,3 +6,19 @@ if (CONFIG_NRF_802154_RADIO_DRIVER OR CONFIG_NRF_802154_SERIALIZATION) endif (CONFIG_NRF_802154_RADIO_DRIVER OR CONFIG_NRF_802154_SERIALIZATION) add_subdirectory_ifdef(CONFIG_HAS_NRFX nrfx) + +if(CONFIG_NRF_REGTOOL_GENERATE_UICR) + list(APPEND nrf_regtool_components GENERATE:UICR) +endif() +if(DEFINED nrf_regtool_components) + find_package(nrf-regtool 5.0.1 + COMPONENTS ${nrf_regtool_components} + PATHS ${CMAKE_CURRENT_LIST_DIR}/nrf-regtool + NO_CMAKE_PATH + NO_CMAKE_ENVIRONMENT_PATH + NO_SYSTEM_ENVIRONMENT_PATH + NO_CMAKE_PACKAGE_REGISTRY + NO_CMAKE_SYSTEM_PATH + NO_CMAKE_SYSTEM_PACKAGE_REGISTRY + ) +endif() diff --git a/modules/hal_nordic/Kconfig b/modules/hal_nordic/Kconfig index 6f77bbea427..c9cc93e9329 100644 --- a/modules/hal_nordic/Kconfig +++ b/modules/hal_nordic/Kconfig @@ -236,3 +236,4 @@ endif # NRF_802154_RADIO_DRIVER || NRF_802154_SERIALIZATION endmenu # HAS_NORDIC_DRIVERS rsource "nrfx/Kconfig" +rsource "Kconfig.nrf_regtool" diff --git a/modules/hal_nordic/Kconfig.nrf_regtool b/modules/hal_nordic/Kconfig.nrf_regtool new file mode 100644 index 00000000000..81659bcf0bb --- /dev/null +++ b/modules/hal_nordic/Kconfig.nrf_regtool @@ -0,0 +1,36 @@ +# Copyright (c) 2024 Nordic Semiconductor ASA +# SPDX-License-Identifier: Apache-2.0 + +menu "nrf-regtool options" + depends on SOC_SERIES_NRF54HX + +config NRF_REGTOOL_GENERATE_UICR + bool "Generate UICR" + help + Generate a UICR hex based on devicetree contents using nrf-regtool. + CPU domains that require UICR allocation aren't bootable without it + being programmed alongside the firmware. + +config NRF_REGTOOL_VERBOSITY + int "Verbosity level of console output" + range 0 3 + default 0 + help + Level of verbose output that nrf-regtool will print to the console. + + 0. Only critical information and warnings. + 1. Print a pretty, human-readable representation of a peripheral's + configuration. This is recommended for inspecting register values. + 2. Print extra details for debugging purposes, such as memory maps of + the peripheral configurations, but in a less readable format. + 3. Print even more details, which are typically only useful for + nrf-regtool developers. + +config NRF_REGTOOL_EXTRA_GENERATE_ARGS + string "Extra arguments to 'nrf-regtool generate'" + help + List of additional arguments to every nrf-regtool invocation used for + generating hex files. Example value: "--fill all --fill-byte 0xff". + Run "nrf-regtool generate -h" to see all of the available options. + +endmenu diff --git a/modules/hal_nordic/nrf-regtool/nrf-regtoolConfig.cmake b/modules/hal_nordic/nrf-regtool/nrf-regtoolConfig.cmake new file mode 100644 index 00000000000..d057c735e3f --- /dev/null +++ b/modules/hal_nordic/nrf-regtool/nrf-regtoolConfig.cmake @@ -0,0 +1,48 @@ +# Copyright (c) 2024 Nordic Semiconductor ASA +# SPDX-License-Identifier: Apache-2.0 + +function(nrf_regtool_generate_hex_from_dts peripheral) + string(TOLOWER "${peripheral}.hex" generated_hex_name) + string(TOLOWER "${peripheral}_merged.hex" merged_hex_name) + + # Prepare common argument sub-lists. + string(REPEAT "-v;" ${CONFIG_NRF_REGTOOL_VERBOSITY} verbosity) + list(TRANSFORM CACHED_DTS_ROOT_BINDINGS PREPEND "--bindings-dir;" OUTPUT_VARIABLE bindings_dirs) + separate_arguments(extra_args UNIX_COMMAND "${CONFIG_NRF_REGTOOL_EXTRA_GENERATE_ARGS}") + + set(generated_hex_file ${PROJECT_BINARY_DIR}/${generated_hex_name}) + execute_process( + COMMAND ${NRF_REGTOOL} ${verbosity} generate + --peripheral ${peripheral} + --svd-file ${SOC_SVD_FILE} + --dts-file ${ZEPHYR_DTS} + ${bindings_dirs} + --output-file ${generated_hex_file} + ${extra_args} + WORKING_DIRECTORY ${APPLICATION_SOURCE_DIR} + COMMAND_ERROR_IS_FATAL ANY + ) + message(STATUS "Generated ${peripheral} hex file: ${generated_hex_file}") + + set(merged_hex_file ${PROJECT_BINARY_DIR}/${merged_hex_name}) + set_property(GLOBAL APPEND PROPERTY extra_post_build_commands + COMMAND ${PYTHON_EXECUTABLE} ${ZEPHYR_BASE}/scripts/build/mergehex.py + -o ${merged_hex_file} + ${generated_hex_file} + ${PROJECT_BINARY_DIR}/${KERNEL_HEX_NAME} + ) + set_property(TARGET runners_yaml_props_target PROPERTY hex_file ${merged_hex_file}) +endfunction() + + +foreach(component IN LISTS ${CMAKE_FIND_PACKAGE_NAME}_FIND_COMPONENTS) + string(REGEX MATCH "(^.*):(.*$)" match ${component}) + set(operation "${CMAKE_MATCH_1}") + set(peripheral "${CMAKE_MATCH_2}") + + if(operation STREQUAL "GENERATE") + nrf_regtool_generate_hex_from_dts(${peripheral}) + else() + message(FATAL_ERROR "Unrecognized package component: \"${component}\"") + endif() +endforeach() diff --git a/modules/hal_nordic/nrf-regtool/nrf-regtoolConfigVersion.cmake b/modules/hal_nordic/nrf-regtool/nrf-regtoolConfigVersion.cmake new file mode 100644 index 00000000000..e147d1b0532 --- /dev/null +++ b/modules/hal_nordic/nrf-regtool/nrf-regtoolConfigVersion.cmake @@ -0,0 +1,32 @@ +# Copyright (c) 2024 Nordic Semiconductor ASA +# SPDX-License-Identifier: Apache-2.0 + +find_program(NRF_REGTOOL nrf-regtool) + +if(NRF_REGTOOL) + execute_process( + COMMAND ${NRF_REGTOOL} --version + OUTPUT_VARIABLE version + RESULT_VARIABLE result + ) + + if(result EQUAL 0 AND version MATCHES "version ([0-9]+[.][0-9]+[.][0-9]+)") + set(PACKAGE_VERSION ${CMAKE_MATCH_1}) + if(PACKAGE_VERSION VERSION_GREATER_EQUAL PACKAGE_FIND_VERSION) + set(PACKAGE_VERSION_COMPATIBLE TRUE) + if(PACKAGE_VERSION VERSION_EQUAL PACKAGE_FIND_VERSION) + set(PACKAGE_VERSION_EXACT TRUE) + endif() + + message(STATUS + "Found nrf-regtool (found suitable version \"${PACKAGE_VERSION}\", " + "minimum required is \"${PACKAGE_FIND_VERSION}\")" + ) + return() + endif() + endif() +endif() + +# We only get here if we don't pass the version check. +set(PACKAGE_VERSION_UNSUITABLE TRUE) +set(NRF_REGTOOL NRF_REGTOOL-NOTFOUND CACHE INTERNAL "Path to a program") diff --git a/soc/arm/nordic_nrf/nrf54h/Kconfig.defconfig.nrf54h20_cpuapp b/soc/arm/nordic_nrf/nrf54h/Kconfig.defconfig.nrf54h20_cpuapp index eb56b8c369e..d90f87c0b89 100644 --- a/soc/arm/nordic_nrf/nrf54h/Kconfig.defconfig.nrf54h20_cpuapp +++ b/soc/arm/nordic_nrf/nrf54h/Kconfig.defconfig.nrf54h20_cpuapp @@ -11,4 +11,7 @@ config SOC config NUM_IRQS default 471 +config NRF_REGTOOL_GENERATE_UICR + default y + endif # SOC_NRF54H20_ENGA_CPUAPP diff --git a/soc/arm/nordic_nrf/nrf54h/Kconfig.defconfig.nrf54h20_cpurad b/soc/arm/nordic_nrf/nrf54h/Kconfig.defconfig.nrf54h20_cpurad index f63b9437775..6aae8c3a105 100644 --- a/soc/arm/nordic_nrf/nrf54h/Kconfig.defconfig.nrf54h20_cpurad +++ b/soc/arm/nordic_nrf/nrf54h/Kconfig.defconfig.nrf54h20_cpurad @@ -11,4 +11,7 @@ config SOC config NUM_IRQS default 471 +config NRF_REGTOOL_GENERATE_UICR + default y + endif # SOC_NRF54H20_ENGA_CPURAD From 784688a511fdfb493289b41e8253163e41fb29b6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andrzej=20G=C5=82=C4=85bek?= Date: Wed, 31 Jan 2024 15:20:20 +0100 Subject: [PATCH 3401/3723] drivers: serial: Kconfig.nrfx: Filter out options unsupported on nRF54H20 MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit On nRF54H20, only the new shim can be used and the enhanced poll out cannot be enabled since there is no DPPI support for this SoC yet. Signed-off-by: Andrzej Głąbek --- drivers/serial/Kconfig.nrfx | 3 +-- drivers/serial/Kconfig.nrfx_uart_instance | 1 + 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/serial/Kconfig.nrfx b/drivers/serial/Kconfig.nrfx index 8995b6b9fbf..4ea38e7b996 100644 --- a/drivers/serial/Kconfig.nrfx +++ b/drivers/serial/Kconfig.nrfx @@ -31,8 +31,7 @@ config UART_NRFX_UARTE config UART_NRFX_UARTE_LEGACY_SHIM bool "Legacy UARTE shim" depends on UART_NRFX_UARTE - # NRF54L15 need new UARTE driver - depends on !SOC_SERIES_NRF54LX + depends on !SOC_SERIES_NRF54LX && !SOC_SERIES_NRF54HX # New shim takes more ROM. Until it is fixed use legacy shim. default y diff --git a/drivers/serial/Kconfig.nrfx_uart_instance b/drivers/serial/Kconfig.nrfx_uart_instance index 718631a4d09..9e992ca9737 100644 --- a/drivers/serial/Kconfig.nrfx_uart_instance +++ b/drivers/serial/Kconfig.nrfx_uart_instance @@ -23,6 +23,7 @@ config UART_$(nrfx_uart_num)_ENHANCED_POLL_OUT depends on !SOC_SERIES_NRF54LX default y depends on HAS_HW_NRF_UARTE$(nrfx_uart_num) + depends on HAS_HW_NRF_PPI || HAS_HW_NRF_DPPIC select NRFX_PPI if HAS_HW_NRF_PPI select NRFX_DPPI if HAS_HW_NRF_DPPIC help From 976de4edbe57b000e5a6fb8239733fe51b45ae60 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andrzej=20G=C5=82=C4=85bek?= Date: Fri, 19 Jan 2024 11:51:41 +0100 Subject: [PATCH 3402/3723] drivers: serial: nrfx: Allow new UARTE instances to be used MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Extend Kconfig definitions and nrfx_config translations so that UARTE instances that are available in nRF54H20 can be used. Signed-off-by: Andrzej Głąbek --- drivers/serial/Kconfig.nrfx | 45 ++++++++++++++++++++ modules/hal_nordic/nrfx/Kconfig | 45 ++++++++++++++++++++ modules/hal_nordic/nrfx/nrfx_config.h | 27 ++++++++++++ soc/arm/nordic_nrf/Kconfig.peripherals | 27 ++++++++++++ soc/arm/nordic_nrf/validate_base_addresses.c | 9 ++++ 5 files changed, 153 insertions(+) diff --git a/drivers/serial/Kconfig.nrfx b/drivers/serial/Kconfig.nrfx index 4ea38e7b996..158731404e6 100644 --- a/drivers/serial/Kconfig.nrfx +++ b/drivers/serial/Kconfig.nrfx @@ -90,6 +90,51 @@ nrfx_uart_num = 30 rsource "Kconfig.nrfx_uart_instance" endif +if HAS_HW_NRF_UARTE120 +nrfx_uart_num = 120 +rsource "Kconfig.nrfx_uart_instance" +endif + +if HAS_HW_NRF_UARTE130 +nrfx_uart_num = 130 +rsource "Kconfig.nrfx_uart_instance" +endif + +if HAS_HW_NRF_UARTE131 +nrfx_uart_num = 131 +rsource "Kconfig.nrfx_uart_instance" +endif + +if HAS_HW_NRF_UARTE132 +nrfx_uart_num = 132 +rsource "Kconfig.nrfx_uart_instance" +endif + +if HAS_HW_NRF_UARTE133 +nrfx_uart_num = 133 +rsource "Kconfig.nrfx_uart_instance" +endif + +if HAS_HW_NRF_UARTE134 +nrfx_uart_num = 134 +rsource "Kconfig.nrfx_uart_instance" +endif + +if HAS_HW_NRF_UARTE135 +nrfx_uart_num = 135 +rsource "Kconfig.nrfx_uart_instance" +endif + +if HAS_HW_NRF_UARTE136 +nrfx_uart_num = 136 +rsource "Kconfig.nrfx_uart_instance" +endif + +if HAS_HW_NRF_UARTE137 +nrfx_uart_num = 137 +rsource "Kconfig.nrfx_uart_instance" +endif + config NRFX_TIMER0 default y depends on UART_0_NRF_HW_ASYNC_TIMER = 0 \ diff --git a/modules/hal_nordic/nrfx/Kconfig b/modules/hal_nordic/nrfx/Kconfig index d4efbb7cac8..ee1bd76b52f 100644 --- a/modules/hal_nordic/nrfx/Kconfig +++ b/modules/hal_nordic/nrfx/Kconfig @@ -637,6 +637,51 @@ config NRFX_UARTE30 depends on $(dt_nodelabel_has_compat,uart30,$(DT_COMPAT_NORDIC_NRF_UARTE)) select NRFX_UARTE +config NRFX_UARTE120 + bool "UARTE120 driver instance" + depends on $(dt_nodelabel_has_compat,uart120,$(DT_COMPAT_NORDIC_NRF_UARTE)) + select NRFX_UARTE + +config NRFX_UARTE130 + bool "UARTE130 driver instance" + depends on $(dt_nodelabel_has_compat,uart130,$(DT_COMPAT_NORDIC_NRF_UARTE)) + select NRFX_UARTE + +config NRFX_UARTE131 + bool "UARTE131 driver instance" + depends on $(dt_nodelabel_has_compat,uart131,$(DT_COMPAT_NORDIC_NRF_UARTE)) + select NRFX_UARTE + +config NRFX_UARTE132 + bool "UARTE132 driver instance" + depends on $(dt_nodelabel_has_compat,uart132,$(DT_COMPAT_NORDIC_NRF_UARTE)) + select NRFX_UARTE + +config NRFX_UARTE133 + bool "UARTE133 driver instance" + depends on $(dt_nodelabel_has_compat,uart133,$(DT_COMPAT_NORDIC_NRF_UARTE)) + select NRFX_UARTE + +config NRFX_UARTE134 + bool "UARTE134 driver instance" + depends on $(dt_nodelabel_has_compat,uart134,$(DT_COMPAT_NORDIC_NRF_UARTE)) + select NRFX_UARTE + +config NRFX_UARTE135 + bool "UARTE135 driver instance" + depends on $(dt_nodelabel_has_compat,uart135,$(DT_COMPAT_NORDIC_NRF_UARTE)) + select NRFX_UARTE + +config NRFX_UARTE136 + bool "UARTE136 driver instance" + depends on $(dt_nodelabel_has_compat,uart136,$(DT_COMPAT_NORDIC_NRF_UARTE)) + select NRFX_UARTE + +config NRFX_UARTE137 + bool "UARTE137 driver instance" + depends on $(dt_nodelabel_has_compat,uart137,$(DT_COMPAT_NORDIC_NRF_UARTE)) + select NRFX_UARTE + config NRFX_UARTE_CONFIG_SKIP_GPIO_CONFIG bool "UARTE GPIO configuration support" depends on NRFX_UARTE diff --git a/modules/hal_nordic/nrfx/nrfx_config.h b/modules/hal_nordic/nrfx/nrfx_config.h index 215eff5bfcd..be2f5599f78 100644 --- a/modules/hal_nordic/nrfx/nrfx_config.h +++ b/modules/hal_nordic/nrfx/nrfx_config.h @@ -606,6 +606,33 @@ #ifdef CONFIG_NRFX_UARTE30 #define NRFX_UARTE30_ENABLED 1 #endif +#ifdef CONFIG_NRFX_UARTE120 +#define NRFX_UARTE120_ENABLED 1 +#endif +#ifdef CONFIG_NRFX_UARTE130 +#define NRFX_UARTE130_ENABLED 1 +#endif +#ifdef CONFIG_NRFX_UARTE131 +#define NRFX_UARTE131_ENABLED 1 +#endif +#ifdef CONFIG_NRFX_UARTE132 +#define NRFX_UARTE132_ENABLED 1 +#endif +#ifdef CONFIG_NRFX_UARTE133 +#define NRFX_UARTE133_ENABLED 1 +#endif +#ifdef CONFIG_NRFX_UARTE134 +#define NRFX_UARTE134_ENABLED 1 +#endif +#ifdef CONFIG_NRFX_UARTE135 +#define NRFX_UARTE135_ENABLED 1 +#endif +#ifdef CONFIG_NRFX_UARTE136 +#define NRFX_UARTE136_ENABLED 1 +#endif +#ifdef CONFIG_NRFX_UARTE137 +#define NRFX_UARTE137_ENABLED 1 +#endif #ifdef CONFIG_NRFX_UARTE_CONFIG_SKIP_GPIO_CONFIG #define NRFX_UARTE_CONFIG_SKIP_GPIO_CONFIG 1 #endif diff --git a/soc/arm/nordic_nrf/Kconfig.peripherals b/soc/arm/nordic_nrf/Kconfig.peripherals index 5eeff856c96..da1c5f473c7 100644 --- a/soc/arm/nordic_nrf/Kconfig.peripherals +++ b/soc/arm/nordic_nrf/Kconfig.peripherals @@ -438,6 +438,33 @@ config HAS_HW_NRF_UARTE22 config HAS_HW_NRF_UARTE30 def_bool $(dt_nodelabel_enabled_with_compat,uart30,$(DT_COMPAT_NORDIC_NRF_UARTE)) +config HAS_HW_NRF_UARTE120 + def_bool $(dt_nodelabel_enabled_with_compat,uart120,$(DT_COMPAT_NORDIC_NRF_UARTE)) + +config HAS_HW_NRF_UARTE130 + def_bool $(dt_nodelabel_enabled_with_compat,uart130,$(DT_COMPAT_NORDIC_NRF_UARTE)) + +config HAS_HW_NRF_UARTE131 + def_bool $(dt_nodelabel_enabled_with_compat,uart131,$(DT_COMPAT_NORDIC_NRF_UARTE)) + +config HAS_HW_NRF_UARTE132 + def_bool $(dt_nodelabel_enabled_with_compat,uart132,$(DT_COMPAT_NORDIC_NRF_UARTE)) + +config HAS_HW_NRF_UARTE133 + def_bool $(dt_nodelabel_enabled_with_compat,uart133,$(DT_COMPAT_NORDIC_NRF_UARTE)) + +config HAS_HW_NRF_UARTE134 + def_bool $(dt_nodelabel_enabled_with_compat,uart134,$(DT_COMPAT_NORDIC_NRF_UARTE)) + +config HAS_HW_NRF_UARTE135 + def_bool $(dt_nodelabel_enabled_with_compat,uart135,$(DT_COMPAT_NORDIC_NRF_UARTE)) + +config HAS_HW_NRF_UARTE136 + def_bool $(dt_nodelabel_enabled_with_compat,uart136,$(DT_COMPAT_NORDIC_NRF_UARTE)) + +config HAS_HW_NRF_UARTE137 + def_bool $(dt_nodelabel_enabled_with_compat,uart137,$(DT_COMPAT_NORDIC_NRF_UARTE)) + config HAS_HW_NRF_USBD def_bool $(dt_compat_enabled,$(DT_COMPAT_NORDIC_NRF_USBD)) diff --git a/soc/arm/nordic_nrf/validate_base_addresses.c b/soc/arm/nordic_nrf/validate_base_addresses.c index 9daa820efa9..28ec231b132 100644 --- a/soc/arm/nordic_nrf/validate_base_addresses.c +++ b/soc/arm/nordic_nrf/validate_base_addresses.c @@ -214,6 +214,15 @@ CHECK_DT_REG(uart20, NRF_UARTE20); CHECK_DT_REG(uart21, NRF_UARTE21); CHECK_DT_REG(uart22, NRF_UARTE22); CHECK_DT_REG(uart30, NRF_UARTE30); +CHECK_DT_REG(uart120, NRF_UARTE120); +CHECK_DT_REG(uart130, NRF_UARTE130); +CHECK_DT_REG(uart131, NRF_UARTE131); +CHECK_DT_REG(uart132, NRF_UARTE132); +CHECK_DT_REG(uart133, NRF_UARTE133); +CHECK_DT_REG(uart134, NRF_UARTE134); +CHECK_DT_REG(uart135, NRF_UARTE135); +CHECK_DT_REG(uart136, NRF_UARTE136); +CHECK_DT_REG(uart137, NRF_UARTE137); CHECK_DT_REG(uicr, NRF_UICR); CHECK_DT_REG(usbd, NRF_USBD); CHECK_DT_REG(usbreg, NRF_USBREGULATOR); From bb065262bc8ea42ab56eda1d4e142b2e9c0ec617 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andrzej=20G=C5=82=C4=85bek?= Date: Wed, 31 Jan 2024 15:30:27 +0100 Subject: [PATCH 3403/3723] drivers: timer: nrf_grtc_timer: Add dependency on nRF clock control MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit ... in the related parts, so that the driver can be used on nRF54H20 where the clock control is not present yet. Signed-off-by: Andrzej Głąbek --- drivers/timer/nrf_grtc_timer.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/drivers/timer/nrf_grtc_timer.c b/drivers/timer/nrf_grtc_timer.c index a706c04bae0..8ac357864cc 100644 --- a/drivers/timer/nrf_grtc_timer.c +++ b/drivers/timer/nrf_grtc_timer.c @@ -7,7 +7,9 @@ #include #include #include +#if defined(CONFIG_CLOCK_CONTROL_NRF) #include +#endif #include #include #include @@ -521,6 +523,7 @@ static int sys_clock_driver_init(void) system_timeout_set(CYC_PER_TICK); } +#if defined(CONFIG_CLOCK_CONTROL_NRF) static const enum nrf_lfclk_start_mode mode = IS_ENABLED(CONFIG_SYSTEM_CLOCK_NO_WAIT) ? CLOCK_CONTROL_NRF_LF_START_NOWAIT @@ -529,6 +532,7 @@ static int sys_clock_driver_init(void) : CLOCK_CONTROL_NRF_LF_START_STABLE); z_nrf_clock_control_lf_on(mode); +#endif return 0; } From c50c4130a012ea7ceca2b4400173fe4db68f0f42 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andrzej=20G=C5=82=C4=85bek?= Date: Wed, 31 Jan 2024 13:05:36 +0100 Subject: [PATCH 3404/3723] tests: arm_irq_vector_table: Add special handling for nRF54H20 MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Different set of IRQ lines need to be used for this SoC and the CLOCK IRQ is not to be installed in the vector table. Signed-off-by: Andrzej Głąbek --- .../arm/arm_irq_vector_table/src/arm_irq_vector_table.c | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/tests/arch/arm/arm_irq_vector_table/src/arm_irq_vector_table.c b/tests/arch/arm/arm_irq_vector_table/src/arm_irq_vector_table.c index f18c30dac9a..61679107103 100644 --- a/tests/arch/arm/arm_irq_vector_table/src/arm_irq_vector_table.c +++ b/tests/arch/arm/arm_irq_vector_table/src/arm_irq_vector_table.c @@ -27,6 +27,9 @@ #elif defined(CONFIG_SOC_SERIES_NRF54LX) /* For nRF54L Series, use SWI00-02 interrupt lines. */ #define _ISR_OFFSET SWI00_IRQn +#elif defined(CONFIG_SOC_SERIES_NRF54HX) +/* For nRF54H Series, use BELLBOARD_0-2 interrupt lines. */ +#define _ISR_OFFSET BELLBOARD_0_IRQn #else /* For other nRF targets, use TIMER0-2 interrupt lines. */ #define _ISR_OFFSET TIMER0_IRQn @@ -141,6 +144,8 @@ typedef void (*vth)(void); /* Vector Table Handler */ void nrfx_power_clock_irq_handler(void); #if defined(CONFIG_SOC_SERIES_NRF51X) || defined(CONFIG_SOC_SERIES_NRF52X) #define POWER_CLOCK_IRQ_NUM POWER_CLOCK_IRQn +#elif defined(CONFIG_SOC_SERIES_NRF54HX) +#define POWER_CLOCK_IRQ_NUM -1 /* not needed */ #else #define POWER_CLOCK_IRQ_NUM CLOCK_POWER_IRQn #endif @@ -149,7 +154,7 @@ void nrfx_power_clock_irq_handler(void); void timer0_nrf_isr(void); #define TIMER_IRQ_HANDLER timer0_nrf_isr #define TIMER_IRQ_NUM TIMER0_IRQn -#elif defined(CONFIG_SOC_SERIES_NRF54LX) +#elif defined(CONFIG_SOC_SERIES_NRF54LX) || defined(CONFIG_SOC_SERIES_NRF54HX) void nrfx_grtc_irq_handler(void); #define TIMER_IRQ_HANDLER nrfx_grtc_irq_handler #define TIMER_IRQ_NUM GRTC_0_IRQn @@ -162,7 +167,9 @@ void rtc_nrf_isr(void); #define IRQ_VECTOR_TABLE_SIZE (MAX(POWER_CLOCK_IRQ_NUM, MAX(TIMER_IRQ_NUM, _ISR_OFFSET + 2)) + 1) vth __irq_vector_table _irq_vector_table[IRQ_VECTOR_TABLE_SIZE] = { +#if (POWER_CLOCK_IRQ_NUM != -1) [POWER_CLOCK_IRQ_NUM] = nrfx_power_clock_irq_handler, +#endif [TIMER_IRQ_NUM] = TIMER_IRQ_HANDLER, [_ISR_OFFSET] = isr0, isr1, isr2, }; From 1606f65972bea823bea8bbad181d8610c064bc71 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andrzej=20G=C5=82=C4=85bek?= Date: Thu, 1 Feb 2024 09:10:52 +0100 Subject: [PATCH 3405/3723] dts: nordic: Include input-event-codes.h from nrf_common.dtsi MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit ... so that there is no need to include that header individually for every added board based on an nRF SoC. Signed-off-by: Andrzej Głąbek --- dts/common/nordic/nrf_common.dtsi | 1 + 1 file changed, 1 insertion(+) diff --git a/dts/common/nordic/nrf_common.dtsi b/dts/common/nordic/nrf_common.dtsi index f09557b23de..cb2df6bcccd 100644 --- a/dts/common/nordic/nrf_common.dtsi +++ b/dts/common/nordic/nrf_common.dtsi @@ -8,6 +8,7 @@ #include #include #include +#include #include #include From b2c8f7680d1ad3cdb308c0a45c2c30f61d2c87e3 Mon Sep 17 00:00:00 2001 From: Gerard Marull-Paretas Date: Mon, 29 Jan 2024 16:13:27 +0100 Subject: [PATCH 3406/3723] scripts: west: runners: nrfjprog: add option to not erase On some new SoCs, the erase option is not required, so introduce a new option that doesn't set any erase mode. Signed-off-by: Gerard Marull-Paretas --- scripts/west_commands/runners/nrfjprog.py | 2 ++ 1 file changed, 2 insertions(+) diff --git a/scripts/west_commands/runners/nrfjprog.py b/scripts/west_commands/runners/nrfjprog.py index a28681ae6a5..15f147a4d87 100644 --- a/scripts/west_commands/runners/nrfjprog.py +++ b/scripts/west_commands/runners/nrfjprog.py @@ -69,6 +69,8 @@ def do_exec_op(self, op, force=False): cmd.append('--sectorerase') elif erase == 'ERASE_PAGES_INCLUDING_UICR': cmd.append('--sectoranduicrerase') + elif erase == 'NO_ERASE': + pass else: raise RuntimeError(f'Invalid erase mode: {erase}') From a99b5ca01b2e3d641e61c8a7f0b98e44e5cd42b5 Mon Sep 17 00:00:00 2001 From: Gerard Marull-Paretas Date: Mon, 29 Jan 2024 16:15:03 +0100 Subject: [PATCH 3407/3723] scripts: west: runners: nrfjprog: add erasepage op Add a new operation that allows erasing pages. Signed-off-by: Gerard Marull-Paretas --- scripts/west_commands/runners/nrfjprog.py | 3 +++ 1 file changed, 3 insertions(+) diff --git a/scripts/west_commands/runners/nrfjprog.py b/scripts/west_commands/runners/nrfjprog.py index 15f147a4d87..c1eebd32914 100644 --- a/scripts/west_commands/runners/nrfjprog.py +++ b/scripts/west_commands/runners/nrfjprog.py @@ -87,6 +87,9 @@ def do_exec_op(self, op, force=False): cmd.append('--reset') if _op['option'] == 'RESET_PIN': cmd.append('--pinreset') + elif op_type == 'erasepage': + cmd.append('--erasepage') + cmd.append(f"0x{_op['page']:08x}") else: raise RuntimeError(f'Invalid operation: {op_type}') From 6b987d31922d870b91b3530153243e2b4787be44 Mon Sep 17 00:00:00 2001 From: Gerard Marull-Paretas Date: Mon, 29 Jan 2024 16:19:30 +0100 Subject: [PATCH 3408/3723] scripts: west: runners: nrfjprog: add basic support for nRF54H series Add basic support to flash application and/or radio core for nRF54H series. Note that features like merged hexes present in nRF53 series is not supported. Signed-off-by: Gerard Marull-Paretas --- scripts/west_commands/runners/nrf_common.py | 63 +++++++++++++++------ scripts/west_commands/runners/nrfjprog.py | 6 +- 2 files changed, 51 insertions(+), 18 deletions(-) diff --git a/scripts/west_commands/runners/nrf_common.py b/scripts/west_commands/runners/nrf_common.py index 93871d831ee..76662c72ea9 100644 --- a/scripts/west_commands/runners/nrf_common.py +++ b/scripts/west_commands/runners/nrf_common.py @@ -24,11 +24,26 @@ ErrNotAvailableBecauseProtection = 24 ErrVerify = 25 +UICR_RANGES = { + 'NRF53_FAMILY': { + 'NRFDL_DEVICE_CORE_APPLICATION': (0x00FF8000, 0x00FF8800), + 'NRFDL_DEVICE_CORE_NETWORK': (0x01FF8000, 0x01FF8800), + }, + 'NRF54H_FAMILY': { + 'NRFDL_DEVICE_CORE_APPLICATION': (0x0FFF8000, 0x0FFF8800), + 'NRFDL_DEVICE_CORE_NETWORK': (0x0FFFA000, 0x0FFFA800), + }, + 'NRF91_FAMILY': { + 'NRFDL_DEVICE_CORE_APPLICATION': (0x00FF8000, 0x00FF8800), + } +} + class NrfBinaryRunner(ZephyrBinaryRunner): '''Runner front-end base class for nrf tools.''' def __init__(self, cfg, family, softreset, dev_id, erase=False, - reset=True, tool_opt=[], force=False, recover=False): + reset=True, tool_opt=[], force=False, recover=False, + erase_all_uicrs=False): super().__init__(cfg) self.hex_ = cfg.hex_file if family and not family.endswith('_FAMILY'): @@ -40,6 +55,7 @@ def __init__(self, cfg, family, softreset, dev_id, erase=False, self.reset = bool(reset) self.force = force self.recover = bool(recover) + self.erase_all_uicrs = bool(erase_all_uicrs) self.tool_opt = [] for opts in [shlex.split(opt) for opt in tool_opt]: @@ -59,7 +75,8 @@ def dev_id_help(cls) -> str: @classmethod def do_add_parser(cls, parser): parser.add_argument('--nrf-family', - choices=['NRF51', 'NRF52', 'NRF53', 'NRF54L', 'NRF91'], + choices=['NRF51', 'NRF52', 'NRF53', 'NRF54L', + 'NRF54H', 'NRF91'], help='''MCU family; still accepted for compatibility only''') parser.add_argument('--softreset', required=False, @@ -75,6 +92,11 @@ def do_add_parser(cls, parser): help='''erase all user available non-volatile memory and disable read back protection before flashing (erases flash for both cores on nRF53)''') + parser.add_argument('--erase-all-uicrs', required=False, + action='store_true', + help='''Erase all UICR registers before flashing + (nRF54H only). When not set, only UICR registers + present in the hex file will be erased.''') parser.set_defaults(reset=True) @@ -163,6 +185,8 @@ def ensure_family(self): self.family = 'NRF53_FAMILY' elif self.build_conf.getboolean('CONFIG_SOC_SERIES_NRF54LX'): self.family = 'NRF54L_FAMILY' + elif self.build_conf.getboolean('CONFIG_SOC_SERIES_NRF54HX'): + self.family = 'NRF54H_FAMILY' elif self.build_conf.getboolean('CONFIG_SOC_SERIES_NRF91X'): self.family = 'NRF91_FAMILY' else: @@ -174,21 +198,15 @@ def hex_refers_region(self, region_start, region_end): return True return False - def hex_has_uicr_content(self): - # A map from SoCs which need this check to their UICR address - # ranges. If self.family isn't in here, do nothing. - uicr_ranges = { - 'NRF53_FAMILY': ((0x00FF8000, 0x00FF8800), - (0x01FF8000, 0x01FF8800)), - 'NRF91_FAMILY': ((0x00FF8000, 0x00FF8800),), - } + def hex_get_uicrs(self): + hex_uicrs = {} - if self.family not in uicr_ranges: - return + if self.family in UICR_RANGES: + for uicr_core, uicr_range in UICR_RANGES[self.family].items(): + if self.hex_refers_region(*uicr_range): + hex_uicrs[uicr_core] = uicr_range - for region_start, region_end in uicr_ranges[self.family]: - if self.hex_refers_region(region_start, region_end): - return True + return hex_uicrs def flush(self, force=False): try: @@ -213,7 +231,7 @@ def flush(self, force=False): # If there are data in the UICR region it is likely that the # verify failed du to the UICR not been erased before, so giving # a warning here will hopefully enhance UX. - if self.hex_has_uicr_content(): + if self.hex_get_uicrs(): self.logger.warning( 'The hex file contains data placed in the UICR, which ' 'may require a full erase before reprogramming. Run ' @@ -266,11 +284,24 @@ def program_hex(self): if self.family == 'NRF53_FAMILY': # nRF53 requires special treatment due to the extra coprocessor. self.program_hex_nrf53(erase_arg, qspi_erase_opt) + elif self.family == 'NRF54H_FAMILY': + self.program_hex_nrf54h() else: self.op_program(self.hex_, erase_arg, qspi_erase_opt, defer=True) self.flush(force=False) + def program_hex_nrf54h(self): + if self.erase_all_uicrs: + uicrs = UICR_RANGES['NRF54H_FAMILY'] + else: + uicrs = self.hex_get_uicrs() + + for uicr_core, range in uicrs.items(): + self.exec_op('erasepage', defer=True, core=uicr_core, page=range[0]) + + self.op_program(self.hex_, 'NO_ERASE', None, defer=True) + def program_hex_nrf53(self, erase_arg, qspi_erase_opt): # program_hex() helper for nRF53. diff --git a/scripts/west_commands/runners/nrfjprog.py b/scripts/west_commands/runners/nrfjprog.py index c1eebd32914..723080d56c3 100644 --- a/scripts/west_commands/runners/nrfjprog.py +++ b/scripts/west_commands/runners/nrfjprog.py @@ -32,7 +32,8 @@ def do_create(cls, cfg, args): args.dev_id, erase=args.erase, reset=args.reset, tool_opt=args.tool_opt, force=args.force, - recover=args.recover) + recover=args.recover, + erase_all_uicrs=args.erase_all_uicrs) def do_get_boards(self): snrs = self.check_output(['nrfjprog', '--ids']) @@ -46,7 +47,8 @@ def do_exec_op(self, op, force=False): # Translate the op families = {'NRF51_FAMILY': 'NRF51', 'NRF52_FAMILY': 'NRF52', - 'NRF53_FAMILY': 'NRF53', 'NRF54L_FAMILY': 'NRF54L', 'NRF91_FAMILY': 'NRF91'} + 'NRF53_FAMILY': 'NRF53', 'NRF54L_FAMILY': 'NRF54L', + 'NRF54H_FAMILY': 'NRF54H', 'NRF91_FAMILY': 'NRF91'} cores = {'NRFDL_DEVICE_CORE_APPLICATION': 'CP_APPLICATION', 'NRFDL_DEVICE_CORE_NETWORK': 'CP_NETWORK'} From 38520a93d3f0e11ee54e9ae326d8139bd17e8ac0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andrzej=20G=C5=82=C4=85bek?= Date: Tue, 23 Jan 2024 17:54:45 +0100 Subject: [PATCH 3409/3723] boards: arm: Add initial support for nRF54H20 PDK MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Add targets that allows building for the Application and Radio cores in the nRF54H20 SoC on the nRF54H20 PDK board. Signed-off-by: Grzegorz Swiderski Signed-off-by: Gerard Marull-Paretas Signed-off-by: Andrzej Głąbek --- boards/arm/nrf54h20pdk_nrf54h20/Kconfig.board | 10 ++ .../nrf54h20pdk_nrf54h20/Kconfig.defconfig | 14 ++ boards/arm/nrf54h20pdk_nrf54h20/board.cmake | 3 + .../doc/img/nrf54h20pdk_nrf54h20.webp | Bin 0 -> 27232 bytes boards/arm/nrf54h20pdk_nrf54h20/doc/index.rst | 148 ++++++++++++++++++ .../nrf54h20pdk_nrf54h20-memory_map.dtsi | 79 ++++++++++ .../nrf54h20pdk_nrf54h20-pinctrl.dtsi | 53 +++++++ .../nrf54h20pdk_nrf54h20_cpuapp.dts | 137 ++++++++++++++++ .../nrf54h20pdk_nrf54h20_cpuapp.yaml | 15 ++ .../nrf54h20pdk_nrf54h20_cpuapp_defconfig | 33 ++++ .../nrf54h20pdk_nrf54h20_cpurad.dts | 58 +++++++ .../nrf54h20pdk_nrf54h20_cpurad.yaml | 15 ++ .../nrf54h20pdk_nrf54h20_cpurad_defconfig | 30 ++++ 13 files changed, 595 insertions(+) create mode 100644 boards/arm/nrf54h20pdk_nrf54h20/Kconfig.board create mode 100644 boards/arm/nrf54h20pdk_nrf54h20/Kconfig.defconfig create mode 100644 boards/arm/nrf54h20pdk_nrf54h20/board.cmake create mode 100644 boards/arm/nrf54h20pdk_nrf54h20/doc/img/nrf54h20pdk_nrf54h20.webp create mode 100644 boards/arm/nrf54h20pdk_nrf54h20/doc/index.rst create mode 100644 boards/arm/nrf54h20pdk_nrf54h20/nrf54h20pdk_nrf54h20-memory_map.dtsi create mode 100644 boards/arm/nrf54h20pdk_nrf54h20/nrf54h20pdk_nrf54h20-pinctrl.dtsi create mode 100644 boards/arm/nrf54h20pdk_nrf54h20/nrf54h20pdk_nrf54h20_cpuapp.dts create mode 100644 boards/arm/nrf54h20pdk_nrf54h20/nrf54h20pdk_nrf54h20_cpuapp.yaml create mode 100644 boards/arm/nrf54h20pdk_nrf54h20/nrf54h20pdk_nrf54h20_cpuapp_defconfig create mode 100644 boards/arm/nrf54h20pdk_nrf54h20/nrf54h20pdk_nrf54h20_cpurad.dts create mode 100644 boards/arm/nrf54h20pdk_nrf54h20/nrf54h20pdk_nrf54h20_cpurad.yaml create mode 100644 boards/arm/nrf54h20pdk_nrf54h20/nrf54h20pdk_nrf54h20_cpurad_defconfig diff --git a/boards/arm/nrf54h20pdk_nrf54h20/Kconfig.board b/boards/arm/nrf54h20pdk_nrf54h20/Kconfig.board new file mode 100644 index 00000000000..b76cfce6800 --- /dev/null +++ b/boards/arm/nrf54h20pdk_nrf54h20/Kconfig.board @@ -0,0 +1,10 @@ +# Copyright (c) 2024 Nordic Semiconductor ASA +# SPDX-License-Identifier: Apache-2.0 + +config BOARD_NRF54H20PDK_NRF54H20_CPUAPP + bool "nRF54H20 PDK nRF54H20 Application MCU" + depends on SOC_NRF54H20_ENGA_CPUAPP + +config BOARD_NRF54H20PDK_NRF54H20_CPURAD + bool "nRF54H20 PDK nRF54H20 Radio MCU" + depends on SOC_NRF54H20_ENGA_CPURAD diff --git a/boards/arm/nrf54h20pdk_nrf54h20/Kconfig.defconfig b/boards/arm/nrf54h20pdk_nrf54h20/Kconfig.defconfig new file mode 100644 index 00000000000..954276ec829 --- /dev/null +++ b/boards/arm/nrf54h20pdk_nrf54h20/Kconfig.defconfig @@ -0,0 +1,14 @@ +# Copyright (c) 2024 Nordic Semiconductor ASA +# SPDX-License-Identifier: Apache-2.0 + +config BOARD + default "nrf54h20pdk_nrf54h20_cpuapp" if BOARD_NRF54H20PDK_NRF54H20_CPUAPP + default "nrf54h20pdk_nrf54h20_cpurad" if BOARD_NRF54H20PDK_NRF54H20_CPURAD + +if BOARD_NRF54H20PDK_NRF54H20_CPUAPP || BOARD_NRF54H20PDK_NRF54H20_CPURAD + +# Data cache is disabled due to a HW issue in the EngA SoC revision. +config DCACHE + default n + +endif # BOARD_NRF54H20PDK_NRF54H20_CPUAPP || BOARD_NRF54H20PDK_NRF54H20_CPURAD diff --git a/boards/arm/nrf54h20pdk_nrf54h20/board.cmake b/boards/arm/nrf54h20pdk_nrf54h20/board.cmake new file mode 100644 index 00000000000..4c63f1dd05e --- /dev/null +++ b/boards/arm/nrf54h20pdk_nrf54h20/board.cmake @@ -0,0 +1,3 @@ +# SPDX-License-Identifier: Apache-2.0 + +include(${ZEPHYR_BASE}/boards/common/nrfjprog.board.cmake) diff --git a/boards/arm/nrf54h20pdk_nrf54h20/doc/img/nrf54h20pdk_nrf54h20.webp b/boards/arm/nrf54h20pdk_nrf54h20/doc/img/nrf54h20pdk_nrf54h20.webp new file mode 100644 index 0000000000000000000000000000000000000000..bcda6b0732b3acefe24e83332692e8ae898d47b4 GIT binary patch literal 27232 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 + status = "disabled"; + perm-read; + perm-write; + perm-execute; + }; + + ram3x_dma_region: memory@2fc07000 { + compatible = "nordic,owned-memory"; + reg = <0x2fc07000 DT_SIZE_K(4)>; + status = "disabled"; + perm-read; + perm-write; + #address-cells = <1>; + #size-cells = <1>; + ranges = <0x0 0x2fc07000 0x1000>; + + cpuapp_dma_region: memory@680 { + compatible = "zephyr,memory-region"; + reg = <0x680 DT_SIZE_K(2)>; + status = "disabled"; + #memory-region-cells = <0>; + zephyr,memory-region = "DMA_RAM3x_APP"; + }; + + cpurad_dma_region: memory@e80 { + compatible = "zephyr,memory-region"; + reg = <0xe80 0x80>; + status = "disabled"; + #memory-region-cells = <0>; + zephyr,memory-region = "DMA_RAM3x_RAD"; + }; + }; + }; +}; + +&mram1x { + cpurad_rx_partitions: cpurad-rx-partitions { + compatible = "nordic,owned-partitions", "fixed-partitions"; + status = "disabled"; + perm-read; + perm-execute; + perm-secure; + #address-cells = <1>; + #size-cells = <1>; + + cpurad_slot0_partition: partition@66000 { + reg = <0x66000 DT_SIZE_K(256)>; + }; + }; + + cpuapp_rx_partitions: cpuapp-rx-partitions { + compatible = "nordic,owned-partitions", "fixed-partitions"; + status = "disabled"; + perm-read; + perm-execute; + perm-secure; + #address-cells = <1>; + #size-cells = <1>; + + cpuapp_slot0_partition: partition@a6000 { + reg = <0xa6000 DT_SIZE_K(512)>; + }; + + cpuppr_code_partition: partition@126000 { + reg = <0x126000 DT_SIZE_K(28)>; + }; + }; +}; diff --git a/boards/arm/nrf54h20pdk_nrf54h20/nrf54h20pdk_nrf54h20-pinctrl.dtsi b/boards/arm/nrf54h20pdk_nrf54h20/nrf54h20pdk_nrf54h20-pinctrl.dtsi new file mode 100644 index 00000000000..d3b79120322 --- /dev/null +++ b/boards/arm/nrf54h20pdk_nrf54h20/nrf54h20pdk_nrf54h20-pinctrl.dtsi @@ -0,0 +1,53 @@ +/* + * Copyright (c) 2024 Nordic Semiconductor ASA + * + * SPDX-License-Identifier: Apache-2.0 + */ + +&pinctrl { + /omit-if-no-ref/ uart135_default: uart135_default { + group1 { + psels = , + ; + }; + + group2 { + bias-pull-up; + psels = , + ; + }; + }; + + /omit-if-no-ref/ uart135_sleep: uart135_sleep { + group1 { + low-power-enable; + psels = , + , + , + ; + }; + }; + + /omit-if-no-ref/ uart136_default: uart136_default { + group1 { + psels = , + ; + }; + + group2 { + bias-pull-up; + psels = , + ; + }; + }; + + /omit-if-no-ref/ uart136_sleep: uart136_sleep { + group1 { + low-power-enable; + psels = , + , + , + ; + }; + }; +}; diff --git a/boards/arm/nrf54h20pdk_nrf54h20/nrf54h20pdk_nrf54h20_cpuapp.dts b/boards/arm/nrf54h20pdk_nrf54h20/nrf54h20pdk_nrf54h20_cpuapp.dts new file mode 100644 index 00000000000..359c1f84307 --- /dev/null +++ b/boards/arm/nrf54h20pdk_nrf54h20/nrf54h20pdk_nrf54h20_cpuapp.dts @@ -0,0 +1,137 @@ +/* + * Copyright (c) 2024 Nordic Semiconductor ASA + * + * SPDX-License-Identifier: Apache-2.0 + */ + +/dts-v1/; + +#include +#include "nrf54h20pdk_nrf54h20-memory_map.dtsi" +#include "nrf54h20pdk_nrf54h20-pinctrl.dtsi" + +/ { + compatible = "nordic,nrf54h20pdk_nrf54h20-cpuapp"; + model = "Nordic nRF54H20 PDK nRF54H20 Application MCU"; + + chosen { + zephyr,console = &uart136; + zephyr,code-partition = &cpuapp_slot0_partition; + zephyr,flash = &mram1x; + zephyr,sram = &cpuapp_ram0; + }; + + aliases { + led0 = &led0; + led1 = &led1; + led2 = &led2; + led3 = &led3; + sw0 = &button0; + sw1 = &button1; + sw2 = &button2; + sw3 = &button3; + }; + + buttons { + compatible = "gpio-keys"; + + button0: button_0 { + gpios = <&gpio0 8 (GPIO_PULL_UP | GPIO_ACTIVE_LOW)>; + label = "Push button 0"; + zephyr,code = ; + }; + + button1: button_1 { + gpios = <&gpio0 9 (GPIO_PULL_UP | GPIO_ACTIVE_LOW)>; + label = "Push button 1"; + zephyr,code = ; + }; + + button2: button_2 { + gpios = <&gpio0 10 (GPIO_PULL_UP | GPIO_ACTIVE_LOW)>; + label = "Push button 2"; + zephyr,code = ; + }; + + button3: button_3 { + gpios = <&gpio0 11 (GPIO_PULL_UP | GPIO_ACTIVE_LOW)>; + label = "Push button 3"; + zephyr,code = ; + }; + }; + + leds { + compatible = "gpio-leds"; + + led0: led_0 { + gpios = <&gpio9 0 GPIO_ACTIVE_HIGH>; + label = "Green LED 0"; + }; + + led1: led_1 { + gpios = <&gpio9 1 GPIO_ACTIVE_HIGH>; + label = "Green LED 1"; + }; + + led2: led_2 { + gpios = <&gpio9 2 GPIO_ACTIVE_HIGH>; + label = "Green LED 2"; + }; + + led3: led_3 { + gpios = <&gpio9 3 GPIO_ACTIVE_HIGH>; + label = "Green LED 3"; + }; + }; +}; + +&ram3x_dma_region { + status = "okay"; +}; + +&cpuapp_dma_region { + status = "okay"; +}; + +&cpuapp_rx_partitions { + status = "okay"; +}; + +&cpuppr_vpr { + source-memory = <&cpuppr_code_partition>; + execution-memory = <&cpuppr_ram3x_region>; +}; + +&gpiote130 { + status = "okay"; + owned-channels = <0 1 2 3 4 5 6 7>; +}; + +&gpio0 { + status = "okay"; +}; + +&gpio9 { + status = "okay"; +}; + +&grtc { + status = "okay"; + child-owned-channels = <5 6>; + nonsecure-channels = <5 6>; + owned-channels = <4 5 6>; +}; + +&uart135 { + pinctrl-0 = <&uart135_default>; + pinctrl-1 = <&uart135_sleep>; + pinctrl-names = "default", "sleep"; +}; + +&uart136 { + status = "okay"; + memory-regions = <&cpuapp_dma_region>; + pinctrl-0 = <&uart136_default>; + pinctrl-1 = <&uart136_sleep>; + pinctrl-names = "default", "sleep"; +}; diff --git a/boards/arm/nrf54h20pdk_nrf54h20/nrf54h20pdk_nrf54h20_cpuapp.yaml b/boards/arm/nrf54h20pdk_nrf54h20/nrf54h20pdk_nrf54h20_cpuapp.yaml new file mode 100644 index 00000000000..a364c2863d3 --- /dev/null +++ b/boards/arm/nrf54h20pdk_nrf54h20/nrf54h20pdk_nrf54h20_cpuapp.yaml @@ -0,0 +1,15 @@ +# Copyright (c) 2024 Nordic Semiconductor ASA +# SPDX-License-Identifier: Apache-2.0 + +identifier: nrf54h20pdk_nrf54h20_cpuapp +name: nRF54H20-PDK-nRF54H20-Application +type: mcu +arch: arm +toolchain: + - gnuarmemb + - xtools + - zephyr +ram: 32 +flash: 368 +supported: + - gpio diff --git a/boards/arm/nrf54h20pdk_nrf54h20/nrf54h20pdk_nrf54h20_cpuapp_defconfig b/boards/arm/nrf54h20pdk_nrf54h20/nrf54h20pdk_nrf54h20_cpuapp_defconfig new file mode 100644 index 00000000000..1f7ef38a7fc --- /dev/null +++ b/boards/arm/nrf54h20pdk_nrf54h20/nrf54h20pdk_nrf54h20_cpuapp_defconfig @@ -0,0 +1,33 @@ +# Copyright (c) 2024 Nordic Semiconductor ASA +# SPDX-License-Identifier: Apache-2.0 + +CONFIG_SOC_SERIES_NRF54HX=y +CONFIG_SOC_NRF54H20=y +CONFIG_SOC_NRF54H20_ENGA_CPUAPP=y +CONFIG_BOARD_NRF54H20PDK_NRF54H20_CPUAPP=y + +CONFIG_USE_DT_CODE_PARTITION=y + +# Enable MPU +CONFIG_ARM_MPU=y + +# Enable hardware stack protection +CONFIG_HW_STACK_PROTECTION=y + +# MPU-based null-pointer dereferencing detection cannot be applied +# as the (0x0 - 0x400) region is unmapped for this target. +CONFIG_NULL_POINTER_EXCEPTION_DETECTION_NONE=y + +# Enable cache +CONFIG_CACHE_MANAGEMENT=y +CONFIG_EXTERNAL_CACHE=y + +# Enable GPIO +CONFIG_GPIO=y + +# Enable UART driver +CONFIG_SERIAL=y + +# Enable console +CONFIG_CONSOLE=y +CONFIG_UART_CONSOLE=y diff --git a/boards/arm/nrf54h20pdk_nrf54h20/nrf54h20pdk_nrf54h20_cpurad.dts b/boards/arm/nrf54h20pdk_nrf54h20/nrf54h20pdk_nrf54h20_cpurad.dts new file mode 100644 index 00000000000..02213d88645 --- /dev/null +++ b/boards/arm/nrf54h20pdk_nrf54h20/nrf54h20pdk_nrf54h20_cpurad.dts @@ -0,0 +1,58 @@ +/* + * Copyright (c) 2024 Nordic Semiconductor ASA + * + * SPDX-License-Identifier: Apache-2.0 + */ + +/dts-v1/; + +#include +#include "nrf54h20pdk_nrf54h20-memory_map.dtsi" +#include "nrf54h20pdk_nrf54h20-pinctrl.dtsi" + +/ { + compatible = "nordic,nrf54h20pdk_nrf54h20-cpurad"; + model = "Nordic nRF54H20 PDK nRF54H20 Radio MCU"; + + chosen { + zephyr,console = &uart135; + zephyr,code-partition = &cpurad_slot0_partition; + zephyr,flash = &mram1x; + zephyr,sram = &cpurad_ram0; + }; +}; + +&ram3x_dma_region { + status = "okay"; +}; + +&cpurad_dma_region { + status = "okay"; +}; + +&cpurad_rx_partitions { + status = "okay"; +}; + +&grtc { + status = "okay"; + child-owned-channels = <8 9 10 11 12>; + interrupts = <109 NRF_DEFAULT_IRQ_PRIORITY>, + <108 NRF_DEFAULT_IRQ_PRIORITY>; + nonsecure-channels = <8 9 10 11 12>; + owned-channels = <7 8 9 10 11 12 13 14>; +}; + +&uart135 { + status = "okay"; + memory-regions = <&cpurad_dma_region>; + pinctrl-0 = <&uart135_default>; + pinctrl-1 = <&uart135_sleep>; + pinctrl-names = "default", "sleep"; +}; + +&uart136 { + pinctrl-0 = <&uart136_default>; + pinctrl-1 = <&uart136_sleep>; + pinctrl-names = "default", "sleep"; +}; diff --git a/boards/arm/nrf54h20pdk_nrf54h20/nrf54h20pdk_nrf54h20_cpurad.yaml b/boards/arm/nrf54h20pdk_nrf54h20/nrf54h20pdk_nrf54h20_cpurad.yaml new file mode 100644 index 00000000000..d1c8548d07d --- /dev/null +++ b/boards/arm/nrf54h20pdk_nrf54h20/nrf54h20pdk_nrf54h20_cpurad.yaml @@ -0,0 +1,15 @@ +# Copyright (c) 2024 Nordic Semiconductor ASA +# SPDX-License-Identifier: Apache-2.0 + +identifier: nrf54h20pdk_nrf54h20_cpurad +name: nRF54H20-PDK-nRF54H20-Radio +type: mcu +arch: arm +toolchain: + - gnuarmemb + - xtools + - zephyr +ram: 32 +flash: 368 +supported: + - gpio diff --git a/boards/arm/nrf54h20pdk_nrf54h20/nrf54h20pdk_nrf54h20_cpurad_defconfig b/boards/arm/nrf54h20pdk_nrf54h20/nrf54h20pdk_nrf54h20_cpurad_defconfig new file mode 100644 index 00000000000..254d8656e61 --- /dev/null +++ b/boards/arm/nrf54h20pdk_nrf54h20/nrf54h20pdk_nrf54h20_cpurad_defconfig @@ -0,0 +1,30 @@ +# Copyright (c) 2024 Nordic Semiconductor ASA +# SPDX-License-Identifier: Apache-2.0 + +CONFIG_SOC_SERIES_NRF54HX=y +CONFIG_SOC_NRF54H20=y +CONFIG_SOC_NRF54H20_ENGA_CPURAD=y +CONFIG_BOARD_NRF54H20PDK_NRF54H20_CPURAD=y + +CONFIG_USE_DT_CODE_PARTITION=y + +# Enable MPU +CONFIG_ARM_MPU=y + +# Enable hardware stack protection +CONFIG_HW_STACK_PROTECTION=y + +# MPU-based null-pointer dereferencing detection cannot be applied +# as the (0x0 - 0x400) region is unmapped for this target. +CONFIG_NULL_POINTER_EXCEPTION_DETECTION_NONE=y + +# Enable cache +CONFIG_CACHE_MANAGEMENT=y +CONFIG_EXTERNAL_CACHE=y + +# Enable UART driver +CONFIG_SERIAL=y + +# Enable console +CONFIG_CONSOLE=y +CONFIG_UART_CONSOLE=y From 00566d64fa901cbd7725068f6ff82ee0f0fffc16 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andrzej=20G=C5=82=C4=85bek?= Date: Wed, 31 Jan 2024 15:37:12 +0100 Subject: [PATCH 3410/3723] tests: lib: cpp: Exclude cpp98 test on nRF54H20 MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Similar to nRF54L15, the MDK files in HAL for this SoC are not compatible with C++98, so currently the test cannot be performed on this SoC. Signed-off-by: Andrzej Głąbek --- tests/lib/cpp/cxx/testcase.yaml | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/tests/lib/cpp/cxx/testcase.yaml b/tests/lib/cpp/cxx/testcase.yaml index 465a751dab3..f06b451742b 100644 --- a/tests/lib/cpp/cxx/testcase.yaml +++ b/tests/lib/cpp/cxx/testcase.yaml @@ -34,8 +34,11 @@ tests: # -std=c++98) cpp.main.cpp98: arch_exclude: posix - # Exclude nRF54L15 as its HAL is not compatible with C++98. - platform_exclude: nrf54l15pdk_nrf54l15_cpuapp + # Exclude nRF54L15 and nRF54H20 as Nordic HAL is not compatible with C++98. + platform_exclude: + - nrf54l15pdk_nrf54l15_cpuapp + - nrf54h20pdk_nrf54h20_cpuapp + - nrf54h20pdk_nrf54h20_cpurad build_only: true extra_configs: - CONFIG_STD_CPP98=y From d1468b8484af50053b29b2fd673d577623979324 Mon Sep 17 00:00:00 2001 From: Gerard Marull-Paretas Date: Wed, 31 Jan 2024 13:21:10 +0100 Subject: [PATCH 3411/3723] drivers: misc: nordic_vpr_launcher: initial version Add a custom driver that takes care of loading and launching RISC-V VPR cores found on the new nRF54 SoCs. Signed-off-by: Gerard Marull-Paretas --- drivers/misc/CMakeLists.txt | 1 + drivers/misc/Kconfig | 1 + .../misc/nordic_vpr_launcher/CMakeLists.txt | 5 ++ drivers/misc/nordic_vpr_launcher/Kconfig | 24 +++++++ .../nordic_vpr_launcher/nordic_vpr_launcher.c | 71 +++++++++++++++++++ 5 files changed, 102 insertions(+) create mode 100644 drivers/misc/nordic_vpr_launcher/CMakeLists.txt create mode 100644 drivers/misc/nordic_vpr_launcher/Kconfig create mode 100644 drivers/misc/nordic_vpr_launcher/nordic_vpr_launcher.c diff --git a/drivers/misc/CMakeLists.txt b/drivers/misc/CMakeLists.txt index 6c4ec2384d9..c23bdb185de 100644 --- a/drivers/misc/CMakeLists.txt +++ b/drivers/misc/CMakeLists.txt @@ -7,3 +7,4 @@ add_subdirectory_ifdef(CONFIG_PIO_RPI_PICO pio_rpi_pico) add_subdirectory_ifdef(CONFIG_NXP_S32_EMIOS nxp_s32_emios) add_subdirectory_ifdef(CONFIG_TIMEAWARE_GPIO timeaware_gpio) add_subdirectory_ifdef(CONFIG_DEVMUX devmux) +add_subdirectory_ifdef(CONFIG_NORDIC_VPR_LAUNCHER nordic_vpr_launcher) diff --git a/drivers/misc/Kconfig b/drivers/misc/Kconfig index 52c77b4c7ec..3511b8b6fd4 100644 --- a/drivers/misc/Kconfig +++ b/drivers/misc/Kconfig @@ -11,5 +11,6 @@ source "drivers/misc/pio_rpi_pico/Kconfig" source "drivers/misc/nxp_s32_emios/Kconfig" source "drivers/misc/timeaware_gpio/Kconfig" source "drivers/misc/devmux/Kconfig" +source "drivers/misc/nordic_vpr_launcher/Kconfig" endmenu diff --git a/drivers/misc/nordic_vpr_launcher/CMakeLists.txt b/drivers/misc/nordic_vpr_launcher/CMakeLists.txt new file mode 100644 index 00000000000..70c84e84217 --- /dev/null +++ b/drivers/misc/nordic_vpr_launcher/CMakeLists.txt @@ -0,0 +1,5 @@ +# Copyright (c) 2024 Nordic Semiconductor ASA +# SPDX-License-Identifier: Apache-2.0 + +zephyr_library() +zephyr_library_sources(nordic_vpr_launcher.c) diff --git a/drivers/misc/nordic_vpr_launcher/Kconfig b/drivers/misc/nordic_vpr_launcher/Kconfig new file mode 100644 index 00000000000..57605e505f2 --- /dev/null +++ b/drivers/misc/nordic_vpr_launcher/Kconfig @@ -0,0 +1,24 @@ +# Copyright (c) 2024 Nordic Semiconductor ASA +# SPDX-License-Identifier: Apache-2.0 + +config NORDIC_VPR_LAUNCHER + bool "Nordic VPR coprocessor launcher" + default y + depends on DT_HAS_NORDIC_NRF_VPR_COPROCESSOR_ENABLED + help + When enabled, the VPR coprocessors will be automatically launched + during system initialization. + +if NORDIC_VPR_LAUNCHER + +module = NORDIC_VPR_LAUNCHER +module-str = Nordic VPR Launcher +source "subsys/logging/Kconfig.template.log_config" + +config NORDIC_VPR_LAUNCHER_INIT_PRIORITY + int "Nordic VPR coprocessor launcher init priority" + default KERNEL_INIT_PRIORITY_DEVICE + help + The init priority of the VPR coprocessor launcher. + +endif # NORDIC_VPR_LAUNCHER diff --git a/drivers/misc/nordic_vpr_launcher/nordic_vpr_launcher.c b/drivers/misc/nordic_vpr_launcher/nordic_vpr_launcher.c new file mode 100644 index 00000000000..161465ba02c --- /dev/null +++ b/drivers/misc/nordic_vpr_launcher/nordic_vpr_launcher.c @@ -0,0 +1,71 @@ +/* + * Copyright (c) 2024 Nordic Semiconductor ASA + * SPDX-License-Identifier: Apache-2.0 + */ + +#define DT_DRV_COMPAT nordic_nrf_vpr_coprocessor + +#include + +#include +#include +#include +#include +#include + +#include + +LOG_MODULE_REGISTER(nordic_vpr_launcher, CONFIG_NORDIC_VPR_LAUNCHER_LOG_LEVEL); + +struct nordic_vpr_launcher_config { + NRF_VPR_Type *vpr; + uintptr_t exec_addr; +#if DT_ANY_INST_HAS_PROP_STATUS_OKAY(source_memory) + uintptr_t src_addr; + size_t src_size; +#endif +}; + +static int nordic_vpr_launcher_init(const struct device *dev) +{ + const struct nordic_vpr_launcher_config *config = dev->config; + +#if DT_ANY_INST_HAS_PROP_STATUS_OKAY(source_memory) + if (config->src_size > 0U) { + LOG_DBG("Loading VPR (%p) from %p to %p (%zu bytes)", config->vpr, + (void *)config->src_addr, (void *)config->exec_addr, config->src_size); + memcpy((void *)config->exec_addr, (void *)config->src_addr, config->src_size); + } +#endif + + LOG_DBG("Launching VPR (%p) from %p", config->vpr, (void *)config->exec_addr); + nrf_vpr_initpc_set(config->vpr, config->exec_addr); + nrf_vpr_cpurun_set(config->vpr, true); + + return 0; +} + +/* obtain VPR source address either from memory or partition */ +#define VPR_SRC_ADDR(node_id) \ + (DT_REG_ADDR(node_id) + \ + COND_CODE_0(DT_FIXED_PARTITION_EXISTS(node_id), (0), (DT_REG_ADDR(DT_GPARENT(node_id))))) + +#define NORDIC_VPR_LAUNCHER_DEFINE(inst) \ + COND_CODE_1(DT_NODE_HAS_PROP(inst, source_memory), \ + (BUILD_ASSERT((DT_REG_SIZE(DT_INST_PHANDLE(inst, execution_memory)) == \ + DT_REG_SIZE(DT_INST_PHANDLE(inst, source_memory))), \ + "Source/execution memory sizes mismatch");), \ + ()) \ + \ + static const struct nordic_vpr_launcher_config config##inst = { \ + .vpr = (NRF_VPR_Type *)DT_INST_REG_ADDR(inst), \ + .exec_addr = DT_REG_ADDR(DT_INST_PHANDLE(inst, execution_memory)), \ + COND_CODE_1(DT_INST_NODE_HAS_PROP(inst, source_memory), \ + (.src_addr = VPR_SRC_ADDR(DT_INST_PHANDLE(inst, source_memory)), \ + .src_size = DT_REG_SIZE(DT_INST_PHANDLE(inst, source_memory)),), \ + ())}; \ + \ + DEVICE_DT_INST_DEFINE(inst, nordic_vpr_launcher_init, NULL, NULL, &config##inst, \ + POST_KERNEL, CONFIG_NORDIC_VPR_LAUNCHER_INIT_PRIORITY, NULL); + +DT_INST_FOREACH_STATUS_OKAY(NORDIC_VPR_LAUNCHER_DEFINE) From 245da8aae65b2abdaa2654c63dc22994de64ee08 Mon Sep 17 00:00:00 2001 From: Gerard Marull-Paretas Date: Thu, 1 Feb 2024 15:14:53 +0100 Subject: [PATCH 3412/3723] snippets: add nordic-ppr Add a new snippet that allows to build any application with the capability to boot the PPR core found in some nRF54 SoCs. Signed-off-by: Gerard Marull-Paretas --- snippets/nordic-ppr/README.rst | 10 ++++++++++ .../boards/nrf54h20pdk_nrf54h20_cpuapp.overlay | 12 ++++++++++++ snippets/nordic-ppr/nordic-ppr.overlay | 8 ++++++++ snippets/nordic-ppr/snippet.yml | 8 ++++++++ 4 files changed, 38 insertions(+) create mode 100644 snippets/nordic-ppr/README.rst create mode 100644 snippets/nordic-ppr/boards/nrf54h20pdk_nrf54h20_cpuapp.overlay create mode 100644 snippets/nordic-ppr/nordic-ppr.overlay create mode 100644 snippets/nordic-ppr/snippet.yml diff --git a/snippets/nordic-ppr/README.rst b/snippets/nordic-ppr/README.rst new file mode 100644 index 00000000000..36eb74d193f --- /dev/null +++ b/snippets/nordic-ppr/README.rst @@ -0,0 +1,10 @@ +.. _nordic-ppr: + +Nordic PPR snippet (nordic-ppr) +############################### + +Overview +******** + +This snippet allows users to build Zephyr with the capability to boot Nordic PPR +(Peripheral Processor) from another core. diff --git a/snippets/nordic-ppr/boards/nrf54h20pdk_nrf54h20_cpuapp.overlay b/snippets/nordic-ppr/boards/nrf54h20pdk_nrf54h20_cpuapp.overlay new file mode 100644 index 00000000000..75128f42a13 --- /dev/null +++ b/snippets/nordic-ppr/boards/nrf54h20pdk_nrf54h20_cpuapp.overlay @@ -0,0 +1,12 @@ +/* + * Copyright (c) 2024 Nordic Semiconductor + * SPDX-License-Identifier: Apache-2.0 + */ + +&cpuppr_ram3x_region { + status = "okay"; +}; + +&uart135 { + status = "reserved"; +}; diff --git a/snippets/nordic-ppr/nordic-ppr.overlay b/snippets/nordic-ppr/nordic-ppr.overlay new file mode 100644 index 00000000000..e33885fc10d --- /dev/null +++ b/snippets/nordic-ppr/nordic-ppr.overlay @@ -0,0 +1,8 @@ +/* + * Copyright (c) 2024 Nordic Semiconductor + * SPDX-License-Identifier: Apache-2.0 + */ + +&cpuppr_vpr { + status = "okay"; +}; diff --git a/snippets/nordic-ppr/snippet.yml b/snippets/nordic-ppr/snippet.yml new file mode 100644 index 00000000000..9e1f20bb757 --- /dev/null +++ b/snippets/nordic-ppr/snippet.yml @@ -0,0 +1,8 @@ +name: nordic-ppr +append: + EXTRA_DTC_OVERLAY_FILE: nordic-ppr.overlay + +boards: + nrf54h20pdk_nrf54h20_cpuapp: + append: + EXTRA_DTC_OVERLAY_FILE: boards/nrf54h20pdk_nrf54h20_cpuapp.overlay From d230542f1d0e94f10cf817f6b4c9a99b49927259 Mon Sep 17 00:00:00 2001 From: Gerard Marull-Paretas Date: Wed, 31 Jan 2024 20:16:21 +0100 Subject: [PATCH 3413/3723] drivers: serial: nrfx_uarte2: drop soc.h As it is not required (e.g. RISC-V nRF54H port does not provide soc.h) Signed-off-by: Gerard Marull-Paretas --- drivers/serial/uart_nrfx_uarte2.c | 1 - 1 file changed, 1 deletion(-) diff --git a/drivers/serial/uart_nrfx_uarte2.c b/drivers/serial/uart_nrfx_uarte2.c index 65bfeccdafd..750c211efb0 100644 --- a/drivers/serial/uart_nrfx_uarte2.c +++ b/drivers/serial/uart_nrfx_uarte2.c @@ -17,7 +17,6 @@ #include #include #include -#include #include #include #include From 270ae630368781b58701f76ee1559391d83f1d39 Mon Sep 17 00:00:00 2001 From: Gerard Marull-Paretas Date: Wed, 31 Jan 2024 20:15:20 +0100 Subject: [PATCH 3414/3723] modules: hal_nordic: add configuration for nRF54H PPR core MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Add nrfx configuration file to make the nrfx HAL work for nRF54H PPR core. Signed-off-by: Gerard Marull-Paretas Signed-off-by: Andrzej Głąbek --- modules/hal_nordic/nrfx/nrfx_config.h | 2 + .../nrfx/nrfx_config_nrf54h20_enga_ppr.h | 1855 +++++++++++++++++ modules/hal_nordic/nrfx/nrfx_glue.h | 23 +- 3 files changed, 1877 insertions(+), 3 deletions(-) create mode 100644 modules/hal_nordic/nrfx/nrfx_config_nrf54h20_enga_ppr.h diff --git a/modules/hal_nordic/nrfx/nrfx_config.h b/modules/hal_nordic/nrfx/nrfx_config.h index be2f5599f78..26d662be39d 100644 --- a/modules/hal_nordic/nrfx/nrfx_config.h +++ b/modules/hal_nordic/nrfx/nrfx_config.h @@ -748,6 +748,8 @@ #include #elif defined(NRF54H20_ENGA_XXAA) && defined(NRF_RADIOCORE) #include +#elif defined(NRF54H20_ENGA_XXAA) && defined(NRF_PPR) + #include #elif defined(NRF9120_XXAA) || defined(NRF9160_XXAA) #include #elif defined(NRF54L15_ENGA_XXAA) && defined(NRF_APPLICATION) diff --git a/modules/hal_nordic/nrfx/nrfx_config_nrf54h20_enga_ppr.h b/modules/hal_nordic/nrfx/nrfx_config_nrf54h20_enga_ppr.h new file mode 100644 index 00000000000..369fe18a81f --- /dev/null +++ b/modules/hal_nordic/nrfx/nrfx_config_nrf54h20_enga_ppr.h @@ -0,0 +1,1855 @@ +/* + * Copyright (c) 2024, Nordic Semiconductor ASA + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#ifndef NRFX_CONFIG_NRF54H20_ENGA_PPR_H__ +#define NRFX_CONFIG_NRF54H20_ENGA_PPR_H__ + +#ifndef NRFX_CONFIG_H__ +#error "This file should not be included directly. Include nrfx_config.h instead." +#endif + + +/** + * @brief NRFX_DEFAULT_IRQ_PRIORITY + * + * Integer value. Minimum: 0. Maximum: 3. + */ +#ifndef NRFX_DEFAULT_IRQ_PRIORITY +#define NRFX_DEFAULT_IRQ_PRIORITY 3 +#endif + +/** + * @brief NRFX_COMP_ENABLED + * + * Boolean. Accepted values: 0 and 1. + */ +#ifndef NRFX_COMP_ENABLED +#define NRFX_COMP_ENABLED 0 +#endif + +/** + * @brief NRFX_COMP_DEFAULT_CONFIG_IRQ_PRIORITY + * + * Integer value. Minimum: 0. Maximum: 3. + */ +#ifndef NRFX_COMP_DEFAULT_CONFIG_IRQ_PRIORITY +#define NRFX_COMP_DEFAULT_CONFIG_IRQ_PRIORITY NRFX_DEFAULT_IRQ_PRIORITY +#endif + +/** + * @brief NRFX_COMP_CONFIG_LOG_ENABLED + * + * Boolean. Accepted values: 0 and 1. + */ +#ifndef NRFX_COMP_CONFIG_LOG_ENABLED +#define NRFX_COMP_CONFIG_LOG_ENABLED 0 +#endif + +/** + * @brief NRFX_COMP_CONFIG_LOG_LEVEL + * + * Integer value. + * Supported values: + * - Off = 0 + * - Error = 1 + * - Warning = 2 + * - Info = 3 + * - Debug = 4 + */ +#ifndef NRFX_COMP_CONFIG_LOG_LEVEL +#define NRFX_COMP_CONFIG_LOG_LEVEL 3 +#endif + +/** + * @brief NRFX_DPPI_ENABLED + * + * Boolean. Accepted values: 0 and 1. + */ +#ifndef NRFX_DPPI_ENABLED +#define NRFX_DPPI_ENABLED 0 +#endif + +/** + * @brief NRFX_DPPI_CONFIG_LOG_ENABLED + * + * Boolean. Accepted values: 0 and 1. + */ +#ifndef NRFX_DPPI_CONFIG_LOG_ENABLED +#define NRFX_DPPI_CONFIG_LOG_ENABLED 0 +#endif + +/** + * @brief NRFX_DPPI_CONFIG_LOG_LEVEL + * + * Integer value. + * Supported values: + * - Off = 0 + * - Error = 1 + * - Warning = 2 + * - Info = 3 + * - Debug = 4 + */ +#ifndef NRFX_DPPI_CONFIG_LOG_LEVEL +#define NRFX_DPPI_CONFIG_LOG_LEVEL 3 +#endif + +/** + * @brief NRFX_DPPI120_PUB_CONFIG_ALLOWED_CHANNELS_MASK + */ +#ifndef NRFX_DPPI120_PUB_CONFIG_ALLOWED_CHANNELS_MASK +#define NRFX_DPPI120_PUB_CONFIG_ALLOWED_CHANNELS_MASK 0x00000030 +#endif + +/** + * @brief NRFX_DPPI130_PUB_CONFIG_ALLOWED_CHANNELS_MASK + */ +#ifndef NRFX_DPPI130_PUB_CONFIG_ALLOWED_CHANNELS_MASK +#define NRFX_DPPI130_PUB_CONFIG_ALLOWED_CHANNELS_MASK 0x000000ff +#endif + +/** + * @brief NRFX_DPPI131_PUB_CONFIG_ALLOWED_CHANNELS_MASK + */ +#ifndef NRFX_DPPI131_PUB_CONFIG_ALLOWED_CHANNELS_MASK +#define NRFX_DPPI131_PUB_CONFIG_ALLOWED_CHANNELS_MASK 0 +#endif + +/** + * @brief NRFX_DPPI132_PUB_CONFIG_ALLOWED_CHANNELS_MASK + */ +#ifndef NRFX_DPPI132_PUB_CONFIG_ALLOWED_CHANNELS_MASK +#define NRFX_DPPI132_PUB_CONFIG_ALLOWED_CHANNELS_MASK 0 +#endif + +/** + * @brief NRFX_DPPI133_PUB_CONFIG_ALLOWED_CHANNELS_MASK + */ +#ifndef NRFX_DPPI133_PUB_CONFIG_ALLOWED_CHANNELS_MASK +#define NRFX_DPPI133_PUB_CONFIG_ALLOWED_CHANNELS_MASK 0x0000001e +#endif + +/** + * @brief NRFX_DPPI134_PUB_CONFIG_ALLOWED_CHANNELS_MASK + */ +#ifndef NRFX_DPPI134_PUB_CONFIG_ALLOWED_CHANNELS_MASK +#define NRFX_DPPI134_PUB_CONFIG_ALLOWED_CHANNELS_MASK 0x00000020 +#endif + +/** + * @brief NRFX_DPPI135_PUB_CONFIG_ALLOWED_CHANNELS_MASK + */ +#ifndef NRFX_DPPI135_PUB_CONFIG_ALLOWED_CHANNELS_MASK +#define NRFX_DPPI135_PUB_CONFIG_ALLOWED_CHANNELS_MASK 0x00000040 +#endif + +/** + * @brief NRFX_DPPI136_PUB_CONFIG_ALLOWED_CHANNELS_MASK + */ +#ifndef NRFX_DPPI136_PUB_CONFIG_ALLOWED_CHANNELS_MASK +#define NRFX_DPPI136_PUB_CONFIG_ALLOWED_CHANNELS_MASK 0x00000081 +#endif + +/** + * @brief NRFX_DPPI120_SUB_CONFIG_ALLOWED_CHANNELS_MASK + */ +#ifndef NRFX_DPPI120_SUB_CONFIG_ALLOWED_CHANNELS_MASK +#define NRFX_DPPI120_SUB_CONFIG_ALLOWED_CHANNELS_MASK 0x0000000c +#endif + +/** + * @brief NRFX_DPPI130_SUB_CONFIG_ALLOWED_CHANNELS_MASK + */ +#ifndef NRFX_DPPI130_SUB_CONFIG_ALLOWED_CHANNELS_MASK +#define NRFX_DPPI130_SUB_CONFIG_ALLOWED_CHANNELS_MASK 0x000000ff +#endif + +/** + * @brief NRFX_DPPI131_SUB_CONFIG_ALLOWED_CHANNELS_MASK + */ +#ifndef NRFX_DPPI131_SUB_CONFIG_ALLOWED_CHANNELS_MASK +#define NRFX_DPPI131_SUB_CONFIG_ALLOWED_CHANNELS_MASK 0x000000ff +#endif + +/** + * @brief NRFX_DPPI132_SUB_CONFIG_ALLOWED_CHANNELS_MASK + */ +#ifndef NRFX_DPPI132_SUB_CONFIG_ALLOWED_CHANNELS_MASK +#define NRFX_DPPI132_SUB_CONFIG_ALLOWED_CHANNELS_MASK 0 +#endif + +/** + * @brief NRFX_DPPI133_SUB_CONFIG_ALLOWED_CHANNELS_MASK + */ +#ifndef NRFX_DPPI133_SUB_CONFIG_ALLOWED_CHANNELS_MASK +#define NRFX_DPPI133_SUB_CONFIG_ALLOWED_CHANNELS_MASK 0x000000e1 +#endif + +/** + * @brief NRFX_DPPI134_SUB_CONFIG_ALLOWED_CHANNELS_MASK + */ +#ifndef NRFX_DPPI134_SUB_CONFIG_ALLOWED_CHANNELS_MASK +#define NRFX_DPPI134_SUB_CONFIG_ALLOWED_CHANNELS_MASK 0x000000df +#endif + +/** + * @brief NRFX_DPPI135_SUB_CONFIG_ALLOWED_CHANNELS_MASK + */ +#ifndef NRFX_DPPI135_SUB_CONFIG_ALLOWED_CHANNELS_MASK +#define NRFX_DPPI135_SUB_CONFIG_ALLOWED_CHANNELS_MASK 0x000000bf +#endif + +/** + * @brief NRFX_DPPI136_SUB_CONFIG_ALLOWED_CHANNELS_MASK + */ +#ifndef NRFX_DPPI136_SUB_CONFIG_ALLOWED_CHANNELS_MASK +#define NRFX_DPPI136_SUB_CONFIG_ALLOWED_CHANNELS_MASK 0x0000007e +#endif + +/** + * @brief NRFX_GPIOTE_ENABLED + * + * Boolean. Accepted values: 0 and 1. + */ +#ifndef NRFX_GPIOTE_ENABLED +#define NRFX_GPIOTE_ENABLED 0 +#endif + +/** + * @brief NRFX_GPIOTE_DEFAULT_CONFIG_IRQ_PRIORITY + * + * Integer value. Minimum: 0. Maximum: 3. + */ +#ifndef NRFX_GPIOTE_DEFAULT_CONFIG_IRQ_PRIORITY +#define NRFX_GPIOTE_DEFAULT_CONFIG_IRQ_PRIORITY NRFX_DEFAULT_IRQ_PRIORITY +#endif + +/** + * @brief NRFX_GPIOTE_CONFIG_NUM_OF_EVT_HANDLERS + * + * Integer value. Minimum: 0. Maximum: 15. + */ +#ifndef NRFX_GPIOTE_CONFIG_NUM_OF_EVT_HANDLERS +#define NRFX_GPIOTE_CONFIG_NUM_OF_EVT_HANDLERS 1 +#endif + +/** + * @brief NRFX_GPIOTE_CONFIG_LOG_ENABLED + * + * Boolean. Accepted values: 0 and 1. + */ +#ifndef NRFX_GPIOTE_CONFIG_LOG_ENABLED +#define NRFX_GPIOTE_CONFIG_LOG_ENABLED 0 +#endif + +/** + * @brief NRFX_GPIOTE_CONFIG_LOG_LEVEL + * + * Integer value. + * Supported values: + * - Off = 0 + * - Error = 1 + * - Warning = 2 + * - Info = 3 + * - Debug = 4 + */ +#ifndef NRFX_GPIOTE_CONFIG_LOG_LEVEL +#define NRFX_GPIOTE_CONFIG_LOG_LEVEL 3 +#endif + +/** + * @brief NRFX_GPIOTE130_ENABLED + * + * Boolean. Accepted values: 0 and 1. + */ +#ifndef NRFX_GPIOTE130_ENABLED +#define NRFX_GPIOTE130_ENABLED 0 +#endif + +/** + * @brief NRFX_GRTC_ENABLED + * + * Boolean. Accepted values: 0 and 1. + */ +#ifndef NRFX_GRTC_ENABLED +#define NRFX_GRTC_ENABLED 0 +#endif + +/** + * @brief NRFX_GRTC_CONFIG_NUM_OF_CC_CHANNELS + * + * Integer value. + */ +#ifndef NRFX_GRTC_CONFIG_NUM_OF_CC_CHANNELS +#define NRFX_GRTC_CONFIG_NUM_OF_CC_CHANNELS 2 +#endif + +/** + * @brief NRFX_GRTC_CONFIG_ALLOWED_CC_CHANNELS_MASK + */ +#ifndef NRFX_GRTC_CONFIG_ALLOWED_CC_CHANNELS_MASK +#define NRFX_GRTC_CONFIG_ALLOWED_CC_CHANNELS_MASK 0x000000c0 +#endif + +/** + * @brief NRFX_GRTC_DEFAULT_CONFIG_IRQ_PRIORITY + * + * Integer value. Minimum: 0. Maximum: 3. + */ +#ifndef NRFX_GRTC_DEFAULT_CONFIG_IRQ_PRIORITY +#define NRFX_GRTC_DEFAULT_CONFIG_IRQ_PRIORITY NRFX_DEFAULT_IRQ_PRIORITY +#endif + +/** + * @brief NRFX_GRTC_CONFIG_LOG_ENABLED + * + * Boolean. Accepted values: 0 and 1. + */ +#ifndef NRFX_GRTC_CONFIG_LOG_ENABLED +#define NRFX_GRTC_CONFIG_LOG_ENABLED 0 +#endif + +/** + * @brief NRFX_GRTC_CONFIG_LOG_LEVEL + * + * Integer value. + * Supported values: + * - Off = 0 + * - Error = 1 + * - Warning = 2 + * - Info = 3 + * - Debug = 4 + */ +#ifndef NRFX_GRTC_CONFIG_LOG_LEVEL +#define NRFX_GRTC_CONFIG_LOG_LEVEL 3 +#endif + +/** + * @brief NRFX_I2S_ENABLED + * + * Boolean. Accepted values: 0 and 1. + */ +#ifndef NRFX_I2S_ENABLED +#define NRFX_I2S_ENABLED 0 +#endif + +/** + * @brief NRFX_I2S_DEFAULT_CONFIG_IRQ_PRIORITY + * + * Integer value. Minimum: 0. Maximum: 3. + */ +#ifndef NRFX_I2S_DEFAULT_CONFIG_IRQ_PRIORITY +#define NRFX_I2S_DEFAULT_CONFIG_IRQ_PRIORITY NRFX_DEFAULT_IRQ_PRIORITY +#endif + +/** + * @brief NRFX_I2S_CONFIG_LOG_ENABLED + * + * Boolean. Accepted values: 0 and 1. + */ +#ifndef NRFX_I2S_CONFIG_LOG_ENABLED +#define NRFX_I2S_CONFIG_LOG_ENABLED 0 +#endif + +/** + * @brief NRFX_I2S_CONFIG_LOG_LEVEL + * + * Integer value. + * Supported values: + * - Off = 0 + * - Error = 1 + * - Warning = 2 + * - Info = 3 + * - Debug = 4 + */ +#ifndef NRFX_I2S_CONFIG_LOG_LEVEL +#define NRFX_I2S_CONFIG_LOG_LEVEL 3 +#endif + +/** + * @brief NRFX_I2S130_ENABLED + * + * Boolean. Accepted values: 0 and 1. + */ +#ifndef NRFX_I2S130_ENABLED +#define NRFX_I2S130_ENABLED 0 +#endif + +/** + * @brief NRFX_I2S131_ENABLED + * + * Boolean. Accepted values: 0 and 1. + */ +#ifndef NRFX_I2S131_ENABLED +#define NRFX_I2S131_ENABLED 0 +#endif + +/** + * @brief NRFX_IPCT_PUB_CONFIG_ALLOWED_CHANNELS_MASK + */ +#ifndef NRFX_IPCT_PUB_CONFIG_ALLOWED_CHANNELS_MASK +#define NRFX_IPCT_PUB_CONFIG_ALLOWED_CHANNELS_MASK 0 +#endif + +/** + * @brief NRFX_IPCT120_PUB_CONFIG_ALLOWED_CHANNELS_MASK + */ +#ifndef NRFX_IPCT120_PUB_CONFIG_ALLOWED_CHANNELS_MASK +#define NRFX_IPCT120_PUB_CONFIG_ALLOWED_CHANNELS_MASK 0 +#endif + +/** + * @brief NRFX_IPCT130_PUB_CONFIG_ALLOWED_CHANNELS_MASK + */ +#ifndef NRFX_IPCT130_PUB_CONFIG_ALLOWED_CHANNELS_MASK +#define NRFX_IPCT130_PUB_CONFIG_ALLOWED_CHANNELS_MASK 0x0000000c +#endif + +/** + * @brief NRFX_IPCT_SUB_CONFIG_ALLOWED_CHANNELS_MASK + */ +#ifndef NRFX_IPCT_SUB_CONFIG_ALLOWED_CHANNELS_MASK +#define NRFX_IPCT_SUB_CONFIG_ALLOWED_CHANNELS_MASK 0 +#endif + +/** + * @brief NRFX_IPCT120_SUB_CONFIG_ALLOWED_CHANNELS_MASK + */ +#ifndef NRFX_IPCT120_SUB_CONFIG_ALLOWED_CHANNELS_MASK +#define NRFX_IPCT120_SUB_CONFIG_ALLOWED_CHANNELS_MASK 0 +#endif + +/** + * @brief NRFX_IPCT130_SUB_CONFIG_ALLOWED_CHANNELS_MASK + */ +#ifndef NRFX_IPCT130_SUB_CONFIG_ALLOWED_CHANNELS_MASK +#define NRFX_IPCT130_SUB_CONFIG_ALLOWED_CHANNELS_MASK 0x00000003 +#endif + +/** + * @brief NRFX_LPCOMP_ENABLED + * + * Boolean. Accepted values: 0 and 1. + */ +#ifndef NRFX_LPCOMP_ENABLED +#define NRFX_LPCOMP_ENABLED 0 +#endif + +/** + * @brief NRFX_LPCOMP_DEFAULT_CONFIG_IRQ_PRIORITY + * + * Integer value. Minimum: 0. Maximum: 3. + */ +#ifndef NRFX_LPCOMP_DEFAULT_CONFIG_IRQ_PRIORITY +#define NRFX_LPCOMP_DEFAULT_CONFIG_IRQ_PRIORITY NRFX_DEFAULT_IRQ_PRIORITY +#endif + +/** + * @brief NRFX_LPCOMP_CONFIG_LOG_ENABLED + * + * Boolean. Accepted values: 0 and 1. + */ +#ifndef NRFX_LPCOMP_CONFIG_LOG_ENABLED +#define NRFX_LPCOMP_CONFIG_LOG_ENABLED 0 +#endif + +/** + * @brief NRFX_LPCOMP_CONFIG_LOG_LEVEL + * + * Integer value. + * Supported values: + * - Off = 0 + * - Error = 1 + * - Warning = 2 + * - Info = 3 + * - Debug = 4 + */ +#ifndef NRFX_LPCOMP_CONFIG_LOG_LEVEL +#define NRFX_LPCOMP_CONFIG_LOG_LEVEL 3 +#endif + +/** + * @brief NRFX_NFCT_ENABLED + * + * Boolean. Accepted values: 0 and 1. + */ +#ifndef NRFX_NFCT_ENABLED +#define NRFX_NFCT_ENABLED 0 +#endif + +/** + * @brief NRFX_NFCT_DEFAULT_CONFIG_IRQ_PRIORITY + * + * Integer value. Minimum: 0. Maximum: 3. + */ +#ifndef NRFX_NFCT_DEFAULT_CONFIG_IRQ_PRIORITY +#define NRFX_NFCT_DEFAULT_CONFIG_IRQ_PRIORITY NRFX_DEFAULT_IRQ_PRIORITY +#endif + +/** + * @brief NRFX_NFCT_CONFIG_TIMER_INSTANCE_ID - Timer instance used for + * workarounds in the driver. + * + * Integer value. Minimum: 0. Maximum: 5. + */ +#ifndef NRFX_NFCT_CONFIG_TIMER_INSTANCE_ID +#define NRFX_NFCT_CONFIG_TIMER_INSTANCE_ID 0 +#endif + +/** + * @brief NRFX_NFCT_CONFIG_LOG_ENABLED + * + * Boolean. Accepted values: 0 and 1. + */ +#ifndef NRFX_NFCT_CONFIG_LOG_ENABLED +#define NRFX_NFCT_CONFIG_LOG_ENABLED 0 +#endif + +/** + * @brief NRFX_NFCT_CONFIG_LOG_LEVEL + * + * Integer value. + * Supported values: + * - Off = 0 + * - Error = 1 + * - Warning = 2 + * - Info = 3 + * - Debug = 4 + */ +#ifndef NRFX_NFCT_CONFIG_LOG_LEVEL +#define NRFX_NFCT_CONFIG_LOG_LEVEL 3 +#endif + +/** + * @brief NRFX_PDM_ENABLED + * + * Boolean. Accepted values: 0 and 1. + */ +#ifndef NRFX_PDM_ENABLED +#define NRFX_PDM_ENABLED 0 +#endif + +/** + * @brief NRFX_PDM_DEFAULT_CONFIG_IRQ_PRIORITY + * + * Integer value. Minimum: 0. Maximum: 3. + */ +#ifndef NRFX_PDM_DEFAULT_CONFIG_IRQ_PRIORITY +#define NRFX_PDM_DEFAULT_CONFIG_IRQ_PRIORITY NRFX_DEFAULT_IRQ_PRIORITY +#endif + +/** + * @brief NRFX_PDM_CONFIG_LOG_ENABLED + * + * Boolean. Accepted values: 0 and 1. + */ +#ifndef NRFX_PDM_CONFIG_LOG_ENABLED +#define NRFX_PDM_CONFIG_LOG_ENABLED 0 +#endif + +/** + * @brief NRFX_PDM_CONFIG_LOG_LEVEL + * + * Integer value. + * Supported values: + * - Off = 0 + * - Error = 1 + * - Warning = 2 + * - Info = 3 + * - Debug = 4 + */ +#ifndef NRFX_PDM_CONFIG_LOG_LEVEL +#define NRFX_PDM_CONFIG_LOG_LEVEL 3 +#endif + +/** + * @brief NRFX_PRS_ENABLED + * + * Boolean. Accepted values: 0 and 1. + */ +#ifndef NRFX_PRS_ENABLED +#define NRFX_PRS_ENABLED 0 +#endif + +/** + * @brief NRFX_PRS_CONFIG_LOG_ENABLED + * + * Boolean. Accepted values: 0 and 1. + */ +#ifndef NRFX_PRS_CONFIG_LOG_ENABLED +#define NRFX_PRS_CONFIG_LOG_ENABLED 0 +#endif + +/** + * @brief NRFX_PRS_CONFIG_LOG_LEVEL + * + * Integer value. + * Supported values: + * - Off = 0 + * - Error = 1 + * - Warning = 2 + * - Info = 3 + * - Debug = 4 + */ +#ifndef NRFX_PRS_CONFIG_LOG_LEVEL +#define NRFX_PRS_CONFIG_LOG_LEVEL 3 +#endif + +/** + * @brief NRFX_PRS_BOX_0_ENABLED + * + * Boolean. Accepted values: 0 and 1. + */ +#ifndef NRFX_PRS_BOX_0_ENABLED +#define NRFX_PRS_BOX_0_ENABLED 0 +#endif + +/** + * @brief NRFX_PRS_BOX_1_ENABLED + * + * Boolean. Accepted values: 0 and 1. + */ +#ifndef NRFX_PRS_BOX_1_ENABLED +#define NRFX_PRS_BOX_1_ENABLED 0 +#endif + +/** + * @brief NRFX_PRS_BOX_2_ENABLED + * + * Boolean. Accepted values: 0 and 1. + */ +#ifndef NRFX_PRS_BOX_2_ENABLED +#define NRFX_PRS_BOX_2_ENABLED 0 +#endif + +/** + * @brief NRFX_PRS_BOX_3_ENABLED + * + * Boolean. Accepted values: 0 and 1. + */ +#ifndef NRFX_PRS_BOX_3_ENABLED +#define NRFX_PRS_BOX_3_ENABLED 0 +#endif + +/** + * @brief NRFX_PRS_BOX_4_ENABLED + * + * Boolean. Accepted values: 0 and 1. + */ +#ifndef NRFX_PRS_BOX_4_ENABLED +#define NRFX_PRS_BOX_4_ENABLED 0 +#endif + +/** + * @brief NRFX_PRS_BOX_5_ENABLED + * + * Boolean. Accepted values: 0 and 1. + */ +#ifndef NRFX_PRS_BOX_5_ENABLED +#define NRFX_PRS_BOX_5_ENABLED 0 +#endif + +/** + * @brief NRFX_PRS_BOX_6_ENABLED + * + * Boolean. Accepted values: 0 and 1. + */ +#ifndef NRFX_PRS_BOX_6_ENABLED +#define NRFX_PRS_BOX_6_ENABLED 0 +#endif + +/** + * @brief NRFX_PRS_BOX_7_ENABLED + * + * Boolean. Accepted values: 0 and 1. + */ +#ifndef NRFX_PRS_BOX_7_ENABLED +#define NRFX_PRS_BOX_7_ENABLED 0 +#endif + +/** + * @brief NRFX_PRS_BOX_8_ENABLED + * + * Boolean. Accepted values: 0 and 1. + */ +#ifndef NRFX_PRS_BOX_8_ENABLED +#define NRFX_PRS_BOX_8_ENABLED 0 +#endif + +/** + * @brief NRFX_PRS_BOX_9_ENABLED + * + * Boolean. Accepted values: 0 and 1. + */ +#ifndef NRFX_PRS_BOX_9_ENABLED +#define NRFX_PRS_BOX_9_ENABLED 0 +#endif + +/** + * @brief NRFX_PWM_ENABLED + * + * Boolean. Accepted values: 0 and 1. + */ +#ifndef NRFX_PWM_ENABLED +#define NRFX_PWM_ENABLED 0 +#endif + +/** + * @brief NRFX_PWM_DEFAULT_CONFIG_IRQ_PRIORITY + * + * Integer value. Minimum: 0. Maximum: 3. + */ +#ifndef NRFX_PWM_DEFAULT_CONFIG_IRQ_PRIORITY +#define NRFX_PWM_DEFAULT_CONFIG_IRQ_PRIORITY NRFX_DEFAULT_IRQ_PRIORITY +#endif + +/** + * @brief NRFX_PWM_CONFIG_LOG_ENABLED + * + * Boolean. Accepted values: 0 and 1. + */ +#ifndef NRFX_PWM_CONFIG_LOG_ENABLED +#define NRFX_PWM_CONFIG_LOG_ENABLED 0 +#endif + +/** + * @brief NRFX_PWM_CONFIG_LOG_LEVEL + * + * Integer value. + * Supported values: + * - Off = 0 + * - Error = 1 + * - Warning = 2 + * - Info = 3 + * - Debug = 4 + */ +#ifndef NRFX_PWM_CONFIG_LOG_LEVEL +#define NRFX_PWM_CONFIG_LOG_LEVEL 3 +#endif + +/** + * @brief NRFX_PWM120_ENABLED + * + * Boolean. Accepted values: 0 and 1. + */ +#ifndef NRFX_PWM120_ENABLED +#define NRFX_PWM120_ENABLED 0 +#endif + +/** + * @brief NRFX_PWM130_ENABLED + * + * Boolean. Accepted values: 0 and 1. + */ +#ifndef NRFX_PWM130_ENABLED +#define NRFX_PWM130_ENABLED 0 +#endif + +/** + * @brief NRFX_PWM131_ENABLED + * + * Boolean. Accepted values: 0 and 1. + */ +#ifndef NRFX_PWM131_ENABLED +#define NRFX_PWM131_ENABLED 0 +#endif + +/** + * @brief NRFX_PWM132_ENABLED + * + * Boolean. Accepted values: 0 and 1. + */ +#ifndef NRFX_PWM132_ENABLED +#define NRFX_PWM132_ENABLED 0 +#endif + +/** + * @brief NRFX_PWM133_ENABLED + * + * Boolean. Accepted values: 0 and 1. + */ +#ifndef NRFX_PWM133_ENABLED +#define NRFX_PWM133_ENABLED 0 +#endif + +/** + * @brief NRFX_QDEC_ENABLED + * + * Boolean. Accepted values: 0 and 1. + */ +#ifndef NRFX_QDEC_ENABLED +#define NRFX_QDEC_ENABLED 0 +#endif + +/** + * @brief NRFX_QDEC_DEFAULT_CONFIG_IRQ_PRIORITY + * + * Integer value. Minimum: 0. Maximum: 3. + */ +#ifndef NRFX_QDEC_DEFAULT_CONFIG_IRQ_PRIORITY +#define NRFX_QDEC_DEFAULT_CONFIG_IRQ_PRIORITY NRFX_DEFAULT_IRQ_PRIORITY +#endif + +/** + * @brief NRFX_QDEC_CONFIG_LOG_ENABLED + * + * Boolean. Accepted values: 0 and 1. + */ +#ifndef NRFX_QDEC_CONFIG_LOG_ENABLED +#define NRFX_QDEC_CONFIG_LOG_ENABLED 0 +#endif + +/** + * @brief NRFX_QDEC_CONFIG_LOG_LEVEL + * + * Integer value. + * Supported values: + * - Off = 0 + * - Error = 1 + * - Warning = 2 + * - Info = 3 + * - Debug = 4 + */ +#ifndef NRFX_QDEC_CONFIG_LOG_LEVEL +#define NRFX_QDEC_CONFIG_LOG_LEVEL 3 +#endif + +/** + * @brief NRFX_QDEC130_ENABLED + * + * Boolean. Accepted values: 0 and 1. + */ +#ifndef NRFX_QDEC130_ENABLED +#define NRFX_QDEC130_ENABLED 0 +#endif + +/** + * @brief NRFX_QDEC131_ENABLED + * + * Boolean. Accepted values: 0 and 1. + */ +#ifndef NRFX_QDEC131_ENABLED +#define NRFX_QDEC131_ENABLED 0 +#endif + +/** + * @brief NRFX_RTC_ENABLED + * + * Boolean. Accepted values: 0 and 1. + */ +#ifndef NRFX_RTC_ENABLED +#define NRFX_RTC_ENABLED 0 +#endif + +/** + * @brief NRFX_RTC_DEFAULT_CONFIG_IRQ_PRIORITY + * + * Integer value. Minimum: 0. Maximum: 3. + */ +#ifndef NRFX_RTC_DEFAULT_CONFIG_IRQ_PRIORITY +#define NRFX_RTC_DEFAULT_CONFIG_IRQ_PRIORITY NRFX_DEFAULT_IRQ_PRIORITY +#endif + +/** + * @brief NRFX_RTC_CONFIG_LOG_ENABLED + * + * Boolean. Accepted values: 0 and 1. + */ +#ifndef NRFX_RTC_CONFIG_LOG_ENABLED +#define NRFX_RTC_CONFIG_LOG_ENABLED 0 +#endif + +/** + * @brief NRFX_RTC_CONFIG_LOG_LEVEL + * + * Integer value. + * Supported values: + * - Off = 0 + * - Error = 1 + * - Warning = 2 + * - Info = 3 + * - Debug = 4 + */ +#ifndef NRFX_RTC_CONFIG_LOG_LEVEL +#define NRFX_RTC_CONFIG_LOG_LEVEL 3 +#endif + +/** + * @brief NRFX_RTC130_ENABLED + * + * Boolean. Accepted values: 0 and 1. + */ +#ifndef NRFX_RTC130_ENABLED +#define NRFX_RTC130_ENABLED 0 +#endif + +/** + * @brief NRFX_RTC131_ENABLED + * + * Boolean. Accepted values: 0 and 1. + */ +#ifndef NRFX_RTC131_ENABLED +#define NRFX_RTC131_ENABLED 0 +#endif + +/** + * @brief NRFX_SAADC_ENABLED + * + * Boolean. Accepted values: 0 and 1. + */ +#ifndef NRFX_SAADC_ENABLED +#define NRFX_SAADC_ENABLED 0 +#endif + +/** + * @brief NRFX_SAADC_DEFAULT_CONFIG_IRQ_PRIORITY + * + * Integer value. Minimum: 0. Maximum: 3. + */ +#ifndef NRFX_SAADC_DEFAULT_CONFIG_IRQ_PRIORITY +#define NRFX_SAADC_DEFAULT_CONFIG_IRQ_PRIORITY NRFX_DEFAULT_IRQ_PRIORITY +#endif + +/** + * @brief NRFX_SAADC_CONFIG_LOG_ENABLED + * + * Boolean. Accepted values: 0 and 1. + */ +#ifndef NRFX_SAADC_CONFIG_LOG_ENABLED +#define NRFX_SAADC_CONFIG_LOG_ENABLED 0 +#endif + +/** + * @brief NRFX_SAADC_CONFIG_LOG_LEVEL + * + * Integer value. + * Supported values: + * - Off = 0 + * - Error = 1 + * - Warning = 2 + * - Info = 3 + * - Debug = 4 + */ +#ifndef NRFX_SAADC_CONFIG_LOG_LEVEL +#define NRFX_SAADC_CONFIG_LOG_LEVEL 3 +#endif + +/** + * @brief NRFX_SPIM_ENABLED + * + * Boolean. Accepted values: 0 and 1. + */ +#ifndef NRFX_SPIM_ENABLED +#define NRFX_SPIM_ENABLED 0 +#endif + +/** + * @brief NRFX_SPIM_DEFAULT_CONFIG_IRQ_PRIORITY + * + * Integer value. Minimum: 0. Maximum: 3. + */ +#ifndef NRFX_SPIM_DEFAULT_CONFIG_IRQ_PRIORITY +#define NRFX_SPIM_DEFAULT_CONFIG_IRQ_PRIORITY NRFX_DEFAULT_IRQ_PRIORITY +#endif + +/** + * @brief NRFX_SPIM_CONFIG_LOG_ENABLED + * + * Boolean. Accepted values: 0 and 1. + */ +#ifndef NRFX_SPIM_CONFIG_LOG_ENABLED +#define NRFX_SPIM_CONFIG_LOG_ENABLED 0 +#endif + +/** + * @brief NRFX_SPIM_CONFIG_LOG_LEVEL + * + * Integer value. + * Supported values: + * - Off = 0 + * - Error = 1 + * - Warning = 2 + * - Info = 3 + * - Debug = 4 + */ +#ifndef NRFX_SPIM_CONFIG_LOG_LEVEL +#define NRFX_SPIM_CONFIG_LOG_LEVEL 3 +#endif + +/** + * @brief NRFX_SPIM120_ENABLED + * + * Boolean. Accepted values: 0 and 1. + */ +#ifndef NRFX_SPIM120_ENABLED +#define NRFX_SPIM120_ENABLED 0 +#endif + +/** + * @brief NRFX_SPIM121_ENABLED + * + * Boolean. Accepted values: 0 and 1. + */ +#ifndef NRFX_SPIM121_ENABLED +#define NRFX_SPIM121_ENABLED 0 +#endif + +/** + * @brief NRFX_SPIM130_ENABLED + * + * Boolean. Accepted values: 0 and 1. + */ +#ifndef NRFX_SPIM130_ENABLED +#define NRFX_SPIM130_ENABLED 0 +#endif + +/** + * @brief NRFX_SPIM131_ENABLED + * + * Boolean. Accepted values: 0 and 1. + */ +#ifndef NRFX_SPIM131_ENABLED +#define NRFX_SPIM131_ENABLED 0 +#endif + +/** + * @brief NRFX_SPIM132_ENABLED + * + * Boolean. Accepted values: 0 and 1. + */ +#ifndef NRFX_SPIM132_ENABLED +#define NRFX_SPIM132_ENABLED 0 +#endif + +/** + * @brief NRFX_SPIM133_ENABLED + * + * Boolean. Accepted values: 0 and 1. + */ +#ifndef NRFX_SPIM133_ENABLED +#define NRFX_SPIM133_ENABLED 0 +#endif + +/** + * @brief NRFX_SPIM134_ENABLED + * + * Boolean. Accepted values: 0 and 1. + */ +#ifndef NRFX_SPIM134_ENABLED +#define NRFX_SPIM134_ENABLED 0 +#endif + +/** + * @brief NRFX_SPIM135_ENABLED + * + * Boolean. Accepted values: 0 and 1. + */ +#ifndef NRFX_SPIM135_ENABLED +#define NRFX_SPIM135_ENABLED 0 +#endif + +/** + * @brief NRFX_SPIM136_ENABLED + * + * Boolean. Accepted values: 0 and 1. + */ +#ifndef NRFX_SPIM136_ENABLED +#define NRFX_SPIM136_ENABLED 0 +#endif + +/** + * @brief NRFX_SPIM137_ENABLED + * + * Boolean. Accepted values: 0 and 1. + */ +#ifndef NRFX_SPIM137_ENABLED +#define NRFX_SPIM137_ENABLED 0 +#endif + +/** + * @brief NRFX_SPIS_ENABLED + * + * Boolean. Accepted values: 0 and 1. + */ +#ifndef NRFX_SPIS_ENABLED +#define NRFX_SPIS_ENABLED 0 +#endif + +/** + * @brief NRFX_SPIS_DEFAULT_CONFIG_IRQ_PRIORITY + * + * Integer value. Minimum: 0. Maximum: 3. + */ +#ifndef NRFX_SPIS_DEFAULT_CONFIG_IRQ_PRIORITY +#define NRFX_SPIS_DEFAULT_CONFIG_IRQ_PRIORITY NRFX_DEFAULT_IRQ_PRIORITY +#endif + +/** + * @brief NRFX_SPIS_CONFIG_LOG_ENABLED + * + * Boolean. Accepted values: 0 and 1. + */ +#ifndef NRFX_SPIS_CONFIG_LOG_ENABLED +#define NRFX_SPIS_CONFIG_LOG_ENABLED 0 +#endif + +/** + * @brief NRFX_SPIS_CONFIG_LOG_LEVEL + * + * Integer value. + * Supported values: + * - Off = 0 + * - Error = 1 + * - Warning = 2 + * - Info = 3 + * - Debug = 4 + */ +#ifndef NRFX_SPIS_CONFIG_LOG_LEVEL +#define NRFX_SPIS_CONFIG_LOG_LEVEL 3 +#endif + +/** + * @brief NRFX_SPIS120_ENABLED + * + * Boolean. Accepted values: 0 and 1. + */ +#ifndef NRFX_SPIS120_ENABLED +#define NRFX_SPIS120_ENABLED 0 +#endif + +/** + * @brief NRFX_SPIS130_ENABLED + * + * Boolean. Accepted values: 0 and 1. + */ +#ifndef NRFX_SPIS130_ENABLED +#define NRFX_SPIS130_ENABLED 0 +#endif + +/** + * @brief NRFX_SPIS131_ENABLED + * + * Boolean. Accepted values: 0 and 1. + */ +#ifndef NRFX_SPIS131_ENABLED +#define NRFX_SPIS131_ENABLED 0 +#endif + +/** + * @brief NRFX_SPIS132_ENABLED + * + * Boolean. Accepted values: 0 and 1. + */ +#ifndef NRFX_SPIS132_ENABLED +#define NRFX_SPIS132_ENABLED 0 +#endif + +/** + * @brief NRFX_SPIS133_ENABLED + * + * Boolean. Accepted values: 0 and 1. + */ +#ifndef NRFX_SPIS133_ENABLED +#define NRFX_SPIS133_ENABLED 0 +#endif + +/** + * @brief NRFX_SPIS134_ENABLED + * + * Boolean. Accepted values: 0 and 1. + */ +#ifndef NRFX_SPIS134_ENABLED +#define NRFX_SPIS134_ENABLED 0 +#endif + +/** + * @brief NRFX_SPIS135_ENABLED + * + * Boolean. Accepted values: 0 and 1. + */ +#ifndef NRFX_SPIS135_ENABLED +#define NRFX_SPIS135_ENABLED 0 +#endif + +/** + * @brief NRFX_SPIS136_ENABLED + * + * Boolean. Accepted values: 0 and 1. + */ +#ifndef NRFX_SPIS136_ENABLED +#define NRFX_SPIS136_ENABLED 0 +#endif + +/** + * @brief NRFX_SPIS137_ENABLED + * + * Boolean. Accepted values: 0 and 1. + */ +#ifndef NRFX_SPIS137_ENABLED +#define NRFX_SPIS137_ENABLED 0 +#endif + +/** + * @brief NRFX_TEMP_ENABLED + * + * Boolean. Accepted values: 0 and 1. + */ +#ifndef NRFX_TEMP_ENABLED +#define NRFX_TEMP_ENABLED 0 +#endif + +/** + * @brief NRFX_TEMP_DEFAULT_CONFIG_IRQ_PRIORITY + * + * Integer value. Minimum: 0. Maximum: 3. + */ +#ifndef NRFX_TEMP_DEFAULT_CONFIG_IRQ_PRIORITY +#define NRFX_TEMP_DEFAULT_CONFIG_IRQ_PRIORITY NRFX_DEFAULT_IRQ_PRIORITY +#endif + +/** + * @brief NRFX_TEMP_CONFIG_LOG_ENABLED + * + * Boolean. Accepted values: 0 and 1. + */ +#ifndef NRFX_TEMP_CONFIG_LOG_ENABLED +#define NRFX_TEMP_CONFIG_LOG_ENABLED 0 +#endif + +/** + * @brief NRFX_TEMP_CONFIG_LOG_LEVEL + * + * Integer value. + * Supported values: + * - Off = 0 + * - Error = 1 + * - Warning = 2 + * - Info = 3 + * - Debug = 4 + */ +#ifndef NRFX_TEMP_CONFIG_LOG_LEVEL +#define NRFX_TEMP_CONFIG_LOG_LEVEL 3 +#endif + +/** + * @brief NRFX_TIMER_ENABLED + * + * Boolean. Accepted values: 0 and 1. + */ +#ifndef NRFX_TIMER_ENABLED +#define NRFX_TIMER_ENABLED 0 +#endif + +/** + * @brief NRFX_TIMER_DEFAULT_CONFIG_IRQ_PRIORITY + * + * Integer value. Minimum: 0. Maximum: 3. + */ +#ifndef NRFX_TIMER_DEFAULT_CONFIG_IRQ_PRIORITY +#define NRFX_TIMER_DEFAULT_CONFIG_IRQ_PRIORITY NRFX_DEFAULT_IRQ_PRIORITY +#endif + +/** + * @brief NRFX_TIMER_CONFIG_LOG_ENABLED + * + * Boolean. Accepted values: 0 and 1. + */ +#ifndef NRFX_TIMER_CONFIG_LOG_ENABLED +#define NRFX_TIMER_CONFIG_LOG_ENABLED 0 +#endif + +/** + * @brief NRFX_TIMER_CONFIG_LOG_LEVEL + * + * Integer value. + * Supported values: + * - Off = 0 + * - Error = 1 + * - Warning = 2 + * - Info = 3 + * - Debug = 4 + */ +#ifndef NRFX_TIMER_CONFIG_LOG_LEVEL +#define NRFX_TIMER_CONFIG_LOG_LEVEL 3 +#endif + +/** + * @brief NRFX_TIMER120_ENABLED + * + * Boolean. Accepted values: 0 and 1. + */ +#ifndef NRFX_TIMER120_ENABLED +#define NRFX_TIMER120_ENABLED 0 +#endif + +/** + * @brief NRFX_TIMER121_ENABLED + * + * Boolean. Accepted values: 0 and 1. + */ +#ifndef NRFX_TIMER121_ENABLED +#define NRFX_TIMER121_ENABLED 0 +#endif + +/** + * @brief NRFX_TIMER130_ENABLED + * + * Boolean. Accepted values: 0 and 1. + */ +#ifndef NRFX_TIMER130_ENABLED +#define NRFX_TIMER130_ENABLED 0 +#endif + +/** + * @brief NRFX_TIMER131_ENABLED + * + * Boolean. Accepted values: 0 and 1. + */ +#ifndef NRFX_TIMER131_ENABLED +#define NRFX_TIMER131_ENABLED 0 +#endif + +/** + * @brief NRFX_TIMER132_ENABLED + * + * Boolean. Accepted values: 0 and 1. + */ +#ifndef NRFX_TIMER132_ENABLED +#define NRFX_TIMER132_ENABLED 0 +#endif + +/** + * @brief NRFX_TIMER133_ENABLED + * + * Boolean. Accepted values: 0 and 1. + */ +#ifndef NRFX_TIMER133_ENABLED +#define NRFX_TIMER133_ENABLED 0 +#endif + +/** + * @brief NRFX_TIMER134_ENABLED + * + * Boolean. Accepted values: 0 and 1. + */ +#ifndef NRFX_TIMER134_ENABLED +#define NRFX_TIMER134_ENABLED 0 +#endif + +/** + * @brief NRFX_TIMER135_ENABLED + * + * Boolean. Accepted values: 0 and 1. + */ +#ifndef NRFX_TIMER135_ENABLED +#define NRFX_TIMER135_ENABLED 0 +#endif + +/** + * @brief NRFX_TIMER136_ENABLED + * + * Boolean. Accepted values: 0 and 1. + */ +#ifndef NRFX_TIMER136_ENABLED +#define NRFX_TIMER136_ENABLED 0 +#endif + +/** + * @brief NRFX_TIMER137_ENABLED + * + * Boolean. Accepted values: 0 and 1. + */ +#ifndef NRFX_TIMER137_ENABLED +#define NRFX_TIMER137_ENABLED 0 +#endif + +/** + * @brief NRFX_TWIM_ENABLED + * + * Boolean. Accepted values: 0 and 1. + */ +#ifndef NRFX_TWIM_ENABLED +#define NRFX_TWIM_ENABLED 0 +#endif + +/** + * @brief NRFX_TWIM_DEFAULT_CONFIG_IRQ_PRIORITY + * + * Integer value. Minimum: 0. Maximum: 3. + */ +#ifndef NRFX_TWIM_DEFAULT_CONFIG_IRQ_PRIORITY +#define NRFX_TWIM_DEFAULT_CONFIG_IRQ_PRIORITY NRFX_DEFAULT_IRQ_PRIORITY +#endif + +/** + * @brief NRFX_TWIM_CONFIG_LOG_ENABLED + * + * Boolean. Accepted values: 0 and 1. + */ +#ifndef NRFX_TWIM_CONFIG_LOG_ENABLED +#define NRFX_TWIM_CONFIG_LOG_ENABLED 0 +#endif + +/** + * @brief NRFX_TWIM_CONFIG_LOG_LEVEL + * + * Integer value. + * Supported values: + * - Off = 0 + * - Error = 1 + * - Warning = 2 + * - Info = 3 + * - Debug = 4 + */ +#ifndef NRFX_TWIM_CONFIG_LOG_LEVEL +#define NRFX_TWIM_CONFIG_LOG_LEVEL 3 +#endif + +/** + * @brief NRFX_TWIM130_ENABLED + * + * Boolean. Accepted values: 0 and 1. + */ +#ifndef NRFX_TWIM130_ENABLED +#define NRFX_TWIM130_ENABLED 0 +#endif + +/** + * @brief NRFX_TWIM131_ENABLED + * + * Boolean. Accepted values: 0 and 1. + */ +#ifndef NRFX_TWIM131_ENABLED +#define NRFX_TWIM131_ENABLED 0 +#endif + +/** + * @brief NRFX_TWIM132_ENABLED + * + * Boolean. Accepted values: 0 and 1. + */ +#ifndef NRFX_TWIM132_ENABLED +#define NRFX_TWIM132_ENABLED 0 +#endif + +/** + * @brief NRFX_TWIM133_ENABLED + * + * Boolean. Accepted values: 0 and 1. + */ +#ifndef NRFX_TWIM133_ENABLED +#define NRFX_TWIM133_ENABLED 0 +#endif + +/** + * @brief NRFX_TWIM134_ENABLED + * + * Boolean. Accepted values: 0 and 1. + */ +#ifndef NRFX_TWIM134_ENABLED +#define NRFX_TWIM134_ENABLED 0 +#endif + +/** + * @brief NRFX_TWIM135_ENABLED + * + * Boolean. Accepted values: 0 and 1. + */ +#ifndef NRFX_TWIM135_ENABLED +#define NRFX_TWIM135_ENABLED 0 +#endif + +/** + * @brief NRFX_TWIM136_ENABLED + * + * Boolean. Accepted values: 0 and 1. + */ +#ifndef NRFX_TWIM136_ENABLED +#define NRFX_TWIM136_ENABLED 0 +#endif + +/** + * @brief NRFX_TWIM137_ENABLED + * + * Boolean. Accepted values: 0 and 1. + */ +#ifndef NRFX_TWIM137_ENABLED +#define NRFX_TWIM137_ENABLED 0 +#endif + +/** + * @brief NRFX_TWIS_ENABLED + * + * Boolean. Accepted values: 0 and 1. + */ +#ifndef NRFX_TWIS_ENABLED +#define NRFX_TWIS_ENABLED 0 +#endif + +/** + * @brief NRFX_TWIS_DEFAULT_CONFIG_IRQ_PRIORITY + * + * Integer value. Minimum: 0. Maximum: 3. + */ +#ifndef NRFX_TWIS_DEFAULT_CONFIG_IRQ_PRIORITY +#define NRFX_TWIS_DEFAULT_CONFIG_IRQ_PRIORITY NRFX_DEFAULT_IRQ_PRIORITY +#endif + +/** + * @brief NRFX_TWIS_CONFIG_LOG_ENABLED + * + * Boolean. Accepted values: 0 and 1. + */ +#ifndef NRFX_TWIS_CONFIG_LOG_ENABLED +#define NRFX_TWIS_CONFIG_LOG_ENABLED 0 +#endif + +/** + * @brief NRFX_TWIS_ASSUME_INIT_AFTER_RESET_ONLY - Assume that any instance + * would be initialized only once. + * + * Boolean. Accepted values: 0 and 1. + */ +#ifndef NRFX_TWIS_ASSUME_INIT_AFTER_RESET_ONLY +#define NRFX_TWIS_ASSUME_INIT_AFTER_RESET_ONLY 0 +#endif + +/** + * @brief NRFX_TWIS_NO_SYNC_MODE - Remove support for synchronous mode. + * + * Boolean. Accepted values: 0 and 1. + */ +#ifndef NRFX_TWIS_NO_SYNC_MODE +#define NRFX_TWIS_NO_SYNC_MODE 0 +#endif + +/** + * @brief NRFX_TWIS_CONFIG_LOG_LEVEL + * + * Integer value. + * Supported values: + * - Off = 0 + * - Error = 1 + * - Warning = 2 + * - Info = 3 + * - Debug = 4 + */ +#ifndef NRFX_TWIS_CONFIG_LOG_LEVEL +#define NRFX_TWIS_CONFIG_LOG_LEVEL 3 +#endif + +/** + * @brief NRFX_TWIS130_ENABLED + * + * Boolean. Accepted values: 0 and 1. + */ +#ifndef NRFX_TWIS130_ENABLED +#define NRFX_TWIS130_ENABLED 0 +#endif + +/** + * @brief NRFX_TWIS131_ENABLED + * + * Boolean. Accepted values: 0 and 1. + */ +#ifndef NRFX_TWIS131_ENABLED +#define NRFX_TWIS131_ENABLED 0 +#endif + +/** + * @brief NRFX_TWIS132_ENABLED + * + * Boolean. Accepted values: 0 and 1. + */ +#ifndef NRFX_TWIS132_ENABLED +#define NRFX_TWIS132_ENABLED 0 +#endif + +/** + * @brief NRFX_TWIS133_ENABLED + * + * Boolean. Accepted values: 0 and 1. + */ +#ifndef NRFX_TWIS133_ENABLED +#define NRFX_TWIS133_ENABLED 0 +#endif + +/** + * @brief NRFX_TWIS134_ENABLED + * + * Boolean. Accepted values: 0 and 1. + */ +#ifndef NRFX_TWIS134_ENABLED +#define NRFX_TWIS134_ENABLED 0 +#endif + +/** + * @brief NRFX_TWIS135_ENABLED + * + * Boolean. Accepted values: 0 and 1. + */ +#ifndef NRFX_TWIS135_ENABLED +#define NRFX_TWIS135_ENABLED 0 +#endif + +/** + * @brief NRFX_TWIS136_ENABLED + * + * Boolean. Accepted values: 0 and 1. + */ +#ifndef NRFX_TWIS136_ENABLED +#define NRFX_TWIS136_ENABLED 0 +#endif + +/** + * @brief NRFX_TWIS137_ENABLED + * + * Boolean. Accepted values: 0 and 1. + */ +#ifndef NRFX_TWIS137_ENABLED +#define NRFX_TWIS137_ENABLED 0 +#endif + +/** + * @brief NRFX_UARTE_ENABLED + * + * Boolean. Accepted values: 0 and 1. + */ +#ifndef NRFX_UARTE_ENABLED +#define NRFX_UARTE_ENABLED 0 +#endif + +/** + * @brief NRFX_UARTE_CONFIG_SKIP_GPIO_CONFIG - If enabled, support for + * configuring GPIO pins is removed from the driver + * + * Boolean. Accepted values: 0 and 1. + */ +#ifndef NRFX_UARTE_CONFIG_SKIP_GPIO_CONFIG +#define NRFX_UARTE_CONFIG_SKIP_GPIO_CONFIG 0 +#endif + +/** + * @brief NRFX_UARTE_CONFIG_SKIP_PSEL_CONFIG - If enabled, support for + * configuring PSEL registers is removed from the driver + * + * Boolean. Accepted values: 0 and 1. + */ +#ifndef NRFX_UARTE_CONFIG_SKIP_PSEL_CONFIG +#define NRFX_UARTE_CONFIG_SKIP_PSEL_CONFIG 0 +#endif + +/** + * @brief NRFX_UARTE_CONFIG_TX_LINK - If enabled, driver supports linking of TX + * transfers. + * + * Boolean. Accepted values: 0 and 1. + */ +#ifndef NRFX_UARTE_CONFIG_TX_LINK +#define NRFX_UARTE_CONFIG_TX_LINK 1 +#endif + +/** + * @brief NRFX_UARTE_CONFIG_RX_CACHE_ENABLED + * + * Boolean. Accepted values: 0 and 1. + */ +#ifndef NRFX_UARTE_CONFIG_RX_CACHE_ENABLED +#define NRFX_UARTE_CONFIG_RX_CACHE_ENABLED 1 +#endif + +/** + * @brief NRFX_UARTE_DEFAULT_CONFIG_IRQ_PRIORITY + * + * Integer value. Minimum: 0. Maximum: 3. + */ +#ifndef NRFX_UARTE_DEFAULT_CONFIG_IRQ_PRIORITY +#define NRFX_UARTE_DEFAULT_CONFIG_IRQ_PRIORITY NRFX_DEFAULT_IRQ_PRIORITY +#endif + +/** + * @brief NRFX_UARTE_CONFIG_LOG_ENABLED + * + * Boolean. Accepted values: 0 and 1. + */ +#ifndef NRFX_UARTE_CONFIG_LOG_ENABLED +#define NRFX_UARTE_CONFIG_LOG_ENABLED 0 +#endif + +/** + * @brief NRFX_UARTE_CONFIG_LOG_LEVEL + * + * Integer value. + * Supported values: + * - Off = 0 + * - Error = 1 + * - Warning = 2 + * - Info = 3 + * - Debug = 4 + */ +#ifndef NRFX_UARTE_CONFIG_LOG_LEVEL +#define NRFX_UARTE_CONFIG_LOG_LEVEL 3 +#endif + +/** + * @brief NRFX_UARTE120_ENABLED + * + * Boolean. Accepted values: 0 and 1. + */ +#ifndef NRFX_UARTE120_ENABLED +#define NRFX_UARTE120_ENABLED 0 +#endif + +/** + * @brief NRFX_UARTE130_ENABLED + * + * Boolean. Accepted values: 0 and 1. + */ +#ifndef NRFX_UARTE130_ENABLED +#define NRFX_UARTE130_ENABLED 0 +#endif + +/** + * @brief NRFX_UARTE131_ENABLED + * + * Boolean. Accepted values: 0 and 1. + */ +#ifndef NRFX_UARTE131_ENABLED +#define NRFX_UARTE131_ENABLED 0 +#endif + +/** + * @brief NRFX_UARTE132_ENABLED + * + * Boolean. Accepted values: 0 and 1. + */ +#ifndef NRFX_UARTE132_ENABLED +#define NRFX_UARTE132_ENABLED 0 +#endif + +/** + * @brief NRFX_UARTE133_ENABLED + * + * Boolean. Accepted values: 0 and 1. + */ +#ifndef NRFX_UARTE133_ENABLED +#define NRFX_UARTE133_ENABLED 0 +#endif + +/** + * @brief NRFX_UARTE134_ENABLED + * + * Boolean. Accepted values: 0 and 1. + */ +#ifndef NRFX_UARTE134_ENABLED +#define NRFX_UARTE134_ENABLED 0 +#endif + +/** + * @brief NRFX_UARTE135_ENABLED + * + * Boolean. Accepted values: 0 and 1. + */ +#ifndef NRFX_UARTE135_ENABLED +#define NRFX_UARTE135_ENABLED 0 +#endif + +/** + * @brief NRFX_UARTE136_ENABLED + * + * Boolean. Accepted values: 0 and 1. + */ +#ifndef NRFX_UARTE136_ENABLED +#define NRFX_UARTE136_ENABLED 0 +#endif + +/** + * @brief NRFX_UARTE137_ENABLED + * + * Boolean. Accepted values: 0 and 1. + */ +#ifndef NRFX_UARTE137_ENABLED +#define NRFX_UARTE137_ENABLED 0 +#endif + +/** + * @brief NRFX_VEVIF_ENABLED + * + * Boolean. Accepted values: 0 and 1. + */ +#ifndef NRFX_VEVIF_ENABLED +#define NRFX_VEVIF_ENABLED 0 +#endif + +/** + * @brief NRFX_WDT_ENABLED + * + * Boolean. Accepted values: 0 and 1. + */ +#ifndef NRFX_WDT_ENABLED +#define NRFX_WDT_ENABLED 0 +#endif + +/** + * @brief NRFX_WDT_DEFAULT_CONFIG_IRQ_PRIORITY + * + * Integer value. Minimum: 0. Maximum: 3. + */ +#ifndef NRFX_WDT_DEFAULT_CONFIG_IRQ_PRIORITY +#define NRFX_WDT_DEFAULT_CONFIG_IRQ_PRIORITY NRFX_DEFAULT_IRQ_PRIORITY +#endif + +/** + * @brief NRFX_WDT_CONFIG_NO_IRQ - Remove WDT IRQ handling from WDT driver + * + * Boolean. Accepted values: 0 and 1. + */ +#ifndef NRFX_WDT_CONFIG_NO_IRQ +#define NRFX_WDT_CONFIG_NO_IRQ 0 +#endif + +/** + * @brief NRFX_WDT_CONFIG_LOG_ENABLED + * + * Boolean. Accepted values: 0 and 1. + */ +#ifndef NRFX_WDT_CONFIG_LOG_ENABLED +#define NRFX_WDT_CONFIG_LOG_ENABLED 0 +#endif + +/** + * @brief NRFX_WDT_CONFIG_LOG_LEVEL + * + * Integer value. + * Supported values: + * - Off = 0 + * - Error = 1 + * - Warning = 2 + * - Info = 3 + * - Debug = 4 + */ +#ifndef NRFX_WDT_CONFIG_LOG_LEVEL +#define NRFX_WDT_CONFIG_LOG_LEVEL 3 +#endif + +/** + * @brief NRFX_WDT131_ENABLED + * + * Boolean. Accepted values: 0 and 1. + */ +#ifndef NRFX_WDT131_ENABLED +#define NRFX_WDT131_ENABLED 0 +#endif + +/** + * @brief NRFX_WDT132_ENABLED + * + * Boolean. Accepted values: 0 and 1. + */ +#ifndef NRFX_WDT132_ENABLED +#define NRFX_WDT132_ENABLED 0 +#endif + +#endif /* NRFX_CONFIG_NRF54H20_ENGA_PPR_H__ */ diff --git a/modules/hal_nordic/nrfx/nrfx_glue.h b/modules/hal_nordic/nrfx/nrfx_glue.h index 851cb8a9614..0edda440112 100644 --- a/modules/hal_nordic/nrfx/nrfx_glue.h +++ b/modules/hal_nordic/nrfx/nrfx_glue.h @@ -42,6 +42,11 @@ extern "C" { #define NRFX_ASSERT(expression) __ASSERT_NO_MSG(expression) #endif +#if defined(CONFIG_RISCV) +/* included here due to dependency on NRFX_ASSERT definition */ +#include +#endif + /** * @brief Macro for placing a compile time assertion. * @@ -91,14 +96,22 @@ extern "C" { * * @param irq_number IRQ number. */ -#define NRFX_IRQ_PENDING_SET(irq_number) NVIC_SetPendingIRQ(irq_number) +#if defined(CONFIG_RISCV) +#define NRFX_IRQ_PENDING_SET(irq_number) nrf_vpr_clic_int_pending_set(NRF_VPRCLIC, irq_number) +#else +#define NRFX_IRQ_PENDING_SET(irq_number) NVIC_SetPendingIRQ(irq_number) +#endif /** * @brief Macro for clearing the pending status of a specific IRQ. * * @param irq_number IRQ number. */ -#define NRFX_IRQ_PENDING_CLEAR(irq_number) NVIC_ClearPendingIRQ(irq_number) +#if defined(CONFIG_RISCV) +#define NRFX_IRQ_PENDING_CLEAR(irq_number) nrf_vpr_clic_int_pending_clear(NRF_VPRCLIC, irq_number) +#else +#define NRFX_IRQ_PENDING_CLEAR(irq_number) NVIC_ClearPendingIRQ(irq_number) +#endif /** * @brief Macro for checking the pending status of a specific IRQ. @@ -106,7 +119,11 @@ extern "C" { * @retval true If the IRQ is pending. * @retval false Otherwise. */ -#define NRFX_IRQ_IS_PENDING(irq_number) (NVIC_GetPendingIRQ(irq_number) == 1) +#if defined(CONFIG_RISCV) +#define NRFX_IRQ_IS_PENDING(irq_number) nrf_vpr_clic_int_pending_check(NRF_VPRCLIC, irq_number) +#else +#define NRFX_IRQ_IS_PENDING(irq_number) (NVIC_GetPendingIRQ(irq_number) == 1) +#endif /** @brief Macro for entering into a critical section. */ #define NRFX_CRITICAL_SECTION_ENTER() { unsigned int irq_lock_key = irq_lock(); From 018cf08d8dbcfb3d2da2d2f26e067e3a8e92ba0e Mon Sep 17 00:00:00 2001 From: Gerard Marull-Paretas Date: Thu, 1 Feb 2024 10:25:18 +0100 Subject: [PATCH 3415/3723] scripts: kconfig: functions: add dt_chosen_partition_addr_int|hex dt_chosen_partition_addr_int|hex allow obtaining the absolute address of a partition, which is the result of the grandparent node address plus the partition node address. Signed-off-by: Gerard Marull-Paretas --- scripts/kconfig/kconfigfunctions.py | 44 +++++++++++++++++++++++++++++ 1 file changed, 44 insertions(+) diff --git a/scripts/kconfig/kconfigfunctions.py b/scripts/kconfig/kconfigfunctions.py index 4a74c6ff88c..71200b7f955 100644 --- a/scripts/kconfig/kconfigfunctions.py +++ b/scripts/kconfig/kconfigfunctions.py @@ -336,6 +336,48 @@ def dt_chosen_reg(kconf, name, chosen, index=0, unit=None): return hex(_dt_chosen_reg_addr(kconf, chosen, index, unit)) +def _dt_chosen_partition_addr(kconf, chosen, index=0, unit=None): + """ + This function takes a 'chosen' property and treats that property as a path + to an EDT node. If it finds an EDT node, it will look to see if that + node has a register, and if that node has a grandparent that has a register + at the given 'index'. The addition of both addresses will be returned, if + not, we return 0. + + The function will divide the value based on 'unit': + None No division + 'k' or 'K' divide by 1024 (1 << 10) + 'm' or 'M' divide by 1,048,576 (1 << 20) + 'g' or 'G' divide by 1,073,741,824 (1 << 30) + 'kb' or 'Kb' divide by 8192 (1 << 13) + 'mb' or 'Mb' divide by 8,388,608 (1 << 23) + 'gb' or 'Gb' divide by 8,589,934,592 (1 << 33) + """ + if doc_mode or edt is None: + return 0 + + node = edt.chosen_node(chosen) + if not node: + return 0 + + p_node = node.parent + if not p_node: + return 0 + + return _node_reg_addr(p_node.parent, index, unit) + _node_reg_addr(node, 0, unit) + + +def dt_chosen_partition_addr(kconf, name, chosen, index=0, unit=None): + """ + This function just routes to the proper function and converts + the result to either a string int or string hex value. + """ + if name == "dt_chosen_partition_addr_int": + return str(_dt_chosen_partition_addr(kconf, chosen, index, unit)) + if name == "dt_chosen_partition_addr_hex": + return hex(_dt_chosen_partition_addr(kconf, chosen, index, unit)) + + def _dt_node_reg_addr(kconf, path, index=0, unit=None): """ This function takes a 'path' and looks for an EDT node at that path. If it @@ -863,5 +905,7 @@ def shields_list_contains(kconf, _, shield): "dt_node_parent": (dt_node_parent, 1, 1), "dt_nodelabel_array_prop_has_val": (dt_nodelabel_array_prop_has_val, 3, 3), "dt_gpio_hogs_enabled": (dt_gpio_hogs_enabled, 0, 0), + "dt_chosen_partition_addr_int": (dt_chosen_partition_addr, 1, 3), + "dt_chosen_partition_addr_hex": (dt_chosen_partition_addr, 1, 3), "shields_list_contains": (shields_list_contains, 1, 1), } From d7dc942382a2c05539c14f8df32d5756fd88a9a2 Mon Sep 17 00:00:00 2001 From: Gerard Marull-Paretas Date: Thu, 1 Feb 2024 10:40:53 +0100 Subject: [PATCH 3416/3723] soc: common: nordic_nrf: move pinctrl_soc.h to a common dir Because both, RISC-V and ARM cores share the same pinctrl driver. The top level common folder will disappear with the introduction of HWMv2, where multi-arch SoCs will be well supported. Signed-off-by: Gerard Marull-Paretas --- boards/posix/nrf_bsim/soc/pinctrl_soc.h | 2 +- soc/CMakeLists.txt | 2 ++ soc/common/CMakeLists.txt | 4 ++++ soc/common/nordic_nrf/CMakeLists.txt | 4 ++++ .../nordic_nrf/common => common/nordic_nrf}/pinctrl_soc.h | 0 5 files changed, 11 insertions(+), 1 deletion(-) create mode 100644 soc/common/CMakeLists.txt create mode 100644 soc/common/nordic_nrf/CMakeLists.txt rename soc/{arm/nordic_nrf/common => common/nordic_nrf}/pinctrl_soc.h (100%) diff --git a/boards/posix/nrf_bsim/soc/pinctrl_soc.h b/boards/posix/nrf_bsim/soc/pinctrl_soc.h index 08252b57fee..f0be0443d5b 100644 --- a/boards/posix/nrf_bsim/soc/pinctrl_soc.h +++ b/boards/posix/nrf_bsim/soc/pinctrl_soc.h @@ -8,6 +8,6 @@ #define BOARDS_POSIX_NRF_BSIM_SOC_PINCTRL_SOC_H /* We reuse the real SOC's header: */ -#include "../soc/arm/nordic_nrf/common/pinctrl_soc.h" +#include "../soc/common/nordic_nrf/pinctrl_soc.h" #endif /* BOARDS_POSIX_NRF_BSIM_SOC_PINCTRL_SOC_H */ diff --git a/soc/CMakeLists.txt b/soc/CMakeLists.txt index 6706168281e..d55bd63f496 100644 --- a/soc/CMakeLists.txt +++ b/soc/CMakeLists.txt @@ -9,6 +9,8 @@ if(_SOC_IS_IN_TREE) endif() unset(_SOC_IS_IN_TREE) +add_subdirectory(common) + if(EXISTS ${SOC_DIR}/${ARCH}/CMakeLists.txt) add_subdirectory(${SOC_DIR}/${ARCH} soc/${ARCH}) else() diff --git a/soc/common/CMakeLists.txt b/soc/common/CMakeLists.txt new file mode 100644 index 00000000000..d9abad218cd --- /dev/null +++ b/soc/common/CMakeLists.txt @@ -0,0 +1,4 @@ +# Copyright (c) 2024 Nordic Semiconductor ASA +# SPDX-License-Identifier: Apache-2.0 + +add_subdirectory_ifdef(CONFIG_SOC_FAMILY_NRF nordic_nrf) diff --git a/soc/common/nordic_nrf/CMakeLists.txt b/soc/common/nordic_nrf/CMakeLists.txt new file mode 100644 index 00000000000..6f397a07fab --- /dev/null +++ b/soc/common/nordic_nrf/CMakeLists.txt @@ -0,0 +1,4 @@ +# Copyright (c) 2024 Nordic Semiconductor ASA +# SPDX-License-Identifier: Apache-2.0 + +zephyr_include_directories(.) diff --git a/soc/arm/nordic_nrf/common/pinctrl_soc.h b/soc/common/nordic_nrf/pinctrl_soc.h similarity index 100% rename from soc/arm/nordic_nrf/common/pinctrl_soc.h rename to soc/common/nordic_nrf/pinctrl_soc.h From 1a6b88608e10b6f2dde0c99077d32a63f9337a0b Mon Sep 17 00:00:00 2001 From: Gerard Marull-Paretas Date: Thu, 1 Feb 2024 10:44:47 +0100 Subject: [PATCH 3417/3723] soc: arm: nordic_nrf: move Kconfig.peripherals to common folder Because RISC-V cores also need to include this file, so it is no longer ARM specific. Signed-off-by: Gerard Marull-Paretas --- boards/posix/nrf_bsim/Kconfig | 2 +- soc/arm/nordic_nrf/Kconfig | 2 +- soc/{arm => common}/nordic_nrf/Kconfig.peripherals | 0 3 files changed, 2 insertions(+), 2 deletions(-) rename soc/{arm => common}/nordic_nrf/Kconfig.peripherals (100%) diff --git a/boards/posix/nrf_bsim/Kconfig b/boards/posix/nrf_bsim/Kconfig index c9a855d2111..b43db7fac4a 100644 --- a/boards/posix/nrf_bsim/Kconfig +++ b/boards/posix/nrf_bsim/Kconfig @@ -6,7 +6,7 @@ if SOC_SERIES_BSIM_NRFXX # used by Nordic SoCs, so to make the symbols defined in this file available for # the simulated nrf5x_bsim boards, which use the POSIX architecture, the file # must be read also from here. -source "soc/arm/nordic_nrf/Kconfig.peripherals" +source "soc/common/nordic_nrf/Kconfig.peripherals" source "boards/$(ARCH)/common/extra_args/Kconfig" diff --git a/soc/arm/nordic_nrf/Kconfig b/soc/arm/nordic_nrf/Kconfig index 589c1b59735..b2d164e7c78 100644 --- a/soc/arm/nordic_nrf/Kconfig +++ b/soc/arm/nordic_nrf/Kconfig @@ -13,7 +13,7 @@ config SOC_FAMILY string default "nordic_nrf" -source "soc/arm/nordic_nrf/Kconfig.peripherals" +source "soc/common/nordic_nrf/Kconfig.peripherals" source "soc/arm/nordic_nrf/*/Kconfig.soc" config NRF_SOC_SECURE_SUPPORTED diff --git a/soc/arm/nordic_nrf/Kconfig.peripherals b/soc/common/nordic_nrf/Kconfig.peripherals similarity index 100% rename from soc/arm/nordic_nrf/Kconfig.peripherals rename to soc/common/nordic_nrf/Kconfig.peripherals From ba16e3dd13e5d16d038c816defebad62ef8249a1 Mon Sep 17 00:00:00 2001 From: Gerard Marull-Paretas Date: Wed, 31 Jan 2024 19:46:00 +0100 Subject: [PATCH 3418/3723] soc: riscv: nordic_nrf: add initial support for VPR core Add initial support for the VPR RISC-V core found in the new nRF54 SoCs. Signed-off-by: Carlo Caione Signed-off-by: Gerard Marull-Paretas --- soc/riscv/nordic_nrf/CMakeLists.txt | 4 + soc/riscv/nordic_nrf/Kconfig | 15 +++ soc/riscv/nordic_nrf/Kconfig.defconfig | 8 ++ soc/riscv/nordic_nrf/common/CMakeLists.txt | 4 + soc/riscv/nordic_nrf/common/Kconfig | 4 + soc/riscv/nordic_nrf/common/Kconfig.defconfig | 8 ++ .../nordic_nrf/common/vpr/CMakeLists.txt | 9 ++ soc/riscv/nordic_nrf/common/vpr/Kconfig | 18 +++ .../nordic_nrf/common/vpr/Kconfig.defconfig | 27 ++++ soc/riscv/nordic_nrf/common/vpr/soc_context.h | 12 ++ soc/riscv/nordic_nrf/common/vpr/soc_irq.S | 30 +++++ soc/riscv/nordic_nrf/common/vpr/soc_irq.c | 26 ++++ .../nordic_nrf/common/vpr/soc_isr_stacking.h | 118 ++++++++++++++++++ soc/riscv/nordic_nrf/common/vpr/soc_offsets.h | 11 ++ soc/riscv/nordic_nrf/common/vpr/vector.S | 28 +++++ 15 files changed, 322 insertions(+) create mode 100644 soc/riscv/nordic_nrf/CMakeLists.txt create mode 100644 soc/riscv/nordic_nrf/Kconfig create mode 100644 soc/riscv/nordic_nrf/Kconfig.defconfig create mode 100644 soc/riscv/nordic_nrf/common/CMakeLists.txt create mode 100644 soc/riscv/nordic_nrf/common/Kconfig create mode 100644 soc/riscv/nordic_nrf/common/Kconfig.defconfig create mode 100644 soc/riscv/nordic_nrf/common/vpr/CMakeLists.txt create mode 100644 soc/riscv/nordic_nrf/common/vpr/Kconfig create mode 100644 soc/riscv/nordic_nrf/common/vpr/Kconfig.defconfig create mode 100644 soc/riscv/nordic_nrf/common/vpr/soc_context.h create mode 100644 soc/riscv/nordic_nrf/common/vpr/soc_irq.S create mode 100644 soc/riscv/nordic_nrf/common/vpr/soc_irq.c create mode 100644 soc/riscv/nordic_nrf/common/vpr/soc_isr_stacking.h create mode 100644 soc/riscv/nordic_nrf/common/vpr/soc_offsets.h create mode 100644 soc/riscv/nordic_nrf/common/vpr/vector.S diff --git a/soc/riscv/nordic_nrf/CMakeLists.txt b/soc/riscv/nordic_nrf/CMakeLists.txt new file mode 100644 index 00000000000..91bd222e147 --- /dev/null +++ b/soc/riscv/nordic_nrf/CMakeLists.txt @@ -0,0 +1,4 @@ +# Copyright (c) 2024 Nordic Semiconductor +# SPDX-License-Identifier: Apache-2.0 + +add_subdirectory(common) diff --git a/soc/riscv/nordic_nrf/Kconfig b/soc/riscv/nordic_nrf/Kconfig new file mode 100644 index 00000000000..3f17bea1756 --- /dev/null +++ b/soc/riscv/nordic_nrf/Kconfig @@ -0,0 +1,15 @@ +# Copyright (c) 2024 Nordic Semiconductor ASA +# SPDX-License-Identifier: Apache-2.0 + +config SOC_FAMILY_NRF + bool + +if SOC_FAMILY_NRF + +config SOC_FAMILY + string + default "nordic_nrf" + +source "soc/riscv/nordic_nrf/common/Kconfig" + +endif # SOC_FAMILY_NRF diff --git a/soc/riscv/nordic_nrf/Kconfig.defconfig b/soc/riscv/nordic_nrf/Kconfig.defconfig new file mode 100644 index 00000000000..a6d85ac846a --- /dev/null +++ b/soc/riscv/nordic_nrf/Kconfig.defconfig @@ -0,0 +1,8 @@ +# Copyright (c) 2024 Nordic Semiconductor ASA +# SPDX-License-Identifier: Apache-2.0 + +if SOC_FAMILY_NRF + +source "soc/riscv/nordic_nrf/common/Kconfig.defconfig" + +endif # SOC_FAMILY_NRF diff --git a/soc/riscv/nordic_nrf/common/CMakeLists.txt b/soc/riscv/nordic_nrf/common/CMakeLists.txt new file mode 100644 index 00000000000..806a295ea22 --- /dev/null +++ b/soc/riscv/nordic_nrf/common/CMakeLists.txt @@ -0,0 +1,4 @@ +# Copyright (c) 2024 Nordic Semiconductor ASA +# SPDX-License-Identifier: Apache-2.0 + +add_subdirectory_ifdef(CONFIG_RISCV_CORE_NORDIC_VPR vpr) diff --git a/soc/riscv/nordic_nrf/common/Kconfig b/soc/riscv/nordic_nrf/common/Kconfig new file mode 100644 index 00000000000..610689ecc6d --- /dev/null +++ b/soc/riscv/nordic_nrf/common/Kconfig @@ -0,0 +1,4 @@ +# Copyright (c) 2024 Nordic Semiconductor ASA +# SPDX-License-Identifier: Apache-2.0 + +source "soc/riscv/nordic_nrf/common/vpr/Kconfig" diff --git a/soc/riscv/nordic_nrf/common/Kconfig.defconfig b/soc/riscv/nordic_nrf/common/Kconfig.defconfig new file mode 100644 index 00000000000..9beb943edb8 --- /dev/null +++ b/soc/riscv/nordic_nrf/common/Kconfig.defconfig @@ -0,0 +1,8 @@ +# Copyright (c) 2024 Nordic Semiconductor ASA +# SPDX-License-Identifier: Apache-2.0 + +if RISCV_CORE_NORDIC_VPR + +source "soc/riscv/nordic_nrf/common/vpr/Kconfig.defconfig" + +endif # RISCV_CORE_NORDIC_VPR diff --git a/soc/riscv/nordic_nrf/common/vpr/CMakeLists.txt b/soc/riscv/nordic_nrf/common/vpr/CMakeLists.txt new file mode 100644 index 00000000000..e0331bb8e0b --- /dev/null +++ b/soc/riscv/nordic_nrf/common/vpr/CMakeLists.txt @@ -0,0 +1,9 @@ +# Copyright (c) 2024 Nordic Semiconductor ASA +# SPDX-License-Identifier: Apache-2.0 + +zephyr_include_directories(.) + +zephyr_library() +zephyr_library_sources(soc_irq.S soc_irq.c vector.S) + +set(SOC_LINKER_SCRIPT ${ZEPHYR_BASE}/include/zephyr/arch/riscv/common/linker.ld CACHE INTERNAL "") diff --git a/soc/riscv/nordic_nrf/common/vpr/Kconfig b/soc/riscv/nordic_nrf/common/vpr/Kconfig new file mode 100644 index 00000000000..40a7d199c0c --- /dev/null +++ b/soc/riscv/nordic_nrf/common/vpr/Kconfig @@ -0,0 +1,18 @@ +# Copyright (c) 2024 Nordic Semiconductor ASA +# SPDX-License-Identifier: Apache-2.0 + +config RISCV_CORE_NORDIC_VPR + bool "RISC-V Nordic VPR core" + default y + depends on DT_HAS_NORDIC_VPR_ENABLED + depends on RISCV + select ATOMIC_OPERATIONS_C + select RISCV_ISA_RV32E + select RISCV_ISA_EXT_M + select RISCV_ISA_EXT_C + select RISCV_ISA_EXT_ZICSR + select RISCV_ISA_EXT_ZIFENCEI + select RISCV_SOC_HAS_ISR_STACKING + select RISCV_SOC_CONTEXT_SAVE + help + Enable support for the RISC-V Nordic VPR core. diff --git a/soc/riscv/nordic_nrf/common/vpr/Kconfig.defconfig b/soc/riscv/nordic_nrf/common/vpr/Kconfig.defconfig new file mode 100644 index 00000000000..f0014455b3a --- /dev/null +++ b/soc/riscv/nordic_nrf/common/vpr/Kconfig.defconfig @@ -0,0 +1,27 @@ +# Copyright (c) 2024 Nordic Semiconductor ASA +# SPDX-License-Identifier: Apache-2.0 + +CPU_PATH := $(dt_nodelabel_path,cpu) +CPU_ID := $(dt_node_reg_addr_int,$(CPU_PATH)) + +config RV_BOOT_HART + default $(CPU_ID) + +config RISCV_MCAUSE_EXCEPTION_MASK + default 0xFFF + +config RISCV_RESERVED_IRQ_ISR_TABLES_OFFSET + default 16 + +config GEN_IRQ_VECTOR_TABLE + default y + +choice IRQ_VECTOR_TABLE_TYPE + default IRQ_VECTOR_TABLE_JUMP_BY_ADDRESS +endchoice + +config ARCH_SW_ISR_TABLE_ALIGN + default 64 + +config RISCV_ALWAYS_SWITCH_THROUGH_ECALL + default y if MULTITHREADING diff --git a/soc/riscv/nordic_nrf/common/vpr/soc_context.h b/soc/riscv/nordic_nrf/common/vpr/soc_context.h new file mode 100644 index 00000000000..8cd0d1e5094 --- /dev/null +++ b/soc/riscv/nordic_nrf/common/vpr/soc_context.h @@ -0,0 +1,12 @@ +/* + * Copyright (C) 2024 Nordic Semiconductor ASA + * SPDX-License-Identifier: Apache-2.0 + */ + +#ifndef SOC_RISCV_NORDIC_NRF_COMMON_VPR_SOC_CONTEXT_H_ +#define SOC_RISCV_NORDIC_NRF_COMMON_VPR_SOC_CONTEXT_H_ + +#define SOC_ESF_MEMBERS unsigned long minttresh +#define SOC_ESF_INIT 0 + +#endif /* SOC_RISCV_NORDIC_NRF_COMMON_VPR_SOC_CONTEXT_H_ */ diff --git a/soc/riscv/nordic_nrf/common/vpr/soc_irq.S b/soc/riscv/nordic_nrf/common/vpr/soc_irq.S new file mode 100644 index 00000000000..0e9db48d9b4 --- /dev/null +++ b/soc/riscv/nordic_nrf/common/vpr/soc_irq.S @@ -0,0 +1,30 @@ +/* + * Copyright (C) 2024 Nordic Semiconductor ASA + * SPDX-License-Identifier: Apache-2.0 + */ + +#include +#include + +/* Exports */ +GTEXT(__soc_handle_irq) +GTEXT(__soc_save_context) +GTEXT(__soc_restore_context) + +/* + * No need to clear anything, pending bit is cleared by HW. + */ +SECTION_FUNC(exception.other, __soc_handle_irq) + ret + +SECTION_FUNC(exception.other, __soc_save_context) + csrr t0, 0x347 + sw t0, __soc_esf_t_minttresh_OFFSET(a0) + + ret + +SECTION_FUNC(exception.other, __soc_restore_context) + lw t0, __soc_esf_t_minttresh_OFFSET(a0) + csrw 0x347, t0 + + ret diff --git a/soc/riscv/nordic_nrf/common/vpr/soc_irq.c b/soc/riscv/nordic_nrf/common/vpr/soc_irq.c new file mode 100644 index 00000000000..88655f6efa0 --- /dev/null +++ b/soc/riscv/nordic_nrf/common/vpr/soc_irq.c @@ -0,0 +1,26 @@ +/* + * Copyright (C) 2024 Nordic Semiconductor ASA + * SPDX-License-Identifier: Apache-2.0 + */ + +#include + +void arch_irq_enable(unsigned int irq) +{ + nrf_vpr_clic_int_enable_set(NRF_VPRCLIC, irq, true); +} + +void arch_irq_disable(unsigned int irq) +{ + nrf_vpr_clic_int_enable_set(NRF_VPRCLIC, irq, false); +} + +void arch_irq_priority_set(unsigned int irq, unsigned int prio) +{ + nrf_vpr_clic_int_priority_set(NRF_VPRCLIC, irq, prio); +} + +int arch_irq_is_enabled(unsigned int irq) +{ + return nrf_vpr_clic_int_enable_check(NRF_VPRCLIC, irq); +} diff --git a/soc/riscv/nordic_nrf/common/vpr/soc_isr_stacking.h b/soc/riscv/nordic_nrf/common/vpr/soc_isr_stacking.h new file mode 100644 index 00000000000..d5b139111d0 --- /dev/null +++ b/soc/riscv/nordic_nrf/common/vpr/soc_isr_stacking.h @@ -0,0 +1,118 @@ +/* + * Copyright (C) 2024 Nordic Semiconductor ASA + * SPDX-License-Identifier: Apache-2.0 + */ + +#ifndef SOC_RISCV_NORDIC_NRF_COMMON_VPR_SOC_ISR_STACKING_H_ +#define SOC_RISCV_NORDIC_NRF_COMMON_VPR_SOC_ISR_STACKING_H_ + +#include + +#if !defined(_ASMLANGUAGE) + +#include + +#define VPR_CPU DT_INST(0, nordic_vpr) + +#if DT_PROP(VPR_CPU, nordic_bus_width) == 64 + +#define SOC_ISR_STACKING_ESF_DECLARE \ + struct __esf { \ + unsigned long s0; \ + unsigned long mstatus; \ + unsigned long tp; \ + struct soc_esf soc_context; \ + \ + unsigned long t2; \ + unsigned long ra; \ + unsigned long t0; \ + unsigned long t1; \ + unsigned long a4; \ + unsigned long a5; \ + unsigned long a2; \ + unsigned long a3; \ + unsigned long a0; \ + unsigned long a1; \ + unsigned long mepc; \ + unsigned long _mcause; \ + } __aligned(16); + +#else /* DT_PROP(VPR_CPU, nordic_bus_width) == 32 */ + +#define SOC_ISR_STACKING_ESF_DECLARE \ + struct __esf { \ + unsigned long s0; \ + unsigned long mstatus; \ + unsigned long tp; \ + struct soc_esf soc_context; \ + \ + unsigned long ra; \ + unsigned long t2; \ + unsigned long t1; \ + unsigned long t0; \ + unsigned long a5; \ + unsigned long a4; \ + unsigned long a3; \ + unsigned long a2; \ + unsigned long a1; \ + unsigned long a0; \ + unsigned long mepc; \ + unsigned long _mcause; \ + } __aligned(16); + +#endif /* DT_PROP(VPR_CPU, nordic_bus_width) == 64 */ + +#else /* _ASMLANGUAGE */ + +/* + * Size of the HW managed part of the ESF: + * sizeof(_mcause) + sizeof(_mepc) + */ +#define ESF_HW_SIZEOF (0x8) + +/* + * Size of the SW managed part of the ESF in case of exception + */ +#define ESF_SW_EXC_SIZEOF (__z_arch_esf_t_SIZEOF - ESF_HW_SIZEOF) + +/* + * Size of the SW managed part of the ESF in case of interrupt + * sizeof(__padding) + ... + sizeof(soc_context) + */ +#define ESF_SW_IRQ_SIZEOF (0x10) + +#define SOC_ISR_SW_STACKING \ + csrw mscratch, t0; \ + \ + csrr t0, mcause; \ + srli t0, t0, RISCV_MCAUSE_IRQ_POS; \ + bnez t0, stacking_is_interrupt; \ + \ + csrrw t0, mscratch, zero; \ + \ + addi sp, sp, -ESF_SW_EXC_SIZEOF; \ + DO_CALLER_SAVED(sr); \ + j stacking_keep_going; \ + \ +stacking_is_interrupt: \ + addi sp, sp, -ESF_SW_IRQ_SIZEOF; \ + \ +stacking_keep_going: + +#define SOC_ISR_SW_UNSTACKING \ + csrr t0, mcause; \ + srli t0, t0, RISCV_MCAUSE_IRQ_POS; \ + bnez t0, unstacking_is_interrupt; \ + \ + DO_CALLER_SAVED(lr); \ + addi sp, sp, ESF_SW_EXC_SIZEOF; \ + j unstacking_keep_going; \ + \ +unstacking_is_interrupt: \ + addi sp, sp, ESF_SW_IRQ_SIZEOF; \ + \ +unstacking_keep_going: + +#endif /* _ASMLANGUAGE */ + +#endif /* SOC_RISCV_NORDIC_NRF_COMMON_VPR_SOC_ISR_STACKING_H_ */ diff --git a/soc/riscv/nordic_nrf/common/vpr/soc_offsets.h b/soc/riscv/nordic_nrf/common/vpr/soc_offsets.h new file mode 100644 index 00000000000..92d91044e1a --- /dev/null +++ b/soc/riscv/nordic_nrf/common/vpr/soc_offsets.h @@ -0,0 +1,11 @@ +/* + * Copyright (C) 2024 Nordic Semiconductor ASA + * SPDX-License-Identifier: Apache-2.0 + */ + +#ifndef SOC_RISCV_NORDIC_NRF_COMMON_VPR_SOC_OFFSETS_H_ +#define SOC_RISCV_NORDIC_NRF_COMMON_VPR_SOC_OFFSETS_H_ + +#define GEN_SOC_OFFSET_SYMS() GEN_OFFSET_SYM(soc_esf_t, minttresh) + +#endif /* SOC_RISCV_NORDIC_NRF_COMMON_VPR_SOC_OFFSETS_H_ */ diff --git a/soc/riscv/nordic_nrf/common/vpr/vector.S b/soc/riscv/nordic_nrf/common/vpr/vector.S new file mode 100644 index 00000000000..b8c6d97170c --- /dev/null +++ b/soc/riscv/nordic_nrf/common/vpr/vector.S @@ -0,0 +1,28 @@ +/* + * Copyright (C) 2024 Nordic Semiconductor ASA + * SPDX-License-Identifier: Apache-2.0 + */ + +#include + +/* Imports */ +GTEXT(__initialize) + +/* Exports */ +GTEXT(__start) + +SECTION_FUNC(vectors, __start) + /* Set mtvec.base (mtvec.mode is RO, no need to mask it). */ + la t0, _isr_wrapper + csrw mtvec, t0 + + /* Set mtvt. */ + la t0, _irq_vector_table + csrw 0x307, t0 + + /* Enable mstatus.mie */ + li t0, 0x1888 + csrw mstatus, t0 + + /* Call into Zephyr initialization. */ + tail __initialize From 426bbf5649a93aba5d42bf1087178b992e5e3409 Mon Sep 17 00:00:00 2001 From: Gerard Marull-Paretas Date: Thu, 1 Feb 2024 10:36:27 +0100 Subject: [PATCH 3419/3723] soc: riscv: nordic_nrf: nrf54h: introduce PPR support Add support for the nRF54H PPR (Peripheral Processor), based on the VPR RISC-V core. Signed-off-by: Gerard Marull-Paretas --- modules/hal_nordic/nrfx/CMakeLists.txt | 3 +++ soc/riscv/nordic_nrf/CMakeLists.txt | 1 + soc/riscv/nordic_nrf/Kconfig | 3 +++ soc/riscv/nordic_nrf/Kconfig.defconfig | 8 ++++++++ soc/riscv/nordic_nrf/Kconfig.soc | 4 ++++ soc/riscv/nordic_nrf/nrf54h/CMakeLists.txt | 6 ++++++ .../Kconfig.defconfig.nrf54h20_enga_cpuppr | 15 +++++++++++++++ .../nrf54h/Kconfig.defconfig.series | 19 +++++++++++++++++++ soc/riscv/nordic_nrf/nrf54h/Kconfig.series | 10 ++++++++++ soc/riscv/nordic_nrf/nrf54h/Kconfig.soc | 19 +++++++++++++++++++ soc/riscv/nordic_nrf/nrf54h/align.ld | 10 ++++++++++ 11 files changed, 98 insertions(+) create mode 100644 soc/riscv/nordic_nrf/Kconfig.soc create mode 100644 soc/riscv/nordic_nrf/nrf54h/CMakeLists.txt create mode 100644 soc/riscv/nordic_nrf/nrf54h/Kconfig.defconfig.nrf54h20_enga_cpuppr create mode 100644 soc/riscv/nordic_nrf/nrf54h/Kconfig.defconfig.series create mode 100644 soc/riscv/nordic_nrf/nrf54h/Kconfig.series create mode 100644 soc/riscv/nordic_nrf/nrf54h/Kconfig.soc create mode 100644 soc/riscv/nordic_nrf/nrf54h/align.ld diff --git a/modules/hal_nordic/nrfx/CMakeLists.txt b/modules/hal_nordic/nrfx/CMakeLists.txt index 9b8bd0caff4..5a97c7ba44b 100644 --- a/modules/hal_nordic/nrfx/CMakeLists.txt +++ b/modules/hal_nordic/nrfx/CMakeLists.txt @@ -45,6 +45,8 @@ zephyr_compile_definitions_ifdef(CONFIG_SOC_NRF54H20_ENGA_CPUAPP NRF54H20_ENGA_X NRF_APPLICATION) zephyr_compile_definitions_ifdef(CONFIG_SOC_NRF54H20_ENGA_CPURAD NRF54H20_ENGA_XXAA NRF_RADIOCORE) +zephyr_compile_definitions_ifdef(CONFIG_SOC_NRF54H20_ENGA_CPUPPR NRF54H20_ENGA_XXAA + NRF_PPR) zephyr_compile_definitions_ifdef(CONFIG_NRF_APPROTECT_LOCK ENABLE_APPROTECT) @@ -178,6 +180,7 @@ mdk_svd_ifdef(CONFIG_SOC_NRF52840 nrf52840.svd) mdk_svd_ifdef(CONFIG_SOC_NRF5340_CPUAPP nrf5340_application.svd) mdk_svd_ifdef(CONFIG_SOC_NRF5340_CPUNET nrf5340_network.svd) mdk_svd_ifdef(CONFIG_SOC_NRF54H20_ENGA_CPUAPP nrf54h20_enga_application.svd) +mdk_svd_ifdef(CONFIG_SOC_NRF54H20_ENGA_CPUPPR nrf54h20_enga_ppr.svd) mdk_svd_ifdef(CONFIG_SOC_NRF54H20_ENGA_CPURAD nrf54h20_enga_radiocore.svd) mdk_svd_ifdef(CONFIG_SOC_NRF9120 nrf9120.svd) mdk_svd_ifdef(CONFIG_SOC_NRF9160 nrf9160.svd) diff --git a/soc/riscv/nordic_nrf/CMakeLists.txt b/soc/riscv/nordic_nrf/CMakeLists.txt index 91bd222e147..6a5b10545ff 100644 --- a/soc/riscv/nordic_nrf/CMakeLists.txt +++ b/soc/riscv/nordic_nrf/CMakeLists.txt @@ -2,3 +2,4 @@ # SPDX-License-Identifier: Apache-2.0 add_subdirectory(common) +add_subdirectory(${SOC_SERIES}) diff --git a/soc/riscv/nordic_nrf/Kconfig b/soc/riscv/nordic_nrf/Kconfig index 3f17bea1756..a39db4671d5 100644 --- a/soc/riscv/nordic_nrf/Kconfig +++ b/soc/riscv/nordic_nrf/Kconfig @@ -12,4 +12,7 @@ config SOC_FAMILY source "soc/riscv/nordic_nrf/common/Kconfig" +source "soc/common/nordic_nrf/Kconfig.peripherals" +source "soc/riscv/nordic_nrf/*/Kconfig.soc" + endif # SOC_FAMILY_NRF diff --git a/soc/riscv/nordic_nrf/Kconfig.defconfig b/soc/riscv/nordic_nrf/Kconfig.defconfig index a6d85ac846a..cc3ec954985 100644 --- a/soc/riscv/nordic_nrf/Kconfig.defconfig +++ b/soc/riscv/nordic_nrf/Kconfig.defconfig @@ -3,6 +3,14 @@ if SOC_FAMILY_NRF +source "soc/riscv/nordic_nrf/*/Kconfig.defconfig.series" source "soc/riscv/nordic_nrf/common/Kconfig.defconfig" +config BUILD_OUTPUT_HEX + default y + +config SYS_CLOCK_HW_CYCLES_PER_SEC + default 1000000 if NRF_GRTC_TIMER + default 32768 if NRF_RTC_TIMER + endif # SOC_FAMILY_NRF diff --git a/soc/riscv/nordic_nrf/Kconfig.soc b/soc/riscv/nordic_nrf/Kconfig.soc new file mode 100644 index 00000000000..593d6f91769 --- /dev/null +++ b/soc/riscv/nordic_nrf/Kconfig.soc @@ -0,0 +1,4 @@ +# Copyright (c) 2024 Nordic Semiconductor ASA +# SPDX-License-Identifier: Apache-2.0 + +source "soc/riscv/nordic_nrf/*/Kconfig.series" diff --git a/soc/riscv/nordic_nrf/nrf54h/CMakeLists.txt b/soc/riscv/nordic_nrf/nrf54h/CMakeLists.txt new file mode 100644 index 00000000000..5b37b3a54d8 --- /dev/null +++ b/soc/riscv/nordic_nrf/nrf54h/CMakeLists.txt @@ -0,0 +1,6 @@ +# Copyright (c) 2024 Nordic Semiconductor +# SPDX-License-Identifier: Apache-2.0 + +# Ensure that image size aligns with 16 bytes so that MRAMC finalizes all writes +# for the image correctly +zephyr_linker_sources(SECTIONS SORT_KEY zzz_place_align_at_end align.ld) diff --git a/soc/riscv/nordic_nrf/nrf54h/Kconfig.defconfig.nrf54h20_enga_cpuppr b/soc/riscv/nordic_nrf/nrf54h/Kconfig.defconfig.nrf54h20_enga_cpuppr new file mode 100644 index 00000000000..a36d24c72ae --- /dev/null +++ b/soc/riscv/nordic_nrf/nrf54h/Kconfig.defconfig.nrf54h20_enga_cpuppr @@ -0,0 +1,15 @@ +# Copyright (c) 2024 Nordic Semiconductor ASA +# SPDX-License-Identifier: Apache-2.0 + +if SOC_NRF54H20_ENGA_CPUPPR + +config SOC + default "nrf54h20_enga_cpuppr" + +config NUM_IRQS + default 496 + +config SYS_CLOCK_TICKS_PER_SEC + default 1000 + +endif # SOC_NRF54H20_ENGA_CPUPPR diff --git a/soc/riscv/nordic_nrf/nrf54h/Kconfig.defconfig.series b/soc/riscv/nordic_nrf/nrf54h/Kconfig.defconfig.series new file mode 100644 index 00000000000..0f827fbe96b --- /dev/null +++ b/soc/riscv/nordic_nrf/nrf54h/Kconfig.defconfig.series @@ -0,0 +1,19 @@ +# Copyright (c) 2024 Nordic Semiconductor ASA +# SPDX-License-Identifier: Apache-2.0 + +if SOC_SERIES_NRF54HX + +rsource "Kconfig.defconfig.nrf54h*" + +config SOC_SERIES + default "nrf54h" + +DT_CHOSEN_Z_SRAM = zephyr,sram +DT_CHOSEN_Z_CODE = zephyr,code-partition + +config BUILD_OUTPUT_ADJUST_LMA + depends on !XIP + default "$(dt_chosen_partition_addr_hex,$(DT_CHOSEN_Z_CODE)) - \ + $(dt_chosen_reg_addr_hex,$(DT_CHOSEN_Z_SRAM))" + +endif # SOC_SERIES_NRF54HX diff --git a/soc/riscv/nordic_nrf/nrf54h/Kconfig.series b/soc/riscv/nordic_nrf/nrf54h/Kconfig.series new file mode 100644 index 00000000000..acb85b5623a --- /dev/null +++ b/soc/riscv/nordic_nrf/nrf54h/Kconfig.series @@ -0,0 +1,10 @@ +# Copyright (c) 2024 Nordic Semiconductor ASA +# SPDX-License-Identifier: Apache-2.0 + +config SOC_SERIES_NRF54HX + bool "Nordic Semiconductor nRF54H series MCU" + select SOC_FAMILY_NRF + select HAS_NRFX + select HAS_NORDIC_DRIVERS + help + Enable support for nRF54H MCU series diff --git a/soc/riscv/nordic_nrf/nrf54h/Kconfig.soc b/soc/riscv/nordic_nrf/nrf54h/Kconfig.soc new file mode 100644 index 00000000000..17a6dd667c6 --- /dev/null +++ b/soc/riscv/nordic_nrf/nrf54h/Kconfig.soc @@ -0,0 +1,19 @@ +# Copyright (c) 2024 Nordic Semiconductor ASA +# SPDX-License-Identifier: Apache-2.0 + +config SOC_NRF54H20 + bool "nRF54H20" + depends on SOC_SERIES_NRF54HX + +if SOC_NRF54H20 + +choice + prompt "nRF54Hx MCU Selection" + +config SOC_NRF54H20_ENGA_CPUPPR + bool "nRF54H20 ENGA CPUPPR" + select RISCV + +endchoice + +endif # SOC_NRF54H20 diff --git a/soc/riscv/nordic_nrf/nrf54h/align.ld b/soc/riscv/nordic_nrf/nrf54h/align.ld new file mode 100644 index 00000000000..0905aa7f7bc --- /dev/null +++ b/soc/riscv/nordic_nrf/nrf54h/align.ld @@ -0,0 +1,10 @@ +/* + * Copyright (c) 2024 Nordic Semiconductor ASA. + * SPDX-License-Identifier: Apache-2.0 + */ + +SECTION_PROLOGUE(.align16,,) +{ + . = (ALIGN(16) > 0 ? ALIGN(16) : 16) - 1; + BYTE(0); +} GROUP_LINK_IN(ROMABLE_REGION) From 117194ae22b16faa54716701f3f949d643e10d68 Mon Sep 17 00:00:00 2001 From: Gerard Marull-Paretas Date: Wed, 31 Jan 2024 19:47:33 +0100 Subject: [PATCH 3420/3723] boards: riscv: add nrf54h20pdk_nrf54h20_cpuppr Add a board that allows to build for the nRF54H20 PPR RISC-V core. Signed-off-by: Grzegorz Swiderski Signed-off-by: Gerard Marull-Paretas --- .../riscv/nrf54h20pdk_nrf54h20/Kconfig.board | 6 +++ .../nrf54h20pdk_nrf54h20/Kconfig.defconfig | 6 +++ boards/riscv/nrf54h20pdk_nrf54h20/board.cmake | 3 ++ .../nrf54h20pdk_nrf54h20_cpuppr.dts | 43 +++++++++++++++++++ .../nrf54h20pdk_nrf54h20_cpuppr.yaml | 13 ++++++ .../nrf54h20pdk_nrf54h20_cpuppr_defconfig | 14 ++++++ .../nrf54h20pdk_nrf54h20/pre_dt_board.cmake | 7 +++ 7 files changed, 92 insertions(+) create mode 100644 boards/riscv/nrf54h20pdk_nrf54h20/Kconfig.board create mode 100644 boards/riscv/nrf54h20pdk_nrf54h20/Kconfig.defconfig create mode 100644 boards/riscv/nrf54h20pdk_nrf54h20/board.cmake create mode 100644 boards/riscv/nrf54h20pdk_nrf54h20/nrf54h20pdk_nrf54h20_cpuppr.dts create mode 100644 boards/riscv/nrf54h20pdk_nrf54h20/nrf54h20pdk_nrf54h20_cpuppr.yaml create mode 100644 boards/riscv/nrf54h20pdk_nrf54h20/nrf54h20pdk_nrf54h20_cpuppr_defconfig create mode 100644 boards/riscv/nrf54h20pdk_nrf54h20/pre_dt_board.cmake diff --git a/boards/riscv/nrf54h20pdk_nrf54h20/Kconfig.board b/boards/riscv/nrf54h20pdk_nrf54h20/Kconfig.board new file mode 100644 index 00000000000..9bbbba60dd4 --- /dev/null +++ b/boards/riscv/nrf54h20pdk_nrf54h20/Kconfig.board @@ -0,0 +1,6 @@ +# Copyright (c) 2024 Nordic Semiconductor ASA +# SPDX-License-Identifier: Apache-2.0 + +config BOARD_NRF54H20PDK_NRF54H20_CPUPPR + bool "nRF54H20 PDK nRF54H20 PPR MCU" + depends on SOC_NRF54H20_ENGA_CPUPPR diff --git a/boards/riscv/nrf54h20pdk_nrf54h20/Kconfig.defconfig b/boards/riscv/nrf54h20pdk_nrf54h20/Kconfig.defconfig new file mode 100644 index 00000000000..256976d6519 --- /dev/null +++ b/boards/riscv/nrf54h20pdk_nrf54h20/Kconfig.defconfig @@ -0,0 +1,6 @@ +# Copyright (c) 2024 Nordic Semiconductor ASA +# SPDX-License-Identifier: Apache-2.0 + +config BOARD + default "nrf54h20pdk_nrf54h20_cpuppr" + depends on BOARD_NRF54H20PDK_NRF54H20_CPUPPR diff --git a/boards/riscv/nrf54h20pdk_nrf54h20/board.cmake b/boards/riscv/nrf54h20pdk_nrf54h20/board.cmake new file mode 100644 index 00000000000..4c63f1dd05e --- /dev/null +++ b/boards/riscv/nrf54h20pdk_nrf54h20/board.cmake @@ -0,0 +1,3 @@ +# SPDX-License-Identifier: Apache-2.0 + +include(${ZEPHYR_BASE}/boards/common/nrfjprog.board.cmake) diff --git a/boards/riscv/nrf54h20pdk_nrf54h20/nrf54h20pdk_nrf54h20_cpuppr.dts b/boards/riscv/nrf54h20pdk_nrf54h20/nrf54h20pdk_nrf54h20_cpuppr.dts new file mode 100644 index 00000000000..83aface6f5c --- /dev/null +++ b/boards/riscv/nrf54h20pdk_nrf54h20/nrf54h20pdk_nrf54h20_cpuppr.dts @@ -0,0 +1,43 @@ +/* + * Copyright (c) 2024 Nordic Semiconductor ASA + * + * SPDX-License-Identifier: Apache-2.0 + */ + +/dts-v1/; + +#include +#include "nrf54h20pdk_nrf54h20-memory_map.dtsi" +#include "nrf54h20pdk_nrf54h20-pinctrl.dtsi" + +/ { + compatible = "nordic,nrf54h20pdk_nrf54h20-cpuppr"; + model = "Nordic nRF54H20 PDK nRF54H20 Peripheral Processor MCU"; + #address-cells = <1>; + #size-cells = <1>; + + chosen { + zephyr,console = &uart135; + zephyr,code-partition = &cpuppr_code_partition; + zephyr,flash = &mram1x; + zephyr,sram = &cpuppr_ram3x_region; + }; +}; + +&grtc { + status = "okay"; + owned-channels = <5>; +}; + +&uart135 { + status = "okay"; + pinctrl-0 = <&uart135_default>; + pinctrl-1 = <&uart135_sleep>; + pinctrl-names = "default", "sleep"; +}; + +&uart136 { + pinctrl-0 = <&uart136_default>; + pinctrl-1 = <&uart136_sleep>; + pinctrl-names = "default", "sleep"; +}; diff --git a/boards/riscv/nrf54h20pdk_nrf54h20/nrf54h20pdk_nrf54h20_cpuppr.yaml b/boards/riscv/nrf54h20pdk_nrf54h20/nrf54h20pdk_nrf54h20_cpuppr.yaml new file mode 100644 index 00000000000..274be865c36 --- /dev/null +++ b/boards/riscv/nrf54h20pdk_nrf54h20/nrf54h20pdk_nrf54h20_cpuppr.yaml @@ -0,0 +1,13 @@ +# Copyright (c) 2024 Nordic Semiconductor ASA +# SPDX-License-Identifier: Apache-2.0 + +identifier: nrf54h20pdk_nrf54h20_cpuppr +name: nRF54H20-PDK-nRF54H20-PPR +type: mcu +arch: riscv +toolchain: + - zephyr +ram: 28 +flash: 28 +supported: + - gpio diff --git a/boards/riscv/nrf54h20pdk_nrf54h20/nrf54h20pdk_nrf54h20_cpuppr_defconfig b/boards/riscv/nrf54h20pdk_nrf54h20/nrf54h20pdk_nrf54h20_cpuppr_defconfig new file mode 100644 index 00000000000..fb3dca2266d --- /dev/null +++ b/boards/riscv/nrf54h20pdk_nrf54h20/nrf54h20pdk_nrf54h20_cpuppr_defconfig @@ -0,0 +1,14 @@ +# Copyright (c) 2024 Nordic Semiconductor ASA +# SPDX-License-Identifier: Apache-2.0 + +CONFIG_SOC_SERIES_NRF54HX=y +CONFIG_SOC_NRF54H20=y +CONFIG_SOC_NRF54H20_ENGA_CPUPPR=y +CONFIG_BOARD_NRF54H20PDK_NRF54H20_CPUPPR=y + +CONFIG_XIP=n + +CONFIG_SERIAL=y + +CONFIG_CONSOLE=y +CONFIG_UART_CONSOLE=y diff --git a/boards/riscv/nrf54h20pdk_nrf54h20/pre_dt_board.cmake b/boards/riscv/nrf54h20pdk_nrf54h20/pre_dt_board.cmake new file mode 100644 index 00000000000..5e0fecebdc8 --- /dev/null +++ b/boards/riscv/nrf54h20pdk_nrf54h20/pre_dt_board.cmake @@ -0,0 +1,7 @@ +# Copyright (c) 2024 Nordic Semiconductor ASA +# SPDX-License-Identifier: Apache-2.0 + +# Allow common DTS files to be included from the other board directory. +# To be removed after HWMv2 (#51831), once both directories can be merged into one. +string(REGEX REPLACE "/riscv/(.*$)" "/arm/\\1" BOARD_DIR_ARM "${BOARD_DIR}") +list(APPEND DTS_EXTRA_CPPFLAGS -isystem "${BOARD_DIR_ARM}") From c460d285c0a6cb1db619340f4290c0e983d8045d Mon Sep 17 00:00:00 2001 From: Lars Knudsen Date: Thu, 1 Feb 2024 21:38:55 +0100 Subject: [PATCH 3421/3723] MAINTAINERS: Add pin-zephyr to Bluetooth Audio Ping is collaborating on Bluetooth Audio and is attending the weekly LE Audio Zephyr meetings Signed-off-by: Lars Knudsen --- MAINTAINERS.yml | 1 + 1 file changed, 1 insertion(+) diff --git a/MAINTAINERS.yml b/MAINTAINERS.yml index ae4698ccbe8..9ea1f4bde65 100644 --- a/MAINTAINERS.yml +++ b/MAINTAINERS.yml @@ -443,6 +443,7 @@ Bluetooth Audio: - fredrikdanebjer - kruithofa - larsgk + - pin-zephyr files: - subsys/bluetooth/audio/ - include/zephyr/bluetooth/audio/ From 125a2bccaae29d16b1085fa72139c17a4321fe95 Mon Sep 17 00:00:00 2001 From: John Johnson Date: Fri, 26 Jan 2024 07:32:11 +0100 Subject: [PATCH 3422/3723] net: net_pkt: add peer sockaddr member in net_pkt struct Add sockaddr member in struct net_pkt to store peer address if offloaded network inteface is used. This enables recvfrom() to fill in src_addr if socket type is UDP and offloaded interface driver supports it. Signed-off-by: John Johnson --- include/zephyr/net/net_pkt.h | 7 +++ subsys/net/lib/sockets/sockets.c | 95 ++++++++++++++++++++++++++------ 2 files changed, 86 insertions(+), 16 deletions(-) diff --git a/include/zephyr/net/net_pkt.h b/include/zephyr/net/net_pkt.h index c5878213a02..c3ef9418085 100644 --- a/include/zephyr/net/net_pkt.h +++ b/include/zephyr/net/net_pkt.h @@ -290,6 +290,13 @@ struct net_pkt { */ uint8_t priority; +#if defined(CONFIG_NET_OFFLOAD) + /* Remote address of the recived packet. This is only used by + * network interfaces with an offloaded TCP/IP stack. + */ + struct sockaddr remote; +#endif /* CONFIG_NET_OFFLOAD */ + /* @endcond */ }; diff --git a/subsys/net/lib/sockets/sockets.c b/subsys/net/lib/sockets/sockets.c index 48fbad2d03f..4f34f5013d2 100644 --- a/subsys/net/lib/sockets/sockets.c +++ b/subsys/net/lib/sockets/sockets.c @@ -1134,6 +1134,73 @@ static int sock_get_pkt_src_addr(struct net_pkt *pkt, return ret; } +#if defined(CONFIG_NET_OFFLOAD) +static bool net_pkt_remote_addr_is_unspecified(struct net_pkt *pkt) +{ + bool ret = true; + + if (net_pkt_family(pkt) == AF_INET) { + ret = net_ipv4_is_addr_unspecified(&net_sin(&pkt->remote)->sin_addr); + } else if (net_pkt_family(pkt) == AF_INET6) { + ret = net_ipv6_is_addr_unspecified(&net_sin6(&pkt->remote)->sin6_addr); + } + + return ret; +} + +static int sock_get_offload_pkt_src_addr(struct net_pkt *pkt, + struct net_context *ctx, + struct sockaddr *addr, + socklen_t addrlen) +{ + int ret = 0; + + if (!addr || !pkt) { + return -EINVAL; + } + + if (!net_pkt_remote_addr_is_unspecified(pkt)) { + if (IS_ENABLED(CONFIG_NET_IPV4) && + net_pkt_family(pkt) == AF_INET) { + if (addrlen < sizeof(struct sockaddr_in)) { + ret = -EINVAL; + goto error; + } + + memcpy(addr, &pkt->remote, sizeof(struct sockaddr_in)); + } else if (IS_ENABLED(CONFIG_NET_IPV6) && + net_pkt_family(pkt) == AF_INET6) { + if (addrlen < sizeof(struct sockaddr_in6)) { + ret = -EINVAL; + goto error; + } + + memcpy(addr, &pkt->remote, sizeof(struct sockaddr_in6)); + } + } else if (ctx->flags & NET_CONTEXT_REMOTE_ADDR_SET) { + memcpy(addr, &ctx->remote, MIN(addrlen, sizeof(ctx->remote))); + } else { + ret = -ENOTSUP; + } + +error: + return ret; +} +#else +static int sock_get_offload_pkt_src_addr(struct net_pkt *pkt, + struct net_context *ctx, + struct sockaddr *addr, + socklen_t addrlen) +{ + ARG_UNUSED(pkt); + ARG_UNUSED(ctx); + ARG_UNUSED(addr); + ARG_UNUSED(addrlen); + + return 0; +} +#endif /* CONFIG_NET_OFFLOAD */ + void net_socket_update_tc_rx_time(struct net_pkt *pkt, uint32_t end_tick) { net_pkt_set_rx_stats_tick(pkt, end_tick); @@ -1337,27 +1404,23 @@ static inline ssize_t zsock_recv_dgram(struct net_context *ctx, if (src_addr && addrlen) { if (IS_ENABLED(CONFIG_NET_OFFLOAD) && net_if_is_ip_offloaded(net_context_get_iface(ctx))) { - /* - * Packets from offloaded IP stack do not have IP - * headers, so src address cannot be figured out at this - * point. The best we can do is returning remote address - * if that was set using connect() call. - */ - if (ctx->flags & NET_CONTEXT_REMOTE_ADDR_SET) { - memcpy(src_addr, &ctx->remote, - MIN(*addrlen, sizeof(ctx->remote))); - } else { - errno = ENOTSUP; + int ret; + + ret = sock_get_offload_pkt_src_addr(pkt, ctx, src_addr, + *addrlen); + if (ret < 0) { + errno = -ret; + NET_DBG("sock_get_offload_pkt_src_addr %d", ret); goto fail; } } else { - int rv; + int ret; - rv = sock_get_pkt_src_addr(pkt, net_context_get_proto(ctx), + ret = sock_get_pkt_src_addr(pkt, net_context_get_proto(ctx), src_addr, *addrlen); - if (rv < 0) { - errno = -rv; - LOG_ERR("sock_get_pkt_src_addr %d", rv); + if (ret < 0) { + errno = -ret; + NET_DBG("sock_get_pkt_src_addr %d", ret); goto fail; } } From d676234493d375e80f49afb9954f42bda30f3dd7 Mon Sep 17 00:00:00 2001 From: Jamie McCrae Date: Fri, 13 Oct 2023 11:08:32 +0100 Subject: [PATCH 3423/3723] cmake: Add support for sysbuild-set signing script Allows a sysbuild project to specify a signing script file to use instead of the default zephyr one Signed-off-by: Jamie McCrae --- CMakeLists.txt | 15 ++++++++++----- 1 file changed, 10 insertions(+), 5 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index ff12e0852ec..ce9121b3f73 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -1818,16 +1818,21 @@ if(NOT CMAKE_C_COMPILER_ID STREQUAL "ARMClang") ) endif() -# Generate and use MCUboot related artifacts as needed. -if(CONFIG_BOOTLOADER_MCUBOOT) +# Generate signed (MCUboot or other) related artifacts as needed. Priority is: +# * Sysbuild (if set) +# * SIGNING_SCRIPT target property (if set) +# * MCUboot signing script (if MCUboot is enabled) +zephyr_get(signing_script VAR SIGNING_SCRIPT SYSBUILD) + +if(NOT signing_script) get_target_property(signing_script zephyr_property_target SIGNING_SCRIPT) - if(NOT signing_script) - set_target_properties(zephyr_property_target PROPERTIES SIGNING_SCRIPT ${CMAKE_CURRENT_LIST_DIR}/cmake/mcuboot.cmake) + + if(NOT signing_script AND CONFIG_BOOTLOADER_MCUBOOT) + set(signing_script ${CMAKE_CURRENT_LIST_DIR}/cmake/mcuboot.cmake) endif() endif() # Include signing script, if set -get_target_property(signing_script zephyr_property_target SIGNING_SCRIPT) if(signing_script) message(STATUS "Including signing script: ${signing_script}") From 605c854369146f21f4759450b21db663af5af586 Mon Sep 17 00:00:00 2001 From: Jamie McCrae Date: Mon, 29 Jan 2024 09:09:34 +0000 Subject: [PATCH 3424/3723] doc: release: 3.6: Add note on signing script addition Adds a note about how the signing script can be set Signed-off-by: Jamie McCrae --- doc/releases/release-notes-3.6.rst | 3 +++ 1 file changed, 3 insertions(+) diff --git a/doc/releases/release-notes-3.6.rst b/doc/releases/release-notes-3.6.rst index 4885510387f..23a03dd58e1 100644 --- a/doc/releases/release-notes-3.6.rst +++ b/doc/releases/release-notes-3.6.rst @@ -176,6 +176,9 @@ Build system and infrastructure After this change users may need to define them for their own applications or libraries if they require them. +* Added support for sysbuild setting a signing script (``SIGNING_SCRIPT``), see + :ref:`west-extending-signing` for details. + Drivers and Sensors ******************* From 1c70041dcb4c55166f77ac7b440b29f1f0007325 Mon Sep 17 00:00:00 2001 From: Jamie McCrae Date: Mon, 29 Jan 2024 09:14:02 +0000 Subject: [PATCH 3425/3723] doc: develop: west: sign: Add details on signing Adds details on how to do signing using sysbuild Signed-off-by: Jamie McCrae --- doc/develop/west/sign.rst | 19 +++++++++++++++++-- 1 file changed, 17 insertions(+), 2 deletions(-) diff --git a/doc/develop/west/sign.rst b/doc/develop/west/sign.rst index 8cc55ffeea4..ef98631be1c 100644 --- a/doc/develop/west/sign.rst +++ b/doc/develop/west/sign.rst @@ -100,8 +100,23 @@ The signing script used when running ``west flash`` can be extended or replaced to change features or introduce different signing mechanisms. By default with MCUboot enabled, signing is setup by the :file:`cmake/mcuboot.cmake` file in Zephyr which adds extra post build commands for generating the signed images. -The file used for signing can be replaced by adjusting the ``SIGNING_SCRIPT`` -property on the `zephyr_property_target`, ideally done by a module using: +The file used for signing can be replaced from a sysbuild scope (if being used) +or from a zephyr/zephyr module scope, the priority of which is: + +* Sysbuild +* Zephyr property +* Default MCUboot script (if enabled) + +From sysbuild, ``-D_SIGNING_SCRIPT`` can be used to set a signing script +for a specific image or ``-DSIGNING_SCRIPT`` can be used to set a signing script +for all images, for example: + +.. code-block:: console + + west build -b -DSIGNING_SCRIPT= + +The zephyr property method is achieved by adjusting the ``SIGNING_SCRIPT`` property +on the `zephyr_property_target`, ideally from by a module by using: .. code-block:: cmake From 139bc4e87e7c219fc9dc9b04a34a8cea13bb164e Mon Sep 17 00:00:00 2001 From: Robert Lubos Date: Wed, 31 Jan 2024 15:33:27 +0100 Subject: [PATCH 3426/3723] net: zperf: Fix UDP receiver start/stop operation This commit fixes restarting of UDP receiver service, along with some other minor cleanups: * The core issue was udp_server_running flag not being cleared when service was stopped. Fix this by introducing udp_receiver_cleanup() which does all of the required cleanups when receiver service is stopped. The function is called either when the application stopped the service with zperf_udp_download_stop(), or when the service was stopped due to error. * net_socket_service_unregister() was not called on zperf_udp_download_stop(), but only from the service callback - that would not work in case there's no active communication. * at the same time, net_socket_service_unregister() would be called from the service callback in case of errors. Fix this, by making udp_recv_data() only return an error, and let the service callback to do the cleanup. * Remove no longer used udp_server_run semaphore * Remove udp_server_stop - with socket services it seems no longer needed. * zperf_udp_receiver_init() now returns an error, so that we don't mark the service as running in case of socket/services error. Signed-off-by: Robert Lubos --- subsys/net/lib/zperf/zperf_udp_receiver.c | 72 ++++++++++++++--------- 1 file changed, 43 insertions(+), 29 deletions(-) diff --git a/subsys/net/lib/zperf/zperf_udp_receiver.c b/subsys/net/lib/zperf/zperf_udp_receiver.c index ba44590c621..64f489ed8dc 100644 --- a/subsys/net/lib/zperf/zperf_udp_receiver.c +++ b/subsys/net/lib/zperf/zperf_udp_receiver.c @@ -36,10 +36,8 @@ static struct sockaddr_in *in4_addr_my; static zperf_callback udp_session_cb; static void *udp_user_data; static bool udp_server_running; -static bool udp_server_stop; static uint16_t udp_server_port; static struct sockaddr udp_server_addr; -static K_SEM_DEFINE(udp_server_run, 0, 1); struct zsock_pollfd fds[SOCK_ID_MAX] = { 0 }; @@ -227,26 +225,45 @@ static void udp_received(int sock, const struct sockaddr *addr, uint8_t *data, } } +static void udp_receiver_cleanup(void) +{ + int i; + + (void)net_socket_service_unregister(&svc_udp); + + for (i = 0; i < ARRAY_SIZE(fds); i++) { + if (fds[i].fd >= 0) { + zsock_close(fds[i].fd); + fds[i].fd = -1; + } + } + + udp_server_running = false; + udp_session_cb = NULL; +} + static int udp_recv_data(struct net_socket_service_event *pev) { static uint8_t buf[UDP_RECEIVER_BUF_SIZE]; - int i, ret = 0; - int family; + int ret = 0; + int family, sock_error; struct sockaddr addr; socklen_t optlen = sizeof(int); socklen_t addrlen = sizeof(addr); - if (udp_server_stop) { - ret = -ENOENT; - goto cleanup; + if (!udp_server_running) { + return -ENOENT; } if ((pev->event.revents & ZSOCK_POLLERR) || (pev->event.revents & ZSOCK_POLLNVAL)) { (void)zsock_getsockopt(pev->event.fd, SOL_SOCKET, SO_DOMAIN, &family, &optlen); - NET_ERR("UDP receiver IPv%d socket error", - family == AF_INET ? 4 : 6); + (void)zsock_getsockopt(pev->event.fd, SOL_SOCKET, + SO_ERROR, &sock_error, &optlen); + NET_ERR("UDP receiver IPv%d socket error (%d)", + family == AF_INET ? 4 : 6, sock_error); + ret = -sock_error; goto error; } @@ -257,10 +274,11 @@ static int udp_recv_data(struct net_socket_service_event *pev) ret = zsock_recvfrom(pev->event.fd, buf, sizeof(buf), 0, &addr, &addrlen); if (ret < 0) { + ret = -errno; (void)zsock_getsockopt(pev->event.fd, SOL_SOCKET, SO_DOMAIN, &family, &optlen); NET_ERR("recv failed on IPv%d socket (%d)", - family == AF_INET ? 4 : 6, errno); + family == AF_INET ? 4 : 6, -ret); goto error; } @@ -273,16 +291,6 @@ static int udp_recv_data(struct net_socket_service_event *pev) udp_session_cb(ZPERF_SESSION_ERROR, NULL, udp_user_data); } -cleanup: - for (i = 0; i < ARRAY_SIZE(fds); i++) { - if (fds[i].fd >= 0) { - zsock_close(fds[i].fd); - fds[i].fd = -1; - } - } - - (void)net_socket_service_unregister(&svc_udp); - return ret; } @@ -294,11 +302,11 @@ static void udp_svc_handler(struct k_work *work) ret = udp_recv_data(pev); if (ret < 0) { - (void)net_socket_service_unregister(&svc_udp); + udp_receiver_cleanup(); } } -static void zperf_udp_receiver_init(void) +static int zperf_udp_receiver_init(void) { int ret; @@ -314,6 +322,7 @@ static void zperf_udp_receiver_init(void) fds[SOCK_ID_IPV4].fd = zsock_socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP); if (fds[SOCK_ID_IPV4].fd < 0) { + ret = -errno; NET_ERR("Cannot create IPv4 network socket."); goto error; } @@ -362,6 +371,7 @@ static void zperf_udp_receiver_init(void) fds[SOCK_ID_IPV6].fd = zsock_socket(AF_INET6, SOCK_DGRAM, IPPROTO_UDP); if (fds[SOCK_ID_IPV6].fd < 0) { + ret = -errno; NET_ERR("Cannot create IPv4 network socket."); goto error; } @@ -414,12 +424,15 @@ static void zperf_udp_receiver_init(void) } error: - return; + + return ret; } int zperf_udp_download(const struct zperf_download_params *param, zperf_callback callback, void *user_data) { + int ret; + if (param == NULL || callback == NULL) { return -EINVAL; } @@ -431,13 +444,15 @@ int zperf_udp_download(const struct zperf_download_params *param, udp_session_cb = callback; udp_user_data = user_data; udp_server_port = param->port; - udp_server_running = true; - udp_server_stop = false; memcpy(&udp_server_addr, ¶m->addr, sizeof(struct sockaddr)); - zperf_udp_receiver_init(); + ret = zperf_udp_receiver_init(); + if (ret < 0) { + udp_receiver_cleanup(); + return ret; + } - k_sem_give(&udp_server_run); + udp_server_running = true; return 0; } @@ -448,8 +463,7 @@ int zperf_udp_download_stop(void) return -EALREADY; } - udp_server_stop = true; - udp_session_cb = NULL; + udp_receiver_cleanup(); return 0; } From 4ce03520264d7bd135eb5eccf4fabe060e78e9ae Mon Sep 17 00:00:00 2001 From: Robert Lubos Date: Wed, 31 Jan 2024 15:58:20 +0100 Subject: [PATCH 3427/3723] net: zperf: Fix TCP receiver start/stop operation The issues found for UDP receiver were also identified for TCP receiver, this commit applies practically the same set of changes as in case of UDP. Signed-off-by: Robert Lubos --- subsys/net/lib/zperf/zperf_tcp_receiver.c | 73 +++++++++++++---------- 1 file changed, 43 insertions(+), 30 deletions(-) diff --git a/subsys/net/lib/zperf/zperf_tcp_receiver.c b/subsys/net/lib/zperf/zperf_tcp_receiver.c index c782124e36b..09624dd07b7 100644 --- a/subsys/net/lib/zperf/zperf_tcp_receiver.c +++ b/subsys/net/lib/zperf/zperf_tcp_receiver.c @@ -33,10 +33,8 @@ LOG_MODULE_DECLARE(net_zperf, CONFIG_NET_ZPERF_LOG_LEVEL); static zperf_callback tcp_session_cb; static void *tcp_user_data; static bool tcp_server_running; -static bool tcp_server_stop; static uint16_t tcp_server_port; static struct sockaddr tcp_server_addr; -static K_SEM_DEFINE(tcp_server_run, 0, 1); static struct zsock_pollfd fds[SOCK_ID_MAX]; static struct sockaddr sock_addr[SOCK_ID_MAX]; @@ -103,26 +101,46 @@ static void tcp_session_error_report(void) } } +static void tcp_receiver_cleanup(void) +{ + int i; + + (void)net_socket_service_unregister(&svc_tcp); + + for (i = 0; i < ARRAY_SIZE(fds); i++) { + if (fds[i].fd >= 0) { + zsock_close(fds[i].fd); + fds[i].fd = -1; + memset(&sock_addr[i], 0, sizeof(struct sockaddr)); + } + } + + tcp_server_running = false; + tcp_session_cb = NULL; +} + static int tcp_recv_data(struct net_socket_service_event *pev) { static uint8_t buf[TCP_RECEIVER_BUF_SIZE]; int i, ret = 0; - int family, sock; + int family, sock, sock_error; struct sockaddr addr_incoming_conn; socklen_t optlen = sizeof(int); socklen_t addrlen = sizeof(struct sockaddr); - if (tcp_server_stop) { - ret = -ENOENT; - goto cleanup; + if (!tcp_server_running) { + return -ENOENT; } if ((pev->event.revents & ZSOCK_POLLERR) || (pev->event.revents & ZSOCK_POLLNVAL)) { (void)zsock_getsockopt(pev->event.fd, SOL_SOCKET, SO_DOMAIN, &family, &optlen); - NET_ERR("TCP receiver IPv%d socket error", - family == AF_INET ? 4 : 6); + (void)zsock_getsockopt(pev->event.fd, SOL_SOCKET, + SO_ERROR, &sock_error, &optlen); + NET_ERR("TCP receiver IPv%d socket error (%d)", + family == AF_INET ? 4 : 6, sock_error); + ret = -sock_error; goto error; } @@ -140,10 +158,11 @@ static int tcp_recv_data(struct net_socket_service_event *pev) &addr_incoming_conn, &addrlen); if (sock < 0) { + ret = -errno; (void)zsock_getsockopt(pev->event.fd, SOL_SOCKET, SO_DOMAIN, &family, &optlen); - NET_ERR("TCP receiver IPv%d accept error", - family == AF_INET ? 4 : 6); + NET_ERR("TCP receiver IPv%d accept error (%d)", + family == AF_INET ? 4 : 6, ret); goto error; } @@ -207,17 +226,6 @@ static int tcp_recv_data(struct net_socket_service_event *pev) error: tcp_session_error_report(); -cleanup: - for (i = 0; i < ARRAY_SIZE(fds); i++) { - if (fds[i].fd >= 0) { - zsock_close(fds[i].fd); - fds[i].fd = -1; - memset(&sock_addr[i], 0, sizeof(struct sockaddr)); - } - } - - (void)net_socket_service_unregister(&svc_tcp); - return ret; } @@ -229,7 +237,7 @@ static void tcp_svc_handler(struct k_work *work) ret = tcp_recv_data(pev); if (ret < 0) { - (void)net_socket_service_unregister(&svc_tcp); + tcp_receiver_cleanup(); } } @@ -265,7 +273,7 @@ static int tcp_bind_listen_connection(struct zsock_pollfd *pollfd, return ret; } -static void zperf_tcp_receiver_init(void) +static int zperf_tcp_receiver_init(void) { int ret; @@ -280,6 +288,7 @@ static void zperf_tcp_receiver_init(void) fds[SOCK_ID_IPV4_LISTEN].fd = zsock_socket(AF_INET, SOCK_STREAM, IPPROTO_TCP); if (fds[SOCK_ID_IPV4_LISTEN].fd < 0) { + ret = -errno; NET_ERR("Cannot create IPv4 network socket."); goto error; } @@ -325,6 +334,7 @@ static void zperf_tcp_receiver_init(void) fds[SOCK_ID_IPV6_LISTEN].fd = zsock_socket(AF_INET6, SOCK_STREAM, IPPROTO_TCP); if (fds[SOCK_ID_IPV6_LISTEN].fd < 0) { + ret = -errno; NET_ERR("Cannot create IPv6 network socket."); goto error; } @@ -374,12 +384,14 @@ static void zperf_tcp_receiver_init(void) } error: - return; + return ret; } int zperf_tcp_download(const struct zperf_download_params *param, zperf_callback callback, void *user_data) { + int ret; + if (param == NULL || callback == NULL) { return -EINVAL; } @@ -391,13 +403,15 @@ int zperf_tcp_download(const struct zperf_download_params *param, tcp_session_cb = callback; tcp_user_data = user_data; tcp_server_port = param->port; - tcp_server_running = true; - tcp_server_stop = false; memcpy(&tcp_server_addr, ¶m->addr, sizeof(struct sockaddr)); - zperf_tcp_receiver_init(); + ret = zperf_tcp_receiver_init(); + if (ret < 0) { + tcp_receiver_cleanup(); + return ret; + } - k_sem_give(&tcp_server_run); + tcp_server_running = true; return 0; } @@ -408,8 +422,7 @@ int zperf_tcp_download_stop(void) return -EALREADY; } - tcp_server_stop = true; - tcp_session_cb = NULL; + tcp_receiver_cleanup(); return 0; } From 68bc981c523d085f5a705cfae63b95fc6b5015ca Mon Sep 17 00:00:00 2001 From: Robert Lubos Date: Wed, 31 Jan 2024 16:17:45 +0100 Subject: [PATCH 3428/3723] net: zperf: Fix session leak In case zperf session was aborted by the user (by for instance stopping it from shell), or practically in case of any other communication-related error, the zperf session could end up in a state other than NULL or COMPLETED, with no way to recover. This made the session no longer usable and eventually could lead to zperf being not able to start a new session anymore. Fix this by introducing zperf_session_reset() function, which resets the session state back to defaults. The function is called when the zperf receiver service is stopped. Signed-off-by: Robert Lubos --- subsys/net/lib/zperf/zperf_session.c | 23 ++++++++++++++++++----- subsys/net/lib/zperf/zperf_session.h | 2 ++ subsys/net/lib/zperf/zperf_tcp_receiver.c | 2 ++ subsys/net/lib/zperf/zperf_udp_receiver.c | 2 ++ 4 files changed, 24 insertions(+), 5 deletions(-) diff --git a/subsys/net/lib/zperf/zperf_session.c b/subsys/net/lib/zperf/zperf_session.c index 3b72367e179..6fff4abf9cc 100644 --- a/subsys/net/lib/zperf/zperf_session.c +++ b/subsys/net/lib/zperf/zperf_session.c @@ -102,14 +102,27 @@ void zperf_reset_session_stats(struct session *session) session->last_transit_time = 0; } -void zperf_session_init(void) +void zperf_session_reset(enum session_proto proto) { int i, j; + if (proto >= SESSION_PROTO_END) { + return; + } + + i = (int)proto; + + for (j = 0; j < SESSION_MAX; j++) { + sessions[i][j].state = STATE_NULL; + zperf_reset_session_stats(&(sessions[i][j])); + } +} + +void zperf_session_init(void) +{ + int i; + for (i = 0; i < SESSION_PROTO_END; i++) { - for (j = 0; j < SESSION_MAX; j++) { - sessions[i][j].state = STATE_NULL; - zperf_reset_session_stats(&(sessions[i][j])); - } + zperf_session_reset(i); } } diff --git a/subsys/net/lib/zperf/zperf_session.h b/subsys/net/lib/zperf/zperf_session.h index ea28dec2c60..f01bc66b71a 100644 --- a/subsys/net/lib/zperf/zperf_session.h +++ b/subsys/net/lib/zperf/zperf_session.h @@ -58,5 +58,7 @@ struct session *get_session(const struct sockaddr *addr, enum session_proto proto); void zperf_session_init(void); void zperf_reset_session_stats(struct session *session); +/* Reset all sessions for a given protocol. */ +void zperf_session_reset(enum session_proto proto); #endif /* __ZPERF_SESSION_H */ diff --git a/subsys/net/lib/zperf/zperf_tcp_receiver.c b/subsys/net/lib/zperf/zperf_tcp_receiver.c index 09624dd07b7..3efd3ff630b 100644 --- a/subsys/net/lib/zperf/zperf_tcp_receiver.c +++ b/subsys/net/lib/zperf/zperf_tcp_receiver.c @@ -117,6 +117,8 @@ static void tcp_receiver_cleanup(void) tcp_server_running = false; tcp_session_cb = NULL; + + zperf_session_reset(SESSION_TCP); } static int tcp_recv_data(struct net_socket_service_event *pev) diff --git a/subsys/net/lib/zperf/zperf_udp_receiver.c b/subsys/net/lib/zperf/zperf_udp_receiver.c index 64f489ed8dc..ae1ac063300 100644 --- a/subsys/net/lib/zperf/zperf_udp_receiver.c +++ b/subsys/net/lib/zperf/zperf_udp_receiver.c @@ -240,6 +240,8 @@ static void udp_receiver_cleanup(void) udp_server_running = false; udp_session_cb = NULL; + + zperf_session_reset(SESSION_UDP); } static int udp_recv_data(struct net_socket_service_event *pev) From 34cb22e9192fd77e279780f54610b6ba9ea760d6 Mon Sep 17 00:00:00 2001 From: Juliane Schulze Date: Thu, 14 Dec 2023 16:11:04 +0100 Subject: [PATCH 3429/3723] sensors: Add driver for Vischay VCNL36825T Proximity Sensor Driver for the Vishay VCNL36825T including power management support. Signed-off-by: Juliane Schulze --- drivers/sensor/CMakeLists.txt | 1 + drivers/sensor/Kconfig | 1 + drivers/sensor/vcnl36825t/CMakeLists.txt | 6 + drivers/sensor/vcnl36825t/Kconfig | 12 + drivers/sensor/vcnl36825t/vcnl36825t.c | 478 +++++++++++++++++++++ drivers/sensor/vcnl36825t/vcnl36825t.h | 298 +++++++++++++ dts/bindings/sensor/vishay,vcnl36825t.yaml | 90 ++++ tests/drivers/build_all/sensor/i2c.dtsi | 10 + 8 files changed, 896 insertions(+) create mode 100644 drivers/sensor/vcnl36825t/CMakeLists.txt create mode 100644 drivers/sensor/vcnl36825t/Kconfig create mode 100644 drivers/sensor/vcnl36825t/vcnl36825t.c create mode 100644 drivers/sensor/vcnl36825t/vcnl36825t.h create mode 100644 dts/bindings/sensor/vishay,vcnl36825t.yaml diff --git a/drivers/sensor/CMakeLists.txt b/drivers/sensor/CMakeLists.txt index effdf205427..dd77976c086 100644 --- a/drivers/sensor/CMakeLists.txt +++ b/drivers/sensor/CMakeLists.txt @@ -158,6 +158,7 @@ add_subdirectory_ifdef(CONFIG_TSL2540 tsl2540) add_subdirectory_ifdef(CONFIG_TSL2561 tsl2561) add_subdirectory_ifdef(CONFIG_VCMP_IT8XXX2 ite_vcmp_it8xxx2) add_subdirectory_ifdef(CONFIG_VCNL4040 vcnl4040) +add_subdirectory_ifdef(CONFIG_VCNL36825T vcnl36825t) add_subdirectory_ifdef(CONFIG_VEML7700 veml7700) add_subdirectory_ifdef(CONFIG_VL53L0X vl53l0x) add_subdirectory_ifdef(CONFIG_VL53L1X vl53l1x) diff --git a/drivers/sensor/Kconfig b/drivers/sensor/Kconfig index c3b682175c8..c27b3906405 100644 --- a/drivers/sensor/Kconfig +++ b/drivers/sensor/Kconfig @@ -237,6 +237,7 @@ source "drivers/sensor/tmp116/Kconfig" source "drivers/sensor/tsl2540/Kconfig" source "drivers/sensor/tsl2561/Kconfig" source "drivers/sensor/vcnl4040/Kconfig" +source "drivers/sensor/vcnl36825t/Kconfig" source "drivers/sensor/veml7700/Kconfig" source "drivers/sensor/vl53l0x/Kconfig" source "drivers/sensor/vl53l1x/Kconfig" diff --git a/drivers/sensor/vcnl36825t/CMakeLists.txt b/drivers/sensor/vcnl36825t/CMakeLists.txt new file mode 100644 index 00000000000..cbf96f6d2b7 --- /dev/null +++ b/drivers/sensor/vcnl36825t/CMakeLists.txt @@ -0,0 +1,6 @@ +# Copyright (c) 2024 Juliane Schulze, deveritec Gmbh +# SPDX-License-Identifier: Apache-2.0 + +zephyr_library() + +zephyr_library_sources(vcnl36825t.c) diff --git a/drivers/sensor/vcnl36825t/Kconfig b/drivers/sensor/vcnl36825t/Kconfig new file mode 100644 index 00000000000..46d20598af4 --- /dev/null +++ b/drivers/sensor/vcnl36825t/Kconfig @@ -0,0 +1,12 @@ +# VCNL36825T Proximity Sensor configuration options + +# Copyright (c) 2024 Juliane Schulze, deveritec Gmbh +# SPDX-License-Identifier: Apache-2.0 + +config VCNL36825T + bool "VCNL36825T Proximity Sensor" + default y + depends on DT_HAS_VISHAY_VCNL36825T_ENABLED + select I2C + help + Enable driver for VCNL36825T sensors. diff --git a/drivers/sensor/vcnl36825t/vcnl36825t.c b/drivers/sensor/vcnl36825t/vcnl36825t.c new file mode 100644 index 00000000000..940943950a4 --- /dev/null +++ b/drivers/sensor/vcnl36825t/vcnl36825t.c @@ -0,0 +1,478 @@ +/* + * Copyright (c) 2024 Juliane Schulze, deveritec GmbH + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#define DT_DRV_COMPAT vishay_vcnl36825t + +#include "vcnl36825t.h" + +#include + +#include +#include +#include +#include +#include + +LOG_MODULE_REGISTER(VCNL36825T, CONFIG_SENSOR_LOG_LEVEL); + +static int vcnl36825t_read(const struct i2c_dt_spec *spec, uint8_t reg_addr, uint16_t *value) +{ + uint8_t rx_buf[2]; + int rc; + + rc = i2c_write_read_dt(spec, ®_addr, sizeof(reg_addr), rx_buf, sizeof(rx_buf)); + if (rc < 0) { + return rc; + } + + *value = sys_get_le16(rx_buf); + + return 0; +} + +static int vcnl36825t_write(const struct i2c_dt_spec *spec, uint8_t reg_addr, uint16_t value) +{ + uint8_t tx_buf[3] = {reg_addr}; + + sys_put_le16(value, &tx_buf[1]); + return i2c_write_dt(spec, tx_buf, sizeof(tx_buf)); +} + +static int vcnl36825t_update(const struct i2c_dt_spec *spec, uint8_t reg_addr, uint16_t mask, + uint16_t value) +{ + int rc; + uint16_t old_value, new_value; + + rc = vcnl36825t_read(spec, reg_addr, &old_value); + if (rc < 0) { + return rc; + } + + new_value = (old_value & ~mask) | (value & mask); + + if (new_value == old_value) { + return 0; + } + + return vcnl36825t_write(spec, reg_addr, new_value); +} + +#if CONFIG_PM_DEVICE +static int vcnl36825t_pm_action(const struct device *dev, enum pm_device_action action) +{ + const struct vcnl36825t_config *config = dev->config; + int rc = 0; + + switch (action) { + case PM_DEVICE_ACTION_RESUME: + rc = vcnl36825t_update(&config->i2c, VCNL36825T_REG_PS_CONF1, VCNL36825T_PS_ON_MSK, + VCNL36825T_PS_ON); + if (rc < 0) { + return rc; + } + + rc = vcnl36825t_update(&config->i2c, VCNL36825T_REG_PS_CONF2, VCNL36825T_PS_ST_MSK, + VCNL36825T_PS_ST_START); + if (rc < 0) { + return rc; + } + break; + case PM_DEVICE_ACTION_SUSPEND: + rc = vcnl36825t_update(&config->i2c, VCNL36825T_REG_PS_CONF2, VCNL36825T_PS_ST_MSK, + VCNL36825T_PS_ST_STOP); + if (rc < 0) { + return rc; + } + + rc = vcnl36825t_update(&config->i2c, VCNL36825T_REG_PS_CONF1, VCNL36825T_PS_ON_MSK, + VCNL36825T_PS_OFF); + if (rc < 0) { + return rc; + } + break; + default: + LOG_ERR("action %d not supported", (int)action); + return -ENOTSUP; + } + + return 0; +} + +#endif + +static int vcnl36825t_sample_fetch(const struct device *dev, enum sensor_channel chan) +{ + const struct vcnl36825t_config *config = dev->config; + struct vcnl36825t_data *data = dev->data; + int rc; + +#if CONFIG_PM_DEVICE + enum pm_device_state state; + + (void)pm_device_state_get(dev, &state); + if (state != PM_DEVICE_STATE_ACTIVE) { + return -EBUSY; + } +#endif + + switch (chan) { + case SENSOR_CHAN_ALL: + case SENSOR_CHAN_PROX: + if (config->operation_mode == VCNL36825T_OPERATION_MODE_FORCE) { + rc = vcnl36825t_update(&config->i2c, VCNL36825T_REG_PS_CONF3, + VCNL36825T_PS_TRIG_MSK, VCNL36825T_PS_TRIG_ONCE); + if (rc < 0) { + LOG_ERR("could not trigger proximity measurement %d", rc); + return rc; + } + + k_usleep(data->meas_timeout_us); + } + + rc = vcnl36825t_read(&config->i2c, VCNL36825T_REG_PS_DATA, &data->proximity); + if (rc < 0) { + LOG_ERR("could not fetch proximity measurement %d", rc); + return rc; + } + + break; + default: + LOG_ERR("invalid sensor channel"); + return -EINVAL; + } + + return 0; +} + +static int vcnl36825t_channel_get(const struct device *dev, enum sensor_channel chan, + struct sensor_value *val) +{ + struct vcnl36825t_data *data = dev->data; + + switch (chan) { + case SENSOR_CHAN_ALL: + case SENSOR_CHAN_PROX: + val->val1 = data->proximity & VCNL36825T_OS_DATA_MSK; + val->val2 = 0; + break; + default: + return -ENOTSUP; + } + + return 0; +} + +/** + * @brief helper function to configure the registers + * + * @param dev pointer to the VCNL36825T instance + */ +static int vcnl36825t_init_registers(const struct device *dev) +{ + const struct vcnl36825t_config *config = dev->config; + struct vcnl36825t_data *data = dev->data; + + int rc; + uint16_t reg_value; + + /* reset registers as defined by the datasheet */ + const uint16_t resetValues[][2] = { + {VCNL36825T_REG_PS_CONF1, VCNL36825T_CONF1_DEFAULT}, + {VCNL36825T_REG_PS_CONF2, VCNL36825T_CONF2_DEFAULT}, + {VCNL36825T_REG_PS_CONF3, VCNL36825T_CONF3_DEFAULT}, + {VCNL36825T_REG_PS_THDL, VCNL36825T_THDL_DEFAULT}, + {VCNL36825T_REG_PS_THDH, VCNL36825T_THDH_DEFAULT}, + {VCNL36825T_REG_PS_CANC, VCNL36825T_CANC_DEFAULT}, + {VCNL36825T_REG_PS_CONF4, VCNL36825T_CONF4_DEFAULT}, + }; + + for (size_t i = 0; i < ARRAY_SIZE(resetValues); ++i) { + vcnl36825t_write(&config->i2c, resetValues[i][0], resetValues[i][1]); + } + + data->meas_timeout_us = 1; + + /* PS_CONF1 */ + reg_value = 0x01; /* must be set according to datasheet */ + reg_value |= VCNL36825T_PS_ON; + + rc = vcnl36825t_write(&config->i2c, VCNL36825T_REG_PS_CONF1, reg_value); + if (rc < 0) { + LOG_ERR("I2C for PS_ON returned %d", rc); + return -EIO; + } + + reg_value |= VCNL36825T_PS_CAL; + reg_value |= FIELD_PREP(1 << 9, 1); /* reserved, must be set by datasheet */ + + rc = vcnl36825t_write(&config->i2c, VCNL36825T_REG_PS_CONF1, reg_value); + if (rc < 0) { + LOG_ERR("I2C for PS_CAL returned %d", rc); + } + + /* PS_CONF2 */ + reg_value = 0; + + switch (config->period) { + case VCNL36825T_MEAS_PERIOD_10MS: + reg_value |= VCNL36825T_PS_PERIOD_10MS; + break; + case VCNL36825T_MEAS_PERIOD_20MS: + reg_value |= VCNL36825T_PS_PERIOD_20MS; + break; + case VCNL36825T_MEAS_PERIOD_40MS: + reg_value |= VCNL36825T_PS_PERIOD_40MS; + break; + case VCNL36825T_MEAS_PERIOD_80MS: + __fallthrough; + default: + reg_value |= VCNL36825T_PS_PERIOD_80MS; + break; + } + + reg_value |= VCNL36825T_PS_PERS_1; + reg_value |= VCNL36825T_PS_ST_STOP; + + switch (config->proximity_it) { + case VCNL36825T_PROXIMITY_INTEGRATION_1T: + reg_value |= VCNL36825T_PS_IT_1T; + data->meas_timeout_us *= 1 * VCNL36825T_FORCED_FACTOR_SCALE; + break; + case VCNL36825T_PROXIMITY_INTEGRATION_1_5T: + reg_value |= VCNL36825T_PS_IT_1_5T; + data->meas_timeout_us *= 1.5 * VCNL36825T_FORCED_FACTOR_SCALE; + break; + case VCNL36825T_PROXIMITY_INTEGRATION_2T: + reg_value |= VCNL36825T_PS_IT_2T; + data->meas_timeout_us *= 2 * VCNL36825T_FORCED_FACTOR_SCALE; + break; + case VCNL36825T_PROXIMITY_INTEGRATION_2_5T: + reg_value |= VCNL36825T_PS_IT_2_5T; + data->meas_timeout_us *= 2.5 * VCNL36825T_FORCED_FACTOR_SCALE; + break; + case VCNL36825T_PROXIMITY_INTEGRATION_3T: + reg_value |= VCNL36825T_PS_IT_3T; + data->meas_timeout_us *= 3 * VCNL36825T_FORCED_FACTOR_SCALE; + break; + case VCNL36825T_PROXIMITY_INTEGRATION_3_5T: + reg_value |= VCNL36825T_PS_IT_3_5T; + data->meas_timeout_us *= 3.5 * VCNL36825T_FORCED_FACTOR_SCALE; + break; + case VCNL36825T_PROXIMITY_INTEGRATION_4T: + reg_value |= VCNL36825T_PS_IT_4T; + data->meas_timeout_us *= 4 * VCNL36825T_FORCED_FACTOR_SCALE; + break; + case VCNL36825T_PROXIMITY_INTEGRATION_8T: + __fallthrough; + default: + reg_value |= VCNL36825T_PS_IT_8T; + data->meas_timeout_us *= 8 * VCNL36825T_FORCED_FACTOR_SCALE; + break; + } + + switch (config->multi_pulse) { + case VCNL38652T_MULTI_PULSE_1: + reg_value |= VCNL36825T_MPS_PULSES_1; + break; + case VCNL38652T_MULTI_PULSE_2: + reg_value |= VCNL36825T_MPS_PULSES_2; + break; + case VCNL38652T_MULTI_PULSE_4: + reg_value |= VCNL36825T_MPS_PULSES_4; + break; + case VCNL38652T_MULTI_PULSE_8: + __fallthrough; + default: + reg_value |= VCNL36825T_MPS_PULSES_8; + break; + } + + switch (config->proximity_itb) { + case VCNL36825T_PROXIMITY_INTEGRATION_DURATION_25us: + reg_value |= VCNL36825T_PS_ITB_25us; + data->meas_timeout_us *= 25; + break; + case VCNL36825T_PROXIMITY_INTEGRATION_DURATION_50us: + __fallthrough; + default: + reg_value |= VCNL36825T_PS_ITB_50us; + data->meas_timeout_us *= 50; + break; + } + + if (config->high_gain) { + reg_value |= VCNL36825T_PS_HG_HIGH; + } + + rc = vcnl36825t_write(&config->i2c, VCNL36825T_REG_PS_CONF2, reg_value); + if (rc < 0) { + LOG_ERR("I2C for setting PS_CONF2 returned %d", rc); + return -EIO; + } + + /* PS_CONF3 */ + reg_value = 0; + + if (config->operation_mode == VCNL36825T_OPERATION_MODE_FORCE) { + reg_value |= VCNL36825T_PS_AF_FORCE; + } + + switch (config->laser_current) { + case VCNL36825T_LASER_CURRENT_10MS: + reg_value |= VCNL36825T_PS_I_VCSEL_10MA; + break; + case VCNL36825T_LASER_CURRENT_12MS: + reg_value |= VCNL36825T_PS_I_VCSEL_12MA; + break; + case VCNL36825T_LASER_CURRENT_14MS: + reg_value |= VCNL36825T_PS_I_VCSEL_14MA; + break; + case VCNL36825T_LASER_CURRENT_16MS: + reg_value |= VCNL36825T_PS_I_VCSEL_16MA; + break; + case VCNL36825T_LASER_CURRENT_18MS: + reg_value |= VCNL36825T_PS_I_VCSEL_18MA; + break; + case VCNL36825T_LASER_CURRENT_20MS: + __fallthrough; + default: + reg_value |= VCNL36825T_PS_I_VCSEL_20MA; + break; + } + + if (config->high_dynamic_output) { + reg_value |= VCNL36825T_PS_HD_16BIT; + } + + if (config->sunlight_cancellation) { + reg_value |= VCNL36825T_PS_SC_ENABLED; + } + + rc = vcnl36825t_write(&config->i2c, VCNL36825T_REG_PS_CONF3, reg_value); + if (rc < 0) { + LOG_ERR("I2C for setting PS_CONF3 returned %d", rc); + return -EIO; + } + + /* PS_CONF4 */ + reg_value = 0; + + if (config->low_power) { + reg_value |= VCNL36825T_PS_LPEN_ENABLED; + } + + switch (config->period) { + case VCNL36825T_MEAS_PERIOD_40MS: + reg_value |= VCNL36825T_PS_LPPER_40MS; + break; + case VCNL36825T_MEAS_PERIOD_80MS: + reg_value |= VCNL36825T_PS_LPPER_80MS; + break; + case VCNL36825T_MEAS_PERIOD_160MS: + reg_value |= VCNL36825T_PS_LPPER_160MS; + break; + case VCNL36825T_MEAS_PERIOD_320MS: + __fallthrough; + default: + reg_value |= VCNL36825T_PS_LPPER_320MS; + break; + } + + rc = vcnl36825t_write(&config->i2c, VCNL36825T_REG_PS_CONF4, reg_value); + if (rc < 0) { + LOG_ERR("I2C for setting PS_CONF4 returned %d", rc); + return -EIO; + } + + /* calculate measurement timeout + * Note: always add 1 to prevent corner case losses due to precision. + */ + data->meas_timeout_us = + (data->meas_timeout_us * VCNL36825T_FORCED_FACTOR_SUM) / + (VCNL36825T_FORCED_FACTOR_SCALE * VCNL36825T_FORCED_FACTOR_SCALE) + + 1; + + return 0; +} + +static int vcnl36825t_init(const struct device *dev) +{ + const struct vcnl36825t_config *config = dev->config; + int rc; + uint16_t reg_value; + + if (!i2c_is_ready_dt(&config->i2c)) { + LOG_ERR("device is not ready"); + return -ENODEV; + } + + rc = vcnl36825t_read(&config->i2c, VCNL36825T_REG_DEV_ID, ®_value); + if (rc < 0) { + LOG_ERR("could not read device id"); + return rc; + } + + if ((reg_value & VCNL36825T_ID_MSK) != VCNL36825T_DEVICE_ID) { + LOG_ERR("incorrect device id (%d)", reg_value); + return -EIO; + } + + LOG_INF("version code: 0x%X", + (unsigned int)FIELD_GET(VCNL36825T_VERSION_CODE_MSK, reg_value)); + + rc = vcnl36825t_init_registers(dev); + if (rc < 0) { + return rc; + } + + if (config->operation_mode == VCNL36825T_OPERATION_MODE_AUTO) { + rc = vcnl36825t_update(&config->i2c, VCNL36825T_REG_PS_CONF2, VCNL36825T_PS_ST_MSK, + VCNL36825T_PS_ST_START); + if (rc < 0) { + LOG_ERR("error starting measurement"); + return -EIO; + } + } + + return 0; +} + +static const struct sensor_driver_api vcnl36825t_driver_api = { + .sample_fetch = vcnl36825t_sample_fetch, + .channel_get = vcnl36825t_channel_get, +}; + +#define VCNL36825T_DEFINE(inst) \ + BUILD_ASSERT(!DT_INST_PROP(inst, low_power) || (DT_INST_PROP(inst, measurement_period) >= \ + VCNL36825T_PS_LPPER_VALUE_MIN_MS), \ + "measurement-period must be greater/equal 40 ms in low-power mode"); \ + BUILD_ASSERT( \ + DT_INST_PROP(inst, low_power) || (DT_INST_PROP(inst, measurement_period) <= \ + VCNL36825T_PS_PERIOD_VALUE_MAX_MS), \ + "measurement-period must be less/equal 80 ms with deactivated low-power mode"); \ + static struct vcnl36825t_data vcnl36825t_data_##inst; \ + static const struct vcnl36825t_config vcnl36825t_config_##inst = { \ + .i2c = I2C_DT_SPEC_INST_GET(inst), \ + .operation_mode = DT_INST_ENUM_IDX(inst, operation_mode), \ + .period = DT_INST_ENUM_IDX(inst, measurement_period), \ + .proximity_it = DT_INST_ENUM_IDX(inst, proximity_it), \ + .proximity_itb = DT_INST_ENUM_IDX(inst, proximity_itb), \ + .multi_pulse = DT_INST_ENUM_IDX(inst, multi_pulse), \ + .low_power = DT_INST_PROP(inst, low_power), \ + .high_gain = DT_INST_PROP(inst, high_gain), \ + .laser_current = DT_INST_ENUM_IDX(inst, laser_current), \ + .high_dynamic_output = DT_INST_PROP(inst, high_dynamic_output), \ + .sunlight_cancellation = DT_INST_PROP(inst, sunlight_cancellation), \ + }; \ + IF_ENABLED(CONFIG_PM_DEVICE, (PM_DEVICE_DT_INST_DEFINE(inst, vcnl36825t_pm_action))); \ + SENSOR_DEVICE_DT_INST_DEFINE( \ + inst, vcnl36825t_init, \ + COND_CODE_1(CONFIG_PM_DEVICE, (PM_DEVICE_DT_INST_GET(inst)), (NULL)), \ + &vcnl36825t_data_##inst, &vcnl36825t_config_##inst, POST_KERNEL, \ + CONFIG_SENSOR_INIT_PRIORITY, &vcnl36825t_driver_api); + +DT_INST_FOREACH_STATUS_OKAY(VCNL36825T_DEFINE) diff --git a/drivers/sensor/vcnl36825t/vcnl36825t.h b/drivers/sensor/vcnl36825t/vcnl36825t.h new file mode 100644 index 00000000000..8c022b34d2d --- /dev/null +++ b/drivers/sensor/vcnl36825t/vcnl36825t.h @@ -0,0 +1,298 @@ +/* + * Copyright (c) 2024 Juliane Schulze, deveritec GmbH + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#ifndef ZEPHYR_DRIVERS_SENSOR_VCNL36825T_VCNL36825T_H_ +#define ZEPHYR_DRIVERS_SENSOR_VCNL36825T_VCNL36825T_H_ + +#include +#include +#include +#include +#include + +#define VCNL36825T_REG_PS_CONF1 0x00 +#define VCNL36825T_REG_PS_CONF2 0x03 +#define VCNL36825T_REG_PS_CONF3 0x04 +#define VCNL36825T_REG_PS_THDL 0x05 +#define VCNL36825T_REG_PS_THDH 0x06 +#define VCNL36825T_REG_PS_CANC 0x07 +#define VCNL36825T_REG_PS_CONF4 0x08 +#define VCNL36825T_REG_PS_DATA 0xF8 +#define VCNL36825T_REG_INT_FLAG 0xF9 +#define VCNL36825T_REG_DEV_ID 0xFA +#define VCNL36825T_REG_PS_AC_DATA 0xFB + +/* default values */ +#define VCNL36825T_CONF1_DEFAULT 0x0001 +#define VCNL36825T_CONF2_DEFAULT 0x0000 +#define VCNL36825T_CONF3_DEFAULT 0x0000 +#define VCNL36825T_THDL_DEFAULT 0x0000 +#define VCNL36825T_THDH_DEFAULT 0x0000 +#define VCNL36825T_CANC_DEFAULT 0x0000 +#define VCNL36825T_CONF4_DEFAULT 0x0000 + +/* PS_CONF1 */ +#define VCNL36825T_PS_ON_POS 1 +#define VCNL36825T_PS_CAL_POS 7 + +#define VCNL36825T_PS_ON_MSK GENMASK(1, 1) + +#define VCNL36825T_PS_ON (1 << VCNL36825T_PS_ON_POS) +#define VCNL36825T_PS_OFF (0 << VCNL36825T_PS_ON_POS) + +#define VCNL36825T_PS_CAL (1 << VCNL36825T_PS_CAL_POS) + +/* PS_CONF2 */ +#define VCNL36825T_PS_ST_POS 0 +#define VCNL36825T_PS_PS_SMART_PERS_POS 1 +#define VCNL36825T_PS_INT_POS 2 +#define VCNL36825T_PS_PERS_POS 4 +#define VCNL36825T_PS_PERIOD_POS 6 +#define VCNL36825T_PS_HG_POS 10 +#define VCNL36825T_PS_ITB_POS 11 +#define VCNL36825T_PS_MPS_POS 12 +#define VCNL36825T_PS_IT_POS 14 + +#define VCNL36825T_PS_ST_MSK GENMASK(0, 0) + +#define VCNL36825T_PS_ST_START (0 << VCNL36825T_PS_ST_POS) +#define VCNL36825T_PS_ST_STOP (1 << VCNL36825T_PS_ST_POS) + +#define VCNL36825T_PS_SMART_PERS_DISABLED (0 << VCNL36825T_PS_PS_SMART_PERS_POS) +#define VCNL36825T_PS_SMART_PERS_ENABLED (1 << VCNL36825T_PS_PS_SMART_PERS_POS) + +#define VCNL36825T_PS_INT_DISABLE (0 << VCNL36825T_PS_INT_POS) +#define VCNL36825T_PS_INT_THDH_PERS_LATCHED (1 << VCNL36825T_PS_INT_POS) +#define VCNL36825T_PS_INT_THDH_FIRST_LATCHED (2 << VCNL36825T_PS_INT_POS) +#define VCNL36825T_PS_INT_ENABLED (3 << VCNL36825T_PS_INT_POS) + +#define VCNL36825T_PS_PERS_1 (0 << VCNL36825T_PS_PERS_POS) +#define VCNL36825T_PS_PERS_2 (1 << VCNL36825T_PS_PERS_POS) +#define VCNL36825T_PS_PERS_3 (2 << VCNL36825T_PS_PERS_POS) +#define VCNL36825T_PS_PERS_4 (3 << VCNL36825T_PS_PERS_POS) + +#define VCNL36825T_PS_PERIOD_10MS (0 << VCNL36825T_PS_PERIOD_POS) +#define VCNL36825T_PS_PERIOD_20MS (1 << VCNL36825T_PS_PERIOD_POS) +#define VCNL36825T_PS_PERIOD_40MS (2 << VCNL36825T_PS_PERIOD_POS) +#define VCNL36825T_PS_PERIOD_80MS (3 << VCNL36825T_PS_PERIOD_POS) + +#define VCNL36825T_PS_HG_LOW (0 << VCNL36825T_PS_HG_POS) +#define VCNL36825T_PS_HG_HIGH (1 << VCNL36825T_PS_HG_POS) + +#define VCNL36825T_PS_ITB_25us (0 << VCNL36825T_PS_ITB_POS) +#define VCNL36825T_PS_ITB_50us (1 << VCNL36825T_PS_ITB_POS) + +#define VCNL36825T_MPS_PULSES_1 (0 << VCNL36825T_PS_MPS_POS) +#define VCNL36825T_MPS_PULSES_2 (1 << VCNL36825T_PS_MPS_POS) +#define VCNL36825T_MPS_PULSES_4 (2 << VCNL36825T_PS_MPS_POS) +#define VCNL36825T_MPS_PULSES_8 (4 << VCNL36825T_PS_MPS_POS) + +#define VCNL36825T_PS_IT_1T (0 << VCNL36825T_PS_IT_POS) +#define VCNL36825T_PS_IT_1_5T (1 << VCNL36825T_PS_IT_POS) +#define VCNL36825T_PS_IT_2T (2 << VCNL36825T_PS_IT_POS) +#define VCNL36825T_PS_IT_2_5T (3 << VCNL36825T_PS_IT_POS) +#define VCNL36825T_PS_IT_3T (4 << VCNL36825T_PS_IT_POS) +#define VCNL36825T_PS_IT_3_5T (5 << VCNL36825T_PS_IT_POS) +#define VCNL36825T_PS_IT_4T (6 << VCNL36825T_PS_IT_POS) +#define VCNL36825T_PS_IT_8T (7 << VCNL36825T_PS_IT_POS) + +/* PS_CONF3 */ +#define VCNL36825T_PS_SP_INT_POS 2 +#define VCNL36825T_PS_FORCENUM_POS 4 +#define VCNL36825T_PS_TRIG_POS 5 +#define VCNL36825T_PS_AF_POS 6 +#define VCNL36825T_PS_I_VCSEL_POS 8 +#define VCNL36825T_PS_HD_POS 12 +#define VCNL36825T_PS_SC_POS 13 + +#define VCNL36825T_PS_TRIG_MSK GENMASK(5, 5) + +#define VCNL36825T_PS_SP_INT_DISABLED (0 << VCNL36825T_PS_SP_INT_POS) +#define VCNL36825T_PS_SP_INT_ENABLED (1 << VCNL36825T_PS_SP_INT_POS) + +#define VCNL36825T_PS_FORCENUM_ONE_CYCLE (0 << VCNL36825T_PS_FORCENUM_POS) +#define VCNL36825T_PS_FORCENUM_TWO_CYCLES (1 << VCNL36825T_PS_FORCENUM_POS) + +#define VCNL36825T_PS_TRIG_NONE (0 << VCNL36825T_PS_TRIG_POS) +#define VCNL36825T_PS_TRIG_ONCE (1 << VCNL36825T_PS_TRIG_POS) + +#define VCNL36825T_PS_AF_AUTO (0 << VCNL36825T_PS_AF_POS) +#define VCNL36825T_PS_AF_FORCE (1 << VCNL36825T_PS_AF_POS) + +#define VCNL36825T_PS_I_VCSEL_10MA (2 << VCNL36825T_PS_I_VCSEL_POS) +#define VCNL36825T_PS_I_VCSEL_12MA (3 << VCNL36825T_PS_I_VCSEL_POS) +#define VCNL36825T_PS_I_VCSEL_14MA (4 << VCNL36825T_PS_I_VCSEL_POS) +#define VCNL36825T_PS_I_VCSEL_16MA (5 << VCNL36825T_PS_I_VCSEL_POS) +#define VCNL36825T_PS_I_VCSEL_18MA (6 << VCNL36825T_PS_I_VCSEL_POS) +#define VCNL36825T_PS_I_VCSEL_20MA (7 << VCNL36825T_PS_I_VCSEL_POS) + +#define VCNL36825T_PS_HD_12BIT (0 << VCNL36825T_PS_HD_POS) +#define VCNL36825T_PS_HD_16BIT (1 << VCNL36825T_PS_HD_POS) + +#define VCNL36825T_PS_SC_DISABLED (0 << VCNL36825T_PS_SC_POS) +#define VCNL36825T_PS_SC_ENABLED (7 << VCNL36825T_PS_SC_POS) + +/* PS CONF4 */ +#define VCNL36825T_PS_AC_INT_POS 0 +#define VCNL36825T_PS_AC_TRIG_POS 2 +#define VCNL36825T_PS_AC_POS 3 +#define VCNL36825T_PS_AC_NUM_POS 4 +#define VCNL36825T_PS_AC_PERIOD_POS 6 +#define VCNL36825T_PS_LPEN_POS 8 +#define VCNL36825T_PS_LPPER_POS 9 + +#define VCNL36825T_PS_AC_INT_DISABLED (0 << VCNL36825T_PS_AC_INT_POS) +#define VCNL36825T_PS_AC_INT_ENABLED (1 << VCNL36825T_PS_AC_INT_POS) + +#define VCNL36825T_PS_AC_TRIG_DISABLED (0 << VCNL36825T_PS_AC_TRIG_POS) +#define VCNL36825T_PS_AC_TRIG_ONCE (1 << VCNL36825T_PS_AC_TRIG_POS) + +#define VCNL36825T_PS_AC_DISABLED (0 << VCNL36825T_PS_AC_POS) +#define VCNL36825T_PS_AC_ENABLED (1 << VCNL36825T_PS_AC_POS) + +#define VCNL36825T_PS_AC_NUM_1 (0 << VCNL36825T_PS_AC_NUM_POS) +#define VCNL36825T_PS_AC_NUM_2 (1 << VCNL36825T_PS_AC_NUM_POS) +#define VCNL36825T_PS_AC_NUM_4 (2 << VCNL36825T_PS_AC_NUM_POS) +#define VCNL36825T_PS_AC_NUM_8 (3 << VCNL36825T_PS_AC_NUM_POS) + +#define VCNL36825T_PS_AC_PERIOD_3MS (0 << VCNL36825T_PS_AC_PERIOD_POS) +#define VCNL36825T_PS_AC_PERIOD_6MS (1 << VCNL36825T_PS_AC_PERIOD_POS) +#define VCNL36825T_PS_AC_PERIOD_12MS (2 << VCNL36825T_PS_AC_PERIOD_POS) +#define VCNL36825T_PS_AC_PERIOD_24MS (3 << VCNL36825T_PS_AC_PERIOD_POS) + +#define VCNL36825T_PS_LPEN_DISABLED (0 << VCNL36825T_PS_LPEN_POS) +#define VCNL36825T_PS_LPEN_ENABLED (1 << VCNL36825T_PS_LPEN_POS) + +#define VCNL36825T_PS_LPPER_40MS (0 << VCNL36825T_PS_LPPER_POS) +#define VCNL36825T_PS_LPPER_80MS (1 << VCNL36825T_PS_LPPER_POS) +#define VCNL36825T_PS_LPPER_160MS (2 << VCNL36825T_PS_LPPER_POS) +#define VCNL36825T_PS_LPPER_320MS (3 << VCNL36825T_PS_LPPER_POS) + +/* PS_DATA */ +#define VCNL36825T_PS_DATA_L_POS 0 +#define VCNL36825T_PS_DATA_H_POS 8 + +#define VCNL36825T_PS_DATA_L_MSK GENMASK(7, 0) +#define VCNL36825T_PS_DATA_H_MSK GENMASK(11, 8) +#define VCNL36825T_OS_DATA_MSK (VCNL36825T_PS_DATA_L_MSK | VCNL36825T_PS_DATA_H_MSK) + +/* INT_FLAG */ +#define VCNL36825T_PS_IF_AWAY_POS 8 +#define VCNL36825T_PS_IF_CLOSE_POS 9 +#define VCNL36825T_PS_SPFLAG_POS 12 +#define VCNL36825T_PS_ACFLAG_POS 13 + +#define VCNL36825T_PS_IF_AWAY_MSK GENMASK(8, 8) +#define VCNL36825T_PS_IF_CLOSE_MSK GENMASK(9, 9) +#define VCNL36825T_PS_SPFLAG_MSK GENMASK(12, 12) +#define VCNL36825T_PS_ACFLAG_MSK GENMASK(13, 13) + +/* ID */ +#define VCNL36825T_ID_POS 0 +#define VCNL36825T_VERSION_CODE_POS 8 + +#define VCNL36825T_ID_MSK GENMASK(7, 0) +#define VCNL36825T_VERSION_CODE_MSK GENMASK(11, 8) + +#define VCNL36825T_DEVICE_ID 0b00100110 + +/* PS_AC_DATA */ +#define VCNL36825T_AC_DATA_L_POS 0 +#define VCNL36825T_AC_DATA_H_POS 8 +#define VCNL36825T_AC_SUN_POS 14 +#define VCNL36825T_AC_BUSY_POS 15 + +#define VCNL36825T_AC_DATA_L_MSK GENMASK(7, 0) +#define VCNL36825T_AC_DATA_H_MSK GENMASK(11, 8) +#define VCNL36825T_AC_SUN_MSK GENMASK(14, 14) +#define VCNL36825T_AC_BUSY_MSK GENMASK(15, 15) + +/* --- */ + +#define VCNL36825T_PS_PERIOD_VALUE_MAX_MS 80 +#define VCNL36825T_PS_LPPER_VALUE_MIN_MS 40 + +#define VCNL36825T_FORCED_FACTOR_TIME_TO_TRIGGER 0.5 +#define VCNL36825T_FORCED_FACTOR_DC_KILL_AMBIENT 3 +#define VCNL36825T_FORCED_FACTOR_MEASUREMENT 1 +#define VCNL36825T_FORCED_FACTOR_SHUTDOWN 1 +#define VCNL36825T_FORCED_FACTOR_SCALE 10 +#define VCNL36825T_FORCED_FACTOR_SUM \ + ((VCNL36825T_FORCED_FACTOR_TIME_TO_TRIGGER + VCNL36825T_FORCED_FACTOR_DC_KILL_AMBIENT + \ + VCNL36825T_FORCED_FACTOR_MEASUREMENT + VCNL36825T_FORCED_FACTOR_SHUTDOWN) * \ + VCNL36825T_FORCED_FACTOR_SCALE) + +enum vcnl36825t_operation_mode { + VCNL36825T_OPERATION_MODE_AUTO, + VCNL36825T_OPERATION_MODE_FORCE, +}; + +enum vcnl36825t_measurement_period { + VCNL36825T_MEAS_PERIOD_10MS, + VCNL36825T_MEAS_PERIOD_20MS, + VCNL36825T_MEAS_PERIOD_40MS, + VCNL36825T_MEAS_PERIOD_80MS, + VCNL36825T_MEAS_PERIOD_160MS, + VCNL36825T_MEAS_PERIOD_320MS, +}; + +enum vcnl36825t_proximity_integration_time { + VCNL36825T_PROXIMITY_INTEGRATION_1T, + VCNL36825T_PROXIMITY_INTEGRATION_1_5T, + VCNL36825T_PROXIMITY_INTEGRATION_2T, + VCNL36825T_PROXIMITY_INTEGRATION_2_5T, + VCNL36825T_PROXIMITY_INTEGRATION_3T, + VCNL36825T_PROXIMITY_INTEGRATION_3_5T, + VCNL36825T_PROXIMITY_INTEGRATION_4T, + VCNL36825T_PROXIMITY_INTEGRATION_8T, +}; + +enum vcnl36825t_proximity_integration_duration { + VCNL36825T_PROXIMITY_INTEGRATION_DURATION_25us, + VCNL36825T_PROXIMITY_INTEGRATION_DURATION_50us, +}; + +enum vcnl36825t_multi_pulse { + VCNL38652T_MULTI_PULSE_1, + VCNL38652T_MULTI_PULSE_2, + VCNL38652T_MULTI_PULSE_4, + VCNL38652T_MULTI_PULSE_8, +}; + +enum vcnl38625t_laser_current { + VCNL36825T_LASER_CURRENT_10MS, + VCNL36825T_LASER_CURRENT_12MS, + VCNL36825T_LASER_CURRENT_14MS, + VCNL36825T_LASER_CURRENT_16MS, + VCNL36825T_LASER_CURRENT_18MS, + VCNL36825T_LASER_CURRENT_20MS, +}; + +struct vcnl36825t_config { + struct i2c_dt_spec i2c; + + enum vcnl36825t_operation_mode operation_mode; + + enum vcnl36825t_measurement_period period; + enum vcnl36825t_proximity_integration_time proximity_it; + enum vcnl36825t_proximity_integration_duration proximity_itb; + enum vcnl36825t_multi_pulse multi_pulse; + + bool low_power; + bool high_gain; + + enum vcnl38625t_laser_current laser_current; + bool high_dynamic_output; + bool sunlight_cancellation; +}; + +struct vcnl36825t_data { + uint16_t proximity; + + int meas_timeout_us; /** wait time for finished measurement for "forced" operation mode */ +}; + +#endif diff --git a/dts/bindings/sensor/vishay,vcnl36825t.yaml b/dts/bindings/sensor/vishay,vcnl36825t.yaml new file mode 100644 index 00000000000..b1188b3d77e --- /dev/null +++ b/dts/bindings/sensor/vishay,vcnl36825t.yaml @@ -0,0 +1,90 @@ +# Copyright (c) 2024 Juliane Schulze, deveritec GmbH +# SPDX-License-Identifier: Apache-2.0 + +description: | + VCNL36825T proximity and ambient light sensor. See datasheet at + https://www.vishay.com/docs/84274/vcnl36825t.pdf + +compatible: "vishay,vcnl36825t" + +include: [sensor-device.yaml, i2c-device.yaml] + +properties: + operation-mode: + type: string + default: "auto" + enum: ["auto", "force"] + description: | + Mode of operation. + - "auto": the sensor performs sampling continuously, + - "force": the sampling is performed on every fetch command. + + Defaults to sensor reset value. + + measurement-period: + type: int + default: 40 + enum: [10, 20, 40, 80, 160, 320] + description: | + Measurement period of the sensors in ms. + Higher values yield lower power consumption. + Note: + - [10, 80] ms only if low power mode is inactive + - [80, 320] ms only in low power mode + + Defaults to 40 ms which is supported in both normal and low-power mode. + + proximity-it: + type: string + default: "1" + enum: ["1", "1.5", "2", "2.5", "3", "3.5", "4", "8"] + description: | + Proximity integration time in T. + Defaults to sensor reset value. + + proximity-itb: + type: int + default: 25 + enum: [25, 50] + description: | + Duration of the proximity integration time T in us. + Defaults to sensor reset value. + + multi-pulse: + type: int + default: 1 + enum: [1, 2, 4, 8] + description: | + Number of pulses per single measurement. + Higher values increase accuracy and power consumption. + Defaults to sensor reset value. + + laser-current: + type: int + default: 10 + enum: [10, 12, 14, 16, 18, 20] + description: | + Current used by the laser during measurement periods. + Defaults to minimum allowed value. + + low-power: + type: boolean + description: | + Activate low power mode. + This allows to increase the measurement period up to 320 ms. + + high-gain: + type: boolean + description: | + Activate the high gain mode. + + sunlight-cancellation: + type: boolean + description: | + Activate sunlight cancellation. + + high-dynamic-output: + type: boolean + description: | + Activate 16bit high dynamic output mode. + Cannot be used with threshold interrupt. diff --git a/tests/drivers/build_all/sensor/i2c.dtsi b/tests/drivers/build_all/sensor/i2c.dtsi index 0a10dec83d3..3488c0e7d67 100644 --- a/tests/drivers/build_all/sensor/i2c.dtsi +++ b/tests/drivers/build_all/sensor/i2c.dtsi @@ -905,3 +905,13 @@ test_i2c_lis2de12: lis2de12@80 { accel-range = ; accel-odr = ; }; + +test_i2c_vishay_vcnl36825t: vcnl36825t@81 { + compatible = "vishay,vcnl36825t"; + reg = <0x81>; + + proximity-it = "3.5"; + multi-pulse = <8>; + + low-power; +}; From 8f18094c623b473ed855065d287c55e0c99c0b3b Mon Sep 17 00:00:00 2001 From: Grzegorz Chwierut Date: Wed, 31 Jan 2024 17:05:00 +0100 Subject: [PATCH 3430/3723] twister: pytest: Fix shell fixture On the hardware, after booting up the device, on the console might appear additional logs after receiving first prompt. Wait and clear the buffer to avoid unexpected messages when verifying output. Signed-off-by: Grzegorz Chwierut --- .../src/twister_harness/fixtures.py | 9 ++++++++- .../src/twister_harness/helpers/shell.py | 2 -- 2 files changed, 8 insertions(+), 3 deletions(-) diff --git a/scripts/pylib/pytest-twister-harness/src/twister_harness/fixtures.py b/scripts/pylib/pytest-twister-harness/src/twister_harness/fixtures.py index f2b1b53706c..a4819ca20c1 100644 --- a/scripts/pylib/pytest-twister-harness/src/twister_harness/fixtures.py +++ b/scripts/pylib/pytest-twister-harness/src/twister_harness/fixtures.py @@ -6,6 +6,7 @@ from typing import Generator, Type import pytest +import time from twister_harness.device.device_adapter import DeviceAdapter from twister_harness.device.factory import DeviceFactory @@ -58,7 +59,13 @@ def shell(dut: DeviceAdapter) -> Shell: """Return ready to use shell interface""" shell = Shell(dut, timeout=20.0) logger.info('Wait for prompt') - assert shell.wait_for_prompt() + if not shell.wait_for_prompt(): + pytest.fail('Prompt not found') + if dut.device_config.type == 'hardware': + # after booting up the device, there might appear additional logs + # after first prompt, so we need to wait and clear the buffer + time.sleep(0.5) + dut.clear_buffer() return shell diff --git a/scripts/pylib/pytest-twister-harness/src/twister_harness/helpers/shell.py b/scripts/pylib/pytest-twister-harness/src/twister_harness/helpers/shell.py index 64f1cac63f4..bf8b70cea91 100644 --- a/scripts/pylib/pytest-twister-harness/src/twister_harness/helpers/shell.py +++ b/scripts/pylib/pytest-twister-harness/src/twister_harness/helpers/shell.py @@ -45,8 +45,6 @@ def wait_for_prompt(self, timeout: float | None = None) -> bool: continue if self.prompt in line: logger.debug('Got prompt') - time.sleep(0.05) - self._device.clear_buffer() return True return False From 12017b848164f52d71bafc7be4d17efbbe525454 Mon Sep 17 00:00:00 2001 From: Armando Visconti Date: Wed, 31 Jan 2024 17:06:50 +0100 Subject: [PATCH 3431/3723] drivers/sensor: lps2xdf: Fix uninitialized variables Fix some uninitialized variables calling the proper get() routine prior the equivalent set() operation. Fixes: #66791, #66778, #66772. Coverity-CID: 338119, 338144, 338157. Signed-off-by: Armando Visconti --- drivers/sensor/lps2xdf/lps22df.c | 1 + drivers/sensor/lps2xdf/lps28dfw.c | 1 + drivers/sensor/lps2xdf/lps2xdf_trigger.c | 6 ++++++ 3 files changed, 8 insertions(+) diff --git a/drivers/sensor/lps2xdf/lps22df.c b/drivers/sensor/lps2xdf/lps22df.c index 627d02a55b9..ff5537cf37c 100644 --- a/drivers/sensor/lps2xdf/lps22df.c +++ b/drivers/sensor/lps2xdf/lps22df.c @@ -207,6 +207,7 @@ int st_lps22df_init(const struct device *dev) lps22df_bus_mode_t bus_mode; /* Select bus interface */ + lps22df_bus_mode_get(ctx, &bus_mode); bus_mode.filter = LPS22DF_AUTO; bus_mode.interface = LPS22DF_SEL_BY_HW; lps22df_bus_mode_set(ctx, &bus_mode); diff --git a/drivers/sensor/lps2xdf/lps28dfw.c b/drivers/sensor/lps2xdf/lps28dfw.c index 86d0ab4edf5..40ea39bb571 100644 --- a/drivers/sensor/lps2xdf/lps28dfw.c +++ b/drivers/sensor/lps2xdf/lps28dfw.c @@ -214,6 +214,7 @@ int st_lps28dfw_init(const struct device *dev) lps28dfw_bus_mode_t bus_mode; /* Select bus interface */ + lps28dfw_bus_mode_get(ctx, &bus_mode); bus_mode.filter = LPS28DFW_AUTO; bus_mode.interface = LPS28DFW_SEL_BY_HW; lps28dfw_bus_mode_set(ctx, &bus_mode); diff --git a/drivers/sensor/lps2xdf/lps2xdf_trigger.c b/drivers/sensor/lps2xdf/lps2xdf_trigger.c index 2c3aa76124b..b196e1f40c2 100644 --- a/drivers/sensor/lps2xdf/lps2xdf_trigger.c +++ b/drivers/sensor/lps2xdf/lps2xdf_trigger.c @@ -168,6 +168,9 @@ int lps2xdf_init_interrupt(const struct device *dev, enum sensor_variant variant #if DT_HAS_COMPAT_STATUS_OKAY(st_lps22df) lps22df_int_mode_t mode; + if (lps22df_interrupt_mode_get(ctx, &mode) < 0) { + return -EIO; + } mode.drdy_latched = ~cfg->drdy_pulsed; if (lps22df_interrupt_mode_set(ctx, &mode) < 0) { return -EIO; @@ -177,6 +180,9 @@ int lps2xdf_init_interrupt(const struct device *dev, enum sensor_variant variant #if DT_HAS_COMPAT_STATUS_OKAY(st_lps28dfw) lps28dfw_int_mode_t mode; + if (lps28dfw_interrupt_mode_get(ctx, &mode) < 0) { + return -EIO; + } mode.drdy_latched = ~cfg->drdy_pulsed; if (lps28dfw_interrupt_mode_set(ctx, &mode) < 0) { return -EIO; From 692ebf404c7974bd38bcaae39afb874a16dd560a Mon Sep 17 00:00:00 2001 From: Jukka Rissanen Date: Wed, 31 Jan 2024 18:51:17 +0200 Subject: [PATCH 3432/3723] net: sockets: Update msg_controllen in recvmsg properly If recvmsg() does not update control data, then it must set msg_controllen length to 0 so that the caller can understand this. Fixes #68352 Signed-off-by: Jukka Rissanen --- subsys/net/lib/sockets/sockets.c | 22 +++++++++++++++++----- 1 file changed, 17 insertions(+), 5 deletions(-) diff --git a/subsys/net/lib/sockets/sockets.c b/subsys/net/lib/sockets/sockets.c index 4f34f5013d2..8fb5b4c6427 100644 --- a/subsys/net/lib/sockets/sockets.c +++ b/subsys/net/lib/sockets/sockets.c @@ -1492,12 +1492,20 @@ static inline ssize_t zsock_recv_dgram(struct net_context *ctx, } } - if (msg != NULL && msg->msg_control != NULL && msg->msg_controllen > 0) { - if (IS_ENABLED(CONFIG_NET_CONTEXT_RECV_PKTINFO) && - net_context_is_recv_pktinfo_set(ctx)) { - if (add_pktinfo(ctx, pkt, msg) < 0) { - msg->msg_flags |= ZSOCK_MSG_CTRUNC; + if (msg != NULL) { + if (msg->msg_control != NULL) { + if (msg->msg_controllen > 0) { + if (IS_ENABLED(CONFIG_NET_CONTEXT_RECV_PKTINFO) && + net_context_is_recv_pktinfo_set(ctx)) { + if (add_pktinfo(ctx, pkt, msg) < 0) { + msg->msg_flags |= ZSOCK_MSG_CTRUNC; + } + } else { + msg->msg_controllen = 0U; + } } + } else { + msg->msg_controllen = 0U; } } @@ -1948,6 +1956,10 @@ ssize_t z_vrfy_zsock_recvmsg(int sock, struct msghdr *msg, int flags) K_OOPS(k_usermode_to_copy(msg->msg_control, msg_copy.msg_control, msg_copy.msg_controllen)); + + msg->msg_controllen = msg_copy.msg_controllen; + } else { + msg->msg_controllen = 0U; } k_usermode_to_copy(&msg->msg_iovlen, From aa546baf441b2f69f8ac490c14dd695e8e4824c0 Mon Sep 17 00:00:00 2001 From: Jukka Rissanen Date: Wed, 31 Jan 2024 18:52:56 +0200 Subject: [PATCH 3433/3723] tests: net: sockets: udp: Add recvmsg test for checking msg_controllen Make sure that msg_controllen is cleared if there is no control data received. Signed-off-by: Jukka Rissanen --- tests/net/socket/udp/src/main.c | 92 +++++++++++++++++++++++++++++++-- 1 file changed, 88 insertions(+), 4 deletions(-) diff --git a/tests/net/socket/udp/src/main.c b/tests/net/socket/udp/src/main.c index 690512785eb..566ed3934f5 100644 --- a/tests/net/socket/udp/src/main.c +++ b/tests/net/socket/udp/src/main.c @@ -1450,7 +1450,8 @@ static void comm_sendmsg_recvmsg(int client_sock, struct sockaddr *server_addr, socklen_t server_addrlen, struct msghdr *msg, - void *cmsgbuf, int cmsgbuf_len) + void *cmsgbuf, int cmsgbuf_len, + bool expect_control_data) { #define MAX_BUF_LEN 64 #define SMALL_BUF_LEN (sizeof(TEST_STR_SMALL) - 1 - 2) @@ -1519,6 +1520,13 @@ static void comm_sendmsg_recvmsg(int client_sock, "wrong data (%s)", rx_buf); zassert_equal(addrlen, client_addrlen, "unexpected addrlen"); + /* Control data should be empty */ + if (!expect_control_data) { + zassert_equal(msg->msg_controllen, 0, + "We received control data (%u vs %zu)", + 0U, msg->msg_controllen); + } + /* Check the client port */ if (addr.sa_family == AF_INET) { if (net_sin(client_addr)->sin_port != ANY_PORT) { @@ -1592,6 +1600,13 @@ static void comm_sendmsg_recvmsg(int client_sock, "wrong data in %s", "iov[1]"); zassert_equal(addrlen, client_addrlen, "unexpected addrlen"); + /* Control data should be empty */ + if (!expect_control_data) { + zassert_equal(msg->msg_controllen, 0, + "We received control data (%u vs %zu)", + 0U, msg->msg_controllen); + } + /* Then check that the trucation flag is set correctly */ sent = sendmsg(client_sock, client_msg, 0); zassert_true(sent > 0, "sendmsg failed (%d)", -errno); @@ -1625,6 +1640,13 @@ static void comm_sendmsg_recvmsg(int client_sock, zassert_mem_equal(buf2, TEST_STR_SMALL, sizeof(buf2), "wrong data (%s)", buf2); zassert_equal(addrlen, client_addrlen, "unexpected addrlen"); + + /* Control data should be empty */ + if (!expect_control_data) { + zassert_equal(msg->msg_controllen, 0, + "We received control data (%u vs %zu)", + 0U, msg->msg_controllen); + } } ZTEST_USER(net_socket_udp, test_27_recvmsg_user) @@ -1666,7 +1688,7 @@ ZTEST_USER(net_socket_udp, test_27_recvmsg_user) server_sock, (struct sockaddr *)&server_addr, sizeof(server_addr), - &server_msg, NULL, 0); + &server_msg, NULL, 0, false); rv = close(client_sock); zassert_equal(rv, 0, "close failed"); @@ -1724,7 +1746,10 @@ static void run_ancillary_recvmsg_test(int client_sock, server_sock, server_addr, server_addr_len, - &server_msg, &cmsgbuf.buf, sizeof(cmsgbuf.buf)); + &server_msg, + &cmsgbuf.buf, + sizeof(cmsgbuf.buf), + true); for (prevcmsg = NULL, cmsg = CMSG_FIRSTHDR(&server_msg); cmsg != NULL && prevcmsg != cmsg; @@ -1769,7 +1794,10 @@ static void run_ancillary_recvmsg_test(int client_sock, server_sock, server_addr, server_addr_len, - &server_msg, &cmsgbuf.buf, sizeof(cmsgbuf.buf)); + &server_msg, + &cmsgbuf.buf, + sizeof(cmsgbuf.buf), + true); for (cmsg = CMSG_FIRSTHDR(&server_msg); cmsg != NULL; cmsg = CMSG_NXTHDR(&server_msg, cmsg)) { @@ -2324,6 +2352,62 @@ ZTEST(net_socket_udp, test_34_v6_hops) AF_INET6, hops, 0); } +ZTEST_USER(net_socket_udp, test_35_recvmsg_msg_controllen_update) +{ + int rv; + int client_sock; + int server_sock; + struct sockaddr_in client_addr; + struct sockaddr_in server_addr; + struct msghdr msg, server_msg; + struct iovec io_vector[1]; + union { + struct cmsghdr hdr; + unsigned char buf[CMSG_SPACE(sizeof(struct in6_pktinfo))]; + } cmsgbuf; + + prepare_sock_udp_v4(MY_IPV4_ADDR, ANY_PORT, &client_sock, &client_addr); + prepare_sock_udp_v4(MY_IPV4_ADDR, SERVER_PORT, &server_sock, &server_addr); + + rv = bind(server_sock, + (struct sockaddr *)&server_addr, + sizeof(server_addr)); + zassert_equal(rv, 0, "server bind failed"); + + rv = bind(client_sock, + (struct sockaddr *)&client_addr, + sizeof(client_addr)); + zassert_equal(rv, 0, "client bind failed"); + + memset(&cmsgbuf, 0, sizeof(cmsgbuf)); + + io_vector[0].iov_base = TEST_STR_SMALL; + io_vector[0].iov_len = strlen(TEST_STR_SMALL); + + memset(&msg, 0, sizeof(msg)); + msg.msg_iov = io_vector; + msg.msg_iovlen = 1; + msg.msg_name = &server_addr; + msg.msg_namelen = sizeof(server_addr); + + comm_sendmsg_recvmsg(client_sock, + (struct sockaddr *)&client_addr, + sizeof(client_addr), + &msg, + server_sock, + (struct sockaddr *)&server_addr, + sizeof(server_addr), + &server_msg, + &cmsgbuf.buf, + sizeof(cmsgbuf.buf), + false); + + rv = close(client_sock); + zassert_equal(rv, 0, "close failed"); + rv = close(server_sock); + zassert_equal(rv, 0, "close failed"); +} + static void after(void *arg) { ARG_UNUSED(arg); From f81ca136fed07db4020d3a707a755f5c6a5aec80 Mon Sep 17 00:00:00 2001 From: Daniel DeGrasse Date: Wed, 31 Jan 2024 10:50:11 -0600 Subject: [PATCH 3434/3723] drivers: mipi_dbi: clarify write size for mipi_write_display Clarify write size used by mipi_write_display, so that implementers of MIPI drivers know to use the buf_size field of the display buffer descriptor to determine write size. Signed-off-by: Daniel DeGrasse --- include/zephyr/drivers/mipi_dbi.h | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/include/zephyr/drivers/mipi_dbi.h b/include/zephyr/drivers/mipi_dbi.h index 4cd69845bff..5dca3d6f659 100644 --- a/include/zephyr/drivers/mipi_dbi.h +++ b/include/zephyr/drivers/mipi_dbi.h @@ -208,7 +208,8 @@ static inline int mipi_dbi_command_read(const struct device *dev, * @param config MIPI DBI configuration * @param framebuf: framebuffer to write to display * @param desc: descriptor of framebuffer to write. Note that the pitch must - * be equal to width. + * be equal to width. "buf_size" field determines how many bytes will be + * written. * @param pixfmt: pixel format of framebuffer data * @retval 0 buffer write succeeded. * @retval -EIO I/O error From 5b767a0dd23c5c55840749f69aadb710b503fcae Mon Sep 17 00:00:00 2001 From: Daniel DeGrasse Date: Wed, 31 Jan 2024 10:54:34 -0600 Subject: [PATCH 3435/3723] drvers: display: ili9xxx: fix usage of MIPI buffer descriptor Fix usage of MIPI buffer descriptor in ili9xxx driver. Previously, the buffer descriptor size was being set to display buffer size. For cases where the write height/width was not equal to the size of the buffer, this resulted in additional data being written that was not needed. To resolve this, calculate the mipi descriptor buffer size in the driver Also, remove the unconditional setting of mipi_desc.height, as this would override the previous (correct) setting. Signed-off-by: Daniel DeGrasse --- drivers/display/display_ili9xxx.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/drivers/display/display_ili9xxx.c b/drivers/display/display_ili9xxx.c index 6f1ff01d6b1..dc53daa3c86 100644 --- a/drivers/display/display_ili9xxx.c +++ b/drivers/display/display_ili9xxx.c @@ -111,12 +111,11 @@ static int ili9xxx_write(const struct device *dev, const uint16_t x, } else { write_h = desc->height; mipi_desc.height = desc->height; - mipi_desc.buf_size = desc->buf_size; + mipi_desc.buf_size = desc->width * data->bytes_per_pixel * write_h; nbr_of_writes = 1U; } mipi_desc.width = desc->width; - mipi_desc.height = desc->height; /* Per MIPI API, pitch must always match width */ mipi_desc.pitch = desc->width; From b6feb567d14bc77f3beb780463c739d1b0bf1040 Mon Sep 17 00:00:00 2001 From: Daniel DeGrasse Date: Wed, 31 Jan 2024 10:57:08 -0600 Subject: [PATCH 3436/3723] drivers: display: ili9xxx: do not delay for reset unless supported Check the return code of mipi_dbi_reset, and do not delay for the reset wait time unless the mipi controller has issued a hardware reset to the display. Signed-off-by: Daniel DeGrasse --- drivers/display/display_ili9xxx.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/drivers/display/display_ili9xxx.c b/drivers/display/display_ili9xxx.c index dc53daa3c86..e07e26c274b 100644 --- a/drivers/display/display_ili9xxx.c +++ b/drivers/display/display_ili9xxx.c @@ -48,7 +48,9 @@ static void ili9xxx_hw_reset(const struct device *dev) { const struct ili9xxx_config *config = dev->config; - mipi_dbi_reset(config->mipi_dev, ILI9XXX_RESET_PULSE_TIME); + if (mipi_dbi_reset(config->mipi_dev, ILI9XXX_RESET_PULSE_TIME) < 0) { + return; + }; k_sleep(K_MSEC(ILI9XXX_RESET_WAIT_TIME)); } From 172bc0c23875bf9ce61f5080af6159022be6d872 Mon Sep 17 00:00:00 2001 From: Tom Burdick Date: Thu, 1 Feb 2024 14:00:34 -0600 Subject: [PATCH 3437/3723] llext: Remove automatic include clangd like to automatically add include directives, this one slipped by and made its way in the tree. Remove it. Signed-off-by: Tom Burdick --- subsys/llext/llext.c | 1 - 1 file changed, 1 deletion(-) diff --git a/subsys/llext/llext.c b/subsys/llext/llext.c index bcd5ccda843..cbafa134eaa 100644 --- a/subsys/llext/llext.c +++ b/subsys/llext/llext.c @@ -5,7 +5,6 @@ * */ -#include "zephyr/sys/__assert.h" #include #include #include From 84e883b611276e0717b54ce4673502938504f05b Mon Sep 17 00:00:00 2001 From: Tom Burdick Date: Fri, 19 Jan 2024 11:03:46 -0600 Subject: [PATCH 3438/3723] llext: Support memory protection Sets up memory partitions and allows for the partitions to be added to a memory domain after loading an extension. This allows for applying memory protection attributes to all of the needed memory regions an extension requires to execute code correctly. Currently only works when usermode is enabled as otherwise memory protection APIs are unavailable. Signed-off-by: Tom Burdick --- include/zephyr/llext/llext.h | 23 +++++ subsys/llext/llext.c | 99 ++++++++++++++++++- tests/subsys/llext/hello_world/prj.conf | 1 - .../hello_world/src/test/test_llext_simple.c | 37 ++++++- tests/subsys/llext/hello_world/testcase.yaml | 21 +++- 5 files changed, 174 insertions(+), 7 deletions(-) diff --git a/include/zephyr/llext/llext.h b/include/zephyr/llext/llext.h index 832aba25cac..0a006dc53b7 100644 --- a/include/zephyr/llext/llext.h +++ b/include/zephyr/llext/llext.h @@ -10,6 +10,7 @@ #include #include #include +#include #include #include @@ -40,6 +41,8 @@ enum llext_mem { LLEXT_MEM_COUNT, }; +#define LLEXT_MEM_PARTITIONS (LLEXT_MEM_BSS+1) + struct llext_loader; /** @@ -48,6 +51,12 @@ struct llext_loader; struct llext { /** @cond ignore */ sys_snode_t _llext_list; + +#ifdef CONFIG_USERSPACE + struct k_mem_partition mem_parts[LLEXT_MEM_PARTITIONS]; + struct k_mem_domain mem_domain; +#endif + /** @endcond */ /** Name of the llext */ @@ -167,6 +176,20 @@ const void * const llext_find_sym(const struct llext_symtable *sym_table, const */ int llext_call_fn(struct llext *ext, const char *sym_name); +/** + * @brief Add the known memory partitions of the extension to a memory domain + * + * Allows an extension to be executed in supervisor or user mode threads when + * memory protection hardware is enabled. + * + * @param[in] ext Extension to add to a domain + * @param[in] domain Memory domain to add partitions to + * + * @retval 0 success + * @retval -errno error + */ +int llext_add_domain(struct llext *ext, struct k_mem_domain *domain); + /** * @brief Architecture specific function for updating op codes given a relocation * diff --git a/subsys/llext/llext.c b/subsys/llext/llext.c index cbafa134eaa..e36dbd86633 100644 --- a/subsys/llext/llext.c +++ b/subsys/llext/llext.c @@ -17,6 +17,13 @@ LOG_MODULE_REGISTER(llext, CONFIG_LLEXT_LOG_LEVEL); #include +#ifdef CONFIG_MMU_PAGE_SIZE +#define LLEXT_PAGE_SIZE CONFIG_MMU_PAGE_SIZE +#else +/* Arm's MPU wants a 32 byte minimum mpu region */ +#define LLEXT_PAGE_SIZE 32 +#endif + K_HEAP_DEFINE(llext_heap, CONFIG_LLEXT_HEAP_SIZE * 1024); static const char ELF_MAGIC[] = {0x7f, 'E', 'L', 'F'}; @@ -251,6 +258,38 @@ static int llext_map_sections(struct llext_loader *ldr, struct llext *ext) return 0; } +/* + * Initialize the memory partition associated with the extension memory + */ +static void llext_init_mem_part(struct llext *ext, enum llext_mem mem_idx, + uintptr_t start, size_t len) +{ +#ifdef CONFIG_USERSPACE + if (mem_idx < LLEXT_MEM_PARTITIONS) { + ext->mem_parts[mem_idx].start = start; + ext->mem_parts[mem_idx].size = len; + + switch (mem_idx) { + case LLEXT_MEM_TEXT: + ext->mem_parts[mem_idx].attr = K_MEM_PARTITION_P_RX_U_RX; + break; + case LLEXT_MEM_DATA: + case LLEXT_MEM_BSS: + ext->mem_parts[mem_idx].attr = K_MEM_PARTITION_P_RW_U_RW; + break; + case LLEXT_MEM_RODATA: + ext->mem_parts[mem_idx].attr = K_MEM_PARTITION_P_RO_U_RO; + break; + default: + break; + } + LOG_DBG("mem partition %d start 0x%lx, size %d", mem_idx, + ext->mem_parts[mem_idx].start, + ext->mem_parts[mem_idx].size); + } +#endif +} + static int llext_copy_section(struct llext_loader *ldr, struct llext *ext, enum llext_mem mem_idx) { @@ -265,18 +304,41 @@ static int llext_copy_section(struct llext_loader *ldr, struct llext *ext, IS_ENABLED(CONFIG_LLEXT_STORAGE_WRITABLE)) { ext->mem[mem_idx] = llext_peek(ldr, ldr->sects[mem_idx].sh_offset); if (ext->mem[mem_idx]) { + llext_init_mem_part(ext, mem_idx, (uintptr_t)ext->mem[mem_idx], + ldr->sects[mem_idx].sh_size); ext->mem_on_heap[mem_idx] = false; return 0; } } - ext->mem[mem_idx] = k_heap_aligned_alloc(&llext_heap, sizeof(uintptr_t), - ldr->sects[mem_idx].sh_size, + /* On ARM with an MPU a pow(2, N)*32 sized and aligned region is needed, + * otherwise its typically an mmu page (sized and aligned memory region) + * we are after that we can assign memory permission bits on. + */ +#ifndef CONFIG_ARM_MPU + const uintptr_t sect_alloc = ROUND_UP(ldr->sects[mem_idx].sh_size, LLEXT_PAGE_SIZE); + const uintptr_t sect_align = LLEXT_PAGE_SIZE; +#else + uintptr_t sect_alloc = LLEXT_PAGE_SIZE; + + while (sect_alloc < ldr->sects[mem_idx].sh_size) { + sect_alloc *= 2; + } + uintptr_t sect_align = sect_alloc; +#endif + + ext->mem[mem_idx] = k_heap_aligned_alloc(&llext_heap, sect_align, + sect_alloc, K_NO_WAIT); + if (!ext->mem[mem_idx]) { return -ENOMEM; } - ext->alloc_size += ldr->sects[mem_idx].sh_size; + + ext->alloc_size += sect_alloc; + + llext_init_mem_part(ext, mem_idx, (uintptr_t)ext->mem[mem_idx], + sect_alloc); if (ldr->sects[mem_idx].sh_type == SHT_NOBITS) { memset(ext->mem[mem_idx], 0, ldr->sects[mem_idx].sh_size); @@ -769,6 +831,14 @@ static int do_llext_load(struct llext_loader *ldr, struct llext *ext, ldr->sect_cnt = ldr->hdr.e_shnum; ext->alloc_size += sect_map_sz; +#ifdef CONFIG_USERSPACE + ret = k_mem_domain_init(&ext->mem_domain, 0, NULL); + if (ret != 0) { + LOG_ERR("Failed to initialize extenion memory domain %d", ret); + goto out; + } +#endif + LOG_DBG("Finding ELF tables..."); ret = llext_find_tables(ldr); if (ret != 0) { @@ -974,3 +1044,26 @@ int llext_call_fn(struct llext *ext, const char *sym_name) return 0; } + +int llext_add_domain(struct llext *ext, struct k_mem_domain *domain) +{ +#ifdef CONFIG_USERSPACE + int ret = 0; + + for (int i = 0; i < LLEXT_MEM_PARTITIONS; i++) { + if (ext->mem_size[i] == 0) { + continue; + } + ret = k_mem_domain_add_partition(domain, &ext->mem_parts[i]); + if (ret != 0) { + LOG_ERR("Failed adding memory partition %d to domain %p", + i, domain); + return ret; + } + } + + return ret; +#else + return -ENOSYS; +#endif +} diff --git a/tests/subsys/llext/hello_world/prj.conf b/tests/subsys/llext/hello_world/prj.conf index ed104f56b08..ad4d6c5a0b7 100644 --- a/tests/subsys/llext/hello_world/prj.conf +++ b/tests/subsys/llext/hello_world/prj.conf @@ -1,7 +1,6 @@ CONFIG_ZTEST=y CONFIG_ZTEST_STACK_SIZE=8192 CONFIG_LOG=y -CONFIG_LOG_MODE_IMMEDIATE=y CONFIG_LLEXT=y CONFIG_LLEXT_HEAP_SIZE=32 CONFIG_LLEXT_LOG_LEVEL_DBG=y diff --git a/tests/subsys/llext/hello_world/src/test/test_llext_simple.c b/tests/subsys/llext/hello_world/src/test/test_llext_simple.c index b78f2809009..ee68e72d73a 100644 --- a/tests/subsys/llext/hello_world/src/test/test_llext_simple.c +++ b/tests/subsys/llext/hello_world/src/test/test_llext_simple.c @@ -18,6 +18,19 @@ static uint8_t hello_world_elf[] __aligned(4) = { }; #endif +K_THREAD_STACK_DEFINE(llext_stack, 1024); +struct k_thread llext_thread; + +#ifdef CONFIG_USERSPACE +void llext_entry(void *arg0, void *arg1, void *arg2) +{ + struct llext *ext = arg0; + + zassert_ok(llext_call_fn(ext, "hello_world"), + "hello_world call should succeed"); +} +#endif /* CONFIG_USERSPACE */ + /** * Attempt to load, list, list symbols, call a fn, and unload a * hello world extension for each supported architecture @@ -45,9 +58,29 @@ ZTEST(llext, test_llext_simple) zassert_not_null(hello_world_fn, "hello_world should be an exported symbol"); - res = llext_call_fn(ext, "hello_world"); +#ifdef CONFIG_USERSPACE + struct k_mem_domain domain; + + k_mem_domain_init(&domain, 0, NULL); + + res = llext_add_domain(ext, &domain); + zassert_ok(res, "adding partitions to domain should succeed"); + + /* Should be runnable from newly created thread */ + k_thread_create(&llext_thread, llext_stack, + K_THREAD_STACK_SIZEOF(llext_stack), + &llext_entry, ext, NULL, NULL, + 1, 0, K_FOREVER); + + k_mem_domain_add_thread(&domain, &llext_thread); + + k_thread_start(&llext_thread); + k_thread_join(&llext_thread, K_FOREVER); - zassert_ok(res, "calling hello world should succeed"); +#else /* CONFIG_USERSPACE */ + zassert_ok(llext_call_fn(ext, "hello_world"), + "hello_world call should succeed"); +#endif /* CONFIG_USERSPACE */ llext_unload(&ext); } diff --git a/tests/subsys/llext/hello_world/testcase.yaml b/tests/subsys/llext/hello_world/testcase.yaml index 35370a65ece..c977dc5f94f 100644 --- a/tests/subsys/llext/hello_world/testcase.yaml +++ b/tests/subsys/llext/hello_world/testcase.yaml @@ -3,20 +3,28 @@ common: arch_allow: - arm - xtensa - filter: not CONFIG_MPU and not CONFIG_MMU and not CONFIG_SOC_SERIES_S32ZE_R52 platform_exclude: - nuvoton_pfm_m487 # See #63167 tests: llext.simple.readonly: arch_exclude: xtensa # for now + filter: not CONFIG_MPU and not CONFIG_MMU and not CONFIG_SOC_SERIES_S32ZE_R52 extra_configs: - arch:arm:CONFIG_ARM_MPU=n - CONFIG_LLEXT_STORAGE_WRITABLE=n + llext.simple.readonly_mpu: + arch_exclude: xtensa # for now + filter: CONFIG_CPU_HAS_MPU + extra_configs: + - CONFIG_USERSPACE=y + - CONFIG_LLEXT_STORAGE_WRITABLE=n llext.simple.writable: + filter: not CONFIG_MPU and not CONFIG_MMU and not CONFIG_SOC_SERIES_S32ZE_R52 extra_configs: - arch:arm:CONFIG_ARM_MPU=n - CONFIG_LLEXT_STORAGE_WRITABLE=y llext.simple.modules_enabled_writable: + filter: not CONFIG_MPU and not CONFIG_MMU platform_key: - simulation - arch @@ -28,6 +36,7 @@ tests: - CONFIG_LLEXT_STORAGE_WRITABLE=y - CONFIG_LLEXT_TEST_HELLO=m llext.simple.modules_enabled_readonly: + filter: not CONFIG_MPU and not CONFIG_MMU arch_exclude: xtensa # for now platform_key: - simulation @@ -38,3 +47,13 @@ tests: - arch:arm:CONFIG_ARM_MPU=n - CONFIG_MODULES=y - CONFIG_LLEXT_TEST_HELLO=m + llext.simple.modules_enabled_readonly_mpu: + filter: CONFIG_CPU_HAS_MPU + arch_exclude: xtensa # for now + platform_key: + - simulation + - arch + extra_configs: + - CONFIG_USERSPACE=y + - CONFIG_MODULES=y + - CONFIG_LLEXT_TEST_HELLO=m From 717c5835d6df56f58e114fb9e4548d963332a87d Mon Sep 17 00:00:00 2001 From: Radoslaw Koppel Date: Wed, 10 Jan 2024 12:23:11 +0100 Subject: [PATCH 3439/3723] arch: isr_tables: Add __used attribute to int_list_header MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This commit adds missing __used attribute it int_list_header, preventing it from being optimized out. Signed-off-by: Radosław Koppel --- arch/common/isr_tables.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/arch/common/isr_tables.c b/arch/common/isr_tables.c index 0311f81f252..9677c92683d 100644 --- a/arch/common/isr_tables.c +++ b/arch/common/isr_tables.c @@ -21,7 +21,7 @@ struct int_list_header { * header of the initList section, which is used by gen_isr_tables.py to create * the vector and sw isr tables, */ -Z_GENERIC_SECTION(.irq_info) struct int_list_header _iheader = { +Z_GENERIC_SECTION(.irq_info) __used struct int_list_header _iheader = { .table_size = IRQ_TABLE_SIZE, .offset = CONFIG_GEN_IRQ_START_VECTOR, }; From 4360acb27ea2c28c7db555a6be02c0da74d8b6fd Mon Sep 17 00:00:00 2001 From: Radoslaw Koppel Date: Mon, 30 Oct 2023 16:23:58 +0100 Subject: [PATCH 3440/3723] scripts: gen_isr_tables: Code cleanup MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This commit cleans up the gen_isr_tables code for better clarity and easier modification. Changes include: - Separate functions to load intList section. - Replace spurious handlers in internal data with None. Now it is the output generator work to choose right function. - All the work to generate vt and swt separated into its own functions. - Remove the need for internal shared array - all the information is here in swt array. - The update_masks function - more functionality moved here. - Simplify bit_mask function. Signed-off-by: Radosław Koppel --- scripts/build/gen_isr_tables.py | 364 ++++++++++++++++++-------------- 1 file changed, 207 insertions(+), 157 deletions(-) diff --git a/scripts/build/gen_isr_tables.py b/scripts/build/gen_isr_tables.py index e257074e55b..41fc20957a6 100755 --- a/scripts/build/gen_isr_tables.py +++ b/scripts/build/gen_isr_tables.py @@ -2,6 +2,7 @@ # # Copyright (c) 2017 Intel Corporation # Copyright (c) 2018 Foundries.io +# Copyright (c) 2023 Nordic Semiconductor NA # # SPDX-License-Identifier: Apache-2.0 # @@ -27,6 +28,13 @@ INTERRUPT_BITS = [8, 8, 8] +swt_spurious_handler = "((uintptr_t)&z_irq_spurious)" +swt_shared_handler = "((uintptr_t)&z_shared_isr)" +vt_spurious_handler = "z_irq_spurious" +vt_irq_handler = "_isr_wrapper" +vt_default_handler = None + + def debug(text): if args.debug: sys.stdout.write(os.path.basename(sys.argv[0]) + ": " + text + "\n") @@ -40,7 +48,7 @@ def endian_prefix(): else: return "<" -def read_intlist(elfobj, syms, snames): +def read_intlist(intlist_data, syms): """read a binary file containing the contents of the kernel's .intList section. This is an instance of a header created by include/zephyr/linker/intlist.ld: @@ -64,37 +72,25 @@ def read_intlist(elfobj, syms, snames): const void *param; }; """ - intList_sect = None intlist = {} - prefix = endian_prefix() + # Extract header and the rest of the data intlist_header_fmt = prefix + "II" + header_sz = struct.calcsize(intlist_header_fmt) + header_raw = struct.unpack_from(intlist_header_fmt, intlist_data, 0) + debug(str(header_raw)) + + intlist["num_vectors"] = header_raw[0] + intlist["offset"] = header_raw[1] + intdata = intlist_data[header_sz:] + + # Extract information about interrupts if "CONFIG_64BIT" in syms: intlist_entry_fmt = prefix + "iiQQ" else: intlist_entry_fmt = prefix + "iiII" - for sname in snames: - intList_sect = elfobj.get_section_by_name(sname) - if intList_sect is not None: - debug("Found intlist section: \"{}\"".format(sname)) - break - - if intList_sect is None: - error("Cannot find the intlist section!") - - intdata = intList_sect.data() - - header_sz = struct.calcsize(intlist_header_fmt) - header = struct.unpack_from(intlist_header_fmt, intdata, 0) - intdata = intdata[header_sz:] - - debug(str(header)) - - intlist["num_vectors"] = header[0] - intlist["offset"] = header[1] - intlist["interrupts"] = [i for i in struct.iter_unpack(intlist_entry_fmt, intdata)] @@ -108,32 +104,6 @@ def read_intlist(elfobj, syms, snames): return intlist - -def parse_args(): - global args - - parser = argparse.ArgumentParser(description=__doc__, - formatter_class=argparse.RawDescriptionHelpFormatter, allow_abbrev=False) - - parser.add_argument("-e", "--big-endian", action="store_true", - help="Target encodes data in big-endian format (little endian is " - "the default)") - parser.add_argument("-d", "--debug", action="store_true", - help="Print additional debugging information") - parser.add_argument("-o", "--output-source", required=True, - help="Output source file") - parser.add_argument("-k", "--kernel", required=True, - help="Zephyr kernel image") - parser.add_argument("-s", "--sw-isr-table", action="store_true", - help="Generate SW ISR table") - parser.add_argument("-V", "--vector-table", action="store_true", - help="Generate vector table") - parser.add_argument("-i", "--intlist-section", action="append", required=True, - help="The name of the section to search for the interrupt data. " - "This is accumulative argument. The first section found would be used.") - - args = parser.parse_args() - source_assembly_header = """ #ifndef ARCH_IRQ_VECTOR_JUMP_CODE #error "ARCH_IRQ_VECTOR_JUMP_CODE not defined" @@ -153,6 +123,9 @@ def write_code_irq_vector_table(fp, vt, nv, syms): for i in range(nv): func = vt[i] + if func is None: + func = vt_default_handler + if isinstance(func, int): func_as_string = get_symbol_from_addr(syms, func) else: @@ -166,10 +139,13 @@ def write_address_irq_vector_table(fp, vt, nv): for i in range(nv): func = vt[i] + if func is None: + func = vt_default_handler + if isinstance(func, int): - fp.write("\t{},\n".format(vt[i])) + fp.write("\t{},\n".format(func)) else: - fp.write("\t((uintptr_t)&{}),\n".format(vt[i])) + fp.write("\t((uintptr_t)&{}),\n".format(func)) fp.write("};\n") @@ -184,15 +160,19 @@ def write_address_irq_vector_table(fp, vt, nv): typedef void (* ISR)(const void *); """ -def write_shared_table(fp, shared, nv): +def write_shared_table(fp, swt, nv): fp.write("struct z_shared_isr_table_entry __shared_sw_isr_table" " z_shared_sw_isr_table[%d] = {\n" % nv) for i in range(nv): - client_num = shared[i][1] - client_list = shared[i][0] + if swt[i] is None: + client_num = 0 + client_list = None + else: + client_num = len(swt[i]) + client_list = swt[i] - if not client_num: + if client_num <= 1: fp.write("\t{ },\n") else: fp.write(f"\t{{ .client_num = {client_num}, .clients = {{ ") @@ -207,13 +187,13 @@ def write_shared_table(fp, shared, nv): fp.write("};\n") -def write_source_file(fp, vt, swt, intlist, syms, shared): +def write_source_file(fp, vt, swt, intlist, syms): fp.write(source_header) nv = intlist["num_vectors"] if "CONFIG_SHARED_INTERRUPTS" in syms: - write_shared_table(fp, shared, nv) + write_shared_table(fp, swt, nv) if vt: if "CONFIG_IRQ_VECTOR_TABLE_JUMP_BY_ADDRESS" in syms: @@ -233,11 +213,19 @@ def write_source_file(fp, vt, swt, intlist, syms, shared): level3_offset = syms.get("CONFIG_3RD_LVL_ISR_TBL_OFFSET") for i in range(nv): - param = "{0:#x}".format(swt[i][0]) - func = swt[i][1] - - if isinstance (func, str) and "z_shared_isr" in func: + if len(swt[i]) == 0: + # Not used interrupt + param = "0x0" + func = swt_spurious_handler + elif len(swt[i]) == 1: + # Single interrupt + param = "{0:#x}".format(swt[i][0][0]) + func = swt[i][0][1] + else: + # Shared interrupt param = "&z_shared_sw_isr_table[{0}]".format(i) + func = swt_shared_handler + if isinstance(func, int): func_as_string = "{0:#x}".format(func) else: @@ -253,14 +241,6 @@ def write_source_file(fp, vt, swt, intlist, syms, shared): fp.write("\t{{(const void *){0}, (ISR){1}}}, /* {2} */\n".format(param, func_as_string, i)) fp.write("};\n") -def get_symbols(obj): - for section in obj.iter_sections(): - if isinstance(section, SymbolTableSection): - return {sym.name: sym.entry.st_value - for sym in section.iter_symbols()} - - error("Could not find symbol table") - def getindex(irq, irq_aggregator_pos): try: return irq_aggregator_pos.index(irq) @@ -270,32 +250,9 @@ def getindex(irq, irq_aggregator_pos): " Recheck interrupt configuration.") def bit_mask(bits): - mask = 0 - for _ in range(0, bits): - mask = (mask << 1) | 1 - return mask - -def update_masks(): - if sum(INTERRUPT_BITS) > 32: - raise ValueError("Too many interrupt bits") - - INTERRUPT_LVL_BITMASK[0] = bit_mask(INTERRUPT_BITS[0]) - INTERRUPT_LVL_BITMASK[1] = bit_mask(INTERRUPT_BITS[1]) << INTERRUPT_BITS[0] - INTERRUPT_LVL_BITMASK[2] = bit_mask(INTERRUPT_BITS[2]) << INTERRUPT_BITS[0] + INTERRUPT_BITS[1] + return (1 << bits) - 1 - debug("Level Bits Bitmask") - debug("----------------------------") - for i in range(3): - bitmask_str = "0x" + format(INTERRUPT_LVL_BITMASK[i], '08X') - debug(f"{i + 1:>5} {INTERRUPT_BITS[i]:>7} {bitmask_str:>14}") - -def main(): - parse_args() - - with open(args.kernel, "rb") as fp: - kernel = ELFFile(fp) - syms = get_symbols(kernel) - intlist = read_intlist(kernel, syms, args.intlist_section) +def update_masks(syms): if "CONFIG_MULTI_LEVEL_INTERRUPTS" in syms: max_irq_per = syms["CONFIG_MAX_IRQ_PER_AGGREGATOR"] @@ -303,59 +260,98 @@ def main(): INTERRUPT_BITS[0] = syms["CONFIG_1ST_LEVEL_INTERRUPT_BITS"] INTERRUPT_BITS[1] = syms["CONFIG_2ND_LEVEL_INTERRUPT_BITS"] INTERRUPT_BITS[2] = syms["CONFIG_3RD_LEVEL_INTERRUPT_BITS"] - update_masks() - if "CONFIG_2ND_LEVEL_INTERRUPTS" in syms: - num_aggregators = syms["CONFIG_NUM_2ND_LEVEL_AGGREGATORS"] - irq2_baseoffset = syms["CONFIG_2ND_LVL_ISR_TBL_OFFSET"] - list_2nd_lvl_offsets = [syms['CONFIG_2ND_LVL_INTR_{}_OFFSET'. - format(str(i).zfill(2))] for i in - range(num_aggregators)] + if sum(INTERRUPT_BITS) > 32: + raise ValueError("Too many interrupt bits") - debug('2nd level offsets: {}'.format(list_2nd_lvl_offsets)) + INTERRUPT_LVL_BITMASK[0] = bit_mask(INTERRUPT_BITS[0]) + INTERRUPT_LVL_BITMASK[1] = bit_mask(INTERRUPT_BITS[1]) << INTERRUPT_BITS[0] + INTERRUPT_LVL_BITMASK[2] = bit_mask(INTERRUPT_BITS[2]) << INTERRUPT_BITS[0] + INTERRUPT_BITS[1] - if "CONFIG_3RD_LEVEL_INTERRUPTS" in syms: - num_aggregators = syms["CONFIG_NUM_3RD_LEVEL_AGGREGATORS"] - irq3_baseoffset = syms["CONFIG_3RD_LVL_ISR_TBL_OFFSET"] - list_3rd_lvl_offsets = [syms['CONFIG_3RD_LVL_INTR_{}_OFFSET'. - format(str(i).zfill(2))] for i in - range(num_aggregators)] + debug("Level Bits Bitmask") + debug("----------------------------") + for i in range(3): + bitmask_str = "0x" + format(INTERRUPT_LVL_BITMASK[i], '08X') + debug(f"{i + 1:>5} {INTERRUPT_BITS[i]:>7} {bitmask_str:>14}") - debug('3rd level offsets: {}'.format(list_3rd_lvl_offsets)) +def update_vt_default_handler(): + """Update the vt default handler based on parsed arguments. + + The default vt handler would be different depending on the fact if we have sw_isr_table. + If we have it - the default handler would lead to common handler. + If we do not - the default handler would be spurious handler + + The result is writen into vt_default_handler variable. + """ + global vt_default_handler + + if args.sw_isr_table: + vt_default_handler = vt_irq_handler + else: + vt_default_handler = vt_spurious_handler +def parse_intlist(intlist, syms): + """All the intlist data are parsed into swt and vt arrays. + + The vt array is prepared for hardware interrupt table. + Every entry in the selected position would contain None or the name of the function pointer + (address or string). + + The swt is a little more complex. At every position it would contain an array of parameter and + function pointer pairs. If CONFIG_SHARED_INTERRUPTS is enabled there may be more than 1 entry. + If empty array is placed on selected position - it means that the application does not implement + this interrupt. + + Parameters: + - intlist: The preprocessed list of intlist section content (see read_intlist) + - syms: Symbols + + Return: + vt, swt - parsed vt and swt arrays (see function description above) + """ nvec = intlist["num_vectors"] offset = intlist["offset"] if nvec > pow(2, 15): raise ValueError('nvec is too large, check endianness.') - swt_spurious_handler = "((uintptr_t)&z_irq_spurious)" - swt_shared_handler = "((uintptr_t)&z_shared_isr)" - vt_spurious_handler = "z_irq_spurious" - vt_irq_handler = "_isr_wrapper" - debug('offset is ' + str(offset)) debug('num_vectors is ' + str(nvec)) # Set default entries in both tables + if not(args.sw_isr_table or args.vector_table): + error("one or both of -s or -V needs to be specified on command line") + if args.vector_table: + vt = [None for i in range(nvec)] + else: + vt = None if args.sw_isr_table: - # All vectors just jump to the common vt_irq_handler. If some entries - # are used for direct interrupts, they will be replaced later. - if args.vector_table: - vt = [vt_irq_handler for i in range(nvec)] - else: - vt = None - # Default to spurious interrupt handler. Configured interrupts - # will replace these entries. - swt = [(0, swt_spurious_handler) for i in range(nvec)] - shared = [([], 0) for i in range(nvec)] + swt = [[] for i in range(nvec)] else: - if args.vector_table: - vt = [vt_spurious_handler for i in range(nvec)] - else: - error("one or both of -s or -V needs to be specified on command line") swt = None + # Gather info about multi level interrupts if enabled + if "CONFIG_MULTI_LEVEL_INTERRUPTS" in syms: + max_irq_per = syms["CONFIG_MAX_IRQ_PER_AGGREGATOR"] + + if "CONFIG_2ND_LEVEL_INTERRUPTS" in syms: + num_aggregators = syms["CONFIG_NUM_2ND_LEVEL_AGGREGATORS"] + irq2_baseoffset = syms["CONFIG_2ND_LVL_ISR_TBL_OFFSET"] + list_2nd_lvl_offsets = [syms['CONFIG_2ND_LVL_INTR_{}_OFFSET'. + format(str(i).zfill(2))] for i in + range(num_aggregators)] + + debug('2nd level offsets: {}'.format(list_2nd_lvl_offsets)) + + if "CONFIG_3RD_LEVEL_INTERRUPTS" in syms: + num_aggregators = syms["CONFIG_NUM_3RD_LEVEL_AGGREGATORS"] + irq3_baseoffset = syms["CONFIG_3RD_LVL_ISR_TBL_OFFSET"] + list_3rd_lvl_offsets = [syms['CONFIG_3RD_LVL_INTR_{}_OFFSET'. + format(str(i).zfill(2))] for i in + range(num_aggregators)] + + debug('3rd level offsets: {}'.format(list_3rd_lvl_offsets)) + # Process intlist and write to the tables created for irq, flags, func, param in intlist["interrupts"]: if flags & ISR_FLAG_DIRECT: if not vt: @@ -381,13 +377,12 @@ def main(): else: # Figure out third level interrupt position debug('IRQ = ' + hex(irq)) - irq3 = (irq & INTERRUPT_LVL_BITMASK[2]) >> INTERRUPT_BITS[0] + INTERRUPT_BITS[1] - irq2 = (irq & INTERRUPT_LVL_BITMASK[1]) >> INTERRUPT_BITS[0] + irq3 = (irq & INTERRUPT_LVL_BITMASK[2]) >> (INTERRUPT_BITS[0] + INTERRUPT_BITS[1]) + irq2 = (irq & INTERRUPT_LVL_BITMASK[1]) >> (INTERRUPT_BITS[0]) irq1 = irq & INTERRUPT_LVL_BITMASK[0] if irq3: - irq_parent = irq2 - list_index = getindex(irq_parent, list_3rd_lvl_offsets) + list_index = getindex(irq2, list_3rd_lvl_offsets) irq3_pos = irq3_baseoffset + max_irq_per*list_index + irq3 - 1 debug('IRQ_level = 3') debug('IRQ_Indx = ' + str(irq3)) @@ -396,8 +391,7 @@ def main(): # Figure out second level interrupt position elif irq2: - irq_parent = irq1 - list_index = getindex(irq_parent, list_2nd_lvl_offsets) + list_index = getindex(irq1, list_2nd_lvl_offsets) irq2_pos = irq2_baseoffset + max_irq_per*list_index + irq2 - 1 debug('IRQ_level = 2') debug('IRQ_Indx = ' + str(irq2)) @@ -415,36 +409,92 @@ def main(): error("IRQ %d (offset=%d) exceeds the maximum of %d" % (table_index, offset, len(swt) - 1)) if "CONFIG_SHARED_INTERRUPTS" in syms: - if swt[table_index] != (0, swt_spurious_handler): - # check client limit - if syms["CONFIG_SHARED_IRQ_MAX_NUM_CLIENTS"] == shared[table_index][1]: - error(f"Reached shared interrupt client limit. Maybe increase" + lst = swt[table_index] + if (param, func) in lst: + error("Attempting to register the same ISR/arg pair twice.") + if len(lst) >= syms["CONFIG_SHARED_IRQ_MAX_NUM_CLIENTS"]: + error(f"Reached shared interrupt client limit. Maybe increase" + f" CONFIG_SHARED_IRQ_MAX_NUM_CLIENTS?") - lst = shared[table_index][0] - delta_size = 1 - if not shared[table_index][1]: - lst.append(swt[table_index]) - # note: the argument will be fixed when writing the ISR table - # to isr_table.c - swt[table_index] = (0, swt_shared_handler) - delta_size += 1 - if (param, func) in lst: - error("Attempting to register the same ISR/arg pair twice.") - lst.append((param, func)) - shared[table_index] = (lst, shared[table_index][1] + delta_size) - else: - swt[table_index] = (param, func) else: - if swt[table_index] != (0, swt_spurious_handler): + if len(swt[table_index]) > 0: error(f"multiple registrations at table_index {table_index} for irq {irq} (0x{irq:x})" - + f"\nExisting handler 0x{swt[table_index][1]:x}, new handler 0x{func:x}" + + f"\nExisting handler 0x{swt[table_index][0][1]:x}, new handler 0x{func:x}" + "\nHas IRQ_CONNECT or IRQ_DIRECT_CONNECT accidentally been invoked on the same irq multiple times?" ) - else: - swt[table_index] = (param, func) + swt[table_index].append((param, func)) + + return vt, swt + +def get_symbols(obj): + for section in obj.iter_sections(): + if isinstance(section, SymbolTableSection): + return {sym.name: sym.entry.st_value + for sym in section.iter_symbols()} + + error("Could not find symbol table") + +def read_intList_sect(elfobj, snames): + """ + Load the raw intList section data in a form of byte array. + """ + intList_sect = None + + for sname in snames: + intList_sect = elfobj.get_section_by_name(sname) + if intList_sect is not None: + debug("Found intlist section: \"{}\"".format(sname)) + break + + if intList_sect is None: + error("Cannot find the intlist section!") + + intdata = intList_sect.data() + + return intdata + +def parse_args(): + global args + + parser = argparse.ArgumentParser(description=__doc__, + formatter_class=argparse.RawDescriptionHelpFormatter, allow_abbrev=False) + + parser.add_argument("-e", "--big-endian", action="store_true", + help="Target encodes data in big-endian format (little endian is " + "the default)") + parser.add_argument("-d", "--debug", action="store_true", + help="Print additional debugging information") + parser.add_argument("-o", "--output-source", required=True, + help="Output source file") + parser.add_argument("-k", "--kernel", required=True, + help="Zephyr kernel image") + parser.add_argument("-s", "--sw-isr-table", action="store_true", + help="Generate SW ISR table") + parser.add_argument("-V", "--vector-table", action="store_true", + help="Generate vector table") + parser.add_argument("-i", "--intlist-section", action="append", required=True, + help="The name of the section to search for the interrupt data. " + "This is accumulative argument. The first section found would be used.") + + args = parser.parse_args() + +def main(): + """ + All the input data are parsed to vt + """ + parse_args() + + with open(args.kernel, "rb") as fp: + kernel = ELFFile(fp) + syms = get_symbols(kernel) + intlist_data = read_intList_sect(kernel, args.intlist_section) + intlist = read_intlist(intlist_data, syms) + + update_masks(syms) + update_vt_default_handler() + vt, swt = parse_intlist(intlist, syms) with open(args.output_source, "w") as fp: - write_source_file(fp, vt, swt, intlist, syms, shared) + write_source_file(fp, vt, swt, intlist, syms) if __name__ == "__main__": main() From 568cced14fabe686b01ceea3884a488ca4213fb4 Mon Sep 17 00:00:00 2001 From: Radoslaw Koppel Date: Thu, 9 Nov 2023 09:41:43 +0100 Subject: [PATCH 3441/3723] scripts: gen_isr_tables: Break code into classes MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This commit breaks the code into functional classes. This way the functionality is visibly splitted into functional parts and it is easier to replace the specific parser part to implement new code generators. There is also common functionality to handle multi level interrupts moved to configuration class. Signed-off-by: Radosław Koppel --- scripts/build/gen_isr_tables.py | 826 ++++++++++++++++++-------------- 1 file changed, 456 insertions(+), 370 deletions(-) diff --git a/scripts/build/gen_isr_tables.py b/scripts/build/gen_isr_tables.py index 41fc20957a6..3032d1e30c9 100755 --- a/scripts/build/gen_isr_tables.py +++ b/scripts/build/gen_isr_tables.py @@ -14,142 +14,227 @@ from elftools.elf.elffile import ELFFile from elftools.elf.sections import SymbolTableSection -ISR_FLAG_DIRECT = 1 << 0 - -# The below few hardware independent magic numbers represent various -# levels of interrupts in a multi-level interrupt system. -# 0x000000FF - represents the 1st level (i.e. the interrupts -# that directly go to the processor). -# 0x0000FF00 - represents the 2nd level (i.e. the interrupts funnel -# into 1 line which then goes into the 1st level) -# 0x00FF0000 - represents the 3rd level (i.e. the interrupts funnel -# into 1 line which then goes into the 2nd level) -INTERRUPT_LVL_BITMASK = [0x000000FF, 0x0000FF00, 0x00FF0000] - -INTERRUPT_BITS = [8, 8, 8] - -swt_spurious_handler = "((uintptr_t)&z_irq_spurious)" -swt_shared_handler = "((uintptr_t)&z_shared_isr)" -vt_spurious_handler = "z_irq_spurious" -vt_irq_handler = "_isr_wrapper" -vt_default_handler = None - - -def debug(text): - if args.debug: - sys.stdout.write(os.path.basename(sys.argv[0]) + ": " + text + "\n") - -def error(text): - sys.exit(os.path.basename(sys.argv[0]) + ": error: " + text + "\n") - -def endian_prefix(): - if args.big_endian: - return ">" - else: - return "<" - -def read_intlist(intlist_data, syms): - """read a binary file containing the contents of the kernel's .intList - section. This is an instance of a header created by - include/zephyr/linker/intlist.ld: - - struct { - uint32_t num_vectors; <- typically CONFIG_NUM_IRQS - struct _isr_list isrs[]; <- Usually of smaller size than num_vectors - } - - Followed by instances of struct _isr_list created by IRQ_CONNECT() - calls: - - struct _isr_list { - /** IRQ line number */ - int32_t irq; - /** Flags for this IRQ, see ISR_FLAG_* definitions */ - int32_t flags; - /** ISR to call */ - void *func; - /** Parameter for non-direct IRQs */ - const void *param; - }; - """ - intlist = {} - prefix = endian_prefix() - - # Extract header and the rest of the data - intlist_header_fmt = prefix + "II" - header_sz = struct.calcsize(intlist_header_fmt) - header_raw = struct.unpack_from(intlist_header_fmt, intlist_data, 0) - debug(str(header_raw)) - intlist["num_vectors"] = header_raw[0] - intlist["offset"] = header_raw[1] - intdata = intlist_data[header_sz:] +class gen_isr_log: - # Extract information about interrupts - if "CONFIG_64BIT" in syms: - intlist_entry_fmt = prefix + "iiQQ" - else: - intlist_entry_fmt = prefix + "iiII" + def __init__(self, debug = False): + self.__debug = debug - intlist["interrupts"] = [i for i in - struct.iter_unpack(intlist_entry_fmt, intdata)] + def debug(self, text): + """Print debug message if debugging is enabled. - debug("Configured interrupt routing") - debug("handler irq flags param") - debug("--------------------------") + Note - this function requires config global variable to be initialized. + """ + if self.__debug: + sys.stdout.write(os.path.basename(sys.argv[0]) + ": " + text + "\n") - for irq in intlist["interrupts"]: - debug("{0:<10} {1:<3} {2:<3} {3}".format( - hex(irq[2]), irq[0], irq[1], hex(irq[3]))) + @staticmethod + def error(text): + sys.exit(os.path.basename(sys.argv[0]) + ": error: " + text + "\n") - return intlist - -source_assembly_header = """ -#ifndef ARCH_IRQ_VECTOR_JUMP_CODE -#error "ARCH_IRQ_VECTOR_JUMP_CODE not defined" -#endif -""" + def set_debug(self, state): + self.__debug = state -def get_symbol_from_addr(syms, addr): - for key, value in syms.items(): - if addr == value: - return key - return None -def write_code_irq_vector_table(fp, vt, nv, syms): - fp.write(source_assembly_header) +log = gen_isr_log() - fp.write("void __irq_vector_table __attribute__((naked)) _irq_vector_table(void) {\n") - for i in range(nv): - func = vt[i] - if func is None: - func = vt_default_handler - - if isinstance(func, int): - func_as_string = get_symbol_from_addr(syms, func) +class gen_isr_config: + """All the constants and configuration gathered in single class for readability. + """ + # Constants + __ISR_FLAG_DIRECT = 1 << 0 + __swt_spurious_handler = "((uintptr_t)&z_irq_spurious)" + __swt_shared_handler = "((uintptr_t)&z_shared_isr)" + __vt_spurious_handler = "z_irq_spurious" + __vt_irq_handler = "_isr_wrapper" + + @staticmethod + def __bm(bits): + return (1 << bits) - 1 + + def __init__(self, args, syms, log): + """Initialize the configuration object. + + The configuration object initialization takes only arguments as a parameter. + This is done to allow debug function work as soon as possible. + """ + # Store the arguments required for work + self.__args = args + self.__syms = syms + self.__log = log + + # Select the default interrupt vector handler + if self.args.sw_isr_table: + self.__vt_default_handler = self.__vt_irq_handler else: - func_as_string = func - - fp.write("\t__asm(ARCH_IRQ_VECTOR_JUMP_CODE({}));\n".format(func_as_string)) - fp.write("}\n") - -def write_address_irq_vector_table(fp, vt, nv): - fp.write("uintptr_t __irq_vector_table _irq_vector_table[%d] = {\n" % nv) - for i in range(nv): - func = vt[i] - - if func is None: - func = vt_default_handler - - if isinstance(func, int): - fp.write("\t{},\n".format(func)) + self.__vt_default_handler = self.__vt_spurious_handler + # Calculate interrupt bits + self.__int_bits = [8, 8, 8] + # The below few hardware independent magic numbers represent various + # levels of interrupts in a multi-level interrupt system. + # 0x000000FF - represents the 1st level (i.e. the interrupts + # that directly go to the processor). + # 0x0000FF00 - represents the 2nd level (i.e. the interrupts funnel + # into 1 line which then goes into the 1st level) + # 0x00FF0000 - represents the 3rd level (i.e. the interrupts funnel + # into 1 line which then goes into the 2nd level) + self.__int_lvl_masks = [0x000000FF, 0x0000FF00, 0x00FF0000] + + self.__irq2_baseoffset = None + self.__irq3_baseoffset = None + self.__irq2_offsets = None + self.__irq3_offsets = None + + if self.check_multi_level_interrupts(): + self.__max_irq_per = self.get_sym("CONFIG_MAX_IRQ_PER_AGGREGATOR") + + self.__int_bits[0] = self.get_sym("CONFIG_1ST_LEVEL_INTERRUPT_BITS") + self.__int_bits[1] = self.get_sym("CONFIG_2ND_LEVEL_INTERRUPT_BITS") + self.__int_bits[2] = self.get_sym("CONFIG_3RD_LEVEL_INTERRUPT_BITS") + + if sum(self.int_bits) > 32: + raise ValueError("Too many interrupt bits") + + self.__int_lvl_masks[0] = self.__bm(self.int_bits[0]) + self.__int_lvl_masks[1] = self.__bm(self.int_bits[1]) << self.int_bits[0] + self.__int_lvl_masks[2] = self.__bm(self.int_bits[2]) << (self.int_bits[0] + self.int_bits[1]) + + self.__log.debug("Level Bits Bitmask") + self.__log.debug("----------------------------") + for i in range(3): + bitmask_str = "0x" + format(self.__int_lvl_masks[i], '08X') + self.__log.debug(f"{i + 1:>5} {self.__int_bits[i]:>7} {bitmask_str:>14}") + + if self.check_sym("CONFIG_2ND_LEVEL_INTERRUPTS"): + num_aggregators = self.get_sym("CONFIG_NUM_2ND_LEVEL_AGGREGATORS") + self.__irq2_baseoffset = self.get_sym("CONFIG_2ND_LVL_ISR_TBL_OFFSET") + self.__irq2_offsets = [self.get_sym('CONFIG_2ND_LVL_INTR_{}_OFFSET'. + format(str(i).zfill(2))) for i in + range(num_aggregators)] + + self.__log.debug('2nd level offsets: {}'.format(self.__irq2_offsets)) + + if self.check_sym("CONFIG_3RD_LEVEL_INTERRUPTS"): + num_aggregators = self.get_sym("CONFIG_NUM_3RD_LEVEL_AGGREGATORS") + self.__irq3_baseoffset = self.get_sym("CONFIG_3RD_LVL_ISR_TBL_OFFSET") + self.__irq3_offsets = [self.get_sym('CONFIG_3RD_LVL_INTR_{}_OFFSET'. + format(str(i).zfill(2))) for i in + range(num_aggregators)] + + self.__log.debug('3rd level offsets: {}'.format(self.__irq3_offsets)) + + @property + def args(self): + return self.__args + + @property + def swt_spurious_handler(self): + return self.__swt_spurious_handler + + @property + def swt_shared_handler(self): + return self.__swt_shared_handler + + @property + def vt_default_handler(self): + return self.__vt_default_handler + + @property + def int_bits(self): + return self.__int_bits + + @property + def int_lvl_masks(self): + return self.__int_lvl_masks + + def endian_prefix(self): + if self.args.big_endian: + return ">" else: - fp.write("\t((uintptr_t)&{}),\n".format(func)) - - fp.write("};\n") - -source_header = """ + return "<" + + def get_irq_baseoffset(self, lvl): + if lvl == 2: + return self.__irq2_baseoffset + if lvl == 3: + return self.__irq3_baseoffset + self.__log.error("Unsupported irq level: {}".format(lvl)) + + def get_irq_index(self, irq, lvl): + if lvl == 2: + offsets = self.__irq2_offsets + elif lvl == 3: + offsets = self.__irq3_offsets + else: + self.__log.error("Unsupported irq level: {}".format(lvl)) + try: + return offsets.index(irq) + except ValueError: + self.__log.error("IRQ {} not present in parent offsets ({}). ". + format(irq, offsets) + + " Recheck interrupt configuration.") + + def get_swt_table_index(self, offset, irq): + if not self.check_multi_level_interrupts(): + return irq - offset + # Calculate index for multi level interrupts + self.__log.debug('IRQ = ' + hex(irq)) + irq3 = (irq & self.int_lvl_masks[2]) >> (self.int_bits[0] + self.int_bits[1]) + irq2 = (irq & self.int_lvl_masks[1]) >> (self.int_bits[0]) + irq1 = irq & self.int_lvl_masks[0] + # Figure out third level interrupt position + if irq3: + list_index = self.get_irq_index(irq2, 3) + irq3_pos = self.get_irq_baseoffset(3) + self.__max_irq_per * list_index + irq3 - 1 + self.__log.debug('IRQ_level = 3') + self.__log.debug('IRQ_Indx = ' + str(irq3)) + self.__log.debug('IRQ_Pos = ' + str(irq3_pos)) + return irq3_pos - offset + # Figure out second level interrupt position + if irq2: + list_index = self.get_irq_index(irq1, 2) + irq2_pos = self.get_irq_baseoffset(2) + self.__max_irq_per * list_index + irq2 - 1 + self.__log.debug('IRQ_level = 2') + self.__log.debug('IRQ_Indx = ' + str(irq2)) + self.__log.debug('IRQ_Pos = ' + str(irq2_pos)) + return irq2_pos - offset + # Figure out first level interrupt position + self.__log.debug('IRQ_level = 1') + self.__log.debug('IRQ_Indx = ' + str(irq1)) + self.__log.debug('IRQ_Pos = ' + str(irq1)) + return irq1 - offset + + def get_intlist_snames(self): + return self.args.intlist_section + + def test_isr_direct(self, flags): + return flags & self.__ISR_FLAG_DIRECT + + def get_sym_from_addr(self, addr): + for key, value in self.__syms.items(): + if addr == value: + return key + return None + + def get_sym(self, name): + return self.__syms.get(name) + + def check_sym(self, name): + return name in self.__syms + + def check_multi_level_interrupts(self): + return self.check_sym("CONFIG_MULTI_LEVEL_INTERRUPTS") + + def check_shared_interrupts(self): + return self.check_sym("CONFIG_SHARED_INTERRUPTS") + + def check_64b(self): + return self.check_sym("CONFIG_64BIT") + + +class gen_isr_parser: + source_header = """ /* AUTO-GENERATED by gen_isr_tables.py, do not edit! */ #include @@ -160,270 +245,276 @@ def write_address_irq_vector_table(fp, vt, nv): typedef void (* ISR)(const void *); """ -def write_shared_table(fp, swt, nv): - fp.write("struct z_shared_isr_table_entry __shared_sw_isr_table" - " z_shared_sw_isr_table[%d] = {\n" % nv) + source_assembly_header = """ +#ifndef ARCH_IRQ_VECTOR_JUMP_CODE +#error "ARCH_IRQ_VECTOR_JUMP_CODE not defined" +#endif +""" - for i in range(nv): - if swt[i] is None: - client_num = 0 - client_list = None + def __init__(self, intlist_data, config, log): + """Initialize the parser. + + The function prepares parser to work. + Parameters: + - intlist_data: The binnary data from intlist section + - config: The configuration object + - log: The logging object, has to have error and debug methods + """ + self.__config = config + self.__log = log + intlist = self.__read_intlist(intlist_data) + self.__vt, self.__swt, self.__nv = self.__parse_intlist(intlist) + + def __read_intlist(self, intlist_data): + """read a binary file containing the contents of the kernel's .intList + section. This is an instance of a header created by + include/zephyr/linker/intlist.ld: + + struct { + uint32_t num_vectors; <- typically CONFIG_NUM_IRQS + struct _isr_list isrs[]; <- Usually of smaller size than num_vectors + } + + Followed by instances of struct _isr_list created by IRQ_CONNECT() + calls: + + struct _isr_list { + /** IRQ line number */ + int32_t irq; + /** Flags for this IRQ, see ISR_FLAG_* definitions */ + int32_t flags; + /** ISR to call */ + void *func; + /** Parameter for non-direct IRQs */ + const void *param; + }; + """ + intlist = {} + prefix = self.__config.endian_prefix() + + # Extract header and the rest of the data + intlist_header_fmt = prefix + "II" + header_sz = struct.calcsize(intlist_header_fmt) + header_raw = struct.unpack_from(intlist_header_fmt, intlist_data, 0) + self.__log.debug(str(header_raw)) + + intlist["num_vectors"] = header_raw[0] + intlist["offset"] = header_raw[1] + intdata = intlist_data[header_sz:] + + # Extract information about interrupts + if self.__config.check_64b(): + intlist_entry_fmt = prefix + "iiQQ" else: - client_num = len(swt[i]) - client_list = swt[i] + intlist_entry_fmt = prefix + "iiII" - if client_num <= 1: - fp.write("\t{ },\n") - else: - fp.write(f"\t{{ .client_num = {client_num}, .clients = {{ ") - for j in range(0, client_num): - routine = client_list[j][1] - arg = client_list[j][0] + intlist["interrupts"] = [i for i in + struct.iter_unpack(intlist_entry_fmt, intdata)] + + self.__log.debug("Configured interrupt routing") + self.__log.debug("handler irq flags param") + self.__log.debug("--------------------------") + + for irq in intlist["interrupts"]: + self.__log.debug("{0:<10} {1:<3} {2:<3} {3}".format( + hex(irq[2]), irq[0], irq[1], hex(irq[3]))) - fp.write(f"{{ .isr = (ISR){ hex(routine) if isinstance(routine, int) else routine }, " - f".arg = (const void *){hex(arg)} }},") + return intlist - fp.write(" },\n},\n") + def __parse_intlist(self, intlist): + """All the intlist data are parsed into swt and vt arrays. - fp.write("};\n") + The vt array is prepared for hardware interrupt table. + Every entry in the selected position would contain None or the name of the function pointer + (address or string). -def write_source_file(fp, vt, swt, intlist, syms): - fp.write(source_header) + The swt is a little more complex. At every position it would contain an array of parameter and + function pointer pairs. If CONFIG_SHARED_INTERRUPTS is enabled there may be more than 1 entry. + If empty array is placed on selected position - it means that the application does not implement + this interrupt. - nv = intlist["num_vectors"] + Parameters: + - intlist: The preprocessed list of intlist section content (see read_intlist) - if "CONFIG_SHARED_INTERRUPTS" in syms: - write_shared_table(fp, swt, nv) + Return: + vt, swt - parsed vt and swt arrays (see function description above) + """ + nvec = intlist["num_vectors"] + offset = intlist["offset"] - if vt: - if "CONFIG_IRQ_VECTOR_TABLE_JUMP_BY_ADDRESS" in syms: - write_address_irq_vector_table(fp, vt, nv) - elif "CONFIG_IRQ_VECTOR_TABLE_JUMP_BY_CODE" in syms: - write_code_irq_vector_table(fp, vt, nv, syms) + if nvec > pow(2, 15): + raise ValueError('nvec is too large, check endianness.') + + self.__log.debug('offset is ' + str(offset)) + self.__log.debug('num_vectors is ' + str(nvec)) + + # Set default entries in both tables + if not(self.__config.args.sw_isr_table or self.__config.args.vector_table): + self.__log.error("one or both of -s or -V needs to be specified on command line") + if self.__config.args.vector_table: + vt = [None for i in range(nvec)] else: - error("CONFIG_IRQ_VECTOR_TABLE_JUMP_BY_{ADDRESS,CODE} not set") - - if not swt: - return - - fp.write("struct _isr_table_entry __sw_isr_table _sw_isr_table[%d] = {\n" - % nv) - - level2_offset = syms.get("CONFIG_2ND_LVL_ISR_TBL_OFFSET") - level3_offset = syms.get("CONFIG_3RD_LVL_ISR_TBL_OFFSET") - - for i in range(nv): - if len(swt[i]) == 0: - # Not used interrupt - param = "0x0" - func = swt_spurious_handler - elif len(swt[i]) == 1: - # Single interrupt - param = "{0:#x}".format(swt[i][0][0]) - func = swt[i][0][1] + vt = None + if self.__config.args.sw_isr_table: + swt = [[] for i in range(nvec)] else: - # Shared interrupt - param = "&z_shared_sw_isr_table[{0}]".format(i) - func = swt_shared_handler + swt = None - if isinstance(func, int): - func_as_string = "{0:#x}".format(func) - else: - func_as_string = func + # Process intlist and write to the tables created + for irq, flags, func, param in intlist["interrupts"]: + if not vt: + error("Direct Interrupt %d declared with parameter 0x%x " + "but no vector table in use" + % (irq, param)) + if self.__config.test_isr_direct(flags): + if param != 0: + self.__log.error("Direct irq %d declared, but has non-NULL parameter" + % irq) + if not 0 <= irq - offset < len(vt): + self.__log.error("IRQ %d (offset=%d) exceeds the maximum of %d" % + (irq - offset, offset, len(vt) - 1)) + vt[irq - offset] = func + else: + # Regular interrupt + if not swt: + self.__log.error("Regular Interrupt %d declared with parameter 0x%x " + "but no SW ISR_TABLE in use" + % (irq, param)) + + table_index = self.__config.get_swt_table_index(offset, irq) + + if not 0 <= table_index < len(swt): + self.__log.error("IRQ %d (offset=%d) exceeds the maximum of %d" % + (table_index, offset, len(swt) - 1)) + if self.__config.check_shared_interrupts(): + lst = swt[table_index] + if (param, func) in lst: + self.__log.error("Attempting to register the same ISR/arg pair twice.") + if len(lst) >= self.__config.get_sym("CONFIG_SHARED_IRQ_MAX_NUM_CLIENTS"): + self.__log.error(f"Reached shared interrupt client limit. Maybe increase" + + f" CONFIG_SHARED_IRQ_MAX_NUM_CLIENTS?") + else: + if len(swt[table_index]) > 0: + self.__log.error(f"multiple registrations at table_index {table_index} for irq {irq} (0x{irq:x})" + + f"\nExisting handler 0x{swt[table_index][0][1]:x}, new handler 0x{func:x}" + + "\nHas IRQ_CONNECT or IRQ_DIRECT_CONNECT accidentally been invoked on the same irq multiple times?" + ) + swt[table_index].append((param, func)) - if level2_offset is not None and i == level2_offset: - fp.write("\t/* Level 2 interrupts start here (offset: {}) */\n". - format(level2_offset)) - if level3_offset is not None and i == level3_offset: - fp.write("\t/* Level 3 interrupts start here (offset: {}) */\n". - format(level3_offset)) + return vt, swt, nvec - fp.write("\t{{(const void *){0}, (ISR){1}}}, /* {2} */\n".format(param, func_as_string, i)) - fp.write("};\n") + def __write_code_irq_vector_table(self, fp): + fp.write(self.source_assembly_header) -def getindex(irq, irq_aggregator_pos): - try: - return irq_aggregator_pos.index(irq) - except ValueError: - error("IRQ {} not present in parent offsets ({}). ". - format(irq, irq_aggregator_pos) + - " Recheck interrupt configuration.") + fp.write("void __irq_vector_table __attribute__((naked)) _irq_vector_table(void) {\n") + for i in range(self.__nv): + func = self.__vt[i] -def bit_mask(bits): - return (1 << bits) - 1 + if func is None: + func = self.__config.vt_default_handler -def update_masks(syms): + if isinstance(func, int): + func_as_string = self.__config.get_sym_from_addr(func) + else: + func_as_string = func - if "CONFIG_MULTI_LEVEL_INTERRUPTS" in syms: - max_irq_per = syms["CONFIG_MAX_IRQ_PER_AGGREGATOR"] + fp.write("\t__asm(ARCH_IRQ_VECTOR_JUMP_CODE({}));\n".format(func_as_string)) + fp.write("}\n") - INTERRUPT_BITS[0] = syms["CONFIG_1ST_LEVEL_INTERRUPT_BITS"] - INTERRUPT_BITS[1] = syms["CONFIG_2ND_LEVEL_INTERRUPT_BITS"] - INTERRUPT_BITS[2] = syms["CONFIG_3RD_LEVEL_INTERRUPT_BITS"] + def __write_address_irq_vector_table(self, fp): + fp.write("uintptr_t __irq_vector_table _irq_vector_table[%d] = {\n" % self.__nv) + for i in range(self.__nv): + func = self.__vt[i] - if sum(INTERRUPT_BITS) > 32: - raise ValueError("Too many interrupt bits") + if func is None: + func = self.__config.vt_default_handler - INTERRUPT_LVL_BITMASK[0] = bit_mask(INTERRUPT_BITS[0]) - INTERRUPT_LVL_BITMASK[1] = bit_mask(INTERRUPT_BITS[1]) << INTERRUPT_BITS[0] - INTERRUPT_LVL_BITMASK[2] = bit_mask(INTERRUPT_BITS[2]) << INTERRUPT_BITS[0] + INTERRUPT_BITS[1] + if isinstance(func, int): + fp.write("\t{},\n".format(func)) + else: + fp.write("\t((uintptr_t)&{}),\n".format(func)) - debug("Level Bits Bitmask") - debug("----------------------------") - for i in range(3): - bitmask_str = "0x" + format(INTERRUPT_LVL_BITMASK[i], '08X') - debug(f"{i + 1:>5} {INTERRUPT_BITS[i]:>7} {bitmask_str:>14}") + fp.write("};\n") -def update_vt_default_handler(): - """Update the vt default handler based on parsed arguments. + def __write_shared_table(self, fp): + fp.write("struct z_shared_isr_table_entry __shared_sw_isr_table" + " z_shared_sw_isr_table[%d] = {\n" % self.__nv) - The default vt handler would be different depending on the fact if we have sw_isr_table. - If we have it - the default handler would lead to common handler. - If we do not - the default handler would be spurious handler + for i in range(self.__nv): + if self.__swt[i] is None: + client_num = 0 + client_list = None + else: + client_num = len(self.__swt[i]) + client_list = self.__swt[i] - The result is writen into vt_default_handler variable. - """ - global vt_default_handler + if client_num <= 1: + fp.write("\t{ },\n") + else: + fp.write(f"\t{{ .client_num = {client_num}, .clients = {{ ") + for j in range(0, client_num): + routine = client_list[j][1] + arg = client_list[j][0] - if args.sw_isr_table: - vt_default_handler = vt_irq_handler - else: - vt_default_handler = vt_spurious_handler + fp.write(f"{{ .isr = (ISR){ hex(routine) if isinstance(routine, int) else routine }, " + f".arg = (const void *){hex(arg)} }},") -def parse_intlist(intlist, syms): - """All the intlist data are parsed into swt and vt arrays. + fp.write(" },\n},\n") - The vt array is prepared for hardware interrupt table. - Every entry in the selected position would contain None or the name of the function pointer - (address or string). + fp.write("};\n") - The swt is a little more complex. At every position it would contain an array of parameter and - function pointer pairs. If CONFIG_SHARED_INTERRUPTS is enabled there may be more than 1 entry. - If empty array is placed on selected position - it means that the application does not implement - this interrupt. + def write_source(self, fp): + fp.write(self.source_header) - Parameters: - - intlist: The preprocessed list of intlist section content (see read_intlist) - - syms: Symbols + if self.__config.check_shared_interrupts(): + self.__write_shared_table(fp) - Return: - vt, swt - parsed vt and swt arrays (see function description above) - """ - nvec = intlist["num_vectors"] - offset = intlist["offset"] - - if nvec > pow(2, 15): - raise ValueError('nvec is too large, check endianness.') - - debug('offset is ' + str(offset)) - debug('num_vectors is ' + str(nvec)) - - # Set default entries in both tables - if not(args.sw_isr_table or args.vector_table): - error("one or both of -s or -V needs to be specified on command line") - if args.vector_table: - vt = [None for i in range(nvec)] - else: - vt = None - if args.sw_isr_table: - swt = [[] for i in range(nvec)] - else: - swt = None - - # Gather info about multi level interrupts if enabled - if "CONFIG_MULTI_LEVEL_INTERRUPTS" in syms: - max_irq_per = syms["CONFIG_MAX_IRQ_PER_AGGREGATOR"] - - if "CONFIG_2ND_LEVEL_INTERRUPTS" in syms: - num_aggregators = syms["CONFIG_NUM_2ND_LEVEL_AGGREGATORS"] - irq2_baseoffset = syms["CONFIG_2ND_LVL_ISR_TBL_OFFSET"] - list_2nd_lvl_offsets = [syms['CONFIG_2ND_LVL_INTR_{}_OFFSET'. - format(str(i).zfill(2))] for i in - range(num_aggregators)] - - debug('2nd level offsets: {}'.format(list_2nd_lvl_offsets)) - - if "CONFIG_3RD_LEVEL_INTERRUPTS" in syms: - num_aggregators = syms["CONFIG_NUM_3RD_LEVEL_AGGREGATORS"] - irq3_baseoffset = syms["CONFIG_3RD_LVL_ISR_TBL_OFFSET"] - list_3rd_lvl_offsets = [syms['CONFIG_3RD_LVL_INTR_{}_OFFSET'. - format(str(i).zfill(2))] for i in - range(num_aggregators)] - - debug('3rd level offsets: {}'.format(list_3rd_lvl_offsets)) - # Process intlist and write to the tables created - for irq, flags, func, param in intlist["interrupts"]: - if flags & ISR_FLAG_DIRECT: - if not vt: - error("Direct Interrupt %d declared with parameter 0x%x " - "but no vector table in use" - % (irq, param)) - if param != 0: - error("Direct irq %d declared, but has non-NULL parameter" - % irq) - if not 0 <= irq - offset < len(vt): - error("IRQ %d (offset=%d) exceeds the maximum of %d" % - (irq - offset, offset, len(vt) - 1)) - vt[irq - offset] = func - else: - # Regular interrupt - if not swt: - error("Regular Interrupt %d declared with parameter 0x%x " - "but no SW ISR_TABLE in use" - % (irq, param)) - - if not "CONFIG_MULTI_LEVEL_INTERRUPTS" in syms: - table_index = irq - offset + if self.__vt: + if self.__config.check_sym("CONFIG_IRQ_VECTOR_TABLE_JUMP_BY_ADDRESS"): + self.__write_address_irq_vector_table(fp) + elif self.__config.check_sym("CONFIG_IRQ_VECTOR_TABLE_JUMP_BY_CODE"): + self.__write_code_irq_vector_table(fp) else: - # Figure out third level interrupt position - debug('IRQ = ' + hex(irq)) - irq3 = (irq & INTERRUPT_LVL_BITMASK[2]) >> (INTERRUPT_BITS[0] + INTERRUPT_BITS[1]) - irq2 = (irq & INTERRUPT_LVL_BITMASK[1]) >> (INTERRUPT_BITS[0]) - irq1 = irq & INTERRUPT_LVL_BITMASK[0] - - if irq3: - list_index = getindex(irq2, list_3rd_lvl_offsets) - irq3_pos = irq3_baseoffset + max_irq_per*list_index + irq3 - 1 - debug('IRQ_level = 3') - debug('IRQ_Indx = ' + str(irq3)) - debug('IRQ_Pos = ' + str(irq3_pos)) - table_index = irq3_pos - offset - - # Figure out second level interrupt position - elif irq2: - list_index = getindex(irq1, list_2nd_lvl_offsets) - irq2_pos = irq2_baseoffset + max_irq_per*list_index + irq2 - 1 - debug('IRQ_level = 2') - debug('IRQ_Indx = ' + str(irq2)) - debug('IRQ_Pos = ' + str(irq2_pos)) - table_index = irq2_pos - offset - - # Figure out first level interrupt position - else: - debug('IRQ_level = 1') - debug('IRQ_Indx = ' + str(irq1)) - debug('IRQ_Pos = ' + str(irq1)) - table_index = irq1 - offset - - if not 0 <= table_index < len(swt): - error("IRQ %d (offset=%d) exceeds the maximum of %d" % - (table_index, offset, len(swt) - 1)) - if "CONFIG_SHARED_INTERRUPTS" in syms: - lst = swt[table_index] - if (param, func) in lst: - error("Attempting to register the same ISR/arg pair twice.") - if len(lst) >= syms["CONFIG_SHARED_IRQ_MAX_NUM_CLIENTS"]: - error(f"Reached shared interrupt client limit. Maybe increase" - + f" CONFIG_SHARED_IRQ_MAX_NUM_CLIENTS?") + self.__log.error("CONFIG_IRQ_VECTOR_TABLE_JUMP_BY_{ADDRESS,CODE} not set") + + if not self.__swt: + return + + fp.write("struct _isr_table_entry __sw_isr_table _sw_isr_table[%d] = {\n" + % self.__nv) + + level2_offset = self.__config.get_irq_baseoffset(2) + level3_offset = self.__config.get_irq_baseoffset(3) + + for i in range(self.__nv): + if len(self.__swt[i]) == 0: + # Not used interrupt + param = "0x0" + func = self.__config.swt_spurious_handler + elif len(self.__swt[i]) == 1: + # Single interrupt + param = "{0:#x}".format(self.__swt[i][0][0]) + func = self.__swt[i][0][1] + else: + # Shared interrupt + param = "&z_shared_sw_isr_table[{0}]".format(i) + func = self.__config.swt_shared_handler + + if isinstance(func, int): + func_as_string = "{0:#x}".format(func) else: - if len(swt[table_index]) > 0: - error(f"multiple registrations at table_index {table_index} for irq {irq} (0x{irq:x})" - + f"\nExisting handler 0x{swt[table_index][0][1]:x}, new handler 0x{func:x}" - + "\nHas IRQ_CONNECT or IRQ_DIRECT_CONNECT accidentally been invoked on the same irq multiple times?" - ) - swt[table_index].append((param, func)) + func_as_string = func + + if level2_offset is not None and i == level2_offset: + fp.write("\t/* Level 2 interrupts start here (offset: {}) */\n". + format(level2_offset)) + if level3_offset is not None and i == level3_offset: + fp.write("\t/* Level 3 interrupts start here (offset: {}) */\n". + format(level3_offset)) + + fp.write("\t{{(const void *){0}, (ISR){1}}}, /* {2} */\n".format(param, func_as_string, i)) + fp.write("};\n") - return vt, swt def get_symbols(obj): for section in obj.iter_sections(): @@ -431,7 +522,7 @@ def get_symbols(obj): return {sym.name: sym.entry.st_value for sym in section.iter_symbols()} - error("Could not find symbol table") + log.error("Could not find symbol table") def read_intList_sect(elfobj, snames): """ @@ -442,19 +533,17 @@ def read_intList_sect(elfobj, snames): for sname in snames: intList_sect = elfobj.get_section_by_name(sname) if intList_sect is not None: - debug("Found intlist section: \"{}\"".format(sname)) + log.debug("Found intlist section: \"{}\"".format(sname)) break if intList_sect is None: - error("Cannot find the intlist section!") + log.error("Cannot find the intlist section!") intdata = intList_sect.data() return intdata def parse_args(): - global args - parser = argparse.ArgumentParser(description=__doc__, formatter_class=argparse.RawDescriptionHelpFormatter, allow_abbrev=False) @@ -475,26 +564,23 @@ def parse_args(): help="The name of the section to search for the interrupt data. " "This is accumulative argument. The first section found would be used.") - args = parser.parse_args() + return parser.parse_args() def main(): - """ - All the input data are parsed to vt - """ - parse_args() + args = parse_args() + # Configure logging as soon as possible + log.set_debug(args.debug) with open(args.kernel, "rb") as fp: kernel = ELFFile(fp) - syms = get_symbols(kernel) - intlist_data = read_intList_sect(kernel, args.intlist_section) - intlist = read_intlist(intlist_data, syms) + config = gen_isr_config(args, get_symbols(kernel), log) + intlist_data = read_intList_sect(kernel, config.get_intlist_snames()) - update_masks(syms) - update_vt_default_handler() - vt, swt = parse_intlist(intlist, syms) + parser = gen_isr_parser(intlist_data, config, log) with open(args.output_source, "w") as fp: - write_source_file(fp, vt, swt, intlist, syms) + parser.write_source(fp) + if __name__ == "__main__": main() From b0c83f328c2bc62c1bade3e77da083a00ce36102 Mon Sep 17 00:00:00 2001 From: Radoslaw Koppel Date: Wed, 31 Jan 2024 22:50:24 +0100 Subject: [PATCH 3442/3723] arch: sw_isr_table: Update shared interrupts structures MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This commit updates the definition of z_shared_isr_table_entry to use _isr_table_entry instead of specially created z_shared_isr_client. Signed-off-by: Radosław Koppel --- arch/common/shared_irq.c | 12 ++++++------ doc/kernel/services/interrupts.rst | 11 +---------- include/zephyr/sw_isr_table.h | 7 +------ tests/kernel/interrupt/src/test_shared_irq.h | 2 +- 4 files changed, 9 insertions(+), 23 deletions(-) diff --git a/arch/common/shared_irq.c b/arch/common/shared_irq.c index 68641cb2bb0..a05e78002ce 100644 --- a/arch/common/shared_irq.c +++ b/arch/common/shared_irq.c @@ -20,7 +20,7 @@ void z_shared_isr(const void *data) { size_t i; const struct z_shared_isr_table_entry *entry; - const struct z_shared_isr_client *client; + const struct _isr_table_entry *client; entry = data; @@ -42,7 +42,7 @@ void z_isr_install(unsigned int irq, void (*routine)(const void *), { struct z_shared_isr_table_entry *shared_entry; struct _isr_table_entry *entry; - struct z_shared_isr_client *client; + struct _isr_table_entry *client; unsigned int table_idx; int i; k_spinlock_key_t key; @@ -103,10 +103,10 @@ void z_isr_install(unsigned int irq, void (*routine)(const void *), k_spin_unlock(&lock, key); } -static void swap_client_data(struct z_shared_isr_client *a, - struct z_shared_isr_client *b) +static void swap_client_data(struct _isr_table_entry *a, + struct _isr_table_entry *b) { - struct z_shared_isr_client tmp; + struct _isr_table_entry tmp; tmp.arg = a->arg; tmp.isr = a->isr; @@ -162,7 +162,7 @@ int z_isr_uninstall(unsigned int irq, { struct z_shared_isr_table_entry *shared_entry; struct _isr_table_entry *entry; - struct z_shared_isr_client *client; + struct _isr_table_entry *client; unsigned int table_idx; size_t i; k_spinlock_key_t key; diff --git a/doc/kernel/services/interrupts.rst b/doc/kernel/services/interrupts.rst index b1f7421ed01..05e4809e568 100644 --- a/doc/kernel/services/interrupts.rst +++ b/doc/kernel/services/interrupts.rst @@ -549,7 +549,7 @@ This is an array of struct z_shared_isr_table_entry: .. code-block:: c struct z_shared_isr_table_entry { - struct z_shared_isr_client clients[CONFIG_SHARED_IRQ_MAX_NUM_CLIENTS]; + struct _isr_table_entry clients[CONFIG_SHARED_IRQ_MAX_NUM_CLIENTS]; size_t client_num; }; @@ -558,15 +558,6 @@ lines. Whenever an interrupt line becomes shared, :c:func:`z_shared_isr` will replace the currently registered ISR in _sw_isr_table. This special ISR will iterate through the list of registered clients and invoke the ISRs. -The definition for struct z_shared_isr_client is as follows: - -.. code-block:: c - - struct z_shared_isr_client { - void (*isr)(const void *arg); - const void *arg; - }; - x86 Details ----------- diff --git a/include/zephyr/sw_isr_table.h b/include/zephyr/sw_isr_table.h index f43efafad49..fc094b887ba 100644 --- a/include/zephyr/sw_isr_table.h +++ b/include/zephyr/sw_isr_table.h @@ -69,13 +69,8 @@ struct _isr_list { }; #ifdef CONFIG_SHARED_INTERRUPTS -struct z_shared_isr_client { - void (*isr)(const void *arg); - const void *arg; -}; - struct z_shared_isr_table_entry { - struct z_shared_isr_client clients[CONFIG_SHARED_IRQ_MAX_NUM_CLIENTS]; + struct _isr_table_entry clients[CONFIG_SHARED_IRQ_MAX_NUM_CLIENTS]; size_t client_num; }; diff --git a/tests/kernel/interrupt/src/test_shared_irq.h b/tests/kernel/interrupt/src/test_shared_irq.h index fd3c4c4a624..5ddd50a16e1 100644 --- a/tests/kernel/interrupt/src/test_shared_irq.h +++ b/tests/kernel/interrupt/src/test_shared_irq.h @@ -41,7 +41,7 @@ static inline bool client_exists_at_index(void (*routine)(const void *arg), { size_t i; struct z_shared_isr_table_entry *shared_entry; - struct z_shared_isr_client *client; + struct _isr_table_entry *client; shared_entry = &z_shared_sw_isr_table[irq]; From 0ae48ecb58da5ab8c3e942aa02b28ac4d604afbe Mon Sep 17 00:00:00 2001 From: Radoslaw Koppel Date: Sat, 2 Dec 2023 23:09:11 +0100 Subject: [PATCH 3443/3723] scripts: build: gen_isr_tables: Implement local ISR generation MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This commit moves all the functionality related to the current interrupt parser into gen_isr_tables_parser_carrays.py file. The new parser file gen_isr_tables_parser_local.py file is implemented with the new parser that. Additional information added to the generated interrupt header that contains data required by the new parser. Signed-off-by: Radosław Koppel --- CMakeLists.txt | 3 +- arch/common/isr_tables.c | 12 + scripts/build/gen_isr_tables.py | 332 +++------------- .../build/gen_isr_tables_parser_carrays.py | 292 ++++++++++++++ scripts/build/gen_isr_tables_parser_local.py | 375 ++++++++++++++++++ 5 files changed, 726 insertions(+), 288 deletions(-) create mode 100644 scripts/build/gen_isr_tables_parser_carrays.py create mode 100644 scripts/build/gen_isr_tables_parser_local.py diff --git a/CMakeLists.txt b/CMakeLists.txt index ce9121b3f73..a1876013aa9 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -1228,10 +1228,11 @@ if(CONFIG_GEN_ISR_TABLES) # isr_tables.c is generated from ${ZEPHYR_LINK_STAGE_EXECUTABLE} by # gen_isr_tables.py add_custom_command( - OUTPUT isr_tables.c + OUTPUT isr_tables.c isr_tables_vt.ld isr_tables_swi.ld COMMAND ${PYTHON_EXECUTABLE} ${ZEPHYR_BASE}/scripts/build/gen_isr_tables.py --output-source isr_tables.c + --linker-output-files isr_tables_vt.ld isr_tables_swi.ld --kernel $ --intlist-section .intList --intlist-section intList diff --git a/arch/common/isr_tables.c b/arch/common/isr_tables.c index 9677c92683d..050597b7b1d 100644 --- a/arch/common/isr_tables.c +++ b/arch/common/isr_tables.c @@ -15,6 +15,11 @@ struct int_list_header { uint32_t table_size; uint32_t offset; +#if IS_ENABLED(CONFIG_ISR_TABLES_LOCAL_DECLARATION) + uint32_t swi_table_entry_size; + uint32_t shared_isr_table_entry_size; + uint32_t shared_isr_client_num_offset; +#endif /* IS_ENABLED(CONFIG_ISR_TABLES_LOCAL_DECLARATION) */ }; /* These values are not included in the resulting binary, but instead form the @@ -24,6 +29,13 @@ struct int_list_header { Z_GENERIC_SECTION(.irq_info) __used struct int_list_header _iheader = { .table_size = IRQ_TABLE_SIZE, .offset = CONFIG_GEN_IRQ_START_VECTOR, +#if IS_ENABLED(CONFIG_ISR_TABLES_LOCAL_DECLARATION) + .swi_table_entry_size = sizeof(struct _isr_table_entry), +#if IS_ENABLED(CONFIG_SHARED_INTERRUPTS) + .shared_isr_table_entry_size = sizeof(struct z_shared_isr_table_entry), + .shared_isr_client_num_offset = offsetof(struct z_shared_isr_table_entry, client_num), +#endif /* IS_ENABLED(CONFIG_SHARED_INTERRUPTS) */ +#endif /* IS_ENABLED(CONFIG_ISR_TABLES_LOCAL_DECLARATION) */ }; /* These are placeholder tables. They will be replaced by the real tables diff --git a/scripts/build/gen_isr_tables.py b/scripts/build/gen_isr_tables.py index 3032d1e30c9..84812d708e8 100755 --- a/scripts/build/gen_isr_tables.py +++ b/scripts/build/gen_isr_tables.py @@ -8,9 +8,9 @@ # import argparse -import struct import sys import os +import importlib from elftools.elf.elffile import ELFFile from elftools.elf.sections import SymbolTableSection @@ -44,10 +44,13 @@ class gen_isr_config: """ # Constants __ISR_FLAG_DIRECT = 1 << 0 - __swt_spurious_handler = "((uintptr_t)&z_irq_spurious)" - __swt_shared_handler = "((uintptr_t)&z_shared_isr)" + __swt_spurious_handler = "z_irq_spurious" + __swt_shared_handler = "z_shared_isr" __vt_spurious_handler = "z_irq_spurious" __vt_irq_handler = "_isr_wrapper" + __shared_array_name = "z_shared_sw_isr_table" + __sw_isr_array_name = "_sw_isr_table" + __irq_vector_array_name = "_irq_vector_table" @staticmethod def __bm(bits): @@ -140,6 +143,18 @@ def swt_shared_handler(self): def vt_default_handler(self): return self.__vt_default_handler + @property + def shared_array_name(self): + return self.__shared_array_name + + @property + def sw_isr_array_name(self): + return self.__sw_isr_array_name + + @property + def irq_vector_array_name(self): + return self.__irq_vector_array_name + @property def int_bits(self): return self.__int_bits @@ -233,289 +248,6 @@ def check_64b(self): return self.check_sym("CONFIG_64BIT") -class gen_isr_parser: - source_header = """ -/* AUTO-GENERATED by gen_isr_tables.py, do not edit! */ - -#include -#include -#include -#include - -typedef void (* ISR)(const void *); -""" - - source_assembly_header = """ -#ifndef ARCH_IRQ_VECTOR_JUMP_CODE -#error "ARCH_IRQ_VECTOR_JUMP_CODE not defined" -#endif -""" - - def __init__(self, intlist_data, config, log): - """Initialize the parser. - - The function prepares parser to work. - Parameters: - - intlist_data: The binnary data from intlist section - - config: The configuration object - - log: The logging object, has to have error and debug methods - """ - self.__config = config - self.__log = log - intlist = self.__read_intlist(intlist_data) - self.__vt, self.__swt, self.__nv = self.__parse_intlist(intlist) - - def __read_intlist(self, intlist_data): - """read a binary file containing the contents of the kernel's .intList - section. This is an instance of a header created by - include/zephyr/linker/intlist.ld: - - struct { - uint32_t num_vectors; <- typically CONFIG_NUM_IRQS - struct _isr_list isrs[]; <- Usually of smaller size than num_vectors - } - - Followed by instances of struct _isr_list created by IRQ_CONNECT() - calls: - - struct _isr_list { - /** IRQ line number */ - int32_t irq; - /** Flags for this IRQ, see ISR_FLAG_* definitions */ - int32_t flags; - /** ISR to call */ - void *func; - /** Parameter for non-direct IRQs */ - const void *param; - }; - """ - intlist = {} - prefix = self.__config.endian_prefix() - - # Extract header and the rest of the data - intlist_header_fmt = prefix + "II" - header_sz = struct.calcsize(intlist_header_fmt) - header_raw = struct.unpack_from(intlist_header_fmt, intlist_data, 0) - self.__log.debug(str(header_raw)) - - intlist["num_vectors"] = header_raw[0] - intlist["offset"] = header_raw[1] - intdata = intlist_data[header_sz:] - - # Extract information about interrupts - if self.__config.check_64b(): - intlist_entry_fmt = prefix + "iiQQ" - else: - intlist_entry_fmt = prefix + "iiII" - - intlist["interrupts"] = [i for i in - struct.iter_unpack(intlist_entry_fmt, intdata)] - - self.__log.debug("Configured interrupt routing") - self.__log.debug("handler irq flags param") - self.__log.debug("--------------------------") - - for irq in intlist["interrupts"]: - self.__log.debug("{0:<10} {1:<3} {2:<3} {3}".format( - hex(irq[2]), irq[0], irq[1], hex(irq[3]))) - - return intlist - - def __parse_intlist(self, intlist): - """All the intlist data are parsed into swt and vt arrays. - - The vt array is prepared for hardware interrupt table. - Every entry in the selected position would contain None or the name of the function pointer - (address or string). - - The swt is a little more complex. At every position it would contain an array of parameter and - function pointer pairs. If CONFIG_SHARED_INTERRUPTS is enabled there may be more than 1 entry. - If empty array is placed on selected position - it means that the application does not implement - this interrupt. - - Parameters: - - intlist: The preprocessed list of intlist section content (see read_intlist) - - Return: - vt, swt - parsed vt and swt arrays (see function description above) - """ - nvec = intlist["num_vectors"] - offset = intlist["offset"] - - if nvec > pow(2, 15): - raise ValueError('nvec is too large, check endianness.') - - self.__log.debug('offset is ' + str(offset)) - self.__log.debug('num_vectors is ' + str(nvec)) - - # Set default entries in both tables - if not(self.__config.args.sw_isr_table or self.__config.args.vector_table): - self.__log.error("one or both of -s or -V needs to be specified on command line") - if self.__config.args.vector_table: - vt = [None for i in range(nvec)] - else: - vt = None - if self.__config.args.sw_isr_table: - swt = [[] for i in range(nvec)] - else: - swt = None - - # Process intlist and write to the tables created - for irq, flags, func, param in intlist["interrupts"]: - if not vt: - error("Direct Interrupt %d declared with parameter 0x%x " - "but no vector table in use" - % (irq, param)) - if self.__config.test_isr_direct(flags): - if param != 0: - self.__log.error("Direct irq %d declared, but has non-NULL parameter" - % irq) - if not 0 <= irq - offset < len(vt): - self.__log.error("IRQ %d (offset=%d) exceeds the maximum of %d" % - (irq - offset, offset, len(vt) - 1)) - vt[irq - offset] = func - else: - # Regular interrupt - if not swt: - self.__log.error("Regular Interrupt %d declared with parameter 0x%x " - "but no SW ISR_TABLE in use" - % (irq, param)) - - table_index = self.__config.get_swt_table_index(offset, irq) - - if not 0 <= table_index < len(swt): - self.__log.error("IRQ %d (offset=%d) exceeds the maximum of %d" % - (table_index, offset, len(swt) - 1)) - if self.__config.check_shared_interrupts(): - lst = swt[table_index] - if (param, func) in lst: - self.__log.error("Attempting to register the same ISR/arg pair twice.") - if len(lst) >= self.__config.get_sym("CONFIG_SHARED_IRQ_MAX_NUM_CLIENTS"): - self.__log.error(f"Reached shared interrupt client limit. Maybe increase" - + f" CONFIG_SHARED_IRQ_MAX_NUM_CLIENTS?") - else: - if len(swt[table_index]) > 0: - self.__log.error(f"multiple registrations at table_index {table_index} for irq {irq} (0x{irq:x})" - + f"\nExisting handler 0x{swt[table_index][0][1]:x}, new handler 0x{func:x}" - + "\nHas IRQ_CONNECT or IRQ_DIRECT_CONNECT accidentally been invoked on the same irq multiple times?" - ) - swt[table_index].append((param, func)) - - return vt, swt, nvec - - def __write_code_irq_vector_table(self, fp): - fp.write(self.source_assembly_header) - - fp.write("void __irq_vector_table __attribute__((naked)) _irq_vector_table(void) {\n") - for i in range(self.__nv): - func = self.__vt[i] - - if func is None: - func = self.__config.vt_default_handler - - if isinstance(func, int): - func_as_string = self.__config.get_sym_from_addr(func) - else: - func_as_string = func - - fp.write("\t__asm(ARCH_IRQ_VECTOR_JUMP_CODE({}));\n".format(func_as_string)) - fp.write("}\n") - - def __write_address_irq_vector_table(self, fp): - fp.write("uintptr_t __irq_vector_table _irq_vector_table[%d] = {\n" % self.__nv) - for i in range(self.__nv): - func = self.__vt[i] - - if func is None: - func = self.__config.vt_default_handler - - if isinstance(func, int): - fp.write("\t{},\n".format(func)) - else: - fp.write("\t((uintptr_t)&{}),\n".format(func)) - - fp.write("};\n") - - def __write_shared_table(self, fp): - fp.write("struct z_shared_isr_table_entry __shared_sw_isr_table" - " z_shared_sw_isr_table[%d] = {\n" % self.__nv) - - for i in range(self.__nv): - if self.__swt[i] is None: - client_num = 0 - client_list = None - else: - client_num = len(self.__swt[i]) - client_list = self.__swt[i] - - if client_num <= 1: - fp.write("\t{ },\n") - else: - fp.write(f"\t{{ .client_num = {client_num}, .clients = {{ ") - for j in range(0, client_num): - routine = client_list[j][1] - arg = client_list[j][0] - - fp.write(f"{{ .isr = (ISR){ hex(routine) if isinstance(routine, int) else routine }, " - f".arg = (const void *){hex(arg)} }},") - - fp.write(" },\n},\n") - - fp.write("};\n") - - def write_source(self, fp): - fp.write(self.source_header) - - if self.__config.check_shared_interrupts(): - self.__write_shared_table(fp) - - if self.__vt: - if self.__config.check_sym("CONFIG_IRQ_VECTOR_TABLE_JUMP_BY_ADDRESS"): - self.__write_address_irq_vector_table(fp) - elif self.__config.check_sym("CONFIG_IRQ_VECTOR_TABLE_JUMP_BY_CODE"): - self.__write_code_irq_vector_table(fp) - else: - self.__log.error("CONFIG_IRQ_VECTOR_TABLE_JUMP_BY_{ADDRESS,CODE} not set") - - if not self.__swt: - return - - fp.write("struct _isr_table_entry __sw_isr_table _sw_isr_table[%d] = {\n" - % self.__nv) - - level2_offset = self.__config.get_irq_baseoffset(2) - level3_offset = self.__config.get_irq_baseoffset(3) - - for i in range(self.__nv): - if len(self.__swt[i]) == 0: - # Not used interrupt - param = "0x0" - func = self.__config.swt_spurious_handler - elif len(self.__swt[i]) == 1: - # Single interrupt - param = "{0:#x}".format(self.__swt[i][0][0]) - func = self.__swt[i][0][1] - else: - # Shared interrupt - param = "&z_shared_sw_isr_table[{0}]".format(i) - func = self.__config.swt_shared_handler - - if isinstance(func, int): - func_as_string = "{0:#x}".format(func) - else: - func_as_string = func - - if level2_offset is not None and i == level2_offset: - fp.write("\t/* Level 2 interrupts start here (offset: {}) */\n". - format(level2_offset)) - if level3_offset is not None and i == level3_offset: - fp.write("\t/* Level 3 interrupts start here (offset: {}) */\n". - format(level3_offset)) - - fp.write("\t{{(const void *){0}, (ISR){1}}}, /* {2} */\n".format(param, func_as_string, i)) - fp.write("};\n") - - def get_symbols(obj): for section in obj.iter_sections(): if isinstance(section, SymbolTableSection): @@ -554,6 +286,12 @@ def parse_args(): help="Print additional debugging information") parser.add_argument("-o", "--output-source", required=True, help="Output source file") + parser.add_argument("-l", "--linker-output-files", + nargs=2, + metavar=("vector_table_link", "software_interrupt_link"), + help="Output linker files. " + "Used only if CONFIG_ISR_TABLES_LOCAL_DECLARATION is enabled. " + "In other case empty file would be generated.") parser.add_argument("-k", "--kernel", required=True, help="Zephyr kernel image") parser.add_argument("-s", "--sw-isr-table", action="store_true", @@ -576,11 +314,31 @@ def main(): config = gen_isr_config(args, get_symbols(kernel), log) intlist_data = read_intList_sect(kernel, config.get_intlist_snames()) - parser = gen_isr_parser(intlist_data, config, log) + if config.check_sym("CONFIG_ISR_TABLES_LOCAL_DECLARATION"): + sys.stdout.write( + "Warning: The EXPERIMENTAL ISR_TABLES_LOCAL_DECLARATION feature selected\n") + parser_module = importlib.import_module('gen_isr_tables_parser_local') + parser = parser_module.gen_isr_parser(intlist_data, config, log) + else: + parser_module = importlib.import_module('gen_isr_tables_parser_carrays') + parser = parser_module.gen_isr_parser(intlist_data, config, log) with open(args.output_source, "w") as fp: parser.write_source(fp) + if args.linker_output_files is not None: + with open(args.linker_output_files[0], "w") as fp_vt, \ + open(args.linker_output_files[1], "w") as fp_swi: + if hasattr(parser, 'write_linker_vt'): + parser.write_linker_vt(fp_vt) + else: + log.debug("Chosen parser does not support vector table linker file") + fp_vt.write('/* Empty */\n') + if hasattr(parser, 'write_linker_swi'): + parser.write_linker_swi(fp_swi) + else: + log.debug("Chosen parser does not support software interrupt linker file") + fp_swi.write('/* Empty */\n') if __name__ == "__main__": main() diff --git a/scripts/build/gen_isr_tables_parser_carrays.py b/scripts/build/gen_isr_tables_parser_carrays.py new file mode 100644 index 00000000000..e13ef19c1f8 --- /dev/null +++ b/scripts/build/gen_isr_tables_parser_carrays.py @@ -0,0 +1,292 @@ +#!/usr/bin/env python3 +# +# Copyright (c) 2017 Intel Corporation +# Copyright (c) 2018 Foundries.io +# Copyright (c) 2023 Nordic Semiconductor NA +# +# SPDX-License-Identifier: Apache-2.0 +# + +import struct + +class gen_isr_parser: + source_header = """ +/* AUTO-GENERATED by gen_isr_tables.py, do not edit! */ + +#include +#include +#include +#include + +typedef void (* ISR)(const void *); +""" + + source_assembly_header = """ +#ifndef ARCH_IRQ_VECTOR_JUMP_CODE +#error "ARCH_IRQ_VECTOR_JUMP_CODE not defined" +#endif +""" + + def __init__(self, intlist_data, config, log): + """Initialize the parser. + + The function prepares parser to work. + Parameters: + - intlist_data: The binnary data from intlist section + - config: The configuration object + - log: The logging object, has to have error and debug methods + """ + self.__config = config + self.__log = log + intlist = self.__read_intlist(intlist_data) + self.__vt, self.__swt, self.__nv = self.__parse_intlist(intlist) + + def __read_intlist(self, intlist_data): + """read a binary file containing the contents of the kernel's .intList + section. This is an instance of a header created by + include/zephyr/linker/intlist.ld: + + struct { + uint32_t num_vectors; <- typically CONFIG_NUM_IRQS + struct _isr_list isrs[]; <- Usually of smaller size than num_vectors + } + + Followed by instances of struct _isr_list created by IRQ_CONNECT() + calls: + + struct _isr_list { + /** IRQ line number */ + int32_t irq; + /** Flags for this IRQ, see ISR_FLAG_* definitions */ + int32_t flags; + /** ISR to call */ + void *func; + /** Parameter for non-direct IRQs */ + const void *param; + }; + """ + intlist = {} + prefix = self.__config.endian_prefix() + + # Extract header and the rest of the data + intlist_header_fmt = prefix + "II" + header_sz = struct.calcsize(intlist_header_fmt) + header_raw = struct.unpack_from(intlist_header_fmt, intlist_data, 0) + self.__log.debug(str(header_raw)) + + intlist["num_vectors"] = header_raw[0] + intlist["offset"] = header_raw[1] + intdata = intlist_data[header_sz:] + + # Extract information about interrupts + if self.__config.check_64b(): + intlist_entry_fmt = prefix + "iiQQ" + else: + intlist_entry_fmt = prefix + "iiII" + + intlist["interrupts"] = [i for i in + struct.iter_unpack(intlist_entry_fmt, intdata)] + + self.__log.debug("Configured interrupt routing") + self.__log.debug("handler irq flags param") + self.__log.debug("--------------------------") + + for irq in intlist["interrupts"]: + self.__log.debug("{0:<10} {1:<3} {2:<3} {3}".format( + hex(irq[2]), irq[0], irq[1], hex(irq[3]))) + + return intlist + + def __parse_intlist(self, intlist): + """All the intlist data are parsed into swt and vt arrays. + + The vt array is prepared for hardware interrupt table. + Every entry in the selected position would contain None or the name of the function pointer + (address or string). + + The swt is a little more complex. At every position it would contain an array of parameter and + function pointer pairs. If CONFIG_SHARED_INTERRUPTS is enabled there may be more than 1 entry. + If empty array is placed on selected position - it means that the application does not implement + this interrupt. + + Parameters: + - intlist: The preprocessed list of intlist section content (see read_intlist) + + Return: + vt, swt - parsed vt and swt arrays (see function description above) + """ + nvec = intlist["num_vectors"] + offset = intlist["offset"] + + if nvec > pow(2, 15): + raise ValueError('nvec is too large, check endianness.') + + self.__log.debug('offset is ' + str(offset)) + self.__log.debug('num_vectors is ' + str(nvec)) + + # Set default entries in both tables + if not(self.__config.args.sw_isr_table or self.__config.args.vector_table): + self.__log.error("one or both of -s or -V needs to be specified on command line") + if self.__config.args.vector_table: + vt = [None for i in range(nvec)] + else: + vt = None + if self.__config.args.sw_isr_table: + swt = [[] for i in range(nvec)] + else: + swt = None + + # Process intlist and write to the tables created + for irq, flags, func, param in intlist["interrupts"]: + if self.__config.test_isr_direct(flags): + if not vt: + self.__log.error("Direct Interrupt %d declared with parameter 0x%x " + "but no vector table in use" + % (irq, param)) + if param != 0: + self.__log.error("Direct irq %d declared, but has non-NULL parameter" + % irq) + if not 0 <= irq - offset < len(vt): + self.__log.error("IRQ %d (offset=%d) exceeds the maximum of %d" + % (irq - offset, offset, len(vt) - 1)) + vt[irq - offset] = func + else: + # Regular interrupt + if not swt: + self.__log.error("Regular Interrupt %d declared with parameter 0x%x " + "but no SW ISR_TABLE in use" + % (irq, param)) + + table_index = self.__config.get_swt_table_index(offset, irq) + + if not 0 <= table_index < len(swt): + self.__log.error("IRQ %d (offset=%d) exceeds the maximum of %d" % + (table_index, offset, len(swt) - 1)) + if self.__config.check_shared_interrupts(): + lst = swt[table_index] + if (param, func) in lst: + self.__log.error("Attempting to register the same ISR/arg pair twice.") + if len(lst) >= self.__config.get_sym("CONFIG_SHARED_IRQ_MAX_NUM_CLIENTS"): + self.__log.error(f"Reached shared interrupt client limit. Maybe increase" + + f" CONFIG_SHARED_IRQ_MAX_NUM_CLIENTS?") + else: + if len(swt[table_index]) > 0: + self.__log.error(f"multiple registrations at table_index {table_index} for irq {irq} (0x{irq:x})" + + f"\nExisting handler 0x{swt[table_index][0][1]:x}, new handler 0x{func:x}" + + "\nHas IRQ_CONNECT or IRQ_DIRECT_CONNECT accidentally been invoked on the same irq multiple times?" + ) + swt[table_index].append((param, func)) + + return vt, swt, nvec + + def __write_code_irq_vector_table(self, fp): + fp.write(self.source_assembly_header) + + fp.write("void __irq_vector_table __attribute__((naked)) _irq_vector_table(void) {\n") + for i in range(self.__nv): + func = self.__vt[i] + + if func is None: + func = self.__config.vt_default_handler + + if isinstance(func, int): + func_as_string = self.__config.get_sym_from_addr(func) + else: + func_as_string = func + + fp.write("\t__asm(ARCH_IRQ_VECTOR_JUMP_CODE({}));\n".format(func_as_string)) + fp.write("}\n") + + def __write_address_irq_vector_table(self, fp): + fp.write("uintptr_t __irq_vector_table _irq_vector_table[%d] = {\n" % self.__nv) + for i in range(self.__nv): + func = self.__vt[i] + + if func is None: + func = self.__config.vt_default_handler + + if isinstance(func, int): + fp.write("\t{},\n".format(func)) + else: + fp.write("\t((uintptr_t)&{}),\n".format(func)) + + fp.write("};\n") + + def __write_shared_table(self, fp): + fp.write("struct z_shared_isr_table_entry __shared_sw_isr_table" + " z_shared_sw_isr_table[%d] = {\n" % self.__nv) + + for i in range(self.__nv): + if self.__swt[i] is None: + client_num = 0 + client_list = None + else: + client_num = len(self.__swt[i]) + client_list = self.__swt[i] + + if client_num <= 1: + fp.write("\t{ },\n") + else: + fp.write(f"\t{{ .client_num = {client_num}, .clients = {{ ") + for j in range(0, client_num): + routine = client_list[j][1] + arg = client_list[j][0] + + fp.write(f"{{ .isr = (ISR){ hex(routine) if isinstance(routine, int) else routine }, " + f".arg = (const void *){hex(arg)} }},") + + fp.write(" },\n},\n") + + fp.write("};\n") + + def write_source(self, fp): + fp.write(self.source_header) + + if self.__config.check_shared_interrupts(): + self.__write_shared_table(fp) + + if self.__vt: + if self.__config.check_sym("CONFIG_IRQ_VECTOR_TABLE_JUMP_BY_ADDRESS"): + self.__write_address_irq_vector_table(fp) + elif self.__config.check_sym("CONFIG_IRQ_VECTOR_TABLE_JUMP_BY_CODE"): + self.__write_code_irq_vector_table(fp) + else: + self.__log.error("CONFIG_IRQ_VECTOR_TABLE_JUMP_BY_{ADDRESS,CODE} not set") + + if not self.__swt: + return + + fp.write("struct _isr_table_entry __sw_isr_table _sw_isr_table[%d] = {\n" + % self.__nv) + + level2_offset = self.__config.get_irq_baseoffset(2) + level3_offset = self.__config.get_irq_baseoffset(3) + + for i in range(self.__nv): + if len(self.__swt[i]) == 0: + # Not used interrupt + param = "0x0" + func = self.__config.swt_spurious_handler + elif len(self.__swt[i]) == 1: + # Single interrupt + param = "{0:#x}".format(self.__swt[i][0][0]) + func = self.__swt[i][0][1] + else: + # Shared interrupt + param = "&z_shared_sw_isr_table[{0}]".format(i) + func = self.__config.swt_shared_handler + + if isinstance(func, int): + func_as_string = "{0:#x}".format(func) + else: + func_as_string = func + + if level2_offset is not None and i == level2_offset: + fp.write("\t/* Level 2 interrupts start here (offset: {}) */\n". + format(level2_offset)) + if level3_offset is not None and i == level3_offset: + fp.write("\t/* Level 3 interrupts start here (offset: {}) */\n". + format(level3_offset)) + + fp.write("\t{{(const void *){0}, (ISR){1}}}, /* {2} */\n".format(param, func_as_string, i)) + fp.write("};\n") diff --git a/scripts/build/gen_isr_tables_parser_local.py b/scripts/build/gen_isr_tables_parser_local.py new file mode 100644 index 00000000000..91bd4a65471 --- /dev/null +++ b/scripts/build/gen_isr_tables_parser_local.py @@ -0,0 +1,375 @@ +#!/usr/bin/env python3 +# +# Copyright (c) 2017 Intel Corporation +# Copyright (c) 2018 Foundries.io +# Copyright (c) 2023 Nordic Semiconductor NA +# +# SPDX-License-Identifier: Apache-2.0 +# + +import struct + +class gen_isr_parser: + source_header = """ +/* AUTO-GENERATED by gen_isr_tables.py, do not edit! */ + +#include +#include +#include +#include + +""" + + shared_isr_table_header = """ + +/* For this parser to work, we have to be sure that shared interrupts table entry + * and the normal isr table entry have exactly the same layout + */ +BUILD_ASSERT(sizeof(struct _isr_table_entry) + == + sizeof(struct z_shared_isr_table_entry), + "Shared ISR and ISR table entries layout do not match"); +BUILD_ASSERT(offsetof(struct _isr_table_entry, arg) + == + offsetof(struct z_shared_isr_table_entry, arg), + "Shared ISR and ISR table entries layout do not match"); +BUILD_ASSERT(offsetof(struct _isr_table_entry, isr) + == + offsetof(struct z_shared_isr_table_entry, isr), + "Shared ISR and ISR table entries layout do not match"); + +""" + + def __init__(self, intlist_data, config, log): + """Initialize the parser. + + The function prepares parser to work. + Parameters: + - intlist_data: The binnary data from intlist section + - config: The configuration object + - log: The logging object, has to have error and debug methods + """ + self.__config = config + self.__log = log + intlist = self.__read_intlist(intlist_data) + self.__vt, self.__swt, self.__nv, header = self.__parse_intlist(intlist) + self.__swi_table_entry_size = header["swi_table_entry_size"] + self.__shared_isr_table_entry_size = header["shared_isr_table_entry_size"] + self.__shared_isr_client_num_offset = header["shared_isr_client_num_offset"] + + def __read_intlist(self, intlist_data): + """read an intList section from the elf file. + This is version 2 of a header created by include/zephyr/linker/intlist.ld: + + struct { + uint32_t num_vectors; <- typically CONFIG_NUM_IRQS + uint8_t stream[]; <- the stream with the interrupt data + }; + + The stream is contained from variable length records in a form: + + struct _isr_list_sname { + /** IRQ line number */ + int32_t irq; + /** Flags for this IRQ, see ISR_FLAG_* definitions */ + int32_t flags; + /** The section name */ + const char sname[]; + }; + + The flexible array member here (sname) contains the name of the section where the structure + with interrupt data is located. + It is always Null-terminated string thus we have to search through the input data for the + structure end. + + """ + intlist = {} + prefix = self.__config.endian_prefix() + + # Extract header and the rest of the data + intlist_header_fmt = prefix + "IIIII" + header_sz = struct.calcsize(intlist_header_fmt) + header_raw = struct.unpack_from(intlist_header_fmt, intlist_data, 0) + self.__log.debug(str(header_raw)) + + intlist["num_vectors"] = header_raw[0] + intlist["offset"] = header_raw[1] + intlist["swi_table_entry_size"] = header_raw[2] + intlist["shared_isr_table_entry_size"] = header_raw[3] + intlist["shared_isr_client_num_offset"] = header_raw[4] + + intdata = intlist_data[header_sz:] + + # Extract information about interrupts + intlist_entry_fmt = prefix + "ii" + entry_sz = struct.calcsize(intlist_entry_fmt) + intlist["interrupts"] = [] + + while len(intdata) > entry_sz: + entry_raw = struct.unpack_from(intlist_entry_fmt, intdata, 0) + intdata = intdata[entry_sz:] + null_idx = intdata.find(0) + if null_idx < 0: + self.__log.error("Cannot find sname null termination at IRQ{}".format(entry_raw[0])) + bname = intdata[:null_idx] + # Next structure starts with 4B alignment + next_idx = null_idx + 1 + next_idx = (next_idx + 3) & ~3 + intdata = intdata[next_idx:] + sname = bname.decode() + intlist["interrupts"].append([entry_raw[0], entry_raw[1], sname]) + self.__log.debug("Unpacked IRQ{}, flags: {}, sname: \"{}\"\n".format( + entry_raw[0], entry_raw[1], sname)) + + # If any data left at the end - it has to be all the way 0 - this is just a check + if (len(intdata) and not all([d == 0 for d in intdata])): + self.__log.error("Non-zero data found at the end of the intList data.\n") + + self.__log.debug("Configured interrupt routing with linker") + self.__log.debug("irq flags sname") + self.__log.debug("--------------------------") + + for irq in intlist["interrupts"]: + self.__log.debug("{0:<3} {1:<5} {2}".format( + hex(irq[0]), irq[1], irq[2])) + + return intlist + + def __parse_intlist(self, intlist): + """All the intlist data are parsed into swt and vt arrays. + + The vt array is prepared for hardware interrupt table. + Every entry in the selected position would contain None or the name of the function pointer + (address or string). + + The swt is a little more complex. At every position it would contain an array of parameter and + function pointer pairs. If CONFIG_SHARED_INTERRUPTS is enabled there may be more than 1 entry. + If empty array is placed on selected position - it means that the application does not implement + this interrupt. + + Parameters: + - intlist: The preprocessed list of intlist section content (see read_intlist) + + Return: + vt, swt - parsed vt and swt arrays (see function description above) + """ + nvec = intlist["num_vectors"] + offset = intlist["offset"] + header = { + "swi_table_entry_size": intlist["swi_table_entry_size"], + "shared_isr_table_entry_size": intlist["shared_isr_table_entry_size"], + "shared_isr_client_num_offset": intlist["shared_isr_client_num_offset"] + } + + if nvec > pow(2, 15): + raise ValueError('nvec is too large, check endianness.') + + self.__log.debug('offset is ' + str(offset)) + self.__log.debug('num_vectors is ' + str(nvec)) + + # Set default entries in both tables + if not(self.__config.args.sw_isr_table or self.__config.args.vector_table): + self.__log.error("one or both of -s or -V needs to be specified on command line") + if self.__config.args.vector_table: + vt = [None for i in range(nvec)] + else: + vt = None + if self.__config.args.sw_isr_table: + swt = [[] for i in range(nvec)] + else: + swt = None + + # Process intlist and write to the tables created + for irq, flags, sname in intlist["interrupts"]: + if self.__config.test_isr_direct(flags): + if not 0 <= irq - offset < len(vt): + self.__log.error("IRQ %d (offset=%d) exceeds the maximum of %d" % + (irq - offset, offset, len(vt) - 1)) + vt[irq - offset] = sname + else: + # Regular interrupt + if not swt: + self.__log.error("Regular Interrupt %d declared with section name %s " + "but no SW ISR_TABLE in use" + % (irq, sname)) + + table_index = self.__config.get_swt_table_index(offset, irq) + + if not 0 <= table_index < len(swt): + self.__log.error("IRQ %d (offset=%d) exceeds the maximum of %d" % + (table_index, offset, len(swt) - 1)) + # Check if the given section name does not repeat outside of current interrupt + for i in range(nvec): + if i == irq: + continue + if sname in swt[i]: + self.__log.error(("Attempting to register the same section name \"{}\"for" + + "different interrupts: {} and {}").format(sname, i, irq)) + if self.__config.check_shared_interrupts(): + lst = swt[table_index] + if len(lst) >= self.__config.get_sym("CONFIG_SHARED_IRQ_MAX_NUM_CLIENTS"): + self.__log.error(f"Reached shared interrupt client limit. Maybe increase" + + f" CONFIG_SHARED_IRQ_MAX_NUM_CLIENTS?") + else: + if len(swt[table_index]) > 0: + self.__log.error(f"multiple registrations at table_index {table_index} for irq {irq} (0x{irq:x})" + + f"\nExisting section {swt[table_index]}, new section {sname}" + + "\nHas IRQ_CONNECT or IRQ_DIRECT_CONNECT accidentally been invoked on the same irq multiple times?" + ) + swt[table_index].append(sname) + + return vt, swt, nvec, header + + @staticmethod + def __irq_spurious_section(irq): + return '.irq_spurious.0x{:x}'.format(irq) + + @staticmethod + def __isr_generated_section(irq): + return '.isr_generated.0x{:x}'.format(irq) + + @staticmethod + def __shared_entry_section(irq, ent): + return '.isr_shared.0x{:x}_0x{:x}'.format(irq, ent) + + @staticmethod + def __shared_client_num_section(irq): + return '.isr_shared.0x{:x}_client_num'.format(irq) + + def __isr_spurious_entry(self, irq): + return '_Z_ISR_TABLE_ENTRY({irq}, {func}, NULL, "{sect}");'.format( + irq = irq, + func = self.__config.swt_spurious_handler, + sect = self.__isr_generated_section(irq) + ) + + def __isr_shared_entry(self, irq): + return '_Z_ISR_TABLE_ENTRY({irq}, {func}, {arg}, "{sect}");'.format( + irq = irq, + arg = '&{}[{}]'.format(self.__config.shared_array_name, irq), + func = self.__config.swt_shared_handler, + sect = self.__isr_generated_section(irq) + ) + + def __irq_spurious_entry(self, irq): + return '_Z_ISR_DIRECT_TABLE_ENTRY({irq}, {func}, "{sect}");'.format( + irq = irq, + func = self.__config.vt_default_handler, + sect = self.__irq_spurious_section(irq) + ) + + def __write_isr_handlers(self, fp): + for i in range(self.__nv): + if len(self.__swt[i]) <= 0: + fp.write(self.__isr_spurious_entry(i) + '\n') + elif len(self.__swt[i]) > 1: + # Connect to shared handlers + fp.write(self.__isr_shared_entry(i) + '\n') + else: + fp.write('/* ISR: {} implemented in app in "{}" section. */\n'.format( + i, self.__swt[i][0])) + + def __write_irq_handlers(self, fp): + for i in range(self.__nv): + if self.__vt[i] is None: + fp.write(self.__irq_spurious_entry(i) + '\n') + else: + fp.write('/* ISR: {} implemented in app. */\n'.format(i)) + + def __write_shared_handlers(self, fp): + fp.write("extern struct z_shared_isr_table_entry " + "{}[{}];\n".format(self.__config.shared_array_name, self.__nv)) + + shared_cnt = self.__config.get_sym('CONFIG_SHARED_IRQ_MAX_NUM_CLIENTS') + for i in range(self.__nv): + swt_len = len(self.__swt[i]) + for j in range(shared_cnt): + if (swt_len <= 1) or (swt_len <= j): + # Add all unused entry + fp.write('static Z_DECL_ALIGN(struct _isr_table_entry)\n' + + '\tZ_GENERIC_SECTION({})\n'.format(self.__shared_entry_section(i, j)) + + '\t__used isr_shared_empty_entry_0x{:x}_0x{:x} = {{\n'.format(i, j) + + '\t\t.arg = (const void *)NULL,\n' + + '\t\t.isr = (void (*)(const void *))(void *)0\n' + + '};\n' + ) + else: + # Add information about entry implemented by application + fp.write('/* Shared isr {} entry {} implemented in "{}" section*/\n'.format( + i, j, self.__swt[i][j])) + + # Add information about clients count + fp.write(('static size_t Z_GENERIC_SECTION({}) __used\n' + + 'isr_shared_client_num_0x{:x} = {};\n\n').format( + self.__shared_client_num_section(i), + i, + 0 if swt_len < 2 else swt_len) + ) + + def write_source(self, fp): + fp.write(self.source_header) + + if self.__vt: + self.__write_irq_handlers(fp) + + if not self.__swt: + return + + if self.__config.check_shared_interrupts(): + self.__write_shared_handlers(fp) + + self.__write_isr_handlers(fp) + + def __write_linker_irq(self, fp): + fp.write('{} = .;\n'.format(self.__config.irq_vector_array_name)) + for i in range(self.__nv): + if self.__vt[i] is None: + sname = self.__irq_spurious_section(i) + else: + sname = self.__vt[i] + fp.write('KEEP(*("{}"))\n'.format(sname)) + + def __write_linker_shared(self, fp): + fp.write(". = ALIGN({});\n".format(self.__shared_isr_table_entry_size)) + fp.write('{} = .;\n'.format(self.__config.shared_array_name)) + shared_cnt = self.__config.get_sym('CONFIG_SHARED_IRQ_MAX_NUM_CLIENTS') + client_num_pads = self.__shared_isr_client_num_offset - \ + shared_cnt * self.__swi_table_entry_size + if client_num_pads < 0: + self.__log.error("Invalid __shared_isr_client_num_offset header value") + for i in range(self.__nv): + swt_len = len(self.__swt[i]) + # Add all entries + for j in range(shared_cnt): + if (swt_len <= 1) or (swt_len <= j): + fp.write('KEEP(*("{}"))\n'.format(self.__shared_entry_section(i, j))) + else: + sname = self.__swt[i][j] + if (j != 0) and (sname in self.__swt[i][0:j]): + fp.write('/* Repetition of "{}" section */\n'.format(sname)) + else: + fp.write('KEEP(*("{}"))\n'.format(sname)) + fp.write('. = . + {};\n'.format(client_num_pads)) + fp.write('KEEP(*("{}"))\n'.format(self.__shared_client_num_section(i))) + fp.write(". = ALIGN({});\n".format(self.__shared_isr_table_entry_size)) + + def __write_linker_isr(self, fp): + fp.write(". = ALIGN({});\n".format(self.__swi_table_entry_size)) + fp.write('{} = .;\n'.format(self.__config.sw_isr_array_name)) + for i in range(self.__nv): + if (len(self.__swt[i])) == 1: + sname = self.__swt[i][0] + else: + sname = self.__isr_generated_section(i) + fp.write('KEEP(*("{}"))\n'.format(sname)) + + def write_linker_vt(self, fp): + if self.__vt: + self.__write_linker_irq(fp) + + def write_linker_swi(self, fp): + if self.__swt: + self.__write_linker_isr(fp) + + if self.__config.check_shared_interrupts(): + self.__write_linker_shared(fp) From 13638a03519db634c519a6511b9719f6d6f6b674 Mon Sep 17 00:00:00 2001 From: Radoslaw Koppel Date: Tue, 17 Oct 2023 17:41:17 +0200 Subject: [PATCH 3444/3723] arch: sw_isr_table: Implement local interrupt table entry creation MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This commit implements the possibility to locally create an interrupt table entry. This changes the way interrput table is created, now it should not be created as an source file but rather it would be constructed by the linker. Signed-off-by: Radosław Koppel --- arch/Kconfig | 23 +++++++ include/zephyr/sw_isr_table.h | 114 ++++++++++++++++++++++++++++++++++ 2 files changed, 137 insertions(+) diff --git a/arch/Kconfig b/arch/Kconfig index b8661fa5964..39800a1b7b7 100644 --- a/arch/Kconfig +++ b/arch/Kconfig @@ -391,6 +391,29 @@ config NOCACHE_MEMORY menu "Interrupt Configuration" +config ISR_TABLES_LOCAL_DECLARATION_SUPPORTED + bool + default y + # Userspace is currently not supported + depends on !USERSPACE + # List of currently supported architectures + depends on ARM || ARM64 + # List of currently supported toolchains + depends on "$(ZEPHYR_TOOLCHAIN_VARIANT)" = "zephyr" || "$(ZEPHYR_TOOLCHAIN_VARIANT)" = "gnuarmemb" + +config ISR_TABLES_LOCAL_DECLARATION + bool "ISR tables created locally and placed by linker [EXPERIMENTAL]" + depends on ISR_TABLES_LOCAL_DECLARATION_SUPPORTED + select EXPERIMENTAL + help + Enable new scheme of interrupt tables generation. + This is totally different generator that would create tables entries locally + where the IRQ_CONNECT macro is called and then use the linker script to position it + in the right place in memory. + The most important advantage of such approach is that the generated interrupt tables + are LTO compatible. + The drawback is that the support on the architecture port is required. + config DYNAMIC_INTERRUPTS bool "Installation of IRQs at runtime" help diff --git a/include/zephyr/sw_isr_table.h b/include/zephyr/sw_isr_table.h index fc094b887ba..7b1bfddb2cb 100644 --- a/include/zephyr/sw_isr_table.h +++ b/include/zephyr/sw_isr_table.h @@ -18,6 +18,7 @@ #include #include #include +#include #ifdef __cplusplus extern "C" { @@ -56,6 +57,9 @@ struct _irq_parent_entry { * uses it to create the IRQ vector table and the _sw_isr_table. * * More discussion in include/linker/intlist.ld + * + * This is a version used when CONFIG_ISR_TABLES_LOCAL_DECLARATION is disabled. + * See _isr_list_sname used otherwise. */ struct _isr_list { /** IRQ line number */ @@ -68,6 +72,24 @@ struct _isr_list { const void *param; }; +/* + * Data structure created in a special binary .intlist section for each + * configured interrupt. gen_isr_tables.py pulls this out of the binary and + * uses it to create linker script chunks that would place interrupt table entries + * in the right place in the memory. + * + * This is a version used when CONFIG_ISR_TABLES_LOCAL_DECLARATION is enabled. + * See _isr_list used otherwise. + */ +struct _isr_list_sname { + /** IRQ line number */ + int32_t irq; + /** Flags for this IRQ, see ISR_FLAG_* definitions */ + int32_t flags; + /** The section name */ + const char sname[]; +}; + #ifdef CONFIG_SHARED_INTERRUPTS struct z_shared_isr_table_entry { struct _isr_table_entry clients[CONFIG_SHARED_IRQ_MAX_NUM_CLIENTS]; @@ -85,6 +107,90 @@ extern struct z_shared_isr_table_entry z_shared_sw_isr_table[]; #define _MK_ISR_NAME(x, y) __MK_ISR_NAME(x, y) #define __MK_ISR_NAME(x, y) __isr_ ## x ## _irq_ ## y + +#if IS_ENABLED(CONFIG_ISR_TABLES_LOCAL_DECLARATION) + +#define _MK_ISR_ELEMENT_NAME(func, id) __MK_ISR_ELEMENT_NAME(func, id) +#define __MK_ISR_ELEMENT_NAME(func, id) __isr_table_entry_ ## func ## _irq_ ## id + +#define _MK_IRQ_ELEMENT_NAME(func, id) __MK_ISR_ELEMENT_NAME(func, id) +#define __MK_IRQ_ELEMENT_NAME(func, id) __irq_table_entry_ ## func ## _irq_ ## id + +#define _MK_ISR_SECTION_NAME(prefix, file, counter) \ + "." Z_STRINGIFY(prefix)"."file"." Z_STRINGIFY(counter) + +#define _MK_ISR_ELEMENT_SECTION(counter) _MK_ISR_SECTION_NAME(irq, __FILE__, counter) +#define _MK_IRQ_ELEMENT_SECTION(counter) _MK_ISR_SECTION_NAME(isr, __FILE__, counter) + +/* Separated macro to create ISR table entry only. + * Used by Z_ISR_DECLARE and ISR tables generation script. + */ +#define _Z_ISR_TABLE_ENTRY(irq, func, param, sect) \ + static Z_DECL_ALIGN(struct _isr_table_entry) \ + __attribute__((section(sect))) \ + __used _MK_ISR_ELEMENT_NAME(func, __COUNTER__) = { \ + .arg = (const void *)(param), \ + .isr = (void (*)(const void *))(void *)(func) \ + } + +#define Z_ISR_DECLARE_C(irq, flags, func, param, counter) \ + _Z_ISR_DECLARE_C(irq, flags, func, param, counter) + +#define _Z_ISR_DECLARE_C(irq, flags, func, param, counter) \ + _Z_ISR_TABLE_ENTRY(irq, func, param, _MK_ISR_ELEMENT_SECTION(counter)); \ + static struct _isr_list_sname Z_GENERIC_SECTION(.intList) \ + __used _MK_ISR_NAME(func, counter) = \ + {irq, flags, _MK_ISR_ELEMENT_SECTION(counter)} + +/* Create an entry for _isr_table to be then placed by the linker. + * An instance of struct _isr_list which gets put in the .intList + * section is created with the name of the section where _isr_table entry is placed to be then + * used by isr generation script to create linker script chunk. + */ +#define Z_ISR_DECLARE(irq, flags, func, param) \ + BUILD_ASSERT(((flags) & ISR_FLAG_DIRECT) == 0, "Use Z_ISR_DECLARE_DIRECT macro"); \ + Z_ISR_DECLARE_C(irq, flags, func, param, __COUNTER__) + + +/* Separated macro to create ISR Direct table entry only. + * Used by Z_ISR_DECLARE_DIRECT and ISR tables generation script. + */ +#define _Z_ISR_DIRECT_TABLE_ENTRY(irq, func, sect) \ + COND_CODE_1(CONFIG_IRQ_VECTOR_TABLE_JUMP_BY_ADDRESS, ( \ + static Z_DECL_ALIGN(uintptr_t) \ + __attribute__((section(sect))) \ + __used _MK_IRQ_ELEMENT_NAME(func, __COUNTER__) = ((uintptr_t)(func)); \ + ), ( \ + static void __attribute__((section(sect))) __attribute__((naked)) \ + __used _MK_IRQ_ELEMENT_NAME(func, __COUNTER__)(void) { \ + __asm(ARCH_IRQ_VECTOR_JUMP_CODE(func)); \ + } \ + )) + +#define Z_ISR_DECLARE_DIRECT_C(irq, flags, func, counter) \ + _Z_ISR_DECLARE_DIRECT_C(irq, flags, func, counter) + +#define _Z_ISR_DECLARE_DIRECT_C(irq, flags, func, counter) \ + _Z_ISR_DIRECT_TABLE_ENTRY(irq, func, _MK_IRQ_ELEMENT_SECTION(counter)); \ + static struct _isr_list_sname Z_GENERIC_SECTION(.intList) \ + __used _MK_ISR_NAME(func, counter) = { \ + irq, \ + ISR_FLAG_DIRECT | (flags), \ + _MK_IRQ_ELEMENT_SECTION(counter)} + +/* Create an entry to irq table and place it in specific section which name is then placed + * in an instance of struct _isr_list to be then used by the isr generation script to create + * the linker script chunks. + */ +#define Z_ISR_DECLARE_DIRECT(irq, flags, func) \ + BUILD_ASSERT(IS_ENABLED(CONFIG_IRQ_VECTOR_TABLE_JUMP_BY_ADDRESS) || \ + IS_ENABLED(CONFIG_IRQ_VECTOR_TABLE_JUMP_BY_CODE), \ + "CONFIG_IRQ_VECTOR_TABLE_JUMP_BY_{ADDRESS,CODE} not set"); \ + Z_ISR_DECLARE_DIRECT_C(irq, flags, func, __COUNTER__) + + +#else /* IS_ENABLED(CONFIG_ISR_TABLES_LOCAL_DECLARATION) */ + /* Create an instance of struct _isr_list which gets put in the .intList * section. This gets consumed by gen_isr_tables.py which creates the vector * and/or SW ISR tables. @@ -94,6 +200,14 @@ extern struct z_shared_isr_table_entry z_shared_sw_isr_table[]; __used _MK_ISR_NAME(func, __COUNTER__) = \ {irq, flags, (void *)&func, (const void *)param} +/* The version of the Z_ISR_DECLARE that should be used for direct ISR declaration. + * It is here for the API match the version with CONFIG_ISR_TABLES_LOCAL_DECLARATION enabled. + */ +#define Z_ISR_DECLARE_DIRECT(irq, flags, func) \ + Z_ISR_DECLARE(irq, ISR_FLAG_DIRECT | (flags), func, NULL) + +#endif + #define IRQ_TABLE_SIZE (CONFIG_NUM_IRQS - CONFIG_GEN_IRQ_START_VECTOR) #ifdef CONFIG_DYNAMIC_INTERRUPTS From 19bb21ef6d95a850f598822c7d4a872f8f127a9a Mon Sep 17 00:00:00 2001 From: Radoslaw Koppel Date: Thu, 1 Feb 2024 16:34:55 +0100 Subject: [PATCH 3445/3723] doc: kernel: interrupts: Description of the local isr declaration MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This commit adds a documentation about the new parser of the interrupt vectors tables that is using linker to construct the arrays with all the runtime required data. Signed-off-by: Radosław Koppel --- doc/kernel/services/interrupts.rst | 120 ++++++++++++++++++++++++++++- 1 file changed, 117 insertions(+), 3 deletions(-) diff --git a/doc/kernel/services/interrupts.rst b/doc/kernel/services/interrupts.rst index 05e4809e568..ea1f7935197 100644 --- a/doc/kernel/services/interrupts.rst +++ b/doc/kernel/services/interrupts.rst @@ -457,6 +457,38 @@ Interrupt tables are set up at build time using some special build tools. The details laid out here apply to all architectures except x86, which are covered in the `x86 Details`_ section below. +The invocation of :c:macro:`IRQ_CONNECT` will declare an instance of +struct _isr_list wich is placed in a special .intList section. +This section is placed in compiled code on precompilation stages only. +It is meant to be used by Zephyr script to generate interrupt tables +and is removed from the final build. +The script implements different parsers to process the data from .intList section +and produce the required output. + +The default parser generates C arrays filled with arguments and interrupt +handlers in a form of addresses directly taken from .intList section entries. +It works with all the architectures and compillers (with the exception mentioned above). +The limitation of this parser is the fact that after the arrays are generated +it is expected for the code not to relocate. +Any relocation on this stage may lead to the situation where the entry in the interrupt array +is no longer pointing to the function that was expected. +It means that this parser, being more compatible is limiting us from using Link Time Optimization. + +The local isr declaration parser uses different approach to construct +the same arrays at binnary level. +All the entries to the arrays are declared and defined locally, +directly in the file where :c:macro:`IRQ_CONNECT` is used. +They are placed in a section with the unique, synthetized name. +The name of the section is then placed in .intList section and it is used to create linker script +to properly place the created entry in the right place in the memory. +This parser is now limited to the supported architectures and toolchains but in reward it keeps +the information about object relations for linker thus allowing the Link Time Optimization. + +Implementation using C arrays +----------------------------- + +This is the default configuration available for all Zephyr supported architectures. + Any invocation of :c:macro:`IRQ_CONNECT` will declare an instance of struct _isr_list which is placed in a special .intList section: @@ -500,7 +532,7 @@ do not support the notion of interrupt priority, in which case the priority argument is ignored. Vector Table ------------- +~~~~~~~~~~~~ A vector table is generated when :kconfig:option:`CONFIG_GEN_IRQ_VECTOR_TABLE` is enabled. This data structure is used natively by the CPU and is simply an array of function pointers, where each element n corresponds to the IRQ handler @@ -527,7 +559,7 @@ CONFIG_GEN_IRQ_START_VECTOR needs to be set to properly offset the indices in the table. SW ISR Table ------------- +~~~~~~~~~~~~ This is an array of struct _isr_table_entry: .. code-block:: c @@ -542,7 +574,7 @@ argument and execute it. The active IRQ line is looked up in an interrupt controller register and used to index this table. Shared SW ISR Table -------------------- +~~~~~~~~~~~~~~~~~~~ This is an array of struct z_shared_isr_table_entry: @@ -558,6 +590,88 @@ lines. Whenever an interrupt line becomes shared, :c:func:`z_shared_isr` will replace the currently registered ISR in _sw_isr_table. This special ISR will iterate through the list of registered clients and invoke the ISRs. +Implementation using linker script +---------------------------------- + +This way of prepare and parse .isrList section to implement interrupt vectors arrays +is called local isr declaration. +The name comes from the fact that all the entries to the arrays that would create +interrupt vectors are created locally in place of invocation of :c:macro:`IRQ_CONNECT` macro. +Then automatically generated linker scripts are used to place it in the right place in the memory. + +This option requires enabling by the choose of :kconfig:option:`ISR_TABLES_LOCAL_DECLARATION`. +If this configuration is supported by the used architecture and toolchaing the +:kconfig:option:`ISR_TABLES_LOCAL_DECLARATION_SUPPORTED` is set. +See defails of this option for the information about currently supported configurations. + +Any invocation of :c:macro:`IRQ_CONNECT` or `IRQ_DIRECT_CONNECT` will declare an instance of struct +_isr_list_sname which is placde in a special .intList section: + +.. code-block:: c + + struct _isr_list_sname { + /** IRQ line number */ + int32_t irq; + /** Flags for this IRQ, see ISR_FLAG_* definitions */ + int32_t flags; + /** The section name */ + const char sname[]; + }; + +Note that the section name is placed in flexible array member. +It means that the size of the initialized structure will warry depending on the +structure name length. +The whole entry is used by the script during the build of the application +and has all the information needed for proper interrupt placement. + +Beside of the _isr_list_sname the :c:macro:`IRQ_CONNECT` macro generates an entry +that would be the part of the interrupt array: + +.. code-block:: c + + struct _isr_table_entry { + const void *arg; + void (*isr)(const void *); + }; + +This array is placed in a section with the name saved in _isr_list_sname structure. + +The values created by :c:macro:`IRQ_DIRECT_CONNECT` macro depends on the architecture. +It can be changed to variable that points to a interrupt handler: + +.. code-block:: c + + static uintptr_t = ((uintptr_t)func); + +Or to actuall naked function that implements a jump to the interrupt handler: + +.. code-block:: c + + static void (void) + { + __asm(ARCH_IRQ_VECTOR_JUMP_CODE(func)); + } + +Simillar like for :c:macro:`IRQ_CONNECT`, the created variable or function is placed +in a section, saved in _isr_list_sname section. + +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. + +The 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 +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 +elements. The separated file is required as it might be placed in writable on nonwritable +section, depending on the current configuration. + x86 Details ----------- From 8174c7e049414747ad9077a6da5c608ad0ef61c6 Mon Sep 17 00:00:00 2001 From: Radoslaw Koppel Date: Fri, 22 Dec 2023 14:44:15 +0100 Subject: [PATCH 3446/3723] arch: irq: Use Z_ISR_DECLARE_DIRECT for direct ISR declaration. MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This commit changes the way how ARCH_IRQ_DIRECT_CONNECT is defined. Now it uses Z_ISR_DECLARE_DIRECT internally. That is a requirement for local isr declaration. Signed-off-by: Radosław Koppel --- include/zephyr/arch/arc/v2/irq.h | 2 +- include/zephyr/arch/arm/irq.h | 2 +- include/zephyr/arch/riscv/irq.h | 4 ++-- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/include/zephyr/arch/arc/v2/irq.h b/include/zephyr/arch/arc/v2/irq.h index e0b42549597..45b9d138857 100644 --- a/include/zephyr/arch/arc/v2/irq.h +++ b/include/zephyr/arch/arc/v2/irq.h @@ -77,7 +77,7 @@ extern void z_irq_priority_set(unsigned int irq, unsigned int prio, */ #define ARCH_IRQ_DIRECT_CONNECT(irq_p, priority_p, isr_p, flags_p) \ { \ - Z_ISR_DECLARE(irq_p, ISR_FLAG_DIRECT, isr_p, NULL); \ + Z_ISR_DECLARE_DIRECT(irq_p, ISR_FLAG_DIRECT, isr_p); \ BUILD_ASSERT(priority_p || !IS_ENABLED(CONFIG_ARC_FIRQ) || \ (IS_ENABLED(CONFIG_ARC_FIRQ_STACK) && \ !IS_ENABLED(CONFIG_ARC_STACK_CHECKING)), \ diff --git a/include/zephyr/arch/arm/irq.h b/include/zephyr/arch/arm/irq.h index 42a2a364fb3..31cfce1e667 100644 --- a/include/zephyr/arch/arm/irq.h +++ b/include/zephyr/arch/arm/irq.h @@ -127,7 +127,7 @@ extern void z_arm_interrupt_init(void); BUILD_ASSERT(IS_ENABLED(CONFIG_ZERO_LATENCY_IRQS) || !(flags_p & IRQ_ZERO_LATENCY), \ "ZLI interrupt registered but feature is disabled"); \ _CHECK_PRIO(priority_p, flags_p) \ - Z_ISR_DECLARE(irq_p, ISR_FLAG_DIRECT, isr_p, NULL); \ + Z_ISR_DECLARE_DIRECT(irq_p, ISR_FLAG_DIRECT, isr_p); \ z_arm_irq_priority_set(irq_p, priority_p, flags_p); \ } diff --git a/include/zephyr/arch/riscv/irq.h b/include/zephyr/arch/riscv/irq.h index c3764f8289b..3d81415e0d7 100644 --- a/include/zephyr/arch/riscv/irq.h +++ b/include/zephyr/arch/riscv/irq.h @@ -69,8 +69,8 @@ extern void z_riscv_irq_priority_set(unsigned int irq, #define ARCH_IRQ_DIRECT_CONNECT(irq_p, priority_p, isr_p, flags_p) \ { \ - Z_ISR_DECLARE(irq_p + CONFIG_RISCV_RESERVED_IRQ_ISR_TABLES_OFFSET, \ - ISR_FLAG_DIRECT, isr_p, NULL); \ + Z_ISR_DECLARE_DIRECT(irq_p + CONFIG_RISCV_RESERVED_IRQ_ISR_TABLES_OFFSET, \ + ISR_FLAG_DIRECT, isr_p); \ z_riscv_irq_priority_set(irq_p, priority_p, flags_p); \ } From 1ff24b34ebe568a5d606928af69914de946b9762 Mon Sep 17 00:00:00 2001 From: Radoslaw Koppel Date: Tue, 19 Dec 2023 16:54:18 +0100 Subject: [PATCH 3447/3723] arch: arm: Update to support local ISR declaration MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This commit updates the arm and arm64 architecture files to support the new ISR handlers creation parser. Signed-off-by: Radosław Koppel --- arch/arm/core/CMakeLists.txt | 8 ++++++++ arch/arm/core/swi_tables.ld | 8 ++++++++ arch/arm/core/vector_table.ld | 4 ++++ arch/arm64/core/CMakeLists.txt | 8 ++++++++ arch/arm64/core/swi_tables.ld | 8 ++++++++ arch/common/CMakeLists.txt | 5 +++++ include/zephyr/arch/arm64/scripts/linker.ld | 5 ++++- include/zephyr/linker/irq-vector-table-section.ld | 2 ++ include/zephyr/linker/isr-local-drop-unused.ld | 9 +++++++++ 9 files changed, 56 insertions(+), 1 deletion(-) create mode 100644 arch/arm/core/swi_tables.ld create mode 100644 arch/arm64/core/swi_tables.ld create mode 100644 include/zephyr/linker/isr-local-drop-unused.ld diff --git a/arch/arm/core/CMakeLists.txt b/arch/arm/core/CMakeLists.txt index 41e3dc485ff..922dab2ddba 100644 --- a/arch/arm/core/CMakeLists.txt +++ b/arch/arm/core/CMakeLists.txt @@ -35,3 +35,11 @@ else() zephyr_linker_sources(ROM_START SORT_KEY 0x0vectors vector_table.ld) zephyr_linker_sources(ROM_START SORT_KEY 0x1vectors cortex_m/vector_table_pad.ld) endif() + +if(CONFIG_GEN_SW_ISR_TABLE) + if(CONFIG_DYNAMIC_INTERRUPTS) + zephyr_linker_sources(RWDATA swi_tables.ld) + else() + zephyr_linker_sources(RODATA swi_tables.ld) + endif() +endif() diff --git a/arch/arm/core/swi_tables.ld b/arch/arm/core/swi_tables.ld new file mode 100644 index 00000000000..c6ca94604dd --- /dev/null +++ b/arch/arm/core/swi_tables.ld @@ -0,0 +1,8 @@ +/* + * Copyright (c) 2023 Nordic Semiconductor ASA + * + * SPDX-License-Identifier: Apache-2.0 + */ +#if LINKER_ZEPHYR_FINAL +INCLUDE zephyr/isr_tables_swi.ld +#endif diff --git a/arch/arm/core/vector_table.ld b/arch/arm/core/vector_table.ld index 615067dbf74..58210afdcbc 100644 --- a/arch/arm/core/vector_table.ld +++ b/arch/arm/core/vector_table.ld @@ -51,6 +51,10 @@ _vector_start = .; KEEP(*(.exc_vector_table)) KEEP(*(".exc_vector_table.*")) +#if LINKER_ZEPHYR_FINAL && CONFIG_ISR_TABLES_LOCAL_DECLARATION +INCLUDE zephyr/isr_tables_vt.ld +#else KEEP(*(.vectors)) +#endif _vector_end = .; diff --git a/arch/arm64/core/CMakeLists.txt b/arch/arm64/core/CMakeLists.txt index 1804556c1a7..05e4be8c0ea 100644 --- a/arch/arm64/core/CMakeLists.txt +++ b/arch/arm64/core/CMakeLists.txt @@ -55,3 +55,11 @@ if(CMAKE_C_COMPILER_ID STREQUAL "GNU") endif() add_subdirectory_ifdef(CONFIG_XEN xen) + +if(CONFIG_GEN_SW_ISR_TABLE) + if(CONFIG_DYNAMIC_INTERRUPTS) + zephyr_linker_sources(RWDATA swi_tables.ld) + else() + zephyr_linker_sources(RODATA swi_tables.ld) + endif() +endif() diff --git a/arch/arm64/core/swi_tables.ld b/arch/arm64/core/swi_tables.ld new file mode 100644 index 00000000000..c6ca94604dd --- /dev/null +++ b/arch/arm64/core/swi_tables.ld @@ -0,0 +1,8 @@ +/* + * Copyright (c) 2023 Nordic Semiconductor ASA + * + * SPDX-License-Identifier: Apache-2.0 + */ +#if LINKER_ZEPHYR_FINAL +INCLUDE zephyr/isr_tables_swi.ld +#endif diff --git a/arch/common/CMakeLists.txt b/arch/common/CMakeLists.txt index 1a89ba9c13a..409c378f620 100644 --- a/arch/common/CMakeLists.txt +++ b/arch/common/CMakeLists.txt @@ -39,6 +39,11 @@ zephyr_linker_sources_ifdef(CONFIG_GEN_ISR_TABLES ${ZEPHYR_BASE}/include/zephyr/linker/intlist.ld ) +zephyr_linker_sources_ifdef(CONFIG_ISR_TABLES_LOCAL_DECLARATION + SECTIONS + ${ZEPHYR_BASE}/include/zephyr/linker/isr-local-drop-unused.ld +) + zephyr_linker_sources_ifdef(CONFIG_GEN_IRQ_VECTOR_TABLE ROM_START SORT_KEY 0x0vectors diff --git a/include/zephyr/arch/arm64/scripts/linker.ld b/include/zephyr/arch/arm64/scripts/linker.ld index 38a7bac297b..55c768f55e4 100644 --- a/include/zephyr/arch/arm64/scripts/linker.ld +++ b/include/zephyr/arch/arm64/scripts/linker.ld @@ -111,8 +111,11 @@ SECTIONS KEEP(*(.exc_vector_table)) KEEP(*(".exc_vector_table.*")) +#if LINKER_ZEPHYR_FINAL && CONFIG_ISR_TABLES_LOCAL_DECLARATION + INCLUDE zephyr/isr_tables_vt.ld +#else KEEP(*(.vectors)) - +#endif _vector_end = .; *(.text) diff --git a/include/zephyr/linker/irq-vector-table-section.ld b/include/zephyr/linker/irq-vector-table-section.ld index 17c483db98f..141eee4d28d 100644 --- a/include/zephyr/linker/irq-vector-table-section.ld +++ b/include/zephyr/linker/irq-vector-table-section.ld @@ -1,7 +1,9 @@ /* SPDX-License-Identifier: Apache-2.0 */ +#if !(LINKER_ZEPHYR_FINAL && CONFIG_ISR_TABLES_LOCAL_DECLARATION) . = ALIGN(CONFIG_ARCH_IRQ_VECTOR_TABLE_ALIGN); KEEP(*(_IRQ_VECTOR_TABLE_SECTION_SYMS)) +#endif /* * Some ARM platforms require this symbol to be placed after the IRQ vector diff --git a/include/zephyr/linker/isr-local-drop-unused.ld b/include/zephyr/linker/isr-local-drop-unused.ld new file mode 100644 index 00000000000..9b6e1272413 --- /dev/null +++ b/include/zephyr/linker/isr-local-drop-unused.ld @@ -0,0 +1,9 @@ +/* SPDX-License-Identifier: Apache-2.0 */ + +#if LINKER_ZEPHYR_FINAL && CONFIG_ISR_TABLES_LOCAL_DECLARATION +/DISCARD/ : +{ + KEEP(*(.vectors)) + KEEP(*(_IRQ_VECTOR_TABLE_SECTION_SYMS)) +} +#endif From 664319f9efc933ee0d3cc4e331b95d1bafe3ba58 Mon Sep 17 00:00:00 2001 From: Radoslaw Koppel Date: Thu, 4 Jan 2024 13:41:27 +0100 Subject: [PATCH 3448/3723] arch: arm: Upgrade IDT_LIST memory section size MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Make IDT_LIST section bigger to fit bigger interrupt description. Note: This section would be removed from final build. Signed-off-by: Radosław Koppel --- include/zephyr/arch/arm/cortex_a_r/scripts/linker.ld | 2 +- include/zephyr/arch/arm/cortex_m/scripts/linker.ld | 2 +- include/zephyr/arch/arm64/scripts/linker.ld | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/include/zephyr/arch/arm/cortex_a_r/scripts/linker.ld b/include/zephyr/arch/arm/cortex_a_r/scripts/linker.ld index 0514690689c..947c18de313 100644 --- a/include/zephyr/arch/arm/cortex_a_r/scripts/linker.ld +++ b/include/zephyr/arch/arm/cortex_a_r/scripts/linker.ld @@ -89,7 +89,7 @@ MEMORY RAM (wx) : ORIGIN = RAM_ADDR, LENGTH = RAM_SIZE LINKER_DT_REGIONS() /* Used by and documented in include/linker/intlist.ld */ - IDT_LIST (wx) : ORIGIN = 0xFFFFF7FF, LENGTH = 2K + IDT_LIST (wx) : ORIGIN = 0xFFFF8000, LENGTH = 32K } ENTRY(CONFIG_KERNEL_ENTRY) diff --git a/include/zephyr/arch/arm/cortex_m/scripts/linker.ld b/include/zephyr/arch/arm/cortex_m/scripts/linker.ld index 7d842ae0567..d061468d2ac 100644 --- a/include/zephyr/arch/arm/cortex_m/scripts/linker.ld +++ b/include/zephyr/arch/arm/cortex_m/scripts/linker.ld @@ -92,7 +92,7 @@ MEMORY #endif LINKER_DT_REGIONS() /* Used by and documented in include/linker/intlist.ld */ - IDT_LIST (wx) : ORIGIN = 0xFFFFF7FF, LENGTH = 2K + IDT_LIST (wx) : ORIGIN = 0xFFFF7FFF, LENGTH = 32K } ENTRY(CONFIG_KERNEL_ENTRY) diff --git a/include/zephyr/arch/arm64/scripts/linker.ld b/include/zephyr/arch/arm64/scripts/linker.ld index 55c768f55e4..fb21c3fda5e 100644 --- a/include/zephyr/arch/arm64/scripts/linker.ld +++ b/include/zephyr/arch/arm64/scripts/linker.ld @@ -67,7 +67,7 @@ MEMORY FLASH (rx) : ORIGIN = ROM_ADDR, LENGTH = ROM_SIZE RAM (wx) : ORIGIN = RAM_ADDR, LENGTH = RAM_SIZE /* Used by and documented in include/linker/intlist.ld */ - IDT_LIST (wx) : ORIGIN = 0xFFFFF7FF, LENGTH = 2K + IDT_LIST (wx) : ORIGIN = 0xFFFF8000, LENGTH = 32K } ENTRY(CONFIG_KERNEL_ENTRY) From 8f98b8b574bdce4c930a7b2a2e2c78764940b6dd Mon Sep 17 00:00:00 2001 From: Radoslaw Koppel Date: Fri, 22 Dec 2023 14:45:18 +0100 Subject: [PATCH 3449/3723] bluetooth: nordic: lll: Use direct ISR when applicable MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This commit updates nordic lll controller to use IRQ_DIRECT_CONNECT where applicable instead of using IRQ_CONNECT with ISR_FLAG_DIRECT. Signed-off-by: Radosław Koppel --- subsys/bluetooth/controller/ll_sw/nordic/lll/lll.c | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/subsys/bluetooth/controller/ll_sw/nordic/lll/lll.c b/subsys/bluetooth/controller/ll_sw/nordic/lll/lll.c index 30fca6d1e2e..ed459c20d19 100644 --- a/subsys/bluetooth/controller/ll_sw/nordic/lll/lll.c +++ b/subsys/bluetooth/controller/ll_sw/nordic/lll/lll.c @@ -221,8 +221,13 @@ int lll_init(void) radio_nrf5_isr, IRQ_CONNECT_FLAGS); IRQ_CONNECT(RTC0_IRQn, CONFIG_BT_CTLR_ULL_HIGH_PRIO, rtc0_nrf5_isr, NULL, 0); +#if defined(CONFIG_BT_CTLR_ZLI) + IRQ_DIRECT_CONNECT(HAL_SWI_RADIO_IRQ, CONFIG_BT_CTLR_LLL_PRIO, + swi_lll_nrf5_isr, IRQ_CONNECT_FLAGS); +#else IRQ_CONNECT(HAL_SWI_RADIO_IRQ, CONFIG_BT_CTLR_LLL_PRIO, swi_lll_nrf5_isr, NULL, IRQ_CONNECT_FLAGS); +#endif #if defined(CONFIG_BT_CTLR_LOW_LAT) || \ (CONFIG_BT_CTLR_ULL_HIGH_PRIO != CONFIG_BT_CTLR_ULL_LOW_PRIO) IRQ_CONNECT(HAL_SWI_JOB_IRQ, CONFIG_BT_CTLR_ULL_LOW_PRIO, From 3799b9368955f0299cd4ab68946b8a548ac9746f Mon Sep 17 00:00:00 2001 From: Radoslaw Koppel Date: Mon, 8 Jan 2024 14:50:30 +0100 Subject: [PATCH 3450/3723] tests: kernel: gen_isr_table: Add tests for local ISR tables declaration MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This commit adds configurations to test local ISR tables declaration. Signed-off-by: Radosław Koppel --- tests/kernel/gen_isr_table/testcase.yaml | 27 +++++++++++++++++++++--- 1 file changed, 24 insertions(+), 3 deletions(-) diff --git a/tests/kernel/gen_isr_table/testcase.yaml b/tests/kernel/gen_isr_table/testcase.yaml index 292a801080b..6f1ca851e32 100644 --- a/tests/kernel/gen_isr_table/testcase.yaml +++ b/tests/kernel/gen_isr_table/testcase.yaml @@ -4,12 +4,12 @@ common: - interrupt - isr_table tests: - arch.interrupt.gen_isr_table.arm_baseline: + arch.interrupt.gen_isr_table.arm_baseline: &arm-baseline platform_allow: qemu_cortex_m3 filter: CONFIG_GEN_ISR_TABLES and CONFIG_ARMV6_M_ARMV8_M_BASELINE extra_configs: - CONFIG_NULL_POINTER_EXCEPTION_DETECTION_NONE=y - arch.interrupt.gen_isr_table.arm_baseline.linker_generator: + arch.interrupt.gen_isr_table.arm_baseline.linker_generator: &arm-baseline-linker-generator platform_allow: qemu_cortex_m3 filter: CONFIG_GEN_ISR_TABLES and CONFIG_ARMV6_M_ARMV8_M_BASELINE tags: @@ -17,7 +17,7 @@ tests: extra_configs: - CONFIG_NULL_POINTER_EXCEPTION_DETECTION_NONE=y - CONFIG_CMAKE_LINKER_GENERATOR=y - arch.interrupt.gen_isr_table.arm_mainline: + arch.interrupt.gen_isr_table.arm_mainline: &arm-mainline platform_allow: qemu_cortex_m3 platform_exclude: - stmf103_mini @@ -40,6 +40,27 @@ tests: - CONFIG_GEN_ISR_TABLES=n - CONFIG_NULL_POINTER_EXCEPTION_DETECTION_NONE=y build_only: true + + arch.interrupt.gen_isr_table_local.arm_baseline: + <<: *arm-baseline + filter: CONFIG_GEN_ISR_TABLES and CONFIG_ARMV6_M_ARMV8_M_BASELINE and not CONFIG_USERSPACE + extra_configs: + - CONFIG_NULL_POINTER_EXCEPTION_DETECTION_NONE=y + - CONFIG_ISR_TABLES_LOCAL_DECLARATION=y + arch.interrupt.gen_isr_table_local.arm_baseline.linker_generator: + <<: *arm-baseline-linker-generator + filter: CONFIG_GEN_ISR_TABLES and CONFIG_ARMV6_M_ARMV8_M_BASELINE and not CONFIG_USERSPACE + extra_configs: + - CONFIG_NULL_POINTER_EXCEPTION_DETECTION_NONE=y + - CONFIG_CMAKE_LINKER_GENERATOR=y + - CONFIG_ISR_TABLES_LOCAL_DECLARATION=y + arch.interrupt.gen_isr_table_local.arm_mainline: + <<: *arm-mainline + filter: CONFIG_GEN_ISR_TABLES and CONFIG_ARMV6_M_ARMV8_M_BASELINE and not CONFIG_USERSPACE + extra_configs: + - CONFIG_NULL_POINTER_EXCEPTION_DETECTION_NONE=y + - CONFIG_ISR_TABLES_LOCAL_DECLARATION=y + arch.interrupt.gen_isr_table.arc: arch_allow: arc filter: CONFIG_RGF_NUM_BANKS > 1 From 26c8776c70ea00773f1c9e9947c38ffe8719233c Mon Sep 17 00:00:00 2001 From: Radoslaw Koppel Date: Tue, 30 Jan 2024 12:32:32 +0100 Subject: [PATCH 3451/3723] buildsystem: Add an option to enable LTO MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This commit adds option to enable Link Time Optimization. Signed-off-by: Radosław Koppel --- CMakeLists.txt | 9 +++++++++ Kconfig.zephyr | 7 +++++++ cmake/bintools/gnu/target.cmake | 9 +++++++-- cmake/compiler/gcc/compiler_flags.cmake | 3 +++ cmake/linker/ld/linker_flags.cmake | 2 ++ 5 files changed, 28 insertions(+), 2 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index a1876013aa9..f1fb89660f9 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -213,6 +213,11 @@ endif() # Apply the final optimization flag(s) zephyr_compile_options(${OPTIMIZATION_FLAG}) +if(CONFIG_LTO) + add_compile_options($) + add_link_options($) +endif() + # @Intent: Obtain compiler specific flags related to C++ that are not influenced by kconfig zephyr_compile_options($<$:$>) @@ -805,6 +810,10 @@ target_include_directories(${OFFSETS_LIB} PRIVATE kernel/include ${ARCH_DIR}/${ARCH}/include ) + +# Make sure that LTO will never be enabled when compiling offsets.c +set_source_files_properties(${OFFSETS_C_PATH} PROPERTIES COMPILE_OPTIONS $) + target_link_libraries(${OFFSETS_LIB} zephyr_interface) add_dependencies(zephyr_interface ${SYSCALL_LIST_H_TARGET} diff --git a/Kconfig.zephyr b/Kconfig.zephyr index c384c8053f9..829deac2a9c 100644 --- a/Kconfig.zephyr +++ b/Kconfig.zephyr @@ -428,6 +428,13 @@ config NO_OPTIMIZATIONS default stack sizes in order to avoid stack overflows. endchoice +config LTO + bool "Link Time Optimization [EXPERIMENTAL]" + depends on !(GEN_ISR_TABLES || GEN_IRQ_VECTOR_TABLE) || ISR_TABLES_LOCAL_DECLARATION + select EXPERIMENTAL + help + This option enables Link Time Optimization. + config COMPILER_WARNINGS_AS_ERRORS bool "Treat warnings as errors" help diff --git a/cmake/bintools/gnu/target.cmake b/cmake/bintools/gnu/target.cmake index 86c66b4825c..612f6de79b2 100644 --- a/cmake/bintools/gnu/target.cmake +++ b/cmake/bintools/gnu/target.cmake @@ -5,8 +5,13 @@ find_program(CMAKE_OBJCOPY ${CROSS_COMPILE}objcopy PATHS ${TOOLCHAIN_HOME} NO_DEFAULT_PATH) find_program(CMAKE_OBJDUMP ${CROSS_COMPILE}objdump PATHS ${TOOLCHAIN_HOME} NO_DEFAULT_PATH) find_program(CMAKE_AS ${CROSS_COMPILE}as PATHS ${TOOLCHAIN_HOME} NO_DEFAULT_PATH) -find_program(CMAKE_AR ${CROSS_COMPILE}ar PATHS ${TOOLCHAIN_HOME} NO_DEFAULT_PATH) -find_program(CMAKE_RANLIB ${CROSS_COMPILE}ranlib PATHS ${TOOLCHAIN_HOME} NO_DEFAULT_PATH) +if(CONFIG_LTO) + find_program(CMAKE_AR ${CROSS_COMPILE}gcc-ar PATHS ${TOOLCHAIN_HOME} NO_DEFAULT_PATH) + find_program(CMAKE_RANLIB ${CROSS_COMPILE}gcc-ranlib PATHS ${TOOLCHAIN_HOME} NO_DEFAULT_PATH) +else() + find_program(CMAKE_AR ${CROSS_COMPILE}ar PATHS ${TOOLCHAIN_HOME} NO_DEFAULT_PATH) + find_program(CMAKE_RANLIB ${CROSS_COMPILE}ranlib PATHS ${TOOLCHAIN_HOME} NO_DEFAULT_PATH) +endif() find_program(CMAKE_READELF ${CROSS_COMPILE}readelf PATHS ${TOOLCHAIN_HOME} NO_DEFAULT_PATH) find_program(CMAKE_NM ${CROSS_COMPILE}nm PATHS ${TOOLCHAIN_HOME} NO_DEFAULT_PATH) find_program(CMAKE_STRIP ${CROSS_COMPILE}strip PATHS ${TOOLCHAIN_HOME} NO_DEFAULT_PATH) diff --git a/cmake/compiler/gcc/compiler_flags.cmake b/cmake/compiler/gcc/compiler_flags.cmake index db252077101..5867392c307 100644 --- a/cmake/compiler/gcc/compiler_flags.cmake +++ b/cmake/compiler/gcc/compiler_flags.cmake @@ -21,6 +21,9 @@ endif() set_compiler_property(PROPERTY optimization_speed -O2) set_compiler_property(PROPERTY optimization_size -Os) +set_compiler_property(PROPERTY optimization_lto -flto) +set_compiler_property(PROPERTY prohibit_lto -fno-lto) + ####################################################### # This section covers flags related to warning levels # ####################################################### diff --git a/cmake/linker/ld/linker_flags.cmake b/cmake/linker/ld/linker_flags.cmake index 8209f4dfbdc..5660b410760 100644 --- a/cmake/linker/ld/linker_flags.cmake +++ b/cmake/linker/ld/linker_flags.cmake @@ -12,6 +12,8 @@ endif() set_property(TARGET linker PROPERTY partial_linking "-r") +set_property(TARGET linker PROPERTY lto_arguments -flto -fno-ipa-sra -ffunction-sections -fdata-sections) + # Some linker flags might not be purely ld specific, but a combination of # linker and compiler, such as: # --coverage for clang From 53becb05bfa1d383b0497a0422761fd53e9ead24 Mon Sep 17 00:00:00 2001 From: Radoslaw Koppel Date: Tue, 30 Jan 2024 13:15:36 +0100 Subject: [PATCH 3452/3723] tests: kernel: common: Enable tests with LTO MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This commit enables some kernel tests with Link Time Optimization enabled. Signed-off-by: Radosław Koppel --- tests/kernel/common/testcase.yaml | 7 +++++++ tests/kernel/interrupt/testcase.yaml | 20 ++++++++++++++++++++ 2 files changed, 27 insertions(+) diff --git a/tests/kernel/common/testcase.yaml b/tests/kernel/common/testcase.yaml index 91e505c85a4..d02a4f5ae8f 100644 --- a/tests/kernel/common/testcase.yaml +++ b/tests/kernel/common/testcase.yaml @@ -47,3 +47,10 @@ tests: tags: picolibc extra_configs: - CONFIG_PICOLIBC=y + kernel.common.lto: + filter: CONFIG_ISR_TABLES_LOCAL_DECLARATION_SUPPORTED + tags: lto + extra_configs: + - CONFIG_TEST_USERSPACE=n + - CONFIG_ISR_TABLES_LOCAL_DECLARATION=y + - CONFIG_LTO=y diff --git a/tests/kernel/interrupt/testcase.yaml b/tests/kernel/interrupt/testcase.yaml index cbe58c65e47..47cbba93e0d 100644 --- a/tests/kernel/interrupt/testcase.yaml +++ b/tests/kernel/interrupt/testcase.yaml @@ -52,3 +52,23 @@ tests: extra_configs: - CONFIG_SHARED_INTERRUPTS=y filter: not CONFIG_TRUSTED_EXECUTION_NONSECURE + arch.shared_interrupt.lto: + # excluded because of failures during test_prevent_interruption + platform_exclude: qemu_cortex_m0 + arch_exclude: + # same as above, #22956 + - nios2 + # test needs 2 working interrupt lines + - xtensa + # TODO: make test work on this arch + - mips + tags: + - kernel + - interrupt + - lto + extra_configs: + - CONFIG_SHARED_INTERRUPTS=y + - CONFIG_TEST_USERSPACE=n + - CONFIG_ISR_TABLES_LOCAL_DECLARATION=y + - CONFIG_LTO=y + filter: not CONFIG_TRUSTED_EXECUTION_NONSECURE and CONFIG_ISR_TABLES_LOCAL_DECLARATION_SUPPORTED From 3eaab029ec6ad3180e0d7049dd38ad66595c3943 Mon Sep 17 00:00:00 2001 From: Torsten Rasmussen Date: Fri, 2 Feb 2024 13:35:36 +0100 Subject: [PATCH 3453/3723] cmake: extend zephyr_file(CONF_FILES ...) to take NAMES as argument Extend zephyr_file(CONF_FILES ...) to take a NAMES list of file names to find instead of creating file names based on board and revision. This allows to unify lookup prj.conf and /app.overlay for application, as well as pave the way for future enhancements to configuration file handling. Signed-off-by: Torsten Rasmussen --- cmake/modules/configuration_files.cmake | 58 +++++----------- cmake/modules/extensions.cmake | 90 +++++++++++++++++++------ 2 files changed, 83 insertions(+), 65 deletions(-) diff --git a/cmake/modules/configuration_files.cmake b/cmake/modules/configuration_files.cmake index d4357425d10..2020204a818 100644 --- a/cmake/modules/configuration_files.cmake +++ b/cmake/modules/configuration_files.cmake @@ -40,70 +40,42 @@ else() endif() zephyr_get(CONF_FILE SYSBUILD LOCAL) -if(DEFINED CONF_FILE) - # This ensures that CACHE{CONF_FILE} will be set correctly to current scope - # variable CONF_FILE. An already current scope variable will stay the same. - set(CONF_FILE ${CONF_FILE}) - - # CONF_FILE has either been specified on the cmake CLI or is already - # in the CMakeCache.txt. This has precedence over the environment - # variable CONF_FILE and the default prj.conf - - # In order to support a `prj_.conf pattern for auto inclusion of board - # overlays, then we must first ensure only a single conf file is provided. +if(NOT DEFINED CONF_FILE) + zephyr_file(CONF_FILES ${APPLICATION_CONFIG_DIR} KCONF CONF_FILE NAMES "prj.conf" REQUIRED) + zephyr_file(CONF_FILES ${APPLICATION_CONFIG_DIR}/boards KCONF CONF_FILE) +else() string(CONFIGURE "${CONF_FILE}" CONF_FILE_EXPANDED) string(REPLACE " " ";" CONF_FILE_AS_LIST "${CONF_FILE_EXPANDED}") list(LENGTH CONF_FILE_AS_LIST CONF_FILE_LENGTH) if(${CONF_FILE_LENGTH} EQUAL 1) - # Need the file name to look for match. - # Need path in order to check if it is absolute. get_filename_component(CONF_FILE_NAME ${CONF_FILE} NAME) if(${CONF_FILE_NAME} MATCHES "prj_(.*).conf") set(CONF_FILE_BUILD_TYPE ${CMAKE_MATCH_1}) - set(CONF_FILE_INCLUDE_FRAGMENTS true) + zephyr_file(CONF_FILES ${APPLICATION_CONFIG_DIR}/boards KCONF CONF_FILE + BUILD ${CONF_FILE_BUILD_TYPE} + ) + set(CONF_FILE_FORCE_CACHE FORCE) endif() endif() -elseif(CACHED_CONF_FILE) - # Cached conf file is present. - # That value has precedence over anything else than a new - # `cmake -DCONF_FILE=` invocation. - set(CONF_FILE ${CACHED_CONF_FILE}) -elseif(EXISTS ${APPLICATION_CONFIG_DIR}/prj.conf) - set(CONF_FILE ${APPLICATION_CONFIG_DIR}/prj.conf) - set(CONF_FILE_INCLUDE_FRAGMENTS true) -else() - message(FATAL_ERROR "No prj.conf file was found in the ${APPLICATION_CONFIG_DIR} folder, " - "please read the Zephyr documentation on application development.") -endif() - -if(CONF_FILE_INCLUDE_FRAGMENTS) - zephyr_file(CONF_FILES ${APPLICATION_CONFIG_DIR}/boards KCONF CONF_FILE BUILD ${CONF_FILE_BUILD_TYPE}) endif() set(APPLICATION_CONFIG_DIR ${APPLICATION_CONFIG_DIR} CACHE INTERNAL "The application configuration folder" FORCE) -set(CACHED_CONF_FILE ${CONF_FILE} CACHE STRING "If desired, you can build the application using\ +set(CONF_FILE ${CONF_FILE} CACHE STRING "If desired, you can build the application using\ the configuration settings specified in an alternate .conf file using this parameter. \ These settings will override the settings in the application’s .config file or its default .conf file.\ Multiple files may be listed, e.g. CONF_FILE=\"prj1.conf;prj2.conf\" \ The CACHED_CONF_FILE is internal Zephyr variable used between CMake runs. \ -To change CONF_FILE, use the CONF_FILE variable.") -unset(CONF_FILE CACHE) - -zephyr_file(CONF_FILES ${APPLICATION_CONFIG_DIR}/boards DTS APP_BOARD_DTS) +To change CONF_FILE, use the CONF_FILE variable." ${CONF_FILE_FORCE_CACHE}) # The CONF_FILE variable is now set to its final value. zephyr_boilerplate_watch(CONF_FILE) +zephyr_file(CONF_FILES ${APPLICATION_CONFIG_DIR}/boards DTS APP_BOARD_DTS) + zephyr_get(DTC_OVERLAY_FILE SYSBUILD LOCAL) -if(DTC_OVERLAY_FILE) - # DTC_OVERLAY_FILE has either been specified on the cmake CLI or is already - # in the CMakeCache.txt. -elseif(APP_BOARD_DTS) - set(DTC_OVERLAY_FILE ${APP_BOARD_DTS}) -elseif(EXISTS ${APPLICATION_CONFIG_DIR}/${BOARD}.overlay) - set(DTC_OVERLAY_FILE ${APPLICATION_CONFIG_DIR}/${BOARD}.overlay) -elseif(EXISTS ${APPLICATION_CONFIG_DIR}/app.overlay) - set(DTC_OVERLAY_FILE ${APPLICATION_CONFIG_DIR}/app.overlay) +if(NOT DEFINED DTC_OVERLAY_FILE) + zephyr_file(CONF_FILES ${APPLICATION_CONFIG_DIR} DTS DTC_OVERLAY_FILE + NAMES "${APP_BOARD_DTS};${BOARD}.overlay;app.overlay") endif() set(DTC_OVERLAY_FILE ${DTC_OVERLAY_FILE} CACHE STRING "If desired, you can \ diff --git a/cmake/modules/extensions.cmake b/cmake/modules/extensions.cmake index 4a96b50bb20..9dfd5bb73a5 100644 --- a/cmake/modules/extensions.cmake +++ b/cmake/modules/extensions.cmake @@ -2425,6 +2425,12 @@ endfunction() # # returns an updated list of absolute paths # +# Usage: +# zephyr_file(CONF_FILES [DTS ] [KCONF ] +# [BOARD [BOARD_REVISION ] | NAMES ...] +# [BUILD ] [REQUIRED] +# ) +# # CONF_FILES : Find all configuration files in the list of paths and # return them in a list. If paths is empty then no configuration # files are returned. Configuration files will be: @@ -2438,7 +2444,13 @@ endfunction() # revision. Requires BOARD to be specified. # # If no board is given the current BOARD and -# BOARD_REVISION will be used. +# BOARD_REVISION will be used, unless NAMES are +# specified. +# +# NAMES [name2] ... List of file names to look for and instead of +# creating file names based on board settings. +# Only the first match found in will be +# returned in the # # DTS : List to append DTS overlay files in to # KCONF : List to append Kconfig fragment files in to @@ -2446,6 +2458,8 @@ endfunction() # For example: # BUILD debug, will look for _debug.conf # and _debug.overlay, instead of .conf +# REQUIRED: Option to indicate that the specified by DTS or KCONF +# must contain at least one element, else an error will be raised. # function(zephyr_file) set(file_options APPLICATION_ROOT CONF_FILES) @@ -2457,11 +2471,12 @@ Please provide one of following: APPLICATION_ROOT, CONF_FILES") if(${ARGV0} STREQUAL APPLICATION_ROOT) set(single_args APPLICATION_ROOT) elseif(${ARGV0} STREQUAL CONF_FILES) + set(options REQUIRED) set(single_args BOARD BOARD_REVISION DTS KCONF BUILD) - set(multi_args CONF_FILES) + set(multi_args CONF_FILES NAMES) endif() - cmake_parse_arguments(FILE "" "${single_args}" "${multi_args}" ${ARGN}) + cmake_parse_arguments(FILE "${options}" "${single_args}" "${multi_args}" ${ARGN}) if(FILE_UNPARSED_ARGUMENTS) message(FATAL_ERROR "zephyr_file(${ARGV0} ...) given unknown arguments: ${FILE_UNPARSED_ARGUMENTS}") endif() @@ -2518,44 +2533,75 @@ Relative paths are only allowed with `-D${ARGV1}=`") endif() endif() - zephyr_build_string(filename - BOARD ${FILE_BOARD} - BUILD ${FILE_BUILD} - ) - set(filename_list ${filename}) + if(FILE_NAMES) + set(dts_filename_list ${FILE_NAMES}) + set(kconf_filename_list ${FILE_NAMES}) + else() + zephyr_build_string(filename + BOARD ${FILE_BOARD} + BUILD ${FILE_BUILD} + ) + set(filename_list ${filename}) - zephyr_build_string(filename - BOARD ${FILE_BOARD} - BOARD_REVISION ${FILE_BOARD_REVISION} - BUILD ${FILE_BUILD} - ) - list(APPEND filename_list ${filename}) - list(REMOVE_DUPLICATES filename_list) + zephyr_build_string(filename + BOARD ${FILE_BOARD} + BOARD_REVISION ${FILE_BOARD_REVISION} + BUILD ${FILE_BUILD} + ) + list(APPEND filename_list ${filename}) + list(REMOVE_DUPLICATES filename_list) + set(dts_filename_list ${filename_list}) + list(TRANSFORM dts_filename_list APPEND ".overlay") + + set(kconf_filename_list ${filename_list}) + list(TRANSFORM kconf_filename_list APPEND ".conf") + endif() if(FILE_DTS) foreach(path ${FILE_CONF_FILES}) - foreach(filename ${filename_list}) - if(EXISTS ${path}/${filename}.overlay) - list(APPEND ${FILE_DTS} ${path}/${filename}.overlay) + foreach(filename ${dts_filename_list}) + if(EXISTS ${path}/${filename}) + list(APPEND ${FILE_DTS} ${path}/${filename}) + if(FILE_NAMES) + break() + endif() endif() endforeach() endforeach() # This updates the provided list in parent scope (callers scope) set(${FILE_DTS} ${${FILE_DTS}} PARENT_SCOPE) + + if(NOT ${FILE_DTS}) + set(not_found ${dts_filename_list}) + endif() endif() if(FILE_KCONF) foreach(path ${FILE_CONF_FILES}) - foreach(filename ${filename_list}) - if(EXISTS ${path}/${filename}.conf) - list(APPEND ${FILE_KCONF} ${path}/${filename}.conf) + foreach(filename ${kconf_filename_list}) + if(EXISTS ${path}/${filename}) + list(APPEND ${FILE_KCONF} ${path}/${filename}) + if(FILE_NAMES) + break() + endif() endif() endforeach() endforeach() # This updates the provided list in parent scope (callers scope) set(${FILE_KCONF} ${${FILE_KCONF}} PARENT_SCOPE) + + if(NOT ${FILE_KCONF}) + set(not_found ${kconf_filename_list}) + endif() + endif() + + if(FILE_REQUIRED AND DEFINED not_found) + message(FATAL_ERROR + "No ${not_found} file(s) was found in the ${FILE_CONF_FILES} folder(s), " + "please read the Zephyr documentation on application development." + ) endif() endif() endfunction() @@ -4164,7 +4210,7 @@ function(zephyr_linker_dts_section) if(DTS_SECTION_UNPARSED_ARGUMENTS) message(FATAL_ERROR "zephyr_linker_dts_section(${ARGV0} ...) given unknown " - "arguments: ${DTS_SECTION_UNPARSED_ARGUMENTS}" + "arguments: ${DTS_SECTION_UNPARSED_ARGUMENTS}" ) endif() From 5b6c5856732cb962638517ff6c0a188760afe249 Mon Sep 17 00:00:00 2001 From: Jamie McCrae Date: Tue, 5 Dec 2023 09:35:42 +0000 Subject: [PATCH 3454/3723] cmake: Add function for file suffix checking/appending Adds a function that can be used to check if a file suffix is supplied and, if so, will update a variable with these filenames Signed-off-by: Jamie McCrae --- cmake/modules/extensions.cmake | 99 ++++++++++++++++++++++++++++------ 1 file changed, 84 insertions(+), 15 deletions(-) diff --git a/cmake/modules/extensions.cmake b/cmake/modules/extensions.cmake index 9dfd5bb73a5..99b98358689 100644 --- a/cmake/modules/extensions.cmake +++ b/cmake/modules/extensions.cmake @@ -2428,7 +2428,7 @@ endfunction() # Usage: # zephyr_file(CONF_FILES [DTS ] [KCONF ] # [BOARD [BOARD_REVISION ] | NAMES ...] -# [BUILD ] [REQUIRED] +# [BUILD ] [SUFFIX ] [REQUIRED] # ) # # CONF_FILES : Find all configuration files in the list of paths and @@ -2452,14 +2452,19 @@ endfunction() # Only the first match found in will be # returned in the # -# DTS : List to append DTS overlay files in to -# KCONF : List to append Kconfig fragment files in to -# BUILD : Build type to include for search. -# For example: -# BUILD debug, will look for _debug.conf -# and _debug.overlay, instead of .conf -# REQUIRED: Option to indicate that the specified by DTS or KCONF -# must contain at least one element, else an error will be raised. +# DTS : List to append DTS overlay files in to +# KCONF : List to append Kconfig fragment files in to +# BUILD : Build type to include for search. +# For example: +# BUILD debug, will look for _debug.conf +# and _debug.overlay, instead of .conf +# SUFFIX : Suffix name to check for instead of the default name +# but with a fallback to the default name if not found. +# For example: +# SUFFIX fish, will look for _fish.conf and use +# if found but will use .conf if not found +# REQUIRED: Option to indicate that the specified by DTS or KCONF +# must contain at least one element, else an error will be raised. # function(zephyr_file) set(file_options APPLICATION_ROOT CONF_FILES) @@ -2472,7 +2477,7 @@ Please provide one of following: APPLICATION_ROOT, CONF_FILES") set(single_args APPLICATION_ROOT) elseif(${ARGV0} STREQUAL CONF_FILES) set(options REQUIRED) - set(single_args BOARD BOARD_REVISION DTS KCONF BUILD) + set(single_args BOARD BOARD_REVISION DTS KCONF BUILD SUFFIX) set(multi_args CONF_FILES NAMES) endif() @@ -2481,7 +2486,6 @@ Please provide one of following: APPLICATION_ROOT, CONF_FILES") message(FATAL_ERROR "zephyr_file(${ARGV0} ...) given unknown arguments: ${FILE_UNPARSED_ARGUMENTS}") endif() - if(FILE_APPLICATION_ROOT) # Note: user can do: `-D=` and app can at same # time specify `list(APPEND )` @@ -2560,8 +2564,16 @@ Relative paths are only allowed with `-D${ARGV1}=`") if(FILE_DTS) foreach(path ${FILE_CONF_FILES}) foreach(filename ${dts_filename_list}) - if(EXISTS ${path}/${filename}) - list(APPEND ${FILE_DTS} ${path}/${filename}) + if(NOT IS_ABSOLUTE ${filename}) + set(test_file ${path}/${filename}) + else() + set(test_file ${filename}) + endif() + zephyr_file_suffix(test_file SUFFIX ${FILE_SUFFIX}) + + if(EXISTS ${test_file}) + list(APPEND ${FILE_DTS} ${test_file}) + if(FILE_NAMES) break() endif() @@ -2580,8 +2592,15 @@ Relative paths are only allowed with `-D${ARGV1}=`") if(FILE_KCONF) foreach(path ${FILE_CONF_FILES}) foreach(filename ${kconf_filename_list}) - if(EXISTS ${path}/${filename}) - list(APPEND ${FILE_KCONF} ${path}/${filename}) + if(NOT IS_ABSOLUTE ${filename}) + set(test_file ${path}/${filename}) + else() + set(test_file ${filename}) + endif() + zephyr_file_suffix(test_file SUFFIX ${FILE_SUFFIX}) + + if(EXISTS ${test_file}) + list(APPEND ${FILE_KCONF} ${test_file}) if(FILE_NAMES) break() endif() @@ -2642,6 +2661,56 @@ function(zephyr_file_copy oldname newname) endif() endfunction() +# Usage: +# zephyr_file_suffix( SUFFIX ) +# +# Zephyr file add suffix extension. +# This function will check the provied filename or list of filenames to see if they have a +# `_` extension to them and if so, updates the supplied variable/list with the new +# path/paths. +# +# : Variable (singlular or list) of absolute path filename(s) which should be checked +# and updated if there is a filename which has the present. +# : The suffix to test for and append to the end of the provided filename. +# +# Returns an updated variable of absolute path(s) +# +function(zephyr_file_suffix filename) + set(single_args SUFFIX) + cmake_parse_arguments(FILE "" "${single_args}" "" ${ARGN}) + + if(NOT DEFINED FILE_SUFFIX OR NOT DEFINED ${filename}) + # If the file suffix variable is not known then there is nothing to do, return early + return() + endif() + + set(tmp_new_list) + + foreach(file ${${filename}}) + if("${file}" STREQUAL "") + # Skip checking empty variables + continue() + endif() + + # Search for the full stop so we know where to add the file suffix before the file extension + cmake_path(GET file EXTENSION file_ext) + cmake_path(REMOVE_EXTENSION file OUTPUT_VARIABLE new_filename) + cmake_path(APPEND_STRING new_filename "_${FILE_SUFFIX}${file_ext}") + + # Use the filename with the suffix if it exists, if not then fall back to the default + if(EXISTS "${new_filename}") + list(APPEND tmp_new_list ${new_filename}) + else() + list(APPEND tmp_new_list ${file}) + endif() + endforeach() + + # Update supplied variable if it differs + if(NOT "${${filename}}" STREQUAL "${tmp_new_list}") + set(${filename} "${tmp_new_list}" PARENT_SCOPE) + endif() +endfunction() + # Usage: # zephyr_string( ...) # From ef251048e4b6be9db423a8a9806cd25557dbc20e Mon Sep 17 00:00:00 2001 From: Jamie McCrae Date: Tue, 5 Dec 2023 10:10:59 +0000 Subject: [PATCH 3455/3723] cmake: Add support for file suffixes Adds support for configuration files to use file suffixes Signed-off-by: Jamie McCrae --- cmake/modules/configuration_files.cmake | 12 +++++++++--- cmake/modules/kconfig.cmake | 2 +- 2 files changed, 10 insertions(+), 4 deletions(-) diff --git a/cmake/modules/configuration_files.cmake b/cmake/modules/configuration_files.cmake index 2020204a818..d671b796105 100644 --- a/cmake/modules/configuration_files.cmake +++ b/cmake/modules/configuration_files.cmake @@ -27,6 +27,9 @@ include_guard(GLOBAL) include(extensions) +# Merge in variables from other sources (e.g. sysbuild) +zephyr_get(FILE_SUFFIX SYSBUILD GLOBAL) + zephyr_get(APPLICATION_CONFIG_DIR) if(DEFINED APPLICATION_CONFIG_DIR) string(CONFIGURE ${APPLICATION_CONFIG_DIR} APPLICATION_CONFIG_DIR) @@ -41,7 +44,7 @@ endif() zephyr_get(CONF_FILE SYSBUILD LOCAL) if(NOT DEFINED CONF_FILE) - zephyr_file(CONF_FILES ${APPLICATION_CONFIG_DIR} KCONF CONF_FILE NAMES "prj.conf" REQUIRED) + zephyr_file(CONF_FILES ${APPLICATION_CONFIG_DIR} KCONF CONF_FILE NAMES "prj.conf" SUFFIX ${FILE_SUFFIX} REQUIRED) zephyr_file(CONF_FILES ${APPLICATION_CONFIG_DIR}/boards KCONF CONF_FILE) else() string(CONFIGURE "${CONF_FILE}" CONF_FILE_EXPANDED) @@ -70,12 +73,12 @@ To change CONF_FILE, use the CONF_FILE variable." ${CONF_FILE_FORCE_CACHE}) # The CONF_FILE variable is now set to its final value. zephyr_boilerplate_watch(CONF_FILE) -zephyr_file(CONF_FILES ${APPLICATION_CONFIG_DIR}/boards DTS APP_BOARD_DTS) +zephyr_file(CONF_FILES ${APPLICATION_CONFIG_DIR}/boards DTS APP_BOARD_DTS SUFFIX ${FILE_SUFFIX}) zephyr_get(DTC_OVERLAY_FILE SYSBUILD LOCAL) if(NOT DEFINED DTC_OVERLAY_FILE) zephyr_file(CONF_FILES ${APPLICATION_CONFIG_DIR} DTS DTC_OVERLAY_FILE - NAMES "${APP_BOARD_DTS};${BOARD}.overlay;app.overlay") + NAMES "${APP_BOARD_DTS};${BOARD}.overlay;app.overlay" SUFFIX ${FILE_SUFFIX}) endif() set(DTC_OVERLAY_FILE ${DTC_OVERLAY_FILE} CACHE STRING "If desired, you can \ @@ -87,6 +90,9 @@ DTC_OVERLAY_FILE=\"dts1.overlay dts2.overlay\"") # The DTC_OVERLAY_FILE variable is now set to its final value. zephyr_boilerplate_watch(DTC_OVERLAY_FILE) +# Watch the FILE_SUFFIX variable for changes too +zephyr_boilerplate_watch(FILE_SUFFIX) + zephyr_get(EXTRA_CONF_FILE SYSBUILD LOCAL VAR EXTRA_CONF_FILE OVERLAY_CONFIG MERGE REVERSE) zephyr_get(EXTRA_DTC_OVERLAY_FILE SYSBUILD LOCAL MERGE REVERSE) zephyr_get(DTS_EXTRA_CPPFLAGS SYSBUILD LOCAL MERGE REVERSE) diff --git a/cmake/modules/kconfig.cmake b/cmake/modules/kconfig.cmake index 2077dc926e7..f355bf2beb5 100644 --- a/cmake/modules/kconfig.cmake +++ b/cmake/modules/kconfig.cmake @@ -84,7 +84,7 @@ if(EXTRA_CONF_FILE) string(REPLACE " " ";" EXTRA_CONF_FILE_AS_LIST "${EXTRA_CONF_FILE_EXPANDED}") endif() -zephyr_file(CONF_FILES ${BOARD_EXTENSION_DIRS} KCONF board_extension_conf_files) +zephyr_file(CONF_FILES ${BOARD_EXTENSION_DIRS} KCONF board_extension_conf_files SUFFIX ${FILE_SUFFIX}) # DTS_ROOT_BINDINGS is a semicolon separated list, this causes # problems when invoking kconfig_target since semicolon is a special From f7f320c4940397fb6d31fd29d3673ef6684efb65 Mon Sep 17 00:00:00 2001 From: Jamie McCrae Date: Tue, 5 Dec 2023 13:25:56 +0000 Subject: [PATCH 3456/3723] sysbuild: Add support for FILE_SUFFIX Adds supports for sysbuild loading project-specific Kconfiguration fragments that are suffixed with the user-provided value Signed-off-by: Jamie McCrae --- cmake/modules/configuration_files.cmake | 3 --- .../cmake/modules/sysbuild_extensions.cmake | 14 ++++++-------- 2 files changed, 6 insertions(+), 11 deletions(-) diff --git a/cmake/modules/configuration_files.cmake b/cmake/modules/configuration_files.cmake index d671b796105..4f2e469ab79 100644 --- a/cmake/modules/configuration_files.cmake +++ b/cmake/modules/configuration_files.cmake @@ -90,9 +90,6 @@ DTC_OVERLAY_FILE=\"dts1.overlay dts2.overlay\"") # The DTC_OVERLAY_FILE variable is now set to its final value. zephyr_boilerplate_watch(DTC_OVERLAY_FILE) -# Watch the FILE_SUFFIX variable for changes too -zephyr_boilerplate_watch(FILE_SUFFIX) - zephyr_get(EXTRA_CONF_FILE SYSBUILD LOCAL VAR EXTRA_CONF_FILE OVERLAY_CONFIG MERGE REVERSE) zephyr_get(EXTRA_DTC_OVERLAY_FILE SYSBUILD LOCAL MERGE REVERSE) zephyr_get(DTS_EXTRA_CPPFLAGS SYSBUILD LOCAL MERGE REVERSE) diff --git a/share/sysbuild/cmake/modules/sysbuild_extensions.cmake b/share/sysbuild/cmake/modules/sysbuild_extensions.cmake index 980c54ef766..fea359f475b 100644 --- a/share/sysbuild/cmake/modules/sysbuild_extensions.cmake +++ b/share/sysbuild/cmake/modules/sysbuild_extensions.cmake @@ -268,14 +268,12 @@ function(ExternalZephyrProject_Add) ) endif() - # Check for sysbuild related configuration fragments. - # The contents of these are appended to the image existing configuration - # when user is not specifying custom fragments. - if(NOT "${CONF_FILE_BUILD_TYPE}" STREQUAL "") - set(sysbuild_image_conf_fragment ${sysbuild_image_conf_dir}/${ZBUILD_APPLICATION}_${CONF_FILE_BUILD_TYPE}.conf) - else() - set(sysbuild_image_conf_fragment ${sysbuild_image_conf_dir}/${ZBUILD_APPLICATION}.conf) - endif() + # Check for sysbuild related configuration fragments. + # The contents of these are appended to the image existing configuration + # when user is not specifying custom fragments. + zephyr_file(CONF_FILES ${sysbuild_image_conf_dir} KCONF sysbuild_image_conf_fragment + NAMES ${ZBUILD_APPLICATION}.conf SUFFIX ${FILE_SUFFIX} + ) if (NOT (${ZBUILD_APPLICATION}_OVERLAY_CONFIG OR ${ZBUILD_APPLICATION}_EXTRA_CONF_FILE) AND EXISTS ${sysbuild_image_conf_fragment} From 5bf056046afe2e49f80309bfd7911f60ac2e33a8 Mon Sep 17 00:00:00 2001 From: Jamie McCrae Date: Wed, 31 Jan 2024 08:26:38 +0000 Subject: [PATCH 3457/3723] cmake: modules: extensions: Deprecate build type Adds a deprecation notice if a file is found which has the build type informing the user of the replacement Signed-off-by: Jamie McCrae --- cmake/modules/extensions.cmake | 16 +++++++++++++++- 1 file changed, 15 insertions(+), 1 deletion(-) diff --git a/cmake/modules/extensions.cmake b/cmake/modules/extensions.cmake index 99b98358689..e636a2cb473 100644 --- a/cmake/modules/extensions.cmake +++ b/cmake/modules/extensions.cmake @@ -2574,6 +2574,10 @@ Relative paths are only allowed with `-D${ARGV1}=`") if(EXISTS ${test_file}) list(APPEND ${FILE_DTS} ${test_file}) + if(DEFINED FILE_BUILD) + set(deprecated_file_found y) + endif() + if(FILE_NAMES) break() endif() @@ -2601,6 +2605,11 @@ Relative paths are only allowed with `-D${ARGV1}=`") if(EXISTS ${test_file}) list(APPEND ${FILE_KCONF} ${test_file}) + + if(DEFINED FILE_BUILD) + set(deprecated_file_found y) + endif() + if(FILE_NAMES) break() endif() @@ -2622,6 +2631,11 @@ Relative paths are only allowed with `-D${ARGV1}=`") "please read the Zephyr documentation on application development." ) endif() + + if(deprecated_file_found) + message(DEPRECATION "prj_.conf was deprecated after Zephyr 3.5," + " you should switch to using -DFILE_SUFFIX instead") + endif() endif() endfunction() @@ -4279,7 +4293,7 @@ function(zephyr_linker_dts_section) if(DTS_SECTION_UNPARSED_ARGUMENTS) message(FATAL_ERROR "zephyr_linker_dts_section(${ARGV0} ...) given unknown " - "arguments: ${DTS_SECTION_UNPARSED_ARGUMENTS}" + "arguments: ${DTS_SECTION_UNPARSED_ARGUMENTS}" ) endif() From 425ef8abd34e056455e0355ce1aa95e3c808d360 Mon Sep 17 00:00:00 2001 From: Jamie McCrae Date: Tue, 5 Dec 2023 14:00:35 +0000 Subject: [PATCH 3458/3723] doc: Add documentation on FILE_SUFFIX build variable Adds details to the application development page and sysbuild page documenting the variable, how it works and how it should be used Signed-off-by: Jamie McCrae --- doc/build/sysbuild/index.rst | 68 +++++++++++++++++++++++++++++++ doc/develop/application/index.rst | 49 ++++++++++++++++++++++ 2 files changed, 117 insertions(+) diff --git a/doc/build/sysbuild/index.rst b/doc/build/sysbuild/index.rst index b66ec8938c7..5827f135865 100644 --- a/doc/build/sysbuild/index.rst +++ b/doc/build/sysbuild/index.rst @@ -651,6 +651,74 @@ configuration files for ``my_sample`` will be ignored. This give you full control on how images are configured when integrating those with ``application``. +.. _sysbuild_file_suffixes: + +Sysbuild file suffix support +---------------------------- + +File suffix support through the makevar:`FILE_SUFFIX` is supported in sysbuild +(see :ref:`application-file-suffixes` for details on this feature in applications). For sysbuild, +a globally provided option will be passed down to all images. In addition, the image configuration +file will have this value applied and used (instead of the build type) if the file exists. + +Given the example project: + +.. code-block:: none + + /application + ├── CMakeLists.txt + ├── prj.conf + ├── sysbuild.conf + ├── sysbuild_test_key.conf + └── sysbuild + ├── mcuboot.conf + ├── mcuboot_max_log.conf + └── my_sample.conf + +* If ``FILE_SUFFIX`` is not defined and both ``mcuboot`` and ``my_sample`` images are included, + ``mcuboot`` will use the ``mcuboot.conf`` Kconfig fragment file and ``my_sample`` will use the + ``my_sample.conf`` Kconfig fragment file. Sysbuild itself will use the ``sysbuild.conf`` + Kconfig fragment file. + +* If ``FILE_SUFFIX`` is set to ``max_log`` and both ``mcuboot`` and ``my_sample`` images are + included, ``mcuboot`` will use the ``mcuboot_max_log.conf`` Kconfig fragment file and + ``my_sample`` will use the ``my_sample.conf`` Kconfig fragment file (as it will fallback to the + file without the suffix). Sysbuild itself will use the ``sysbuild.conf`` Kconfig fragment file + (as it will fallback to the file without the suffix). + +* If ``FILE_SUFFIX`` is set to ``test_key`` and both ``mcuboot`` and ``my_sample`` images are + included, ``mcuboot`` will use the ``mcuboot.conf`` Kconfig fragment file and + ``my_sample`` will use the ``my_sample.conf`` Kconfig fragment file (as it will fallback to the + files without the suffix). Sysbuild itself will use the ``sysbuild_test_key.conf`` Kconfig + fragment file. This can be used to apply a different sysbuild configuration, for example to use + a different signing key in MCUboot and when signing the main application. + +The ``FILE_SUFFIX`` can also be applied only to single images by prefixing the variable with the +image name: + +.. tabs:: + + .. group-tab:: ``west build`` + + .. zephyr-app-commands:: + :tool: west + :app: file_suffix_example + :board: reel_board + :goals: build + :west-args: --sysbuild + :gen-args: -DSB_CONFIG_BOOTLOADER_MCUBOOT=y -Dmcuboot_FILE_SUFFIX="max_log" + :compact: + + .. group-tab:: ``cmake`` + + .. zephyr-app-commands:: + :tool: cmake + :app: share/sysbuild + :board: reel_board + :goals: build + :gen-args: -DAPP_DIR= -DSB_CONFIG_BOOTLOADER_MCUBOOT=y -Dmcuboot_FILE_SUFFIX="max_log" + :compact: + .. _sysbuild_zephyr_application_dependencies: Adding dependencies among Zephyr applications diff --git a/doc/develop/application/index.rst b/doc/develop/application/index.rst index 4346e011670..62758cf71d0 100644 --- a/doc/develop/application/index.rst +++ b/doc/develop/application/index.rst @@ -445,6 +445,10 @@ should know about. * :makevar:`EXTRA_ZEPHYR_MODULES`: Like :makevar:`ZEPHYR_MODULES`, except these will be added to the list of modules found via west, instead of replacing it. +* :makevar:`FILE_SUFFIX`: Optional suffix for filenames that will be added to Kconfig + fragments and devicetree overlays (if these files exists, otherwise will fallback to + the name without the prefix). See :ref:`application-file-suffixes` for details. + .. note:: You can use a :ref:`cmake_build_config_package` to share common settings for @@ -681,6 +685,51 @@ Devicetree Overlays See :ref:`set-devicetree-overlays`. +.. _application-file-suffixes: + +File Suffixes +============= + +Zephyr applications might want to have a single code base with multiple configurations for +different build/product variants which would necessitate different Kconfig options and devicetree +configuration. In order to better configure this, Zephyr provides a :makevar:`FILE_SUFFIX` option +when configuring applications that can be automatically appended to filenames. This is applied to +Kconfig fragments and board overlays but with a fallback so that if such files do not exist, the +files without these suffixes will be used instead. + +Given the following example project layout: + +.. code-block:: none + + + ├── CMakeLists.txt + ├── prj.conf + ├── prj_mouse.conf + ├── boards + │ ├── native_posix.overlay + │ └── qemu_cortex_m3_mouse.overlay + └── src + └── main.c + +* If this is built normally without ``FILE_SUFFIX`` being defined for ``native_posix`` then + ``prj.conf`` and ``boards/native_posix.overlay`` will be used. + +* If this is build normally without ``FILE_SUFFIX`` being defined for ``qemu_cortex_m3`` then + ``prj.conf`` will be used, no application devicetree overlay will be used. + +* If this is built with ``FILE_SUFFIX`` set to ``mouse`` for ``native_posix`` then + ``prj_mouse.conf`` and ``boards/native_posix.overlay`` will be used (there is no + ``native_posix_mouse.overlay`` file so it falls back to ``native_posix.overlay``). + +* If this is build with ``FILE_SUFFIX`` set to ``mouse`` for ``qemu_cortex_m3`` then + ``prj_mouse.conf`` will be used and ``boards/qemu_cortex_m3_mouse.overlay`` will be used. + +.. note:: + + When ``CONF_FILE`` is set in the form of ``prj_X.conf`` then the ``X`` will be used as the + build type. If this is combined with ``FILE_SUFFIX`` then the file suffix option will take + priority over the build type. + Application-Specific Code ************************* From 0f94e5eab9d76384d9ef6d2c5ba002ec19b7c8b4 Mon Sep 17 00:00:00 2001 From: Jamie McCrae Date: Tue, 5 Dec 2023 14:04:44 +0000 Subject: [PATCH 3459/3723] doc: release: 3.6: Add note on FILE_SUFFIX support Adds a note with a link to the documentation pages for this new feature Signed-off-by: Jamie McCrae --- doc/releases/release-notes-3.6.rst | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/doc/releases/release-notes-3.6.rst b/doc/releases/release-notes-3.6.rst index 23a03dd58e1..1f6e6159844 100644 --- a/doc/releases/release-notes-3.6.rst +++ b/doc/releases/release-notes-3.6.rst @@ -179,6 +179,10 @@ Build system and infrastructure * Added support for sysbuild setting a signing script (``SIGNING_SCRIPT``), see :ref:`west-extending-signing` for details. +* Added support for ``FILE_SUFFIX`` in the build system which allows for adding suffixes to + application Kconfig fragment file names and devicetree overlay file names, see + :ref:`application-file-suffixes` and :ref:`sysbuild_file_suffixes` for details. + Drivers and Sensors ******************* From 1a7fb576e7b0d70e9037fa6b1171023c638a8538 Mon Sep 17 00:00:00 2001 From: Jamie McCrae Date: Wed, 31 Jan 2024 08:29:29 +0000 Subject: [PATCH 3460/3723] doc: release: 3.6: Add deprecation note for build type Adds a note that build type has been deprecated in favour of file suffix Signed-off-by: Jamie McCrae --- doc/releases/migration-guide-3.6.rst | 3 +++ doc/releases/release-notes-3.6.rst | 2 ++ 2 files changed, 5 insertions(+) diff --git a/doc/releases/migration-guide-3.6.rst b/doc/releases/migration-guide-3.6.rst index a45117ef9b0..ceb57a40edf 100644 --- a/doc/releases/migration-guide-3.6.rst +++ b/doc/releases/migration-guide-3.6.rst @@ -36,6 +36,9 @@ Build System ``target_compile_definitions(app PRIVATE _POSIX_C_SOURCE=200809L)`` to your application or ``zephyr_library_compile_definitions(_POSIX_C_SOURCE=200809L)`` to your library. +* Build type by setting ``CONF_FILE`` to ``prj_.conf`` is now deprecated, users should + instead use the new ``-DFILE_SUFFIX`` feature :ref:`application-file-suffixes`. + Kernel ====== diff --git a/doc/releases/release-notes-3.6.rst b/doc/releases/release-notes-3.6.rst index 1f6e6159844..2bba24bdbed 100644 --- a/doc/releases/release-notes-3.6.rst +++ b/doc/releases/release-notes-3.6.rst @@ -183,6 +183,8 @@ Build system and infrastructure application Kconfig fragment file names and devicetree overlay file names, see :ref:`application-file-suffixes` and :ref:`sysbuild_file_suffixes` for details. +* Deprecated ``CONF_FILE`` ``prj_.conf`` build type. + Drivers and Sensors ******************* From e569a13d395c881f185e8c504cbe2a81cb272426 Mon Sep 17 00:00:00 2001 From: Keith Packard Date: Thu, 28 Dec 2023 12:35:45 -0800 Subject: [PATCH 3461/3723] libc/newlib: Wrap to define strnlen and strtok_r when needed Newlib doesn't have Zephyr support, so we need to define these functions when the application doesn't ask for the right level of POSIX support. Signed-off-by: Keith Packard --- lib/libc/newlib/include/string.h | 37 ++++++++++++++++++++++++++++++++ 1 file changed, 37 insertions(+) create mode 100644 lib/libc/newlib/include/string.h diff --git a/lib/libc/newlib/include/string.h b/lib/libc/newlib/include/string.h new file mode 100644 index 00000000000..74ba3ccdd9e --- /dev/null +++ b/lib/libc/newlib/include/string.h @@ -0,0 +1,37 @@ +/* + * Copyright © 2024 Keith Packard + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#ifndef ZEPHYR_LIB_LIBC_NEWLIB_INCLUDE_STRING_H_ +#define ZEPHYR_LIB_LIBC_NEWLIB_INCLUDE_STRING_H_ + +/* This should work on GCC and clang. + * + * If we need to support a toolchain without #include_next the CMake + * infrastructure should be used to identify it and provide an + * alternative solution. + */ +#include_next + +#ifdef __cplusplus +extern "C" { +#endif + +/* + * Define these two Zephyr APIs when _POSIX_C_SOURCE is not set to expose + * them from newlib + */ +#if !__MISC_VISIBLE && !__POSIX_VISIBLE +char *strtok_r(char *__restrict, const char *__restrict, char **__restrict); +#endif +#if __POSIX_VISIBLE < 200809L +size_t strnlen(const char *, size_t); +#endif + +#ifdef __cplusplus +} +#endif + +#endif /* ZEPHYR_LIB_LIBC_NEWLIB_INCLUDE_STRING_H_ */ From c4d05b5f9e99cfa020b5832a33abf9f7235d2860 Mon Sep 17 00:00:00 2001 From: Keith Packard Date: Thu, 28 Dec 2023 12:37:38 -0800 Subject: [PATCH 3462/3723] tests/c_lib: Remove define of _POSIX_C_SOURCE for newlib This test does not use any APIs beyond those provided in the Zephyr standard set, so it should not define _POSIX_C_SOURCE. Signed-off-by: Keith Packard --- tests/lib/c_lib/common/src/main.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/lib/c_lib/common/src/main.c b/tests/lib/c_lib/common/src/main.c index 1995693cad4..716e2e0fd9b 100644 --- a/tests/lib/c_lib/common/src/main.c +++ b/tests/lib/c_lib/common/src/main.c @@ -15,7 +15,7 @@ * it guarantee that ALL functionality provided is working correctly. */ -#if defined(CONFIG_NEWLIB_LIBC) || defined(CONFIG_NATIVE_LIBC) +#if defined(CONFIG_NATIVE_LIBC) #undef _POSIX_C_SOURCE #define _POSIX_C_SOURCE 200809L #endif From 32fd2f57b161529485550199737978e2bb4d2cc4 Mon Sep 17 00:00:00 2001 From: Abderrahmane Jarmouni Date: Thu, 25 Jan 2024 13:05:20 +0100 Subject: [PATCH 3463/3723] drivers: display: stm32_ltdc: fix for stm32f429i_disc1 Display is not working on STM32F429i-DISC1 board because display_blanking_off() needs to be sent to ILI9341 device, but it's sent to LTDC instead which does not implement it. This patch adds a LTDC DT property that provides the pHandle of the display's own controller so that display_blanking_off/on are forwarded to it when they are called by an application. Signed-off-by: Abderrahmane Jarmouni --- .../arm/stm32f429i_disc1/stm32f429i_disc1.dts | 2 + drivers/display/display_stm32_ltdc.c | 42 ++++++++++++++++++- dts/bindings/display/st,stm32-ltdc.yaml | 7 ++++ 3 files changed, 50 insertions(+), 1 deletion(-) diff --git a/boards/arm/stm32f429i_disc1/stm32f429i_disc1.dts b/boards/arm/stm32f429i_disc1/stm32f429i_disc1.dts index 51b7ac84d49..cbcc551a716 100644 --- a/boards/arm/stm32f429i_disc1/stm32f429i_disc1.dts +++ b/boards/arm/stm32f429i_disc1/stm32f429i_disc1.dts @@ -1,5 +1,6 @@ /* * Copyright (c) 2017 Linaro Limited + * Copyright (c) 2024 STMicroelectronics * * SPDX-License-Identifier: Apache-2.0 */ @@ -234,6 +235,7 @@ <dc_hsync_pc6 <dc_vsync_pa4>; pinctrl-names = "default"; ext-sdram = <&sdram2>; + display-controller = <&ili9341>; status = "okay"; width = <240>; diff --git a/drivers/display/display_stm32_ltdc.c b/drivers/display/display_stm32_ltdc.c index a70cea32461..4581ea1d012 100644 --- a/drivers/display/display_stm32_ltdc.c +++ b/drivers/display/display_stm32_ltdc.c @@ -1,6 +1,7 @@ /* * Copyright (c) 2022 Byte-Lab d.o.o. * Copyright 2023 NXP + * Copyright (c) 2024 STMicroelectronics * * SPDX-License-Identifier: Apache-2.0 */ @@ -74,6 +75,7 @@ struct display_stm32_ltdc_config { struct stm32_pclken pclken; const struct pinctrl_dev_config *pctrl; void (*irq_config_func)(const struct device *dev); + const struct device *display_controller; }; static void stm32_ltdc_global_isr(const struct device *dev) @@ -245,6 +247,40 @@ static int stm32_ltdc_read(const struct device *dev, const uint16_t x, return 0; } +static int stm32_ltdc_display_blanking_off(const struct device *dev) +{ + const struct display_stm32_ltdc_config *config = dev->config; + const struct device *display_dev = config->display_controller; + + if (display_dev == NULL) { + return 0; + } + + if (!device_is_ready(display_dev)) { + LOG_ERR("Display device %s not ready", display_dev->name); + return -ENODEV; + } + + return display_blanking_off(display_dev); +} + +static int stm32_ltdc_display_blanking_on(const struct device *dev) +{ + const struct display_stm32_ltdc_config *config = dev->config; + const struct device *display_dev = config->display_controller; + + if (display_dev == NULL) { + return 0; + } + + if (!device_is_ready(config->display_controller)) { + LOG_ERR("Display device %s not ready", display_dev->name); + return -ENODEV; + } + + return display_blanking_on(display_dev); +} + static int stm32_ltdc_init(const struct device *dev) { int err; @@ -424,7 +460,9 @@ static const struct display_driver_api stm32_ltdc_display_api = { .read = stm32_ltdc_read, .get_capabilities = stm32_ltdc_get_capabilities, .set_pixel_format = stm32_ltdc_set_pixel_format, - .set_orientation = stm32_ltdc_set_orientation + .set_orientation = stm32_ltdc_set_orientation, + .blanking_off = stm32_ltdc_display_blanking_off, + .blanking_on = stm32_ltdc_display_blanking_on, }; #if DT_INST_NODE_HAS_PROP(0, ext_sdram) @@ -569,6 +607,8 @@ static const struct display_driver_api stm32_ltdc_display_api = { }, \ .pctrl = STM32_LTDC_DEVICE_PINCTRL_GET(inst), \ .irq_config_func = stm32_ltdc_irq_config_func_##inst, \ + .display_controller = DEVICE_DT_GET_OR_NULL( \ + DT_INST_PHANDLE(inst, display_controller)), \ }; \ DEVICE_DT_INST_DEFINE(inst, \ &stm32_ltdc_init, \ diff --git a/dts/bindings/display/st,stm32-ltdc.yaml b/dts/bindings/display/st,stm32-ltdc.yaml index 73ae19f7fcb..5513c811ac5 100644 --- a/dts/bindings/display/st,stm32-ltdc.yaml +++ b/dts/bindings/display/st,stm32-ltdc.yaml @@ -1,4 +1,5 @@ # Copyright (c) 2022, Byte-Lab d.o.o. +# Copyright (c) 2024 STMicroelectronics # SPDX-License-Identifier: Apache-2.0 description: STM32 LCD-TFT display controller @@ -64,3 +65,9 @@ properties: window0-y1: type: int description: Last pixel in y direction on layer 0. Defaults to height. + + display-controller: + type: phandle + description: | + Phandle of the display's controller. When provided, it's used to forward some of the + configuration calls (e.g. blanking on/off) sent to LTDC device. From c6f2f2cf53d16b0573ea7f35169d96183008ae9e Mon Sep 17 00:00:00 2001 From: Robert Lubos Date: Fri, 2 Feb 2024 11:26:48 +0100 Subject: [PATCH 3464/3723] tests: net: ip-addr: Fix compiler warning Building with Zephyr SDK 0.16.5 revealed a minor bug with the buffer size provided to snprintk(): specified bound 38 exceeds destination size 20 [-Wstringop-overflow=] As we provide the buffer to snprintk() with an offset, the actual buffer size should be reduced by that offset value. Signed-off-by: Robert Lubos --- tests/net/ip-addr/src/main.c | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/tests/net/ip-addr/src/main.c b/tests/net/ip-addr/src/main.c index 23f8d4b6437..d4ef6b0b947 100644 --- a/tests/net/ip-addr/src/main.c +++ b/tests/net/ip-addr/src/main.c @@ -68,15 +68,17 @@ static struct net_if *default_iface; "Test %s failed.\n", expected); \ } while (0) +#define LL_ADDR_STR_SIZE sizeof("xx:xx:xx:xx:xx:xx") + #define TEST_LL_6_TWO(a, b, c, d, e, f, expected) \ do { \ uint8_t ll1[] = { a, b, c, d, e, f }; \ uint8_t ll2[] = { f, e, d, c, b, a }; \ - char out[2 * sizeof("xx:xx:xx:xx:xx:xx") + 1 + 1]; \ + char out[2 * LL_ADDR_STR_SIZE + 1 + 1]; \ snprintk(out, sizeof(out), "%s ", \ net_sprint_ll_addr(ll1, sizeof(ll1))); \ - snprintk(out + sizeof("xx:xx:xx:xx:xx:xx"), \ - sizeof(out), "%s", \ + snprintk(out + LL_ADDR_STR_SIZE, \ + sizeof(out) - LL_ADDR_STR_SIZE, "%s", \ net_sprint_ll_addr(ll2, sizeof(ll2))); \ zassert_false(strcmp(out, expected), \ "Test %s failed, got %s\n", expected, \ From 9001512e1fc309e525461b874f37dd94ea25414b Mon Sep 17 00:00:00 2001 From: Daniel DeGrasse Date: Fri, 2 Feb 2024 12:22:40 -0600 Subject: [PATCH 3465/3723] dts: arm: nxp: nxp_rt1010: provide flexspi clock source Add FlexSPI clock source to RT1010 devicetree definition for FlexSPI node, to match FlexSPI clock source defined on standard FlexSPI dt node that is removed in the RT1010 devicetree. Fixes #68488 Signed-off-by: Daniel DeGrasse --- dts/arm/nxp/nxp_rt1010.dtsi | 1 + 1 file changed, 1 insertion(+) diff --git a/dts/arm/nxp/nxp_rt1010.dtsi b/dts/arm/nxp/nxp_rt1010.dtsi index 84d47e0f35e..f9f06dc56d0 100644 --- a/dts/arm/nxp/nxp_rt1010.dtsi +++ b/dts/arm/nxp/nxp_rt1010.dtsi @@ -112,6 +112,7 @@ ahb-bufferable; ahb-cacheable; status = "disabled"; + clocks = <&ccm IMX_CCM_FLEXSPI_CLK 0x0 0x0>; }; /* Remove SEMC, it does'nt exist on RT1010 */ From 583f24e7e8caa624e186cd54bf6527c9103f6883 Mon Sep 17 00:00:00 2001 From: Guilherme Casa Nova Date: Tue, 30 Jan 2024 16:24:21 -0600 Subject: [PATCH 3466/3723] i2c_mcux_flexcomm: add transaction timeout option With the device_sync_sem semaphore, there is the possibility of the code not returning to give it back (mcux_flexcomm_master_transfer_callback is never called), causing it to get stuck in k_sem_take(&data->device_sync_sem, K_FOREVER) in subsequent calls. The i2c driver recovers by other means (enabling FSL_FEATURE_I2C_TIMEOUT_RECOVERY) but the callback might not return. Adding a timeout option allows for this occurrence to be avoided. Signed-off-by: Guilherme Casa Nova --- drivers/i2c/Kconfig | 1 + drivers/i2c/Kconfig.mcux | 14 ++++++++++++++ drivers/i2c/i2c_mcux_flexcomm.c | 6 +++++- 3 files changed, 20 insertions(+), 1 deletion(-) create mode 100644 drivers/i2c/Kconfig.mcux diff --git a/drivers/i2c/Kconfig b/drivers/i2c/Kconfig index b486977fbb0..86e9cd87934 100644 --- a/drivers/i2c/Kconfig +++ b/drivers/i2c/Kconfig @@ -93,6 +93,7 @@ source "drivers/i2c/Kconfig.mchp_mss" source "drivers/i2c/Kconfig.sedi" source "drivers/i2c/Kconfig.ambiq" source "drivers/i2c/Kconfig.numaker" +source "drivers/i2c/Kconfig.mcux" config I2C_INIT_PRIORITY int "Init priority" diff --git a/drivers/i2c/Kconfig.mcux b/drivers/i2c/Kconfig.mcux new file mode 100644 index 00000000000..7c519abac3b --- /dev/null +++ b/drivers/i2c/Kconfig.mcux @@ -0,0 +1,14 @@ +# I2C configuration options + +# Copyright (c) 2024, NXP +# SPDX-License-Identifier: Apache-2.0 + +config I2C_NXP_TRANSFER_TIMEOUT + int "Transfer timeout [ms]" + default 0 + help + Timeout in milliseconds used for each I2C transfer. + 0 means that the driver should use the K_FOREVER value, + i.e. it should wait as long as necessary. + In conjunction with this, FSL_FEATURE_I2C_TIMEOUT_RECOVERY + must be enabled to allow the driver to fully recover. diff --git a/drivers/i2c/i2c_mcux_flexcomm.c b/drivers/i2c/i2c_mcux_flexcomm.c index 2eee6adebda..151992ecc9d 100644 --- a/drivers/i2c/i2c_mcux_flexcomm.c +++ b/drivers/i2c/i2c_mcux_flexcomm.c @@ -19,6 +19,10 @@ LOG_MODULE_REGISTER(mcux_flexcomm); #include "i2c-priv.h" +#define I2C_TRANSFER_TIMEOUT_MSEC \ + COND_CODE_0(CONFIG_I2C_NXP_TRANSFER_TIMEOUT, (K_FOREVER), \ + (K_MSEC(CONFIG_I2C_NXP_TRANSFER_TIMEOUT))) + struct mcux_flexcomm_config { I2C_Type *base; const struct device *clock_dev; @@ -168,7 +172,7 @@ static int mcux_flexcomm_transfer(const struct device *dev, } /* Wait for the transfer to complete */ - k_sem_take(&data->device_sync_sem, K_FOREVER); + k_sem_take(&data->device_sync_sem, I2C_TRANSFER_TIMEOUT_MSEC); /* Return an error if the transfer didn't complete * successfully. e.g., nak, timeout, lost arbitration From b5bf5a3cef26c1c23ce4f108827c28252e360aa0 Mon Sep 17 00:00:00 2001 From: Manuel Schappacher Date: Wed, 31 Jan 2024 22:05:55 +0100 Subject: [PATCH 3467/3723] net: gptp: Use local port identity when forwarding sync messages As defined in IEEE802.1AS-2020 ch. 10.2.12.2.1, the port identity of an MDSyncSend structure sent from a port shall be set to the port identity of the sending port according to and ch. 8.5.2. This commit replaces the port identity before forwarding a sync. Fixes #68385 Signed-off-by: Manuel Schappacher --- subsys/net/l2/ethernet/gptp/gptp_mi.c | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/subsys/net/l2/ethernet/gptp/gptp_mi.c b/subsys/net/l2/ethernet/gptp/gptp_mi.c index 03c8ee3ef0c..2e460ce0303 100644 --- a/subsys/net/l2/ethernet/gptp/gptp_mi.c +++ b/subsys/net/l2/ethernet/gptp/gptp_mi.c @@ -560,6 +560,15 @@ static void gptp_mi_pss_send_state_machine(int port) k_timer_start(&state->half_sync_itv_timer, duration, K_NO_WAIT); + /* sourcePortIdentity is set to the portIdentity of this + * PTP Port (see ch. 10.2.12.2.1 and ch 8.5.2). + */ + memcpy(&state->pss_sync_ptr->sync_info.src_port_id.clk_id, + GPTP_DEFAULT_DS()->clk_id, + GPTP_CLOCK_ID_LEN); + state->pss_sync_ptr->sync_info.src_port_id.port_number = port; + + gptp_mi_pss_send_md_sync_send(port); __fallthrough; From 031f84dff5d3e1eb8ce8bbb59d168690126dfe92 Mon Sep 17 00:00:00 2001 From: Jacob Siverskog Date: Thu, 11 Jan 2024 14:56:46 +0100 Subject: [PATCH 3468/3723] manifest: bump hal_nxp revision this brings in a newer version of the usb middleware. see https://github.com/zephyrproject-rtos/hal_nxp/pull/316 for more information. Signed-off-by: Jacob Siverskog --- west.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/west.yml b/west.yml index 0f130ef20d5..7909b3676cf 100644 --- a/west.yml +++ b/west.yml @@ -193,7 +193,7 @@ manifest: groups: - hal - name: hal_nxp - revision: 0463d6aa0de62761fb9ae56e3521c61b0e490374 + revision: d45b14c198d778658b7853b48378d2e132a6c4be path: modules/hal/nxp groups: - hal From 3409d0ab27b7d96b1e72cc1f219816b6f6960837 Mon Sep 17 00:00:00 2001 From: Gaetan Perrot Date: Thu, 1 Feb 2024 00:19:49 +0900 Subject: [PATCH 3469/3723] doc: posix: mark sched_getscheduler and getparam as supported `sched_getscheduler()` and `sched_getparam()` is now implemented, mark it so. Was missing on the documentation before. signed-off-by: Gaetan Perrot --- doc/services/portability/posix/option_groups/index.rst | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/doc/services/portability/posix/option_groups/index.rst b/doc/services/portability/posix/option_groups/index.rst index efdb2917d65..55b11d3da20 100644 --- a/doc/services/portability/posix/option_groups/index.rst +++ b/doc/services/portability/posix/option_groups/index.rst @@ -377,8 +377,8 @@ _POSIX_PRIORITY_SCHEDULING sched_get_priority_max(),yes sched_get_priority_min(),yes - sched_getparam(), - sched_getscheduler(), + sched_getparam(),yes + sched_getscheduler(),yes sched_rr_get_interval(),yes sched_setparam(),yes sched_setscheduler(),yes From c81eaff1d9306d49049b60b58d11b60ff5a34c42 Mon Sep 17 00:00:00 2001 From: Grant Ramsay Date: Sun, 28 Jan 2024 11:40:00 +1300 Subject: [PATCH 3470/3723] tests: kernel: mem_protect: Handle thumb instructions for Cortex-R Check for COMPILER_ISA_THUMB2 rather than CPU_CORTEX_M when determining if special handling is required for thumb instructions. This prevents false negative results on Cortex-R devices that may generate a fault (test pass) even if the MMU/MPU is not configured correctly. Signed-off-by: Grant Ramsay --- tests/kernel/mem_protect/protection/src/main.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/tests/kernel/mem_protect/protection/src/main.c b/tests/kernel/mem_protect/protection/src/main.c index 328531f54af..2f66edcdb90 100644 --- a/tests/kernel/mem_protect/protection/src/main.c +++ b/tests/kernel/mem_protect/protection/src/main.c @@ -34,8 +34,7 @@ void k_sys_fatal_error_handler(unsigned int reason, const z_arch_esf_t *pEsf) ztest_test_pass(); } -#ifdef CONFIG_CPU_CORTEX_M -#include +#ifdef CONFIG_COMPILER_ISA_THUMB2 /* Must clear LSB of function address to access as data. */ #define FUNC_TO_PTR(x) (void *)((uintptr_t)(x) & ~0x1) /* Must set LSB of function address to call in Thumb mode. */ From 211ddf1c7e09050051c95450d0f8974af56811c7 Mon Sep 17 00:00:00 2001 From: Grant Ramsay Date: Sun, 28 Jan 2024 11:51:13 +1300 Subject: [PATCH 3471/3723] soc: arm: xilinx_zynqmp: Add "Execute Never" MPU flag to non-code RAM Executing from RAM sections other than rom/code should cause a fault. This is tested as part of the kernel mem_protect tests. Signed-off-by: Grant Ramsay --- soc/arm/xilinx_zynqmp/arm_mpu_regions.c | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/soc/arm/xilinx_zynqmp/arm_mpu_regions.c b/soc/arm/xilinx_zynqmp/arm_mpu_regions.c index 5a6f8dc6c21..a4f36402d2c 100644 --- a/soc/arm/xilinx_zynqmp/arm_mpu_regions.c +++ b/soc/arm/xilinx_zynqmp/arm_mpu_regions.c @@ -22,11 +22,12 @@ | MPU_RASR_B_Msk) \ } -#define MPUTYPE_PRIV_WBWACACHE \ +#define MPUTYPE_PRIV_WBWACACHE_XN \ { \ .rasr = (P_RW_U_NA_Msk \ | (5 << MPU_RASR_TEX_Pos) \ - | MPU_RASR_B_Msk) \ + | MPU_RASR_B_Msk \ + | MPU_RASR_XN_Msk) \ } #define MPUTYPE_PRIV_DEVICE \ @@ -45,7 +46,7 @@ static const struct arm_mpu_region mpu_regions[] = { MPU_REGION_ENTRY("SRAM_PRIV", 0x00000000, REGION_2G, - MPUTYPE_PRIV_WBWACACHE), + MPUTYPE_PRIV_WBWACACHE_XN), MPU_REGION_ENTRY("SRAM", 0x00000000, From 9183ceaf911965fd1e30f4172e0518c176ed644a Mon Sep 17 00:00:00 2001 From: Anas Nashif Date: Wed, 24 Jan 2024 21:46:14 -0500 Subject: [PATCH 3472/3723] cache: introduce incoherent cache interface Introduce a set of cache APIs used on architectures with cache incoherency. Signed-off-by: Anas Nashif --- arch/Kconfig | 18 +++++++ doc/zephyr.doxyfile.in | 1 + include/zephyr/arch/cache.h | 14 +++++ include/zephyr/cache.h | 102 ++++++++++++++++++++++++++++++++++++ 4 files changed, 135 insertions(+) diff --git a/arch/Kconfig b/arch/Kconfig index 39800a1b7b7..1e28103509f 100644 --- a/arch/Kconfig +++ b/arch/Kconfig @@ -730,6 +730,13 @@ config CPU_HAS_DCACHE help This hidden configuration should be selected when the CPU has a d-cache. +config CPU_CACHE_INCOHERENT + bool + help + This hidden configuration should be selected when the CPU has + incoherent cache. This applies to intra-CPU multiprocessing + incoherence and makes only sense when MP_NUM_CPUS > 1. + config CPU_HAS_ICACHE bool help @@ -925,6 +932,17 @@ config ICACHE help This option enables the support for the instruction cache (i-cache). +config CACHE_DOUBLEMAP + bool "Cache double-mapping support" + depends on CPU_CACHE_INCOHERENT + default y + help + Double-mapping behavior where a pointer can be cheaply converted to + point to the same cached/uncached memory at different locations. + + This applies to intra-CPU multiprocessing incoherence and makes only + sense when MP_NUM_CPUS > 1. + config CACHE_MANAGEMENT bool "Cache management features" depends on DCACHE || ICACHE diff --git a/doc/zephyr.doxyfile.in b/doc/zephyr.doxyfile.in index 2332b2f5932..29b4651765b 100644 --- a/doc/zephyr.doxyfile.in +++ b/doc/zephyr.doxyfile.in @@ -2399,6 +2399,7 @@ PREDEFINED = __DOXYGEN__ \ XEN_GUEST_HANDLE_64(x)= \ _LINKER \ __deprecated= \ + __sparse_cache= \ __packed= \ __aligned(x)= \ __attribute_nonnull(...)= \ diff --git a/include/zephyr/arch/cache.h b/include/zephyr/arch/cache.h index f2943bdd7f9..1516f03ee72 100644 --- a/include/zephyr/arch/cache.h +++ b/include/zephyr/arch/cache.h @@ -335,6 +335,20 @@ size_t arch_icache_line_size_get(void); #endif /* CONFIG_ICACHE || __DOXYGEN__ */ +#if CONFIG_CACHE_DOUBLEMAP || __DOXYGEN__ +bool arch_cache_is_ptr_cached(void *ptr); +#define cache_is_ptr_cached(ptr) arch_cache_is_ptr_cached(ptr) + +bool arch_cache_is_ptr_uncached(void *ptr); +#define cache_is_ptr_uncached(ptr) arch_cache_is_ptr_uncached(ptr) + +void __sparse_cache *arch_cache_cached_ptr_get(void *ptr); +#define cache_cached_ptr(ptr) arch_cache_cached_ptr_get(ptr) + +void *arch_cache_uncached_ptr_get(void __sparse_cache *ptr); +#define cache_uncached_ptr(ptr) arch_cache_uncached_ptr_get(ptr) +#endif /* CONFIG_CACHE_DOUBLEMAP */ + /** * @} */ diff --git a/include/zephyr/cache.h b/include/zephyr/cache.h index 994d96dccbe..f5547f64afd 100644 --- a/include/zephyr/cache.h +++ b/include/zephyr/cache.h @@ -15,6 +15,7 @@ #include #include +#include #ifdef __cplusplus extern "C" { @@ -441,6 +442,107 @@ static ALWAYS_INLINE size_t sys_cache_instr_line_size_get(void) #endif } +/** + * @brief Test if a pointer is in cached region. + * + * Some hardware may map the same physical memory twice + * so that it can be seen in both (incoherent) cached mappings + * and a coherent "shared" area. This tests if a particular + * pointer is within the cached, coherent area. + * + * @param ptr Pointer + * + * @retval True if pointer is in cached region. + * @retval False if pointer is not in cached region. + */ +static ALWAYS_INLINE bool sys_cache_is_ptr_cached(void *ptr) +{ +#if defined(CONFIG_CACHE_MANAGEMENT) && defined(CONFIG_CACHE_DOUBLEMAP) + return cache_is_ptr_cached(ptr); +#else + ARG_UNUSED(ptr); + + return false; +#endif +} + +/** + * @brief Test if a pointer is in un-cached region. + * + * Some hardware may map the same physical memory twice + * so that it can be seen in both (incoherent) cached mappings + * and a coherent "shared" area. This tests if a particular + * pointer is within the un-cached, incoherent area. + * + * @param ptr Pointer + * + * @retval True if pointer is not in cached region. + * @retval False if pointer is in cached region. + */ +static ALWAYS_INLINE bool sys_cache_is_ptr_uncached(void *ptr) +{ +#if defined(CONFIG_CACHE_MANAGEMENT) && defined(CONFIG_CACHE_DOUBLEMAP) + return cache_is_ptr_uncached(ptr); +#else + ARG_UNUSED(ptr); + + return false; +#endif +} + +/** + * @brief Return cached pointer to a RAM address + * + * This function takes a pointer to any addressable object (either in + * cacheable memory or not) and returns a pointer that can be used to + * refer to the same memory through the L1 data cache. Data read + * through the resulting pointer will reflect locally cached values on + * the current CPU if they exist, and writes will go first into the + * cache and be written back later. + * + * @note This API returns the same pointer if CONFIG_CACHE_DOUBLEMAP is not + * enabled. + * + * @see arch_uncached_ptr() + * + * @param ptr A pointer to a valid C object + * @return A pointer to the same object via the L1 dcache + */ +static ALWAYS_INLINE void __sparse_cache *sys_cache_cached_ptr_get(void *ptr) +{ +#if defined(CONFIG_CACHE_MANAGEMENT) && defined(CONFIG_CACHE_DOUBLEMAP) + return cache_cached_ptr(ptr); +#else + return (__sparse_force void __sparse_cache *)ptr; +#endif +} + +/** + * @brief Return uncached pointer to a RAM address + * + * This function takes a pointer to any addressable object (either in + * cacheable memory or not) and returns a pointer that can be used to + * refer to the same memory while bypassing the L1 data cache. Data + * in the L1 cache will not be inspected nor modified by the access. + * + * @note This API returns the same pointer if CONFIG_CACHE_DOUBLEMAP is not + * enabled. + * + * @see arch_cached_ptr() + * + * @param ptr A pointer to a valid C object + * @return A pointer to the same object bypassing the L1 dcache + */ +static ALWAYS_INLINE void *sys_cache_uncached_ptr_get(void __sparse_cache *ptr) +{ +#if defined(CONFIG_CACHE_MANAGEMENT) && defined(CONFIG_CACHE_DOUBLEMAP) + return cache_uncached_ptr(ptr); +#else + return (__sparse_force void *)ptr; +#endif +} + + #ifdef CONFIG_LIBMETAL static ALWAYS_INLINE void sys_cache_flush(void *addr, size_t size) { From d7678f1694e7790dc6a0281e330971cebb4123f5 Mon Sep 17 00:00:00 2001 From: Anas Nashif Date: Wed, 24 Jan 2024 21:20:26 -0500 Subject: [PATCH 3473/3723] xtensa: move to use system cache API support for coherency Remove custom implementation and use system cache interface instead. Signed-off-by: Anas Nashif --- arch/xtensa/core/mem_manage.c | 5 +- arch/xtensa/core/ptables.c | 36 ++--- drivers/console/winstream_console.c | 4 +- drivers/ipm/ipm_cavs_host.c | 8 +- drivers/mm/mm_drv_intel_adsp_mtl_tlb.c | 34 ++--- drivers/mm/mm_drv_intel_adsp_tlb.c | 31 ++-- include/zephyr/arch/xtensa/arch.h | 139 ------------------ include/zephyr/arch/xtensa/cache.h | 138 +++++++++++++++++ soc/xtensa/intel_adsp/Kconfig | 2 + soc/xtensa/intel_adsp/ace/multiprocessing.c | 2 +- soc/xtensa/intel_adsp/ace/power.c | 2 +- soc/xtensa/intel_adsp/cavs/multiprocessing.c | 5 +- soc/xtensa/intel_adsp/cavs/power.c | 3 +- soc/xtensa/intel_adsp/common/boot_complete.c | 4 +- .../common/include/adsp_debug_window.h | 3 +- .../common/include/intel_adsp_hda.h | 2 +- soc/xtensa/intel_adsp/common/include/soc.h | 4 - tests/boards/intel_adsp/cache/src/main.c | 2 +- tests/boards/intel_adsp/smoke/src/cpus.c | 12 +- 19 files changed, 218 insertions(+), 218 deletions(-) diff --git a/arch/xtensa/core/mem_manage.c b/arch/xtensa/core/mem_manage.c index e43bf4b75d6..0085000d5ce 100644 --- a/arch/xtensa/core/mem_manage.c +++ b/arch/xtensa/core/mem_manage.c @@ -8,11 +8,12 @@ #include #include #include +#include __weak bool sys_mm_is_phys_addr_in_range(uintptr_t phys) { bool valid; - uintptr_t cached = (uintptr_t)arch_xtensa_cached_ptr((void *)phys); + uintptr_t cached = (uintptr_t)sys_cache_cached_ptr_get((void *)phys); valid = ((phys >= CONFIG_SRAM_BASE_ADDRESS) && (phys < (CONFIG_SRAM_BASE_ADDRESS + (CONFIG_SRAM_SIZE * 1024UL)))); @@ -28,7 +29,7 @@ __weak bool sys_mm_is_virt_addr_in_range(void *virt) bool valid; uintptr_t addr = (uintptr_t)virt; - uintptr_t cached = (uintptr_t)arch_xtensa_cached_ptr(virt); + uintptr_t cached = (uintptr_t)sys_cache_cached_ptr_get(virt); valid = ((addr >= CONFIG_KERNEL_VM_BASE) && (addr < (CONFIG_KERNEL_VM_BASE + CONFIG_KERNEL_VM_SIZE))); diff --git a/arch/xtensa/core/ptables.c b/arch/xtensa/core/ptables.c index ec8295f6144..bd2e8a61581 100644 --- a/arch/xtensa/core/ptables.c +++ b/arch/xtensa/core/ptables.c @@ -255,13 +255,13 @@ static void map_memory(const uint32_t start, const uint32_t end, map_memory_range(start, end, attrs, shared); #ifdef CONFIG_XTENSA_MMU_DOUBLE_MAP - if (arch_xtensa_is_ptr_uncached((void *)start)) { - map_memory_range(POINTER_TO_UINT(z_soc_cached_ptr((void *)start)), - POINTER_TO_UINT(z_soc_cached_ptr((void *)end)), + if (sys_cache_is_ptr_uncached((void *)start)) { + map_memory_range(POINTER_TO_UINT(sys_cache_cached_ptr_get((void *)start)), + POINTER_TO_UINT(sys_cache_cached_ptr_get((void *)end)), attrs | XTENSA_MMU_CACHED_WB, shared); - } else if (arch_xtensa_is_ptr_cached((void *)start)) { - map_memory_range(POINTER_TO_UINT(z_soc_uncached_ptr((void *)start)), - POINTER_TO_UINT(z_soc_uncached_ptr((void *)end)), attrs, shared); + } else if (sys_cache_is_ptr_cached((void *)start)) { + map_memory_range(POINTER_TO_UINT(sys_cache_uncached_ptr_get((void *)start)), + POINTER_TO_UINT(sys_cache_uncached_ptr_get((void *)end)), attrs, shared); } #endif } @@ -413,19 +413,19 @@ static inline void __arch_mem_map(void *va, uintptr_t pa, uint32_t xtensa_flags, uint32_t flags, flags_uc; if (IS_ENABLED(CONFIG_XTENSA_MMU_DOUBLE_MAP)) { - if (arch_xtensa_is_ptr_cached(va)) { + if (sys_cache_is_ptr_cached(va)) { vaddr = va; - vaddr_uc = arch_xtensa_uncached_ptr(va); + vaddr_uc = sys_cache_uncached_ptr_get(va); } else { - vaddr = arch_xtensa_cached_ptr(va); + vaddr = sys_cache_cached_ptr_get(va); vaddr_uc = va; } - if (arch_xtensa_is_ptr_cached((void *)pa)) { + if (sys_cache_is_ptr_cached((void *)pa)) { paddr = pa; - paddr_uc = (uintptr_t)arch_xtensa_uncached_ptr((void *)pa); + paddr_uc = (uintptr_t)sys_cache_uncached_ptr_get((void *)pa); } else { - paddr = (uintptr_t)arch_xtensa_cached_ptr((void *)pa); + paddr = (uintptr_t)sys_cache_cached_ptr_get((void *)pa); paddr_uc = pa; } @@ -588,11 +588,11 @@ static inline void __arch_mem_unmap(void *va) void *vaddr, *vaddr_uc; if (IS_ENABLED(CONFIG_XTENSA_MMU_DOUBLE_MAP)) { - if (arch_xtensa_is_ptr_cached(va)) { + if (sys_cache_is_ptr_cached(va)) { vaddr = va; - vaddr_uc = arch_xtensa_uncached_ptr(va); + vaddr_uc = sys_cache_uncached_ptr_get(va); } else { - vaddr = arch_xtensa_cached_ptr(va); + vaddr = sys_cache_cached_ptr_get(va); vaddr_uc = va; } } else { @@ -866,11 +866,11 @@ static inline int update_region(uint32_t *ptables, uintptr_t start, uintptr_t va, va_uc; uint32_t new_flags, new_flags_uc; - if (arch_xtensa_is_ptr_cached((void *)start)) { + if (sys_cache_is_ptr_cached((void *)start)) { va = start; - va_uc = (uintptr_t)arch_xtensa_uncached_ptr((void *)start); + va_uc = (uintptr_t)sys_cache_uncached_ptr_get((void *)start); } else { - va = (uintptr_t)arch_xtensa_cached_ptr((void *)start); + va = (uintptr_t)sys_cache_cached_ptr_get((void *)start); va_uc = start; } diff --git a/drivers/console/winstream_console.c b/drivers/console/winstream_console.c index 442616aaf3e..8d056a8f6f8 100644 --- a/drivers/console/winstream_console.c +++ b/drivers/console/winstream_console.c @@ -8,10 +8,10 @@ #include #include #include +#include #include #include -#include struct k_spinlock trace_lock; @@ -78,7 +78,7 @@ static int winstream_console_init(void) } const struct mem_win_config *config = dev->config; void *buf = - arch_xtensa_uncached_ptr((__sparse_force void __sparse_cache *)config->mem_base); + sys_cache_uncached_ptr_get((__sparse_force void __sparse_cache *)config->mem_base); winstream = sys_winstream_init(buf, config->size); winstream_console_hook_install(); diff --git a/drivers/ipm/ipm_cavs_host.c b/drivers/ipm/ipm_cavs_host.c index 5877309d48d..2a6acef6efb 100644 --- a/drivers/ipm/ipm_cavs_host.c +++ b/drivers/ipm/ipm_cavs_host.c @@ -7,6 +7,7 @@ #include #include #include +#include /* Matches SOF_IPC_MSG_MAX_SIZE, though in practice nothing anywhere * near that big is ever sent. Should maybe consider making this a @@ -49,8 +50,9 @@ static int send(const struct device *dev, int wait, uint32_t id, return -ENODEV; } const struct mem_win_config *mw0_config = mw0->config; - uint32_t *buf = (uint32_t *)arch_xtensa_uncached_ptr((void *)((uint32_t)mw0_config->mem_base - + CONFIG_IPM_CAVS_HOST_OUTBOX_OFFSET)); + uint32_t *buf = (uint32_t *)sys_cache_uncached_ptr_get( + (void *)((uint32_t)mw0_config->mem_base + + CONFIG_IPM_CAVS_HOST_OUTBOX_OFFSET)); if (!intel_adsp_ipc_is_complete(INTEL_ADSP_IPC_HOST_DEV)) { return -EBUSY; @@ -108,7 +110,7 @@ static bool ipc_handler(const struct device *dev, void *arg, return -ENODEV; } const struct mem_win_config *mw1_config = mw1->config; - uint32_t *msg = arch_xtensa_uncached_ptr((void *)mw1_config->mem_base); + uint32_t *msg = sys_cache_uncached_ptr_get((void *)mw1_config->mem_base); /* We play tricks to leave one word available before the * beginning of the SRAM window, this way the host can see the diff --git a/drivers/mm/mm_drv_intel_adsp_mtl_tlb.c b/drivers/mm/mm_drv_intel_adsp_mtl_tlb.c index ea3bb385b3b..a068abafc36 100644 --- a/drivers/mm/mm_drv_intel_adsp_mtl_tlb.c +++ b/drivers/mm/mm_drv_intel_adsp_mtl_tlb.c @@ -16,7 +16,7 @@ * Note that all passed in addresses should be in cached range * (aka cached addresses). Due to the need to calculate TLB * indexes, virtual addresses will be converted internally to - * cached one via z_soc_cached_ptr(). However, physical addresses + * cached one via sys_cache_cached_ptr_get(). However, physical addresses * are untouched. */ @@ -183,8 +183,8 @@ int sys_mm_drv_map_page(void *virt, uintptr_t phys, uint32_t flags) * the cached physical address is needed to perform * bound check. */ - uintptr_t pa = POINTER_TO_UINT(z_soc_cached_ptr(UINT_TO_POINTER(phys))); - uintptr_t va = POINTER_TO_UINT(z_soc_cached_ptr(virt)); + uintptr_t pa = POINTER_TO_UINT(sys_cache_cached_ptr_get(UINT_TO_POINTER(phys))); + uintptr_t va = POINTER_TO_UINT(sys_cache_cached_ptr_get(virt)); ARG_UNUSED(flags); @@ -215,7 +215,7 @@ int sys_mm_drv_map_page(void *virt, uintptr_t phys, uint32_t flags) "unable to assign free phys page %d\n", ret); goto out; } - pa = POINTER_TO_UINT(z_soc_cached_ptr(phys_block_ptr)); + pa = POINTER_TO_UINT(sys_cache_cached_ptr_get(phys_block_ptr)); } /* Check bounds of physical address space */ @@ -296,7 +296,7 @@ int sys_mm_drv_map_region(void *virt, uintptr_t phys, goto out; } - va = (__sparse_force uint8_t *)z_soc_cached_ptr(virt); + va = (__sparse_force uint8_t *)sys_cache_cached_ptr_get(virt); pa = phys; key = k_spin_lock(&sys_mm_drv_common_lock); @@ -324,7 +324,7 @@ int sys_mm_drv_map_region(void *virt, uintptr_t phys, int sys_mm_drv_map_array(void *virt, uintptr_t *phys, size_t cnt, uint32_t flags) { - void *va = (__sparse_force void *)z_soc_cached_ptr(virt); + void *va = (__sparse_force void *)sys_cache_cached_ptr_get(virt); return sys_mm_drv_simple_map_array(va, phys, cnt, flags); } @@ -339,7 +339,7 @@ int sys_mm_drv_unmap_page(void *virt) int ret = 0; /* Use cached virtual address */ - uintptr_t va = POINTER_TO_UINT(z_soc_cached_ptr(virt)); + uintptr_t va = POINTER_TO_UINT(sys_cache_cached_ptr_get(virt)); /* Check bounds of virtual address space */ CHECKIF((va < UNUSED_L2_START_ALIGNED) || @@ -396,7 +396,7 @@ int sys_mm_drv_unmap_page(void *virt) int sys_mm_drv_unmap_region(void *virt, size_t size) { - void *va = (__sparse_force void *)z_soc_cached_ptr(virt); + void *va = (__sparse_force void *)sys_cache_cached_ptr_get(virt); return sys_mm_drv_simple_unmap_region(va, size); } @@ -408,7 +408,7 @@ int sys_mm_drv_page_phys_get(void *virt, uintptr_t *phys) int ret = 0; /* Use cached address */ - uintptr_t va = POINTER_TO_UINT(z_soc_cached_ptr(virt)); + uintptr_t va = POINTER_TO_UINT(sys_cache_cached_ptr_get(virt)); CHECKIF(!sys_mm_drv_is_addr_aligned(va)) { ret = -EINVAL; @@ -449,7 +449,7 @@ int sys_mm_drv_page_flag_get(void *virt, uint32_t *flags) uint16_t ent; /* Use cached address */ - uintptr_t va = POINTER_TO_UINT(z_soc_cached_ptr(virt)); + uintptr_t va = POINTER_TO_UINT(sys_cache_cached_ptr_get(virt)); CHECKIF(!sys_mm_drv_is_addr_aligned(va)) { ret = -EINVAL; @@ -487,8 +487,8 @@ int sys_mm_drv_page_flag_get(void *virt, uint32_t *flags) int sys_mm_drv_remap_region(void *virt_old, size_t size, void *virt_new) { - void *va_new = (__sparse_force void *)z_soc_cached_ptr(virt_new); - void *va_old = (__sparse_force void *)z_soc_cached_ptr(virt_old); + void *va_new = (__sparse_force void *)sys_cache_cached_ptr_get(virt_new); + void *va_old = (__sparse_force void *)sys_cache_cached_ptr_get(virt_old); return sys_mm_drv_simple_remap_region(va_old, size, va_new); } @@ -500,8 +500,8 @@ int sys_mm_drv_move_region(void *virt_old, size_t size, void *virt_new, size_t offset; int ret = 0; - virt_new = (__sparse_force void *)z_soc_cached_ptr(virt_new); - virt_old = (__sparse_force void *)z_soc_cached_ptr(virt_old); + virt_new = (__sparse_force void *)sys_cache_cached_ptr_get(virt_new); + virt_old = (__sparse_force void *)sys_cache_cached_ptr_get(virt_old); CHECKIF(!sys_mm_drv_is_virt_addr_aligned(virt_old) || !sys_mm_drv_is_virt_addr_aligned(virt_new) || @@ -598,8 +598,8 @@ int sys_mm_drv_move_array(void *virt_old, size_t size, void *virt_new, { int ret; - void *va_new = (__sparse_force void *)z_soc_cached_ptr(virt_new); - void *va_old = (__sparse_force void *)z_soc_cached_ptr(virt_old); + void *va_new = (__sparse_force void *)sys_cache_cached_ptr_get(virt_new); + void *va_old = (__sparse_force void *)sys_cache_cached_ptr_get(virt_old); ret = sys_mm_drv_simple_move_array(va_old, size, va_new, phys_new, phys_cnt); @@ -783,7 +783,7 @@ __imr void adsp_mm_restore_context(void *storage_buffer) while (phys_addr != 0) { uint32_t phys_addr_uncached = - POINTER_TO_UINT(z_soc_uncached_ptr( + POINTER_TO_UINT(sys_cache_uncached_ptr_get( (void __sparse_cache *)UINT_TO_POINTER(phys_addr))); uint32_t phys_offset = phys_addr - L2_SRAM_BASE; uint32_t bank_idx = (phys_offset / SRAM_BANK_SIZE); diff --git a/drivers/mm/mm_drv_intel_adsp_tlb.c b/drivers/mm/mm_drv_intel_adsp_tlb.c index 315496be8e0..0807bc787d1 100644 --- a/drivers/mm/mm_drv_intel_adsp_tlb.c +++ b/drivers/mm/mm_drv_intel_adsp_tlb.c @@ -16,7 +16,7 @@ * Note that all passed in addresses should be in cached range * (aka cached addresses). Due to the need to calculate TLB * indexes, virtual addresses will be converted internally to - * cached one via z_soc_cached_ptr(). However, physical addresses + * cached one via sys_cache_cached_ptr_get(). However, physical addresses * are untouched. */ @@ -32,7 +32,6 @@ #include #include -#include #include #include @@ -80,8 +79,8 @@ int sys_mm_drv_map_page(void *virt, uintptr_t phys, uint32_t flags) * the cached physical address is needed to perform * bound check. */ - uintptr_t pa = POINTER_TO_UINT(z_soc_cached_ptr(UINT_TO_POINTER(phys))); - uintptr_t va = POINTER_TO_UINT(z_soc_cached_ptr(virt)); + uintptr_t pa = POINTER_TO_UINT(sys_cache_cached_ptr_get(UINT_TO_POINTER(phys))); + uintptr_t va = POINTER_TO_UINT(sys_cache_cached_ptr_get(virt)); ARG_UNUSED(flags); @@ -145,7 +144,7 @@ int sys_mm_drv_map_page(void *virt, uintptr_t phys, uint32_t flags) int sys_mm_drv_map_region(void *virt, uintptr_t phys, size_t size, uint32_t flags) { - void *va = (__sparse_force void *)z_soc_cached_ptr(virt); + void *va = (__sparse_force void *)sys_cache_cached_ptr_get(virt); return sys_mm_drv_simple_map_region(va, phys, size, flags); } @@ -153,7 +152,7 @@ int sys_mm_drv_map_region(void *virt, uintptr_t phys, int sys_mm_drv_map_array(void *virt, uintptr_t *phys, size_t cnt, uint32_t flags) { - void *va = (__sparse_force void *)z_soc_cached_ptr(virt); + void *va = (__sparse_force void *)sys_cache_cached_ptr_get(virt); return sys_mm_drv_simple_map_array(va, phys, cnt, flags); } @@ -166,7 +165,7 @@ int sys_mm_drv_unmap_page(void *virt) int ret = 0; /* Use cached virtual address */ - uintptr_t va = POINTER_TO_UINT(z_soc_cached_ptr(virt)); + uintptr_t va = POINTER_TO_UINT(sys_cache_cached_ptr_get(virt)); /* Check bounds of virtual address space */ CHECKIF((va < CONFIG_KERNEL_VM_BASE) || @@ -202,7 +201,7 @@ int sys_mm_drv_unmap_page(void *virt) int sys_mm_drv_unmap_region(void *virt, size_t size) { - void *va = (__sparse_force void *)z_soc_cached_ptr(virt); + void *va = (__sparse_force void *)sys_cache_cached_ptr_get(virt); return sys_mm_drv_simple_unmap_region(va, size); } @@ -214,7 +213,7 @@ int sys_mm_drv_page_phys_get(void *virt, uintptr_t *phys) int ret = 0; /* Use cached address */ - uintptr_t va = POINTER_TO_UINT(z_soc_cached_ptr(virt)); + uintptr_t va = POINTER_TO_UINT(sys_cache_cached_ptr_get(virt)); CHECKIF(!sys_mm_drv_is_addr_aligned(va)) { ret = -EINVAL; @@ -274,7 +273,7 @@ int sys_mm_drv_update_page_flags(void *virt, uint32_t flags) int sys_mm_drv_update_region_flags(void *virt, size_t size, uint32_t flags) { - void *va = (__sparse_force void *)z_soc_cached_ptr(virt); + void *va = (__sparse_force void *)sys_cache_cached_ptr_get(virt); return sys_mm_drv_simple_update_region_flags(va, size, flags); } @@ -283,8 +282,8 @@ int sys_mm_drv_update_region_flags(void *virt, size_t size, int sys_mm_drv_remap_region(void *virt_old, size_t size, void *virt_new) { - void *va_new = (__sparse_force void *)z_soc_cached_ptr(virt_new); - void *va_old = (__sparse_force void *)z_soc_cached_ptr(virt_old); + void *va_new = (__sparse_force void *)sys_cache_cached_ptr_get(virt_new); + void *va_old = (__sparse_force void *)sys_cache_cached_ptr_get(virt_old); return sys_mm_drv_simple_remap_region(va_old, size, va_new); } @@ -294,8 +293,8 @@ int sys_mm_drv_move_region(void *virt_old, size_t size, void *virt_new, { int ret; - void *va_new = (__sparse_force void *)z_soc_cached_ptr(virt_new); - void *va_old = (__sparse_force void *)z_soc_cached_ptr(virt_old); + void *va_new = (__sparse_force void *)sys_cache_cached_ptr_get(virt_new); + void *va_old = (__sparse_force void *)sys_cache_cached_ptr_get(virt_old); ret = sys_mm_drv_simple_move_region(va_old, size, va_new, phys_new); @@ -314,8 +313,8 @@ int sys_mm_drv_move_array(void *virt_old, size_t size, void *virt_new, { int ret; - void *va_new = (__sparse_force void *)z_soc_cached_ptr(virt_new); - void *va_old = (__sparse_force void *)z_soc_cached_ptr(virt_old); + void *va_new = (__sparse_force void *)sys_cache_cached_ptr_get(virt_new); + void *va_old = (__sparse_force void *)sys_cache_cached_ptr_get(virt_old); ret = sys_mm_drv_simple_move_array(va_old, size, va_new, phys_new, phys_cnt); diff --git a/include/zephyr/arch/xtensa/arch.h b/include/zephyr/arch/xtensa/arch.h index 26325a984e1..f3358cafe2f 100644 --- a/include/zephyr/arch/xtensa/arch.h +++ b/include/zephyr/arch/xtensa/arch.h @@ -160,118 +160,6 @@ static inline bool arch_mem_coherent(void *ptr) } #endif -/** - * @brief Test if a pointer is in cached region. - * - * Some hardware may map the same physical memory twice - * so that it can be seen in both (incoherent) cached mappings - * and a coherent "shared" area. This tests if a particular - * pointer is within the cached, coherent area. - * - * @param ptr Pointer - * - * @retval True if pointer is in cached region. - * @retval False if pointer is not in cached region. - */ -static inline bool arch_xtensa_is_ptr_cached(void *ptr) -{ - size_t addr = (size_t) ptr; - - return (addr >> 29) == CONFIG_XTENSA_CACHED_REGION; -} - -/** - * @brief Test if a pointer is in un-cached region. - * - * Some hardware may map the same physical memory twice - * so that it can be seen in both (incoherent) cached mappings - * and a coherent "shared" area. This tests if a particular - * pointer is within the un-cached, incoherent area. - * - * @param ptr Pointer - * - * @retval True if pointer is not in cached region. - * @retval False if pointer is in cached region. - */ -static inline bool arch_xtensa_is_ptr_uncached(void *ptr) -{ - size_t addr = (size_t) ptr; - - return (addr >> 29) == CONFIG_XTENSA_UNCACHED_REGION; -} - -static ALWAYS_INLINE uint32_t z_xtrpoflip(uint32_t addr, uint32_t rto, uint32_t rfrom) -{ - /* The math here is all compile-time: when the two regions - * differ by a power of two, we can convert between them by - * setting or clearing just one bit. Otherwise it needs two - * operations. - */ - uint32_t rxor = (rto ^ rfrom) << 29; - - rto <<= 29; - if (Z_IS_POW2(rxor)) { - if ((rxor & rto) == 0) { - return addr & ~rxor; - } else { - return addr | rxor; - } - } else { - return (addr & ~(7U << 29)) | rto; - } -} - -/** - * @brief Return cached pointer to a RAM address - * - * The Xtensa coherence architecture maps addressable RAM twice, in - * two different 512MB regions whose L1 cache settings can be - * controlled independently. So for any given pointer, it is possible - * to convert it to and from a cached version. - * - * This function takes a pointer to any addressable object (either in - * cacheable memory or not) and returns a pointer that can be used to - * refer to the same memory through the L1 data cache. Data read - * through the resulting pointer will reflect locally cached values on - * the current CPU if they exist, and writes will go first into the - * cache and be written back later. - * - * @see arch_xtensa_uncached_ptr() - * - * @param ptr A pointer to a valid C object - * @return A pointer to the same object via the L1 dcache - */ -static inline void __sparse_cache *arch_xtensa_cached_ptr(void *ptr) -{ - return (__sparse_force void __sparse_cache *)z_xtrpoflip((uint32_t) ptr, - CONFIG_XTENSA_CACHED_REGION, - CONFIG_XTENSA_UNCACHED_REGION); -} - -/** - * @brief Return uncached pointer to a RAM address - * - * The Xtensa coherence architecture maps addressable RAM twice, in - * two different 512MB regions whose L1 cache settings can be - * controlled independently. So for any given pointer, it is possible - * to convert it to and from a cached version. - * - * This function takes a pointer to any addressable object (either in - * cacheable memory or not) and returns a pointer that can be used to - * refer to the same memory while bypassing the L1 data cache. Data - * in the L1 cache will not be inspected nor modified by the access. - * - * @see arch_xtensa_cached_ptr() - * - * @param ptr A pointer to a valid C object - * @return A pointer to the same object bypassing the L1 dcache - */ -static inline void *arch_xtensa_uncached_ptr(void __sparse_cache *ptr) -{ - return (void *)z_xtrpoflip((__sparse_force uint32_t)ptr, - CONFIG_XTENSA_UNCACHED_REGION, - CONFIG_XTENSA_CACHED_REGION); -} /* Utility to generate an unrolled and optimal[1] code sequence to set * the RPO TLB registers (contra the HAL cacheattr macros, which @@ -327,33 +215,6 @@ static inline void *arch_xtensa_uncached_ptr(void __sparse_cache *ptr) register uint32_t addr = 0, addrincr = 0x20000000; \ FOR_EACH(_SET_ONE_TLB, (;), 0, 1, 2, 3, 4, 5, 6, 7); \ } while (0) - -#else /* CONFIG_XTENSA_RPO_CACHE */ - -static inline bool arch_xtensa_is_ptr_cached(void *ptr) -{ - ARG_UNUSED(ptr); - - return false; -} - -static inline bool arch_xtensa_is_ptr_uncached(void *ptr) -{ - ARG_UNUSED(ptr); - - return false; -} - -static inline void *arch_xtensa_cached_ptr(void *ptr) -{ - return ptr; -} - -static inline void *arch_xtensa_uncached_ptr(void *ptr) -{ - return ptr; -} - #endif /* CONFIG_XTENSA_RPO_CACHE */ #if defined(CONFIG_XTENSA_MMU) || defined(__DOXYGEN__) diff --git a/include/zephyr/arch/xtensa/cache.h b/include/zephyr/arch/xtensa/cache.h index 6fb64ef30d5..c5964c16ce7 100644 --- a/include/zephyr/arch/xtensa/cache.h +++ b/include/zephyr/arch/xtensa/cache.h @@ -192,6 +192,144 @@ static ALWAYS_INLINE void arch_icache_disable(void) #endif /* CONFIG_ICACHE */ +#if defined(CONFIG_CACHE_DOUBLEMAP) +/** + * @brief Test if a pointer is in cached region. + * + * Some hardware may map the same physical memory twice + * so that it can be seen in both (incoherent) cached mappings + * and a coherent "shared" area. This tests if a particular + * pointer is within the cached, coherent area. + * + * @param ptr Pointer + * + * @retval True if pointer is in cached region. + * @retval False if pointer is not in cached region. + */ +static inline bool arch_cache_is_ptr_cached(void *ptr) +{ + size_t addr = (size_t) ptr; + + return (addr >> 29) == CONFIG_XTENSA_CACHED_REGION; +} + +/** + * @brief Test if a pointer is in un-cached region. + * + * Some hardware may map the same physical memory twice + * so that it can be seen in both (incoherent) cached mappings + * and a coherent "shared" area. This tests if a particular + * pointer is within the un-cached, incoherent area. + * + * @param ptr Pointer + * + * @retval True if pointer is not in cached region. + * @retval False if pointer is in cached region. + */ +static inline bool arch_cache_is_ptr_uncached(void *ptr) +{ + size_t addr = (size_t) ptr; + + return (addr >> 29) == CONFIG_XTENSA_UNCACHED_REGION; +} + +static ALWAYS_INLINE uint32_t z_xtrpoflip(uint32_t addr, uint32_t rto, uint32_t rfrom) +{ + /* The math here is all compile-time: when the two regions + * differ by a power of two, we can convert between them by + * setting or clearing just one bit. Otherwise it needs two + * operations. + */ + uint32_t rxor = (rto ^ rfrom) << 29; + + rto <<= 29; + if (Z_IS_POW2(rxor)) { + if ((rxor & rto) == 0) { + return addr & ~rxor; + } else { + return addr | rxor; + } + } else { + return (addr & ~(7U << 29)) | rto; + } +} + +/** + * @brief Return cached pointer to a RAM address + * + * The Xtensa coherence architecture maps addressable RAM twice, in + * two different 512MB regions whose L1 cache settings can be + * controlled independently. So for any given pointer, it is possible + * to convert it to and from a cached version. + * + * This function takes a pointer to any addressable object (either in + * cacheable memory or not) and returns a pointer that can be used to + * refer to the same memory through the L1 data cache. Data read + * through the resulting pointer will reflect locally cached values on + * the current CPU if they exist, and writes will go first into the + * cache and be written back later. + * + * @see arch_uncached_ptr() + * + * @param ptr A pointer to a valid C object + * @return A pointer to the same object via the L1 dcache + */ +static inline void __sparse_cache *arch_cache_cached_ptr_get(void *ptr) +{ + return (__sparse_force void __sparse_cache *)z_xtrpoflip((uint32_t) ptr, + CONFIG_XTENSA_CACHED_REGION, + CONFIG_XTENSA_UNCACHED_REGION); +} + +/** + * @brief Return uncached pointer to a RAM address + * + * The Xtensa coherence architecture maps addressable RAM twice, in + * two different 512MB regions whose L1 cache settings can be + * controlled independently. So for any given pointer, it is possible + * to convert it to and from a cached version. + * + * This function takes a pointer to any addressable object (either in + * cacheable memory or not) and returns a pointer that can be used to + * refer to the same memory while bypassing the L1 data cache. Data + * in the L1 cache will not be inspected nor modified by the access. + * + * @see arch_cached_ptr() + * + * @param ptr A pointer to a valid C object + * @return A pointer to the same object bypassing the L1 dcache + */ +static inline void *arch_cache_uncached_ptr_get(void __sparse_cache *ptr) +{ + return (void *)z_xtrpoflip((__sparse_force uint32_t)ptr, + CONFIG_XTENSA_UNCACHED_REGION, + CONFIG_XTENSA_CACHED_REGION); +} +#else +static inline bool arch_cache_is_ptr_cached(void *ptr) +{ + ARG_UNUSED(ptr); + + return false; +} + +static inline bool arch_cache_is_ptr_uncached(void *ptr) +{ + ARG_UNUSED(ptr); + + return false; +} + +static inline void *arch_cache_cached_ptr_get(void *ptr) +{ + return ptr; +} + +static inline void *arch_cache_uncached_ptr_get(void *ptr) +{ + return ptr; +} +#endif #ifdef __cplusplus diff --git a/soc/xtensa/intel_adsp/Kconfig b/soc/xtensa/intel_adsp/Kconfig index ed491015fac..32dae7612f5 100644 --- a/soc/xtensa/intel_adsp/Kconfig +++ b/soc/xtensa/intel_adsp/Kconfig @@ -7,6 +7,8 @@ config SOC_FAMILY_INTEL_ADSP select WINSTREAM select ARCH_SUPPORTS_COREDUMP select CPU_HAS_DCACHE + select ARCH_HAS_USERSPACE if XTENSA_MMU + select CPU_CACHE_INCOHERENT bool if SOC_FAMILY_INTEL_ADSP diff --git a/soc/xtensa/intel_adsp/ace/multiprocessing.c b/soc/xtensa/intel_adsp/ace/multiprocessing.c index 8e5657f033f..3170a8f1090 100644 --- a/soc/xtensa/intel_adsp/ace/multiprocessing.c +++ b/soc/xtensa/intel_adsp/ace/multiprocessing.c @@ -94,7 +94,7 @@ void soc_mp_init(void) * Only when more than 1 CPUs is enabled, then this is in uncached area. * Otherwise, this is in cached area and will fail this test. */ - __ASSERT(!arch_xtensa_is_ptr_cached(&g_key_read_holder), + __ASSERT(!sys_cache_is_ptr_cached(&g_key_read_holder), "g_key_read_holder must be uncached"); #endif /* defined(CONFIG_SMP) && (CONFIG_MP_MAX_NUM_CPUS > 1) */ g_key_read_holder = INTEL_ADSP_ACE15_MAGIC_KEY; diff --git a/soc/xtensa/intel_adsp/ace/power.c b/soc/xtensa/intel_adsp/ace/power.c index 878d6a58bc2..b77246ad50e 100644 --- a/soc/xtensa/intel_adsp/ace/power.c +++ b/soc/xtensa/intel_adsp/ace/power.c @@ -227,7 +227,7 @@ __imr void pm_state_imr_restore(void) { struct imr_layout *imr_layout = (struct imr_layout *)(IMR_LAYOUT_ADDRESS); /* restore lpsram power and contents */ - bmemcpy(z_soc_uncached_ptr((__sparse_force void __sparse_cache *) + bmemcpy(sys_cache_uncached_ptr_get((__sparse_force void __sparse_cache *) UINT_TO_POINTER(LP_SRAM_BASE)), imr_layout->imr_state.header.imr_ram_storage, LP_SRAM_SIZE); diff --git a/soc/xtensa/intel_adsp/cavs/multiprocessing.c b/soc/xtensa/intel_adsp/cavs/multiprocessing.c index 5b13b813858..2a38f20355d 100644 --- a/soc/xtensa/intel_adsp/cavs/multiprocessing.c +++ b/soc/xtensa/intel_adsp/cavs/multiprocessing.c @@ -5,9 +5,9 @@ #include #include #include -#include #include #include +#include /* IDC power up message to the ROM firmware. This isn't documented * anywhere, it's basically just a magic number (except the high bit, @@ -62,7 +62,8 @@ void soc_start_core(int cpu_num) * such that the standard system bootstrap out of IMR can * place it there. But this is fine for now. */ - void **lpsram = z_soc_uncached_ptr((__sparse_force void __sparse_cache *)LP_SRAM_BASE); + void **lpsram = sys_cache_uncached_ptr_get( + (__sparse_force void __sparse_cache *)LP_SRAM_BASE); uint8_t tramp[] = { 0x06, 0x01, 0x00, /* J (jump to L32R) */ 0, /* (padding to align entry_addr) */ diff --git a/soc/xtensa/intel_adsp/cavs/power.c b/soc/xtensa/intel_adsp/cavs/power.c index f21a09910d3..704d7aa9d3f 100644 --- a/soc/xtensa/intel_adsp/cavs/power.c +++ b/soc/xtensa/intel_adsp/cavs/power.c @@ -20,7 +20,6 @@ #include #include #include -#include "soc.h" #ifdef CONFIG_DYNAMIC_INTERRUPTS #include @@ -150,7 +149,7 @@ void pm_state_set(enum pm_state state, uint8_t substate_id) .imr_restore_vector = rom_entry, }; struct imr_layout *imr_layout = - z_soc_uncached_ptr((__sparse_force void __sparse_cache *) + sys_cache_uncached_ptr_get((__sparse_force void __sparse_cache *) L3_MEM_BASE_ADDR); imr_layout->imr_state.header = hdr; diff --git a/soc/xtensa/intel_adsp/common/boot_complete.c b/soc/xtensa/intel_adsp/common/boot_complete.c index 445fd57b064..3d27ae18d13 100644 --- a/soc/xtensa/intel_adsp/common/boot_complete.c +++ b/soc/xtensa/intel_adsp/common/boot_complete.c @@ -7,7 +7,7 @@ #include #include #include -#include +#include #include @@ -22,7 +22,7 @@ int boot_complete(void) } config = dev->config; - win = z_soc_uncached_ptr((__sparse_force void __sparse_cache *)config->mem_base); + win = sys_cache_uncached_ptr_get((__sparse_force void __sparse_cache *)config->mem_base); /* Software protocol: "firmware entered" has the value 5 */ win[0] = 5; diff --git a/soc/xtensa/intel_adsp/common/include/adsp_debug_window.h b/soc/xtensa/intel_adsp/common/include/adsp_debug_window.h index ddd94e77ce3..868d549c5e5 100644 --- a/soc/xtensa/intel_adsp/common/include/adsp_debug_window.h +++ b/soc/xtensa/intel_adsp/common/include/adsp_debug_window.h @@ -6,6 +6,7 @@ #include #include +#include /* * SRAM window for debug info (window 2) is organized in slots, @@ -67,7 +68,7 @@ struct adsp_debug_window { #define WIN2_MBASE DT_REG_ADDR(DT_PHANDLE(DT_NODELABEL(mem_window2), memory)) #define ADSP_DW ((volatile struct adsp_debug_window *) \ - (z_soc_uncached_ptr((__sparse_force void __sparse_cache *) \ + (sys_cache_uncached_ptr_get((__sparse_force void __sparse_cache *) \ (WIN2_MBASE + WIN2_OFFSET)))) #endif diff --git a/soc/xtensa/intel_adsp/common/include/intel_adsp_hda.h b/soc/xtensa/intel_adsp/common/include/intel_adsp_hda.h index 0b3f86890a1..f56c77e2523 100644 --- a/soc/xtensa/intel_adsp/common/include/intel_adsp_hda.h +++ b/soc/xtensa/intel_adsp/common/include/intel_adsp_hda.h @@ -159,7 +159,7 @@ static inline int intel_adsp_hda_set_buffer(uint32_t base, * region or not, we do need a consistent address space to check * against for our assertion. This is cheap. */ - uint32_t addr = (uint32_t)arch_xtensa_cached_ptr(buf); + uint32_t addr = (uint32_t)sys_cache_cached_ptr_get(buf); uint32_t aligned_addr = addr & HDA_ALIGN_MASK; uint32_t aligned_size = buf_size & HDA_BUFFER_SIZE_MASK; diff --git a/soc/xtensa/intel_adsp/common/include/soc.h b/soc/xtensa/intel_adsp/common/include/soc.h index 014ba18e434..1db8320428f 100644 --- a/soc/xtensa/intel_adsp/common/include/soc.h +++ b/soc/xtensa/intel_adsp/common/include/soc.h @@ -26,10 +26,6 @@ extern void soc_start_core(int cpu_num); extern bool soc_cpus_active[CONFIG_MP_MAX_NUM_CPUS]; -/* Legacy cache APIs still used in a few places */ -#define z_soc_cached_ptr(p) arch_xtensa_cached_ptr(p) -#define z_soc_uncached_ptr(p) arch_xtensa_uncached_ptr(p) - /** * @brief Halts and offlines a running CPU * diff --git a/tests/boards/intel_adsp/cache/src/main.c b/tests/boards/intel_adsp/cache/src/main.c index cd37ca6ad8c..b0476bd0665 100644 --- a/tests/boards/intel_adsp/cache/src/main.c +++ b/tests/boards/intel_adsp/cache/src/main.c @@ -13,7 +13,7 @@ ZTEST(adsp_cache, test_adsp_cache_flush_inv_all) uint32_t *cached, *uncached; cached = (uint32_t *)LP_SRAM_BASE; - uncached = arch_xtensa_uncached_ptr(cached); + uncached = sys_cache_uncached_ptr_get(cached); *cached = 42; *uncached = 40; diff --git a/tests/boards/intel_adsp/smoke/src/cpus.c b/tests/boards/intel_adsp/smoke/src/cpus.c index 2c3f30af513..07e3b40777e 100644 --- a/tests/boards/intel_adsp/smoke/src/cpus.c +++ b/tests/boards/intel_adsp/smoke/src/cpus.c @@ -84,19 +84,19 @@ static void core_smoke(void *arg) zassert_equal(cpu, arch_curr_cpu()->id, "wrong cpu"); /* Un/cached regions should be configured and distinct */ - zassert_equal(&tag, arch_xtensa_cached_ptr((void *)&tag), + zassert_equal(&tag, sys_cache_cached_ptr_get((void *)&tag), "stack memory not cached"); - zassert_not_equal(&tag, arch_xtensa_uncached_ptr((void *)&tag), + zassert_not_equal(&tag, sys_cache_uncached_ptr_get((void *)&tag), "stack memory not cached"); - zassert_not_equal(&static_tag, arch_xtensa_cached_ptr((void *)&static_tag), + zassert_not_equal(&static_tag, sys_cache_cached_ptr_get((void *)&static_tag), "stack memory not cached"); - zassert_equal(&static_tag, arch_xtensa_uncached_ptr((void *)&static_tag), + zassert_equal(&static_tag, sys_cache_uncached_ptr_get((void *)&static_tag), "stack memory not cached"); /* Un/cached regions should be working */ printk(" Cache behavior check\n"); - volatile int *ctag = (volatile int *)arch_xtensa_cached_ptr((void *)&tag); - volatile int *utag = (volatile int *)arch_xtensa_uncached_ptr((void *)&tag); + volatile int *ctag = (volatile int *)sys_cache_cached_ptr_get((void *)&tag); + volatile int *utag = (volatile int *)sys_cache_uncached_ptr_get((void *)&tag); tag = 99; zassert_true(*ctag == 99, "variable is cached"); From f6adaf55aadb3207343205b6a478088b1271243f Mon Sep 17 00:00:00 2001 From: Anas Nashif Date: Fri, 26 Jan 2024 13:20:21 +0000 Subject: [PATCH 3474/3723] manifest: update sof sha in manifest point to d40682678b7378fb930ca5535ccd2ce667ed5c27. Signed-off-by: Anas Nashif --- submanifests/optional.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/submanifests/optional.yaml b/submanifests/optional.yaml index a15d0fd6be5..127930a65c7 100644 --- a/submanifests/optional.yaml +++ b/submanifests/optional.yaml @@ -34,7 +34,7 @@ manifest: groups: - optional - name: sof - revision: 7a0ff76e05cab6b1d99767258680a7b8711dd476 + revision: 0606152d4aafc1f7ed43df1b1813252bfc74e154 path: modules/audio/sof remote: upstream groups: From 840db7858e90cb49c1ba253ce037a44c01549b18 Mon Sep 17 00:00:00 2001 From: Andy Ross Date: Thu, 1 Feb 2024 08:29:13 -0800 Subject: [PATCH 3475/3723] kernel/thread: Detect in-kernel "reserved" stack overflow Traditionally, k_thread_create() has required that the application size the stack correctly. Zephyr doesn't detect or return errors and treats stack overflow as an application bug (though obviously some architectures have runtime features to trap on overflows). At this one spot though, it's possible for the kernel to adjust the stack for K_THREAD_STACK_RESERVED in such a way that the arch layer's own stack initialization overflows. That failure can be seen by static analysis, so we can't just sweep it under the rug as an application failure. Unfortunately there aren't any good options for handling it here (no way to return failure, can't be a build assert as the size is a runtime argument). A panic will have to do. Fixes: #67106 Fixes: #65584 Signed-off-by: Andy Ross --- kernel/thread.c | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/kernel/thread.c b/kernel/thread.c index fc31f4b36d8..51803c87f42 100644 --- a/kernel/thread.c +++ b/kernel/thread.c @@ -530,6 +530,15 @@ static char *setup_thread_stack(struct k_thread *new_thread, stack_obj_size = Z_KERNEL_STACK_SIZE_ADJUST(stack_size); stack_buf_start = Z_KERNEL_STACK_BUFFER(stack); stack_buf_size = stack_obj_size - K_KERNEL_STACK_RESERVED; + + /* Zephyr treats stack overflow as an app bug. But + * this particular overflow can be seen by static + * analysis so needs to be handled somehow. + */ + if (K_KERNEL_STACK_RESERVED > stack_obj_size) { + k_panic(); + } + } /* Initial stack pointer at the high end of the stack object, may From f35e9871d508cbe425dce0cbbe61c8f89d157921 Mon Sep 17 00:00:00 2001 From: Emil Gydesen Date: Wed, 17 Jan 2024 15:25:22 +0100 Subject: [PATCH 3476/3723] Bluetooth: CAP: Remove unicast group param from unicast_audio_start Since we can always lookup the group from the streams, the group parameter had no purpose. Signed-off-by: Emil Gydesen --- include/zephyr/bluetooth/audio/cap.h | 24 +++--------- .../tmap_central/src/cap_initiator.c | 12 +++--- subsys/bluetooth/audio/cap_initiator.c | 38 ++++++++----------- subsys/bluetooth/audio/cap_internal.h | 1 - subsys/bluetooth/audio/shell/cap_initiator.c | 37 +++++++----------- tests/bluetooth/tester/src/btp_cap.c | 19 +++++----- .../audio/src/cap_initiator_unicast_test.c | 32 ++++++---------- .../bsim/bluetooth/audio/src/gmap_ugg_test.c | 8 ++-- 8 files changed, 65 insertions(+), 106 deletions(-) diff --git a/include/zephyr/bluetooth/audio/cap.h b/include/zephyr/bluetooth/audio/cap.h index 8a0ab5d5666..95cd6dc2079 100644 --- a/include/zephyr/bluetooth/audio/cap.h +++ b/include/zephyr/bluetooth/audio/cap.h @@ -76,8 +76,6 @@ struct bt_cap_initiator_cb { /** * @brief Callback for bt_cap_initiator_unicast_audio_start(). * - * @param unicast_group The unicast group pointer supplied to - * bt_cap_initiator_unicast_audio_start(). * @param err 0 if success, BT_GATT_ERR() with a * specific ATT (BT_ATT_ERR_*) error code or -ECANCELED if cancelled * by bt_cap_initiator_unicast_audio_cancel(). @@ -85,8 +83,7 @@ struct bt_cap_initiator_cb { * occurred. NULL if @p err is 0 or if cancelled by * bt_cap_initiator_unicast_audio_cancel() */ - void (*unicast_start_complete)(struct bt_bap_unicast_group *unicast_group, - int err, struct bt_conn *conn); + void (*unicast_start_complete)(int err, struct bt_conn *conn); /** * @brief Callback for bt_cap_initiator_unicast_audio_update(). @@ -103,14 +100,6 @@ struct bt_cap_initiator_cb { /** * @brief Callback for bt_cap_initiator_unicast_audio_stop(). * - * If @p err is 0, then @p unicast_group has been deleted and can no - * longer be used. - * - * If @p err is not 0 and @p conn is NULL, then the deletion of the - * @p unicast_group failed with @p err as the error. - * - * @param unicast_group The unicast group pointer supplied to - * bt_cap_initiator_unicast_audio_stop(). * @param err 0 if success, BT_GATT_ERR() with a * specific ATT (BT_ATT_ERR_*) error code or -ECANCELED if cancelled * by bt_cap_initiator_unicast_audio_cancel(). @@ -118,8 +107,7 @@ struct bt_cap_initiator_cb { * occurred. NULL if @p err is 0 or if cancelled by * bt_cap_initiator_unicast_audio_cancel() */ - void (*unicast_stop_complete)(struct bt_bap_unicast_group *unicast_group, - int err, struct bt_conn *conn); + void (*unicast_stop_complete)(int err, struct bt_conn *conn); #endif /* CONFIG_BT_BAP_UNICAST_CLIENT */ }; @@ -206,6 +194,7 @@ int bt_cap_stream_send(struct bt_cap_stream *stream, struct net_buf *buf, uint16 */ int bt_cap_stream_get_tx_sync(struct bt_cap_stream *stream, struct bt_iso_tx_info *info); +/** Stream specific parameters for the bt_cap_initiator_unicast_audio_start() function */ struct bt_cap_unicast_audio_start_stream_param { /** Coordinated or ad-hoc set member. */ union bt_cap_set_member member; @@ -226,6 +215,7 @@ struct bt_cap_unicast_audio_start_stream_param { struct bt_audio_codec_cfg *codec_cfg; }; +/** Parameters for the bt_cap_initiator_unicast_audio_start() function */ struct bt_cap_unicast_audio_start_param { /** The type of the set. */ enum bt_cap_set_type type; @@ -272,13 +262,11 @@ int bt_cap_initiator_register_cb(const struct bt_cap_initiator_cb *cb); * @kconfig{CONFIG_BT_BAP_UNICAST_CLIENT} must be enabled for this function * to be enabled. * - * @param[in] param Parameters to start the audio streams. - * @param[out] unicast_group Pointer to the unicast group. + * @param param Parameters to start the audio streams. * * @return 0 on success or negative error value on failure. */ -int bt_cap_initiator_unicast_audio_start(const struct bt_cap_unicast_audio_start_param *param, - struct bt_bap_unicast_group *unicast_group); +int bt_cap_initiator_unicast_audio_start(const struct bt_cap_unicast_audio_start_param *param); /** * @brief Update unicast audio streams. diff --git a/samples/bluetooth/tmap_central/src/cap_initiator.c b/samples/bluetooth/tmap_central/src/cap_initiator.c index 1b45741e14b..fe75d0e0ace 100644 --- a/samples/bluetooth/tmap_central/src/cap_initiator.c +++ b/samples/bluetooth/tmap_central/src/cap_initiator.c @@ -119,8 +119,7 @@ static void cap_discovery_complete_cb(struct bt_conn *conn, int err, k_sem_give(&sem_cas_discovery); } -static void unicast_start_complete_cb(struct bt_bap_unicast_group *unicast_group, - int err, struct bt_conn *conn) +static void unicast_start_complete_cb(int err, struct bt_conn *conn) { if (err != 0) { printk("Failed to start (failing conn %p): %d", conn, err); @@ -138,8 +137,7 @@ static void unicast_update_complete_cb(int err, struct bt_conn *conn) } } -static void unicast_stop_complete_cb(struct bt_bap_unicast_group *unicast_group, int err, - struct bt_conn *conn) +static void unicast_stop_complete_cb(int err, struct bt_conn *conn) { if (err != 0) { printk("Failed to stop (failing conn %p): %d", conn, err); @@ -330,7 +328,7 @@ static int unicast_group_create(struct bt_bap_unicast_group **out_unicast_group) return err; } -static int unicast_audio_start(struct bt_conn *conn, struct bt_bap_unicast_group *unicast_group) +static int unicast_audio_start(struct bt_conn *conn) { int err = 0; struct bt_cap_unicast_audio_start_stream_param stream_param; @@ -345,7 +343,7 @@ static int unicast_audio_start(struct bt_conn *conn, struct bt_bap_unicast_group stream_param.ep = unicast_sink_eps[0]; stream_param.codec_cfg = &unicast_preset_48_2_1.codec_cfg; - err = bt_cap_initiator_unicast_audio_start(¶m, unicast_group); + err = bt_cap_initiator_unicast_audio_start(¶m); if (err != 0) { printk("Failed to start unicast audio: %d\n", err); return err; @@ -457,7 +455,7 @@ int cap_initiator_setup(struct bt_conn *conn) return err; } - err = unicast_audio_start(conn, unicast_group); + err = unicast_audio_start(conn); if (err != 0) { return err; } diff --git a/subsys/bluetooth/audio/cap_initiator.c b/subsys/bluetooth/audio/cap_initiator.c index 1a51638af3f..0d86d311fe5 100644 --- a/subsys/bluetooth/audio/cap_initiator.c +++ b/subsys/bluetooth/audio/cap_initiator.c @@ -332,9 +332,10 @@ int bt_cap_initiator_unicast_discover(struct bt_conn *conn) return bt_cap_common_discover(conn, bt_cap_initiator_discover_complete); } -static bool valid_unicast_audio_start_param(const struct bt_cap_unicast_audio_start_param *param, - struct bt_bap_unicast_group *unicast_group) +static bool valid_unicast_audio_start_param(const struct bt_cap_unicast_audio_start_param *param) { + struct bt_bap_unicast_group *unicast_group = NULL; + CHECKIF(param == NULL) { LOG_DBG("param is NULL"); return false; @@ -410,9 +411,15 @@ static bool valid_unicast_audio_start_param(const struct bt_cap_unicast_audio_st return false; } - CHECKIF(bap_stream->group != unicast_group) { - LOG_DBG("param->streams[%zu] is not in this group %p", i, unicast_group); - return false; + /* Use the group of the first stream for comparison */ + if (unicast_group == NULL) { + unicast_group = bap_stream->group; + } else { + CHECKIF(bap_stream->group != unicast_group) { + LOG_DBG("param->streams[%zu] is not in this group %p", i, + unicast_group); + return false; + } } for (size_t j = 0U; j < i; j++) { @@ -433,12 +440,10 @@ static bool valid_unicast_audio_start_param(const struct bt_cap_unicast_audio_st static void cap_initiator_unicast_audio_proc_complete(void) { struct bt_cap_common_proc *active_proc = bt_cap_common_get_active_proc(); - struct bt_bap_unicast_group *unicast_group; enum bt_cap_common_proc_type proc_type; struct bt_conn *failed_conn; int err; - unicast_group = active_proc->unicast_group; failed_conn = active_proc->failed_conn; err = active_proc->err; proc_type = active_proc->proc_type; @@ -451,7 +456,7 @@ static void cap_initiator_unicast_audio_proc_complete(void) switch (proc_type) { case BT_CAP_COMMON_PROC_TYPE_START: if (cap_cb->unicast_start_complete != NULL) { - cap_cb->unicast_start_complete(unicast_group, err, failed_conn); + cap_cb->unicast_start_complete(err, failed_conn); } break; case BT_CAP_COMMON_PROC_TYPE_UPDATE: @@ -461,7 +466,7 @@ static void cap_initiator_unicast_audio_proc_complete(void) break; case BT_CAP_COMMON_PROC_TYPE_STOP: if (cap_cb->unicast_stop_complete != NULL) { - cap_cb->unicast_stop_complete(unicast_group, err, failed_conn); + cap_cb->unicast_stop_complete(err, failed_conn); } break; case BT_CAP_COMMON_PROC_TYPE_NONE: @@ -533,28 +538,18 @@ static int cap_initiator_unicast_audio_configure( return err; } -int bt_cap_initiator_unicast_audio_start(const struct bt_cap_unicast_audio_start_param *param, - struct bt_bap_unicast_group *unicast_group) +int bt_cap_initiator_unicast_audio_start(const struct bt_cap_unicast_audio_start_param *param) { - struct bt_cap_common_proc *active_proc = bt_cap_common_get_active_proc(); - if (bt_cap_common_proc_is_active()) { LOG_DBG("A CAP procedure is already in progress"); return -EBUSY; } - CHECKIF(unicast_group == NULL) { - LOG_DBG("unicast_group is NULL"); + if (!valid_unicast_audio_start_param(param)) { return -EINVAL; } - if (!valid_unicast_audio_start_param(param, unicast_group)) { - return -EINVAL; - } - - active_proc->unicast_group = unicast_group; - return cap_initiator_unicast_audio_configure(param); } @@ -1119,7 +1114,6 @@ int bt_cap_initiator_unicast_audio_stop(struct bt_bap_unicast_group *unicast_gro } bt_cap_common_start_proc(BT_CAP_COMMON_PROC_TYPE_STOP, stream_cnt); - active_proc->unicast_group = unicast_group; bt_cap_common_set_subproc(BT_CAP_COMMON_SUBPROC_TYPE_RELEASE); diff --git a/subsys/bluetooth/audio/cap_internal.h b/subsys/bluetooth/audio/cap_internal.h index 942f0985ac8..145cb2fd24e 100644 --- a/subsys/bluetooth/audio/cap_internal.h +++ b/subsys/bluetooth/audio/cap_internal.h @@ -111,7 +111,6 @@ struct bt_cap_common_proc { struct bt_conn *failed_conn; struct bt_cap_common_proc_param proc_param; #if defined(CONFIG_BT_CAP_INITIATOR_UNICAST) - struct bt_bap_unicast_group *unicast_group; enum bt_cap_common_subproc_type subproc_type; #endif /* CONFIG_BT_CAP_INITIATOR_UNICAST */ }; diff --git a/subsys/bluetooth/audio/shell/cap_initiator.c b/subsys/bluetooth/audio/shell/cap_initiator.c index 64cff4672c5..17b4e96ec8e 100644 --- a/subsys/bluetooth/audio/shell/cap_initiator.c +++ b/subsys/bluetooth/audio/shell/cap_initiator.c @@ -36,8 +36,7 @@ static void cap_discover_cb(struct bt_conn *conn, int err, csis_inst == NULL ? "" : " with CSIS"); } -static void cap_unicast_start_complete_cb(struct bt_bap_unicast_group *unicast_group, - int err, struct bt_conn *conn) +static void cap_unicast_start_complete_cb(int err, struct bt_conn *conn) { if (err == -ECANCELED) { shell_print(ctx_shell, "Unicast start was cancelled for conn %p", conn); @@ -60,31 +59,23 @@ static void unicast_update_complete_cb(int err, struct bt_conn *conn) } } -static void unicast_stop_complete_cb(struct bt_bap_unicast_group *unicast_group, int err, - struct bt_conn *conn) +static void unicast_stop_complete_cb(int err, struct bt_conn *conn) { - if (default_unicast_group != unicast_group) { - /* ignore */ - return; - } - if (err == -ECANCELED) { shell_print(ctx_shell, "Unicast stop was cancelled for conn %p", conn); } else if (err != 0) { - shell_error(ctx_shell, - "Unicast stop failed for group %p and conn %p (%d)", - unicast_group, conn, err); + shell_error(ctx_shell, "Unicast stop failed for conn %p (%d)", conn, err); } else { - shell_print(ctx_shell, - "Unicast stopped for group %p completed", - default_unicast_group); + shell_print(ctx_shell, "Unicast stopped completed"); - err = bt_bap_unicast_group_delete(unicast_group); - if (err != 0) { - shell_error(ctx_shell, "Failed to delete unicast group %p: %d", - unicast_group, err); - } else { - default_unicast_group = NULL; + if (default_unicast_group != NULL) { + err = bt_bap_unicast_group_delete(default_unicast_group); + if (err != 0) { + shell_error(ctx_shell, "Failed to delete unicast group %p: %d", + default_unicast_group, err); + } else { + default_unicast_group = NULL; + } } } } @@ -320,7 +311,7 @@ static int cmd_cap_initiator_unicast_start(const struct shell *sh, size_t argc, shell_print(sh, "Starting %zu streams", start_param.count); - err = bt_cap_initiator_unicast_audio_start(&start_param, default_unicast_group); + err = bt_cap_initiator_unicast_audio_start(&start_param); if (err != 0) { shell_print(sh, "Failed to start unicast audio: %d", err); @@ -625,7 +616,7 @@ static int cap_ac_unicast_start(const struct bap_unicast_ac_param *param, start_param.count = stream_cnt; start_param.type = BT_CAP_SET_TYPE_AD_HOC; - return bt_cap_initiator_unicast_audio_start(&start_param, default_unicast_group); + return bt_cap_initiator_unicast_audio_start(&start_param); } int cap_ac_unicast(const struct shell *sh, size_t argc, char **argv, diff --git a/tests/bluetooth/tester/src/btp_cap.c b/tests/bluetooth/tester/src/btp_cap.c index 0220b838143..c28fe6e5e7d 100644 --- a/tests/bluetooth/tester/src/btp_cap.c +++ b/tests/bluetooth/tester/src/btp_cap.c @@ -20,6 +20,8 @@ LOG_MODULE_REGISTER(LOG_MODULE_NAME, CONFIG_BTTESTER_LOG_LEVEL); #include "btp_bap_unicast.h" #include "btp_bap_broadcast.h" +static struct btp_bap_unicast_group *u_group; + extern struct bt_csip_set_coordinator_set_member *btp_csip_set_members[CONFIG_BT_MAX_CONN]; static struct bt_bap_stream *stream_unicast_to_bap(struct btp_bap_unicast_stream *stream) @@ -95,20 +97,19 @@ static void btp_send_cap_unicast_stop_completed_ev(uint8_t cig_id, uint8_t statu tester_event(BTP_SERVICE_ID_CAP, BTP_CAP_EV_UNICAST_STOP_COMPLETED, &ev, sizeof(ev)); } -static void unicast_start_complete_cb(struct bt_bap_unicast_group *group, - int err, struct bt_conn *conn) +static void unicast_start_complete_cb(int err, struct bt_conn *conn) { LOG_DBG(""); if (err != 0) { LOG_DBG("Failed to unicast-start, err %d", err); - btp_send_cap_unicast_start_completed_ev(group->index, + btp_send_cap_unicast_start_completed_ev(u_group->cig->index, BTP_CAP_UNICAST_START_STATUS_FAILED); return; } - btp_send_cap_unicast_start_completed_ev(group->index, + btp_send_cap_unicast_start_completed_ev(u_group->cig->index, BTP_CAP_UNICAST_START_STATUS_SUCCESS); } @@ -121,20 +122,19 @@ static void unicast_update_complete_cb(int err, struct bt_conn *conn) } } -static void unicast_stop_complete_cb(struct bt_bap_unicast_group *group, int err, - struct bt_conn *conn) +static void unicast_stop_complete_cb(int err, struct bt_conn *conn) { LOG_DBG(""); if (err != 0) { LOG_DBG("Failed to unicast-stop, err %d", err); - btp_send_cap_unicast_stop_completed_ev(group->index, + btp_send_cap_unicast_stop_completed_ev(u_group->cig->index, BTP_CAP_UNICAST_START_STATUS_FAILED); return; } - btp_send_cap_unicast_stop_completed_ev(group->index, + btp_send_cap_unicast_stop_completed_ev(u_group->cig->index, BTP_CAP_UNICAST_START_STATUS_SUCCESS); } @@ -282,7 +282,6 @@ static uint8_t btp_cap_unicast_audio_start(const void *cmd, uint16_t cmd_len, { int err; size_t stream_count = 0; - struct btp_bap_unicast_group *u_group; const struct btp_cap_unicast_audio_start_cmd *cp = cmd; struct bt_cap_unicast_audio_start_param start_param; struct bt_cap_unicast_audio_start_stream_param stream_params[ @@ -326,7 +325,7 @@ static uint8_t btp_cap_unicast_audio_start(const void *cmd, uint16_t cmd_len, start_param.count = stream_count; start_param.stream_params = stream_params; - err = bt_cap_initiator_unicast_audio_start(&start_param, u_group->cig); + err = bt_cap_initiator_unicast_audio_start(&start_param); if (err != 0) { LOG_ERR("Failed to start unicast audio: %d", err); diff --git a/tests/bsim/bluetooth/audio/src/cap_initiator_unicast_test.c b/tests/bsim/bluetooth/audio/src/cap_initiator_unicast_test.c index adfbf2416a1..1c2f7b40007 100644 --- a/tests/bsim/bluetooth/audio/src/cap_initiator_unicast_test.c +++ b/tests/bsim/bluetooth/audio/src/cap_initiator_unicast_test.c @@ -183,8 +183,7 @@ static void cap_discovery_complete_cb(struct bt_conn *conn, int err, SET_FLAG(flag_discovered); } -static void unicast_start_complete_cb(struct bt_bap_unicast_group *unicast_group, int err, - struct bt_conn *conn) +static void unicast_start_complete_cb(int err, struct bt_conn *conn) { if (err == -ECANCELED) { SET_FLAG(flag_start_timeout); @@ -206,8 +205,7 @@ static void unicast_update_complete_cb(int err, struct bt_conn *conn) SET_FLAG(flag_updated); } -static void unicast_stop_complete_cb(struct bt_bap_unicast_group *unicast_group, int err, - struct bt_conn *conn) +static void unicast_stop_complete_cb(int err, struct bt_conn *conn) { if (err != 0) { FAIL("Failed to stop (failing conn %p): %d", conn, err); @@ -545,18 +543,12 @@ static void unicast_audio_start_inval(struct bt_bap_unicast_group *unicast_group valid_stream_param.codec_cfg = &unicast_preset_16_2_1.codec_cfg; /* Test NULL parameters */ - err = bt_cap_initiator_unicast_audio_start(NULL, unicast_group); + err = bt_cap_initiator_unicast_audio_start(NULL); if (err == 0) { FAIL("bt_cap_initiator_unicast_audio_start with NULL param did not fail\n"); return; } - err = bt_cap_initiator_unicast_audio_start(&valid_start_param, NULL); - if (err == 0) { - FAIL("bt_cap_initiator_unicast_audio_start with NULL group did not fail\n"); - return; - } - /* Test invalid parameters */ memcpy(&invalid_stream_param, &valid_stream_param, sizeof(valid_stream_param)); memcpy(&invalid_start_param, &valid_start_param, sizeof(valid_start_param)); @@ -564,7 +556,7 @@ static void unicast_audio_start_inval(struct bt_bap_unicast_group *unicast_group /* Test invalid stream_start parameters */ invalid_start_param.count = 0U; - err = bt_cap_initiator_unicast_audio_start(&invalid_start_param, unicast_group); + err = bt_cap_initiator_unicast_audio_start(&invalid_start_param); if (err == 0) { FAIL("bt_cap_initiator_unicast_audio_start with 0 count did not fail\n"); return; @@ -574,7 +566,7 @@ static void unicast_audio_start_inval(struct bt_bap_unicast_group *unicast_group invalid_start_param.stream_params = &invalid_stream_param; invalid_start_param.stream_params = NULL; - err = bt_cap_initiator_unicast_audio_start(&invalid_start_param, unicast_group); + err = bt_cap_initiator_unicast_audio_start(&invalid_start_param); if (err == 0) { FAIL("bt_cap_initiator_unicast_audio_start with NULL stream params did not fail\n"); return; @@ -585,7 +577,7 @@ static void unicast_audio_start_inval(struct bt_bap_unicast_group *unicast_group /* Test invalid stream_param parameters */ invalid_stream_param.member.member = NULL; - err = bt_cap_initiator_unicast_audio_start(&invalid_start_param, unicast_group); + err = bt_cap_initiator_unicast_audio_start(&invalid_start_param); if (err == 0) { FAIL("bt_cap_initiator_unicast_audio_start with NULL stream params member did not " "fail\n"); @@ -595,7 +587,7 @@ static void unicast_audio_start_inval(struct bt_bap_unicast_group *unicast_group memcpy(&invalid_stream_param, &valid_stream_param, sizeof(valid_stream_param)); invalid_stream_param.stream = NULL; - err = bt_cap_initiator_unicast_audio_start(&invalid_start_param, unicast_group); + err = bt_cap_initiator_unicast_audio_start(&invalid_start_param); if (err == 0) { FAIL("bt_cap_initiator_unicast_audio_start with NULL stream params stream did not " "fail\n"); @@ -605,7 +597,7 @@ static void unicast_audio_start_inval(struct bt_bap_unicast_group *unicast_group memcpy(&invalid_stream_param, &valid_stream_param, sizeof(valid_stream_param)); invalid_stream_param.ep = NULL; - err = bt_cap_initiator_unicast_audio_start(&invalid_start_param, unicast_group); + err = bt_cap_initiator_unicast_audio_start(&invalid_start_param); if (err == 0) { FAIL("bt_cap_initiator_unicast_audio_start with NULL stream params ep did not " "fail\n"); @@ -615,7 +607,7 @@ static void unicast_audio_start_inval(struct bt_bap_unicast_group *unicast_group memcpy(&invalid_stream_param, &valid_stream_param, sizeof(valid_stream_param)); invalid_stream_param.codec_cfg = NULL; - err = bt_cap_initiator_unicast_audio_start(&invalid_start_param, unicast_group); + err = bt_cap_initiator_unicast_audio_start(&invalid_start_param); if (err == 0) { FAIL("bt_cap_initiator_unicast_audio_start with NULL stream params codec did not " "fail\n"); @@ -627,7 +619,7 @@ static void unicast_audio_start_inval(struct bt_bap_unicast_group *unicast_group memset(&invalid_codec.meta, 0, sizeof(invalid_codec.meta)); invalid_stream_param.codec_cfg = &invalid_codec; - err = bt_cap_initiator_unicast_audio_start(&invalid_start_param, unicast_group); + err = bt_cap_initiator_unicast_audio_start(&invalid_start_param); if (err == 0) { FAIL("bt_cap_initiator_unicast_audio_start with invalid Codec metadata did not " "fail\n"); @@ -656,7 +648,7 @@ static void unicast_audio_start(struct bt_bap_unicast_group *unicast_group, bool UNSET_FLAG(flag_started); - err = bt_cap_initiator_unicast_audio_start(¶m, unicast_group); + err = bt_cap_initiator_unicast_audio_start(¶m); if (err != 0) { FAIL("Failed to start unicast audio: %d\n", err); return; @@ -1129,7 +1121,7 @@ static int cap_initiator_ac_cap_unicast_start(const struct cap_initiator_ac_para start_param.count = stream_cnt; start_param.type = BT_CAP_SET_TYPE_AD_HOC; - return bt_cap_initiator_unicast_audio_start(&start_param, unicast_group); + return bt_cap_initiator_unicast_audio_start(&start_param); } static int cap_initiator_ac_unicast(const struct cap_initiator_ac_param *param, diff --git a/tests/bsim/bluetooth/audio/src/gmap_ugg_test.c b/tests/bsim/bluetooth/audio/src/gmap_ugg_test.c index 1e5713f08ad..303be04b6c1 100644 --- a/tests/bsim/bluetooth/audio/src/gmap_ugg_test.c +++ b/tests/bsim/bluetooth/audio/src/gmap_ugg_test.c @@ -285,8 +285,7 @@ static void cap_discovery_complete_cb(struct bt_conn *conn, int err, SET_FLAG(flag_cas_discovered); } -static void unicast_start_complete_cb(struct bt_bap_unicast_group *unicast_group, int err, - struct bt_conn *conn) +static void unicast_start_complete_cb(int err, struct bt_conn *conn) { if (err != 0) { FAIL("Failed to start (failing conn %p): %d\n", conn, err); @@ -308,8 +307,7 @@ static void unicast_update_complete_cb(int err, struct bt_conn *conn) SET_FLAG(flag_updated); } -static void unicast_stop_complete_cb(struct bt_bap_unicast_group *unicast_group, int err, - struct bt_conn *conn) +static void unicast_stop_complete_cb(int err, struct bt_conn *conn) { if (err != 0) { FAIL("Failed to stop (failing conn %p): %d\n", conn, err); @@ -799,7 +797,7 @@ static int gmap_ac_cap_unicast_start(const struct gmap_unicast_ac_param *param, start_param.count = stream_cnt; start_param.type = BT_CAP_SET_TYPE_AD_HOC; - return bt_cap_initiator_unicast_audio_start(&start_param, unicast_group); + return bt_cap_initiator_unicast_audio_start(&start_param); } static int gmap_ac_unicast(const struct gmap_unicast_ac_param *param, From ec549cebd51b977319d89173a6621273547f6c7f Mon Sep 17 00:00:00 2001 From: Emil Gydesen Date: Wed, 17 Jan 2024 15:59:13 +0100 Subject: [PATCH 3477/3723] Bluetooth: CAP: Make unicast update more similar to unicast start Modify the parameters for bt_cap_initiator_unicast_audio_update so that they are more similar to bt_cap_initiator_unicast_audio_start. Signed-off-by: Emil Gydesen --- include/zephyr/bluetooth/audio/cap.h | 23 ++- subsys/bluetooth/audio/cap_initiator.c | 139 ++++++++++++------ subsys/bluetooth/audio/shell/cap_initiator.c | 33 +++-- tests/bluetooth/tester/src/btp_cap.c | 21 ++- .../audio/src/cap_initiator_unicast_test.c | 43 ++++-- 5 files changed, 172 insertions(+), 87 deletions(-) diff --git a/include/zephyr/bluetooth/audio/cap.h b/include/zephyr/bluetooth/audio/cap.h index 95cd6dc2079..447e0c2f9b2 100644 --- a/include/zephyr/bluetooth/audio/cap.h +++ b/include/zephyr/bluetooth/audio/cap.h @@ -227,8 +227,9 @@ struct bt_cap_unicast_audio_start_param { struct bt_cap_unicast_audio_start_stream_param *stream_params; }; -struct bt_cap_unicast_audio_update_param { - /** @brief Stream for the @p member */ +/** Stream specific parameters for the bt_cap_initiator_unicast_audio_update() function */ +struct bt_cap_unicast_audio_update_stream_param { + /** Stream to update */ struct bt_cap_stream *stream; /** The length of @p meta. */ @@ -242,6 +243,18 @@ struct bt_cap_unicast_audio_update_param { uint8_t *meta; }; +/** Parameters for the bt_cap_initiator_unicast_audio_update() function */ +struct bt_cap_unicast_audio_update_param { + /** The type of the set. */ + enum bt_cap_set_type type; + + /** The number of parameters in @p stream_params */ + size_t count; + + /** Array of stream parameters */ + struct bt_cap_unicast_audio_update_stream_param *stream_params; +}; + /** * @brief Register Common Audio Profile Initiator callbacks * @@ -277,13 +290,11 @@ int bt_cap_initiator_unicast_audio_start(const struct bt_cap_unicast_audio_start * @kconfig{CONFIG_BT_BAP_UNICAST_CLIENT} must be enabled for this function * to be enabled. * - * @param params Array of update parameters. - * @param count The number of entries in @p params. + * @param param Update parameters. * * @return 0 on success or negative error value on failure. */ -int bt_cap_initiator_unicast_audio_update(const struct bt_cap_unicast_audio_update_param params[], - size_t count); +int bt_cap_initiator_unicast_audio_update(const struct bt_cap_unicast_audio_update_param *param); /** * @brief Stop unicast audio streams for a unicast group. diff --git a/subsys/bluetooth/audio/cap_initiator.c b/subsys/bluetooth/audio/cap_initiator.c index 0d86d311fe5..78f278aa421 100644 --- a/subsys/bluetooth/audio/cap_initiator.c +++ b/subsys/bluetooth/audio/cap_initiator.c @@ -891,77 +891,134 @@ static bool can_update_metadata(const struct bt_bap_stream *bap_stream) ep_info.state == BT_BAP_EP_STATE_STREAMING; } -int bt_cap_initiator_unicast_audio_update(const struct bt_cap_unicast_audio_update_param params[], - size_t count) +static bool valid_unicast_audio_update_param(const struct bt_cap_unicast_audio_update_param *param) { - struct bt_cap_common_proc *active_proc = bt_cap_common_get_active_proc(); - struct bt_cap_initiator_proc_param *proc_param; - struct bt_bap_stream *bap_stream; - const uint8_t *meta; - size_t meta_len; - int err; - - CHECKIF(params == NULL) { - LOG_DBG("params is NULL"); + struct bt_bap_unicast_group *unicast_group = NULL; - return -EINVAL; + CHECKIF(param == NULL) { + LOG_DBG("param is NULL"); + return false; } - CHECKIF(count == 0) { - LOG_DBG("count is 0"); - - return -EINVAL; + CHECKIF(param->count == 0) { + LOG_DBG("Invalid param->count: %u", param->count); + return false; } - if (bt_cap_common_proc_is_active()) { - LOG_DBG("A CAP procedure is already in progress"); + CHECKIF(param->stream_params == NULL) { + LOG_DBG("param->stream_params is NULL"); + return false; + } - return -EBUSY; + CHECKIF(param->count > CONFIG_BT_BAP_UNICAST_CLIENT_GROUP_STREAM_COUNT) { + LOG_DBG("param->count (%zu) is larger than " + "CONFIG_BT_BAP_UNICAST_CLIENT_GROUP_STREAM_COUNT (%d)", + param->count, CONFIG_BT_BAP_UNICAST_CLIENT_GROUP_STREAM_COUNT); + return false; } - for (size_t i = 0U; i < count; i++) { - struct bt_cap_stream *cap_stream = params[i].stream; + for (size_t i = 0U; i < param->count; i++) { + const struct bt_cap_unicast_audio_update_stream_param *stream_param = + ¶m->stream_params[i]; + const struct bt_cap_stream *cap_stream = stream_param->stream; + const struct bt_bap_stream *bap_stream; + struct bt_cap_common_client *client; + struct bt_conn *conn; CHECKIF(cap_stream == NULL) { - LOG_DBG("params[%zu].stream is NULL", i); + LOG_DBG("param->stream_params[%zu] is NULL", i); + return false; + } + + bap_stream = &cap_stream->bap_stream; + conn = bap_stream->conn; + CHECKIF(conn == NULL) { + LOG_DBG("param->stream_params[%zu].stream->bap_stream.conn is NULL", i); return -EINVAL; } - CHECKIF(cap_stream->bap_stream.conn == NULL) { - LOG_DBG("params[%zu].stream->bap_stream.conn is NULL", i); + client = bt_cap_common_get_client_by_acl(conn); + if (!client->cas_found) { + LOG_DBG("CAS was not found for param->stream_params[%zu].stream", i); + return false; + } + + CHECKIF(bap_stream->group == NULL) { + LOG_DBG("param->stream_params[%zu] is not in a unicast group", i); + return false; + } - return -EINVAL; + /* Use the group of the first stream for comparison */ + if (unicast_group == NULL) { + unicast_group = bap_stream->group; + } else { + CHECKIF(bap_stream->group != unicast_group) { + LOG_DBG("param->stream_params[%zu] is not in this group %p", i, + unicast_group); + return false; + } } - CHECKIF(!cap_initiator_valid_metadata(params[i].meta, - params[i].meta_len)) { - LOG_DBG("params[%zu].meta is invalid", i); + if (!can_update_metadata(bap_stream)) { + LOG_DBG("param->stream_params[%zu].stream is not in right state to be " + "updated", + i); - return -EINVAL; + return false; + } + + if (!cap_initiator_valid_metadata(stream_param->meta, stream_param->meta_len)) { + LOG_DBG("param->stream_params[%zu] invalid metadata", i); + + return false; } for (size_t j = 0U; j < i; j++) { - if (params[j].stream == cap_stream) { - LOG_DBG("param.streams[%zu] is duplicated by param.streams[%zu]", - j, i); - return -EINVAL; + if (param->stream_params[j].stream == cap_stream) { + LOG_DBG("param->stream_params[%zu] (%p) is " + "duplicated by " + "param->stream_params[%zu] (%p)", + j, param->stream_params[j].stream, i, cap_stream); + return false; } } + } - if (!can_update_metadata(&cap_stream->bap_stream)) { - LOG_DBG("params[%zu].stream is not in right state to be updated", i); + return true; +} - return -EINVAL; - } +int bt_cap_initiator_unicast_audio_update(const struct bt_cap_unicast_audio_update_param *param) +{ + struct bt_cap_common_proc *active_proc = bt_cap_common_get_active_proc(); + struct bt_cap_initiator_proc_param *proc_param; + struct bt_bap_stream *bap_stream; + const uint8_t *meta; + size_t meta_len; + int err; + + if (bt_cap_common_proc_is_active()) { + LOG_DBG("A CAP procedure is already in progress"); + + return -EBUSY; + } + + if (!valid_unicast_audio_update_param(param)) { + return -EINVAL; + } + + for (size_t i = 0U; i < param->count; i++) { + const struct bt_cap_unicast_audio_update_stream_param *stream_param = + ¶m->stream_params[i]; + struct bt_cap_stream *cap_stream = stream_param->stream; active_proc->proc_param.initiator[i].stream = cap_stream; - active_proc->proc_param.initiator[i].meta_update.meta_len = params[i].meta_len; - memcpy(&active_proc->proc_param.initiator[i].meta_update.meta, params[i].meta, - params[i].meta_len); + active_proc->proc_param.initiator[i].meta_update.meta_len = stream_param->meta_len; + memcpy(&active_proc->proc_param.initiator[i].meta_update.meta, stream_param->meta, + stream_param->meta_len); } - bt_cap_common_start_proc(BT_CAP_COMMON_PROC_TYPE_UPDATE, count); + bt_cap_common_start_proc(BT_CAP_COMMON_PROC_TYPE_UPDATE, param->count); bt_cap_common_set_subproc(BT_CAP_COMMON_SUBPROC_TYPE_META_UPDATE); proc_param = &active_proc->proc_param.initiator[0]; diff --git a/subsys/bluetooth/audio/shell/cap_initiator.c b/subsys/bluetooth/audio/shell/cap_initiator.c index 17b4e96ec8e..988fb6238da 100644 --- a/subsys/bluetooth/audio/shell/cap_initiator.c +++ b/subsys/bluetooth/audio/shell/cap_initiator.c @@ -337,8 +337,9 @@ static int cmd_cap_initiator_unicast_list(const struct shell *sh, size_t argc, static int cmd_cap_initiator_unicast_update(const struct shell *sh, size_t argc, char *argv[]) { - struct bt_cap_unicast_audio_update_param params[CAP_UNICAST_CLIENT_STREAM_COUNT]; - size_t count; + struct bt_cap_unicast_audio_update_stream_param + stream_params[CAP_UNICAST_CLIENT_STREAM_COUNT] = {0}; + struct bt_cap_unicast_audio_update_param param = {0}; int err = 0; if (default_conn == NULL) { @@ -346,8 +347,6 @@ static int cmd_cap_initiator_unicast_update(const struct shell *sh, size_t argc, return -ENOEXEC; } - count = 0; - if (argc == 2 && strcmp(argv[1], "all") == 0) { for (size_t i = 0U; i < ARRAY_SIZE(unicast_streams); i++) { struct bt_cap_stream *stream = &unicast_streams[i].stream; @@ -366,8 +365,7 @@ static int cmd_cap_initiator_unicast_update(const struct shell *sh, size_t argc, return -ENOEXEC; } - params[count].stream = stream; - + stream_params[param.count].stream = stream; if (ep_info.dir == BT_AUDIO_DIR_SINK) { copy_unicast_stream_preset(uni_stream, default_sink_preset); @@ -375,10 +373,10 @@ static int cmd_cap_initiator_unicast_update(const struct shell *sh, size_t argc, copy_unicast_stream_preset(uni_stream, default_source_preset); } - params[count].meta = uni_stream->codec_cfg.meta; - params[count].meta_len = uni_stream->codec_cfg.meta_len; + stream_params[param.count].meta = uni_stream->codec_cfg.meta; + stream_params[param.count].meta_len = uni_stream->codec_cfg.meta_len; - count++; + param.count++; } } else { @@ -409,7 +407,7 @@ static int cmd_cap_initiator_unicast_update(const struct shell *sh, size_t argc, return -ENOEXEC; } - params[count].stream = stream; + stream_params[param.count].stream = stream; if (ep_info.dir == BT_AUDIO_DIR_SINK) { copy_unicast_stream_preset(uni_stream, default_sink_preset); @@ -417,22 +415,25 @@ static int cmd_cap_initiator_unicast_update(const struct shell *sh, size_t argc, copy_unicast_stream_preset(uni_stream, default_source_preset); } - params[count].meta = uni_stream->codec_cfg.meta; - params[count].meta_len = uni_stream->codec_cfg.meta_len; + stream_params[param.count].meta = uni_stream->codec_cfg.meta; + stream_params[param.count].meta_len = uni_stream->codec_cfg.meta_len; - count++; + param.count++; } } - if (count == 0) { + if (param.count == 0) { shell_error(sh, "No streams to update"); return -ENOEXEC; } - shell_print(sh, "Updating %zu streams", count); + param.stream_params = stream_params; + param.type = BT_CAP_SET_TYPE_AD_HOC; + + shell_print(sh, "Updating %zu streams", param.count); - err = bt_cap_initiator_unicast_audio_update(params, count); + err = bt_cap_initiator_unicast_audio_update(¶m); if (err != 0) { shell_print(sh, "Failed to update unicast audio: %d", err); } diff --git a/tests/bluetooth/tester/src/btp_cap.c b/tests/bluetooth/tester/src/btp_cap.c index c28fe6e5e7d..c1e48e11909 100644 --- a/tests/bluetooth/tester/src/btp_cap.c +++ b/tests/bluetooth/tester/src/btp_cap.c @@ -341,8 +341,9 @@ static uint8_t btp_cap_unicast_audio_update(const void *cmd, uint16_t cmd_len, int err; const uint8_t *data_ptr; const struct btp_cap_unicast_audio_update_cmd *cp = cmd; - struct bt_cap_unicast_audio_update_param stream_params[ - ARRAY_SIZE(btp_csip_set_members) * BTP_BAP_UNICAST_MAX_STREAMS_COUNT]; + struct bt_cap_unicast_audio_update_stream_param + stream_params[ARRAY_SIZE(btp_csip_set_members) * BTP_BAP_UNICAST_MAX_STREAMS_COUNT]; + struct bt_cap_unicast_audio_update_param param = {0}; LOG_DBG(""); @@ -357,7 +358,7 @@ static uint8_t btp_cap_unicast_audio_update(const void *cmd, uint16_t cmd_len, struct bt_conn *conn; struct btp_cap_unicast_audio_update_data *update_data = (struct btp_cap_unicast_audio_update_data *)data_ptr; - struct bt_cap_unicast_audio_update_param *param = &stream_params[i]; + struct bt_cap_unicast_audio_update_stream_param *stream_param = &stream_params[i]; conn = bt_conn_lookup_addr_le(BT_ID_DEFAULT, &update_data->address); if (!conn) { @@ -379,15 +380,19 @@ static uint8_t btp_cap_unicast_audio_update(const void *cmd, uint16_t cmd_len, return BTP_STATUS_FAILED; } - param->stream = &u_stream->audio_stream.cap_stream; - param->meta_len = update_data->metadata_ltvs_len; - param->meta = update_data->metadata_ltvs; + stream_param->stream = &u_stream->audio_stream.cap_stream; + stream_param->meta_len = update_data->metadata_ltvs_len; + stream_param->meta = update_data->metadata_ltvs; - data_ptr = ((uint8_t *)update_data) + param->meta_len + + data_ptr = ((uint8_t *)update_data) + stream_param->meta_len + sizeof(struct btp_cap_unicast_audio_update_data); } - err = bt_cap_initiator_unicast_audio_update(stream_params, cp->stream_count); + param.count = cp->stream_count; + param.stream_params = stream_params; + param.type = BT_CAP_SET_TYPE_AD_HOC; + + err = bt_cap_initiator_unicast_audio_update(¶m); if (err != 0) { LOG_ERR("Failed to start unicast audio: %d", err); diff --git a/tests/bsim/bluetooth/audio/src/cap_initiator_unicast_test.c b/tests/bsim/bluetooth/audio/src/cap_initiator_unicast_test.c index 1c2f7b40007..347323efc87 100644 --- a/tests/bsim/bluetooth/audio/src/cap_initiator_unicast_test.c +++ b/tests/bsim/bluetooth/audio/src/cap_initiator_unicast_test.c @@ -663,30 +663,36 @@ static void unicast_audio_update_inval(void) { struct bt_audio_codec_cfg invalid_codec = BT_AUDIO_CODEC_LC3_CONFIG_16_2( BT_AUDIO_LOCATION_FRONT_LEFT, BT_AUDIO_CONTEXT_TYPE_MEDIA); - struct bt_cap_unicast_audio_update_param param; + struct bt_cap_unicast_audio_update_stream_param stream_params[1] = {0}; + struct bt_cap_unicast_audio_update_param param = {0}; int err; - param.stream = &unicast_client_sink_streams[0]; - param.meta = unicast_preset_16_2_1.codec_cfg.meta; - param.meta_len = unicast_preset_16_2_1.codec_cfg.meta_len; + stream_params[0].stream = &unicast_client_sink_streams[0]; + stream_params[0].meta = unicast_preset_16_2_1.codec_cfg.meta; + stream_params[0].meta_len = unicast_preset_16_2_1.codec_cfg.meta_len; + param.count = ARRAY_SIZE(stream_params); + param.stream_params = stream_params; + param.type = BT_CAP_SET_TYPE_AD_HOC; - err = bt_cap_initiator_unicast_audio_update(NULL, 1); + err = bt_cap_initiator_unicast_audio_update(NULL); if (err == 0) { FAIL("bt_cap_initiator_unicast_audio_update with NULL params did not fail\n"); return; } - err = bt_cap_initiator_unicast_audio_update(¶m, 0); + param.count = 0U; + err = bt_cap_initiator_unicast_audio_update(¶m); if (err == 0) { FAIL("bt_cap_initiator_unicast_audio_update with 0 param count did not fail\n"); return; } /* Clear metadata so that it does not contain the mandatory stream context */ + param.count = ARRAY_SIZE(stream_params); memset(&invalid_codec.meta, 0, sizeof(invalid_codec.meta)); - param.meta = invalid_codec.meta; + stream_params[0].meta = invalid_codec.meta; - err = bt_cap_initiator_unicast_audio_update(¶m, 1); + err = bt_cap_initiator_unicast_audio_update(¶m); if (err == 0) { FAIL("bt_cap_initiator_unicast_audio_update with invalid Codec metadata did not " "fail\n"); @@ -696,7 +702,8 @@ static void unicast_audio_update_inval(void) static void unicast_audio_update(void) { - struct bt_cap_unicast_audio_update_param param[2]; + struct bt_cap_unicast_audio_update_stream_param stream_params[2] = {0}; + struct bt_cap_unicast_audio_update_param param = {0}; uint8_t new_meta[] = { 3, BT_AUDIO_METADATA_TYPE_STREAM_CONTEXT, @@ -707,17 +714,21 @@ static void unicast_audio_update(void) }; int err; - param[0].stream = &unicast_client_sink_streams[0]; - param[0].meta = new_meta; - param[0].meta_len = ARRAY_SIZE(new_meta); + stream_params[0].stream = &unicast_client_sink_streams[0]; + stream_params[0].meta = new_meta; + stream_params[0].meta_len = ARRAY_SIZE(new_meta); + + stream_params[1].stream = &unicast_client_source_streams[0]; + stream_params[1].meta = new_meta; + stream_params[1].meta_len = ARRAY_SIZE(new_meta); - param[1].stream = &unicast_client_source_streams[0]; - param[1].meta = new_meta; - param[1].meta_len = ARRAY_SIZE(new_meta); + param.count = ARRAY_SIZE(stream_params); + param.stream_params = stream_params; + param.type = BT_CAP_SET_TYPE_AD_HOC; UNSET_FLAG(flag_updated); - err = bt_cap_initiator_unicast_audio_update(param, ARRAY_SIZE(param)); + err = bt_cap_initiator_unicast_audio_update(¶m); if (err != 0) { FAIL("Failed to update unicast audio: %d\n", err); return; From 065253c17347c13306588d19ec9a6f3ebc880f81 Mon Sep 17 00:00:00 2001 From: Emil Gydesen Date: Thu, 18 Jan 2024 12:05:25 +0100 Subject: [PATCH 3478/3723] Bluetooth: CAP: Make unicast stop more similar to unicast start Modify the parameters for bt_cap_initiator_unicast_audio_stop so that they are more similar to bt_cap_initiator_unicast_audio_start. Signed-off-by: Emil Gydesen --- include/zephyr/bluetooth/audio/cap.h | 22 +++- subsys/bluetooth/audio/cap_initiator.c | 111 +++++++++++++++--- subsys/bluetooth/audio/shell/cap_initiator.c | 64 +++++++++- tests/bluetooth/tester/src/btp_cap.c | 32 ++++- .../audio/src/cap_initiator_unicast_test.c | 46 +++++++- tests/bsim/bluetooth/audio/src/common.h | 17 ++- .../bsim/bluetooth/audio/src/gmap_ugg_test.c | 24 +++- 7 files changed, 273 insertions(+), 43 deletions(-) diff --git a/include/zephyr/bluetooth/audio/cap.h b/include/zephyr/bluetooth/audio/cap.h index 447e0c2f9b2..c595e6171fd 100644 --- a/include/zephyr/bluetooth/audio/cap.h +++ b/include/zephyr/bluetooth/audio/cap.h @@ -255,6 +255,18 @@ struct bt_cap_unicast_audio_update_param { struct bt_cap_unicast_audio_update_stream_param *stream_params; }; +/** Parameters for the bt_cap_initiator_unicast_audio_stop() function */ +struct bt_cap_unicast_audio_stop_param { + /** The type of the set. */ + enum bt_cap_set_type type; + + /** The number of streams in @p streams */ + size_t count; + + /** Array of streams to stop */ + struct bt_cap_stream **streams; +}; + /** * @brief Register Common Audio Profile Initiator callbacks * @@ -297,19 +309,19 @@ int bt_cap_initiator_unicast_audio_start(const struct bt_cap_unicast_audio_start int bt_cap_initiator_unicast_audio_update(const struct bt_cap_unicast_audio_update_param *param); /** - * @brief Stop unicast audio streams for a unicast group. + * @brief Stop unicast audio streams. + * + * This will stop one or more streams. * * @note @kconfig{CONFIG_BT_CAP_INITIATOR} and * @kconfig{CONFIG_BT_BAP_UNICAST_CLIENT} must be enabled for this function * to be enabled. * - * @param unicast_group The group of unicast devices to stop. The audio streams - * in this will be stopped and reset, and the - * @p unicast_group will be invalidated. + * @param param Stop parameters. * * @return 0 on success or negative error value on failure. */ -int bt_cap_initiator_unicast_audio_stop(struct bt_bap_unicast_group *unicast_group); +int bt_cap_initiator_unicast_audio_stop(const struct bt_cap_unicast_audio_stop_param *param); /** @brief Cancel any current Common Audio Profile procedure * diff --git a/subsys/bluetooth/audio/cap_initiator.c b/subsys/bluetooth/audio/cap_initiator.c index 78f278aa421..b75b1c327c8 100644 --- a/subsys/bluetooth/audio/cap_initiator.c +++ b/subsys/bluetooth/audio/cap_initiator.c @@ -1135,12 +1135,98 @@ static bool can_release(const struct bt_bap_stream *bap_stream) return ep_info.state != BT_BAP_EP_STATE_IDLE; } -int bt_cap_initiator_unicast_audio_stop(struct bt_bap_unicast_group *unicast_group) +static bool valid_unicast_audio_stop_param(const struct bt_cap_unicast_audio_stop_param *param) +{ + struct bt_bap_unicast_group *unicast_group = NULL; + + CHECKIF(param == NULL) { + LOG_DBG("param is NULL"); + return false; + } + + CHECKIF(param->count == 0) { + LOG_DBG("Invalid param->count: %u", param->count); + return false; + } + + CHECKIF(param->streams == NULL) { + LOG_DBG("param->streams is NULL"); + return false; + } + + CHECKIF(param->count > CONFIG_BT_BAP_UNICAST_CLIENT_GROUP_STREAM_COUNT) { + LOG_DBG("param->count (%zu) is larger than " + "CONFIG_BT_BAP_UNICAST_CLIENT_GROUP_STREAM_COUNT (%d)", + param->count, CONFIG_BT_BAP_UNICAST_CLIENT_GROUP_STREAM_COUNT); + return false; + } + + for (size_t i = 0U; i < param->count; i++) { + const struct bt_cap_stream *cap_stream = param->streams[i]; + const struct bt_bap_stream *bap_stream; + struct bt_cap_common_client *client; + struct bt_conn *conn; + + CHECKIF(cap_stream == NULL) { + LOG_DBG("param->streams[%zu] is NULL", i); + return false; + } + + bap_stream = &cap_stream->bap_stream; + conn = bap_stream->conn; + CHECKIF(conn == NULL) { + LOG_DBG("param->streams[%zu]->bap_stream.conn is NULL", i); + + return -EINVAL; + } + + client = bt_cap_common_get_client_by_acl(conn); + if (!client->cas_found) { + LOG_DBG("CAS was not found for param->streams[%zu]", i); + return false; + } + + CHECKIF(bap_stream->group == NULL) { + LOG_DBG("param->streams[%zu] is not in a unicast group", i); + return false; + } + + /* Use the group of the first stream for comparison */ + if (unicast_group == NULL) { + unicast_group = bap_stream->group; + } else { + CHECKIF(bap_stream->group != unicast_group) { + LOG_DBG("param->streams[%zu] is not in this group %p", i, + unicast_group); + return false; + } + } + + if (!can_release(bap_stream)) { + LOG_DBG("Cannot stop param->streams[%zu]", i); + + return false; + } + + for (size_t j = 0U; j < i; j++) { + if (param->streams[j] == cap_stream) { + LOG_DBG("param->stream_params[%zu] (%p) is " + "duplicated by " + "param->stream_params[%zu] (%p)", + j, param->streams[j], i, cap_stream); + return false; + } + } + } + + return true; +} + +int bt_cap_initiator_unicast_audio_stop(const struct bt_cap_unicast_audio_stop_param *param) { struct bt_cap_common_proc *active_proc = bt_cap_common_get_active_proc(); struct bt_cap_initiator_proc_param *proc_param; struct bt_bap_stream *bap_stream; - size_t stream_cnt; int err; if (bt_cap_common_proc_is_active()) { @@ -1149,28 +1235,17 @@ int bt_cap_initiator_unicast_audio_stop(struct bt_bap_unicast_group *unicast_gro return -EBUSY; } - CHECKIF(unicast_group == NULL) { - LOG_DBG("unicast_group is NULL"); + if (!valid_unicast_audio_stop_param(param)) { return -EINVAL; } - stream_cnt = 0U; - SYS_SLIST_FOR_EACH_CONTAINER(&unicast_group->streams, bap_stream, _node) { - if (can_release(bap_stream)) { - struct bt_cap_stream *cap_stream = - CONTAINER_OF(bap_stream, struct bt_cap_stream, bap_stream); - active_proc->proc_param.initiator[stream_cnt].stream = cap_stream; - stream_cnt++; - } - } - - if (stream_cnt == 0U) { - LOG_DBG("All streams are already stopped"); + for (size_t i = 0U; i < param->count; i++) { + struct bt_cap_stream *cap_stream = param->streams[i]; - return -EALREADY; + active_proc->proc_param.initiator[i].stream = cap_stream; } - bt_cap_common_start_proc(BT_CAP_COMMON_PROC_TYPE_STOP, stream_cnt); + bt_cap_common_start_proc(BT_CAP_COMMON_PROC_TYPE_STOP, param->count); bt_cap_common_set_subproc(BT_CAP_COMMON_SUBPROC_TYPE_RELEASE); diff --git a/subsys/bluetooth/audio/shell/cap_initiator.c b/subsys/bluetooth/audio/shell/cap_initiator.c index 988fb6238da..936d0142ca4 100644 --- a/subsys/bluetooth/audio/shell/cap_initiator.c +++ b/subsys/bluetooth/audio/shell/cap_initiator.c @@ -444,17 +444,75 @@ static int cmd_cap_initiator_unicast_update(const struct shell *sh, size_t argc, static int cmd_cap_initiator_unicast_stop(const struct shell *sh, size_t argc, char *argv[]) { + struct bt_cap_stream *streams[CAP_UNICAST_CLIENT_STREAM_COUNT]; + struct bt_cap_unicast_audio_stop_param param = {0}; int err = 0; if (default_conn == NULL) { shell_error(sh, "Not connected"); return -ENOEXEC; - } else if (default_unicast_group == NULL) { - shell_error(sh, "No unicast group started"); + } + + if (argc == 2 && strcmp(argv[1], "all") == 0) { + for (size_t i = 0U; i < ARRAY_SIZE(unicast_streams); i++) { + struct bt_cap_stream *stream = &unicast_streams[i].stream; + struct bt_bap_ep_info ep_info; + + if (stream->bap_stream.conn == NULL) { + break; + } + + err = bt_bap_ep_get_info(stream->bap_stream.ep, &ep_info); + if (err != 0) { + shell_error(sh, "Failed to get endpoint info: %d", err); + + return -ENOEXEC; + } + + streams[param.count] = stream; + param.count++; + } + + } else { + for (size_t i = 1U; i < argc; i++) { + struct bt_cap_stream *stream = (void *)shell_strtoul(argv[i], 16, &err); + struct bt_bap_ep_info ep_info; + + if (err != 0) { + shell_error(sh, "Failed to parse stream argument %s: %d", argv[i], + err); + + return err; + } + + if (!PART_OF_ARRAY(unicast_streams, stream)) { + shell_error(sh, "Pointer %p is not a CAP stream pointer", stream); + + return -ENOEXEC; + } + + err = bt_bap_ep_get_info(stream->bap_stream.ep, &ep_info); + if (err != 0) { + shell_error(sh, "Failed to get endpoint info: %d", err); + + return -ENOEXEC; + } + + streams[param.count] = stream; + param.count++; + } + } + + if (param.count == 0) { + shell_error(sh, "No streams to update"); + return -ENOEXEC; } - err = bt_cap_initiator_unicast_audio_stop(default_unicast_group); + param.streams = streams; + param.type = BT_CAP_SET_TYPE_AD_HOC; + + err = bt_cap_initiator_unicast_audio_stop(¶m); if (err != 0) { shell_print(sh, "Failed to update unicast audio: %d", err); } diff --git a/tests/bluetooth/tester/src/btp_cap.c b/tests/bluetooth/tester/src/btp_cap.c index c1e48e11909..ea1a6acf89e 100644 --- a/tests/bluetooth/tester/src/btp_cap.c +++ b/tests/bluetooth/tester/src/btp_cap.c @@ -405,16 +405,40 @@ static uint8_t btp_cap_unicast_audio_update(const void *cmd, uint16_t cmd_len, static uint8_t btp_cap_unicast_audio_stop(const void *cmd, uint16_t cmd_len, void *rsp, uint16_t *rsp_len) { - + struct bt_cap_stream + *streams[ARRAY_SIZE(btp_csip_set_members) * BTP_BAP_UNICAST_MAX_STREAMS_COUNT]; + struct bt_cap_unicast_audio_stop_param param = {0}; int err; const struct btp_cap_unicast_audio_stop_cmd *cp = cmd; - struct btp_bap_unicast_group *group; + size_t stream_cnt = 0U; LOG_DBG(""); - group = btp_bap_unicast_group_find(cp->cig_id); + /* Get generate the same stream list as used by btp_cap_unicast_audio_start */ + for (size_t conn_index = 0; conn_index < ARRAY_SIZE(btp_csip_set_members); conn_index++) { + struct btp_bap_unicast_connection *u_conn = btp_bap_unicast_conn_get(conn_index); + + if (u_conn->end_points_count == 0) { + /* Connection not initialized */ + continue; + } + + for (size_t i = 0; i < ARRAY_SIZE(u_conn->streams); i++) { + struct btp_bap_unicast_stream *u_stream = &u_conn->streams[i]; + + if (!u_stream->in_use || u_stream->cig_id != cp->cig_id) { + continue; + } + + streams[stream_cnt++] = stream_unicast_to_cap(u_stream); + } + } + + param.streams = streams; + param.count = stream_cnt; + param.type = BT_CAP_SET_TYPE_AD_HOC; - err = bt_cap_initiator_unicast_audio_stop(group->cig); + err = bt_cap_initiator_unicast_audio_stop(¶m); if (err != 0) { LOG_ERR("Failed to start unicast audio: %d", err); diff --git a/tests/bsim/bluetooth/audio/src/cap_initiator_unicast_test.c b/tests/bsim/bluetooth/audio/src/cap_initiator_unicast_test.c index 347323efc87..72ef686b1db 100644 --- a/tests/bsim/bluetooth/audio/src/cap_initiator_unicast_test.c +++ b/tests/bsim/bluetooth/audio/src/cap_initiator_unicast_test.c @@ -55,6 +55,8 @@ static struct bt_conn *connected_conns[CAP_AC_MAX_CONN]; static size_t connected_conn_cnt; static const struct named_lc3_preset *snk_named_preset; static const struct named_lc3_preset *src_named_preset; +static struct bt_cap_stream *non_idle_streams[CONFIG_BT_BAP_UNICAST_CLIENT_GROUP_STREAM_COUNT]; +static size_t non_idle_streams_cnt; CREATE_FLAG(flag_discovered); CREATE_FLAG(flag_codec_found); @@ -106,8 +108,19 @@ static const struct named_lc3_preset lc3_unicast_presets[] = { static void unicast_stream_configured(struct bt_bap_stream *stream, const struct bt_audio_codec_qos_pref *pref) { + struct bt_cap_stream *cap_stream = cap_stream_from_bap_stream(stream); printk("Configured stream %p\n", stream); + for (size_t i = 0U; i < ARRAY_SIZE(non_idle_streams); i++) { + if (non_idle_streams[i] == NULL) { + non_idle_streams[i] = cap_stream; + non_idle_streams_cnt++; + return; + } + } + + FAIL("Could not store cap_stream in non_idle_streams\n"); + /* TODO: The preference should be used/taken into account when * setting the QoS */ @@ -145,7 +158,19 @@ static void unicast_stream_stopped(struct bt_bap_stream *stream, uint8_t reason) static void unicast_stream_released(struct bt_bap_stream *stream) { + struct bt_cap_stream *cap_stream = cap_stream_from_bap_stream(stream); + printk("Released stream %p\n", stream); + + for (size_t i = 0U; i < ARRAY_SIZE(non_idle_streams); i++) { + if (non_idle_streams[i] == cap_stream) { + non_idle_streams[i] = NULL; + non_idle_streams_cnt--; + return; + } + } + + FAIL("Could not find cap_stream in non_idle_streams\n"); } static struct bt_bap_stream_ops unicast_stream_ops = { @@ -347,6 +372,10 @@ static void init(void) for (size_t i = 0; i < ARRAY_SIZE(unicast_client_source_streams); i++) { bt_cap_stream_ops_register(&unicast_client_source_streams[i], &unicast_stream_ops); } + + for (size_t i = 0; i < ARRAY_SIZE(unicast_streams); i++) { + bt_cap_stream_ops_register(&unicast_streams[i].stream, &unicast_stream_ops); + } } static void cap_device_found(const bt_addr_le_t *addr, int8_t rssi, uint8_t type, @@ -744,30 +773,35 @@ static void unicast_audio_stop_inval(void) err = bt_cap_initiator_unicast_audio_stop(NULL); if (err == 0) { - FAIL("bt_cap_initiator_unicast_audio_stop with NULL group did not fail\n"); + FAIL("bt_cap_initiator_unicast_audio_stop with NULL param did not fail\n"); return; } } static void unicast_audio_stop(struct bt_bap_unicast_group *unicast_group) { + struct bt_cap_unicast_audio_stop_param param; int err; + param.type = BT_CAP_SET_TYPE_AD_HOC; + param.count = non_idle_streams_cnt; + param.streams = non_idle_streams; + UNSET_FLAG(flag_stopped); - err = bt_cap_initiator_unicast_audio_stop(unicast_group); + err = bt_cap_initiator_unicast_audio_stop(¶m); if (err != 0) { - FAIL("Failed to start unicast audio: %d\n", err); + FAIL("Failed to stop unicast audio: %d\n", err); return; } WAIT_FOR_FLAG(flag_stopped); /* Verify that it cannot be stopped twice */ - err = bt_cap_initiator_unicast_audio_stop(unicast_group); + err = bt_cap_initiator_unicast_audio_stop(¶m); if (err == 0) { - FAIL("bt_cap_initiator_unicast_audio_stop with already-stopped unicast group did " - "not fail\n"); + FAIL("bt_cap_initiator_unicast_audio_stop with already-stopped streams did not " + "fail\n"); return; } } diff --git a/tests/bsim/bluetooth/audio/src/common.h b/tests/bsim/bluetooth/audio/src/common.h index d39cfcd656b..f77c4bab5c0 100644 --- a/tests/bsim/bluetooth/audio/src/common.h +++ b/tests/bsim/bluetooth/audio/src/common.h @@ -139,6 +139,16 @@ struct audio_test_stream { size_t rx_cnt; }; +static inline struct bt_cap_stream *cap_stream_from_bap_stream(struct bt_bap_stream *bap_stream) +{ + return CONTAINER_OF(bap_stream, struct bt_cap_stream, bap_stream); +} + +static inline struct bt_bap_stream *bap_stream_from_cap_stream(struct bt_cap_stream *cap_stream) +{ + return &cap_stream->bap_stream; +} + static inline struct audio_test_stream * audio_test_stream_from_cap_stream(struct bt_cap_stream *cap_stream) { @@ -148,10 +158,7 @@ audio_test_stream_from_cap_stream(struct bt_cap_stream *cap_stream) static inline struct audio_test_stream * audio_test_stream_from_bap_stream(struct bt_bap_stream *bap_stream) { - struct bt_cap_stream *cap_stream = - CONTAINER_OF(bap_stream, struct bt_cap_stream, bap_stream); - - return audio_test_stream_from_cap_stream(cap_stream); + return audio_test_stream_from_cap_stream(cap_stream_from_bap_stream(bap_stream)); } static inline struct bt_cap_stream * @@ -163,7 +170,7 @@ cap_stream_from_audio_test_stream(struct audio_test_stream *test_stream) static inline struct bt_bap_stream * bap_stream_from_audio_test_stream(struct audio_test_stream *test_stream) { - return &cap_stream_from_audio_test_stream(test_stream)->bap_stream; + return bap_stream_from_cap_stream(cap_stream_from_audio_test_stream(test_stream)); } #endif /* ZEPHYR_TEST_BSIM_BT_AUDIO_TEST_ */ diff --git a/tests/bsim/bluetooth/audio/src/gmap_ugg_test.c b/tests/bsim/bluetooth/audio/src/gmap_ugg_test.c index 303be04b6c1..53b43b36e89 100644 --- a/tests/bsim/bluetooth/audio/src/gmap_ugg_test.c +++ b/tests/bsim/bluetooth/audio/src/gmap_ugg_test.c @@ -106,6 +106,8 @@ struct named_lc3_preset named_preset; static struct audio_test_stream broadcast_streams[CONFIG_BT_BAP_BROADCAST_SRC_STREAM_COUNT]; static struct unicast_stream unicast_streams[GMAP_UNICAST_AC_MAX_STREAM]; +static struct bt_cap_stream *started_unicast_streams[GMAP_UNICAST_AC_MAX_STREAM]; +static size_t started_unicast_streams_cnt; static struct bt_bap_ep *sink_eps[GMAP_UNICAST_AC_MAX_CONN][CONFIG_BT_BAP_UNICAST_CLIENT_ASE_SNK_COUNT]; static struct bt_bap_ep @@ -685,6 +687,7 @@ static int gmap_ac_cap_unicast_start(const struct gmap_unicast_ac_param *param, size_t stream_cnt = 0U; size_t snk_ep_cnt = 0U; size_t src_ep_cnt = 0U; + int err; for (size_t i = 0U; i < param->conn_cnt; i++) { #if UNICAST_SINK_SUPPORTED @@ -797,7 +800,16 @@ static int gmap_ac_cap_unicast_start(const struct gmap_unicast_ac_param *param, start_param.count = stream_cnt; start_param.type = BT_CAP_SET_TYPE_AD_HOC; - return bt_cap_initiator_unicast_audio_start(&start_param); + err = bt_cap_initiator_unicast_audio_start(&start_param); + if (err == 0) { + for (size_t i = 0U; i < start_param.count; i++) { + started_unicast_streams[i] = start_param.stream_params[i].stream; + } + + started_unicast_streams_cnt = start_param.count; + } + + return err; } static int gmap_ac_unicast(const struct gmap_unicast_ac_param *param, @@ -887,17 +899,25 @@ static int gmap_ac_unicast(const struct gmap_unicast_ac_param *param, static void unicast_audio_stop(struct bt_bap_unicast_group *unicast_group) { + struct bt_cap_unicast_audio_stop_param param; int err; UNSET_FLAG(flag_stopped); - err = bt_cap_initiator_unicast_audio_stop(unicast_group); + param.type = BT_CAP_SET_TYPE_AD_HOC; + param.count = started_unicast_streams_cnt; + param.streams = started_unicast_streams; + + err = bt_cap_initiator_unicast_audio_stop(¶m); if (err != 0) { FAIL("Failed to start unicast audio: %d\n", err); return; } WAIT_FOR_FLAG(flag_stopped); + + started_unicast_streams_cnt = 0U; + memset(started_unicast_streams, 0, sizeof(started_unicast_streams)); } static void unicast_group_delete(struct bt_bap_unicast_group *unicast_group) From caacc27d3738ff065dc85b5afbd390cfba179453 Mon Sep 17 00:00:00 2001 From: Daniel Leung Date: Wed, 31 Jan 2024 10:54:53 -0800 Subject: [PATCH 3479/3723] kernel: smp: CPU start may result in null pointer access It is observed that starting up CPU may result in other CPUs crashing due to de-referencing NULL pointers. Note that this happened on the up_squared board, but there was no way to attach debugger to verify. It started working again after moving z_dummy_thread_init() before smp_timer_init(), which was the old behavior before commit eefaeee061c869cfa33be9693ff186ca60f76ff9 where the issue first appeared. So mimic the old behavior to workaround the issue. Fixes #68115 Signed-off-by: Daniel Leung --- kernel/smp.c | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) diff --git a/kernel/smp.c b/kernel/smp.c index 45ec956dff9..177362c6a7c 100644 --- a/kernel/smp.c +++ b/kernel/smp.c @@ -119,6 +119,13 @@ static inline void smp_init_top(void *arg) */ wait_for_start_signal(&cpu_start_flag); + if ((csc == NULL) || csc->invoke_sched) { + /* Initialize the dummy thread struct so that + * the scheduler can schedule actual threads to run. + */ + z_dummy_thread_init(&dummy_thread); + } + #ifdef CONFIG_SYS_CLOCK_EXISTS if ((csc == NULL) || csc->reinit_timer) { smp_timer_init(); @@ -135,11 +142,6 @@ static inline void smp_init_top(void *arg) return; } - /* Initialize the dummy thread struct so that - * the scheduler can schedule actual threads to run. - */ - z_dummy_thread_init(&dummy_thread); - /* Let scheduler decide what thread to run next. */ z_swap_unlocked(); From 826d67af9169880ede225eec7aa0949ebff865f5 Mon Sep 17 00:00:00 2001 From: Ian Morris Date: Fri, 5 Jan 2024 15:01:15 -0800 Subject: [PATCH 3480/3723] drivers: serial: ra: reduce uart baud rate error Using the 8 base clock cycles per bit period setting (instead of 16) reduces the uart baud rate error when using a 12MHz crystal (found on many RA Microcontroller development kits boards). This setting also slightly reduces the error when using the internal 48MHz oscillator, used by the Arduino UNO R4 Minima board currently support by Zephyr. Signed-off-by: Ian Morris --- drivers/serial/uart_renesas_ra.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/drivers/serial/uart_renesas_ra.c b/drivers/serial/uart_renesas_ra.c index f9c1607bfca..81f6c567c84 100644 --- a/drivers/serial/uart_renesas_ra.c +++ b/drivers/serial/uart_renesas_ra.c @@ -216,11 +216,11 @@ static void uart_ra_set_baudrate(const struct device *dev, uint32_t baud_rate) uint8_t reg_val; reg_val = uart_ra_read_8(dev, SEMR); - reg_val |= REG_MASK(SEMR_BGDM); - reg_val &= ~(REG_MASK(SEMR_BRME) | REG_MASK(SEMR_ABCSE) | REG_MASK(SEMR_ABCS)); + reg_val |= (REG_MASK(SEMR_BGDM) | REG_MASK(SEMR_ABCS)); + reg_val &= ~(REG_MASK(SEMR_BRME) | REG_MASK(SEMR_ABCSE)); uart_ra_write_8(dev, SEMR, reg_val); - reg_val = (data->clk_rate / (16 * data->current_config.baudrate)) - 1; + reg_val = (data->clk_rate / (8 * data->current_config.baudrate)) - 1; uart_ra_write_8(dev, BRR, reg_val); } From 8f267065f2269e920d7c911d0fa902c6c2bc8d21 Mon Sep 17 00:00:00 2001 From: Joel Guittet Date: Sat, 20 Jan 2024 22:36:53 +0100 Subject: [PATCH 3481/3723] dts: bindings: fix gc9x01x display documentation The bindings documentation contains a deprecated pixel-format. Signed-off-by: Joel Guittet --- dts/bindings/display/galaxycore,gc9x01x.yaml | 2 -- 1 file changed, 2 deletions(-) diff --git a/dts/bindings/display/galaxycore,gc9x01x.yaml b/dts/bindings/display/galaxycore,gc9x01x.yaml index fbfa6009a8a..37c4a5680a5 100644 --- a/dts/bindings/display/galaxycore,gc9x01x.yaml +++ b/dts/bindings/display/galaxycore,gc9x01x.yaml @@ -21,10 +21,8 @@ description: | cmd-data-gpios = <&gpio0 4 GPIO_ACTIVE_HIGH>; reset-gpios = <&gpio0 8 GPIO_ACTIVE_LOW>; pixel-format = ; - width = <240>; height = <240>; - pixel-format = ; }; }; From e90613efb2ba84e99295fe88d2fe8324316b4271 Mon Sep 17 00:00:00 2001 From: Joel Guittet Date: Sat, 20 Jan 2024 22:38:08 +0100 Subject: [PATCH 3482/3723] drivers: display: gc9x01x: fix bindings include The GC9X01X driver relies on panel.h instead of gc9x01x.h (doesn't exist). Signed-off-by: Joel Guittet --- drivers/display/display_gc9x01x.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/display/display_gc9x01x.c b/drivers/display/display_gc9x01x.c index cddf14e11f2..1d432d3f355 100644 --- a/drivers/display/display_gc9x01x.c +++ b/drivers/display/display_gc9x01x.c @@ -8,7 +8,7 @@ #include "display_gc9x01x.h" -#include +#include #include #include #include From adaacefc2032721c510e91d3ac8b50251c95300c Mon Sep 17 00:00:00 2001 From: Radoslaw Koppel Date: Mon, 5 Feb 2024 10:28:06 +0100 Subject: [PATCH 3483/3723] arch: arm, arm64: Disable swi_tables.ld file when not required MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This commit removes the need of swi_tables.ld file if the ISR table generator is not configured to use it. Signed-off-by: Radosław Koppel --- arch/arm/core/swi_tables.ld | 2 +- arch/arm/core/vector_table.ld | 2 +- arch/arm64/core/swi_tables.ld | 2 +- include/zephyr/arch/arm64/scripts/linker.ld | 2 +- 4 files changed, 4 insertions(+), 4 deletions(-) diff --git a/arch/arm/core/swi_tables.ld b/arch/arm/core/swi_tables.ld index c6ca94604dd..a06e851e52e 100644 --- a/arch/arm/core/swi_tables.ld +++ b/arch/arm/core/swi_tables.ld @@ -3,6 +3,6 @@ * * SPDX-License-Identifier: Apache-2.0 */ -#if LINKER_ZEPHYR_FINAL +#if LINKER_ZEPHYR_FINAL && defined(CONFIG_ISR_TABLES_LOCAL_DECLARATION) INCLUDE zephyr/isr_tables_swi.ld #endif diff --git a/arch/arm/core/vector_table.ld b/arch/arm/core/vector_table.ld index 58210afdcbc..a5af58fe6de 100644 --- a/arch/arm/core/vector_table.ld +++ b/arch/arm/core/vector_table.ld @@ -51,7 +51,7 @@ _vector_start = .; KEEP(*(.exc_vector_table)) KEEP(*(".exc_vector_table.*")) -#if LINKER_ZEPHYR_FINAL && CONFIG_ISR_TABLES_LOCAL_DECLARATION +#if LINKER_ZEPHYR_FINAL && defined(CONFIG_ISR_TABLES_LOCAL_DECLARATION) INCLUDE zephyr/isr_tables_vt.ld #else KEEP(*(.vectors)) diff --git a/arch/arm64/core/swi_tables.ld b/arch/arm64/core/swi_tables.ld index c6ca94604dd..a06e851e52e 100644 --- a/arch/arm64/core/swi_tables.ld +++ b/arch/arm64/core/swi_tables.ld @@ -3,6 +3,6 @@ * * SPDX-License-Identifier: Apache-2.0 */ -#if LINKER_ZEPHYR_FINAL +#if LINKER_ZEPHYR_FINAL && defined(CONFIG_ISR_TABLES_LOCAL_DECLARATION) INCLUDE zephyr/isr_tables_swi.ld #endif diff --git a/include/zephyr/arch/arm64/scripts/linker.ld b/include/zephyr/arch/arm64/scripts/linker.ld index fb21c3fda5e..fd1a1ea4bb4 100644 --- a/include/zephyr/arch/arm64/scripts/linker.ld +++ b/include/zephyr/arch/arm64/scripts/linker.ld @@ -111,7 +111,7 @@ SECTIONS KEEP(*(.exc_vector_table)) KEEP(*(".exc_vector_table.*")) -#if LINKER_ZEPHYR_FINAL && CONFIG_ISR_TABLES_LOCAL_DECLARATION +#if LINKER_ZEPHYR_FINAL && defined(CONFIG_ISR_TABLES_LOCAL_DECLARATION) INCLUDE zephyr/isr_tables_vt.ld #else KEEP(*(.vectors)) From 08070fbf1f4ca15956a7aef104a131ec5924462c Mon Sep 17 00:00:00 2001 From: Radoslaw Koppel Date: Mon, 5 Feb 2024 10:59:22 +0100 Subject: [PATCH 3484/3723] arch: arm, arm64: Remove zephyr prefix from linker includes MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This fix removes the zephyr/ prefix from linker included files. With this prefix the build works only for Ninja and not for other build tools. Linking in Zephyr / CMake: - Ninja invokes linking directly from . - Make invokes linking form /zephyr. The linker default uses cwd for looking up INCLUDE directives if not found in list of includes. Zephyr always adds /zephyr as link include using CMake, and this is passed to ld as -L/zephyr therefore using INCLUDE isr_tables_swi.ld ensures it will be correctly found in all cases. Signed-off-by: Radosław Koppel --- arch/arm/core/swi_tables.ld | 2 +- arch/arm/core/vector_table.ld | 2 +- arch/arm64/core/swi_tables.ld | 2 +- include/zephyr/arch/arm64/scripts/linker.ld | 2 +- 4 files changed, 4 insertions(+), 4 deletions(-) diff --git a/arch/arm/core/swi_tables.ld b/arch/arm/core/swi_tables.ld index a06e851e52e..a5dd3eaf652 100644 --- a/arch/arm/core/swi_tables.ld +++ b/arch/arm/core/swi_tables.ld @@ -4,5 +4,5 @@ * SPDX-License-Identifier: Apache-2.0 */ #if LINKER_ZEPHYR_FINAL && defined(CONFIG_ISR_TABLES_LOCAL_DECLARATION) -INCLUDE zephyr/isr_tables_swi.ld +INCLUDE isr_tables_swi.ld #endif diff --git a/arch/arm/core/vector_table.ld b/arch/arm/core/vector_table.ld index a5af58fe6de..463e389de9f 100644 --- a/arch/arm/core/vector_table.ld +++ b/arch/arm/core/vector_table.ld @@ -52,7 +52,7 @@ KEEP(*(.exc_vector_table)) KEEP(*(".exc_vector_table.*")) #if LINKER_ZEPHYR_FINAL && defined(CONFIG_ISR_TABLES_LOCAL_DECLARATION) -INCLUDE zephyr/isr_tables_vt.ld +INCLUDE isr_tables_vt.ld #else KEEP(*(.vectors)) #endif diff --git a/arch/arm64/core/swi_tables.ld b/arch/arm64/core/swi_tables.ld index a06e851e52e..a5dd3eaf652 100644 --- a/arch/arm64/core/swi_tables.ld +++ b/arch/arm64/core/swi_tables.ld @@ -4,5 +4,5 @@ * SPDX-License-Identifier: Apache-2.0 */ #if LINKER_ZEPHYR_FINAL && defined(CONFIG_ISR_TABLES_LOCAL_DECLARATION) -INCLUDE zephyr/isr_tables_swi.ld +INCLUDE isr_tables_swi.ld #endif diff --git a/include/zephyr/arch/arm64/scripts/linker.ld b/include/zephyr/arch/arm64/scripts/linker.ld index fd1a1ea4bb4..5a8e1404a98 100644 --- a/include/zephyr/arch/arm64/scripts/linker.ld +++ b/include/zephyr/arch/arm64/scripts/linker.ld @@ -112,7 +112,7 @@ SECTIONS KEEP(*(".exc_vector_table.*")) #if LINKER_ZEPHYR_FINAL && defined(CONFIG_ISR_TABLES_LOCAL_DECLARATION) - INCLUDE zephyr/isr_tables_vt.ld + INCLUDE isr_tables_vt.ld #else KEEP(*(.vectors)) #endif From ab1b43ee1ad8e048a12ff840518e68dfd8c8ef09 Mon Sep 17 00:00:00 2001 From: Emil Gydesen Date: Wed, 20 Dec 2023 17:32:53 +0100 Subject: [PATCH 3485/3723] Bluetooth: VCP/MICP: Fix VOCS and AICS instance counts The VCP and MICP instances should use their respective AICS and VOCS Kconfig options, rather than the overall Kconfig options. Signed-off-by: Emil Gydesen --- subsys/bluetooth/audio/micp_internal.h | 2 +- subsys/bluetooth/audio/vcp_internal.h | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/subsys/bluetooth/audio/micp_internal.h b/subsys/bluetooth/audio/micp_internal.h index a68aaca7cdf..507e7547c75 100644 --- a/subsys/bluetooth/audio/micp_internal.h +++ b/subsys/bluetooth/audio/micp_internal.h @@ -30,7 +30,7 @@ struct bt_micp_mic_ctlr { struct bt_conn *conn; uint8_t aics_inst_cnt; - struct bt_aics *aics[CONFIG_BT_AICS_CLIENT_MAX_INSTANCE_COUNT]; + struct bt_aics *aics[CONFIG_BT_MICP_MIC_CTLR_MAX_AICS_INST]; }; #endif /* ZEPHYR_INCLUDE_BLUETOOTH_AUDIO_MICP_INTERNAL_ */ diff --git a/subsys/bluetooth/audio/vcp_internal.h b/subsys/bluetooth/audio/vcp_internal.h index b791b526c1b..73cbe3a8e69 100644 --- a/subsys/bluetooth/audio/vcp_internal.h +++ b/subsys/bluetooth/audio/vcp_internal.h @@ -60,9 +60,9 @@ struct bt_vcp_vol_ctlr { struct bt_conn *conn; uint8_t vocs_inst_cnt; - struct bt_vocs *vocs[CONFIG_BT_VOCS_CLIENT_MAX_INSTANCE_COUNT]; + struct bt_vocs *vocs[CONFIG_BT_VCP_VOL_CTLR_MAX_VOCS_INST]; uint8_t aics_inst_cnt; - struct bt_aics *aics[CONFIG_BT_AICS_CLIENT_MAX_INSTANCE_COUNT]; + struct bt_aics *aics[CONFIG_BT_VCP_VOL_CTLR_MAX_AICS_INST]; }; #endif /* ZEPHYR_INCLUDE_BLUETOOTH_AUDIO_VCP_INTERNAL_*/ From adb74f0f1606a33c86c1a00d4ed756a34d42cb54 Mon Sep 17 00:00:00 2001 From: Emil Gydesen Date: Thu, 21 Dec 2023 11:03:28 +0100 Subject: [PATCH 3486/3723] Bluetooth: MICP: Fix missing guards for AICS Some places MICP accessed AICS when it was not supported. Signed-off-by: Emil Gydesen --- subsys/bluetooth/audio/micp_internal.h | 2 ++ subsys/bluetooth/audio/micp_mic_ctlr.c | 44 ++++++++++++++++---------- 2 files changed, 30 insertions(+), 16 deletions(-) diff --git a/subsys/bluetooth/audio/micp_internal.h b/subsys/bluetooth/audio/micp_internal.h index 507e7547c75..ce486bf6fe6 100644 --- a/subsys/bluetooth/audio/micp_internal.h +++ b/subsys/bluetooth/audio/micp_internal.h @@ -29,8 +29,10 @@ struct bt_micp_mic_ctlr { struct bt_gatt_discover_params discover_params; struct bt_conn *conn; +#if defined(CONFIG_BT_MICP_MIC_CTLR_AICS) uint8_t aics_inst_cnt; struct bt_aics *aics[CONFIG_BT_MICP_MIC_CTLR_MAX_AICS_INST]; +#endif /* CONFIG_BT_MICP_MIC_CTLR_AICS */ }; #endif /* ZEPHYR_INCLUDE_BLUETOOTH_AUDIO_MICP_INTERNAL_ */ diff --git a/subsys/bluetooth/audio/micp_mic_ctlr.c b/subsys/bluetooth/audio/micp_mic_ctlr.c index 8232d664dce..45190b7c9b4 100644 --- a/subsys/bluetooth/audio/micp_mic_ctlr.c +++ b/subsys/bluetooth/audio/micp_mic_ctlr.c @@ -72,7 +72,15 @@ static void micp_mic_ctlr_discover_complete(struct bt_micp_mic_ctlr *mic_ctlr, i SYS_SLIST_FOR_EACH_CONTAINER_SAFE(&micp_mic_ctlr_cbs, listener, next, _node) { if (listener->discover) { - listener->discover(mic_ctlr, err, err == 0 ? mic_ctlr->aics_inst_cnt : 0U); + uint8_t aics_cnt = 0U; + +#if defined(CONFIG_BT_MICP_MIC_CTLR_AICS) + if (err == 0) { + aics_cnt = mic_ctlr->aics_inst_cnt; + } +#endif /* CONFIG_BT_MICP_MIC_CTLR_AICS */ + + listener->discover(mic_ctlr, err, aics_cnt); } } } @@ -298,7 +306,6 @@ static void micp_mic_ctlr_aics_set_auto_mode_cb(struct bt_aics *inst, int err) } } } -#endif /* CONFIG_BT_MICP_MIC_CTLR_AICS */ static uint8_t micp_discover_include_func( struct bt_conn *conn, const struct bt_gatt_attr *attr, @@ -350,6 +357,7 @@ static uint8_t micp_discover_include_func( return BT_GATT_ITER_CONTINUE; } +#endif /* CONFIG_BT_MICP_MIC_CTLR_AICS */ /** * @brief This will discover all characteristics on the server, retrieving the @@ -367,22 +375,22 @@ static uint8_t micp_discover_func(struct bt_conn *conn, LOG_DBG("Discovery complete"); (void)memset(params, 0, sizeof(*params)); - if (CONFIG_BT_MICP_MIC_CTLR_MAX_AICS_INST > 0) { - /* Discover included services */ - mic_ctlr->discover_params.start_handle = mic_ctlr->start_handle; - mic_ctlr->discover_params.end_handle = mic_ctlr->end_handle; - mic_ctlr->discover_params.type = BT_GATT_DISCOVER_INCLUDE; - mic_ctlr->discover_params.func = micp_discover_include_func; - - err = bt_gatt_discover(conn, - &mic_ctlr->discover_params); - if (err != 0) { - LOG_DBG("Discover AICS failed (err %d)", err); - micp_mic_ctlr_discover_complete(mic_ctlr, err); - } - } else { + +#if defined(CONFIG_BT_MICP_MIC_CTLR_AICS) + /* Discover included services */ + mic_ctlr->discover_params.start_handle = mic_ctlr->start_handle; + mic_ctlr->discover_params.end_handle = mic_ctlr->end_handle; + mic_ctlr->discover_params.type = BT_GATT_DISCOVER_INCLUDE; + mic_ctlr->discover_params.func = micp_discover_include_func; + + err = bt_gatt_discover(conn, &mic_ctlr->discover_params); + if (err != 0) { + LOG_DBG("Discover AICS failed (err %d)", err); micp_mic_ctlr_discover_complete(mic_ctlr, err); } +#else + micp_mic_ctlr_discover_complete(mic_ctlr, err); +#endif /* CONFIG_BT_MICP_MIC_CTLR_AICS */ return BT_GATT_ITER_STOP; } @@ -476,7 +484,9 @@ static void micp_mic_ctlr_reset(struct bt_micp_mic_ctlr *mic_ctlr) mic_ctlr->start_handle = 0; mic_ctlr->end_handle = 0; mic_ctlr->mute_handle = 0; +#if defined(CONFIG_BT_MICP_MIC_CTLR_AICS) mic_ctlr->aics_inst_cnt = 0; +#endif /* CONFIG_BT_MICP_MIC_CTLR_AICS */ if (mic_ctlr->conn != NULL) { struct bt_conn *conn = mic_ctlr->conn; @@ -594,6 +604,7 @@ int bt_micp_mic_ctlr_cb_register(struct bt_micp_mic_ctlr_cb *cb) return 0; } +#if defined(CONFIG_BT_MICP_MIC_CTLR_AICS) int bt_micp_mic_ctlr_included_get(struct bt_micp_mic_ctlr *mic_ctlr, struct bt_micp_included *included) { @@ -611,6 +622,7 @@ int bt_micp_mic_ctlr_included_get(struct bt_micp_mic_ctlr *mic_ctlr, return 0; } +#endif /* CONFIG_BT_MICP_MIC_CTLR_AICS */ struct bt_micp_mic_ctlr *bt_micp_mic_ctlr_get_by_conn(const struct bt_conn *conn) { From 68ed2e019fe88e0b72bc0f7d7f6687871e1ef27e Mon Sep 17 00:00:00 2001 From: Emil Gydesen Date: Thu, 21 Dec 2023 11:25:07 +0100 Subject: [PATCH 3487/3723] Bluetooth: VCP: Fix missing guards for AICS and VOCS Some places VCP accessed AICS and VOCS when it was not supported. Also modify existing guards to be consistent with new guards. Signed-off-by: Emil Gydesen --- include/zephyr/bluetooth/audio/vcp.h | 3 ++ subsys/bluetooth/audio/vcp_internal.h | 4 ++ subsys/bluetooth/audio/vcp_vol_ctlr.c | 60 +++++++++++++++++++++------ 3 files changed, 55 insertions(+), 12 deletions(-) diff --git a/include/zephyr/bluetooth/audio/vcp.h b/include/zephyr/bluetooth/audio/vcp.h index a902ceaed4d..15d91fae330 100644 --- a/include/zephyr/bluetooth/audio/vcp.h +++ b/include/zephyr/bluetooth/audio/vcp.h @@ -435,6 +435,9 @@ int bt_vcp_vol_ctlr_conn_get(const struct bt_vcp_vol_ctlr *vol_ctlr, * Volume Offset Control Service (Volume Offset Control Service) or * Audio Input Control Service (AICS) instances. * + * Requires that @kconfig{CONFIG_BT_VCP_VOL_CTLR_VOCS} or @kconfig{CONFIG_BT_VCP_VOL_CTLR_AICS} is + * enabled. + * * @param vol_ctlr Volume Controller instance pointer. * @param[out] included Pointer to store the result in. * diff --git a/subsys/bluetooth/audio/vcp_internal.h b/subsys/bluetooth/audio/vcp_internal.h index 73cbe3a8e69..26d9f5d2ca7 100644 --- a/subsys/bluetooth/audio/vcp_internal.h +++ b/subsys/bluetooth/audio/vcp_internal.h @@ -59,10 +59,14 @@ struct bt_vcp_vol_ctlr { struct bt_uuid_16 uuid; struct bt_conn *conn; +#if defined(CONFIG_BT_VCP_VOL_CTLR_VOCS) uint8_t vocs_inst_cnt; struct bt_vocs *vocs[CONFIG_BT_VCP_VOL_CTLR_MAX_VOCS_INST]; +#endif /* CONFIG_BT_VCP_VOL_CTLR_VOCS */ +#if defined(CONFIG_BT_VCP_VOL_CTLR_AICS) uint8_t aics_inst_cnt; struct bt_aics *aics[CONFIG_BT_VCP_VOL_CTLR_MAX_AICS_INST]; +#endif /* CONFIG_BT_VCP_VOL_CTLR_AICS */ }; #endif /* ZEPHYR_INCLUDE_BLUETOOTH_AUDIO_VCP_INTERNAL_*/ diff --git a/subsys/bluetooth/audio/vcp_vol_ctlr.c b/subsys/bluetooth/audio/vcp_vol_ctlr.c index d0f9075dafe..56082740894 100644 --- a/subsys/bluetooth/audio/vcp_vol_ctlr.c +++ b/subsys/bluetooth/audio/vcp_vol_ctlr.c @@ -68,8 +68,21 @@ static void vcp_vol_ctlr_discover_complete(struct bt_vcp_vol_ctlr *vol_ctlr, int SYS_SLIST_FOR_EACH_CONTAINER_SAFE(&vcp_vol_ctlr_cbs, listener, next, _node) { if (listener->discover) { - listener->discover(vol_ctlr, err, err == 0 ? vol_ctlr->vocs_inst_cnt : 0, - err == 0 ? vol_ctlr->aics_inst_cnt : 0); + uint8_t vocs_cnt = 0U; + uint8_t aics_cnt = 0U; + +#if defined(CONFIG_BT_VCP_VOL_CTLR_VOCS) + if (err == 0) { + vocs_cnt = vol_ctlr->vocs_inst_cnt; + } +#endif /* CONFIG_BT_VCP_VOL_CTLR_VOCS */ +#if defined(CONFIG_BT_VCP_VOL_CTLR_AICS) + if (err == 0) { + aics_cnt = vol_ctlr->aics_inst_cnt; + } +#endif /* CONFIG_BT_VCP_VOL_CTLR_VOCS */ + + listener->discover(vol_ctlr, err, vocs_cnt, aics_cnt); } } } @@ -303,7 +316,7 @@ static void vcp_vol_ctlr_write_vcs_cp_cb(struct bt_conn *conn, uint8_t err, vcs_cp_notify_app(vol_ctlr, opcode, err); } -#if (CONFIG_BT_VCP_VOL_CTLR_MAX_AICS_INST > 0 || CONFIG_BT_VCP_VOL_CTLR_MAX_VOCS_INST > 0) +#if defined(CONFIG_BT_VCP_VOL_CTLR_VOCS) || defined(CONFIG_BT_VCP_VOL_CTLR_AICS) static uint8_t vcs_discover_include_func(struct bt_conn *conn, const struct bt_gatt_attr *attr, struct bt_gatt_discover_params *params) @@ -314,8 +327,19 @@ static uint8_t vcs_discover_include_func(struct bt_conn *conn, struct bt_vcp_vol_ctlr *vol_ctlr = vol_ctlr_get_by_conn(conn); if (attr == NULL) { - LOG_DBG("Discover include complete for vol_ctlr: %u AICS and %u VOCS", - vol_ctlr->aics_inst_cnt, vol_ctlr->vocs_inst_cnt); + uint8_t vocs_cnt = 0U; + uint8_t aics_cnt = 0U; + +#if defined(CONFIG_BT_VCP_VOL_CTLR_VOCS) + vocs_cnt = vol_ctlr->vocs_inst_cnt; +#endif /* CONFIG_BT_VCP_VOL_CTLR_VOCS */ + +#if defined(CONFIG_BT_VCP_VOL_CTLR_AICS) + aics_cnt = vol_ctlr->aics_inst_cnt; +#endif /* CONFIG_BT_VCP_VOL_CTLR_VOCS */ + + LOG_DBG("Discover include complete for vol_ctlr: %u AICS and %u VOCS", aics_cnt, + vocs_cnt); (void)memset(params, 0, sizeof(*params)); vcp_vol_ctlr_discover_complete(vol_ctlr, 0); @@ -331,7 +355,7 @@ static uint8_t vcs_discover_include_func(struct bt_conn *conn, include = (struct bt_gatt_include *)attr->user_data; LOG_DBG("Include UUID %s", bt_uuid_str(include->uuid)); -#if CONFIG_BT_VCP_VOL_CTLR_MAX_AICS_INST > 0 +#if defined(CONFIG_BT_VCP_VOL_CTLR_AICS) if (bt_uuid_cmp(include->uuid, BT_UUID_AICS) == 0 && vol_ctlr->aics_inst_cnt < CONFIG_BT_VCP_VOL_CTLR_MAX_AICS_INST) { struct bt_aics_discover_param param = { @@ -355,8 +379,8 @@ static uint8_t vcs_discover_include_func(struct bt_conn *conn, return BT_GATT_ITER_STOP; } -#endif /* CONFIG_BT_VCP_VOL_CTLR_MAX_AICS_INST */ -#if CONFIG_BT_VCP_VOL_CTLR_MAX_VOCS_INST > 0 +#endif /* CONFIG_BT_VCP_VOL_CTLR_AICS */ +#if defined(CONFIG_BT_VCP_VOL_CTLR_VOCS) if (bt_uuid_cmp(include->uuid, BT_UUID_VOCS) == 0 && vol_ctlr->vocs_inst_cnt < CONFIG_BT_VCP_VOL_CTLR_MAX_VOCS_INST) { struct bt_vocs_discover_param param = { @@ -380,12 +404,12 @@ static uint8_t vcs_discover_include_func(struct bt_conn *conn, return BT_GATT_ITER_STOP; } -#endif /* CONFIG_BT_VCP_VOL_CTLR_MAX_VOCS_INST */ +#endif /* CONFIG_BT_VCP_VOL_CTLR_VOCS */ } return BT_GATT_ITER_CONTINUE; } -#endif /* (CONFIG_BT_VCP_VOL_CTLR_MAX_AICS_INST > 0 || CONFIG_BT_VCP_VOL_CTLR_MAX_VOCS_INST > 0) */ +#endif /* CONFIG_BT_VCP_VOL_CTLR_VOCS || CONFIG_BT_VCP_VOL_CTLR_AICS */ /** * @brief This will discover all characteristics on the server, retrieving the @@ -404,7 +428,7 @@ static uint8_t vcs_discover_func(struct bt_conn *conn, if (attr == NULL) { LOG_DBG("Setup complete for vol_ctlr"); (void)memset(params, 0, sizeof(*params)); -#if (CONFIG_BT_VCP_VOL_CTLR_MAX_AICS_INST > 0 || CONFIG_BT_VCP_VOL_CTLR_MAX_VOCS_INST > 0) +#if defined(CONFIG_BT_VCP_VOL_CTLR_VOCS) || defined(CONFIG_BT_VCP_VOL_CTLR_AICS) /* Discover included services */ vol_ctlr->discover_params.start_handle = vol_ctlr->start_handle; vol_ctlr->discover_params.end_handle = vol_ctlr->end_handle; @@ -418,7 +442,7 @@ static uint8_t vcs_discover_func(struct bt_conn *conn, } #else vcp_vol_ctlr_discover_complete(vol_ctlr, err); -#endif /* (CONFIG_BT_VCP_VOL_CTLR_MAX_AICS_INST > 0 || CONFIG_BT_VCP_VOL_CTLR_MAX_VOCS_INST > 0) */ +#endif /* CONFIG_BT_VCP_VOL_CTLR_VOCS || CONFIG_BT_VCP_VOL_CTLR_AICS */ return BT_GATT_ITER_STOP; } @@ -811,8 +835,12 @@ static void vcp_vol_ctlr_reset(struct bt_vcp_vol_ctlr *vol_ctlr) vol_ctlr->state_handle = 0; vol_ctlr->control_handle = 0; vol_ctlr->flag_handle = 0; +#if defined(CONFIG_BT_VCP_VOL_CTLR_VOCS) vol_ctlr->vocs_inst_cnt = 0; +#endif /* CONFIG_BT_VCP_VOL_CTLR_VOCS */ +#if defined(CONFIG_BT_VCP_VOL_CTLR_AICS) vol_ctlr->aics_inst_cnt = 0; +#endif /* CONFIG_BT_VCP_VOL_CTLR_AICS */ memset(&vol_ctlr->discover_params, 0, sizeof(vol_ctlr->discover_params)); @@ -976,6 +1004,7 @@ int bt_vcp_vol_ctlr_cb_unregister(struct bt_vcp_vol_ctlr_cb *cb) return 0; } +#if defined(CONFIG_BT_VCP_VOL_CTLR_VOCS) || defined(CONFIG_BT_VCP_VOL_CTLR_AICS) int bt_vcp_vol_ctlr_included_get(struct bt_vcp_vol_ctlr *vol_ctlr, struct bt_vcp_included *included) { @@ -983,14 +1012,21 @@ int bt_vcp_vol_ctlr_included_get(struct bt_vcp_vol_ctlr *vol_ctlr, return -EINVAL; } + memset(included, 0, sizeof(*included)); + +#if defined(CONFIG_BT_VCP_VOL_CTLR_VOCS) included->vocs_cnt = vol_ctlr->vocs_inst_cnt; included->vocs = vol_ctlr->vocs; +#endif /* CONFIG_BT_VCP_VOL_CTLR_VOCS */ +#if defined(CONFIG_BT_VCP_VOL_CTLR_AICS) included->aics_cnt = vol_ctlr->aics_inst_cnt; included->aics = vol_ctlr->aics; +#endif /* CONFIG_BT_VCP_VOL_CTLR_AICS */ return 0; } +#endif /* CONFIG_BT_VCP_VOL_CTLR_VOCS || CONFIG_BT_VCP_VOL_CTLR_AICS*/ struct bt_vcp_vol_ctlr *bt_vcp_vol_ctlr_get_by_conn(const struct bt_conn *conn) { From 277d649bdaed1da651f21f22ef9e101612b2a344 Mon Sep 17 00:00:00 2001 From: Armando Visconti Date: Thu, 1 Feb 2024 12:02:27 +0100 Subject: [PATCH 3488/3723] drivers: sensor: tmp108: fix coverity integer handling issue Fix coverity integer handling issue (CWE-188). Modifying a variable through a pointer of an incompatible type (other than unsigned char) can lead to unpredictable results. Fix: #67965 Coverity-CID: 248434 Signed-off-by: Armando Visconti --- drivers/sensor/tmp108/tmp108.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/drivers/sensor/tmp108/tmp108.c b/drivers/sensor/tmp108/tmp108.c index 13480ff7aef..79f31a305ab 100644 --- a/drivers/sensor/tmp108/tmp108.c +++ b/drivers/sensor/tmp108/tmp108.c @@ -165,6 +165,7 @@ static int tmp108_attr_get(const struct device *dev, struct sensor_value *val) { int result; + uint16_t tmp_val; if (chan != SENSOR_CHAN_AMBIENT_TEMP && chan != SENSOR_CHAN_ALL) { return -ENOTSUP; @@ -174,7 +175,9 @@ static int tmp108_attr_get(const struct device *dev, case SENSOR_ATTR_CONFIGURATION: result = tmp108_reg_read(dev, TI_TMP108_REG_CONF, - (uint16_t *) &(val->val1)); + &tmp_val); + val->val1 = tmp_val; + val->val2 = 0; break; default: return -ENOTSUP; From 5903c7a669f274e4a99422b241cbe4233a27daa0 Mon Sep 17 00:00:00 2001 From: Gerson Fernando Budke Date: Thu, 30 Nov 2023 12:46:02 +0200 Subject: [PATCH 3489/3723] drivers: watchdog: sam0: initialize GCLK2 in wdt_sam0_init Initialize GCLK2 to output 1.024kHz required by watchdog timer. Co-authored-by: Vlad Laba7 Signed-off-by: Gerson Fernando Budke --- soc/arm/atmel_sam0/common/soc_samd2x.c | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+) diff --git a/soc/arm/atmel_sam0/common/soc_samd2x.c b/soc/arm/atmel_sam0/common/soc_samd2x.c index b15108ead8c..6f86ac1a8a7 100644 --- a/soc/arm/atmel_sam0/common/soc_samd2x.c +++ b/soc/arm/atmel_sam0/common/soc_samd2x.c @@ -259,6 +259,24 @@ static inline void gclk_adc_configure(void) } #endif +#if !CONFIG_WDT_SAM0 +#define gclk_wdt_configure() +#else +static inline void gclk_wdt_configure(void) +{ + GCLK->GENDIV.reg = GCLK_GENDIV_ID(2) + | GCLK_GENDIV_DIV(4); + + GCLK->GENCTRL.reg = GCLK_GENCTRL_ID(2) + | GCLK_GENCTRL_GENEN + | GCLK_GENCTRL_SRC_OSCULP32K + | GCLK_GENCTRL_DIVSEL; + + while (GCLK->STATUS.bit.SYNCBUSY) { + } +} +#endif + #if CONFIG_SOC_ATMEL_SAMD_OSC8M || CONFIG_SOC_ATMEL_SAMD_DEFAULT_AS_MAIN #define osc8m_disable() #else @@ -278,5 +296,6 @@ void z_arm_platform_init(void) flash_waitstates_init(); gclk_main_configure(); gclk_adc_configure(); + gclk_wdt_configure(); osc8m_disable(); } From e5d14c682136832652c74b2c054c91e203b04950 Mon Sep 17 00:00:00 2001 From: Grzegorz Swiderski Date: Fri, 2 Feb 2024 10:57:12 +0100 Subject: [PATCH 3490/3723] riscv: linker: Fallback to Kconfig when defining ROM region With `CONFIG_XIP=y`, this linker script would derive the ROM region from the chosen `zephyr,flash` DT node with "soc-nv-flash" or "jedec,spi-nor" as its compatible. If the node was absent or had a different compatible, then linking would fail with: undefined symbol `ROM_BASE' referenced in expression Fix this by using `CONFIG_FLASH_BASE_ADDRESS` and `CONFIG_FLASH_SIZE` for ROM base and size respectively. The existing DT logic is preserved for compatibility with out-of-tree boards, so the flash Kconfigs serve as a mere fallback. In addition, use `CONFIG_FLASH_LOAD_OFFSET` and `CONFIG_FLASH_LOAD_SIZE` if defined, to align with some other architectures' linker scripts. For the existing in-tree RISC-V boards, this should not make a difference. The alternative would've been making sure that all boards and SoCs have the relevant Kconfigs set, and only using those in the linker script. The downside is that `CONFIG_FLASH_SIZE` is given in units of 1 KiB, while some existing boards - hifive1_revb, sparkfun_red_v_things_plus - have more granular flash sizes, which would've been rounded down. Signed-off-by: Grzegorz Swiderski --- include/zephyr/arch/riscv/common/linker.ld | 33 +++++++++++++++++----- 1 file changed, 26 insertions(+), 7 deletions(-) diff --git a/include/zephyr/arch/riscv/common/linker.ld b/include/zephyr/arch/riscv/common/linker.ld index 8c3dee305f9..a9bfa7a42ee 100644 --- a/include/zephyr/arch/riscv/common/linker.ld +++ b/include/zephyr/arch/riscv/common/linker.ld @@ -35,24 +35,43 @@ #define ROM_END_OFFSET 0 #endif +#if defined(CONFIG_FLASH_LOAD_OFFSET) +#define FLASH_LOAD_OFFSET CONFIG_FLASH_LOAD_OFFSET +#else +#define FLASH_LOAD_OFFSET 0 +#endif + #ifdef CONFIG_XIP + +#if CONFIG_FLASH_LOAD_SIZE > 0 +#define ROM_SIZE (CONFIG_FLASH_LOAD_SIZE - ROM_END_OFFSET) +#endif + #if DT_NODE_HAS_COMPAT_STATUS(DT_CHOSEN(zephyr_flash), soc_nv_flash, okay) -#ifdef CONFIG_FLASH_LOAD_OFFSET -#define ROM_BASE (DT_REG_ADDR(DT_CHOSEN(zephyr_flash)) + \ - CONFIG_FLASH_LOAD_OFFSET) -#else /* !CONFIG_FLASH_LOAD_OFFSET */ -#define ROM_BASE DT_REG_ADDR(DT_CHOSEN(zephyr_flash)) -#endif /* CONFIG_FLASH_LOAD_OFFSET */ +#define ROM_BASE (DT_REG_ADDR(DT_CHOSEN(zephyr_flash)) + FLASH_LOAD_OFFSET) +#ifndef ROM_SIZE #define ROM_SIZE (DT_REG_SIZE(DT_CHOSEN(zephyr_flash)) - ROM_END_OFFSET) +#endif + #elif DT_NODE_HAS_COMPAT(DT_CHOSEN(zephyr_flash), jedec_spi_nor) /* For jedec,spi-nor we expect the spi controller to memory map the flash * and for that mapping to be the second register property of the spi * controller. */ #define SPI_CTRL DT_PARENT(DT_CHOSEN(zephyr_flash)) -#define ROM_BASE DT_REG_ADDR_BY_IDX(SPI_CTRL, 1) +#define ROM_BASE (DT_REG_ADDR_BY_IDX(SPI_CTRL, 1) + FLASH_LOAD_OFFSET) +#ifndef ROM_SIZE #define ROM_SIZE (DT_REG_SIZE_BY_IDX(SPI_CTRL, 1) - ROM_END_OFFSET) #endif + +#else /* Use Kconfig to cover the remaining cases */ +#define ROM_BASE (CONFIG_FLASH_BASE_ADDRESS + FLASH_LOAD_OFFSET) +#ifndef ROM_SIZE +#define ROM_SIZE (CONFIG_FLASH_SIZE * 1024 - FLASH_LOAD_OFFSET - ROM_END_OFFSET) +#endif + +#endif /* DT_NODE_HAS_COMPAT_STATUS */ + #else /* CONFIG_XIP */ #define ROM_BASE CONFIG_SRAM_BASE_ADDRESS #define ROM_SIZE (KB(CONFIG_SRAM_SIZE) - ROM_END_OFFSET) From 415cb65e3f486a498bc49830467f6993106dadde Mon Sep 17 00:00:00 2001 From: Joel Guittet Date: Mon, 8 Jan 2024 13:40:44 +0100 Subject: [PATCH 3491/3723] drivers: input: cst816s: add alternative chip id The CST816S chip ID have an alternative value. It seems that this field represents in fact a version number of controller. Fix by adding the new chip ID. Signed-off-by: Joel Guittet --- drivers/input/input_cst816s.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/drivers/input/input_cst816s.c b/drivers/input/input_cst816s.c index 9409deb045a..6c17af3aca9 100644 --- a/drivers/input/input_cst816s.c +++ b/drivers/input/input_cst816s.c @@ -14,7 +14,8 @@ LOG_MODULE_REGISTER(cst816s, CONFIG_INPUT_LOG_LEVEL); -#define CST816S_CHIP_ID 0xB4 +#define CST816S_CHIP_ID1 0xB4 +#define CST816S_CHIP_ID2 0xB5 #define CST816S_REG_DATA 0x00 #define CST816S_REG_GESTURE_ID 0x01 @@ -202,7 +203,7 @@ static int cst816s_chip_init(const struct device *dev) return ret; } - if (chip_id != CST816S_CHIP_ID) { + if ((chip_id != CST816S_CHIP_ID1) && (chip_id != CST816S_CHIP_ID2)) { LOG_ERR("CST816S wrong chip id: returned 0x%x", chip_id); return -ENODEV; } From 00d4661273fea5d1dddafd3a6957540c76ce0fcf Mon Sep 17 00:00:00 2001 From: Kai Vehmanen Date: Thu, 1 Feb 2024 14:53:15 +0200 Subject: [PATCH 3492/3723] drivers: dma: intel-adsp-hda: modify stop dma logic Commit b2eaa6448076 ("drivers: dma: intel-adsp-hda: add delay to stop host dma") added a wait on GBUSY state to host DMA stop. This is problematic as in some case (like SOF chain-DMA usage), the host DMA side RUN bit is not cleared when intel_adsp_hda_dma_stop() is called. It is not possible to wait on GBUSY bit as there are valid cases where it can remain set. Address the original problem described in SOF bug #8686 and add a polling check for intel_adsp_hda_is_enabled(). As per the bug description, in some cases the GEN/FIFORDY bits are not cleared immediately and if a new call to intel_adsp_hda_dma_stop() is made, the PM refcounting will go haywire. Link: https://github.com/thesofproject/sof/issues/8686 Signed-off-by: Kai Vehmanen --- drivers/dma/dma_intel_adsp_hda.c | 9 +++------ 1 file changed, 3 insertions(+), 6 deletions(-) diff --git a/drivers/dma/dma_intel_adsp_hda.c b/drivers/dma/dma_intel_adsp_hda.c index 7717013fddc..fe86b8ca61f 100644 --- a/drivers/dma/dma_intel_adsp_hda.c +++ b/drivers/dma/dma_intel_adsp_hda.c @@ -326,12 +326,9 @@ int intel_adsp_hda_dma_stop(const struct device *dev, uint32_t channel) intel_adsp_hda_disable(cfg->base, cfg->regblock_size, channel); - /* host dma needs some cycles to completely stop */ - if (cfg->direction == HOST_TO_MEMORY || cfg->direction == MEMORY_TO_HOST) { - if (!WAIT_FOR(!(*DGCS(cfg->base, cfg->regblock_size, channel) & DGCS_GBUSY), 1000, - k_busy_wait(1))) { - return -EBUSY; - } + if (!WAIT_FOR(!intel_adsp_hda_is_enabled(cfg->base, cfg->regblock_size, channel), 1000, + k_busy_wait(1))) { + return -EBUSY; } return pm_device_runtime_put(dev); From 5f31c15b1ddab8ce344de63e4f230f8bd741bdfd Mon Sep 17 00:00:00 2001 From: Dominik Ermel Date: Tue, 9 Jan 2024 14:29:29 +0000 Subject: [PATCH 3493/3723] tests/settings/file: increase main stack size Increase ZTEST and MAIN stack to 4k. Fixes #57324 Signed-off-by: Dominik Ermel --- tests/subsys/settings/file/prj.conf | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/tests/subsys/settings/file/prj.conf b/tests/subsys/settings/file/prj.conf index 07e79b3233e..9a61b45661d 100644 --- a/tests/subsys/settings/file/prj.conf +++ b/tests/subsys/settings/file/prj.conf @@ -6,8 +6,8 @@ CONFIG_FLASH=y CONFIG_FLASH_PAGE_LAYOUT=y CONFIG_FLASH_MAP=y -CONFIG_ZTEST_STACK_SIZE=2048 -CONFIG_MAIN_STACK_SIZE=2048 +CONFIG_ZTEST_STACK_SIZE=4096 +CONFIG_MAIN_STACK_SIZE=4096 CONFIG_HEAP_MEM_POOL_SIZE=1024 CONFIG_FILE_SYSTEM=y From 75d2bb3c3e1b258423dccd3db3e7f0830815eba3 Mon Sep 17 00:00:00 2001 From: Robert Lubos Date: Tue, 6 Feb 2024 11:06:58 +0100 Subject: [PATCH 3494/3723] Revert "[nrf fromtree] net: openthread: upmerge to `7761b81`" This reverts commit b3c97b010983e5523d90f9140b8e657b06a2ea3f. Signed-off-by: Robert Lubos --- drivers/ieee802154/ieee802154_nrf5.c | 6 ------ include/zephyr/net/ieee802154_radio.h | 9 --------- modules/openthread/platform/radio.c | 16 ---------------- west.yml | 2 +- 4 files changed, 1 insertion(+), 32 deletions(-) diff --git a/drivers/ieee802154/ieee802154_nrf5.c b/drivers/ieee802154/ieee802154_nrf5.c index 553d71188e9..16eb2cb0022 100644 --- a/drivers/ieee802154/ieee802154_nrf5.c +++ b/drivers/ieee802154/ieee802154_nrf5.c @@ -901,12 +901,6 @@ static int nrf5_configure(const struct device *dev, uint8_t element_id; bool valid_vendor_specific_ie = false; - if (config->ack_ie.purge_ie) { - nrf_802154_ack_data_remove_all(false, NRF_802154_ACK_DATA_IE); - nrf_802154_ack_data_remove_all(true, NRF_802154_ACK_DATA_IE); - break; - } - if (config->ack_ie.short_addr == IEEE802154_BROADCAST_ADDRESS || config->ack_ie.ext_addr == NULL) { return -ENOTSUP; diff --git a/include/zephyr/net/ieee802154_radio.h b/include/zephyr/net/ieee802154_radio.h index 259d67b4321..de0cf89da4c 100644 --- a/include/zephyr/net/ieee802154_radio.h +++ b/include/zephyr/net/ieee802154_radio.h @@ -1241,15 +1241,6 @@ struct ieee802154_config { * in CPU byte order */ uint16_t short_addr; - - /** - * Flag for purging enh ACK header IEs. - * When flag is set to true, driver should remove all existing - * header IEs, and all other entries in config should be ignored. - * This means that purging current header IEs and - * configuring a new one in the same call is not allowed. - */ - bool purge_ie; } ack_ie; }; }; diff --git a/modules/openthread/platform/radio.c b/modules/openthread/platform/radio.c index d405539bcc0..c0df98367af 100644 --- a/modules/openthread/platform/radio.c +++ b/modules/openthread/platform/radio.c @@ -1294,22 +1294,6 @@ otError otPlatRadioEnableCsl(otInstance *aInstance, uint32_t aCslPeriod, otShort return result ? OT_ERROR_FAILED : OT_ERROR_NONE; } -otError otPlatRadioResetCsl(otInstance *aInstance) -{ - struct ieee802154_config config = { 0 }; - int result; - - result = radio_api->configure(radio_dev, IEEE802154_CONFIG_CSL_PERIOD, &config); - if (result) { - return OT_ERROR_FAILED; - } - - config.ack_ie.purge_ie = true; - result = radio_api->configure(radio_dev, IEEE802154_CONFIG_ENH_ACK_HEADER_IE, &config); - - return result ? OT_ERROR_FAILED : OT_ERROR_NONE; -} - void otPlatRadioUpdateCslSampleTime(otInstance *aInstance, uint32_t aCslSampleTime) { ARG_UNUSED(aInstance); diff --git a/west.yml b/west.yml index ea8352aa7cf..2892d3db451 100644 --- a/west.yml +++ b/west.yml @@ -301,7 +301,7 @@ manifest: revision: 214f9fc1539f8e5937c0474cb6ee29b6dcb2d4b8 path: modules/lib/open-amp - name: openthread - revision: 7761b81d23b10b3d5ee21b8504c67535cde10896 + revision: 00076aff3ae571db7c90509ec9dc293457098c35 path: modules/lib/openthread - name: percepio path: modules/debug/percepio From a8766965af5c7618ae9960482ebfdfb5a9193c38 Mon Sep 17 00:00:00 2001 From: Robert Lubos Date: Tue, 6 Feb 2024 11:06:59 +0100 Subject: [PATCH 3495/3723] Revert "[nrf fromtree] drivers: ieee802154: fix handling of `struct ieee802154_config`" This reverts commit 93c590c3a81e738e59a95db384c58a8fbe73b762. Signed-off-by: Robert Lubos --- modules/openthread/platform/radio.c | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/modules/openthread/platform/radio.c b/modules/openthread/platform/radio.c index c0df98367af..a26c66d875d 100644 --- a/modules/openthread/platform/radio.c +++ b/modules/openthread/platform/radio.c @@ -1255,7 +1255,10 @@ void otPlatRadioSetMacFrameCounterIfLarger(otInstance *aInstance, uint32_t aMacF otError otPlatRadioEnableCsl(otInstance *aInstance, uint32_t aCslPeriod, otShortAddress aShortAddr, const otExtAddress *aExtAddr) { - struct ieee802154_config config = { 0 }; + struct ieee802154_config config = { + .ack_ie.short_addr = aShortAddr, + .ack_ie.ext_addr = aExtAddr->m8, + }; int result; ARG_UNUSED(aInstance); @@ -1268,8 +1271,6 @@ otError otPlatRadioEnableCsl(otInstance *aInstance, uint32_t aCslPeriod, otShort if (result) { return OT_ERROR_FAILED; } - config.ack_ie.short_addr = aShortAddr; - config.ack_ie.ext_addr = aExtAddr != NULL ? aExtAddr->m8 : NULL; /* Configure the CSL IE. */ if (aCslPeriod > 0) { From 7f15058d06a79da1c3e60ec6bf2a9e183d4c98b3 Mon Sep 17 00:00:00 2001 From: Robert Lubos Date: Tue, 6 Feb 2024 11:06:59 +0100 Subject: [PATCH 3496/3723] Revert "[nrf fromtree] drivers: ieee802154: fix ACK header IE implementation" This reverts commit 02e7e0f34df3ded888a736debf84573094d8af6c. Signed-off-by: Robert Lubos --- drivers/ieee802154/ieee802154_nrf5.c | 38 ++++++++++++++-------------- modules/openthread/platform/radio.c | 13 ++++++---- 2 files changed, 27 insertions(+), 24 deletions(-) diff --git a/drivers/ieee802154/ieee802154_nrf5.c b/drivers/ieee802154/ieee802154_nrf5.c index 16eb2cb0022..4f7c3f863a3 100644 --- a/drivers/ieee802154/ieee802154_nrf5.c +++ b/drivers/ieee802154/ieee802154_nrf5.c @@ -899,38 +899,35 @@ static int nrf5_configure(const struct device *dev, uint8_t ext_addr_le[EXTENDED_ADDRESS_SIZE]; uint8_t short_addr_le[SHORT_ADDRESS_SIZE]; uint8_t element_id; - bool valid_vendor_specific_ie = false; if (config->ack_ie.short_addr == IEEE802154_BROADCAST_ADDRESS || config->ack_ie.ext_addr == NULL) { return -ENOTSUP; } - sys_put_le16(config->ack_ie.short_addr, short_addr_le); - sys_memcpy_swap(ext_addr_le, config->ack_ie.ext_addr, EXTENDED_ADDRESS_SIZE); + element_id = ieee802154_header_ie_get_element_id(config->ack_ie.header_ie); - if (config->ack_ie.header_ie == NULL || config->ack_ie.header_ie->length == 0) { - nrf_802154_ack_data_clear(short_addr_le, false, NRF_802154_ACK_DATA_IE); - nrf_802154_ack_data_clear(ext_addr_le, true, NRF_802154_ACK_DATA_IE); - } else { - element_id = ieee802154_header_ie_get_element_id(config->ack_ie.header_ie); + if (element_id != IEEE802154_HEADER_IE_ELEMENT_ID_CSL_IE && + (!IS_ENABLED(CONFIG_NET_L2_OPENTHREAD) || + element_id != IEEE802154_HEADER_IE_ELEMENT_ID_VENDOR_SPECIFIC_IE)) { + return -ENOTSUP; + } #if defined(CONFIG_NET_L2_OPENTHREAD) - uint8_t vendor_oui_le[IEEE802154_OPENTHREAD_VENDOR_OUI_LEN] = - IEEE802154_OPENTHREAD_THREAD_IE_VENDOR_OUI; + uint8_t vendor_oui_le[IEEE802154_OPENTHREAD_VENDOR_OUI_LEN] = + IEEE802154_OPENTHREAD_THREAD_IE_VENDOR_OUI; - if (element_id == IEEE802154_HEADER_IE_ELEMENT_ID_VENDOR_SPECIFIC_IE && - memcmp(config->ack_ie.header_ie->content.vendor_specific.vendor_oui, - vendor_oui_le, sizeof(vendor_oui_le)) == 0) { - valid_vendor_specific_ie = true; - } + if (element_id == IEEE802154_HEADER_IE_ELEMENT_ID_VENDOR_SPECIFIC_IE && + memcmp(config->ack_ie.header_ie->content.vendor_specific.vendor_oui, + vendor_oui_le, sizeof(vendor_oui_le))) { + return -ENOTSUP; + } #endif - if (element_id != IEEE802154_HEADER_IE_ELEMENT_ID_CSL_IE && - !valid_vendor_specific_ie) { - return -ENOTSUP; - } + sys_put_le16(config->ack_ie.short_addr, short_addr_le); + sys_memcpy_swap(ext_addr_le, config->ack_ie.ext_addr, EXTENDED_ADDRESS_SIZE); + if (config->ack_ie.header_ie && config->ack_ie.header_ie->length > 0) { nrf_802154_ack_data_set(short_addr_le, false, config->ack_ie.header_ie, config->ack_ie.header_ie->length + IEEE802154_HEADER_IE_HEADER_LENGTH, @@ -939,6 +936,9 @@ static int nrf5_configure(const struct device *dev, config->ack_ie.header_ie->length + IEEE802154_HEADER_IE_HEADER_LENGTH, NRF_802154_ACK_DATA_IE); + } else { + nrf_802154_ack_data_clear(short_addr_le, false, NRF_802154_ACK_DATA_IE); + nrf_802154_ack_data_clear(ext_addr_le, true, NRF_802154_ACK_DATA_IE); } } break; diff --git a/modules/openthread/platform/radio.c b/modules/openthread/platform/radio.c index a26c66d875d..cec73e3ef6f 100644 --- a/modules/openthread/platform/radio.c +++ b/modules/openthread/platform/radio.c @@ -1348,7 +1348,7 @@ uint8_t otPlatRadioGetCslUncertainty(otInstance *aInstance) * | IE_VENDOR_THREAD_ACK_PROBING_ID | LINK_METRIC_TOKEN | LINK_METRIC_TOKEN| * |---------------------------------|-------------------|------------------| */ -static void set_vendor_ie_header_lm(bool lqi, bool link_margin, bool rssi, uint8_t *ie_header) +static uint8_t set_vendor_ie_header_lm(bool lqi, bool link_margin, bool rssi, uint8_t *ie_header) { /* Vendor-specific IE identifier */ const uint8_t ie_vendor_id = 0x00; @@ -1362,6 +1362,7 @@ static void set_vendor_ie_header_lm(bool lqi, bool link_margin, bool rssi, uint8 const uint8_t ie_vendor_thread_margin_token = 0x02; /* Thread Vendor-specific ACK Probing IE LQI value placeholder */ const uint8_t ie_vendor_thread_lqi_token = 0x03; + const uint8_t ie_header_size = 2; const uint8_t oui_size = 3; const uint8_t sub_type = 1; const uint8_t id_offset = 7; @@ -1379,8 +1380,7 @@ static void set_vendor_ie_header_lm(bool lqi, bool link_margin, bool rssi, uint8 __ASSERT(ie_header, "Invalid argument"); if (link_metrics_data_len == 0) { - ie_header[0] = 0; - return; + return 0; } /* Set Element ID */ @@ -1415,6 +1415,8 @@ static void set_vendor_ie_header_lm(bool lqi, bool link_margin, bool rssi, uint8 if (rssi) { ie_header[link_metrics_idx++] = ie_vendor_thread_rssi_token; } + + return ie_header_size + content_len; } otError otPlatRadioConfigureEnhAckProbing(otInstance *aInstance, otLinkMetrics aLinkMetrics, @@ -1426,12 +1428,13 @@ otError otPlatRadioConfigureEnhAckProbing(otInstance *aInstance, otLinkMetrics a .ack_ie.ext_addr = aExtAddress->m8, }; uint8_t header_ie_buf[OT_ACK_IE_MAX_SIZE]; + uint16_t header_ie_len; int result; ARG_UNUSED(aInstance); - set_vendor_ie_header_lm(aLinkMetrics.mLqi, aLinkMetrics.mLinkMargin, - aLinkMetrics.mRssi, header_ie_buf); + header_ie_len = set_vendor_ie_header_lm(aLinkMetrics.mLqi, aLinkMetrics.mLinkMargin, + aLinkMetrics.mRssi, header_ie_buf); config.ack_ie.header_ie = (struct ieee802154_header_ie *)header_ie_buf; result = radio_api->configure(radio_dev, IEEE802154_CONFIG_ENH_ACK_HEADER_IE, &config); From 60fa5462ed9f5566a0090b479a515a2a1061d85f Mon Sep 17 00:00:00 2001 From: Robert Lubos Date: Tue, 6 Feb 2024 11:06:59 +0100 Subject: [PATCH 3497/3723] Revert "Revert "[nrf noup] drivers: ieee802154: temporary fix for ACK header IE config"" This reverts commit 593e6c8e4b831082ac8e225fd2db4fd8f14a15af. Signed-off-by: Robert Lubos --- drivers/ieee802154/ieee802154_nrf5.c | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/drivers/ieee802154/ieee802154_nrf5.c b/drivers/ieee802154/ieee802154_nrf5.c index 4f7c3f863a3..b542c5007f8 100644 --- a/drivers/ieee802154/ieee802154_nrf5.c +++ b/drivers/ieee802154/ieee802154_nrf5.c @@ -900,6 +900,19 @@ static int nrf5_configure(const struct device *dev, uint8_t short_addr_le[SHORT_ADDRESS_SIZE]; uint8_t element_id; + if (config->ack_ie.ext_addr == NULL && + config->ack_ie.header_ie == NULL && + config->ack_ie.short_addr == IEEE802154_NO_SHORT_ADDRESS_ASSIGNED) { + /* Hotfix for case when `EnableCsl()` has been called with arguments: + * - `aCslPeriod` == 0 + * - `aShortAddr` == IEEE802154_NO_SHORT_ADDRESS_ASSIGNED + * - `aExtAddr` == NULL + * In this case skip configuring ACK header IE until proper resetting of + * configuration is implemented. + */ + break; + } + if (config->ack_ie.short_addr == IEEE802154_BROADCAST_ADDRESS || config->ack_ie.ext_addr == NULL) { return -ENOTSUP; From 847b8e6330acd8bbda6a7ba7b0bd6135939b6fae Mon Sep 17 00:00:00 2001 From: Robert Lubos Date: Tue, 6 Feb 2024 11:06:59 +0100 Subject: [PATCH 3498/3723] Revert "[nrf fromtree] net: wifi_shell: Remove TX-Injection and Promisc mode" This reverts commit f923004850f7ae85f2b02bf339edc69a4e9b0172. Signed-off-by: Robert Lubos --- subsys/net/l2/wifi/wifi_shell.c | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/subsys/net/l2/wifi/wifi_shell.c b/subsys/net/l2/wifi/wifi_shell.c index d70e48024b7..5a3d7e632a7 100644 --- a/subsys/net/l2/wifi/wifi_shell.c +++ b/subsys/net/l2/wifi/wifi_shell.c @@ -1539,6 +1539,8 @@ void parse_mode_args_to_params(const struct shell *sh, int argc, static struct option long_options[] = {{"if-index", optional_argument, 0, 'i'}, {"sta", no_argument, 0, 's'}, {"monitor", no_argument, 0, 'm'}, + {"tx-injection", no_argument, 0, 't'}, + {"promiscuous", no_argument, 0, 'p'}, {"ap", no_argument, 0, 'a'}, {"softap", no_argument, 0, 'k'}, {"get", no_argument, 0, 'g'}, @@ -1553,6 +1555,12 @@ void parse_mode_args_to_params(const struct shell *sh, int argc, case 'm': mode->mode |= WIFI_MONITOR_MODE; break; + case 't': + mode->mode |= WIFI_TX_INJECTION_MODE; + break; + case 'p': + mode->mode |= WIFI_PROMISCUOUS_MODE; + break; case 'a': mode->mode |= WIFI_AP_MODE; break; @@ -1954,6 +1962,8 @@ SHELL_STATIC_SUBCMD_SET_CREATE(wifi_commands, "[-i, --if-index ] : Interface index\n" "[-s, --sta] : Station mode\n" "[-m, --monitor] : Monitor mode\n" + "[-p, --promiscuous] : Promiscuous mode\n" + "[-t, --tx-injection] : TX-Injection mode\n" "[-a, --ap] : AP mode\n" "[-k, --softap] : Softap mode\n" "[-h, --help] : Help\n" From 41449eef6d50e939ed8abd8dbd81bfb7d645ec1c Mon Sep 17 00:00:00 2001 From: Robert Lubos Date: Tue, 6 Feb 2024 11:06:59 +0100 Subject: [PATCH 3499/3723] Revert "[nrf fromtree] net: l2: ethernet: bring in TX-Injection mode to l2 ethernet" This reverts commit f1f5d375838a07cf2c0d0669cec91a7133508d62. Signed-off-by: Robert Lubos --- include/zephyr/net/ethernet.h | 16 ---------------- include/zephyr/net/ethernet_mgmt.h | 13 ------------- subsys/net/l2/ethernet/ethernet.c | 14 -------------- subsys/net/l2/ethernet/ethernet_mgmt.c | 26 -------------------------- 4 files changed, 69 deletions(-) diff --git a/include/zephyr/net/ethernet.h b/include/zephyr/net/ethernet.h index faa6cf7fc0b..181503140a7 100644 --- a/include/zephyr/net/ethernet.h +++ b/include/zephyr/net/ethernet.h @@ -179,9 +179,6 @@ enum ethernet_hw_caps { /** TXTIME supported */ ETHERNET_TXTIME = BIT(19), - - /** TX-Injection supported */ - ETHERNET_TXINJECTION_MODE = BIT(20), }; /** @cond INTERNAL_HIDDEN */ @@ -200,7 +197,6 @@ enum ethernet_config_type { ETHERNET_CONFIG_TYPE_FILTER, ETHERNET_CONFIG_TYPE_PORTS_NUM, ETHERNET_CONFIG_TYPE_T1S_PARAM, - ETHERNET_CONFIG_TYPE_TXINJECTION_MODE, }; enum ethernet_qav_param_type { @@ -446,7 +442,6 @@ struct ethernet_config { bool auto_negotiation; bool full_duplex; bool promisc_mode; - bool txinjection_mode; struct { bool link_10bt; @@ -1034,17 +1029,6 @@ void net_eth_carrier_off(struct net_if *iface); */ int net_eth_promisc_mode(struct net_if *iface, bool enable); -/** - * @brief Set TX-Injection mode either ON or OFF. - * - * @param iface Network interface - * - * @param enable on (true) or off (false) - * - * @return 0 if mode set or unset was successful, <0 otherwise. - */ -int net_eth_txinjection_mode(struct net_if *iface, bool enable); - /** * @brief Return PTP clock that is tied to this ethernet network interface. * diff --git a/include/zephyr/net/ethernet_mgmt.h b/include/zephyr/net/ethernet_mgmt.h index 18039e9f3aa..32a38f2df88 100644 --- a/include/zephyr/net/ethernet_mgmt.h +++ b/include/zephyr/net/ethernet_mgmt.h @@ -52,8 +52,6 @@ enum net_request_ethernet_cmd { NET_REQUEST_ETHERNET_CMD_GET_QBU_PARAM, NET_REQUEST_ETHERNET_CMD_GET_TXTIME_PARAM, NET_REQUEST_ETHERNET_CMD_SET_T1S_PARAM, - NET_REQUEST_ETHERNET_CMD_SET_TXINJECTION_MODE, - NET_REQUEST_ETHERNET_CMD_GET_TXINJECTION_MODE, }; #define NET_REQUEST_ETHERNET_SET_AUTO_NEGOTIATION \ @@ -136,16 +134,6 @@ NET_MGMT_DEFINE_REQUEST_HANDLER(NET_REQUEST_ETHERNET_GET_TXTIME_PARAM); NET_MGMT_DEFINE_REQUEST_HANDLER(NET_REQUEST_ETHERNET_SET_T1S_PARAM); -#define NET_REQUEST_ETHERNET_SET_TXINJECTION_MODE \ - (_NET_ETHERNET_BASE | NET_REQUEST_ETHERNET_CMD_SET_TXINJECTION_MODE) - -NET_MGMT_DEFINE_REQUEST_HANDLER(NET_REQUEST_ETHERNET_SET_TXINJECTION_MODE); - -#define NET_REQUEST_ETHERNET_GET_TXINJECTION_MODE \ - (_NET_ETHERNET_BASE | NET_REQUEST_ETHERNET_CMD_GET_TXINJECTION_MODE) - -NET_MGMT_DEFINE_REQUEST_HANDLER(NET_REQUEST_ETHERNET_GET_TXINJECTION_MODE); - struct net_eth_addr; struct ethernet_qav_param; struct ethernet_qbv_param; @@ -157,7 +145,6 @@ struct ethernet_req_params { bool auto_negotiation; bool full_duplex; bool promisc_mode; - bool txinjection_mode; struct { bool link_10bt; diff --git a/subsys/net/l2/ethernet/ethernet.c b/subsys/net/l2/ethernet/ethernet.c index 8e73e8bcd43..2be3c5f2820 100644 --- a/subsys/net/l2/ethernet/ethernet.c +++ b/subsys/net/l2/ethernet/ethernet.c @@ -1197,20 +1197,6 @@ int net_eth_promisc_mode(struct net_if *iface, bool enable) } #endif/* CONFIG_NET_PROMISCUOUS_MODE */ -int net_eth_txinjection_mode(struct net_if *iface, bool enable) -{ - struct ethernet_req_params params; - - if (!(net_eth_get_hw_capabilities(iface) & ETHERNET_TXINJECTION_MODE)) { - return -ENOTSUP; - } - - params.txinjection_mode = enable; - - return net_mgmt(NET_REQUEST_ETHERNET_SET_TXINJECTION_MODE, iface, - ¶ms, sizeof(struct ethernet_req_params)); -} - void ethernet_init(struct net_if *iface) { struct ethernet_context *ctx = net_if_l2_data(iface); diff --git a/subsys/net/l2/ethernet/ethernet_mgmt.c b/subsys/net/l2/ethernet/ethernet_mgmt.c index 899aa7a9516..3e957e52c1e 100644 --- a/subsys/net/l2/ethernet/ethernet_mgmt.c +++ b/subsys/net/l2/ethernet/ethernet_mgmt.c @@ -200,13 +200,6 @@ static int ethernet_set_config(uint32_t mgmt_request, memcpy(&config.t1s_param, ¶ms->t1s_param, sizeof(struct ethernet_t1s_param)); type = ETHERNET_CONFIG_TYPE_T1S_PARAM; - } else if (mgmt_request == NET_REQUEST_ETHERNET_SET_TXINJECTION_MODE) { - if (!is_hw_caps_supported(dev, ETHERNET_TXINJECTION_MODE)) { - return -ENOTSUP; - } - - config.txinjection_mode = params->txinjection_mode; - type = ETHERNET_CONFIG_TYPE_TXINJECTION_MODE; } else { return -EINVAL; } @@ -244,9 +237,6 @@ NET_MGMT_REGISTER_REQUEST_HANDLER(NET_REQUEST_ETHERNET_SET_PROMISC_MODE, NET_MGMT_REGISTER_REQUEST_HANDLER(NET_REQUEST_ETHERNET_SET_T1S_PARAM, ethernet_set_config); -NET_MGMT_REGISTER_REQUEST_HANDLER(NET_REQUEST_ETHERNET_SET_TXINJECTION_MODE, - ethernet_set_config); - static int ethernet_get_config(uint32_t mgmt_request, struct net_if *iface, void *data, size_t len) @@ -440,19 +430,6 @@ static int ethernet_get_config(uint32_t mgmt_request, config.txtime_param.enable_txtime; break; } - } else if (mgmt_request == NET_REQUEST_ETHERNET_GET_TXINJECTION_MODE) { - if (!is_hw_caps_supported(dev, ETHERNET_TXINJECTION_MODE)) { - return -ENOTSUP; - } - - type = ETHERNET_CONFIG_TYPE_TXINJECTION_MODE; - - ret = api->get_config(dev, type, &config); - if (ret) { - return ret; - } - - params->txinjection_mode = config.txinjection_mode; } else { return -EINVAL; } @@ -478,9 +455,6 @@ NET_MGMT_REGISTER_REQUEST_HANDLER(NET_REQUEST_ETHERNET_GET_QBU_PARAM, NET_MGMT_REGISTER_REQUEST_HANDLER(NET_REQUEST_ETHERNET_GET_TXTIME_PARAM, ethernet_get_config); -NET_MGMT_REGISTER_REQUEST_HANDLER(NET_REQUEST_ETHERNET_GET_TXINJECTION_MODE, - ethernet_get_config); - void ethernet_mgmt_raise_carrier_on_event(struct net_if *iface) { net_mgmt_event_notify(NET_EVENT_ETHERNET_CARRIER_ON, iface); From 8c074e72c8df5bed94504bea6c84882eabe19ae9 Mon Sep 17 00:00:00 2001 From: Robert Lubos Date: Tue, 6 Feb 2024 11:06:59 +0100 Subject: [PATCH 3500/3723] Revert "[nrf fromtree] net: ethernet: Add support for setting T1S PLCA parameters" This reverts commit c6c44468cd4f3ddc9256cce990232ec2dbba4d64. Signed-off-by: Robert Lubos --- include/zephyr/net/ethernet.h | 48 -------------------------- include/zephyr/net/ethernet_mgmt.h | 7 ---- subsys/net/l2/ethernet/ethernet_mgmt.c | 11 ------ 3 files changed, 66 deletions(-) diff --git a/include/zephyr/net/ethernet.h b/include/zephyr/net/ethernet.h index 181503140a7..a47ec767a60 100644 --- a/include/zephyr/net/ethernet.h +++ b/include/zephyr/net/ethernet.h @@ -196,7 +196,6 @@ enum ethernet_config_type { ETHERNET_CONFIG_TYPE_PRIORITY_QUEUES_NUM, ETHERNET_CONFIG_TYPE_FILTER, ETHERNET_CONFIG_TYPE_PORTS_NUM, - ETHERNET_CONFIG_TYPE_T1S_PARAM, }; enum ethernet_qav_param_type { @@ -207,53 +206,7 @@ enum ethernet_qav_param_type { ETHERNET_QAV_PARAM_TYPE_STATUS, }; -enum ethernet_t1s_param_type { - ETHERNET_T1S_PARAM_TYPE_PLCA_CONFIG, -}; - /** @endcond */ -struct ethernet_t1s_param { - /** Type of T1S parameter */ - enum ethernet_t1s_param_type type; - union { - /* PLCA is the Physical Layer (PHY) Collision - * Avoidance technique employed with multidrop - * 10Base-T1S standard. - * - * The PLCA parameters are described in standard [1] - * as registers in memory map 4 (MMS = 4) (point 9.6). - * - * IDVER (PLCA ID Version) - * CTRL0 (PLCA Control 0) - * CTRL1 (PLCA Control 1) - * STATUS (PLCA Status) - * TOTMR (PLCA TO Control) - * BURST (PLCA Burst Control) - * - * Those registers are implemented by each OA TC6 - * compliant vendor (like for e.g. LAN865x - e.g. [2]). - * - * Documents: - * [1] - "OPEN Alliance 10BASE-T1x MAC-PHY Serial - * Interface" (ver. 1.1) - * [2] - "DS60001734C" - LAN865x data sheet - */ - struct { - /** T1S PLCA enabled */ - bool enable; - /** T1S PLCA node id range: 0 to 254 */ - uint8_t node_id; - /** T1S PLCA node count range: 1 to 255 */ - uint8_t node_count; - /** T1S PLCA burst count range: 0x0 to 0xFF */ - uint8_t burst_count; - /** T1S PLCA burst timer */ - uint8_t burst_timer; - /** T1S PLCA TO value */ - uint8_t to_timer; - } plca; - }; -}; struct ethernet_qav_param { /** ID of the priority queue to use */ @@ -451,7 +404,6 @@ struct ethernet_config { struct net_eth_addr mac_address; - struct ethernet_t1s_param t1s_param; struct ethernet_qav_param qav_param; struct ethernet_qbv_param qbv_param; struct ethernet_qbu_param qbu_param; diff --git a/include/zephyr/net/ethernet_mgmt.h b/include/zephyr/net/ethernet_mgmt.h index 32a38f2df88..9d95fa7a42e 100644 --- a/include/zephyr/net/ethernet_mgmt.h +++ b/include/zephyr/net/ethernet_mgmt.h @@ -51,7 +51,6 @@ enum net_request_ethernet_cmd { NET_REQUEST_ETHERNET_CMD_GET_QBV_PARAM, NET_REQUEST_ETHERNET_CMD_GET_QBU_PARAM, NET_REQUEST_ETHERNET_CMD_GET_TXTIME_PARAM, - NET_REQUEST_ETHERNET_CMD_SET_T1S_PARAM, }; #define NET_REQUEST_ETHERNET_SET_AUTO_NEGOTIATION \ @@ -129,11 +128,6 @@ NET_MGMT_DEFINE_REQUEST_HANDLER(NET_REQUEST_ETHERNET_GET_QBU_PARAM); NET_MGMT_DEFINE_REQUEST_HANDLER(NET_REQUEST_ETHERNET_GET_TXTIME_PARAM); -#define NET_REQUEST_ETHERNET_SET_T1S_PARAM \ - (_NET_ETHERNET_BASE | NET_REQUEST_ETHERNET_CMD_SET_T1S_PARAM) - -NET_MGMT_DEFINE_REQUEST_HANDLER(NET_REQUEST_ETHERNET_SET_T1S_PARAM); - struct net_eth_addr; struct ethernet_qav_param; struct ethernet_qbv_param; @@ -158,7 +152,6 @@ struct ethernet_req_params { struct ethernet_qbv_param qbv_param; struct ethernet_qbu_param qbu_param; struct ethernet_txtime_param txtime_param; - struct ethernet_t1s_param t1s_param; int priority_queues_num; int ports_num; diff --git a/subsys/net/l2/ethernet/ethernet_mgmt.c b/subsys/net/l2/ethernet/ethernet_mgmt.c index 3e957e52c1e..e7fcae8ac99 100644 --- a/subsys/net/l2/ethernet/ethernet_mgmt.c +++ b/subsys/net/l2/ethernet/ethernet_mgmt.c @@ -192,14 +192,6 @@ static int ethernet_set_config(uint32_t mgmt_request, config.promisc_mode = params->promisc_mode; type = ETHERNET_CONFIG_TYPE_PROMISC_MODE; - } else if (mgmt_request == NET_REQUEST_ETHERNET_SET_T1S_PARAM) { - if (net_if_is_up(iface)) { - return -EACCES; - } - - memcpy(&config.t1s_param, ¶ms->t1s_param, - sizeof(struct ethernet_t1s_param)); - type = ETHERNET_CONFIG_TYPE_T1S_PARAM; } else { return -EINVAL; } @@ -234,9 +226,6 @@ NET_MGMT_REGISTER_REQUEST_HANDLER(NET_REQUEST_ETHERNET_SET_TXTIME_PARAM, NET_MGMT_REGISTER_REQUEST_HANDLER(NET_REQUEST_ETHERNET_SET_PROMISC_MODE, ethernet_set_config); -NET_MGMT_REGISTER_REQUEST_HANDLER(NET_REQUEST_ETHERNET_SET_T1S_PARAM, - ethernet_set_config); - static int ethernet_get_config(uint32_t mgmt_request, struct net_if *iface, void *data, size_t len) From 7228978c1e55f3a4c563b7419538a60e6bd2211e Mon Sep 17 00:00:00 2001 From: Robert Lubos Date: Tue, 6 Feb 2024 11:06:59 +0100 Subject: [PATCH 3501/3723] Revert "[nrf fromlist] wifi: shell: ap: Add a command to disconnect a station" This reverts commit 7265d089ed41eeaf0663cab55a3dab2215491d94. Signed-off-by: Robert Lubos --- subsys/net/l2/wifi/wifi_shell.c | 33 --------------------------------- 1 file changed, 33 deletions(-) diff --git a/subsys/net/l2/wifi/wifi_shell.c b/subsys/net/l2/wifi/wifi_shell.c index 5a3d7e632a7..70b4f96d861 100644 --- a/subsys/net/l2/wifi/wifi_shell.c +++ b/subsys/net/l2/wifi/wifi_shell.c @@ -1353,34 +1353,6 @@ static int cmd_wifi_ap_stations(const struct shell *sh, size_t argc, return 0; } -static int cmd_wifi_ap_sta_disconnect(const struct shell *sh, size_t argc, - char *argv[]) -{ - struct net_if *iface = net_if_get_first_wifi(); - uint8_t mac[6]; - int ret; - - if (argc != 2) { - shell_fprintf(sh, SHELL_WARNING, "Invalid number of arguments\n"); - shell_help(sh); - return -ENOEXEC; - } - - if (net_bytes_from_str(mac, sizeof(mac), argv[1]) < 0) { - shell_fprintf(sh, SHELL_WARNING, "Invalid MAC address\n"); - return -ENOEXEC; - } - - ret = net_mgmt(NET_REQUEST_WIFI_AP_STA_DISCONNECT, iface, mac, sizeof(mac)); - if (ret) { - shell_fprintf(sh, SHELL_WARNING, "AP station disconnect failed: %s\n", - strerror(-ret)); - return -ENOEXEC; - } - - shell_fprintf(sh, SHELL_NORMAL, "AP station disconnect requested\n"); - return 0; -} static int cmd_wifi_reg_domain(const struct shell *sh, size_t argc, char *argv[]) @@ -1877,11 +1849,6 @@ SHELL_STATIC_SUBCMD_SET_CREATE(wifi_cmd_ap, "List stations connected to the AP", cmd_wifi_ap_stations, 1, 0), - SHELL_CMD_ARG(disconnect, NULL, - "Disconnect a station from the AP\n" - "\n", - cmd_wifi_ap_sta_disconnect, - 2, 0), SHELL_SUBCMD_SET_END ); From bd9ccb8ff12133213f3b5b4781aec2ac6aef1555 Mon Sep 17 00:00:00 2001 From: Robert Lubos Date: Tue, 6 Feb 2024 11:06:59 +0100 Subject: [PATCH 3502/3723] Revert "[nrf fromlist] wifi: ap: Add support to disconnect a STA" This reverts commit beb27ee66e9cac0d6cb09733a3c891bd85040a68. Signed-off-by: Robert Lubos --- include/zephyr/net/wifi_mgmt.h | 15 --------------- subsys/net/l2/wifi/wifi_mgmt.c | 24 ------------------------ 2 files changed, 39 deletions(-) diff --git a/include/zephyr/net/wifi_mgmt.h b/include/zephyr/net/wifi_mgmt.h index bd8cba81d28..0c64cab3c01 100644 --- a/include/zephyr/net/wifi_mgmt.h +++ b/include/zephyr/net/wifi_mgmt.h @@ -81,8 +81,6 @@ enum net_request_wifi_cmd { NET_REQUEST_WIFI_CMD_PACKET_FILTER, /** Set or get Wi-Fi channel for Monitor or TX-Injection mode */ NET_REQUEST_WIFI_CMD_CHANNEL, - /** Disconnect a STA from AP */ - NET_REQUEST_WIFI_CMD_AP_STA_DISCONNECT, NET_REQUEST_WIFI_CMD_MAX }; @@ -160,11 +158,6 @@ NET_MGMT_DEFINE_REQUEST_HANDLER(NET_REQUEST_WIFI_PACKET_FILTER); NET_MGMT_DEFINE_REQUEST_HANDLER(NET_REQUEST_WIFI_CHANNEL); -#define NET_REQUEST_WIFI_AP_STA_DISCONNECT \ - (_NET_WIFI_BASE | NET_REQUEST_WIFI_CMD_AP_STA_DISCONNECT) - -NET_MGMT_DEFINE_REQUEST_HANDLER(NET_REQUEST_WIFI_AP_STA_DISCONNECT); - /** Wi-Fi management events */ enum net_event_wifi_cmd { /** Scan results available */ @@ -733,14 +726,6 @@ struct wifi_mgmt_ops { * @return 0 if ok, < 0 if error */ int (*ap_disable)(const struct device *dev); - /** Disconnect a STA from AP - * - * @param dev Pointer to the device structure for the driver instance. - * @param mac MAC address of the STA to disconnect - * - * @return 0 if ok, < 0 if error - */ - int (*ap_sta_disconnect)(const struct device *dev, const uint8_t *mac); /** Get interface status * * @param dev Pointer to the device structure for the driver instance. diff --git a/subsys/net/l2/wifi/wifi_mgmt.c b/subsys/net/l2/wifi/wifi_mgmt.c index 2cfe8e25d89..6e0cb761dbf 100644 --- a/subsys/net/l2/wifi/wifi_mgmt.c +++ b/subsys/net/l2/wifi/wifi_mgmt.c @@ -410,30 +410,6 @@ static int wifi_ap_disable(uint32_t mgmt_request, struct net_if *iface, NET_MGMT_REGISTER_REQUEST_HANDLER(NET_REQUEST_WIFI_AP_DISABLE, wifi_ap_disable); -static int wifi_ap_sta_disconnect(uint32_t mgmt_request, struct net_if *iface, - void *data, size_t len) -{ - const struct device *dev = net_if_get_device(iface); - const struct wifi_mgmt_ops *const wifi_mgmt_api = get_wifi_api(iface); - uint8_t *mac = data; - - if (dev == NULL) { - return -ENODEV; - } - - if (wifi_mgmt_api == NULL || wifi_mgmt_api->ap_sta_disconnect == NULL) { - return -ENOTSUP; - } - - if (!data || len != sizeof(uint8_t) * WIFI_MAC_ADDR_LEN) { - return -EINVAL; - } - - return wifi_mgmt_api->ap_sta_disconnect(dev, mac); -} - -NET_MGMT_REGISTER_REQUEST_HANDLER(NET_REQUEST_WIFI_AP_STA_DISCONNECT, wifi_ap_sta_disconnect); - static int wifi_iface_status(uint32_t mgmt_request, struct net_if *iface, void *data, size_t len) { From 17f627aede69985bde8d7f13ca0cf9e2c40fed7a Mon Sep 17 00:00:00 2001 From: Robert Lubos Date: Tue, 6 Feb 2024 11:07:00 +0100 Subject: [PATCH 3503/3723] Revert "[nrf fromtree] Bluetooth: BAP: Fix issue with setting invalid iso data path" This reverts commit efade47773f7a119b9576a168e1e5c59ceb2c3d3. Signed-off-by: Robert Lubos --- subsys/bluetooth/audio/ascs.c | 6 ++- subsys/bluetooth/audio/bap_broadcast_sink.c | 2 +- subsys/bluetooth/audio/bap_broadcast_source.c | 4 +- subsys/bluetooth/audio/bap_iso.c | 48 ++++--------------- subsys/bluetooth/audio/bap_iso.h | 1 - subsys/bluetooth/audio/bap_stream.c | 22 +++++++++ subsys/bluetooth/audio/bap_stream.h | 2 + subsys/bluetooth/audio/bap_unicast_client.c | 13 ++++- 8 files changed, 52 insertions(+), 46 deletions(-) diff --git a/subsys/bluetooth/audio/ascs.c b/subsys/bluetooth/audio/ascs.c index 6df91e5f43e..116071d4c0f 100644 --- a/subsys/bluetooth/audio/ascs.c +++ b/subsys/bluetooth/audio/ascs.c @@ -1820,7 +1820,11 @@ static int ase_stream_qos(struct bt_bap_stream *stream, struct bt_audio_codec_qo * we have the ISO <-> EP coupling completed (due to setting * the CIS ID in the QoS procedure). */ - bt_bap_iso_configure_data_path(ep, stream->codec_cfg); + if (ep->dir == BT_AUDIO_DIR_SINK) { + bt_audio_codec_cfg_to_iso_path(&ep->iso->rx.path, stream->codec_cfg); + } else { + bt_audio_codec_cfg_to_iso_path(&ep->iso->tx.path, stream->codec_cfg); + } ep->cig_id = cig_id; ep->cis_id = cis_id; diff --git a/subsys/bluetooth/audio/bap_broadcast_sink.c b/subsys/bluetooth/audio/bap_broadcast_sink.c index aa4bc08f761..4d2134455b8 100644 --- a/subsys/bluetooth/audio/bap_broadcast_sink.c +++ b/subsys/bluetooth/audio/bap_broadcast_sink.c @@ -764,7 +764,7 @@ static int bt_bap_broadcast_sink_setup_stream(struct bt_bap_broadcast_sink *sink bt_bap_iso_bind_ep(iso, ep); bt_audio_codec_qos_to_iso_qos(iso->chan.qos->rx, &sink->codec_qos); - bt_bap_iso_configure_data_path(ep, codec_cfg); + bt_audio_codec_cfg_to_iso_path(iso->chan.qos->rx->path, codec_cfg); bt_bap_iso_unref(iso); diff --git a/subsys/bluetooth/audio/bap_broadcast_source.c b/subsys/bluetooth/audio/bap_broadcast_source.c index 33fd1f0e17d..8978e2816cb 100644 --- a/subsys/bluetooth/audio/bap_broadcast_source.c +++ b/subsys/bluetooth/audio/bap_broadcast_source.c @@ -288,7 +288,7 @@ static int broadcast_source_setup_stream(uint8_t index, struct bt_bap_stream *st bt_bap_iso_bind_ep(iso, ep); bt_audio_codec_qos_to_iso_qos(iso->chan.qos->tx, qos); - bt_bap_iso_configure_data_path(ep, codec_cfg); + bt_audio_codec_cfg_to_iso_path(iso->chan.qos->tx->path, codec_cfg); #if defined(CONFIG_BT_ISO_TEST_PARAMS) iso->chan.qos->num_subevents = qos->num_subevents; #endif /* CONFIG_BT_ISO_TEST_PARAMS */ @@ -878,7 +878,7 @@ int bt_bap_broadcast_source_reconfig(struct bt_bap_broadcast_source *source, iso_qos = stream->ep->iso->chan.qos->tx; bt_bap_stream_attach(NULL, stream, stream->ep, codec_cfg); - bt_bap_iso_configure_data_path(stream->ep, codec_cfg); + bt_audio_codec_cfg_to_iso_path(iso_qos->path, codec_cfg); } } diff --git a/subsys/bluetooth/audio/bap_iso.c b/subsys/bluetooth/audio/bap_iso.c index 3fa2059ea94..cb68a8032f5 100644 --- a/subsys/bluetooth/audio/bap_iso.c +++ b/subsys/bluetooth/audio/bap_iso.c @@ -129,12 +129,19 @@ void bt_bap_iso_init(struct bt_bap_iso *iso, struct bt_iso_chan_ops *ops) iso->chan.ops = ops; iso->chan.qos = &iso->qos; - /* Setup the QoS for both Tx and Rx + /* Setup points for both Tx and Rx * This is due to the limitation in the ISO API where pointers like - * the `qos->tx` shall be initialized before the CIS is created + * the `qos->tx` shall be initialized before the CIS is connected if + * ever want to use it for TX, and ditto for RX. They cannot be + * initialized after the CIS has been connected */ iso->chan.qos->rx = &iso->rx.qos; + iso->chan.qos->rx->path = &iso->rx.path; + iso->chan.qos->rx->path->cc = iso->rx.cc; + iso->chan.qos->tx = &iso->tx.qos; + iso->chan.qos->tx->path = &iso->tx.path; + iso->chan.qos->tx->path->cc = iso->tx.cc; } static struct bt_bap_iso_dir *bap_iso_get_iso_dir(bool unicast_client, struct bt_bap_iso *iso, @@ -157,43 +164,6 @@ static struct bt_bap_iso_dir *bap_iso_get_iso_dir(bool unicast_client, struct bt } } -void bt_bap_iso_configure_data_path(struct bt_bap_ep *ep, struct bt_audio_codec_cfg *codec_cfg) -{ - struct bt_bap_iso *bap_iso = ep->iso; - struct bt_iso_chan_qos *qos = bap_iso->chan.qos; - const bool is_unicast_client = - IS_ENABLED(CONFIG_BT_BAP_UNICAST_CLIENT) && bt_bap_ep_is_unicast_client(ep); - struct bt_bap_iso_dir *iso_dir = bap_iso_get_iso_dir(is_unicast_client, bap_iso, ep->dir); - struct bt_iso_chan_path *path = &iso_dir->path; - - /* Setup the data path objects */ - if (iso_dir == &bap_iso->rx) { - qos->rx->path = path; - } else { - qos->tx->path = path; - } - - /* Configure the data path to either use the controller for transcoding, or set the path to - * be transparant to indicate that the transcoding happens somewhere else - */ - path->pid = codec_cfg->path_id; - - if (codec_cfg->ctlr_transcode) { - path->format = codec_cfg->id; - path->cid = codec_cfg->cid; - path->vid = codec_cfg->vid; - path->delay = 0; - path->cc_len = codec_cfg->data_len; - path->cc = codec_cfg->data; - } else { - path->format = BT_HCI_CODING_FORMAT_TRANSPARENT; - path->cid = 0; - path->vid = 0; - path->delay = 0; - path->cc_len = 0; - path->cc = NULL; - } -} static bool is_unicast_client_ep(struct bt_bap_ep *ep) { return IS_ENABLED(CONFIG_BT_BAP_UNICAST_CLIENT) && bt_bap_ep_is_unicast_client(ep); diff --git a/subsys/bluetooth/audio/bap_iso.h b/subsys/bluetooth/audio/bap_iso.h index 4384182d697..d3b27f3823a 100644 --- a/subsys/bluetooth/audio/bap_iso.h +++ b/subsys/bluetooth/audio/bap_iso.h @@ -41,7 +41,6 @@ void bt_bap_iso_foreach(bt_bap_iso_func_t func, void *user_data); struct bt_bap_iso *bt_bap_iso_find(bt_bap_iso_func_t func, void *user_data); void bt_bap_iso_init(struct bt_bap_iso *iso, struct bt_iso_chan_ops *ops); void bt_bap_iso_bind_ep(struct bt_bap_iso *iso, struct bt_bap_ep *ep); -void bt_bap_iso_configure_data_path(struct bt_bap_ep *ep, struct bt_audio_codec_cfg *codec_cfg); void bt_bap_iso_unbind_ep(struct bt_bap_iso *iso, struct bt_bap_ep *ep); struct bt_bap_ep *bt_bap_iso_get_ep(bool unicast_client, struct bt_bap_iso *iso, enum bt_audio_dir dir); diff --git a/subsys/bluetooth/audio/bap_stream.c b/subsys/bluetooth/audio/bap_stream.c index d6df9524e14..6dae679ddef 100644 --- a/subsys/bluetooth/audio/bap_stream.c +++ b/subsys/bluetooth/audio/bap_stream.c @@ -31,6 +31,28 @@ LOG_MODULE_REGISTER(bt_bap_stream, CONFIG_BT_BAP_STREAM_LOG_LEVEL); +void bt_audio_codec_cfg_to_iso_path(struct bt_iso_chan_path *path, + struct bt_audio_codec_cfg *codec_cfg) +{ + path->pid = codec_cfg->path_id; + + if (codec_cfg->ctlr_transcode) { + path->format = codec_cfg->id; + path->cid = codec_cfg->cid; + path->vid = codec_cfg->vid; + path->delay = 0; + path->cc_len = codec_cfg->data_len; + path->cc = codec_cfg->data; + } else { + path->format = BT_HCI_CODING_FORMAT_TRANSPARENT; + path->cid = 0; + path->vid = 0; + path->delay = 0; + path->cc_len = 0; + path->cc = NULL; + } +} + #if defined(CONFIG_BT_BAP_UNICAST_CLIENT) || defined(CONFIG_BT_BAP_BROADCAST_SOURCE) || \ defined(CONFIG_BT_BAP_BROADCAST_SINK) void bt_audio_codec_qos_to_iso_qos(struct bt_iso_chan_io_qos *io, diff --git a/subsys/bluetooth/audio/bap_stream.h b/subsys/bluetooth/audio/bap_stream.h index d16cf2cfcc9..67e8c0470df 100644 --- a/subsys/bluetooth/audio/bap_stream.h +++ b/subsys/bluetooth/audio/bap_stream.h @@ -17,6 +17,8 @@ void bt_bap_stream_reset(struct bt_bap_stream *stream); void bt_bap_stream_attach(struct bt_conn *conn, struct bt_bap_stream *stream, struct bt_bap_ep *ep, struct bt_audio_codec_cfg *codec_cfg); +void bt_audio_codec_cfg_to_iso_path(struct bt_iso_chan_path *path, + struct bt_audio_codec_cfg *codec_cfg); void bt_audio_codec_qos_to_iso_qos(struct bt_iso_chan_io_qos *io, const struct bt_audio_codec_qos *codec_qos); diff --git a/subsys/bluetooth/audio/bap_unicast_client.c b/subsys/bluetooth/audio/bap_unicast_client.c index b6de9b61a66..933db93ec72 100644 --- a/subsys/bluetooth/audio/bap_unicast_client.c +++ b/subsys/bluetooth/audio/bap_unicast_client.c @@ -774,8 +774,17 @@ static void unicast_client_ep_qos_state(struct bt_bap_ep *ep, struct net_buf_sim * we have the ISO <-> EP coupling completed (due to setting * the CIS ID in the QoS procedure). */ - - bt_bap_iso_configure_data_path(ep, stream->codec_cfg); + if (ep->dir == BT_AUDIO_DIR_SOURCE) { + /* If the endpoint is a source, then we need to + * configure our RX parameters + */ + bt_audio_codec_cfg_to_iso_path(&ep->iso->rx.path, stream->codec_cfg); + } else { + /* If the endpoint is a sink, then we need to + * configure our TX parameters + */ + bt_audio_codec_cfg_to_iso_path(&ep->iso->tx.path, stream->codec_cfg); + } } /* Notify upper layer */ From 82c15c9d17a1322c699c9cb2ade9612536095e56 Mon Sep 17 00:00:00 2001 From: Robert Lubos Date: Tue, 6 Feb 2024 11:07:00 +0100 Subject: [PATCH 3504/3723] Revert "[nrf fromtree] Bluetooth: BAP: Add support for transparent coding format" This reverts commit e79378647820cd929411c0da58df5ede8075f1ec. Signed-off-by: Robert Lubos --- include/zephyr/bluetooth/audio/audio.h | 14 -------------- subsys/bluetooth/audio/bap_stream.c | 22 ++++++---------------- 2 files changed, 6 insertions(+), 30 deletions(-) diff --git a/include/zephyr/bluetooth/audio/audio.h b/include/zephyr/bluetooth/audio/audio.h index 03f451a3c8b..17bac991f18 100644 --- a/include/zephyr/bluetooth/audio/audio.h +++ b/include/zephyr/bluetooth/audio/audio.h @@ -209,7 +209,6 @@ enum bt_audio_metadata_type { ((struct bt_audio_codec_cfg){ \ /* Use HCI data path as default, can be overwritten by application */ \ .path_id = BT_ISO_DATA_PATH_HCI, \ - .ctlr_transcode = false, \ .id = _id, \ .cid = _cid, \ .vid = _vid, \ @@ -232,7 +231,6 @@ enum bt_audio_metadata_type { ((struct bt_audio_codec_cap){ \ /* Use HCI data path as default, can be overwritten by application */ \ .path_id = BT_ISO_DATA_PATH_HCI, \ - .ctlr_transcode = false, \ .id = (_id), \ .cid = (_cid), \ .vid = (_vid), \ @@ -318,12 +316,6 @@ struct bt_audio_codec_cap { * vendor specific ID. */ uint8_t path_id; - /** Whether or not the local controller should transcode - * - * This effectively sets the coding format for the ISO data path to @ref - * BT_HCI_CODING_FORMAT_TRANSPARENT if false, else uses the @ref bt_audio_codec_cfg.id. - */ - bool ctlr_transcode; /** Codec ID */ uint8_t id; /** Codec Company ID */ @@ -352,12 +344,6 @@ struct bt_audio_codec_cfg { * vendor specific ID. */ uint8_t path_id; - /** Whether or not the local controller should transcode - * - * This effectively sets the coding format for the ISO data path to @ref - * BT_HCI_CODING_FORMAT_TRANSPARENT if false, else uses the @ref bt_audio_codec_cfg.id. - */ - bool ctlr_transcode; /** Codec ID */ uint8_t id; /** Codec Company ID */ diff --git a/subsys/bluetooth/audio/bap_stream.c b/subsys/bluetooth/audio/bap_stream.c index 6dae679ddef..23e5bb8564b 100644 --- a/subsys/bluetooth/audio/bap_stream.c +++ b/subsys/bluetooth/audio/bap_stream.c @@ -35,22 +35,12 @@ void bt_audio_codec_cfg_to_iso_path(struct bt_iso_chan_path *path, struct bt_audio_codec_cfg *codec_cfg) { path->pid = codec_cfg->path_id; - - if (codec_cfg->ctlr_transcode) { - path->format = codec_cfg->id; - path->cid = codec_cfg->cid; - path->vid = codec_cfg->vid; - path->delay = 0; - path->cc_len = codec_cfg->data_len; - path->cc = codec_cfg->data; - } else { - path->format = BT_HCI_CODING_FORMAT_TRANSPARENT; - path->cid = 0; - path->vid = 0; - path->delay = 0; - path->cc_len = 0; - path->cc = NULL; - } + path->format = codec_cfg->id; + path->cid = codec_cfg->cid; + path->vid = codec_cfg->vid; + path->delay = 0; /* TODO: Add to bt_audio_codec_cfg? Use presentation delay? */ + path->cc_len = codec_cfg->data_len; + path->cc = codec_cfg->data; } #if defined(CONFIG_BT_BAP_UNICAST_CLIENT) || defined(CONFIG_BT_BAP_BROADCAST_SOURCE) || \ From 1ec79063cb51b5ae38a0fa4a15a82b79eebcbb23 Mon Sep 17 00:00:00 2001 From: Robert Lubos Date: Tue, 6 Feb 2024 11:07:00 +0100 Subject: [PATCH 3505/3723] Revert "[nrf fromtree] net: openthread: Fix key import in case of ECDSA." This reverts commit 0c16a9a6fa8163a6166955124f7ab6a32217377e. Signed-off-by: Robert Lubos --- modules/openthread/platform/crypto_psa.c | 114 ++++++++++++----------- 1 file changed, 62 insertions(+), 52 deletions(-) diff --git a/modules/openthread/platform/crypto_psa.c b/modules/openthread/platform/crypto_psa.c index c818c5695a3..55018254154 100644 --- a/modules/openthread/platform/crypto_psa.c +++ b/modules/openthread/platform/crypto_psa.c @@ -16,7 +16,6 @@ #if defined(CONFIG_OPENTHREAD_ECDSA) #include -#include #endif static otError psaToOtError(psa_status_t aStatus) @@ -63,7 +62,7 @@ static psa_algorithm_t toPsaAlgorithm(otCryptoKeyAlgorithm aAlgorithm) * There is currently no constant like PSA_ALG_NONE, but 0 is used * to indicate an unknown algorithm. */ - return (psa_algorithm_t)0; + return (psa_algorithm_t) 0; } } @@ -97,9 +96,11 @@ static psa_key_usage_t toPsaKeyUsage(int aUsage) static bool checkKeyUsage(int aUsage) { /* Check if only supported flags have been passed */ - int supported_flags = OT_CRYPTO_KEY_USAGE_EXPORT | OT_CRYPTO_KEY_USAGE_ENCRYPT | - OT_CRYPTO_KEY_USAGE_DECRYPT | OT_CRYPTO_KEY_USAGE_SIGN_HASH | - OT_CRYPTO_KEY_USAGE_VERIFY_HASH; + int supported_flags = OT_CRYPTO_KEY_USAGE_EXPORT | + OT_CRYPTO_KEY_USAGE_ENCRYPT | + OT_CRYPTO_KEY_USAGE_DECRYPT | + OT_CRYPTO_KEY_USAGE_SIGN_HASH | + OT_CRYPTO_KEY_USAGE_VERIFY_HASH; return (aUsage & ~supported_flags) == 0; } @@ -120,57 +121,26 @@ void otPlatCryptoInit(void) * PSA with emulated TFM, Settings have to be initialized at the end of otPlatCryptoInit(), * to be available before storing Network Key. */ - __ASSERT_EVAL((void)settings_subsys_init(), int err = settings_subsys_init(), !err, - "Failed to initialize settings"); + __ASSERT_EVAL((void) settings_subsys_init(), int err = settings_subsys_init(), + !err, "Failed to initialize settings"); #endif } -otError otPlatCryptoImportKey(otCryptoKeyRef *aKeyRef, otCryptoKeyType aKeyType, - otCryptoKeyAlgorithm aKeyAlgorithm, int aKeyUsage, - otCryptoKeyStorage aKeyPersistence, const uint8_t *aKey, +otError otPlatCryptoImportKey(otCryptoKeyRef *aKeyRef, + otCryptoKeyType aKeyType, + otCryptoKeyAlgorithm aKeyAlgorithm, + int aKeyUsage, + otCryptoKeyStorage aKeyPersistence, + const uint8_t *aKey, size_t aKeyLen) { -#if defined(CONFIG_OPENTHREAD_ECDSA) - int version; - size_t len; - unsigned char *p = (unsigned char *)aKey; - unsigned char *end; -#endif - psa_key_attributes_t attributes = PSA_KEY_ATTRIBUTES_INIT; - psa_status_t status = 0; + psa_status_t status; if (aKeyRef == NULL || aKey == NULL || !checkKeyUsage(aKeyUsage)) { return OT_ERROR_INVALID_ARGS; } -#if defined(CONFIG_OPENTHREAD_ECDSA) - /* Check if key is ECDSA pair and extract private key from it since PSA expects it. */ - if (aKeyType == OT_CRYPTO_KEY_TYPE_ECDSA) { - - end = p + aKeyLen; - status = mbedtls_asn1_get_tag(&p, end, &len, - MBEDTLS_ASN1_CONSTRUCTED | MBEDTLS_ASN1_SEQUENCE); - if (status != 0) { - return OT_ERROR_FAILED; - } - - end = p + len; - status = mbedtls_asn1_get_int(&p, end, &version); - if (status != 0) { - return OT_ERROR_FAILED; - } - - status = mbedtls_asn1_get_tag(&p, end, &len, MBEDTLS_ASN1_OCTET_STRING); - if (status != 0 || len != 32) { - return OT_ERROR_FAILED; - } - - aKey = p; - aKeyLen = len; - } -#endif - psa_set_key_type(&attributes, toPsaKeyType(aKeyType)); psa_set_key_algorithm(&attributes, toPsaAlgorithm(aKeyAlgorithm)); psa_set_key_usage_flags(&attributes, toPsaKeyUsage(aKeyUsage)); @@ -191,7 +161,9 @@ otError otPlatCryptoImportKey(otCryptoKeyRef *aKeyRef, otCryptoKeyType aKeyType, return psaToOtError(status); } -otError otPlatCryptoExportKey(otCryptoKeyRef aKeyRef, uint8_t *aBuffer, size_t aBufferLen, +otError otPlatCryptoExportKey(otCryptoKeyRef aKeyRef, + uint8_t *aBuffer, + size_t aBufferLen, size_t *aKeyLen) { if (aBuffer == NULL) { @@ -259,7 +231,8 @@ otError otPlatCryptoHmacSha256Start(otCryptoContext *aContext, const otCryptoKey return psaToOtError(status); } -otError otPlatCryptoHmacSha256Update(otCryptoContext *aContext, const void *aBuf, +otError otPlatCryptoHmacSha256Update(otCryptoContext *aContext, + const void *aBuf, uint16_t aBufLength) { psa_mac_operation_t *operation; @@ -270,7 +243,7 @@ otError otPlatCryptoHmacSha256Update(otCryptoContext *aContext, const void *aBuf operation = aContext->mContext; - return psaToOtError(psa_mac_update(operation, (const uint8_t *)aBuf, aBufLength)); + return psaToOtError(psa_mac_update(operation, (const uint8_t *) aBuf, aBufLength)); } otError otPlatCryptoHmacSha256Finish(otCryptoContext *aContext, uint8_t *aBuf, size_t aBufLength) @@ -296,7 +269,7 @@ otError otPlatCryptoAesInit(otCryptoContext *aContext) } key_ref = aContext->mContext; - *key_ref = (psa_key_id_t)0; /* In TF-M 1.5.0 this can be replaced with PSA_KEY_ID_NULL */ + *key_ref = (psa_key_id_t) 0; /* In TF-M 1.5.0 this can be replaced with PSA_KEY_ID_NULL */ return OT_ERROR_NONE; } @@ -327,8 +300,13 @@ otError otPlatCryptoAesEncrypt(otCryptoContext *aContext, const uint8_t *aInput, } key_ref = aContext->mContext; - status = psa_cipher_encrypt(*key_ref, PSA_ALG_ECB_NO_PADDING, aInput, block_size, aOutput, - block_size, &cipher_length); + status = psa_cipher_encrypt(*key_ref, + PSA_ALG_ECB_NO_PADDING, + aInput, + block_size, + aOutput, + block_size, + &cipher_length); return psaToOtError(status); } @@ -388,7 +366,7 @@ otError otPlatCryptoSha256Update(otCryptoContext *aContext, const void *aBuf, ui operation = aContext->mContext; - return psaToOtError(psa_hash_update(operation, (const uint8_t *)aBuf, aBufLength)); + return psaToOtError(psa_hash_update(operation, (const uint8_t *) aBuf, aBufLength)); } otError otPlatCryptoSha256Finish(otCryptoContext *aContext, uint8_t *aHash, uint16_t aHashSize) @@ -452,6 +430,38 @@ otError otPlatCryptoEcdsaGenerateKey(otPlatCryptoEcdsaKeyPair *aKeyPair) return psaToOtError(status); } +otError otPlatCryptoEcdsaGetPublicKey(const otPlatCryptoEcdsaKeyPair *aKeyPair, + otPlatCryptoEcdsaPublicKey *aPublicKey) +{ + psa_key_attributes_t attributes = PSA_KEY_ATTRIBUTES_INIT; + psa_key_id_t key_id = 0; + psa_status_t status; + size_t exported_length; + uint8_t buffer[1 + OT_CRYPTO_ECDSA_PUBLIC_KEY_SIZE]; + + psa_set_key_algorithm(&attributes, PSA_ALG_DETERMINISTIC_ECDSA(PSA_ALG_SHA_256)); + psa_set_key_type(&attributes, PSA_KEY_TYPE_ECC_KEY_PAIR(PSA_ECC_FAMILY_SECP_R1)); + psa_set_key_bits(&attributes, 256); + + status = psa_import_key(&attributes, aKeyPair->mDerBytes, aKeyPair->mDerLength, &key_id); + if (status != PSA_SUCCESS) { + goto out; + } + + status = psa_export_public_key(key_id, buffer, sizeof(buffer), &exported_length); + if (status != PSA_SUCCESS) { + goto out; + } + __ASSERT_NO_MSG(exported_length == sizeof(buffer)); + memcpy(aPublicKey->m8, buffer + 1, OT_CRYPTO_ECDSA_PUBLIC_KEY_SIZE); + +out: + psa_reset_key_attributes(&attributes); + psa_destroy_key(key_id); + + return psaToOtError(status); +} + otError otPlatCryptoEcdsaSign(const otPlatCryptoEcdsaKeyPair *aKeyPair, const otPlatCryptoSha256Hash *aHash, otPlatCryptoEcdsaSignature *aSignature) From 4c0ff7869930924d2d09ad58e98666877167449c Mon Sep 17 00:00:00 2001 From: Robert Lubos Date: Tue, 6 Feb 2024 11:07:00 +0100 Subject: [PATCH 3506/3723] Revert "[nrf fromtree] net: openthread: Regular openthread upmerge to `00076af`" This reverts commit bca3722d75202fdbe6c7d8dcc546ad90f1c03895. Signed-off-by: Robert Lubos --- west.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/west.yml b/west.yml index 2892d3db451..b9a84545850 100644 --- a/west.yml +++ b/west.yml @@ -301,7 +301,7 @@ manifest: revision: 214f9fc1539f8e5937c0474cb6ee29b6dcb2d4b8 path: modules/lib/open-amp - name: openthread - revision: 00076aff3ae571db7c90509ec9dc293457098c35 + revision: 4ed44bc7d58d9a98c6cca13a50d38129045ab3df path: modules/lib/openthread - name: percepio path: modules/debug/percepio From ff32d9f60992a9f37a780c2ec78ba8b7919017d1 Mon Sep 17 00:00:00 2001 From: Robert Lubos Date: Tue, 6 Feb 2024 11:07:00 +0100 Subject: [PATCH 3507/3723] Revert "[nrf fromtree] net: mgmt: Print correct TWT teardown status message" This reverts commit 8f02d6eeec4b4b0a8aebfceca05f1a029b8b08a0. Signed-off-by: Robert Lubos --- subsys/net/l2/wifi/wifi_shell.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/subsys/net/l2/wifi/wifi_shell.c b/subsys/net/l2/wifi/wifi_shell.c index 70b4f96d861..44f507f6e02 100644 --- a/subsys/net/l2/wifi/wifi_shell.c +++ b/subsys/net/l2/wifi/wifi_shell.c @@ -294,7 +294,7 @@ static void handle_wifi_twt_event(struct net_mgmt_event_callback *cb) if (resp->operation == WIFI_TWT_TEARDOWN) { if (resp->teardown_status == WIFI_TWT_TEARDOWN_SUCCESS) { - print(context.sh, SHELL_NORMAL, "TWT teardown succeeded for flow ID %d\n", + print(context.sh, SHELL_NORMAL, "TWT teardown received for flow ID %d\n", resp->flow_id); } else { print(context.sh, SHELL_NORMAL, "TWT teardown failed for flow ID %d\n", From 3ba43d79e1720e0bde72259ac050ab2ff61e106a Mon Sep 17 00:00:00 2001 From: Robert Lubos Date: Tue, 6 Feb 2024 11:07:00 +0100 Subject: [PATCH 3508/3723] Revert "[nrf fromtree] net: mgmt: Update app of TWT teardown status" This reverts commit 0f41950fd18eaa6125d2041ed2525a5aa27397ea. Signed-off-by: Robert Lubos --- include/zephyr/net/wifi.h | 8 -------- include/zephyr/net/wifi_mgmt.h | 2 -- subsys/net/l2/wifi/wifi_shell.c | 9 ++------- 3 files changed, 2 insertions(+), 17 deletions(-) diff --git a/include/zephyr/net/wifi.h b/include/zephyr/net/wifi.h index c49d6ad0f66..5c7d5b493fa 100644 --- a/include/zephyr/net/wifi.h +++ b/include/zephyr/net/wifi.h @@ -345,14 +345,6 @@ enum wifi_twt_fail_reason { WIFI_TWT_FAIL_FLOW_ALREADY_EXISTS, }; -/** Wi-Fi Target Wake Time (TWT) teradown status. */ -enum wifi_twt_teardown_status { - /** TWT teardown success */ - WIFI_TWT_TEARDOWN_SUCCESS = 0, - /** TWT teardown failure */ - WIFI_TWT_TEARDOWN_FAILED, -}; - /** @cond INTERNAL_HIDDEN */ static const char * const wifi_twt_err_code_tbl[] = { [WIFI_TWT_FAIL_UNSPECIFIED] = "Unspecified", diff --git a/include/zephyr/net/wifi_mgmt.h b/include/zephyr/net/wifi_mgmt.h index 0c64cab3c01..f6ae631a830 100644 --- a/include/zephyr/net/wifi_mgmt.h +++ b/include/zephyr/net/wifi_mgmt.h @@ -470,8 +470,6 @@ struct wifi_twt_params { enum wifi_twt_setup_cmd setup_cmd; /** TWT setup response status, see enum wifi_twt_setup_resp_status */ enum wifi_twt_setup_resp_status resp_status; - /** TWT teardown cmd status, see enum wifi_twt_teardown_status */ - enum wifi_twt_teardown_status teardown_status; /** Dialog token, used to map requests to responses */ uint8_t dialog_token; /** Flow ID, used to map setup with teardown */ diff --git a/subsys/net/l2/wifi/wifi_shell.c b/subsys/net/l2/wifi/wifi_shell.c index 44f507f6e02..1f13ae864ae 100644 --- a/subsys/net/l2/wifi/wifi_shell.c +++ b/subsys/net/l2/wifi/wifi_shell.c @@ -293,13 +293,8 @@ static void handle_wifi_twt_event(struct net_mgmt_event_callback *cb) (const struct wifi_twt_params *)cb->info; if (resp->operation == WIFI_TWT_TEARDOWN) { - if (resp->teardown_status == WIFI_TWT_TEARDOWN_SUCCESS) { - print(context.sh, SHELL_NORMAL, "TWT teardown received for flow ID %d\n", - resp->flow_id); - } else { - print(context.sh, SHELL_NORMAL, "TWT teardown failed for flow ID %d\n", - resp->flow_id); - } + print(context.sh, SHELL_NORMAL, "TWT teardown received for flow ID %d\n", + resp->flow_id); return; } From 9b1082c5ffc4a0ac1e3c5217283c078d14a1cf19 Mon Sep 17 00:00:00 2001 From: Robert Lubos Date: Tue, 6 Feb 2024 11:07:01 +0100 Subject: [PATCH 3509/3723] Revert "[nrf fromtree] tests: bsim: bluetooth: host: gatt: add authorization callback API test" This reverts commit e4e6dc87bafd8f3e9c2562fc55dbfa4f8185b14b. Signed-off-by: Robert Lubos --- tests/bsim/bluetooth/host/compile.sh | 1 - .../host/gatt/authorization/CMakeLists.txt | 14 - .../host/gatt/authorization/prj.conf | 7 - .../host/gatt/authorization/src/common.c | 20 - .../host/gatt/authorization/src/common.h | 73 ---- .../gatt/authorization/src/gatt_client_test.c | 341 ---------------- .../gatt/authorization/src/gatt_server_test.c | 370 ------------------ .../host/gatt/authorization/src/main.c | 22 -- .../gatt/authorization/test_scripts/gatt.sh | 22 -- 9 files changed, 870 deletions(-) delete mode 100644 tests/bsim/bluetooth/host/gatt/authorization/CMakeLists.txt delete mode 100644 tests/bsim/bluetooth/host/gatt/authorization/prj.conf delete mode 100644 tests/bsim/bluetooth/host/gatt/authorization/src/common.c delete mode 100644 tests/bsim/bluetooth/host/gatt/authorization/src/common.h delete mode 100644 tests/bsim/bluetooth/host/gatt/authorization/src/gatt_client_test.c delete mode 100644 tests/bsim/bluetooth/host/gatt/authorization/src/gatt_server_test.c delete mode 100644 tests/bsim/bluetooth/host/gatt/authorization/src/main.c delete mode 100755 tests/bsim/bluetooth/host/gatt/authorization/test_scripts/gatt.sh diff --git a/tests/bsim/bluetooth/host/compile.sh b/tests/bsim/bluetooth/host/compile.sh index 098c983d75f..ff42fd27adf 100755 --- a/tests/bsim/bluetooth/host/compile.sh +++ b/tests/bsim/bluetooth/host/compile.sh @@ -41,7 +41,6 @@ app=tests/bsim/bluetooth/host/att/sequential/dut compile app=tests/bsim/bluetooth/host/att/sequential/tester compile app=tests/bsim/bluetooth/host/att/long_read compile -app=tests/bsim/bluetooth/host/gatt/authorization compile app=tests/bsim/bluetooth/host/gatt/caching compile app=tests/bsim/bluetooth/host/gatt/general compile app=tests/bsim/bluetooth/host/gatt/notify compile diff --git a/tests/bsim/bluetooth/host/gatt/authorization/CMakeLists.txt b/tests/bsim/bluetooth/host/gatt/authorization/CMakeLists.txt deleted file mode 100644 index acb0dd45947..00000000000 --- a/tests/bsim/bluetooth/host/gatt/authorization/CMakeLists.txt +++ /dev/null @@ -1,14 +0,0 @@ -# SPDX-License-Identifier: Apache-2.0 - -cmake_minimum_required(VERSION 3.20.0) - -find_package(Zephyr REQUIRED HINTS $ENV{ZEPHYR_BASE}) -project(bsim_test_gatt_authorization) - -FILE(GLOB app_sources src/*.c) -target_sources(app PRIVATE ${app_sources} ) - -zephyr_include_directories( - ${BSIM_COMPONENTS_PATH}/libUtilv1/src/ - ${BSIM_COMPONENTS_PATH}/libPhyComv1/src/ - ) diff --git a/tests/bsim/bluetooth/host/gatt/authorization/prj.conf b/tests/bsim/bluetooth/host/gatt/authorization/prj.conf deleted file mode 100644 index 9cba554afef..00000000000 --- a/tests/bsim/bluetooth/host/gatt/authorization/prj.conf +++ /dev/null @@ -1,7 +0,0 @@ -CONFIG_BT=y -CONFIG_BT_DEVICE_NAME="GATT tester" -CONFIG_BT_PERIPHERAL=y -CONFIG_BT_CENTRAL=y -CONFIG_BT_GATT_CLIENT=y -CONFIG_BT_GATT_AUTHORIZATION_CUSTOM=y -CONFIG_BT_ATT_PREPARE_COUNT=3 diff --git a/tests/bsim/bluetooth/host/gatt/authorization/src/common.c b/tests/bsim/bluetooth/host/gatt/authorization/src/common.c deleted file mode 100644 index adff2dd05ef..00000000000 --- a/tests/bsim/bluetooth/host/gatt/authorization/src/common.c +++ /dev/null @@ -1,20 +0,0 @@ -/* - * Copyright (c) 2024 Nordic Semiconductor ASA - * - * SPDX-License-Identifier: Apache-2.0 - */ - -#include "common.h" - -void test_tick(bs_time_t HW_device_time) -{ - if (bst_result != Passed) { - FAIL("test failed (not passed after %i seconds)\n", WAIT_TIME); - } -} - -void test_init(void) -{ - bst_ticker_set_next_tick_absolute(WAIT_TIME); - bst_result = In_progress; -} diff --git a/tests/bsim/bluetooth/host/gatt/authorization/src/common.h b/tests/bsim/bluetooth/host/gatt/authorization/src/common.h deleted file mode 100644 index 339919dfe88..00000000000 --- a/tests/bsim/bluetooth/host/gatt/authorization/src/common.h +++ /dev/null @@ -1,73 +0,0 @@ -/** - * Common functions and helpers for BSIM GATT tests - * - * Copyright (c) 2024 Nordic Semiconductor ASA - * - * SPDX-License-Identifier: Apache-2.0 - */ - -#include - -#include "bs_types.h" -#include "bs_tracing.h" -#include "time_machine.h" -#include "bstests.h" - -#include -#include -#include - -#include -#include -#include -#include -#include - -extern enum bst_result_t bst_result; - -#define WAIT_TIME (30 * 1e6) /*seconds*/ - -#define CREATE_FLAG(flag) static atomic_t flag = (atomic_t)false -#define SET_FLAG(flag) (void)atomic_set(&flag, (atomic_t)true) -#define UNSET_FLAG(flag) (void)atomic_set(&flag, (atomic_t)false) -#define WAIT_FOR_FLAG(flag) \ - while (!(bool)atomic_get(&flag)) { \ - (void)k_sleep(K_MSEC(1)); \ - } - -#define FAIL(...) \ - do { \ - bst_result = Failed; \ - bs_trace_error_time_line(__VA_ARGS__); \ - } while (0) - -#define PASS(...) \ - do { \ - bst_result = Passed; \ - bs_trace_info_time(1, __VA_ARGS__); \ - } while (0) - -#define CHRC_SIZE 10 - -#define TEST_SERVICE_UUID \ - BT_UUID_DECLARE_128(0x01, 0x23, 0x45, 0x67, 0x89, 0x01, 0x02, 0x03, \ - 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x00, 0x00) - -#define TEST_UNHANDLED_CHRC_UUID \ - BT_UUID_DECLARE_128(0x01, 0x23, 0x45, 0x67, 0x89, 0x01, 0x02, 0x03, \ - 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0xFD, 0x00) - -#define TEST_UNAUTHORIZED_CHRC_UUID \ - BT_UUID_DECLARE_128(0x01, 0x23, 0x45, 0x67, 0x89, 0x01, 0x02, 0x03, \ - 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0xFE, 0x00) - -#define TEST_AUTHORIZED_CHRC_UUID \ - BT_UUID_DECLARE_128(0x01, 0x23, 0x45, 0x67, 0x89, 0x01, 0x02, 0x03, \ - 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0xFF, 0x00) - -#define TEST_CP_CHRC_UUID \ - BT_UUID_DECLARE_128(0x01, 0x23, 0x45, 0x67, 0x89, 0x01, 0x02, 0x03, \ - 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0xF0, 0x00) - -void test_tick(bs_time_t HW_device_time); -void test_init(void); diff --git a/tests/bsim/bluetooth/host/gatt/authorization/src/gatt_client_test.c b/tests/bsim/bluetooth/host/gatt/authorization/src/gatt_client_test.c deleted file mode 100644 index 9c60c5b57b2..00000000000 --- a/tests/bsim/bluetooth/host/gatt/authorization/src/gatt_client_test.c +++ /dev/null @@ -1,341 +0,0 @@ -/* - * Copyright (c) 2024 Nordic Semiconductor ASA - * - * SPDX-License-Identifier: Apache-2.0 - */ - -#include -#include - -#include "common.h" - -CREATE_FLAG(flag_is_connected); -CREATE_FLAG(flag_discover_complete); -CREATE_FLAG(flag_write_complete); -CREATE_FLAG(flag_read_complete); - -static struct bt_conn *g_conn; -static uint16_t unhandled_chrc_handle; -static uint16_t unauthorized_chrc_handle; -static uint16_t authorized_chrc_handle; -static uint16_t cp_chrc_handle; -static const struct bt_uuid *test_svc_uuid = TEST_SERVICE_UUID; - -#define ARRAY_ITEM(i, _) i -static uint8_t chrc_data[] = { LISTIFY(CHRC_SIZE, ARRAY_ITEM, (,)) }; /* 1, 2, 3 ... */ - -static void connected(struct bt_conn *conn, uint8_t err) -{ - char addr[BT_ADDR_LE_STR_LEN]; - - bt_addr_le_to_str(bt_conn_get_dst(conn), addr, sizeof(addr)); - - if (err != 0) { - FAIL("Failed to connect to %s (%u)\n", addr, err); - return; - } - - printk("Connected to %s\n", addr); - - __ASSERT_NO_MSG(g_conn == conn); - - SET_FLAG(flag_is_connected); -} - -static void disconnected(struct bt_conn *conn, uint8_t reason) -{ - char addr[BT_ADDR_LE_STR_LEN]; - - if (conn != g_conn) { - return; - } - - bt_addr_le_to_str(bt_conn_get_dst(conn), addr, sizeof(addr)); - - printk("Disconnected: %s (reason 0x%02x)\n", addr, reason); - - bt_conn_unref(g_conn); - - g_conn = NULL; - UNSET_FLAG(flag_is_connected); -} - -BT_CONN_CB_DEFINE(conn_callbacks) = { - .connected = connected, - .disconnected = disconnected, -}; - -void device_found(const bt_addr_le_t *addr, int8_t rssi, uint8_t type, - struct net_buf_simple *ad) -{ - char addr_str[BT_ADDR_LE_STR_LEN]; - int err; - - if (g_conn != NULL) { - return; - } - - /* We're only interested in connectable events */ - if (type != BT_HCI_ADV_IND && type != BT_HCI_ADV_DIRECT_IND) { - return; - } - - bt_addr_le_to_str(addr, addr_str, sizeof(addr_str)); - printk("Device found: %s (RSSI %d)\n", addr_str, rssi); - - printk("Stopping scan\n"); - err = bt_le_scan_stop(); - if (err != 0) { - FAIL("Could not stop scan: %d"); - return; - } - - err = bt_conn_le_create(addr, BT_CONN_LE_CREATE_CONN, - BT_LE_CONN_PARAM_DEFAULT, &g_conn); - if (err != 0) { - FAIL("Could not connect to peer: %d", err); - } -} - -static uint8_t discover_func(struct bt_conn *conn, - const struct bt_gatt_attr *attr, - struct bt_gatt_discover_params *params) -{ - int err; - - if (attr == NULL) { - if (unhandled_chrc_handle == 0 || - unauthorized_chrc_handle == 0 || - authorized_chrc_handle == 0) { - FAIL("Did not discover required characterstics"); - } - - (void)memset(params, 0, sizeof(*params)); - - SET_FLAG(flag_discover_complete); - - return BT_GATT_ITER_STOP; - } - - printk("[ATTRIBUTE] handle %u\n", attr->handle); - - if (params->type == BT_GATT_DISCOVER_PRIMARY && - bt_uuid_cmp(params->uuid, TEST_SERVICE_UUID) == 0) { - printk("Found test service\n"); - params->uuid = NULL; - params->start_handle = attr->handle + 1; - params->type = BT_GATT_DISCOVER_CHARACTERISTIC; - - err = bt_gatt_discover(conn, params); - if (err != 0) { - FAIL("Discover failed (err %d)\n", err); - } - - return BT_GATT_ITER_STOP; - } else if (params->type == BT_GATT_DISCOVER_CHARACTERISTIC) { - struct bt_gatt_chrc *chrc = (struct bt_gatt_chrc *)attr->user_data; - - if (bt_uuid_cmp(chrc->uuid, TEST_UNHANDLED_CHRC_UUID) == 0) { - printk("Found unhandled chrc\n"); - unhandled_chrc_handle = chrc->value_handle; - } else if (bt_uuid_cmp(chrc->uuid, TEST_UNAUTHORIZED_CHRC_UUID) == 0) { - printk("Found unauthorized\n"); - unauthorized_chrc_handle = chrc->value_handle; - } else if (bt_uuid_cmp(chrc->uuid, TEST_AUTHORIZED_CHRC_UUID) == 0) { - printk("Found authorized chrc\n"); - authorized_chrc_handle = chrc->value_handle; - } else if (bt_uuid_cmp(chrc->uuid, TEST_CP_CHRC_UUID) == 0) { - printk("Found CP chrc\n"); - cp_chrc_handle = chrc->value_handle; - } - } - - return BT_GATT_ITER_CONTINUE; -} - -static void gatt_discover(void) -{ - static struct bt_gatt_discover_params discover_params; - int err; - - printk("Discovering services and characteristics\n"); - - discover_params.uuid = test_svc_uuid; - discover_params.func = discover_func; - discover_params.start_handle = BT_ATT_FIRST_ATTRIBUTE_HANDLE; - discover_params.end_handle = BT_ATT_LAST_ATTRIBUTE_HANDLE; - discover_params.type = BT_GATT_DISCOVER_PRIMARY; - - err = bt_gatt_discover(g_conn, &discover_params); - if (err != 0) { - FAIL("Discover failed(err %d)\n", err); - } - - WAIT_FOR_FLAG(flag_discover_complete); - printk("Discover complete\n"); -} - -static void gatt_write_cb(struct bt_conn *conn, uint8_t err, - struct bt_gatt_write_params *params) -{ - if ((err != BT_ATT_ERR_SUCCESS) && (params->handle != unauthorized_chrc_handle)) { - FAIL("Write failed on authorized characteristics: 0x%02X\n", err); - } - - if ((err != BT_ATT_ERR_AUTHORIZATION) && (params->handle == unauthorized_chrc_handle)) { - FAIL("Write failed on unauthorized characteristics: 0x%02X\n", err); - } - - (void)memset(params, 0, sizeof(*params)); - - SET_FLAG(flag_write_complete); -} - -static void gatt_write(uint16_t handle) -{ - static struct bt_gatt_write_params write_params; - int err; - - printk("Writing to chrc\n"); - - write_params.data = chrc_data; - write_params.length = sizeof(chrc_data); - write_params.func = gatt_write_cb; - write_params.handle = handle; - - UNSET_FLAG(flag_write_complete); - - err = bt_gatt_write(g_conn, &write_params); - if (err != 0) { - FAIL("bt_gatt_write failed: %d\n", err); - } - - WAIT_FOR_FLAG(flag_write_complete); - printk("success\n"); -} - -static void gatt_cp_write(void) -{ - static struct bt_gatt_write_params write_params; - int err; - uint8_t cp_write_data[] = {0x00}; - - printk("Writing to CP chrc\n"); - - write_params.data = cp_write_data; - write_params.length = sizeof(cp_write_data); - write_params.func = gatt_write_cb; - write_params.handle = cp_chrc_handle; - - UNSET_FLAG(flag_write_complete); - - err = bt_gatt_write(g_conn, &write_params); - if (err != 0) { - FAIL("bt_gatt_write failed: %d\n", err); - } - - WAIT_FOR_FLAG(flag_write_complete); - printk("success\n"); -} - -static uint8_t gatt_read_cb(struct bt_conn *conn, uint8_t err, - struct bt_gatt_read_params *params, - const void *data, uint16_t length) -{ - if ((err != BT_ATT_ERR_SUCCESS) && - (params->single.handle != unauthorized_chrc_handle)) { - FAIL("Read failed on authorized characteristics: 0x%02X\n", err); - - if ((length != CHRC_SIZE) || (memcmp(data, chrc_data, length) != 0)) { - FAIL("chrc data different than expected", err); - } - } - - if ((err != BT_ATT_ERR_AUTHORIZATION) && - (params->single.handle == unauthorized_chrc_handle)) { - FAIL("Read failed on unauthorized characteristics: 0x%02X\n", err); - } - - (void)memset(params, 0, sizeof(*params)); - - SET_FLAG(flag_read_complete); - - return 0; -} - -static void gatt_read(uint16_t handle) -{ - static struct bt_gatt_read_params read_params; - int err; - - printk("Reading chrc\n"); - - read_params.func = gatt_read_cb; - read_params.handle_count = 1; - read_params.single.handle = handle; - read_params.single.offset = 0; - - UNSET_FLAG(flag_read_complete); - - err = bt_gatt_read(g_conn, &read_params); - if (err != 0) { - FAIL("bt_gatt_read failed: %d\n", err); - } - - WAIT_FOR_FLAG(flag_read_complete); - printk("success\n"); -} - -static void gatt_interact(uint16_t handle) -{ - gatt_write(handle); - gatt_read(handle); - gatt_cp_write(); -} - -static void test_main(void) -{ - int err; - - err = bt_enable(NULL); - if (err != 0) { - FAIL("Bluetooth discover failed (err %d)\n", err); - } - - err = bt_le_scan_start(BT_LE_SCAN_PASSIVE, device_found); - if (err != 0) { - FAIL("Scanning failed to start (err %d)\n", err); - } - - printk("Scanning successfully started\n"); - - WAIT_FOR_FLAG(flag_is_connected); - - gatt_discover(); - - printk("Interacting with the unhandled characteristic\n"); - gatt_interact(unhandled_chrc_handle); - - printk("Interacting with the unauthorized characteristic\n"); - gatt_interact(unauthorized_chrc_handle); - - printk("Interacting with the authorized characteristic\n"); - gatt_interact(authorized_chrc_handle); - - PASS("GATT client Passed\n"); -} - -static const struct bst_test_instance test_vcs[] = { - { - .test_id = "gatt_client", - .test_post_init_f = test_init, - .test_tick_f = test_tick, - .test_main_f = test_main - }, - BSTEST_END_MARKER -}; - -struct bst_test_list *test_gatt_client_install(struct bst_test_list *tests) -{ - return bst_add_tests(tests, test_vcs); -} diff --git a/tests/bsim/bluetooth/host/gatt/authorization/src/gatt_server_test.c b/tests/bsim/bluetooth/host/gatt/authorization/src/gatt_server_test.c deleted file mode 100644 index d5dd5e0e0a7..00000000000 --- a/tests/bsim/bluetooth/host/gatt/authorization/src/gatt_server_test.c +++ /dev/null @@ -1,370 +0,0 @@ -/* - * Copyright (c) 2024 Nordic Semiconductor ASA - * - * SPDX-License-Identifier: Apache-2.0 - */ - -#include "common.h" - -extern enum bst_result_t bst_result; - -CREATE_FLAG(flag_is_chrc_ctx_validated); - -static struct bt_conn *g_conn; - -static void connected(struct bt_conn *conn, uint8_t err) -{ - char addr[BT_ADDR_LE_STR_LEN]; - - bt_addr_le_to_str(bt_conn_get_dst(conn), addr, sizeof(addr)); - - if (err != 0) { - FAIL("Failed to connect to %s (%u)\n", addr, err); - return; - } - - printk("Connected to %s\n", addr); - - g_conn = bt_conn_ref(conn); -} - -static void disconnected(struct bt_conn *conn, uint8_t reason) -{ - char addr[BT_ADDR_LE_STR_LEN]; - - if (conn != g_conn) { - return; - } - - bt_addr_le_to_str(bt_conn_get_dst(conn), addr, sizeof(addr)); - - printk("Disconnected: %s (reason 0x%02x)\n", addr, reason); - - bt_conn_unref(g_conn); - - g_conn = NULL; -} - -BT_CONN_CB_DEFINE(conn_callbacks) = { - .connected = connected, - .disconnected = disconnected, -}; - -struct test_chrc_ctx { - uint16_t auth_read_cnt; - uint16_t read_cnt; - uint16_t auth_write_cnt; - uint16_t write_cnt; - uint8_t data[CHRC_SIZE]; -}; - -static ssize_t read_test_chrc(struct test_chrc_ctx *chrc_ctx, - struct bt_conn *conn, - const struct bt_gatt_attr *attr, - void *buf, uint16_t len, uint16_t offset) -{ - chrc_ctx->read_cnt++; - - return bt_gatt_attr_read(conn, attr, buf, len, offset, - (void *)chrc_ctx->data, - sizeof(chrc_ctx->data)); -} - -static ssize_t write_test_chrc(struct test_chrc_ctx *chrc_ctx, - const void *buf, uint16_t len, - uint16_t offset, uint8_t flags) -{ - chrc_ctx->write_cnt++; - - if (len != sizeof(chrc_ctx->data)) { - printk("Invalid chrc length\n"); - return BT_GATT_ERR(BT_ATT_ERR_INVALID_ATTRIBUTE_LEN); - } - - if (offset != 0) { - printk("Invalid chrc offset and length\n"); - return BT_GATT_ERR(BT_ATT_ERR_INVALID_OFFSET); - } - - if (flags != 0) { - FAIL("Invalid flags %u\n", flags); - return BT_GATT_ERR(BT_ATT_ERR_UNLIKELY); - } - - (void)memcpy(chrc_ctx->data, buf, len); - - return len; -} - -static struct test_chrc_ctx unhandled_chrc_ctx; - -static ssize_t read_test_unhandled_chrc(struct bt_conn *conn, - const struct bt_gatt_attr *attr, - void *buf, uint16_t len, uint16_t offset) -{ - return read_test_chrc(&unhandled_chrc_ctx, conn, attr, buf, len, offset); -} - -static ssize_t write_test_unhandled_chrc(struct bt_conn *conn, - const struct bt_gatt_attr *attr, - const void *buf, uint16_t len, - uint16_t offset, uint8_t flags) -{ - printk("unhandled chrc len %u offset %u\n", len, offset); - - return write_test_chrc(&unhandled_chrc_ctx, buf, len, offset, flags); -} - -static struct test_chrc_ctx unauthorized_chrc_ctx; - -static ssize_t read_test_unauthorized_chrc(struct bt_conn *conn, - const struct bt_gatt_attr *attr, - void *buf, uint16_t len, uint16_t offset) -{ - return read_test_chrc(&unauthorized_chrc_ctx, conn, attr, buf, len, offset); -} - -static ssize_t write_test_unauthorized_chrc(struct bt_conn *conn, - const struct bt_gatt_attr *attr, - const void *buf, uint16_t len, - uint16_t offset, uint8_t flags) -{ - printk("unauthorized chrc len %u offset %u\n", len, offset); - - return write_test_chrc(&unauthorized_chrc_ctx, buf, len, offset, flags); -} - -static struct test_chrc_ctx authorized_chrc_ctx; - -static ssize_t read_test_authorized_chrc(struct bt_conn *conn, - const struct bt_gatt_attr *attr, - void *buf, uint16_t len, uint16_t offset) -{ - return read_test_chrc(&authorized_chrc_ctx, conn, attr, buf, len, offset); -} - -static ssize_t write_test_authorized_chrc(struct bt_conn *conn, - const struct bt_gatt_attr *attr, - const void *buf, uint16_t len, - uint16_t offset, uint8_t flags) -{ - printk("authorized chrc len %u offset %u\n", len, offset); - - return write_test_chrc(&authorized_chrc_ctx, buf, len, offset, flags); -} - -static const struct test_chrc_ctx zeroed_chrc_ctx; - -static bool unhandled_chrc_operation_validate(void) -{ - if (memcmp(&unauthorized_chrc_ctx, &zeroed_chrc_ctx, sizeof(zeroed_chrc_ctx)) != 0) { - return false; - } - - if (memcmp(&authorized_chrc_ctx, &zeroed_chrc_ctx, sizeof(zeroed_chrc_ctx)) != 0) { - return false; - } - - if ((unhandled_chrc_ctx.read_cnt != 1) && (unhandled_chrc_ctx.write_cnt != 1)) { - return false; - } - - if ((unhandled_chrc_ctx.auth_read_cnt != 0) && - (unhandled_chrc_ctx.auth_write_cnt != 0)) { - return false; - } - - return true; -} - -static bool unauthorized_chrc_operation_validate(void) -{ - if (memcmp(&unhandled_chrc_ctx, &zeroed_chrc_ctx, sizeof(zeroed_chrc_ctx)) != 0) { - return false; - } - - if (memcmp(&authorized_chrc_ctx, &zeroed_chrc_ctx, sizeof(zeroed_chrc_ctx)) != 0) { - return false; - } - - if ((unauthorized_chrc_ctx.read_cnt != 0) && (unauthorized_chrc_ctx.write_cnt != 0)) { - return false; - } - - if ((unauthorized_chrc_ctx.auth_read_cnt != 1) && - (unauthorized_chrc_ctx.auth_write_cnt != 1)) { - return false; - } - - return true; -} - -static bool authorized_chrc_operation_validate(void) -{ - if (memcmp(&unhandled_chrc_ctx, &zeroed_chrc_ctx, sizeof(zeroed_chrc_ctx)) != 0) { - return false; - } - - if (memcmp(&unauthorized_chrc_ctx, &zeroed_chrc_ctx, sizeof(zeroed_chrc_ctx)) != 0) { - return false; - } - - if ((authorized_chrc_ctx.read_cnt != 1) && (authorized_chrc_ctx.write_cnt != 1)) { - return false; - } - - if ((authorized_chrc_ctx.auth_read_cnt != 1) && - (authorized_chrc_ctx.auth_write_cnt != 1)) { - return false; - } - - return true; -} - -static ssize_t write_cp_chrc(struct bt_conn *conn, - const struct bt_gatt_attr *attr, - const void *buf, uint16_t len, - uint16_t offset, uint8_t flags) -{ - static uint16_t cp_write_cnt; - bool pass; - char *log_str; - - if (cp_write_cnt == 0) { - pass = unhandled_chrc_operation_validate(); - log_str = "unhandled"; - } else if (cp_write_cnt == 1) { - pass = unauthorized_chrc_operation_validate(); - log_str = "unauthorized"; - } else if (cp_write_cnt == 2) { - pass = authorized_chrc_operation_validate(); - log_str = "authorized"; - } else { - FAIL("Invalid value of CP write counter %u\n", cp_write_cnt); - return BT_GATT_ERR(BT_ATT_ERR_UNLIKELY); - } - - if (pass) { - printk("Correct context for %s chrc\n", log_str); - } else { - FAIL("Invalid context for %s chrc\n", log_str); - return BT_GATT_ERR(BT_ATT_ERR_UNLIKELY); - } - - memset(&unhandled_chrc_ctx, 0, sizeof(unhandled_chrc_ctx)); - memset(&unauthorized_chrc_ctx, 0, sizeof(unauthorized_chrc_ctx)); - memset(&authorized_chrc_ctx, 0, sizeof(authorized_chrc_ctx)); - - cp_write_cnt++; - - if (cp_write_cnt == 3) { - SET_FLAG(flag_is_chrc_ctx_validated); - } - - return len; -} - -BT_GATT_SERVICE_DEFINE(test_svc, - BT_GATT_PRIMARY_SERVICE(TEST_SERVICE_UUID), - BT_GATT_CHARACTERISTIC(TEST_UNHANDLED_CHRC_UUID, - BT_GATT_CHRC_WRITE | BT_GATT_CHRC_READ, - BT_GATT_PERM_WRITE | BT_GATT_PERM_READ, - read_test_unhandled_chrc, - write_test_unhandled_chrc, NULL), - BT_GATT_CHARACTERISTIC(TEST_UNAUTHORIZED_CHRC_UUID, - BT_GATT_CHRC_WRITE | BT_GATT_CHRC_READ, - BT_GATT_PERM_WRITE | BT_GATT_PERM_READ, - read_test_unauthorized_chrc, - write_test_unauthorized_chrc, NULL), - BT_GATT_CHARACTERISTIC(TEST_AUTHORIZED_CHRC_UUID, - BT_GATT_CHRC_WRITE | BT_GATT_CHRC_READ, - BT_GATT_PERM_WRITE | BT_GATT_PERM_READ, - read_test_authorized_chrc, - write_test_authorized_chrc, NULL), - BT_GATT_CHARACTERISTIC(TEST_CP_CHRC_UUID, - BT_GATT_CHRC_WRITE, - BT_GATT_PERM_WRITE, - NULL, write_cp_chrc, NULL), -); - -static bool gatt_read_operation_authorize(struct bt_conn *conn, - const struct bt_gatt_attr *attr) -{ - if (bt_uuid_cmp(attr->uuid, TEST_UNAUTHORIZED_CHRC_UUID) == 0) { - unauthorized_chrc_ctx.auth_read_cnt++; - return false; - } else if (bt_uuid_cmp(attr->uuid, TEST_AUTHORIZED_CHRC_UUID) == 0) { - authorized_chrc_ctx.auth_read_cnt++; - return true; - } else { - return true; - } -} - -static bool gatt_write_operation_authorize(struct bt_conn *conn, - const struct bt_gatt_attr *attr) -{ - if (bt_uuid_cmp(attr->uuid, TEST_UNAUTHORIZED_CHRC_UUID) == 0) { - unauthorized_chrc_ctx.auth_write_cnt++; - return false; - } else if (bt_uuid_cmp(attr->uuid, TEST_AUTHORIZED_CHRC_UUID) == 0) { - authorized_chrc_ctx.auth_write_cnt++; - return true; - } else { - return true; - } -} - -static const struct bt_gatt_authorization_cb gatt_authorization_callbacks = { - .read_operation_authorize = gatt_read_operation_authorize, - .write_operation_authorize = gatt_write_operation_authorize, -}; - -static void test_main(void) -{ - int err; - const struct bt_data ad[] = { - BT_DATA_BYTES(BT_DATA_FLAGS, (BT_LE_AD_GENERAL | BT_LE_AD_NO_BREDR)) - }; - - err = bt_gatt_authorization_cb_register(&gatt_authorization_callbacks); - if (err) { - FAIL("Registering GATT authorization callbacks failed (err %d)\n", err); - return; - } - - err = bt_enable(NULL); - if (err != 0) { - FAIL("Bluetooth init failed (err %d)\n", err); - return; - } - - printk("Bluetooth initialized\n"); - - err = bt_le_adv_start(BT_LE_ADV_CONN_NAME, ad, ARRAY_SIZE(ad), NULL, 0); - if (err != 0) { - FAIL("Advertising failed to start (err %d)\n", err); - return; - } - - printk("Advertising successfully started\n"); - - WAIT_FOR_FLAG(flag_is_chrc_ctx_validated); - - PASS("GATT server passed\n"); -} - -static const struct bst_test_instance test_gatt_server[] = { - { - .test_id = "gatt_server", - .test_post_init_f = test_init, - .test_tick_f = test_tick, - .test_main_f = test_main - }, - BSTEST_END_MARKER -}; - -struct bst_test_list *test_gatt_server_install(struct bst_test_list *tests) -{ - return bst_add_tests(tests, test_gatt_server); -} diff --git a/tests/bsim/bluetooth/host/gatt/authorization/src/main.c b/tests/bsim/bluetooth/host/gatt/authorization/src/main.c deleted file mode 100644 index a95f0285e75..00000000000 --- a/tests/bsim/bluetooth/host/gatt/authorization/src/main.c +++ /dev/null @@ -1,22 +0,0 @@ -/* - * Copyright (c) 2024 Nordic Semiconductor ASA - * - * SPDX-License-Identifier: Apache-2.0 - */ - -#include "bstests.h" - -extern struct bst_test_list *test_gatt_server_install(struct bst_test_list *tests); -extern struct bst_test_list *test_gatt_client_install(struct bst_test_list *tests); - -bst_test_install_t test_installers[] = { - test_gatt_server_install, - test_gatt_client_install, - NULL -}; - -int main(void) -{ - bst_main(); - return 0; -} diff --git a/tests/bsim/bluetooth/host/gatt/authorization/test_scripts/gatt.sh b/tests/bsim/bluetooth/host/gatt/authorization/test_scripts/gatt.sh deleted file mode 100755 index edad0eb86c9..00000000000 --- a/tests/bsim/bluetooth/host/gatt/authorization/test_scripts/gatt.sh +++ /dev/null @@ -1,22 +0,0 @@ -#!/usr/bin/env bash -# Copyright 2024 Nordic Semiconductor ASA -# SPDX-License-Identifier: Apache-2.0 - -source ${ZEPHYR_BASE}/tests/bsim/sh_common.source - -simulation_id="gatt_authorization" -verbosity_level=2 -EXECUTE_TIMEOUT=120 - -cd ${BSIM_OUT_PATH}/bin - -Execute ./bs_${BOARD}_tests_bsim_bluetooth_host_gatt_authorization_prj_conf \ - -v=${verbosity_level} -s=${simulation_id} -d=0 -testid=gatt_client - -Execute ./bs_${BOARD}_tests_bsim_bluetooth_host_gatt_authorization_prj_conf \ - -v=${verbosity_level} -s=${simulation_id} -d=1 -testid=gatt_server - -Execute ./bs_2G4_phy_v1 -v=${verbosity_level} -s=${simulation_id} \ - -D=2 -sim_length=60e6 $@ - -wait_for_background_jobs From f87aa461caa3db7c4fc4f8dc19e383b63e9ef93c Mon Sep 17 00:00:00 2001 From: Robert Lubos Date: Tue, 6 Feb 2024 11:07:01 +0100 Subject: [PATCH 3510/3723] Revert "[nrf fromtree] bluetooth: gatt: add authorization callback API for gatt operations" This reverts commit e537e00b1bc1325945dc9d29df13100d6ba2280a. Signed-off-by: Robert Lubos --- include/zephyr/bluetooth/gatt.h | 51 ------------------ subsys/bluetooth/host/Kconfig.gatt | 9 ---- subsys/bluetooth/host/att.c | 83 ------------------------------ 3 files changed, 143 deletions(-) diff --git a/include/zephyr/bluetooth/gatt.h b/include/zephyr/bluetooth/gatt.h index eb38f765afb..c53422648f0 100644 --- a/include/zephyr/bluetooth/gatt.h +++ b/include/zephyr/bluetooth/gatt.h @@ -235,37 +235,6 @@ struct bt_gatt_cb { sys_snode_t node; }; -/** @brief GATT authorization callback structure. */ -struct bt_gatt_authorization_cb { - /** @brief Authorize the GATT read operation. - * - * This callback allows the application to authorize the GATT - * read operation for the attribute that is being read. - * - * @param conn Connection object. - * @param attr The attribute that is being read. - * - * @retval true Authorize the operation and allow it to execute. - * @retval false Reject the operation and prevent it from executing. - */ - bool (*read_operation_authorize)(struct bt_conn *conn, - const struct bt_gatt_attr *attr); - - /** @brief Authorize the GATT write operation. - * - * This callback allows the application to authorize the GATT - * write operation for the attribute that is being written. - * - * @param conn Connection object. - * @param attr The attribute that is being written. - * - * @retval true Authorize the operation and allow it to execute. - * @retval false Reject the operation and prevent it from executing. - */ - bool (*write_operation_authorize)(struct bt_conn *conn, - const struct bt_gatt_attr *attr); -}; - /** Characteristic Properties Bit field values */ /** @@ -408,26 +377,6 @@ struct bt_gatt_cpf { */ void bt_gatt_cb_register(struct bt_gatt_cb *cb); -/** @brief Register GATT authorization callbacks. - * - * Register callbacks to perform application-specific authorization of GATT - * operations on all registered GATT attributes. The callback structure must - * remain valid throughout the entire duration of the Bluetooth subsys - * activity. - * - * The @kconfig{CONFIG_BT_GATT_AUTHORIZATION_CUSTOM} Kconfig must be enabled - * to make this API functional. - * - * This API allows the user to register only one callback structure - * concurrently. Passing NULL unregisters the previous set of callbacks - * and makes it possible to register a new one. - * - * @param cb Callback struct. - * - * @return Zero on success or negative error code otherwise - */ -int bt_gatt_authorization_cb_register(const struct bt_gatt_authorization_cb *cb); - /** @brief Register GATT service. * * Register GATT service. Applications can make use of diff --git a/subsys/bluetooth/host/Kconfig.gatt b/subsys/bluetooth/host/Kconfig.gatt index a2364bbe557..9209368f943 100644 --- a/subsys/bluetooth/host/Kconfig.gatt +++ b/subsys/bluetooth/host/Kconfig.gatt @@ -276,13 +276,4 @@ config DEVICE_NAME_GATT_WRITABLE_AUTHEN endif #BT_DEVICE_NAME_GATT_WRITABLE -config BT_GATT_AUTHORIZATION_CUSTOM - bool "Custom authorization of GATT operations [EXPERIMENTAL]" - select EXPERIMENTAL - help - This option allows the user to define application-specific - authorization logic for GATT operations that can be registered - with the bt_gatt_authorization_cb_register API. See the API - documentation for more details. - endmenu diff --git a/subsys/bluetooth/host/att.c b/subsys/bluetooth/host/att.c index 44862f5bf25..130b4ab0853 100644 --- a/subsys/bluetooth/host/att.c +++ b/subsys/bluetooth/host/att.c @@ -115,11 +115,6 @@ static uint16_t bt_att_mtu(struct bt_att_chan *chan) return MIN(chan->chan.rx.mtu, chan->chan.tx.mtu); } -/* Descriptor of application-specific authorization callbacks that are used - * with the CONFIG_BT_GATT_AUTHORIZATION_CUSTOM Kconfig enabled. - */ -const static struct bt_gatt_authorization_cb *authorization_cb; - /* ATT connection specific data */ struct bt_att { struct bt_conn *conn; @@ -1294,20 +1289,6 @@ struct read_type_data { typedef bool (*attr_read_cb)(struct net_buf *buf, ssize_t read, void *user_data); -static bool attr_read_authorize(struct bt_conn *conn, - const struct bt_gatt_attr *attr) -{ - if (!IS_ENABLED(CONFIG_BT_GATT_AUTHORIZATION_CUSTOM)) { - return true; - } - - if (!authorization_cb || !authorization_cb->read_operation_authorize) { - return true; - } - - return authorization_cb->read_operation_authorize(conn, attr); -} - static bool attr_read_type_cb(struct net_buf *frag, ssize_t read, void *user_data) { @@ -1417,12 +1398,6 @@ static uint8_t read_type_cb(const struct bt_gatt_attr *attr, uint16_t handle, return BT_GATT_ITER_STOP; } - /* Check the attribute authorization logic */ - if (!attr_read_authorize(conn, attr)) { - data->err = BT_ATT_ERR_AUTHORIZATION; - return BT_GATT_ITER_STOP; - } - /* * If any attribute is founded in handle range it means that error * should be changed from pre-set: attr not found error to no error. @@ -1551,12 +1526,6 @@ static uint8_t read_cb(const struct bt_gatt_attr *attr, uint16_t handle, return BT_GATT_ITER_STOP; } - /* Check the attribute authorization logic */ - if (!attr_read_authorize(conn, attr)) { - data->err = BT_ATT_ERR_AUTHORIZATION; - return BT_GATT_ITER_STOP; - } - /* Read attribute value and store in the buffer */ ret = att_chan_read(chan, attr, data->buf, data->offset, NULL, NULL); if (ret < 0) { @@ -1724,12 +1693,6 @@ static uint8_t read_vl_cb(const struct bt_gatt_attr *attr, uint16_t handle, return BT_GATT_ITER_STOP; } - /* Check the attribute authorization logic */ - if (!attr_read_authorize(conn, attr)) { - data->err = BT_ATT_ERR_AUTHORIZATION; - return BT_GATT_ITER_STOP; - } - /* The Length Value Tuple List may be truncated within the first two * octets of a tuple due to the size limits of the current ATT_MTU. */ @@ -1977,20 +1940,6 @@ struct write_data { uint8_t err; }; -static bool attr_write_authorize(struct bt_conn *conn, - const struct bt_gatt_attr *attr) -{ - if (!IS_ENABLED(CONFIG_BT_GATT_AUTHORIZATION_CUSTOM)) { - return true; - } - - if (!authorization_cb || !authorization_cb->write_operation_authorize) { - return true; - } - - return authorization_cb->write_operation_authorize(conn, attr); -} - static uint8_t write_cb(const struct bt_gatt_attr *attr, uint16_t handle, void *user_data) { @@ -2007,12 +1956,6 @@ static uint8_t write_cb(const struct bt_gatt_attr *attr, uint16_t handle, return BT_GATT_ITER_STOP; } - /* Check the attribute authorization logic */ - if (!attr_write_authorize(data->conn, attr)) { - data->err = BT_ATT_ERR_AUTHORIZATION; - return BT_GATT_ITER_STOP; - } - /* Set command flag if not a request */ if (!data->req) { flags |= BT_GATT_WRITE_FLAG_CMD; @@ -2126,12 +2069,6 @@ static uint8_t prep_write_cb(const struct bt_gatt_attr *attr, uint16_t handle, return BT_GATT_ITER_STOP; } - /* Check the attribute authorization logic */ - if (!attr_write_authorize(data->conn, attr)) { - data->err = BT_ATT_ERR_AUTHORIZATION; - return BT_GATT_ITER_STOP; - } - /* Check if attribute requires handler to accept the data */ if (!(attr->perm & BT_GATT_PERM_PREPARE_WRITE)) { goto append; @@ -4060,23 +3997,3 @@ bool bt_att_chan_opt_valid(struct bt_conn *conn, enum bt_att_chan_opt chan_opt) return true; } - -int bt_gatt_authorization_cb_register(const struct bt_gatt_authorization_cb *cb) -{ - if (!IS_ENABLED(CONFIG_BT_GATT_AUTHORIZATION_CUSTOM)) { - return -ENOSYS; - } - - if (!cb) { - authorization_cb = NULL; - return 0; - } - - if (authorization_cb) { - return -EALREADY; - } - - authorization_cb = cb; - - return 0; -} From 3bedfc7640fa54b8ebcd8b8e1bda02db804fefad Mon Sep 17 00:00:00 2001 From: Robert Lubos Date: Tue, 6 Feb 2024 11:07:01 +0100 Subject: [PATCH 3511/3723] Revert "[nrf fromtree] net: shell: Implement DHCPv4 server shell commands" This reverts commit d97e4bc99ec6a3bbd96ebfa4a16b2a3a7efcf94f. Signed-off-by: Robert Lubos --- subsys/net/lib/shell/CMakeLists.txt | 1 - subsys/net/lib/shell/dhcpv4.c | 215 ---------------------------- 2 files changed, 216 deletions(-) delete mode 100644 subsys/net/lib/shell/dhcpv4.c diff --git a/subsys/net/lib/shell/CMakeLists.txt b/subsys/net/lib/shell/CMakeLists.txt index 5cfb5c269b4..2c5c0757505 100644 --- a/subsys/net/lib/shell/CMakeLists.txt +++ b/subsys/net/lib/shell/CMakeLists.txt @@ -10,7 +10,6 @@ zephyr_library_sources(allocs.c) zephyr_library_sources(arp.c) zephyr_library_sources(capture.c) zephyr_library_sources(conn.c) -zephyr_library_sources(dhcpv4.c) zephyr_library_sources(dns.c) zephyr_library_sources(events.c) zephyr_library_sources(gptp.c) diff --git a/subsys/net/lib/shell/dhcpv4.c b/subsys/net/lib/shell/dhcpv4.c deleted file mode 100644 index a59b9c45edb..00000000000 --- a/subsys/net/lib/shell/dhcpv4.c +++ /dev/null @@ -1,215 +0,0 @@ -/* - * Copyright (c) 2024 Nordic Semiconductor ASA - * - * SPDX-License-Identifier: Apache-2.0 - */ - -#include -LOG_MODULE_DECLARE(net_shell); - -#include -#include -#include - -#include "net_shell_private.h" - -static int cmd_net_dhcpv4_server_start(const struct shell *sh, size_t argc, char *argv[]) -{ -#if defined(CONFIG_NET_DHCPV4_SERVER) - struct net_if *iface = NULL; - struct in_addr base_addr; - int idx, ret; - - idx = get_iface_idx(sh, argv[1]); - if (idx < 0) { - return -ENOEXEC; - } - - iface = net_if_get_by_index(idx); - if (!iface) { - PR_WARNING("No such interface in index %d\n", idx); - return -ENOEXEC; - } - - if (net_addr_pton(AF_INET, argv[2], &base_addr)) { - PR_ERROR("Invalid address: %s\n", argv[2]); - return -EINVAL; - } - - ret = net_dhcpv4_server_start(iface, &base_addr); - if (ret == -EALREADY) { - PR_WARNING("DHCPv4 server already running on interface %d\n", idx); - } else if (ret < 0) { - PR_ERROR("DHCPv4 server failed to start on interface %d, error %d\n", - idx, -ret); - } else { - PR("DHCPv4 server started on interface %d\n", idx); - } -#else /* CONFIG_NET_DHCPV4_SERVER */ - PR_INFO("Set %s to enable %s support.\n", - "CONFIG_NET_DHCPV4_SERVER", "DHCPv4 server"); -#endif /* CONFIG_NET_DHCPV4_SERVER */ - return 0; -} - -static int cmd_net_dhcpv4_server_stop(const struct shell *sh, size_t argc, char *argv[]) -{ -#if defined(CONFIG_NET_DHCPV4_SERVER) - struct net_if *iface = NULL; - int idx, ret; - - idx = get_iface_idx(sh, argv[1]); - if (idx < 0) { - return -ENOEXEC; - } - - iface = net_if_get_by_index(idx); - if (!iface) { - PR_WARNING("No such interface in index %d\n", idx); - return -ENOEXEC; - } - - ret = net_dhcpv4_server_stop(iface); - if (ret == -ENOENT) { - PR_WARNING("DHCPv4 server is not running on interface %d\n", idx); - } else if (ret < 0) { - PR_ERROR("DHCPv4 server failed to stop on interface %d, error %d\n", - idx, -ret); - } else { - PR("DHCPv4 server stopped on interface %d\n", idx); - } -#else /* CONFIG_NET_DHCPV4_SERVER */ - PR_INFO("Set %s to enable %s support.\n", - "CONFIG_NET_DHCPV4_SERVER", "DHCPv4 server"); -#endif /* CONFIG_NET_DHCPV4_SERVER */ - return 0; -} - -#if defined(CONFIG_NET_DHCPV4_SERVER) -static const char *dhcpv4_addr_state_to_str(enum dhcpv4_server_addr_state state) -{ - switch (state) { - case DHCPV4_SERVER_ADDR_FREE: - return "FREE"; - case DHCPV4_SERVER_ADDR_RESERVED: - return "RESERVED"; - case DHCPV4_SERVER_ADDR_ALLOCATED: - return "ALLOCATED"; - case DHCPV4_SERVER_ADDR_DECLINED: - return "DECLINED"; - } - - return ""; -} - -static uint32_t timepoint_to_s(k_timepoint_t timepoint) -{ - k_timeout_t timeout = sys_timepoint_timeout(timepoint); - - if (K_TIMEOUT_EQ(timeout, K_NO_WAIT)) { - return 0; - } - - if (K_TIMEOUT_EQ(timeout, K_FOREVER)) { - return UINT32_MAX; - } - - return k_ticks_to_ms_floor64(timeout.ticks) / 1000; -} - -static void dhcpv4_lease_cb(struct net_if *iface, - struct dhcpv4_addr_slot *lease, - void *user_data) -{ - struct net_shell_user_data *data = user_data; - const struct shell *sh = data->sh; - int *count = data->user_data; - char expiry_str[] = "4294967295"; /* Lease time is uint32_t, so take - * theoretical max. - */ - char iface_name[IFNAMSIZ] = ""; - - if (*count == 0) { - PR(" Iface Address\t State\tExpiry (sec)\n"); - } - - (*count)++; - - (void)net_if_get_name(iface, iface_name, sizeof(iface_name)); - - if (lease->state == DHCPV4_SERVER_ADDR_DECLINED) { - snprintk(expiry_str, sizeof(expiry_str) - 1, "infinite"); - } else { - snprintk(expiry_str, sizeof(expiry_str) - 1, "%u", - timepoint_to_s(lease->expiry)); - } - - PR("%2d. %6s %15s\t%9s\t%12s\n", - *count, iface_name, net_sprint_ipv4_addr(&lease->addr), - dhcpv4_addr_state_to_str(lease->state), expiry_str); -} -#endif /* CONFIG_NET_DHCPV4_SERVER */ - -static int cmd_net_dhcpv4_server_status(const struct shell *sh, size_t argc, char *argv[]) -{ -#if defined(CONFIG_NET_DHCPV4_SERVER) - struct net_shell_user_data user_data; - struct net_if *iface = NULL; - int idx = 0, ret; - int count = 0; - - if (argc > 1) { - idx = get_iface_idx(sh, argv[1]); - if (idx < 0) { - return -ENOEXEC; - } - - iface = net_if_get_by_index(idx); - if (!iface) { - PR_WARNING("No such interface in index %d\n", idx); - return -ENOEXEC; - } - } - - user_data.sh = sh; - user_data.user_data = &count; - - ret = net_dhcpv4_server_foreach_lease(iface, dhcpv4_lease_cb, &user_data); - if (ret == -ENOENT) { - PR_WARNING("DHCPv4 server is not running on interface %d\n", idx); - } else if (count == 0) { - PR("DHCPv4 server - no addresses assigned\n"); - } -#else /* CONFIG_NET_DHCPV4_SERVER */ - PR_INFO("Set %s to enable %s support.\n", - "CONFIG_NET_DHCPV4_SERVER", "DHCPv4 server"); -#endif /* CONFIG_NET_DHCPV4_SERVER */ - return 0; -} - -SHELL_STATIC_SUBCMD_SET_CREATE(net_cmd_dhcpv4_server, - SHELL_CMD_ARG(start, NULL, "Start the DHCPv4 server operation on the interface.\n" - "'net dhcpv4 server start '\n" - " is the network interface index.\n" - " is the first address for the address pool.", - cmd_net_dhcpv4_server_start, 3, 0), - SHELL_CMD_ARG(stop, NULL, "Stop the DHCPv4 server operation on the interface.\n" - "'net dhcpv4 server stop '\n" - " is the network interface index.", - cmd_net_dhcpv4_server_stop, 2, 0), - SHELL_CMD_ARG(status, NULL, "Print the DHCPv4 server status on the interface.\n" - "'net dhcpv4 server status '\n" - " is the network interface index. Optional.", - cmd_net_dhcpv4_server_status, 1, 1), - SHELL_SUBCMD_SET_END -); - -SHELL_STATIC_SUBCMD_SET_CREATE(net_cmd_dhcpv4, - SHELL_CMD(server, &net_cmd_dhcpv4_server, - "DHCPv4 server service management.", - NULL), - SHELL_SUBCMD_SET_END -); - -SHELL_SUBCMD_ADD((net), dhcpv4, &net_cmd_dhcpv4, "Manage DHPCv4 services.", - NULL, 1, 0); From 693fd4ee5d10ae083936f6b91637748e7a3f32f2 Mon Sep 17 00:00:00 2001 From: Robert Lubos Date: Tue, 6 Feb 2024 11:07:01 +0100 Subject: [PATCH 3512/3723] Revert "[nrf fromtree] net: socket_services: Increase default stack size for DHCPv4 server" This reverts commit 7a0cbb67886c736bdf31f87246a5a626765087b3. Signed-off-by: Robert Lubos --- subsys/net/lib/sockets/Kconfig | 1 - 1 file changed, 1 deletion(-) diff --git a/subsys/net/lib/sockets/Kconfig b/subsys/net/lib/sockets/Kconfig index 35750dd3583..40d86b9498f 100644 --- a/subsys/net/lib/sockets/Kconfig +++ b/subsys/net/lib/sockets/Kconfig @@ -88,7 +88,6 @@ config NET_SOCKETS_SERVICE config NET_SOCKETS_SERVICE_STACK_SIZE int "Stack size for the thread handling socket services" - default 2400 if NET_DHCPV4_SERVER default 1200 depends on NET_SOCKETS_SERVICE help From 364065ff0d410e29bd65fbd94821bde089d320c2 Mon Sep 17 00:00:00 2001 From: Robert Lubos Date: Tue, 6 Feb 2024 11:07:01 +0100 Subject: [PATCH 3513/3723] Revert "[nrf fromtree] net: dhcpv4: Implement DHCPv4 server" This reverts commit fb9ace0f2e6ac68e2f7a3438cafdf6f6f5799f33. Signed-off-by: Robert Lubos --- include/zephyr/net/dhcpv4_server.h | 118 -- subsys/net/ip/dhcpv4.h | 11 - subsys/net/ip/net_core.c | 2 - subsys/net/lib/CMakeLists.txt | 1 - subsys/net/lib/Kconfig | 2 - subsys/net/lib/dhcpv4/CMakeLists.txt | 11 - subsys/net/lib/dhcpv4/Kconfig | 46 - subsys/net/lib/dhcpv4/dhcpv4_server.c | 1439 ------------------------- 8 files changed, 1630 deletions(-) delete mode 100644 include/zephyr/net/dhcpv4_server.h delete mode 100644 subsys/net/lib/dhcpv4/CMakeLists.txt delete mode 100644 subsys/net/lib/dhcpv4/Kconfig delete mode 100644 subsys/net/lib/dhcpv4/dhcpv4_server.c diff --git a/include/zephyr/net/dhcpv4_server.h b/include/zephyr/net/dhcpv4_server.h deleted file mode 100644 index 18c4af114cd..00000000000 --- a/include/zephyr/net/dhcpv4_server.h +++ /dev/null @@ -1,118 +0,0 @@ -/** @file - * @brief DHCPv4 Server API - */ - -/* - * Copyright (c) 2024 Nordic Semiconductor ASA - * - * SPDX-License-Identifier: Apache-2.0 - */ - -#ifndef ZEPHYR_INCLUDE_NET_DHCPV4_SERVER_H_ -#define ZEPHYR_INCLUDE_NET_DHCPV4_SERVER_H_ - -#include -#include - -#ifdef __cplusplus -extern "C" { -#endif - -/** - * @brief DHCPv4 server - * @defgroup dhcpv4_server DHCPv4 server - * @ingroup networking - * @{ - */ - -/** @cond INTERNAL_HIDDEN */ - -struct net_if; - -#define DHCPV4_CLIENT_ID_MAX_SIZE 20 - -enum dhcpv4_server_addr_state { - DHCPV4_SERVER_ADDR_FREE, - DHCPV4_SERVER_ADDR_RESERVED, - DHCPV4_SERVER_ADDR_ALLOCATED, - DHCPV4_SERVER_ADDR_DECLINED, -}; - -struct dhcpv4_client_id { - uint8_t buf[DHCPV4_CLIENT_ID_MAX_SIZE]; - uint8_t len; -}; - -struct dhcpv4_addr_slot { - enum dhcpv4_server_addr_state state; - struct dhcpv4_client_id client_id; - struct in_addr addr; - uint32_t lease_time; - k_timepoint_t expiry; -}; - -/** @endcond */ - -/** - * @brief Start DHCPv4 server instance on an iface - * - * @details Start DHCPv4 server on a given interface. The server will start - * listening for DHCPv4 Discover/Request messages on the interface and assign - * IPv4 addresses from the configured address pool accordingly. - * - * @param iface A valid pointer on an interface - * @param base_addr First IPv4 address from the DHCPv4 address pool. The number - * of addresses in the pool is configured statically with Kconfig - * (CONFIG_NET_DHCPV4_SERVER_ADDR_COUNT). - * - * @return 0 on success, a negative error code otherwise. - */ -int net_dhcpv4_server_start(struct net_if *iface, struct in_addr *base_addr); - -/** - * @brief Stop DHCPv4 server instance on an iface - * - * @details Stop DHCPv4 server on a given interface. DHCPv4 requests will no - * longer be handled on the interface, and all of the allocations are cleared. - * - * @param iface A valid pointer on an interface - * - * @return 0 on success, a negative error code otherwise. - */ -int net_dhcpv4_server_stop(struct net_if *iface); - -/** - * @typedef net_dhcpv4_lease_cb_t - * @brief Callback used while iterating over active DHCPv4 address leases - * - * @param iface Pointer to the network interface - * @param lease Pointer to the DHPCv4 address lease slot - * @param user_data A valid pointer to user data or NULL - */ -typedef void (*net_dhcpv4_lease_cb_t)(struct net_if *iface, - struct dhcpv4_addr_slot *lease, - void *user_data); - -/** - * @brief Iterate over all DHCPv4 address leases on a given network interface - * and call callback for each lease. In case no network interface is provided - * (NULL interface pointer), will iterate over all interfaces running DHCPv4 - * server instance. - * - * @param iface Pointer to the network interface, can be NULL - * @param cb User-supplied callback function to call - * @param user_data User specified data - */ -int net_dhcpv4_server_foreach_lease(struct net_if *iface, - net_dhcpv4_lease_cb_t cb, - void *user_data); - -/** - * @} - */ - -#ifdef __cplusplus -} -#endif - -#endif /* ZEPHYR_INCLUDE_NET_DHCPV4_SERVER_H_ */ diff --git a/subsys/net/ip/dhcpv4.h b/subsys/net/ip/dhcpv4.h index 712d361ac80..a274e3a6aea 100644 --- a/subsys/net/ip/dhcpv4.h +++ b/subsys/net/ip/dhcpv4.h @@ -62,7 +62,6 @@ struct dhcp_msg { #define DHCPV4_OPTIONS_REQ_LIST 55 #define DHCPV4_OPTIONS_RENEWAL 58 #define DHCPV4_OPTIONS_REBINDING 59 -#define DHCPV4_OPTIONS_CLIENT_ID 61 #define DHCPV4_OPTIONS_END 255 /* Useful size macros */ @@ -143,14 +142,4 @@ static inline bool net_dhcpv4_accept_unicast(struct net_pkt *pkt) #endif /* CONFIG_NET_DHCPV4 && CONFIG_NET_DHCPV4_ACCEPT_UNICAST */ -#if defined(CONFIG_NET_DHCPV4_SERVER) - -void net_dhcpv4_server_init(void); - -#else - -#define net_dhcpv4_server_init() - -#endif /* CONFIG_NET_DHCPV4_SERVER */ - #endif /* __INTERNAL_DHCPV4_H */ diff --git a/subsys/net/ip/net_core.c b/subsys/net/ip/net_core.c index 3187b40a66b..baa8cd695c5 100644 --- a/subsys/net/ip/net_core.c +++ b/subsys/net/ip/net_core.c @@ -495,8 +495,6 @@ static inline int services_init(void) return status; } - net_dhcpv4_server_init(); - dns_init_resolver(); websocket_init(); diff --git a/subsys/net/lib/CMakeLists.txt b/subsys/net/lib/CMakeLists.txt index e3319f6cd8d..5e4eae7e028 100644 --- a/subsys/net/lib/CMakeLists.txt +++ b/subsys/net/lib/CMakeLists.txt @@ -15,7 +15,6 @@ add_subdirectory_ifdef(CONFIG_NET_CAPTURE capture) add_subdirectory_ifdef(CONFIG_NET_ZPERF zperf) add_subdirectory_ifdef(CONFIG_NET_SHELL shell) add_subdirectory_ifdef(CONFIG_NET_TRICKLE trickle) -add_subdirectory_ifdef(CONFIG_NET_DHCPV4_SERVER dhcpv4) if (CONFIG_DNS_RESOLVER OR CONFIG_MDNS_RESPONDER diff --git a/subsys/net/lib/Kconfig b/subsys/net/lib/Kconfig index 6cfa0445241..b70105d5f9b 100644 --- a/subsys/net/lib/Kconfig +++ b/subsys/net/lib/Kconfig @@ -39,8 +39,6 @@ menu "Network additional services" source "subsys/net/lib/capture/Kconfig" -source "subsys/net/lib/dhcpv4/Kconfig" - source "subsys/net/lib/trickle/Kconfig" source "subsys/net/lib/zperf/Kconfig" diff --git a/subsys/net/lib/dhcpv4/CMakeLists.txt b/subsys/net/lib/dhcpv4/CMakeLists.txt deleted file mode 100644 index 348b6c99bb7..00000000000 --- a/subsys/net/lib/dhcpv4/CMakeLists.txt +++ /dev/null @@ -1,11 +0,0 @@ -# Copyright (c) 2024 Nordic Semiconductor ASA -# -# SPDX-License-Identifier: Apache-2.0 - -zephyr_library() - -zephyr_library_include_directories(${ZEPHYR_BASE}/subsys/net/ip) - -zephyr_library_sources( - dhcpv4_server.c - ) diff --git a/subsys/net/lib/dhcpv4/Kconfig b/subsys/net/lib/dhcpv4/Kconfig deleted file mode 100644 index 801d536a5a1..00000000000 --- a/subsys/net/lib/dhcpv4/Kconfig +++ /dev/null @@ -1,46 +0,0 @@ -# DHCPv4 server implementation for Zephyr - -# Copyright (c) 2024 Nordic Semiconductor ASA -# -# SPDX-License-Identifier: Apache-2.0 - -config NET_DHCPV4_SERVER - bool "DHCPv4 server" - depends on NET_IPV4 && NET_UDP - select NET_SOCKETS - select NET_SOCKETS_SERVICE - -if NET_DHCPV4_SERVER - -module = NET_DHCPV4_SERVER -module-dep = NET_LOG -module-str = Log level for DHCPv4 server -module-help = Enables DHCPv4 server output debug messages -source "subsys/net/Kconfig.template.log_config.net" - -config NET_DHCPV4_SERVER_INSTANCES - int "Maximum number of DHCPv4 server instances" - default 1 - help - Maximum number of DHCPv4 server instances supported by the system. - Each network interface that wants to act as a DHCPv4 server requires - a separate instance. - -config NET_DHCPV4_SERVER_ADDR_COUNT - int "Number of IPv4 addresses that can be assigned by the server" - default 4 - help - Maximum number of IPv4 addresses that can be assigned by the DHCPv4 - server instance. The base IPv4 address in the address pool is provided - at runtime, during server initialization. Consecutive addresses in the - pool have the lowest address octet incremented. - -config NET_DHCPV4_SERVER_ADDR_LEASE_TIME - int "Lease time for IPv4 addresses assigned by the server (seconds)" - default 86400 - help - Lease time in seconds for IPv4 addresses assigned by the server. - The lease time determines when the IPv4 address lease expires if the - client does not renew it. - -endif # NET_DHCPV4_SERVER diff --git a/subsys/net/lib/dhcpv4/dhcpv4_server.c b/subsys/net/lib/dhcpv4/dhcpv4_server.c deleted file mode 100644 index 714d036ddde..00000000000 --- a/subsys/net/lib/dhcpv4/dhcpv4_server.c +++ /dev/null @@ -1,1439 +0,0 @@ -/** @file - * @brief DHCPv4 server implementation - */ - -/* - * Copyright (c) 2024 Nordic Semiconductor ASA - * - * SPDX-License-Identifier: Apache-2.0 - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include - -LOG_MODULE_REGISTER(net_dhcpv4_server, CONFIG_NET_DHCPV4_SERVER_LOG_LEVEL); - -#include "dhcpv4.h" -#include "net_private.h" -#include "../../l2/ethernet/arp.h" - -#define DHCPV4_OPTIONS_MSG_TYPE_SIZE 3 -#define DHCPV4_OPTIONS_IP_LEASE_TIME_SIZE 6 -#define DHCPV4_OPTIONS_SERVER_ID_SIZE 6 -#define DHCPV4_OPTIONS_SUBNET_MASK_SIZE 6 -#define DHCPV4_OPTIONS_CLIENT_ID_MIN_SIZE 2 - -#define ADDRESS_RESERVED_TIMEOUT K_SECONDS(5) - -/* RFC 1497 [17] */ -static const uint8_t magic_cookie[4] = { 0x63, 0x82, 0x53, 0x63 }; - -struct dhcpv4_server_ctx { - struct net_if *iface; - int sock; - struct k_work_delayable timeout_work; - struct dhcpv4_addr_slot addr_pool[CONFIG_NET_DHCPV4_SERVER_ADDR_COUNT]; - struct in_addr server_addr; - struct in_addr netmask; -}; - -static struct dhcpv4_server_ctx server_ctx[CONFIG_NET_DHCPV4_SERVER_INSTANCES]; -static struct zsock_pollfd fds[CONFIG_NET_DHCPV4_SERVER_INSTANCES]; -static K_MUTEX_DEFINE(server_lock); - -#define DHCPV4_MAX_PARAMETERS_REQUEST_LEN 16 - -struct dhcpv4_parameter_request_list { - uint8_t list[DHCPV4_MAX_PARAMETERS_REQUEST_LEN]; - uint8_t count; -}; - -static void dhcpv4_server_timeout_recalc(struct dhcpv4_server_ctx *ctx) -{ - k_timepoint_t next = sys_timepoint_calc(K_FOREVER); - k_timeout_t timeout; - - for (int i = 0; i < ARRAY_SIZE(ctx->addr_pool); i++) { - struct dhcpv4_addr_slot *slot = &ctx->addr_pool[i]; - - if (slot->state == DHCPV4_SERVER_ADDR_RESERVED || - slot->state == DHCPV4_SERVER_ADDR_ALLOCATED) { - if (sys_timepoint_cmp(slot->expiry, next) < 0) { - next = slot->expiry; - } - } - } - - timeout = sys_timepoint_timeout(next); - - if (K_TIMEOUT_EQ(timeout, K_FOREVER)) { - LOG_DBG("No more addresses, canceling timer"); - k_work_cancel_delayable(&ctx->timeout_work); - } else { - k_work_reschedule(&ctx->timeout_work, timeout); - } -} - -/* Option parsing. */ - -static uint8_t *dhcpv4_find_option(uint8_t *data, size_t datalen, - uint8_t *optlen, uint8_t opt_code) -{ - uint8_t *opt = NULL; - - while (datalen > 0) { - uint8_t code; - uint8_t len; - - code = *data; - - /* Two special cases (fixed sized options) */ - if (code == 0) { - data++; - datalen--; - continue; - } - - if (code == DHCPV4_OPTIONS_END) { - break; - } - - /* Length field should now follow. */ - if (datalen < 2) { - break; - } - - len = *(data + 1); - - if (datalen < len + 2) { - break; - } - - if (code == opt_code) { - /* Found the option. */ - opt = data + 2; - *optlen = len; - break; - } - - data += len + 2; - datalen -= len + 2; - } - - return opt; -} - -static int dhcpv4_find_message_type_option(uint8_t *data, size_t datalen, - uint8_t *msgtype) -{ - uint8_t *opt; - uint8_t optlen; - - opt = dhcpv4_find_option(data, datalen, &optlen, - DHCPV4_OPTIONS_MSG_TYPE); - if (opt == NULL) { - return -ENOENT; - } - - if (optlen != 1) { - return -EINVAL; - } - - *msgtype = *opt; - - return 0; -} - -static int dhcpv4_find_server_id_option(uint8_t *data, size_t datalen, - struct in_addr *server_id) -{ - uint8_t *opt; - uint8_t optlen; - - opt = dhcpv4_find_option(data, datalen, &optlen, - DHCPV4_OPTIONS_SERVER_ID); - if (opt == NULL) { - return -ENOENT; - } - - if (optlen != sizeof(struct in_addr)) { - return -EINVAL; - } - - memcpy(server_id, opt, sizeof(struct in_addr)); - - return 0; -} - -static int dhcpv4_find_client_id_option(uint8_t *data, size_t datalen, - uint8_t *client_id, uint8_t *len) -{ - uint8_t *opt; - uint8_t optlen; - - opt = dhcpv4_find_option(data, datalen, &optlen, - DHCPV4_OPTIONS_CLIENT_ID); - if (opt == NULL) { - return -ENOENT; - } - - if (optlen < DHCPV4_OPTIONS_CLIENT_ID_MIN_SIZE) { - return -EINVAL; - } - - if (optlen > *len) { - LOG_ERR("Not enough memory for DHCPv4 client identifier."); - return -ENOMEM; - } - - memcpy(client_id, opt, optlen); - *len = optlen; - - return 0; -} - -static int dhcpv4_find_requested_ip_option(uint8_t *data, size_t datalen, - struct in_addr *requested_ip) -{ - uint8_t *opt; - uint8_t optlen; - - opt = dhcpv4_find_option(data, datalen, &optlen, - DHCPV4_OPTIONS_REQ_IPADDR); - if (opt == NULL) { - return -ENOENT; - } - - if (optlen != sizeof(struct in_addr)) { - return -EINVAL; - } - - memcpy(requested_ip, opt, sizeof(struct in_addr)); - - return 0; -} - -static int dhcpv4_find_ip_lease_time_option(uint8_t *data, size_t datalen, - uint32_t *lease_time) -{ - uint8_t *opt; - uint8_t optlen; - - opt = dhcpv4_find_option(data, datalen, &optlen, - DHCPV4_OPTIONS_LEASE_TIME); - if (opt == NULL) { - return -ENOENT; - } - - if (optlen != sizeof(uint32_t)) { - return -EINVAL; - } - - *lease_time = sys_get_be32(opt); - - return 0; -} - -static int dhcpv4_find_parameter_request_list_option( - uint8_t *data, size_t datalen, - struct dhcpv4_parameter_request_list *params) -{ - uint8_t *opt; - uint8_t optlen; - - opt = dhcpv4_find_option(data, datalen, &optlen, - DHCPV4_OPTIONS_REQ_LIST); - if (opt == NULL) { - return -ENOENT; - } - - if (optlen > sizeof(params->list)) { - /* Best effort here, copy as much as we can. */ - optlen = sizeof(params->list); - } - - memcpy(params->list, opt, optlen); - params->count = optlen; - - return 0; -} - -/* Option encoding. */ - -static uint8_t *dhcpv4_encode_magic_cookie(uint8_t *buf, size_t *buflen) -{ - if (buf == NULL || *buflen < SIZE_OF_MAGIC_COOKIE) { - return NULL; - } - - memcpy(buf, magic_cookie, SIZE_OF_MAGIC_COOKIE); - - *buflen -= SIZE_OF_MAGIC_COOKIE; - - return buf + SIZE_OF_MAGIC_COOKIE; -} - -static uint8_t *dhcpv4_encode_ip_lease_time_option(uint8_t *buf, size_t *buflen, - uint32_t lease_time) -{ - if (buf == NULL || *buflen < DHCPV4_OPTIONS_IP_LEASE_TIME_SIZE) { - return NULL; - } - - buf[0] = DHCPV4_OPTIONS_LEASE_TIME; - buf[1] = sizeof(lease_time); - sys_put_be32(lease_time, &buf[2]); - - *buflen -= DHCPV4_OPTIONS_IP_LEASE_TIME_SIZE; - - return buf + DHCPV4_OPTIONS_IP_LEASE_TIME_SIZE; -} - -static uint8_t *dhcpv4_encode_message_type_option(uint8_t *buf, size_t *buflen, - uint8_t msgtype) -{ - if (buf == NULL || *buflen < DHCPV4_OPTIONS_MSG_TYPE_SIZE) { - return NULL; - } - - buf[0] = DHCPV4_OPTIONS_MSG_TYPE; - buf[1] = 1; - buf[2] = msgtype; - - *buflen -= DHCPV4_OPTIONS_MSG_TYPE_SIZE; - - return buf + DHCPV4_OPTIONS_MSG_TYPE_SIZE; -} - -static uint8_t *dhcpv4_encode_server_id_option(uint8_t *buf, size_t *buflen, - struct in_addr *server_id) -{ - if (buf == NULL || *buflen < DHCPV4_OPTIONS_SERVER_ID_SIZE) { - return NULL; - } - - buf[0] = DHCPV4_OPTIONS_SERVER_ID; - buf[1] = sizeof(struct in_addr); - memcpy(&buf[2], server_id->s4_addr, sizeof(struct in_addr)); - - *buflen -= DHCPV4_OPTIONS_SERVER_ID_SIZE; - - return buf + DHCPV4_OPTIONS_SERVER_ID_SIZE; -} - -static uint8_t *dhcpv4_encode_subnet_mask_option(uint8_t *buf, size_t *buflen, - struct in_addr *mask) -{ - if (buf == NULL || *buflen < DHCPV4_OPTIONS_SUBNET_MASK_SIZE) { - return NULL; - } - - buf[0] = DHCPV4_OPTIONS_SUBNET_MASK; - buf[1] = sizeof(struct in_addr); - memcpy(&buf[2], mask->s4_addr, sizeof(struct in_addr)); - - *buflen -= DHCPV4_OPTIONS_SUBNET_MASK_SIZE; - - return buf + DHCPV4_OPTIONS_SUBNET_MASK_SIZE; -} - -static uint8_t *dhcpv4_encode_end_option(uint8_t *buf, size_t *buflen) -{ - if (buf == NULL || *buflen < 1) { - return NULL; - } - - buf[0] = DHCPV4_OPTIONS_END; - - *buflen -= 1; - - return buf + 1; -} - -/* Response handlers. */ - -static uint8_t *dhcpv4_encode_header(uint8_t *buf, size_t *buflen, - struct dhcp_msg *msg, - struct in_addr *yiaddr) -{ - struct dhcp_msg *reply_msg = (struct dhcp_msg *)buf; - - if (buf == NULL || *buflen < sizeof(struct dhcp_msg)) { - return NULL; - } - - reply_msg->op = DHCPV4_MSG_BOOT_REPLY; - reply_msg->htype = msg->htype; - reply_msg->hlen = msg->hlen; - reply_msg->hops = 0; - reply_msg->xid = msg->xid; - reply_msg->secs = 0; - reply_msg->flags = msg->flags; - memcpy(reply_msg->ciaddr, msg->ciaddr, sizeof(reply_msg->ciaddr)); - if (yiaddr != NULL) { - memcpy(reply_msg->yiaddr, yiaddr, sizeof(struct in_addr)); - } else { - memset(reply_msg->yiaddr, 0, sizeof(reply_msg->ciaddr)); - } - memset(reply_msg->siaddr, 0, sizeof(reply_msg->siaddr)); - memcpy(reply_msg->giaddr, msg->giaddr, sizeof(reply_msg->giaddr)); - memcpy(reply_msg->chaddr, msg->chaddr, sizeof(reply_msg->chaddr)); - - *buflen -= sizeof(struct dhcp_msg); - - return buf + sizeof(struct dhcp_msg); -} - -static uint8_t *dhcpv4_encode_string(uint8_t *buf, size_t *buflen, char *str, - size_t max_len) -{ - if (buf == NULL || *buflen < max_len) { - return NULL; - } - - memset(buf, 0, max_len); - - if (str == NULL) { - goto out; - } - - strncpy(buf, str, max_len - 1); - - out: - *buflen -= max_len; - - return buf + max_len; -} - -static uint8_t *dhcpv4_encode_sname(uint8_t *buf, size_t *buflen, char *sname) -{ - return dhcpv4_encode_string(buf, buflen, sname, SIZE_OF_SNAME); -} - -static uint8_t *dhcpv4_encode_file(uint8_t *buf, size_t *buflen, char *file) -{ - return dhcpv4_encode_string(buf, buflen, file, SIZE_OF_FILE); -} - -static uint8_t *dhcpv4_encode_requested_params( - uint8_t *buf, size_t *buflen, - struct dhcpv4_server_ctx *ctx, - struct dhcpv4_parameter_request_list *params) -{ - for (uint8_t i = 0; i < params->count; i++) { - switch (params->list[i]) { - case DHCPV4_OPTIONS_SUBNET_MASK: - buf = dhcpv4_encode_subnet_mask_option( - buf, buflen, &ctx->netmask); - if (buf == NULL) { - goto out; - } - break; - - /* Others - just ignore. */ - default: - break; - } - } - -out: - return buf; -} - -static int dhcpv4_send(struct dhcpv4_server_ctx *ctx, enum net_dhcpv4_msg_type type, - uint8_t *reply, size_t len, struct dhcp_msg *msg, - struct in_addr *yiaddr) -{ - struct sockaddr_in dst_addr = { - .sin_family = AF_INET, - .sin_port = htons(DHCPV4_CLIENT_PORT), - }; - struct in_addr giaddr; /* Relay agent address */ - struct in_addr ciaddr; /* Client address */ - int ret; - - memcpy(&giaddr, msg->giaddr, sizeof(giaddr)); - memcpy(&ciaddr, msg->ciaddr, sizeof(ciaddr)); - - /* Select destination address as described in ch. 4.1. */ - if (!net_ipv4_is_addr_unspecified(&giaddr)) { - /* If the 'giaddr' field in a DHCP message from a client is - * non-zero, the server sends any return messages to the - * 'DHCP server' port on the BOOTP relay agent whose address - * appears in 'giaddr'. - */ - dst_addr.sin_addr = giaddr; - dst_addr.sin_port = htons(DHCPV4_SERVER_PORT); - } else if (type == NET_DHCPV4_MSG_TYPE_NAK) { - /* In all cases, when 'giaddr' is zero, the server broadcasts - * any DHCPNAK messages to 0xffffffff. - */ - dst_addr.sin_addr = *net_ipv4_broadcast_address(); - } else if (!net_ipv4_is_addr_unspecified(&ciaddr)) { - /* If the 'giaddr' field is zero and the 'ciaddr' field is - * nonzero, then the server unicasts DHCPOFFER and DHCPACK - * messages to the address in 'ciaddr'. - */ - dst_addr.sin_addr = ciaddr; - } else if (ntohs(msg->flags) & DHCPV4_MSG_BROADCAST) { - /* If 'giaddr' is zero and 'ciaddr' is zero, and the broadcast - * bit is set, then the server broadcasts DHCPOFFER and DHCPACK - * messages to 0xffffffff. - */ - dst_addr.sin_addr = *net_ipv4_broadcast_address(); - } else if (yiaddr != NULL) { - /* If the broadcast bit is not set and 'giaddr' is zero and - * 'ciaddr' is zero, then the server unicasts DHCPOFFER and - * DHCPACK messages to the client's hardware address and 'yiaddr' - * address. - */ - struct net_eth_addr hwaddr; - - memcpy(&hwaddr, msg->chaddr, sizeof(hwaddr)); - net_arp_update(ctx->iface, yiaddr, &hwaddr, false, true); - dst_addr.sin_addr = *yiaddr; - } else { - NET_ERR("Unspecified destination address."); - return -EDESTADDRREQ; - } - - ret = zsock_sendto(ctx->sock, reply, len, 0, (struct sockaddr *)&dst_addr, - sizeof(dst_addr)); - if (ret < 0) { - return -errno; - } - - return 0; -} - -static int dhcpv4_send_offer(struct dhcpv4_server_ctx *ctx, struct dhcp_msg *msg, - struct in_addr *addr, uint32_t lease_time, - struct dhcpv4_parameter_request_list *params) -{ - uint8_t reply[NET_IPV4_MTU]; - uint8_t *buf = reply; - size_t buflen = sizeof(reply); - size_t reply_len = 0; - int ret; - - buf = dhcpv4_encode_header(buf, &buflen, msg, addr); - buf = dhcpv4_encode_sname(buf, &buflen, NULL); - buf = dhcpv4_encode_file(buf, &buflen, NULL); - buf = dhcpv4_encode_magic_cookie(buf, &buflen); - buf = dhcpv4_encode_ip_lease_time_option(buf, &buflen, lease_time); - buf = dhcpv4_encode_message_type_option(buf, &buflen, - NET_DHCPV4_MSG_TYPE_OFFER); - buf = dhcpv4_encode_server_id_option(buf, &buflen, &ctx->server_addr); - buf = dhcpv4_encode_requested_params(buf, &buflen, ctx, params); - buf = dhcpv4_encode_end_option(buf, &buflen); - - if (buf == NULL) { - LOG_ERR("Failed to encode %s message", "Offer"); - return -ENOMEM; - } - - reply_len = sizeof(reply) - buflen; - - ret = dhcpv4_send(ctx, NET_DHCPV4_MSG_TYPE_OFFER, reply, reply_len, - msg, addr); - if (ret < 0) { - LOG_ERR("Failed to send %s message, %d", "Offer", ret); - return ret; - } - - return 0; -} - -static int dhcpv4_send_ack(struct dhcpv4_server_ctx *ctx, struct dhcp_msg *msg, - struct in_addr *addr, uint32_t lease_time, - struct dhcpv4_parameter_request_list *params, - bool inform) -{ - uint8_t reply[NET_IPV4_MTU]; - uint8_t *buf = reply; - size_t buflen = sizeof(reply); - size_t reply_len = 0; - int ret; - - buf = dhcpv4_encode_header(buf, &buflen, msg, inform ? NULL : addr); - buf = dhcpv4_encode_sname(buf, &buflen, NULL); - buf = dhcpv4_encode_file(buf, &buflen, NULL); - buf = dhcpv4_encode_magic_cookie(buf, &buflen); - if (!inform) { - buf = dhcpv4_encode_ip_lease_time_option(buf, &buflen, lease_time); - } - buf = dhcpv4_encode_message_type_option(buf, &buflen, - NET_DHCPV4_MSG_TYPE_ACK); - buf = dhcpv4_encode_server_id_option(buf, &buflen, &ctx->server_addr); - buf = dhcpv4_encode_requested_params(buf, &buflen, ctx, params); - buf = dhcpv4_encode_end_option(buf, &buflen); - - if (buf == NULL) { - LOG_ERR("Failed to encode %s message", "ACK"); - return -ENOMEM; - } - - reply_len = sizeof(reply) - buflen; - - ret = dhcpv4_send(ctx, NET_DHCPV4_MSG_TYPE_ACK, reply, reply_len, msg, - addr); - if (ret < 0) { - LOG_ERR("Failed to send %s message, %d", "ACK", ret); - return ret; - } - - return 0; -} - -static int dhcpv4_send_nak(struct dhcpv4_server_ctx *ctx, struct dhcp_msg *msg) -{ - uint8_t reply[NET_IPV4_MTU]; - uint8_t *buf = reply; - size_t buflen = sizeof(reply); - size_t reply_len = 0; - int ret; - - buf = dhcpv4_encode_header(buf, &buflen, msg, NULL); - buf = dhcpv4_encode_sname(buf, &buflen, NULL); - buf = dhcpv4_encode_file(buf, &buflen, NULL); - buf = dhcpv4_encode_magic_cookie(buf, &buflen); - buf = dhcpv4_encode_message_type_option(buf, &buflen, - NET_DHCPV4_MSG_TYPE_NAK); - buf = dhcpv4_encode_server_id_option(buf, &buflen, &ctx->server_addr); - buf = dhcpv4_encode_end_option(buf, &buflen); - - if (buf == NULL) { - LOG_ERR("Failed to encode %s message", "NAK"); - return -ENOMEM; - } - - reply_len = sizeof(reply) - buflen; - - ret = dhcpv4_send(ctx, NET_DHCPV4_MSG_TYPE_NAK, reply, reply_len, msg, - NULL); - if (ret < 0) { - LOG_ERR("Failed to send %s message, %d", "NAK", ret); - return ret; - } - - return 0; -} - -/* Message handlers. */ - -static int dhcpv4_get_client_id(struct dhcp_msg *msg, uint8_t *options, - uint8_t optlen, struct dhcpv4_client_id *client_id) -{ - int ret; - - client_id->len = sizeof(client_id->buf); - - ret = dhcpv4_find_client_id_option(options, optlen, client_id->buf, - &client_id->len); - if (ret == 0) { - return 0; - } - - /* No Client Id option or too long to use, fallback to hardware address. */ - if (msg->hlen > sizeof(msg->chaddr)) { - LOG_ERR("Malformed chaddr length."); - return -EINVAL; - } - - client_id->buf[0] = msg->htype; - client_id->buf[1] = msg->hlen; - memcpy(client_id->buf + 2, msg->chaddr, msg->hlen); - client_id->len = msg->hlen + 2; - - return 0; -} - -static uint32_t dhcpv4_get_lease_time(uint8_t *options, uint8_t optlen) -{ - uint32_t lease_time; - - if (dhcpv4_find_ip_lease_time_option(options, optlen, - &lease_time) == 0) { - return lease_time; - } - - return CONFIG_NET_DHCPV4_SERVER_ADDR_LEASE_TIME; -} - -static void dhcpv4_handle_discover(struct dhcpv4_server_ctx *ctx, - struct dhcp_msg *msg, uint8_t *options, - uint8_t optlen) -{ - struct dhcpv4_parameter_request_list params = { 0 }; - struct dhcpv4_addr_slot *selected = NULL; - struct dhcpv4_client_id client_id; - int ret; - - ret = dhcpv4_get_client_id(msg, options, optlen, &client_id); - if (ret < 0) { - return; - } - - (void)dhcpv4_find_parameter_request_list_option(options, optlen, ¶ms); - - /* Address pool and address selection algorithm as - * described in 4.3.1 - */ - - /* 1. Check for current bindings */ - for (int i = 0; i < ARRAY_SIZE(ctx->addr_pool); i++) { - struct dhcpv4_addr_slot *slot = &ctx->addr_pool[i]; - - if ((slot->state == DHCPV4_SERVER_ADDR_RESERVED || - slot->state == DHCPV4_SERVER_ADDR_ALLOCATED) && - slot->client_id.len == client_id.len && - memcmp(slot->client_id.buf, client_id.buf, - client_id.len) == 0) { - /* Got match in current bindings. */ - selected = slot; - break; - } - } - - /* 2. Skipped, for now expired/released entries are forgotten. */ - - /* 3. Check Requested IP Address option. */ - if (selected == NULL) { - struct in_addr requested_ip; - - ret = dhcpv4_find_requested_ip_option(options, optlen, - &requested_ip); - if (ret == 0) { - for (int i = 0; i < ARRAY_SIZE(ctx->addr_pool); i++) { - struct dhcpv4_addr_slot *slot = - &ctx->addr_pool[i]; - - if (net_ipv4_addr_cmp(&slot->addr, - &requested_ip) && - slot->state == DHCPV4_SERVER_ADDR_FREE) { - /* Requested address is free. */ - selected = slot; - break; - } - } - } - } - - /* 4. Allocate new address from pool, if available. */ - if (selected == NULL) { - struct in_addr giaddr; - - memcpy(&giaddr, msg->giaddr, sizeof(giaddr)); - if (!net_ipv4_is_addr_unspecified(&giaddr)) { - /* Only addresses in local subnet supproted for now. */ - return; - } - - for (int i = 0; i < ARRAY_SIZE(ctx->addr_pool); i++) { - struct dhcpv4_addr_slot *slot = &ctx->addr_pool[i]; - - if (slot->state == DHCPV4_SERVER_ADDR_FREE) { - /* Requested address is free. */ - selected = slot; - break; - } - } - } - - if (selected == NULL) { - LOG_ERR("No free address found in address pool"); - } else { - uint32_t lease_time = dhcpv4_get_lease_time(options, optlen); - - if (dhcpv4_send_offer(ctx, msg, &selected->addr, lease_time, - ¶ms) < 0) { - return; - } - - LOG_DBG("DHCPv4 processing Discover - reserved %s", - net_sprint_ipv4_addr(&selected->addr)); - - selected->state = DHCPV4_SERVER_ADDR_RESERVED; - selected->client_id.len = client_id.len; - memcpy(selected->client_id.buf, client_id.buf, client_id.len); - selected->lease_time = lease_time; - selected->expiry = sys_timepoint_calc(ADDRESS_RESERVED_TIMEOUT); - dhcpv4_server_timeout_recalc(ctx); - } -} - -static void dhcpv4_handle_request(struct dhcpv4_server_ctx *ctx, - struct dhcp_msg *msg, uint8_t *options, - uint8_t optlen) -{ - struct dhcpv4_parameter_request_list params = { 0 }; - struct dhcpv4_addr_slot *selected = NULL; - struct dhcpv4_client_id client_id; - struct in_addr requested_ip, server_id, ciaddr, giaddr; - int ret; - - memcpy(&ciaddr, msg->ciaddr, sizeof(ciaddr)); - memcpy(&giaddr, msg->giaddr, sizeof(giaddr)); - - if (!net_ipv4_is_addr_unspecified(&giaddr)) { - /* Only addresses in local subnet supported for now. */ - return; - } - - ret = dhcpv4_get_client_id(msg, options, optlen, &client_id); - if (ret < 0) { - /* Failed to obtain Client ID, ignore. */ - return; - } - - (void)dhcpv4_find_parameter_request_list_option(options, optlen, ¶ms); - - ret = dhcpv4_find_server_id_option(options, optlen, &server_id); - if (ret == 0) { - /* Server ID present, Request generated during SELECTING. */ - if (!net_ipv4_addr_cmp(&ctx->server_addr, &server_id)) { - /* Not for us, ignore. */ - return; - } - - ret = dhcpv4_find_requested_ip_option(options, optlen, - &requested_ip); - if (ret < 0) { - /* Requested IP missing, ignore. */ - return; - } - - if (!net_ipv4_is_addr_unspecified(&ciaddr)) { - /* ciaddr MUST be zero */ - return; - } - - for (int i = 0; i < ARRAY_SIZE(ctx->addr_pool); i++) { - struct dhcpv4_addr_slot *slot = &ctx->addr_pool[i]; - - if (net_ipv4_addr_cmp(&slot->addr, &requested_ip) && - slot->client_id.len == client_id.len && - memcmp(slot->client_id.buf, client_id.buf, - client_id.len) == 0 && - slot->state == DHCPV4_SERVER_ADDR_RESERVED) { - selected = slot; - break; - } - } - - if (selected == NULL) { - LOG_ERR("No valid slot found for DHCPv4 Request"); - } else { - uint32_t lease_time = dhcpv4_get_lease_time(options, optlen); - - if (dhcpv4_send_ack(ctx, msg, &selected->addr, lease_time, - ¶ms, false) < 0) { - return; - } - - LOG_DBG("DHCPv4 processing Request - allocated %s", - net_sprint_ipv4_addr(&selected->addr)); - - selected->lease_time = lease_time; - selected->expiry = sys_timepoint_calc( - K_SECONDS(lease_time)); - selected->state = DHCPV4_SERVER_ADDR_ALLOCATED; - dhcpv4_server_timeout_recalc(ctx); - } - - return; - } - - /* No server ID option - check requested address. */ - ret = dhcpv4_find_requested_ip_option(options, optlen, &requested_ip); - if (ret == 0) { - /* Requested IP present, Request generated during INIT-REBOOT. */ - if (!net_ipv4_is_addr_unspecified(&ciaddr)) { - /* ciaddr MUST be zero */ - return; - } - - if (!net_if_ipv4_addr_mask_cmp(ctx->iface, &requested_ip)) { - /* Wrong subnet. */ - dhcpv4_send_nak(ctx, msg); - } - - for (int i = 0; i < ARRAY_SIZE(ctx->addr_pool); i++) { - struct dhcpv4_addr_slot *slot = &ctx->addr_pool[i]; - - if (slot->client_id.len == client_id.len && - memcmp(slot->client_id.buf, client_id.buf, - client_id.len) == 0 && - (slot->state == DHCPV4_SERVER_ADDR_RESERVED || - slot->state == DHCPV4_SERVER_ADDR_ALLOCATED)) { - selected = slot; - break; - } - } - - if (selected != NULL) { - if (net_ipv4_addr_cmp(&selected->addr, &requested_ip)) { - uint32_t lease_time = dhcpv4_get_lease_time( - options, optlen); - - if (dhcpv4_send_ack(ctx, msg, &selected->addr, - lease_time, ¶ms, - false) < 0) { - return; - } - - selected->lease_time = lease_time; - selected->expiry = sys_timepoint_calc( - K_SECONDS(lease_time)); - dhcpv4_server_timeout_recalc(ctx); - } else { - dhcpv4_send_nak(ctx, msg); - } - } - - /* No notion of the client, remain silent. */ - return; - } - - /* Neither server ID or requested IP set, Request generated during - * RENEWING or REBINDING. - */ - - if (!net_if_ipv4_addr_mask_cmp(ctx->iface, &ciaddr)) { - /* Wrong subnet. */ - dhcpv4_send_nak(ctx, msg); - } - - for (int i = 0; i < ARRAY_SIZE(ctx->addr_pool); i++) { - struct dhcpv4_addr_slot *slot = &ctx->addr_pool[i]; - - if (net_ipv4_addr_cmp(&slot->addr, &ciaddr)) { - selected = slot; - break; - } - } - - if (selected != NULL) { - if (selected->state == DHCPV4_SERVER_ADDR_ALLOCATED && - selected->client_id.len == client_id.len && - memcmp(selected->client_id.buf, client_id.buf, - client_id.len) == 0) { - uint32_t lease_time = dhcpv4_get_lease_time( - options, optlen); - - if (dhcpv4_send_ack(ctx, msg, &ciaddr, lease_time, - ¶ms, false) < 0) { - return; - } - - selected->lease_time = lease_time; - selected->expiry = sys_timepoint_calc( - K_SECONDS(lease_time)); - dhcpv4_server_timeout_recalc(ctx); - } else { - dhcpv4_send_nak(ctx, msg); - } - } -} - -static void dhcpv4_handle_decline(struct dhcpv4_server_ctx *ctx, - struct dhcp_msg *msg, uint8_t *options, - uint8_t optlen) -{ - struct dhcpv4_client_id client_id; - struct in_addr requested_ip, server_id; - int ret; - - ret = dhcpv4_find_server_id_option(options, optlen, &server_id); - if (ret < 0) { - /* No server ID, ignore. */ - return; - } - - if (!net_ipv4_addr_cmp(&ctx->server_addr, &server_id)) { - /* Not for us, ignore. */ - return; - } - - ret = dhcpv4_get_client_id(msg, options, optlen, &client_id); - if (ret < 0) { - /* Failed to obtain Client ID, ignore. */ - return; - } - - ret = dhcpv4_find_requested_ip_option(options, optlen, - &requested_ip); - if (ret < 0) { - /* Requested IP missing, ignore. */ - return; - } - - LOG_ERR("Received DHCPv4 Decline for %s (address already in use)", - net_sprint_ipv4_addr(&requested_ip)); - - for (int i = 0; i < ARRAY_SIZE(ctx->addr_pool); i++) { - struct dhcpv4_addr_slot *slot = &ctx->addr_pool[i]; - - if (net_ipv4_addr_cmp(&slot->addr, &requested_ip) && - slot->client_id.len == client_id.len && - memcmp(slot->client_id.buf, client_id.buf, - client_id.len) == 0 && - (slot->state == DHCPV4_SERVER_ADDR_RESERVED || - slot->state == DHCPV4_SERVER_ADDR_ALLOCATED)) { - slot->state = DHCPV4_SERVER_ADDR_DECLINED; - slot->expiry = sys_timepoint_calc(K_FOREVER); - dhcpv4_server_timeout_recalc(ctx); - break; - } - } -} - -static void dhcpv4_handle_release(struct dhcpv4_server_ctx *ctx, - struct dhcp_msg *msg, uint8_t *options, - uint8_t optlen) -{ - struct dhcpv4_client_id client_id; - struct in_addr ciaddr, server_id; - int ret; - - ret = dhcpv4_find_server_id_option(options, optlen, &server_id); - if (ret < 0) { - /* No server ID, ignore. */ - return; - } - - if (!net_ipv4_addr_cmp(&ctx->server_addr, &server_id)) { - /* Not for us, ignore. */ - return; - } - - ret = dhcpv4_get_client_id(msg, options, optlen, &client_id); - if (ret < 0) { - /* Failed to obtain Client ID, ignore. */ - return; - } - - memcpy(&ciaddr, msg->ciaddr, sizeof(ciaddr)); - - for (int i = 0; i < ARRAY_SIZE(ctx->addr_pool); i++) { - struct dhcpv4_addr_slot *slot = &ctx->addr_pool[i]; - - if (net_ipv4_addr_cmp(&slot->addr, &ciaddr) && - slot->client_id.len == client_id.len && - memcmp(slot->client_id.buf, client_id.buf, - client_id.len) == 0 && - (slot->state == DHCPV4_SERVER_ADDR_RESERVED || - slot->state == DHCPV4_SERVER_ADDR_ALLOCATED)) { - LOG_DBG("DHCPv4 processing Release - %s", - net_sprint_ipv4_addr(&slot->addr)); - - slot->state = DHCPV4_SERVER_ADDR_FREE; - slot->expiry = sys_timepoint_calc(K_FOREVER); - dhcpv4_server_timeout_recalc(ctx); - break; - } - } -} - -static void dhcpv4_handle_inform(struct dhcpv4_server_ctx *ctx, - struct dhcp_msg *msg, uint8_t *options, - uint8_t optlen) -{ - struct dhcpv4_parameter_request_list params = { 0 }; - - (void)dhcpv4_find_parameter_request_list_option(options, optlen, ¶ms); - (void)dhcpv4_send_ack(ctx, msg, (struct in_addr *)msg->ciaddr, 0, - ¶ms, true); -} - -/* Server core. */ - -static void dhcpv4_server_timeout(struct k_work *work) -{ - struct k_work_delayable *dwork = k_work_delayable_from_work(work); - struct dhcpv4_server_ctx *ctx = - CONTAINER_OF(dwork, struct dhcpv4_server_ctx, timeout_work); - - - k_mutex_lock(&server_lock, K_FOREVER); - - for (int i = 0; i < ARRAY_SIZE(ctx->addr_pool); i++) { - struct dhcpv4_addr_slot *slot = &ctx->addr_pool[i]; - - if (slot->state == DHCPV4_SERVER_ADDR_RESERVED || - slot->state == DHCPV4_SERVER_ADDR_ALLOCATED) { - if (sys_timepoint_expired(slot->expiry)) { - LOG_DBG("Address %s expired", - net_sprint_ipv4_addr(&slot->addr)); - slot->state = DHCPV4_SERVER_ADDR_FREE; - } - } - } - - dhcpv4_server_timeout_recalc(ctx); - - k_mutex_unlock(&server_lock); -} - -static void dhcpv4_process_data(struct dhcpv4_server_ctx *ctx, uint8_t *data, - size_t datalen) -{ - struct dhcp_msg *msg; - uint8_t msgtype; - int ret; - - if (datalen < sizeof(struct dhcp_msg)) { - LOG_DBG("DHCPv4 server malformed message"); - return; - } - - msg = (struct dhcp_msg *)data; - - if (msg->op != DHCPV4_MSG_BOOT_REQUEST) { - /* Silently drop messages other than BOOTREQUEST */ - return; - } - - data += sizeof(struct dhcp_msg); - datalen -= sizeof(struct dhcp_msg); - - /* Skip server hostname/filename/option cookie */ - if (datalen < (SIZE_OF_SNAME + SIZE_OF_FILE + SIZE_OF_MAGIC_COOKIE)) { - return; - } - - data += SIZE_OF_SNAME + SIZE_OF_FILE + SIZE_OF_MAGIC_COOKIE; - datalen -= SIZE_OF_SNAME + SIZE_OF_FILE + SIZE_OF_MAGIC_COOKIE; - - /* Search options for DHCP message type. */ - ret = dhcpv4_find_message_type_option(data, datalen, &msgtype); - if (ret < 0) { - LOG_ERR("No message type option"); - return; - } - - k_mutex_lock(&server_lock, K_FOREVER); - - switch (msgtype) { - case NET_DHCPV4_MSG_TYPE_DISCOVER: - dhcpv4_handle_discover(ctx, msg, data, datalen); - break; - case NET_DHCPV4_MSG_TYPE_REQUEST: - dhcpv4_handle_request(ctx, msg, data, datalen); - break; - case NET_DHCPV4_MSG_TYPE_DECLINE: - dhcpv4_handle_decline(ctx, msg, data, datalen); - break; - case NET_DHCPV4_MSG_TYPE_RELEASE: - dhcpv4_handle_release(ctx, msg, data, datalen); - break; - case NET_DHCPV4_MSG_TYPE_INFORM: - dhcpv4_handle_inform(ctx, msg, data, datalen); - break; - - case NET_DHCPV4_MSG_TYPE_OFFER: - case NET_DHCPV4_MSG_TYPE_ACK: - case NET_DHCPV4_MSG_TYPE_NAK: - default: - /* Ignore server initiated and unknown message types. */ - break; - } - - k_mutex_unlock(&server_lock); -} - -static void dhcpv4_server_cb(struct k_work *work) -{ - struct net_socket_service_event *evt = - CONTAINER_OF(work, struct net_socket_service_event, work); - struct dhcpv4_server_ctx *ctx = NULL; - uint8_t recv_buf[NET_IPV4_MTU]; - int ret; - - for (int i = 0; i < ARRAY_SIZE(server_ctx); i++) { - if (server_ctx[i].sock == evt->event.fd) { - ctx = &server_ctx[i]; - break; - } - } - - if (ctx == NULL) { - LOG_ERR("No DHCPv4 server context found for given FD."); - return; - } - - if (evt->event.revents & ZSOCK_POLLERR) { - LOG_ERR("DHCPv4 server poll revents error"); - net_dhcpv4_server_stop(ctx->iface); - return; - } - - if (!(evt->event.revents & ZSOCK_POLLIN)) { - return; - } - - ret = zsock_recvfrom(evt->event.fd, recv_buf, sizeof(recv_buf), - ZSOCK_MSG_DONTWAIT, NULL, 0); - if (ret < 0) { - if (errno == EAGAIN) { - return; - } - - LOG_ERR("DHCPv4 server recv error, %d", errno); - net_dhcpv4_server_stop(ctx->iface); - return; - } - - dhcpv4_process_data(ctx, recv_buf, ret); -} - -NET_SOCKET_SERVICE_SYNC_DEFINE_STATIC(dhcpv4_server, NULL, dhcpv4_server_cb, - CONFIG_NET_DHCPV4_SERVER_INSTANCES); - -int net_dhcpv4_server_start(struct net_if *iface, struct in_addr *base_addr) -{ - struct sockaddr_in addr = { - .sin_family = AF_INET, - .sin_addr = INADDR_ANY_INIT, - .sin_port = htons(DHCPV4_SERVER_PORT), - }; - struct ifreq ifreq = { 0 }; - int ret, sock = -1, slot = -1; - const struct in_addr *server_addr; - struct in_addr netmask; - - if (iface == NULL || base_addr == NULL) { - return -EINVAL; - } - - if (!net_if_ipv4_addr_mask_cmp(iface, base_addr)) { - LOG_ERR("Address pool does not belong to the interface subnet."); - return -EINVAL; - } - - server_addr = net_if_ipv4_select_src_addr(iface, base_addr); - if (server_addr == NULL) { - LOG_ERR("Failed to obtain a valid server address."); - return -EINVAL; - } - - netmask = net_if_ipv4_get_netmask(iface); - if (net_ipv4_is_addr_unspecified(&netmask)) { - LOG_ERR("Failed to obtain subnet mask."); - return -EINVAL; - } - - k_mutex_lock(&server_lock, K_FOREVER); - - for (int i = 0; i < ARRAY_SIZE(server_ctx); i++) { - if (server_ctx[i].iface != NULL) { - if (server_ctx[i].iface == iface) { - LOG_ERR("DHCPv4 server instance already running."); - ret = -EALREADY; - goto error; - } - } else { - if (slot < 0) { - slot = i; - } - } - } - - if (slot < 0) { - LOG_ERR("No free DHCPv4 server intance."); - ret = -ENOMEM; - goto error; - } - - ret = net_if_get_name(iface, ifreq.ifr_name, sizeof(ifreq.ifr_name)); - if (ret < 0) { - LOG_ERR("Failed to obtain interface name."); - goto error; - } - - sock = zsock_socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP); - if (sock < 0) { - ret = errno; - LOG_ERR("Failed to create DHCPv4 server socket, %d", ret); - goto error; - } - - ret = zsock_setsockopt(sock, SOL_SOCKET, SO_BINDTODEVICE, &ifreq, - sizeof(ifreq)); - if (ret < 0) { - ret = errno; - LOG_ERR("Failed to bind DHCPv4 server socket with interface, %d", - ret); - goto error; - } - - ret = zsock_bind(sock, (struct sockaddr *)&addr, sizeof(addr)); - if (ret < 0) { - ret = errno; - LOG_ERR("Failed to bind DHCPv4 server socket, %d", ret); - goto error; - } - - fds[slot].fd = sock; - fds[slot].events = ZSOCK_POLLIN; - - server_ctx[slot].iface = iface; - server_ctx[slot].sock = sock; - server_ctx[slot].server_addr = *server_addr; - server_ctx[slot].netmask = netmask; - - k_work_init_delayable(&server_ctx[slot].timeout_work, - dhcpv4_server_timeout); - - LOG_DBG("Started DHCPv4 server, address pool:"); - for (int i = 0; i < ARRAY_SIZE(server_ctx[slot].addr_pool); i++) { - server_ctx[slot].addr_pool[i].state = DHCPV4_SERVER_ADDR_FREE; - server_ctx[slot].addr_pool[i].addr.s_addr = - htonl(ntohl(base_addr->s_addr) + i); - - LOG_DBG("\t%2d: %s", i, - net_sprint_ipv4_addr( - &server_ctx[slot].addr_pool[i].addr)); - } - - ret = net_socket_service_register(&dhcpv4_server, fds, ARRAY_SIZE(fds), - NULL); - if (ret < 0) { - LOG_ERR("Failed to register socket service, %d", ret); - memset(&server_ctx[slot], 0, sizeof(server_ctx[slot])); - fds[slot].fd = -1; - goto error; - } - - k_mutex_unlock(&server_lock); - - return 0; - -error: - if (sock >= 0) { - (void)zsock_close(sock); - } - - k_mutex_unlock(&server_lock); - - return ret; -} - -int net_dhcpv4_server_stop(struct net_if *iface) -{ - struct k_work_sync sync; - int slot = -1; - int ret = 0; - bool service_stop = true; - - if (iface == NULL) { - return -EINVAL; - } - - k_mutex_lock(&server_lock, K_FOREVER); - - for (int i = 0; i < ARRAY_SIZE(server_ctx); i++) { - if (server_ctx[i].iface == iface) { - slot = i; - break; - } - } - - if (slot < 0) { - ret = -ENOENT; - goto out; - } - - fds[slot].fd = -1; - (void)zsock_close(server_ctx[slot].sock); - - k_work_cancel_delayable_sync(&server_ctx[slot].timeout_work, &sync); - - memset(&server_ctx[slot], 0, sizeof(server_ctx[slot])); - - for (int i = 0; i < ARRAY_SIZE(fds); i++) { - if (fds[i].fd >= 0) { - service_stop = false; - break; - } - } - - if (service_stop) { - ret = net_socket_service_unregister(&dhcpv4_server); - } else { - ret = net_socket_service_register(&dhcpv4_server, fds, - ARRAY_SIZE(fds), NULL); - } - -out: - k_mutex_unlock(&server_lock); - - return ret; -} - -static void dhcpv4_server_foreach_lease_on_ctx(struct dhcpv4_server_ctx *ctx, - net_dhcpv4_lease_cb_t cb, - void *user_data) -{ - for (int i = 0; i < ARRAY_SIZE(ctx->addr_pool); i++) { - struct dhcpv4_addr_slot *addr = &ctx->addr_pool[i]; - - if (addr->state != DHCPV4_SERVER_ADDR_FREE) { - cb(ctx->iface, addr, user_data); - } - } -} - -int net_dhcpv4_server_foreach_lease(struct net_if *iface, - net_dhcpv4_lease_cb_t cb, - void *user_data) -{ - int slot = -1; - int ret = 0; - - k_mutex_lock(&server_lock, K_FOREVER); - - if (iface == NULL) { - for (int i = 0; i < ARRAY_SIZE(server_ctx); i++) { - if (server_ctx[i].iface != NULL) { - dhcpv4_server_foreach_lease_on_ctx( - &server_ctx[i], cb, user_data); - } - } - - return 0; - } - - for (int i = 0; i < ARRAY_SIZE(server_ctx); i++) { - if (server_ctx[i].iface == iface) { - slot = i; - break; - } - } - - if (slot < 0) { - ret = -ENOENT; - goto out; - } - - dhcpv4_server_foreach_lease_on_ctx(&server_ctx[slot], cb, user_data); - -out: - k_mutex_unlock(&server_lock); - - return ret; -} - -void net_dhcpv4_server_init(void) -{ - for (int i = 0; i < ARRAY_SIZE(fds); i++) { - fds[i].fd = -1; - } -} From c2c869ff611e10513e5b2409cff12907ba5a3c4d Mon Sep 17 00:00:00 2001 From: Robert Lubos Date: Tue, 6 Feb 2024 11:07:01 +0100 Subject: [PATCH 3514/3723] Revert "[nrf fromtree] net: if: Add function to obtain IPv4 netmask" This reverts commit f3d115bad99c167900b83d59dd1a88bb75acf27a. Signed-off-by: Robert Lubos --- include/zephyr/net/net_if.h | 9 --------- subsys/net/ip/net_if.c | 21 --------------------- 2 files changed, 30 deletions(-) diff --git a/include/zephyr/net/net_if.h b/include/zephyr/net/net_if.h index f1e5be67cf7..788c3316391 100644 --- a/include/zephyr/net/net_if.h +++ b/include/zephyr/net/net_if.h @@ -2217,15 +2217,6 @@ struct in_addr *net_if_ipv4_get_ll(struct net_if *iface, struct in_addr *net_if_ipv4_get_global_addr(struct net_if *iface, enum net_addr_state addr_state); -/** - * @brief Get IPv4 netmask of an interface. - * - * @param iface Interface to use. - * - * @return The netmask set on the interface, unspecified address if not found. - */ -struct in_addr net_if_ipv4_get_netmask(struct net_if *iface); - /** * @brief Set IPv4 netmask for an interface. * diff --git a/subsys/net/ip/net_if.c b/subsys/net/ip/net_if.c index 1a8199ad62c..00c9c74495d 100644 --- a/subsys/net/ip/net_if.c +++ b/subsys/net/ip/net_if.c @@ -3532,27 +3532,6 @@ static inline int z_vrfy_net_if_ipv4_addr_lookup_by_index( #include #endif -struct in_addr net_if_ipv4_get_netmask(struct net_if *iface) -{ - struct in_addr netmask = { 0 }; - - net_if_lock(iface); - - if (net_if_config_ipv4_get(iface, NULL) < 0) { - goto out; - } - - if (!iface->config.ip.ipv4) { - goto out; - } - - netmask = iface->config.ip.ipv4->netmask; -out: - net_if_unlock(iface); - - return netmask; -} - void net_if_ipv4_set_netmask(struct net_if *iface, const struct in_addr *netmask) { From 19bb99e699cc57fb5f28f052822756bd52b4e974 Mon Sep 17 00:00:00 2001 From: Robert Lubos Date: Tue, 6 Feb 2024 11:07:02 +0100 Subject: [PATCH 3515/3723] Revert "[nrf fromtree] net: arp: Make arp_update() function externally visible" This reverts commit 70abf9f2c7ff978d3218e6a1246fb75dcfa0cd19. Signed-off-by: Robert Lubos --- subsys/net/l2/ethernet/arp.c | 34 +++++++++++++++++----------------- subsys/net/l2/ethernet/arp.h | 4 ---- 2 files changed, 17 insertions(+), 21 deletions(-) diff --git a/subsys/net/l2/ethernet/arp.c b/subsys/net/l2/ethernet/arp.c index 6be7255b19b..39a06ed64a0 100644 --- a/subsys/net/l2/ethernet/arp.c +++ b/subsys/net/l2/ethernet/arp.c @@ -457,11 +457,11 @@ static void arp_gratuitous(struct net_if *iface, } } -void net_arp_update(struct net_if *iface, - struct in_addr *src, - struct net_eth_addr *hwaddr, - bool gratuitous, - bool force) +static void arp_update(struct net_if *iface, + struct in_addr *src, + struct net_eth_addr *hwaddr, + bool gratuitous, + bool force) { struct arp_entry *entry; struct net_pkt *pkt; @@ -647,10 +647,10 @@ enum net_verdict net_arp_input(struct net_pkt *pkt, /* If the IP address is in our cache, * then update it here. */ - net_arp_update(net_pkt_iface(pkt), - (struct in_addr *)arp_hdr->src_ipaddr, - &arp_hdr->src_hwaddr, - true, false); + arp_update(net_pkt_iface(pkt), + (struct in_addr *)arp_hdr->src_ipaddr, + &arp_hdr->src_hwaddr, + true, false); break; } } @@ -689,10 +689,10 @@ enum net_verdict net_arp_input(struct net_pkt *pkt, net_sprint_ll_addr((uint8_t *)&arp_hdr->src_hwaddr, arp_hdr->hwlen)); - net_arp_update(net_pkt_iface(pkt), - (struct in_addr *)arp_hdr->src_ipaddr, - &arp_hdr->src_hwaddr, - false, true); + arp_update(net_pkt_iface(pkt), + (struct in_addr *)arp_hdr->src_ipaddr, + &arp_hdr->src_hwaddr, + false, true); dst_hw_addr = &arp_hdr->src_hwaddr; } else { @@ -711,10 +711,10 @@ enum net_verdict net_arp_input(struct net_pkt *pkt, case NET_ARP_REPLY: if (net_ipv4_is_my_addr((struct in_addr *)arp_hdr->dst_ipaddr)) { - net_arp_update(net_pkt_iface(pkt), - (struct in_addr *)arp_hdr->src_ipaddr, - &arp_hdr->src_hwaddr, - false, false); + arp_update(net_pkt_iface(pkt), + (struct in_addr *)arp_hdr->src_ipaddr, + &arp_hdr->src_hwaddr, + false, false); } break; diff --git a/subsys/net/l2/ethernet/arp.h b/subsys/net/l2/ethernet/arp.h index 46589cbc1f7..28cafe5f20a 100644 --- a/subsys/net/l2/ethernet/arp.h +++ b/subsys/net/l2/ethernet/arp.h @@ -67,9 +67,6 @@ int net_arp_foreach(net_arp_cb_t cb, void *user_data); void net_arp_clear_cache(struct net_if *iface); void net_arp_init(void); -void net_arp_update(struct net_if *iface, struct in_addr *src, - struct net_eth_addr *hwaddr, bool gratuitous, - bool force); /** * @} @@ -86,7 +83,6 @@ void net_arp_update(struct net_if *iface, struct in_addr *src, #define net_arp_foreach(...) 0 #define net_arp_init(...) #define net_arp_clear_pending(...) 0 -#define net_arp_update(...) #endif /* CONFIG_NET_ARP */ From bc4e6ec174f84ca26d1123e065c7416672ebd605 Mon Sep 17 00:00:00 2001 From: Robert Lubos Date: Tue, 6 Feb 2024 11:07:02 +0100 Subject: [PATCH 3516/3723] Revert "[nrf fromtree] net: socket_service: Fix iterable section location" This reverts commit 93ac51d09be899f0f5e5fea4e03dea49e60ce882. Signed-off-by: Robert Lubos --- include/zephyr/linker/common-rom/common-rom-net.ld | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/include/zephyr/linker/common-rom/common-rom-net.ld b/include/zephyr/linker/common-rom/common-rom-net.ld index 2aa46dfecf5..18360212edc 100644 --- a/include/zephyr/linker/common-rom/common-rom-net.ld +++ b/include/zephyr/linker/common-rom/common-rom-net.ld @@ -23,5 +23,5 @@ #endif #if defined(CONFIG_NET_SOCKETS_SERVICE) - ITERABLE_SECTION_ROM(net_socket_service_desc, 4) + ITERABLE_SECTION_RAM(net_socket_service_desc, 4) #endif From 55332b6479dd52d8f0c5cb3fea95c66707425531 Mon Sep 17 00:00:00 2001 From: Robert Lubos Date: Tue, 6 Feb 2024 11:07:02 +0100 Subject: [PATCH 3517/3723] Revert "[nrf fromtree] net: socket_service: Add underscore in the idx variable name" This reverts commit 227b98f4aeeabb05f6660944f043a51bf6ef9f15. Signed-off-by: Robert Lubos --- include/zephyr/net/socket_service.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/include/zephyr/net/socket_service.h b/include/zephyr/net/socket_service.h index a4e21f00a33..16da94d238b 100644 --- a/include/zephyr/net/socket_service.h +++ b/include/zephyr/net/socket_service.h @@ -76,7 +76,7 @@ struct net_socket_service_desc { }; #define __z_net_socket_svc_get_name(_svc_id) __z_net_socket_service_##_svc_id -#define __z_net_socket_svc_get_idx(_svc_id) __z_net_socket_service_idx_##_svc_id +#define __z_net_socket_svc_get_idx(_svc_id) __z_net_socket_service_idx##_svc_id #define __z_net_socket_svc_get_owner __FILE__ ":" STRINGIFY(__LINE__) extern void net_socket_service_callback(struct k_work *work); From 97e2eabb9f41e8a8bac321873f3a57e81a30e842 Mon Sep 17 00:00:00 2001 From: Robert Lubos Date: Tue, 6 Feb 2024 11:07:02 +0100 Subject: [PATCH 3518/3723] Revert "[nrf fromtree] net: sockets: Create a socket service API" This reverts commit 87cbab4403bc4627e1454521631beba6d925355a. Signed-off-by: Robert Lubos --- .../linker/common-rom/common-rom-net.ld | 4 - include/zephyr/net/socket_service.h | 246 --------------- subsys/net/lib/sockets/CMakeLists.txt | 1 - subsys/net/lib/sockets/Kconfig | 25 -- subsys/net/lib/sockets/sockets_service.c | 291 ------------------ 5 files changed, 567 deletions(-) delete mode 100644 include/zephyr/net/socket_service.h delete mode 100644 subsys/net/lib/sockets/sockets_service.c diff --git a/include/zephyr/linker/common-rom/common-rom-net.ld b/include/zephyr/linker/common-rom/common-rom-net.ld index 18360212edc..71c1c1e089f 100644 --- a/include/zephyr/linker/common-rom/common-rom-net.ld +++ b/include/zephyr/linker/common-rom/common-rom-net.ld @@ -21,7 +21,3 @@ #if defined(CONFIG_COAP_SERVER) ITERABLE_SECTION_ROM(coap_service, 4) #endif - -#if defined(CONFIG_NET_SOCKETS_SERVICE) - ITERABLE_SECTION_RAM(net_socket_service_desc, 4) -#endif diff --git a/include/zephyr/net/socket_service.h b/include/zephyr/net/socket_service.h deleted file mode 100644 index 16da94d238b..00000000000 --- a/include/zephyr/net/socket_service.h +++ /dev/null @@ -1,246 +0,0 @@ -/** - * @file - * @brief BSD Socket service API - * - * API can be used to install a k_work that is called - * if there is data received to a socket. - */ - -/* - * Copyright (c) 2023 Nordic Semiconductor ASA - * - * SPDX-License-Identifier: Apache-2.0 - */ - -#ifndef ZEPHYR_INCLUDE_NET_SOCKET_SERVICE_H_ -#define ZEPHYR_INCLUDE_NET_SOCKET_SERVICE_H_ - -/** - * @brief BSD socket service API - * @defgroup bsd_socket_service BSD socket service API - * @ingroup networking - * @{ - */ - -#include -#include -#include - -#ifdef __cplusplus -extern "C" { -#endif - -/** - * This struct contains information which socket triggered - * calls to the callback function. - */ -struct net_socket_service_event { - /** k_work that is done when there is desired activity in file descriptor. */ - struct k_work work; - /** Callback to be called for desired socket activity */ - k_work_handler_t callback; - /** Socket information that triggered this event. */ - struct zsock_pollfd event; - /** User data */ - void *user_data; - /** Service back pointer */ - struct net_socket_service_desc *svc; -}; - -/** - * Main structure holding socket service configuration information. - * The k_work item is created so that when there is data coming - * to those fds, the k_work callback is then called. - * The workqueue can be set NULL in which case system workqueue is used. - * The service descriptor should be created at built time, and then used - * as a parameter to register the sockets to be monitored. - * User should create needed sockets and then setup the poll struct and - * then register the sockets to be monitored at runtime. - */ -struct net_socket_service_desc { -#if CONFIG_NET_SOCKETS_LOG_LEVEL >= LOG_LEVEL_DBG - /** - * Owner name. This can be used in debugging to see who has - * registered this service. - */ - const char *owner; -#endif - /** Workqueue where the work is submitted. */ - struct k_work_q *work_q; - /** Pointer to the list of services that we are listening */ - struct net_socket_service_event *pev; - /** Length of the pollable socket array for this service. */ - int pev_len; - /** Where are my pollfd entries in the global list */ - int *idx; -}; - -#define __z_net_socket_svc_get_name(_svc_id) __z_net_socket_service_##_svc_id -#define __z_net_socket_svc_get_idx(_svc_id) __z_net_socket_service_idx##_svc_id -#define __z_net_socket_svc_get_owner __FILE__ ":" STRINGIFY(__LINE__) - -extern void net_socket_service_callback(struct k_work *work); - -#if CONFIG_NET_SOCKETS_LOG_LEVEL >= LOG_LEVEL_DBG -#define NET_SOCKET_SERVICE_OWNER .owner = __z_net_socket_svc_get_owner, -#else -#define NET_SOCKET_SERVICE_OWNER -#endif - -#define NET_SOCKET_SERVICE_CALLBACK_MODE(_flag) \ - IF_ENABLED(_flag, \ - (.work = Z_WORK_INITIALIZER(net_socket_service_callback),)) - -#define __z_net_socket_service_define(_name, _work_q, _cb, _count, _async, ...) \ - static int __z_net_socket_svc_get_idx(_name); \ - static struct net_socket_service_event \ - __z_net_socket_svc_get_name(_name)[_count] = { \ - [0 ... ((_count) - 1)] = { \ - .event.fd = -1, /* Invalid socket */ \ - NET_SOCKET_SERVICE_CALLBACK_MODE(_async) \ - .callback = _cb, \ - } \ - }; \ - COND_CODE_0(NUM_VA_ARGS_LESS_1(__VA_ARGS__), (), __VA_ARGS__) \ - const STRUCT_SECTION_ITERABLE(net_socket_service_desc, _name) = { \ - NET_SOCKET_SERVICE_OWNER \ - .work_q = (_work_q), \ - .pev = __z_net_socket_svc_get_name(_name), \ - .pev_len = (_count), \ - .idx = &__z_net_socket_svc_get_idx(_name), \ - } - -/** - * @brief Statically define a network socket service. - * The user callback is called asynchronously for this service meaning that - * the service API will not wait until the user callback returns before continuing - * with next socket service. - * - * The socket service can be accessed outside the module where it is defined using: - * - * @code extern struct net_socket_service_desc ; @endcode - * - * @note This macro cannot be used together with a static keyword. - * If such a use-case is desired, use NET_SOCKET_SERVICE_ASYNC_DEFINE_STATIC - * instead. - * - * @param name Name of the service. - * @param work_q Pointer to workqueue where the work is done. Can be null in which case - * system workqueue is used. - * @param cb Callback function that is called for socket activity. - * @param count How many pollable sockets is needed for this service. - */ -#define NET_SOCKET_SERVICE_ASYNC_DEFINE(name, work_q, cb, count) \ - __z_net_socket_service_define(name, work_q, cb, count, 1) - -/** - * @brief Statically define a network socket service in a private (static) scope. - * The user callback is called asynchronously for this service meaning that - * the service API will not wait until the user callback returns before continuing - * with next socket service. - * - * @param name Name of the service. - * @param work_q Pointer to workqueue where the work is done. Can be null in which case - * system workqueue is used. - * @param cb Callback function that is called for socket activity. - * @param count How many pollable sockets is needed for this service. - */ -#define NET_SOCKET_SERVICE_ASYNC_DEFINE_STATIC(name, work_q, cb, count) \ - __z_net_socket_service_define(name, work_q, cb, count, 1, static) - -/** - * @brief Statically define a network socket service. - * The user callback is called synchronously for this service meaning that - * the service API will wait until the user callback returns before continuing - * with next socket service. - * - * The socket service can be accessed outside the module where it is defined using: - * - * @code extern struct net_socket_service_desc ; @endcode - * - * @note This macro cannot be used together with a static keyword. - * If such a use-case is desired, use NET_SOCKET_SERVICE_SYNC_DEFINE_STATIC - * instead. - * - * @param name Name of the service. - * @param work_q Pointer to workqueue where the work is done. Can be null in which case - * system workqueue is used. - * @param cb Callback function that is called for socket activity. - * @param count How many pollable sockets is needed for this service. - */ -#define NET_SOCKET_SERVICE_SYNC_DEFINE(name, work_q, cb, count) \ - __z_net_socket_service_define(name, work_q, cb, count, 0) - -/** - * @brief Statically define a network socket service in a private (static) scope. - * The user callback is called synchronously for this service meaning that - * the service API will wait until the user callback returns before continuing - * with next socket service. - * - * @param name Name of the service. - * @param work_q Pointer to workqueue where the work is done. Can be null in which case - * system workqueue is used. - * @param cb Callback function that is called for socket activity. - * @param count How many pollable sockets is needed for this service. - */ -#define NET_SOCKET_SERVICE_SYNC_DEFINE_STATIC(name, work_q, cb, count) \ - __z_net_socket_service_define(name, work_q, cb, count, 0, static) - -/** - * @brief Register pollable sockets. - * - * @param service Pointer to a service description. - * @param fds Socket array to poll. - * @param len Length of the socket array. - * @param user_data User specific data. - * - * @retval 0 No error - * @retval -ENOENT Service is not found. - * @retval -ENINVAL Invalid parameter. - */ -__syscall int net_socket_service_register(const struct net_socket_service_desc *service, - struct zsock_pollfd *fds, int len, void *user_data); - -/** - * @brief Unregister pollable sockets. - * - * @param service Pointer to a service description. - * - * @retval 0 No error - * @retval -ENOENT Service is not found. - * @retval -ENINVAL Invalid parameter. - */ -static inline int net_socket_service_unregister(const struct net_socket_service_desc *service) -{ - return net_socket_service_register(service, NULL, 0, NULL); -} - -/** - * @typedef net_socket_service_cb_t - * @brief Callback used while iterating over socket services. - * - * @param svc Pointer to current socket service. - * @param user_data A valid pointer to user data or NULL - */ -typedef void (*net_socket_service_cb_t)(const struct net_socket_service_desc *svc, - void *user_data); - -/** - * @brief Go through all the socket services and call callback for each service. - * - * @param cb User-supplied callback function to call - * @param user_data User specified data - */ -void net_socket_service_foreach(net_socket_service_cb_t cb, void *user_data); - -#ifdef __cplusplus -} -#endif - -#include - -/** - * @} - */ - -#endif /* ZEPHYR_INCLUDE_NET_SOCKET_SERVICE_H_ */ diff --git a/subsys/net/lib/sockets/CMakeLists.txt b/subsys/net/lib/sockets/CMakeLists.txt index 253cb4a182f..7ffd6dc476b 100644 --- a/subsys/net/lib/sockets/CMakeLists.txt +++ b/subsys/net/lib/sockets/CMakeLists.txt @@ -26,7 +26,6 @@ zephyr_library_sources_ifdef(CONFIG_NET_SOCKETS_SOCKOPT_TLS sockets_tls.c zephyr_library_sources_ifdef(CONFIG_NET_SOCKETS_OFFLOAD socket_offload.c) zephyr_library_sources_ifdef(CONFIG_NET_SOCKETS_OFFLOAD_DISPATCHER socket_dispatcher.c) zephyr_library_sources_ifdef(CONFIG_NET_SOCKETS_OBJ_CORE socket_obj_core.c) -zephyr_library_sources_ifdef(CONFIG_NET_SOCKETS_SERVICE sockets_service.c) if(CONFIG_NET_SOCKETS_NET_MGMT) zephyr_library_sources(sockets_net_mgmt.c) diff --git a/subsys/net/lib/sockets/Kconfig b/subsys/net/lib/sockets/Kconfig index 40d86b9498f..b2da30c1e48 100644 --- a/subsys/net/lib/sockets/Kconfig +++ b/subsys/net/lib/sockets/Kconfig @@ -73,31 +73,6 @@ config NET_SOCKET_MAX_SEND_WAIT The maximum time a socket is waiting for a blocked connection before returning an ENOBUFS error. -config NET_SOCKETS_SERVICE - bool "Socket service support [EXPERIMENTAL]" - select EXPERIMENTAL - select EVENTFD - help - The socket service can monitor multiple sockets and save memory - by only having one thread listening socket data. If data is received - in the monitored socket, a user supplied work is called. - Note that you need to set CONFIG_NET_SOCKETS_POLL_MAX high enough - so that enough sockets entries can be serviced. This depends on - system needs as multiple services can be activated at the same time - depending on network configuration. - -config NET_SOCKETS_SERVICE_STACK_SIZE - int "Stack size for the thread handling socket services" - default 1200 - depends on NET_SOCKETS_SERVICE - help - Set the internal stack size for the thread that polls sockets. - -config NET_SOCKETS_SERVICE_INIT_PRIO - int "Startup priority for the network socket service" - default 95 - depends on NET_SOCKETS_SERVICE - config NET_SOCKETS_SOCKOPT_TLS bool "TCP TLS socket option support [EXPERIMENTAL]" imply TLS_CREDENTIALS diff --git a/subsys/net/lib/sockets/sockets_service.c b/subsys/net/lib/sockets/sockets_service.c deleted file mode 100644 index d253ece629c..00000000000 --- a/subsys/net/lib/sockets/sockets_service.c +++ /dev/null @@ -1,291 +0,0 @@ -/* - * Copyright (c) 2023 Nordic Semiconductor ASA - * - * SPDX-License-Identifier: Apache-2.0 - */ - -#include -LOG_MODULE_REGISTER(net_sock_svc, CONFIG_NET_SOCKETS_LOG_LEVEL); - -#include -#include -#include - -static int init_socket_service(void); -static bool init_done; - -static K_MUTEX_DEFINE(lock); -static K_CONDVAR_DEFINE(wait_start); - -STRUCT_SECTION_START_EXTERN(net_socket_service_desc); -STRUCT_SECTION_END_EXTERN(net_socket_service_desc); - -static struct service { - /* The +1 is for triggering events from register function */ - struct zsock_pollfd events[1 + CONFIG_NET_SOCKETS_POLL_MAX]; - int count; -} ctx; - -#define get_idx(svc) (*(svc->idx)) - -void net_socket_service_foreach(net_socket_service_cb_t cb, void *user_data) -{ - STRUCT_SECTION_FOREACH(net_socket_service_desc, svc) { - cb(svc, user_data); - } -} - -static void cleanup_svc_events(const struct net_socket_service_desc *svc) -{ - for (int i = 0; i < svc->pev_len; i++) { - ctx.events[get_idx(svc) + i].fd = -1; - svc->pev[i].event.fd = -1; - svc->pev[i].event.events = 0; - } -} - -int z_impl_net_socket_service_register(const struct net_socket_service_desc *svc, - struct zsock_pollfd *fds, int len, - void *user_data) -{ - int i, ret = -ENOENT; - - k_mutex_lock(&lock, K_FOREVER); - - if (!init_done) { - (void)k_condvar_wait(&wait_start, &lock, K_FOREVER); - } - - if (STRUCT_SECTION_START(net_socket_service_desc) > svc || - STRUCT_SECTION_END(net_socket_service_desc) <= svc) { - goto out; - } - - if (fds == NULL) { - cleanup_svc_events(svc); - } else { - if (len > svc->pev_len) { - NET_DBG("Too many file descriptors, " - "max is %d for service %p", - svc->pev_len, svc); - ret = -ENOMEM; - goto out; - } - - for (i = 0; i < len; i++) { - svc->pev[i].event = fds[i]; - svc->pev[i].user_data = user_data; - } - - for (i = 0; i < svc->pev_len; i++) { - ctx.events[get_idx(svc) + i] = svc->pev[i].event; - } - } - - /* Tell the thread to re-read the variables */ - eventfd_write(ctx.events[0].fd, 1); - ret = 0; - -out: - k_mutex_unlock(&lock); - - return ret; -} - -static struct net_socket_service_desc *find_svc_and_event( - struct zsock_pollfd *pev, - struct net_socket_service_event **event) -{ - STRUCT_SECTION_FOREACH(net_socket_service_desc, svc) { - for (int i = 0; i < svc->pev_len; i++) { - if (svc->pev[i].event.fd == pev->fd) { - *event = &svc->pev[i]; - return svc; - } - } - } - - return NULL; -} - -/* We do not set the user callback to our work struct because we need to - * hook into the flow and restore the global poll array so that the next poll - * round will not notice it and call the callback again while we are - * servicing the callback. - */ -void net_socket_service_callback(struct k_work *work) -{ - struct net_socket_service_event *pev = - CONTAINER_OF(work, struct net_socket_service_event, work); - struct net_socket_service_desc *svc = pev->svc; - struct net_socket_service_event ev = *pev; - - ev.callback(&ev.work); - - /* Copy back the socket fd to the global array because we marked - * it as -1 when triggering the work. - */ - for (int i = 0; i < svc->pev_len; i++) { - ctx.events[get_idx(svc) + i] = svc->pev[i].event; - } -} - -static int call_work(struct zsock_pollfd *pev, struct k_work_q *work_q, - struct k_work *work) -{ - int ret = 0; - - /* Mark the global fd non pollable so that we do not - * call the callback second time. - */ - pev->fd = -1; - - if (work->handler == NULL) { - /* Synchronous call */ - net_socket_service_callback(work); - } else { - if (work_q != NULL) { - ret = k_work_submit_to_queue(work_q, work); - } else { - ret = k_work_submit(work); - } - - k_yield(); - } - - return ret; - -} - -static int trigger_work(struct zsock_pollfd *pev) -{ - struct net_socket_service_event *event; - struct net_socket_service_desc *svc; - - svc = find_svc_and_event(pev, &event); - if (svc == NULL) { - return -ENOENT; - } - - event->svc = svc; - - /* Copy the triggered event to our event so that we know what - * was actually causing the event. - */ - event->event = *pev; - - return call_work(pev, svc->work_q, &event->work); -} - -static void socket_service_thread(void) -{ - int ret, i, fd, count = 0; - eventfd_t value; - - STRUCT_SECTION_COUNT(net_socket_service_desc, &ret); - if (ret == 0) { - NET_INFO("No socket services found, service disabled."); - goto fail; - } - - /* Create contiguous poll event array to enable socket polling */ - STRUCT_SECTION_FOREACH(net_socket_service_desc, svc) { - get_idx(svc) = count + 1; - count += svc->pev_len; - } - - if ((count + 1) > ARRAY_SIZE(ctx.events)) { - NET_WARN("You have %d services to monitor but " - "%d poll entries configured.", - count + 1, ARRAY_SIZE(ctx.events)); - NET_WARN("Consider increasing value of %s to %d", - "CONFIG_NET_SOCKETS_POLL_MAX", count + 1); - } - - NET_DBG("Monitoring %d socket entries", count); - - ctx.count = count + 1; - - /* Create an eventfd that can be used to trigger events during polling */ - fd = eventfd(0, 0); - if (fd < 0) { - fd = -errno; - NET_ERR("eventfd failed (%d)", fd); - goto out; - } - - init_done = true; - k_condvar_broadcast(&wait_start); - - ctx.events[0].fd = fd; - ctx.events[0].events = ZSOCK_POLLIN; - -restart: - i = 1; - - k_mutex_lock(&lock, K_FOREVER); - - /* Copy individual events to the big array */ - STRUCT_SECTION_FOREACH(net_socket_service_desc, svc) { - for (int j = 0; j < svc->pev_len; j++) { - ctx.events[get_idx(svc) + j] = svc->pev[j].event; - } - } - - k_mutex_unlock(&lock); - - while (true) { - ret = zsock_poll(ctx.events, count + 1, -1); - if (ret < 0) { - ret = -errno; - NET_ERR("poll failed (%d)", ret); - goto out; - } - - if (ret == 0) { - /* should not happen because timeout is -1 */ - break; - } - - if (ret > 0 && ctx.events[0].revents) { - eventfd_read(ctx.events[0].fd, &value); - NET_DBG("Received restart event."); - goto restart; - } - - for (i = 1; i < (count + 1); i++) { - if (ctx.events[i].fd < 0) { - continue; - } - - if (ctx.events[i].revents > 0) { - ret = trigger_work(&ctx.events[i]); - if (ret < 0) { - NET_DBG("Triggering work failed (%d)", ret); - } - } - } - } - -out: - NET_DBG("Socket service thread stopped"); - init_done = false; - - return; - -fail: - k_condvar_broadcast(&wait_start); -} - -K_THREAD_DEFINE(socket_service_monitor, CONFIG_NET_SOCKETS_SERVICE_STACK_SIZE, - socket_service_thread, NULL, NULL, NULL, - K_LOWEST_APPLICATION_THREAD_PRIO, 0, 0); - -static int init_socket_service(void) -{ - k_thread_name_set(socket_service_monitor, "net_socket_service"); - - return 0; -} - -SYS_INIT(init_socket_service, APPLICATION, CONFIG_NET_SOCKETS_SERVICE_INIT_PRIO); From cfa532ea6d9f87a51d132a0c7433ba70ffb6fe63 Mon Sep 17 00:00:00 2001 From: Robert Lubos Date: Tue, 6 Feb 2024 11:07:02 +0100 Subject: [PATCH 3519/3723] Revert "[nrf fromtree] net: Move trickle files to lib" This reverts commit 2e5e0b159563eba914f44bdbcdbb06eef31f8f98. Signed-off-by: Robert Lubos --- subsys/net/ip/CMakeLists.txt | 1 + subsys/net/ip/Kconfig | 14 ++++++++++++++ subsys/net/{lib/trickle => ip}/trickle.c | 0 subsys/net/lib/CMakeLists.txt | 1 - subsys/net/lib/Kconfig | 2 -- subsys/net/lib/trickle/CMakeLists.txt | 7 ------- subsys/net/lib/trickle/Kconfig | 18 ------------------ 7 files changed, 15 insertions(+), 28 deletions(-) rename subsys/net/{lib/trickle => ip}/trickle.c (100%) delete mode 100644 subsys/net/lib/trickle/CMakeLists.txt delete mode 100644 subsys/net/lib/trickle/Kconfig diff --git a/subsys/net/ip/CMakeLists.txt b/subsys/net/ip/CMakeLists.txt index 3a93e5020d4..b9493b894a7 100644 --- a/subsys/net/ip/CMakeLists.txt +++ b/subsys/net/ip/CMakeLists.txt @@ -45,6 +45,7 @@ zephyr_library_sources_ifdef(CONFIG_NET_ROUTE route.c) zephyr_library_sources_ifdef(CONFIG_NET_STATISTICS net_stats.c) zephyr_library_sources_ifdef(CONFIG_NET_TCP tcp.c) zephyr_library_sources_ifdef(CONFIG_NET_TEST_PROTOCOL tp.c) +zephyr_library_sources_ifdef(CONFIG_NET_TRICKLE trickle.c) zephyr_library_sources_ifdef(CONFIG_NET_UDP udp.c) zephyr_library_sources_ifdef(CONFIG_NET_PROMISCUOUS_MODE promiscuous.c) diff --git a/subsys/net/ip/Kconfig b/subsys/net/ip/Kconfig index a5a6b7ba01e..fffa028b628 100644 --- a/subsys/net/ip/Kconfig +++ b/subsys/net/ip/Kconfig @@ -758,6 +758,20 @@ config NET_SLIP_TAP communicate via the SLIP driver. See net-tools project at https://github.com/zephyrproject-rtos/net-tools for more details. +config NET_TRICKLE + bool "Trickle library" + help + Normally this is enabled automatically if needed, + so say 'n' if unsure. + +if NET_TRICKLE +module = NET_TRICKLE +module-dep = NET_LOG +module-str = Log level for Trickle algorithm +module-help = Enables Trickle library output debug messages +source "subsys/net/Kconfig.template.log_config.net" +endif # NET_TRICKLE + endif # NET_RAW_MODE config NET_PKT_RX_COUNT diff --git a/subsys/net/lib/trickle/trickle.c b/subsys/net/ip/trickle.c similarity index 100% rename from subsys/net/lib/trickle/trickle.c rename to subsys/net/ip/trickle.c diff --git a/subsys/net/lib/CMakeLists.txt b/subsys/net/lib/CMakeLists.txt index 5e4eae7e028..756adb41341 100644 --- a/subsys/net/lib/CMakeLists.txt +++ b/subsys/net/lib/CMakeLists.txt @@ -14,7 +14,6 @@ add_subdirectory_ifdef(CONFIG_TLS_CREDENTIALS tls_credentials) add_subdirectory_ifdef(CONFIG_NET_CAPTURE capture) add_subdirectory_ifdef(CONFIG_NET_ZPERF zperf) add_subdirectory_ifdef(CONFIG_NET_SHELL shell) -add_subdirectory_ifdef(CONFIG_NET_TRICKLE trickle) if (CONFIG_DNS_RESOLVER OR CONFIG_MDNS_RESPONDER diff --git a/subsys/net/lib/Kconfig b/subsys/net/lib/Kconfig index b70105d5f9b..5df4a445885 100644 --- a/subsys/net/lib/Kconfig +++ b/subsys/net/lib/Kconfig @@ -39,8 +39,6 @@ menu "Network additional services" source "subsys/net/lib/capture/Kconfig" -source "subsys/net/lib/trickle/Kconfig" - source "subsys/net/lib/zperf/Kconfig" endmenu diff --git a/subsys/net/lib/trickle/CMakeLists.txt b/subsys/net/lib/trickle/CMakeLists.txt deleted file mode 100644 index b9cf222aab5..00000000000 --- a/subsys/net/lib/trickle/CMakeLists.txt +++ /dev/null @@ -1,7 +0,0 @@ -# SPDX-License-Identifier: Apache-2.0 - -zephyr_library() - -zephyr_library_sources( - trickle.c - ) diff --git a/subsys/net/lib/trickle/Kconfig b/subsys/net/lib/trickle/Kconfig deleted file mode 100644 index edc4f8fcf56..00000000000 --- a/subsys/net/lib/trickle/Kconfig +++ /dev/null @@ -1,18 +0,0 @@ -# Trickle Library for Zephyr - -# Copyright (c) 2016 Intel Corporation. -# SPDX-License-Identifier: Apache-2.0 - -config NET_TRICKLE - bool "Trickle library" - help - Normally this is enabled automatically if needed, - so say 'n' if unsure. - -if NET_TRICKLE -module = NET_TRICKLE -module-dep = NET_LOG -module-str = Log level for Trickle algorithm -module-help = Enables Trickle library output debug messages -source "subsys/net/Kconfig.template.log_config.net" -endif # NET_TRICKLE From abefe313b638b4fabd80f8bc4111544ba1927dec Mon Sep 17 00:00:00 2001 From: Robert Lubos Date: Tue, 6 Feb 2024 11:07:02 +0100 Subject: [PATCH 3520/3723] Revert "[nrf fromtree] Bluetooth: ISO: Fix CIS peripheral disconnection during setup" This reverts commit d142e4b062d5e5c9f107d2702ee7db7f065292e0. Signed-off-by: Robert Lubos --- subsys/bluetooth/host/iso.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/subsys/bluetooth/host/iso.c b/subsys/bluetooth/host/iso.c index 4d6366ead67..42e9c877a9a 100644 --- a/subsys/bluetooth/host/iso.c +++ b/subsys/bluetooth/host/iso.c @@ -1117,8 +1117,7 @@ void hci_le_cis_established(struct net_buf *buf) bt_conn_set_state(iso, BT_CONN_CONNECTED); bt_conn_unref(iso); return; - } else if (iso->role == BT_HCI_ROLE_PERIPHERAL || - evt->status != BT_HCI_ERR_OP_CANCELLED_BY_HOST) { + } else if (evt->status != BT_HCI_ERR_OP_CANCELLED_BY_HOST) { iso->err = evt->status; bt_iso_disconnected(iso); } /* else we wait for disconnect event */ From 1eed469a37c34c6facb84607a5e19ce41735fba1 Mon Sep 17 00:00:00 2001 From: Robert Lubos Date: Tue, 6 Feb 2024 11:07:03 +0100 Subject: [PATCH 3521/3723] Revert "[nrf fromtree] boards nrf5340bsim_cpuapp: Select approprite 802154 radio in DT" This reverts commit a8136cb27e83a594085a0f95d533c20ccd23354c. Signed-off-by: Robert Lubos --- boards/posix/nrf_bsim/nrf5340bsim_nrf5340_cpuapp.dts | 1 - 1 file changed, 1 deletion(-) diff --git a/boards/posix/nrf_bsim/nrf5340bsim_nrf5340_cpuapp.dts b/boards/posix/nrf_bsim/nrf5340bsim_nrf5340_cpuapp.dts index c5ec3c95af5..a7c3d39ace5 100644 --- a/boards/posix/nrf_bsim/nrf5340bsim_nrf5340_cpuapp.dts +++ b/boards/posix/nrf_bsim/nrf5340bsim_nrf5340_cpuapp.dts @@ -49,7 +49,6 @@ zephyr,flash = &flash0; zephyr,bt-hci-ipc = &ipc0; nordic,802154-spinel-ipc = &ipc0; - zephyr,ieee802154 = &ieee802154; }; soc { From 3d9cb3bc3162c7a688c47abf26780d77e2f912cd Mon Sep 17 00:00:00 2001 From: Robert Lubos Date: Tue, 6 Feb 2024 11:07:03 +0100 Subject: [PATCH 3522/3723] Revert "[nrf fromtree] manifest: Update nrf hw models to latest" This reverts commit 09da644ab209a2a329b5ebd59c012822d0796e39. Signed-off-by: Robert Lubos --- west.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/west.yml b/west.yml index b9a84545850..a141e94edd6 100644 --- a/west.yml +++ b/west.yml @@ -295,7 +295,7 @@ manifest: groups: - tools - name: nrf_hw_models - revision: 9b985ea6bc237b6ae06f48eb228f2ac7f6e3b96b + revision: a715dcc179f1a71f51c574165958b72fe932ae3f path: modules/bsim_hw_models/nrf_hw_models - name: open-amp revision: 214f9fc1539f8e5937c0474cb6ee29b6dcb2d4b8 From 3fb0f9c46736b61feaa554ee61b374369ff7d302 Mon Sep 17 00:00:00 2001 From: Robert Lubos Date: Tue, 6 Feb 2024 11:07:03 +0100 Subject: [PATCH 3523/3723] Revert "[nrf fromtree] boards nrf5340bsim_cpuapp: Define chosen entropy source" This reverts commit ba7cedd0bc880c07fef2c689a19561fd5b96631e. Signed-off-by: Robert Lubos --- boards/posix/nrf_bsim/nrf5340bsim_nrf5340_cpuapp.dts | 1 - 1 file changed, 1 deletion(-) diff --git a/boards/posix/nrf_bsim/nrf5340bsim_nrf5340_cpuapp.dts b/boards/posix/nrf_bsim/nrf5340bsim_nrf5340_cpuapp.dts index a7c3d39ace5..36cbf9691b3 100644 --- a/boards/posix/nrf_bsim/nrf5340bsim_nrf5340_cpuapp.dts +++ b/boards/posix/nrf_bsim/nrf5340bsim_nrf5340_cpuapp.dts @@ -45,7 +45,6 @@ }; chosen { - zephyr,entropy = &rng_hci; zephyr,flash = &flash0; zephyr,bt-hci-ipc = &ipc0; nordic,802154-spinel-ipc = &ipc0; From b2d949843e3d30a78422ad1ca05879ce5959bc6c Mon Sep 17 00:00:00 2001 From: Robert Lubos Date: Tue, 6 Feb 2024 11:07:03 +0100 Subject: [PATCH 3524/3723] Revert "[nrf fromtree] net: wifi_shell: Add help for maximum channels in scan" This reverts commit 9c754a80d072e415d54fc6dd45235359b016433b. Signed-off-by: Robert Lubos --- subsys/net/l2/wifi/wifi_shell.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/subsys/net/l2/wifi/wifi_shell.c b/subsys/net/l2/wifi/wifi_shell.c index 1f13ae864ae..1e1ab4a3724 100644 --- a/subsys/net/l2/wifi/wifi_shell.c +++ b/subsys/net/l2/wifi/wifi_shell.c @@ -1905,7 +1905,7 @@ SHELL_STATIC_SUBCMD_SET_CREATE(wifi_commands, "[-p, --dwell_time_passive ] : Passive scan dwell time (in ms) on a channel. Range 10 ms to 1000 ms\n" "[-s, --ssid] : SSID to scan for. Can be provided multiple times\n" "[-m, --max_bss ] : Maximum BSSes to scan for. Range 1 - 65535\n" - "[-c, --chans ] : Channels to be scanned. The channels must be specified in the form band1:chan1,chan2_band2:chan3,..etc. band1, band2 must be valid band values and chan1, chan2, chan3 must be specified as a list of comma separated values where each value is either a single channel or a channel range specified as chan_start-chan_end. Each band channel set has to be separated by a _. For example, a valid channel specification can be 2:1,6_5:36 or 2:1,6-11,14_5:36,163-177,52. Care should be taken to ensure that configured channels don't exceed CONFIG_WIFI_MGMT_SCAN_CHAN_MAX_MANUAL\n" + "[-c, --chans ] : Channels to be scanned. The channels must be specified in the form band1:chan1,chan2_band2:chan3,..etc. band1, band2 must be valid band values and chan1, chan2, chan3 must be specified as a list of comma separated values where each value is either a single channel or a channel range specified as chan_start-chan_end. Each band channel set has to be separated by a _. For example, a valid channel specification can be 2:1,6_5:36 or 2:1,6-11,14_5:36,163-177,52\n" "[-h, --help] : Print out the help for the scan command.\n", cmd_wifi_scan, 1, 8), From 383e81a5ffc4268f9b8c1074fbdea08666b38a2d Mon Sep 17 00:00:00 2001 From: Robert Lubos Date: Tue, 6 Feb 2024 11:07:03 +0100 Subject: [PATCH 3525/3723] Revert "[nrf fromtree] net: wifi_shell: Add example of scan option" This reverts commit 11305e472b97ad23381700865c424926498301e5. Signed-off-by: Robert Lubos --- subsys/net/l2/wifi/wifi_shell.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/subsys/net/l2/wifi/wifi_shell.c b/subsys/net/l2/wifi/wifi_shell.c index 1e1ab4a3724..d3f573a28d6 100644 --- a/subsys/net/l2/wifi/wifi_shell.c +++ b/subsys/net/l2/wifi/wifi_shell.c @@ -1905,7 +1905,7 @@ SHELL_STATIC_SUBCMD_SET_CREATE(wifi_commands, "[-p, --dwell_time_passive ] : Passive scan dwell time (in ms) on a channel. Range 10 ms to 1000 ms\n" "[-s, --ssid] : SSID to scan for. Can be provided multiple times\n" "[-m, --max_bss ] : Maximum BSSes to scan for. Range 1 - 65535\n" - "[-c, --chans ] : Channels to be scanned. The channels must be specified in the form band1:chan1,chan2_band2:chan3,..etc. band1, band2 must be valid band values and chan1, chan2, chan3 must be specified as a list of comma separated values where each value is either a single channel or a channel range specified as chan_start-chan_end. Each band channel set has to be separated by a _. For example, a valid channel specification can be 2:1,6_5:36 or 2:1,6-11,14_5:36,163-177,52\n" + "[-c, --chans ] : Channels to be scanned. The channels must be specified in the form band1:chan1,chan2_band2:chan3,..etc. band1, band2 must be valid band values and chan1, chan2, chan3 must be specified as a list of comma separated values where each value is either a single channel or a channel range specified as chan_start-chan_end. Each band channel set has to be separated by a _. For example, a valid channel specification can be 2:1,6_5:36\n" "[-h, --help] : Print out the help for the scan command.\n", cmd_wifi_scan, 1, 8), From aac1e9a879438b5e75e725d95d080fdca77bf1d3 Mon Sep 17 00:00:00 2001 From: Robert Lubos Date: Tue, 6 Feb 2024 11:07:04 +0100 Subject: [PATCH 3526/3723] Revert "[nrf fromtree] net: wifi_shell: Update scan argument shell" This reverts commit 8505a727386cf57765845ca3110ef21bcdc6d91d. Signed-off-by: Robert Lubos --- subsys/net/l2/wifi/wifi_shell.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/subsys/net/l2/wifi/wifi_shell.c b/subsys/net/l2/wifi/wifi_shell.c index d3f573a28d6..f470e700f8c 100644 --- a/subsys/net/l2/wifi/wifi_shell.c +++ b/subsys/net/l2/wifi/wifi_shell.c @@ -1903,9 +1903,9 @@ SHELL_STATIC_SUBCMD_SET_CREATE(wifi_commands, "[-b, --bands ] : Bands to be scanned where 2: 2.4 GHz, 5: 5 GHz, 6: 6 GHz\n" "[-a, --dwell_time_active ] : Active scan dwell time (in ms) on a channel. Range 5 ms to 1000 ms\n" "[-p, --dwell_time_passive ] : Passive scan dwell time (in ms) on a channel. Range 10 ms to 1000 ms\n" - "[-s, --ssid] : SSID to scan for. Can be provided multiple times\n" + "[-s, --ssid : SSID to scan for. Can be provided multiple times\n" "[-m, --max_bss ] : Maximum BSSes to scan for. Range 1 - 65535\n" - "[-c, --chans ] : Channels to be scanned. The channels must be specified in the form band1:chan1,chan2_band2:chan3,..etc. band1, band2 must be valid band values and chan1, chan2, chan3 must be specified as a list of comma separated values where each value is either a single channel or a channel range specified as chan_start-chan_end. Each band channel set has to be separated by a _. For example, a valid channel specification can be 2:1,6_5:36\n" + "[-c, --chans ] : Channels to be scanned. The channels must be specified in the form band1:chan1,chan2_band2:chan3,..etc. band1, band2 must be valid band values and chan1, chan2, chan3 must be specified as a list of comma separated values where each value is either a single channel or a channel range specified as chan_start-chan_end. Each band channel set has to be separated by a _. For example, a valid channel specification can be 2:1,6-11,14_5:36,149-165,44\n" "[-h, --help] : Print out the help for the scan command.\n", cmd_wifi_scan, 1, 8), From ee10501a8b3f32fd9dd28efb46c7c2c82675187d Mon Sep 17 00:00:00 2001 From: Robert Lubos Date: Tue, 6 Feb 2024 11:07:04 +0100 Subject: [PATCH 3527/3723] Revert "[nrf fromtree] net: wifi_utils: Fix max channels allow for scan" This reverts commit 0b0b17ec9b28d37fa303ae49564a68420b902414. Signed-off-by: Robert Lubos --- subsys/net/l2/wifi/wifi_utils.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/subsys/net/l2/wifi/wifi_utils.c b/subsys/net/l2/wifi/wifi_utils.c index bd47205e4f9..76e93fc33e0 100644 --- a/subsys/net/l2/wifi/wifi_utils.c +++ b/subsys/net/l2/wifi/wifi_utils.c @@ -368,7 +368,7 @@ int wifi_utils_parse_scan_chan(char *scan_chan_str, memset(chan_str, 0, sizeof(chan_str)); if (chan_start) { - if ((chan_idx + (chan_val - chan_start)) > max_channels) { + if ((chan_idx + (chan_val - chan_start)) >= max_channels) { NET_ERR("Too many channels specified (%d)", max_channels); return -EINVAL; } From 19937e8f3cbdd9ba67950a1a715148e55cece709 Mon Sep 17 00:00:00 2001 From: Robert Lubos Date: Tue, 6 Feb 2024 11:07:04 +0100 Subject: [PATCH 3528/3723] Revert "[nrf fromtree] boards: arm: add nrf9151dk_nrf9151" This reverts commit 79858b97c0996a8c67fdc70ffcc745b19111f9de. Signed-off-by: Robert Lubos --- boards/arm/nrf9151dk_nrf9151/Kconfig.board | 14 - .../arm/nrf9151dk_nrf9151/Kconfig.defconfig | 47 --- boards/arm/nrf9151dk_nrf9151/board.cmake | 14 - boards/arm/nrf9151dk_nrf9151/doc/index.rst | 203 ------------- .../nordic,nrf9151dk-nrf5340-reset.yaml | 18 -- .../dts/nrf9151dk_buttons_on_io_expander.dtsi | 25 -- .../dts/nrf9151dk_leds_on_io_expander.dtsi | 25 -- .../nrf9151dk_nrf9151/nrf9151dk_nrf9151.dts | 19 -- .../nrf9151dk_nrf9151/nrf9151dk_nrf9151.yaml | 22 -- .../nrf9151dk_nrf9151_common-pinctrl.dtsi | 96 ------- .../nrf9151dk_nrf9151_common.dtsi | 268 ------------------ .../nrf9151dk_nrf9151_defconfig | 24 -- .../nrf9151dk_nrf9151_ns.dts | 22 -- .../nrf9151dk_nrf9151_ns.yaml | 20 -- .../nrf9151dk_nrf9151_ns_defconfig | 27 -- .../nrf9151dk_nrf9151_partition_conf.dtsi | 60 ---- .../arm/nrf9151dk_nrf9151/pre_dt_board.cmake | 7 - 17 files changed, 911 deletions(-) delete mode 100644 boards/arm/nrf9151dk_nrf9151/Kconfig.board delete mode 100644 boards/arm/nrf9151dk_nrf9151/Kconfig.defconfig delete mode 100644 boards/arm/nrf9151dk_nrf9151/board.cmake delete mode 100644 boards/arm/nrf9151dk_nrf9151/doc/index.rst delete mode 100644 boards/arm/nrf9151dk_nrf9151/dts/bindings/nordic,nrf9151dk-nrf5340-reset.yaml delete mode 100644 boards/arm/nrf9151dk_nrf9151/dts/nrf9151dk_buttons_on_io_expander.dtsi delete mode 100644 boards/arm/nrf9151dk_nrf9151/dts/nrf9151dk_leds_on_io_expander.dtsi delete mode 100644 boards/arm/nrf9151dk_nrf9151/nrf9151dk_nrf9151.dts delete mode 100644 boards/arm/nrf9151dk_nrf9151/nrf9151dk_nrf9151.yaml delete mode 100644 boards/arm/nrf9151dk_nrf9151/nrf9151dk_nrf9151_common-pinctrl.dtsi delete mode 100644 boards/arm/nrf9151dk_nrf9151/nrf9151dk_nrf9151_common.dtsi delete mode 100644 boards/arm/nrf9151dk_nrf9151/nrf9151dk_nrf9151_defconfig delete mode 100644 boards/arm/nrf9151dk_nrf9151/nrf9151dk_nrf9151_ns.dts delete mode 100644 boards/arm/nrf9151dk_nrf9151/nrf9151dk_nrf9151_ns.yaml delete mode 100644 boards/arm/nrf9151dk_nrf9151/nrf9151dk_nrf9151_ns_defconfig delete mode 100644 boards/arm/nrf9151dk_nrf9151/nrf9151dk_nrf9151_partition_conf.dtsi delete mode 100644 boards/arm/nrf9151dk_nrf9151/pre_dt_board.cmake diff --git a/boards/arm/nrf9151dk_nrf9151/Kconfig.board b/boards/arm/nrf9151dk_nrf9151/Kconfig.board deleted file mode 100644 index 92352ddc16f..00000000000 --- a/boards/arm/nrf9151dk_nrf9151/Kconfig.board +++ /dev/null @@ -1,14 +0,0 @@ -# nRF9151 DK NRF9151 board configuration - -# Copyright (c) 2023 Nordic Semiconductor ASA -# SPDX-License-Identifier: Apache-2.0 - -if SOC_NRF9151_LACA - -config BOARD_NRF9151DK_NRF9151 - bool "nRF9151 DK NRF9151" - -config BOARD_NRF9151DK_NRF9151_NS - bool "nRF9151 DK NRF9151 non-secure" - -endif # SOC_NRF9151_LACA diff --git a/boards/arm/nrf9151dk_nrf9151/Kconfig.defconfig b/boards/arm/nrf9151dk_nrf9151/Kconfig.defconfig deleted file mode 100644 index 3cbff101d63..00000000000 --- a/boards/arm/nrf9151dk_nrf9151/Kconfig.defconfig +++ /dev/null @@ -1,47 +0,0 @@ -# nRF9151 DK NRF9151 board configuration - -# Copyright (c) 2023 Nordic Semiconductor ASA -# SPDX-License-Identifier: Apache-2.0 - -if BOARD_NRF9151DK_NRF9151 || BOARD_NRF9151DK_NRF9151_NS - -config BOARD - default "nrf9151dk_nrf9151" - -# 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)) - depends on BOARD_NRF9151DK_NRF9151 && TRUSTED_EXECUTION_SECURE - -if BOARD_NRF9151DK_NRF9151_NS - -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)) - -endif # BOARD_NRF9151DK_NRF9151_NS - -config BT_HCI_VS - default y if BT - -config BT_WAIT_NOP - default BT && $(dt_nodelabel_enabled,nrf5340_reset) - -config I2C - default $(dt_compat_on_bus,$(DT_COMPAT_NXP_PCAL6408A),i2c) - -endif # BOARD_NRF9151DK_NRF9151 || BOARD_NRF9151DK_NRF9151_NS diff --git a/boards/arm/nrf9151dk_nrf9151/board.cmake b/boards/arm/nrf9151dk_nrf9151/board.cmake deleted file mode 100644 index a3126c941d9..00000000000 --- a/boards/arm/nrf9151dk_nrf9151/board.cmake +++ /dev/null @@ -1,14 +0,0 @@ -# SPDX-License-Identifier: Apache-2.0 - -if(CONFIG_BOARD_NRF9151DK_NRF9151_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() - -# TODO: change to nRF9151_xxAA when such device is available in JLink -board_runner_args(jlink "--device=nRF9160_xxAA" "--speed=4000") -include(${ZEPHYR_BASE}/boards/common/nrfjprog.board.cmake) -include(${ZEPHYR_BASE}/boards/common/jlink.board.cmake) diff --git a/boards/arm/nrf9151dk_nrf9151/doc/index.rst b/boards/arm/nrf9151dk_nrf9151/doc/index.rst deleted file mode 100644 index 4c02e7ed372..00000000000 --- a/boards/arm/nrf9151dk_nrf9151/doc/index.rst +++ /dev/null @@ -1,203 +0,0 @@ -.. _nrf9151dk_nrf9151: - -nRF9151 DK -########## - -Overview -******** - -The nRF9151 DK (PCA10171) is a single-board development kit for evaluation and -development on the nRF9151 SiP for DECT NR+ and LTE-M/NB-IoT with GNSS. The nrf9151dk_nrf9151 -board configuration provides support for the Nordic Semiconductor nRF9151 ARM -Cortex-M33F CPU with ARMv8-M Security Extension and the following devices: - -* :abbr:`ADC (Analog to Digital Converter)` -* CLOCK -* FLASH -* :abbr:`GPIO (General Purpose Input Output)` -* :abbr:`I2C (Inter-Integrated Circuit)` -* :abbr:`MPU (Memory Protection Unit)` -* :abbr:`NVIC (Nested Vectored Interrupt Controller)` -* :abbr:`PWM (Pulse Width Modulation)` -* :abbr:`RTC (nRF RTC System Clock)` -* Segger RTT (RTT Console) -* :abbr:`SPI (Serial Peripheral Interface)` -* :abbr:`UARTE (Universal asynchronous receiver-transmitter with EasyDMA)` -* :abbr:`WDT (Watchdog Timer)` -* :abbr:`IDAU (Implementation Defined Attribution Unit)` - -More information about the board can be found at the -`nRF9151 DK website`_. The `Nordic Semiconductor Infocenter`_ -contains the processor's information and the datasheet. - - -Hardware -******** - -nRF9151 DK has two external oscillators. The frequency of -the slow clock is 32.768 kHz. The frequency of the main clock -is 32 MHz. - -Supported Features -================== - -The nrf9151dk_nrf9151 board configuration supports the following -hardware features: - -+-----------+------------+----------------------+ -| Interface | Controller | Driver/Component | -+===========+============+======================+ -| ADC | on-chip | adc | -+-----------+------------+----------------------+ -| CLOCK | on-chip | clock_control | -+-----------+------------+----------------------+ -| FLASH | on-chip | flash | -+-----------+------------+----------------------+ -| FLASH | external | spi | -+-----------+------------+----------------------+ -| GPIO | on-chip | gpio | -+-----------+------------+----------------------+ -| GPIO | external | i2c | -+-----------+------------+----------------------+ -| I2C(M) | on-chip | i2c | -+-----------+------------+----------------------+ -| MPU | on-chip | arch/arm | -+-----------+------------+----------------------+ -| NVIC | on-chip | arch/arm | -+-----------+------------+----------------------+ -| PWM | on-chip | pwm | -+-----------+------------+----------------------+ -| RTC | on-chip | system clock | -+-----------+------------+----------------------+ -| RTT | nRF53 | console | -+-----------+------------+----------------------+ -| SPI(M/S) | on-chip | spi | -+-----------+------------+----------------------+ -| SPU | on-chip | system protection | -+-----------+------------+----------------------+ -| UARTE | on-chip | serial | -+-----------+------------+----------------------+ -| WDT | on-chip | watchdog | -+-----------+------------+----------------------+ - - -.. _nrf9151dk_additional_hardware: - -Other hardware features have not been enabled yet for this board. -See `nRF9151 DK website`_ and `Nordic Semiconductor Infocenter`_ -for a complete list of nRF9151 DK board hardware features. - -Connections and IOs -=================== - -LED ---- - -* LED1 (green) = P0.0 -* LED2 (green) = P0.1 -* LED3 (green) = P0.4 -* LED4 (green) = P0.5 - -Push buttons and Switches -------------------------- - -* BUTTON1 = P0.8 -* BUTTON2 = P0.9 -* SWITCH1 = P0.18 -* SWITCH2 = P0.19 -* BOOT = SW5 = boot/reset - -Security components -=================== - -- Implementation Defined Attribution Unit (`IDAU`_). The IDAU is implemented - with the System Protection Unit and is used to define secure and non-secure - memory maps. By default, all of the memory space (Flash, SRAM, and - peripheral address space) is defined to be secure accessible only. -- Secure boot. - - -Programming and Debugging -************************* - -nrf9151dk_nrf9151 supports the Armv8m Security Extension, and by default boots -in the Secure state. - -Building Secure/Non-Secure Zephyr applications with Arm |reg| TrustZone |reg| -============================================================================= - -The process requires the following steps: - -1. Build the Secure Zephyr application using ``-DBOARD=nrf9151dk_nrf9151`` and - ``CONFIG_TRUSTED_EXECUTION_SECURE=y`` in the application project configuration file. -2. Build the Non-Secure Zephyr application using ``-DBOARD=nrf9151dk_nrf9151_ns``. -3. Merge the two binaries together. - -When building a Secure/Non-Secure application, the Secure application will -have to set the IDAU (SPU) configuration to allow Non-Secure access to all -CPU resources utilized by the Non-Secure application firmware. SPU -configuration shall take place before jumping to the Non-Secure application. - -Building a Secure only application -================================== - -Build the Zephyr app in the usual way (see :ref:`build_an_application` -and :ref:`application_run`), using ``-DBOARD=nrf9151dk_nrf9151``. - -Flashing -======== - -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`. Then build and flash -applications as usual (see :ref:`build_an_application` and -:ref:`application_run` for more details). - -Here is an example for the :ref:`hello_world` application. - -First, run your favorite terminal program to listen for output. - -.. code-block:: console - - $ minicom -D -b 115200 - -Replace :code:`` with the port where the nRF9151 DK -can be found. For example, under Linux, :code:`/dev/ttyACM0`. - -Then build and flash the application in the usual way. - -.. zephyr-app-commands:: - :zephyr-app: samples/hello_world - :board: nrf9151dk_nrf9151 - :goals: build flash - -Debugging -========= - -Refer to the :ref:`nordic_segger` page to learn about debugging Nordic boards with a -Segger IC. - - -Testing the LEDs and buttons in the nRF9151 DK -********************************************** - -There are 2 samples that allow you to test that the buttons (switches) and LEDs on -the board are working properly with Zephyr: - -* :zephyr:code-sample:`blinky` -* :zephyr:code-sample:`button` - -You can build and flash the examples to make sure Zephyr is running correctly on -your board. The button and LED definitions can be found in -:zephyr_file:`boards/arm/nrf9151dk_nrf9151/nrf9151dk_nrf9151_common.dtsi`. - -References -********** - -.. target-notes:: - -.. _IDAU: - https://developer.arm.com/docs/100690/latest/attribution-units-sau-and-idau -.. _nRF9151 DK website: https://www.nordicsemi.com/Software-and-Tools/Development-Kits/nRF9151-DK -.. _Nordic Semiconductor Infocenter: https://infocenter.nordicsemi.com -.. _Trusted Firmware M: https://www.trustedfirmware.org/projects/tf-m/ diff --git a/boards/arm/nrf9151dk_nrf9151/dts/bindings/nordic,nrf9151dk-nrf5340-reset.yaml b/boards/arm/nrf9151dk_nrf9151/dts/bindings/nordic,nrf9151dk-nrf5340-reset.yaml deleted file mode 100644 index 2b51125312c..00000000000 --- a/boards/arm/nrf9151dk_nrf9151/dts/bindings/nordic,nrf9151dk-nrf5340-reset.yaml +++ /dev/null @@ -1,18 +0,0 @@ -# Copyright (c) 2023 Nordic Semiconductor ASA -# SPDX-License-Identifier: Apache-2.0 - -description: GPIO used to reset nRF5340 on nRF9151 DK - -compatible: "nordic,nrf9151dk-nrf5340-reset" - -include: base.yaml - -properties: - status: - required: true - - gpios: - type: phandle-array - required: true - description: | - GPIO to use as nRF5340 reset line: output in nRF9151, input in nRF5340. diff --git a/boards/arm/nrf9151dk_nrf9151/dts/nrf9151dk_buttons_on_io_expander.dtsi b/boards/arm/nrf9151dk_nrf9151/dts/nrf9151dk_buttons_on_io_expander.dtsi deleted file mode 100644 index 20f7d2406a5..00000000000 --- a/boards/arm/nrf9151dk_nrf9151/dts/nrf9151dk_buttons_on_io_expander.dtsi +++ /dev/null @@ -1,25 +0,0 @@ -/* - * Copyright (c) 2023 Nordic Semiconductor ASA - * - * SPDX-License-Identifier: Apache-2.0 - */ - -&pcal6408a { - status = "okay"; -}; - -&button0 { - gpios = <&pcal6408a 0 (GPIO_PULL_UP | GPIO_ACTIVE_LOW)>; -}; - -&button1 { - gpios = <&pcal6408a 1 (GPIO_PULL_UP | GPIO_ACTIVE_LOW)>; -}; - -&button2 { - gpios = <&pcal6408a 2 (GPIO_PULL_UP | GPIO_ACTIVE_LOW)>; -}; - -&button3 { - gpios = <&pcal6408a 3 (GPIO_PULL_UP | GPIO_ACTIVE_LOW)>; -}; diff --git a/boards/arm/nrf9151dk_nrf9151/dts/nrf9151dk_leds_on_io_expander.dtsi b/boards/arm/nrf9151dk_nrf9151/dts/nrf9151dk_leds_on_io_expander.dtsi deleted file mode 100644 index d80c509d215..00000000000 --- a/boards/arm/nrf9151dk_nrf9151/dts/nrf9151dk_leds_on_io_expander.dtsi +++ /dev/null @@ -1,25 +0,0 @@ -/* - * Copyright (c) 2023 Nordic Semiconductor ASA - * - * SPDX-License-Identifier: Apache-2.0 - */ - -&pcal6408a { - status = "okay"; -}; - -&led0 { - gpios = <&pcal6408a 4 GPIO_ACTIVE_HIGH>; -}; - -&led1 { - gpios = <&pcal6408a 5 GPIO_ACTIVE_HIGH>; -}; - -&led2 { - gpios = <&pcal6408a 6 GPIO_ACTIVE_HIGH>; -}; - -&led3 { - gpios = <&pcal6408a 7 GPIO_ACTIVE_HIGH>; -}; diff --git a/boards/arm/nrf9151dk_nrf9151/nrf9151dk_nrf9151.dts b/boards/arm/nrf9151dk_nrf9151/nrf9151dk_nrf9151.dts deleted file mode 100644 index 8c3b4921434..00000000000 --- a/boards/arm/nrf9151dk_nrf9151/nrf9151dk_nrf9151.dts +++ /dev/null @@ -1,19 +0,0 @@ -/* - * Copyright (c) 2023 Nordic Semiconductor ASA - * - * SPDX-License-Identifier: Apache-2.0 - */ - -/dts-v1/; -#include -#include "nrf9151dk_nrf9151_common.dtsi" - -/ { - chosen { - zephyr,sram = &sram0_s; - zephyr,flash = &flash0; - zephyr,code-partition = &slot0_partition; - zephyr,sram-secure-partition = &sram0_s; - zephyr,sram-non-secure-partition = &sram0_ns; - }; -}; diff --git a/boards/arm/nrf9151dk_nrf9151/nrf9151dk_nrf9151.yaml b/boards/arm/nrf9151dk_nrf9151/nrf9151dk_nrf9151.yaml deleted file mode 100644 index 3ad90fea76d..00000000000 --- a/boards/arm/nrf9151dk_nrf9151/nrf9151dk_nrf9151.yaml +++ /dev/null @@ -1,22 +0,0 @@ -identifier: nrf9151dk_nrf9151 -name: nRF9151-DK-NRF9151 -type: mcu -arch: arm -toolchain: - - gnuarmemb - - xtools - - zephyr -ram: 88 -flash: 1024 -supported: - - arduino_gpio - - arduino_i2c - - arduino_serial - - arduino_spi - - gpio - - i2c - - pwm - - spi - - watchdog - - counter -vendor: nordic diff --git a/boards/arm/nrf9151dk_nrf9151/nrf9151dk_nrf9151_common-pinctrl.dtsi b/boards/arm/nrf9151dk_nrf9151/nrf9151dk_nrf9151_common-pinctrl.dtsi deleted file mode 100644 index a1680e830f4..00000000000 --- a/boards/arm/nrf9151dk_nrf9151/nrf9151dk_nrf9151_common-pinctrl.dtsi +++ /dev/null @@ -1,96 +0,0 @@ -/* - * Copyright (c) 2023 Nordic Semiconductor - * SPDX-License-Identifier: Apache-2.0 - */ - -&pinctrl { - uart0_default: uart0_default { - group1 { - psels = , - ; - }; - group2 { - psels = , - ; - bias-pull-up; - }; - }; - - uart0_sleep: uart0_sleep { - group1 { - psels = , - , - , - ; - low-power-enable; - }; - }; - - uart1_default: uart1_default { - group1 { - psels = , - ; - }; - group2 { - psels = , - ; - bias-pull-up; - }; - }; - - uart1_sleep: uart1_sleep { - group1 { - psels = , - , - , - ; - low-power-enable; - }; - }; - - i2c2_default: i2c2_default { - group1 { - psels = , - ; - }; - }; - - i2c2_sleep: i2c2_sleep { - group1 { - psels = , - ; - low-power-enable; - }; - }; - - pwm0_default: pwm0_default { - group1 { - psels = ; - }; - }; - - pwm0_sleep: pwm0_sleep { - group1 { - psels = ; - low-power-enable; - }; - }; - - spi3_default: spi3_default { - group1 { - psels = , - , - ; - nordic,drive-mode = ; - }; - }; - - spi3_sleep: spi3_sleep { - group1 { - psels = , - , - ; - low-power-enable; - }; - }; -}; diff --git a/boards/arm/nrf9151dk_nrf9151/nrf9151dk_nrf9151_common.dtsi b/boards/arm/nrf9151dk_nrf9151/nrf9151dk_nrf9151_common.dtsi deleted file mode 100644 index 958e864c63c..00000000000 --- a/boards/arm/nrf9151dk_nrf9151/nrf9151dk_nrf9151_common.dtsi +++ /dev/null @@ -1,268 +0,0 @@ -/* - * Copyright (c) 2023 Nordic Semiconductor ASA - * - * SPDX-License-Identifier: Apache-2.0 - */ -#include "nrf9151dk_nrf9151_common-pinctrl.dtsi" -#include - -/ { - model = "Nordic nRF9151 DK NRF9151"; - compatible = "nordic,nrf9151-dk-nrf9151"; - - chosen { - zephyr,console = &uart0; - zephyr,shell-uart = &uart0; - zephyr,uart-mcumgr = &uart0; - }; - - leds { - compatible = "gpio-leds"; - led0: led_0 { - gpios = <&gpio0 0 GPIO_ACTIVE_HIGH>; - label = "Green LED 1"; - }; - led1: led_1 { - gpios = <&gpio0 1 GPIO_ACTIVE_HIGH>; - label = "Green LED 2"; - }; - led2: led_2 { - gpios = <&gpio0 4 GPIO_ACTIVE_HIGH>; - label = "Green LED 3"; - }; - led3: led_3 { - gpios = <&gpio0 5 GPIO_ACTIVE_HIGH>; - label = "Green LED 4"; - }; - }; - - pwmleds { - compatible = "pwm-leds"; - pwm_led0: pwm_led_0 { - pwms = <&pwm0 0 PWM_MSEC(20) PWM_POLARITY_NORMAL>; - }; - }; - - buttons { - compatible = "gpio-keys"; - button0: button_0 { - gpios = <&gpio0 8 (GPIO_PULL_UP | GPIO_ACTIVE_LOW)>; - label = "Push button 1"; - zephyr,code = ; - }; - button1: button_1 { - gpios = <&gpio0 9 (GPIO_PULL_UP | GPIO_ACTIVE_LOW)>; - label = "Push button 2"; - zephyr,code = ; - }; - button2: button_2 { - gpios = <&gpio0 18 (GPIO_PULL_UP | GPIO_ACTIVE_LOW)>; - label = "Push button 3"; - zephyr,code = ; - }; - button3: button_3 { - gpios = <&gpio0 19 (GPIO_PULL_UP | GPIO_ACTIVE_LOW)>; - label = "Push button 4"; - zephyr,code = ; - }; - }; - - nrf5340_reset: gpio-reset { - compatible = "nordic,nrf9151dk-nrf5340-reset"; - status = "disabled"; - gpios = <&gpio0 21 GPIO_ACTIVE_LOW>; - }; - - arduino_header: connector { - compatible = "arduino-header-r3"; - #gpio-cells = <2>; - gpio-map-mask = <0xffffffff 0xffffffc0>; - gpio-map-pass-thru = <0 0x3f>; - gpio-map = <0 0 &gpio0 14 0>, /* A0 */ - <1 0 &gpio0 15 0>, /* A1 */ - <2 0 &gpio0 16 0>, /* A2 */ - <3 0 &gpio0 17 0>, /* A3 */ - <4 0 &gpio0 18 0>, /* A4 */ - <5 0 &gpio0 19 0>, /* A5 */ - <6 0 &gpio0 0 0>, /* D0 */ - <7 0 &gpio0 1 0>, /* D1 */ - <8 0 &gpio0 2 0>, /* D2 */ - <9 0 &gpio0 3 0>, /* D3 */ - <10 0 &gpio0 4 0>, /* D4 */ - <11 0 &gpio0 5 0>, /* D5 */ - <12 0 &gpio0 6 0>, /* D6 */ - <13 0 &gpio0 7 0>, /* D7 */ - <14 0 &gpio0 8 0>, /* D8 */ - <15 0 &gpio0 9 0>, /* D9 */ - <16 0 &gpio0 10 0>, /* D10 */ - <17 0 &gpio0 11 0>, /* D11 */ - <18 0 &gpio0 12 0>, /* D12 */ - <19 0 &gpio0 13 0>, /* D13 */ - <20 0 &gpio0 30 0>, /* D14 */ - <21 0 &gpio0 31 0>; /* D15 */ - }; - - arduino_adc: analog-connector { - compatible = "arduino,uno-adc"; - #io-channel-cells = <1>; - io-channel-map = <0 &adc 1>, /* A0 = P0.14 = AIN1 */ - <1 &adc 2>, /* A1 = P0.15 = AIN2 */ - <2 &adc 3>, /* A2 = P0.16 = AIN3 */ - <3 &adc 4>, /* A3 = P0.17 = AIN4 */ - <4 &adc 5>, /* A4 = P0.18 = AIN5 */ - <5 &adc 6>; /* A5 = P0.19 = AIN6 */ - }; - - /* These aliases are provided for compatibility with samples */ - aliases { - led0 = &led0; - led1 = &led1; - led2 = &led2; - led3 = &led3; - pwm-led0 = &pwm_led0; - sw0 = &button0; - sw1 = &button1; - sw2 = &button2; - sw3 = &button3; - bootloader-led0 = &led0; - mcuboot-button0 = &button0; - mcuboot-led0 = &led0; - watchdog0 = &wdt0; - spi-flash0 = &gd25wb256; - }; -}; - -&adc { - status = "okay"; -}; - -&gpiote { - status = "okay"; -}; - -&gpio0 { - status = "okay"; -}; - -&uart0 { - status = "okay"; - current-speed = <115200>; - pinctrl-0 = <&uart0_default>; - pinctrl-1 = <&uart0_sleep>; - pinctrl-names = "default", "sleep"; -}; - -arduino_serial: &uart1 { - status = "okay"; - current-speed = <115200>; - pinctrl-0 = <&uart1_default>; - pinctrl-1 = <&uart1_sleep>; - pinctrl-names = "default", "sleep"; -}; - -arduino_i2c: &i2c2 { - compatible = "nordic,nrf-twim"; - status = "okay"; - pinctrl-0 = <&i2c2_default>; - pinctrl-1 = <&i2c2_sleep>; - pinctrl-names = "default", "sleep"; - clock-frequency = ; - - pcal6408a: pcal6408a@21 { - compatible = "nxp,pcal6408a"; - status = "disabled"; - reg = <0x21>; - gpio-controller; - #gpio-cells = <2>; - ngpios = <8>; - int-gpios = <&gpio0 19 (GPIO_PULL_UP | GPIO_ACTIVE_LOW)>; - }; -}; - -&pwm0 { - status = "okay"; - pinctrl-0 = <&pwm0_default>; - pinctrl-1 = <&pwm0_sleep>; - pinctrl-names = "default", "sleep"; -}; - -arduino_spi: &spi3 { - compatible = "nordic,nrf-spim"; - status = "okay"; - cs-gpios = <&arduino_header 16 GPIO_ACTIVE_LOW>, /* D10 */ - <&gpio0 20 GPIO_ACTIVE_LOW>; - pinctrl-0 = <&spi3_default>; - pinctrl-1 = <&spi3_sleep>; - pinctrl-names = "default", "sleep"; - - gd25wb256: gd25wb256e3ir@1 { - compatible = "jedec,spi-nor"; - status = "disabled"; - reg = <1>; - spi-max-frequency = <8000000>; - size = <268435456>; - has-dpd; - t-enter-dpd = <3000>; - t-exit-dpd = <40000>; - sfdp-bfp = [ - e5 20 f3 ff ff ff ff 0f 44 eb 08 6b 08 3b 42 bb - ee ff ff ff ff ff 00 ff ff ff 00 ff 0c 20 0f 52 - 10 d8 00 ff 44 7a c9 fe 83 67 26 62 ec 82 18 44 - 7a 75 7a 75 04 c4 d5 5c 00 06 74 00 08 50 00 01 - ]; - jedec-id = [c8 65 19]; - }; -}; - -&flash0 { - partitions { - compatible = "fixed-partitions"; - #address-cells = <1>; - #size-cells = <1>; - - boot_partition: partition@0 { - label = "mcuboot"; - reg = <0x00000000 0x10000>; - }; - slot0_partition: partition@10000 { - label = "image-0"; - }; - slot0_ns_partition: partition@50000 { - label = "image-0-nonsecure"; - }; - slot1_partition: partition@85000 { - label = "image-1"; - }; - slot1_ns_partition: partition@c5000 { - label = "image-1-nonsecure"; - }; - storage_partition: partition@fa000 { - label = "storage"; - reg = <0x000fa000 0x00006000>; - }; - }; -}; - -/ { - - reserved-memory { - #address-cells = <1>; - #size-cells = <1>; - ranges; - - sram0_s: image_s@20000000 { - /* Secure image memory */ - }; - - sram0_modem: image_modem@20016000 { - /* Modem (shared) memory */ - }; - - sram0_ns: image_ns@20020000 { - /* Non-Secure image memory */ - }; - }; -}; - -/* Include partition configuration file */ -#include "nrf9151dk_nrf9151_partition_conf.dtsi" diff --git a/boards/arm/nrf9151dk_nrf9151/nrf9151dk_nrf9151_defconfig b/boards/arm/nrf9151dk_nrf9151/nrf9151dk_nrf9151_defconfig deleted file mode 100644 index 7afe5ac7aa9..00000000000 --- a/boards/arm/nrf9151dk_nrf9151/nrf9151dk_nrf9151_defconfig +++ /dev/null @@ -1,24 +0,0 @@ -# SPDX-License-Identifier: Apache-2.0 - -CONFIG_SOC_SERIES_NRF91X=y -CONFIG_SOC_NRF9151_LACA=y -CONFIG_BOARD_NRF9151DK_NRF9151=y - -# Enable MPU -CONFIG_ARM_MPU=y - -# Enable hardware stack protection -CONFIG_HW_STACK_PROTECTION=y - -# Enable TrustZone-M -CONFIG_ARM_TRUSTZONE_M=y - -# enable GPIO -CONFIG_GPIO=y - -# Enable uart driver -CONFIG_SERIAL=y - -# enable console -CONFIG_CONSOLE=y -CONFIG_UART_CONSOLE=y diff --git a/boards/arm/nrf9151dk_nrf9151/nrf9151dk_nrf9151_ns.dts b/boards/arm/nrf9151dk_nrf9151/nrf9151dk_nrf9151_ns.dts deleted file mode 100644 index a41c4aad388..00000000000 --- a/boards/arm/nrf9151dk_nrf9151/nrf9151dk_nrf9151_ns.dts +++ /dev/null @@ -1,22 +0,0 @@ -/* - * Copyright (c) 2023 Nordic Semiconductor ASA - * - * SPDX-License-Identifier: Apache-2.0 - */ - -/dts-v1/; -#include -#include "nrf9151dk_nrf9151_common.dtsi" - -/ { - chosen { - zephyr,flash = &flash0; - zephyr,sram = &sram0_ns; - zephyr,code-partition = &slot0_ns_partition; - }; -}; - -/* Disable UART1, because it is used by default in TF-M */ -&uart1 { - status = "disabled"; -}; diff --git a/boards/arm/nrf9151dk_nrf9151/nrf9151dk_nrf9151_ns.yaml b/boards/arm/nrf9151dk_nrf9151/nrf9151dk_nrf9151_ns.yaml deleted file mode 100644 index c5d4fe92541..00000000000 --- a/boards/arm/nrf9151dk_nrf9151/nrf9151dk_nrf9151_ns.yaml +++ /dev/null @@ -1,20 +0,0 @@ -identifier: nrf9151dk_nrf9151_ns -name: nRF9151-DK-NRF9151-Non-Secure -type: mcu -arch: arm -toolchain: - - gnuarmemb - - xtools - - zephyr -ram: 128 -flash: 192 -supported: - - arduino_gpio - - arduino_i2c - - arduino_serial - - arduino_spi - - i2c - - pwm - - watchdog - - netif:modem -vendor: nordic diff --git a/boards/arm/nrf9151dk_nrf9151/nrf9151dk_nrf9151_ns_defconfig b/boards/arm/nrf9151dk_nrf9151/nrf9151dk_nrf9151_ns_defconfig deleted file mode 100644 index 949ef39f856..00000000000 --- a/boards/arm/nrf9151dk_nrf9151/nrf9151dk_nrf9151_ns_defconfig +++ /dev/null @@ -1,27 +0,0 @@ -# SPDX-License-Identifier: Apache-2.0 - -CONFIG_SOC_SERIES_NRF91X=y -CONFIG_SOC_NRF9151_LACA=y -CONFIG_BOARD_NRF9151DK_NRF9151_NS=y - -# Enable MPU -CONFIG_ARM_MPU=y - -# Enable hardware stack protection -CONFIG_HW_STACK_PROTECTION=y - -# Enable TrustZone-M -CONFIG_ARM_TRUSTZONE_M=y - -# This Board implies building Non-Secure firmware -CONFIG_TRUSTED_EXECUTION_NONSECURE=y - -# enable GPIO -CONFIG_GPIO=y - -# Enable uart driver -CONFIG_SERIAL=y - -# enable console -CONFIG_CONSOLE=y -CONFIG_UART_CONSOLE=y diff --git a/boards/arm/nrf9151dk_nrf9151/nrf9151dk_nrf9151_partition_conf.dtsi b/boards/arm/nrf9151dk_nrf9151/nrf9151dk_nrf9151_partition_conf.dtsi deleted file mode 100644 index b209608a725..00000000000 --- a/boards/arm/nrf9151dk_nrf9151/nrf9151dk_nrf9151_partition_conf.dtsi +++ /dev/null @@ -1,60 +0,0 @@ -/* - * Copyright (c) 2023 Nordic Semiconductor ASA - * - * SPDX-License-Identifier: Apache-2.0 - */ - -/* - * Default Flash planning for nRF9151dk_nrf9151. - * - * Zephyr build for nRF9151 with ARM TrustZone-M support, - * implies building Secure and Non-Secure Zephyr images. - * - * Secure image will be placed, by default, in flash0 - * (or in slot0, if MCUboot is present). - * Secure image will use sram0 for system memory. - * - * Non-Secure image will be placed in slot0_ns, and use - * sram0_ns for system memory. - * - * Note that the Secure image only requires knowledge of - * the beginning of the Non-Secure image (not its size). - */ - -&slot0_partition { - reg = <0x00010000 0x40000>; -}; - -&slot0_ns_partition { - reg = <0x00050000 0x35000>; -}; - -&slot1_partition { - reg = <0x00085000 0x40000>; -}; - -&slot1_ns_partition { - reg = <0x000c5000 0x35000>; -}; - -/* Default SRAM planning when building for nRF9151 with - * ARM TrustZone-M support - * - Lowest 88 kB SRAM allocated to Secure image (sram0_s). - * - 40 kB SRAM reserved for and used by the modem library - * (sram0_modem). This memory is Non-Secure. - * - Upper 128 kB allocated to Non-Secure image (sram0_ns). - * When building with TF-M, both sram0_modem and sram0_ns - * are allocated to the Non-Secure image. - */ - -&sram0_s { - reg = <0x20000000 DT_SIZE_K(88)>; -}; - -&sram0_modem { - reg = <0x20016000 DT_SIZE_K(40)>; -}; - -&sram0_ns { - reg = <0x20020000 DT_SIZE_K(128)>; -}; diff --git a/boards/arm/nrf9151dk_nrf9151/pre_dt_board.cmake b/boards/arm/nrf9151dk_nrf9151/pre_dt_board.cmake deleted file mode 100644 index c8267afd1b4..00000000000 --- a/boards/arm/nrf9151dk_nrf9151/pre_dt_board.cmake +++ /dev/null @@ -1,7 +0,0 @@ -# Copyright (c) 2021 Linaro Limited -# SPDX-License-Identifier: Apache-2.0 - -# Suppress "unique_unit_address_if_enabled" to handle the following overlaps: -# - flash-controller@39000 & kmu@39000 -# - power@5000 & clock@5000 -list(APPEND EXTRA_DTC_FLAGS "-Wno-unique_unit_address_if_enabled") From e3b1416bd3e062a951ae3b95b080e19edbc413fa Mon Sep 17 00:00:00 2001 From: Robert Lubos Date: Tue, 6 Feb 2024 11:07:04 +0100 Subject: [PATCH 3529/3723] Revert "[nrf fromtree] soc: arm: nordic_nrf: nrf91: add nRF9151 LACA" This reverts commit bc1d19177ed3633941254563852a9c3d2cf82ff3. Signed-off-by: Robert Lubos --- dts/arm/nordic/nrf9151_laca.dtsi | 23 ------------------- dts/arm/nordic/nrf9151ns_laca.dtsi | 23 ------------------- .../nrf91/Kconfig.defconfig.nrf9151_LACA | 14 ----------- soc/arm/nordic_nrf/nrf91/Kconfig.soc | 4 ---- 4 files changed, 64 deletions(-) delete mode 100644 dts/arm/nordic/nrf9151_laca.dtsi delete mode 100644 dts/arm/nordic/nrf9151ns_laca.dtsi delete mode 100644 soc/arm/nordic_nrf/nrf91/Kconfig.defconfig.nrf9151_LACA diff --git a/dts/arm/nordic/nrf9151_laca.dtsi b/dts/arm/nordic/nrf9151_laca.dtsi deleted file mode 100644 index 9ed20274017..00000000000 --- a/dts/arm/nordic/nrf9151_laca.dtsi +++ /dev/null @@ -1,23 +0,0 @@ -/* - * Copyright (c) 2023 Nordic Semiconductor ASA - * - * SPDX-License-Identifier: Apache-2.0 - */ - -#include -#include - -&flash0 { - reg = <0x00000000 DT_SIZE_K(1024)>; -}; - -&sram0 { - reg = <0x20000000 DT_SIZE_K(256)>; -}; - -/ { - soc { - compatible = "nordic,nrf9151-laca", "nordic,nrf9120", - "nordic,nrf91", "simple-bus"; - }; -}; diff --git a/dts/arm/nordic/nrf9151ns_laca.dtsi b/dts/arm/nordic/nrf9151ns_laca.dtsi deleted file mode 100644 index ac31c6e19c6..00000000000 --- a/dts/arm/nordic/nrf9151ns_laca.dtsi +++ /dev/null @@ -1,23 +0,0 @@ -/* - * Copyright (c) 2023 Nordic Semiconductor ASA - * - * SPDX-License-Identifier: Apache-2.0 - */ - -#include -#include - -&flash0 { - reg = <0x00000000 DT_SIZE_K(1024)>; -}; - -&sram0 { - reg = <0x20000000 DT_SIZE_K(256)>; -}; - -/ { - soc { - compatible = "nordic,nrf9151-laca", "nordic,nrf9120", - "nordic,nrf91", "simple-bus"; - }; -}; diff --git a/soc/arm/nordic_nrf/nrf91/Kconfig.defconfig.nrf9151_LACA b/soc/arm/nordic_nrf/nrf91/Kconfig.defconfig.nrf9151_LACA deleted file mode 100644 index 1b3ea88e359..00000000000 --- a/soc/arm/nordic_nrf/nrf91/Kconfig.defconfig.nrf9151_LACA +++ /dev/null @@ -1,14 +0,0 @@ -# Nordic Semiconductor nRF9151 MCU - -# Copyright (c) 2023 Nordic Semiconductor ASA -# SPDX-License-Identifier: Apache-2.0 - -if SOC_NRF9151_LACA - -config SOC - default "nRF9151_LACA" - -config NUM_IRQS - default 65 - -endif # SOC_NRF9151_LACA diff --git a/soc/arm/nordic_nrf/nrf91/Kconfig.soc b/soc/arm/nordic_nrf/nrf91/Kconfig.soc index 0267ada4850..c9b8c54438b 100644 --- a/soc/arm/nordic_nrf/nrf91/Kconfig.soc +++ b/soc/arm/nordic_nrf/nrf91/Kconfig.soc @@ -34,10 +34,6 @@ config SOC_NRF9131_LACA bool "NRF9131_LACA" select SOC_NRF9120 -config SOC_NRF9151_LACA - bool "NRF9151_LACA" - select SOC_NRF9120 - endchoice config NRF_ENABLE_ICACHE From 31301a24487714792afd294da814558635885340 Mon Sep 17 00:00:00 2001 From: Robert Lubos Date: Tue, 6 Feb 2024 11:07:04 +0100 Subject: [PATCH 3530/3723] Revert "[nrf fromtree] drivers: sensor: adxl367: Add missing breaks" This reverts commit 51d4b69e9a0e82ba04b226c338aea438315d9913. Signed-off-by: Robert Lubos --- drivers/sensor/adxl367/adxl367.c | 6 ------ 1 file changed, 6 deletions(-) diff --git a/drivers/sensor/adxl367/adxl367.c b/drivers/sensor/adxl367/adxl367.c index 1d5c31ad021..f63b8f73a32 100644 --- a/drivers/sensor/adxl367/adxl367.c +++ b/drivers/sensor/adxl367/adxl367.c @@ -287,22 +287,16 @@ int adxl367_self_test(const struct device *dev) switch (cfg->odr) { case ADXL367_ODR_12P5HZ: st_delay_ms = 320; - break; case ADXL367_ODR_25HZ: st_delay_ms = 160; - break; case ADXL367_ODR_50HZ: st_delay_ms = 80; - break; case ADXL367_ODR_100HZ: st_delay_ms = 40; - break; case ADXL367_ODR_200HZ: st_delay_ms = 20; - break; case ADXL367_ODR_400HZ: st_delay_ms = 10; - break; default: return -EINVAL; } From 625b07b75bf0317b3fb9af822860fa82fee018dc Mon Sep 17 00:00:00 2001 From: Robert Lubos Date: Tue, 6 Feb 2024 11:07:04 +0100 Subject: [PATCH 3531/3723] Revert "[nrf fromlist] drivers: ieee802154: fix nRF5 Rx error handling" This reverts commit 8ba9711786a4cd6eea313b900130633f8b36145b. Signed-off-by: Robert Lubos --- drivers/ieee802154/ieee802154_nrf5.c | 10 +--------- drivers/ieee802154/ieee802154_nrf5.h | 3 --- 2 files changed, 1 insertion(+), 12 deletions(-) diff --git a/drivers/ieee802154/ieee802154_nrf5.c b/drivers/ieee802154/ieee802154_nrf5.c index b542c5007f8..6cbeb6ee2af 100644 --- a/drivers/ieee802154/ieee802154_nrf5.c +++ b/drivers/ieee802154/ieee802154_nrf5.c @@ -763,7 +763,6 @@ static int nrf5_init(const struct device *dev) nrf5_get_capabilities_at_boot(); - nrf5_radio->rx_on_when_idle = true; nrf5_radio_cfg->irq_config_func(dev); k_thread_create(&nrf5_radio->rx_thread, nrf5_radio->rx_stack, @@ -1004,7 +1003,6 @@ static int nrf5_configure(const struct device *dev, case IEEE802154_CONFIG_RX_ON_WHEN_IDLE: nrf_802154_rx_on_when_idle_set(config->rx_on_when_idle); - nrf5_data.rx_on_when_idle = config->rx_on_when_idle; break; default: @@ -1085,13 +1083,7 @@ void nrf_802154_receive_failed(nrf_802154_rx_error_t error, uint32_t id) #if defined(CONFIG_IEEE802154_CSL_ENDPOINT) if (id == DRX_SLOT_RX && error == NRF_802154_RX_ERROR_DELAYED_TIMEOUT) { - if (!nrf5_data.rx_on_when_idle) { - /* Transition to RxOff done automatically by the driver */ - return; - } else if (nrf5_data.event_handler) { - /* Notify the higher layer to allow it to transition if needed */ - nrf5_data.event_handler(dev, IEEE802154_EVENT_RX_OFF, NULL); - } + return; } #else ARG_UNUSED(id); diff --git a/drivers/ieee802154/ieee802154_nrf5.h b/drivers/ieee802154/ieee802154_nrf5.h index 0d4d9c9accf..b9f46dff307 100644 --- a/drivers/ieee802154/ieee802154_nrf5.h +++ b/drivers/ieee802154/ieee802154_nrf5.h @@ -110,9 +110,6 @@ struct nrf5_802154_data { /* The last configured value of CSL phase time in nanoseconds. */ net_time_t csl_rx_time; #endif /* CONFIG_NRF_802154_SER_HOST && CONFIG_IEEE802154_CSL_ENDPOINT */ - - /* Indicates if RxOnWhenIdle mode is enabled. */ - bool rx_on_when_idle; }; #endif /* ZEPHYR_DRIVERS_IEEE802154_IEEE802154_NRF5_H_ */ From 263d834460c10e288ba68003cc81c83273043147 Mon Sep 17 00:00:00 2001 From: Robert Lubos Date: Tue, 6 Feb 2024 11:07:05 +0100 Subject: [PATCH 3532/3723] Revert "[nrf fromtree] drivers: regulator: Fixed reference counting during enable" This reverts commit 908763768e6de644d8d08a34dc3834c32563ab15. Signed-off-by: Robert Lubos --- drivers/regulator/regulator_common.c | 9 +++------ 1 file changed, 3 insertions(+), 6 deletions(-) diff --git a/drivers/regulator/regulator_common.c b/drivers/regulator/regulator_common.c index 14866a3738f..7f33040d2d9 100644 --- a/drivers/regulator/regulator_common.c +++ b/drivers/regulator/regulator_common.c @@ -107,13 +107,10 @@ int regulator_enable(const struct device *dev) (void)k_mutex_lock(&data->lock, K_FOREVER); #endif - data->refcnt++; - - if (data->refcnt == 1) { + if (data->refcnt == 0) { ret = api->enable(dev); - if (ret < 0) { - data->refcnt--; - } else { + if (ret == 0) { + data->refcnt++; regulator_delay(config->off_on_delay_us); } } From 8c172ab0a5b54d33beb6abd296ffbab27ff346bd Mon Sep 17 00:00:00 2001 From: Robert Lubos Date: Tue, 6 Feb 2024 11:07:05 +0100 Subject: [PATCH 3533/3723] Revert "[nrf fromtree] net: openthread: Print the actual assert location" This reverts commit 5d7a30bb2fa0bc6130e0e054821a0daa7043a736. Signed-off-by: Robert Lubos --- modules/openthread/platform/misc.c | 7 +------ 1 file changed, 1 insertion(+), 6 deletions(-) diff --git a/modules/openthread/platform/misc.c b/modules/openthread/platform/misc.c index 5f9043dfa27..11fdc42ec34 100644 --- a/modules/openthread/platform/misc.c +++ b/modules/openthread/platform/misc.c @@ -99,10 +99,5 @@ void otPlatWakeHost(void) void otPlatAssertFail(const char *aFilename, int aLineNumber) { - /* - * The code below is used instead of __ASSERT(false) to print the actual assert - * location instead of __FILE__:__LINE__, which would point to this function. - */ - __ASSERT_PRINT("OpenThread ASSERT @ %s:%d\n", aFilename, aLineNumber); - __ASSERT_POST_ACTION(); + __ASSERT(false, "OpenThread ASSERT @ %s:%d", aFilename, aLineNumber); } From fd2a3a0ad33727ffd0a2fe80707f99f945fe3a99 Mon Sep 17 00:00:00 2001 From: Robert Lubos Date: Tue, 6 Feb 2024 11:07:05 +0100 Subject: [PATCH 3534/3723] Revert "[nrf fromtree] net: openthread: Remove PSA crypto backend workarounds" This reverts commit f6a644d15377ea7b9c8b953eb60398a017c6402a. Signed-off-by: Robert Lubos --- modules/openthread/platform/crypto_psa.c | 68 +++++++++++++++++++++--- 1 file changed, 61 insertions(+), 7 deletions(-) diff --git a/modules/openthread/platform/crypto_psa.c b/modules/openthread/platform/crypto_psa.c index 55018254154..0dcf3803fde 100644 --- a/modules/openthread/platform/crypto_psa.c +++ b/modules/openthread/platform/crypto_psa.c @@ -111,6 +111,31 @@ static bool checkContext(otCryptoContext *aContext, size_t aMinSize) return aContext != NULL && aContext->mContext != NULL && aContext->mContextSize >= aMinSize; } +static void ensureKeyIsLoaded(otCryptoKeyRef aKeyRef) +{ + /* + * The workaround below will no longer be need after updating TF-M version used in Zephyr + * to 1.5.0 (see upstream commit 42e77b561fcfe19819ff1e63cb7c0b672ee8ba41). + * In the recent versions of TF-M the concept of key handles and psa_open_key()/ + * psa_close_key() APIs have been being deprecated, but the version currently used in Zephyr + * is in the middle of that transition. Consequently, psa_destroy_key() and lots of other + * functions will fail when a key ID that they take as a parameter is not loaded from the + * persistent storage. That may occur when a given persistent key is created via + * psa_generate_key() or psa_import_key(), and then the device reboots. + * + * Use psa_open_key() when the key has not been loaded yet to work around the issue. + */ + psa_key_attributes_t attributes = PSA_KEY_ATTRIBUTES_INIT; + psa_status_t status = psa_get_key_attributes(aKeyRef, &attributes); + psa_key_id_t key_handle; + + if (status == PSA_ERROR_INVALID_HANDLE) { + psa_open_key(aKeyRef, &key_handle); + } + + psa_reset_key_attributes(&attributes); +} + void otPlatCryptoInit(void) { psa_crypto_init(); @@ -170,11 +195,15 @@ otError otPlatCryptoExportKey(otCryptoKeyRef aKeyRef, return OT_ERROR_INVALID_ARGS; } + ensureKeyIsLoaded(aKeyRef); + return psaToOtError(psa_export_key(aKeyRef, aBuffer, aBufferLen, aKeyLen)); } otError otPlatCryptoDestroyKey(otCryptoKeyRef aKeyRef) { + ensureKeyIsLoaded(aKeyRef); + return psaToOtError(psa_destroy_key(aKeyRef)); } @@ -183,6 +212,7 @@ bool otPlatCryptoHasKey(otCryptoKeyRef aKeyRef) psa_key_attributes_t attributes = PSA_KEY_ATTRIBUTES_INIT; psa_status_t status; + ensureKeyIsLoaded(aKeyRef); status = psa_get_key_attributes(aKeyRef, &attributes); psa_reset_key_attributes(&attributes); @@ -225,6 +255,7 @@ otError otPlatCryptoHmacSha256Start(otCryptoContext *aContext, const otCryptoKey return OT_ERROR_INVALID_ARGS; } + ensureKeyIsLoaded(aKey->mKeyRef); operation = aContext->mContext; status = psa_mac_sign_setup(operation, aKey->mKeyRef, PSA_ALG_HMAC(PSA_ALG_SHA_256)); @@ -292,6 +323,7 @@ otError otPlatCryptoAesEncrypt(otCryptoContext *aContext, const uint8_t *aInput, { const size_t block_size = PSA_BLOCK_CIPHER_BLOCK_LENGTH(PSA_KEY_TYPE_AES); psa_status_t status = PSA_SUCCESS; + psa_cipher_operation_t operation = PSA_CIPHER_OPERATION_INIT; psa_key_id_t *key_ref; size_t cipher_length; @@ -299,15 +331,37 @@ otError otPlatCryptoAesEncrypt(otCryptoContext *aContext, const uint8_t *aInput, return OT_ERROR_INVALID_ARGS; } + /* + * The code below can be simplified after updating TF-M version used in Zephyr to 1.5.0 + * (see upstream commit: 045ec4abfc73152a0116684ba9127d0a97cc8d34), using + * psa_cipher_encrypt() function which will replace the setup-update-finish sequence below. + */ key_ref = aContext->mContext; - status = psa_cipher_encrypt(*key_ref, - PSA_ALG_ECB_NO_PADDING, - aInput, - block_size, - aOutput, - block_size, - &cipher_length); + ensureKeyIsLoaded(*key_ref); + status = psa_cipher_encrypt_setup(&operation, *key_ref, PSA_ALG_ECB_NO_PADDING); + + if (status != PSA_SUCCESS) { + goto out; + } + + status = psa_cipher_update(&operation, + aInput, + block_size, + aOutput, + block_size, + &cipher_length); + if (status != PSA_SUCCESS) { + goto out; + } + + status = psa_cipher_finish(&operation, + aOutput + cipher_length, + block_size - cipher_length, + &cipher_length); + +out: + psa_cipher_abort(&operation); return psaToOtError(status); } From 20797209576e5856248b19aab25060d876d71f46 Mon Sep 17 00:00:00 2001 From: Robert Lubos Date: Tue, 6 Feb 2024 11:07:05 +0100 Subject: [PATCH 3535/3723] Revert "[nrf fromtree] net: openthread: Add new key and algorithm in PSA." This reverts commit 6ba80b70b43cce7e3a84fcfb9833ea51b2139450. Signed-off-by: Robert Lubos --- modules/openthread/platform/crypto_psa.c | 15 +++------------ 1 file changed, 3 insertions(+), 12 deletions(-) diff --git a/modules/openthread/platform/crypto_psa.c b/modules/openthread/platform/crypto_psa.c index 0dcf3803fde..e5b234ce030 100644 --- a/modules/openthread/platform/crypto_psa.c +++ b/modules/openthread/platform/crypto_psa.c @@ -41,8 +41,6 @@ static psa_key_type_t toPsaKeyType(otCryptoKeyType aType) return PSA_KEY_TYPE_AES; case OT_CRYPTO_KEY_TYPE_HMAC: return PSA_KEY_TYPE_HMAC; - case OT_CRYPTO_KEY_TYPE_ECDSA: - return PSA_KEY_TYPE_ECC_KEY_PAIR(PSA_ECC_FAMILY_SECP_R1); default: return PSA_KEY_TYPE_NONE; } @@ -55,8 +53,6 @@ static psa_algorithm_t toPsaAlgorithm(otCryptoKeyAlgorithm aAlgorithm) return PSA_ALG_ECB_NO_PADDING; case OT_CRYPTO_KEY_ALG_HMAC_SHA_256: return PSA_ALG_HMAC(PSA_ALG_SHA_256); - case OT_CRYPTO_KEY_ALG_ECDSA: - return PSA_ALG_DETERMINISTIC_ECDSA(PSA_ALG_SHA_256); default: /* * There is currently no constant like PSA_ALG_NONE, but 0 is used @@ -86,10 +82,6 @@ static psa_key_usage_t toPsaKeyUsage(int aUsage) usage |= PSA_KEY_USAGE_SIGN_HASH; } - if (aUsage & OT_CRYPTO_KEY_USAGE_VERIFY_HASH) { - usage |= PSA_KEY_USAGE_VERIFY_HASH; - } - return usage; } @@ -97,10 +89,9 @@ static bool checkKeyUsage(int aUsage) { /* Check if only supported flags have been passed */ int supported_flags = OT_CRYPTO_KEY_USAGE_EXPORT | - OT_CRYPTO_KEY_USAGE_ENCRYPT | - OT_CRYPTO_KEY_USAGE_DECRYPT | - OT_CRYPTO_KEY_USAGE_SIGN_HASH | - OT_CRYPTO_KEY_USAGE_VERIFY_HASH; + OT_CRYPTO_KEY_USAGE_ENCRYPT | + OT_CRYPTO_KEY_USAGE_DECRYPT | + OT_CRYPTO_KEY_USAGE_SIGN_HASH; return (aUsage & ~supported_flags) == 0; } From 1fc0c9cd4f5517e4cdcdf95f0cc72f4cba970b6d Mon Sep 17 00:00:00 2001 From: Robert Lubos Date: Tue, 6 Feb 2024 11:07:05 +0100 Subject: [PATCH 3536/3723] Revert "[nrf fromtree] net: openthread: implement `otPlatResetToBootloader`" This reverts commit aa1125153bc9e3ead72dc65ae5f969d3d4281965. Signed-off-by: Robert Lubos --- dts/bindings/options/openthread,config.yaml | 7 --- modules/openthread/CMakeLists.txt | 1 - modules/openthread/Kconfig.features | 23 +------ modules/openthread/platform/misc.c | 66 --------------------- 4 files changed, 2 insertions(+), 95 deletions(-) diff --git a/dts/bindings/options/openthread,config.yaml b/dts/bindings/options/openthread,config.yaml index 6366c289c80..054107fab44 100644 --- a/dts/bindings/options/openthread,config.yaml +++ b/dts/bindings/options/openthread,config.yaml @@ -10,7 +10,6 @@ description: | compatible = "openthread,config"; diag-gpios = <&gpio0 0 GPIO_ACTIVE_HIGH>, <&gpio1 0 GPIO_ACTIVE_LOW>; - bootloader-gpios = <&gpio0 1 GPIO_ACTIVE_HIGH>; }; }; @@ -22,9 +21,3 @@ properties: description: | This enables access to diagnostic GPIO pins. Each field consists of GPIO pin's configuration: controller's phandle, pin number and configuration flags. - - bootloader-gpios: - type: phandle-array - description: | - This enables resetting to bootloader by triggering given GPIO pin. Property represents - chosen GPIO pin's configuration: controller's phandle, pin number and configuration flags. diff --git a/modules/openthread/CMakeLists.txt b/modules/openthread/CMakeLists.txt index 5b64d3be2f5..c9ccf074649 100644 --- a/modules/openthread/CMakeLists.txt +++ b/modules/openthread/CMakeLists.txt @@ -99,7 +99,6 @@ kconfig_to_ot_option(CONFIG_OPENTHREAD_NETDATA_PUBLISHER OT_NETDATA_PUBLISHER "E kconfig_to_ot_option(CONFIG_OPENTHREAD_OPERATIONAL_DATASET_AUTO_INIT OT_OPERATIONAL_DATASET_AUTO_INIT "Enable operational dataset auto init") kconfig_to_ot_option(CONFIG_OPENTHREAD_OTNS OT_OTNS "Enable OTNS support") kconfig_to_ot_option(CONFIG_OPENTHREAD_PING_SENDER OT_PING_SENDER "Enable ping sender support") -kconfig_to_ot_option(CONFIG_OPENTHREAD_PLATFORM_BOOTLOADER_MODE OT_PLATFORM_BOOTLOADER_MODE "Enable platform bootloader mode support") kconfig_to_ot_option(CONFIG_OPENTHREAD_PLATFORM_KEY_REF OT_PLATFORM_KEY_REF "Enable platform key reference support") kconfig_to_ot_option(CONFIG_OPENTHREAD_PLATFORM_NETIF OT_PLATFORM_NETIF "Enable platform netif support") kconfig_to_ot_option(CONFIG_OPENTHREAD_PLATFORM_UDP OT_PLATFORM_UDP "Enable platform UDP support") diff --git a/modules/openthread/Kconfig.features b/modules/openthread/Kconfig.features index ba3990a348d..952a7853b43 100644 --- a/modules/openthread/Kconfig.features +++ b/modules/openthread/Kconfig.features @@ -17,7 +17,7 @@ config OPENTHREAD_THREAD_VERSION_1_3 bool "Version 1.3" config OPENTHREAD_THREAD_VERSION_1_3_1 bool "Version 1.3.1" -endchoice # OPENTHREAD_STACK_VERSION +endchoice config OPENTHREAD_THREAD_VERSION string @@ -255,25 +255,6 @@ config OPENTHREAD_PLATFORM_KEY_REF Enable usage of cryptographic key references instead of literal keys. This requires a crypto backend library that supports key references. -choice OPENTHREAD_PLATFORM_BOOTLOADER_MODE_CHOICE - prompt "Platform bootloader mode configuration" - optional - -config OPENTHREAD_PLATFORM_BOOTLOADER_MODE_RETENTION - bool "Bootloader mode support with boot mode retention API" - depends on RETENTION_BOOT_MODE && REBOOT - select OPENTHREAD_PLATFORM_BOOTLOADER_MODE - -config OPENTHREAD_PLATFORM_BOOTLOADER_MODE_GPIO - bool "Bootloader mode support with GPIO pin trigger" - select OPENTHREAD_PLATFORM_BOOTLOADER_MODE -endchoice # OPENTHREAD_PLATFORM_BOOTLOADER_MODE - -config OPENTHREAD_PLATFORM_BOOTLOADER_MODE - bool - help - Platform bootloader mode support - config OPENTHREAD_PLATFORM_NETIF bool "Platform netif support" @@ -295,7 +276,7 @@ config OPENTHREAD_POWER_SUPPLY_EXTERNAL_STABLE config OPENTHREAD_POWER_SUPPLY_EXTERNAL_UNSTABLE bool "OT_POWER_SUPPLY_EXTERNAL_UNSTABLE" -endchoice # OPENTHREAD_POWER_SUPPLY_CHOICE +endchoice config OPENTHREAD_POWER_SUPPLY string diff --git a/modules/openthread/platform/misc.c b/modules/openthread/platform/misc.c index 11fdc42ec34..7f57dddb9e3 100644 --- a/modules/openthread/platform/misc.c +++ b/modules/openthread/platform/misc.c @@ -9,24 +9,6 @@ #include #include -#if defined(CONFIG_OPENTHREAD_PLATFORM_BOOTLOADER_MODE_RETENTION) - -#include - -#elif defined(CONFIG_OPENTHREAD_PLATFORM_BOOTLOADER_MODE_GPIO) - -BUILD_ASSERT(DT_HAS_COMPAT_STATUS_OKAY(openthread_config), - "`openthread,config` compatible node not found"); -BUILD_ASSERT(DT_NODE_HAS_PROP(DT_COMPAT_GET_ANY_STATUS_OKAY(openthread_config), bootloader_gpios), - "`bootloader-gpios` property missing from `openthread,config` compatible node"); - -#include - -static const struct gpio_dt_spec bootloader_gpio = - GPIO_DT_SPEC_GET(DT_COMPAT_GET_ANY_STATUS_OKAY(openthread_config), - bootloader_gpios); -#endif - #include "platform-zephyr.h" void otPlatReset(otInstance *aInstance) @@ -37,54 +19,6 @@ void otPlatReset(otInstance *aInstance) sys_reboot(SYS_REBOOT_WARM); } -#if defined(CONFIG_OPENTHREAD_PLATFORM_BOOTLOADER_MODE) -otError otPlatResetToBootloader(otInstance *aInstance) -{ - OT_UNUSED_VARIABLE(aInstance); - -#if defined(CONFIG_OPENTHREAD_PLATFORM_BOOTLOADER_MODE_RETENTION) - if (bootmode_set(BOOT_MODE_TYPE_BOOTLOADER)) { - return OT_ERROR_NOT_CAPABLE; - } - sys_reboot(SYS_REBOOT_WARM); - -#elif defined(CONFIG_OPENTHREAD_PLATFORM_BOOTLOADER_MODE_GPIO) - /* - * To enable resetting to bootloader by triggering gpio pin, - * select `CONFIG_OPENTHREAD_PLATFORM_BOOTLOADER_MODE_GPIO=y`, - * and in Devicetree create `openthread` node in `/options/` path with - * `compatible = "openthread,config"` property and `bootloader-gpios` property, - * which should represent GPIO pin's configuration, - * containing controller phandle, pin number and pin flags. e.g: - * - * options { - * openthread { - * compatible = "openthread,config"; - * bootloader-gpios = <&gpio0 0 GPIO_ACTIVE_HIGH>; - * }; - * }; - * - * Note: in below implementation, chosen GPIO pin is configured as output - * and initialized to active state (logical value ‘1’). - * Configuring pin flags in `bootloader-gpios` allows to choose - * if pin should be active in high or in low state. - */ - - if (!gpio_is_ready_dt(&bootloader_gpio)) { - return OT_ERROR_NOT_CAPABLE; - } - gpio_pin_configure_dt(&bootloader_gpio, GPIO_OUTPUT_ACTIVE); - -#endif - - /* - * Return OT_ERROR_NOT_CAPABLE if resetting has been unsuccessful (invalid configuration or - * triggering reset had no effect) - */ - return OT_ERROR_NOT_CAPABLE; -} -#endif /* defined(CONFIG_OPENTHREAD_PLATFORM_BOOTLOADER_MODE) */ - otPlatResetReason otPlatGetResetReason(otInstance *aInstance) { ARG_UNUSED(aInstance); From 907c17028a3c5d91c8398f2a698e7003c1897fbe Mon Sep 17 00:00:00 2001 From: Robert Lubos Date: Tue, 6 Feb 2024 11:07:05 +0100 Subject: [PATCH 3537/3723] Revert "[nrf fromtree] net: openthread: add missing cmake option" This reverts commit 49502a0e47021b69efc7b2708ff68c8a2dc19423. Signed-off-by: Robert Lubos --- modules/openthread/CMakeLists.txt | 1 - .../platform/openthread-core-zephyr-config.h | 11 +++++++++++ 2 files changed, 11 insertions(+), 1 deletion(-) diff --git a/modules/openthread/CMakeLists.txt b/modules/openthread/CMakeLists.txt index c9ccf074649..6691084eebd 100644 --- a/modules/openthread/CMakeLists.txt +++ b/modules/openthread/CMakeLists.txt @@ -15,7 +15,6 @@ endmacro() set(OT_BUILD_EXECUTABLES OFF CACHE BOOL "Disable OpenThread samples") set(OT_BUILTIN_MBEDTLS_MANAGEMENT OFF CACHE BOOL "Use Zephyr's mbedTLS heap") set(OT_PLATFORM "zephyr" CACHE STRING "Zephyr as a target platform") -set(OT_PLATFORM_POWER_CALIBRATION OFF CACHE BOOL "Use Zephyr's power calibration handled by Radio Driver") set(OT_THREAD_VERSION ${CONFIG_OPENTHREAD_THREAD_VERSION} CACHE STRING "User selected Thread stack version") set(OT_CLI_TRANSPORT "CONSOLE" CACHE STRING "Set CLI to use console interpreter") diff --git a/modules/openthread/platform/openthread-core-zephyr-config.h b/modules/openthread/platform/openthread-core-zephyr-config.h index 71a087ca0b5..773cd170f2c 100644 --- a/modules/openthread/platform/openthread-core-zephyr-config.h +++ b/modules/openthread/platform/openthread-core-zephyr-config.h @@ -438,6 +438,17 @@ #define OPENTHREAD_CONFIG_POWER_CALIBRATION_ENABLE 0 #endif +/** + * @def OPENTHREAD_CONFIG_PLATFORM_POWER_CALIBRATION_ENABLE + * + * In Zephyr, power calibration is handled by Radio Driver, so it can't be handled on OT level. + * + */ +#ifndef OPENTHREAD_CONFIG_PLATFORM_POWER_CALIBRATION_ENABLE +#define OPENTHREAD_CONFIG_PLATFORM_POWER_CALIBRATION_ENABLE 0 +#endif + + /** * @def OPENTHREAD_CONFIG_RADIO_STATS * From d7f400030bb16dece2e1771f7bf1d933dcd149b5 Mon Sep 17 00:00:00 2001 From: Robert Lubos Date: Tue, 6 Feb 2024 11:07:06 +0100 Subject: [PATCH 3538/3723] Revert "[nrf fromtree] net: openthread: increase TCAT stack size" This reverts commit 2fea89562a6981c749378721e65cd3ed19d6c30a. Signed-off-by: Robert Lubos --- modules/openthread/Kconfig.thread | 1 - 1 file changed, 1 deletion(-) diff --git a/modules/openthread/Kconfig.thread b/modules/openthread/Kconfig.thread index 542992e7fa1..66e039b7300 100644 --- a/modules/openthread/Kconfig.thread +++ b/modules/openthread/Kconfig.thread @@ -184,7 +184,6 @@ config OPENTHREAD_DEFAULT_TX_POWER config OPENTHREAD_BLE_TCAT_THREAD_STACK_SIZE int "Openthread default TCAT stack size" - default 5120 if OPENTHREAD_CRYPTO_PSA default 4200 help Openthread default TCAT stack size. From 3f6cfbedd6a4614ee30efb1c5076b42eea637717 Mon Sep 17 00:00:00 2001 From: Robert Lubos Date: Tue, 6 Feb 2024 11:07:06 +0100 Subject: [PATCH 3539/3723] Revert "[nrf fromtree] net: openthread: Add cmake makro to openthread cmake lists." This reverts commit a0272bc8bc2343fefe6abcd5e3949b505b055c9f. Signed-off-by: Robert Lubos --- modules/openthread/CMakeLists.txt | 571 +++++++++++++++++++++++++----- 1 file changed, 481 insertions(+), 90 deletions(-) diff --git a/modules/openthread/CMakeLists.txt b/modules/openthread/CMakeLists.txt index 6691084eebd..150039863d9 100644 --- a/modules/openthread/CMakeLists.txt +++ b/modules/openthread/CMakeLists.txt @@ -3,14 +3,6 @@ if(CONFIG_OPENTHREAD_SOURCES) set(CMAKE_TRY_COMPILE_TARGET_TYPE STATIC_LIBRARY) -macro(kconfig_to_ot_option kconfig_option ot_config description) - if(${kconfig_option}) - set(${ot_config} ON CACHE BOOL "${description}" FORCE) - else() - set(${ot_config} OFF CACHE BOOL "${description}" FORCE) - endif() -endmacro() - # OpenThread options set(OT_BUILD_EXECUTABLES OFF CACHE BOOL "Disable OpenThread samples") set(OT_BUILTIN_MBEDTLS_MANAGEMENT OFF CACHE BOOL "Use Zephyr's mbedTLS heap") @@ -36,95 +28,494 @@ elseif(CONFIG_OPENTHREAD_MTD) set(OT_MTD ON CACHE BOOL "Enable MTD" FORCE) endif() -kconfig_to_ot_option(CONFIG_OPENTHREAD_ANYCAST_LOCATOR OT_ANYCAST_LOCATOR "Enable anycast locator") -kconfig_to_ot_option(CONFIG_ASSERT OT_ASSERT "Enable assert function OT_ASSERT()") -kconfig_to_ot_option(CONFIG_OPENTHREAD_BACKBONE_ROUTER OT_BACKBONE_ROUTER "Enable backbone router functionality") -kconfig_to_ot_option(CONFIG_OPENTHREAD_BACKBONE_ROUTER_DUA_NDPROXYING OT_BACKBONE_ROUTER_DUA_NDPROXYING "Enable BBR DUA ND Proxy support") -kconfig_to_ot_option(CONFIG_OPENTHREAD_BACKBONE_ROUTER_MULTICAST_ROUTING OT_BACKBONE_ROUTER_MULTICAST_ROUTING "Enable BBR MR support") -kconfig_to_ot_option(CONFIG_OPENTHREAD_BLE_TCAT OT_BLE_TCAT "Enable BLE TCAT support") -kconfig_to_ot_option(CONFIG_OPENTHREAD_BORDER_AGENT OT_BORDER_AGENT "Enable Border Agent") -kconfig_to_ot_option(CONFIG_OPENTHREAD_BORDER_ROUTER OT_BORDER_ROUTER "Enable Border Router") -kconfig_to_ot_option(CONFIG_OPENTHREAD_BORDER_ROUTING OT_BORDER_ROUTING "Enable Border routing") -kconfig_to_ot_option(CONFIG_OPENTHREAD_BORDER_ROUTING_COUNTERS OT_BORDER_ROUTING_COUNTERS "Enable Border routing counters") -kconfig_to_ot_option(CONFIG_OPENTHREAD_BORDER_ROUTING_DHCP6_PD OT_BORDER_ROUTING_DHCP6_PD "DHCPv6-PD support in border routing") -kconfig_to_ot_option(CONFIG_OPENTHREAD_CHANNEL_MANAGER OT_CHANNEL_MANAGER "Enable channel manager support") -kconfig_to_ot_option(CONFIG_OPENTHREAD_CHANNEL_MONITOR OT_CHANNEL_MONITOR "Enable channel monitor support") -kconfig_to_ot_option(CONFIG_OPENTHREAD_COAP OT_COAP "Enable CoAP API") -kconfig_to_ot_option(CONFIG_OPENTHREAD_COAP_BLOCK OT_COAP_BLOCK "Enable CoAP Block-wise option support") -kconfig_to_ot_option(CONFIG_OPENTHREAD_COAP_OBSERVE OT_COAP_OBSERVE "Enable CoAP Observe option support") -kconfig_to_ot_option(CONFIG_OPENTHREAD_COAPS OT_COAPS "Enable secure CoAP API support") -kconfig_to_ot_option(CONFIG_OPENTHREAD_COMMISSIONER OT_COMMISSIONER "Enable Commissioner") -kconfig_to_ot_option(CONFIG_OPENTHREAD_CSL_AUTO_SYNC OT_CSL_AUTO_SYNC "Enable csl autosync") -kconfig_to_ot_option(CONFIG_OPENTHREAD_CSL_DEBUG OT_CSL_DEBUG "Enable CSL debug") -kconfig_to_ot_option(CONFIG_OPENTHREAD_CSL_RECEIVER OT_CSL_RECEIVER "Enable CSL receiver feature for Thread 1.2") -kconfig_to_ot_option(CONFIG_OPENTHREAD_CSL_RECEIVER_LOCAL_TIME_SYNC OT_CSL_RECEIVER_LOCAL_TIME_SYNC "Use local time for CSL sync") -kconfig_to_ot_option(CONFIG_OPENTHREAD_DATASET_UPDATER OT_DATASET_UPDATER "Enable Dataset updater") -kconfig_to_ot_option(CONFIG_OPENTHREAD_DEVICE_PROP_LEADER_WEIGHT OT_DEVICE_PROP_LEADER_WEIGHT "Enable device props for leader weight") -kconfig_to_ot_option(CONFIG_OPENTHREAD_DHCP6_CLIENT OT_DHCP6_CLIENT "Enable DHCPv6 Client") -kconfig_to_ot_option(CONFIG_OPENTHREAD_DHCP6_SERVER OT_DHCP6_SERVER "Enable DHCPv6 Server") -kconfig_to_ot_option(CONFIG_OPENTHREAD_DIAG OT_DIAGNOSTIC "Enable Diagnostics support") -kconfig_to_ot_option(CONFIG_OPENTHREAD_DNS_CLIENT OT_DNS_CLIENT "Enable DNS client support") -kconfig_to_ot_option(CONFIG_OPENTHREAD_DNS_CLIENT_OVER_TCP OT_DNS_CLIENT_OVER_TCP "Enable dns query over tcp") -kconfig_to_ot_option(CONFIG_OPENTHREAD_DNS_DSO OT_DNS_DSO "Enable DNS Stateful Operations (DSO) support") -kconfig_to_ot_option(CONFIG_OPENTHREAD_DNS_UPSTREAM_QUERY OT_DNS_UPSTREAM_QUERY "Enable forwarding DNS queries to upstream") -kconfig_to_ot_option(CONFIG_OPENTHREAD_DNSSD_SERVER OT_DNSSD_SERVER "Enable DNS-SD server support") -kconfig_to_ot_option(CONFIG_OPENTHREAD_DUA OT_DUA "Enable Domain Unicast Address feature for Thread 1.2") -kconfig_to_ot_option(CONFIG_OPENTHREAD_ECDSA OT_ECDSA "Enable ECDSA support") -kconfig_to_ot_option(CONFIG_OPENTHREAD_ENABLE_SERVICE OT_SERVICE "Enable Service entries in Thread Network Data") -kconfig_to_ot_option(CONFIG_OPENTHREAD_EXTERNAL_HEAP OT_EXTERNAL_HEAP "Enable external heap support") -kconfig_to_ot_option(CONFIG_OPENTHREAD_FIREWALL OT_FIREWALL "Enable firewall") -kconfig_to_ot_option(CONFIG_OPENTHREAD_FULL_LOGS OT_FULL_LOGS "Enable full logs") -kconfig_to_ot_option(CONFIG_OPENTHREAD_HISTORY_TRACKER OT_HISTORY_TRACKER "Enable history tracker support.") -kconfig_to_ot_option(CONFIG_OPENTHREAD_IP6_FRAGM OT_IP6_FRAGM "Enable IPv6 fragmentation support") -kconfig_to_ot_option(CONFIG_OPENTHREAD_JAM_DETECTION OT_JAM_DETECTION "Enable Jam Detection") -kconfig_to_ot_option(CONFIG_OPENTHREAD_JOINER OT_JOINER "Enable Joiner") -kconfig_to_ot_option(CONFIG_OPENTHREAD_LEGACY OT_LEGACY "Enable legacy network support") -kconfig_to_ot_option(CONFIG_OPENTHREAD_LINK_METRICS_INITIATOR OT_LINK_METRICS_INITIATOR "Enable Link Metrics initiator for Thread 1.2") -kconfig_to_ot_option(CONFIG_OPENTHREAD_LINK_METRICS_MANAGER OT_LINK_METRICS_MANAGER "Enable Link Metrics manager for Thread 1.2") -kconfig_to_ot_option(CONFIG_OPENTHREAD_LINK_METRICS_SUBJECT OT_LINK_METRICS_SUBJECT "Enable Link Metrics subject for Thread 1.2") -kconfig_to_ot_option(CONFIG_OPENTHREAD_LOG_LEVEL_DYNAMIC OT_LOG_LEVEL_DYNAMIC "Enable dynamic log level control") -kconfig_to_ot_option(CONFIG_OPENTHREAD_MAC_FILTER OT_MAC_FILTER "Enable MAC filter support") -kconfig_to_ot_option(CONFIG_OPENTHREAD_MESH_DIAG OT_MESH_DIAG "Enable Mesh Diagnostics") -kconfig_to_ot_option(CONFIG_OPENTHREAD_MESSAGE_USE_HEAP OT_MESSAGE_USE_HEAP "Enable heap allocator for message buffers") -kconfig_to_ot_option(CONFIG_OPENTHREAD_MLE_LONG_ROUTES OT_MLE_LONG_ROUTES "Enable MLE long routes support (Experimental)") -kconfig_to_ot_option(CONFIG_OPENTHREAD_MLR OT_MLR "Enable Multicast Listener Registration feature for Thread 1.2") -kconfig_to_ot_option(CONFIG_OPENTHREAD_MULTIPAN_RCP OT_MULTIPAN_RCP "Enable Multi-PAN RCP") -kconfig_to_ot_option(CONFIG_OPENTHREAD_MULTIPLE_INSTANCE OT_MULTIPLE_INSTANCE "Enable multiple instances") -kconfig_to_ot_option(CONFIG_OPENTHREAD_NAT64_BORDER_ROUTING OT_NAT64_BORDER_ROUTING "Enable border routing NAT64 support") -kconfig_to_ot_option(CONFIG_OPENTHREAD_NAT64_TRANSLATOR OT_NAT64_TRANSLATOR "Enable NAT64 translator") -kconfig_to_ot_option(CONFIG_OPENTHREAD_NEIGHBOR_DISCOVERY_AGENT OT_NEIGHBOR_DISCOVERY_AGENT "Enable neighbor discovery agent support") -kconfig_to_ot_option(CONFIG_OPENTHREAD_NETDIAG_CLIENT OT_NETDIAG_CLIENT "Enable TMF network diagnostics on clients") -kconfig_to_ot_option(CONFIG_OPENTHREAD_NETDATA_PUBLISHER OT_NETDATA_PUBLISHER "Enable Thread Network Data publisher") -kconfig_to_ot_option(CONFIG_OPENTHREAD_OPERATIONAL_DATASET_AUTO_INIT OT_OPERATIONAL_DATASET_AUTO_INIT "Enable operational dataset auto init") -kconfig_to_ot_option(CONFIG_OPENTHREAD_OTNS OT_OTNS "Enable OTNS support") -kconfig_to_ot_option(CONFIG_OPENTHREAD_PING_SENDER OT_PING_SENDER "Enable ping sender support") -kconfig_to_ot_option(CONFIG_OPENTHREAD_PLATFORM_KEY_REF OT_PLATFORM_KEY_REF "Enable platform key reference support") -kconfig_to_ot_option(CONFIG_OPENTHREAD_PLATFORM_NETIF OT_PLATFORM_NETIF "Enable platform netif support") -kconfig_to_ot_option(CONFIG_OPENTHREAD_PLATFORM_UDP OT_PLATFORM_UDP "Enable platform UDP support") -kconfig_to_ot_option(CONFIG_OPENTHREAD_RADIO_LINK_IEEE_802_15_4_ENABLE OT_15_4 "Enable 802.15.4 radio") -kconfig_to_ot_option(CONFIG_OPENTHREAD_RAW OT_LINK_RAW "Enable Link Raw") -kconfig_to_ot_option(CONFIG_OPENTHREAD_REFERENCE_DEVICE OT_REFERENCE_DEVICE "Enable Thread Certification Reference Device") -kconfig_to_ot_option(CONFIG_OPENTHREAD_SETTINGS_RAM OT_SETTINGS_RAM "Enable volatile-only storage of settings") -kconfig_to_ot_option(CONFIG_OPENTHREAD_SLAAC OT_SLAAC "Enable SLAAC") -kconfig_to_ot_option(CONFIG_OPENTHREAD_SNTP_CLIENT OT_SNTP_CLIENT "Enable SNTP Client support") -kconfig_to_ot_option(CONFIG_OPENTHREAD_SRP_CLIENT OT_SRP_CLIENT "Enable SRP Client support") -kconfig_to_ot_option(CONFIG_OPENTHREAD_SRP_SERVER OT_SRP_SERVER "Enable SRP Server support") -kconfig_to_ot_option(CONFIG_OPENTHREAD_TCP_ENABLE OT_TCP "Enable TCP support") -kconfig_to_ot_option(CONFIG_OPENTHREAD_TIME_SYNC OT_TIME_SYNC "Enable the time synchronization service feature") -kconfig_to_ot_option(CONFIG_OPENTHREAD_TREL OT_TREL "Enable TREL radio link for Thread over Infrastructure feature") -kconfig_to_ot_option(CONFIG_OPENTHREAD_TX_BEACON_PAYLOAD OT_TX_BEACON_PAYLOAD "Enable tx beacon payload support") -kconfig_to_ot_option(CONFIG_OPENTHREAD_TX_QUEUE_STATISTICS OT_TX_QUEUE_STATS "Enable tx queue statistics") -kconfig_to_ot_option(CONFIG_OPENTHREAD_UDP_FORWARD OT_UDP_FORWARD "Enable UDP forward feature") -kconfig_to_ot_option(CONFIG_OPENTHREAD_UPTIME OT_UPTIME "Enable support for tracking OpenThread instance's uptime") +if(CONFIG_OPENTHREAD_ANYCAST_LOCATOR) + set(OT_ANYCAST_LOCATOR ON CACHE BOOL "Enable anycast locator" FORCE) +else() + set(OT_ANYCAST_LOCATOR OFF CACHE BOOL "Enable anycast locator" FORCE) +endif() -if(CONFIG_OPENTHREAD_COPROCESSOR_VENDOR_HOOK_SOURCE) - set(OT_NCP_VENDOR_HOOK_SOURCE ${CONFIG_OPENTHREAD_COPROCESSOR_VENDOR_HOOK_SOURCE} CACHE STRING "NCP vendor hook source file name" FORCE) +if(CONFIG_ASSERT) + set(OT_ASSERT ON CACHE BOOL "Enable assert function OT_ASSERT()" FORCE) +else() + set(OT_ASSERT OFF CACHE BOOL "Enable assert function OT_ASSERT()" FORCE) +endif() + +if(CONFIG_OPENTHREAD_BACKBONE_ROUTER) + set(OT_BACKBONE_ROUTER ON CACHE BOOL "Enable backbone router functionality" FORCE) +else() + set(OT_BACKBONE_ROUTER OFF CACHE BOOL "Enable backbone router functionality" FORCE) +endif() + +if(CONFIG_OPENTHREAD_BACKBONE_ROUTER_DUA_NDPROXYING) + set(OT_BACKBONE_ROUTER_DUA_NDPROXYING ON CACHE BOOL "Enable BBR DUA ND Proxy support" FORCE) +else() + set(OT_BACKBONE_ROUTER_DUA_NDPROXYING OFF CACHE BOOL "Enable BBR DUA ND Proxy support" FORCE) +endif() + +if(CONFIG_OPENTHREAD_BACKBONE_ROUTER_MULTICAST_ROUTING) + set(OT_BACKBONE_ROUTER_MULTICAST_ROUTING ON CACHE BOOL "Enable BBR MR support" FORCE) +else() + set(OT_BACKBONE_ROUTER_MULTICAST_ROUTING OFF CACHE BOOL "Enable BBR MR support" FORCE) +endif() + +if(CONFIG_OPENTHREAD_BLE_TCAT) + set(OT_BLE_TCAT ON CACHE BOOL "Enable BLE TCAT support" FORCE) +else() + set(OT_BLE_TCAT OFF CACHE BOOL "Enable BLE TCAT support" FORCE) +endif() + +if(CONFIG_OPENTHREAD_BORDER_AGENT) + set(OT_BORDER_AGENT ON CACHE BOOL "Enable Border Agent" FORCE) +else() + set(OT_BORDER_AGENT OFF CACHE BOOL "Enable Border Agent" FORCE) +endif() + +if(CONFIG_OPENTHREAD_BORDER_ROUTER) + set(OT_BORDER_ROUTER ON CACHE BOOL "Enable Border Router" FORCE) +else() + set(OT_BORDER_ROUTER OFF CACHE BOOL "Enable Border Router" FORCE) +endif() + +if(CONFIG_OPENTHREAD_BORDER_ROUTING) + set(OT_BORDER_ROUTING ON CACHE BOOL "Enable Border routing" FORCE) +else() + set(OT_BORDER_ROUTING OFF CACHE BOOL "Enable Border routing" FORCE) +endif() + +if(CONFIG_OPENTHREAD_BORDER_ROUTING_COUNTERS) + set(OT_BORDER_ROUTING_COUNTERS ON CACHE BOOL "Enable Border routing counters" FORCE) +else() + set(OT_BORDER_ROUTING_COUNTERS OFF CACHE BOOL "Enable Border routing counters" FORCE) +endif() + +if(CONFIG_OPENTHREAD_BORDER_ROUTING_DHCP6_PD) + set(OT_BORDER_ROUTING_DHCP6_PD ON CACHE BOOL "DHCPv6-PD support in border routing" FORCE) +else() + set(OT_BORDER_ROUTING_DHCP6_PD OFF CACHE BOOL "DHCPv6-PD support in border routing" FORCE) +endif() + +if(CONFIG_OPENTHREAD_CHANNEL_MANAGER) + set(OT_CHANNEL_MANAGER ON CACHE BOOL "Enable channel manager support" FORCE) +else() + set(OT_CHANNEL_MANAGER OFF CACHE BOOL "Enable channel manager support" FORCE) +endif() + +if(CONFIG_OPENTHREAD_CHANNEL_MONITOR) + set(OT_CHANNEL_MONITOR ON CACHE BOOL "Enable channel monitor support" FORCE) +else() + set(OT_CHANNEL_MONITOR OFF CACHE BOOL "Enable channel monitor support" FORCE) +endif() + +if(CONFIG_OPENTHREAD_COAP) + set(OT_COAP ON CACHE BOOL "Enable CoAP API" FORCE) +else() + set(OT_COAP OFF CACHE BOOL "Enable CoAP API" FORCE) +endif() + +if(CONFIG_OPENTHREAD_COAP_BLOCK) + set(OT_COAP_BLOCK ON CACHE BOOL "Enable CoAP Block-wise option support" FORCE) +else() + set(OT_COAP_BLOCK OFF CACHE BOOL "Enable CoAP Block-wise option support" FORCE) +endif() + +if(CONFIG_OPENTHREAD_COAP_OBSERVE) + set(OT_COAP_OBSERVE ON CACHE BOOL "Enable CoAP Observe option support" FORCE) +else() + set(OT_COAP_OBSERVE OFF CACHE BOOL "Enable CoAP Observe option support" FORCE) +endif() + +if(CONFIG_OPENTHREAD_COAPS) + set(OT_COAPS ON CACHE BOOL "Enable secure CoAP API support" FORCE) +else() + set(OT_COAPS OFF CACHE BOOL "Enable secure CoAP API support" FORCE) +endif() + +if(CONFIG_OPENTHREAD_COMMISSIONER) + set(OT_COMMISSIONER ON CACHE BOOL "Enable Commissioner" FORCE) +else() + set(OT_COMMISSIONER OFF CACHE BOOL "Enable Commissioner" FORCE) +endif() + +if(CONFIG_OPENTHREAD_CSL_AUTO_SYNC) + set(OT_CSL_AUTO_SYNC ON CACHE BOOL "Enable csl autosync" FORCE) +else() + set(OT_CSL_AUTO_SYNC OFF CACHE BOOL "Enable csl autosync" FORCE) +endif() + +if(CONFIG_OPENTHREAD_CSL_DEBUG) + set(OT_CSL_DEBUG ON CACHE BOOL "Enable CSL debug" FORCE) +else() + set(OT_CSL_DEBUG OFF CACHE BOOL "Enable CSL debug" FORCE) +endif() + +if(CONFIG_OPENTHREAD_CSL_RECEIVER) + set(OT_CSL_RECEIVER ON CACHE BOOL "Enable CSL receiver feature for Thread 1.2" FORCE) +else() + set(OT_CSL_RECEIVER OFF CACHE BOOL "Enable CSL receiver feature for Thread 1.2" FORCE) +endif() + +if(CONFIG_OPENTHREAD_CSL_RECEIVER_LOCAL_TIME_SYNC) + set(OT_CSL_RECEIVER_LOCAL_TIME_SYNC ON CACHE BOOL "Use local time for CSL sync" FORCE) +else() + set(OT_CSL_RECEIVER_LOCAL_TIME_SYNC OFF CACHE BOOL "Use local time for CSL sync" FORCE) +endif() + +if(CONFIG_OPENTHREAD_DATASET_UPDATER) + set(OT_DATASET_UPDATER ON CACHE BOOL "Enable Dataset updater" FORCE) +else() + set(OT_DATASET_UPDATER OFF CACHE BOOL "Enable Dataset updater" FORCE) +endif() + +if(CONFIG_OPENTHREAD_DEVICE_PROP_LEADER_WEIGHT) + set(OT_DEVICE_PROP_LEADER_WEIGHT ON CACHE BOOL "Enable device props for leader weight" FORCE) +else() + set(OT_DEVICE_PROP_LEADER_WEIGHT OFF CACHE BOOL "Enable device props for leader weight" FORCE) +endif() + +if(CONFIG_OPENTHREAD_DHCP6_CLIENT) + set(OT_DHCP6_CLIENT ON CACHE BOOL "Enable DHCPv6 Client" FORCE) +else() + set(OT_DHCP6_CLIENT OFF CACHE BOOL "Enable DHCPv6 Client" FORCE) +endif() + +if(CONFIG_OPENTHREAD_DHCP6_SERVER) + set(OT_DHCP6_SERVER ON CACHE BOOL "Enable DHCPv6 Server" FORCE) +else() + set(OT_DHCP6_SERVER OFF CACHE BOOL "Enable DHCPv6 Server" FORCE) +endif() + +if(CONFIG_OPENTHREAD_DIAG) + set(OT_DIAGNOSTIC ON CACHE BOOL "Enable Diagnostics support" FORCE) +else() + set(OT_DIAGNOSTIC OFF CACHE BOOL "Enable Diagnostics support" FORCE) +endif() + +if(CONFIG_OPENTHREAD_DNS_CLIENT) + set(OT_DNS_CLIENT ON CACHE BOOL "Enable DNS client support" FORCE) +else() + set(OT_DNS_CLIENT OFF CACHE BOOL "Enable DNS client support" FORCE) +endif() + +if(CONFIG_OPENTHREAD_DNS_CLIENT_OVER_TCP) + set(OT_DNS_CLIENT_OVER_TCP ON CACHE BOOL "Enable dns query over tcp" FORCE) +else() + set(OT_DNS_CLIENT_OVER_TCP OFF CACHE BOOL "Enable dns query over tcp" FORCE) +endif() + +if(CONFIG_OPENTHREAD_DNS_DSO) + set(OT_DNS_DSO ON CACHE BOOL "Enable DNS Stateful Operations (DSO) support" FORCE) +else() + set(OT_DNS_DSO OFF CACHE BOOL "Enable DNS Stateful Operations (DSO) support" FORCE) +endif() + +if(CONFIG_OPENTHREAD_DNS_UPSTREAM_QUERY) + set(OT_DNS_UPSTREAM_QUERY ON CACHE BOOL "Enable forwarding DNS queries to upstream" FORCE) +else() + set(OT_DNS_UPSTREAM_QUERY OFF CACHE BOOL "Enable forwarding DNS queries to upstream" FORCE) +endif() + +if(CONFIG_OPENTHREAD_DNSSD_SERVER) + set(OT_DNSSD_SERVER ON CACHE BOOL "Enable DNS-SD server support" FORCE) +else() + set(OT_DNSSD_SERVER OFF CACHE BOOL "Enable DNS-SD server support" FORCE) +endif() + +if(CONFIG_OPENTHREAD_DUA) + set(OT_DUA ON CACHE BOOL "Enable Domain Unicast Address feature for Thread 1.2" FORCE) +else() + set(OT_DUA OFF CACHE BOOL "Enable Domain Unicast Address feature for Thread 1.2" FORCE) +endif() + +if(CONFIG_OPENTHREAD_ECDSA) + set(OT_ECDSA ON CACHE BOOL "Enable ECDSA support" FORCE) +else() + set(OT_ECDSA OFF CACHE BOOL "Enable ECDSA support" FORCE) +endif() + +if(CONFIG_OPENTHREAD_ENABLE_SERVICE) + set(OT_SERVICE ON CACHE BOOL "Enable Service entries in Thread Network Data" FORCE) +else() + set(OT_SERVICE OFF CACHE BOOL "Enable Service entries in Thread Network Data" FORCE) +endif() + +if(CONFIG_OPENTHREAD_EXTERNAL_HEAP) + set(OT_EXTERNAL_HEAP ON CACHE BOOL "Enable external heap support" FORCE) +else() + set(OT_EXTERNAL_HEAP OFF CACHE BOOL "Enable external heap support" FORCE) +endif() + +if(CONFIG_OPENTHREAD_FIREWALL) + set(OT_FIREWALL ON CACHE BOOL "Enable firewall" FORCE) +else() + set(OT_FIREWALL OFF CACHE BOOL "Enable firewall" FORCE) +endif() + +if(CONFIG_OPENTHREAD_FULL_LOGS) + set(OT_FULL_LOGS ON CACHE BOOL "Enable full logs" FORCE) +else() + set(OT_FULL_LOGS OFF CACHE BOOL "Enable full logs" FORCE) +endif() + +if(CONFIG_OPENTHREAD_HISTORY_TRACKER) + set(OT_HISTORY_TRACKER ON CACHE BOOL "Enable history tracker support." FORCE) +else() + set(OT_HISTORY_TRACKER OFF CACHE BOOL "Enable history tracker support." FORCE) +endif() + +if(CONFIG_OPENTHREAD_IP6_FRAGM) + set(OT_IP6_FRAGM ON CACHE BOOL "Enable IPv6 fragmentation support" FORCE) +else() + set(OT_IP6_FRAGM OFF CACHE BOOL "Enable IPv6 fragmentation support" FORCE) +endif() + +if(CONFIG_OPENTHREAD_JAM_DETECTION) + set(OT_JAM_DETECTION ON CACHE BOOL "Enable Jam Detection" FORCE) +else() + set(OT_JAM_DETECTION OFF CACHE BOOL "Enable Jam Detection" FORCE) +endif() + +if(CONFIG_OPENTHREAD_JOINER) + set(OT_JOINER ON CACHE BOOL "Enable Joiner" FORCE) +else() + set(OT_JOINER OFF CACHE BOOL "Enable Joiner" FORCE) +endif() + +if(CONFIG_OPENTHREAD_LEGACY) + set(OT_LEGACY ON CACHE BOOL "Enable legacy network support" FORCE) +else() + set(OT_LEGACY OFF CACHE BOOL "Enable legacy network support" FORCE) +endif() + +if(CONFIG_OPENTHREAD_LINK_METRICS_INITIATOR) + set(OT_LINK_METRICS_INITIATOR ON CACHE BOOL "Enable Link Metrics initiator for Thread 1.2" FORCE) +else() + set(OT_LINK_METRICS_INITIATOR OFF CACHE BOOL "Enable Link Metrics initiator for Thread 1.2" FORCE) +endif() + +if(CONFIG_OPENTHREAD_LINK_METRICS_MANAGER) + set(OT_LINK_METRICS_MANAGER ON CACHE BOOL "Enable Link Metrics manager for Thread 1.2" FORCE) +else() + set(OT_LINK_METRICS_MANAGER OFF CACHE BOOL "Enable Link Metrics manager for Thread 1.2" FORCE) +endif() + +if(CONFIG_OPENTHREAD_LINK_METRICS_SUBJECT) + set(OT_LINK_METRICS_SUBJECT ON CACHE BOOL "Enable Link Metrics subject for Thread 1.2" FORCE) +else() + set(OT_LINK_METRICS_SUBJECT OFF CACHE BOOL "Enable Link Metrics subject for Thread 1.2" FORCE) +endif() + +if(CONFIG_OPENTHREAD_LOG_LEVEL_DYNAMIC) + set(OT_LOG_LEVEL_DYNAMIC ON CACHE BOOL "Enable dynamic log level control" FORCE) +else() + set(OT_LOG_LEVEL_DYNAMIC OFF CACHE BOOL "Enable dynamic log level control" FORCE) +endif() + +if(CONFIG_OPENTHREAD_MAC_FILTER) + set(OT_MAC_FILTER ON CACHE BOOL "Enable MAC filter support" FORCE) +else() + set(OT_MAC_FILTER OFF CACHE BOOL "Enable MAC filter support" FORCE) +endif() + +if(CONFIG_OPENTHREAD_MESH_DIAG) + set(OT_MESH_DIAG ON CACHE BOOL "Enable Mesh Diagnostics" FORCE) +else() + set(OT_MESH_DIAG OFF CACHE BOOL "Enable Mesh Diagnostics" FORCE) +endif() + +if(CONFIG_OPENTHREAD_MESSAGE_USE_HEAP) + set(OT_MESSAGE_USE_HEAP ON CACHE BOOL "Enable heap allocator for message buffers" FORCE) +else() + set(OT_MESSAGE_USE_HEAP OFF CACHE BOOL "Enable heap allocator for message buffers" FORCE) +endif() + +if(CONFIG_OPENTHREAD_MLE_LONG_ROUTES) + set(OT_MLE_LONG_ROUTES ON CACHE BOOL "Enable MLE long routes support (Experimental)" FORCE) +else() + set(OT_MLE_LONG_ROUTES OFF CACHE BOOL "Enable MLE long routes support (Experimental)" FORCE) +endif() + +if(CONFIG_OPENTHREAD_MLR) + set(OT_MLR ON CACHE BOOL "Enable Multicast Listener Registration feature for Thread 1.2" FORCE) +else() + set(OT_MLR OFF CACHE BOOL "Enable Multicast Listener Registration feature for Thread 1.2" FORCE) +endif() + +if(CONFIG_OPENTHREAD_MULTIPAN_RCP) + set(OT_MULTIPAN_RCP ON CACHE BOOL "Enable Multi-PAN RCP" FORCE) +else() + set(OT_MULTIPAN_RCP OFF CACHE BOOL "Enable Multi-PAN RCP" FORCE) +endif() + +if(CONFIG_OPENTHREAD_MULTIPLE_INSTANCE) + set(OT_MULTIPLE_INSTANCE ON CACHE BOOL "Enable multiple instances" FORCE) +else() + set(OT_MULTIPLE_INSTANCE OFF CACHE BOOL "Enable multiple instances" FORCE) +endif() + +if(CONFIG_OPENTHREAD_NAT64_BORDER_ROUTING) + set(OT_NAT64_BORDER_ROUTING ON CACHE BOOL "Enable border routing NAT64 support" FORCE) +else() + set(OT_NAT64_BORDER_ROUTING OFF CACHE BOOL "Enable border routing NAT64 support" FORCE) +endif() + +if(CONFIG_OPENTHREAD_NAT64_TRANSLATOR) + set(OT_NAT64_TRANSLATOR ON CACHE BOOL "Enable NAT64 translator" FORCE) +else() + set(OT_NAT64_TRANSLATOR OFF CACHE BOOL "Enable NAT64 translator" FORCE) +endif() + +if(CONFIG_OPENTHREAD_NEIGHBOR_DISCOVERY_AGENT) + set(OT_NEIGHBOR_DISCOVERY_AGENT ON CACHE BOOL "Enable neighbor discovery agent support" FORCE) +else() + set(OT_NEIGHBOR_DISCOVERY_AGENT OFF CACHE BOOL "Enable neighbor discovery agent support" FORCE) +endif() + +if(CONFIG_OPENTHREAD_NETDIAG_CLIENT) + set(OT_NETDIAG_CLIENT ON CACHE BOOL "Enable TMF network diagnostics on clients" FORCE) +else() + set(OT_NETDIAG_CLIENT OFF CACHE BOOL "Enable TMF network diagnostics on clients" FORCE) +endif() + +if(CONFIG_OPENTHREAD_NETDATA_PUBLISHER) + set(OT_NETDATA_PUBLISHER ON CACHE BOOL "Enable Thread Network Data publisher" FORCE) +else() + set(OT_NETDATA_PUBLISHER OFF CACHE BOOL "Enable Thread Network Data publisher" FORCE) +endif() + +if(CONFIG_OPENTHREAD_OPERATIONAL_DATASET_AUTO_INIT) + set(OT_OPERATIONAL_DATASET_AUTO_INIT ON CACHE BOOL "Enable operational dataset auto init" FORCE) +else() + set(OT_OPERATIONAL_DATASET_AUTO_INIT OFF CACHE BOOL "Enable operational dataset auto init" FORCE) +endif() + +if(CONFIG_OPENTHREAD_OTNS) + set(OT_OTNS ON CACHE BOOL "Enable OTNS support" FORCE) +else() + set(OT_OTNS OFF CACHE BOOL "Enable OTNS support" FORCE) +endif() + +if(CONFIG_OPENTHREAD_PING_SENDER) + set(OT_PING_SENDER ON CACHE BOOL "Enable ping sender support" FORCE) +else() + set(OT_PING_SENDER OFF CACHE BOOL "Enable ping sender support" FORCE) +endif() + +if(OPENTHREAD_PLATFORM_KEY_REF) + set(OT_PLATFORM_KEY_REF ON CACHE BOOL "Enable platform key reference support" FORCE) +else() + set(OT_PLATFORM_KEY_REF OFF CACHE BOOL "Enable platform key reference support" FORCE) +endif() + +if(CONFIG_OPENTHREAD_PLATFORM_NETIF) + set(OT_PLATFORM_NETIF ON CACHE BOOL "Enable platform netif support" FORCE) +else() + set(OT_PLATFORM_NETIF OFF CACHE BOOL "Enable platform netif support" FORCE) +endif() + +if(CONFIG_OPENTHREAD_PLATFORM_UDP) + set(OT_PLATFORM_UDP ON CACHE BOOL "Enable platform UDP support" FORCE) +else() + set(OT_PLATFORM_UDP OFF CACHE BOOL "Enable platform UDP support" FORCE) endif() if(CONFIG_OPENTHREAD_POWER_SUPPLY) set(OT_POWER_SUPPLY ${CONFIG_OPENTHREAD_POWER_SUPPLY} CACHE STRING "Power supply configuration" FORCE) endif() +if(CONFIG_OPENTHREAD_RADIO_LINK_IEEE_802_15_4_ENABLE) + set(OT_15_4 ON CACHE BOOL "Enable 802.15.4 radio" FORCE) +else() + set(OT_15_4 OFF CACHE BOOL "Enable 802.15.4 radio" FORCE) +endif() + +if(CONFIG_OPENTHREAD_RAW) + set(OT_LINK_RAW ON CACHE BOOL "Enable Link Raw" FORCE) +else() + set(OT_LINK_RAW OFF CACHE BOOL "Enable Link Raw" FORCE) +endif() + +if(CONFIG_OPENTHREAD_REFERENCE_DEVICE) + set(OT_REFERENCE_DEVICE ON CACHE BOOL "Enable Thread Certification Reference Device" FORCE) +else() + set(OT_REFERENCE_DEVICE OFF CACHE BOOL "Enable Thread Certification Reference Device" FORCE) +endif() + +if(CONFIG_OPENTHREAD_SETTINGS_RAM) + set(OT_SETTINGS_RAM ON CACHE BOOL "Enable volatile-only storage of settings" FORCE) +else() + set(OT_SETTINGS_RAM OFF CACHE BOOL "Enable volatile-only storage of settings" FORCE) +endif() + +if(CONFIG_OPENTHREAD_SLAAC) + set(OT_SLAAC ON CACHE BOOL "Enable SLAAC" FORCE) +else() + set(OT_SLAAC OFF CACHE BOOL "Enable SLAAC" FORCE) +endif() + +if(CONFIG_OPENTHREAD_SNTP_CLIENT) + set(OT_SNTP_CLIENT ON CACHE BOOL "Enable SNTP Client support" FORCE) +else() + set(OT_SNTP_CLIENT OFF CACHE BOOL "Enable SNTP Client support" FORCE) +endif() + +if(CONFIG_OPENTHREAD_SRP_CLIENT) + set(OT_SRP_CLIENT ON CACHE BOOL "Enable SRP Client support" FORCE) +else() + set(OT_SRP_CLIENT OFF CACHE BOOL "Enable SRP Client support" FORCE) +endif() + +if(CONFIG_OPENTHREAD_SRP_SERVER) + set(OT_SRP_SERVER ON CACHE BOOL "Enable SRP Server support" FORCE) +else() + set(OT_SRP_SERVER OFF CACHE BOOL "Enable SRP Server support" FORCE) +endif() + +if(CONFIG_OPENTHREAD_TCP_ENABLE) + set(OT_TCP ON CACHE BOOL "Enable TCP support" FORCE) +else() + set(OT_TCP OFF CACHE BOOL "Enable TCP support" FORCE) +endif() + +if(CONFIG_OPENTHREAD_TIME_SYNC) + set(OT_TIME_SYNC ON CACHE BOOL "Enable the time synchronization service feature" FORCE) +else() + set(OT_TIME_SYNC OFF CACHE BOOL "Enable the time synchronization service feature" FORCE) +endif() + +if(CONFIG_OPENTHREAD_TREL) + set(OT_TREL ON CACHE BOOL "Enable TREL radio link for Thread over Infrastructure feature" FORCE) +else() + set(OT_TREL OFF CACHE BOOL "Enable TREL radio link for Thread over Infrastructure feature" FORCE) +endif() + +if(CONFIG_OPENTHREAD_TX_BEACON_PAYLOAD) + set(OT_TX_BEACON_PAYLOAD ON CACHE BOOL "Enable tx beacon payload support" FORCE) +else() + set(OT_TX_BEACON_PAYLOAD OFF CACHE BOOL "Enable tx beacon payload support" FORCE) +endif() + +if(CONFIG_OPENTHREAD_TX_QUEUE_STATISTICS) + set(OT_TX_QUEUE_STATS ON CACHE BOOL "Enable tx queue statistics" FORCE) +else() + set(OT_TX_QUEUE_STATS OFF CACHE BOOL "Enable tx queue statistics" FORCE) +endif() + +if(CONFIG_OPENTHREAD_UDP_FORWARD) + set(OT_UDP_FORWARD ON CACHE BOOL "Enable UDP forward feature" FORCE) +else() + set(OT_UDP_FORWARD OFF CACHE BOOL "Enable UDP forward feature" FORCE) +endif() + +if(CONFIG_OPENTHREAD_UPTIME) + set(OT_UPTIME ON CACHE BOOL "Enable support for tracking OpenThread instance's uptime" FORCE) +else() + set(OT_UPTIME OFF CACHE BOOL "Enable support for tracking OpenThread instance's uptime" FORCE) +endif() + +if(CONFIG_OPENTHREAD_COPROCESSOR_VENDOR_HOOK_SOURCE) + set(OT_NCP_VENDOR_HOOK_SOURCE ${CONFIG_OPENTHREAD_COPROCESSOR_VENDOR_HOOK_SOURCE} CACHE STRING "NCP vendor hook source file name" FORCE) +endif() + set(BUILD_TESTING OFF CACHE BOOL "Disable openthread cmake testing targets" FORCE) # Zephyr logging options From fa282cf9315fbff7646fbcfa6cefe62eeb29638f Mon Sep 17 00:00:00 2001 From: Robert Lubos Date: Tue, 6 Feb 2024 11:07:06 +0100 Subject: [PATCH 3540/3723] Revert "[nrf fromtree] net: openthread: upmerge to `75694d2`" This reverts commit 6aa16dca7035766f29e87ea9f443d1f5d8fa9655. Signed-off-by: Robert Lubos --- modules/openthread/CMakeLists.txt | 6 ------ modules/openthread/Kconfig.features | 6 ------ .../platform/openthread-core-zephyr-config.h | 10 ++++++++++ subsys/net/l2/openthread/Kconfig | 10 ++++++++-- 4 files changed, 18 insertions(+), 14 deletions(-) diff --git a/modules/openthread/CMakeLists.txt b/modules/openthread/CMakeLists.txt index 150039863d9..646b086ef1e 100644 --- a/modules/openthread/CMakeLists.txt +++ b/modules/openthread/CMakeLists.txt @@ -400,12 +400,6 @@ else() set(OT_PING_SENDER OFF CACHE BOOL "Enable ping sender support" FORCE) endif() -if(OPENTHREAD_PLATFORM_KEY_REF) - set(OT_PLATFORM_KEY_REF ON CACHE BOOL "Enable platform key reference support" FORCE) -else() - set(OT_PLATFORM_KEY_REF OFF CACHE BOOL "Enable platform key reference support" FORCE) -endif() - if(CONFIG_OPENTHREAD_PLATFORM_NETIF) set(OT_PLATFORM_NETIF ON CACHE BOOL "Enable platform netif support" FORCE) else() diff --git a/modules/openthread/Kconfig.features b/modules/openthread/Kconfig.features index 952a7853b43..2be5332cde3 100644 --- a/modules/openthread/Kconfig.features +++ b/modules/openthread/Kconfig.features @@ -249,12 +249,6 @@ config OPENTHREAD_OTNS config OPENTHREAD_PING_SENDER bool "Ping sender support" -config OPENTHREAD_PLATFORM_KEY_REF - bool "Platform cryptographic key reference support" - help - Enable usage of cryptographic key references instead of literal keys. - This requires a crypto backend library that supports key references. - config OPENTHREAD_PLATFORM_NETIF bool "Platform netif support" diff --git a/modules/openthread/platform/openthread-core-zephyr-config.h b/modules/openthread/platform/openthread-core-zephyr-config.h index 773cd170f2c..881585e5578 100644 --- a/modules/openthread/platform/openthread-core-zephyr-config.h +++ b/modules/openthread/platform/openthread-core-zephyr-config.h @@ -396,6 +396,16 @@ #define OPENTHREAD_CONFIG_CRYPTO_LIB OPENTHREAD_CONFIG_CRYPTO_LIB_PSA #endif +/** + * @def OPENTHREAD_CONFIG_PLATFORM_KEY_REFERENCES_ENABLE + * + * Set to 1 if you want to enable key reference usage support. + * + */ +#ifdef CONFIG_OPENTHREAD_PLATFORM_KEY_REFERENCES_ENABLE +#define OPENTHREAD_CONFIG_PLATFORM_KEY_REFERENCES_ENABLE 1 +#endif + /** * @def OPENTHREAD_CONFIG_PLATFORM_MAC_KEYS_EXPORTABLE_ENABLE * diff --git a/subsys/net/l2/openthread/Kconfig b/subsys/net/l2/openthread/Kconfig index aa7e03b8204..98113975797 100644 --- a/subsys/net/l2/openthread/Kconfig +++ b/subsys/net/l2/openthread/Kconfig @@ -324,15 +324,21 @@ config OPENTHREAD_MAC_SOFTWARE_CSMA_BACKOFF_ENABLE config OPENTHREAD_CRYPTO_PSA bool "ARM PSA crypto API" depends on MBEDTLS_PSA_CRYPTO_C || BUILD_WITH_TFM - select OPENTHREAD_PLATFORM_KEY_REF + select OPENTHREAD_PLATFORM_KEY_REFERENCES_ENABLE select OPENTHREAD_PLATFORM_KEYS_EXPORTABLE_ENABLE help Enable crypto backend library implementation based on ARM PSA crypto API instead of the default, using mbedTLS. +config OPENTHREAD_PLATFORM_KEY_REFERENCES_ENABLE + bool "Cryptographic key reference support" + help + Enable usage of cryptographic key references instead of literal keys + This requires a crypto backend library that supports key references. + config OPENTHREAD_PLATFORM_KEYS_EXPORTABLE_ENABLE bool "Make MAC keys exportable" - depends on OPENTHREAD_PLATFORM_KEY_REF + depends on OPENTHREAD_PLATFORM_KEY_REFERENCES_ENABLE help Enable the creation of exportable MAC keys in the OpenThread Key Manager. From 87e41f9e922221739627d8a127e53ae48dc862b5 Mon Sep 17 00:00:00 2001 From: Robert Lubos Date: Tue, 6 Feb 2024 11:07:07 +0100 Subject: [PATCH 3541/3723] Revert "[nrf fromtree] drivers: nrf_qspi_nor: Deactivate QSPI peripheral after initialization" This reverts commit 4a043af1d0515aab82ec54ceeae543bb7f27a247. Signed-off-by: Robert Lubos --- drivers/flash/nrf_qspi_nor.c | 4 ---- 1 file changed, 4 deletions(-) diff --git a/drivers/flash/nrf_qspi_nor.c b/drivers/flash/nrf_qspi_nor.c index 0e9d4181418..d6695989857 100644 --- a/drivers/flash/nrf_qspi_nor.c +++ b/drivers/flash/nrf_qspi_nor.c @@ -1090,10 +1090,6 @@ static int qspi_nor_init(const struct device *dev) qspi_clock_div_restore(); - if (!IS_ENABLED(CONFIG_NORDIC_QSPI_NOR_XIP) && nrfx_qspi_init_check()) { - (void)nrfx_qspi_deactivate(); - } - #ifdef CONFIG_PM_DEVICE_RUNTIME int rc2 = pm_device_runtime_enable(dev); From 2b2558cac562e706d944063d80e620357c3f87e3 Mon Sep 17 00:00:00 2001 From: Robert Lubos Date: Tue, 6 Feb 2024 11:07:08 +0100 Subject: [PATCH 3542/3723] Revert "[nrf fromlist] wifi: shell: Log errors for validation" This reverts commit c3be80e41e8271190d4b0eaa4923e28dfe5d6802. Signed-off-by: Robert Lubos --- subsys/net/l2/wifi/wifi_shell.c | 43 +++------------------------------ 1 file changed, 3 insertions(+), 40 deletions(-) diff --git a/subsys/net/l2/wifi/wifi_shell.c b/subsys/net/l2/wifi/wifi_shell.c index f470e700f8c..49459774655 100644 --- a/subsys/net/l2/wifi/wifi_shell.c +++ b/subsys/net/l2/wifi/wifi_shell.c @@ -48,8 +48,6 @@ LOG_MODULE_REGISTER(net_wifi_shell, LOG_LEVEL_INF); NET_EVENT_WIFI_SCAN_RESULT) #endif /* CONFIG_WIFI_MGMT_RAW_SCAN_RESULTS_ONLY */ -#define MAX_BANDS_STR_LEN 64 - static struct { const struct shell *sh; @@ -446,8 +444,6 @@ static int __wifi_args_to_params(size_t argc, char *argv[], int idx = 1; if (argc < 1) { - print(context.sh, SHELL_WARNING, - "SSID not specified\n"); return -EINVAL; } @@ -460,9 +456,6 @@ static int __wifi_args_to_params(size_t argc, char *argv[], params->ssid = argv[0]; params->ssid_length = strlen(params->ssid); if (params->ssid_length > WIFI_SSID_MAX_LEN) { - print(context.sh, SHELL_WARNING, - "SSID too long (max %d characters)\n", - WIFI_SSID_MAX_LEN); return -EINVAL; } @@ -471,11 +464,6 @@ static int __wifi_args_to_params(size_t argc, char *argv[], long channel = strtol(argv[idx], &endptr, 10); if (*endptr != '\0') { - print(context.sh, SHELL_ERROR, - "Failed to parse channel: %s: endp: %s, err: %s\n", - argv[idx], - endptr, - strerror(errno)); return -EINVAL; } @@ -487,23 +475,8 @@ static int __wifi_args_to_params(size_t argc, char *argv[], WIFI_FREQ_BAND_6_GHZ}; uint8_t band; bool found = false; - char bands_str[MAX_BANDS_STR_LEN] = {0}; - size_t offset = 0; for (band = 0; band < ARRAY_SIZE(bands); band++) { - offset += snprintf(bands_str + offset, - sizeof(bands_str) - offset, - "%s%s", - band ? "," : "", - wifi_band_txt(bands[band])); - if (offset >= sizeof(bands_str)) { - print(context.sh, SHELL_ERROR, - "Failed to parse channel: %s: " - "band string too long\n", - argv[idx]); - return -EINVAL; - } - if (wifi_utils_validate_chan(bands[band], channel)) { found = true; @@ -512,10 +485,6 @@ static int __wifi_args_to_params(size_t argc, char *argv[], } if (!found) { - print(context.sh, SHELL_ERROR, - "Invalid channel: %ld, checked bands: %s\n", - channel, - bands_str); return -EINVAL; } @@ -548,9 +517,6 @@ static int __wifi_args_to_params(size_t argc, char *argv[], if (security == WIFI_SECURITY_TYPE_NONE || security == WIFI_SECURITY_TYPE_WPA_PSK) { - print(context.sh, SHELL_ERROR, - "MFP not supported for security type %s\n", - wifi_security_txt(security)); return -EINVAL; } @@ -566,10 +532,6 @@ static int __wifi_args_to_params(size_t argc, char *argv[], params->psk_length > WIFI_PSK_MAX_LEN) || (params->security == WIFI_SECURITY_TYPE_SAE && params->psk_length > WIFI_SAE_PSWD_MAX_LEN)) { - print(context.sh, SHELL_ERROR, - "Invalid PSK length (%d) for security type %s\n", - params->psk_length, - wifi_security_txt(params->security)); return -EINVAL; } } @@ -584,13 +546,13 @@ static int cmd_wifi_connect(const struct shell *sh, size_t argc, struct net_if *iface = net_if_get_first_wifi(); struct wifi_connect_req_params cnx_params = { 0 }; - context.sh = sh; if (__wifi_args_to_params(argc - 1, &argv[1], &cnx_params, WIFI_MODE_INFRA)) { shell_help(sh); return -ENOEXEC; } context.connecting = true; + context.sh = sh; if (net_mgmt(NET_REQUEST_WIFI_CONNECT, iface, &cnx_params, sizeof(struct wifi_connect_req_params))) { @@ -1269,12 +1231,13 @@ static int cmd_wifi_ap_enable(const struct shell *sh, size_t argc, static struct wifi_connect_req_params cnx_params; int ret; - context.sh = sh; if (__wifi_args_to_params(argc - 1, &argv[1], &cnx_params, WIFI_MODE_AP)) { shell_help(sh); return -ENOEXEC; } + context.sh = sh; + k_mutex_init(&wifi_ap_sta_list_lock); ret = net_mgmt(NET_REQUEST_WIFI_AP_ENABLE, iface, &cnx_params, From 972c158247c0ddc568979598485f103877bebc72 Mon Sep 17 00:00:00 2001 From: Robert Lubos Date: Tue, 6 Feb 2024 11:07:08 +0100 Subject: [PATCH 3543/3723] Revert "[nrf fromlist] wifi: shell: Fix the channel extraction" This reverts commit 595c41f2e62df604316f242afd8c65ab828ac299. Signed-off-by: Robert Lubos --- subsys/net/l2/wifi/wifi_shell.c | 10 ++++------ 1 file changed, 4 insertions(+), 6 deletions(-) diff --git a/subsys/net/l2/wifi/wifi_shell.c b/subsys/net/l2/wifi/wifi_shell.c index 49459774655..01a76359702 100644 --- a/subsys/net/l2/wifi/wifi_shell.c +++ b/subsys/net/l2/wifi/wifi_shell.c @@ -461,13 +461,12 @@ static int __wifi_args_to_params(size_t argc, char *argv[], /* Channel (optional: STA, mandatory: AP) */ if ((idx < argc) && (strlen(argv[idx]) <= 3)) { - long channel = strtol(argv[idx], &endptr, 10); - + params->channel = strtol(argv[idx], &endptr, 10); if (*endptr != '\0') { return -EINVAL; } - if (iface_mode == WIFI_MODE_INFRA && channel == 0) { + if (iface_mode == WIFI_MODE_INFRA && params->channel == 0) { params->channel = WIFI_CHANNEL_ANY; } else { const uint8_t bands[] = {WIFI_FREQ_BAND_2_4_GHZ, @@ -478,7 +477,7 @@ static int __wifi_args_to_params(size_t argc, char *argv[], for (band = 0; band < ARRAY_SIZE(bands); band++) { if (wifi_utils_validate_chan(bands[band], - channel)) { + params->channel)) { found = true; break; } @@ -487,9 +486,8 @@ static int __wifi_args_to_params(size_t argc, char *argv[], if (!found) { return -EINVAL; } - - params->channel = channel; } + idx++; } From d0ef48337b12043714f3dd5598aca20d64386a67 Mon Sep 17 00:00:00 2001 From: Robert Lubos Date: Tue, 6 Feb 2024 11:07:09 +0100 Subject: [PATCH 3544/3723] Revert "[nrf fromlist] wifi: shell: Add channel validation" This reverts commit bf61fbcf89eaebefdb91d9bab370446cbd7edccc. Signed-off-by: Robert Lubos --- subsys/net/l2/wifi/wifi_shell.c | 27 ++++----------------------- 1 file changed, 4 insertions(+), 23 deletions(-) diff --git a/subsys/net/l2/wifi/wifi_shell.c b/subsys/net/l2/wifi/wifi_shell.c index 01a76359702..0ab9e884780 100644 --- a/subsys/net/l2/wifi/wifi_shell.c +++ b/subsys/net/l2/wifi/wifi_shell.c @@ -437,8 +437,7 @@ static void wifi_mgmt_event_handler(struct net_mgmt_event_callback *cb, } static int __wifi_args_to_params(size_t argc, char *argv[], - struct wifi_connect_req_params *params, - enum wifi_iface_mode iface_mode) + struct wifi_connect_req_params *params) { char *endptr; int idx = 1; @@ -466,26 +465,8 @@ static int __wifi_args_to_params(size_t argc, char *argv[], return -EINVAL; } - if (iface_mode == WIFI_MODE_INFRA && params->channel == 0) { + if (params->channel == 0U) { params->channel = WIFI_CHANNEL_ANY; - } else { - const uint8_t bands[] = {WIFI_FREQ_BAND_2_4_GHZ, - WIFI_FREQ_BAND_5_GHZ, - WIFI_FREQ_BAND_6_GHZ}; - uint8_t band; - bool found = false; - - for (band = 0; band < ARRAY_SIZE(bands); band++) { - if (wifi_utils_validate_chan(bands[band], - params->channel)) { - found = true; - break; - } - } - - if (!found) { - return -EINVAL; - } } idx++; @@ -544,7 +525,7 @@ static int cmd_wifi_connect(const struct shell *sh, size_t argc, struct net_if *iface = net_if_get_first_wifi(); struct wifi_connect_req_params cnx_params = { 0 }; - if (__wifi_args_to_params(argc - 1, &argv[1], &cnx_params, WIFI_MODE_INFRA)) { + if (__wifi_args_to_params(argc - 1, &argv[1], &cnx_params)) { shell_help(sh); return -ENOEXEC; } @@ -1229,7 +1210,7 @@ static int cmd_wifi_ap_enable(const struct shell *sh, size_t argc, static struct wifi_connect_req_params cnx_params; int ret; - if (__wifi_args_to_params(argc - 1, &argv[1], &cnx_params, WIFI_MODE_AP)) { + if (__wifi_args_to_params(argc - 1, &argv[1], &cnx_params)) { shell_help(sh); return -ENOEXEC; } From f1198e9e35da81e858b6ede9cfd24520846bb35b Mon Sep 17 00:00:00 2001 From: Robert Lubos Date: Tue, 6 Feb 2024 11:07:09 +0100 Subject: [PATCH 3545/3723] Revert "[nrf fromlist] wifi: utils: Move channel helpers to public API" This reverts commit 02ac99c10a16f304298c6f39f5c5724fceda17bf. Signed-off-by: Robert Lubos --- include/zephyr/net/wifi_utils.h | 43 --------------------------------- subsys/net/l2/wifi/wifi_utils.c | 8 +++--- 2 files changed, 4 insertions(+), 47 deletions(-) diff --git a/include/zephyr/net/wifi_utils.h b/include/zephyr/net/wifi_utils.h index 537db787648..c16eef0e5b2 100644 --- a/include/zephyr/net/wifi_utils.h +++ b/include/zephyr/net/wifi_utils.h @@ -103,49 +103,6 @@ int wifi_utils_parse_scan_chan(char *scan_chan_str, struct wifi_band_channel *chan, uint8_t max_channels); - -/** - * @brief Validate a channel against a band. - * - * @param band Band to validate the channel against. - * @param chan Channel to validate. - * - * @retval true if the channel is valid for the band. - * @retval false if the channel is not valid for the band. - */ -bool wifi_utils_validate_chan(uint8_t band, - uint16_t chan); - -/** - * @brief Validate a channel against the 2.4 GHz band. - * - * @param chan Channel to validate. - * - * @retval true if the channel is valid for the band. - * @retval false if the channel is not valid for the band. - */ -bool wifi_utils_validate_chan_2g(uint16_t chan); - -/** - * @brief Validate a channel against the 5 GHz band. - * - * @param chan Channel to validate. - * - * @retval true if the channel is valid for the band. - * @retval false if the channel is not valid for the band. - */ -bool wifi_utils_validate_chan_5g(uint16_t chan); - -/** - * @brief Validate a channel against the 6 GHz band. - * - * @param chan Channel to validate. - * - * @retval true if the channel is valid for the band. - * @retval false if the channel is not valid for the band. - */ -bool wifi_utils_validate_chan_6g(uint16_t chan); - /** * @} */ diff --git a/subsys/net/l2/wifi/wifi_utils.c b/subsys/net/l2/wifi/wifi_utils.c index 76e93fc33e0..52d25d90566 100644 --- a/subsys/net/l2/wifi/wifi_utils.c +++ b/subsys/net/l2/wifi/wifi_utils.c @@ -44,7 +44,7 @@ static enum wifi_frequency_bands wifi_utils_map_band_str_to_idx(char *band_str) } -bool wifi_utils_validate_chan_2g(uint16_t chan) +static bool wifi_utils_validate_chan_2g(uint16_t chan) { if ((chan >= 1) && (chan <= 14)) { return true; @@ -54,7 +54,7 @@ bool wifi_utils_validate_chan_2g(uint16_t chan) } -bool wifi_utils_validate_chan_5g(uint16_t chan) +static bool wifi_utils_validate_chan_5g(uint16_t chan) { uint16_t i; @@ -68,7 +68,7 @@ bool wifi_utils_validate_chan_5g(uint16_t chan) } -bool wifi_utils_validate_chan_6g(uint16_t chan) +static bool wifi_utils_validate_chan_6g(uint16_t chan) { if (((chan >= 1) && (chan <= 233) && (!((chan - 1)%4))) || (chan == 2)) { @@ -79,7 +79,7 @@ bool wifi_utils_validate_chan_6g(uint16_t chan) } -bool wifi_utils_validate_chan(uint8_t band, +static bool wifi_utils_validate_chan(uint8_t band, uint16_t chan) { bool result = false; From 82983e166681d8157bb45fb2be59ec6c3fe70af1 Mon Sep 17 00:00:00 2001 From: Robert Lubos Date: Tue, 6 Feb 2024 11:07:10 +0100 Subject: [PATCH 3546/3723] Revert "[nrf fromlist] wifi: shell: Add a sanity check for MFP" This reverts commit 75b68d8e2ace1632f64e9bdff36d571211ed4a1b. Signed-off-by: Robert Lubos --- subsys/net/l2/wifi/wifi_shell.c | 5 ----- 1 file changed, 5 deletions(-) diff --git a/subsys/net/l2/wifi/wifi_shell.c b/subsys/net/l2/wifi/wifi_shell.c index 0ab9e884780..96ce19e3e5c 100644 --- a/subsys/net/l2/wifi/wifi_shell.c +++ b/subsys/net/l2/wifi/wifi_shell.c @@ -494,11 +494,6 @@ static int __wifi_args_to_params(size_t argc, char *argv[], if (idx < argc) { unsigned int mfp = strtol(argv[idx], &endptr, 10); - if (security == WIFI_SECURITY_TYPE_NONE || - security == WIFI_SECURITY_TYPE_WPA_PSK) { - return -EINVAL; - } - if (mfp <= WIFI_MFP_REQUIRED) { params->mfp = mfp; } From faa20a8d96b976ee5cd279faa24e32c5390691e3 Mon Sep 17 00:00:00 2001 From: Robert Lubos Date: Tue, 6 Feb 2024 11:07:10 +0100 Subject: [PATCH 3547/3723] Revert "[nrf fromlist] wifi: shell: Make channel mandatory for AP" This reverts commit e09a8d4a07e55e1e5666348f0c7b69d9f2b5bab7. Signed-off-by: Robert Lubos --- subsys/net/l2/wifi/wifi_shell.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/subsys/net/l2/wifi/wifi_shell.c b/subsys/net/l2/wifi/wifi_shell.c index 96ce19e3e5c..726ce69b435 100644 --- a/subsys/net/l2/wifi/wifi_shell.c +++ b/subsys/net/l2/wifi/wifi_shell.c @@ -458,7 +458,7 @@ static int __wifi_args_to_params(size_t argc, char *argv[], return -EINVAL; } - /* Channel (optional: STA, mandatory: AP) */ + /* Channel (optional) */ if ((idx < argc) && (strlen(argv[idx]) <= 3)) { params->channel = strtol(argv[idx], &endptr, 10); if (*endptr != '\0') { @@ -1769,14 +1769,14 @@ SHELL_STATIC_SUBCMD_SET_CREATE(wifi_cmd_ap, 1, 0), SHELL_CMD_ARG(enable, NULL, "\"\"\n" - "\n" + "[channel number: 0 means all]\n" "[PSK: valid only for secure SSIDs]\n" "[Security type: valid only for secure SSIDs]\n" "0:None, 1:WPA2-PSK, 2:WPA2-PSK-256, 3:SAE, 4:WAPI, 5:EAP, 6:WEP, 7: WPA-PSK\n" "[MFP (optional: needs security type to be specified)]\n" ": 0:Disable, 1:Optional, 2:Required.\n", cmd_wifi_ap_enable, - 3, 3), + 2, 4), SHELL_CMD_ARG(stations, NULL, "List stations connected to the AP", cmd_wifi_ap_stations, From 489c4f201bd9285abb8b76312a6d9616b1d538fd Mon Sep 17 00:00:00 2001 From: Robert Lubos Date: Tue, 6 Feb 2024 11:07:10 +0100 Subject: [PATCH 3548/3723] Revert "[nrf fromtree] wifi: shell: Fix typo in comparison" This reverts commit cec939280dca0f61b214b0cd1141105b408651b8. Signed-off-by: Robert Lubos --- subsys/net/l2/wifi/wifi_shell.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/subsys/net/l2/wifi/wifi_shell.c b/subsys/net/l2/wifi/wifi_shell.c index 726ce69b435..450b7b00eb5 100644 --- a/subsys/net/l2/wifi/wifi_shell.c +++ b/subsys/net/l2/wifi/wifi_shell.c @@ -920,7 +920,7 @@ static int cmd_wifi_ps_mode(const struct shell *sh, size_t argc, char *argv[]) if (!strncasecmp(argv[1], "legacy", 6)) { params.mode = WIFI_PS_MODE_LEGACY; - } else if (!strncasecmp(argv[1], "WMM", 3)) { + } else if (!strncasecmp(argv[1], "WMM", 4)) { params.mode = WIFI_PS_MODE_WMM; } else { shell_fprintf(sh, SHELL_WARNING, "Invalid PS mode\n"); From dd4a1362ccd2a61cb094843d3a2a199f6f9bc33b Mon Sep 17 00:00:00 2001 From: Robert Lubos Date: Tue, 6 Feb 2024 11:07:10 +0100 Subject: [PATCH 3549/3723] Revert "[nrf fromtree] wifi: shell: Fix missing case sensitivity" This reverts commit 8fe4834f8a7da79703d224f15547011e636c725e. Signed-off-by: Robert Lubos --- subsys/net/l2/wifi/wifi_shell.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/subsys/net/l2/wifi/wifi_shell.c b/subsys/net/l2/wifi/wifi_shell.c index 450b7b00eb5..4f378a5029b 100644 --- a/subsys/net/l2/wifi/wifi_shell.c +++ b/subsys/net/l2/wifi/wifi_shell.c @@ -601,9 +601,9 @@ static int wifi_scan_args_to_params(const struct shell *sh, state = getopt_state_get(); switch (opt) { case 't': - if (!strncasecmp(optarg, "passive", 7)) { + if (!strcmp(optarg, "passive")) { params->scan_type = WIFI_SCAN_TYPE_PASSIVE; - } else if (!strncasecmp(optarg, "active", 6)) { + } else if (!strcmp(optarg, "active")) { params->scan_type = WIFI_SCAN_TYPE_ACTIVE; } else { shell_fprintf(sh, SHELL_ERROR, "Invalid scan type %s\n", optarg); From 03a1b2fd62ddbd274da006a80a4bc31344672483 Mon Sep 17 00:00:00 2001 From: Robert Lubos Date: Tue, 6 Feb 2024 11:07:10 +0100 Subject: [PATCH 3550/3723] Revert "[nrf fromtree] wifi: shell: Use case insensitive comparison" This reverts commit fdb262308db6a867ad2ca650fd17c823fe1c58db. Signed-off-by: Robert Lubos --- subsys/net/l2/wifi/wifi_shell.c | 13 ++++++------- 1 file changed, 6 insertions(+), 7 deletions(-) diff --git a/subsys/net/l2/wifi/wifi_shell.c b/subsys/net/l2/wifi/wifi_shell.c index 4f378a5029b..e1446cceca0 100644 --- a/subsys/net/l2/wifi/wifi_shell.c +++ b/subsys/net/l2/wifi/wifi_shell.c @@ -15,7 +15,6 @@ LOG_MODULE_REGISTER(net_wifi_shell, LOG_LEVEL_INF); #include #include #include -#include #include #include #include @@ -887,9 +886,9 @@ static int cmd_wifi_ps(const struct shell *sh, size_t argc, char *argv[]) return 0; } - if (!strncasecmp(argv[1], "on", 2)) { + if (!strncmp(argv[1], "on", 2)) { params.enabled = WIFI_PS_ENABLED; - } else if (!strncasecmp(argv[1], "off", 3)) { + } else if (!strncmp(argv[1], "off", 3)) { params.enabled = WIFI_PS_DISABLED; } else { shell_fprintf(sh, SHELL_WARNING, "Invalid argument\n"); @@ -918,9 +917,9 @@ static int cmd_wifi_ps_mode(const struct shell *sh, size_t argc, char *argv[]) context.sh = sh; - if (!strncasecmp(argv[1], "legacy", 6)) { + if (!strncmp(argv[1], "legacy", 6)) { params.mode = WIFI_PS_MODE_LEGACY; - } else if (!strncasecmp(argv[1], "WMM", 4)) { + } else if (!strncmp(argv[1], "wmm", 3)) { params.mode = WIFI_PS_MODE_WMM; } else { shell_fprintf(sh, SHELL_WARNING, "Invalid PS mode\n"); @@ -1406,9 +1405,9 @@ static int cmd_wifi_ps_wakeup_mode(const struct shell *sh, size_t argc, char *ar context.sh = sh; - if (!strncasecmp(argv[1], "dtim", 4)) { + if (!strncmp(argv[1], "dtim", 4)) { params.wakeup_mode = WIFI_PS_WAKEUP_MODE_DTIM; - } else if (!strncasecmp(argv[1], "listen_interval", 15)) { + } else if (!strncmp(argv[1], "listen_interval", 15)) { params.wakeup_mode = WIFI_PS_WAKEUP_MODE_LISTEN_INTERVAL; } else { shell_fprintf(sh, SHELL_WARNING, "Invalid argument\n"); From bbe905495ee2a7c826fc7e86eb2cfc078a667496 Mon Sep 17 00:00:00 2001 From: Robert Lubos Date: Tue, 6 Feb 2024 11:07:11 +0100 Subject: [PATCH 3551/3723] Revert "[nrf fromtree] net: lwm2m: add gateway callback to handle prefixed messages" This reverts commit e1a716774ebac8c8fd9ef7baa0b7e3c04d1c9514. Signed-off-by: Robert Lubos --- subsys/net/lib/lwm2m/lwm2m_message_handling.c | 12 +---- subsys/net/lib/lwm2m/lwm2m_message_handling.h | 2 - subsys/net/lib/lwm2m/lwm2m_obj_gateway.c | 52 ------------------- subsys/net/lib/lwm2m/lwm2m_obj_gateway.h | 40 -------------- 4 files changed, 1 insertion(+), 105 deletions(-) diff --git a/subsys/net/lib/lwm2m/lwm2m_message_handling.c b/subsys/net/lib/lwm2m/lwm2m_message_handling.c index 480c64372e8..677879304f8 100644 --- a/subsys/net/lib/lwm2m/lwm2m_message_handling.c +++ b/subsys/net/lib/lwm2m/lwm2m_message_handling.c @@ -46,7 +46,6 @@ LOG_MODULE_REGISTER(LOG_MODULE_NAME); #include "lwm2m_object.h" #include "lwm2m_obj_access_control.h" #include "lwm2m_obj_server.h" -#include "lwm2m_obj_gateway.h" #include "lwm2m_rw_link_format.h" #include "lwm2m_rw_oma_tlv.h" #include "lwm2m_rw_plain_text.h" @@ -480,7 +479,7 @@ void lwm2m_engine_context_init(struct lwm2m_ctx *client_ctx) } /* utility functions */ -int coap_options_to_path(struct coap_option *opt, int options_count, +static int coap_options_to_path(struct coap_option *opt, int options_count, struct lwm2m_obj_path *path) { uint16_t len, @@ -2269,15 +2268,6 @@ static int handle_request(struct coap_packet *request, struct lwm2m_message *msg msg->token = token; } - if (IS_ENABLED(CONFIG_LWM2M_GATEWAY_OBJ_SUPPORT)) { - r = lwm2m_gw_handle_req(msg); - if (r == 0) { - return 0; - } else if (r != -ENOENT) { - goto error; - } - } - /* parse the URL path into components */ r = coap_find_options(msg->in.in_cpkt, COAP_OPTION_URI_PATH, options, ARRAY_SIZE(options)); if (r < 0) { diff --git a/subsys/net/lib/lwm2m/lwm2m_message_handling.h b/subsys/net/lib/lwm2m/lwm2m_message_handling.h index 3ac014b5db8..c41fbbac0ee 100644 --- a/subsys/net/lib/lwm2m/lwm2m_message_handling.h +++ b/subsys/net/lib/lwm2m/lwm2m_message_handling.h @@ -39,8 +39,6 @@ #define NUM_OUTPUT_BLOCK_CONTEXT CONFIG_LWM2M_NUM_OUTPUT_BLOCK_CONTEXT #endif -int coap_options_to_path(struct coap_option *opt, int options_count, - struct lwm2m_obj_path *path); /* LwM2M message functions */ struct lwm2m_message *lwm2m_get_message(struct lwm2m_ctx *client_ctx); struct lwm2m_message *find_msg(struct coap_pending *pending, struct coap_reply *reply); diff --git a/subsys/net/lib/lwm2m/lwm2m_obj_gateway.c b/subsys/net/lib/lwm2m/lwm2m_obj_gateway.c index 5bb12f80f47..711fd5fe127 100644 --- a/subsys/net/lib/lwm2m/lwm2m_obj_gateway.c +++ b/subsys/net/lib/lwm2m/lwm2m_obj_gateway.c @@ -59,7 +59,6 @@ static struct lwm2m_engine_obj_field fields[] = { static struct lwm2m_engine_obj_inst inst[MAX_INSTANCE_COUNT]; static struct lwm2m_engine_res res[MAX_INSTANCE_COUNT][GATEWAY_MAX_ID]; static struct lwm2m_engine_res_inst res_inst[MAX_INSTANCE_COUNT][RESOURCE_INSTANCE_COUNT]; -lwm2m_engine_gateway_msg_cb gateway_msg_cb[MAX_INSTANCE_COUNT]; static int prefix_validation_cb(uint16_t obj_inst_id, uint16_t res_id, uint16_t res_inst_id, uint8_t *data, uint16_t data_len, bool last_block, @@ -147,57 +146,6 @@ static struct lwm2m_engine_obj_inst *lwm2m_gw_create(uint16_t obj_inst_id) return &inst[index]; } -int lwm2m_gw_handle_req(struct lwm2m_message *msg) -{ - struct coap_option options[4]; - int ret; - - ret = coap_find_options(msg->in.in_cpkt, COAP_OPTION_URI_PATH, options, - ARRAY_SIZE(options)); - if (ret < 0) { - return ret; - } - - for (int index = 0; index < MAX_INSTANCE_COUNT; index++) { - /* Skip uninitialized objects */ - if (!inst[index].obj) { - continue; - } - - char *prefix = device_table[index].prefix; - size_t prefix_len = strlen(prefix); - - if (prefix_len != options[0].len) { - continue; - } - if (strncmp(options[0].value, prefix, prefix_len) != 0) { - continue; - } - - if (gateway_msg_cb[index] == NULL) { - return -ENOENT; - } - /* Delete prefix from path*/ - ret = coap_options_to_path(&options[1], ret - 1, &msg->path); - if (ret < 0) { - return ret; - } - return gateway_msg_cb[index](msg); - } - return -ENOENT; -} - -int lwm2m_register_gw_callback(uint16_t obj_inst_id, lwm2m_engine_gateway_msg_cb cb) -{ - for (int index = 0; index < MAX_INSTANCE_COUNT; index++) { - if (inst[index].obj_inst_id == obj_inst_id) { - gateway_msg_cb[index] = cb; - return 0; - } - } - return -ENOENT; -} - static int lwm2m_gw_init(void) { int ret = 0; diff --git a/subsys/net/lib/lwm2m/lwm2m_obj_gateway.h b/subsys/net/lib/lwm2m/lwm2m_obj_gateway.h index 0f7a82af249..597e3de19bc 100644 --- a/subsys/net/lib/lwm2m/lwm2m_obj_gateway.h +++ b/subsys/net/lib/lwm2m/lwm2m_obj_gateway.h @@ -9,8 +9,6 @@ #ifndef __LWM2M_OBJ_GATEWAY__ #define __LWM2M_OBJ_GATEWAY__ -#include - /* LwM2M Gateway resource IDs */ /* clang-format off */ #define LWM2M_GATEWAY_DEVICE_RID 0 @@ -19,42 +17,4 @@ #define LWM2M_GATEWAY_IOT_DEVICE_OBJECTS_RID 3 /* clang-format on */ -/** - * @brief A callback which handles the prefixed messages from the server. - * - * The callback gets triggered each time the prefix in front of a received lwm2m - * msg path matches the prefix set in the LWM2M_GATEWAY_PREFIX_RID buffer. - * - * It must handle the content of the coap message completely. - * In case of success the LwM2M engine will then send the formatted coap message, - * otherwise a coap response code is sent. - * - * Example of returning CoAP response: - * @code{.c} - * lwm2m_init_message(msg); - * // Write CoAP packet to msg->out.out_cpkt - * return 0; - * @endcode - * - * - * @return 0 if msg contains a valid CoAP response. - * @return negative error code otherwise. - */ -typedef int (*lwm2m_engine_gateway_msg_cb)(struct lwm2m_message *msg); -/** - * @brief Register a callback which handles the prefixed messages from the server. - * - * @return 0 on success - * @return -ENOENT if no object instance with obj_inst_id was found - */ -int lwm2m_register_gw_callback(uint16_t obj_inst_id, lwm2m_engine_gateway_msg_cb cb); -/** - * @brief Check if given message is handled by Gateway callback. - * - * @return 0 if msg was handled by Gateawy and contains a valid response. Negative error code - * otherwise. - * @return -ENOENT if this msg was not handled by Gateway object. - */ -int lwm2m_gw_handle_req(struct lwm2m_message *msg); - #endif /* __LWM2M_OBJ_GATEWAY__ */ From cd402082170e9722ac87b7ee2059a52984d21b3c Mon Sep 17 00:00:00 2001 From: Robert Lubos Date: Tue, 6 Feb 2024 11:07:11 +0100 Subject: [PATCH 3552/3723] Revert "[nrf fromtree] tests: net: lwm2m_engine: workaround stack overflow on qemu_x86" This reverts commit 30d13f412fd3adff9f781aa6ff6919fc1ba7c618. Signed-off-by: Robert Lubos --- tests/net/lib/lwm2m/lwm2m_engine/boards/qemu_x86.conf | 1 - 1 file changed, 1 deletion(-) delete mode 100644 tests/net/lib/lwm2m/lwm2m_engine/boards/qemu_x86.conf diff --git a/tests/net/lib/lwm2m/lwm2m_engine/boards/qemu_x86.conf b/tests/net/lib/lwm2m/lwm2m_engine/boards/qemu_x86.conf deleted file mode 100644 index c735e1a8a2d..00000000000 --- a/tests/net/lib/lwm2m/lwm2m_engine/boards/qemu_x86.conf +++ /dev/null @@ -1 +0,0 @@ -CONFIG_TEST_EXTRA_STACK_SIZE=1024 From 2fc9fe830414aff9ea417fc63e87eae39c159f3d Mon Sep 17 00:00:00 2001 From: Robert Lubos Date: Tue, 6 Feb 2024 11:07:11 +0100 Subject: [PATCH 3553/3723] Revert "[nrf fromtree] net: lwm2m: Fix deadlock when calling lwm2m_engine_pause()" This reverts commit 38abd5701f082d0f219ba8e8f27763810d5d5adc. Signed-off-by: Robert Lubos --- subsys/net/lib/lwm2m/lwm2m_engine.c | 11 ++++------- 1 file changed, 4 insertions(+), 7 deletions(-) diff --git a/subsys/net/lib/lwm2m/lwm2m_engine.c b/subsys/net/lib/lwm2m/lwm2m_engine.c index e08bb4ca17e..639f65ea0fa 100644 --- a/subsys/net/lib/lwm2m/lwm2m_engine.c +++ b/subsys/net/lib/lwm2m/lwm2m_engine.c @@ -1259,12 +1259,6 @@ int lwm2m_engine_pause(void) suspend_engine_thread = true; lwm2m_engine_wake_up(); - /* Check if pause requested within a engine thread, a callback for example. */ - if (engine_thread_id == k_current_get()) { - LOG_DBG("Pause requested"); - return 0; - } - while (active_engine_thread) { k_msleep(10); } @@ -1281,7 +1275,10 @@ int lwm2m_engine_resume(void) k_thread_resume(engine_thread_id); lwm2m_engine_wake_up(); - + while (!active_engine_thread) { + k_msleep(10); + } + LOG_INF("LWM2M engine thread resume"); return 0; } From ef36a396d567d0efcf6e12f4f24bd666abcb09ba Mon Sep 17 00:00:00 2001 From: Robert Lubos Date: Tue, 6 Feb 2024 11:07:11 +0100 Subject: [PATCH 3554/3723] Revert "[nrf fromtree] net: lwm2m: Delay triggering registration update" This reverts commit 9029ec9bf830893072ca2825a9704eb8b0169df4. Signed-off-by: Robert Lubos --- subsys/net/lib/lwm2m/lwm2m_rd_client.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/subsys/net/lib/lwm2m/lwm2m_rd_client.c b/subsys/net/lib/lwm2m/lwm2m_rd_client.c index 95b576cb1c6..6b3fbcccc68 100644 --- a/subsys/net/lib/lwm2m/lwm2m_rd_client.c +++ b/subsys/net/lib/lwm2m/lwm2m_rd_client.c @@ -1132,7 +1132,7 @@ static void sm_registration_done(void) if (sm_is_registered() && (client.trigger_update || now >= next_update())) { - set_sm_state_delayed(ENGINE_UPDATE_REGISTRATION, DELAY_FOR_ACK); + set_sm_state(ENGINE_UPDATE_REGISTRATION); } else if (IS_ENABLED(CONFIG_LWM2M_QUEUE_MODE_ENABLED) && (client.engine_state != ENGINE_REGISTRATION_DONE_RX_OFF) && (now >= next_rx_off())) { From 058346c96c8f9a93e2b0c727da1ba757c2127035 Mon Sep 17 00:00:00 2001 From: Robert Lubos Date: Tue, 6 Feb 2024 11:07:12 +0100 Subject: [PATCH 3555/3723] Revert "[nrf fromtree] net: lwm2m: Add transmission state indicator to RX as well" This reverts commit fa2e2446f70fb44dafafa409b03fde40031d3b79. Signed-off-by: Robert Lubos --- subsys/net/lib/lwm2m/lwm2m_engine.c | 72 ++++++++++------------------- 1 file changed, 25 insertions(+), 47 deletions(-) diff --git a/subsys/net/lib/lwm2m/lwm2m_engine.c b/subsys/net/lib/lwm2m/lwm2m_engine.c index 639f65ea0fa..d5a289a111f 100644 --- a/subsys/net/lib/lwm2m/lwm2m_engine.c +++ b/subsys/net/lib/lwm2m/lwm2m_engine.c @@ -630,50 +630,6 @@ static int64_t check_notifications(struct lwm2m_ctx *ctx, const int64_t timestam return next; } -/** - * @brief Check TX queue states as well as number or pending CoAP transmissions. - * - * If all queues are empty and there is no packet we are currently transmitting and no - * CoAP responses (pendings) we are waiting, inform the application by a callback - * that socket is in state LWM2M_SOCKET_STATE_NO_DATA. - * Otherwise, before sending a packet, depending on the state of the queues, inform with - * one of the ONGOING, ONE_RESPONSE or LAST indicators. - * - * @param ctx Client context. - * @param ongoing_tx Current packet to be transmitted or NULL. - */ -static void hint_socket_state(struct lwm2m_ctx *ctx, struct lwm2m_message *ongoing_tx) -{ - if (!ctx->set_socket_state) { - return; - } - -#if defined(CONFIG_LWM2M_QUEUE_MODE_ENABLED) - bool empty = sys_slist_is_empty(&ctx->pending_sends) && - sys_slist_is_empty(&ctx->queued_messages); -#else - bool empty = sys_slist_is_empty(&ctx->pending_sends); -#endif - size_t pendings = coap_pendings_count(ctx->pendings, ARRAY_SIZE(ctx->pendings)); - - if (ongoing_tx) { - /* Check if more than current TX is in pendings list*/ - if (pendings > 1) { - empty = false; - } - - if (!empty) { - ctx->set_socket_state(ctx->sock_fd, LWM2M_SOCKET_STATE_ONGOING); - } else if (ongoing_tx->type == COAP_TYPE_CON) { - ctx->set_socket_state(ctx->sock_fd, LWM2M_SOCKET_STATE_ONE_RESPONSE); - } else { - ctx->set_socket_state(ctx->sock_fd, LWM2M_SOCKET_STATE_LAST); - } - } else if (empty && pendings == 0) { - ctx->set_socket_state(ctx->sock_fd, LWM2M_SOCKET_STATE_NO_DATA); - } -} - static int socket_recv_message(struct lwm2m_ctx *client_ctx) { static uint8_t in_buf[NET_IPV6_MTU]; @@ -728,7 +684,31 @@ static int socket_send_message(struct lwm2m_ctx *ctx) coap_pending_cycle(msg->pending); } - hint_socket_state(ctx, msg); + if (ctx->set_socket_state) { +#if defined(CONFIG_LWM2M_QUEUE_MODE_ENABLED) + bool empty = sys_slist_is_empty(&ctx->pending_sends) && + sys_slist_is_empty(&ctx->queued_messages); +#else + bool empty = sys_slist_is_empty(&ctx->pending_sends); +#endif + if (coap_pendings_count(ctx->pendings, ARRAY_SIZE(ctx->pendings)) > 1) { + empty = false; + } + + if (!empty) { + ctx->set_socket_state(ctx->sock_fd, LWM2M_SOCKET_STATE_ONGOING); + } else { + switch (msg->type) { + case COAP_TYPE_CON: + ctx->set_socket_state(ctx->sock_fd, + LWM2M_SOCKET_STATE_ONE_RESPONSE); + break; + default: + ctx->set_socket_state(ctx->sock_fd, LWM2M_SOCKET_STATE_LAST); + break; + } + } + } rc = zsock_send(msg->ctx->sock_fd, msg->cpkt.data, msg->cpkt.offset, 0); @@ -867,8 +847,6 @@ static void socket_loop(void *p1, void *p2, void *p3) break; } } - - hint_socket_state(sock_ctx[i], NULL); } if (sock_fds[i].revents & ZSOCK_POLLOUT) { From 516baa17d7761c1aea83c998c618826e7a1dbec8 Mon Sep 17 00:00:00 2001 From: Robert Lubos Date: Tue, 6 Feb 2024 11:07:12 +0100 Subject: [PATCH 3556/3723] Revert "[nrf fromtree] net: lwm2m: Deprecate lwm2m_get/set_u64" This reverts commit 3fe5a7ae2f6ef9a4d7e1cdbb99fffe5c1ba66330. Signed-off-by: Robert Lubos --- include/zephyr/net/lwm2m.h | 10 ---------- subsys/net/lib/lwm2m/lwm2m_registry.c | 4 ++-- subsys/net/lib/lwm2m/lwm2m_shell.c | 10 ++++++++++ .../net/lib/lwm2m/lwm2m_registry/src/lwm2m_registry.c | 10 ++++++++++ 4 files changed, 22 insertions(+), 12 deletions(-) diff --git a/include/zephyr/net/lwm2m.h b/include/zephyr/net/lwm2m.h index c643c32f0bf..3fca8bffae3 100644 --- a/include/zephyr/net/lwm2m.h +++ b/include/zephyr/net/lwm2m.h @@ -1009,16 +1009,11 @@ int lwm2m_engine_set_u64(const char *pathstr, uint64_t value); /** * @brief Set resource (instance) value (u64) * - * @deprecated Unsigned 64bit value type does not exits. - * This is internally handled as a int64_t. - * Use lwm2m_set_s64() instead. - * * @param[in] path LwM2M path as a struct * @param[in] value u64 value * * @return 0 for success or negative in case of error. */ -__deprecated int lwm2m_set_u64(const struct lwm2m_obj_path *path, uint64_t value); /** @@ -1340,16 +1335,11 @@ int lwm2m_engine_get_u64(const char *pathstr, uint64_t *value); /** * @brief Get resource (instance) value (u64) * - * @deprecated Unsigned 64bit value type does not exits. - * This is internally handled as a int64_t. - * Use lwm2m_get_s64() instead. - * @param[in] path LwM2M path as a struct * @param[out] value u64 buffer to copy data into * * @return 0 for success or negative in case of error. */ -__deprecated int lwm2m_get_u64(const struct lwm2m_obj_path *path, uint64_t *value); /** diff --git a/subsys/net/lib/lwm2m/lwm2m_registry.c b/subsys/net/lib/lwm2m/lwm2m_registry.c index 1701b7f7412..210c5525756 100644 --- a/subsys/net/lib/lwm2m/lwm2m_registry.c +++ b/subsys/net/lib/lwm2m/lwm2m_registry.c @@ -890,7 +890,7 @@ int lwm2m_engine_set_u64(const char *pathstr, uint64_t value) if (ret < 0) { return ret; } - return lwm2m_set_s64(&path, (int64_t) value); + return lwm2m_set_u64(&path, value); } int lwm2m_set_s8(const struct lwm2m_obj_path *path, int8_t value) @@ -1378,7 +1378,7 @@ int lwm2m_engine_get_u64(const char *pathstr, uint64_t *value) if (ret < 0) { return ret; } - return lwm2m_get_s64(&path, (int64_t *) value); + return lwm2m_get_u64(&path, value); } int lwm2m_get_s8(const struct lwm2m_obj_path *path, int8_t *value) diff --git a/subsys/net/lib/lwm2m/lwm2m_shell.c b/subsys/net/lib/lwm2m/lwm2m_shell.c index aad7dc5d166..a4cedf8cd62 100644 --- a/subsys/net/lib/lwm2m/lwm2m_shell.c +++ b/subsys/net/lib/lwm2m/lwm2m_shell.c @@ -246,6 +246,14 @@ static int cmd_read(const struct shell *sh, size_t argc, char **argv) goto out; } shell_print(sh, "%d\n", temp); + } else if (strcmp(dtype, "-u64") == 0) { + uint64_t temp = 0; + + ret = lwm2m_get_u64(&path, &temp); + if (ret != 0) { + goto out; + } + shell_print(sh, "%lld\n", temp); } else if (strcmp(dtype, "-f") == 0) { double temp = 0; @@ -341,6 +349,8 @@ static int cmd_write(const struct shell *sh, size_t argc, char **argv) ret = lwm2m_set_u16(&path, strtoul(value, &e, 10)); } else if (strcmp(dtype, "-u32") == 0) { ret = lwm2m_set_u32(&path, strtoul(value, &e, 10)); + } else if (strcmp(dtype, "-u64") == 0) { + ret = lwm2m_set_u64(&path, strtoull(value, &e, 10)); } else if (strcmp(dtype, "-b") == 0) { ret = lwm2m_set_bool(&path, strtoul(value, &e, 10)); } else if (strcmp(dtype, "-t") == 0) { diff --git a/tests/net/lib/lwm2m/lwm2m_registry/src/lwm2m_registry.c b/tests/net/lib/lwm2m/lwm2m_registry/src/lwm2m_registry.c index 8e99f666b7f..d4c0a7757a6 100644 --- a/tests/net/lib/lwm2m/lwm2m_registry/src/lwm2m_registry.c +++ b/tests/net/lib/lwm2m/lwm2m_registry/src/lwm2m_registry.c @@ -203,6 +203,16 @@ ZTEST(lwm2m_registry, test_get_set) zassert_equal(strlen(buf), 0); } +ZTEST(lwm2m_registry, test_missing_u64) +{ + /* This data type is missing, so use S64 resource instead */ + uint64_t u64 = 123; + + zassert_equal(lwm2m_set_u64(&LWM2M_OBJ(32768, 0, LWM2M_RES_TYPE_S64), u64), 0); + zassert_equal(lwm2m_get_u64(&LWM2M_OBJ(32768, 0, LWM2M_RES_TYPE_S64), &u64), 0); + zassert_equal(u64, 123); +} + ZTEST(lwm2m_registry, test_temp_sensor) { int ret; From 95bc2902e81e47d9172e9e3e9138406c200e2b59 Mon Sep 17 00:00:00 2001 From: Robert Lubos Date: Tue, 6 Feb 2024 11:07:12 +0100 Subject: [PATCH 3557/3723] Revert "[nrf fromtree] net: lwm2m: Transmission state indications" This reverts commit aced8e7eb6e18ad4c3c12ee810883a3ff298866d. Signed-off-by: Robert Lubos --- include/zephyr/net/lwm2m.h | 24 ------- samples/net/lwm2m_client/overlay-queue.conf | 2 - samples/net/lwm2m_client/src/lwm2m-client.c | 20 ------ subsys/net/lib/lwm2m/lwm2m_engine.c | 35 +--------- tests/net/lib/lwm2m/lwm2m_engine/src/main.c | 72 +------------------- tests/net/lib/lwm2m/lwm2m_engine/src/stubs.c | 2 - tests/net/lib/lwm2m/lwm2m_engine/src/stubs.h | 4 -- 7 files changed, 4 insertions(+), 155 deletions(-) diff --git a/include/zephyr/net/lwm2m.h b/include/zephyr/net/lwm2m.h index 3fca8bffae3..51324f63153 100644 --- a/include/zephyr/net/lwm2m.h +++ b/include/zephyr/net/lwm2m.h @@ -134,22 +134,6 @@ typedef void (*lwm2m_ctx_event_cb_t)(struct lwm2m_ctx *ctx, enum lwm2m_rd_client_event event); -/** - * @brief Different traffic states of the LwM2M socket. - * - * This information can be used to give hints for the network interface - * that can decide what kind of power management should be used. - * - * These hints are given from CoAP layer messages, so usage of DTLS might affect the - * actual number of expected datagrams. - */ -enum lwm2m_socket_states { - LWM2M_SOCKET_STATE_ONGOING, /**< Ongoing traffic is expected. */ - LWM2M_SOCKET_STATE_ONE_RESPONSE, /**< One response is expected for the next message. */ - LWM2M_SOCKET_STATE_LAST, /**< Next message is the last one. */ - LWM2M_SOCKET_STATE_NO_DATA, /**< No more data is expected. */ -}; - /** * @brief LwM2M context structure to maintain information for a single * LwM2M connection. @@ -265,14 +249,6 @@ struct lwm2m_ctx { * copied into the actual resource buffer. */ uint8_t validate_buf[CONFIG_LWM2M_ENGINE_VALIDATION_BUFFER_SIZE]; - - /** - * Callback to indicate transmission states. - * Client application may request LwM2M engine to indicate hints about - * transmission states and use that information to control various power - * saving modes. - */ - void (*set_socket_state)(int fd, enum lwm2m_socket_states state); }; /** diff --git a/samples/net/lwm2m_client/overlay-queue.conf b/samples/net/lwm2m_client/overlay-queue.conf index 946c0fbab67..1adc9eda5ec 100644 --- a/samples/net/lwm2m_client/overlay-queue.conf +++ b/samples/net/lwm2m_client/overlay-queue.conf @@ -1,7 +1,5 @@ CONFIG_LWM2M_QUEUE_MODE_ENABLED=y CONFIG_LWM2M_QUEUE_MODE_UPTIME=20 -CONFIG_LWM2M_RD_CLIENT_STOP_POLLING_AT_IDLE=y - # Default lifetime is 1 day CONFIG_LWM2M_ENGINE_DEFAULT_LIFETIME=86400 # Send update once an hour diff --git a/samples/net/lwm2m_client/src/lwm2m-client.c b/samples/net/lwm2m_client/src/lwm2m-client.c index 2e9792e51ea..c610f1ad8dd 100644 --- a/samples/net/lwm2m_client/src/lwm2m-client.c +++ b/samples/net/lwm2m_client/src/lwm2m-client.c @@ -253,25 +253,6 @@ static void rd_client_event(struct lwm2m_ctx *client, } } -static void socket_state(int fd, enum lwm2m_socket_states state) -{ - (void) fd; - switch (state) { - case LWM2M_SOCKET_STATE_ONGOING: - LOG_DBG("LWM2M_SOCKET_STATE_ONGOING"); - break; - case LWM2M_SOCKET_STATE_ONE_RESPONSE: - LOG_DBG("LWM2M_SOCKET_STATE_ONE_RESPONSE"); - break; - case LWM2M_SOCKET_STATE_LAST: - LOG_DBG("LWM2M_SOCKET_STATE_LAST"); - break; - case LWM2M_SOCKET_STATE_NO_DATA: - LOG_DBG("LWM2M_SOCKET_STATE_NO_DATA"); - break; - } -} - static void observe_cb(enum lwm2m_observe_event event, struct lwm2m_obj_path *path, void *user_data) { @@ -386,7 +367,6 @@ int main(void) #if defined(CONFIG_LWM2M_DTLS_SUPPORT) client_ctx.tls_tag = CONFIG_LWM2M_APP_TLS_TAG; #endif - client_ctx.set_socket_state = socket_state; /* client_ctx.sec_obj_inst is 0 as a starting point */ lwm2m_rd_client_start(&client_ctx, endpoint, flags, rd_client_event, observe_cb); diff --git a/subsys/net/lib/lwm2m/lwm2m_engine.c b/subsys/net/lib/lwm2m/lwm2m_engine.c index d5a289a111f..85a428eeb5d 100644 --- a/subsys/net/lib/lwm2m/lwm2m_engine.c +++ b/subsys/net/lib/lwm2m/lwm2m_engine.c @@ -197,11 +197,6 @@ int lwm2m_socket_suspend(struct lwm2m_ctx *client_ctx) lwm2m_close_socket(client_ctx); /* store back the socket handle */ client_ctx->sock_fd = socket_temp_id; - - if (client_ctx->set_socket_state) { - client_ctx->set_socket_state(client_ctx->sock_fd, - LWM2M_SOCKET_STATE_NO_DATA); - } } return ret; @@ -664,10 +659,10 @@ static int socket_recv_message(struct lwm2m_ctx *client_ctx) return 0; } -static int socket_send_message(struct lwm2m_ctx *ctx) +static int socket_send_message(struct lwm2m_ctx *client_ctx) { int rc; - sys_snode_t *msg_node = sys_slist_get(&ctx->pending_sends); + sys_snode_t *msg_node = sys_slist_get(&client_ctx->pending_sends); struct lwm2m_message *msg; if (!msg_node) { @@ -684,32 +679,6 @@ static int socket_send_message(struct lwm2m_ctx *ctx) coap_pending_cycle(msg->pending); } - if (ctx->set_socket_state) { -#if defined(CONFIG_LWM2M_QUEUE_MODE_ENABLED) - bool empty = sys_slist_is_empty(&ctx->pending_sends) && - sys_slist_is_empty(&ctx->queued_messages); -#else - bool empty = sys_slist_is_empty(&ctx->pending_sends); -#endif - if (coap_pendings_count(ctx->pendings, ARRAY_SIZE(ctx->pendings)) > 1) { - empty = false; - } - - if (!empty) { - ctx->set_socket_state(ctx->sock_fd, LWM2M_SOCKET_STATE_ONGOING); - } else { - switch (msg->type) { - case COAP_TYPE_CON: - ctx->set_socket_state(ctx->sock_fd, - LWM2M_SOCKET_STATE_ONE_RESPONSE); - break; - default: - ctx->set_socket_state(ctx->sock_fd, LWM2M_SOCKET_STATE_LAST); - break; - } - } - } - rc = zsock_send(msg->ctx->sock_fd, msg->cpkt.data, msg->cpkt.offset, 0); if (rc < 0) { diff --git a/tests/net/lib/lwm2m/lwm2m_engine/src/main.c b/tests/net/lib/lwm2m/lwm2m_engine/src/main.c index 5d80f5d1049..ed26380eccd 100644 --- a/tests/net/lib/lwm2m/lwm2m_engine/src/main.c +++ b/tests/net/lib/lwm2m/lwm2m_engine/src/main.c @@ -13,11 +13,10 @@ #include "lwm2m_rd_client.h" #include "stubs.h" -#if defined(CONFIG_NATIVE_SIM_SLOWDOWN_TO_REAL_TIME) +#if defined(CONFIG_NATIVE_POSIX_SLOWDOWN_TO_REAL_TIME) #include "timer_model.h" #endif -#define LOG_LEVEL LOG_LEVEL_DBG LOG_MODULE_REGISTER(lwm2m_engine_test); DEFINE_FFF_GLOBALS; @@ -68,7 +67,7 @@ static void test_service(struct k_work *work) static void setup(void *data) { -#if defined(CONFIG_NATIVE_SIM_SLOWDOWN_TO_REAL_TIME) +#if defined(CONFIG_NATIVE_POSIX_SLOWDOWN_TO_REAL_TIME) /* It is enough that some slow-down is happening on sleeps, it does not have to be * real time */ @@ -468,70 +467,3 @@ ZTEST(lwm2m_engine, test_security) zassert_equal(tls_credential_add_fake.arg1_history[2], TLS_CREDENTIAL_CA_CERTIFICATE); zassert_equal(lwm2m_engine_stop(&ctx), 0); } - -static enum lwm2m_socket_states last_state; - -static void socket_state(int fd, enum lwm2m_socket_states state) -{ - (void) fd; - last_state = state; -} - -ZTEST(lwm2m_engine, test_socket_state) -{ - int ret; - struct lwm2m_ctx ctx = { - .remote_addr.sa_family = AF_INET, - .sock_fd = -1, - .set_socket_state = socket_state, - }; - struct lwm2m_message msg1 = { - .ctx = &ctx, - .type = COAP_TYPE_CON, - }; - struct lwm2m_message msg2 = msg1; - struct lwm2m_message ack = { - .ctx = &ctx, - .type = COAP_TYPE_ACK, - }; - - sys_slist_init(&ctx.pending_sends); - ret = lwm2m_engine_start(&ctx); - zassert_equal(ret, 0); - - /* One confimable in queue, should cause ONE_RESPONSE status */ - coap_pendings_count_fake.return_val = 1; - sys_slist_append(&ctx.pending_sends, &msg1.node); - set_socket_events(ZSOCK_POLLOUT); - k_sleep(K_MSEC(100)); - zassert_equal(last_state, LWM2M_SOCKET_STATE_ONE_RESPONSE); - - /* More than one messages in queue, not empty, should cause ONGOING */ - coap_pendings_count_fake.return_val = 2; - sys_slist_append(&ctx.pending_sends, &msg1.node); - sys_slist_append(&ctx.pending_sends, &msg2.node); - set_socket_events(ZSOCK_POLLOUT); - k_sleep(K_MSEC(100)); - zassert_equal(last_state, LWM2M_SOCKET_STATE_ONGOING); - - /* Last out, while waiting for ACK to both, should still cause ONGOING */ - coap_pendings_count_fake.return_val = 2; - set_socket_events(ZSOCK_POLLOUT); - k_sleep(K_MSEC(100)); - zassert_equal(last_state, LWM2M_SOCKET_STATE_ONGOING); - - /* Only one Ack transmiting, nothing expected back -> LAST */ - coap_pendings_count_fake.return_val = 0; - sys_slist_append(&ctx.pending_sends, &ack.node); - set_socket_events(ZSOCK_POLLOUT); - k_sleep(K_MSEC(100)); - zassert_equal(last_state, LWM2M_SOCKET_STATE_LAST); - - /* Socket suspended (as in QUEUE_RX_OFF), should cause NO_DATA */ - ret = lwm2m_socket_suspend(&ctx); - zassert_equal(ret, 0); - zassert_equal(last_state, LWM2M_SOCKET_STATE_NO_DATA); - - ret = lwm2m_engine_stop(&ctx); - zassert_equal(ret, 0); -} diff --git a/tests/net/lib/lwm2m/lwm2m_engine/src/stubs.c b/tests/net/lib/lwm2m/lwm2m_engine/src/stubs.c index 0958d75a54a..5db155f1e29 100644 --- a/tests/net/lib/lwm2m/lwm2m_engine/src/stubs.c +++ b/tests/net/lib/lwm2m/lwm2m_engine/src/stubs.c @@ -19,7 +19,6 @@ DEFINE_FAKE_VALUE_FUNC(int, lwm2m_send_message_async, struct lwm2m_message *); DEFINE_FAKE_VOID_FUNC(lwm2m_registry_lock); DEFINE_FAKE_VOID_FUNC(lwm2m_registry_unlock); DEFINE_FAKE_VALUE_FUNC(bool, coap_pending_cycle, struct coap_pending *); -DEFINE_FAKE_VALUE_FUNC(size_t, coap_pendings_count, struct coap_pending *, size_t); DEFINE_FAKE_VALUE_FUNC(int, generate_notify_message, struct lwm2m_ctx *, struct observe_node *, void *); DEFINE_FAKE_VALUE_FUNC(int64_t, engine_observe_shedule_next_event, struct observe_node *, uint16_t, @@ -42,7 +41,6 @@ DEFINE_FAKE_VALUE_FUNC(int, lwm2m_delete_obj_inst, uint16_t, uint16_t); DEFINE_FAKE_VOID_FUNC(lwm2m_clear_block_contexts); DEFINE_FAKE_VALUE_FUNC(int, lwm2m_security_mode, struct lwm2m_ctx *); DEFINE_FAKE_VALUE_FUNC(int, z_impl_zsock_setsockopt, int, int, int, const void *, socklen_t); -DEFINE_FAKE_VOID_FUNC(engine_update_tx_time); static sys_slist_t obs_obj_path_list = SYS_SLIST_STATIC_INIT(&obs_obj_path_list); sys_slist_t *lwm2m_obs_obj_path_list(void) diff --git a/tests/net/lib/lwm2m/lwm2m_engine/src/stubs.h b/tests/net/lib/lwm2m/lwm2m_engine/src/stubs.h index 67c4cde883d..7b8ca481f85 100644 --- a/tests/net/lib/lwm2m/lwm2m_engine/src/stubs.h +++ b/tests/net/lib/lwm2m/lwm2m_engine/src/stubs.h @@ -28,7 +28,6 @@ DECLARE_FAKE_VALUE_FUNC(int, lwm2m_rd_client_resume); DECLARE_FAKE_VALUE_FUNC(struct lwm2m_message *, find_msg, struct coap_pending *, struct coap_reply *); DECLARE_FAKE_VOID_FUNC(coap_pending_clear, struct coap_pending *); -DECLARE_FAKE_VALUE_FUNC(size_t, coap_pendings_count, struct coap_pending *, size_t); DECLARE_FAKE_VOID_FUNC(lwm2m_reset_message, struct lwm2m_message *, bool); DECLARE_FAKE_VALUE_FUNC(int, lwm2m_send_message_async, struct lwm2m_message *); DECLARE_FAKE_VOID_FUNC(lwm2m_registry_lock); @@ -57,7 +56,6 @@ DECLARE_FAKE_VOID_FUNC(lwm2m_clear_block_contexts); DECLARE_FAKE_VALUE_FUNC(int, z_impl_zsock_connect, int, const struct sockaddr *, socklen_t); DECLARE_FAKE_VALUE_FUNC(int, lwm2m_security_mode, struct lwm2m_ctx *); DECLARE_FAKE_VALUE_FUNC(int, z_impl_zsock_setsockopt, int, int, int, const void *, socklen_t); -DECLARE_FAKE_VOID_FUNC(engine_update_tx_time); #define DO_FOREACH_FAKE(FUNC) \ do { \ @@ -65,7 +63,6 @@ DECLARE_FAKE_VOID_FUNC(engine_update_tx_time); FUNC(lwm2m_rd_client_resume) \ FUNC(find_msg) \ FUNC(coap_pending_clear) \ - FUNC(coap_pendings_count) \ FUNC(lwm2m_reset_message) \ FUNC(lwm2m_send_message_async) \ FUNC(lwm2m_registry_lock) \ @@ -88,7 +85,6 @@ DECLARE_FAKE_VOID_FUNC(engine_update_tx_time); FUNC(z_impl_zsock_connect) \ FUNC(lwm2m_security_mode) \ FUNC(z_impl_zsock_setsockopt) \ - FUNC(engine_update_tx_time) \ } while (0) #endif /* STUBS_H */ From 73f42ce74a51658d0f1e89807ec4ecf7084e4d0a Mon Sep 17 00:00:00 2001 From: Robert Lubos Date: Tue, 6 Feb 2024 11:07:12 +0100 Subject: [PATCH 3558/3723] Revert "[nrf fromtree] net: lwm2m: Update TX timestamp on zsock_send()" This reverts commit c431117e0aeb2ae0e62bbe38af41480cc9730b3f. Signed-off-by: Robert Lubos --- subsys/net/lib/lwm2m/lwm2m_engine.c | 2 -- 1 file changed, 2 deletions(-) diff --git a/subsys/net/lib/lwm2m/lwm2m_engine.c b/subsys/net/lib/lwm2m/lwm2m_engine.c index 85a428eeb5d..959d07419d3 100644 --- a/subsys/net/lib/lwm2m/lwm2m_engine.c +++ b/subsys/net/lib/lwm2m/lwm2m_engine.c @@ -684,8 +684,6 @@ static int socket_send_message(struct lwm2m_ctx *client_ctx) if (rc < 0) { LOG_ERR("Failed to send packet, err %d", errno); rc = -errno; - } else { - engine_update_tx_time(); } if (msg->type != COAP_TYPE_CON) { From 1b96d0a55e06cefeedb3f32e3c717c1a7a944c50 Mon Sep 17 00:00:00 2001 From: Robert Lubos Date: Tue, 6 Feb 2024 11:07:12 +0100 Subject: [PATCH 3559/3723] Revert "[nrf fromtree] net: coap: Add API to count number of pending requests" This reverts commit b03f75da925a56c6b939328dcc1130ed7f9046f5. Signed-off-by: Robert Lubos --- include/zephyr/net/coap.h | 9 --------- subsys/net/lib/coap/coap.c | 13 ------------- 2 files changed, 22 deletions(-) diff --git a/include/zephyr/net/coap.h b/include/zephyr/net/coap.h index cd57c560bee..e303d5c8ad3 100644 --- a/include/zephyr/net/coap.h +++ b/include/zephyr/net/coap.h @@ -1112,15 +1112,6 @@ void coap_pending_clear(struct coap_pending *pending); */ void coap_pendings_clear(struct coap_pending *pendings, size_t len); -/** - * @brief Count number of pending requests. - * - * @param len Number of elements in array. - * @param pendings Array of pending requests. - * @return count of elements where timeout is not zero. - */ -size_t coap_pendings_count(struct coap_pending *pendings, size_t len); - /** * @brief Cancels awaiting for this reply, so it becomes available * again. User responsibility to free the memory associated with data. diff --git a/subsys/net/lib/coap/coap.c b/subsys/net/lib/coap/coap.c index d22ee29bea7..bfb643a8e8c 100644 --- a/subsys/net/lib/coap/coap.c +++ b/subsys/net/lib/coap/coap.c @@ -1734,19 +1734,6 @@ void coap_pendings_clear(struct coap_pending *pendings, size_t len) } } -size_t coap_pendings_count(struct coap_pending *pendings, size_t len) -{ - struct coap_pending *p = pendings; - size_t c = 0; - - for (size_t i = 0; i < len && p; i++, p++) { - if (p->timeout) { - c++; - } - } - return c; -} - /* Reordering according to RFC7641 section 3.4 but without timestamp comparison */ static inline bool is_newer(int v1, int v2) { From e92977d0239fca75db489ecbc4e3619b9097c79f Mon Sep 17 00:00:00 2001 From: Robert Lubos Date: Tue, 6 Feb 2024 11:07:12 +0100 Subject: [PATCH 3560/3723] Revert "[nrf fromtree] doc: migration-guide: 3.6: Add CoAP service send functions update." This reverts commit a3324c83c81941b2a8ddea05ffbb002ac5085583. Signed-off-by: Robert Lubos --- doc/releases/migration-guide-3.6.rst | 4 ---- 1 file changed, 4 deletions(-) diff --git a/doc/releases/migration-guide-3.6.rst b/doc/releases/migration-guide-3.6.rst index eeac0a89b75..27567c3c052 100644 --- a/doc/releases/migration-guide-3.6.rst +++ b/doc/releases/migration-guide-3.6.rst @@ -160,10 +160,6 @@ Networking use default values. (:github:`66482`) -* The CoAP public API functions :c:func:`coap_service_send` and :c:func:`coap_resource_send` have - changed. An additional parameter pointer to :c:struct:`coap_transmission_parameters` has been - added. It is safe to pass a NULL pointer to use default values. (:github:`66540`) - * The IGMP multicast library now supports IGMPv3. This results in a minor change to the existing api. The :c:func:`net_ipv4_igmp_join` now takes an additional argument of the type ``const struct igmp_param *param``. This allows IGMPv3 to exclude/include certain groups of From 362e81c634372626d441f40e6660b651d2291516 Mon Sep 17 00:00:00 2001 From: Robert Lubos Date: Tue, 6 Feb 2024 11:07:13 +0100 Subject: [PATCH 3561/3723] Revert "[nrf fromtree] net: lib: coap: Use coap_transmission_parameters in coap_server" This reverts commit ab3e1338b6df45aae5bb77faff8aaeab2e26950b. Signed-off-by: Robert Lubos --- .../networking/api/coap_server.rst | 4 ++-- include/zephyr/net/coap_service.h | 8 ++------ samples/net/sockets/coap_server/src/core.c | 2 +- samples/net/sockets/coap_server/src/large.c | 6 +++--- .../sockets/coap_server/src/location_query.c | 2 +- samples/net/sockets/coap_server/src/observer.c | 2 +- samples/net/sockets/coap_server/src/query.c | 2 +- samples/net/sockets/coap_server/src/separate.c | 4 ++-- samples/net/sockets/coap_server/src/test.c | 8 ++++---- subsys/net/lib/coap/Kconfig | 6 ++++++ subsys/net/lib/coap/coap_server.c | 18 ++++++++++-------- 11 files changed, 33 insertions(+), 29 deletions(-) diff --git a/doc/connectivity/networking/api/coap_server.rst b/doc/connectivity/networking/api/coap_server.rst index bd53630ad6c..eb816665f41 100644 --- a/doc/connectivity/networking/api/coap_server.rst +++ b/doc/connectivity/networking/api/coap_server.rst @@ -97,7 +97,7 @@ The following is an example of a CoAP resource registered with our service: coap_packet_append_payload(&response, (uint8_t *)msg, sizeof(msg)); /* Send to response back to the client */ - return coap_resource_send(resource, &response, addr, addr_len, NULL); + return coap_resource_send(resource, &response, addr, addr_len); } static int my_put(struct coap_resource *resource, struct coap_packet *request, @@ -189,7 +189,7 @@ and send state updates. An example using a temperature sensor can look like: coap_packet_append_payload_marker(&response); coap_packet_append_payload(&response, (uint8_t *)payload, strlen(payload)); - return coap_resource_send(resource, &response, addr, addr_len, NULL); + return coap_resource_send(resource, &response, addr, addr_len); } static int temp_get(struct coap_resource *resource, struct coap_packet *request, diff --git a/include/zephyr/net/coap_service.h b/include/zephyr/net/coap_service.h index b894fecf519..6f038ce61e1 100644 --- a/include/zephyr/net/coap_service.h +++ b/include/zephyr/net/coap_service.h @@ -235,12 +235,10 @@ int coap_service_is_running(const struct coap_service *service); * @param cpkt CoAP Packet to send * @param addr Peer address * @param addr_len Peer address length - * @param params Pointer to transmission parameters structure or NULL to use default values. * @return 0 in case of success or negative in case of error. */ int coap_service_send(const struct coap_service *service, const struct coap_packet *cpkt, - const struct sockaddr *addr, socklen_t addr_len, - const struct coap_transmission_parameters *params); + const struct sockaddr *addr, socklen_t addr_len); /** * @brief Send a CoAP message from the provided @p resource . @@ -251,12 +249,10 @@ int coap_service_send(const struct coap_service *service, const struct coap_pack * @param cpkt CoAP Packet to send * @param addr Peer address * @param addr_len Peer address length - * @param params Pointer to transmission parameters structure or NULL to use default values. * @return 0 in case of success or negative in case of error. */ int coap_resource_send(const struct coap_resource *resource, const struct coap_packet *cpkt, - const struct sockaddr *addr, socklen_t addr_len, - const struct coap_transmission_parameters *params); + const struct sockaddr *addr, socklen_t addr_len); /** * @brief Parse a CoAP observe request for the provided @p resource . diff --git a/samples/net/sockets/coap_server/src/core.c b/samples/net/sockets/coap_server/src/core.c index 00f4adb4d34..276ab0d5de1 100644 --- a/samples/net/sockets/coap_server/src/core.c +++ b/samples/net/sockets/coap_server/src/core.c @@ -45,7 +45,7 @@ static int core_get(struct coap_resource *resource, return r; } - r = coap_resource_send(resource, &response, addr, addr_len, NULL); + r = coap_resource_send(resource, &response, addr, addr_len); return r; } diff --git a/samples/net/sockets/coap_server/src/large.c b/samples/net/sockets/coap_server/src/large.c index 8656a5b53b1..28a3eebe099 100644 --- a/samples/net/sockets/coap_server/src/large.c +++ b/samples/net/sockets/coap_server/src/large.c @@ -87,7 +87,7 @@ static int large_get(struct coap_resource *resource, memset(&ctx, 0, sizeof(ctx)); } - r = coap_resource_send(resource, &response, addr, addr_len, NULL); + r = coap_resource_send(resource, &response, addr, addr_len); return r; } @@ -167,7 +167,7 @@ static int large_update_put(struct coap_resource *resource, return r; } - r = coap_resource_send(resource, &response, addr, addr_len, NULL); + r = coap_resource_send(resource, &response, addr, addr_len); return r; } @@ -239,7 +239,7 @@ static int large_create_post(struct coap_resource *resource, return r; } - r = coap_resource_send(resource, &response, addr, addr_len, NULL); + r = coap_resource_send(resource, &response, addr, addr_len); return r; } diff --git a/samples/net/sockets/coap_server/src/location_query.c b/samples/net/sockets/coap_server/src/location_query.c index bce4eb67b86..b13079bc456 100644 --- a/samples/net/sockets/coap_server/src/location_query.c +++ b/samples/net/sockets/coap_server/src/location_query.c @@ -59,7 +59,7 @@ static int location_query_post(struct coap_resource *resource, } } - r = coap_resource_send(resource, &response, addr, addr_len, NULL); + r = coap_resource_send(resource, &response, addr, addr_len); return r; } diff --git a/samples/net/sockets/coap_server/src/observer.c b/samples/net/sockets/coap_server/src/observer.c index 8a14d316c61..6d39536e232 100644 --- a/samples/net/sockets/coap_server/src/observer.c +++ b/samples/net/sockets/coap_server/src/observer.c @@ -80,7 +80,7 @@ static int send_notification_packet(struct coap_resource *resource, k_work_reschedule(&obs_work, K_SECONDS(5)); - r = coap_resource_send(resource, &response, addr, addr_len, NULL); + r = coap_resource_send(resource, &response, addr, addr_len); return r; } diff --git a/samples/net/sockets/coap_server/src/query.c b/samples/net/sockets/coap_server/src/query.c index 95272189d9c..10479b1e6f1 100644 --- a/samples/net/sockets/coap_server/src/query.c +++ b/samples/net/sockets/coap_server/src/query.c @@ -89,7 +89,7 @@ static int query_get(struct coap_resource *resource, return r; } - r = coap_resource_send(resource, &response, addr, addr_len, NULL); + r = coap_resource_send(resource, &response, addr, addr_len); return r; } diff --git a/samples/net/sockets/coap_server/src/separate.c b/samples/net/sockets/coap_server/src/separate.c index 68bba0bb473..c3f6f6c256e 100644 --- a/samples/net/sockets/coap_server/src/separate.c +++ b/samples/net/sockets/coap_server/src/separate.c @@ -43,7 +43,7 @@ static int separate_get(struct coap_resource *resource, return r; } - r = coap_resource_send(resource, &response, addr, addr_len, NULL); + r = coap_resource_send(resource, &response, addr, addr_len); if (r < 0) { return r; } @@ -86,7 +86,7 @@ static int separate_get(struct coap_resource *resource, return r; } - r = coap_resource_send(resource, &response, addr, addr_len, NULL); + r = coap_resource_send(resource, &response, addr, addr_len); return r; } diff --git a/samples/net/sockets/coap_server/src/test.c b/samples/net/sockets/coap_server/src/test.c index 52885b31a5d..aa496a125b1 100644 --- a/samples/net/sockets/coap_server/src/test.c +++ b/samples/net/sockets/coap_server/src/test.c @@ -73,7 +73,7 @@ static int piggyback_get(struct coap_resource *resource, return r; } - r = coap_resource_send(resource, &response, addr, addr_len, NULL); + r = coap_resource_send(resource, &response, addr, addr_len); return r; } @@ -113,7 +113,7 @@ static int test_del(struct coap_resource *resource, return r; } - r = coap_resource_send(resource, &response, addr, addr_len, NULL); + r = coap_resource_send(resource, &response, addr, addr_len); return r; } @@ -160,7 +160,7 @@ static int test_put(struct coap_resource *resource, return r; } - r = coap_resource_send(resource, &response, addr, addr_len, NULL); + r = coap_resource_send(resource, &response, addr, addr_len); return r; } @@ -221,7 +221,7 @@ static int test_post(struct coap_resource *resource, } } - r = coap_resource_send(resource, &response, addr, addr_len, NULL); + r = coap_resource_send(resource, &response, addr, addr_len); return r; } diff --git a/subsys/net/lib/coap/Kconfig b/subsys/net/lib/coap/Kconfig index 63396bb0518..f4d002d0c5d 100644 --- a/subsys/net/lib/coap/Kconfig +++ b/subsys/net/lib/coap/Kconfig @@ -202,6 +202,12 @@ config COAP_SERVICE_PENDING_MESSAGES help Maximum number of pending CoAP messages to retransmit per active service. +config COAP_SERVICE_PENDING_RETRANSMITS + int "CoAP retransmit count" + default 2 + help + Maximum number of retries to send a pending message. + config COAP_SERVICE_OBSERVERS int "CoAP service observers" default 3 diff --git a/subsys/net/lib/coap/coap_server.c b/subsys/net/lib/coap/coap_server.c index 28d5b8de47f..66e5dcbc32c 100644 --- a/subsys/net/lib/coap/coap_server.c +++ b/subsys/net/lib/coap/coap_server.c @@ -215,7 +215,7 @@ static int coap_server_process(int sock_fd) goto unlock; } - ret = coap_service_send(service, &response, &client_addr, client_addr_len, NULL); + ret = coap_service_send(service, &response, &client_addr, client_addr_len); } else { ret = coap_handle_request_len(&request, service->res_begin, COAP_SERVICE_RESOURCE_COUNT(service), @@ -246,7 +246,7 @@ static int coap_server_process(int sock_fd) goto unlock; } - ret = coap_service_send(service, &ack, &client_addr, client_addr_len, NULL); + ret = coap_service_send(service, &ack, &client_addr, client_addr_len); } } @@ -521,8 +521,7 @@ int coap_service_is_running(const struct coap_service *service) } int coap_service_send(const struct coap_service *service, const struct coap_packet *cpkt, - const struct sockaddr *addr, socklen_t addr_len, - const struct coap_transmission_parameters *params) + const struct sockaddr *addr, socklen_t addr_len) { int ret; @@ -543,6 +542,8 @@ int coap_service_send(const struct coap_service *service, const struct coap_pack * try to send. */ if (coap_header_get_type(cpkt) == COAP_TYPE_CON) { + struct coap_transmission_parameters params; + struct coap_pending *pending = coap_pending_next_unused(service->data->pending, MAX_PENDINGS); @@ -551,7 +552,9 @@ int coap_service_send(const struct coap_service *service, const struct coap_pack goto send; } - ret = coap_pending_init(pending, cpkt, addr, params); + params = coap_get_transmission_parameters(); + params.max_retransmission = CONFIG_COAP_SERVICE_PENDING_RETRANSMITS; + ret = coap_pending_init(pending, cpkt, addr, ¶ms); if (ret < 0) { LOG_WRN("Failed to init pending message for %s (%d)", service->name, ret); goto send; @@ -586,13 +589,12 @@ int coap_service_send(const struct coap_service *service, const struct coap_pack } int coap_resource_send(const struct coap_resource *resource, const struct coap_packet *cpkt, - const struct sockaddr *addr, socklen_t addr_len, - const struct coap_transmission_parameters *params) + const struct sockaddr *addr, socklen_t addr_len) { /* Find owning service */ COAP_SERVICE_FOREACH(svc) { if (COAP_SERVICE_HAS_RESOURCE(svc, resource)) { - return coap_service_send(svc, cpkt, addr, addr_len, params); + return coap_service_send(svc, cpkt, addr, addr_len); } } From d45a843ae6d65a6eecf110a09e02cf8d8a93489c Mon Sep 17 00:00:00 2001 From: Robert Lubos Date: Tue, 6 Feb 2024 11:07:13 +0100 Subject: [PATCH 3562/3723] Revert "[nrf fromtree] tests: net: coap: Add test case for transmission parameters" This reverts commit b953247879b2a9ef5acb901e561996c984e5cd3e. Signed-off-by: Robert Lubos --- tests/net/lib/coap/src/main.c | 53 ----------------------------------- 1 file changed, 53 deletions(-) diff --git a/tests/net/lib/coap/src/main.c b/tests/net/lib/coap/src/main.c index d1903dea10c..52b6cf0fd2a 100644 --- a/tests/net/lib/coap/src/main.c +++ b/tests/net/lib/coap/src/main.c @@ -1718,57 +1718,4 @@ ZTEST(coap, test_coap_packet_set_path) COAP_OPTION_URI_PATH); } -ZTEST(coap, test_transmission_parameters) -{ - struct coap_packet cpkt; - struct coap_pending *pending; - struct coap_transmission_parameters params; - uint8_t *data = data_buf[0]; - int r; - uint16_t id; - - params = coap_get_transmission_parameters(); - zassert_equal(params.ack_timeout, CONFIG_COAP_INIT_ACK_TIMEOUT_MS, "Wrong ACK timeout"); - zassert_equal(params.coap_backoff_percent, CONFIG_COAP_BACKOFF_PERCENT, - "Wrong backoff percent"); - zassert_equal(params.max_retransmission, CONFIG_COAP_MAX_RETRANSMIT, - "Wrong max retransmission value"); - - params.ack_timeout = 1000; - params.coap_backoff_percent = 150; - params.max_retransmission = 2; - - coap_set_transmission_parameters(¶ms); - - id = coap_next_id(); - - r = coap_packet_init(&cpkt, data, COAP_BUF_SIZE, COAP_VERSION_1, - COAP_TYPE_CON, 0, coap_next_token(), - COAP_METHOD_GET, id); - zassert_equal(r, 0, "Could not initialize packet"); - - pending = coap_pending_next_unused(pendings, NUM_PENDINGS); - zassert_not_null(pending, "No free pending"); - - params.ack_timeout = 3000; - params.coap_backoff_percent = 250; - params.max_retransmission = 3; - - r = coap_pending_init(pending, &cpkt, (struct sockaddr *) &dummy_addr, - ¶ms); - zassert_equal(r, 0, "Could not initialize packet"); - - zassert_equal(pending->params.ack_timeout, 3000, "Wrong ACK timeout"); - zassert_equal(pending->params.coap_backoff_percent, 250, "Wrong backoff percent"); - zassert_equal(pending->params.max_retransmission, 3, "Wrong max retransmission value"); - - r = coap_pending_init(pending, &cpkt, (struct sockaddr *) &dummy_addr, - NULL); - zassert_equal(r, 0, "Could not initialize packet"); - - zassert_equal(pending->params.ack_timeout, 1000, "Wrong ACK timeout"); - zassert_equal(pending->params.coap_backoff_percent, 150, "Wrong backoff percent"); - zassert_equal(pending->params.max_retransmission, 2, "Wrong max retransmission value"); -} - ZTEST_SUITE(coap, NULL, NULL, NULL, NULL, NULL); From 64679b7e059979f0da5068924c08c9759010059e Mon Sep 17 00:00:00 2001 From: Robert Lubos Date: Tue, 6 Feb 2024 11:07:13 +0100 Subject: [PATCH 3563/3723] Revert "[nrf fromtree] net: lib: coap: Change coap_pending_init()" This reverts commit 737dfd9d5bb4abe5abdef0661d3a5443c1611373. Signed-off-by: Robert Lubos --- doc/releases/migration-guide-3.6.rst | 22 ------------ doc/releases/release-notes-3.6.rst | 5 --- include/zephyr/net/coap.h | 30 ++++++++-------- include/zephyr/net/coap_client.h | 5 +-- subsys/net/lib/coap/coap.c | 23 +++++------- subsys/net/lib/coap/coap_client.c | 19 ++++++---- subsys/net/lib/coap/coap_server.c | 7 ++-- subsys/net/lib/lwm2m/lwm2m_message_handling.c | 6 ++-- tests/net/lib/coap/src/main.c | 2 +- tests/net/lib/coap_client/src/main.c | 35 +++++++------------ 10 files changed, 57 insertions(+), 97 deletions(-) diff --git a/doc/releases/migration-guide-3.6.rst b/doc/releases/migration-guide-3.6.rst index 27567c3c052..c1739adf74d 100644 --- a/doc/releases/migration-guide-3.6.rst +++ b/doc/releases/migration-guide-3.6.rst @@ -150,28 +150,6 @@ Networking ``request`` argument for :c:func:`coap_well_known_core_get` is made ``const``. (:github:`64265`) -* CoAP observer events have moved from a callback function in a CoAP resource to the Network Events - subsystem. The ``CONFIG_COAP_OBSERVER_EVENTS`` configuration option has been removed. - (:github:`65936`) - -* The CoAP public API function :c:func:`coap_pending_init` has changed. The parameter - ``retries`` is replaced with a pointer to :c:struct:`coap_transmission_parameters`. This allows to - specify retransmission parameters of the confirmable message. It is safe to pass a NULL pointer to - use default values. - (:github:`66482`) - -* The IGMP multicast library now supports IGMPv3. This results in a minor change to the existing - api. The :c:func:`net_ipv4_igmp_join` now takes an additional argument of the type - ``const struct igmp_param *param``. This allows IGMPv3 to exclude/include certain groups of - addresses. If this functionality is not used or available (when using IGMPv2), you can safely pass - a NULL pointer. IGMPv3 can be enabled using the Kconfig ``CONFIG_NET_IPV4_IGMPV3``. - (:github:`65293`) - -* The network stack now uses a separate IPv4 TTL (time-to-live) value for multicast packets. - Before, the same TTL value was used for unicast and multicast packets. - The IPv6 hop limit value is also changed so that unicast and multicast packets can have a - different one. (:github:`65886`) - Other Subsystems ================ diff --git a/doc/releases/release-notes-3.6.rst b/doc/releases/release-notes-3.6.rst index f4d813432b1..a253434a085 100644 --- a/doc/releases/release-notes-3.6.rst +++ b/doc/releases/release-notes-3.6.rst @@ -195,11 +195,6 @@ Networking * CoAP: - * Added new API functions: - - * :c:func:`coap_get_transmission_parameters` - * :c:func:`coap_set_transmission_parameters` - * Connection Manager: * DHCP: diff --git a/include/zephyr/net/coap.h b/include/zephyr/net/coap.h index e303d5c8ad3..e4374f41e34 100644 --- a/include/zephyr/net/coap.h +++ b/include/zephyr/net/coap.h @@ -309,18 +309,6 @@ typedef int (*coap_reply_t)(const struct coap_packet *response, struct coap_reply *reply, const struct sockaddr *from); -/** - * @brief CoAP transmission parameters. - */ -struct coap_transmission_parameters { - /** Initial ACK timeout. Value is used as a base value to retry pending CoAP packets. */ - uint32_t ack_timeout; - /** Set CoAP retry backoff factor. A value of 200 means a factor of 2.0. */ - uint16_t coap_backoff_percent; - /** Maximum number of retransmissions. */ - uint8_t max_retransmission; -}; - /** * @brief Represents a request awaiting for an acknowledgment (ACK). */ @@ -332,7 +320,6 @@ struct coap_pending { uint8_t *data; /**< User allocated buffer */ uint16_t len; /**< Length of the CoAP packet */ uint8_t retries; /**< Number of times the request has been sent */ - struct coap_transmission_parameters params; /**< Transmission parameters */ }; /** @@ -1002,15 +989,14 @@ void coap_reply_init(struct coap_reply *reply, * confirmation message, initialized with data from @a request * @param request Message waiting for confirmation * @param addr Address to send the retransmission - * @param params Pointer to the CoAP transmission parameters struct, - * or NULL to use default values + * @param retries Maximum number of retransmissions of the message. * * @return 0 in case of success or negative in case of error. */ int coap_pending_init(struct coap_pending *pending, const struct coap_packet *request, const struct sockaddr *addr, - const struct coap_transmission_parameters *params); + uint8_t retries); /** * @brief Returns the next available pending struct, that can be used @@ -1148,6 +1134,18 @@ int coap_resource_notify(struct coap_resource *resource); */ bool coap_request_is_observe(const struct coap_packet *request); +/** + * @brief CoAP transmission parameters. + */ +struct coap_transmission_parameters { + /** Initial AKC timeout. Value is used as a base value to retry pending CoAP packets. */ + uint32_t ack_timeout; + /** Set CoAP retry backoff factor. A value of 200 means a factor of 2.0. */ + uint16_t coap_backoff_percent; + /** Maximum number of retransmissions. */ + uint8_t max_retransmission; +}; + /** * @brief Get currently active CoAP transmission parameters. * diff --git a/include/zephyr/net/coap_client.h b/include/zephyr/net/coap_client.h index e48048d5c26..c3de1abee27 100644 --- a/include/zephyr/net/coap_client.h +++ b/include/zephyr/net/coap_client.h @@ -83,6 +83,7 @@ struct coap_client_internal_request { uint32_t offset; uint32_t last_id; uint8_t request_tkl; + uint8_t retry_count; bool request_ongoing; struct coap_block_context recv_blk_ctx; struct coap_block_context send_blk_ctx; @@ -130,12 +131,12 @@ int coap_client_init(struct coap_client *client, const char *info); * @param sock Open socket file descriptor. * @param addr the destination address of the request, NULL if socket is already connected. * @param req CoAP request structure - * @param params Pointer to transmission parameters structure or NULL to use default values. + * @param retries How many times to retry or -1 to use default. * @return zero when operation started successfully or negative error code otherwise. */ int coap_client_req(struct coap_client *client, int sock, const struct sockaddr *addr, - struct coap_client_request *req, struct coap_transmission_parameters *params); + struct coap_client_request *req, int retries); /** * @} diff --git a/subsys/net/lib/coap/coap.c b/subsys/net/lib/coap/coap.c index bfb643a8e8c..c21e14e5ded 100644 --- a/subsys/net/lib/coap/coap.c +++ b/subsys/net/lib/coap/coap.c @@ -1553,7 +1553,7 @@ size_t coap_next_block(const struct coap_packet *cpkt, int coap_pending_init(struct coap_pending *pending, const struct coap_packet *request, const struct sockaddr *addr, - const struct coap_transmission_parameters *params) + uint8_t retries) { memset(pending, 0, sizeof(*pending)); @@ -1561,16 +1561,10 @@ int coap_pending_init(struct coap_pending *pending, memcpy(&pending->addr, addr, sizeof(*addr)); - if (params) { - pending->params = *params; - } else { - pending->params = coap_transmission_params; - } - pending->data = request->data; pending->len = request->offset; pending->t0 = k_uptime_get(); - pending->retries = pending->params.max_retransmission; + pending->retries = retries; return 0; } @@ -1682,12 +1676,12 @@ struct coap_pending *coap_pending_next_to_expire( return found; } -static uint32_t init_ack_timeout(const struct coap_transmission_parameters *params) +static uint32_t init_ack_timeout(void) { #if defined(CONFIG_COAP_RANDOMIZE_ACK_TIMEOUT) - const uint32_t max_ack = params->ack_timeout * + const uint32_t max_ack = coap_transmission_params.ack_timeout * CONFIG_COAP_ACK_RANDOM_PERCENT / 100; - const uint32_t min_ack = params->ack_timeout; + const uint32_t min_ack = coap_transmission_params.ack_timeout; /* Randomly generated initial ACK timeout * ACK_TIMEOUT < INIT_ACK_TIMEOUT < ACK_TIMEOUT * ACK_RANDOM_FACTOR @@ -1695,7 +1689,7 @@ static uint32_t init_ack_timeout(const struct coap_transmission_parameters *para */ return min_ack + (sys_rand32_get() % (max_ack - min_ack)); #else - return params->ack_timeout; + return coap_transmission_params.ack_timeout; #endif /* defined(CONFIG_COAP_RANDOMIZE_ACK_TIMEOUT) */ } @@ -1703,7 +1697,8 @@ bool coap_pending_cycle(struct coap_pending *pending) { if (pending->timeout == 0) { /* Initial transmission. */ - pending->timeout = init_ack_timeout(&pending->params); + pending->timeout = init_ack_timeout(); + return true; } @@ -1712,7 +1707,7 @@ bool coap_pending_cycle(struct coap_pending *pending) } pending->t0 += pending->timeout; - pending->timeout = pending->timeout * pending->params.coap_backoff_percent / 100; + pending->timeout = pending->timeout * coap_transmission_params.coap_backoff_percent / 100; pending->retries--; return true; diff --git a/subsys/net/lib/coap/coap_client.c b/subsys/net/lib/coap/coap_client.c index 4bdf387a242..a947b15ae8e 100644 --- a/subsys/net/lib/coap/coap_client.c +++ b/subsys/net/lib/coap/coap_client.c @@ -16,6 +16,7 @@ LOG_MODULE_DECLARE(net_coap, CONFIG_COAP_LOG_LEVEL); #define COAP_VERSION 1 #define COAP_SEPARATE_TIMEOUT 6000 #define COAP_PERIODIC_TIMEOUT 500 +#define DEFAULT_RETRY_AMOUNT 5 #define BLOCK1_OPTION_SIZE 4 #define PAYLOAD_MARKER_SIZE 1 @@ -59,6 +60,7 @@ static void reset_internal_request(struct coap_client_internal_request *request) { request->offset = 0; request->last_id = 0; + request->retry_count = 0; reset_block_contexts(request); } @@ -275,7 +277,7 @@ static int coap_client_init_request(struct coap_client *client, } int coap_client_req(struct coap_client *client, int sock, const struct sockaddr *addr, - struct coap_client_request *req, struct coap_transmission_parameters *params) + struct coap_client_request *req, int retries) { int ret; @@ -350,8 +352,14 @@ int coap_client_req(struct coap_client *client, int sock, const struct sockaddr /* only TYPE_CON messages need pending tracking */ if (coap_header_get_type(&internal_req->request) == COAP_TYPE_CON) { + if (retries == -1) { + internal_req->retry_count = DEFAULT_RETRY_AMOUNT; + } else { + internal_req->retry_count = retries; + } + ret = coap_pending_init(&internal_req->pending, &internal_req->request, - &client->address, params); + &client->address, internal_req->retry_count); if (ret < 0) { LOG_ERR("Failed to initialize pending struct"); @@ -684,11 +692,9 @@ static int handle_response(struct coap_client *client, const struct coap_packet } if (coap_header_get_type(&internal_req->request) == COAP_TYPE_CON) { - struct coap_transmission_parameters params = - internal_req->pending.params; ret = coap_pending_init(&internal_req->pending, &internal_req->request, &client->address, - ¶ms); + internal_req->retry_count); if (ret < 0) { LOG_ERR("Error creating pending"); k_mutex_unlock(&client->send_mutex); @@ -787,9 +793,8 @@ static int handle_response(struct coap_client *client, const struct coap_packet goto fail; } - struct coap_transmission_parameters params = internal_req->pending.params; ret = coap_pending_init(&internal_req->pending, &internal_req->request, - &client->address, ¶ms); + &client->address, internal_req->retry_count); if (ret < 0) { LOG_ERR("Error creating pending"); k_mutex_unlock(&client->send_mutex); diff --git a/subsys/net/lib/coap/coap_server.c b/subsys/net/lib/coap/coap_server.c index 66e5dcbc32c..ce312968ea7 100644 --- a/subsys/net/lib/coap/coap_server.c +++ b/subsys/net/lib/coap/coap_server.c @@ -542,8 +542,6 @@ int coap_service_send(const struct coap_service *service, const struct coap_pack * try to send. */ if (coap_header_get_type(cpkt) == COAP_TYPE_CON) { - struct coap_transmission_parameters params; - struct coap_pending *pending = coap_pending_next_unused(service->data->pending, MAX_PENDINGS); @@ -552,9 +550,8 @@ int coap_service_send(const struct coap_service *service, const struct coap_pack goto send; } - params = coap_get_transmission_parameters(); - params.max_retransmission = CONFIG_COAP_SERVICE_PENDING_RETRANSMITS; - ret = coap_pending_init(pending, cpkt, addr, ¶ms); + ret = coap_pending_init(pending, cpkt, addr, + CONFIG_COAP_SERVICE_PENDING_RETRANSMITS); if (ret < 0) { LOG_WRN("Failed to init pending message for %s (%d)", service->name, ret); goto send; diff --git a/subsys/net/lib/lwm2m/lwm2m_message_handling.c b/subsys/net/lib/lwm2m/lwm2m_message_handling.c index 677879304f8..02c62cee67c 100644 --- a/subsys/net/lib/lwm2m/lwm2m_message_handling.c +++ b/subsys/net/lib/lwm2m/lwm2m_message_handling.c @@ -654,7 +654,8 @@ int lwm2m_init_message(struct lwm2m_message *msg) goto cleanup; } - r = coap_pending_init(msg->pending, &msg->cpkt, &msg->ctx->remote_addr, NULL); + r = coap_pending_init(msg->pending, &msg->cpkt, &msg->ctx->remote_addr, + CONFIG_COAP_MAX_RETRANSMIT); if (r < 0) { LOG_ERR("Unable to initialize a pending " "retransmission (err:%d).", @@ -2593,7 +2594,8 @@ static int lwm2m_response_promote_to_con(struct lwm2m_message *msg) return -ENOMEM; } - ret = coap_pending_init(msg->pending, &msg->cpkt, &msg->ctx->remote_addr, NULL); + ret = coap_pending_init(msg->pending, &msg->cpkt, &msg->ctx->remote_addr, + CONFIG_COAP_MAX_RETRANSMIT); if (ret < 0) { LOG_ERR("Unable to initialize a pending " "retransmission (err:%d).", diff --git a/tests/net/lib/coap/src/main.c b/tests/net/lib/coap/src/main.c index 52b6cf0fd2a..c9d0456d332 100644 --- a/tests/net/lib/coap/src/main.c +++ b/tests/net/lib/coap/src/main.c @@ -779,7 +779,7 @@ ZTEST(coap, test_retransmit_second_round) zassert_not_null(pending, "No free pending"); r = coap_pending_init(pending, &cpkt, (struct sockaddr *) &dummy_addr, - NULL); + CONFIG_COAP_MAX_RETRANSMIT); zassert_equal(r, 0, "Could not initialize packet"); /* We "send" the packet the first time here */ diff --git a/tests/net/lib/coap_client/src/main.c b/tests/net/lib/coap_client/src/main.c index 7d99c738950..e1240c5e2ed 100644 --- a/tests/net/lib/coap_client/src/main.c +++ b/tests/net/lib/coap_client/src/main.c @@ -378,7 +378,7 @@ ZTEST(coap_client, test_get_request) k_sleep(K_MSEC(1)); LOG_INF("Send request"); - ret = coap_client_req(&client, 0, &address, &client_request, NULL); + ret = coap_client_req(&client, 0, &address, &client_request, -1); zassert_true(ret >= 0, "Sending request failed, %d", ret); set_socket_events(ZSOCK_POLLIN); @@ -409,7 +409,7 @@ ZTEST(coap_client, test_resend_request) k_sleep(K_MSEC(1)); LOG_INF("Send request"); - ret = coap_client_req(&client, 0, &address, &client_request, NULL); + ret = coap_client_req(&client, 0, &address, &client_request, -1); zassert_true(ret >= 0, "Sending request failed, %d", ret); k_sleep(K_MSEC(300)); set_socket_events(ZSOCK_POLLIN); @@ -441,7 +441,7 @@ ZTEST(coap_client, test_echo_option) k_sleep(K_MSEC(1)); LOG_INF("Send request"); - ret = coap_client_req(&client, 0, &address, &client_request, NULL); + ret = coap_client_req(&client, 0, &address, &client_request, -1); zassert_true(ret >= 0, "Sending request failed, %d", ret); set_socket_events(ZSOCK_POLLIN); @@ -472,7 +472,7 @@ ZTEST(coap_client, test_echo_option_next_req) k_sleep(K_MSEC(1)); LOG_INF("Send request"); - ret = coap_client_req(&client, 0, &address, &client_request, NULL); + ret = coap_client_req(&client, 0, &address, &client_request, -1); zassert_true(ret >= 0, "Sending request failed, %d", ret); set_socket_events(ZSOCK_POLLIN); @@ -487,7 +487,7 @@ ZTEST(coap_client, test_echo_option_next_req) client_request.len = strlen(payload); LOG_INF("Send next request"); - ret = coap_client_req(&client, 0, &address, &client_request, NULL); + ret = coap_client_req(&client, 0, &address, &client_request, -1); zassert_true(ret >= 0, "Sending request failed, %d", ret); set_socket_events(ZSOCK_POLLIN); @@ -516,7 +516,7 @@ ZTEST(coap_client, test_get_no_path) k_sleep(K_MSEC(1)); LOG_INF("Send request"); - ret = coap_client_req(&client, 0, &address, &client_request, NULL); + ret = coap_client_req(&client, 0, &address, &client_request, -1); zassert_equal(ret, -EINVAL, "Get request without path"); } @@ -541,7 +541,7 @@ ZTEST(coap_client, test_send_large_data) k_sleep(K_MSEC(1)); LOG_INF("Send request"); - ret = coap_client_req(&client, 0, &address, &client_request, NULL); + ret = coap_client_req(&client, 0, &address, &client_request, -1); zassert_true(ret >= 0, "Sending request failed, %d", ret); set_socket_events(ZSOCK_POLLIN); @@ -563,11 +563,6 @@ ZTEST(coap_client, test_no_response) .payload = NULL, .len = 0 }; - struct coap_transmission_parameters params = { - .ack_timeout = 200, - .coap_backoff_percent = 200, - .max_retransmission = 0 - }; client_request.payload = short_payload; client_request.len = strlen(short_payload); @@ -576,7 +571,7 @@ ZTEST(coap_client, test_no_response) LOG_INF("Send request"); clear_socket_events(); - ret = coap_client_req(&client, 0, &address, &client_request, ¶ms); + ret = coap_client_req(&client, 0, &address, &client_request, 0); zassert_true(ret >= 0, "Sending request failed, %d", ret); k_sleep(K_MSEC(300)); @@ -606,7 +601,7 @@ ZTEST(coap_client, test_separate_response) k_sleep(K_MSEC(1)); LOG_INF("Send request"); - ret = coap_client_req(&client, 0, &address, &client_request, NULL); + ret = coap_client_req(&client, 0, &address, &client_request, -1); zassert_true(ret >= 0, "Sending request failed, %d", ret); set_socket_events(ZSOCK_POLLIN); @@ -637,10 +632,10 @@ ZTEST(coap_client, test_multiple_requests) set_socket_events(ZSOCK_POLLIN); LOG_INF("Send request"); - ret = coap_client_req(&client, 0, &address, &client_request, NULL); + ret = coap_client_req(&client, 0, &address, &client_request, -1); zassert_true(ret >= 0, "Sending request failed, %d", ret); - ret = coap_client_req(&client, 0, &address, &client_request, NULL); + ret = coap_client_req(&client, 0, &address, &client_request, -1); zassert_true(ret >= 0, "Sending request failed, %d", ret); k_sleep(K_MSEC(5)); @@ -665,11 +660,6 @@ ZTEST(coap_client, test_unmatching_tokens) .payload = NULL, .len = 0 }; - struct coap_transmission_parameters params = { - .ack_timeout = 200, - .coap_backoff_percent = 200, - .max_retransmission = 0 - }; client_request.payload = short_payload; client_request.len = strlen(short_payload); @@ -677,7 +667,7 @@ ZTEST(coap_client, test_unmatching_tokens) z_impl_zsock_recvfrom_fake.custom_fake = z_impl_zsock_recvfrom_custom_fake_unmatching; LOG_INF("Send request"); - ret = coap_client_req(&client, 0, &address, &client_request, ¶ms); + ret = coap_client_req(&client, 0, &address, &client_request, 0); zassert_true(ret >= 0, "Sending request failed, %d", ret); set_socket_events(ZSOCK_POLLIN); @@ -685,5 +675,4 @@ ZTEST(coap_client, test_unmatching_tokens) k_sleep(K_MSEC(1)); clear_socket_events(); k_sleep(K_MSEC(500)); - zassert_equal(last_response_code, -ETIMEDOUT, "Unexpected response"); } From 4b07815179618d6dea11a92b6b2482e33c6d08f2 Mon Sep 17 00:00:00 2001 From: Robert Lubos Date: Tue, 6 Feb 2024 11:07:13 +0100 Subject: [PATCH 3564/3723] Revert "[nrf fromtree] net: lib: lwm2m: use correct format specifier for LOG_ERR" This reverts commit 1a65a63f833d09179133249c2133139d918845f0. Signed-off-by: Robert Lubos --- subsys/net/lib/lwm2m/lwm2m_obj_device.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/subsys/net/lib/lwm2m/lwm2m_obj_device.c b/subsys/net/lib/lwm2m/lwm2m_obj_device.c index f5399fefc1e..9416b3cf92c 100644 --- a/subsys/net/lib/lwm2m/lwm2m_obj_device.c +++ b/subsys/net/lib/lwm2m/lwm2m_obj_device.c @@ -261,7 +261,7 @@ static int lwm2m_obj_device_settings_set(const char *name, size_t len, if (settings_name_steq(name, ERROR_LIST_KEY, &next) && !next) { if (len > sizeof(error_code_list)) { - LOG_ERR("Error code list too large: %zu", len); + LOG_ERR("Error code list too large: %u", len); return -EINVAL; } From 5e0d5c30b2750fd97013ff4dae4ab4368f6412c5 Mon Sep 17 00:00:00 2001 From: Robert Lubos Date: Tue, 6 Feb 2024 11:07:14 +0100 Subject: [PATCH 3565/3723] Revert "[nrf fromtree] net: lib: coap: Add new API to configure retransmission settings" This reverts commit 4bd6aac3a8765d2588baff084e543a800fc4487e. Signed-off-by: Robert Lubos --- include/zephyr/net/coap.h | 26 ------------------------ subsys/net/lib/coap/Kconfig | 7 ------- subsys/net/lib/coap/coap.c | 24 ++++------------------ tests/net/lib/coap_client/CMakeLists.txt | 2 -- 4 files changed, 4 insertions(+), 55 deletions(-) diff --git a/include/zephyr/net/coap.h b/include/zephyr/net/coap.h index e4374f41e34..dceed869b43 100644 --- a/include/zephyr/net/coap.h +++ b/include/zephyr/net/coap.h @@ -1134,32 +1134,6 @@ int coap_resource_notify(struct coap_resource *resource); */ bool coap_request_is_observe(const struct coap_packet *request); -/** - * @brief CoAP transmission parameters. - */ -struct coap_transmission_parameters { - /** Initial AKC timeout. Value is used as a base value to retry pending CoAP packets. */ - uint32_t ack_timeout; - /** Set CoAP retry backoff factor. A value of 200 means a factor of 2.0. */ - uint16_t coap_backoff_percent; - /** Maximum number of retransmissions. */ - uint8_t max_retransmission; -}; - -/** - * @brief Get currently active CoAP transmission parameters. - * - * @return CoAP transmission parameters structure. - */ -struct coap_transmission_parameters coap_get_transmission_parameters(void); - -/** - * @brief Set CoAP transmission parameters. - * - * @param params Pointer to the transmission parameters structure. - */ -void coap_set_transmission_parameters(const struct coap_transmission_parameters *params); - #ifdef __cplusplus } #endif diff --git a/subsys/net/lib/coap/Kconfig b/subsys/net/lib/coap/Kconfig index f4d002d0c5d..cc6bee04f53 100644 --- a/subsys/net/lib/coap/Kconfig +++ b/subsys/net/lib/coap/Kconfig @@ -82,13 +82,6 @@ config COAP_MAX_RETRANSMIT default 4 range 1 10 -config COAP_BACKOFF_PERCENT - int "Retransmission backoff factor for ACK timeout described as percentage" - default 200 - help - Factor described as percentage to extend CoAP ACK timeout for retransmissions. - A value of 200 means a factor of 2.0. - config COAP_URI_WILDCARD bool "Wildcards in CoAP resource path" default y diff --git a/subsys/net/lib/coap/coap.c b/subsys/net/lib/coap/coap.c index c21e14e5ded..c49264e6776 100644 --- a/subsys/net/lib/coap/coap.c +++ b/subsys/net/lib/coap/coap.c @@ -54,12 +54,6 @@ LOG_MODULE_REGISTER(net_coap, CONFIG_COAP_LOG_LEVEL); /* The CoAP message ID that is incremented each time coap_next_id() is called. */ static uint16_t message_id; -static struct coap_transmission_parameters coap_transmission_params = { - .max_retransmission = CONFIG_COAP_MAX_RETRANSMIT, - .ack_timeout = CONFIG_COAP_INIT_ACK_TIMEOUT_MS, - .coap_backoff_percent = CONFIG_COAP_BACKOFF_PERCENT -}; - static int insert_option(struct coap_packet *cpkt, uint16_t code, const uint8_t *value, uint16_t len); @@ -1679,9 +1673,9 @@ struct coap_pending *coap_pending_next_to_expire( static uint32_t init_ack_timeout(void) { #if defined(CONFIG_COAP_RANDOMIZE_ACK_TIMEOUT) - const uint32_t max_ack = coap_transmission_params.ack_timeout * + const uint32_t max_ack = CONFIG_COAP_INIT_ACK_TIMEOUT_MS * CONFIG_COAP_ACK_RANDOM_PERCENT / 100; - const uint32_t min_ack = coap_transmission_params.ack_timeout; + const uint32_t min_ack = CONFIG_COAP_INIT_ACK_TIMEOUT_MS; /* Randomly generated initial ACK timeout * ACK_TIMEOUT < INIT_ACK_TIMEOUT < ACK_TIMEOUT * ACK_RANDOM_FACTOR @@ -1689,7 +1683,7 @@ static uint32_t init_ack_timeout(void) */ return min_ack + (sys_rand32_get() % (max_ack - min_ack)); #else - return coap_transmission_params.ack_timeout; + return CONFIG_COAP_INIT_ACK_TIMEOUT_MS; #endif /* defined(CONFIG_COAP_RANDOMIZE_ACK_TIMEOUT) */ } @@ -1707,7 +1701,7 @@ bool coap_pending_cycle(struct coap_pending *pending) } pending->t0 += pending->timeout; - pending->timeout = pending->timeout * coap_transmission_params.coap_backoff_percent / 100; + pending->timeout = pending->timeout << 1; pending->retries--; return true; @@ -2012,13 +2006,3 @@ uint16_t coap_next_id(void) { return message_id++; } - -struct coap_transmission_parameters coap_get_transmission_parameters(void) -{ - return coap_transmission_params; -} - -void coap_set_transmission_parameters(const struct coap_transmission_parameters *params) -{ - coap_transmission_params = *params; -} diff --git a/tests/net/lib/coap_client/CMakeLists.txt b/tests/net/lib/coap_client/CMakeLists.txt index cb86d78f611..2e94112f0b0 100644 --- a/tests/net/lib/coap_client/CMakeLists.txt +++ b/tests/net/lib/coap_client/CMakeLists.txt @@ -27,5 +27,3 @@ add_compile_definitions(CONFIG_COAP_LOG_LEVEL=4) add_compile_definitions(CONFIG_COAP_INIT_ACK_TIMEOUT_MS=200) add_compile_definitions(CONFIG_COAP_CLIENT_MAX_REQUESTS=2) add_compile_definitions(CONFIG_COAP_CLIENT_MAX_INSTANCES=2) -add_compile_definitions(CONFIG_COAP_MAX_RETRANSMIT=4) -add_compile_definitions(CONFIG_COAP_BACKOFF_PERCENT=200) From c2ffdf7402fd20f5c8d46e2191e129386e4f028a Mon Sep 17 00:00:00 2001 From: Robert Lubos Date: Tue, 6 Feb 2024 11:07:14 +0100 Subject: [PATCH 3566/3723] Revert "[nrf fromtree] doc: connectivity: networking: api: Add doxygengroup for coap_mgmt" This reverts commit 613a359e5d0f6c2a96590b6fe2d211f6b6cef016. Signed-off-by: Robert Lubos --- doc/connectivity/networking/api/coap_server.rst | 1 - 1 file changed, 1 deletion(-) diff --git a/doc/connectivity/networking/api/coap_server.rst b/doc/connectivity/networking/api/coap_server.rst index eb816665f41..9a91081f449 100644 --- a/doc/connectivity/networking/api/coap_server.rst +++ b/doc/connectivity/networking/api/coap_server.rst @@ -245,4 +245,3 @@ API Reference ************* .. doxygengroup:: coap_service -.. doxygengroup:: coap_mgmt From 25d2a95a03ee3809e9c84574bbcdbed23e8e2f88 Mon Sep 17 00:00:00 2001 From: Robert Lubos Date: Tue, 6 Feb 2024 11:07:14 +0100 Subject: [PATCH 3567/3723] Revert "[nrf fromtree] test: lwm2m: Run interop tests in tickless mode" This reverts commit 162f4739d13bc2fb1d2cb84da2e2e820257cb6dc. Signed-off-by: Robert Lubos --- tests/net/lib/lwm2m/interop/prj.conf | 3 --- 1 file changed, 3 deletions(-) diff --git a/tests/net/lib/lwm2m/interop/prj.conf b/tests/net/lib/lwm2m/interop/prj.conf index 6115e6f40e3..43d4e73f081 100644 --- a/tests/net/lib/lwm2m/interop/prj.conf +++ b/tests/net/lib/lwm2m/interop/prj.conf @@ -18,9 +18,6 @@ CONFIG_LWM2M=y CONFIG_LWM2M_IPSO_SUPPORT=y CONFIG_LWM2M_SHELL=y -CONFIG_LWM2M_TICKLESS=y -CONFIG_NET_SOCKETPAIR=y - #Enable Portfolio object CONFIG_LWM2M_PORTFOLIO_OBJ_SUPPORT=y From 46f3d5948d97f4953e3e7a833faac4466afa0187 Mon Sep 17 00:00:00 2001 From: Robert Lubos Date: Tue, 6 Feb 2024 11:07:14 +0100 Subject: [PATCH 3568/3723] Revert "[nrf fromtree] net: lwm2m: Fix pmin handling on tickless" This reverts commit c8e65c71cb7e43e07f41303d31b3ed45e1df03ac. Signed-off-by: Robert Lubos --- subsys/net/lib/lwm2m/lwm2m_engine.c | 29 +++++++---------------------- 1 file changed, 7 insertions(+), 22 deletions(-) diff --git a/subsys/net/lib/lwm2m/lwm2m_engine.c b/subsys/net/lib/lwm2m/lwm2m_engine.c index 959d07419d3..45d3822bdbb 100644 --- a/subsys/net/lib/lwm2m/lwm2m_engine.c +++ b/subsys/net/lib/lwm2m/lwm2m_engine.c @@ -581,24 +581,14 @@ void lwm2m_socket_del(struct lwm2m_ctx *ctx) lwm2m_engine_wake_up(); } -/* Generate notify messages. Return timestamp of next Notify event */ -static int64_t check_notifications(struct lwm2m_ctx *ctx, const int64_t timestamp) +static void check_notifications(struct lwm2m_ctx *ctx, const int64_t timestamp) { struct observe_node *obs; int rc; - int64_t next = INT64_MAX; lwm2m_registry_lock(); SYS_SLIST_FOR_EACH_CONTAINER(&ctx->observer, obs, node) { - if (!obs->event_timestamp) { - continue; - } - - if (obs->event_timestamp < next) { - next = obs->event_timestamp; - } - - if (timestamp < obs->event_timestamp) { + if (!obs->event_timestamp || timestamp < obs->event_timestamp) { continue; } /* Check That There is not pending process*/ @@ -614,7 +604,6 @@ static int64_t check_notifications(struct lwm2m_ctx *ctx, const int64_t timestam obs->event_timestamp = engine_observe_shedule_next_event(obs, ctx->srv_obj_inst, timestamp); obs->last_timestamp = timestamp; - if (!rc) { /* create at most one notification */ goto cleanup; @@ -622,7 +611,6 @@ static int64_t check_notifications(struct lwm2m_ctx *ctx, const int64_t timestam } cleanup: lwm2m_registry_unlock(); - return next; } static int socket_recv_message(struct lwm2m_ctx *client_ctx) @@ -716,7 +704,7 @@ static void socket_loop(void *p1, void *p2, void *p3) int i, rc; int64_t now, next; - int64_t timeout, next_tx; + int64_t timeout, next_retransmit; bool rd_client_paused; while (1) { @@ -753,15 +741,12 @@ static void socket_loop(void *p1, void *p2, void *p3) if (!sys_slist_is_empty(&sock_ctx[i]->pending_sends)) { continue; } - next_tx = retransmit_request(sock_ctx[i], now); - if (next_tx < next) { - next = next_tx; + next_retransmit = retransmit_request(sock_ctx[i], now); + if (next_retransmit < next) { + next = next_retransmit; } if (lwm2m_rd_client_is_registred(sock_ctx[i])) { - next_tx = check_notifications(sock_ctx[i], now); - if (next_tx < next) { - next = next_tx; - } + check_notifications(sock_ctx[i], now); } } From def3c5a91301f709f32c9e4c1a2caa4dcb522810 Mon Sep 17 00:00:00 2001 From: Robert Lubos Date: Tue, 6 Feb 2024 11:07:14 +0100 Subject: [PATCH 3569/3723] Revert "[nrf fromtree] test: lwm2m: Implement missing test case 103" This reverts commit 67e3744033592ac13037e4fb89ccafb569659133. Signed-off-by: Robert Lubos --- tests/net/lib/lwm2m/interop/README.md | 2 +- tests/net/lib/lwm2m/interop/pytest/test_lwm2m.py | 11 ----------- 2 files changed, 1 insertion(+), 12 deletions(-) diff --git a/tests/net/lib/lwm2m/interop/README.md b/tests/net/lib/lwm2m/interop/README.md index 7df931203aa..28d8e12ccca 100644 --- a/tests/net/lib/lwm2m/interop/README.md +++ b/tests/net/lib/lwm2m/interop/README.md @@ -135,7 +135,7 @@ Tests are written from test spec; |LightweightM2M-1.1-int-9 - Bootstrap and Configuration Consistency | |testcase not implemented | |LightweightM2M-1.1-int-101 - Initial Registration |:white_check_mark:| | |LightweightM2M-1.1-int-102 - Registration Update |:white_check_mark:| | -|LightweightM2M-1.1-int-103 - Deregistration |:white_check_mark:| | +|LightweightM2M-1.1-int-103 - Deregistration |:large_orange_diamond:|We don't have "disabled" functionality in server object| |LightweightM2M-1.1-int-104 - Registration Update Trigge |:white_check_mark:| | |LightweightM2M-1.1-int-105 - Discarded Register Update |:white_check_mark:| | |LightweightM2M-1.1-int-107 - Extending the lifetime of a registration |:white_check_mark:| | diff --git a/tests/net/lib/lwm2m/interop/pytest/test_lwm2m.py b/tests/net/lib/lwm2m/interop/pytest/test_lwm2m.py index 4e0ae207e8d..ed7aaceac20 100644 --- a/tests/net/lib/lwm2m/interop/pytest/test_lwm2m.py +++ b/tests/net/lib/lwm2m/interop/pytest/test_lwm2m.py @@ -44,17 +44,6 @@ def test_LightweightM2M_1_1_int_102(shell: Shell, dut: DeviceAdapter, leshan: Le assert latest["lifetime"] == lifetime shell.exec_command('lwm2m write 1/0/1 -u32 86400') -def test_LightweightM2M_1_1_int_103(shell: Shell, dut: DeviceAdapter, leshan: Leshan, endpoint: str): - """LightweightM2M-1.1-int-103 - Deregistration""" - leshan.execute(endpoint, '1/0/4') - dut.readlines_until(regex='LwM2M server disabled', timeout=5.0) - dut.readlines_until(regex='Deregistration success', timeout=5.0) - # Reset timers by restarting the client - shell.exec_command('lwm2m stop') - time.sleep(1) - shell.exec_command(f'lwm2m start {endpoint}') - dut.readlines_until(regex='.*Registration Done', timeout=5.0) - def test_LightweightM2M_1_1_int_104(shell: Shell, dut: DeviceAdapter, leshan: Leshan, endpoint: str): """LightweightM2M-1.1-int-104 - Registration Update Trigger""" shell.exec_command('lwm2m update') From 0b23568ff095be1deb2e373ea7d4b24c4c532972 Mon Sep 17 00:00:00 2001 From: Robert Lubos Date: Tue, 6 Feb 2024 11:07:15 +0100 Subject: [PATCH 3570/3723] Revert "[nrf fromtree] test: lwm2m: Implement bootstrap tests 4 - 7" This reverts commit 191896cdb8935ad3c71bf4b3452f2ea4d9db2f82. Signed-off-by: Robert Lubos --- tests/net/lib/lwm2m/interop/README.md | 8 --- tests/net/lib/lwm2m/interop/prj.conf | 5 -- .../lwm2m/interop/pytest/test_bootstrap.py | 63 +++---------------- .../net/lib/lwm2m/interop/src/lwm2m-client.c | 11 ---- 4 files changed, 8 insertions(+), 79 deletions(-) diff --git a/tests/net/lib/lwm2m/interop/README.md b/tests/net/lib/lwm2m/interop/README.md index 28d8e12ccca..3acbfcc71f8 100644 --- a/tests/net/lib/lwm2m/interop/README.md +++ b/tests/net/lib/lwm2m/interop/README.md @@ -125,14 +125,6 @@ Tests are written from test spec; |---------|------|-----| |LightweightM2M-1.1-int-0 - Client Initiated Bootstrap |:white_check_mark:| | |LightweightM2M-1.1-int-1 - Client Initiated Bootstrap Full (PSK) |:white_check_mark:| | -|LightweightM2M-1.1-int-2 - Client Initiated Bootstrap Full (Cert) | |testcase not implemented | -|LightweightM2M-1.1-int-3 – Simple Bootstrap from Smartcard |:large_orange_diamond:|We don't have any smartcard support.| -|LightweightM2M-1.1-int-4 - Bootstrap Delete |:white_check_mark:| | -|LightweightM2M-1.1-int-5 - Server Initiated Bootstrap |:white_check_mark:| | -|LightweightM2M-1.1-int-6 - Bootstrap Sequence |:white_check_mark:| | -|LightweightM2M-1.1-int-7 - Fallback to bootstrap |:white_check_mark:| | -|LightweightM2M-1.1-int-8 - Bootstrap Read | |Test cannot be implemented from client side.| -|LightweightM2M-1.1-int-9 - Bootstrap and Configuration Consistency | |testcase not implemented | |LightweightM2M-1.1-int-101 - Initial Registration |:white_check_mark:| | |LightweightM2M-1.1-int-102 - Registration Update |:white_check_mark:| | |LightweightM2M-1.1-int-103 - Deregistration |:large_orange_diamond:|We don't have "disabled" functionality in server object| diff --git a/tests/net/lib/lwm2m/interop/prj.conf b/tests/net/lib/lwm2m/interop/prj.conf index 43d4e73f081..07bd9a0535d 100644 --- a/tests/net/lib/lwm2m/interop/prj.conf +++ b/tests/net/lib/lwm2m/interop/prj.conf @@ -44,11 +44,6 @@ CONFIG_LWM2M_RW_OMA_TLV_SUPPORT=y CONFIG_COAP_EXTENDED_OPTIONS_LEN=y CONFIG_COAP_EXTENDED_OPTIONS_LEN_VALUE=40 -# Speed up testing, we are running in non-lossy network -CONFIG_COAP_INIT_ACK_TIMEOUT_MS=1000 -CONFIG_COAP_RANDOMIZE_ACK_TIMEOUT=n -CONFIG_LWM2M_RD_CLIENT_MAX_RETRIES=2 - # Use QUEUE mode by default CONFIG_LWM2M_QUEUE_MODE_ENABLED=y CONFIG_LWM2M_QUEUE_MODE_UPTIME=20 diff --git a/tests/net/lib/lwm2m/interop/pytest/test_bootstrap.py b/tests/net/lib/lwm2m/interop/pytest/test_bootstrap.py index 2a45669d912..65561db0676 100644 --- a/tests/net/lib/lwm2m/interop/pytest/test_bootstrap.py +++ b/tests/net/lib/lwm2m/interop/pytest/test_bootstrap.py @@ -15,11 +15,9 @@ """ import logging -import pytest from leshan import Leshan from twister_harness import Shell from twister_harness import DeviceAdapter -from conftest import Endpoint logger = logging.getLogger(__name__) @@ -31,69 +29,24 @@ # Bootstrap Interface: [0-99] # -def verify_LightweightM2M_1_1_int_0(dut: DeviceAdapter, endpoint_bootstrap: Endpoint): +def verify_LightweightM2M_1_1_int_0(shell: Shell, dut: DeviceAdapter): """LightweightM2M-1.1-int-0 - Client Initiated Bootstrap""" - dut.readlines_until(regex='.*Bootstrap transfer complete', timeout=5.0) - endpoint_bootstrap.bootstrap = True + dut.readlines_until(regex='.*Bootstrap started with endpoint', timeout=5.0) + dut.readlines_until(regex='.*Bootstrap registration done', timeout=5.0) + dut.readlines_until(regex='.*Bootstrap data transfer done', timeout=5.0) -def test_LightweightM2M_1_1_int_1(shell: Shell, dut: DeviceAdapter, leshan: Leshan, endpoint_bootstrap: Endpoint): +def test_LightweightM2M_1_1_int_1(shell: Shell, dut: DeviceAdapter, leshan: Leshan, endpoint_bootstrap: str): """LightweightM2M-1.1-int-1 - Client Initiated Bootstrap Full (PSK)""" - verify_LightweightM2M_1_1_int_0(dut, endpoint_bootstrap) + verify_LightweightM2M_1_1_int_0(shell, dut) verify_LightweightM2M_1_1_int_101(shell, dut, leshan, endpoint_bootstrap) verify_LightweightM2M_1_1_int_401(shell, leshan, endpoint_bootstrap) -def test_LightweightM2M_1_1_int_4(shell: Shell, dut: DeviceAdapter, leshan: Leshan, endpoint: Endpoint): - """LightweightM2M-1.1-int-4 - Bootstrap Delete""" - shell.exec_command('lwm2m create 1/2') - shell.exec_command('lwm2m read 1/2/0') - retval = int(shell.get_filtered_output(shell.exec_command('retval'))[0]) - assert retval == 0 - leshan.execute(endpoint, '1/0/9') - dut.readlines_until(regex='.*Registration Done', timeout=5.0) - shell.exec_command('lwm2m read 1/2/0') - retval = int(shell.get_filtered_output(shell.exec_command('retval'))[0]) - assert retval < 0 - logger.info('retval: %s', retval) - -def test_LightweightM2M_1_1_int_5(dut: DeviceAdapter, leshan: Leshan, endpoint: Endpoint): - """LightweightM2M-1.1-int-5 - Server Initiated Bootstrap""" - leshan.execute(endpoint, '1/0/9') - dut.readlines_until(regex='.*Server Initiated Bootstrap', timeout=1) - dut.readlines_until(regex='.*Bootstrap transfer complete', timeout=5.0) - dut.readlines_until(regex='.*Registration Done', timeout=5.0) - -def test_LightweightM2M_1_1_int_6(shell: Shell, dut: DeviceAdapter, endpoint: Endpoint): - """LightweightM2M-1.1-int-6 - Bootstrap Sequence""" - shell.exec_command('lwm2m stop') - dut.readlines_until(regex=r'.*Deregistration success', timeout=5) - shell.exec_command(f'lwm2m start {endpoint}') - lines = dut.readlines_until(regex='.*Registration Done', timeout=5.0) - assert not any("Bootstrap" in line for line in lines) - shell.exec_command('lwm2m stop') - dut.readlines_until(regex=r'.*Deregistration success', timeout=5) - shell.exec_command("lwm2m delete 1/0") - shell.exec_command("lwm2m delete 0/1") - shell.exec_command(f'lwm2m start {endpoint}') - lines = dut.readlines_until(regex='.*Registration Done', timeout=5.0) - assert any("Bootstrap" in line for line in lines) - -@pytest.mark.slow -def test_LightweightM2M_1_1_int_7(shell: Shell, dut: DeviceAdapter, endpoint: Endpoint): - """LightweightM2M-1.1-int-7 - Fallback to bootstrap""" - shell.exec_command('lwm2m stop') - dut.readlines_until(regex=r'.*Deregistration success', timeout=5) - shell.exec_command('lwm2m write 0/1/0 -s coaps://10.10.10.10:5684') - shell.exec_command(f'lwm2m start {endpoint}') - lines = dut.readlines_until(regex='.*Registration Done', timeout=600.0) - assert any("Bootstrap" in line for line in lines) - -def verify_LightweightM2M_1_1_int_101(shell: Shell, dut: DeviceAdapter, leshan: Leshan, endpoint: Endpoint): +def verify_LightweightM2M_1_1_int_101(shell: Shell, dut: DeviceAdapter, leshan: Leshan, endpoint: str): """LightweightM2M-1.1-int-101 - Initial Registration""" dut.readlines_until(regex='.*Registration Done', timeout=5.0) assert leshan.get(f'/clients/{endpoint}') - endpoint.registered = True -def verify_LightweightM2M_1_1_int_401(shell: Shell, leshan: Leshan, endpoint: Endpoint): +def verify_LightweightM2M_1_1_int_401(shell: Shell, leshan: Leshan, endpoint: str): """LightweightM2M-1.1-int-401 - UDP Channel Security - Pre-shared Key Mode""" lines = shell.get_filtered_output(shell.exec_command('lwm2m read 0/0/0 -s')) host = lines[0] diff --git a/tests/net/lib/lwm2m/interop/src/lwm2m-client.c b/tests/net/lib/lwm2m/interop/src/lwm2m-client.c index a150f1b41cb..b6634069fbd 100644 --- a/tests/net/lib/lwm2m/interop/src/lwm2m-client.c +++ b/tests/net/lib/lwm2m/interop/src/lwm2m-client.c @@ -73,17 +73,6 @@ int set_socketoptions(struct lwm2m_ctx *ctx) ret = -errno; LOG_ERR("Failed to enable TLS_DTLS_CID: %d", ret); } - - /* Allow DTLS handshake to timeout much faster. - * these tests run on TUN/TAP network, so there should be no network latency. - */ - uint32_t min = 100; - uint32_t max = 500; - - zsock_setsockopt(ctx->sock_fd, SOL_TLS, TLS_DTLS_HANDSHAKE_TIMEOUT_MIN, &min, - sizeof(min)); - zsock_setsockopt(ctx->sock_fd, SOL_TLS, TLS_DTLS_HANDSHAKE_TIMEOUT_MAX, &max, - sizeof(max)); } return lwm2m_set_default_sockopt(ctx); } From ba691cc9eb6fd7f9d99dad969d09ffdc966f357c Mon Sep 17 00:00:00 2001 From: Robert Lubos Date: Tue, 6 Feb 2024 11:07:15 +0100 Subject: [PATCH 3571/3723] Revert "[nrf fromtree] net: lwm2m: Reduce dependency on firmware update pull Kconfig" This reverts commit 09a0826979591e4bd0ce562b24d0c81c3a120d45. Signed-off-by: Robert Lubos --- include/zephyr/net/lwm2m.h | 3 +++ 1 file changed, 3 insertions(+) diff --git a/include/zephyr/net/lwm2m.h b/include/zephyr/net/lwm2m.h index 51324f63153..6ac0458af87 100644 --- a/include/zephyr/net/lwm2m.h +++ b/include/zephyr/net/lwm2m.h @@ -551,6 +551,7 @@ void lwm2m_firmware_set_cancel_cb_inst(uint16_t obj_inst_id, lwm2m_engine_user_c */ lwm2m_engine_user_cb_t lwm2m_firmware_get_cancel_cb_inst(uint16_t obj_inst_id); +#if defined(CONFIG_LWM2M_FIRMWARE_UPDATE_PULL_SUPPORT) || defined(__DOXYGEN__) /** * @brief Set data callback to handle firmware update execute events. * @@ -587,6 +588,8 @@ void lwm2m_firmware_set_update_cb_inst(uint16_t obj_inst_id, lwm2m_engine_execut */ lwm2m_engine_execute_cb_t lwm2m_firmware_get_update_cb_inst(uint16_t obj_inst_id); #endif +#endif + #if defined(CONFIG_LWM2M_SWMGMT_OBJ_SUPPORT) || defined(__DOXYGEN__) From ddaf96aecda594a6e5af2dcd014b655f8cf18dc8 Mon Sep 17 00:00:00 2001 From: Robert Lubos Date: Tue, 6 Feb 2024 11:07:15 +0100 Subject: [PATCH 3572/3723] Revert "[nrf fromtree] samples: net: sockets: coap_server: Add CoAP events example" This reverts commit 8461ad27e602773abf402d044b167a84d8037081. Signed-off-by: Robert Lubos --- samples/net/sockets/coap_server/prj.conf | 5 -- samples/net/sockets/coap_server/src/events.c | 50 -------------------- 2 files changed, 55 deletions(-) delete mode 100644 samples/net/sockets/coap_server/src/events.c diff --git a/samples/net/sockets/coap_server/prj.conf b/samples/net/sockets/coap_server/prj.conf index 59d444db456..e9ff24577b7 100644 --- a/samples/net/sockets/coap_server/prj.conf +++ b/samples/net/sockets/coap_server/prj.conf @@ -29,11 +29,6 @@ CONFIG_COAP_SERVER_SHELL=y # Configuration CONFIG_NET_CONFIG_SETTINGS=y -# Events -CONFIG_NET_MGMT=y -CONFIG_NET_MGMT_EVENT=y -CONFIG_NET_MGMT_EVENT_INFO=y - # Enable only one protocol, if you enable both sources # won't compile. # IPv6 Support diff --git a/samples/net/sockets/coap_server/src/events.c b/samples/net/sockets/coap_server/src/events.c deleted file mode 100644 index 3f843fba017..00000000000 --- a/samples/net/sockets/coap_server/src/events.c +++ /dev/null @@ -1,50 +0,0 @@ -/* - * Copyright (c) 2023 Basalte bv - * - * SPDX-License-Identifier: Apache-2.0 - */ - -#include -LOG_MODULE_DECLARE(net_coap_service_sample); - -#include -#include - -#define COAP_EVENTS_SET (NET_EVENT_COAP_OBSERVER_ADDED | NET_EVENT_COAP_OBSERVER_REMOVED | \ - NET_EVENT_COAP_SERVICE_STARTED | NET_EVENT_COAP_SERVICE_STOPPED) - -void coap_event_handler(uint32_t mgmt_event, struct net_if *iface, - void *info, size_t info_length, void *user_data) -{ - ARG_UNUSED(iface); - ARG_UNUSED(user_data); - - switch (mgmt_event) { - case NET_EVENT_COAP_OBSERVER_ADDED: - LOG_INF("CoAP observer added"); - break; - case NET_EVENT_COAP_OBSERVER_REMOVED: - LOG_INF("CoAP observer removed"); - break; - case NET_EVENT_COAP_SERVICE_STARTED: - if (info != NULL && info_length == sizeof(struct net_event_coap_service)) { - struct net_event_coap_service *net_event = info; - - LOG_INF("CoAP service %s started", net_event->service->name); - } else { - LOG_INF("CoAP service started"); - } - break; - case NET_EVENT_COAP_SERVICE_STOPPED: - if (info != NULL && info_length == sizeof(struct net_event_coap_service)) { - struct net_event_coap_service *net_event = info; - - LOG_INF("CoAP service %s stopped", net_event->service->name); - } else { - LOG_INF("CoAP service stopped"); - } - break; - } -} - -NET_MGMT_REGISTER_EVENT_HANDLER(coap_events, COAP_EVENTS_SET, coap_event_handler, NULL); From 3db2542af8ee2a1a706938593e9f60763587a30f Mon Sep 17 00:00:00 2001 From: Robert Lubos Date: Tue, 6 Feb 2024 11:07:15 +0100 Subject: [PATCH 3573/3723] Revert "[nrf fromtree] net: lib: coap: Introduce net mgmt events for CoAP" This reverts commit 7b7d001bb68ed4cd5450127fa93c1e99a1047762. Signed-off-by: Robert Lubos --- include/zephyr/net/coap_mgmt.h | 102 ------------------------------ subsys/net/lib/coap/coap.c | 30 +-------- subsys/net/lib/coap/coap_server.c | 25 +------- 3 files changed, 4 insertions(+), 153 deletions(-) delete mode 100644 include/zephyr/net/coap_mgmt.h diff --git a/include/zephyr/net/coap_mgmt.h b/include/zephyr/net/coap_mgmt.h deleted file mode 100644 index f19eec6eb4b..00000000000 --- a/include/zephyr/net/coap_mgmt.h +++ /dev/null @@ -1,102 +0,0 @@ -/* - * Copyright (c) 2023 Basalte bv - * - * SPDX-License-Identifier: Apache-2.0 - */ - -/** - * @file - * @brief CoAP Events code public header - */ - -#ifndef ZEPHYR_INCLUDE_NET_COAP_MGMT_H_ -#define ZEPHYR_INCLUDE_NET_COAP_MGMT_H_ - -#include - -#ifdef __cplusplus -extern "C" { -#endif - -/** - * @brief CoAP Manager Events - * @defgroup coap_mgmt CoAP Manager Events - * @ingroup networking - * @{ - */ - -/** @cond INTERNAL_HIDDEN */ - -/* CoAP events */ -#define _NET_COAP_LAYER NET_MGMT_LAYER_L4 -#define _NET_COAP_CODE 0x1c0 -#define _NET_COAP_IF_BASE (NET_MGMT_EVENT_BIT | \ - NET_MGMT_LAYER(_NET_COAP_LAYER) | \ - NET_MGMT_LAYER_CODE(_NET_COAP_CODE)) - -struct coap_service; -struct coap_resource; -struct coap_observer; - -/** @endcond */ - -enum net_event_coap_cmd { - /* Service events */ - NET_EVENT_COAP_CMD_SERVICE_STARTED = 1, - NET_EVENT_COAP_CMD_SERVICE_STOPPED, - /* Observer events */ - NET_EVENT_COAP_CMD_OBSERVER_ADDED, - NET_EVENT_COAP_CMD_OBSERVER_REMOVED, -}; - -/** - * @brief coap_mgmt event raised when a service has started - */ -#define NET_EVENT_COAP_SERVICE_STARTED \ - (_NET_COAP_IF_BASE | NET_EVENT_COAP_CMD_SERVICE_STARTED) - -/** - * @brief coap_mgmt event raised when a service has stopped - */ -#define NET_EVENT_COAP_SERVICE_STOPPED \ - (_NET_COAP_IF_BASE | NET_EVENT_COAP_CMD_SERVICE_STOPPED) - -/** - * @brief coap_mgmt event raised when an observer has been added to a resource - */ -#define NET_EVENT_COAP_OBSERVER_ADDED \ - (_NET_COAP_IF_BASE | NET_EVENT_COAP_CMD_OBSERVER_ADDED) - -/** - * @brief coap_mgmt event raised when an observer has been removed from a resource - */ -#define NET_EVENT_COAP_OBSERVER_REMOVED \ - (_NET_COAP_IF_BASE | NET_EVENT_COAP_CMD_OBSERVER_REMOVED) - -/** - * @brief CoAP Service event structure. - */ -struct net_event_coap_service { - /* The CoAP service for which the event is emitted */ - const struct coap_service *service; -}; - -/** - * @brief CoAP Observer event structure. - */ -struct net_event_coap_observer { - /* The CoAP resource for which the event is emitted */ - struct coap_resource *resource; - /* The observer that is added/removed */ - struct coap_observer *observer; -}; - -#ifdef __cplusplus -} -#endif - -/** - * @} - */ - -#endif /* ZEPHYR_INCLUDE_NET_COAP_MGMT_H_ */ diff --git a/subsys/net/lib/coap/coap.c b/subsys/net/lib/coap/coap.c index c49264e6776..e2ff715aec6 100644 --- a/subsys/net/lib/coap/coap.c +++ b/subsys/net/lib/coap/coap.c @@ -23,7 +23,6 @@ LOG_MODULE_REGISTER(net_coap, CONFIG_COAP_LOG_LEVEL); #include #include #include -#include #define COAP_PATH_ELEM_DELIM '/' #define COAP_PATH_ELEM_QUERY '?' @@ -1845,25 +1844,6 @@ void coap_observer_init(struct coap_observer *observer, net_ipaddr_copy(&observer->addr, addr); } -static inline void coap_observer_raise_event(struct coap_resource *resource, - struct coap_observer *observer, - uint32_t mgmt_event) -{ -#ifdef CONFIG_NET_MGMT_EVENT_INFO - const struct net_event_coap_observer net_event = { - .resource = resource, - .observer = observer, - }; - - net_mgmt_event_notify_with_info(mgmt_event, NULL, (void *)&net_event, sizeof(net_event)); -#else - ARG_UNUSED(resource); - ARG_UNUSED(observer); - - net_mgmt_event_notify(mgmt_event, NULL); -#endif -} - bool coap_register_observer(struct coap_resource *resource, struct coap_observer *observer) { @@ -1876,21 +1856,13 @@ bool coap_register_observer(struct coap_resource *resource, resource->age = 2; } - coap_observer_raise_event(resource, observer, NET_EVENT_COAP_OBSERVER_ADDED); - return first; } bool coap_remove_observer(struct coap_resource *resource, struct coap_observer *observer) { - if (!sys_slist_find_and_remove(&resource->observers, &observer->list)) { - return false; - } - - coap_observer_raise_event(resource, observer, NET_EVENT_COAP_OBSERVER_REMOVED); - - return true; + return sys_slist_find_and_remove(&resource->observers, &observer->list); } static bool sockaddr_equal(const struct sockaddr *a, diff --git a/subsys/net/lib/coap/coap_server.c b/subsys/net/lib/coap/coap_server.c index ce312968ea7..386bc2081bb 100644 --- a/subsys/net/lib/coap/coap_server.c +++ b/subsys/net/lib/coap/coap_server.c @@ -14,7 +14,6 @@ LOG_MODULE_DECLARE(net_coap, CONFIG_COAP_LOG_LEVEL); #include #include #include -#include #include #ifdef CONFIG_ARCH_POSIX #include @@ -346,21 +345,6 @@ static inline bool coap_service_in_section(const struct coap_service *service) STRUCT_SECTION_END(coap_service) > service; } -static inline void coap_service_raise_event(const struct coap_service *service, uint32_t mgmt_event) -{ -#if defined(CONFIG_NET_MGMT_EVENT_INFO) - const struct net_event_coap_service net_event = { - .service = service, - }; - - net_mgmt_event_notify_with_info(mgmt_event, NULL, (void *)&net_event, sizeof(net_event)); -#else - ARG_UNUSED(service); - - net_mgmt_event_notify(mgmt_event, NULL); -#endif -} - int coap_service_start(const struct coap_service *service) { int ret; @@ -462,8 +446,6 @@ int coap_service_start(const struct coap_service *service) coap_server_update_services(); - coap_service_raise_event(service, NET_EVENT_COAP_SERVICE_STARTED); - return ret; close: @@ -487,18 +469,17 @@ int coap_service_stop(const struct coap_service *service) k_mutex_lock(&lock, K_FOREVER); if (service->data->sock_fd < 0) { - k_mutex_unlock(&lock); - return -EALREADY; + ret = -EALREADY; + goto end; } /* Closing a socket will trigger a poll event */ ret = zsock_close(service->data->sock_fd); service->data->sock_fd = -1; +end: k_mutex_unlock(&lock); - coap_service_raise_event(service, NET_EVENT_COAP_SERVICE_STOPPED); - return ret; } From cf92a631e2ef2b2c9609fb8912eeb9d5e159056f Mon Sep 17 00:00:00 2001 From: Robert Lubos Date: Tue, 6 Feb 2024 11:07:15 +0100 Subject: [PATCH 3574/3723] Revert "[nrf fromtree] Revert "net: lib: coap: Add support for observer event callbacks"" This reverts commit 9af0dc0c004d20a23b174d0d5a3ba8996a22a403. Signed-off-by: Robert Lubos --- include/zephyr/net/coap.h | 30 ++++++++++++++++++++++++++++++ subsys/net/lib/coap/Kconfig | 6 ++++++ subsys/net/lib/coap/coap.c | 17 ++++++++++++++++- 3 files changed, 52 insertions(+), 1 deletion(-) diff --git a/include/zephyr/net/coap.h b/include/zephyr/net/coap.h index dceed869b43..a907d1311e1 100644 --- a/include/zephyr/net/coap.h +++ b/include/zephyr/net/coap.h @@ -238,6 +238,29 @@ typedef int (*coap_method_t)(struct coap_resource *resource, typedef void (*coap_notify_t)(struct coap_resource *resource, struct coap_observer *observer); +/** + * @brief Event types for observer event callbacks. + */ +enum coap_observer_event { + /** An observer was added. */ + COAP_OBSERVER_ADDED = 0, + /** An observer was removed. */ + COAP_OBSERVER_REMOVED, +}; + +/** + * @typedef coap_observer_event_handler_t + * @brief Type of the handler being called when a resource's observers has been modified. + * Either an observer was added or removed. + * + * @param resource A pointer to a CoAP resource for which the event occurred + * @param observer The observer being added/removed + * @param event The event type + */ +typedef void (*coap_observer_event_handler_t)(struct coap_resource *resource, + struct coap_observer *observer, + enum coap_observer_event event); + /** * @brief Description of CoAP resource. * @@ -252,6 +275,13 @@ struct coap_resource { void *user_data; sys_slist_t observers; int age; +#if defined(CONFIG_COAP_OBSERVER_EVENTS) || defined(DOXYGEN) + /** + * Optional observer event callback function + * Only available when @kconfig{CONFIG_COAP_OBSERVER_EVENTS} is enabled. + */ + coap_observer_event_handler_t observer_event_handler; +#endif }; /** diff --git a/subsys/net/lib/coap/Kconfig b/subsys/net/lib/coap/Kconfig index cc6bee04f53..8e62983ea72 100644 --- a/subsys/net/lib/coap/Kconfig +++ b/subsys/net/lib/coap/Kconfig @@ -89,6 +89,12 @@ config COAP_URI_WILDCARD This option enables MQTT-style wildcards in path. Disable it if resource path may contain plus or hash symbol. +config COAP_OBSERVER_EVENTS + bool "CoAP resource observer events" + help + This option enables to register a callback function to CoAP resources + that will be called when adding/removing observers. + config COAP_KEEP_USER_DATA bool "Keeping user data in the CoAP packet" help diff --git a/subsys/net/lib/coap/coap.c b/subsys/net/lib/coap/coap.c index e2ff715aec6..9fe62730b47 100644 --- a/subsys/net/lib/coap/coap.c +++ b/subsys/net/lib/coap/coap.c @@ -1856,13 +1856,28 @@ bool coap_register_observer(struct coap_resource *resource, resource->age = 2; } +#ifdef CONFIG_COAP_OBSERVER_EVENTS + if (resource->observer_event_handler) { + resource->observer_event_handler(resource, observer, COAP_OBSERVER_ADDED); + } +#endif + return first; } bool coap_remove_observer(struct coap_resource *resource, struct coap_observer *observer) { - return sys_slist_find_and_remove(&resource->observers, &observer->list); + if (!sys_slist_find_and_remove(&resource->observers, &observer->list)) { + return false; + } + +#ifdef CONFIG_COAP_OBSERVER_EVENTS + if (resource->observer_event_handler) { + resource->observer_event_handler(resource, observer, COAP_OBSERVER_REMOVED); + } +#endif + return true; } static bool sockaddr_equal(const struct sockaddr *a, From bbd023514d6bc1cbf0ef9cb36d9a51ce9af794a0 Mon Sep 17 00:00:00 2001 From: Robert Lubos Date: Tue, 6 Feb 2024 11:07:15 +0100 Subject: [PATCH 3575/3723] Revert "[nrf fromtree] samples: net: sockets: coap_server: Remove observer events" This reverts commit 20f9d5c5a19f5129fd5308b4fe69edd5428938f6. Signed-off-by: Robert Lubos --- samples/net/sockets/coap_server/prj.conf | 1 + samples/net/sockets/coap_server/src/observer.c | 13 +++++++++++++ 2 files changed, 14 insertions(+) diff --git a/samples/net/sockets/coap_server/prj.conf b/samples/net/sockets/coap_server/prj.conf index e9ff24577b7..1a26e614786 100644 --- a/samples/net/sockets/coap_server/prj.conf +++ b/samples/net/sockets/coap_server/prj.conf @@ -13,6 +13,7 @@ CONFIG_COAP=y CONFIG_COAP_SERVER=y CONFIG_COAP_SERVER_WELL_KNOWN_CORE=y CONFIG_COAP_WELL_KNOWN_BLOCK_WISE=n +CONFIG_COAP_OBSERVER_EVENTS=y # Kernel options CONFIG_ENTROPY_GENERATOR=y diff --git a/samples/net/sockets/coap_server/src/observer.c b/samples/net/sockets/coap_server/src/observer.c index 6d39536e232..29b7b4ed472 100644 --- a/samples/net/sockets/coap_server/src/observer.c +++ b/samples/net/sockets/coap_server/src/observer.c @@ -17,6 +17,16 @@ static int obs_counter; static void update_counter(struct k_work *work); K_WORK_DELAYABLE_DEFINE(obs_work, update_counter); +#ifdef CONFIG_COAP_OBSERVER_EVENTS + +static void observer_event(struct coap_resource *resource, struct coap_observer *observer, + enum coap_observer_event event) +{ + LOG_INF("Observer %s", event == COAP_OBSERVER_ADDED ? "added" : "removed"); +} + +#endif + static int send_notification_packet(struct coap_resource *resource, const struct sockaddr *addr, socklen_t addr_len, @@ -128,6 +138,9 @@ COAP_RESOURCE_DEFINE(obs, coap_server, .get = obs_get, .path = obs_path, .notify = obs_notify, +#ifdef CONFIG_COAP_OBSERVER_EVENTS + .observer_event_handler = observer_event, +#endif }); static void update_counter(struct k_work *work) From 3789b2eb5738d3f1e4f62c002685e5079c8a97fe Mon Sep 17 00:00:00 2001 From: Robert Lubos Date: Tue, 6 Feb 2024 11:07:15 +0100 Subject: [PATCH 3576/3723] Revert "[nrf fromtree] net: lwm2m: device object: optionally store error list in settings" This reverts commit ac786725181640eaabd87a07b8b81064a4410101. Signed-off-by: Robert Lubos --- subsys/net/lib/lwm2m/Kconfig | 7 -- subsys/net/lib/lwm2m/lwm2m_obj_device.c | 106 ++---------------------- 2 files changed, 8 insertions(+), 105 deletions(-) diff --git a/subsys/net/lib/lwm2m/Kconfig b/subsys/net/lib/lwm2m/Kconfig index 1e5a7ac8f6a..dd3c0c45618 100644 --- a/subsys/net/lib/lwm2m/Kconfig +++ b/subsys/net/lib/lwm2m/Kconfig @@ -392,13 +392,6 @@ config LWM2M_COMPOSITE_PATH_LIST_SIZE help Define path list size for Composite Read and send operation. -config LWM2M_DEVICE_ERROR_CODE_SETTINGS - bool "Use settings to store error codes across device resets" - depends on SETTINGS - help - Store the device error code list in settings. Ensures error list can - be transferred to LwM2M server even if the device is reset. - config LWM2M_DEVICE_PWRSRC_MAX int "Maximum # of device power source records" default 5 diff --git a/subsys/net/lib/lwm2m/lwm2m_obj_device.c b/subsys/net/lib/lwm2m/lwm2m_obj_device.c index 9416b3cf92c..7df9df03a93 100644 --- a/subsys/net/lib/lwm2m/lwm2m_obj_device.c +++ b/subsys/net/lib/lwm2m/lwm2m_obj_device.c @@ -1,7 +1,6 @@ /* * Copyright (c) 2017 Linaro Limited * Copyright (c) 2018-2019 Foundries.io - * Copyright (c) 2023 FTP Technologies * * SPDX-License-Identifier: Apache-2.0 */ @@ -20,7 +19,6 @@ LOG_MODULE_REGISTER(LOG_MODULE_NAME); #include #include #include -#include #include "lwm2m_object.h" #include "lwm2m_engine.h" @@ -131,12 +129,10 @@ static struct lwm2m_engine_res_inst res_inst[RESOURCE_INSTANCE_COUNT]; /* save error code resource instance point so we can easily clear later */ static struct lwm2m_engine_res_inst *error_code_ri; -#define SETTINGS_SUBTREE_LWM2M_OBJ_DEVICE "lwm2m_obj_dev" -#define ERROR_LIST_KEY "err" - /* callbacks */ -static void reset_error_list(void) +static int reset_error_list_cb(uint16_t obj_inst_id, + uint8_t *args, uint16_t args_len) { int i; @@ -148,29 +144,8 @@ static void reset_error_list(void) /* Default error code indicating no error */ error_code_ri[0].res_inst_id = 0; -} - -static int reset_error_list_cb(uint16_t obj_inst_id, - uint8_t *args, uint16_t args_len) -{ - int ret = 0; - - ARG_UNUSED(obj_inst_id); - ARG_UNUSED(args); - ARG_UNUSED(args_len); - - reset_error_list(); - lwm2m_notify_observer(LWM2M_OBJECT_DEVICE_ID, 0, DEVICE_ERROR_CODE_ID); - - if (IS_ENABLED(CONFIG_LWM2M_DEVICE_ERROR_CODE_SETTINGS)) { - ret = settings_delete(SETTINGS_SUBTREE_LWM2M_OBJ_DEVICE "/" ERROR_LIST_KEY); - if (ret != 0) { - LOG_ERR("Couldn't save error list: %d", ret); - } - } - - return ret; + return 0; } static void *current_time_read_cb(uint16_t obj_inst_id, uint16_t res_id, @@ -207,9 +182,9 @@ static int current_time_post_write_cb(uint16_t obj_inst_id, uint16_t res_id, } /* error code function */ + int lwm2m_device_add_err(uint8_t error_code) { - int ret = 0; int i; for (i = 0; i < DEVICE_ERROR_CODE_MAX; i++) { @@ -231,15 +206,7 @@ int lwm2m_device_add_err(uint8_t error_code) error_code_ri[i].res_inst_id = i; lwm2m_notify_observer(LWM2M_OBJECT_DEVICE_ID, 0, DEVICE_ERROR_CODE_ID); - if (IS_ENABLED(CONFIG_LWM2M_DEVICE_ERROR_CODE_SETTINGS)) { - ret = settings_save_one(SETTINGS_SUBTREE_LWM2M_OBJ_DEVICE "/" ERROR_LIST_KEY, - error_code_list, i + 1); - if (ret != 0) { - LOG_ERR("Couldn't save error list: %d", ret); - } - } - - return ret; + return 0; } static void device_periodic_service(struct k_work *work) @@ -252,49 +219,6 @@ int lwm2m_update_device_service_period(uint32_t period_ms) return lwm2m_engine_update_service_period(device_periodic_service, period_ms); } -static int lwm2m_obj_device_settings_set(const char *name, size_t len, - settings_read_cb read_cb, void *cb_arg) -{ - const char *next; - int rc; - int i; - - if (settings_name_steq(name, ERROR_LIST_KEY, &next) && !next) { - if (len > sizeof(error_code_list)) { - LOG_ERR("Error code list too large: %u", len); - return -EINVAL; - } - - rc = read_cb(cb_arg, error_code_list, sizeof(error_code_list)); - if (rc == 0) { - reset_error_list(); - return 0; - } else if (rc > 0) { - for (i = 0; i < ARRAY_SIZE(error_code_list); i++) { - if (i < rc) { - error_code_ri[i].res_inst_id = i; - } else { - /* Reset remaining error code instances */ - error_code_list[i] = LWM2M_DEVICE_ERROR_NONE; - error_code_ri[i].res_inst_id = RES_INSTANCE_NOT_CREATED; - } - } - return 0; - } - - LOG_ERR("Error code list read failure: %d", rc); - - return rc; - } - - return -ENOENT; -} - -static struct settings_handler lwm2m_obj_device_settings_handler = { - .name = SETTINGS_SUBTREE_LWM2M_OBJ_DEVICE, - .h_set = lwm2m_obj_device_settings_set, -}; - static struct lwm2m_engine_obj_inst *device_create(uint16_t obj_inst_id) { int i = 0, j = 0; @@ -347,7 +271,7 @@ static struct lwm2m_engine_obj_inst *device_create(uint16_t obj_inst_id) static int lwm2m_device_init(void) { struct lwm2m_engine_obj_inst *obj_inst = NULL; - int ret; + int ret = 0; /* Set default values */ time_offset = 0U; @@ -370,26 +294,12 @@ static int lwm2m_device_init(void) LOG_DBG("Create LWM2M instance 0 error: %d", ret); } - /* Ensure error list is reset if not loaded from settings */ - reset_error_list(); - - /* Load error code resource instances */ - if (IS_ENABLED(CONFIG_LWM2M_DEVICE_ERROR_CODE_SETTINGS)) { - ret = settings_register(&lwm2m_obj_device_settings_handler); - if (ret == 0) { - ret = settings_load_subtree(SETTINGS_SUBTREE_LWM2M_OBJ_DEVICE); - if (ret != 0) { - LOG_ERR("Settings load failed: %d", ret); - } - } else { - LOG_ERR("Settings register failed: %d", ret); - } - } + /* Create the default error code resource instance */ + lwm2m_device_add_err(0); /* call device_periodic_service() every 10 seconds */ ret = lwm2m_engine_add_service(device_periodic_service, DEVICE_SERVICE_INTERVAL_MS); - return ret; } From ec53c19b7a322717af16ae515b40a72a2fe83a79 Mon Sep 17 00:00:00 2001 From: Robert Lubos Date: Tue, 6 Feb 2024 11:07:16 +0100 Subject: [PATCH 3577/3723] Revert "[nrf fromtree] net: lwm2m: device object: use LWM2M_DEVICE_ERROR_NONE" This reverts commit 789fd359bd995a28bcfbeca023b98393b23655a5. Signed-off-by: Robert Lubos --- subsys/net/lib/lwm2m/lwm2m_obj_device.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/subsys/net/lib/lwm2m/lwm2m_obj_device.c b/subsys/net/lib/lwm2m/lwm2m_obj_device.c index 7df9df03a93..c17815795c2 100644 --- a/subsys/net/lib/lwm2m/lwm2m_obj_device.c +++ b/subsys/net/lib/lwm2m/lwm2m_obj_device.c @@ -89,7 +89,7 @@ LOG_MODULE_REGISTER(LOG_MODULE_NAME); DEVICE_EXT_DEV_INFO_MAX) /* resource state variables */ -static uint8_t error_code_list[DEVICE_ERROR_CODE_MAX] = { LWM2M_DEVICE_ERROR_NONE }; +static uint8_t error_code_list[DEVICE_ERROR_CODE_MAX]; static time_t time_temp; static time_t time_offset; static uint8_t binding_mode[DEVICE_STRING_SHORT]; @@ -138,7 +138,7 @@ static int reset_error_list_cb(uint16_t obj_inst_id, /* "delete" error codes */ for (i = 0; i < DEVICE_ERROR_CODE_MAX; i++) { - error_code_list[i] = LWM2M_DEVICE_ERROR_NONE; + error_code_list[i] = 0; error_code_ri[i].res_inst_id = RES_INSTANCE_NOT_CREATED; } @@ -188,7 +188,7 @@ int lwm2m_device_add_err(uint8_t error_code) int i; for (i = 0; i < DEVICE_ERROR_CODE_MAX; i++) { - if (error_code_list[i] == LWM2M_DEVICE_ERROR_NONE) { + if (error_code_list[i] == 0) { break; } From 2470b5c198f82f69510d2c7cc2651587e182a5d7 Mon Sep 17 00:00:00 2001 From: Robert Lubos Date: Tue, 6 Feb 2024 11:07:16 +0100 Subject: [PATCH 3578/3723] Revert "[nrf fromtree] test: lwm2m: Refactor tests to work with fallback changes" This reverts commit 1b26dba2528d3ba817bce40d0d5d95e312fdb977. Signed-off-by: Robert Lubos --- .../net/lib/lwm2m/interop/pytest/conftest.py | 34 ++++--------------- .../lib/lwm2m/interop/pytest/test_lwm2m.py | 9 +++-- 2 files changed, 10 insertions(+), 33 deletions(-) diff --git a/tests/net/lib/lwm2m/interop/pytest/conftest.py b/tests/net/lib/lwm2m/interop/pytest/conftest.py index 7d3ea4e7f80..9ca971b85c7 100644 --- a/tests/net/lib/lwm2m/interop/pytest/conftest.py +++ b/tests/net/lib/lwm2m/interop/pytest/conftest.py @@ -27,25 +27,6 @@ logger = logging.getLogger(__name__) -class Endpoint: - def __init__(self, name: str, shell: Shell, registered: bool = False, bootstrap: bool = False): - self.name = name - self.registered = registered - self.bootstrap = bootstrap - self.shell = shell - self.last_update = 0.0 - - def check_update(self): - if not self.registered: - return - if self.last_update < time.time() - 5: - self.shell.exec_command('lwm2m update') - self.last_update = time.time() - - def __str__(self): - return self.name - - @pytest.fixture(scope='session') def leshan() -> Leshan: """ @@ -108,8 +89,9 @@ def endpoint_nosec(shell: Shell, dut: DeviceAdapter, leshan: Leshan) -> str: shell.exec_command('lwm2m write 1/0/0 -u16 1') shell.exec_command('lwm2m write 1/0/1 -u32 86400') shell.exec_command(f'lwm2m start {ep} -b 0') + dut.readlines_until(regex=f"RD Client started with endpoint '{ep}'", timeout=10.0) - yield Endpoint(ep, shell) + yield ep # All done shell.exec_command('lwm2m stop') @@ -143,7 +125,7 @@ def endpoint_bootstrap(shell: Shell, dut: DeviceAdapter, leshan: Leshan, leshan_ shell.exec_command(f'lwm2m write 0/0/5 -s {bs_passwd}') shell.exec_command(f'lwm2m start {ep} -b 1') - yield Endpoint(ep, shell) + yield ep shell.exec_command('lwm2m stop') dut.readlines_until(regex=r'.*Deregistration success', timeout=10.0) @@ -155,16 +137,12 @@ def endpoint_bootstrap(shell: Shell, dut: DeviceAdapter, leshan: Leshan, leshan_ leshan_bootstrap.delete_bs_device(ep) @pytest.fixture(scope='module') -def endpoint_registered(endpoint_bootstrap, dut: DeviceAdapter) -> str: +def endpoint_registered(endpoint_bootstrap, shell: Shell, dut: DeviceAdapter) -> str: """Fixture that returns an endpoint that is registered.""" - if not endpoint_bootstrap.registered: - dut.readlines_until(regex='.*Registration Done', timeout=5.0) - endpoint_bootstrap.bootstrap = True - endpoint_bootstrap.registered = True + dut.readlines_until(regex='.*Registration Done', timeout=5.0) return endpoint_bootstrap -@pytest.fixture(scope='function') +@pytest.fixture(scope='module') def endpoint(endpoint_registered) -> str: """Fixture that returns an endpoint that is registered.""" - endpoint_registered.check_update() return endpoint_registered diff --git a/tests/net/lib/lwm2m/interop/pytest/test_lwm2m.py b/tests/net/lib/lwm2m/interop/pytest/test_lwm2m.py index ed7aaceac20..131acb68e14 100644 --- a/tests/net/lib/lwm2m/interop/pytest/test_lwm2m.py +++ b/tests/net/lib/lwm2m/interop/pytest/test_lwm2m.py @@ -171,7 +171,6 @@ def verify_setting_basic_in_format(shell, leshan, endpoint, format): verify_server_object(server_obj) # Remove Read-Only resources, so we don't end up writing those del server_obj[0][0] - del server_obj[0][13] data = { 2: 101, 3: 1010, @@ -209,7 +208,7 @@ def test_LightweightM2M_1_1_int_222(shell: Shell, leshan: Leshan, endpoint: str) """LightweightM2M-1.1-int-222 - Read on Object""" resp = leshan.read(endpoint, '1') assert len(resp) == 1 - assert len(resp[1][0]) == 11 + assert len(resp[1][0]) == 9 resp = leshan.read(endpoint, '3') assert len(resp) == 1 assert len(resp[3]) == 1 @@ -219,7 +218,7 @@ def test_LightweightM2M_1_1_int_222(shell: Shell, leshan: Leshan, endpoint: str) def test_LightweightM2M_1_1_int_223(shell: Shell, leshan: Leshan, endpoint: str): """LightweightM2M-1.1-int-223 - Read on Object Instance""" resp = leshan.read(endpoint, '1/0') - assert len(resp[0]) == 11 + assert len(resp[0]) == 9 resp = leshan.read(endpoint, '3/0') assert len(resp[0]) == 15 assert resp[0][0] == 'Zephyr' @@ -283,7 +282,7 @@ def test_LightweightM2M_1_1_int_229(shell: Shell, leshan: Leshan, endpoint: str) assert resp[3] is not None assert resp[1][0] is not None assert len(resp[3][0]) == 15 - assert len(resp[1][0]) == 11 + assert len(resp[1][0]) == 9 resp = leshan.composite_read(endpoint, ['1/0/1', '/3/0/11/0']) logger.debug(resp) @@ -371,7 +370,7 @@ def test_LightweightM2M_1_1_int_234(shell: Shell, leshan: Leshan, endpoint: str) def test_LightweightM2M_1_1_int_235(leshan: Leshan, endpoint: str): """LightweightM2M-1.1-int-235 - Read-Composite Operation on root path""" resp = leshan.composite_read(endpoint, ['/']) - expected_keys = [1, 3, 5] + expected_keys = [16, 1, 3, 5] missing_keys = [key for key in expected_keys if key not in resp.keys()] assert len(missing_keys) == 0 From 1a5ae365fe70c9334141884ce3061b47a5cc30ea Mon Sep 17 00:00:00 2001 From: Robert Lubos Date: Tue, 6 Feb 2024 11:07:16 +0100 Subject: [PATCH 3579/3723] Revert "[nrf fromtree] net: lwm2m: Implement fallback mechanism and support for diable" This reverts commit c673375d64d8df0b2777168cba4ebfdabfbd7c87. Signed-off-by: Robert Lubos --- include/zephyr/net/lwm2m.h | 1 - samples/net/lwm2m_client/src/lwm2m-client.c | 4 - subsys/net/lib/lwm2m/lwm2m_obj_server.c | 18 +- subsys/net/lib/lwm2m/lwm2m_rd_client.c | 421 +++++++----------- subsys/net/lib/lwm2m/lwm2m_rd_client.h | 10 - .../net/lib/lwm2m/interop/src/lwm2m-client.c | 4 - .../net/lib/lwm2m/lwm2m_rd_client/src/main.c | 201 ++------- .../net/lib/lwm2m/lwm2m_rd_client/src/stubs.c | 22 - .../net/lib/lwm2m/lwm2m_rd_client/src/stubs.h | 9 +- 9 files changed, 195 insertions(+), 495 deletions(-) diff --git a/include/zephyr/net/lwm2m.h b/include/zephyr/net/lwm2m.h index 6ac0458af87..a57b5542f88 100644 --- a/include/zephyr/net/lwm2m.h +++ b/include/zephyr/net/lwm2m.h @@ -2075,7 +2075,6 @@ enum lwm2m_rd_client_event { LWM2M_RD_CLIENT_EVENT_NETWORK_ERROR, LWM2M_RD_CLIENT_EVENT_REG_UPDATE, LWM2M_RD_CLIENT_EVENT_DEREGISTER, - LWM2M_RD_CLIENT_EVENT_SERVER_DISABLED, }; /** diff --git a/samples/net/lwm2m_client/src/lwm2m-client.c b/samples/net/lwm2m_client/src/lwm2m-client.c index c610f1ad8dd..a120506639d 100644 --- a/samples/net/lwm2m_client/src/lwm2m-client.c +++ b/samples/net/lwm2m_client/src/lwm2m-client.c @@ -191,10 +191,6 @@ static void rd_client_event(struct lwm2m_ctx *client, /* do nothing */ break; - case LWM2M_RD_CLIENT_EVENT_SERVER_DISABLED: - LOG_DBG("LwM2M server disabled"); - break; - case LWM2M_RD_CLIENT_EVENT_BOOTSTRAP_REG_FAILURE: LOG_DBG("Bootstrap registration failure!"); break; diff --git a/subsys/net/lib/lwm2m/lwm2m_obj_server.c b/subsys/net/lib/lwm2m/lwm2m_obj_server.c index a9432340038..10c7a1a1ea0 100644 --- a/subsys/net/lib/lwm2m/lwm2m_obj_server.c +++ b/subsys/net/lib/lwm2m/lwm2m_obj_server.c @@ -95,21 +95,13 @@ static struct lwm2m_engine_res_inst static int disable_cb(uint16_t obj_inst_id, uint8_t *args, uint16_t args_len) { - ARG_UNUSED(args); - ARG_UNUSED(args_len); - - int ret; + int i; - for (int i = 0; i < MAX_INSTANCE_COUNT; i++) { + LOG_DBG("DISABLE %d", obj_inst_id); + for (i = 0; i < MAX_INSTANCE_COUNT; i++) { if (inst[i].obj && inst[i].obj_inst_id == obj_inst_id) { - LOG_DBG("DISABLE %d", obj_inst_id); - ret = lwm2m_rd_client_server_disabled(obj_inst_id); - if (ret == 0) { - disabled_until[i] = - sys_timepoint_calc(K_SECONDS(disabled_timeout[i])); - return 0; - } - return ret; + disabled_until[i] = sys_timepoint_calc(K_SECONDS(disabled_timeout[i])); + return 0; } } diff --git a/subsys/net/lib/lwm2m/lwm2m_rd_client.c b/subsys/net/lib/lwm2m/lwm2m_rd_client.c index 6b3fbcccc68..6eacba0ee0d 100644 --- a/subsys/net/lib/lwm2m/lwm2m_rd_client.c +++ b/subsys/net/lib/lwm2m/lwm2m_rd_client.c @@ -72,7 +72,6 @@ LOG_MODULE_REGISTER(LOG_MODULE_NAME); #define DELAY_FOR_ACK 100U #define EXCHANGE_LIFETIME 247U #define MINIMUM_PERIOD 15 -#define DISABLE_TIMEOUT (K_SECONDS(CONFIG_LWM2M_RD_CLIENT_MAX_RETRIES * EXCHANGE_LIFETIME)) static void sm_handle_registration_update_failure(void); static int sm_send_registration_msg(void); @@ -81,8 +80,6 @@ static void lwm2m_rd_client_service(struct k_work *work); static int64_t calc_next_event(void); static void set_sm_state_delayed(uint8_t sm_state, int64_t delay_ms); static void set_sm_state(uint8_t sm_state); -/** Try to fallback to bootstrap. Return true if we did. */ -static bool fallback_to_bootstrap(void); /* The states for the RD client state machine */ /* @@ -104,7 +101,6 @@ enum sm_engine_state { ENGINE_REGISTRATION_DONE_RX_OFF, ENGINE_UPDATE_REGISTRATION, ENGINE_UPDATE_SENT, - ENGINE_SERVER_DISABLED, ENGINE_SUSPENDED, ENGINE_DEREGISTER, ENGINE_DEREGISTER_SENT, @@ -129,11 +125,11 @@ struct lwm2m_rd_client_info { char ep_name[CLIENT_EP_LEN]; char server_ep[CLIENT_EP_LEN]; - bool use_bootstrap : 1; + bool use_bootstrap : 1; + bool trigger_update : 1; bool update_objects : 1; - bool close_socket : 1; - bool server_disabled: 1; + bool close_socket : 1; } client; /* Allocate some data for queries and updates. Make sure it's large enough to @@ -205,18 +201,23 @@ static void set_sm_state_delayed(uint8_t sm_state, int64_t delay_ms) event = LWM2M_RD_CLIENT_EVENT_REGISTRATION_COMPLETE; } else if (sm_state == ENGINE_REGISTRATION_DONE_RX_OFF) { event = LWM2M_RD_CLIENT_EVENT_QUEUE_MODE_RX_OFF; - } else if (sm_state == ENGINE_DEREGISTERED && + } else if ((sm_state == ENGINE_INIT || + sm_state == ENGINE_DEREGISTERED) && (client.engine_state >= ENGINE_DO_REGISTRATION && - client.engine_state <= ENGINE_DEREGISTER_SENT) && !client.server_disabled) { + client.engine_state <= ENGINE_DEREGISTER_SENT)) { event = LWM2M_RD_CLIENT_EVENT_DISCONNECT; + } else if (sm_state == ENGINE_NETWORK_ERROR) { + lwm2m_socket_close(client.ctx); + client.retry_delay = 1 << client.retries; + client.retries++; + if (client.retries > CONFIG_LWM2M_RD_CLIENT_MAX_RETRIES) { + client.retries = 0; + event = LWM2M_RD_CLIENT_EVENT_NETWORK_ERROR; + } } else if (sm_state == ENGINE_UPDATE_REGISTRATION) { event = LWM2M_RD_CLIENT_EVENT_REG_UPDATE; } else if (sm_state == ENGINE_DEREGISTER) { - if (client.server_disabled) { - event = LWM2M_RD_CLIENT_EVENT_SERVER_DISABLED; - } else { - event = LWM2M_RD_CLIENT_EVENT_DEREGISTER; - } + event = LWM2M_RD_CLIENT_EVENT_DEREGISTER; } if (sm_is_suspended()) { @@ -291,22 +292,27 @@ static uint8_t get_sm_state(void) return state; } -static void sm_handle_timeout_state(enum sm_engine_state sm_state) +static void sm_handle_timeout_state(struct lwm2m_message *msg, + enum sm_engine_state sm_state) { k_mutex_lock(&client.mutex, K_FOREVER); enum lwm2m_rd_client_event event = LWM2M_RD_CLIENT_EVENT_NONE; - /* Don't send BOOTSTRAP_REG_FAILURE event, that is only emitted from - * do_network_error() once we are out of retries. - */ - if (client.engine_state == ENGINE_REGISTRATION_SENT) { - event = LWM2M_RD_CLIENT_EVENT_REG_TIMEOUT; - } else if (client.engine_state == ENGINE_UPDATE_SENT) { - event = LWM2M_RD_CLIENT_EVENT_REG_TIMEOUT; - } else if (client.engine_state == ENGINE_DEREGISTER_SENT) { - event = LWM2M_RD_CLIENT_EVENT_DEREGISTER_FAILURE; - } else { - /* TODO: unknown timeout state */ +#if defined(CONFIG_LWM2M_RD_CLIENT_SUPPORT_BOOTSTRAP) + if (client.engine_state == ENGINE_BOOTSTRAP_REG_SENT) { + event = LWM2M_RD_CLIENT_EVENT_BOOTSTRAP_REG_FAILURE; + } else +#endif + { + if (client.engine_state == ENGINE_REGISTRATION_SENT) { + event = LWM2M_RD_CLIENT_EVENT_REG_TIMEOUT; + } else if (client.engine_state == ENGINE_UPDATE_SENT) { + event = LWM2M_RD_CLIENT_EVENT_REG_TIMEOUT; + } else if (client.engine_state == ENGINE_DEREGISTER_SENT) { + event = LWM2M_RD_CLIENT_EVENT_DEREGISTER_FAILURE; + } else { + /* TODO: unknown timeout state */ + } } set_sm_state(sm_state); @@ -368,14 +374,11 @@ static void socket_fault_cb(int error) /* Network error state causes engine to re-register, * so only trigger that state if we are not stopping the * engine. - * Also when engine is going to be disabled, for a while, we might get spurious - * socket errors when closing, so ignore them. */ if (client.engine_state > ENGINE_IDLE && - client.engine_state < ENGINE_SERVER_DISABLED) { - sm_handle_timeout_state(ENGINE_NETWORK_ERROR); - } else if (client.engine_state != ENGINE_SUSPENDED && - !client.server_disabled) { + client.engine_state < ENGINE_SUSPENDED) { + set_sm_state(ENGINE_NETWORK_ERROR); + } else if (client.engine_state != ENGINE_SUSPENDED) { sm_handle_failure_state(ENGINE_IDLE); } } @@ -450,7 +453,13 @@ static int do_bootstrap_reply_cb(const struct coap_packet *response, static void do_bootstrap_reg_timeout_cb(struct lwm2m_message *msg) { LOG_WRN("Bootstrap Timeout"); - sm_handle_timeout_state(ENGINE_NETWORK_ERROR); + + /* TODO: + * Look for the "next" BOOTSTRAP server entry in our security info + */ + + /* Restart from scratch */ + sm_handle_timeout_state(msg, ENGINE_INIT); } #endif @@ -513,8 +522,6 @@ static int do_registration_reply_cb(const struct coap_packet *response, /* remember the last reg time */ client.last_update = k_uptime_get(); - client.server_disabled = false; - client.retries = 0; memcpy(client.server_ep, options[1].value, options[1].len); @@ -526,12 +533,11 @@ static int do_registration_reply_cb(const struct coap_packet *response, return 0; } - LOG_ERR("Failed with code %u.%u (%s).", + LOG_ERR("Failed with code %u.%u (%s). Not Retrying.", COAP_RESPONSE_CODE_CLASS(code), COAP_RESPONSE_CODE_DETAIL(code), code2str(code)); fail: - lwm2m_server_disable(client.ctx->srv_obj_inst, DISABLE_TIMEOUT); - sm_handle_failure_state(ENGINE_NETWORK_ERROR); + sm_handle_failure_state(ENGINE_IDLE); return ret; } @@ -540,7 +546,8 @@ static void do_registration_timeout_cb(struct lwm2m_message *msg) { LOG_WRN("Registration Timeout"); - sm_handle_timeout_state(ENGINE_NETWORK_ERROR); + /* Restart from scratch */ + sm_handle_timeout_state(msg, ENGINE_INIT); } static int do_update_reply_cb(const struct coap_packet *response, @@ -581,7 +588,7 @@ static void do_update_timeout_cb(struct lwm2m_message *msg) client.close_socket = true; } /* Re-do registration */ - sm_handle_timeout_state(ENGINE_DO_REGISTRATION); + sm_handle_timeout_state(msg, ENGINE_DO_REGISTRATION); } static int do_deregister_reply_cb(const struct coap_packet *response, @@ -605,7 +612,7 @@ static int do_deregister_reply_cb(const struct coap_packet *response, COAP_RESPONSE_CODE_CLASS(code), COAP_RESPONSE_CODE_DETAIL(code), code2str(code)); - sm_handle_failure_state(ENGINE_DEREGISTERED); + sm_handle_failure_state(ENGINE_IDLE); return 0; } @@ -614,10 +621,10 @@ static void do_deregister_timeout_cb(struct lwm2m_message *msg) { LOG_WRN("De-Registration Timeout"); - sm_handle_timeout_state(ENGINE_DEREGISTERED); + sm_handle_timeout_state(msg, ENGINE_IDLE); } -static bool is_bootsrap_server(int sec_obj_inst) +static bool sm_bootstrap_verify(bool bootstrap_server, int sec_obj_inst) { bool bootstrap; int ret; @@ -627,7 +634,12 @@ static bool is_bootsrap_server(int sec_obj_inst) LOG_WRN("Failed to check bootstrap, err %d", ret); return false; } - return bootstrap; + + if (bootstrap == bootstrap_server) { + return true; + } else { + return false; + } } static bool sm_update_lifetime(int srv_obj_inst, uint32_t *lifetime) @@ -653,40 +665,58 @@ static bool sm_update_lifetime(int srv_obj_inst, uint32_t *lifetime) return false; } -/** - * @brief Find the next security instance for bootstrapping. - * - * Search for the next security instance that has the bootstrap flag set and - * is not the same as current security instance. - * - * @param sec_obj_inst current security instance or -1. - * @return zero on success, negative on error. - */ -static int sm_next_bootstrap_inst(int *sec_obj_inst) +static int sm_select_server_inst(int sec_obj_inst, int *srv_obj_inst, + uint32_t *lifetime) +{ + uint16_t server_id; + int ret, obj_inst_id; + + ret = lwm2m_get_u16(&LWM2M_OBJ(0, sec_obj_inst, 10), &server_id); + if (ret < 0) { + LOG_WRN("Failed to obtain Short Server ID, err %d", ret); + return -EINVAL; + } + + obj_inst_id = lwm2m_server_short_id_to_inst(server_id); + if (obj_inst_id < 0) { + LOG_WRN("Failed to obtain Server Object instance, err %d", + obj_inst_id); + return -EINVAL; + } + + sm_update_lifetime(obj_inst_id, lifetime); + *srv_obj_inst = obj_inst_id; + + return 0; +} + +static int sm_select_security_inst(bool bootstrap_server, int *sec_obj_inst) { int i, obj_inst_id = -1; - if (*sec_obj_inst >= 0 && !is_bootsrap_server(*sec_obj_inst)) { - *sec_obj_inst = -1; + /* lookup existing index */ + i = lwm2m_security_inst_id_to_index(*sec_obj_inst); + if (i >= 0 && sm_bootstrap_verify(bootstrap_server, *sec_obj_inst)) { + return 0; } + *sec_obj_inst = -1; + /* Iterate over all instances to find the correct one. */ for (i = 0; i < CONFIG_LWM2M_SECURITY_INSTANCE_COUNT; i++) { obj_inst_id = lwm2m_security_index_to_inst_id(i); if (obj_inst_id < 0) { - continue; - } - if (obj_inst_id == *sec_obj_inst) { + LOG_WRN("Failed to get inst id for %d", i); continue; } - if (is_bootsrap_server(obj_inst_id)) { + if (sm_bootstrap_verify(bootstrap_server, obj_inst_id)) { *sec_obj_inst = obj_inst_id; return 0; } } - LOG_WRN("No Bootstrap servers found."); + LOG_WRN("sec_obj_inst: No matching servers found."); return -ENOENT; } @@ -696,17 +726,24 @@ static int sm_next_bootstrap_inst(int *sec_obj_inst) static int sm_do_init(void) { lwm2m_engine_stop(client.ctx); + client.ctx->sec_obj_inst = -1; + client.ctx->srv_obj_inst = -1; client.trigger_update = false; client.lifetime = 0U; + client.retries = 0U; client.last_update = 0U; client.close_socket = false; /* Do bootstrap or registration */ - if (client.use_bootstrap && IS_ENABLED(CONFIG_LWM2M_RD_CLIENT_SUPPORT_BOOTSTRAP)) { +#if defined(CONFIG_LWM2M_RD_CLIENT_SUPPORT_BOOTSTRAP) + if (client.use_bootstrap) { set_sm_state(ENGINE_DO_BOOTSTRAP_REG); } else { set_sm_state(ENGINE_DO_REGISTRATION); } +#else + set_sm_state(ENGINE_DO_REGISTRATION); +#endif return 0; } @@ -777,7 +814,7 @@ static int sm_send_bootstrap_registration(void) return ret; } -static void sm_do_bootstrap_reg(void) +static int sm_do_bootstrap_reg(void) { int ret; @@ -787,20 +824,23 @@ static void sm_do_bootstrap_reg(void) } client.ctx->bootstrap_mode = true; - ret = sm_next_bootstrap_inst(&client.ctx->sec_obj_inst); + ret = sm_select_security_inst(client.ctx->bootstrap_mode, + &client.ctx->sec_obj_inst); if (ret < 0) { - set_sm_state(ENGINE_NETWORK_ERROR); - return; + /* no bootstrap server found, let's move to registration */ + LOG_WRN("Bootstrap server not found! Try normal registration."); + set_sm_state(ENGINE_DO_REGISTRATION); + return ret; } - LOG_INF("Bootstrap started with endpoint '%s' using security object %d", - client.ep_name, client.ctx->sec_obj_inst); + LOG_INF("Bootstrap started with endpoint '%s' with client lifetime %d", + client.ep_name, client.lifetime); ret = lwm2m_engine_start(client.ctx); if (ret < 0) { LOG_ERR("Cannot init LWM2M engine (%d)", ret); set_sm_state(ENGINE_NETWORK_ERROR); - return; + return ret; } ret = sm_send_bootstrap_registration(); @@ -811,7 +851,7 @@ static void sm_do_bootstrap_reg(void) set_sm_state(ENGINE_NETWORK_ERROR); } - return; + return ret; } void engine_bootstrap_finish(void) @@ -1007,9 +1047,8 @@ static int sm_send_registration_msg(void) return ret; } -static void sm_do_registration(void) +static int sm_do_registration(void) { - uint16_t ssid; int ret = 0; if (client.ctx->connection_suspended) { @@ -1017,16 +1056,10 @@ static void sm_do_registration(void) lwm2m_engine_context_close(client.ctx); /* perform full registration */ set_sm_state(ENGINE_DO_REGISTRATION); - return; + return 0; } } else { - bool select_srv = true; - uint16_t srv = (uint16_t) client.ctx->srv_obj_inst; - - client.last_update = 0; - client.ctx->bootstrap_mode = false; - /* clear out existing connection data */ if (client.ctx->sock_fd > -1) { if (client.close_socket) { @@ -1035,58 +1068,43 @@ static void sm_do_registration(void) lwm2m_engine_stop(client.ctx); } else { lwm2m_engine_context_close(client.ctx); - /* Keep current connection, retry registration with same server */ - select_srv = false; } } - if (select_srv) { - /* Select next one from the list, or fail */ - if (!lwm2m_server_select(&srv)) { - LOG_ERR("Unable to find a valid server instance."); - goto bootstrap_or_retry; - } - - client.ctx->srv_obj_inst = srv; - sm_update_lifetime(srv, &client.lifetime); + client.last_update = 0; - ret = lwm2m_get_u16(&LWM2M_OBJ(1, client.ctx->srv_obj_inst, 0), &ssid); - if (ret < 0) { - LOG_ERR("Failed to read SSID"); - lwm2m_server_disable(srv, K_FOREVER); - goto bootstrap_or_retry; - } + client.ctx->bootstrap_mode = false; + ret = sm_select_security_inst(client.ctx->bootstrap_mode, + &client.ctx->sec_obj_inst); + if (ret < 0) { + LOG_ERR("Unable to find a valid security instance."); + set_sm_state(ENGINE_INIT); + return -EINVAL; + } - ret = lwm2m_security_short_id_to_inst(ssid); - if (ret < 0) { - LOG_ERR("Unable to find a valid security instance."); - lwm2m_server_disable(srv, K_FOREVER); - goto bootstrap_or_retry; - } - client.ctx->sec_obj_inst = (uint16_t) ret; + ret = sm_select_server_inst(client.ctx->sec_obj_inst, + &client.ctx->srv_obj_inst, + &client.lifetime); + if (ret < 0) { + LOG_ERR("Unable to find a valid server instance."); + set_sm_state(ENGINE_INIT); + return -EINVAL; } - LOG_INF("RD Client started with endpoint '%s' with client lifetime %d using server " - "object %d", - client.ep_name, client.lifetime, client.ctx->srv_obj_inst); + LOG_INF("RD Client started with endpoint '%s' with client lifetime %d", + client.ep_name, client.lifetime); ret = lwm2m_engine_start(client.ctx); if (ret < 0) { LOG_ERR("Cannot init LWM2M engine (%d)", ret); - goto bootstrap_or_retry; + set_sm_state(ENGINE_NETWORK_ERROR); + return ret; } } - sm_send_registration_msg(); - return; - -bootstrap_or_retry: - lwm2m_engine_stop(client.ctx); - if (!client.server_disabled && fallback_to_bootstrap()) { - return; - } + ret = sm_send_registration_msg(); - set_sm_state(ENGINE_NETWORK_ERROR); + return ret; } static int64_t next_update(void) @@ -1251,116 +1269,32 @@ static int sm_do_deregister(void) return ret; } -static bool fallback_to_bootstrap(void) -{ - if (IS_ENABLED(CONFIG_LWM2M_RD_CLIENT_SUPPORT_BOOTSTRAP)) { - bool fallback = true; - - (void)lwm2m_get_bool(&LWM2M_OBJ(LWM2M_OBJECT_SERVER_ID, client.ctx->srv_obj_inst, - SERVER_BOOTSTRAP_ON_REGISTRATION_FAILURE_ID), - &fallback); - if (fallback) { - client.use_bootstrap = true; - set_sm_state(ENGINE_INIT); - return true; - } - } - return false; -} - static void sm_do_network_error(void) { int err; - LOG_ERR("sm_do_network_error, retries %d", client.retries); - - lwm2m_socket_close(client.ctx); - if (client.retry_delay) { - next_event_at(k_uptime_get() + client.retry_delay * MSEC_PER_SEC); client.retry_delay = 0; + next_event_at(k_uptime_get() + client.retry_delay * MSEC_PER_SEC); return; } - client.retry_delay = 1 << client.retries; - client.retries++; - - /* Stop retrying and try fallback */ - if (client.retries > CONFIG_LWM2M_RD_CLIENT_MAX_RETRIES) { - LOG_ERR("Network error, max retries reached (%d)", client.retries); - /* Disable current server for a period so lwm2m_server_select() does not pick it */ - if (client.ctx->srv_obj_inst > -1) { - lwm2m_server_disable(client.ctx->srv_obj_inst, DISABLE_TIMEOUT); - } - - /* Are we in bootstrap? Try if we can fallback to some other BS server */ - if (client.ctx->bootstrap_mode && - IS_ENABLED(CONFIG_LWM2M_RD_CLIENT_SUPPORT_BOOTSTRAP)) { - LOG_DBG("In bootstrap, try fallback srv"); - /* Do we have any other bootstrap server to back off to? */ - if (sm_next_bootstrap_inst(&client.ctx->sec_obj_inst) < 0) { - /* No, we are out of options, stop engine */ - goto stop_engine; - } - set_sm_state(ENGINE_INIT); - return; - } - - /* Try if there are other server to fall back to, - * Only allow fallback to higher priority server (lower value, or lower id) - * if we have successfully registered before. - * This should block us from looping the same list again. - * Instead we should fallback to bootstrap. - */ - uint16_t srv; - - if (lwm2m_server_select(&srv)) { - uint8_t p1, p2; - - p1 = lwm2m_server_get_prio(client.ctx->srv_obj_inst); - p2 = lwm2m_server_get_prio(srv); - if (p1 < p2 || client.last_update != 0) { - set_sm_state(ENGINE_INIT); - return; - } - } - - /* If we have been disabled by some server, don't fall back to bootstrap */ - if (client.server_disabled) { - set_sm_state(ENGINE_SERVER_DISABLED); - return; - } - - if (fallback_to_bootstrap()) { - return; - } - goto stop_engine; - } - - /* Retry bootstrap */ - if (IS_ENABLED(CONFIG_LWM2M_RD_CLIENT_SUPPORT_BOOTSTRAP)) { - if (client.ctx->bootstrap_mode) { - lwm2m_engine_context_close(client.ctx); - /* If we don't have fallback BS server, retry with current one */ - if (sm_next_bootstrap_inst(&client.ctx->sec_obj_inst) < 0) { - client.ctx->sec_obj_inst = -1; - } - set_sm_state(ENGINE_DO_BOOTSTRAP_REG); - return; - } +#if defined(CONFIG_LWM2M_RD_CLIENT_SUPPORT_BOOTSTRAP) + if (client.ctx->bootstrap_mode) { + lwm2m_engine_context_close(client.ctx); + set_sm_state(ENGINE_DO_BOOTSTRAP_REG); + return; } +#endif if (!client.last_update || (k_uptime_get() - client.last_update) / MSEC_PER_SEC > client.lifetime) { /* do full registration as there is no active registration or lifetime exceeded */ - /* Keep the same server until out of retry */ + lwm2m_engine_context_close(client.ctx); set_sm_state(ENGINE_DO_REGISTRATION); return; } - /* Try if we can recover the DTLS session and try Update. - * This might fallback into full registration on sm_handle_registration_update_failure(). - */ err = lwm2m_socket_start(client.ctx); if (err) { LOG_ERR("Failed to start socket %d", err); @@ -1371,21 +1305,8 @@ static void sm_do_network_error(void) set_sm_state(ENGINE_NETWORK_ERROR); return; } - set_sm_state(ENGINE_UPDATE_REGISTRATION); - return; - -stop_engine: - /* We are out of options, stop engine */ - if (client.ctx->event_cb) { - if (client.ctx->bootstrap_mode) { - client.ctx->event_cb(client.ctx, - LWM2M_RD_CLIENT_EVENT_BOOTSTRAP_REG_FAILURE); - } else { - client.ctx->event_cb(client.ctx, LWM2M_RD_CLIENT_EVENT_NETWORK_ERROR); - } - } - set_sm_state(ENGINE_IDLE); + set_sm_state(ENGINE_UPDATE_REGISTRATION); } static void lwm2m_rd_client_service(struct k_work *work) @@ -1459,19 +1380,6 @@ static void lwm2m_rd_client_service(struct k_work *work) timeout = EXCHANGE_LIFETIME; break; - case ENGINE_SERVER_DISABLED: - if (lwm2m_server_select(NULL)) { - set_sm_state(ENGINE_INIT); - } else { - /* wait for server to be enabled. */ - /* - * TODO: Once engine is converted to use timepoint_t - * this should calculate the next event from the previous server. - */ - next_event_at(k_uptime_get() + SEC_PER_MIN * MSEC_PER_SEC); - } - break; - case ENGINE_DEREGISTER: sm_do_deregister(); break; @@ -1483,11 +1391,7 @@ static void lwm2m_rd_client_service(struct k_work *work) case ENGINE_DEREGISTERED: lwm2m_engine_stop(client.ctx); - if (client.server_disabled) { - set_sm_state(ENGINE_SERVER_DISABLED); - } else { - set_sm_state(ENGINE_IDLE); - } + set_sm_state(ENGINE_IDLE); break; case ENGINE_NETWORK_ERROR: @@ -1504,7 +1408,7 @@ static void lwm2m_rd_client_service(struct k_work *work) if (end < k_uptime_get()) { LOG_DBG("State machine have timed out"); - sm_handle_timeout_state(ENGINE_INIT); + sm_handle_timeout_state(NULL, ENGINE_INIT); } else if (client.next_event > end) { next_event_at(end); } @@ -1538,7 +1442,6 @@ int lwm2m_rd_client_start(struct lwm2m_ctx *client_ctx, const char *ep_name, } /* Init Context */ - lwm2m_server_reset_timestamps(); lwm2m_engine_context_init(client_ctx); client.ctx = client_ctx; @@ -1547,15 +1450,13 @@ int lwm2m_rd_client_start(struct lwm2m_ctx *client_ctx, const char *ep_name, client.ctx->observe_cb = observe_cb; client.ctx->event_cb = event_cb; client.use_bootstrap = flags & LWM2M_RD_CLIENT_FLAG_BOOTSTRAP; - client.ctx->srv_obj_inst = -1; - client.ctx->sec_obj_inst = -1; - client.retries = 0; + set_sm_state(ENGINE_INIT); strncpy(client.ep_name, ep_name, CLIENT_EP_LEN - 1); client.ep_name[CLIENT_EP_LEN - 1] = '\0'; LOG_INF("Start LWM2M Client: %s", client.ep_name); - set_sm_state(ENGINE_INIT); + next_event_at(0); k_mutex_unlock(&client.mutex); @@ -1576,10 +1477,9 @@ int lwm2m_rd_client_stop(struct lwm2m_ctx *client_ctx, client.ctx->event_cb = event_cb; rd_client_message_free(); - if (sm_is_registered() && deregister && !client.server_disabled) { + if (sm_is_registered() && deregister) { set_sm_state(ENGINE_DEREGISTER); } else { - client.server_disabled = false; set_sm_state(ENGINE_DEREGISTERED); } @@ -1657,7 +1557,7 @@ int lwm2m_rd_client_resume(void) #endif /* Or do we resume into registration state */ if (client.engine_state >= ENGINE_DO_REGISTRATION && - client.engine_state <= ENGINE_SERVER_DISABLED) { + client.engine_state <= ENGINE_SUSPENDED) { if (!client.last_update || (client.lifetime <= (k_uptime_get() - client.last_update) / MSEC_PER_SEC)) { /* No lifetime left, register again */ @@ -1675,29 +1575,6 @@ int lwm2m_rd_client_resume(void) return 0; } -int lwm2m_rd_client_server_disabled(uint16_t inst_id) -{ - if (client.ctx->srv_obj_inst != inst_id) { - return -EPERM; - } - - k_mutex_lock(&client.mutex, K_FOREVER); - - client.server_disabled = true; - - if (sm_is_registered()) { - LOG_INF("Server disabled, deregister"); - set_sm_state_delayed(ENGINE_DEREGISTER, DELAY_BEFORE_CLOSING); - } else { - LOG_INF("Server disabled"); - set_sm_state(ENGINE_DEREGISTERED); - } - - k_mutex_unlock(&client.mutex); - - return 0; -} - void lwm2m_rd_client_update(void) { engine_trigger_update(false); diff --git a/subsys/net/lib/lwm2m/lwm2m_rd_client.h b/subsys/net/lib/lwm2m/lwm2m_rd_client.h index 5d71ccb30f6..66a3aac20f3 100644 --- a/subsys/net/lib/lwm2m/lwm2m_rd_client.h +++ b/subsys/net/lib/lwm2m/lwm2m_rd_client.h @@ -56,14 +56,4 @@ int lwm2m_rd_client_connection_resume(struct lwm2m_ctx *client_ctx); void engine_update_tx_time(void); struct lwm2m_message *lwm2m_get_ongoing_rd_msg(void); -/** - * @brief Notify RD client that this server is disabled. - * - * This may return error -EPERM, if RD client is not registered on that server. - * - * @param inst_id server instance id - * @return int 0 on success, negative errno on failure. - */ -int lwm2m_rd_client_server_disabled(uint16_t inst_id); - #endif /* LWM2M_RD_CLIENT_H */ diff --git a/tests/net/lib/lwm2m/interop/src/lwm2m-client.c b/tests/net/lib/lwm2m/interop/src/lwm2m-client.c index b6634069fbd..706091659a5 100644 --- a/tests/net/lib/lwm2m/interop/src/lwm2m-client.c +++ b/tests/net/lib/lwm2m/interop/src/lwm2m-client.c @@ -119,10 +119,6 @@ static void rd_client_event(struct lwm2m_ctx *client, /* do nothing */ break; - case LWM2M_RD_CLIENT_EVENT_SERVER_DISABLED: - LOG_DBG("LwM2M server disabled"); - break; - case LWM2M_RD_CLIENT_EVENT_BOOTSTRAP_REG_FAILURE: LOG_DBG("Bootstrap registration failure!"); break; diff --git a/tests/net/lib/lwm2m/lwm2m_rd_client/src/main.c b/tests/net/lib/lwm2m/lwm2m_rd_client/src/main.c index 1d6a4e584fa..208298512d4 100644 --- a/tests/net/lib/lwm2m/lwm2m_rd_client/src/main.c +++ b/tests/net/lib/lwm2m/lwm2m_rd_client/src/main.c @@ -21,7 +21,7 @@ DEFINE_FFF_GLOBALS; /* Maximum number of iterations within the state machine of RD Client * service that is waited for until a possible event occurs */ -#define RD_CLIENT_MAX_LOOKUP_ITERATIONS 500 +static const uint8_t RD_CLIENT_MAX_LOOKUP_ITERATIONS = 100; FAKE_VOID_FUNC(show_lwm2m_event, enum lwm2m_rd_client_event); FAKE_VOID_FUNC(show_lwm2m_observe, enum lwm2m_observe_event); @@ -97,9 +97,6 @@ static void lwm2m_event_cb(struct lwm2m_ctx *client, enum lwm2m_rd_client_event case LWM2M_RD_CLIENT_EVENT_QUEUE_MODE_RX_OFF: LOG_INF("*** LWM2M_RD_CLIENT_EVENT_QUEUE_MODE_RX_OFF"); break; - case LWM2M_RD_CLIENT_EVENT_SERVER_DISABLED: - LOG_INF("*** LWM2M_RD_CLIENT_EVENT_SERVER_DISABLED"); - break; case LWM2M_RD_CLIENT_EVENT_ENGINE_SUSPENDED: LOG_INF("*** LWM2M_RD_CLIENT_EVENT_ENGINE_SUSPENDED"); break; @@ -168,7 +165,6 @@ static void my_suite_before(void *data) lwm2m_init_message_fake.custom_fake = lwm2m_init_message_fake_default; coap_header_get_code_fake.custom_fake = coap_header_get_code_fake_created; coap_packet_append_option_fake.custom_fake = NULL; - stub_lwm2m_server_disable(false); } static void my_suite_after(void *data) @@ -202,6 +198,8 @@ ZTEST(lwm2m_rd_client, test_start_registration_ok) (void)memset(&ctx, 0x0, sizeof(ctx)); + test_prepare_pending_message_cb(&message_reply_cb_default); + lwm2m_rd_client_init(); test_lwm2m_engine_start_service(); wait_for_service(1); @@ -209,7 +207,6 @@ ZTEST(lwm2m_rd_client, test_start_registration_ok) coap_find_options_fake.custom_fake = coap_find_options_do_registration_reply_cb_ok; zassert_true(lwm2m_rd_client_start(&ctx, "Test", 0, lwm2m_event_cb, lwm2m_observe_cb) == 0, NULL); - test_prepare_pending_message_cb(&message_reply_cb_default); zassert(lwm2m_rd_client_ctx() == &ctx, ""); zassert_true(expect_lwm2m_rd_client_event(LWM2M_RD_CLIENT_EVENT_REGISTRATION_COMPLETE), NULL); @@ -231,6 +228,8 @@ ZTEST(lwm2m_rd_client, test_register_update_too_small_lifetime_to_default) (void)memset(&ctx, 0x0, sizeof(ctx)); + test_prepare_pending_message_cb(&message_reply_cb_default); + lwm2m_rd_client_init(); test_lwm2m_engine_start_service(); wait_for_service(1); @@ -238,7 +237,6 @@ ZTEST(lwm2m_rd_client, test_register_update_too_small_lifetime_to_default) coap_find_options_fake.custom_fake = coap_find_options_do_registration_reply_cb_ok; zassert_true(lwm2m_rd_client_start(&ctx, "Test", 0, lwm2m_event_cb, lwm2m_observe_cb) == 0, NULL); - test_prepare_pending_message_cb(&message_reply_cb_default); zassert(lwm2m_rd_client_ctx() == &ctx, ""); zassert_true(expect_lwm2m_rd_client_event(LWM2M_RD_CLIENT_EVENT_REGISTRATION_COMPLETE), NULL); @@ -251,13 +249,14 @@ ZTEST(lwm2m_rd_client, test_timeout_resume_registration) (void)memset(&ctx, 0x0, sizeof(ctx)); + test_prepare_pending_message_cb(&message_reply_cb_default); + lwm2m_rd_client_init(); test_lwm2m_engine_start_service(); coap_find_options_fake.custom_fake = coap_find_options_do_registration_reply_cb_ok; zassert_true(lwm2m_rd_client_start(&ctx, "Test", 0, lwm2m_event_cb, lwm2m_observe_cb) == 0, NULL); - test_prepare_pending_message_cb(&message_reply_cb_default); zassert(lwm2m_rd_client_ctx() == &ctx, ""); zassert_true(expect_lwm2m_rd_client_event(LWM2M_RD_CLIENT_EVENT_REGISTRATION_COMPLETE), NULL); @@ -274,17 +273,16 @@ ZTEST(lwm2m_rd_client, test_start_registration_timeout) (void)memset(&ctx, 0x0, sizeof(ctx)); + test_prepare_pending_message_cb(&message_reply_timeout_cb_default); + lwm2m_rd_client_init(); test_lwm2m_engine_start_service(); wait_for_service(1); zassert_true(lwm2m_rd_client_start(&ctx, "Test", 0, lwm2m_event_cb, lwm2m_observe_cb) == 0, NULL); - test_prepare_pending_message_cb(&message_reply_timeout_cb_default); - zassert_true(expect_lwm2m_rd_client_event(LWM2M_RD_CLIENT_EVENT_REG_TIMEOUT), NULL); - zassert_true(expect_lwm2m_rd_client_event(LWM2M_RD_CLIENT_EVENT_REG_TIMEOUT), NULL); + zassert_true(expect_lwm2m_rd_client_event(LWM2M_RD_CLIENT_EVENT_DISCONNECT), NULL); zassert_true(expect_lwm2m_rd_client_event(LWM2M_RD_CLIENT_EVENT_REG_TIMEOUT), NULL); - zassert_true(expect_lwm2m_rd_client_event(LWM2M_RD_CLIENT_EVENT_NETWORK_ERROR), NULL); } ZTEST(lwm2m_rd_client, test_start_registration_fail) @@ -293,6 +291,8 @@ ZTEST(lwm2m_rd_client, test_start_registration_fail) (void)memset(&ctx, 0x0, sizeof(ctx)); + test_prepare_pending_message_cb(&message_reply_cb_default); + lwm2m_rd_client_init(); test_lwm2m_engine_start_service(); wait_for_service(1); @@ -302,15 +302,8 @@ ZTEST(lwm2m_rd_client, test_start_registration_fail) lwm2m_init_message_fake.custom_fake = lwm2m_init_message_fake_default; zassert_true(lwm2m_rd_client_start(&ctx, "Test", 0, lwm2m_event_cb, lwm2m_observe_cb) == 0, NULL); - test_prepare_pending_message_cb(&message_reply_cb_default); - zassert_true(expect_lwm2m_rd_client_event(LWM2M_RD_CLIENT_EVENT_REGISTRATION_FAILURE), - NULL); zassert_true(expect_lwm2m_rd_client_event(LWM2M_RD_CLIENT_EVENT_REGISTRATION_FAILURE), NULL); - zassert_true(expect_lwm2m_rd_client_event(LWM2M_RD_CLIENT_EVENT_REGISTRATION_FAILURE), - NULL); - zassert_true(expect_lwm2m_rd_client_event(LWM2M_RD_CLIENT_EVENT_NETWORK_ERROR), - NULL); } ZTEST(lwm2m_rd_client, test_start_registration_update) @@ -319,6 +312,8 @@ ZTEST(lwm2m_rd_client, test_start_registration_update) (void)memset(&ctx, 0x0, sizeof(ctx)); + test_prepare_pending_message_cb(&message_reply_cb_default); + lwm2m_rd_client_init(); test_lwm2m_engine_start_service(); wait_for_service(1); @@ -326,7 +321,6 @@ ZTEST(lwm2m_rd_client, test_start_registration_update) coap_find_options_fake.custom_fake = coap_find_options_do_registration_reply_cb_ok; zassert_true(lwm2m_rd_client_start(&ctx, "Test", 0, lwm2m_event_cb, lwm2m_observe_cb) == 0, NULL); - test_prepare_pending_message_cb(&message_reply_cb_default); zassert_true(expect_lwm2m_rd_client_event(LWM2M_RD_CLIENT_EVENT_REGISTRATION_COMPLETE), NULL); @@ -341,6 +335,8 @@ ZTEST(lwm2m_rd_client, test_rx_off) (void)memset(&ctx, 0x0, sizeof(ctx)); + test_prepare_pending_message_cb(&message_reply_cb_default); + lwm2m_rd_client_init(); test_lwm2m_engine_start_service(); wait_for_service(1); @@ -348,7 +344,6 @@ ZTEST(lwm2m_rd_client, test_rx_off) coap_find_options_fake.custom_fake = coap_find_options_do_registration_reply_cb_ok; zassert_true(lwm2m_rd_client_start(&ctx, "Test", 0, lwm2m_event_cb, lwm2m_observe_cb) == 0, NULL); - test_prepare_pending_message_cb(&message_reply_cb_default); zassert_true(expect_lwm2m_rd_client_event(LWM2M_RD_CLIENT_EVENT_REGISTRATION_COMPLETE), NULL); @@ -364,6 +359,8 @@ ZTEST(lwm2m_rd_client, test_start_registration_update_fail) (void)memset(&ctx, 0x0, sizeof(ctx)); + test_prepare_pending_message_cb(&message_reply_cb_default); + lwm2m_rd_client_init(); test_lwm2m_engine_start_service(); wait_for_service(1); @@ -371,7 +368,6 @@ ZTEST(lwm2m_rd_client, test_start_registration_update_fail) coap_find_options_fake.custom_fake = coap_find_options_do_registration_reply_cb_ok; zassert_true(lwm2m_rd_client_start(&ctx, "Test", 0, lwm2m_event_cb, lwm2m_observe_cb) == 0, NULL); - test_prepare_pending_message_cb(&message_reply_cb_default); zassert_true(expect_lwm2m_rd_client_event(LWM2M_RD_CLIENT_EVENT_REGISTRATION_COMPLETE), NULL); @@ -388,6 +384,8 @@ ZTEST(lwm2m_rd_client, test_registration_update_timeout) (void)memset(&ctx, 0x0, sizeof(ctx)); + test_prepare_pending_message_cb(&message_reply_cb_default); + lwm2m_rd_client_init(); test_lwm2m_engine_start_service(); wait_for_service(1); @@ -395,7 +393,6 @@ ZTEST(lwm2m_rd_client, test_registration_update_timeout) coap_find_options_fake.custom_fake = coap_find_options_do_registration_reply_cb_ok; zassert_true(lwm2m_rd_client_start(&ctx, "Test", 0, lwm2m_event_cb, lwm2m_observe_cb) == 0, NULL); - test_prepare_pending_message_cb(&message_reply_cb_default); zassert_true(expect_lwm2m_rd_client_event(LWM2M_RD_CLIENT_EVENT_REGISTRATION_COMPLETE), NULL); test_prepare_pending_message_cb(&message_reply_timeout_cb_default); @@ -418,6 +415,8 @@ ZTEST(lwm2m_rd_client, test_deregistration_timeout) (void)memset(&ctx, 0x0, sizeof(ctx)); + test_prepare_pending_message_cb(&message_reply_cb_default); + lwm2m_rd_client_init(); test_lwm2m_engine_start_service(); wait_for_service(1); @@ -425,7 +424,6 @@ ZTEST(lwm2m_rd_client, test_deregistration_timeout) coap_find_options_fake.custom_fake = coap_find_options_do_registration_reply_cb_ok; zassert_true(lwm2m_rd_client_start(&ctx, "Test", 0, lwm2m_event_cb, lwm2m_observe_cb) == 0, NULL); - test_prepare_pending_message_cb(&message_reply_cb_default); zassert_true(expect_lwm2m_rd_client_event(LWM2M_RD_CLIENT_EVENT_REGISTRATION_COMPLETE), NULL); @@ -441,6 +439,8 @@ ZTEST(lwm2m_rd_client, test_error_on_registration_update) (void)memset(&ctx, 0x0, sizeof(ctx)); + test_prepare_pending_message_cb(&message_reply_cb_default); + lwm2m_rd_client_init(); test_lwm2m_engine_start_service(); wait_for_service(1); @@ -449,8 +449,6 @@ ZTEST(lwm2m_rd_client, test_error_on_registration_update) coap_packet_append_option_fake.custom_fake = NULL; zassert_true(lwm2m_rd_client_start(&ctx, "Test", 0, lwm2m_event_cb, lwm2m_observe_cb) == 0, NULL); - test_prepare_pending_message_cb(&message_reply_cb_default); - zassert_true(expect_lwm2m_rd_client_event(LWM2M_RD_CLIENT_EVENT_REGISTRATION_COMPLETE), NULL); @@ -484,6 +482,8 @@ ZTEST(lwm2m_rd_client, test_suspend_resume_registration) (void)memset(&ctx, 0x0, sizeof(ctx)); + test_prepare_pending_message_cb(&message_reply_cb_default); + lwm2m_rd_client_init(); test_lwm2m_engine_start_service(); wait_for_service(1); @@ -491,7 +491,6 @@ ZTEST(lwm2m_rd_client, test_suspend_resume_registration) coap_find_options_fake.custom_fake = coap_find_options_do_registration_reply_cb_ok; zassert_true(lwm2m_rd_client_start(&ctx, "Test", 0, lwm2m_event_cb, lwm2m_observe_cb) == 0, NULL); - test_prepare_pending_message_cb(&message_reply_cb_default); zassert_true(expect_lwm2m_rd_client_event(LWM2M_RD_CLIENT_EVENT_REGISTRATION_COMPLETE), NULL); zassert_true(!lwm2m_rd_client_is_suspended(&ctx), NULL); @@ -518,6 +517,8 @@ ZTEST(lwm2m_rd_client, test_suspend_stop_resume) (void)memset(&ctx, 0x0, sizeof(ctx)); + test_prepare_pending_message_cb(&message_reply_cb_default); + lwm2m_rd_client_init(); test_lwm2m_engine_start_service(); wait_for_service(1); @@ -526,7 +527,6 @@ ZTEST(lwm2m_rd_client, test_suspend_stop_resume) coap_find_options_fake.custom_fake = coap_find_options_do_registration_reply_cb_ok; zassert_true(lwm2m_rd_client_start(&ctx, "Test", 0, lwm2m_event_cb, lwm2m_observe_cb) == 0, NULL); - test_prepare_pending_message_cb(&message_reply_cb_default); zassert_true(expect_lwm2m_rd_client_event(LWM2M_RD_CLIENT_EVENT_REGISTRATION_COMPLETE), NULL); zassert_true(lwm2m_rd_client_pause() == 0, NULL); @@ -544,6 +544,8 @@ ZTEST(lwm2m_rd_client, test_socket_error) (void)memset(&ctx, 0x0, sizeof(ctx)); + test_prepare_pending_message_cb(&message_reply_cb_default); + lwm2m_rd_client_init(); test_lwm2m_engine_start_service(); wait_for_service(1); @@ -552,7 +554,6 @@ ZTEST(lwm2m_rd_client, test_socket_error) coap_find_options_fake.custom_fake = coap_find_options_do_registration_reply_cb_ok; zassert_true(lwm2m_rd_client_start(&ctx, "Test", 0, lwm2m_event_cb, lwm2m_observe_cb) == 0, NULL); - test_prepare_pending_message_cb(&message_reply_cb_default); zassert_true(expect_lwm2m_rd_client_event(LWM2M_RD_CLIENT_EVENT_REGISTRATION_COMPLETE), NULL); @@ -568,6 +569,8 @@ ZTEST(lwm2m_rd_client, test_socket_error_on_stop) (void)memset(&ctx, 0x0, sizeof(ctx)); + test_prepare_pending_message_cb(&message_reply_cb_default); + lwm2m_rd_client_init(); test_lwm2m_engine_start_service(); wait_for_service(1); @@ -576,7 +579,6 @@ ZTEST(lwm2m_rd_client, test_socket_error_on_stop) coap_find_options_fake.custom_fake = coap_find_options_do_registration_reply_cb_ok; zassert_true(lwm2m_rd_client_start(&ctx, "Test", 0, lwm2m_event_cb, lwm2m_observe_cb) == 0, NULL); - test_prepare_pending_message_cb(&message_reply_cb_default); zassert_true(expect_lwm2m_rd_client_event(LWM2M_RD_CLIENT_EVENT_REGISTRATION_COMPLETE), NULL); @@ -606,6 +608,8 @@ ZTEST(lwm2m_rd_client, test_engine_trigger_bootstrap) (void)memset(&ctx, 0x0, sizeof(ctx)); + test_prepare_pending_message_cb(&message_reply_cb_default); + lwm2m_rd_client_init(); test_lwm2m_engine_start_service(); wait_for_service(1); @@ -613,7 +617,6 @@ ZTEST(lwm2m_rd_client, test_engine_trigger_bootstrap) coap_find_options_fake.custom_fake = coap_find_options_do_registration_reply_cb_ok; zassert_true(lwm2m_rd_client_start(&ctx, "Test", 0, lwm2m_event_cb, lwm2m_observe_cb) == 0, NULL); - test_prepare_pending_message_cb(&message_reply_cb_default); zassert_true(expect_lwm2m_rd_client_event(LWM2M_RD_CLIENT_EVENT_REGISTRATION_COMPLETE), NULL); lwm2m_get_bool_fake.custom_fake = lwm2m_get_bool_fake_true; @@ -635,6 +638,8 @@ ZTEST(lwm2m_rd_client, test_bootstrap_timeout) (void)memset(&ctx, 0x0, sizeof(ctx)); + test_prepare_pending_message_cb(&message_reply_timeout_cb_default); + lwm2m_rd_client_init(); test_lwm2m_engine_start_service(); wait_for_service(1); @@ -646,7 +651,6 @@ ZTEST(lwm2m_rd_client, test_bootstrap_timeout) coap_find_options_fake.custom_fake = coap_find_options_do_registration_reply_cb_ok; zassert_true(lwm2m_rd_client_start(&ctx, "Test", 1, lwm2m_event_cb, lwm2m_observe_cb) == 0, NULL); - test_prepare_pending_message_cb(&message_reply_timeout_cb_default); zassert_true(expect_lwm2m_rd_client_event(LWM2M_RD_CLIENT_EVENT_BOOTSTRAP_REG_FAILURE), NULL); } @@ -657,6 +661,8 @@ ZTEST(lwm2m_rd_client, test_bootstrap_fail) (void)memset(&ctx, 0x0, sizeof(ctx)); + test_prepare_pending_message_cb(&message_reply_cb_default); + lwm2m_rd_client_init(); test_lwm2m_engine_start_service(); wait_for_service(1); @@ -668,154 +674,27 @@ ZTEST(lwm2m_rd_client, test_bootstrap_fail) coap_find_options_fake.custom_fake = coap_find_options_do_registration_reply_cb_ok; zassert_true(lwm2m_rd_client_start(&ctx, "Test", 1, lwm2m_event_cb, lwm2m_observe_cb) == 0, NULL); - test_prepare_pending_message_cb(&message_reply_cb_default); zassert_true(expect_lwm2m_rd_client_event(LWM2M_RD_CLIENT_EVENT_BOOTSTRAP_REG_FAILURE), NULL); } -ZTEST(lwm2m_rd_client, test_bootstrap_no_srv) +ZTEST(lwm2m_rd_client, test_bootstrap_no_srv_fallback_to_register) { struct lwm2m_ctx ctx; (void)memset(&ctx, 0x0, sizeof(ctx)); - lwm2m_rd_client_init(); - test_lwm2m_engine_start_service(); - wait_for_service(1); - - coap_find_options_fake.custom_fake = coap_find_options_do_registration_reply_cb_ok; - zassert_true(lwm2m_rd_client_start(&ctx, "Test", 1, lwm2m_event_cb, lwm2m_observe_cb) == 0, - NULL); test_prepare_pending_message_cb(&message_reply_cb_default); - zassert_true(expect_lwm2m_rd_client_event(LWM2M_RD_CLIENT_EVENT_BOOTSTRAP_REG_FAILURE), - NULL); -} - -ZTEST(lwm2m_rd_client, test_disable_server) -{ - struct lwm2m_ctx ctx; - - (void)memset(&ctx, 0x0, sizeof(ctx)); lwm2m_rd_client_init(); test_lwm2m_engine_start_service(); wait_for_service(1); coap_find_options_fake.custom_fake = coap_find_options_do_registration_reply_cb_ok; - zassert_true(lwm2m_rd_client_start(&ctx, "Test", 0, lwm2m_event_cb, lwm2m_observe_cb) == 0, - NULL); - test_prepare_pending_message_cb(&message_reply_cb_default); - zassert_true(expect_lwm2m_rd_client_event(LWM2M_RD_CLIENT_EVENT_REGISTRATION_COMPLETE), - NULL); - coap_header_get_code_fake.custom_fake = coap_header_get_code_fake_deleted; - stub_lwm2m_server_disable(true); - lwm2m_rd_client_server_disabled(0); - zassert_true(expect_lwm2m_rd_client_event(LWM2M_RD_CLIENT_EVENT_SERVER_DISABLED), - NULL); -} - -ZTEST(lwm2m_rd_client, test_disable_server_stop) -{ - struct lwm2m_ctx ctx; - - (void)memset(&ctx, 0x0, sizeof(ctx)); - - lwm2m_rd_client_init(); - test_lwm2m_engine_start_service(); - wait_for_service(1); - - coap_find_options_fake.custom_fake = coap_find_options_do_registration_reply_cb_ok; - zassert_true(lwm2m_rd_client_start(&ctx, "Test", 0, lwm2m_event_cb, lwm2m_observe_cb) == 0, - NULL); - test_prepare_pending_message_cb(&message_reply_cb_default); - zassert_true(expect_lwm2m_rd_client_event(LWM2M_RD_CLIENT_EVENT_REGISTRATION_COMPLETE), - NULL); - coap_header_get_code_fake.custom_fake = coap_header_get_code_fake_deleted; - stub_lwm2m_server_disable(true); - lwm2m_rd_client_server_disabled(0); - zassert_true(expect_lwm2m_rd_client_event(LWM2M_RD_CLIENT_EVENT_SERVER_DISABLED), - NULL); - wait_for_service(1); - zassert_true(lwm2m_rd_client_stop(&ctx, lwm2m_event_cb, true) == 0, NULL); - zassert_true(expect_lwm2m_rd_client_event(LWM2M_RD_CLIENT_EVENT_DISCONNECT), NULL); -} - -ZTEST(lwm2m_rd_client, test_disable_server_connect) -{ - struct lwm2m_ctx ctx; - - (void)memset(&ctx, 0x0, sizeof(ctx)); - - lwm2m_rd_client_init(); - test_lwm2m_engine_start_service(); - wait_for_service(1); - - coap_find_options_fake.custom_fake = coap_find_options_do_registration_reply_cb_ok; - zassert_true(lwm2m_rd_client_start(&ctx, "Test", 0, lwm2m_event_cb, lwm2m_observe_cb) == 0, - NULL); - test_prepare_pending_message_cb(&message_reply_cb_default); - zassert_true(expect_lwm2m_rd_client_event(LWM2M_RD_CLIENT_EVENT_REGISTRATION_COMPLETE), - NULL); - coap_header_get_code_fake.custom_fake = coap_header_get_code_fake_deleted; - stub_lwm2m_server_disable(true); - lwm2m_rd_client_server_disabled(0); - zassert_true(expect_lwm2m_rd_client_event(LWM2M_RD_CLIENT_EVENT_SERVER_DISABLED), - NULL); - - wait_for_service(500); - - coap_header_get_code_fake.custom_fake = coap_header_get_code_fake_created; - stub_lwm2m_server_disable(false); - zassert_true(expect_lwm2m_rd_client_event(LWM2M_RD_CLIENT_EVENT_REGISTRATION_COMPLETE), - NULL); -} - -ZTEST(lwm2m_rd_client, test_fallback_to_bootstrap) -{ - struct lwm2m_ctx ctx; - - (void)memset(&ctx, 0x0, sizeof(ctx)); - - lwm2m_rd_client_init(); - test_lwm2m_engine_start_service(); - wait_for_service(1); - - lwm2m_get_bool_fake.custom_fake = lwm2m_get_bool_fake_true; - zassert_true(lwm2m_rd_client_start(&ctx, "Test", 0, lwm2m_event_cb, lwm2m_observe_cb) == 0, - NULL); - test_prepare_pending_message_cb(&message_reply_timeout_cb_default); - zassert_true(expect_lwm2m_rd_client_event(LWM2M_RD_CLIENT_EVENT_REG_TIMEOUT), NULL); - zassert_true(expect_lwm2m_rd_client_event(LWM2M_RD_CLIENT_EVENT_REG_TIMEOUT), NULL); - zassert_true(expect_lwm2m_rd_client_event(LWM2M_RD_CLIENT_EVENT_REG_TIMEOUT), NULL); - - zassert_true(expect_lwm2m_rd_client_event(LWM2M_RD_CLIENT_EVENT_BOOTSTRAP_REG_FAILURE), - NULL); -} - -ZTEST(lwm2m_rd_client, test_no_srv_fallback_to_bootstrap) -{ - struct lwm2m_ctx ctx; - - (void)memset(&ctx, 0x0, sizeof(ctx)); - - lwm2m_rd_client_init(); - test_lwm2m_engine_start_service(); - wait_for_service(1); - - coap_header_get_code_fake.custom_fake = coap_header_get_code_fake_changed; - lwm2m_get_bool_fake.custom_fake = lwm2m_get_bool_fake_true; - stub_lwm2m_server_disable(true); - zassert_true(lwm2m_rd_client_start(&ctx, "Test", 0, lwm2m_event_cb, lwm2m_observe_cb) == 0, - NULL); - test_prepare_pending_message_cb(&message_reply_cb_default); - zassert_true(expect_lwm2m_rd_client_event(LWM2M_RD_CLIENT_EVENT_BOOTSTRAP_REG_COMPLETE), + zassert_true(lwm2m_rd_client_start(&ctx, "Test", 1, lwm2m_event_cb, lwm2m_observe_cb) == 0, NULL); - coap_header_get_code_fake.custom_fake = coap_header_get_code_fake_created; - coap_find_options_fake.custom_fake = coap_find_options_do_registration_reply_cb_ok; - stub_lwm2m_server_disable(false); - engine_bootstrap_finish(); zassert_true(expect_lwm2m_rd_client_event(LWM2M_RD_CLIENT_EVENT_REGISTRATION_COMPLETE), NULL); } diff --git a/tests/net/lib/lwm2m/lwm2m_rd_client/src/stubs.c b/tests/net/lib/lwm2m/lwm2m_rd_client/src/stubs.c index 621057f8496..3cbde9060ce 100644 --- a/tests/net/lib/lwm2m/lwm2m_rd_client/src/stubs.c +++ b/tests/net/lib/lwm2m/lwm2m_rd_client/src/stubs.c @@ -116,24 +116,6 @@ char *lwm2m_sprint_ip_addr_fake_default(const struct sockaddr *addr) DEFINE_FAKE_VALUE_FUNC(int, lwm2m_server_short_id_to_inst, uint16_t); DEFINE_FAKE_VALUE_FUNC(int, lwm2m_security_index_to_inst_id, int); -DEFINE_FAKE_VALUE_FUNC(int, lwm2m_security_short_id_to_inst, uint16_t); -DEFINE_FAKE_VALUE_FUNC(int, lwm2m_server_disable, uint16_t, k_timeout_t); -DEFINE_FAKE_VALUE_FUNC(uint8_t, lwm2m_server_get_prio, uint16_t); -DEFINE_FAKE_VOID_FUNC(lwm2m_server_reset_timestamps); - -static bool srv_disabled; -bool lwm2m_server_select(uint16_t *obj_inst_id) -{ - if (obj_inst_id) { - *obj_inst_id = 0; - } - return !srv_disabled; -} - -void stub_lwm2m_server_disable(bool disable) -{ - srv_disabled = disable; -} k_work_handler_t service; int64_t next; @@ -195,13 +177,9 @@ void test_lwm2m_engine_start_service(void) void test_lwm2m_engine_stop_service(void) { - struct k_work_sync sync; - pending_message_cb = NULL; - pending_message = NULL; running = false; k_work_cancel(&service_work); - k_work_flush(&service_work, &sync); } /* subsys/net/lib/lwm2m/lwm2m_message_handling.h */ diff --git a/tests/net/lib/lwm2m/lwm2m_rd_client/src/stubs.h b/tests/net/lib/lwm2m/lwm2m_rd_client/src/stubs.h index 0a3ce31d9e8..1276dd5c109 100644 --- a/tests/net/lib/lwm2m/lwm2m_rd_client/src/stubs.h +++ b/tests/net/lib/lwm2m/lwm2m_rd_client/src/stubs.h @@ -59,8 +59,6 @@ DECLARE_FAKE_VALUE_FUNC(int, lwm2m_socket_close, struct lwm2m_ctx *); DECLARE_FAKE_VALUE_FUNC(int, lwm2m_close_socket, struct lwm2m_ctx *); DECLARE_FAKE_VALUE_FUNC(int, lwm2m_socket_suspend, struct lwm2m_ctx *); DECLARE_FAKE_VALUE_FUNC(int, lwm2m_security_inst_id_to_index, uint16_t); -DECLARE_FAKE_VALUE_FUNC(int, lwm2m_security_short_id_to_inst, uint16_t); -DECLARE_FAKE_VALUE_FUNC(int, lwm2m_security_index_to_inst_id, int); DECLARE_FAKE_VALUE_FUNC(int, lwm2m_engine_connection_resume, struct lwm2m_ctx *); DECLARE_FAKE_VALUE_FUNC(int, lwm2m_push_queued_buffers, struct lwm2m_ctx *); DECLARE_FAKE_VOID_FUNC(lwm2m_engine_context_init, struct lwm2m_ctx *); @@ -70,15 +68,10 @@ DECLARE_FAKE_VOID_FUNC(lwm2m_engine_context_close, struct lwm2m_ctx *); DECLARE_FAKE_VALUE_FUNC(char *, lwm2m_sprint_ip_addr, const struct sockaddr *); char *lwm2m_sprint_ip_addr_fake_default(const struct sockaddr *addr); DECLARE_FAKE_VALUE_FUNC(int, lwm2m_server_short_id_to_inst, uint16_t); -DECLARE_FAKE_VALUE_FUNC(int, lwm2m_server_disable, uint16_t, k_timeout_t); -DECLARE_FAKE_VALUE_FUNC(uint8_t, lwm2m_server_get_prio, uint16_t); -DECLARE_FAKE_VOID_FUNC(lwm2m_server_reset_timestamps); - - +DECLARE_FAKE_VALUE_FUNC(int, lwm2m_security_index_to_inst_id, int); void wait_for_service(uint16_t cycles); void test_lwm2m_engine_start_service(void); void test_lwm2m_engine_stop_service(void); -void stub_lwm2m_server_disable(bool disable); /* subsys/net/lib/lwm2m/lwm2m_message_handling.h */ DECLARE_FAKE_VALUE_FUNC(int, lwm2m_init_message, struct lwm2m_message *); From a827619d67418a65dfcd3bea605590aa46fe7ca5 Mon Sep 17 00:00:00 2001 From: Robert Lubos Date: Tue, 6 Feb 2024 11:07:16 +0100 Subject: [PATCH 3580/3723] Revert "[nrf fromtree] net: lwm2m: Allow disabling server for a period of time" This reverts commit 7a29fd1a6439a6db0b4981b68a8c7850317079fc. Signed-off-by: Robert Lubos --- subsys/net/lib/lwm2m/lwm2m_engine.h | 40 +++- subsys/net/lib/lwm2m/lwm2m_message_handling.c | 1 - subsys/net/lib/lwm2m/lwm2m_obj_server.c | 224 ++++++------------ subsys/net/lib/lwm2m/lwm2m_obj_server.h | 144 ----------- subsys/net/lib/lwm2m/lwm2m_observation.c | 1 - subsys/net/lib/lwm2m/lwm2m_rd_client.c | 1 - 6 files changed, 109 insertions(+), 302 deletions(-) delete mode 100644 subsys/net/lib/lwm2m/lwm2m_obj_server.h diff --git a/subsys/net/lib/lwm2m/lwm2m_engine.h b/subsys/net/lib/lwm2m/lwm2m_engine.h index 81b28395662..2ea3e583242 100644 --- a/subsys/net/lib/lwm2m/lwm2m_engine.h +++ b/subsys/net/lib/lwm2m/lwm2m_engine.h @@ -30,7 +30,6 @@ /* length of time in milliseconds to wait for buffer allocations */ #define BUF_ALLOC_TIMEOUT K_SECONDS(1) - /** * @brief Validates that writing is a legal operation on the field given by the object in * @p obj_inst and the resource id in @p msg. Returns the field to obj_field (if it exists). @@ -151,6 +150,45 @@ int lwm2m_security_short_id_to_inst(uint16_t short_id); */ int lwm2m_security_index_to_inst_id(int index); +/** + * @brief Returns the default minimum period for an observation set for the server + * with object instance id given by @p obj_inst_id. + * + * @param[in] obj_inst_id Object instance id of the server object instance + * @return int32_t pmin value + */ +int32_t lwm2m_server_get_pmin(uint16_t obj_inst_id); + +/** + * @brief Returns the default maximum period for an observation set for the server + * with object instance id given by @p obj_inst_id. + * + * @param[in] obj_inst_id Object instance id of the server object instance + * @return int32_t pmax value + */ +int32_t lwm2m_server_get_pmax(uint16_t obj_inst_id); + +/** + * @brief Returns the Short Server ID of the server object instance with + * object instance id given by @p obj_inst_id. + * + * @param[in] obj_inst_id Object instance id of the server object + * @return SSID or negative in case not found + */ +int lwm2m_server_get_ssid(uint16_t obj_inst_id); + +/** + * @brief Returns the object instance id of the server having ssid given by @p short_id. + * + * @param[in] short_id ssid of the server object + * @return Object instance id or negative in case not found + */ +int lwm2m_server_short_id_to_inst(uint16_t short_id); + +#if defined(CONFIG_LWM2M_SERVER_OBJECT_VERSION_1_1) +bool lwm2m_server_get_mute_send(uint16_t obj_inst_id); +#endif + #if defined(CONFIG_LWM2M_FIRMWARE_UPDATE_OBJ_SUPPORT) /** * @brief Sets the update state (as specified in LWM2M SPEC E.6 regarding the firmware update) diff --git a/subsys/net/lib/lwm2m/lwm2m_message_handling.c b/subsys/net/lib/lwm2m/lwm2m_message_handling.c index 02c62cee67c..6d006b4603e 100644 --- a/subsys/net/lib/lwm2m/lwm2m_message_handling.c +++ b/subsys/net/lib/lwm2m/lwm2m_message_handling.c @@ -45,7 +45,6 @@ LOG_MODULE_REGISTER(LOG_MODULE_NAME); #include "lwm2m_engine.h" #include "lwm2m_object.h" #include "lwm2m_obj_access_control.h" -#include "lwm2m_obj_server.h" #include "lwm2m_rw_link_format.h" #include "lwm2m_rw_oma_tlv.h" #include "lwm2m_rw_plain_text.h" diff --git a/subsys/net/lib/lwm2m/lwm2m_obj_server.c b/subsys/net/lib/lwm2m/lwm2m_obj_server.c index 10c7a1a1ea0..a1b2185ef1d 100644 --- a/subsys/net/lib/lwm2m/lwm2m_obj_server.c +++ b/subsys/net/lib/lwm2m/lwm2m_obj_server.c @@ -15,9 +15,8 @@ LOG_MODULE_REGISTER(LOG_MODULE_NAME); #include #include "lwm2m_object.h" -#include "lwm2m_obj_server.h" +#include "lwm2m_engine.h" #include "lwm2m_rd_client.h" -#include "lwm2m_registry.h" #define SERVER_VERSION_MAJOR 1 #if defined(CONFIG_LWM2M_SERVER_OBJECT_VERSION_1_1) @@ -28,7 +27,37 @@ LOG_MODULE_REGISTER(LOG_MODULE_NAME); #define SERVER_MAX_ID 9 #endif /* defined(CONFIG_LWM2M_SERVER_OBJECT_VERSION_1_1) */ +/* Server resource IDs */ +#define SERVER_SHORT_SERVER_ID 0 +#define SERVER_LIFETIME_ID 1 +#define SERVER_DEFAULT_MIN_PERIOD_ID 2 +#define SERVER_DEFAULT_MAX_PERIOD_ID 3 +#define SERVER_DISABLE_ID 4 +#define SERVER_DISABLE_TIMEOUT_ID 5 +#define SERVER_STORE_NOTIFY_ID 6 +#define SERVER_TRANSPORT_BINDING_ID 7 +#define SERVER_REG_UPDATE_TRIGGER_ID 8 +#if defined(CONFIG_LWM2M_SERVER_OBJECT_VERSION_1_1) +#define SERVER_BOOTSTRAP_UPDATE_TRIGGER_ID 9 +#define SERVER_APN_LINK_ID 10 +#define SERVER_TLS_DTLS_ALERT_CODE_ID 11 +#define SERVER_LAST_BOOTSTRAPPED_ID 12 +#define SERVER_REGISTRATION_PRIORITY_ORDER_ID 13 +#define SERVER_INITIAL_REGISTRATION_DELAY_TIMER_ID 14 +#define SERVER_REGISTRATION_FAILURE_BLOCK_ID 15 +#define SERVER_BOOTSTRAP_ON_REGISTRATION_FAILURE_ID 16 +#define SERVER_COMMUNICATION_RETRY_COUNT_ID 17 +#define SERVER_COMMUNICATION_RETRY_TIMER_ID 18 +#define SERVER_COMMUNICATION_SEQUENCE_DELAY_TIMER_ID 19 +#define SERVER_COMMUNICATION_SEQUENCE_RETRY_TIMER_ID 20 +#define SERVER_SMS_TRIGGER_ID 21 +#define SERVER_PREFERRED_TRANSPORT_ID 22 +#define SERVER_MUTE_SEND_ID 23 +#endif /* defined(CONFIG_LWM2M_SERVER_OBJECT_VERSION_1_1) */ + + /* Server flags */ +#define SERVER_FLAG_DISABLED 1 #define SERVER_FLAG_STORE_NOTIFY 2 #define MAX_INSTANCE_COUNT CONFIG_LWM2M_SERVER_INSTANCE_COUNT @@ -47,14 +76,13 @@ static uint16_t server_id[MAX_INSTANCE_COUNT]; static uint32_t lifetime[MAX_INSTANCE_COUNT]; static uint32_t default_min_period[MAX_INSTANCE_COUNT]; static uint32_t default_max_period[MAX_INSTANCE_COUNT]; -static k_timepoint_t disabled_until[MAX_INSTANCE_COUNT]; +static uint8_t server_flag_disabled[MAX_INSTANCE_COUNT]; static uint32_t disabled_timeout[MAX_INSTANCE_COUNT]; static uint8_t server_flag_store_notify[MAX_INSTANCE_COUNT]; static char transport_binding[MAX_INSTANCE_COUNT][TRANSPORT_BINDING_LEN]; -/* Server object version 1.1 */ -static uint8_t priority[MAX_INSTANCE_COUNT]; +#if defined(CONFIG_LWM2M_SERVER_OBJECT_VERSION_1_1) static bool mute_send[MAX_INSTANCE_COUNT]; -static bool boostrap_on_fail[MAX_INSTANCE_COUNT]; +#endif static struct lwm2m_engine_obj server; static struct lwm2m_engine_obj_field fields[] = { @@ -73,10 +101,10 @@ static struct lwm2m_engine_obj_field fields[] = { OBJ_FIELD_DATA(SERVER_APN_LINK_ID, RW_OPT, OBJLNK), OBJ_FIELD_DATA(SERVER_TLS_DTLS_ALERT_CODE_ID, R_OPT, U8), OBJ_FIELD_DATA(SERVER_LAST_BOOTSTRAPPED_ID, R_OPT, TIME), - OBJ_FIELD_DATA(SERVER_REGISTRATION_PRIORITY_ORDER_ID, RW_OPT, U8), + OBJ_FIELD_DATA(SERVER_REGISTRATION_PRIORITY_ORDER_ID, W_OPT, U16), OBJ_FIELD_DATA(SERVER_INITIAL_REGISTRATION_DELAY_TIMER_ID, W_OPT, U16), OBJ_FIELD_DATA(SERVER_REGISTRATION_FAILURE_BLOCK_ID, W_OPT, BOOL), - OBJ_FIELD_DATA(SERVER_BOOTSTRAP_ON_REGISTRATION_FAILURE_ID, RW_OPT, BOOL), + OBJ_FIELD_DATA(SERVER_BOOTSTRAP_ON_REGISTRATION_FAILURE_ID, W_OPT, BOOL), OBJ_FIELD_DATA(SERVER_COMMUNICATION_RETRY_COUNT_ID, W_OPT, U16), OBJ_FIELD_DATA(SERVER_COMMUNICATION_RETRY_TIMER_ID, W_OPT, U16), OBJ_FIELD_DATA(SERVER_COMMUNICATION_SEQUENCE_DELAY_TIMER_ID, W_OPT, U16), @@ -100,7 +128,7 @@ static int disable_cb(uint16_t obj_inst_id, uint8_t *args, uint16_t args_len) LOG_DBG("DISABLE %d", obj_inst_id); for (i = 0; i < MAX_INSTANCE_COUNT; i++) { if (inst[i].obj && inst[i].obj_inst_id == obj_inst_id) { - disabled_until[i] = sys_timepoint_calc(K_SECONDS(disabled_timeout[i])); + server_flag_disabled[i] = 1U; return 0; } } @@ -115,6 +143,7 @@ static int update_trigger_cb(uint16_t obj_inst_id, return 0; } +#if defined(CONFIG_LWM2M_SERVER_OBJECT_VERSION_1_1) static int bootstrap_trigger_cb(uint16_t obj_inst_id, uint8_t *args, uint16_t args_len) { @@ -132,6 +161,7 @@ bool lwm2m_server_get_mute_send(uint16_t obj_inst_id) } return false; } +#endif /* defined(CONFIG_LWM2M_SERVER_OBJECT_VERSION_1_1) */ static int lifetime_write_cb(uint16_t obj_inst_id, uint16_t res_id, @@ -203,116 +233,6 @@ int lwm2m_server_short_id_to_inst(uint16_t short_id) return -ENOENT; } -static int lwm2m_server_inst_id_to_index(uint16_t obj_inst_id) -{ - for (int i = 0; i < ARRAY_SIZE(inst); i++) { - if (inst[i].obj && inst[i].obj_inst_id == obj_inst_id) { - return i; - } - } - return -1; -} - -bool lwm2m_server_is_enabled(uint16_t obj_inst_id) -{ - int idx = lwm2m_server_inst_id_to_index(obj_inst_id); - - if (idx < 0) { - return false; - } - return sys_timepoint_expired(disabled_until[idx]); -} - -int lwm2m_server_disable(uint16_t obj_inst_id, k_timeout_t timeout) -{ - int idx = lwm2m_server_inst_id_to_index(obj_inst_id); - - if (idx < 0) { - return -ENOENT; - } - disabled_until[idx] = sys_timepoint_calc(timeout); - return 0; -} - -k_timepoint_t lwm2m_server_get_disabled_time(uint16_t obj_inst_id) -{ - int idx = lwm2m_server_inst_id_to_index(obj_inst_id); - - if (idx < 0) { - return sys_timepoint_calc(K_FOREVER); - } - return disabled_until[idx]; -} - -void lwm2m_server_reset_timestamps(void) -{ - for (int i = 0; i < ARRAY_SIZE(inst); i++) { - disabled_until[i] = sys_timepoint_calc(K_NO_WAIT); - } -} - -bool lwm2m_server_select(uint16_t *obj_inst_id) -{ - uint8_t min = UINT8_MAX; - uint8_t max = 0; - - /* Find priority boundaries */ - if (IS_ENABLED(CONFIG_LWM2M_SERVER_OBJECT_VERSION_1_1)) { - for (int i = 0; i < ARRAY_SIZE(inst); i++) { - if (min > priority[i]) { - min = priority[i]; - } - if (max < priority[i]) { - max = priority[i]; - } - } - } else { - min = max = 0; - } - - for (uint8_t prio = min; prio <= max; prio++) { - for (int i = 0; i < ARRAY_SIZE(inst); i++) { - /* Disabled for a period */ - if (!lwm2m_server_is_enabled(inst[i].obj_inst_id)) { - continue; - } - - /* Invalid short IDs */ - if (server_id[i] == 0 || server_id[i] == UINT16_MAX) { - continue; - } - - /* Check priority */ - if (IS_ENABLED(CONFIG_LWM2M_SERVER_OBJECT_VERSION_1_1)) { - if (priority[i] > prio) { - continue; - } - } - if (obj_inst_id) { - *obj_inst_id = inst[i].obj_inst_id; - } - return true; - } - } - - LOG_ERR("No server candidate found"); - return false; -} - -uint8_t lwm2m_server_get_prio(uint16_t obj_inst_id) -{ - if (IS_ENABLED(CONFIG_LWM2M_SERVER_OBJECT_VERSION_1_1)) { - int idx = lwm2m_server_inst_id_to_index(obj_inst_id); - - if (idx < 0) { - return UINT8_MAX; - } - return priority[idx]; - } - - return (uint8_t)obj_inst_id % UINT8_MAX; -} - static struct lwm2m_engine_obj_inst *server_create(uint16_t obj_inst_id) { int index, i = 0, j = 0; @@ -339,14 +259,16 @@ static struct lwm2m_engine_obj_inst *server_create(uint16_t obj_inst_id) } /* Set default values */ - disabled_until[i] = sys_timepoint_calc(K_NO_WAIT); + server_flag_disabled[index] = 0U; server_flag_store_notify[index] = 0U; server_id[index] = index + 1; lifetime[index] = CONFIG_LWM2M_ENGINE_DEFAULT_LIFETIME; default_min_period[index] = CONFIG_LWM2M_SERVER_DEFAULT_PMIN; default_max_period[index] = CONFIG_LWM2M_SERVER_DEFAULT_PMAX; disabled_timeout[index] = 86400U; - boostrap_on_fail[index] = true; +#if defined(CONFIG_LWM2M_SERVER_OBJECT_VERSION_1_1) + mute_send[index] = false; +#endif lwm2m_engine_get_binding(transport_binding[index]); @@ -383,39 +305,33 @@ static struct lwm2m_engine_obj_inst *server_create(uint16_t obj_inst_id) transport_binding[index], TRANSPORT_BINDING_LEN, strlen(transport_binding[index]) + 1); INIT_OBJ_RES_EXECUTE(SERVER_REG_UPDATE_TRIGGER_ID, res[index], i, update_trigger_cb); - - if (IS_ENABLED(CONFIG_LWM2M_SERVER_OBJECT_VERSION_1_1)) { - mute_send[index] = false; - priority[index] = 0; - INIT_OBJ_RES_EXECUTE(SERVER_BOOTSTRAP_UPDATE_TRIGGER_ID, res[index], i, - bootstrap_trigger_cb); - INIT_OBJ_RES_OPTDATA(SERVER_APN_LINK_ID, res[index], i, res_inst[index], j); - INIT_OBJ_RES_OPTDATA(SERVER_TLS_DTLS_ALERT_CODE_ID, res[index], i, res_inst[index], - j); - INIT_OBJ_RES_OPTDATA(SERVER_LAST_BOOTSTRAPPED_ID, res[index], i, res_inst[index], - j); - INIT_OBJ_RES_DATA(SERVER_REGISTRATION_PRIORITY_ORDER_ID, res[index], i, - res_inst[index], j, &priority[index], sizeof(uint8_t)); - INIT_OBJ_RES_OPTDATA(SERVER_INITIAL_REGISTRATION_DELAY_TIMER_ID, res[index], i, - res_inst[index], j); - INIT_OBJ_RES_OPTDATA(SERVER_REGISTRATION_FAILURE_BLOCK_ID, res[index], i, - res_inst[index], j); - INIT_OBJ_RES_DATA(SERVER_BOOTSTRAP_ON_REGISTRATION_FAILURE_ID, res[index], i, - res_inst[index], j, &boostrap_on_fail[index], sizeof(bool)); - INIT_OBJ_RES_OPTDATA(SERVER_COMMUNICATION_RETRY_COUNT_ID, res[index], i, - res_inst[index], j); - INIT_OBJ_RES_OPTDATA(SERVER_COMMUNICATION_RETRY_TIMER_ID, res[index], i, - res_inst[index], j); - INIT_OBJ_RES_OPTDATA(SERVER_COMMUNICATION_SEQUENCE_DELAY_TIMER_ID, res[index], i, - res_inst[index], j); - INIT_OBJ_RES_OPTDATA(SERVER_COMMUNICATION_SEQUENCE_RETRY_TIMER_ID, res[index], i, - res_inst[index], j); - INIT_OBJ_RES_OPTDATA(SERVER_SMS_TRIGGER_ID, res[index], i, res_inst[index], j); - INIT_OBJ_RES_OPTDATA(SERVER_PREFERRED_TRANSPORT_ID, res[index], i, res_inst[index], - j); - INIT_OBJ_RES_DATA(SERVER_MUTE_SEND_ID, res[index], i, res_inst[index], j, - &mute_send[index], sizeof(bool)); - } +#if defined(CONFIG_LWM2M_SERVER_OBJECT_VERSION_1_1) + INIT_OBJ_RES_EXECUTE(SERVER_BOOTSTRAP_UPDATE_TRIGGER_ID, res[index], i, + bootstrap_trigger_cb); + INIT_OBJ_RES_OPTDATA(SERVER_APN_LINK_ID, res[index], i, res_inst[index], j); + INIT_OBJ_RES_OPTDATA(SERVER_TLS_DTLS_ALERT_CODE_ID, res[index], i, res_inst[index], j); + INIT_OBJ_RES_OPTDATA(SERVER_LAST_BOOTSTRAPPED_ID, res[index], i, res_inst[index], j); + INIT_OBJ_RES_OPTDATA(SERVER_REGISTRATION_PRIORITY_ORDER_ID, res[index], i, res_inst[index], + j); + INIT_OBJ_RES_OPTDATA(SERVER_INITIAL_REGISTRATION_DELAY_TIMER_ID, res[index], i, + res_inst[index], j); + INIT_OBJ_RES_OPTDATA(SERVER_REGISTRATION_FAILURE_BLOCK_ID, res[index], i, res_inst[index], + j); + INIT_OBJ_RES_OPTDATA(SERVER_BOOTSTRAP_ON_REGISTRATION_FAILURE_ID, res[index], i, + res_inst[index], j); + INIT_OBJ_RES_OPTDATA(SERVER_COMMUNICATION_RETRY_COUNT_ID, res[index], i, res_inst[index], + j); + INIT_OBJ_RES_OPTDATA(SERVER_COMMUNICATION_RETRY_TIMER_ID, res[index], i, res_inst[index], + j); + INIT_OBJ_RES_OPTDATA(SERVER_COMMUNICATION_SEQUENCE_DELAY_TIMER_ID, res[index], i, + res_inst[index], j); + INIT_OBJ_RES_OPTDATA(SERVER_COMMUNICATION_SEQUENCE_RETRY_TIMER_ID, res[index], i, + res_inst[index], j); + INIT_OBJ_RES_OPTDATA(SERVER_SMS_TRIGGER_ID, res[index], i, res_inst[index], j); + INIT_OBJ_RES_OPTDATA(SERVER_PREFERRED_TRANSPORT_ID, res[index], i, res_inst[index], j); + INIT_OBJ_RES_DATA(SERVER_MUTE_SEND_ID, res[index], i, res_inst[index], j, &mute_send[index], + sizeof(bool)); +#endif /* defined(CONFIG_LWM2M_SERVER_OBJECT_VERSION_1_1) */ inst[index].resources = res[index]; inst[index].resource_count = i; diff --git a/subsys/net/lib/lwm2m/lwm2m_obj_server.h b/subsys/net/lib/lwm2m/lwm2m_obj_server.h deleted file mode 100644 index 56d7a674071..00000000000 --- a/subsys/net/lib/lwm2m/lwm2m_obj_server.h +++ /dev/null @@ -1,144 +0,0 @@ -/* - * Copyright (c) 2023 Nordic Semiconductor ASA - * - * SPDX-License-Identifier: Apache-2.0 - */ - -#ifndef LWM2M_OBJ_SERVER_H_ -#define LWM2M_OBJ_SERVER_H_ - -#include -#include -#include - -/* Server resource IDs */ -#define SERVER_SHORT_SERVER_ID 0 -#define SERVER_LIFETIME_ID 1 -#define SERVER_DEFAULT_MIN_PERIOD_ID 2 -#define SERVER_DEFAULT_MAX_PERIOD_ID 3 -#define SERVER_DISABLE_ID 4 -#define SERVER_DISABLE_TIMEOUT_ID 5 -#define SERVER_STORE_NOTIFY_ID 6 -#define SERVER_TRANSPORT_BINDING_ID 7 -#define SERVER_REG_UPDATE_TRIGGER_ID 8 -/* Server object version 1.1 resource IDs */ -#define SERVER_BOOTSTRAP_UPDATE_TRIGGER_ID 9 -#define SERVER_APN_LINK_ID 10 -#define SERVER_TLS_DTLS_ALERT_CODE_ID 11 -#define SERVER_LAST_BOOTSTRAPPED_ID 12 -#define SERVER_REGISTRATION_PRIORITY_ORDER_ID 13 -#define SERVER_INITIAL_REGISTRATION_DELAY_TIMER_ID 14 -#define SERVER_REGISTRATION_FAILURE_BLOCK_ID 15 -#define SERVER_BOOTSTRAP_ON_REGISTRATION_FAILURE_ID 16 -#define SERVER_COMMUNICATION_RETRY_COUNT_ID 17 -#define SERVER_COMMUNICATION_RETRY_TIMER_ID 18 -#define SERVER_COMMUNICATION_SEQUENCE_DELAY_TIMER_ID 19 -#define SERVER_COMMUNICATION_SEQUENCE_RETRY_TIMER_ID 20 -#define SERVER_SMS_TRIGGER_ID 21 -#define SERVER_PREFERRED_TRANSPORT_ID 22 -#define SERVER_MUTE_SEND_ID 23 - -/** - * @brief Returns the default minimum period for an observation set for the server - * with object instance id given by @p obj_inst_id. - * - * @param[in] obj_inst_id Object instance id of the server object instance - * @return int32_t pmin value - */ -int32_t lwm2m_server_get_pmin(uint16_t obj_inst_id); - -/** - * @brief Returns the default maximum period for an observation set for the server - * with object instance id given by @p obj_inst_id. - * - * @param[in] obj_inst_id Object instance id of the server object instance - * @return int32_t pmax value - */ -int32_t lwm2m_server_get_pmax(uint16_t obj_inst_id); - -/** - * @brief Returns the Short Server ID of the server object instance with - * object instance id given by @p obj_inst_id. - * - * @param[in] obj_inst_id Object instance id of the server object - * @return SSID or negative in case not found - */ -int lwm2m_server_get_ssid(uint16_t obj_inst_id); - -/** - * @brief Returns the object instance id of the server having ssid given by @p short_id. - * - * @param[in] short_id ssid of the server object - * @return Object instance id or negative in case not found - */ -int lwm2m_server_short_id_to_inst(uint16_t short_id); - -/** - * @brief Check if given server instance is not disabled - * - * @param[in] obj_inst_id server instance - * @return true if not disabled, false otherwise. - */ -bool lwm2m_server_is_enabled(uint16_t obj_inst_id); - -/** - * @brief Select server instance. - * - * Find possible server instance considering values on server data. - * Server candidates cannot be in disabled state and if priority values are set, - * those are compared and lowest values are considered first. - * - * If @ref obj_inst_id is NULL, this can be used to check if there are any server available. - * - * @param[out] obj_inst_id where selected server instance ID is written. Can be NULL. - * @return true if server instance was found, false otherwise. - */ -bool lwm2m_server_select(uint16_t *obj_inst_id); - -/** - * @brief Disable server instance for a period of time. - * - * Timeout values can be calculated using kernel macros like K_SECONDS(). - * Values like K_FOREVER or K_NO_WAIT are also accepted. - * - * @param timeout Timeout value. - * @return zero on success, negative error code otherwise. - */ -int lwm2m_server_disable(uint16_t obj_inst_id, k_timeout_t timeout); - -/** - * @brief Get timepoint how long server instance is disabled. - * - * If server instance is not disabled, this still returns a valid timepoint - * that have already expired. - * If the instance id is not valid, the timepoint is set to K_FOREVER. - * - * @param obj_inst_id Server instance ID. - * @return timepoint - */ -k_timepoint_t lwm2m_server_get_disabled_time(uint16_t obj_inst_id); - -/** - * @brief Get priority of given server instance. - * - * Lower values mean higher priority. - * If LwM2M server object version 1.1 is not enabled, - * this returns obj_inst_id as priority. - * - * @param obj_inst_id instance ID - * @return priority or UINT8_MAX if instance not found - */ -uint8_t lwm2m_server_get_prio(uint16_t obj_inst_id); - -/** - * @brief Reset all disable-timers for all server instances. - * - */ -void lwm2m_server_reset_timestamps(void); - -#if defined(CONFIG_LWM2M_SERVER_OBJECT_VERSION_1_1) -bool lwm2m_server_get_mute_send(uint16_t obj_inst_id); -#endif - - -#endif /* LWM2M_OBJ_SERVER_H_ */ diff --git a/subsys/net/lib/lwm2m/lwm2m_observation.c b/subsys/net/lib/lwm2m/lwm2m_observation.c index 1c8034e6535..9ee1fa6eda1 100644 --- a/subsys/net/lib/lwm2m/lwm2m_observation.c +++ b/subsys/net/lib/lwm2m/lwm2m_observation.c @@ -37,7 +37,6 @@ LOG_MODULE_REGISTER(LOG_MODULE_NAME); #include #include #include -#include "lwm2m_obj_server.h" #if defined(CONFIG_LWM2M_RW_SENML_JSON_SUPPORT) #include "lwm2m_rw_senml_json.h" diff --git a/subsys/net/lib/lwm2m/lwm2m_rd_client.c b/subsys/net/lib/lwm2m/lwm2m_rd_client.c index 6eacba0ee0d..d9f2e229edd 100644 --- a/subsys/net/lib/lwm2m/lwm2m_rd_client.c +++ b/subsys/net/lib/lwm2m/lwm2m_rd_client.c @@ -62,7 +62,6 @@ LOG_MODULE_REGISTER(LOG_MODULE_NAME); #include "lwm2m_rd_client.h" #include "lwm2m_rw_link_format.h" #include "lwm2m_util.h" -#include "lwm2m_obj_server.h" #define LWM2M_RD_CLIENT_URI "rd" #define CLIENT_EP_LEN CONFIG_LWM2M_RD_CLIENT_ENDPOINT_NAME_MAX_LENGTH From 5d5eef2633560c92cda6c6537c963d2c44f87516 Mon Sep 17 00:00:00 2001 From: Robert Lubos Date: Tue, 6 Feb 2024 11:07:16 +0100 Subject: [PATCH 3581/3723] Revert "[nrf fromtree] net: lwm2m: Allow finding security instance by short ID." This reverts commit 00b8ca550f27fcef408ec238fb576354e7ec1906. Signed-off-by: Robert Lubos --- subsys/net/lib/lwm2m/lwm2m_engine.h | 8 -------- subsys/net/lib/lwm2m/lwm2m_obj_security.c | 10 ---------- 2 files changed, 18 deletions(-) diff --git a/subsys/net/lib/lwm2m/lwm2m_engine.h b/subsys/net/lib/lwm2m/lwm2m_engine.h index 2ea3e583242..2306fced197 100644 --- a/subsys/net/lib/lwm2m/lwm2m_engine.h +++ b/subsys/net/lib/lwm2m/lwm2m_engine.h @@ -133,14 +133,6 @@ int lwm2m_engine_call_now(k_work_handler_t service); */ int lwm2m_security_inst_id_to_index(uint16_t obj_inst_id); -/** - * @brief Returns the object instance id of the security having ssid given by @p short_id. - * - * @param[in] short_id ssid of the security object - * @return Object instance id or negative in case not found - */ -int lwm2m_security_short_id_to_inst(uint16_t short_id); - /** * @brief Returns the object instance id of the security object instance at @p index * in the security object list. diff --git a/subsys/net/lib/lwm2m/lwm2m_obj_security.c b/subsys/net/lib/lwm2m/lwm2m_obj_security.c index 00796648634..874925c39d8 100644 --- a/subsys/net/lib/lwm2m/lwm2m_obj_security.c +++ b/subsys/net/lib/lwm2m/lwm2m_obj_security.c @@ -212,16 +212,6 @@ int lwm2m_security_index_to_inst_id(int index) return inst[index].obj_inst_id; } -int lwm2m_security_short_id_to_inst(uint16_t short_id) -{ - for (int i = 0; i < MAX_INSTANCE_COUNT; i++) { - if (short_server_id[i] == short_id) { - return inst[i].obj_inst_id; - } - } - return -ENOENT; -} - int lwm2m_security_mode(struct lwm2m_ctx *ctx) { int ret; From 53defb2adbf3eb76fec8ffdf02022a04abceff01 Mon Sep 17 00:00:00 2001 From: Robert Lubos Date: Tue, 6 Feb 2024 11:07:16 +0100 Subject: [PATCH 3582/3723] Revert "[nrf fromtree] net: lib: coap: Add coap_service_is_running" This reverts commit 717fb2bcdf37a5eb83dd4d6e1d9fa59ce0120e54. Signed-off-by: Robert Lubos --- include/zephyr/net/coap_service.h | 12 ------------ subsys/net/lib/coap/coap_server.c | 18 ------------------ 2 files changed, 30 deletions(-) diff --git a/include/zephyr/net/coap_service.h b/include/zephyr/net/coap_service.h index 6f038ce61e1..92a276d0d48 100644 --- a/include/zephyr/net/coap_service.h +++ b/include/zephyr/net/coap_service.h @@ -214,18 +214,6 @@ int coap_service_start(const struct coap_service *service); */ int coap_service_stop(const struct coap_service *service); -/** - * @brief Query the provided @p service running state. - * - * @note This function is suitable for a @p service defined with @ref COAP_SERVICE_DEFINE. - * - * @param service Pointer to CoAP service - * @retval 1 if the service is running - * @retval 0 if the service is stopped - * @retval negative in case of an error. - */ -int coap_service_is_running(const struct coap_service *service); - /** * @brief Send a CoAP message from the provided @p service . * diff --git a/subsys/net/lib/coap/coap_server.c b/subsys/net/lib/coap/coap_server.c index 386bc2081bb..009a0fe0274 100644 --- a/subsys/net/lib/coap/coap_server.c +++ b/subsys/net/lib/coap/coap_server.c @@ -483,24 +483,6 @@ int coap_service_stop(const struct coap_service *service) return ret; } -int coap_service_is_running(const struct coap_service *service) -{ - int ret; - - if (!coap_service_in_section(service)) { - __ASSERT_NO_MSG(false); - return -EINVAL; - } - - k_mutex_lock(&lock, K_FOREVER); - - ret = (service->data->sock_fd < 0) ? 0 : 1; - - k_mutex_unlock(&lock); - - return ret; -} - int coap_service_send(const struct coap_service *service, const struct coap_packet *cpkt, const struct sockaddr *addr, socklen_t addr_len) { From defacfdd36e29dd47e0a358abd5ced77c8d21ed7 Mon Sep 17 00:00:00 2001 From: Robert Lubos Date: Tue, 6 Feb 2024 11:07:16 +0100 Subject: [PATCH 3583/3723] Revert "[nrf fromtree] net: lib: coap: Fix return value documentation coap_service_start" This reverts commit da039ffccc0d0fbb15a702391d0bf2f10a36c427. Signed-off-by: Robert Lubos --- include/zephyr/net/coap_service.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/include/zephyr/net/coap_service.h b/include/zephyr/net/coap_service.h index 92a276d0d48..377c89a7bef 100644 --- a/include/zephyr/net/coap_service.h +++ b/include/zephyr/net/coap_service.h @@ -199,7 +199,7 @@ struct coap_service { * @param service Pointer to CoAP service * @retval 0 in case of success. * @retval -EALREADY in case of an already running service. - * @retval -ENOTSUP in case the server has no valid host and port configuration. + * @retval -ENOMEM in case the server has no available context. */ int coap_service_start(const struct coap_service *service); From cd9f69349feb035845d8ebcb2d506b06d22d4f92 Mon Sep 17 00:00:00 2001 From: Robert Lubos Date: Tue, 6 Feb 2024 11:07:16 +0100 Subject: [PATCH 3584/3723] Revert "[nrf fromtree] net: lib: coap: Init CoAP service socket fd to -1" This reverts commit 9dcf2ec3e25f0c7853541c039bd246a0f660e333. Signed-off-by: Robert Lubos --- include/zephyr/net/coap_service.h | 4 +--- subsys/net/lib/coap/coap_server.c | 3 +++ 2 files changed, 4 insertions(+), 3 deletions(-) diff --git a/include/zephyr/net/coap_service.h b/include/zephyr/net/coap_service.h index 377c89a7bef..3e3201308b9 100644 --- a/include/zephyr/net/coap_service.h +++ b/include/zephyr/net/coap_service.h @@ -57,9 +57,7 @@ struct coap_service { }; #define __z_coap_service_define(_name, _host, _port, _flags, _res_begin, _res_end) \ - static struct coap_service_data coap_service_data_##_name = { \ - .sock_fd = -1, \ - }; \ + static struct coap_service_data coap_service_data_##_name; \ const STRUCT_SECTION_ITERABLE(coap_service, _name) = { \ .name = STRINGIFY(_name), \ .host = _host, \ diff --git a/subsys/net/lib/coap/coap_server.c b/subsys/net/lib/coap/coap_server.c index 009a0fe0274..ac179f5545e 100644 --- a/subsys/net/lib/coap/coap_server.c +++ b/subsys/net/lib/coap/coap_server.c @@ -707,6 +707,9 @@ static void coap_server_thread(void *p1, void *p2, void *p3) } COAP_SERVICE_FOREACH(svc) { + /* Init all file descriptors to -1 */ + svc->data->sock_fd = -1; + if (svc->flags & COAP_SERVICE_AUTOSTART) { ret = coap_service_start(svc); if (ret < 0) { From 5f20cb709305902aee3a69e470eeb5bfc40e4bda Mon Sep 17 00:00:00 2001 From: Robert Lubos Date: Tue, 6 Feb 2024 11:07:17 +0100 Subject: [PATCH 3585/3723] Revert "[nrf fromtree] tests: net: lib: coap_server: Do not autostart service B with port 0" This reverts commit 56595ecd433cfacc8746bd47ac30735abdb68751. Signed-off-by: Robert Lubos --- tests/net/lib/coap_server/common/src/main.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/tests/net/lib/coap_server/common/src/main.c b/tests/net/lib/coap_server/common/src/main.c index 20c4b7c0317..7af940c5360 100644 --- a/tests/net/lib/coap_server/common/src/main.c +++ b/tests/net/lib/coap_server/common/src/main.c @@ -48,7 +48,7 @@ COAP_RESOURCE_DEFINE(resource_1, service_A, { }); static uint16_t service_B_port; -COAP_SERVICE_DEFINE(service_B, "b.service.com", &service_B_port, 0); +COAP_SERVICE_DEFINE(service_B, "b.service.com", &service_B_port, COAP_SERVICE_AUTOSTART); static const char * const resource_2_path[] = { "res2", "sub", NULL }; COAP_RESOURCE_DEFINE(resource_2, service_B, { @@ -132,7 +132,7 @@ ZTEST(coap_service, test_COAP_SERVICE_FOREACH) zassert_equal(svc->flags & COAP_SERVICE_AUTOSTART, COAP_SERVICE_AUTOSTART); } else if (svc == &service_B) { have_service_B = 1; - zassert_equal(svc->flags & COAP_SERVICE_AUTOSTART, 0); + zassert_equal(svc->flags & COAP_SERVICE_AUTOSTART, COAP_SERVICE_AUTOSTART); } else if (svc == &service_C) { have_service_C = 1; zassert_equal(svc->flags & COAP_SERVICE_AUTOSTART, 0); From d9583bb189891b9fc86567179cf2f7e37e04ecd7 Mon Sep 17 00:00:00 2001 From: Robert Lubos Date: Tue, 6 Feb 2024 11:07:17 +0100 Subject: [PATCH 3586/3723] Revert "[nrf fromtree] net: lib: coap: Translate handler errors to CoAP response codes" This reverts commit 601069bfb239219ed109c06472dce9b45ec57c6c. Signed-off-by: Robert Lubos --- subsys/net/lib/coap/coap_server.c | 13 ------------- 1 file changed, 13 deletions(-) diff --git a/subsys/net/lib/coap/coap_server.c b/subsys/net/lib/coap/coap_server.c index ac179f5545e..4b4f1719f46 100644 --- a/subsys/net/lib/coap/coap_server.c +++ b/subsys/net/lib/coap/coap_server.c @@ -220,19 +220,6 @@ static int coap_server_process(int sock_fd) COAP_SERVICE_RESOURCE_COUNT(service), options, opt_num, &client_addr, client_addr_len); - /* Translate errors to response codes */ - switch (ret) { - case -ENOENT: - ret = COAP_RESPONSE_CODE_NOT_FOUND; - break; - case -ENOTSUP: - ret = COAP_RESPONSE_CODE_BAD_REQUEST; - break; - case -EPERM: - ret = COAP_RESPONSE_CODE_NOT_ALLOWED; - break; - } - /* Shortcut for replying a code without a body */ if (ret > 0 && type == COAP_TYPE_CON) { /* Minimal sized ack buffer */ From 93ae4f6ca7becf52dd5e32b3cffb620c13971720 Mon Sep 17 00:00:00 2001 From: Robert Lubos Date: Tue, 6 Feb 2024 11:07:17 +0100 Subject: [PATCH 3587/3723] Revert "[nrf fromtree] tests: lwm2m_rd_client: Added more fff tests" This reverts commit f5555ac8164d085e79bf37ec1e537e47f7c7ea17. Signed-off-by: Robert Lubos --- .../net/lib/lwm2m/lwm2m_rd_client/src/main.c | 70 ------------------- .../net/lib/lwm2m/lwm2m_rd_client/src/stubs.c | 14 ---- .../net/lib/lwm2m/lwm2m_rd_client/src/stubs.h | 3 - 3 files changed, 87 deletions(-) diff --git a/tests/net/lib/lwm2m/lwm2m_rd_client/src/main.c b/tests/net/lib/lwm2m/lwm2m_rd_client/src/main.c index 208298512d4..931f6f15904 100644 --- a/tests/net/lib/lwm2m/lwm2m_rd_client/src/main.c +++ b/tests/net/lib/lwm2m/lwm2m_rd_client/src/main.c @@ -698,73 +698,3 @@ ZTEST(lwm2m_rd_client, test_bootstrap_no_srv_fallback_to_register) zassert_true(expect_lwm2m_rd_client_event(LWM2M_RD_CLIENT_EVENT_REGISTRATION_COMPLETE), NULL); } - -ZTEST(lwm2m_rd_client, test_start_stop_ignore_engine_fault) -{ - struct lwm2m_ctx ctx; - - (void)memset(&ctx, 0x0, sizeof(ctx)); - - test_prepare_pending_message_cb(&message_reply_cb_default); - - lwm2m_rd_client_init(); - test_lwm2m_engine_start_service(); - wait_for_service(1); - - lwm2m_engine_context_init_fake.custom_fake = lwm2m_engine_context_init_fake1; - lwm2m_get_bool_fake.custom_fake = lwm2m_get_bool_fake_default; - lwm2m_sprint_ip_addr_fake.custom_fake = lwm2m_sprint_ip_addr_fake_default; - lwm2m_init_message_fake.custom_fake = lwm2m_init_message_fake_default; - coap_header_get_code_fake.custom_fake = coap_header_get_code_fake_created; - coap_find_options_fake.custom_fake = coap_find_options_do_registration_reply_cb_ok; - zassert_true(lwm2m_rd_client_start(&ctx, "Test", 0, lwm2m_event_cb, lwm2m_observe_cb) == 0, - NULL); - zassert_true(expect_lwm2m_rd_client_event(LWM2M_RD_CLIENT_EVENT_REGISTRATION_COMPLETE), - NULL); - - coap_header_get_code_fake.custom_fake = coap_header_get_code_fake_deleted; - zassert_true(lwm2m_rd_client_stop(&ctx, lwm2m_event_cb, true) == 0, NULL); - zassert_true(expect_lwm2m_rd_client_event(LWM2M_RD_CLIENT_EVENT_DISCONNECT), NULL); - - int c = show_lwm2m_event_fake.call_count; - - test_throw_network_error_from_engine(EIO); - wait_for_service(10); - zassert_equal(show_lwm2m_event_fake.call_count, c, - "Should not enter any other state and throw an event"); -} - -ZTEST(lwm2m_rd_client, test_start_suspend_ignore_engine_fault) -{ - struct lwm2m_ctx ctx; - - (void)memset(&ctx, 0x0, sizeof(ctx)); - - test_prepare_pending_message_cb(&message_reply_cb_default); - - lwm2m_rd_client_init(); - test_lwm2m_engine_start_service(); - wait_for_service(1); - - lwm2m_engine_context_init_fake.custom_fake = lwm2m_engine_context_init_fake1; - lwm2m_get_bool_fake.custom_fake = lwm2m_get_bool_fake_default; - lwm2m_sprint_ip_addr_fake.custom_fake = lwm2m_sprint_ip_addr_fake_default; - lwm2m_init_message_fake.custom_fake = lwm2m_init_message_fake_default; - coap_header_get_code_fake.custom_fake = coap_header_get_code_fake_created; - coap_find_options_fake.custom_fake = coap_find_options_do_registration_reply_cb_ok; - zassert_true(lwm2m_rd_client_start(&ctx, "Test", 0, lwm2m_event_cb, lwm2m_observe_cb) == 0, - NULL); - zassert_true(expect_lwm2m_rd_client_event(LWM2M_RD_CLIENT_EVENT_REGISTRATION_COMPLETE), - NULL); - - coap_header_get_code_fake.custom_fake = coap_header_get_code_fake_deleted; - zassert_true(lwm2m_rd_client_pause() == 0, NULL); - zassert_true(expect_lwm2m_rd_client_event(LWM2M_RD_CLIENT_EVENT_ENGINE_SUSPENDED), NULL); - - int c = show_lwm2m_event_fake.call_count; - - test_throw_network_error_from_engine(EIO); - wait_for_service(10); - zassert_equal(show_lwm2m_event_fake.call_count, c, - "Should not enter any other state and throw an event"); -} diff --git a/tests/net/lib/lwm2m/lwm2m_rd_client/src/stubs.c b/tests/net/lib/lwm2m/lwm2m_rd_client/src/stubs.c index 3cbde9060ce..41789e20340 100644 --- a/tests/net/lib/lwm2m/lwm2m_rd_client/src/stubs.c +++ b/tests/net/lib/lwm2m/lwm2m_rd_client/src/stubs.c @@ -86,10 +86,6 @@ int lwm2m_get_u32_val(const struct lwm2m_obj_path *path, uint32_t *val) /* subsys/net/lib/lwm2m/lwm2m_engine.h */ DEFINE_FAKE_VALUE_FUNC(int, lwm2m_socket_start, struct lwm2m_ctx *); -int lwm2m_socket_start_fake_fail(struct lwm2m_ctx *client_ctx) -{ - return -1; -} DEFINE_FAKE_VALUE_FUNC(int, lwm2m_socket_close, struct lwm2m_ctx *); DEFINE_FAKE_VALUE_FUNC(int, lwm2m_close_socket, struct lwm2m_ctx *); DEFINE_FAKE_VALUE_FUNC(int, lwm2m_socket_suspend, struct lwm2m_ctx *); @@ -97,16 +93,6 @@ DEFINE_FAKE_VALUE_FUNC(int, lwm2m_security_inst_id_to_index, uint16_t); DEFINE_FAKE_VALUE_FUNC(int, lwm2m_engine_connection_resume, struct lwm2m_ctx *); DEFINE_FAKE_VALUE_FUNC(int, lwm2m_push_queued_buffers, struct lwm2m_ctx *); DEFINE_FAKE_VOID_FUNC(lwm2m_engine_context_init, struct lwm2m_ctx *); -struct lwm2m_ctx *client_ctx_fake; -void lwm2m_engine_context_init_fake1(struct lwm2m_ctx *client_ctx) -{ - client_ctx_fake = client_ctx; -} -void test_throw_network_error_from_engine(int err) -{ - client_ctx_fake->fault_cb(err); -} - DEFINE_FAKE_VOID_FUNC(lwm2m_engine_context_close, struct lwm2m_ctx *); DEFINE_FAKE_VALUE_FUNC(char *, lwm2m_sprint_ip_addr, const struct sockaddr *); char *lwm2m_sprint_ip_addr_fake_default(const struct sockaddr *addr) diff --git a/tests/net/lib/lwm2m/lwm2m_rd_client/src/stubs.h b/tests/net/lib/lwm2m/lwm2m_rd_client/src/stubs.h index 1276dd5c109..620e4d8fc12 100644 --- a/tests/net/lib/lwm2m/lwm2m_rd_client/src/stubs.h +++ b/tests/net/lib/lwm2m/lwm2m_rd_client/src/stubs.h @@ -54,7 +54,6 @@ int lwm2m_get_u32_val(const struct lwm2m_obj_path *path, uint32_t *val); /* subsys/net/lib/lwm2m/lwm2m_engine.h */ DECLARE_FAKE_VALUE_FUNC(int, lwm2m_socket_start, struct lwm2m_ctx *); -int lwm2m_socket_start_fake_fail(struct lwm2m_ctx *client_ctx); DECLARE_FAKE_VALUE_FUNC(int, lwm2m_socket_close, struct lwm2m_ctx *); DECLARE_FAKE_VALUE_FUNC(int, lwm2m_close_socket, struct lwm2m_ctx *); DECLARE_FAKE_VALUE_FUNC(int, lwm2m_socket_suspend, struct lwm2m_ctx *); @@ -62,8 +61,6 @@ DECLARE_FAKE_VALUE_FUNC(int, lwm2m_security_inst_id_to_index, uint16_t); DECLARE_FAKE_VALUE_FUNC(int, lwm2m_engine_connection_resume, struct lwm2m_ctx *); DECLARE_FAKE_VALUE_FUNC(int, lwm2m_push_queued_buffers, struct lwm2m_ctx *); DECLARE_FAKE_VOID_FUNC(lwm2m_engine_context_init, struct lwm2m_ctx *); -void lwm2m_engine_context_init_fake1(struct lwm2m_ctx *client_ctx); -void test_throw_network_error_from_engine(int err); DECLARE_FAKE_VOID_FUNC(lwm2m_engine_context_close, struct lwm2m_ctx *); DECLARE_FAKE_VALUE_FUNC(char *, lwm2m_sprint_ip_addr, const struct sockaddr *); char *lwm2m_sprint_ip_addr_fake_default(const struct sockaddr *addr); From 424d6154666f5d620fd66a47c44810196ceedc28 Mon Sep 17 00:00:00 2001 From: Robert Lubos Date: Tue, 6 Feb 2024 11:07:17 +0100 Subject: [PATCH 3588/3723] Revert "[nrf fromtree] samples: lwm2m: Add support for Connection Manager" This reverts commit 03aacf0cfc5d2235d5812b0ccd4103c99bc23e5c. Signed-off-by: Robert Lubos --- samples/net/lwm2m_client/src/lwm2m-client.c | 78 --------------------- 1 file changed, 78 deletions(-) diff --git a/samples/net/lwm2m_client/src/lwm2m-client.c b/samples/net/lwm2m_client/src/lwm2m-client.c index a120506639d..748f654d9ee 100644 --- a/samples/net/lwm2m_client/src/lwm2m-client.c +++ b/samples/net/lwm2m_client/src/lwm2m-client.c @@ -16,8 +16,6 @@ LOG_MODULE_REGISTER(LOG_MODULE_NAME); #include #include #include -#include -#include #include "modules.h" #define APP_BANNER "Run LWM2M client" @@ -31,10 +29,6 @@ LOG_MODULE_REGISTER(LOG_MODULE_NAME); #define CLIENT_FIRMWARE_VER "1.0" #define CLIENT_HW_VER "1.0.1" -/* Macros used to subscribe to specific Zephyr NET management events. */ -#define L4_EVENT_MASK (NET_EVENT_L4_CONNECTED | NET_EVENT_L4_DISCONNECTED) -#define CONN_LAYER_EVENT_MASK (NET_EVENT_CONN_IF_FATAL_ERROR) - static uint8_t bat_idx = LWM2M_DEVICE_PWR_SRC_TYPE_BAT_INT; static int bat_mv = 3800; static int bat_ma = 125; @@ -58,12 +52,6 @@ BUILD_ASSERT(sizeof(endpoint) <= CONFIG_LWM2M_SECURITY_KEY_SIZE, static struct k_sem quit_lock; -/* Zephyr NET management event callback structures. */ -static struct net_mgmt_event_callback l4_cb; -static struct net_mgmt_event_callback conn_cb; - -static K_SEM_DEFINE(network_connected_sem, 0, 1); - static int device_reboot_cb(uint16_t obj_inst_id, uint8_t *args, uint16_t args_len) { @@ -277,47 +265,6 @@ static void observe_cb(enum lwm2m_observe_event event, } } -static void on_net_event_l4_disconnected(void) -{ - LOG_INF("Disconnected from network"); - lwm2m_engine_pause(); -} - -static void on_net_event_l4_connected(void) -{ - LOG_INF("Connected to network"); - k_sem_give(&network_connected_sem); - lwm2m_engine_resume(); -} - -static void l4_event_handler(struct net_mgmt_event_callback *cb, - uint32_t event, - struct net_if *iface) -{ - switch (event) { - case NET_EVENT_L4_CONNECTED: - LOG_INF("IP Up"); - on_net_event_l4_connected(); - break; - case NET_EVENT_L4_DISCONNECTED: - LOG_INF("IP down"); - on_net_event_l4_disconnected(); - break; - default: - break; - } -} - -static void connectivity_event_handler(struct net_mgmt_event_callback *cb, - uint32_t event, - struct net_if *iface) -{ - if (event == NET_EVENT_CONN_IF_FATAL_ERROR) { - LOG_ERR("Fatal error received from the connectivity layer"); - return; - } -} - int main(void) { uint32_t flags = IS_ENABLED(CONFIG_LWM2M_RD_CLIENT_SUPPORT_BOOTSTRAP) ? @@ -328,31 +275,6 @@ int main(void) k_sem_init(&quit_lock, 0, K_SEM_MAX_LIMIT); - if (IS_ENABLED(CONFIG_NET_CONNECTION_MANAGER)) { - /* Setup handler for Zephyr NET Connection Manager events. */ - net_mgmt_init_event_callback(&l4_cb, l4_event_handler, L4_EVENT_MASK); - net_mgmt_add_event_callback(&l4_cb); - - /* Setup handler for Zephyr NET Connection Manager Connectivity layer. */ - net_mgmt_init_event_callback(&conn_cb, connectivity_event_handler, - CONN_LAYER_EVENT_MASK); - net_mgmt_add_event_callback(&conn_cb); - - ret = net_if_up(net_if_get_default()); - - if (ret < 0 && ret != -EALREADY) { - LOG_ERR("net_if_up, error: %d", ret); - return ret; - } - - ret = conn_mgr_if_connect(net_if_get_default()); - /* Ignore errors from interfaces not requiring connectivity */ - if (ret == 0) { - LOG_INF("Connecting to network"); - k_sem_take(&network_connected_sem, K_FOREVER); - } - } - ret = lwm2m_setup(); if (ret < 0) { LOG_ERR("Cannot setup LWM2M fields (%d)", ret); From 7b5c2cb02621a0aafcb94826a7fdcaa9f65f6bbe Mon Sep 17 00:00:00 2001 From: Robert Lubos Date: Tue, 6 Feb 2024 11:07:17 +0100 Subject: [PATCH 3589/3723] Revert "[nrf fromtree] test: lwm2m: Test cancellation using observe parameter" This reverts commit b120890dddda2eb725ed66d78fa815126d972d65. Signed-off-by: Robert Lubos --- tests/net/lib/lwm2m/interop/README.md | 4 +-- tests/net/lib/lwm2m/interop/pytest/leshan.py | 7 ----- .../lib/lwm2m/interop/pytest/test_lwm2m.py | 30 ++----------------- 3 files changed, 5 insertions(+), 36 deletions(-) diff --git a/tests/net/lib/lwm2m/interop/README.md b/tests/net/lib/lwm2m/interop/README.md index 3acbfcc71f8..204aff636ac 100644 --- a/tests/net/lib/lwm2m/interop/README.md +++ b/tests/net/lib/lwm2m/interop/README.md @@ -172,9 +172,9 @@ Tests are written from test spec; |LightweightM2M-1.1-int-281 - Partially Successful Read-Composite Operation|:white_check_mark:| | |LightweightM2M-1.1-int-301 - Observation and Notification of parameter values|:white_check_mark:| | |LightweightM2M-1.1-int-302 - Cancel Observations using Reset Operation|:white_check_mark:| | -|LightweightM2M-1.1-int-303 - Cancel observations using Observe with Cancel parameter|:white_check_mark:|| +|LightweightM2M-1.1-int-303 - Cancel observations using Observe with Cancel parameter|:large_orange_diamond:|Leshan only supports passive cancelling| |LightweightM2M-1.1-int-304 - Observe-Composite Operation|:white_check_mark:| | -|LightweightM2M-1.1-int-305 - Cancel Observation-Composite Operation|:white_check_mark:| | +|LightweightM2M-1.1-int-305 - Cancel Observation-Composite Operation|:large_orange_diamond:|Leshan only supports passive cancelling| |LightweightM2M-1.1-int-306 – Send Operation|:white_check_mark:|[~~#64290~~](https://github.com/zephyrproject-rtos/zephyr/issues/64290)| |LightweightM2M-1.1-int-307 – Muting Send|:white_check_mark:| | |LightweightM2M-1.1-int-308 - Observe-Composite and Creating Object Instance|:white_check_mark:|[~~#64634~~](https://github.com/zephyrproject-rtos/zephyr/issues/64634)| diff --git a/tests/net/lib/lwm2m/interop/pytest/leshan.py b/tests/net/lib/lwm2m/interop/pytest/leshan.py index 181f15ebf61..65295e652bc 100644 --- a/tests/net/lib/lwm2m/interop/pytest/leshan.py +++ b/tests/net/lib/lwm2m/interop/pytest/leshan.py @@ -389,9 +389,6 @@ def observe(self, endpoint: str, path: str): return self.post(f'/clients/{endpoint}/{path}/observe', data="") def cancel_observe(self, endpoint: str, path: str): - return self.delete_raw(f'/clients/{endpoint}/{path}/observe?active') - - def passive_cancel_observe(self, endpoint: str, path: str): return self.delete_raw(f'/clients/{endpoint}/{path}/observe') def composite_observe(self, endpoint: str, paths: list[str]): @@ -401,10 +398,6 @@ def composite_observe(self, endpoint: str, paths: list[str]): return self.parse_composite(payload) def cancel_composite_observe(self, endpoint: str, paths: list[str]): - paths = [path if path.startswith('/') else '/' + path for path in paths] - return self.delete_raw(f'/clients/{endpoint}/composite/observe?paths=' + ','.join(paths) + '&active') - - def passive_cancel_composite_observe(self, endpoint: str, paths: list[str]): paths = [path if path.startswith('/') else '/' + path for path in paths] return self.delete_raw(f'/clients/{endpoint}/composite/observe?paths=' + ','.join(paths)) diff --git a/tests/net/lib/lwm2m/interop/pytest/test_lwm2m.py b/tests/net/lib/lwm2m/interop/pytest/test_lwm2m.py index 131acb68e14..eabc4bbc614 100644 --- a/tests/net/lib/lwm2m/interop/pytest/test_lwm2m.py +++ b/tests/net/lib/lwm2m/interop/pytest/test_lwm2m.py @@ -532,40 +532,24 @@ def test_LightweightM2M_1_1_int_301(shell: Shell, leshan: Leshan, endpoint: str) leshan.cancel_observe(endpoint, '3/0/7') leshan.remove_attributes(endpoint, '3/0/7', ['pmin', 'pmax']) +@pytest.mark.slow def test_LightweightM2M_1_1_int_302(shell: Shell, dut: DeviceAdapter, leshan: Leshan, endpoint: str): """LightweightM2M-1.1-int-302 - Cancel Observations using Reset Operation""" leshan.observe(endpoint, '3/0/7') leshan.observe(endpoint, '3/0/8') - with leshan.get_event_stream(endpoint) as events: - shell.exec_command('lwm2m write /3/0/7/0 -u32 4000') - data = events.next_event('NOTIFICATION') - assert data[3][0][7][0] == 4000 - leshan.passive_cancel_observe(endpoint, '3/0/7') - shell.exec_command('lwm2m write /3/0/7/0 -u32 3000') - dut.readlines_until(regex=r'.*Observer removed for 3/0/7') - with leshan.get_event_stream(endpoint) as events: - shell.exec_command('lwm2m write /3/0/8/0 -u32 100') - data = events.next_event('NOTIFICATION') - assert data[3][0][8][0] == 100 - leshan.passive_cancel_observe(endpoint, '3/0/8') - shell.exec_command('lwm2m write /3/0/8/0 -u32 50') - dut.readlines_until(regex=r'.*Observer removed for 3/0/8') - -def test_LightweightM2M_1_1_int_303(shell: Shell, dut: DeviceAdapter, leshan: Leshan, endpoint: str): - """LightweightM2M-1.1-int-303 - Cancel observations using Observe with Cancel parameter""" - leshan.observe(endpoint, '3/0/7') - leshan.observe(endpoint, '3/0/8') with leshan.get_event_stream(endpoint) as events: shell.exec_command('lwm2m write /3/0/7/0 -u32 4000') data = events.next_event('NOTIFICATION') assert data[3][0][7][0] == 4000 leshan.cancel_observe(endpoint, '3/0/7') + shell.exec_command('lwm2m write /3/0/7/0 -u32 3000') dut.readlines_until(regex=r'.*Observer removed for 3/0/7') with leshan.get_event_stream(endpoint) as events: shell.exec_command('lwm2m write /3/0/8/0 -u32 100') data = events.next_event('NOTIFICATION') assert data[3][0][8][0] == 100 leshan.cancel_observe(endpoint, '3/0/8') + shell.exec_command('lwm2m write /3/0/8/0 -u32 50') dut.readlines_until(regex=r'.*Observer removed for 3/0/8') @pytest.mark.slow @@ -600,14 +584,6 @@ def test_LightweightM2M_1_1_int_304(shell: Shell, leshan: Leshan, endpoint: str) shell.exec_command('lwm2m write 1/0/3 -u32 10') leshan.remove_attributes(endpoint, '1/0/1', ['pmin', 'pmax']) -def test_LightweightM2M_1_1_int_305(dut: DeviceAdapter, leshan: Leshan, endpoint: str): - """LightweightM2M-1.1-int-305 - Cancel Observation-Composite Operation""" - leshan.composite_observe(endpoint, ['/1/0/1', '/3/0/11/0', '/3/0/16']) - leshan.cancel_composite_observe(endpoint, ['/1/0/1', '/3/0/11/0', '/3/0/16']) - dut.readlines_until(regex=r'.*Observer removed for 1/0/1') - dut.readlines_until(regex=r'.*Observer removed for 3/0/11/0') - dut.readlines_until(regex=r'.*Observer removed for 3/0/16') - def test_LightweightM2M_1_1_int_306(shell: Shell, dut: DeviceAdapter, leshan: Leshan, endpoint: str): """LightweightM2M-1.1-int-306 - Send Operation""" with leshan.get_event_stream(endpoint) as events: From 11f0ad356bb2553bf78b430122a12b6195923217 Mon Sep 17 00:00:00 2001 From: Robert Lubos Date: Tue, 6 Feb 2024 11:07:17 +0100 Subject: [PATCH 3590/3723] Revert "[nrf fromtree] test: lwm2m: Implement Read-Composite Operation on root path" This reverts commit 913d9a36ff76cc8c01e7d68228ff13519ac27a12. Signed-off-by: Robert Lubos --- tests/net/lib/lwm2m/interop/README.md | 2 +- tests/net/lib/lwm2m/interop/pytest/leshan.py | 4 ---- tests/net/lib/lwm2m/interop/pytest/test_lwm2m.py | 7 ++----- 3 files changed, 3 insertions(+), 10 deletions(-) diff --git a/tests/net/lib/lwm2m/interop/README.md b/tests/net/lib/lwm2m/interop/README.md index 204aff636ac..3654ca94b01 100644 --- a/tests/net/lib/lwm2m/interop/README.md +++ b/tests/net/lib/lwm2m/interop/README.md @@ -160,7 +160,7 @@ Tests are written from test spec; |LightweightM2M-1.1-int-232 - Querying basic information in SenML CBOR format|:white_check_mark:| | |LightweightM2M-1.1-int-233 - Setting basic information in SenML CBOR format|:white_check_mark:| | |LightweightM2M-1.1-int-234 - Setting basic information in SenML JSON format|:white_check_mark:| | -|LightweightM2M-1.1-int-235 - Read-Composite Operation on root path|:white_check_mark:| | +|LightweightM2M-1.1-int-235 - Read-Composite Operation on root path|:large_orange_diamond:|Root Path is not yet supported by Leshan.| |LightweightM2M-1.1-int-236 - Read-Composite - Partial Presence|:white_check_mark:| | |LightweightM2M-1.1-int-237 - Read on Object without specifying Content-Type|:white_check_mark:| | |LightweightM2M-1.1-int-241 - Executable Resource: Rebooting the device|:white_check_mark:| | diff --git a/tests/net/lib/lwm2m/interop/pytest/leshan.py b/tests/net/lib/lwm2m/interop/pytest/leshan.py index 65295e652bc..4add988ea77 100644 --- a/tests/net/lib/lwm2m/interop/pytest/leshan.py +++ b/tests/net/lib/lwm2m/interop/pytest/leshan.py @@ -271,10 +271,6 @@ def parse_composite(cls, payload: dict): raise RuntimeError(f'No content received') payload = payload['content'] for path, content in payload.items(): - if path == "/": - for obj in content['objects']: - data.update(cls._decode_obj(obj)) - continue keys = [int(key) for key in path.lstrip("/").split('/')] if len(keys) == 1: data.update(cls._decode_obj(content)) diff --git a/tests/net/lib/lwm2m/interop/pytest/test_lwm2m.py b/tests/net/lib/lwm2m/interop/pytest/test_lwm2m.py index eabc4bbc614..f596f74d30a 100644 --- a/tests/net/lib/lwm2m/interop/pytest/test_lwm2m.py +++ b/tests/net/lib/lwm2m/interop/pytest/test_lwm2m.py @@ -367,12 +367,9 @@ def test_LightweightM2M_1_1_int_234(shell: Shell, leshan: Leshan, endpoint: str) """LightweightM2M-1.1-int-234 - Setting basic information in SenML JSON format""" setting_basic_senml(shell, leshan, endpoint, 'SENML_JSON') -def test_LightweightM2M_1_1_int_235(leshan: Leshan, endpoint: str): +@pytest.mark.skip("Leshan does not allow reading root path") +def test_LightweightM2M_1_1_int_235(): """LightweightM2M-1.1-int-235 - Read-Composite Operation on root path""" - resp = leshan.composite_read(endpoint, ['/']) - expected_keys = [16, 1, 3, 5] - missing_keys = [key for key in expected_keys if key not in resp.keys()] - assert len(missing_keys) == 0 def test_LightweightM2M_1_1_int_236(shell: Shell, leshan: Leshan, endpoint: str): """LightweightM2M-1.1-int-236 - Read-Composite - Partial Presence""" From 84a31ca892000c70bb9051643ee703073a493a95 Mon Sep 17 00:00:00 2001 From: Robert Lubos Date: Tue, 6 Feb 2024 11:07:17 +0100 Subject: [PATCH 3591/3723] Revert "[nrf fromtree] test: lwm2m: Implement write_attributes()" This reverts commit 1f4da8e3d3d31db845cf7df983e031b5211fa7aa. Signed-off-by: Robert Lubos --- tests/net/lib/lwm2m/interop/README.md | 2 +- tests/net/lib/lwm2m/interop/pytest/leshan.py | 19 +------ .../lib/lwm2m/interop/pytest/test_lwm2m.py | 56 +++++++++---------- 3 files changed, 29 insertions(+), 48 deletions(-) diff --git a/tests/net/lib/lwm2m/interop/README.md b/tests/net/lib/lwm2m/interop/README.md index 3654ca94b01..bda38924d26 100644 --- a/tests/net/lib/lwm2m/interop/README.md +++ b/tests/net/lib/lwm2m/interop/README.md @@ -167,7 +167,7 @@ Tests are written from test spec; |LightweightM2M-1.1-int-256 - Write Operation Failure|:white_check_mark:| | |LightweightM2M-1.1-int-257 - Write-Composite Operation|:white_check_mark:| | |LightweightM2M-1.1-int-260 - Discover Command|:white_check_mark:| | -|LightweightM2M-1.1-int-261 - Write-Attribute Operation on a multiple resource|:white_check_mark:| | +|LightweightM2M-1.1-int-261 - Write-Attribute Operation on a multiple resource|:large_orange_diamond:|Leshan don't allow writing attributes to resource instance| |LightweightM2M-1.1-int-280 - Successful Read-Composite Operation|:white_check_mark:| | |LightweightM2M-1.1-int-281 - Partially Successful Read-Composite Operation|:white_check_mark:| | |LightweightM2M-1.1-int-301 - Observation and Notification of parameter values|:white_check_mark:| | diff --git a/tests/net/lib/lwm2m/interop/pytest/leshan.py b/tests/net/lib/lwm2m/interop/pytest/leshan.py index 4add988ea77..7240aae2baf 100644 --- a/tests/net/lib/lwm2m/interop/pytest/leshan.py +++ b/tests/net/lib/lwm2m/interop/pytest/leshan.py @@ -62,9 +62,9 @@ def get(self, path: str): resp = self._s.get(f'{self.api_url}{path}', params=params, timeout=self.timeout) return Leshan.handle_response(resp) - def put_raw(self, path: str, data: str | dict | None = None, headers: dict | None = None, params: dict | None = None): + def put_raw(self, path: str, data: str | dict | None = None, headers: dict | None = None): """Send HTTP PUT query without any default parameters""" - resp = self._s.put(f'{self.api_url}{path}', data=data, headers=headers, params=params, timeout=self.timeout) + resp = self._s.put(f'{self.api_url}{path}', data=data, headers=headers, timeout=self.timeout) return Leshan.handle_response(resp) def put(self, path: str, data: str | dict, uri_options: str = ''): @@ -108,21 +108,6 @@ def write(self, endpoint: str, path: str, value: bool | int | str): rid = path.split('/')[-1] return self.put(f'/clients/{endpoint}/{path}', self._define_resource(rid, value, kind)) - def write_attributes(self, endpoint: str, path: str, attributes: dict): - """Send LwM2M Write-Attributes to given path - example: - leshan.write_attributes(endpoint, '1/2/3, {'pmin': 10, 'pmax': 40}) - """ - return self.put_raw(f'/clients/{endpoint}/{path}/attributes', params=attributes) - - def remove_attributes(self, endpoint: str, path: str, attributes: list): - """Send LwM2M Write-Attributes to given path - example: - leshan.remove_attributes(endpoint, '1/2/3, ['pmin', 'pmax']) - """ - attrs = '&'.join(attributes) - return self.put_raw(f'/clients/{endpoint}/{path}/attributes?'+ attrs) - def update_obj_instance(self, endpoint: str, path: str, resources: dict): """Update object instance""" data = self._define_obj_inst(path, resources) diff --git a/tests/net/lib/lwm2m/interop/pytest/test_lwm2m.py b/tests/net/lib/lwm2m/interop/pytest/test_lwm2m.py index f596f74d30a..c37a3900aa6 100644 --- a/tests/net/lib/lwm2m/interop/pytest/test_lwm2m.py +++ b/tests/net/lib/lwm2m/interop/pytest/test_lwm2m.py @@ -202,7 +202,7 @@ def test_LightweightM2M_1_1_int_221(shell: Shell, leshan: Leshan, endpoint: str) """LightweightM2M-1.1-int-221 - Attempt to perform operations on Security""" assert leshan.read(endpoint, '0/0')['status'] == 'UNAUTHORIZED(401)' assert leshan.write(endpoint, '0/0/0', 'coap://localhost')['status'] == 'UNAUTHORIZED(401)' - assert leshan.write_attributes(endpoint, '0', {'pmin':10})['status'] == 'UNAUTHORIZED(401)' + assert leshan.put_raw(f'/clients/{endpoint}/0/attributes?pmin=10')['status'] == 'UNAUTHORIZED(401)' def test_LightweightM2M_1_1_int_222(shell: Shell, leshan: Leshan, endpoint: str): """LightweightM2M-1.1-int-222 - Read on Object""" @@ -429,12 +429,15 @@ def test_LightweightM2M_1_1_int_260(shell: Shell, leshan: Leshan, endpoint: str) expected_keys = ['/3', '/3/0', '/3/0/1', '/3/0/2', '/3/0/3', '/3/0/4', '/3/0/6', '/3/0/7', '/3/0/8', '/3/0/9', '/3/0/11', '/3/0/16'] missing_keys = [key for key in expected_keys if key not in resp.keys()] assert len(missing_keys) == 0 - assert leshan.write_attributes(endpoint, '3', {'pmin': 10, 'pmax': 200})['status'] == 'CHANGED(204)' + assert leshan.put_raw(f'/clients/{endpoint}/3/attributes?pmin=10')['status'] == 'CHANGED(204)' + assert leshan.put_raw(f'/clients/{endpoint}/3/attributes?pmax=200')['status'] == 'CHANGED(204)' resp = leshan.discover(endpoint, '3/0') assert int(resp['/3/0/6']['dim']) == 2 assert int(resp['/3/0/7']['dim']) == 2 assert int(resp['/3/0/8']['dim']) == 2 - assert leshan.write_attributes(endpoint, '3/0/7', {'lt': 1, 'gt': 6, 'st': 1})['status'] == 'CHANGED(204)' + assert leshan.put_raw(f'/clients/{endpoint}/3/0/7/attributes?lt=1')['status'] == 'CHANGED(204)' + assert leshan.put_raw(f'/clients/{endpoint}/3/0/7/attributes?gt=6')['status'] == 'CHANGED(204)' + assert leshan.put_raw(f'/clients/{endpoint}/3/0/7/attributes?st=1')['status'] == 'CHANGED(204)' resp = leshan.discover(endpoint, '3/0') expected_keys = ['/3/0', '/3/0/1', '/3/0/2', '/3/0/3', '/3/0/4', '/3/0/6', '/3/0/7', '/3/0/8', '/3/0/9', '/3/0/11', '/3/0/16'] missing_keys = [key for key in expected_keys if key not in resp.keys()] @@ -448,9 +451,8 @@ def test_LightweightM2M_1_1_int_260(shell: Shell, leshan: Leshan, endpoint: str) missing_keys = [key for key in expected_keys if key not in resp.keys()] assert len(missing_keys) == 0 assert len(resp) == len(expected_keys) - # restore - leshan.remove_attributes(endpoint, '3', ['pmin', 'pmax']) +@pytest.mark.skip(reason="Leshan don't allow writing attributes to resource instance") def test_LightweightM2M_1_1_int_261(shell: Shell, leshan: Leshan, endpoint: str): """LightweightM2M-1.1-int-261 - Write-Attribute Operation on a multiple resource""" resp = leshan.discover(endpoint, '3/0/11') @@ -460,20 +462,19 @@ def test_LightweightM2M_1_1_int_261(shell: Shell, leshan: Leshan, endpoint: str) assert len(missing_keys) == 0 assert len(resp) == len(expected_keys) assert int(resp['/3/0/11']['dim']) == 1 - assert leshan.write_attributes(endpoint, '3', {'pmin':10, 'pmax':200})['status'] == 'CHANGED(204)' - assert leshan.write_attributes(endpoint, '3/0', {'pmax':320})['status'] == 'CHANGED(204)' - assert leshan.write_attributes(endpoint, '3/0/11/0', {'pmax':100, 'epmin':1, 'epmax':20})['status'] == 'CHANGED(204)' + assert leshan.put_raw(f'/clients/{endpoint}/3/attributes?pmin=10')['status'] == 'CHANGED(204)' + assert leshan.put_raw(f'/clients/{endpoint}/3/attributes?pmax=200')['status'] == 'CHANGED(204)' + assert leshan.put_raw(f'/clients/{endpoint}/3/0/attributes?pmax=320')['status'] == 'CHANGED(204)' + assert leshan.put_raw(f'/clients/{endpoint}/3/0/11/0/attributes?pmax=100')['status'] == 'CHANGED(204)' + assert leshan.put_raw(f'/clients/{endpoint}/3/0/11/0/attributes?epmin=1')['status'] == 'CHANGED(204)' + assert leshan.put_raw(f'/clients/{endpoint}/3/0/11/0/attributes?epmax=20')['status'] == 'CHANGED(204)' resp = leshan.discover(endpoint, '3/0/11') logger.debug(resp) assert int(resp['/3/0/11']['pmin']) == 10 assert int(resp['/3/0/11']['pmax']) == 320 assert int(resp['/3/0/11/0']['pmax']) == 100 - # Note: Zephyr does not support epmin&epmax. - # Restore - leshan.remove_attributes(endpoint, '3', ['pmin', 'pmax']) - leshan.remove_attributes(endpoint, '3/0', ['pmax']) - leshan.remove_attributes(endpoint, '3/0/11/0', ['pmax']) - + assert int(resp['/3/0/11/0']['epmin']) == 1 + assert int(resp['/3/0/11/0']['epmax']) == 20 def test_LightweightM2M_1_1_int_280(shell: Shell, leshan: Leshan, endpoint: str): """LightweightM2M-1.1-int-280 - Successful Read-Composite Operation""" @@ -508,7 +509,8 @@ def test_LightweightM2M_1_1_int_301(shell: Shell, leshan: Leshan, endpoint: str) logger.debug(pwr_src) assert pwr_src[6][0] == 1 assert pwr_src[6][1] == 5 - assert leshan.write_attributes(endpoint, '3/0/7', {'pmin': 5, 'pmax': 10})['status'] == 'CHANGED(204)' + assert leshan.put_raw(f'/clients/{endpoint}/3/0/7/attributes?pmin=5')['status'] == 'CHANGED(204)' + assert leshan.put_raw(f'/clients/{endpoint}/3/0/7/attributes?pmax=10')['status'] == 'CHANGED(204)' leshan.observe(endpoint, '3/0/7') with leshan.get_event_stream(endpoint, timeout=30) as events: shell.exec_command('lwm2m write /3/0/7/0 -u32 3000') @@ -527,7 +529,6 @@ def test_LightweightM2M_1_1_int_301(shell: Shell, leshan: Leshan, endpoint: str) assert data[3][0][7][0] == 3500 assert (start + 15) <= time.time() + 1 # Allow 1 second slack. (pMinx + pMax=15) leshan.cancel_observe(endpoint, '3/0/7') - leshan.remove_attributes(endpoint, '3/0/7', ['pmin', 'pmax']) @pytest.mark.slow def test_LightweightM2M_1_1_int_302(shell: Shell, dut: DeviceAdapter, leshan: Leshan, endpoint: str): @@ -552,10 +553,8 @@ def test_LightweightM2M_1_1_int_302(shell: Shell, dut: DeviceAdapter, leshan: Le @pytest.mark.slow def test_LightweightM2M_1_1_int_304(shell: Shell, leshan: Leshan, endpoint: str): """LightweightM2M-1.1-int-304 - Observe-Composite Operation""" - # Need to use Configuration C.1 - shell.exec_command('lwm2m write 1/0/2 -u32 0') - shell.exec_command('lwm2m write 1/0/3 -u32 0') - assert leshan.write_attributes(endpoint, '1/0/1', {'pmin': 30, 'pmax': 45})['status'] == 'CHANGED(204)' + assert leshan.put_raw(f'/clients/{endpoint}/1/0/1/attributes?pmin=30')['status'] == 'CHANGED(204)' + assert leshan.put_raw(f'/clients/{endpoint}/1/0/1/attributes?pmax=45')['status'] == 'CHANGED(204)' data = leshan.composite_observe(endpoint, ['/1/0/1', '/3/0/11/0', '/3/0/16']) assert data[1][0][1] is not None assert data[3][0][11][0] is not None @@ -576,10 +575,6 @@ def test_LightweightM2M_1_1_int_304(shell: Shell, leshan: Leshan, endpoint: str) assert (start + 30) < time.time() assert (start + 45) > time.time() - 1 leshan.cancel_composite_observe(endpoint, ['/1/0/1', '/3/0/11/0', '/3/0/16']) - # Restore configuration C.3 - shell.exec_command('lwm2m write 1/0/2 -u32 1') - shell.exec_command('lwm2m write 1/0/3 -u32 10') - leshan.remove_attributes(endpoint, '1/0/1', ['pmin', 'pmax']) def test_LightweightM2M_1_1_int_306(shell: Shell, dut: DeviceAdapter, leshan: Leshan, endpoint: str): """LightweightM2M-1.1-int-306 - Send Operation""" @@ -625,7 +620,8 @@ def test_LightweightM2M_1_1_int_308(shell: Shell, dut: DeviceAdapter, leshan: Le content_both = {16: {0: resources_a, 1: resources_b}} assert leshan.create_obj_instance(endpoint, '16/0', resources_a)['status'] == 'CREATED(201)' dut.readlines_until(regex='.*net_lwm2m_rd_client: Update Done', timeout=5.0) - assert leshan.write_attributes(endpoint, '16/0', {'pmin': 30, 'pmax': 45})['status'] == 'CHANGED(204)' + assert leshan.put_raw(f'/clients/{endpoint}/16/0/attributes?pmin=30')['status'] == 'CHANGED(204)' + assert leshan.put_raw(f'/clients/{endpoint}/16/0/attributes?pmax=45')['status'] == 'CHANGED(204)' data = leshan.composite_observe(endpoint, ['/16/0', '/16/1']) assert data == content_one with leshan.get_event_stream(endpoint, timeout=50) as events: @@ -641,7 +637,6 @@ def test_LightweightM2M_1_1_int_308(shell: Shell, dut: DeviceAdapter, leshan: Le # Restore configuration C.3 shell.exec_command('lwm2m write 1/0/2 -u32 1') shell.exec_command('lwm2m write 1/0/3 -u32 10') - leshan.remove_attributes(endpoint, '16/0', ['pmin','pmax']) @pytest.mark.slow def test_LightweightM2M_1_1_int_309(shell: Shell, dut: DeviceAdapter, leshan: Leshan, endpoint: str): @@ -668,7 +663,8 @@ def test_LightweightM2M_1_1_int_309(shell: Shell, dut: DeviceAdapter, leshan: Le assert leshan.create_obj_instance(endpoint, '16/0', resources_a)['status'] == 'CREATED(201)' assert leshan.create_obj_instance(endpoint, '16/1', resources_b)['status'] == 'CREATED(201)' dut.readlines_until(regex='.*net_lwm2m_rd_client: Update Done', timeout=5.0) - assert leshan.write_attributes(endpoint, '16/0', {'pmin': 30, 'pmax': 45})['status'] == 'CHANGED(204)' + assert leshan.put_raw(f'/clients/{endpoint}/16/0/attributes?pmin=30')['status'] == 'CHANGED(204)' + assert leshan.put_raw(f'/clients/{endpoint}/16/0/attributes?pmax=45')['status'] == 'CHANGED(204)' data = leshan.composite_observe(endpoint, ['/16/0', '/16/1']) assert data == content_both with leshan.get_event_stream(endpoint, timeout=50) as events: @@ -684,7 +680,6 @@ def test_LightweightM2M_1_1_int_309(shell: Shell, dut: DeviceAdapter, leshan: Le # Restore configuration C.3 shell.exec_command('lwm2m write 1/0/2 -u32 1') shell.exec_command('lwm2m write 1/0/3 -u32 10') - leshan.remove_attributes(endpoint, '16/0', ['pmin', 'pmax']) @pytest.mark.slow def test_LightweightM2M_1_1_int_310(shell: Shell, leshan: Leshan, endpoint: str): @@ -692,9 +687,11 @@ def test_LightweightM2M_1_1_int_310(shell: Shell, leshan: Leshan, endpoint: str) # Need to use Configuration C.1 shell.exec_command('lwm2m write 1/0/2 -u32 0') shell.exec_command('lwm2m write 1/0/3 -u32 0') + # Ensure that our previous attributes are not conflicting + assert leshan.put_raw(f'/clients/{endpoint}/3/attributes?pmin=0')['status'] == 'CHANGED(204)' leshan.composite_observe(endpoint, ['/1/0/1', '/3/0']) with leshan.get_event_stream(endpoint, timeout=50) as events: - assert leshan.write_attributes(endpoint, '3', {'pmax': 5})['status'] == 'CHANGED(204)' + assert leshan.put_raw(f'/clients/{endpoint}/3/attributes?pmax=5')['status'] == 'CHANGED(204)' start = time.time() data = events.next_event('NOTIFICATION') assert data[3][0][0] == 'Zephyr' @@ -707,7 +704,6 @@ def test_LightweightM2M_1_1_int_310(shell: Shell, leshan: Leshan, endpoint: str) # Restore configuration C.3 shell.exec_command('lwm2m write 1/0/2 -u32 1') shell.exec_command('lwm2m write 1/0/3 -u32 10') - leshan.remove_attributes(endpoint, '3', ['pmax']) def test_LightweightM2M_1_1_int_311(shell: Shell, leshan: Leshan, endpoint: str): """LightweightM2M-1.1-int-311 - Send command""" From 9267fb0f51f401141d72c46b514aa2a469ae5745 Mon Sep 17 00:00:00 2001 From: Robert Lubos Date: Tue, 6 Feb 2024 11:07:18 +0100 Subject: [PATCH 3592/3723] Revert "[nrf fromtree] test: lwm2m: Mark some tests as slow" This reverts commit 195291f95f6ba354b0d8e33cd370c27f3991dd19. Signed-off-by: Robert Lubos --- tests/net/lib/lwm2m/interop/pytest/pytest.ini | 3 --- tests/net/lib/lwm2m/interop/pytest/test_lwm2m.py | 9 --------- 2 files changed, 12 deletions(-) delete mode 100644 tests/net/lib/lwm2m/interop/pytest/pytest.ini diff --git a/tests/net/lib/lwm2m/interop/pytest/pytest.ini b/tests/net/lib/lwm2m/interop/pytest/pytest.ini deleted file mode 100644 index 761785364d8..00000000000 --- a/tests/net/lib/lwm2m/interop/pytest/pytest.ini +++ /dev/null @@ -1,3 +0,0 @@ -[pytest] -markers = - slow: marks tests as slow (deselect with '-m "not slow"') diff --git a/tests/net/lib/lwm2m/interop/pytest/test_lwm2m.py b/tests/net/lib/lwm2m/interop/pytest/test_lwm2m.py index c37a3900aa6..8f3acd69c7e 100644 --- a/tests/net/lib/lwm2m/interop/pytest/test_lwm2m.py +++ b/tests/net/lib/lwm2m/interop/pytest/test_lwm2m.py @@ -51,7 +51,6 @@ def test_LightweightM2M_1_1_int_104(shell: Shell, dut: DeviceAdapter, leshan: Le leshan.execute(endpoint, '1/0/8') dut.readlines_until(regex='.*net_lwm2m_rd_client: Update Done', timeout=5.0) -@pytest.mark.slow def test_LightweightM2M_1_1_int_107(shell: Shell, dut: DeviceAdapter, leshan: Leshan, endpoint: str): """LightweightM2M-1.1-int-107 - Extending the lifetime of a registration""" leshan.write(endpoint, '1/0/1', 120) @@ -67,7 +66,6 @@ def test_LightweightM2M_1_1_int_108(leshan, endpoint): """LightweightM2M-1.1-int-108 - Turn on Queue Mode""" assert leshan.get(f'/clients/{endpoint}')["queuemode"] -@pytest.mark.slow def test_LightweightM2M_1_1_int_109(shell: Shell, dut: DeviceAdapter, leshan: Leshan, endpoint: str): """LightweightM2M-1.1-int-109 - Behavior in Queue Mode""" logger.debug('Wait for Queue RX OFF') @@ -502,7 +500,6 @@ def test_LightweightM2M_1_1_int_281(shell: Shell, leshan: Leshan, endpoint: str) # Information Reporting Interface [300-399] # -@pytest.mark.slow def test_LightweightM2M_1_1_int_301(shell: Shell, leshan: Leshan, endpoint: str): """LightweightM2M-1.1-int-301 - Observation and Notification of parameter values""" pwr_src = leshan.read(endpoint, '3/0/6') @@ -530,7 +527,6 @@ def test_LightweightM2M_1_1_int_301(shell: Shell, leshan: Leshan, endpoint: str) assert (start + 15) <= time.time() + 1 # Allow 1 second slack. (pMinx + pMax=15) leshan.cancel_observe(endpoint, '3/0/7') -@pytest.mark.slow def test_LightweightM2M_1_1_int_302(shell: Shell, dut: DeviceAdapter, leshan: Leshan, endpoint: str): """LightweightM2M-1.1-int-302 - Cancel Observations using Reset Operation""" leshan.observe(endpoint, '3/0/7') @@ -550,7 +546,6 @@ def test_LightweightM2M_1_1_int_302(shell: Shell, dut: DeviceAdapter, leshan: Le shell.exec_command('lwm2m write /3/0/8/0 -u32 50') dut.readlines_until(regex=r'.*Observer removed for 3/0/8') -@pytest.mark.slow def test_LightweightM2M_1_1_int_304(shell: Shell, leshan: Leshan, endpoint: str): """LightweightM2M-1.1-int-304 - Observe-Composite Operation""" assert leshan.put_raw(f'/clients/{endpoint}/1/0/1/attributes?pmin=30')['status'] == 'CHANGED(204)' @@ -595,8 +590,6 @@ def test_LightweightM2M_1_1_int_307(shell: Shell, dut: DeviceAdapter, leshan: Le shell.exec_command('lwm2m send /3/0') dut.readlines_until(regex=r'.*SEND status: 0', timeout=5.0) - -@pytest.mark.slow def test_LightweightM2M_1_1_int_308(shell: Shell, dut: DeviceAdapter, leshan: Leshan, endpoint: str): """LightweightM2M-1.1-int-308 - Observe-Composite and Creating Object Instance""" shell.exec_command('lwm2m delete /16/0') @@ -638,7 +631,6 @@ def test_LightweightM2M_1_1_int_308(shell: Shell, dut: DeviceAdapter, leshan: Le shell.exec_command('lwm2m write 1/0/2 -u32 1') shell.exec_command('lwm2m write 1/0/3 -u32 10') -@pytest.mark.slow def test_LightweightM2M_1_1_int_309(shell: Shell, dut: DeviceAdapter, leshan: Leshan, endpoint: str): """LightweightM2M-1.1-int-309 - Observe-Composite and Deleting Object Instance""" shell.exec_command('lwm2m delete /16/0') @@ -681,7 +673,6 @@ def test_LightweightM2M_1_1_int_309(shell: Shell, dut: DeviceAdapter, leshan: Le shell.exec_command('lwm2m write 1/0/2 -u32 1') shell.exec_command('lwm2m write 1/0/3 -u32 10') -@pytest.mark.slow def test_LightweightM2M_1_1_int_310(shell: Shell, leshan: Leshan, endpoint: str): """LightweightM2M-1.1-int-310 - Observe-Composite and modification of parameter values""" # Need to use Configuration C.1 From 5474ae5633a5cab4e1843db8a9e6df6a7b97df3b Mon Sep 17 00:00:00 2001 From: Robert Lubos Date: Tue, 6 Feb 2024 11:07:18 +0100 Subject: [PATCH 3593/3723] Revert "[nrf fromtree] net: sockets: prevent null pointer dereference" This reverts commit c2784307ce7f6016105eddf47f786b913ec1cfb3. Signed-off-by: Robert Lubos --- subsys/net/lib/sockets/sockets.c | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/subsys/net/lib/sockets/sockets.c b/subsys/net/lib/sockets/sockets.c index 060c7fff8f7..d35317352c9 100644 --- a/subsys/net/lib/sockets/sockets.c +++ b/subsys/net/lib/sockets/sockets.c @@ -681,9 +681,7 @@ int z_impl_zsock_accept(int sock, struct sockaddr *addr, socklen_t *addrlen) new_sock = VTABLE_CALL(accept, sock, addr, addrlen); - if (addr) { - (void)sock_obj_core_alloc_find(sock, new_sock, addr->sa_family, SOCK_STREAM); - } + (void)sock_obj_core_alloc_find(sock, new_sock, addr->sa_family, SOCK_STREAM); return new_sock; } From 9968c1d6645fae32b774115e8815f75ea9e7b891 Mon Sep 17 00:00:00 2001 From: Robert Lubos Date: Tue, 6 Feb 2024 11:07:18 +0100 Subject: [PATCH 3594/3723] Revert "[nrf fromtree] drivers: ieee802154: nrf5: add `IEEE802154_RX_ON_WHEN_IDLE` capability" This reverts commit 440b2b6a935365f1a0a4790d69ee1dc40b59306b. Signed-off-by: Robert Lubos --- drivers/ieee802154/ieee802154_nrf5.c | 21 ++++++++++++++------- 1 file changed, 14 insertions(+), 7 deletions(-) diff --git a/drivers/ieee802154/ieee802154_nrf5.c b/drivers/ieee802154/ieee802154_nrf5.c index 6cbeb6ee2af..891517a2a0f 100644 --- a/drivers/ieee802154/ieee802154_nrf5.c +++ b/drivers/ieee802154/ieee802154_nrf5.c @@ -236,7 +236,6 @@ static void nrf5_get_capabilities_at_boot(void) ((caps & NRF_802154_CAPABILITY_DELAYED_TX) ? IEEE802154_HW_TXTIME : 0UL) | ((caps & NRF_802154_CAPABILITY_DELAYED_RX) ? IEEE802154_HW_RXTIME : 0UL) | IEEE802154_HW_SLEEP_TO_TX | - IEEE802154_RX_ON_WHEN_IDLE | ((caps & NRF_802154_CAPABILITY_SECURITY) ? IEEE802154_HW_TX_SEC : 0UL) #if defined(CONFIG_IEEE802154_NRF5_MULTIPLE_CCA) | IEEE802154_OPENTHREAD_HW_MULTIPLE_CCA @@ -1001,10 +1000,6 @@ static int nrf5_configure(const struct device *dev, break; #endif /* CONFIG_IEEE802154_NRF5_MULTIPLE_CCA */ - case IEEE802154_CONFIG_RX_ON_WHEN_IDLE: - nrf_802154_rx_on_when_idle_set(config->rx_on_when_idle); - break; - default: return -EINVAL; } @@ -1082,8 +1077,20 @@ void nrf_802154_receive_failed(nrf_802154_rx_error_t error, uint32_t id) const struct device *dev = nrf5_get_device(); #if defined(CONFIG_IEEE802154_CSL_ENDPOINT) - if (id == DRX_SLOT_RX && error == NRF_802154_RX_ERROR_DELAYED_TIMEOUT) { - return; + if (id == DRX_SLOT_RX) { + __ASSERT_NO_MSG(nrf5_data.event_handler); +#if !defined(CONFIG_IEEE802154_CSL_DEBUG) + /* When CSL debug option is used we intentionally avoid notifying the higher layer + * about the finalization of a DRX slot, so that the radio stays in receive state + * for receiving "out of slot" frames. + * As a side effect, regular failure notifications would be reported with the + * incorrect ID. + */ + nrf5_data.event_handler(dev, IEEE802154_EVENT_RX_OFF, NULL); +#endif + if (error == NRF_802154_RX_ERROR_DELAYED_TIMEOUT) { + return; + } } #else ARG_UNUSED(id); From fb7ef6ee7d81eeb87bb56ae4e6ca31755ad0d33e Mon Sep 17 00:00:00 2001 From: Robert Lubos Date: Tue, 6 Feb 2024 11:07:18 +0100 Subject: [PATCH 3595/3723] Revert "[nrf fromtree] drivers: ieee802154: nrf: cache radio channel" This reverts commit c46683f948d3b1f1c632b2424d3fb836b36706b8. Signed-off-by: Robert Lubos --- drivers/ieee802154/ieee802154_nrf5.c | 18 ++---------------- drivers/ieee802154/ieee802154_nrf5.h | 3 --- 2 files changed, 2 insertions(+), 19 deletions(-) diff --git a/drivers/ieee802154/ieee802154_nrf5.c b/drivers/ieee802154/ieee802154_nrf5.c index 891517a2a0f..a43a1b44471 100644 --- a/drivers/ieee802154/ieee802154_nrf5.c +++ b/drivers/ieee802154/ieee802154_nrf5.c @@ -254,8 +254,6 @@ static int nrf5_cca(const struct device *dev) { struct nrf5_802154_data *nrf5_radio = NRF5_802154_DATA(dev); - nrf_802154_channel_set(nrf5_data.channel); - if (!nrf_802154_cca()) { LOG_DBG("CCA failed"); return -EBUSY; @@ -281,7 +279,7 @@ static int nrf5_set_channel(const struct device *dev, uint16_t channel) return channel < 11 ? -ENOTSUP : -EINVAL; } - nrf5_data.channel = channel; + nrf_802154_channel_set(channel); return 0; } @@ -294,8 +292,6 @@ static int nrf5_energy_scan_start(const struct device *dev, ARG_UNUSED(dev); - nrf_802154_channel_set(nrf5_data.channel); - if (nrf5_data.energy_scan_done == NULL) { nrf5_data.energy_scan_done = done_cb; @@ -461,10 +457,6 @@ static bool nrf5_tx_immediate(struct net_pkt *pkt, uint8_t *payload, bool cca) .use_metadata_value = true, .power = nrf5_data.txpwr, }, - .tx_channel = { - .use_metadata_value = true, - .channel = nrf5_data.channel, - }, }; return nrf_802154_transmit_raw(payload, &metadata); @@ -482,10 +474,6 @@ static bool nrf5_tx_csma_ca(struct net_pkt *pkt, uint8_t *payload) .use_metadata_value = true, .power = nrf5_data.txpwr, }, - .tx_channel = { - .use_metadata_value = true, - .channel = nrf5_data.channel, - }, }; return nrf_802154_transmit_csma_ca_raw(payload, &metadata); @@ -525,7 +513,7 @@ static bool nrf5_tx_at(struct nrf5_802154_data *nrf5_radio, struct net_pkt *pkt, .dynamic_data_is_set = net_pkt_ieee802154_mac_hdr_rdy(pkt), }, .cca = cca, - .channel = nrf5_data.channel, + .channel = nrf_802154_channel_get(), .tx_power = { .use_metadata_value = true, .power = nrf5_data.txpwr, @@ -667,7 +655,6 @@ static int nrf5_start(const struct device *dev) ARG_UNUSED(dev); nrf_802154_tx_power_set(nrf5_data.txpwr); - nrf_802154_channel_set(nrf5_data.channel); if (!nrf_802154_receive()) { LOG_ERR("Failed to enter receive state"); @@ -712,7 +699,6 @@ static int nrf5_continuous_carrier(const struct device *dev) ARG_UNUSED(dev); nrf_802154_tx_power_set(nrf5_data.txpwr); - nrf_802154_channel_set(nrf5_data.channel); if (!nrf_802154_continuous_carrier()) { LOG_ERR("Failed to enter continuous carrier state"); diff --git a/drivers/ieee802154/ieee802154_nrf5.h b/drivers/ieee802154/ieee802154_nrf5.h index b9f46dff307..79b47827d72 100644 --- a/drivers/ieee802154/ieee802154_nrf5.h +++ b/drivers/ieee802154/ieee802154_nrf5.h @@ -100,9 +100,6 @@ struct nrf5_802154_data { /* The TX power in dBm. */ int8_t txpwr; - /* The radio channel. */ - uint8_t channel; - #if defined(CONFIG_NRF_802154_SER_HOST) && defined(CONFIG_IEEE802154_CSL_ENDPOINT) /* The last configured value of CSL period in units of 10 symbols. */ uint32_t csl_period; From a37cec88a9561eb75ea7dae5497b6ebee8e0cbc2 Mon Sep 17 00:00:00 2001 From: Robert Lubos Date: Tue, 6 Feb 2024 11:07:18 +0100 Subject: [PATCH 3596/3723] Revert "[nrf fromtree] drivers: ieee802154: nrf: make selective tx power the default" This reverts commit c2f6fa7a7b1b6ec8d7b3901f8cf008328b773ae0. Signed-off-by: Robert Lubos --- doc/releases/release-notes-3.6.rst | 2 -- drivers/ieee802154/Kconfig | 5 +++++ drivers/ieee802154/ieee802154_nrf5.c | 24 +++++++++++++----------- drivers/ieee802154/ieee802154_nrf5.h | 3 --- include/zephyr/net/ieee802154_pkt.h | 18 ++++++++++++++++++ modules/openthread/platform/radio.c | 7 ++++++- 6 files changed, 42 insertions(+), 17 deletions(-) diff --git a/doc/releases/release-notes-3.6.rst b/doc/releases/release-notes-3.6.rst index a253434a085..8edd3280382 100644 --- a/doc/releases/release-notes-3.6.rst +++ b/doc/releases/release-notes-3.6.rst @@ -154,8 +154,6 @@ Drivers and Sensors * IEEE 802.15.4 - * Removed :kconfig:option:`CONFIG_IEEE802154_SELECTIVE_TXPOWER` Kconfig option. - * Interrupt Controller * Input diff --git a/drivers/ieee802154/Kconfig b/drivers/ieee802154/Kconfig index d692024b096..feccd4a6001 100644 --- a/drivers/ieee802154/Kconfig +++ b/drivers/ieee802154/Kconfig @@ -98,6 +98,11 @@ config IEEE802154_CSL_DEBUG help Enable support for CSL debugging by avoiding sleep state in favor of receive state. +config IEEE802154_SELECTIVE_TXPOWER + bool "Support selective TX power setting" + help + Enable support for selectively setting TX power for every transmission request. + module = IEEE802154_DRIVER module-str = IEEE 802.15.4 driver module-help = Sets log level for IEEE 802.15.4 Device Drivers. diff --git a/drivers/ieee802154/ieee802154_nrf5.c b/drivers/ieee802154/ieee802154_nrf5.c index a43a1b44471..e9c49e6089e 100644 --- a/drivers/ieee802154/ieee802154_nrf5.c +++ b/drivers/ieee802154/ieee802154_nrf5.c @@ -375,7 +375,7 @@ static int nrf5_set_txpower(const struct device *dev, int16_t dbm) LOG_DBG("%d", dbm); - nrf5_data.txpwr = dbm; + nrf_802154_tx_power_set(dbm); return 0; } @@ -454,8 +454,10 @@ static bool nrf5_tx_immediate(struct net_pkt *pkt, uint8_t *payload, bool cca) }, .cca = cca, .tx_power = { - .use_metadata_value = true, - .power = nrf5_data.txpwr, + .use_metadata_value = IS_ENABLED(CONFIG_IEEE802154_SELECTIVE_TXPOWER), +#if defined(CONFIG_IEEE802154_SELECTIVE_TXPOWER) + .power = net_pkt_ieee802154_txpwr(pkt), +#endif }, }; @@ -471,8 +473,10 @@ static bool nrf5_tx_csma_ca(struct net_pkt *pkt, uint8_t *payload) .dynamic_data_is_set = net_pkt_ieee802154_mac_hdr_rdy(pkt), }, .tx_power = { - .use_metadata_value = true, - .power = nrf5_data.txpwr, + .use_metadata_value = IS_ENABLED(CONFIG_IEEE802154_SELECTIVE_TXPOWER), +#if defined(CONFIG_IEEE802154_SELECTIVE_TXPOWER) + .power = net_pkt_ieee802154_txpwr(pkt), +#endif }, }; @@ -515,8 +519,10 @@ static bool nrf5_tx_at(struct nrf5_802154_data *nrf5_radio, struct net_pkt *pkt, .cca = cca, .channel = nrf_802154_channel_get(), .tx_power = { - .use_metadata_value = true, - .power = nrf5_data.txpwr, + .use_metadata_value = IS_ENABLED(CONFIG_IEEE802154_SELECTIVE_TXPOWER), +#if defined(CONFIG_IEEE802154_SELECTIVE_TXPOWER) + .power = net_pkt_ieee802154_txpwr(pkt), +#endif }, #if defined(CONFIG_IEEE802154_NRF5_MULTIPLE_CCA) .extra_cca_attempts = max_extra_cca_attempts, @@ -654,8 +660,6 @@ static int nrf5_start(const struct device *dev) { ARG_UNUSED(dev); - nrf_802154_tx_power_set(nrf5_data.txpwr); - if (!nrf_802154_receive()) { LOG_ERR("Failed to enter receive state"); return -EIO; @@ -698,8 +702,6 @@ static int nrf5_continuous_carrier(const struct device *dev) { ARG_UNUSED(dev); - nrf_802154_tx_power_set(nrf5_data.txpwr); - if (!nrf_802154_continuous_carrier()) { LOG_ERR("Failed to enter continuous carrier state"); return -EIO; diff --git a/drivers/ieee802154/ieee802154_nrf5.h b/drivers/ieee802154/ieee802154_nrf5.h index 79b47827d72..9115fe0bdae 100644 --- a/drivers/ieee802154/ieee802154_nrf5.h +++ b/drivers/ieee802154/ieee802154_nrf5.h @@ -97,9 +97,6 @@ struct nrf5_802154_data { uint8_t max_extra_cca_attempts; #endif - /* The TX power in dBm. */ - int8_t txpwr; - #if defined(CONFIG_NRF_802154_SER_HOST) && defined(CONFIG_IEEE802154_CSL_ENDPOINT) /* The last configured value of CSL period in units of 10 symbols. */ uint32_t csl_period; diff --git a/include/zephyr/net/ieee802154_pkt.h b/include/zephyr/net/ieee802154_pkt.h index 3270f994248..d5fdc712b49 100644 --- a/include/zephyr/net/ieee802154_pkt.h +++ b/include/zephyr/net/ieee802154_pkt.h @@ -59,6 +59,12 @@ struct net_pkt_cb_ieee802154 { */ uint8_t rssi; }; +#if defined(CONFIG_IEEE802154_SELECTIVE_TXPOWER) + /* TX packets */ + struct { + int8_t txpwr; /* TX power in dBm. */ + }; +#endif /* CONFIG_IEEE802154_SELECTIVE_TXPOWER */ }; /* Flags */ @@ -179,6 +185,18 @@ static inline void net_pkt_set_ieee802154_rssi_dbm(struct net_pkt *pkt, int16_t CODE_UNREACHABLE; } +#if defined(CONFIG_IEEE802154_SELECTIVE_TXPOWER) +static inline int8_t net_pkt_ieee802154_txpwr(struct net_pkt *pkt) +{ + return net_pkt_cb_ieee802154(pkt)->txpwr; +} + +static inline void net_pkt_set_ieee802154_txpwr(struct net_pkt *pkt, int8_t txpwr) +{ + net_pkt_cb_ieee802154(pkt)->txpwr = txpwr; +} +#endif /* CONFIG_IEEE802154_SELECTIVE_TXPOWER */ + static inline bool net_pkt_ieee802154_ack_fpb(struct net_pkt *pkt) { return net_pkt_cb_ieee802154(pkt)->ack_fpb; diff --git a/modules/openthread/platform/radio.c b/modules/openthread/platform/radio.c index cec73e3ef6f..a09b7dd3b67 100644 --- a/modules/openthread/platform/radio.c +++ b/modules/openthread/platform/radio.c @@ -380,8 +380,13 @@ void transmit_message(struct k_work *tx_job) channel = sTransmitFrame.mChannel; - radio_api->set_channel(radio_dev, channel); + radio_api->set_channel(radio_dev, sTransmitFrame.mChannel); + +#if defined(CONFIG_IEEE802154_SELECTIVE_TXPOWER) + net_pkt_set_ieee802154_txpwr(tx_pkt, get_transmit_power_for_channel(channel)); +#else radio_api->set_txpower(radio_dev, get_transmit_power_for_channel(channel)); +#endif /* CONFIG_IEEE802154_SELECTIVE_TXPOWER */ net_pkt_set_ieee802154_frame_secured(tx_pkt, sTransmitFrame.mInfo.mTxInfo.mIsSecurityProcessed); From e9ce066e4e38931f5041f7797fe590ca8fdb701d Mon Sep 17 00:00:00 2001 From: Robert Lubos Date: Tue, 6 Feb 2024 11:07:18 +0100 Subject: [PATCH 3597/3723] Revert "[nrf fromtree] manifest: update hal_nordic revision" This reverts commit 5ff2ec1ac15ad91cd16229a698b3b3ecbc2aa468. Signed-off-by: Robert Lubos --- west.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/west.yml b/west.yml index a141e94edd6..c99118074eb 100644 --- a/west.yml +++ b/west.yml @@ -183,7 +183,7 @@ manifest: groups: - hal - name: hal_nordic - revision: 3786c55424d4d64c62dd25219de31618cef26fdf + revision: b9633ecea67bf52925d4c61455046223b46402b1 path: modules/hal/nordic groups: - hal From d4555e10d352dc3938d9d407e6f99af769b1470d Mon Sep 17 00:00:00 2001 From: Robert Lubos Date: Tue, 6 Feb 2024 11:07:19 +0100 Subject: [PATCH 3598/3723] Revert "[nrf fromtree] net: mgmt: Provide Regulatory channel info" This reverts commit 65d32263c87639e9c199b31f6d770ab579796072. Signed-off-by: Robert Lubos --- include/zephyr/net/wifi_mgmt.h | 20 -------------------- subsys/net/l2/wifi/wifi_shell.c | 19 ++----------------- 2 files changed, 2 insertions(+), 37 deletions(-) diff --git a/include/zephyr/net/wifi_mgmt.h b/include/zephyr/net/wifi_mgmt.h index f6ae631a830..78800f451e7 100644 --- a/include/zephyr/net/wifi_mgmt.h +++ b/include/zephyr/net/wifi_mgmt.h @@ -546,22 +546,6 @@ enum wifi_mgmt_op { WIFI_MGMT_SET = 1, }; -#define MAX_REG_CHAN_NUM 42 - -/** Per-channel regulatory attributes */ -struct wifi_reg_chan_info { - /** Center frequency in MHz */ - unsigned short center_frequency; - /** Maximum transmission power (in dBm) */ - unsigned short max_power:8; - /** Is channel supported or not */ - unsigned short supported:1; - /** Passive transmissions only */ - unsigned short passive_only:1; - /** Is a DFS channel */ - unsigned short dfs:1; -} __packed; - /** Regulatory domain information or configuration */ struct wifi_reg_domain { /* Regulatory domain operation */ @@ -570,10 +554,6 @@ struct wifi_reg_domain { bool force; /** Country code: ISO/IEC 3166-1 alpha-2 */ uint8_t country_code[WIFI_COUNTRY_CODE_LEN]; - /** Number of channels supported */ - unsigned int num_channels; - /** Channels information */ - struct wifi_reg_chan_info *chan_info; }; /** Wi-Fi TWT sleep states */ diff --git a/subsys/net/l2/wifi/wifi_shell.c b/subsys/net/l2/wifi/wifi_shell.c index e1446cceca0..1ee94304781 100644 --- a/subsys/net/l2/wifi/wifi_shell.c +++ b/subsys/net/l2/wifi/wifi_shell.c @@ -64,7 +64,6 @@ static struct { static uint32_t scan_result; static struct net_mgmt_event_callback wifi_shell_mgmt_cb; -static struct wifi_reg_chan_info chan_info[MAX_REG_CHAN_NUM]; static K_MUTEX_DEFINE(wifi_ap_sta_list_lock); struct wifi_ap_sta_node { @@ -135,6 +134,7 @@ static void handle_wifi_scan_result(struct net_mgmt_event_callback *cb) wifi_mfp_txt(entry->mfp)); } +#ifdef CONFIG_WIFI_MGMT_RAW_SCAN_RESULTS static int wifi_freq_to_channel(int frequency) { int channel = 0; @@ -156,7 +156,6 @@ static int wifi_freq_to_channel(int frequency) return channel; } -#ifdef CONFIG_WIFI_MGMT_RAW_SCAN_RESULTS static enum wifi_frequency_bands wifi_freq_to_band(int frequency) { enum wifi_frequency_bands band = WIFI_FREQ_BAND_2_4_GHZ; @@ -1290,10 +1289,9 @@ static int cmd_wifi_reg_domain(const struct shell *sh, size_t argc, { struct net_if *iface = net_if_get_first_wifi(); struct wifi_reg_domain regd = {0}; - int ret, chan_idx = 0; + int ret; if (argc == 1) { - (®d)->chan_info = &chan_info[0]; regd.oper = WIFI_MGMT_GET; } else if (argc >= 2 && argc <= 3) { regd.oper = WIFI_MGMT_SET; @@ -1338,19 +1336,6 @@ static int cmd_wifi_reg_domain(const struct shell *sh, size_t argc, if (regd.oper == WIFI_MGMT_GET) { shell_fprintf(sh, SHELL_NORMAL, "Wi-Fi Regulatory domain is: %c%c\n", regd.country_code[0], regd.country_code[1]); - shell_fprintf(sh, SHELL_NORMAL, - "\t
\t\t" - "\t\t\n"); - for (chan_idx = 0; chan_idx < regd.num_channels; chan_idx++) { - shell_fprintf(sh, SHELL_NORMAL, - " %d\t\t\t\%d\t\t\t\%s\t\t\t%d\t\t\t%s\t\t\t\t%s\n", - wifi_freq_to_channel(chan_info[chan_idx].center_frequency), - chan_info[chan_idx].center_frequency, - chan_info[chan_idx].supported ? "y" : "n", - chan_info[chan_idx].max_power, - chan_info[chan_idx].passive_only ? "y" : "n", - chan_info[chan_idx].dfs ? "y" : "n"); - } } else { shell_fprintf(sh, SHELL_NORMAL, "Wi-Fi Regulatory domain set to: %c%c\n", regd.country_code[0], regd.country_code[1]); From 7419138dee74645f909841f9d59efe1e30965595 Mon Sep 17 00:00:00 2001 From: Robert Lubos Date: Tue, 6 Feb 2024 11:07:19 +0100 Subject: [PATCH 3599/3723] Revert "[nrf fromtree] dts: nrf5340: add missing `easydma-maxcnt-bits` for nrf5340_cpunet" This reverts commit f6e704ceefa7330d061eb9a5579e670d26524708. Signed-off-by: Robert Lubos --- dts/arm/nordic/nrf5340_cpunet.dtsi | 1 - 1 file changed, 1 deletion(-) diff --git a/dts/arm/nordic/nrf5340_cpunet.dtsi b/dts/arm/nordic/nrf5340_cpunet.dtsi index c1e8371d410..63c7e920f81 100644 --- a/dts/arm/nordic/nrf5340_cpunet.dtsi +++ b/dts/arm/nordic/nrf5340_cpunet.dtsi @@ -192,7 +192,6 @@ reg = <0x41013000 0x1000>; clock-frequency = ; interrupts = <19 NRF_DEFAULT_IRQ_PRIORITY>; - easydma-maxcnt-bits = <16>; status = "disabled"; }; From ddb4d9e20108f7d6b1c8a0afd950d122aa2d823b Mon Sep 17 00:00:00 2001 From: Robert Lubos Date: Tue, 6 Feb 2024 11:07:19 +0100 Subject: [PATCH 3600/3723] Revert "[nrf fromtree] Bluetooth: Mesh: suspend/resume gatt advs" This reverts commit 9aa5cc1391f01d02c72e2d44cc636e5edd7899d6. Signed-off-by: Robert Lubos --- subsys/bluetooth/mesh/main.c | 40 +----------------------------------- 1 file changed, 1 insertion(+), 39 deletions(-) diff --git a/subsys/bluetooth/mesh/main.c b/subsys/bluetooth/mesh/main.c index 1b80233cec1..2689a3355c1 100644 --- a/subsys/bluetooth/mesh/main.c +++ b/subsys/bluetooth/mesh/main.c @@ -462,22 +462,6 @@ int bt_mesh_suspend(void) bt_mesh_access_suspend(); - if (IS_ENABLED(CONFIG_BT_MESH_PB_GATT)) { - err = bt_mesh_pb_gatt_srv_disable(); - if (err && err != -EALREADY) { - LOG_WRN("Disabling PB-GATT failed (err %d)", err); - return err; - } - } - - if (IS_ENABLED(CONFIG_BT_MESH_GATT_PROXY)) { - err = bt_mesh_proxy_gatt_disable(); - if (err && err != -EALREADY) { - LOG_WRN("Disabling GATT proxy failed (err %d)", err); - return err; - } - } - err = bt_mesh_adv_disable(); if (err) { atomic_clear_bit(bt_mesh.flags, BT_MESH_SUSPENDED); @@ -524,22 +508,6 @@ int bt_mesh_resume(void) return err; } - if (IS_ENABLED(CONFIG_BT_MESH_GATT_PROXY) && bt_mesh_is_provisioned()) { - err = bt_mesh_proxy_gatt_enable(); - if (err) { - LOG_WRN("Re-enabling GATT proxy failed (err %d)", err); - return err; - } - } - - if (IS_ENABLED(CONFIG_BT_MESH_PB_GATT) && !bt_mesh_is_provisioned()) { - err = bt_mesh_pb_gatt_srv_enable(); - if (err) { - LOG_WRN("Re-enabling PB-GATT failed (err %d)", err); - return err; - } - } - err = bt_mesh_scan_enable(); if (err) { LOG_WRN("Re-enabling scanning failed (err %d)", err); @@ -556,13 +524,7 @@ int bt_mesh_resume(void) bt_mesh_model_foreach(model_resume, NULL); - err = bt_mesh_adv_gatt_send(); - if (err && (err != -ENOTSUP)) { - LOG_WRN("GATT send failed (err %d)", err); - return err; - } - - return 0; + return err; } int bt_mesh_init(const struct bt_mesh_prov *prov, From 0b7b8d937927b8ed2938ddd20762aceaf6cf0fef Mon Sep 17 00:00:00 2001 From: Robert Lubos Date: Tue, 6 Feb 2024 11:07:19 +0100 Subject: [PATCH 3601/3723] Revert "[nrf fromtree] Bluetooth: Mesh: fix proxy srv return value" This reverts commit 609321cdd817d0e6201a0ed19b8a17011b567ced. Signed-off-by: Robert Lubos --- subsys/bluetooth/mesh/proxy_srv.c | 10 +--------- 1 file changed, 1 insertion(+), 9 deletions(-) diff --git a/subsys/bluetooth/mesh/proxy_srv.c b/subsys/bluetooth/mesh/proxy_srv.c index a903d94ffa9..25a44abfded 100644 --- a/subsys/bluetooth/mesh/proxy_srv.c +++ b/subsys/bluetooth/mesh/proxy_srv.c @@ -975,8 +975,6 @@ static void svc_reg_work_handler(struct k_work *work) int bt_mesh_proxy_gatt_enable(void) { - int err; - LOG_DBG(""); if (!bt_mesh_is_provisioned()) { @@ -988,13 +986,7 @@ int bt_mesh_proxy_gatt_enable(void) } svc_reg_attempts = PROXY_SVC_REG_ATTEMPTS; - err = k_work_schedule(&svc_reg_work, PROXY_SVC_INIT_TIMEOUT); - if (err < 0) { - LOG_ERR("Enabling GATT proxy failed (err %d)", err); - return err; - } - - return 0; + return k_work_schedule(&svc_reg_work, PROXY_SVC_INIT_TIMEOUT); } void bt_mesh_proxy_gatt_disconnect(void) From da7cf84bcfca90e51ef4db5a88148c0ed5788027 Mon Sep 17 00:00:00 2001 From: Robert Lubos Date: Tue, 6 Feb 2024 11:07:19 +0100 Subject: [PATCH 3602/3723] Revert "[nrf fromtree] Bluetooth: Mesh: remove 20ms tx delay in adv bearer" This reverts commit f4b0993d4966c82f9a18c6ac7d55dc9960ef5be3. Signed-off-by: Robert Lubos --- subsys/bluetooth/mesh/adv_ext.c | 54 +++++++++++++------ tests/bsim/bluetooth/mesh/overlay_pst.conf | 2 - .../bluetooth/mesh/src/test_persistence.c | 6 --- .../bsim/bluetooth/mesh/src/test_provision.c | 10 ---- 4 files changed, 38 insertions(+), 34 deletions(-) diff --git a/subsys/bluetooth/mesh/adv_ext.c b/subsys/bluetooth/mesh/adv_ext.c index c30a3a2b9bc..a4f3f32ee5f 100644 --- a/subsys/bluetooth/mesh/adv_ext.c +++ b/subsys/bluetooth/mesh/adv_ext.c @@ -63,8 +63,8 @@ struct bt_mesh_ext_adv { ATOMIC_DEFINE(flags, ADV_FLAGS_NUM); struct bt_le_ext_adv *instance; struct bt_mesh_adv *adv; - uint32_t timestamp; - struct k_work work; + uint64_t timestamp; + struct k_work_delayable work; struct bt_le_adv_param adv_param; }; @@ -88,7 +88,7 @@ static struct bt_mesh_ext_adv advs[] = { #endif /* CONFIG_BT_MESH_PB_ADV */ BT_MESH_ADV_TAG_BIT_LOCAL ), - .work = Z_WORK_INITIALIZER(send_pending_adv), + .work = Z_WORK_DELAYABLE_INITIALIZER(send_pending_adv), }, #if CONFIG_BT_MESH_RELAY_ADV_SETS [1 ... CONFIG_BT_MESH_RELAY_ADV_SETS] = { @@ -100,19 +100,19 @@ static struct bt_mesh_ext_adv advs[] = { BT_MESH_ADV_TAG_BIT_PROV | #endif /* CONFIG_BT_MESH_PB_ADV_USE_RELAY_SETS */ 0), - .work = Z_WORK_INITIALIZER(send_pending_adv), + .work = Z_WORK_DELAYABLE_INITIALIZER(send_pending_adv), }, #endif /* CONFIG_BT_MESH_RELAY_ADV_SETS */ #if defined(CONFIG_BT_MESH_ADV_EXT_FRIEND_SEPARATE) { .tags = BT_MESH_ADV_TAG_BIT_FRIEND, - .work = Z_WORK_INITIALIZER(send_pending_adv), + .work = Z_WORK_DELAYABLE_INITIALIZER(send_pending_adv), }, #endif /* CONFIG_BT_MESH_ADV_EXT_FRIEND_SEPARATE */ #if defined(CONFIG_BT_MESH_ADV_EXT_GATT_SEPARATE) { .tags = BT_MESH_ADV_TAG_BIT_PROXY, - .work = Z_WORK_INITIALIZER(send_pending_adv), + .work = Z_WORK_DELAYABLE_INITIALIZER(send_pending_adv), }, #endif /* CONFIG_BT_MESH_ADV_EXT_GATT_SEPARATE */ }; @@ -197,7 +197,7 @@ static int adv_start(struct bt_mesh_ext_adv *ext_adv, return err; } - ext_adv->timestamp = k_uptime_get_32(); + ext_adv->timestamp = k_uptime_get(); err = bt_le_ext_adv_start(ext_adv->instance, start); if (err) { @@ -271,13 +271,18 @@ static void send_pending_adv(struct k_work *work) struct bt_mesh_adv *adv; int err; - ext_adv = CONTAINER_OF(work, struct bt_mesh_ext_adv, work); + ext_adv = CONTAINER_OF(work, struct bt_mesh_ext_adv, work.work); if (atomic_test_and_clear_bit(ext_adv->flags, ADV_FLAG_SENT)) { - LOG_DBG("Advertising stopped after %u ms for %s", - k_uptime_get_32() - ext_adv->timestamp, - ext_adv->adv ? adv_tag_to_str[ext_adv->adv->ctx.tag] - : adv_tag_to_str[BT_MESH_ADV_TAG_PROXY]); + /* Calling k_uptime_delta on a timestamp moves it to the current time. + * This is essential here, as schedule_send() uses the end of the event + * as a reference to avoid sending the next advertisement too soon. + */ + int64_t duration = k_uptime_delta(&ext_adv->timestamp); + + LOG_DBG("Advertising stopped after %u ms for %s", (uint32_t)duration, + ext_adv->adv ? adv_tag_to_str[ext_adv->adv->ctx.tag] : + adv_tag_to_str[BT_MESH_ADV_TAG_PROXY]); atomic_clear_bit(ext_adv->flags, ADV_FLAG_ACTIVE); atomic_clear_bit(ext_adv->flags, ADV_FLAG_PROXY); @@ -335,6 +340,11 @@ static void send_pending_adv(struct k_work *work) static bool schedule_send(struct bt_mesh_ext_adv *ext_adv) { + uint64_t timestamp; + int64_t delta; + + timestamp = ext_adv->timestamp; + if (atomic_test_and_clear_bit(ext_adv->flags, ADV_FLAG_PROXY)) { atomic_clear_bit(ext_adv->flags, ADV_FLAG_PROXY_START); (void)bt_le_ext_adv_stop(ext_adv->instance); @@ -350,7 +360,19 @@ static bool schedule_send(struct bt_mesh_ext_adv *ext_adv) } atomic_clear_bit(ext_adv->flags, ADV_FLAG_SCHEDULE_PENDING); - k_work_submit(&ext_adv->work); + + if ((IS_ENABLED(CONFIG_BT_MESH_ADV_EXT_FRIEND_SEPARATE) && + ext_adv->tags & BT_MESH_ADV_TAG_BIT_FRIEND) || + (CONFIG_BT_MESH_RELAY_ADV_SETS > 0 && ext_adv->tags & BT_MESH_ADV_TAG_BIT_RELAY)) { + k_work_reschedule(&ext_adv->work, K_NO_WAIT); + } else { + /* The controller will send the next advertisement immediately. + * Introduce a delay here to avoid sending the next mesh packet closer + * to the previous packet than what's permitted by the specification. + */ + delta = k_uptime_delta(×tamp); + k_work_reschedule(&ext_adv->work, K_MSEC(ADV_INT_FAST_MS - delta)); + } return true; } @@ -416,7 +438,7 @@ void bt_mesh_adv_terminate(struct bt_mesh_adv *adv) atomic_set_bit(ext_adv->flags, ADV_FLAG_SENT); - k_work_submit(&ext_adv->work); + k_work_submit(&ext_adv->work.work); return; } @@ -465,7 +487,7 @@ static void adv_sent(struct bt_le_ext_adv *instance, atomic_set_bit(ext_adv->flags, ADV_FLAG_SENT); - k_work_submit(&ext_adv->work); + k_work_submit(&ext_adv->work.work); } #if defined(CONFIG_BT_MESH_GATT_SERVER) @@ -523,7 +545,7 @@ int bt_mesh_adv_disable(void) struct k_work_sync sync; for (int i = 0; i < ARRAY_SIZE(advs); i++) { - k_work_flush(&advs[i].work, &sync); + k_work_flush_delayable(&advs[i].work, &sync); err = bt_le_ext_adv_stop(advs[i].instance); if (err) { diff --git a/tests/bsim/bluetooth/mesh/overlay_pst.conf b/tests/bsim/bluetooth/mesh/overlay_pst.conf index 6730b9ee233..6a56ec8065b 100644 --- a/tests/bsim/bluetooth/mesh/overlay_pst.conf +++ b/tests/bsim/bluetooth/mesh/overlay_pst.conf @@ -19,6 +19,4 @@ CONFIG_BT_MESH_SEQ_STORE_RATE=1 CONFIG_BT_MESH_RPL_STORE_TIMEOUT=1 CONFIG_BT_MESH_STORE_TIMEOUT=1 CONFIG_BT_MESH_TX_SEG_RETRANS_COUNT=1 -CONFIG_BT_MESH_TX_SEG_RETRANS_TIMEOUT_UNICAST=200 -CONFIG_BT_MESH_SEG_ACK_BASE_TIMEOUT=400 CONFIG_BT_MESH_COMP_PST_BUF_SIZE=600 diff --git a/tests/bsim/bluetooth/mesh/src/test_persistence.c b/tests/bsim/bluetooth/mesh/src/test_persistence.c index ec7d838d26a..4bf1f9faa93 100644 --- a/tests/bsim/bluetooth/mesh/src/test_persistence.c +++ b/tests/bsim/bluetooth/mesh/src/test_persistence.c @@ -455,12 +455,6 @@ static void provisioner_setup(void) FAIL("Failed to add test_netkey (err: %d, status: %d)", err, status); } - err = bt_mesh_cfg_cli_net_transmit_set(test_netkey_idx, TEST_PROV_ADDR, - BT_MESH_TRANSMIT(3, 50), &status); - if (err || status != BT_MESH_TRANSMIT(3, 50)) { - FAIL("Net transmit set failed (err %d, transmit %x)", err, status); - } - provisioner_ready = true; } diff --git a/tests/bsim/bluetooth/mesh/src/test_provision.c b/tests/bsim/bluetooth/mesh/src/test_provision.c index 2bff871b187..3d0e8010c75 100644 --- a/tests/bsim/bluetooth/mesh/src/test_provision.c +++ b/tests/bsim/bluetooth/mesh/src/test_provision.c @@ -1205,7 +1205,6 @@ static void test_provisioner_pb_remote_client_nppi_robustness(void) uint16_t pb_remote_server_addr; uint8_t status; struct bt_mesh_cdb_node *node; - int err; provisioner_pb_remote_client_setup(); @@ -1219,15 +1218,6 @@ static void test_provisioner_pb_remote_client_nppi_robustness(void) .ttl = 3, }; - /* Set Network Transmit Count state on the remote client greater than on the remote server - * to increase probability of reception responses. - */ - err = bt_mesh_cfg_cli_net_transmit_set(0, current_dev_addr, BT_MESH_TRANSMIT(3, 50), - &status); - if (err || status != BT_MESH_TRANSMIT(3, 50)) { - FAIL("Net transmit set failed (err %d, transmit %x)", err, status); - } - ASSERT_OK(provision_remote(&srv, 2, &srv.addr)); /* Check device key by adding appkey. */ From 2c42295af235ef8256936e9229fbe7565aeed440 Mon Sep 17 00:00:00 2001 From: Robert Lubos Date: Tue, 6 Feb 2024 11:07:20 +0100 Subject: [PATCH 3603/3723] Revert "[nrf fromtree] tests: Bluetooth: Mesh: Add proxy adv coex test." This reverts commit f6350f1e94fa82e3f9b982014f32f046f2eb5379. Signed-off-by: Robert Lubos --- subsys/bluetooth/mesh/proxy_srv.c | 11 +- tests/bsim/bluetooth/mesh/overlay_gatt.conf | 1 - tests/bsim/bluetooth/mesh/src/test_beacon.c | 366 ++---------------- .../proxy_adv_multi_subnet_coex.sh | 54 --- 4 files changed, 35 insertions(+), 397 deletions(-) delete mode 100755 tests/bsim/bluetooth/mesh/tests_scripts/priv_beacon/proxy_adv_multi_subnet_coex.sh diff --git a/subsys/bluetooth/mesh/proxy_srv.c b/subsys/bluetooth/mesh/proxy_srv.c index 25a44abfded..9cad9e2fe04 100644 --- a/subsys/bluetooth/mesh/proxy_srv.c +++ b/subsys/bluetooth/mesh/proxy_srv.c @@ -712,13 +712,6 @@ static bool proxy_adv_request_get(struct bt_mesh_subnet *sub, struct proxy_adv_r return false; } - /** The priority for proxy adv is first solicitation, then Node Identity, - * and lastly Network ID. Network ID is prioritized last since, in many - * cases, another device can fulfill the same demand. Solicitation is - * prioritized first since legacy devices are dependent on this to - * connect to the network. - */ - #if defined(CONFIG_BT_MESH_OD_PRIV_PROXY_SRV) if (bt_mesh_od_priv_proxy_get() > 0 && sub->solicited) { int32_t timeout = MSEC_PER_SEC * (int32_t)bt_mesh_od_priv_proxy_get(); @@ -760,7 +753,7 @@ static bool proxy_adv_request_get(struct bt_mesh_subnet *sub, struct proxy_adv_r static struct bt_mesh_subnet *adv_sub_get_next(struct bt_mesh_subnet *sub_start, struct proxy_adv_request *request) { - struct bt_mesh_subnet *sub_temp = bt_mesh_subnet_next(sub_start); + struct bt_mesh_subnet *sub_temp = sub_start; do { if (proxy_adv_request_get(sub_temp, request)) { @@ -830,7 +823,7 @@ static int gatt_proxy_advertise(void) } } - sub = adv_sub_get_next(sub_adv.sub, &request); + sub = adv_sub_get_next(bt_mesh_subnet_next(sub_adv.sub), &request); if (!sub) { LOG_ERR("Could not find subnet to advertise"); return -ENOENT; diff --git a/tests/bsim/bluetooth/mesh/overlay_gatt.conf b/tests/bsim/bluetooth/mesh/overlay_gatt.conf index 7660313b700..f94a26d623f 100644 --- a/tests/bsim/bluetooth/mesh/overlay_gatt.conf +++ b/tests/bsim/bluetooth/mesh/overlay_gatt.conf @@ -6,4 +6,3 @@ CONFIG_BT_MESH_LOW_POWER=n CONFIG_BT_MESH_FRIEND=n CONFIG_BT_CENTRAL=y CONFIG_BT_MESH_PROXY_CLIENT=y -CONFIG_BT_MESH_PROXY_SOLICITATION=y diff --git a/tests/bsim/bluetooth/mesh/src/test_beacon.c b/tests/bsim/bluetooth/mesh/src/test_beacon.c index e5f7d515da7..f9230a397a9 100644 --- a/tests/bsim/bluetooth/mesh/src/test_beacon.c +++ b/tests/bsim/bluetooth/mesh/src/test_beacon.c @@ -31,7 +31,7 @@ LOG_MODULE_REGISTER(LOG_MODULE_NAME, LOG_LEVEL_INF); #define BEACON_TYPE_PRIVATE 0x02 #endif -static uint8_t test_net_key_2[16] = { 0xca, 0x11, 0xab, 0x1e }; +static uint8_t test_net_key_secondary[16] = { 0xca, 0x11, 0xab, 0x1e }; static struct { uint8_t primary[16]; uint8_t secondary[16]; @@ -334,7 +334,6 @@ static struct { uint8_t random[13]; uint64_t pp_hash; uint64_t pp_random; - uint64_t net_id; bt_addr_le_t adv_addr; #endif bool (*process_cb)(const uint8_t *net_id, void *ctx); @@ -626,7 +625,7 @@ static void test_tx_kr_old_key(void) * the new Net Key. The node shall set Key Refresh phase to 2. The beacon interval shall * be increased. */ - beacon_create(&buf, test_net_key_2, 0x03, 0x0001); + beacon_create(&buf, test_net_key_secondary, 0x03, 0x0001); send_beacon(&buf); ASSERT_FALSE(wait_for_beacon(beacon_scan_cb, BEACON_INTERVAL + 1, NULL, NULL)); ASSERT_TRUE(wait_for_beacon(beacon_scan_cb, BEACON_INTERVAL + 1, NULL, NULL)); @@ -646,7 +645,7 @@ static void test_tx_kr_old_key(void) /* Try the same with the new Net Key. Now the node shall change Key Refresh phase to 0. The * beacon interval shall be increased. */ - beacon_create(&buf, test_net_key_2, 0x02, 0x0001); + beacon_create(&buf, test_net_key_secondary, 0x02, 0x0001); send_beacon(&buf); ASSERT_FALSE(wait_for_beacon(beacon_scan_cb, BEACON_INTERVAL + 1, NULL, NULL)); ASSERT_TRUE(wait_for_beacon(beacon_scan_cb, BEACON_INTERVAL + 1, NULL, NULL)); @@ -666,7 +665,7 @@ static void test_tx_kr_old_key(void) /* Do the same, but secure beacon with the new Net Key. Now the node shall change IV Update * flag to 0. The beacon interval shall be increased. */ - beacon_create(&buf, test_net_key_2, 0x00, 0x0001); + beacon_create(&buf, test_net_key_secondary, 0x00, 0x0001); send_beacon(&buf); ASSERT_FALSE(wait_for_beacon(beacon_scan_cb, BEACON_INTERVAL + 1, NULL, NULL)); ASSERT_TRUE(wait_for_beacon(beacon_scan_cb, BEACON_INTERVAL + 1, NULL, NULL)); @@ -687,7 +686,7 @@ static void test_rx_kr_old_key(void) bt_mesh_test_setup(); bt_mesh_iv_update_test(true); - err = bt_mesh_cfg_cli_net_key_update(0, cfg->addr, 0, test_net_key_2, &status); + err = bt_mesh_cfg_cli_net_key_update(0, cfg->addr, 0, test_net_key_secondary, &status); if (err || status) { FAIL("Net Key update failed (err %d, status %u)", err, status); } @@ -1542,73 +1541,60 @@ static void test_tx_priv_beacon_cache(void) #if IS_ENABLED(CONFIG_BT_MESH_GATT_PROXY) -static uint8_t test_net_key_3[16] = {0x12, 0x54, 0xab, 0x1e}; - -#define UNTIL_UPTIME(time) (k_uptime_get() > (time) ? K_NO_WAIT : K_MSEC((time) - k_uptime_get())) -#define BEACON_TYPE_NET_ID 0 -#define BEACON_TYPE_NODE_ID 1 #define BEACON_TYPE_PRIVATE_NET_ID 2 #define BEACON_TYPE_PRIVATE_NODE_ID 3 #define BEACON_TYPE_PRIVATE_LEN 28 #define TEST_NET_IDX1 0 #define TEST_NET_IDX2 1 -#define TEST_NET_IDX3 2 #define MAX_TIMEOUT ((CONFIG_BT_MESH_NODE_ID_TIMEOUT * 1000) / 6) #define PP_NET_ID_WAIT_TIME 610 /*seconds*/ #define PP_NODE_ID_WAIT_TIME 80 /*seconds*/ #define PP_MULT_NET_ID_WAIT_TIME 50 /*seconds*/ -#define PROXY_ADV_MULTI_SUBNET_COEX_WAIT_TIME 151 /*seconds*/ -struct netkey_ctx { +struct pp_netkey_ctx { uint8_t *net_key; uint8_t net_id[8]; - uint8_t net_idx; struct bt_mesh_key id_key; }; -static struct netkey_ctx pp_net0 = {.net_key = (uint8_t *)test_net_key, .net_idx = 0}; -static struct netkey_ctx pp_net1 = {.net_key = (uint8_t *)test_net_key_2, .net_idx = 1}; -static struct netkey_ctx pp_net2 = {.net_key = (uint8_t *)test_net_key_3, .net_idx = 2}; +static struct pp_netkey_ctx pp_net0 = {.net_key = (uint8_t *)test_net_key}; +static struct pp_netkey_ctx pp_net1 = {.net_key = (uint8_t *)test_net_key_secondary}; struct priv_test_ctx { uint8_t beacon_type; uint16_t *node_id_addr; }; -static void pp_netkey_ctx_init(struct netkey_ctx *net) +static void pp_netkey_ctx_init(struct pp_netkey_ctx *net) { ASSERT_OK_MSG(bt_mesh_identity_key(net->net_key, &net->id_key), "Failed to generate ID key"); ASSERT_OK_MSG(bt_mesh_k3(net->net_key, net->net_id), "Failed to generate Net ID"); } -static uint8_t proxy_adv_type_get(uint8_t adv_type, struct net_buf_simple *buf) +static bool pp_type_check(uint16_t expected_beacon, uint8_t adv_type, struct net_buf_simple *buf) { - uint8_t type; - uint8_t len = buf->len; - - if (adv_type != BT_GAP_ADV_TYPE_ADV_IND || len < 12) { - return 0xFF; + if (adv_type != BT_GAP_ADV_TYPE_ADV_IND || buf->len != BEACON_TYPE_PRIVATE_LEN) { + return false; } + /* Remove Header */ (void)net_buf_simple_pull_mem(buf, 11); - type = net_buf_simple_pull_u8(buf); - /* BEACON_TYPE_NET_ID is 20 bytes long, while the three other accepted types are 28 bytes*/ - if (len != ((type == BEACON_TYPE_NET_ID) ? 20 : 28)) { - return 0xFF; + + uint8_t beacon_type = net_buf_simple_pull_u8(buf); + + if (beacon_type != expected_beacon) { + return false; } - return type; + return true; } -static uint64_t proxy_adv_hash_calc(struct netkey_ctx *net, uint64_t random, uint16_t *addr, - bool is_priv) +static uint64_t pp_hash_calc(struct pp_netkey_ctx *net, uint64_t random, uint16_t *addr) { uint64_t hash; - uint8_t tmp[16] = {0}; - - tmp[5] = is_priv ? 3 : 0; + uint8_t tmp[16] = {0, 0, 0, 0, 0, 3}; if (addr) { memcpy(&tmp[6], &random, 8); @@ -1630,7 +1616,7 @@ static bool pp_beacon_check(const uint8_t *net_id, void *ctx) struct priv_test_ctx *test_ctx = (struct priv_test_ctx *)ctx; ASSERT_EQUAL(beacon.pp_hash, - proxy_adv_hash_calc(&pp_net0, beacon.pp_random, test_ctx->node_id_addr, true)); + pp_hash_calc(&pp_net0, beacon.pp_random, test_ctx->node_id_addr)); if (memcmp(beacon.adv_addr.a.val, last_beacon_adv_addr.a.val, BT_ADDR_SIZE) == 0) { return false; @@ -1646,58 +1632,15 @@ static void priv_scan_cb(const bt_addr_le_t *addr, int8_t rssi, uint8_t adv_type { struct priv_test_ctx *ctx = (struct priv_test_ctx *)beacon.user_ctx; - if (proxy_adv_type_get(adv_type, buf) != ctx->beacon_type) { + if (!pp_type_check(ctx->beacon_type, adv_type, buf)) { /* Wrong message type */ return; } bt_addr_le_copy(&beacon.adv_addr, addr); - if (ctx->beacon_type == BEACON_TYPE_NET_ID) { - beacon.net_id = net_buf_simple_pull_le64(buf); - } else { - beacon.pp_hash = net_buf_simple_pull_le64(buf); - beacon.pp_random = net_buf_simple_pull_le64(buf); - } - - if (!beacon.process_cb || beacon.process_cb(NULL, beacon.user_ctx)) { - k_sem_give(&observer_sem); - } -} - -struct proxy_adv_beacon { - uint8_t evt_type; - uint8_t net_idx; - int64_t rx_timestamp; - union { - uint64_t net_id; - struct { - uint64_t hash; - uint64_t random; - } enc; - } ctx; -}; - -static void proxy_adv_scan_all_cb(const bt_addr_le_t *addr, int8_t rssi, uint8_t adv_type, - struct net_buf_simple *buf) -{ - struct proxy_adv_beacon *beac = (struct proxy_adv_beacon *)beacon.user_ctx; - - beac->evt_type = proxy_adv_type_get(adv_type, buf); - if (beac->evt_type == 0xFF) { - /* Not a related beacon type */ - return; - } - - bt_addr_le_copy(&beacon.adv_addr, addr); - beac->rx_timestamp = k_uptime_get(); - - if (beac->evt_type == BEACON_TYPE_NET_ID) { - beac->ctx.net_id = net_buf_simple_pull_le64(buf); - } else { - beac->ctx.enc.hash = net_buf_simple_pull_le64(buf); - beac->ctx.enc.random = net_buf_simple_pull_le64(buf); - } + beacon.pp_hash = net_buf_simple_pull_le64(buf); + beacon.pp_random = net_buf_simple_pull_le64(buf); if (!beacon.process_cb || beacon.process_cb(NULL, beacon.user_ctx)) { k_sem_give(&observer_sem); @@ -1713,11 +1656,11 @@ static void rx_priv_common_init(uint16_t wait) ASSERT_OK_MSG(bt_enable(NULL), "Bluetooth init failed"); } -static void tx_proxy_adv_common_init(uint16_t wait, const struct bt_mesh_test_cfg *cfg) +static void tx_priv_common_init(uint16_t wait) { bt_mesh_test_cfg_set(NULL, wait); bt_mesh_device_setup(&prov, &prb_comp); - provision(cfg); + provision(&tx_cfg); /* Disable GATT proxy */ ASSERT_OK_MSG(bt_mesh_gatt_proxy_set(BT_MESH_GATT_PROXY_DISABLED), @@ -1726,7 +1669,7 @@ static void tx_proxy_adv_common_init(uint16_t wait, const struct bt_mesh_test_cf static void test_tx_priv_net_id(void) { - tx_proxy_adv_common_init(PP_NET_ID_WAIT_TIME, &tx_cfg); + tx_priv_common_init(PP_NET_ID_WAIT_TIME); /* Enable private GATT proxy */ ASSERT_OK_MSG(bt_mesh_priv_gatt_proxy_set(BT_MESH_GATT_PROXY_ENABLED), @@ -1765,7 +1708,7 @@ static void test_tx_priv_node_id(void) { enum bt_mesh_feat_state state; - tx_proxy_adv_common_init(PP_NODE_ID_WAIT_TIME, &tx_cfg); + tx_priv_common_init(PP_NODE_ID_WAIT_TIME); /* Start first node advertisement */ ASSERT_OK_MSG(bt_mesh_subnet_priv_node_id_set(TEST_NET_IDX1, BT_MESH_NODE_IDENTITY_RUNNING), @@ -1818,10 +1761,10 @@ static void test_rx_priv_node_id(void) static void test_tx_priv_multi_net_id(void) { - tx_proxy_adv_common_init(PP_MULT_NET_ID_WAIT_TIME, &tx_cfg); + tx_priv_common_init(PP_MULT_NET_ID_WAIT_TIME); /* Add second network */ - ASSERT_OK_MSG(bt_mesh_subnet_add(TEST_NET_IDX2, test_net_key_2), + ASSERT_OK_MSG(bt_mesh_subnet_add(TEST_NET_IDX2, test_net_key_secondary), "Failed to add second subnet"); /* Enable private GATT proxy */ @@ -1831,246 +1774,6 @@ static void test_tx_priv_multi_net_id(void) PASS(); } -static void proxy_adv_subnet_find(struct proxy_adv_beacon *beac, struct netkey_ctx **nets, - uint8_t net_cnt) -{ - for (size_t i = 0; i < net_cnt; i++) { - - switch (beac->evt_type) { - case BEACON_TYPE_NET_ID: - if (!memcmp(nets[i]->net_id, &beac->ctx.net_id, 8)) { - beac->net_idx = nets[i]->net_idx; - return; - } - break; - case BEACON_TYPE_NODE_ID: - if (beac->ctx.enc.hash == - proxy_adv_hash_calc(nets[i], beac->ctx.enc.random, - (uint16_t *)&tx_cfg.addr, false)) { - beac->net_idx = nets[i]->net_idx; - return; - } - break; - case BEACON_TYPE_PRIVATE_NET_ID: - if (beac->ctx.enc.hash == - proxy_adv_hash_calc(nets[i], beac->ctx.enc.random, - NULL, true)) { - beac->net_idx = nets[i]->net_idx; - return; - } - break; - case BEACON_TYPE_PRIVATE_NODE_ID: - if (beac->ctx.enc.hash == - proxy_adv_hash_calc(nets[i], beac->ctx.enc.random, - (uint16_t *)&tx_cfg.addr, true)) { - beac->net_idx = nets[i]->net_idx; - return; - } - break; - - default: - FAIL("Unexpected beacon type"); - break; - } - } - - FAIL("Could not find matching subnet for incoming proxy adv beacon"); -} - -static const char *const proxy_adv_str[] = {"Net_ID", "Node_ID", "Priv_Net_ID", "Priv_Node_ID"}; -struct expected_proxy_adv_evt { - uint8_t evt_type; - uint8_t net_idx; - uint16_t evt_cnt; - struct { - int64_t after; - int64_t before; - } time; -}; - -static void proxy_adv_register_evt(struct proxy_adv_beacon *beac, - struct expected_proxy_adv_evt *exp_evts, uint8_t cnt) -{ - for (int i = 0; i < cnt; i++) { - if ((exp_evts[i].evt_cnt) && (beac->evt_type == exp_evts[i].evt_type) && - (beac->net_idx == exp_evts[i].net_idx) && - (beac->rx_timestamp >= exp_evts[i].time.after) && - (beac->rx_timestamp <= exp_evts[i].time.before)) { - exp_evts[i].evt_cnt--; - } - } -} - -static void proxy_adv_confirm_evt(struct expected_proxy_adv_evt *exp_evts, uint8_t cnt) -{ - bool missing_evts = false; - - for (int i = 0; i < cnt; i++) { - if (exp_evts[i].evt_cnt) { - LOG_ERR("Missing %d expected %s events in period %llums-%llums", - exp_evts[i].evt_cnt, proxy_adv_str[exp_evts[i].evt_type], - exp_evts[i].time.after, exp_evts[i].time.before); - missing_evts = true; - } - } - - if (missing_evts) { - FAIL("Test failed due to missing events"); - } -} - -static void proxy_adv_scan_all(struct netkey_ctx **nets, uint16_t net_cnt, - struct expected_proxy_adv_evt *exp_evt, uint16_t exp_evt_cnt, - int64_t timeout) -{ - struct proxy_adv_beacon beac; - - while (k_uptime_get() < timeout) { - - ASSERT_TRUE(wait_for_beacon(proxy_adv_scan_all_cb, 2, NULL, &beac)); - proxy_adv_subnet_find(&beac, nets, net_cnt); - proxy_adv_register_evt(&beac, exp_evt, exp_evt_cnt); - - /** We want to monitor an even distribution of adv events. - * To ensure this, we wait a little less than the minimum - * proxy adv period (1 second) before scanning for the next - * evt. - */ - k_sleep(K_MSEC(990)); - } - - proxy_adv_confirm_evt(exp_evt, exp_evt_cnt); -} - -#define PROXY_ADV_MULTI_CHECKPOINT_1 20000 -#define PROXY_ADV_MULTI_CHECKPOINT_2 50000 -#define PROXY_ADV_MULTI_CHECKPOINT_3 110000 -#define PROXY_ADV_MULTI_CHECKPOINT_4 130000 -#define PROXY_ADV_MULTI_CHECKPOINT_END 150000 - -static void test_tx_proxy_adv_multi_subnet_coex(void) -{ - tx_proxy_adv_common_init(PROXY_ADV_MULTI_SUBNET_COEX_WAIT_TIME, &tx_cfg); - - /* Enable GATT proxy */ - ASSERT_OK_MSG(bt_mesh_gatt_proxy_set(BT_MESH_GATT_PROXY_ENABLED), - "Failed to Enable gatt proxy"); - - k_sleep(UNTIL_UPTIME(PROXY_ADV_MULTI_CHECKPOINT_1)); - /* Add second and third network */ - ASSERT_OK_MSG(bt_mesh_subnet_add(TEST_NET_IDX2, test_net_key_2), - "Failed to add second subnet"); - ASSERT_OK_MSG(bt_mesh_subnet_add(TEST_NET_IDX3, test_net_key_3), - "Failed to add third subnet"); - - k_sleep(UNTIL_UPTIME(PROXY_ADV_MULTI_CHECKPOINT_2)); - /* Start Node Identity on second network */ - bt_mesh_proxy_identity_start(bt_mesh_subnet_get(TEST_NET_IDX2), false); - - k_sleep(UNTIL_UPTIME(PROXY_ADV_MULTI_CHECKPOINT_3)); - /* Prepare for solicitation */ - ASSERT_OK_MSG(bt_mesh_gatt_proxy_set(BT_MESH_GATT_PROXY_DISABLED), - "Failed to Enable gatt proxy"); - ASSERT_OK_MSG(bt_mesh_od_priv_proxy_set(20), "Failed to set OD priv proxy state"); - - k_sleep(UNTIL_UPTIME(PROXY_ADV_MULTI_CHECKPOINT_4)); - /* Re-enable GATT proxy and remove second and third network */ - ASSERT_OK_MSG(bt_mesh_gatt_proxy_set(BT_MESH_GATT_PROXY_ENABLED), - "Failed to Enable gatt proxy"); - ASSERT_OK_MSG(bt_mesh_subnet_del(TEST_NET_IDX2), "Failed to delete subnet"); - ASSERT_OK_MSG(bt_mesh_subnet_del(TEST_NET_IDX3), "Failed to delete subnet"); - - PASS(); -} - -static const struct bt_mesh_test_cfg solicit_trigger_cfg = { - .addr = 0x0003, - .dev_key = { 0x03 }, -}; - -static void test_tx_proxy_adv_solicit_trigger(void) -{ - tx_proxy_adv_common_init(PROXY_ADV_MULTI_SUBNET_COEX_WAIT_TIME, &solicit_trigger_cfg); - ASSERT_OK_MSG(bt_mesh_subnet_add(TEST_NET_IDX2, test_net_key_2), - "Failed to add second subnet"); - - k_sleep(UNTIL_UPTIME(PROXY_ADV_MULTI_CHECKPOINT_3)); - - /* Solicit first and second network */ - ASSERT_OK_MSG(bt_mesh_proxy_solicit(TEST_NET_IDX1), - "Failed to start solicitation"); - ASSERT_OK_MSG(bt_mesh_proxy_solicit(TEST_NET_IDX2), - "Failed to start solicitation"); - - PASS(); -} - -static void test_rx_proxy_adv_multi_subnet_coex(void) -{ - rx_priv_common_init(PROXY_ADV_MULTI_SUBNET_COEX_WAIT_TIME); - pp_netkey_ctx_init(&pp_net1); - pp_netkey_ctx_init(&pp_net2); - - struct netkey_ctx *nets[] = {&pp_net0, &pp_net1, &pp_net2}; - struct expected_proxy_adv_evt exp_evt[] = { - /** A single subnet is active on the device with GATT Proxy - * enabled. Verify that the single subnet has exclusive - * access to the adv medium. - */ - {.evt_type = BEACON_TYPE_NET_ID, .net_idx = 0, .evt_cnt = 19, - .time = {.after = 0, .before = PROXY_ADV_MULTI_CHECKPOINT_1}}, - - /** Two additional subnets are added to the device. - * Check that the subnets are sharing the adv medium, - * advertising NET_ID beacons. - */ - {.evt_type = BEACON_TYPE_NET_ID, .net_idx = 0, .evt_cnt = 8, - .time = {.after = PROXY_ADV_MULTI_CHECKPOINT_1, - .before = PROXY_ADV_MULTI_CHECKPOINT_2}}, - {.evt_type = BEACON_TYPE_NET_ID, .net_idx = 1, .evt_cnt = 8, - .time = {.after = PROXY_ADV_MULTI_CHECKPOINT_1, - .before = PROXY_ADV_MULTI_CHECKPOINT_2}}, - {.evt_type = BEACON_TYPE_NET_ID, .net_idx = 2, .evt_cnt = 8, - .time = {.after = PROXY_ADV_MULTI_CHECKPOINT_1, - .before = PROXY_ADV_MULTI_CHECKPOINT_2}}, - - /** The second subnet enables Node Identity. Check that NODE_ID - * is advertised by this subnet, and that the two others - * continues to advertise NET_ID. - */ - {.evt_type = BEACON_TYPE_NET_ID, .net_idx = 0, .evt_cnt = 17, - .time = {.after = PROXY_ADV_MULTI_CHECKPOINT_2, - .before = PROXY_ADV_MULTI_CHECKPOINT_3}}, - {.evt_type = BEACON_TYPE_NODE_ID, .net_idx = 1, .evt_cnt = 17, - .time = {.after = PROXY_ADV_MULTI_CHECKPOINT_2, - .before = PROXY_ADV_MULTI_CHECKPOINT_3}}, - {.evt_type = BEACON_TYPE_NET_ID, .net_idx = 2, .evt_cnt = 17, - .time = {.after = PROXY_ADV_MULTI_CHECKPOINT_2, - .before = PROXY_ADV_MULTI_CHECKPOINT_3}}, - - /** The first and second subnet gets solicited. Check that - * PRIVATE_NET_ID is advertised by these subnet, - */ - {.evt_type = BEACON_TYPE_PRIVATE_NET_ID, .net_idx = 0, .evt_cnt = 9, - .time = {.after = PROXY_ADV_MULTI_CHECKPOINT_3, - .before = PROXY_ADV_MULTI_CHECKPOINT_4}}, - {.evt_type = BEACON_TYPE_PRIVATE_NET_ID, .net_idx = 1, .evt_cnt = 9, - .time = {.after = PROXY_ADV_MULTI_CHECKPOINT_3, - .before = PROXY_ADV_MULTI_CHECKPOINT_4}}, - - /** Second and third subnet are disabled. Verify that the single - * subnet has exclusive access to the adv medium. - */ - {.evt_type = BEACON_TYPE_NET_ID, .net_idx = 0, .evt_cnt = 19, - .time = {.after = PROXY_ADV_MULTI_CHECKPOINT_4, - .before = PROXY_ADV_MULTI_CHECKPOINT_END}}, - }; - - proxy_adv_scan_all(nets, ARRAY_SIZE(nets), exp_evt, ARRAY_SIZE(exp_evt), - PROXY_ADV_MULTI_CHECKPOINT_END); - PASS(); -} - static void test_rx_priv_multi_net_id(void) { rx_priv_common_init(PP_MULT_NET_ID_WAIT_TIME); @@ -2084,7 +1787,7 @@ static void test_rx_priv_multi_net_id(void) uint16_t itr = 4; static uint8_t old_idx = 0xff; static struct { - struct netkey_ctx *net; + struct pp_netkey_ctx *net; uint16_t recv_cnt; int64_t start; } net_ctx[2] = { @@ -2099,7 +1802,7 @@ static void test_rx_priv_multi_net_id(void) for (size_t i = 0; i < ARRAY_SIZE(net_ctx); i++) { if (beacon.pp_hash == - proxy_adv_hash_calc(net_ctx[i].net, beacon.pp_random, NULL, true)) { + pp_hash_calc(net_ctx[i].net, beacon.pp_random, NULL)) { if (old_idx == 0xff) { /* Received first Net ID advertisment */ old_idx = i; @@ -2228,8 +1931,6 @@ static const struct bst_test_instance test_beacon[] = { TEST_CASE(tx, priv_node_id, "Private Proxy: advertise Node ID"), TEST_CASE(tx, priv_multi_net_id, "Private Proxy: advertise multiple Net ID"), TEST_CASE(tx, priv_gatt_proxy, "Private Proxy: Send Private Beacons over GATT"), - TEST_CASE(tx, proxy_adv_multi_subnet_coex, "Proxy Adv: Multi subnet coex proxy adv"), - TEST_CASE(tx, proxy_adv_solicit_trigger, "Proxy Adv: Trigger Solicitation"), #endif #endif @@ -2250,7 +1951,6 @@ static const struct bst_test_instance test_beacon[] = { TEST_CASE(rx, priv_node_id, "Private Proxy: scan for Node ID"), TEST_CASE(rx, priv_multi_net_id, "Private Proxy: scan for multiple Net ID"), TEST_CASE(rx, priv_gatt_proxy, "Private Proxy: Receive Private Beacons over GATT"), - TEST_CASE(rx, proxy_adv_multi_subnet_coex, "Proxy Adv: Multi subnet coex proxy adv"), #endif #endif BSTEST_END_MARKER diff --git a/tests/bsim/bluetooth/mesh/tests_scripts/priv_beacon/proxy_adv_multi_subnet_coex.sh b/tests/bsim/bluetooth/mesh/tests_scripts/priv_beacon/proxy_adv_multi_subnet_coex.sh deleted file mode 100755 index aa96ee325d8..00000000000 --- a/tests/bsim/bluetooth/mesh/tests_scripts/priv_beacon/proxy_adv_multi_subnet_coex.sh +++ /dev/null @@ -1,54 +0,0 @@ -#!/usr/bin/env bash -# Copyright 2023 Nordic Semiconductor -# SPDX-License-Identifier: Apache-2.0 - -source $(dirname "${BASH_SOURCE[0]}")/../../_mesh_test.sh - -# Test Proxy advertisement Coex - -# This test verifies correct Proxy advertisement behavior for a device -# where the Proxy adv requirements changes over time, both for single -# and multiple subnets. The TX device is the DUT in this instance, while -# the RX device scans and verifies that the correct proxy adv messages of -# the different subnets is sent within the expected time delta. - -# Note 1: The maximum allowed timeslot for a subnet to advertise proxy -# in this scenario is 10 seconds when there is more than one subnet that -# has active proxy adv work. This is reflected in the scanning criteria -# on the RX device. - -# Note 2: The expected message received count for each event is based on -# what would be a reasonable/acceptable to receive within a given time -# window. The Mesh Protocol specification does not specify exactly the -# timing for Proxy ADV messages. - -# Test procedure: -# 1. (0-20 seconds) A single subnet is active on the TX device with GATT -# Proxy enabled. RX device verifies that the single subnet has exclusive -# access to the adv medium. -# 2. (20-50 seconds) Two additional subnets are added to the TX device. RX -# device checks that the subnets are sharing the adv medium, advertising -# NET_ID beacons. -# 3. (50-110 seconds) The second subnet enables Node Identity. RX device -# checks that NODE_ID is advertised by this subnet, and that the two -# others continues to advertise NET_ID. -# 4. (110-130 seconds) The first and second subnet gets solicited. RX device -# checks that PRIVATE_NET_ID is advertised by these subnets. -# 5. (130-150 seconds) The second and third subnet are disabled on the TX -# device. RX device verifies that the single subnet has exclusive access -# to the adv medium again. - - -conf=prj_mesh1d1_conf -overlay=overlay_gatt_conf -RunTest proxy_adv_multi_subnet_coex \ - beacon_tx_proxy_adv_multi_subnet_coex \ - beacon_rx_proxy_adv_multi_subnet_coex \ - beacon_tx_proxy_adv_solicit_trigger - -conf=prj_mesh1d1_conf -overlay=overlay_gatt_conf_overlay_psa_conf -RunTest proxy_adv_multi_subnet_coex \ - beacon_tx_proxy_adv_multi_subnet_coex \ - beacon_rx_proxy_adv_multi_subnet_coex \ - beacon_tx_proxy_adv_solicit_trigger From 24d500271843de50a34ef39f3c8a024ee971801c Mon Sep 17 00:00:00 2001 From: Robert Lubos Date: Tue, 6 Feb 2024 11:07:20 +0100 Subject: [PATCH 3604/3723] Revert "[nrf fromtree] Bluetooth: Mesh: Refactor proxy adv" This reverts commit 0408887166fe5c6d5636569437881bd21147250c. Signed-off-by: Robert Lubos --- subsys/bluetooth/mesh/proxy_srv.c | 332 +++++++++----------- tests/bsim/bluetooth/mesh/src/test_beacon.c | 10 +- 2 files changed, 152 insertions(+), 190 deletions(-) diff --git a/subsys/bluetooth/mesh/proxy_srv.c b/subsys/bluetooth/mesh/proxy_srv.c index 9cad9e2fe04..45e29915325 100644 --- a/subsys/bluetooth/mesh/proxy_srv.c +++ b/subsys/bluetooth/mesh/proxy_srv.c @@ -625,7 +625,7 @@ static int net_id_adv(struct bt_mesh_subnet *sub, int32_t duration) return 0; } -static bool is_sub_proxy_active(struct bt_mesh_subnet *sub) +static bool advertise_subnet(struct bt_mesh_subnet *sub) { if (sub->net_idx == BT_MESH_KEY_UNUSED) { return false; @@ -633,245 +633,201 @@ static bool is_sub_proxy_active(struct bt_mesh_subnet *sub) return (sub->node_id == BT_MESH_NODE_IDENTITY_RUNNING || #if defined(CONFIG_BT_MESH_OD_PRIV_PROXY_SRV) - (bt_mesh_od_priv_proxy_get() > 0 && sub->solicited) || + sub->solicited || #endif bt_mesh_gatt_proxy_get() == BT_MESH_GATT_PROXY_ENABLED || bt_mesh_priv_gatt_proxy_get() == BT_MESH_GATT_PROXY_ENABLED); } -static bool active_proxy_sub_cnt_cb(struct bt_mesh_subnet *sub, void *cb_data) +static struct bt_mesh_subnet *next_sub(void) { - int *cnt = cb_data; + struct bt_mesh_subnet *sub = NULL; - if (is_sub_proxy_active(sub)) { - (*cnt)++; - } - - /* Don't stop until we've visited all subnets. - * We're only using the "find" variant of the subnet iteration to get a context parameter. - */ - return false; -} - -static int active_proxy_sub_cnt_get(void) -{ - int cnt = 0; - - (void)bt_mesh_subnet_find(active_proxy_sub_cnt_cb, &cnt); - - return cnt; -} - -static void proxy_adv_timeout_eval(struct bt_mesh_subnet *sub) -{ - int32_t time_passed; - - if (sub->node_id == BT_MESH_NODE_IDENTITY_RUNNING) { - time_passed = k_uptime_get_32() - sub->node_id_start; - if (time_passed > (NODE_ID_TIMEOUT - MSEC_PER_SEC)) { - bt_mesh_proxy_identity_stop(sub); - LOG_DBG("Node ID stopped for subnet %d after %dms", sub->net_idx, - time_passed); + if (!beacon_sub) { + beacon_sub = bt_mesh_subnet_next(NULL); + if (!beacon_sub) { + /* No valid subnets */ + return NULL; } } -#if defined(CONFIG_BT_MESH_OD_PRIV_PROXY_SRV) - if (bt_mesh_od_priv_proxy_get() > 0 && sub->solicited && sub->priv_net_id_sent) { - time_passed = k_uptime_get_32() - sub->priv_net_id_sent; - if (time_passed > ((MSEC_PER_SEC * bt_mesh_od_priv_proxy_get()) - MSEC_PER_SEC)) { - sub->priv_net_id_sent = 0; - sub->solicited = false; - LOG_DBG("Private Network ID stopped for subnet %d after %dms on " - "solicitation", - sub->net_idx, time_passed); + sub = beacon_sub; + do { + if (advertise_subnet(sub)) { + beacon_sub = sub; + return sub; } - } -#endif -} -enum proxy_adv_evt { - NET_ID, - PRIV_NET_ID, - NODE_ID, - PRIV_NODE_ID, - OD_PRIV_NET_ID, -}; + sub = bt_mesh_subnet_next(sub); + } while (sub != beacon_sub); -struct proxy_adv_request { - int32_t duration; - enum proxy_adv_evt evt; -}; + /* No subnets to advertise on */ + return NULL; +} -static bool proxy_adv_request_get(struct bt_mesh_subnet *sub, struct proxy_adv_request *request) +static bool sub_count_cb(struct bt_mesh_subnet *sub, void *cb_data) { - if (!sub) { - return false; - } + int *count = cb_data; - if (sub->net_idx == BT_MESH_KEY_UNUSED) { - return false; + if (advertise_subnet(sub)) { + (*count)++; } -#if defined(CONFIG_BT_MESH_OD_PRIV_PROXY_SRV) - if (bt_mesh_od_priv_proxy_get() > 0 && sub->solicited) { - int32_t timeout = MSEC_PER_SEC * (int32_t)bt_mesh_od_priv_proxy_get(); - - request->evt = OD_PRIV_NET_ID; - request->duration = !sub->priv_net_id_sent - ? timeout - : timeout - (k_uptime_get_32() - sub->priv_net_id_sent); - return true; - } -#endif - - if (sub->node_id == BT_MESH_NODE_IDENTITY_RUNNING) { - request->duration = NODE_ID_TIMEOUT - (k_uptime_get_32() - sub->node_id_start); - request->evt = -#if defined(CONFIG_BT_MESH_PRIV_BEACONS) - sub->priv_beacon_ctx.node_id ? PRIV_NODE_ID : -#endif - NODE_ID; - - return true; - } + /* Don't stop until we've visited all subnets. + * We're only using the "find" variant of the subnet iteration to get a context parameter. + */ + return false; +} - if (bt_mesh_priv_gatt_proxy_get() == BT_MESH_FEATURE_ENABLED) { - request->evt = PRIV_NET_ID; - request->duration = PROXY_RANDOM_UPDATE_INTERVAL; - return true; - } +static int sub_count(void) +{ + int count = 0; - if (bt_mesh_gatt_proxy_get() == BT_MESH_FEATURE_ENABLED) { - request->evt = NET_ID; - request->duration = SYS_FOREVER_MS; - return true; - } + (void)bt_mesh_subnet_find(sub_count_cb, &count); - return false; + return count; } -static struct bt_mesh_subnet *adv_sub_get_next(struct bt_mesh_subnet *sub_start, - struct proxy_adv_request *request) +#if defined(CONFIG_BT_MESH_OD_PRIV_PROXY_SRV) +static void gatt_proxy_solicited(struct bt_mesh_subnet *sub) { - struct bt_mesh_subnet *sub_temp = sub_start; - - do { - if (proxy_adv_request_get(sub_temp, request)) { - return sub_temp; - } + int64_t now = k_uptime_get(); + int64_t timeout = 0; + int32_t remaining; + + if (sub->priv_net_id_sent > 0) { + timeout = sub->priv_net_id_sent + + MSEC_PER_SEC * (int64_t) bt_mesh_od_priv_proxy_get(); + remaining = MIN(timeout - now, INT32_MAX); + } else { + remaining = MSEC_PER_SEC * bt_mesh_od_priv_proxy_get(); + } - sub_temp = bt_mesh_subnet_next(sub_temp); - } while (sub_temp != sub_start); + if ((timeout > 0 && now > timeout) || (remaining / MSEC_PER_SEC < 1)) { + LOG_DBG("Advertising Private Network ID timed out " + "after solicitation"); + sub->priv_net_id_sent = 0; + sub->solicited = false; + } else { + LOG_DBG("Advertising Private Network ID for %ds" + "(%d remaining)", + bt_mesh_od_priv_proxy_get(), + remaining / MSEC_PER_SEC); + priv_net_id_adv(sub, remaining); - return NULL; + if (!sub->priv_net_id_sent) { + sub->priv_net_id_sent = now; + } + } } +#endif -static struct { - int32_t start; - struct bt_mesh_subnet *sub; - struct proxy_adv_request request; -} sub_adv; - -static int gatt_proxy_advertise(void) +static int gatt_proxy_advertise(struct bt_mesh_subnet *sub) { - int err; - - int32_t max_adv_duration; - int cnt; - struct bt_mesh_subnet *sub; - struct proxy_adv_request request; + int32_t remaining = SYS_FOREVER_MS; + int subnet_count; + int err = -EBUSY; + bool planned = false; LOG_DBG(""); - /* Close proxy activity that has timed out on all subnets */ - bt_mesh_subnet_foreach(proxy_adv_timeout_eval); - if (!bt_mesh_proxy_has_avail_conn()) { LOG_DBG("Connectable advertising deferred (max connections)"); return -ENOMEM; } - cnt = active_proxy_sub_cnt_get(); - if (!cnt) { - LOG_DBG("No subnets to advertise proxy on"); + sub = beacon_sub ? beacon_sub : bt_mesh_subnet_next(beacon_sub); + if (!sub) { + LOG_WRN("No subnets to advertise on"); return -ENOENT; - } else if (cnt > 1) { - /** There is more than one subnet that requires proxy adv, - * and the adv resources must be shared. - */ + } + + subnet_count = sub_count(); + LOG_DBG("sub_count %u", subnet_count); + if (subnet_count > 1) { + int32_t max_timeout; /* We use NODE_ID_TIMEOUT as a starting point since it may * be less than 60 seconds. Divide this period into at least - * 6 slices, but make sure that a slice is more than one + * 6 slices, but make sure that a slice is at least one * second long (to avoid excessive rotation). */ - max_adv_duration = NODE_ID_TIMEOUT / MAX(cnt, 6); - max_adv_duration = MAX(max_adv_duration, MSEC_PER_SEC + 20); - - /* Check if the previous subnet finished its allocated timeslot */ - if ((sub_adv.request.duration != SYS_FOREVER_MS) && - proxy_adv_request_get(sub_adv.sub, &request) && - (sub_adv.request.evt == request.evt)) { - int32_t time_passed = k_uptime_get_32() - sub_adv.start; - - if (time_passed < sub_adv.request.duration && - ((sub_adv.request.duration - time_passed) >= MSEC_PER_SEC)) { - sub = sub_adv.sub; - request.duration = sub_adv.request.duration - time_passed; - goto end; - } + max_timeout = NODE_ID_TIMEOUT / MAX(subnet_count, 6); + max_timeout = MAX(max_timeout, 1 * MSEC_PER_SEC); + + if (remaining > max_timeout || remaining == SYS_FOREVER_MS) { + remaining = max_timeout; } } - sub = adv_sub_get_next(bt_mesh_subnet_next(sub_adv.sub), &request); - if (!sub) { - LOG_ERR("Could not find subnet to advertise"); - return -ENOENT; - } -end: - if (cnt > 1) { - request.duration = (request.duration == SYS_FOREVER_MS) - ? max_adv_duration - : MIN(request.duration, max_adv_duration); - } + for (int i = 0; i < subnet_count; i++) { - /* Save current state for next iteration */ - sub_adv.start = k_uptime_get_32(); - sub_adv.sub = sub; - sub_adv.request = request; + if (sub->node_id == BT_MESH_NODE_IDENTITY_RUNNING) { + uint32_t active = k_uptime_get_32() - sub->node_id_start; + bool priv_node_id = false; - switch (request.evt) { - case NET_ID: - err = net_id_adv(sub, request.duration); - break; -#if defined(CONFIG_BT_MESH_OD_PRIV_PROXY_SRV) - case OD_PRIV_NET_ID: - if (!sub->priv_net_id_sent) { - sub->priv_net_id_sent = k_uptime_get(); + if (active < NODE_ID_TIMEOUT) { + remaining = MIN(remaining, NODE_ID_TIMEOUT - active); + LOG_DBG("Node ID active for %u ms, %d ms remaining", + active, remaining); +#if defined(CONFIG_BT_MESH_PRIV_BEACONS) + priv_node_id = sub->priv_beacon_ctx.node_id; +#endif + if (priv_node_id) { + err = priv_node_id_adv(sub, remaining); + } else { + err = node_id_adv(sub, remaining); + } + planned = true; + } else { + bt_mesh_proxy_identity_stop(sub); + LOG_DBG("Node ID stopped"); + } } - /* Fall through */ + + /* MshPRTv1.1: section 7.2.2.2.1: + * "A node that does not support the Proxy feature or + * has the GATT Proxy state disabled shall not advertise with Network ID." + */ + if (sub->node_id == BT_MESH_NODE_IDENTITY_STOPPED) { + if (IS_ENABLED(CONFIG_BT_MESH_PRIV_BEACONS) && + (bt_mesh_priv_gatt_proxy_get() == BT_MESH_GATT_PROXY_ENABLED)) { + /* MshPRTv1.1: 7.2.2.2.4: The Random + * field should be updated every 10 minutes. Limit advertising to + * 10 minutes to ensure regeneration of a new random value at least + * that often. + */ + if (remaining == SYS_FOREVER_MS || + remaining > PROXY_RANDOM_UPDATE_INTERVAL) { + remaining = PROXY_RANDOM_UPDATE_INTERVAL; + } + + err = priv_net_id_adv(sub, remaining); + planned = true; + } else if (bt_mesh_gatt_proxy_get() == BT_MESH_FEATURE_ENABLED) { + err = net_id_adv(sub, remaining); + planned = true; + } + +#if defined(CONFIG_BT_MESH_OD_PRIV_PROXY_SRV) + else if (bt_mesh_od_priv_proxy_get() > 0 && + sub->solicited) { + gatt_proxy_solicited(sub); + } #endif - case PRIV_NET_ID: - err = priv_net_id_adv(sub, request.duration); - break; - case NODE_ID: - err = node_id_adv(sub, request.duration); - break; - case PRIV_NODE_ID: - err = priv_node_id_adv(sub, request.duration); - break; - default: - LOG_ERR("Unexpected proxy adv evt: %d", request.evt); - return -ENODEV; - } + } - if (err) { - LOG_ERR("Advertising proxy failed (err: %d)", err); - return err; + beacon_sub = bt_mesh_subnet_next(sub); + + if (planned) { + LOG_DBG("Advertising %d ms for net_idx 0x%04x", remaining, sub->net_idx); + return err; + } + + sub = beacon_sub; } - LOG_DBG("Advertising %d ms for net_idx 0x%04x", request.duration, sub->net_idx); - return err; + return 0; } static void subnet_evt(struct bt_mesh_subnet *sub, enum bt_mesh_key_evt evt) @@ -1196,7 +1152,7 @@ int bt_mesh_proxy_adv_start(void) return -ENOTSUP; } - return gatt_proxy_advertise(); + return gatt_proxy_advertise(next_sub()); } BT_CONN_CB_DEFINE(conn_callbacks) = { diff --git a/tests/bsim/bluetooth/mesh/src/test_beacon.c b/tests/bsim/bluetooth/mesh/src/test_beacon.c index f9230a397a9..038c705f2cb 100644 --- a/tests/bsim/bluetooth/mesh/src/test_beacon.c +++ b/tests/bsim/bluetooth/mesh/src/test_beacon.c @@ -1763,6 +1763,12 @@ static void test_tx_priv_multi_net_id(void) { tx_priv_common_init(PP_MULT_NET_ID_WAIT_TIME); + /* TODO: This should be removed as soon as + * SNB/proxy service advertising issue has + * been resolved. + */ + bt_mesh_beacon_set(false); + /* Add second network */ ASSERT_OK_MSG(bt_mesh_subnet_add(TEST_NET_IDX2, test_net_key_secondary), "Failed to add second subnet"); @@ -1813,8 +1819,8 @@ static void test_rx_priv_multi_net_id(void) /* Verify last Net ID adv result */ ASSERT_IN_RANGE(k_uptime_get() - net_ctx[old_idx].start, - MAX_TIMEOUT - 1000, MAX_TIMEOUT + 1000); - ASSERT_IN_RANGE(net_ctx[old_idx].recv_cnt, 9, 12); + MAX_TIMEOUT - 1000, MAX_TIMEOUT); + ASSERT_IN_RANGE(net_ctx[old_idx].recv_cnt, 9, 10); net_ctx[old_idx].recv_cnt = 0; old_idx = i; From d24272de9d20f04fc7dbd999d3c8b6223030e4a9 Mon Sep 17 00:00:00 2001 From: Robert Lubos Date: Tue, 6 Feb 2024 11:07:20 +0100 Subject: [PATCH 3605/3723] Revert "[nrf fromtree] Bluetooth: Mesh: Added support for randomly delaying publications" This reverts commit 9fe0ab63064c48af7e7a52080d7804c8811748fa. Signed-off-by: Robert Lubos --- .../bluetooth/api/mesh/access.rst | 15 -- include/zephyr/bluetooth/mesh/access.h | 2 - subsys/bluetooth/mesh/Kconfig | 9 - subsys/bluetooth/mesh/access.c | 91 +-------- tests/bsim/bluetooth/mesh/src/test_access.c | 176 ++---------------- .../access/access_period_delayable.sh | 17 -- .../access/access_transmit_delayable.sh | 17 -- 7 files changed, 16 insertions(+), 311 deletions(-) delete mode 100755 tests/bsim/bluetooth/mesh/tests_scripts/access/access_period_delayable.sh delete mode 100755 tests/bsim/bluetooth/mesh/tests_scripts/access/access_transmit_delayable.sh diff --git a/doc/connectivity/bluetooth/api/mesh/access.rst b/doc/connectivity/bluetooth/api/mesh/access.rst index cb02028b697..7030a3c14b2 100644 --- a/doc/connectivity/bluetooth/api/mesh/access.rst +++ b/doc/connectivity/bluetooth/api/mesh/access.rst @@ -255,21 +255,6 @@ message, it will send messages with delay close to expiration to free memory. When the mesh stack is suspended or reset, messages not yet sent are removed and the :c:member:`bt_mesh_send_cb.start` callback is raised with an error code. -Delayable publications -====================== - -The delayable publication functionality implements the specification recommendations for message -publication delays in the following cases: - -* Between 20 to 500 milliseconds when the Bluetooth Mesh stack starts or when the publication is - triggered by the :c:func:`bt_mesh_model_publish` function -* Between 20 to 50 milliseconds for periodically published messages - -This feature is optional and enabled with the :kconfig:option:`CONFIG_BT_MESH_DELAYABLE_PUBLICATION` -Kconfig option. When enabled, each model can enable or disable the delayable publication by setting -the :c:member:`bt_mesh_model_pub.delayable` bit field to ``1`` or ``0`` correspondingly. This bit -field can be changed at any time. - API reference ************* diff --git a/include/zephyr/bluetooth/mesh/access.h b/include/zephyr/bluetooth/mesh/access.h index a236ede525d..d57f30f8f05 100644 --- a/include/zephyr/bluetooth/mesh/access.h +++ b/include/zephyr/bluetooth/mesh/access.h @@ -713,8 +713,6 @@ struct bt_mesh_model_pub { uint8_t period_div:4, /**< Divisor for the Period. */ count:4; /**< Transmissions left. */ - uint8_t delayable:1; /**< Use random delay for publishing. */ - uint32_t period_start; /**< Start of the current period. */ /** @brief Publication buffer, containing the publication message. diff --git a/subsys/bluetooth/mesh/Kconfig b/subsys/bluetooth/mesh/Kconfig index af6af8c44dc..bffbac3e8e7 100644 --- a/subsys/bluetooth/mesh/Kconfig +++ b/subsys/bluetooth/mesh/Kconfig @@ -672,15 +672,6 @@ config BT_MESH_ACCESS_DELAYABLE_MSG_CHUNK_COUNT endif # BT_MESH_ACCESS_DELAYABLE_MSG -config BT_MESH_DELAYABLE_PUBLICATION - bool "Delayable publication" - default y - help - When enabled, the periodic publications are randomly delayed by 20 to 50ms. Publications - triggered at the start of the stack or by the bt_mesh_model_publish() call are delayed by - 20 to 500ms. This option reduces the probability of collisions when multiple nodes publish - at the same time. - endmenu # Access layer menu "Models" diff --git a/subsys/bluetooth/mesh/access.c b/subsys/bluetooth/mesh/access.c index c3ef6a40554..4cffe064329 100644 --- a/subsys/bluetooth/mesh/access.c +++ b/subsys/bluetooth/mesh/access.c @@ -33,11 +33,6 @@ #include LOG_MODULE_REGISTER(bt_mesh_access); -/* 20 - 50ms */ -#define RANDOM_DELAY_SHORT 30 -/* 20 - 500ms */ -#define RANDOM_DELAY_LONG 480 - /* Model publication information for persistent storage. */ struct mod_pub_val { struct { @@ -766,16 +761,8 @@ static int32_t next_period(const struct bt_mesh_model *mod) if (period && elapsed >= period) { LOG_WRN("Retransmission interval is too short"); - - if (!!pub->delayable) { - LOG_WRN("Publication period is too short for" - " retransmissions"); - } - - /* Keep retransmitting the message with the interval sacrificing the - * next publication period start. - */ - return BT_MESH_PUB_TRANSMIT_INT(mod->pub->retransmit); + /* Return smallest positive number since 0 means disabled */ + return 1; } } @@ -788,11 +775,6 @@ static int32_t next_period(const struct bt_mesh_model *mod) if (elapsed >= period) { LOG_WRN("Publication sending took longer than the period"); - - if (!!pub->delayable) { - LOG_WRN("Publication period is too short to be delayable"); - } - /* Return smallest positive number since 0 means disabled */ return 1; } @@ -873,39 +855,6 @@ static int pub_period_start(struct bt_mesh_model_pub *pub) return 0; } -static uint16_t pub_delay_get(int random_delay_window) -{ - if (!IS_ENABLED(CONFIG_BT_MESH_DELAYABLE_PUBLICATION)) { - return 0; - } - - uint16_t num = 0; - - (void)bt_rand(&num, sizeof(num)); - - return 20 + (num % random_delay_window); -} - -static int pub_delay_schedule(struct bt_mesh_model_pub *pub, int delay) -{ - uint16_t random; - int err; - - if (!IS_ENABLED(CONFIG_BT_MESH_DELAYABLE_PUBLICATION)) { - return -ENOTSUP; - } - - random = pub_delay_get(delay); - err = k_work_reschedule(&pub->timer, K_MSEC(random)); - if (err < 0) { - LOG_ERR("Unable to delay publication (err %d)", err); - return err; - } - - LOG_DBG("Publication delayed by %dms", random); - return 0; -} - static void mod_publish(struct k_work *work) { struct k_work_delayable *dwork = k_work_delayable_from_work(work); @@ -941,13 +890,6 @@ static void mod_publish(struct k_work *work) if (err) { return; } - - /* Delay the first publication in a period. */ - if (!!pub->delayable && !pub_delay_schedule(pub, RANDOM_DELAY_SHORT)) { - /* Increment count as it would do BT_MESH_PUB_MSG_TOTAL */ - pub->count++; - return; - } } err = publish_transmit(pub->mod); @@ -1622,18 +1564,6 @@ int bt_mesh_model_publish(const struct bt_mesh_model *model) LOG_DBG("Publish Retransmit Count %u Interval %ums", pub->count, BT_MESH_PUB_TRANSMIT_INT(pub->retransmit)); - /* Delay the publication for longer time when the publication is triggered manually (section - * 3.7.3.1): - * - * When the publication of a message is the result of a power-up, a state transition - * progress update, or completion of a state transition, multiple nodes may be reporting the - * state change at the same time. To reduce the probability of a message collision, these - * messages should be sent with a random delay between 20 and 500 milliseconds. - */ - if (!!pub->delayable && !pub_delay_schedule(pub, RANDOM_DELAY_LONG)) { - return 0; - } - k_work_reschedule(&pub->timer, K_NO_WAIT); return 0; @@ -2638,21 +2568,8 @@ static void commit_mod(const struct bt_mesh_model *mod, const struct bt_mesh_ele int32_t ms = bt_mesh_model_pub_period_get(mod); if (ms > 0) { - /* Delay the first publication after power-up for longer time (section - * 3.7.3.1): - * - * When the publication of a message is the result of a power-up, a state - * transition progress update, or completion of a state transition, multiple - * nodes may be reporting the state change at the same time. To reduce the - * probability of a message collision, these messages should be sent with a - * random delay between 20 and 500 milliseconds. - */ - uint16_t random; - - random = !!mod->pub->delayable ? pub_delay_get(RANDOM_DELAY_LONG) : 0; - - LOG_DBG("Starting publish timer (period %u ms, delay %u ms)", ms, random); - k_work_schedule(&mod->pub->timer, K_MSEC(ms + random)); + LOG_DBG("Starting publish timer (period %u ms)", ms); + k_work_schedule(&mod->pub->timer, K_MSEC(ms)); } } diff --git a/tests/bsim/bluetooth/mesh/src/test_access.c b/tests/bsim/bluetooth/mesh/src/test_access.c index 5cb7d2e28e1..b8b10fd7634 100644 --- a/tests/bsim/bluetooth/mesh/src/test_access.c +++ b/tests/bsim/bluetooth/mesh/src/test_access.c @@ -60,7 +60,6 @@ static const struct { uint8_t div; int32_t period_ms; } test_period[] = { - { BT_MESH_PUB_PERIOD_100MS(1), 0, 100 }, { BT_MESH_PUB_PERIOD_100MS(5), 0, 500 }, { BT_MESH_PUB_PERIOD_SEC(2), 0, 2000 }, { BT_MESH_PUB_PERIOD_10SEC(1), 0, 10000 }, @@ -523,91 +522,6 @@ static void msgf_publish(void) bt_mesh_model_publish(model); } -static void pub_delayable_check(int32_t interval, uint8_t count) -{ - int64_t timestamp = k_uptime_get(); - int err; - - for (size_t j = 0; j < count; j++) { - /* Every new publication will release semaphore in the update handler and the time - * between two consecutive publications will be measured. - */ - err = k_sem_take(&publish_sem, K_SECONDS(20)); - if (err) { - FAIL("Send timed out"); - } - - int32_t time_delta = k_uptime_delta(×tamp); - int32_t pub_delta = time_delta - interval; - - LOG_DBG("Send time: %d delta: %d pub_delta: %d", (int32_t)timestamp, time_delta, - pub_delta); - - if (j == 0) { - /* The first delta will be between the messages published manually and next - * publication (or retransmission). So the time difference should not be - * longer than 500 - 20 + 10 (margin): - * - * |---|-------|--------|-------|----> - * M1 20ms tx(M1) 500ms - * update() - */ - ASSERT_IN_RANGE(pub_delta, 0, 510); - } else { - /* Time difference between the consequtive update callback calls should be - * within a small margin like without random delay as the callbacks should - * be called at the regular interval or immediately (if it passed the next - * period time). - */ - ASSERT_IN_RANGE(pub_delta, 0, 10); - } - } -} - -static void recv_delayable_check(int32_t interval, uint8_t count) -{ - int64_t timestamp; - int err; - - /* The measurement starts by the first received message. */ - err = k_sem_take(&publish_sem, K_SECONDS(20)); - if (err) { - FAIL("Recv timed out"); - } - - timestamp = k_uptime_get(); - - for (size_t j = 0; j < count; j++) { - /* Every new received message will release semaphore in the message handler and - * the time between two consecutive publications will be measured. - */ - err = k_sem_take(&publish_sem, K_SECONDS(20)); - if (err) { - FAIL("Recv timed out"); - } - - int32_t time_delta = k_uptime_delta(×tamp); - /* First message can be delayed up to 500ms, others for up to 50ms. */ - int32_t upper_delay = j == 0 ? 500 : 50; - - /* - * Lower boundary: tx2 - tx1 + interval - * |---|-------|---------------|-------|-----> - * M1 tx1(50ms/500ms) M2 tx2(20ms) - * - * Upper boundary: tx2 - tx1 + interval - * |---|-------|--------|-----------|-----> - * M1 tx1(20ms) M2 tx2(50ms/500ms) - */ - int32_t lower_boundary = 20 - upper_delay + interval; - int32_t upper_boundary = upper_delay - 20 + interval; - - LOG_DBG("Recv time: %d delta: %d boundaries: %d/%d", (int32_t)timestamp, time_delta, - lower_boundary, upper_boundary); - ASSERT_IN_RANGE(time_delta, lower_boundary, upper_boundary + RX_JITTER_MAX); - } -} - static void pub_jitter_check(int32_t interval, uint8_t count) { int64_t timestamp = k_uptime_get(); @@ -664,8 +578,8 @@ static void recv_jitter_check(int32_t interval, uint8_t count) jitter = MAX(pub_delta, jitter); - LOG_DBG("Recv time: %d delta: %d jitter: %d, j: %d", (int32_t)timestamp, time_delta, - jitter, j); + LOG_DBG("Recv time: %d delta: %d jitter: %d", (int32_t)timestamp, time_delta, + jitter); } LOG_INF("Recv jitter: %d", jitter); @@ -675,19 +589,17 @@ static void recv_jitter_check(int32_t interval, uint8_t count) /* Test publish period states by publishing a message and checking interval between update handler * calls. */ -static void tx_period(bool delayable) +static void test_tx_period(void) { const struct bt_mesh_model *model = &models[2]; - bt_mesh_test_cfg_set(NULL, 70); + bt_mesh_test_cfg_set(NULL, 60); bt_mesh_device_setup(&prov, &local_comp); provision(UNICAST_ADDR1); common_configure(UNICAST_ADDR1); k_sem_init(&publish_sem, 0, 1); - model->pub->delayable = delayable; - for (size_t i = 0; i < ARRAY_SIZE(test_period); i++) { pub_param_set(test_period[i].period, 0); @@ -699,11 +611,7 @@ static void tx_period(bool delayable) /* Start publishing messages and measure jitter. */ msgf_publish(); publish_allow = true; - if (delayable) { - pub_delayable_check(test_period[i].period_ms, PUB_PERIOD_COUNT); - } else { - pub_jitter_check(test_period[i].period_ms, PUB_PERIOD_COUNT); - } + pub_jitter_check(test_period[i].period_ms, PUB_PERIOD_COUNT); /* Disable periodic publication before the next test iteration. */ publish_allow = false; @@ -718,9 +626,9 @@ static void tx_period(bool delayable) /* Receive a periodically published message and check publication period by measuring interval * between message handler calls. */ -static void rx_period(bool delayable) +static void test_rx_period(void) { - bt_mesh_test_cfg_set(NULL, 70); + bt_mesh_test_cfg_set(NULL, 60); bt_mesh_device_setup(&prov, &local_comp); provision(UNICAST_ADDR2); common_configure(UNICAST_ADDR2); @@ -728,40 +636,16 @@ static void rx_period(bool delayable) k_sem_init(&publish_sem, 0, 1); for (size_t i = 0; i < ARRAY_SIZE(test_period); i++) { - if (delayable) { - recv_delayable_check(test_period[i].period_ms, PUB_PERIOD_COUNT); - } else { - recv_jitter_check(test_period[i].period_ms, PUB_PERIOD_COUNT); - } + recv_jitter_check(test_period[i].period_ms, PUB_PERIOD_COUNT); } PASS(); } -static void test_tx_period(void) -{ - tx_period(false); -} - -static void test_rx_period(void) -{ - rx_period(false); -} - -static void test_tx_period_delayable(void) -{ - tx_period(true); -} - -static void test_rx_period_delayable(void) -{ - rx_period(true); -} - /* Test publish retransmit interval and count states by publishing a message and checking interval * between update handler calls. */ -static void tx_transmit(bool delayable) +static void test_tx_transmit(void) { const struct bt_mesh_model *model = &models[2]; uint8_t status; @@ -788,7 +672,6 @@ static void tx_transmit(bool delayable) publish_allow = true; model->pub->retr_update = true; - model->pub->delayable = delayable; for (size_t i = 0; i < ARRAY_SIZE(test_transmit); i++) { pub_param_set(0, test_transmit[i]); @@ -800,11 +683,7 @@ static void tx_transmit(bool delayable) /* Start publishing messages and measure jitter. */ msgf_publish(); - if (delayable) { - pub_delayable_check(interval, count); - } else { - pub_jitter_check(interval, count); - } + pub_jitter_check(interval, count); /* Let the receiver hit the first semaphore. */ k_sleep(K_SECONDS(1)); @@ -816,7 +695,7 @@ static void tx_transmit(bool delayable) /* Receive a published message and check retransmission interval by measuring interval between * message handler calls. */ -static void rx_transmit(bool delayable) +static void test_rx_transmit(void) { bt_mesh_test_cfg_set(NULL, 60); bt_mesh_device_setup(&prov, &local_comp); @@ -829,36 +708,12 @@ static void rx_transmit(bool delayable) int32_t interval = BT_MESH_PUB_TRANSMIT_INT(test_transmit[i]); int count = BT_MESH_PUB_TRANSMIT_COUNT(test_transmit[i]); - if (delayable) { - recv_delayable_check(interval, count); - } else { - recv_jitter_check(interval, count); - } + recv_jitter_check(interval, count); } PASS(); } -static void test_tx_transmit(void) -{ - tx_transmit(false); -} - -static void test_rx_transmit(void) -{ - rx_transmit(false); -} - -static void test_tx_transmit_delayable(void) -{ - tx_transmit(true); -} - -static void test_rx_transmit_delayable(void) -{ - rx_transmit(true); -} - /* Cancel one of messages to be published and check that the next one is published when next period * starts. */ @@ -986,13 +841,6 @@ static const struct bst_test_instance test_access[] = { TEST_CASE(tx, cancel, "Access: Cancel a message during publication"), TEST_CASE(rx, cancel, "Access: Receive published messages except cancelled"), - TEST_CASE(tx, period_delayable, "Access: Test delayable periodic publication"), - TEST_CASE(rx, period_delayable, "Access: Receive delayable periodic publication"), - - TEST_CASE(tx, transmit_delayable, "Access: Test delayable publication with retransmission"), - TEST_CASE(rx, transmit_delayable, "Access: Receive delayable publication with" - " retransmissions"), - BSTEST_END_MARKER }; diff --git a/tests/bsim/bluetooth/mesh/tests_scripts/access/access_period_delayable.sh b/tests/bsim/bluetooth/mesh/tests_scripts/access/access_period_delayable.sh deleted file mode 100755 index 5ecd4a061de..00000000000 --- a/tests/bsim/bluetooth/mesh/tests_scripts/access/access_period_delayable.sh +++ /dev/null @@ -1,17 +0,0 @@ -#!/usr/bin/env bash -# Copyright 2023 Nordic Semiconductor -# SPDX-License-Identifier: Apache-2.0 - -source $(dirname "${BASH_SOURCE[0]}")/../../_mesh_test.sh - -RunTest mesh_access_pub_period_delayable_retr \ - access_tx_period_delayable access_rx_period_delayable - -conf=prj_mesh1d1_conf -RunTest mesh_access_pub_period_delayable_retr_1d1 \ - access_tx_period_delayable access_rx_period_delayable - -conf=prj_mesh1d1_conf -overlay=overlay_psa_conf -RunTest mesh_access_pub_period_delayable_retr_psa \ - access_tx_period_delayable access_rx_period_delayable diff --git a/tests/bsim/bluetooth/mesh/tests_scripts/access/access_transmit_delayable.sh b/tests/bsim/bluetooth/mesh/tests_scripts/access/access_transmit_delayable.sh deleted file mode 100755 index 1622ac49f06..00000000000 --- a/tests/bsim/bluetooth/mesh/tests_scripts/access/access_transmit_delayable.sh +++ /dev/null @@ -1,17 +0,0 @@ -#!/usr/bin/env bash -# Copyright 2023 Nordic Semiconductor -# SPDX-License-Identifier: Apache-2.0 - -source $(dirname "${BASH_SOURCE[0]}")/../../_mesh_test.sh - -RunTest mesh_access_pub_transmit_delayable_retr \ - access_tx_transmit_delayable access_rx_transmit_delayable - -conf=prj_mesh1d1_conf -RunTest mesh_access_pub_transmit_delayable_retr_1d1 \ - access_tx_transmit_delayable access_rx_transmit_delayable - -conf=prj_mesh1d1_conf -overlay=overlay_psa_conf -RunTest mesh_access_pub_transmit_delayable_retr_psa \ - access_tx_period_delayable access_rx_period_delayable From dbe7aefedf30d0c0adbe16e645fb397b3c105ea8 Mon Sep 17 00:00:00 2001 From: Robert Lubos Date: Tue, 6 Feb 2024 11:07:20 +0100 Subject: [PATCH 3606/3723] Revert "[nrf fromtree] Bluetooth: Mesh: Rename prov_dev->provisionee" This reverts commit 7184e98ff549316a48c49f19b24d8e07472bfd1f. Signed-off-by: Robert Lubos --- doc/connectivity/bluetooth/api/mesh/shell.rst | 4 +- doc/releases/migration-guide-3.6.rst | 25 ++----- samples/bluetooth/mesh_provisioner/prj.conf | 2 +- subsys/bluetooth/Kconfig.logging | 2 +- subsys/bluetooth/mesh/CMakeLists.txt | 2 +- subsys/bluetooth/mesh/Kconfig | 15 +--- .../mesh/{provisionee.c => prov_device.c} | 8 +-- subsys/bluetooth/mesh/provisioner.c | 72 +++++++++---------- subsys/bluetooth/mesh/shell/shell.c | 8 +-- tests/bsim/bluetooth/mesh/prj.conf | 2 +- tests/bsim/bluetooth/mesh/prj_mesh1d1.conf | 2 +- 11 files changed, 61 insertions(+), 81 deletions(-) rename subsys/bluetooth/mesh/{provisionee.c => prov_device.c} (99%) diff --git a/doc/connectivity/bluetooth/api/mesh/shell.rst b/doc/connectivity/bluetooth/api/mesh/shell.rst index 3d925f29a3e..9d5829fe380 100644 --- a/doc/connectivity/bluetooth/api/mesh/shell.rst +++ b/doc/connectivity/bluetooth/api/mesh/shell.rst @@ -282,7 +282,7 @@ Provisioning ============ To allow a device to broadcast connectable unprovisioned beacons, the -:kconfig:option:`CONFIG_BT_MESH_PROVISIONEE` configuration option must be enabled, along with the +:kconfig:option:`CONFIG_BT_MESH_PROV_DEVICE` configuration option must be enabled, along with the :kconfig:option:`CONFIG_BT_MESH_PB_GATT` option. ``mesh prov pb-gatt `` @@ -295,7 +295,7 @@ To allow a device to broadcast connectable unprovisioned beacons, the * ``Val``: Enable or disable provisioning with GATT To allow a device to broadcast unprovisioned beacons, the -:kconfig:option:`CONFIG_BT_MESH_PROVISIONEE` configuration option must be enabled, along with the +:kconfig:option:`CONFIG_BT_MESH_PROV_DEVICE` configuration option must be enabled, along with the :kconfig:option:`CONFIG_BT_MESH_PB_ADV` option. ``mesh prov pb-adv `` diff --git a/doc/releases/migration-guide-3.6.rst b/doc/releases/migration-guide-3.6.rst index c1739adf74d..c4b93e5f150 100644 --- a/doc/releases/migration-guide-3.6.rst +++ b/doc/releases/migration-guide-3.6.rst @@ -113,24 +113,13 @@ Bluetooth cleared on :c:func:`bt_enable`. Callbacks can now be registered before the initial call to :c:func:`bt_enable`, and should no longer be re-registered after a :c:func:`bt_disable` :c:func:`bt_enable` cycle. (:github:`63693`) -* The Bluetooth UUID has been modified to rodata in ``BT_UUID_DECLARE_16``, ``BT_UUID_DECLARE_32` - and ``BT_UUID_DECLARE_128`` as the return value has been changed to `const`. - Any pointer to a UUID must be prefixed with `const`, otherwise there will be a compilation warning. - For example change ``struct bt_uuid *uuid = BT_UUID_DECLARE_16(xx)`` to - ``const struct bt_uuid *uuid = BT_UUID_DECLARE_16(xx)``. (:github:`66136`) - -* Mesh - - * The Bluetooth Mesh ``model`` declaration has been changed to add prefix ``const``. - The ``model->user_data``, ``model->elem_idx`` and ``model->mod_idx`` field has been changed to - the new runtime structure, replaced by ``model->rt->user_data``, ``model->rt->elem_idx`` and - ``model->rt->mod_idx`` separately. (:github:`65152`) - * The Bluetooth Mesh ``element`` declaration has been changed to add prefix ``const``. - The ``elem->addr`` field has been changed to the new runtime structure, replaced by - ``elem->rt->addr``. (:github:`65388`) - * Deprecated :kconfig:option:`CONFIG_BT_MESH_PROV_DEVICE`. This option is - replaced by new option :kconfig:option:`CONFIG_BT_MESH_PROVISIONEE` to - be aligned with Mesh Protocol Specification v1.1, section 5.4. (:github:`64252`) +* The Bluetooth Mesh ``model`` declaration has been changed to add prefix ``const``. + The ``model->user_data``, ``model->elem_idx`` and ``model->mod_idx`` field has been changed to + the new runtime structure, replaced by ``model->rt->user_data``, ``model->rt->elem_idx`` and + ``model->rt->mod_idx`` separately. (:github:`65152`) +* The Bluetooth Mesh ``element`` declaration has been changed to add prefix ``const``. + The ``elem->addr`` field has been changed to the new runtime structure, replaced by + ``elem->rt->addr``. (:github:`65388`) LoRaWAN ======= diff --git a/samples/bluetooth/mesh_provisioner/prj.conf b/samples/bluetooth/mesh_provisioner/prj.conf index 341dd49ed2e..bfc6d5a1241 100644 --- a/samples/bluetooth/mesh_provisioner/prj.conf +++ b/samples/bluetooth/mesh_provisioner/prj.conf @@ -33,7 +33,7 @@ CONFIG_BT_MESH_RELAY=y CONFIG_BT_MESH_RELAY_RETRANSMIT_COUNT=3 CONFIG_BT_MESH_PROVISIONER=y -CONFIG_BT_MESH_PROVISIONEE=n +CONFIG_BT_MESH_PROV_DEVICE=n CONFIG_BT_MESH_CDB=y CONFIG_BT_MESH_CDB_NODE_COUNT=16 CONFIG_BT_MESH_CDB_SUBNET_COUNT=3 diff --git a/subsys/bluetooth/Kconfig.logging b/subsys/bluetooth/Kconfig.logging index b6505f6e53a..6d8b999e03c 100644 --- a/subsys/bluetooth/Kconfig.logging +++ b/subsys/bluetooth/Kconfig.logging @@ -1002,7 +1002,7 @@ legacy-debug-sym = BT_MESH_DEBUG_PROVISIONER module-str = "Provisioner" source "subsys/bluetooth/common/Kconfig.template.log_config_bt" -module = BT_MESH_PROVISIONEE +module = BT_MESH_PROV_DEVICE legacy-debug-sym = BT_MESH_DEBUG_PROV_DEVICE module-str = "Provisioning device" source "subsys/bluetooth/common/Kconfig.template.log_config_bt" diff --git a/subsys/bluetooth/mesh/CMakeLists.txt b/subsys/bluetooth/mesh/CMakeLists.txt index fe4444b28ab..3fd2e7c3bfc 100644 --- a/subsys/bluetooth/mesh/CMakeLists.txt +++ b/subsys/bluetooth/mesh/CMakeLists.txt @@ -40,7 +40,7 @@ zephyr_library_sources_ifdef(CONFIG_BT_MESH_FRIEND friend.c) zephyr_library_sources_ifdef(CONFIG_BT_MESH_PROV prov.c) -zephyr_library_sources_ifdef(CONFIG_BT_MESH_PROVISIONEE provisionee.c) +zephyr_library_sources_ifdef(CONFIG_BT_MESH_PROV_DEVICE prov_device.c) zephyr_library_sources_ifdef(CONFIG_BT_MESH_PROVISIONER provisioner.c) diff --git a/subsys/bluetooth/mesh/Kconfig b/subsys/bluetooth/mesh/Kconfig index bffbac3e8e7..3bc7dd2940f 100644 --- a/subsys/bluetooth/mesh/Kconfig +++ b/subsys/bluetooth/mesh/Kconfig @@ -240,7 +240,7 @@ config BT_MESH_PB_GATT select BT_MESH_GATT_SERVER select BT_MESH_PROV select BT_MESH_PB_GATT_COMMON - select BT_MESH_PROVISIONEE + select BT_MESH_PROV_DEVICE help Enable this option to allow the device to be provisioned over GATT. @@ -268,16 +268,7 @@ config BT_MESH_PB_GATT_CLIENT endif # BT_CONN config BT_MESH_PROV_DEVICE - bool "[DEPRECATED] Provisioning device role support" - select DEPRECATED - select BT_MESH_PROVISIONEE - help - Enable this option to allow the device to be provisioned into a mesh network. - The option is marked as deprecated and will be replaced by BT_MESH_PROVISIONEE - option. - -config BT_MESH_PROVISIONEE - bool "Provisionee role support" + bool "Provisioning device role support" depends on BT_MESH_PB_ADV || BT_MESH_PB_GATT default y help @@ -285,7 +276,7 @@ config BT_MESH_PROVISIONEE config BT_MESH_PROV_OOB_PUBLIC_KEY bool "OOB Public key support" - depends on BT_MESH_PROVISIONEE + depends on BT_MESH_PROV_DEVICE help Enable this option if public key is to be exchanged via Out of Band (OOB) technology. diff --git a/subsys/bluetooth/mesh/provisionee.c b/subsys/bluetooth/mesh/prov_device.c similarity index 99% rename from subsys/bluetooth/mesh/provisionee.c rename to subsys/bluetooth/mesh/prov_device.c index dcecb5838f0..6ca65c2ec63 100644 --- a/subsys/bluetooth/mesh/provisionee.c +++ b/subsys/bluetooth/mesh/prov_device.c @@ -32,9 +32,9 @@ #include "settings.h" #include "rpr.h" -#define LOG_LEVEL CONFIG_BT_MESH_PROVISIONEE_LOG_LEVEL +#define LOG_LEVEL CONFIG_BT_MESH_PROV_DEVICE_LOG_LEVEL #include -LOG_MODULE_REGISTER(bt_mesh_provisionee); +LOG_MODULE_REGISTER(bt_mesh_prov_device); static void reprovision_fail(void); @@ -696,8 +696,8 @@ int bt_mesh_prov_enable(bt_mesh_prov_bearer_t bearers) return -EALREADY; } -#if defined(CONFIG_BT_MESH_PROVISIONEE_LOG_LEVEL) - if (CONFIG_BT_MESH_PROVISIONEE_LOG_LEVEL > 2) { +#if defined(CONFIG_BT_MESH_PROV_DEVICE_LOG_LEVEL) + if (CONFIG_BT_MESH_PROV_DEVICE_LOG_LEVEL > 2) { struct bt_uuid_128 uuid = { .uuid = { BT_UUID_TYPE_128 } }; sys_memcpy_swap(uuid.val, bt_mesh_prov->uuid, 16); diff --git a/subsys/bluetooth/mesh/provisioner.c b/subsys/bluetooth/mesh/provisioner.c index 08b3f8bb8f1..ba02723e830 100644 --- a/subsys/bluetooth/mesh/provisioner.c +++ b/subsys/bluetooth/mesh/provisioner.c @@ -46,7 +46,7 @@ static struct { uint8_t attention_duration; uint8_t uuid[16]; uint8_t new_dev_key[16]; -} provisionee; +} prov_device; static void send_pub_key(void); static void prov_dh_key_gen(void); @@ -54,8 +54,8 @@ static void prov_dh_key_gen(void); static int reset_state(void) { if (!atomic_test_bit(bt_mesh_prov_link.flags, REPROVISION) && - provisionee.node != NULL) { - bt_mesh_cdb_node_del(provisionee.node, false); + prov_device.node != NULL) { + bt_mesh_cdb_node_del(prov_device.node, false); } return bt_mesh_prov_reset_state(); @@ -86,9 +86,9 @@ static void send_invite(void) LOG_DBG(""); bt_mesh_prov_buf_init(&inv, PROV_INVITE); - net_buf_simple_add_u8(&inv, provisionee.attention_duration); + net_buf_simple_add_u8(&inv, prov_device.attention_duration); - memcpy(bt_mesh_prov_link.conf_inputs.invite, &provisionee.attention_duration, + memcpy(bt_mesh_prov_link.conf_inputs.invite, &prov_device.attention_duration, PDU_LEN_INVITE); if (bt_mesh_prov_send(&inv, NULL)) { @@ -246,8 +246,8 @@ static void prov_capabilities(const uint8_t *data) LOG_DBG("Input OOB Size: %u", caps.input_size); LOG_DBG("Input OOB Action: 0x%04x", caps.input_actions); - provisionee.elem_count = caps.elem_count; - if (provisionee.elem_count == 0) { + prov_device.elem_count = caps.elem_count; + if (prov_device.elem_count == 0) { LOG_ERR("Invalid number of elements"); prov_fail(PROV_ERR_NVAL_FMT); return; @@ -271,7 +271,7 @@ static void prov_capabilities(const uint8_t *data) if (atomic_test_bit(bt_mesh_prov_link.flags, REPROVISION)) { if (!bt_mesh_prov_link.addr) { bt_mesh_prov_link.addr = bt_mesh_cdb_free_addr_get( - provisionee.elem_count); + prov_device.elem_count); if (!bt_mesh_prov_link.addr) { LOG_ERR("Failed allocating address for node"); prov_fail(PROV_ERR_ADDR); @@ -279,19 +279,19 @@ static void prov_capabilities(const uint8_t *data) } } } else { - provisionee.node = - bt_mesh_cdb_node_alloc(provisionee.uuid, + prov_device.node = + bt_mesh_cdb_node_alloc(prov_device.uuid, bt_mesh_prov_link.addr, - provisionee.elem_count, - provisionee.net_idx); - if (provisionee.node == NULL) { + prov_device.elem_count, + prov_device.net_idx); + if (prov_device.node == NULL) { LOG_ERR("Failed allocating node 0x%04x", bt_mesh_prov_link.addr); prov_fail(PROV_ERR_RESOURCES); return; } /* Address might change in the alloc call */ - bt_mesh_prov_link.addr = provisionee.node->addr; + bt_mesh_prov_link.addr = prov_device.node->addr; } memcpy(bt_mesh_prov_link.conf_inputs.capabilities, data, PDU_LEN_CAPABILITIES); @@ -517,16 +517,16 @@ static void send_prov_data(void) LOG_DBG("Nonce: %s", bt_hex(nonce, 13)); err = bt_mesh_dev_key(bt_mesh_prov_link.dhkey, - bt_mesh_prov_link.prov_salt, provisionee.new_dev_key); + bt_mesh_prov_link.prov_salt, prov_device.new_dev_key); if (err) { LOG_ERR("Unable to generate device key"); prov_fail(PROV_ERR_UNEXP_ERR); goto session_key_destructor; } - sub = bt_mesh_cdb_subnet_get(provisionee.node->net_idx); + sub = bt_mesh_cdb_subnet_get(prov_device.node->net_idx); if (sub == NULL) { - LOG_ERR("No subnet with net_idx %u", provisionee.node->net_idx); + LOG_ERR("No subnet with net_idx %u", prov_device.node->net_idx); prov_fail(PROV_ERR_UNEXP_ERR); goto session_key_destructor; } @@ -540,14 +540,14 @@ static void send_prov_data(void) bt_mesh_prov_buf_init(&pdu, PROV_DATA); net_buf_simple_add_mem(&pdu, net_key, sizeof(net_key)); - net_buf_simple_add_be16(&pdu, provisionee.node->net_idx); + net_buf_simple_add_be16(&pdu, prov_device.node->net_idx); net_buf_simple_add_u8(&pdu, bt_mesh_cdb_subnet_flags(sub)); net_buf_simple_add_be32(&pdu, bt_mesh_cdb.iv_index); net_buf_simple_add_be16(&pdu, bt_mesh_prov_link.addr); net_buf_simple_add(&pdu, 8); /* For MIC */ LOG_DBG("net_idx %u, iv_index 0x%08x, addr 0x%04x", - provisionee.node->net_idx, bt_mesh.iv_index, + prov_device.node->net_idx, bt_mesh.iv_index, bt_mesh_prov_link.addr); err = bt_mesh_prov_encrypt(&session_key, nonce, &pdu.data[1], @@ -571,10 +571,10 @@ static void send_prov_data(void) static void prov_complete(const uint8_t *data) { - struct bt_mesh_cdb_node *node = provisionee.node; + struct bt_mesh_cdb_node *node = prov_device.node; LOG_DBG("key %s, net_idx %u, num_elem %u, addr 0x%04x", - bt_hex(&provisionee.new_dev_key, 16), node->net_idx, + bt_hex(&prov_device.new_dev_key, 16), node->net_idx, node->num_elem, node->addr); bt_mesh_prov_link.expect = PROV_NO_PDU; @@ -586,15 +586,15 @@ static void prov_complete(const uint8_t *data) static void prov_node_add(void) { LOG_DBG(""); - struct bt_mesh_cdb_node *node = provisionee.node; + struct bt_mesh_cdb_node *node = prov_device.node; int err; if (atomic_test_bit(bt_mesh_prov_link.flags, REPROVISION)) { bt_mesh_cdb_node_update(node, bt_mesh_prov_link.addr, - provisionee.elem_count); + prov_device.elem_count); } - err = bt_mesh_cdb_node_key_import(node, provisionee.new_dev_key); + err = bt_mesh_cdb_node_key_import(node, prov_device.new_dev_key); if (err) { LOG_ERR("Failed to import node device key"); return; @@ -604,7 +604,7 @@ static void prov_node_add(void) bt_mesh_cdb_node_store(node); } - provisionee.node = NULL; + prov_device.node = NULL; if (bt_mesh_prov->node_added) { bt_mesh_prov->node_added(node->net_idx, node->uuid, node->addr, @@ -807,7 +807,7 @@ static int link_open(const uint8_t *uuid, const struct prov_bearer *bearer, } if (uuid) { - memcpy(provisionee.uuid, uuid, 16); + memcpy(prov_device.uuid, uuid, 16); struct bt_uuid_128 uuid_repr = { .uuid = { BT_UUID_TYPE_128 } }; @@ -823,8 +823,8 @@ static int link_open(const uint8_t *uuid, const struct prov_bearer *bearer, bt_mesh_prov_link.addr = addr; bt_mesh_prov_link.bearer = bearer; bt_mesh_prov_link.role = &role_provisioner; - provisionee.net_idx = net_idx; - provisionee.attention_duration = attention_duration; + prov_device.net_idx = net_idx; + prov_device.attention_duration = attention_duration; err = bt_mesh_prov_link.bearer->link_open( uuid, timeout, bt_mesh_prov_bearer_cb_get(), bearer_cb_data); @@ -877,15 +877,15 @@ static int reprovision_local_client_server(uint16_t addr) } LOG_DBG("net_idx %u iv_index 0x%08x, addr 0x%04x", - provisionee.node->net_idx, bt_mesh_cdb.iv_index, addr); + prov_device.node->net_idx, bt_mesh_cdb.iv_index, addr); atomic_set_bit(bt_mesh_prov_link.flags, REPROVISION); atomic_set_bit(bt_mesh_prov_link.flags, PROVISIONER); bt_mesh_prov_link.addr = addr; bt_mesh_prov_link.bearer = &pb_remote_cli; bt_mesh_prov_link.role = &role_provisioner; - provisionee.net_idx = provisionee.node->net_idx; - provisionee.attention_duration = 0; + prov_device.net_idx = prov_device.node->net_idx; + prov_device.attention_duration = 0; if (IS_ENABLED(CONFIG_BT_MESH_PROV_OOB_PUBLIC_KEY) && bt_mesh_prov->public_key_be && bt_mesh_prov->private_key_be) { @@ -908,13 +908,13 @@ static int reprovision_local_client_server(uint16_t addr) LOG_DBG("DHkey: %s", bt_hex(bt_mesh_prov_link.dhkey, DH_KEY_SIZE)); err = bt_mesh_dev_key(bt_mesh_prov_link.dhkey, - bt_mesh_prov_link.prov_salt, provisionee.new_dev_key); + bt_mesh_prov_link.prov_salt, prov_device.new_dev_key); if (err) { LOG_ERR("Unable to generate device key"); return err; } - bt_mesh_dev_key_cand(provisionee.new_dev_key); + bt_mesh_dev_key_cand(prov_device.new_dev_key); /* Mark the link that was never opened as closed. */ atomic_set_bit(bt_mesh_prov_link.flags, COMPLETE); bt_mesh_reprovision(addr); @@ -943,8 +943,8 @@ int bt_mesh_pb_remote_open_node(struct bt_mesh_rpr_cli *cli, ctx.refresh = BT_MESH_RPR_NODE_REFRESH_DEVKEY; } - provisionee.node = bt_mesh_cdb_node_get(srv->addr); - if (!provisionee.node) { + prov_device.node = bt_mesh_cdb_node_get(srv->addr); + if (!prov_device.node) { LOG_ERR("No CDB node for 0x%04x", srv->addr); return -ENOENT; } @@ -954,7 +954,7 @@ int bt_mesh_pb_remote_open_node(struct bt_mesh_rpr_cli *cli, return reprovision_local_client_server(addr); } - return link_open(NULL, &pb_remote_cli, provisionee.node->net_idx, addr, + return link_open(NULL, &pb_remote_cli, prov_device.node->net_idx, addr, 0, &ctx, 0); } #endif diff --git a/subsys/bluetooth/mesh/shell/shell.c b/subsys/bluetooth/mesh/shell/shell.c index 9a0e5ece5e3..bb9892eb355 100644 --- a/subsys/bluetooth/mesh/shell/shell.c +++ b/subsys/bluetooth/mesh/shell/shell.c @@ -771,7 +771,7 @@ static int cmd_provision_gatt(const struct shell *sh, size_t argc, } #endif /* CONFIG_BT_MESH_PB_GATT_CLIENT */ -#if defined(CONFIG_BT_MESH_PROVISIONEE) +#if defined(CONFIG_BT_MESH_PROV_DEVICE) static int cmd_pb(bt_mesh_prov_bearer_t bearer, const struct shell *sh, size_t argc, char *argv[]) { @@ -822,7 +822,7 @@ static int cmd_pb_gatt(const struct shell *sh, size_t argc, char *argv[]) return cmd_pb(BT_MESH_PROV_GATT, sh, argc, argv); } #endif /* CONFIG_BT_MESH_PB_GATT */ -#endif /* CONFIG_BT_MESH_PROVISIONEE */ +#endif /* CONFIG_BT_MESH_PROV_DEVICE */ #if defined(CONFIG_BT_MESH_PROVISIONER) static int cmd_remote_pub_key_set(const struct shell *sh, size_t argc, char *argv[]) @@ -1681,14 +1681,14 @@ SHELL_STATIC_SUBCMD_SET_CREATE( SHELL_CMD_ARG(comp-change, NULL, NULL, cmd_comp_change, 1, 0), /* Provisioning operations */ -#if defined(CONFIG_BT_MESH_PROVISIONEE) +#if defined(CONFIG_BT_MESH_PROV_DEVICE) #if defined(CONFIG_BT_MESH_PB_GATT) SHELL_CMD_ARG(pb-gatt, NULL, "", cmd_pb_gatt, 2, 0), #endif #if defined(CONFIG_BT_MESH_PB_ADV) SHELL_CMD_ARG(pb-adv, NULL, "", cmd_pb_adv, 2, 0), #endif -#endif /* CONFIG_BT_MESH_PROVISIONEE */ +#endif /* CONFIG_BT_MESH_PROV_DEVICE */ #if defined(CONFIG_BT_MESH_PROVISIONER) SHELL_CMD(auth-method, &auth_cmds, "Authentication methods", bt_mesh_shell_mdl_cmds_help), diff --git a/tests/bsim/bluetooth/mesh/prj.conf b/tests/bsim/bluetooth/mesh/prj.conf index e9c719de6d7..a45bef89775 100644 --- a/tests/bsim/bluetooth/mesh/prj.conf +++ b/tests/bsim/bluetooth/mesh/prj.conf @@ -37,7 +37,7 @@ CONFIG_BT_MESH_LABEL_COUNT=3 CONFIG_BT_MESH_IV_UPDATE_TEST=y CONFIG_BT_MESH_PB_ADV=y CONFIG_BT_MESH_PROVISIONER=y -CONFIG_BT_MESH_PROVISIONEE=y +CONFIG_BT_MESH_PROV_DEVICE=y CONFIG_BT_MESH_CDB=y CONFIG_BT_MESH_CDB_NODE_COUNT=4 CONFIG_BT_MESH_PROV_OOB_PUBLIC_KEY=y diff --git a/tests/bsim/bluetooth/mesh/prj_mesh1d1.conf b/tests/bsim/bluetooth/mesh/prj_mesh1d1.conf index fd0c953226b..11059c03da4 100644 --- a/tests/bsim/bluetooth/mesh/prj_mesh1d1.conf +++ b/tests/bsim/bluetooth/mesh/prj_mesh1d1.conf @@ -39,7 +39,7 @@ CONFIG_BT_MESH_LABEL_COUNT=3 CONFIG_BT_MESH_IV_UPDATE_TEST=y CONFIG_BT_MESH_PB_ADV=y CONFIG_BT_MESH_PROVISIONER=y -CONFIG_BT_MESH_PROVISIONEE=y +CONFIG_BT_MESH_PROV_DEVICE=y CONFIG_BT_MESH_CDB=y CONFIG_BT_MESH_CDB_NODE_COUNT=4 CONFIG_BT_MESH_PROV_OOB_PUBLIC_KEY=y From 5862b1e0f5803c5effcc8fb75310905ded9c80ef Mon Sep 17 00:00:00 2001 From: Robert Lubos Date: Tue, 6 Feb 2024 11:07:20 +0100 Subject: [PATCH 3607/3723] Revert "[nrf fromtree] Bluetooth: Mesh: access tx msg randomizer" This reverts commit 113bf618d85999f6c705ab4bb8b5304873b4e46c. Signed-off-by: Robert Lubos --- .../bluetooth/api/mesh/access.rst | 33 -- doc/releases/release-notes-3.6.rst | 5 - include/zephyr/bluetooth/mesh/msg.h | 3 - .../bluetooth/mesh/boards/bbc_microbit.conf | 1 - .../mesh_demo/boards/bbc_microbit.conf | 1 - subsys/bluetooth/mesh/CMakeLists.txt | 2 - subsys/bluetooth/mesh/Kconfig | 35 -- subsys/bluetooth/mesh/access.c | 29 -- subsys/bluetooth/mesh/access.h | 17 - subsys/bluetooth/mesh/delayable_msg.c | 314 ------------------ subsys/bluetooth/mesh/delayable_msg.h | 16 - subsys/bluetooth/mesh/main.c | 4 - 12 files changed, 460 deletions(-) delete mode 100644 subsys/bluetooth/mesh/delayable_msg.c delete mode 100644 subsys/bluetooth/mesh/delayable_msg.h diff --git a/doc/connectivity/bluetooth/api/mesh/access.rst b/doc/connectivity/bluetooth/api/mesh/access.rst index 7030a3c14b2..e4a94440556 100644 --- a/doc/connectivity/bluetooth/api/mesh/access.rst +++ b/doc/connectivity/bluetooth/api/mesh/access.rst @@ -222,39 +222,6 @@ They are used to represent the new content of the mirrored pages when the Compos change after a firmware update. See :ref:`bluetooth_mesh_dfu_srv_comp_data_and_models_metadata` for details. -Delayable messages -================== - -The delayable message functionality is enabled with Kconfig option -:kconfig:option:`CONFIG_BT_MESH_ACCESS_DELAYABLE_MSG`. -This is an optional functionality that implements specification recommendations for -messages that are transmitted by a model in a response to a received message, also called -response messages. - -Response messages should be sent with the following random delays: - -* Between 20 and 50 milliseconds if the received message was sent - to a unicast address -* Between 20 and 500 milliseconds if the received message was sent - to a group or virtual address - -The delayable message functionality is triggered if the :c:member:`bt_mesh_msg_ctx.rnd_delay` -flag is set. -The delayable message functionality stores messages in the local memory while they are -waiting for the random delay expiration. - -If the transport layer doesn't have sufficient memory to send a message at the moment -the random delay expires, the message is postponed for another 10 milliseconds. -If the transport layer cannot send a message for any other reason, the delayable message -functionality raises the :c:member:`bt_mesh_send_cb.start` callback with a transport layer -error code. - -If the delayable message functionality cannot find enough free memory to store an incoming -message, it will send messages with delay close to expiration to free memory. - -When the mesh stack is suspended or reset, messages not yet sent are removed and -the :c:member:`bt_mesh_send_cb.start` callback is raised with an error code. - API reference ************* diff --git a/doc/releases/release-notes-3.6.rst b/doc/releases/release-notes-3.6.rst index 8edd3280382..676e16fa77c 100644 --- a/doc/releases/release-notes-3.6.rst +++ b/doc/releases/release-notes-3.6.rst @@ -52,11 +52,6 @@ Bluetooth * Mesh - * Added the delayable messages functionality to apply random delays for - the transmitted responses on the Access layer. - The functionality is enabled by the :kconfig:option:`CONFIG_BT_MESH_ACCESS_DELAYABLE_MSG` - Kconfig option. - * Controller Boards & SoC Support diff --git a/include/zephyr/bluetooth/mesh/msg.h b/include/zephyr/bluetooth/mesh/msg.h index 8a7ce1a7128..e52ca85e3a4 100644 --- a/include/zephyr/bluetooth/mesh/msg.h +++ b/include/zephyr/bluetooth/mesh/msg.h @@ -98,9 +98,6 @@ struct bt_mesh_msg_ctx { /** Force sending reliably by using segment acknowledgment */ bool send_rel; - /** Send message with a random delay according to the Access layer transmitting rules. */ - bool rnd_delay; - /** TTL, or BT_MESH_TTL_DEFAULT for default TTL. */ uint8_t send_ttl; }; diff --git a/samples/bluetooth/mesh/boards/bbc_microbit.conf b/samples/bluetooth/mesh/boards/bbc_microbit.conf index 1655768864b..26fb05301c1 100644 --- a/samples/bluetooth/mesh/boards/bbc_microbit.conf +++ b/samples/bluetooth/mesh/boards/bbc_microbit.conf @@ -32,4 +32,3 @@ CONFIG_BT_MESH_SUBNET_COUNT=1 CONFIG_BT_MESH_APP_KEY_COUNT=1 CONFIG_BT_MESH_MODEL_GROUP_COUNT=1 CONFIG_BT_MESH_LABEL_COUNT=0 -CONFIG_BT_MESH_ACCESS_DELAYABLE_MSG=n diff --git a/samples/bluetooth/mesh_demo/boards/bbc_microbit.conf b/samples/bluetooth/mesh_demo/boards/bbc_microbit.conf index 64adc465794..5eb087c4ced 100644 --- a/samples/bluetooth/mesh_demo/boards/bbc_microbit.conf +++ b/samples/bluetooth/mesh_demo/boards/bbc_microbit.conf @@ -22,4 +22,3 @@ CONFIG_BT_MESH_BEACON_ENABLED=n CONFIG_BT_MESH_LABEL_COUNT=1 CONFIG_BT_MESH_SETTINGS_WORKQ=n -CONFIG_BT_MESH_ACCESS_DELAYABLE_MSG=n diff --git a/subsys/bluetooth/mesh/CMakeLists.txt b/subsys/bluetooth/mesh/CMakeLists.txt index 3fd2e7c3bfc..10b142e87f5 100644 --- a/subsys/bluetooth/mesh/CMakeLists.txt +++ b/subsys/bluetooth/mesh/CMakeLists.txt @@ -122,8 +122,6 @@ zephyr_library_sources_ifdef(CONFIG_BT_MESH_SOLICITATION solicitation.c) zephyr_library_sources_ifdef(CONFIG_BT_MESH_STATISTIC statistic.c) -zephyr_library_sources_ifdef(CONFIG_BT_MESH_ACCESS_DELAYABLE_MSG delayable_msg.c) - if (CONFIG_BT_MESH_USES_TINYCRYPT) zephyr_library_sources(crypto_tc.c) else() diff --git a/subsys/bluetooth/mesh/Kconfig b/subsys/bluetooth/mesh/Kconfig index 3bc7dd2940f..0c654e18064 100644 --- a/subsys/bluetooth/mesh/Kconfig +++ b/subsys/bluetooth/mesh/Kconfig @@ -628,41 +628,6 @@ config BT_MESH_LABEL_NO_RECOVER unprovisioned before upgrading to the version with this option). The option is marked as deprecated to remove the recovery code eventually. -menuconfig BT_MESH_ACCESS_DELAYABLE_MSG - bool "Access layer tx delayable message" - help - Enable following of the message transmitting recommendations, the Access layer - specification. The recommendations are optional. - However, they are strictly recommended if the device participates in the network with - intensive communication where the device receives a lot of requests that require responses. - -if BT_MESH_ACCESS_DELAYABLE_MSG - -config BT_MESH_ACCESS_DELAYABLE_MSG_COUNT - int "Number of simultaneously delayed messages" - default 4 - help - The maximum number of messages the Access layer can manage to delay - at the same time. The number of messages can be handled only if the Access layer - has a sufficient amount of memory to store the model payload for them. - -config BT_MESH_ACCESS_DELAYABLE_MSG_CHUNK_SIZE - int "Maximum delayable message storage chunk" - default 20 - help - Size of memory that Access layer uses to split model message to. It allocates - a sufficient number of these chunks from the pool to store the full model payload. - -config BT_MESH_ACCESS_DELAYABLE_MSG_CHUNK_COUNT - int "Maximum number of available chunks" - default 20 - help - The maximum number of available chunks the Access layer allocates to store model payload. - It is recommended to keep chunk size equal to the reasonable small value to prevent - unnecessary memory wasting. - -endif # BT_MESH_ACCESS_DELAYABLE_MSG - endmenu # Access layer menu "Models" diff --git a/subsys/bluetooth/mesh/access.c b/subsys/bluetooth/mesh/access.c index 4cffe064329..f7de46fe167 100644 --- a/subsys/bluetooth/mesh/access.c +++ b/subsys/bluetooth/mesh/access.c @@ -27,7 +27,6 @@ #include "op_agg.h" #include "settings.h" #include "va.h" -#include "delayable_msg.h" #define LOG_LEVEL CONFIG_BT_MESH_ACCESS_LOG_LEVEL #include @@ -1519,13 +1518,6 @@ int bt_mesh_model_send(const struct bt_mesh_model *model, struct bt_mesh_msg_ctx return -EINVAL; } -#if defined CONFIG_BT_MESH_ACCESS_DELAYABLE_MSG - if (ctx->rnd_delay) { - return bt_mesh_delayable_msg_manage(ctx, msg, bt_mesh_model_elem(model)->rt->addr, - cb, cb_data); - } -#endif - return bt_mesh_access_send(ctx, msg, bt_mesh_model_elem(model)->rt->addr, cb, cb_data); } @@ -2621,24 +2613,3 @@ uint8_t bt_mesh_comp_parse_page(struct net_buf_simple *buf) return page; } - -void bt_mesh_access_init(void) -{ -#if defined CONFIG_BT_MESH_ACCESS_DELAYABLE_MSG - bt_mesh_delayable_msg_init(); -#endif -} - -void bt_mesh_access_suspend(void) -{ -#if defined CONFIG_BT_MESH_ACCESS_DELAYABLE_MSG - bt_mesh_delayable_msg_stop(); -#endif -} - -void bt_mesh_access_reset(void) -{ -#if defined CONFIG_BT_MESH_ACCESS_DELAYABLE_MSG - bt_mesh_delayable_msg_stop(); -#endif -} diff --git a/subsys/bluetooth/mesh/access.h b/subsys/bluetooth/mesh/access.h index 210fceee319..48e0eadec10 100644 --- a/subsys/bluetooth/mesh/access.h +++ b/subsys/bluetooth/mesh/access.h @@ -96,25 +96,8 @@ void bt_mesh_msg_cb_set(void (*cb)(uint32_t opcode, struct bt_mesh_msg_ctx *ctx, * * @param ctx The Bluetooth Mesh message context. * @param buf The message payload. - * @param src_addr The source address of model - * @param cb Callback function. - * @param cb_data Callback data. * * @return 0 on success or negative error code on failure. */ int bt_mesh_access_send(struct bt_mesh_msg_ctx *ctx, struct net_buf_simple *buf, uint16_t src_addr, const struct bt_mesh_send_cb *cb, void *cb_data); - -/** @brief Initialize the Access layer. - * - * Initialize the delayable message mechanism if it has been enabled. - */ -void bt_mesh_access_init(void); - -/** @brief Suspend the Access layer. - */ -void bt_mesh_access_suspend(void); - -/** @brief Reset the Access layer. - */ -void bt_mesh_access_reset(void); diff --git a/subsys/bluetooth/mesh/delayable_msg.c b/subsys/bluetooth/mesh/delayable_msg.c deleted file mode 100644 index 5fa43205d63..00000000000 --- a/subsys/bluetooth/mesh/delayable_msg.c +++ /dev/null @@ -1,314 +0,0 @@ -/* - * Copyright (c) 2023 Nordic Semiconductor ASA - * - * SPDX-License-Identifier: Apache-2.0 - */ - -#include -#include -#include -#include - -#include -#include - -#include "msg.h" -#include "access.h" -#include "net.h" - -#define LOG_LEVEL CONFIG_BT_MESH_ACCESS_LOG_LEVEL -#include -LOG_MODULE_REGISTER(bt_mesh_delayable_msg); - -static void delayable_msg_handler(struct k_work *w); -static bool push_msg_from_delayable_msgs(void); - -static struct delayable_msg_chunk { - sys_snode_t node; - uint8_t data[CONFIG_BT_MESH_ACCESS_DELAYABLE_MSG_CHUNK_SIZE]; -} delayable_msg_chunks[CONFIG_BT_MESH_ACCESS_DELAYABLE_MSG_CHUNK_COUNT]; - -static struct delayable_msg_ctx { - sys_snode_t node; - sys_slist_t chunks; - struct bt_mesh_msg_ctx ctx; - uint16_t src_addr; - const struct bt_mesh_send_cb *cb; - void *cb_data; - uint32_t fired_time; - uint16_t len; -} delayable_msgs_ctx[CONFIG_BT_MESH_ACCESS_DELAYABLE_MSG_COUNT]; - -static struct { - sys_slist_t busy_ctx; - sys_slist_t free_ctx; - sys_slist_t free_chunks; - struct k_work_delayable random_delay; -} access_delayable_msg = {.random_delay = Z_WORK_DELAYABLE_INITIALIZER(delayable_msg_handler)}; - -static void put_ctx_to_busy_list(struct delayable_msg_ctx *ctx) -{ - struct delayable_msg_ctx *curr_ctx; - sys_slist_t *list = &access_delayable_msg.busy_ctx; - sys_snode_t *head = sys_slist_peek_head(list); - sys_snode_t *curr = head; - sys_snode_t *prev = curr; - - if (!head) { - sys_slist_append(list, &ctx->node); - return; - } - - do { - curr_ctx = CONTAINER_OF(curr, struct delayable_msg_ctx, node); - if (ctx->fired_time < curr_ctx->fired_time) { - if (curr == head) { - sys_slist_prepend(list, &ctx->node); - } else { - sys_slist_insert(list, prev, &ctx->node); - } - return; - } - prev = curr; - } while ((curr = sys_slist_peek_next(curr))); - - sys_slist_append(list, &ctx->node); -} - -static struct delayable_msg_ctx *peek_pending_msg(void) -{ - struct delayable_msg_ctx *pending_msg = NULL; - sys_snode_t *node = sys_slist_peek_head(&access_delayable_msg.busy_ctx); - - if (node) { - pending_msg = CONTAINER_OF(node, struct delayable_msg_ctx, node); - } - - return pending_msg; -} - -static void reschedule_delayable_msg(struct delayable_msg_ctx *msg) -{ - uint32_t curr_time; - k_timeout_t delay = K_NO_WAIT; - struct delayable_msg_ctx *pending_msg; - - if (msg) { - put_ctx_to_busy_list(msg); - } - - pending_msg = peek_pending_msg(); - - if (!pending_msg) { - return; - } - - curr_time = k_uptime_get_32(); - if (curr_time < pending_msg->fired_time) { - delay = K_MSEC(pending_msg->fired_time - curr_time); - } - - k_work_reschedule(&access_delayable_msg.random_delay, delay); -} - -static int allocate_delayable_msg_chunks(struct delayable_msg_ctx *msg, int number) -{ - sys_snode_t *node; - - for (int i = 0; i < number; i++) { - node = sys_slist_get(&access_delayable_msg.free_chunks); - if (!node) { - LOG_WRN("Unable allocate %u chunks, allocated %u", number, i); - return i; - } - sys_slist_append(&msg->chunks, node); - } - - return number; -} - -static void release_delayable_msg_chunks(struct delayable_msg_ctx *msg) -{ - sys_snode_t *node; - - while ((node = sys_slist_get(&msg->chunks))) { - sys_slist_append(&access_delayable_msg.free_chunks, node); - } -} - -static struct delayable_msg_ctx *allocate_delayable_msg_ctx(void) -{ - struct delayable_msg_ctx *msg; - sys_snode_t *node; - - if (sys_slist_is_empty(&access_delayable_msg.free_ctx)) { - LOG_WRN("Purge pending delayable message."); - if (!push_msg_from_delayable_msgs()) { - return NULL; - } - } - - node = sys_slist_get(&access_delayable_msg.free_ctx); - msg = CONTAINER_OF(node, struct delayable_msg_ctx, node); - sys_slist_init(&msg->chunks); - - return msg; -} - -static void release_delayable_msg_ctx(struct delayable_msg_ctx *ctx) -{ - if (sys_slist_find_and_remove(&access_delayable_msg.busy_ctx, &ctx->node)) { - sys_slist_append(&access_delayable_msg.free_ctx, &ctx->node); - } -} - -static bool push_msg_from_delayable_msgs(void) -{ - sys_snode_t *node; - struct delayable_msg_chunk *chunk; - struct delayable_msg_ctx *msg = peek_pending_msg(); - uint16_t len = msg->len; - int err; - - if (!msg) { - return false; - } - - NET_BUF_SIMPLE_DEFINE(buf, BT_MESH_TX_SDU_MAX); - - SYS_SLIST_FOR_EACH_NODE(&msg->chunks, node) { - uint16_t tmp = MIN(CONFIG_BT_MESH_ACCESS_DELAYABLE_MSG_CHUNK_SIZE, len); - - chunk = CONTAINER_OF(node, struct delayable_msg_chunk, node); - memcpy(net_buf_simple_add(&buf, tmp), chunk->data, tmp); - len -= tmp; - } - - msg->ctx.rnd_delay = false; - err = bt_mesh_access_send(&msg->ctx, &buf, msg->src_addr, msg->cb, msg->cb_data); - msg->ctx.rnd_delay = true; - - if (err == -EBUSY || err == -ENOBUFS) { - return false; - } - - release_delayable_msg_chunks(msg); - release_delayable_msg_ctx(msg); - - if (err && msg->cb && msg->cb->start) { - msg->cb->start(0, err, msg->cb_data); - } - - return true; -} - -static void delayable_msg_handler(struct k_work *w) -{ - if (!push_msg_from_delayable_msgs()) { - sys_snode_t *node = sys_slist_get(&access_delayable_msg.busy_ctx); - struct delayable_msg_ctx *pending_msg = - CONTAINER_OF(node, struct delayable_msg_ctx, node); - - pending_msg->fired_time += 10; - reschedule_delayable_msg(pending_msg); - } else { - reschedule_delayable_msg(NULL); - } -} - -int bt_mesh_delayable_msg_manage(struct bt_mesh_msg_ctx *ctx, struct net_buf_simple *buf, - uint16_t src_addr, const struct bt_mesh_send_cb *cb, void *cb_data) -{ - sys_snode_t *node; - struct delayable_msg_ctx *msg; - uint16_t random_delay; - int total_number = DIV_ROUND_UP(buf->size, CONFIG_BT_MESH_ACCESS_DELAYABLE_MSG_CHUNK_SIZE); - int allocated_number = 0; - uint16_t len = buf->len; - - if (atomic_test_bit(bt_mesh.flags, BT_MESH_SUSPENDED)) { - LOG_WRN("Refusing to allocate message context while suspended"); - return -ENODEV; - } - - if (total_number > CONFIG_BT_MESH_ACCESS_DELAYABLE_MSG_CHUNK_COUNT) { - return -EINVAL; - } - - msg = allocate_delayable_msg_ctx(); - if (!msg) { - LOG_WRN("No available free delayable message context."); - return -ENOMEM; - } - - do { - allocated_number += - allocate_delayable_msg_chunks(msg, total_number - allocated_number); - - if (total_number > allocated_number) { - LOG_DBG("Unable allocate %u chunks, allocated %u", total_number, - allocated_number); - if (!push_msg_from_delayable_msgs()) { - LOG_WRN("No available chunk memory."); - release_delayable_msg_chunks(msg); - release_delayable_msg_ctx(msg); - return -ENOMEM; - } - } - } while (total_number > allocated_number); - - SYS_SLIST_FOR_EACH_NODE(&msg->chunks, node) { - uint16_t tmp = MIN(CONFIG_BT_MESH_ACCESS_DELAYABLE_MSG_CHUNK_SIZE, buf->len); - - struct delayable_msg_chunk *chunk = - CONTAINER_OF(node, struct delayable_msg_chunk, node); - - memcpy(chunk->data, net_buf_simple_pull_mem(buf, tmp), tmp); - } - - bt_rand(&random_delay, sizeof(uint16_t)); - random_delay = 20 + random_delay % (BT_MESH_ADDR_IS_UNICAST(ctx->recv_dst) ? 30 : 480); - msg->fired_time = k_uptime_get_32() + random_delay; - msg->ctx = *ctx; - msg->src_addr = src_addr; - msg->cb = cb; - msg->cb_data = cb_data; - msg->len = len; - - reschedule_delayable_msg(msg); - - return 0; -} - -void bt_mesh_delayable_msg_init(void) -{ - sys_slist_init(&access_delayable_msg.busy_ctx); - sys_slist_init(&access_delayable_msg.free_ctx); - sys_slist_init(&access_delayable_msg.free_chunks); - - for (int i = 0; i < CONFIG_BT_MESH_ACCESS_DELAYABLE_MSG_COUNT; i++) { - sys_slist_append(&access_delayable_msg.free_ctx, &delayable_msgs_ctx[i].node); - } - - for (int i = 0; i < CONFIG_BT_MESH_ACCESS_DELAYABLE_MSG_CHUNK_COUNT; i++) { - sys_slist_append(&access_delayable_msg.free_chunks, &delayable_msg_chunks[i].node); - } -} - -void bt_mesh_delayable_msg_stop(void) -{ - sys_snode_t *node; - struct delayable_msg_ctx *ctx; - - k_work_cancel_delayable(&access_delayable_msg.random_delay); - - while ((node = sys_slist_peek_head(&access_delayable_msg.busy_ctx))) { - ctx = CONTAINER_OF(node, struct delayable_msg_ctx, node); - release_delayable_msg_chunks(ctx); - release_delayable_msg_ctx(ctx); - - if (ctx->cb && ctx->cb->start) { - ctx->cb->start(0, -ENODEV, ctx->cb_data); - } - } -} diff --git a/subsys/bluetooth/mesh/delayable_msg.h b/subsys/bluetooth/mesh/delayable_msg.h deleted file mode 100644 index 1ab5dde2e76..00000000000 --- a/subsys/bluetooth/mesh/delayable_msg.h +++ /dev/null @@ -1,16 +0,0 @@ -/* - * Copyright (c) 2023 Nordic Semiconductor ASA - * - * SPDX-License-Identifier: Apache-2.0 - */ - -#ifndef ZEPHYR_INCLUDE_BLUETOOTH_MESH_DELAYABLE_MSG_H__ -#define ZEPHYR_INCLUDE_BLUETOOTH_MESH_DELAYABLE_MSG_H__ - -int bt_mesh_delayable_msg_manage(struct bt_mesh_msg_ctx *ctx, struct net_buf_simple *buf, - uint16_t src_addr, const struct bt_mesh_send_cb *cb, - void *cb_data); -void bt_mesh_delayable_msg_init(void); -void bt_mesh_delayable_msg_stop(void); - -#endif /* ZEPHYR_INCLUDE_BLUETOOTH_MESH_DELAYABLE_MSG_H__ */ diff --git a/subsys/bluetooth/mesh/main.c b/subsys/bluetooth/mesh/main.c index 2689a3355c1..89115ebe3e8 100644 --- a/subsys/bluetooth/mesh/main.c +++ b/subsys/bluetooth/mesh/main.c @@ -359,7 +359,6 @@ void bt_mesh_reset(void) */ (void)k_work_cancel_delayable(&bt_mesh.ivu_timer); - bt_mesh_access_reset(); bt_mesh_model_reset(); bt_mesh_cfg_default_set(); bt_mesh_trans_reset(); @@ -460,8 +459,6 @@ int bt_mesh_suspend(void) bt_mesh_model_foreach(model_suspend, NULL); - bt_mesh_access_suspend(); - err = bt_mesh_adv_disable(); if (err) { atomic_clear_bit(bt_mesh.flags, BT_MESH_SUSPENDED); @@ -561,7 +558,6 @@ int bt_mesh_init(const struct bt_mesh_prov *prov, bt_mesh_cfg_default_set(); bt_mesh_net_init(); bt_mesh_trans_init(); - bt_mesh_access_init(); bt_mesh_hb_init(); bt_mesh_beacon_init(); bt_mesh_adv_init(); From 10b1cd1cc1c53e467608600ad1d51d2a8146f7a9 Mon Sep 17 00:00:00 2001 From: Robert Lubos Date: Tue, 6 Feb 2024 11:07:21 +0100 Subject: [PATCH 3608/3723] Revert "[nrf fromtree] Bluetooth: Mesh: Use memslab replace with net_buf_pool" This reverts commit e12a81c47a25da93925863046dd79808643f1f8d. Signed-off-by: Robert Lubos --- subsys/bluetooth/mesh/access.c | 1 + subsys/bluetooth/mesh/adv.c | 195 ++++++++---------- subsys/bluetooth/mesh/adv.h | 51 ++--- subsys/bluetooth/mesh/adv_ext.c | 193 ++++++++--------- subsys/bluetooth/mesh/adv_legacy.c | 65 +++--- subsys/bluetooth/mesh/app_keys.c | 1 + subsys/bluetooth/mesh/beacon.c | 49 ++--- subsys/bluetooth/mesh/cfg.c | 1 + subsys/bluetooth/mesh/cfg_srv.c | 1 + subsys/bluetooth/mesh/friend.c | 15 +- subsys/bluetooth/mesh/gatt_cli.c | 1 + subsys/bluetooth/mesh/health_srv.c | 1 + subsys/bluetooth/mesh/lpn.c | 1 + subsys/bluetooth/mesh/main.c | 1 + subsys/bluetooth/mesh/net.c | 49 ++--- subsys/bluetooth/mesh/net.h | 3 +- subsys/bluetooth/mesh/pb_adv.c | 143 ++++++------- subsys/bluetooth/mesh/pb_gatt.c | 1 + subsys/bluetooth/mesh/pb_gatt_cli.c | 1 + subsys/bluetooth/mesh/pb_gatt_srv.c | 1 + subsys/bluetooth/mesh/priv_beacon_srv.c | 1 + subsys/bluetooth/mesh/prov_device.c | 1 + subsys/bluetooth/mesh/provisioner.c | 1 + subsys/bluetooth/mesh/proxy.h | 2 +- subsys/bluetooth/mesh/proxy_cli.c | 5 +- subsys/bluetooth/mesh/proxy_cli.h | 2 +- subsys/bluetooth/mesh/proxy_msg.c | 15 +- subsys/bluetooth/mesh/proxy_msg.h | 2 +- subsys/bluetooth/mesh/proxy_srv.c | 7 +- subsys/bluetooth/mesh/rpl.c | 1 + subsys/bluetooth/mesh/rpr_srv.c | 1 + subsys/bluetooth/mesh/solicitation.c | 1 + subsys/bluetooth/mesh/statistic.c | 17 +- subsys/bluetooth/mesh/statistic.h | 4 +- subsys/bluetooth/mesh/subnet.c | 1 + subsys/bluetooth/mesh/transport.c | 31 +-- subsys/bluetooth/mesh/transport_legacy.c | 31 +-- .../bsim/bluetooth/mesh/src/test_advertiser.c | 142 ++++++------- tests/bsim/bluetooth/mesh/src/test_beacon.c | 1 + tests/bsim/bluetooth/mesh/src/test_blob.c | 2 +- tests/bsim/bluetooth/mesh/src/test_dfu.c | 1 + .../bsim/bluetooth/mesh/src/test_provision.c | 1 + tests/bsim/bluetooth/mesh/src/test_scanner.c | 1 + 43 files changed, 524 insertions(+), 521 deletions(-) diff --git a/subsys/bluetooth/mesh/access.c b/subsys/bluetooth/mesh/access.c index f7de46fe167..81e2902afd1 100644 --- a/subsys/bluetooth/mesh/access.c +++ b/subsys/bluetooth/mesh/access.c @@ -19,6 +19,7 @@ #include "host/testing.h" #include "mesh.h" +#include "adv.h" #include "net.h" #include "lpn.h" #include "transport.h" diff --git a/subsys/bluetooth/mesh/adv.c b/subsys/bluetooth/mesh/adv.c index 00e2a4aa7bb..548e7f3fe15 100644 --- a/subsys/bluetooth/mesh/adv.c +++ b/subsys/bluetooth/mesh/adv.c @@ -17,6 +17,7 @@ #include "common/bt_str.h" +#include "adv.h" #include "net.h" #include "foundation.h" #include "beacon.h" @@ -46,144 +47,124 @@ static K_FIFO_DEFINE(bt_mesh_adv_queue); static K_FIFO_DEFINE(bt_mesh_relay_queue); static K_FIFO_DEFINE(bt_mesh_friend_queue); -K_MEM_SLAB_DEFINE_STATIC(local_adv_pool, sizeof(struct bt_mesh_adv), - CONFIG_BT_MESH_ADV_BUF_COUNT, __alignof__(struct bt_mesh_adv)); - -#if defined(CONFIG_BT_MESH_RELAY_BUF_COUNT) -K_MEM_SLAB_DEFINE_STATIC(relay_adv_pool, sizeof(struct bt_mesh_adv), - CONFIG_BT_MESH_RELAY_BUF_COUNT, __alignof__(struct bt_mesh_adv)); -#endif - -#if defined(CONFIG_BT_MESH_ADV_EXT_FRIEND_SEPARATE) -K_MEM_SLAB_DEFINE_STATIC(friend_adv_pool, sizeof(struct bt_mesh_adv), - CONFIG_BT_MESH_FRIEND_LPN_COUNT, __alignof__(struct bt_mesh_adv)); -#endif - -void bt_mesh_adv_send_start(uint16_t duration, int err, struct bt_mesh_adv_ctx *ctx) +void bt_mesh_adv_send_start(uint16_t duration, int err, struct bt_mesh_adv *adv) { - if (!ctx->started) { - ctx->started = 1; + if (!adv->started) { + adv->started = 1; - if (ctx->cb && ctx->cb->start) { - ctx->cb->start(duration, err, ctx->cb_data); + if (adv->cb && adv->cb->start) { + adv->cb->start(duration, err, adv->cb_data); } if (err) { - ctx->cb = NULL; + adv->cb = NULL; } else if (IS_ENABLED(CONFIG_BT_MESH_STATISTIC)) { - bt_mesh_stat_succeeded_count(ctx); + bt_mesh_stat_succeeded_count(adv); } } } -static void bt_mesh_adv_send_end(int err, struct bt_mesh_adv_ctx const *ctx) +static void bt_mesh_adv_send_end(int err, struct bt_mesh_adv const *adv) { - if (ctx->started && ctx->cb && ctx->cb->end) { - ctx->cb->end(err, ctx->cb_data); + if (adv->started && adv->cb && adv->cb->end) { + adv->cb->end(err, adv->cb_data); } } -static struct bt_mesh_adv *adv_create_from_pool(struct k_mem_slab *buf_pool, - enum bt_mesh_adv_type type, - enum bt_mesh_adv_tag tag, - uint8_t xmit, k_timeout_t timeout) +static void adv_buf_destroy(struct net_buf *buf) { - struct bt_mesh_adv_ctx *ctx; - struct bt_mesh_adv *adv; - int err; + struct bt_mesh_adv adv = *BT_MESH_ADV(buf); - if (atomic_test_bit(bt_mesh.flags, BT_MESH_SUSPENDED)) { - LOG_WRN("Refusing to allocate buffer while suspended"); - return NULL; - } + net_buf_destroy(buf); - err = k_mem_slab_alloc(buf_pool, (void **)&adv, timeout); - if (err) { - return NULL; - } + bt_mesh_adv_send_end(0, &adv); +} - adv->__ref = 1; +NET_BUF_POOL_DEFINE(adv_buf_pool, CONFIG_BT_MESH_ADV_BUF_COUNT, + BT_MESH_ADV_DATA_SIZE, BT_MESH_ADV_USER_DATA_SIZE, + adv_buf_destroy); - net_buf_simple_init_with_data(&adv->b, adv->__bufs, BT_MESH_ADV_DATA_SIZE); - net_buf_simple_reset(&adv->b); +static struct bt_mesh_adv adv_local_pool[CONFIG_BT_MESH_ADV_BUF_COUNT]; - ctx = &adv->ctx; +#if defined(CONFIG_BT_MESH_RELAY) +NET_BUF_POOL_DEFINE(relay_buf_pool, CONFIG_BT_MESH_RELAY_BUF_COUNT, + BT_MESH_ADV_DATA_SIZE, BT_MESH_ADV_USER_DATA_SIZE, + adv_buf_destroy); - (void)memset(ctx, 0, sizeof(*ctx)); +static struct bt_mesh_adv adv_relay_pool[CONFIG_BT_MESH_RELAY_BUF_COUNT]; +#endif - ctx->type = type; - ctx->tag = tag; - ctx->xmit = xmit; +#if defined(CONFIG_BT_MESH_ADV_EXT_FRIEND_SEPARATE) +NET_BUF_POOL_DEFINE(friend_buf_pool, CONFIG_BT_MESH_FRIEND_LPN_COUNT, + BT_MESH_ADV_DATA_SIZE, BT_MESH_ADV_USER_DATA_SIZE, + adv_buf_destroy); - return adv; -} +static struct bt_mesh_adv adv_friend_pool[CONFIG_BT_MESH_FRIEND_LPN_COUNT]; +#endif -struct bt_mesh_adv *bt_mesh_adv_ref(struct bt_mesh_adv *adv) +static struct net_buf *bt_mesh_adv_create_from_pool(struct net_buf_pool *buf_pool, + struct bt_mesh_adv *adv_pool, + enum bt_mesh_adv_type type, + enum bt_mesh_adv_tag tag, + uint8_t xmit, k_timeout_t timeout) { - __ASSERT_NO_MSG(adv->__ref < UINT8_MAX); - - adv->__ref++; - - return adv; -} + struct bt_mesh_adv *adv; + struct net_buf *buf; -void bt_mesh_adv_unref(struct bt_mesh_adv *adv) -{ - __ASSERT_NO_MSG(adv->__ref > 0); + if (atomic_test_bit(bt_mesh.flags, BT_MESH_SUSPENDED)) { + LOG_WRN("Refusing to allocate buffer while suspended"); + return NULL; + } - if (--adv->__ref > 0) { - return; + buf = net_buf_alloc(buf_pool, timeout); + if (!buf) { + return NULL; } - struct k_mem_slab *slab = &local_adv_pool; - struct bt_mesh_adv_ctx ctx = adv->ctx; + adv = &adv_pool[net_buf_id(buf)]; + BT_MESH_ADV(buf) = adv; -#if defined(CONFIG_BT_MESH_RELAY) - if (adv->ctx.tag == BT_MESH_ADV_TAG_RELAY) { - slab = &relay_adv_pool; - } -#endif + (void)memset(adv, 0, sizeof(*adv)); -#if defined(CONFIG_BT_MESH_ADV_EXT_FRIEND_SEPARATE) - if (adv->ctx.tag == BT_MESH_ADV_TAG_FRIEND) { - slab = &friend_adv_pool; - } -#endif + adv->type = type; + adv->tag = tag; + adv->xmit = xmit; - k_mem_slab_free(slab, (void *)adv); - bt_mesh_adv_send_end(0, &ctx); + return buf; } -struct bt_mesh_adv *bt_mesh_adv_create(enum bt_mesh_adv_type type, - enum bt_mesh_adv_tag tag, - uint8_t xmit, k_timeout_t timeout) +struct net_buf *bt_mesh_adv_create(enum bt_mesh_adv_type type, + enum bt_mesh_adv_tag tag, + uint8_t xmit, k_timeout_t timeout) { #if defined(CONFIG_BT_MESH_RELAY) if (tag == BT_MESH_ADV_TAG_RELAY) { - return adv_create_from_pool(&relay_adv_pool, - type, tag, xmit, timeout); + return bt_mesh_adv_create_from_pool(&relay_buf_pool, + adv_relay_pool, type, + tag, xmit, timeout); } #endif #if defined(CONFIG_BT_MESH_ADV_EXT_FRIEND_SEPARATE) if (tag == BT_MESH_ADV_TAG_FRIEND) { - return adv_create_from_pool(&friend_adv_pool, - type, tag, xmit, timeout); + return bt_mesh_adv_create_from_pool(&friend_buf_pool, + adv_friend_pool, type, + tag, xmit, timeout); } #endif - return adv_create_from_pool(&local_adv_pool, type, - tag, xmit, timeout); + return bt_mesh_adv_create_from_pool(&adv_buf_pool, adv_local_pool, type, + tag, xmit, timeout); } -static struct bt_mesh_adv *process_events(struct k_poll_event *ev, int count) +static struct net_buf *process_events(struct k_poll_event *ev, int count) { for (; count; ev++, count--) { LOG_DBG("ev->state %u", ev->state); switch (ev->state) { case K_POLL_STATE_FIFO_DATA_AVAILABLE: - return k_fifo_get(ev->fifo, K_NO_WAIT); + return net_buf_get(ev->fifo, K_NO_WAIT); case K_POLL_STATE_NOT_READY: case K_POLL_STATE_CANCELLED: break; @@ -196,7 +177,7 @@ static struct bt_mesh_adv *process_events(struct k_poll_event *ev, int count) return NULL; } -struct bt_mesh_adv *bt_mesh_adv_get(k_timeout_t timeout) +struct net_buf *bt_mesh_adv_buf_get(k_timeout_t timeout) { int err; struct k_poll_event events[] = { @@ -223,22 +204,22 @@ struct bt_mesh_adv *bt_mesh_adv_get(k_timeout_t timeout) return process_events(events, ARRAY_SIZE(events)); } -struct bt_mesh_adv *bt_mesh_adv_get_by_tag(enum bt_mesh_adv_tag_bit tags, k_timeout_t timeout) +struct net_buf *bt_mesh_adv_buf_get_by_tag(enum bt_mesh_adv_tag_bit tags, k_timeout_t timeout) { if (IS_ENABLED(CONFIG_BT_MESH_ADV_EXT_FRIEND_SEPARATE) && tags & BT_MESH_ADV_TAG_BIT_FRIEND) { - return k_fifo_get(&bt_mesh_friend_queue, timeout); + return net_buf_get(&bt_mesh_friend_queue, timeout); } if (IS_ENABLED(CONFIG_BT_MESH_RELAY) && !(tags & BT_MESH_ADV_TAG_BIT_LOCAL)) { - return k_fifo_get(&bt_mesh_relay_queue, timeout); + return net_buf_get(&bt_mesh_relay_queue, timeout); } - return bt_mesh_adv_get(timeout); + return bt_mesh_adv_buf_get(timeout); } -void bt_mesh_adv_get_cancel(void) +void bt_mesh_adv_buf_get_cancel(void) { LOG_DBG(""); @@ -253,38 +234,38 @@ void bt_mesh_adv_get_cancel(void) } } -void bt_mesh_adv_send(struct bt_mesh_adv *adv, const struct bt_mesh_send_cb *cb, +void bt_mesh_adv_send(struct net_buf *buf, const struct bt_mesh_send_cb *cb, void *cb_data) { - LOG_DBG("type 0x%02x len %u: %s", adv->ctx.type, adv->b.len, - bt_hex(adv->b.data, adv->b.len)); + LOG_DBG("type 0x%02x len %u: %s", BT_MESH_ADV(buf)->type, buf->len, + bt_hex(buf->data, buf->len)); - adv->ctx.cb = cb; - adv->ctx.cb_data = cb_data; - adv->ctx.busy = 1U; + BT_MESH_ADV(buf)->cb = cb; + BT_MESH_ADV(buf)->cb_data = cb_data; + BT_MESH_ADV(buf)->busy = 1U; if (IS_ENABLED(CONFIG_BT_MESH_STATISTIC)) { - bt_mesh_stat_planned_count(&adv->ctx); + bt_mesh_stat_planned_count(BT_MESH_ADV(buf)); } if (IS_ENABLED(CONFIG_BT_MESH_ADV_EXT_FRIEND_SEPARATE) && - adv->ctx.tag == BT_MESH_ADV_TAG_FRIEND) { - k_fifo_put(&bt_mesh_friend_queue, bt_mesh_adv_ref(adv)); - bt_mesh_adv_friend_ready(); + BT_MESH_ADV(buf)->tag == BT_MESH_ADV_TAG_FRIEND) { + net_buf_put(&bt_mesh_friend_queue, net_buf_ref(buf)); + bt_mesh_adv_buf_friend_ready(); return; } if ((IS_ENABLED(CONFIG_BT_MESH_RELAY) && - adv->ctx.tag == BT_MESH_ADV_TAG_RELAY) || + BT_MESH_ADV(buf)->tag == BT_MESH_ADV_TAG_RELAY) || (IS_ENABLED(CONFIG_BT_MESH_PB_ADV_USE_RELAY_SETS) && - adv->ctx.tag == BT_MESH_ADV_TAG_PROV)) { - k_fifo_put(&bt_mesh_relay_queue, bt_mesh_adv_ref(adv)); - bt_mesh_adv_relay_ready(); + BT_MESH_ADV(buf)->tag == BT_MESH_ADV_TAG_PROV)) { + net_buf_put(&bt_mesh_relay_queue, net_buf_ref(buf)); + bt_mesh_adv_buf_relay_ready(); return; } - k_fifo_put(&bt_mesh_adv_queue, bt_mesh_adv_ref(adv)); - bt_mesh_adv_local_ready(); + net_buf_put(&bt_mesh_adv_queue, net_buf_ref(buf)); + bt_mesh_adv_buf_local_ready(); } int bt_mesh_adv_gatt_send(void) diff --git a/subsys/bluetooth/mesh/adv.h b/subsys/bluetooth/mesh/adv.h index 0c936a1aa52..42b07601ad5 100644 --- a/subsys/bluetooth/mesh/adv.h +++ b/subsys/bluetooth/mesh/adv.h @@ -4,12 +4,14 @@ * SPDX-License-Identifier: Apache-2.0 */ -#ifndef ZEPHYR_SUBSYS_BLUETOOTH_MESH_ADV_H_ -#define ZEPHYR_SUBSYS_BLUETOOTH_MESH_ADV_H_ - /* Maximum advertising data payload for a single data type */ #define BT_MESH_ADV_DATA_SIZE 29 +/* The user data is a pointer (4 bytes) to struct bt_mesh_adv */ +#define BT_MESH_ADV_USER_DATA_SIZE 4 + +#define BT_MESH_ADV(buf) (*(struct bt_mesh_adv **)net_buf_user_data(buf)) + #define BT_MESH_ADV_SCAN_UNIT(_ms) ((_ms) * 8 / 5) #define BT_MESH_SCAN_INTERVAL_MS 30 #define BT_MESH_SCAN_WINDOW_MS 30 @@ -39,7 +41,7 @@ enum bt_mesh_adv_tag_bit { BT_MESH_ADV_TAG_BIT_PROV = BIT(BT_MESH_ADV_TAG_PROV), }; -struct bt_mesh_adv_ctx { +struct bt_mesh_adv { const struct bt_mesh_send_cb *cb; void *cb_data; @@ -51,39 +53,24 @@ struct bt_mesh_adv_ctx { uint8_t xmit; }; -struct bt_mesh_adv { - sys_snode_t node; - - struct bt_mesh_adv_ctx ctx; - - struct net_buf_simple b; - - uint8_t __ref; - - uint8_t __bufs[BT_MESH_ADV_DATA_SIZE]; -}; - /* Lookup table for Advertising data types for bt_mesh_adv_type: */ extern const uint8_t bt_mesh_adv_type[BT_MESH_ADV_TYPES]; -struct bt_mesh_adv *bt_mesh_adv_ref(struct bt_mesh_adv *adv); -void bt_mesh_adv_unref(struct bt_mesh_adv *adv); - /* xmit_count: Number of retransmissions, i.e. 0 == 1 transmission */ -struct bt_mesh_adv *bt_mesh_adv_create(enum bt_mesh_adv_type type, - enum bt_mesh_adv_tag tag, - uint8_t xmit, k_timeout_t timeout); +struct net_buf *bt_mesh_adv_create(enum bt_mesh_adv_type type, + enum bt_mesh_adv_tag tag, + uint8_t xmit, k_timeout_t timeout); -void bt_mesh_adv_send(struct bt_mesh_adv *adv, const struct bt_mesh_send_cb *cb, +void bt_mesh_adv_send(struct net_buf *buf, const struct bt_mesh_send_cb *cb, void *cb_data); -struct bt_mesh_adv *bt_mesh_adv_get(k_timeout_t timeout); +struct net_buf *bt_mesh_adv_buf_get(k_timeout_t timeout); -struct bt_mesh_adv *bt_mesh_adv_get_by_tag(enum bt_mesh_adv_tag_bit tags, k_timeout_t timeout); +struct net_buf *bt_mesh_adv_buf_get_by_tag(enum bt_mesh_adv_tag_bit tags, k_timeout_t timeout); void bt_mesh_adv_gatt_update(void); -void bt_mesh_adv_get_cancel(void); +void bt_mesh_adv_buf_get_cancel(void); void bt_mesh_adv_init(void); @@ -96,13 +83,13 @@ int bt_mesh_adv_enable(void); /* Should not be called from work queue due to undefined behavior */ int bt_mesh_adv_disable(void); -void bt_mesh_adv_local_ready(void); +void bt_mesh_adv_buf_local_ready(void); -void bt_mesh_adv_relay_ready(void); +void bt_mesh_adv_buf_relay_ready(void); -void bt_mesh_adv_terminate(struct bt_mesh_adv *adv); +void bt_mesh_adv_buf_terminate(const struct net_buf *buf); -void bt_mesh_adv_friend_ready(void); +void bt_mesh_adv_buf_friend_ready(void); int bt_mesh_adv_gatt_send(void); @@ -110,11 +97,9 @@ int bt_mesh_adv_gatt_start(const struct bt_le_adv_param *param, int32_t duration const struct bt_data *ad, size_t ad_len, const struct bt_data *sd, size_t sd_len); -void bt_mesh_adv_send_start(uint16_t duration, int err, struct bt_mesh_adv_ctx *ctx); +void bt_mesh_adv_send_start(uint16_t duration, int err, struct bt_mesh_adv *adv); int bt_mesh_scan_active_set(bool active); int bt_mesh_adv_bt_data_send(uint8_t num_events, uint16_t adv_interval, const struct bt_data *ad, size_t ad_len); - -#endif /* ZEPHYR_SUBSYS_BLUETOOTH_MESH_ADV_H_ */ diff --git a/subsys/bluetooth/mesh/adv_ext.c b/subsys/bluetooth/mesh/adv_ext.c index a4f3f32ee5f..aaea8845ae5 100644 --- a/subsys/bluetooth/mesh/adv_ext.c +++ b/subsys/bluetooth/mesh/adv_ext.c @@ -21,6 +21,7 @@ #include "host/hci_core.h" +#include "adv.h" #include "net.h" #include "proxy.h" #include "solicitation.h" @@ -62,14 +63,14 @@ struct bt_mesh_ext_adv { const enum bt_mesh_adv_tag_bit tags; ATOMIC_DEFINE(flags, ADV_FLAGS_NUM); struct bt_le_ext_adv *instance; - struct bt_mesh_adv *adv; + struct net_buf *buf; uint64_t timestamp; struct k_work_delayable work; struct bt_le_adv_param adv_param; }; static void send_pending_adv(struct k_work *work); -static bool schedule_send(struct bt_mesh_ext_adv *ext_adv); +static bool schedule_send(struct bt_mesh_ext_adv *adv); static struct bt_mesh_ext_adv advs[] = { [0] = { @@ -160,7 +161,7 @@ static int set_adv_randomness(uint8_t handle, int rand_us) #endif /* defined(CONFIG_BT_LL_SOFTDEVICE) */ } -static int adv_start(struct bt_mesh_ext_adv *ext_adv, +static int adv_start(struct bt_mesh_ext_adv *adv, const struct bt_le_adv_param *param, struct bt_le_ext_adv_start_param *start, const struct bt_data *ad, size_t ad_len, @@ -168,47 +169,47 @@ static int adv_start(struct bt_mesh_ext_adv *ext_adv, { int err; - if (!ext_adv->instance) { + if (!adv->instance) { LOG_ERR("Mesh advertiser not enabled"); return -ENODEV; } - if (atomic_test_and_set_bit(ext_adv->flags, ADV_FLAG_ACTIVE)) { + if (atomic_test_and_set_bit(adv->flags, ADV_FLAG_ACTIVE)) { LOG_ERR("Advertiser is busy"); return -EBUSY; } - if (atomic_test_bit(ext_adv->flags, ADV_FLAG_UPDATE_PARAMS)) { - err = bt_le_ext_adv_update_param(ext_adv->instance, param); + if (atomic_test_bit(adv->flags, ADV_FLAG_UPDATE_PARAMS)) { + err = bt_le_ext_adv_update_param(adv->instance, param); if (err) { LOG_ERR("Failed updating adv params: %d", err); - atomic_clear_bit(ext_adv->flags, ADV_FLAG_ACTIVE); + atomic_clear_bit(adv->flags, ADV_FLAG_ACTIVE); return err; } - atomic_set_bit_to(ext_adv->flags, ADV_FLAG_UPDATE_PARAMS, - param != &ext_adv->adv_param); + atomic_set_bit_to(adv->flags, ADV_FLAG_UPDATE_PARAMS, + param != &adv->adv_param); } - err = bt_le_ext_adv_set_data(ext_adv->instance, ad, ad_len, sd, sd_len); + err = bt_le_ext_adv_set_data(adv->instance, ad, ad_len, sd, sd_len); if (err) { LOG_ERR("Failed setting adv data: %d", err); - atomic_clear_bit(ext_adv->flags, ADV_FLAG_ACTIVE); + atomic_clear_bit(adv->flags, ADV_FLAG_ACTIVE); return err; } - ext_adv->timestamp = k_uptime_get(); + adv->timestamp = k_uptime_get(); - err = bt_le_ext_adv_start(ext_adv->instance, start); + err = bt_le_ext_adv_start(adv->instance, start); if (err) { LOG_ERR("Advertising failed: err %d", err); - atomic_clear_bit(ext_adv->flags, ADV_FLAG_ACTIVE); + atomic_clear_bit(adv->flags, ADV_FLAG_ACTIVE); } return err; } -static int bt_data_send(struct bt_mesh_ext_adv *ext_adv, uint8_t num_events, uint16_t adv_interval, +static int bt_data_send(struct bt_mesh_ext_adv *adv, uint8_t num_events, uint16_t adv_interval, const struct bt_data *ad, size_t ad_len) { struct bt_le_ext_adv_start_param start = { @@ -218,41 +219,41 @@ static int bt_data_send(struct bt_mesh_ext_adv *ext_adv, uint8_t num_events, uin adv_interval = MAX(ADV_INT_FAST_MS, adv_interval); /* Only update advertising parameters if they're different */ - if (ext_adv->adv_param.interval_min != BT_MESH_ADV_SCAN_UNIT(adv_interval)) { - ext_adv->adv_param.interval_min = BT_MESH_ADV_SCAN_UNIT(adv_interval); - ext_adv->adv_param.interval_max = ext_adv->adv_param.interval_min; - atomic_set_bit(ext_adv->flags, ADV_FLAG_UPDATE_PARAMS); + if (adv->adv_param.interval_min != BT_MESH_ADV_SCAN_UNIT(adv_interval)) { + adv->adv_param.interval_min = BT_MESH_ADV_SCAN_UNIT(adv_interval); + adv->adv_param.interval_max = adv->adv_param.interval_min; + atomic_set_bit(adv->flags, ADV_FLAG_UPDATE_PARAMS); } - return adv_start(ext_adv, &ext_adv->adv_param, &start, ad, ad_len, NULL, 0); + return adv_start(adv, &adv->adv_param, &start, ad, ad_len, NULL, 0); } -static int adv_send(struct bt_mesh_ext_adv *ext_adv, struct bt_mesh_adv *adv) +static int buf_send(struct bt_mesh_ext_adv *adv, struct net_buf *buf) { - uint8_t num_events = BT_MESH_TRANSMIT_COUNT(adv->ctx.xmit) + 1; + uint8_t num_events = BT_MESH_TRANSMIT_COUNT(BT_MESH_ADV(buf)->xmit) + 1; uint16_t duration, adv_int; struct bt_data ad; int err; - adv_int = BT_MESH_TRANSMIT_INT(adv->ctx.xmit); + adv_int = BT_MESH_TRANSMIT_INT(BT_MESH_ADV(buf)->xmit); /* Upper boundary estimate: */ duration = num_events * (adv_int + 10); - LOG_DBG("type %u len %u: %s", adv->ctx.type, - adv->b.len, bt_hex(adv->b.data, adv->b.len)); + LOG_DBG("type %u len %u: %s", BT_MESH_ADV(buf)->type, + buf->len, bt_hex(buf->data, buf->len)); LOG_DBG("count %u interval %ums duration %ums", num_events, adv_int, duration); - ad.type = bt_mesh_adv_type[adv->ctx.type]; - ad.data_len = adv->b.len; - ad.data = adv->b.data; + ad.type = bt_mesh_adv_type[BT_MESH_ADV(buf)->type]; + ad.data_len = buf->len; + ad.data = buf->data; - err = bt_data_send(ext_adv, num_events, adv_int, &ad, 1); + err = bt_data_send(adv, num_events, adv_int, &ad, 1); if (!err) { - ext_adv->adv = bt_mesh_adv_ref(adv); + adv->buf = net_buf_ref(buf); } - bt_mesh_adv_send_start(duration, err, &adv->ctx); + bt_mesh_adv_send_start(duration, err, BT_MESH_ADV(buf)); return err; } @@ -267,50 +268,50 @@ static const char * const adv_tag_to_str[] = { static void send_pending_adv(struct k_work *work) { - struct bt_mesh_ext_adv *ext_adv; - struct bt_mesh_adv *adv; + struct bt_mesh_ext_adv *adv; + struct net_buf *buf; int err; - ext_adv = CONTAINER_OF(work, struct bt_mesh_ext_adv, work.work); + adv = CONTAINER_OF(work, struct bt_mesh_ext_adv, work.work); - if (atomic_test_and_clear_bit(ext_adv->flags, ADV_FLAG_SENT)) { + if (atomic_test_and_clear_bit(adv->flags, ADV_FLAG_SENT)) { /* Calling k_uptime_delta on a timestamp moves it to the current time. * This is essential here, as schedule_send() uses the end of the event * as a reference to avoid sending the next advertisement too soon. */ - int64_t duration = k_uptime_delta(&ext_adv->timestamp); + int64_t duration = k_uptime_delta(&adv->timestamp); LOG_DBG("Advertising stopped after %u ms for %s", (uint32_t)duration, - ext_adv->adv ? adv_tag_to_str[ext_adv->adv->ctx.tag] : + adv->buf ? adv_tag_to_str[BT_MESH_ADV(adv->buf)->tag] : adv_tag_to_str[BT_MESH_ADV_TAG_PROXY]); - atomic_clear_bit(ext_adv->flags, ADV_FLAG_ACTIVE); - atomic_clear_bit(ext_adv->flags, ADV_FLAG_PROXY); - atomic_clear_bit(ext_adv->flags, ADV_FLAG_PROXY_START); + atomic_clear_bit(adv->flags, ADV_FLAG_ACTIVE); + atomic_clear_bit(adv->flags, ADV_FLAG_PROXY); + atomic_clear_bit(adv->flags, ADV_FLAG_PROXY_START); - if (ext_adv->adv) { - bt_mesh_adv_unref(ext_adv->adv); - ext_adv->adv = NULL; + if (adv->buf) { + net_buf_unref(adv->buf); + adv->buf = NULL; } - (void)schedule_send(ext_adv); + (void)schedule_send(adv); return; } - atomic_clear_bit(ext_adv->flags, ADV_FLAG_SCHEDULED); + atomic_clear_bit(adv->flags, ADV_FLAG_SCHEDULED); - while ((adv = bt_mesh_adv_get_by_tag(ext_adv->tags, K_NO_WAIT))) { + while ((buf = bt_mesh_adv_buf_get_by_tag(adv->tags, K_NO_WAIT))) { /* busy == 0 means this was canceled */ - if (!adv->ctx.busy) { - bt_mesh_adv_unref(adv); + if (!BT_MESH_ADV(buf)->busy) { + net_buf_unref(buf); continue; } - adv->ctx.busy = 0U; - err = adv_send(ext_adv, adv); + BT_MESH_ADV(buf)->busy = 0U; + err = buf_send(adv, buf); - bt_mesh_adv_unref(adv); + net_buf_unref(buf); if (!err) { return; /* Wait for advertising to finish */ @@ -318,7 +319,7 @@ static void send_pending_adv(struct k_work *work) } if (!IS_ENABLED(CONFIG_BT_MESH_GATT_SERVER) || - !(ext_adv->tags & BT_MESH_ADV_TAG_BIT_PROXY)) { + !(adv->tags & BT_MESH_ADV_TAG_BIT_PROXY)) { return; } @@ -327,51 +328,51 @@ static void send_pending_adv(struct k_work *work) return; } - atomic_set_bit(ext_adv->flags, ADV_FLAG_PROXY_START); + atomic_set_bit(adv->flags, ADV_FLAG_PROXY_START); if (!bt_mesh_adv_gatt_send()) { - atomic_set_bit(ext_adv->flags, ADV_FLAG_PROXY); + atomic_set_bit(adv->flags, ADV_FLAG_PROXY); } - if (atomic_test_and_clear_bit(ext_adv->flags, ADV_FLAG_SCHEDULE_PENDING)) { - schedule_send(ext_adv); + if (atomic_test_and_clear_bit(adv->flags, ADV_FLAG_SCHEDULE_PENDING)) { + schedule_send(adv); } } -static bool schedule_send(struct bt_mesh_ext_adv *ext_adv) +static bool schedule_send(struct bt_mesh_ext_adv *adv) { uint64_t timestamp; int64_t delta; - timestamp = ext_adv->timestamp; + timestamp = adv->timestamp; - if (atomic_test_and_clear_bit(ext_adv->flags, ADV_FLAG_PROXY)) { - atomic_clear_bit(ext_adv->flags, ADV_FLAG_PROXY_START); - (void)bt_le_ext_adv_stop(ext_adv->instance); + if (atomic_test_and_clear_bit(adv->flags, ADV_FLAG_PROXY)) { + atomic_clear_bit(adv->flags, ADV_FLAG_PROXY_START); + (void)bt_le_ext_adv_stop(adv->instance); - atomic_clear_bit(ext_adv->flags, ADV_FLAG_ACTIVE); + atomic_clear_bit(adv->flags, ADV_FLAG_ACTIVE); } - if (atomic_test_bit(ext_adv->flags, ADV_FLAG_ACTIVE)) { - atomic_set_bit(ext_adv->flags, ADV_FLAG_SCHEDULE_PENDING); + if (atomic_test_bit(adv->flags, ADV_FLAG_ACTIVE)) { + atomic_set_bit(adv->flags, ADV_FLAG_SCHEDULE_PENDING); return false; - } else if (atomic_test_and_set_bit(ext_adv->flags, ADV_FLAG_SCHEDULED)) { + } else if (atomic_test_and_set_bit(adv->flags, ADV_FLAG_SCHEDULED)) { return false; } - atomic_clear_bit(ext_adv->flags, ADV_FLAG_SCHEDULE_PENDING); + atomic_clear_bit(adv->flags, ADV_FLAG_SCHEDULE_PENDING); if ((IS_ENABLED(CONFIG_BT_MESH_ADV_EXT_FRIEND_SEPARATE) && - ext_adv->tags & BT_MESH_ADV_TAG_BIT_FRIEND) || - (CONFIG_BT_MESH_RELAY_ADV_SETS > 0 && ext_adv->tags & BT_MESH_ADV_TAG_BIT_RELAY)) { - k_work_reschedule(&ext_adv->work, K_NO_WAIT); + adv->tags & BT_MESH_ADV_TAG_BIT_FRIEND) || + (CONFIG_BT_MESH_RELAY_ADV_SETS > 0 && adv->tags & BT_MESH_ADV_TAG_BIT_RELAY)) { + k_work_reschedule(&adv->work, K_NO_WAIT); } else { /* The controller will send the next advertisement immediately. * Introduce a delay here to avoid sending the next mesh packet closer * to the previous packet than what's permitted by the specification. */ delta = k_uptime_delta(×tamp); - k_work_reschedule(&ext_adv->work, K_MSEC(ADV_INT_FAST_MS - delta)); + k_work_reschedule(&adv->work, K_MSEC(ADV_INT_FAST_MS - delta)); } return true; @@ -382,17 +383,17 @@ void bt_mesh_adv_gatt_update(void) (void)schedule_send(gatt_adv_get()); } -void bt_mesh_adv_local_ready(void) +void bt_mesh_adv_buf_local_ready(void) { (void)schedule_send(advs); } -void bt_mesh_adv_relay_ready(void) +void bt_mesh_adv_buf_relay_ready(void) { - struct bt_mesh_ext_adv *ext_adv = relay_adv_get(); + struct bt_mesh_ext_adv *adv = relay_adv_get(); for (int i = 0; i < CONFIG_BT_MESH_RELAY_ADV_SETS; i++) { - if (schedule_send(&ext_adv[i])) { + if (schedule_send(&adv[i])) { return; } } @@ -403,7 +404,7 @@ void bt_mesh_adv_relay_ready(void) } } -void bt_mesh_adv_friend_ready(void) +void bt_mesh_adv_buf_friend_ready(void) { if (IS_ENABLED(CONFIG_BT_MESH_ADV_EXT_FRIEND_SEPARATE)) { schedule_send(&advs[1 + CONFIG_BT_MESH_RELAY_ADV_SETS]); @@ -412,33 +413,33 @@ void bt_mesh_adv_friend_ready(void) } } -void bt_mesh_adv_terminate(struct bt_mesh_adv *adv) +void bt_mesh_adv_buf_terminate(const struct net_buf *buf) { int err; for (int i = 0; i < ARRAY_SIZE(advs); i++) { - struct bt_mesh_ext_adv *ext_adv = &advs[i]; + struct bt_mesh_ext_adv *adv = &advs[i]; - if (ext_adv->adv != adv) { + if (adv->buf != buf) { continue; } - if (!atomic_test_bit(ext_adv->flags, ADV_FLAG_ACTIVE)) { + if (!atomic_test_bit(adv->flags, ADV_FLAG_ACTIVE)) { return; } - err = bt_le_ext_adv_stop(ext_adv->instance); + err = bt_le_ext_adv_stop(adv->instance); if (err) { LOG_ERR("Failed to stop adv %d", err); return; } /* Do not call `cb:end`, since this user action */ - adv->ctx.cb = NULL; + BT_MESH_ADV(adv->buf)->cb = NULL; - atomic_set_bit(ext_adv->flags, ADV_FLAG_SENT); + atomic_set_bit(adv->flags, ADV_FLAG_SENT); - k_work_submit(&ext_adv->work.work); + k_work_submit(&adv->work.work); return; } @@ -474,31 +475,31 @@ static struct bt_mesh_ext_adv *adv_instance_find(struct bt_le_ext_adv *instance) static void adv_sent(struct bt_le_ext_adv *instance, struct bt_le_ext_adv_sent_info *info) { - struct bt_mesh_ext_adv *ext_adv = adv_instance_find(instance); + struct bt_mesh_ext_adv *adv = adv_instance_find(instance); - if (!ext_adv) { + if (!adv) { LOG_WRN("Unexpected adv instance"); return; } - if (!atomic_test_bit(ext_adv->flags, ADV_FLAG_ACTIVE)) { + if (!atomic_test_bit(adv->flags, ADV_FLAG_ACTIVE)) { return; } - atomic_set_bit(ext_adv->flags, ADV_FLAG_SENT); + atomic_set_bit(adv->flags, ADV_FLAG_SENT); - k_work_submit(&ext_adv->work.work); + k_work_submit(&adv->work.work); } #if defined(CONFIG_BT_MESH_GATT_SERVER) static void connected(struct bt_le_ext_adv *instance, struct bt_le_ext_adv_connected_info *info) { - struct bt_mesh_ext_adv *ext_adv = gatt_adv_get(); + struct bt_mesh_ext_adv *adv = gatt_adv_get(); - if (atomic_test_and_clear_bit(ext_adv->flags, ADV_FLAG_PROXY_START)) { - atomic_clear_bit(ext_adv->flags, ADV_FLAG_ACTIVE); - (void)schedule_send(ext_adv); + if (atomic_test_and_clear_bit(adv->flags, ADV_FLAG_PROXY_START)) { + atomic_clear_bit(adv->flags, ADV_FLAG_ACTIVE); + (void)schedule_send(adv); } } #endif /* CONFIG_BT_MESH_GATT_SERVER */ @@ -574,7 +575,7 @@ int bt_mesh_adv_gatt_start(const struct bt_le_adv_param *param, const struct bt_data *ad, size_t ad_len, const struct bt_data *sd, size_t sd_len) { - struct bt_mesh_ext_adv *ext_adv = gatt_adv_get(); + struct bt_mesh_ext_adv *adv = gatt_adv_get(); struct bt_le_ext_adv_start_param start = { /* Timeout is set in 10 ms steps, with 0 indicating "forever" */ .timeout = (duration == SYS_FOREVER_MS) ? 0 : MAX(1, duration / 10), @@ -582,9 +583,9 @@ int bt_mesh_adv_gatt_start(const struct bt_le_adv_param *param, LOG_DBG("Start advertising %d ms", duration); - atomic_set_bit(ext_adv->flags, ADV_FLAG_UPDATE_PARAMS); + atomic_set_bit(adv->flags, ADV_FLAG_UPDATE_PARAMS); - return adv_start(ext_adv, param, &start, ad, ad_len, sd, sd_len); + return adv_start(adv, param, &start, ad, ad_len, sd, sd_len); } int bt_mesh_adv_bt_data_send(uint8_t num_events, uint16_t adv_interval, diff --git a/subsys/bluetooth/mesh/adv_legacy.c b/subsys/bluetooth/mesh/adv_legacy.c index d4003e497bb..aef13864131 100644 --- a/subsys/bluetooth/mesh/adv_legacy.c +++ b/subsys/bluetooth/mesh/adv_legacy.c @@ -19,6 +19,7 @@ #include "host/hci_core.h" +#include "adv.h" #include "net.h" #include "foundation.h" #include "beacon.h" @@ -42,7 +43,7 @@ static bool enabled; static int bt_data_send(uint8_t num_events, uint16_t adv_int, const struct bt_data *ad, size_t ad_len, - struct bt_mesh_adv_ctx *ctx) + struct bt_mesh_adv *adv) { struct bt_le_adv_param param = {}; uint64_t uptime = k_uptime_get(); @@ -100,8 +101,8 @@ static int bt_data_send(uint8_t num_events, uint16_t adv_int, LOG_DBG("Advertising started. Sleeping %u ms", duration); - if (ctx) { - bt_mesh_adv_send_start(duration, err, ctx); + if (adv) { + bt_mesh_adv_send_start(duration, err, adv); } k_sleep(K_MSEC(duration)); @@ -123,37 +124,37 @@ int bt_mesh_adv_bt_data_send(uint8_t num_events, uint16_t adv_int, return bt_data_send(num_events, adv_int, ad, ad_len, NULL); } -static inline void adv_send(struct bt_mesh_adv *adv) +static inline void buf_send(struct net_buf *buf) { - uint16_t num_events = BT_MESH_TRANSMIT_COUNT(adv->ctx.xmit) + 1; + uint16_t num_events = BT_MESH_TRANSMIT_COUNT(BT_MESH_ADV(buf)->xmit) + 1; uint16_t adv_int; struct bt_data ad; - adv_int = BT_MESH_TRANSMIT_INT(adv->ctx.xmit); + adv_int = BT_MESH_TRANSMIT_INT(BT_MESH_ADV(buf)->xmit); - LOG_DBG("type %u len %u: %s", adv->ctx.type, - adv->b.len, bt_hex(adv->b.data, adv->b.len)); + LOG_DBG("type %u len %u: %s", BT_MESH_ADV(buf)->type, + buf->len, bt_hex(buf->data, buf->len)); - ad.type = bt_mesh_adv_type[adv->ctx.type]; - ad.data_len = adv->b.len; - ad.data = adv->b.data; + ad.type = bt_mesh_adv_type[BT_MESH_ADV(buf)->type]; + ad.data_len = buf->len; + ad.data = buf->data; - bt_data_send(num_events, adv_int, &ad, 1, &adv->ctx); + bt_data_send(num_events, adv_int, &ad, 1, BT_MESH_ADV(buf)); } static void adv_thread(void *p1, void *p2, void *p3) { LOG_DBG("started"); - struct bt_mesh_adv *adv; + struct net_buf *buf; while (enabled) { if (IS_ENABLED(CONFIG_BT_MESH_GATT_SERVER)) { - adv = bt_mesh_adv_get(K_NO_WAIT); - if (IS_ENABLED(CONFIG_BT_MESH_PROXY_SOLICITATION) && !adv) { + buf = bt_mesh_adv_buf_get(K_NO_WAIT); + if (IS_ENABLED(CONFIG_BT_MESH_PROXY_SOLICITATION) && !buf) { (void)bt_mesh_sol_send(); } - while (!adv) { + while (!buf) { /* Adv timeout may be set by a call from proxy * to bt_mesh_adv_gatt_start: @@ -161,58 +162,58 @@ static void adv_thread(void *p1, void *p2, void *p3) adv_timeout = SYS_FOREVER_MS; (void)bt_mesh_adv_gatt_send(); - adv = bt_mesh_adv_get(SYS_TIMEOUT_MS(adv_timeout)); + buf = bt_mesh_adv_buf_get(SYS_TIMEOUT_MS(adv_timeout)); bt_le_adv_stop(); - if (IS_ENABLED(CONFIG_BT_MESH_PROXY_SOLICITATION) && !adv) { + if (IS_ENABLED(CONFIG_BT_MESH_PROXY_SOLICITATION) && !buf) { (void)bt_mesh_sol_send(); } } } else { - adv = bt_mesh_adv_get(K_FOREVER); + buf = bt_mesh_adv_buf_get(K_FOREVER); } - if (!adv) { + if (!buf) { continue; } /* busy == 0 means this was canceled */ - if (adv->ctx.busy) { - adv->ctx.busy = 0U; - adv_send(adv); + if (BT_MESH_ADV(buf)->busy) { + BT_MESH_ADV(buf)->busy = 0U; + buf_send(buf); } - bt_mesh_adv_unref(adv); + net_buf_unref(buf); /* Give other threads a chance to run */ k_yield(); } /* Empty the advertising pool when advertising is disabled */ - while ((adv = bt_mesh_adv_get(K_NO_WAIT))) { - bt_mesh_adv_send_start(0, -ENODEV, &adv->ctx); - bt_mesh_adv_unref(adv); + while ((buf = bt_mesh_adv_buf_get(K_NO_WAIT))) { + bt_mesh_adv_send_start(0, -ENODEV, BT_MESH_ADV(buf)); + net_buf_unref(buf); } } -void bt_mesh_adv_local_ready(void) +void bt_mesh_adv_buf_local_ready(void) { /* Will be handled automatically */ } -void bt_mesh_adv_relay_ready(void) +void bt_mesh_adv_buf_relay_ready(void) { /* Will be handled automatically */ } void bt_mesh_adv_gatt_update(void) { - bt_mesh_adv_get_cancel(); + bt_mesh_adv_buf_get_cancel(); } -void bt_mesh_adv_terminate(struct bt_mesh_adv *adv) +void bt_mesh_adv_buf_terminate(const struct net_buf *buf) { - ARG_UNUSED(adv); + ARG_UNUSED(buf); } void bt_mesh_adv_init(void) diff --git a/subsys/bluetooth/mesh/app_keys.c b/subsys/bluetooth/mesh/app_keys.c index 5afd887a8e8..a47d31447c5 100644 --- a/subsys/bluetooth/mesh/app_keys.c +++ b/subsys/bluetooth/mesh/app_keys.c @@ -17,6 +17,7 @@ #include "rpl.h" #include "settings.h" #include "crypto.h" +#include "adv.h" #include "proxy.h" #include "friend.h" #include "foundation.h" diff --git a/subsys/bluetooth/mesh/beacon.c b/subsys/bluetooth/mesh/beacon.c index ef337f9f510..afdea5b4c6a 100644 --- a/subsys/bluetooth/mesh/beacon.c +++ b/subsys/bluetooth/mesh/beacon.c @@ -16,6 +16,7 @@ #include "common/bt_str.h" +#include "adv.h" #include "mesh.h" #include "net.h" #include "prov.h" @@ -255,7 +256,7 @@ static bool net_beacon_send(struct bt_mesh_subnet *sub, struct bt_mesh_beacon *b .end = beacon_complete, }; uint32_t now = k_uptime_get_32(); - struct bt_mesh_adv *adv; + struct net_buf *buf; uint32_t time_diff; uint32_t time_since_last_recv; int err; @@ -270,19 +271,19 @@ static bool net_beacon_send(struct bt_mesh_subnet *sub, struct bt_mesh_beacon *b return false; } - adv = bt_mesh_adv_create(BT_MESH_ADV_BEACON, BT_MESH_ADV_TAG_LOCAL, + buf = bt_mesh_adv_create(BT_MESH_ADV_BEACON, BT_MESH_ADV_TAG_LOCAL, PROV_XMIT, K_NO_WAIT); - if (!adv) { - LOG_ERR("Unable to allocate beacon adv"); + if (!buf) { + LOG_ERR("Unable to allocate beacon buffer"); return true; /* Bail out */ } - err = beacon_create(sub, &adv->b); + err = beacon_create(sub, &buf->b); if (!err) { - bt_mesh_adv_send(adv, &send_cb, beacon); + bt_mesh_adv_send(buf, &send_cb, beacon); } - bt_mesh_adv_unref(adv); + net_buf_unref(buf); return err != 0; } @@ -329,22 +330,22 @@ static int unprovisioned_beacon_send(void) { const struct bt_mesh_prov *prov; uint8_t uri_hash[16] = { 0 }; - struct bt_mesh_adv *adv; + struct net_buf *buf; uint16_t oob_info; LOG_DBG(""); - adv = bt_mesh_adv_create(BT_MESH_ADV_BEACON, BT_MESH_ADV_TAG_LOCAL, + buf = bt_mesh_adv_create(BT_MESH_ADV_BEACON, BT_MESH_ADV_TAG_LOCAL, UNPROV_XMIT, K_NO_WAIT); - if (!adv) { - LOG_ERR("Unable to allocate beacon adv"); + if (!buf) { + LOG_ERR("Unable to allocate beacon buffer"); return -ENOBUFS; } prov = bt_mesh_prov_get(); - net_buf_simple_add_u8(&adv->b, BEACON_TYPE_UNPROVISIONED); - net_buf_simple_add_mem(&adv->b, prov->uuid, 16); + net_buf_add_u8(buf, BEACON_TYPE_UNPROVISIONED); + net_buf_add_mem(buf, prov->uuid, 16); if (prov->uri && bt_mesh_s1_str(prov->uri, uri_hash) == 0) { oob_info = prov->oob_info | BT_MESH_PROV_OOB_URI; @@ -352,31 +353,31 @@ static int unprovisioned_beacon_send(void) oob_info = prov->oob_info; } - net_buf_simple_add_be16(&adv->b, oob_info); - net_buf_simple_add_mem(&adv->b, uri_hash, 4); + net_buf_add_be16(buf, oob_info); + net_buf_add_mem(buf, uri_hash, 4); - bt_mesh_adv_send(adv, NULL, NULL); - bt_mesh_adv_unref(adv); + bt_mesh_adv_send(buf, NULL, NULL); + net_buf_unref(buf); if (prov->uri) { size_t len; - adv = bt_mesh_adv_create(BT_MESH_ADV_URI, BT_MESH_ADV_TAG_LOCAL, + buf = bt_mesh_adv_create(BT_MESH_ADV_URI, BT_MESH_ADV_TAG_LOCAL, UNPROV_XMIT, K_NO_WAIT); - if (!adv) { - LOG_ERR("Unable to allocate URI adv"); + if (!buf) { + LOG_ERR("Unable to allocate URI buffer"); return -ENOBUFS; } len = strlen(prov->uri); - if (net_buf_simple_tailroom(&adv->b) < len) { + if (net_buf_tailroom(buf) < len) { LOG_WRN("Too long URI to fit advertising data"); } else { - net_buf_simple_add_mem(&adv->b, prov->uri, len); - bt_mesh_adv_send(adv, NULL, NULL); + net_buf_add_mem(buf, prov->uri, len); + bt_mesh_adv_send(buf, NULL, NULL); } - bt_mesh_adv_unref(adv); + net_buf_unref(buf); } return 0; diff --git a/subsys/bluetooth/mesh/cfg.c b/subsys/bluetooth/mesh/cfg.c index 4fef60d5c8d..c7bea0d29b0 100644 --- a/subsys/bluetooth/mesh/cfg.c +++ b/subsys/bluetooth/mesh/cfg.c @@ -14,6 +14,7 @@ #include "settings.h" #include "heartbeat.h" #include "friend.h" +#include "adv.h" #include "cfg.h" #include "od_priv_proxy.h" #include "priv_beacon.h" diff --git a/subsys/bluetooth/mesh/cfg_srv.c b/subsys/bluetooth/mesh/cfg_srv.c index 268f883d8b8..fa6bb48703a 100644 --- a/subsys/bluetooth/mesh/cfg_srv.c +++ b/subsys/bluetooth/mesh/cfg_srv.c @@ -21,6 +21,7 @@ #include "host/testing.h" #include "mesh.h" +#include "adv.h" #include "net.h" #include "rpl.h" #include "lpn.h" diff --git a/subsys/bluetooth/mesh/friend.c b/subsys/bluetooth/mesh/friend.c index 6fbd9f81a68..73b75eadf4f 100644 --- a/subsys/bluetooth/mesh/friend.c +++ b/subsys/bluetooth/mesh/friend.c @@ -13,6 +13,7 @@ #include #include "crypto.h" +#include "adv.h" #include "mesh.h" #include "net.h" #include "app_keys.h" @@ -1238,7 +1239,7 @@ static void friend_timeout(struct k_work *work) .start = buf_send_start, .end = buf_send_end, }; - struct bt_mesh_adv *adv; + struct net_buf *buf; uint8_t md; if (!friend_is_allocated(frnd)) { @@ -1280,19 +1281,19 @@ static void friend_timeout(struct k_work *work) frnd->queue_size--; send_last: - adv = bt_mesh_adv_create(BT_MESH_ADV_DATA, BT_MESH_ADV_TAG_FRIEND, + buf = bt_mesh_adv_create(BT_MESH_ADV_DATA, BT_MESH_ADV_TAG_FRIEND, FRIEND_XMIT, K_NO_WAIT); - if (!adv) { - LOG_ERR("Unable to allocate friend adv"); + if (!buf) { + LOG_ERR("Unable to allocate friend adv buffer"); return; } - net_buf_simple_add_mem(&adv->b, frnd->last->data, frnd->last->len); + net_buf_add_mem(buf, frnd->last->data, frnd->last->len); frnd->pending_req = 0U; frnd->pending_buf = 1U; - bt_mesh_adv_send(adv, &buf_sent_cb, frnd); - bt_mesh_adv_unref(adv); + bt_mesh_adv_send(buf, &buf_sent_cb, frnd); + net_buf_unref(buf); } static void subnet_evt(struct bt_mesh_subnet *sub, enum bt_mesh_key_evt evt) diff --git a/subsys/bluetooth/mesh/gatt_cli.c b/subsys/bluetooth/mesh/gatt_cli.c index 7814f32f27f..bff9b567011 100644 --- a/subsys/bluetooth/mesh/gatt_cli.c +++ b/subsys/bluetooth/mesh/gatt_cli.c @@ -18,6 +18,7 @@ #include "common/bt_str.h" #include "mesh.h" +#include "adv.h" #include "net.h" #include "rpl.h" #include "transport.h" diff --git a/subsys/bluetooth/mesh/health_srv.c b/subsys/bluetooth/mesh/health_srv.c index 3db3410aa34..8611e1004f6 100644 --- a/subsys/bluetooth/mesh/health_srv.c +++ b/subsys/bluetooth/mesh/health_srv.c @@ -16,6 +16,7 @@ #include #include "mesh.h" +#include "adv.h" #include "net.h" #include "transport.h" #include "access.h" diff --git a/subsys/bluetooth/mesh/lpn.c b/subsys/bluetooth/mesh/lpn.c index f6f906b12fe..2b655f729f3 100644 --- a/subsys/bluetooth/mesh/lpn.c +++ b/subsys/bluetooth/mesh/lpn.c @@ -13,6 +13,7 @@ #include #include "crypto.h" +#include "adv.h" #include "mesh.h" #include "net.h" #include "transport.h" diff --git a/subsys/bluetooth/mesh/main.c b/subsys/bluetooth/mesh/main.c index 89115ebe3e8..24bbd7c7e94 100644 --- a/subsys/bluetooth/mesh/main.c +++ b/subsys/bluetooth/mesh/main.c @@ -18,6 +18,7 @@ #include #include "test.h" +#include "adv.h" #include "prov.h" #include "provisioner.h" #include "net.h" diff --git a/subsys/bluetooth/mesh/net.c b/subsys/bluetooth/mesh/net.c index 943a5e83c23..6a9f29b4064 100644 --- a/subsys/bluetooth/mesh/net.c +++ b/subsys/bluetooth/mesh/net.c @@ -20,6 +20,7 @@ #include "common/bt_str.h" #include "crypto.h" +#include "adv.h" #include "mesh.h" #include "net.h" #include "rpl.h" @@ -525,19 +526,19 @@ static int net_loopback(const struct bt_mesh_net_tx *tx, const uint8_t *data, return 0; } -int bt_mesh_net_send(struct bt_mesh_net_tx *tx, struct bt_mesh_adv *adv, +int bt_mesh_net_send(struct bt_mesh_net_tx *tx, struct net_buf *buf, const struct bt_mesh_send_cb *cb, void *cb_data) { const struct bt_mesh_net_cred *cred; int err; LOG_DBG("src 0x%04x dst 0x%04x len %u headroom %zu tailroom %zu", tx->src, tx->ctx->addr, - adv->b.len, net_buf_simple_headroom(&adv->b), net_buf_simple_tailroom(&adv->b)); - LOG_DBG("Payload len %u: %s", adv->b.len, bt_hex(adv->b.data, adv->b.len)); + buf->len, net_buf_headroom(buf), net_buf_tailroom(buf)); + LOG_DBG("Payload len %u: %s", buf->len, bt_hex(buf->data, buf->len)); LOG_DBG("Seq 0x%06x", bt_mesh.seq); cred = net_tx_cred_get(tx); - err = net_header_encode(tx, cred->nid, &adv->b); + err = net_header_encode(tx, cred->nid, &buf->b); if (err) { goto done; } @@ -545,7 +546,7 @@ int bt_mesh_net_send(struct bt_mesh_net_tx *tx, struct bt_mesh_adv *adv, /* Deliver to local network interface if necessary */ if (bt_mesh_fixed_group_match(tx->ctx->addr) || bt_mesh_has_addr(tx->ctx->addr)) { - err = net_loopback(tx, adv->b.data, adv->b.len); + err = net_loopback(tx, buf->data, buf->len); /* Local unicast messages should not go out to network */ if (BT_MESH_ADDR_IS_UNICAST(tx->ctx->addr) || @@ -568,28 +569,28 @@ int bt_mesh_net_send(struct bt_mesh_net_tx *tx, struct bt_mesh_adv *adv, goto done; } - err = net_encrypt(&adv->b, cred, BT_MESH_NET_IVI_TX, BT_MESH_NONCE_NETWORK); + err = net_encrypt(&buf->b, cred, BT_MESH_NET_IVI_TX, BT_MESH_NONCE_NETWORK); if (err) { goto done; } - adv->ctx.cb = cb; - adv->ctx.cb_data = cb_data; + BT_MESH_ADV(buf)->cb = cb; + BT_MESH_ADV(buf)->cb_data = cb_data; /* Deliver to GATT Proxy Clients if necessary. */ if (IS_ENABLED(CONFIG_BT_MESH_GATT_PROXY)) { - (void)bt_mesh_proxy_relay(adv, tx->ctx->addr); + (void)bt_mesh_proxy_relay(buf, tx->ctx->addr); } /* Deliver to GATT Proxy Servers if necessary. */ if (IS_ENABLED(CONFIG_BT_MESH_PROXY_CLIENT)) { - (void)bt_mesh_proxy_cli_relay(adv); + (void)bt_mesh_proxy_cli_relay(buf); } - bt_mesh_adv_send(adv, cb, cb_data); + bt_mesh_adv_send(buf, cb, cb_data); done: - bt_mesh_adv_unref(adv); + net_buf_unref(buf); return err; } @@ -683,7 +684,7 @@ static void bt_mesh_net_relay(struct net_buf_simple *sbuf, struct bt_mesh_net_rx *rx) { const struct bt_mesh_net_cred *cred; - struct bt_mesh_adv *adv; + struct net_buf *buf; uint8_t transmit; if (rx->ctx.recv_ttl <= 1U) { @@ -710,10 +711,10 @@ static void bt_mesh_net_relay(struct net_buf_simple *sbuf, transmit = bt_mesh_net_transmit_get(); } - adv = bt_mesh_adv_create(BT_MESH_ADV_DATA, BT_MESH_ADV_TAG_RELAY, + buf = bt_mesh_adv_create(BT_MESH_ADV_DATA, BT_MESH_ADV_TAG_RELAY, transmit, K_NO_WAIT); - if (!adv) { - LOG_DBG("Out of relay advs"); + if (!buf) { + LOG_DBG("Out of relay buffers"); return; } @@ -721,23 +722,23 @@ static void bt_mesh_net_relay(struct net_buf_simple *sbuf, sbuf->data[1] &= 0x80; sbuf->data[1] |= rx->ctx.recv_ttl - 1U; - net_buf_simple_add_mem(&adv->b, sbuf->data, sbuf->len); + net_buf_add_mem(buf, sbuf->data, sbuf->len); cred = &rx->sub->keys[SUBNET_KEY_TX_IDX(rx->sub)].msg; - LOG_DBG("Relaying packet. TTL is now %u", TTL(adv->b.data)); + LOG_DBG("Relaying packet. TTL is now %u", TTL(buf->data)); /* Update NID if RX or RX was with friend credentials */ if (rx->friend_cred) { - adv->b.data[0] &= 0x80; /* Clear everything except IVI */ - adv->b.data[0] |= cred->nid; + buf->data[0] &= 0x80; /* Clear everything except IVI */ + buf->data[0] |= cred->nid; } /* We re-encrypt and obfuscate using the received IVI rather than * the normal TX IVI (which may be different) since the transport * layer nonce includes the IVI. */ - if (net_encrypt(&adv->b, cred, BT_MESH_NET_IVI_RX(rx), BT_MESH_NONCE_NETWORK)) { + if (net_encrypt(&buf->b, cred, BT_MESH_NET_IVI_RX(rx), BT_MESH_NONCE_NETWORK)) { LOG_ERR("Re-encrypting failed"); goto done; } @@ -750,15 +751,15 @@ static void bt_mesh_net_relay(struct net_buf_simple *sbuf, (rx->friend_cred || bt_mesh_gatt_proxy_get() == BT_MESH_GATT_PROXY_ENABLED || bt_mesh_priv_gatt_proxy_get() == BT_MESH_PRIV_GATT_PROXY_ENABLED)) { - bt_mesh_proxy_relay(adv, rx->ctx.recv_dst); + bt_mesh_proxy_relay(buf, rx->ctx.recv_dst); } if (relay_to_adv(rx->net_if) || rx->friend_cred) { - bt_mesh_adv_send(adv, NULL, NULL); + bt_mesh_adv_send(buf, NULL, NULL); } done: - bt_mesh_adv_unref(adv); + net_buf_unref(buf); } void bt_mesh_net_header_parse(struct net_buf_simple *buf, diff --git a/subsys/bluetooth/mesh/net.h b/subsys/bluetooth/mesh/net.h index 28c21da3eaf..04179a4dd49 100644 --- a/subsys/bluetooth/mesh/net.h +++ b/subsys/bluetooth/mesh/net.h @@ -4,7 +4,6 @@ * SPDX-License-Identifier: Apache-2.0 */ -#include "adv.h" #include "subnet.h" #include @@ -292,7 +291,7 @@ bool bt_mesh_net_iv_update(uint32_t iv_index, bool iv_update); int bt_mesh_net_encode(struct bt_mesh_net_tx *tx, struct net_buf_simple *buf, enum bt_mesh_nonce_type type); -int bt_mesh_net_send(struct bt_mesh_net_tx *tx, struct bt_mesh_adv *adv, +int bt_mesh_net_send(struct bt_mesh_net_tx *tx, struct net_buf *buf, const struct bt_mesh_send_cb *cb, void *cb_data); int bt_mesh_net_decode(struct net_buf_simple *in, enum bt_mesh_net_if net_if, diff --git a/subsys/bluetooth/mesh/pb_adv.c b/subsys/bluetooth/mesh/pb_adv.c index f723ff48c14..e273739ed72 100644 --- a/subsys/bluetooth/mesh/pb_adv.c +++ b/subsys/bluetooth/mesh/pb_adv.c @@ -11,6 +11,7 @@ #include #include "host/testing.h" #include "net.h" +#include "adv.h" #include "crypto.h" #include "beacon.h" #include "prov.h" @@ -100,8 +101,8 @@ struct pb_adv { /* Transaction timeout in seconds */ uint8_t timeout; - /* Pending outgoing adv(s) */ - struct bt_mesh_adv *adv[3]; + /* Pending outgoing buffer(s) */ + struct net_buf *buf[3]; prov_bearer_send_complete_t cb; @@ -169,24 +170,24 @@ static void free_segments(void) { int i; - for (i = 0; i < ARRAY_SIZE(link.tx.adv); i++) { - struct bt_mesh_adv *adv = link.tx.adv[i]; + for (i = 0; i < ARRAY_SIZE(link.tx.buf); i++) { + struct net_buf *buf = link.tx.buf[i]; - if (!adv) { + if (!buf) { break; } - link.tx.adv[i] = NULL; + link.tx.buf[i] = NULL; /* Terminate active adv */ - if (adv->ctx.busy == 0U) { - bt_mesh_adv_terminate(adv); + if (BT_MESH_ADV(buf)->busy == 0U) { + bt_mesh_adv_buf_terminate(buf); } else { /* Mark as canceled */ - adv->ctx.busy = 0U; + BT_MESH_ADV(buf)->busy = 0U; } - bt_mesh_adv_unref(adv); + net_buf_unref(buf); } } @@ -199,7 +200,7 @@ static void prov_clear_tx(void) { LOG_DBG(""); - /* If this fails, the work handler will not find any advs to send, + /* If this fails, the work handler will not find any buffers to send, * and return without rescheduling. The work handler also checks the * LINK_ACTIVE flag, so if this call is part of reset_adv_link, it'll * exit early. @@ -253,19 +254,19 @@ static void close_link(enum prov_bearer_link_status reason) cb->link_closed(&bt_mesh_pb_adv, cb_data, reason); } -static struct bt_mesh_adv *adv_create(uint8_t retransmits) +static struct net_buf *adv_buf_create(uint8_t retransmits) { - struct bt_mesh_adv *adv; + struct net_buf *buf; - adv = bt_mesh_adv_create(BT_MESH_ADV_PROV, BT_MESH_ADV_TAG_PROV, + buf = bt_mesh_adv_create(BT_MESH_ADV_PROV, BT_MESH_ADV_TAG_PROV, BT_MESH_TRANSMIT(retransmits, 20), BUF_TIMEOUT); - if (!adv) { - LOG_ERR("Out of provisioning advs"); + if (!buf) { + LOG_ERR("Out of provisioning buffers"); return NULL; } - return adv; + return buf; } static void ack_complete(uint16_t duration, int err, void *user_data) @@ -327,7 +328,7 @@ static void gen_prov_ack_send(uint8_t xact_id) .start = ack_complete, }; const struct bt_mesh_send_cb *complete; - struct bt_mesh_adv *adv; + struct net_buf *buf; bool pending = atomic_test_and_set_bit(link.flags, ADV_ACK_PENDING); LOG_DBG("xact_id 0x%x", xact_id); @@ -337,8 +338,8 @@ static void gen_prov_ack_send(uint8_t xact_id) return; } - adv = adv_create(RETRANSMITS_ACK); - if (!adv) { + buf = adv_buf_create(RETRANSMITS_ACK); + if (!buf) { atomic_clear_bit(link.flags, ADV_ACK_PENDING); return; } @@ -350,12 +351,12 @@ static void gen_prov_ack_send(uint8_t xact_id) complete = &cb; } - net_buf_simple_add_be32(&adv->b, link.id); - net_buf_simple_add_u8(&adv->b, xact_id); - net_buf_simple_add_u8(&adv->b, GPC_ACK); + net_buf_add_be32(buf, link.id); + net_buf_add_u8(buf, xact_id); + net_buf_add_u8(buf, GPC_ACK); - bt_mesh_adv_send(adv, complete, NULL); - bt_mesh_adv_unref(adv); + bt_mesh_adv_send(buf, complete, NULL); + net_buf_unref(buf); } static void gen_prov_cont(struct prov_rx *rx, struct net_buf_simple *buf) @@ -430,7 +431,7 @@ static void gen_prov_ack(struct prov_rx *rx, struct net_buf_simple *buf) { LOG_DBG("len %u", buf->len); - if (!link.tx.adv[0]) { + if (!link.tx.buf[0]) { return; } @@ -595,20 +596,20 @@ static void send_reliable(void) { int i; - for (i = 0; i < ARRAY_SIZE(link.tx.adv); i++) { - struct bt_mesh_adv *adv = link.tx.adv[i]; + for (i = 0; i < ARRAY_SIZE(link.tx.buf); i++) { + struct net_buf *buf = link.tx.buf[i]; - if (!adv) { + if (!buf) { break; } - if (adv->ctx.busy) { + if (BT_MESH_ADV(buf)->busy) { continue; } - LOG_DBG("%u bytes: %s", adv->b.len, bt_hex(adv->b.data, adv->b.len)); + LOG_DBG("%u bytes: %s", buf->len, bt_hex(buf->data, buf->len)); - bt_mesh_adv_send(adv, NULL, NULL); + bt_mesh_adv_send(buf, NULL, NULL); } k_work_reschedule(&link.tx.retransmit, RETRANSMIT_TIMEOUT); @@ -632,30 +633,30 @@ static void prov_retransmit(struct k_work *work) send_reliable(); } -static struct bt_mesh_adv *ctl_adv_create(uint8_t op, const void *data, uint8_t data_len, - uint8_t retransmits) +static struct net_buf *ctl_buf_create(uint8_t op, const void *data, uint8_t data_len, + uint8_t retransmits) { - struct bt_mesh_adv *adv; + struct net_buf *buf; LOG_DBG("op 0x%02x data_len %u", op, data_len); - adv = adv_create(retransmits); - if (!adv) { + buf = adv_buf_create(retransmits); + if (!buf) { return NULL; } - net_buf_simple_add_be32(&adv->b, link.id); + net_buf_add_be32(buf, link.id); /* Transaction ID, always 0 for Bearer messages */ - net_buf_simple_add_u8(&adv->b, 0x00); - net_buf_simple_add_u8(&adv->b, GPC_CTL(op)); - net_buf_simple_add_mem(&adv->b, data, data_len); + net_buf_add_u8(buf, 0x00); + net_buf_add_u8(buf, GPC_CTL(op)); + net_buf_add_mem(buf, data, data_len); - return adv; + return buf; } -static int bearer_ctl_send(struct bt_mesh_adv *adv) +static int bearer_ctl_send(struct net_buf *buf) { - if (!adv) { + if (!buf) { return -ENOMEM; } @@ -663,23 +664,23 @@ static int bearer_ctl_send(struct bt_mesh_adv *adv) k_work_reschedule(&link.prot_timer, bt_mesh_prov_protocol_timeout_get()); link.tx.start = k_uptime_get(); - link.tx.adv[0] = adv; + link.tx.buf[0] = buf; send_reliable(); return 0; } -static int bearer_ctl_send_unacked(struct bt_mesh_adv *adv, void *user_data) +static int bearer_ctl_send_unacked(struct net_buf *buf, void *user_data) { - if (!adv) { + if (!buf) { return -ENOMEM; } prov_clear_tx(); k_work_reschedule(&link.prot_timer, bt_mesh_prov_protocol_timeout_get()); - bt_mesh_adv_send(adv, &buf_sent_cb, user_data); - bt_mesh_adv_unref(adv); + bt_mesh_adv_send(buf, &buf_sent_cb, user_data); + net_buf_unref(buf); return 0; } @@ -687,26 +688,26 @@ static int bearer_ctl_send_unacked(struct bt_mesh_adv *adv, void *user_data) static int prov_send_adv(struct net_buf_simple *msg, prov_bearer_send_complete_t cb, void *cb_data) { - struct bt_mesh_adv *start, *adv; + struct net_buf *start, *buf; uint8_t seg_len, seg_id; prov_clear_tx(); k_work_reschedule(&link.prot_timer, bt_mesh_prov_protocol_timeout_get()); - start = adv_create(RETRANSMITS_RELIABLE); + start = adv_buf_create(RETRANSMITS_RELIABLE); if (!start) { return -ENOBUFS; } link.tx.id = next_transaction_id(link.tx.id); - net_buf_simple_add_be32(&start->b, link.id); - net_buf_simple_add_u8(&start->b, link.tx.id); + net_buf_add_be32(start, link.id); + net_buf_add_u8(start, link.tx.id); - net_buf_simple_add_u8(&start->b, GPC_START(last_seg(msg->len))); - net_buf_simple_add_be16(&start->b, msg->len); - net_buf_simple_add_u8(&start->b, bt_mesh_fcs_calc(msg->data, msg->len)); + net_buf_add_u8(start, GPC_START(last_seg(msg->len))); + net_buf_add_be16(start, msg->len); + net_buf_add_u8(start, bt_mesh_fcs_calc(msg->data, msg->len)); - link.tx.adv[0] = start; + link.tx.buf[0] = start; link.tx.cb = cb; link.tx.cb_data = cb_data; link.tx.start = k_uptime_get(); @@ -715,33 +716,33 @@ static int prov_send_adv(struct net_buf_simple *msg, seg_len = MIN(msg->len, START_PAYLOAD_MAX); LOG_DBG("seg 0 len %u: %s", seg_len, bt_hex(msg->data, seg_len)); - net_buf_simple_add_mem(&start->b, msg->data, seg_len); + net_buf_add_mem(start, msg->data, seg_len); net_buf_simple_pull(msg, seg_len); - adv = start; + buf = start; for (seg_id = 1U; msg->len > 0; seg_id++) { - if (seg_id >= ARRAY_SIZE(link.tx.adv)) { + if (seg_id >= ARRAY_SIZE(link.tx.buf)) { LOG_ERR("Too big message"); free_segments(); return -E2BIG; } - adv = adv_create(RETRANSMITS_RELIABLE); - if (!adv) { + buf = adv_buf_create(RETRANSMITS_RELIABLE); + if (!buf) { free_segments(); return -ENOBUFS; } - link.tx.adv[seg_id] = adv; + link.tx.buf[seg_id] = buf; seg_len = MIN(msg->len, CONT_PAYLOAD_MAX); LOG_DBG("seg %u len %u: %s", seg_id, seg_len, bt_hex(msg->data, seg_len)); - net_buf_simple_add_be32(&adv->b, link.id); - net_buf_simple_add_u8(&adv->b, link.tx.id); - net_buf_simple_add_u8(&adv->b, GPC_CONT(seg_id)); - net_buf_simple_add_mem(&adv->b, msg->data, seg_len); + net_buf_add_be32(buf, link.id); + net_buf_add_u8(buf, link.tx.id); + net_buf_add_u8(buf, GPC_CONT(seg_id)); + net_buf_add_mem(buf, msg->data, seg_len); net_buf_simple_pull(msg, seg_len); } @@ -775,7 +776,7 @@ static void link_open(struct prov_rx *rx, struct net_buf_simple *buf) LOG_DBG("Resending link ack"); /* Ignore errors, message will be attempted again if we keep receiving link open: */ (void)bearer_ctl_send_unacked( - ctl_adv_create(LINK_ACK, NULL, 0, RETRANSMITS_ACK), + ctl_buf_create(LINK_ACK, NULL, 0, RETRANSMITS_ACK), (void *)PROV_BEARER_LINK_STATUS_SUCCESS); return; } @@ -790,7 +791,7 @@ static void link_open(struct prov_rx *rx, struct net_buf_simple *buf) net_buf_simple_reset(link.rx.buf); err = bearer_ctl_send_unacked( - ctl_adv_create(LINK_ACK, NULL, 0, RETRANSMITS_ACK), + ctl_buf_create(LINK_ACK, NULL, 0, RETRANSMITS_ACK), (void *)PROV_BEARER_LINK_STATUS_SUCCESS); if (err) { reset_adv_link(); @@ -890,7 +891,7 @@ static int prov_link_open(const uint8_t uuid[16], uint8_t timeout, net_buf_simple_reset(link.rx.buf); - return bearer_ctl_send(ctl_adv_create(LINK_OPEN, uuid, 16, RETRANSMITS_RELIABLE)); + return bearer_ctl_send(ctl_buf_create(LINK_OPEN, uuid, 16, RETRANSMITS_RELIABLE)); } static int prov_link_accept(const struct prov_bearer_cb *cb, void *cb_data) @@ -935,7 +936,7 @@ static void prov_link_close(enum prov_bearer_link_status status) link.tx.timeout = CLOSING_TIMEOUT; /* Ignore errors, the link will time out eventually if this doesn't get sent */ bearer_ctl_send_unacked( - ctl_adv_create(LINK_CLOSE, &status, 1, RETRANSMITS_LINK_CLOSE), + ctl_buf_create(LINK_CLOSE, &status, 1, RETRANSMITS_LINK_CLOSE), (void *)status); } diff --git a/subsys/bluetooth/mesh/pb_gatt.c b/subsys/bluetooth/mesh/pb_gatt.c index 849914f4b5f..f8acc8f6c5a 100644 --- a/subsys/bluetooth/mesh/pb_gatt.c +++ b/subsys/bluetooth/mesh/pb_gatt.c @@ -8,6 +8,7 @@ #include #include "net.h" #include "proxy.h" +#include "adv.h" #include "prov.h" #include "pb_gatt.h" #include "proxy_msg.h" diff --git a/subsys/bluetooth/mesh/pb_gatt_cli.c b/subsys/bluetooth/mesh/pb_gatt_cli.c index bf7dc14029a..9231cc0f0b1 100644 --- a/subsys/bluetooth/mesh/pb_gatt_cli.c +++ b/subsys/bluetooth/mesh/pb_gatt_cli.c @@ -16,6 +16,7 @@ #include #include "mesh.h" +#include "adv.h" #include "net.h" #include "rpl.h" #include "transport.h" diff --git a/subsys/bluetooth/mesh/pb_gatt_srv.c b/subsys/bluetooth/mesh/pb_gatt_srv.c index f4fdac53570..f6d9298fc78 100644 --- a/subsys/bluetooth/mesh/pb_gatt_srv.c +++ b/subsys/bluetooth/mesh/pb_gatt_srv.c @@ -17,6 +17,7 @@ #include "common/bt_str.h" #include "mesh.h" +#include "adv.h" #include "net.h" #include "rpl.h" #include "transport.h" diff --git a/subsys/bluetooth/mesh/priv_beacon_srv.c b/subsys/bluetooth/mesh/priv_beacon_srv.c index 98be589fc22..5b5e62f1736 100644 --- a/subsys/bluetooth/mesh/priv_beacon_srv.c +++ b/subsys/bluetooth/mesh/priv_beacon_srv.c @@ -5,6 +5,7 @@ */ #include #include "net.h" +#include "adv.h" #include #include "proxy.h" #include "foundation.h" diff --git a/subsys/bluetooth/mesh/prov_device.c b/subsys/bluetooth/mesh/prov_device.c index 6ca65c2ec63..af890396ac7 100644 --- a/subsys/bluetooth/mesh/prov_device.c +++ b/subsys/bluetooth/mesh/prov_device.c @@ -20,6 +20,7 @@ #include "common/bt_str.h" #include "crypto.h" +#include "adv.h" #include "mesh.h" #include "net.h" #include "rpl.h" diff --git a/subsys/bluetooth/mesh/provisioner.c b/subsys/bluetooth/mesh/provisioner.c index ba02723e830..aba2449892f 100644 --- a/subsys/bluetooth/mesh/provisioner.c +++ b/subsys/bluetooth/mesh/provisioner.c @@ -21,6 +21,7 @@ #include "common/bt_str.h" #include "crypto.h" +#include "adv.h" #include "mesh.h" #include "net.h" #include "rpl.h" diff --git a/subsys/bluetooth/mesh/proxy.h b/subsys/bluetooth/mesh/proxy.h index 34a119c3df6..a2f6bb45ff6 100644 --- a/subsys/bluetooth/mesh/proxy.h +++ b/subsys/bluetooth/mesh/proxy.h @@ -34,6 +34,6 @@ int bt_mesh_proxy_adv_start(void); void bt_mesh_proxy_identity_start(struct bt_mesh_subnet *sub, bool private); void bt_mesh_proxy_identity_stop(struct bt_mesh_subnet *sub); -bool bt_mesh_proxy_relay(struct bt_mesh_adv *adv, uint16_t dst); +bool bt_mesh_proxy_relay(struct net_buf *buf, uint16_t dst); void bt_mesh_proxy_addr_add(struct net_buf_simple *buf, uint16_t addr); uint8_t bt_mesh_proxy_srv_connected_cnt(void); diff --git a/subsys/bluetooth/mesh/proxy_cli.c b/subsys/bluetooth/mesh/proxy_cli.c index 5dd6b02361f..a0a25751b41 100644 --- a/subsys/bluetooth/mesh/proxy_cli.c +++ b/subsys/bluetooth/mesh/proxy_cli.c @@ -16,6 +16,7 @@ #include #include "mesh.h" +#include "adv.h" #include "net.h" #include "rpl.h" #include "transport.h" @@ -78,7 +79,7 @@ static struct bt_mesh_proxy_server *find_proxy_srv_by_conn(struct bt_conn *conn) return NULL; } -bool bt_mesh_proxy_cli_relay(struct bt_mesh_adv *adv) +bool bt_mesh_proxy_cli_relay(struct net_buf *buf) { bool relayed = false; int i; @@ -90,7 +91,7 @@ bool bt_mesh_proxy_cli_relay(struct bt_mesh_adv *adv) continue; } - if (bt_mesh_proxy_relay_send(server->role->conn, adv)) { + if (bt_mesh_proxy_relay_send(server->role->conn, buf)) { continue; } diff --git a/subsys/bluetooth/mesh/proxy_cli.h b/subsys/bluetooth/mesh/proxy_cli.h index c0b69f4aaf6..8c1fae10e84 100644 --- a/subsys/bluetooth/mesh/proxy_cli.h +++ b/subsys/bluetooth/mesh/proxy_cli.h @@ -8,6 +8,6 @@ void bt_mesh_proxy_cli_adv_recv(const struct bt_le_scan_recv_info *info, struct net_buf_simple *buf); -bool bt_mesh_proxy_cli_relay(struct bt_mesh_adv *adv); +bool bt_mesh_proxy_cli_relay(struct net_buf *buf); bool bt_mesh_proxy_cli_is_connected(uint16_t net_idx); diff --git a/subsys/bluetooth/mesh/proxy_msg.c b/subsys/bluetooth/mesh/proxy_msg.c index b2fa113d456..025909e0503 100644 --- a/subsys/bluetooth/mesh/proxy_msg.c +++ b/subsys/bluetooth/mesh/proxy_msg.c @@ -21,6 +21,7 @@ #include "common/bt_str.h" #include "mesh.h" +#include "adv.h" #include "net.h" #include "rpl.h" #include "transport.h" @@ -195,12 +196,12 @@ int bt_mesh_proxy_msg_send(struct bt_conn *conn, uint8_t type, static void buf_send_end(struct bt_conn *conn, void *user_data) { - struct bt_mesh_adv *adv = user_data; + struct net_buf *buf = user_data; - bt_mesh_adv_unref(adv); + net_buf_unref(buf); } -int bt_mesh_proxy_relay_send(struct bt_conn *conn, struct bt_mesh_adv *adv) +int bt_mesh_proxy_relay_send(struct bt_conn *conn, struct net_buf *buf) { int err; @@ -210,12 +211,12 @@ int bt_mesh_proxy_relay_send(struct bt_conn *conn, struct bt_mesh_adv *adv) * so we need to make a copy. */ net_buf_simple_reserve(&msg, 1); - net_buf_simple_add_mem(&msg, adv->b.data, adv->b.len); + net_buf_simple_add_mem(&msg, buf->data, buf->len); err = bt_mesh_proxy_msg_send(conn, BT_MESH_PROXY_NET_PDU, - &msg, buf_send_end, bt_mesh_adv_ref(adv)); + &msg, buf_send_end, net_buf_ref(buf)); - bt_mesh_adv_send_start(0, err, &adv->ctx); + bt_mesh_adv_send_start(0, err, BT_MESH_ADV(buf)); if (err) { LOG_ERR("Failed to send proxy message (err %d)", err); @@ -224,7 +225,7 @@ int bt_mesh_proxy_relay_send(struct bt_conn *conn, struct bt_mesh_adv *adv) * which is just opaque data to segment_and send) reference given * to segment_and_send() here. */ - bt_mesh_adv_unref(adv); + net_buf_unref(buf); } return err; diff --git a/subsys/bluetooth/mesh/proxy_msg.h b/subsys/bluetooth/mesh/proxy_msg.h index 7ad4be7ae5d..7d4bd51ae4f 100644 --- a/subsys/bluetooth/mesh/proxy_msg.h +++ b/subsys/bluetooth/mesh/proxy_msg.h @@ -51,7 +51,7 @@ ssize_t bt_mesh_proxy_msg_recv(struct bt_conn *conn, int bt_mesh_proxy_msg_send(struct bt_conn *conn, uint8_t type, struct net_buf_simple *msg, bt_gatt_complete_func_t end, void *user_data); -int bt_mesh_proxy_relay_send(struct bt_conn *conn, struct bt_mesh_adv *adv); +int bt_mesh_proxy_relay_send(struct bt_conn *conn, struct net_buf *buf); struct bt_mesh_proxy_role *bt_mesh_proxy_role_setup(struct bt_conn *conn, proxy_send_cb_t send, proxy_recv_cb_t recv); diff --git a/subsys/bluetooth/mesh/proxy_srv.c b/subsys/bluetooth/mesh/proxy_srv.c index 45e29915325..571144ceaed 100644 --- a/subsys/bluetooth/mesh/proxy_srv.c +++ b/subsys/bluetooth/mesh/proxy_srv.c @@ -20,6 +20,7 @@ #include "common/bt_str.h" #include "mesh.h" +#include "adv.h" #include "net.h" #include "rpl.h" #include "transport.h" @@ -1021,12 +1022,12 @@ static bool client_filter_match(struct bt_mesh_proxy_client *client, return false; } -bool bt_mesh_proxy_relay(struct bt_mesh_adv *adv, uint16_t dst) +bool bt_mesh_proxy_relay(struct net_buf *buf, uint16_t dst) { bool relayed = false; int i; - LOG_DBG("%u bytes to dst 0x%04x", adv->b.len, dst); + LOG_DBG("%u bytes to dst 0x%04x", buf->len, dst); for (i = 0; i < ARRAY_SIZE(clients); i++) { struct bt_mesh_proxy_client *client = &clients[i]; @@ -1039,7 +1040,7 @@ bool bt_mesh_proxy_relay(struct bt_mesh_adv *adv, uint16_t dst) continue; } - if (bt_mesh_proxy_relay_send(client->cli->conn, adv)) { + if (bt_mesh_proxy_relay_send(client->cli->conn, buf)) { continue; } diff --git a/subsys/bluetooth/mesh/rpl.c b/subsys/bluetooth/mesh/rpl.c index df67ddf9d2e..e19df33908f 100644 --- a/subsys/bluetooth/mesh/rpl.c +++ b/subsys/bluetooth/mesh/rpl.c @@ -20,6 +20,7 @@ #include #include "mesh.h" +#include "adv.h" #include "net.h" #include "rpl.h" #include "settings.h" diff --git a/subsys/bluetooth/mesh/rpr_srv.c b/subsys/bluetooth/mesh/rpr_srv.c index e97df35f28f..9813842a367 100644 --- a/subsys/bluetooth/mesh/rpr_srv.c +++ b/subsys/bluetooth/mesh/rpr_srv.c @@ -14,6 +14,7 @@ #include #include #include "access.h" +#include "adv.h" #include "prov.h" #include "crypto.h" #include "rpr.h" diff --git a/subsys/bluetooth/mesh/solicitation.c b/subsys/bluetooth/mesh/solicitation.c index 642abfd87f1..e2100fa42db 100644 --- a/subsys/bluetooth/mesh/solicitation.c +++ b/subsys/bluetooth/mesh/solicitation.c @@ -12,6 +12,7 @@ #include #include #include "access.h" +#include "adv.h" #include "cfg.h" #include "crypto.h" #include "mesh.h" diff --git a/subsys/bluetooth/mesh/statistic.c b/subsys/bluetooth/mesh/statistic.c index b9f542a5923..21c451bee73 100644 --- a/subsys/bluetooth/mesh/statistic.c +++ b/subsys/bluetooth/mesh/statistic.c @@ -6,6 +6,7 @@ #include +#include "adv.h" #include "net.h" #include "statistic.h" @@ -21,24 +22,24 @@ void bt_mesh_stat_reset(void) memset(&stat, 0, sizeof(struct bt_mesh_statistic)); } -void bt_mesh_stat_planned_count(struct bt_mesh_adv_ctx *ctx) +void bt_mesh_stat_planned_count(struct bt_mesh_adv *adv) { - if (ctx->tag == BT_MESH_ADV_TAG_LOCAL) { + if (adv->tag == BT_MESH_ADV_TAG_LOCAL) { stat.tx_local_planned++; - } else if (ctx->tag == BT_MESH_ADV_TAG_RELAY) { + } else if (adv->tag == BT_MESH_ADV_TAG_RELAY) { stat.tx_adv_relay_planned++; - } else if (ctx->tag == BT_MESH_ADV_TAG_FRIEND) { + } else if (adv->tag == BT_MESH_ADV_TAG_FRIEND) { stat.tx_friend_planned++; } } -void bt_mesh_stat_succeeded_count(struct bt_mesh_adv_ctx *ctx) +void bt_mesh_stat_succeeded_count(struct bt_mesh_adv *adv) { - if (ctx->tag == BT_MESH_ADV_TAG_LOCAL) { + if (adv->tag == BT_MESH_ADV_TAG_LOCAL) { stat.tx_local_succeeded++; - } else if (ctx->tag == BT_MESH_ADV_TAG_RELAY) { + } else if (adv->tag == BT_MESH_ADV_TAG_RELAY) { stat.tx_adv_relay_succeeded++; - } else if (ctx->tag == BT_MESH_ADV_TAG_FRIEND) { + } else if (adv->tag == BT_MESH_ADV_TAG_FRIEND) { stat.tx_friend_succeeded++; } } diff --git a/subsys/bluetooth/mesh/statistic.h b/subsys/bluetooth/mesh/statistic.h index 4cd9187f45a..fdb488f0d81 100644 --- a/subsys/bluetooth/mesh/statistic.h +++ b/subsys/bluetooth/mesh/statistic.h @@ -7,8 +7,8 @@ #ifndef ZEPHYR_SUBSYS_BLUETOOTH_MESH_STATISTIC_H_ #define ZEPHYR_SUBSYS_BLUETOOTH_MESH_STATISTIC_H_ -void bt_mesh_stat_planned_count(struct bt_mesh_adv_ctx *ctx); -void bt_mesh_stat_succeeded_count(struct bt_mesh_adv_ctx *ctx); +void bt_mesh_stat_planned_count(struct bt_mesh_adv *adv); +void bt_mesh_stat_succeeded_count(struct bt_mesh_adv *adv); void bt_mesh_stat_rx(enum bt_mesh_net_if net_if); #endif /* ZEPHYR_SUBSYS_BLUETOOTH_MESH_STATISTIC_H_ */ diff --git a/subsys/bluetooth/mesh/subnet.c b/subsys/bluetooth/mesh/subnet.c index 695dd321b49..ef90ff8f725 100644 --- a/subsys/bluetooth/mesh/subnet.c +++ b/subsys/bluetooth/mesh/subnet.c @@ -22,6 +22,7 @@ #include "common/bt_str.h" #include "crypto.h" +#include "adv.h" #include "mesh.h" #include "net.h" #include "lpn.h" diff --git a/subsys/bluetooth/mesh/transport.c b/subsys/bluetooth/mesh/transport.c index 47e8492a901..94c1f698e91 100644 --- a/subsys/bluetooth/mesh/transport.c +++ b/subsys/bluetooth/mesh/transport.c @@ -22,6 +22,7 @@ #include "host/testing.h" #include "crypto.h" +#include "adv.h" #include "mesh.h" #include "net.h" #include "app_keys.h" @@ -121,26 +122,26 @@ static int send_unseg(struct bt_mesh_net_tx *tx, struct net_buf_simple *sdu, const struct bt_mesh_send_cb *cb, void *cb_data, const uint8_t *ctl_op) { - struct bt_mesh_adv *adv; + struct net_buf *buf; - adv = bt_mesh_adv_create(BT_MESH_ADV_DATA, BT_MESH_ADV_TAG_LOCAL, + buf = bt_mesh_adv_create(BT_MESH_ADV_DATA, BT_MESH_ADV_TAG_LOCAL, tx->xmit, BUF_TIMEOUT); - if (!adv) { - LOG_ERR("Out of network advs"); + if (!buf) { + LOG_ERR("Out of network buffers"); return -ENOBUFS; } - net_buf_simple_reserve(&adv->b, BT_MESH_NET_HDR_LEN); + net_buf_reserve(buf, BT_MESH_NET_HDR_LEN); if (ctl_op) { - net_buf_simple_add_u8(&adv->b, TRANS_CTL_HDR(*ctl_op, 0)); + net_buf_add_u8(buf, TRANS_CTL_HDR(*ctl_op, 0)); } else if (BT_MESH_IS_DEV_KEY(tx->ctx->app_idx)) { - net_buf_simple_add_u8(&adv->b, UNSEG_HDR(0, 0)); + net_buf_add_u8(buf, UNSEG_HDR(0, 0)); } else { - net_buf_simple_add_u8(&adv->b, UNSEG_HDR(1, tx->aid)); + net_buf_add_u8(buf, UNSEG_HDR(1, tx->aid)); } - net_buf_simple_add_mem(&adv->b, sdu->data, sdu->len); + net_buf_add_mem(buf, sdu->data, sdu->len); if (IS_ENABLED(CONFIG_BT_MESH_FRIEND)) { if (!bt_mesh_friend_queue_has_space(tx->sub->net_idx, @@ -148,7 +149,7 @@ static int send_unseg(struct bt_mesh_net_tx *tx, struct net_buf_simple *sdu, NULL, 1)) { if (BT_MESH_ADDR_IS_UNICAST(tx->ctx->addr)) { LOG_ERR("Not enough space in Friend Queue"); - bt_mesh_adv_unref(adv); + net_buf_unref(buf); return -ENOBUFS; } else { LOG_WRN("No space in Friend Queue"); @@ -157,19 +158,19 @@ static int send_unseg(struct bt_mesh_net_tx *tx, struct net_buf_simple *sdu, } if (bt_mesh_friend_enqueue_tx(tx, BT_MESH_FRIEND_PDU_SINGLE, - NULL, 1, &adv->b) && + NULL, 1, &buf->b) && BT_MESH_ADDR_IS_UNICAST(tx->ctx->addr)) { /* PDUs for a specific Friend should only go * out through the Friend Queue. */ - bt_mesh_adv_unref(adv); + net_buf_unref(buf); send_cb_finalize(cb, cb_data); return 0; } } send: - return bt_mesh_net_send(tx, adv, cb, cb_data); + return bt_mesh_net_send(tx, buf, cb, cb_data); } static inline uint8_t seg_len(bool ctl) @@ -404,7 +405,7 @@ static void seg_tx_send_unacked(struct seg_tx *tx) (uint16_t)(tx->seq_auth & TRANS_SEQ_ZERO_MASK), tx->attempts_left); while (tx->seg_o <= tx->seg_n) { - struct bt_mesh_adv *seg; + struct net_buf *seg; int err; if (!tx->seg[tx->seg_o]) { @@ -420,7 +421,7 @@ static void seg_tx_send_unacked(struct seg_tx *tx) goto end; } - net_buf_simple_reserve(&seg->b, BT_MESH_NET_HDR_LEN); + net_buf_reserve(seg, BT_MESH_NET_HDR_LEN); seg_tx_buf_build(tx, tx->seg_o, &seg->b); LOG_DBG("Sending %u/%u", tx->seg_o, tx->seg_n); diff --git a/subsys/bluetooth/mesh/transport_legacy.c b/subsys/bluetooth/mesh/transport_legacy.c index 1a826db4ac4..da0c1830f73 100644 --- a/subsys/bluetooth/mesh/transport_legacy.c +++ b/subsys/bluetooth/mesh/transport_legacy.c @@ -22,6 +22,7 @@ #include "host/testing.h" #include "crypto.h" +#include "adv.h" #include "mesh.h" #include "net.h" #include "app_keys.h" @@ -128,26 +129,26 @@ static int send_unseg(struct bt_mesh_net_tx *tx, struct net_buf_simple *sdu, const struct bt_mesh_send_cb *cb, void *cb_data, const uint8_t *ctl_op) { - struct bt_mesh_adv *adv; + struct net_buf *buf; - adv = bt_mesh_adv_create(BT_MESH_ADV_DATA, BT_MESH_ADV_TAG_LOCAL, + buf = bt_mesh_adv_create(BT_MESH_ADV_DATA, BT_MESH_ADV_TAG_LOCAL, tx->xmit, BUF_TIMEOUT); - if (!adv) { - LOG_ERR("Out of network advs"); + if (!buf) { + LOG_ERR("Out of network buffers"); return -ENOBUFS; } - net_buf_simple_reserve(&adv->b, BT_MESH_NET_HDR_LEN); + net_buf_reserve(buf, BT_MESH_NET_HDR_LEN); if (ctl_op) { - net_buf_simple_add_u8(&adv->b, TRANS_CTL_HDR(*ctl_op, 0)); + net_buf_add_u8(buf, TRANS_CTL_HDR(*ctl_op, 0)); } else if (BT_MESH_IS_DEV_KEY(tx->ctx->app_idx)) { - net_buf_simple_add_u8(&adv->b, UNSEG_HDR(0, 0)); + net_buf_add_u8(buf, UNSEG_HDR(0, 0)); } else { - net_buf_simple_add_u8(&adv->b, UNSEG_HDR(1, tx->aid)); + net_buf_add_u8(buf, UNSEG_HDR(1, tx->aid)); } - net_buf_simple_add_mem(&adv->b, sdu->data, sdu->len); + net_buf_add_mem(buf, sdu->data, sdu->len); if (IS_ENABLED(CONFIG_BT_MESH_FRIEND)) { if (!bt_mesh_friend_queue_has_space(tx->sub->net_idx, @@ -155,7 +156,7 @@ static int send_unseg(struct bt_mesh_net_tx *tx, struct net_buf_simple *sdu, NULL, 1)) { if (BT_MESH_ADDR_IS_UNICAST(tx->ctx->addr)) { LOG_ERR("Not enough space in Friend Queue"); - bt_mesh_adv_unref(adv); + net_buf_unref(buf); return -ENOBUFS; } @@ -164,19 +165,19 @@ static int send_unseg(struct bt_mesh_net_tx *tx, struct net_buf_simple *sdu, } if (bt_mesh_friend_enqueue_tx(tx, BT_MESH_FRIEND_PDU_SINGLE, - NULL, 1, &adv->b) && + NULL, 1, &buf->b) && BT_MESH_ADDR_IS_UNICAST(tx->ctx->addr)) { /* PDUs for a specific Friend should only go * out through the Friend Queue. */ - bt_mesh_adv_unref(adv); + net_buf_unref(buf); send_cb_finalize(cb, cb_data); return 0; } } send: - return bt_mesh_net_send(tx, adv, cb, cb_data); + return bt_mesh_net_send(tx, buf, cb, cb_data); } static inline uint8_t seg_len(bool ctl) @@ -391,7 +392,7 @@ static void seg_tx_send_unacked(struct seg_tx *tx) tx->attempts); while (tx->seg_o <= tx->seg_n) { - struct bt_mesh_adv *seg; + struct net_buf *seg; int err; if (!tx->seg[tx->seg_o]) { @@ -407,7 +408,7 @@ static void seg_tx_send_unacked(struct seg_tx *tx) goto end; } - net_buf_simple_reserve(&seg->b, BT_MESH_NET_HDR_LEN); + net_buf_reserve(seg, BT_MESH_NET_HDR_LEN); seg_tx_buf_build(tx, tx->seg_o, &seg->b); LOG_DBG("Sending %u/%u", tx->seg_o, tx->seg_n); diff --git a/tests/bsim/bluetooth/mesh/src/test_advertiser.c b/tests/bsim/bluetooth/mesh/src/test_advertiser.c index 47851fc72f4..073651ae843 100644 --- a/tests/bsim/bluetooth/mesh/src/test_advertiser.c +++ b/tests/bsim/bluetooth/mesh/src/test_advertiser.c @@ -7,6 +7,7 @@ #include #include #include "mesh_test.h" +#include "mesh/adv.h" #include "mesh/net.h" #include "mesh/mesh.h" #include "mesh/foundation.h" @@ -77,25 +78,25 @@ static void adv_init(void) ASSERT_OK_MSG(bt_mesh_adv_enable(), "Mesh adv init failed"); } -static void allocate_all_array(struct bt_mesh_adv **adv, size_t num_adv, uint8_t xmit) +static void allocate_all_array(struct net_buf **buf, size_t num_buf, uint8_t xmit) { - for (int i = 0; i < num_adv; i++) { - *adv = bt_mesh_adv_create(BT_MESH_ADV_DATA, BT_MESH_ADV_TAG_LOCAL, + for (int i = 0; i < num_buf; i++) { + *buf = bt_mesh_adv_create(BT_MESH_ADV_DATA, BT_MESH_ADV_TAG_LOCAL, xmit, K_NO_WAIT); - ASSERT_FALSE_MSG(!*adv, "Out of advs\n"); - adv++; + ASSERT_FALSE_MSG(!*buf, "Out of buffers\n"); + buf++; } } static void verify_adv_queue_overflow(void) { - struct bt_mesh_adv *dummy_adv; + struct net_buf *dummy_buf; /* Verity Queue overflow */ - dummy_adv = bt_mesh_adv_create(BT_MESH_ADV_DATA, BT_MESH_ADV_TAG_LOCAL, + dummy_buf = bt_mesh_adv_create(BT_MESH_ADV_DATA, BT_MESH_ADV_TAG_LOCAL, BT_MESH_TRANSMIT(2, 20), K_NO_WAIT); - ASSERT_TRUE_MSG(!dummy_adv, "Unexpected extra adv\n"); + ASSERT_TRUE_MSG(!dummy_buf, "Unexpected extra buffer\n"); } static bool check_delta_time(uint8_t transmit, uint64_t interval) @@ -156,12 +157,12 @@ static void single_end_cb(int err, void *cb_data) static void realloc_end_cb(int err, void *cb_data) { - struct bt_mesh_adv *adv = (struct bt_mesh_adv *)cb_data; + struct net_buf *buf = (struct net_buf *)cb_data; ASSERT_EQUAL(0, err); - adv = bt_mesh_adv_create(BT_MESH_ADV_DATA, BT_MESH_ADV_TAG_LOCAL, + buf = bt_mesh_adv_create(BT_MESH_ADV_DATA, BT_MESH_ADV_TAG_LOCAL, BT_MESH_TRANSMIT(2, 20), K_NO_WAIT); - ASSERT_FALSE_MSG(!adv, "Out of advs\n"); + ASSERT_FALSE_MSG(!buf, "Out of buffers\n"); k_sem_give(&observer_sem); } @@ -304,13 +305,13 @@ static void rx_xmit_adv(void) static void send_order_start_cb(uint16_t duration, int err, void *user_data) { - struct bt_mesh_adv *adv = (struct bt_mesh_adv *)user_data; + struct net_buf *buf = (struct net_buf *)user_data; ASSERT_OK_MSG(err, "Failed adv start cb err (%d)", err); - ASSERT_EQUAL(2, adv->b.len); + ASSERT_EQUAL(2, buf->len); - uint8_t current = adv->b.data[0]; - uint8_t previous = adv->b.data[1]; + uint8_t current = buf->data[0]; + uint8_t previous = buf->data[1]; LOG_INF("tx start: current(%d) previous(%d)", current, previous); @@ -320,7 +321,10 @@ static void send_order_start_cb(uint16_t duration, int err, void *user_data) static void send_order_end_cb(int err, void *user_data) { + struct net_buf *buf = (struct net_buf *)user_data; + ASSERT_OK_MSG(err, "Failed adv start cb err (%d)", err); + ASSERT_TRUE_MSG(!buf->data, "Data not cleared!\n"); seq_checker++; LOG_INF("tx end: seq(%d)", seq_checker); @@ -376,19 +380,19 @@ static void receive_order(int expect_adv) ASSERT_FALSE_MSG(err && err != -EALREADY, "Stopping scan failed (err %d)\n", err); } -static void send_adv_buf(struct bt_mesh_adv *adv, uint8_t curr, uint8_t prev) +static void send_adv_buf(struct net_buf *buf, uint8_t curr, uint8_t prev) { send_cb.start = send_order_start_cb; send_cb.end = send_order_end_cb; - (void)net_buf_simple_add_u8(&adv->b, curr); - (void)net_buf_simple_add_u8(&adv->b, prev); + (void)net_buf_add_u8(buf, curr); + (void)net_buf_add_u8(buf, prev); - bt_mesh_adv_send(adv, &send_cb, adv); - bt_mesh_adv_unref(adv); + bt_mesh_adv_send(buf, &send_cb, buf); + net_buf_unref(buf); } -static void send_adv_array(struct bt_mesh_adv **adv, size_t num_buf, bool reverse) +static void send_adv_array(struct net_buf **buf, size_t num_buf, bool reverse) { uint8_t previous; int i; @@ -401,13 +405,13 @@ static void send_adv_array(struct bt_mesh_adv **adv, size_t num_buf, bool revers i = num_buf - 1; } while ((!reverse && i < num_buf) || (reverse && i >= 0)) { - send_adv_buf(*adv, (uint8_t)i, previous); + send_adv_buf(*buf, (uint8_t)i, previous); previous = (uint8_t)i; if (!reverse) { - adv++; + buf++; i++; } else { - adv--; + buf--; i--; } } @@ -415,24 +419,24 @@ static void send_adv_array(struct bt_mesh_adv **adv, size_t num_buf, bool revers static void test_tx_cb_single(void) { - struct bt_mesh_adv *adv; + struct net_buf *buf; int err; bt_init(); adv_init(); - adv = bt_mesh_adv_create(BT_MESH_ADV_DATA, BT_MESH_ADV_TAG_LOCAL, + buf = bt_mesh_adv_create(BT_MESH_ADV_DATA, BT_MESH_ADV_TAG_LOCAL, BT_MESH_TRANSMIT(2, 20), K_NO_WAIT); - ASSERT_FALSE_MSG(!adv, "Out of advs\n"); + ASSERT_FALSE_MSG(!buf, "Out of buffers\n"); send_cb.start = single_start_cb; send_cb.end = single_end_cb; - net_buf_simple_add_mem(&adv->b, txt_msg, sizeof(txt_msg)); + net_buf_add_mem(buf, txt_msg, sizeof(txt_msg)); seq_checker = 0; tx_timestamp = k_uptime_get(); - bt_mesh_adv_send(adv, &send_cb, (void *)cb_msg); - bt_mesh_adv_unref(adv); + bt_mesh_adv_send(buf, &send_cb, (void *)cb_msg); + net_buf_unref(buf); err = k_sem_take(&observer_sem, K_SECONDS(1)); ASSERT_OK_MSG(err, "Didn't call end tx cb."); @@ -453,37 +457,37 @@ static void test_rx_xmit(void) static void test_tx_cb_multi(void) { - struct bt_mesh_adv *adv[CONFIG_BT_MESH_ADV_BUF_COUNT]; + struct net_buf *buf[CONFIG_BT_MESH_ADV_BUF_COUNT]; int err; bt_init(); adv_init(); - /* Allocate all network advs. */ - allocate_all_array(adv, ARRAY_SIZE(adv), BT_MESH_TRANSMIT(2, 20)); + /* Allocate all network buffers. */ + allocate_all_array(buf, ARRAY_SIZE(buf), BT_MESH_TRANSMIT(2, 20)); - /* Start single adv to reallocate one network adv in callback. - * Check that the adv is freed before cb is triggered. + /* Start single adv to reallocate one network buffer in callback. + * Check that the buffer is freed before cb is triggered. */ send_cb.start = NULL; send_cb.end = realloc_end_cb; - net_buf_simple_add_mem(&(adv[0]->b), txt_msg, sizeof(txt_msg)); + net_buf_add_mem(buf[0], txt_msg, sizeof(txt_msg)); - bt_mesh_adv_send(adv[0], &send_cb, adv[0]); - bt_mesh_adv_unref(adv[0]); + bt_mesh_adv_send(buf[0], &send_cb, buf[0]); + net_buf_unref(buf[0]); err = k_sem_take(&observer_sem, K_SECONDS(1)); - ASSERT_OK_MSG(err, "Didn't call the end tx cb that reallocates adv one more time."); + ASSERT_OK_MSG(err, "Didn't call the end tx cb that reallocates buffer one more time."); - /* Start multi advs to check that all advs are sent and cbs are triggered. */ + /* Start multi advs to check that all buffers are sent and cbs are triggered. */ send_cb.start = seq_start_cb; send_cb.end = seq_end_cb; seq_checker = 0; for (int i = 0; i < CONFIG_BT_MESH_ADV_BUF_COUNT; i++) { - net_buf_simple_add_le32(&(adv[i]->b), i); - bt_mesh_adv_send(adv[i], &send_cb, (void *)(intptr_t)i); - bt_mesh_adv_unref(adv[i]); + net_buf_add_le32(buf[i], i); + bt_mesh_adv_send(buf[i], &send_cb, (void *)(intptr_t)i); + net_buf_unref(buf[i]); } err = k_sem_take(&observer_sem, K_SECONDS(10)); @@ -526,10 +530,10 @@ static void test_tx_proxy_mixin(void) * Advertising the proxy service should be resumed after * finishing advertising the message. */ - struct bt_mesh_adv *adv = bt_mesh_adv_create(BT_MESH_ADV_DATA, BT_MESH_ADV_TAG_LOCAL, + struct net_buf *buf = bt_mesh_adv_create(BT_MESH_ADV_DATA, BT_MESH_ADV_TAG_LOCAL, BT_MESH_TRANSMIT(5, 20), K_NO_WAIT); - net_buf_simple_add_mem(&adv->b, txt_msg, sizeof(txt_msg)); - bt_mesh_adv_send(adv, NULL, NULL); + net_buf_add_mem(buf, txt_msg, sizeof(txt_msg)); + bt_mesh_adv_send(buf, NULL, NULL); k_sleep(K_MSEC(150)); /* Let the tester to measure an interval between advertisements again. */ @@ -573,46 +577,46 @@ static void test_rx_proxy_mixin(void) static void test_tx_send_order(void) { - struct bt_mesh_adv *adv[CONFIG_BT_MESH_ADV_BUF_COUNT]; + struct net_buf *buf[CONFIG_BT_MESH_ADV_BUF_COUNT]; uint8_t xmit = BT_MESH_TRANSMIT(2, 20); bt_init(); adv_init(); /* Verify sending order */ - allocate_all_array(adv, ARRAY_SIZE(adv), xmit); + allocate_all_array(buf, ARRAY_SIZE(buf), xmit); verify_adv_queue_overflow(); - send_adv_array(&adv[0], ARRAY_SIZE(adv), false); + send_adv_array(&buf[0], ARRAY_SIZE(buf), false); /* Wait for no message receive window to end. */ ASSERT_OK_MSG(k_sem_take(&observer_sem, K_SECONDS(10)), "Didn't call the last end tx cb."); - /* Verify adv allocation/deallocation after sending */ - allocate_all_array(adv, ARRAY_SIZE(adv), xmit); + /* Verify buffer allocation/deallocation after sending */ + allocate_all_array(buf, ARRAY_SIZE(buf), xmit); verify_adv_queue_overflow(); for (int i = 0; i < CONFIG_BT_MESH_ADV_BUF_COUNT; i++) { - bt_mesh_adv_unref(adv[i]); - adv[i] = NULL; + net_buf_unref(buf[i]); + buf[i] = NULL; } - /* Check that it possible to add just one net adv. */ - allocate_all_array(adv, 1, xmit); + /* Check that it possible to add just one net buf. */ + allocate_all_array(buf, 1, xmit); PASS(); } static void test_tx_reverse_order(void) { - struct bt_mesh_adv *adv[CONFIG_BT_MESH_ADV_BUF_COUNT]; + struct net_buf *buf[CONFIG_BT_MESH_ADV_BUF_COUNT]; uint8_t xmit = BT_MESH_TRANSMIT(2, 20); bt_init(); adv_init(); /* Verify reversed sending order */ - allocate_all_array(adv, ARRAY_SIZE(adv), xmit); + allocate_all_array(buf, ARRAY_SIZE(buf), xmit); - send_adv_array(&adv[CONFIG_BT_MESH_ADV_BUF_COUNT - 1], ARRAY_SIZE(adv), true); + send_adv_array(&buf[CONFIG_BT_MESH_ADV_BUF_COUNT - 1], ARRAY_SIZE(buf), true); /* Wait for no message receive window to end. */ ASSERT_OK_MSG(k_sem_take(&observer_sem, K_SECONDS(10)), @@ -623,31 +627,31 @@ static void test_tx_reverse_order(void) static void test_tx_random_order(void) { - struct bt_mesh_adv *adv[3]; + struct net_buf *buf[3]; uint8_t xmit = BT_MESH_TRANSMIT(0, 20); bt_init(); adv_init(); /* Verify random order calls */ - num_adv_sent = ARRAY_SIZE(adv); + num_adv_sent = ARRAY_SIZE(buf); previous_checker = 0xff; - adv[0] = bt_mesh_adv_create(BT_MESH_ADV_DATA, BT_MESH_ADV_TAG_LOCAL, + buf[0] = bt_mesh_adv_create(BT_MESH_ADV_DATA, BT_MESH_ADV_TAG_LOCAL, xmit, K_NO_WAIT); - ASSERT_FALSE_MSG(!adv[0], "Out of advs\n"); - adv[1] = bt_mesh_adv_create(BT_MESH_ADV_DATA, BT_MESH_ADV_TAG_LOCAL, + ASSERT_FALSE_MSG(!buf[0], "Out of buffers\n"); + buf[1] = bt_mesh_adv_create(BT_MESH_ADV_DATA, BT_MESH_ADV_TAG_LOCAL, xmit, K_NO_WAIT); - ASSERT_FALSE_MSG(!adv[1], "Out of advs\n"); + ASSERT_FALSE_MSG(!buf[1], "Out of buffers\n"); - send_adv_buf(adv[0], 0, 0xff); + send_adv_buf(buf[0], 0, 0xff); - adv[2] = bt_mesh_adv_create(BT_MESH_ADV_DATA, BT_MESH_ADV_TAG_LOCAL, + buf[2] = bt_mesh_adv_create(BT_MESH_ADV_DATA, BT_MESH_ADV_TAG_LOCAL, xmit, K_NO_WAIT); - ASSERT_FALSE_MSG(!adv[2], "Out of advs\n"); + ASSERT_FALSE_MSG(!buf[2], "Out of buffers\n"); - send_adv_buf(adv[2], 2, 0); + send_adv_buf(buf[2], 2, 0); - send_adv_buf(adv[1], 1, 2); + send_adv_buf(buf[1], 1, 2); /* Wait for no message receive window to end. */ ASSERT_OK_MSG(k_sem_take(&observer_sem, K_SECONDS(10)), diff --git a/tests/bsim/bluetooth/mesh/src/test_beacon.c b/tests/bsim/bluetooth/mesh/src/test_beacon.c index 038c705f2cb..e93c2301e46 100644 --- a/tests/bsim/bluetooth/mesh/src/test_beacon.c +++ b/tests/bsim/bluetooth/mesh/src/test_beacon.c @@ -6,6 +6,7 @@ #include #include #include "mesh_test.h" +#include "mesh/adv.h" #include "mesh/net.h" #include "mesh/beacon.h" #include "mesh/mesh.h" diff --git a/tests/bsim/bluetooth/mesh/src/test_blob.c b/tests/bsim/bluetooth/mesh/src/test_blob.c index 0d3a69da2fc..4258ff77c62 100644 --- a/tests/bsim/bluetooth/mesh/src/test_blob.c +++ b/tests/bsim/bluetooth/mesh/src/test_blob.c @@ -6,9 +6,9 @@ #include "mesh_test.h" #include "dfu_blob_common.h" #include "friendship_common.h" -#include "mesh/adv.h" #include "mesh/blob.h" #include "argparse.h" +#include "mesh/adv.h" #define LOG_MODULE_NAME test_blob diff --git a/tests/bsim/bluetooth/mesh/src/test_dfu.c b/tests/bsim/bluetooth/mesh/src/test_dfu.c index 1b54e873cc5..06f7248a6ad 100644 --- a/tests/bsim/bluetooth/mesh/src/test_dfu.c +++ b/tests/bsim/bluetooth/mesh/src/test_dfu.c @@ -6,6 +6,7 @@ #include "mesh_test.h" #include "mesh/dfd_srv_internal.h" #include "mesh/dfu_slot.h" +#include "mesh/adv.h" #include "mesh/dfu.h" #include "mesh/blob.h" #include "argparse.h" diff --git a/tests/bsim/bluetooth/mesh/src/test_provision.c b/tests/bsim/bluetooth/mesh/src/test_provision.c index 3d0e8010c75..f2c98778a3b 100644 --- a/tests/bsim/bluetooth/mesh/src/test_provision.c +++ b/tests/bsim/bluetooth/mesh/src/test_provision.c @@ -28,6 +28,7 @@ #define LOG_MODULE_NAME mesh_prov #include +#include "mesh/adv.h" #include "mesh/rpr.h" LOG_MODULE_REGISTER(LOG_MODULE_NAME); diff --git a/tests/bsim/bluetooth/mesh/src/test_scanner.c b/tests/bsim/bluetooth/mesh/src/test_scanner.c index a63284701df..12557b7e1b2 100644 --- a/tests/bsim/bluetooth/mesh/src/test_scanner.c +++ b/tests/bsim/bluetooth/mesh/src/test_scanner.c @@ -6,6 +6,7 @@ #include #include "mesh_test.h" #include "mesh/net.h" +#include "mesh/adv.h" #include "mesh/mesh.h" #include "mesh/foundation.h" From ea33fface28bca878b339c91d6c528a7af0b38b2 Mon Sep 17 00:00:00 2001 From: Robert Lubos Date: Tue, 6 Feb 2024 11:07:21 +0100 Subject: [PATCH 3609/3723] Revert "[nrf fromtree] Bluetooth: Mesh: Convert no opcode error to debug log" This reverts commit 353bc561d85af3e637b299aaee1b36fb75070321. Signed-off-by: Robert Lubos --- subsys/bluetooth/mesh/access.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/subsys/bluetooth/mesh/access.c b/subsys/bluetooth/mesh/access.c index 81e2902afd1..dcf7f0f783b 100644 --- a/subsys/bluetooth/mesh/access.c +++ b/subsys/bluetooth/mesh/access.c @@ -1424,7 +1424,7 @@ static int element_model_recv(struct bt_mesh_msg_ctx *ctx, struct net_buf_simple op = find_op(elem, opcode, &model); if (!op) { - LOG_DBG("No OpCode 0x%08x for elem 0x%02x", opcode, elem->rt->addr); + LOG_ERR("No OpCode 0x%08x for elem 0x%02x", opcode, elem->rt->addr); return ACCESS_STATUS_WRONG_OPCODE; } From cd6c5913cf108813a61c5b02529b9c0b604c9567 Mon Sep 17 00:00:00 2001 From: Robert Lubos Date: Tue, 6 Feb 2024 11:07:21 +0100 Subject: [PATCH 3610/3723] Revert "[nrf fromtree] Bluetooth: Mesh: Allow custom RPL use mesh settings work" This reverts commit 88122bae6f022d60b9a306908d31e2832372335c. Signed-off-by: Robert Lubos --- subsys/bluetooth/mesh/settings.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/subsys/bluetooth/mesh/settings.c b/subsys/bluetooth/mesh/settings.c index 8ec9c66481a..9cfcb3f5c2c 100644 --- a/subsys/bluetooth/mesh/settings.c +++ b/subsys/bluetooth/mesh/settings.c @@ -186,7 +186,8 @@ static void store_pending(struct k_work *work) { LOG_DBG(""); - if (atomic_test_and_clear_bit(pending_flags, BT_MESH_SETTINGS_RPL_PENDING)) { + if (IS_ENABLED(CONFIG_BT_MESH_RPL_STORAGE_MODE_SETTINGS) && + atomic_test_and_clear_bit(pending_flags, BT_MESH_SETTINGS_RPL_PENDING)) { bt_mesh_rpl_pending_store(BT_MESH_ADDR_ALL_NODES); } From a6f9db90234f8f44ea498ebb601cee5c980ea62e Mon Sep 17 00:00:00 2001 From: Robert Lubos Date: Tue, 6 Feb 2024 11:07:21 +0100 Subject: [PATCH 3611/3723] Revert "[nrf fromtree] Bluetooth: Mesh: suspend/resume advertising" This reverts commit 00539bcdf7cd4f15f7e786d13d98c2eac828fd42. Signed-off-by: Robert Lubos --- subsys/bluetooth/mesh/main.c | 18 ------------------ 1 file changed, 18 deletions(-) diff --git a/subsys/bluetooth/mesh/main.c b/subsys/bluetooth/mesh/main.c index 24bbd7c7e94..2c78ea227de 100644 --- a/subsys/bluetooth/mesh/main.c +++ b/subsys/bluetooth/mesh/main.c @@ -460,13 +460,6 @@ int bt_mesh_suspend(void) bt_mesh_model_foreach(model_suspend, NULL); - err = bt_mesh_adv_disable(); - if (err) { - atomic_clear_bit(bt_mesh.flags, BT_MESH_SUSPENDED); - LOG_WRN("Disabling advertisers failed (err %d)", err); - return err; - } - return 0; } @@ -495,17 +488,6 @@ int bt_mesh_resume(void) return -EALREADY; } - if (!IS_ENABLED(CONFIG_BT_EXT_ADV)) { - bt_mesh_adv_init(); - } - - err = bt_mesh_adv_enable(); - if (err) { - atomic_set_bit(bt_mesh.flags, BT_MESH_SUSPENDED); - LOG_WRN("Re-enabling advertisers failed (err %d)", err); - return err; - } - err = bt_mesh_scan_enable(); if (err) { LOG_WRN("Re-enabling scanning failed (err %d)", err); From 816bdbee93e1f4addf3a18c532bb8bcfd3f04b36 Mon Sep 17 00:00:00 2001 From: Robert Lubos Date: Tue, 6 Feb 2024 11:07:21 +0100 Subject: [PATCH 3612/3723] Revert "[nrf fromtree] Bluetooth: Mesh: advertiser: add disable function" This reverts commit ac4f2cdb0c616b46fa0775bd001cc68951e62074. Signed-off-by: Robert Lubos --- include/zephyr/bluetooth/mesh/main.h | 4 ---- subsys/bluetooth/mesh/adv.h | 3 --- subsys/bluetooth/mesh/adv_ext.c | 30 ---------------------------- subsys/bluetooth/mesh/adv_legacy.c | 21 +++---------------- 4 files changed, 3 insertions(+), 55 deletions(-) diff --git a/include/zephyr/bluetooth/mesh/main.h b/include/zephyr/bluetooth/mesh/main.h index a213e8ce22c..8e7445fae6f 100644 --- a/include/zephyr/bluetooth/mesh/main.h +++ b/include/zephyr/bluetooth/mesh/main.h @@ -607,10 +607,6 @@ void bt_mesh_reset(void); * If at all possible, the Friendship feature should be used instead, to * make the node into a Low Power Node. * - * @note Should not be called from work queue due to undefined behavior. - * This is due to k_work_flush_delayable() being used in disabling of the - * extended advertising. - * * @return 0 on success, or (negative) error code on failure. */ int bt_mesh_suspend(void); diff --git a/subsys/bluetooth/mesh/adv.h b/subsys/bluetooth/mesh/adv.h index 42b07601ad5..a80ff7e8d4b 100644 --- a/subsys/bluetooth/mesh/adv.h +++ b/subsys/bluetooth/mesh/adv.h @@ -80,9 +80,6 @@ int bt_mesh_scan_disable(void); int bt_mesh_adv_enable(void); -/* Should not be called from work queue due to undefined behavior */ -int bt_mesh_adv_disable(void); - void bt_mesh_adv_buf_local_ready(void); void bt_mesh_adv_buf_relay_ready(void); diff --git a/subsys/bluetooth/mesh/adv_ext.c b/subsys/bluetooth/mesh/adv_ext.c index aaea8845ae5..fe9fc4fd403 100644 --- a/subsys/bluetooth/mesh/adv_ext.c +++ b/subsys/bluetooth/mesh/adv_ext.c @@ -540,36 +540,6 @@ int bt_mesh_adv_enable(void) return 0; } -int bt_mesh_adv_disable(void) -{ - int err; - struct k_work_sync sync; - - for (int i = 0; i < ARRAY_SIZE(advs); i++) { - k_work_flush_delayable(&advs[i].work, &sync); - - err = bt_le_ext_adv_stop(advs[i].instance); - if (err) { - LOG_ERR("Failed to stop adv %d", err); - return err; - } - - /* `adv_sent` is called to finish transmission of an adv buffer that was pushed to - * the host before the advertiser was stopped, but did not finish. - */ - adv_sent(advs[i].instance, NULL); - - err = bt_le_ext_adv_delete(advs[i].instance); - if (err) { - LOG_ERR("Failed to delete adv %d", err); - return err; - } - advs[i].instance = NULL; - } - - return 0; -} - int bt_mesh_adv_gatt_start(const struct bt_le_adv_param *param, int32_t duration, const struct bt_data *ad, size_t ad_len, diff --git a/subsys/bluetooth/mesh/adv_legacy.c b/subsys/bluetooth/mesh/adv_legacy.c index aef13864131..a7d7dd1a320 100644 --- a/subsys/bluetooth/mesh/adv_legacy.c +++ b/subsys/bluetooth/mesh/adv_legacy.c @@ -39,7 +39,6 @@ LOG_MODULE_REGISTER(bt_mesh_adv_legacy); static struct k_thread adv_thread_data; static K_KERNEL_STACK_DEFINE(adv_thread_stack, CONFIG_BT_MESH_ADV_STACK_SIZE); static int32_t adv_timeout; -static bool enabled; static int bt_data_send(uint8_t num_events, uint16_t adv_int, const struct bt_data *ad, size_t ad_len, @@ -145,9 +144,10 @@ static inline void buf_send(struct net_buf *buf) static void adv_thread(void *p1, void *p2, void *p3) { LOG_DBG("started"); - struct net_buf *buf; - while (enabled) { + while (1) { + struct net_buf *buf; + if (IS_ENABLED(CONFIG_BT_MESH_GATT_SERVER)) { buf = bt_mesh_adv_buf_get(K_NO_WAIT); if (IS_ENABLED(CONFIG_BT_MESH_PROXY_SOLICITATION) && !buf) { @@ -188,12 +188,6 @@ static void adv_thread(void *p1, void *p2, void *p3) /* Give other threads a chance to run */ k_yield(); } - - /* Empty the advertising pool when advertising is disabled */ - while ((buf = bt_mesh_adv_buf_get(K_NO_WAIT))) { - bt_mesh_adv_send_start(0, -ENODEV, BT_MESH_ADV(buf)); - net_buf_unref(buf); - } } void bt_mesh_adv_buf_local_ready(void) @@ -227,19 +221,10 @@ void bt_mesh_adv_init(void) int bt_mesh_adv_enable(void) { - enabled = true; k_thread_start(&adv_thread_data); return 0; } -int bt_mesh_adv_disable(void) -{ - enabled = false; - k_thread_join(&adv_thread_data, K_FOREVER); - LOG_DBG("Advertising disabled"); - return 0; -} - int bt_mesh_adv_gatt_start(const struct bt_le_adv_param *param, int32_t duration, const struct bt_data *ad, size_t ad_len, const struct bt_data *sd, size_t sd_len) From c88dd43954f9b95f8bde7ce76e7dfd22745cf70e Mon Sep 17 00:00:00 2001 From: Robert Lubos Date: Tue, 6 Feb 2024 11:07:21 +0100 Subject: [PATCH 3613/3723] Revert "[nrf fromtree] Bluetooth: Mesh: Align some code" This reverts commit 8ce58a5c1e34394175903babacd17cb953bda4a2. Signed-off-by: Robert Lubos --- include/zephyr/bluetooth/mesh/access.h | 4 ++-- include/zephyr/bluetooth/mesh/blob_cli.h | 8 ++++---- include/zephyr/bluetooth/mesh/cdb.h | 2 +- include/zephyr/bluetooth/mesh/cfg_cli.h | 20 ++++++++++---------- 4 files changed, 17 insertions(+), 17 deletions(-) diff --git a/include/zephyr/bluetooth/mesh/access.h b/include/zephyr/bluetooth/mesh/access.h index d57f30f8f05..817fba918ef 100644 --- a/include/zephyr/bluetooth/mesh/access.h +++ b/include/zephyr/bluetooth/mesh/access.h @@ -1011,7 +1011,7 @@ const struct bt_mesh_elem *bt_mesh_model_elem(const struct bt_mesh_model *mod); * if no SIG model with the given ID exists in the given element. */ const struct bt_mesh_model *bt_mesh_model_find(const struct bt_mesh_elem *elem, - uint16_t id); + uint16_t id); /** @brief Find a vendor model. * @@ -1023,7 +1023,7 @@ const struct bt_mesh_model *bt_mesh_model_find(const struct bt_mesh_elem *elem, * if no vendor model with the given ID exists in the given element. */ const struct bt_mesh_model *bt_mesh_model_find_vnd(const struct bt_mesh_elem *elem, - uint16_t company, uint16_t id); + uint16_t company, uint16_t id); /** @brief Get whether the model is in the primary element of the device. * diff --git a/include/zephyr/bluetooth/mesh/blob_cli.h b/include/zephyr/bluetooth/mesh/blob_cli.h index 9b591cfdd35..8e239b31457 100644 --- a/include/zephyr/bluetooth/mesh/blob_cli.h +++ b/include/zephyr/bluetooth/mesh/blob_cli.h @@ -265,10 +265,10 @@ struct blob_cli_broadcast_ctx { void (*send)(struct bt_mesh_blob_cli *cli, uint16_t dst); /** Called after every @ref blob_cli_broadcast_ctx::send callback. */ void (*send_complete)(struct bt_mesh_blob_cli *cli, uint16_t dst); - /** If @ref blob_cli_broadcast_ctx::acked is true, called after all Target nodes - * have confirmed reception by @ref blob_cli_broadcast_rsp. Otherwise, called - * after transmission has been completed. - */ + /** If @ref blob_cli_broadcast_ctx::acked is true, called after all Target nodes + * have confirmed reception by @ref blob_cli_broadcast_rsp. Otherwise, called + * after transmission has been completed. + */ void (*next)(struct bt_mesh_blob_cli *cli); /** If true, every transmission needs to be confirmed by @ref blob_cli_broadcast_rsp before * @ref blob_cli_broadcast_ctx::next is called. diff --git a/include/zephyr/bluetooth/mesh/cdb.h b/include/zephyr/bluetooth/mesh/cdb.h index 8ea35ec2e55..800ae07edc4 100644 --- a/include/zephyr/bluetooth/mesh/cdb.h +++ b/include/zephyr/bluetooth/mesh/cdb.h @@ -231,7 +231,7 @@ enum { * or BT_MESH_CDB_ITER_STOP to stop. */ typedef uint8_t (*bt_mesh_cdb_node_func_t)(struct bt_mesh_cdb_node *node, - void *user_data); + void *user_data); /** @brief Node iterator. * diff --git a/include/zephyr/bluetooth/mesh/cfg_cli.h b/include/zephyr/bluetooth/mesh/cfg_cli.h index 4aca0c17451..0e8c26131ff 100644 --- a/include/zephyr/bluetooth/mesh/cfg_cli.h +++ b/include/zephyr/bluetooth/mesh/cfg_cli.h @@ -96,8 +96,8 @@ struct bt_mesh_cfg_cli_cb { * @param buf Message buffer containing subscription addresses. */ void (*mod_sub_list)(struct bt_mesh_cfg_cli *cli, uint16_t addr, uint8_t status, - uint16_t elem_addr, uint16_t mod_id, uint16_t cid, - struct net_buf_simple *buf); + uint16_t elem_addr, uint16_t mod_id, uint16_t cid, + struct net_buf_simple *buf); /** @brief Optional callback for Node Reset Status messages. * @@ -128,7 +128,7 @@ struct bt_mesh_cfg_cli_cb { * @param status Status Code for requesting message. */ void (*ttl_status)(struct bt_mesh_cfg_cli *cli, uint16_t addr, - uint8_t status); + uint8_t status); /** @brief Optional callback for Friend Status messages. * @@ -139,7 +139,7 @@ struct bt_mesh_cfg_cli_cb { * @param status Status Code for requesting message. */ void (*friend_status)(struct bt_mesh_cfg_cli *cli, uint16_t addr, - uint8_t status); + uint8_t status); /** @brief Optional callback for GATT Proxy Status messages. * @@ -150,7 +150,7 @@ struct bt_mesh_cfg_cli_cb { * @param status Status Code for requesting message. */ void (*gatt_proxy_status)(struct bt_mesh_cfg_cli *cli, uint16_t addr, - uint8_t status); + uint8_t status); /** @brief Optional callback for Network Transmit Status messages. * @@ -199,7 +199,7 @@ struct bt_mesh_cfg_cli_cb { * @param buf Message buffer containing key indexes. */ void (*net_key_list)(struct bt_mesh_cfg_cli *cli, uint16_t addr, - struct net_buf_simple *buf); + struct net_buf_simple *buf); /** @brief Optional callback for AppKey Status messages. * @@ -229,7 +229,7 @@ struct bt_mesh_cfg_cli_cb { * @param buf Message buffer containing key indexes. */ void (*app_key_list)(struct bt_mesh_cfg_cli *cli, uint16_t addr, uint8_t status, - uint16_t net_idx, struct net_buf_simple *buf); + uint16_t net_idx, struct net_buf_simple *buf); /** @brief Optional callback for Model App Status messages. * @@ -262,8 +262,8 @@ struct bt_mesh_cfg_cli_cb { * @param buf Message buffer containing key indexes. */ void (*mod_app_list)(struct bt_mesh_cfg_cli *cli, uint16_t addr, uint8_t status, - uint16_t elem_addr, uint16_t mod_id, uint16_t cid, - struct net_buf_simple *buf); + uint16_t elem_addr, uint16_t mod_id, uint16_t cid, + struct net_buf_simple *buf); /** @brief Optional callback for Node Identity Status messages. * @@ -326,7 +326,7 @@ struct bt_mesh_cfg_cli_cb { * @param sub HB subscription configuration parameters. */ void (*hb_sub_status)(struct bt_mesh_cfg_cli *cli, uint16_t addr, uint8_t status, - struct bt_mesh_cfg_cli_hb_sub *sub); + struct bt_mesh_cfg_cli_hb_sub *sub); }; /** Mesh Configuration Client Model Context */ From a28518666e1d2c6399566dfa3782c5d26a476351 Mon Sep 17 00:00:00 2001 From: Robert Lubos Date: Tue, 6 Feb 2024 11:07:22 +0100 Subject: [PATCH 3614/3723] Revert "[nrf fromtree] bluetooth: mesh: Doc fix Bluetooth mesh to Mesh" This reverts commit e9382bacb83cffda685d77a5d94702f577d41303. Signed-off-by: Robert Lubos --- boards/arm/nrf52840_mdk/doc/index.rst | 2 +- boards/riscv/esp32c3_devkitm/doc/index.rst | 2 +- .../riscv/esp32c3_luatos_core/doc/index.rst | 2 +- doc/connectivity/bluetooth/api/mesh.rst | 4 +-- .../bluetooth/api/mesh/access.rst | 4 +-- doc/connectivity/bluetooth/api/mesh/blob.rst | 6 ++-- .../bluetooth/api/mesh/blob_cli.rst | 2 +- .../bluetooth/api/mesh/blob_srv.rst | 2 +- doc/connectivity/bluetooth/api/mesh/cfg.rst | 2 +- .../bluetooth/api/mesh/cfg_cli.rst | 2 +- .../bluetooth/api/mesh/cfg_srv.rst | 4 +-- doc/connectivity/bluetooth/api/mesh/core.rst | 4 +-- doc/connectivity/bluetooth/api/mesh/dfu.rst | 24 ++++++------- .../bluetooth/api/mesh/dfu_srv.rst | 8 ++--- .../bluetooth/api/mesh/health_srv.rst | 4 +-- .../bluetooth/api/mesh/heartbeat.rst | 2 +- .../bluetooth/api/mesh/lcd_cli.rst | 2 +- .../bluetooth/api/mesh/lcd_srv.rst | 2 +- .../bluetooth/api/mesh/models.rst | 4 +-- doc/connectivity/bluetooth/api/mesh/msg.rst | 2 +- .../bluetooth/api/mesh/od_cli.rst | 2 +- .../bluetooth/api/mesh/od_srv.rst | 2 +- .../bluetooth/api/mesh/op_agg_cli.rst | 2 +- .../bluetooth/api/mesh/priv_beacon_cli.rst | 2 +- .../bluetooth/api/mesh/priv_beacon_srv.rst | 2 +- .../bluetooth/api/mesh/provisioning.rst | 8 ++--- doc/connectivity/bluetooth/api/mesh/proxy.rst | 2 +- .../bluetooth/api/mesh/sar_cfg.rst | 4 +-- .../bluetooth/api/mesh/sar_cfg_cli.rst | 2 +- .../bluetooth/api/mesh/sar_cfg_srv.rst | 4 +-- doc/connectivity/bluetooth/api/mesh/shell.rst | 34 +++++++++---------- doc/connectivity/bluetooth/bluetooth-arch.rst | 2 +- doc/connectivity/bluetooth/overview.rst | 2 +- doc/introduction/index.rst | 2 +- doc/kernel/timeutil.rst | 2 +- doc/security/vulnerabilities.rst | 4 +-- include/zephyr/bluetooth/mesh.h | 2 +- include/zephyr/bluetooth/mesh/blob_srv.h | 2 +- include/zephyr/bluetooth/mesh/cfg.h | 2 +- include/zephyr/bluetooth/mesh/dfu_cli.h | 2 +- include/zephyr/bluetooth/mesh/dfu_metadata.h | 4 +-- include/zephyr/bluetooth/mesh/dfu_srv.h | 4 +-- include/zephyr/bluetooth/mesh/main.h | 6 ++-- samples/bluetooth/mesh/README.rst | 2 +- samples/bluetooth/mesh_demo/README.rst | 2 +- samples/bluetooth/mesh_provisioner/README.rst | 2 +- samples/boards/nrf/mesh/onoff-app/README.rst | 2 +- .../onoff_level_lighting_vnd_app/README.rst | 2 +- .../boards/reel_board/mesh_badge/README.rst | 4 +-- subsys/bluetooth/Kconfig.logging | 26 +++++++------- subsys/bluetooth/common/Kconfig | 2 +- subsys/bluetooth/mesh/Kconfig | 20 +++++------ subsys/bluetooth/mesh/access.h | 2 +- subsys/bluetooth/mesh/settings.c | 2 +- subsys/bluetooth/mesh/shell/Kconfig | 10 +++--- subsys/bluetooth/mesh/shell/shell.c | 2 +- tests/bsim/bluetooth/mesh/README.rst | 14 ++++---- tests/bsim/bluetooth/mesh/prj.conf | 2 +- tests/bsim/bluetooth/mesh/prj_mesh1d1.conf | 2 +- tests/bsim/bluetooth/mesh/src/mesh_test.h | 2 +- 60 files changed, 140 insertions(+), 140 deletions(-) diff --git a/boards/arm/nrf52840_mdk/doc/index.rst b/boards/arm/nrf52840_mdk/doc/index.rst index 6e0b24b65f2..fce05bee593 100644 --- a/boards/arm/nrf52840_mdk/doc/index.rst +++ b/boards/arm/nrf52840_mdk/doc/index.rst @@ -7,7 +7,7 @@ Overview ******** The nRF52840-MDK is a versatile, easy-to-use IoT hardware platform for -Bluetooth 5, Bluetooth Mesh, Thread, IEEE 802.15.4, ANT and 2.4GHz proprietary +Bluetooth 5, Bluetooth mesh, Thread, IEEE 802.15.4, ANT and 2.4GHz proprietary applications using the nRF52840 SoC. The development kit comes with a fully integrated debugger (also known as diff --git a/boards/riscv/esp32c3_devkitm/doc/index.rst b/boards/riscv/esp32c3_devkitm/doc/index.rst index 26f1521e087..6d21b2918c3 100644 --- a/boards/riscv/esp32c3_devkitm/doc/index.rst +++ b/boards/riscv/esp32c3_devkitm/doc/index.rst @@ -18,7 +18,7 @@ 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 +- A Bluetooth LE subsystem that supports features of Bluetooth 5 and Bluetooth mesh - Various peripherals: - 12-bit ADC with up to 6 channels diff --git a/boards/riscv/esp32c3_luatos_core/doc/index.rst b/boards/riscv/esp32c3_luatos_core/doc/index.rst index fae8e2eb178..c943931a9e6 100644 --- a/boards/riscv/esp32c3_luatos_core/doc/index.rst +++ b/boards/riscv/esp32c3_luatos_core/doc/index.rst @@ -18,7 +18,7 @@ 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 +- A Bluetooth LE subsystem that supports features of Bluetooth 5 and Bluetooth mesh - Various peripherals: - 12-bit ADC with up to 6 channels diff --git a/doc/connectivity/bluetooth/api/mesh.rst b/doc/connectivity/bluetooth/api/mesh.rst index f234ff7cedc..457aa5b6895 100644 --- a/doc/connectivity/bluetooth/api/mesh.rst +++ b/doc/connectivity/bluetooth/api/mesh.rst @@ -3,14 +3,14 @@ Bluetooth Mesh Profile ###################### -The Bluetooth Mesh profile adds secure wireless multi-hop communication for +The Bluetooth mesh profile adds secure wireless multi-hop communication for Bluetooth Low Energy. This module implements the `Bluetooth Mesh Profile Specification v1.0.1 `_. Implementation of the `Bluetooth Mesh Protocol Specification v1.1 `_ is in experimental state. -Read more about Bluetooth Mesh on the +Read more about Bluetooth mesh on the `Bluetooth SIG Website `_. .. toctree:: diff --git a/doc/connectivity/bluetooth/api/mesh/access.rst b/doc/connectivity/bluetooth/api/mesh/access.rst index e4a94440556..2af8e6a03b8 100644 --- a/doc/connectivity/bluetooth/api/mesh/access.rst +++ b/doc/connectivity/bluetooth/api/mesh/access.rst @@ -3,7 +3,7 @@ Access layer ############ -The access layer is the application's interface to the Bluetooth Mesh network. +The access layer is the application's interface to the Bluetooth mesh network. The access layer provides mechanisms for compartmentalizing the node behavior into elements and models, which are implemented by the application. @@ -113,7 +113,7 @@ number within one publication interval. Extended models =============== -The Bluetooth Mesh specification allows the mesh models to extend each other. +The Bluetooth mesh specification allows the mesh models to extend each other. When a model extends another, it inherits that model's functionality, and extension can be used to construct complex models out of simple ones, leveraging the existing model functionality to avoid defining new opcodes. diff --git a/doc/connectivity/bluetooth/api/mesh/blob.rst b/doc/connectivity/bluetooth/api/mesh/blob.rst index 8395026afe4..31f45289560 100644 --- a/doc/connectivity/bluetooth/api/mesh/blob.rst +++ b/doc/connectivity/bluetooth/api/mesh/blob.rst @@ -5,7 +5,7 @@ BLOB Transfer models The Binary Large Object (BLOB) Transfer models implement the Bluetooth Mesh Binary Large Object Transfer Model specification version 1.0 and provide functionality for sending large binary objects -from a single source to many Target nodes over the Bluetooth Mesh network. It is the underlying +from a single source to many Target nodes over the Bluetooth mesh network. It is the underlying transport method for the :ref:`bluetooth_mesh_dfu`, but may be used for other object transfer purposes. The implementation is in experimental state. @@ -50,7 +50,7 @@ structure of the BLOB, and applications are free to define any encoding or compr on the data itself. The BLOB transfer protocol does not provide any built-in integrity checks, encryption or -authentication of the BLOB data. However, the underlying encryption of the Bluetooth Mesh protocol +authentication of the BLOB data. However, the underlying encryption of the Bluetooth mesh protocol provides data integrity checks and protects the contents of the BLOB from third parties using network and application level encryption. @@ -68,7 +68,7 @@ Chunks ------ Each block is divided into chunks. A chunk is the smallest data unit in the BLOB transfer, and must -fit inside a single Bluetooth Mesh access message excluding the opcode (379 bytes or less). The +fit inside a single Bluetooth mesh access message excluding the opcode (379 bytes or less). The mechanism for transferring chunks depends on the transfer mode. When operating in Push BLOB Transfer Mode, the chunks are sent as unacknowledged packets from the diff --git a/doc/connectivity/bluetooth/api/mesh/blob_cli.rst b/doc/connectivity/bluetooth/api/mesh/blob_cli.rst index b4193d50334..25b90c281c4 100644 --- a/doc/connectivity/bluetooth/api/mesh/blob_cli.rst +++ b/doc/connectivity/bluetooth/api/mesh/blob_cli.rst @@ -67,7 +67,7 @@ Target nodes having the BLOB Transfer Server model subscribe to this group addre Using group addresses for transferring the BLOBs can generally increase the transfer speed, as the BLOB Transfer Client sends each message to all Target nodes at the same time. However, sending -large, segmented messages to group addresses in Bluetooth Mesh is generally less reliable than +large, segmented messages to group addresses in Bluetooth mesh is generally less reliable than sending them to unicast addresses, as there is no transport layer acknowledgment mechanism for groups. This can lead to longer recovery periods at the end of each block, and increases the risk of losing Target nodes. Using group addresses for BLOB transfers will generally only pay off if the diff --git a/doc/connectivity/bluetooth/api/mesh/blob_srv.rst b/doc/connectivity/bluetooth/api/mesh/blob_srv.rst index 0d13e92148e..918b9493ff9 100644 --- a/doc/connectivity/bluetooth/api/mesh/blob_srv.rst +++ b/doc/connectivity/bluetooth/api/mesh/blob_srv.rst @@ -77,7 +77,7 @@ Transfer recovery ***************** The state of the BLOB transfer is stored persistently. If a reboot occurs, the BLOB Transfer Server -will attempt to recover the transfer. When the Bluetooth Mesh subsystem is started (for instance by +will attempt to recover the transfer. When the Bluetooth mesh subsystem is started (for instance by calling :c:func:`bt_mesh_init`), the BLOB Transfer Server will check for aborted transfers, and call the :c:member:`recover ` callback if there is any. In the recover callback, the user must provide a BLOB stream to use for the rest of the transfer. If the recover diff --git a/doc/connectivity/bluetooth/api/mesh/cfg.rst b/doc/connectivity/bluetooth/api/mesh/cfg.rst index e178984210d..01d3c9ca2e5 100644 --- a/doc/connectivity/bluetooth/api/mesh/cfg.rst +++ b/doc/connectivity/bluetooth/api/mesh/cfg.rst @@ -6,7 +6,7 @@ Runtime Configuration The runtime configuration API allows applications to change their runtime configuration directly, without going through the Configuration models. -Bluetooth Mesh nodes should generally be configured by a central network +Bluetooth mesh nodes should generally be configured by a central network configurator device with a :ref:`bluetooth_mesh_models_cfg_cli` model. Each mesh node instantiates a :ref:`bluetooth_mesh_models_cfg_srv` model that the Configuration Client can communicate with to change the node configuration. In some diff --git a/doc/connectivity/bluetooth/api/mesh/cfg_cli.rst b/doc/connectivity/bluetooth/api/mesh/cfg_cli.rst index 300c8ee3bc1..bf84edc6b86 100644 --- a/doc/connectivity/bluetooth/api/mesh/cfg_cli.rst +++ b/doc/connectivity/bluetooth/api/mesh/cfg_cli.rst @@ -3,7 +3,7 @@ Configuration Client #################### -The Configuration Client model is a foundation model defined by the Bluetooth Mesh +The Configuration Client model is a foundation model defined by the Bluetooth mesh specification. It provides functionality for configuring most parameters of a mesh node, including encryption keys, model configuration and feature enabling. diff --git a/doc/connectivity/bluetooth/api/mesh/cfg_srv.rst b/doc/connectivity/bluetooth/api/mesh/cfg_srv.rst index 8f595bf9b11..84f174df88b 100644 --- a/doc/connectivity/bluetooth/api/mesh/cfg_srv.rst +++ b/doc/connectivity/bluetooth/api/mesh/cfg_srv.rst @@ -3,7 +3,7 @@ Configuration Server #################### -The Configuration Server model is a foundation model defined by the Bluetooth Mesh +The Configuration Server model is a foundation model defined by the Bluetooth mesh specification. The Configuration Server model controls most parameters of the mesh node. It does not have an API of its own, but relies on a :ref:`bluetooth_mesh_models_cfg_cli` to control it. @@ -14,7 +14,7 @@ mesh node. It does not have an API of its own, but relies on a should be set through Kconfig, and the Heartbeat feature should be controlled through the :ref:`bluetooth_mesh_heartbeat` API. -The Configuration Server model is mandatory on all Bluetooth Mesh nodes, and +The Configuration Server model is mandatory on all Bluetooth mesh nodes, and must only be instantiated on the primary element. API reference diff --git a/doc/connectivity/bluetooth/api/mesh/core.rst b/doc/connectivity/bluetooth/api/mesh/core.rst index 94e2b8a6e5e..b9fdd164257 100644 --- a/doc/connectivity/bluetooth/api/mesh/core.rst +++ b/doc/connectivity/bluetooth/api/mesh/core.rst @@ -3,7 +3,7 @@ Core #### -The core provides functionality for managing the general Bluetooth Mesh +The core provides functionality for managing the general Bluetooth mesh state. .. _bluetooth_mesh_lpn: @@ -117,7 +117,7 @@ Advertisement identity All mesh stack bearers advertise data with the :c:macro:`BT_ID_DEFAULT` local identity. The value is preset in the mesh stack implementation. When Bluetooth® Low Energy (LE) -and Bluetooth Mesh coexist on the same device, the application should allocate and +and Bluetooth mesh coexist on the same device, the application should allocate and configure another local identity for Bluetooth LE purposes before starting the communication. API reference diff --git a/doc/connectivity/bluetooth/api/mesh/dfu.rst b/doc/connectivity/bluetooth/api/mesh/dfu.rst index 6718b3ea0ce..9cf55e244d6 100644 --- a/doc/connectivity/bluetooth/api/mesh/dfu.rst +++ b/doc/connectivity/bluetooth/api/mesh/dfu.rst @@ -3,16 +3,16 @@ Device Firmware Update (DFU) ############################ -Bluetooth Mesh supports the distribution of firmware images across a mesh network. The Bluetooth +Bluetooth mesh supports the distribution of firmware images across a mesh network. The Bluetooth mesh DFU subsystem implements the Bluetooth Mesh Device Firmware Update Model specification version 1.0. The implementation is in experimental state. -Bluetooth Mesh DFU implements a distribution mechanism for firmware images, and does not put any +Bluetooth mesh DFU implements a distribution mechanism for firmware images, and does not put any restrictions on the size, format or usage of the images. The primary design goal of the subsystem is -to provide the qualifiable parts of the Bluetooth Mesh DFU specification, and leave the usage, +to provide the qualifiable parts of the Bluetooth mesh DFU specification, and leave the usage, firmware validation and deployment to the application. -The DFU specification is implemented in the Zephyr Bluetooth Mesh DFU subsystem as three separate +The DFU specification is implemented in the Zephyr Bluetooth mesh DFU subsystem as three separate models: .. toctree:: @@ -28,7 +28,7 @@ Overview DFU roles ========= -The Bluetooth Mesh DFU subsystem defines three different roles the mesh nodes have to assume in the +The Bluetooth mesh DFU subsystem defines three different roles the mesh nodes have to assume in the distribution of firmware images: Target node @@ -47,20 +47,20 @@ Distributor image to the Target nodes. Initiator - The Initiator role is typically implemented by the same device that implements the Bluetooth Mesh + The Initiator role is typically implemented by the same device that implements the Bluetooth mesh :ref:`Provisioner ` and :ref:`Configurator ` roles. The Initiator needs a full overview of the potential Target nodes and their firmware, and will control (and initiate) all firmware updates. The - Initiator role is not implemented in the Zephyr Bluetooth Mesh DFU subsystem. + Initiator role is not implemented in the Zephyr Bluetooth mesh DFU subsystem. .. figure:: images/dfu_roles_mesh.svg :align: center :alt: Graphic overview of the DFU roles mesh nodes can have during the process of image distribution - DFU roles and the associated Bluetooth Mesh models + DFU roles and the associated Bluetooth mesh models -Bluetooth Mesh applications may combine the DFU roles in any way they'd like, and even take on +Bluetooth mesh applications may combine the DFU roles in any way they'd like, and even take on multiple instances of the same role by instantiating the models on separate elements. For instance, the Distributor and Initiator role can be combined by instantiating the :ref:`bluetooth_mesh_dfu_cli` on the Initiator node and calling its API directly. @@ -76,7 +76,7 @@ Firmware Update Client model directly, e.g. over a serial protocol. Stages ====== -The Bluetooth Mesh DFU process is designed to act in three stages: +The Bluetooth mesh DFU process is designed to act in three stages: Upload stage First, the image is uploaded to a Distributor in a mesh network by an external entity, such as a @@ -131,7 +131,7 @@ Firmware metadata Target node. The firmware metadata is optional, and its maximum length is determined by :kconfig:option:`CONFIG_BT_MESH_DFU_METADATA_MAXLEN`. - The Bluetooth Mesh DFU subsystem in Zephyr provides its own metadata format + The Bluetooth mesh DFU subsystem in Zephyr provides its own metadata format (:c:struct:`bt_mesh_dfu_metadata`) together with a set of related functions that can be used by an end product. The support for it is enabled using the :kconfig:option:`CONFIG_BT_MESH_DFU_METADATA` option. The format of the metadata is presented in @@ -299,7 +299,7 @@ following steps: node firmware image index and the firmware image metadata. Each Target node performs a metadata check and prepares their BLOB Transfer Server model for the transfer, before sending a status response to the Firmware Update Client, indicating if the firmware update will have any effect on - the Bluetooth Mesh state of the node. + the Bluetooth mesh state of the node. #. The Distributor's BLOB Transfer Client model transfers the firmware image to all Target nodes. #. Once the BLOB transfer has been received, the Target nodes' applications verify that the firmware is valid by performing checks such as signature verification or image checksums against the image diff --git a/doc/connectivity/bluetooth/api/mesh/dfu_srv.rst b/doc/connectivity/bluetooth/api/mesh/dfu_srv.rst index 105bdecb86c..2642dec8cc9 100644 --- a/doc/connectivity/bluetooth/api/mesh/dfu_srv.rst +++ b/doc/connectivity/bluetooth/api/mesh/dfu_srv.rst @@ -16,7 +16,7 @@ Firmware images The Firmware Update Server holds a list of all the updatable firmware images on the device. The full list shall be passed to the server through the ``_imgs`` parameter in -:c:macro:`BT_MESH_DFU_SRV_INIT`, and must be populated before the Bluetooth Mesh subsystem is +:c:macro:`BT_MESH_DFU_SRV_INIT`, and must be populated before the Bluetooth mesh subsystem is started. Each firmware image in the image list must be independently updatable, and should have its own firmware ID. @@ -33,9 +33,9 @@ application is described below: .. figure:: images/dfu_srv.svg :align: center - :alt: Bluetooth Mesh Firmware Update Server transfer + :alt: Bluetooth mesh Firmware Update Server transfer - Bluetooth Mesh Firmware Update Server transfer + Bluetooth mesh Firmware Update Server transfer Transfer check ============== @@ -118,7 +118,7 @@ updated image. When the transfer applies to the mesh application itself, the device might have to reboot as part of the swap. This restart can be performed from inside the apply callback, or done asynchronously. After booting up with the new firmware, the firmware image table should be updated before the -Bluetooth Mesh subsystem is started. +Bluetooth mesh subsystem is started. The Distributor will read out the firmware image table to confirm that the transfer was successfully applied. If the metadata check indicated that the device would become unprovisioned, the Target node diff --git a/doc/connectivity/bluetooth/api/mesh/health_srv.rst b/doc/connectivity/bluetooth/api/mesh/health_srv.rst index 6f7b1fc3f33..84c543b4766 100644 --- a/doc/connectivity/bluetooth/api/mesh/health_srv.rst +++ b/doc/connectivity/bluetooth/api/mesh/health_srv.rst @@ -21,7 +21,7 @@ necessarily damaging to the device. Errors indicate conditions that are outside of the node's design limits, and may have caused invalid behavior or permanent damage to the device. -Fault values ``0x01`` to ``0x7f`` are reserved for the Bluetooth Mesh +Fault values ``0x01`` to ``0x7f`` are reserved for the Bluetooth mesh specification, and the full list of specification defined faults are available in :ref:`bluetooth_mesh_health_faults`. Fault values ``0x80`` to ``0xff`` are vendor specific. The list of faults are always reported with a company ID to @@ -57,6 +57,6 @@ API reference Health faults ============= -Fault values defined by the Bluetooth Mesh specification. +Fault values defined by the Bluetooth mesh specification. .. doxygengroup:: bt_mesh_health_faults diff --git a/doc/connectivity/bluetooth/api/mesh/heartbeat.rst b/doc/connectivity/bluetooth/api/mesh/heartbeat.rst index 706625849c1..16c2bfa7840 100644 --- a/doc/connectivity/bluetooth/api/mesh/heartbeat.rst +++ b/doc/connectivity/bluetooth/api/mesh/heartbeat.rst @@ -3,7 +3,7 @@ Heartbeat ######### -The Heartbeat feature provides functionality for monitoring Bluetooth Mesh nodes +The Heartbeat feature provides functionality for monitoring Bluetooth mesh nodes and determining the distance between nodes. The Heartbeat feature is configured through the :ref:`bluetooth_mesh_models_cfg_srv` model. diff --git a/doc/connectivity/bluetooth/api/mesh/lcd_cli.rst b/doc/connectivity/bluetooth/api/mesh/lcd_cli.rst index 96189e21dd3..0eca28f1b2a 100644 --- a/doc/connectivity/bluetooth/api/mesh/lcd_cli.rst +++ b/doc/connectivity/bluetooth/api/mesh/lcd_cli.rst @@ -3,7 +3,7 @@ Large Composition Data Client ############################# -The Large Composition Data Client model is a foundation model defined by the Bluetooth Mesh +The Large Composition Data Client model is a foundation model defined by the Bluetooth mesh specification. The model is optional, and is enabled through the :kconfig:option:`CONFIG_BT_MESH_LARGE_COMP_DATA_CLI` option. diff --git a/doc/connectivity/bluetooth/api/mesh/lcd_srv.rst b/doc/connectivity/bluetooth/api/mesh/lcd_srv.rst index f67b31c27f8..f96436138b7 100644 --- a/doc/connectivity/bluetooth/api/mesh/lcd_srv.rst +++ b/doc/connectivity/bluetooth/api/mesh/lcd_srv.rst @@ -3,7 +3,7 @@ Large Composition Data Server ############################# -The Large Composition Data Server model is a foundation model defined by the Bluetooth Mesh +The Large Composition Data Server model is a foundation model defined by the Bluetooth mesh specification. The model is optional, and is enabled through the :kconfig:option:`CONFIG_BT_MESH_LARGE_COMP_DATA_SRV` option. diff --git a/doc/connectivity/bluetooth/api/mesh/models.rst b/doc/connectivity/bluetooth/api/mesh/models.rst index 94c3914ca53..3f5f94152ce 100644 --- a/doc/connectivity/bluetooth/api/mesh/models.rst +++ b/doc/connectivity/bluetooth/api/mesh/models.rst @@ -6,7 +6,7 @@ Mesh models Foundation models ***************** -The Bluetooth Mesh specification defines foundation models that can be +The Bluetooth mesh specification defines foundation models that can be used by network administrators to configure and diagnose mesh nodes. .. toctree:: @@ -34,7 +34,7 @@ used by network administrators to configure and diagnose mesh nodes. Model specification models ************************** -In addition to the foundation models defined in the Bluetooth Mesh specification, the Bluetooth Mesh +In addition to the foundation models defined in the Bluetooth mesh specification, the Bluetooth Mesh Model Specification defines several models, some of which are implemented in Zephyr: .. toctree:: diff --git a/doc/connectivity/bluetooth/api/mesh/msg.rst b/doc/connectivity/bluetooth/api/mesh/msg.rst index 614d2604d90..ae8b968198a 100644 --- a/doc/connectivity/bluetooth/api/mesh/msg.rst +++ b/doc/connectivity/bluetooth/api/mesh/msg.rst @@ -3,7 +3,7 @@ Message ####### -The Bluetooth Mesh message provides set of structures, macros and functions used +The Bluetooth mesh message provides set of structures, macros and functions used for preparing message buffers, managing message and acknowledged message contexts. diff --git a/doc/connectivity/bluetooth/api/mesh/od_cli.rst b/doc/connectivity/bluetooth/api/mesh/od_cli.rst index e419acb7572..5fc841716ce 100644 --- a/doc/connectivity/bluetooth/api/mesh/od_cli.rst +++ b/doc/connectivity/bluetooth/api/mesh/od_cli.rst @@ -3,7 +3,7 @@ On-Demand Private Proxy Client ############################## -The On-Demand Private Proxy Client model is a foundation model defined by the Bluetooth Mesh +The On-Demand Private Proxy Client model is a foundation model defined by the Bluetooth mesh specification. The model is optional, and is enabled with the :kconfig:option:`CONFIG_BT_MESH_OD_PRIV_PROXY_CLI` option. diff --git a/doc/connectivity/bluetooth/api/mesh/od_srv.rst b/doc/connectivity/bluetooth/api/mesh/od_srv.rst index 3c2f993bb30..700517e4283 100644 --- a/doc/connectivity/bluetooth/api/mesh/od_srv.rst +++ b/doc/connectivity/bluetooth/api/mesh/od_srv.rst @@ -3,7 +3,7 @@ On-Demand Private Proxy Server ############################## -The On-Demand Private Proxy Server model is a foundation model defined by the Bluetooth Mesh +The On-Demand Private Proxy Server model is a foundation model defined by the Bluetooth mesh specification. It is enabled with the :kconfig:option:`CONFIG_BT_MESH_OD_PRIV_PROXY_SRV` option. The On-Demand Private Proxy Server model was introduced in the Bluetooth Mesh Protocol Specification diff --git a/doc/connectivity/bluetooth/api/mesh/op_agg_cli.rst b/doc/connectivity/bluetooth/api/mesh/op_agg_cli.rst index 4648b4495cd..148557a4e81 100644 --- a/doc/connectivity/bluetooth/api/mesh/op_agg_cli.rst +++ b/doc/connectivity/bluetooth/api/mesh/op_agg_cli.rst @@ -3,7 +3,7 @@ Opcodes Aggregator Client ######################### -The Opcodes Aggregator Client model is a foundation model defined by the Bluetooth Mesh +The Opcodes Aggregator Client model is a foundation model defined by the Bluetooth mesh specification. It is an optional model, enabled with the :kconfig:option:`CONFIG_BT_MESH_OP_AGG_CLI` option. diff --git a/doc/connectivity/bluetooth/api/mesh/priv_beacon_cli.rst b/doc/connectivity/bluetooth/api/mesh/priv_beacon_cli.rst index c9bcc8e5eb1..cb531a4c3c8 100644 --- a/doc/connectivity/bluetooth/api/mesh/priv_beacon_cli.rst +++ b/doc/connectivity/bluetooth/api/mesh/priv_beacon_cli.rst @@ -11,7 +11,7 @@ The Private Beacon Client model is introduced in the Bluetooth Mesh Protocol Specification version 1.1, and provides functionality for configuring the :ref:`bluetooth_mesh_models_priv_beacon_srv` models. -The Private Beacons feature adds privacy to the different Bluetooth Mesh +The Private Beacons feature adds privacy to the different Bluetooth mesh beacons by periodically randomizing the beacon input data. This protects the mesh node from being tracked by devices outside the mesh network, and hides the network's IV index, IV update and the Key Refresh state. diff --git a/doc/connectivity/bluetooth/api/mesh/priv_beacon_srv.rst b/doc/connectivity/bluetooth/api/mesh/priv_beacon_srv.rst index 62450634a31..3c17cc44675 100644 --- a/doc/connectivity/bluetooth/api/mesh/priv_beacon_srv.rst +++ b/doc/connectivity/bluetooth/api/mesh/priv_beacon_srv.rst @@ -11,7 +11,7 @@ The Private Beacon Server model is introduced in the Bluetooth Mesh Protocol Specification version 1.1, and controls the mesh node's Private Beacon state, Private GATT Proxy state and Private Node Identity state. -The Private Beacons feature adds privacy to the different Bluetooth Mesh +The Private Beacons feature adds privacy to the different Bluetooth mesh beacons by periodically randomizing the beacon input data. This protects the mesh node from being tracked by devices outside the mesh network, and hides the network's IV index, IV update and the Key Refresh state. The Private Beacon Server diff --git a/doc/connectivity/bluetooth/api/mesh/provisioning.rst b/doc/connectivity/bluetooth/api/mesh/provisioning.rst index 685c9dda455..36fa38927a3 100644 --- a/doc/connectivity/bluetooth/api/mesh/provisioning.rst +++ b/doc/connectivity/bluetooth/api/mesh/provisioning.rst @@ -12,15 +12,15 @@ two devices operating in the following roles: Provisioning process. Before the provisioning process starts, the provisionee is an *unprovisioned device*. -The Provisioning module in the Zephyr Bluetooth Mesh stack supports both the +The Provisioning module in the Zephyr Bluetooth mesh stack supports both the Advertising and GATT Provisioning bearers for the provisionee role, as well as the Advertising Provisioning bearer for the provisioner role. The Provisioning process ************************ -All Bluetooth Mesh nodes must be provisioned before they can participate in a -Bluetooth Mesh network. The Provisioning API provides all the functionality +All Bluetooth mesh nodes must be provisioned before they can participate in a +Bluetooth mesh network. The Provisioning API provides all the functionality necessary for a device to become a provisioned mesh node. Provisioning is a five-step process, involving the following steps: @@ -176,7 +176,7 @@ Depending on the choice of public key exchange mechanism and authentication meth the provisioning process can be secure or insecure. On May 24th 2021, ANSSI `disclosed `_ -a set of vulnerabilities in the Bluetooth Mesh provisioning protocol that showcased +a set of vulnerabilities in the Bluetooth mesh provisioning protocol that showcased how the low entropy provided by the Blink, Vibrate, Push, Twist and Input/Output numeric OOB methods could be exploited in impersonation and MITM attacks. In response, the Bluetooth SIG has reclassified these OOB methods as diff --git a/doc/connectivity/bluetooth/api/mesh/proxy.rst b/doc/connectivity/bluetooth/api/mesh/proxy.rst index 5e905f2c9ef..823401c9571 100644 --- a/doc/connectivity/bluetooth/api/mesh/proxy.rst +++ b/doc/connectivity/bluetooth/api/mesh/proxy.rst @@ -3,7 +3,7 @@ Proxy ##### -The Proxy feature allows legacy devices like phones to access the Bluetooth Mesh network through +The Proxy feature allows legacy devices like phones to access the Bluetooth mesh network through GATT. The Proxy feature is only compiled in if the :kconfig:option:`CONFIG_BT_MESH_GATT_PROXY` option is set. The Proxy feature state is controlled by the :ref:`bluetooth_mesh_models_cfg_srv`, and the initial value can be set with :c:member:`bt_mesh_cfg_srv.gatt_proxy`. diff --git a/doc/connectivity/bluetooth/api/mesh/sar_cfg.rst b/doc/connectivity/bluetooth/api/mesh/sar_cfg.rst index 4f3354945c9..a0aa2b46a3e 100644 --- a/doc/connectivity/bluetooth/api/mesh/sar_cfg.rst +++ b/doc/connectivity/bluetooth/api/mesh/sar_cfg.rst @@ -4,7 +4,7 @@ Segmentation and reassembly (SAR) ################################# Segmentation and reassembly (SAR) provides a way of handling larger upper transport layer messages -in a mesh network, with a purpose of enhancing the Bluetooth Mesh throughput. The segmentation and +in a mesh network, with a purpose of enhancing the Bluetooth mesh throughput. The segmentation and reassembly mechanism is used by the lower transport layer. The lower transport layer defines how the upper transport layer PDUs are segmented and reassembled @@ -23,7 +23,7 @@ required. Set the ``send rel`` flag (see :c:struct:`bt_mesh_msg_ctx`) to use the transmission and acknowledge single-segment segmented messages. The transport layer is able to transport up to 32 segments with its SAR mechanism, with a maximum -message (PDU) size of 384 octets. To configure message size for the Bluetooth Mesh stack, use the +message (PDU) size of 384 octets. To configure message size for the Bluetooth mesh stack, use the following Kconfig options: * :kconfig:option:`CONFIG_BT_MESH_RX_SEG_MAX` to set the maximum number of segments in an incoming message. diff --git a/doc/connectivity/bluetooth/api/mesh/sar_cfg_cli.rst b/doc/connectivity/bluetooth/api/mesh/sar_cfg_cli.rst index 1e2ab6c47a1..b017b53a01a 100644 --- a/doc/connectivity/bluetooth/api/mesh/sar_cfg_cli.rst +++ b/doc/connectivity/bluetooth/api/mesh/sar_cfg_cli.rst @@ -3,7 +3,7 @@ SAR Configuration Client ######################## -The SAR Configuration Client model is a foundation model defined by the Bluetooth Mesh +The SAR Configuration Client model is a foundation model defined by the Bluetooth mesh specification. It is an optional model, enabled with the :kconfig:option:`CONFIG_BT_MESH_SAR_CFG_CLI` configuration option. diff --git a/doc/connectivity/bluetooth/api/mesh/sar_cfg_srv.rst b/doc/connectivity/bluetooth/api/mesh/sar_cfg_srv.rst index 4280fae1350..2ea1446c9ea 100644 --- a/doc/connectivity/bluetooth/api/mesh/sar_cfg_srv.rst +++ b/doc/connectivity/bluetooth/api/mesh/sar_cfg_srv.rst @@ -3,13 +3,13 @@ SAR Configuration Server ######################## -The SAR Configuration Server model is a foundation model defined by the Bluetooth Mesh +The SAR Configuration Server model is a foundation model defined by the Bluetooth mesh specification. It is an optional model, enabled with the :kconfig:option:`CONFIG_BT_MESH_SAR_CFG_SRV` configuration option. The SAR Configuration Server model is introduced in the Bluetooth Mesh Protocol Specification version 1.1, and it supports the configuration of the -:ref:`segmentation and reassembly (SAR) ` behavior of a Bluetooth Mesh node. +:ref:`segmentation and reassembly (SAR) ` behavior of a Bluetooth mesh node. The model defines a set of states and messages for the SAR configuration. The SAR Configuration Server model defines two states, SAR Transmitter state and SAR Receiver state. diff --git a/doc/connectivity/bluetooth/api/mesh/shell.rst b/doc/connectivity/bluetooth/api/mesh/shell.rst index 9d5829fe380..66bfcdf6168 100644 --- a/doc/connectivity/bluetooth/api/mesh/shell.rst +++ b/doc/connectivity/bluetooth/api/mesh/shell.rst @@ -3,32 +3,32 @@ Bluetooth Mesh Shell #################### -The Bluetooth Mesh shell subsystem provides a set of Bluetooth Mesh shell commands for the -:ref:`shell_api` module. It allows for testing and exploring the Bluetooth Mesh API through an +The Bluetooth mesh shell subsystem provides a set of Bluetooth mesh shell commands for the +:ref:`shell_api` module. It allows for testing and exploring the Bluetooth mesh API through an interactive interface, without having to write an application. -The Bluetooth Mesh shell interface provides access to most Bluetooth Mesh features, including +The Bluetooth mesh shell interface provides access to most Bluetooth mesh features, including provisioning, configuration, and message sending. Prerequisites ************* -The Bluetooth Mesh shell subsystem depends on the application to create the composition data and do +The Bluetooth mesh shell subsystem depends on the application to create the composition data and do the mesh initialization. Application *********** -The Bluetooth Mesh shell subsystem is most easily used through the Bluetooth Mesh shell application +The Bluetooth mesh shell subsystem is most easily used through the Bluetooth mesh shell application under ``tests/bluetooth/mesh_shell``. See :ref:`shell_api` for information on how to connect and -interact with the Bluetooth Mesh shell application. +interact with the Bluetooth mesh shell application. Basic usage *********** -The Bluetooth Mesh shell subsystem adds a single ``mesh`` command, which holds a set of +The Bluetooth mesh shell subsystem adds a single ``mesh`` command, which holds a set of sub-commands. Every time the device boots up, make sure to call ``mesh init`` before any of the -other Bluetooth Mesh shell commands can be called:: +other Bluetooth mesh shell commands can be called:: uart:~$ mesh init @@ -82,7 +82,7 @@ Message sending =============== With an application key added (see above), the mesh node's transition parameters are all valid, and -the Bluetooth Mesh shell can send raw mesh messages through the network. +the Bluetooth mesh shell can send raw mesh messages through the network. For example, to send a Generic OnOff Set message, call:: @@ -107,7 +107,7 @@ configured network and application keys will receive and process the messages we Sending raw mesh packets is a good way to test model message handler implementations during development, as it can be done without having to implement the sending model. By default, only the -reception of the model messages can be tested this way, as the Bluetooth Mesh shell only includes +reception of the model messages can be tested this way, as the Bluetooth mesh shell only includes the foundation models. To receive a packet in the mesh node, you have to add a model with a valid opcode handler list to the composition data in ``subsys/bluetooth/mesh/shell.c``, and print the incoming message to the shell in the handler callback. @@ -115,7 +115,7 @@ incoming message to the shell in the handler callback. Parameter formats ***************** -The Bluetooth Mesh shell commands are parsed with a variety of formats: +The Bluetooth mesh shell commands are parsed with a variety of formats: .. list-table:: Parameter formats :widths: 1 4 2 @@ -139,12 +139,12 @@ The Bluetooth Mesh shell commands are parsed with a variety of formats: Commands ******** -The Bluetooth Mesh shell implements a large set of commands. Some of the commands accept parameters, +The Bluetooth mesh shell implements a large set of commands. Some of the commands accept parameters, which are mentioned in brackets after the command name. For example, ``mesh lpn set ``. Mandatory parameters are marked with angle brackets (e.g. ````), and optional parameters are marked with square brackets (e.g. ``[DstAddr]``). -The Bluetooth Mesh shell commands are divided into the following groups: +The Bluetooth mesh shell commands are divided into the following groups: .. contents:: :depth: 1 @@ -500,10 +500,10 @@ application. This shell module can be used for configuring itself and other node network. The Configuration Client uses general message parameters set by ``mesh target dst`` and ``mesh -target net`` to target specific nodes. When the Bluetooth Mesh shell node is provisioned, given that +target net`` to target specific nodes. When the Bluetooth mesh shell node is provisioned, given that the :kconfig:option:`CONFIG_BT_MESH_SHELL_PROV_CTX_INSTANCE` option is enabled with the shell provisioning context initialized, the Configuration Client model targets itself by default. -Similarly, when another node has been provisioned by the Bluetooth Mesh shell, the Configuration +Similarly, when another node has been provisioned by the Bluetooth mesh shell, the Configuration Client model targets the new node. In most common use-cases, the Configuration Client is depending on the provisioning features and the Configuration database to be fully functional. The Configuration Client always sends messages using the Device key bound to the destination address, so @@ -1645,7 +1645,7 @@ The Private Beacon Client model is an optional mesh subsystem that can be enable Opcodes Aggregator Client ------------------------- -The Opcodes Aggregator client is an optional Bluetooth Mesh model that can be enabled through the +The Opcodes Aggregator client is an optional Bluetooth mesh model that can be enabled through the :kconfig:option:`CONFIG_BT_MESH_OP_AGG_CLI` configuration option. The Opcodes Aggregator Client model is used to support the functionality of dispatching a sequence of access layer messages to nodes supporting the Opcodes Aggregator Server model. @@ -1675,7 +1675,7 @@ nodes supporting the Opcodes Aggregator Server model. Remote Provisioning Client -------------------------- -The Remote Provisioning Client is an optional Bluetooth Mesh model enabled through the +The Remote Provisioning Client is an optional Bluetooth mesh model enabled through the :kconfig:option:`CONFIG_BT_MESH_RPR_CLI` configuration option. The Remote Provisioning Client model provides support for remote provisioning of devices into a mesh network by using the Remote Provisioning Server model. diff --git a/doc/connectivity/bluetooth/bluetooth-arch.rst b/doc/connectivity/bluetooth/bluetooth-arch.rst index ed0cf1ea9f6..9b455e680d0 100644 --- a/doc/connectivity/bluetooth/bluetooth-arch.rst +++ b/doc/connectivity/bluetooth/bluetooth-arch.rst @@ -248,7 +248,7 @@ Each role comes with its own build-time configuration option: connection-oriented roles central implicitly enables observer role, and peripheral implicitly enables broadcaster role. Usually the first step when creating an application is to decide which roles are needed and go -from there. Bluetooth Mesh is a slightly special case, requiring at +from there. Bluetooth mesh is a slightly special case, requiring at least the observer and broadcaster roles, and possibly also the Peripheral role. This will be described in more detail in a later section. diff --git a/doc/connectivity/bluetooth/overview.rst b/doc/connectivity/bluetooth/overview.rst index 1f727736b2d..fece4ade496 100644 --- a/doc/connectivity/bluetooth/overview.rst +++ b/doc/connectivity/bluetooth/overview.rst @@ -76,7 +76,7 @@ Bluetooth stack. * Non-volatile storage support for permanent storage of Bluetooth-specific settings and data - * Bluetooth Mesh support + * Bluetooth mesh support * Relay, Friend Node, Low-Power Node (LPN) and GATT Proxy features * Both Provisioning roles and bearers supported (PB-ADV & PB-GATT) diff --git a/doc/introduction/index.rst b/doc/introduction/index.rst index 13204e6bb7d..85968ca456a 100644 --- a/doc/introduction/index.rst +++ b/doc/introduction/index.rst @@ -123,7 +123,7 @@ Zephyr offers a large and ever growing number of features including: **Bluetooth Low Energy 5.0 support** Bluetooth 5.0 compliant (ESR10) and Bluetooth Low Energy Controller support - (LE Link Layer). Includes Bluetooth Mesh and a Bluetooth qualification-ready + (LE Link Layer). Includes Bluetooth mesh and a Bluetooth qualification-ready Bluetooth controller. * Generic Access Profile (GAP) with all possible LE roles diff --git a/doc/kernel/timeutil.rst b/doc/kernel/timeutil.rst index 203d52ea9af..d41c5b48b89 100644 --- a/doc/kernel/timeutil.rst +++ b/doc/kernel/timeutil.rst @@ -223,7 +223,7 @@ include: - GPS time: epoch of 1980-01-06T00:00:00Z, continuous following TAI with an offset of TAI-GPS=19 s. -- Bluetooth Mesh time: epoch of 2000-01-01T00:00:00Z, continuous following TAI +- Bluetooth mesh time: epoch of 2000-01-01T00:00:00Z, continuous following TAI with an offset of -32. - UNIX Leap Time: epoch of 1970-01-01T00:00:00Z, continuous following TAI with an offset of -8. diff --git a/doc/security/vulnerabilities.rst b/doc/security/vulnerabilities.rst index fde156983d3..61d0d25f618 100644 --- a/doc/security/vulnerabilities.rst +++ b/doc/security/vulnerabilities.rst @@ -1176,7 +1176,7 @@ This has been fixed in main for v3.0.0 CVE-2022-1041 -------------- -Out-of-bound write vulnerability in the Bluetooth Mesh core stack can be triggered during provisioning +Out-of-bound write vulnerability in the Bluetooth mesh core stack can be triggered during provisioning This has been fixed in main for v3.1.0 @@ -1195,7 +1195,7 @@ This has been fixed in main for v3.1.0 CVE-2022-1042 -------------- -Out-of-bound write vulnerability in the Bluetooth Mesh core stack can be triggered during provisioning +Out-of-bound write vulnerability in the Bluetooth mesh core stack can be triggered during provisioning This has been fixed in main for v3.1.0 diff --git a/include/zephyr/bluetooth/mesh.h b/include/zephyr/bluetooth/mesh.h index fc84814fa44..a4ef70dc6de 100644 --- a/include/zephyr/bluetooth/mesh.h +++ b/include/zephyr/bluetooth/mesh.h @@ -1,5 +1,5 @@ /** @file - * @brief Bluetooth Mesh Profile APIs. + * @brief Bluetooth mesh Profile APIs. */ /* diff --git a/include/zephyr/bluetooth/mesh/blob_srv.h b/include/zephyr/bluetooth/mesh/blob_srv.h index 92c809bd6b5..bf807bad92f 100644 --- a/include/zephyr/bluetooth/mesh/blob_srv.h +++ b/include/zephyr/bluetooth/mesh/blob_srv.h @@ -108,7 +108,7 @@ struct bt_mesh_blob_srv_cb { /** @brief Transfer recovery callback. * - * Called when the Bluetooth Mesh subsystem is started if the device is rebooted + * Called when the Bluetooth mesh subsystem is started if the device is rebooted * in the middle of a transfer. * * Transfers will not be resumed after a reboot if this callback is not diff --git a/include/zephyr/bluetooth/mesh/cfg.h b/include/zephyr/bluetooth/mesh/cfg.h index 9bfd067da9b..7d1ca4e868f 100644 --- a/include/zephyr/bluetooth/mesh/cfg.h +++ b/include/zephyr/bluetooth/mesh/cfg.h @@ -26,7 +26,7 @@ extern "C" { #endif -/** Bluetooth Mesh feature states */ +/** Bluetooth mesh feature states */ enum bt_mesh_feat_state { /** Feature is supported, but disabled. */ BT_MESH_FEATURE_DISABLED, diff --git a/include/zephyr/bluetooth/mesh/dfu_cli.h b/include/zephyr/bluetooth/mesh/dfu_cli.h index ad8881ebc26..3cbc220d825 100644 --- a/include/zephyr/bluetooth/mesh/dfu_cli.h +++ b/include/zephyr/bluetooth/mesh/dfu_cli.h @@ -9,7 +9,7 @@ * @defgroup bt_mesh_dfu_cli Firmware Uppdate Client model * @ingroup bt_mesh_dfu * @{ - * @brief API for the Bluetooth Mesh Firmware Update Client model + * @brief API for the Bluetooth mesh Firmware Update Client model */ #ifndef ZEPHYR_INCLUDE_BLUETOOTH_MESH_DFU_CLI_H__ diff --git a/include/zephyr/bluetooth/mesh/dfu_metadata.h b/include/zephyr/bluetooth/mesh/dfu_metadata.h index 21d032236a7..bec65897ac7 100644 --- a/include/zephyr/bluetooth/mesh/dfu_metadata.h +++ b/include/zephyr/bluetooth/mesh/dfu_metadata.h @@ -6,10 +6,10 @@ /** * @file - * @defgroup bt_mesh_dfu_metadata Bluetooth Mesh Device Firmware Update (DFU) metadata + * @defgroup bt_mesh_dfu_metadata Bluetooth mesh Device Firmware Update (DFU) metadata * @ingroup bt_mesh_dfu * @{ - * @brief Common types and functions for the Bluetooth Mesh DFU metadata. + * @brief Common types and functions for the Bluetooth mesh DFU metadata. */ #ifndef ZEPHYR_INCLUDE_BLUETOOTH_MESH_DFU_METADATA_H__ diff --git a/include/zephyr/bluetooth/mesh/dfu_srv.h b/include/zephyr/bluetooth/mesh/dfu_srv.h index 2beaf2d9772..e136701e664 100644 --- a/include/zephyr/bluetooth/mesh/dfu_srv.h +++ b/include/zephyr/bluetooth/mesh/dfu_srv.h @@ -9,7 +9,7 @@ * @defgroup bt_mesh_dfu_srv Firmware Update Server model * @ingroup bt_mesh_dfu * @{ - * @brief API for the Bluetooth Mesh Firmware Update Server model + * @brief API for the Bluetooth mesh Firmware Update Server model */ #ifndef ZEPHYR_INCLUDE_BLUETOOTH_MESH_DFU_SRV_H__ @@ -136,7 +136,7 @@ struct bt_mesh_dfu_srv_cb { /** @brief Transfer recovery callback. * * If the device reboots in the middle of a transfer, the Firmware Update Server - * calls this function when the Bluetooth Mesh subsystem is started. + * calls this function when the Bluetooth mesh subsystem is started. * * This callback is optional, but transfers will not be recovered after * a reboot without it. diff --git a/include/zephyr/bluetooth/mesh/main.h b/include/zephyr/bluetooth/mesh/main.h index 8e7445fae6f..a4e98b97f8c 100644 --- a/include/zephyr/bluetooth/mesh/main.h +++ b/include/zephyr/bluetooth/mesh/main.h @@ -1,5 +1,5 @@ /** @file - * @brief Bluetooth Mesh Protocol APIs. + * @brief Bluetooth mesh Protocol APIs. */ /* @@ -550,8 +550,8 @@ bool bt_mesh_is_provisioned(void); */ /** - * @brief Bluetooth Mesh - * @defgroup bt_mesh Bluetooth Mesh + * @brief Bluetooth mesh + * @defgroup bt_mesh Bluetooth mesh * @ingroup bluetooth * @{ */ diff --git a/samples/bluetooth/mesh/README.rst b/samples/bluetooth/mesh/README.rst index 58532a0600b..e6ee78ba3a7 100644 --- a/samples/bluetooth/mesh/README.rst +++ b/samples/bluetooth/mesh/README.rst @@ -6,7 +6,7 @@ Bluetooth: Mesh Overview ******** -This sample demonstrates Bluetooth Mesh functionality. It has several +This sample demonstrates Bluetooth mesh functionality. It has several standard mesh models, and supports provisioning over both the Advertising and the GATT Provisioning Bearers (i.e. PB-ADV and PB-GATT). The application also needs a functioning serial console, since that's diff --git a/samples/bluetooth/mesh_demo/README.rst b/samples/bluetooth/mesh_demo/README.rst index 2edb690ab19..7fe7f0908ce 100644 --- a/samples/bluetooth/mesh_demo/README.rst +++ b/samples/bluetooth/mesh_demo/README.rst @@ -6,7 +6,7 @@ Bluetooth: Mesh Demo Overview ******** -This sample is a Bluetooth Mesh application intended for demonstration +This sample is a Bluetooth mesh application intended for demonstration purposes only. The application provisions and configures itself (i.e. no external provisioner needed) with hard-coded network and application key values. The local unicast address can be set using a NODE_ADDR build diff --git a/samples/bluetooth/mesh_provisioner/README.rst b/samples/bluetooth/mesh_provisioner/README.rst index 1b37a04a4a8..6da113afc1b 100644 --- a/samples/bluetooth/mesh_provisioner/README.rst +++ b/samples/bluetooth/mesh_provisioner/README.rst @@ -6,7 +6,7 @@ Bluetooth: Mesh Provisioner Overview ******** -This sample demonstrates how to use the Bluetooth Mesh APIs related to +This sample demonstrates how to use the Bluetooth mesh APIs related to provisioning and using the Configuration Database (CDB). It is intended to be tested together with a device capable of being provisioned. For example, one could use the sample in diff --git a/samples/boards/nrf/mesh/onoff-app/README.rst b/samples/boards/nrf/mesh/onoff-app/README.rst index 35e37d6a599..e8cadccd53c 100644 --- a/samples/boards/nrf/mesh/onoff-app/README.rst +++ b/samples/boards/nrf/mesh/onoff-app/README.rst @@ -6,7 +6,7 @@ Bluetooth: Mesh OnOff Model Overview ******** -This is a simple application demonstrating a Bluetooth Mesh multi-element node. +This is a simple application demonstrating a Bluetooth mesh multi-element node. Each element has a mesh onoff client and server model which controls one of the 4 sets of buttons and LEDs . diff --git a/samples/boards/nrf/mesh/onoff_level_lighting_vnd_app/README.rst b/samples/boards/nrf/mesh/onoff_level_lighting_vnd_app/README.rst index f33bf1e7761..05b8d896e77 100644 --- a/samples/boards/nrf/mesh/onoff_level_lighting_vnd_app/README.rst +++ b/samples/boards/nrf/mesh/onoff_level_lighting_vnd_app/README.rst @@ -4,7 +4,7 @@ Bluetooth: Mesh Generic OnOff, Generic Level, Lighting & Vendor Models ###################################################################### Overview ******** -This is a application demonstrating a Bluetooth Mesh node in +This is a application demonstrating a Bluetooth mesh node in which Root element has following models - Generic OnOff Server diff --git a/samples/boards/reel_board/mesh_badge/README.rst b/samples/boards/reel_board/mesh_badge/README.rst index ccfc7e771ae..d5973ab8e9c 100644 --- a/samples/boards/reel_board/mesh_badge/README.rst +++ b/samples/boards/reel_board/mesh_badge/README.rst @@ -6,7 +6,7 @@ Mesh Badge Overview ******** -This sample app for the reel board showcases Bluetooth Mesh +This sample app for the reel board showcases Bluetooth mesh The app starts off as a regular Bluetooth GATT peripheral application. Install the "nRF Connect" app on your phone (available both for @@ -34,7 +34,7 @@ Steps to set up you're not happy with it you can try writing something else. #. When you're happy with the text, disconnect from the board (exit the app or go back to the device scan page) -#. Once disconnected the board switches over to Bluetooth Mesh mode, and you +#. Once disconnected the board switches over to Bluetooth mesh mode, and you can't connect to it anymore over GATT. If you configure multiple boards like this they can communicate with diff --git a/subsys/bluetooth/Kconfig.logging b/subsys/bluetooth/Kconfig.logging index 6d8b999e03c..ec95ddad10e 100644 --- a/subsys/bluetooth/Kconfig.logging +++ b/subsys/bluetooth/Kconfig.logging @@ -469,56 +469,56 @@ config BT_MESH_DEBUG_NET select DEPRECATED help Use this option to enable Network layer debug logs for the - Bluetooth Mesh functionality. + Bluetooth mesh functionality. config BT_MESH_DEBUG_RPL bool "[DEPRECATED] Replay protection list debug" select DEPRECATED help Use this option to enable Replay protection list debug logs - for the Bluetooth Mesh functionality. + for the Bluetooth mesh functionality. config BT_MESH_DEBUG_TRANS bool "[DEPRECATED] Transport layer debug" select DEPRECATED help Use this option to enable Transport layer debug logs for the - Bluetooth Mesh functionality. + Bluetooth mesh functionality. config BT_MESH_DEBUG_BEACON bool "[DEPRECATED] Beacon debug" select DEPRECATED help Use this option to enable Beacon-related debug logs for the - Bluetooth Mesh functionality. + Bluetooth mesh functionality. config BT_MESH_DEBUG_CRYPTO bool "[DEPRECATED] Crypto debug" select DEPRECATED help Use this option to enable cryptographic debug logs for the - Bluetooth Mesh functionality. + Bluetooth mesh functionality. config BT_MESH_DEBUG_KEYS bool "[DEPRECATED] Key management debug" select DEPRECATED help Use this option to enable key management debug logs for the - Bluetooth Mesh functionality. + Bluetooth mesh functionality. config BT_MESH_DEBUG_PROV bool "[DEPRECATED] Provisioning debug" select DEPRECATED help Use this option to enable Provisioning debug logs for the - Bluetooth Mesh functionality. + Bluetooth mesh functionality. config BT_MESH_DEBUG_PROVISIONER bool "[DEPRECATED] Provisioner debug" select DEPRECATED help Use this option to enable Provisioner debug logs for the - Bluetooth Mesh functionality. + Bluetooth mesh functionality. config BT_MESH_DEBUG_PROV_DEVICE bool "[DEPRECATED] Provisioning device debug" @@ -532,7 +532,7 @@ config BT_MESH_DEBUG_ACCESS select DEPRECATED help Use this option to enable Access layer and device composition - related debug logs for Bluetooth Mesh. + related debug logs for Bluetooth mesh. config BT_MESH_DEBUG_MODEL bool "[DEPRECATED] Foundation model debug" @@ -546,21 +546,21 @@ config BT_MESH_DEBUG_ADV select DEPRECATED help Use this option to enable advertising debug logs for - the Bluetooth Mesh functionality. + the Bluetooth mesh functionality. config BT_MESH_DEBUG_LOW_POWER bool "[DEPRECATED] Low Power debug" select DEPRECATED help Use this option to enable Low Power debug logs for the - Bluetooth Mesh functionality. + Bluetooth mesh functionality. config BT_MESH_DEBUG_FRIEND bool "[DEPRECATED] Friend debug" select DEPRECATED help Use this option to enable Friend debug logs for the - Bluetooth Mesh functionality. + Bluetooth mesh functionality. config BT_MESH_DEBUG_PROXY bool "[DEPRECATED] Proxy debug" @@ -588,7 +588,7 @@ config BT_MESH_DEBUG_CFG select DEPRECATED help Use this option to enable node configuration debug logs for the - Bluetooth Mesh functionality. + Bluetooth mesh functionality. endmenu # [DEPRECATED] Mesh diff --git a/subsys/bluetooth/common/Kconfig b/subsys/bluetooth/common/Kconfig index 2fdc98694b1..7b6bc839b89 100644 --- a/subsys/bluetooth/common/Kconfig +++ b/subsys/bluetooth/common/Kconfig @@ -243,7 +243,7 @@ config BT_HCI_MESH_EXT bool "Mesh HCI Command support" depends on BT_BROADCASTER && BT_OBSERVER && !BT_LL_SW_SPLIT help - Enable support for the Bluetooth Mesh HCI Commands. + Enable support for the Bluetooth mesh HCI Commands. config BT_WAIT_NOP bool "Wait for \"NOP\" Command Complete event during init" diff --git a/subsys/bluetooth/mesh/Kconfig b/subsys/bluetooth/mesh/Kconfig index 0c654e18064..04366828bbe 100644 --- a/subsys/bluetooth/mesh/Kconfig +++ b/subsys/bluetooth/mesh/Kconfig @@ -1,13 +1,13 @@ -# Bluetooth Mesh configuration options +# Bluetooth mesh configuration options # Copyright (c) 2017 Intel Corporation # SPDX-License-Identifier: Apache-2.0 menuconfig BT_MESH - bool "Bluetooth Mesh support" + bool "Bluetooth mesh support" depends on BT_OBSERVER && BT_BROADCASTER help - This option enables Bluetooth Mesh support. The specific + This option enables Bluetooth mesh support. The specific features that are available may depend on other features that have been enabled in the stack, such as GATT support. @@ -598,7 +598,7 @@ config BT_MESH_ACCESS_LAYER_MSG help This option allows the application to directly access Bluetooth access layer messages without the need to - instantiate Bluetooth Mesh models. + instantiate Bluetooth mesh models. config BT_MESH_MODEL_VND_MSG_CID_FORCE bool "Force vendor model to use the corresponding CID field message" @@ -1049,9 +1049,9 @@ config BT_MESH_FRIEND_ADV_LATENCY endif # BT_MESH_FRIEND menuconfig BT_MESH_V1d1 - bool "Bluetooth Mesh v1.1 support" + bool "Bluetooth mesh v1.1 support" help - This option enables Bluetooth Mesh v1.1 support. Bluetooth Mesh v1.1 + This option enables Bluetooth mesh v1.1 support. Bluetooth mesh v1.1 is backward compatible with v1.0.1. config BT_MESH_ECDH_P256_CMAC_AES128_AES_CCM @@ -1201,7 +1201,7 @@ config BT_MESH_DFU_METADATA bool "Support for the default metadata format" help This option adds a set of functions that can be used to encode and decode a firmware - metadata using the format defined in the Bluetooth Mesh DFU subsystem. + metadata using the format defined in the Bluetooth mesh DFU subsystem. config BT_MESH_DFU_URI_MAXLEN int "DFU URI max length" @@ -1734,16 +1734,16 @@ config BT_MESH_RPL_STORE_TIMEOUT endif # BT_MESH_RPL_STORAGE_MODE_SETTINGS && BT_SETTINGS config BT_MESH_SETTINGS_WORKQ - bool "Store the Bluetooth Mesh settings in a separate work queue" + bool "Store the Bluetooth mesh settings in a separate work queue" default y help This option enables a separate cooperative thread which is used to - store Bluetooth Mesh configuration. When this option is disabled, + store Bluetooth mesh configuration. When this option is disabled, the stack's configuration is stored in the system workqueue. This means that the system workqueue will be blocked for the time needed to store the pending data. This time may significantly increase if the flash driver does the erase operation. Enabling this option - allows Bluetooth Mesh not to block the system workqueue, and thus + allows Bluetooth mesh not to block the system workqueue, and thus process the incoming and outgoing messages while the flash driver waits for the controller to allocate the time needed to write the data and/or erase the required flash pages. diff --git a/subsys/bluetooth/mesh/access.h b/subsys/bluetooth/mesh/access.h index 48e0eadec10..b7ce1abd0ea 100644 --- a/subsys/bluetooth/mesh/access.h +++ b/subsys/bluetooth/mesh/access.h @@ -94,7 +94,7 @@ void bt_mesh_msg_cb_set(void (*cb)(uint32_t opcode, struct bt_mesh_msg_ctx *ctx, * Send a mesh model layer message out into the mesh network without having instantiated * the relevant mesh models. * - * @param ctx The Bluetooth Mesh message context. + * @param ctx The Bluetooth mesh message context. * @param buf The message payload. * * @return 0 on success or negative error code on failure. diff --git a/subsys/bluetooth/mesh/settings.c b/subsys/bluetooth/mesh/settings.c index 9cfcb3f5c2c..771aad9b946 100644 --- a/subsys/bluetooth/mesh/settings.c +++ b/subsys/bluetooth/mesh/settings.c @@ -88,7 +88,7 @@ static int mesh_commit(void) } if (!atomic_test_bit(bt_dev.flags, BT_DEV_ENABLE)) { - /* The Bluetooth Mesh settings loader calls bt_mesh_start() immediately + /* The Bluetooth mesh settings loader calls bt_mesh_start() immediately * after loading the settings. This is not intended to work before * bt_enable(). The doc on @ref bt_enable requires the "bt/" settings * tree to be loaded after @ref bt_enable is completed, so this handler diff --git a/subsys/bluetooth/mesh/shell/Kconfig b/subsys/bluetooth/mesh/shell/Kconfig index 46671c3bfaa..5e1e43f0057 100644 --- a/subsys/bluetooth/mesh/shell/Kconfig +++ b/subsys/bluetooth/mesh/shell/Kconfig @@ -1,13 +1,13 @@ -# Bluetooth Mesh shell configuration options +# Bluetooth mesh shell configuration options # Copyright (c) 2022 Nordic Semiconductor # SPDX-License-Identifier: Apache-2.0 menuconfig BT_MESH_SHELL - bool "Bluetooth Mesh shell" + bool "Bluetooth mesh shell" select SHELL help - Activate shell module that provides Bluetooth Mesh commands to + Activate shell module that provides Bluetooth mesh commands to the console. if BT_MESH_SHELL @@ -24,7 +24,7 @@ config BT_MESH_SHELL_PROV_CTX_INSTANCE depends on BT_MESH_SHELL_PROV help This option enables the provisioning context instance in the - Bluetooth Mesh shell module together with several provisioning + Bluetooth mesh shell module together with several provisioning commands and target utility features. To use the provisioning context instance, use bt_mesh_shell_prov in the initialization of mesh. @@ -54,7 +54,7 @@ config BT_MESH_SHELL_HEALTH_SRV_INSTANCE depends on BT_MESH_SHELL_TEST help This option enables Health Server model instance in the - Bluetooth Mesh shell module together with fault controlling + Bluetooth mesh shell module together with fault controlling shell commands. To use the model instance, add bt_mesh_shell_health_srv to the device composition data. Use BT_MESH_SHELL_HEALTH_PUB_DEFINE to instantiate publication context. diff --git a/subsys/bluetooth/mesh/shell/shell.c b/subsys/bluetooth/mesh/shell/shell.c index bb9892eb355..a169bb16422 100644 --- a/subsys/bluetooth/mesh/shell/shell.c +++ b/subsys/bluetooth/mesh/shell/shell.c @@ -1814,5 +1814,5 @@ SHELL_STATIC_SUBCMD_SET_CREATE(mesh_cmds, SHELL_SUBCMD_SET_END ); -SHELL_CMD_ARG_REGISTER(mesh, &mesh_cmds, "Bluetooth Mesh shell commands", +SHELL_CMD_ARG_REGISTER(mesh, &mesh_cmds, "Bluetooth mesh shell commands", bt_mesh_shell_mdl_cmds_help, 1, 1); diff --git a/tests/bsim/bluetooth/mesh/README.rst b/tests/bsim/bluetooth/mesh/README.rst index 1ae78887b71..787b0084f0b 100644 --- a/tests/bsim/bluetooth/mesh/README.rst +++ b/tests/bsim/bluetooth/mesh/README.rst @@ -1,7 +1,7 @@ -Bluetooth Mesh BabbleSim tests +Bluetooth mesh BabbleSim tests ############################## -This directory contains a set of high level system tests for the Bluetooth Mesh +This directory contains a set of high level system tests for the Bluetooth mesh subsystem. The tests run on the BabbleSim simulator, using the BabbleSim test framework. @@ -10,7 +10,7 @@ subfolder of test_scripts contains tests for a specific module in the Bluetooth mesh subsystem, and each folder has a corresponding test_.c under the src/ directory containing the necessary test harnesses to execute the tests. -There's only a single test application for all the Bluetooth Mesh BabbleSim +There's only a single test application for all the Bluetooth mesh BabbleSim tests. The test application is built from this directory, and includes all test harnesses in every build. The overlying bsim test framework selects the harness to use at runtime, using the test identifiers passed in the test scripts. @@ -18,7 +18,7 @@ to use at runtime, using the test identifiers passed in the test scripts. Running the tests ***************** -The Bluetooth Mesh tests have no extra requirements, and can be run using the +The Bluetooth mesh tests have no extra requirements, and can be run using the procedure described in the parent folder. To only run the mesh tests, set ``SEARCH_PATH`` to point to this folder before @@ -57,13 +57,13 @@ Then separately, call Framework ********* -The Bluetooth Mesh BabbleSim tests mainly operate on the test framework for the +The Bluetooth mesh BabbleSim tests mainly operate on the test framework for the BabbleSim platform, but with some mesh specific additions: mesh_test.sh ============= -All test scripts in the Bluetooth Mesh BabbleSim test suite follow a common +All test scripts in the Bluetooth mesh BabbleSim test suite follow a common pattern for running a single test across N devices with different test harnesses. ``mesh_test.sh`` is sourced in each test script, and its ``RunTest`` function is called once in each script with the following parameters: @@ -113,6 +113,6 @@ has been called - otherwise, it will fail. The Bluetooth stack must be initialized in the ``test_main_f`` function of the harness, as the previous callbacks are all executed in hardware threads. -The Bluetooth Mesh tests include the entire Bluetooth host and controller +The Bluetooth mesh tests include the entire Bluetooth host and controller subsystems, so timing requirements should generally be kept fairly liberal to avoid regressions on changes in the underlying layers. diff --git a/tests/bsim/bluetooth/mesh/prj.conf b/tests/bsim/bluetooth/mesh/prj.conf index a45bef89775..b0738c4fa05 100644 --- a/tests/bsim/bluetooth/mesh/prj.conf +++ b/tests/bsim/bluetooth/mesh/prj.conf @@ -15,7 +15,7 @@ CONFIG_BT_BROADCASTER=y CONFIG_BT_CTLR_DUP_FILTER_LEN=0 CONFIG_BT_CTLR_PRIVACY=n -# Bluetooth Mesh configuration +# Bluetooth mesh configuration CONFIG_BT_MESH=y CONFIG_BT_MESH_LOG_LEVEL_DBG=y CONFIG_BT_MESH_RELAY=y diff --git a/tests/bsim/bluetooth/mesh/prj_mesh1d1.conf b/tests/bsim/bluetooth/mesh/prj_mesh1d1.conf index 11059c03da4..ab6066e01bf 100644 --- a/tests/bsim/bluetooth/mesh/prj_mesh1d1.conf +++ b/tests/bsim/bluetooth/mesh/prj_mesh1d1.conf @@ -15,7 +15,7 @@ CONFIG_BT_BROADCASTER=y CONFIG_BT_CTLR_DUP_FILTER_LEN=0 CONFIG_BT_CTLR_PRIVACY=n -# Bluetooth Mesh configuration +# Bluetooth mesh configuration CONFIG_BT_MESH=y CONFIG_BT_MESH_V1d1=y CONFIG_BT_MESH_LOG_LEVEL_DBG=y diff --git a/tests/bsim/bluetooth/mesh/src/mesh_test.h b/tests/bsim/bluetooth/mesh/src/mesh_test.h index 3dcaa5f784a..a5c8694947b 100644 --- a/tests/bsim/bluetooth/mesh/src/mesh_test.h +++ b/tests/bsim/bluetooth/mesh/src/mesh_test.h @@ -1,5 +1,5 @@ /** @file - * @brief Common functionality for Bluetooth Mesh BabbleSim tests. + * @brief Common functionality for Bluetooth mesh BabbleSim tests. */ /* From fccc3162aa809c0956061d7bbf0f6dd11c608479 Mon Sep 17 00:00:00 2001 From: Robert Lubos Date: Tue, 6 Feb 2024 11:07:22 +0100 Subject: [PATCH 3615/3723] Revert "[nrf fromtree] Bluetooth: Mesh: Return immediately if labels not supported" This reverts commit 17fa0a84c7f6fbe2286a8b415b939160516bbae2. Signed-off-by: Robert Lubos --- subsys/bluetooth/mesh/va.c | 4 ---- 1 file changed, 4 deletions(-) diff --git a/subsys/bluetooth/mesh/va.c b/subsys/bluetooth/mesh/va.c index b69c22f40e9..6db9194da47 100644 --- a/subsys/bluetooth/mesh/va.c +++ b/subsys/bluetooth/mesh/va.c @@ -306,10 +306,6 @@ void bt_mesh_va_clear(void) { int i; - if (CONFIG_BT_MESH_LABEL_COUNT == 0) { - return; - } - for (i = 0; i < ARRAY_SIZE(virtual_addrs); i++) { if (virtual_addrs[i].ref) { virtual_addrs[i].ref = 0U; From 22922cbeb969696dc312e95503810d8ee233e619 Mon Sep 17 00:00:00 2001 From: Robert Lubos Date: Tue, 6 Feb 2024 11:07:22 +0100 Subject: [PATCH 3616/3723] Revert "[nrf fromtree] Bluetooth: Mesh: Use ATOMIC_DEFINE instead of atomic_t" This reverts commit 64e37c9348350f47639cfaa6e2ff7d63e58ba025. Signed-off-by: Robert Lubos --- subsys/bluetooth/mesh/rpl.c | 15 +++++++-------- 1 file changed, 7 insertions(+), 8 deletions(-) diff --git a/subsys/bluetooth/mesh/rpl.c b/subsys/bluetooth/mesh/rpl.c index e19df33908f..b3113530854 100644 --- a/subsys/bluetooth/mesh/rpl.c +++ b/subsys/bluetooth/mesh/rpl.c @@ -41,9 +41,8 @@ static ATOMIC_DEFINE(store, CONFIG_BT_MESH_CRPL); enum { PENDING_CLEAR, PENDING_RESET, - RPL_FLAGS_COUNT, }; -static ATOMIC_DEFINE(rpl_flags, RPL_FLAGS_COUNT); +static atomic_t rpl_flags; static inline int rpl_idx(const struct bt_mesh_rpl *rpl) { @@ -134,7 +133,7 @@ bool bt_mesh_rpl_check(struct bt_mesh_net_rx *rx, /* Existing slot for given address */ if (rpl->src == rx->ctx.addr) { if (!rpl->old_iv && - atomic_test_bit(rpl_flags, PENDING_RESET) && + atomic_test_bit(&rpl_flags, PENDING_RESET) && !atomic_test_bit(store, i)) { /* Until rpl reset is finished, entry with old_iv == false and * without "store" bit set will be removed, therefore it can be @@ -179,7 +178,7 @@ void bt_mesh_rpl_clear(void) return; } - atomic_set_bit(rpl_flags, PENDING_CLEAR); + atomic_set_bit(&rpl_flags, PENDING_CLEAR); bt_mesh_settings_store_schedule(BT_MESH_SETTINGS_RPL_PENDING); } @@ -234,7 +233,7 @@ void bt_mesh_rpl_reset(void) } if (i != 0) { - atomic_set_bit(rpl_flags, PENDING_RESET); + atomic_set_bit(&rpl_flags, PENDING_RESET); bt_mesh_settings_store_schedule(BT_MESH_SETTINGS_RPL_PENDING); } } else { @@ -359,8 +358,8 @@ void bt_mesh_rpl_pending_store(uint16_t addr) bt_mesh_settings_store_cancel(BT_MESH_SETTINGS_RPL_PENDING); } - clr = atomic_test_and_clear_bit(rpl_flags, PENDING_CLEAR); - rst = atomic_test_bit(rpl_flags, PENDING_RESET); + clr = atomic_test_and_clear_bit(&rpl_flags, PENDING_CLEAR); + rst = atomic_test_bit(&rpl_flags, PENDING_RESET); for (int i = 0; i < ARRAY_SIZE(replay_list); i++) { struct bt_mesh_rpl *rpl = &replay_list[i]; @@ -399,7 +398,7 @@ void bt_mesh_rpl_pending_store(uint16_t addr) } } - atomic_clear_bit(rpl_flags, PENDING_RESET); + atomic_clear_bit(&rpl_flags, PENDING_RESET); if (addr == BT_MESH_ADDR_ALL_NODES) { (void)memset(&replay_list[last - shift + 1], 0, sizeof(struct bt_mesh_rpl) * shift); From 447799e9a410ba5512654c05f5345a3092bcf5e2 Mon Sep 17 00:00:00 2001 From: Robert Lubos Date: Tue, 6 Feb 2024 11:07:22 +0100 Subject: [PATCH 3617/3723] Revert "[nrf fromtree] Bluetooth: Mesh: allocate mesh max required buffer number" This reverts commit accb038d8c6a7c7fc9afa522e781c5d87bd68b56. Signed-off-by: Robert Lubos --- subsys/bluetooth/common/Kconfig | 1 - 1 file changed, 1 deletion(-) diff --git a/subsys/bluetooth/common/Kconfig b/subsys/bluetooth/common/Kconfig index 7b6bc839b89..bf4aee75e48 100644 --- a/subsys/bluetooth/common/Kconfig +++ b/subsys/bluetooth/common/Kconfig @@ -33,7 +33,6 @@ config BT_BUF_ACL_TX_SIZE config BT_BUF_ACL_TX_COUNT int "Number of outgoing ACL data buffers" default 7 if BT_HCI_RAW - default 4 if BT_MESH_GATT default 3 range 1 255 help From ea4c35612123a4d597bac51b7bf754dbdd8e6cb4 Mon Sep 17 00:00:00 2001 From: Robert Lubos Date: Tue, 6 Feb 2024 11:07:22 +0100 Subject: [PATCH 3618/3723] Revert "[nrf noup] drivers: ieee802154: temporary fix for ACK header IE config" This reverts commit 1da00e0c84f7da2f4017f4efde99e479d40e5e6e. Signed-off-by: Robert Lubos --- drivers/ieee802154/ieee802154_nrf5.c | 13 ------------- 1 file changed, 13 deletions(-) diff --git a/drivers/ieee802154/ieee802154_nrf5.c b/drivers/ieee802154/ieee802154_nrf5.c index e9c49e6089e..df01f530abf 100644 --- a/drivers/ieee802154/ieee802154_nrf5.c +++ b/drivers/ieee802154/ieee802154_nrf5.c @@ -886,19 +886,6 @@ static int nrf5_configure(const struct device *dev, uint8_t short_addr_le[SHORT_ADDRESS_SIZE]; uint8_t element_id; - if (config->ack_ie.ext_addr == NULL && - config->ack_ie.header_ie == NULL && - config->ack_ie.short_addr == IEEE802154_NO_SHORT_ADDRESS_ASSIGNED) { - /* Hotfix for case when `EnableCsl()` has been called with arguments: - * - `aCslPeriod` == 0 - * - `aShortAddr` == IEEE802154_NO_SHORT_ADDRESS_ASSIGNED - * - `aExtAddr` == NULL - * In this case skip configuring ACK header IE until proper resetting of - * configuration is implemented. - */ - break; - } - if (config->ack_ie.short_addr == IEEE802154_BROADCAST_ADDRESS || config->ack_ie.ext_addr == NULL) { return -ENOTSUP; From 9942110caf636e96d109456fe7e1b20288000416 Mon Sep 17 00:00:00 2001 From: Robert Lubos Date: Tue, 6 Feb 2024 11:07:22 +0100 Subject: [PATCH 3619/3723] Revert "[nrf fromtree] tests: modem: backend: uart: Add fixture to test suite" This reverts commit 883c3709f9c8fd845a8dfa39d2583d5c665a915b. Signed-off-by: Robert Lubos --- .../uart/boards/b_u585i_iot02a.overlay | 35 +++++++++++++--- .../boards/nrf5340dk_nrf5340_cpuapp.overlay | 42 +++++++++++-------- tests/subsys/modem/backends/uart/src/main.c | 2 +- .../subsys/modem/backends/uart/testcase.yaml | 18 ++++---- 4 files changed, 64 insertions(+), 33 deletions(-) diff --git a/tests/subsys/modem/backends/uart/boards/b_u585i_iot02a.overlay b/tests/subsys/modem/backends/uart/boards/b_u585i_iot02a.overlay index 30402e6e9d2..394facef7bb 100644 --- a/tests/subsys/modem/backends/uart/boards/b_u585i_iot02a.overlay +++ b/tests/subsys/modem/backends/uart/boards/b_u585i_iot02a.overlay @@ -1,11 +1,34 @@ -/* SPDX-License-Identifier: Apache-2.0 */ - /* - * The Arduino D0 and D1 must be connected to each other to loopback RX/TX. + * Pins 2 and 3 must be connected to each other on the STMOD+1 connector to + * loopback RX/TX. */ -dut: &usart3 { - dmas = <&gpdma1 0 29 STM32_DMA_PERIPH_TX - &gpdma1 1 28 STM32_DMA_PERIPH_RX>; +/ { + aliases { + test-uart = &usart2; + }; +}; + +&gpioh { + misc_fixed_usart2 { + gpio-hog; + gpios = <13 GPIO_ACTIVE_HIGH>; + output-high; + }; +}; + +&gpdma1 { + status = "okay"; +}; + +&usart2 { + pinctrl-0 = <&usart2_tx_pa2 &usart2_rx_pa3 &usart2_rts_pa1 &usart2_cts_pa0>; + pinctrl-names = "default"; + current-speed = <115200>; + + dmas = <&gpdma1 0 27 STM32_DMA_PERIPH_TX + &gpdma1 1 26 STM32_DMA_PERIPH_RX>; dma-names = "tx", "rx"; + + status = "okay"; }; diff --git a/tests/subsys/modem/backends/uart/boards/nrf5340dk_nrf5340_cpuapp.overlay b/tests/subsys/modem/backends/uart/boards/nrf5340dk_nrf5340_cpuapp.overlay index 777aebd8d3b..2d47b0f0744 100644 --- a/tests/subsys/modem/backends/uart/boards/nrf5340dk_nrf5340_cpuapp.overlay +++ b/tests/subsys/modem/backends/uart/boards/nrf5340dk_nrf5340_cpuapp.overlay @@ -1,31 +1,37 @@ -/* SPDX-License-Identifier: Apache-2.0 */ - /* - * Pins P0.4 and P0.5 must be connected to each other to loopback RX/TX. + * Pins P1.10 and P1.11 must be connected to each other to loopback RX/TX. */ +/ { + aliases { + test-uart = &uart1; + }; +}; + +&uart1 { + status = "okay"; + current-speed = <115200>; + pinctrl-0 = <&uart1_default>; + pinctrl-1 = <&uart1_sleep>; + hw-flow-control; + pinctrl-names = "default", "sleep"; +}; + &pinctrl { - uart1_default_alt: uart1_default_alt { + uart1_default: uart1_default { group1 { - psels = , - ; + psels = ; + }; + group2 { + psels = ; }; }; - uart1_sleep_alt: uart1_sleep_alt { + uart1_sleep: uart1_sleep { group1 { - psels = , - ; + psels = , + ; low-power-enable; }; }; }; - -dut: &uart1 { - compatible = "nordic,nrf-uarte"; - current-speed = <115200>; - status = "okay"; - pinctrl-0 = <&uart1_default_alt>; - pinctrl-1 = <&uart1_sleep_alt>; - pinctrl-names = "default", "sleep"; -}; diff --git a/tests/subsys/modem/backends/uart/src/main.c b/tests/subsys/modem/backends/uart/src/main.c index dffc203bb21..8a6c4c2813a 100644 --- a/tests/subsys/modem/backends/uart/src/main.c +++ b/tests/subsys/modem/backends/uart/src/main.c @@ -28,7 +28,7 @@ /*************************************************************************************************/ /* Mock pipe */ /*************************************************************************************************/ -static const struct device *uart = DEVICE_DT_GET(DT_NODELABEL(dut)); +static const struct device *uart = DEVICE_DT_GET(DT_ALIAS(test_uart)); static struct modem_backend_uart uart_backend; static struct modem_pipe *pipe; K_SEM_DEFINE(receive_ready_sem, 0, 1); diff --git a/tests/subsys/modem/backends/uart/testcase.yaml b/tests/subsys/modem/backends/uart/testcase.yaml index 54d8a6b9470..626ca639f75 100644 --- a/tests/subsys/modem/backends/uart/testcase.yaml +++ b/tests/subsys/modem/backends/uart/testcase.yaml @@ -1,19 +1,21 @@ # Copyright (c) 2023 Trackunit Corporation # SPDX-License-Identifier: Apache-2.0 -common: - harness: ztest - harness_config: - fixture: gpio_loopback - platform_allow: - - b_u585i_iot02a - - nrf5340dk_nrf5340_cpuapp - tests: modem.backends.uart.async: + tags: modem_backend + harness: ztest + platform_allow: + - b_u585i_iot02a + - nrf5340dk_nrf5340_cpuapp extra_configs: - CONFIG_UART_ASYNC_API=y modem.backends.uart.isr: + tags: modem_backend + harness: ztest + platform_allow: + - b_u585i_iot02a + - nrf5340dk_nrf5340_cpuapp extra_configs: - CONFIG_UART_INTERRUPT_DRIVEN=y From d44bba0ead835cecec50332984569bfbba1e516e Mon Sep 17 00:00:00 2001 From: Robert Lubos Date: Tue, 6 Feb 2024 11:07:22 +0100 Subject: [PATCH 3620/3723] Revert "[nrf fromtree] tests: logging: log_backend_uart: Disable backends other than UART" This reverts commit ead6b4d1db7209abda3c81a7bd8312eb42ef7a36. Signed-off-by: Robert Lubos --- tests/subsys/logging/log_backend_uart/prj.conf | 5 ----- 1 file changed, 5 deletions(-) diff --git a/tests/subsys/logging/log_backend_uart/prj.conf b/tests/subsys/logging/log_backend_uart/prj.conf index c8615a65adb..ef6894f355e 100644 --- a/tests/subsys/logging/log_backend_uart/prj.conf +++ b/tests/subsys/logging/log_backend_uart/prj.conf @@ -9,8 +9,3 @@ CONFIG_LOG=y CONFIG_LOG_BACKEND_UART=y CONFIG_LOG_MODE_IMMEDIATE=y CONFIG_LOG_PRINTK=n -# -# Disable all potential other default backends -CONFIG_LOG_BACKEND_NATIVE_POSIX=n -CONFIG_LOG_BACKEND_RTT=n -CONFIG_LOG_BACKEND_XTENSA_SIM=n From b6573d77a48271e9f52dc94a5aba15b0a60ebddb Mon Sep 17 00:00:00 2001 From: Robert Lubos Date: Tue, 6 Feb 2024 11:07:22 +0100 Subject: [PATCH 3621/3723] Revert "[nrf fromlist] doc: extensions: zephyr-domain: make transforms optional" This reverts commit 774a528ecbc8aae382cc969d8b944b59e4bb9dde. Signed-off-by: Robert Lubos --- doc/_extensions/zephyr/domain.py | 14 +------------- doc/conf.py | 4 ---- 2 files changed, 1 insertion(+), 17 deletions(-) diff --git a/doc/_extensions/zephyr/domain.py b/doc/_extensions/zephyr/domain.py index 053965e26e3..beb94eb4d2f 100644 --- a/doc/_extensions/zephyr/domain.py +++ b/doc/_extensions/zephyr/domain.py @@ -80,9 +80,6 @@ class ConvertCodeSampleNode(SphinxTransform): default_priority = 100 def apply(self): - if not self.config.zephyr_domain_apply_transforms: - return - matcher = NodeMatcher(CodeSampleNode) for node in self.document.traverse(matcher): self.convert_node(node) @@ -143,9 +140,6 @@ class ProcessRelatedCodeSamplesNode(SphinxPostTransform): default_priority = 5 # before ReferencesResolver def run(self, **kwargs: Any) -> None: - if not self.config.zephyr_domain_apply_transforms: - return - matcher = NodeMatcher(RelatedCodeSamplesNode) for node in self.document.traverse(matcher): id = node["id"] # the ID of the node is the name of the doxygen group for which we @@ -314,16 +308,10 @@ class CustomDoxygenGroupDirective(DoxygenGroupDirective): def run(self) -> List[Node]: nodes = super().run() - - if self.config.zephyr_domain_apply_transforms: - return [RelatedCodeSamplesNode(id=self.arguments[0]), *nodes] - else: - return nodes + return [RelatedCodeSamplesNode(id=self.arguments[0]), *nodes] def setup(app): - app.add_config_value("zephyr_domain_apply_transforms", False, "env") - app.add_domain(ZephyrDomain) app.add_transform(ConvertCodeSampleNode) diff --git a/doc/conf.py b/doc/conf.py index 4bab42dcc90..85488318a0a 100644 --- a/doc/conf.py +++ b/doc/conf.py @@ -302,10 +302,6 @@ "build/dts/api/compatibles/**/*", ] -# -- Options for zephyr.domain -------------------------------------------- - -zephyr_domain_apply_transforms = True - # -- Options for sphinx.ext.graphviz -------------------------------------- graphviz_dot = os.environ.get("DOT_EXECUTABLE", "dot") From 1625bf9e70571359345e2962b0222a4396fd862b Mon Sep 17 00:00:00 2001 From: Robert Lubos Date: Tue, 6 Feb 2024 11:07:23 +0100 Subject: [PATCH 3622/3723] Revert "[nrf fromlist] doc: extensions: zephyr-domain: fix object descriptions" This reverts commit ed20dd66fdd81408bc26a693c299f829fb05214f. Signed-off-by: Robert Lubos --- doc/_extensions/zephyr/domain.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/doc/_extensions/zephyr/domain.py b/doc/_extensions/zephyr/domain.py index beb94eb4d2f..8c395142818 100644 --- a/doc/_extensions/zephyr/domain.py +++ b/doc/_extensions/zephyr/domain.py @@ -249,7 +249,7 @@ class ZephyrDomain(Domain): directives = {"code-sample": CodeSampleDirective} object_types: Dict[str, ObjType] = { - "code-sample": ObjType("code-sample", "code-sample"), + "code-sample": ObjType("code sample", "code-sample"), } initial_data: Dict[str, Any] = {"code-samples": {}} @@ -267,9 +267,9 @@ def merge_domaindata(self, docnames: List[str], otherdata: Dict) -> None: def get_objects(self): for _, code_sample in self.data["code-samples"].items(): yield ( - code_sample["id"], code_sample["name"], - "code-sample", + code_sample["name"], + "code sample", code_sample["docname"], code_sample["id"], 1, From 265a256d504bd007950cfd86a16c9a4b8db9c640 Mon Sep 17 00:00:00 2001 From: Robert Lubos Date: Tue, 6 Feb 2024 11:07:23 +0100 Subject: [PATCH 3623/3723] Revert "[nrf fromtree] doc: ext/gh_utils: pass MAINTAINERS.yml to Maintainers" This reverts commit 6946f4c6748eebe6c048074c2f1fa0cda9f25cb9. Signed-off-by: Robert Lubos --- doc/_extensions/zephyr/gh_utils.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/doc/_extensions/zephyr/gh_utils.py b/doc/_extensions/zephyr/gh_utils.py index 2c992436c87..6ba75ce5ab7 100644 --- a/doc/_extensions/zephyr/gh_utils.py +++ b/doc/_extensions/zephyr/gh_utils.py @@ -53,7 +53,7 @@ from get_maintainer import Maintainers -MAINTAINERS : Final[Maintainers] = Maintainers(filename=f"{ZEPHYR_BASE}/MAINTAINERS.yml") +MAINTAINERS : Final[Maintainers] = Maintainers() __version__ = "0.1.0" From d818aaee85b99c5ab7df8804bd3b38fb4ae7d763 Mon Sep 17 00:00:00 2001 From: Robert Lubos Date: Tue, 6 Feb 2024 11:07:23 +0100 Subject: [PATCH 3624/3723] Revert "[nrf fromtree] samples: ipc: multi_endpoint: Fix synchronisation of data receiving" This reverts commit a5fa2ffb399f2d98727848c2d37a4d3cfc9af53b. Signed-off-by: Robert Lubos --- samples/subsys/ipc/ipc_service/multi_endpoint/remote/src/main.c | 2 +- samples/subsys/ipc/ipc_service/multi_endpoint/src/main.c | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/samples/subsys/ipc/ipc_service/multi_endpoint/remote/src/main.c b/samples/subsys/ipc/ipc_service/multi_endpoint/remote/src/main.c index f285f4b6d23..9b288f8a6a1 100644 --- a/samples/subsys/ipc/ipc_service/multi_endpoint/remote/src/main.c +++ b/samples/subsys/ipc/ipc_service/multi_endpoint/remote/src/main.c @@ -193,7 +193,7 @@ static void ipc1_ept_recv(const void *data, size_t len, void *priv) { ipc1_received_data = *((uint8_t *) data); - k_sem_give(&ipc1_data_sem); + k_sem_give(&ipc0B_data_sem); } static struct ipc_ept_cfg ipc1_ept_cfg = { diff --git a/samples/subsys/ipc/ipc_service/multi_endpoint/src/main.c b/samples/subsys/ipc/ipc_service/multi_endpoint/src/main.c index 4ad5659df38..78d7af05288 100644 --- a/samples/subsys/ipc/ipc_service/multi_endpoint/src/main.c +++ b/samples/subsys/ipc/ipc_service/multi_endpoint/src/main.c @@ -190,7 +190,7 @@ static void ipc1_ept_recv(const void *data, size_t len, void *priv) { ipc1_received_data = *((uint8_t *) data); - k_sem_give(&ipc1_data_sem); + k_sem_give(&ipc0B_data_sem); } static struct ipc_ept_cfg ipc1_ept_cfg = { From dd87619116e9ae4e11f288de4c62fb3364c9924f Mon Sep 17 00:00:00 2001 From: Robert Lubos Date: Tue, 6 Feb 2024 11:07:23 +0100 Subject: [PATCH 3625/3723] Revert "[nrf fromtree] tests: drivers: flash: Use fixtures for tests requiring external chips" This reverts commit bea8d6bcc98289cf500718f87b303a3127bcca54. Signed-off-by: Robert Lubos --- tests/drivers/flash/common/testcase.yaml | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/tests/drivers/flash/common/testcase.yaml b/tests/drivers/flash/common/testcase.yaml index 88ce0a40e07..9aa13bb40d5 100644 --- a/tests/drivers/flash/common/testcase.yaml +++ b/tests/drivers/flash/common/testcase.yaml @@ -21,7 +21,7 @@ tests: - OVERLAY_CONFIG=boards/nrf52840_flash_qspi.conf - DTC_OVERLAY_FILE=boards/nrf52840dk_mx25l51245g.overlay harness_config: - fixture: external_flash_mx25l51245g + fixture: external_flash integration_platforms: - nrf52840dk_nrf52840 drivers.flash.common.soc_flash_nrf: @@ -78,15 +78,11 @@ tests: extra_args: - OVERLAY_CONFIG=boards/nrf52840dk_flash_spi.conf - DTC_OVERLAY_FILE=boards/nrf52840dk_spi_nor.overlay - harness_config: - fixture: external_flash_mx25v1635f drivers.flash.common.spi_nor_wp_hold: platform_allow: nrf52840dk_nrf52840 extra_args: - OVERLAY_CONFIG=boards/nrf52840dk_flash_spi.conf - DTC_OVERLAY_FILE=boards/nrf52840dk_spi_nor_wp_hold.overlay - harness_config: - fixture: external_flash_mx25v1635f drivers.flash.common.sam0: platform_allow: - atsamd20_xpro From ca8a54cdce83ba734856c69ba1ce068fdb8d7f46 Mon Sep 17 00:00:00 2001 From: Robert Lubos Date: Tue, 6 Feb 2024 11:07:23 +0100 Subject: [PATCH 3626/3723] Revert "[nrf fromtree] tests: drivers: flash: Update nrf52840dk_mx25r_high_perf.overlay" This reverts commit 1a7010954b184b1e29c9ad1a9a19600f213e4c03. Signed-off-by: Robert Lubos --- .../flash/common/boards/nrf52840dk_mx25r_high_perf.overlay | 4 ---- 1 file changed, 4 deletions(-) diff --git a/tests/drivers/flash/common/boards/nrf52840dk_mx25r_high_perf.overlay b/tests/drivers/flash/common/boards/nrf52840dk_mx25r_high_perf.overlay index a67f25e46c0..eabb26ebda6 100644 --- a/tests/drivers/flash/common/boards/nrf52840dk_mx25r_high_perf.overlay +++ b/tests/drivers/flash/common/boards/nrf52840dk_mx25r_high_perf.overlay @@ -1,9 +1,5 @@ /delete-node/ &qspi; -&gpio0 { - gpio-reserved-ranges = <0 2>, <6 1>, <8 3>, <18 6>; -}; - &spi2 { compatible = "nordic,nrf-spim"; status = "okay"; From d297b804bbbdaeead7fb7fff5866e639954fbe05 Mon Sep 17 00:00:00 2001 From: Robert Lubos Date: Tue, 6 Feb 2024 11:07:23 +0100 Subject: [PATCH 3627/3723] Revert "[nrf fromtree] boards: nrf52840dk_nrf52840: Fix reserved GPIO lines" This reverts commit de1f9a6bec791ecf6c6d3002bd143a719b3ad069. Signed-off-by: Robert Lubos --- .../nrf52840dk_nrf52840/nrf52840dk_nrf52840.dts | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/boards/arm/nrf52840dk_nrf52840/nrf52840dk_nrf52840.dts b/boards/arm/nrf52840dk_nrf52840/nrf52840dk_nrf52840.dts index 60c3ecf55a1..dcee7b0db5f 100644 --- a/boards/arm/nrf52840dk_nrf52840/nrf52840dk_nrf52840.dts +++ b/boards/arm/nrf52840dk_nrf52840/nrf52840dk_nrf52840.dts @@ -149,18 +149,18 @@ &gpio0 { status = "okay"; - gpio-reserved-ranges = <0 2>, <6 1>, <8 3>, <17 7>; - gpio-line-names = "XL1", "XL2", "AREF", "A0", "A1", "RTS", "TXD", - "CTS", "RXD", "NFC1", "NFC2", "BUTTON1", "BUTTON2", "LED1", - "LED2", "LED3", "LED4", "QSPI CS", "RESET", "QSPI CLK", - "QSPI DIO0", "QSPI DIO1", "QSPI DIO2", "QSPI DIO3","BUTTON3", - "BUTTON4", "SDA", "SCL", "A2", "A3", "A4", "A5"; + gpio-reserved-ranges = <0 11>, <17 7>, <26 6>; + gpio-line-names = "", "", "", "", "", "", "", "", + "", "", "", "BUTTON1", "BUTTON2", "LED1", "LED2", "LED3", + "LED4", "", "", "", "", "", "", "", + "BUTTON3", "BUTTON4", "", "", "", "", "", ""; }; &gpio1 { status = "okay"; + gpio-reserved-ranges = <0 1>, <9 1>, <12 4>; gpio-line-names = "", "D0", "D1", "D2", "D3", "D4", "D5", "D6", - "D7", "", "D8", "D9", "D10", "D11", "D12", "D13"; + "D7", "", "D8", "D9", "", "", "", ""; }; &uart0 { From b6133fa48ab6542a8521d847ba9c9f7666080509 Mon Sep 17 00:00:00 2001 From: Robert Lubos Date: Tue, 6 Feb 2024 11:07:23 +0100 Subject: [PATCH 3628/3723] Revert "[nrf fromtree] llext: fix read-only extension image" This reverts commit fa777ddca7d6c7a37f512d324c7c8ce69221ddfb. Signed-off-by: Robert Lubos --- subsys/llext/Kconfig | 6 ------ subsys/llext/llext.c | 3 +-- tests/subsys/llext/src/test_llext_simple.c | 5 +---- tests/subsys/llext/testcase.yaml | 2 -- 4 files changed, 2 insertions(+), 14 deletions(-) diff --git a/subsys/llext/Kconfig b/subsys/llext/Kconfig index b1210b8f2e8..9fec16cb230 100644 --- a/subsys/llext/Kconfig +++ b/subsys/llext/Kconfig @@ -27,12 +27,6 @@ config LLEXT_SHELL_MAX_SIZE help When loading llext with shell it is stored in a temporary buffer of this size -config LLEXT_STORAGE_WRITABLE - bool "llext storage is writable" - help - Select if LLEXT storage is writable, i.e. if extensions are stored in - RAM and can be modified in place - module = LLEXT module-str = llext source "subsys/logging/Kconfig.template.log_config" diff --git a/subsys/llext/llext.c b/subsys/llext/llext.c index 8dd5801bc95..a24d2b0833f 100644 --- a/subsys/llext/llext.c +++ b/subsys/llext/llext.c @@ -242,8 +242,7 @@ static int llext_copy_section(struct llext_loader *ldr, struct llext *ext, return 0; } - if (ldr->sects[sect_idx].sh_type != SHT_NOBITS && - IS_ENABLED(CONFIG_LLEXT_STORAGE_WRITABLE)) { + if (ldr->sects[sect_idx].sh_type != SHT_NOBITS) { ext->mem[mem_idx] = llext_peek(ldr, ldr->sects[sect_idx].sh_offset); if (ext->mem[mem_idx]) { ext->mem_on_heap[mem_idx] = false; diff --git a/tests/subsys/llext/src/test_llext_simple.c b/tests/subsys/llext/src/test_llext_simple.c index 557697f576c..d96191c1d72 100644 --- a/tests/subsys/llext/src/test_llext_simple.c +++ b/tests/subsys/llext/src/test_llext_simple.c @@ -10,10 +10,7 @@ #include #if defined(CONFIG_ARM) /* ARMV7 */ || defined(CONFIG_XTENSA) -#ifndef CONFIG_LLEXT_STORAGE_WRITABLE -const -#endif -static uint8_t hello_world_elf[] __aligned(4) = { +const static uint8_t hello_world_elf[] __aligned(4) = { #include "hello_world.inc" }; #endif diff --git a/tests/subsys/llext/testcase.yaml b/tests/subsys/llext/testcase.yaml index 2747edf8d0c..0bbccd5e1ca 100644 --- a/tests/subsys/llext/testcase.yaml +++ b/tests/subsys/llext/testcase.yaml @@ -11,8 +11,6 @@ tests: - nuvoton_pfm_m487 # See #63167 llext.simple.xtensa: arch_allow: xtensa - extra_configs: - - CONFIG_LLEXT_STORAGE_WRITABLE=y # Broken platforms platform_exclude: - qemu_xtensa_mmu # ELF sections are read-only, and without peek() .text copy isn't executable From 06b8daafaf9c52a90a3313cb1227c383fd2416f8 Mon Sep 17 00:00:00 2001 From: Robert Lubos Date: Tue, 6 Feb 2024 11:07:23 +0100 Subject: [PATCH 3629/3723] Revert "[nrf fromtree] llext: remove redundant initialisation" This reverts commit 1f1048a9e98c1b11a9caa0628ab63c2af4200e93. Signed-off-by: Robert Lubos --- subsys/llext/llext.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/subsys/llext/llext.c b/subsys/llext/llext.c index a24d2b0833f..4f43dc17a1d 100644 --- a/subsys/llext/llext.c +++ b/subsys/llext/llext.c @@ -792,6 +792,10 @@ int llext_load(struct llext_loader *ldr, const char *name, struct llext **ext) } memset(*ext, 0, sizeof(struct llext)); + for (int i = 0; i < LLEXT_MEM_COUNT; i++) { + (*ext)->mem[i] = NULL; + } + ldr->hdr = ehdr; ret = do_llext_load(ldr, *ext); break; From 8b2e5f3108853ff417b553fe74eebae63b4c9e90 Mon Sep 17 00:00:00 2001 From: Robert Lubos Date: Tue, 6 Feb 2024 11:07:24 +0100 Subject: [PATCH 3630/3723] Revert "[nrf fromtree] llext: clarify section map allocation size" This reverts commit 7459728d37f039ded52d174b9597112676d7a5b5. Signed-off-by: Robert Lubos --- subsys/llext/llext.c | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/subsys/llext/llext.c b/subsys/llext/llext.c index 4f43dc17a1d..6c47ddf29c6 100644 --- a/subsys/llext/llext.c +++ b/subsys/llext/llext.c @@ -670,7 +670,7 @@ static int do_llext_load(struct llext_loader *ldr, struct llext *ext) memset(ldr->sects, 0, sizeof(ldr->sects)); ldr->sect_cnt = 0; - size_t sect_map_sz = ldr->hdr.e_shnum * sizeof(ldr->sect_map[0]); + size_t sect_map_sz = ldr->hdr.e_shnum * sizeof(uint32_t); ldr->sect_map = k_heap_alloc(&llext_heap, sect_map_sz, K_NO_WAIT); if (!ldr->sect_map) { @@ -678,8 +678,7 @@ static int do_llext_load(struct llext_loader *ldr, struct llext *ext) ret = -ENOMEM; goto out; } - memset(ldr->sect_map, 0, sect_map_sz); - + memset(ldr->sect_map, 0, ldr->hdr.e_shnum*sizeof(uint32_t)); ldr->sect_cnt = ldr->hdr.e_shnum; ext->mem_size += sect_map_sz; From 1441521199467adb1acaf30f98bc844ae173ed27 Mon Sep 17 00:00:00 2001 From: Robert Lubos Date: Tue, 6 Feb 2024 11:07:24 +0100 Subject: [PATCH 3631/3723] Revert "[nrf fromtree] llext: add Xtensa test support" This reverts commit 94e99e2116f5370aee0d56bc4e52fcd5c0415bc9. Signed-off-by: Robert Lubos --- tests/subsys/llext/hello_world/CMakeLists.txt | 23 ++++--------------- tests/subsys/llext/src/test_llext_simple.c | 4 ++-- tests/subsys/llext/testcase.yaml | 5 ---- 3 files changed, 6 insertions(+), 26 deletions(-) diff --git a/tests/subsys/llext/hello_world/CMakeLists.txt b/tests/subsys/llext/hello_world/CMakeLists.txt index 6519075e2f4..1a16d4be26b 100644 --- a/tests/subsys/llext/hello_world/CMakeLists.txt +++ b/tests/subsys/llext/hello_world/CMakeLists.txt @@ -6,26 +6,11 @@ find_package(Zephyr REQUIRED HINTS $ENV{ZEPHYR_BASE}) project(hello_world) # TODO check which architecture is being used -if(CONFIG_ARM) - set(CMAKE_C_FLAGS "-mlong-calls" "-mthumb") +set(CMAKE_C_FLAGS "-mlong-calls" "-mthumb") - add_custom_command(OUTPUT ${PROJECT_BINARY_DIR}/hello_world.llext - COMMAND ${CMAKE_C_COMPILER} ${CMAKE_C_FLAGS} -c - -o ${PROJECT_BINARY_DIR}/hello_world.llext - ${PROJECT_SOURCE_DIR}/hello_world.c - ) -elseif(CONFIG_XTENSA) - set(CMAKE_C_FLAGS "-shared" "-fPIC" "-nostdlib" "-nodefaultlibs") - - add_custom_command(OUTPUT ${PROJECT_BINARY_DIR}/hello_world.llext - COMMAND ${CMAKE_C_COMPILER} ${CMAKE_C_FLAGS} - -o ${PROJECT_BINARY_DIR}/hello_world.pre.llext - ${PROJECT_SOURCE_DIR}/hello_world.c - COMMAND ${CROSS_COMPILE}strip -R .xt.* - -o ${PROJECT_BINARY_DIR}/hello_world.llext - ${PROJECT_BINARY_DIR}/hello_world.pre.llext - ) -endif() +add_custom_command(OUTPUT ${PROJECT_BINARY_DIR}/hello_world.llext + COMMAND ${CMAKE_C_COMPILER} ${CMAKE_C_FLAGS} -c -o ${PROJECT_BINARY_DIR}/hello_world.llext ${PROJECT_SOURCE_DIR}/hello_world.c +) set(HELLO_WORLD_LLEXT ${PROJECT_BINARY_DIR}/hello_world.llext PARENT_SCOPE) diff --git a/tests/subsys/llext/src/test_llext_simple.c b/tests/subsys/llext/src/test_llext_simple.c index d96191c1d72..ef0e62b93b5 100644 --- a/tests/subsys/llext/src/test_llext_simple.c +++ b/tests/subsys/llext/src/test_llext_simple.c @@ -9,7 +9,7 @@ #include #include -#if defined(CONFIG_ARM) /* ARMV7 */ || defined(CONFIG_XTENSA) +#ifdef CONFIG_ARM /* ARMV7 */ const static uint8_t hello_world_elf[] __aligned(4) = { #include "hello_world.inc" }; @@ -24,7 +24,7 @@ const static uint8_t hello_world_elf[] __aligned(4) = { */ ZTEST(llext, test_llext_simple) { - const char name[16] = "hello"; + const char name[16] = {'h', 'e', 'l', 'l', 'o', 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; struct llext_buf_loader buf_loader = LLEXT_BUF_LOADER(hello_world_elf, ARRAY_SIZE(hello_world_elf)); struct llext_loader *loader = &buf_loader.loader; diff --git a/tests/subsys/llext/testcase.yaml b/tests/subsys/llext/testcase.yaml index 0bbccd5e1ca..79d8f5a1fd9 100644 --- a/tests/subsys/llext/testcase.yaml +++ b/tests/subsys/llext/testcase.yaml @@ -9,8 +9,3 @@ tests: # Broken platforms platform_exclude: - nuvoton_pfm_m487 # See #63167 - llext.simple.xtensa: - arch_allow: xtensa - # Broken platforms - platform_exclude: - - qemu_xtensa_mmu # ELF sections are read-only, and without peek() .text copy isn't executable From 1ac0334a906a70caa98408cbdb3fb1668f7de1ae Mon Sep 17 00:00:00 2001 From: Robert Lubos Date: Tue, 6 Feb 2024 11:07:24 +0100 Subject: [PATCH 3632/3723] Revert "[nrf fromtree] llext: make buffer access functions accessible externally" This reverts commit 710df4fbe059934005a8c7399658b9e6ac6fd346. Signed-off-by: Robert Lubos --- include/zephyr/llext/loader.h | 19 ------------------- subsys/llext/llext.c | 19 +++++++++++++++++++ 2 files changed, 19 insertions(+), 19 deletions(-) diff --git a/include/zephyr/llext/loader.h b/include/zephyr/llext/loader.h index 3102f17cf1a..3cc53da7d88 100644 --- a/include/zephyr/llext/loader.h +++ b/include/zephyr/llext/loader.h @@ -97,25 +97,6 @@ struct llext_loader { /** @endcond */ }; -static inline int llext_read(struct llext_loader *l, void *buf, size_t len) -{ - return l->read(l, buf, len); -} - -static inline int llext_seek(struct llext_loader *l, size_t pos) -{ - return l->seek(l, pos); -} - -static inline void *llext_peek(struct llext_loader *l, size_t pos) -{ - if (l->peek) { - return l->peek(l, pos); - } - - return NULL; -} - /** * @} */ diff --git a/subsys/llext/llext.c b/subsys/llext/llext.c index 6c47ddf29c6..7b8099a9190 100644 --- a/subsys/llext/llext.c +++ b/subsys/llext/llext.c @@ -21,6 +21,25 @@ K_HEAP_DEFINE(llext_heap, CONFIG_LLEXT_HEAP_SIZE * 1024); static const char ELF_MAGIC[] = {0x7f, 'E', 'L', 'F'}; +static inline int llext_read(struct llext_loader *l, void *buf, size_t len) +{ + return l->read(l, buf, len); +} + +static inline int llext_seek(struct llext_loader *l, size_t pos) +{ + return l->seek(l, pos); +} + +static inline void *llext_peek(struct llext_loader *l, size_t pos) +{ + if (l->peek) { + return l->peek(l, pos); + } + + return NULL; +} + static sys_slist_t _llext_list = SYS_SLIST_STATIC_INIT(&_llext_list); sys_slist_t *llext_list(void) From 7c8f5ce7704c7eeca4f92960e15f7e159f650e4d Mon Sep 17 00:00:00 2001 From: Robert Lubos Date: Tue, 6 Feb 2024 11:07:24 +0100 Subject: [PATCH 3633/3723] Revert "[nrf fromtree] llext: export some symbols" This reverts commit 3ffae176371cc9aaf673e1ae05c3498e08f9fec9. Signed-off-by: Robert Lubos --- include/zephyr/llext/symbol.h | 10 ---------- kernel/mutex.c | 3 --- kernel/thread.c | 2 -- lib/os/assert.c | 4 +--- subsys/llext/CMakeLists.txt | 3 ++- subsys/llext/llext_export.c | 17 ----------------- subsys/logging/log_msg.c | 2 -- 7 files changed, 3 insertions(+), 38 deletions(-) delete mode 100644 subsys/llext/llext_export.c diff --git a/include/zephyr/llext/symbol.h b/include/zephyr/llext/symbol.h index 84e43d22b5b..b1aef67413e 100644 --- a/include/zephyr/llext/symbol.h +++ b/include/zephyr/llext/symbol.h @@ -78,16 +78,6 @@ struct llext_symtable { .name = STRINGIFY(x), .addr = &x, \ } -/** - * @brief Export a system call to a table of symbols - * - * Takes a system call name and uses @a EXPORT_SYMBOL() to export the respective - * function. - * - * @param x System call to export - */ -#define EXPORT_SYSCALL(x) EXPORT_SYMBOL(z_impl_ ## x) - /** * @} */ diff --git a/kernel/mutex.c b/kernel/mutex.c index 622422aef7b..6d22ce83f22 100644 --- a/kernel/mutex.c +++ b/kernel/mutex.c @@ -37,7 +37,6 @@ #include #include #include -#include LOG_MODULE_DECLARE(os, CONFIG_KERNEL_LOG_LEVEL); /* We use a global spinlock here because some of the synchronization @@ -196,7 +195,6 @@ int z_impl_k_mutex_lock(struct k_mutex *mutex, k_timeout_t timeout) return -EAGAIN; } -EXPORT_SYSCALL(k_mutex_lock); #ifdef CONFIG_USERSPACE static inline int z_vrfy_k_mutex_lock(struct k_mutex *mutex, @@ -282,7 +280,6 @@ int z_impl_k_mutex_unlock(struct k_mutex *mutex) return 0; } -EXPORT_SYSCALL(k_mutex_unlock); #ifdef CONFIG_USERSPACE static inline int z_vrfy_k_mutex_unlock(struct k_mutex *mutex) diff --git a/kernel/thread.c b/kernel/thread.c index fc31f4b36d8..8f60054e798 100644 --- a/kernel/thread.c +++ b/kernel/thread.c @@ -29,7 +29,6 @@ #include #include #include -#include #include LOG_MODULE_DECLARE(os, CONFIG_KERNEL_LOG_LEVEL); @@ -142,7 +141,6 @@ bool k_is_in_isr(void) { return arch_is_in_isr(); } -EXPORT_SYMBOL(k_is_in_isr); /* * This function tags the current thread as essential to system operation. diff --git a/lib/os/assert.c b/lib/os/assert.c index 1fee487bff6..b6a33ae7320 100644 --- a/lib/os/assert.c +++ b/lib/os/assert.c @@ -7,7 +7,7 @@ #include #include #include -#include + /** * @brief Assert Action Handler @@ -42,7 +42,6 @@ __weak void assert_post_action(const char *file, unsigned int line) k_panic(); } -EXPORT_SYMBOL(assert_post_action); void assert_print(const char *fmt, ...) { @@ -54,4 +53,3 @@ void assert_print(const char *fmt, ...) va_end(ap); } -EXPORT_SYMBOL(assert_print); diff --git a/subsys/llext/CMakeLists.txt b/subsys/llext/CMakeLists.txt index b129dc7f943..ac54f3172c3 100644 --- a/subsys/llext/CMakeLists.txt +++ b/subsys/llext/CMakeLists.txt @@ -1,5 +1,6 @@ if(CONFIG_LLEXT) zephyr_library() - zephyr_library_sources(llext.c llext_export.c buf_loader.c) + zephyr_library_sources(llext.c) + zephyr_library_sources(buf_loader.c) zephyr_library_sources_ifdef(CONFIG_LLEXT_SHELL shell.c) endif() diff --git a/subsys/llext/llext_export.c b/subsys/llext/llext_export.c deleted file mode 100644 index 0ec7fe4ac0a..00000000000 --- a/subsys/llext/llext_export.c +++ /dev/null @@ -1,17 +0,0 @@ -/* - * Copyright (c) 2023 Intel Corporation - * - * SPDX-License-Identifier: Apache-2.0 - */ - -#include -#include - -EXPORT_SYMBOL(strcpy); -EXPORT_SYMBOL(strncpy); -EXPORT_SYMBOL(strlen); -EXPORT_SYMBOL(strcmp); -EXPORT_SYMBOL(strncmp); -EXPORT_SYMBOL(memcmp); -EXPORT_SYMBOL(memcpy); -EXPORT_SYMBOL(memset); diff --git a/subsys/logging/log_msg.c b/subsys/logging/log_msg.c index da9dffdc62e..8023cefbf8c 100644 --- a/subsys/logging/log_msg.c +++ b/subsys/logging/log_msg.c @@ -10,7 +10,6 @@ #include #include #include -#include LOG_MODULE_DECLARE(log); BUILD_ASSERT(sizeof(struct log_msg_desc) == sizeof(uint32_t), @@ -271,7 +270,6 @@ void z_impl_z_log_msg_static_create(const void *source, z_log_msg_finalize(msg, source, out_desc, data); } -EXPORT_SYSCALL(z_log_msg_static_create); #ifdef CONFIG_USERSPACE static inline void z_vrfy_z_log_msg_static_create(const void *source, From bd92c33c90256941379dc640857a1e8142bd5402 Mon Sep 17 00:00:00 2001 From: Robert Lubos Date: Tue, 6 Feb 2024 11:07:24 +0100 Subject: [PATCH 3634/3723] Revert "[nrf fromtree] llext: add support for shared objects" This reverts commit e3c172a8be333da55dc7802cb83eff23e786c81c. Signed-off-by: Robert Lubos --- subsys/llext/llext.c | 112 ++----------------------------------------- 1 file changed, 3 insertions(+), 109 deletions(-) diff --git a/subsys/llext/llext.c b/subsys/llext/llext.c index 7b8099a9190..3d99c8af4fa 100644 --- a/subsys/llext/llext.c +++ b/subsys/llext/llext.c @@ -446,105 +446,6 @@ static int llext_copy_symbols(struct llext_loader *ldr, struct llext *ext) return 0; } -/* - * Find the section, containing the supplied offset and return file offset for - * that value - */ -static size_t llext_file_offset(struct llext_loader *ldr, size_t offset) -{ - unsigned int i; - - for (i = 0; i < LLEXT_SECT_COUNT; i++) - if (ldr->sects[i].sh_addr <= offset && - ldr->sects[i].sh_addr + ldr->sects[i].sh_size > offset) - return offset - ldr->sects[i].sh_addr + ldr->sects[i].sh_offset; - - return offset; -} - -static void llext_link_plt(struct llext_loader *ldr, struct llext *ext, elf_shdr_t *shdr) -{ - unsigned int sh_cnt = shdr->sh_size / shdr->sh_entsize; - /* - * CPU address where the .text section is stored, we use .text just as a - * reference point - */ - uint8_t *text = ext->mem[LLEXT_MEM_TEXT]; - - LOG_DBG("Found %p in PLT %u size %u cnt %u text %p", - (void *)llext_string(ldr, ext, LLEXT_MEM_SHSTRTAB, shdr->sh_name), - shdr->sh_type, shdr->sh_entsize, sh_cnt, (void *)text); - - const elf_shdr_t *sym_shdr = ldr->sects + LLEXT_SECT_SYMTAB; - unsigned int sym_cnt = sym_shdr->sh_size / sym_shdr->sh_entsize; - - for (unsigned int i = 0; i < sh_cnt; i++) { - elf_rela_t rela; - - int ret = llext_seek(ldr, shdr->sh_offset + i * shdr->sh_entsize); - - if (!ret) { - ret = llext_read(ldr, &rela, sizeof(rela)); - } - - if (ret < 0) { - LOG_ERR("PLT: failed to read RELA #%u, trying to continue", i); - continue; - } - - /* Index in the symbol table */ - unsigned int j = ELF32_R_SYM(rela.r_info); - - if (j >= sym_cnt) { - LOG_WRN("PLT: idx %u >= %u", j, sym_cnt); - continue; - } - - elf_sym_t sym_tbl; - - ret = llext_seek(ldr, sym_shdr->sh_offset + j * sizeof(elf_sym_t)); - if (!ret) { - ret = llext_read(ldr, &sym_tbl, sizeof(sym_tbl)); - } - - if (ret < 0) { - LOG_ERR("PLT: failed to read symbol table #%u RELA #%u, trying to continue", - j, i); - continue; - } - - uint32_t stt = ELF_ST_TYPE(sym_tbl.st_info); - const char *name = llext_string(ldr, ext, LLEXT_MEM_STRTAB, sym_tbl.st_name); - /* - * Both r_offset and sh_addr are addresses for which the extension - * has been built. - */ - size_t got_offset = llext_file_offset(ldr, rela.r_offset) - - ldr->sects[LLEXT_SECT_TEXT].sh_offset; - - if (stt == STT_NOTYPE && sym_tbl.st_shndx == SHN_UNDEF && name[0] != '\0') { - const void *link_addr = llext_find_sym(NULL, name); - - if (!link_addr) { - LOG_WRN("PLT: cannot find idx %u name %s", j, name); - continue; - } - - if (!rela.r_offset) { - LOG_WRN("PLT: zero offset idx %u name %s", j, name); - continue; - } - - LOG_DBG("symbol %s offset %#x r-offset %#x .text offset %#x", - name, got_offset, - rela.r_offset, ldr->sects[LLEXT_SECT_TEXT].sh_offset); - - /* Resolve the symbol */ - *(const void **)(text + got_offset) = link_addr; - } - } -} - __weak void arch_elf_relocate(elf_rela_t *rel, uintptr_t opaddr, uintptr_t opval) { } @@ -585,19 +486,12 @@ static int llext_link(struct llext_loader *ldr, struct llext *ext) if (strcmp(name, ".rel.text") == 0 || strcmp(name, ".rela.text") == 0) { loc = (uintptr_t)ext->mem[LLEXT_MEM_TEXT]; - } else if (strcmp(name, ".rel.bss") == 0 || - strcmp(name, ".rela.bss") == 0) { + } else if (strcmp(name, ".rel.bss") == 0) { loc = (uintptr_t)ext->mem[LLEXT_MEM_BSS]; - } else if (strcmp(name, ".rel.rodata") == 0 || - strcmp(name, ".rela.rodata") == 0) { + } else if (strcmp(name, ".rel.rodata") == 0) { loc = (uintptr_t)ext->mem[LLEXT_MEM_RODATA]; - } else if (strcmp(name, ".rel.data") == 0 || - strcmp(name, ".rela.data") == 0) { + } else if (strcmp(name, ".rel.data") == 0) { loc = (uintptr_t)ext->mem[LLEXT_MEM_DATA]; - } else if (strcmp(name, ".rela.plt") == 0 || - strcmp(name, ".rela.dyn") == 0) { - llext_link_plt(ldr, ext, &shdr); - continue; } LOG_DBG("relocation section %s (%d) linked to section %d has %d relocations", From 0df46ab98eb98364294619f6a9a062606860b6d7 Mon Sep 17 00:00:00 2001 From: Robert Lubos Date: Tue, 6 Feb 2024 11:07:24 +0100 Subject: [PATCH 3635/3723] Revert "[nrf fromtree] net: shell: Rename the common.h to be more unique" This reverts commit 4a03d8a097843a324fe7746fb5383476b341671a. Signed-off-by: Robert Lubos --- subsys/net/lib/shell/allocs.c | 2 +- subsys/net/lib/shell/arp.c | 2 +- subsys/net/lib/shell/capture.c | 2 +- subsys/net/lib/shell/{net_shell_private.h => common.h} | 0 subsys/net/lib/shell/conn.c | 2 +- subsys/net/lib/shell/dns.c | 2 +- subsys/net/lib/shell/events.c | 2 +- subsys/net/lib/shell/gptp.c | 2 +- subsys/net/lib/shell/iface.c | 2 +- subsys/net/lib/shell/ipv4.c | 2 +- subsys/net/lib/shell/ipv6.c | 2 +- subsys/net/lib/shell/mem.c | 2 +- subsys/net/lib/shell/nbr.c | 2 +- subsys/net/lib/shell/net_shell.c | 2 +- subsys/net/lib/shell/ping.c | 2 +- subsys/net/lib/shell/pkt.c | 2 +- subsys/net/lib/shell/ppp.c | 2 +- subsys/net/lib/shell/resume.c | 2 +- subsys/net/lib/shell/route.c | 2 +- subsys/net/lib/shell/sockets.c | 2 +- subsys/net/lib/shell/stats.c | 2 +- subsys/net/lib/shell/suspend.c | 2 +- subsys/net/lib/shell/tcp.c | 2 +- subsys/net/lib/shell/udp.c | 2 +- subsys/net/lib/shell/virtual.c | 2 +- subsys/net/lib/shell/vlan.c | 2 +- subsys/net/lib/shell/websocket.c | 2 +- 27 files changed, 26 insertions(+), 26 deletions(-) rename subsys/net/lib/shell/{net_shell_private.h => common.h} (100%) diff --git a/subsys/net/lib/shell/allocs.c b/subsys/net/lib/shell/allocs.c index a2669590520..1c6e7288003 100644 --- a/subsys/net/lib/shell/allocs.c +++ b/subsys/net/lib/shell/allocs.c @@ -8,7 +8,7 @@ #include LOG_MODULE_DECLARE(net_shell); -#include "net_shell_private.h" +#include "common.h" #if defined(CONFIG_NET_DEBUG_NET_PKT_ALLOC) static void allocs_cb(struct net_pkt *pkt, diff --git a/subsys/net/lib/shell/arp.c b/subsys/net/lib/shell/arp.c index 58889f27d5c..fb1582411e9 100644 --- a/subsys/net/lib/shell/arp.c +++ b/subsys/net/lib/shell/arp.c @@ -8,7 +8,7 @@ #include LOG_MODULE_DECLARE(net_shell); -#include "net_shell_private.h" +#include "common.h" #if defined(CONFIG_NET_ARP) #include "ethernet/arp.h" diff --git a/subsys/net/lib/shell/capture.c b/subsys/net/lib/shell/capture.c index 0c7347f8774..f05531562ae 100644 --- a/subsys/net/lib/shell/capture.c +++ b/subsys/net/lib/shell/capture.c @@ -10,7 +10,7 @@ LOG_MODULE_DECLARE(net_shell); #include -#include "net_shell_private.h" +#include "common.h" #include diff --git a/subsys/net/lib/shell/net_shell_private.h b/subsys/net/lib/shell/common.h similarity index 100% rename from subsys/net/lib/shell/net_shell_private.h rename to subsys/net/lib/shell/common.h diff --git a/subsys/net/lib/shell/conn.c b/subsys/net/lib/shell/conn.c index 24b528537bd..36831809eb8 100644 --- a/subsys/net/lib/shell/conn.c +++ b/subsys/net/lib/shell/conn.c @@ -8,7 +8,7 @@ #include LOG_MODULE_DECLARE(net_shell); -#include "net_shell_private.h" +#include "common.h" #if defined(CONFIG_NET_TCP) #include "tcp_internal.h" diff --git a/subsys/net/lib/shell/dns.c b/subsys/net/lib/shell/dns.c index 54c768cecd1..24a52f5e8a2 100644 --- a/subsys/net/lib/shell/dns.c +++ b/subsys/net/lib/shell/dns.c @@ -10,7 +10,7 @@ LOG_MODULE_DECLARE(net_shell); #include -#include "net_shell_private.h" +#include "common.h" #if defined(CONFIG_DNS_RESOLVER) static void dns_result_cb(enum dns_resolve_status status, diff --git a/subsys/net/lib/shell/events.c b/subsys/net/lib/shell/events.c index 5a5d0f38f7d..047fd1e2186 100644 --- a/subsys/net/lib/shell/events.c +++ b/subsys/net/lib/shell/events.c @@ -13,7 +13,7 @@ LOG_MODULE_DECLARE(net_shell); #include #include -#include "net_shell_private.h" +#include "common.h" #if defined(CONFIG_NET_MGMT_EVENT_MONITOR) #define EVENT_MON_STACK_SIZE 1024 diff --git a/subsys/net/lib/shell/gptp.c b/subsys/net/lib/shell/gptp.c index 0de653e26cd..a156637e3af 100644 --- a/subsys/net/lib/shell/gptp.c +++ b/subsys/net/lib/shell/gptp.c @@ -19,7 +19,7 @@ LOG_MODULE_DECLARE(net_shell); #include "ethernet/gptp/gptp_private.h" #endif -#include "net_shell_private.h" +#include "common.h" #if defined(CONFIG_NET_GPTP) static const char *selected_role_str(int port); diff --git a/subsys/net/lib/shell/iface.c b/subsys/net/lib/shell/iface.c index 53d4e99bd21..89983bd4839 100644 --- a/subsys/net/lib/shell/iface.c +++ b/subsys/net/lib/shell/iface.c @@ -18,7 +18,7 @@ LOG_MODULE_DECLARE(net_shell); #include #endif -#include "net_shell_private.h" +#include "common.h" #if defined(CONFIG_NET_L2_ETHERNET) && defined(CONFIG_NET_NATIVE) struct ethernet_capabilities { diff --git a/subsys/net/lib/shell/ipv4.c b/subsys/net/lib/shell/ipv4.c index e8584b205fb..8fc88168c9a 100644 --- a/subsys/net/lib/shell/ipv4.c +++ b/subsys/net/lib/shell/ipv4.c @@ -10,7 +10,7 @@ LOG_MODULE_DECLARE(net_shell); #include -#include "net_shell_private.h" +#include "common.h" #include "../ip/ipv4.h" #if defined(CONFIG_NET_NATIVE_IPV4) diff --git a/subsys/net/lib/shell/ipv6.c b/subsys/net/lib/shell/ipv6.c index 04efda65d0f..f81b8dcae23 100644 --- a/subsys/net/lib/shell/ipv6.c +++ b/subsys/net/lib/shell/ipv6.c @@ -8,7 +8,7 @@ #include LOG_MODULE_DECLARE(net_shell); -#include "net_shell_private.h" +#include "common.h" #include "../ip/ipv6.h" #if defined(CONFIG_NET_IPV6_FRAGMENT) diff --git a/subsys/net/lib/shell/mem.c b/subsys/net/lib/shell/mem.c index 47058f92767..cf58cda6bd6 100644 --- a/subsys/net/lib/shell/mem.c +++ b/subsys/net/lib/shell/mem.c @@ -8,7 +8,7 @@ #include LOG_MODULE_DECLARE(net_shell); -#include "net_shell_private.h" +#include "common.h" struct ctx_info { int pos; diff --git a/subsys/net/lib/shell/nbr.c b/subsys/net/lib/shell/nbr.c index 63b62406702..fd420b818ae 100644 --- a/subsys/net/lib/shell/nbr.c +++ b/subsys/net/lib/shell/nbr.c @@ -8,7 +8,7 @@ #include LOG_MODULE_DECLARE(net_shell); -#include "net_shell_private.h" +#include "common.h" static int cmd_net_nbr_rm(const struct shell *sh, size_t argc, char *argv[]) { diff --git a/subsys/net/lib/shell/net_shell.c b/subsys/net/lib/shell/net_shell.c index 9f932cb1bc4..19bab12e029 100644 --- a/subsys/net/lib/shell/net_shell.c +++ b/subsys/net/lib/shell/net_shell.c @@ -20,7 +20,7 @@ LOG_MODULE_REGISTER(net_shell, LOG_LEVEL_DBG); #include -#include "net_shell_private.h" +#include "common.h" #include "net_shell.h" int get_iface_idx(const struct shell *sh, char *index_str) diff --git a/subsys/net/lib/shell/ping.c b/subsys/net/lib/shell/ping.c index 833c6eb8d54..8b52df110be 100644 --- a/subsys/net/lib/shell/ping.c +++ b/subsys/net/lib/shell/ping.c @@ -13,7 +13,7 @@ LOG_MODULE_DECLARE(net_shell); #include #include -#include "net_shell_private.h" +#include "common.h" #include "../ip/icmpv6.h" #include "../ip/icmpv4.h" diff --git a/subsys/net/lib/shell/pkt.c b/subsys/net/lib/shell/pkt.c index 3306b05d1a7..09d7ae6738a 100644 --- a/subsys/net/lib/shell/pkt.c +++ b/subsys/net/lib/shell/pkt.c @@ -8,7 +8,7 @@ #include LOG_MODULE_DECLARE(net_shell); -#include "net_shell_private.h" +#include "common.h" static bool is_pkt_part_of_slab(const struct k_mem_slab *slab, const char *ptr) { diff --git a/subsys/net/lib/shell/ppp.c b/subsys/net/lib/shell/ppp.c index f63c6ca3324..9b5f8355d47 100644 --- a/subsys/net/lib/shell/ppp.c +++ b/subsys/net/lib/shell/ppp.c @@ -10,7 +10,7 @@ LOG_MODULE_DECLARE(net_shell); #include -#include "net_shell_private.h" +#include "common.h" #if defined(CONFIG_NET_L2_PPP) #include diff --git a/subsys/net/lib/shell/resume.c b/subsys/net/lib/shell/resume.c index dcd3fbf309d..585d421efab 100644 --- a/subsys/net/lib/shell/resume.c +++ b/subsys/net/lib/shell/resume.c @@ -9,7 +9,7 @@ #include LOG_MODULE_DECLARE(net_shell); -#include "net_shell_private.h" +#include "common.h" static int cmd_net_resume(const struct shell *sh, size_t argc, char *argv[]) { diff --git a/subsys/net/lib/shell/route.c b/subsys/net/lib/shell/route.c index 035b56f6dfc..d48c442ed41 100644 --- a/subsys/net/lib/shell/route.c +++ b/subsys/net/lib/shell/route.c @@ -8,7 +8,7 @@ #include LOG_MODULE_DECLARE(net_shell); -#include "net_shell_private.h" +#include "common.h" #include "../ip/route.h" diff --git a/subsys/net/lib/shell/sockets.c b/subsys/net/lib/shell/sockets.c index 8be67fc5faf..792e34efc21 100644 --- a/subsys/net/lib/shell/sockets.c +++ b/subsys/net/lib/shell/sockets.c @@ -7,7 +7,7 @@ #include LOG_MODULE_DECLARE(net_shell); -#include "net_shell_private.h" +#include "common.h" #include #if defined(CONFIG_NET_SOCKETS_OBJ_CORE) diff --git a/subsys/net/lib/shell/stats.c b/subsys/net/lib/shell/stats.c index 666a98e35d7..455f5d7decd 100644 --- a/subsys/net/lib/shell/stats.c +++ b/subsys/net/lib/shell/stats.c @@ -10,7 +10,7 @@ LOG_MODULE_DECLARE(net_shell); #include -#include "net_shell_private.h" +#include "common.h" #include "../ip/net_stats.h" diff --git a/subsys/net/lib/shell/suspend.c b/subsys/net/lib/shell/suspend.c index cfa01375cac..326eb602077 100644 --- a/subsys/net/lib/shell/suspend.c +++ b/subsys/net/lib/shell/suspend.c @@ -9,7 +9,7 @@ #include LOG_MODULE_DECLARE(net_shell); -#include "net_shell_private.h" +#include "common.h" static int cmd_net_suspend(const struct shell *sh, size_t argc, char *argv[]) { diff --git a/subsys/net/lib/shell/tcp.c b/subsys/net/lib/shell/tcp.c index e2839af36ba..f90e16b3b66 100644 --- a/subsys/net/lib/shell/tcp.c +++ b/subsys/net/lib/shell/tcp.c @@ -10,7 +10,7 @@ LOG_MODULE_DECLARE(net_shell); #include -#include "net_shell_private.h" +#include "common.h" #if defined(CONFIG_NET_TCP) && defined(CONFIG_NET_NATIVE_TCP) static struct net_context *tcp_ctx; diff --git a/subsys/net/lib/shell/udp.c b/subsys/net/lib/shell/udp.c index 7bccbf93ba3..9eaf3254514 100644 --- a/subsys/net/lib/shell/udp.c +++ b/subsys/net/lib/shell/udp.c @@ -10,7 +10,7 @@ LOG_MODULE_DECLARE(net_shell); #include -#include "net_shell_private.h" +#include "common.h" #if defined(CONFIG_NET_UDP) && defined(CONFIG_NET_NATIVE_UDP) static struct net_context *udp_ctx; diff --git a/subsys/net/lib/shell/virtual.c b/subsys/net/lib/shell/virtual.c index 4eaabaa9916..19c9b1c1b0e 100644 --- a/subsys/net/lib/shell/virtual.c +++ b/subsys/net/lib/shell/virtual.c @@ -12,7 +12,7 @@ LOG_MODULE_DECLARE(net_shell); #include #endif -#include "net_shell_private.h" +#include "common.h" #if defined(CONFIG_NET_L2_VIRTUAL) static void virtual_iface_cb(struct net_if *iface, void *user_data) diff --git a/subsys/net/lib/shell/vlan.c b/subsys/net/lib/shell/vlan.c index ea7103ef1c9..0a980caa11f 100644 --- a/subsys/net/lib/shell/vlan.c +++ b/subsys/net/lib/shell/vlan.c @@ -15,7 +15,7 @@ LOG_MODULE_DECLARE(net_shell); #include -#include "net_shell_private.h" +#include "common.h" #if defined(CONFIG_NET_VLAN) static void iface_vlan_del_cb(struct net_if *iface, void *user_data) diff --git a/subsys/net/lib/shell/websocket.c b/subsys/net/lib/shell/websocket.c index 56e705199e3..f3e77187627 100644 --- a/subsys/net/lib/shell/websocket.c +++ b/subsys/net/lib/shell/websocket.c @@ -12,7 +12,7 @@ LOG_MODULE_DECLARE(net_shell); #include #endif -#include "net_shell_private.h" +#include "common.h" #include "websocket/websocket_internal.h" From 7db319d42af37574c92e8f6a2f1ccb36aebecc97 Mon Sep 17 00:00:00 2001 From: Robert Lubos Date: Tue, 6 Feb 2024 11:07:25 +0100 Subject: [PATCH 3636/3723] Revert "[nrf fromtree] samples/drivers/mbox: Reduce sysbuild boilerplate" This reverts commit ab3ed158d57b033b08ed76952e3112b9802c7d67. Signed-off-by: Robert Lubos --- samples/drivers/mbox/sysbuild.cmake | 22 ++++++++++++++++++++-- 1 file changed, 20 insertions(+), 2 deletions(-) diff --git a/samples/drivers/mbox/sysbuild.cmake b/samples/drivers/mbox/sysbuild.cmake index a8dfb8ebdf4..1bd6a00ae9e 100644 --- a/samples/drivers/mbox/sysbuild.cmake +++ b/samples/drivers/mbox/sysbuild.cmake @@ -15,6 +15,24 @@ ExternalZephyrProject_Add( BOARD ${SB_CONFIG_REMOTE_BOARD} ) -native_simulator_set_child_images(${DEFAULT_IMAGE} ${REMOTE_APP}) +if("${BOARD}" STREQUAL "nrf5340bsim_nrf5340_cpuapp") + # For the simulated board, the application core build will produce the final executable + # for that, we give it the path to the netcore image + set(NET_LIBRARY_PATH ${CMAKE_BINARY_DIR}/${REMOTE_APP}/zephyr/zephyr.elf) + set_property(TARGET ${DEFAULT_IMAGE} APPEND_STRING PROPERTY CONFIG + "CONFIG_NATIVE_SIMULATOR_EXTRA_IMAGE_PATHS=\"${NET_LIBRARY_PATH}\"\n" + ) -native_simulator_set_final_executable(${DEFAULT_IMAGE}) + # Let's build the net core library first + add_dependencies(${DEFAULT_IMAGE} ${REMOTE_APP}) + + # Let's meet users expectations of finding the final executable in zephyr/zephyr.exe + add_custom_target(final_executable + ALL + COMMAND + ${CMAKE_COMMAND} -E copy + ${CMAKE_BINARY_DIR}/${DEFAULT_IMAGE}/zephyr/zephyr.exe + ${CMAKE_BINARY_DIR}/zephyr/zephyr.exe + DEPENDS ${DEFAULT_IMAGE} + ) +endif() From 4e3aaae3509443d02e7186fc55f54b0b927ebe73 Mon Sep 17 00:00:00 2001 From: Robert Lubos Date: Tue, 6 Feb 2024 11:07:25 +0100 Subject: [PATCH 3637/3723] Revert "[nrf fromtree] samples/boards/nrf/nrf53_sync_rtc: Reduce sysbuild boilerplate" This reverts commit e4b78eddab9555b80726f00dfae9139f7f85cc35. Signed-off-by: Robert Lubos --- .../boards/nrf/nrf53_sync_rtc/sysbuild.cmake | 22 +++++++++++++++++-- 1 file changed, 20 insertions(+), 2 deletions(-) diff --git a/samples/boards/nrf/nrf53_sync_rtc/sysbuild.cmake b/samples/boards/nrf/nrf53_sync_rtc/sysbuild.cmake index 0c97244fd7b..a5d1eb9874f 100644 --- a/samples/boards/nrf/nrf53_sync_rtc/sysbuild.cmake +++ b/samples/boards/nrf/nrf53_sync_rtc/sysbuild.cmake @@ -15,6 +15,24 @@ ExternalZephyrProject_Add( BOARD ${SB_CONFIG_NET_CORE_BOARD} ) -native_simulator_set_child_images(${DEFAULT_IMAGE} ${REMOTE_APP}) +if("${BOARD}" STREQUAL "nrf5340bsim_nrf5340_cpuapp") + # For the simulated board, the application core build will produce the final executable + # for that, we give it the path to the netcore image + set(NET_LIBRARY_PATH ${CMAKE_BINARY_DIR}/${REMOTE_APP}/zephyr/zephyr.elf) + set_property(TARGET ${DEFAULT_IMAGE} APPEND_STRING PROPERTY CONFIG + "CONFIG_NATIVE_SIMULATOR_EXTRA_IMAGE_PATHS=\"${NET_LIBRARY_PATH}\"\n" + ) -native_simulator_set_final_executable(${DEFAULT_IMAGE}) + # Let's build the net core library first + add_dependencies(${DEFAULT_IMAGE} ${REMOTE_APP}) + + # Let's meet users expectations of finding the final executable in zephyr/zephyr.exe + add_custom_target(final_executable + ALL + COMMAND + ${CMAKE_COMMAND} -E copy + ${CMAKE_BINARY_DIR}/${DEFAULT_IMAGE}/zephyr/zephyr.exe + ${CMAKE_BINARY_DIR}/zephyr/zephyr.exe + DEPENDS ${DEFAULT_IMAGE} + ) +endif() From d0c2ca6ffa658bdbeb8034577ea0d50d755da4ae Mon Sep 17 00:00:00 2001 From: Robert Lubos Date: Tue, 6 Feb 2024 11:07:25 +0100 Subject: [PATCH 3638/3723] Revert "[nrf fromtree] samples/subsys/logging/multidomain: Reduce sysbuild boilerplate" This reverts commit bbbf671ef88cdf8c3b064fc79a38eec317a780c6. Signed-off-by: Robert Lubos --- .../subsys/logging/multidomain/sysbuild.cmake | 22 +++++++++++++++++-- 1 file changed, 20 insertions(+), 2 deletions(-) diff --git a/samples/subsys/logging/multidomain/sysbuild.cmake b/samples/subsys/logging/multidomain/sysbuild.cmake index 496a7a03f9d..e50f47b6db1 100644 --- a/samples/subsys/logging/multidomain/sysbuild.cmake +++ b/samples/subsys/logging/multidomain/sysbuild.cmake @@ -15,6 +15,24 @@ ExternalZephyrProject_Add( BOARD ${SB_CONFIG_NET_CORE_BOARD} ) -native_simulator_set_child_images(${DEFAULT_IMAGE} ${NET_APP}) +if("${BOARD}" STREQUAL "nrf5340bsim_nrf5340_cpuapp") + # For the simulated board, the application core build will produce the final executable + # for that, we give it the path to the netcore image + set(NET_LIBRARY_PATH ${CMAKE_BINARY_DIR}/${NET_APP}/zephyr/zephyr.elf) + set_property(TARGET ${DEFAULT_IMAGE} APPEND_STRING PROPERTY CONFIG + "CONFIG_NATIVE_SIMULATOR_EXTRA_IMAGE_PATHS=\"${NET_LIBRARY_PATH}\"\n" + ) -native_simulator_set_final_executable(${DEFAULT_IMAGE}) + # Let's build the net core library first + add_dependencies(${DEFAULT_IMAGE} ${NET_APP}) + + # Let's meet users expectations of finding the final executable in zephyr/zephyr.exe + add_custom_target(final_executable + ALL + COMMAND + ${CMAKE_COMMAND} -E copy + ${CMAKE_BINARY_DIR}/${DEFAULT_IMAGE}/zephyr/zephyr.exe + ${CMAKE_BINARY_DIR}/zephyr/zephyr.exe + DEPENDS ${DEFAULT_IMAGE} + ) +endif() From b6b1f44a3d42ee90ef9760798b6926ed40f6225f Mon Sep 17 00:00:00 2001 From: Robert Lubos Date: Tue, 6 Feb 2024 11:07:25 +0100 Subject: [PATCH 3639/3723] Revert "[nrf fromtree] tests/bsim/bluetooth: Reduce sysbuild boilerplate" This reverts commit 273508cf01151f3ab8d13e4df580f0b941fdcdeb. Signed-off-by: Robert Lubos --- .../broadcast_audio_sink/sysbuild.cmake | 9 +++++- .../unicast_audio_client/sysbuild.cmake | 9 +++++- tests/bsim/bluetooth/ll/bis/sysbuild.cmake | 29 +++++++++++++++++-- tests/bsim/bluetooth/ll/cis/sysbuild.cmake | 29 +++++++++++++++++-- tests/bsim/bluetooth/ll/conn/sysbuild.cmake | 29 +++++++++++++++++-- 5 files changed, 94 insertions(+), 11 deletions(-) diff --git a/tests/bsim/bluetooth/audio_samples/broadcast_audio_sink/sysbuild.cmake b/tests/bsim/bluetooth/audio_samples/broadcast_audio_sink/sysbuild.cmake index 2bf2920a476..a922830546d 100644 --- a/tests/bsim/bluetooth/audio_samples/broadcast_audio_sink/sysbuild.cmake +++ b/tests/bsim/bluetooth/audio_samples/broadcast_audio_sink/sysbuild.cmake @@ -3,4 +3,11 @@ include(${ZEPHYR_BASE}/samples/bluetooth/broadcast_audio_sink/sysbuild.cmake) -native_simulator_set_primary_mcu_index(${DEFAULT_IMAGE} ${NET_APP}) +if (NOT ("${SB_CONFIG_NATIVE_SIMULATOR_PRIMARY_MCU_INDEX}" STREQUAL "")) + set_property(TARGET ${NET_APP} APPEND_STRING PROPERTY CONFIG + "CONFIG_NATIVE_SIMULATOR_PRIMARY_MCU_INDEX=${SB_CONFIG_NATIVE_SIMULATOR_PRIMARY_MCU_INDEX}\n" + ) + set_property(TARGET ${DEFAULT_IMAGE} APPEND_STRING PROPERTY CONFIG + "CONFIG_NATIVE_SIMULATOR_PRIMARY_MCU_INDEX=${SB_CONFIG_NATIVE_SIMULATOR_PRIMARY_MCU_INDEX}\n" + ) +endif() diff --git a/tests/bsim/bluetooth/audio_samples/unicast_audio_client/sysbuild.cmake b/tests/bsim/bluetooth/audio_samples/unicast_audio_client/sysbuild.cmake index 85b85b7cb63..9686cde1bce 100644 --- a/tests/bsim/bluetooth/audio_samples/unicast_audio_client/sysbuild.cmake +++ b/tests/bsim/bluetooth/audio_samples/unicast_audio_client/sysbuild.cmake @@ -3,4 +3,11 @@ include(${ZEPHYR_BASE}/samples/bluetooth/unicast_audio_client/sysbuild.cmake) -native_simulator_set_primary_mcu_index(${DEFAULT_IMAGE} ${NET_APP}) +if (NOT ("${SB_CONFIG_NATIVE_SIMULATOR_PRIMARY_MCU_INDEX}" STREQUAL "")) + set_property(TARGET ${NET_APP} APPEND_STRING PROPERTY CONFIG + "CONFIG_NATIVE_SIMULATOR_PRIMARY_MCU_INDEX=${SB_CONFIG_NATIVE_SIMULATOR_PRIMARY_MCU_INDEX}\n" + ) + set_property(TARGET ${DEFAULT_IMAGE} APPEND_STRING PROPERTY CONFIG + "CONFIG_NATIVE_SIMULATOR_PRIMARY_MCU_INDEX=${SB_CONFIG_NATIVE_SIMULATOR_PRIMARY_MCU_INDEX}\n" + ) +endif() diff --git a/tests/bsim/bluetooth/ll/bis/sysbuild.cmake b/tests/bsim/bluetooth/ll/bis/sysbuild.cmake index 69397264edf..eb75debccd3 100644 --- a/tests/bsim/bluetooth/ll/bis/sysbuild.cmake +++ b/tests/bsim/bluetooth/ll/bis/sysbuild.cmake @@ -16,9 +16,32 @@ if(NOT("${SB_CONFIG_NET_CORE_BOARD}" STREQUAL "")) CACHE INTERNAL "" ) - native_simulator_set_primary_mcu_index(${DEFAULT_IMAGE} ${NET_APP}) + # For the simulated board, the application core build will produce the final executable + # for that, we give it the path to the netcore image + set(NET_LIBRARY_PATH ${CMAKE_BINARY_DIR}/${NET_APP}/zephyr/zephyr.elf) + set_property(TARGET ${DEFAULT_IMAGE} APPEND_STRING PROPERTY CONFIG + "CONFIG_NATIVE_SIMULATOR_EXTRA_IMAGE_PATHS=\"${NET_LIBRARY_PATH}\"\n" + ) + + if (NOT ("${SB_CONFIG_NATIVE_SIMULATOR_PRIMARY_MCU_INDEX}" STREQUAL "")) + set_property(TARGET ${NET_APP} APPEND_STRING PROPERTY CONFIG + "CONFIG_NATIVE_SIMULATOR_PRIMARY_MCU_INDEX=${SB_CONFIG_NATIVE_SIMULATOR_PRIMARY_MCU_INDEX}\n" + ) + set_property(TARGET ${DEFAULT_IMAGE} APPEND_STRING PROPERTY CONFIG + "CONFIG_NATIVE_SIMULATOR_PRIMARY_MCU_INDEX=${SB_CONFIG_NATIVE_SIMULATOR_PRIMARY_MCU_INDEX}\n" + ) + endif() - native_simulator_set_child_images(${DEFAULT_IMAGE} ${NET_APP}) + # Let's build the net core library first + add_dependencies(${DEFAULT_IMAGE} ${NET_APP}) endif() -native_simulator_set_final_executable(${DEFAULT_IMAGE}) +# Let's meet the expectation of finding the final executable in zephyr/zephyr.exe +add_custom_target(final_executable + ALL + COMMAND + ${CMAKE_COMMAND} -E copy + ${CMAKE_BINARY_DIR}/${DEFAULT_IMAGE}/zephyr/zephyr.exe + ${CMAKE_BINARY_DIR}/zephyr/zephyr.exe + DEPENDS ${DEFAULT_IMAGE} +) diff --git a/tests/bsim/bluetooth/ll/cis/sysbuild.cmake b/tests/bsim/bluetooth/ll/cis/sysbuild.cmake index a1258ecf1f2..495c3f4a20d 100644 --- a/tests/bsim/bluetooth/ll/cis/sysbuild.cmake +++ b/tests/bsim/bluetooth/ll/cis/sysbuild.cmake @@ -16,9 +16,32 @@ if(NOT("${SB_CONFIG_NET_CORE_BOARD}" STREQUAL "")) CACHE INTERNAL "" ) - native_simulator_set_primary_mcu_index(${DEFAULT_IMAGE} ${NET_APP}) + # For the simulated board, the application core build will produce the final executable + # for that, we give it the path to the netcore image + set(NET_LIBRARY_PATH ${CMAKE_BINARY_DIR}/${NET_APP}/zephyr/zephyr.elf) + set_property(TARGET ${DEFAULT_IMAGE} APPEND_STRING PROPERTY CONFIG + "CONFIG_NATIVE_SIMULATOR_EXTRA_IMAGE_PATHS=\"${NET_LIBRARY_PATH}\"\n" + ) + + if (NOT ("${SB_CONFIG_NATIVE_SIMULATOR_PRIMARY_MCU_INDEX}" STREQUAL "")) + set_property(TARGET ${NET_APP} APPEND_STRING PROPERTY CONFIG + "CONFIG_NATIVE_SIMULATOR_PRIMARY_MCU_INDEX=${SB_CONFIG_NATIVE_SIMULATOR_PRIMARY_MCU_INDEX}\n" + ) + set_property(TARGET ${DEFAULT_IMAGE} APPEND_STRING PROPERTY CONFIG + "CONFIG_NATIVE_SIMULATOR_PRIMARY_MCU_INDEX=${SB_CONFIG_NATIVE_SIMULATOR_PRIMARY_MCU_INDEX}\n" + ) + endif() - native_simulator_set_child_images(${DEFAULT_IMAGE} ${NET_APP}) + # Let's build the net core library first + add_dependencies(${DEFAULT_IMAGE} ${NET_APP}) endif() -native_simulator_set_final_executable(${DEFAULT_IMAGE}) +# Let's meet the expectation of finding the final executable in zephyr/zephyr.exe +add_custom_target(final_executable + ALL + COMMAND + ${CMAKE_COMMAND} -E copy + ${CMAKE_BINARY_DIR}/${DEFAULT_IMAGE}/zephyr/zephyr.exe + ${CMAKE_BINARY_DIR}/zephyr/zephyr.exe + DEPENDS ${DEFAULT_IMAGE} +) diff --git a/tests/bsim/bluetooth/ll/conn/sysbuild.cmake b/tests/bsim/bluetooth/ll/conn/sysbuild.cmake index 4dfa34ef519..2294fd5bb5e 100644 --- a/tests/bsim/bluetooth/ll/conn/sysbuild.cmake +++ b/tests/bsim/bluetooth/ll/conn/sysbuild.cmake @@ -11,9 +11,32 @@ if(NOT("${SB_CONFIG_NET_CORE_BOARD}" STREQUAL "")) BOARD ${SB_CONFIG_NET_CORE_BOARD} ) - native_simulator_set_primary_mcu_index(${DEFAULT_IMAGE} ${NET_APP}) + # For the simulated board, the application core build will produce the final executable + # for that, we give it the path to the netcore image + set(NET_LIBRARY_PATH ${CMAKE_BINARY_DIR}/${NET_APP}/zephyr/zephyr.elf) + set_property(TARGET ${DEFAULT_IMAGE} APPEND_STRING PROPERTY CONFIG + "CONFIG_NATIVE_SIMULATOR_EXTRA_IMAGE_PATHS=\"${NET_LIBRARY_PATH}\"\n" + ) + + if (NOT ("${SB_CONFIG_NATIVE_SIMULATOR_PRIMARY_MCU_INDEX}" STREQUAL "")) + set_property(TARGET ${NET_APP} APPEND_STRING PROPERTY CONFIG + "CONFIG_NATIVE_SIMULATOR_PRIMARY_MCU_INDEX=${SB_CONFIG_NATIVE_SIMULATOR_PRIMARY_MCU_INDEX}\n" + ) + set_property(TARGET ${DEFAULT_IMAGE} APPEND_STRING PROPERTY CONFIG + "CONFIG_NATIVE_SIMULATOR_PRIMARY_MCU_INDEX=${SB_CONFIG_NATIVE_SIMULATOR_PRIMARY_MCU_INDEX}\n" + ) + endif() - native_simulator_set_child_images(${DEFAULT_IMAGE} ${NET_APP}) + # Let's build the net core library first + add_dependencies(${DEFAULT_IMAGE} ${NET_APP}) endif() -native_simulator_set_final_executable(${DEFAULT_IMAGE}) +# Let's meet the expectation of finding the final executable in zephyr/zephyr.exe +add_custom_target(final_executable + ALL + COMMAND + ${CMAKE_COMMAND} -E copy + ${CMAKE_BINARY_DIR}/${DEFAULT_IMAGE}/zephyr/zephyr.exe + ${CMAKE_BINARY_DIR}/zephyr/zephyr.exe + DEPENDS ${DEFAULT_IMAGE} +) From 6caf9b80efe5d844e245461bf34ab990518a93f1 Mon Sep 17 00:00:00 2001 From: Robert Lubos Date: Tue, 6 Feb 2024 11:07:25 +0100 Subject: [PATCH 3640/3723] Revert "[nrf fromtree] samples/bluetooth: Reduce sysbuild boilerplate" This reverts commit c4fefa79ee03bf2c4b9c8d49012c50888ae43e09. Signed-off-by: Robert Lubos --- .../broadcast_audio_sink/sysbuild.cmake | 24 +++++++++++++++++-- .../broadcast_audio_source/sysbuild.cmake | 24 +++++++++++++++++-- .../unicast_audio_client/sysbuild.cmake | 24 +++++++++++++++++-- .../unicast_audio_server/sysbuild.cmake | 24 +++++++++++++++++-- 4 files changed, 88 insertions(+), 8 deletions(-) diff --git a/samples/bluetooth/broadcast_audio_sink/sysbuild.cmake b/samples/bluetooth/broadcast_audio_sink/sysbuild.cmake index 2523aac8ea7..ed30d7f31f3 100644 --- a/samples/bluetooth/broadcast_audio_sink/sysbuild.cmake +++ b/samples/bluetooth/broadcast_audio_sink/sysbuild.cmake @@ -18,7 +18,27 @@ if(SB_CONFIG_NET_CORE_IMAGE_HCI_IPC) CACHE INTERNAL "" ) - native_simulator_set_child_images(${DEFAULT_IMAGE} ${NET_APP}) + # Let's build the net core library first + add_dependencies(${DEFAULT_IMAGE} ${NET_APP}) + + if("${BOARD}" STREQUAL "nrf5340bsim_nrf5340_cpuapp") + # For the simulated board, the application core build will produce the final executable + # for that, we give it the path to the netcore image + set(NET_LIBRARY_PATH ${CMAKE_BINARY_DIR}/${NET_APP}/zephyr/zephyr.elf) + set_property(TARGET ${DEFAULT_IMAGE} APPEND_STRING PROPERTY CONFIG + "CONFIG_NATIVE_SIMULATOR_EXTRA_IMAGE_PATHS=\"${NET_LIBRARY_PATH}\"\n" + ) + endif() endif() -native_simulator_set_final_executable(${DEFAULT_IMAGE}) +if(("${BOARD}" MATCHES "native") OR ("${BOARD}" MATCHES "bsim")) + # Let's meet the expectation of finding the final executable in zephyr/zephyr.exe + add_custom_target(final_executable + ALL + COMMAND + ${CMAKE_COMMAND} -E copy + ${CMAKE_BINARY_DIR}/${DEFAULT_IMAGE}/zephyr/zephyr.exe + ${CMAKE_BINARY_DIR}/zephyr/zephyr.exe + DEPENDS ${DEFAULT_IMAGE} + ) +endif() diff --git a/samples/bluetooth/broadcast_audio_source/sysbuild.cmake b/samples/bluetooth/broadcast_audio_source/sysbuild.cmake index 2523aac8ea7..ed30d7f31f3 100644 --- a/samples/bluetooth/broadcast_audio_source/sysbuild.cmake +++ b/samples/bluetooth/broadcast_audio_source/sysbuild.cmake @@ -18,7 +18,27 @@ if(SB_CONFIG_NET_CORE_IMAGE_HCI_IPC) CACHE INTERNAL "" ) - native_simulator_set_child_images(${DEFAULT_IMAGE} ${NET_APP}) + # Let's build the net core library first + add_dependencies(${DEFAULT_IMAGE} ${NET_APP}) + + if("${BOARD}" STREQUAL "nrf5340bsim_nrf5340_cpuapp") + # For the simulated board, the application core build will produce the final executable + # for that, we give it the path to the netcore image + set(NET_LIBRARY_PATH ${CMAKE_BINARY_DIR}/${NET_APP}/zephyr/zephyr.elf) + set_property(TARGET ${DEFAULT_IMAGE} APPEND_STRING PROPERTY CONFIG + "CONFIG_NATIVE_SIMULATOR_EXTRA_IMAGE_PATHS=\"${NET_LIBRARY_PATH}\"\n" + ) + endif() endif() -native_simulator_set_final_executable(${DEFAULT_IMAGE}) +if(("${BOARD}" MATCHES "native") OR ("${BOARD}" MATCHES "bsim")) + # Let's meet the expectation of finding the final executable in zephyr/zephyr.exe + add_custom_target(final_executable + ALL + COMMAND + ${CMAKE_COMMAND} -E copy + ${CMAKE_BINARY_DIR}/${DEFAULT_IMAGE}/zephyr/zephyr.exe + ${CMAKE_BINARY_DIR}/zephyr/zephyr.exe + DEPENDS ${DEFAULT_IMAGE} + ) +endif() diff --git a/samples/bluetooth/unicast_audio_client/sysbuild.cmake b/samples/bluetooth/unicast_audio_client/sysbuild.cmake index 2523aac8ea7..ed30d7f31f3 100644 --- a/samples/bluetooth/unicast_audio_client/sysbuild.cmake +++ b/samples/bluetooth/unicast_audio_client/sysbuild.cmake @@ -18,7 +18,27 @@ if(SB_CONFIG_NET_CORE_IMAGE_HCI_IPC) CACHE INTERNAL "" ) - native_simulator_set_child_images(${DEFAULT_IMAGE} ${NET_APP}) + # Let's build the net core library first + add_dependencies(${DEFAULT_IMAGE} ${NET_APP}) + + if("${BOARD}" STREQUAL "nrf5340bsim_nrf5340_cpuapp") + # For the simulated board, the application core build will produce the final executable + # for that, we give it the path to the netcore image + set(NET_LIBRARY_PATH ${CMAKE_BINARY_DIR}/${NET_APP}/zephyr/zephyr.elf) + set_property(TARGET ${DEFAULT_IMAGE} APPEND_STRING PROPERTY CONFIG + "CONFIG_NATIVE_SIMULATOR_EXTRA_IMAGE_PATHS=\"${NET_LIBRARY_PATH}\"\n" + ) + endif() endif() -native_simulator_set_final_executable(${DEFAULT_IMAGE}) +if(("${BOARD}" MATCHES "native") OR ("${BOARD}" MATCHES "bsim")) + # Let's meet the expectation of finding the final executable in zephyr/zephyr.exe + add_custom_target(final_executable + ALL + COMMAND + ${CMAKE_COMMAND} -E copy + ${CMAKE_BINARY_DIR}/${DEFAULT_IMAGE}/zephyr/zephyr.exe + ${CMAKE_BINARY_DIR}/zephyr/zephyr.exe + DEPENDS ${DEFAULT_IMAGE} + ) +endif() diff --git a/samples/bluetooth/unicast_audio_server/sysbuild.cmake b/samples/bluetooth/unicast_audio_server/sysbuild.cmake index 2523aac8ea7..ed30d7f31f3 100644 --- a/samples/bluetooth/unicast_audio_server/sysbuild.cmake +++ b/samples/bluetooth/unicast_audio_server/sysbuild.cmake @@ -18,7 +18,27 @@ if(SB_CONFIG_NET_CORE_IMAGE_HCI_IPC) CACHE INTERNAL "" ) - native_simulator_set_child_images(${DEFAULT_IMAGE} ${NET_APP}) + # Let's build the net core library first + add_dependencies(${DEFAULT_IMAGE} ${NET_APP}) + + if("${BOARD}" STREQUAL "nrf5340bsim_nrf5340_cpuapp") + # For the simulated board, the application core build will produce the final executable + # for that, we give it the path to the netcore image + set(NET_LIBRARY_PATH ${CMAKE_BINARY_DIR}/${NET_APP}/zephyr/zephyr.elf) + set_property(TARGET ${DEFAULT_IMAGE} APPEND_STRING PROPERTY CONFIG + "CONFIG_NATIVE_SIMULATOR_EXTRA_IMAGE_PATHS=\"${NET_LIBRARY_PATH}\"\n" + ) + endif() endif() -native_simulator_set_final_executable(${DEFAULT_IMAGE}) +if(("${BOARD}" MATCHES "native") OR ("${BOARD}" MATCHES "bsim")) + # Let's meet the expectation of finding the final executable in zephyr/zephyr.exe + add_custom_target(final_executable + ALL + COMMAND + ${CMAKE_COMMAND} -E copy + ${CMAKE_BINARY_DIR}/${DEFAULT_IMAGE}/zephyr/zephyr.exe + ${CMAKE_BINARY_DIR}/zephyr/zephyr.exe + DEPENDS ${DEFAULT_IMAGE} + ) +endif() From db788afd42afbab7ecb7fda6eac68a3305782272 Mon Sep 17 00:00:00 2001 From: Robert Lubos Date: Tue, 6 Feb 2024 11:07:25 +0100 Subject: [PATCH 3641/3723] Revert "[nrf fromtree] sysbuild: Add extensions for native_simulator based targets" This reverts commit 2076afcd51b67a313fd5813bb74efe7ebe313c7e. Signed-off-by: Robert Lubos --- share/sysbuild/CMakeLists.txt | 7 +-- .../native_simulator_sb_extensions.cmake | 62 ------------------- 2 files changed, 2 insertions(+), 67 deletions(-) delete mode 100644 share/sysbuild/cmake/modules/native_simulator_sb_extensions.cmake diff --git a/share/sysbuild/CMakeLists.txt b/share/sysbuild/CMakeLists.txt index 8a15da9cef5..7bbfe138760 100644 --- a/share/sysbuild/CMakeLists.txt +++ b/share/sysbuild/CMakeLists.txt @@ -1,4 +1,4 @@ -# Copyright (c) 2023 Nordic Semiconductor +# Copyright (c) 2021-2023 Nordic Semiconductor # # SPDX-License-Identifier: Apache-2.0 @@ -18,10 +18,7 @@ set(APP_DIR ${APP_DIR} CACHE PATH "Main Application Source Directory") list(APPEND CMAKE_MODULE_PATH ${CMAKE_CURRENT_LIST_DIR}/cmake/modules) # List of Zephyr and sysbuild CMake modules we need for sysbuild. # Note: sysbuild_kconfig will internally load kconfig CMake module. -set(zephyr_modules extensions - sysbuild_extensions python west root zephyr_module boards shields - sysbuild_kconfig native_simulator_sb_extensions - ) +set(zephyr_modules extensions sysbuild_extensions python west root zephyr_module boards shields sysbuild_kconfig) find_package(Zephyr REQUIRED HINTS $ENV{ZEPHYR_BASE} COMPONENTS ${zephyr_modules}) diff --git a/share/sysbuild/cmake/modules/native_simulator_sb_extensions.cmake b/share/sysbuild/cmake/modules/native_simulator_sb_extensions.cmake deleted file mode 100644 index 3d888d1775e..00000000000 --- a/share/sysbuild/cmake/modules/native_simulator_sb_extensions.cmake +++ /dev/null @@ -1,62 +0,0 @@ -# Copyright (c) 2023 Nordic Semiconductor -# -# SPDX-License-Identifier: Apache-2.0 - -# Usage: -# native_simulator_set_final_executable() -# -# When building for a native_simulator based target (including bsim targets), -# this function adds an extra build target which will copy the executable produced by -# `` to the top level, as zephyr/zephyr.exe -# -# This final image is expected to have been set to assemble other dependent images into -# itself if necessary, by calling native_simulator_set_child_images() -# This will allow other tools, like twister, or the bsim test scripts, as well as users to find -# this final executable in the same place as for non-sysbuild builds. -# -function(native_simulator_set_final_executable final_image) - if(("${BOARD}" MATCHES "native") OR ("${BOARD}" MATCHES "bsim")) - add_custom_target(final_executable - ALL - COMMAND - ${CMAKE_COMMAND} -E copy - ${CMAKE_BINARY_DIR}/${final_image}/zephyr/zephyr.exe - ${CMAKE_BINARY_DIR}/zephyr/zephyr.exe - DEPENDS ${final_image} - ) - endif() -endfunction() - -# Usage: -# native_simulator_set_child_images( ) -# -# When building for a native_simulator based target (including bsim targets), -# this function sets a `` as dependencies of `` -# and configures the final image to assemble the child images into its final executable. -# -function(native_simulator_set_child_images final_image child_image) - if(("${BOARD}" MATCHES "native") OR ("${BOARD}" MATCHES "bsim")) - add_dependencies(${final_image} ${child_image}) - - set(CHILD_LIBRARY_PATH ${CMAKE_BINARY_DIR}/${child_image}/zephyr/zephyr.elf) - set_property(TARGET ${final_image} APPEND_STRING PROPERTY CONFIG - "CONFIG_NATIVE_SIMULATOR_EXTRA_IMAGE_PATHS=\"${CHILD_LIBRARY_PATH}\"\n" - ) - endif() -endfunction() - -# Usage: -# native_simulator_set_primary_mcu_index( [ ...]) -# -# Propagate the SB_CONFIG_NATIVE_SIMULATOR_PRIMARY_MCU_INDEX setting, -# if it is set, to each given image CONFIG_NATIVE_SIMULATOR_PRIMARY_MCU_INDEX -# -function(native_simulator_set_primary_mcu_index) - if (NOT ("${SB_CONFIG_NATIVE_SIMULATOR_PRIMARY_MCU_INDEX}" STREQUAL "")) - foreach(arg IN LISTS ARGV) - set_property(TARGET ${arg} APPEND_STRING PROPERTY CONFIG - "CONFIG_NATIVE_SIMULATOR_PRIMARY_MCU_INDEX=${SB_CONFIG_NATIVE_SIMULATOR_PRIMARY_MCU_INDEX}\n" - ) - endforeach() - endif() -endfunction() From ecd4c16312eab413dcfe5e5927674ad9c07d7e49 Mon Sep 17 00:00:00 2001 From: Robert Lubos Date: Tue, 6 Feb 2024 11:07:25 +0100 Subject: [PATCH 3642/3723] Revert "[nrf fromtree] tests: bsim: Bluetooth: Enable nrf5340bsim CIS ACL group test" This reverts commit cebd9529012a78d5d15738b91b2556bfddc1c0ed. Signed-off-by: Robert Lubos --- .../compile.nrf5340bsim_nrf5340_cpuapp.sh | 1 - tests/bsim/bluetooth/ll/cis/Kconfig.sysbuild | 14 -- tests/bsim/bluetooth/ll/cis/sysbuild.cmake | 47 ------- ...0_cpunet_iso_acl_group-bt_ll_sw_split.conf | 122 ------------------ 4 files changed, 184 deletions(-) delete mode 100644 tests/bsim/bluetooth/ll/cis/Kconfig.sysbuild delete mode 100644 tests/bsim/bluetooth/ll/cis/sysbuild.cmake delete mode 100644 tests/bsim/bluetooth/ll/cis/sysbuild/hci_ipc/nrf5340_cpunet_iso_acl_group-bt_ll_sw_split.conf diff --git a/tests/bsim/bluetooth/compile.nrf5340bsim_nrf5340_cpuapp.sh b/tests/bsim/bluetooth/compile.nrf5340bsim_nrf5340_cpuapp.sh index 65769185867..4f175540347 100755 --- a/tests/bsim/bluetooth/compile.nrf5340bsim_nrf5340_cpuapp.sh +++ b/tests/bsim/bluetooth/compile.nrf5340bsim_nrf5340_cpuapp.sh @@ -21,7 +21,6 @@ source ${ZEPHYR_BASE}/tests/bsim/compile.source app=tests/bsim/bluetooth/ll/conn conf_file=prj_split_privacy.conf sysbuild=1 compile app=tests/bsim/bluetooth/ll/bis sysbuild=1 compile -app=tests/bsim/bluetooth/ll/cis conf_overlay=overlay-acl_group.conf sysbuild=1 compile run_in_background ${ZEPHYR_BASE}/tests/bsim/bluetooth/audio_samples/compile.sh diff --git a/tests/bsim/bluetooth/ll/cis/Kconfig.sysbuild b/tests/bsim/bluetooth/ll/cis/Kconfig.sysbuild deleted file mode 100644 index 6c89fddc9f3..00000000000 --- a/tests/bsim/bluetooth/ll/cis/Kconfig.sysbuild +++ /dev/null @@ -1,14 +0,0 @@ -# Copyright 2023 Nordic Semiconductor ASA -# SPDX-License-Identifier: Apache-2.0 - -source "share/sysbuild/Kconfig" - -config NET_CORE_BOARD - string - default "nrf5340bsim_nrf5340_cpunet" if $(BOARD) = "nrf5340bsim_nrf5340_cpuapp" - -config NATIVE_SIMULATOR_PRIMARY_MCU_INDEX - int - # Let's pass the test arguments to the application MCU test - # otherwise by default they would have gone to the net core. - default 0 if $(BOARD) = "nrf5340bsim_nrf5340_cpuapp" diff --git a/tests/bsim/bluetooth/ll/cis/sysbuild.cmake b/tests/bsim/bluetooth/ll/cis/sysbuild.cmake deleted file mode 100644 index 495c3f4a20d..00000000000 --- a/tests/bsim/bluetooth/ll/cis/sysbuild.cmake +++ /dev/null @@ -1,47 +0,0 @@ -# Copyright (c) 2023 Nordic Semiconductor ASA -# SPDX-License-Identifier: Apache-2.0 - -if(NOT("${SB_CONFIG_NET_CORE_BOARD}" STREQUAL "")) - set(NET_APP hci_ipc) - set(NET_APP_SRC_DIR ${ZEPHYR_BASE}/samples/bluetooth/${NET_APP}) - - ExternalZephyrProject_Add( - APPLICATION ${NET_APP} - SOURCE_DIR ${NET_APP_SRC_DIR} - BOARD ${SB_CONFIG_NET_CORE_BOARD} - ) - - set(${NET_APP}_CONF_FILE - ${APP_DIR}/sysbuild/hci_ipc/nrf5340_cpunet_iso_acl_group-bt_ll_sw_split.conf - CACHE INTERNAL "" - ) - - # For the simulated board, the application core build will produce the final executable - # for that, we give it the path to the netcore image - set(NET_LIBRARY_PATH ${CMAKE_BINARY_DIR}/${NET_APP}/zephyr/zephyr.elf) - set_property(TARGET ${DEFAULT_IMAGE} APPEND_STRING PROPERTY CONFIG - "CONFIG_NATIVE_SIMULATOR_EXTRA_IMAGE_PATHS=\"${NET_LIBRARY_PATH}\"\n" - ) - - if (NOT ("${SB_CONFIG_NATIVE_SIMULATOR_PRIMARY_MCU_INDEX}" STREQUAL "")) - set_property(TARGET ${NET_APP} APPEND_STRING PROPERTY CONFIG - "CONFIG_NATIVE_SIMULATOR_PRIMARY_MCU_INDEX=${SB_CONFIG_NATIVE_SIMULATOR_PRIMARY_MCU_INDEX}\n" - ) - set_property(TARGET ${DEFAULT_IMAGE} APPEND_STRING PROPERTY CONFIG - "CONFIG_NATIVE_SIMULATOR_PRIMARY_MCU_INDEX=${SB_CONFIG_NATIVE_SIMULATOR_PRIMARY_MCU_INDEX}\n" - ) - endif() - - # Let's build the net core library first - add_dependencies(${DEFAULT_IMAGE} ${NET_APP}) -endif() - -# Let's meet the expectation of finding the final executable in zephyr/zephyr.exe -add_custom_target(final_executable - ALL - COMMAND - ${CMAKE_COMMAND} -E copy - ${CMAKE_BINARY_DIR}/${DEFAULT_IMAGE}/zephyr/zephyr.exe - ${CMAKE_BINARY_DIR}/zephyr/zephyr.exe - DEPENDS ${DEFAULT_IMAGE} -) diff --git a/tests/bsim/bluetooth/ll/cis/sysbuild/hci_ipc/nrf5340_cpunet_iso_acl_group-bt_ll_sw_split.conf b/tests/bsim/bluetooth/ll/cis/sysbuild/hci_ipc/nrf5340_cpunet_iso_acl_group-bt_ll_sw_split.conf deleted file mode 100644 index a3c8f43c71f..00000000000 --- a/tests/bsim/bluetooth/ll/cis/sysbuild/hci_ipc/nrf5340_cpunet_iso_acl_group-bt_ll_sw_split.conf +++ /dev/null @@ -1,122 +0,0 @@ -CONFIG_IPC_SERVICE=y -CONFIG_MBOX=y - -CONFIG_ISR_STACK_SIZE=1024 -CONFIG_IDLE_STACK_SIZE=256 -CONFIG_MAIN_STACK_SIZE=512 -CONFIG_SYSTEM_WORKQUEUE_STACK_SIZE=512 -CONFIG_IPC_SERVICE_BACKEND_RPMSG_WQ_STACK_SIZE=512 -CONFIG_HEAP_MEM_POOL_SIZE=8192 -CONFIG_CBPRINTF_REDUCED_INTEGRAL=y - -CONFIG_BT=y -CONFIG_BT_HCI_RAW=y -CONFIG_BT_HCI_RAW_RESERVE=1 -CONFIG_BT_MAX_CONN=4 - -# Workaround: Unable to allocate command buffer when using K_NO_WAIT since -# Host number of completed commands does not follow normal flow control. -CONFIG_BT_BUF_CMD_TX_COUNT=10 - -CONFIG_BT_BUF_EVT_RX_COUNT=16 - -CONFIG_BT_BUF_EVT_RX_SIZE=255 -CONFIG_BT_BUF_ACL_RX_SIZE=255 -CONFIG_BT_BUF_ACL_TX_SIZE=251 -CONFIG_BT_BUF_CMD_TX_SIZE=255 - -# Tx/Rx Thread Stack Sizes -CONFIG_BT_HCI_TX_STACK_SIZE_WITH_PROMPT=y -CONFIG_BT_HCI_TX_STACK_SIZE=1152 -CONFIG_BT_RX_STACK_SIZE=640 -CONFIG_BT_CTLR_RX_PRIO_STACK_SIZE=448 - -# Host features -CONFIG_BT_EXT_ADV=y -CONFIG_BT_PER_ADV=y -CONFIG_BT_PER_ADV_SYNC=y -CONFIG_BT_PER_ADV_SYNC_MAX=2 - -# Broadcast and Connected ISO -CONFIG_BT_ISO_BROADCASTER=y -CONFIG_BT_ISO_SYNC_RECEIVER=y -CONFIG_BT_ISO_CENTRAL=y -CONFIG_BT_ISO_PERIPHERAL=y - -# ISO Streams -CONFIG_BT_ISO_MAX_CHAN=4 - -# Controller -CONFIG_BT_LL_SW_SPLIT=y -CONFIG_BT_CTLR_ASSERT_HANDLER=y -CONFIG_BT_CTLR_DTM_HCI=y - -# Rx ACL and Adv Reports -CONFIG_BT_CTLR_RX_BUFFERS=9 -CONFIG_BT_CTLR_DATA_LENGTH_MAX=251 - -# Coded PHY support -CONFIG_BT_CTLR_PHY_CODED=n - -# Advertising Sets and Extended Scanning -CONFIG_BT_CTLR_ADV_EXT=y -CONFIG_BT_CTLR_ADV_SET=3 -CONFIG_BT_CTLR_ADV_DATA_LEN_MAX=191 -CONFIG_BT_CTLR_SCAN_DATA_LEN_MAX=1650 - -CONFIG_BT_CTLR_ADVANCED_FEATURES=y -CONFIG_BT_CTLR_ADV_AUX_SET=3 -CONFIG_BT_CTLR_ADV_AUX_PDU_BACK2BACK=y -CONFIG_BT_CTLR_ADV_SYNC_SET=3 -CONFIG_BT_CTLR_ADV_SYNC_PDU_BACK2BACK=y -CONFIG_BT_CTLR_ADV_DATA_BUF_MAX=6 - -# Increase the below to receive interleaved advertising chains -CONFIG_BT_CTLR_SCAN_AUX_SET=1 - -CONFIG_BT_CTLR_ADV_RESERVE_MAX=n -CONFIG_BT_CTLR_CENTRAL_RESERVE_MAX=n -# CONFIG_BT_CTLR_CENTRAL_SPACING=10000 -CONFIG_BT_CTLR_CENTRAL_SPACING=0 -CONFIG_BT_CTLR_SLOT_RESERVATION_UPDATE=n -CONFIG_BT_CTLR_SCAN_UNRESERVED=n -CONFIG_BT_TICKER_NEXT_SLOT_GET_MATCH=y -CONFIG_BT_TICKER_EXT=y -CONFIG_BT_TICKER_EXT_SLOT_WINDOW_YIELD=y - -# Control Procedure -CONFIG_BT_CTLR_LLCP_LOCAL_PROC_CTX_BUF_NUM=9 - -# ISO Broadcaster Controller -CONFIG_BT_CTLR_ADV_EXT=y -CONFIG_BT_CTLR_ADV_PERIODIC=y -CONFIG_BT_CTLR_ADV_ISO=y -CONFIG_BT_CTLR_ADV_ISO_PDU_LEN_MAX=251 -CONFIG_BT_CTLR_ADV_ISO_STREAM_MAX=2 - -# ISO Receive Controller -CONFIG_BT_CTLR_ADV_EXT=y -CONFIG_BT_CTLR_SYNC_PERIODIC=y -CONFIG_BT_CTLR_SYNC_ISO=y -CONFIG_BT_CTLR_SYNC_ISO_PDU_LEN_MAX=251 -CONFIG_BT_CTLR_SYNC_ISO_STREAM_MAX=2 - -# ISO Connection Oriented -CONFIG_BT_CTLR_CENTRAL_ISO=y -CONFIG_BT_CTLR_PERIPHERAL_ISO=y -CONFIG_BT_CTLR_CONN_ISO_SDU_LEN_MAX=251 -CONFIG_BT_CTLR_CONN_ISO_PDU_LEN_MAX=251 -CONFIG_BT_CTLR_CONN_ISO_STREAMS=4 -CONFIG_BT_CTLR_CONN_ISO_STREAMS_PER_GROUP=4 - -# ISO Transmissions -CONFIG_BT_CTLR_ISO_TX_BUFFERS=18 -CONFIG_BT_CTLR_ISO_TX_BUFFER_SIZE=251 -CONFIG_BT_CTLR_ISOAL_SOURCES=4 - -# ISO Receptions -CONFIG_BT_CTLR_ISO_RX_BUFFERS=8 -CONFIG_BT_CTLR_ISOAL_SINKS=4 - -# Tx Power Dynamic Control -CONFIG_BT_CTLR_TX_PWR_DYNAMIC_CONTROL=y From 533d84c722ea6601c2ab10f425f5eff295a975c9 Mon Sep 17 00:00:00 2001 From: Robert Lubos Date: Tue, 6 Feb 2024 11:07:25 +0100 Subject: [PATCH 3643/3723] Revert "[nrf fromtree] samples/bluetooth: sysbuild: Add Kconfig setting for HCI IPC inclusion" This reverts commit 6da4c914b11a8a5c0441ee2c50e9450908ca9a51. Signed-off-by: Robert Lubos --- samples/bluetooth/broadcast_audio_source/Kconfig.sysbuild | 5 ----- samples/bluetooth/broadcast_audio_source/sysbuild.cmake | 2 +- samples/bluetooth/unicast_audio_client/Kconfig.sysbuild | 5 ----- samples/bluetooth/unicast_audio_client/sysbuild.cmake | 2 +- samples/bluetooth/unicast_audio_server/Kconfig.sysbuild | 5 ----- samples/bluetooth/unicast_audio_server/sysbuild.cmake | 2 +- 6 files changed, 3 insertions(+), 18 deletions(-) diff --git a/samples/bluetooth/broadcast_audio_source/Kconfig.sysbuild b/samples/bluetooth/broadcast_audio_source/Kconfig.sysbuild index f434010f81d..37a6b66c7f4 100644 --- a/samples/bluetooth/broadcast_audio_source/Kconfig.sysbuild +++ b/samples/bluetooth/broadcast_audio_source/Kconfig.sysbuild @@ -8,8 +8,3 @@ config NET_CORE_BOARD default "nrf5340dk_nrf5340_cpunet" if $(BOARD) = "nrf5340dk_nrf5340_cpuapp" default "nrf5340_audio_dk_nrf5340_cpunet" if $(BOARD) = "nrf5340_audio_dk_nrf5340_cpuapp" default "nrf5340bsim_nrf5340_cpunet" if $(BOARD) = "nrf5340bsim_nrf5340_cpuapp" - -config NET_CORE_IMAGE_HCI_IPC - bool "HCI IPC image on network core" - default y - depends on NET_CORE_BOARD != "" diff --git a/samples/bluetooth/broadcast_audio_source/sysbuild.cmake b/samples/bluetooth/broadcast_audio_source/sysbuild.cmake index ed30d7f31f3..c150913cc55 100644 --- a/samples/bluetooth/broadcast_audio_source/sysbuild.cmake +++ b/samples/bluetooth/broadcast_audio_source/sysbuild.cmake @@ -1,7 +1,7 @@ # Copyright (c) 2023 Nordic Semiconductor ASA # SPDX-License-Identifier: Apache-2.0 -if(SB_CONFIG_NET_CORE_IMAGE_HCI_IPC) +if(NOT("${SB_CONFIG_NET_CORE_BOARD}" STREQUAL "")) # For builds in the nrf5340, we build the netcore image with the controller set(NET_APP hci_ipc) diff --git a/samples/bluetooth/unicast_audio_client/Kconfig.sysbuild b/samples/bluetooth/unicast_audio_client/Kconfig.sysbuild index f434010f81d..37a6b66c7f4 100644 --- a/samples/bluetooth/unicast_audio_client/Kconfig.sysbuild +++ b/samples/bluetooth/unicast_audio_client/Kconfig.sysbuild @@ -8,8 +8,3 @@ config NET_CORE_BOARD default "nrf5340dk_nrf5340_cpunet" if $(BOARD) = "nrf5340dk_nrf5340_cpuapp" default "nrf5340_audio_dk_nrf5340_cpunet" if $(BOARD) = "nrf5340_audio_dk_nrf5340_cpuapp" default "nrf5340bsim_nrf5340_cpunet" if $(BOARD) = "nrf5340bsim_nrf5340_cpuapp" - -config NET_CORE_IMAGE_HCI_IPC - bool "HCI IPC image on network core" - default y - depends on NET_CORE_BOARD != "" diff --git a/samples/bluetooth/unicast_audio_client/sysbuild.cmake b/samples/bluetooth/unicast_audio_client/sysbuild.cmake index ed30d7f31f3..c150913cc55 100644 --- a/samples/bluetooth/unicast_audio_client/sysbuild.cmake +++ b/samples/bluetooth/unicast_audio_client/sysbuild.cmake @@ -1,7 +1,7 @@ # Copyright (c) 2023 Nordic Semiconductor ASA # SPDX-License-Identifier: Apache-2.0 -if(SB_CONFIG_NET_CORE_IMAGE_HCI_IPC) +if(NOT("${SB_CONFIG_NET_CORE_BOARD}" STREQUAL "")) # For builds in the nrf5340, we build the netcore image with the controller set(NET_APP hci_ipc) diff --git a/samples/bluetooth/unicast_audio_server/Kconfig.sysbuild b/samples/bluetooth/unicast_audio_server/Kconfig.sysbuild index f434010f81d..37a6b66c7f4 100644 --- a/samples/bluetooth/unicast_audio_server/Kconfig.sysbuild +++ b/samples/bluetooth/unicast_audio_server/Kconfig.sysbuild @@ -8,8 +8,3 @@ config NET_CORE_BOARD default "nrf5340dk_nrf5340_cpunet" if $(BOARD) = "nrf5340dk_nrf5340_cpuapp" default "nrf5340_audio_dk_nrf5340_cpunet" if $(BOARD) = "nrf5340_audio_dk_nrf5340_cpuapp" default "nrf5340bsim_nrf5340_cpunet" if $(BOARD) = "nrf5340bsim_nrf5340_cpuapp" - -config NET_CORE_IMAGE_HCI_IPC - bool "HCI IPC image on network core" - default y - depends on NET_CORE_BOARD != "" diff --git a/samples/bluetooth/unicast_audio_server/sysbuild.cmake b/samples/bluetooth/unicast_audio_server/sysbuild.cmake index ed30d7f31f3..c150913cc55 100644 --- a/samples/bluetooth/unicast_audio_server/sysbuild.cmake +++ b/samples/bluetooth/unicast_audio_server/sysbuild.cmake @@ -1,7 +1,7 @@ # Copyright (c) 2023 Nordic Semiconductor ASA # SPDX-License-Identifier: Apache-2.0 -if(SB_CONFIG_NET_CORE_IMAGE_HCI_IPC) +if(NOT("${SB_CONFIG_NET_CORE_BOARD}" STREQUAL "")) # For builds in the nrf5340, we build the netcore image with the controller set(NET_APP hci_ipc) From c4924dcbac80268ace97af2d901343922b1fc228 Mon Sep 17 00:00:00 2001 From: Robert Lubos Date: Tue, 6 Feb 2024 11:07:26 +0100 Subject: [PATCH 3644/3723] Revert "[nrf fromlist] logging: Fix using simplified message creation mode" This reverts commit 6f609a096e5ecc3ac2a993de4b2bbc33c4fe3a98. Signed-off-by: Robert Lubos --- include/zephyr/logging/log_msg.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/include/zephyr/logging/log_msg.h b/include/zephyr/logging/log_msg.h index 39cbf1cedbc..fabc7a16b0c 100644 --- a/include/zephyr/logging/log_msg.h +++ b/include/zephyr/logging/log_msg.h @@ -241,7 +241,7 @@ enum z_log_msg_mode { #define LOG_MSG_SIMPLE_ARG_TYPE_CHECK_0(fmt) 1 #define LOG_MSG_SIMPLE_ARG_TYPE_CHECK_1(fmt, arg) Z_CBPRINTF_IS_WORD_NUM(arg) #define LOG_MSG_SIMPLE_ARG_TYPE_CHECK_2(fmt, arg0, arg1) \ - Z_CBPRINTF_IS_WORD_NUM(arg0) && Z_CBPRINTF_IS_WORD_NUM(arg1) + Z_CBPRINTF_IS_WORD_NUM(arg0) || Z_CBPRINTF_IS_WORD_NUM(arg1) /** brief Determine if string arguments types allow to use simplified message creation mode. * From 55ab9f6f874a2d89812d72e638db3f545ace5809 Mon Sep 17 00:00:00 2001 From: Robert Lubos Date: Tue, 6 Feb 2024 11:07:26 +0100 Subject: [PATCH 3645/3723] Revert "[nrf fromlist] drivers: usb: nrf_usbd_common: Remove unneeded assertion" This reverts commit 23f410daa5232429398b95350a82c5368b4d32eb. Signed-off-by: Robert Lubos --- drivers/usb/common/nrf_usbd_common/nrf_usbd_common.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/drivers/usb/common/nrf_usbd_common/nrf_usbd_common.c b/drivers/usb/common/nrf_usbd_common/nrf_usbd_common.c index 3db193ee2f0..9045e1ded70 100644 --- a/drivers/usb/common/nrf_usbd_common/nrf_usbd_common.c +++ b/drivers/usb/common/nrf_usbd_common/nrf_usbd_common.c @@ -376,6 +376,8 @@ static bool nrf_usbd_common_feeder(nrf_usbd_common_ep_transfer_t *p_next, nrf_usbd_common_transfer_t *p_transfer, size_t ep_size) { + __ASSERT_NO_MSG(nrfx_is_in_ram(p_transfer->p_data.tx)); + size_t tx_size = p_transfer->size; if (tx_size > ep_size) { From dd739b59ed8dacce9abd07f6a9d2abf1afe72470 Mon Sep 17 00:00:00 2001 From: Robert Lubos Date: Tue, 6 Feb 2024 11:07:26 +0100 Subject: [PATCH 3646/3723] Revert "[nrf fromtree] soc: arm: nrf52: Configurable EGU instance for anomaly 109 workaround" This reverts commit 7086c624dbd5fd627891e1a7ee683a182370657f. Signed-off-by: Robert Lubos --- modules/hal_nordic/nrfx/nrfx_config.h | 2 -- soc/arm/nordic_nrf/nrf52/Kconfig.soc | 8 -------- 2 files changed, 10 deletions(-) diff --git a/modules/hal_nordic/nrfx/nrfx_config.h b/modules/hal_nordic/nrfx/nrfx_config.h index b5b09b96078..aaf31751004 100644 --- a/modules/hal_nordic/nrfx/nrfx_config.h +++ b/modules/hal_nordic/nrfx/nrfx_config.h @@ -586,8 +586,6 @@ #define NRFX_SPIS_NRF52_ANOMALY_109_WORKAROUND_ENABLED 1 #define NRFX_TWIM_NRF52_ANOMALY_109_WORKAROUND_ENABLED 1 #define NRFX_PWM_NRF52_ANOMALY_109_WORKAROUND_ENABLED 1 -#define NRFX_PWM_NRF52_ANOMALY_109_EGU_INSTANCE \ - CONFIG_NRF52_ANOMALY_109_WORKAROUND_EGU_INSTANCE #endif #if defined(CONFIG_SOC_SERIES_BSIM_NRFXX) diff --git a/soc/arm/nordic_nrf/nrf52/Kconfig.soc b/soc/arm/nordic_nrf/nrf52/Kconfig.soc index de6a16129d3..517b4ce2baa 100644 --- a/soc/arm/nordic_nrf/nrf52/Kconfig.soc +++ b/soc/arm/nordic_nrf/nrf52/Kconfig.soc @@ -147,12 +147,4 @@ config NRF52_ANOMALY_109_WORKAROUND 64MHz clock at the same time as the peripheral that is using DMA is started. This anomaly applies to IC revisions up to "3", the most recent one. -config NRF52_ANOMALY_109_WORKAROUND_EGU_INSTANCE - int "Anomaly 109 workaround EGU instance" - depends on NRF52_ANOMALY_109_WORKAROUND - range 0 5 - default 5 - help - EGU instance used by the nRF52 Anomaly 109 workaround for PWM. - endif # SOC_SERIES_NRF52X From 258642ef1262c9b24eaffdd0dfabdaca4271a348 Mon Sep 17 00:00:00 2001 From: Robert Lubos Date: Tue, 6 Feb 2024 11:07:26 +0100 Subject: [PATCH 3647/3723] Revert "[nrf fromtree] sysbuild: introduce Kconfig setting for controlling HCI IPC inclusion" This reverts commit 7513bd8b9de3664eea8dc02121fa083dbae9e188. Signed-off-by: Robert Lubos --- samples/bluetooth/broadcast_audio_sink/Kconfig.sysbuild | 5 ----- samples/bluetooth/broadcast_audio_sink/sysbuild.cmake | 2 +- 2 files changed, 1 insertion(+), 6 deletions(-) diff --git a/samples/bluetooth/broadcast_audio_sink/Kconfig.sysbuild b/samples/bluetooth/broadcast_audio_sink/Kconfig.sysbuild index f434010f81d..37a6b66c7f4 100644 --- a/samples/bluetooth/broadcast_audio_sink/Kconfig.sysbuild +++ b/samples/bluetooth/broadcast_audio_sink/Kconfig.sysbuild @@ -8,8 +8,3 @@ config NET_CORE_BOARD default "nrf5340dk_nrf5340_cpunet" if $(BOARD) = "nrf5340dk_nrf5340_cpuapp" default "nrf5340_audio_dk_nrf5340_cpunet" if $(BOARD) = "nrf5340_audio_dk_nrf5340_cpuapp" default "nrf5340bsim_nrf5340_cpunet" if $(BOARD) = "nrf5340bsim_nrf5340_cpuapp" - -config NET_CORE_IMAGE_HCI_IPC - bool "HCI IPC image on network core" - default y - depends on NET_CORE_BOARD != "" diff --git a/samples/bluetooth/broadcast_audio_sink/sysbuild.cmake b/samples/bluetooth/broadcast_audio_sink/sysbuild.cmake index ed30d7f31f3..c150913cc55 100644 --- a/samples/bluetooth/broadcast_audio_sink/sysbuild.cmake +++ b/samples/bluetooth/broadcast_audio_sink/sysbuild.cmake @@ -1,7 +1,7 @@ # Copyright (c) 2023 Nordic Semiconductor ASA # SPDX-License-Identifier: Apache-2.0 -if(SB_CONFIG_NET_CORE_IMAGE_HCI_IPC) +if(NOT("${SB_CONFIG_NET_CORE_BOARD}" STREQUAL "")) # For builds in the nrf5340, we build the netcore image with the controller set(NET_APP hci_ipc) From 6bd67538cca32a55c286cc51b9d0bcd763fa7d35 Mon Sep 17 00:00:00 2001 From: Robert Lubos Date: Tue, 6 Feb 2024 11:07:26 +0100 Subject: [PATCH 3648/3723] Revert "[nrf fromlist] drivers: ieee802154: nrf5: Fix missed variable rename" This reverts commit 7300a52ddc328f6ba9b8d081a2224143f74c869d. Signed-off-by: Robert Lubos --- drivers/ieee802154/ieee802154_nrf5.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/ieee802154/ieee802154_nrf5.c b/drivers/ieee802154/ieee802154_nrf5.c index df01f530abf..defbc90cd07 100644 --- a/drivers/ieee802154/ieee802154_nrf5.c +++ b/drivers/ieee802154/ieee802154_nrf5.c @@ -933,9 +933,9 @@ static int nrf5_configure(const struct device *dev, #if defined(CONFIG_NRF_802154_SER_HOST) net_time_t period_ns = nrf5_data.csl_period * NSEC_PER_TEN_SYMBOLS; - bool changed = (config->expected_rx_time - nrf5_data.csl_rx_time) % period_ns; + bool changed = (config->csl_rx_time - nrf5_data.csl_rx_time) % period_ns; - nrf5_data.csl_rx_time = config->expected_rx_time; + nrf5_data.csl_rx_time = config->csl_rx_time; if (changed) #endif /* CONFIG_NRF_802154_SER_HOST */ From ca0af470cc494653bec20de12a7278be1e90be3e Mon Sep 17 00:00:00 2001 From: Robert Lubos Date: Tue, 6 Feb 2024 11:07:27 +0100 Subject: [PATCH 3649/3723] Revert "[nrf fromlist] wifi: shell: Add a shell command to list stations" This reverts commit b5c01369df121c4a9ee23f4c9c51ccdf4edb16d1. Signed-off-by: Robert Lubos --- subsys/net/l2/wifi/Kconfig | 8 --- subsys/net/l2/wifi/wifi_shell.c | 90 --------------------------------- 2 files changed, 98 deletions(-) diff --git a/subsys/net/l2/wifi/Kconfig b/subsys/net/l2/wifi/Kconfig index 2816be56d74..134448aa57f 100644 --- a/subsys/net/l2/wifi/Kconfig +++ b/subsys/net/l2/wifi/Kconfig @@ -64,14 +64,6 @@ config WIFI_MGMT_SCAN_CHAN_MAX_MANUAL There are approximately 100 channels allocated across the three supported bands. The default of 3 allows the 3 most common channels (2.4GHz: 1, 6, 11) to be specified. -config WIFI_SHELL_MAX_AP_STA - int "Maximum number of APs and STAs that can be managed in Wi-Fi shell" - range 1 5 - default 1 - help - This option defines the maximum number of APs and STAs that can be managed - in Wi-Fi shell. - config WIFI_NM bool "Wi-Fi Network manager support" help diff --git a/subsys/net/l2/wifi/wifi_shell.c b/subsys/net/l2/wifi/wifi_shell.c index 1ee94304781..045fbed197e 100644 --- a/subsys/net/l2/wifi/wifi_shell.c +++ b/subsys/net/l2/wifi/wifi_shell.c @@ -24,7 +24,6 @@ LOG_MODULE_REGISTER(net_wifi_shell, LOG_LEVEL_INF); #include #include #include -#include #include "net_private.h" @@ -65,13 +64,6 @@ static uint32_t scan_result; static struct net_mgmt_event_callback wifi_shell_mgmt_cb; -static K_MUTEX_DEFINE(wifi_ap_sta_list_lock); -struct wifi_ap_sta_node { - bool valid; - struct wifi_ap_sta_info sta_info; -}; -static struct wifi_ap_sta_node sta_list[CONFIG_WIFI_SHELL_MAX_AP_STA]; - #define print(sh, level, fmt, ...) \ do { \ if (sh) { \ @@ -336,10 +328,6 @@ static void handle_wifi_ap_disable_result(struct net_mgmt_event_callback *cb) } else { print(context.sh, SHELL_NORMAL, "AP disabled\n"); } - - k_mutex_lock(&wifi_ap_sta_list_lock, K_FOREVER); - memset(&sta_list, 0, sizeof(sta_list)); - k_mutex_unlock(&wifi_ap_sta_list_lock); } static void handle_wifi_ap_sta_connected(struct net_mgmt_event_callback *cb) @@ -347,25 +335,10 @@ static void handle_wifi_ap_sta_connected(struct net_mgmt_event_callback *cb) const struct wifi_ap_sta_info *sta_info = (const struct wifi_ap_sta_info *)cb->info; uint8_t mac_string_buf[sizeof("xx:xx:xx:xx:xx:xx")]; - int i; print(context.sh, SHELL_NORMAL, "Station connected: %s\n", net_sprint_ll_addr_buf(sta_info->mac, WIFI_MAC_ADDR_LEN, mac_string_buf, sizeof(mac_string_buf))); - - k_mutex_lock(&wifi_ap_sta_list_lock, K_FOREVER); - for (i = 0; i < CONFIG_WIFI_SHELL_MAX_AP_STA; i++) { - if (!sta_list[i].valid) { - sta_list[i].sta_info = *sta_info; - sta_list[i].valid = true; - break; - } - } - if (i == CONFIG_WIFI_SHELL_MAX_AP_STA) { - print(context.sh, SHELL_WARNING, "No space to store station info: " - "Increase CONFIG_WIFI_SHELL_MAX_AP_STA\n"); - } - k_mutex_unlock(&wifi_ap_sta_list_lock); } static void handle_wifi_ap_sta_disconnected(struct net_mgmt_event_callback *cb) @@ -377,20 +350,6 @@ static void handle_wifi_ap_sta_disconnected(struct net_mgmt_event_callback *cb) print(context.sh, SHELL_NORMAL, "Station disconnected: %s\n", net_sprint_ll_addr_buf(sta_info->mac, WIFI_MAC_ADDR_LEN, mac_string_buf, sizeof(mac_string_buf))); - - k_mutex_lock(&wifi_ap_sta_list_lock, K_FOREVER); - for (int i = 0; i < CONFIG_WIFI_SHELL_MAX_AP_STA; i++) { - if (!sta_list[i].valid) { - continue; - } - - if (!memcmp(sta_list[i].sta_info.mac, sta_info->mac, - WIFI_MAC_ADDR_LEN)) { - sta_list[i].valid = false; - break; - } - } - k_mutex_unlock(&wifi_ap_sta_list_lock); } static void wifi_mgmt_event_handler(struct net_mgmt_event_callback *cb, @@ -1210,8 +1169,6 @@ static int cmd_wifi_ap_enable(const struct shell *sh, size_t argc, context.sh = sh; - k_mutex_init(&wifi_ap_sta_list_lock); - ret = net_mgmt(NET_REQUEST_WIFI_AP_ENABLE, iface, &cnx_params, sizeof(struct wifi_connect_req_params)); if (ret) { @@ -1240,49 +1197,6 @@ static int cmd_wifi_ap_disable(const struct shell *sh, size_t argc, return 0; } -static int cmd_wifi_ap_stations(const struct shell *sh, size_t argc, - char *argv[]) -{ - size_t id = 1; - - ARG_UNUSED(argv); - ARG_UNUSED(argc); - - shell_fprintf(sh, SHELL_NORMAL, "AP stations:\n"); - shell_fprintf(sh, SHELL_NORMAL, "============\n"); - - k_mutex_lock(&wifi_ap_sta_list_lock, K_FOREVER); - for (int i = 0; i < CONFIG_WIFI_SHELL_MAX_AP_STA; i++) { - struct wifi_ap_sta_info *sta; - uint8_t mac_string_buf[sizeof("xx:xx:xx:xx:xx:xx")]; - - if (!sta_list[i].valid) { - continue; - } - - sta = &sta_list[i].sta_info; - - shell_fprintf(sh, SHELL_NORMAL, "Station %zu:\n", id++); - shell_fprintf(sh, SHELL_NORMAL, "==========\n"); - shell_fprintf(sh, SHELL_NORMAL, "MAC: %s\n", - net_sprint_ll_addr_buf(sta->mac, - WIFI_MAC_ADDR_LEN, - mac_string_buf, - sizeof(mac_string_buf))); - shell_fprintf(sh, SHELL_NORMAL, "Link mode: %s\n", - wifi_link_mode_txt(sta->link_mode)); - shell_fprintf(sh, SHELL_NORMAL, "TWT: %s\n", - sta->twt_capable ? "Supported" : "Not supported"); - } - - if (id == 1) { - shell_fprintf(sh, SHELL_NORMAL, "No stations connected\n"); - } - k_mutex_unlock(&wifi_ap_sta_list_lock); - - return 0; -} - static int cmd_wifi_reg_domain(const struct shell *sh, size_t argc, char *argv[]) @@ -1761,10 +1675,6 @@ SHELL_STATIC_SUBCMD_SET_CREATE(wifi_cmd_ap, ": 0:Disable, 1:Optional, 2:Required.\n", cmd_wifi_ap_enable, 2, 4), - SHELL_CMD_ARG(stations, NULL, - "List stations connected to the AP", - cmd_wifi_ap_stations, - 1, 0), SHELL_SUBCMD_SET_END ); From f3e24332c2a3f45dc39a3d2817a8a055cc37fc2b Mon Sep 17 00:00:00 2001 From: Robert Lubos Date: Tue, 6 Feb 2024 11:07:27 +0100 Subject: [PATCH 3650/3723] Revert "[nrf fromlist] wifi: ap: Add client side events" This reverts commit 9a5a739cde1ed10fab5a0c989b991390d0412236. Signed-off-by: Robert Lubos --- include/zephyr/net/wifi_mgmt.h | 38 --------------------------------- subsys/net/l2/wifi/wifi_mgmt.c | 16 -------------- subsys/net/l2/wifi/wifi_shell.c | 32 +-------------------------- 3 files changed, 1 insertion(+), 85 deletions(-) diff --git a/include/zephyr/net/wifi_mgmt.h b/include/zephyr/net/wifi_mgmt.h index 78800f451e7..0897bdd5715 100644 --- a/include/zephyr/net/wifi_mgmt.h +++ b/include/zephyr/net/wifi_mgmt.h @@ -184,10 +184,6 @@ enum net_event_wifi_cmd { NET_EVENT_WIFI_CMD_AP_ENABLE_RESULT, /** AP mode disable result */ NET_EVENT_WIFI_CMD_AP_DISABLE_RESULT, - /** STA connected to AP */ - NET_EVENT_WIFI_CMD_AP_STA_CONNECTED, - /** STA disconnected from AP */ - NET_EVENT_WIFI_CMD_AP_STA_DISCONNECTED, }; #define NET_EVENT_WIFI_SCAN_RESULT \ @@ -223,12 +219,6 @@ enum net_event_wifi_cmd { #define NET_EVENT_WIFI_AP_DISABLE_RESULT \ (_NET_WIFI_EVENT | NET_EVENT_WIFI_CMD_AP_DISABLE_RESULT) -#define NET_EVENT_WIFI_AP_STA_CONNECTED \ - (_NET_WIFI_EVENT | NET_EVENT_WIFI_CMD_AP_STA_CONNECTED) - -#define NET_EVENT_WIFI_AP_STA_DISCONNECTED \ - (_NET_WIFI_EVENT | NET_EVENT_WIFI_CMD_AP_STA_DISCONNECTED) - /** * @brief Wi-Fi structure to uniquely identify a band-channel pair */ @@ -578,18 +568,6 @@ struct wifi_raw_scan_result { }; #endif /* CONFIG_WIFI_MGMT_RAW_SCAN_RESULTS */ -/** AP mode - connected STA details */ -struct wifi_ap_sta_info { - /** Link mode, see enum wifi_link_mode */ - enum wifi_link_mode link_mode; - /** MAC address */ - uint8_t mac[WIFI_MAC_ADDR_LEN]; - /** MAC address length */ - uint8_t mac_length; - /** is TWT capable ? */ - bool twt_capable; -}; - /* for use in max info size calculations */ union wifi_mgmt_events { struct wifi_scan_result scan_result; @@ -599,7 +577,6 @@ union wifi_mgmt_events { struct wifi_raw_scan_result raw_scan_result; #endif /* CONFIG_WIFI_MGMT_RAW_SCAN_RESULTS */ struct wifi_twt_params twt_params; - struct wifi_ap_sta_info ap_sta_info; }; /** Wi-Fi mode setup */ @@ -872,21 +849,6 @@ void wifi_mgmt_raise_ap_enable_result_event(struct net_if *iface, enum wifi_ap_s */ void wifi_mgmt_raise_ap_disable_result_event(struct net_if *iface, enum wifi_ap_status status); -/** Wi-Fi management AP mode STA connected event - * - * @param iface Network interface - * @param sta_info STA information - */ -void wifi_mgmt_raise_ap_sta_connected_event(struct net_if *iface, - struct wifi_ap_sta_info *sta_info); - -/** Wi-Fi management AP mode STA disconnected event - * @param iface Network interface - * @param sta_info STA information - */ -void wifi_mgmt_raise_ap_sta_disconnected_event(struct net_if *iface, - struct wifi_ap_sta_info *sta_info); - /** * @} */ diff --git a/subsys/net/l2/wifi/wifi_mgmt.c b/subsys/net/l2/wifi/wifi_mgmt.c index 6e0cb761dbf..21a426d794d 100644 --- a/subsys/net/l2/wifi/wifi_mgmt.c +++ b/subsys/net/l2/wifi/wifi_mgmt.c @@ -731,19 +731,3 @@ void wifi_mgmt_raise_ap_disable_result_event(struct net_if *iface, iface, &cnx_status, sizeof(enum wifi_ap_status)); } - -void wifi_mgmt_raise_ap_sta_connected_event(struct net_if *iface, - struct wifi_ap_sta_info *sta_info) -{ - net_mgmt_event_notify_with_info(NET_EVENT_WIFI_AP_STA_CONNECTED, - iface, sta_info, - sizeof(struct wifi_ap_sta_info)); -} - -void wifi_mgmt_raise_ap_sta_disconnected_event(struct net_if *iface, - struct wifi_ap_sta_info *sta_info) -{ - net_mgmt_event_notify_with_info(NET_EVENT_WIFI_AP_STA_DISCONNECTED, - iface, sta_info, - sizeof(struct wifi_ap_sta_info)); -} diff --git a/subsys/net/l2/wifi/wifi_shell.c b/subsys/net/l2/wifi/wifi_shell.c index 045fbed197e..217e4c703c0 100644 --- a/subsys/net/l2/wifi/wifi_shell.c +++ b/subsys/net/l2/wifi/wifi_shell.c @@ -35,9 +35,7 @@ LOG_MODULE_REGISTER(net_wifi_shell, LOG_LEVEL_INF); NET_EVENT_WIFI_TWT |\ NET_EVENT_WIFI_RAW_SCAN_RESULT |\ NET_EVENT_WIFI_AP_ENABLE_RESULT |\ - NET_EVENT_WIFI_AP_DISABLE_RESULT |\ - NET_EVENT_WIFI_AP_STA_CONNECTED |\ - NET_EVENT_WIFI_AP_STA_DISCONNECTED) + NET_EVENT_WIFI_AP_DISABLE_RESULT) #ifdef CONFIG_WIFI_MGMT_RAW_SCAN_RESULTS_ONLY #define WIFI_SHELL_MGMT_EVENTS (WIFI_SHELL_MGMT_EVENTS_COMMON) @@ -330,28 +328,6 @@ static void handle_wifi_ap_disable_result(struct net_mgmt_event_callback *cb) } } -static void handle_wifi_ap_sta_connected(struct net_mgmt_event_callback *cb) -{ - const struct wifi_ap_sta_info *sta_info = - (const struct wifi_ap_sta_info *)cb->info; - uint8_t mac_string_buf[sizeof("xx:xx:xx:xx:xx:xx")]; - - print(context.sh, SHELL_NORMAL, "Station connected: %s\n", - net_sprint_ll_addr_buf(sta_info->mac, WIFI_MAC_ADDR_LEN, - mac_string_buf, sizeof(mac_string_buf))); -} - -static void handle_wifi_ap_sta_disconnected(struct net_mgmt_event_callback *cb) -{ - const struct wifi_ap_sta_info *sta_info = - (const struct wifi_ap_sta_info *)cb->info; - uint8_t mac_string_buf[sizeof("xx:xx:xx:xx:xx:xx")]; - - print(context.sh, SHELL_NORMAL, "Station disconnected: %s\n", - net_sprint_ll_addr_buf(sta_info->mac, WIFI_MAC_ADDR_LEN, - mac_string_buf, sizeof(mac_string_buf))); -} - static void wifi_mgmt_event_handler(struct net_mgmt_event_callback *cb, uint32_t mgmt_event, struct net_if *iface) { @@ -382,12 +358,6 @@ static void wifi_mgmt_event_handler(struct net_mgmt_event_callback *cb, case NET_EVENT_WIFI_AP_DISABLE_RESULT: handle_wifi_ap_disable_result(cb); break; - case NET_EVENT_WIFI_AP_STA_CONNECTED: - handle_wifi_ap_sta_connected(cb); - break; - case NET_EVENT_WIFI_AP_STA_DISCONNECTED: - handle_wifi_ap_sta_disconnected(cb); - break; default: break; } From 1f85db433b5898181f21c8b4dff72f3c9bbc2fd7 Mon Sep 17 00:00:00 2001 From: Robert Lubos Date: Tue, 6 Feb 2024 11:07:27 +0100 Subject: [PATCH 3651/3723] Revert "[nrf fromlist] wifi: ap: Add status events" This reverts commit 15fe6c5d4ecfdf5d2e6ab9ebc5d6d41bcf74648a. Signed-off-by: Robert Lubos --- include/zephyr/net/wifi_mgmt.h | 47 --------------------------------- subsys/net/l2/wifi/wifi_mgmt.c | 24 ----------------- subsys/net/l2/wifi/wifi_shell.c | 41 +++------------------------- 3 files changed, 4 insertions(+), 108 deletions(-) diff --git a/include/zephyr/net/wifi_mgmt.h b/include/zephyr/net/wifi_mgmt.h index 0897bdd5715..babf67722c1 100644 --- a/include/zephyr/net/wifi_mgmt.h +++ b/include/zephyr/net/wifi_mgmt.h @@ -180,10 +180,6 @@ enum net_event_wifi_cmd { NET_EVENT_WIFI_CMD_RAW_SCAN_RESULT, /** Disconnect complete */ NET_EVENT_WIFI_CMD_DISCONNECT_COMPLETE, - /** AP mode enable result */ - NET_EVENT_WIFI_CMD_AP_ENABLE_RESULT, - /** AP mode disable result */ - NET_EVENT_WIFI_CMD_AP_DISABLE_RESULT, }; #define NET_EVENT_WIFI_SCAN_RESULT \ @@ -213,12 +209,6 @@ enum net_event_wifi_cmd { #define NET_EVENT_WIFI_DISCONNECT_COMPLETE \ (_NET_WIFI_EVENT | NET_EVENT_WIFI_CMD_DISCONNECT_COMPLETE) -#define NET_EVENT_WIFI_AP_ENABLE_RESULT \ - (_NET_WIFI_EVENT | NET_EVENT_WIFI_CMD_AP_ENABLE_RESULT) - -#define NET_EVENT_WIFI_AP_DISABLE_RESULT \ - (_NET_WIFI_EVENT | NET_EVENT_WIFI_CMD_AP_DISABLE_RESULT) - /** * @brief Wi-Fi structure to uniquely identify a band-channel pair */ @@ -361,35 +351,12 @@ enum wifi_disconn_reason { WIFI_REASON_DISCONN_INACTIVITY, }; -/** Wi-Fi AP mode result codes. To be overlaid on top of \ref wifi_status - * in the AP mode enable or disable result event for detailed status. - */ -enum wifi_ap_status { - /** AP mode enable or disable successful */ - WIFI_STATUS_AP_SUCCESS = 0, - /** AP mode enable or disable failed - generic failure */ - WIFI_STATUS_AP_FAIL, - /** AP mode enable failed - channel not supported */ - WIFI_STATUS_AP_CHANNEL_NOT_SUPPORTED, - /** AP mode enable failed - channel not allowed */ - WIFI_STATUS_AP_CHANNEL_NOT_ALLOWED, - /** AP mode enable failed - SSID not allowed */ - WIFI_STATUS_AP_SSID_NOT_ALLOWED, - /** AP mode enable failed - authentication type not supported */ - WIFI_STATUS_AP_AUTH_TYPE_NOT_SUPPORTED, - /** AP mode enable failed - operation not supported */ - WIFI_STATUS_AP_OP_NOT_SUPPORTED, - /** AP mode enable failed - operation not permitted */ - WIFI_STATUS_AP_OP_NOT_PERMITTED, -}; - /** Generic Wi-Fi status for commands and events */ struct wifi_status { union { int status; enum wifi_conn_status conn_status; enum wifi_disconn_reason disconn_reason; - enum wifi_ap_status ap_status; }; }; @@ -835,20 +802,6 @@ void wifi_mgmt_raise_raw_scan_result_event(struct net_if *iface, */ void wifi_mgmt_raise_disconnect_complete_event(struct net_if *iface, int status); -/** Wi-Fi management AP mode enable result event - * - * @param iface Network interface - * @param status AP mode enable result status - */ -void wifi_mgmt_raise_ap_enable_result_event(struct net_if *iface, enum wifi_ap_status status); - -/** Wi-Fi management AP mode disable result event - * - * @param iface Network interface - * @param status AP mode disable result status - */ -void wifi_mgmt_raise_ap_disable_result_event(struct net_if *iface, enum wifi_ap_status status); - /** * @} */ diff --git a/subsys/net/l2/wifi/wifi_mgmt.c b/subsys/net/l2/wifi/wifi_mgmt.c index 21a426d794d..1a866d4c47c 100644 --- a/subsys/net/l2/wifi/wifi_mgmt.c +++ b/subsys/net/l2/wifi/wifi_mgmt.c @@ -707,27 +707,3 @@ void wifi_mgmt_raise_disconnect_complete_event(struct net_if *iface, iface, &cnx_status, sizeof(struct wifi_status)); } - -void wifi_mgmt_raise_ap_enable_result_event(struct net_if *iface, - enum wifi_ap_status status) -{ - struct wifi_status cnx_status = { - .status = status, - }; - - net_mgmt_event_notify_with_info(NET_EVENT_WIFI_AP_ENABLE_RESULT, - iface, &cnx_status, - sizeof(enum wifi_ap_status)); -} - -void wifi_mgmt_raise_ap_disable_result_event(struct net_if *iface, - enum wifi_ap_status status) -{ - struct wifi_status cnx_status = { - .status = status, - }; - - net_mgmt_event_notify_with_info(NET_EVENT_WIFI_AP_DISABLE_RESULT, - iface, &cnx_status, - sizeof(enum wifi_ap_status)); -} diff --git a/subsys/net/l2/wifi/wifi_shell.c b/subsys/net/l2/wifi/wifi_shell.c index 217e4c703c0..236e5cd05b8 100644 --- a/subsys/net/l2/wifi/wifi_shell.c +++ b/subsys/net/l2/wifi/wifi_shell.c @@ -33,9 +33,7 @@ LOG_MODULE_REGISTER(net_wifi_shell, LOG_LEVEL_INF); NET_EVENT_WIFI_CONNECT_RESULT |\ NET_EVENT_WIFI_DISCONNECT_RESULT | \ NET_EVENT_WIFI_TWT |\ - NET_EVENT_WIFI_RAW_SCAN_RESULT |\ - NET_EVENT_WIFI_AP_ENABLE_RESULT |\ - NET_EVENT_WIFI_AP_DISABLE_RESULT) + NET_EVENT_WIFI_RAW_SCAN_RESULT) #ifdef CONFIG_WIFI_MGMT_RAW_SCAN_RESULTS_ONLY #define WIFI_SHELL_MGMT_EVENTS (WIFI_SHELL_MGMT_EVENTS_COMMON) @@ -302,32 +300,6 @@ static void handle_wifi_twt_event(struct net_mgmt_event_callback *cb) } } -static void handle_wifi_ap_enable_result(struct net_mgmt_event_callback *cb) -{ - const struct wifi_status *status = - (const struct wifi_status *)cb->info; - - if (status->status) { - print(context.sh, SHELL_WARNING, - "AP enable request failed (%d)\n", status->status); - } else { - print(context.sh, SHELL_NORMAL, "AP enabled\n"); - } -} - -static void handle_wifi_ap_disable_result(struct net_mgmt_event_callback *cb) -{ - const struct wifi_status *status = - (const struct wifi_status *)cb->info; - - if (status->status) { - print(context.sh, SHELL_WARNING, - "AP disable request failed (%d)\n", status->status); - } else { - print(context.sh, SHELL_NORMAL, "AP disabled\n"); - } -} - static void wifi_mgmt_event_handler(struct net_mgmt_event_callback *cb, uint32_t mgmt_event, struct net_if *iface) { @@ -352,12 +324,6 @@ static void wifi_mgmt_event_handler(struct net_mgmt_event_callback *cb, handle_wifi_raw_scan_result(cb); break; #endif /* CONFIG_WIFI_MGMT_RAW_SCAN_RESULTS */ - case NET_EVENT_WIFI_AP_ENABLE_RESULT: - handle_wifi_ap_enable_result(cb); - break; - case NET_EVENT_WIFI_AP_DISABLE_RESULT: - handle_wifi_ap_disable_result(cb); - break; default: break; } @@ -1146,7 +1112,7 @@ static int cmd_wifi_ap_enable(const struct shell *sh, size_t argc, return -ENOEXEC; } - shell_fprintf(sh, SHELL_NORMAL, "AP mode enable requested\n"); + shell_fprintf(sh, SHELL_NORMAL, "AP mode enabled\n"); return 0; } @@ -1163,7 +1129,8 @@ static int cmd_wifi_ap_disable(const struct shell *sh, size_t argc, return -ENOEXEC; } - shell_fprintf(sh, SHELL_NORMAL, "AP mode disable requested\n"); + shell_fprintf(sh, SHELL_NORMAL, "AP mode disabled\n"); + return 0; } From 93e474d42ed921c78ee0da01ded43c1ee74ba149 Mon Sep 17 00:00:00 2001 From: Robert Lubos Date: Tue, 6 Feb 2024 11:07:27 +0100 Subject: [PATCH 3652/3723] Revert "[nrf fromlist] wifi: Fix duplication" This reverts commit c0ea30dbc132c23d11c863fda9592ad7bfde6843. Signed-off-by: Robert Lubos --- subsys/net/l2/wifi/wifi_shell.c | 20 +++++++++++--------- 1 file changed, 11 insertions(+), 9 deletions(-) diff --git a/subsys/net/l2/wifi/wifi_shell.c b/subsys/net/l2/wifi/wifi_shell.c index 236e5cd05b8..9bf33e827ec 100644 --- a/subsys/net/l2/wifi/wifi_shell.c +++ b/subsys/net/l2/wifi/wifi_shell.c @@ -29,17 +29,19 @@ LOG_MODULE_REGISTER(net_wifi_shell, LOG_LEVEL_INF); #define WIFI_SHELL_MODULE "wifi" -#define WIFI_SHELL_MGMT_EVENTS_COMMON (NET_EVENT_WIFI_SCAN_DONE |\ - NET_EVENT_WIFI_CONNECT_RESULT |\ - NET_EVENT_WIFI_DISCONNECT_RESULT | \ - NET_EVENT_WIFI_TWT |\ - NET_EVENT_WIFI_RAW_SCAN_RESULT) - #ifdef CONFIG_WIFI_MGMT_RAW_SCAN_RESULTS_ONLY -#define WIFI_SHELL_MGMT_EVENTS (WIFI_SHELL_MGMT_EVENTS_COMMON) +#define WIFI_SHELL_MGMT_EVENTS (NET_EVENT_WIFI_RAW_SCAN_RESULT | \ + NET_EVENT_WIFI_SCAN_DONE | \ + NET_EVENT_WIFI_CONNECT_RESULT | \ + NET_EVENT_WIFI_DISCONNECT_RESULT | \ + NET_EVENT_WIFI_TWT) #else -#define WIFI_SHELL_MGMT_EVENTS (WIFI_SHELL_MGMT_EVENTS_COMMON |\ - NET_EVENT_WIFI_SCAN_RESULT) +#define WIFI_SHELL_MGMT_EVENTS (NET_EVENT_WIFI_SCAN_RESULT | \ + NET_EVENT_WIFI_SCAN_DONE | \ + NET_EVENT_WIFI_CONNECT_RESULT | \ + NET_EVENT_WIFI_DISCONNECT_RESULT | \ + NET_EVENT_WIFI_TWT | \ + NET_EVENT_WIFI_RAW_SCAN_RESULT) #endif /* CONFIG_WIFI_MGMT_RAW_SCAN_RESULTS_ONLY */ static struct { From 0fdfec13c825b7663e585ec2384174da914c117a Mon Sep 17 00:00:00 2001 From: Robert Lubos Date: Tue, 6 Feb 2024 11:07:27 +0100 Subject: [PATCH 3653/3723] Revert "[nrf fromlist] shell: Add a space after colon" This reverts commit 89aa0c510361acbbf4704d97b2db33f39671a491. Signed-off-by: Robert Lubos --- subsys/shell/shell_help.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/subsys/shell/shell_help.c b/subsys/shell/shell_help.c index 235e2111032..53bf00953c1 100644 --- a/subsys/shell/shell_help.c +++ b/subsys/shell/shell_help.c @@ -139,7 +139,7 @@ static void help_item_print(const struct shell *sh, const char *item_name, z_cursor_next_line_move(sh); return; } else { - z_shell_fprintf(sh, SHELL_NORMAL, "%s: ", tabulator); + z_shell_fprintf(sh, SHELL_NORMAL, "%s:", tabulator); } /* print option help */ formatted_text_print(sh, item_help, offset, false); From 356ddb437da6865196012e153b9bd6120bfbfedf Mon Sep 17 00:00:00 2001 From: Robert Lubos Date: Tue, 6 Feb 2024 11:07:27 +0100 Subject: [PATCH 3654/3723] Revert "[nrf fromlist] wifi: shell: Fix the inconsistency in commands separation" This reverts commit 260afe3c20a494877fb38bc691c401c721870da2. Signed-off-by: Robert Lubos --- subsys/net/l2/wifi/wifi_shell.c | 98 ++++++++++++++++----------------- 1 file changed, 49 insertions(+), 49 deletions(-) diff --git a/subsys/net/l2/wifi/wifi_shell.c b/subsys/net/l2/wifi/wifi_shell.c index 9bf33e827ec..a983e5c18f5 100644 --- a/subsys/net/l2/wifi/wifi_shell.c +++ b/subsys/net/l2/wifi/wifi_shell.c @@ -1601,7 +1601,7 @@ static int cmd_wifi_packet_filter(const struct shell *sh, size_t argc, char *arg SHELL_STATIC_SUBCMD_SET_CREATE(wifi_cmd_ap, SHELL_CMD_ARG(disable, NULL, - "Disable Access Point mode.\n", + "Disable Access Point mode", cmd_wifi_ap_disable, 1, 0), SHELL_CMD_ARG(enable, NULL, @@ -1611,7 +1611,7 @@ SHELL_STATIC_SUBCMD_SET_CREATE(wifi_cmd_ap, "[Security type: valid only for secure SSIDs]\n" "0:None, 1:WPA2-PSK, 2:WPA2-PSK-256, 3:SAE, 4:WAPI, 5:EAP, 6:WEP, 7: WPA-PSK\n" "[MFP (optional: needs security type to be specified)]\n" - ": 0:Disable, 1:Optional, 2:Required.\n", + ": 0:Disable, 1:Optional, 2:Required", cmd_wifi_ap_enable, 2, 4), SHELL_SUBCMD_SET_END @@ -1619,30 +1619,30 @@ SHELL_STATIC_SUBCMD_SET_CREATE(wifi_cmd_ap, SHELL_STATIC_SUBCMD_SET_CREATE(wifi_twt_ops, SHELL_CMD_ARG(quick_setup, NULL, " Start a TWT flow with defaults:\n" - " .\n", + " \n", cmd_wifi_twt_setup_quick, 3, 0), SHELL_CMD_ARG(setup, NULL, " Start a TWT flow:\n" "\n" "\n" " " - " .\n", + " \n", cmd_wifi_twt_setup, 11, 0), SHELL_CMD_ARG(teardown, NULL, " Teardown a TWT flow:\n" "\n" "\n" - " .\n", + " \n", cmd_wifi_twt_teardown, 5, 0), - SHELL_CMD_ARG(teardown_all, NULL, " Teardown all TWT flows.\n", + SHELL_CMD_ARG(teardown_all, NULL, " Teardown all TWT flows\n", cmd_wifi_twt_teardown_all, 1, 0), SHELL_SUBCMD_SET_END ); SHELL_STATIC_SUBCMD_SET_CREATE(wifi_commands, - SHELL_CMD(ap, &wifi_cmd_ap, "Access Point mode commands.\n", NULL), + SHELL_CMD(ap, &wifi_cmd_ap, "Access Point mode commands", NULL), SHELL_CMD_ARG(connect, NULL, "Connect to a Wi-Fi AP\n" "\"\"\n" @@ -1651,108 +1651,108 @@ SHELL_STATIC_SUBCMD_SET_CREATE(wifi_commands, "[Security type: valid only for secure SSIDs]\n" "0:None, 1:WPA2-PSK, 2:WPA2-PSK-256, 3:SAE, 4:WAPI, 5:EAP, 6:WEP, 7: WPA-PSK\n" "[MFP (optional: needs security type to be specified)]\n" - ": 0:Disable, 1:Optional, 2:Required.\n", + ": 0:Disable, 1:Optional, 2:Required", cmd_wifi_connect, 2, 4), - SHELL_CMD_ARG(disconnect, NULL, "Disconnect from the Wi-Fi AP.\n", + SHELL_CMD_ARG(disconnect, NULL, "Disconnect from the Wi-Fi AP", cmd_wifi_disconnect, 1, 0), SHELL_CMD_ARG(ps, NULL, "Configure or display Wi-Fi power save state\n" - "[on/off].\n", + "[on/off]\n", cmd_wifi_ps, 1, 1), SHELL_CMD_ARG(ps_mode, NULL, - ".\n", + "\n", cmd_wifi_ps_mode, 2, 0), SHELL_CMD_ARG(scan, NULL, "Scan for Wi-Fi APs\n" - "[-t, --type ] : Preferred mode of scan. The actual mode of scan can depend on factors such as the Wi-Fi chip implementation, regulatory domain restrictions. Default type is active\n" - "[-b, --bands ] : Bands to be scanned where 2: 2.4 GHz, 5: 5 GHz, 6: 6 GHz\n" - "[-a, --dwell_time_active ] : Active scan dwell time (in ms) on a channel. Range 5 ms to 1000 ms\n" - "[-p, --dwell_time_passive ] : Passive scan dwell time (in ms) on a channel. Range 10 ms to 1000 ms\n" - "[-s, --ssid : SSID to scan for. Can be provided multiple times\n" - "[-m, --max_bss ] : Maximum BSSes to scan for. Range 1 - 65535\n" + "[-t, --type ] : Preferred mode of scan. The actual mode of scan can depend on factors such as the Wi-Fi chip implementation, regulatory domain restrictions. Default type is active.\n" + "[-b, --bands ] : Bands to be scanned where 2: 2.4 GHz, 5: 5 GHz, 6: 6 GHz.\n" + "[-a, --dwell_time_active ] : Active scan dwell time (in ms) on a channel. Range 5 ms to 1000 ms.\n" + "[-p, --dwell_time_passive ] : Passive scan dwell time (in ms) on a channel. Range 10 ms to 1000 ms.\n" + "[-s, --ssid : SSID to scan for. Can be provided multiple times.\n" + "[-m, --max_bss ] : Maximum BSSes to scan for. Range 1 - 65535.\n" "[-c, --chans ] : Channels to be scanned. The channels must be specified in the form band1:chan1,chan2_band2:chan3,..etc. band1, band2 must be valid band values and chan1, chan2, chan3 must be specified as a list of comma separated values where each value is either a single channel or a channel range specified as chan_start-chan_end. Each band channel set has to be separated by a _. For example, a valid channel specification can be 2:1,6-11,14_5:36,149-165,44\n" - "[-h, --help] : Print out the help for the scan command.\n", + "[-h, --help] : Print out the help for the scan command.", cmd_wifi_scan, 1, 8), - SHELL_CMD_ARG(statistics, NULL, "Wi-Fi interface statistics.\n", cmd_wifi_stats, 1, 0), - SHELL_CMD_ARG(status, NULL, "Status of the Wi-Fi interface.\n", cmd_wifi_status, 1, 0), - SHELL_CMD(twt, &wifi_twt_ops, "Manage TWT flows.\n", NULL), + SHELL_CMD_ARG(statistics, NULL, "Wi-Fi interface statistics", cmd_wifi_stats, 1, 0), + SHELL_CMD_ARG(status, NULL, "Status of the Wi-Fi interface", cmd_wifi_status, 1, 0), + SHELL_CMD(twt, &wifi_twt_ops, "Manage TWT flows", NULL), SHELL_CMD_ARG(reg_domain, NULL, "Set or Get Wi-Fi regulatory domain\n" "[ISO/IEC 3166-1 alpha2]: Regulatory domain\n" "[-f]: Force to use this regulatory hint over any other regulatory hints\n" - "Note: This may cause regulatory compliance issues, use it at your own risk.\n", + "Note: This may cause regulatory compliance issues, use it at your own risk.", cmd_wifi_reg_domain, 1, 2), SHELL_CMD_ARG(mode, NULL, "mode operational setting\n" "This command may be used to set the Wi-Fi device into a specific mode of operation\n" - "[-i, --if-index ] : Interface index\n" - "[-s, --sta] : Station mode\n" - "[-m, --monitor] : Monitor mode\n" - "[-p, --promiscuous] : Promiscuous mode\n" - "[-t, --tx-injection] : TX-Injection mode\n" - "[-a, --ap] : AP mode\n" - "[-k, --softap] : Softap mode\n" - "[-h, --help] : Help\n" - "[-g, --get] : Get current mode for a specific interface index\n" + "[-i, --if-index ] : Interface index.\n" + "[-s, --sta] : Station mode.\n" + "[-m, --monitor] : Monitor mode.\n" + "[-p, --promiscuous] : Promiscuous mode.\n" + "[-t, --tx-injection] : TX-Injection mode.\n" + "[-a, --ap] : AP mode.\n" + "[-k, --softap] : Softap mode.\n" + "[-h, --help] : Help.\n" + "[-g, --get] : Get current mode for a specific interface index.\n" "Usage: Get operation example for interface index 1\n" "wifi mode -g -i1\n" "Set operation example for interface index 1 - set station+promiscuous\n" - "wifi mode -i1 -sp.\n", + "wifi mode -i1 -sp\n", cmd_wifi_mode, 1, 9), SHELL_CMD_ARG(packet_filter, NULL, "mode filter setting\n" "This command is used to set packet filter setting when\n" - "monitor, TX-Injection and promiscuous mode is enabled\n" + "monitor, TX-Injection and promiscuous mode is enabled.\n" "The different packet filter modes are control, management, data and enable all filters\n" - "[-i, --if-index ] : Interface index\n" + "[-i, --if-index ] : Interface index.\n" "[-a, --all] : Enable all packet filter modes\n" - "[-m, --mgmt] : Enable management packets to allowed up the stack\n" - "[-c, --ctrl] : Enable control packets to be allowed up the stack\n" - "[-d, --data] : Enable Data packets to be allowed up the stack\n" - "[-g, --get] : Get current filter settings for a specific interface index\n" + "[-m, --mgmt] : Enable management packets to allowed up the stack.\n" + "[-c, --ctrl] : Enable control packets to be allowed up the stack.\n" + "[-d, --data] : Enable Data packets to be allowed up the stack.\n" + "[-g, --get] : Get current filter settings for a specific interface index.\n" "[-b, --capture-len ] : Capture length buffer size for each packet to be captured\n" - "[-h, --help] : Help\n" + "[-h, --help] : Help.\n" "Usage: Get operation example for interface index 1\n" "wifi packet_filter -g -i1\n" "Set operation example for interface index 1 - set data+management frame filter\n" - "wifi packet_filter -i1 -md.\n", + "wifi packet_filter -i1 -md\n", cmd_wifi_packet_filter, 1, 8), SHELL_CMD_ARG(channel, NULL, "wifi channel setting\n" "This command is used to set the channel when\n" - "monitor or TX-Injection mode is enabled\n" + "monitor or TX-Injection mode is enabled.\n" "Currently 20 MHz is only supported and no BW parameter is provided\n" - "[-i, --if-index ] : Interface index\n" - "[-c, --channel ] : Set a specific channel number to the lower layer\n" - "[-g, --get] : Get current set channel number from the lower layer\n" - "[-h, --help] : Help\n" + "[-i, --if-index ] : Interface index.\n" + "[-c, --channel ] : Set a specific channel number to the lower layer.\n" + "[-g, --get] : Get current set channel number from the lower layer.\n" + "[-h, --help] : Help.\n" "Usage: Get operation example for interface index 1\n" "wifi channel -g -i1\n" "Set operation example for interface index 1 (setting channel 5)\n" - "wifi -i1 -c5.\n", + "wifi -i1 -c5\n", cmd_wifi_channel, 1, 4), SHELL_CMD_ARG(ps_timeout, NULL, - " - PS inactivity timer(in ms).\n", + " - PS inactivity timer(in ms)", cmd_wifi_ps_timeout, 2, 0), SHELL_CMD_ARG(ps_listen_interval, NULL, - " - Listen interval in the range of <0-65535>.\n", + " - Listen interval in the range of <0-65535>", cmd_wifi_listen_interval, 2, 0), SHELL_CMD_ARG(ps_wakeup_mode, NULL, - ".\n", + "\n", cmd_wifi_ps_wakeup_mode, 2, 0), From a196e17585e31154c8f5c6a43ae5a9b5ea1c2fb0 Mon Sep 17 00:00:00 2001 From: Robert Lubos Date: Tue, 6 Feb 2024 11:07:28 +0100 Subject: [PATCH 3655/3723] Revert "[nrf fromlist] wifi: shell: Remove the unnecessary text" This reverts commit fd36c75dc0124f043c8875aef3163e8b40a99ec9. Signed-off-by: Robert Lubos --- subsys/net/l2/wifi/wifi_shell.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/subsys/net/l2/wifi/wifi_shell.c b/subsys/net/l2/wifi/wifi_shell.c index a983e5c18f5..890bb8f121e 100644 --- a/subsys/net/l2/wifi/wifi_shell.c +++ b/subsys/net/l2/wifi/wifi_shell.c @@ -1691,6 +1691,7 @@ SHELL_STATIC_SUBCMD_SET_CREATE(wifi_commands, 1, 2), SHELL_CMD_ARG(mode, NULL, "mode operational setting\n" "This command may be used to set the Wi-Fi device into a specific mode of operation\n" + "parameters:" "[-i, --if-index ] : Interface index.\n" "[-s, --sta] : Station mode.\n" "[-m, --monitor] : Monitor mode.\n" @@ -1710,6 +1711,7 @@ SHELL_STATIC_SUBCMD_SET_CREATE(wifi_commands, "This command is used to set packet filter setting when\n" "monitor, TX-Injection and promiscuous mode is enabled.\n" "The different packet filter modes are control, management, data and enable all filters\n" + "parameters:" "[-i, --if-index ] : Interface index.\n" "[-a, --all] : Enable all packet filter modes\n" "[-m, --mgmt] : Enable management packets to allowed up the stack.\n" @@ -1728,6 +1730,7 @@ SHELL_STATIC_SUBCMD_SET_CREATE(wifi_commands, "This command is used to set the channel when\n" "monitor or TX-Injection mode is enabled.\n" "Currently 20 MHz is only supported and no BW parameter is provided\n" + "parameters:" "[-i, --if-index ] : Interface index.\n" "[-c, --channel ] : Set a specific channel number to the lower layer.\n" "[-g, --get] : Get current set channel number from the lower layer.\n" From 27a2933b1176d7b62139d277b03a828821c8dd87 Mon Sep 17 00:00:00 2001 From: Robert Lubos Date: Tue, 6 Feb 2024 11:07:28 +0100 Subject: [PATCH 3656/3723] Revert "[nrf fromlist] wifi: shell: Fix the help for reg domain" This reverts commit b86194298032cf0ffc53d990b8d71e0a08aa6012. Signed-off-by: Robert Lubos --- subsys/net/l2/wifi/wifi_shell.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/subsys/net/l2/wifi/wifi_shell.c b/subsys/net/l2/wifi/wifi_shell.c index 890bb8f121e..d6d14c86bf1 100644 --- a/subsys/net/l2/wifi/wifi_shell.c +++ b/subsys/net/l2/wifi/wifi_shell.c @@ -1684,7 +1684,7 @@ SHELL_STATIC_SUBCMD_SET_CREATE(wifi_commands, SHELL_CMD(twt, &wifi_twt_ops, "Manage TWT flows", NULL), SHELL_CMD_ARG(reg_domain, NULL, "Set or Get Wi-Fi regulatory domain\n" - "[ISO/IEC 3166-1 alpha2]: Regulatory domain\n" + "Usage: wifi reg_domain [ISO/IEC 3166-1 alpha2] [-f]\n" "[-f]: Force to use this regulatory hint over any other regulatory hints\n" "Note: This may cause regulatory compliance issues, use it at your own risk.", cmd_wifi_reg_domain, From 2cbbf4862a8df033fba15bdac2c426223c891b5f Mon Sep 17 00:00:00 2001 From: Robert Lubos Date: Tue, 6 Feb 2024 11:07:28 +0100 Subject: [PATCH 3657/3723] Revert "[nrf fromlist] wifi: shell: Remove the unnecessary text in scan" This reverts commit 6f6774acf02d236c1a67dd4783ad2d7c5fed3919. Signed-off-by: Robert Lubos --- subsys/net/l2/wifi/wifi_shell.c | 1 + 1 file changed, 1 insertion(+) diff --git a/subsys/net/l2/wifi/wifi_shell.c b/subsys/net/l2/wifi/wifi_shell.c index d6d14c86bf1..6ef745670ab 100644 --- a/subsys/net/l2/wifi/wifi_shell.c +++ b/subsys/net/l2/wifi/wifi_shell.c @@ -1669,6 +1669,7 @@ SHELL_STATIC_SUBCMD_SET_CREATE(wifi_commands, 0), SHELL_CMD_ARG(scan, NULL, "Scan for Wi-Fi APs\n" + "OPTIONAL PARAMETERS:\n" "[-t, --type ] : Preferred mode of scan. The actual mode of scan can depend on factors such as the Wi-Fi chip implementation, regulatory domain restrictions. Default type is active.\n" "[-b, --bands ] : Bands to be scanned where 2: 2.4 GHz, 5: 5 GHz, 6: 6 GHz.\n" "[-a, --dwell_time_active ] : Active scan dwell time (in ms) on a channel. Range 5 ms to 1000 ms.\n" From a0d0cbd38479eb65ed08ee1a5d9540fbd9c208b8 Mon Sep 17 00:00:00 2001 From: Robert Lubos Date: Tue, 6 Feb 2024 11:07:28 +0100 Subject: [PATCH 3658/3723] Revert "[nrf fromlist] wifi: shell: Fix help for PS command" This reverts commit f076140f55d70269c733b633a9ca2dc5612500c5. Signed-off-by: Robert Lubos --- subsys/net/l2/wifi/wifi_shell.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/subsys/net/l2/wifi/wifi_shell.c b/subsys/net/l2/wifi/wifi_shell.c index 6ef745670ab..dbec138fea0 100644 --- a/subsys/net/l2/wifi/wifi_shell.c +++ b/subsys/net/l2/wifi/wifi_shell.c @@ -1657,8 +1657,7 @@ SHELL_STATIC_SUBCMD_SET_CREATE(wifi_commands, SHELL_CMD_ARG(disconnect, NULL, "Disconnect from the Wi-Fi AP", cmd_wifi_disconnect, 1, 0), - SHELL_CMD_ARG(ps, NULL, "Configure or display Wi-Fi power save state\n" - "[on/off]\n", + SHELL_CMD_ARG(ps, NULL, "Configure Wi-F PS on/off, no arguments will dump config", cmd_wifi_ps, 1, 1), SHELL_CMD_ARG(ps_mode, From 3440b22d2f6c4f1188700b7e4e3cceb73e61250e Mon Sep 17 00:00:00 2001 From: Robert Lubos Date: Tue, 6 Feb 2024 11:07:29 +0100 Subject: [PATCH 3659/3723] Revert "[nrf fromlist] wifi: shell: Fix optional arg count for connect" This reverts commit ee07a2d47bae600063b0e048355a9d8a44243a3a. Signed-off-by: Robert Lubos --- subsys/net/l2/wifi/wifi_shell.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/subsys/net/l2/wifi/wifi_shell.c b/subsys/net/l2/wifi/wifi_shell.c index dbec138fea0..c3100c9ad2c 100644 --- a/subsys/net/l2/wifi/wifi_shell.c +++ b/subsys/net/l2/wifi/wifi_shell.c @@ -1653,7 +1653,7 @@ SHELL_STATIC_SUBCMD_SET_CREATE(wifi_commands, "[MFP (optional: needs security type to be specified)]\n" ": 0:Disable, 1:Optional, 2:Required", cmd_wifi_connect, - 2, 4), + 2, 5), SHELL_CMD_ARG(disconnect, NULL, "Disconnect from the Wi-Fi AP", cmd_wifi_disconnect, 1, 0), From 30403d8f178c8424211ecadd9b9f97a2d39c2f16 Mon Sep 17 00:00:00 2001 From: Robert Lubos Date: Tue, 6 Feb 2024 11:07:29 +0100 Subject: [PATCH 3660/3723] Revert "[nrf fromlist] wifi: shell: Fix the arg count for reg domain" This reverts commit 277b6e66bc52f5bdf22a140c8db748054e93a38c. Signed-off-by: Robert Lubos --- subsys/net/l2/wifi/wifi_shell.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/subsys/net/l2/wifi/wifi_shell.c b/subsys/net/l2/wifi/wifi_shell.c index c3100c9ad2c..3aa674e73b7 100644 --- a/subsys/net/l2/wifi/wifi_shell.c +++ b/subsys/net/l2/wifi/wifi_shell.c @@ -1688,7 +1688,7 @@ SHELL_STATIC_SUBCMD_SET_CREATE(wifi_commands, "[-f]: Force to use this regulatory hint over any other regulatory hints\n" "Note: This may cause regulatory compliance issues, use it at your own risk.", cmd_wifi_reg_domain, - 1, 2), + 1, 1), SHELL_CMD_ARG(mode, NULL, "mode operational setting\n" "This command may be used to set the Wi-Fi device into a specific mode of operation\n" "parameters:" From cda8e1986c9900150851b9e051ea37fd711860e0 Mon Sep 17 00:00:00 2001 From: Robert Lubos Date: Tue, 6 Feb 2024 11:07:29 +0100 Subject: [PATCH 3661/3723] Revert "[nrf fromlist] wifi: shell: Fix arg count for regulatory domain" This reverts commit 9fb63a841e1dc54b7ed3a28bff90aa8ce41ceb8c. Signed-off-by: Robert Lubos --- subsys/net/l2/wifi/wifi_shell.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/subsys/net/l2/wifi/wifi_shell.c b/subsys/net/l2/wifi/wifi_shell.c index 3aa674e73b7..f1a98105204 100644 --- a/subsys/net/l2/wifi/wifi_shell.c +++ b/subsys/net/l2/wifi/wifi_shell.c @@ -1688,7 +1688,7 @@ SHELL_STATIC_SUBCMD_SET_CREATE(wifi_commands, "[-f]: Force to use this regulatory hint over any other regulatory hints\n" "Note: This may cause regulatory compliance issues, use it at your own risk.", cmd_wifi_reg_domain, - 1, 1), + 2, 1), SHELL_CMD_ARG(mode, NULL, "mode operational setting\n" "This command may be used to set the Wi-Fi device into a specific mode of operation\n" "parameters:" From d0b3d785090bbc73ade453810c64235319e6820e Mon Sep 17 00:00:00 2001 From: Robert Lubos Date: Tue, 6 Feb 2024 11:07:29 +0100 Subject: [PATCH 3662/3723] Revert "[nrf fromtree] wifi: shell: Display RSSI only for station mode" This reverts commit 620bad8edd3f13a77595747002554fec3ff60ed2. Signed-off-by: Robert Lubos --- subsys/net/l2/wifi/wifi_shell.c | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/subsys/net/l2/wifi/wifi_shell.c b/subsys/net/l2/wifi/wifi_shell.c index f1a98105204..e243a9de4e4 100644 --- a/subsys/net/l2/wifi/wifi_shell.c +++ b/subsys/net/l2/wifi/wifi_shell.c @@ -660,9 +660,7 @@ static int cmd_wifi_status(const struct shell *sh, size_t argc, char *argv[]) wifi_security_txt(status.security)); shell_fprintf(sh, SHELL_NORMAL, "MFP: %s\n", wifi_mfp_txt(status.mfp)); - if (status.iface_mode == WIFI_MODE_INFRA) { - shell_fprintf(sh, SHELL_NORMAL, "RSSI: %d\n", status.rssi); - } + shell_fprintf(sh, SHELL_NORMAL, "RSSI: %d\n", status.rssi); shell_fprintf(sh, SHELL_NORMAL, "Beacon Interval: %d\n", status.beacon_interval); shell_fprintf(sh, SHELL_NORMAL, "DTIM: %d\n", status.dtim_period); shell_fprintf(sh, SHELL_NORMAL, "TWT: %s\n", From 65da944311ea7d4f54f9eafa0cae28010ad0eb1e Mon Sep 17 00:00:00 2001 From: Robert Lubos Date: Tue, 6 Feb 2024 11:07:29 +0100 Subject: [PATCH 3663/3723] Revert "[nrf fromtree] wifi: shell: Fix AP argument checks and help" This reverts commit 915ea12b7c706f7c9667aa85b2fb90b406d36e19. Signed-off-by: Robert Lubos --- subsys/net/l2/wifi/wifi_shell.c | 11 ++--------- 1 file changed, 2 insertions(+), 9 deletions(-) diff --git a/subsys/net/l2/wifi/wifi_shell.c b/subsys/net/l2/wifi/wifi_shell.c index e243a9de4e4..c5b8f60d933 100644 --- a/subsys/net/l2/wifi/wifi_shell.c +++ b/subsys/net/l2/wifi/wifi_shell.c @@ -1602,16 +1602,9 @@ SHELL_STATIC_SUBCMD_SET_CREATE(wifi_cmd_ap, "Disable Access Point mode", cmd_wifi_ap_disable, 1, 0), - SHELL_CMD_ARG(enable, NULL, - "\"\"\n" - "[channel number: 0 means all]\n" - "[PSK: valid only for secure SSIDs]\n" - "[Security type: valid only for secure SSIDs]\n" - "0:None, 1:WPA2-PSK, 2:WPA2-PSK-256, 3:SAE, 4:WAPI, 5:EAP, 6:WEP, 7: WPA-PSK\n" - "[MFP (optional: needs security type to be specified)]\n" - ": 0:Disable, 1:Optional, 2:Required", + SHELL_CMD_ARG(enable, NULL, " [channel] [PSK]", cmd_wifi_ap_enable, - 2, 4), + 2, 1), SHELL_SUBCMD_SET_END ); From 6c73bc697ed781f8ace6ddac6fb1cb3e04609c78 Mon Sep 17 00:00:00 2001 From: Robert Lubos Date: Tue, 6 Feb 2024 11:07:30 +0100 Subject: [PATCH 3664/3723] Revert "[nrf fromtree] drivers: nrf_qspi_nor: Fix and refactor driver initialization" This reverts commit 05688141d94c0cb28ab1cb48a653d733a4133001. Signed-off-by: Robert Lubos --- drivers/flash/nrf_qspi_nor.c | 125 ++++++++++++++++++++++------------- 1 file changed, 80 insertions(+), 45 deletions(-) diff --git a/drivers/flash/nrf_qspi_nor.c b/drivers/flash/nrf_qspi_nor.c index d6695989857..aa6449763be 100644 --- a/drivers/flash/nrf_qspi_nor.c +++ b/drivers/flash/nrf_qspi_nor.c @@ -599,10 +599,41 @@ static int qspi_erase(const struct device *dev, uint32_t addr, uint32_t size) return rc != 0 ? rc : rc2; } -static int configure_chip(const struct device *dev) +/* Configures QSPI memory for the transfer */ +static int qspi_nrfx_configure(const struct device *dev) { + struct qspi_nor_data *dev_data = dev->data; const struct qspi_nor_config *dev_config = dev->config; - int rc = 0; + nrfx_err_t res; + int rc; + + res = nrfx_qspi_init(&dev_config->nrfx_cfg, qspi_handler, dev_data); + rc = qspi_get_zephyr_ret_code(res); + if (rc < 0) { + return rc; + } + +#if DT_INST_NODE_HAS_PROP(0, rx_delay) + if (!nrf53_errata_121()) { + nrf_qspi_iftiming_set(NRF_QSPI, DT_INST_PROP(0, rx_delay)); + } +#endif + + /* It may happen that after the flash chip was previously put into + * the DPD mode, the system was reset but the flash chip was not. + * Consequently, the flash chip can be in the DPD mode at this point. + * Some flash chips will just exit the DPD mode on the first CS pulse, + * but some need to receive the dedicated command to do it, so send it. + * This can be the case even if the current image does not have + * CONFIG_PM_DEVICE set to enter DPD mode, as a previously executing image + * (for example the main image if the currently executing image is the + * bootloader) might have set DPD mode before reboot. As a result, + * attempt to exit DPD mode regardless of whether CONFIG_PM_DEVICE is set. + */ + rc = exit_dpd(dev); + if (rc < 0) { + return rc; + } /* Set QE to match transfer mode. If not using quad * it's OK to leave QE set, but doing so prevents use @@ -753,6 +784,33 @@ static int qspi_sfdp_read(const struct device *dev, off_t offset, #endif /* CONFIG_FLASH_JESD216_API */ +/** + * @brief Retrieve the Flash JEDEC ID and compare it with the one expected + * + * @param dev The device structure + * @return 0 on success, negative errno code otherwise + */ +static inline int qspi_nor_read_id(const struct device *dev) +{ + uint8_t id[SPI_NOR_MAX_ID_LEN]; + int rc = qspi_rdid(dev, id); + + if (rc != 0) { + return -EIO; + } + + const struct qspi_nor_config *qnc = dev->config; + + if (memcmp(qnc->id, id, SPI_NOR_MAX_ID_LEN) != 0) { + LOG_ERR("JEDEC id [%02x %02x %02x] expect [%02x %02x %02x]", + id[0], id[1], id[2], + qnc->id[0], qnc->id[1], qnc->id[2]); + return -ENODEV; + } + + return 0; +} + static inline nrfx_err_t read_non_aligned(const struct device *dev, off_t addr, void *dest, size_t size) @@ -1019,58 +1077,35 @@ static int qspi_nor_write_protection_set(const struct device *dev, return rc; } -static int qspi_init(const struct device *dev) +/** + * @brief Configure the flash + * + * @param dev The flash device structure + * @param info The flash info structure + * @return 0 on success, negative errno code otherwise + */ +static int qspi_nor_configure(const struct device *dev) { - const struct qspi_nor_config *dev_config = dev->config; - uint8_t id[SPI_NOR_MAX_ID_LEN]; - nrfx_err_t res; - int rc; - - res = nrfx_qspi_init(&dev_config->nrfx_cfg, qspi_handler, dev->data); - rc = qspi_get_zephyr_ret_code(res); - if (rc < 0) { - return rc; - } - -#if DT_INST_NODE_HAS_PROP(0, rx_delay) - if (!nrf53_errata_121()) { - nrf_qspi_iftiming_set(NRF_QSPI, DT_INST_PROP(0, rx_delay)); - } -#endif - - /* It may happen that after the flash chip was previously put into - * the DPD mode, the system was reset but the flash chip was not. - * Consequently, the flash chip can be in the DPD mode at this point. - * Some flash chips will just exit the DPD mode on the first CS pulse, - * but some need to receive the dedicated command to do it, so send it. - * This can be the case even if the current image does not have - * CONFIG_PM_DEVICE set to enter DPD mode, as a previously executing image - * (for example the main image if the currently executing image is the - * bootloader) might have set DPD mode before reboot. As a result, - * attempt to exit DPD mode regardless of whether CONFIG_PM_DEVICE is set. - */ - rc = exit_dpd(dev); - if (rc < 0) { - return rc; - } + int rc = qspi_nrfx_configure(dev); - /* Retrieve the Flash JEDEC ID and compare it with the one expected. */ - rc = qspi_rdid(dev, id); - if (rc < 0) { + if (rc != 0) { return rc; } - if (memcmp(dev_config->id, id, SPI_NOR_MAX_ID_LEN) != 0) { - LOG_ERR("JEDEC id [%02x %02x %02x] expect [%02x %02x %02x]", - id[0], id[1], id[2], dev_config->id[0], - dev_config->id[1], dev_config->id[2]); + /* now the spi bus is configured, we can verify the flash id */ + if (qspi_nor_read_id(dev) != 0) { return -ENODEV; } - /* The chip is correct, it can be configured now. */ - return configure_chip(dev); + return 0; } +/** + * @brief Initialize and configure the flash + * + * @param name The flash name + * @return 0 on success, negative errno code otherwise + */ static int qspi_nor_init(const struct device *dev) { const struct qspi_nor_config *dev_config = dev->config; @@ -1086,7 +1121,7 @@ static int qspi_nor_init(const struct device *dev) qspi_clock_div_change(); - rc = qspi_init(dev); + rc = qspi_nor_configure(dev); qspi_clock_div_restore(); From b77210102f213e2b6cc98c0f9eb0aec5648af667 Mon Sep 17 00:00:00 2001 From: Robert Lubos Date: Tue, 6 Feb 2024 11:07:30 +0100 Subject: [PATCH 3665/3723] Revert "[nrf fromtree] drivers: nrf_qspi_nor: Refactor deactivation and locking access to QSPI" This reverts commit 24e7218a2b0831b0f2d162d858d2556ff661d012. Signed-off-by: Robert Lubos --- drivers/flash/nrf_qspi_nor.c | 507 ++++++++++++++++++++++------------- 1 file changed, 314 insertions(+), 193 deletions(-) diff --git a/drivers/flash/nrf_qspi_nor.c b/drivers/flash/nrf_qspi_nor.c index aa6449763be..ca4673e8aa2 100644 --- a/drivers/flash/nrf_qspi_nor.c +++ b/drivers/flash/nrf_qspi_nor.c @@ -26,15 +26,15 @@ LOG_MODULE_REGISTER(qspi_nor, CONFIG_FLASH_LOG_LEVEL); #include struct qspi_nor_data { -#if !defined(CONFIG_PM_DEVICE_RUNTIME) && defined(CONFIG_MULTITHREADING) - /* A semaphore to control QSPI deactivation. */ - struct k_sem count; -#endif #ifdef CONFIG_MULTITHREADING + /* The semaphore to control exclusive access on write/erase. */ + struct k_sem trans; /* The semaphore to control exclusive access to the device. */ struct k_sem sem; /* The semaphore to indicate that transfer has completed. */ struct k_sem sync; + /* The semaphore to control driver init/uninit. */ + struct k_sem count; #else /* CONFIG_MULTITHREADING */ /* A flag that signals completed transfer when threads are * not enabled. @@ -173,6 +173,12 @@ BUILD_ASSERT(DT_INST_PROP(0, address_size_32), "After entering 4 byte addressing mode, 4 byte addressing is expected"); #endif +#ifndef CONFIG_PM_DEVICE_RUNTIME +static bool qspi_initialized; +#endif + +static int qspi_device_init(const struct device *dev); +static void qspi_device_uninit(const struct device *dev); void z_impl_nrf_qspi_nor_xip_enable(const struct device *dev, bool enable); void z_vrfy_nrf_qspi_nor_xip_enable(const struct device *dev, bool enable); @@ -239,99 +245,72 @@ static inline int qspi_get_zephyr_ret_code(nrfx_err_t res) static inline void qspi_lock(const struct device *dev) { -#ifdef CONFIG_MULTITHREADING struct qspi_nor_data *dev_data = dev->data; + pm_device_busy_set(dev); + +#ifdef CONFIG_MULTITHREADING k_sem_take(&dev_data->sem, K_FOREVER); +#else /* CONFIG_MULTITHREADING */ + ARG_UNUSED(dev_data); +#endif /* CONFIG_MULTITHREADING */ + + /* + * Change the base clock divider only for the time the driver is locked + * to perform a QSPI operation, otherwise the power consumption would be + * increased also when the QSPI peripheral is idle. + * When XIP is enabled, there is nothing to do here as the changed + * divider is kept all the time. + */ +#if defined(CONFIG_SOC_SERIES_NRF53X) + if (!dev_data->xip_enabled) { + nrf_clock_hfclk192m_div_set(NRF_CLOCK, BASE_CLOCK_DIV); + } #endif } static inline void qspi_unlock(const struct device *dev) { -#ifdef CONFIG_MULTITHREADING struct qspi_nor_data *dev_data = dev->data; - k_sem_give(&dev_data->sem); -#endif -} - -static inline void qspi_clock_div_change(void) -{ -#ifdef CONFIG_SOC_SERIES_NRF53X - /* Make sure the base clock divider is changed accordingly - * before a QSPI transfer is performed. +#if defined(CONFIG_SOC_SERIES_NRF53X) + /* Restore the default base clock divider to reduce power consumption. + * Unless XIP is enabled, then the changed divider needs to be kept. */ - nrf_clock_hfclk192m_div_set(NRF_CLOCK, BASE_CLOCK_DIV); + if (!dev_data->xip_enabled) { + nrf_clock_hfclk192m_div_set(NRF_CLOCK, NRF_CLOCK_HFCLK_DIV_4); + } #endif -} -static inline void qspi_clock_div_restore(void) -{ -#ifdef CONFIG_SOC_SERIES_NRF53X - /* Restore the default base clock divider to reduce power - * consumption when the QSPI peripheral is idle. - */ - nrf_clock_hfclk192m_div_set(NRF_CLOCK, NRF_CLOCK_HFCLK_DIV_4); +#ifdef CONFIG_MULTITHREADING + k_sem_give(&dev_data->sem); +#else + ARG_UNUSED(dev_data); #endif + + pm_device_busy_clear(dev); } -static void qspi_acquire(const struct device *dev) +static inline void qspi_trans_lock(const struct device *dev) { +#ifdef CONFIG_MULTITHREADING struct qspi_nor_data *dev_data = dev->data; -#if defined(CONFIG_PM_DEVICE_RUNTIME) - int rc = pm_device_runtime_get(dev); - - if (rc < 0) { - LOG_ERR("pm_device_runtime_get failed: %d", rc); - } -#elif defined(CONFIG_MULTITHREADING) - /* In multithreading, the driver can call qspi_acquire more than once - * before calling qspi_release. Keeping count, so QSPI is deactivated - * only at the last call (count == 0). - */ - k_sem_give(&dev_data->count); -#endif - - qspi_lock(dev); - - if (!dev_data->xip_enabled) { - qspi_clock_div_change(); - - pm_device_busy_set(dev); - } + k_sem_take(&dev_data->trans, K_FOREVER); +#else /* CONFIG_MULTITHREADING */ + ARG_UNUSED(dev); +#endif /* CONFIG_MULTITHREADING */ } -static void qspi_release(const struct device *dev) +static inline void qspi_trans_unlock(const struct device *dev) { +#ifdef CONFIG_MULTITHREADING struct qspi_nor_data *dev_data = dev->data; - bool deactivate = true; -#if !defined(CONFIG_PM_DEVICE_RUNTIME) && defined(CONFIG_MULTITHREADING) - /* The last thread to finish using the driver deactivates the QSPI */ - (void) k_sem_take(&dev_data->count, K_NO_WAIT); - deactivate = (k_sem_count_get(&dev_data->count) == 0); -#endif - - if (!dev_data->xip_enabled) { - qspi_clock_div_restore(); - - if (deactivate && !IS_ENABLED(CONFIG_PM_DEVICE_RUNTIME)) { - (void) nrfx_qspi_deactivate(); - } - - pm_device_busy_clear(dev); - } - - qspi_unlock(dev); - -#if defined(CONFIG_PM_DEVICE_RUNTIME) - int rc = pm_device_runtime_put(dev); - - if (rc < 0) { - LOG_ERR("pm_device_runtime_put failed: %d", rc); - } -#endif + k_sem_give(&dev_data->trans); +#else /* CONFIG_MULTITHREADING */ + ARG_UNUSED(dev); +#endif /* CONFIG_MULTITHREADING */ } static inline void qspi_wait_for_completion(const struct device *dev, @@ -380,6 +359,89 @@ static void qspi_handler(nrfx_qspi_evt_t event, void *p_context) } } +static int qspi_device_init(const struct device *dev) +{ + struct qspi_nor_data *dev_data = dev->data; + + if (dev_data->xip_enabled) { + return 0; + } + +#ifdef CONFIG_PM_DEVICE_RUNTIME + return pm_device_runtime_get(dev); +#else + nrfx_err_t res; + int rc = 0; + + qspi_lock(dev); + + /* In multithreading, driver can call qspi_device_init more than once + * before calling qspi_device_uninit. Keepping count, so QSPI is + * uninitialized only at the last call (count == 0). + */ +#ifdef CONFIG_MULTITHREADING + k_sem_give(&dev_data->count); +#endif + + if (!qspi_initialized) { + const struct qspi_nor_config *dev_config = dev->config; + + res = nrfx_qspi_init(&dev_config->nrfx_cfg, + qspi_handler, + dev_data); + rc = qspi_get_zephyr_ret_code(res); + qspi_initialized = (rc == 0); + } + + qspi_unlock(dev); + + return rc; +#endif +} + +static void qspi_device_uninit(const struct device *dev) +{ + struct qspi_nor_data *dev_data = dev->data; + + if (dev_data->xip_enabled) { + return; + } + +#ifdef CONFIG_PM_DEVICE_RUNTIME + int rc = pm_device_runtime_put(dev); + + if (rc < 0) { + LOG_ERR("Failed to schedule device sleep: %d", rc); + } +#else + bool last = true; + + qspi_lock(dev); + +#ifdef CONFIG_MULTITHREADING + /* The last thread to finish using the driver uninit the QSPI */ + (void) k_sem_take(&dev_data->count, K_NO_WAIT); + last = (k_sem_count_get(&dev_data->count) == 0); +#endif + + if (last) { + while (nrfx_qspi_mem_busy_check() != NRFX_SUCCESS) { + if (IS_ENABLED(CONFIG_MULTITHREADING)) { + k_msleep(50); + } else { + k_busy_wait(50000); + } + } + + nrfx_qspi_uninit(); + + qspi_initialized = false; + } + + qspi_unlock(dev); +#endif +} + /* QSPI send custom command. * * If this is used for both send and receive the buffer sizes must be @@ -435,8 +497,11 @@ static int qspi_send_cmd(const struct device *dev, const struct qspi_cmd *cmd, .wren = wren, }; + qspi_lock(dev); + int res = nrfx_qspi_cinstr_xfer(&cinstr_cfg, tx_buf, rx_buf); + qspi_unlock(dev); return qspi_get_zephyr_ret_code(res); } @@ -552,13 +617,29 @@ static int qspi_wrsr(const struct device *dev, uint8_t sr_val, uint8_t sr_num) /* QSPI erase */ static int qspi_erase(const struct device *dev, uint32_t addr, uint32_t size) { + /* address must be sector-aligned */ + if ((addr % QSPI_SECTOR_SIZE) != 0) { + return -EINVAL; + } + + /* size must be a non-zero multiple of sectors */ + if ((size == 0) || (size % QSPI_SECTOR_SIZE) != 0) { + return -EINVAL; + } + const struct qspi_nor_config *params = dev->config; int rc, rc2; + rc = qspi_device_init(dev); + if (rc != 0) { + goto out; + } + qspi_trans_lock(dev); rc = qspi_nor_write_protection_set(dev, false); if (rc != 0) { - return rc; + goto out_trans_unlock; } + qspi_lock(dev); while (size > 0) { nrfx_err_t res = !NRFX_SUCCESS; uint32_t adj = 0; @@ -593,10 +674,20 @@ static int qspi_erase(const struct device *dev, uint32_t addr, uint32_t size) break; } } + qspi_unlock(dev); rc2 = qspi_nor_write_protection_set(dev, true); - return rc != 0 ? rc : rc2; + if (!rc) { + rc = rc2; + } + +out_trans_unlock: + qspi_trans_unlock(dev); + +out: + qspi_device_uninit(dev); + return rc; } /* Configures QSPI memory for the transfer */ @@ -607,7 +698,22 @@ static int qspi_nrfx_configure(const struct device *dev) nrfx_err_t res; int rc; +#if defined(CONFIG_SOC_SERIES_NRF53X) + /* When the QSPI peripheral is activated, during the nrfx_qspi driver + * initialization, it reads the status of the connected flash chip. + * Make sure this transaction is performed with a valid base clock + * divider. + */ + nrf_clock_hfclk192m_div_set(NRF_CLOCK, BASE_CLOCK_DIV); +#endif + res = nrfx_qspi_init(&dev_config->nrfx_cfg, qspi_handler, dev_data); + +#if defined(CONFIG_SOC_SERIES_NRF53X) + /* Restore the default /4 divider after the QSPI initialization. */ + nrf_clock_hfclk192m_div_set(NRF_CLOCK, NRF_CLOCK_HFCLK_DIV_4); +#endif + rc = qspi_get_zephyr_ret_code(res); if (rc < 0) { return rc; @@ -708,7 +814,8 @@ static int qspi_nrfx_configure(const struct device *dev) return rc; } -static int qspi_rdid(const struct device *dev, uint8_t *id) +static int qspi_read_jedec_id(const struct device *dev, + uint8_t *id) { const struct qspi_buf rx_buf = { .buf = id, @@ -719,24 +826,18 @@ static int qspi_rdid(const struct device *dev, uint8_t *id) .rx_buf = &rx_buf, }; - return qspi_send_cmd(dev, &cmd, false); -} - -#if defined(CONFIG_FLASH_JESD216_API) + int rc = qspi_device_init(dev); -static int qspi_read_jedec_id(const struct device *dev, uint8_t *id) -{ - int rc; - - qspi_acquire(dev); - - rc = qspi_rdid(dev, id); - - qspi_release(dev); + if (rc == 0) { + rc = qspi_send_cmd(dev, &cmd, false); + } + qspi_device_uninit(dev); return rc; } +#if defined(CONFIG_FLASH_JESD216_API) + static int qspi_sfdp_read(const struct device *dev, off_t offset, void *data, size_t len) { @@ -754,10 +855,17 @@ static int qspi_sfdp_read(const struct device *dev, off_t offset, .io2_level = true, .io3_level = true, }; - nrfx_err_t res; - qspi_acquire(dev); + int rc = qspi_device_init(dev); + nrfx_err_t res = NRFX_SUCCESS; + + if (rc != 0) { + LOG_DBG("qspi_device_init: %d", rc); + qspi_device_uninit(dev); + return rc; + } + qspi_lock(dev); res = nrfx_qspi_lfm_start(&cinstr_cfg); if (res != NRFX_SUCCESS) { LOG_DBG("lfm_start: %x", res); @@ -777,8 +885,8 @@ static int qspi_sfdp_read(const struct device *dev, off_t offset, } out: - qspi_release(dev); - + qspi_unlock(dev); + qspi_device_uninit(dev); return qspi_get_zephyr_ret_code(res); } @@ -793,7 +901,7 @@ static int qspi_sfdp_read(const struct device *dev, off_t offset, static inline int qspi_nor_read_id(const struct device *dev) { uint8_t id[SPI_NOR_MAX_ID_LEN]; - int rc = qspi_rdid(dev, id); + int rc = qspi_read_jedec_id(dev, id); if (rc != 0) { return -EIO; @@ -885,9 +993,6 @@ static inline nrfx_err_t read_non_aligned(const struct device *dev, static int qspi_nor_read(const struct device *dev, off_t addr, void *dest, size_t size) { - const struct qspi_nor_config *params = dev->config; - nrfx_err_t res; - if (!dest) { return -EINVAL; } @@ -897,6 +1002,8 @@ static int qspi_nor_read(const struct device *dev, off_t addr, void *dest, return 0; } + const struct qspi_nor_config *params = dev->config; + /* affected region should be within device */ if (addr < 0 || (addr + size) > params->size) { @@ -906,13 +1013,23 @@ static int qspi_nor_read(const struct device *dev, off_t addr, void *dest, return -EINVAL; } - qspi_acquire(dev); + int rc = qspi_device_init(dev); + + if (rc != 0) { + goto out; + } - res = read_non_aligned(dev, addr, dest, size); + qspi_lock(dev); - qspi_release(dev); + nrfx_err_t res = read_non_aligned(dev, addr, dest, size); - return qspi_get_zephyr_ret_code(res); + qspi_unlock(dev); + + rc = qspi_get_zephyr_ret_code(res); + +out: + qspi_device_uninit(dev); + return rc; } /* addr aligned, sptr not null, slen less than 4 */ @@ -977,9 +1094,6 @@ static int qspi_nor_write(const struct device *dev, off_t addr, const void *src, size_t size) { - const struct qspi_nor_config *params = dev->config; - int rc, rc2; - if (!src) { return -EINVAL; } @@ -994,6 +1108,9 @@ static int qspi_nor_write(const struct device *dev, off_t addr, return -EINVAL; } + const struct qspi_nor_config *params = dev->config; + int rc, rc2; + /* affected region should be within device */ if (addr < 0 || (addr + size) > params->size) { @@ -1003,9 +1120,15 @@ static int qspi_nor_write(const struct device *dev, off_t addr, return -EINVAL; } - qspi_acquire(dev); + rc = qspi_device_init(dev); + if (rc != 0) { + goto out; + } + + qspi_trans_lock(dev); rc = qspi_nor_write_protection_set(dev, false); + qspi_lock(dev); if (rc == 0) { nrfx_err_t res; @@ -1021,28 +1144,23 @@ static int qspi_nor_write(const struct device *dev, off_t addr, rc = qspi_get_zephyr_ret_code(res); } + qspi_unlock(dev); rc2 = qspi_nor_write_protection_set(dev, true); - qspi_release(dev); + qspi_trans_unlock(dev); + if (rc == 0) { + rc = rc2; + } - return rc != 0 ? rc : rc2; +out: + qspi_device_uninit(dev); + return rc; } static int qspi_nor_erase(const struct device *dev, off_t addr, size_t size) { const struct qspi_nor_config *params = dev->config; - int rc; - - /* address must be sector-aligned */ - if ((addr % QSPI_SECTOR_SIZE) != 0) { - return -EINVAL; - } - - /* size must be a non-zero multiple of sectors */ - if ((size == 0) || (size % QSPI_SECTOR_SIZE) != 0) { - return -EINVAL; - } /* affected region should be within device */ if (addr < 0 || @@ -1053,11 +1171,7 @@ static int qspi_nor_erase(const struct device *dev, off_t addr, size_t size) return -EINVAL; } - qspi_acquire(dev); - - rc = qspi_erase(dev, addr, size); - - qspi_release(dev); + int rc = qspi_erase(dev, addr, size); return rc; } @@ -1092,6 +1206,17 @@ static int qspi_nor_configure(const struct device *dev) return rc; } +#ifdef CONFIG_PM_DEVICE_RUNTIME + rc = pm_device_runtime_enable(dev); + if (rc < 0) { + LOG_ERR("Failed to enable runtime power management: %d", rc); + } else { + LOG_DBG("Runtime power management enabled"); + } +#else + qspi_device_uninit(dev); +#endif + /* now the spi bus is configured, we can verify the flash id */ if (qspi_nor_read_id(dev) != 0) { return -ENODEV; @@ -1119,24 +1244,10 @@ static int qspi_nor_init(const struct device *dev) IRQ_CONNECT(DT_IRQN(QSPI_NODE), DT_IRQ(QSPI_NODE, priority), nrfx_isr, nrfx_qspi_irq_handler, 0); - qspi_clock_div_change(); - rc = qspi_nor_configure(dev); - qspi_clock_div_restore(); - -#ifdef CONFIG_PM_DEVICE_RUNTIME - int rc2 = pm_device_runtime_enable(dev); - - if (rc2 < 0) { - LOG_ERR("Failed to enable runtime power management: %d", rc2); - } else { - LOG_DBG("Runtime power management enabled"); - } -#endif - #ifdef CONFIG_NORDIC_QSPI_NOR_XIP - if (rc == 0) { + if (!rc) { /* Enable XIP mode for QSPI NOR flash, this will prevent the * flash from being powered down */ @@ -1272,97 +1383,108 @@ static int exit_dpd(const struct device *const dev) } #ifdef CONFIG_PM_DEVICE -static int qspi_suspend(const struct device *dev) -{ - const struct qspi_nor_config *dev_config = dev->config; - nrfx_err_t res; - int rc; - - res = nrfx_qspi_mem_busy_check(); - if (res != NRFX_SUCCESS) { - return -EBUSY; - } - - rc = enter_dpd(dev); - if (rc < 0) { - return rc; - } - - nrfx_qspi_uninit(); - - return pinctrl_apply_state(dev_config->pcfg, PINCTRL_STATE_SLEEP); -} - -static int qspi_resume(const struct device *dev) -{ - const struct qspi_nor_config *dev_config = dev->config; - nrfx_err_t res; - int rc; - - rc = pinctrl_apply_state(dev_config->pcfg, PINCTRL_STATE_DEFAULT); - if (rc < 0) { - return rc; - } - - res = nrfx_qspi_init(&dev_config->nrfx_cfg, qspi_handler, dev->data); - if (res != NRFX_SUCCESS) { - return -EIO; - } - - return exit_dpd(dev); -} - static int qspi_nor_pm_action(const struct device *dev, enum pm_device_action action) { + struct qspi_nor_data *dev_data = dev->data; + const struct qspi_nor_config *dev_config = dev->config; int rc; + nrfx_err_t res; if (pm_device_is_busy(dev)) { return -EBUSY; } - qspi_lock(dev); - qspi_clock_div_change(); - switch (action) { case PM_DEVICE_ACTION_SUSPEND: - rc = qspi_suspend(dev); +#ifndef CONFIG_PM_DEVICE_RUNTIME + /* If PM_DEVICE_RUNTIME, we don't uninit after RESUME */ + rc = qspi_device_init(dev); + if (rc < 0) { + return rc; + } +#endif + + if (dev_data->xip_enabled) { + return -EBUSY; + } + + if (nrfx_qspi_mem_busy_check() != NRFX_SUCCESS) { + return -EBUSY; + } + + rc = enter_dpd(dev); + if (rc < 0) { + return rc; + } + + nrfx_qspi_uninit(); + rc = pinctrl_apply_state(dev_config->pcfg, + PINCTRL_STATE_SLEEP); + if (rc < 0) { + return rc; + } break; case PM_DEVICE_ACTION_RESUME: - rc = qspi_resume(dev); + rc = pinctrl_apply_state(dev_config->pcfg, + PINCTRL_STATE_DEFAULT); + if (rc < 0) { + return rc; + } + res = nrfx_qspi_init(&dev_config->nrfx_cfg, + qspi_handler, + dev_data); + if (res != NRFX_SUCCESS) { + return -EIO; + } + + rc = exit_dpd(dev); + if (rc < 0) { + return rc; + } + +#ifndef CONFIG_PM_DEVICE_RUNTIME + /* If PM_DEVICE_RUNTIME, we're immediately going to use the device */ + qspi_device_uninit(dev); +#endif break; default: - rc = -ENOTSUP; + return -ENOTSUP; } - qspi_clock_div_restore(); - qspi_unlock(dev); - - return rc; + return 0; } #endif /* CONFIG_PM_DEVICE */ void z_impl_nrf_qspi_nor_xip_enable(const struct device *dev, bool enable) { struct qspi_nor_data *dev_data = dev->data; + int rc; if (dev_data->xip_enabled == enable) { return; } - qspi_acquire(dev); + rc = qspi_device_init(dev); + + if (rc != 0) { + LOG_ERR("NRF QSPI NOR XIP %s failed with %d\n", enable ? "enable" : "disable", rc); + return; + } #if NRF_QSPI_HAS_XIPEN nrf_qspi_xip_set(NRF_QSPI, enable); #endif + qspi_lock(dev); if (enable) { (void)nrfx_qspi_activate(false); } dev_data->xip_enabled = enable; + qspi_unlock(dev); - qspi_release(dev); + qspi_device_uninit(dev); } #ifdef CONFIG_USERSPACE @@ -1380,12 +1502,11 @@ void z_vrfy_nrf_qspi_nor_xip_enable(const struct device *dev, bool enable) #endif /* CONFIG_USERSPACE */ static struct qspi_nor_data qspi_nor_dev_data = { -#if !defined(CONFIG_PM_DEVICE_RUNTIME) && defined(CONFIG_MULTITHREADING) - .count = Z_SEM_INITIALIZER(qspi_nor_dev_data.count, 0, K_SEM_MAX_LIMIT), -#endif #ifdef CONFIG_MULTITHREADING + .trans = Z_SEM_INITIALIZER(qspi_nor_dev_data.trans, 1, 1), .sem = Z_SEM_INITIALIZER(qspi_nor_dev_data.sem, 1, 1), .sync = Z_SEM_INITIALIZER(qspi_nor_dev_data.sync, 0, 1), + .count = Z_SEM_INITIALIZER(qspi_nor_dev_data.count, 0, K_SEM_MAX_LIMIT), #endif /* CONFIG_MULTITHREADING */ }; From a3a8f447a1ecdc34a4a7ddfc55b1b1e9af1ece2b Mon Sep 17 00:00:00 2001 From: Robert Lubos Date: Tue, 6 Feb 2024 11:07:30 +0100 Subject: [PATCH 3666/3723] Revert "[nrf fromtree] drivers: nrf_qspi_nor: Clean up handling of return values" This reverts commit 3ae035a26abc2d5fe064e12c18c2496f4f51ff00. Signed-off-by: Robert Lubos --- drivers/flash/nrf_qspi_nor.c | 248 +++++++++++++++++------------------ 1 file changed, 123 insertions(+), 125 deletions(-) diff --git a/drivers/flash/nrf_qspi_nor.c b/drivers/flash/nrf_qspi_nor.c index ca4673e8aa2..467d0643d48 100644 --- a/drivers/flash/nrf_qspi_nor.c +++ b/drivers/flash/nrf_qspi_nor.c @@ -371,7 +371,7 @@ static int qspi_device_init(const struct device *dev) return pm_device_runtime_get(dev); #else nrfx_err_t res; - int rc = 0; + int ret = 0; qspi_lock(dev); @@ -389,13 +389,13 @@ static int qspi_device_init(const struct device *dev) res = nrfx_qspi_init(&dev_config->nrfx_cfg, qspi_handler, dev_data); - rc = qspi_get_zephyr_ret_code(res); - qspi_initialized = (rc == 0); + ret = qspi_get_zephyr_ret_code(res); + qspi_initialized = (ret == 0); } qspi_unlock(dev); - return rc; + return ret; #endif } @@ -408,10 +408,10 @@ static void qspi_device_uninit(const struct device *dev) } #ifdef CONFIG_PM_DEVICE_RUNTIME - int rc = pm_device_runtime_put(dev); + int ret = pm_device_runtime_put(dev); - if (rc < 0) { - LOG_ERR("Failed to schedule device sleep: %d", rc); + if (ret < 0) { + LOG_ERR("Failed to schedule device sleep: %d", ret); } #else bool last = true; @@ -526,27 +526,27 @@ static int qspi_rdsr(const struct device *dev, uint8_t sr_num) .op_code = opcode, .rx_buf = &sr_buf, }; - int rc = qspi_send_cmd(dev, &cmd, false); + int ret = qspi_send_cmd(dev, &cmd, false); - return (rc < 0) ? rc : sr; + return (ret < 0) ? ret : sr; } /* Wait until RDSR confirms write is not in progress. */ static int qspi_wait_while_writing(const struct device *dev) { - int rc; + int ret; do { - rc = qspi_rdsr(dev, 1); - } while ((rc >= 0) - && ((rc & SPI_NOR_WIP_BIT) != 0U)); + ret = qspi_rdsr(dev, 1); + } while ((ret >= 0) + && ((ret & SPI_NOR_WIP_BIT) != 0U)); - return (rc < 0) ? rc : 0; + return (ret < 0) ? ret : 0; } static int qspi_wrsr(const struct device *dev, uint8_t sr_val, uint8_t sr_num) { - int rc = 0; + int ret = 0; uint8_t opcode = SPI_NOR_CMD_WRSR; uint8_t length = 1; uint8_t sr_array[2] = {0}; @@ -559,12 +559,12 @@ static int qspi_wrsr(const struct device *dev, uint8_t sr_val, uint8_t sr_num) sr_array[0] = sr_val; #if SR1_WRITE_CLEARS_SR2 /* Writing sr1 clears sr2. need to read/modify/write both. */ - rc = qspi_rdsr(dev, 2); - if (rc < 0) { - LOG_ERR("RDSR for WRSR failed: %d", rc); - return rc; + ret = qspi_rdsr(dev, 2); + if (ret < 0) { + LOG_ERR("RDSR for WRSR failed: %d", ret); + return ret; } - sr_array[1] = rc; + sr_array[1] = ret; length = 2; #endif } else { /* sr_num == 2 */ @@ -574,12 +574,12 @@ static int qspi_wrsr(const struct device *dev, uint8_t sr_val, uint8_t sr_num) * Uses standard WRSR opcode */ sr_array[1] = sr_val; - rc = qspi_rdsr(dev, 1); - if (rc < 0) { - LOG_ERR("RDSR for WRSR failed: %d", rc); - return rc; + ret = qspi_rdsr(dev, 1); + if (ret < 0) { + LOG_ERR("RDSR for WRSR failed: %d", ret); + return ret; } - sr_array[0] = rc; + sr_array[0] = ret; length = 2; #elif IS_EQUAL(INST_0_QER, JESD216_DW15_QER_VAL_S2B1v6) /* Writing sr2 uses a dedicated WRSR2 command */ @@ -600,17 +600,17 @@ static int qspi_wrsr(const struct device *dev, uint8_t sr_val, uint8_t sr_num) .tx_buf = &sr_buf, }; - rc = qspi_send_cmd(dev, &cmd, true); + ret = qspi_send_cmd(dev, &cmd, true); /* Writing SR can take some time, and further * commands sent while it's happening can be * corrupted. Wait. */ - if (rc == 0) { - rc = qspi_wait_while_writing(dev); + if (ret == 0) { + ret = qspi_wait_while_writing(dev); } - return rc; + return ret; } #endif /* !IS_EQUAL(INST_0_QER, JESD216_DW15_QER_VAL_NONE) */ @@ -627,16 +627,16 @@ static int qspi_erase(const struct device *dev, uint32_t addr, uint32_t size) return -EINVAL; } + int rv = 0; const struct qspi_nor_config *params = dev->config; - int rc, rc2; - rc = qspi_device_init(dev); - if (rc != 0) { + rv = qspi_device_init(dev); + if (rv != 0) { goto out; } qspi_trans_lock(dev); - rc = qspi_nor_write_protection_set(dev, false); - if (rc != 0) { + rv = qspi_nor_write_protection_set(dev, false); + if (rv != 0) { goto out_trans_unlock; } qspi_lock(dev); @@ -670,16 +670,16 @@ static int qspi_erase(const struct device *dev, uint32_t addr, uint32_t size) size -= adj; } else { LOG_ERR("erase error at 0x%lx size %zu", (long)addr, size); - rc = qspi_get_zephyr_ret_code(res); + rv = qspi_get_zephyr_ret_code(res); break; } } qspi_unlock(dev); - rc2 = qspi_nor_write_protection_set(dev, true); + int rv2 = qspi_nor_write_protection_set(dev, true); - if (!rc) { - rc = rc2; + if (!rv) { + rv = rv2; } out_trans_unlock: @@ -687,7 +687,7 @@ static int qspi_erase(const struct device *dev, uint32_t addr, uint32_t size) out: qspi_device_uninit(dev); - return rc; + return rv; } /* Configures QSPI memory for the transfer */ @@ -695,8 +695,6 @@ static int qspi_nrfx_configure(const struct device *dev) { struct qspi_nor_data *dev_data = dev->data; const struct qspi_nor_config *dev_config = dev->config; - nrfx_err_t res; - int rc; #if defined(CONFIG_SOC_SERIES_NRF53X) /* When the QSPI peripheral is activated, during the nrfx_qspi driver @@ -707,16 +705,18 @@ static int qspi_nrfx_configure(const struct device *dev) nrf_clock_hfclk192m_div_set(NRF_CLOCK, BASE_CLOCK_DIV); #endif - res = nrfx_qspi_init(&dev_config->nrfx_cfg, qspi_handler, dev_data); + nrfx_err_t res = nrfx_qspi_init(&dev_config->nrfx_cfg, + qspi_handler, + dev_data); #if defined(CONFIG_SOC_SERIES_NRF53X) /* Restore the default /4 divider after the QSPI initialization. */ nrf_clock_hfclk192m_div_set(NRF_CLOCK, NRF_CLOCK_HFCLK_DIV_4); #endif - rc = qspi_get_zephyr_ret_code(res); - if (rc < 0) { - return rc; + int ret = qspi_get_zephyr_ret_code(res); + if (ret < 0) { + return ret; } #if DT_INST_NODE_HAS_PROP(0, rx_delay) @@ -736,9 +736,9 @@ static int qspi_nrfx_configure(const struct device *dev) * bootloader) might have set DPD mode before reboot. As a result, * attempt to exit DPD mode regardless of whether CONFIG_PM_DEVICE is set. */ - rc = exit_dpd(dev); - if (rc < 0) { - return rc; + ret = exit_dpd(dev); + if (ret < 0) { + return ret; } /* Set QE to match transfer mode. If not using quad @@ -769,28 +769,28 @@ static int qspi_nrfx_configure(const struct device *dev) return -EINVAL; #endif - rc = qspi_rdsr(dev, sr_num); - if (rc < 0) { - LOG_ERR("RDSR failed: %d", rc); - return rc; + ret = qspi_rdsr(dev, sr_num); + if (ret < 0) { + LOG_ERR("RDSR failed: %d", ret); + return ret; } - uint8_t sr = (uint8_t)rc; + uint8_t sr = (uint8_t)ret; bool qe_state = ((sr & qe_mask) != 0U); LOG_DBG("RDSR %02x QE %d need %d: %s", sr, qe_state, qe_value, (qe_state != qe_value) ? "updating" : "no-change"); - rc = 0; + ret = 0; if (qe_state != qe_value) { sr ^= qe_mask; - rc = qspi_wrsr(dev, sr, sr_num); + ret = qspi_wrsr(dev, sr, sr_num); } - if (rc < 0) { + if (ret < 0) { LOG_ERR("QE %s failed: %d", qe_value ? "set" : "clear", - rc); - return rc; + ret); + return ret; } #endif @@ -802,16 +802,16 @@ static int qspi_nrfx_configure(const struct device *dev) /* Call will send write enable before instruction if that * requirement is encoded in INST_0_4BA. */ - rc = qspi_send_cmd(dev, &cmd, (INST_0_4BA & 0x02)); + ret = qspi_send_cmd(dev, &cmd, (INST_0_4BA & 0x02)); - if (rc < 0) { - LOG_ERR("E4BA cmd issue failed: %d.", rc); + if (ret < 0) { + LOG_ERR("E4BA cmd issue failed: %d.", ret); } else { LOG_DBG("E4BA cmd issued."); } } - return rc; + return ret; } static int qspi_read_jedec_id(const struct device *dev, @@ -826,14 +826,14 @@ static int qspi_read_jedec_id(const struct device *dev, .rx_buf = &rx_buf, }; - int rc = qspi_device_init(dev); + int ret = qspi_device_init(dev); - if (rc == 0) { - rc = qspi_send_cmd(dev, &cmd, false); + if (ret == 0) { + ret = qspi_send_cmd(dev, &cmd, false); } qspi_device_uninit(dev); - return rc; + return ret; } #if defined(CONFIG_FLASH_JESD216_API) @@ -856,13 +856,13 @@ static int qspi_sfdp_read(const struct device *dev, off_t offset, .io3_level = true, }; - int rc = qspi_device_init(dev); + int ret = qspi_device_init(dev); nrfx_err_t res = NRFX_SUCCESS; - if (rc != 0) { - LOG_DBG("qspi_device_init: %d", rc); + if (ret != 0) { + LOG_DBG("qspi_device_init: %d", ret); qspi_device_uninit(dev); - return rc; + return ret; } qspi_lock(dev); @@ -901,9 +901,9 @@ static int qspi_sfdp_read(const struct device *dev, off_t offset, static inline int qspi_nor_read_id(const struct device *dev) { uint8_t id[SPI_NOR_MAX_ID_LEN]; - int rc = qspi_read_jedec_id(dev, id); + int ret = qspi_read_jedec_id(dev, id); - if (rc != 0) { + if (ret != 0) { return -EIO; } @@ -1109,7 +1109,6 @@ static int qspi_nor_write(const struct device *dev, off_t addr, } const struct qspi_nor_config *params = dev->config; - int rc, rc2; /* affected region should be within device */ if (addr < 0 || @@ -1120,18 +1119,18 @@ static int qspi_nor_write(const struct device *dev, off_t addr, return -EINVAL; } + nrfx_err_t res = NRFX_SUCCESS; + + int rc = qspi_device_init(dev); - rc = qspi_device_init(dev); if (rc != 0) { goto out; } qspi_trans_lock(dev); - rc = qspi_nor_write_protection_set(dev, false); + res = qspi_nor_write_protection_set(dev, false); qspi_lock(dev); - if (rc == 0) { - nrfx_err_t res; - + if (!res) { if (size < 4U) { res = write_sub_word(dev, addr, src, size); } else if (!nrfx_is_in_ram(src) || @@ -1141,18 +1140,17 @@ static int qspi_nor_write(const struct device *dev, off_t addr, res = nrfx_qspi_write(src, size, addr); qspi_wait_for_completion(dev, res); } - - rc = qspi_get_zephyr_ret_code(res); } qspi_unlock(dev); - rc2 = qspi_nor_write_protection_set(dev, true); + int res2 = qspi_nor_write_protection_set(dev, true); qspi_trans_unlock(dev); - if (rc == 0) { - rc = rc2; + if (!res) { + res = res2; } + rc = qspi_get_zephyr_ret_code(res); out: qspi_device_uninit(dev); return rc; @@ -1171,24 +1169,24 @@ static int qspi_nor_erase(const struct device *dev, off_t addr, size_t size) return -EINVAL; } - int rc = qspi_erase(dev, addr, size); + int ret = qspi_erase(dev, addr, size); - return rc; + return ret; } static int qspi_nor_write_protection_set(const struct device *dev, bool write_protect) { - int rc = 0; + int ret = 0; struct qspi_cmd cmd = { .op_code = ((write_protect) ? SPI_NOR_CMD_WRDI : SPI_NOR_CMD_WREN), }; if (qspi_send_cmd(dev, &cmd, false) != 0) { - rc = -EIO; + ret = -EIO; } - return rc; + return ret; } /** @@ -1200,16 +1198,16 @@ static int qspi_nor_write_protection_set(const struct device *dev, */ static int qspi_nor_configure(const struct device *dev) { - int rc = qspi_nrfx_configure(dev); + int ret = qspi_nrfx_configure(dev); - if (rc != 0) { - return rc; + if (ret != 0) { + return ret; } #ifdef CONFIG_PM_DEVICE_RUNTIME - rc = pm_device_runtime_enable(dev); - if (rc < 0) { - LOG_ERR("Failed to enable runtime power management: %d", rc); + ret = pm_device_runtime_enable(dev); + if (ret < 0) { + LOG_ERR("Failed to enable runtime power management: %d", ret); } else { LOG_DBG("Runtime power management enabled"); } @@ -1233,12 +1231,12 @@ static int qspi_nor_configure(const struct device *dev) */ static int qspi_nor_init(const struct device *dev) { - const struct qspi_nor_config *dev_config = dev->config; int rc; + const struct qspi_nor_config *dev_config = dev->config; + int ret = pinctrl_apply_state(dev_config->pcfg, PINCTRL_STATE_DEFAULT); - rc = pinctrl_apply_state(dev_config->pcfg, PINCTRL_STATE_DEFAULT); - if (rc < 0) { - return rc; + if (ret < 0) { + return ret; } IRQ_CONNECT(DT_IRQN(QSPI_NODE), DT_IRQ(QSPI_NODE, priority), @@ -1319,11 +1317,11 @@ static int enter_dpd(const struct device *const dev) .op_code = SPI_NOR_CMD_DPD, }; uint32_t t_enter_dpd = DT_INST_PROP_OR(0, t_enter_dpd, 0); - int rc; + int ret; - rc = qspi_send_cmd(dev, &cmd, false); - if (rc < 0) { - return rc; + ret = qspi_send_cmd(dev, &cmd, false); + if (ret < 0) { + return ret; } if (t_enter_dpd) { @@ -1388,8 +1386,8 @@ static int qspi_nor_pm_action(const struct device *dev, { struct qspi_nor_data *dev_data = dev->data; const struct qspi_nor_config *dev_config = dev->config; - int rc; - nrfx_err_t res; + int ret; + nrfx_err_t err; if (pm_device_is_busy(dev)) { return -EBUSY; @@ -1399,9 +1397,9 @@ static int qspi_nor_pm_action(const struct device *dev, case PM_DEVICE_ACTION_SUSPEND: #ifndef CONFIG_PM_DEVICE_RUNTIME /* If PM_DEVICE_RUNTIME, we don't uninit after RESUME */ - rc = qspi_device_init(dev); - if (rc < 0) { - return rc; + ret = qspi_device_init(dev); + if (ret < 0) { + return ret; } #endif @@ -1413,35 +1411,35 @@ static int qspi_nor_pm_action(const struct device *dev, return -EBUSY; } - rc = enter_dpd(dev); - if (rc < 0) { - return rc; + ret = enter_dpd(dev); + if (ret < 0) { + return ret; } nrfx_qspi_uninit(); - rc = pinctrl_apply_state(dev_config->pcfg, + ret = pinctrl_apply_state(dev_config->pcfg, PINCTRL_STATE_SLEEP); - if (rc < 0) { - return rc; + if (ret < 0) { + return ret; } break; case PM_DEVICE_ACTION_RESUME: - rc = pinctrl_apply_state(dev_config->pcfg, + ret = pinctrl_apply_state(dev_config->pcfg, PINCTRL_STATE_DEFAULT); - if (rc < 0) { - return rc; + if (ret < 0) { + return ret; } - res = nrfx_qspi_init(&dev_config->nrfx_cfg, + err = nrfx_qspi_init(&dev_config->nrfx_cfg, qspi_handler, dev_data); - if (res != NRFX_SUCCESS) { + if (err != NRFX_SUCCESS) { return -EIO; } - rc = exit_dpd(dev); - if (rc < 0) { - return rc; + ret = exit_dpd(dev); + if (ret < 0) { + return ret; } #ifndef CONFIG_PM_DEVICE_RUNTIME @@ -1461,16 +1459,16 @@ static int qspi_nor_pm_action(const struct device *dev, void z_impl_nrf_qspi_nor_xip_enable(const struct device *dev, bool enable) { struct qspi_nor_data *dev_data = dev->data; - int rc; + int ret; if (dev_data->xip_enabled == enable) { return; } - rc = qspi_device_init(dev); + ret = qspi_device_init(dev); - if (rc != 0) { - LOG_ERR("NRF QSPI NOR XIP %s failed with %d\n", enable ? "enable" : "disable", rc); + if (ret != 0) { + LOG_ERR("NRF QSPI NOR XIP %s failed with %d\n", enable ? "enable" : "disable", ret); return; } From a9202011d3880f884c515b89c7b1c519d9678469 Mon Sep 17 00:00:00 2001 From: Robert Lubos Date: Tue, 6 Feb 2024 11:07:30 +0100 Subject: [PATCH 3667/3723] Revert "[nrf fromtree] drivers: nrf_qspi_nor: Prevent reading status before sending RDPD" This reverts commit de501648fc3071d44bb0b6169c09ad9ed3d71b19. Signed-off-by: Robert Lubos --- drivers/flash/nrf_qspi_nor.c | 27 ++++----------------------- 1 file changed, 4 insertions(+), 23 deletions(-) diff --git a/drivers/flash/nrf_qspi_nor.c b/drivers/flash/nrf_qspi_nor.c index 467d0643d48..28c705f6707 100644 --- a/drivers/flash/nrf_qspi_nor.c +++ b/drivers/flash/nrf_qspi_nor.c @@ -1339,34 +1339,15 @@ static int enter_dpd(const struct device *const dev) static int exit_dpd(const struct device *const dev) { if (IS_ENABLED(DT_INST_PROP(0, has_dpd))) { - nrf_qspi_pins_t pins; - nrf_qspi_pins_t disconnected_pins = { - .sck_pin = NRF_QSPI_PIN_NOT_CONNECTED, - .csn_pin = NRF_QSPI_PIN_NOT_CONNECTED, - .io0_pin = NRF_QSPI_PIN_NOT_CONNECTED, - .io1_pin = NRF_QSPI_PIN_NOT_CONNECTED, - .io2_pin = NRF_QSPI_PIN_NOT_CONNECTED, - .io3_pin = NRF_QSPI_PIN_NOT_CONNECTED, - }; struct qspi_cmd cmd = { .op_code = SPI_NOR_CMD_RDPD, }; uint32_t t_exit_dpd = DT_INST_PROP_OR(0, t_exit_dpd, 0); - nrfx_err_t res; - int rc; - - nrf_qspi_pins_get(NRF_QSPI, &pins); - nrf_qspi_pins_set(NRF_QSPI, &disconnected_pins); - res = nrfx_qspi_activate(true); - nrf_qspi_pins_set(NRF_QSPI, &pins); - - if (res != NRFX_SUCCESS) { - return -EIO; - } + int ret; - rc = qspi_send_cmd(dev, &cmd, false); - if (rc < 0) { - return rc; + ret = qspi_send_cmd(dev, &cmd, false); + if (ret < 0) { + return ret; } if (t_exit_dpd) { From a271d25fc911355be1af660e2ef94d49ecd18b97 Mon Sep 17 00:00:00 2001 From: Robert Lubos Date: Tue, 6 Feb 2024 11:07:30 +0100 Subject: [PATCH 3668/3723] Revert "[nrf fromtree] tfm: Enforce initial attestation with required key provisioned" This reverts commit cf3cec5e97911a6a1e4b4d1b93b48f2508a46d34. Signed-off-by: Robert Lubos --- boards/arm/b_u585i_iot02a/Kconfig.defconfig | 4 ---- modules/trusted-firmware-m/Kconfig.tfm | 8 -------- modules/trusted-firmware-m/Kconfig.tfm.partitions | 1 - 3 files changed, 13 deletions(-) diff --git a/boards/arm/b_u585i_iot02a/Kconfig.defconfig b/boards/arm/b_u585i_iot02a/Kconfig.defconfig index 6b3b72554ff..e8224106dae 100644 --- a/boards/arm/b_u585i_iot02a/Kconfig.defconfig +++ b/boards/arm/b_u585i_iot02a/Kconfig.defconfig @@ -18,10 +18,6 @@ config USE_DT_CODE_PARTITION if BUILD_WITH_TFM -# Initial Attestation key provisioned by the BL1 bootloader -config TFM_INITIAL_ATTESTATION_KEY - default y - config TFM_DUMMY_PROVISIONING default n diff --git a/modules/trusted-firmware-m/Kconfig.tfm b/modules/trusted-firmware-m/Kconfig.tfm index a0d71328540..fed6ae4f485 100644 --- a/modules/trusted-firmware-m/Kconfig.tfm +++ b/modules/trusted-firmware-m/Kconfig.tfm @@ -179,7 +179,6 @@ config TFM_PARTITION_PLATFORM_CUSTOM_REBOOT config TFM_DUMMY_PROVISIONING bool "Provision with dummy values. NOT to be used in production" - select TFM_INITIAL_ATTESTATION_KEY default y help If this option is enabled (as it is by default), a set of dummy @@ -189,13 +188,6 @@ config TFM_DUMMY_PROVISIONING This option MUST not be used in production hardware, as the keys are insecure. -config TFM_INITIAL_ATTESTATION_KEY - bool - help - Hidden option to mark that the TF-M platform has an initial - attestation key, which is a requirement for the Initial Attestation - partition. - config TFM_BL2_NOT_SUPPORTED bool help diff --git a/modules/trusted-firmware-m/Kconfig.tfm.partitions b/modules/trusted-firmware-m/Kconfig.tfm.partitions index 67b46f5328b..cd9aaadb1ec 100644 --- a/modules/trusted-firmware-m/Kconfig.tfm.partitions +++ b/modules/trusted-firmware-m/Kconfig.tfm.partitions @@ -44,7 +44,6 @@ config TFM_PARTITION_CRYPTO config TFM_PARTITION_INITIAL_ATTESTATION bool "Secure partition 'Initial Attestation'" depends on TFM_PARTITION_CRYPTO - depends on TFM_INITIAL_ATTESTATION_KEY default n help Setting this option will cause '-DTFM_PARTITION_INITIAL_ATTESTATION' From 82251dcadac4304f49e0f2e191f51b4c99eefa00 Mon Sep 17 00:00:00 2001 From: Robert Lubos Date: Tue, 6 Feb 2024 11:07:31 +0100 Subject: [PATCH 3669/3723] Revert "[nrf fromtree] tfm: Harded build against TF-M built with unsecure keys" This reverts commit 80251a66e6ddacbd9fc2855f2ae5fd25c0e1a143. Signed-off-by: Robert Lubos --- boards/arm/b_u585i_iot02a/Kconfig.defconfig | 7 ------- modules/trusted-firmware-m/CMakeLists.txt | 17 +---------------- modules/trusted-firmware-m/Kconfig.tfm | 11 ----------- scripts/kconfig/hardened.csv | 1 - 4 files changed, 1 insertion(+), 35 deletions(-) diff --git a/boards/arm/b_u585i_iot02a/Kconfig.defconfig b/boards/arm/b_u585i_iot02a/Kconfig.defconfig index e8224106dae..ae1e57aba8e 100644 --- a/boards/arm/b_u585i_iot02a/Kconfig.defconfig +++ b/boards/arm/b_u585i_iot02a/Kconfig.defconfig @@ -16,11 +16,4 @@ config SPI_STM32_INTERRUPT config USE_DT_CODE_PARTITION default y if TRUSTED_EXECUTION_NONSECURE -if BUILD_WITH_TFM - -config TFM_DUMMY_PROVISIONING - default n - -endif # BUILD_WITH_TFM - endif # BOARD_B_U585I_IOT02A diff --git a/modules/trusted-firmware-m/CMakeLists.txt b/modules/trusted-firmware-m/CMakeLists.txt index ad1109d849b..177a47e28d6 100644 --- a/modules/trusted-firmware-m/CMakeLists.txt +++ b/modules/trusted-firmware-m/CMakeLists.txt @@ -95,12 +95,6 @@ if (CONFIG_BUILD_WITH_TFM) list(APPEND TFM_CMAKE_ARGS -DMCUBOOT_IMAGE_NUMBER=${CONFIG_TFM_MCUBOOT_IMAGE_NUMBER}) endif() - if (CONFIG_TFM_DUMMY_PROVISIONING) - list(APPEND TFM_CMAKE_ARGS -DTFM_DUMMY_PROVISIONING=ON) - else() - list(APPEND TFM_CMAKE_ARGS -DTFM_DUMMY_PROVISIONING=OFF) - endif() - if (CONFIG_TFM_EXCEPTION_INFO_DUMP) list(APPEND TFM_CMAKE_ARGS -DTFM_EXCEPTION_INFO_DUMP=ON) else() @@ -585,13 +579,4 @@ if (CONFIG_BUILD_WITH_TFM) ${MERGED_FILE} ) endif() - - if(CONFIG_TFM_DUMMY_PROVISIONING) - message(WARNING - "TFM_DUMMY_PROVISIONING is enabled: - The device will be provisioned using dummy keys and is NOT secure! - This is not suitable for production" - ) - endif() - -endif() # CONFIG_BUILD_WITH_TFM +endif() diff --git a/modules/trusted-firmware-m/Kconfig.tfm b/modules/trusted-firmware-m/Kconfig.tfm index fed6ae4f485..b635347b6e1 100644 --- a/modules/trusted-firmware-m/Kconfig.tfm +++ b/modules/trusted-firmware-m/Kconfig.tfm @@ -177,17 +177,6 @@ config TFM_PARTITION_PLATFORM_CUSTOM_REBOOT Instead the application will have to override the weak ARM implementation of sys_arch_reset(). -config TFM_DUMMY_PROVISIONING - bool "Provision with dummy values. NOT to be used in production" - default y - help - If this option is enabled (as it is by default), a set of dummy - keys / data will be provisioned. The dummy IAK matches the IAK tested - by the TF-M tests, and the dummy bl2 ROTPKs match the dummy bl2 keys - used by default. - This option MUST not be used in production hardware, as the keys are - insecure. - config TFM_BL2_NOT_SUPPORTED bool help diff --git a/scripts/kconfig/hardened.csv b/scripts/kconfig/hardened.csv index 6cc978f7e56..ee95b54b3a7 100644 --- a/scripts/kconfig/hardened.csv +++ b/scripts/kconfig/hardened.csv @@ -39,7 +39,6 @@ TEST_RANDOM_GENERATOR,n TEST_SHELL,n TEST_USERSPACE,n TFM_CMAKE_BUILD_TYPE_DEBUG,n -TFM_DUMMY_PROVISIONING,n THREAD_MONITOR,n THREAD_NAME,n TIMER_RANDOM_GENERATOR,n From a9645cfeedabd47991eb95257643c46d93e8ce1b Mon Sep 17 00:00:00 2001 From: Robert Lubos Date: Tue, 6 Feb 2024 11:07:31 +0100 Subject: [PATCH 3670/3723] Revert "[nrf fromlist] soc: nordic_nrf: Enable the TF-M NS storage partition for nordic boards" This reverts commit 8e3a9faff9e21e2f92bc3f7a01bd77311c58087c. Signed-off-by: Robert Lubos --- soc/arm/nordic_nrf/CMakeLists.txt | 4 ---- soc/arm/nordic_nrf/Kconfig | 4 ---- 2 files changed, 8 deletions(-) diff --git a/soc/arm/nordic_nrf/CMakeLists.txt b/soc/arm/nordic_nrf/CMakeLists.txt index 3b097d73569..47364b35ffb 100644 --- a/soc/arm/nordic_nrf/CMakeLists.txt +++ b/soc/arm/nordic_nrf/CMakeLists.txt @@ -25,8 +25,4 @@ if(CONFIG_BUILD_WITH_TFM) set_property(TARGET zephyr_property_target APPEND PROPERTY TFM_CMAKE_OPTIONS -DZEPHYR_BASE=${ZEPHYR_BASE} ) - - set_property(TARGET zephyr_property_target - APPEND PROPERTY TFM_CMAKE_OPTIONS -DNRF_NS_STORAGE=${CONFIG_TFM_NRF_NS_STORAGE} - ) endif() diff --git a/soc/arm/nordic_nrf/Kconfig b/soc/arm/nordic_nrf/Kconfig index 0372492cd7d..19e49c05454 100644 --- a/soc/arm/nordic_nrf/Kconfig +++ b/soc/arm/nordic_nrf/Kconfig @@ -45,10 +45,6 @@ config TFM_LOG_LEVEL_SILENCE Disable TF-M secure output if the uart1 node has not assigned GPIO pins using pinctrl. -config TFM_NRF_NS_STORAGE - bool "TF-M non-secure storage partition" - default y - endif # BUILD_WITH_TFM From 38aa4b351ebb2bcf4059ad9b0bed12616e0d6bec Mon Sep 17 00:00:00 2001 From: Robert Lubos Date: Tue, 6 Feb 2024 11:07:31 +0100 Subject: [PATCH 3671/3723] Revert "[nrf fromtree] net: openthread: Openthread upmerge to `4ed44bc`" This reverts commit 414a63955a3e0e60301b1970266b7c659553eff3. Signed-off-by: Robert Lubos --- modules/openthread/CMakeLists.txt | 6 ------ modules/openthread/Kconfig.features | 3 --- west.yml | 2 +- 3 files changed, 1 insertion(+), 10 deletions(-) diff --git a/modules/openthread/CMakeLists.txt b/modules/openthread/CMakeLists.txt index 646b086ef1e..8afa1aec440 100644 --- a/modules/openthread/CMakeLists.txt +++ b/modules/openthread/CMakeLists.txt @@ -340,12 +340,6 @@ else() set(OT_MLR OFF CACHE BOOL "Enable Multicast Listener Registration feature for Thread 1.2" FORCE) endif() -if(CONFIG_OPENTHREAD_MULTIPAN_RCP) - set(OT_MULTIPAN_RCP ON CACHE BOOL "Enable Multi-PAN RCP" FORCE) -else() - set(OT_MULTIPAN_RCP OFF CACHE BOOL "Enable Multi-PAN RCP" FORCE) -endif() - if(CONFIG_OPENTHREAD_MULTIPLE_INSTANCE) set(OT_MULTIPLE_INSTANCE ON CACHE BOOL "Enable multiple instances" FORCE) else() diff --git a/modules/openthread/Kconfig.features b/modules/openthread/Kconfig.features index 2be5332cde3..bd8a05ed9b9 100644 --- a/modules/openthread/Kconfig.features +++ b/modules/openthread/Kconfig.features @@ -218,9 +218,6 @@ config OPENTHREAD_MLR help Enable Multicast Listener Registration support for Thread 1.2 -config OPENTHREAD_MULTIPAN_RCP - bool "OpenThread multipan rcp" - config OPENTHREAD_MULTIPLE_INSTANCE bool "OpenThread multiple instances" diff --git a/west.yml b/west.yml index c99118074eb..ed84e713620 100644 --- a/west.yml +++ b/west.yml @@ -301,7 +301,7 @@ manifest: revision: 214f9fc1539f8e5937c0474cb6ee29b6dcb2d4b8 path: modules/lib/open-amp - name: openthread - revision: 4ed44bc7d58d9a98c6cca13a50d38129045ab3df + revision: 193e77e40ec2387d458eaebd1e03902d86f484a5 path: modules/lib/openthread - name: percepio path: modules/debug/percepio From 85c3694c4bf8e5bfa5e1081610a454af6a982b37 Mon Sep 17 00:00:00 2001 From: Robert Lubos Date: Tue, 6 Feb 2024 11:07:31 +0100 Subject: [PATCH 3672/3723] Revert "[nrf fromlist] manifest: hal_nordic: Update revision with fixed workaround in nrfx_qspi" This reverts commit 85997eb5ce6d0dcebdc02488e347b0dc59aa2303. Signed-off-by: Robert Lubos --- west.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/west.yml b/west.yml index ed84e713620..14847109194 100644 --- a/west.yml +++ b/west.yml @@ -183,7 +183,7 @@ manifest: groups: - hal - name: hal_nordic - revision: b9633ecea67bf52925d4c61455046223b46402b1 + revision: 56e0b052dff311c2f8eb08c6804e60fc79feb56f path: modules/hal/nordic groups: - hal From 963aed8ac9c239462282cb353bfbe1a51670dcdd Mon Sep 17 00:00:00 2001 From: Robert Lubos Date: Tue, 6 Feb 2024 11:07:31 +0100 Subject: [PATCH 3673/3723] Revert "[nrf fromtree] scripts/pylib/twister/twisterlib: Support multiple `--pytest-args`" This reverts commit 2837a3c6bd07e5920bfd0dcbab9392086f1769f3. Signed-off-by: Robert Lubos --- doc/develop/test/pytest.rst | 2 -- .../pylib/twister/twisterlib/environment.py | 3 +-- scripts/pylib/twister/twisterlib/harness.py | 19 +++++++++---------- .../pytest_integration/test_harness_pytest.py | 5 ++--- 4 files changed, 12 insertions(+), 17 deletions(-) diff --git a/doc/develop/test/pytest.rst b/doc/develop/test/pytest.rst index f6ba54fa52e..f3db6fcee89 100644 --- a/doc/develop/test/pytest.rst +++ b/doc/develop/test/pytest.rst @@ -67,8 +67,6 @@ For instance, one can use a command: --pytest-args='-k test_shell_print_version' -Note that ``--pytest-args`` can be passed multiple times to pass several arguments to the pytest. - Helpers & fixtures ================== diff --git a/scripts/pylib/twister/twisterlib/environment.py b/scripts/pylib/twister/twisterlib/environment.py index 16e19c85fec..b7e11406cd4 100644 --- a/scripts/pylib/twister/twisterlib/environment.py +++ b/scripts/pylib/twister/twisterlib/environment.py @@ -216,8 +216,7 @@ def add_parse_arguments(parser = None): and 'fifo_loop' is a name of a function found in main.c without test prefix. """) - parser.add_argument( - "--pytest-args", action="append", + parser.add_argument("--pytest-args", help="""Pass additional arguments to the pytest subprocess. This parameter will override the pytest_args from the harness_config in YAML file. """) diff --git a/scripts/pylib/twister/twisterlib/harness.py b/scripts/pylib/twister/twisterlib/harness.py index 8b8ad92fc51..dece1673c7a 100644 --- a/scripts/pylib/twister/twisterlib/harness.py +++ b/scripts/pylib/twister/twisterlib/harness.py @@ -326,6 +326,15 @@ def generate_command(self): command.extend([os.path.normpath(os.path.join( self.source_dir, os.path.expanduser(os.path.expandvars(src)))) for src in pytest_root]) + if handler.options.pytest_args: + command.append(handler.options.pytest_args) + if pytest_args_yaml: + logger.warning(f'The pytest_args ({handler.options.pytest_args}) specified ' + 'in the command line will override the pytest_args defined ' + f'in the YAML file {pytest_args_yaml}') + else: + command.extend(pytest_args_yaml) + if pytest_dut_scope: command.append(f'--dut-scope={pytest_dut_scope}') @@ -345,16 +354,6 @@ def generate_command(self): command.append('--device-type=custom') else: raise PytestHarnessException(f'Handling of handler {handler.type_str} not implemented yet') - - if handler.options.pytest_args: - command.extend(handler.options.pytest_args) - if pytest_args_yaml: - logger.warning(f'The pytest_args ({handler.options.pytest_args}) specified ' - 'in the command line will override the pytest_args defined ' - f'in the YAML file {pytest_args_yaml}') - else: - command.extend(pytest_args_yaml) - return command def _generate_parameters_for_hardware(self, handler: Handler): diff --git a/scripts/tests/twister/pytest_integration/test_harness_pytest.py b/scripts/tests/twister/pytest_integration/test_harness_pytest.py index befd384be37..fc60b99e0d1 100644 --- a/scripts/tests/twister/pytest_integration/test_harness_pytest.py +++ b/scripts/tests/twister/pytest_integration/test_harness_pytest.py @@ -71,13 +71,12 @@ def test_pytest_command_extra_args(testinstance: TestInstance): def test_pytest_command_extra_args_in_options(testinstance: TestInstance): pytest_harness = Pytest() pytest_args_from_yaml = '-k test_from_yaml' - pytest_args_from_cmd = ['-k', 'test_from_cmd'] + pytest_args_from_cmd = '-k test_from_cmd' testinstance.testsuite.harness_config['pytest_args'] = [pytest_args_from_yaml] testinstance.handler.options.pytest_args = pytest_args_from_cmd pytest_harness.configure(testinstance) command = pytest_harness.generate_command() - assert pytest_args_from_cmd[0] in command - assert pytest_args_from_cmd[1] in command + assert pytest_args_from_cmd in command assert pytest_args_from_yaml not in command From 4b559a8c56f236f12955cb6f626215251835ded4 Mon Sep 17 00:00:00 2001 From: Robert Lubos Date: Tue, 6 Feb 2024 11:07:32 +0100 Subject: [PATCH 3674/3723] Revert "[nrf fromtree] twister: pytest: Add --pytest-args to Twister command line" This reverts commit 130824afa4d94bf56a6c3ea9e83384744eb7d9c4. Signed-off-by: Robert Lubos --- doc/develop/test/pytest.rst | 10 --- .../pylib/twister/twisterlib/environment.py | 5 -- scripts/pylib/twister/twisterlib/harness.py | 19 ++---- .../pytest_integration/test_harness_pytest.py | 66 ------------------- 4 files changed, 4 insertions(+), 96 deletions(-) diff --git a/doc/develop/test/pytest.rst b/doc/develop/test/pytest.rst index f3db6fcee89..e644882191e 100644 --- a/doc/develop/test/pytest.rst +++ b/doc/develop/test/pytest.rst @@ -56,16 +56,6 @@ Pytest scans the given locations looking for tests, following its default `discovery rules `_ One can also pass some extra arguments to the pytest from yaml file using ``pytest_args`` keyword under ``harness_config``, e.g.: ``pytest_args: [‘-k=test_method’, ‘--log-level=DEBUG’]``. -There is also an option to pass ``--pytest-args`` through Twister command line parameters. -This can be particularly useful when one wants to select a specific testcase from a test suite. -For instance, one can use a command: - -.. code-block:: console - - $ ./scripts/twister --platform native_sim -T samples/subsys/testsuite/pytest/shell \ - -s samples/subsys/testsuite/pytest/shell/sample.pytest.shell \ - --pytest-args='-k test_shell_print_version' - Helpers & fixtures ================== diff --git a/scripts/pylib/twister/twisterlib/environment.py b/scripts/pylib/twister/twisterlib/environment.py index b7e11406cd4..86965f1f9cf 100644 --- a/scripts/pylib/twister/twisterlib/environment.py +++ b/scripts/pylib/twister/twisterlib/environment.py @@ -216,11 +216,6 @@ def add_parse_arguments(parser = None): and 'fifo_loop' is a name of a function found in main.c without test prefix. """) - parser.add_argument("--pytest-args", - help="""Pass additional arguments to the pytest subprocess. This parameter - will override the pytest_args from the harness_config in YAML file. - """) - valgrind_asan_group.add_argument( "--enable-valgrind", action="store_true", help="""Run binary through valgrind and check for several memory access diff --git a/scripts/pylib/twister/twisterlib/harness.py b/scripts/pylib/twister/twisterlib/harness.py index dece1673c7a..052def7162a 100644 --- a/scripts/pylib/twister/twisterlib/harness.py +++ b/scripts/pylib/twister/twisterlib/harness.py @@ -309,9 +309,8 @@ def pytest_run(self, timeout): def generate_command(self): config = self.instance.testsuite.harness_config - handler: Handler = self.instance.handler pytest_root = config.get('pytest_root', ['pytest']) if config else ['pytest'] - pytest_args_yaml = config.get('pytest_args', []) if config else [] + pytest_args = config.get('pytest_args', []) if config else [] pytest_dut_scope = config.get('pytest_dut_scope', None) if config else None command = [ 'pytest', @@ -325,19 +324,12 @@ def generate_command(self): ] command.extend([os.path.normpath(os.path.join( self.source_dir, os.path.expanduser(os.path.expandvars(src)))) for src in pytest_root]) - - if handler.options.pytest_args: - command.append(handler.options.pytest_args) - if pytest_args_yaml: - logger.warning(f'The pytest_args ({handler.options.pytest_args}) specified ' - 'in the command line will override the pytest_args defined ' - f'in the YAML file {pytest_args_yaml}') - else: - command.extend(pytest_args_yaml) - + command.extend(pytest_args) if pytest_dut_scope: command.append(f'--dut-scope={pytest_dut_scope}') + handler: Handler = self.instance.handler + if handler.options.verbose > 1: command.extend([ '--log-cli-level=DEBUG', @@ -497,9 +489,6 @@ def _parse_report_file(self, report): tc.status = 'error' tc.reason = elem.get('message') tc.output = elem.text - else: - self.state = 'skipped' - self.instance.reason = 'No tests collected' class Gtest(Harness): diff --git a/scripts/tests/twister/pytest_integration/test_harness_pytest.py b/scripts/tests/twister/pytest_integration/test_harness_pytest.py index fc60b99e0d1..150980059b3 100644 --- a/scripts/tests/twister/pytest_integration/test_harness_pytest.py +++ b/scripts/tests/twister/pytest_integration/test_harness_pytest.py @@ -25,7 +25,6 @@ def testinstance() -> TestInstance: testinstance.handler = mock.Mock() testinstance.handler.options = mock.Mock() testinstance.handler.options.verbose = 1 - testinstance.handler.options.pytest_args = None testinstance.handler.type_str = 'native' return testinstance @@ -68,18 +67,6 @@ def test_pytest_command_extra_args(testinstance: TestInstance): assert c in command -def test_pytest_command_extra_args_in_options(testinstance: TestInstance): - pytest_harness = Pytest() - pytest_args_from_yaml = '-k test_from_yaml' - pytest_args_from_cmd = '-k test_from_cmd' - testinstance.testsuite.harness_config['pytest_args'] = [pytest_args_from_yaml] - testinstance.handler.options.pytest_args = pytest_args_from_cmd - pytest_harness.configure(testinstance) - command = pytest_harness.generate_command() - assert pytest_args_from_cmd in command - assert pytest_args_from_yaml not in command - - @pytest.mark.parametrize( ('pytest_root', 'expected'), [ @@ -235,56 +222,3 @@ def test_skip_2(): assert len(testinstance.testcases) == 2 for tc in testinstance.testcases: assert tc.status == "skipped" - - -def test_if_report_with_filter(pytester, testinstance: TestInstance): - test_file_content = textwrap.dedent(""" - import pytest - def test_A(): - pass - def test_B(): - pass - """) - test_file = pytester.path / 'test_filter.py' - test_file.write_text(test_file_content) - report_file = pytester.path / 'report.xml' - result = pytester.runpytest( - str(test_file), - '-k', 'test_B', - f'--junit-xml={str(report_file)}' - ) - result.assert_outcomes(passed=1) - assert report_file.is_file() - - pytest_harness = Pytest() - pytest_harness.configure(testinstance) - pytest_harness.report_file = report_file - pytest_harness._update_test_status() - assert pytest_harness.state == "passed" - assert testinstance.status == "passed" - assert len(testinstance.testcases) == 1 - - -def test_if_report_with_no_collected(pytester, testinstance: TestInstance): - test_file_content = textwrap.dedent(""" - import pytest - def test_A(): - pass - """) - test_file = pytester.path / 'test_filter.py' - test_file.write_text(test_file_content) - report_file = pytester.path / 'report.xml' - result = pytester.runpytest( - str(test_file), - '-k', 'test_B', - f'--junit-xml={str(report_file)}' - ) - result.assert_outcomes(passed=0) - assert report_file.is_file() - - pytest_harness = Pytest() - pytest_harness.configure(testinstance) - pytest_harness.report_file = report_file - pytest_harness._update_test_status() - assert pytest_harness.state == "skipped" - assert testinstance.status == "skipped" From 9483d334f927d5eb1887ffd9aebead46be57401a Mon Sep 17 00:00:00 2001 From: Robert Lubos Date: Tue, 6 Feb 2024 11:07:32 +0100 Subject: [PATCH 3675/3723] Revert "[nrf fromlist] wifi: shell: Add long arguments to help" This reverts commit 893e58ca65abc6f5da237733ef7a4ebdecb0bc29. Signed-off-by: Robert Lubos --- subsys/net/l2/wifi/wifi_shell.c | 52 ++++++++++++++++----------------- 1 file changed, 26 insertions(+), 26 deletions(-) diff --git a/subsys/net/l2/wifi/wifi_shell.c b/subsys/net/l2/wifi/wifi_shell.c index c5b8f60d933..d0cd0551897 100644 --- a/subsys/net/l2/wifi/wifi_shell.c +++ b/subsys/net/l2/wifi/wifi_shell.c @@ -1275,10 +1275,10 @@ void parse_mode_args_to_params(const struct shell *sh, int argc, int opt; int option_index = 0; - static struct option long_options[] = {{"if-index", optional_argument, 0, 'i'}, + static struct option long_options[] = {{"if_index", optional_argument, 0, 'i'}, {"sta", no_argument, 0, 's'}, {"monitor", no_argument, 0, 'm'}, - {"tx-injection", no_argument, 0, 't'}, + {"TX-injection", no_argument, 0, 't'}, {"promiscuous", no_argument, 0, 'p'}, {"ap", no_argument, 0, 'a'}, {"softap", no_argument, 0, 'k'}, @@ -1385,7 +1385,7 @@ void parse_channel_args_to_params(const struct shell *sh, int argc, int opt; int option_index = 0; - static struct option long_options[] = {{"if-index", optional_argument, 0, 'i'}, + static struct option long_options[] = {{"if_index", optional_argument, 0, 'i'}, {"channel", required_argument, 0, 'c'}, {"get", no_argument, 0, 'g'}, {"help", no_argument, 0, 'h'}, @@ -1491,8 +1491,8 @@ void parse_filter_args_to_params(const struct shell *sh, int argc, int opt; int option_index = 0; - static struct option long_options[] = {{"if-index", optional_argument, 0, 'i'}, - {"capture-len", optional_argument, 0, 'b'}, + static struct option long_options[] = {{"if_index", optional_argument, 0, 'i'}, + {"capture_len", optional_argument, 0, 'b'}, {"all", no_argument, 0, 'a'}, {"mgmt", no_argument, 0, 'm'}, {"ctrl", no_argument, 0, 'c'}, @@ -1683,15 +1683,15 @@ SHELL_STATIC_SUBCMD_SET_CREATE(wifi_commands, SHELL_CMD_ARG(mode, NULL, "mode operational setting\n" "This command may be used to set the Wi-Fi device into a specific mode of operation\n" "parameters:" - "[-i, --if-index ] : Interface index.\n" - "[-s, --sta] : Station mode.\n" - "[-m, --monitor] : Monitor mode.\n" - "[-p, --promiscuous] : Promiscuous mode.\n" - "[-t, --tx-injection] : TX-Injection mode.\n" - "[-a, --ap] : AP mode.\n" - "[-k, --softap] : Softap mode.\n" - "[-h, --help] : Help.\n" - "[-g, --get] : Get current mode for a specific interface index.\n" + "[-i] : Interface index - optional argument\n" + "[-s] : Station mode.\n" + "[-m] : Monitor mode.\n" + "[-p] : Promiscuous mode.\n" + "[-t] : TX-Injection mode.\n" + "[-a] : AP mode.\n" + "[-k] : Softap mode.\n" + "[-h] : Help.\n" + "[-g] : Get current mode for a specific interface index.\n" "Usage: Get operation example for interface index 1\n" "wifi mode -g -i1\n" "Set operation example for interface index 1 - set station+promiscuous\n" @@ -1703,14 +1703,14 @@ SHELL_STATIC_SUBCMD_SET_CREATE(wifi_commands, "monitor, TX-Injection and promiscuous mode is enabled.\n" "The different packet filter modes are control, management, data and enable all filters\n" "parameters:" - "[-i, --if-index ] : Interface index.\n" - "[-a, --all] : Enable all packet filter modes\n" - "[-m, --mgmt] : Enable management packets to allowed up the stack.\n" - "[-c, --ctrl] : Enable control packets to be allowed up the stack.\n" - "[-d, --data] : Enable Data packets to be allowed up the stack.\n" - "[-g, --get] : Get current filter settings for a specific interface index.\n" - "[-b, --capture-len ] : Capture length buffer size for each packet to be captured\n" - "[-h, --help] : Help.\n" + "[-i] : Interface index - optional argument.\n" + "[-a] : Enable all packet filter modes\n" + "[-m] : Enable management packets to allowed up the stack.\n" + "[-c] : Enable control packets to be allowed up the stack.\n" + "[-d] : Enable Data packets to be allowed up the stack.\n" + "[-g] : Get current filter settings for a specific interface index.\n" + "<-b> : Capture length buffer size for each packet to be captured - optional argument.\n" + "<-h> : Help.\n" "Usage: Get operation example for interface index 1\n" "wifi packet_filter -g -i1\n" "Set operation example for interface index 1 - set data+management frame filter\n" @@ -1722,10 +1722,10 @@ SHELL_STATIC_SUBCMD_SET_CREATE(wifi_commands, "monitor or TX-Injection mode is enabled.\n" "Currently 20 MHz is only supported and no BW parameter is provided\n" "parameters:" - "[-i, --if-index ] : Interface index.\n" - "[-c, --channel ] : Set a specific channel number to the lower layer.\n" - "[-g, --get] : Get current set channel number from the lower layer.\n" - "[-h, --help] : Help.\n" + "[-i] : Interface index - optional argument.\n" + "[-c] : Set a specific channel number to the lower layer.\n" + "[-g] : Get current set channel number from the lower layer.\n" + "[-h] : Help.\n" "Usage: Get operation example for interface index 1\n" "wifi channel -g -i1\n" "Set operation example for interface index 1 (setting channel 5)\n" From f9fe43d1701544756d1223cc9627ea91f4d4b8e8 Mon Sep 17 00:00:00 2001 From: Robert Lubos Date: Tue, 6 Feb 2024 11:07:32 +0100 Subject: [PATCH 3676/3723] Revert "[nrf fromlist] wifi: shell: Enforce argument count checks" This reverts commit 4ffdc9cb53bf752a13a6ee1ef6ad3f08b96159d1. Signed-off-by: Robert Lubos --- subsys/net/l2/wifi/wifi_shell.c | 74 +++++++++++++-------------------- 1 file changed, 30 insertions(+), 44 deletions(-) diff --git a/subsys/net/l2/wifi/wifi_shell.c b/subsys/net/l2/wifi/wifi_shell.c index d0cd0551897..767ac3eaf05 100644 --- a/subsys/net/l2/wifi/wifi_shell.c +++ b/subsys/net/l2/wifi/wifi_shell.c @@ -1598,43 +1598,37 @@ static int cmd_wifi_packet_filter(const struct shell *sh, size_t argc, char *arg } SHELL_STATIC_SUBCMD_SET_CREATE(wifi_cmd_ap, - SHELL_CMD_ARG(disable, NULL, + SHELL_CMD(disable, NULL, "Disable Access Point mode", - cmd_wifi_ap_disable, - 1, 0), - SHELL_CMD_ARG(enable, NULL, " [channel] [PSK]", - cmd_wifi_ap_enable, - 2, 1), + cmd_wifi_ap_disable), + SHELL_CMD(enable, NULL, " [channel] [PSK]", + cmd_wifi_ap_enable), SHELL_SUBCMD_SET_END ); SHELL_STATIC_SUBCMD_SET_CREATE(wifi_twt_ops, - SHELL_CMD_ARG(quick_setup, NULL, " Start a TWT flow with defaults:\n" + SHELL_CMD(quick_setup, NULL, " Start a TWT flow with defaults:\n" " \n", - cmd_wifi_twt_setup_quick, - 3, 0), - SHELL_CMD_ARG(setup, NULL, " Start a TWT flow:\n" + cmd_wifi_twt_setup_quick), + SHELL_CMD(setup, NULL, " Start a TWT flow:\n" "\n" "\n" " " " \n", - cmd_wifi_twt_setup, - 11, 0), - SHELL_CMD_ARG(teardown, NULL, " Teardown a TWT flow:\n" + cmd_wifi_twt_setup), + SHELL_CMD(teardown, NULL, " Teardown a TWT flow:\n" "\n" "\n" " \n", - cmd_wifi_twt_teardown, - 5, 0), - SHELL_CMD_ARG(teardown_all, NULL, " Teardown all TWT flows\n", - cmd_wifi_twt_teardown_all, - 1, 0), + cmd_wifi_twt_teardown), + SHELL_CMD(teardown_all, NULL, " Teardown all TWT flows\n", + cmd_wifi_twt_teardown_all), SHELL_SUBCMD_SET_END ); SHELL_STATIC_SUBCMD_SET_CREATE(wifi_commands, SHELL_CMD(ap, &wifi_cmd_ap, "Access Point mode commands", NULL), - SHELL_CMD_ARG(connect, NULL, + SHELL_CMD(connect, NULL, "Connect to a Wi-Fi AP\n" "\"\"\n" "[channel number: 0 means all]\n" @@ -1643,21 +1637,18 @@ SHELL_STATIC_SUBCMD_SET_CREATE(wifi_commands, "0:None, 1:WPA2-PSK, 2:WPA2-PSK-256, 3:SAE, 4:WAPI, 5:EAP, 6:WEP, 7: WPA-PSK\n" "[MFP (optional: needs security type to be specified)]\n" ": 0:Disable, 1:Optional, 2:Required", - cmd_wifi_connect, - 2, 5), - SHELL_CMD_ARG(disconnect, NULL, "Disconnect from the Wi-Fi AP", - cmd_wifi_disconnect, - 1, 0), - SHELL_CMD_ARG(ps, NULL, "Configure Wi-F PS on/off, no arguments will dump config", - cmd_wifi_ps, - 1, 1), + cmd_wifi_connect), + SHELL_CMD(disconnect, NULL, "Disconnect from the Wi-Fi AP", + cmd_wifi_disconnect), + SHELL_CMD(ps, NULL, "Configure Wi-F PS on/off, no arguments will dump config", + cmd_wifi_ps), SHELL_CMD_ARG(ps_mode, NULL, "\n", cmd_wifi_ps_mode, 2, 0), - SHELL_CMD_ARG(scan, NULL, + SHELL_CMD(scan, NULL, "Scan for Wi-Fi APs\n" "OPTIONAL PARAMETERS:\n" "[-t, --type ] : Preferred mode of scan. The actual mode of scan can depend on factors such as the Wi-Fi chip implementation, regulatory domain restrictions. Default type is active.\n" @@ -1668,19 +1659,17 @@ SHELL_STATIC_SUBCMD_SET_CREATE(wifi_commands, "[-m, --max_bss ] : Maximum BSSes to scan for. Range 1 - 65535.\n" "[-c, --chans ] : Channels to be scanned. The channels must be specified in the form band1:chan1,chan2_band2:chan3,..etc. band1, band2 must be valid band values and chan1, chan2, chan3 must be specified as a list of comma separated values where each value is either a single channel or a channel range specified as chan_start-chan_end. Each band channel set has to be separated by a _. For example, a valid channel specification can be 2:1,6-11,14_5:36,149-165,44\n" "[-h, --help] : Print out the help for the scan command.", - cmd_wifi_scan, - 1, 8), - SHELL_CMD_ARG(statistics, NULL, "Wi-Fi interface statistics", cmd_wifi_stats, 1, 0), - SHELL_CMD_ARG(status, NULL, "Status of the Wi-Fi interface", cmd_wifi_status, 1, 0), + cmd_wifi_scan), + SHELL_CMD(statistics, NULL, "Wi-Fi interface statistics", cmd_wifi_stats), + SHELL_CMD(status, NULL, "Status of the Wi-Fi interface", cmd_wifi_status), SHELL_CMD(twt, &wifi_twt_ops, "Manage TWT flows", NULL), - SHELL_CMD_ARG(reg_domain, NULL, + SHELL_CMD(reg_domain, NULL, "Set or Get Wi-Fi regulatory domain\n" "Usage: wifi reg_domain [ISO/IEC 3166-1 alpha2] [-f]\n" "[-f]: Force to use this regulatory hint over any other regulatory hints\n" "Note: This may cause regulatory compliance issues, use it at your own risk.", - cmd_wifi_reg_domain, - 2, 1), - SHELL_CMD_ARG(mode, NULL, "mode operational setting\n" + cmd_wifi_reg_domain), + SHELL_CMD(mode, NULL, "mode operational setting\n" "This command may be used to set the Wi-Fi device into a specific mode of operation\n" "parameters:" "[-i] : Interface index - optional argument\n" @@ -1696,9 +1685,8 @@ SHELL_STATIC_SUBCMD_SET_CREATE(wifi_commands, "wifi mode -g -i1\n" "Set operation example for interface index 1 - set station+promiscuous\n" "wifi mode -i1 -sp\n", - cmd_wifi_mode, - 1, 9), - SHELL_CMD_ARG(packet_filter, NULL, "mode filter setting\n" + cmd_wifi_mode), + SHELL_CMD(packet_filter, NULL, "mode filter setting\n" "This command is used to set packet filter setting when\n" "monitor, TX-Injection and promiscuous mode is enabled.\n" "The different packet filter modes are control, management, data and enable all filters\n" @@ -1715,9 +1703,8 @@ SHELL_STATIC_SUBCMD_SET_CREATE(wifi_commands, "wifi packet_filter -g -i1\n" "Set operation example for interface index 1 - set data+management frame filter\n" "wifi packet_filter -i1 -md\n", - cmd_wifi_packet_filter, - 1, 8), - SHELL_CMD_ARG(channel, NULL, "wifi channel setting\n" + cmd_wifi_packet_filter), + SHELL_CMD(channel, NULL, "wifi channel setting\n" "This command is used to set the channel when\n" "monitor or TX-Injection mode is enabled.\n" "Currently 20 MHz is only supported and no BW parameter is provided\n" @@ -1730,8 +1717,7 @@ SHELL_STATIC_SUBCMD_SET_CREATE(wifi_commands, "wifi channel -g -i1\n" "Set operation example for interface index 1 (setting channel 5)\n" "wifi -i1 -c5\n", - cmd_wifi_channel, - 1, 4), + cmd_wifi_channel), SHELL_CMD_ARG(ps_timeout, NULL, " - PS inactivity timer(in ms)", From b1365544c0e665ee65c2f2136facefd362795a5a Mon Sep 17 00:00:00 2001 From: Robert Lubos Date: Tue, 6 Feb 2024 11:07:32 +0100 Subject: [PATCH 3677/3723] Revert "[nrf fromlist] wifi: shell: Add missing security options" This reverts commit d20bbab16aec2aaca8ce716723c3fc641b9cedf8. Signed-off-by: Robert Lubos --- subsys/net/l2/wifi/wifi_shell.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/subsys/net/l2/wifi/wifi_shell.c b/subsys/net/l2/wifi/wifi_shell.c index 767ac3eaf05..cd3390828d1 100644 --- a/subsys/net/l2/wifi/wifi_shell.c +++ b/subsys/net/l2/wifi/wifi_shell.c @@ -1634,7 +1634,7 @@ SHELL_STATIC_SUBCMD_SET_CREATE(wifi_commands, "[channel number: 0 means all]\n" "[PSK: valid only for secure SSIDs]\n" "[Security type: valid only for secure SSIDs]\n" - "0:None, 1:WPA2-PSK, 2:WPA2-PSK-256, 3:SAE, 4:WAPI, 5:EAP, 6:WEP, 7: WPA-PSK\n" + "0:None, 1:PSK, 2:PSK-256, 3:SAE\n" "[MFP (optional: needs security type to be specified)]\n" ": 0:Disable, 1:Optional, 2:Required", cmd_wifi_connect), From 52613aec61ce2819b844de1c54a5d1dfe6c3faeb Mon Sep 17 00:00:00 2001 From: Robert Lubos Date: Tue, 6 Feb 2024 11:07:32 +0100 Subject: [PATCH 3678/3723] Revert "[nrf fromlist] wifi: shell: Fix PS mode help" This reverts commit b16198a61fb3225013e1b2a0791ed2289ff978c0. Signed-off-by: Robert Lubos --- subsys/net/l2/wifi/wifi_shell.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/subsys/net/l2/wifi/wifi_shell.c b/subsys/net/l2/wifi/wifi_shell.c index cd3390828d1..64f125dea01 100644 --- a/subsys/net/l2/wifi/wifi_shell.c +++ b/subsys/net/l2/wifi/wifi_shell.c @@ -1644,7 +1644,8 @@ SHELL_STATIC_SUBCMD_SET_CREATE(wifi_commands, cmd_wifi_ps), SHELL_CMD_ARG(ps_mode, NULL, - "\n", + "\n" + "", cmd_wifi_ps_mode, 2, 0), @@ -1732,7 +1733,8 @@ SHELL_STATIC_SUBCMD_SET_CREATE(wifi_commands, 0), SHELL_CMD_ARG(ps_wakeup_mode, NULL, - "\n", + " : Set PS wake up mode to DTIM interval\n" + " : Set PS wake up mode to listen interval", cmd_wifi_ps_wakeup_mode, 2, 0), From da12e69f8837778f25c0e7a6618306b82a85246a Mon Sep 17 00:00:00 2001 From: Robert Lubos Date: Tue, 6 Feb 2024 11:07:33 +0100 Subject: [PATCH 3679/3723] Revert "[nrf fromlist] wifi: shell: Fix brackets type for optional params" This reverts commit ea492ab1190b2fd08cba1119b40ee525bd0455ed. Signed-off-by: Robert Lubos --- subsys/net/l2/wifi/wifi_shell.c | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/subsys/net/l2/wifi/wifi_shell.c b/subsys/net/l2/wifi/wifi_shell.c index 64f125dea01..c50175e086f 100644 --- a/subsys/net/l2/wifi/wifi_shell.c +++ b/subsys/net/l2/wifi/wifi_shell.c @@ -1631,11 +1631,11 @@ SHELL_STATIC_SUBCMD_SET_CREATE(wifi_commands, SHELL_CMD(connect, NULL, "Connect to a Wi-Fi AP\n" "\"\"\n" - "[channel number: 0 means all]\n" - "[PSK: valid only for secure SSIDs]\n" - "[Security type: valid only for secure SSIDs]\n" + "\n" + "\n" + "\n" "0:None, 1:PSK, 2:PSK-256, 3:SAE\n" - "[MFP (optional: needs security type to be specified)]\n" + "\n" ": 0:Disable, 1:Optional, 2:Required", cmd_wifi_connect), SHELL_CMD(disconnect, NULL, "Disconnect from the Wi-Fi AP", @@ -1667,7 +1667,7 @@ SHELL_STATIC_SUBCMD_SET_CREATE(wifi_commands, SHELL_CMD(reg_domain, NULL, "Set or Get Wi-Fi regulatory domain\n" "Usage: wifi reg_domain [ISO/IEC 3166-1 alpha2] [-f]\n" - "[-f]: Force to use this regulatory hint over any other regulatory hints\n" + "-f: Force to use this regulatory hint over any other regulatory hints\n" "Note: This may cause regulatory compliance issues, use it at your own risk.", cmd_wifi_reg_domain), SHELL_CMD(mode, NULL, "mode operational setting\n" From 3b1ad8a2734fab077e5f5f398d1dc42039214d61 Mon Sep 17 00:00:00 2001 From: Robert Lubos Date: Tue, 6 Feb 2024 11:07:33 +0100 Subject: [PATCH 3680/3723] Revert "[nrf fromlist] wifi: shell: Fix unbalanced braces" This reverts commit 03b90ac09da07502981123dc46a63a8cb283b7ab. Signed-off-by: Robert Lubos --- subsys/net/l2/wifi/wifi_shell.c | 42 ++++++++++++++++----------------- 1 file changed, 21 insertions(+), 21 deletions(-) diff --git a/subsys/net/l2/wifi/wifi_shell.c b/subsys/net/l2/wifi/wifi_shell.c index c50175e086f..5f7eb5ba0ee 100644 --- a/subsys/net/l2/wifi/wifi_shell.c +++ b/subsys/net/l2/wifi/wifi_shell.c @@ -1673,15 +1673,15 @@ SHELL_STATIC_SUBCMD_SET_CREATE(wifi_commands, SHELL_CMD(mode, NULL, "mode operational setting\n" "This command may be used to set the Wi-Fi device into a specific mode of operation\n" "parameters:" - "[-i] : Interface index - optional argument\n" - "[-s] : Station mode.\n" - "[-m] : Monitor mode.\n" - "[-p] : Promiscuous mode.\n" - "[-t] : TX-Injection mode.\n" - "[-a] : AP mode.\n" - "[-k] : Softap mode.\n" - "[-h] : Help.\n" - "[-g] : Get current mode for a specific interface index.\n" + "[-i : Interface index - optional argument\n" + "[-s : Station mode.\n" + "[-m : Monitor mode.\n" + "[-p : Promiscuous mode.\n" + "[-t : TX-Injection mode.\n" + "[-a : AP mode.\n" + "[-k : Softap mode.\n" + "[-h : Help.\n" + "[-g : Get current mode for a specific interface index.\n" "Usage: Get operation example for interface index 1\n" "wifi mode -g -i1\n" "Set operation example for interface index 1 - set station+promiscuous\n" @@ -1692,14 +1692,14 @@ SHELL_STATIC_SUBCMD_SET_CREATE(wifi_commands, "monitor, TX-Injection and promiscuous mode is enabled.\n" "The different packet filter modes are control, management, data and enable all filters\n" "parameters:" - "[-i] : Interface index - optional argument.\n" - "[-a] : Enable all packet filter modes\n" - "[-m] : Enable management packets to allowed up the stack.\n" - "[-c] : Enable control packets to be allowed up the stack.\n" - "[-d] : Enable Data packets to be allowed up the stack.\n" - "[-g] : Get current filter settings for a specific interface index.\n" - "<-b> : Capture length buffer size for each packet to be captured - optional argument.\n" - "<-h> : Help.\n" + "[-i : Interface index - optional argument.\n" + "[-a : Enable all packet filter modes\n" + "[-m : Enable management packets to allowed up the stack.\n" + "[-c : Enable control packets to be allowed up the stack.\n" + "[-d : Enable Data packets to be allowed up the stack.\n" + "[-g : Get current filter settings for a specific interface index.\n" + "<-b : Capture length buffer size for each packet to be captured - optional argument.\n" + "<-h : Help.\n" "Usage: Get operation example for interface index 1\n" "wifi packet_filter -g -i1\n" "Set operation example for interface index 1 - set data+management frame filter\n" @@ -1710,10 +1710,10 @@ SHELL_STATIC_SUBCMD_SET_CREATE(wifi_commands, "monitor or TX-Injection mode is enabled.\n" "Currently 20 MHz is only supported and no BW parameter is provided\n" "parameters:" - "[-i] : Interface index - optional argument.\n" - "[-c] : Set a specific channel number to the lower layer.\n" - "[-g] : Get current set channel number from the lower layer.\n" - "[-h] : Help.\n" + "[-i : Interface index - optional argument.\n" + "[-c : Set a specific channel number to the lower layer.\n" + "[-g : Get current set channel number from the lower layer.\n" + "[-h : Help.\n" "Usage: Get operation example for interface index 1\n" "wifi channel -g -i1\n" "Set operation example for interface index 1 (setting channel 5)\n" From bb03dad0156abd36e3de12579ce7c13523f3ce04 Mon Sep 17 00:00:00 2001 From: Robert Lubos Date: Tue, 6 Feb 2024 11:07:33 +0100 Subject: [PATCH 3681/3723] Revert "[nrf fromlist] tfm: Remove limitation of enabling FP when build TF-M NS application" This reverts commit 26cebfca894cccafb2237dfdc0eaf7fde354f457. Signed-off-by: Robert Lubos --- arch/arm/core/Kconfig | 3 +++ 1 file changed, 3 insertions(+) diff --git a/arch/arm/core/Kconfig b/arch/arm/core/Kconfig index 4afe6c06ab5..75a64ea90eb 100644 --- a/arch/arm/core/Kconfig +++ b/arch/arm/core/Kconfig @@ -268,6 +268,9 @@ choice config FP_HARDABI bool "Floating point Hard ABI" + # TF-M build system does not build the NS app and libraries correctly with Hard ABI. + # This limitation should be removed in the next TF-M synchronization. + depends on !TFM_BUILD_NS help This option selects the Floating point ABI in which hardware floating point instructions are generated and uses FPU-specific calling From 7fbb932b08fc1aa49fdf07a7730fb9e3f2d42b22 Mon Sep 17 00:00:00 2001 From: Robert Lubos Date: Tue, 6 Feb 2024 11:07:33 +0100 Subject: [PATCH 3682/3723] Revert "[nrf noup] Bluetooth: Mesh: adapt SDC specific api usage" This reverts commit 36710dee098619426dcadcecdb7f217c12d01910. Signed-off-by: Robert Lubos --- subsys/bluetooth/mesh/adv_ext.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/subsys/bluetooth/mesh/adv_ext.c b/subsys/bluetooth/mesh/adv_ext.c index fe9fc4fd403..525e5ee5066 100644 --- a/subsys/bluetooth/mesh/adv_ext.c +++ b/subsys/bluetooth/mesh/adv_ext.c @@ -529,8 +529,8 @@ int bt_mesh_adv_enable(void) if (IS_ENABLED(CONFIG_BT_LL_SOFTDEVICE) && IS_ENABLED(CONFIG_BT_MESH_ADV_EXT_FRIEND_SEPARATE) && - advs[i].tags == BT_MESH_ADV_TAG_BIT_FRIEND) { - err = set_adv_randomness(advs[i].instance->handle, 0); + adv->tag == BT_MESH_FRIEND_ADV) { + err = set_adv_randomness(adv->instance->handle, 0); if (err) { LOG_ERR("Failed to set zero randomness: %d", err); } From 1f34c7b34c397f0598a93f1f53a4d968c4f54663 Mon Sep 17 00:00:00 2001 From: Robert Lubos Date: Tue, 6 Feb 2024 11:07:34 +0100 Subject: [PATCH 3683/3723] Revert "[nrf noup] tree-wide: support NCS Partition Manager (PM) definitions" This reverts commit a7fb26837763ee7c21fb666fe2faa8c7503a17f1. Signed-off-by: Robert Lubos --- arch/arm/core/mpu/arm_mpu_regions.c | 13 ------ cmake/modules/kernel.cmake | 4 -- drivers/flash/soc_flash_nrf.c | 11 ----- .../arch/arm/cortex_m/scripts/linker.ld | 46 ------------------- include/zephyr/storage/flash_map.h | 6 --- lib/libc/common/source/stdlib/malloc.c | 18 +------- lib/os/Kconfig.heap | 2 +- subsys/fs/littlefs_fs.c | 7 +-- subsys/ipc/rpmsg_service/rpmsg_backend.h | 27 ----------- 9 files changed, 4 insertions(+), 130 deletions(-) diff --git a/arch/arm/core/mpu/arm_mpu_regions.c b/arch/arm/core/mpu/arm_mpu_regions.c index cfe1230c907..6af62f84078 100644 --- a/arch/arm/core/mpu/arm_mpu_regions.c +++ b/arch/arm/core/mpu/arm_mpu_regions.c @@ -8,9 +8,6 @@ #include #include -#if USE_PARTITION_MANAGER -#include -#endif static const struct arm_mpu_region mpu_regions[] = { /* Region 0 */ @@ -24,14 +21,6 @@ static const struct arm_mpu_region mpu_regions[] = { #endif /* Region 1 */ MPU_REGION_ENTRY("SRAM_0", -#if USE_PARTITION_MANAGER - PM_SRAM_ADDRESS, -#if defined(CONFIG_ARMV8_M_BASELINE) || defined(CONFIG_ARMV8_M_MAINLINE) - REGION_RAM_ATTR(PM_SRAM_ADDRESS, PM_SRAM_SIZE)), -#else - REGION_RAM_ATTR(REGION_SRAM_SIZE)), -#endif -#else CONFIG_SRAM_BASE_ADDRESS, #if defined(CONFIG_ARMV8_M_BASELINE) || defined(CONFIG_ARMV8_M_MAINLINE) REGION_RAM_ATTR(CONFIG_SRAM_BASE_ADDRESS, \ @@ -39,8 +28,6 @@ static const struct arm_mpu_region mpu_regions[] = { #else REGION_RAM_ATTR(REGION_SRAM_SIZE)), #endif - -#endif /* USE_PARTITION_MANAGER */ }; const struct arm_mpu_config mpu_config = { diff --git a/cmake/modules/kernel.cmake b/cmake/modules/kernel.cmake index 06e1642f362..a093d46691f 100644 --- a/cmake/modules/kernel.cmake +++ b/cmake/modules/kernel.cmake @@ -243,7 +243,3 @@ if("${CMAKE_EXTRA_GENERATOR}" STREQUAL "Eclipse CDT4") include(${ZEPHYR_BASE}/cmake/ide/eclipse_cdt4_generator_amendment.cmake) eclipse_cdt4_generator_amendment(1) endif() - -if(ZEPHYR_NRF_MODULE_DIR) - include(${ZEPHYR_NRF_MODULE_DIR}/cmake/partition_manager.cmake) -endif() diff --git a/drivers/flash/soc_flash_nrf.c b/drivers/flash/soc_flash_nrf.c index b5a3fefa1e5..cc840309264 100644 --- a/drivers/flash/soc_flash_nrf.c +++ b/drivers/flash/soc_flash_nrf.c @@ -37,11 +37,6 @@ LOG_MODULE_REGISTER(flash_nrf); #define SOC_NV_FLASH_NODE DT_INST(0, soc_nv_flash) -#if CONFIG_TRUSTED_EXECUTION_NONSECURE && USE_PARTITION_MANAGER -#include -#include -#endif /* CONFIG_TRUSTED_EXECUTION_NONSECURE && USE_PARTITION_MANAGER */ - #ifndef CONFIG_SOC_FLASH_NRF_RADIO_SYNC_NONE #define FLASH_SLOT_WRITE 7500 #if defined(CONFIG_SOC_FLASH_NRF_PARTIAL_ERASE) @@ -171,12 +166,6 @@ static int flash_nrf_read(const struct device *dev, off_t addr, } #endif -#if CONFIG_TRUSTED_EXECUTION_NONSECURE && USE_PARTITION_MANAGER && PM_APP_ADDRESS - if (addr < PM_APP_ADDRESS) { - return soc_secure_mem_read(data, (void *)addr, len); - } -#endif - nrf_nvmc_buffer_read(data, (uint32_t)addr, len); return 0; diff --git a/include/zephyr/arch/arm/cortex_m/scripts/linker.ld b/include/zephyr/arch/arm/cortex_m/scripts/linker.ld index 5050c778627..13c2747f5a3 100644 --- a/include/zephyr/arch/arm/cortex_m/scripts/linker.ld +++ b/include/zephyr/arch/arm/cortex_m/scripts/linker.ld @@ -26,35 +26,6 @@ #endif #define RAMABLE_REGION RAM -#if USE_PARTITION_MANAGER - -#include - -#if CONFIG_NCS_IS_VARIANT_IMAGE && defined(PM_S0_ID) -/* We are linking against S1, create symbol containing the flash ID of S0. - * This is used when writing code operating on the "other" slot. - */ -_image_1_primary_slot_id = PM_S0_ID; - -#else /* ! CONFIG_NCS_IS_VARIANT_IMAGE */ - -#ifdef PM_S1_ID -/* We are linking against S0, create symbol containing the flash ID of S1. - * This is used when writing code operating on the "other" slot. - */ -_image_1_primary_slot_id = PM_S1_ID; -#endif /* PM_S1_ID */ - -#endif /* CONFIG_NCS_IS_VARIANT_IMAGE */ - -#define ROM_ADDR PM_ADDRESS -#define ROM_SIZE PM_SIZE - -#define RAM_SIZE PM_SRAM_SIZE -#define RAM_ADDR PM_SRAM_ADDRESS - -#else /* ! USE_PARTITION_MANAGER */ - #if !defined(CONFIG_XIP) && (CONFIG_FLASH_SIZE == 0) #define ROM_ADDR RAM_ADDR #else @@ -81,23 +52,6 @@ _image_1_primary_slot_id = PM_S1_ID; #define RAM_ADDR CONFIG_SRAM_BASE_ADDRESS #endif -#endif /* USE_PARTITION_MANAGER */ - -#if DT_NODE_HAS_STATUS(DT_CHOSEN(zephyr_ccm), okay) -#define CCM_SIZE DT_REG_SIZE(DT_CHOSEN(zephyr_ccm)) -#define CCM_ADDR DT_REG_ADDR(DT_CHOSEN(zephyr_ccm)) -#endif - -#if DT_NODE_HAS_STATUS(DT_CHOSEN(zephyr_itcm), okay) -#define ITCM_SIZE DT_REG_SIZE(DT_CHOSEN(zephyr_itcm)) -#define ITCM_ADDR DT_REG_ADDR(DT_CHOSEN(zephyr_itcm)) -#endif - -#if DT_NODE_HAS_STATUS(DT_CHOSEN(zephyr_dtcm), okay) -#define DTCM_SIZE DT_REG_SIZE(DT_CHOSEN(zephyr_dtcm)) -#define DTCM_ADDR DT_REG_ADDR(DT_CHOSEN(zephyr_dtcm)) -#endif - #if defined(CONFIG_CUSTOM_SECTION_ALIGN) _region_min_align = CONFIG_CUSTOM_SECTION_MIN_ALIGN_SIZE; #else diff --git a/include/zephyr/storage/flash_map.h b/include/zephyr/storage/flash_map.h index cc4a246105d..380e58691e9 100644 --- a/include/zephyr/storage/flash_map.h +++ b/include/zephyr/storage/flash_map.h @@ -271,10 +271,6 @@ const char *flash_area_label(const struct flash_area *fa); */ uint8_t flash_area_erased_val(const struct flash_area *fa); -#if USE_PARTITION_MANAGER -#include -#else - #define FLASH_AREA_LABEL_EXISTS(label) __DEPRECATED_MACRO \ DT_HAS_FIXED_PARTITION_LABEL(label) @@ -347,8 +343,6 @@ uint8_t flash_area_erased_val(const struct flash_area *fa); #define FIXED_PARTITION_DEVICE(label) \ DEVICE_DT_GET(DT_MTD_FROM_FIXED_PARTITION(DT_NODELABEL(label))) -#endif /* USE_PARTITION_MANAGER */ - #ifdef __cplusplus } #endif diff --git a/lib/libc/common/source/stdlib/malloc.c b/lib/libc/common/source/stdlib/malloc.c index 2f469d673e4..e3a5db6f7d5 100644 --- a/lib/libc/common/source/stdlib/malloc.c +++ b/lib/libc/common/source/stdlib/malloc.c @@ -25,20 +25,6 @@ #include LOG_MODULE_DECLARE(os, CONFIG_KERNEL_LOG_LEVEL); -#if USE_PARTITION_MANAGER - -#include - -#define RAM_SIZE PM_SRAM_SIZE -#define RAM_ADDR PM_SRAM_ADDRESS - -#else /* ! USE_PARTITION_MANAGER */ - -#define RAM_SIZE (KB((size_t) CONFIG_SRAM_SIZE)) -#define RAM_ADDR CONFIG_SRAM_BASE_ADDRESS - -#endif /* USE_PARTITION_MANAGER */ - #ifdef CONFIG_COMMON_LIBC_MALLOC #if (CONFIG_COMMON_LIBC_MALLOC_ARENA_SIZE != 0) @@ -120,8 +106,8 @@ static POOL_SECTION unsigned char __aligned(HEAP_ALIGN) malloc_arena[HEAP_SIZE]; extern char _heap_sentry[]; # define HEAP_SIZE ROUND_DOWN((POINTER_TO_UINT(_heap_sentry) - HEAP_BASE), HEAP_ALIGN) # else -# define HEAP_SIZE ROUND_DOWN((RAM_SIZE - \ - ((size_t) HEAP_BASE - (size_t) RAM_ADDR)), HEAP_ALIGN) +# define HEAP_SIZE ROUND_DOWN((KB((size_t) CONFIG_SRAM_SIZE) - \ + ((size_t) HEAP_BASE - (size_t) CONFIG_SRAM_BASE_ADDRESS)), HEAP_ALIGN) # endif /* else CONFIG_XTENSA */ # endif /* else CONFIG_COMMON_LIBC_MALLOC_ARENA_SIZE > 0 */ diff --git a/lib/os/Kconfig.heap b/lib/os/Kconfig.heap index f6e8d93ae50..b913d6100dc 100644 --- a/lib/os/Kconfig.heap +++ b/lib/os/Kconfig.heap @@ -51,7 +51,7 @@ config HEAP_LISTENER choice prompt "Supported heap sizes" depends on !64BIT - default SYS_HEAP_SMALL_ONLY if (SRAM_SIZE <= 256) && !PARTITION_MANAGER_ENABLED + default SYS_HEAP_SMALL_ONLY if (SRAM_SIZE <= 256) default SYS_HEAP_AUTO help Heaps using reduced-size chunk headers can accommodate so called diff --git a/subsys/fs/littlefs_fs.c b/subsys/fs/littlefs_fs.c index c4c75bb48c4..3058f402d73 100644 --- a/subsys/fs/littlefs_fs.c +++ b/subsys/fs/littlefs_fs.c @@ -1054,12 +1054,7 @@ struct fs_mount_t FS_FSTAB_ENTRY(DT_DRV_INST(inst)) = { \ .type = FS_LITTLEFS, \ .mnt_point = DT_INST_PROP(inst, mount_point), \ .fs_data = &fs_data_##inst, \ - .storage_dev = (void *) \ - COND_CODE_1(USE_PARTITION_MANAGER, \ - (COND_CODE_1(FIXED_PARTITION_EXISTS(littlefs_storage), \ - (FIXED_PARTITION_ID(littlefs_storage)), \ - (FIXED_PARTITION_ID(storage)))), \ - (DT_FIXED_PARTITION_ID(FS_PARTITION(inst)))), \ + .storage_dev = (void *)DT_FIXED_PARTITION_ID(FS_PARTITION(inst)), \ .flags = FSTAB_ENTRY_DT_MOUNT_FLAGS(DT_DRV_INST(inst)), \ }; diff --git a/subsys/ipc/rpmsg_service/rpmsg_backend.h b/subsys/ipc/rpmsg_service/rpmsg_backend.h index 9996e1d74d9..a74e46b8520 100644 --- a/subsys/ipc/rpmsg_service/rpmsg_backend.h +++ b/subsys/ipc/rpmsg_service/rpmsg_backend.h @@ -13,35 +13,8 @@ extern "C" { #endif -#if CONFIG_PARTITION_MANAGER_ENABLED - -#include "pm_config.h" - -#if defined(PM_RPMSG_NRF53_SRAM_ADDRESS) || defined(PM__RPMSG_NRF53_SRAM_ADDRESS) - -#if defined(PM_RPMSG_NRF53_SRAM_ADDRESS) -#define VDEV_START_ADDR PM_RPMSG_NRF53_SRAM_ADDRESS -#define VDEV_SIZE PM_RPMSG_NRF53_SRAM_SIZE -#else -/* The current image is a child image in a different domain than the image - * which defined the required values. To reach the values of the parent domain - * we use the 'PM__' variant of the define. - */ -#define VDEV_START_ADDR PM__RPMSG_NRF53_SRAM_ADDRESS -#define VDEV_SIZE PM__RPMSG_NRF53_SRAM_SIZE -#endif /* defined(PM_RPMSG_NRF53_SRAM_ADDRESS) */ - -#else #define VDEV_START_ADDR DT_REG_ADDR(DT_CHOSEN(zephyr_ipc_shm)) #define VDEV_SIZE DT_REG_SIZE(DT_CHOSEN(zephyr_ipc_shm)) -#endif /* defined(PM_RPMSG_NRF53_SRAM_ADDRESS) || defined(PM__RPMSG_NRF53_SRAM_ADDRESS) */ - -#else - -#define VDEV_START_ADDR DT_REG_ADDR(DT_CHOSEN(zephyr_ipc_shm)) -#define VDEV_SIZE DT_REG_SIZE(DT_CHOSEN(zephyr_ipc_shm)) - -#endif /* CONFIG_PARTITION_MANAGER_ENABLED */ #define VDEV_STATUS_ADDR VDEV_START_ADDR #define VDEV_STATUS_SIZE 0x400 From 2b7c2572e4e13822f7ae82a43e16613cc49d004a Mon Sep 17 00:00:00 2001 From: Robert Lubos Date: Tue, 6 Feb 2024 11:07:34 +0100 Subject: [PATCH 3684/3723] Revert "[nrf noup] Bluetooth: Mesh: Fix adv randomness bug" This reverts commit 3afe29330d959ee78d57db509a7380f0e05b6bba. Signed-off-by: Robert Lubos --- subsys/bluetooth/mesh/adv_ext.c | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/subsys/bluetooth/mesh/adv_ext.c b/subsys/bluetooth/mesh/adv_ext.c index 525e5ee5066..0c11fc0053a 100644 --- a/subsys/bluetooth/mesh/adv_ext.c +++ b/subsys/bluetooth/mesh/adv_ext.c @@ -527,9 +527,7 @@ int bt_mesh_adv_enable(void) return err; } - if (IS_ENABLED(CONFIG_BT_LL_SOFTDEVICE) && - IS_ENABLED(CONFIG_BT_MESH_ADV_EXT_FRIEND_SEPARATE) && - adv->tag == BT_MESH_FRIEND_ADV) { + if (IS_ENABLED(CONFIG_BT_LL_SOFTDEVICE) && adv->tag & BT_MESH_FRIEND_ADV) { err = set_adv_randomness(adv->instance->handle, 0); if (err) { LOG_ERR("Failed to set zero randomness: %d", err); From f7ba52b4e5a07f199c6975de7513efebe64eabb3 Mon Sep 17 00:00:00 2001 From: Robert Lubos Date: Tue, 6 Feb 2024 11:07:34 +0100 Subject: [PATCH 3685/3723] Revert "[nrf fromtree] modules: hal_nordic: new nrf_802154 configuration option" This reverts commit f59385bdd3af03f3d825e60089a6ec3fcf8c40a2. Signed-off-by: Robert Lubos --- modules/hal_nordic/Kconfig | 6 ------ modules/hal_nordic/nrf_802154/CMakeLists.txt | 3 --- 2 files changed, 9 deletions(-) diff --git a/modules/hal_nordic/Kconfig b/modules/hal_nordic/Kconfig index 6f77bbea427..b461c094ef4 100644 --- a/modules/hal_nordic/Kconfig +++ b/modules/hal_nordic/Kconfig @@ -196,12 +196,6 @@ config NRF_802154_ENCRYPTION bool "nRF 802.15.4 AES-CCM* authentication & encryption" depends on !CRYPTO_NRF_ECB -config NRF_802154_SECURITY_KEY_STORAGE_SIZE - int "nRF 802.15.4 security key storage size" - default 3 - help - Number of encryption keys that the nRF 802.15.4 Radio Driver can store simultaneously. - config NRF_802154_CARRIER_FUNCTIONS bool "nRF 802.15.4 carrier functions" help diff --git a/modules/hal_nordic/nrf_802154/CMakeLists.txt b/modules/hal_nordic/nrf_802154/CMakeLists.txt index 763f9625be8..a274a019e25 100644 --- a/modules/hal_nordic/nrf_802154/CMakeLists.txt +++ b/modules/hal_nordic/nrf_802154/CMakeLists.txt @@ -56,9 +56,6 @@ target_compile_definitions(zephyr-802154-interface NRF_802154_CCA_CORR_LIMIT_DEFAULT=${CONFIG_NRF_802154_CCA_CORR_LIMIT} NRF_802154_CCA_CORR_THRESHOLD_DEFAULT=${CONFIG_NRF_802154_CCA_CORR_THRESHOLD} NRF_802154_CCA_ED_THRESHOLD_DEFAULT=${CONFIG_NRF_802154_CCA_ED_THRESHOLD} - - # Key storage size - NRF_802154_SECURITY_KEY_STORAGE_SIZE=${CONFIG_NRF_802154_SECURITY_KEY_STORAGE_SIZE} ) if (CONFIG_NRF_802154_CCA_MODE_ED) From ad297e8726dbed5dff348c0486b8fc41decd294c Mon Sep 17 00:00:00 2001 From: Robert Lubos Date: Tue, 6 Feb 2024 11:07:34 +0100 Subject: [PATCH 3686/3723] Revert "[nrf fromtree] modules: hal_nordic: reorganize nrf_802154 Kconfig" This reverts commit 6fe770053b0f7beac3cccddca856b90b58285d1d. Signed-off-by: Robert Lubos --- modules/hal_nordic/Kconfig | 119 ++++++++++--------- modules/hal_nordic/nrf_802154/CMakeLists.txt | 46 +++---- 2 files changed, 90 insertions(+), 75 deletions(-) diff --git a/modules/hal_nordic/Kconfig b/modules/hal_nordic/Kconfig index b461c094ef4..44c12e88685 100644 --- a/modules/hal_nordic/Kconfig +++ b/modules/hal_nordic/Kconfig @@ -43,6 +43,30 @@ config NRF_802154_MULTIPROTOCOL_SUPPORT in the driver, this option must be enabled. Otherwise, the driver assumes that access to the radio peripheral is granted indefinitely. +config NRF_802154_ENCRYPTION + bool "nRF 802.15.4 AES-CCM* authentication & encryption" + depends on !CRYPTO_NRF_ECB + +choice NRF_802154_CCA_MODE + prompt "nRF IEEE 802.15.4 CCA mode" + default NRF_802154_CCA_MODE_ED + help + CCA mode + +config NRF_802154_CCA_MODE_ED + bool "Energy Above Threshold" + +config NRF_802154_CCA_MODE_CARRIER + bool "Carrier Seen" + +config NRF_802154_CCA_MODE_CARRIER_AND_ED + bool "Energy Above Threshold AND Carrier Seen" + +config NRF_802154_CCA_MODE_CARRIER_OR_ED + bool "Energy Above Threshold OR Carrier Seen" + +endchoice + choice NRF_802154_SL_TYPE prompt "nRF IEEE 802.15.4 Service Layer Type" @@ -53,6 +77,43 @@ config NRF_802154_SL_OPENSOURCE endchoice +config NRF_802154_CCA_ED_THRESHOLD + int "nRF IEEE 802.15.4 CCA Energy Detection threshold" + default 45 + help + If energy detected in a given channel is above the value then the + channel is deemed busy. The unit is defined as per 802.15.4-2006 spec. + +config NRF_802154_CCA_CORR_THRESHOLD + int "nRF IEEE 802.15.4 CCA Correlator threshold" + default 45 + +config NRF_802154_CCA_CORR_LIMIT + int "nRF IEEE 802.15.4 CCA Correlator limit" + default 2 + help + Limit for occurrences above correlator threshold. When not equal to + zero the correlator based signal detect is enabled. + +config NRF_802154_PENDING_SHORT_ADDRESSES + int "nRF 802.15.4 pending short addresses" + default 16 + help + Number of slots containing short addresses of nodes for which pending data is stored + +config NRF_802154_PENDING_EXTENDED_ADDRESSES + int "nRF 802.15.4 pending extended addresses" + default 16 + help + Number of slots containing extended addresses of nodes for which pending data is stored + +config NRF_802154_RX_BUFFERS + int "nRF 802.15.4 receive buffers" + default 16 + help + Number of buffers in nRF 802.15.4 driver receive queue. If this value is modified, + its serialization host counterpart must be set to the exact same value. + config NRF_802154_TEMPERATURE_UPDATE bool "nRF 802.15.4 temperature update" default y @@ -131,47 +192,7 @@ config NRF_802154_SER_DEFAULT_RESPONSE_TIMEOUT This option specifies default timeout of spinel status response in milliseconds. -endmenu # NRF_802154_SER_HOST || NRF_802154_SER_RADIO - -if NRF_802154_RADIO_DRIVER || NRF_802154_SERIALIZATION - -choice NRF_802154_CCA_MODE - prompt "nRF IEEE 802.15.4 CCA mode" - default NRF_802154_CCA_MODE_ED - help - CCA mode - -config NRF_802154_CCA_MODE_ED - bool "Energy Above Threshold" - -config NRF_802154_CCA_MODE_CARRIER - bool "Carrier Seen" - -config NRF_802154_CCA_MODE_CARRIER_AND_ED - bool "Energy Above Threshold AND Carrier Seen" - -config NRF_802154_CCA_MODE_CARRIER_OR_ED - bool "Energy Above Threshold OR Carrier Seen" - -endchoice - -config NRF_802154_CCA_ED_THRESHOLD - int "nRF IEEE 802.15.4 CCA Energy Detection threshold" - default 45 - help - If energy detected in a given channel is above the value then the - channel is deemed busy. The unit is defined as per 802.15.4-2006 spec. - -config NRF_802154_CCA_CORR_THRESHOLD - int "nRF IEEE 802.15.4 CCA Correlator threshold" - default 45 - -config NRF_802154_CCA_CORR_LIMIT - int "nRF IEEE 802.15.4 CCA Correlator limit" - default 2 - help - Limit for occurrences above correlator threshold. When not equal to - zero the correlator based signal detect is enabled. +if NRF_802154_SER_HOST config NRF_802154_RX_BUFFERS int "nRF 802.15.4 receive buffers" @@ -180,21 +201,11 @@ config NRF_802154_RX_BUFFERS Number of buffers in nRF 802.15.4 driver serialization host's receive queue. If this value is modified, its remote counterpart must be set to the exact same value. -config NRF_802154_PENDING_SHORT_ADDRESSES - int "nRF 802.15.4 pending short addresses" - default 16 - help - Number of slots containing short addresses of nodes for which pending data is stored +endif -config NRF_802154_PENDING_EXTENDED_ADDRESSES - int "nRF 802.15.4 pending extended addresses" - default 16 - help - Number of slots containing extended addresses of nodes for which pending data is stored +endmenu # NRF_802154_SER_HOST || NRF_802154_SER_RADIO -config NRF_802154_ENCRYPTION - bool "nRF 802.15.4 AES-CCM* authentication & encryption" - depends on !CRYPTO_NRF_ECB +if NRF_802154_RADIO_DRIVER || NRF_802154_SERIALIZATION config NRF_802154_CARRIER_FUNCTIONS bool "nRF 802.15.4 carrier functions" diff --git a/modules/hal_nordic/nrf_802154/CMakeLists.txt b/modules/hal_nordic/nrf_802154/CMakeLists.txt index a274a019e25..cd5ace0b278 100644 --- a/modules/hal_nordic/nrf_802154/CMakeLists.txt +++ b/modules/hal_nordic/nrf_802154/CMakeLists.txt @@ -12,6 +12,24 @@ if (CONFIG_NRF_802154_RADIO_DRIVER) sl_opensource/platform/nrf_802154_irq_zephyr.c sl_opensource/platform/nrf_802154_temperature_zephyr.c ) + + target_compile_definitions(zephyr-802154-interface + INTERFACE + # CCA mode options + NRF_802154_CCA_CORR_LIMIT_DEFAULT=${CONFIG_NRF_802154_CCA_CORR_LIMIT} + NRF_802154_CCA_CORR_THRESHOLD_DEFAULT=${CONFIG_NRF_802154_CCA_CORR_THRESHOLD} + NRF_802154_CCA_ED_THRESHOLD_DEFAULT=${CONFIG_NRF_802154_CCA_ED_THRESHOLD} + ) + + if (CONFIG_NRF_802154_CCA_MODE_ED) + target_compile_definitions(zephyr-802154-interface INTERFACE NRF_802154_CCA_MODE_DEFAULT=NRF_RADIO_CCA_MODE_ED) + elseif (CONFIG_NRF_802154_CCA_MODE_CARRIER) + target_compile_definitions(zephyr-802154-interface INTERFACE NRF_802154_CCA_MODE_DEFAULT=NRF_RADIO_CCA_MODE_CARRIER) + elseif (CONFIG_NRF_802154_CCA_MODE_CARRIER_AND_ED) + target_compile_definitions(zephyr-802154-interface INTERFACE NRF_802154_CCA_MODE_DEFAULT=NRF_RADIO_CCA_MODE_CARRIER_AND_ED) + elseif (CONFIG_NRF_802154_CCA_MODE_CARRIER_OR_ED) + target_compile_definitions(zephyr-802154-interface INTERFACE NRF_802154_CCA_MODE_DEFAULT=NRF_RADIO_CCA_MODE_CARRIER_OR_ED) + endif() endif () if (CONFIG_NRF_802154_SERIALIZATION) @@ -51,23 +69,8 @@ target_compile_definitions(zephyr-802154-interface # ACK timeout NRF_802154_ACK_TIMEOUT_ENABLED=1 - - # CCA mode options - NRF_802154_CCA_CORR_LIMIT_DEFAULT=${CONFIG_NRF_802154_CCA_CORR_LIMIT} - NRF_802154_CCA_CORR_THRESHOLD_DEFAULT=${CONFIG_NRF_802154_CCA_CORR_THRESHOLD} - NRF_802154_CCA_ED_THRESHOLD_DEFAULT=${CONFIG_NRF_802154_CCA_ED_THRESHOLD} ) -if (CONFIG_NRF_802154_CCA_MODE_ED) - target_compile_definitions(zephyr-802154-interface INTERFACE NRF_802154_CCA_MODE_DEFAULT=NRF_RADIO_CCA_MODE_ED) -elseif (CONFIG_NRF_802154_CCA_MODE_CARRIER) - target_compile_definitions(zephyr-802154-interface INTERFACE NRF_802154_CCA_MODE_DEFAULT=NRF_RADIO_CCA_MODE_CARRIER) -elseif (CONFIG_NRF_802154_CCA_MODE_CARRIER_AND_ED) - target_compile_definitions(zephyr-802154-interface INTERFACE NRF_802154_CCA_MODE_DEFAULT=NRF_RADIO_CCA_MODE_CARRIER_AND_ED) -elseif (CONFIG_NRF_802154_CCA_MODE_CARRIER_OR_ED) - target_compile_definitions(zephyr-802154-interface INTERFACE NRF_802154_CCA_MODE_DEFAULT=NRF_RADIO_CCA_MODE_CARRIER_OR_ED) -endif() - if (CONFIG_NRF_802154_ENCRYPTION) target_compile_definitions(zephyr-802154-interface INTERFACE NRF_802154_ENCRYPTION_ENABLED=1) target_compile_definitions(zephyr-802154-interface INTERFACE NRF_802154_SECURITY_WRITER_ENABLED=1) @@ -90,12 +93,13 @@ else() target_compile_definitions(zephyr-802154-interface INTERFACE NRF_802154_CARRIER_FUNCTIONS_ENABLED=0) endif() -target_compile_definitions(zephyr-802154-interface INTERFACE NRF_802154_ENERGY_DETECTED_VERSION=1) - -if (CONFIG_NRF_802154_ASSERT_ZEPHYR OR CONFIG_NRF_802154_ASSERT_ZEPHYR_MINIMAL) - target_include_directories(zephyr-802154-interface INTERFACE include) - target_compile_definitions(zephyr-802154-interface INTERFACE NRF_802154_PLATFORM_ASSERT_INCLUDE=\"nrf_802154_assert_zephyr.h\") - target_sources(nrf-802154-platform PRIVATE nrf_802154_assert_handler.c) +if (CONFIG_NRF_802154_RADIO_DRIVER OR CONFIG_NRF_802154_SERIALIZATION) + target_compile_definitions(zephyr-802154-interface INTERFACE NRF_802154_ENERGY_DETECTED_VERSION=1) + if (CONFIG_NRF_802154_ASSERT_ZEPHYR OR CONFIG_NRF_802154_ASSERT_ZEPHYR_MINIMAL) + target_include_directories(zephyr-802154-interface INTERFACE include) + target_compile_definitions(zephyr-802154-interface INTERFACE NRF_802154_PLATFORM_ASSERT_INCLUDE=\"nrf_802154_assert_zephyr.h\") + target_sources(nrf-802154-platform PRIVATE nrf_802154_assert_handler.c) + endif() endif() set(NRF52_SERIES ${CONFIG_SOC_SERIES_NRF52X}) From 5c5a82cbfc702b59bf447c6f7a231e32d31d1494 Mon Sep 17 00:00:00 2001 From: Robert Lubos Date: Tue, 6 Feb 2024 11:07:34 +0100 Subject: [PATCH 3687/3723] Revert "[nrf fromtree] modules: hal_nordic: nrf_802154: remove magic number" This reverts commit cac385035be59178826590a46db63f5d3d800e66. Signed-off-by: Robert Lubos --- .../serialization/platform/nrf_802154_spinel_backend_ipc.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/modules/hal_nordic/nrf_802154/serialization/platform/nrf_802154_spinel_backend_ipc.c b/modules/hal_nordic/nrf_802154/serialization/platform/nrf_802154_spinel_backend_ipc.c index b2629eef67b..8a9cd8739b2 100644 --- a/modules/hal_nordic/nrf_802154/serialization/platform/nrf_802154_spinel_backend_ipc.c +++ b/modules/hal_nordic/nrf_802154/serialization/platform/nrf_802154_spinel_backend_ipc.c @@ -9,7 +9,6 @@ #include #include -#include "nrf_802154.h" #include "nrf_802154_spinel_backend_callouts.h" #include "nrf_802154_serialization_error.h" #include "../../spinel_base/spinel.h" @@ -75,7 +74,7 @@ nrf_802154_ser_err_t nrf_802154_backend_init(void) #define SEND_THREAD_STACK_SIZE 1024 /* Make the ring buffer long enough to hold all notifications that the driver can produce */ -#define RING_BUFFER_LEN (NRF_802154_MAX_PENDING_NOTIFICATIONS + 1) +#define RING_BUFFER_LEN (CONFIG_NRF_802154_RX_BUFFERS + 10) static K_SEM_DEFINE(send_sem, 0, RING_BUFFER_LEN); K_THREAD_STACK_DEFINE(send_thread_stack, SEND_THREAD_STACK_SIZE); From c7ef6e8866ea2a9c3b2dda2007831e034abfa962 Mon Sep 17 00:00:00 2001 From: Robert Lubos Date: Tue, 6 Feb 2024 11:07:34 +0100 Subject: [PATCH 3688/3723] Revert "[nrf fromtree] drivers: ieee802154: support Key Identifier Mode > 1" This reverts commit 14a3d4d979bee0ecae346e24b112bb61732f0915. Signed-off-by: Robert Lubos --- drivers/ieee802154/ieee802154_nrf5.c | 26 +++++++++++++++++++------- include/zephyr/net/ieee802154_radio.h | 7 +------ modules/openthread/platform/radio.c | 27 +++++++++------------------ 3 files changed, 29 insertions(+), 31 deletions(-) diff --git a/drivers/ieee802154/ieee802154_nrf5.c b/drivers/ieee802154/ieee802154_nrf5.c index defbc90cd07..94924e06dba 100644 --- a/drivers/ieee802154/ieee802154_nrf5.c +++ b/drivers/ieee802154/ieee802154_nrf5.c @@ -781,17 +781,25 @@ static void nrf5_iface_init(struct net_if *iface) #if defined(CONFIG_NRF_802154_ENCRYPTION) static void nrf5_config_mac_keys(struct ieee802154_key *mac_keys) { - nrf_802154_security_key_remove_all(); + static nrf_802154_key_id_t stored_key_ids[NRF_802154_SECURITY_KEY_STORAGE_SIZE]; + static uint8_t stored_ids[NRF_802154_SECURITY_KEY_STORAGE_SIZE]; + uint8_t i; - for (uint8_t i = 0; mac_keys->key_value - && i < NRF_802154_SECURITY_KEY_STORAGE_SIZE; mac_keys++, i++) { + for (i = 0; i < NRF_802154_SECURITY_KEY_STORAGE_SIZE && stored_key_ids[i].p_key_id; i++) { + nrf_802154_security_key_remove(&stored_key_ids[i]); + stored_key_ids[i].p_key_id = NULL; + } + + i = 0; + for (struct ieee802154_key *keys = mac_keys; keys->key_value + && i < NRF_802154_SECURITY_KEY_STORAGE_SIZE; keys++, i++) { nrf_802154_key_t key = { - .value.p_cleartext_key = mac_keys->key_value, - .id.mode = mac_keys->key_id_mode, - .id.p_key_id = mac_keys->key_id, + .value.p_cleartext_key = keys->key_value, + .id.mode = keys->key_id_mode, + .id.p_key_id = &(keys->key_index), .type = NRF_802154_KEY_CLEARTEXT, .frame_counter = 0, - .use_global_frame_counter = !(mac_keys->frame_counter_per_key), + .use_global_frame_counter = !(keys->frame_counter_per_key), }; __ASSERT_EVAL((void)nrf_802154_security_key_store(&key), @@ -799,6 +807,10 @@ static void nrf5_config_mac_keys(struct ieee802154_key *mac_keys) err == NRF_802154_SECURITY_ERROR_NONE || err == NRF_802154_SECURITY_ERROR_ALREADY_PRESENT, "Storing key failed, err: %d", err); + + stored_ids[i] = *key.id.p_key_id; + stored_key_ids[i].mode = key.id.mode; + stored_key_ids[i].p_key_id = &stored_ids[i]; }; } #endif /* CONFIG_NRF_802154_ENCRYPTION */ diff --git a/include/zephyr/net/ieee802154_radio.h b/include/zephyr/net/ieee802154_radio.h index de0cf89da4c..59608fac391 100644 --- a/include/zephyr/net/ieee802154_radio.h +++ b/include/zephyr/net/ieee802154_radio.h @@ -592,16 +592,11 @@ struct ieee802154_filter { * IEEE802154_CONFIG_MAC_KEYS. */ struct ieee802154_key { - /** Key material */ uint8_t *key_value; - /** Initial value of frame counter associated with the key, see section 9.4.3 */ uint32_t key_frame_counter; - /** Indicates if per-key frame counter should be used, see section 9.4.3 */ bool frame_counter_per_key; - /** Key Identifier Mode, see section 9.4.2.3, Table 9-7 */ uint8_t key_id_mode; - /** Key Identifier, see section 9.4.4 */ - uint8_t *key_id; + uint8_t key_index; }; /** IEEE 802.15.4 Transmission mode. */ diff --git a/modules/openthread/platform/radio.c b/modules/openthread/platform/radio.c index a09b7dd3b67..98eab182aad 100644 --- a/modules/openthread/platform/radio.c +++ b/modules/openthread/platform/radio.c @@ -1188,14 +1188,20 @@ void otPlatRadioSetMacKey(otInstance *aInstance, uint8_t aKeyIdMode, uint8_t aKe struct ieee802154_key keys[] = { { .key_id_mode = key_id_mode, + .key_index = aKeyId == 1 ? 0x80 : aKeyId - 1, + .key_value = (uint8_t *)aPrevKey->mKeyMaterial.mKey.m8, .frame_counter_per_key = false, }, { .key_id_mode = key_id_mode, + .key_index = aKeyId, + .key_value = (uint8_t *)aCurrKey->mKeyMaterial.mKey.m8, .frame_counter_per_key = false, }, { .key_id_mode = key_id_mode, + .key_index = aKeyId == 0x80 ? 1 : aKeyId + 1, + .key_value = (uint8_t *)aNextKey->mKeyMaterial.mKey.m8, .frame_counter_per_key = false, }, { @@ -1209,24 +1215,9 @@ void otPlatRadioSetMacKey(otInstance *aInstance, uint8_t aKeyIdMode, uint8_t aKe }, }; - if (key_id_mode == 1) { - /* aKeyId in range: (1, 0x80) means valid keys */ - uint8_t prev_key_id = aKeyId == 1 ? 0x80 : aKeyId - 1; - uint8_t next_key_id = aKeyId == 0x80 ? 1 : aKeyId + 1; - - keys[0].key_id = &prev_key_id; - keys[0].key_value = (uint8_t *)aPrevKey->mKeyMaterial.mKey.m8; - - keys[1].key_id = &aKeyId; - keys[1].key_value = (uint8_t *)aCurrKey->mKeyMaterial.mKey.m8; - - keys[2].key_id = &next_key_id; - keys[2].key_value = (uint8_t *)aNextKey->mKeyMaterial.mKey.m8; - } else { - /* aKeyId == 0 is used only to clear keys for stack reset in RCP */ - __ASSERT_NO_MSG((key_id_mode == 0) && (aKeyId == 0)); - } - + /* aKeyId in range: (1, 0x80) means valid keys + * aKeyId == 0 is used only to clear keys for stack reset in RCP + */ struct ieee802154_config config = { .mac_keys = aKeyId == 0 ? clear_keys : keys, }; From 99162b25e80515d138b41686245ddb5453b5065b Mon Sep 17 00:00:00 2001 From: Robert Lubos Date: Tue, 6 Feb 2024 11:07:35 +0100 Subject: [PATCH 3689/3723] Revert "[nrf fromtree] modules: hal_nordic: nrf_802154: lengthen serialization ring buffer" This reverts commit 6e296fb2733fb373b5059bf642e8eec2b8635277. Signed-off-by: Robert Lubos --- .../serialization/platform/nrf_802154_spinel_backend_ipc.c | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/modules/hal_nordic/nrf_802154/serialization/platform/nrf_802154_spinel_backend_ipc.c b/modules/hal_nordic/nrf_802154/serialization/platform/nrf_802154_spinel_backend_ipc.c index 8a9cd8739b2..06ad1f003e6 100644 --- a/modules/hal_nordic/nrf_802154/serialization/platform/nrf_802154_spinel_backend_ipc.c +++ b/modules/hal_nordic/nrf_802154/serialization/platform/nrf_802154_spinel_backend_ipc.c @@ -71,11 +71,9 @@ nrf_802154_ser_err_t nrf_802154_backend_init(void) } /* Send packet thread details */ +#define RING_BUFFER_LEN 16 #define SEND_THREAD_STACK_SIZE 1024 -/* Make the ring buffer long enough to hold all notifications that the driver can produce */ -#define RING_BUFFER_LEN (CONFIG_NRF_802154_RX_BUFFERS + 10) - static K_SEM_DEFINE(send_sem, 0, RING_BUFFER_LEN); K_THREAD_STACK_DEFINE(send_thread_stack, SEND_THREAD_STACK_SIZE); struct k_thread send_thread_data; From caecd2b37767d53e101be8066982ec29b4291837 Mon Sep 17 00:00:00 2001 From: Robert Lubos Date: Tue, 6 Feb 2024 11:07:35 +0100 Subject: [PATCH 3690/3723] Revert "[nrf fromtree] drivers: ieee802154: nrf5: support raw mode" This reverts commit ae5914c83154f90d3ab115e81c067e5275ff2917. Signed-off-by: Robert Lubos --- drivers/ieee802154/ieee802154_nrf5.c | 21 +++------------------ 1 file changed, 3 insertions(+), 18 deletions(-) diff --git a/drivers/ieee802154/ieee802154_nrf5.c b/drivers/ieee802154/ieee802154_nrf5.c index 94924e06dba..9a02aef7e4c 100644 --- a/drivers/ieee802154/ieee802154_nrf5.c +++ b/drivers/ieee802154/ieee802154_nrf5.c @@ -57,9 +57,6 @@ struct nrf5_802154_config { }; static struct nrf5_802154_data nrf5_data; -#if defined(CONFIG_IEEE802154_RAW_MODE) -static const struct device *nrf5_dev; -#endif #define DRX_SLOT_RX 0 /* Delayed reception window ID */ @@ -98,15 +95,6 @@ static const struct device *nrf5_dev; #define IEEE802154_NRF5_VENDOR_OUI (uint32_t)0xF4CE36 #endif -static inline const struct device *nrf5_get_device(void) -{ -#if defined(CONFIG_IEEE802154_RAW_MODE) - return nrf5_dev; -#else - return net_if_get_device(nrf5_data.iface); -#endif -} - static void nrf5_get_eui64(uint8_t *mac) { uint64_t factoryAddress; @@ -738,9 +726,6 @@ static int nrf5_init(const struct device *dev) { const struct nrf5_802154_config *nrf5_radio_cfg = NRF5_802154_CFG(dev); struct nrf5_802154_data *nrf5_radio = NRF5_802154_DATA(dev); -#if defined(CONFIG_IEEE802154_RAW_MODE) - nrf5_dev = dev; -#endif k_fifo_init(&nrf5_radio->rx_fifo); k_sem_init(&nrf5_radio->tx_wait, 0, 1); @@ -1061,7 +1046,7 @@ void nrf_802154_received_timestamp_raw(uint8_t *data, int8_t power, uint8_t lqi, void nrf_802154_receive_failed(nrf_802154_rx_error_t error, uint32_t id) { - const struct device *dev = nrf5_get_device(); + const struct device *dev = net_if_get_device(nrf5_data.iface); #if defined(CONFIG_IEEE802154_CSL_ENDPOINT) if (id == DRX_SLOT_RX) { @@ -1180,7 +1165,7 @@ void nrf_802154_energy_detected(const nrf_802154_energy_detected_t *result) energy_scan_done_cb_t callback = nrf5_data.energy_scan_done; nrf5_data.energy_scan_done = NULL; - callback(nrf5_get_device(), result->ed_dbm); + callback(net_if_get_device(nrf5_data.iface), result->ed_dbm); } } @@ -1190,7 +1175,7 @@ void nrf_802154_energy_detection_failed(nrf_802154_ed_error_t error) energy_scan_done_cb_t callback = nrf5_data.energy_scan_done; nrf5_data.energy_scan_done = NULL; - callback(nrf5_get_device(), SHRT_MAX); + callback(net_if_get_device(nrf5_data.iface), SHRT_MAX); } } From 88193b185c2cedd4388bd4d606d4ec68e0020d0a Mon Sep 17 00:00:00 2001 From: Robert Lubos Date: Tue, 6 Feb 2024 11:07:35 +0100 Subject: [PATCH 3691/3723] Revert "[nrf fromlist] tests: flash: Use a flash partition that is known to be nonsecure" This reverts commit 1c92e08276186aaa7bff4935c5b4ec03b5294b05. Signed-off-by: Robert Lubos --- .../flash/common/boards/nrf5340dk_nrf5340_cpuapp_ns.conf | 4 ---- tests/drivers/flash/common/boards/nrf9160dk_nrf9160_ns.conf | 4 ---- tests/drivers/flash/common/boards/nrf9161dk_nrf9161_ns.conf | 4 ---- tests/drivers/flash/common/src/main.c | 3 +++ tests/drivers/flash/common/testcase.yaml | 2 +- 5 files changed, 4 insertions(+), 13 deletions(-) delete mode 100644 tests/drivers/flash/common/boards/nrf5340dk_nrf5340_cpuapp_ns.conf delete mode 100644 tests/drivers/flash/common/boards/nrf9160dk_nrf9160_ns.conf delete mode 100644 tests/drivers/flash/common/boards/nrf9161dk_nrf9161_ns.conf diff --git a/tests/drivers/flash/common/boards/nrf5340dk_nrf5340_cpuapp_ns.conf b/tests/drivers/flash/common/boards/nrf5340dk_nrf5340_cpuapp_ns.conf deleted file mode 100644 index 821a5e77e5b..00000000000 --- a/tests/drivers/flash/common/boards/nrf5340dk_nrf5340_cpuapp_ns.conf +++ /dev/null @@ -1,4 +0,0 @@ -CONFIG_FCB=y -CONFIG_FLASH_MAP=y -CONFIG_SETTINGS=y -CONFIG_SETTINGS_FCB=y diff --git a/tests/drivers/flash/common/boards/nrf9160dk_nrf9160_ns.conf b/tests/drivers/flash/common/boards/nrf9160dk_nrf9160_ns.conf deleted file mode 100644 index 821a5e77e5b..00000000000 --- a/tests/drivers/flash/common/boards/nrf9160dk_nrf9160_ns.conf +++ /dev/null @@ -1,4 +0,0 @@ -CONFIG_FCB=y -CONFIG_FLASH_MAP=y -CONFIG_SETTINGS=y -CONFIG_SETTINGS_FCB=y diff --git a/tests/drivers/flash/common/boards/nrf9161dk_nrf9161_ns.conf b/tests/drivers/flash/common/boards/nrf9161dk_nrf9161_ns.conf deleted file mode 100644 index 821a5e77e5b..00000000000 --- a/tests/drivers/flash/common/boards/nrf9161dk_nrf9161_ns.conf +++ /dev/null @@ -1,4 +0,0 @@ -CONFIG_FCB=y -CONFIG_FLASH_MAP=y -CONFIG_SETTINGS=y -CONFIG_SETTINGS_FCB=y diff --git a/tests/drivers/flash/common/src/main.c b/tests/drivers/flash/common/src/main.c index 79d75ca9b13..4e73617ba41 100644 --- a/tests/drivers/flash/common/src/main.c +++ b/tests/drivers/flash/common/src/main.c @@ -14,6 +14,9 @@ #define TEST_AREA_DEV_NODE DT_INST(0, nordic_qspi_nor) #elif defined(CONFIG_SPI_NOR) #define TEST_AREA_DEV_NODE DT_INST(0, jedec_spi_nor) +#elif defined(CONFIG_TRUSTED_EXECUTION_NONSECURE) +/* SoC embedded NVM */ +#define TEST_AREA slot1_ns_partition #else #define TEST_AREA storage_partition #endif diff --git a/tests/drivers/flash/common/testcase.yaml b/tests/drivers/flash/common/testcase.yaml index 9aa13bb40d5..f7ee0b7fc6d 100644 --- a/tests/drivers/flash/common/testcase.yaml +++ b/tests/drivers/flash/common/testcase.yaml @@ -38,7 +38,7 @@ tests: drivers.flash.common.tfm_ns: build_only: true filter: (CONFIG_FLASH_HAS_DRIVER_ENABLED and CONFIG_TRUSTED_EXECUTION_NONSECURE - and dt_label_with_parent_compat_enabled("storage_partition", "fixed-partitions")) + and dt_label_with_parent_compat_enabled("slot1_ns_partition", "fixed-partitions")) integration_platforms: - nrf9161dk_nrf9161_ns drivers.flash.common.stm32: From 9cca4caac7c5841b1d99b6d44cd447b6c9afb876 Mon Sep 17 00:00:00 2001 From: Robert Lubos Date: Tue, 6 Feb 2024 11:07:35 +0100 Subject: [PATCH 3692/3723] Revert "[nrf fromlist] samples: soc_flash_nrf: Make sure that the flash partition is valid" This reverts commit 4b2ae638e61279338ce40b65a6bbed0a1f73fae2. Signed-off-by: Robert Lubos --- samples/drivers/soc_flash_nrf/prj.conf | 4 ---- samples/drivers/soc_flash_nrf/src/main.c | 6 +++++- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/samples/drivers/soc_flash_nrf/prj.conf b/samples/drivers/soc_flash_nrf/prj.conf index 48e64121b6a..9909ef3b29f 100644 --- a/samples/drivers/soc_flash_nrf/prj.conf +++ b/samples/drivers/soc_flash_nrf/prj.conf @@ -3,7 +3,3 @@ CONFIG_FLASH=y CONFIG_FLASH_PAGE_LAYOUT=y CONFIG_MPU_ALLOW_FLASH_WRITE=y CONFIG_SOC_FLASH_NRF_EMULATE_ONE_BYTE_WRITE_ACCESS=y -CONFIG_FCB=y -CONFIG_FLASH_MAP=y -CONFIG_SETTINGS=y -CONFIG_SETTINGS_FCB=y diff --git a/samples/drivers/soc_flash_nrf/src/main.c b/samples/drivers/soc_flash_nrf/src/main.c index 29606a9ca5d..33ab9b28e1d 100644 --- a/samples/drivers/soc_flash_nrf/src/main.c +++ b/samples/drivers/soc_flash_nrf/src/main.c @@ -13,7 +13,11 @@ #include -#define TEST_PARTITION storage_partition +#ifdef CONFIG_TRUSTED_EXECUTION_NONSECURE +#define TEST_PARTITION slot1_ns_partition +#else +#define TEST_PARTITION slot1_partition +#endif #define TEST_PARTITION_OFFSET FIXED_PARTITION_OFFSET(TEST_PARTITION) #define TEST_PARTITION_DEVICE FIXED_PARTITION_DEVICE(TEST_PARTITION) From 27c92a6b85884f02d3f95591e37bf0d01a314707 Mon Sep 17 00:00:00 2001 From: Robert Lubos Date: Tue, 6 Feb 2024 11:07:35 +0100 Subject: [PATCH 3693/3723] Revert "[nrf fromlist] samples: soc_flash_nrf: Print finished message" This reverts commit 4819e656ade0727dca44e2a8d5cde16c1ebd4dc1. Signed-off-by: Robert Lubos --- samples/drivers/soc_flash_nrf/README.rst | 2 -- samples/drivers/soc_flash_nrf/sample.yaml | 1 - samples/drivers/soc_flash_nrf/src/main.c | 2 -- 3 files changed, 5 deletions(-) diff --git a/samples/drivers/soc_flash_nrf/README.rst b/samples/drivers/soc_flash_nrf/README.rst index 2ee87739aad..de49eb6db28 100644 --- a/samples/drivers/soc_flash_nrf/README.rst +++ b/samples/drivers/soc_flash_nrf/README.rst @@ -131,5 +131,3 @@ Sample Output Test 8: Write block size API write-block-size = 1 - - Finished! diff --git a/samples/drivers/soc_flash_nrf/sample.yaml b/samples/drivers/soc_flash_nrf/sample.yaml index d1f635ca93f..b8a59328be4 100644 --- a/samples/drivers/soc_flash_nrf/sample.yaml +++ b/samples/drivers/soc_flash_nrf/sample.yaml @@ -29,4 +29,3 @@ tests: - "Data read matches data written. Good!" - "SoC flash consists of \\d+ pages." - "write-block-size = 1" - - "Finished!" diff --git a/samples/drivers/soc_flash_nrf/src/main.c b/samples/drivers/soc_flash_nrf/src/main.c index 33ab9b28e1d..91a763c781d 100644 --- a/samples/drivers/soc_flash_nrf/src/main.c +++ b/samples/drivers/soc_flash_nrf/src/main.c @@ -191,7 +191,5 @@ int main(void) printf("\nTest 8: Write block size API\n"); printf(" write-block-size = %u\n", flash_get_write_block_size(flash_dev)); - - printf("\nFinished!\n"); return 0; } From 449f8f2482544dab3f634d0a07d458fa06d88f73 Mon Sep 17 00:00:00 2001 From: Robert Lubos Date: Tue, 6 Feb 2024 11:07:35 +0100 Subject: [PATCH 3694/3723] Revert "[nrf fromlist] samples: soc_flash_nrf: Stop erasing outside of test partition" This reverts commit 349b71d443761d191fa7f0af9df0ee77229b3597. Signed-off-by: Robert Lubos --- samples/drivers/soc_flash_nrf/README.rst | 2 +- samples/drivers/soc_flash_nrf/src/main.c | 6 +++--- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/samples/drivers/soc_flash_nrf/README.rst b/samples/drivers/soc_flash_nrf/README.rst index de49eb6db28..496688e8b65 100644 --- a/samples/drivers/soc_flash_nrf/README.rst +++ b/samples/drivers/soc_flash_nrf/README.rst @@ -62,7 +62,7 @@ Sample Output Data read: 1234 Data read matches data written. Good! - Test 3: Flash erase (2 pages at 0x80000) + Test 3: Flash erase (4 pages at 0x80000) Flash erase succeeded! Test 4: Flash write (word array 2) diff --git a/samples/drivers/soc_flash_nrf/src/main.c b/samples/drivers/soc_flash_nrf/src/main.c index 91a763c781d..a438a67cf2f 100644 --- a/samples/drivers/soc_flash_nrf/src/main.c +++ b/samples/drivers/soc_flash_nrf/src/main.c @@ -84,9 +84,9 @@ int main(void) } } - offset = TEST_PARTITION_OFFSET; - printf("\nTest 3: Flash erase (2 pages at 0x%x)\n", offset); - if (flash_erase(flash_dev, offset, FLASH_PAGE_SIZE * 2) != 0) { + offset = TEST_PARTITION_OFFSET - FLASH_PAGE_SIZE * 2; + printf("\nTest 3: Flash erase (4 pages at 0x%x)\n", offset); + if (flash_erase(flash_dev, offset, FLASH_PAGE_SIZE * 4) != 0) { printf(" Flash erase failed!\n"); } else { printf(" Flash erase succeeded!\n"); From 3b8edc7fd8eabaf7532593e262b9c711ad27f7b2 Mon Sep 17 00:00:00 2001 From: Robert Lubos Date: Tue, 6 Feb 2024 11:07:36 +0100 Subject: [PATCH 3695/3723] Revert "[nrf noup] newlib: Revert unintended change" This reverts commit b3979ec709df026fc655286f1a58be30b0f688e0. Signed-off-by: Robert Lubos --- lib/libc/newlib/Kconfig | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/libc/newlib/Kconfig b/lib/libc/newlib/Kconfig index 1b4f90341b0..a7d3ac38364 100644 --- a/lib/libc/newlib/Kconfig +++ b/lib/libc/newlib/Kconfig @@ -5,7 +5,7 @@ if NEWLIB_LIBC config NEWLIB_LIBC_NANO bool "Build with newlib-nano C library" - depends on HAS_NEWLIB_LIBC_NANO + depends on HAS_NEWLIB_LIBC_NANO && !WPA_SUPP help Build with newlib-nano library, for small embedded apps. The newlib-nano library for ARM embedded processors is a part of the From 1955b3468dab06a3e7521dd6303377c36a110e55 Mon Sep 17 00:00:00 2001 From: Robert Lubos Date: Tue, 6 Feb 2024 11:07:36 +0100 Subject: [PATCH 3696/3723] Revert "[nrf fromtree] net: openthread: Add openthread TCAT implementation." This reverts commit 145754e56829d73776aa285ea9de275d5e0d026d. Signed-off-by: Robert Lubos --- modules/openthread/CMakeLists.txt | 6 - modules/openthread/Kconfig.features | 4 - modules/openthread/Kconfig.thread | 12 - modules/openthread/platform/CMakeLists.txt | 1 - modules/openthread/platform/ble.c | 458 --------------------- 5 files changed, 481 deletions(-) delete mode 100644 modules/openthread/platform/ble.c diff --git a/modules/openthread/CMakeLists.txt b/modules/openthread/CMakeLists.txt index 8afa1aec440..2b2b593f82f 100644 --- a/modules/openthread/CMakeLists.txt +++ b/modules/openthread/CMakeLists.txt @@ -58,12 +58,6 @@ else() set(OT_BACKBONE_ROUTER_MULTICAST_ROUTING OFF CACHE BOOL "Enable BBR MR support" FORCE) endif() -if(CONFIG_OPENTHREAD_BLE_TCAT) - set(OT_BLE_TCAT ON CACHE BOOL "Enable BLE TCAT support" FORCE) -else() - set(OT_BLE_TCAT OFF CACHE BOOL "Enable BLE TCAT support" FORCE) -endif() - if(CONFIG_OPENTHREAD_BORDER_AGENT) set(OT_BORDER_AGENT ON CACHE BOOL "Enable Border Agent" FORCE) else() diff --git a/modules/openthread/Kconfig.features b/modules/openthread/Kconfig.features index bd8a05ed9b9..a75c9e8fd48 100644 --- a/modules/openthread/Kconfig.features +++ b/modules/openthread/Kconfig.features @@ -39,10 +39,6 @@ config OPENTHREAD_BACKBONE_ROUTER_DUA_NDPROXYING config OPENTHREAD_BACKBONE_ROUTER_MULTICAST_ROUTING bool "BBR MR support" -config OPENTHREAD_BLE_TCAT - bool "BLE TCAT support" - select EXPERIMENTAL - config OPENTHREAD_BORDER_AGENT bool "Border Agent support" diff --git a/modules/openthread/Kconfig.thread b/modules/openthread/Kconfig.thread index 66e039b7300..891365b4672 100644 --- a/modules/openthread/Kconfig.thread +++ b/modules/openthread/Kconfig.thread @@ -181,15 +181,3 @@ config OPENTHREAD_DEFAULT_TX_POWER default 0 help Set the default TX output power [dBm] in radio driver for OpenThread purpose. - -config OPENTHREAD_BLE_TCAT_THREAD_STACK_SIZE - int "Openthread default TCAT stack size" - default 4200 - help - Openthread default TCAT stack size. - -config OPENTHREAD_BLE_TCAT_RING_BUF_SIZE - int "Openthread BLE ringbuffer size" - default 512 - help - Openthread BLE TCAT ringbuffer size. diff --git a/modules/openthread/platform/CMakeLists.txt b/modules/openthread/platform/CMakeLists.txt index 542aa5186ea..d363bcda7df 100644 --- a/modules/openthread/platform/CMakeLists.txt +++ b/modules/openthread/platform/CMakeLists.txt @@ -10,7 +10,6 @@ zephyr_library_sources( spi.c ) -zephyr_library_sources_ifdef(CONFIG_OPENTHREAD_BLE_TCAT ble.c) zephyr_library_sources_ifdef(CONFIG_OPENTHREAD_DIAG diag.c) zephyr_library_sources_ifdef(CONFIG_OPENTHREAD_COPROCESSOR uart.c) zephyr_library_sources_ifdef(CONFIG_OPENTHREAD_CRYPTO_PSA crypto_psa.c) diff --git a/modules/openthread/platform/ble.c b/modules/openthread/platform/ble.c deleted file mode 100644 index 7b41556b617..00000000000 --- a/modules/openthread/platform/ble.c +++ /dev/null @@ -1,458 +0,0 @@ -/* - * Copyright (c) 2023 Nordic Semiconductor ASA - * - * SPDX-License-Identifier: Apache-2.0 - */ - -#include -#include -#include - -#include -#include -#include -#include - -#include -#include -#include -#include -#include - -/* Zephyr OpenThread integration Library */ -#include - -/* OpenThread BLE driver API */ -#include - -/* Zephyr Logging */ - -#define LOG_MODULE_NAME net_openthread_tcat -#define LOG_LEVEL CONFIG_OPENTHREAD_LOG_LEVEL - -LOG_MODULE_REGISTER(LOG_MODULE_NAME); - -#define DEVICE_NAME CONFIG_BT_DEVICE_NAME -#define DEVICE_NAME_LEN (sizeof(DEVICE_NAME) - 1) - -/* BLE connection constants as defined in thread specification. */ -#define TOBLE_SERVICE_UUID 0xfffb -#define RX_CHARACTERISTIC_UUID \ - BT_UUID_128_ENCODE(0x6bd10d8b, 0x85a7, 0x4e5a, 0xba2d, 0xc83558a5f220) -#define TX_CHARACTERISTIC_UUID \ - BT_UUID_128_ENCODE(0x7fddf61f, 0x280a, 0x4773, 0xb448, 0xba1b8fe0dd69) - -#define BT_UUID_TCAT_SERVICE BT_UUID_DECLARE_16(TOBLE_SERVICE_UUID) -#define BT_UUID_TCAT_SERVICE_RX BT_UUID_DECLARE_128(RX_CHARACTERISTIC_UUID) -#define BT_UUID_TCAT_SERVICE_TX BT_UUID_DECLARE_128(TX_CHARACTERISTIC_UUID) - -#define PLAT_BLE_THREAD_DEALY 500 -#define PLAT_BLE_MSG_DATA_MAX CONFIG_BT_L2CAP_TX_MTU /* must match the maximum MTU size used */ - -#define PLAT_BLE_MSG_CONNECT (PLAT_BLE_MSG_DATA_MAX + 1U) -#define PLAT_BLE_MSG_DISCONNECT (PLAT_BLE_MSG_CONNECT + 1U) - -/* Zephyr Kernel Objects */ - -static void ot_plat_ble_thread(void *, void *, void *); -static uint8_t ot_plat_ble_msg_buf[PLAT_BLE_MSG_DATA_MAX]; - -static K_SEM_DEFINE(ot_plat_ble_init_semaphore, 0, 1); -static K_SEM_DEFINE(ot_plat_ble_event_semaphore, 0, K_SEM_MAX_LIMIT); -RING_BUF_DECLARE(ot_plat_ble_ring_buf, CONFIG_OPENTHREAD_BLE_TCAT_RING_BUF_SIZE); -static K_THREAD_DEFINE(ot_plat_ble_tid, CONFIG_OPENTHREAD_BLE_TCAT_THREAD_STACK_SIZE, - ot_plat_ble_thread, NULL, NULL, NULL, 5, 0, PLAT_BLE_THREAD_DEALY); - -/* OpenThread Objects */ - -static otInstance *ble_openthread_instance; - -/* BLE service Objects */ - -/* forward declaration for callback functions */ -static ssize_t on_receive(struct bt_conn *conn, const struct bt_gatt_attr *attr, const void *buf, - uint16_t len, uint16_t offset, uint8_t flags); -static void on_cccd_changed(const struct bt_gatt_attr *attr, uint16_t value); - -/* Service Declaration and Registration */ -BT_GATT_SERVICE_DEFINE(my_service, BT_GATT_PRIMARY_SERVICE(BT_UUID_TCAT_SERVICE), - BT_GATT_CHARACTERISTIC(BT_UUID_TCAT_SERVICE_RX, - BT_GATT_CHRC_WRITE | BT_GATT_CHRC_WRITE_WITHOUT_RESP, - BT_GATT_PERM_READ | BT_GATT_PERM_WRITE, NULL, - on_receive, NULL), - BT_GATT_CHARACTERISTIC(BT_UUID_TCAT_SERVICE_TX, BT_GATT_CHRC_NOTIFY, - BT_GATT_PERM_READ, NULL, NULL, NULL), - BT_GATT_CCC(on_cccd_changed, BT_GATT_PERM_READ | BT_GATT_PERM_WRITE),); - -/* Zephyr BLE Objects */ - -/* forward declaration for callback functions */ -static void connected(struct bt_conn *conn, uint8_t err); -static void disconnected(struct bt_conn *conn, uint8_t reason); -static bool le_param_req(struct bt_conn *conn, struct bt_le_conn_param *param); -static void le_param_updated(struct bt_conn *conn, uint16_t interval, uint16_t latency, - uint16_t timeout); - -static struct bt_conn *ot_plat_ble_connection; - -static struct bt_conn_cb conn_callbacks = {.connected = connected, - .disconnected = disconnected, - .le_param_req = le_param_req, - .le_param_updated = le_param_updated}; - -static const struct bt_data ad[] = { - BT_DATA_BYTES(BT_DATA_FLAGS, (BT_LE_AD_GENERAL | BT_LE_AD_NO_BREDR)), - BT_DATA(BT_DATA_NAME_COMPLETE, DEVICE_NAME, DEVICE_NAME_LEN), -}; - -static const struct bt_data sd[] = { - BT_DATA_BYTES(BT_DATA_UUID16_ALL, BT_UUID_16_ENCODE(TOBLE_SERVICE_UUID)), -}; - -/* Zephyr BLE Message Queue and Thread */ - -static bool ot_plat_ble_queue_msg(const uint8_t *aData, uint16_t aLen, int8_t aRssi) -{ - otError error = OT_ERROR_NONE; - uint16_t len = 0; - - if (aLen <= PLAT_BLE_MSG_DATA_MAX && aData == NULL) { - return OT_ERROR_INVALID_ARGS; - } - - k_sched_lock(); - - len = sizeof(aLen) + sizeof(aRssi) + ((aLen <= PLAT_BLE_MSG_DATA_MAX) ? aLen : 0); - - if (ring_buf_space_get(&ot_plat_ble_ring_buf) >= len) { - ring_buf_put(&ot_plat_ble_ring_buf, (uint8_t *)&aLen, sizeof(aLen)); - ring_buf_put(&ot_plat_ble_ring_buf, &aRssi, sizeof(aRssi)); - if (aLen <= PLAT_BLE_MSG_DATA_MAX) { - ring_buf_put(&ot_plat_ble_ring_buf, aData, aLen); - } - k_sem_give(&ot_plat_ble_event_semaphore); - } else { - error = OT_ERROR_NO_BUFS; - } - - k_sched_unlock(); - - return error; -} - -static void ot_plat_ble_thread(void *unused1, void *unused2, void *unused3) -{ - ARG_UNUSED(unused1); - ARG_UNUSED(unused2); - ARG_UNUSED(unused3); - - uint16_t len; - int8_t rssi; - otBleRadioPacket my_packet; - - LOG_INF("%s started", __func__); - - while (1) { - k_sem_take(&ot_plat_ble_event_semaphore, K_FOREVER); - ring_buf_get(&ot_plat_ble_ring_buf, (uint8_t *)&len, sizeof(len)); - ring_buf_get(&ot_plat_ble_ring_buf, &rssi, sizeof(rssi)); - if (len <= PLAT_BLE_MSG_DATA_MAX) { - ring_buf_get(&ot_plat_ble_ring_buf, ot_plat_ble_msg_buf, len); - } - - openthread_api_mutex_lock(openthread_get_default_context()); - - if (len <= PLAT_BLE_MSG_DATA_MAX) { - /* The packet parameter in otPlatBleGattServerOnWriteRequest is not const. - * Re-write all members. - */ - my_packet.mValue = ot_plat_ble_msg_buf; - my_packet.mPower = rssi; - my_packet.mLength = len; - otPlatBleGattServerOnWriteRequest(ble_openthread_instance, 0, &my_packet); - } else if (len == PLAT_BLE_MSG_CONNECT) { - otPlatBleGapOnConnected(ble_openthread_instance, 0); - } else if (len == PLAT_BLE_MSG_DISCONNECT) { - otPlatBleGapOnDisconnected(ble_openthread_instance, 0); - } - openthread_api_mutex_unlock(openthread_get_default_context()); - } -} - -/* Zephyr BLE service callbacks */ - -/* This function is called whenever the RX Characteristic has been written to by a Client */ -static ssize_t on_receive(struct bt_conn *conn, const struct bt_gatt_attr *attr, const void *buf, - uint16_t len, uint16_t offset, uint8_t flags) -{ - LOG_DBG("Received data, handle %" PRIu16 ", len %" PRIu16, attr->handle, len); - - otError error = ot_plat_ble_queue_msg(buf, len, 0); - - if (error != OT_ERROR_NONE) { - LOG_WRN("Error queuing message: %s", otThreadErrorToString(error)); - } - - return len; -} - -/* This function is called whenever a Notification has been sent by the TX Characteristic */ -static void on_sent(struct bt_conn *conn, void *user_data) -{ - ARG_UNUSED(conn); - ARG_UNUSED(user_data); - - LOG_DBG("Data sent"); -} - -/* This function is called whenever the CCCD register has been changed by the client */ -void on_cccd_changed(const struct bt_gatt_attr *attr, uint16_t value) -{ - uint16_t mtu; - otError error = OT_ERROR_NONE; - - ARG_UNUSED(attr); - - switch (value) { - case BT_GATT_CCC_NOTIFY: - - error = ot_plat_ble_queue_msg(NULL, PLAT_BLE_MSG_CONNECT, 0); - if (error != OT_ERROR_NONE) { - LOG_WRN("Error queuing message: %s", otThreadErrorToString(error)); - } - - error = otPlatBleGattMtuGet(ble_openthread_instance, &mtu); - if (error != OT_ERROR_NONE) { - LOG_WRN("Error retrieving mtu: %s", otThreadErrorToString(error)); - } - - LOG_INF("CCCD update (mtu=%" PRIu16 ")!", mtu); - - break; - - default: - break; - } -} - -otError otPlatBleGattServerIndicate(otInstance *aInstance, uint16_t aHandle, - const otBleRadioPacket *aPacket) -{ - ARG_UNUSED(aInstance); - - /* TO DO change to indications. */ - const struct bt_gatt_attr *attr = &my_service.attrs[3]; - - struct bt_gatt_notify_params params = {.uuid = BT_UUID_TCAT_SERVICE_TX, - .attr = attr, - .data = aPacket->mValue, - .len = aPacket->mLength, - .func = on_sent}; - - LOG_DBG("Send data, handle %d, len %d", attr->handle, aPacket->mLength); - - /* Only one connection supported */ - if (aHandle != 0) { - return OT_ERROR_INVALID_ARGS; - } - - if (ot_plat_ble_connection == NULL) { - return OT_ERROR_INVALID_STATE; - } - - /* Check whether notifications are enabled or not */ - if (bt_gatt_is_subscribed(ot_plat_ble_connection, attr, BT_GATT_CCC_NOTIFY)) { - if (bt_gatt_notify_cb(ot_plat_ble_connection, ¶ms)) { - LOG_WRN("Error, unable to send notification"); - return OT_ERROR_INVALID_ARGS; - } - } else { - LOG_WRN("Warning, notification not enabled on the selected attribute"); - return OT_ERROR_INVALID_STATE; - } - - return OT_ERROR_NONE; -} - -otError otPlatBleGattMtuGet(otInstance *aInstance, uint16_t *aMtu) -{ - ARG_UNUSED(aInstance); - - if (ot_plat_ble_connection == NULL) { - return OT_ERROR_FAILED; - } - - if (aMtu != NULL) { - *aMtu = bt_gatt_get_mtu(ot_plat_ble_connection); - } - - return OT_ERROR_NONE; -} - -otError otPlatBleGapDisconnect(otInstance *aInstance) -{ - ARG_UNUSED(aInstance); - - if (ot_plat_ble_connection == NULL) { - return OT_ERROR_INVALID_STATE; - } - - if (bt_conn_disconnect(ot_plat_ble_connection, BT_HCI_ERR_REMOTE_USER_TERM_CONN)) { - return OT_ERROR_INVALID_STATE; - } - - return OT_ERROR_NONE; -} - -/* Zephyr BLE callbacks */ - -static void connected(struct bt_conn *conn, uint8_t err) -{ - struct bt_conn_info info; - char addr[BT_ADDR_LE_STR_LEN]; - uint16_t mtu; - otError error = OT_ERROR_NONE; - - ot_plat_ble_connection = bt_conn_ref(conn); - - if (err) { - LOG_WRN("Connection failed (err %u)", err); - return; - } else if (bt_conn_get_info(conn, &info)) { - LOG_WRN("Could not parse connection info"); - } else { - bt_addr_le_to_str(bt_conn_get_dst(conn), addr, sizeof(addr)); - - error = otPlatBleGattMtuGet(ble_openthread_instance, &mtu); - if (error != OT_ERROR_NONE) { - LOG_WRN("Error retrieving mtu: %s", otThreadErrorToString(error)); - } - - LOG_INF("Connection established (mtu=%" PRIu16 ")!", mtu); - } -} - -static void disconnected(struct bt_conn *conn, uint8_t reason) -{ - otError error = OT_ERROR_NONE; - - LOG_INF("Disconnected (reason %" PRIu8 ")", reason); - - if (ot_plat_ble_connection) { - bt_conn_unref(ot_plat_ble_connection); - ot_plat_ble_connection = NULL; - - error = ot_plat_ble_queue_msg(NULL, PLAT_BLE_MSG_DISCONNECT, 0); - if (error != OT_ERROR_NONE) { - LOG_WRN("Error queuing message: %s", otThreadErrorToString(error)); - } - } -} - -static bool le_param_req(struct bt_conn *conn, struct bt_le_conn_param *param) -{ - return true; -} - -static void le_param_updated(struct bt_conn *conn, uint16_t interval, uint16_t latency, - uint16_t timeout) -{ - struct bt_conn_info info; - char addr[BT_ADDR_LE_STR_LEN]; - uint16_t mtu; - otError error = OT_ERROR_NONE; - - if (bt_conn_get_info(conn, &info)) { - LOG_INF("Could not parse connection info"); - } else { - bt_addr_le_to_str(bt_conn_get_dst(conn), addr, sizeof(addr)); - - error = otPlatBleGattMtuGet(ble_openthread_instance, &mtu); - - if (error != OT_ERROR_NONE) { - LOG_WRN("Error retrieving mtu: %s", otThreadErrorToString(error)); - } - - LOG_INF("Connection parameters updated (mtu=%" PRIu16 ")!", mtu); - } -} - -static void bt_ready(int err) -{ - if (err) { - LOG_WRN("BLE init failed with error code %d", err); - return; - } - - bt_conn_cb_register(&conn_callbacks); - k_sem_give(&ot_plat_ble_init_semaphore); /* BLE stack up an running */ -} - -otError otPlatBleGapAdvStart(otInstance *aInstance, uint16_t aInterval) -{ - ARG_UNUSED(aInstance); - ARG_UNUSED(aInterval); - - /* TO DO advertisement format change */ - int err = bt_le_adv_start(BT_LE_ADV_CONN, ad, ARRAY_SIZE(ad), sd, ARRAY_SIZE(sd)); - - if (err != 0 && err != -EALREADY) { - LOG_WRN("Advertising failed to start (err %d)", err); - return OT_ERROR_INVALID_STATE; - } - - LOG_INF("Advertising successfully started"); - - return OT_ERROR_NONE; -} - -otError otPlatBleGapAdvStop(otInstance *aInstance) -{ - ARG_UNUSED(aInstance); - - int err = bt_le_adv_stop(); - - if (err != 0 && err != -EALREADY) { - LOG_WRN("Advertisement failed to stop (err %d)", err); - return OT_ERROR_FAILED; - } - return OT_ERROR_NONE; -} - -/* Zephyr BLE initialization */ - -otError otPlatBleEnable(otInstance *aInstance) -{ - int err; - - ble_openthread_instance = aInstance; - err = bt_enable(bt_ready); - - if (err != 0 && err != -EALREADY) { - LOG_WRN("BLE enable failed with error code %d", err); - return OT_ERROR_FAILED; - } else if (err == -EALREADY) { - err = k_sem_take(&ot_plat_ble_init_semaphore, K_MSEC(500)); - return OT_ERROR_NONE; - } - - err = k_sem_take(&ot_plat_ble_init_semaphore, K_MSEC(500)); - - if (!err) { - LOG_INF("Bluetooth initialized"); - } else { - LOG_INF("BLE initialization did not complete in time"); - return OT_ERROR_FAILED; - } - - return OT_ERROR_NONE; -} - -otError otPlatBleDisable(otInstance *aInstance) -{ - ARG_UNUSED(aInstance); - /* This function intentionally does nothing since disabling advertisement disables BLE - * stack. - */ - return OT_ERROR_NONE; -} From acf6e97938d787f4db65f884222016ec55982fae Mon Sep 17 00:00:00 2001 From: Robert Lubos Date: Tue, 6 Feb 2024 11:07:36 +0100 Subject: [PATCH 3697/3723] Revert "[nrf fromtree] modules: hal_nordic: nRF 802.15.4 customizable asserts" This reverts commit e4511cfcb7a672ca1bb0d6296dc257df6af0b12f. Signed-off-by: Robert Lubos --- modules/hal_nordic/Kconfig | 28 +----------------- modules/hal_nordic/nrf_802154/CMakeLists.txt | 5 ---- .../include/nrf_802154_assert_zephyr.h | 29 ------------------- .../nrf_802154/nrf_802154_assert_handler.c | 26 ----------------- 4 files changed, 1 insertion(+), 87 deletions(-) delete mode 100644 modules/hal_nordic/nrf_802154/include/nrf_802154_assert_zephyr.h delete mode 100644 modules/hal_nordic/nrf_802154/nrf_802154_assert_handler.c diff --git a/modules/hal_nordic/Kconfig b/modules/hal_nordic/Kconfig index 44c12e88685..f842d2cb646 100644 --- a/modules/hal_nordic/Kconfig +++ b/modules/hal_nordic/Kconfig @@ -205,39 +205,13 @@ endif endmenu # NRF_802154_SER_HOST || NRF_802154_SER_RADIO -if NRF_802154_RADIO_DRIVER || NRF_802154_SERIALIZATION - config NRF_802154_CARRIER_FUNCTIONS bool "nRF 802.15.4 carrier functions" + depends on NRF_802154_RADIO_DRIVER || NRF_802154_SERIALIZATION help This option enables functions such as modulated carrier and continuous carrier. If this option is modified on a multicore SoC, its remote counterpart must be set to the exact same value. -choice NRF_802154_ASSERT_CHOICE - prompt "nRF 802.15.4 assert implementation" - default NRF_802154_ASSERT_ZEPHYR_MINIMAL - -config NRF_802154_ASSERT_ZEPHYR_MINIMAL - bool "nRF 802.15.4 minimal assertions" - help - This option provides minimal run-time checking of the nRF 802.15.4 Radio Driver's operation, - even if kernel-wide CONFIG_ASSERT is disabled. In case of an abnormal condition the function - `nrf_802154_assert_handler()` is called. File and line debug information are not provided - to save memory of the image file. Default implementation of the `nrf_802154_assert_handler` - involves a call to `k_panic`/`k_oops` and allows further tweaking of the behavior. - You can also provide your own implementation of `nrf_802154_assert_handler`. - -config NRF_802154_ASSERT_ZEPHYR - bool "nRF 802.15.4 Radio Driver assertions as Zephyr's standard __ASERT_NO_MSG" - help - The run-time checking of the nRF 802.15.4 Radio Driver depends fully on the configuration - of the `__ASSERT_NO_MSG` macro, including the ability to completely turn off the run-time - checking. - -endchoice # NRF_802154_ASSERT_CHOICE - -endif # NRF_802154_RADIO_DRIVER || NRF_802154_SERIALIZATION - endmenu # HAS_NORDIC_DRIVERS rsource "nrfx/Kconfig" diff --git a/modules/hal_nordic/nrf_802154/CMakeLists.txt b/modules/hal_nordic/nrf_802154/CMakeLists.txt index cd5ace0b278..c338981b651 100644 --- a/modules/hal_nordic/nrf_802154/CMakeLists.txt +++ b/modules/hal_nordic/nrf_802154/CMakeLists.txt @@ -95,11 +95,6 @@ endif() if (CONFIG_NRF_802154_RADIO_DRIVER OR CONFIG_NRF_802154_SERIALIZATION) target_compile_definitions(zephyr-802154-interface INTERFACE NRF_802154_ENERGY_DETECTED_VERSION=1) - if (CONFIG_NRF_802154_ASSERT_ZEPHYR OR CONFIG_NRF_802154_ASSERT_ZEPHYR_MINIMAL) - target_include_directories(zephyr-802154-interface INTERFACE include) - target_compile_definitions(zephyr-802154-interface INTERFACE NRF_802154_PLATFORM_ASSERT_INCLUDE=\"nrf_802154_assert_zephyr.h\") - target_sources(nrf-802154-platform PRIVATE nrf_802154_assert_handler.c) - endif() endif() set(NRF52_SERIES ${CONFIG_SOC_SERIES_NRF52X}) diff --git a/modules/hal_nordic/nrf_802154/include/nrf_802154_assert_zephyr.h b/modules/hal_nordic/nrf_802154/include/nrf_802154_assert_zephyr.h deleted file mode 100644 index ecd09de609a..00000000000 --- a/modules/hal_nordic/nrf_802154/include/nrf_802154_assert_zephyr.h +++ /dev/null @@ -1,29 +0,0 @@ -/* - * Copyright (c) 2023, Nordic Semiconductor ASA - * - * SPDX-License-Identifier: Apache-2.0 - */ - -#ifndef NRF_802154_ASSERT_ZEPHYR_H__ -#define NRF_802154_ASSERT_ZEPHYR_H__ - -#if defined(CONFIG_NRF_802154_ASSERT_ZEPHYR) - -#include - -#define NRF_802154_ASSERT(condition) __ASSERT_NO_MSG(condition) - -#elif defined(CONFIG_NRF_802154_ASSERT_ZEPHYR_MINIMAL) - -extern void nrf_802154_assert_handler(void); - -#define NRF_802154_ASSERT(condition) \ - do { \ - if (!(condition)) { \ - nrf_802154_assert_handler(); \ - } \ - } while (0) - -#endif /* CONFIG_NRF_802154_ASSERT_ZEPHYR_MINIMAL */ - -#endif /* NRF_802154_ASSERT_ZEPHYR_H__*/ diff --git a/modules/hal_nordic/nrf_802154/nrf_802154_assert_handler.c b/modules/hal_nordic/nrf_802154/nrf_802154_assert_handler.c deleted file mode 100644 index 14d964724c6..00000000000 --- a/modules/hal_nordic/nrf_802154/nrf_802154_assert_handler.c +++ /dev/null @@ -1,26 +0,0 @@ -/* - * Copyright (c) 2023 Nordic Semiconductor ASA - * - * SPDX-License-Identifier: Apache-2.0 - */ - -#include -#include "nrf_802154_assert_zephyr.h" - -#if defined(CONFIG_NRF_802154_ASSERT_ZEPHYR_MINIMAL) - -__weak void nrf_802154_assert_handler(void) -{ -#ifdef CONFIG_USERSPACE - /* User threads aren't allowed to induce kernel panics; generate - * an oops instead. - */ - if (k_is_user_context()) { - k_oops(); - } -#endif - - k_panic(); -} - -#endif /* CONFIG_NRF_802154_ASSERT_ZEPHYR_MINIMAL */ From 740c753548235acd931cb483fe9d573c1bed504e Mon Sep 17 00:00:00 2001 From: Robert Lubos Date: Tue, 6 Feb 2024 11:07:36 +0100 Subject: [PATCH 3698/3723] Revert "[nrf fromlist] wifi: Add the enums to the status" This reverts commit 1a6d964dd2e6aa19ae755b5e2404e63b015e060c. Signed-off-by: Robert Lubos --- include/zephyr/net/wifi_mgmt.h | 6 +----- lib/libc/newlib/Kconfig | 2 +- 2 files changed, 2 insertions(+), 6 deletions(-) diff --git a/include/zephyr/net/wifi_mgmt.h b/include/zephyr/net/wifi_mgmt.h index babf67722c1..e52cefd2d68 100644 --- a/include/zephyr/net/wifi_mgmt.h +++ b/include/zephyr/net/wifi_mgmt.h @@ -353,11 +353,7 @@ enum wifi_disconn_reason { /** Generic Wi-Fi status for commands and events */ struct wifi_status { - union { - int status; - enum wifi_conn_status conn_status; - enum wifi_disconn_reason disconn_reason; - }; + int status; }; /** Wi-Fi interface status */ diff --git a/lib/libc/newlib/Kconfig b/lib/libc/newlib/Kconfig index a7d3ac38364..1b4f90341b0 100644 --- a/lib/libc/newlib/Kconfig +++ b/lib/libc/newlib/Kconfig @@ -5,7 +5,7 @@ if NEWLIB_LIBC config NEWLIB_LIBC_NANO bool "Build with newlib-nano C library" - depends on HAS_NEWLIB_LIBC_NANO && !WPA_SUPP + depends on HAS_NEWLIB_LIBC_NANO help Build with newlib-nano library, for small embedded apps. The newlib-nano library for ARM embedded processors is a part of the From 3399c881284818f66e4ab9bce9675faf888d2fcb Mon Sep 17 00:00:00 2001 From: Robert Lubos Date: Tue, 6 Feb 2024 11:07:36 +0100 Subject: [PATCH 3699/3723] Revert "[nrf fromlist] wifi: Add an enum for disconnect reasons" This reverts commit 4c6c7fa95617e53d2b9d5347d0a066a2fbe559a0. Signed-off-by: Robert Lubos --- include/zephyr/net/wifi_mgmt.h | 14 -------------- 1 file changed, 14 deletions(-) diff --git a/include/zephyr/net/wifi_mgmt.h b/include/zephyr/net/wifi_mgmt.h index e52cefd2d68..91c9ad088a8 100644 --- a/include/zephyr/net/wifi_mgmt.h +++ b/include/zephyr/net/wifi_mgmt.h @@ -337,20 +337,6 @@ enum wifi_conn_status { WIFI_STATUS_CONN_AP_NOT_FOUND, }; -/** Wi-Fi disconnect reason codes. To be overlaid on top of \ref wifi_status - * in the disconnect result event for detailed reason. - */ -enum wifi_disconn_reason { - /** Unspecified reason */ - WIFI_REASON_DISCONN_UNSPECIFIED = 0, - /** Disconnected due to user request */ - WIFI_REASON_DISCONN_USER_REQUEST, - /** Disconnected due to AP leaving */ - WIFI_REASON_DISCONN_AP_LEAVING, - /** Disconnected due to inactivity */ - WIFI_REASON_DISCONN_INACTIVITY, -}; - /** Generic Wi-Fi status for commands and events */ struct wifi_status { int status; From 2f2eb9e8223596bb99004acd372e7ede8a622d8f Mon Sep 17 00:00:00 2001 From: Robert Lubos Date: Tue, 6 Feb 2024 11:07:36 +0100 Subject: [PATCH 3700/3723] Revert "[nrf fromlist] wifi: Add an enum for connect result status" This reverts commit 3e94ff1efea007b75e8d9bf6b8e86076cb31525a. Signed-off-by: Robert Lubos --- include/zephyr/net/wifi_mgmt.h | 16 ---------------- 1 file changed, 16 deletions(-) diff --git a/include/zephyr/net/wifi_mgmt.h b/include/zephyr/net/wifi_mgmt.h index 91c9ad088a8..faf83b42b84 100644 --- a/include/zephyr/net/wifi_mgmt.h +++ b/include/zephyr/net/wifi_mgmt.h @@ -321,22 +321,6 @@ struct wifi_connect_req_params { int timeout; }; -/** Wi-Fi connect result codes. To be overlaid on top of \ref wifi_status - * in the connect result event for detailed status. - */ -enum wifi_conn_status { - /** Connection successful */ - WIFI_STATUS_CONN_SUCCESS = 0, - /** Connection failed - generic failure */ - WIFI_STATUS_CONN_FAIL, - /** Connection failed - wrong password */ - WIFI_STATUS_CONN_WRONG_PASSWORD, - /** Connection timed out */ - WIFI_STATUS_CONN_TIMEOUT, - /** Connection failed - AP not found */ - WIFI_STATUS_CONN_AP_NOT_FOUND, -}; - /** Generic Wi-Fi status for commands and events */ struct wifi_status { int status; From af06478dde4abc4fdd2dcca1bc747ca6fb075cf9 Mon Sep 17 00:00:00 2001 From: Robert Lubos Date: Tue, 6 Feb 2024 11:07:37 +0100 Subject: [PATCH 3701/3723] Revert "[nrf fromtree] net: l2: wifi: Fix Print of SSID in WIFI status" This reverts commit 2364b332d085341d78e9618125256ae3a5cc71b0. Signed-off-by: Robert Lubos --- subsys/net/l2/wifi/wifi_shell.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/subsys/net/l2/wifi/wifi_shell.c b/subsys/net/l2/wifi/wifi_shell.c index 5f7eb5ba0ee..ed85b015971 100644 --- a/subsys/net/l2/wifi/wifi_shell.c +++ b/subsys/net/l2/wifi/wifi_shell.c @@ -647,7 +647,7 @@ static int cmd_wifi_status(const struct shell *sh, size_t argc, char *argv[]) wifi_mode_txt(status.iface_mode)); shell_fprintf(sh, SHELL_NORMAL, "Link Mode: %s\n", wifi_link_mode_txt(status.link_mode)); - shell_fprintf(sh, SHELL_NORMAL, "SSID: %.32s\n", status.ssid); + shell_fprintf(sh, SHELL_NORMAL, "SSID: %-32s\n", status.ssid); shell_fprintf(sh, SHELL_NORMAL, "BSSID: %s\n", net_sprint_ll_addr_buf(status.bssid, WIFI_MAC_ADDR_LEN, mac_string_buf, From 3218999933e02d64ef5a961733c9ba2afb087d37 Mon Sep 17 00:00:00 2001 From: Robert Lubos Date: Tue, 6 Feb 2024 11:07:37 +0100 Subject: [PATCH 3702/3723] Revert "[nrf fromlist] wifi: Check WPA-PSK passphrase length" This reverts commit 8721401fed0cd5df940610005b411821c6c16648. Signed-off-by: Robert Lubos --- subsys/net/l2/wifi/wifi_mgmt.c | 1 - 1 file changed, 1 deletion(-) diff --git a/subsys/net/l2/wifi/wifi_mgmt.c b/subsys/net/l2/wifi/wifi_mgmt.c index 1a866d4c47c..6eb8a6682c2 100644 --- a/subsys/net/l2/wifi/wifi_mgmt.c +++ b/subsys/net/l2/wifi/wifi_mgmt.c @@ -274,7 +274,6 @@ static int wifi_connect(uint32_t mgmt_request, struct net_if *iface, (params->ssid_length > WIFI_SSID_MAX_LEN) || (params->ssid_length == 0U) || ((params->security == WIFI_SECURITY_TYPE_PSK || - params->security == WIFI_SECURITY_TYPE_WPA_PSK || params->security == WIFI_SECURITY_TYPE_PSK_SHA256) && ((params->psk_length < 8) || (params->psk_length > 64) || (params->psk_length == 0U) || !params->psk)) || From ee8145adfd9e9a39b6438bfb9d7d302ee174d220 Mon Sep 17 00:00:00 2001 From: Robert Lubos Date: Tue, 6 Feb 2024 11:07:37 +0100 Subject: [PATCH 3703/3723] Revert "[nrf fromtree] Bluetooth: Host: build shell power_control_request" This reverts commit f8dc8ac55203667f5137e4d4e245de4277db4980. Signed-off-by: Robert Lubos --- tests/bluetooth/shell/testcase.yaml | 7 ------- 1 file changed, 7 deletions(-) diff --git a/tests/bluetooth/shell/testcase.yaml b/tests/bluetooth/shell/testcase.yaml index ef4eed67eb3..4b46c8d6781 100644 --- a/tests/bluetooth/shell/testcase.yaml +++ b/tests/bluetooth/shell/testcase.yaml @@ -13,13 +13,6 @@ tests: tags: bluetooth harness: keyboard min_flash: 145 - bluetooth.shell.power_control_request: - extra_configs: - - CONFIG_BT_TRANSMIT_POWER_CONTROL=y - - CONFIG_BT_CTLR=n - platform_allow: - - native_posix - build_only: true bluetooth.shell.cdc_acm: extra_args: - OVERLAY_CONFIG=cdc_acm.conf From a47783bedf33a00c42c55f3acd624bb3683ce37b Mon Sep 17 00:00:00 2001 From: Robert Lubos Date: Tue, 6 Feb 2024 11:07:37 +0100 Subject: [PATCH 3704/3723] Revert "[nrf fromtree] Bluetooth: Host: Align return lines of bt shell helper function phy2str" This reverts commit 74b0d020e749332b39d9a1140d49a2afa538c2ec. Signed-off-by: Robert Lubos --- subsys/bluetooth/shell/bt.c | 12 ++++-------- 1 file changed, 4 insertions(+), 8 deletions(-) diff --git a/subsys/bluetooth/shell/bt.c b/subsys/bluetooth/shell/bt.c index 4e0111fa757..f9bdd8f8094 100644 --- a/subsys/bluetooth/shell/bt.c +++ b/subsys/bluetooth/shell/bt.c @@ -99,14 +99,10 @@ static const char *phy2str(uint8_t phy) { switch (phy) { case 0: return "No packets"; - case BT_GAP_LE_PHY_1M: - return "LE 1M"; - case BT_GAP_LE_PHY_2M: - return "LE 2M"; - case BT_GAP_LE_PHY_CODED: - return "LE Coded"; - default: - return "Unknown"; + case BT_GAP_LE_PHY_1M: return "LE 1M"; + case BT_GAP_LE_PHY_2M: return "LE 2M"; + case BT_GAP_LE_PHY_CODED: return "LE Coded"; + default: return "Unknown"; } } #endif From 896393e8a2d2c39c8ef04802dba0ebd4d1b8b457 Mon Sep 17 00:00:00 2001 From: Robert Lubos Date: Tue, 6 Feb 2024 11:07:37 +0100 Subject: [PATCH 3705/3723] Revert "[nrf fromtree] Bluetooth: Host: Add bt shell functions LE Power Control Request Feature" This reverts commit 9d18c0aa9ac4139965935775aa58925f78c85a06. Signed-off-by: Robert Lubos --- subsys/bluetooth/shell/bt.c | 178 ------------------------------------ 1 file changed, 178 deletions(-) diff --git a/subsys/bluetooth/shell/bt.c b/subsys/bluetooth/shell/bt.c index f9bdd8f8094..3f1af44de6f 100644 --- a/subsys/bluetooth/shell/bt.c +++ b/subsys/bluetooth/shell/bt.c @@ -123,67 +123,6 @@ static void print_le_addr(const char *desc, const bt_addr_le_t *addr) } #endif /* CONFIG_BT_CONN || (CONFIG_BT_BROADCASTER && CONFIG_BT_EXT_ADV) */ -#if defined(CONFIG_BT_TRANSMIT_POWER_CONTROL) -static const char *tx_power_flag2str(int8_t flag) -{ - switch (flag) { - case 0: - return "Neither Max nor Min Tx Power"; - case 1: - return "Tx Power Level is at minimum"; - case 2: - return "Tx Power Level is at maximum"; - /* Current Tx Power Level is the only available one*/ - case 3: - return "Tx Power Level is at minimum & maximum."; - default: - return "Unknown"; - } -} - -static const char *tx_power_report_reason2str(uint8_t reason) -{ - switch (reason) { - case BT_HCI_LE_TX_POWER_REPORT_REASON_LOCAL_CHANGED: - return "Local Tx Power changed"; - case BT_HCI_LE_TX_POWER_REPORT_REASON_REMOTE_CHANGED: - return "Remote Tx Power changed"; - case BT_HCI_LE_TX_POWER_REPORT_REASON_READ_REMOTE_COMPLETED: - return "Completed to read remote Tx Power"; - default: - return "Unknown"; - } -} - -static const char *tx_pwr_ctrl_phy2str(enum bt_conn_le_tx_power_phy phy) -{ - switch (phy) { - case BT_CONN_LE_TX_POWER_PHY_NONE: - return "None"; - case BT_CONN_LE_TX_POWER_PHY_1M: - return "LE 1M"; - case BT_CONN_LE_TX_POWER_PHY_2M: - return "LE 2M"; - case BT_CONN_LE_TX_POWER_PHY_CODED_S8: - return "LE Coded S8"; - case BT_CONN_LE_TX_POWER_PHY_CODED_S2: - return "LE Coded S2"; - default: - return "Unknown"; - } -} - -static const char *enabled2str(bool enabled) -{ - if (enabled) { - return "Enabled"; - } else { - return "Disabled"; - } -} - -#endif /* CONFIG_BT_TRANSMIT_POWER_CONTROL */ - #if defined(CONFIG_BT_CENTRAL) static int cmd_scan_off(const struct shell *sh); static int cmd_connect_le(const struct shell *sh, size_t argc, char *argv[]); @@ -870,19 +809,6 @@ void le_phy_updated(struct bt_conn *conn, } #endif -#if defined(CONFIG_BT_TRANSMIT_POWER_CONTROL) -void tx_power_report(struct bt_conn *conn, - const struct bt_conn_le_tx_power_report *report) -{ - shell_print(ctx_shell, "Tx Power Report: Reason: %s, PHY: %s, Tx Power Level: %d", - tx_power_report_reason2str(report->reason), tx_pwr_ctrl_phy2str(report->phy), - report->tx_power_level); - shell_print(ctx_shell, "Tx Power Level Flag Info: %s, Delta: %d", - tx_power_flag2str(report->tx_power_level_flag), report->delta); -} -#endif - - static struct bt_conn_cb conn_callbacks = { .connected = connected, .disconnected = disconnected, @@ -903,9 +829,6 @@ static struct bt_conn_cb conn_callbacks = { #if defined(CONFIG_BT_USER_PHY_UPDATE) .le_phy_updated = le_phy_updated, #endif -#if defined(CONFIG_BT_TRANSMIT_POWER_CONTROL) - .tx_power_report = tx_power_report, -#endif }; #endif /* CONFIG_BT_CONN */ @@ -2685,102 +2608,6 @@ static int cmd_per_adv_set_info_transfer(const struct shell *sh, size_t argc, } #endif /* CONFIG_BT_PER_ADV_SYNC_TRANSFER_SENDER && CONFIG_BT_PER_ADV */ -#if defined(CONFIG_BT_TRANSMIT_POWER_CONTROL) -static int cmd_read_remote_tx_power(const struct shell *sh, size_t argc, char *argv[]) -{ - if (argc < 3) { - int err = 0; - enum bt_conn_le_tx_power_phy phy = strtoul(argv[1], NULL, 16); - - err = bt_conn_le_get_remote_tx_power_level(default_conn, phy); - - if (!err) { - shell_print(sh, "Read Remote TX Power for PHY %s", - tx_pwr_ctrl_phy2str(phy)); - } else { - shell_print(sh, "error %d", err); - } - } else { - shell_help(sh); - return SHELL_CMD_HELP_PRINTED; - } - return 0; -} - -static int cmd_read_local_tx_power(const struct shell *sh, size_t argc, char *argv[]) -{ - int err = 0; - - if (argc < 3) { - struct bt_conn_le_tx_power tx_power_level; - - tx_power_level.phy = strtoul(argv[1], NULL, 16); - - int8_t unachievable_current_level = -100; - /* Arbitrary, these are output parameters.*/ - tx_power_level.current_level = unachievable_current_level; - tx_power_level.max_level = 6; - - if (default_conn == NULL) { - shell_error(sh, "Conn handle error, at least one connection is required."); - return -ENOEXEC; - } - err = bt_conn_le_get_tx_power_level(default_conn, &tx_power_level); - if (err) { - shell_print(sh, "Commad returned error error %d", err); - return err; - } - if (tx_power_level.current_level == unachievable_current_level) { - shell_print(sh, "We received no current tx power level."); - return -EIO; - } - shell_print(sh, "Read local TX Power: current level: %d, PHY: %s, Max Level: %d", - tx_power_level.current_level, - tx_pwr_ctrl_phy2str((enum bt_conn_le_tx_power_phy)tx_power_level.phy), - tx_power_level.max_level); - } else { - shell_help(sh); - return SHELL_CMD_HELP_PRINTED; - } - - return err; -} - -static int cmd_set_power_report_enable(const struct shell *sh, size_t argc, char *argv[]) -{ - if (argc < 4) { - int err = 0; - bool local_enable = 0; - bool remote_enable = 0; - - if (*argv[1] == '1') { - local_enable = 1; - } - if (*argv[2] == '1') { - remote_enable = 1; - } - if (default_conn == NULL) { - shell_error(sh, "Conn handle error, at least one connection is required."); - return -ENOEXEC; - } - err = bt_conn_le_set_tx_power_report_enable(default_conn, local_enable, - remote_enable); - if (!err) { - shell_print(sh, "Tx Power Report: local: %s, remote: %s", - enabled2str(local_enable), enabled2str(remote_enable)); - } else { - shell_print(sh, "error %d", err); - } - } else { - shell_help(sh); - return SHELL_CMD_HELP_PRINTED; - } - return 0; -} - -#endif - - #if defined(CONFIG_BT_CONN) #if defined(CONFIG_BT_CENTRAL) static int cmd_connect_le(const struct shell *sh, size_t argc, char *argv[]) @@ -4188,11 +4015,6 @@ SHELL_STATIC_SUBCMD_SET_CREATE(bt_cmds, cmd_default_handler), SHELL_CMD_ARG(scan-verbose-output, NULL, "", cmd_scan_verbose_output, 2, 0), #endif /* CONFIG_BT_OBSERVER */ -#if defined(CONFIG_BT_TRANSMIT_POWER_CONTROL) - SHELL_CMD_ARG(read-remote-tx-power, NULL, HELP_NONE, cmd_read_remote_tx_power, 2, 0), - SHELL_CMD_ARG(read-local-tx-power, NULL, HELP_NONE, cmd_read_local_tx_power, 2, 0), - SHELL_CMD_ARG(set-power-report-enable, NULL, HELP_NONE, cmd_set_power_report_enable, 3, 0), -#endif #if defined(CONFIG_BT_BROADCASTER) SHELL_CMD_ARG(advertise, NULL, " [mode: discov, non_discov] " From a615b1d9a8300db06ea360f260ddf21fa59358e2 Mon Sep 17 00:00:00 2001 From: Robert Lubos Date: Tue, 6 Feb 2024 11:07:37 +0100 Subject: [PATCH 3706/3723] Revert "[nrf fromtree] Bluetooth: Host: Add LE Power Control Request Procedure APIs" This reverts commit 90bd9418d718975f0cba8d2a1c3c27fddb10cbcf. Signed-off-by: Robert Lubos --- include/zephyr/bluetooth/conn.h | 87 --------------------- include/zephyr/bluetooth/hci_types.h | 49 ------------ subsys/bluetooth/Kconfig | 8 -- subsys/bluetooth/host/conn.c | 108 +------------------------- subsys/bluetooth/host/conn_internal.h | 3 - subsys/bluetooth/host/hci_core.c | 34 -------- 6 files changed, 4 insertions(+), 285 deletions(-) diff --git a/include/zephyr/bluetooth/conn.h b/include/zephyr/bluetooth/conn.h index bdc644d82e9..09b8321d685 100644 --- a/include/zephyr/bluetooth/conn.h +++ b/include/zephyr/bluetooth/conn.h @@ -479,42 +479,6 @@ struct bt_conn_le_tx_power { int8_t max_level; }; - -/** LE Transmit Power Reporting Structure */ -struct bt_conn_le_tx_power_report { - - /** Reason for Transmit power reporting, - * as documented in Core Spec. Version 5.4 Vol. 4, Part E, 7.7.65.33. - */ - uint8_t reason; - - /** Phy of Transmit power reporting. */ - enum bt_conn_le_tx_power_phy phy; - - /** Transmit power level - * - 0xXX - Transmit power level - * + Range: -127 to 20 - * + Units: dBm - * - * - 0x7E - Remote device is not managing power levels on this PHY. - * - 0x7F - Transmit power level is not available - */ - int8_t tx_power_level; - - /** Bit 0: Transmit power level is at minimum level. - * Bit 1: Transmit power level is at maximum level. - */ - uint8_t tx_power_level_flag; - - /** Change in transmit power level - * - 0xXX - Change in transmit power level (positive indicates increased - * power, negative indicates decreased power, zero indicates unchanged) - * Units: dB - * - 0x7F - Change is not available or is out of range. - */ - int8_t delta; -}; - /** @brief Passkey Keypress Notification type * * The numeric values are the same as in the Core specification for Pairing @@ -566,41 +530,6 @@ int bt_conn_get_remote_info(struct bt_conn *conn, int bt_conn_le_get_tx_power_level(struct bt_conn *conn, struct bt_conn_le_tx_power *tx_power_level); -/** @brief Get local enhanced connection transmit power level. - * - * @param conn Connection object. - * @param tx_power Transmit power level descriptor. - * - * @return Zero on success or (negative) error code on failure. - * @retval -ENOBUFS HCI command buffer is not available. - */ -int bt_conn_le_enhanced_get_tx_power_level(struct bt_conn *conn, - struct bt_conn_le_tx_power *tx_power); - -/** @brief Get remote (peer) transmit power level. - * - * @param conn Connection object. - * @param phy PHY information. - * - * @return Zero on success or (negative) error code on failure. - * @retval -ENOBUFS HCI command buffer is not available. - */ -int bt_conn_le_get_remote_tx_power_level(struct bt_conn *conn, - enum bt_conn_le_tx_power_phy phy); - -/** @brief Enable transmit power reporting. - * - * @param conn Connection object. - * @param local_enable Enable/disable reporting for local. - * @param remote_enable Enable/disable reporting for remote. - * - * @return Zero on success or (negative) error code on failure. - * @retval -ENOBUFS HCI command buffer is not available. - */ -int bt_conn_le_set_tx_power_report_enable(struct bt_conn *conn, - bool local_enable, - bool remote_enable); - /** @brief Update the connection parameters. * * If the local device is in the peripheral role then updating the connection @@ -1123,22 +1052,6 @@ struct bt_conn_cb { const struct bt_df_conn_iq_samples_report *iq_report); #endif /* CONFIG_BT_DF_CONNECTION_CTE_RX */ -#if defined(CONFIG_BT_TRANSMIT_POWER_CONTROL) - /** @brief LE Read Remote Transmit Power Level procedure has completed or LE - * Transmit Power Reporting event. - * - * This callback notifies the application that either the remote transmit power level - * has been read from the peer or transmit power level has changed for the local or - * remote controller when transmit power reporting is enabled for the respective side - * using @ref bt_conn_le_set_tx_power_report_enable. - * - * @param conn Connection object. - * @param report Transmit power report. - */ - void (*tx_power_report)(struct bt_conn *conn, - const struct bt_conn_le_tx_power_report *report); -#endif /* CONFIG_BT_TRANSMIT_POWER_CONTROL */ - struct bt_conn_cb *_next; }; diff --git a/include/zephyr/bluetooth/hci_types.h b/include/zephyr/bluetooth/hci_types.h index f1cb92f372c..4d637bbe4e2 100644 --- a/include/zephyr/bluetooth/hci_types.h +++ b/include/zephyr/bluetooth/hci_types.h @@ -571,35 +571,6 @@ struct bt_hci_rp_read_tx_power_level { int8_t tx_power_level; } __packed; -#define BT_HCI_LE_TX_POWER_PHY_1M 0x01 -#define BT_HCI_LE_TX_POWER_PHY_2M 0x02 -#define BT_HCI_LE_TX_POWER_PHY_CODED_S8 0x03 -#define BT_HCI_LE_TX_POWER_PHY_CODED_S2 0x04 -#define BT_HCI_OP_LE_ENH_READ_TX_POWER_LEVEL BT_OP(BT_OGF_LE, 0x0076) -struct bt_hci_cp_le_read_tx_power_level { - uint16_t handle; - uint8_t phy; -} __packed; - -struct bt_hci_rp_le_read_tx_power_level { - uint8_t status; - uint16_t handle; - uint8_t phy; - int8_t current_tx_power_level; - int8_t max_tx_power_level; -} __packed; - -#define BT_HCI_OP_LE_READ_REMOTE_TX_POWER_LEVEL BT_OP(BT_OGF_LE, 0x0077) - -#define BT_HCI_LE_TX_POWER_REPORT_DISABLE 0x00 -#define BT_HCI_LE_TX_POWER_REPORT_ENABLE 0x01 -#define BT_HCI_OP_LE_SET_TX_POWER_REPORT_ENABLE BT_OP(BT_OGF_LE, 0x007A) -struct bt_hci_cp_le_set_tx_power_report_enable { - uint16_t handle; - uint8_t local_enable; - uint8_t remote_enable; -} __packed; - #define BT_HCI_CTL_TO_HOST_FLOW_DISABLE 0x00 #define BT_HCI_CTL_TO_HOST_FLOW_ENABLE 0x01 #define BT_HCI_OP_SET_CTL_TO_HOST_FLOW BT_OP(BT_OGF_BASEBAND, 0x0031) @@ -2934,26 +2905,6 @@ struct bt_hci_evt_le_req_peer_sca_complete { uint8_t sca; } __packed; -/** Reason for Transmit power reporting. - */ -/* Local Transmit power changed. */ -#define BT_HCI_LE_TX_POWER_REPORT_REASON_LOCAL_CHANGED 0x00 -/* Remote Transmit power changed. */ -#define BT_HCI_LE_TX_POWER_REPORT_REASON_REMOTE_CHANGED 0x01 -/* HCI_LE_Read_Remote_Transmit_Power_Level command completed. */ -#define BT_HCI_LE_TX_POWER_REPORT_REASON_READ_REMOTE_COMPLETED 0x02 - -#define BT_HCI_EVT_LE_TRANSMIT_POWER_REPORT 0x21 -struct bt_hci_evt_le_transmit_power_report { - uint8_t status; - uint16_t handle; - uint8_t reason; - uint8_t phy; - int8_t tx_power_level; - uint8_t tx_power_level_flag; - int8_t delta; -} __packed; - #define BT_HCI_EVT_LE_BIGINFO_ADV_REPORT 0x22 struct bt_hci_evt_le_biginfo_adv_report { uint16_t sync_handle; diff --git a/subsys/bluetooth/Kconfig b/subsys/bluetooth/Kconfig index 912846e4cda..e02901cd906 100644 --- a/subsys/bluetooth/Kconfig +++ b/subsys/bluetooth/Kconfig @@ -175,14 +175,6 @@ config BT_SCA_UPDATE depends on !BT_CTLR || BT_CTLR_SCA_UPDATE_SUPPORT help Enable support for Bluetooth 5.1 Sleep Clock Accuracy Update Procedure - -config BT_TRANSMIT_POWER_CONTROL - bool "LE Power Control" - depends on !BT_CTLR || BT_CTLR_LE_POWER_CONTROL_SUPPORT - help - Enable support for LE Power Control Request feature that is defined in the - Bluetooth Core specification, Version 5.4 | Vol 6, Part B, Section 4.6.31. - endif # BT_CONN rsource "Kconfig.iso" diff --git a/subsys/bluetooth/host/conn.c b/subsys/bluetooth/host/conn.c index 06a3e7553a2..1fd2f5fbc49 100644 --- a/subsys/bluetooth/host/conn.c +++ b/subsys/bluetooth/host/conn.c @@ -2619,116 +2619,16 @@ static int bt_conn_get_tx_power_level(struct bt_conn *conn, uint8_t type, return 0; } -#if defined(CONFIG_BT_TRANSMIT_POWER_CONTROL) -void notify_tx_power_report(struct bt_conn *conn, - struct bt_conn_le_tx_power_report report) -{ - for (struct bt_conn_cb *cb = callback_list; cb; cb = cb->_next) { - if (cb->tx_power_report) { - cb->tx_power_report(conn, &report); - } - } - - STRUCT_SECTION_FOREACH(bt_conn_cb, cb) - { - if (cb->tx_power_report) { - cb->tx_power_report(conn, &report); - } - } -} - -int bt_conn_le_enhanced_get_tx_power_level(struct bt_conn *conn, - struct bt_conn_le_tx_power *tx_power) -{ - int err; - struct bt_hci_rp_le_read_tx_power_level *rp; - struct net_buf *rsp; - struct bt_hci_cp_le_read_tx_power_level *cp; - struct net_buf *buf; - - if (!tx_power->phy) { - return -EINVAL; - } - - buf = bt_hci_cmd_create(BT_HCI_OP_LE_ENH_READ_TX_POWER_LEVEL, sizeof(*cp)); - if (!buf) { - return -ENOBUFS; - } - - cp = net_buf_add(buf, sizeof(*cp)); - cp->handle = sys_cpu_to_le16(conn->handle); - cp->phy = tx_power->phy; - - err = bt_hci_cmd_send_sync(BT_HCI_OP_LE_ENH_READ_TX_POWER_LEVEL, buf, &rsp); - if (err) { - return err; - } - - rp = (void *) rsp->data; - tx_power->phy = rp->phy; - tx_power->current_level = rp->current_tx_power_level; - tx_power->max_level = rp->max_tx_power_level; - net_buf_unref(rsp); - - return 0; -} - -int bt_conn_le_get_remote_tx_power_level(struct bt_conn *conn, - enum bt_conn_le_tx_power_phy phy) -{ - struct bt_hci_cp_le_read_tx_power_level *cp; - struct net_buf *buf; - - if (!phy) { - return -EINVAL; - } - - buf = bt_hci_cmd_create(BT_HCI_OP_LE_READ_REMOTE_TX_POWER_LEVEL, sizeof(*cp)); - if (!buf) { - return -ENOBUFS; - } - - cp = net_buf_add(buf, sizeof(*cp)); - cp->handle = sys_cpu_to_le16(conn->handle); - cp->phy = phy; - - return bt_hci_cmd_send_sync(BT_HCI_OP_LE_READ_REMOTE_TX_POWER_LEVEL, buf, NULL); -} - -int bt_conn_le_set_tx_power_report_enable(struct bt_conn *conn, - bool local_enable, - bool remote_enable) -{ - struct bt_hci_cp_le_set_tx_power_report_enable *cp; - struct net_buf *buf; - - buf = bt_hci_cmd_create(BT_HCI_OP_LE_SET_TX_POWER_REPORT_ENABLE, sizeof(*cp)); - if (!buf) { - return -ENOBUFS; - } - - cp = net_buf_add(buf, sizeof(*cp)); - cp->handle = sys_cpu_to_le16(conn->handle); - cp->local_enable = local_enable ? BT_HCI_LE_TX_POWER_REPORT_ENABLE : - BT_HCI_LE_TX_POWER_REPORT_DISABLE; - cp->remote_enable = remote_enable ? BT_HCI_LE_TX_POWER_REPORT_ENABLE : - BT_HCI_LE_TX_POWER_REPORT_DISABLE; - - return bt_hci_cmd_send_sync(BT_HCI_OP_LE_SET_TX_POWER_REPORT_ENABLE, buf, NULL); -} -#endif /* CONFIG_BT_TRANSMIT_POWER_CONTROL */ - int bt_conn_le_get_tx_power_level(struct bt_conn *conn, struct bt_conn_le_tx_power *tx_power_level) { int err; if (tx_power_level->phy != 0) { - if (IS_ENABLED(CONFIG_BT_TRANSMIT_POWER_CONTROL)) { - return bt_conn_le_enhanced_get_tx_power_level(conn, tx_power_level); - } else { - return -ENOTSUP; - } + /* Extend the implementation when LE Enhanced Read Transmit + * Power Level HCI command is available for use. + */ + return -ENOTSUP; } err = bt_conn_get_tx_power_level(conn, BT_TX_POWER_LEVEL_CURRENT, diff --git a/subsys/bluetooth/host/conn_internal.h b/subsys/bluetooth/host/conn_internal.h index a13adff704a..7741e259a61 100644 --- a/subsys/bluetooth/host/conn_internal.h +++ b/subsys/bluetooth/host/conn_internal.h @@ -364,9 +364,6 @@ void notify_le_phy_updated(struct bt_conn *conn); bool le_param_req(struct bt_conn *conn, struct bt_le_conn_param *param); -void notify_tx_power_report(struct bt_conn *conn, - struct bt_conn_le_tx_power_report report); - #if defined(CONFIG_BT_SMP) /* If role specific LTK is present */ bool bt_conn_ltk_present(const struct bt_conn *conn); diff --git a/subsys/bluetooth/host/hci_core.c b/subsys/bluetooth/host/hci_core.c index b37cd45e1ae..de4fb637b49 100644 --- a/subsys/bluetooth/host/hci_core.c +++ b/subsys/bluetooth/host/hci_core.c @@ -2399,33 +2399,6 @@ int bt_hci_register_vnd_evt_cb(bt_hci_vnd_evt_cb_t cb) } #endif /* CONFIG_BT_HCI_VS_EVT_USER */ -#if defined(CONFIG_BT_TRANSMIT_POWER_CONTROL) -void bt_hci_le_transmit_power_report(struct net_buf *buf) -{ - struct bt_hci_evt_le_transmit_power_report *evt; - struct bt_conn_le_tx_power_report report; - struct bt_conn *conn; - - evt = net_buf_pull_mem(buf, sizeof(*evt)); - conn = bt_conn_lookup_handle(sys_le16_to_cpu(evt->handle), BT_CONN_TYPE_LE); - if (!conn) { - LOG_ERR("Unknown conn handle 0x%04X for transmit power report", - sys_le16_to_cpu(evt->handle)); - return; - } - - report.reason = evt->reason; - report.phy = evt->phy; - report.tx_power_level = evt->tx_power_level; - report.tx_power_level_flag = evt->tx_power_level_flag; - report.delta = evt->delta; - - notify_tx_power_report(conn, report); - - bt_conn_unref(conn); -} -#endif /* CONFIG_BT_TRANSMIT_POWER_CONTROL */ - static const struct event_handler vs_events[] = { #if defined(CONFIG_BT_DF_VS_CL_IQ_REPORT_16_BITS_IQ_SAMPLES) EVENT_HANDLER(BT_HCI_EVT_VS_LE_CONNECTIONLESS_IQ_REPORT, @@ -2571,10 +2544,6 @@ static const struct event_handler meta_events[] = { EVENT_HANDLER(BT_HCI_EVT_LE_CTE_REQUEST_FAILED, bt_hci_le_df_cte_req_failed, sizeof(struct bt_hci_evt_le_cte_req_failed)), #endif /* CONFIG_BT_DF_CONNECTION_CTE_REQ */ -#if defined(CONFIG_BT_TRANSMIT_POWER_CONTROL) - EVENT_HANDLER(BT_HCI_EVT_LE_TRANSMIT_POWER_REPORT, bt_hci_le_transmit_power_report, - sizeof(struct bt_hci_evt_le_transmit_power_report)), -#endif /* CONFIG_BT_TRANSMIT_POWER_CONTROL */ #if defined(CONFIG_BT_PER_ADV_SYNC_RSP) EVENT_HANDLER(BT_HCI_EVT_LE_PER_ADVERTISING_REPORT_V2, bt_hci_le_per_adv_report_v2, sizeof(struct bt_hci_evt_le_per_advertising_report_v2)), @@ -3120,9 +3089,6 @@ static int le_set_event_mask(void) BT_FEAT_LE_PHY_CODED(bt_dev.le.features))) { mask |= BT_EVT_MASK_LE_PHY_UPDATE_COMPLETE; } - if (IS_ENABLED(CONFIG_BT_TRANSMIT_POWER_CONTROL)) { - mask |= BT_EVT_MASK_LE_TRANSMIT_POWER_REPORTING; - } } if (IS_ENABLED(CONFIG_BT_SMP) && From 20406b0c111332c910bddc8a22de7771842eecc6 Mon Sep 17 00:00:00 2001 From: Robert Lubos Date: Tue, 6 Feb 2024 11:07:38 +0100 Subject: [PATCH 3707/3723] Revert "[nrf fromtree] Bluetooth: Controller: Add Kconfig for LE Power Control Request Feature" This reverts commit 6af59667d730b009cec654671b0a1f3eee0f06fd. Signed-off-by: Robert Lubos --- subsys/bluetooth/controller/Kconfig | 11 ----------- 1 file changed, 11 deletions(-) diff --git a/subsys/bluetooth/controller/Kconfig b/subsys/bluetooth/controller/Kconfig index 077c8e4f6f5..07636c780d0 100644 --- a/subsys/bluetooth/controller/Kconfig +++ b/subsys/bluetooth/controller/Kconfig @@ -101,9 +101,6 @@ config BT_CTLR_READ_ISO_LINK_QUALITY_SUPPORT BT_CTLR_PERIPHERAL_ISO_SUPPORT bool -config BT_CTLR_LE_POWER_CONTROL_SUPPORT - bool - config BT_CTLR bool "Bluetooth Controller" help @@ -488,14 +485,6 @@ config BT_CTLR_CONN_RSSI help Enable connection RSSI measurement. -config BT_CTLR_LE_POWER_CONTROL - bool "LE Power Control Request Feature" - depends on BT_CTLR_LE_POWER_CONTROL_SUPPORT - default y if BT_TRANSMIT_POWER_CONTROL - help - Enable support for LE Power Control Request feature that is defined in the - Bluetooth Core specification, Version 5.4 | Vol 6, Part B, Section 4.6.31. - endif # BT_CONN config BT_CTLR_FILTER_ACCEPT_LIST From bc98d05adb7833bd0292517663ced93fd1a8d7c4 Mon Sep 17 00:00:00 2001 From: Robert Lubos Date: Tue, 6 Feb 2024 11:07:38 +0100 Subject: [PATCH 3708/3723] Revert "[nrf fromlist] cmake: Add support for sysbuild-set signing script" This reverts commit f8e27684ca11e884c1e8ae6e1903c815277137a6. Signed-off-by: Robert Lubos --- CMakeLists.txt | 9 +-------- 1 file changed, 1 insertion(+), 8 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 97bcd98d0d7..164d82fde0e 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -1806,15 +1806,8 @@ endif() # Generate and use MCUboot related artifacts as needed. if(CONFIG_BOOTLOADER_MCUBOOT) get_target_property(signing_script zephyr_property_target SIGNING_SCRIPT) - if(NOT signing_script) - zephyr_get(signing_script VAR SIGNING_SCRIPT SYSBUILD) - - if(signing_script) - set_target_properties(zephyr_property_target PROPERTIES SIGNING_SCRIPT ${signing_script}) - else() - set_target_properties(zephyr_property_target PROPERTIES SIGNING_SCRIPT ${CMAKE_CURRENT_LIST_DIR}/cmake/mcuboot.cmake) - endif() + set_target_properties(zephyr_property_target PROPERTIES SIGNING_SCRIPT ${CMAKE_CURRENT_LIST_DIR}/cmake/mcuboot.cmake) endif() endif() From 530b6060cc9cb10308a17549938cd640d90f8dd0 Mon Sep 17 00:00:00 2001 From: Robert Lubos Date: Tue, 6 Feb 2024 11:07:38 +0100 Subject: [PATCH 3709/3723] Revert "[nrf noup] modules: mbedtls: Disable configurations in Kconfig.tls-generic" This reverts commit ca0298cc20b632388a8cf75e166dde4a09987847. Signed-off-by: Robert Lubos --- modules/mbedtls/Kconfig.tls-generic | 31 -------------------- modules/mbedtls/configs/config-tls-generic.h | 4 --- modules/mbedtls/zephyr_init.c | 2 +- 3 files changed, 1 insertion(+), 36 deletions(-) diff --git a/modules/mbedtls/Kconfig.tls-generic b/modules/mbedtls/Kconfig.tls-generic index d629c1b1d2a..3c0e17c0fe3 100644 --- a/modules/mbedtls/Kconfig.tls-generic +++ b/modules/mbedtls/Kconfig.tls-generic @@ -9,8 +9,6 @@ menu "TLS configuration" menu "Supported TLS version" -if !(NRF_SECURITY || NORDIC_SECURITY_BACKEND) - config MBEDTLS_TLS_VERSION_1_0 bool "Support for TLS 1.0" select MBEDTLS_CIPHER @@ -35,8 +33,6 @@ config MBEDTLS_DTLS bool "Support for DTLS" depends on MBEDTLS_TLS_VERSION_1_1 || MBEDTLS_TLS_VERSION_1_2 -endif - config MBEDTLS_SSL_EXPORT_KEYS bool "Support for exporting SSL key block and master secret" depends on MBEDTLS_TLS_VERSION_1_0 || MBEDTLS_TLS_VERSION_1_1 || MBEDTLS_TLS_VERSION_1_2 @@ -51,8 +47,6 @@ menu "Ciphersuite configuration" comment "Supported key exchange modes" -if !(NRF_SECURITY || NORDIC_SECURITY_BACKEND) - config MBEDTLS_KEY_EXCHANGE_ALL_ENABLED bool "All available ciphersuite modes" select MBEDTLS_KEY_EXCHANGE_PSK_ENABLED @@ -87,8 +81,6 @@ config MBEDTLS_KEY_EXCHANGE_SOME_PSK_ENABLED MBEDTLS_KEY_EXCHANGE_ECDHE_PSK_ENABLED || \ MBEDTLS_KEY_EXCHANGE_RSA_PSK_ENABLED -endif - config MBEDTLS_PSK_MAX_LEN int "Max size of TLS pre-shared keys" default 32 @@ -96,8 +88,6 @@ config MBEDTLS_PSK_MAX_LEN help Max size of TLS pre-shared keys, in bytes. -if !(NRF_SECURITY || NORDIC_SECURITY_BACKEND) - config MBEDTLS_KEY_EXCHANGE_RSA_ENABLED bool "RSA-only based ciphersuite modes" default y if !NET_L2_OPENTHREAD @@ -212,7 +202,6 @@ config MBEDTLS_ECP_NIST_OPTIM bool "NSIT curves optimization" endif -endif # !(NRF_SECURITY || NORDIC_SECURITY_BACKEND) comment "Supported hash" @@ -237,8 +226,6 @@ config MBEDTLS_HASH_SHA512_ENABLED comment "Supported cipher modes" -if !(NRF_SECURITY || NORDIC_SECURITY_BACKEND) - config MBEDTLS_CIPHER_ALL_ENABLED bool "All available ciphers" select MBEDTLS_CIPHER_AES_ENABLED @@ -312,12 +299,8 @@ config MBEDTLS_CHACHAPOLY_AEAD_ENABLED bool "ChaCha20-Poly1305 AEAD algorithm" depends on MBEDTLS_CIPHER_CHACHA20_ENABLED || MBEDTLS_MAC_POLY1305_ENABLED -endif - comment "Supported message authentication methods" -if !(NRF_SECURITY || NORDIC_SECURITY_BACKEND) - config MBEDTLS_MAC_ALL_ENABLED bool "All available MAC methods" select MBEDTLS_MAC_MD4_ENABLED @@ -366,14 +349,10 @@ config MBEDTLS_MAC_CMAC_ENABLED bool "CMAC (Cipher-based Message Authentication Code) mode for block ciphers." depends on MBEDTLS_CIPHER_AES_ENABLED || MBEDTLS_CIPHER_DES_ENABLED -endif - endmenu comment "Random number generators" -if !(NRF_SECURITY || NORDIC_SECURITY_BACKEND) - config MBEDTLS_CTR_DRBG_ENABLED bool "CTR_DRBG AES-256-based random generator" depends on MBEDTLS_CIPHER_AES_ENABLED @@ -383,20 +362,14 @@ config MBEDTLS_HMAC_DRBG_ENABLED bool "HMAC_DRBG random generator" select MBEDTLS_MD -endif - comment "Other configurations" config MBEDTLS_CIPHER bool "generic cipher layer." -if !(NRF_SECURITY || NORDIC_SECURITY_BACKEND) - config MBEDTLS_MD bool "generic message digest layer." -endif - config MBEDTLS_GENPRIME_ENABLED bool "prime-number generation code." @@ -414,15 +387,11 @@ config MBEDTLS_HAVE_ASM of asymmetric cryptography, however this might have an impact on the code size. -if !(NRF_SECURITY || NORDIC_SECURITY_BACKEND) - config MBEDTLS_ENTROPY_ENABLED bool "MbedTLS generic entropy pool" depends on MBEDTLS_MAC_SHA256_ENABLED || MBEDTLS_MAC_SHA384_ENABLED || MBEDTLS_MAC_SHA512_ENABLED default y if MBEDTLS_ZEPHYR_ENTROPY -endif - config MBEDTLS_OPENTHREAD_OPTIMIZATIONS_ENABLED bool "MbedTLS optimizations for OpenThread" depends on NET_L2_OPENTHREAD diff --git a/modules/mbedtls/configs/config-tls-generic.h b/modules/mbedtls/configs/config-tls-generic.h index ab4a9610732..7cf85731c85 100644 --- a/modules/mbedtls/configs/config-tls-generic.h +++ b/modules/mbedtls/configs/config-tls-generic.h @@ -501,8 +501,4 @@ #include "mbedtls/check_config.h" #endif -#if defined(CONFIG_NRF_CC3XX_PLATFORM) -#define MBEDTLS_PLATFORM_ZEROIZE_ALT -#endif - #endif /* MBEDTLS_CONFIG_H */ diff --git a/modules/mbedtls/zephyr_init.c b/modules/mbedtls/zephyr_init.c index 3329c3b9c8d..d882b0aedb8 100644 --- a/modules/mbedtls/zephyr_init.c +++ b/modules/mbedtls/zephyr_init.c @@ -45,7 +45,7 @@ static void init_heap(void) #define init_heap(...) #endif /* CONFIG_MBEDTLS_ENABLE_HEAP && MBEDTLS_MEMORY_BUFFER_ALLOC_C */ -#if defined(CONFIG_MBEDTLS_ZEPHYR_ENTROPY) && !defined(CONFIG_NRF_CC3XX_PLATFORM) +#if defined(CONFIG_MBEDTLS_ZEPHYR_ENTROPY) static const struct device *const entropy_dev = DEVICE_DT_GET_OR_NULL(DT_CHOSEN(zephyr_entropy)); From 01b2f46c10ec9c4c30f9ffb38fc17dfb9dcf2169 Mon Sep 17 00:00:00 2001 From: Robert Lubos Date: Tue, 6 Feb 2024 11:07:39 +0100 Subject: [PATCH 3710/3723] Revert "[nrf noup] ci: clang: parallel execution" This reverts commit 4d76b6a7403a5d3c14098d4d67e26e284e3c5757. Signed-off-by: Robert Lubos --- .github/workflows/clang.yaml | 21 +++++---------------- 1 file changed, 5 insertions(+), 16 deletions(-) diff --git a/.github/workflows/clang.yaml b/.github/workflows/clang.yaml index 34b4b8595a9..0aa8d5cd690 100644 --- a/.github/workflows/clang.yaml +++ b/.github/workflows/clang.yaml @@ -8,7 +8,8 @@ concurrency: jobs: clang-build: - runs-on: ubuntu-latest + if: github.repository_owner == 'zephyrproject-rtos' + runs-on: zephyr-runner-linux-x64-4xlarge container: image: ghcr.io/zephyrproject-rtos/ci:v0.26.5 options: '--entrypoint /bin/bash' @@ -18,13 +19,11 @@ jobs: fail-fast: false matrix: platform: ["native_posix"] - subset: [1, 2, 3, 4, 5] env: ZEPHYR_SDK_INSTALL_DIR: /opt/toolchains/zephyr-sdk-0.16.3 LLVM_TOOLCHAIN_PATH: /usr/lib/llvm-16 COMMIT_RANGE: ${{ github.event.pull_request.base.sha }}..${{ github.event.pull_request.head.sha }} BASE_REF: ${{ github.base_ref }} - MATRIX_SIZE: 5 outputs: report_needed: ${{ steps.twister.outputs.report_needed }} steps: @@ -87,7 +86,7 @@ jobs: id: cache-ccache uses: zephyrproject-rtos/action-s3-cache@v1.2.0 with: - key: ${{ steps.ccache_cache_timestamp.outputs.repo }}-${{ github.ref_name }}-clang-${{ matrix.subset }}-ccache + key: ${{ steps.ccache_cache_timestamp.outputs.repo }}-${{ github.ref_name }}-clang-${{ matrix.platform }}-ccache path: /github/home/.cache/ccache aws-s3-bucket: ccache.zephyrproject.org aws-access-key-id: ${{ vars.AWS_CCACHE_ACCESS_KEY_ID }} @@ -100,16 +99,6 @@ jobs: test -d github/home/.cache/ccache && rm -rf /github/home/.cache/ccache && mv github/home/.cache/ccache /github/home/.cache/ccache ccache -M 10G -s - - name: Build test plan with Twister - id: twister_test_plan - run: | - export ZEPHYR_BASE=${PWD} - export ZEPHYR_TOOLCHAIN_VARIANT=llvm - - # check if we need to run a full twister or not based on files changed - python3 ./scripts/ci/test_plan.py -p native_posix -c origin/${BASE_REF}.. - - - name: Run Tests with Twister id: twister run: | @@ -123,7 +112,7 @@ jobs: if [ -s testplan.json ]; then echo "report_needed=1" >> $GITHUB_OUTPUT # Full twister but with options based on changes - ./scripts/twister --inline-logs -M -N -v --load-tests testplan.json --retry-failed 2 --subset ${{matrix.subset}}/${MATRIX_SIZE} + ./scripts/twister --force-color --inline-logs -M -N -v --load-tests testplan.json --retry-failed 2 else # if nothing is run, skip reporting step echo "report_needed=0" >> $GITHUB_OUTPUT @@ -138,7 +127,7 @@ jobs: if: always() && steps.twister.outputs.report_needed != 0 uses: actions/upload-artifact@v3 with: - name: Unit Test Results (Subset ${{ matrix.subset }}) + name: Unit Test Results (Subset ${{ matrix.platform }}) path: twister-out/twister.xml clang-build-results: From 9202bbdaf793003b4a398a4dc28f33d073ffda41 Mon Sep 17 00:00:00 2001 From: Robert Lubos Date: Tue, 6 Feb 2024 11:07:39 +0100 Subject: [PATCH 3711/3723] Revert "[nrf noup] Bluetooth: Mesh: zero randomization for friend's adv" This reverts commit 468009977970899f2d250231847e160671f74d18. Signed-off-by: Robert Lubos --- subsys/bluetooth/mesh/Kconfig | 2 +- subsys/bluetooth/mesh/adv_ext.c | 32 -------------------------------- 2 files changed, 1 insertion(+), 33 deletions(-) diff --git a/subsys/bluetooth/mesh/Kconfig b/subsys/bluetooth/mesh/Kconfig index 04366828bbe..de409e9c53c 100644 --- a/subsys/bluetooth/mesh/Kconfig +++ b/subsys/bluetooth/mesh/Kconfig @@ -958,7 +958,7 @@ config BT_MESH_LPN_INIT_POLL_TIMEOUT config BT_MESH_LPN_SCAN_LATENCY int "Latency for enabling scanning" range 0 50 - default 2 + default 15 help Latency in milliseconds that it takes to enable scanning. This is in practice how much time in advance before the Receive Window diff --git a/subsys/bluetooth/mesh/adv_ext.c b/subsys/bluetooth/mesh/adv_ext.c index 0c11fc0053a..0bfc2041c7d 100644 --- a/subsys/bluetooth/mesh/adv_ext.c +++ b/subsys/bluetooth/mesh/adv_ext.c @@ -13,9 +13,6 @@ #include #include #include -#if defined(CONFIG_BT_LL_SOFTDEVICE) -#include -#endif #include "common/bt_str.h" @@ -139,28 +136,6 @@ static inline struct bt_mesh_ext_adv *gatt_adv_get(void) } } -static int set_adv_randomness(uint8_t handle, int rand_us) -{ -#if defined(CONFIG_BT_LL_SOFTDEVICE) - struct net_buf *buf; - sdc_hci_cmd_vs_set_adv_randomness_t *cmd_params; - - buf = bt_hci_cmd_create(SDC_HCI_OPCODE_CMD_VS_SET_ADV_RANDOMNESS, sizeof(*cmd_params)); - if (!buf) { - LOG_ERR("Could not allocate command buffer"); - return -ENOMEM; - } - - cmd_params = net_buf_add(buf, sizeof(*cmd_params)); - cmd_params->adv_handle = handle; - cmd_params->rand_us = rand_us; - - return bt_hci_cmd_send_sync(SDC_HCI_OPCODE_CMD_VS_SET_ADV_RANDOMNESS, buf, NULL); -#else - return 0; -#endif /* defined(CONFIG_BT_LL_SOFTDEVICE) */ -} - static int adv_start(struct bt_mesh_ext_adv *adv, const struct bt_le_adv_param *param, struct bt_le_ext_adv_start_param *start, @@ -526,13 +501,6 @@ int bt_mesh_adv_enable(void) if (err) { return err; } - - if (IS_ENABLED(CONFIG_BT_LL_SOFTDEVICE) && adv->tag & BT_MESH_FRIEND_ADV) { - err = set_adv_randomness(adv->instance->handle, 0); - if (err) { - LOG_ERR("Failed to set zero randomness: %d", err); - } - } } return 0; From 6563ebcb7f57678454d0276808ac243e2f9fb96d Mon Sep 17 00:00:00 2001 From: Aleksandr Khromykh Date: Tue, 7 Feb 2023 12:39:12 +0100 Subject: [PATCH 3712/3723] [nrf noup] Bluetooth: Mesh: zero randomization for friend's adv Friend's replies on LPN's polls do not assume randomization in advertiser. Zero randomization will help to optimize time when LPN keeps receiving window open and save power. Signed-off-by: Aleksandr Khromykh (cherry picked from commit 88d5ef9efab511212a171fe67faf82468bcd0531) (cherry picked from commit a5ab323470201713ded500729f8cd34fc13c96f0) (cherry picked from commit 468009977970899f2d250231847e160671f74d18) Signed-off-by: Robert Lubos --- subsys/bluetooth/mesh/Kconfig | 2 +- subsys/bluetooth/mesh/adv_ext.c | 32 ++++++++++++++++++++++++++++++++ 2 files changed, 33 insertions(+), 1 deletion(-) diff --git a/subsys/bluetooth/mesh/Kconfig b/subsys/bluetooth/mesh/Kconfig index 25fb2e870d4..e0b4761232c 100644 --- a/subsys/bluetooth/mesh/Kconfig +++ b/subsys/bluetooth/mesh/Kconfig @@ -1549,7 +1549,7 @@ config BT_MESH_LPN_INIT_POLL_TIMEOUT config BT_MESH_LPN_SCAN_LATENCY int "Latency for enabling scanning" range 0 50 - default 15 + default 2 help Latency in milliseconds that it takes to enable scanning. This is in practice how much time in advance before the Receive Window diff --git a/subsys/bluetooth/mesh/adv_ext.c b/subsys/bluetooth/mesh/adv_ext.c index 592081f2773..c195671ebcb 100644 --- a/subsys/bluetooth/mesh/adv_ext.c +++ b/subsys/bluetooth/mesh/adv_ext.c @@ -13,6 +13,9 @@ #include #include #include +#if defined(CONFIG_BT_LL_SOFTDEVICE) +#include +#endif #include "common/bt_str.h" @@ -135,6 +138,28 @@ static inline struct bt_mesh_ext_adv *gatt_adv_get(void) } } +static int set_adv_randomness(uint8_t handle, int rand_us) +{ +#if defined(CONFIG_BT_LL_SOFTDEVICE) + struct net_buf *buf; + sdc_hci_cmd_vs_set_adv_randomness_t *cmd_params; + + buf = bt_hci_cmd_create(SDC_HCI_OPCODE_CMD_VS_SET_ADV_RANDOMNESS, sizeof(*cmd_params)); + if (!buf) { + LOG_ERR("Could not allocate command buffer"); + return -ENOMEM; + } + + cmd_params = net_buf_add(buf, sizeof(*cmd_params)); + cmd_params->adv_handle = handle; + cmd_params->rand_us = rand_us; + + return bt_hci_cmd_send_sync(SDC_HCI_OPCODE_CMD_VS_SET_ADV_RANDOMNESS, buf, NULL); +#else + return 0; +#endif /* defined(CONFIG_BT_LL_SOFTDEVICE) */ +} + static int adv_start(struct bt_mesh_ext_adv *ext_adv, const struct bt_le_adv_param *param, struct bt_le_ext_adv_start_param *start, @@ -485,6 +510,13 @@ int bt_mesh_adv_enable(void) if (err) { return err; } + + if (IS_ENABLED(CONFIG_BT_LL_SOFTDEVICE) && adv->tag & BT_MESH_FRIEND_ADV) { + err = set_adv_randomness(adv->instance->handle, 0); + if (err) { + LOG_ERR("Failed to set zero randomness: %d", err); + } + } } return 0; From fbf12ee3bf8cd8a2367ca3bd63eac5a36051093a Mon Sep 17 00:00:00 2001 From: Maciej Perkowski Date: Fri, 28 Jan 2022 12:02:58 +0100 Subject: [PATCH 3713/3723] [nrf noup] ci: clang: parallel execution MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Bring back parallel execution to the clang action. In the upstream they went to use a single dedicated powerful agent to run this. We need to keep this as we have to base on agents available in github's cloud. zephyr_runner is upstream's proprietary agent inaccessible outside of upstream's CI. Use ubuntu-latest instead. Signed-off-by: Maciej Perkowski Signed-off-by: Gerard Marull-Paretas Signed-off-by: Dominik Ermel Signed-off-by: Torsten Rasmussen Signed-off-by: Tomasz Moń Signed-off-by: Stephanos Ioannidis Signed-off-by: Vinayak Kariappa Chettimada (cherry picked from commit 5b3d0ff9ab29e66d52fd7c3ffbd50e9e97b1d7d5) (cherry picked from commit 5e2f4ecc0bd4171ff60bfbc9f60271d0a30142cc) Signed-off-by: Dominik Ermel (cherry picked from commit 0948638f2e3a857bdfcd4bad0e1b5bd6d4760fb6) (cherry picked from commit 4d76b6a7403a5d3c14098d4d67e26e284e3c5757) Signed-off-by: Robert Lubos --- .github/workflows/clang.yaml | 21 ++++++++++++++++----- 1 file changed, 16 insertions(+), 5 deletions(-) diff --git a/.github/workflows/clang.yaml b/.github/workflows/clang.yaml index 17fbc1c72bd..b28d3c387e4 100644 --- a/.github/workflows/clang.yaml +++ b/.github/workflows/clang.yaml @@ -8,8 +8,7 @@ concurrency: jobs: clang-build: - if: github.repository_owner == 'zephyrproject-rtos' - runs-on: zephyr-runner-linux-x64-4xlarge + runs-on: ubuntu-latest container: image: ghcr.io/zephyrproject-rtos/ci:v0.26.7 options: '--entrypoint /bin/bash' @@ -19,10 +18,12 @@ jobs: fail-fast: false matrix: platform: ["native_sim"] + subset: [1, 2, 3, 4, 5] env: LLVM_TOOLCHAIN_PATH: /usr/lib/llvm-16 COMMIT_RANGE: ${{ github.event.pull_request.base.sha }}..${{ github.event.pull_request.head.sha }} BASE_REF: ${{ github.base_ref }} + MATRIX_SIZE: 5 outputs: report_needed: ${{ steps.twister.outputs.report_needed }} steps: @@ -87,7 +88,7 @@ jobs: id: cache-ccache uses: zephyrproject-rtos/action-s3-cache@v1.2.0 with: - key: ${{ steps.ccache_cache_timestamp.outputs.repo }}-${{ github.ref_name }}-clang-${{ matrix.platform }}-ccache + key: ${{ steps.ccache_cache_timestamp.outputs.repo }}-${{ github.ref_name }}-clang-${{ matrix.subset }}-ccache path: /github/home/.cache/ccache aws-s3-bucket: ccache.zephyrproject.org aws-access-key-id: ${{ vars.AWS_CCACHE_ACCESS_KEY_ID }} @@ -100,6 +101,16 @@ jobs: test -d github/home/.cache/ccache && rm -rf /github/home/.cache/ccache && mv github/home/.cache/ccache /github/home/.cache/ccache ccache -M 10G -s + - name: Build test plan with Twister + id: twister_test_plan + run: | + export ZEPHYR_BASE=${PWD} + export ZEPHYR_TOOLCHAIN_VARIANT=llvm + + # check if we need to run a full twister or not based on files changed + python3 ./scripts/ci/test_plan.py -p native_posix -c origin/${BASE_REF}.. + + - name: Run Tests with Twister id: twister run: | @@ -113,7 +124,7 @@ jobs: if [ -s testplan.json ]; then echo "report_needed=1" >> $GITHUB_OUTPUT # Full twister but with options based on changes - ./scripts/twister --force-color --inline-logs -M -N -v --load-tests testplan.json --retry-failed 2 + ./scripts/twister --inline-logs -M -N -v --load-tests testplan.json --retry-failed 2 --subset ${{matrix.subset}}/${MATRIX_SIZE} else # if nothing is run, skip reporting step echo "report_needed=0" >> $GITHUB_OUTPUT @@ -128,7 +139,7 @@ jobs: if: always() && steps.twister.outputs.report_needed != 0 uses: actions/upload-artifact@v4 with: - name: Unit Test Results (Subset ${{ matrix.platform }}) + name: Unit Test Results (Subset ${{ matrix.subset }}) path: twister-out/twister.xml clang-build-results: From d35f9096c4893159b911d93cf1376f6a8dd2ba30 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Frank=20Audun=20Kvamtr=C3=B8?= Date: Mon, 31 Jan 2022 03:48:11 +0100 Subject: [PATCH 3714/3723] [nrf noup] modules: mbedtls: Disable configurations in Kconfig.tls-generic MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit -This commit prevents legacy mbed TLS configurations from being in conflict with PSA Configurations while using nrf_security -Removing use of unsupported TLS protocols (TLS 1.0, 1.1) -Required configurations are duplicated inside nrf_security Kconfig -Ensured that mbedtls_platform_zeroize is not duplicated when CONFIG_NRF_CC3XX_PLATFORM is set ref: NCSDK-13503 Signed-off-by: Frank Audun Kvamtrø Signed-off-by: Andrzej Głąbek (cherry picked from commit 84ee8c8015d1362b7888aeb7e0991e3f7092b35a) (cherry picked from commit ea5314da140b632aad85d39ea2dad02929ac83a5) Signed-off-by: Dominik Ermel (cherry picked from commit 8022c47f2ee2ca8c998bc44412ef2742535dcb74) [nrf noup] modules: mbedtls: Disable mbedtls_hardware_poll with CC3xx enabled Precompiled CC3xx libraries silently provide mbedtls_hardware_poll function (used internally by the library on initialization), which creates ambiguity with Zephyr-provided implementation. In result, the CC3xx entropy source is broken when CONFIG_MBEDTLS_ZEPHYR_ENTROPY is enabled. Workaround this, by disabling the Zephyr implementation if CC3xx is enabled, and let mbed TLS use the implementation from the CC library instead. Signed-off-by: Robert Lubos (cherry picked from commit e2ad826809bbcdeaa04f1edc2a57f21a0b2151ff) (cherry picked from commit ca0298cc20b632388a8cf75e166dde4a09987847) --- modules/mbedtls/Kconfig.tls-generic | 31 ++++++++++++++++++++ modules/mbedtls/configs/config-tls-generic.h | 4 +++ modules/mbedtls/zephyr_init.c | 2 +- 3 files changed, 36 insertions(+), 1 deletion(-) diff --git a/modules/mbedtls/Kconfig.tls-generic b/modules/mbedtls/Kconfig.tls-generic index 3c0e17c0fe3..d629c1b1d2a 100644 --- a/modules/mbedtls/Kconfig.tls-generic +++ b/modules/mbedtls/Kconfig.tls-generic @@ -9,6 +9,8 @@ menu "TLS configuration" menu "Supported TLS version" +if !(NRF_SECURITY || NORDIC_SECURITY_BACKEND) + config MBEDTLS_TLS_VERSION_1_0 bool "Support for TLS 1.0" select MBEDTLS_CIPHER @@ -33,6 +35,8 @@ config MBEDTLS_DTLS bool "Support for DTLS" depends on MBEDTLS_TLS_VERSION_1_1 || MBEDTLS_TLS_VERSION_1_2 +endif + config MBEDTLS_SSL_EXPORT_KEYS bool "Support for exporting SSL key block and master secret" depends on MBEDTLS_TLS_VERSION_1_0 || MBEDTLS_TLS_VERSION_1_1 || MBEDTLS_TLS_VERSION_1_2 @@ -47,6 +51,8 @@ menu "Ciphersuite configuration" comment "Supported key exchange modes" +if !(NRF_SECURITY || NORDIC_SECURITY_BACKEND) + config MBEDTLS_KEY_EXCHANGE_ALL_ENABLED bool "All available ciphersuite modes" select MBEDTLS_KEY_EXCHANGE_PSK_ENABLED @@ -81,6 +87,8 @@ config MBEDTLS_KEY_EXCHANGE_SOME_PSK_ENABLED MBEDTLS_KEY_EXCHANGE_ECDHE_PSK_ENABLED || \ MBEDTLS_KEY_EXCHANGE_RSA_PSK_ENABLED +endif + config MBEDTLS_PSK_MAX_LEN int "Max size of TLS pre-shared keys" default 32 @@ -88,6 +96,8 @@ config MBEDTLS_PSK_MAX_LEN help Max size of TLS pre-shared keys, in bytes. +if !(NRF_SECURITY || NORDIC_SECURITY_BACKEND) + config MBEDTLS_KEY_EXCHANGE_RSA_ENABLED bool "RSA-only based ciphersuite modes" default y if !NET_L2_OPENTHREAD @@ -202,6 +212,7 @@ config MBEDTLS_ECP_NIST_OPTIM bool "NSIT curves optimization" endif +endif # !(NRF_SECURITY || NORDIC_SECURITY_BACKEND) comment "Supported hash" @@ -226,6 +237,8 @@ config MBEDTLS_HASH_SHA512_ENABLED comment "Supported cipher modes" +if !(NRF_SECURITY || NORDIC_SECURITY_BACKEND) + config MBEDTLS_CIPHER_ALL_ENABLED bool "All available ciphers" select MBEDTLS_CIPHER_AES_ENABLED @@ -299,8 +312,12 @@ config MBEDTLS_CHACHAPOLY_AEAD_ENABLED bool "ChaCha20-Poly1305 AEAD algorithm" depends on MBEDTLS_CIPHER_CHACHA20_ENABLED || MBEDTLS_MAC_POLY1305_ENABLED +endif + comment "Supported message authentication methods" +if !(NRF_SECURITY || NORDIC_SECURITY_BACKEND) + config MBEDTLS_MAC_ALL_ENABLED bool "All available MAC methods" select MBEDTLS_MAC_MD4_ENABLED @@ -349,10 +366,14 @@ config MBEDTLS_MAC_CMAC_ENABLED bool "CMAC (Cipher-based Message Authentication Code) mode for block ciphers." depends on MBEDTLS_CIPHER_AES_ENABLED || MBEDTLS_CIPHER_DES_ENABLED +endif + endmenu comment "Random number generators" +if !(NRF_SECURITY || NORDIC_SECURITY_BACKEND) + config MBEDTLS_CTR_DRBG_ENABLED bool "CTR_DRBG AES-256-based random generator" depends on MBEDTLS_CIPHER_AES_ENABLED @@ -362,14 +383,20 @@ config MBEDTLS_HMAC_DRBG_ENABLED bool "HMAC_DRBG random generator" select MBEDTLS_MD +endif + comment "Other configurations" config MBEDTLS_CIPHER bool "generic cipher layer." +if !(NRF_SECURITY || NORDIC_SECURITY_BACKEND) + config MBEDTLS_MD bool "generic message digest layer." +endif + config MBEDTLS_GENPRIME_ENABLED bool "prime-number generation code." @@ -387,11 +414,15 @@ config MBEDTLS_HAVE_ASM of asymmetric cryptography, however this might have an impact on the code size. +if !(NRF_SECURITY || NORDIC_SECURITY_BACKEND) + config MBEDTLS_ENTROPY_ENABLED bool "MbedTLS generic entropy pool" depends on MBEDTLS_MAC_SHA256_ENABLED || MBEDTLS_MAC_SHA384_ENABLED || MBEDTLS_MAC_SHA512_ENABLED default y if MBEDTLS_ZEPHYR_ENTROPY +endif + config MBEDTLS_OPENTHREAD_OPTIMIZATIONS_ENABLED bool "MbedTLS optimizations for OpenThread" depends on NET_L2_OPENTHREAD diff --git a/modules/mbedtls/configs/config-tls-generic.h b/modules/mbedtls/configs/config-tls-generic.h index 59d98f65067..ea12a28e84d 100644 --- a/modules/mbedtls/configs/config-tls-generic.h +++ b/modules/mbedtls/configs/config-tls-generic.h @@ -487,4 +487,8 @@ #include CONFIG_MBEDTLS_USER_CONFIG_FILE #endif +#if defined(CONFIG_NRF_CC3XX_PLATFORM) +#define MBEDTLS_PLATFORM_ZEROIZE_ALT +#endif + #endif /* MBEDTLS_CONFIG_H */ diff --git a/modules/mbedtls/zephyr_init.c b/modules/mbedtls/zephyr_init.c index 28a6a40fdc5..49c9ffc8aff 100644 --- a/modules/mbedtls/zephyr_init.c +++ b/modules/mbedtls/zephyr_init.c @@ -47,7 +47,7 @@ static void init_heap(void) #define init_heap(...) #endif /* CONFIG_MBEDTLS_ENABLE_HEAP && MBEDTLS_MEMORY_BUFFER_ALLOC_C */ -#if defined(CONFIG_MBEDTLS_ZEPHYR_ENTROPY) +#if defined(CONFIG_MBEDTLS_ZEPHYR_ENTROPY) && !defined(CONFIG_NRF_CC3XX_PLATFORM) static const struct device *const entropy_dev = DEVICE_DT_GET_OR_NULL(DT_CHOSEN(zephyr_entropy)); From 9aee26e44927fb19afac2599e5a88ea79d06957e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Anders=20Storr=C3=B8?= Date: Wed, 8 Mar 2023 12:17:09 +0100 Subject: [PATCH 3715/3723] [nrf noup] Bluetooth: Mesh: Fix adv randomness bug MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Fixes issue where randomness can be removed for advertising sets that have to handle other adv types than the BT_MESH_FRIEND_ADV tag type. Signed-off-by: Anders Storrø (cherry picked from commit f8f113382356934cb6d1ef4cdad95a843f922085) (cherry picked from commit 996037de254a91a9b2da4a288f48c09e90427501) (cherry picked from commit 62a4cadefae85308a801698f8a164eaecaea2358) Signed-off-by: Dominik Ermel (cherry picked from commit 3afe29330d959ee78d57db509a7380f0e05b6bba) Signed-off-by: Robert Lubos --- subsys/bluetooth/mesh/adv_ext.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/subsys/bluetooth/mesh/adv_ext.c b/subsys/bluetooth/mesh/adv_ext.c index c195671ebcb..1be3ca16c51 100644 --- a/subsys/bluetooth/mesh/adv_ext.c +++ b/subsys/bluetooth/mesh/adv_ext.c @@ -511,7 +511,9 @@ int bt_mesh_adv_enable(void) return err; } - if (IS_ENABLED(CONFIG_BT_LL_SOFTDEVICE) && adv->tag & BT_MESH_FRIEND_ADV) { + if (IS_ENABLED(CONFIG_BT_LL_SOFTDEVICE) && + IS_ENABLED(CONFIG_BT_MESH_ADV_EXT_FRIEND_SEPARATE) && + adv->tag == BT_MESH_FRIEND_ADV) { err = set_adv_randomness(adv->instance->handle, 0); if (err) { LOG_ERR("Failed to set zero randomness: %d", err); From 19605ba6f9a5acaa28a4b8a38ce7b3289e21d71e Mon Sep 17 00:00:00 2001 From: Sigvart Hovland Date: Fri, 3 May 2019 14:21:52 +0200 Subject: [PATCH 3716/3723] [nrf noup] tree-wide: support NCS Partition Manager (PM) definitions MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Partition Manager (PM) is a component of the nRF Connect SDK (NCS) which uses yaml files to resolve flash partition placement with a holistic view of the entire device, including each firmware image present on the flash device, and various subsystems, such as settings and NFFS. When this NCS extension is used, various source files which would use partition information from devicetree in "vanilla" zephyr instead use defines generated by PM instead. This commit removes support for HEX_FILES_TO_MERGE, as it conflicts with PM. The settings subsystem pm.yml defines a partition 'settings_storage'. The nffs subsystem pm.yml defines 'nffs_storage'. Leverage label translation to avoid patching partition names. Refer to the NCS documentation page for this feature for more details. This is a long-running out of tree patch which has been worked on by several people. The following sign-offs are in alphabetical order by first name. Signed-off-by: Andrzej Głąbek Signed-off-by: Andrzej Puzdrowski Signed-off-by: Håkon Øye Amundsen Signed-off-by: Ioannis Glaropoulos Signed-off-by: Joakim Andersson Signed-off-by: Johann Fischer Signed-off-by: Martí Bolívar Signed-off-by: Ole Sæther Signed-off-by: Robert Lubos Signed-off-by: Sebastian Bøe Signed-off-by: Sigvart Hovland Signed-off-by: Thomas Stenersen Signed-off-by: Torsten Rasmussen Signed-off-by: Øyvind Rønningstad Signed-off-by: Trond Einar Snekvik Signed-off-by: Gerard Marull-Paretas Signed-off-by: Tomasz Moń (cherry picked from commit ba54fe88dcfe3b25aca4c02f01e47f232b0f8bf7) (cherry picked from commit 68110ee5a75167e8e2c65746211571315618a3e1) (cherry picked from commit 12d1ebfb98a4f89dc018af4e7872382222b3b74a) (cherry picked from commit 5e8e748917649fc0a4a44a02c2c91c581007856d) (cherry picked from commit d1fa3da6c37763e1ae9306c43bfaf5cf965af594) Signed-off-by: Dominik Ermel (cherry picked from commit a7fb26837763ee7c21fb666fe2faa8c7503a17f1) --- arch/arm/core/mpu/arm_mpu_regions.c | 13 ++++++ cmake/modules/kernel.cmake | 4 ++ drivers/flash/soc_flash_nrf.c | 11 +++++ .../arch/arm/cortex_m/scripts/linker.ld | 46 +++++++++++++++++++ include/zephyr/storage/flash_map.h | 6 +++ lib/heap/Kconfig | 2 +- lib/libc/common/source/stdlib/malloc.c | 18 +++++++- subsys/fs/littlefs_fs.c | 7 ++- subsys/ipc/rpmsg_service/rpmsg_backend.h | 27 +++++++++++ 9 files changed, 130 insertions(+), 4 deletions(-) diff --git a/arch/arm/core/mpu/arm_mpu_regions.c b/arch/arm/core/mpu/arm_mpu_regions.c index 6af62f84078..cfe1230c907 100644 --- a/arch/arm/core/mpu/arm_mpu_regions.c +++ b/arch/arm/core/mpu/arm_mpu_regions.c @@ -8,6 +8,9 @@ #include #include +#if USE_PARTITION_MANAGER +#include +#endif static const struct arm_mpu_region mpu_regions[] = { /* Region 0 */ @@ -21,6 +24,14 @@ static const struct arm_mpu_region mpu_regions[] = { #endif /* Region 1 */ MPU_REGION_ENTRY("SRAM_0", +#if USE_PARTITION_MANAGER + PM_SRAM_ADDRESS, +#if defined(CONFIG_ARMV8_M_BASELINE) || defined(CONFIG_ARMV8_M_MAINLINE) + REGION_RAM_ATTR(PM_SRAM_ADDRESS, PM_SRAM_SIZE)), +#else + REGION_RAM_ATTR(REGION_SRAM_SIZE)), +#endif +#else CONFIG_SRAM_BASE_ADDRESS, #if defined(CONFIG_ARMV8_M_BASELINE) || defined(CONFIG_ARMV8_M_MAINLINE) REGION_RAM_ATTR(CONFIG_SRAM_BASE_ADDRESS, \ @@ -28,6 +39,8 @@ static const struct arm_mpu_region mpu_regions[] = { #else REGION_RAM_ATTR(REGION_SRAM_SIZE)), #endif + +#endif /* USE_PARTITION_MANAGER */ }; const struct arm_mpu_config mpu_config = { diff --git a/cmake/modules/kernel.cmake b/cmake/modules/kernel.cmake index a093d46691f..06e1642f362 100644 --- a/cmake/modules/kernel.cmake +++ b/cmake/modules/kernel.cmake @@ -243,3 +243,7 @@ if("${CMAKE_EXTRA_GENERATOR}" STREQUAL "Eclipse CDT4") include(${ZEPHYR_BASE}/cmake/ide/eclipse_cdt4_generator_amendment.cmake) eclipse_cdt4_generator_amendment(1) endif() + +if(ZEPHYR_NRF_MODULE_DIR) + include(${ZEPHYR_NRF_MODULE_DIR}/cmake/partition_manager.cmake) +endif() diff --git a/drivers/flash/soc_flash_nrf.c b/drivers/flash/soc_flash_nrf.c index cc840309264..b5a3fefa1e5 100644 --- a/drivers/flash/soc_flash_nrf.c +++ b/drivers/flash/soc_flash_nrf.c @@ -37,6 +37,11 @@ LOG_MODULE_REGISTER(flash_nrf); #define SOC_NV_FLASH_NODE DT_INST(0, soc_nv_flash) +#if CONFIG_TRUSTED_EXECUTION_NONSECURE && USE_PARTITION_MANAGER +#include +#include +#endif /* CONFIG_TRUSTED_EXECUTION_NONSECURE && USE_PARTITION_MANAGER */ + #ifndef CONFIG_SOC_FLASH_NRF_RADIO_SYNC_NONE #define FLASH_SLOT_WRITE 7500 #if defined(CONFIG_SOC_FLASH_NRF_PARTIAL_ERASE) @@ -166,6 +171,12 @@ static int flash_nrf_read(const struct device *dev, off_t addr, } #endif +#if CONFIG_TRUSTED_EXECUTION_NONSECURE && USE_PARTITION_MANAGER && PM_APP_ADDRESS + if (addr < PM_APP_ADDRESS) { + return soc_secure_mem_read(data, (void *)addr, len); + } +#endif + nrf_nvmc_buffer_read(data, (uint32_t)addr, len); return 0; diff --git a/include/zephyr/arch/arm/cortex_m/scripts/linker.ld b/include/zephyr/arch/arm/cortex_m/scripts/linker.ld index d061468d2ac..14eb78f3e70 100644 --- a/include/zephyr/arch/arm/cortex_m/scripts/linker.ld +++ b/include/zephyr/arch/arm/cortex_m/scripts/linker.ld @@ -26,6 +26,35 @@ #endif #define RAMABLE_REGION RAM +#if USE_PARTITION_MANAGER + +#include + +#if CONFIG_NCS_IS_VARIANT_IMAGE && defined(PM_S0_ID) +/* We are linking against S1, create symbol containing the flash ID of S0. + * This is used when writing code operating on the "other" slot. + */ +_image_1_primary_slot_id = PM_S0_ID; + +#else /* ! CONFIG_NCS_IS_VARIANT_IMAGE */ + +#ifdef PM_S1_ID +/* We are linking against S0, create symbol containing the flash ID of S1. + * This is used when writing code operating on the "other" slot. + */ +_image_1_primary_slot_id = PM_S1_ID; +#endif /* PM_S1_ID */ + +#endif /* CONFIG_NCS_IS_VARIANT_IMAGE */ + +#define ROM_ADDR PM_ADDRESS +#define ROM_SIZE PM_SIZE + +#define RAM_SIZE PM_SRAM_SIZE +#define RAM_ADDR PM_SRAM_ADDRESS + +#else /* ! USE_PARTITION_MANAGER */ + #if !defined(CONFIG_XIP) && (CONFIG_FLASH_SIZE == 0) #define ROM_ADDR RAM_ADDR #else @@ -58,6 +87,23 @@ #define RAM_ADDR CONFIG_SRAM_BASE_ADDRESS #endif +#endif /* USE_PARTITION_MANAGER */ + +#if DT_NODE_HAS_STATUS(DT_CHOSEN(zephyr_ccm), okay) +#define CCM_SIZE DT_REG_SIZE(DT_CHOSEN(zephyr_ccm)) +#define CCM_ADDR DT_REG_ADDR(DT_CHOSEN(zephyr_ccm)) +#endif + +#if DT_NODE_HAS_STATUS(DT_CHOSEN(zephyr_itcm), okay) +#define ITCM_SIZE DT_REG_SIZE(DT_CHOSEN(zephyr_itcm)) +#define ITCM_ADDR DT_REG_ADDR(DT_CHOSEN(zephyr_itcm)) +#endif + +#if DT_NODE_HAS_STATUS(DT_CHOSEN(zephyr_dtcm), okay) +#define DTCM_SIZE DT_REG_SIZE(DT_CHOSEN(zephyr_dtcm)) +#define DTCM_ADDR DT_REG_ADDR(DT_CHOSEN(zephyr_dtcm)) +#endif + #if defined(CONFIG_CUSTOM_SECTION_ALIGN) _region_min_align = CONFIG_CUSTOM_SECTION_MIN_ALIGN_SIZE; #else diff --git a/include/zephyr/storage/flash_map.h b/include/zephyr/storage/flash_map.h index 12f4f4c34a2..ffe386d6b7a 100644 --- a/include/zephyr/storage/flash_map.h +++ b/include/zephyr/storage/flash_map.h @@ -271,6 +271,10 @@ const char *flash_area_label(const struct flash_area *fa); */ uint8_t flash_area_erased_val(const struct flash_area *fa); +#if USE_PARTITION_MANAGER +#include +#else + /** * Returns non-0 value if fixed-partition of given DTS node label exists. * @@ -328,6 +332,8 @@ uint8_t flash_area_erased_val(const struct flash_area *fa); #define FIXED_PARTITION_DEVICE(label) \ DEVICE_DT_GET(DT_MTD_FROM_FIXED_PARTITION(DT_NODELABEL(label))) +#endif /* USE_PARTITION_MANAGER */ + #ifdef __cplusplus } #endif diff --git a/lib/heap/Kconfig b/lib/heap/Kconfig index 7f01b280b3b..68476eb735c 100644 --- a/lib/heap/Kconfig +++ b/lib/heap/Kconfig @@ -68,7 +68,7 @@ config HEAP_LISTENER choice prompt "Supported heap sizes" depends on !64BIT - default SYS_HEAP_SMALL_ONLY if (SRAM_SIZE <= 256) + default SYS_HEAP_SMALL_ONLY if (SRAM_SIZE <= 256) && !PARTITION_MANAGER_ENABLED default SYS_HEAP_AUTO help Heaps using reduced-size chunk headers can accommodate so called diff --git a/lib/libc/common/source/stdlib/malloc.c b/lib/libc/common/source/stdlib/malloc.c index e3a5db6f7d5..2f469d673e4 100644 --- a/lib/libc/common/source/stdlib/malloc.c +++ b/lib/libc/common/source/stdlib/malloc.c @@ -25,6 +25,20 @@ #include LOG_MODULE_DECLARE(os, CONFIG_KERNEL_LOG_LEVEL); +#if USE_PARTITION_MANAGER + +#include + +#define RAM_SIZE PM_SRAM_SIZE +#define RAM_ADDR PM_SRAM_ADDRESS + +#else /* ! USE_PARTITION_MANAGER */ + +#define RAM_SIZE (KB((size_t) CONFIG_SRAM_SIZE)) +#define RAM_ADDR CONFIG_SRAM_BASE_ADDRESS + +#endif /* USE_PARTITION_MANAGER */ + #ifdef CONFIG_COMMON_LIBC_MALLOC #if (CONFIG_COMMON_LIBC_MALLOC_ARENA_SIZE != 0) @@ -106,8 +120,8 @@ static POOL_SECTION unsigned char __aligned(HEAP_ALIGN) malloc_arena[HEAP_SIZE]; extern char _heap_sentry[]; # define HEAP_SIZE ROUND_DOWN((POINTER_TO_UINT(_heap_sentry) - HEAP_BASE), HEAP_ALIGN) # else -# define HEAP_SIZE ROUND_DOWN((KB((size_t) CONFIG_SRAM_SIZE) - \ - ((size_t) HEAP_BASE - (size_t) CONFIG_SRAM_BASE_ADDRESS)), HEAP_ALIGN) +# define HEAP_SIZE ROUND_DOWN((RAM_SIZE - \ + ((size_t) HEAP_BASE - (size_t) RAM_ADDR)), HEAP_ALIGN) # endif /* else CONFIG_XTENSA */ # endif /* else CONFIG_COMMON_LIBC_MALLOC_ARENA_SIZE > 0 */ diff --git a/subsys/fs/littlefs_fs.c b/subsys/fs/littlefs_fs.c index b373ca92ba8..3fc84c2922d 100644 --- a/subsys/fs/littlefs_fs.c +++ b/subsys/fs/littlefs_fs.c @@ -1054,7 +1054,12 @@ struct fs_mount_t FS_FSTAB_ENTRY(DT_DRV_INST(inst)) = { \ .type = FS_LITTLEFS, \ .mnt_point = DT_INST_PROP(inst, mount_point), \ .fs_data = &fs_data_##inst, \ - .storage_dev = (void *)DT_FIXED_PARTITION_ID(FS_PARTITION(inst)), \ + .storage_dev = (void *) \ + COND_CODE_1(USE_PARTITION_MANAGER, \ + (COND_CODE_1(FIXED_PARTITION_EXISTS(littlefs_storage), \ + (FIXED_PARTITION_ID(littlefs_storage)), \ + (FIXED_PARTITION_ID(storage)))), \ + (DT_FIXED_PARTITION_ID(FS_PARTITION(inst)))), \ .flags = FSTAB_ENTRY_DT_MOUNT_FLAGS(DT_DRV_INST(inst)), \ }; diff --git a/subsys/ipc/rpmsg_service/rpmsg_backend.h b/subsys/ipc/rpmsg_service/rpmsg_backend.h index a74e46b8520..9996e1d74d9 100644 --- a/subsys/ipc/rpmsg_service/rpmsg_backend.h +++ b/subsys/ipc/rpmsg_service/rpmsg_backend.h @@ -13,8 +13,35 @@ extern "C" { #endif +#if CONFIG_PARTITION_MANAGER_ENABLED + +#include "pm_config.h" + +#if defined(PM_RPMSG_NRF53_SRAM_ADDRESS) || defined(PM__RPMSG_NRF53_SRAM_ADDRESS) + +#if defined(PM_RPMSG_NRF53_SRAM_ADDRESS) +#define VDEV_START_ADDR PM_RPMSG_NRF53_SRAM_ADDRESS +#define VDEV_SIZE PM_RPMSG_NRF53_SRAM_SIZE +#else +/* The current image is a child image in a different domain than the image + * which defined the required values. To reach the values of the parent domain + * we use the 'PM__' variant of the define. + */ +#define VDEV_START_ADDR PM__RPMSG_NRF53_SRAM_ADDRESS +#define VDEV_SIZE PM__RPMSG_NRF53_SRAM_SIZE +#endif /* defined(PM_RPMSG_NRF53_SRAM_ADDRESS) */ + +#else #define VDEV_START_ADDR DT_REG_ADDR(DT_CHOSEN(zephyr_ipc_shm)) #define VDEV_SIZE DT_REG_SIZE(DT_CHOSEN(zephyr_ipc_shm)) +#endif /* defined(PM_RPMSG_NRF53_SRAM_ADDRESS) || defined(PM__RPMSG_NRF53_SRAM_ADDRESS) */ + +#else + +#define VDEV_START_ADDR DT_REG_ADDR(DT_CHOSEN(zephyr_ipc_shm)) +#define VDEV_SIZE DT_REG_SIZE(DT_CHOSEN(zephyr_ipc_shm)) + +#endif /* CONFIG_PARTITION_MANAGER_ENABLED */ #define VDEV_STATUS_ADDR VDEV_START_ADDR #define VDEV_STATUS_SIZE 0x400 From 28b4037b4b52217c9014e3355c40764dd2415a05 Mon Sep 17 00:00:00 2001 From: Aleksandr Khromykh Date: Thu, 9 Nov 2023 13:30:15 +0100 Subject: [PATCH 3717/3723] [nrf noup] Bluetooth: Mesh: adapt SDC specific api usage Usage of the Softdevice specific api has been adapted to upstream adv changes. Signed-off-by: Aleksandr Khromykh (cherry picked from commit 533baa16b5a6750cf59a7ce7257bc09bcac09637) Signed-off-by: Dominik Ermel (cherry picked from commit 36710dee098619426dcadcecdb7f217c12d01910) Signed-off-by: Robert Lubos --- subsys/bluetooth/mesh/adv_ext.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/subsys/bluetooth/mesh/adv_ext.c b/subsys/bluetooth/mesh/adv_ext.c index 1be3ca16c51..67709a221ba 100644 --- a/subsys/bluetooth/mesh/adv_ext.c +++ b/subsys/bluetooth/mesh/adv_ext.c @@ -513,8 +513,8 @@ int bt_mesh_adv_enable(void) if (IS_ENABLED(CONFIG_BT_LL_SOFTDEVICE) && IS_ENABLED(CONFIG_BT_MESH_ADV_EXT_FRIEND_SEPARATE) && - adv->tag == BT_MESH_FRIEND_ADV) { - err = set_adv_randomness(adv->instance->handle, 0); + advs[i].tags == BT_MESH_ADV_TAG_BIT_FRIEND) { + err = set_adv_randomness(advs[i].instance->handle, 0); if (err) { LOG_ERR("Failed to set zero randomness: %d", err); } From 67515d933c0b25b484bbe11d4737945e919ec69d Mon Sep 17 00:00:00 2001 From: Markus Swarowsky Date: Mon, 22 Jan 2024 12:28:47 +0100 Subject: [PATCH 3718/3723] [nrf toup] modules: tf-m: Remove TFM_TEST_REPO_PATH TF-M 2.0.0 doesn't use the TFM_TEST_REPO_PATH anymore so removing it. Signed-off-by: Markus Swarowsky --- modules/trusted-firmware-m/CMakeLists.txt | 2 -- 1 file changed, 2 deletions(-) diff --git a/modules/trusted-firmware-m/CMakeLists.txt b/modules/trusted-firmware-m/CMakeLists.txt index f647e385dcf..ec28b603249 100644 --- a/modules/trusted-firmware-m/CMakeLists.txt +++ b/modules/trusted-firmware-m/CMakeLists.txt @@ -161,7 +161,6 @@ if (CONFIG_BUILD_WITH_TFM) set(TFM_BINARY_DIR ${CMAKE_BINARY_DIR}/tfm) - set(TFM_TEST_REPO_PATH ${ZEPHYR_CURRENT_MODULE_DIR}/../tf-m-tests) set(PSA_ARCH_TESTS_PATH ${ZEPHYR_CURRENT_MODULE_DIR}/../psa-arch-tests) set(TFM_INTERFACE_SOURCE_DIR ${TFM_BINARY_DIR}/api_ns/interface/src) @@ -281,7 +280,6 @@ if (CONFIG_BUILD_WITH_TFM) ${TFM_CMAKE_ARGS} $> -DMBEDCRYPTO_PATH=$>,$,${ZEPHYR_MBEDTLS_MODULE_DIR}> - -DTFM_TEST_REPO_PATH=${TFM_TEST_REPO_PATH} -DPSA_ARCH_TESTS_PATH=${PSA_ARCH_TESTS_PATH} ${ZEPHYR_TRUSTED_FIRMWARE_M_MODULE_DIR} WORKING_DIRECTORY ${TFM_BINARY_DIR} From 084928e602d8732df1c5c31074a7b7ea2224eb02 Mon Sep 17 00:00:00 2001 From: Markus Swarowsky Date: Mon, 22 Jan 2024 13:28:35 +0100 Subject: [PATCH 3719/3723] [nrf toup] modules: tf-m: Remove QCBOR path from build QCBOR is only needed by the TF-M tests, as they are not build separately due to the TF-M split build By still setting it we get a CMake build warning Signed-off-by: Markus Swarowsky --- modules/trusted-firmware-m/CMakeLists.txt | 8 -------- 1 file changed, 8 deletions(-) diff --git a/modules/trusted-firmware-m/CMakeLists.txt b/modules/trusted-firmware-m/CMakeLists.txt index ec28b603249..247ac050337 100644 --- a/modules/trusted-firmware-m/CMakeLists.txt +++ b/modules/trusted-firmware-m/CMakeLists.txt @@ -229,14 +229,6 @@ if (CONFIG_BUILD_WITH_TFM) string(REPLACE "toolchain" "toolchain_ns" TFM_TOOLCHAIN_NS_FILE ${TFM_TOOLCHAIN_FILE}) - if (CONFIG_TFM_QCBOR_PATH STREQUAL "DOWNLOAD") - # Change CMake cache type to string to avoid QCBOR_PATH=/absolute/path/DOWNLOAD being set. - set(QCBOR_PATH_TYPE ":STRING") - endif() - # Always set QCBOR_PATH, this will make sure that we don't automatically download this - # dependency in the TF-M build system and it will fail when set to an invalid value. - list(APPEND TFM_CMAKE_ARGS -DQCBOR_PATH${QCBOR_PATH_TYPE}=${CONFIG_TFM_QCBOR_PATH}) - if(CONFIG_BOARD_LPCXPRESSO55S69_CPU0) # Supply path to NXP HAL sources used for TF-M build set(TFM_PLATFORM_NXP_HAL_FILE_PATH ${ZEPHYR_TRUSTED_FIRMWARE_M_MODULE_DIR}/platform/ext/target/nxp/) From e8a280e2c6113887fc95d5213c188cbfe1bbc347 Mon Sep 17 00:00:00 2001 From: Markus Swarowsky Date: Mon, 22 Jan 2024 14:05:52 +0100 Subject: [PATCH 3720/3723] [nrf toup] modules: tf-m: Rename crypto modules to ENABLED The TF-M crypto modules got renames from CRYPTO_XXX_MODULE_DISABLED to CRYPTO_XXX_MODULE_ENABLED Therefore also re naming it in zephyr build integration. Signed-off-by: Markus Swarowsky --- modules/trusted-firmware-m/CMakeLists.txt | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/modules/trusted-firmware-m/CMakeLists.txt b/modules/trusted-firmware-m/CMakeLists.txt index 247ac050337..2ca875c4df2 100644 --- a/modules/trusted-firmware-m/CMakeLists.txt +++ b/modules/trusted-firmware-m/CMakeLists.txt @@ -152,11 +152,8 @@ if (CONFIG_BUILD_WITH_TFM) foreach(module ${TFM_CRYPTO_MODULES}) if (CONFIG_TFM_${module}_ENABLED) # list(APPEND TFM_ENABLED_CRYPTO_MODULES_ARG ${module}) - set(val "FALSE") - else() - set(val "TRUE") + list(APPEND TFM_CMAKE_ARGS -D${module}_ENABLED=True) endif() - list(APPEND TFM_CMAKE_ARGS -D${module}_DISABLED=${val}) endforeach() set(TFM_BINARY_DIR ${CMAKE_BINARY_DIR}/tfm) From 78335e31586d2143a760344dae7c91a95494bcab Mon Sep 17 00:00:00 2001 From: Georgios Vasilakis Date: Thu, 25 Jan 2024 15:38:22 +0100 Subject: [PATCH 3721/3723] [nrf noup]: Add PSA_WANT Kconfigs for key types The new Oberon PSA core (1.2.0) uses new PSA_WANT symbols for the ECC and RSA keys. This adds these new Kconfigs without removing the old ones to avoid necessary changes in the configuration of an application. Signed-off-by: Georgios Vasilakis Signed-off-by: Markus Swarowsky --- modules/mbedtls/Kconfig.psa | 57 +++++++++++++++++++++++++++++++++++++ 1 file changed, 57 insertions(+) diff --git a/modules/mbedtls/Kconfig.psa b/modules/mbedtls/Kconfig.psa index 42d2a48825b..291160cd9da 100644 --- a/modules/mbedtls/Kconfig.psa +++ b/modules/mbedtls/Kconfig.psa @@ -133,6 +133,35 @@ config PSA_WANT_KEY_TYPE_ECC_PUBLIC_KEY help Elliptic curve public key. + +config PSA_WANT_KEY_TYPE_ECC_KEY_PAIR_IMPORT + bool "PSA ECC import key pair support" + default y if PSA_WANT_KEY_TYPE_ECC_KEY_PAIR + select PSA_WANT_KEY_TYPE_ECC_PUBLIC_KEY + help + Elliptic curve key pair: import for both the private and public key. + +config PSA_WANT_KEY_TYPE_ECC_KEY_PAIR_EXPORT + bool "PSA ECC export key pair support" + default y if PSA_WANT_KEY_TYPE_ECC_KEY_PAIR + select PSA_WANT_KEY_TYPE_ECC_PUBLIC_KEY + help + Elliptic curve key pair: export for both the private and public key. + +config PSA_WANT_KEY_TYPE_ECC_KEY_PAIR_GENERATE + bool "PSA ECC generate key pair support" + default y if PSA_WANT_KEY_TYPE_ECC_KEY_PAIR + select PSA_WANT_KEY_TYPE_ECC_PUBLIC_KEY + help + Elliptic curve key pair: generate for both the private and public key. + +config PSA_WANT_KEY_TYPE_ECC_KEY_PAIR_BASIC + bool + depends on PSA_WANT_KEY_TYPE_ECC_KEY_PAIR_IMPORT || \ + PSA_WANT_KEY_TYPE_ECC_KEY_PAIR_EXPORT || \ + PSA_WANT_KEY_TYPE_ECC_KEY_PAIR_GENERATE + + config PSA_WANT_KEY_TYPE_RSA_KEY_PAIR bool "PSA RSA key pair type support" select PSA_WANT_KEY_TYPE_RSA_PUBLIC_KEY @@ -144,6 +173,34 @@ config PSA_WANT_KEY_TYPE_RSA_PUBLIC_KEY help RSA public key. +config PSA_WANT_KEY_TYPE_RSA_KEY_PAIR_IMPORT + bool "PSA RSA key pair import key" + default y if PSA_WANT_KEY_TYPE_RSA_KEY_PAIR + select PSA_WANT_KEY_TYPE_RSA_PUBLIC_KEY + help + RSA key pair: import key for both the private and public key. + +config PSA_WANT_KEY_TYPE_RSA_KEY_PAIR_EXPORT + bool "PSA RSA key pair export key" + default y if PSA_WANT_KEY_TYPE_RSA_KEY_PAIR + select PSA_WANT_KEY_TYPE_RSA_PUBLIC_KEY + help + RSA key pair: export key for both the private and public key. + +config PSA_WANT_KEY_TYPE_RSA_KEY_PAIR_GENERATE + bool "PSA RSA key pair generate key" + default y if PSA_WANT_KEY_TYPE_RSA_KEY_PAIR + select PSA_WANT_KEY_TYPE_RSA_PUBLIC_KEY + help + RSA key pair: key generation for both the private and public key. + +config PSA_WANT_KEY_TYPE_RSA_KEY_PAIR_BASIC + bool + default y + depends on PSA_WANT_KEY_TYPE_RSA_KEY_PAIR_IMPORT || \ + PSA_WANT_KEY_TYPE_RSA_KEY_PAIR_EXPORT || \ + PSA_WANT_KEY_TYPE_RSA_KEY_PAIR_GENERATE + config PSA_WANT_KEY_TYPE_DH_KEY_PAIR bool "PSA DH key pair type support" select PSA_WANT_KEY_TYPE_DH_PUBLIC_KEY From 94c398a4a282535892e32fe00447bac0d73ad14e Mon Sep 17 00:00:00 2001 From: Georgios Vasilakis Date: Tue, 30 Jan 2024 13:14:26 +0100 Subject: [PATCH 3722/3723] fixup! [nrf noup]: Add PSA_WANT Kconfigs for key types Signed-off-by: Markus Swarowsky --- modules/mbedtls/Kconfig.psa | 1 + 1 file changed, 1 insertion(+) diff --git a/modules/mbedtls/Kconfig.psa b/modules/mbedtls/Kconfig.psa index 291160cd9da..9e3310e0a61 100644 --- a/modules/mbedtls/Kconfig.psa +++ b/modules/mbedtls/Kconfig.psa @@ -157,6 +157,7 @@ config PSA_WANT_KEY_TYPE_ECC_KEY_PAIR_GENERATE config PSA_WANT_KEY_TYPE_ECC_KEY_PAIR_BASIC bool + default y depends on PSA_WANT_KEY_TYPE_ECC_KEY_PAIR_IMPORT || \ PSA_WANT_KEY_TYPE_ECC_KEY_PAIR_EXPORT || \ PSA_WANT_KEY_TYPE_ECC_KEY_PAIR_GENERATE From adc2cebafac2ec8e5f6ce35431cc9a72eebfc553 Mon Sep 17 00:00:00 2001 From: Georgios Vasilakis Date: Tue, 30 Jan 2024 14:57:38 +0100 Subject: [PATCH 3723/3723] fixup! [nrf noup]: Add PSA_WANT Kconfigs for key types Signed-off-by: Markus Swarowsky --- modules/mbedtls/Kconfig.psa | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/modules/mbedtls/Kconfig.psa b/modules/mbedtls/Kconfig.psa index 9e3310e0a61..25ac778eb2d 100644 --- a/modules/mbedtls/Kconfig.psa +++ b/modules/mbedtls/Kconfig.psa @@ -162,6 +162,10 @@ config PSA_WANT_KEY_TYPE_ECC_KEY_PAIR_BASIC PSA_WANT_KEY_TYPE_ECC_KEY_PAIR_EXPORT || \ PSA_WANT_KEY_TYPE_ECC_KEY_PAIR_GENERATE +config PSA_WANT_KEY_TYPE_ECC_KEY_PAIR_DERIVE + bool + default y + depends on PSA_WANT_KEY_TYPE_ECC_KEY_PAIR config PSA_WANT_KEY_TYPE_RSA_KEY_PAIR bool "PSA RSA key pair type support"

` application. + +Run a serial host program to connect with your B-U585I-IOT02A board: + +.. code-block:: console + + $ minicom -D /dev/ttyACM0 + +Then build and flash the application for the STM32WB5MMG module. + +.. zephyr-app-commands:: + :zephyr-app: samples/bluetooth/hci_uart + :board: stm32wb5mmg + :goals: build flash + +Next, reverse back the buttons to default mode (SW4 on ON and SW5 +on OFF) mode. In this case we will upload the Bluetooth sample on the +main microcontroller.Then, build the bluetooth +:zephyr_file:`samples/bluetooth/observer` demo application for +B-U585I-IOT02A board: + +.. zephyr-app-commands:: + :zephyr-app: samples/bluetooth/observer + :board: b_u585i_iot02a + :goals: build flash + +Rest the board and you should see the following messages on the console: + +.. code-block:: console + + Starting Observer Demo + Started scanning... + Exiting main thread. + Device found: 2C:98:F3:64:58:06 (random) (RSSI -82), type 3, AD data len 31 + Device found: CE:5B:9A:87:69:4F (random) (RSSI -80), type 3, AD data len 8 + Device found: 7B:1E:DD:38:23:E1 (random) (RSSI -85), type 0, AD data len 17 + + +Debugging +========= + +You can debug an application in the usual way. Here is an example for the +:ref:`hci_uart ` application. + +.. zephyr-app-commands:: + :zephyr-app: samples/bluetooth/observer + :board: b_u585i_iot02a + :maybe-skip-config: + :goals: debug + +.. _STM32WB5MMG on www.st.com: + https://www.st.com/en/microcontrollers-microprocessors/stm32wb5mmg.html + +.. _STM32WB5MMG datasheet: + https://www.st.com/resource/en/datasheet/stm32wb5mmg.pdf +.. _modules/hal/stm32/lib/stm32wb/hci/README: + https://github.com/zephyrproject-rtos/hal_stm32/blob/main/lib/stm32wb/hci/README diff --git a/boards/arm/stm32wb5mmg/stm32wb5mmg.dts b/boards/arm/stm32wb5mmg/stm32wb5mmg.dts new file mode 100644 index 00000000000..d494b7024dc --- /dev/null +++ b/boards/arm/stm32wb5mmg/stm32wb5mmg.dts @@ -0,0 +1,106 @@ +/* + * Copyright (c) 2024 Javad Rahimipetroudi + * + * SPDX-License-Identifier: Apache-2.0 + */ + +/dts-v1/; +#include +#include +#include + +/ { + model = "STMicroelectronics STM32WB5MMG Bluetooth module"; + compatible = "st,stm32wb5mmgh6"; + + chosen { + zephyr,console = &usart1; + zephyr,shell-uart = &usart1; + zephyr,bt-mon-uart = &lpuart1; + zephyr,bt-c2h-uart = &lpuart1; + zephyr,sram = &sram0; + zephyr,flash = &flash0; + zephyr,code-partition = &slot0_partition; + }; +}; + +&clk_hse { + status = "okay"; +}; + +&clk_lse { + status = "okay"; +}; + +&clk_hsi48 { + status = "okay"; +}; + +&clk48 { + /* Node is disabled by default as default source is HSI48 */ + /* To select another clock, enable the node */ + clocks = <&rcc STM32_SRC_HSI48 CLK48_SEL(0)>; +}; + +&rcc { + clocks = <&clk_hse>; + clock-frequency = ; + cpu1-prescaler = <1>; + cpu2-prescaler = <1>; + ahb4-prescaler = <1>; + apb1-prescaler = <1>; + apb2-prescaler = <1>; +}; + +&usart1 { + pinctrl-0 = <&usart1_tx_pb6 &usart1_rx_pb7>; + pinctrl-names = "default"; + current-speed = <115200>; + status = "okay"; +}; + +&lpuart1 { + pinctrl-0 = <&lpuart1_tx_pa2 &lpuart1_rx_pa3>; + pinctrl-names = "default"; + current-speed = <100000>; + status = "okay"; +}; + +&adc1 { + pinctrl-0 = <&adc1_in3_pc2>; + pinctrl-names = "default"; + st,adc-clock-source = ; + st,adc-prescaler = <4>; + status = "okay"; +}; + +zephyr_udc0: &usb { + status = "okay"; + pinctrl-0 = <&usb_dm_pa11 &usb_dp_pa12>; + pinctrl-names = "default"; +}; + +&flash0 { + partitions { + compatible = "fixed-partitions"; + #address-cells = <1>; + #size-cells = <1>; + + /* + * Configure partitions while leaving space for M0 BLE f/w + * Since STM32WBCube release V1.13.2, only _HCIOnly_ f/w are supported. + * These FW are expected to be located not before 0x080DB000 + * Current partition is using the first 876K of the flash for M4 + */ + + boot_partition: partition@0 { + label = "mcuboot"; + reg = <0x00000000 DT_SIZE_K(48)>; + }; + slot0_partition: partition@c000 { + label = "image-0"; + reg = <0x0000c000 DT_SIZE_K(400)>; + }; + + }; +}; diff --git a/boards/arm/stm32wb5mmg/stm32wb5mmg.yaml b/boards/arm/stm32wb5mmg/stm32wb5mmg.yaml new file mode 100644 index 00000000000..2e3667f18d5 --- /dev/null +++ b/boards/arm/stm32wb5mmg/stm32wb5mmg.yaml @@ -0,0 +1,16 @@ +identifier: stm32wb5mmg +name: ST STM32WB5MMG Ultra-low-power Module +type: mcu +arch: arm +toolchain: + - zephyr + - gnuarmemb + - xtools +ram: 256 +flash: 1024 +supported: + - gpio + - dma + - uart + - usb_device +vendor: st diff --git a/boards/arm/stm32wb5mmg/stm32wb5mmg_defconfig b/boards/arm/stm32wb5mmg/stm32wb5mmg_defconfig new file mode 100644 index 00000000000..9fdd732848e --- /dev/null +++ b/boards/arm/stm32wb5mmg/stm32wb5mmg_defconfig @@ -0,0 +1,24 @@ +CONFIG_SOC_SERIES_STM32WBX=y +CONFIG_SOC_STM32WB55XX=y + +# enable uart driver +CONFIG_SERIAL=y + +# enable GPIO +CONFIG_GPIO=y + +# enable clocks +CONFIG_CLOCK_CONTROL=y + +# console +CONFIG_CONSOLE=y +CONFIG_UART_CONSOLE=y + +# Enable MPU +CONFIG_ARM_MPU=y + +# Enable HW stack protection +CONFIG_HW_STACK_PROTECTION=y + +# enable pin controller +CONFIG_PINCTRL=y diff --git a/boards/arm/stm32wb5mmg/support/openocd.cfg b/boards/arm/stm32wb5mmg/support/openocd.cfg new file mode 100644 index 00000000000..2ad58270368 --- /dev/null +++ b/boards/arm/stm32wb5mmg/support/openocd.cfg @@ -0,0 +1,7 @@ +source [find interface/stlink.cfg] + +transport select hla_swd + +source [find target/stm32wbx.cfg] + +reset_config srst_only From ce4cdd8d37e18e40ccf21f27ff1cba8030f9013b Mon Sep 17 00:00:00 2001 From: Javad Rahimipetroudi Date: Mon, 15 Jan 2024 15:01:40 +0100 Subject: [PATCH 2954/3723] boards: arm: b_u585i_iot02a: add bluetooth support This commits makes it possible to use the onboard bluetooth module (STM32WB5MMG) with existing zephyr bluetooth samples. Note that there was no hardware flow control wiring available on the board, which is why it has been disabled in the both main board and BLE module Device Tree. As the board doesn't support HW flow control, users must set CONFIG_BT_HCI_ACL_FLOW_CONTROL=n in project files. Signed-off-by: Javad Rahimipetroudi --- boards/arm/b_u585i_iot02a/Kconfig.defconfig | 8 ++++++++ boards/arm/b_u585i_iot02a/b_u585i_iot02a.dts | 8 ++++++++ boards/arm/b_u585i_iot02a/doc/index.rst | 2 ++ 3 files changed, 18 insertions(+) diff --git a/boards/arm/b_u585i_iot02a/Kconfig.defconfig b/boards/arm/b_u585i_iot02a/Kconfig.defconfig index 6b3b72554ff..bc10deca7a2 100644 --- a/boards/arm/b_u585i_iot02a/Kconfig.defconfig +++ b/boards/arm/b_u585i_iot02a/Kconfig.defconfig @@ -27,4 +27,12 @@ config TFM_DUMMY_PROVISIONING endif # BUILD_WITH_TFM +# Disable Flow control +if BT + +config BT_HCI_ACL_FLOW_CONTROL + default n + +endif # BT + endif # BOARD_B_U585I_IOT02A diff --git a/boards/arm/b_u585i_iot02a/b_u585i_iot02a.dts b/boards/arm/b_u585i_iot02a/b_u585i_iot02a.dts index f8a826b1b6e..33093d701b7 100644 --- a/boards/arm/b_u585i_iot02a/b_u585i_iot02a.dts +++ b/boards/arm/b_u585i_iot02a/b_u585i_iot02a.dts @@ -17,6 +17,7 @@ zephyr,sram = &sram0; zephyr,flash = &flash0; zephyr,code-partition = &slot0_partition; + zephyr,bt-uart=&uart4; }; aliases { @@ -64,3 +65,10 @@ &gpdma1 { status = "okay"; }; + +&uart4 { + pinctrl-0 = <&uart4_tx_pc10 &uart4_rx_pc11>; + pinctrl-names = "default"; + current-speed = <100000>; + status = "okay"; +}; diff --git a/boards/arm/b_u585i_iot02a/doc/index.rst b/boards/arm/b_u585i_iot02a/doc/index.rst index 4850b1efee7..3121cfc5471 100644 --- a/boards/arm/b_u585i_iot02a/doc/index.rst +++ b/boards/arm/b_u585i_iot02a/doc/index.rst @@ -195,6 +195,8 @@ The Zephyr b_u585i_iot02a board configuration supports the following hardware fe +-----------+------------+-------------------------------------+ | AES | on-chip | crypto | +-----------+------------+-------------------------------------+ +| RADIO | STM32WB5MMG| Bluetooth Low Energy (BLE) | ++-----------+------------+-------------------------------------+ The default configuration can be found in the defconfig file: From 03bd8d0dd2090ec42cff55ba3fa44c45bf9326da Mon Sep 17 00:00:00 2001 From: Lukasz Mrugala Date: Tue, 16 Jan 2024 13:46:45 +0000 Subject: [PATCH 2955/3723] scripts: tests: Blackbox - make clear_log fixture autouse clear_log is used to prevent a common pytest log error, which makes logs unusable in testing. Such a fix is useful for all tests, so it should be autouse by default. Signed-off-by: Lukasz Mrugala --- scripts/tests/twister_blackbox/conftest.py | 10 ++++++++-- scripts/tests/twister_blackbox/test_error.py | 1 - scripts/tests/twister_blackbox/test_printouts.py | 3 --- scripts/tests/twister_blackbox/test_testplan.py | 5 ----- 4 files changed, 8 insertions(+), 11 deletions(-) diff --git a/scripts/tests/twister_blackbox/conftest.py b/scripts/tests/twister_blackbox/conftest.py index 1271af06694..517af1a79b7 100644 --- a/scripts/tests/twister_blackbox/conftest.py +++ b/scripts/tests/twister_blackbox/conftest.py @@ -24,6 +24,7 @@ testsuite_filename_mock = mock.PropertyMock(return_value='test_data.yaml') def pytest_configure(config): + config.addinivalue_line("markers", "noclearlog: disable the clear_log autouse fixture") config.addinivalue_line("markers", "noclearout: disable the provide_out autouse fixture") @pytest.fixture(name='zephyr_base') @@ -35,8 +36,13 @@ def zephyr_base_directory(): def zephyr_test_directory(): return TEST_DATA -@pytest.fixture -def clear_log(): +@pytest.fixture(autouse=True) +def clear_log(request): + # As this fixture is autouse, one can use the pytest.mark.noclearlog decorator + # in order to be sure that this fixture's code will not fire. + if 'noclearlog' in request.keywords: + return + # clear_log is used by pytest fixture # However, clear_log_in_test is prepared to be used directly in the code, wherever required clear_log_in_test() diff --git a/scripts/tests/twister_blackbox/test_error.py b/scripts/tests/twister_blackbox/test_error.py index 693b90f5228..85cb726a313 100644 --- a/scripts/tests/twister_blackbox/test_error.py +++ b/scripts/tests/twister_blackbox/test_error.py @@ -39,7 +39,6 @@ def setup_class(cls): def teardown_class(cls): pass - @pytest.mark.usefixtures("clear_log") @pytest.mark.parametrize( 'test, expected_exception', TESTDATA_1, diff --git a/scripts/tests/twister_blackbox/test_printouts.py b/scripts/tests/twister_blackbox/test_printouts.py index 845cea92161..a548137595b 100644 --- a/scripts/tests/twister_blackbox/test_printouts.py +++ b/scripts/tests/twister_blackbox/test_printouts.py @@ -167,7 +167,6 @@ def test_tree(self, capfd, out_path, test_path, expected): assert expected in out assert str(sys_exit.value) == '0' - @pytest.mark.usefixtures("clear_log") @pytest.mark.parametrize( 'test_path, test_platforms', TESTDATA_4, @@ -204,7 +203,6 @@ def test_timestamps(self, capfd, out_path, test_path, test_platforms): assert False, f'No timestamp in line {err_lines}' assert str(sys_exit.value) == '0' - @pytest.mark.usefixtures("clear_log") @pytest.mark.parametrize( 'flag', ['--abcd', '--1234', '-%', '-1'] @@ -226,7 +224,6 @@ def test_broken_parameter(self, capfd, flag): else: assert str(sys_exit.value) == '2' - @pytest.mark.usefixtures("clear_log") @pytest.mark.parametrize( 'flag', ['--help', '-h'] diff --git a/scripts/tests/twister_blackbox/test_testplan.py b/scripts/tests/twister_blackbox/test_testplan.py index 0444a564455..5a4ff0b9fb4 100644 --- a/scripts/tests/twister_blackbox/test_testplan.py +++ b/scripts/tests/twister_blackbox/test_testplan.py @@ -53,7 +53,6 @@ def setup_class(cls): def teardown_class(cls): pass - @pytest.mark.usefixtures("clear_log") @pytest.mark.parametrize( 'level, expected_tests', TESTDATA_1, @@ -86,7 +85,6 @@ def test_level(self, out_path, level, expected_tests): assert expected_tests == len(filtered_j) - @pytest.mark.usefixtures("clear_log") @pytest.mark.parametrize( 'test, expected_exception, expected_subtest_count', TESTDATA_2, @@ -120,8 +118,6 @@ def test_subtest(self, out_path, test, expected_exception, expected_subtest_coun assert str(exc.value) == '0' assert len(filtered_j) == expected_subtest_count - - @pytest.mark.usefixtures("clear_log") @pytest.mark.parametrize( 'filter, expected_count', TESTDATA_3, @@ -152,7 +148,6 @@ def test_filter(self, out_path, filter, expected_count): assert expected_count == len(filtered_j) - @pytest.mark.usefixtures("clear_log") @pytest.mark.parametrize( 'integration, expected_count', TESTDATA_4, From 5e9da1320018b45442ee1f94cf3d85afa7b84997 Mon Sep 17 00:00:00 2001 From: Henrik Brix Andersen Date: Wed, 24 Jan 2024 14:09:31 +0100 Subject: [PATCH 2956/3723] drivers: can: propagate CAN controller operation mode to CAN transceiver Propagate the current CAN controller operation mode to the CAN transceiver when enabling it. Some more advanced CAN transceivers, especially those supporting Partial Networking (CAN PN), require knowledge of the intended CAN operation mode (e.g. normal mode vs. listen-only mode). This commit simply prepares the CAN transceiver API for supporting such CAN transceivers, although no in-tree drivers require this information yet. Signed-off-by: Henrik Brix Andersen --- drivers/can/can_mcan.c | 2 +- drivers/can/can_mcp2515.c | 2 +- drivers/can/can_mcp251xfd.c | 2 +- drivers/can/can_mcux_flexcan.c | 2 +- drivers/can/can_nxp_s32_canxl.c | 2 +- drivers/can/can_rcar.c | 2 +- drivers/can/can_sja1000.c | 2 +- drivers/can/can_stm32_bxcan.c | 2 +- drivers/can/transceiver/can_transceiver_gpio.c | 4 +++- include/zephyr/drivers/can/transceiver.h | 8 +++++--- 10 files changed, 16 insertions(+), 12 deletions(-) diff --git a/drivers/can/can_mcan.c b/drivers/can/can_mcan.c index 8718e91d223..886f959b29a 100644 --- a/drivers/can/can_mcan.c +++ b/drivers/can/can_mcan.c @@ -276,7 +276,7 @@ int can_mcan_start(const struct device *dev) } if (config->common.phy != NULL) { - err = can_transceiver_enable(config->common.phy); + err = can_transceiver_enable(config->common.phy, data->common.mode); if (err != 0) { LOG_ERR("failed to enable CAN transceiver (err %d)", err); return err; diff --git a/drivers/can/can_mcp2515.c b/drivers/can/can_mcp2515.c index 126dee34c6f..750273fc715 100644 --- a/drivers/can/can_mcp2515.c +++ b/drivers/can/can_mcp2515.c @@ -435,7 +435,7 @@ static int mcp2515_start(const struct device *dev) } if (dev_cfg->common.phy != NULL) { - ret = can_transceiver_enable(dev_cfg->common.phy); + ret = can_transceiver_enable(dev_cfg->common.phy, dev_data->common.mode); if (ret != 0) { LOG_ERR("Failed to enable CAN transceiver [%d]", ret); return ret; diff --git a/drivers/can/can_mcp251xfd.c b/drivers/can/can_mcp251xfd.c index 490d660169a..a5b93b19c8f 100644 --- a/drivers/can/can_mcp251xfd.c +++ b/drivers/can/can_mcp251xfd.c @@ -1164,7 +1164,7 @@ static int mcp251xfd_start(const struct device *dev) mcp251xfd_reset_tx_fifos(dev, -ENETDOWN); if (dev_cfg->common.phy != NULL) { - ret = can_transceiver_enable(dev_cfg->common.phy); + ret = can_transceiver_enable(dev_cfg->common.phy, dev_data->common.mode); if (ret < 0) { LOG_ERR("Failed to enable CAN transceiver [%d]", ret); return ret; diff --git a/drivers/can/can_mcux_flexcan.c b/drivers/can/can_mcux_flexcan.c index 8d3eccac150..cf09ef23ec7 100644 --- a/drivers/can/can_mcux_flexcan.c +++ b/drivers/can/can_mcux_flexcan.c @@ -275,7 +275,7 @@ static int mcux_flexcan_start(const struct device *dev) } if (config->common.phy != NULL) { - err = can_transceiver_enable(config->common.phy); + err = can_transceiver_enable(config->common.phy, data->common.mode); if (err != 0) { LOG_ERR("failed to enable CAN transceiver (err %d)", err); return err; diff --git a/drivers/can/can_nxp_s32_canxl.c b/drivers/can/can_nxp_s32_canxl.c index f214b3924eb..2076429e279 100644 --- a/drivers/can/can_nxp_s32_canxl.c +++ b/drivers/can/can_nxp_s32_canxl.c @@ -218,7 +218,7 @@ static int can_nxp_s32_start(const struct device *dev) } if (config->common.phy != NULL) { - err = can_transceiver_enable(config->common.phy); + err = can_transceiver_enable(config->common.phy, data->common.mode); if (err != 0) { LOG_ERR("failed to enable CAN transceiver (err %d)", err); return err; diff --git a/drivers/can/can_rcar.c b/drivers/can/can_rcar.c index b988e748afc..55bbdb981d9 100644 --- a/drivers/can/can_rcar.c +++ b/drivers/can/can_rcar.c @@ -584,7 +584,7 @@ static int can_rcar_start(const struct device *dev) } if (config->common.phy != NULL) { - ret = can_transceiver_enable(config->common.phy); + ret = can_transceiver_enable(config->common.phy, data->common.mode); if (ret != 0) { LOG_ERR("failed to enable CAN transceiver (err %d)", ret); return ret; diff --git a/drivers/can/can_sja1000.c b/drivers/can/can_sja1000.c index d6c565f9ea2..c764251f628 100644 --- a/drivers/can/can_sja1000.c +++ b/drivers/can/can_sja1000.c @@ -155,7 +155,7 @@ int can_sja1000_start(const struct device *dev) } if (config->common.phy != NULL) { - err = can_transceiver_enable(config->common.phy); + err = can_transceiver_enable(config->common.phy, data->common.mode); if (err != 0) { LOG_ERR("failed to enable CAN transceiver (err %d)", err); return err; diff --git a/drivers/can/can_stm32_bxcan.c b/drivers/can/can_stm32_bxcan.c index 5f3d3a25c3b..8d2f3db3d8b 100644 --- a/drivers/can/can_stm32_bxcan.c +++ b/drivers/can/can_stm32_bxcan.c @@ -419,7 +419,7 @@ static int can_stm32_start(const struct device *dev) } if (cfg->common.phy != NULL) { - ret = can_transceiver_enable(cfg->common.phy); + ret = can_transceiver_enable(cfg->common.phy, data->common.mode); if (ret != 0) { LOG_ERR("failed to enable CAN transceiver (err %d)", ret); goto unlock; diff --git a/drivers/can/transceiver/can_transceiver_gpio.c b/drivers/can/transceiver/can_transceiver_gpio.c index 9f036599f31..e6aaacc8c34 100644 --- a/drivers/can/transceiver/can_transceiver_gpio.c +++ b/drivers/can/transceiver/can_transceiver_gpio.c @@ -58,8 +58,10 @@ static int can_transceiver_gpio_set_state(const struct device *dev, bool enabled return 0; } -static int can_transceiver_gpio_enable(const struct device *dev) +static int can_transceiver_gpio_enable(const struct device *dev, can_mode_t mode) { + ARG_UNUSED(mode); + return can_transceiver_gpio_set_state(dev, true); } diff --git a/include/zephyr/drivers/can/transceiver.h b/include/zephyr/drivers/can/transceiver.h index e4c6828983c..19c22e7733d 100644 --- a/include/zephyr/drivers/can/transceiver.h +++ b/include/zephyr/drivers/can/transceiver.h @@ -7,6 +7,7 @@ #ifndef ZEPHYR_INCLUDE_DRIVERS_CAN_TRANSCEIVER_H_ #define ZEPHYR_INCLUDE_DRIVERS_CAN_TRANSCEIVER_H_ +#include #include #ifdef __cplusplus @@ -30,7 +31,7 @@ extern "C" { * @brief Callback API upon enabling CAN transceiver * See @a can_transceiver_enable() for argument description */ -typedef int (*can_transceiver_enable_t)(const struct device *dev); +typedef int (*can_transceiver_enable_t)(const struct device *dev, can_mode_t mode); /** * @brief Callback API upon disabling CAN transceiver @@ -56,15 +57,16 @@ __subsystem struct can_transceiver_driver_api { * @see can_start() * * @param dev Pointer to the device structure for the driver instance. + * @param mode Operation mode. * @retval 0 If successful. * @retval -EIO General input/output error, failed to enable device. */ -static inline int can_transceiver_enable(const struct device *dev) +static inline int can_transceiver_enable(const struct device *dev, can_mode_t mode) { const struct can_transceiver_driver_api *api = (const struct can_transceiver_driver_api *)dev->api; - return api->enable(dev); + return api->enable(dev, mode); } /** From ffa3e415a0af31dba1a582157b6665c3098ddeb0 Mon Sep 17 00:00:00 2001 From: Henrik Brix Andersen Date: Wed, 24 Jan 2024 14:22:14 +0100 Subject: [PATCH 2957/3723] doc: releases: migration-guide: 3.6: list CAN transceiver API change Add a note about the addition of a can_mode_t argument to the can_transceiver_enable() API call. Signed-off-by: Henrik Brix Andersen --- doc/releases/migration-guide-3.6.rst | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/doc/releases/migration-guide-3.6.rst b/doc/releases/migration-guide-3.6.rst index af7c9c7c444..21740fe90fb 100644 --- a/doc/releases/migration-guide-3.6.rst +++ b/doc/releases/migration-guide-3.6.rst @@ -184,6 +184,11 @@ Device Drivers and Device Tree common accessor function. Out-of-tree CAN controller drivers need to be updated to no longer supply this callback. +* The CAN transceiver API function :c:func:`can_transceiver_enable` now takes a :c:type:`can_mode_t` + argument for propagating the CAN controller operational mode to the CAN transceiver. Out-of-tree + CAN controller and CAN transceiver drivers need to be updated to match this new API function + signature. + * The ``CAN_FILTER_FDF`` flag for filtering classic CAN/CAN FD frames was removed since no known CAN controllers implement support for this. Applications can still filter on classic CAN/CAN FD frames in their receive callback functions as needed. From 7d762050ba8ce64ba89f61a05ac5b71448d6fd75 Mon Sep 17 00:00:00 2001 From: Peter Mitsis Date: Wed, 24 Jan 2024 09:31:04 -0500 Subject: [PATCH 2958/3723] tests: smp_suspend: Add configurable delay Adds a configurable delay to the test threads. It exists to keep thread0 from hogging the scheduler's spin lock and giving threads on another core a better chance to obtain that lock and not starve. Signed-off-by: Peter Mitsis --- tests/kernel/smp_suspend/Kconfig | 10 ++++++++++ tests/kernel/smp_suspend/src/main.c | 15 ++++++++++++++- 2 files changed, 24 insertions(+), 1 deletion(-) create mode 100644 tests/kernel/smp_suspend/Kconfig diff --git a/tests/kernel/smp_suspend/Kconfig b/tests/kernel/smp_suspend/Kconfig new file mode 100644 index 00000000000..c84386a9f91 --- /dev/null +++ b/tests/kernel/smp_suspend/Kconfig @@ -0,0 +1,10 @@ +# Copyright (c) 2024 Intel Corporation +# SPDX-License-Identifier: Apache-2.0 + +mainmenu "SMP suspend test" + +source "Kconfig.zephyr" + +config SMP_TEST_RELAX + int "A delay to compensate for spinlock bias induced by arch_spin_relax" + default 16 diff --git a/tests/kernel/smp_suspend/src/main.c b/tests/kernel/smp_suspend/src/main.c index 0ed7111fae1..013fcd9d5a0 100644 --- a/tests/kernel/smp_suspend/src/main.c +++ b/tests/kernel/smp_suspend/src/main.c @@ -33,6 +33,19 @@ static void thread_entry(void *p1, void *p2, void *p3) thread_counter[self_index]++; + /* + * Contentious spinlocks embedded within tight loops (such as + * this one) have a CPU bias induced by arch_spin_relax(). We + * counteract this by introducing a configurable delay so that + * other threads have a chance to acquire the spinlock and + * prevent starvation. + */ + + for (volatile unsigned int i = 0; + i < CONFIG_SMP_TEST_RELAX; + i++) { + } + if (self_index != 0) { k_thread_suspend(k_current_get()); } @@ -73,7 +86,7 @@ ZTEST(smp_suspend_resume, test_smp_thread_suspend_resume_stress) for (i = 0; i < NUM_THREADS; i++) { zassert_false(counter[i] == thread_counter[i], - " -- Thread %u appears to be hung: %llu\n", + " -- Thread %u is starving: %llu\n", i, thread_counter[i]); counter[i] = thread_counter[i]; From 9f1e1b4c603e61305fdfd1b996ddb41bd41bd0cc Mon Sep 17 00:00:00 2001 From: Robert Lubos Date: Wed, 17 Jan 2024 16:38:53 +0100 Subject: [PATCH 2959/3723] tests: net: dhcpv4: Move DHCPv4 client tests to subdirectory Move DHCPv4 client tests to subdirectory, to make room for DHCPv4 server tests. Rename test project to dhcpv4_client to better reflect its purpose. Signed-off-by: Robert Lubos --- tests/net/dhcpv4/{ => client}/CMakeLists.txt | 2 +- tests/net/dhcpv4/{ => client}/prj.conf | 0 tests/net/dhcpv4/{ => client}/src/main.c | 0 tests/net/dhcpv4/{ => client}/testcase.yaml | 6 +++--- 4 files changed, 4 insertions(+), 4 deletions(-) rename tests/net/dhcpv4/{ => client}/CMakeLists.txt (92%) rename tests/net/dhcpv4/{ => client}/prj.conf (100%) rename tests/net/dhcpv4/{ => client}/src/main.c (100%) rename tests/net/dhcpv4/{ => client}/testcase.yaml (75%) diff --git a/tests/net/dhcpv4/CMakeLists.txt b/tests/net/dhcpv4/client/CMakeLists.txt similarity index 92% rename from tests/net/dhcpv4/CMakeLists.txt rename to tests/net/dhcpv4/client/CMakeLists.txt index a26e2495de5..fe86f122061 100644 --- a/tests/net/dhcpv4/CMakeLists.txt +++ b/tests/net/dhcpv4/client/CMakeLists.txt @@ -2,7 +2,7 @@ cmake_minimum_required(VERSION 3.20.0) find_package(Zephyr REQUIRED HINTS $ENV{ZEPHYR_BASE}) -project(dhcpv4) +project(dhcpv4_client) target_include_directories(app PRIVATE ${ZEPHYR_BASE}/subsys/net/ip) FILE(GLOB app_sources src/*.c) diff --git a/tests/net/dhcpv4/prj.conf b/tests/net/dhcpv4/client/prj.conf similarity index 100% rename from tests/net/dhcpv4/prj.conf rename to tests/net/dhcpv4/client/prj.conf diff --git a/tests/net/dhcpv4/src/main.c b/tests/net/dhcpv4/client/src/main.c similarity index 100% rename from tests/net/dhcpv4/src/main.c rename to tests/net/dhcpv4/client/src/main.c diff --git a/tests/net/dhcpv4/testcase.yaml b/tests/net/dhcpv4/client/testcase.yaml similarity index 75% rename from tests/net/dhcpv4/testcase.yaml rename to tests/net/dhcpv4/client/testcase.yaml index ba0dde95571..f0a476cfcf5 100644 --- a/tests/net/dhcpv4/testcase.yaml +++ b/tests/net/dhcpv4/client/testcase.yaml @@ -4,12 +4,12 @@ common: - net - dhcpv4 tests: - net.dhcp: + net.dhcpv4_client: extra_configs: - CONFIG_NET_TC_THREAD_COOPERATIVE=y - net.dhcp.preempt: + net.dhcpv4_client.preempt: extra_configs: - CONFIG_NET_TC_THREAD_PREEMPTIVE=y - net.dhcp.optioncbs: + net.dhcpv4_client.optioncbs: extra_configs: - CONFIG_NET_DHCPV4_OPTION_CALLBACKS=y From 154e415c36b1a2cb4c16db4c28b0575e46e5f43a Mon Sep 17 00:00:00 2001 From: Robert Lubos Date: Wed, 17 Jan 2024 16:48:53 +0100 Subject: [PATCH 2960/3723] tests: net: dhcpv4_server: Add test suite for DHCPv4 server library Add test suite covering DHCPv4 server library functionality. Signed-off-by: Robert Lubos --- tests/net/dhcpv4/server/CMakeLists.txt | 9 + tests/net/dhcpv4/server/prj.conf | 16 + tests/net/dhcpv4/server/src/main.c | 867 +++++++++++++++++++++++++ tests/net/dhcpv4/server/testcase.yaml | 14 + 4 files changed, 906 insertions(+) create mode 100644 tests/net/dhcpv4/server/CMakeLists.txt create mode 100644 tests/net/dhcpv4/server/prj.conf create mode 100644 tests/net/dhcpv4/server/src/main.c create mode 100644 tests/net/dhcpv4/server/testcase.yaml diff --git a/tests/net/dhcpv4/server/CMakeLists.txt b/tests/net/dhcpv4/server/CMakeLists.txt new file mode 100644 index 00000000000..dfa76bb411d --- /dev/null +++ b/tests/net/dhcpv4/server/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(dhcpv4_server) + +target_include_directories(app PRIVATE ${ZEPHYR_BASE}/subsys/net/ip) +target_sources(app PRIVATE src/main.c) diff --git a/tests/net/dhcpv4/server/prj.conf b/tests/net/dhcpv4/server/prj.conf new file mode 100644 index 00000000000..d29050e4baf --- /dev/null +++ b/tests/net/dhcpv4/server/prj.conf @@ -0,0 +1,16 @@ +CONFIG_NET_TEST=y +CONFIG_ZTEST=y + +CONFIG_ENTROPY_GENERATOR=y +CONFIG_TEST_RANDOM_GENERATOR=y + +CONFIG_NETWORKING=y +CONFIG_NET_L2_DUMMY=y +CONFIG_NET_IPV4=y +CONFIG_NET_IPV6=n +CONFIG_NET_UDP=y +CONFIG_NET_DHCPV4_SERVER=y + +# We need to set POSIX_API and use picolibc for eventfd to work +CONFIG_POSIX_API=y +CONFIG_PICOLIBC=y diff --git a/tests/net/dhcpv4/server/src/main.c b/tests/net/dhcpv4/server/src/main.c new file mode 100644 index 00000000000..c288fbedb31 --- /dev/null +++ b/tests/net/dhcpv4/server/src/main.c @@ -0,0 +1,867 @@ +/* + * Copyright (c) 2024 Nordic Semiconductor ASA + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include +#include +#include +#include +#include +#include + +#include "dhcpv4.h" +#include "ipv4.h" +#include "udp_internal.h" + +/* 00-00-5E-00-53-xx Documentation RFC 7042 */ +static uint8_t server_mac_addr[] = { 0x00, 0x00, 0x5E, 0x00, 0x53, 0x01 }; +static uint8_t client_mac_addr[] = { 0x00, 0x00, 0x5E, 0x00, 0x53, 0x02 }; + +static struct in_addr server_addr = { { { 192, 0, 2, 1 } } }; +static struct in_addr netmask = { { { 255, 255, 255, 0 } } }; +static struct in_addr test_base_addr = { { { 192, 0, 2, 10 } } }; + +/* Only to test Inform. */ +static struct in_addr client_addr_static = { { { 192, 0, 2, 2 } } }; + +typedef void (*test_dhcpv4_server_fn_t)(struct net_if *iface, + struct net_pkt *pkt); + + +static struct test_dhcpv4_server_ctx { + struct net_if *iface; + struct k_sem test_proceed; + struct net_pkt *pkt; + struct in_addr assigned_ip; + + /* Request params */ + const char *client_id; + int lease_time; + bool broadcast; +} test_ctx; + +struct test_lease_count { + int reserved; + int allocated; + int declined; +}; + +#define CLIENT_ID_1 "client1" +#define CLIENT_ID_2 "client2" +#define NO_LEASE_TIME -1 +#define TEST_XID 0x12345678 + +#define TEST_TIMEOUT K_MSEC(100) + +static void server_iface_init(struct net_if *iface) +{ + net_if_set_link_addr(iface, server_mac_addr, sizeof(server_mac_addr), + NET_LINK_ETHERNET); + + test_ctx.iface = iface; + + (void)net_if_ipv4_addr_add(iface, &server_addr, NET_ADDR_MANUAL, 0); + (void)net_if_ipv4_set_netmask(iface, &netmask); +} + +static int server_send(const struct device *dev, struct net_pkt *pkt) +{ + test_ctx.pkt = pkt; + net_pkt_ref(pkt); + + k_sem_give(&test_ctx.test_proceed); + + return 0; +} + +static struct dummy_api server_if_api = { + .iface_api.init = server_iface_init, + .send = server_send, +}; + +NET_DEVICE_INIT(server_iface, "server_iface", NULL, NULL, NULL, NULL, + CONFIG_KERNEL_INIT_PRIORITY_DEFAULT, &server_if_api, + DUMMY_L2, NET_L2_GET_CTX_TYPE(DUMMY_L2), NET_IPV4_MTU); + +static const uint8_t cookie[4] = { 0x63, 0x82, 0x53, 0x63 }; + +static void test_pkt_free(void) +{ + if (test_ctx.pkt != NULL) { + net_pkt_unref(test_ctx.pkt); + test_ctx.pkt = NULL; + } +} + +static void client_prepare_test_msg( + const struct in_addr *src_addr, const struct in_addr *dst_addr, + enum net_dhcpv4_msg_type type, const struct in_addr *server_id, + const struct in_addr *requested_ip, const struct in_addr *ciaddr) +{ + struct dhcp_msg msg = { 0 }; + uint8_t empty_buf[SIZE_OF_FILE] = { 0 }; + struct net_pkt *pkt; + + pkt = net_pkt_alloc_with_buffer(test_ctx.iface, NET_IPV4_MTU, AF_INET, + IPPROTO_UDP, K_FOREVER); + zassert_not_null(pkt, "Failed to allocate packet"); + + net_pkt_set_ipv4_ttl(pkt, 1); + + zassert_ok(net_ipv4_create(pkt, src_addr, dst_addr), + "Failed to create IPv4 header"); + zassert_ok(net_udp_create(pkt, htons(DHCPV4_CLIENT_PORT), + htons(DHCPV4_SERVER_PORT)), + "Failed to create UDP header"); + + msg.op = DHCPV4_MSG_BOOT_REQUEST; + msg.htype = HARDWARE_ETHERNET_TYPE; + msg.hlen = sizeof(client_mac_addr); + msg.xid = htonl(TEST_XID); + if (test_ctx.broadcast) { + msg.flags = htons(DHCPV4_MSG_BROADCAST); + } + + if (ciaddr) { + memcpy(msg.ciaddr, ciaddr, sizeof(*ciaddr)); + } else { + memset(msg.ciaddr, 0, sizeof(msg.ciaddr)); + + } + memset(msg.yiaddr, 0, sizeof(msg.ciaddr)); + memset(msg.siaddr, 0, sizeof(msg.siaddr)); + memset(msg.giaddr, 0, sizeof(msg.giaddr)); + memcpy(msg.chaddr, client_mac_addr, sizeof(client_mac_addr)); + + net_pkt_write(pkt, &msg, sizeof(msg)); + net_pkt_write(pkt, empty_buf, SIZE_OF_SNAME); + net_pkt_write(pkt, empty_buf, SIZE_OF_FILE); + net_pkt_write(pkt, cookie, SIZE_OF_MAGIC_COOKIE); + + /* Options */ + net_pkt_write_u8(pkt, DHCPV4_OPTIONS_MSG_TYPE); + net_pkt_write_u8(pkt, 1); + net_pkt_write_u8(pkt, type); + + if (requested_ip) { + net_pkt_write_u8(pkt, DHCPV4_OPTIONS_REQ_IPADDR); + net_pkt_write_u8(pkt, sizeof(*requested_ip)); + net_pkt_write(pkt, requested_ip, sizeof(*requested_ip)); + } + + if (server_id) { + net_pkt_write_u8(pkt, DHCPV4_OPTIONS_SERVER_ID); + net_pkt_write_u8(pkt, sizeof(*server_id)); + net_pkt_write(pkt, server_id, sizeof(*server_id)); + } + + net_pkt_write_u8(pkt, DHCPV4_OPTIONS_REQ_LIST); + net_pkt_write_u8(pkt, 1); + net_pkt_write_u8(pkt, DHCPV4_OPTIONS_SUBNET_MASK); + + if (test_ctx.client_id) { + net_pkt_write_u8(pkt, DHCPV4_OPTIONS_CLIENT_ID); + net_pkt_write_u8(pkt, strlen(test_ctx.client_id)); + net_pkt_write(pkt, test_ctx.client_id, strlen(test_ctx.client_id)); + } + + if (test_ctx.lease_time != NO_LEASE_TIME) { + net_pkt_write_u8(pkt, DHCPV4_OPTIONS_LEASE_TIME); + net_pkt_write_u8(pkt, 4); + net_pkt_write_be32(pkt, test_ctx.lease_time); + } + + net_pkt_write_u8(pkt, DHCPV4_OPTIONS_END); + + net_pkt_cursor_init(pkt); + net_ipv4_finalize(pkt, IPPROTO_UDP); + + zassert_ok(net_recv_data(test_ctx.iface, pkt), "Failed to receive data"); +} + +static void client_send_discover(void) +{ + int ret; + + client_prepare_test_msg( + net_ipv4_unspecified_address(), net_ipv4_broadcast_address(), + NET_DHCPV4_MSG_TYPE_DISCOVER, NULL, NULL, NULL); + + /* Wait for reply */ + ret = k_sem_take(&test_ctx.test_proceed, TEST_TIMEOUT); + zassert_ok(ret, "Exchange not completed in required time"); +} + +static void client_send_request_solicit(void) +{ + int ret; + + client_prepare_test_msg( + net_ipv4_unspecified_address(), net_ipv4_broadcast_address(), + NET_DHCPV4_MSG_TYPE_REQUEST, &server_addr, &test_ctx.assigned_ip, + NULL); + + /* Wait for reply */ + ret = k_sem_take(&test_ctx.test_proceed, TEST_TIMEOUT); + zassert_ok(ret, "Exchange not completed in required time"); +} + +static void client_send_request_renew(void) +{ + int ret; + + client_prepare_test_msg( + &test_ctx.assigned_ip, &server_addr, + NET_DHCPV4_MSG_TYPE_REQUEST, NULL, NULL, + &test_ctx.assigned_ip); + + /* Wait for reply */ + ret = k_sem_take(&test_ctx.test_proceed, TEST_TIMEOUT); + zassert_ok(ret, "Exchange not completed in required time"); +} + +static void client_send_request_rebind(void) +{ + int ret; + + client_prepare_test_msg( + &test_ctx.assigned_ip, net_ipv4_broadcast_address(), + NET_DHCPV4_MSG_TYPE_REQUEST, NULL, NULL, + &test_ctx.assigned_ip); + + /* Wait for reply */ + ret = k_sem_take(&test_ctx.test_proceed, TEST_TIMEOUT); + zassert_ok(ret, "Exchange not completed in required time"); +} + +static void client_send_release(void) +{ + client_prepare_test_msg( + &test_ctx.assigned_ip, &server_addr, + NET_DHCPV4_MSG_TYPE_RELEASE, &server_addr, NULL, + &test_ctx.assigned_ip); + + /* Small delay to let the DHCP server process the packet */ + k_msleep(10); +} + +static void client_send_decline(void) +{ + client_prepare_test_msg( + net_ipv4_unspecified_address(), net_ipv4_broadcast_address(), + NET_DHCPV4_MSG_TYPE_DECLINE, &server_addr, + &test_ctx.assigned_ip, NULL); + + /* Small delay to let the DHCP server process the packet */ + k_msleep(10); +} + +static void client_send_inform(void) +{ + int ret; + + client_prepare_test_msg( + &client_addr_static, net_ipv4_broadcast_address(), + NET_DHCPV4_MSG_TYPE_INFORM, NULL, NULL, &client_addr_static); + + /* Wait for reply */ + ret = k_sem_take(&test_ctx.test_proceed, TEST_TIMEOUT); + zassert_ok(ret, "Exchange not completed in required time"); +} + +static void lease_count_cb(struct net_if *iface, struct dhcpv4_addr_slot *lease, + void *user_data) +{ + struct test_lease_count *count = user_data; + + switch (lease->state) { + case DHCPV4_SERVER_ADDR_RESERVED: + count->reserved++; + break; + + case DHCPV4_SERVER_ADDR_ALLOCATED: + count->allocated++; + break; + + case DHCPV4_SERVER_ADDR_DECLINED: + count->declined++; + break; + + default: + break; + } +} + +static void test_get_lease_count(struct test_lease_count *count) +{ + int ret; + + memset(count, 0, sizeof(*count)); + + ret = net_dhcpv4_server_foreach_lease(test_ctx.iface, lease_count_cb, + count); + zassert_ok(ret, "Failed to obtain lease count"); +} + +static void verify_lease_count(int reserved, int allocated, int declined) +{ + struct test_lease_count count; + + test_get_lease_count(&count); + zassert_equal(count.reserved, reserved, + "Incorrect %s count, expected %d got %d", "reserved", + reserved, count.reserved); + zassert_equal(count.allocated, allocated, + "Incorrect %s count, expected %d got %d", "allocated", + allocated, count.allocated); + zassert_equal(count.declined, declined, + "Incorrect %s count, expected %d got %d", "declined", + declined, count.declined); +} + +static void get_reserved_cb(struct net_if *iface, + struct dhcpv4_addr_slot *lease, + void *user_data) +{ + struct in_addr *reserved = user_data; + + if (lease->state == DHCPV4_SERVER_ADDR_RESERVED) { + reserved->s_addr = lease->addr.s_addr; + } +} + +static void get_reserved_address(struct in_addr *reserved) +{ + int ret; + + ret = net_dhcpv4_server_foreach_lease(test_ctx.iface, + get_reserved_cb, + reserved); + zassert_ok(ret, "Failed to obtain reserved address"); +} + +static void client_get_lease(void) +{ + client_send_discover(); + verify_lease_count(1, 0, 0); + get_reserved_address(&test_ctx.assigned_ip); + test_pkt_free(); + + client_send_request_solicit(); + verify_lease_count(0, 1, 0); + test_pkt_free(); +} + +static void verify_no_option(struct net_pkt *pkt, uint8_t opt_type) +{ + struct net_pkt_cursor cursor; + + net_pkt_cursor_backup(pkt, &cursor); + + while (true) { + uint8_t type; + uint8_t len; + + if (net_pkt_read_u8(pkt, &type) < 0) { + break; + } + + if (net_pkt_read_u8(pkt, &len) < 0) { + break; + } + + zassert_not_equal(type, opt_type, + "Option %d should not be present", opt_type); + + (void)net_pkt_skip(pkt, len); + } + + net_pkt_cursor_restore(pkt, &cursor); +} + +static void verify_option(struct net_pkt *pkt, uint8_t opt_type, + void *optval, uint8_t optlen) +{ + struct net_pkt_cursor cursor; + + net_pkt_cursor_backup(pkt, &cursor); + + while (true) { + static uint8_t buf[255]; + uint8_t type; + uint8_t len; + + if (net_pkt_read_u8(pkt, &type) < 0) { + break; + } + + if (net_pkt_read_u8(pkt, &len) < 0) { + break; + } + + if (net_pkt_read(pkt, buf, len)) { + break; + } + + if (type == opt_type) { + zassert_equal(len, optlen, "Invalid option length"); + zassert_mem_equal(buf, optval, optlen, "Invalid option value"); + + net_pkt_cursor_restore(pkt, &cursor); + return; + } + } + + zassert_true(false, "Option %d not found", opt_type); +} + +static void verify_option_uint32(struct net_pkt *pkt, uint8_t opt_type, + uint32_t optval) +{ + optval = htonl(optval); + + verify_option(pkt, opt_type, &optval, sizeof(optval)); +} + +static void verify_option_uint8(struct net_pkt *pkt, uint8_t opt_type, + uint8_t optval) +{ + verify_option(pkt, opt_type, &optval, sizeof(optval)); +} + +static void verify_offer(bool broadcast) +{ + NET_PKT_DATA_ACCESS_DEFINE(ipv4_access, struct net_ipv4_hdr); + NET_PKT_DATA_ACCESS_DEFINE(udp_access, struct net_udp_hdr); + NET_PKT_DATA_ACCESS_DEFINE(dhcp_access, struct dhcp_msg); + uint8_t cookie_buf[SIZE_OF_MAGIC_COOKIE]; + struct net_pkt *pkt = test_ctx.pkt; + struct net_ipv4_hdr *ipv4_hdr; + struct net_udp_hdr *udp_hdr; + struct dhcp_msg *msg; + int ret; + + ipv4_hdr = (struct net_ipv4_hdr *)net_pkt_get_data(pkt, &ipv4_access); + zassert_not_null(ipv4_hdr, "Failed to access IPv4 header."); + net_pkt_acknowledge_data(pkt, &ipv4_access); + + udp_hdr = (struct net_udp_hdr *)net_pkt_get_data(pkt, &udp_access); + zassert_not_null(udp_hdr, "Failed to access UDP header."); + net_pkt_acknowledge_data(pkt, &udp_access); + + msg = (struct dhcp_msg *)net_pkt_get_data(pkt, &dhcp_access); + zassert_not_null(msg, "Failed to access DHCP data."); + net_pkt_acknowledge_data(pkt, &dhcp_access); + + /* IPv4 */ + zassert_mem_equal(ipv4_hdr->src, server_addr.s4_addr, + sizeof(struct in_addr), "Incorrect source address"); + if (broadcast) { + zassert_mem_equal(ipv4_hdr->dst, net_ipv4_broadcast_address(), + sizeof(struct in_addr), + "Destination should be broadcast"); + } else { + zassert_mem_equal(ipv4_hdr->dst, msg->yiaddr, + sizeof(struct in_addr), + "Destination should match address lease"); + } + zassert_equal(ipv4_hdr->proto, IPPROTO_UDP, "Wrong protocol"); + + /* UDP */ + zassert_equal(udp_hdr->src_port, htons(DHCPV4_SERVER_PORT), + "Wrong source port"); + zassert_equal(udp_hdr->dst_port, htons(DHCPV4_CLIENT_PORT), + "Wrong client port"); + + /* DHCPv4 */ + zassert_equal(msg->op, DHCPV4_MSG_BOOT_REPLY, "Incorrect %s value", "op"); + zassert_equal(msg->htype, HARDWARE_ETHERNET_TYPE, "Incorrect %s value", "htype"); + zassert_equal(msg->hlen, sizeof(client_mac_addr), "Incorrect %s value", "hlen"); + zassert_equal(msg->hops, 0, "Incorrect %s value", "hops"); + zassert_equal(msg->xid, htonl(TEST_XID), "Incorrect %s value", "xid"); + zassert_equal(msg->secs, 0, "Incorrect %s value", "secs"); + zassert_equal(sys_get_be32(msg->ciaddr), 0, "Incorrect %s value", "ciaddr"); + zassert_true((sys_get_be32(msg->yiaddr) >= + sys_get_be32(test_base_addr.s4_addr)) && + (sys_get_be32(msg->yiaddr) < + sys_get_be32(test_base_addr.s4_addr) + + CONFIG_NET_DHCPV4_SERVER_ADDR_COUNT), + "Assigned DHCP address outside of address pool"); + zassert_equal(sys_get_be32(msg->siaddr), 0, "Incorrect %s value", "siaddr"); + if (broadcast) { + zassert_equal(msg->flags, htons(DHCPV4_MSG_BROADCAST), + "Incorrect %s value", "flags"); + } else { + zassert_equal(msg->flags, 0, "Incorrect %s value", "flags"); + } + zassert_equal(sys_get_be32(msg->giaddr), 0, "Incorrect %s value", "giaddr"); + zassert_mem_equal(msg->chaddr, client_mac_addr, sizeof(client_mac_addr), + "Incorrect %s value", "chaddr"); + + memcpy(&test_ctx.assigned_ip, msg->yiaddr, sizeof(struct in_addr)); + + ret = net_pkt_skip(pkt, SIZE_OF_SNAME + SIZE_OF_FILE); + zassert_ok(ret, "DHCP Offer too short"); + + ret = net_pkt_read(pkt, cookie_buf, SIZE_OF_MAGIC_COOKIE); + zassert_ok(ret, "DHCP Offer too short"); + zassert_mem_equal(cookie_buf, cookie, SIZE_OF_MAGIC_COOKIE, + "Incorrect cookie value"); + + verify_option_uint32(pkt, DHCPV4_OPTIONS_LEASE_TIME, + CONFIG_NET_DHCPV4_SERVER_ADDR_LEASE_TIME); + verify_option_uint8(pkt, DHCPV4_OPTIONS_MSG_TYPE, + NET_DHCPV4_MSG_TYPE_OFFER); + verify_option(pkt, DHCPV4_OPTIONS_SERVER_ID, server_addr.s4_addr, + sizeof(struct in_addr)); + verify_option(pkt, DHCPV4_OPTIONS_SUBNET_MASK, netmask.s4_addr, + sizeof(struct in_addr)); + verify_no_option(pkt, DHCPV4_OPTIONS_REQ_IPADDR); + verify_no_option(pkt, DHCPV4_OPTIONS_REQ_LIST); + verify_no_option(pkt, DHCPV4_OPTIONS_CLIENT_ID); +} + +static void reserved_address_cb(struct net_if *iface, + struct dhcpv4_addr_slot *lease, + void *user_data) +{ + struct in_addr *reserved = user_data; + + zassert_equal(lease->state, DHCPV4_SERVER_ADDR_RESERVED, + "Wrong lease state"); + zassert_equal(reserved->s_addr, lease->addr.s_addr, + "Reserved wrong address"); +} + +static void verify_reserved_address(struct in_addr *reserved) +{ + int ret; + + ret = net_dhcpv4_server_foreach_lease(test_ctx.iface, + reserved_address_cb, + reserved); + zassert_ok(ret, "Failed to verify reserved address"); +} + +/* Verify that the DHCP server replies with Offer for a Discover message. */ +ZTEST(dhcpv4_server_tests, test_discover) +{ + client_send_discover(); + verify_offer(false); + test_pkt_free(); + + verify_lease_count(1, 0, 0); + verify_reserved_address(&test_ctx.assigned_ip); +} + +/* Verify that the DHCP server offers the same IP address for repeated Discover + * message. + */ +ZTEST(dhcpv4_server_tests, test_discover_repeat) +{ + struct in_addr first_addr; + + client_send_discover(); + verify_offer(false); + test_pkt_free(); + + first_addr = test_ctx.assigned_ip; + verify_lease_count(1, 0, 0); + + /* Repeat Discover with the same client ID */ + client_send_discover(); + verify_offer(false); + test_pkt_free(); + + verify_lease_count(1, 0, 0); + zassert_equal(first_addr.s_addr, test_ctx.assigned_ip.s_addr, + "Received different address for the same client ID"); + + /* Send Discover with a different client ID */ + test_ctx.client_id = CLIENT_ID_2; + + client_send_discover(); + verify_offer(false); + test_pkt_free(); + + verify_lease_count(2, 0, 0); + zassert_not_equal(first_addr.s_addr, test_ctx.assigned_ip.s_addr, + "Received same address for the different client ID"); +} + +/* Verify that the DHCP server replies to broadcast address if broadcast flag + * is set. + */ +ZTEST(dhcpv4_server_tests, test_discover_with_broadcast) +{ + test_ctx.broadcast = true; + + client_send_discover(); + verify_offer(true); + verify_lease_count(1, 0, 0); + test_pkt_free(); +} + +static void verify_ack(bool inform, bool renew) +{ + NET_PKT_DATA_ACCESS_DEFINE(ipv4_access, struct net_ipv4_hdr); + NET_PKT_DATA_ACCESS_DEFINE(udp_access, struct net_udp_hdr); + NET_PKT_DATA_ACCESS_DEFINE(dhcp_access, struct dhcp_msg); + uint8_t cookie_buf[SIZE_OF_MAGIC_COOKIE]; + struct net_pkt *pkt = test_ctx.pkt; + struct net_ipv4_hdr *ipv4_hdr; + struct net_udp_hdr *udp_hdr; + struct dhcp_msg *msg; + int ret; + + ipv4_hdr = (struct net_ipv4_hdr *)net_pkt_get_data(pkt, &ipv4_access); + zassert_not_null(ipv4_hdr, "Failed to access IPv4 header."); + net_pkt_acknowledge_data(pkt, &ipv4_access); + + udp_hdr = (struct net_udp_hdr *)net_pkt_get_data(pkt, &udp_access); + zassert_not_null(udp_hdr, "Failed to access UDP header."); + net_pkt_acknowledge_data(pkt, &udp_access); + + msg = (struct dhcp_msg *)net_pkt_get_data(pkt, &dhcp_access); + zassert_not_null(msg, "Failed to access DHCP data."); + net_pkt_acknowledge_data(pkt, &dhcp_access); + + /* IPv4 */ + zassert_mem_equal(ipv4_hdr->src, server_addr.s4_addr, + sizeof(struct in_addr), "Incorrect source address"); + if (inform || renew) { + zassert_mem_equal(ipv4_hdr->dst, msg->ciaddr, sizeof(struct in_addr), + "Destination should match client address"); + } else { + zassert_mem_equal(ipv4_hdr->dst, msg->yiaddr, sizeof(struct in_addr), + "Destination should match client address"); + } + + zassert_equal(ipv4_hdr->proto, IPPROTO_UDP, "Wrong protocol"); + + /* UDP */ + zassert_equal(udp_hdr->src_port, htons(DHCPV4_SERVER_PORT), + "Wrong source port"); + zassert_equal(udp_hdr->dst_port, htons(DHCPV4_CLIENT_PORT), + "Wrong client port"); + + /* DHCPv4 */ + zassert_equal(msg->op, DHCPV4_MSG_BOOT_REPLY, "Incorrect %s value", "op"); + zassert_equal(msg->htype, HARDWARE_ETHERNET_TYPE, "Incorrect %s value", "htype"); + zassert_equal(msg->hlen, sizeof(client_mac_addr), "Incorrect %s value", "hlen"); + zassert_equal(msg->hops, 0, "Incorrect %s value", "hops"); + zassert_equal(msg->xid, htonl(TEST_XID), "Incorrect %s value", "xid"); + zassert_equal(msg->secs, 0, "Incorrect %s value", "secs"); + + if (inform) { + zassert_mem_equal(msg->ciaddr, client_addr_static.s4_addr, + sizeof(struct in_addr), + "Incorrect %s value", "ciaddr"); + } else if (renew) { + zassert_mem_equal(msg->ciaddr, test_ctx.assigned_ip.s4_addr, + sizeof(struct in_addr), + "Incorrect %s value", "ciaddr"); + } else { + zassert_equal(sys_get_be32(msg->ciaddr), 0, "Incorrect %s value", "ciaddr"); + } + + if (inform) { + zassert_equal(sys_get_be32(msg->yiaddr), 0, "Incorrect %s value", "yiaddr"); + } else { + zassert_mem_equal(msg->yiaddr, test_ctx.assigned_ip.s4_addr, + sizeof(struct in_addr), "Incorrect %s value", "yiaddr"); + } + + zassert_equal(sys_get_be32(msg->siaddr), 0, "Incorrect %s value", "siaddr"); + zassert_equal(msg->flags, 0, "Incorrect %s value", "flags"); + zassert_equal(sys_get_be32(msg->giaddr), 0, "Incorrect %s value", "giaddr"); + zassert_mem_equal(msg->chaddr, client_mac_addr, sizeof(client_mac_addr), + "Incorrect %s value", "chaddr"); + + if (!inform) { + memcpy(&test_ctx.assigned_ip, msg->yiaddr, sizeof(struct in_addr)); + } + + ret = net_pkt_skip(pkt, SIZE_OF_SNAME + SIZE_OF_FILE); + zassert_ok(ret, "DHCP Offer too short"); + + ret = net_pkt_read(pkt, cookie_buf, SIZE_OF_MAGIC_COOKIE); + zassert_ok(ret, "DHCP Offer too short"); + zassert_mem_equal(cookie_buf, cookie, SIZE_OF_MAGIC_COOKIE, + "Incorrect cookie value"); + + if (inform) { + verify_no_option(pkt, DHCPV4_OPTIONS_LEASE_TIME); + } else { + verify_option_uint32(pkt, DHCPV4_OPTIONS_LEASE_TIME, + CONFIG_NET_DHCPV4_SERVER_ADDR_LEASE_TIME); + } + + verify_option_uint8(pkt, DHCPV4_OPTIONS_MSG_TYPE, + NET_DHCPV4_MSG_TYPE_ACK); + verify_option(pkt, DHCPV4_OPTIONS_SERVER_ID, server_addr.s4_addr, + sizeof(struct in_addr)); + verify_option(pkt, DHCPV4_OPTIONS_SUBNET_MASK, netmask.s4_addr, + sizeof(struct in_addr)); + verify_no_option(pkt, DHCPV4_OPTIONS_REQ_IPADDR); + verify_no_option(pkt, DHCPV4_OPTIONS_REQ_LIST); + verify_no_option(pkt, DHCPV4_OPTIONS_CLIENT_ID); +} + +static void allocated_address_cb(struct net_if *iface, + struct dhcpv4_addr_slot *lease, + void *user_data) +{ + struct in_addr *allocated = user_data; + + zassert_equal(lease->state, DHCPV4_SERVER_ADDR_ALLOCATED, + "Wrong lease state"); + zassert_equal(allocated->s_addr, lease->addr.s_addr, + "Reserved wrong address"); +} + +static void verify_allocated_address(struct in_addr *allocated) +{ + int ret; + + ret = net_dhcpv4_server_foreach_lease(test_ctx.iface, + allocated_address_cb, + allocated); + zassert_ok(ret, "Failed to verify allocated address"); +} + +/* Verify that the DHCP server replies with ACK for a Request message. */ +ZTEST(dhcpv4_server_tests, test_request) +{ + client_send_discover(); + verify_offer(false); + verify_lease_count(1, 0, 0); + test_pkt_free(); + + client_send_request_solicit(); + verify_ack(false, false); + verify_lease_count(0, 1, 0); + verify_allocated_address(&test_ctx.assigned_ip); + test_pkt_free(); +} + +/* Verify that the DHCP server replies with ACK for a Request message + * (renewing). + */ +ZTEST(dhcpv4_server_tests, test_renew) +{ + client_get_lease(); + + client_send_request_renew(); + verify_ack(false, true); + verify_lease_count(0, 1, 0); + test_pkt_free(); +} + +/* Verify that the DHCP server replies with ACK for a Request message + * (rebinding). + */ +ZTEST(dhcpv4_server_tests, test_rebind) +{ + client_get_lease(); + + client_send_request_rebind(); + verify_ack(false, true); + verify_lease_count(0, 1, 0); + test_pkt_free(); +} + +/* Verify that the DHCP server lease expires after the lease timeout. */ +ZTEST(dhcpv4_server_tests, test_expiry) +{ + test_ctx.lease_time = 1; + client_get_lease(); + + /* Add extra 10ms to avoid race. */ + k_msleep(1000 + 10); + verify_lease_count(0, 0, 0); +} + +/* Verify that the DHCP server releases the lease after receiving Release + * message. + */ +ZTEST(dhcpv4_server_tests, test_release) +{ + client_get_lease(); + + client_send_release(); + verify_lease_count(0, 0, 0); +} + +static void declined_address_cb(struct net_if *iface, + struct dhcpv4_addr_slot *lease, + void *user_data) +{ + struct in_addr *declined = user_data; + + zassert_equal(lease->state, DHCPV4_SERVER_ADDR_DECLINED, + "Wrong lease state"); + zassert_equal(declined->s_addr, lease->addr.s_addr, + "Declined wrong address"); +} + +static void verify_declined_address(struct in_addr *declined) +{ + int ret; + + ret = net_dhcpv4_server_foreach_lease(test_ctx.iface, + declined_address_cb, + declined); + zassert_ok(ret, "Failed to verify declined address"); +} + +/* Verify that the DHCP server blocks the address after receiving Decline + * message. + */ +ZTEST(dhcpv4_server_tests, test_decline) +{ + client_get_lease(); + verify_lease_count(0, 1, 0); + + client_send_decline(); + verify_lease_count(0, 0, 1); + verify_declined_address(&test_ctx.assigned_ip); +} + +/* Verify that the DHCP server replies with ACK for a Inform message, w/o + * address assignment. + */ +ZTEST(dhcpv4_server_tests, test_inform) +{ + client_send_inform(); + verify_ack(true, false); + verify_lease_count(0, 0, 0); +} + +static void dhcpv4_server_tests_before(void *fixture) +{ + ARG_UNUSED(fixture); + + k_sem_init(&test_ctx.test_proceed, 0, 1); + test_ctx.client_id = CLIENT_ID_1; + test_ctx.broadcast = false; + test_ctx.pkt = NULL; + test_ctx.lease_time = NO_LEASE_TIME; + memset(&test_ctx.assigned_ip, 0, sizeof(test_ctx.assigned_ip)); + + net_dhcpv4_server_start(test_ctx.iface, &test_base_addr); +} + +static void dhcpv4_server_tests_after(void *fixture) +{ + ARG_UNUSED(fixture); + + test_pkt_free(); + + net_dhcpv4_server_stop(test_ctx.iface); +} + +ZTEST_SUITE(dhcpv4_server_tests, NULL, NULL, dhcpv4_server_tests_before, + dhcpv4_server_tests_after, NULL); diff --git a/tests/net/dhcpv4/server/testcase.yaml b/tests/net/dhcpv4/server/testcase.yaml new file mode 100644 index 00000000000..13919e42b13 --- /dev/null +++ b/tests/net/dhcpv4/server/testcase.yaml @@ -0,0 +1,14 @@ +common: + depends_on: netif + tags: net dhcpv4 + # eventfd API does not work with native_posix so exclude it here + platform_exclude: + - native_posix + - native_posix_64 +tests: + net.dhcpv4_server: + extra_configs: + - CONFIG_NET_TC_THREAD_COOPERATIVE=y + net.dhcpv4_server.preempt: + extra_configs: + - CONFIG_NET_TC_THREAD_PREEMPTIVE=y From 29b0cd4278f0ec4887d23425daa2f45cbba0ba07 Mon Sep 17 00:00:00 2001 From: Francois Ramu Date: Fri, 26 Jan 2024 10:35:57 +0100 Subject: [PATCH 2961/3723] drivers: clock_control: stm32h5 driver input vco range Set the correct VCO input range for the PLL frequency with each bit PLL1RGE of the PLL1CFGR register This get_vco_input_range is similar to the stm32h7 one. Signed-off-by: Francois Ramu --- drivers/clock_control/clock_stm32_ll_h5.c | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/drivers/clock_control/clock_stm32_ll_h5.c b/drivers/clock_control/clock_stm32_ll_h5.c index a5a6a055f44..f6f0bbb0033 100644 --- a/drivers/clock_control/clock_stm32_ll_h5.c +++ b/drivers/clock_control/clock_stm32_ll_h5.c @@ -348,7 +348,11 @@ static int get_vco_input_range(uint32_t m_div, uint32_t *range, size_t pll_id) vco_freq = get_pllsrc_frequency(pll_id) / m_div; - if (MHZ(4) <= vco_freq && vco_freq <= MHZ(8)) { + if (MHZ(1) <= vco_freq && vco_freq <= MHZ(2)) { + *range = LL_RCC_PLLINPUTRANGE_1_2; + } else if (MHZ(2) < vco_freq && vco_freq <= MHZ(4)) { + *range = LL_RCC_PLLINPUTRANGE_2_4; + } else if (MHZ(4) < vco_freq && vco_freq <= MHZ(8)) { *range = LL_RCC_PLLINPUTRANGE_4_8; } else if (MHZ(8) < vco_freq && vco_freq <= MHZ(16)) { *range = LL_RCC_PLLINPUTRANGE_8_16; From d75b44327a228c91e49f737bd0de1656a5bc1849 Mon Sep 17 00:00:00 2001 From: Jonathan Rico Date: Thu, 25 Jan 2024 13:03:20 +0100 Subject: [PATCH 2962/3723] Bluetooth: ATT: don't callback if bearer is invalid If an att buf is destroyed during bearer teardown, we want to avoid using and passing invalid references to the application. Double-check that the current bearer, the ATT object and the ACL conn objects it is attached to are not NULL before proceeding. Signed-off-by: Jonathan Rico --- subsys/bluetooth/host/att.c | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/subsys/bluetooth/host/att.c b/subsys/bluetooth/host/att.c index 6e16f98a0e6..23e0b7eff55 100644 --- a/subsys/bluetooth/host/att.c +++ b/subsys/bluetooth/host/att.c @@ -595,6 +595,13 @@ static void att_on_sent_cb(struct bt_att_tx_meta_data *meta) LOG_DBG("opcode 0x%x", meta->opcode); + if (!meta->att_chan || + !meta->att_chan->att || + !meta->att_chan->att->conn) { + LOG_DBG("Bearer not connected, dropping ATT cb"); + return; + } + if (meta->err) { LOG_ERR("Got err %d, not calling ATT cb", meta->err); return; From 339173051280e6dba1730c07512011eacaa44d9e Mon Sep 17 00:00:00 2001 From: Sateesh Kotapati Date: Thu, 25 Jan 2024 11:24:47 +0530 Subject: [PATCH 2963/3723] gecko: Update BG22, BG27 and MG24 Device files | Update to GSDK 4.4.0 Update the EFR32BG22, BG27 and MG24 device files inside gecko/Device/SiliconLabs/ from gecko_sdk to align the codebase of hal_silabs with gecko_sdk 4.4.0. Signed-off-by: Sateesh Kotapati --- west.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/west.yml b/west.yml index 7a25afd58da..2e437c0b7bb 100644 --- a/west.yml +++ b/west.yml @@ -219,7 +219,7 @@ manifest: groups: - hal - name: hal_silabs - revision: 2ea874714edf5ce76b7b5fd19e7fa83507e83cc2 + revision: 20024164aa2a79c186aedc721cf51d667eecb35a path: modules/hal/silabs groups: - hal From 0ac5835c597b75bc27666adc5883d5e759866d0b Mon Sep 17 00:00:00 2001 From: Jordan Yates Date: Thu, 25 Jan 2024 14:45:34 +1000 Subject: [PATCH 2964/3723] doc: release-notes: document `spi_nor` sleep changes Document the changes to sleeping in `spi_nor_wait_until_ready`. Signed-off-by: Jordan Yates --- doc/releases/release-notes-3.6.rst | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/doc/releases/release-notes-3.6.rst b/doc/releases/release-notes-3.6.rst index 95cfd3e9824..3065fd0be4f 100644 --- a/doc/releases/release-notes-3.6.rst +++ b/doc/releases/release-notes-3.6.rst @@ -182,6 +182,10 @@ Drivers and Sensors * Flash + * ``spi_nor`` driver now sleeps between polls in ``spi_nor_wait_until_ready``. If this is not + desired (For example due to ROM constraints in a bootloader), + :kconfig:option:`CONFIG_SPI_NOR_SLEEP_WHILE_WAITING_UNTIL_READY` can be disabled. + * GPIO * Renesas R-Car GPIO driver now supports Gen4 SoCs From 2deb3d5b0c5b744638102fb50c5d2382482ef1ec Mon Sep 17 00:00:00 2001 From: Seppo Takalo Date: Thu, 25 Jan 2024 16:32:18 +0200 Subject: [PATCH 2965/3723] samples: lwm2m: Set default bootstrap URI Don't rely on just port number to select a bootstrap server. Use full URI. Signed-off-by: Seppo Takalo --- samples/net/lwm2m_client/Kconfig | 3 ++- samples/net/lwm2m_client/overlay-bootstrap.conf | 1 - 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/samples/net/lwm2m_client/Kconfig b/samples/net/lwm2m_client/Kconfig index 22fab04bbef..2037d281ce0 100644 --- a/samples/net/lwm2m_client/Kconfig +++ b/samples/net/lwm2m_client/Kconfig @@ -29,8 +29,9 @@ endif config LWM2M_APP_SERVER string "LwM2M server address" - default "coaps://192.0.2.2:5684" if LWM2M_DTLS_SUPPORT default "coap://192.0.2.2:5683" if !LWM2M_DTLS_SUPPORT + default "coaps://192.0.2.2:5684" if (LWM2M_DTLS_SUPPORT && !LWM2M_RD_CLIENT_SUPPORT_BOOTSTRAP) + default "coaps://192.0.2.2:5784" if (LWM2M_DTLS_SUPPORT && LWM2M_RD_CLIENT_SUPPORT_BOOTSTRAP) help LwM2M server address. Write as a full URI including optional port number. Only accepted protocols are "coap://" and "coaps://" diff --git a/samples/net/lwm2m_client/overlay-bootstrap.conf b/samples/net/lwm2m_client/overlay-bootstrap.conf index 68308bbd22b..5993329cb1b 100644 --- a/samples/net/lwm2m_client/overlay-bootstrap.conf +++ b/samples/net/lwm2m_client/overlay-bootstrap.conf @@ -1,2 +1 @@ -CONFIG_LWM2M_PEER_PORT=5783 CONFIG_LWM2M_RD_CLIENT_SUPPORT_BOOTSTRAP=y From 53705c062e4e50a634ffbb4a727352fedf831dfa Mon Sep 17 00:00:00 2001 From: Seppo Takalo Date: Thu, 25 Jan 2024 16:34:21 +0200 Subject: [PATCH 2966/3723] samples: lwm2m: Clarify DTLS settings Clarify some documentation regarding DTLS settings. Set default QUEUE uptime to 30s, which would be same as most cellular networks use, and nRF SDK use. Signed-off-by: Seppo Takalo --- samples/net/lwm2m_client/overlay-queue.conf | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/samples/net/lwm2m_client/overlay-queue.conf b/samples/net/lwm2m_client/overlay-queue.conf index 946c0fbab67..2f2ee2aceaa 100644 --- a/samples/net/lwm2m_client/overlay-queue.conf +++ b/samples/net/lwm2m_client/overlay-queue.conf @@ -1,5 +1,12 @@ CONFIG_LWM2M_QUEUE_MODE_ENABLED=y -CONFIG_LWM2M_QUEUE_MODE_UPTIME=20 + +# Listen for incoming CoAP messages for 30 seconds after last TX. +# This is a common NAT timeout for cellular networks. +CONFIG_LWM2M_QUEUE_MODE_UPTIME=30 + +# When DTLS Connection Identifier is used, we can keep socket open +# and just stop polling while in idle state (QUEUE_RX_OFF). +# If the server does not support DTLS-CID, use CONFIG_LWM2M_RD_CLIENT_STOP_POLLING_AT_IDLE=y # Default lifetime is 1 day From 992936300bf684806ca02022399224a2030ad4e9 Mon Sep 17 00:00:00 2001 From: Seppo Takalo Date: Thu, 25 Jan 2024 16:35:29 +0200 Subject: [PATCH 2967/3723] net: lwm2m: Use CID_SUPPORTED instead of CID_ENABLED When ENABLED flag is used, we generate 32 byte DTLS Connection Identifier and include that in our DTLS Client HELO. This has no benefit as client only has one connection toward the server, it does not need any identification. When SUPPORTED flag is used, we just include zero length Connection Identifier in the handshake, which tell server that we support Connection Identifier and server can generate one for it. We then use the CID in the packets that we send towards server, but response packets don't contain any CID. This gives all the benefit of CID as server is able to identify us even when NAT mapping have changed. Signed-off-by: Seppo Takalo --- subsys/net/lib/lwm2m/lwm2m_engine.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/subsys/net/lib/lwm2m/lwm2m_engine.c b/subsys/net/lib/lwm2m/lwm2m_engine.c index ba408c1de8e..061a3d42346 100644 --- a/subsys/net/lib/lwm2m/lwm2m_engine.c +++ b/subsys/net/lib/lwm2m/lwm2m_engine.c @@ -1060,7 +1060,7 @@ int lwm2m_set_default_sockopt(struct lwm2m_ctx *ctx) } if (IS_ENABLED(CONFIG_LWM2M_DTLS_CID)) { /* Enable CID */ - int cid = TLS_DTLS_CID_ENABLED; + int cid = TLS_DTLS_CID_SUPPORTED; ret = zsock_setsockopt(ctx->sock_fd, SOL_TLS, TLS_DTLS_CID, &cid, sizeof(cid)); From cca78041f802499efd2715df90f86cd07656b3f3 Mon Sep 17 00:00:00 2001 From: Grzegorz Chwierut Date: Fri, 26 Jan 2024 17:29:55 +0100 Subject: [PATCH 2968/3723] twister: pytest: Fix failing tests of mcumgr fixture. Updated tests of mcumgr fixture in pytest-twister-harness plugin. Signed-off-by: Grzegorz Chwierut --- .../src/twister_harness/helpers/mcumgr.py | 4 ++-- .../tests/fixtures/mcumgr_fixture_test.py | 13 ++++++++----- 2 files changed, 10 insertions(+), 7 deletions(-) diff --git a/scripts/pylib/pytest-twister-harness/src/twister_harness/helpers/mcumgr.py b/scripts/pylib/pytest-twister-harness/src/twister_harness/helpers/mcumgr.py index c1cb109524e..038c16a4fc8 100755 --- a/scripts/pylib/pytest-twister-harness/src/twister_harness/helpers/mcumgr.py +++ b/scripts/pylib/pytest-twister-harness/src/twister_harness/helpers/mcumgr.py @@ -56,7 +56,7 @@ def reset_device(self): def image_upload(self, image: Path | str, slot: int | None = None, timeout: int = 30): command = f'-t {timeout} image upload {image}' - if slot: + if slot is not None: command += f' -e -n {slot}' self.run_command(command) logger.info('Image successfully uploaded') @@ -98,7 +98,7 @@ def get_hash_to_test(self) -> str: raise MCUmgrException('No not active image found') def get_hash_to_confirm(self): - image_list = self.mcumgr.get_image_list() + image_list = self.get_image_list() for image in image_list: if 'confirmed' not in image.flags: return image.hash diff --git a/scripts/pylib/pytest-twister-harness/tests/fixtures/mcumgr_fixture_test.py b/scripts/pylib/pytest-twister-harness/tests/fixtures/mcumgr_fixture_test.py index f336311143a..e8aaabe8fe1 100644 --- a/scripts/pylib/pytest-twister-harness/tests/fixtures/mcumgr_fixture_test.py +++ b/scripts/pylib/pytest-twister-harness/tests/fixtures/mcumgr_fixture_test.py @@ -27,6 +27,9 @@ def test_if_mcumgr_fixture_generate_proper_command( mcumgr.image_upload('/path/to/image', timeout=100) patched_run_command.assert_called_with('-t 100 image upload /path/to/image') + mcumgr.image_upload('/path/to/image', slot=2, timeout=100) + patched_run_command.assert_called_with('-t 100 image upload /path/to/image -e -n 2') + mcumgr.image_test(hash='ABCD') patched_run_command.assert_called_with('image test ABCD') @@ -55,12 +58,12 @@ def test_if_mcumgr_fixture_parse_image_list(mcumgr: MCUmgr) -> None: image=0 slot=0 version: 0.0.0 bootable: true - flags: + flags: active confirmed hash: 0000 image=0 slot=1 version: 1.1.1 bootable: true - flags: pending + flags: hash: 1111 Split status: N/A (0) """) @@ -69,12 +72,12 @@ def test_if_mcumgr_fixture_parse_image_list(mcumgr: MCUmgr) -> None: assert image_list[0].image == 0 assert image_list[0].slot == 0 assert image_list[0].version == '0.0.0' - assert image_list[0].flags == '' + assert image_list[0].flags == 'active confirmed' assert image_list[0].hash == '0000' assert image_list[1].image == 0 assert image_list[1].slot == 1 assert image_list[1].version == '1.1.1' - assert image_list[1].flags == 'pending' + assert image_list[1].flags == '' assert image_list[1].hash == '1111' # take second hash to test @@ -83,4 +86,4 @@ def test_if_mcumgr_fixture_parse_image_list(mcumgr: MCUmgr) -> None: # take first hash to confirm mcumgr.image_confirm() - mcumgr.run_command.assert_called_with('image confirm 0000') + mcumgr.run_command.assert_called_with('image confirm 1111') From a1d0764922a0626b763904442259ed61b00f8f72 Mon Sep 17 00:00:00 2001 From: Jukka Rissanen Date: Fri, 26 Jan 2024 14:02:01 +0200 Subject: [PATCH 2969/3723] net: wifi: Make sure scan band string is null terminated Make sure that scan band string is properly terminated when parsing user supplied string. Fixes: #67944 Coverity-CID: 342930 Signed-off-by: Jukka Rissanen --- subsys/net/l2/wifi/wifi_utils.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/subsys/net/l2/wifi/wifi_utils.c b/subsys/net/l2/wifi/wifi_utils.c index 01c4bf1ea81..204872cc9b1 100644 --- a/subsys/net/l2/wifi/wifi_utils.c +++ b/subsys/net/l2/wifi/wifi_utils.c @@ -241,7 +241,8 @@ int wifi_utils_parse_scan_bands(char *scan_bands_str, uint8_t *band_map) return -EINVAL; } - strncpy(parse_str, scan_bands_str, sizeof(parse_str)); + strncpy(parse_str, scan_bands_str, sizeof(parse_str) - 1); + parse_str[sizeof(parse_str) - 1] = '\0'; band_str = strtok_r(parse_str, ",", &ctx); From 5808018b05f9ffd055e70e8a0b615857d413ee67 Mon Sep 17 00:00:00 2001 From: Daniel DeGrasse Date: Thu, 25 Jan 2024 15:55:14 -0600 Subject: [PATCH 2970/3723] drivers: i2s: i2s_mcux_flexcomm: Guard use of I2S_EnableSecondaryChannel Guard use of I2S_EnableSecondaryChannel behind the SDK feature macro that determines if this support is available, since when this macro is not defined the SDK function is not implemented. Fixes #68136 Signed-off-by: Daniel DeGrasse --- drivers/i2s/i2s_mcux_flexcomm.c | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/drivers/i2s/i2s_mcux_flexcomm.c b/drivers/i2s/i2s_mcux_flexcomm.c index ab61097c023..6e966edd4a1 100644 --- a/drivers/i2s/i2s_mcux_flexcomm.c +++ b/drivers/i2s/i2s_mcux_flexcomm.c @@ -264,6 +264,8 @@ static int i2s_mcux_configure(const struct device *dev, enum i2s_dir dir, * More than 2 channels are enabled, so we need to enable * secondary channel pairs. */ +#if (defined(FSL_FEATURE_I2S_SUPPORT_SECONDARY_CHANNEL) && \ + FSL_FEATURE_I2S_SUPPORT_SECONDARY_CHANNEL) for (uint32_t slot = 1; slot < i2s_cfg->channels / 2; slot++) { /* Position must be set so that data does not overlap * with previous channel pair. Each channel pair @@ -272,6 +274,10 @@ static int i2s_mcux_configure(const struct device *dev, enum i2s_dir dir, I2S_EnableSecondaryChannel(cfg->base, slot - 1, false, i2s_cfg->word_size * 2 * slot); } +#else + /* No support */ + return -ENOTSUP; +#endif } /* From a0a599b54b8afe75d7a8196a478b9295dc3b3fd3 Mon Sep 17 00:00:00 2001 From: Tim Lin Date: Thu, 18 Jan 2024 14:10:49 +0800 Subject: [PATCH 2971/3723] ITE: drivers/pinctrl: Distinguish between func3-gcr and func3-ext settings This PR separates the GCTRL settings from func3-gcr to func3-ext. Signed-off-by: Tim Lin --- drivers/pinctrl/pinctrl_ite_it8xxx2.c | 8 ++++++-- dts/riscv/ite/it82xx2.dtsi | 16 ++++++++-------- 2 files changed, 14 insertions(+), 10 deletions(-) diff --git a/drivers/pinctrl/pinctrl_ite_it8xxx2.c b/drivers/pinctrl/pinctrl_ite_it8xxx2.c index 449e90953f0..33ed9130b62 100644 --- a/drivers/pinctrl/pinctrl_ite_it8xxx2.c +++ b/drivers/pinctrl/pinctrl_ite_it8xxx2.c @@ -162,6 +162,9 @@ static int pinctrl_gpio_it8xxx2_configure_pins(const pinctrl_soc_pin_t *pins) /* * Handle alternate function. */ + if (reg_func3_gcr != NULL) { + *reg_func3_gcr &= ~gpio->func3_en_mask[pin]; + } /* Ensure that func3-ext setting is in default state. */ if (reg_func3_ext != NULL) { *reg_func3_ext &= ~gpio->func3_ext_mask[pin]; @@ -179,8 +182,9 @@ static int pinctrl_gpio_it8xxx2_configure_pins(const pinctrl_soc_pin_t *pins) * Func3: In addition to the alternate setting above, * Func3 also need to set the general control. */ - *reg_func3_gcr |= gpio->func3_en_mask[pin]; - + if (reg_func3_gcr != NULL) { + *reg_func3_gcr |= gpio->func3_en_mask[pin]; + } /* Func3-external: Some pins require external setting. */ if (reg_func3_ext != NULL) { *reg_func3_ext |= gpio->func3_ext_mask[pin]; diff --git a/dts/riscv/ite/it82xx2.dtsi b/dts/riscv/ite/it82xx2.dtsi index ad11462b92b..a400d65914b 100644 --- a/dts/riscv/ite/it82xx2.dtsi +++ b/dts/riscv/ite/it82xx2.dtsi @@ -524,14 +524,14 @@ pinctrle: pinctrl@f01680 { compatible = "ite,it8xxx2-pinctrl-func"; reg = <0x00f01680 8>; /* GPCR */ - func3-gcr = <0xf02032 0xf03e16 0xf03e16 NO_FUNC - NO_FUNC 0xf03e10 NO_FUNC 0xf02032>; - func3-en-mask = <0x01 0x20 0x20 0 - 0 0x08 0 0x01 >; - func3-ext = ; - func3-ext-mask = <0 0x02 0x02 0 - 0 0 0 0 >; + func3-gcr = ; + func3-en-mask = <0 0x20 0x20 0 + 0 0x08 0 0 >; + func3-ext = <0xf02032 0xf02032 0xf02032 NO_FUNC + NO_FUNC NO_FUNC NO_FUNC 0xf02032>; + func3-ext-mask = <0x01 0x02 0x02 0 + 0 0 0 0x01 >; func4-gcr = <0xf03e13 NO_FUNC NO_FUNC NO_FUNC NO_FUNC NO_FUNC NO_FUNC NO_FUNC >; func4-en-mask = <0x01 0 0 0 From 10183797a125329f9b93e22b151e00a00d8d984a Mon Sep 17 00:00:00 2001 From: John Whittington Date: Thu, 11 Jan 2024 13:54:19 +0100 Subject: [PATCH 2972/3723] west: runners: blackmagicprobe: flash hex_file The cfg.elf_file is not signed, so `west flash` with a sysbuild will not run the application if MCUboot image signature checking is on. Using the cfg.hex_file for `bmp_flash` resolves since as the signed hex is used when using sysbuild. Symbols are not required for flashing so the switching from elf to hex is not an issue. Signed-off-by: John Whittington --- scripts/west_commands/runners/blackmagicprobe.py | 8 +++++--- scripts/west_commands/tests/test_blackmagicprobe.py | 4 ++-- 2 files changed, 7 insertions(+), 5 deletions(-) diff --git a/scripts/west_commands/runners/blackmagicprobe.py b/scripts/west_commands/runners/blackmagicprobe.py index 54fc22a7eda..95cb6e2efd8 100644 --- a/scripts/west_commands/runners/blackmagicprobe.py +++ b/scripts/west_commands/runners/blackmagicprobe.py @@ -116,6 +116,8 @@ def __init__(self, cfg, gdb_serial, connect_rst=False): # # https://github.com/zephyrproject-rtos/zephyr/issues/50789 self.elf_file = Path(cfg.elf_file).as_posix() + # hex_file for flash signed image + self.hex_file = Path(cfg.hex_file).as_posix() self.gdb_serial = blackmagicprobe_gdb_serial(gdb_serial) self.logger.info(f'using GDB serial: {self.gdb_serial}') if connect_rst: @@ -150,8 +152,8 @@ def do_add_parser(cls, parser): help='Assert SRST during connect? (default: no)') def bmp_flash(self, command, **kwargs): - if self.elf_file is None: - raise ValueError('Cannot debug; elf file is missing') + if self.hex_file is None: + raise ValueError('Cannot flash; hex file is missing') command = (self.gdb + ['-ex', "set confirm off", '-ex', "target extended-remote {}".format( @@ -159,7 +161,7 @@ def bmp_flash(self, command, **kwargs): self.connect_rst_enable_arg + ['-ex', "monitor swdp_scan", '-ex', "attach 1", - '-ex', "load {}".format(self.elf_file), + '-ex', "load {}".format(self.hex_file), '-ex', "kill", '-ex', "quit", '-silent']) diff --git a/scripts/west_commands/tests/test_blackmagicprobe.py b/scripts/west_commands/tests/test_blackmagicprobe.py index 6e083d87c96..3ee50def406 100644 --- a/scripts/west_commands/tests/test_blackmagicprobe.py +++ b/scripts/west_commands/tests/test_blackmagicprobe.py @@ -11,7 +11,7 @@ from runners import blackmagicprobe from runners.blackmagicprobe import BlackMagicProbeRunner -from conftest import RC_KERNEL_ELF, RC_GDB +from conftest import RC_KERNEL_ELF, RC_KERNEL_HEX, RC_GDB import serial.tools.list_ports TEST_GDB_SERIAL = 'test-gdb-serial' @@ -41,7 +41,7 @@ '-ex', "target extended-remote {}".format(TEST_GDB_SERIAL), '-ex', "monitor swdp_scan", '-ex', "attach 1", - '-ex', "load {}".format(RC_KERNEL_ELF), + '-ex', "load {}".format(RC_KERNEL_HEX), '-ex', "kill", '-ex', "quit", '-silent'],), From 3f282da22ddae4d2b178994ae9950e57a2bd3119 Mon Sep 17 00:00:00 2001 From: John Whittington Date: Wed, 24 Jan 2024 13:45:08 +0100 Subject: [PATCH 2973/3723] west: runners: blackmagicprobe: elf_file fallback Building the HEX file is optional (CONFIG_BUILD_OUTPUT_HEX), so `bmp_flash` will fallback to elf_file if missing. Additionally, to maintain section names the HEX is only used if it is signed. Signed-off-by: John Whittington --- .../west_commands/runners/blackmagicprobe.py | 24 +++++++++++++++---- .../tests/test_blackmagicprobe.py | 4 ++-- 2 files changed, 21 insertions(+), 7 deletions(-) diff --git a/scripts/west_commands/runners/blackmagicprobe.py b/scripts/west_commands/runners/blackmagicprobe.py index 95cb6e2efd8..1c2c8fa0d6a 100644 --- a/scripts/west_commands/runners/blackmagicprobe.py +++ b/scripts/west_commands/runners/blackmagicprobe.py @@ -116,8 +116,10 @@ def __init__(self, cfg, gdb_serial, connect_rst=False): # # https://github.com/zephyrproject-rtos/zephyr/issues/50789 self.elf_file = Path(cfg.elf_file).as_posix() - # hex_file for flash signed image - self.hex_file = Path(cfg.hex_file).as_posix() + if cfg.hex_file is not None: + self.hex_file = Path(cfg.hex_file).as_posix() + else: + self.hex_file = None self.gdb_serial = blackmagicprobe_gdb_serial(gdb_serial) self.logger.info(f'using GDB serial: {self.gdb_serial}') if connect_rst: @@ -152,8 +154,20 @@ def do_add_parser(cls, parser): help='Assert SRST during connect? (default: no)') def bmp_flash(self, command, **kwargs): - if self.hex_file is None: - raise ValueError('Cannot flash; hex file is missing') + # if hex file is present and signed, use it else use elf file + if self.hex_file: + split = self.hex_file.split('.') + # eg zephyr.signed.hex + if len(split) >= 3 and split[-2] == 'signed': + flash_file = self.hex_file + else: + flash_file = self.elf_file + else: + flash_file = self.elf_file + + if flash_file is None: + raise ValueError('Cannot flash; elf file is missing') + command = (self.gdb + ['-ex', "set confirm off", '-ex', "target extended-remote {}".format( @@ -161,7 +175,7 @@ def bmp_flash(self, command, **kwargs): self.connect_rst_enable_arg + ['-ex', "monitor swdp_scan", '-ex', "attach 1", - '-ex', "load {}".format(self.hex_file), + '-ex', "load {}".format(flash_file), '-ex', "kill", '-ex', "quit", '-silent']) diff --git a/scripts/west_commands/tests/test_blackmagicprobe.py b/scripts/west_commands/tests/test_blackmagicprobe.py index 3ee50def406..6e083d87c96 100644 --- a/scripts/west_commands/tests/test_blackmagicprobe.py +++ b/scripts/west_commands/tests/test_blackmagicprobe.py @@ -11,7 +11,7 @@ from runners import blackmagicprobe from runners.blackmagicprobe import BlackMagicProbeRunner -from conftest import RC_KERNEL_ELF, RC_KERNEL_HEX, RC_GDB +from conftest import RC_KERNEL_ELF, RC_GDB import serial.tools.list_ports TEST_GDB_SERIAL = 'test-gdb-serial' @@ -41,7 +41,7 @@ '-ex', "target extended-remote {}".format(TEST_GDB_SERIAL), '-ex', "monitor swdp_scan", '-ex', "attach 1", - '-ex', "load {}".format(RC_KERNEL_HEX), + '-ex', "load {}".format(RC_KERNEL_ELF), '-ex', "kill", '-ex', "quit", '-silent'],), From 9dfd3681655d15987cc7c9ed0ec0ab1d0120f6b9 Mon Sep 17 00:00:00 2001 From: Ren Chen Date: Wed, 24 Jan 2024 08:05:18 +0800 Subject: [PATCH 2974/3723] it82xx2/usb: disable 15K-ohm default pull-down if device isn't enabled There is default 15K-ohm pull-down for USB controller. To disable the default pull-down to avoid signal contention in GPIO mode. Signed-off-by: Ren Chen --- drivers/usb/device/usb_dc_it82xx2.c | 3 --- soc/riscv/ite_ec/common/chip_chipregs.h | 7 +++++++ soc/riscv/ite_ec/it8xxx2/soc.c | 7 +++++++ 3 files changed, 14 insertions(+), 3 deletions(-) diff --git a/drivers/usb/device/usb_dc_it82xx2.c b/drivers/usb/device/usb_dc_it82xx2.c index 5020c1c39ed..e453144473c 100644 --- a/drivers/usb/device/usb_dc_it82xx2.c +++ b/drivers/usb/device/usb_dc_it82xx2.c @@ -62,9 +62,6 @@ enum it82xx2_transaction_types { /* The bit definitions of the register Host/Device Control: 0XE0 */ #define RESET_CORE BIT(1) -/* Bit definitions of the register Port0/Port1 MISC Control: 0XE4/0xE8 */ -#define PULL_DOWN_EN BIT(4) - /* ENDPOINT[3..0]_STATUS_REG */ #define DC_STALL_SENT BIT(5) diff --git a/soc/riscv/ite_ec/common/chip_chipregs.h b/soc/riscv/ite_ec/common/chip_chipregs.h index 75e240de530..240a8bb8234 100644 --- a/soc/riscv/ite_ec/common/chip_chipregs.h +++ b/soc/riscv/ite_ec/common/chip_chipregs.h @@ -708,6 +708,13 @@ struct it82xx2_usb_ep_fifo_regs { }; +/* USB Control registers */ +#define USB_IT82XX2_REGS_BASE \ + ((struct usb_it82xx2_regs *)DT_REG_ADDR(DT_NODELABEL(usb0))) + +/* Bit definitions of the register Port0/Port1 MISC Control: 0XE4/0xE8 */ +#define PULL_DOWN_EN BIT(4) + struct usb_it82xx2_regs { /* 0x00: Host TX Contrl Register */ volatile uint8_t host_tx_ctrl; diff --git a/soc/riscv/ite_ec/it8xxx2/soc.c b/soc/riscv/ite_ec/it8xxx2/soc.c index f9a52a1cd3e..48e9360e208 100644 --- a/soc/riscv/ite_ec/it8xxx2/soc.c +++ b/soc/riscv/ite_ec/it8xxx2/soc.c @@ -288,6 +288,13 @@ static int ite_it8xxx2_init(void) struct gpio_it8xxx2_regs *const gpio_regs = GPIO_IT8XXX2_REG_BASE; struct gctrl_it8xxx2_regs *const gctrl_regs = GCTRL_IT8XXX2_REGS_BASE; +#if DT_NODE_HAS_STATUS(DT_NODELABEL(usb0), disabled) + struct usb_it82xx2_regs *const usb_regs = USB_IT82XX2_REGS_BASE; + + usb_regs->port0_misc_control &= ~PULL_DOWN_EN; + usb_regs->port1_misc_control &= ~PULL_DOWN_EN; +#endif + /* * bit7: wake up CPU if it is in low power mode and * an interrupt is pending. From dc90d6ccff28dd7c37c160453abe53874cef39b5 Mon Sep 17 00:00:00 2001 From: Adam Wojasinski Date: Fri, 26 Jan 2024 11:29:52 +0100 Subject: [PATCH 2975/3723] doc: posix: Add missing entries in POSIX supported API doc `mq_timedsend()` and `mq_timedreceive()` are implemented but the information is missing in the documentation. Signed-off-by: Adam Wojasinski --- doc/services/portability/posix/option_groups/index.rst | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/doc/services/portability/posix/option_groups/index.rst b/doc/services/portability/posix/option_groups/index.rst index 40871f99820..5c27d32aa2f 100644 --- a/doc/services/portability/posix/option_groups/index.rst +++ b/doc/services/portability/posix/option_groups/index.rst @@ -486,8 +486,8 @@ _POSIX_TIMEOUTS :header: API, Supported :widths: 50,10 - mq_timedreceive(), - mq_timedsend(), + mq_timedreceive(),yes + mq_timedsend(),yes pthread_mutex_timedlock(),yes pthread_rwlock_timedrdlock(),yes pthread_rwlock_timedwrlock(),yes From 432f4a0b9a93a3793e373dc8a3e2a98745055d68 Mon Sep 17 00:00:00 2001 From: Tyler Ng Date: Fri, 19 Jan 2024 08:48:41 -0800 Subject: [PATCH 2976/3723] soc/riscv/opentitan: Kconfig.defconfig.series: Set NUM_IRQS to 256 The OpenTitan PLIC has support for up to 255 interrupt vectors, so set it to that. Previously was set to number of IRQs used. Signed-off-by: Tyler Ng --- soc/riscv/opentitan/Kconfig.defconfig | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/soc/riscv/opentitan/Kconfig.defconfig b/soc/riscv/opentitan/Kconfig.defconfig index 19a72fc70bd..4b067ef76af 100644 --- a/soc/riscv/opentitan/Kconfig.defconfig +++ b/soc/riscv/opentitan/Kconfig.defconfig @@ -22,6 +22,6 @@ config 2ND_LVL_INTR_00_OFFSET default 11 config NUM_IRQS - default 217 + default 256 endif # SOC_OPENTITAN From 018dbcfd6679c273842084ce34c167295bc6f354 Mon Sep 17 00:00:00 2001 From: Ryan McClelland Date: Sat, 22 Apr 2023 14:23:57 -0700 Subject: [PATCH 2977/3723] cmake: compiler: add double promotion warning Too many times, code is pushed that includes floats that really becomes doubles and C implicit promotion rules will want to make floats into doubles very easily. As zephyr primarily targets low-end process that may not have a double precision floating point unit, enable this flag globally for now. Signed-off-by: Ryan McClelland --- cmake/compiler/arcmwdt/compiler_flags.cmake | 3 +++ cmake/compiler/clang/compiler_flags.cmake | 3 +++ cmake/compiler/gcc/compiler_flags.cmake | 3 +++ 3 files changed, 9 insertions(+) diff --git a/cmake/compiler/arcmwdt/compiler_flags.cmake b/cmake/compiler/arcmwdt/compiler_flags.cmake index 7ab83ba507d..5383016795b 100644 --- a/cmake/compiler/arcmwdt/compiler_flags.cmake +++ b/cmake/compiler/arcmwdt/compiler_flags.cmake @@ -33,6 +33,9 @@ set_compiler_property(PROPERTY warning_base -Wno-typedef-redefinition ) +# C implicit promotion rules will want to make floats into doubles very easily +check_set_compiler_property(APPEND PROPERTY warning_base -Wdouble-promotion) + check_set_compiler_property(APPEND PROPERTY warning_base -Wno-pointer-sign) # Prohibit void pointer arithmetic. Illegal in C99 diff --git a/cmake/compiler/clang/compiler_flags.cmake b/cmake/compiler/clang/compiler_flags.cmake index 3658161123b..e0448d0720e 100644 --- a/cmake/compiler/clang/compiler_flags.cmake +++ b/cmake/compiler/clang/compiler_flags.cmake @@ -45,6 +45,9 @@ check_set_compiler_property(PROPERTY warning_base -Wno-deprecated-non-prototype ) +# C implicit promotion rules will want to make floats into doubles very easily +check_set_compiler_property(APPEND PROPERTY warning_base -Wdouble-promotion) + check_set_compiler_property(APPEND PROPERTY warning_base -Wno-pointer-sign) # Prohibit void pointer arithmetic. Illegal in C99 diff --git a/cmake/compiler/gcc/compiler_flags.cmake b/cmake/compiler/gcc/compiler_flags.cmake index a118fbe570c..db252077101 100644 --- a/cmake/compiler/gcc/compiler_flags.cmake +++ b/cmake/compiler/gcc/compiler_flags.cmake @@ -32,6 +32,9 @@ check_set_compiler_property(PROPERTY warning_base "SHELL:-Wformat -Wno-format-zero-length" ) +# C implicit promotion rules will want to make floats into doubles very easily +check_set_compiler_property(APPEND PROPERTY warning_base -Wdouble-promotion) + check_set_compiler_property(APPEND PROPERTY warning_base -Wno-pointer-sign) # Prohibit void pointer arithmetic. Illegal in C99 From cf14d4f1fd6d3049e3417d82ab18a2c9aa43b370 Mon Sep 17 00:00:00 2001 From: Attie Grande Date: Thu, 4 Jan 2024 16:43:57 +0000 Subject: [PATCH 2978/3723] samples: drivers: uart: Add a 'passthrough' example This sample can be used as a "virtual wire", allowing direct access to devices connected to the target processor - for example: GPS, Cellular, etc... This is also useful as a utility - no other connectivity options exist for UART, where other interfaces like SPI and I2C have shell commands. Signed-off-by: Attie Grande --- .../drivers/uart/passthrough/CMakeLists.txt | 7 + samples/drivers/uart/passthrough/README.rst | 50 ++++++ .../passthrough/boards/nucleo_l476rg.overlay | 12 ++ samples/drivers/uart/passthrough/prj.conf | 3 + samples/drivers/uart/passthrough/sample.yml | 14 ++ samples/drivers/uart/passthrough/src/main.c | 150 ++++++++++++++++++ 6 files changed, 236 insertions(+) create mode 100644 samples/drivers/uart/passthrough/CMakeLists.txt create mode 100644 samples/drivers/uart/passthrough/README.rst create mode 100644 samples/drivers/uart/passthrough/boards/nucleo_l476rg.overlay create mode 100644 samples/drivers/uart/passthrough/prj.conf create mode 100644 samples/drivers/uart/passthrough/sample.yml create mode 100644 samples/drivers/uart/passthrough/src/main.c diff --git a/samples/drivers/uart/passthrough/CMakeLists.txt b/samples/drivers/uart/passthrough/CMakeLists.txt new file mode 100644 index 00000000000..ca7c7f7faa5 --- /dev/null +++ b/samples/drivers/uart/passthrough/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(passthrough) + +target_sources(app PRIVATE src/main.c) diff --git a/samples/drivers/uart/passthrough/README.rst b/samples/drivers/uart/passthrough/README.rst new file mode 100644 index 00000000000..94d58f3dca1 --- /dev/null +++ b/samples/drivers/uart/passthrough/README.rst @@ -0,0 +1,50 @@ +.. zephyr:code-sample:: uart-passthrough + :name: UART Passthrough + :relevant-api: uart_interface + + Pass data directly between the console and another UART interface. + +Overview +******** + +This sample will virtually connect two UART interfaces together, as if Zephyr +and the processor were not present. Data read from the console is transmitted +to the "*other*" interface, and data read from the "*other*" interface is +relayed to the console. + +The source code for this sample application can be found at: +:zephyr_file:`samples/drivers/uart/passthrough`. + +Requirements +************ + +#. One UART interface, identified as Zephyr's console. +#. A second UART connected to something interesting (e.g: GPS), identified as + the chosen ``uart,passthrough`` device - the pins and baudrate will need to + be configured correctly. + +Building and Running +******************** + +Build and flash the sample as follows, changing ``nucleo_l476rg`` for your +board: + +.. zephyr-app-commands:: + :zephyr-app: samples/drivers/uart/passthrough + :board: nucleo_l476rg + :goals: build flash + :compact: + +Sample Output +============= + +.. code-block:: console + + *** Booting Zephyr OS build zephyr-v3.5.0-2988-gb84bab36b941 *** + Console Device: 0x8003940 + Other Device: 0x800392c + $GNGSA,A,3,31,29,25,26,,,,,,,,,11.15,10.66,3.29,1*06 + $GNGSA,A,3,,,,,,,,,,,,,11.15,10.66,3.29,2*0F + $GNGSA,A,3,,,,,,,,,,,,,11.15,10.66,3.29,3*0E + $GNGSA,A,3,,,,,,,,,,,,,11.15,10.66,3.29,4*09 + $GNGSA,A,3,,,,,,,,,,,,,11.15,10.66,3.29,5*08 diff --git a/samples/drivers/uart/passthrough/boards/nucleo_l476rg.overlay b/samples/drivers/uart/passthrough/boards/nucleo_l476rg.overlay new file mode 100644 index 00000000000..5292b54e5f5 --- /dev/null +++ b/samples/drivers/uart/passthrough/boards/nucleo_l476rg.overlay @@ -0,0 +1,12 @@ +/ { + chosen { + uart,passthrough = &uart4; + }; +}; + +&uart4 { + pinctrl-0 = <&uart4_tx_pa0 &uart4_rx_pa1>; + pinctrl-names = "default"; + current-speed = <9600>; + status = "okay"; +}; diff --git a/samples/drivers/uart/passthrough/prj.conf b/samples/drivers/uart/passthrough/prj.conf new file mode 100644 index 00000000000..70eec2fbac3 --- /dev/null +++ b/samples/drivers/uart/passthrough/prj.conf @@ -0,0 +1,3 @@ +CONFIG_SERIAL=y +CONFIG_RING_BUFFER=y +CONFIG_UART_INTERRUPT_DRIVEN=y diff --git a/samples/drivers/uart/passthrough/sample.yml b/samples/drivers/uart/passthrough/sample.yml new file mode 100644 index 00000000000..5e4abf91f4d --- /dev/null +++ b/samples/drivers/uart/passthrough/sample.yml @@ -0,0 +1,14 @@ +sample: + name: UART Passthrough +tests: + sample.drivers.uart: + integration_platforms: + - qemu_x86 + tags: + - serial + - uart + filter: CONFIG_SERIAL and + CONFIG_UART_INTERRUPT_DRIVEN and + dt_chosen_enabled("zephyr,console") and + dt_chosen_enabled("uart,passthrough") + harness: keyboard diff --git a/samples/drivers/uart/passthrough/src/main.c b/samples/drivers/uart/passthrough/src/main.c new file mode 100644 index 00000000000..2168207a751 --- /dev/null +++ b/samples/drivers/uart/passthrough/src/main.c @@ -0,0 +1,150 @@ +/* + * Copyright (c) 2024 Argentum Systems Ltd. + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include +#include +#include +#include + +#include +#include + +struct patch_info { + const uint8_t * const name; + + const struct device *rx_dev; + struct ring_buf *rx_ring_buf; + bool rx_error; + bool rx_overflow; + + const struct device *tx_dev; +}; + +#define DEV_CONSOLE DEVICE_DT_GET(DT_CHOSEN(zephyr_console)) +#define DEV_OTHER DEVICE_DT_GET(DT_CHOSEN(uart_passthrough)) + +#define RING_BUF_SIZE 64 + +RING_BUF_DECLARE(rb_console, RING_BUF_SIZE); +struct patch_info patch_c2o = { + .name = "c2o", + + .rx_dev = DEV_CONSOLE, + .rx_ring_buf = &rb_console, + .rx_error = false, + .rx_overflow = false, + + .tx_dev = DEV_OTHER, +}; + +RING_BUF_DECLARE(rb_other, RING_BUF_SIZE); +struct patch_info patch_o2c = { + .name = "o2c", + + .rx_dev = DEV_OTHER, + .rx_ring_buf = &rb_other, + .rx_error = false, + .rx_overflow = false, + + .tx_dev = DEV_CONSOLE, +}; + +static void uart_cb(const struct device *dev, void *ctx) +{ + struct patch_info *patch = (struct patch_info *)ctx; + int ret; + uint8_t *buf; + uint32_t len; + + while (uart_irq_update(patch->rx_dev) > 0) { + ret = uart_irq_rx_ready(patch->rx_dev); + if (ret < 0) { + patch->rx_error = true; + } + if (ret <= 0) { + break; + } + + len = ring_buf_put_claim(patch->rx_ring_buf, &buf, RING_BUF_SIZE); + if (len == 0) { + /* no space for Rx, disable the IRQ */ + uart_irq_rx_disable(patch->rx_dev); + patch->rx_overflow = true; + break; + } + + ret = uart_fifo_read(patch->rx_dev, buf, len); + if (ret < 0) { + patch->rx_error = true; + } + if (ret <= 0) { + break; + } + len = ret; + + ret = ring_buf_put_finish(patch->rx_ring_buf, len); + if (ret != 0) { + patch->rx_error = true; + break; + } + } +} + +static void passthrough(struct patch_info *patch) +{ + int ret; + uint8_t *buf; + uint32_t len; + + if (patch->rx_error) { + printk("<<%s: Rx Error!>>\n", patch->name); + patch->rx_error = false; + } + + if (patch->rx_overflow) { + printk("<<%s: Rx Overflow!>>\n", patch->name); + patch->rx_overflow = false; + } + + len = ring_buf_get_claim(patch->rx_ring_buf, &buf, RING_BUF_SIZE); + if (len == 0) { + goto done; + } + + ret = uart_fifo_fill(patch->tx_dev, buf, len); + if (ret < 0) { + goto error; + } + len = ret; + + ret = ring_buf_get_finish(patch->rx_ring_buf, len); + if (ret < 0) { + goto error; + } + +done: + uart_irq_rx_enable(patch->rx_dev); + return; + +error: + printk("<<%s: Tx Error!>>\n", patch->name); +} + +int main(void) +{ + printk("Console Device: %p\n", patch_c2o.rx_dev); + printk("Other Device: %p\n", patch_o2c.rx_dev); + + uart_irq_callback_user_data_set(patch_c2o.rx_dev, uart_cb, (void *)&patch_c2o); + uart_irq_callback_user_data_set(patch_o2c.rx_dev, uart_cb, (void *)&patch_o2c); + + for (;;) { + passthrough(&patch_c2o); + passthrough(&patch_o2c); + } + + return 0; +} From e357ba835d45a30552d6df57d45b54490a182ea5 Mon Sep 17 00:00:00 2001 From: Christopher Friedt Date: Sun, 14 Jan 2024 11:20:22 -0500 Subject: [PATCH 2979/3723] posix: internal: make priority / policy transforms available Two functions can be used with relative ease to convert between Zephyr and POSIX priorities and policies. Namely, uint32_t zephyr_to_posix_priority(int32_t z_prio, int *policy) int32_t posix_to_zephyr_priority(uint32_t priority, int policy) These are not necessarily public API, but they helped with the POSIX Philosophers Sample, which is in a subsequent commit. Signed-off-by: Christopher Friedt --- lib/posix/posix_internal.h | 3 +++ 1 file changed, 3 insertions(+) diff --git a/lib/posix/posix_internal.h b/lib/posix/posix_internal.h index 837349b4d32..17d8c29d438 100644 --- a/lib/posix/posix_internal.h +++ b/lib/posix/posix_internal.h @@ -102,4 +102,7 @@ struct posix_thread *to_posix_thread(pthread_t pth); /* get and possibly initialize a posix_mutex */ struct k_mutex *to_posix_mutex(pthread_mutex_t *mu); +int posix_to_zephyr_priority(int priority, int policy); +int zephyr_to_posix_priority(int priority, int *policy); + #endif From 248324b67aa60b80fe6725197c7119b55ad8b000 Mon Sep 17 00:00:00 2001 From: Christopher Friedt Date: Sun, 14 Jan 2024 11:23:40 -0500 Subject: [PATCH 2980/3723] samples: posix: implement philosphers using pthreads This sample takes a POSIX-y spin on the existing Dining Philosophers sample application. The objects used in the POSIX version are pthread_mutex_t, and the threads are pthread_t. Signed-off-by: Christopher Friedt --- samples/posix/philosophers/CMakeLists.txt | 10 + samples/posix/philosophers/Kconfig | 16 ++ samples/posix/philosophers/README.rst | 57 +++++ samples/posix/philosophers/prj.conf | 25 ++ samples/posix/philosophers/sample.yaml | 21 ++ samples/posix/philosophers/src/main.c | 278 ++++++++++++++++++++++ 6 files changed, 407 insertions(+) create mode 100644 samples/posix/philosophers/CMakeLists.txt create mode 100644 samples/posix/philosophers/Kconfig create mode 100644 samples/posix/philosophers/README.rst create mode 100644 samples/posix/philosophers/prj.conf create mode 100644 samples/posix/philosophers/sample.yaml create mode 100644 samples/posix/philosophers/src/main.c diff --git a/samples/posix/philosophers/CMakeLists.txt b/samples/posix/philosophers/CMakeLists.txt new file mode 100644 index 00000000000..e8a6a207987 --- /dev/null +++ b/samples/posix/philosophers/CMakeLists.txt @@ -0,0 +1,10 @@ +# SPDX-License-Identifier: Apache-2.0 + +cmake_minimum_required(VERSION 3.20.0) +find_package(Zephyr REQUIRED HINTS $ENV{ZEPHYR_BASE}) +project(posix_philosophers) + +target_sources(app PRIVATE src/main.c) +# For translating POSIX scheduler policies and priorities to +# Zephyr priorities. +target_include_directories(app PRIVATE ${ZEPHYR_BASE}/lib/posix) diff --git a/samples/posix/philosophers/Kconfig b/samples/posix/philosophers/Kconfig new file mode 100644 index 00000000000..5105138ca83 --- /dev/null +++ b/samples/posix/philosophers/Kconfig @@ -0,0 +1,16 @@ +# Copyright (c) 2024, Meta +# +# SPDX-License-Identifier: Apache-2.0 + +config SAMPLE_ERROR_CHECKING + bool "Perform error checking" + +config SAMPLE_DEBUG_PRINTF + bool "Print debug information" + default y + +config SAMPLE_SAME_PRIO + bool "Print debug information" + default n + +source "Kconfig.zephyr" diff --git a/samples/posix/philosophers/README.rst b/samples/posix/philosophers/README.rst new file mode 100644 index 00000000000..e7e1b958e5c --- /dev/null +++ b/samples/posix/philosophers/README.rst @@ -0,0 +1,57 @@ +.. _posix-philosophers-sample: + +POSIX Philosophers +################## + +Overview +******** + +This sample implements Zephyr's :ref:`Dining Philosophers Sample ` using the +:ref:`POSIX API `. The source code for this sample can be found under +:file:`samples/posix/philosophers`. + +Building and Running +******************** + +This project outputs to the console. It can be built and executed +on QEMU as follows: + +.. zephyr-app-commands:: + :zephyr-app: samples/posix/philosophers + :host-os: unix + :board: qemu_riscv64 + :goals: run + :compact: + +Sample Output +============= + +.. code-block:: console + + Philosopher 0 [P: 3] HOLDING ONE FORK + Philosopher 1 [P: 2] HOLDING ONE FORK + Philosopher 2 [P: 1] EATING [ 1900 ms ] + Philosopher 3 [P: 0] THINKING [ 2500 ms ] + Philosopher 4 [C:-1] THINKING [ 2200 ms ] + Philosopher 5 [C:-2] THINKING [ 1700 ms ] + +Exit QEMU by pressing :kbd:`CTRL+A` :kbd:`x`. + +Debugging +********* + +Like the original philosophers sample, the POSIX variant also enables +:kconfig:option:`CONFIG_DEBUG_THREAD_INFO` by default. + +.. zephyr-app-commands:: + :zephyr-app: samples/philosophers + :host-os: unix + :board: + :goals: debug + :compact: + +Additional Information +********************** + +For additional information, please refer to the +:ref:`Dining Philosophers Sample `. diff --git a/samples/posix/philosophers/prj.conf b/samples/posix/philosophers/prj.conf new file mode 100644 index 00000000000..ccee021cdf7 --- /dev/null +++ b/samples/posix/philosophers/prj.conf @@ -0,0 +1,25 @@ +CONFIG_STDOUT_CONSOLE=n +CONFIG_ASSERT=y +CONFIG_ASSERT_LEVEL=2 +CONFIG_NUM_COOP_PRIORITIES=29 +CONFIG_NUM_PREEMPT_PRIORITIES=40 +CONFIG_SCHED_SCALABLE=y +CONFIG_MP_MAX_NUM_CPUS=1 + +CONFIG_LOG=y +CONFIG_LOG_MODE_MINIMAL=y + +CONFIG_POSIX_API=y +CONFIG_THREAD_STACK_INFO=y +CONFIG_DYNAMIC_THREAD=y + +CONFIG_DYNAMIC_THREAD_POOL_SIZE=6 +CONFIG_MAX_PTHREAD_COUNT=6 +CONFIG_MAX_PTHREAD_MUTEX_COUNT=7 + +#Enable thread awareness for debugging tools supporting it +CONFIG_DEBUG_THREAD_INFO=y + +# CONFIG_SAMPLE_ERROR_CHECKING=y +# CONFIG_PTHREAD_MUTEX_LOG_LEVEL_DBG=y +# CONFIG_PTHREAD_LOG_LEVEL_DBG=y diff --git a/samples/posix/philosophers/sample.yaml b/samples/posix/philosophers/sample.yaml new file mode 100644 index 00000000000..1e3a6a2cb36 --- /dev/null +++ b/samples/posix/philosophers/sample.yaml @@ -0,0 +1,21 @@ +sample: + name: POSIX Philosophers +common: + tags: + - inroduction + - posix + harness: console + min_ram: 16 + integration_platforms: + - native_sim + filter: not CONFIG_NATIVE_APPLICATION + harness_config: + type: multi_line + ordered: false + regex: + - ".*STARVING.*" + - ".*DROPPED ONE FORK.*" + - ".*THINKING.*" + - ".*EATING.*" +tests: + sample.posix.philosopher: {} diff --git a/samples/posix/philosophers/src/main.c b/samples/posix/philosophers/src/main.c new file mode 100644 index 00000000000..bf1db7d707f --- /dev/null +++ b/samples/posix/philosophers/src/main.c @@ -0,0 +1,278 @@ +/* + * Copyright (c) 2011-2016 Wind River Systems, Inc. + * Copyright (c) 2024, Meta + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include "posix_internal.h" + +#include +#include +#include +#include + +#include +#include + +#ifdef CONFIG_THREAD_NAME +#define MAX_NAME_LEN CONFIG_THREAD_MAX_NAME_LEN +#else +#define MAX_NAME_LEN 1 +#endif + +#define NUM_PHIL CONFIG_MAX_PTHREAD_COUNT +#define obj_init_type "POSIX" +#define fork_type_str "mutexes" + +BUILD_ASSERT(CONFIG_MAX_PTHREAD_COUNT == CONFIG_MAX_PTHREAD_MUTEX_COUNT - 1); +BUILD_ASSERT(CONFIG_DYNAMIC_THREAD_POOL_SIZE == CONFIG_MAX_PTHREAD_COUNT); + +typedef pthread_mutex_t *fork_t; + +LOG_MODULE_REGISTER(posix_philosophers, LOG_LEVEL_INF); + +static pthread_mutex_t forks[NUM_PHIL]; +static pthread_t threads[NUM_PHIL]; + +static inline void fork_init(fork_t frk) +{ + int ret; + + ret = pthread_mutex_init(frk, NULL); + if (IS_ENABLED(CONFIG_SAMPLE_ERROR_CHECKING) && ret != 0) { + errno = ret; + perror("pthread_mutex_init"); + __ASSERT(false, "Failed to initialize fork"); + } +} + +static inline fork_t fork(size_t idx) +{ + return &forks[idx]; +} + +static inline void take(fork_t frk) +{ + int ret; + + ret = pthread_mutex_lock(frk); + if (IS_ENABLED(CONFIG_SAMPLE_ERROR_CHECKING) && ret != 0) { + errno = ret; + perror("pthread_mutex_lock"); + __ASSERT(false, "Failed to lock mutex"); + } +} + +static inline void drop(fork_t frk) +{ + int ret; + + ret = pthread_mutex_unlock(frk); + if (IS_ENABLED(CONFIG_SAMPLE_ERROR_CHECKING) && ret != 0) { + errno = ret; + perror("pthread_mutex_unlock"); + __ASSERT(false, "Failed to unlock mutex"); + } +} + +static void set_phil_state_pos(int id) +{ + if (IS_ENABLED(CONFIG_SAMPLE_DEBUG_PRINTF)) { + printk("\x1b[%d;%dH", id + 1, 1); + } +} + +static void print_phil_state(int id, const char *fmt, int32_t delay) +{ + int ret; + int prio; + int policy; + struct sched_param param; + + ret = pthread_getschedparam(pthread_self(), &policy, ¶m); + if (IS_ENABLED(CONFIG_SAMPLE_ERROR_CHECKING) && ret != 0) { + errno = ret; + perror("pthread_getschedparam"); + __ASSERT(false, "Failed to get scheduler params"); + } + + prio = posix_to_zephyr_priority(param.sched_priority, policy); + + set_phil_state_pos(id); + + printk("Philosopher %d [%s:%s%d] ", id, prio < 0 ? "C" : "P", prio < 0 ? "" : " ", prio); + + if (delay) { + printk(fmt, delay < 1000 ? " " : "", delay); + } else { + printk(fmt, ""); + } + + printk("\n"); +} + +static int32_t get_random_delay(int id, int period_in_ms) +{ + int32_t ms; + int32_t delay; + int32_t uptime; + struct timespec ts; + + /* + * The random delay is unit-less, and is based on the philosopher's ID + * and the current uptime to create some pseudo-randomness. It produces + * a value between 0 and 31. + */ + clock_gettime(CLOCK_MONOTONIC, &ts); + uptime = ts.tv_sec * MSEC_PER_SEC + (ts.tv_nsec / NSEC_PER_MSEC); + delay = (uptime / 100 * (id + 1)) & 0x1f; + + /* add 1 to not generate a delay of 0 */ + ms = (delay + 1) * period_in_ms; + + return ms; +} + +static inline int is_last_philosopher(int id) +{ + return id == (NUM_PHIL - 1); +} + +static void *philosopher(void *arg) +{ + fork_t my_fork1; + fork_t my_fork2; + + int my_id = POINTER_TO_INT(arg); + + /* Djkstra's solution: always pick up the lowest numbered fork first */ + if (is_last_philosopher(my_id)) { + my_fork1 = fork(0); + my_fork2 = fork(my_id); + } else { + my_fork1 = fork(my_id); + my_fork2 = fork(my_id + 1); + } + + while (1) { + int32_t delay; + + print_phil_state(my_id, " STARVING ", 0); + take(my_fork1); + print_phil_state(my_id, " HOLDING ONE FORK ", 0); + take(my_fork2); + + delay = get_random_delay(my_id, 25); + print_phil_state(my_id, " EATING [ %s%d ms ] ", delay); + usleep(delay * USEC_PER_MSEC); + + drop(my_fork2); + print_phil_state(my_id, " DROPPED ONE FORK ", 0); + drop(my_fork1); + + delay = get_random_delay(my_id, 25); + print_phil_state(my_id, " THINKING [ %s%d ms ] ", delay); + usleep(delay * USEC_PER_MSEC); + } + + return NULL; +} + +static int new_prio(int phil) +{ + if (CONFIG_NUM_COOP_PRIORITIES > 0 && CONFIG_NUM_PREEMPT_PRIORITIES > 0) { + if (IS_ENABLED(CONFIG_SAMPLE_SAME_PRIO)) { + return 0; + } + + return -(phil - (NUM_PHIL / 2)); + } + + if (CONFIG_NUM_COOP_PRIORITIES > 0) { + return -phil - 2; + } + + if (CONFIG_NUM_PREEMPT_PRIORITIES > 0) { + return phil; + } + + __ASSERT_NO_MSG("Unsupported scheduler configuration"); +} + +static void init_objects(void) +{ + ARRAY_FOR_EACH(forks, i) { + LOG_DBG("Initializing fork %zu", i); + fork_init(fork(i)); + } +} + +static void start_threads(void) +{ + int ret; + int prio; + int policy; + struct sched_param param; + + ARRAY_FOR_EACH(forks, i) { + LOG_DBG("Initializing philosopher %zu", i); + ret = pthread_create(&threads[i], NULL, philosopher, INT_TO_POINTER(i)); + if (IS_ENABLED(CONFIG_SAMPLE_ERROR_CHECKING) && ret != 0) { + errno = ret; + perror("pthread_create"); + __ASSERT(false, "Failed to create thread"); + } + + prio = new_prio(i); + param.sched_priority = zephyr_to_posix_priority(prio, &policy); + ret = pthread_setschedparam(threads[i], policy, ¶m); + if (IS_ENABLED(CONFIG_SAMPLE_ERROR_CHECKING) && ret != 0) { + errno = ret; + perror("pthread_setschedparam"); + __ASSERT(false, "Failed to set scheduler params"); + } + + if (IS_ENABLED(CONFIG_THREAD_NAME)) { + char tname[MAX_NAME_LEN]; + + snprintf(tname, sizeof(tname), "Philosopher %zu", i); + pthread_setname_np(threads[i], tname); + } + } +} + +#define DEMO_DESCRIPTION \ + "\x1b[2J\x1b[15;1H" \ + "Demo Description\n" \ + "----------------\n" \ + "An implementation of a solution to the Dining Philosophers\n" \ + "problem (a classic multi-thread synchronization problem).\n" \ + "This particular implementation demonstrates the usage of multiple\n" \ + "preemptible and cooperative threads of differing priorities, as\n" \ + "well as %s %s and thread sleeping.\n", \ + obj_init_type, fork_type_str + +static void display_demo_description(void) +{ + if (IS_ENABLED(CONFIG_SAMPLE_DEBUG_PRINTF)) { + printk(DEMO_DESCRIPTION); + } +} + +int main(void) +{ + display_demo_description(); + + init_objects(); + start_threads(); + + if (IS_ENABLED(CONFIG_COVERAGE)) { + /* Wait a few seconds before main() exit, giving the sample the + * opportunity to dump some output before coverage data gets emitted + */ + sleep(5); + } + + return 0; +} From a37254140b0b4964fab97571470140ff6df96323 Mon Sep 17 00:00:00 2001 From: Christopher Friedt Date: Fri, 19 Jan 2024 07:37:33 -0500 Subject: [PATCH 2981/3723] scripts: checkpatch.pl: fix constant comparison false positives Comparisons that have constants on both side of the operator were getting flagged incorrectly. Adjust the check so that pure constant comparisons are not flagged, reducing false positives. WARNING:CONSTANT_COMPARISON: \ Comparisons should place the constant on the right side of \ the test +BUILD_ASSERT(CONFIG_MAX_PTHREAD_COUNT == \ CONFIG_MAX_PTHREAD_MUTEX_COUNT - 1); Signed-off-by: Christopher Friedt --- scripts/checkpatch.pl | 1 + 1 file changed, 1 insertion(+) diff --git a/scripts/checkpatch.pl b/scripts/checkpatch.pl index 110eed8ec56..b3bfd180cca 100755 --- a/scripts/checkpatch.pl +++ b/scripts/checkpatch.pl @@ -5004,6 +5004,7 @@ sub process { # only fix matches surrounded by parentheses to avoid incorrect # conversions like "FOO < baz() + 5" being "misfixed" to "baz() > FOO + 5" if ($perl_version_ok && + !($line =~ /^\+(.*)($Constant|[A-Z_][A-Z0-9_]*)\s*($Compare)\s*(.*)($Constant|[A-Z_][A-Z0-9_]*)(.*)/) && $line =~ /^\+(.*)\b($Constant|[A-Z_][A-Z0-9_]*)\s*($Compare)\s*($LvalOrFunc)/) { my $lead = $1; my $const = $2; From 64cedb5f358763bfe5131b8e5afe60b02192ab2e Mon Sep 17 00:00:00 2001 From: Henrik Brix Andersen Date: Sun, 28 Jan 2024 18:35:06 +0100 Subject: [PATCH 2982/3723] drivers: can: stm32: bxcan: fix header order Sort the included headers by name, remove unneeded includes and ensure soc.h is included prior to the Zephyr CAN headers. Signed-off-by: Henrik Brix Andersen --- drivers/can/can_stm32_bxcan.c | 15 +++++++-------- 1 file changed, 7 insertions(+), 8 deletions(-) diff --git a/drivers/can/can_stm32_bxcan.c b/drivers/can/can_stm32_bxcan.c index 8d2f3db3d8b..557079e2e3c 100644 --- a/drivers/can/can_stm32_bxcan.c +++ b/drivers/can/can_stm32_bxcan.c @@ -5,19 +5,18 @@ * SPDX-License-Identifier: Apache-2.0 */ +/* Include soc.h prior to Zephyr CAN headers to pull in HAL fixups */ +#include +#include #include -#include + #include +#include #include -#include -#include +#include #include -#include -#include -#include -#include #include -#include +#include LOG_MODULE_REGISTER(can_stm32, CONFIG_CAN_LOG_LEVEL); From 673009f66539e63724cfd96e205bd3c167d6ef4d Mon Sep 17 00:00:00 2001 From: Jordan Yates Date: Sun, 19 Mar 2023 22:54:43 +1000 Subject: [PATCH 2983/3723] drivers: power_domain: add missing dependency The GPIO power domain driver needs device power management enabled to compile if `PM_DEVICE_POWER_DOMAIN` is enabled. Signed-off-by: Jordan Yates --- drivers/power_domain/Kconfig | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/power_domain/Kconfig b/drivers/power_domain/Kconfig index fc552490b8e..c1fe5d3bd9b 100644 --- a/drivers/power_domain/Kconfig +++ b/drivers/power_domain/Kconfig @@ -23,6 +23,7 @@ config POWER_DOMAIN_GPIO default y depends on DT_HAS_POWER_DOMAIN_GPIO_ENABLED depends on GPIO + depends on PM_DEVICE || !PM_DEVICE_POWER_DOMAIN depends on TIMEOUT_64BIT select DEVICE_DEPS From 6cb98162b7b40041a9f9a5cb638faf371fcdfa7e Mon Sep 17 00:00:00 2001 From: Yasin Ustuner Date: Sun, 24 Dec 2023 00:48:19 +0300 Subject: [PATCH 2984/3723] scripts: ci: check_compliance.py: Add out-of-tree dts/bindings This commit includes out-of-tree dts/bindings to temporary Kconfig.dts for compliance checks. Signed-off-by: Yasin Ustuner --- scripts/ci/check_compliance.py | 30 +++++++++++++++++++++++------- 1 file changed, 23 insertions(+), 7 deletions(-) diff --git a/scripts/ci/check_compliance.py b/scripts/ci/check_compliance.py index 0d8e472f6c6..c9f09520277 100755 --- a/scripts/ci/check_compliance.py +++ b/scripts/ci/check_compliance.py @@ -286,7 +286,7 @@ def run(self, full=True, no_modules=False): if full: self.check_no_undef_outside_kconfig(kconf) - def get_modules(self, modules_file): + def get_modules(self, modules_file, settings_file): """ Get a list of modules and put them in a file that is parsed by Kconfig @@ -304,7 +304,7 @@ def get_modules(self, modules_file): zephyr_module_path = os.path.join(ZEPHYR_BASE, "scripts", "zephyr_module.py") cmd = [sys.executable, zephyr_module_path, - '--kconfig-out', modules_file] + '--kconfig-out', modules_file, '--settings-out', settings_file] try: subprocess.run(cmd, check=True, stdout=subprocess.PIPE, stderr=subprocess.STDOUT) @@ -326,7 +326,7 @@ def get_modules(self, modules_file): )) fp_module_file.write(content) - def get_kconfig_dts(self, kconfig_dts_file): + def get_kconfig_dts(self, kconfig_dts_file, settings_file): """ Generate the Kconfig.dts using dts/bindings as the source. @@ -337,9 +337,23 @@ def get_kconfig_dts(self, kconfig_dts_file): # not a module nor a pip-installed Python utility zephyr_drv_kconfig_path = os.path.join(ZEPHYR_BASE, "scripts", "dts", "gen_driver_kconfig_dts.py") - binding_path = os.path.join(ZEPHYR_BASE, "dts", "bindings") + binding_paths = [] + binding_paths.append(os.path.join(ZEPHYR_BASE, "dts", "bindings")) + + if os.path.exists(settings_file): + with open(settings_file, 'r') as fp_setting_file: + content = fp_setting_file.read() + + lines = content.strip().split('\n') + for line in lines: + if line.startswith('"DTS_ROOT":'): + _, dts_root_path = line.split(":") + binding_paths.append(os.path.join(dts_root_path.strip('"'), "dts", "bindings")) + cmd = [sys.executable, zephyr_drv_kconfig_path, - '--kconfig-out', kconfig_dts_file, '--bindings-dirs', binding_path] + '--kconfig-out', kconfig_dts_file, '--bindings-dirs'] + for binding_path in binding_paths: + cmd.append(binding_path) try: subprocess.run(cmd, check=True, stdout=subprocess.PIPE, stderr=subprocess.STDOUT) @@ -383,9 +397,11 @@ def parse_kconfig(self): os.environ["GENERATED_DTS_BOARD_CONF"] = "dummy" # For multi repo support - self.get_modules(os.path.join(kconfiglib_dir, "Kconfig.modules")) + self.get_modules(os.path.join(kconfiglib_dir, "Kconfig.modules"), + os.path.join(kconfiglib_dir, "settings_file.txt")) # For Kconfig.dts support - self.get_kconfig_dts(os.path.join(kconfiglib_dir, "Kconfig.dts")) + self.get_kconfig_dts(os.path.join(kconfiglib_dir, "Kconfig.dts"), + os.path.join(kconfiglib_dir, "settings_file.txt")) # Tells Kconfiglib to generate warnings for all references to undefined # symbols within Kconfig files From 9af051e3499fccdb1898748d2afd8dcd06d013f2 Mon Sep 17 00:00:00 2001 From: Pavel Vasilyev Date: Mon, 22 Jan 2024 14:40:38 +0100 Subject: [PATCH 2985/3723] Bluetooth: Mesh: Call bt_mesh_send_cb.end cb by the end of adv Before this change, the bt_mesh_send_cb.end callback was called when all references to the adv were removed. If an implementation kept more references to the adv buffer after calling `bt_mesh_adv_send`, the end callback would not be called when the advertiser finished advertising this adv. With this change, the end callback is always called by the advertiser when the advertisement is finished regardless of the number of references. This allows an implementation to keep the adv buffer for the future use. As an example, pb_adv.c keeps advs for retransmission. Signed-off-by: Pavel Vasilyev --- subsys/bluetooth/mesh/adv.c | 4 +--- subsys/bluetooth/mesh/adv.h | 1 + subsys/bluetooth/mesh/adv_ext.c | 5 +++++ subsys/bluetooth/mesh/adv_legacy.c | 4 ++++ 4 files changed, 11 insertions(+), 3 deletions(-) diff --git a/subsys/bluetooth/mesh/adv.c b/subsys/bluetooth/mesh/adv.c index 00e2a4aa7bb..d51f0946b85 100644 --- a/subsys/bluetooth/mesh/adv.c +++ b/subsys/bluetooth/mesh/adv.c @@ -76,7 +76,7 @@ void bt_mesh_adv_send_start(uint16_t duration, int err, struct bt_mesh_adv_ctx * } } -static void bt_mesh_adv_send_end(int err, struct bt_mesh_adv_ctx const *ctx) +void bt_mesh_adv_send_end(int err, struct bt_mesh_adv_ctx const *ctx) { if (ctx->started && ctx->cb && ctx->cb->end) { ctx->cb->end(err, ctx->cb_data); @@ -136,7 +136,6 @@ void bt_mesh_adv_unref(struct bt_mesh_adv *adv) } struct k_mem_slab *slab = &local_adv_pool; - struct bt_mesh_adv_ctx ctx = adv->ctx; #if defined(CONFIG_BT_MESH_RELAY) if (adv->ctx.tag == BT_MESH_ADV_TAG_RELAY) { @@ -151,7 +150,6 @@ void bt_mesh_adv_unref(struct bt_mesh_adv *adv) #endif k_mem_slab_free(slab, (void *)adv); - bt_mesh_adv_send_end(0, &ctx); } struct bt_mesh_adv *bt_mesh_adv_create(enum bt_mesh_adv_type type, diff --git a/subsys/bluetooth/mesh/adv.h b/subsys/bluetooth/mesh/adv.h index 0c936a1aa52..e79d082862a 100644 --- a/subsys/bluetooth/mesh/adv.h +++ b/subsys/bluetooth/mesh/adv.h @@ -76,6 +76,7 @@ struct bt_mesh_adv *bt_mesh_adv_create(enum bt_mesh_adv_type type, void bt_mesh_adv_send(struct bt_mesh_adv *adv, const struct bt_mesh_send_cb *cb, void *cb_data); +void bt_mesh_adv_send_end(int err, struct bt_mesh_adv_ctx const *ctx); struct bt_mesh_adv *bt_mesh_adv_get(k_timeout_t timeout); diff --git a/subsys/bluetooth/mesh/adv_ext.c b/subsys/bluetooth/mesh/adv_ext.c index 48d83e8b05a..c19eb2cc00d 100644 --- a/subsys/bluetooth/mesh/adv_ext.c +++ b/subsys/bluetooth/mesh/adv_ext.c @@ -259,7 +259,12 @@ static void send_pending_adv(struct k_work *work) atomic_clear_bit(ext_adv->flags, ADV_FLAG_PROXY_START); if (ext_adv->adv) { + struct bt_mesh_adv_ctx ctx = ext_adv->adv->ctx; + + ext_adv->adv->ctx.started = 0; bt_mesh_adv_unref(ext_adv->adv); + bt_mesh_adv_send_end(0, &ctx); + ext_adv->adv = NULL; } diff --git a/subsys/bluetooth/mesh/adv_legacy.c b/subsys/bluetooth/mesh/adv_legacy.c index d4003e497bb..135f444b9b4 100644 --- a/subsys/bluetooth/mesh/adv_legacy.c +++ b/subsys/bluetooth/mesh/adv_legacy.c @@ -182,7 +182,11 @@ static void adv_thread(void *p1, void *p2, void *p3) adv_send(adv); } + struct bt_mesh_adv_ctx ctx = adv->ctx; + + adv->ctx.started = 0; bt_mesh_adv_unref(adv); + bt_mesh_adv_send_end(0, &ctx); /* Give other threads a chance to run */ k_yield(); From fcfc99a21d25b38aad036937f6aabef244390644 Mon Sep 17 00:00:00 2001 From: Pavel Vasilyev Date: Mon, 22 Jan 2024 14:49:19 +0100 Subject: [PATCH 2986/3723] Bluetooth: Mesh: Add error code for bt_mesh_adv_terminate Return error code to let an implementation know if the adv was actually stopped (was scheduled) or not. Signed-off-by: Pavel Vasilyev --- subsys/bluetooth/mesh/adv.h | 2 +- subsys/bluetooth/mesh/adv_ext.c | 10 ++++++---- subsys/bluetooth/mesh/adv_legacy.c | 4 +++- 3 files changed, 10 insertions(+), 6 deletions(-) diff --git a/subsys/bluetooth/mesh/adv.h b/subsys/bluetooth/mesh/adv.h index e79d082862a..6595badc9f9 100644 --- a/subsys/bluetooth/mesh/adv.h +++ b/subsys/bluetooth/mesh/adv.h @@ -101,7 +101,7 @@ void bt_mesh_adv_local_ready(void); void bt_mesh_adv_relay_ready(void); -void bt_mesh_adv_terminate(struct bt_mesh_adv *adv); +int bt_mesh_adv_terminate(struct bt_mesh_adv *adv); void bt_mesh_adv_friend_ready(void); diff --git a/subsys/bluetooth/mesh/adv_ext.c b/subsys/bluetooth/mesh/adv_ext.c index c19eb2cc00d..592081f2773 100644 --- a/subsys/bluetooth/mesh/adv_ext.c +++ b/subsys/bluetooth/mesh/adv_ext.c @@ -370,7 +370,7 @@ void bt_mesh_adv_friend_ready(void) } } -void bt_mesh_adv_terminate(struct bt_mesh_adv *adv) +int bt_mesh_adv_terminate(struct bt_mesh_adv *adv) { int err; @@ -382,13 +382,13 @@ void bt_mesh_adv_terminate(struct bt_mesh_adv *adv) } if (!atomic_test_bit(ext_adv->flags, ADV_FLAG_ACTIVE)) { - return; + return 0; } err = bt_le_ext_adv_stop(ext_adv->instance); if (err) { LOG_ERR("Failed to stop adv %d", err); - return; + return err; } /* Do not call `cb:end`, since this user action */ @@ -398,8 +398,10 @@ void bt_mesh_adv_terminate(struct bt_mesh_adv *adv) k_work_submit(&ext_adv->work); - return; + return 0; } + + return -EINVAL; } void bt_mesh_adv_init(void) diff --git a/subsys/bluetooth/mesh/adv_legacy.c b/subsys/bluetooth/mesh/adv_legacy.c index 135f444b9b4..867c91bbf8e 100644 --- a/subsys/bluetooth/mesh/adv_legacy.c +++ b/subsys/bluetooth/mesh/adv_legacy.c @@ -214,9 +214,11 @@ void bt_mesh_adv_gatt_update(void) bt_mesh_adv_get_cancel(); } -void bt_mesh_adv_terminate(struct bt_mesh_adv *adv) +int bt_mesh_adv_terminate(struct bt_mesh_adv *adv) { ARG_UNUSED(adv); + + return 0; } void bt_mesh_adv_init(void) From 54c048989d343ecfd1a8dd00ce9993cbd11685d8 Mon Sep 17 00:00:00 2001 From: Pavel Vasilyev Date: Mon, 22 Jan 2024 14:50:19 +0100 Subject: [PATCH 2987/3723] Bluetooth: Mesh: Send provisioning PDUs with randomized delay This implements the following statement from the section 5.3.3: Each Generic Provisioning PDU shall be sent after a random delay between 20 and 50 milliseconds. Signed-off-by: Pavel Vasilyev --- subsys/bluetooth/mesh/pb_adv.c | 224 +++++++++++++++++++++++++-------- 1 file changed, 174 insertions(+), 50 deletions(-) diff --git a/subsys/bluetooth/mesh/pb_adv.c b/subsys/bluetooth/mesh/pb_adv.c index f723ff48c14..c5c56b1e5b0 100644 --- a/subsys/bluetooth/mesh/pb_adv.c +++ b/subsys/bluetooth/mesh/pb_adv.c @@ -67,6 +67,8 @@ enum { ADV_LINK_INVALID, /* Error occurred during provisioning */ ADV_ACK_PENDING, /* An acknowledgment is being sent */ ADV_PROVISIONER, /* The link was opened as provisioner */ + ADV_LINK_ACK_SENDING, /* Link Ack tx was scheduled but not finished. */ + ADV_SENDING, /* Sending any PDU */ ADV_NUM_FLAGS, }; @@ -100,15 +102,30 @@ struct pb_adv { /* Transaction timeout in seconds */ uint8_t timeout; - /* Pending outgoing adv(s) */ + /* Pending outgoing adv(s) (Link Open, Gen Trans Start and Gen Trans Cont) */ struct bt_mesh_adv *adv[3]; + /* Index of the next adv to be sent */ + int next; + prov_bearer_send_complete_t cb; void *cb_data; /* Retransmit timer */ struct k_work_delayable retransmit; + + /* Unacked adv buffers (Link Ack, Link Close and Gen Trans Ack). Array size is + * hardcoded to 2 allowing to send Gen Trans Ack and Link Close at the same time. + */ + struct unacked_adv_ctx { + struct bt_mesh_adv *adv; + prov_bearer_send_complete_t cb; + void *cb_data; + } unacked[2]; + + /* Last sent unacked[] buffer */ + int last_unacked; } tx; /* Protocol timeout */ @@ -132,28 +149,124 @@ static void link_close(struct prov_rx *rx, struct net_buf_simple *buf); static void prov_link_close(enum prov_bearer_link_status status); static void close_link(enum prov_bearer_link_status status); -static void buf_sent(int err, void *user_data) +static void tx_work_handler(struct k_work *work); +static K_WORK_DELAYABLE_DEFINE(tx_work, tx_work_handler); + +static void tx_schedule(void) { - enum prov_bearer_link_status reason = (enum prov_bearer_link_status)(int)user_data; + uint16_t random_delay; - if (atomic_test_and_clear_bit(link.flags, ADV_LINK_CLOSING)) { - close_link(reason); + if (atomic_test_bit(link.flags, ADV_SENDING)) { + LOG_DBG("Another tx is in progress"); return; } + + (void)bt_rand(&random_delay, sizeof(random_delay)); + random_delay = 20 + (random_delay % 30); + + LOG_DBG("Next PDU delayed by %ums", random_delay); + + (void)k_work_schedule(&tx_work, K_MSEC(random_delay)); +} + +static int send_unacked(struct bt_mesh_adv *adv, prov_bearer_send_complete_t cb, + void *cb_data) +{ + for (int i = 0; i < ARRAY_SIZE(link.tx.unacked); i++) { + if (link.tx.unacked[i].adv != NULL) { + continue; + } + + link.tx.unacked[i].adv = adv; + link.tx.unacked[i].cb = cb; + link.tx.unacked[i].cb_data = cb_data; + + tx_schedule(); + + return 0; + } + + LOG_WRN("No memory to send unacked PDU: %s", bt_hex(adv->b.data, adv->b.len)); + return -ENOMEM; +} + +static void send_reliable(void) +{ + /* Dropping next tx adv index to start transmission from the first adv buffer. */ + link.tx.next = 0; + + tx_schedule(); +} + +static void delayed_adv_send_end(int err, void *user_data) +{ + bool unacked = (bool)user_data; + struct unacked_adv_ctx *unacked_adv = &link.tx.unacked[link.tx.last_unacked]; + + if (unacked && unacked_adv->adv != NULL) { + if (unacked_adv->cb) { + unacked_adv->cb(err, unacked_adv->cb_data); + } + + bt_mesh_adv_unref(unacked_adv->adv); + unacked_adv->adv = NULL; + } + + atomic_clear_bit(link.flags, ADV_SENDING); + tx_schedule(); } -static void buf_start(uint16_t duration, int err, void *user_data) +static void delayed_adv_send_start(uint16_t duration, int err, void *user_data) { if (err) { - buf_sent(err, user_data); + delayed_adv_send_end(err, user_data); } } -static struct bt_mesh_send_cb buf_sent_cb = { - .start = buf_start, - .end = buf_sent, +static const struct bt_mesh_send_cb delayed_adv_send_cb = { + .start = delayed_adv_send_start, + .end = delayed_adv_send_end, }; +static void tx_work_handler(struct k_work *work) +{ + int i; + + /* Send Link Ack, Link Close and Gen Trans Ack first. */ + for (i = 0; i < ARRAY_SIZE(link.tx.unacked); i++) { + int idx = (i + link.tx.last_unacked) % ARRAY_SIZE(link.tx.unacked); + struct unacked_adv_ctx *unacked = &link.tx.unacked[idx]; + + if (!unacked->adv) { + continue; + } + + atomic_set_bit(link.flags, ADV_SENDING); + bt_mesh_adv_send(unacked->adv, &delayed_adv_send_cb, (void *)true); + + link.tx.last_unacked = idx; + + return; + } + + /* Send Trans Start, Trans Cont and Link Open */ + if (link.tx.next >= ARRAY_SIZE(link.tx.adv) || link.tx.adv[link.tx.next] == NULL) { + LOG_DBG("All PDUs were sent"); + return; + } + + atomic_set_bit(link.flags, ADV_SENDING); + bt_mesh_adv_send(link.tx.adv[link.tx.next], &delayed_adv_send_cb, (void *)false); + + link.tx.next++; + + if (link.tx.next == ARRAY_SIZE(link.tx.adv) || link.tx.adv[link.tx.next] == NULL) { + /* All ack-able PDUs are sent. Now we can run the retransmit timer. */ + LOG_DBG("Starting retransmit timer"); + k_work_reschedule(&link.tx.retransmit, RETRANSMIT_TIMEOUT); + } +} + static uint8_t last_seg(uint16_t len) { if (len <= START_PAYLOAD_MAX) { @@ -168,9 +281,11 @@ static uint8_t last_seg(uint16_t len) static void free_segments(void) { int i; + bool canceled = false; for (i = 0; i < ARRAY_SIZE(link.tx.adv); i++) { struct bt_mesh_adv *adv = link.tx.adv[i]; + int err; if (!adv) { break; @@ -180,14 +295,23 @@ static void free_segments(void) /* Terminate active adv */ if (adv->ctx.busy == 0U) { - bt_mesh_adv_terminate(adv); + err = bt_mesh_adv_terminate(adv); + if (err == 0) { + canceled = true; + } } else { /* Mark as canceled */ adv->ctx.busy = 0U; + canceled = true; } bt_mesh_adv_unref(adv); } + + if (canceled) { + atomic_clear_bit(link.flags, ADV_SENDING); + tx_schedule(); + } } static uint8_t next_transaction_id(uint8_t id) @@ -268,7 +392,7 @@ static struct bt_mesh_adv *adv_create(uint8_t retransmits) return adv; } -static void ack_complete(uint16_t duration, int err, void *user_data) +static void ack_complete(int err, void *user_data) { LOG_DBG("xact 0x%x complete", (uint8_t)link.tx.pending_ack); atomic_clear_bit(link.flags, ADV_ACK_PENDING); @@ -323,12 +447,9 @@ static void protocol_timeout(struct k_work *work) static void gen_prov_ack_send(uint8_t xact_id) { - static const struct bt_mesh_send_cb cb = { - .start = ack_complete, - }; - const struct bt_mesh_send_cb *complete; struct bt_mesh_adv *adv; bool pending = atomic_test_and_set_bit(link.flags, ADV_ACK_PENDING); + int err; LOG_DBG("xact_id 0x%x", xact_id); @@ -343,19 +464,18 @@ static void gen_prov_ack_send(uint8_t xact_id) return; } - if (pending) { - complete = NULL; - } else { + if (!pending) { link.tx.pending_ack = xact_id; - complete = &cb; } net_buf_simple_add_be32(&adv->b, link.id); net_buf_simple_add_u8(&adv->b, xact_id); net_buf_simple_add_u8(&adv->b, GPC_ACK); - bt_mesh_adv_send(adv, complete, NULL); - bt_mesh_adv_unref(adv); + err = send_unacked(adv, pending ? NULL : ack_complete, NULL); + if (err) { + atomic_clear_bit(link.flags, ADV_ACK_PENDING); + } } static void gen_prov_cont(struct prov_rx *rx, struct net_buf_simple *buf) @@ -591,29 +711,6 @@ static void gen_prov_recv(struct prov_rx *rx, struct net_buf_simple *buf) * TX ******************************************************************************/ -static void send_reliable(void) -{ - int i; - - for (i = 0; i < ARRAY_SIZE(link.tx.adv); i++) { - struct bt_mesh_adv *adv = link.tx.adv[i]; - - if (!adv) { - break; - } - - if (adv->ctx.busy) { - continue; - } - - LOG_DBG("%u bytes: %s", adv->b.len, bt_hex(adv->b.data, adv->b.len)); - - bt_mesh_adv_send(adv, NULL, NULL); - } - - k_work_reschedule(&link.tx.retransmit, RETRANSMIT_TIMEOUT); -} - static void prov_retransmit(struct k_work *work) { LOG_DBG(""); @@ -669,8 +766,22 @@ static int bearer_ctl_send(struct bt_mesh_adv *adv) return 0; } +static void buf_sent(int err, void *user_data) +{ + enum prov_bearer_link_status reason = (enum prov_bearer_link_status)(int)user_data; + + atomic_clear_bit(link.flags, ADV_LINK_ACK_SENDING); + + if (atomic_test_and_clear_bit(link.flags, ADV_LINK_CLOSING)) { + close_link(reason); + return; + } +} + static int bearer_ctl_send_unacked(struct bt_mesh_adv *adv, void *user_data) { + int err; + if (!adv) { return -ENOMEM; } @@ -678,10 +789,12 @@ static int bearer_ctl_send_unacked(struct bt_mesh_adv *adv, void *user_data) prov_clear_tx(); k_work_reschedule(&link.prot_timer, bt_mesh_prov_protocol_timeout_get()); - bt_mesh_adv_send(adv, &buf_sent_cb, user_data); - bt_mesh_adv_unref(adv); + err = send_unacked(adv, &buf_sent, user_data); + if (err) { + bt_mesh_adv_unref(adv); + } - return 0; + return err; } static int prov_send_adv(struct net_buf_simple *msg, @@ -772,8 +885,13 @@ static void link_open(struct prov_rx *rx, struct net_buf_simple *buf) return; } - LOG_DBG("Resending link ack"); + if (atomic_test_bit(link.flags, ADV_LINK_ACK_SENDING)) { + LOG_DBG("Still sending Link Ack"); + return; + } + /* Ignore errors, message will be attempted again if we keep receiving link open: */ + atomic_set_bit(link.flags, ADV_LINK_ACK_SENDING); (void)bearer_ctl_send_unacked( ctl_adv_create(LINK_ACK, NULL, 0, RETRANSMITS_ACK), (void *)PROV_BEARER_LINK_STATUS_SUCCESS); @@ -789,6 +907,7 @@ static void link_open(struct prov_rx *rx, struct net_buf_simple *buf) atomic_set_bit(link.flags, ADV_LINK_ACTIVE); net_buf_simple_reset(link.rx.buf); + atomic_set_bit(link.flags, ADV_LINK_ACK_SENDING); err = bearer_ctl_send_unacked( ctl_adv_create(LINK_ACK, NULL, 0, RETRANSMITS_ACK), (void *)PROV_BEARER_LINK_STATUS_SUCCESS); @@ -923,6 +1042,8 @@ static int prov_link_accept(const struct prov_bearer_cb *cb, void *cb_data) static void prov_link_close(enum prov_bearer_link_status status) { + int err; + if (atomic_test_and_set_bit(link.flags, ADV_LINK_CLOSING)) { return; } @@ -934,9 +1055,12 @@ static void prov_link_close(enum prov_bearer_link_status status) */ link.tx.timeout = CLOSING_TIMEOUT; /* Ignore errors, the link will time out eventually if this doesn't get sent */ - bearer_ctl_send_unacked( + err = bearer_ctl_send_unacked( ctl_adv_create(LINK_CLOSE, &status, 1, RETRANSMITS_LINK_CLOSE), (void *)status); + if (err) { + close_link(status); + } } void bt_mesh_pb_adv_init(void) From c9208b3864c1dbc1899c006577b62d5083505412 Mon Sep 17 00:00:00 2001 From: honglin leng Date: Wed, 20 Dec 2023 02:39:27 +0800 Subject: [PATCH 2988/3723] arm64: smp: Fix cache operations in the SMP The arm64_cpu_boot_params will be read on other cores call sys_cache_data_flush_range flush the data from the cache to RAM. This ensures that other cores can access the correct data. Signed-off-by: honglin leng --- arch/arm64/core/smp.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/arch/arm64/core/smp.c b/arch/arm64/core/smp.c index 20faef06108..97fd60b4236 100644 --- a/arch/arm64/core/smp.c +++ b/arch/arm64/core/smp.c @@ -101,7 +101,7 @@ void arch_start_cpu(int cpu_num, k_thread_stack_t *stack, int sz, /* store mpid last as this is our synchronization point */ arm64_cpu_boot_params.mpid = cpu_mpid; - sys_cache_data_invd_range((void *)&arm64_cpu_boot_params, + sys_cache_data_flush_range((void *)&arm64_cpu_boot_params, sizeof(arm64_cpu_boot_params)); if (pm_cpu_on(cpu_mpid, (uint64_t)&__start)) { From 77d8c2768e9c8b1d09a42b45639f9b07c296a0d1 Mon Sep 17 00:00:00 2001 From: Jonathan Rico Date: Tue, 9 Jan 2024 14:40:08 +0100 Subject: [PATCH 2989/3723] Bluetooth: L2CAP: initialize `servers` slist Somehow it slipped through the cracks and didn't crash before. Signed-off-by: Jonathan Rico --- subsys/bluetooth/host/l2cap.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/subsys/bluetooth/host/l2cap.c b/subsys/bluetooth/host/l2cap.c index 05900f34885..7ba636490b8 100644 --- a/subsys/bluetooth/host/l2cap.c +++ b/subsys/bluetooth/host/l2cap.c @@ -96,7 +96,7 @@ static void free_tx_meta_data(struct l2cap_tx_meta_data *data) #define l2cap_tx_meta_data(buf) (((struct l2cap_tx_meta *)net_buf_user_data(buf))->data) -static sys_slist_t servers; +static sys_slist_t servers = SYS_SLIST_STATIC_INIT(&servers); static void l2cap_tx_buf_destroy(struct bt_conn *conn, struct net_buf *buf, int err) { From 3a4fd5e23dd0bfff99a30dc50ed9a9a2ee4baaf3 Mon Sep 17 00:00:00 2001 From: Jonathan Rico Date: Tue, 9 Jan 2024 14:40:50 +0100 Subject: [PATCH 2990/3723] Bluetooth: L2CAP: remove cb/userdata from TX metadata They were never used. Only thing to remove is `cid`. Signed-off-by: Jonathan Rico --- subsys/bluetooth/host/l2cap.c | 31 +++++++------------------------ 1 file changed, 7 insertions(+), 24 deletions(-) diff --git a/subsys/bluetooth/host/l2cap.c b/subsys/bluetooth/host/l2cap.c index 7ba636490b8..c128ee14793 100644 --- a/subsys/bluetooth/host/l2cap.c +++ b/subsys/bluetooth/host/l2cap.c @@ -72,8 +72,10 @@ NET_BUF_POOL_FIXED_DEFINE(disc_pool, 1, struct l2cap_tx_meta_data { uint16_t cid; - bt_conn_tx_cb_t cb; - void *user_data; + /* FIXME: remove this. + * `servers` gets messed up somehow if not present + */ + uint16_t pad; }; struct l2cap_tx_meta { @@ -101,16 +103,9 @@ static sys_slist_t servers = SYS_SLIST_STATIC_INIT(&servers); static void l2cap_tx_buf_destroy(struct bt_conn *conn, struct net_buf *buf, int err) { struct l2cap_tx_meta_data *data = l2cap_tx_meta_data(buf); - bt_conn_tx_cb_t cb = data->cb; - void *cb_user_data = data->user_data; free_tx_meta_data(data); net_buf_unref(buf); - - /* Make sure to call associated callback, if any */ - if (cb) { - cb(conn, cb_user_data, err); - } } #endif /* CONFIG_BT_L2CAP_DYNAMIC_CHANNEL */ @@ -1855,8 +1850,6 @@ static void l2cap_chan_sdu_sent(struct bt_conn *conn, void *user_data, int err) { struct l2cap_tx_meta_data *data = user_data; struct bt_l2cap_chan *chan; - bt_conn_tx_cb_t cb = data->cb; - void *cb_user_data = data->user_data; uint16_t cid = data->cid; LOG_DBG("conn %p CID 0x%04x err %d", conn, cid, err); @@ -1864,19 +1857,15 @@ static void l2cap_chan_sdu_sent(struct bt_conn *conn, void *user_data, int err) free_tx_meta_data(data); if (err) { - if (cb) { - cb(conn, cb_user_data, err); - } + LOG_DBG("error %d when sending SDU", err); return; } chan = bt_l2cap_le_lookup_tx_cid(conn, cid); if (!chan) { - /* Received SDU sent callback for disconnected channel */ - if (cb) { - cb(conn, cb_user_data, -ESHUTDOWN); - } + LOG_DBG("got SDU sent cb for disconnected chan (CID %u)", cid); + return; } @@ -1884,10 +1873,6 @@ static void l2cap_chan_sdu_sent(struct bt_conn *conn, void *user_data, int err) chan->ops->sent(chan); } - if (cb) { - cb(conn, cb_user_data, 0); - } - /* Resume the current channel */ l2cap_chan_tx_resume(BT_L2CAP_LE_CHAN(chan)); } @@ -3173,8 +3158,6 @@ static int bt_l2cap_dyn_chan_send(struct bt_l2cap_le_chan *le_chan, struct net_b /* Put buffer on TX queue */ data->cid = le_chan->tx.cid; - data->cb = NULL; - data->user_data = NULL; l2cap_tx_meta_data(buf) = data; net_buf_put(&le_chan->tx_queue, buf); From 2d9b56d7139babf2a934b6df28ccb931b271562a Mon Sep 17 00:00:00 2001 From: Jonathan Rico Date: Tue, 9 Jan 2024 15:09:10 +0100 Subject: [PATCH 2991/3723] Bluetooth: L2CAP: remove metadata allocation The only thing we put in there is the CID and that fits comfortably into the (at least) 4-byte void pointer `user_data`. This removes the dependency between `CONFIG_BT_ATT_TX_COUNT` and `CONFIG_BT_L2CAP_TX_BUF_COUNT` since previously there was still a need for an L2CAP context for every TX'd buffer. Signed-off-by: Jonathan Rico --- subsys/bluetooth/host/l2cap.c | 86 +++-------------------------------- 1 file changed, 7 insertions(+), 79 deletions(-) diff --git a/subsys/bluetooth/host/l2cap.c b/subsys/bluetooth/host/l2cap.c index c128ee14793..e79e878ccbf 100644 --- a/subsys/bluetooth/host/l2cap.c +++ b/subsys/bluetooth/host/l2cap.c @@ -70,41 +70,10 @@ NET_BUF_POOL_FIXED_DEFINE(disc_pool, 1, #define l2cap_lookup_ident(conn, ident) __l2cap_lookup_ident(conn, ident, false) #define l2cap_remove_ident(conn, ident) __l2cap_lookup_ident(conn, ident, true) -struct l2cap_tx_meta_data { - uint16_t cid; - /* FIXME: remove this. - * `servers` gets messed up somehow if not present - */ - uint16_t pad; -}; - -struct l2cap_tx_meta { - struct l2cap_tx_meta_data *data; -}; - -static struct l2cap_tx_meta_data l2cap_tx_meta_data_storage[CONFIG_BT_CONN_TX_MAX]; -K_FIFO_DEFINE(free_l2cap_tx_meta_data); - -static struct l2cap_tx_meta_data *alloc_tx_meta_data(void) -{ - return k_fifo_get(&free_l2cap_tx_meta_data, K_NO_WAIT); -} - -static void free_tx_meta_data(struct l2cap_tx_meta_data *data) -{ - (void)memset(data, 0, sizeof(*data)); - k_fifo_put(&free_l2cap_tx_meta_data, data); -} - -#define l2cap_tx_meta_data(buf) (((struct l2cap_tx_meta *)net_buf_user_data(buf))->data) - static sys_slist_t servers = SYS_SLIST_STATIC_INIT(&servers); static void l2cap_tx_buf_destroy(struct bt_conn *conn, struct net_buf *buf, int err) { - struct l2cap_tx_meta_data *data = l2cap_tx_meta_data(buf); - - free_tx_meta_data(data); net_buf_unref(buf); } #endif /* CONFIG_BT_L2CAP_DYNAMIC_CHANNEL */ @@ -1848,14 +1817,11 @@ static void l2cap_chan_tx_resume(struct bt_l2cap_le_chan *ch) static void l2cap_chan_sdu_sent(struct bt_conn *conn, void *user_data, int err) { - struct l2cap_tx_meta_data *data = user_data; struct bt_l2cap_chan *chan; - uint16_t cid = data->cid; + uint16_t cid = POINTER_TO_UINT(user_data); LOG_DBG("conn %p CID 0x%04x err %d", conn, cid, err); - free_tx_meta_data(data); - if (err) { LOG_DBG("error %d when sending SDU", err); @@ -1879,16 +1845,16 @@ static void l2cap_chan_sdu_sent(struct bt_conn *conn, void *user_data, int err) static void l2cap_chan_seg_sent(struct bt_conn *conn, void *user_data, int err) { - struct l2cap_tx_meta_data *data = user_data; struct bt_l2cap_chan *chan; + uint16_t cid = POINTER_TO_UINT(user_data); - LOG_DBG("conn %p CID 0x%04x err %d", conn, data->cid, err); + LOG_DBG("conn %p CID 0x%04x err %d", conn, cid, err); if (err) { return; } - chan = bt_l2cap_le_lookup_tx_cid(conn, data->cid); + chan = bt_l2cap_le_lookup_tx_cid(conn, cid); if (!chan) { /* Received segment sent callback for disconnected channel */ return; @@ -1987,7 +1953,8 @@ static int l2cap_chan_le_send(struct bt_l2cap_le_chan *ch, * considered lost, as the lower layers are free to re-use it as they * see fit. Reading from it later is obviously a no-no. */ - err = bt_l2cap_send_cb(ch->chan.conn, ch->tx.cid, seg, cb, l2cap_tx_meta_data(buf)); + err = bt_l2cap_send_cb(ch->chan.conn, ch->tx.cid, seg, + cb, UINT_TO_POINTER(ch->tx.cid)); if (err) { LOG_DBG("Unable to send seg %d", err); @@ -2024,33 +1991,12 @@ static int l2cap_chan_le_send(struct bt_l2cap_le_chan *ch, } /* return next netbuf fragment if present, also assign metadata */ -static struct net_buf *prepare_next_frag(struct net_buf *parent, - struct l2cap_tx_meta_data *meta) -{ - /* this does an unref on `parent` */ - struct net_buf *next = net_buf_frag_del(NULL, parent); - - if (next) { - LOG_DBG("process next frag: %p -> %p", parent, next); - - /* Copy the l2cap metadata ref to the next buffer in the chain. - * We need it to figure out which channel the PDU has been sent - * on, in order to either send the rest of the SDU or call the - * application callback. - */ - l2cap_tx_meta_data(next) = meta; - } - - return next; -} - static int l2cap_chan_le_send_sdu(struct bt_l2cap_le_chan *ch, struct net_buf **buf) { int ret; size_t sent, rem_len, frag_len; struct net_buf *frag; - struct l2cap_tx_meta_data *meta = l2cap_tx_meta_data(*buf); frag = *buf; if (!frag->len && frag->frags) { @@ -2079,7 +2025,7 @@ static int l2cap_chan_le_send_sdu(struct bt_l2cap_le_chan *ch, * proceed to the next fragment of the netbuf chain. */ if (ret == frag_len) { - frag = prepare_next_frag(frag, meta); + frag = net_buf_frag_del(NULL, frag); } } @@ -2821,15 +2767,6 @@ void bt_l2cap_init(void) if (IS_ENABLED(CONFIG_BT_BREDR)) { bt_l2cap_br_init(); } - -#if defined(CONFIG_BT_L2CAP_DYNAMIC_CHANNEL) - k_fifo_init(&free_l2cap_tx_meta_data); - for (size_t i = 0; i < ARRAY_SIZE(l2cap_tx_meta_data_storage); i++) { - (void)memset(&l2cap_tx_meta_data_storage[i], 0, - sizeof(l2cap_tx_meta_data_storage[i])); - k_fifo_put(&free_l2cap_tx_meta_data, &l2cap_tx_meta_data_storage[i]); - } -#endif /* CONFIG_BT_L2CAP_DYNAMIC_CHANNEL */ } #if defined(CONFIG_BT_L2CAP_DYNAMIC_CHANNEL) @@ -3109,7 +3046,6 @@ int bt_l2cap_chan_disconnect(struct bt_l2cap_chan *chan) static int bt_l2cap_dyn_chan_send(struct bt_l2cap_le_chan *le_chan, struct net_buf *buf) { - struct l2cap_tx_meta_data *data; uint16_t sdu_len = net_buf_frags_len(buf); LOG_DBG("chan %p buf %p", le_chan, buf); @@ -3128,12 +3064,6 @@ static int bt_l2cap_dyn_chan_send(struct bt_l2cap_le_chan *le_chan, struct net_b return -EINVAL; } - data = alloc_tx_meta_data(); - if (!data) { - LOG_WRN("Unable to allocate TX context"); - return -ENOBUFS; - } - /* Prepend SDU "header". * * L2CAP LE CoC SDUs are segmented into PDUs and sent over so-called @@ -3157,8 +3087,6 @@ static int bt_l2cap_dyn_chan_send(struct bt_l2cap_le_chan *le_chan, struct net_b net_buf_push_le16(buf, sdu_len); /* Put buffer on TX queue */ - data->cid = le_chan->tx.cid; - l2cap_tx_meta_data(buf) = data; net_buf_put(&le_chan->tx_queue, buf); /* Always process the queue in the same context */ From 5a125a619c8858324ff172add20ca664b0cb91e7 Mon Sep 17 00:00:00 2001 From: Ryan McClelland Date: Tue, 1 Aug 2023 22:01:55 -0700 Subject: [PATCH 2992/3723] regulator: add active-discharge api Add an active discharge api for regulators. This uses the already existing but previously unused regulator-active-discharge property. Signed-off-by: Ryan McClelland --- drivers/regulator/regulator_common.c | 10 ++++ include/zephyr/drivers/regulator.h | 80 ++++++++++++++++++++++++++-- 2 files changed, 86 insertions(+), 4 deletions(-) diff --git a/drivers/regulator/regulator_common.c b/drivers/regulator/regulator_common.c index f4f583d6f88..f2d9f6275e6 100644 --- a/drivers/regulator/regulator_common.c +++ b/drivers/regulator/regulator_common.c @@ -1,5 +1,6 @@ /* * Copyright 2022 Nordic Semiconductor ASA + * Copyright 2023 Meta Platforms * SPDX-License-Identifier: Apache-2.0 */ @@ -42,6 +43,15 @@ int regulator_common_init(const struct device *dev, bool is_enabled) } } + if (REGULATOR_ACTIVE_DISCHARGE_GET_BITS(config->flags) != + REGULATOR_ACTIVE_DISCHARGE_DEFAULT) { + ret = regulator_set_active_discharge(dev, + (bool)REGULATOR_ACTIVE_DISCHARGE_GET_BITS(config->flags)); + if (ret < 0) { + return ret; + } + } + if (config->init_uv > INT32_MIN) { ret = regulator_set_voltage(dev, config->init_uv, config->init_uv); if (ret < 0) { diff --git a/include/zephyr/drivers/regulator.h b/include/zephyr/drivers/regulator.h index 7cf905f774e..77e441d0dae 100644 --- a/include/zephyr/drivers/regulator.h +++ b/include/zephyr/drivers/regulator.h @@ -3,6 +3,7 @@ * Copyright (c) 2021 NXP * Copyright (c) 2022 Nordic Semiconductor ASA * Copyright (c) 2023 EPAM Systems + * Copyright (c) 2023 Meta Platforms * SPDX-License-Identifier: Apache-2.0 */ @@ -87,6 +88,10 @@ typedef int (*regulator_set_mode_t)(const struct device *dev, regulator_mode_t mode); typedef int (*regulator_get_mode_t)(const struct device *dev, regulator_mode_t *mode); +typedef int (*regulator_set_active_discharge_t)(const struct device *dev, + bool active_discharge); +typedef int (*regulator_get_active_discharge_t)(const struct device *dev, + bool *active_discharge); typedef int (*regulator_get_error_flags_t)( const struct device *dev, regulator_error_flags_t *flags); @@ -104,6 +109,8 @@ __subsystem struct regulator_driver_api { regulator_get_current_limit_t get_current_limit; regulator_set_mode_t set_mode; regulator_get_mode_t get_mode; + regulator_set_active_discharge_t set_active_discharge; + regulator_get_active_discharge_t get_active_discharge; regulator_get_error_flags_t get_error_flags; }; @@ -113,11 +120,27 @@ __subsystem struct regulator_driver_api { * @{ */ /** Indicates regulator must stay always ON */ -#define REGULATOR_ALWAYS_ON BIT(0) +#define REGULATOR_ALWAYS_ON BIT(0) /** Indicates regulator must be initialized ON */ -#define REGULATOR_BOOT_ON BIT(1) +#define REGULATOR_BOOT_ON BIT(1) /** Indicates if regulator must be enabled when initialized */ -#define REGULATOR_INIT_ENABLED (REGULATOR_ALWAYS_ON | REGULATOR_BOOT_ON) +#define REGULATOR_INIT_ENABLED (REGULATOR_ALWAYS_ON | REGULATOR_BOOT_ON) +/** Regulator active discharge state mask */ +#define REGULATOR_ACTIVE_DISCHARGE_MASK GENMASK(3, 2) +/** Regulator active discharge state flag position*/ +#define REGULATOR_ACTIVE_DISCHARGE_POS 2 +/** Disable regulator active discharge */ +#define REGULATOR_ACTIVE_DISCHARGE_DISABLE 0 +/** Enable regulator active discharge */ +#define REGULATOR_ACTIVE_DISCHARGE_ENABLE 1 +/** Leave regulator active discharge state as default */ +#define REGULATOR_ACTIVE_DISCHARGE_DEFAULT 2 +/** Regulator active discharge set bits */ +#define REGULATOR_ACTIVE_DISCHARGE_SET_BITS(x) \ + (((x) << REGULATOR_ACTIVE_DISCHARGE_POS) & REGULATOR_ACTIVE_DISCHARGE_MASK) +/** Regulator active discharge get bits */ +#define REGULATOR_ACTIVE_DISCHARGE_GET_BITS(x) \ + (((x) & REGULATOR_ACTIVE_DISCHARGE_MASK) >> REGULATOR_ACTIVE_DISCHARGE_POS) /** @} */ @@ -186,7 +209,10 @@ struct regulator_common_config { .flags = ((DT_PROP_OR(node_id, regulator_always_on, 0U) * \ REGULATOR_ALWAYS_ON) | \ (DT_PROP_OR(node_id, regulator_boot_on, 0U) * \ - REGULATOR_BOOT_ON)), \ + REGULATOR_BOOT_ON) | \ + (REGULATOR_ACTIVE_DISCHARGE_SET_BITS( \ + DT_PROP_OR(node_id, regulator_active_discharge, \ + REGULATOR_ACTIVE_DISCHARGE_DEFAULT)))), \ } /** @@ -635,6 +661,52 @@ static inline int regulator_get_mode(const struct device *dev, return api->get_mode(dev, mode); } +/** + * @brief Set active discharge setting. + * + * @param dev Regulator device instance. + * @param active_discharge Active discharge enable or disable. + * + * @retval 0 If successful. + * @retval -ENOSYS If function is not implemented. + * @retval -errno In case of any other error. + */ +static inline int regulator_set_active_discharge(const struct device *dev, + bool active_discharge) +{ + const struct regulator_driver_api *api = + (const struct regulator_driver_api *)dev->api; + + if (api->set_active_discharge == NULL) { + return -ENOSYS; + } + + return api->set_active_discharge(dev, active_discharge); +} + +/** + * @brief Get active discharge setting. + * + * @param dev Regulator device instance. + * @param[out] active_discharge Where active discharge will be stored. + * + * @retval 0 If successful. + * @retval -ENOSYS If function is not implemented. + * @retval -errno In case of any other error. + */ +static inline int regulator_get_active_discharge(const struct device *dev, + bool *active_discharge) +{ + const struct regulator_driver_api *api = + (const struct regulator_driver_api *)dev->api; + + if (api->get_active_discharge == NULL) { + return -ENOSYS; + } + + return api->get_active_discharge(dev, active_discharge); +} + /** * @brief Get active error flags. * From 97efd21ce9bef77d2fb9c6d8db7fae64abd08afe Mon Sep 17 00:00:00 2001 From: Ryan McClelland Date: Wed, 2 Aug 2023 13:05:15 -0700 Subject: [PATCH 2993/3723] tests: drivers: regulator: add api test for active discharge Add tests for active discharge apis not being implemented. Signed-off-by: Ryan McClelland --- drivers/regulator/regulator_fake.c | 6 +++ include/zephyr/drivers/regulator/fake.h | 4 ++ tests/drivers/regulator/api/app.overlay | 1 + tests/drivers/regulator/api/src/main.c | 60 +++++++++++++++++++++++-- 4 files changed, 68 insertions(+), 3 deletions(-) diff --git a/drivers/regulator/regulator_fake.c b/drivers/regulator/regulator_fake.c index 05b74bc56e1..129ef2f215e 100644 --- a/drivers/regulator/regulator_fake.c +++ b/drivers/regulator/regulator_fake.c @@ -39,6 +39,10 @@ DEFINE_FAKE_VALUE_FUNC(int, regulator_fake_set_mode, const struct device *, regulator_mode_t); DEFINE_FAKE_VALUE_FUNC(int, regulator_fake_get_mode, const struct device *, regulator_mode_t *); +DEFINE_FAKE_VALUE_FUNC(int, regulator_fake_set_active_discharge, const struct device *, + bool); +DEFINE_FAKE_VALUE_FUNC(int, regulator_fake_get_active_discharge, const struct device *, + bool *); DEFINE_FAKE_VALUE_FUNC(int, regulator_fake_get_error_flags, const struct device *, regulator_error_flags_t *); @@ -53,6 +57,8 @@ static struct regulator_driver_api api = { .get_current_limit = regulator_fake_get_current_limit, .set_mode = regulator_fake_set_mode, .get_mode = regulator_fake_get_mode, + .set_active_discharge = regulator_fake_set_active_discharge, + .get_active_discharge = regulator_fake_get_active_discharge, .get_error_flags = regulator_fake_get_error_flags, }; diff --git a/include/zephyr/drivers/regulator/fake.h b/include/zephyr/drivers/regulator/fake.h index 1bfffe6381b..d91161dbc7a 100644 --- a/include/zephyr/drivers/regulator/fake.h +++ b/include/zephyr/drivers/regulator/fake.h @@ -31,6 +31,10 @@ DECLARE_FAKE_VALUE_FUNC(int, regulator_fake_set_mode, const struct device *, regulator_mode_t); DECLARE_FAKE_VALUE_FUNC(int, regulator_fake_get_mode, const struct device *, regulator_mode_t *); +DECLARE_FAKE_VALUE_FUNC(int, regulator_fake_set_active_discharge, const struct device *, + bool); +DECLARE_FAKE_VALUE_FUNC(int, regulator_fake_get_active_discharge, const struct device *, + bool *); DECLARE_FAKE_VALUE_FUNC(int, regulator_fake_get_error_flags, const struct device *, regulator_error_flags_t *); diff --git a/tests/drivers/regulator/api/app.overlay b/tests/drivers/regulator/api/app.overlay index ea25ef18da6..25d1d8bb795 100644 --- a/tests/drivers/regulator/api/app.overlay +++ b/tests/drivers/regulator/api/app.overlay @@ -24,6 +24,7 @@ regulator-max-microamp = <200>; regulator-allowed-modes = <1 10>; regulator-initial-mode = <1>; + regulator-active-discharge = <1>; }; }; }; diff --git a/tests/drivers/regulator/api/src/main.c b/tests/drivers/regulator/api/src/main.c index cf598067301..648d761a8b4 100644 --- a/tests/drivers/regulator/api/src/main.c +++ b/tests/drivers/regulator/api/src/main.c @@ -108,15 +108,16 @@ ZTEST(regulator_api, test_common_config) zassert_equal(config->max_ua, INT32_MAX); zassert_equal(config->allowed_modes_cnt, 0U); zassert_equal(config->initial_mode, REGULATOR_INITIAL_MODE_UNKNOWN); - zassert_equal(config->flags, 0U); + zassert_equal(REGULATOR_ACTIVE_DISCHARGE_GET_BITS(config->flags), + REGULATOR_ACTIVE_DISCHARGE_DEFAULT); /* reg1: regulator-always-on */ config = reg1->config; - zassert_equal(config->flags, REGULATOR_ALWAYS_ON); + zassert_equal(config->flags & REGULATOR_ALWAYS_ON, REGULATOR_ALWAYS_ON); /* reg2: regulator-boot-on */ config = reg2->config; - zassert_equal(config->flags, REGULATOR_BOOT_ON); + zassert_equal(config->flags & REGULATOR_BOOT_ON, REGULATOR_BOOT_ON); /* reg3: regulator-min/max-microvolt/microamp */ config = reg3->config; @@ -127,6 +128,7 @@ ZTEST(regulator_api, test_common_config) zassert_equal(config->allowed_modes[0], 1U); zassert_equal(config->allowed_modes[1], 10U); zassert_equal(config->allowed_modes_cnt, 2U); + zassert_equal(REGULATOR_ACTIVE_DISCHARGE_GET_BITS(config->flags), 1U); } ZTEST(regulator_api, test_common_is_init_enabled) @@ -611,6 +613,58 @@ ZTEST(regulator_api, test_get_mode_not_implemented) zassert_equal(ret, -ENOSYS); } +ZTEST(regulator_api, test_set_active_discharge_not_implemented) +{ + int ret; + struct regulator_driver_api *api = + (struct regulator_driver_api *)reg0->api; + regulator_set_active_discharge_t set_active_discharge = api->set_active_discharge; + + api->set_active_discharge = NULL; + ret = regulator_set_active_discharge(reg0, false); + api->set_active_discharge = set_active_discharge; + + zassert_equal(ret, -ENOSYS); +} + +static int get_active_discharge_ok(const struct device *dev, bool *active_discharge) +{ + ARG_UNUSED(dev); + + *active_discharge = true; + + return 0; +} + +ZTEST(regulator_api, test_get_active_discharge_ok) +{ + bool active_discharge; + + RESET_FAKE(regulator_fake_get_active_discharge); + + regulator_fake_get_active_discharge_fake.custom_fake = get_active_discharge_ok; + + zassert_equal(regulator_get_active_discharge(reg0, &active_discharge), false); + zassert_equal(active_discharge, true); + zassert_equal(regulator_fake_get_active_discharge_fake.call_count, 1U); + zassert_equal(regulator_fake_get_active_discharge_fake.arg0_val, reg0); + zassert_equal(regulator_fake_get_active_discharge_fake.arg1_val, &active_discharge); +} + +ZTEST(regulator_api, test_get_active_discharge_not_implemented) +{ + int ret; + struct regulator_driver_api *api = + (struct regulator_driver_api *)reg0->api; + regulator_get_active_discharge_t get_active_discharge = api->get_active_discharge; + + api->get_active_discharge = NULL; + ret = regulator_get_active_discharge(reg0, NULL); + api->get_active_discharge = get_active_discharge; + + zassert_equal(ret, -ENOSYS); +} + static int get_mode_ok(const struct device *dev, regulator_mode_t *mode) { ARG_UNUSED(dev); From 0f8ab3cf2ddb4c1d15096970d51deba0ab4aae74 Mon Sep 17 00:00:00 2001 From: Ryan McClelland Date: Wed, 2 Aug 2023 12:53:02 -0700 Subject: [PATCH 2994/3723] drivers: regulator: add active discharge api to regulator shell Add the active discharge functions that can be called from the regulator shell. Signed-off-by: Ryan McClelland --- drivers/regulator/regulator_shell.c | 65 +++++++++++++++++++++++++++++ 1 file changed, 65 insertions(+) diff --git a/drivers/regulator/regulator_shell.c b/drivers/regulator/regulator_shell.c index 74aa1f22ca6..5dddbb5b8d7 100644 --- a/drivers/regulator/regulator_shell.c +++ b/drivers/regulator/regulator_shell.c @@ -364,6 +364,63 @@ static int cmd_modeget(const struct shell *sh, size_t argc, char **argv) return 0; } +static int cmd_adset(const struct shell *sh, size_t argc, char **argv) +{ + const struct device *dev; + bool ad; + int ret; + + ARG_UNUSED(argc); + + dev = device_get_binding(argv[1]); + if (dev == NULL) { + shell_error(sh, "Regulator device %s not available", argv[1]); + return -ENODEV; + } + + if (strcmp(argv[2], "enable")) { + ad = true; + } else if (strcmp(argv[2], "disable")) { + ad = false; + } else { + shell_error(sh, "Invalid parameter"); + return -EINVAL; + } + + ret = regulator_set_active_discharge(dev, ad); + if (ret < 0) { + shell_error(sh, "Could not set mode (%d)", ret); + return ret; + } + + return 0; +} + +static int cmd_adget(const struct shell *sh, size_t argc, char **argv) +{ + const struct device *dev; + bool ad; + int ret; + + ARG_UNUSED(argc); + + dev = device_get_binding(argv[1]); + if (dev == NULL) { + shell_error(sh, "Regulator device %s not available", argv[1]); + return -ENODEV; + } + + ret = regulator_get_active_discharge(dev, &ad); + if (ret < 0) { + shell_error(sh, "Could not get active discharge (%d)", ret); + return ret; + } + + shell_print(sh, "Active Discharge: %s", ad ? "enabled" : "disabled"); + + return 0; +} + static int cmd_errors(const struct shell *sh, size_t argc, char **argv) { const struct device *dev; @@ -503,6 +560,14 @@ SHELL_STATIC_SUBCMD_SET_CREATE( "Get regulator mode\n" "Usage: modeget ", cmd_modeget, 2, 0), + SHELL_CMD_ARG(adset, NULL, + "Set active discharge\n" + "Usage: adset ", + cmd_adset, 3, 0), + SHELL_CMD_ARG(adget, NULL, + "Get active discharge\n" + "Usage: adset ", + cmd_adget, 2, 0), SHELL_CMD_ARG(errors, &dsub_device_name, "Get errors\n" "Usage: errors ", From 4fb4f71f088d9bc6d6962e98e98e5dd589dc769b Mon Sep 17 00:00:00 2001 From: Ryan McClelland Date: Tue, 1 Aug 2023 22:03:33 -0700 Subject: [PATCH 2995/3723] drivers: regulator: pca9420: implement active discharge api Implement the api for controlling the active discharge setting within the pca9420. Signed-off-by: Ryan McClelland --- drivers/regulator/regulator_pca9420.c | 56 +++++++++++++++++++++++++++ 1 file changed, 56 insertions(+) diff --git a/drivers/regulator/regulator_pca9420.c b/drivers/regulator/regulator_pca9420.c index c7978242871..705d4f3a8e9 100644 --- a/drivers/regulator/regulator_pca9420.c +++ b/drivers/regulator/regulator_pca9420.c @@ -24,6 +24,8 @@ #define PCA9420_TOP_CNTL3 0x0CU /** Regulator status indication registers */ +/** @brief Active Discharge configuration for mode 0_0 */ +#define PCA9420_ACT_DISCHARGE_CNTL 0x21U /** @brief Mode configuration for mode 0_0 */ #define PCA9420_MODECFG_0_0 0x22U /** @brief Mode configuration for mode 0_1 */ @@ -81,6 +83,18 @@ /** @brief LDO2_OUT offset and voltage level mask */ #define PCA9420_MODECFG_3_LDO2_OUT_MASK 0x3FU #define PCA9420_MODECFG_3_LDO2_OUT_POS 0U +/** @brief SW1 active discharge control */ +#define PCA9420_ACT_DISCHARGE_CNTL_SW1_MASK 0x08U +#define PCA9420_ACT_DISCHARGE_CNTL_SW1_POS 4U +/** @brief SW2 active discharge control */ +#define PCA9420_ACT_DISCHARGE_CNTL_SW2_MASK 0x04U +#define PCA9420_ACT_DISCHARGE_CNTL_SW2_POS 3U +/** @brief LDO1 active discharge control */ +#define PCA9420_ACT_DISCHARGE_CNTL_LDO1_MASK 0x02U +#define PCA9420_ACT_DISCHARGE_CNTL_LDO1_POS 2U +/** @brief LDO2 active discharge control */ +#define PCA9420_ACT_DISCHARGE_CNTL_LDO2_MASK 0x01U +#define PCA9420_ACT_DISCHARGE_CNTL_LDO2_POS 1U /** VIN ILIM resolution, uA/LSB */ #define PCA9420_VIN_ILIM_UA_LSB 170000 @@ -99,6 +113,8 @@ struct regulator_pca9420_desc { uint8_t vsel_reg; uint8_t vsel_mask; uint8_t vsel_pos; + uint8_t ad_mask; + uint8_t ad_pos; int32_t max_ua; uint8_t num_ranges; const struct linear_range *ranges; @@ -159,6 +175,8 @@ static const struct regulator_pca9420_desc buck1_desc = { .vsel_mask = PCA9420_MODECFG_0_SW1_OUT_MASK, .vsel_pos = PCA9420_MODECFG_0_SW1_OUT_POS, .vsel_reg = PCA9420_MODECFG_0_0, + .ad_mask = PCA9420_ACT_DISCHARGE_CNTL_SW1_MASK, + .ad_pos = PCA9420_ACT_DISCHARGE_CNTL_SW1_POS, .max_ua = 250000, .ranges = buck1_ranges, .num_ranges = ARRAY_SIZE(buck1_ranges), @@ -171,6 +189,8 @@ static const struct regulator_pca9420_desc buck2_desc = { .vsel_mask = PCA9420_MODECFG_1_SW2_OUT_MASK, .vsel_pos = PCA9420_MODECFG_1_SW2_OUT_POS, .vsel_reg = PCA9420_MODECFG_0_1, + .ad_mask = PCA9420_ACT_DISCHARGE_CNTL_SW2_MASK, + .ad_pos = PCA9420_ACT_DISCHARGE_CNTL_SW2_POS, .max_ua = 500000, .ranges = buck2_ranges, .num_ranges = ARRAY_SIZE(buck2_ranges), @@ -183,6 +203,8 @@ static const struct regulator_pca9420_desc ldo1_desc = { .vsel_mask = PCA9420_MODECFG_2_LDO1_OUT_MASK, .vsel_pos = PCA9420_MODECFG_2_LDO1_OUT_POS, .vsel_reg = PCA9420_MODECFG_0_2, + .ad_mask = PCA9420_ACT_DISCHARGE_CNTL_LDO1_MASK, + .ad_pos = PCA9420_ACT_DISCHARGE_CNTL_LDO1_POS, .max_ua = 1000, .ranges = ldo1_ranges, .num_ranges = ARRAY_SIZE(ldo1_ranges), @@ -195,6 +217,8 @@ static const struct regulator_pca9420_desc ldo2_desc = { .vsel_reg = PCA9420_MODECFG_0_3, .vsel_mask = PCA9420_MODECFG_3_LDO2_OUT_MASK, .vsel_pos = PCA9420_MODECFG_3_LDO2_OUT_POS, + .ad_mask = PCA9420_ACT_DISCHARGE_CNTL_LDO2_MASK, + .ad_pos = PCA9420_ACT_DISCHARGE_CNTL_LDO2_POS, .max_ua = 250000, .ranges = ldo2_ranges, .num_ranges = ARRAY_SIZE(ldo2_ranges), @@ -279,6 +303,36 @@ static int regulator_pca9420_get_current_limit(const struct device *dev, return 0; } +static int regulator_pca9420_set_active_discharge(const struct device *dev, + bool active_discharge) +{ + const struct regulator_pca9420_config *config = dev->config; + const struct regulator_pca9420_common_config *cconfig = config->parent->config; + uint8_t dis_val; + + dis_val = (!active_discharge) << config->desc->ad_pos; + return i2c_reg_update_byte_dt(&cconfig->i2c, PCA9420_ACT_DISCHARGE_CNTL, + config->desc->ad_mask, dis_val); +} + +static int regulator_pca9420_get_active_discharge(const struct device *dev, + bool *active_discharge) +{ + const struct regulator_pca9420_config *config = dev->config; + const struct regulator_pca9420_common_config *cconfig = config->parent->config; + uint8_t raw_reg; + int ret; + + ret = i2c_reg_read_byte_dt(&cconfig->i2c, PCA9420_ACT_DISCHARGE_CNTL, &raw_reg); + if (ret < 0) { + return ret; + } + + *active_discharge = !((raw_reg & config->desc->ad_mask) >> config->desc->ad_pos); + + return 0; +} + static int regulator_pca9420_enable(const struct device *dev) { const struct regulator_pca9420_config *config = dev->config; @@ -313,6 +367,8 @@ static const struct regulator_driver_api api = { .set_voltage = regulator_pca9420_set_voltage, .get_voltage = regulator_pca9420_get_voltage, .get_current_limit = regulator_pca9420_get_current_limit, + .set_active_discharge = regulator_pca9420_set_active_discharge, + .get_active_discharge = regulator_pca9420_get_active_discharge, }; static int regulator_pca9420_init(const struct device *dev) From f61a0cb1fa5de524ade69e241d9737173b49d947 Mon Sep 17 00:00:00 2001 From: Fengming Ye Date: Sun, 21 Jan 2024 16:49:20 +0900 Subject: [PATCH 2996/3723] net: zperf: fix the calculation ratio between mbps, kbps and bps The ratio between mbps and kbps, kbps and bps should be 1000, instead of 1024, as common sense. The wrong ratio will decrease the Zperf throughput result. Signed-off-by: Fengming Ye --- subsys/net/lib/zperf/zperf_shell.c | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/subsys/net/lib/zperf/zperf_shell.c b/subsys/net/lib/zperf/zperf_shell.c index 444cf125c31..2c30c1e33e3 100644 --- a/subsys/net/lib/zperf/zperf_shell.c +++ b/subsys/net/lib/zperf/zperf_shell.c @@ -76,9 +76,9 @@ static struct in_addr shell_ipv4; const uint32_t TIME_US[] = { 60 * 1000 * 1000, 1000 * 1000, 1000, 0 }; const char *TIME_US_UNIT[] = { "m", "s", "ms", "us" }; -const uint32_t KBPS[] = { 1024, 0 }; +const uint32_t KBPS[] = { 1000, 0 }; const char *KBPS_UNIT[] = { "Mbps", "Kbps" }; -const uint32_t K[] = { 1024 * 1024, 1024, 0 }; +const uint32_t K[] = { 1000 * 1000, 1000, 0 }; const char *K_UNIT[] = { "M", "K", "" }; static void print_number(const struct shell *sh, uint32_t value, @@ -308,7 +308,7 @@ static void udp_session_cb(enum zperf_status status, rate_in_kbps = (uint32_t) (((uint64_t)result->total_len * 8ULL * (uint64_t)USEC_PER_SEC) / - ((uint64_t)result->time_in_us * 1024ULL)); + ((uint64_t)result->time_in_us * 1000ULL)); } else { rate_in_kbps = 0U; } @@ -408,7 +408,7 @@ static void shell_udp_upload_print_stats(const struct shell *sh, rate_in_kbps = (uint32_t) (((uint64_t)results->total_len * (uint64_t)8 * (uint64_t)USEC_PER_SEC) / - ((uint64_t)results->time_in_us * 1024U)); + ((uint64_t)results->time_in_us * 1000U)); } else { rate_in_kbps = 0U; } @@ -418,7 +418,7 @@ static void shell_udp_upload_print_stats(const struct shell *sh, (((uint64_t)results->nb_packets_sent * (uint64_t)results->packet_size * (uint64_t)8 * (uint64_t)USEC_PER_SEC) / - ((uint64_t)results->client_time_in_us * 1024U)); + ((uint64_t)results->client_time_in_us * 1000U)); } else { client_rate_in_kbps = 0U; } @@ -474,7 +474,7 @@ static void shell_tcp_upload_print_stats(const struct shell *sh, (((uint64_t)results->nb_packets_sent * (uint64_t)results->packet_size * (uint64_t)8 * (uint64_t)USEC_PER_SEC) / - ((uint64_t)results->client_time_in_us * 1024U)); + ((uint64_t)results->client_time_in_us * 1000U)); } else { client_rate_in_kbps = 0U; } @@ -884,7 +884,7 @@ static int shell_cmd_upload(const struct shell *sh, size_t argc, if (argc > 5) { param.rate_kbps = - (parse_number(argv[start + 5], K, K_UNIT) + 1023) / 1024; + (parse_number(argv[start + 5], K, K_UNIT) + 999) / 1000; } else { param.rate_kbps = 10U; } @@ -1035,7 +1035,7 @@ static int shell_cmd_upload2(const struct shell *sh, size_t argc, if (argc > 4) { param.rate_kbps = - (parse_number(argv[start + 4], K, K_UNIT) + 1023) / 1024; + (parse_number(argv[start + 4], K, K_UNIT) + 999) / 1000; } else { param.rate_kbps = 10U; } @@ -1108,7 +1108,7 @@ static void tcp_session_cb(enum zperf_status status, rate_in_kbps = (uint32_t) (((uint64_t)result->total_len * 8ULL * (uint64_t)USEC_PER_SEC) / - ((uint64_t)result->time_in_us * 1024ULL)); + ((uint64_t)result->time_in_us * 1000ULL)); } else { rate_in_kbps = 0U; } From 8cd61b6c668fc5e50d40bdefe2f9e02ed67ccecc Mon Sep 17 00:00:00 2001 From: Fengming Ye Date: Wed, 24 Jan 2024 13:43:07 +0900 Subject: [PATCH 2997/3723] doc: migration-guide: 3.6: zperf statistics changes Add information about zperf ratio between mbps and kbps, kbps and bps changes from 1024 to 1000, to align with iperf. Signed-off-by: Fengming Ye --- doc/releases/migration-guide-3.6.rst | 3 +++ 1 file changed, 3 insertions(+) diff --git a/doc/releases/migration-guide-3.6.rst b/doc/releases/migration-guide-3.6.rst index 21740fe90fb..479c1cbd838 100644 --- a/doc/releases/migration-guide-3.6.rst +++ b/doc/releases/migration-guide-3.6.rst @@ -435,6 +435,9 @@ Networking cannot be accessed from usermode thread. This means that the API calls will need to made from supervisor mode thread. +* The zperf ratio between mbps and kbps, kbps and bps is changed to 1000, instead of 1024, + to align with iperf ratios. + zcbor ===== From b600e8a870d54eb2da071529dbb44e95d6bd628c Mon Sep 17 00:00:00 2001 From: Christopher Friedt Date: Sun, 28 Jan 2024 09:15:18 -0500 Subject: [PATCH 2998/3723] posix: timer: build timer.c using the correct kconfig option Previously timer.c was only built with CONFIG_POSIX_CLOCK=y even though it has had its own Kconfig symbol (CONFIG_TIMER) for a very long time. Make POSIX_CLOCK imply TIMER rather than control whether it is built, and adjust Kconfig / CMake as necessary. Signed-off-by: Christopher Friedt --- lib/posix/CMakeLists.txt | 2 +- lib/posix/Kconfig.clock | 6 +++--- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/lib/posix/CMakeLists.txt b/lib/posix/CMakeLists.txt index 06782677999..5477e27b386 100644 --- a/lib/posix/CMakeLists.txt +++ b/lib/posix/CMakeLists.txt @@ -43,7 +43,6 @@ zephyr_library_sources_ifdef(CONFIG_POSIX_API perror.c) zephyr_library_sources_ifdef(CONFIG_POSIX_CLOCK clock.c) zephyr_library_sources_ifdef(CONFIG_POSIX_CLOCK nanosleep.c) zephyr_library_sources_ifdef(CONFIG_POSIX_CLOCK sleep.c) -zephyr_library_sources_ifdef(CONFIG_POSIX_CLOCK timer.c) zephyr_library_sources_ifdef(CONFIG_POSIX_FS fs.c) zephyr_library_sources_ifdef(CONFIG_POSIX_MQUEUE mqueue.c) zephyr_library_sources_ifdef(CONFIG_POSIX_SIGNAL signal.c ${STRSIGNAL_TABLE_H}) @@ -58,6 +57,7 @@ zephyr_library_sources_ifdef(CONFIG_PTHREAD_RWLOCK rwlock.c) zephyr_library_sources_ifdef(CONFIG_POSIX_PRIORITY_SCHEDULING sched.c) zephyr_library_sources_ifdef(CONFIG_PTHREAD_IPC semaphore.c) zephyr_library_sources_ifdef(CONFIG_PTHREAD_SPINLOCK spinlock.c) +zephyr_library_sources_ifdef(CONFIG_TIMER timer.c) zephyr_library_include_directories( ${ZEPHYR_BASE}/kernel/include diff --git a/lib/posix/Kconfig.clock b/lib/posix/Kconfig.clock index e9b83a12d0a..e306e691b44 100644 --- a/lib/posix/Kconfig.clock +++ b/lib/posix/Kconfig.clock @@ -3,9 +3,9 @@ # SPDX-License-Identifier: Apache-2.0 config POSIX_CLOCK - bool "POSIX clock, timer, and sleep APIs" + bool "POSIX clock and sleep APIs" default y if POSIX_API + imply TIMER depends on !NATIVE_LIBC help - This enables POSIX clock\_\*(), timer\_\*(), and \*sleep() - functions. + This enables POSIX clock\_\*() and \*sleep() functions. From c7d1dc3b42914712019bc3360c34a0ff931bbd5a Mon Sep 17 00:00:00 2001 From: Ping Wang Date: Wed, 24 Jan 2024 21:32:26 +0100 Subject: [PATCH 2999/3723] Bluetooth: Audio: Use utf8_lcpy to copy UTF8 strings with termination. use the function utf8_lcpy to ensure that UTF8 encoded strings are properly copied and NULL terminated. Fixes #42128 Signed-off-by: Ping Wang --- subsys/bluetooth/audio/aics.c | 6 ++---- subsys/bluetooth/audio/tbs.c | 15 ++++++++------- subsys/bluetooth/audio/vocs.c | 6 ++---- 3 files changed, 12 insertions(+), 15 deletions(-) diff --git a/subsys/bluetooth/audio/aics.c b/subsys/bluetooth/audio/aics.c index f4ff95cac06..1e42cc73da5 100644 --- a/subsys/bluetooth/audio/aics.c +++ b/subsys/bluetooth/audio/aics.c @@ -512,10 +512,8 @@ int bt_aics_register(struct bt_aics *aics, struct bt_aics_register_param *param) k_work_init_delayable(&aics->srv.notify_work, notify_work_handler); if (param->description) { - strncpy(aics->srv.description, param->description, - sizeof(aics->srv.description) - 1); - /* strncpy may not always null-terminate */ - aics->srv.description[sizeof(aics->srv.description) - 1] = '\0'; + (void)utf8_lcpy(aics->srv.description, param->description, + sizeof(aics->srv.description)); if (IS_ENABLED(CONFIG_BT_AICS_LOG_LEVEL_DBG) && strcmp(aics->srv.description, param->description)) { LOG_DBG("Input desc clipped to %s", aics->srv.description); diff --git a/subsys/bluetooth/audio/tbs.c b/subsys/bluetooth/audio/tbs.c index 0ab0c63b616..b9186a75e49 100644 --- a/subsys/bluetooth/audio/tbs.c +++ b/subsys/bluetooth/audio/tbs.c @@ -1590,8 +1590,8 @@ static void tbs_inst_init(struct service_inst *inst, const struct bt_gatt_attr * LOG_DBG("inst %p index 0x%02x provider_name %s", inst, inst_index(inst), provider_name); inst->ccid = bt_ccid_get_value(); - (void)strcpy(inst->provider_name, provider_name); - (void)strcpy(inst->uci, CONFIG_BT_TBS_UCI); + (void)utf8_lcpy(inst->provider_name, provider_name, sizeof(inst->provider_name)); + (void)utf8_lcpy(inst->uci, CONFIG_BT_TBS_UCI, sizeof(inst->uci)); inst->optional_opcodes = CONFIG_BT_TBS_SUPPORTED_FEATURES; inst->technology = CONFIG_BT_TBS_TECHNOLOGY; inst->signal_strength_interval = CONFIG_BT_TBS_SIGNAL_STRENGTH_INTERVAL; @@ -1612,7 +1612,8 @@ static void tbs_service_inst_init(struct tbs_service_inst *inst, struct bt_gatt_ { tbs_inst_init(&inst->inst, service->attrs, service->attr_count, CONFIG_BT_TBS_PROVIDER_NAME); - (void)strcpy(inst->uri_scheme_list, CONFIG_BT_TBS_URI_SCHEMES_LIST); + (void)utf8_lcpy(inst->uri_scheme_list, CONFIG_BT_TBS_URI_SCHEMES_LIST, + sizeof(inst->uri_scheme_list)); } static int bt_tbs_init(void) @@ -1889,10 +1890,10 @@ static void tbs_inst_remote_incoming(struct service_inst *inst, const char *to, remote_uri_ind_len = strlen(from) + 1; inst->in_call.call_index = call->index; - (void)strcpy(inst->in_call.uri, from); + (void)utf8_lcpy(inst->in_call.uri, from, sizeof(inst->in_call.uri)); inst->incoming_uri.call_index = call->index; - (void)strcpy(inst->incoming_uri.uri, to); + (void)utf8_lcpy(inst->incoming_uri.uri, to, sizeof(inst->incoming_uri.uri)); bt_gatt_notify_uuid(NULL, BT_UUID_TBS_INCOMING_URI, inst->attrs, &inst->incoming_uri, local_uri_ind_len); @@ -1967,7 +1968,7 @@ int bt_tbs_set_bearer_provider_name(uint8_t bearer_index, const char *name) return 0; } - (void)strcpy(inst->provider_name, name); + (void)utf8_lcpy(inst->provider_name, name, sizeof(inst->provider_name)); bt_gatt_notify_uuid(NULL, BT_UUID_TBS_PROVIDER_NAME, inst->attrs, inst->provider_name, strlen(inst->provider_name)); @@ -2087,7 +2088,7 @@ int bt_tbs_set_uri_scheme_list(uint8_t bearer_index, const char **uri_list, } /* Store final result */ - (void)strcpy(inst->uri_scheme_list, uri_scheme_list); + (void)utf8_lcpy(inst->uri_scheme_list, uri_scheme_list, sizeof(inst->uri_scheme_list)); LOG_DBG("TBS instance %u uri prefix list is now %s", bearer_index, inst->uri_scheme_list); diff --git a/subsys/bluetooth/audio/vocs.c b/subsys/bluetooth/audio/vocs.c index fe958d5fe33..1b5cd066dc1 100644 --- a/subsys/bluetooth/audio/vocs.c +++ b/subsys/bluetooth/audio/vocs.c @@ -412,10 +412,8 @@ int bt_vocs_register(struct bt_vocs *vocs, inst->cb = param->cb; if (param->output_desc) { - strncpy(inst->output_desc, param->output_desc, - sizeof(inst->output_desc) - 1); - /* strncpy may not always null-terminate */ - inst->output_desc[sizeof(inst->output_desc) - 1] = '\0'; + (void)utf8_lcpy(inst->output_desc, param->output_desc, + sizeof(inst->output_desc)); if (IS_ENABLED(CONFIG_BT_VOCS_LOG_LEVEL_DBG) && strcmp(inst->output_desc, param->output_desc)) { LOG_DBG("Output desc clipped to %s", inst->output_desc); From 682f38fa3663e483dd381d868b1e6f9eb6f4d2fb Mon Sep 17 00:00:00 2001 From: Fabio Baltieri Date: Thu, 25 Jan 2024 09:09:43 +0000 Subject: [PATCH 3000/3723] tests: lib: devicetree devices: only run on native_sim The test instantiate few vnd,i2c devices so it fails with boards with devices that select I2C, as that causes i2c_test.c to be included with the build that tries to redefine the same devices as well. This is a library test anyway, so restricting to native_sim should be good enough for it anyway. Signed-off-by: Fabio Baltieri --- tests/lib/devicetree/devices/testcase.yaml | 18 ++++-------------- 1 file changed, 4 insertions(+), 14 deletions(-) diff --git a/tests/lib/devicetree/devices/testcase.yaml b/tests/lib/devicetree/devices/testcase.yaml index 47e8d6cf9f9..0aa279267e7 100644 --- a/tests/lib/devicetree/devices/testcase.yaml +++ b/tests/lib/devicetree/devices/testcase.yaml @@ -5,17 +5,7 @@ tests: # will mostly likely be the fastest. integration_platforms: - native_sim - platform_exclude: - - hsdk - - hsdk_2cores - - thingy52_nrf52832 - - bbc_microbit - - bbc_microbit_v2 - - bt610 - - bl5340_dvk_cpuapp - - bl5340_dvk_cpuapp_ns - - m5stack_core2 - - mimxrt595_evk_cm33 - - nrf9131ek_nrf9131 - - nrf9131ek_nrf9131_ns - - kincony_kc868_a32 + # The test instantiate few vnd,i2c devices so it fails with boards with + # devices that select I2C. + platform_allow: + - native_sim From fe02e32f86e3f6c01252502616ff6735d83e9e48 Mon Sep 17 00:00:00 2001 From: Aymeric Aillet Date: Wed, 24 Jan 2024 16:05:14 +0100 Subject: [PATCH 3001/3723] drivers: clock: Rename renesas ra driver Need this rename to be able to target this driver in the "Renesas RA" maintainer area. Signed-off-by: Aymeric Aillet --- drivers/clock_control/CMakeLists.txt | 2 +- drivers/clock_control/Kconfig | 2 +- drivers/clock_control/{Kconfig.ra => Kconfig.renesas_ra} | 2 +- .../{clock_control_ra.c => clock_control_renesas_ra.c} | 0 4 files changed, 3 insertions(+), 3 deletions(-) rename drivers/clock_control/{Kconfig.ra => Kconfig.renesas_ra} (90%) rename drivers/clock_control/{clock_control_ra.c => clock_control_renesas_ra.c} (100%) diff --git a/drivers/clock_control/CMakeLists.txt b/drivers/clock_control/CMakeLists.txt index 14f6c603000..596b07676e0 100644 --- a/drivers/clock_control/CMakeLists.txt +++ b/drivers/clock_control/CMakeLists.txt @@ -26,7 +26,7 @@ zephyr_library_sources_ifdef(CONFIG_CLOCK_CONTROL_SAM clock_cont 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_S32 clock_control_nxp_s32.c) -zephyr_library_sources_ifdef(CONFIG_CLOCK_CONTROL_RA clock_control_ra.c) +zephyr_library_sources_ifdef(CONFIG_CLOCK_CONTROL_RENESAS_RA clock_control_renesas_ra.c) zephyr_library_sources_ifdef(CONFIG_CLOCK_CONTROL_AMBIQ clock_control_ambiq.c) zephyr_library_sources_ifdef(CONFIG_CLOCK_CONTROL_PWM clock_control_pwm.c) zephyr_library_sources_ifdef(CONFIG_CLOCK_CONTROL_RPI_PICO clock_control_rpi_pico.c) diff --git a/drivers/clock_control/Kconfig b/drivers/clock_control/Kconfig index 9f7412cd9f2..b0c6cf8de48 100644 --- a/drivers/clock_control/Kconfig +++ b/drivers/clock_control/Kconfig @@ -80,7 +80,7 @@ source "drivers/clock_control/Kconfig.nxp_s32" source "drivers/clock_control/Kconfig.agilex5" -source "drivers/clock_control/Kconfig.ra" +source "drivers/clock_control/Kconfig.renesas_ra" source "drivers/clock_control/Kconfig.ambiq" diff --git a/drivers/clock_control/Kconfig.ra b/drivers/clock_control/Kconfig.renesas_ra similarity index 90% rename from drivers/clock_control/Kconfig.ra rename to drivers/clock_control/Kconfig.renesas_ra index 2b4aea0fb81..5a14f593f9b 100644 --- a/drivers/clock_control/Kconfig.ra +++ b/drivers/clock_control/Kconfig.renesas_ra @@ -1,7 +1,7 @@ # Copyright (c) 2023 TOKITA Hiroshi # SPDX-License-Identifier: Apache-2.0 -config CLOCK_CONTROL_RA +config CLOCK_CONTROL_RENESAS_RA bool "Renesas RA series clock generation circuit driver" default y depends on DT_HAS_RENESAS_RA_CLOCK_GENERATION_CIRCUIT_ENABLED diff --git a/drivers/clock_control/clock_control_ra.c b/drivers/clock_control/clock_control_renesas_ra.c similarity index 100% rename from drivers/clock_control/clock_control_ra.c rename to drivers/clock_control/clock_control_renesas_ra.c From fd04892322bf3e1fbebb26f732daa8854a39aea6 Mon Sep 17 00:00:00 2001 From: Aymeric Aillet Date: Wed, 24 Jan 2024 16:05:41 +0100 Subject: [PATCH 3002/3723] drivers: gpio: Rename renesas ra driver Need this rename to be able to target this driver in the "Renesas RA" maintainer area. Signed-off-by: Aymeric Aillet --- drivers/gpio/CMakeLists.txt | 2 +- drivers/gpio/Kconfig | 2 +- drivers/gpio/{Kconfig.ra => Kconfig.renesas_ra} | 2 +- drivers/gpio/{gpio_ra.c => gpio_renesas_ra.c} | 0 4 files changed, 3 insertions(+), 3 deletions(-) rename drivers/gpio/{Kconfig.ra => Kconfig.renesas_ra} (92%) rename drivers/gpio/{gpio_ra.c => gpio_renesas_ra.c} (100%) diff --git a/drivers/gpio/CMakeLists.txt b/drivers/gpio/CMakeLists.txt index f3f00d79db6..3e4ae12dc4a 100644 --- a/drivers/gpio/CMakeLists.txt +++ b/drivers/gpio/CMakeLists.txt @@ -88,7 +88,7 @@ zephyr_library_sources_ifdef(CONFIG_GPIO_SEDI gpio_sedi.c) zephyr_library_sources_ifdef(CONFIG_GPIO_TLE9104 gpio_tle9104.c) zephyr_library_sources_ifdef(CONFIG_GPIO_ALTERA_PIO gpio_altera_pio.c) zephyr_library_sources_ifdef(CONFIG_GPIO_BCM2711 gpio_bcm2711.c) -zephyr_library_sources_ifdef(CONFIG_GPIO_RA gpio_ra.c) +zephyr_library_sources_ifdef(CONFIG_GPIO_RENESAS_RA gpio_renesas_ra.c) zephyr_library_sources_ifdef(CONFIG_GPIO_RZT2M gpio_rzt2m.c) zephyr_library_sources_ifdef(CONFIG_GPIO_AMBIQ gpio_ambiq.c) diff --git a/drivers/gpio/Kconfig b/drivers/gpio/Kconfig index a6c2417144d..ff9d02704d8 100644 --- a/drivers/gpio/Kconfig +++ b/drivers/gpio/Kconfig @@ -234,7 +234,7 @@ source "drivers/gpio/Kconfig.altera" source "drivers/gpio/Kconfig.bcm2711" -source "drivers/gpio/Kconfig.ra" +source "drivers/gpio/Kconfig.renesas_ra" source "drivers/gpio/Kconfig.rzt2m" diff --git a/drivers/gpio/Kconfig.ra b/drivers/gpio/Kconfig.renesas_ra similarity index 92% rename from drivers/gpio/Kconfig.ra rename to drivers/gpio/Kconfig.renesas_ra index 391a32f293d..bd6f536ee80 100644 --- a/drivers/gpio/Kconfig.ra +++ b/drivers/gpio/Kconfig.renesas_ra @@ -1,7 +1,7 @@ # Copyright (c) 2023 TOKITA Hiroshi # SPDX-License-Identifier: Apache-2.0 -config GPIO_RA +config GPIO_RENESAS_RA bool "Renesas RA Series GPIO driver" default y select GPIO_GET_CONFIG diff --git a/drivers/gpio/gpio_ra.c b/drivers/gpio/gpio_renesas_ra.c similarity index 100% rename from drivers/gpio/gpio_ra.c rename to drivers/gpio/gpio_renesas_ra.c From 1cd2ce1cc72579eadb00c22a76b554cd23865745 Mon Sep 17 00:00:00 2001 From: Aymeric Aillet Date: Wed, 24 Jan 2024 16:06:24 +0100 Subject: [PATCH 3003/3723] drivers: intc: Rename renesas ra driver Need this rename to be able to target this driver in the "Renesas RA" maintainer area. Signed-off-by: Aymeric Aillet --- drivers/interrupt_controller/CMakeLists.txt | 2 +- drivers/interrupt_controller/Kconfig | 2 +- drivers/interrupt_controller/{Kconfig.ra => Kconfig.renesas_ra} | 0 .../{intc_ra_icu.c => intc_renesas_ra_icu.c} | 0 4 files changed, 2 insertions(+), 2 deletions(-) rename drivers/interrupt_controller/{Kconfig.ra => Kconfig.renesas_ra} (100%) rename drivers/interrupt_controller/{intc_ra_icu.c => intc_renesas_ra_icu.c} (100%) diff --git a/drivers/interrupt_controller/CMakeLists.txt b/drivers/interrupt_controller/CMakeLists.txt index 1d4175e5408..0df052e6045 100644 --- a/drivers/interrupt_controller/CMakeLists.txt +++ b/drivers/interrupt_controller/CMakeLists.txt @@ -37,7 +37,7 @@ zephyr_library_sources_ifdef(CONFIG_NXP_S32_EIRQ intc_eirq_nxp_s32.c) zephyr_library_sources_ifdef(CONFIG_NXP_S32_WKPU intc_wkpu_nxp_s32.c) zephyr_library_sources_ifdef(CONFIG_XMC4XXX_INTC intc_xmc4xxx.c) zephyr_library_sources_ifdef(CONFIG_NXP_PINT intc_nxp_pint.c) -zephyr_library_sources_ifdef(CONFIG_RENESAS_RA_ICU intc_ra_icu.c) +zephyr_library_sources_ifdef(CONFIG_RENESAS_RA_ICU intc_renesas_ra_icu.c) zephyr_library_sources_ifdef(CONFIG_NXP_IRQSTEER intc_nxp_irqsteer.c) if(CONFIG_INTEL_VTD_ICTL) diff --git a/drivers/interrupt_controller/Kconfig b/drivers/interrupt_controller/Kconfig index fca4b32e6a4..a956afdf1f6 100644 --- a/drivers/interrupt_controller/Kconfig +++ b/drivers/interrupt_controller/Kconfig @@ -102,7 +102,7 @@ source "drivers/interrupt_controller/Kconfig.nxp_pint" source "drivers/interrupt_controller/Kconfig.vim" -source "drivers/interrupt_controller/Kconfig.ra" +source "drivers/interrupt_controller/Kconfig.renesas_ra" source "drivers/interrupt_controller/Kconfig.nxp_irqsteer" diff --git a/drivers/interrupt_controller/Kconfig.ra b/drivers/interrupt_controller/Kconfig.renesas_ra similarity index 100% rename from drivers/interrupt_controller/Kconfig.ra rename to drivers/interrupt_controller/Kconfig.renesas_ra diff --git a/drivers/interrupt_controller/intc_ra_icu.c b/drivers/interrupt_controller/intc_renesas_ra_icu.c similarity index 100% rename from drivers/interrupt_controller/intc_ra_icu.c rename to drivers/interrupt_controller/intc_renesas_ra_icu.c From 9db09d8dc0b8f1de854c2054b7b84c25bbf8e462 Mon Sep 17 00:00:00 2001 From: Aymeric Aillet Date: Wed, 24 Jan 2024 16:06:39 +0100 Subject: [PATCH 3004/3723] drivers: pinctrl: Rename renesas ra driver Need this rename to be able to target this driver in the "Renesas RA" maintainer area. Signed-off-by: Aymeric Aillet --- drivers/pinctrl/CMakeLists.txt | 2 +- drivers/pinctrl/Kconfig | 2 +- drivers/pinctrl/{Kconfig.ra => Kconfig.renesas_ra} | 2 +- drivers/pinctrl/{pinctrl_ra.c => pinctrl_renesas_ra.c} | 0 4 files changed, 3 insertions(+), 3 deletions(-) rename drivers/pinctrl/{Kconfig.ra => Kconfig.renesas_ra} (91%) rename drivers/pinctrl/{pinctrl_ra.c => pinctrl_renesas_ra.c} (100%) diff --git a/drivers/pinctrl/CMakeLists.txt b/drivers/pinctrl/CMakeLists.txt index 9ef54940b46..9f104c6e323 100644 --- a/drivers/pinctrl/CMakeLists.txt +++ b/drivers/pinctrl/CMakeLists.txt @@ -36,6 +36,6 @@ zephyr_library_sources_ifdef(CONFIG_PINCTRL_EMSDP pinctrl_emsdp.c) zephyr_library_sources_ifdef(CONFIG_PINCTRL_TI_CC32XX pinctrl_ti_cc32xx.c) zephyr_library_sources_ifdef(CONFIG_PINCTRL_NUMAKER pinctrl_numaker.c) zephyr_library_sources_ifdef(CONFIG_PINCTRL_QUICKLOGIC_EOS_S3 pinctrl_eos_s3.c) -zephyr_library_sources_ifdef(CONFIG_PINCTRL_RA pinctrl_ra.c) +zephyr_library_sources_ifdef(CONFIG_PINCTRL_RENESAS_RA pinctrl_renesas_ra.c) zephyr_library_sources_ifdef(CONFIG_PINCTRL_IMX_SCU pinctrl_imx_scu.c) zephyr_library_sources_ifdef(CONFIG_PINCTRL_RZT2M pinctrl_rzt2m.c) diff --git a/drivers/pinctrl/Kconfig b/drivers/pinctrl/Kconfig index d549622b3db..f03af874bbf 100644 --- a/drivers/pinctrl/Kconfig +++ b/drivers/pinctrl/Kconfig @@ -64,7 +64,7 @@ source "drivers/pinctrl/Kconfig.emsdp" source "drivers/pinctrl/Kconfig.ti_cc32xx" source "drivers/pinctrl/Kconfig.numaker" source "drivers/pinctrl/Kconfig.eos_s3" -source "drivers/pinctrl/Kconfig.ra" +source "drivers/pinctrl/Kconfig.renesas_ra" source "drivers/pinctrl/Kconfig.rzt2m" source "drivers/pinctrl/Kconfig.zynqmp" diff --git a/drivers/pinctrl/Kconfig.ra b/drivers/pinctrl/Kconfig.renesas_ra similarity index 91% rename from drivers/pinctrl/Kconfig.ra rename to drivers/pinctrl/Kconfig.renesas_ra index 6ad0ebd8c06..6f3c301d07b 100644 --- a/drivers/pinctrl/Kconfig.ra +++ b/drivers/pinctrl/Kconfig.renesas_ra @@ -1,7 +1,7 @@ # Copyright (c) 2023 TOKITA Hiroshi # SPDX-License-Identifier: Apache-2.0 -config PINCTRL_RA +config PINCTRL_RENESAS_RA bool "Renesas RA series pin controller driver" default y depends on DT_HAS_RENESAS_RA_PINCTRL_ENABLED diff --git a/drivers/pinctrl/pinctrl_ra.c b/drivers/pinctrl/pinctrl_renesas_ra.c similarity index 100% rename from drivers/pinctrl/pinctrl_ra.c rename to drivers/pinctrl/pinctrl_renesas_ra.c From 48dc603f0c81fcc169f05ed1688a52da266ed330 Mon Sep 17 00:00:00 2001 From: Aymeric Aillet Date: Wed, 24 Jan 2024 16:07:08 +0100 Subject: [PATCH 3005/3723] drivers: serial: Rename renesas ra driver Need this rename to be able to target this driver in the "Renesas RA" maintainer area. Signed-off-by: Aymeric Aillet --- drivers/serial/CMakeLists.txt | 2 +- drivers/serial/Kconfig | 2 +- drivers/serial/{Kconfig.ra => Kconfig.renesas_ra} | 2 +- drivers/serial/{uart_ra.c => uart_renesas_ra.c} | 0 4 files changed, 3 insertions(+), 3 deletions(-) rename drivers/serial/{Kconfig.ra => Kconfig.renesas_ra} (93%) rename drivers/serial/{uart_ra.c => uart_renesas_ra.c} (100%) diff --git a/drivers/serial/CMakeLists.txt b/drivers/serial/CMakeLists.txt index 67e02e0c261..1648f3a7081 100644 --- a/drivers/serial/CMakeLists.txt +++ b/drivers/serial/CMakeLists.txt @@ -72,7 +72,7 @@ zephyr_library_sources_ifdef(CONFIG_UART_EFINIX_SAPPIHIRE uart_efinix_sapphire.c zephyr_library_sources_ifdef(CONFIG_UART_SEDI uart_sedi.c) zephyr_library_sources_ifdef(CONFIG_UART_BCM2711_MU uart_bcm2711.c) zephyr_library_sources_ifdef(CONFIG_UART_INTEL_LW uart_intel_lw.c) -zephyr_library_sources_ifdef(CONFIG_UART_RA uart_ra.c) +zephyr_library_sources_ifdef(CONFIG_UART_RENESAS_RA uart_renesas_ra.c) zephyr_library_sources_ifdef(CONFIG_UART_RZT2M uart_rzt2m.c) zephyr_library_sources_ifdef(CONFIG_USERSPACE uart_handlers.c) diff --git a/drivers/serial/Kconfig b/drivers/serial/Kconfig index 2d097932cf4..a3041b2cae6 100644 --- a/drivers/serial/Kconfig +++ b/drivers/serial/Kconfig @@ -268,7 +268,7 @@ source "drivers/serial/Kconfig.bcm2711" source "drivers/serial/Kconfig.intel_lw" -source "drivers/serial/Kconfig.ra" +source "drivers/serial/Kconfig.renesas_ra" source "drivers/serial/Kconfig.rzt2m" diff --git a/drivers/serial/Kconfig.ra b/drivers/serial/Kconfig.renesas_ra similarity index 93% rename from drivers/serial/Kconfig.ra rename to drivers/serial/Kconfig.renesas_ra index 3e35afed2de..14311f27fe4 100644 --- a/drivers/serial/Kconfig.ra +++ b/drivers/serial/Kconfig.renesas_ra @@ -1,7 +1,7 @@ # Copyright (c) 2023 TOKITA Hiroshi # SPDX-License-Identifier: Apache-2.0 -config UART_RA +config UART_RENESAS_RA bool "Renesas RA Series UART Driver" default y depends on DT_HAS_RENESAS_RA_UART_SCI_ENABLED diff --git a/drivers/serial/uart_ra.c b/drivers/serial/uart_renesas_ra.c similarity index 100% rename from drivers/serial/uart_ra.c rename to drivers/serial/uart_renesas_ra.c From bf30c2a3b32308f4ccc15c2f487896b9b0a331b2 Mon Sep 17 00:00:00 2001 From: Aymeric Aillet Date: Fri, 26 Jan 2024 09:49:35 +0100 Subject: [PATCH 3006/3723] doc: releases: 3.6: note on renaming RA drivers kconfig options Add a note about the renaming of several Renesas RA driver kconfig options. These options have been renamed when renaming several driver file names. Signed-off-by: Aymeric Aillet --- doc/releases/release-notes-3.6.rst | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/doc/releases/release-notes-3.6.rst b/doc/releases/release-notes-3.6.rst index 3065fd0be4f..c64815a8e92 100644 --- a/doc/releases/release-notes-3.6.rst +++ b/doc/releases/release-notes-3.6.rst @@ -163,6 +163,7 @@ Drivers and Sensors * Clock control * Renesas R-Car clock control driver now supports Gen4 SoCs + * Renamed ``CONFIG_CLOCK_CONTROL_RA`` to :kconfig:option:`CONFIG_CLOCK_CONTROL_RENESAS_RA` * Counter @@ -189,6 +190,7 @@ Drivers and Sensors * GPIO * Renesas R-Car GPIO driver now supports Gen4 SoCs + * Renamed ``CONFIG_GPIO_RA`` to :kconfig:option:`CONFIG_GPIO_RENESAS_RA` * I2C @@ -214,6 +216,7 @@ Drivers and Sensors * Pin control * Renesas R-Car pinctrl driver now supports Gen4 SoCs + * Renamed ``CONFIG_PINCTRL_RA`` to :kconfig:option:`CONFIG_PINCTRL_RENESAS_RA` * PWM @@ -235,6 +238,8 @@ Drivers and Sensors * Serial + * Renamed ``CONFIG_UART_RA`` to :kconfig:option:`CONFIG_UART_RENESAS_RA` + * SPI * Timer From 2a93e06fba52017b7a13b5c9c01e41ad812ff657 Mon Sep 17 00:00:00 2001 From: Aymeric Aillet Date: Fri, 26 Jan 2024 09:50:33 +0100 Subject: [PATCH 3007/3723] doc: releases: migration-guide: 3.6: note on renaming RA kconfig options Add a note about the renaming of several Renesas RA driver kconfig options. These options have been renamed when renaming several driver file names. Signed-off-by: Aymeric Aillet --- doc/releases/migration-guide-3.6.rst | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/doc/releases/migration-guide-3.6.rst b/doc/releases/migration-guide-3.6.rst index 479c1cbd838..fc2e35ffb6f 100644 --- a/doc/releases/migration-guide-3.6.rst +++ b/doc/releases/migration-guide-3.6.rst @@ -276,6 +276,13 @@ Device Drivers and Device Tree * ``DT_INST_IRQ_BY_IDX(inst, idx, irq)`` -> ``DT_INST_IRQN_BY_IDX(inst, idx)`` * ``DT_INST_IRQ_BY_NAME(inst, name, irq)`` -> ``DT_INST_IRQN_BY_NAME(inst, name)`` +* Several Renesas RA series drivers Kconfig options have been renamed: + + * ``CONFIG_CLOCK_CONTROL_RA`` -> :kconfig:option:`CONFIG_CLOCK_CONTROL_RENESAS_RA` + * ``CONFIG_GPIO_RA`` -> :kconfig:option:`CONFIG_GPIO_RENESAS_RA` + * ``CONFIG_PINCTRL_RA`` -> :kconfig:option:`CONFIG_PINCTRL_RENESAS_RA` + * ``CONFIG_UART_RA`` -> :kconfig:option:`CONFIG_UART_RENESAS_RA` + Power Management ================ From aae51921df37c86059d67ccc2274913145102f01 Mon Sep 17 00:00:00 2001 From: Trond Einar Snekvik Date: Tue, 14 Jun 2022 10:41:39 +0200 Subject: [PATCH 3008/3723] sys: util: Accept empty FOR_EACH MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The ## part of ##__VA_ARGS__ in the Z_FOR_EACH_ENGINE macro technically breaks the invocation of empty FOR_EACH sequences, as the empty __VA_ARGS__ gets squashed with in the invocation of Z_FOR_LOOP_1() in Z_FOR_LOOP_2(), which makes the macro only pass 4 arguments to Z_FOR_LOOP_1. This breaks IntelliSense in Microsoft's C/C++ extension for VS Code, which is strict about the amount of arguments you can pass to a variadic macro. Signed-off-by: Krzysztof Chruściński Signed-off-by: Trond Einar Snekvik --- include/zephyr/sys/util_loops.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/include/zephyr/sys/util_loops.h b/include/zephyr/sys/util_loops.h index ff64e7b1ef9..8c71edd16f3 100644 --- a/include/zephyr/sys/util_loops.h +++ b/include/zephyr/sys/util_loops.h @@ -408,7 +408,7 @@ Z_FOR_LOOP_3, \ Z_FOR_LOOP_2, \ Z_FOR_LOOP_1, \ - Z_FOR_LOOP_0)(x, sep, fixed_arg0, fixed_arg1, ##__VA_ARGS__) + Z_FOR_LOOP_0)(x, sep, fixed_arg0, fixed_arg1, __VA_ARGS__) #define Z_GET_ARG_1(_0, ...) _0 From fdafbdb1c9ad85348595bf4eefe244521cda1e5c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Krzysztof=20Chru=C5=9Bci=C5=84ski?= Date: Tue, 23 Jan 2024 07:47:56 +0100 Subject: [PATCH 3009/3723] tests: unit: util: Extend FOR_EACH test MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Extend test to check also no arguments. Signed-off-by: Krzysztof Chruściński --- tests/unit/util/main.c | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/tests/unit/util/main.c b/tests/unit/util/main.c index 4486d89272a..3ae9778ae19 100644 --- a/tests/unit/util/main.c +++ b/tests/unit/util/main.c @@ -236,6 +236,7 @@ ZTEST(util, test_IN_RANGE) { ZTEST(util, test_FOR_EACH) { #define FOR_EACH_MACRO_TEST(arg) *buf++ = arg + #define FOR_EACH_MACRO_TEST2(arg) arg uint8_t array[3] = {0}; uint8_t *buf = array; @@ -245,6 +246,14 @@ ZTEST(util, test_FOR_EACH) { zassert_equal(array[0], 1, "Unexpected value %d", array[0]); zassert_equal(array[1], 2, "Unexpected value %d", array[1]); zassert_equal(array[2], 3, "Unexpected value %d", array[2]); + + uint8_t test0[] = { 0, FOR_EACH(FOR_EACH_MACRO_TEST2, (,))}; + + BUILD_ASSERT(sizeof(test0) == 1, "Unexpected length due to FOR_EACH fail"); + + uint8_t test1[] = { 0, FOR_EACH(FOR_EACH_MACRO_TEST2, (,), 1)}; + + BUILD_ASSERT(sizeof(test1) == 2, "Unexpected length due to FOR_EACH fail"); } ZTEST(util, test_FOR_EACH_NONEMPTY_TERM) { From d2e79866ad5e19abe8c6369cf8df3f350546d977 Mon Sep 17 00:00:00 2001 From: Aymeric Aillet Date: Wed, 29 Nov 2023 14:38:11 +0100 Subject: [PATCH 3010/3723] drivers: clock: rcar: r8a7795 driver cleanup Remove old unused defines from header Use clang-format to apply coding guideline to r8a7795 driver Signed-off-by: Aymeric Aillet --- .../clock_control_r8a7795_cpg_mssr.c | 33 ++++++++----------- .../clock_control_renesas_cpg_mssr.h | 14 -------- 2 files changed, 14 insertions(+), 33 deletions(-) diff --git a/drivers/clock_control/clock_control_r8a7795_cpg_mssr.c b/drivers/clock_control/clock_control_r8a7795_cpg_mssr.c index 26b0b1959c6..a369db995b6 100644 --- a/drivers/clock_control/clock_control_r8a7795_cpg_mssr.c +++ b/drivers/clock_control/clock_control_r8a7795_cpg_mssr.c @@ -19,12 +19,12 @@ LOG_MODULE_DECLARE(clock_control_rcar); -#define R8A7795_CLK_SD_STOP_BIT 8 -#define R8A7795_CLK_SD_DIV_MASK 0x3 +#define R8A7795_CLK_SD_STOP_BIT 8 +#define R8A7795_CLK_SD_DIV_MASK 0x3 #define R8A7795_CLK_SD_DIV_SHIFT 0 -#define R8A7795_CLK_SDH_STOP_BIT 9 -#define R8A7795_CLK_SDH_DIV_MASK 0x7 +#define R8A7795_CLK_SDH_STOP_BIT 9 +#define R8A7795_CLK_SDH_DIV_MASK 0x7 #define R8A7795_CLK_SDH_DIV_SHIFT 2 #define R8A7795_CLK_CANFD_STOP_BIT 8 @@ -40,8 +40,8 @@ struct r8a7795_cpg_mssr_data { /* NOTE: the array MUST be sorted by module field */ static struct cpg_clk_info_table core_props[] = { - RCAR_CORE_CLK_INFO_ITEM(R8A7795_CLK_S3D4, RCAR_CPG_NONE, - RCAR_CPG_NONE, RCAR_CPG_KHZ(66600)), + RCAR_CORE_CLK_INFO_ITEM(R8A7795_CLK_S3D4, RCAR_CPG_NONE, RCAR_CPG_NONE, + RCAR_CPG_KHZ(66600)), RCAR_CORE_CLK_INFO_ITEM(R8A7795_CLK_SD0H, 0x0074, RCAR_CPG_NONE, RCAR_CPG_MHZ(800)), RCAR_CORE_CLK_INFO_ITEM(R8A7795_CLK_SD0, 0x0074, R8A7795_CLK_SD0H, RCAR_CPG_MHZ(800)), @@ -57,8 +57,8 @@ static struct cpg_clk_info_table core_props[] = { RCAR_CORE_CLK_INFO_ITEM(R8A7795_CLK_CANFD, 0x0244, RCAR_CPG_NONE, RCAR_CPG_MHZ(800)), - RCAR_CORE_CLK_INFO_ITEM(R8A7795_CLK_S0D12, RCAR_CPG_NONE, - RCAR_CPG_NONE, RCAR_CPG_KHZ(66600)), + RCAR_CORE_CLK_INFO_ITEM(R8A7795_CLK_S0D12, RCAR_CPG_NONE, RCAR_CPG_NONE, + RCAR_CPG_KHZ(66600)), }; /* NOTE: the array MUST be sorted by module field */ @@ -72,8 +72,7 @@ static struct cpg_clk_info_table mod_props[] = { }; static int r8a7795_cpg_enable_disable_core(const struct device *dev, - struct cpg_clk_info_table *clk_info, - uint32_t enable) + struct cpg_clk_info_table *clk_info, uint32_t enable) { int ret = 0; uint32_t reg; @@ -113,8 +112,7 @@ static int r8a7795_cpg_enable_disable_core(const struct device *dev, return ret; } -static int r8a7795_cpg_core_clock_endisable(const struct device *dev, - struct rcar_cpg_clk *clk, +static int r8a7795_cpg_core_clock_endisable(const struct device *dev, struct rcar_cpg_clk *clk, bool enable) { struct cpg_clk_info_table *clk_info; @@ -132,7 +130,7 @@ static int r8a7795_cpg_core_clock_endisable(const struct device *dev, uintptr_t rate = clk->rate; ret = rcar_cpg_set_rate(dev, (clock_control_subsys_t)clk, - (clock_control_subsys_rate_t)rate); + (clock_control_subsys_rate_t)rate); if (ret < 0) { return ret; } @@ -146,8 +144,7 @@ static int r8a7795_cpg_core_clock_endisable(const struct device *dev, return ret; } -static int r8a7795_cpg_mssr_start_stop(const struct device *dev, - clock_control_subsys_t sys, +static int r8a7795_cpg_mssr_start_stop(const struct device *dev, clock_control_subsys_t sys, bool enable) { struct rcar_cpg_clk *clk = (struct rcar_cpg_clk *)sys; @@ -258,14 +255,12 @@ static int r8a7795_set_rate_helper(uint32_t module, uint32_t *divider, uint32_t return ret; } -static int r8a7795_cpg_mssr_start(const struct device *dev, - clock_control_subsys_t sys) +static int r8a7795_cpg_mssr_start(const struct device *dev, clock_control_subsys_t sys) { return r8a7795_cpg_mssr_start_stop(dev, sys, true); } -static int r8a7795_cpg_mssr_stop(const struct device *dev, - clock_control_subsys_t sys) +static int r8a7795_cpg_mssr_stop(const struct device *dev, clock_control_subsys_t sys) { return r8a7795_cpg_mssr_start_stop(dev, sys, false); } diff --git a/drivers/clock_control/clock_control_renesas_cpg_mssr.h b/drivers/clock_control/clock_control_renesas_cpg_mssr.h index 5850d6f12db..6829d5a96b6 100644 --- a/drivers/clock_control/clock_control_renesas_cpg_mssr.h +++ b/drivers/clock_control/clock_control_renesas_cpg_mssr.h @@ -95,20 +95,6 @@ static const uint16_t srcr[] = { 0x0BC, 0x0C4, 0x1C8, 0x1CC, 0x920, 0x924, 0x928, 0x92C, }; - -/* CAN FD Clock Frequency Control Register */ -#define CANFDCKCR 0x244 - -/* Clock stop bit */ -#define CANFDCKCR_CKSTP BIT(8) - -/* CANFD Clock */ -#define CANFDCKCR_PARENT_CLK_RATE 800000000 -#define CANFDCKCR_DIVIDER_MASK 0x1FF - -/* Peripherals Clocks */ -#define S3D4_CLK_RATE 66600000 /* SCIF */ -#define S0D12_CLK_RATE 66600000 /* PWM */ #elif defined(CONFIG_SOC_SERIES_RCAR_GEN4) /* Software Reset Clearing Register offsets */ #define SRSTCLR(i) (0x2C80 + (i) * 4) From ff4b9ebd65bb35b0db712e888f3a94a6788a88b1 Mon Sep 17 00:00:00 2001 From: Aymeric Aillet Date: Wed, 29 Nov 2023 14:47:22 +0100 Subject: [PATCH 3011/3723] drivers: clock: rcar: harmonize r8a7795 and r8a779f0 drivers Based on edit done at r8a779f0 driver creation (f5634a1a0e6f607809a7e4b8d1933a85b5eb7642) following comments on #56043. Signed-off-by: Aymeric Aillet --- .../clock_control_r8a7795_cpg_mssr.c | 49 +++++++------------ 1 file changed, 19 insertions(+), 30 deletions(-) diff --git a/drivers/clock_control/clock_control_r8a7795_cpg_mssr.c b/drivers/clock_control/clock_control_r8a7795_cpg_mssr.c index a369db995b6..a796c6efc6c 100644 --- a/drivers/clock_control/clock_control_r8a7795_cpg_mssr.c +++ b/drivers/clock_control/clock_control_r8a7795_cpg_mssr.c @@ -118,7 +118,6 @@ static int r8a7795_cpg_core_clock_endisable(const struct device *dev, struct rca struct cpg_clk_info_table *clk_info; struct r8a7795_cpg_mssr_data *data = dev->data; k_spinlock_key_t key; - int ret = 0; clk_info = rcar_cpg_find_clk_info_by_module_id(dev, clk->domain, clk->module); if (!clk_info) { @@ -127,6 +126,7 @@ static int r8a7795_cpg_core_clock_endisable(const struct device *dev, struct rca if (enable) { if (clk->rate > 0) { + int ret; uintptr_t rate = clk->rate; ret = rcar_cpg_set_rate(dev, (clock_control_subsys_t)clk, @@ -141,14 +141,14 @@ static int r8a7795_cpg_core_clock_endisable(const struct device *dev, struct rca r8a7795_cpg_enable_disable_core(dev, clk_info, enable); k_spin_unlock(&data->cmn.lock, key); - return ret; + return 0; } static int r8a7795_cpg_mssr_start_stop(const struct device *dev, clock_control_subsys_t sys, bool enable) { struct rcar_cpg_clk *clk = (struct rcar_cpg_clk *)sys; - int ret = -EINVAL; + int ret; if (!dev || !sys) { return -EINVAL; @@ -163,6 +163,8 @@ static int r8a7795_cpg_mssr_start_stop(const struct device *dev, clock_control_s k_spin_unlock(&data->cmn.lock, key); } else if (clk->domain == CPG_CORE) { ret = r8a7795_cpg_core_clock_endisable(dev, clk, enable); + } else { + ret = -EINVAL; } return ret; @@ -170,8 +172,6 @@ static int r8a7795_cpg_mssr_start_stop(const struct device *dev, clock_control_s static uint32_t r8a7795_get_div_helper(uint32_t reg_val, uint32_t module) { - uint32_t divider = RCAR_CPG_NONE; - switch (module) { case R8A7795_CLK_SD0H: case R8A7795_CLK_SD1H: @@ -180,35 +180,29 @@ static uint32_t r8a7795_get_div_helper(uint32_t reg_val, uint32_t module) reg_val >>= R8A7795_CLK_SDH_DIV_SHIFT; /* setting of value bigger than 4 is prohibited */ if ((reg_val & R8A7795_CLK_SDH_DIV_MASK) < 5) { - divider = 1 << (reg_val & R8A7795_CLK_SDH_DIV_MASK); + return 1 << (reg_val & R8A7795_CLK_SDH_DIV_MASK); + } else { + return RCAR_CPG_NONE; } - break; case R8A7795_CLK_SD0: case R8A7795_CLK_SD1: case R8A7795_CLK_SD2: case R8A7795_CLK_SD3: /* convert only two possible values 0,1 to 2,4 */ - divider = 1 << ((reg_val & R8A7795_CLK_SD_DIV_MASK) + 1); - break; + return 1 << ((reg_val & R8A7795_CLK_SD_DIV_MASK) + 1); case R8A7795_CLK_CANFD: /* according to documentation, divider value stored in reg is equal to: val + 1 */ - divider = (reg_val & R8A7795_CLK_CANFD_DIV_MASK) + 1; - break; + return (reg_val & R8A7795_CLK_CANFD_DIV_MASK) + 1; case R8A7795_CLK_S3D4: case R8A7795_CLK_S0D12: - divider = 1; - break; + return 1; default: - break; + return RCAR_CPG_NONE; } - - return divider; } static int r8a7795_set_rate_helper(uint32_t module, uint32_t *divider, uint32_t *div_mask) { - int ret = -ENOTSUP; - switch (module) { case R8A7795_CLK_SD0: case R8A7795_CLK_SD1: @@ -219,40 +213,35 @@ static int r8a7795_set_rate_helper(uint32_t module, uint32_t *divider, uint32_t /* convert 2/4 to 0/1 */ *divider >>= 2; *div_mask = R8A7795_CLK_SD_DIV_MASK << R8A7795_CLK_SD_DIV_SHIFT; - ret = 0; + return 0; } else { - ret = -EINVAL; + return -EINVAL; } - break; case R8A7795_CLK_SD0H: case R8A7795_CLK_SD1H: case R8A7795_CLK_SD2H: case R8A7795_CLK_SD3H: /* divider should be power of two and max possible value 16 */ if (!is_power_of_two(*divider) || *divider > 16) { - ret = -EINVAL; + return -EINVAL; break; } - ret = 0; /* 1,2,4,8,16 have to be converted to 0,1,2,3,4 and then shifted */ *divider = (find_lsb_set(*divider) - 1) << R8A7795_CLK_SDH_DIV_SHIFT; *div_mask = R8A7795_CLK_SDH_DIV_MASK << R8A7795_CLK_SDH_DIV_SHIFT; - break; + return 0; case R8A7795_CLK_CANFD: /* according to documentation, divider value stored in reg is equal to: val + 1 */ *divider -= 1; if (*divider <= R8A7795_CLK_CANFD_DIV_MASK) { - ret = 0; *div_mask = R8A7795_CLK_CANFD_DIV_MASK; + return 0; } else { - ret = -EINVAL; + return -EINVAL; } - break; default: - break; + return -ENOTSUP; } - - return ret; } static int r8a7795_cpg_mssr_start(const struct device *dev, clock_control_subsys_t sys) From 4ae4217e588a9f75bf00310793791ef1696a1940 Mon Sep 17 00:00:00 2001 From: Anas Nashif Date: Mon, 22 Jan 2024 12:19:08 -0500 Subject: [PATCH 3012/3723] ci: run assigner bot on collab branches Get more reviewers added to make sure we have all relevant reviewers looking at changes targeting collab branches. Signed-off-by: Anas Nashif --- .github/workflows/assigner.yml | 1 + 1 file changed, 1 insertion(+) diff --git a/.github/workflows/assigner.yml b/.github/workflows/assigner.yml index 6a3198086de..b1a53fc93e4 100644 --- a/.github/workflows/assigner.yml +++ b/.github/workflows/assigner.yml @@ -9,6 +9,7 @@ on: - ready_for_review branches: - main + - collab-* - v*-branch issues: types: From a45d66c478085fa5fd86e6b95045184e9726c344 Mon Sep 17 00:00:00 2001 From: Jukka Rissanen Date: Sun, 28 Jan 2024 16:23:45 +0200 Subject: [PATCH 3013/3723] net: if: Do not join multicast address if IPv6 is not enabled If IPv6 is not enabled for the interface, then do not try to join the IPv6 solicited multicast address. Signed-off-by: Jukka Rissanen --- subsys/net/ip/net_if.c | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/subsys/net/ip/net_if.c b/subsys/net/ip/net_if.c index a5486ce4283..a2fb43f947b 100644 --- a/subsys/net/ip/net_if.c +++ b/subsys/net/ip/net_if.c @@ -2995,10 +2995,12 @@ static void iface_ipv6_start(struct net_if *iface) if (IS_ENABLED(CONFIG_NET_IPV6_DAD)) { net_if_start_dad(iface); } else { - struct net_if_ipv6 *ipv6 __unused = iface->config.ip.ipv6; + struct net_if_ipv6 *ipv6 = iface->config.ip.ipv6; - join_mcast_nodes(iface, - &ipv6->mcast[0].address.in6_addr); + if (ipv6 != NULL) { + join_mcast_nodes(iface, + &ipv6->mcast[0].address.in6_addr); + } } net_if_start_rs(iface); From 7da14d3129f6725a6e2ac47b3a1e5d97623db59f Mon Sep 17 00:00:00 2001 From: Jukka Rissanen Date: Sun, 28 Jan 2024 16:26:20 +0200 Subject: [PATCH 3014/3723] net: shell: Clarify the name of the virtual interface The net-shell printed virtual interface name so that it got the impression it was the network interface name which is not correct. Now the name is printed as "Virtual name" which is unambiguous. Signed-off-by: Jukka Rissanen --- subsys/net/lib/shell/iface.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/subsys/net/lib/shell/iface.c b/subsys/net/lib/shell/iface.c index 53d4e99bd21..fb0ed4e00fd 100644 --- a/subsys/net/lib/shell/iface.c +++ b/subsys/net/lib/shell/iface.c @@ -218,7 +218,7 @@ static void iface_cb(struct net_if *iface, void *user_data) name = ""; } - PR("Name : %s\n", name); + PR("Virtual name : %s\n", name); orig_iface = net_virtual_get_iface(iface); if (orig_iface == NULL) { From a9ffd91294fc8d0cc29c20136bd2e986daa86af6 Mon Sep 17 00:00:00 2001 From: Bjarki Arge Andreasen Date: Wed, 24 Jan 2024 08:48:30 +0100 Subject: [PATCH 3015/3723] drivers: gnss: lcx6g: Remove left over from testing The k_msleep() removed with this has no utility. Signed-off-by: Bjarki Arge Andreasen --- drivers/gnss/gnss_quectel_lcx6g.c | 2 -- 1 file changed, 2 deletions(-) diff --git a/drivers/gnss/gnss_quectel_lcx6g.c b/drivers/gnss/gnss_quectel_lcx6g.c index 9c706e237a3..8ab3b26a6d9 100644 --- a/drivers/gnss/gnss_quectel_lcx6g.c +++ b/drivers/gnss/gnss_quectel_lcx6g.c @@ -195,8 +195,6 @@ static int quectel_lcx6g_resume(const struct device *dev) return ret; } - k_msleep(1000); - ret = quectel_lcx6g_configure_pps(dev); if (ret < 0) { modem_pipe_close(data->uart_pipe); From 59b9a86f30af343c16bc2f7b35d328fe91e5e718 Mon Sep 17 00:00:00 2001 From: Bjarki Arge Andreasen Date: Wed, 24 Jan 2024 09:06:26 +0100 Subject: [PATCH 3016/3723] drivers: gnss: lcx7g: Refactor power management The implementation of power management did not account for being on a power domain when initializing, and handling being powered on and off at runtime. The GNSS requires time to start up, which it always does when powered on, before accepting commands. It also requires time after resuming and suspending before accepting commands. This commit implements this timeout, and improves logging to make the power management more transparent, and removes some redundant parenthesis for better readability. Signed-off-by: Bjarki Arge Andreasen --- drivers/gnss/gnss_quectel_lcx6g.c | 91 +++++++++++++++++++++++-------- 1 file changed, 67 insertions(+), 24 deletions(-) diff --git a/drivers/gnss/gnss_quectel_lcx6g.c b/drivers/gnss/gnss_quectel_lcx6g.c index 8ab3b26a6d9..30919f963ac 100644 --- a/drivers/gnss/gnss_quectel_lcx6g.c +++ b/drivers/gnss/gnss_quectel_lcx6g.c @@ -22,20 +22,18 @@ #include LOG_MODULE_REGISTER(quectel_lcx6g, CONFIG_GNSS_LOG_LEVEL); -#define QUECTEL_LCX6G_STARTUP_DELAY (K_MSEC(300U)) -#define QUECTEL_LCX6G_STATE_CHANGE_DELAY_MSEC (300LL) -#define QUECTEL_LCX6G_PAIR_TIMEOUT (K_SECONDS(11)) -#define QUECTEL_LCX6G_SCRIPT_TIMEOUT_S (10U) +#define QUECTEL_LCX6G_PM_TIMEOUT_MS 500U +#define QUECTEL_LCX6G_SCRIPT_TIMEOUT_S 10U -#define QUECTEL_LCX6G_PAIR_NAV_MODE_STATIONARY (4) -#define QUECTEL_LCX6G_PAIR_NAV_MODE_FITNESS (1) -#define QUECTEL_LCX6G_PAIR_NAV_MODE_NORMAL (0) -#define QUECTEL_LCX6G_PAIR_NAV_MODE_DRONE (5) +#define QUECTEL_LCX6G_PAIR_NAV_MODE_STATIONARY 4 +#define QUECTEL_LCX6G_PAIR_NAV_MODE_FITNESS 1 +#define QUECTEL_LCX6G_PAIR_NAV_MODE_NORMAL 0 +#define QUECTEL_LCX6G_PAIR_NAV_MODE_DRONE 5 -#define QUECTEL_LCX6G_PAIR_PPS_MODE_DISABLED (0) -#define QUECTEL_LCX6G_PAIR_PPS_MODE_ENABLED (4) -#define QUECTEL_LCX6G_PAIR_PPS_MODE_ENABLED_AFTER_LOCK (1) -#define QUECTEL_LCX6G_PAIR_PPS_MODE_ENABLED_WHILE_LOCKED (2) +#define QUECTEL_LCX6G_PAIR_PPS_MODE_DISABLED 0 +#define QUECTEL_LCX6G_PAIR_PPS_MODE_ENABLED 4 +#define QUECTEL_LCX6G_PAIR_PPS_MODE_ENABLED_AFTER_LOCK 1 +#define QUECTEL_LCX6G_PAIR_PPS_MODE_ENABLED_WHILE_LOCKED 2 struct quectel_lcx6g_config { const struct device *uart; @@ -77,6 +75,7 @@ struct quectel_lcx6g_data { }; struct k_spinlock lock; + k_timeout_t pm_timeout; }; #define MODEM_CHAT_SCRIPT_NO_ABORT_DEFINE(_sym, _script_chats, _callback, _timeout) \ @@ -173,33 +172,60 @@ static int quectel_lcx6g_configure_pps(const struct device *dev) return modem_chat_run_script(&data->chat, &data->dynamic_script); } +static void quectel_lcx6g_pm_changed(const struct device *dev) +{ + struct quectel_lcx6g_data *data = dev->data; + uint32_t pm_ready_at_ms; + + pm_ready_at_ms = k_uptime_get() + QUECTEL_LCX6G_PM_TIMEOUT_MS; + data->pm_timeout = K_TIMEOUT_ABS_MS(pm_ready_at_ms); +} + +static void quectel_lcx6g_await_pm_ready(const struct device *dev) +{ + struct quectel_lcx6g_data *data = dev->data; + + LOG_INF("Waiting until PM ready"); + k_sleep(data->pm_timeout); +} + static int quectel_lcx6g_resume(const struct device *dev) { struct quectel_lcx6g_data *data = dev->data; int ret; + LOG_INF("Resuming"); + + quectel_lcx6g_await_pm_ready(dev); + ret = modem_pipe_open(data->uart_pipe); if (ret < 0) { + LOG_ERR("Failed to open pipe"); return ret; } ret = modem_chat_attach(&data->chat, data->uart_pipe); if (ret < 0) { + LOG_ERR("Failed to attach chat"); modem_pipe_close(data->uart_pipe); return ret; } ret = modem_chat_run_script(&data->chat, &resume_script); if (ret < 0) { + LOG_ERR("Failed to initialize GNSS"); modem_pipe_close(data->uart_pipe); return ret; } ret = quectel_lcx6g_configure_pps(dev); if (ret < 0) { + LOG_ERR("Failed to configure PPS"); modem_pipe_close(data->uart_pipe); + return ret; } + LOG_INF("Resumed"); return ret; } @@ -209,18 +235,32 @@ static int quectel_lcx6g_suspend(const struct device *dev) struct quectel_lcx6g_data *data = dev->data; int ret; + LOG_INF("Suspending"); + + quectel_lcx6g_await_pm_ready(dev); + ret = modem_chat_run_script(&data->chat, &suspend_script); if (ret < 0) { + LOG_ERR("Failed to suspend GNSS"); modem_pipe_close(data->uart_pipe); + return ret; } + LOG_INF("Suspended"); return ret; } +static void quectel_lcx6g_turn_on(const struct device *dev) +{ + LOG_INF("Powered on"); +} + static int quectel_lcx6g_turn_off(const struct device *dev) { struct quectel_lcx6g_data *data = dev->data; + LOG_INF("Powered off"); + return modem_pipe_close(data->uart_pipe); } @@ -242,6 +282,7 @@ static int quectel_lcx6g_pm_action(const struct device *dev, enum pm_device_acti break; case PM_DEVICE_ACTION_TURN_ON: + quectel_lcx6g_turn_on(dev); ret = 0; break; @@ -253,6 +294,8 @@ static int quectel_lcx6g_pm_action(const struct device *dev, enum pm_device_acti break; } + quectel_lcx6g_pm_changed(dev); + k_spin_unlock(&data->lock, key); return ret; } @@ -717,7 +760,6 @@ static int quectel_lcx6g_init(const struct device *dev) { int ret; - LOG_INF("Initializing Quectel LCX6G"); ret = quectel_lcx6g_init_nmea0183_match(dev); if (ret < 0) { return ret; @@ -732,18 +774,19 @@ static int quectel_lcx6g_init(const struct device *dev) quectel_lcx6g_init_dynamic_script(dev); -#ifdef CONFIG_PM_DEVICE_RUNTIME - pm_device_init_suspended(dev); -#else - LOG_INF("Resuming Quectel LCX6G"); - ret = quectel_lcx6g_resume(dev); - if (ret < 0) { - LOG_ERR("Failed to resume Quectel LCX6G"); - return ret; + quectel_lcx6g_pm_changed(dev); + + if (pm_device_is_powered(dev)) { + ret = quectel_lcx6g_resume(dev); + if (ret < 0) { + return ret; + } + quectel_lcx6g_pm_changed(dev); + } else { + pm_device_init_off(dev); } -#endif - LOG_INF("Quectel LCX6G initialized"); - return 0; + + return pm_device_runtime_enable(dev); } #define LCX6G_INST_NAME(inst, name) \ From 41240f9fb1074ec4cf7d486a86b8062e2a7e39ed Mon Sep 17 00:00:00 2001 From: Bjarki Arge Andreasen Date: Wed, 24 Jan 2024 10:16:09 +0100 Subject: [PATCH 3017/3723] drivers: gnss: lcx7g: Close pipe on suspend The pipe should be closed when suspended, both to save ressources and to flush it. Without flushing the pipe, the driver may fail to either resume or suspend the GNSS as the chat module starts processing old data, which can contain acks to commands, breaking the scripts. Signed-off-by: Bjarki Arge Andreasen --- drivers/gnss/gnss_quectel_lcx6g.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/drivers/gnss/gnss_quectel_lcx6g.c b/drivers/gnss/gnss_quectel_lcx6g.c index 30919f963ac..ee15a573ffe 100644 --- a/drivers/gnss/gnss_quectel_lcx6g.c +++ b/drivers/gnss/gnss_quectel_lcx6g.c @@ -242,11 +242,11 @@ static int quectel_lcx6g_suspend(const struct device *dev) ret = modem_chat_run_script(&data->chat, &suspend_script); if (ret < 0) { LOG_ERR("Failed to suspend GNSS"); - modem_pipe_close(data->uart_pipe); - return ret; + } else { + LOG_INF("Suspended"); } - LOG_INF("Suspended"); + modem_pipe_close(data->uart_pipe); return ret; } From 98d95851c6778e86fca22dec3314fcd756ae25a9 Mon Sep 17 00:00:00 2001 From: Bjarki Arge Andreasen Date: Wed, 24 Jan 2024 10:39:29 +0100 Subject: [PATCH 3018/3723] drivers: gnss: lcx7g: Add Kconfigs for configurable buffers Added Kconfigs to define the size of: - UART backend receive buffer - UART backend transmit buffer - Satellites array size and increased the UART RX buffer size a default to 256 as 128 is just on the edge of to small at a baudrate of 115200. Signed-off-by: Bjarki Arge Andreasen --- drivers/gnss/Kconfig.quectel_lcx6g | 20 ++++++++++++++++++++ drivers/gnss/gnss_quectel_lcx6g.c | 6 +++--- 2 files changed, 23 insertions(+), 3 deletions(-) diff --git a/drivers/gnss/Kconfig.quectel_lcx6g b/drivers/gnss/Kconfig.quectel_lcx6g index 6736015aed7..3036f76d05b 100644 --- a/drivers/gnss/Kconfig.quectel_lcx6g +++ b/drivers/gnss/Kconfig.quectel_lcx6g @@ -15,3 +15,23 @@ config GNSS_QUECTEL_LCX6G select GNSS_NMEA0183_MATCH help Enable quectel LCX6G series GNSS modem driver. + +if GNSS_QUECTEL_LCX6G + +config GNSS_QUECTEL_LCX6G_UART_RX_BUF_SIZE + int "Size of UART backend receive buffer" + default 256 + +config GNSS_QUECTEL_LCX6G_UART_TX_BUF_SIZE + int "Size of UART backend transmit buffer" + default 64 + +if GNSS_SATELLITES + +config GNSS_QUECTEL_LCX6G_SAT_ARRAY_SIZE + int "Size of GNSS satellites array" + default 24 + +endif # GNSS_SATELLITES + +endif # GNSS_QUECTEL_LCX6G diff --git a/drivers/gnss/gnss_quectel_lcx6g.c b/drivers/gnss/gnss_quectel_lcx6g.c index ee15a573ffe..09fa8fd8e4a 100644 --- a/drivers/gnss/gnss_quectel_lcx6g.c +++ b/drivers/gnss/gnss_quectel_lcx6g.c @@ -44,14 +44,14 @@ struct quectel_lcx6g_config { struct quectel_lcx6g_data { struct gnss_nmea0183_match_data match_data; #if CONFIG_GNSS_SATELLITES - struct gnss_satellite satellites[24]; + struct gnss_satellite satellites[CONFIG_GNSS_QUECTEL_LCX6G_SAT_ARRAY_SIZE]; #endif /* UART backend */ struct modem_pipe *uart_pipe; struct modem_backend_uart uart_backend; - uint8_t uart_backend_receive_buf[128]; - uint8_t uart_backend_transmit_buf[64]; + uint8_t uart_backend_receive_buf[CONFIG_GNSS_QUECTEL_LCX6G_UART_RX_BUF_SIZE]; + uint8_t uart_backend_transmit_buf[CONFIG_GNSS_QUECTEL_LCX6G_UART_TX_BUF_SIZE]; /* Modem chat */ struct modem_chat chat; From 8596ee933730a63e13d4c367c8fbd1a0e8f77cca Mon Sep 17 00:00:00 2001 From: Daniel DeGrasse Date: Fri, 8 Dec 2023 18:41:33 +0000 Subject: [PATCH 3019/3723] samples: drivers: i2s: add output sample Add simple I2S output sample. This sample is verified with the RT1060 EVKB, but can be ported to any board with I2S support. It simply demonstrates how to write I2S output data using the I2S API. The output can be verified using a signal analyzer, if the user desires. Signed-off-by: Daniel DeGrasse --- samples/drivers/i2s/output/CMakeLists.txt | 8 ++ samples/drivers/i2s/output/README.rst | 36 +++++ .../i2s/output/boards/mimxrt1060_evkb.conf | 2 + .../i2s/output/boards/mimxrt1060_evkb.overlay | 11 ++ samples/drivers/i2s/output/prj.conf | 1 + samples/drivers/i2s/output/sample.yaml | 9 ++ samples/drivers/i2s/output/src/main.c | 128 ++++++++++++++++++ 7 files changed, 195 insertions(+) create mode 100644 samples/drivers/i2s/output/CMakeLists.txt create mode 100644 samples/drivers/i2s/output/README.rst create mode 100644 samples/drivers/i2s/output/boards/mimxrt1060_evkb.conf create mode 100644 samples/drivers/i2s/output/boards/mimxrt1060_evkb.overlay create mode 100644 samples/drivers/i2s/output/prj.conf create mode 100644 samples/drivers/i2s/output/sample.yaml create mode 100644 samples/drivers/i2s/output/src/main.c diff --git a/samples/drivers/i2s/output/CMakeLists.txt b/samples/drivers/i2s/output/CMakeLists.txt new file mode 100644 index 00000000000..100cc967f23 --- /dev/null +++ b/samples/drivers/i2s/output/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(i2s_output) + +target_sources(app PRIVATE src/main.c) diff --git a/samples/drivers/i2s/output/README.rst b/samples/drivers/i2s/output/README.rst new file mode 100644 index 00000000000..d8e10d81e0e --- /dev/null +++ b/samples/drivers/i2s/output/README.rst @@ -0,0 +1,36 @@ +.. zephyr:code-sample:: i2s-output + :name: I2S output + :relevant-api: i2s_interface + + Send I2S output stream + +Overview +******** + +This sample demonstrates how to use an I2S driver to send an output stream of +audio data. Currently, no codec is used with this sample. The I2S output can +be verified with a signal analyzer. + +The sample will send a short burst of audio data, consisting of a sine wave. +The I2S TX queue will then be drained, and audio output will stop. + +Requirements +************ + +The I2S device to be used by the sample is specified by defining +a devicetree alias named ``i2s_tx`` + +This sample has been tested on :ref:`mimxrt1060_evk` (mimxrt1060_evkb) + +Building and Running +******************** + +The code can be found in :zephyr_file:`samples/drivers/i2s/output`. + +To build and flash the application: + +.. zephyr-app-commands:: + :zephyr-app: samples/drivers/i2s/output + :board: mimxrt1060_evkb + :goals: build flash + :compact: diff --git a/samples/drivers/i2s/output/boards/mimxrt1060_evkb.conf b/samples/drivers/i2s/output/boards/mimxrt1060_evkb.conf new file mode 100644 index 00000000000..c27a69285c6 --- /dev/null +++ b/samples/drivers/i2s/output/boards/mimxrt1060_evkb.conf @@ -0,0 +1,2 @@ +# Raise DMA TCD Queue size, as this is required by the I2S SAI driver +CONFIG_DMA_TCD_QUEUE_SIZE=4 diff --git a/samples/drivers/i2s/output/boards/mimxrt1060_evkb.overlay b/samples/drivers/i2s/output/boards/mimxrt1060_evkb.overlay new file mode 100644 index 00000000000..92ffdea0a37 --- /dev/null +++ b/samples/drivers/i2s/output/boards/mimxrt1060_evkb.overlay @@ -0,0 +1,11 @@ +/* + * Copyright 2023 NXP + * + * SPDX-License-Identifier: Apache-2.0 + */ + +/ { + aliases { + i2s-tx = &sai1; + }; +}; diff --git a/samples/drivers/i2s/output/prj.conf b/samples/drivers/i2s/output/prj.conf new file mode 100644 index 00000000000..c1378264b96 --- /dev/null +++ b/samples/drivers/i2s/output/prj.conf @@ -0,0 +1 @@ +CONFIG_I2S=y diff --git a/samples/drivers/i2s/output/sample.yaml b/samples/drivers/i2s/output/sample.yaml new file mode 100644 index 00000000000..8763b5128b2 --- /dev/null +++ b/samples/drivers/i2s/output/sample.yaml @@ -0,0 +1,9 @@ +sample: + description: I2S Output Sample + name: i2s_output +common: + tags: drivers + depends_on: i2s +tests: + sample.drivers.i2s.output: + filter: dt_alias_exists("i2s-tx") diff --git a/samples/drivers/i2s/output/src/main.c b/samples/drivers/i2s/output/src/main.c new file mode 100644 index 00000000000..34f1629ceb3 --- /dev/null +++ b/samples/drivers/i2s/output/src/main.c @@ -0,0 +1,128 @@ +/* + * Copyright 2023 NXP + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include +#include +#include +#include + +#define SAMPLE_NO 64 + +/* The data represent a sine wave */ +static int16_t data[SAMPLE_NO] = { + 3211, 6392, 9511, 12539, 15446, 18204, 20787, 23169, + 25329, 27244, 28897, 30272, 31356, 32137, 32609, 32767, + 32609, 32137, 31356, 30272, 28897, 27244, 25329, 23169, + 20787, 18204, 15446, 12539, 9511, 6392, 3211, 0, + -3212, -6393, -9512, -12540, -15447, -18205, -20788, -23170, + -25330, -27245, -28898, -30273, -31357, -32138, -32610, -32767, + -32610, -32138, -31357, -30273, -28898, -27245, -25330, -23170, + -20788, -18205, -15447, -12540, -9512, -6393, -3212, -1, +}; + +/* Fill buffer with sine wave on left channel, and sine wave shifted by + * 90 degrees on right channel. "att" represents a power of two to attenuate + * the samples by + */ +static void fill_buf(int16_t *tx_block, int att) +{ + int r_idx; + + for (int i = 0; i < SAMPLE_NO; i++) { + /* Left channel is sine wave */ + tx_block[2 * i] = data[i] / (1 << att); + /* Right channel is same sine wave, shifted by 90 degrees */ + r_idx = (i + (ARRAY_SIZE(data) / 4)) % ARRAY_SIZE(data); + tx_block[2 * i + 1] = data[r_idx] / (1 << att); + } +} + +#define NUM_BLOCKS 20 +#define BLOCK_SIZE (2 * sizeof(data)) + +#ifdef CONFIG_NOCACHE_MEMORY + #define MEM_SLAB_CACHE_ATTR __nocache +#else + #define MEM_SLAB_CACHE_ATTR +#endif /* CONFIG_NOCACHE_MEMORY */ + +static char MEM_SLAB_CACHE_ATTR __aligned(WB_UP(32)) + _k_mem_slab_buf_tx_0_mem_slab[(NUM_BLOCKS) * WB_UP(BLOCK_SIZE)]; + +static STRUCT_SECTION_ITERABLE(k_mem_slab, tx_0_mem_slab) = + Z_MEM_SLAB_INITIALIZER(tx_0_mem_slab, _k_mem_slab_buf_tx_0_mem_slab, + WB_UP(BLOCK_SIZE), NUM_BLOCKS); + +int main(void) +{ + void *tx_block[NUM_BLOCKS]; + struct i2s_config i2s_cfg; + int ret; + uint32_t tx_idx; + const struct device *dev_i2s = DEVICE_DT_GET(DT_ALIAS(i2s_tx)); + + if (!device_is_ready(dev_i2s)) { + printf("I2S device not ready\n"); + return -ENODEV; + } + /* Configure I2S stream */ + i2s_cfg.word_size = 16U; + i2s_cfg.channels = 2U; + i2s_cfg.format = I2S_FMT_DATA_FORMAT_I2S; + i2s_cfg.frame_clk_freq = 44100; + i2s_cfg.block_size = BLOCK_SIZE; + i2s_cfg.timeout = 2000; + /* Configure the Transmit port as Master */ + i2s_cfg.options = I2S_OPT_FRAME_CLK_MASTER + | I2S_OPT_BIT_CLK_MASTER; + i2s_cfg.mem_slab = &tx_0_mem_slab; + ret = i2s_configure(dev_i2s, I2S_DIR_TX, &i2s_cfg); + if (ret < 0) { + printf("Failed to configure I2S stream\n"); + return ret; + } + + /* Prepare all TX blocks */ + for (tx_idx = 0; tx_idx < NUM_BLOCKS; tx_idx++) { + ret = k_mem_slab_alloc(&tx_0_mem_slab, &tx_block[tx_idx], + K_FOREVER); + if (ret < 0) { + printf("Failed to allocate TX block\n"); + return ret; + } + fill_buf((uint16_t *)tx_block[tx_idx], tx_idx % 3); + } + + tx_idx = 0; + /* Send first block */ + ret = i2s_write(dev_i2s, tx_block[tx_idx++], BLOCK_SIZE); + if (ret < 0) { + printf("Could not write TX buffer %d\n", tx_idx); + return ret; + } + /* Trigger the I2S transmission */ + ret = i2s_trigger(dev_i2s, I2S_DIR_TX, I2S_TRIGGER_START); + if (ret < 0) { + printf("Could not trigger I2S tx\n"); + return ret; + } + + for (; tx_idx < NUM_BLOCKS; ) { + ret = i2s_write(dev_i2s, tx_block[tx_idx++], BLOCK_SIZE); + if (ret < 0) { + printf("Could not write TX buffer %d\n", tx_idx); + return ret; + } + } + /* Drain TX queue */ + ret = i2s_trigger(dev_i2s, I2S_DIR_TX, I2S_TRIGGER_DRAIN); + if (ret < 0) { + printf("Could not trigger I2S tx\n"); + return ret; + } + printf("All I2S blocks written\n"); + return 0; +} From c7cc58ca771a18faa0a8cb5c7f10a3b8bd429776 Mon Sep 17 00:00:00 2001 From: Marc Desvaux Date: Fri, 19 Jan 2024 10:38:38 +0100 Subject: [PATCH 3020/3723] drivers: usb_dc_stm32: Fix OUT transfer issue The driver cannot handle OUT transactions for an endpoint with an MPS smaller than 64 bytes. To solve the issue, we will not use one fixed value, EP_MPS, but instead use the actual MPS of an endpoint, ep_state->ep_mps. Signed-off-by: Marc Desvaux Signed-off-by: Loic Poulain --- drivers/usb/device/usb_dc_stm32.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/usb/device/usb_dc_stm32.c b/drivers/usb/device/usb_dc_stm32.c index 326c6e284a2..13131061610 100644 --- a/drivers/usb/device/usb_dc_stm32.c +++ b/drivers/usb/device/usb_dc_stm32.c @@ -784,7 +784,7 @@ int usb_dc_ep_enable(const uint8_t ep) if (USB_EP_DIR_IS_OUT(ep) && ep != EP0_OUT) { return usb_dc_ep_start_read(ep, usb_dc_stm32_state.ep_buf[USB_EP_GET_IDX(ep)], - EP_MPS); + ep_state->ep_mps); } return 0; @@ -923,7 +923,7 @@ int usb_dc_ep_read_continue(uint8_t ep) */ if (!ep_state->read_count) { usb_dc_ep_start_read(ep, usb_dc_stm32_state.ep_buf[USB_EP_GET_IDX(ep)], - EP_MPS); + ep_state->ep_mps); } return 0; From 38da03a5d6e96e1313ec94f6d59241e478eaa78f Mon Sep 17 00:00:00 2001 From: Javad Rahimipetroudi Date: Mon, 29 Jan 2024 07:35:06 +0100 Subject: [PATCH 3021/3723] doc: stm32wb5mm_dk: Fix reported typos This patch fix the reported typos and glitches that was reported in PR 67819. Signed-off-by: Javad Rahimipetroudi --- .../arm/stm32wb5mm_dk/doc/stm32wb5mm_dk.rst | 48 +++++++++++-------- 1 file changed, 27 insertions(+), 21 deletions(-) diff --git a/boards/arm/stm32wb5mm_dk/doc/stm32wb5mm_dk.rst b/boards/arm/stm32wb5mm_dk/doc/stm32wb5mm_dk.rst index b23361a30f5..61b70106601 100644 --- a/boards/arm/stm32wb5mm_dk/doc/stm32wb5mm_dk.rst +++ b/boards/arm/stm32wb5mm_dk/doc/stm32wb5mm_dk.rst @@ -8,8 +8,8 @@ Overview The STM32WB5MM-DK Discovery kit is designed as a complete demonstration and development platform for the STMicroelectronics STM32W5MMG module based -on the Arm |reg| Cortex |reg|-M4 and Arm |reg| Cortex |reg|-M0+ cores. The -STM32 device is a multi-protocol wireless and ultra-low-power device +on the Arm |reg| Cortex |reg|-M4 and Arm |reg| Cortex |reg|-M0+ cores. +The STM32 device is a multi-protocol wireless and ultra-low-power device embedding a powerful and ultra-low-power radio compliant with the Bluetooth |reg| Low Energy (BLE) SIG specification v5.2 and with IEEE 802.15.4-2011. @@ -29,6 +29,7 @@ STM32WB5MM-DK supports the following features: - RGB LED - Infrared LED - 3 push-buttons (2 users and 1 reset) and 1 touch key button + * Board connectors: - STMod+ - ARDUINO |reg| Uno V3 expansion connector @@ -41,6 +42,7 @@ STM32WB5MM-DK supports the following features: - ARDUINO |reg|, - external connector, - USB charger, or USB power + * On-board ST-LINK/V2-1 debugger/programmer with USB re-enumeration - Virtual COM port and debug port @@ -49,30 +51,32 @@ STM32WB5MM-DK supports the following features: :align: center :alt: STM32WB5MM-DK -More information about the board can be found at the `` `STM32WB5MM-DK on www.st.com`_. +More information about the board can be found in `STM32WB5MM-DK on www.st.com`_. Hardware ******** STM32WB5MMG is an ultra-low-power and small form factor certified 2.4 GHz -wireless module. It supportsBluetooth |reg| Low Energy 5.4, Zigbee |reg| 3.0, -OpenThread, dynamic, and static concurrent modes, and 802.15.4proprietary -protocols. Based on the STMicroelectronics STM32WB55VGY wireless -microcontroller,STM32WB5MMG provides best-in-class RF performance thanks -to its high receiver sensitivity and output power signal. Its low-power -features enable extended battery life, small coin-cell batteries, and -energy harvesting. +wireless module. It supports Bluetooth |reg| Low Energy 5.4, Zigbee |reg| 3.0, +OpenThread, dynamic, and static concurrent modes, and 802.15.4 proprietary +protocols. + +Based on the STMicroelectronics STM32WB55VGY wireless microcontroller, +STM32WB5MMG provides best-in-class RF performance thanks to its high +receiver sensitivity and output power signal. Its low-power features +enable extended battery life, small coin-cell batteries, and energy harvesting. - Ultra-low-power with FlexPowerControl - Core: ARM |reg| 32-bit Cortex |reg|-M4 CPU with FPU - Radio: -- 2.4GHz + - 2.4GHz - RF transceiver supporting: - Bluetooth |reg| 5.4 specification, - IEEE 802.15.4-2011 PHY and MAC, - - Zigbee|reg| 3.0 + - Zigbee |reg| 3.0 + - RX sensitivity: - -96 dBm (Bluetooth |reg| Low Energy at 1 Mbps), @@ -130,13 +134,15 @@ Bluetooth and compatibility with STM32WB Copro Wireless Binaries To operate bluetooth on STM32WB5MMG, Cortex-M0 core should be flashed with a valid STM32WB Coprocessor binaries (either 'Full stack' or 'HCI Layer'). These binaries are delivered in STM32WB Cube packages, under -Projects/STM32WB_Copro_Wireless_Binaries/STM32WB5x/ +``Projects/STM32WB_Copro_Wireless_Binaries/STM32WB5x/``. + For compatibility information with the various versions of these binaries, please check `modules/hal/stm32/lib/stm32wb/hci/README`_ -in the hal_stm32 repo. -Note that since STM32WB Cube package V1.13.2, "full stack" binaries are not compatible -anymore for a use in Zephyr and only "HCI Only" versions should be used on the M0 -side. +in the ``hal_stm32`` repo. + +Note that since STM32WB Cube package V1.13.2, `"full stack"` binaries are not +compatible anymore for a use in Zephyr and only `"HCI Only"` versions should be +used on the M0 side. Connections and IOs =================== @@ -162,7 +168,7 @@ Serial Port ----------- STM32WB5MM-DK board has 2 (LP)U(S)ARTs. The Zephyr console output is assigned to USART1. -Default settings are 115200 8N1. +Default settings are ``115200 8N1``. Programming and Debugging @@ -174,12 +180,12 @@ usual way (see :ref:`build_an_application`). Flashing ======== -STM32WB5MM-DK has onboard ST-Link to flash and debug the firmware on the +STM32WB5MM-DK has an on-board ST-Link to flash and debug the firmware on the module. -Flashing `hello_world` application to STM32WB5MM-DK ----------------------------------------------------- +Flashing ``hello_world`` application to STM32WB5MM-DK +------------------------------------------------------ Connect the STM32WB5MM-DK to your host computer using the USB port (CN11). Then build and flash an application. Here is an example for the ``hello_world`` From 6dcde57952129a133e6dc601a4b20fb378f8493c Mon Sep 17 00:00:00 2001 From: Ping Wang Date: Thu, 25 Jan 2024 12:17:51 +0100 Subject: [PATCH 3022/3723] Bluetooth: Audio: improve BASS state logging to be more readable. When debugging it is hard to remember each state value (e.g. 0, 1, 2, 3) means. Therefore, make functions to improve logging for humans. Fixes #59679 Signed-off-by: Ping Wang --- subsys/bluetooth/audio/bap_internal.h | 34 +++++++++++++++++++ .../audio/shell/bap_scan_delegator.c | 7 ++-- 2 files changed, 38 insertions(+), 3 deletions(-) diff --git a/subsys/bluetooth/audio/bap_internal.h b/subsys/bluetooth/audio/bap_internal.h index 5a4bf8fb819..5eb53f5de58 100644 --- a/subsys/bluetooth/audio/bap_internal.h +++ b/subsys/bluetooth/audio/bap_internal.h @@ -89,3 +89,37 @@ union bt_bap_bass_cp { struct bt_bap_bass_cp_broadcase_code broadcast_code; struct bt_bap_bass_cp_rem_src rem_src; }; + +static inline const char *bt_bap_pa_state_str(uint8_t state) +{ + switch (state) { + case BT_BAP_PA_STATE_NOT_SYNCED: + return "Not synchronized to PA"; + case BT_BAP_PA_STATE_INFO_REQ: + return "SyncInfo Request"; + case BT_BAP_PA_STATE_SYNCED: + return "Synchronized to PA"; + case BT_BAP_PA_STATE_FAILED: + return "Failed to synchronize to PA"; + case BT_BAP_PA_STATE_NO_PAST: + return "No PAST"; + default: + return "unknown state"; + } +} + +static inline const char *bt_bap_big_enc_state_str(uint8_t state) +{ + switch (state) { + case BT_BAP_BIG_ENC_STATE_NO_ENC: + return "Not encrypted"; + case BT_BAP_BIG_ENC_STATE_BCODE_REQ: + return "Broadcast_Code required"; + case BT_BAP_BIG_ENC_STATE_DEC: + return "Decrypting"; + case BT_BAP_BIG_ENC_STATE_BAD_CODE: + return "Bad_Code (incorrect encryption key)"; + default: + return "unknown state"; + } +} diff --git a/subsys/bluetooth/audio/shell/bap_scan_delegator.c b/subsys/bluetooth/audio/shell/bap_scan_delegator.c index 9ca494d36ae..721553f4ad1 100644 --- a/subsys/bluetooth/audio/shell/bap_scan_delegator.c +++ b/subsys/bluetooth/audio/shell/bap_scan_delegator.c @@ -16,6 +16,7 @@ #include #include #include +#include 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�%gP58--D=>>=)}(7HD9`{P%T9a zq#?w}U=qJOC2kP(^pfL|PVrM3wdDk8G|#AadHRZ5%sSp!`zAE;-SE%Q`alxBs8juG zeZl3iv!#R)RG4Wv6l^msX{rm8g{;`$Rx#>&MfX$LiXL5CkS31LHqGlW=ejlY`a-5o zvT#b&ol#K=l8A!ml9*o)o1Q7Ag#v*`qLG`w|u;yrF2+jIVi>|5;3v5L*lC{WgwBeK`l=aizn;Inxp6PyQ3qWkBh zO_CuoCR4w2R=D#t@3*PKYc zt=&N!zeL&;jK2Oi1quJ5pvV8U;J>R;^nX#~|G41)vupex*9hF4KhO2#uKwfZu%GmZ zKaayG*|g^I@5hmO4jk~$4#90*YrXWR;CIHL|6c`vcV4Esf8W&DoB!wll-Da-h;7AU t0Y_xIK#vqqrqKjZnH$R*|2)f?(?`=WW;K)9*bu5nO$g>;4CXl+{uc&rB&7fV literal 0 HcmV?d00001 diff --git a/boards/arm/efr32_radio/efr32_radio_brd4161a.dts b/boards/arm/efr32_radio/efr32_radio_brd4161a.dts new file mode 100644 index 00000000000..6f1cba19b5c --- /dev/null +++ b/boards/arm/efr32_radio/efr32_radio_brd4161a.dts @@ -0,0 +1,70 @@ +/* + * Copyright (c) 2020 Piotr Mienkowski + * + * SPDX-License-Identifier: Apache-2.0 + */ + +/dts-v1/; +#include +#include +#include "efr32_radio.dtsi" + +/ { + model = "Silicon Labs BRD4161A (Mighty Gecko Radio Board)"; + compatible = "silabs,efr32_radio_brd4161a", "silabs,efr32mg12p"; + + aliases { + spi-flash0 = &mx25r80; + }; +}; + +&cpu0 { + clock-frequency = <38400000>; +}; + +&flash0 { + partitions { + compatible = "fixed-partitions"; + #address-cells = <1>; + #size-cells = <1>; + + /* Reserve 32 kB for the bootloader */ + boot_partition: partition@0 { + label = "mcuboot"; + reg = <0x0 0x00008000>; + read-only; + }; + + /* Reserve 220 kB for the application in slot 0 */ + slot0_partition: partition@8000 { + label = "image-0"; + reg = <0x00008000 0x00037000>; + }; + + /* Reserve 220 kB for the application in slot 1 */ + slot1_partition: partition@3f000 { + label = "image-1"; + reg = <0x0003f000 0x00037000>; + }; + + /* Reserve 32 kB for the scratch partition */ + scratch_partition: partition@76000 { + label = "image-scratch"; + reg = <0x00076000 0x00008000>; + }; + + /* Set 8Kb of storage at the end of the 512KB of flash */ + storage_partition: partition@7e000 { + label = "storage"; + reg = <0x0007e000 0x00002000>; + }; + + }; +}; + +&usart0 { + current-speed = <115200>; + pinctrl-0 = <&usart0_default>; + pinctrl-names = "default"; + status = "okay"; +}; diff --git a/boards/arm/efr32_radio/efr32_radio_brd4161a.yaml b/boards/arm/efr32_radio/efr32_radio_brd4161a.yaml new file mode 100644 index 00000000000..108d6f16c0f --- /dev/null +++ b/boards/arm/efr32_radio/efr32_radio_brd4161a.yaml @@ -0,0 +1,21 @@ +identifier: efr32_radio_brd4161a +name: BRD4161A +type: mcu +arch: arm +ram: 256 +flash: 1024 +toolchain: + - zephyr + - gnuarmemb +supported: + - counter + - gpio + - nvs + - spi + - uart + - watchdog +testing: + ignore_tags: + - net + - bluetooth +vendor: silabs diff --git a/boards/arm/efr32_radio/efr32_radio_brd4161a_defconfig b/boards/arm/efr32_radio/efr32_radio_brd4161a_defconfig new file mode 100644 index 00000000000..fbf7cf38325 --- /dev/null +++ b/boards/arm/efr32_radio/efr32_radio_brd4161a_defconfig @@ -0,0 +1,13 @@ +# SPDX-License-Identifier: Apache-2.0 + +CONFIG_ARM_MPU=y +CONFIG_SOC_SERIES_EFR32MG12P=y +CONFIG_BOARD_EFR32_RADIO_BRD4161A=y +CONFIG_CONSOLE=y +CONFIG_UART_CONSOLE=y +CONFIG_SERIAL=y +CONFIG_GPIO=y +CONFIG_SYS_CLOCK_HW_CYCLES_PER_SEC=38400000 +CONFIG_CMU_HFCLK_HFXO=y +CONFIG_SOC_GECKO_EMU_DCDC=y +CONFIG_SOC_GECKO_EMU_DCDC_MODE_ON=y From 6a41a7abbac12116cd1ab812b62866aa6ab9fe2f Mon Sep 17 00:00:00 2001 From: Armin Brauns Date: Wed, 20 Sep 2023 08:02:03 +0000 Subject: [PATCH 3049/3723] drivers: mcp23xxx: explain more common causes for spurious interrupts Interrupt handling in this chip is broken beyond repair, anyone unfortunate enough to have to use it will probably come across this error and wonder what's up. Signed-off-by: Armin Brauns --- drivers/gpio/gpio_mcp23xxx.c | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/drivers/gpio/gpio_mcp23xxx.c b/drivers/gpio/gpio_mcp23xxx.c index c9bf2f6aa69..c9cb32866b7 100644 --- a/drivers/gpio/gpio_mcp23xxx.c +++ b/drivers/gpio/gpio_mcp23xxx.c @@ -412,8 +412,13 @@ static void mcp23xxx_work_handler(struct k_work *work) } if (!intf) { - /* Probable cause: REG_GPIO was read from somewhere else before the interrupt - * handler had a chance to run + /* Probable causes: + * - REG_GPIO was read from somewhere else before the interrupt handler had a chance + * to run + * - Even though the datasheet says differently, reading INTCAP while a level + * interrupt is active briefly (~2ns) causes the interrupt line to go high and + * low again. This causes a second ISR to be scheduled, which then won't + * find any active interrupts if the callback has disabled the level interrupt. */ LOG_ERR("Spurious interrupt"); goto fail; From 8873c0784772413ee521abae4b9129dd7cd9e3ee Mon Sep 17 00:00:00 2001 From: Szymon Janc Date: Mon, 23 Oct 2023 10:48:27 +0200 Subject: [PATCH 3050/3723] tests: Bluetooth: Update Host Launch Studio Project and ICS This updates host Launch Studio Project and ICS to TCRL 2023-1. BLS file is deliberately left with Windows CRLF line terminators since otherwise Launch Studio silently fails to import such project. Signed-off-by: Szymon Janc --- .../ICS_Zephyr_Bluetooth_Host.pts | 4879 ++++- .../Project_Zephyr_Bluetooth_Host.bls | 14953 ++++++++++------ 2 files changed, 13229 insertions(+), 6603 deletions(-) diff --git a/tests/bluetooth/qualification/ICS_Zephyr_Bluetooth_Host.pts b/tests/bluetooth/qualification/ICS_Zephyr_Bluetooth_Host.pts index 022bc78b90b..3333e4bff11 100644 --- a/tests/bluetooth/qualification/ICS_Zephyr_Bluetooth_Host.pts +++ b/tests/bluetooth/qualification/ICS_Zephyr_Bluetooth_Host.pts @@ -1,6 +1,6 @@ - 194303 + 225924 Zephyr_Bluetooth_Host @@ -9,6 +9,10 @@ 17b
2 + + 35
+ 14 +
11b
3 @@ -17,10 +21,74 @@ 35
11
+ + 14a
+ 7 +
+ + 27b
+ 7 +
+ + 30a
+ 5 +
+ + 30a
+ 3 +
8a
14a
+ + 14a
+ 16 +
+ + 30a
+ 10 +
+ + 30a
+ 17 +
+ + 27b
+ 5 +
+ + 8a
+ 18 +
+ + 35
+ 15 +
+ + 30a
+ 8 +
+ + 27b
+ 2 +
+ + 14a
+ 18 +
+ + 14a
+ 17 +
+ + 14a
+ 5 +
+ + 14a
+ 19 +
25
12 @@ -29,30 +97,214 @@ 17b
3
+ + 30a
+ 19 +
+ + 30a
+ 18 +
+ + 37b
+ 6 +
20A
14a
+ + 11
+ 4 +
+ + 37b
+ 1 +
+ + 27b
+ 1 +
+ + 30a
+ 4 +
+ + 37b
+ 2 +
+ + 30a
+ 12 +
+ + 30a
+ 14 +
+ + 30a
+ 13 +
25
13
+ + 14a
+ 2 +
+ + 11b
+ 4 +
+ + 20A
+ 18 +
+ + 37b
+ 3 +
+ + 30a
+ 15 +
11b
2
+ + 30a
+ 6 +
+ + 14a
+ 4 +
+ + 14a
+ 6 +
+ + 14a
+ 15 +
35
13
+ + 14a
+ 11 +
+ + 20A
+ 19 +
+ + 14a
+ 14 +
+ + 37b
+ 8 +
+ + 30a
+ 16 +
+ + 30a
+ 1 +
35
12
+ + 30a
+ 11 +
+ + 14a
+ 9 +
+ + 30a
+ 9 +
+ + 14a
+ 1 +
+ + 14a
+ 14a +
+ + 30a
+ 14a +
+ + 14a
+ 10 +
+ + 27b
+ 8 +
+ + 27b
+ 3 +
+ + 25
+ 14 +
+ + 37b
+ 5 +
+ + 27b
+ 6 +
+ + 14a
+ 13 +
+ + 30a
+ 7 +
25
11
+ + 8a
+ 19 +
+ + 14a
+ 3 +
+ + 37b
+ 7 +
+ + 14a
+ 8 +
+ + 14a
+ 12 +
+ + 30a
+ 2 +
0
2 @@ -73,6 +325,14 @@ 11
3
+ + 11a
+ 1 +
+ + 11a
+ 2 +
12
1 @@ -121,6 +381,14 @@ 17
4
+ + 17a
+ 1 +
+ + 17a
+ 2 +
18
1 @@ -537,6 +805,10 @@ 35
3
+ + 35
+ 4 +
35
5 @@ -685,6 +957,10 @@ 8a
5
+ + 8a
+ 6 +
8a
7 @@ -737,6 +1013,18 @@ 17b
1
+ + 23
+ 6 +
+ + 33
+ 7 +
+ + 7
+ 3 +
L2CAP @@ -836,7 +1124,7 @@ SUM ICS 31
- 22 + 23
52
@@ -855,14 +1143,15 @@
- 4.0HCI + GATT - 1a
- 2 + 9
+ 3 +
+ + 10
+ 11
-
- - GATT 8
2 @@ -872,27 +1161,143 @@ 3a
- 8
- 8 + 9
+ 10
- 1
- 1 + 10
+ 6
- 1
- 2 + 10
+ 1
- 1a
+ 9
+ 15 +
+ + 10
+ 7 +
+ + 9
+ 2 +
+ + 3a
1
- 1a
+ 8
+ 8 +
+ + 10
+ 2 +
+ + 9
+ 13 +
+ + 10
+ 12 +
+ + 10
+ 5 +
+ + 9
+ 4 +
+ + 3a
+ 2 +
+ + 10
3
2
+ 4 +
+ + 9
+ 8 +
+ + 9
+ 1 +
+ + 9
+ 6 +
+ + 10
+ 9 +
+ + 4a
+ 2 +
+ + 10
+ 4 +
+ + 2
+ 5 +
+ + 9
+ 11 +
+ + 9
+ 14 +
+ + 9
+ 9 +
+ + 9
+ 5 +
+ + 4a
+ 1 +
+ + 9
+ 7 +
+ + 10
+ 8 +
+ + 9
+ 12 +
+ + 1
+ 1 +
+ + 1
+ 2 +
+ + 1a
+ 1 +
+ + 1a
3
@@ -1142,6 +1547,30 @@
SM + + 7a
+ 1 +
+ + 7a
+ 2 +
+ + 7b
+ 1 +
+ + 7b
+ 2 +
+ + 7b
+ 3 +
+ + 7a
+ 3 +
1
1 @@ -1210,6 +1639,13 @@ 6
2
+
+ + ATT + + 7
+ 3 +
7
1 @@ -1219,12 +1655,9 @@ 2
- 7
- 3 + 6
+ 1
-
- - ATT 2
3a @@ -1349,10 +1782,6 @@ 3
28
- - 3
- 29 -
3
3 @@ -1465,10 +1894,6 @@ 4
28
- - 4
- 29 -
4
3 @@ -1497,36 +1922,20 @@ 4
9
+
+ + DIS 5
- 2 + 1
- 5
+ 3
3
- - 5
- 4 -
- - 5
- 5 -
- - 5
- 6 -
- - 5
- 7 -
-
- - DIS 0
- 1 + 2
1
@@ -1567,6 +1976,18 @@
IAS + + 0
+ 1 +
+ + 3
+ 1 +
+ + 3
+ 2 +
1
2 @@ -1589,76 +2010,182 @@
- OTS + HRS - 8
- 3 + 3
+ 4
- 8
+ 0
1
- 8
- 7 + 3
+ 6
- 8
- 8 + 3
+ 2
- 8
- 4 + 3
+ 5
- 0
- 1 + 1
+ 2
2
1
- 4
- 1 + 2
+ 2
+
+ + BAS - 4
- 12 + 3
+ 1
- 4
- 13 + 3
+ 5
- 4
- 15 + 3
+ 3
4
- 16 + 2
- 4
+ 0
2
4
- 20 + 1
- 4
- 6 + 1
+ 2
- 4
- 7 + 2
+ 1
- 5
- 5 + 2
+ 3
- +
+ + OTS + + 8
+ 3 +
+ + 8
+ 1 +
+ + 8
+ 7 +
+ + 8
+ 8 +
+ + 8
+ 4 +
+ + 0
+ 1 +
+ + 2
+ 1 +
+ + 3
+ 2 +
+ + 3
+ 3 +
+ + 4
+ 1 +
+ + 4
+ 12 +
+ + 4
+ 13 +
+ + 4
+ 15 +
+ + 4
+ 16 +
+ + 4
+ 2 +
+ + 4
+ 20 +
+ + 4
+ 3 +
+ + 4
+ 6 +
+ + 4
+ 7 +
+ + 5
+ 1 +
+ + 5
+ 2 +
+ + 5
+ 3 +
+ + 5
+ 4 +
+ + 5
+ 5 +
+ + 5
+ 6 +
+ 6
1
@@ -1678,17 +2205,33 @@ 6
5 + + 7
+ 1 +
MESH + + 12
+ 12 +
18
12
+ + 1a
+ 2 +
4
13
+ + 2
+ 3 +
0a
3 @@ -1761,6 +2304,14 @@ 12
4
+ + 12
+ 5 +
+ + 12
+ 6 +
13
1 @@ -1789,6 +2340,26 @@ 14
5
+ + 15
+ 1 +
+ + 15
+ 2 +
+ + 15
+ 3 +
+ + 15
+ 4 +
+ + 15
+ 5 +
16
1 @@ -1805,6 +2376,14 @@ 16
4
+ + 16
+ 5 +
+ + 16
+ 6 +
3
1 @@ -1917,10 +2496,6 @@ 9
1
- - 17
- 1 -
18
1 @@ -1945,6 +2520,14 @@ 18
4
+ + 18
+ 5 +
+ + 18
+ 6 +
18
7 @@ -1961,6 +2544,26 @@ 19
1
+ + 20
+ 1 +
+ + 20
+ 2 +
+ + 20
+ 3 +
+ + 20
+ 4 +
+ + 20
+ 5 +
21
1 @@ -1969,6 +2572,14 @@ 21
2
+ + 21
+ 3 +
+ + 21
+ 4 +
AICS @@ -2067,6 +2678,10 @@ 2
4 + + 2
+ 7 +
0
1 @@ -2075,6 +2690,10 @@ 3
4
+ + 2
+ 5 +
3
3 @@ -2087,6 +2706,14 @@ 2
1
+ + 2
+ 6 +
+ + 2
+ 8 +
3
1 @@ -2138,6 +2765,10 @@ 3
4
+ + 2
+ 4 +
3
1 @@ -2449,6 +3080,10 @@ 14
6
+ + 17
+ 1 +
3
1 @@ -2543,6 +3178,14 @@ 6
5
+ + 14
+ 2 +
+ + 14
+ 13 +
15
8 @@ -2559,6 +3202,14 @@ 1
1
+ + 14
+ 10 +
+ + 14
+ 8 +
15
2 @@ -2579,6 +3230,10 @@ 8
1
+ + 14
+ 9 +
15
11 @@ -2599,21 +3254,41 @@ 12
1
+ + 14
+ 5 +
+ + 14
+ 11 +
5
1
15
- 9 -
- - 3
1
- 12
- 3 + 15
+ 9 +
+ + 14
+ 7 +
+ + 13
+ 2 +
+ + 3
+ 1 +
+ + 12
+ 3
1
@@ -2627,6 +3302,14 @@ 15
4
+ + 14
+ 3 +
+ + 13
+ 3 +
16
1 @@ -2639,14 +3322,26 @@ 12
2
+ + 13
+ 6 +
16
4
+ + 14
+ 6 +
15
3
+ + 14
+ 12 +
6
4 @@ -2655,10 +3350,18 @@ 6
1
+ + 13
+ 1 +
15
10
+ + 14
+ 1 +
10
2 @@ -2667,10 +3370,26 @@ 7
1
+ + 13
+ 5 +
+ + 14
+ 14 +
+ + 14
+ 4 +
5
2
+ + 13
+ 4 +
2
2 @@ -2917,18 +3636,10 @@ 17
19
- - 14
- 4 -
21
1
- - 13
- 1 -
16
19 @@ -2945,10 +3656,6 @@ 9
2
- - 14
- 13 -
21
3 @@ -2957,22 +3664,10 @@ 18
5
- - 14
- 18 -
17
1
- - 14
- 14 -
- - 14
- 8 -
21
2 @@ -2981,10 +3676,6 @@ 2
2
- - 15
- 15 -
18
2 @@ -2997,10 +3688,6 @@ 16
22
- - 14
- 19 -
6
2 @@ -3009,26 +3696,14 @@ 7
1
- - 14
- 21 -
20
1
- - 14
- 11 -
5
4
- - 15
- 3 -
16
12 @@ -3045,22 +3720,10 @@ 17
2
- - 15
- 12 -
17
17
- - 15
- 18 -
- - 14
- 16 -
17
11 @@ -3069,6 +3732,10 @@ 17
18
+ + 19
+ 3 +
16
6 @@ -3077,22 +3744,10 @@ 6
1
- - 15
- 14 -
- - 15
- 19 -
9
1
- - 15
- 1 -
17
12 @@ -3121,14 +3776,6 @@ 16
11
- - 14
- 9 -
- - 14
- 7 -
17
7 @@ -3137,10 +3784,6 @@ 16
8
- - 15
- 17 -
11
1 @@ -3153,18 +3796,10 @@ 16
14
- - 14
- 17 -
6
7
- - 14
- 10 -
3
1 @@ -3185,10 +3820,6 @@ 10
2
- - 15
- 6 -
16
1 @@ -3197,29 +3828,13 @@ 16
21
- - 15
- 5 -
- - 15
- 13 -
- - 15
- 10 -
- - 15
- 2 -
16
7
- 15
- 4 + 7
+ 3
17
@@ -3229,10 +3844,6 @@ 17
9
- - 15
- 9 -
17
3 @@ -3261,22 +3872,10 @@ 16
20
- - 14
- 15 -
- - 14
- 5 -
16
10
- - 14
- 2 -
6
4 @@ -3285,10 +3884,6 @@ 16
16
- - 15
- 20 -
17
20 @@ -3309,10 +3904,6 @@ 16
5
- - 15
- 7 -
13
2 @@ -3321,34 +3912,14 @@ 16
2
- - 14
- 1 -
13
3
- - 14
- 22 -
- - 15
- 16 -
- - 14
- 20 -
1
2
- - 15
- 8 -
10
1 @@ -3357,26 +3928,10 @@ 1
1
- - 14
- 6 -
- - 15
- 11 -
18
8
- - 14
- 3 -
- - 14
- 12 -
17
16 @@ -4192,6 +4747,10 @@ 13
6
+ + 13
+ 1 +
12
1 @@ -4616,1202 +5175,3956 @@
- BAP + BASS - 44
- 13 + 4
+ 6
- 10
+ 5
1
- 54
- 4 + 5
+ 2
- 23
- 6 + 4
+ 2
- 44
- 9 + 0
+ 1
- 53
- 1 + 5
+ 3
- 7
- 8 + 5
+ 5
- 38
- 4 + 5
+ 6
- 20
- 4 + 3
+ 1
- 46
- 2 + 3
+ 5
- 39
+ 5
4
- 32
- 5 + 4
+ 1
- 23
- 10 + 3
+ 4
- 10
- 5 + 2
+ 2
- 32
- 1 + 4
+ 5
- 11
- 1 + 3
+ 2
- 20
- 1 + 4
+ 3
- 51
+ 4
4
+
+ + BAP - 7
- 7 + 66
+ 2
- 46
- 6 + 44
+ 13
- 20
- 9 + 10
+ 1
- 25
+ 89
2
- 45
- 6 + 70
+ 11
- 45
- 2 + 14
+ 11
- 46
- 9 + 81
+ 1
- 6
+ 54
4
- 52
- 3 + 23
+ 6
- 22
- 2 + 17
+ 8
- 5
- 2 + 38
+ 5
- 29
- 1 + 36
+ 7
- 1
- 3 + 44
+ 9
- 30
- 3 + 89
+ 13
- 36
- 6 + 53
+ 1 +
+ + 13
+ 15
60
- 1 + 4
- 21
- 2 + 54
+ 12
- 25
- 3 + 7
+ 8
- 51
- 1 + 89
+ 5
- 23
- 7 + 38
+ 9
- 44
- 8 + 38
+ 4
- 32
- 7 + 14
+ 13
- 61
- 1 + 20
+ 4
- 8
+ 46
2
- 31
+ 69
5
- 41
- 4 + 68
+ 11
- 9
- 1 + 69
+ 11
- 9
- 3 + 55
+ 6
- 32
- 10 + 33a
+ 7
- 33
+ 9a
6
- 30
- 1 -
- - 52
+ 84
1
- 56
- 6 + 38
+ 11
- 16
- 4 + 22
+ 8
- 16
+ 68
6
- 44
- 1 + 90
+ 6
- 34
+ 39
4
- 61
- 3 + 21
+ 9
- 9
- 4 + 39
+ 12
- 33
- 4 + 32
+ 5
- 45
+ 55
11
- 27
- 3 + 90
+ 1
- 32
+ 14
+ 8 +
+ + 90
+ 4 +
+ + 88
3
- 45
- 9 + 23
+ 10
- 45
- 4 + 56
+ 14
- 52
- 5 + 54
+ 11
- 40
- 4 + 10
+ 5
- 33
+ 32
1
- 45
+ 16
8
- 55
- 4 + 15
+ 15
- 9
- 6 + 11
+ 1
- 33
- 3 + 69
+ 16
- 37
- 4 + 69
+ 9
- 22
- 1 + 14
+ 15
- 59
- 1 + 14
+ 10
- 32
- 9 + 54
+ 17
- 48
+ 1
+ 4 +
+ + 20
1
- 9
+ 41
8
- 50
+ 82
1
- 24
- 1 + 56
+ 10 +
+ + 91
+ 1 +
+ + 91
+ 3 +
+ + 69
+ 8 +
+ + 39
+ 10 +
+ + 12
+ 7 +
+ + 40
+ 5 +
+ + 37
+ 1 +
+ + 43
+ 1 +
+ + 51
+ 4 +
+ + 1
+ 5 +
+ + 65
+ 5 +
+ + 17
+ 12 +
+ + 55
+ 5 +
+ + 59
+ 6 +
+ + 7
+ 7 +
+ + 46
+ 6 +
+ + 21
+ 12 +
+ + 20
+ 9 +
+ + 40
+ 2 +
+ + 73
+ 9 +
+ + 36
+ 1 +
+ + 13
+ 8 +
+ + 21
+ 8 +
+ + 25
+ 2 +
+ + 39
+ 9 +
+ + 40
+ 9 +
+ + 7
+ 10 +
+ + 74
+ 4 +
+ + 45
+ 6 +
+ + 90
+ 2 +
+ + 12
+ 13 +
+ + 45
+ 2 +
+ + 46
+ 9 +
+ + 12
+ 16 +
+ + 15
+ 13 +
+ + 73
+ 2 +
+ + 54
+ 1 +
+ + 41
+ 3 +
+ + 39
+ 3 +
+ + 17
+ 2 +
+ + 6
+ 4 +
+ + 22
+ 5 +
+ + 87
+ 2 +
+ + 52
+ 3 +
+ + 22
+ 2 +
+ + 55
+ 10 +
+ + 16
+ 15 +
+ + 29
+ 1 +
+ + 21
+ 11 +
+ + 1
+ 3 +
+ + 30
+ 3 +
+ + 36
+ 6 +
+ + 60
+ 1 +
+ + 21
+ 2 +
+ + 39
+ 16 +
+ + 36
+ 12 +
+ + 69
+ 10 +
+ + 17
+ 6 +
+ + 39
+ 7 +
+ + 24
+ 3 +
+ + 56
+ 5 +
+ + 25
+ 3 +
+ + 36
+ 17 +
+ + 16
+ 3 +
+ + 16
+ 14 +
+ + 51
+ 1 +
+ + 41
+ 13 +
+ + 23
+ 7 +
+ + 56
+ 1 +
+ + 37
+ 7 +
+ + 77
+ 1 +
+ + 41
+ 16 +
+ + 44
+ 8 +
+ + 13
+ 16 +
+ + 36
+ 5 +
+ + 22
+ 4 +
+ + 32
+ 7 +
+ + 69
+ 13 +
+ + 21
+ 7 +
+ + 89
+ 9 +
+ + 76
+ 3 +
+ + 17
+ 9 +
+ + 61
+ 1 +
+ + 7
+ 9 +
+ + 8
+ 2 +
+ + 31
+ 5 +
+ + 58
+ 3 +
+ + 69
+ 12 +
+ + 41
+ 4 +
+ + 15
+ 8 +
+ + 72
+ 3 +
+ + 9
+ 1 +
+ + 40
+ 6 +
+ + 9
+ 3 +
+ + 32
+ 10 +
+ + 33
+ 6 +
+ + 30
+ 1 +
+ + 80
+ 1 +
+ + 74
+ 2 +
+ + 38
+ 6 +
+ + 59
+ 12 +
+ + 38
+ 13 +
+ + 40
+ 15 +
+ + 15
+ 2 +
+ + 13
+ 5 +
+ + 52
+ 1 +
+ + 11
+ 3 +
+ + 15
+ 12 +
+ + 87
+ 1 +
+ + 12
+ 9 +
+ + 88
+ 7 +
+ + 21
+ 4 +
+ + 92
+ 7 +
+ + 56
+ 6 +
+ + 16
+ 4 +
+ + 12
+ 5 +
+ + 12
+ 11 +
+ + 16
+ 6 +
+ + 44
+ 1 +
+ + 34
+ 4 +
+ + 13
+ 7 +
+ + 56
+ 16 +
+ + 70
+ 12 +
+ + 61
+ 3 +
+ + 14
+ 2 +
+ + 36
+ 11 +
+ + 36
+ 8 +
+ + 14
+ 9 +
+ + 9
+ 4 +
+ + 33a
+ 8 +
+ + 47
+ 3 +
+ + 73
+ 12 +
+ + 33
+ 4 +
+ + 55
+ 8 +
+ + 73
+ 6 +
+ + 33a
+ 4 +
+ + 45
+ 11 +
+ + 62
+ 1 +
+ + 32
+ 3 +
+ + 38
+ 8 +
+ + 68
+ 8 +
+ + 45
+ 9 +
+ + 74
+ 6 +
+ + 56
+ 9 +
+ + 13
+ 2 +
+ + 55
+ 1 +
+ + 36
+ 10 +
+ + 45
+ 4 +
+ + 52
+ 5 +
+ + 15
+ 14 +
+ + 40
+ 4 +
+ + 82
+ 2 +
+ + 68
+ 7 +
+ + 44
+ 4 +
+ + 54
+ 13 +
+ + 37
+ 9 +
+ + 56
+ 11 +
+ + 16
+ 16 +
+ + 74
+ 9 +
+ + 44
+ 10 +
+ + 33
+ 1 +
+ + 70
+ 5 +
+ + 45
+ 8 +
+ + 55
+ 15 +
+ + 36
+ 2 +
+ + 65
+ 3 +
+ + 55
+ 4 +
+ + 69
+ 15 +
+ + 9
+ 6 +
+ + 70
+ 8 +
+ + 54
+ 14 +
+ + 74
+ 8 +
+ + 22
+ 9 +
+ + 88
+ 5 +
+ + 68
+ 5 +
+ + 76
+ 4 +
+ + 39
+ 13 +
+ + 37
+ 17 +
+ + 75
+ 1 +
+ + 16
+ 5 +
+ + 56
+ 2 +
+ + 74
+ 15 +
+ + 33
+ 3 +
+ + 12
+ 12 +
+ + 36
+ 13 +
+ + 16
+ 7 +
+ + 37
+ 4 +
+ + 22
+ 1 +
+ + 37
+ 15 +
+ + 22
+ 3 +
+ + 37
+ 2 +
+ + 59
+ 1 +
+ + 89
+ 1 +
+ + 32
+ 9 +
+ + 48
+ 1 +
+ + 92
+ 3 +
+ + 27
+ 4 +
+ + 54
+ 3 +
+ + 54
+ 7 +
+ + 17
+ 5 +
+ + 40
+ 14 +
+ + 55
+ 12 +
+ + 80
+ 5 +
+ + 59
+ 10 +
+ + 39
+ 6 +
+ + 9
+ 8 +
+ + 73
+ 3 +
+ + 50
+ 1 +
+ + 70
+ 6 +
+ + 40
+ 8 +
+ + 22
+ 7 +
+ + 12
+ 17 +
+ + 86
+ 1 +
+ + 44
+ 5 +
+ + 80
+ 10 +
+ + 38
+ 7 +
+ + 17
+ 13 +
+ + 39
+ 14 +
+ + 40
+ 1 +
+ + 24
+ 1 +
+ + 41
+ 6 +
+ + 34
+ 5 +
+ + 45
+ 3 +
+ + 60
+ 2 +
+ + 37
+ 11 +
+ + 41
+ 14 +
+ + 86
+ 4 +
+ + 67
+ 3 +
+ + 9a
+ 4 +
+ + 33a
+ 5 +
+ + 53
+ 2 +
+ + 89
+ 11 +
+ + 1
+ 6 +
+ + 59
+ 8 +
+ + 5
+ 3 +
+ + 39
+ 5 +
+ + 74
+ 3 +
+ + 7
+ 3 +
+ + 88
+ 4 +
+ + 55
+ 16 +
+ + 46
+ 4 +
+ + 69
+ 4 +
+ + 12
+ 1 +
+ + 28
+ 2 +
+ + 13
+ 10 +
+ + 16
+ 9 +
+ + 21
+ 1 +
+ + 78
+ 1 +
+ + 12
+ 14 +
+ + 20
+ 5 +
+ + 86
+ 3 +
+ + 69
+ 14 +
+ + 12
+ 4 +
+ + 23
+ 4 +
+ + 56
+ 8 +
+ + 38
+ 14 +
+ + 20
+ 11 +
+ + 68
+ 17 +
+ + 37
+ 16 +
+ + 45
+ 13 +
+ + 26
+ 1 +
+ + 32
+ 6 +
+ + 15
+ 11 +
+ + 61
+ 5 +
+ + 40
+ 12 +
+ + 37
+ 10 +
+ + 39
+ 11 +
+ + 14
+ 16 +
+ + 89
+ 3 +
+ + 41
+ 9 +
+ + 37
+ 6 +
+ + 80
+ 6 +
+ + 80
+ 2 +
+ + 9a
+ 1 +
+ + 59
+ 3 +
+ + 17
+ 10 +
+ + 54
+ 16 +
+ + 74
+ 11 +
+ + 81
+ 3 +
+ + 14
+ 7 +
+ + 9a
+ 2 +
+ + 48
+ 2 +
+ + 44
+ 7 +
+ + 41
+ 1 +
+ + 33
+ 8 +
+ + 20
+ 7 +
+ + 12
+ 10 +
+ + 44
+ 14 +
+ + 89
+ 10 +
+ + 22
+ 12 +
+ + 73
+ 4 +
+ + 51
+ 2 +
+ + 87
+ 3 +
+ + 41
+ 11 +
+ + 15
+ 16 +
+ + 54
+ 9 +
+ + 31
+ 6 +
+ + 33a
+ 3 +
+ + 75
+ 3 +
+ + 72
+ 1 +
+ + 66
+ 1 +
+ + 45
+ 10 +
+ + 58
+ 2 +
+ + 23
+ 1 +
+ + 14
+ 4 +
+ + 73
+ 5 +
+ + 28
+ 4 +
+ + 17
+ 15 +
+ + 38
+ 16 +
+ + 36
+ 4 +
+ + 68
+ 14 +
+ + 34
+ 3 +
+ + 9
+ 2 +
+ + 12
+ 3 +
+ + 76
+ 1 +
+ + 37
+ 12 +
+ + 59
+ 9 +
+ + 33a
+ 6 +
+ + 34
+ 1 +
+ + 37
+ 5 +
+ + 71
+ 1 +
+ + 54
+ 15 +
+ + 16
+ 12 +
+ + 34
+ 2 +
+ + 6
+ 2 +
+ + 65
+ 4 +
+ + 51
+ 5 +
+ + 68
+ 2 +
+ + 31
+ 3 +
+ + 70
+ 9 +
+ + 21
+ 10 +
+ + 31
+ 1 +
+ + 20
+ 2 +
+ + 1
+ 2 +
+ + 7
+ 5 +
+ + 55
+ 2 +
+ + 90
+ 3 +
+ + 65
+ 2 +
+ + 46
+ 5 +
+ + 76
+ 2 +
+ + 20
+ 3 +
+ + 21
+ 6 +
+ + 88
+ 6 +
+ + 54
+ 2 +
+ + 89
+ 8 +
+ + 13
+ 6 +
+ + 16
+ 10 +
+ + 89
+ 12 +
+ + 22
+ 11 +
+ + 68
+ 13 +
+ + 45
+ 12 +
+ + 73
+ 7 +
+ + 46
+ 3 +
+ + 90
+ 5 +
+ + 92
+ 1 +
+ + 25
+ 1 +
+ + 17
+ 1 +
+ + 7
+ 4 +
+ + 70
+ 16 +
+ + 39
+ 2 +
+ + 73
+ 8 +
+ + 7
+ 1 +
+ + 52
+ 2 +
+ + 14
+ 6 +
+ + 33a
+ 1 +
+ + 12
+ 15 +
+ + 14
+ 5 +
+ + 13
+ 1 +
+ + 64
+ 2 +
+ + 16
+ 13 +
+ + 70
+ 15 +
+ + 31
+ 2 +
+ + 59
+ 7 +
+ + 85
+ 4 +
+ + 9a
+ 3 +
+ + 33a
+ 2 +
+ + 36
+ 15 +
+ + 32
+ 2 +
+ + 19
+ 1 +
+ + 36
+ 14 +
+ + 15
+ 5 +
+ + 22
+ 10 +
+ + 83
+ 1 +
+ + 56
+ 13 +
+ + 12
+ 8 +
+ + 8
+ 1 +
+ + 33
+ 2 +
+ + 48
+ 3 +
+ + 59
+ 5 +
+ + 69
+ 7 +
+ + 13
+ 13 +
+ + 74
+ 1 +
+ + 37
+ 13 +
+ + 89
+ 7 +
+ + 20
+ 8 +
+ + 69
+ 2 +
+ + 13
+ 11 +
+ + 33
+ 5 +
+ + 16
+ 1 +
+ + 70
+ 2 +
+ + 7
+ 6 +
+ + 23
+ 5 +
+ + 57
+ 1 +
+ + 40
+ 16 +
+ + 44
+ 15 +
+ + 20
+ 6 +
+ + 15
+ 10 +
+ + 47
+ 1 +
+ + 15
+ 3 +
+ + 72
+ 2 +
+ + 35
+ 2 +
+ + 13
+ 14 +
+ + 14
+ 12 +
+ + 33
+ 7 +
+ + 13
+ 12 +
+ + 65
+ 1 +
+ + 21
+ 5 +
+ + 40
+ 3 +
+ + 85
+ 2 +
+ + 90
+ 11 +
+ + 41
+ 12 +
+ + 59
+ 4 +
+ + 68
+ 1 +
+ + 56
+ 12 +
+ + 73
+ 11 +
+ + 37
+ 3 +
+ + 54
+ 6 +
+ + 92
+ 2 +
+ + 59
+ 11 +
+ + 10
+ 3 +
+ + 60
+ 3 +
+ + 45
+ 7 +
+ + 27
+ 2 +
+ + 69
+ 3 +
+ + 44
+ 11 +
+ + 45
+ 14 +
+ + 73
+ 10 +
+ + 87
+ 4 +
+ + 74
+ 10 +
+ + 44
+ 16 +
+ + 70
+ 1 +
+ + 74
+ 7 +
+ + 54
+ 8 +
+ + 40
+ 11 +
+ + 68
+ 3 +
+ + 11
+ 2 +
+ + 12
+ 2 +
+ + 21
+ 3 +
+ + 38
+ 3 +
+ + 80
+ 3 +
+ + 51
+ 3 +
+ + 70
+ 3 +
+ + 54
+ 5 +
+ + 61
+ 2 +
+ + 13
+ 17 +
+ + 40
+ 13 +
+ + 38
+ 2 +
+ + 61
+ 6 +
+ + 61
+ 4 +
+ + 16
+ 11 +
+ + 5
+ 1 +
+ + 80
+ 7 +
+ + 86
+ 2 +
+ + 12
+ 6 +
+ + 15
+ 4 +
+ + 68
+ 16 +
+ + 31
+ 7 +
+ + 41
+ 10 +
+ + 63
+ 1 +
+ + 14
+ 3 +
+ + 88
+ 1 +
+ + 56
+ 3 +
+ + 7
+ 2 +
+ + 15
+ 6 +
+ + 88
+ 2 +
+ + 15
+ 9 +
+ + 45
+ 1 +
+ + 17
+ 11 +
+ + 70
+ 7 +
+ + 17
+ 3 +
+ + 32
+ 4 +
+ + 17
+ 16 +
+ + 3
+ 1 +
+ + 13
+ 9 +
+ + 15
+ 7 +
+ + 56
+ 15 +
+ + 9a
+ 5 +
+ + 14
+ 1 +
+ + 14
+ 14 +
+ + 36
+ 9 +
+ + 37
+ 8 +
+ + 35
+ 1 +
+ + 68
+ 10 +
+ + 41
+ 5 +
+ + 68
+ 12 +
+ + 15
+ 1 +
+ + 69
+ 6 +
+ + 17
+ 7 +
+ + 69
+ 1 +
+ + 10
+ 2 +
+ + 36
+ 16 +
+ + 68
+ 9 +
+ + 40
+ 10 +
+ + 22
+ 6 +
+ + 44
+ 3 +
+ + 54
+ 10 +
+ + 56
+ 4 +
+ + 49
+ 1 +
+ + 37
+ 14 +
+ + 23
+ 2 +
+ + 44
+ 12 +
+ + 45
+ 5 +
+ + 68
+ 4 +
+ + 67
+ 1 +
+ + 38
+ 10 +
+ + 10
+ 4 +
+ + 38
+ 12 +
+ + 68
+ 15 +
+ + 70
+ 14 +
+ + 55
+ 14 +
+ + 4
+ 1 +
+ + 9a
+ 7 +
+ + 38
+ 1 +
+ + 9a
+ 8 +
+ + 1
+ 1 +
+ + 70
+ 13 +
+ + 39
+ 8 +
+ + 20
+ 10 +
+ + 70
+ 4 +
+ + 58
+ 1 +
+ + 67
+ 2 +
+ + 41
+ 15 +
+ + 55
+ 13 +
+ + 73
+ 1 +
+ + 82
+ 3 +
+ + 52
+ 4 +
+ + 32
+ 8 +
+ + 44
+ 2 +
+ + 13
+ 3 +
+ + 46
+ 1 +
+ + 55
+ 7 +
+ + 40
+ 7 +
+ + 90
+ 8 +
+ + 44
+ 6 +
+ + 42
+ 1 +
+ + 9
+ 7 +
+ + 36
+ 3 +
+ + 55
+ 3 +
+ + 30
+ 2 +
+ + 89
+ 6 +
+ + 59
+ 2 +
+ + 9
+ 5 +
+ + 39
+ 15 +
+ + 39
+ 1 +
+ + 55
+ 9 +
+ + 31
+ 4 +
+ + 17
+ 14 +
+ + 90
+ 7 +
+ + 70
+ 10 +
+ + 51
+ 6 +
+ + 38
+ 15 +
+ + 79
+ 2 +
+ + 17
+ 4 +
+ + 13
+ 4 +
+ + 18
+ 1 +
+ + 16
+ 2 +
+ + 41
+ 2 +
+ + 89
+ 4 +
+ + 41
+ 7 +
+ + 29
+ 2 +
+ + 56
+ 7 +
+
+ + CAS + + 2
+ 2 +
+ + 0
+ 1 +
+ + 3
+ 1 +
+
+ + CAP + + 16
+ 5 +
+ + 11
+ 11 +
+ + 22
+ 1 +
+ + 1
+ 1 +
+ + 8
+ 3 +
+ + 7
+ 1 +
+ + 18
+ 2 +
+ + 12
+ 1 +
+ + 2
+ 2 +
+ + 16
+ 2 +
+ + 19
+ 2 +
+ + 20
+ 3 +
+ + 6
+ 1 +
+ + 6
+ 7 +
+ + 7
+ 6 +
+ + 22
+ 8 +
+ + 19
+ 1 +
+ + 17
+ 2 +
+ + 6a
+ 2 +
+ + 20
+ 5 +
+ + 23
+ 2 +
+ + 7
+ 9 +
+ + 4
+ 1 +
+ + 11
+ 7 +
+ + 10
+ 1 +
+ + 13
+ 1 +
+ + 20
+ 2 +
+ + 13
+ 2 +
+ + 7
+ 4 +
+ + 22
+ 2 +
+ + 7
+ 8 +
+ + 11
+ 5 +
+ + 22
+ 7 +
+ + 21
+ 3 +
+ + 22
+ 4 +
+ + 9
+ 1 +
+ + 14
+ 1 +
+ + 11
+ 10 +
+ + 18
+ 1 +
+ + 8
+ 2 +
+ + 1
+ 2 +
+ + 6
+ 4 +
+ + 22
+ 12 +
+ + 22
+ 11 +
+ + 11
+ 8 +
+ + 3
+ 1 +
+ + 22
+ 9 +
+ + 20
+ 1 +
+ + 16
+ 1 +
+ + 7
+ 3 +
+ + 10
+ 2 +
+ + 22
+ 3 +
+ + 21
+ 2 +
+ + 7
+ 2 +
+ + 6
+ 6 +
+ + 16
+ 4 +
+ + 6
+ 8 +
+ + 23
+ 1 +
+ + 11
+ 2 +
+ + 8
+ 1 +
+ + 6
+ 5 +
+ + 11
+ 3 +
+ + 6
+ 3 +
+ + 11
+ 6 +
+ + 6a
+ 1 +
+ + 22
+ 5 +
+ + 20
+ 4 +
+ + 7
+ 7 +
+ + 22
+ 10 +
+ + 8
+ 4 +
+ + 20
+ 9 +
+ + 22
+ 6 +
+ + 17
+ 5 +
+ + 20
+ 6 +
+ + 7
+ 5
- 41
+ 21
+ 1 +
+ + 16
6
- 34
- 5 + 11
+ 9
- 45
- 3 + 11
+ 12
- 60
- 2 + 11
+ 1
- 7
+ 16
3
- 46
+ 19
4
- 28
- 2 + 11
+ 4
- 21
+ 17
1
- 12
- 4 + 6
+ 2
+
+ + HAS - 23
+ 5
4
- 45
- 13 + 4
+ 10
- 26
+ 4
+ 8 +
+ + 4
+ 2 +
+ + 4
+ 3 +
+ + 5
1
- 32
+ 4
+ 1 +
+ + 3
+ 7 +
+ + 3
+ 12 +
+ + 4
+ 7 +
+ + 3
+ 14 +
+ + 3
+ 11 +
+ + 5
+ 2 +
+ + 2
+ 2 +
+ + 5
6
- 61
+ 3
5
- 48
+ 3
+ 4 +
+ + 5
+ 3 +
+ + 3
2
- 44
- 7 + 4
+ 4
- 33
+ 4
+ 5 +
+ + 5
+ 5 +
+ + 3
+ 6 +
+ + 0
+ 1 +
+ + 3
+ 9 +
+ + 3
+ 10 +
+ + 3
+ 1 +
+ + 3
+ 13 +
+ + 3
8
- 20
- 7 + 4
+ 9
- 51
- 2 + 3
+ 3
- 31
+ 3
+ 1a +
+ + 4
6
+
+ + HAP - 45
- 10 + 12
+ 5
- 58
- 2 + 10
+ 1
- 23
+ 92
+ 1 +
+ + 50
1
+ + 24
+ 5 +
14
- 4 + 3
- 28
- 4 + 51
+ 1
- 36
+ 13
4
- 34
- 3 + 43
+ 2
- 9
+ 1
2
- 34
+ 12
+ 7 +
+ + 90
1
- 34
+ 24
2
- 6
+ 50
2
- 51
- 5 + 12
+ 3
- 31
+ 24
3
- 31
+ 13
+ 6 +
+ + 26
1
- 20
- 2 + 43
+ 3
- 1
+ 40
+ 1 +
+ + 13
2
- 7
- 5 + 13
+ 1 +
+ + 18
+ 1 +
+ + 12
+ 6 +
+ + 16
+ 2
46
- 5 + 2
- 20
+ 16
+ 1 +
+ + 1
+ 1 +
+ + 14
+ 2 +
+ + 43
+ 4 +
+ + 13
3
- 45
- 12 + 12
+ 2 +
+ + 19
+ 1
- 46
- 3 + 24
+ 1
- 25
+ 12
1
- 7
+ 24
4
- 7
+ 14
1
- 52
- 2 + 1
+ 4
- 31
+ 19
2
- 32
- 2 + 17
+ 1
- 8
+ 25
1
- 33
+ 13
+ 5 +
+ + 43
+ 1 +
+ + 2
2
- 48
- 3 + 46
+ 1
- 33
- 5 + 12
+ 4
+
+ + TMAP - 7
- 6 + 131
+ 2
- 23
+ 95
5
- 20
- 6 + 114
+ 4
- 47
- 1 + 52
+ 2
- 33
+ 1
7
- 10
- 3 -
- - 60
+ 57
3
- 45
- 7 + 56
+ 12
- 27
- 2 + 56
+ 14
- 45
- 14 + 79
+ 1
- 11
+ 79
2
- 51
- 3 + 153
+ 6
- 61
+ 57
2
- 61
- 6 + 95
+ 7
- 61
- 4 + 76
+ 3
- 5
- 1 + 116
+ 12
- 12
- 6 + 95
+ 3
- 15
- 4 + 115
+ 3
- 31
- 7 + 96
+ 15
- 7
- 2 + 56
+ 1
- 32
+ 116
4
- 3
- 1 + 116
+ 5
- 35
- 1 + 56
+ 5
- 10
- 2 + 78
+ 1
- 44
- 3 + 1
+ 8
- 56
- 4 + 116
+ 11
- 49
+ 70
1
- 23
- 2 + 96
+ 16
- 44
- 12 + 118
+ 2
- 45
+ 76
5
- 10
- 4 + 1
+ 2
- 4
+ 93
1
- 1
- 1 + 55
+ 3
- 20
- 10 + 95
+ 8
- 58
+ 113
1
- 52
- 4 + 96
+ 12
- 32
- 8 + 99
+ 2
- 44
- 2 + 96
+ 7
- 46
+ 94
1
- 44
- 6 + 151
+ 3
- 9
- 7 + 98
+ 3
- 30
- 2 + 116
+ 9
- 59
+ 2
2
- 9
- 5 + 150
+ 1
- 31
+ 153
4
- 51
- 6 -
- - 13
- 4 + 116
+ 1
- 29
+ 96
2
-
- - CAS - 2
- 2 + 116
+ 13
- 0
- 1 + 75
+ 3
- 3
- 1 + 115
+ 5
-
- - CAP - 16
+ 55
5
- 22
- 1 + 116
+ 6
- 1
- 1 + 153
+ 5
- 8
- 3 + 57
+ 1
- 7
+ 112
1
- 18
- 2 + 1
+ 4
- 12
+ 97
1
- 2
- 2 -
- - 16
- 2 + 116
+ 7
- 19
- 2 + 96
+ 13
- 20
- 3 + 56
+ 9
- 6
+ 115
1
- 6
- 7 + 151
+ 6
- 7
+ 56
6
- 19
- 1 + 55
+ 4
- 20
- 5 + 78
+ 3
- 23
- 2 + 76
+ 6
- 7
- 9 + 100
+ 2
- 4
+ 110
1
- 10
- 1 + 98
+ 2
- 20
- 2 + 56
+ 4
- 13
- 2 + 76
+ 4
- 7
+ 95
4
- 22
+ 118
+ 3 +
+ + 116
2
- 9
- 1 + 116
+ 15
- 14
+ 75
1
- 18
+ 114
1
- 8
- 2 + 55
+ 8
- 1
- 2 + 56
+ 3
- 6
+ 75
4
- 3
- 1 + 74
+ 3
- 20
+ 94
+ 4 +
+ + 151
1
- 16
+ 119
1
- 7
- 3 + 1
+ 6
- 10
- 2 + 116
+ 16
- 7
+ 95
2
- 6
- 6 + 56
+ 7
- 6
- 8 + 77
+ 1
- 23
- 1 + 54
+ 3
- 8
- 1 + 97
+ 2
- 6
- 5 + 54
+ 1
- 20
+ 115
4
- 7
- 7 + 53
+ 1
- 20
- 6 + 117
+ 1
- 7
- 5 + 76
+ 2
- 21
- 1 + 78
+ 2
- 16
+ 96
6
- 11
+ 131
1
- 16
- 3 + 156
+ 1
- 19
- 4 + 120
+ 1
- 17
+ 152
1
-
- - HAS - 5
- 4 + 1
+ 5
- 4
- 10 + 74
+ 5
- 4
- 8 + 115
+ 2
- 4
- 2 + 96
+ 1
- 4
+ 96
3
- 5
- 1 + 75
+ 2
- 4
- 1 + 115
+ 6
- 3
- 7 + 154
+ 1
- 3
- 12 + 114
+ 3
- 4
- 7 + 118
+ 1
- 3
- 14 + 96
+ 4
- 3
- 11 + 56
+ 10
- 5
- 2 + 55
+ 6
- 2
- 2 + 52
+ 1
- 5
- 6 + 75
+ 5
- 3
- 5 + 56
+ 11
- 3
- 4 + 96
+ 10
- 5
+ 94
3
- 3
- 2 + 56
+ 16
- 4
- 4 + 72
+ 2
- 4
- 5 + 117
+ 2
- 5
- 5 + 72
+ 1
- 3
- 6 + 116
+ 3
- 0
- 1 + 116
+ 14
- 3
- 9 + 116
+ 8
- 3
+ 116
10
- 3
- 1 + 96
+ 14
- 3
+ 56
13
- 3
- 8 + 56
+ 15
- 4
- 9 + 75
+ 6
- 3
- 3 + 121
+ 2
- 3
- 1a + 77
+ 2
- 4
- 6 + 3
+ 1
-
- - HAP - 12
- 5 + 96
+ 8
- 10
+ 98
1
- 24
- 5 + 115
+ 8
- 14
- 3 + 96
+ 9
- 13
- 4 + 95
+ 1
- 12
+ 115
7
- 24
+ 92
2
- 12
- 3 -
- - 24
- 3 -
- - 13
- 6 + 96
+ 11
- 26
+ 100
1
- 13
- 2 + 121
+ 1
- 13
+ 76
1
- 18
+ 99
1
- 12
- 6 + 55
+ 2
- 16
+ 153
2
- 16
- 1 + 74
+ 4
- 1
+ 119
+ 2 +
+ + 90
1
- 14
+ 112
2
- 13
- 3 + 56
+ 8
- 12
+ 56
2
- 19
- 1 -
- - 24
+ 50
1
- 12
+ 74
1
- 24
- 4 + 96
+ 5
- 14
- 1 + 55
+ 7
- 19
- 2 + 151
+ 5
- 17
+ 92
1
- 25
- 1 + 151
+ 4
- 13
- 5 + 151
+ 2
- 2
- 2 + 55
+ 1
- 12
- 4 + 95
+ 6
diff --git a/tests/bluetooth/qualification/Project_Zephyr_Bluetooth_Host.bls b/tests/bluetooth/qualification/Project_Zephyr_Bluetooth_Host.bls index c9796a24a20..b08c4172cf2 100644 --- a/tests/bluetooth/qualification/Project_Zephyr_Bluetooth_Host.bls +++ b/tests/bluetooth/qualification/Project_Zephyr_Bluetooth_Host.bls @@ -1,5821 +1,9134 @@ - - - 194303 - Zephyr_Bluetooth_Host - 81 - - - - - GAP - - 17b
- 2 -
- - 11b
- 3 -
- - 35
- 11 -
- - 8a
- 14a -
- - 25
- 12 -
- - 17b
- 3 -
- - 20A
- 14a -
- - 25
- 13 -
- - 11b
- 2 -
- - 35
- 13 -
- - 35
- 12 -
- - 25
- 11 -
- - 0
- 2 -
- - 10
- 1 -
- - 11
- 1 -
- - 11
- 2 -
- - 11
- 3 -
- - 12
- 1 -
- - 12
- 2 -
- - 13
- 1 -
- - 13
- 2 -
- - 14
- 1 -
- - 14
- 2 -
- - 15
- 1 -
- - 16
- 1 -
- - 17
- 1 -
- - 17
- 2 -
- - 17
- 3 -
- - 17
- 4 -
- - 18
- 1 -
- - 18
- 2 -
- - 19
- 1 -
- - 19
- 2 -
- - 19
- 3 -
- - 20
- 1 -
- - 20
- 2 -
- - 20
- 3 -
- - 20
- 4 -
- - 20
- 5 -
- - 20
- 6 -
- - 20
- 7 -
- - 20A
- 1 -
- - 20A
- 10 -
- - 20A
- 11 -
- - 20A
- 12 -
- - 20A
- 13 -
- - 20A
- 14 -
- - 20A
- 15 -
- - 20A
- 16 -
- - 20A
- 17 -
- - 20A
- 2 -
- - 20A
- 3 -
- - 20A
- 4 -
- - 20A
- 5 -
- - 20A
- 7 -
- - 20A
- 8 -
- - 20A
- 9 -
- - 21
- 1 -
- - 21
- 10 -
- - 21
- 11 -
- - 21
- 2 -
- - 21
- 3 -
- - 21
- 4 -
- - 21
- 5 -
- - 21
- 6 -
- - 21
- 7 -
- - 21
- 8 -
- - 21
- 9 -
- - 22
- 1 -
- - 22
- 2 -
- - 22
- 3 -
- - 22
- 4 -
- - 23
- 1 -
- - 23
- 2 -
- - 23
- 3 -
- - 23
- 4 -
- - 23
- 5 -
- - 24
- 1 -
- - 24
- 2 -
- - 24
- 3 -
- - 24
- 4 -
- - 25
- 1 -
- - 25
- 10 -
- - 25
- 2 -
- - 25
- 3 -
- - 25
- 4 -
- - 25
- 5 -
- - 25
- 6 -
- - 25
- 7 -
- - 25
- 8 -
- - 25
- 9 -
- - 26
- 1 -
- - 26
- 2 -
- - 26
- 3 -
- - 26
- 4 -
- - 27
- 1 -
- - 27
- 2 -
- - 27
- 5 -
- - 27
- 6 -
- - 27
- 9 -
- - 28
- 1 -
- - 28
- 2 -
- - 29
- 1 -
- - 29
- 2 -
- - 29
- 3 -
- - 29
- 4 -
- - 30
- 1 -
- - 30
- 2 -
- - 31
- 1 -
- - 31
- 10 -
- - 31
- 11 -
- - 31
- 2 -
- - 31
- 3 -
- - 31
- 4 -
- - 31
- 5 -
- - 31
- 6 -
- - 31
- 8 -
- - 31
- 9 -
- - 32
- 1 -
- - 32
- 2 -
- - 32
- 3 -
- - 33
- 1 -
- - 33
- 2 -
- - 33
- 4 -
- - 33
- 5 -
- - 33
- 6 -
- - 34
- 1 -
- - 34
- 2 -
- - 34
- 3 -
- - 35
- 1 -
- - 35
- 10 -
- - 35
- 2 -
- - 35
- 3 -
- - 35
- 5 -
- - 35
- 6 -
- - 35
- 7 -
- - 35
- 8 -
- - 35
- 9 -
- - 36
- 1 -
- - 36
- 2 -
- - 36
- 3 -
- - 36
- 5 -
- - 37
- 1 -
- - 37
- 2 -
- - 37
- 3 -
- - 5
- 1 -
- - 5
- 2 -
- - 5
- 3 -
- - 5
- 4 -
- - 6
- 1 -
- - 6
- 2 -
- - 7
- 1 -
- - 7
- 2 -
- - 8
- 1 -
- - 8
- 2 -
- - 8
- 3 -
- - 8
- 4 -
- - 8a
- 1 -
- - 8a
- 10 -
- - 8a
- 11 -
- - 8a
- 12 -
- - 8a
- 13 -
- - 8a
- 14 -
- - 8a
- 15 -
- - 8a
- 16 -
- - 8a
- 17 -
- - 8a
- 2 -
- - 8a
- 3 -
- - 8a
- 4 -
- - 8a
- 5 -
- - 8a
- 7 -
- - 8a
- 8 -
- - 8a
- 9 -
- - 9
- 1 -
- - 10
- 2 -
- - 10
- 3 -
- - 10
- 4 -
- - 10
- 5 -
- - 11b
- 1 -
- - 16
- 2 -
- - 16
- 3 -
- - 16
- 4 -
- - 17b
- 1 -
-
- - L2CAP - - 2
- 48b -
- - 4
- 3 -
- - 4
- 2 -
- - 4
- 1 -
- - 2
- 40 -
- - 2
- 41 -
- - 2
- 42 -
- - 2
- 43 -
- - 2
- 45a -
- - 2
- 46 -
- - 2
- 47 -
- - 3
- 1 -
- - 3
- 12 -
- - 3
- 16 -
- - 0
- 2 -
- - 1
- 3 -
- - 1
- 4 -
- - 1
- 5 -
- - 1
- 6 -
- - 2
- 48 -
-
- - IOP - - 1
- 1 -
- - 2
- 2 -
-
- - SUM ICS - - 31
- 22 -
- - 52
- 1 -
-
- - PROD - - 1
- 4 -
- - 3
- 3 -
-
- - 4.0HCI - - 1a
- 2 -
-
- - GATT - - 8
- 2 -
- - 2
- 3a -
- - 8
- 8 -
- - 1
- 1 -
- - 1
- 2 -
- - 1a
- 1 -
- - 1a
- 3 -
- - 2
- 3 -
- - 3
- 29 -
- - 3
- 30 -
- - 4
- 30 -
- - 4
- 31 -
- - 2
- 2 -
- - 3
- 1 -
- - 3
- 10 -
- - 3
- 11 -
- - 3
- 12 -
- - 3
- 13 -
- - 3
- 14 -
- - 3
- 15 -
- - 3
- 17 -
- - 3
- 18 -
- - 3
- 19 -
- - 3
- 2 -
- - 3
- 20 -
- - 3
- 21 -
- - 3
- 22 -
- - 3
- 23 -
- - 3
- 25 -
- - 3
- 26 -
- - 3
- 3 -
- - 3
- 4 -
- - 3
- 5 -
- - 3
- 6 -
- - 3
- 7 -
- - 3
- 8 -
- - 3
- 9 -
- - 4
- 1 -
- - 4
- 10 -
- - 4
- 11 -
- - 4
- 12 -
- - 4
- 13 -
- - 4
- 14 -
- - 4
- 15 -
- - 4
- 16 -
- - 4
- 17 -
- - 4
- 18 -
- - 4
- 19 -
- - 4
- 2 -
- - 4
- 20 -
- - 4
- 21 -
- - 4
- 22 -
- - 4
- 23 -
- - 4
- 25 -
- - 4
- 26 -
- - 4
- 27 -
- - 4
- 3 -
- - 4
- 4 -
- - 4
- 5 -
- - 4
- 6 -
- - 4
- 7 -
- - 4
- 8 -
- - 4
- 9 -
- - 7
- 2 -
- - 7
- 3 -
- - 7
- 4 -
- - 7
- 5 -
- - 7
- 6 -
- - 7
- 7 -
-
- - SM - - 1
- 1 -
- - 1
- 2 -
- - 2
- 1 -
- - 2
- 2 -
- - 2
- 3 -
- - 2
- 4 -
- - 2
- 5 -
- - 3
- 1 -
- - 4
- 1 -
- - 4
- 2 -
- - 4
- 3 -
- - 5
- 1 -
- - 5
- 2 -
- - 5
- 3 -
- - 5
- 4 -
- - 6
- 1 -
- - 6
- 2 -
- - 7
- 1 -
- - 7
- 2 -
- - 7
- 3 -
-
- - ATT - - 2
- 3a -
- - 1
- 1 -
- - 1
- 2 -
- - 3
- 30 -
- - 3
- 31 -
- - 3
- 32 -
- - 4
- 31 -
- - 4
- 32 -
- - 4
- 33 -
- - 2
- 2 -
- - 3
- 1 -
- - 3
- 10 -
- - 3
- 11 -
- - 3
- 12 -
- - 3
- 13 -
- - 3
- 14 -
- - 3
- 15 -
- - 3
- 16 -
- - 3
- 17 -
- - 3
- 18 -
- - 3
- 19 -
- - 3
- 2 -
- - 3
- 20 -
- - 3
- 21 -
- - 3
- 22 -
- - 3
- 23 -
- - 3
- 24 -
- - 3
- 25 -
- - 3
- 26 -
- - 3
- 27 -
- - 3
- 28 -
- - 3
- 29 -
- - 3
- 3 -
- - 3
- 4 -
- - 3
- 5 -
- - 3
- 6 -
- - 3
- 7 -
- - 3
- 8 -
- - 3
- 9 -
- - 4
- 1 -
- - 4
- 10 -
- - 4
- 11 -
- - 4
- 12 -
- - 4
- 13 -
- - 4
- 14 -
- - 4
- 15 -
- - 4
- 16 -
- - 4
- 17 -
- - 4
- 18 -
- - 4
- 19 -
- - 4
- 2 -
- - 4
- 20 -
- - 4
- 21 -
- - 4
- 22 -
- - 4
- 23 -
- - 4
- 24 -
- - 4
- 25 -
- - 4
- 26 -
- - 4
- 27 -
- - 4
- 28 -
- - 4
- 29 -
- - 4
- 3 -
- - 4
- 4 -
- - 4
- 5 -
- - 4
- 6 -
- - 4
- 7 -
- - 4
- 8 -
- - 4
- 9 -
- - 5
- 2 -
- - 5
- 3 -
- - 5
- 4 -
- - 5
- 5 -
- - 5
- 6 -
- - 5
- 7 -
-
- - DIS - - 0
- 1 -
- - 1
- 2 -
- - 2
- 1 -
- - 2
- 11 -
- - 2
- 2 -
- - 2
- 3 -
- - 2
- 4 -
- - 2
- 5 -
- - 2
- 6 -
- - 2
- 7 -
-
- - IAS - - 1
- 2 -
- - 2
- 1 -
- - 2
- 2 -
- - 2
- 3 -
- - 2
- 4 -
-
- - OTS - - 8
- 3 -
- - 8
- 1 -
- - 8
- 7 -
- - 8
- 8 -
- - 8
- 4 -
- - 0
- 1 -
- - 2
- 1 -
- - 4
- 1 -
- - 4
- 12 -
- - 4
- 13 -
- - 4
- 15 -
- - 4
- 16 -
- - 4
- 2 -
- - 4
- 20 -
- - 4
- 6 -
- - 4
- 7 -
- - 5
- 5 -
- - 6
- 1 -
- - 6
- 2 -
- - 6
- 3 -
- - 6
- 4 -
- - 6
- 5 -
-
- - MESH - - 18
- 12 -
- - 4
- 13 -
- - 0a
- 3 -
- - 0
- 1 -
- - 0a
- 1 -
- - 0a
- 2 -
- - 2
- 1 -
- - 2
- 2 -
- - 10
- 1 -
- - 10
- 2 -
- - 10
- 3 -
- - 10
- 4 -
- - 11
- 1 -
- - 11
- 2 -
- - 11
- 3 -
- - 11
- 4 -
- - 12
- 1 -
- - 12
- 2 -
- - 12
- 3 -
- - 12
- 4 -
- - 13
- 1 -
- - 13
- 2 -
- - 14
- 1 -
- - 14
- 2 -
- - 14
- 3 -
- - 14
- 4 -
- - 14
- 5 -
- - 16
- 1 -
- - 16
- 2 -
- - 16
- 3 -
- - 16
- 4 -
- - 3
- 1 -
- - 3
- 2 -
- - 4
- 1 -
- - 4
- 10 -
- - 4
- 11 -
- - 4
- 12 -
- - 4
- 2 -
- - 4
- 3 -
- - 4
- 4 -
- - 4
- 5 -
- - 4
- 6 -
- - 4
- 7 -
- - 4
- 8 -
- - 4
- 9 -
- - 5
- 1 -
- - 5
- 2 -
- - 5
- 3 -
- - 5
- 4 -
- - 6
- 1 -
- - 6
- 2 -
- - 6
- 3 -
- - 7
- 1 -
- - 7
- 2 -
- - 7
- 3 -
- - 7
- 4 -
- - 7
- 5 -
- - 8
- 1 -
- - 9
- 1 -
- - 17
- 1 -
- - 18
- 1 -
- - 18
- 10 -
- - 18
- 11 -
- - 18
- 2 -
- - 18
- 3 -
- - 18
- 4 -
- - 18
- 7 -
- - 18
- 8 -
- - 18
- 9 -
- - 19
- 1 -
- - 21
- 1 -
- - 21
- 2 -
-
- - AICS - - 4
- 1 -
- - 3
- 5 -
- - 2
- 2 -
- - 3
- 3 -
- - 4
- 4 -
- - 4
- 2 -
- - 3
- 4 -
- - 3
- 1 -
- - 3
- 2 -
- - 4
- 3 -
- - 2
- 6 -
- - 2
- 3 -
- - 2
- 4 -
- - 2
- 1 -
- - 1
- 2 -
- - 2
- 5 -
- - 2
- 7 -
- - 2
- 8 -
- - 0
- 1 -
-
- - VOCS - - 2
- 2 -
- - 3
- 2 -
- - 1
- 2 -
- - 2
- 4 -
- - 0
- 1 -
- - 3
- 4 -
- - 3
- 3 -
- - 2
- 3 -
- - 2
- 1 -
- - 3
- 1 -
-
- - VCS - - 3
- 6 -
- - 2
- 2 -
- - 3
- 7 -
- - 4
- 2 -
- - 3
- 3 -
- - 4
- 4 -
- - 0
- 1 -
- - 2
- 1 -
- - 3
- 5 -
- - 3
- 2 -
- - 3
- 4 -
- - 3
- 1 -
- - 1
- 2 -
- - 4
- 3 -
- - 2
- 3 -
- - 4
- 1 -
-
- - VCP - - 15
- 1 -
- - 14
- 2 -
- - 15
- 2 -
- - 13
- 2 -
- - 19
- 1 -
- - 12
- 8 -
- - 16
- 3 -
- - 17
- 5 -
- - 10
- 1 -
- - 17
- 11 -
- - 16
- 9 -
- - 5
- 1 -
- - 16
- 10 -
- - 13
- 1 -
- - 16
- 12 -
- - 11
- 1 -
- - 15
- 3 -
- - 6
- 1 -
- - 11
- 3 -
- - 8
- 1 -
- - 12
- 3 -
- - 5
- 2 -
- - 11
- 2 -
- - 18
- 1 -
- - 7
- 1 -
- - 17
- 7 -
- - 17
- 10 -
- - 6
- 3 -
- - 10
- 3 -
- - 16
- 11 -
- - 18
- 7 -
- - 1
- 2 -
- - 12
- 9 -
- - 16
- 13 -
- - 16
- 7 -
- - 12
- 11 -
- - 18
- 3 -
- - 16
- 2 -
- - 14
- 4 -
- - 5
- 4 -
- - 14
- 3 -
- - 5
- 3 -
- - 12
- 10 -
- - 17
- 4 -
- - 14
- 8 -
- - 18
- 12 -
- - 16
- 14 -
- - 14
- 1 -
- - 18
- 2 -
- - 13
- 4 -
- - 17
- 9 -
- - 16
- 1 -
- - 16
- 5 -
- - 17
- 3 -
- - 15
- 4 -
- - 2
- 2 -
- - 12
- 12 -
- - 18
- 4 -
- - 12
- 7 -
- - 12
- 1 -
- - 16
- 8 -
- - 6
- 2 -
- - 14
- 7 -
- - 6
- 8 -
- - 12
- 5 -
- - 12
- 6 -
- - 15
- 6 -
- - 17
- 8 -
- - 10
- 2 -
- - 15
- 5 -
- - 12
- 4 -
- - 14
- 6 -
- - 3
- 1 -
- - 16
- 4 -
- - 14
- 5 -
- - 13
- 3 -
- - 18
- 6 -
- - 12
- 2 -
- - 17
- 6 -
- - 17
- 2 -
- - 1
- 1 -
- - 16
- 6 -
- - 14
- 9 -
-
- - MICS - - 2
- 1 -
- - 3
- 2 -
- - 3
- 3 -
- - 3
- 1 -
- - 0
- 1 -
- - 1
- 2 -
- - 3
- 4 -
-
- - MICP - - 15
- 6 -
- - 16
- 3 -
- - 15
- 5 -
- - 6
- 5 -
- - 15
- 8 -
- - 16
- 5 -
- - 17
- 1 -
- - 1
- 1 -
- - 15
- 2 -
- - 15
- 7 -
- - 6
- 6 -
- - 6
- 8 -
- - 8
- 1 -
- - 15
- 11 -
- - 6
- 2 -
- - 10
- 1 -
- - 11
- 1 -
- - 12
- 1 -
- - 5
- 1 -
- - 15
- 9 -
- - 3
- 1 -
- - 12
- 3 -
- - 1
- 2 -
- - 16
- 7 -
- - 15
- 4 -
- - 16
- 1 -
- - 16
- 6 -
- - 12
- 2 -
- - 16
- 4 -
- - 15
- 3 -
- - 6
- 4 -
- - 6
- 1 -
- - 15
- 10 -
- - 10
- 2 -
- - 7
- 1 -
- - 5
- 2 -
- - 2
- 2 -
-
- - GMCS - - 2
- 15 -
- - 3
- 21 -
- - 2
- 19 -
- - 3
- 4 -
- - 2
- 20 -
- - 3
- 6 -
- - 2
- 6 -
- - 4
- 2 -
- - 2
- 4 -
- - 2
- 1 -
- - 2
- 3 -
- - 5
- 2 -
- - 3
- 12 -
- - 4
- 3 -
- - 3
- 20 -
- - 5
- 4 -
- - 0
- 1 -
- - 3
- 17 -
- - 2
- 24 -
- - 3
- 3 -
- - 3
- 10 -
- - 3
- 8 -
- - 3
- 9 -
- - 2
- 17 -
- - 4
- 1 -
- - 3
- 1 -
- - 2
- 26 -
- - 3
- 14 -
- - 3
- 18 -
- - 2
- 11 -
- - 2
- 14 -
- - 1
- 2 -
- - 2
- 22 -
- - 3
- 15 -
- - 3
- 2 -
- - 2
- 23 -
- - 5
- 1 -
- - 3
- 11 -
- - 2
- 13 -
- - 2
- 18 -
- - 5
- 3 -
- - 3
- 16 -
- - 2
- 16 -
- - 2
- 9 -
- - 3
- 5 -
- - 2
- 7 -
- - 3
- 7 -
- - 2
- 2 -
- - 2
- 10 -
- - 3
- 13 -
- - 2
- 25 -
- - 4
- 4 -
- - 2
- 5 -
- - 2
- 21 -
- - 3
- 19 -
- - 2
- 12 -
- - 2
- 8 -
-
- - MCP - - 17
- 13 -
- - 17
- 19 -
- - 14
- 4 -
- - 21
- 1 -
- - 13
- 1 -
- - 16
- 19 -
- - 6
- 3 -
- - 16
- 4 -
- - 9
- 2 -
- - 14
- 13 -
- - 21
- 3 -
- - 18
- 5 -
- - 14
- 18 -
- - 17
- 1 -
- - 14
- 14 -
- - 14
- 8 -
- - 21
- 2 -
- - 2
- 2 -
- - 15
- 15 -
- - 18
- 2 -
- - 6
- 6 -
- - 16
- 22 -
- - 14
- 19 -
- - 6
- 2 -
- - 7
- 1 -
- - 14
- 21 -
- - 20
- 1 -
- - 14
- 11 -
- - 5
- 4 -
- - 15
- 3 -
- - 16
- 12 -
- - 8
- 1 -
- - 18
- 7 -
- - 17
- 2 -
- - 15
- 12 -
- - 17
- 17 -
- - 15
- 18 -
- - 14
- 16 -
- - 17
- 11 -
- - 17
- 18 -
- - 16
- 6 -
- - 6
- 1 -
- - 15
- 14 -
- - 15
- 19 -
- - 9
- 1 -
- - 15
- 1 -
- - 17
- 12 -
- - 17
- 6 -
- - 16
- 17 -
- - 6
- 5 -
- - 18
- 4 -
- - 19
- 1 -
- - 16
- 11 -
- - 14
- 9 -
- - 14
- 7 -
- - 17
- 7 -
- - 16
- 8 -
- - 15
- 17 -
- - 11
- 1 -
- - 17
- 5 -
- - 16
- 14 -
- - 14
- 17 -
- - 6
- 7 -
- - 14
- 10 -
- - 3
- 1 -
- - 18
- 6 -
- - 16
- 3 -
- - 18
- 3 -
- - 10
- 2 -
- - 15
- 6 -
- - 16
- 1 -
- - 16
- 21 -
- - 15
- 5 -
- - 15
- 13 -
- - 15
- 10 -
- - 15
- 2 -
- - 16
- 7 -
- - 15
- 4 -
- - 17
- 4 -
- - 17
- 9 -
- - 15
- 9 -
- - 17
- 3 -
- - 9
- 3 -
- - 16
- 9 -
- - 16
- 13 -
- - 17
- 14 -
- - 17
- 10 -
- - 16
- 20 -
- - 14
- 15 -
- - 14
- 5 -
- - 16
- 10 -
- - 14
- 2 -
- - 6
- 4 -
- - 16
- 16 -
- - 15
- 20 -
- - 17
- 20 -
- - 5
- 2 -
- - 5
- 3 -
- - 17
- 15 -
- - 16
- 5 -
- - 15
- 7 -
- - 13
- 2 -
- - 16
- 2 -
- - 14
- 1 -
- - 13
- 3 -
- - 14
- 22 -
- - 15
- 16 -
- - 14
- 20 -
- - 1
- 2 -
- - 15
- 8 -
- - 10
- 1 -
- - 1
- 1 -
- - 14
- 6 -
- - 15
- 11 -
- - 18
- 8 -
- - 14
- 3 -
- - 14
- 12 -
- - 17
- 16 -
- - 17
- 8 -
- - 16
- 18 -
- - 16
- 15 -
-
- - TBS - - 2
- 13 -
- - 3
- 1 -
- - 2
- 12 -
- - 4
- 5 -
- - 2
- 15 -
- - 4
- 3 -
- - 2
- 7 -
- - 2
- 22 -
- - 2
- 23 -
- - 2
- 21 -
- - 2
- 2 -
- - 2
- 16 -
- - 3
- 4 -
- - 2
- 18 -
- - 4
- 2 -
- - 3
- 2 -
- - 2
- 5 -
- - 2
- 14 -
- - 3
- 6 -
- - 2
- 19 -
- - 0
- 1 -
- - 2
- 3 -
- - 2
- 25 -
- - 4
- 1 -
- - 2
- 4 -
- - 2
- 9 -
- - 2
- 17 -
- - 4
- 4 -
- - 1
- 2 -
- - 2
- 11 -
- - 3
- 3 -
- - 2
- 20 -
- - 2
- 24 -
- - 2
- 10 -
- - 2
- 6 -
- - 3
- 5 -
- - 2
- 8 -
- - 2
- 1 -
-
- - GTBS - - 3
- 2 -
- - 4
- 1 -
- - 2
- 22 -
- - 3
- 3 -
- - 2
- 20 -
- - 4
- 5 -
- - 2
- 4 -
- - 2
- 18 -
- - 2
- 17 -
- - 4
- 3 -
- - 2
- 5 -
- - 3
- 1 -
- - 4
- 2 -
- - 2
- 24 -
- - 2
- 2 -
- - 1
- 2 -
- - 3
- 5 -
- - 2
- 21 -
- - 2
- 23 -
- - 2
- 25 -
- - 4
- 4 -
- - 3
- 4 -
- - 2
- 7 -
- - 2
- 1 -
- - 2
- 9 -
- - 2
- 16 -
- - 2
- 8 -
- - 2
- 12 -
- - 2
- 14 -
- - 0
- 1 -
- - 2
- 15 -
- - 3
- 6 -
- - 2
- 10 -
- - 2
- 11 -
- - 2
- 6 -
- - 2
- 19 -
- - 2
- 3 -
- - 2
- 13 -
-
- - CCP - - 12
- 7 -
- - 14
- 7 -
- - 14
- 10 -
- - 13
- 14 -
- - 12
- 13 -
- - 11
- 9 -
- - 14
- 20 -
- - 12
- 5 -
- - 13
- 15 -
- - 12
- 6 -
- - 13
- 5 -
- - 14
- 8 -
- - 6
- 2 -
- - 12
- 21 -
- - 12
- 17 -
- - 6
- 4 -
- - 12
- 11 -
- - 11
- 2 -
- - 14
- 3 -
- - 15
- 3 -
- - 10
- 2 -
- - 13
- 10 -
- - 14
- 2 -
- - 14
- 18 -
- - 12
- 9 -
- - 11
- 4 -
- - 13
- 16 -
- - 6
- 6 -
- - 12
- 3 -
- - 5
- 2 -
- - 12
- 2 -
- - 12
- 18 -
- - 15
- 6 -
- - 14
- 13 -
- - 12
- 19 -
- - 12
- 14 -
- - 14
- 14 -
- - 11
- 8 -
- - 15
- 5 -
- - 5
- 3 -
- - 15
- 2 -
- - 14
- 4 -
- - 14
- 22 -
- - 11
- 5 -
- - 12
- 8 -
- - 14
- 9 -
- - 14
- 6 -
- - 6
- 7 -
- - 12
- 22 -
- - 11
- 15 -
- - 14
- 16 -
- - 13
- 12 -
- - 3
- 1 -
- - 12
- 4 -
- - 13
- 6 -
- - 11
- 14 -
- - 12
- 16 -
- - 13
- 2 -
- - 1
- 2 -
- - 13
- 13 -
- - 11
- 1 -
- - 7
- 1 -
- - 12
- 15 -
- - 13
- 11 -
- - 16
- 1 -
- - 14
- 17 -
- - 13
- 3 -
- - 14
- 11 -
- - 15
- 7 -
- - 12
- 20 -
- - 12
- 10 -
- - 1
- 1 -
- - 11
- 11 -
- - 6
- 1 -
- - 11
- 6 -
- - 11
- 10 -
- - 13
- 7 -
- - 12
- 12 -
- - 11
- 12 -
- - 14
- 15 -
- - 13
- 9 -
- - 10
- 1 -
- - 6
- 5 -
- - 11
- 7 -
- - 14
- 5 -
- - 11
- 3 -
- - 13
- 4 -
- - 13
- 1 -
- - 8
- 1 -
- - 5
- 1 -
- - 12
- 1 -
- - 14
- 12 -
- - 14
- 19 -
- - 15
- 4 -
- - 14
- 21 -
- - 2
- 2 -
- - 13
- 8 -
- - 15
- 8 -
- - 11
- 16 -
- - 14
- 1 -
- - 11
- 13 -
-
- - CSIS - - 2
- 2 -
- - 2
- 4 -
- - 0
- 1 -
- - 2
- 6 -
- - 3
- 4 -
- - 1
- 2 -
- - 3
- 3 -
- - 2
- 5 -
- - 0a
- 2 -
- - 3
- 2 -
- - 3
- 1 -
- - 2
- 1 -
- - 2
- 3 -
-
- - CSIP - - 14
- 9 -
- - 6
- 3 -
- - 12
- 5 -
- - 14
- 2 -
- - 13
- 10 -
- - 13
- 6 -
- - 12
- 1 -
- - 5
- 2 -
- - 14
- 6 -
- - 12
- 2 -
- - 5
- 4 -
- - 6
- 6 -
- - 6
- 9 -
- - 13
- 5 -
- - 14
- 8 -
- - 12
- 4 -
- - 6
- 2 -
- - 13
- 8 -
- - 11
- 3 -
- - 8
- 1 -
- - 6
- 1 -
- - 5
- 5 -
- - 1
- 1 -
- - 6
- 4 -
- - 6
- 7 -
- - 11
- 1 -
- - 5
- 1 -
- - 13
- 11 -
- - 10
- 1 -
- - 1
- 2 -
- - 12
- 3 -
- - 14
- 7 -
- - 14
- 5 -
- - 13
- 9 -
- - 4
- 2 -
- - 13
- 4 -
- - 6
- 8 -
- - 9
- 2 -
- - 11
- 4 -
- - 7
- 1 -
- - 13
- 2 -
- - 11
- 2 -
- - 13
- 3 -
- - 14
- 3 -
- - 15
- 1 -
- - 3
- 1 -
- - 14
- 4 -
- - 13
- 7 -
- - 2
- 2 -
-
- - PACS - - 4
- 5 -
- - 4
- 11 -
- - 4
- 4 -
- - 1
- 1 -
- - 4
- 12 -
- - 6
- 3 -
- - 4
- 6 -
- - 4
- 9 -
- - 4
- 8 -
- - 0
- 1 -
- - 6
- 2 -
- - 4
- 15 -
- - 3
- 5 -
- - 4
- 1 -
- - 4
- 2 -
- - 4
- 16 -
- - 6
- 5 -
- - 3
- 4 -
- - 3
- 3 -
- - 3
- 6 -
- - 4
- 10 -
- - 6
- 4 -
- - 6
- 1 -
- - 4
- 3 -
- - 4
- 13 -
- - 4
- 7 -
- - 3
- 1 -
- - 3
- 2 -
- - 5
- 1 -
- - 2
- 2 -
- - 4
- 14 -
-
- - ASCS - - 6
- 3 -
- - 9
- 6 -
- - 9
- 2 -
- - 6
- 2 -
- - 7
- 3 -
- - 9
- 5 -
- - 7
- 5 -
- - 8
- 1 -
- - 5
- 3 -
- - 6
- 5 -
- - 3
- 1 -
- - 6
- 6 -
- - 6
- 7 -
- - 5
- 1 -
- - 7
- 4 -
- - 9
- 3 -
- - 7
- 1 -
- - 6
- 1 -
- - 7
- 2 -
- - 2
- 2 -
- - 6
- 8 -
- - 6
- 9 -
- - 9
- 7 -
- - 0
- 1 -
- - 9
- 4 -
- - 5
- 2 -
- - 6
- 4 -
- - 9
- 1 -
- - 8
- 2 -
- - 4
- 1 -
-
- - BAP - - 44
- 13 -
- - 10
- 1 -
- - 54
- 4 -
- - 23
- 6 -
- - 44
- 9 -
- - 53
- 1 -
- - 7
- 8 -
- - 38
- 4 -
- - 20
- 4 -
- - 46
- 2 -
- - 39
- 4 -
- - 32
- 5 -
- - 23
- 10 -
- - 10
- 5 -
- - 32
- 1 -
- - 11
- 1 -
- - 20
- 1 -
- - 51
- 4 -
- - 7
- 7 -
- - 46
- 6 -
- - 20
- 9 -
- - 25
- 2 -
- - 45
- 6 -
- - 45
- 2 -
- - 46
- 9 -
- - 6
- 4 -
- - 52
- 3 -
- - 22
- 2 -
- - 5
- 2 -
- - 29
- 1 -
- - 1
- 3 -
- - 30
- 3 -
- - 36
- 6 -
- - 60
- 1 -
- - 21
- 2 -
- - 25
- 3 -
- - 51
- 1 -
- - 23
- 7 -
- - 44
- 8 -
- - 32
- 7 -
- - 61
- 1 -
- - 8
- 2 -
- - 31
- 5 -
- - 41
- 4 -
- - 9
- 1 -
- - 9
- 3 -
- - 32
- 10 -
- - 33
- 6 -
- - 30
- 1 -
- - 52
- 1 -
- - 56
- 6 -
- - 16
- 4 -
- - 16
- 6 -
- - 44
- 1 -
- - 34
- 4 -
- - 61
- 3 -
- - 9
- 4 -
- - 33
- 4 -
- - 45
- 11 -
- - 27
- 3 -
- - 32
- 3 -
- - 45
- 9 -
- - 45
- 4 -
- - 52
- 5 -
- - 40
- 4 -
- - 33
- 1 -
- - 45
- 8 -
- - 55
- 4 -
- - 9
- 6 -
- - 33
- 3 -
- - 37
- 4 -
- - 22
- 1 -
- - 59
- 1 -
- - 32
- 9 -
- - 48
- 1 -
- - 9
- 8 -
- - 50
- 1 -
- - 24
- 1 -
- - 41
- 6 -
- - 34
- 5 -
- - 45
- 3 -
- - 60
- 2 -
- - 7
- 3 -
- - 46
- 4 -
- - 28
- 2 -
- - 21
- 1 -
- - 12
- 4 -
- - 23
- 4 -
- - 45
- 13 -
- - 26
- 1 -
- - 32
- 6 -
- - 61
- 5 -
- - 48
- 2 -
- - 44
- 7 -
- - 33
- 8 -
- - 20
- 7 -
- - 51
- 2 -
- - 31
- 6 -
- - 45
- 10 -
- - 58
- 2 -
- - 23
- 1 -
- - 14
- 4 -
- - 28
- 4 -
- - 36
- 4 -
- - 34
- 3 -
- - 9
- 2 -
- - 34
- 1 -
- - 34
- 2 -
- - 6
- 2 -
- - 51
- 5 -
- - 31
- 3 -
- - 31
- 1 -
- - 20
- 2 -
- - 1
- 2 -
- - 7
- 5 -
- - 46
- 5 -
- - 20
- 3 -
- - 45
- 12 -
- - 46
- 3 -
- - 25
- 1 -
- - 7
- 4 -
- - 7
- 1 -
- - 52
- 2 -
- - 31
- 2 -
- - 32
- 2 -
- - 8
- 1 -
- - 33
- 2 -
- - 48
- 3 -
- - 33
- 5 -
- - 7
- 6 -
- - 23
- 5 -
- - 20
- 6 -
- - 47
- 1 -
- - 33
- 7 -
- - 10
- 3 -
- - 60
- 3 -
- - 45
- 7 -
- - 27
- 2 -
- - 45
- 14 -
- - 11
- 2 -
- - 51
- 3 -
- - 61
- 2 -
- - 61
- 6 -
- - 61
- 4 -
- - 5
- 1 -
- - 12
- 6 -
- - 15
- 4 -
- - 31
- 7 -
- - 7
- 2 -
- - 32
- 4 -
- - 3
- 1 -
- - 35
- 1 -
- - 10
- 2 -
- - 44
- 3 -
- - 56
- 4 -
- - 49
- 1 -
- - 23
- 2 -
- - 44
- 12 -
- - 45
- 5 -
- - 10
- 4 -
- - 4
- 1 -
- - 1
- 1 -
- - 20
- 10 -
- - 58
- 1 -
- - 52
- 4 -
- - 32
- 8 -
- - 44
- 2 -
- - 46
- 1 -
- - 44
- 6 -
- - 9
- 7 -
- - 30
- 2 -
- - 59
- 2 -
- - 9
- 5 -
- - 31
- 4 -
- - 51
- 6 -
- - 13
- 4 -
- - 29
- 2 -
-
- - CAS - - 2
- 2 -
- - 0
- 1 -
- - 3
- 1 -
-
- - CAP - - 16
- 5 -
- - 22
- 1 -
- - 1
- 1 -
- - 8
- 3 -
- - 7
- 1 -
- - 18
- 2 -
- - 12
- 1 -
- - 2
- 2 -
- - 16
- 2 -
- - 19
- 2 -
- - 20
- 3 -
- - 6
- 1 -
- - 6
- 7 -
- - 7
- 6 -
- - 19
- 1 -
- - 20
- 5 -
- - 23
- 2 -
- - 7
- 9 -
- - 4
- 1 -
- - 10
- 1 -
- - 20
- 2 -
- - 13
- 2 -
- - 7
- 4 -
- - 22
- 2 -
- - 9
- 1 -
- - 14
- 1 -
- - 18
- 1 -
- - 8
- 2 -
- - 1
- 2 -
- - 6
- 4 -
- - 3
- 1 -
- - 20
- 1 -
- - 16
- 1 -
- - 7
- 3 -
- - 10
- 2 -
- - 7
- 2 -
- - 6
- 6 -
- - 6
- 8 -
- - 23
- 1 -
- - 8
- 1 -
- - 6
- 5 -
- - 20
- 4 -
- - 7
- 7 -
- - 20
- 6 -
- - 7
- 5 -
- - 21
- 1 -
- - 16
- 6 -
- - 11
- 1 -
- - 16
- 3 -
- - 19
- 4 -
- - 17
- 1 -
-
- - HAS - - 5
- 4 -
- - 4
- 10 -
- - 4
- 8 -
- - 4
- 2 -
- - 4
- 3 -
- - 5
- 1 -
- - 4
- 1 -
- - 3
- 7 -
- - 3
- 12 -
- - 4
- 7 -
- - 3
- 14 -
- - 3
- 11 -
- - 5
- 2 -
- - 2
- 2 -
- - 5
- 6 -
- - 3
- 5 -
- - 3
- 4 -
- - 5
- 3 -
- - 3
- 2 -
- - 4
- 4 -
- - 4
- 5 -
- - 5
- 5 -
- - 3
- 6 -
- - 0
- 1 -
- - 3
- 9 -
- - 3
- 10 -
- - 3
- 1 -
- - 3
- 13 -
- - 3
- 8 -
- - 4
- 9 -
- - 3
- 3 -
- - 3
- 1a -
- - 4
- 6 -
-
- - HAP - - 12
- 5 -
- - 10
- 1 -
- - 24
- 5 -
- - 14
- 3 -
- - 13
- 4 -
- - 12
- 7 -
- - 24
- 2 -
- - 12
- 3 -
- - 24
- 3 -
- - 13
- 6 -
- - 26
- 1 -
- - 13
- 2 -
- - 13
- 1 -
- - 18
- 1 -
- - 12
- 6 -
- - 16
- 2 -
- - 16
- 1 -
- - 1
- 1 -
- - 14
- 2 -
- - 13
- 3 -
- - 12
- 2 -
- - 19
- 1 -
- - 24
- 1 -
- - 12
- 1 -
- - 24
- 4 -
- - 14
- 1 -
- - 19
- 2 -
- - 17
- 1 -
- - 25
- 1 -
- - 13
- 5 -
- - 2
- 2 -
- - 12
- 4 -
-
-
+ + + 225924 + Zephyr_Bluetooth_Host + 83 + + + + + GAP + + 17b
+ 2 +
+ + 35
+ 14 +
+ + 11b
+ 3 +
+ + 35
+ 11 +
+ + 14a
+ 7 +
+ + 27b
+ 7 +
+ + 30a
+ 5 +
+ + 30a
+ 3 +
+ + 8a
+ 14a +
+ + 14a
+ 16 +
+ + 30a
+ 10 +
+ + 30a
+ 17 +
+ + 27b
+ 5 +
+ + 8a
+ 18 +
+ + 35
+ 15 +
+ + 30a
+ 8 +
+ + 27b
+ 2 +
+ + 14a
+ 18 +
+ + 14a
+ 17 +
+ + 14a
+ 5 +
+ + 14a
+ 19 +
+ + 25
+ 12 +
+ + 17b
+ 3 +
+ + 30a
+ 19 +
+ + 30a
+ 18 +
+ + 37b
+ 6 +
+ + 20A
+ 14a +
+ + 11
+ 4 +
+ + 37b
+ 1 +
+ + 27b
+ 1 +
+ + 30a
+ 4 +
+ + 37b
+ 2 +
+ + 30a
+ 12 +
+ + 30a
+ 14 +
+ + 30a
+ 13 +
+ + 25
+ 13 +
+ + 14a
+ 2 +
+ + 11b
+ 4 +
+ + 20A
+ 18 +
+ + 37b
+ 3 +
+ + 30a
+ 15 +
+ + 11b
+ 2 +
+ + 30a
+ 6 +
+ + 14a
+ 4 +
+ + 14a
+ 6 +
+ + 14a
+ 15 +
+ + 35
+ 13 +
+ + 14a
+ 11 +
+ + 20A
+ 19 +
+ + 14a
+ 14 +
+ + 37b
+ 8 +
+ + 30a
+ 16 +
+ + 30a
+ 1 +
+ + 35
+ 12 +
+ + 30a
+ 11 +
+ + 14a
+ 9 +
+ + 30a
+ 9 +
+ + 14a
+ 1 +
+ + 14a
+ 14a +
+ + 30a
+ 14a +
+ + 14a
+ 10 +
+ + 27b
+ 8 +
+ + 27b
+ 3 +
+ + 25
+ 14 +
+ + 37b
+ 5 +
+ + 27b
+ 6 +
+ + 14a
+ 13 +
+ + 30a
+ 7 +
+ + 25
+ 11 +
+ + 8a
+ 19 +
+ + 14a
+ 3 +
+ + 37b
+ 7 +
+ + 14a
+ 8 +
+ + 14a
+ 12 +
+ + 30a
+ 2 +
+ + 0
+ 2 +
+ + 10
+ 1 +
+ + 11
+ 1 +
+ + 11
+ 2 +
+ + 11
+ 3 +
+ + 11a
+ 1 +
+ + 11a
+ 2 +
+ + 12
+ 1 +
+ + 12
+ 2 +
+ + 13
+ 1 +
+ + 13
+ 2 +
+ + 14
+ 1 +
+ + 14
+ 2 +
+ + 15
+ 1 +
+ + 16
+ 1 +
+ + 17
+ 1 +
+ + 17
+ 2 +
+ + 17
+ 3 +
+ + 17
+ 4 +
+ + 17a
+ 1 +
+ + 17a
+ 2 +
+ + 18
+ 1 +
+ + 18
+ 2 +
+ + 19
+ 1 +
+ + 19
+ 2 +
+ + 19
+ 3 +
+ + 20
+ 1 +
+ + 20
+ 2 +
+ + 20
+ 3 +
+ + 20
+ 4 +
+ + 20
+ 5 +
+ + 20
+ 6 +
+ + 20
+ 7 +
+ + 20A
+ 1 +
+ + 20A
+ 10 +
+ + 20A
+ 11 +
+ + 20A
+ 12 +
+ + 20A
+ 13 +
+ + 20A
+ 14 +
+ + 20A
+ 15 +
+ + 20A
+ 16 +
+ + 20A
+ 17 +
+ + 20A
+ 2 +
+ + 20A
+ 3 +
+ + 20A
+ 4 +
+ + 20A
+ 5 +
+ + 20A
+ 7 +
+ + 20A
+ 8 +
+ + 20A
+ 9 +
+ + 21
+ 1 +
+ + 21
+ 10 +
+ + 21
+ 11 +
+ + 21
+ 2 +
+ + 21
+ 3 +
+ + 21
+ 4 +
+ + 21
+ 5 +
+ + 21
+ 6 +
+ + 21
+ 7 +
+ + 21
+ 8 +
+ + 21
+ 9 +
+ + 22
+ 1 +
+ + 22
+ 2 +
+ + 22
+ 3 +
+ + 22
+ 4 +
+ + 23
+ 1 +
+ + 23
+ 2 +
+ + 23
+ 3 +
+ + 23
+ 4 +
+ + 23
+ 5 +
+ + 24
+ 1 +
+ + 24
+ 2 +
+ + 24
+ 3 +
+ + 24
+ 4 +
+ + 25
+ 1 +
+ + 25
+ 10 +
+ + 25
+ 2 +
+ + 25
+ 3 +
+ + 25
+ 4 +
+ + 25
+ 5 +
+ + 25
+ 6 +
+ + 25
+ 7 +
+ + 25
+ 8 +
+ + 25
+ 9 +
+ + 26
+ 1 +
+ + 26
+ 2 +
+ + 26
+ 3 +
+ + 26
+ 4 +
+ + 27
+ 1 +
+ + 27
+ 2 +
+ + 27
+ 5 +
+ + 27
+ 6 +
+ + 27
+ 9 +
+ + 28
+ 1 +
+ + 28
+ 2 +
+ + 29
+ 1 +
+ + 29
+ 2 +
+ + 29
+ 3 +
+ + 29
+ 4 +
+ + 30
+ 1 +
+ + 30
+ 2 +
+ + 31
+ 1 +
+ + 31
+ 10 +
+ + 31
+ 11 +
+ + 31
+ 2 +
+ + 31
+ 3 +
+ + 31
+ 4 +
+ + 31
+ 5 +
+ + 31
+ 6 +
+ + 31
+ 8 +
+ + 31
+ 9 +
+ + 32
+ 1 +
+ + 32
+ 2 +
+ + 32
+ 3 +
+ + 33
+ 1 +
+ + 33
+ 2 +
+ + 33
+ 4 +
+ + 33
+ 5 +
+ + 33
+ 6 +
+ + 34
+ 1 +
+ + 34
+ 2 +
+ + 34
+ 3 +
+ + 35
+ 1 +
+ + 35
+ 10 +
+ + 35
+ 2 +
+ + 35
+ 3 +
+ + 35
+ 4 +
+ + 35
+ 5 +
+ + 35
+ 6 +
+ + 35
+ 7 +
+ + 35
+ 8 +
+ + 35
+ 9 +
+ + 36
+ 1 +
+ + 36
+ 2 +
+ + 36
+ 3 +
+ + 36
+ 5 +
+ + 37
+ 1 +
+ + 37
+ 2 +
+ + 37
+ 3 +
+ + 5
+ 1 +
+ + 5
+ 2 +
+ + 5
+ 3 +
+ + 5
+ 4 +
+ + 6
+ 1 +
+ + 6
+ 2 +
+ + 7
+ 1 +
+ + 7
+ 2 +
+ + 8
+ 1 +
+ + 8
+ 2 +
+ + 8
+ 3 +
+ + 8
+ 4 +
+ + 8a
+ 1 +
+ + 8a
+ 10 +
+ + 8a
+ 11 +
+ + 8a
+ 12 +
+ + 8a
+ 13 +
+ + 8a
+ 14 +
+ + 8a
+ 15 +
+ + 8a
+ 16 +
+ + 8a
+ 17 +
+ + 8a
+ 2 +
+ + 8a
+ 3 +
+ + 8a
+ 4 +
+ + 8a
+ 5 +
+ + 8a
+ 6 +
+ + 8a
+ 7 +
+ + 8a
+ 8 +
+ + 8a
+ 9 +
+ + 9
+ 1 +
+ + 10
+ 2 +
+ + 10
+ 3 +
+ + 10
+ 4 +
+ + 10
+ 5 +
+ + 11b
+ 1 +
+ + 16
+ 2 +
+ + 16
+ 3 +
+ + 16
+ 4 +
+ + 17b
+ 1 +
+ + 23
+ 6 +
+ + 33
+ 7 +
+ + 7
+ 3 +
+
+ + L2CAP + + 2
+ 48b +
+ + 4
+ 3 +
+ + 4
+ 2 +
+ + 4
+ 1 +
+ + 2
+ 40 +
+ + 2
+ 41 +
+ + 2
+ 42 +
+ + 2
+ 43 +
+ + 2
+ 45a +
+ + 2
+ 46 +
+ + 2
+ 47 +
+ + 3
+ 1 +
+ + 3
+ 12 +
+ + 3
+ 16 +
+ + 0
+ 2 +
+ + 1
+ 3 +
+ + 1
+ 4 +
+ + 1
+ 5 +
+ + 1
+ 6 +
+ + 2
+ 48 +
+
+ + IOP + + 1
+ 1 +
+ + 2
+ 2 +
+
+ + SUM ICS + + 31
+ 23 +
+ + 52
+ 1 +
+
+ + PROD + + 1
+ 4 +
+ + 3
+ 3 +
+
+ + GATT + + 9
+ 3 +
+ + 10
+ 11 +
+ + 8
+ 2 +
+ + 2
+ 3a +
+ + 9
+ 10 +
+ + 10
+ 6 +
+ + 10
+ 1 +
+ + 9
+ 15 +
+ + 10
+ 7 +
+ + 9
+ 2 +
+ + 3a
+ 1 +
+ + 8
+ 8 +
+ + 10
+ 2 +
+ + 9
+ 13 +
+ + 10
+ 12 +
+ + 10
+ 5 +
+ + 9
+ 4 +
+ + 3a
+ 2 +
+ + 10
+ 3 +
+ + 2
+ 4 +
+ + 9
+ 8 +
+ + 9
+ 1 +
+ + 9
+ 6 +
+ + 10
+ 9 +
+ + 4a
+ 2 +
+ + 10
+ 4 +
+ + 2
+ 5 +
+ + 9
+ 11 +
+ + 9
+ 14 +
+ + 9
+ 9 +
+ + 9
+ 5 +
+ + 4a
+ 1 +
+ + 9
+ 7 +
+ + 10
+ 8 +
+ + 9
+ 12 +
+ + 1
+ 1 +
+ + 1
+ 2 +
+ + 1a
+ 1 +
+ + 1a
+ 3 +
+ + 3
+ 29 +
+ + 3
+ 30 +
+ + 4
+ 30 +
+ + 4
+ 31 +
+ + 2
+ 2 +
+ + 3
+ 1 +
+ + 3
+ 10 +
+ + 3
+ 11 +
+ + 3
+ 12 +
+ + 3
+ 13 +
+ + 3
+ 14 +
+ + 3
+ 15 +
+ + 3
+ 17 +
+ + 3
+ 18 +
+ + 3
+ 19 +
+ + 3
+ 2 +
+ + 3
+ 20 +
+ + 3
+ 21 +
+ + 3
+ 22 +
+ + 3
+ 23 +
+ + 3
+ 25 +
+ + 3
+ 26 +
+ + 3
+ 3 +
+ + 3
+ 4 +
+ + 3
+ 5 +
+ + 3
+ 6 +
+ + 3
+ 7 +
+ + 3
+ 8 +
+ + 3
+ 9 +
+ + 4
+ 1 +
+ + 4
+ 10 +
+ + 4
+ 11 +
+ + 4
+ 12 +
+ + 4
+ 13 +
+ + 4
+ 14 +
+ + 4
+ 15 +
+ + 4
+ 16 +
+ + 4
+ 17 +
+ + 4
+ 18 +
+ + 4
+ 19 +
+ + 4
+ 2 +
+ + 4
+ 20 +
+ + 4
+ 21 +
+ + 4
+ 22 +
+ + 4
+ 23 +
+ + 4
+ 25 +
+ + 4
+ 26 +
+ + 4
+ 27 +
+ + 4
+ 3 +
+ + 4
+ 4 +
+ + 4
+ 5 +
+ + 4
+ 6 +
+ + 4
+ 7 +
+ + 4
+ 8 +
+ + 4
+ 9 +
+ + 7
+ 2 +
+ + 7
+ 3 +
+ + 7
+ 4 +
+ + 7
+ 5 +
+ + 7
+ 6 +
+ + 7
+ 7 +
+
+ + SM + + 7a
+ 1 +
+ + 7a
+ 2 +
+ + 7b
+ 1 +
+ + 7b
+ 2 +
+ + 7b
+ 3 +
+ + 7a
+ 3 +
+ + 1
+ 1 +
+ + 1
+ 2 +
+ + 2
+ 1 +
+ + 2
+ 2 +
+ + 2
+ 3 +
+ + 2
+ 4 +
+ + 2
+ 5 +
+ + 3
+ 1 +
+ + 4
+ 1 +
+ + 4
+ 2 +
+ + 4
+ 3 +
+ + 5
+ 1 +
+ + 5
+ 2 +
+ + 5
+ 3 +
+ + 5
+ 4 +
+ + 6
+ 1 +
+ + 6
+ 2 +
+
+ + ATT + + 7
+ 3 +
+ + 7
+ 1 +
+ + 7
+ 2 +
+ + 6
+ 1 +
+ + 2
+ 3a +
+ + 1
+ 1 +
+ + 1
+ 2 +
+ + 3
+ 30 +
+ + 3
+ 31 +
+ + 3
+ 32 +
+ + 4
+ 31 +
+ + 4
+ 32 +
+ + 4
+ 33 +
+ + 2
+ 2 +
+ + 3
+ 1 +
+ + 3
+ 10 +
+ + 3
+ 11 +
+ + 3
+ 12 +
+ + 3
+ 13 +
+ + 3
+ 14 +
+ + 3
+ 15 +
+ + 3
+ 16 +
+ + 3
+ 17 +
+ + 3
+ 18 +
+ + 3
+ 19 +
+ + 3
+ 2 +
+ + 3
+ 20 +
+ + 3
+ 21 +
+ + 3
+ 22 +
+ + 3
+ 23 +
+ + 3
+ 24 +
+ + 3
+ 25 +
+ + 3
+ 26 +
+ + 3
+ 27 +
+ + 3
+ 28 +
+ + 3
+ 3 +
+ + 3
+ 4 +
+ + 3
+ 5 +
+ + 3
+ 6 +
+ + 3
+ 7 +
+ + 3
+ 8 +
+ + 3
+ 9 +
+ + 4
+ 1 +
+ + 4
+ 10 +
+ + 4
+ 11 +
+ + 4
+ 12 +
+ + 4
+ 13 +
+ + 4
+ 14 +
+ + 4
+ 15 +
+ + 4
+ 16 +
+ + 4
+ 17 +
+ + 4
+ 18 +
+ + 4
+ 19 +
+ + 4
+ 2 +
+ + 4
+ 20 +
+ + 4
+ 21 +
+ + 4
+ 22 +
+ + 4
+ 23 +
+ + 4
+ 24 +
+ + 4
+ 25 +
+ + 4
+ 26 +
+ + 4
+ 27 +
+ + 4
+ 28 +
+ + 4
+ 3 +
+ + 4
+ 4 +
+ + 4
+ 5 +
+ + 4
+ 6 +
+ + 4
+ 7 +
+ + 4
+ 8 +
+ + 4
+ 9 +
+
+ + DIS + + 5
+ 1 +
+ + 3
+ 3 +
+ + 0
+ 2 +
+ + 1
+ 2 +
+ + 2
+ 1 +
+ + 2
+ 11 +
+ + 2
+ 2 +
+ + 2
+ 3 +
+ + 2
+ 4 +
+ + 2
+ 5 +
+ + 2
+ 6 +
+ + 2
+ 7 +
+
+ + IAS + + 0
+ 1 +
+ + 3
+ 1 +
+ + 3
+ 2 +
+ + 1
+ 2 +
+ + 2
+ 1 +
+ + 2
+ 2 +
+ + 2
+ 3 +
+ + 2
+ 4 +
+
+ + HRS + + 3
+ 4 +
+ + 0
+ 1 +
+ + 3
+ 6 +
+ + 3
+ 2 +
+ + 3
+ 5 +
+ + 1
+ 2 +
+ + 2
+ 1 +
+ + 2
+ 2 +
+
+ + BAS + + 3
+ 1 +
+ + 3
+ 5 +
+ + 3
+ 3 +
+ + 4
+ 2 +
+ + 0
+ 2 +
+ + 4
+ 1 +
+ + 1
+ 2 +
+ + 2
+ 1 +
+ + 2
+ 3 +
+
+ + OTS + + 8
+ 3 +
+ + 8
+ 1 +
+ + 8
+ 7 +
+ + 8
+ 8 +
+ + 8
+ 4 +
+ + 0
+ 1 +
+ + 2
+ 1 +
+ + 3
+ 2 +
+ + 3
+ 3 +
+ + 4
+ 1 +
+ + 4
+ 12 +
+ + 4
+ 13 +
+ + 4
+ 15 +
+ + 4
+ 16 +
+ + 4
+ 2 +
+ + 4
+ 20 +
+ + 4
+ 3 +
+ + 4
+ 6 +
+ + 4
+ 7 +
+ + 5
+ 1 +
+ + 5
+ 2 +
+ + 5
+ 3 +
+ + 5
+ 4 +
+ + 5
+ 5 +
+ + 5
+ 6 +
+ + 6
+ 1 +
+ + 6
+ 2 +
+ + 6
+ 3 +
+ + 6
+ 4 +
+ + 6
+ 5 +
+ + 7
+ 1 +
+
+ + MESH + + 12
+ 12 +
+ + 18
+ 12 +
+ + 1a
+ 2 +
+ + 4
+ 13 +
+ + 2
+ 3 +
+ + 0a
+ 3 +
+ + 0
+ 1 +
+ + 0a
+ 1 +
+ + 0a
+ 2 +
+ + 2
+ 1 +
+ + 2
+ 2 +
+ + 10
+ 1 +
+ + 10
+ 2 +
+ + 10
+ 3 +
+ + 10
+ 4 +
+ + 11
+ 1 +
+ + 11
+ 2 +
+ + 11
+ 3 +
+ + 11
+ 4 +
+ + 12
+ 1 +
+ + 12
+ 2 +
+ + 12
+ 3 +
+ + 12
+ 4 +
+ + 12
+ 5 +
+ + 12
+ 6 +
+ + 13
+ 1 +
+ + 13
+ 2 +
+ + 14
+ 1 +
+ + 14
+ 2 +
+ + 14
+ 3 +
+ + 14
+ 4 +
+ + 14
+ 5 +
+ + 15
+ 1 +
+ + 15
+ 2 +
+ + 15
+ 3 +
+ + 15
+ 4 +
+ + 15
+ 5 +
+ + 16
+ 1 +
+ + 16
+ 2 +
+ + 16
+ 3 +
+ + 16
+ 4 +
+ + 16
+ 5 +
+ + 16
+ 6 +
+ + 3
+ 1 +
+ + 3
+ 2 +
+ + 4
+ 1 +
+ + 4
+ 10 +
+ + 4
+ 11 +
+ + 4
+ 12 +
+ + 4
+ 2 +
+ + 4
+ 3 +
+ + 4
+ 4 +
+ + 4
+ 5 +
+ + 4
+ 6 +
+ + 4
+ 7 +
+ + 4
+ 8 +
+ + 4
+ 9 +
+ + 5
+ 1 +
+ + 5
+ 2 +
+ + 5
+ 3 +
+ + 5
+ 4 +
+ + 6
+ 1 +
+ + 6
+ 2 +
+ + 6
+ 3 +
+ + 7
+ 1 +
+ + 7
+ 2 +
+ + 7
+ 3 +
+ + 7
+ 4 +
+ + 7
+ 5 +
+ + 8
+ 1 +
+ + 9
+ 1 +
+ + 18
+ 1 +
+ + 18
+ 10 +
+ + 18
+ 11 +
+ + 18
+ 2 +
+ + 18
+ 3 +
+ + 18
+ 4 +
+ + 18
+ 5 +
+ + 18
+ 6 +
+ + 18
+ 7 +
+ + 18
+ 8 +
+ + 18
+ 9 +
+ + 19
+ 1 +
+ + 20
+ 1 +
+ + 20
+ 2 +
+ + 20
+ 3 +
+ + 20
+ 4 +
+ + 20
+ 5 +
+ + 21
+ 1 +
+ + 21
+ 2 +
+ + 21
+ 3 +
+ + 21
+ 4 +
+
+ + AICS + + 4
+ 1 +
+ + 3
+ 5 +
+ + 2
+ 2 +
+ + 3
+ 3 +
+ + 4
+ 4 +
+ + 4
+ 2 +
+ + 3
+ 4 +
+ + 3
+ 1 +
+ + 3
+ 2 +
+ + 4
+ 3 +
+ + 2
+ 6 +
+ + 2
+ 3 +
+ + 2
+ 4 +
+ + 2
+ 1 +
+ + 1
+ 2 +
+ + 2
+ 5 +
+ + 2
+ 7 +
+ + 2
+ 8 +
+ + 0
+ 1 +
+
+ + VOCS + + 2
+ 2 +
+ + 3
+ 2 +
+ + 1
+ 2 +
+ + 2
+ 4 +
+ + 2
+ 7 +
+ + 0
+ 1 +
+ + 3
+ 4 +
+ + 2
+ 5 +
+ + 3
+ 3 +
+ + 2
+ 3 +
+ + 2
+ 1 +
+ + 2
+ 6 +
+ + 2
+ 8 +
+ + 3
+ 1 +
+
+ + VCS + + 3
+ 6 +
+ + 2
+ 2 +
+ + 3
+ 7 +
+ + 4
+ 2 +
+ + 3
+ 3 +
+ + 4
+ 4 +
+ + 0
+ 1 +
+ + 2
+ 1 +
+ + 3
+ 5 +
+ + 3
+ 2 +
+ + 3
+ 4 +
+ + 2
+ 4 +
+ + 3
+ 1 +
+ + 1
+ 2 +
+ + 4
+ 3 +
+ + 2
+ 3 +
+ + 4
+ 1 +
+
+ + VCP + + 15
+ 1 +
+ + 14
+ 2 +
+ + 15
+ 2 +
+ + 13
+ 2 +
+ + 19
+ 1 +
+ + 12
+ 8 +
+ + 16
+ 3 +
+ + 17
+ 5 +
+ + 10
+ 1 +
+ + 17
+ 11 +
+ + 16
+ 9 +
+ + 5
+ 1 +
+ + 16
+ 10 +
+ + 13
+ 1 +
+ + 16
+ 12 +
+ + 11
+ 1 +
+ + 15
+ 3 +
+ + 6
+ 1 +
+ + 11
+ 3 +
+ + 8
+ 1 +
+ + 12
+ 3 +
+ + 5
+ 2 +
+ + 11
+ 2 +
+ + 18
+ 1 +
+ + 7
+ 1 +
+ + 17
+ 7 +
+ + 17
+ 10 +
+ + 6
+ 3 +
+ + 10
+ 3 +
+ + 16
+ 11 +
+ + 18
+ 7 +
+ + 1
+ 2 +
+ + 12
+ 9 +
+ + 16
+ 13 +
+ + 16
+ 7 +
+ + 12
+ 11 +
+ + 18
+ 3 +
+ + 16
+ 2 +
+ + 14
+ 4 +
+ + 5
+ 4 +
+ + 14
+ 3 +
+ + 5
+ 3 +
+ + 12
+ 10 +
+ + 17
+ 4 +
+ + 14
+ 8 +
+ + 18
+ 12 +
+ + 16
+ 14 +
+ + 14
+ 1 +
+ + 18
+ 2 +
+ + 13
+ 4 +
+ + 17
+ 9 +
+ + 16
+ 1 +
+ + 16
+ 5 +
+ + 17
+ 3 +
+ + 15
+ 4 +
+ + 2
+ 2 +
+ + 12
+ 12 +
+ + 18
+ 4 +
+ + 12
+ 7 +
+ + 12
+ 1 +
+ + 16
+ 8 +
+ + 6
+ 2 +
+ + 14
+ 7 +
+ + 6
+ 8 +
+ + 12
+ 5 +
+ + 12
+ 6 +
+ + 15
+ 6 +
+ + 17
+ 8 +
+ + 10
+ 2 +
+ + 15
+ 5 +
+ + 12
+ 4 +
+ + 14
+ 6 +
+ + 17
+ 1 +
+ + 3
+ 1 +
+ + 16
+ 4 +
+ + 14
+ 5 +
+ + 13
+ 3 +
+ + 18
+ 6 +
+ + 12
+ 2 +
+ + 17
+ 6 +
+ + 17
+ 2 +
+ + 1
+ 1 +
+ + 16
+ 6 +
+ + 14
+ 9 +
+
+ + MICS + + 2
+ 1 +
+ + 3
+ 2 +
+ + 3
+ 3 +
+ + 3
+ 1 +
+ + 0
+ 1 +
+ + 1
+ 2 +
+ + 3
+ 4 +
+
+ + MICP + + 15
+ 6 +
+ + 16
+ 3 +
+ + 15
+ 5 +
+ + 6
+ 5 +
+ + 14
+ 2 +
+ + 14
+ 13 +
+ + 15
+ 8 +
+ + 16
+ 5 +
+ + 17
+ 1 +
+ + 1
+ 1 +
+ + 14
+ 10 +
+ + 14
+ 8 +
+ + 15
+ 2 +
+ + 15
+ 7 +
+ + 6
+ 6 +
+ + 6
+ 8 +
+ + 8
+ 1 +
+ + 14
+ 9 +
+ + 15
+ 11 +
+ + 6
+ 2 +
+ + 10
+ 1 +
+ + 11
+ 1 +
+ + 12
+ 1 +
+ + 14
+ 5 +
+ + 14
+ 11 +
+ + 5
+ 1 +
+ + 15
+ 1 +
+ + 15
+ 9 +
+ + 14
+ 7 +
+ + 13
+ 2 +
+ + 3
+ 1 +
+ + 12
+ 3 +
+ + 1
+ 2 +
+ + 16
+ 7 +
+ + 15
+ 4 +
+ + 14
+ 3 +
+ + 13
+ 3 +
+ + 16
+ 1 +
+ + 16
+ 6 +
+ + 12
+ 2 +
+ + 13
+ 6 +
+ + 16
+ 4 +
+ + 14
+ 6 +
+ + 15
+ 3 +
+ + 14
+ 12 +
+ + 6
+ 4 +
+ + 6
+ 1 +
+ + 13
+ 1 +
+ + 15
+ 10 +
+ + 14
+ 1 +
+ + 10
+ 2 +
+ + 7
+ 1 +
+ + 13
+ 5 +
+ + 14
+ 14 +
+ + 14
+ 4 +
+ + 5
+ 2 +
+ + 13
+ 4 +
+ + 2
+ 2 +
+
+ + GMCS + + 2
+ 15 +
+ + 3
+ 21 +
+ + 2
+ 19 +
+ + 3
+ 4 +
+ + 2
+ 20 +
+ + 3
+ 6 +
+ + 2
+ 6 +
+ + 4
+ 2 +
+ + 2
+ 4 +
+ + 2
+ 1 +
+ + 2
+ 3 +
+ + 5
+ 2 +
+ + 3
+ 12 +
+ + 4
+ 3 +
+ + 3
+ 20 +
+ + 5
+ 4 +
+ + 0
+ 1 +
+ + 3
+ 17 +
+ + 2
+ 24 +
+ + 3
+ 3 +
+ + 3
+ 10 +
+ + 3
+ 8 +
+ + 3
+ 9 +
+ + 2
+ 17 +
+ + 4
+ 1 +
+ + 3
+ 1 +
+ + 2
+ 26 +
+ + 3
+ 14 +
+ + 3
+ 18 +
+ + 2
+ 11 +
+ + 2
+ 14 +
+ + 1
+ 2 +
+ + 2
+ 22 +
+ + 3
+ 15 +
+ + 3
+ 2 +
+ + 2
+ 23 +
+ + 5
+ 1 +
+ + 3
+ 11 +
+ + 2
+ 13 +
+ + 2
+ 18 +
+ + 5
+ 3 +
+ + 3
+ 16 +
+ + 2
+ 16 +
+ + 2
+ 9 +
+ + 3
+ 5 +
+ + 2
+ 7 +
+ + 3
+ 7 +
+ + 2
+ 2 +
+ + 2
+ 10 +
+ + 3
+ 13 +
+ + 2
+ 25 +
+ + 4
+ 4 +
+ + 2
+ 5 +
+ + 2
+ 21 +
+ + 3
+ 19 +
+ + 2
+ 12 +
+ + 2
+ 8 +
+
+ + MCP + + 17
+ 13 +
+ + 17
+ 19 +
+ + 21
+ 1 +
+ + 16
+ 19 +
+ + 6
+ 3 +
+ + 16
+ 4 +
+ + 9
+ 2 +
+ + 21
+ 3 +
+ + 18
+ 5 +
+ + 17
+ 1 +
+ + 21
+ 2 +
+ + 2
+ 2 +
+ + 18
+ 2 +
+ + 6
+ 6 +
+ + 16
+ 22 +
+ + 6
+ 2 +
+ + 7
+ 1 +
+ + 20
+ 1 +
+ + 5
+ 4 +
+ + 16
+ 12 +
+ + 8
+ 1 +
+ + 18
+ 7 +
+ + 17
+ 2 +
+ + 17
+ 17 +
+ + 17
+ 11 +
+ + 17
+ 18 +
+ + 19
+ 3 +
+ + 16
+ 6 +
+ + 6
+ 1 +
+ + 9
+ 1 +
+ + 17
+ 12 +
+ + 17
+ 6 +
+ + 16
+ 17 +
+ + 6
+ 5 +
+ + 18
+ 4 +
+ + 19
+ 1 +
+ + 16
+ 11 +
+ + 17
+ 7 +
+ + 16
+ 8 +
+ + 11
+ 1 +
+ + 17
+ 5 +
+ + 16
+ 14 +
+ + 6
+ 7 +
+ + 3
+ 1 +
+ + 18
+ 6 +
+ + 16
+ 3 +
+ + 18
+ 3 +
+ + 10
+ 2 +
+ + 16
+ 1 +
+ + 16
+ 21 +
+ + 16
+ 7 +
+ + 7
+ 3 +
+ + 17
+ 4 +
+ + 17
+ 9 +
+ + 17
+ 3 +
+ + 9
+ 3 +
+ + 16
+ 9 +
+ + 16
+ 13 +
+ + 17
+ 14 +
+ + 17
+ 10 +
+ + 16
+ 20 +
+ + 16
+ 10 +
+ + 6
+ 4 +
+ + 16
+ 16 +
+ + 17
+ 20 +
+ + 5
+ 2 +
+ + 5
+ 3 +
+ + 17
+ 15 +
+ + 16
+ 5 +
+ + 13
+ 2 +
+ + 16
+ 2 +
+ + 13
+ 3 +
+ + 1
+ 2 +
+ + 10
+ 1 +
+ + 1
+ 1 +
+ + 18
+ 8 +
+ + 17
+ 16 +
+ + 17
+ 8 +
+ + 16
+ 18 +
+ + 16
+ 15 +
+
+ + TBS + + 2
+ 13 +
+ + 3
+ 1 +
+ + 2
+ 12 +
+ + 4
+ 5 +
+ + 2
+ 15 +
+ + 4
+ 3 +
+ + 2
+ 7 +
+ + 2
+ 22 +
+ + 2
+ 23 +
+ + 2
+ 21 +
+ + 2
+ 2 +
+ + 2
+ 16 +
+ + 3
+ 4 +
+ + 2
+ 18 +
+ + 4
+ 2 +
+ + 3
+ 2 +
+ + 2
+ 5 +
+ + 2
+ 14 +
+ + 3
+ 6 +
+ + 2
+ 19 +
+ + 0
+ 1 +
+ + 2
+ 3 +
+ + 2
+ 25 +
+ + 4
+ 1 +
+ + 2
+ 4 +
+ + 2
+ 9 +
+ + 2
+ 17 +
+ + 4
+ 4 +
+ + 1
+ 2 +
+ + 2
+ 11 +
+ + 3
+ 3 +
+ + 2
+ 20 +
+ + 2
+ 24 +
+ + 2
+ 10 +
+ + 2
+ 6 +
+ + 3
+ 5 +
+ + 2
+ 8 +
+ + 2
+ 1 +
+
+ + GTBS + + 3
+ 2 +
+ + 4
+ 1 +
+ + 2
+ 22 +
+ + 3
+ 3 +
+ + 2
+ 20 +
+ + 4
+ 5 +
+ + 2
+ 4 +
+ + 2
+ 18 +
+ + 2
+ 17 +
+ + 4
+ 3 +
+ + 2
+ 5 +
+ + 3
+ 1 +
+ + 4
+ 2 +
+ + 2
+ 24 +
+ + 2
+ 2 +
+ + 1
+ 2 +
+ + 3
+ 5 +
+ + 2
+ 21 +
+ + 2
+ 23 +
+ + 2
+ 25 +
+ + 4
+ 4 +
+ + 3
+ 4 +
+ + 2
+ 7 +
+ + 2
+ 1 +
+ + 2
+ 9 +
+ + 2
+ 16 +
+ + 2
+ 8 +
+ + 2
+ 12 +
+ + 2
+ 14 +
+ + 0
+ 1 +
+ + 2
+ 15 +
+ + 3
+ 6 +
+ + 2
+ 10 +
+ + 2
+ 11 +
+ + 2
+ 6 +
+ + 2
+ 19 +
+ + 2
+ 3 +
+ + 2
+ 13 +
+
+ + CCP + + 12
+ 7 +
+ + 14
+ 7 +
+ + 14
+ 10 +
+ + 13
+ 14 +
+ + 12
+ 13 +
+ + 11
+ 9 +
+ + 14
+ 20 +
+ + 12
+ 5 +
+ + 13
+ 15 +
+ + 12
+ 6 +
+ + 13
+ 5 +
+ + 14
+ 8 +
+ + 6
+ 2 +
+ + 12
+ 21 +
+ + 12
+ 17 +
+ + 6
+ 4 +
+ + 12
+ 11 +
+ + 11
+ 2 +
+ + 14
+ 3 +
+ + 15
+ 3 +
+ + 10
+ 2 +
+ + 13
+ 10 +
+ + 14
+ 2 +
+ + 14
+ 18 +
+ + 12
+ 9 +
+ + 11
+ 4 +
+ + 13
+ 16 +
+ + 6
+ 6 +
+ + 12
+ 3 +
+ + 5
+ 2 +
+ + 12
+ 2 +
+ + 12
+ 18 +
+ + 15
+ 6 +
+ + 14
+ 13 +
+ + 12
+ 19 +
+ + 12
+ 14 +
+ + 14
+ 14 +
+ + 11
+ 8 +
+ + 15
+ 5 +
+ + 5
+ 3 +
+ + 15
+ 2 +
+ + 14
+ 4 +
+ + 14
+ 22 +
+ + 11
+ 5 +
+ + 12
+ 8 +
+ + 14
+ 9 +
+ + 14
+ 6 +
+ + 6
+ 7 +
+ + 12
+ 22 +
+ + 11
+ 15 +
+ + 14
+ 16 +
+ + 13
+ 12 +
+ + 3
+ 1 +
+ + 12
+ 4 +
+ + 13
+ 6 +
+ + 11
+ 14 +
+ + 12
+ 16 +
+ + 13
+ 2 +
+ + 1
+ 2 +
+ + 13
+ 13 +
+ + 11
+ 1 +
+ + 7
+ 1 +
+ + 12
+ 15 +
+ + 13
+ 11 +
+ + 16
+ 1 +
+ + 14
+ 17 +
+ + 13
+ 3 +
+ + 14
+ 11 +
+ + 15
+ 7 +
+ + 12
+ 20 +
+ + 12
+ 10 +
+ + 1
+ 1 +
+ + 11
+ 11 +
+ + 6
+ 1 +
+ + 11
+ 6 +
+ + 11
+ 10 +
+ + 13
+ 7 +
+ + 12
+ 12 +
+ + 11
+ 12 +
+ + 14
+ 15 +
+ + 13
+ 9 +
+ + 10
+ 1 +
+ + 6
+ 5 +
+ + 11
+ 7 +
+ + 14
+ 5 +
+ + 11
+ 3 +
+ + 13
+ 4 +
+ + 13
+ 1 +
+ + 8
+ 1 +
+ + 5
+ 1 +
+ + 12
+ 1 +
+ + 14
+ 12 +
+ + 14
+ 19 +
+ + 15
+ 4 +
+ + 14
+ 21 +
+ + 2
+ 2 +
+ + 13
+ 8 +
+ + 15
+ 8 +
+ + 11
+ 16 +
+ + 14
+ 1 +
+ + 11
+ 13 +
+
+ + CSIS + + 2
+ 2 +
+ + 2
+ 4 +
+ + 0
+ 1 +
+ + 2
+ 6 +
+ + 3
+ 4 +
+ + 1
+ 2 +
+ + 3
+ 3 +
+ + 2
+ 5 +
+ + 0a
+ 2 +
+ + 3
+ 2 +
+ + 3
+ 1 +
+ + 2
+ 1 +
+ + 2
+ 3 +
+
+ + CSIP + + 14
+ 9 +
+ + 6
+ 3 +
+ + 12
+ 5 +
+ + 14
+ 2 +
+ + 13
+ 10 +
+ + 13
+ 6 +
+ + 13
+ 1 +
+ + 12
+ 1 +
+ + 5
+ 2 +
+ + 14
+ 6 +
+ + 12
+ 2 +
+ + 5
+ 4 +
+ + 6
+ 6 +
+ + 6
+ 9 +
+ + 13
+ 5 +
+ + 14
+ 8 +
+ + 12
+ 4 +
+ + 6
+ 2 +
+ + 13
+ 8 +
+ + 11
+ 3 +
+ + 8
+ 1 +
+ + 6
+ 1 +
+ + 5
+ 5 +
+ + 1
+ 1 +
+ + 6
+ 4 +
+ + 6
+ 7 +
+ + 11
+ 1 +
+ + 5
+ 1 +
+ + 13
+ 11 +
+ + 10
+ 1 +
+ + 1
+ 2 +
+ + 12
+ 3 +
+ + 14
+ 7 +
+ + 14
+ 5 +
+ + 13
+ 9 +
+ + 4
+ 2 +
+ + 13
+ 4 +
+ + 6
+ 8 +
+ + 9
+ 2 +
+ + 11
+ 4 +
+ + 7
+ 1 +
+ + 13
+ 2 +
+ + 11
+ 2 +
+ + 13
+ 3 +
+ + 14
+ 3 +
+ + 15
+ 1 +
+ + 3
+ 1 +
+ + 14
+ 4 +
+ + 13
+ 7 +
+ + 2
+ 2 +
+
+ + PACS + + 4
+ 5 +
+ + 4
+ 11 +
+ + 4
+ 4 +
+ + 1
+ 1 +
+ + 4
+ 12 +
+ + 6
+ 3 +
+ + 4
+ 6 +
+ + 4
+ 9 +
+ + 4
+ 8 +
+ + 0
+ 1 +
+ + 6
+ 2 +
+ + 4
+ 15 +
+ + 3
+ 5 +
+ + 4
+ 1 +
+ + 4
+ 2 +
+ + 4
+ 16 +
+ + 6
+ 5 +
+ + 3
+ 4 +
+ + 3
+ 3 +
+ + 3
+ 6 +
+ + 4
+ 10 +
+ + 6
+ 4 +
+ + 6
+ 1 +
+ + 4
+ 3 +
+ + 4
+ 13 +
+ + 4
+ 7 +
+ + 3
+ 1 +
+ + 3
+ 2 +
+ + 5
+ 1 +
+ + 2
+ 2 +
+ + 4
+ 14 +
+
+ + ASCS + + 6
+ 3 +
+ + 9
+ 6 +
+ + 9
+ 2 +
+ + 6
+ 2 +
+ + 7
+ 3 +
+ + 9
+ 5 +
+ + 7
+ 5 +
+ + 8
+ 1 +
+ + 5
+ 3 +
+ + 6
+ 5 +
+ + 3
+ 1 +
+ + 6
+ 6 +
+ + 6
+ 7 +
+ + 5
+ 1 +
+ + 7
+ 4 +
+ + 9
+ 3 +
+ + 7
+ 1 +
+ + 6
+ 1 +
+ + 7
+ 2 +
+ + 2
+ 2 +
+ + 6
+ 8 +
+ + 6
+ 9 +
+ + 9
+ 7 +
+ + 0
+ 1 +
+ + 9
+ 4 +
+ + 5
+ 2 +
+ + 6
+ 4 +
+ + 9
+ 1 +
+ + 8
+ 2 +
+ + 4
+ 1 +
+
+ + BASS + + 4
+ 6 +
+ + 5
+ 1 +
+ + 5
+ 2 +
+ + 4
+ 2 +
+ + 0
+ 1 +
+ + 5
+ 3 +
+ + 5
+ 5 +
+ + 5
+ 6 +
+ + 3
+ 1 +
+ + 3
+ 5 +
+ + 5
+ 4 +
+ + 4
+ 1 +
+ + 3
+ 4 +
+ + 2
+ 2 +
+ + 4
+ 5 +
+ + 3
+ 2 +
+ + 4
+ 3 +
+ + 4
+ 4 +
+
+ + BAP + + 66
+ 2 +
+ + 44
+ 13 +
+ + 10
+ 1 +
+ + 89
+ 2 +
+ + 70
+ 11 +
+ + 14
+ 11 +
+ + 81
+ 1 +
+ + 54
+ 4 +
+ + 23
+ 6 +
+ + 17
+ 8 +
+ + 38
+ 5 +
+ + 36
+ 7 +
+ + 44
+ 9 +
+ + 89
+ 13 +
+ + 53
+ 1 +
+ + 13
+ 15 +
+ + 60
+ 4 +
+ + 54
+ 12 +
+ + 7
+ 8 +
+ + 89
+ 5 +
+ + 38
+ 9 +
+ + 38
+ 4 +
+ + 14
+ 13 +
+ + 20
+ 4 +
+ + 46
+ 2 +
+ + 69
+ 5 +
+ + 68
+ 11 +
+ + 69
+ 11 +
+ + 55
+ 6 +
+ + 33a
+ 7 +
+ + 9a
+ 6 +
+ + 84
+ 1 +
+ + 38
+ 11 +
+ + 22
+ 8 +
+ + 68
+ 6 +
+ + 90
+ 6 +
+ + 39
+ 4 +
+ + 21
+ 9 +
+ + 39
+ 12 +
+ + 32
+ 5 +
+ + 55
+ 11 +
+ + 90
+ 1 +
+ + 14
+ 8 +
+ + 90
+ 4 +
+ + 88
+ 3 +
+ + 23
+ 10 +
+ + 56
+ 14 +
+ + 54
+ 11 +
+ + 10
+ 5 +
+ + 32
+ 1 +
+ + 16
+ 8 +
+ + 15
+ 15 +
+ + 11
+ 1 +
+ + 69
+ 16 +
+ + 69
+ 9 +
+ + 14
+ 15 +
+ + 14
+ 10 +
+ + 54
+ 17 +
+ + 1
+ 4 +
+ + 20
+ 1 +
+ + 41
+ 8 +
+ + 82
+ 1 +
+ + 56
+ 10 +
+ + 91
+ 1 +
+ + 91
+ 3 +
+ + 69
+ 8 +
+ + 39
+ 10 +
+ + 12
+ 7 +
+ + 40
+ 5 +
+ + 37
+ 1 +
+ + 43
+ 1 +
+ + 51
+ 4 +
+ + 1
+ 5 +
+ + 65
+ 5 +
+ + 17
+ 12 +
+ + 55
+ 5 +
+ + 59
+ 6 +
+ + 7
+ 7 +
+ + 46
+ 6 +
+ + 21
+ 12 +
+ + 20
+ 9 +
+ + 40
+ 2 +
+ + 73
+ 9 +
+ + 36
+ 1 +
+ + 13
+ 8 +
+ + 21
+ 8 +
+ + 25
+ 2 +
+ + 39
+ 9 +
+ + 40
+ 9 +
+ + 7
+ 10 +
+ + 74
+ 4 +
+ + 45
+ 6 +
+ + 90
+ 2 +
+ + 12
+ 13 +
+ + 45
+ 2 +
+ + 46
+ 9 +
+ + 12
+ 16 +
+ + 15
+ 13 +
+ + 73
+ 2 +
+ + 54
+ 1 +
+ + 41
+ 3 +
+ + 39
+ 3 +
+ + 17
+ 2 +
+ + 6
+ 4 +
+ + 22
+ 5 +
+ + 87
+ 2 +
+ + 52
+ 3 +
+ + 22
+ 2 +
+ + 55
+ 10 +
+ + 16
+ 15 +
+ + 29
+ 1 +
+ + 21
+ 11 +
+ + 1
+ 3 +
+ + 30
+ 3 +
+ + 36
+ 6 +
+ + 60
+ 1 +
+ + 21
+ 2 +
+ + 39
+ 16 +
+ + 36
+ 12 +
+ + 69
+ 10 +
+ + 17
+ 6 +
+ + 39
+ 7 +
+ + 24
+ 3 +
+ + 56
+ 5 +
+ + 25
+ 3 +
+ + 36
+ 17 +
+ + 16
+ 3 +
+ + 16
+ 14 +
+ + 51
+ 1 +
+ + 41
+ 13 +
+ + 23
+ 7 +
+ + 56
+ 1 +
+ + 37
+ 7 +
+ + 77
+ 1 +
+ + 41
+ 16 +
+ + 44
+ 8 +
+ + 13
+ 16 +
+ + 36
+ 5 +
+ + 22
+ 4 +
+ + 32
+ 7 +
+ + 69
+ 13 +
+ + 21
+ 7 +
+ + 89
+ 9 +
+ + 76
+ 3 +
+ + 17
+ 9 +
+ + 61
+ 1 +
+ + 7
+ 9 +
+ + 8
+ 2 +
+ + 31
+ 5 +
+ + 58
+ 3 +
+ + 69
+ 12 +
+ + 41
+ 4 +
+ + 15
+ 8 +
+ + 72
+ 3 +
+ + 9
+ 1 +
+ + 40
+ 6 +
+ + 9
+ 3 +
+ + 32
+ 10 +
+ + 33
+ 6 +
+ + 30
+ 1 +
+ + 80
+ 1 +
+ + 74
+ 2 +
+ + 38
+ 6 +
+ + 59
+ 12 +
+ + 38
+ 13 +
+ + 40
+ 15 +
+ + 15
+ 2 +
+ + 13
+ 5 +
+ + 52
+ 1 +
+ + 11
+ 3 +
+ + 15
+ 12 +
+ + 87
+ 1 +
+ + 12
+ 9 +
+ + 88
+ 7 +
+ + 21
+ 4 +
+ + 92
+ 7 +
+ + 56
+ 6 +
+ + 16
+ 4 +
+ + 12
+ 5 +
+ + 12
+ 11 +
+ + 16
+ 6 +
+ + 44
+ 1 +
+ + 34
+ 4 +
+ + 13
+ 7 +
+ + 56
+ 16 +
+ + 70
+ 12 +
+ + 61
+ 3 +
+ + 14
+ 2 +
+ + 36
+ 11 +
+ + 36
+ 8 +
+ + 14
+ 9 +
+ + 9
+ 4 +
+ + 33a
+ 8 +
+ + 47
+ 3 +
+ + 73
+ 12 +
+ + 33
+ 4 +
+ + 55
+ 8 +
+ + 73
+ 6 +
+ + 33a
+ 4 +
+ + 45
+ 11 +
+ + 62
+ 1 +
+ + 32
+ 3 +
+ + 38
+ 8 +
+ + 68
+ 8 +
+ + 45
+ 9 +
+ + 74
+ 6 +
+ + 56
+ 9 +
+ + 13
+ 2 +
+ + 55
+ 1 +
+ + 36
+ 10 +
+ + 45
+ 4 +
+ + 52
+ 5 +
+ + 15
+ 14 +
+ + 40
+ 4 +
+ + 82
+ 2 +
+ + 68
+ 7 +
+ + 44
+ 4 +
+ + 54
+ 13 +
+ + 37
+ 9 +
+ + 56
+ 11 +
+ + 16
+ 16 +
+ + 74
+ 9 +
+ + 44
+ 10 +
+ + 33
+ 1 +
+ + 70
+ 5 +
+ + 45
+ 8 +
+ + 55
+ 15 +
+ + 36
+ 2 +
+ + 65
+ 3 +
+ + 55
+ 4 +
+ + 69
+ 15 +
+ + 9
+ 6 +
+ + 70
+ 8 +
+ + 54
+ 14 +
+ + 74
+ 8 +
+ + 22
+ 9 +
+ + 88
+ 5 +
+ + 68
+ 5 +
+ + 76
+ 4 +
+ + 39
+ 13 +
+ + 37
+ 17 +
+ + 75
+ 1 +
+ + 16
+ 5 +
+ + 56
+ 2 +
+ + 74
+ 15 +
+ + 33
+ 3 +
+ + 12
+ 12 +
+ + 36
+ 13 +
+ + 16
+ 7 +
+ + 37
+ 4 +
+ + 22
+ 1 +
+ + 37
+ 15 +
+ + 22
+ 3 +
+ + 37
+ 2 +
+ + 59
+ 1 +
+ + 89
+ 1 +
+ + 32
+ 9 +
+ + 48
+ 1 +
+ + 92
+ 3 +
+ + 27
+ 4 +
+ + 54
+ 3 +
+ + 54
+ 7 +
+ + 17
+ 5 +
+ + 40
+ 14 +
+ + 55
+ 12 +
+ + 80
+ 5 +
+ + 59
+ 10 +
+ + 39
+ 6 +
+ + 9
+ 8 +
+ + 73
+ 3 +
+ + 50
+ 1 +
+ + 70
+ 6 +
+ + 40
+ 8 +
+ + 22
+ 7 +
+ + 12
+ 17 +
+ + 86
+ 1 +
+ + 44
+ 5 +
+ + 80
+ 10 +
+ + 38
+ 7 +
+ + 17
+ 13 +
+ + 39
+ 14 +
+ + 40
+ 1 +
+ + 24
+ 1 +
+ + 41
+ 6 +
+ + 34
+ 5 +
+ + 45
+ 3 +
+ + 60
+ 2 +
+ + 37
+ 11 +
+ + 41
+ 14 +
+ + 86
+ 4 +
+ + 67
+ 3 +
+ + 9a
+ 4 +
+ + 33a
+ 5 +
+ + 53
+ 2 +
+ + 89
+ 11 +
+ + 1
+ 6 +
+ + 59
+ 8 +
+ + 5
+ 3 +
+ + 39
+ 5 +
+ + 74
+ 3 +
+ + 7
+ 3 +
+ + 88
+ 4 +
+ + 55
+ 16 +
+ + 46
+ 4 +
+ + 69
+ 4 +
+ + 12
+ 1 +
+ + 28
+ 2 +
+ + 13
+ 10 +
+ + 16
+ 9 +
+ + 21
+ 1 +
+ + 78
+ 1 +
+ + 12
+ 14 +
+ + 20
+ 5 +
+ + 86
+ 3 +
+ + 69
+ 14 +
+ + 12
+ 4 +
+ + 23
+ 4 +
+ + 56
+ 8 +
+ + 38
+ 14 +
+ + 20
+ 11 +
+ + 68
+ 17 +
+ + 37
+ 16 +
+ + 45
+ 13 +
+ + 26
+ 1 +
+ + 32
+ 6 +
+ + 15
+ 11 +
+ + 61
+ 5 +
+ + 40
+ 12 +
+ + 37
+ 10 +
+ + 39
+ 11 +
+ + 14
+ 16 +
+ + 89
+ 3 +
+ + 41
+ 9 +
+ + 37
+ 6 +
+ + 80
+ 6 +
+ + 80
+ 2 +
+ + 9a
+ 1 +
+ + 59
+ 3 +
+ + 17
+ 10 +
+ + 54
+ 16 +
+ + 74
+ 11 +
+ + 81
+ 3 +
+ + 14
+ 7 +
+ + 9a
+ 2 +
+ + 48
+ 2 +
+ + 44
+ 7 +
+ + 41
+ 1 +
+ + 33
+ 8 +
+ + 20
+ 7 +
+ + 12
+ 10 +
+ + 44
+ 14 +
+ + 89
+ 10 +
+ + 22
+ 12 +
+ + 73
+ 4 +
+ + 51
+ 2 +
+ + 87
+ 3 +
+ + 41
+ 11 +
+ + 15
+ 16 +
+ + 54
+ 9 +
+ + 31
+ 6 +
+ + 33a
+ 3 +
+ + 75
+ 3 +
+ + 72
+ 1 +
+ + 66
+ 1 +
+ + 45
+ 10 +
+ + 58
+ 2 +
+ + 23
+ 1 +
+ + 14
+ 4 +
+ + 73
+ 5 +
+ + 28
+ 4 +
+ + 17
+ 15 +
+ + 38
+ 16 +
+ + 36
+ 4 +
+ + 68
+ 14 +
+ + 34
+ 3 +
+ + 9
+ 2 +
+ + 12
+ 3 +
+ + 76
+ 1 +
+ + 37
+ 12 +
+ + 59
+ 9 +
+ + 33a
+ 6 +
+ + 34
+ 1 +
+ + 37
+ 5 +
+ + 71
+ 1 +
+ + 54
+ 15 +
+ + 16
+ 12 +
+ + 34
+ 2 +
+ + 6
+ 2 +
+ + 65
+ 4 +
+ + 51
+ 5 +
+ + 68
+ 2 +
+ + 31
+ 3 +
+ + 70
+ 9 +
+ + 21
+ 10 +
+ + 31
+ 1 +
+ + 20
+ 2 +
+ + 1
+ 2 +
+ + 7
+ 5 +
+ + 55
+ 2 +
+ + 90
+ 3 +
+ + 65
+ 2 +
+ + 46
+ 5 +
+ + 76
+ 2 +
+ + 20
+ 3 +
+ + 21
+ 6 +
+ + 88
+ 6 +
+ + 54
+ 2 +
+ + 89
+ 8 +
+ + 13
+ 6 +
+ + 16
+ 10 +
+ + 89
+ 12 +
+ + 22
+ 11 +
+ + 68
+ 13 +
+ + 45
+ 12 +
+ + 73
+ 7 +
+ + 46
+ 3 +
+ + 90
+ 5 +
+ + 92
+ 1 +
+ + 25
+ 1 +
+ + 17
+ 1 +
+ + 7
+ 4 +
+ + 70
+ 16 +
+ + 39
+ 2 +
+ + 73
+ 8 +
+ + 7
+ 1 +
+ + 52
+ 2 +
+ + 14
+ 6 +
+ + 33a
+ 1 +
+ + 12
+ 15 +
+ + 14
+ 5 +
+ + 13
+ 1 +
+ + 64
+ 2 +
+ + 16
+ 13 +
+ + 70
+ 15 +
+ + 31
+ 2 +
+ + 59
+ 7 +
+ + 85
+ 4 +
+ + 9a
+ 3 +
+ + 33a
+ 2 +
+ + 36
+ 15 +
+ + 32
+ 2 +
+ + 19
+ 1 +
+ + 36
+ 14 +
+ + 15
+ 5 +
+ + 22
+ 10 +
+ + 83
+ 1 +
+ + 56
+ 13 +
+ + 12
+ 8 +
+ + 8
+ 1 +
+ + 33
+ 2 +
+ + 48
+ 3 +
+ + 59
+ 5 +
+ + 69
+ 7 +
+ + 13
+ 13 +
+ + 74
+ 1 +
+ + 37
+ 13 +
+ + 89
+ 7 +
+ + 20
+ 8 +
+ + 69
+ 2 +
+ + 13
+ 11 +
+ + 33
+ 5 +
+ + 16
+ 1 +
+ + 70
+ 2 +
+ + 7
+ 6 +
+ + 23
+ 5 +
+ + 57
+ 1 +
+ + 40
+ 16 +
+ + 44
+ 15 +
+ + 20
+ 6 +
+ + 15
+ 10 +
+ + 47
+ 1 +
+ + 15
+ 3 +
+ + 72
+ 2 +
+ + 35
+ 2 +
+ + 13
+ 14 +
+ + 14
+ 12 +
+ + 33
+ 7 +
+ + 13
+ 12 +
+ + 65
+ 1 +
+ + 21
+ 5 +
+ + 40
+ 3 +
+ + 85
+ 2 +
+ + 90
+ 11 +
+ + 41
+ 12 +
+ + 59
+ 4 +
+ + 68
+ 1 +
+ + 56
+ 12 +
+ + 73
+ 11 +
+ + 37
+ 3 +
+ + 54
+ 6 +
+ + 92
+ 2 +
+ + 59
+ 11 +
+ + 10
+ 3 +
+ + 60
+ 3 +
+ + 45
+ 7 +
+ + 27
+ 2 +
+ + 69
+ 3 +
+ + 44
+ 11 +
+ + 45
+ 14 +
+ + 73
+ 10 +
+ + 87
+ 4 +
+ + 74
+ 10 +
+ + 44
+ 16 +
+ + 70
+ 1 +
+ + 74
+ 7 +
+ + 54
+ 8 +
+ + 40
+ 11 +
+ + 68
+ 3 +
+ + 11
+ 2 +
+ + 12
+ 2 +
+ + 21
+ 3 +
+ + 38
+ 3 +
+ + 80
+ 3 +
+ + 51
+ 3 +
+ + 70
+ 3 +
+ + 54
+ 5 +
+ + 61
+ 2 +
+ + 13
+ 17 +
+ + 40
+ 13 +
+ + 38
+ 2 +
+ + 61
+ 6 +
+ + 61
+ 4 +
+ + 16
+ 11 +
+ + 5
+ 1 +
+ + 80
+ 7 +
+ + 86
+ 2 +
+ + 12
+ 6 +
+ + 15
+ 4 +
+ + 68
+ 16 +
+ + 31
+ 7 +
+ + 41
+ 10 +
+ + 63
+ 1 +
+ + 14
+ 3 +
+ + 88
+ 1 +
+ + 56
+ 3 +
+ + 7
+ 2 +
+ + 15
+ 6 +
+ + 88
+ 2 +
+ + 15
+ 9 +
+ + 45
+ 1 +
+ + 17
+ 11 +
+ + 70
+ 7 +
+ + 17
+ 3 +
+ + 32
+ 4 +
+ + 17
+ 16 +
+ + 3
+ 1 +
+ + 13
+ 9 +
+ + 15
+ 7 +
+ + 56
+ 15 +
+ + 9a
+ 5 +
+ + 14
+ 1 +
+ + 14
+ 14 +
+ + 36
+ 9 +
+ + 37
+ 8 +
+ + 35
+ 1 +
+ + 68
+ 10 +
+ + 41
+ 5 +
+ + 68
+ 12 +
+ + 15
+ 1 +
+ + 69
+ 6 +
+ + 17
+ 7 +
+ + 69
+ 1 +
+ + 10
+ 2 +
+ + 36
+ 16 +
+ + 68
+ 9 +
+ + 40
+ 10 +
+ + 22
+ 6 +
+ + 44
+ 3 +
+ + 54
+ 10 +
+ + 56
+ 4 +
+ + 49
+ 1 +
+ + 37
+ 14 +
+ + 23
+ 2 +
+ + 44
+ 12 +
+ + 45
+ 5 +
+ + 68
+ 4 +
+ + 67
+ 1 +
+ + 38
+ 10 +
+ + 10
+ 4 +
+ + 38
+ 12 +
+ + 68
+ 15 +
+ + 70
+ 14 +
+ + 55
+ 14 +
+ + 4
+ 1 +
+ + 9a
+ 7 +
+ + 38
+ 1 +
+ + 9a
+ 8 +
+ + 1
+ 1 +
+ + 70
+ 13 +
+ + 39
+ 8 +
+ + 20
+ 10 +
+ + 70
+ 4 +
+ + 58
+ 1 +
+ + 67
+ 2 +
+ + 41
+ 15 +
+ + 55
+ 13 +
+ + 73
+ 1 +
+ + 82
+ 3 +
+ + 52
+ 4 +
+ + 32
+ 8 +
+ + 44
+ 2 +
+ + 13
+ 3 +
+ + 46
+ 1 +
+ + 55
+ 7 +
+ + 40
+ 7 +
+ + 90
+ 8 +
+ + 44
+ 6 +
+ + 42
+ 1 +
+ + 9
+ 7 +
+ + 36
+ 3 +
+ + 55
+ 3 +
+ + 30
+ 2 +
+ + 89
+ 6 +
+ + 59
+ 2 +
+ + 9
+ 5 +
+ + 39
+ 15 +
+ + 39
+ 1 +
+ + 55
+ 9 +
+ + 31
+ 4 +
+ + 17
+ 14 +
+ + 90
+ 7 +
+ + 70
+ 10 +
+ + 51
+ 6 +
+ + 38
+ 15 +
+ + 79
+ 2 +
+ + 17
+ 4 +
+ + 13
+ 4 +
+ + 18
+ 1 +
+ + 16
+ 2 +
+ + 41
+ 2 +
+ + 89
+ 4 +
+ + 41
+ 7 +
+ + 29
+ 2 +
+ + 56
+ 7 +
+
+ + CAS + + 2
+ 2 +
+ + 0
+ 1 +
+ + 3
+ 1 +
+
+ + CAP + + 16
+ 5 +
+ + 11
+ 11 +
+ + 22
+ 1 +
+ + 1
+ 1 +
+ + 8
+ 3 +
+ + 7
+ 1 +
+ + 18
+ 2 +
+ + 12
+ 1 +
+ + 2
+ 2 +
+ + 16
+ 2 +
+ + 19
+ 2 +
+ + 20
+ 3 +
+ + 6
+ 1 +
+ + 6
+ 7 +
+ + 7
+ 6 +
+ + 22
+ 8 +
+ + 19
+ 1 +
+ + 17
+ 2 +
+ + 6a
+ 2 +
+ + 20
+ 5 +
+ + 23
+ 2 +
+ + 7
+ 9 +
+ + 4
+ 1 +
+ + 11
+ 7 +
+ + 10
+ 1 +
+ + 13
+ 1 +
+ + 20
+ 2 +
+ + 13
+ 2 +
+ + 7
+ 4 +
+ + 22
+ 2 +
+ + 7
+ 8 +
+ + 11
+ 5 +
+ + 22
+ 7 +
+ + 21
+ 3 +
+ + 22
+ 4 +
+ + 9
+ 1 +
+ + 14
+ 1 +
+ + 11
+ 10 +
+ + 18
+ 1 +
+ + 8
+ 2 +
+ + 1
+ 2 +
+ + 6
+ 4 +
+ + 22
+ 12 +
+ + 22
+ 11 +
+ + 11
+ 8 +
+ + 3
+ 1 +
+ + 22
+ 9 +
+ + 20
+ 1 +
+ + 16
+ 1 +
+ + 7
+ 3 +
+ + 10
+ 2 +
+ + 22
+ 3 +
+ + 21
+ 2 +
+ + 7
+ 2 +
+ + 6
+ 6 +
+ + 16
+ 4 +
+ + 6
+ 8 +
+ + 23
+ 1 +
+ + 11
+ 2 +
+ + 8
+ 1 +
+ + 6
+ 5 +
+ + 11
+ 3 +
+ + 6
+ 3 +
+ + 11
+ 6 +
+ + 6a
+ 1 +
+ + 22
+ 5 +
+ + 20
+ 4 +
+ + 7
+ 7 +
+ + 22
+ 10 +
+ + 8
+ 4 +
+ + 20
+ 9 +
+ + 22
+ 6 +
+ + 17
+ 5 +
+ + 20
+ 6 +
+ + 7
+ 5 +
+ + 21
+ 1 +
+ + 16
+ 6 +
+ + 11
+ 9 +
+ + 11
+ 12 +
+ + 11
+ 1 +
+ + 16
+ 3 +
+ + 19
+ 4 +
+ + 11
+ 4 +
+ + 17
+ 1 +
+ + 6
+ 2 +
+
+ + HAS + + 5
+ 4 +
+ + 4
+ 10 +
+ + 4
+ 8 +
+ + 4
+ 2 +
+ + 4
+ 3 +
+ + 5
+ 1 +
+ + 4
+ 1 +
+ + 3
+ 7 +
+ + 3
+ 12 +
+ + 4
+ 7 +
+ + 3
+ 14 +
+ + 3
+ 11 +
+ + 5
+ 2 +
+ + 2
+ 2 +
+ + 5
+ 6 +
+ + 3
+ 5 +
+ + 3
+ 4 +
+ + 5
+ 3 +
+ + 3
+ 2 +
+ + 4
+ 4 +
+ + 4
+ 5 +
+ + 5
+ 5 +
+ + 3
+ 6 +
+ + 0
+ 1 +
+ + 3
+ 9 +
+ + 3
+ 10 +
+ + 3
+ 1 +
+ + 3
+ 13 +
+ + 3
+ 8 +
+ + 4
+ 9 +
+ + 3
+ 3 +
+ + 3
+ 1a +
+ + 4
+ 6 +
+
+ + HAP + + 12
+ 5 +
+ + 10
+ 1 +
+ + 92
+ 1 +
+ + 50
+ 1 +
+ + 24
+ 5 +
+ + 14
+ 3 +
+ + 51
+ 1 +
+ + 13
+ 4 +
+ + 43
+ 2 +
+ + 1
+ 2 +
+ + 12
+ 7 +
+ + 90
+ 1 +
+ + 24
+ 2 +
+ + 50
+ 2 +
+ + 12
+ 3 +
+ + 24
+ 3 +
+ + 13
+ 6 +
+ + 26
+ 1 +
+ + 43
+ 3 +
+ + 40
+ 1 +
+ + 13
+ 2 +
+ + 13
+ 1 +
+ + 18
+ 1 +
+ + 12
+ 6 +
+ + 16
+ 2 +
+ + 46
+ 2 +
+ + 16
+ 1 +
+ + 1
+ 1 +
+ + 14
+ 2 +
+ + 43
+ 4 +
+ + 13
+ 3 +
+ + 12
+ 2 +
+ + 19
+ 1 +
+ + 24
+ 1 +
+ + 12
+ 1 +
+ + 24
+ 4 +
+ + 14
+ 1 +
+ + 1
+ 4 +
+ + 19
+ 2 +
+ + 17
+ 1 +
+ + 25
+ 1 +
+ + 13
+ 5 +
+ + 43
+ 1 +
+ + 2
+ 2 +
+ + 46
+ 1 +
+ + 12
+ 4 +
+
+ + TMAP + + 131
+ 2 +
+ + 95
+ 5 +
+ + 114
+ 4 +
+ + 52
+ 2 +
+ + 1
+ 7 +
+ + 57
+ 3 +
+ + 56
+ 12 +
+ + 56
+ 14 +
+ + 79
+ 1 +
+ + 79
+ 2 +
+ + 153
+ 6 +
+ + 57
+ 2 +
+ + 95
+ 7 +
+ + 76
+ 3 +
+ + 116
+ 12 +
+ + 95
+ 3 +
+ + 115
+ 3 +
+ + 96
+ 15 +
+ + 56
+ 1 +
+ + 116
+ 4 +
+ + 116
+ 5 +
+ + 56
+ 5 +
+ + 78
+ 1 +
+ + 1
+ 8 +
+ + 116
+ 11 +
+ + 70
+ 1 +
+ + 96
+ 16 +
+ + 118
+ 2 +
+ + 76
+ 5 +
+ + 1
+ 2 +
+ + 93
+ 1 +
+ + 55
+ 3 +
+ + 95
+ 8 +
+ + 113
+ 1 +
+ + 96
+ 12 +
+ + 99
+ 2 +
+ + 96
+ 7 +
+ + 94
+ 1 +
+ + 151
+ 3 +
+ + 98
+ 3 +
+ + 116
+ 9 +
+ + 2
+ 2 +
+ + 150
+ 1 +
+ + 153
+ 4 +
+ + 116
+ 1 +
+ + 96
+ 2 +
+ + 116
+ 13 +
+ + 75
+ 3 +
+ + 115
+ 5 +
+ + 55
+ 5 +
+ + 116
+ 6 +
+ + 153
+ 5 +
+ + 57
+ 1 +
+ + 112
+ 1 +
+ + 1
+ 4 +
+ + 97
+ 1 +
+ + 116
+ 7 +
+ + 96
+ 13 +
+ + 56
+ 9 +
+ + 115
+ 1 +
+ + 151
+ 6 +
+ + 56
+ 6 +
+ + 55
+ 4 +
+ + 78
+ 3 +
+ + 76
+ 6 +
+ + 100
+ 2 +
+ + 110
+ 1 +
+ + 98
+ 2 +
+ + 56
+ 4 +
+ + 76
+ 4 +
+ + 95
+ 4 +
+ + 118
+ 3 +
+ + 116
+ 2 +
+ + 116
+ 15 +
+ + 75
+ 1 +
+ + 114
+ 1 +
+ + 55
+ 8 +
+ + 56
+ 3 +
+ + 75
+ 4 +
+ + 74
+ 3 +
+ + 94
+ 4 +
+ + 151
+ 1 +
+ + 119
+ 1 +
+ + 1
+ 6 +
+ + 116
+ 16 +
+ + 95
+ 2 +
+ + 56
+ 7 +
+ + 77
+ 1 +
+ + 54
+ 3 +
+ + 97
+ 2 +
+ + 54
+ 1 +
+ + 115
+ 4 +
+ + 53
+ 1 +
+ + 117
+ 1 +
+ + 76
+ 2 +
+ + 78
+ 2 +
+ + 96
+ 6 +
+ + 131
+ 1 +
+ + 156
+ 1 +
+ + 120
+ 1 +
+ + 152
+ 1 +
+ + 1
+ 5 +
+ + 74
+ 5 +
+ + 115
+ 2 +
+ + 96
+ 1 +
+ + 96
+ 3 +
+ + 75
+ 2 +
+ + 115
+ 6 +
+ + 154
+ 1 +
+ + 114
+ 3 +
+ + 118
+ 1 +
+ + 96
+ 4 +
+ + 56
+ 10 +
+ + 55
+ 6 +
+ + 52
+ 1 +
+ + 75
+ 5 +
+ + 56
+ 11 +
+ + 96
+ 10 +
+ + 94
+ 3 +
+ + 56
+ 16 +
+ + 72
+ 2 +
+ + 117
+ 2 +
+ + 72
+ 1 +
+ + 116
+ 3 +
+ + 116
+ 14 +
+ + 116
+ 8 +
+ + 116
+ 10 +
+ + 96
+ 14 +
+ + 56
+ 13 +
+ + 56
+ 15 +
+ + 75
+ 6 +
+ + 121
+ 2 +
+ + 77
+ 2 +
+ + 3
+ 1 +
+ + 96
+ 8 +
+ + 98
+ 1 +
+ + 115
+ 8 +
+ + 96
+ 9 +
+ + 95
+ 1 +
+ + 115
+ 7 +
+ + 92
+ 2 +
+ + 96
+ 11 +
+ + 100
+ 1 +
+ + 121
+ 1 +
+ + 76
+ 1 +
+ + 99
+ 1 +
+ + 55
+ 2 +
+ + 153
+ 2 +
+ + 74
+ 4 +
+ + 119
+ 2 +
+ + 90
+ 1 +
+ + 112
+ 2 +
+ + 56
+ 8 +
+ + 56
+ 2 +
+ + 50
+ 1 +
+ + 74
+ 1 +
+ + 96
+ 5 +
+ + 55
+ 7 +
+ + 151
+ 5 +
+ + 92
+ 1 +
+ + 151
+ 4 +
+ + 151
+ 2 +
+ + 55
+ 1 +
+ + 95
+ 6 +
+
+
\ No newline at end of file From 4b8c0559d6759b7b28ab8443d42dfbfd6c2fa3d8 Mon Sep 17 00:00:00 2001 From: Aymeric Aillet Date: Thu, 11 Jan 2024 15:46:52 +0100 Subject: [PATCH 3051/3723] dts: arm: renesas: Move rz dtsi to range folder Create a folder for RZ Renesas range device tree to follow how it's done for other renesas ranges. It will also help to better delimit areas to maintain. Signed-off-by: Aymeric Aillet --- boards/arm/rzt2m_starterkit/rzt2m_starter_kit.dts | 2 +- dts/arm/renesas/{ => rz}/rzt2m.dtsi | 0 2 files changed, 1 insertion(+), 1 deletion(-) rename dts/arm/renesas/{ => rz}/rzt2m.dtsi (100%) diff --git a/boards/arm/rzt2m_starterkit/rzt2m_starter_kit.dts b/boards/arm/rzt2m_starterkit/rzt2m_starter_kit.dts index 2568a542b5e..6b87455aafe 100644 --- a/boards/arm/rzt2m_starterkit/rzt2m_starter_kit.dts +++ b/boards/arm/rzt2m_starterkit/rzt2m_starter_kit.dts @@ -6,7 +6,7 @@ /dts-v1/; #include -#include +#include / { model = "RZT/2M Starter Kit"; diff --git a/dts/arm/renesas/rzt2m.dtsi b/dts/arm/renesas/rz/rzt2m.dtsi similarity index 100% rename from dts/arm/renesas/rzt2m.dtsi rename to dts/arm/renesas/rz/rzt2m.dtsi From 3c1ad2eb9f3869de922861540aeebd0a2fe70ace Mon Sep 17 00:00:00 2001 From: Aymeric Aillet Date: Thu, 11 Jan 2024 16:07:12 +0100 Subject: [PATCH 3052/3723] MAINTAINERS: Update Renesas ranges area delimitations Create RA & RZ Renesas areas to maintain from previous "Renesas platforms" area. Moved rzt2m dtsi from R-Car to RZ area. Add @soburi as Renesas RA maintainer. Signed-off-by: Aymeric Aillet --- MAINTAINERS.yml | 32 +++++++++++++++++++++++++++----- 1 file changed, 27 insertions(+), 5 deletions(-) diff --git a/MAINTAINERS.yml b/MAINTAINERS.yml index 1dd2be5fa25..5a8a4cf15fc 100644 --- a/MAINTAINERS.yml +++ b/MAINTAINERS.yml @@ -3401,14 +3401,37 @@ Renesas SmartBond Platforms: Renesas SmartBond SOCs, dts files, and related drivers. Renesas boards based on SmartBond SoCs. -Renesas Platforms: - status: odd fixes +Renesas RA Platforms: + status: maintained + maintainers: + - soburi files: - - soc/arm/renesas_ra/ + - boards/arm/arduino_uno_r4/ + - drivers/*/*renesas_ra* - dts/arm/renesas/ra/ + - dts/bindings/*/*renesas,ra* + - soc/arm/renesas_ra/ + labels: + - "platforms: Renesas RA" + description: >- + Renesas RA SOCs, dts files, and related drivers. Boards based + on Renesas RA SoCs. + +Renesas RZ Platforms: + status: maintained + maintainers: + - tgorochowik + files: + - boards/arm/rzt2m_*/ + - drivers/*/*rzt2m* + - dts/arm/renesas/rz/ + - dts/bindings/*/*rzt2m* - soc/arm/renesas_rzt2m/ labels: - - "platforms: Renesas" + - "platforms: Renesas RZ" + description: >- + Renesas RZ SOCs, dts files, and related drivers. Renesas boards based + on RZ SoCs. Renesas R-Car Platforms: status: maintained @@ -3428,7 +3451,6 @@ Renesas R-Car Platforms: - dts/bindings/*/*rcar* - soc/arm/renesas_rcar/ - soc/arm64/renesas_rcar/ - - dts/arm/renesas/rzt2m.dtsi labels: - "platform: Renesas R-Car" description: >- From ffb581a5529735fe882bb6dd37955ffe3c9b4c88 Mon Sep 17 00:00:00 2001 From: Guillaume Gautier Date: Fri, 26 Jan 2024 10:05:39 +0100 Subject: [PATCH 3053/3723] drivers: counter: stm32 rtc: add basic pm support Add basic PM support for STM32 RTC counter. It is useful for Suspend to RAM support to reenable the RTC register clock after wakeup from Standby. Signed-off-by: Guillaume Gautier --- drivers/counter/counter_ll_stm32_rtc.c | 29 +++++++++++++++++++++++++- 1 file changed, 28 insertions(+), 1 deletion(-) diff --git a/drivers/counter/counter_ll_stm32_rtc.c b/drivers/counter/counter_ll_stm32_rtc.c index 76114cab386..317bd367391 100644 --- a/drivers/counter/counter_ll_stm32_rtc.c +++ b/drivers/counter/counter_ll_stm32_rtc.c @@ -24,6 +24,7 @@ #include #include #include +#include #include #include @@ -648,6 +649,30 @@ static const struct rtc_stm32_config rtc_config = { .pclken = rtc_clk, }; +#ifdef CONFIG_PM_DEVICE +static int rtc_stm32_pm_action(const struct device *dev, + enum pm_device_action action) +{ + const struct device *const clk = DEVICE_DT_GET(STM32_CLOCK_CONTROL_NODE); + const struct rtc_stm32_config *cfg = dev->config; + + switch (action) { + case PM_DEVICE_ACTION_RESUME: + /* Enable RTC bus clock */ + if (clock_control_on(clk, (clock_control_subsys_t) &cfg->pclken[0]) != 0) { + LOG_ERR("clock op failed\n"); + return -EIO; + } + break; + case PM_DEVICE_ACTION_SUSPEND: + break; + default: + return -ENOTSUP; + } + + return 0; +} +#endif /* CONFIG_PM_DEVICE */ static const struct counter_driver_api rtc_stm32_driver_api = { .start = rtc_stm32_start, @@ -663,7 +688,9 @@ static const struct counter_driver_api rtc_stm32_driver_api = { .get_top_value = rtc_stm32_get_top_value, }; -DEVICE_DT_INST_DEFINE(0, &rtc_stm32_init, NULL, +PM_DEVICE_DT_INST_DEFINE(0, rtc_stm32_pm_action); + +DEVICE_DT_INST_DEFINE(0, &rtc_stm32_init, PM_DEVICE_DT_INST_GET(0), &rtc_data, &rtc_config, PRE_KERNEL_1, CONFIG_COUNTER_INIT_PRIORITY, &rtc_stm32_driver_api); From 8bb40bbb8e21914e2c64926e197002b97bf2b6e3 Mon Sep 17 00:00:00 2001 From: Oleksii Moisieiev Date: Fri, 29 Sep 2023 08:59:04 +0300 Subject: [PATCH 3054/3723] arm: aarch32: cortex_a_r: Add MMU_ALIGN define to Linker script cortex_a_r lacks of MMU_ALIGN definition. This define is added to the target linker script when CONFIG_NOCACHE_MEMORY is enabled which adds .nocache section where this define is used. Signed-off-by: Oleksii Moisieiev --- include/zephyr/arch/arm/cortex_a_r/scripts/linker.ld | 2 ++ 1 file changed, 2 insertions(+) diff --git a/include/zephyr/arch/arm/cortex_a_r/scripts/linker.ld b/include/zephyr/arch/arm/cortex_a_r/scripts/linker.ld index 48d0f1820c4..0514690689c 100644 --- a/include/zephyr/arch/arm/cortex_a_r/scripts/linker.ld +++ b/include/zephyr/arch/arm/cortex_a_r/scripts/linker.ld @@ -81,6 +81,8 @@ _region_min_align = 4; #define BSS_ALIGN ALIGN(_region_min_align) +#define MMU_ALIGN . = ALIGN(_region_min_align) + MEMORY { FLASH (rx) : ORIGIN = ROM_ADDR, LENGTH = ROM_SIZE From c9818d5eead2601c36d8d67d77f3e9c3a939bbee Mon Sep 17 00:00:00 2001 From: Yong Cong Sin Date: Tue, 30 Jan 2024 14:27:25 +0800 Subject: [PATCH 3055/3723] cmake: modules: generated_file_directories: fix paths The paths that got assigned to these variable don't quite match the description, likely a typo, fix that. Signed-off-by: Yong Cong Sin --- cmake/modules/generated_file_directories.cmake | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/cmake/modules/generated_file_directories.cmake b/cmake/modules/generated_file_directories.cmake index aac3b39a6f9..9b18e1794de 100644 --- a/cmake/modules/generated_file_directories.cmake +++ b/cmake/modules/generated_file_directories.cmake @@ -19,6 +19,6 @@ include_guard(GLOBAL) # Optional environment variables: # None -set(BINARY_DIR_INCLUDE ${PROJECT_BINARY_DIR}/include/generated) -set(BINARY_DIR_INCLUDE_GENERATED ${PROJECT_BINARY_DIR}/include/generated) +set(BINARY_DIR_INCLUDE ${PROJECT_BINARY_DIR}/include) +set(BINARY_DIR_INCLUDE_GENERATED ${BINARY_DIR_INCLUDE}/generated) file(MAKE_DIRECTORY ${BINARY_DIR_INCLUDE_GENERATED}) From 4d86be26c781a4e916587943a2e4a129600ae7cd Mon Sep 17 00:00:00 2001 From: Evgeniy Paltsev Date: Fri, 22 Dec 2023 00:01:44 +0000 Subject: [PATCH 3056/3723] ARC: ARCv3: enable HW prefetch on boot ARCv3 processors have HW prefetch feature which is disabled after reset. Let's enable it. Signed-off-by: Eugeniy Paltsev Signed-off-by: Evgeniy Paltsev --- arch/arc/core/reset.S | 10 ++++++++++ include/zephyr/arch/arc/v2/aux_regs.h | 7 +++++++ 2 files changed, 17 insertions(+) diff --git a/arch/arc/core/reset.S b/arch/arc/core/reset.S index 0894875dcac..a2b038d387e 100644 --- a/arch/arc/core/reset.S +++ b/arch/arc/core/reset.S @@ -151,6 +151,16 @@ done_mpu_regions_reset: #endif #endif +#ifdef CONFIG_ISA_ARCV3 + /* Enable HW prefetcher if exist */ + lr r0, [_ARC_HW_PF_BUILD] + breq r0, 0, hw_pf_setup_done + lr r1, [_ARC_HW_PF_CTRL] + or r1, r1, _ARC_HW_PF_CTRL_ENABLE + sr r1, [_ARC_HW_PF_CTRL] +hw_pf_setup_done: +#endif + #if defined(CONFIG_SMP) || CONFIG_MP_MAX_NUM_CPUS > 1 _get_cpu_id r0 breq r0, 0, _master_core_startup diff --git a/include/zephyr/arch/arc/v2/aux_regs.h b/include/zephyr/arch/arc/v2/aux_regs.h index a2b5d96d8d4..b5e90327177 100644 --- a/include/zephyr/arch/arc/v2/aux_regs.h +++ b/include/zephyr/arch/arc/v2/aux_regs.h @@ -15,6 +15,8 @@ #ifndef ZEPHYR_INCLUDE_ARCH_ARC_V2_AUX_REGS_H_ #define ZEPHYR_INCLUDE_ARCH_ARC_V2_AUX_REGS_H_ +#include + #define _ARC_V2_LP_START 0x002 #define _ARC_V2_LP_END 0x003 #define _ARC_V2_IDENTITY 0x004 @@ -173,6 +175,11 @@ #define _ARC_V2_AGU_MOD21 0x5f5 #define _ARC_V2_AGU_MOD22 0x5f6 #define _ARC_V2_AGU_MOD23 0x5f7 +#define _ARC_HW_PF_BUILD 0xf70 +#define _ARC_HW_PF_CTRL 0x4f + +/* _ARC_HW_PF_CTRL bits */ +#define _ARC_HW_PF_CTRL_ENABLE BIT(0) /* STATUS32/STATUS32_P0 bits */ #define _ARC_V2_STATUS32_H (1 << 0) From d2b5ac20d1adbb8141c61ba7af7315f395031e97 Mon Sep 17 00:00:00 2001 From: Evgeniy Paltsev Date: Fri, 24 Jun 2022 21:51:36 +0400 Subject: [PATCH 3057/3723] ARC: ARCv3: enable shared cache if available In case of ARCv3 we have shared cache disabled after reset (in ARCv2 it was enabled by default). Let's enable it at early boot phase (if it's available in HW). Signed-off-by: Eugeniy Paltsev Signed-off-by: Evgeniy Paltsev --- arch/arc/core/prep_c.c | 35 ++++++++++ include/zephyr/arch/arc/cluster.h | 106 ++++++++++++++++++++++++++++++ 2 files changed, 141 insertions(+) create mode 100644 include/zephyr/arch/arc/cluster.h diff --git a/arch/arc/core/prep_c.c b/arch/arc/core/prep_c.c index a3608717969..0e4975cd3fc 100644 --- a/arch/arc/core/prep_c.c +++ b/arch/arc/core/prep_c.c @@ -20,6 +20,7 @@ #include #include #include +#include #include #include @@ -66,6 +67,36 @@ static void invalidate_dcache(void) } #endif +#ifdef CONFIG_ISA_ARCV3 +/* NOTE: it will be called from early C code - we must NOT use global / static variables in it! */ +static void arc_cluster_scm_enable(void) +{ + unsigned int cluster_version; + + /* Check that we have cluster and its version is supported */ + cluster_version = z_arc_v2_aux_reg_read(_ARC_REG_CLN_BCR) & _ARC_CLN_BCR_VER_MAJOR_MASK; + if (cluster_version < _ARC_REG_CLN_BCR_VER_MAJOR_ARCV3_MIN) { + return; + } + + /* Check that we have shared cache in cluster */ + if (!(z_arc_v2_aux_reg_read(_ARC_CLNR_BCR_0) & _ARC_CLNR_BCR_0_HAS_SCM)) { + return; + } + + /* Disable SCM, just in case. */ + arc_cln_write_reg_nolock(ARC_CLN_CACHE_STATUS, 0); + + /* Invalidate SCM before enabling. */ + arc_cln_write_reg_nolock(ARC_CLN_CACHE_CMD, + ARC_CLN_CACHE_CMD_OP_REG_INV | ARC_CLN_CACHE_CMD_INCR); + while (arc_cln_read_reg_nolock(ARC_CLN_CACHE_STATUS) & ARC_CLN_CACHE_STATUS_BUSY) + ; + + arc_cln_write_reg_nolock(ARC_CLN_CACHE_STATUS, ARC_CLN_CACHE_STATUS_EN); +} +#endif /* CONFIG_ISA_ARCV3 */ + #ifdef __CCAC__ extern char __device_states_start[]; extern char __device_states_end[]; @@ -90,6 +121,10 @@ extern FUNC_NORETURN void z_cstart(void); void z_prep_c(void) { +#ifdef CONFIG_ISA_ARCV3 + arc_cluster_scm_enable(); +#endif + z_bss_zero(); #ifdef __CCAC__ dev_state_zero(); diff --git a/include/zephyr/arch/arc/cluster.h b/include/zephyr/arch/arc/cluster.h new file mode 100644 index 00000000000..8fb535be9ec --- /dev/null +++ b/include/zephyr/arch/arc/cluster.h @@ -0,0 +1,106 @@ +/* + * Copyright (c) 2023 Synopsys. + * + * SPDX-License-Identifier: Apache-2.0 + */ + +/** + * @file + * @brief ARC Cluster registers and accessors + */ + +#ifndef ZEPHYR_INCLUDE_ARCH_ARC_CLUSTER_H_ +#define ZEPHYR_INCLUDE_ARCH_ARC_CLUSTER_H_ + +#include +#include + +/* Cluster AUX */ +#define _ARC_REG_CLN_BCR 0xcf + +#define _ARC_CLNR_ADDR 0x640 /* CLN address for CLNR_DATA */ +#define _ARC_CLNR_DATA 0x641 /* CLN data indicated by CLNR_ADDR */ +#define _ARC_CLNR_DATA_NXT 0x642 /* CLNR_DATA and then CLNR_ADDR++ */ +#define _ARC_CLNR_BCR_0 0xF61 +#define _ARC_CLNR_BCR_1 0xF62 +#define _ARC_CLNR_BCR_2 0xF63 +#define _ARC_CLNR_SCM_BCR_0 0xF64 +#define _ARC_CLNR_SCM_BCR_1 0xF65 + +#define _ARC_REG_CLN_BCR_VER_MAJOR_ARCV3_MIN 32 /* Minimal version of cluster in ARCv3 */ +#define _ARC_CLN_BCR_VER_MAJOR_MASK 0xff +#define _ARC_CLNR_BCR_0_HAS_SCM BIT(29) + +/* Cluster registers (not in the AUX address space - indirect access via CLNR_ADDR + CLNR_DATA) */ +#define ARC_CLN_MST_NOC_0_BCR 0 +#define ARC_CLN_MST_NOC_1_BCR 1 +#define ARC_CLN_MST_NOC_2_BCR 2 +#define ARC_CLN_MST_NOC_3_BCR 3 +#define ARC_CLN_MST_PER_0_BCR 16 +#define ARC_CLN_MST_PER_1_BCR 17 +#define ARC_CLN_PER_0_BASE 2688 +#define ARC_CLN_PER_0_SIZE 2689 +#define ARC_CLN_PER_1_BASE 2690 +#define ARC_CLN_PER_1_SIZE 2691 + +#define ARC_CLN_SCM_BCR_0 100 +#define ARC_CLN_SCM_BCR_1 101 + +#define ARC_CLN_MST_NOC_0_0_ADDR 292 +#define ARC_CLN_MST_NOC_0_0_SIZE 293 +#define ARC_CLN_MST_NOC_0_1_ADDR 2560 +#define ARC_CLN_MST_NOC_0_1_SIZE 2561 +#define ARC_CLN_MST_NOC_0_2_ADDR 2562 +#define ARC_CLN_MST_NOC_0_2_SIZE 2563 +#define ARC_CLN_MST_NOC_0_3_ADDR 2564 +#define ARC_CLN_MST_NOC_0_3_SIZE 2565 +#define ARC_CLN_MST_NOC_0_4_ADDR 2566 +#define ARC_CLN_MST_NOC_0_4_SIZE 2567 + +#define ARC_CLN_PER0_BASE 2688 +#define ARC_CLN_PER0_SIZE 2689 + +#define ARC_CLN_SHMEM_ADDR 200 +#define ARC_CLN_SHMEM_SIZE 201 +#define ARC_CLN_CACHE_ADDR_LO0 204 +#define ARC_CLN_CACHE_ADDR_LO1 205 +#define ARC_CLN_CACHE_ADDR_HI0 206 +#define ARC_CLN_CACHE_ADDR_HI1 207 +#define ARC_CLN_CACHE_CMD 207 +#define ARC_CLN_CACHE_CMD_OP_NOP 0b0000 +#define ARC_CLN_CACHE_CMD_OP_LOOKUP 0b0001 +#define ARC_CLN_CACHE_CMD_OP_PROBE 0b0010 +#define ARC_CLN_CACHE_CMD_OP_IDX_INV 0b0101 +#define ARC_CLN_CACHE_CMD_OP_IDX_CLN 0b0110 +#define ARC_CLN_CACHE_CMD_OP_IDX_CLN_INV 0b0111 +#define ARC_CLN_CACHE_CMD_OP_REG_INV 0b1001 +#define ARC_CLN_CACHE_CMD_OP_REG_CLN 0b1010 +#define ARC_CLN_CACHE_CMD_OP_REG_CLN_INV 0b1011 +#define ARC_CLN_CACHE_CMD_OP_ADDR_INV 0b1101 +#define ARC_CLN_CACHE_CMD_OP_ADDR_CLN 0b1110 +#define ARC_CLN_CACHE_CMD_OP_ADDR_CLN_INV 0b1111 +#define ARC_CLN_CACHE_CMD_INCR BIT(4) + +#define ARC_CLN_CACHE_STATUS 209 +#define ARC_CLN_CACHE_STATUS_BUSY BIT(23) +#define ARC_CLN_CACHE_STATUS_DONE BIT(24) +#define ARC_CLN_CACHE_STATUS_MASK BIT(26) +#define ARC_CLN_CACHE_STATUS_EN BIT(27) +#define ARC_CLN_CACHE_ERR 210 +#define ARC_CLN_CACHE_ERR_ADDR0 211 +#define ARC_CLN_CACHE_ERR_ADDR1 212 + + +static inline unsigned int arc_cln_read_reg_nolock(unsigned int reg) +{ + z_arc_v2_aux_reg_write(_ARC_CLNR_ADDR, reg); + return z_arc_v2_aux_reg_read(_ARC_CLNR_DATA); +} + +static inline void arc_cln_write_reg_nolock(unsigned int reg, unsigned int data) +{ + z_arc_v2_aux_reg_write(_ARC_CLNR_ADDR, reg); + z_arc_v2_aux_reg_write(_ARC_CLNR_DATA, data); +} + +#endif /* ZEPHYR_INCLUDE_ARCH_ARC_CLUSTER_H_ */ From 4e4a2e8d61bba3fac4f5bfb209472aca85b7bd5c Mon Sep 17 00:00:00 2001 From: Evgeniy Paltsev Date: Fri, 22 Dec 2023 16:29:40 +0000 Subject: [PATCH 3058/3723] board: nsim: cleanup ARCv3 haps setup Cleanup ARCv3 haps setup with new cluster accessors Signed-off-by: Eugeniy Paltsev Signed-off-by: Evgeniy Paltsev --- boards/arc/nsim/haps_arcv3_init.c | 41 ++++++------------------------- 1 file changed, 8 insertions(+), 33 deletions(-) diff --git a/boards/arc/nsim/haps_arcv3_init.c b/boards/arc/nsim/haps_arcv3_init.c index 78dfc37f6c7..c29392643f8 100644 --- a/boards/arc/nsim/haps_arcv3_init.c +++ b/boards/arc/nsim/haps_arcv3_init.c @@ -1,48 +1,23 @@ /* - * Copyright (c) 2022 Synopsys + * Copyright (c) 2022-2023 Synopsys * * SPDX-License-Identifier: Apache-2.0 */ -#include +#include #include #include -#define ARC_CLN_MST_NOC_0_0_ADDR 292 -#define ARC_CLN_MST_NOC_0_0_SIZE 293 - -#define ARC_CLN_MST_NOC_0_1_ADDR 2560 -#define ARC_CLN_MST_NOC_0_1_SIZE 2561 - -#define ARC_CLN_MST_NOC_0_2_ADDR 2562 -#define ARC_CLN_MST_NOC_0_2_SIZE 2563 - -#define ARC_CLN_MST_NOC_0_3_ADDR 2564 -#define ARC_CLN_MST_NOC_0_3_SIZE 2565 - -#define ARC_CLN_MST_NOC_0_4_ADDR 2566 -#define ARC_CLN_MST_NOC_0_4_SIZE 2567 - -#define ARC_CLN_PER0_BASE 2688 -#define ARC_CLN_PER0_SIZE 2689 - -#define AUX_CLN_ADDR 0x640 -#define AUX_CLN_DATA 0x641 - +#define DT_SRAM_NODE_ADDR (DT_REG_ADDR(DT_CHOSEN(zephyr_sram)) / (1024 * 1024)) +#define DT_SRAM_NODE_SIZE (DT_REG_SIZE(DT_CHOSEN(zephyr_sram)) / (1024 * 1024)) static int haps_arcv3_init(void) { + arc_cln_write_reg_nolock(ARC_CLN_PER0_BASE, 0xF00); + arc_cln_write_reg_nolock(ARC_CLN_PER0_SIZE, 1); - z_arc_v2_aux_reg_write(AUX_CLN_ADDR, ARC_CLN_PER0_BASE); - z_arc_v2_aux_reg_write(AUX_CLN_DATA, 0xF00); - z_arc_v2_aux_reg_write(AUX_CLN_ADDR, ARC_CLN_PER0_SIZE); - z_arc_v2_aux_reg_write(AUX_CLN_DATA, 1); - - z_arc_v2_aux_reg_write(AUX_CLN_ADDR, ARC_CLN_MST_NOC_0_0_ADDR); - z_arc_v2_aux_reg_write(AUX_CLN_DATA, (DT_REG_ADDR(DT_CHOSEN(zephyr_sram)) / (1024 * 1024))); - z_arc_v2_aux_reg_write(AUX_CLN_ADDR, ARC_CLN_MST_NOC_0_0_SIZE); - z_arc_v2_aux_reg_write(AUX_CLN_DATA, (DT_REG_SIZE(DT_CHOSEN(zephyr_sram)) / (1024 * 1024))); - + arc_cln_write_reg_nolock(ARC_CLN_MST_NOC_0_0_ADDR, DT_SRAM_NODE_ADDR); + arc_cln_write_reg_nolock(ARC_CLN_MST_NOC_0_0_SIZE, DT_SRAM_NODE_SIZE); return 0; } From 515ef17915aa9612e1eae5a60a745f50cc285a18 Mon Sep 17 00:00:00 2001 From: Emil Gydesen Date: Tue, 30 Jan 2024 00:20:28 +0100 Subject: [PATCH 3059/3723] Bluetooth: Audio: Change samples and shell to use sinf Change the samples and shell to use sinf instead of sin, as that return the expect float data type, instead of a double. Signed-off-by: Emil Gydesen --- samples/bluetooth/broadcast_audio_source/src/main.c | 2 +- samples/bluetooth/unicast_audio_client/src/main.c | 3 +-- subsys/bluetooth/audio/shell/bap.c | 2 +- 3 files changed, 3 insertions(+), 4 deletions(-) diff --git a/samples/bluetooth/broadcast_audio_source/src/main.c b/samples/bluetooth/broadcast_audio_source/src/main.c index bc63b68b700..ee343f5123f 100644 --- a/samples/bluetooth/broadcast_audio_source/src/main.c +++ b/samples/bluetooth/broadcast_audio_source/src/main.c @@ -98,7 +98,7 @@ static void fill_audio_buf_sin(int16_t *buf, int length_us, int frequency_hz, in const float step = 2 * 3.1415f / sine_period_samples; for (unsigned int i = 0; i < num_samples; i++) { - const float sample = sin(i * step); + const float sample = sinf(i * step); buf[i] = (int16_t)(AUDIO_VOLUME * sample); } diff --git a/samples/bluetooth/unicast_audio_client/src/main.c b/samples/bluetooth/unicast_audio_client/src/main.c index 14ad2bb80e7..8fe82543ab7 100644 --- a/samples/bluetooth/unicast_audio_client/src/main.c +++ b/samples/bluetooth/unicast_audio_client/src/main.c @@ -106,7 +106,6 @@ static int frame_duration_100us; static int frames_per_sdu; static int octets_per_frame; - /** * Use the math lib to generate a sine-wave using 16 bit samples into a buffer. * @@ -122,7 +121,7 @@ static void fill_audio_buf_sin(int16_t *buf, int length_us, int frequency_hz, in const float step = 2 * 3.1415f / sine_period_samples; for (unsigned int i = 0; i < num_samples; i++) { - const float sample = sin(i * step); + const float sample = sinf(i * step); buf[i] = (int16_t)(AUDIO_VOLUME * sample); } diff --git a/subsys/bluetooth/audio/shell/bap.c b/subsys/bluetooth/audio/shell/bap.c index 2fd5cdce0fb..302be473d70 100644 --- a/subsys/bluetooth/audio/shell/bap.c +++ b/subsys/bluetooth/audio/shell/bap.c @@ -220,7 +220,7 @@ static void fill_audio_buf_sin(int16_t *buf, int length_us, int frequency_hz, in const float step = 2 * 3.1415 / sine_period_samples; for (size_t i = 0; i < num_samples; i++) { - const float sample = sin(i * step); + const float sample = sinf(i * step); buf[i] = (int16_t)(AUDIO_VOLUME * sample); } From a3c4d22e7908afaffe189d0101fc22083722db42 Mon Sep 17 00:00:00 2001 From: Lars Knudsen Date: Fri, 29 Dec 2023 08:34:45 +0100 Subject: [PATCH 3060/3723] boards: bbc_microbit_v2: Add buzzer Tie pwm1 to buzzer pin and adjust sample. Signed-off-by: Lars Knudsen --- .../bbc_microbit_v2-pinctrl.dtsi | 13 +++++++++ .../arm/bbc_microbit_v2/bbc_microbit_v2.dts | 8 ++++++ samples/boards/bbc_microbit/sound/README.rst | 27 +++++++++++++++---- .../sound/boards/bbc_microbit_v2.overlay | 6 +++++ samples/boards/bbc_microbit/sound/prj.conf | 1 - samples/boards/bbc_microbit/sound/sample.yaml | 4 ++- 6 files changed, 52 insertions(+), 7 deletions(-) create mode 100644 samples/boards/bbc_microbit/sound/boards/bbc_microbit_v2.overlay diff --git a/boards/arm/bbc_microbit_v2/bbc_microbit_v2-pinctrl.dtsi b/boards/arm/bbc_microbit_v2/bbc_microbit_v2-pinctrl.dtsi index a91c7674688..d61a30d944b 100644 --- a/boards/arm/bbc_microbit_v2/bbc_microbit_v2-pinctrl.dtsi +++ b/boards/arm/bbc_microbit_v2/bbc_microbit_v2-pinctrl.dtsi @@ -34,4 +34,17 @@ }; }; + pwm1_default: pwm1_default { + group1 { + psels = ; + nordic,invert; + }; + }; + + pwm1_sleep: pwm1_sleep { + group1 { + psels = ; + low-power-enable; + }; + }; }; diff --git a/boards/arm/bbc_microbit_v2/bbc_microbit_v2.dts b/boards/arm/bbc_microbit_v2/bbc_microbit_v2.dts index d802907c973..f123d003217 100644 --- a/boards/arm/bbc_microbit_v2/bbc_microbit_v2.dts +++ b/boards/arm/bbc_microbit_v2/bbc_microbit_v2.dts @@ -113,6 +113,14 @@ status = "okay"; }; +&pwm1 { + /* buzzer */ + status = "okay"; + pinctrl-0 = <&pwm1_default>; + pinctrl-1 = <&pwm1_sleep>; + pinctrl-names = "default", "sleep"; +}; + &uart0 { compatible = "nordic,nrf-uart"; status = "okay"; diff --git a/samples/boards/bbc_microbit/sound/README.rst b/samples/boards/bbc_microbit/sound/README.rst index 33373f0b545..b02faffb2d6 100644 --- a/samples/boards/bbc_microbit/sound/README.rst +++ b/samples/boards/bbc_microbit/sound/README.rst @@ -7,29 +7,46 @@ Overview ******** This sample demonstrates how to use a piezo buzzer connected -to port P0 on the edge connector of the BBC micro:bit board. +to port P0 on the edge connector of the **BBC micro:bit v1** or +using the on-board buzzer on the **BBC micro:bit v2**. Requirements ************ -A separate piezo buzzer connected to the board. One example is the MI:Power -board that has a piezo buzzer in addition to a coin-cell battery. Resellers of -this board can be fairly easily found using online search. +Using **BBC micro:bit v1**, a separate piezo buzzer must be connected to the board. +One example is the MI:Power board that has a piezo buzzer in addition to a +coin-cell battery. Resellers of this board can be fairly easily found using online search. + +The upgraded **BBC micro:bit v2** board does not need a separate buzzer as it has one +built-in on the backside of the board (marked as 'speaker'). + Building and running ******************** The sample can be built as follows: +Building for a BBC micro:bit v1 +------------------------------- + .. zephyr-app-commands:: :zephyr-app: samples/boards/bbc_microbit/sound :board: bbc_microbit :goals: build flash :compact: +Building for a BBC micro:bit v2 +------------------------------- + +.. zephyr-app-commands:: + :zephyr-app: samples/boards/bbc_microbit/sound + :board: bbc_microbit_v2 + :goals: build flash + :compact: + Sample Output ============= -This sample outputs sounds through a connected piezo buzzer based on +This sample outputs sounds through a piezo buzzer based on button presses of the two main buttons. For each press the current output frequency will be printed on the 5x5 LED display. diff --git a/samples/boards/bbc_microbit/sound/boards/bbc_microbit_v2.overlay b/samples/boards/bbc_microbit/sound/boards/bbc_microbit_v2.overlay new file mode 100644 index 00000000000..33e471dc6b5 --- /dev/null +++ b/samples/boards/bbc_microbit/sound/boards/bbc_microbit_v2.overlay @@ -0,0 +1,6 @@ +/ { + zephyr,user { + /* period cell corresponds to initial period */ + pwms = <&pwm1 0 PWM_USEC(1500) PWM_POLARITY_NORMAL>; + }; +}; diff --git a/samples/boards/bbc_microbit/sound/prj.conf b/samples/boards/bbc_microbit/sound/prj.conf index 2341a68c528..d6277787129 100644 --- a/samples/boards/bbc_microbit/sound/prj.conf +++ b/samples/boards/bbc_microbit/sound/prj.conf @@ -2,4 +2,3 @@ CONFIG_GPIO=y CONFIG_DISPLAY=y CONFIG_MICROBIT_DISPLAY=y CONFIG_PWM=y -CONFIG_PWM_NRF_SW=y diff --git a/samples/boards/bbc_microbit/sound/sample.yaml b/samples/boards/bbc_microbit/sound/sample.yaml index 241fce89d8c..8a819a03a1d 100644 --- a/samples/boards/bbc_microbit/sound/sample.yaml +++ b/samples/boards/bbc_microbit/sound/sample.yaml @@ -2,5 +2,7 @@ sample: name: BBC micro:bit Sound tests: sample.board.bbc_microbit.sound: - platform_allow: bbc_microbit + platform_allow: + - bbc_microbit + - bbc_microbit_v2 tags: sound From 8396bf0d9843439dfa558f2d391ed60c71c378fd Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C3=98yvind=20R=C3=B8nningstad?= Date: Fri, 26 Jan 2024 13:27:12 +0100 Subject: [PATCH 3061/3723] west.yml: Update zcbor from 0.8.0 to 0.8.1 MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Brings a few improvements and bugfixes, most notably: - Adds a forward declaration of strnlen() - Adds a ZCBOR_VERSION macro Signed-off-by: Øyvind Rønningstad --- west.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/west.yml b/west.yml index 2e437c0b7bb..3b9b32f5b4e 100644 --- a/west.yml +++ b/west.yml @@ -335,7 +335,7 @@ manifest: revision: 150f4eb2955eaf36ac0f9519d4f4f58d5ade5740 path: modules/lib/uoscore-uedhoc - name: zcbor - revision: dbe20afd00b3ddd6956f4b47f5df202bb49a8707 + revision: d3093b5684f62268c7f27f8a5079f166772619de path: modules/lib/zcbor self: From 3ad47d214a7d5b5af233060413e92e97a21b13e4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C3=98yvind=20R=C3=B8nningstad?= Date: Fri, 26 Jan 2024 15:17:44 +0100 Subject: [PATCH 3062/3723] lwm2m: Regenerate zcbor files MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit with zcbor 0.8.1 Signed-off-by: Øyvind Rønningstad --- subsys/net/lib/lwm2m/lwm2m_senml_cbor.patch | 10 +++++----- subsys/net/lib/lwm2m/lwm2m_senml_cbor_decode.c | 2 +- subsys/net/lib/lwm2m/lwm2m_senml_cbor_decode.h | 2 +- subsys/net/lib/lwm2m/lwm2m_senml_cbor_encode.c | 2 +- subsys/net/lib/lwm2m/lwm2m_senml_cbor_encode.h | 2 +- subsys/net/lib/lwm2m/lwm2m_senml_cbor_regenerate.sh | 2 +- subsys/net/lib/lwm2m/lwm2m_senml_cbor_types.h | 2 +- 7 files changed, 11 insertions(+), 11 deletions(-) diff --git a/subsys/net/lib/lwm2m/lwm2m_senml_cbor.patch b/subsys/net/lib/lwm2m/lwm2m_senml_cbor.patch index 81ec06bab8b..41bb3f0a5d4 100644 --- a/subsys/net/lib/lwm2m/lwm2m_senml_cbor.patch +++ b/subsys/net/lib/lwm2m/lwm2m_senml_cbor.patch @@ -5,7 +5,7 @@ index c12f477cce..f41b81275d 100644 @@ -4,7 +4,7 @@ * SPDX-License-Identifier: Apache-2.0 * - * Generated using zcbor version 0.8.0 + * Generated using zcbor version 0.8.1 - * https://github.com/NordicSemiconductor/zcbor + * https://github.com/zephyrproject-rtos/zcbor * Generated with a --default-max-qty of 99 @@ -47,7 +47,7 @@ index a36f8782c6..b913fb78e9 100644 @@ -4,7 +4,7 @@ * SPDX-License-Identifier: Apache-2.0 * - * Generated using zcbor version 0.8.0 + * Generated using zcbor version 0.8.1 - * https://github.com/NordicSemiconductor/zcbor + * https://github.com/zephyrproject-rtos/zcbor * Generated with a --default-max-qty of 99 @@ -72,7 +72,7 @@ index 94926c531f..5521917853 100644 @@ -4,7 +4,7 @@ * SPDX-License-Identifier: Apache-2.0 * - * Generated using zcbor version 0.8.0 + * Generated using zcbor version 0.8.1 - * https://github.com/NordicSemiconductor/zcbor + * https://github.com/zephyrproject-rtos/zcbor * Generated with a --default-max-qty of 99 @@ -120,7 +120,7 @@ index df2f0ac6a1..8fa1eedb2b 100644 @@ -4,7 +4,7 @@ * SPDX-License-Identifier: Apache-2.0 * - * Generated using zcbor version 0.8.0 + * Generated using zcbor version 0.8.1 - * https://github.com/NordicSemiconductor/zcbor + * https://github.com/zephyrproject-rtos/zcbor * Generated with a --default-max-qty of 99 @@ -145,7 +145,7 @@ index 77649036ef..f0a2958072 100644 @@ -4,7 +4,7 @@ * SPDX-License-Identifier: Apache-2.0 * - * Generated using zcbor version 0.8.0 + * Generated using zcbor version 0.8.1 - * https://github.com/NordicSemiconductor/zcbor + * https://github.com/zephyrproject-rtos/zcbor * Generated with a --default-max-qty of 99 diff --git a/subsys/net/lib/lwm2m/lwm2m_senml_cbor_decode.c b/subsys/net/lib/lwm2m/lwm2m_senml_cbor_decode.c index 3906d476cac..28b0265b9cc 100644 --- a/subsys/net/lib/lwm2m/lwm2m_senml_cbor_decode.c +++ b/subsys/net/lib/lwm2m/lwm2m_senml_cbor_decode.c @@ -3,7 +3,7 @@ * * SPDX-License-Identifier: Apache-2.0 * - * Generated using zcbor version 0.8.0 + * Generated using zcbor version 0.8.1 * https://github.com/zephyrproject-rtos/zcbor * Generated with a --default-max-qty of 99 */ diff --git a/subsys/net/lib/lwm2m/lwm2m_senml_cbor_decode.h b/subsys/net/lib/lwm2m/lwm2m_senml_cbor_decode.h index b47b79de615..4e1fdeb66a2 100644 --- a/subsys/net/lib/lwm2m/lwm2m_senml_cbor_decode.h +++ b/subsys/net/lib/lwm2m/lwm2m_senml_cbor_decode.h @@ -3,7 +3,7 @@ * * SPDX-License-Identifier: Apache-2.0 * - * Generated using zcbor version 0.8.0 + * Generated using zcbor version 0.8.1 * https://github.com/zephyrproject-rtos/zcbor * Generated with a --default-max-qty of 99 */ diff --git a/subsys/net/lib/lwm2m/lwm2m_senml_cbor_encode.c b/subsys/net/lib/lwm2m/lwm2m_senml_cbor_encode.c index 9cf4f3457c6..14ec7431e5b 100644 --- a/subsys/net/lib/lwm2m/lwm2m_senml_cbor_encode.c +++ b/subsys/net/lib/lwm2m/lwm2m_senml_cbor_encode.c @@ -3,7 +3,7 @@ * * SPDX-License-Identifier: Apache-2.0 * - * Generated using zcbor version 0.8.0 + * Generated using zcbor version 0.8.1 * https://github.com/zephyrproject-rtos/zcbor * Generated with a --default-max-qty of 99 */ diff --git a/subsys/net/lib/lwm2m/lwm2m_senml_cbor_encode.h b/subsys/net/lib/lwm2m/lwm2m_senml_cbor_encode.h index 49ce5c55159..fc08ead18d4 100644 --- a/subsys/net/lib/lwm2m/lwm2m_senml_cbor_encode.h +++ b/subsys/net/lib/lwm2m/lwm2m_senml_cbor_encode.h @@ -3,7 +3,7 @@ * * SPDX-License-Identifier: Apache-2.0 * - * Generated using zcbor version 0.8.0 + * Generated using zcbor version 0.8.1 * https://github.com/zephyrproject-rtos/zcbor * Generated with a --default-max-qty of 99 */ diff --git a/subsys/net/lib/lwm2m/lwm2m_senml_cbor_regenerate.sh b/subsys/net/lib/lwm2m/lwm2m_senml_cbor_regenerate.sh index 448a9020862..cf293d7b579 100644 --- a/subsys/net/lib/lwm2m/lwm2m_senml_cbor_regenerate.sh +++ b/subsys/net/lib/lwm2m/lwm2m_senml_cbor_regenerate.sh @@ -12,7 +12,7 @@ SPDX-License-Identifier: Apache-2.0 git add -A git commit -s -m"pre-patch" -git apply lwm2m_senml_cbor.patch +git apply --reject lwm2m_senml_cbor.patch clang-format -i \ lwm2m_senml_cbor_decode.c lwm2m_senml_cbor_decode.h \ diff --git a/subsys/net/lib/lwm2m/lwm2m_senml_cbor_types.h b/subsys/net/lib/lwm2m/lwm2m_senml_cbor_types.h index 4c41385ba4b..dbb5a368551 100644 --- a/subsys/net/lib/lwm2m/lwm2m_senml_cbor_types.h +++ b/subsys/net/lib/lwm2m/lwm2m_senml_cbor_types.h @@ -3,7 +3,7 @@ * * SPDX-License-Identifier: Apache-2.0 * - * Generated using zcbor version 0.8.0 + * Generated using zcbor version 0.8.1 * https://github.com/zephyrproject-rtos/zcbor * Generated with a --default-max-qty of 99 */ From 3e41e68ce64a11cb13db29343535a1c1d52deb38 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C3=98yvind=20R=C3=B8nningstad?= Date: Fri, 26 Jan 2024 15:01:13 +0100 Subject: [PATCH 3063/3723] doc: Update release notes and migration guide for zcbor 0.8.1 MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit No changes, but update version numbers Signed-off-by: Øyvind Rønningstad --- doc/releases/migration-guide-3.6.rst | 2 +- doc/releases/release-notes-3.6.rst | 5 +++-- 2 files changed, 4 insertions(+), 3 deletions(-) diff --git a/doc/releases/migration-guide-3.6.rst b/doc/releases/migration-guide-3.6.rst index fc2e35ffb6f..d8a4c3facbd 100644 --- a/doc/releases/migration-guide-3.6.rst +++ b/doc/releases/migration-guide-3.6.rst @@ -449,7 +449,7 @@ zcbor ===== * If you have zcbor-generated code that relies on the zcbor libraries through Zephyr, you must - regenerate the files using zcbor 0.8.0. Note that the names of generated types and members has + regenerate the files using zcbor 0.8.1. Note that the names of generated types and members has been overhauled, so the code using the generated code must likely be changed. For example: diff --git a/doc/releases/release-notes-3.6.rst b/doc/releases/release-notes-3.6.rst index c64815a8e92..60f461d5ce5 100644 --- a/doc/releases/release-notes-3.6.rst +++ b/doc/releases/release-notes-3.6.rst @@ -390,9 +390,10 @@ Nanopb zcbor ***** -zcbor has been updated from 0.7.0 to 0.8.0. +zcbor has been updated from 0.7.0 to 0.8.1. Full release notes can be found at: -https://github.com/zephyrproject-rtos/zcbor/blob/0.8.0/RELEASE_NOTES.md +https://github.com/zephyrproject-rtos/zcbor/blob/0.8.0/RELEASE_NOTES.md and +https://github.com/zephyrproject-rtos/zcbor/blob/0.8.1/RELEASE_NOTES.md Highlights: From de7621596d992933dfc6fb79b50e9dc37e3c5108 Mon Sep 17 00:00:00 2001 From: Wilfried Chauveau Date: Thu, 20 Jul 2023 16:35:53 +0100 Subject: [PATCH 3064/3723] boards: arm: mps2_an521: add pyocd runner This allows to run tests & examples on the physical board with: ``` west twister -p mps2_an521 --device-testing --device-serial /dev/ttyUSB0 ``` Signed-off-by: Wilfried Chauveau --- boards/arm/mps2_an521/board.cmake | 3 +++ 1 file changed, 3 insertions(+) diff --git a/boards/arm/mps2_an521/board.cmake b/boards/arm/mps2_an521/board.cmake index 806f4ac7052..51e09ba282d 100644 --- a/boards/arm/mps2_an521/board.cmake +++ b/boards/arm/mps2_an521/board.cmake @@ -12,6 +12,9 @@ set(QEMU_FLAGS_${ARCH} ) board_set_debugger_ifnset(qemu) +board_runner_args(pyocd "--target=mps2_an521") + +include(${ZEPHYR_BASE}/boards/common/pyocd.board.cmake) # To enable a host tty switch between serial and pty # -chardev serial,path=/dev/ttyS0,id=hostS0 list(APPEND QEMU_EXTRA_FLAGS -chardev pty,id=hostS0 -serial chardev:hostS0) From dfd758ea4776f881fd2a564e757237294a708f7c Mon Sep 17 00:00:00 2001 From: Wilfried Chauveau Date: Tue, 17 Oct 2023 21:55:44 +0100 Subject: [PATCH 3065/3723] test: kernel: mem_protect: switch to an547 as the integration platform AN521 does not have enough MPU region (8) to handle these tests. Signed-off-by: Wilfried Chauveau --- tests/kernel/mem_protect/mem_protect/testcase.yaml | 4 ++-- tests/kernel/mem_protect/userspace/testcase.yaml | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/tests/kernel/mem_protect/mem_protect/testcase.yaml b/tests/kernel/mem_protect/mem_protect/testcase.yaml index 002b9ae0973..39551533e95 100644 --- a/tests/kernel/mem_protect/mem_protect/testcase.yaml +++ b/tests/kernel/mem_protect/mem_protect/testcase.yaml @@ -24,8 +24,8 @@ tests: arch_allow: arm platform_allow: - efr32_radio_brd4180a - - mps2_an521 + - mps3_an547 - nrf9160dk_nrf9160 integration_platforms: - - mps2_an521 + - mps3_an547 extra_args: CONFIG_MPU_GAP_FILLING=y diff --git a/tests/kernel/mem_protect/userspace/testcase.yaml b/tests/kernel/mem_protect/userspace/testcase.yaml index 40a80ae13a8..858b341875a 100644 --- a/tests/kernel/mem_protect/userspace/testcase.yaml +++ b/tests/kernel/mem_protect/userspace/testcase.yaml @@ -23,8 +23,8 @@ tests: arch_allow: arm platform_allow: - efr32_radio_brd4180a - - mps2_an521 + - mps3_an547 - nrf9160dk_nrf9160 integration_platforms: - - mps2_an521 + - mps3_an547 extra_args: CONFIG_MPU_GAP_FILLING=y From f875cb6cc9c8305a23161b7de814fade7714ddcc Mon Sep 17 00:00:00 2001 From: Wilfried Chauveau Date: Wed, 24 Jan 2024 12:15:47 +0000 Subject: [PATCH 3066/3723] samples: subsys: ipc: switch rpmsg to sysbuild rpmsg_service only loads the main application on the target. Switch to sysbuild which is know to work as expected with the openamp sample. Signed-off-by: Wilfried Chauveau --- .../subsys/ipc/rpmsg_service/CMakeLists.txt | 56 +++---------------- .../subsys/ipc/rpmsg_service/Kconfig.sysbuild | 16 ++++++ samples/subsys/ipc/rpmsg_service/README.rst | 4 +- .../ipc/rpmsg_service/remote/CMakeLists.txt | 16 +----- .../ipc/rpmsg_service/remote/sample.yaml | 14 ----- samples/subsys/ipc/rpmsg_service/sample.yaml | 19 ------- .../subsys/ipc/rpmsg_service/sysbuild.cmake | 15 +++++ 7 files changed, 45 insertions(+), 95 deletions(-) create mode 100644 samples/subsys/ipc/rpmsg_service/Kconfig.sysbuild delete mode 100644 samples/subsys/ipc/rpmsg_service/remote/sample.yaml delete mode 100644 samples/subsys/ipc/rpmsg_service/sample.yaml create mode 100644 samples/subsys/ipc/rpmsg_service/sysbuild.cmake diff --git a/samples/subsys/ipc/rpmsg_service/CMakeLists.txt b/samples/subsys/ipc/rpmsg_service/CMakeLists.txt index ffe26a47a81..85356c531de 100644 --- a/samples/subsys/ipc/rpmsg_service/CMakeLists.txt +++ b/samples/subsys/ipc/rpmsg_service/CMakeLists.txt @@ -1,63 +1,23 @@ cmake_minimum_required(VERSION 3.20.0) # Copyright (c) 2019 Linaro Limited # Copyright (c) 2018-2021 Nordic Semiconductor ASA +# Copyright (c) 2023 Arm Limited # # SPDX-License-Identifier: Apache-2.0 # -set(REMOTE_ZEPHYR_DIR ${CMAKE_CURRENT_BINARY_DIR}/rpmsg_service_remote-prefix/src/rpmsg_service_remote-build/zephyr) - -if("${BOARD}" STREQUAL "nrf5340dk_nrf5340_cpuapp") - set(BOARD_REMOTE "nrf5340dk_nrf5340_cpunet") -elseif("${BOARD}" STREQUAL "bl5340_dvk_cpuapp") - set(BOARD_REMOTE "bl5340_dvk_cpunet") -elseif("${BOARD}" STREQUAL "lpcxpresso54114_m4") - set(BOARD_REMOTE "lpcxpresso54114_m0") -elseif("${BOARD}" STREQUAL "mps2_an521") - set(QEMU_EXTRA_FLAGS "-device;loader,file=${REMOTE_ZEPHYR_DIR}/zephyr.elf") - set(BOARD_REMOTE "mps2_an521_remote") -elseif("${BOARD}" STREQUAL "v2m_musca_b1") - set(BOARD_REMOTE "v2m_musca_b1_ns") -elseif("${BOARD}" STREQUAL "esp32_devkitc_wroom") - set(BOARD_REMOTE "esp32_devkitc_wroom_appcpu") -elseif("${BOARD}" STREQUAL "esp32_devkitc_wrover") - set(BOARD_REMOTE "esp32_devkitc_wrover_appcpu") -elseif("${BOARD}" STREQUAL "esp32s3_devkitm") - set(BOARD_REMOTE "esp32s3_devkitm_appcpu") -else() - message(FATAL_ERROR "${BOARD} was not supported for this sample") -endif() - -message(STATUS "${BOARD} compile as Master in this sample") +set(REMOTE_ZEPHYR_DIR ${CMAKE_CURRENT_BINARY_DIR}/../rpmsg_service_remote/zephyr) find_package(Zephyr REQUIRED HINTS $ENV{ZEPHYR_BASE}) project(rpmsg_service) -enable_language(C ASM) +message(STATUS "${BOARD} compile as Master in this sample") -target_sources(app PRIVATE src/main.c) +enable_language(C ASM) if("${BOARD}" STREQUAL "esp32_devkitc_wrover" OR "${BOARD}" STREQUAL "esp32s3_devkitm") - set_source_files_properties(${REMOTE_ZEPHYR_DIR}/esp32_appcpu_firmware.c PROPERTIES GENERATED TRUE) - target_sources(app PRIVATE src/main.c ${REMOTE_ZEPHYR_DIR}/esp32_appcpu_firmware.c) -endif() - -include(ExternalProject) - -ExternalProject_Add( - rpmsg_service_remote - SOURCE_DIR ${APPLICATION_SOURCE_DIR}/remote - INSTALL_COMMAND "" # This particular build system has no install command - CMAKE_CACHE_ARGS -DBOARD:STRING=${BOARD_REMOTE} - BUILD_BYPRODUCTS "${REMOTE_ZEPHYR_DIR}/${KERNEL_BIN_NAME}" - # NB: Do we need to pass on more CMake variables? - BUILD_ALWAYS True -) - -if(("${BOARD}" STREQUAL "lpcxpresso54114_m4")) - add_dependencies(core_m0_inc_target rpmsg_service_remote) -elseif("${BOARD}" STREQUAL "esp32_devkitc_wrover" OR "${BOARD}" STREQUAL "esp32s3_devkitm") - add_dependencies(app rpmsg_service_remote) + set_source_files_properties(${REMOTE_ZEPHYR_DIR}/esp32_net_firmware.c PROPERTIES GENERATED TRUE) + target_sources(app PRIVATE src/main.c ${REMOTE_ZEPHYR_DIR}/esp32_net_firmware.c) +else() + target_sources(app PRIVATE src/main.c) endif() - -target_include_directories(app PRIVATE ${CMAKE_CURRENT_SOURCE_DIR}) diff --git a/samples/subsys/ipc/rpmsg_service/Kconfig.sysbuild b/samples/subsys/ipc/rpmsg_service/Kconfig.sysbuild new file mode 100644 index 00000000000..9dec2087f95 --- /dev/null +++ b/samples/subsys/ipc/rpmsg_service/Kconfig.sysbuild @@ -0,0 +1,16 @@ +# Copyright (c) 2023 Arm Limited +# +# SPDX-License-Identifier: Apache-2.0 + +source "share/sysbuild/Kconfig" + +config RPMSG_REMOTE_BOARD +string + default "nrf5340dk_nrf5340_cpunet" if $(BOARD) = "nrf5340dk_nrf5340_cpuapp" + default "bl5340_dvk_cpunet" if $(BOARD) = "bl5340_dvk_cpuapp" + default "lpcxpresso54114_m0" if $(BOARD) = "lpcxpresso54114_m4" + default "mps2_an521_remote" if $(BOARD) = "mps2_an521" + default "v2m_musca_b1_ns" if $(BOARD) = "v2m_musca_b1" + default "esp32_devkitc_wroom_appcpu" if $(BOARD) = "esp32_devkitc_wroom" + default "esp32_devkitc_wrover_appcpu" if $(BOARD) = "esp32_devkitc_wrover" + default "esp32s3_devkitm_appcpu" if $(BOARD) = "esp32s3_devkitm" diff --git a/samples/subsys/ipc/rpmsg_service/README.rst b/samples/subsys/ipc/rpmsg_service/README.rst index ce32b16b61e..0c63b8dc3bb 100644 --- a/samples/subsys/ipc/rpmsg_service/README.rst +++ b/samples/subsys/ipc/rpmsg_service/README.rst @@ -11,7 +11,9 @@ RPMsg Service is an abstraction created over OpenAMP that makes initialization and endpoints creation process easier. This application demonstrates how to use RPMsg Service in Zephyr. It is designed to demonstrate how to integrate RPMsg Service with Zephyr both from a build -perspective and code. +perspective and code. Note that the remote and primary image core images can be +flashed independently, but sysbuild must be used in order to flash them in one +step. Building the application for nrf5340dk_nrf5340_cpuapp ***************************************************** diff --git a/samples/subsys/ipc/rpmsg_service/remote/CMakeLists.txt b/samples/subsys/ipc/rpmsg_service/remote/CMakeLists.txt index 2ed6c70c01f..1ee397fb9f3 100644 --- a/samples/subsys/ipc/rpmsg_service/remote/CMakeLists.txt +++ b/samples/subsys/ipc/rpmsg_service/remote/CMakeLists.txt @@ -1,25 +1,15 @@ cmake_minimum_required(VERSION 3.20.0) # Copyright (c) 2019 Linaro Limited # Copyright (c) 2018-2021 Nordic Semiconductor ASA +# Copyright (c) 2023 Arm Limited # # SPDX-License-Identifier: Apache-2.0 # -if("${BOARD}" STREQUAL "nrf5340dk_nrf5340_cpunet" - OR "${BOARD}" STREQUAL "bl5340_dvk_cpunet" - OR "${BOARD}" STREQUAL "lpcxpresso54114_m0" - OR "${BOARD}" STREQUAL "mps2_an521_remote" - OR "${BOARD}" STREQUAL "v2m_musca_b1_ns" - OR "${BOARD}" STREQUAL "esp32_devkitc_wroom_appcpu" - OR "${BOARD}" STREQUAL "esp32_devkitc_wrover_appcpu" - OR "${BOARD}" STREQUAL "esp32s3_devkitm_appcpu") - message(STATUS "${BOARD} compile as slave in this sample") -else() - message(FATAL_ERROR "${BOARD} was not supported for this sample") -endif() - find_package(Zephyr REQUIRED HINTS $ENV{ZEPHYR_BASE}) project(rpmsg_service_remote) +message(STATUS "${BOARD} compile as slave in this sample") + target_sources(app PRIVATE src/main.c) target_include_directories(app PRIVATE ${CMAKE_CURRENT_SOURCE_DIR}/..) diff --git a/samples/subsys/ipc/rpmsg_service/remote/sample.yaml b/samples/subsys/ipc/rpmsg_service/remote/sample.yaml deleted file mode 100644 index e085ef2f51b..00000000000 --- a/samples/subsys/ipc/rpmsg_service/remote/sample.yaml +++ /dev/null @@ -1,14 +0,0 @@ -sample: - description: This app provides an example of how to integrate RPMsg Service with - Zephyr. - name: RPMsg Service example integration (remote) -common: - harness: remote -tests: - sample.ipc.rpmsg_service.remote: - platform_allow: - - mps2_an521_remote - - v2m_musca_b1_ns - integration_platforms: - - v2m_musca_b1_ns - tags: ipm diff --git a/samples/subsys/ipc/rpmsg_service/sample.yaml b/samples/subsys/ipc/rpmsg_service/sample.yaml deleted file mode 100644 index 84647ea51a4..00000000000 --- a/samples/subsys/ipc/rpmsg_service/sample.yaml +++ /dev/null @@ -1,19 +0,0 @@ -sample: - description: This app provides an example of how to integrate RPMsg Service with - Zephyr. - name: RPMsg Service example integration -tests: - sample.ipc.rpmsg_service: - platform_allow: - - mps2_an521 - - v2m_musca_b1 - integration_platforms: - - mps2_an521 - tags: ipm - harness: console - harness_config: - type: multi_line - regex: - - "Master core received a message: 1" - - "Master core received a message: 99" - - "RPMsg Service demo ended." diff --git a/samples/subsys/ipc/rpmsg_service/sysbuild.cmake b/samples/subsys/ipc/rpmsg_service/sysbuild.cmake new file mode 100644 index 00000000000..08af67aeb85 --- /dev/null +++ b/samples/subsys/ipc/rpmsg_service/sysbuild.cmake @@ -0,0 +1,15 @@ +cmake_minimum_required(VERSION 3.20.0) +# Copyright (c) 2019 Linaro Limited +# Copyright (c) 2018-2021 Nordic Semiconductor ASA +# Copyright (c) 2023 Arm Limited +# +# SPDX-License-Identifier: Apache-2.0 +# + +ExternalZephyrProject_Add( + APPLICATION rpmsg_service_remote + SOURCE_DIR ${APP_DIR}/remote + BOARD ${SB_CONFIG_RPMSG_REMOTE_BOARD} + ) + +add_dependencies(rpmsg_service rpmsg_service_remote) From e840c9af011df029bb1208bbdef5e7b605af1c85 Mon Sep 17 00:00:00 2001 From: Wilfried Chauveau Date: Tue, 30 Jan 2024 11:08:38 +0000 Subject: [PATCH 3067/3723] samples: subsys: rpmsg_service improve terminology Signed-off-by: Wilfried Chauveau Co-authored-by: Jamie <40387179+nordicjm@users.noreply.github.com> --- samples/subsys/ipc/rpmsg_service/remote/CMakeLists.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/samples/subsys/ipc/rpmsg_service/remote/CMakeLists.txt b/samples/subsys/ipc/rpmsg_service/remote/CMakeLists.txt index 1ee397fb9f3..2545f2e1d71 100644 --- a/samples/subsys/ipc/rpmsg_service/remote/CMakeLists.txt +++ b/samples/subsys/ipc/rpmsg_service/remote/CMakeLists.txt @@ -9,7 +9,7 @@ cmake_minimum_required(VERSION 3.20.0) find_package(Zephyr REQUIRED HINTS $ENV{ZEPHYR_BASE}) project(rpmsg_service_remote) -message(STATUS "${BOARD} compile as slave in this sample") +message(STATUS "${BOARD} compile as remote in this sample") target_sources(app PRIVATE src/main.c) target_include_directories(app PRIVATE ${CMAKE_CURRENT_SOURCE_DIR}/..) From 894302547115a73704dec9d8842506b989c8c47e Mon Sep 17 00:00:00 2001 From: Johan Stridkvist Date: Fri, 26 Jan 2024 13:39:23 +0100 Subject: [PATCH 3068/3723] doc: peripherals: Document limitation Asynchronous and interrupt driven APIs can be used at the same time for different hardware peripherals. Signed-off-by: Johan Stridkvist --- doc/hardware/peripherals/uart.rst | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/doc/hardware/peripherals/uart.rst b/doc/hardware/peripherals/uart.rst index 42906bca6fa..177a54dbbfe 100644 --- a/doc/hardware/peripherals/uart.rst +++ b/doc/hardware/peripherals/uart.rst @@ -31,11 +31,11 @@ than the other methods. .. warning:: Interrupt-driven API and the Asynchronous API should NOT be used at - the same time, since both APIs require hardware interrupts to function - properly, using the callbacks for both APIs would result in interference - between each other. :kconfig:option:`CONFIG_UART_EXCLUSIVE_API_CALLBACKS` - is enabled by default so that only the callbacks associated with one API - is active at a time. + the same time for the same hardware peripheral, since both APIs require + hardware interrupts to function properly. Using the callbacks for both + APIs would result in interference between each other. + :kconfig:option:`CONFIG_UART_EXCLUSIVE_API_CALLBACKS` is enabled by default + so that only the callbacks associated with one API is active at a time. Configuration Options From defab59dc42de70d55115b57bdc1cfc6d5bc4b98 Mon Sep 17 00:00:00 2001 From: Pisit Sawangvonganan Date: Sun, 21 Jan 2024 12:28:12 +0700 Subject: [PATCH 3069/3723] drivers: can: mcp251xfd: reducing number of *reg pointer dereferences Reducing the number of times the code dereferences the pointer *reg, which points to SRAM. By using a local variable tmp for operations before assigning it to *reg. Signed-off-by: Pisit Sawangvonganan --- drivers/can/can_mcp251xfd.c | 147 ++++++++++++++++++++---------------- 1 file changed, 81 insertions(+), 66 deletions(-) diff --git a/drivers/can/can_mcp251xfd.c b/drivers/can/can_mcp251xfd.c index a5b93b19c8f..81d2820f1f7 100644 --- a/drivers/can/can_mcp251xfd.c +++ b/drivers/can/can_mcp251xfd.c @@ -297,6 +297,7 @@ static int mcp251xfd_reg_check_value_wtimeout(const struct device *dev, uint16_t static int mcp251xfd_set_tdc(const struct device *dev, bool is_enabled, int tdc_offset) { uint32_t *reg; + uint32_t tmp; if (is_enabled && (tdc_offset < MCP251XFD_REG_TDC_TDCO_MIN || tdc_offset > MCP251XFD_REG_TDC_TDCO_MAX)) { @@ -306,13 +307,13 @@ static int mcp251xfd_set_tdc(const struct device *dev, bool is_enabled, int tdc_ reg = mcp251xfd_get_spi_buf_ptr(dev); if (is_enabled) { - *reg = FIELD_PREP(MCP251XFD_REG_TDC_TDCMOD_MASK, MCP251XFD_REG_TDC_TDCMOD_AUTO); - *reg |= FIELD_PREP(MCP251XFD_REG_TDC_TDCO_MASK, tdc_offset); + tmp = FIELD_PREP(MCP251XFD_REG_TDC_TDCMOD_MASK, MCP251XFD_REG_TDC_TDCMOD_AUTO); + tmp |= FIELD_PREP(MCP251XFD_REG_TDC_TDCO_MASK, tdc_offset); } else { - *reg = FIELD_PREP(MCP251XFD_REG_TDC_TDCMOD_MASK, MCP251XFD_REG_TDC_TDCMOD_DISABLED); + tmp = FIELD_PREP(MCP251XFD_REG_TDC_TDCMOD_MASK, MCP251XFD_REG_TDC_TDCMOD_DISABLED); } - *reg = sys_cpu_to_le32(*reg); + *reg = sys_cpu_to_le32(tmp); return mcp251xfd_write(dev, MCP251XFD_REG_TDC, MCP251XFD_REG_SIZE); } @@ -417,6 +418,7 @@ static int mcp251xfd_set_timing(const struct device *dev, const struct can_timin { struct mcp251xfd_data *dev_data = dev->data; uint32_t *reg; + uint32_t tmp; int ret; if (!timing) { @@ -430,11 +432,12 @@ static int mcp251xfd_set_timing(const struct device *dev, const struct can_timin k_mutex_lock(&dev_data->mutex, K_FOREVER); reg = mcp251xfd_get_spi_buf_ptr(dev); - *reg = FIELD_PREP(MCP251XFD_REG_NBTCFG_BRP_MASK, timing->prescaler - 1); - *reg |= FIELD_PREP(MCP251XFD_REG_NBTCFG_TSEG1_MASK, + tmp = FIELD_PREP(MCP251XFD_REG_NBTCFG_BRP_MASK, timing->prescaler - 1); + tmp |= FIELD_PREP(MCP251XFD_REG_NBTCFG_TSEG1_MASK, timing->prop_seg + timing->phase_seg1 - 1); - *reg |= FIELD_PREP(MCP251XFD_REG_NBTCFG_TSEG2_MASK, timing->phase_seg2 - 1); - *reg |= FIELD_PREP(MCP251XFD_REG_NBTCFG_SJW_MASK, timing->sjw - 1); + tmp |= FIELD_PREP(MCP251XFD_REG_NBTCFG_TSEG2_MASK, timing->phase_seg2 - 1); + tmp |= FIELD_PREP(MCP251XFD_REG_NBTCFG_SJW_MASK, timing->sjw - 1); + *reg = tmp; ret = mcp251xfd_write(dev, MCP251XFD_REG_NBTCFG, MCP251XFD_REG_SIZE); if (ret < 0) { @@ -452,6 +455,7 @@ static int mcp251xfd_set_timing_data(const struct device *dev, const struct can_ { struct mcp251xfd_data *dev_data = dev->data; uint32_t *reg; + uint32_t tmp; int ret; if (!timing) { @@ -466,13 +470,13 @@ static int mcp251xfd_set_timing_data(const struct device *dev, const struct can_ reg = mcp251xfd_get_spi_buf_ptr(dev); - *reg = FIELD_PREP(MCP251XFD_REG_DBTCFG_BRP_MASK, timing->prescaler - 1); - *reg |= FIELD_PREP(MCP251XFD_REG_DBTCFG_TSEG1_MASK, - timing->prop_seg + timing->phase_seg1 - 1); - *reg |= FIELD_PREP(MCP251XFD_REG_DBTCFG_TSEG2_MASK, timing->phase_seg2 - 1); - *reg |= FIELD_PREP(MCP251XFD_REG_DBTCFG_SJW_MASK, timing->sjw - 1); + tmp = FIELD_PREP(MCP251XFD_REG_DBTCFG_BRP_MASK, timing->prescaler - 1); + tmp |= FIELD_PREP(MCP251XFD_REG_DBTCFG_TSEG1_MASK, + timing->prop_seg + timing->phase_seg1 - 1); + tmp |= FIELD_PREP(MCP251XFD_REG_DBTCFG_TSEG2_MASK, timing->phase_seg2 - 1); + tmp |= FIELD_PREP(MCP251XFD_REG_DBTCFG_SJW_MASK, timing->sjw - 1); - *reg = sys_cpu_to_le32(*reg); + *reg = sys_cpu_to_le32(tmp); dev_data->tdco = timing->prescaler * (timing->prop_seg + timing->phase_seg1); @@ -558,6 +562,7 @@ static int mcp251xfd_add_rx_filter(const struct device *dev, can_rx_callback_t r { struct mcp251xfd_data *dev_data = dev->data; uint32_t *reg; + uint32_t tmp; uint8_t *reg_byte; int filter_idx; int ret; @@ -579,14 +584,14 @@ static int mcp251xfd_add_rx_filter(const struct device *dev, can_rx_callback_t r reg = mcp251xfd_get_spi_buf_ptr(dev); if ((filter->flags & CAN_FILTER_IDE) != 0) { - *reg = FIELD_PREP(MCP251XFD_REG_FLTOBJ_SID_MASK, filter->id >> 18); - *reg |= FIELD_PREP(MCP251XFD_REG_FLTOBJ_EID_MASK, filter->id); - *reg |= MCP251XFD_REG_FLTOBJ_EXIDE; + tmp = FIELD_PREP(MCP251XFD_REG_FLTOBJ_SID_MASK, filter->id >> 18); + tmp |= FIELD_PREP(MCP251XFD_REG_FLTOBJ_EID_MASK, filter->id); + tmp |= MCP251XFD_REG_FLTOBJ_EXIDE; } else { - *reg = FIELD_PREP(MCP251XFD_REG_FLTOBJ_SID_MASK, filter->id); + tmp = FIELD_PREP(MCP251XFD_REG_FLTOBJ_SID_MASK, filter->id); } - *reg = sys_cpu_to_le32(*reg); + *reg = sys_cpu_to_le32(tmp); ret = mcp251xfd_write(dev, MCP251XFD_REG_FLTOBJ(filter_idx), MCP251XFD_REG_SIZE); if (ret < 0) { LOG_ERR("Failed to write FLTOBJ register [%d]", ret); @@ -595,14 +600,14 @@ static int mcp251xfd_add_rx_filter(const struct device *dev, can_rx_callback_t r reg = mcp251xfd_get_spi_buf_ptr(dev); if ((filter->flags & CAN_FILTER_IDE) != 0) { - *reg = FIELD_PREP(MCP251XFD_REG_MASK_MSID_MASK, filter->mask >> 18); - *reg |= FIELD_PREP(MCP251XFD_REG_MASK_MEID_MASK, filter->mask); + tmp = FIELD_PREP(MCP251XFD_REG_MASK_MSID_MASK, filter->mask >> 18); + tmp |= FIELD_PREP(MCP251XFD_REG_MASK_MEID_MASK, filter->mask); } else { - *reg = FIELD_PREP(MCP251XFD_REG_MASK_MSID_MASK, filter->mask); + tmp = FIELD_PREP(MCP251XFD_REG_MASK_MSID_MASK, filter->mask); } - *reg |= MCP251XFD_REG_MASK_MIDE; + tmp |= MCP251XFD_REG_MASK_MIDE; - *reg = sys_cpu_to_le32(*reg); + *reg = sys_cpu_to_le32(tmp); ret = mcp251xfd_write(dev, MCP251XFD_REG_FLTMASK(filter_idx), MCP251XFD_REG_SIZE); if (ret < 0) { @@ -682,6 +687,7 @@ static int mcp251xfd_get_state(const struct device *dev, enum can_state *state, { struct mcp251xfd_data *dev_data = dev->data; uint32_t *reg; + uint32_t tmp; int ret = 0; k_mutex_lock(&dev_data->mutex, K_FOREVER); @@ -692,11 +698,11 @@ static int mcp251xfd_get_state(const struct device *dev, enum can_state *state, goto done; } - *reg = sys_le32_to_cpu(*reg); + tmp = sys_le32_to_cpu(*reg); if (err_cnt != NULL) { - err_cnt->tx_err_cnt = FIELD_GET(MCP251XFD_REG_TREC_TEC_MASK, *reg); - err_cnt->rx_err_cnt = FIELD_GET(MCP251XFD_REG_TREC_REC_MASK, *reg); + err_cnt->tx_err_cnt = FIELD_GET(MCP251XFD_REG_TREC_TEC_MASK, tmp); + err_cnt->rx_err_cnt = FIELD_GET(MCP251XFD_REG_TREC_REC_MASK, tmp); } if (state == NULL) { @@ -708,15 +714,15 @@ static int mcp251xfd_get_state(const struct device *dev, enum can_state *state, goto done; } - if ((*reg & MCP251XFD_REG_TREC_TXBO) != 0) { + if ((tmp & MCP251XFD_REG_TREC_TXBO) != 0) { *state = CAN_STATE_BUS_OFF; - } else if ((*reg & MCP251XFD_REG_TREC_TXBP) != 0) { + } else if ((tmp & MCP251XFD_REG_TREC_TXBP) != 0) { *state = CAN_STATE_ERROR_PASSIVE; - } else if ((*reg & MCP251XFD_REG_TREC_RXBP) != 0) { + } else if ((tmp & MCP251XFD_REG_TREC_RXBP) != 0) { *state = CAN_STATE_ERROR_PASSIVE; - } else if ((*reg & MCP251XFD_REG_TREC_TXWARN) != 0) { + } else if ((tmp & MCP251XFD_REG_TREC_TXWARN) != 0) { *state = CAN_STATE_ERROR_WARNING; - } else if ((*reg & MCP251XFD_REG_TREC_RXWARN) != 0) { + } else if ((tmp & MCP251XFD_REG_TREC_RXWARN) != 0) { *state = CAN_STATE_ERROR_WARNING; } else { *state = CAN_STATE_ERROR_ACTIVE; @@ -905,7 +911,7 @@ static int mcp251xfd_handle_cerrif(const struct device *dev) enum can_state new_state; struct mcp251xfd_data *dev_data = dev->data; struct can_bus_err_cnt err_cnt; - int ret = 0; + int ret; k_mutex_lock(&dev_data->mutex, K_FOREVER); @@ -1024,7 +1030,7 @@ static void mcp251xfd_handle_interrupts(const struct device *dev) reg_int = *reg_int_hw; /* these interrupt flags need to be explicitly cleared */ - if (*reg_int_hw & MCP251XFD_REG_INT_IF_CLEARABLE_MASK) { + if (reg_int & MCP251XFD_REG_INT_IF_CLEARABLE_MASK) { *reg_int_hw &= ~MCP251XFD_REG_INT_IF_CLEARABLE_MASK; @@ -1355,12 +1361,14 @@ static int mcp251xfd_init_timing_struct(struct can_timing *timing, static inline int mcp251xfd_init_con_reg(const struct device *dev) { uint32_t *reg; + uint32_t tmp; reg = mcp251xfd_get_spi_buf_ptr(dev); - *reg = MCP251XFD_REG_CON_ISOCRCEN | MCP251XFD_REG_CON_WAKFIL | MCP251XFD_REG_CON_TXQEN | - MCP251XFD_REG_CON_STEF; - *reg |= FIELD_PREP(MCP251XFD_REG_CON_WFT_MASK, MCP251XFD_REG_CON_WFT_T11FILTER) | + tmp = MCP251XFD_REG_CON_ISOCRCEN | MCP251XFD_REG_CON_WAKFIL | MCP251XFD_REG_CON_TXQEN | + MCP251XFD_REG_CON_STEF; + tmp |= FIELD_PREP(MCP251XFD_REG_CON_WFT_MASK, MCP251XFD_REG_CON_WFT_T11FILTER) | FIELD_PREP(MCP251XFD_REG_CON_REQOP_MASK, MCP251XFD_REG_CON_MODE_CONFIG); + *reg = tmp; return mcp251xfd_write(dev, MCP251XFD_REG_CON, MCP251XFD_REG_SIZE); } @@ -1371,14 +1379,15 @@ static inline int mcp251xfd_init_osc_reg(const struct device *dev) const struct mcp251xfd_config *dev_cfg = dev->config; uint32_t *reg = mcp251xfd_get_spi_buf_ptr(dev); uint32_t reg_value = MCP251XFD_REG_OSC_OSCRDY; + uint32_t tmp; - *reg = FIELD_PREP(MCP251XFD_REG_OSC_CLKODIV_MASK, dev_cfg->clko_div); + tmp = FIELD_PREP(MCP251XFD_REG_OSC_CLKODIV_MASK, dev_cfg->clko_div); if (dev_cfg->pll_enable) { - *reg |= MCP251XFD_REG_OSC_PLLEN; + tmp |= MCP251XFD_REG_OSC_PLLEN; reg_value |= MCP251XFD_REG_OSC_PLLRDY; } - *reg = sys_cpu_to_le32(*reg); + *reg = sys_cpu_to_le32(tmp); ret = mcp251xfd_write(dev, MCP251XFD_REG_OSC, MCP251XFD_REG_SIZE); if (ret < 0) { @@ -1394,6 +1403,7 @@ static inline int mcp251xfd_init_iocon_reg(const struct device *dev) { const struct mcp251xfd_config *dev_cfg = dev->config; uint32_t *reg = mcp251xfd_get_spi_buf_ptr(dev); + uint32_t tmp; /* * MCP2518FD Errata: DS80000789 @@ -1403,14 +1413,14 @@ static inline int mcp251xfd_init_iocon_reg(const struct device *dev) * to do single byte writes instead. */ - *reg = MCP251XFD_REG_IOCON_TRIS0 | MCP251XFD_REG_IOCON_TRIS1 | MCP251XFD_REG_IOCON_PM0 | - MCP251XFD_REG_IOCON_PM1; + tmp = MCP251XFD_REG_IOCON_TRIS0 | MCP251XFD_REG_IOCON_TRIS1 | MCP251XFD_REG_IOCON_PM0 | + MCP251XFD_REG_IOCON_PM1; if (dev_cfg->sof_on_clko) { - *reg |= MCP251XFD_REG_IOCON_SOF; + tmp |= MCP251XFD_REG_IOCON_SOF; } - *reg = sys_cpu_to_le32(*reg); + *reg = sys_cpu_to_le32(tmp); return mcp251xfd_write(dev, MCP251XFD_REG_IOCON, MCP251XFD_REG_SIZE); } @@ -1418,11 +1428,12 @@ static inline int mcp251xfd_init_iocon_reg(const struct device *dev) static inline int mcp251xfd_init_int_reg(const struct device *dev) { uint32_t *reg = mcp251xfd_get_spi_buf_ptr(dev); + uint32_t tmp; - *reg = MCP251XFD_REG_INT_RXIE | MCP251XFD_REG_INT_MODIE | MCP251XFD_REG_INT_TEFIE | - MCP251XFD_REG_INT_CERRIE; + tmp = MCP251XFD_REG_INT_RXIE | MCP251XFD_REG_INT_MODIE | MCP251XFD_REG_INT_TEFIE | + MCP251XFD_REG_INT_CERRIE; - *reg = sys_cpu_to_le32(*reg); + *reg = sys_cpu_to_le32(tmp); return mcp251xfd_write(dev, MCP251XFD_REG_INT, MCP251XFD_REG_SIZE); } @@ -1430,11 +1441,12 @@ static inline int mcp251xfd_init_int_reg(const struct device *dev) static inline int mcp251xfd_init_tef_fifo(const struct device *dev) { uint32_t *reg = mcp251xfd_get_spi_buf_ptr(dev); + uint32_t tmp; - *reg = MCP251XFD_REG_TEFCON_TEFNEIE | MCP251XFD_REG_TEFCON_FRESET; - *reg |= FIELD_PREP(MCP251XFD_REG_TEFCON_FSIZE_MASK, MCP251XFD_TX_QUEUE_ITEMS - 1); + tmp = MCP251XFD_REG_TEFCON_TEFNEIE | MCP251XFD_REG_TEFCON_FRESET; + tmp |= FIELD_PREP(MCP251XFD_REG_TEFCON_FSIZE_MASK, MCP251XFD_TX_QUEUE_ITEMS - 1); - *reg = sys_cpu_to_le32(*reg); + *reg = sys_cpu_to_le32(tmp); return mcp251xfd_write(dev, MCP251XFD_REG_TEFCON, MCP251XFD_REG_SIZE); } @@ -1442,14 +1454,15 @@ static inline int mcp251xfd_init_tef_fifo(const struct device *dev) static inline int mcp251xfd_init_tx_queue(const struct device *dev) { uint32_t *reg = mcp251xfd_get_spi_buf_ptr(dev); + uint32_t tmp; - *reg = MCP251XFD_REG_TXQCON_TXEN | MCP251XFD_REG_TXQCON_FRESET; - *reg |= FIELD_PREP(MCP251XFD_REG_TXQCON_TXAT_MASK, MCP251XFD_REG_TXQCON_TXAT_UNLIMITED); - *reg |= FIELD_PREP(MCP251XFD_REG_TXQCON_FSIZE_MASK, MCP251XFD_TX_QUEUE_ITEMS - 1); - *reg |= FIELD_PREP(MCP251XFD_REG_TXQCON_PLSIZE_MASK, - can_bytes_to_dlc(MCP251XFD_PAYLOAD_SIZE) - 8); + tmp = MCP251XFD_REG_TXQCON_TXEN | MCP251XFD_REG_TXQCON_FRESET; + tmp |= FIELD_PREP(MCP251XFD_REG_TXQCON_TXAT_MASK, MCP251XFD_REG_TXQCON_TXAT_UNLIMITED); + tmp |= FIELD_PREP(MCP251XFD_REG_TXQCON_FSIZE_MASK, MCP251XFD_TX_QUEUE_ITEMS - 1); + tmp |= FIELD_PREP(MCP251XFD_REG_TXQCON_PLSIZE_MASK, + can_bytes_to_dlc(MCP251XFD_PAYLOAD_SIZE) - 8); - *reg = sys_cpu_to_le32(*reg); + *reg = sys_cpu_to_le32(tmp); return mcp251xfd_write(dev, MCP251XFD_REG_TXQCON, MCP251XFD_REG_SIZE); } @@ -1457,16 +1470,17 @@ static inline int mcp251xfd_init_tx_queue(const struct device *dev) static inline int mcp251xfd_init_rx_fifo(const struct device *dev) { uint32_t *reg = mcp251xfd_get_spi_buf_ptr(dev); + uint32_t tmp; - *reg = MCP251XFD_REG_FIFOCON_TFNRFNIE | MCP251XFD_REG_FIFOCON_FRESET; - *reg |= FIELD_PREP(MCP251XFD_REG_FIFOCON_FSIZE_MASK, MCP251XFD_RX_FIFO_ITEMS - 1); - *reg |= FIELD_PREP(MCP251XFD_REG_FIFOCON_PLSIZE_MASK, - can_bytes_to_dlc(MCP251XFD_PAYLOAD_SIZE) - 8); + tmp = MCP251XFD_REG_FIFOCON_TFNRFNIE | MCP251XFD_REG_FIFOCON_FRESET; + tmp |= FIELD_PREP(MCP251XFD_REG_FIFOCON_FSIZE_MASK, MCP251XFD_RX_FIFO_ITEMS - 1); + tmp |= FIELD_PREP(MCP251XFD_REG_FIFOCON_PLSIZE_MASK, + can_bytes_to_dlc(MCP251XFD_PAYLOAD_SIZE) - 8); #if defined(CONFIG_CAN_RX_TIMESTAMP) - *reg |= MCP251XFD_REG_FIFOCON_RXTSEN; + tmp |= MCP251XFD_REG_FIFOCON_RXTSEN; #endif - *reg = sys_cpu_to_le32(*reg); + *reg = sys_cpu_to_le32(tmp); return mcp251xfd_write(dev, MCP251XFD_REG_FIFOCON(MCP251XFD_RX_FIFO_IDX), MCP251XFD_REG_SIZE); @@ -1477,12 +1491,13 @@ static int mcp251xfd_init_tscon(const struct device *dev) { uint32_t *reg = mcp251xfd_get_spi_buf_ptr(dev); const struct mcp251xfd_config *dev_cfg = dev->config; + uint32_t tmp; - *reg = MCP251XFD_REG_TSCON_TBCEN; - *reg |= FIELD_PREP(MCP251XFD_REG_TSCON_TBCPRE_MASK, - dev_cfg->timestamp_prescaler - 1); + tmp = MCP251XFD_REG_TSCON_TBCEN; + tmp |= FIELD_PREP(MCP251XFD_REG_TSCON_TBCPRE_MASK, + dev_cfg->timestamp_prescaler - 1); - *reg = sys_cpu_to_le32(*reg); + *reg = sys_cpu_to_le32(tmp); return mcp251xfd_write(dev, MCP251XFD_REG_TSCON, MCP251XFD_REG_SIZE); } From 50597b2e5287b67cf1e0fd593c595ffe5c45b2e7 Mon Sep 17 00:00:00 2001 From: Laczen JMS Date: Tue, 30 Jan 2024 10:10:54 +0100 Subject: [PATCH 3070/3723] flash: correct userspace flash_handlers fixes #68248 Signed-off-by: Laczen JMS --- drivers/flash/flash_handlers.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/flash/flash_handlers.c b/drivers/flash/flash_handlers.c index ac727b109e7..8c047adbaf4 100644 --- a/drivers/flash/flash_handlers.c +++ b/drivers/flash/flash_handlers.c @@ -94,7 +94,7 @@ static inline int z_vrfy_flash_sfdp_read(const struct device *dev, K_OOPS(K_SYSCALL_MEMORY_WRITE(data, len)); return z_impl_flash_sfdp_read(dev, offset, data, len); } -#include +#include static inline int z_vrfy_flash_read_jedec_id(const struct device *dev, uint8_t *id) @@ -103,7 +103,7 @@ static inline int z_vrfy_flash_read_jedec_id(const struct device *dev, K_OOPS(K_SYSCALL_MEMORY_WRITE(id, 3)); return z_impl_flash_read_jedec_id(dev, id); } -#include +#include #endif /* CONFIG_FLASH_JESD216_API */ From b898541809b85292dd5b6928ab34cad0be23da57 Mon Sep 17 00:00:00 2001 From: Nikolay Agishev Date: Fri, 19 Jan 2024 14:53:53 +0300 Subject: [PATCH 3071/3723] ARC: Disable TLS for some configurations Disable Thread Local Storage for some configurations of ARC architecture. For cores with more then one RGF_NUM_BANKS the parameter is disabled by-default because banks syncronization requires significant time, and it slows down performance. Signed-off-by: Nikolay Agishev --- arch/arc/Kconfig | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/arch/arc/Kconfig b/arch/arc/Kconfig index b9e59adc498..80b46876e10 100644 --- a/arch/arc/Kconfig +++ b/arch/arc/Kconfig @@ -253,6 +253,18 @@ config ARC_USE_UNALIGNED_MEM_ACCESS to support unaligned memory access which is then disabled by default. Enable unaligned access in hardware and make software to use it. +config ARC_CURRENT_THREAD_USE_NO_TLS + bool + select CURRENT_THREAD_USE_NO_TLS + default y if (RGF_NUM_BANKS > 1) || ("$(ZEPHYR_TOOLCHAIN_VARIANT)" = "arcmwdt") + help + Disable current Thread Local Storage for ARC. For cores with more then one + RGF_NUM_BANKS the parameter is disabled by-default because banks syncronization + requires significant time, and it slows down performance. + ARCMWDT works with tls pointer in different way then GCC. Optimized access to + TLS pointer via _current variable does not provide significant advantages + in case of MetaWare. + config FAULT_DUMP int "Fault dump level" default 2 From 548fb97142495383bb83832c8e7b06b332179cae Mon Sep 17 00:00:00 2001 From: Emil Lindqvist Date: Wed, 24 Jan 2024 12:42:36 +0100 Subject: [PATCH 3072/3723] cache: stm32: add new cache API to display and i2s Use sys_cache API to handle cache flush/invalidate. Signed-off-by: Emil Lindqvist --- drivers/display/Kconfig.stm32_ltdc | 1 + drivers/display/display_stm32_ltdc.c | 21 +++------------------ drivers/i2s/Kconfig.stm32 | 1 + drivers/i2s/i2s_ll_stm32.c | 17 ++++------------- 4 files changed, 9 insertions(+), 31 deletions(-) diff --git a/drivers/display/Kconfig.stm32_ltdc b/drivers/display/Kconfig.stm32_ltdc index 12d7856a5e1..11efe766897 100644 --- a/drivers/display/Kconfig.stm32_ltdc +++ b/drivers/display/Kconfig.stm32_ltdc @@ -8,6 +8,7 @@ menuconfig STM32_LTDC default y depends on DT_HAS_ST_STM32_LTDC_ENABLED select USE_STM32_HAL_LTDC + select CACHE_MANAGEMENT if CPU_HAS_DCACHE help Enable driver for STM32 LCT-TFT display controller periheral. diff --git a/drivers/display/display_stm32_ltdc.c b/drivers/display/display_stm32_ltdc.c index 9360180eb08..a70cea32461 100644 --- a/drivers/display/display_stm32_ltdc.c +++ b/drivers/display/display_stm32_ltdc.c @@ -18,6 +18,7 @@ #include #include #include +#include #include LOG_MODULE_REGISTER(display_stm32_ltdc, CONFIG_DISPLAY_LOG_LEVEL); @@ -54,22 +55,6 @@ LOG_MODULE_REGISTER(display_stm32_ltdc, CONFIG_DISPLAY_LOG_LEVEL); #error "Invalid LTDC pixel format chosen" #endif -#if defined(CONFIG_HAS_CMSIS_CORE_M) -#include - -#if defined(CONFIG_DCACHE) -#define CACHE_INVALIDATE(addr, size) SCB_InvalidateDCache_by_Addr((addr), (size)) -#define CACHE_CLEAN(addr, size) SCB_CleanDCache_by_Addr((addr), (size)) -#else -#define CACHE_INVALIDATE(addr, size) -#define CACHE_CLEAN(addr, size) barrier_dsync_fence_full(); -#endif /* CONFIG_DCACHE */ - -#else -#define CACHE_INVALIDATE(addr, size) -#define CACHE_CLEAN(addr, size) -#endif /* CONFIG_HAS_CMSIS_CORE_M */ - struct display_stm32_ltdc_data { LTDC_HandleTypeDef hltdc; enum display_pixel_format current_pixel_format; @@ -215,7 +200,7 @@ static int stm32_ltdc_write(const struct device *dev, const uint16_t x, for (row = 0; row < desc->height; row++) { (void) memcpy(dst, src, desc->width * data->current_pixel_size); - CACHE_CLEAN(dst, desc->width * data->current_pixel_size); + sys_cache_data_flush_range(dst, desc->width * data->current_pixel_size); dst += (config->width * data->current_pixel_size); src += (desc->pitch * data->current_pixel_size); } @@ -252,7 +237,7 @@ static int stm32_ltdc_read(const struct device *dev, const uint16_t x, for (row = 0; row < desc->height; row++) { (void) memcpy(dst, src, desc->width * data->current_pixel_size); - CACHE_CLEAN(dst, desc->width * data->current_pixel_size); + sys_cache_data_flush_range(dst, desc->width * data->current_pixel_size); src += (config->width * data->current_pixel_size); dst += (desc->pitch * data->current_pixel_size); } diff --git a/drivers/i2s/Kconfig.stm32 b/drivers/i2s/Kconfig.stm32 index 26a5e827544..3a4078d9f7a 100644 --- a/drivers/i2s/Kconfig.stm32 +++ b/drivers/i2s/Kconfig.stm32 @@ -7,6 +7,7 @@ menuconfig I2S_STM32 bool "STM32 MCU I2S controller driver" default y depends on DT_HAS_ST_STM32_I2S_ENABLED + select CACHE_MANAGEMENT if CPU_HAS_DCACHE select DMA help Enable I2S support on the STM32 family of processors. diff --git a/drivers/i2s/i2s_ll_stm32.c b/drivers/i2s/i2s_ll_stm32.c index 168e8097dd0..bf06d5f4df7 100644 --- a/drivers/i2s/i2s_ll_stm32.c +++ b/drivers/i2s/i2s_ll_stm32.c @@ -16,22 +16,13 @@ #include #include #include +#include #include "i2s_ll_stm32.h" #include #include LOG_MODULE_REGISTER(i2s_ll_stm32); -#if __DCACHE_PRESENT == 1 -#define DCACHE_INVALIDATE(addr, size) \ - SCB_InvalidateDCache_by_Addr((uint32_t *)addr, size) -#define DCACHE_CLEAN(addr, size) \ - SCB_CleanDCache_by_Addr((uint32_t *)addr, size) -#else -#define DCACHE_INVALIDATE(addr, size) {; } -#define DCACHE_CLEAN(addr, size) {; } -#endif - #define MODULO_INC(val, max) { val = (++val < max) ? val : 0; } static unsigned int div_round_closest(uint32_t dividend, uint32_t divisor) @@ -561,7 +552,7 @@ static void dma_rx_callback(const struct device *dma_dev, void *arg, } /* Assure cache coherency after DMA write operation */ - DCACHE_INVALIDATE(mblk_tmp, stream->cfg.block_size); + sys_cache_data_invd_range(mblk_tmp, stream->cfg.block_size); /* All block data received */ ret = queue_put(&stream->mem_block_queue, mblk_tmp, @@ -632,7 +623,7 @@ static void dma_tx_callback(const struct device *dma_dev, void *arg, k_sem_give(&stream->sem); /* Assure cache coherency before DMA read operation */ - DCACHE_CLEAN(stream->mem_block, mem_block_size); + sys_cache_data_flush_range(stream->mem_block, mem_block_size); ret = reload_dma(stream->dev_dma, stream->dma_channel, &stream->dma_cfg, @@ -794,7 +785,7 @@ static int tx_stream_start(struct stream *stream, const struct device *dev) k_sem_give(&stream->sem); /* Assure cache coherency before DMA read operation */ - DCACHE_CLEAN(stream->mem_block, mem_block_size); + sys_cache_data_flush_range(stream->mem_block, mem_block_size); if (stream->master) { LL_I2S_SetTransferMode(cfg->i2s, LL_I2S_MODE_MASTER_TX); From 62f11055501854a633847f8b413f9cf5b61aad79 Mon Sep 17 00:00:00 2001 From: Guillaume Gautier Date: Wed, 24 Jan 2024 16:12:33 +0100 Subject: [PATCH 3073/3723] drivers: adc: stm32: do not disable adc after measurement Do not disable the ADC after the end of the measurement to avoid systematic enabling which is time-consuming in case the configuration is unchanged. Signed-off-by: Guillaume Gautier --- drivers/adc/adc_stm32.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/adc/adc_stm32.c b/drivers/adc/adc_stm32.c index 158743f7464..0dcb8a77c78 100644 --- a/drivers/adc/adc_stm32.c +++ b/drivers/adc/adc_stm32.c @@ -1086,8 +1086,6 @@ static void adc_context_on_complete(struct adc_context *ctx, int status) ARG_UNUSED(status); - adc_stm32_disable(adc); - /* Reset acquisition time used for the sequence */ data->acq_time_index[0] = -1; data->acq_time_index[1] = -1; @@ -1095,6 +1093,8 @@ static void adc_context_on_complete(struct adc_context *ctx, int status) #if defined(CONFIG_SOC_SERIES_STM32H7X) || defined(CONFIG_SOC_SERIES_STM32U5X) /* Reset channel preselection register */ LL_ADC_SetChannelPreselection(adc, 0); +#else + ARG_UNUSED(adc); #endif /* CONFIG_SOC_SERIES_STM32H7X || CONFIG_SOC_SERIES_STM32U5X */ } From 5c78b3d842ca6e80f257a46f40a7b7948200627c Mon Sep 17 00:00:00 2001 From: Michal Smola Date: Fri, 26 Jan 2024 13:09:45 +0100 Subject: [PATCH 3074/3723] twister: pytest: fix pty import on Windows Import of pty module causes exception when pytest harness is used for device testing on Windows. Fix it by importing pty module on non-windows hosts only. Add logger message for case pty is used by mistake on Windows. Signed-off-by: Michal Smola --- .../src/twister_harness/device/hardware_adapter.py | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) diff --git a/scripts/pylib/pytest-twister-harness/src/twister_harness/device/hardware_adapter.py b/scripts/pylib/pytest-twister-harness/src/twister_harness/device/hardware_adapter.py index 3b7bf5d8214..4a6967b6372 100644 --- a/scripts/pylib/pytest-twister-harness/src/twister_harness/device/hardware_adapter.py +++ b/scripts/pylib/pytest-twister-harness/src/twister_harness/device/hardware_adapter.py @@ -6,7 +6,8 @@ import logging import os -import pty +if os.name != 'nt': + import pty import re import subprocess import time @@ -150,7 +151,13 @@ def _open_serial_pty(self) -> str | None: """Open a pty pair, run process and return tty name""" if not self.device_config.serial_pty: return None - master, slave = pty.openpty() + + try: + master, slave = pty.openpty() + except NameError as exc: + logger.exception('PTY module is not available.') + raise exc + try: self._serial_pty_proc = subprocess.Popen( re.split(',| ', self.device_config.serial_pty), From 1f25531d7ce04af2b27d321c582a41255b7c5e80 Mon Sep 17 00:00:00 2001 From: Michal Smola Date: Fri, 26 Jan 2024 14:40:08 +0100 Subject: [PATCH 3075/3723] twister: pytest: fix missing messages from hardware target When pytest harness test is run on harware, messages sent from target right after application start-up are lost, because connection to COM port is not established yet. It can cause unexpected behavior of a test. Fix it by flashing and running application after connecting to COM port when testing on hardware. Signed-off-by: Michal Smola --- .../src/twister_harness/device/device_adapter.py | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/scripts/pylib/pytest-twister-harness/src/twister_harness/device/device_adapter.py b/scripts/pylib/pytest-twister-harness/src/twister_harness/device/device_adapter.py index ce8492c78b7..b5560650c1b 100644 --- a/scripts/pylib/pytest-twister-harness/src/twister_harness/device/device_adapter.py +++ b/scripts/pylib/pytest-twister-harness/src/twister_harness/device/device_adapter.py @@ -66,11 +66,19 @@ def launch(self) -> None: if not self.command: self.generate_command() - self._flash_and_run() + + if self.device_config.type != 'hardware': + self._flash_and_run() + self._device_run.set() self._start_reader_thread() self.connect() + if self.device_config.type == 'hardware': + # On hardware, flash after connecting to COM port, otherwise some messages + # from target can be lost. + self._flash_and_run() + def close(self) -> None: """Disconnect, close device and close reader thread.""" if not self._device_run.is_set(): From a4c13fc584c835a2f87474aeae77c96a948fea5a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Martin=20J=C3=A4ger?= Date: Sun, 16 Oct 2022 12:20:10 +0200 Subject: [PATCH 3076/3723] lorawan: services: add Class C session handling MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The new functions are required for Multicast Class C session setup. Signed-off-by: Martin Jäger --- subsys/lorawan/services/clock_sync.c | 6 +++ subsys/lorawan/services/lorawan_services.c | 56 ++++++++++++++++++++++ subsys/lorawan/services/lorawan_services.h | 30 ++++++++++++ 3 files changed, 92 insertions(+) diff --git a/subsys/lorawan/services/clock_sync.c b/subsys/lorawan/services/clock_sync.c index 9e4bbe447a0..1c7b32d0072 100644 --- a/subsys/lorawan/services/clock_sync.c +++ b/subsys/lorawan/services/clock_sync.c @@ -174,6 +174,12 @@ static int clock_sync_app_time_req(void) uint8_t tx_pos = 0; uint8_t tx_buf[6]; + if (lorawan_services_class_c_active() > 0) { + /* avoid disturbing the session and causing potential package loss */ + LOG_DBG("AppTimeReq not sent because of active class C session"); + return -EBUSY; + } + tx_buf[tx_pos++] = CLOCK_SYNC_CMD_APP_TIME; tx_pos += clock_sync_serialize_device_time(tx_buf + tx_pos, sizeof(tx_buf) - tx_pos); diff --git a/subsys/lorawan/services/lorawan_services.c b/subsys/lorawan/services/lorawan_services.c index 76a28f80b58..f12478d37d6 100644 --- a/subsys/lorawan/services/lorawan_services.c +++ b/subsys/lorawan/services/lorawan_services.c @@ -35,6 +35,10 @@ static struct k_work_q services_workq; static struct k_work_delayable uplink_work; +/* Number of active class C sessions and mutex to protect access to session info */ +static uint8_t active_class_c_sessions; +static struct k_mutex session_mutex; + /* single-linked list (with pointers) and array for implementation of priority queue */ static struct service_uplink_msg messages[10]; static sys_slist_t msg_list; @@ -160,6 +164,56 @@ int lorawan_services_reschedule_work(struct k_work_delayable *dwork, k_timeout_t return k_work_reschedule_for_queue(&services_workq, dwork, delay); } +int lorawan_services_class_c_start(void) +{ + int ret; + + k_mutex_lock(&session_mutex, K_FOREVER); + + if (active_class_c_sessions == 0) { + ret = lorawan_set_class(LORAWAN_CLASS_C); + if (ret == 0) { + LOG_DBG("Switched to class C"); + active_class_c_sessions++; + ret = active_class_c_sessions; + } + } else { + active_class_c_sessions++; + ret = active_class_c_sessions; + } + + k_mutex_unlock(&session_mutex); + + return ret; +} + +int lorawan_services_class_c_stop(void) +{ + int ret = 0; + + k_mutex_lock(&session_mutex, K_FOREVER); + + if (active_class_c_sessions == 1) { + ret = lorawan_set_class(LORAWAN_CLASS_A); + if (ret == 0) { + LOG_DBG("Reverted to class A"); + active_class_c_sessions--; + } + } else if (active_class_c_sessions > 1) { + active_class_c_sessions--; + ret = active_class_c_sessions; + } + + k_mutex_unlock(&session_mutex); + + return ret; +} + +int lorawan_services_class_c_active(void) +{ + return active_class_c_sessions; +} + static int lorawan_services_init(void) { @@ -173,6 +227,8 @@ static int lorawan_services_init(void) k_work_init_delayable(&uplink_work, uplink_handler); + k_mutex_init(&session_mutex); + k_thread_name_set(&services_workq.thread, "lorawan_services"); return 0; diff --git a/subsys/lorawan/services/lorawan_services.h b/subsys/lorawan/services/lorawan_services.h index 7e1190e971c..18d3c0911a3 100644 --- a/subsys/lorawan/services/lorawan_services.h +++ b/subsys/lorawan/services/lorawan_services.h @@ -58,4 +58,34 @@ int lorawan_services_schedule_uplink(uint8_t port, uint8_t *data, uint8_t len, u int lorawan_services_reschedule_work(struct k_work_delayable *dwork, k_timeout_t delay); +/** + * @brief Start a class C session + * + * If there is already an ongoing class C session, only the internal counter of + * active sessions is incremented. + * + * @returns Number of active sessions if successful or negative errno otherwise. + */ +int lorawan_services_class_c_start(void); + +/** + * @brief Stop class C session and revert to class A + * + * If there is more than one class C session ongoing, only the internal counter + * of active sessions is decremented. + * + * @returns Number of active sessions if successful or negative errno otherwise. + */ +int lorawan_services_class_c_stop(void); + +/** + * @brief Retrieve number of active sessions + * + * Can be used to determine if sessions are ongoing and avoid disturbing an + * ongoing session by sending out unnecessary messages. + * + * @returns Number of active class C sessions. + */ +int lorawan_services_class_c_active(void); + #endif /* ZEPHYR_SUBSYS_LORAWAN_SERVICES_LORAWAN_SERVICES_H_ */ From d833ab746b35cb224aed180aec03d2e6457540af Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Martin=20J=C3=A4ger?= Date: Mon, 22 Aug 2022 17:57:01 +0200 Subject: [PATCH 3077/3723] lorawan: services: add Remote Multicast Setup MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This service is responsible for multicast session key exchange and setting up a class C session. Signed-off-by: Martin Jäger --- subsys/lorawan/services/CMakeLists.txt | 17 +- subsys/lorawan/services/Kconfig | 14 + subsys/lorawan/services/lorawan_services.h | 2 +- subsys/lorawan/services/multicast.c | 285 +++++++++++++++++++++ 4 files changed, 315 insertions(+), 3 deletions(-) create mode 100644 subsys/lorawan/services/multicast.c diff --git a/subsys/lorawan/services/CMakeLists.txt b/subsys/lorawan/services/CMakeLists.txt index 3ace16d75bf..b634efd69b3 100644 --- a/subsys/lorawan/services/CMakeLists.txt +++ b/subsys/lorawan/services/CMakeLists.txt @@ -1,4 +1,17 @@ # SPDX-License-Identifier: Apache-2.0 -zephyr_library_sources_ifdef(CONFIG_LORAWAN_APP_CLOCK_SYNC clock_sync.c) -zephyr_library_sources_ifdef(CONFIG_LORAWAN_SERVICES lorawan_services.c) +if(CONFIG_LORAWAN_SERVICES) + + zephyr_library_sources(lorawan_services.c) + + zephyr_library_sources_ifdef( + CONFIG_LORAWAN_APP_CLOCK_SYNC + clock_sync.c + ) + + zephyr_library_sources_ifdef( + CONFIG_LORAWAN_REMOTE_MULTICAST + multicast.c + ) + +endif() diff --git a/subsys/lorawan/services/Kconfig b/subsys/lorawan/services/Kconfig index face2bf5d5c..6ab6d4e55af 100644 --- a/subsys/lorawan/services/Kconfig +++ b/subsys/lorawan/services/Kconfig @@ -54,4 +54,18 @@ config LORAWAN_APP_CLOCK_SYNC_PERIODICITY Default setting: 24h. +config LORAWAN_REMOTE_MULTICAST + bool "Remote Multicast Setup" + depends on LORAWAN_APP_CLOCK_SYNC + depends on !LORAWAN_NVM_NONE + help + Enables the LoRaWAN Remote Multicast Setup service according to + TS005-1.0.0 as published by the LoRa Alliance. + + The service is run automatically in the background. It is responsible + for multicast session key exchange and setting up a class C session. + The exchanged keys are stored in the non-volatile memory. + + The used default port for this service is 200. + endif # LORAWAN_SERVICES diff --git a/subsys/lorawan/services/lorawan_services.h b/subsys/lorawan/services/lorawan_services.h index 18d3c0911a3..335eb20df5f 100644 --- a/subsys/lorawan/services/lorawan_services.h +++ b/subsys/lorawan/services/lorawan_services.h @@ -25,7 +25,7 @@ enum lorawan_package_id { * Default ports used for LoRaWAN services. */ enum lorawan_services_port { - LORAWAN_PORT_MULTICAST = 200, + LORAWAN_PORT_MULTICAST_SETUP = 200, LORAWAN_PORT_FRAG_TRANSPORT = 201, LORAWAN_PORT_CLOCK_SYNC = 202, }; diff --git a/subsys/lorawan/services/multicast.c b/subsys/lorawan/services/multicast.c new file mode 100644 index 00000000000..c6af76eca1e --- /dev/null +++ b/subsys/lorawan/services/multicast.c @@ -0,0 +1,285 @@ +/* + * Copyright (c) 2022-2024 Martin Jäger + * Copyright (c) 2022-2024 tado GmbH + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include "lorawan_services.h" +#include "../lw_priv.h" + +#include +#include +#include +#include +#include + +#include + +LOG_MODULE_REGISTER(lorawan_multicast, CONFIG_LORAWAN_SERVICES_LOG_LEVEL); + +/** + * Version of LoRaWAN Remote Multicast Setup Specification + * + * This implementation only supports TS005-1.0.0. + */ +#define MULTICAST_PACKAGE_VERSION 1 + +/** + * Maximum expected number of multicast commands per packet + * + * The standard states "A message MAY carry more than one command". Even though this was not + * observed during testing, space for up to 3 packages is reserved. + */ +#define MAX_MULTICAST_CMDS_PER_PACKAGE 3 + +/** Maximum length of multicast answers */ +#define MAX_MULTICAST_ANS_LEN 5 + +enum multicast_commands { + MULTICAST_CMD_PKG_VERSION = 0x00, + MULTICAST_CMD_MC_GROUP_STATUS = 0x01, + MULTICAST_CMD_MC_GROUP_SETUP = 0x02, + MULTICAST_CMD_MC_GROUP_DELETE = 0x03, + MULTICAST_CMD_MC_CLASS_C_SESSION = 0x04, + MULTICAST_CMD_MC_CLASS_B_SESSION = 0x05, +}; + +struct multicast_context { + struct k_work_delayable session_start_work; + struct k_work_delayable session_stop_work; +}; + +static struct multicast_context ctx[LORAMAC_MAX_MC_CTX]; + +static void multicast_session_start(struct k_work *work) +{ + int ret; + + ret = lorawan_services_class_c_start(); + if (ret < 0) { + LOG_WRN("Failed to switch to class C: %d. Retrying in 1s.", ret); + lorawan_services_reschedule_work(k_work_delayable_from_work(work), K_SECONDS(1)); + } +} + +static void multicast_session_stop(struct k_work *work) +{ + int ret; + + ret = lorawan_services_class_c_stop(); + if (ret < 0) { + LOG_WRN("Failed to revert to class A: %d. Retrying in 1s.", ret); + lorawan_services_reschedule_work(k_work_delayable_from_work(work), K_SECONDS(1)); + } +} + +/** + * Schedule Class C session if valid timing is found + * + * @returns time to start (negative in case of missed start) + */ +static int32_t multicast_schedule_class_c_session(uint8_t id, uint32_t session_time, + uint32_t session_timeout) +{ + uint32_t current_time; + int32_t time_to_start; + int err; + + err = lorawan_clock_sync_get(¤t_time); + time_to_start = session_time - current_time; + + if (err != 0 || time_to_start > 0xFFFFFF) { + LOG_ERR("Clocks not synchronized, cannot schedule class C session"); + + /* truncate value to indicates that clocks are out of sync */ + time_to_start = 0xFFFFFF; + } else if (time_to_start >= 0) { + LOG_DBG("Starting class C session in %d s", time_to_start); + + lorawan_services_reschedule_work(&ctx[id].session_start_work, + K_SECONDS(time_to_start)); + + lorawan_services_reschedule_work(&ctx[id].session_stop_work, + K_SECONDS(time_to_start + session_timeout)); + } + + return time_to_start; +} + +static void multicast_package_callback(uint8_t port, bool data_pending, int16_t rssi, int8_t snr, + uint8_t len, const uint8_t *rx_buf) +{ + uint8_t tx_buf[MAX_MULTICAST_CMDS_PER_PACKAGE * MAX_MULTICAST_ANS_LEN]; + uint8_t tx_pos = 0; + uint8_t rx_pos = 0; + + __ASSERT(port == LORAWAN_PORT_MULTICAST_SETUP, "Wrong port %d", port); + + while (rx_pos < len) { + uint8_t command_id = rx_buf[rx_pos++]; + + if (sizeof(tx_buf) - tx_pos < MAX_MULTICAST_ANS_LEN) { + LOG_ERR("insufficient tx_buf size, some requests discarded"); + break; + } + + switch (command_id) { + case MULTICAST_CMD_PKG_VERSION: + tx_buf[tx_pos++] = MULTICAST_CMD_PKG_VERSION; + tx_buf[tx_pos++] = LORAWAN_PACKAGE_ID_REMOTE_MULTICAST_SETUP; + tx_buf[tx_pos++] = MULTICAST_PACKAGE_VERSION; + LOG_DBG("PackageVersionReq"); + break; + case MULTICAST_CMD_MC_GROUP_STATUS: + LOG_ERR("McGroupStatusReq not implemented"); + return; + case MULTICAST_CMD_MC_GROUP_SETUP: { + uint8_t id = rx_buf[rx_pos++] & 0x03; + McChannelParams_t channel = { + .IsRemotelySetup = true, + .IsEnabled = true, + .GroupID = (AddressIdentifier_t)id, + .RxParams = {0}, + }; + + channel.Address = sys_get_le32(rx_buf + rx_pos); + rx_pos += sizeof(uint32_t); + + /* the key is copied in LoRaMacMcChannelSetup (cast to discard const) */ + channel.McKeys.McKeyE = (uint8_t *)rx_buf + rx_pos; + rx_pos += 16; + + channel.FCountMin = sys_get_le32(rx_buf + rx_pos); + rx_pos += sizeof(uint32_t); + + channel.FCountMax = sys_get_le32(rx_buf + rx_pos); + rx_pos += sizeof(uint32_t); + + LOG_DBG("McGroupSetupReq id: %u, addr: 0x%.8X, fcnt_min: %u, fcnt_max: %u", + id, channel.Address, channel.FCountMin, channel.FCountMax); + + LoRaMacStatus_t ret = LoRaMacMcChannelSetup(&channel); + + tx_buf[tx_pos++] = MULTICAST_CMD_MC_GROUP_SETUP; + if (ret == LORAMAC_STATUS_OK) { + tx_buf[tx_pos++] = id; + } else if (ret == LORAMAC_STATUS_MC_GROUP_UNDEFINED) { + /* set IDerror flag */ + tx_buf[tx_pos++] = (1U << 2) | id; + } else { + LOG_ERR("McGroupSetupReq failed: %s", lorawan_status2str(ret)); + return; + } + break; + } + case MULTICAST_CMD_MC_GROUP_DELETE: { + uint8_t id = rx_buf[rx_pos++] & 0x03; + + LoRaMacStatus_t ret = LoRaMacMcChannelDelete((AddressIdentifier_t)id); + + LOG_DBG("McGroupDeleteReq id: %d", id); + + tx_buf[tx_pos++] = MULTICAST_CMD_MC_GROUP_DELETE; + if (ret == LORAMAC_STATUS_OK) { + tx_buf[tx_pos++] = id; + } else if (ret == LORAMAC_STATUS_MC_GROUP_UNDEFINED) { + /* set McGroupUndefined flag */ + tx_buf[tx_pos++] = (1U << 2) | id; + } else { + LOG_ERR("McGroupDeleteReq failed: %s", lorawan_status2str(ret)); + return; + } + break; + } + case MULTICAST_CMD_MC_CLASS_C_SESSION: { + uint32_t session_time; + uint32_t session_timeout; + uint8_t status = 0x00; + uint8_t id = rx_buf[rx_pos++] & 0x03; + McRxParams_t rx_params; + + session_time = sys_get_le32(rx_buf + rx_pos); + rx_pos += sizeof(uint32_t); + + session_timeout = 1U << (rx_buf[rx_pos++] & 0x0F); + + rx_params.Class = CLASS_C; + + rx_params.Params.ClassC.Frequency = sys_get_le24(rx_buf + rx_pos) * 100; + rx_pos += 3; + + rx_params.Params.ClassC.Datarate = rx_buf[rx_pos++]; + + LOG_DBG("McClassCSessionReq time: %u, timeout: %u, freq: %u, DR: %d", + session_time, session_timeout, rx_params.Params.ClassC.Frequency, + rx_params.Params.ClassC.Datarate); + + LoRaMacStatus_t ret = LoRaMacMcChannelSetupRxParams((AddressIdentifier_t)id, + &rx_params, &status); + + tx_buf[tx_pos++] = MULTICAST_CMD_MC_CLASS_C_SESSION; + if (ret == LORAMAC_STATUS_OK) { + int32_t time_to_start; + + time_to_start = multicast_schedule_class_c_session(id, session_time, + session_timeout); + if (time_to_start >= 0) { + tx_buf[tx_pos++] = status; + sys_put_le24(time_to_start, tx_buf + tx_pos); + tx_pos += 3; + } else { + LOG_ERR("Missed class C session start at %d in %d s", + session_time, time_to_start); + /* set StartMissed flag */ + tx_buf[tx_pos++] = (1U << 5) | status; + } + } else { + LOG_ERR("McClassCSessionReq failed: %s", lorawan_status2str(ret)); + if (ret == LORAMAC_STATUS_MC_GROUP_UNDEFINED) { + /* set McGroupUndefined flag */ + tx_buf[tx_pos++] = (1U << 4) | status; + } else if (ret == LORAMAC_STATUS_FREQ_AND_DR_INVALID) { + /* set FreqError and DR Error flags */ + tx_buf[tx_pos++] = (3U << 2) | status; + return; + } + } + break; + } + case MULTICAST_CMD_MC_CLASS_B_SESSION: + LOG_ERR("McClassBSessionReq not implemented"); + return; + default: + return; + } + } + + if (tx_pos > 0) { + /* Random delay 2+-1 seconds according to RP002-1.0.3, chapter 2.3 */ + uint32_t delay = 1 + sys_rand32_get() % 3; + + lorawan_services_schedule_uplink(LORAWAN_PORT_MULTICAST_SETUP, tx_buf, tx_pos, + delay); + } +} + +static struct lorawan_downlink_cb downlink_cb = { + .port = (uint8_t)LORAWAN_PORT_MULTICAST_SETUP, + .cb = multicast_package_callback, +}; + +static int multicast_init(void) +{ + for (int i = 0; i < ARRAY_SIZE(ctx); i++) { + k_work_init_delayable(&ctx[i].session_start_work, multicast_session_start); + k_work_init_delayable(&ctx[i].session_stop_work, multicast_session_stop); + } + + lorawan_register_downlink_callback(&downlink_cb); + + return 0; +} + +/* initialization must be after lorawan_init in lorawan.c */ +SYS_INIT(multicast_init, POST_KERNEL, 1); From 60c58fe91801e69aa1d443b5196b934596f6f3fd Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Martin=20J=C3=A4ger?= Date: Sat, 13 Jan 2024 12:46:11 +0100 Subject: [PATCH 3078/3723] samples: subsys: lorawan: class_a: add multicast support MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This is mainly to make sure that the multicast code is built in CI. Signed-off-by: Martin Jäger --- samples/subsys/lorawan/class_a/README.rst | 13 ++++++++++++- .../subsys/lorawan/class_a/overlay-multicast.conf | 9 +++++++++ samples/subsys/lorawan/class_a/sample.yaml | 5 +++++ 3 files changed, 26 insertions(+), 1 deletion(-) create mode 100644 samples/subsys/lorawan/class_a/overlay-multicast.conf diff --git a/samples/subsys/lorawan/class_a/README.rst b/samples/subsys/lorawan/class_a/README.rst index 3a7a7944997..c29853ae064 100644 --- a/samples/subsys/lorawan/class_a/README.rst +++ b/samples/subsys/lorawan/class_a/README.rst @@ -30,7 +30,8 @@ Extended Configuration ********************** This sample can be configured to run the application-layer clock -synchronization service in the background. +synchronization service and/or the remote multicast setup service +in the background. The following commands build and flash the sample with clock synchronization enabled. @@ -41,3 +42,13 @@ enabled. :goals: build flash :gen-args: -DEXTRA_CONF_FILE=overlay-clock-sync.conf :compact: + +The following commands build and flash the sample with remote multicast setup +enabled. + +.. zephyr-app-commands:: + :zephyr-app: samples/subsys/lorawan/class_a + :board: nucleo_wl55jc + :goals: build flash + :gen-args: -DEXTRA_CONF_FILE=overlay-multicast.conf + :compact: diff --git a/samples/subsys/lorawan/class_a/overlay-multicast.conf b/samples/subsys/lorawan/class_a/overlay-multicast.conf new file mode 100644 index 00000000000..6bd51655643 --- /dev/null +++ b/samples/subsys/lorawan/class_a/overlay-multicast.conf @@ -0,0 +1,9 @@ +# NVS required to store LoRaWAN DevNonce and multicast sessions +CONFIG_NVS=y +CONFIG_SETTINGS=y +CONFIG_LORAWAN_NVM_SETTINGS=y + +CONFIG_LORAWAN_SERVICES=y +CONFIG_LORAWAN_SERVICES_LOG_LEVEL_DBG=y +CONFIG_LORAWAN_APP_CLOCK_SYNC=y +CONFIG_LORAWAN_REMOTE_MULTICAST=y diff --git a/samples/subsys/lorawan/class_a/sample.yaml b/samples/subsys/lorawan/class_a/sample.yaml index fb0a3c0de30..7a757da815d 100644 --- a/samples/subsys/lorawan/class_a/sample.yaml +++ b/samples/subsys/lorawan/class_a/sample.yaml @@ -49,3 +49,8 @@ tests: filter: CONFIG_ENTROPY_HAS_DRIVER integration_platforms: - nucleo_wl55jc + sample.lorawan.class_a.multicast: + extra_args: OVERLAY_CONFIG="overlay-multicast.conf" + filter: CONFIG_ENTROPY_HAS_DRIVER + integration_platforms: + - nucleo_wl55jc From 0282e7042dd0c64d14b954e00171e4b3d300d3ae Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Benjamin=20Cab=C3=A9?= Date: Mon, 29 Jan 2024 21:17:09 +0100 Subject: [PATCH 3079/3723] MAINTAINERS: fix incorrect files-exclude entry for NXP Drivers MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Typo in a files-exclude entry is causing get_maintainer.py script to error out under certain conditions Signed-off-by: Benjamin Cabé --- MAINTAINERS.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/MAINTAINERS.yml b/MAINTAINERS.yml index 5a8a4cf15fc..2df43c77a11 100644 --- a/MAINTAINERS.yml +++ b/MAINTAINERS.yml @@ -3255,7 +3255,7 @@ NXP Drivers: - dts/bindings/*/nxp* files-exclude: - drivers/*/*s32* - - drivers/misc/*/*s32*/ + - drivers/misc/*/*s32* - include/zephyr/dt-bindings/*/*s32* - include/zephyr/drivers/*/*s32* - dts/bindings/*/*s32* From b4191dd67e4b3555794ff462a176f1a81356b9e2 Mon Sep 17 00:00:00 2001 From: Abderrahmane Jarmouni Date: Fri, 26 Jan 2024 15:52:04 +0100 Subject: [PATCH 3080/3723] samples: drivers: display: add a general test case Add a test case for boards that have a supported built-in display that is enabled by default in DTS. This will make it easier to catch display regressions on these boards in CI. Signed-off-by: Abderrahmane Jarmouni --- samples/drivers/display/sample.yaml | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/samples/drivers/display/sample.yaml b/samples/drivers/display/sample.yaml index ba93efd5c2e..579773f3c8c 100644 --- a/samples/drivers/display/sample.yaml +++ b/samples/drivers/display/sample.yaml @@ -146,3 +146,11 @@ tests: - CONFIG_IDLE_STACK_SIZE=400 harness_config: fixture: fixture_display + sample.display.builtin: + # This test case is intended to insure that this sample builds & runs + # correctly for all boards that have a supported built-in display. + filter: dt_chosen_enabled("zephyr,display") + harness: console + harness_config: + fixture: fixture_display + tags: display From 47f9ee405dd918cec8333d4f21f38d63a9f37bdb Mon Sep 17 00:00:00 2001 From: Abderrahmane Jarmouni Date: Fri, 26 Jan 2024 15:55:02 +0100 Subject: [PATCH 3081/3723] samples: subsys: display: lvgl: add test case for stm32h747i_disco Add a test case for stm32h747i_disco that comes with a display shield. This will make it easier to catch LVGL regressions on this board. Signed-off-by: Abderrahmane Jarmouni --- samples/subsys/display/lvgl/sample.yaml | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/samples/subsys/display/lvgl/sample.yaml b/samples/subsys/display/lvgl/sample.yaml index c57ab87122b..3c6e56cdfe1 100644 --- a/samples/subsys/display/lvgl/sample.yaml +++ b/samples/subsys/display/lvgl/sample.yaml @@ -40,3 +40,17 @@ tests: - mimxrt595_evk_cm33 integration_platforms: - mimxrt1170_evk_cm7 + sample.subsys.display.lvgl.st_b_lcd40_dsi1_mb1166: + platform_allow: stm32h747i_disco_m7 + extra_args: SHIELD=st_b_lcd40_dsi1_mb1166 + harness: console + harness_config: + fixture: fixture_display + modules: + - lvgl + tags: + - samples + - display + - shield + - lvgl + - gui From 43b2f00c84ac888a2e391a819b5b3f5761e1f785 Mon Sep 17 00:00:00 2001 From: Abderrahmane Jarmouni Date: Fri, 26 Jan 2024 15:56:26 +0100 Subject: [PATCH 3082/3723] samples: modules: lvgl: demos: add test case for stm32h747i_disco Add a test case for stm32h747i_disco that comes with a display shield. This will make it easier to catch LVGL regressions on this board. Signed-off-by: Abderrahmane Jarmouni --- samples/modules/lvgl/demos/sample.yaml | 22 +++++++++++++++++++++- 1 file changed, 21 insertions(+), 1 deletion(-) diff --git a/samples/modules/lvgl/demos/sample.yaml b/samples/modules/lvgl/demos/sample.yaml index b928d9f37f0..2b9939eb4fd 100644 --- a/samples/modules/lvgl/demos/sample.yaml +++ b/samples/modules/lvgl/demos/sample.yaml @@ -6,7 +6,11 @@ common: - lvgl harness: none filter: dt_chosen_enabled("zephyr,display") - tags: samples lvgl display gui + tags: + - samples + - display + - lvgl + - gui tests: sample.modules.lvgl.demo_music: extra_configs: @@ -17,3 +21,19 @@ tests: sample.modules.lvgl.demo_stress: extra_configs: - CONFIG_LV_Z_DEMO_STRESS=y + sample.modules.lvgl.demos.st_b_lcd40_dsi1_mb1166: + platform_allow: stm32h747i_disco_m7 + extra_args: SHIELD=st_b_lcd40_dsi1_mb1166 + harness: console + harness_config: + fixture: fixture_display + extra_configs: + - CONFIG_LV_Z_DEMO_BENCHMARK=y + modules: + - lvgl + tags: + - samples + - display + - shield + - lvgl + - gui From ff436674975474dd028c38fd335c6813bac51c91 Mon Sep 17 00:00:00 2001 From: Flavio Ceolin Date: Mon, 22 Jan 2024 23:22:19 -0800 Subject: [PATCH 3083/3723] intel_adsp/ace: power: Restore PS after power gate We are arbitrarily setting a value to PS after power gates and losing valid information like OWB, CALLINC and INTLEVEL. We need to properly save/restore them to avoid possible wrong behavior. Signed-off-by: Flavio Ceolin --- soc/xtensa/intel_adsp/ace/power.c | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/soc/xtensa/intel_adsp/ace/power.c b/soc/xtensa/intel_adsp/ace/power.c index 4ef8575645a..878d6a58bc2 100644 --- a/soc/xtensa/intel_adsp/ace/power.c +++ b/soc/xtensa/intel_adsp/ace/power.c @@ -111,6 +111,7 @@ struct core_state { uint32_t excsave3; uint32_t thread_ptr; uint32_t intenable; + uint32_t ps; uint32_t bctl; }; @@ -127,6 +128,7 @@ struct lpsram_header { static ALWAYS_INLINE void _save_core_context(uint32_t core_id) { + core_desc[core_id].ps = XTENSA_RSR("PS"); core_desc[core_id].vecbase = XTENSA_RSR("VECBASE"); core_desc[core_id].excsave2 = XTENSA_RSR("EXCSAVE2"); core_desc[core_id].excsave3 = XTENSA_RSR("EXCSAVE3"); @@ -140,6 +142,7 @@ static ALWAYS_INLINE void _restore_core_context(void) { uint32_t core_id = arch_proc_id(); + XTENSA_WSR("PS", core_desc[core_id].ps); XTENSA_WSR("VECBASE", core_desc[core_id].vecbase); XTENSA_WSR("EXCSAVE2", core_desc[core_id].excsave2); XTENSA_WSR("EXCSAVE3", core_desc[core_id].excsave3); @@ -404,6 +407,11 @@ void pm_state_exit_post_ops(enum pm_state state, uint8_t substate_id) } z_xt_ints_on(core_desc[cpu].intenable); + + /* We don't have the key used to lock interruptions here. + * Just set PS.INTLEVEL to 0. + */ + __asm__ volatile ("rsil a2, 0"); } #endif /* CONFIG_PM */ From 3e5a593de9f52b0ed96cf99dec21bbea8277e597 Mon Sep 17 00:00:00 2001 From: Flavio Ceolin Date: Sat, 20 Jan 2024 00:36:59 +0000 Subject: [PATCH 3084/3723] intel_adsp/cavs: power: Fix INTLEVEL value In pm_state_set we can't just call k_cpu_idle() because this will clear out PS.INTLEVEL. Use k_cpu_atomic_idle instead since Zephyr's expect interruptions to be locked after pm_state_set. Signed-off-by: Flavio Ceolin --- soc/xtensa/intel_adsp/cavs/power.c | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/soc/xtensa/intel_adsp/cavs/power.c b/soc/xtensa/intel_adsp/cavs/power.c index 3ae758ced61..f21a09910d3 100644 --- a/soc/xtensa/intel_adsp/cavs/power.c +++ b/soc/xtensa/intel_adsp/cavs/power.c @@ -163,7 +163,7 @@ void pm_state_set(enum pm_state state, uint8_t substate_id) /* do power down - this function won't return */ power_down_cavs(true, uncache_to_cache(&hpsram_mask[0])); } else { - k_cpu_idle(); + k_cpu_atomic_idle(arch_irq_lock()); } } else { __ASSERT(false, "invalid argument - unsupported power state"); @@ -183,6 +183,12 @@ void pm_state_exit_post_ops(enum pm_state state, uint8_t substate_id) } else { __ASSERT(false, "invalid argument - unsupported power state"); } + + /** + * We don't have the key used to lock interruptions here. + * Just set PS.INTLEVEL to 0. + */ + __asm__ volatile ("rsil a2, 0"); } #endif /* CONFIG_PM */ From 479c40c8307c88147d6a37f1f22047a22413bfad Mon Sep 17 00:00:00 2001 From: Joel Guittet Date: Wed, 10 Jan 2024 21:58:07 +0100 Subject: [PATCH 3085/3723] boards: arm: wio terminal: separate buttons and joystick definition The purpose of this separation is to avoid conflict initializing gpio-keys because button 0 and joystick up have a shared interrupt source. Joystick is now configured using polling mode option. Signed-off-by: Joel Guittet --- boards/arm/wio_terminal/wio_terminal.dts | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/boards/arm/wio_terminal/wio_terminal.dts b/boards/arm/wio_terminal/wio_terminal.dts index 2e2fe7500a0..99e07373526 100644 --- a/boards/arm/wio_terminal/wio_terminal.dts +++ b/boards/arm/wio_terminal/wio_terminal.dts @@ -48,7 +48,7 @@ }; /* Buttons */ - gpio_keys { + buttons: buttons { compatible = "gpio-keys"; user_button_0: button_0 { label = "User Button 0"; @@ -65,6 +65,13 @@ gpios = <&portc 28 GPIO_ACTIVE_LOW>; zephyr,code = ; }; + }; + + /* Joystick */ + joystick: joystick { + compatible = "gpio-keys"; + polling-mode; + debounce-interval-ms = <100>; joy_sel: joystick_selection { label = "joystick selection"; gpios = <&portd 10 GPIO_ACTIVE_LOW>; From 017b01659f8dbe427f6c42e8e921be09c2b260b5 Mon Sep 17 00:00:00 2001 From: Joel Guittet Date: Wed, 24 Jan 2024 21:59:58 +0100 Subject: [PATCH 3086/3723] samples: subsys: display: lvgl: add wio_terminal board Add Wio Terminal configuration to the LVGL sample with button and keypad overlay. Signed-off-by: Joel Guittet --- .../display/lvgl/boards/wio_terminal.conf | 1 + .../display/lvgl/boards/wio_terminal.overlay | 23 +++++++++++++++++++ 2 files changed, 24 insertions(+) create mode 100644 samples/subsys/display/lvgl/boards/wio_terminal.conf create mode 100644 samples/subsys/display/lvgl/boards/wio_terminal.overlay diff --git a/samples/subsys/display/lvgl/boards/wio_terminal.conf b/samples/subsys/display/lvgl/boards/wio_terminal.conf new file mode 100644 index 00000000000..de103d88fed --- /dev/null +++ b/samples/subsys/display/lvgl/boards/wio_terminal.conf @@ -0,0 +1 @@ +CONFIG_INPUT=y diff --git a/samples/subsys/display/lvgl/boards/wio_terminal.overlay b/samples/subsys/display/lvgl/boards/wio_terminal.overlay new file mode 100644 index 00000000000..2f9e228cd82 --- /dev/null +++ b/samples/subsys/display/lvgl/boards/wio_terminal.overlay @@ -0,0 +1,23 @@ +/* + * Copyright (c) 2024 Joel Guittet + * SPDX-License-Identifier: Apache-2.0 + */ + +#include +#include + +/ { + lvgl_button_input { + compatible = "zephyr,lvgl-button-input"; + input = <&buttons>; + input-codes = ; + coordinates = <160 120>; + }; + + lvgl_keypad_input { + compatible = "zephyr,lvgl-keypad-input"; + input = <&joystick>; + input-codes = ; + lvgl-codes = ; + }; +}; From 5ef7404c7cdffd50a8a7d23fdb879ea614f7da2a Mon Sep 17 00:00:00 2001 From: Gerard Marull-Paretas Date: Tue, 30 Jan 2024 16:19:00 +0100 Subject: [PATCH 3087/3723] drivers: spi: ifx_cat1: drop non-existing DT properties It looks like driver references quite a few non-existing properties in devicetree (see dts/bindings/spi/infineon,cat1-spi.yml). This mistake was hidden because of DT_INST_PROP_OR(), which expands to the default if the property is not present. However, after 260fc89643fd64b74f9983065867d8b368f81a0d, the issue became visible because sme DT_INST_PROP_OR() were changed to DT_INST_PROP(). Note that only fields not initialized to 0 (or false) have been kept. Signed-off-by: Gerard Marull-Paretas --- drivers/spi/spi_ifx_cat1.c | 23 +++++------------------ 1 file changed, 5 insertions(+), 18 deletions(-) diff --git a/drivers/spi/spi_ifx_cat1.c b/drivers/spi/spi_ifx_cat1.c index c1423a9c6cb..dd5295c3960 100644 --- a/drivers/spi/spi_ifx_cat1.c +++ b/drivers/spi/spi_ifx_cat1.c @@ -333,24 +333,11 @@ static int ifx_cat1_spi_init(const struct device *dev) .rxDataWidth = 8, /* overwrite by cfg */ \ .txDataWidth = 8, /* overwrite by cfg */ \ .enableMsbFirst = true, /* overwrite by cfg */ \ - .subMode = DT_INST_PROP_OR(n, sub_mode, CY_SCB_SPI_MOTOROLA), \ - .oversample = \ - DT_INST_PROP_OR(n, oversample, IFX_CAT1_SPI_DEFAULT_OVERSAMPLE), \ - .enableFreeRunSclk = DT_INST_PROP(n, enable_free_run_sclk), \ - .enableInputFilter = DT_INST_PROP(n, enable_input_filter), \ - .enableMisoLateSample = \ - DT_INST_PROP_OR(n, enable_miso_late_sample, true), \ - .enableTransferSeperation = \ - DT_INST_PROP(n, enable_transfer_seperation), \ - .enableWakeFromSleep = DT_INST_PROP(n, enableWakeFromSleep), \ - .ssPolarity = DT_INST_PROP_OR(n, ss_polarity, CY_SCB_SPI_ACTIVE_LOW), \ - .rxFifoTriggerLevel = DT_INST_PROP_OR(n, rx_fifo_trigger_level, 0), \ - .rxFifoIntEnableMask = DT_INST_PROP_OR(n, rx_fifo_int_enable_mask, 0), \ - .txFifoTriggerLevel = DT_INST_PROP_OR(n, tx_fifo_trigger_level, 0), \ - .txFifoIntEnableMask = DT_INST_PROP_OR(n, tx_fifo_int_enable_mask, 0), \ - .masterSlaveIntEnableMask = \ - DT_INST_PROP_OR(n, master_slave_int_enable_mask, 0)}, \ - \ + .subMode = CY_SCB_SPI_MOTOROLA, \ + .oversample = IFX_CAT1_SPI_DEFAULT_OVERSAMPLE, \ + .enableMisoLateSample = true, \ + .ssPolarity = CY_SCB_SPI_ACTIVE_LOW, \ + }, \ .irq_priority = DT_INST_IRQ(n, priority), \ }; \ DEVICE_DT_INST_DEFINE(n, &ifx_cat1_spi_init, NULL, &spi_cat1_data_##n, \ From ab97a44096b30628603ef9ca1e7d5198f20b1b6e Mon Sep 17 00:00:00 2001 From: Wei-Tai Lee Date: Tue, 30 Jan 2024 11:26:04 +0800 Subject: [PATCH 3088/3723] drivers: i2c: andes: Remove the inclusion of soc.h Remove the inclusion of empty file which will cause twister-build error. Signed-off-by: Wei-Tai Lee --- drivers/i2c/i2c_andes_atciic100.h | 1 - 1 file changed, 1 deletion(-) diff --git a/drivers/i2c/i2c_andes_atciic100.h b/drivers/i2c/i2c_andes_atciic100.h index 1aa0ff6f397..9312427ee8e 100644 --- a/drivers/i2c/i2c_andes_atciic100.h +++ b/drivers/i2c/i2c_andes_atciic100.h @@ -10,7 +10,6 @@ #include #include #include -#include #include #include #include From bff1b7487e857c4976456e78c3972e657a5e46c4 Mon Sep 17 00:00:00 2001 From: Chaitanya Tata Date: Fri, 26 Jan 2024 21:42:44 +0530 Subject: [PATCH 3089/3723] wifi: shell: Add band support for STA For a Wi-Fi station the connect API supports both band and channel configuration, but for a shell command either channel or band makes sense, so, overload the channel field to support band. Rejig the band and channel validation to support all modes. Signed-off-by: Chaitanya Tata --- subsys/net/l2/wifi/wifi_shell.c | 53 ++++++++++++++++++++++++--------- 1 file changed, 39 insertions(+), 14 deletions(-) diff --git a/subsys/net/l2/wifi/wifi_shell.c b/subsys/net/l2/wifi/wifi_shell.c index 7d56952ecbd..d84dbb39c8e 100644 --- a/subsys/net/l2/wifi/wifi_shell.c +++ b/subsys/net/l2/wifi/wifi_shell.c @@ -467,7 +467,14 @@ static int __wifi_args_to_params(size_t argc, char *argv[], /* Channel (optional: STA, mandatory: AP) */ if ((idx < argc) && (strlen(argv[idx]) <= 3)) { + uint8_t band; long channel = strtol(argv[idx], &endptr, 10); + const uint8_t all_bands[] = {WIFI_FREQ_BAND_2_4_GHZ, + WIFI_FREQ_BAND_5_GHZ, + WIFI_FREQ_BAND_6_GHZ}; + bool found = false; + char bands_str[MAX_BANDS_STR_LEN] = {0}; + size_t offset = 0; if (*endptr != '\0') { print(context.sh, SHELL_ERROR, @@ -478,23 +485,40 @@ static int __wifi_args_to_params(size_t argc, char *argv[], return -EINVAL; } - if (iface_mode == WIFI_MODE_INFRA && channel == 0) { - params->channel = WIFI_CHANNEL_ANY; + if (iface_mode == WIFI_MODE_INFRA) { + if (channel < 0) { + /* Negative channel means band */ + switch (-channel) { + case 2: + params->band = WIFI_FREQ_BAND_2_4_GHZ; + break; + case 5: + params->band = WIFI_FREQ_BAND_5_GHZ; + break; + case 6: + params->band = WIFI_FREQ_BAND_6_GHZ; + break; + default: + print(context.sh, SHELL_ERROR, + "Invalid band: %ld\n", channel); + return -EINVAL; + } + } } else { - const uint8_t bands[] = {WIFI_FREQ_BAND_2_4_GHZ, - WIFI_FREQ_BAND_5_GHZ, - WIFI_FREQ_BAND_6_GHZ}; - uint8_t band; - bool found = false; - char bands_str[MAX_BANDS_STR_LEN] = {0}; - size_t offset = 0; - - for (band = 0; band < ARRAY_SIZE(bands); band++) { + if (channel < 0) { + print(context.sh, SHELL_ERROR, + "Invalid channel: %ld\n", channel); + return -EINVAL; + } + } + + if (channel > 0) { + for (band = 0; band < ARRAY_SIZE(all_bands); band++) { offset += snprintf(bands_str + offset, sizeof(bands_str) - offset, "%s%s", band ? "," : "", - wifi_band_txt(bands[band])); + wifi_band_txt(all_bands[band])); if (offset >= sizeof(bands_str)) { print(context.sh, SHELL_ERROR, "Failed to parse channel: %s: " @@ -503,7 +527,7 @@ static int __wifi_args_to_params(size_t argc, char *argv[], return -EINVAL; } - if (wifi_utils_validate_chan(bands[band], + if (wifi_utils_validate_chan(all_bands[band], channel)) { found = true; break; @@ -1899,7 +1923,8 @@ SHELL_STATIC_SUBCMD_SET_CREATE(wifi_commands, SHELL_CMD_ARG(connect, NULL, "Connect to a Wi-Fi AP\n" "\"\"\n" - "[channel number: 0 means all]\n" + "[channel number/band: > 0:Channel, 0:any channel,\n" + "< 0:band (-2:2.4GHz, -5:5GHz, -6:6GHz]\n" "[PSK: valid only for secure SSIDs]\n" "[Security type: valid only for secure SSIDs]\n" "0:None, 1:WPA2-PSK, 2:WPA2-PSK-256, 3:SAE, 4:WAPI, 5:EAP, 6:WEP, 7: WPA-PSK\n" From ba81d439e4fe5b8fb874f1687712a42c6cd60350 Mon Sep 17 00:00:00 2001 From: Alberto Escolar Piedras Date: Tue, 23 Jan 2024 15:51:51 +0100 Subject: [PATCH 3090/3723] doc coding_guidelines: Exclude host tooling from rule A.5 Rule A.5 is meant for code build with the embedded libCs and which runs in embedded targets. Let's be more clear about this and explicitly indicate that host tooling is not covered by it. Otherwise, the current "The "Zephyr codebase" in this context refers to all source code files committed to the main Zephyr repository" covers too much. Signed-off-by: Alberto Escolar Piedras --- doc/contribute/coding_guidelines/index.rst | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/doc/contribute/coding_guidelines/index.rst b/doc/contribute/coding_guidelines/index.rst index a5777454eb5..4677da2e86e 100644 --- a/doc/contribute/coding_guidelines/index.rst +++ b/doc/contribute/coding_guidelines/index.rst @@ -1441,9 +1441,12 @@ shall be limited to the functions, excluding the Annex K "Bounds-checking interfaces", from the ISO/IEC 9899:2011 standard, also known as C11, unless exempted by this rule. -The "Zephyr codebase" in this context refers to all source code files committed +The "Zephyr codebase" in this context refers to all embedded source code files committed to the `main Zephyr repository`_, except the Zephyr kernel as defined by the :ref:`coding_guideline_libc_usage_restrictions_in_zephyr_kernel`. +With embedded source code we refer to code which is meant to be executed in embedded +targets, and therefore excludes host tooling, and code specific for the +:ref:`native ` test targets. The following non-ISO 9899:2011, hereinafter referred to as non-standard, functions and macros are exempt from this rule and allowed to be used in the From b097e3198f5ce415c03efc19eed718febb88e955 Mon Sep 17 00:00:00 2001 From: Guillaume Gautier Date: Mon, 27 Nov 2023 12:14:52 +0100 Subject: [PATCH 3091/3723] drivers: clock: wba: add get status function Add a function to get the clock status on STM32WBA Signed-off-by: Guillaume Gautier --- drivers/clock_control/clock_stm32_ll_wba.c | 26 ++++++++++++++++++++++ 1 file changed, 26 insertions(+) diff --git a/drivers/clock_control/clock_stm32_ll_wba.c b/drivers/clock_control/clock_stm32_ll_wba.c index 111cebff6b2..bbc6e1ef393 100644 --- a/drivers/clock_control/clock_stm32_ll_wba.c +++ b/drivers/clock_control/clock_stm32_ll_wba.c @@ -260,10 +260,36 @@ static int stm32_clock_control_get_subsys_rate(const struct device *dev, return 0; } +static enum clock_control_status stm32_clock_control_get_status(const struct device *dev, + clock_control_subsys_t sub_system) +{ + struct stm32_pclken *pclken = (struct stm32_pclken *)sub_system; + + ARG_UNUSED(dev); + + if (IN_RANGE(pclken->bus, STM32_PERIPH_BUS_MIN, STM32_PERIPH_BUS_MAX) == true) { + /* Gated clocks */ + if ((sys_read32(DT_REG_ADDR(DT_NODELABEL(rcc)) + pclken->bus) & pclken->enr) + == pclken->enr) { + return CLOCK_CONTROL_STATUS_ON; + } else { + return CLOCK_CONTROL_STATUS_OFF; + } + } else { + /* Domain clock sources */ + if (enabled_clock(pclken->bus) == 0) { + return CLOCK_CONTROL_STATUS_ON; + } else { + return CLOCK_CONTROL_STATUS_OFF; + } + } +} + static struct clock_control_driver_api stm32_clock_control_api = { .on = stm32_clock_control_on, .off = stm32_clock_control_off, .get_rate = stm32_clock_control_get_subsys_rate, + .get_status = stm32_clock_control_get_status, .configure = stm32_clock_control_configure, }; From 624139ad9acda2357353dd28ee3a5050a1c00c1f Mon Sep 17 00:00:00 2001 From: Guillaume Gautier Date: Fri, 12 Jan 2024 10:01:12 +0100 Subject: [PATCH 3092/3723] drivers: clock_control: stm32wba: remove disabling of backup access Disabling Backup access prevents Suspend to RAM to work. Signed-off-by: Guillaume Gautier --- drivers/clock_control/clock_stm32_ll_wba.c | 2 -- 1 file changed, 2 deletions(-) diff --git a/drivers/clock_control/clock_stm32_ll_wba.c b/drivers/clock_control/clock_stm32_ll_wba.c index bbc6e1ef393..5cc3b8651c7 100644 --- a/drivers/clock_control/clock_stm32_ll_wba.c +++ b/drivers/clock_control/clock_stm32_ll_wba.c @@ -484,8 +484,6 @@ static void set_up_fixed_clock_sources(void) /* Wait till LSESYS is ready */ while (!LL_RCC_LSE_IsPropagationReady()) { } - - LL_PWR_DisableBkUpAccess(); } } From 6b681bcbcc688cc6276d01bd7f22991811cec0ed Mon Sep 17 00:00:00 2001 From: Guillaume Gautier Date: Tue, 7 Nov 2023 09:31:12 +0100 Subject: [PATCH 3093/3723] soc: arm: stm32wba: add support for standby mode with ram retention Add support for STM32WBA Standby low-power mode with RAM retention. Signed-off-by: Guillaume Gautier --- .../stm32wba/Kconfig.defconfig.series | 22 +++ soc/arm/st_stm32/stm32wba/power.c | 126 +++++++++++++++--- soc/arm/st_stm32/stm32wba/soc.c | 3 +- soc/arm/st_stm32/stm32wba/soc.h | 3 + 4 files changed, 131 insertions(+), 23 deletions(-) diff --git a/soc/arm/st_stm32/stm32wba/Kconfig.defconfig.series b/soc/arm/st_stm32/stm32wba/Kconfig.defconfig.series index a1099228e5f..340b62049e8 100644 --- a/soc/arm/st_stm32/stm32wba/Kconfig.defconfig.series +++ b/soc/arm/st_stm32/stm32wba/Kconfig.defconfig.series @@ -39,4 +39,26 @@ config ENTROPY_STM32_CLK_CHECK endif +if PM_S2RAM + +config COUNTER + default y + +config COUNTER_RTC_STM32_SUBSECONDS + default y + +config STM32_LPTIM_STDBY_TIMER + default y + +config TICKLESS_KERNEL + default y + +config COUNTER_RTC_STM32_SAVE_VALUE_BETWEEN_RESETS + default y + +config IDLE_STACK_SIZE + default 512 + +endif + endif # SOC_SERIES_STM32WBAX diff --git a/soc/arm/st_stm32/stm32wba/power.c b/soc/arm/st_stm32/stm32wba/power.c index 89d9f5e72ed..1565c59cfc6 100644 --- a/soc/arm/st_stm32/stm32wba/power.c +++ b/soc/arm/st_stm32/stm32wba/power.c @@ -7,6 +7,8 @@ #include #include #include +#include +#include #include #include @@ -24,7 +26,25 @@ LOG_MODULE_DECLARE(soc, CONFIG_SOC_LOG_LEVEL); -void set_mode_stop(uint8_t substate_id) +static int stm32_power_init(void); + +static void disable_cache(void) +{ + /* Disabling ICACHE */ + LL_ICACHE_Disable(); + while (LL_ICACHE_IsEnabled() == 1U) { + } + + /* Wait until ICACHE_SR.BUSYF is cleared */ + while (LL_ICACHE_IsActiveFlag_BUSY() == 1U) { + } + + /* Wait until ICACHE_SR.BSYENDF is set */ + while (LL_ICACHE_IsActiveFlag_BSYEND() == 0U) { + } +} + +static void set_mode_stop(uint8_t substate_id) { LL_PWR_ClearFlag_STOP(); @@ -33,10 +53,7 @@ void set_mode_stop(uint8_t substate_id) /* Erratum 2.2.15: * Disabling ICACHE is required before entering stop mode */ - LL_ICACHE_Disable(); - while (LL_ICACHE_IsEnabled() == 1U) { - } - + disable_cache(); #ifdef CONFIG_BT_STM32WBA scm_setwaitstates(LP); @@ -60,35 +77,76 @@ void set_mode_stop(uint8_t substate_id) } } +#if defined(CONFIG_PM_S2RAM) +static int suspend_to_ram(void) +{ + LL_LPM_EnableDeepSleep(); + + while (LL_PWR_IsActiveFlag_ACTVOS() == 0) { + } + + /* Select mode entry : WFE or WFI and enter the CPU selected mode */ + k_cpu_idle(); + + return 0; +} + +static void set_mode_suspend_to_ram(void) +{ + /* Enable SRAM full retention */ + LL_PWR_SetSRAM1SBRetention(LL_PWR_SRAM1_SB_FULL_RETENTION); + LL_PWR_SetSRAM2SBRetention(LL_PWR_SRAM2_SB_FULL_RETENTION); + + /* Enable RTC wakeup + * This configures an internal pin that generates an event to wakeup the system + */ + LL_PWR_EnableWakeUpPin(LL_PWR_WAKEUP_PIN7); + LL_PWR_SetWakeUpPinSignal3Selection(LL_PWR_WAKEUP_PIN7); + + /* Clear flags */ + LL_PWR_ClearFlag_SB(); + LL_PWR_ClearFlag_WU(); + LL_RCC_ClearResetFlags(); + + disable_cache(); + + /* Select standby mode */ + LL_PWR_SetPowerMode(LL_PWR_MODE_STANDBY); + + /* Save context and enter Standby mode */ + arch_pm_s2ram_suspend(suspend_to_ram); + + /* Execution is restored at this point after wake up */ + /* Restore system clock as soon as we exit standby mode */ + sys_clock_idle_exit(); +} +#endif + /* Invoke Low Power/System Off specific Tasks */ void pm_state_set(enum pm_state state, uint8_t substate_id) { switch (state) { case PM_STATE_SUSPEND_TO_IDLE: set_mode_stop(substate_id); + + /* Select mode entry : WFE or WFI and enter the CPU selected mode */ + k_cpu_idle(); + break; - case PM_STATE_STANDBY: - /* Not supported today */ - __fallthrough; +#if defined(CONFIG_PM_S2RAM) + case PM_STATE_SUSPEND_TO_RAM: + set_mode_suspend_to_ram(); + break; +#endif default: LOG_DBG("Unsupported power state %u", state); return; } - - /* Select mode entry : WFE or WFI and enter the CPU selected mode */ - k_cpu_idle(); } /* Handle SOC specific activity after Low Power Mode Exit */ void pm_state_exit_post_ops(enum pm_state state, uint8_t substate_id) { - /* Erratum 2.2.15: - * Enable ICACHE when exiting stop mode - */ - LL_ICACHE_Enable(); - while (LL_ICACHE_IsEnabled() == 0U) { - } - #ifdef CONFIG_BT_STM32WBA if (LL_PWR_IsActiveFlag_STOP() == 1U) { scm_setup(); @@ -100,16 +158,33 @@ void pm_state_exit_post_ops(enum pm_state state, uint8_t substate_id) switch (state) { case PM_STATE_SUSPEND_TO_IDLE: if (substate_id <= 2) { + /* Erratum 2.2.15: + * Enable ICACHE when exiting stop mode + */ + LL_ICACHE_SetMode(LL_ICACHE_1WAY); + LL_ICACHE_Enable(); + while (LL_ICACHE_IsEnabled() == 0U) { + } + LL_LPM_DisableSleepOnExit(); LL_LPM_EnableSleep(); } else { LOG_DBG("Unsupported power substate-id %u", substate_id); } - case PM_STATE_STANDBY: - /* To be tested */ - LL_LPM_EnableSleep(); + break; case PM_STATE_SUSPEND_TO_RAM: +#if defined(CONFIG_PM_S2RAM) + stm32wba_init(); + stm32_power_init(); + + LL_LPM_DisableSleepOnExit(); + LL_LPM_EnableSleep(); +#else + LOG_DBG("Suspend to RAM needs CONFIG_PM_S2RAM to be enabled"); +#endif + break; + case PM_STATE_STANDBY: __fallthrough; case PM_STATE_SUSPEND_TO_DISK: __fallthrough; @@ -141,6 +216,15 @@ static int stm32_power_init(void) LL_AHB4_GRP1_EnableClock(LL_AHB4_GRP1_PERIPH_PWR); +#ifdef CONFIG_DEBUG + LL_DBGMCU_EnableDBGStandbyMode(); + LL_DBGMCU_APB7_GRP1_FreezePeriph(LL_DBGMCU_APB7_GRP1_RTC_STOP); + LL_DBGMCU_APB7_GRP1_FreezePeriph(LL_DBGMCU_APB7_GRP1_LPTIM1_STOP); +#else + LL_DBGMCU_DisableDBGStandbyMode(); +#endif + + /* Enabling Ultra Low power mode */ LL_PWR_EnableUltraLowPowerMode(); LL_FLASH_EnableSleepPowerDown(); diff --git a/soc/arm/st_stm32/stm32wba/soc.c b/soc/arm/st_stm32/stm32wba/soc.c index b0e2a439b5a..c3f12078e8d 100644 --- a/soc/arm/st_stm32/stm32wba/soc.c +++ b/soc/arm/st_stm32/stm32wba/soc.c @@ -32,7 +32,7 @@ LOG_MODULE_REGISTER(soc); * * @return 0 */ -static int stm32wba_init(void) +int stm32wba_init(void) { /* Enable instruction cache in 1-way (direct mapped cache) */ LL_ICACHE_SetMode(LL_ICACHE_1WAY); @@ -51,7 +51,6 @@ static int stm32wba_init(void) LL_PWR_SetRegulatorSupply(LL_PWR_LDO_SUPPLY); #endif - return 0; } diff --git a/soc/arm/st_stm32/stm32wba/soc.h b/soc/arm/st_stm32/stm32wba/soc.h index ef41f7adf8a..0c337ea9e22 100644 --- a/soc/arm/st_stm32/stm32wba/soc.h +++ b/soc/arm/st_stm32/stm32wba/soc.h @@ -17,6 +17,9 @@ #include +/* function exported to the soc power.c */ +int stm32wba_init(void); + #endif /* !_ASMLANGUAGE */ #endif /* _STM32WBA_SOC_H_ */ From 7ba1f2e6d884d093b59cecc32e4fd108a4eac599 Mon Sep 17 00:00:00 2001 From: Guillaume Gautier Date: Tue, 7 Nov 2023 09:32:00 +0100 Subject: [PATCH 3094/3723] dts: arm: stm32wba: add standby mode to device tree Add standby mode to device tree Signed-off-by: Guillaume Gautier --- dts/arm/st/wba/stm32wba.dtsi | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/dts/arm/st/wba/stm32wba.dtsi b/dts/arm/st/wba/stm32wba.dtsi index 2d00be8ef53..4ae45491f7f 100644 --- a/dts/arm/st/wba/stm32wba.dtsi +++ b/dts/arm/st/wba/stm32wba.dtsi @@ -22,6 +22,7 @@ chosen { zephyr,entropy = &rng; zephyr,flash-controller = &flash; + st,lptim-stdby-timer = &rtc; }; cpus { @@ -32,7 +33,7 @@ device_type = "cpu"; compatible = "arm,cortex-m33"; reg = <0>; - cpu-power-states = <&stop0 &stop1>; + cpu-power-states = <&stop0 &stop1 &standby>; #address-cells = <1>; #size-cells = <1>; @@ -55,6 +56,13 @@ substate-id = <2>; min-residency-us = <500>; }; + standby: state2 { + compatible = "zephyr,power-state"; + power-state-name = "suspend-to-ram"; + substate-id = <1>; + min-residency-us = <1000>; + exit-latency-us = <50>; + }; }; }; From 05712250eafe73f6a7568fa245189a8bc0781dbd Mon Sep 17 00:00:00 2001 From: Guillaume Gautier Date: Tue, 7 Nov 2023 09:33:57 +0100 Subject: [PATCH 3095/3723] samples: boards: stm32: pm: suspend_to_ram: add wba standby sample Add a sample for STM32WBA standby power management. Signed-off-by: Guillaume Gautier --- .../power_mgmt/suspend_to_ram/CMakeLists.txt | 7 + .../power_mgmt/suspend_to_ram/README.rst | 42 +++++ .../boards/nucleo_wba55cg.overlay | 48 +++++ .../stm32/power_mgmt/suspend_to_ram/prj.conf | 8 + .../power_mgmt/suspend_to_ram/sample.yaml | 17 ++ .../power_mgmt/suspend_to_ram/src/main.c | 164 ++++++++++++++++++ 6 files changed, 286 insertions(+) create mode 100644 samples/boards/stm32/power_mgmt/suspend_to_ram/CMakeLists.txt create mode 100644 samples/boards/stm32/power_mgmt/suspend_to_ram/README.rst create mode 100644 samples/boards/stm32/power_mgmt/suspend_to_ram/boards/nucleo_wba55cg.overlay create mode 100644 samples/boards/stm32/power_mgmt/suspend_to_ram/prj.conf create mode 100644 samples/boards/stm32/power_mgmt/suspend_to_ram/sample.yaml create mode 100644 samples/boards/stm32/power_mgmt/suspend_to_ram/src/main.c diff --git a/samples/boards/stm32/power_mgmt/suspend_to_ram/CMakeLists.txt b/samples/boards/stm32/power_mgmt/suspend_to_ram/CMakeLists.txt new file mode 100644 index 00000000000..8e813b2d175 --- /dev/null +++ b/samples/boards/stm32/power_mgmt/suspend_to_ram/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(stm32_pm_suspend_to_ram) + +target_sources(app PRIVATE src/main.c) diff --git a/samples/boards/stm32/power_mgmt/suspend_to_ram/README.rst b/samples/boards/stm32/power_mgmt/suspend_to_ram/README.rst new file mode 100644 index 00000000000..246ac96ea10 --- /dev/null +++ b/samples/boards/stm32/power_mgmt/suspend_to_ram/README.rst @@ -0,0 +1,42 @@ +.. _stm32-pm-suspend-to-ram-sample: + +STM32 PM Suspend to RAM +####################### + +Overview +******** + +This sample is a minimum application to demonstrate basic power management +behavior in a basic blinking LED set up using the :ref:`GPIO API ` in +low power context + ADC measurements and entropy. + +.. _stm32-pm-suspend-to-ram-sample-requirements: + +Requirements +************ + +The board should support enabling PM. For a STM32 based target, it means that +it should support a clock source alternative to Cortex Systick that can be used +in core sleep states, as LPTIM (:dtcompatible:`st,stm32-lptim`). +The board shall have an RTC to use it during the standby mode as a replacement +for LPTIM (which is disabled). The board shall also have RAM retention to be +able to restore context after standby. + +Building and Running +******************** + +Build and flash Blinky as follows, changing ``stm32wba55cg`` for your board: + +.. zephyr-app-commands:: + :zephyr-app: samples/boards/stm32/power_mgmt/suspend_to_ram + :board: stm32wba55cg + :goals: build flash + :compact: + +After flashing, the LED starts to blink. + +PM configurations +***************** + +By default, :kconfig:option:`CONFIG_PM_DEVICE` and :kconfig:option:`CONFIG_PM_DEVICE_RUNTIME` +are enabled. diff --git a/samples/boards/stm32/power_mgmt/suspend_to_ram/boards/nucleo_wba55cg.overlay b/samples/boards/stm32/power_mgmt/suspend_to_ram/boards/nucleo_wba55cg.overlay new file mode 100644 index 00000000000..3ed3dab7a88 --- /dev/null +++ b/samples/boards/stm32/power_mgmt/suspend_to_ram/boards/nucleo_wba55cg.overlay @@ -0,0 +1,48 @@ +/* + * SPDX-License-Identifier: Apache-2.0 + * + * Copyright (c) 2023 STMicroelectronics + */ + +/ { + /* Change min residency time to ease power consumption measurement */ + cpus { + power-states { + stop0: state0 { + min-residency-us = <500000>; + exit-latency-us = <50>; + }; + stop1: state1 { + min-residency-us = <1000000>; + exit-latency-us = <100>; + }; + standby: state2 { + min-residency-us = <2000000>; + exit-latency-us = <1000>; + }; + }; + }; + + zephyr,user { + /* adjust channel number according to pinmux in board.dts */ + io-channels = <&adc4 8>; + }; +}; + +&lptim1 { + status = "okay"; +}; + +&adc4 { + pinctrl-0 = <&adc4_in8_pa1>; + #address-cells = <1>; + #size-cells = <0>; + + channel@8 { + reg = <8>; + zephyr,gain = "ADC_GAIN_1"; + zephyr,reference = "ADC_REF_INTERNAL"; + zephyr,acquisition-time = ; + zephyr,resolution = <12>; + }; +}; diff --git a/samples/boards/stm32/power_mgmt/suspend_to_ram/prj.conf b/samples/boards/stm32/power_mgmt/suspend_to_ram/prj.conf new file mode 100644 index 00000000000..acef64bb9a8 --- /dev/null +++ b/samples/boards/stm32/power_mgmt/suspend_to_ram/prj.conf @@ -0,0 +1,8 @@ +CONFIG_PM=y +CONFIG_PM_DEVICE=y +CONFIG_PM_DEVICE_RUNTIME=y +CONFIG_PM_DEVICE_RUNTIME_EXCLUSIVE=n +CONFIG_PM_S2RAM=y +CONFIG_ADC=y +CONFIG_ENTROPY_GENERATOR=y +#CONFIG_DEBUG=y diff --git a/samples/boards/stm32/power_mgmt/suspend_to_ram/sample.yaml b/samples/boards/stm32/power_mgmt/suspend_to_ram/sample.yaml new file mode 100644 index 00000000000..f7eb4383664 --- /dev/null +++ b/samples/boards/stm32/power_mgmt/suspend_to_ram/sample.yaml @@ -0,0 +1,17 @@ +sample: + name: STM32 PM Standby Power Management +tests: + sample.boards.stm32.power_mgmt.suspend_to_ram: + tags: + - power + harness: console + harness_config: + type: one_line + regex: + - "Exit Standby" + filter: dt_compat_enabled("zephyr,power-state") and + dt_enabled_alias_with_parent_compat("led0", "gpio-leds") and + dt_compat_enabled("st,stm32-lptim") + extra_args: "CONFIG_DEBUG=y" + platform_allow: + - nucleo_wba55cg diff --git a/samples/boards/stm32/power_mgmt/suspend_to_ram/src/main.c b/samples/boards/stm32/power_mgmt/suspend_to_ram/src/main.c new file mode 100644 index 00000000000..bb1ca9dbb55 --- /dev/null +++ b/samples/boards/stm32/power_mgmt/suspend_to_ram/src/main.c @@ -0,0 +1,164 @@ +/* + * Copyright (c) 2024 STMicroelectronics + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#define SLEEP_TIME_STOP0_MS 800 +#define SLEEP_TIME_STOP1_MS 1500 +#define SLEEP_TIME_STANDBY_MS 3000 +#define SLEEP_TIME_BUSY_MS 2000 + +static const struct gpio_dt_spec led = + GPIO_DT_SPEC_GET(DT_ALIAS(led0), gpios); + +#if !DT_NODE_EXISTS(DT_PATH(zephyr_user)) || \ + !DT_NODE_HAS_PROP(DT_PATH(zephyr_user), io_channels) +#error "No suitable devicetree overlay specified" +#endif + +#define DT_SPEC_AND_COMMA(node_id, prop, idx) \ + ADC_DT_SPEC_GET_BY_IDX(node_id, idx), + +/* Data of ADC io-channels specified in devicetree. */ +static const struct adc_dt_spec adc_channels[] = { + DT_FOREACH_PROP_ELEM(DT_PATH(zephyr_user), io_channels, + DT_SPEC_AND_COMMA) +}; + +const struct device *rng_dev; + +#define BUFFER_LENGTH 3 + +static uint8_t entropy_buffer[BUFFER_LENGTH] = {0}; + +static int adc_test(void) +{ + int err; + static uint32_t count; + uint16_t buf; + struct adc_sequence sequence = { + .buffer = &buf, + /* buffer size in bytes, not number of samples */ + .buffer_size = sizeof(buf), + }; + + /* Configure channels individually prior to sampling. */ + for (size_t i = 0U; i < ARRAY_SIZE(adc_channels); i++) { + if (!adc_is_ready_dt(&adc_channels[i])) { + printk("ADC controller device %s not ready\n", adc_channels[i].dev->name); + return 0; + } + + err = adc_channel_setup_dt(&adc_channels[i]); + if (err < 0) { + printk("Could not setup channel #%d (%d)\n", i, err); + return 0; + } + } + + printk("ADC reading[%u]:\n", count++); + for (size_t i = 0U; i < ARRAY_SIZE(adc_channels); i++) { + int32_t val_mv; + + printk("- %s, channel %d: ", + adc_channels[i].dev->name, + adc_channels[i].channel_id); + + (void)adc_sequence_init_dt(&adc_channels[i], &sequence); + + err = adc_read_dt(&adc_channels[i], &sequence); + if (err < 0) { + printk("Could not read (%d)\n", err); + continue; + } + + /* + * If using differential mode, the 16 bit value + * in the ADC sample buffer should be a signed 2's + * complement value. + */ + if (adc_channels[i].channel_cfg.differential) { + val_mv = (int32_t)((int16_t)buf); + } else { + val_mv = (int32_t)buf; + } + printk("%"PRId32, val_mv); + err = adc_raw_to_millivolts_dt(&adc_channels[i], + &val_mv); + /* conversion to mV may not be supported, skip if not */ + if (err < 0) { + printk(" (value in mV not available)\n"); + } else { + printk(" = %"PRId32" mV\n", val_mv); + } + } + + return 0; +} + +void print_buf(uint8_t *buffer) +{ + int i; + int count = 0; + + for (i = 0; i < BUFFER_LENGTH; i++) { + printk(" 0x%02x", buffer[i]); + if (buffer[i] == 0x00) { + count++; + } + } + printk("\n"); +} + +int main(void) +{ + __ASSERT_NO_MSG(gpio_is_ready_dt(&led)); + + rng_dev = DEVICE_DT_GET(DT_CHOSEN(zephyr_entropy)); + if (!device_is_ready(rng_dev)) { + printk("error: random device not ready"); + } + + printk("Device ready\n"); + + while (true) { + gpio_pin_configure_dt(&led, GPIO_OUTPUT_ACTIVE); + adc_test(); + k_busy_wait(SLEEP_TIME_BUSY_MS*1000); + gpio_pin_set_dt(&led, 0); + k_msleep(SLEEP_TIME_STOP0_MS); + printk("Exit Stop0\n"); + + gpio_pin_set_dt(&led, 1); + adc_test(); + k_busy_wait(SLEEP_TIME_BUSY_MS*1000); + gpio_pin_set_dt(&led, 0); + k_msleep(SLEEP_TIME_STOP1_MS); + printk("Exit Stop1\n"); + + (void)memset(entropy_buffer, 0x00, BUFFER_LENGTH); + entropy_get_entropy(rng_dev, (char *)entropy_buffer, BUFFER_LENGTH); + printk("Sync entropy: "); + print_buf(entropy_buffer); + + gpio_pin_set_dt(&led, 1); + adc_test(); + k_busy_wait(SLEEP_TIME_BUSY_MS*1000); + gpio_pin_configure_dt(&led, GPIO_DISCONNECTED); + k_msleep(SLEEP_TIME_STANDBY_MS); + printk("Exit Standby\n"); + } + return 0; +} From 6f5626d1cfd851a737c197b2731152b97c406206 Mon Sep 17 00:00:00 2001 From: Adam Wojasinski Date: Thu, 11 Jan 2024 21:31:59 +0100 Subject: [PATCH 3096/3723] posix: Add basic sysconf() function implementation The patch introduces basic implementation of sysconf() function. It's based on macro - that means that every function call is resolved at compile time - and is not fully complient with POSIX standard (the errno value is not handled and passing invalid name argument results in compilation error). Treat this commit as a starting point for proper sysconf() implementation. The one introduced in the patch could stay as a defult implementation. sysconf() documentation: https://pubs.opengroup.org/onlinepubs/9699919799/functions/sysconf.html https://man7.org/linux/man-pages/man3/sysconf.3.html Fixes #56670 Signed-off-by: Adam Wojasinski --- include/zephyr/posix/unistd.h | 332 ++++++++++++++++++++++++++++++++++ lib/posix/Kconfig | 17 ++ 2 files changed, 349 insertions(+) diff --git a/include/zephyr/posix/unistd.h b/include/zephyr/posix/unistd.h index 84faf7c1c8f..4d683d0fdb1 100644 --- a/include/zephyr/posix/unistd.h +++ b/include/zephyr/posix/unistd.h @@ -11,16 +11,217 @@ #ifdef CONFIG_NETWORKING /* For zsock_gethostname() */ #include +#include #endif #ifdef CONFIG_POSIX_API #include #endif +#ifdef CONFIG_POSIX_SYSCONF +#include +#endif + #ifdef __cplusplus extern "C" { #endif +/* Version test macros */ +#define _POSIX_VERSION 200809L +#define _POSIX2_VERSION (-1L) +#define _XOPEN_VERSION (-1L) + +/* Internal helper macro to set constant if required Kconfig symbol is enabled */ +#define Z_SC_VAL_IFDEF(_def, _val) COND_CODE_1(_def, (_val), (-1L)) + +/* Constants for Opitions and Option Groups */ +#define _POSIX_ADVISORY_INFO (-1L) +#define _POSIX_ASYNCHRONOUS_IO (-1L) +#define _POSIX_BARRIERS Z_SC_VAL_IFDEF(CONFIG_PTHREAD_IPC, _POSIX_VERSION) +#define _POSIX_CHOWN_RESTRICTED (-1L) +#define _POSIX_CLOCK_SELECTION Z_SC_VAL_IFDEF(CONFIG_POSIX_CLOCK, _POSIX_VERSION) +#define _POSIX_CPUTIME (-1L) +#define _POSIX_FSYNC (-1L) +#define _POSIX_IPV6 Z_SC_VAL_IFDEF(CONFIG_NET_IPV6, _POSIX_VERSION) +#define _POSIX_JOB_CONTROL (-1L) +#define _POSIX_MAPPED_FILES _POSIX_VERSION +#define _POSIX_MEMLOCK (-1L) +#define _POSIX_MEMLOCK_RANGE (-1L) +#define _POSIX_MEMORY_PROTECTION (-1L) +#define _POSIX_MESSAGE_PASSING Z_SC_VAL_IFDEF(CONFIG_POSIX_MQUEUE, _POSIX_VERSION) +#define _POSIX_MONOTONIC_CLOCK Z_SC_VAL_IFDEF(CONFIG_POSIX_CLOCK, _POSIX_VERSION) +#define _POSIX_NO_TRUNC (-1L) +#define _POSIX_PRIORITIZED_IO (-1L) +#define _POSIX_PRIORITY_SCHEDULING (-1L) +#define _POSIX_RAW_SOCKETS Z_SC_VAL_IFDEF(CONFIG_NET_SOCKETS_PACKET, _POSIX_VERSION) +#define _POSIX_READER_WRITER_LOCKS Z_SC_VAL_IFDEF(CONFIG_PTHREAD_IPC, _POSIX_VERSION) +#define _POSIX_REALTIME_SIGNALS (-1L) +#define _POSIX_REGEXP (-1L) +#define _POSIX_SAVED_IDS (-1L) +#define _POSIX_SEMAPHORES Z_SC_VAL_IFDEF(CONFIG_PTHREAD_IPC, _POSIX_VERSION) +#define _POSIX_SHARED_MEMORY_OBJECTS (-1L) +#define _POSIX_SHELL (-1L) +#define _POSIX_SPAWN (-1L) +#define _POSIX_SPIN_LOCKS Z_SC_VAL_IFDEF(CONFIG_PTHREAD_SPINLOCK, _POSIX_VERSION) +#define _POSIX_SPORADIC_SERVER (-1L) +#define _POSIX_SYNCHRONIZED_IO (-1L) +#define _POSIX_THREAD_ATTR_STACKADDR Z_SC_VAL_IFDEF(CONFIG_PTHREAD_IPC, _POSIX_VERSION) +#define _POSIX_THREAD_ATTR_STACKSIZE Z_SC_VAL_IFDEF(CONFIG_PTHREAD_IPC, _POSIX_VERSION) +#define _POSIX_THREAD_CPUTIME (-1L) +#define _POSIX_THREAD_PRIO_INHERIT _POSIX_VERSION +#define _POSIX_THREAD_PRIO_PROTECT (-1L) +#define _POSIX_THREAD_PRIORITY_SCHEDULING Z_SC_VAL_IFDEF(CONFIG_PTHREAD_IPC, _POSIX_VERSION) +#define _POSIX_THREAD_PROCESS_SHARED (-1L) +#define _POSIX_THREAD_ROBUST_PRIO_INHERIT (-1L) +#define _POSIX_THREAD_ROBUST_PRIO_PROTECT (-1L) +#define _POSIX_THREAD_SAFE_FUNCTIONS Z_SC_VAL_IFDEF(CONFIG_PTHREAD_IPC, _POSIX_VERSION) +#define _POSIX_THREAD_SPORADIC_SERVER (-1L) + +#ifndef _POSIX_THREADS +#define _POSIX_THREADS Z_SC_VAL_IFDEF(CONFIG_PTHREAD_IPC, _POSIX_VERSION) +#endif + +#define _POSIX_TIMEOUTS Z_SC_VAL_IFDEF(CONFIG_POSIX_CLOCK, _POSIX_VERSION) +#define _POSIX_TIMERS Z_SC_VAL_IFDEF(CONFIG_POSIX_CLOCK, _POSIX_VERSION) +#define _POSIX_TRACE (-1L) +#define _POSIX_TRACE_EVENT_FILTER (-1L) +#define _POSIX_TRACE_INHERIT (-1L) +#define _POSIX_TRACE_LOG (-1L) +#define _POSIX_TYPED_MEMORY_OBJECTS (-1L) +#define _POSIX_V6_ILP32_OFF32 (-1L) +#define _POSIX_V6_ILP32_OFFBIG (-1L) +#define _POSIX_V6_LP64_OFF64 (-1L) +#define _POSIX_V6_LPBIG_OFFBIG (-1L) +#define _POSIX_V7_ILP32_OFF32 (-1L) +#define _POSIX_V7_ILP32_OFFBIG (-1L) +#define _POSIX_V7_LP64_OFF64 (-1L) +#define _POSIX_V7_LPBIG_OFFBIG (-1L) +#define _POSIX2_C_BIND _POSIX_VERSION +#define _POSIX2_C_DEV (-1L) +#define _POSIX2_CHAR_TERM (-1L) +#define _POSIX2_FORT_DEV (-1L) +#define _POSIX2_FORT_RUN (-1L) +#define _POSIX2_LOCALEDEF (-1L) +#define _POSIX2_PBS (-1L) +#define _POSIX2_PBS_ACCOUNTING (-1L) +#define _POSIX2_PBS_CHECKPOINT (-1L) +#define _POSIX2_PBS_LOCATE (-1L) +#define _POSIX2_PBS_MESSAGE (-1L) +#define _POSIX2_PBS_TRACK (-1L) +#define _POSIX2_SW_DEV (-1L) +#define _POSIX2_UPE (-1L) +#define _XOPEN_CRYPT (-1L) +#define _XOPEN_ENH_I18N (-1L) +#define _XOPEN_REALTIME (-1L) +#define _XOPEN_REALTIME_THREADS (-1L) +#define _XOPEN_SHM (-1L) +#define _XOPEN_STREAMS (-1L) +#define _XOPEN_UNIX (-1L) +#define _XOPEN_UUCP (-1L) + +/* Maximum values */ +#define _POSIX_CLOCKRES_MIN (20000000L) + +/* Minimum values */ +#define _POSIX_AIO_LISTIO_MAX (2) +#define _POSIX_AIO_MAX (1) +#define _POSIX_ARG_MAX (4096) +#define _POSIX_CHILD_MAX (25) +#define _POSIX_DELAYTIMER_MAX (32) +#define _POSIX_HOST_NAME_MAX (255) +#define _POSIX_LINK_MAX (8) +#define _POSIX_LOGIN_NAME_MAX (9) +#define _POSIX_MAX_CANON (255) +#define _POSIX_MAX_INPUT (255) +#define _POSIX_MQ_OPEN_MAX CONFIG_MSG_COUNT_MAX +#define _POSIX_MQ_PRIO_MAX (32) +#define _POSIX_NAME_MAX (14) +#define _POSIX_NGROUPS_MAX (8) +#define _POSIX_OPEN_MAX CONFIG_POSIX_MAX_FDS +#define _POSIX_PATH_MAX (256) +#define _POSIX_PIPE_BUF (512) +#define _POSIX_RE_DUP_MAX (255) +#define _POSIX_RTSIG_MAX CONFIG_POSIX_RTSIG_MAX +#define _POSIX_SEM_NSEMS_MAX CONFIG_SEM_NAMELEN_MAX +#define _POSIX_SEM_VALUE_MAX CONFIG_SEM_VALUE_MAX +#define _POSIX_SIGQUEUE_MAX (32) +#define _POSIX_SSIZE_MAX (32767) +#define _POSIX_SS_REPL_MAX (4) +#define _POSIX_STREAM_MAX (8) +#define _POSIX_SYMLINK_MAX (255) +#define _POSIX_SYMLOOP_MAX (8) +#define _POSIX_THREAD_DESTRUCTOR_ITERATIONS (4) +#define _POSIX_THREAD_KEYS_MAX (128) +#define _POSIX_THREAD_THREADS_MAX (64) +#define _POSIX_TIMER_MAX (32) +#define _POSIX_TRACE_EVENT_NAME_MAX (30) +#define _POSIX_TRACE_NAME_MAX (8) +#define _POSIX_TRACE_SYS_MAX (8) +#define _POSIX_TRACE_USER_EVENT_MAX (32) +#define _POSIX_TTY_NAME_MAX (9) +#define _POSIX_TZNAME_MAX (6) +#define _POSIX2_BC_BASE_MAX (99) +#define _POSIX2_BC_DIM_MAX (2048) +#define _POSIX2_BC_SCALE_MAX (99) +#define _POSIX2_BC_STRING_MAX (1000) +#define _POSIX2_CHARCLASS_NAME_MAX (14) +#define _POSIX2_COLL_WEIGHTS_MAX (2) +#define _POSIX2_EXPR_NEST_MAX (32) +#define _POSIX2_LINE_MAX (2048) +#define _XOPEN_IOV_MAX (16) +#define _XOPEN_NAME_MAX (255) +#define _XOPEN_PATH_MAX (1024) + +/* Other invariant values */ +#define NL_LANGMAX (14) +#define NL_MSGMAX (32767) +#define NL_SETMAX (255) +#define NL_TEXTMAX (_POSIX2_LINE_MAX) +#define NZERO (20) + +/* Runtime invariant values */ +#define AIO_LISTIO_MAX _POSIX_AIO_LISTIO_MAX +#define AIO_MAX _POSIX_AIO_MAX +#define AIO_PRIO_DELTA_MAX (0) +#define DELAYTIMER_MAX _POSIX_DELAYTIMER_MAX +#define HOST_NAME_MAX COND_CODE_1(CONFIG_NETWORKING, \ + (NET_HOSTNAME_MAX_LEN), \ + (_POSIX_HOST_NAME_MAX)) +#define LOGIN_NAME_MAX _POSIX_LOGIN_NAME_MAX +#define MQ_OPEN_MAX _POSIX_MQ_OPEN_MAX +#define MQ_PRIO_MAX _POSIX_MQ_PRIO_MAX + +#ifndef PAGE_SIZE +#define PAGE_SIZE BIT(CONFIG_POSIX_PAGE_SIZE_BITS) +#endif + +#ifndef PAGESIZE +#define PAGESIZE PAGE_SIZE +#endif + +#define PTHREAD_DESTRUCTOR_ITERATIONS _POSIX_THREAD_DESTRUCTOR_ITERATIONS +#define PTHREAD_KEYS_MAX COND_CODE_1(CONFIG_PTHREAD_IPC, \ + (CONFIG_MAX_PTHREAD_KEY_COUNT), \ + (_POSIX_THREAD_KEYS_MAX)) +#define PTHREAD_THREADS_MAX COND_CODE_1(CONFIG_PTHREAD_IPC, CONFIG_MAX_PTHREAD_COUNT, 0) +#define SEM_NSEMS_MAX _POSIX_SEM_NSEMS_MAX +#define SEM_VALUE_MAX CONFIG_SEM_VALUE_MAX +#define SIGQUEUE_MAX _POSIX_SIGQUEUE_MAX +#define STREAM_MAX _POSIX_STREAM_MAX +#define SYMLOOP_MAX _POSIX_SYMLOOP_MAX +#define TIMER_MAX CONFIG_MAX_TIMER_COUNT +#define TTY_NAME_MAX _POSIX_TTY_NAME_MAX +#define TZNAME_MAX _POSIX_TZNAME_MAX + +/* Pathname variable values */ +#define FILESIZEBITS (32) +#define POSIX_ALLOC_SIZE_MIN (256) +#define POSIX_REC_INCR_XFER_SIZE (1024) +#define POSIX_REC_MAX_XFER_SIZE (32767) +#define POSIX_REC_MIN_XFER_SIZE (1) +#define POSIX_REC_XFER_ALIGN (4) +#define SYMLINK_MAX _POSIX_SYMLINK_MAX + #ifdef CONFIG_POSIX_API /* File related operations */ int close(int file); @@ -55,6 +256,137 @@ pid_t getpid(void); unsigned sleep(unsigned int seconds); int usleep(useconds_t useconds); +#ifdef CONFIG_POSIX_SYSCONF +#define __z_posix_sysconf_SC_ADVISORY_INFO _POSIX_ADVISORY_INFO +#define __z_posix_sysconf_SC_ASYNCHRONOUS_IO _POSIX_ASYNCHRONOUS_IO +#define __z_posix_sysconf_SC_BARRIERS _POSIX_BARRIERS +#define __z_posix_sysconf_SC_CLOCK_SELECTION _POSIX_CLOCK_SELECTION +#define __z_posix_sysconf_SC_CPUTIME _POSIX_CPUTIME +#define __z_posix_sysconf_SC_FSYNC _POSIX_FSYNC +#define __z_posix_sysconf_SC_IPV6 _POSIX_IPV6 +#define __z_posix_sysconf_SC_JOB_CONTROL _POSIX_JOB_CONTROL +#define __z_posix_sysconf_SC_MAPPED_FILE _POSIX_MAPPED_FILES +#define __z_posix_sysconf_SC_MEMLOCK _POSIX_MEMLOCK +#define __z_posix_sysconf_SC_MEMLOCK_RANGE _POSIX_MEMLOCK_RANGE +#define __z_posix_sysconf_SC_MEMORY_PROTECTION _POSIX_MEMORY_PROTECTION +#define __z_posix_sysconf_SC_MESSAGE_PASSING _POSIX_MESSAGE_PASSING +#define __z_posix_sysconf_SC_MONOTONIC_CLOCK _POSIX_MONOTONIC_CLOCK +#define __z_posix_sysconf_SC_PRIORITIZED_IO _POSIX_PRIORITIZED_IO +#define __z_posix_sysconf_SC_PRIORITY_SCHEDULING _POSIX_PRIORITY_SCHEDULING +#define __z_posix_sysconf_SC_RAW_SOCKETS _POSIX_RAW_SOCKETS +#define __z_posix_sysconf_SC_RE_DUP_MAX _POSIX_RE_DUP_MAX +#define __z_posix_sysconf_SC_READER_WRITER_LOCKS _POSIX_READER_WRITER_LOCKS +#define __z_posix_sysconf_SC_REALTIME_SIGNALS _POSIX_REALTIME_SIGNALS +#define __z_posix_sysconf_SC_REGEXP _POSIX_REGEXP +#define __z_posix_sysconf_SC_SAVED_IDS _POSIX_SAVED_IDS +#define __z_posix_sysconf_SC_SEMAPHORES _POSIX_SEMAPHORES +#define __z_posix_sysconf_SC_SHARED_MEMORY_OBJECTS _POSIX_SHARED_MEMORY_OBJECTS +#define __z_posix_sysconf_SC_SHELL _POSIX_SHELL +#define __z_posix_sysconf_SC_SPAWN _POSIX_SPAWN +#define __z_posix_sysconf_SC_SPIN_LOCKS _POSIX_SPIN_LOCKS +#define __z_posix_sysconf_SC_SPORADIC_SERVER _POSIX_SPORADIC_SERVER +#define __z_posix_sysconf_SC_SS_REPL_MAX _POSIX_SS_REPL_MAX +#define __z_posix_sysconf_SC_SYNCHRONIZED_IO _POSIX_SYNCHRONIZED_IO +#define __z_posix_sysconf_SC_THREAD_ATTR_STACKADDR _POSIX_THREAD_ATTR_STACKADDR +#define __z_posix_sysconf_SC_THREAD_ATTR_STACKSIZE _POSIX_THREAD_ATTR_STACKSIZE +#define __z_posix_sysconf_SC_THREAD_CPUTIME _POSIX_THREAD_CPUTIME +#define __z_posix_sysconf_SC_THREAD_PRIO_INHERIT _POSIX_THREAD_PRIO_INHERIT +#define __z_posix_sysconf_SC_THREAD_PRIO_PROTECT _POSIX_THREAD_PRIO_PROTECT +#define __z_posix_sysconf_SC_THREAD_PRIORITY_SCHEDULING _POSIX_THREAD_PRIORITY_SCHEDULING +#define __z_posix_sysconf_SC_THREAD_PROCESS_SHARED _POSIX_THREAD_PROCESS_SHARED +#define __z_posix_sysconf_SC_THREAD_ROBUST_PRIO_INHERIT _POSIX_THREAD_ROBUST_PRIO_INHERIT +#define __z_posix_sysconf_SC_THREAD_ROBUST_PRIO_PROTECT _POSIX_THREAD_ROBUST_PRIO_PROTECT +#define __z_posix_sysconf_SC_THREAD_SAFE_FUNCTIONS _POSIX_THREAD_SAFE_FUNCTIONS +#define __z_posix_sysconf_SC_THREAD_SPORADIC_SERVER _POSIX_THREAD_SPORADIC_SERVER +#define __z_posix_sysconf_SC_THREADS _POSIX_THREADS +#define __z_posix_sysconf_SC_TIMEOUTS _POSIX_TIMEOUTS +#define __z_posix_sysconf_SC_TIMERS _POSIX_TIMERS +#define __z_posix_sysconf_SC_TRACE _POSIX_TRACE +#define __z_posix_sysconf_SC_TRACE_EVENT_FILTER _POSIX_TRACE_EVENT_FILTER +#define __z_posix_sysconf_SC_TRACE_EVENT_NAME_MAX _POSIX_TRACE_EVENT_NAME_MAX +#define __z_posix_sysconf_SC_TRACE_INHERIT _POSIX_TRACE_INHERIT +#define __z_posix_sysconf_SC_TRACE_LOG _POSIX_TRACE_LOG +#define __z_posix_sysconf_SC_TRACE_NAME_MAX _POSIX_TRACE_NAME_MAX +#define __z_posix_sysconf_SC_TRACE_SYS_MAX _POSIX_TRACE_SYS_MAX +#define __z_posix_sysconf_SC_TRACE_USER_EVENT_MAX _POSIX_TRACE_USER_EVENT_MAX +#define __z_posix_sysconf_SC_TYPED_MEMORY_OBJECTS _POSIX_TYPED_MEMORY_OBJECTS +#define __z_posix_sysconf_SC_VERSION _POSIX_VERSION +#define __z_posix_sysconf_SC_V7_ILP32_OFF32 _POSIX_V7_ILP32_OFF32 +#define __z_posix_sysconf_SC_V7_ILP32_OFFBIG _POSIX_V7_ILP32_OFFBIG +#define __z_posix_sysconf_SC_V7_LP64_OFF64 _POSIX_V7_LP64_OFF64 +#define __z_posix_sysconf_SC_V7_LPBIG_OFFBIG _POSIX_V7_LPBIG_OFFBIG +#define __z_posix_sysconf_SC_V6_ILP32_OFF32 _POSIX_V6_ILP32_OFF32 +#define __z_posix_sysconf_SC_V6_ILP32_OFFBIG _POSIX_V6_ILP32_OFFBIG +#define __z_posix_sysconf_SC_V6_LP64_OFF64 _POSIX_V6_LP64_OFF64 +#define __z_posix_sysconf_SC_V6_LPBIG_OFFBIG _POSIX_V6_LPBIG_OFFBIG +#define __z_posix_sysconf_SC_BC_BASE_MAX _POSIX2_BC_BASE_MAX +#define __z_posix_sysconf_SC_BC_DIM_MAX _POSIX2_BC_DIM_MAX +#define __z_posix_sysconf_SC_BC_SCALE_MAX _POSIX2_BC_SCALE_MAX +#define __z_posix_sysconf_SC_BC_STRING_MAX _POSIX2_BC_STRING_MAX +#define __z_posix_sysconf_SC_2_C_BIND _POSIX2_C_BIND +#define __z_posix_sysconf_SC_2_C_DEV _POSIX2_C_DEV +#define __z_posix_sysconf_SC_2_CHAR_TERM _POSIX2_CHAR_TERM +#define __z_posix_sysconf_SC_COLL_WEIGHTS_MAX _POSIX2_COLL_WEIGHTS_MAX +#define __z_posix_sysconf_SC_DELAYTIMER_MAX _POSIX2_DELAYTIMER_MAX +#define __z_posix_sysconf_SC_EXPR_NEST_MAX _POSIX2_EXPR_NEST_MAX +#define __z_posix_sysconf_SC_2_FORT_DEV _POSIX2_FORT_DEV +#define __z_posix_sysconf_SC_2_FORT_RUN _POSIX2_FORT_RUN +#define __z_posix_sysconf_SC_LINE_MAX _POSIX2_LINE_MAX +#define __z_posix_sysconf_SC_2_LOCALEDEF _POSIX2_LOCALEDEF +#define __z_posix_sysconf_SC_2_PBS _POSIX2_PBS +#define __z_posix_sysconf_SC_2_PBS_ACCOUNTING _POSIX2_PBS_ACCOUNTING +#define __z_posix_sysconf_SC_2_PBS_CHECKPOINT _POSIX2_PBS_CHECKPOINT +#define __z_posix_sysconf_SC_2_PBS_LOCATE _POSIX2_PBS_LOCATE +#define __z_posix_sysconf_SC_2_PBS_MESSAGE _POSIX2_PBS_MESSAGE +#define __z_posix_sysconf_SC_2_PBS_TRACK _POSIX2_PBS_TRACK +#define __z_posix_sysconf_SC_2_SW_DEV _POSIX2_SW_DEV +#define __z_posix_sysconf_SC_2_UPE _POSIX2_UPE +#define __z_posix_sysconf_SC_2_VERSION _POSIX2_VERSION +#define __z_posix_sysconf_SC_XOPEN_CRYPT _XOPEN_CRYPT +#define __z_posix_sysconf_SC_XOPEN_ENH_I18N _XOPEN_ENH_I18N +#define __z_posix_sysconf_SC_XOPEN_REALTIME _XOPEN_REALTIME +#define __z_posix_sysconf_SC_XOPEN_REALTIME_THREADS _XOPEN_REALTIME_THREADS +#define __z_posix_sysconf_SC_XOPEN_SHM _XOPEN_SHM +#define __z_posix_sysconf_SC_XOPEN_STREAMS _XOPEN_STREAMS +#define __z_posix_sysconf_SC_XOPEN_UNIX _XOPEN_UNIX +#define __z_posix_sysconf_SC_XOPEN_UUCP _XOPEN_UUCP +#define __z_posix_sysconf_SC_XOPEN_VERSION _XOPEN_VERSION +#define __z_posix_sysconf_SC_CLK_TCK (100L) +#define __z_posix_sysconf_SC_GETGR_R_SIZE_MAX (0L) +#define __z_posix_sysconf_SC_GETPW_R_SIZE_MAX (0L) +#define __z_posix_sysconf_SC_AIO_LISTIO_MAX AIO_LISTIO_MAX +#define __z_posix_sysconf_SC_AIO_MAX AIO_MAX +#define __z_posix_sysconf_SC_AIO_PRIO_DELTA_MAX AIO_PRIO_DELTA_MAX +#define __z_posix_sysconf_SC_ARG_MAX ARG_MAX +#define __z_posix_sysconf_SC_ATEXIT_MAX ATEXIT_MAX +#define __z_posix_sysconf_SC_CHILD_MAX CHILD_MAX +#define __z_posix_sysconf_SC_HOST_NAME_MAX HOST_NAME_MAX +#define __z_posix_sysconf_SC_IOV_MAX IOV_MAX +#define __z_posix_sysconf_SC_LOGIN_NAME_MAX LOGIN_NAME_MAX +#define __z_posix_sysconf_SC_NGROUPS_MAX _POSIX_NGROUPS_MAX +#define __z_posix_sysconf_SC_MQ_OPEN_MAX MQ_OPEN_MAX +#define __z_posix_sysconf_SC_MQ_PRIO_MAX MQ_PRIO_MAX +#define __z_posix_sysconf_SC_OPEN_MAX CONFIG_POSIX_MAX_FDS +#define __z_posix_sysconf_SC_PAGE_SIZE PAGE_SIZE +#define __z_posix_sysconf_SC_PAGESIZE PAGESIZE +#define __z_posix_sysconf_SC_THREAD_DESTRUCTOR_ITERATIONS PTHREAD_DESTRUCTOR_ITERATIONS +#define __z_posix_sysconf_SC_THREAD_KEYS_MAX PTHREAD_KEYS_MAX +#define __z_posix_sysconf_SC_THREAD_STACK_MIN PTHREAD_STACK_MIN +#define __z_posix_sysconf_SC_THREAD_THREADS_MAX PTHREAD_THREADS_MAX +#define __z_posix_sysconf_SC_RTSIG_MAX RTSIG_MAX +#define __z_posix_sysconf_SC_SEM_NSEMS_MAX SEM_NSEMS_MAX +#define __z_posix_sysconf_SC_SEM_VALUE_MAX SEM_VALUE_MAX +#define __z_posix_sysconf_SC_SIGQUEUE_MAX SIGQUEUE_MAX +#define __z_posix_sysconf_SC_STREAM_MAX STREAM_MAX +#define __z_posix_sysconf_SC_SYMLOOP_MAX SYMLOOP_MAX +#define __z_posix_sysconf_SC_TIMER_MAX TIMER_MAX +#define __z_posix_sysconf_SC_TTY_NAME_MAX TTY_NAME_MAX +#define __z_posix_sysconf_SC_TZNAME_MAX TZNAME_MAX + +#define sysconf(x) (long)CONCAT(__z_posix_sysconf, x) + +#endif /* CONFIG_POSIX_SYSCONF */ + #ifdef __cplusplus } #endif diff --git a/lib/posix/Kconfig b/lib/posix/Kconfig index b1443a5ab71..b7a75e7933c 100644 --- a/lib/posix/Kconfig +++ b/lib/posix/Kconfig @@ -39,6 +39,23 @@ config PTHREAD_IPC the pthread mutex, condition variable and barrier IPC mechanisms. +config POSIX_SYSCONF + bool "Support for sysconf" + default y if POSIX_API + help + The sysconf() function provides a method for the application to determine + the current value of a configurable system limit or option (variable). + +config POSIX_PAGE_SIZE_BITS + int "Number of bits to use for PAGE_SIZE" + range 6 16 + default 12 if POSIX_API + default 6 + help + Define PAGE_SIZE as BIT(n), where n is the value configured here. + PAGE_SIZE is supported in the range [64, 65536] + If CONFIG_POSIX_API=y, PAGE_SIZE defaults to 4096, otherwise, it is 64 bytes. + source "lib/posix/Kconfig.barrier" source "lib/posix/Kconfig.clock" source "lib/posix/Kconfig.cond" From 31af5f8fe1b9fdfdf5ef96922714ea6ad0dc9733 Mon Sep 17 00:00:00 2001 From: Adam Wojasinski Date: Thu, 11 Jan 2024 21:32:31 +0100 Subject: [PATCH 3097/3723] tests: posix: Add test case for sysconf() Adds test cases for sysconf() basic implementation. Test case does not cover scenario where invalid value is passed to the name argument of the function. Signed-off-by: Adam Wojasinski --- include/zephyr/posix/unistd.h | 4 +- tests/posix/common/src/sysconf.c | 33 ++++++ tests/posix/headers/src/unistd_h.c | 156 ++++++++++++++--------------- 3 files changed, 114 insertions(+), 79 deletions(-) create mode 100644 tests/posix/common/src/sysconf.c diff --git a/include/zephyr/posix/unistd.h b/include/zephyr/posix/unistd.h index 4d683d0fdb1..36918c56365 100644 --- a/include/zephyr/posix/unistd.h +++ b/include/zephyr/posix/unistd.h @@ -203,7 +203,9 @@ extern "C" { #define PTHREAD_KEYS_MAX COND_CODE_1(CONFIG_PTHREAD_IPC, \ (CONFIG_MAX_PTHREAD_KEY_COUNT), \ (_POSIX_THREAD_KEYS_MAX)) -#define PTHREAD_THREADS_MAX COND_CODE_1(CONFIG_PTHREAD_IPC, CONFIG_MAX_PTHREAD_COUNT, 0) +#define PTHREAD_THREADS_MAX COND_CODE_1(CONFIG_PTHREAD_IPC, \ + (CONFIG_MAX_PTHREAD_COUNT), \ + (0)) #define SEM_NSEMS_MAX _POSIX_SEM_NSEMS_MAX #define SEM_VALUE_MAX CONFIG_SEM_VALUE_MAX #define SIGQUEUE_MAX _POSIX_SIGQUEUE_MAX diff --git a/tests/posix/common/src/sysconf.c b/tests/posix/common/src/sysconf.c new file mode 100644 index 00000000000..67929759925 --- /dev/null +++ b/tests/posix/common/src/sysconf.c @@ -0,0 +1,33 @@ +/* + * Copyright (c) 2023, Meta + * Copyright (c) 2024, Adam Wojasinski + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include +#include + +ZTEST(posix_apis, test_posix_sysconf) +{ + long ret; + + /* SC that's implemented */ + ret = sysconf(_SC_VERSION); + zassert_equal(ret, _POSIX_VERSION, "sysconf returned unexpected value %d", ret); + + /* SC that's not implemented */ + ret = sysconf(_SC_MEMLOCK_RANGE); + zassert_equal(ret, -1, "sysconf returned unexpected value %d", ret); + + /* SC that value depends on target's configuration */ + ret = sysconf(_SC_SEMAPHORES); + if (IS_ENABLED(CONFIG_PTHREAD_IPC)) { + zassert_equal(ret, + _POSIX_VERSION, + "sysconf returned unexpected value %d", + ret); + } else { + zassert_equal(ret, -1L, "sysconf returned unexpected value %d", ret); + } +} diff --git a/tests/posix/headers/src/unistd_h.c b/tests/posix/headers/src/unistd_h.c index 6355997905f..a0b51c33206 100644 --- a/tests/posix/headers/src/unistd_h.c +++ b/tests/posix/headers/src/unistd_h.c @@ -19,91 +19,91 @@ */ ZTEST(posix_headers, test_unistd_h) { - /* zassert_not_equal(-1, _POSIX_VERSION); */ /* not implemented */ + zassert_not_equal(-1, _POSIX_VERSION); /* zassert_not_equal(-1, _POSIX2_VERSION); */ /* not implemented */ /* zassert_not_equal(-1, _XOPEN_VERSION); */ /* not implemented */ - /* zassert_not_equal(INT_MIN, _POSIX_ADVISORY_INFO); */ /* not implemented */ - /* zassert_not_equal(INT_MIN, _POSIX_ASYNCHRONOUS_IO); */ /* not implemented */ - /* zassert_not_equal(INT_MIN, _POSIX_BARRIERS); */ /* not implemented */ - /* zassert_not_equal(INT_MIN, _POSIX_CHOWN_RESTRICTED); */ /* not implemented */ - /* zassert_not_equal(INT_MIN, _POSIX_CPUTIME); */ /* not implemented */ - /* zassert_not_equal(INT_MIN, _POSIX_FSYNC); */ /* not implemented */ - /* zassert_not_equal(INT_MIN, _POSIX_IPV6); */ /* not implemented */ - /* zassert_not_equal(INT_MIN, _POSIX_JOB_CONTROL); */ /* not implemented */ - /* zassert_not_equal(INT_MIN, _POSIX_MAPPED_FILES); */ /* not implemented */ - /* zassert_not_equal(INT_MIN, _POSIX_MEMLOCK); */ /* not implemented */ - /* zassert_not_equal(INT_MIN, _POSIX_MEMLOCK_RANGE); */ /* not implemented */ - /* zassert_not_equal(INT_MIN, _POSIX_MEMORY_PROTECTION); */ /* not implemented */ - /* zassert_not_equal(INT_MIN, _POSIX_MESSAGE_PASSING); */ /* not implemented */ - /* zassert_not_equal(INT_MIN, _POSIX_MONOTONIC_CLOCK); */ /* not implemented */ - /* zassert_not_equal(INT_MIN, _POSIX_NO_TRUNC); */ /* not implemented */ - /* zassert_not_equal(INT_MIN, _POSIX_PRIORITIZED_IO); */ /* not implemented */ - /* zassert_not_equal(INT_MIN, _POSIX_PRIORITY_SCHEDULING); */ /* not implemented */ - /* zassert_not_equal(INT_MIN, _POSIX_RAW_SOCKETS); */ /* not implemented */ - /* zassert_not_equal(INT_MIN, _POSIX_READER_WRITER_LOCKS); */ /* not implemented */ - /* zassert_not_equal(INT_MIN, _POSIX_REALTIME_SIGNALS); */ /* not implemented */ - /* zassert_not_equal(INT_MIN, _POSIX_REGEXP); */ /* not implemented */ - /* zassert_not_equal(INT_MIN, _POSIX_SAVED_IDS); */ /* not implemented */ - /* zassert_not_equal(INT_MIN, _POSIX_SHARED_MEMORY_OBJECTS); */ /* not implemented */ - /* zassert_not_equal(INT_MIN, _POSIX_SHELL); */ /* not implemented */ - /* zassert_not_equal(INT_MIN, _POSIX_SPAWN); */ /* not implemented */ - /* zassert_not_equal(INT_MIN, _POSIX_SPIN_LOCKS); */ /* not implemented */ - /* zassert_not_equal(INT_MIN, _POSIX_SPORADIC_SERVER); */ /* not implemented */ - /* zassert_not_equal(INT_MIN, _POSIX_SYNCHRONIZED_IO); */ /* not implemented */ - /* zassert_not_equal(INT_MIN, _POSIX_THREAD_ATTR_STACKADDR); */ /* not implemented */ - /* zassert_not_equal(INT_MIN, _POSIX_THREAD_ATTR_STACKSIZE); */ /* not implemented */ - /* zassert_not_equal(INT_MIN, _POSIX_THREAD_CPUTIME); */ /* not implemented */ - /* zassert_not_equal(INT_MIN, _POSIX_THREAD_PRIO_INHERIT); */ /* not implemented */ - /* zassert_not_equal(INT_MIN, _POSIX_THREAD_PRIO_PROTECT); */ /* not implemented */ - /* zassert_not_equal(INT_MIN, _POSIX_THREAD_PRIORITY_SCHEDULING); */ /* not implemented */ - /* zassert_not_equal(INT_MIN, _POSIX_THREAD_PROCESS_SHARED); */ /* not implemented */ - /* zassert_not_equal(INT_MIN, _POSIX_THREAD_ROBUST_PRIO_INHERIT); */ /* not implemented */ - /* zassert_not_equal(INT_MIN, _POSIX_THREAD_ROBUST_PRIO_PROTECT); */ /* not implemented */ - /* zassert_not_equal(INT_MIN, _POSIX_THREAD_SAFE_FUNCTIONS); */ /* not implemented */ - /* zassert_not_equal(INT_MIN, _POSIX_THREAD_SPORADIC_SERVER); */ /* not implemented */ - /* zassert_not_equal(INT_MIN, _POSIX_THREADS); */ /* not implemented */ - /* zassert_not_equal(INT_MIN, _POSIX_TIMEOUTS); */ /* not implemented */ - /* zassert_not_equal(INT_MIN, _POSIX_TIMERS); */ /* not implemented */ - /* zassert_not_equal(INT_MIN, _POSIX_TRACE); */ /* not implemented */ - /* zassert_not_equal(INT_MIN, _POSIX_TRACE_EVENT_FILTER); */ /* not implemented */ - /* zassert_not_equal(INT_MIN, _POSIX_TRACE_INHERIT); */ /* not implemented */ - /* zassert_not_equal(INT_MIN, _POSIX_TRACE_LOG); */ /* not implemented */ - /* zassert_not_equal(INT_MIN, _POSIX_TYPED_MEMORY_OBJECTS); */ /* not implemented */ + zassert_not_equal(INT_MIN, _POSIX_ADVISORY_INFO); /* not implemented */ + zassert_not_equal(INT_MIN, _POSIX_ASYNCHRONOUS_IO); /* not implemented */ + zassert_not_equal(INT_MIN, _POSIX_BARRIERS); /* not implemented */ + zassert_not_equal(INT_MIN, _POSIX_CHOWN_RESTRICTED); /* not implemented */ + zassert_not_equal(INT_MIN, _POSIX_CPUTIME); /* not implemented */ + zassert_not_equal(INT_MIN, _POSIX_FSYNC); /* not implemented */ + zassert_not_equal(INT_MIN, _POSIX_IPV6); /* not implemented */ + zassert_not_equal(INT_MIN, _POSIX_JOB_CONTROL); /* not implemented */ + zassert_not_equal(INT_MIN, _POSIX_MAPPED_FILES); /* not implemented */ + zassert_not_equal(INT_MIN, _POSIX_MEMLOCK); /* not implemented */ + zassert_not_equal(INT_MIN, _POSIX_MEMLOCK_RANGE); /* not implemented */ + zassert_not_equal(INT_MIN, _POSIX_MEMORY_PROTECTION); /* not implemented */ + zassert_not_equal(INT_MIN, _POSIX_MESSAGE_PASSING); /* not implemented */ + zassert_not_equal(INT_MIN, _POSIX_MONOTONIC_CLOCK); /* not implemented */ + zassert_not_equal(INT_MIN, _POSIX_NO_TRUNC); /* not implemented */ + zassert_not_equal(INT_MIN, _POSIX_PRIORITIZED_IO); /* not implemented */ + zassert_not_equal(INT_MIN, _POSIX_PRIORITY_SCHEDULING); /* not implemented */ + zassert_not_equal(INT_MIN, _POSIX_RAW_SOCKETS); /* not implemented */ + zassert_not_equal(INT_MIN, _POSIX_READER_WRITER_LOCKS); /* not implemented */ + zassert_not_equal(INT_MIN, _POSIX_REALTIME_SIGNALS); /* not implemented */ + zassert_not_equal(INT_MIN, _POSIX_REGEXP); /* not implemented */ + zassert_not_equal(INT_MIN, _POSIX_SAVED_IDS); /* not implemented */ + zassert_not_equal(INT_MIN, _POSIX_SHARED_MEMORY_OBJECTS); /* not implemented */ + zassert_not_equal(INT_MIN, _POSIX_SHELL); /* not implemented */ + zassert_not_equal(INT_MIN, _POSIX_SPAWN); /* not implemented */ + zassert_not_equal(INT_MIN, _POSIX_SPIN_LOCKS); /* not implemented */ + zassert_not_equal(INT_MIN, _POSIX_SPORADIC_SERVER); /* not implemented */ + zassert_not_equal(INT_MIN, _POSIX_SYNCHRONIZED_IO); /* not implemented */ + zassert_not_equal(INT_MIN, _POSIX_THREAD_ATTR_STACKADDR); /* not implemented */ + zassert_not_equal(INT_MIN, _POSIX_THREAD_ATTR_STACKSIZE); /* not implemented */ + zassert_not_equal(INT_MIN, _POSIX_THREAD_CPUTIME); /* not implemented */ + zassert_not_equal(INT_MIN, _POSIX_THREAD_PRIO_INHERIT); /* not implemented */ + zassert_not_equal(INT_MIN, _POSIX_THREAD_PRIO_PROTECT); /* not implemented */ + zassert_not_equal(INT_MIN, _POSIX_THREAD_PRIORITY_SCHEDULING); /* not implemented */ + zassert_not_equal(INT_MIN, _POSIX_THREAD_PROCESS_SHARED); /* not implemented */ + zassert_not_equal(INT_MIN, _POSIX_THREAD_ROBUST_PRIO_INHERIT); /* not implemented */ + zassert_not_equal(INT_MIN, _POSIX_THREAD_ROBUST_PRIO_PROTECT); /* not implemented */ + zassert_not_equal(INT_MIN, _POSIX_THREAD_SAFE_FUNCTIONS); /* not implemented */ + zassert_not_equal(INT_MIN, _POSIX_THREAD_SPORADIC_SERVER); /* not implemented */ + zassert_not_equal(INT_MIN, _POSIX_THREADS); /* not implemented */ + zassert_not_equal(INT_MIN, _POSIX_TIMEOUTS); /* not implemented */ + zassert_not_equal(INT_MIN, _POSIX_TIMERS); /* not implemented */ + zassert_not_equal(INT_MIN, _POSIX_TRACE); /* not implemented */ + zassert_not_equal(INT_MIN, _POSIX_TRACE_EVENT_FILTER); /* not implemented */ + zassert_not_equal(INT_MIN, _POSIX_TRACE_INHERIT); /* not implemented */ + zassert_not_equal(INT_MIN, _POSIX_TRACE_LOG); /* not implemented */ + zassert_not_equal(INT_MIN, _POSIX_TYPED_MEMORY_OBJECTS); /* not implemented */ - /* zassert_not_equal(INT_MIN, _POSIX_V6_ILP32_OFF32); */ /* not implemented */ - /* zassert_not_equal(INT_MIN, _POSIX_V6_ILP32_OFFBIG); */ /* not implemented */ - /* zassert_not_equal(INT_MIN, _POSIX_V6_LP64_OFF64); */ /* not implemented */ - /* zassert_not_equal(INT_MIN, _POSIX_V6_LPBIG_OFFBIG); */ /* not implemented */ + zassert_not_equal(INT_MIN, _POSIX_V6_ILP32_OFF32); /* not implemented */ + zassert_not_equal(INT_MIN, _POSIX_V6_ILP32_OFFBIG); /* not implemented */ + zassert_not_equal(INT_MIN, _POSIX_V6_LP64_OFF64); /* not implemented */ + zassert_not_equal(INT_MIN, _POSIX_V6_LPBIG_OFFBIG); /* not implemented */ - /* zassert_not_equal(INT_MIN, _POSIX_V7_ILP32_OFF32); */ /* not implemented */ - /* zassert_not_equal(INT_MIN, _POSIX_V7_ILP32_OFFBIG); */ /* not implemented */ - /* zassert_not_equal(INT_MIN, _POSIX_V7_LP64_OFF64); */ /* not implemented */ - /* zassert_not_equal(INT_MIN, _POSIX_V7_LPBIG_OFFBIG); */ /* not implemented */ + zassert_not_equal(INT_MIN, _POSIX_V7_ILP32_OFF32); /* not implemented */ + zassert_not_equal(INT_MIN, _POSIX_V7_ILP32_OFFBIG); /* not implemented */ + zassert_not_equal(INT_MIN, _POSIX_V7_LP64_OFF64); /* not implemented */ + zassert_not_equal(INT_MIN, _POSIX_V7_LPBIG_OFFBIG); /* not implemented */ - /* zassert_not_equal(INT_MIN, _POSIX2_C_BIND); */ /* not implemented */ - /* zassert_not_equal(INT_MIN, _POSIX2_C_DEV); */ /* not implemented */ - /* zassert_not_equal(INT_MIN, _POSIX2_CHAR_TERM); */ /* not implemented */ - /* zassert_not_equal(INT_MIN, _POSIX2_FORT_DEV); */ /* not implemented */ - /* zassert_not_equal(INT_MIN, _POSIX2_FORT_RUN); */ /* not implemented */ - /* zassert_not_equal(INT_MIN, _POSIX2_LOCALEDEF); */ /* not implemented */ - /* zassert_not_equal(INT_MIN, _POSIX2_PBS); */ /* not implemented */ - /* zassert_not_equal(INT_MIN, _POSIX2_PBS_ACCOUNTING); */ /* not implemented */ - /* zassert_not_equal(INT_MIN, _POSIX2_PBS_CHECKPOINT); */ /* not implemented */ - /* zassert_not_equal(INT_MIN, _POSIX2_PBS_LOCATE); */ /* not implemented */ - /* zassert_not_equal(INT_MIN, _POSIX2_PBS_MESSAGE); */ /* not implemented */ - /* zassert_not_equal(INT_MIN, _POSIX2_PBS_TRACK); */ /* not implemented */ - /* zassert_not_equal(INT_MIN, _POSIX2_SW_DEV); */ /* not implemented */ - /* zassert_not_equal(INT_MIN, _POSIX2_UPE); */ /* not implemented */ + zassert_not_equal(INT_MIN, _POSIX2_C_BIND); /* not implemented */ + zassert_not_equal(INT_MIN, _POSIX2_C_DEV); /* not implemented */ + zassert_not_equal(INT_MIN, _POSIX2_CHAR_TERM); /* not implemented */ + zassert_not_equal(INT_MIN, _POSIX2_FORT_DEV); /* not implemented */ + zassert_not_equal(INT_MIN, _POSIX2_FORT_RUN); /* not implemented */ + zassert_not_equal(INT_MIN, _POSIX2_LOCALEDEF); /* not implemented */ + zassert_not_equal(INT_MIN, _POSIX2_PBS); /* not implemented */ + zassert_not_equal(INT_MIN, _POSIX2_PBS_ACCOUNTING); /* not implemented */ + zassert_not_equal(INT_MIN, _POSIX2_PBS_CHECKPOINT); /* not implemented */ + zassert_not_equal(INT_MIN, _POSIX2_PBS_LOCATE); /* not implemented */ + zassert_not_equal(INT_MIN, _POSIX2_PBS_MESSAGE); /* not implemented */ + zassert_not_equal(INT_MIN, _POSIX2_PBS_TRACK); /* not implemented */ + zassert_not_equal(INT_MIN, _POSIX2_SW_DEV); /* not implemented */ + zassert_not_equal(INT_MIN, _POSIX2_UPE); /* not implemented */ - /* zassert_not_equal(INT_MIN, _XOPEN_CRYPT); */ /* not implemented */ - /* zassert_not_equal(INT_MIN, _XOPEN_ENH_I18N); */ /* not implemented */ - /* zassert_not_equal(INT_MIN, _XOPEN_REALTIME); */ /* not implemented */ - /* zassert_not_equal(INT_MIN, _XOPEN_REALTIME_THREADS); */ /* not implemented */ - /* zassert_not_equal(INT_MIN, _XOPEN_SHM); */ /* not implemented */ - /* zassert_not_equal(INT_MIN, _XOPEN_STREAMS); */ /* not implemented */ - /* zassert_not_equal(INT_MIN, _XOPEN_UNIX); */ /* not implemented */ - /* zassert_not_equal(INT_MIN, _XOPEN_UUCP); */ /* not implemented */ + zassert_not_equal(INT_MIN, _XOPEN_CRYPT); /* not implemented */ + zassert_not_equal(INT_MIN, _XOPEN_ENH_I18N); /* not implemented */ + zassert_not_equal(INT_MIN, _XOPEN_REALTIME); /* not implemented */ + zassert_not_equal(INT_MIN, _XOPEN_REALTIME_THREADS); /* not implemented */ + zassert_not_equal(INT_MIN, _XOPEN_SHM); /* not implemented */ + zassert_not_equal(INT_MIN, _XOPEN_STREAMS); /* not implemented */ + zassert_not_equal(INT_MIN, _XOPEN_UNIX); /* not implemented */ + zassert_not_equal(INT_MIN, _XOPEN_UUCP); /* not implemented */ /* zassert_not_equal(INT_MIN, _POSIX_ASYNC_IO); */ /* not implemented */ /* zassert_not_equal(INT_MIN, _POSIX_PRIO_IO); */ /* not implemented */ From 9b30b7405e6257e111ed067ee63b3106f6b25cf3 Mon Sep 17 00:00:00 2001 From: Adam Wojasinski Date: Wed, 24 Jan 2024 09:40:13 +0100 Subject: [PATCH 3098/3723] doc: posix: Update POSIX supported API documentation with sysconf() Updates in documentation support for `sysconf` API in the `POSIX_SINGLE_PROCESS` group option. Signed-off-by: Adam Wojasinski --- doc/services/portability/posix/option_groups/index.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/doc/services/portability/posix/option_groups/index.rst b/doc/services/portability/posix/option_groups/index.rst index 5c27d32aa2f..f2557df57c4 100644 --- a/doc/services/portability/posix/option_groups/index.rst +++ b/doc/services/portability/posix/option_groups/index.rst @@ -168,7 +168,7 @@ process applications. errno,yes getenv(), setenv(), - sysconf(), + sysconf(),yes uname(),yes unsetenv() From b236e5bd1127be63f924738749af1546e253a330 Mon Sep 17 00:00:00 2001 From: Jamie McCrae Date: Mon, 29 Jan 2024 11:16:34 +0000 Subject: [PATCH 3099/3723] mgmt: mcumgr: grp: os_mgmt: Add firmware uploader boot type Adds firmware uploader to the output of bootloader mode for MCUboot Signed-off-by: Jamie McCrae --- modules/Kconfig.mcuboot | 9 +++++++++ subsys/mgmt/mcumgr/grp/os_mgmt/src/os_mgmt.c | 2 ++ 2 files changed, 11 insertions(+) diff --git a/modules/Kconfig.mcuboot b/modules/Kconfig.mcuboot index 7f41167d3d3..b9b842b0a36 100644 --- a/modules/Kconfig.mcuboot +++ b/modules/Kconfig.mcuboot @@ -231,6 +231,15 @@ config MCUBOOT_BOOTLOADER_MODE_DIRECT_XIP_WITH_REVERT to downgrade running application, but note that MCUboot may do that if application with higher version will not get confirmed. +config MCUBOOT_BOOTLOADER_MODE_FIRMWARE_UPDATER + bool "MCUboot has been configured in firmware updater mode" + select MCUBOOT_IMGTOOL_OVERWRITE_ONLY + help + MCUboot will only boot slot0_partition for the main application but has + an entrance mechanism defined for entering the slot1_partition which is + a dedicated firmware updater application used to update the slot0_partition + application. + endchoice # MCUBOOT_BOOTLOADER_MODE config MCUBOOT_BOOTLOADER_MODE_HAS_NO_DOWNGRADE diff --git a/subsys/mgmt/mcumgr/grp/os_mgmt/src/os_mgmt.c b/subsys/mgmt/mcumgr/grp/os_mgmt/src/os_mgmt.c index 3e524362fa3..7de448ac78d 100644 --- a/subsys/mgmt/mcumgr/grp/os_mgmt/src/os_mgmt.c +++ b/subsys/mgmt/mcumgr/grp/os_mgmt/src/os_mgmt.c @@ -435,6 +435,8 @@ os_mgmt_mcumgr_params(struct smp_streamer *ctxt) #define BOOTLOADER_MODE MCUBOOT_MODE_DIRECT_XIP #elif IS_ENABLED(CONFIG_MCUBOOT_BOOTLOADER_MODE_DIRECT_XIP_WITH_REVERT) #define BOOTLOADER_MODE MCUBOOT_MODE_DIRECT_XIP_WITH_REVERT +#elif IS_ENABLED(CONFIG_MCUBOOT_BOOTLOADER_MODE_FIRMWARE_UPDATER) +#define BOOTLOADER_MODE MCUBOOT_MODE_FIRMWARE_LOADER #else #define BOOTLOADER_MODE -1 #endif From 620d4828a983de8549084b5484f1389c83367717 Mon Sep 17 00:00:00 2001 From: Jamie McCrae Date: Mon, 29 Jan 2024 11:17:24 +0000 Subject: [PATCH 3100/3723] dfu: Add support for MCUboot estimated update image overhead size Adds support for an overhead size which MCUboot can set when using sysbuild, this can be used to check the provided size of an application being uploaded to ensure it will fit and swap without being rejected Signed-off-by: Jamie McCrae --- subsys/dfu/Kconfig | 17 ++++++++++++----- 1 file changed, 12 insertions(+), 5 deletions(-) diff --git a/subsys/dfu/Kconfig b/subsys/dfu/Kconfig index e320185dfef..ec7d90ba14a 100644 --- a/subsys/dfu/Kconfig +++ b/subsys/dfu/Kconfig @@ -31,9 +31,10 @@ config MCUBOOT_IMG_MANAGER endchoice +if MCUBOOT_IMG_MANAGER + config MCUBOOT_SHELL bool "MCUboot shell" - depends on MCUBOOT_IMG_MANAGER depends on SHELL help Enable shell module, which provides information about image slots and @@ -43,7 +44,6 @@ config MCUBOOT_SHELL config MCUBOOT_TRAILER_SWAP_TYPE bool "use trailer's swap_type field" default y - depends on MCUBOOT_IMG_MANAGER help Enables usage swap type field which is required after "Fix double swap on interrupted revert" mcuboot patch @@ -51,9 +51,16 @@ config MCUBOOT_TRAILER_SWAP_TYPE Disable this option if need to be compatible with earlier version of MCUBoot. +config MCUBOOT_UPDATE_FOOTER_SIZE + hex "Estimated update footer size" + default 0x0 + help + Estimated size of update image data, which is used to prevent loading of firmware updates + that MCUboot cannot update due to being too large. This should be set from sysbuild, only + used when MCUMGR_GRP_IMG_TOO_LARGE_SYSBUILD is enabled. + config IMG_BLOCK_BUF_SIZE int "Image writer buffer size" - depends on MCUBOOT_IMG_MANAGER default 512 help Size (in Bytes) of buffer for image writer. Must be a multiple of @@ -61,7 +68,6 @@ config IMG_BLOCK_BUF_SIZE config IMG_ERASE_PROGRESSIVELY bool "Erase flash progressively when receiving new firmware" - depends on MCUBOOT_IMG_MANAGER select STREAM_FLASH_ERASE help If enabled, flash is erased as necessary when receiving new firmware, @@ -71,7 +77,6 @@ config IMG_ERASE_PROGRESSIVELY config IMG_ENABLE_IMAGE_CHECK bool "Image check functions" - depends on MCUBOOT_IMG_MANAGER select FLASH_AREA_CHECK_INTEGRITY help If enabled, there will be available the function to check flash @@ -80,6 +85,8 @@ config IMG_ENABLE_IMAGE_CHECK Another use is to ensure that firmware upgrade routines from internet server to flash slot are performing properly. +endif # MCUBOOT_IMG_MANAGER + module = IMG_MANAGER module-str = image manager source "subsys/logging/Kconfig.template.log_config" From 1989ac3712b51fe15103c4f69aa9b516a2ac392b Mon Sep 17 00:00:00 2001 From: Jamie McCrae Date: Mon, 29 Jan 2024 11:19:21 +0000 Subject: [PATCH 3101/3723] west.yml: MCUboot synchronization from upstream Update Zephyr fork of MCUboot to revision: a4eda30f5b0cfd0cf15512be9dcd559239dbfc91 Brings following Zephyr relevant fixes: - a4eda30f zephyr: Add estimated size of update trailer to sysbuild - 205d7e5b boot_serial: Adapt to zcbor 0.8.x Signed-off-by: Jamie McCrae --- west.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/west.yml b/west.yml index 3b9b32f5b4e..dff0e29705c 100644 --- a/west.yml +++ b/west.yml @@ -282,7 +282,7 @@ manifest: groups: - crypto - name: mcuboot - revision: f09e205b1e4a8d2bc3f50dffa7960d6ccd14df59 + revision: a4eda30f5b0cfd0cf15512be9dcd559239dbfc91 path: bootloader/mcuboot - name: mipi-sys-t path: modules/debug/mipi-sys-t From b26a4bf31ce97b4b97b315a9f4bfda02c7f2ecad Mon Sep 17 00:00:00 2001 From: Jamie McCrae Date: Mon, 18 Dec 2023 11:41:23 +0000 Subject: [PATCH 3102/3723] mgmt: mcumgr: grp: img_mgmt: Add optional max image size reduction Adds an optional feature that can be used to reduce the maximum allowed image upload file size whereby an image could be uploaded that would be too large to swap even if it could fit the partition Signed-off-by: Jamie McCrae --- .../mgmt/mcumgr/grp/img_mgmt/img_mgmt.h | 3 + subsys/mgmt/mcumgr/grp/img_mgmt/Kconfig | 32 +++++++ .../mcumgr/grp/img_mgmt/src/zephyr_img_mgmt.c | 84 +++++++++++++++++++ 3 files changed, 119 insertions(+) diff --git a/include/zephyr/mgmt/mcumgr/grp/img_mgmt/img_mgmt.h b/include/zephyr/mgmt/mcumgr/grp/img_mgmt/img_mgmt.h index 55c226d217c..c11e423e26d 100644 --- a/include/zephyr/mgmt/mcumgr/grp/img_mgmt/img_mgmt.h +++ b/include/zephyr/mgmt/mcumgr/grp/img_mgmt/img_mgmt.h @@ -162,6 +162,9 @@ enum img_mgmt_err_code_t { /** Setting test to active slot is not allowed */ IMG_MGMT_ERR_IMAGE_SETTING_TEST_TO_ACTIVE_DENIED, + + /** Current active slot for image cannot be determined */ + IMG_MGMT_ERR_ACTIVE_SLOT_NOT_KNOWN, }; /** diff --git a/subsys/mgmt/mcumgr/grp/img_mgmt/Kconfig b/subsys/mgmt/mcumgr/grp/img_mgmt/Kconfig index 81fc57d9238..80e524ff72b 100644 --- a/subsys/mgmt/mcumgr/grp/img_mgmt/Kconfig +++ b/subsys/mgmt/mcumgr/grp/img_mgmt/Kconfig @@ -153,6 +153,38 @@ config MCUMGR_GRP_IMG_MUTEX can be used by applications to reset the image management state (useful if there are multiple ways that firmware updates can be loaded). +choice MCUMGR_GRP_IMG_TOO_LARGE_CHECK + prompt "Image size check overhead" + default MCUMGR_GRP_IMG_TOO_LARGE_DISABLED + help + MCUboot images should be limited to the maximum size that the bootloader can swap, in + order to know this size, additional information is needed from the MCUboot + configuration, otherwise an image can be uploaded that is too large for the bootloader + to swap, this selects which method to use. + + Note: setting this to a non-disabled option will prevent uploading of padded and + confirmed images, if support for that is required then this feature should be left as + disabled. + +config MCUMGR_GRP_IMG_TOO_LARGE_DISABLED + bool "Disabled" + help + Will not take MCUboot configuration into account when checking for maximum file size. + +config MCUMGR_GRP_IMG_TOO_LARGE_SYSBUILD + bool "Via Sysbuild from MCUboot configuration" + depends on ROM_END_OFFSET > 0 || MCUBOOT_UPDATE_FOOTER_SIZE > 0 + help + Will use the image overhead size calculated during Sysbuild image configuration. + +config MCUMGR_GRP_IMG_TOO_LARGE_BOOTLOADER_INFO + bool "Via retention bootloader info" + depends on RETENTION_BOOTLOADER_INFO_OUTPUT_FUNCTION + help + Will fetch the maximum image size from the bootloader info retention subsystem module. + +endchoice + module = MCUMGR_GRP_IMG module-str = mcumgr_grp_img source "subsys/logging/Kconfig.template.log_config" diff --git a/subsys/mgmt/mcumgr/grp/img_mgmt/src/zephyr_img_mgmt.c b/subsys/mgmt/mcumgr/grp/img_mgmt/src/zephyr_img_mgmt.c index 303f112709a..a67db362366 100644 --- a/subsys/mgmt/mcumgr/grp/img_mgmt/src/zephyr_img_mgmt.c +++ b/subsys/mgmt/mcumgr/grp/img_mgmt/src/zephyr_img_mgmt.c @@ -19,6 +19,11 @@ #include +#if defined(CONFIG_MCUMGR_GRP_IMG_TOO_LARGE_BOOTLOADER_INFO) +#include +#include +#endif + LOG_MODULE_DECLARE(mcumgr_img_grp, CONFIG_MCUMGR_GRP_IMG_LOG_LEVEL); #define SLOT0_PARTITION slot0_partition @@ -564,6 +569,18 @@ int img_mgmt_upload_inspect(const struct img_mgmt_upload_req *req, if (req->off == 0) { /* First upload chunk. */ const struct flash_area *fa; +#if defined(CONFIG_MCUMGR_GRP_IMG_TOO_LARGE_SYSBUILD) && \ + (defined(CONFIG_MCUBOOT_BOOTLOADER_MODE_SWAP_WITHOUT_SCRATCH) || \ + defined(CONFIG_MCUBOOT_BOOTLOADER_MODE_SWAP_SCRATCH) || \ + defined(CONFIG_MCUBOOT_BOOTLOADER_MODE_OVERWRITE_ONLY) || \ + defined(CONFIG_MCUBOOT_BOOTLOADER_MODE_DIRECT_XIP) || \ + defined(CONFIG_MCUBOOT_BOOTLOADER_MODE_DIRECT_XIP_WITH_REVERT)) && \ + CONFIG_MCUBOOT_UPDATE_FOOTER_SIZE > 0 + const struct flash_area *fa_current; + int current_img_area; +#elif defined(CONFIG_MCUMGR_GRP_IMG_TOO_LARGE_BOOTLOADER_INFO) + int max_image_size; +#endif if (req->img_data.len < sizeof(struct image_header)) { /* Image header is the first thing in the image */ @@ -576,6 +593,7 @@ int img_mgmt_upload_inspect(const struct img_mgmt_upload_req *req, IMG_MGMT_UPLOAD_ACTION_SET_RC_RSN(action, img_mgmt_err_str_hdr_malformed); return IMG_MGMT_ERR_INVALID_LENGTH; } + action->size = req->size; hdr = (struct image_header *)req->img_data.value; @@ -626,6 +644,72 @@ int img_mgmt_upload_inspect(const struct img_mgmt_upload_req *req, return IMG_MGMT_ERR_INVALID_IMAGE_TOO_LARGE; } +#if defined(CONFIG_MCUMGR_GRP_IMG_TOO_LARGE_SYSBUILD) && \ + (defined(CONFIG_MCUBOOT_BOOTLOADER_MODE_SWAP_WITHOUT_SCRATCH) || \ + defined(CONFIG_MCUBOOT_BOOTLOADER_MODE_SWAP_SCRATCH) || \ + defined(CONFIG_MCUBOOT_BOOTLOADER_MODE_OVERWRITE_ONLY) || \ + defined(CONFIG_MCUBOOT_BOOTLOADER_MODE_DIRECT_XIP) || \ + defined(CONFIG_MCUBOOT_BOOTLOADER_MODE_DIRECT_XIP_WITH_REVERT)) && \ + CONFIG_MCUBOOT_UPDATE_FOOTER_SIZE > 0 + /* Check if slot1 is larger than slot0 by the update size, if so then the size + * check can be skipped because the devicetree partitions are okay + */ + current_img_area = img_mgmt_flash_area_id(req->image); + + if (current_img_area < 0) { + /* Current slot cannot be determined */ + LOG_ERR("Failed to determine active slot for image %d: %d", req->image, + current_img_area); + return IMG_MGMT_ERR_ACTIVE_SLOT_NOT_KNOWN; + } + + rc = flash_area_open(current_img_area, &fa_current); + if (rc) { + IMG_MGMT_UPLOAD_ACTION_SET_RC_RSN(action, + img_mgmt_err_str_flash_open_failed); + LOG_ERR("Failed to open flash area ID %u: %d", current_img_area, rc); + flash_area_close(fa); + return IMG_MGMT_ERR_FLASH_OPEN_FAILED; + } + + flash_area_close(fa_current); + + LOG_DBG("Primary size: %d, secondary size: %d, overhead: %d, max update size: %d", + fa_current->fa_size, fa->fa_size, CONFIG_MCUBOOT_UPDATE_FOOTER_SIZE, + (fa->fa_size + CONFIG_MCUBOOT_UPDATE_FOOTER_SIZE)); + + if (fa_current->fa_size >= (fa->fa_size + CONFIG_MCUBOOT_UPDATE_FOOTER_SIZE)) { + /* Upgrade slot is of sufficient size, nothing to check */ + LOG_INF("Upgrade slots already sized appropriately, " + "CONFIG_MCUMGR_GRP_IMG_TOO_LARGE_SYSBUILD is not needed"); + goto skip_size_check; + } + + if (req->size > (fa->fa_size - CONFIG_MCUBOOT_UPDATE_FOOTER_SIZE)) { + IMG_MGMT_UPLOAD_ACTION_SET_RC_RSN(action, + img_mgmt_err_str_image_too_large); + flash_area_close(fa); + LOG_ERR("Upload too large for slot (with end offset): %u > %u", req->size, + (fa->fa_size - CONFIG_MCUBOOT_UPDATE_FOOTER_SIZE)); + return IMG_MGMT_ERR_INVALID_IMAGE_TOO_LARGE; + } + +skip_size_check: +#elif defined(CONFIG_MCUMGR_GRP_IMG_TOO_LARGE_BOOTLOADER_INFO) + rc = blinfo_lookup(BLINFO_MAX_APPLICATION_SIZE, (char *)&max_image_size, + sizeof(max_image_size)); + + if (rc == sizeof(max_image_size) && max_image_size > 0 && + req->size > max_image_size) { + IMG_MGMT_UPLOAD_ACTION_SET_RC_RSN(action, + img_mgmt_err_str_image_too_large); + flash_area_close(fa); + LOG_ERR("Upload too large for slot (with max image size): %u > %u", + req->size, max_image_size); + return IMG_MGMT_ERR_INVALID_IMAGE_TOO_LARGE; + } +#endif + #if defined(CONFIG_MCUMGR_GRP_IMG_REJECT_DIRECT_XIP_MISMATCHED_SLOT) if (hdr->ih_flags & IMAGE_F_ROM_FIXED) { if (fa->fa_off != hdr->ih_load_addr) { From 05c38cb2f5780b7b3ccb057fb4aa0e65a7fa9b1a Mon Sep 17 00:00:00 2001 From: Navinkumar Balabakthan Date: Mon, 5 Jun 2023 08:42:35 +0000 Subject: [PATCH 3103/3723] soc: arm64: intel_socfpga: changes in system_manager SOCFPGA_SYSMGR_REG_BASE base address now read from Device tree This commit changes the way the SOCFPGA_SYSMGR_REG_BASE base address is determined. Previously, the address was hard-coded in the system_manager source file. This commit changes the code to read the address from the Device tree. This makes the code more flexible and allows the base address to be different for different boards. Signed-off-by: Navinkumar Balabakthan --- soc/arm64/intel_socfpga/common/socfpga_system_manager.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/soc/arm64/intel_socfpga/common/socfpga_system_manager.h b/soc/arm64/intel_socfpga/common/socfpga_system_manager.h index 4e56ee5af4f..58f9e0d2c56 100644 --- a/soc/arm64/intel_socfpga/common/socfpga_system_manager.h +++ b/soc/arm64/intel_socfpga/common/socfpga_system_manager.h @@ -8,7 +8,7 @@ #define SOCFPGA_SYSTEMMANAGER_H /* System Manager Register Map */ -#define SOCFPGA_SYSMGR_REG_BASE 0xffd12000 +#define SOCFPGA_SYSMGR_REG_BASE DT_REG_ADDR(DT_NODELABEL(sysmgr)) #define SOCFPGA_SYSMGR_SDMMC 0x28 From 6048373bd2ab16b6395e4d6a200c050becd50dc2 Mon Sep 17 00:00:00 2001 From: Navinkumar Balabakthan Date: Tue, 17 Oct 2023 06:19:37 +0000 Subject: [PATCH 3104/3723] dts: arm64: intel: dtsi support for cadence Nand driver for Agilex5 dtsi support for nand controller added to bring up nand driver on Agilex5 Signed-off-by: Navinkumar Balabakthan --- dts/arm64/intel/intel_socfpga_agilex5.dtsi | 16 ++++++++++++++ dts/bindings/flash_controller/cdns,nand.yaml | 22 ++++++++++++++++++++ 2 files changed, 38 insertions(+) create mode 100644 dts/bindings/flash_controller/cdns,nand.yaml diff --git a/dts/arm64/intel/intel_socfpga_agilex5.dtsi b/dts/arm64/intel/intel_socfpga_agilex5.dtsi index f4566e2f17e..21cf2e68ed0 100644 --- a/dts/arm64/intel/intel_socfpga_agilex5.dtsi +++ b/dts/arm64/intel/intel_socfpga_agilex5.dtsi @@ -219,4 +219,20 @@ status = "disabled"; zephyr,num-clients = <2>; }; + + /* cadence Nand Flash controller*/ + nand: nand@10B80000 { + compatible = "cdns,nand"; + reg = <0x10B80000 0X10000>, + <0x10840000 0x10000>; + reg-names = "nand_reg","sdma"; + interrupt-parent = <&gic>; + interrupts = ; + resets = <&reset RSTMGR_NAND_RSTLINE>, + <&reset RSTMGR_SOFTPHY_RSTLINE>; + block-size = <0x20000>; + data-rate-mode = <0>; + status = "disabled"; + }; + }; diff --git a/dts/bindings/flash_controller/cdns,nand.yaml b/dts/bindings/flash_controller/cdns,nand.yaml new file mode 100644 index 00000000000..c588c1837fe --- /dev/null +++ b/dts/bindings/flash_controller/cdns,nand.yaml @@ -0,0 +1,22 @@ +# Copyright (c) 2023 Intel Corporation +# SPDX-License-Identifier: Apache-2.0 + +description: Cadence Nand flash controller + +compatible: "cdns,nand" + +include: [flash-controller.yaml, reset-device.yaml] + +properties: + data-rate-mode: + type: int + required: true + description: Data Rate mode Selection. 0 - SDR , 1 - NVDDR. + enum: + - 0 + - 1 + + block-size: + type: int + required: true + description: Erase Block size of Cadence Nand From 966c4c37abe13702b1e35e181b167d221ca99dbb Mon Sep 17 00:00:00 2001 From: Navinkumar Balabakthan Date: Tue, 6 Jun 2023 05:02:03 +0000 Subject: [PATCH 3105/3723] drivers: flash: Added cdns Nand Driver Added Cadence NAND driver to support reading, erasing and writing data. Signed-off-by: Navinkumar Balabakthan --- drivers/flash/CMakeLists.txt | 1 + drivers/flash/Kconfig | 1 + drivers/flash/Kconfig.cadence_nand | 53 + drivers/flash/flash_cadence_nand.c | 270 +++++ drivers/flash/flash_cadence_nand_ll.c | 1472 +++++++++++++++++++++++++ drivers/flash/flash_cadence_nand_ll.h | 377 +++++++ 6 files changed, 2174 insertions(+) create mode 100644 drivers/flash/Kconfig.cadence_nand create mode 100644 drivers/flash/flash_cadence_nand.c create mode 100644 drivers/flash/flash_cadence_nand_ll.c create mode 100644 drivers/flash/flash_cadence_nand_ll.h diff --git a/drivers/flash/CMakeLists.txt b/drivers/flash/CMakeLists.txt index 75bafb85941..6b896288d14 100644 --- a/drivers/flash/CMakeLists.txt +++ b/drivers/flash/CMakeLists.txt @@ -52,6 +52,7 @@ zephyr_library_sources_ifdef(CONFIG_SOC_FLASH_XMC4XXX soc_flash_xmc4xxx.c) zephyr_library_sources_ifdef(CONFIG_FLASH_RPI_PICO flash_rpi_pico.c) zephyr_library_sources_ifdef(CONFIG_FLASH_ANDES_QSPI flash_andes_qspi.c) zephyr_library_sources_ifdef(CONFIG_FLASH_AMBIQ flash_ambiq.c) +zephyr_library_sources_ifdef(CONFIG_FLASH_CDNS_NAND flash_cadence_nand.c flash_cadence_nand_ll.c) if(CONFIG_FLASH_MCUX_FLEXSPI_XIP) dt_chosen(chosen_flash PROPERTY "zephyr,flash") diff --git a/drivers/flash/Kconfig b/drivers/flash/Kconfig index 698190e7780..81b4cdbe40d 100644 --- a/drivers/flash/Kconfig +++ b/drivers/flash/Kconfig @@ -151,6 +151,7 @@ source "drivers/flash/Kconfig.gd32" source "drivers/flash/Kconfig.xmc4xxx" source "drivers/flash/Kconfig.ifx_cat1" +source "drivers/flash/Kconfig.cadence_nand" source "drivers/flash/Kconfig.numaker" diff --git a/drivers/flash/Kconfig.cadence_nand b/drivers/flash/Kconfig.cadence_nand new file mode 100644 index 00000000000..52b7a1422b1 --- /dev/null +++ b/drivers/flash/Kconfig.cadence_nand @@ -0,0 +1,53 @@ +# Copyright (c) 2023 Intel Corporation. +# SPDX-License-Identifier: Apache-2.0 + +# Macro to find node in device tree +DT_CHOSEN_CDNS_NAND_NODE := nand + +config FLASH_CDNS_NAND + bool "Cadence NAND Flash driver" + default y + depends on DT_HAS_CDNS_NAND_ENABLED + select FLASH_HAS_PAGE_LAYOUT + select FLASH_HAS_DRIVER_ENABLED + help + Enable Cadence NAND support. + +if FLASH_CDNS_NAND + +config CDNS_NAND_INTERRUPT_SUPPORT + bool "Cadence Nand Interrupt Support" + def_bool $(dt_node_has_prop,$(DT_CHOSEN_CDNS_NAND_NODE),interrupts) + help + Enable Cadence Nand Interrupt Support. + +choice + prompt "Set the NAND Operating mode" + default CDNS_NAND_CDMA_MODE + help + Specify the Operating mode used by the driver. + +config CDNS_NAND_CDMA_MODE + bool "Cadence Nand CDMA Operating Mode" + +config CDNS_NAND_PIO_MODE + bool "Cadence Nand PIO Operating Mode" + +config CDNS_NAND_GENERIC_MODE + bool "Cadence Nand Generic Operating Mode" + +endchoice + +config FLASH_CDNS_CDMA_PAGE_COUNT + int "Set the page count for a single transfer in the CDMA Mode" + default 10 + help + Configure the page count for a single transfer in the CDMA Mode + +config FLASH_CDNS_CDMA_BLOCK_COUNT + int "Set the block count for a single transfer in the CDMA Mode" + default 10 + help + Configure the block count for a single transfer in the CDMA Mode + +endif # FLASH_CDNS_NAND diff --git a/drivers/flash/flash_cadence_nand.c b/drivers/flash/flash_cadence_nand.c new file mode 100644 index 00000000000..b527a5082ce --- /dev/null +++ b/drivers/flash/flash_cadence_nand.c @@ -0,0 +1,270 @@ +/* + * Copyright (c) 2023, Intel Corporation. + * + * SPDX-License-Identifier: Apache-2.0 + */ +#define DT_DRV_COMPAT cdns_nand + +#include "socfpga_system_manager.h" + +#include +#include +#include + +/* Check if reset property is defined */ +#define CDNS_NAND_RESET_SUPPORT DT_ANY_INST_HAS_PROP_STATUS_OKAY(resets) + +#if CDNS_NAND_RESET_SUPPORT +#include +#endif + +#include "flash_cadence_nand_ll.h" + +#define DEV_CFG(_dev) ((const struct flash_cadence_nand_config *)(_dev)->config) +#define DEV_DATA(_dev) ((struct flash_cadence_nand_data *const)(_dev)->data) + +#define FLASH_WRITE_SIZE DT_PROP(DT_INST(0, DT_DRV_COMPAT), block_size) + +#ifdef CONFIG_BOARD_INTEL_SOCFPGA_AGILEX5_SOCDK +#define DFI_CFG_OFFSET 0xFC +/* To check the DFI register setting for NAND in the System Manager */ +#define DFI_SEL_CHK (SOCFPGA_SYSMGR_REG_BASE + DFI_CFG_OFFSET) +#endif + +LOG_MODULE_REGISTER(flash_cdns_nand, CONFIG_FLASH_LOG_LEVEL); + +struct flash_cadence_nand_data { + DEVICE_MMIO_NAMED_RAM(nand_reg); + DEVICE_MMIO_NAMED_RAM(sdma); + /* device info structure */ + struct cadence_nand_params params; + /* Mutex to prevent multiple processes from accessing the same driver api */ + struct k_mutex nand_mutex; +#if CONFIG_CDNS_NAND_INTERRUPT_SUPPORT + /* Semaphore to send a signal from an interrupt handler to a thread */ + struct k_sem interrupt_sem; +#endif +}; + +struct flash_cadence_nand_config { + DEVICE_MMIO_NAMED_ROM(nand_reg); + DEVICE_MMIO_NAMED_ROM(sdma); +#if CDNS_NAND_RESET_SUPPORT + /* Reset controller device configuration for NAND*/ + const struct reset_dt_spec reset; + /* Reset controller device configuration for Combo Phy*/ + const struct reset_dt_spec combo_phy_reset; +#endif +#if CONFIG_CDNS_NAND_INTERRUPT_SUPPORT + void (*irq_config)(void); +#endif +}; + +static const struct flash_parameters flash_cdns_parameters = {.write_block_size = FLASH_WRITE_SIZE, + .erase_value = 0xFF}; + +#if CONFIG_FLASH_PAGE_LAYOUT + +struct flash_pages_layout flash_cdns_pages_layout; + +void flash_cdns_page_layout(const struct device *nand_dev, const struct flash_pages_layout **layout, + size_t *layout_size) +{ + struct flash_cadence_nand_data *const nand_data = DEV_DATA(nand_dev); + struct cadence_nand_params *nand_param = &nand_data->params; + + flash_cdns_pages_layout.pages_count = nand_param->page_count; + flash_cdns_pages_layout.pages_size = nand_param->page_size; + *layout = &flash_cdns_pages_layout; + *layout_size = 1; +} + +#endif + +static int flash_cdns_nand_erase(const struct device *nand_dev, off_t offset, size_t len) +{ + struct flash_cadence_nand_data *const nand_data = DEV_DATA(nand_dev); + struct cadence_nand_params *nand_param = &nand_data->params; + int ret; + + k_mutex_lock(&nand_data->nand_mutex, K_FOREVER); + + ret = cdns_nand_erase(nand_param, offset, len); + + k_mutex_unlock(&nand_data->nand_mutex); + + return ret; +} + +static int flash_cdns_nand_write(const struct device *nand_dev, off_t offset, const void *data, + size_t len) +{ + struct flash_cadence_nand_data *const nand_data = DEV_DATA(nand_dev); + struct cadence_nand_params *nand_param = &nand_data->params; + int ret; + + if (data == NULL) { + LOG_ERR("Invalid input parameter for NAND Flash Write!"); + return -EINVAL; + } + + k_mutex_lock(&nand_data->nand_mutex, K_FOREVER); + + ret = cdns_nand_write(nand_param, data, offset, len); + + k_mutex_unlock(&nand_data->nand_mutex); + + return ret; +} + +static int flash_cdns_nand_read(const struct device *nand_dev, off_t offset, void *data, size_t len) +{ + struct flash_cadence_nand_data *const nand_data = DEV_DATA(nand_dev); + struct cadence_nand_params *nand_param = &nand_data->params; + int ret; + + if (data == NULL) { + LOG_ERR("Invalid input parameter for NAND Flash Read!"); + return -EINVAL; + } + + k_mutex_lock(&nand_data->nand_mutex, K_FOREVER); + + ret = cdns_nand_read(nand_param, data, offset, len); + + k_mutex_unlock(&nand_data->nand_mutex); + + return ret; +} + +static const struct flash_parameters *flash_cdns_get_parameters(const struct device *nand_dev) +{ + ARG_UNUSED(nand_dev); + + return &flash_cdns_parameters; +} +static const struct flash_driver_api flash_cdns_nand_api = { + .erase = flash_cdns_nand_erase, + .write = flash_cdns_nand_write, + .read = flash_cdns_nand_read, + .get_parameters = flash_cdns_get_parameters, +#ifdef CONFIG_FLASH_PAGE_LAYOUT + .page_layout = flash_cdns_page_layout, +#endif +}; + +#if CONFIG_CDNS_NAND_INTERRUPT_SUPPORT + +static void cdns_nand_irq_handler(const struct device *nand_dev) +{ + struct flash_cadence_nand_data *const nand_data = DEV_DATA(nand_dev); + struct cadence_nand_params *nand_param = &nand_data->params; + + cdns_nand_irq_handler_ll(nand_param); + k_sem_give(&nand_param->interrupt_sem_t); +} + +#endif + +static int flash_cdns_nand_init(const struct device *nand_dev) +{ + DEVICE_MMIO_NAMED_MAP(nand_dev, nand_reg, K_MEM_CACHE_NONE); + DEVICE_MMIO_NAMED_MAP(nand_dev, sdma, K_MEM_CACHE_NONE); + const struct flash_cadence_nand_config *nand_config = DEV_CFG(nand_dev); + struct flash_cadence_nand_data *const nand_data = DEV_DATA(nand_dev); + struct cadence_nand_params *nand_param = &nand_data->params; + int ret; + +#ifdef CONFIG_BOARD_INTEL_SOCFPGA_AGILEX5_SOCDK + uint32_t status; + + status = sys_read32(DFI_SEL_CHK); + if ((status & 1) != 0) { + LOG_ERR("DFI not configured for NAND Flash controller!!!"); + return -ENODEV; + } +#endif + +#if CDNS_NAND_RESET_SUPPORT + /* Reset Combo phy and NAND only if reset controller driver is supported */ + if ((nand_config->combo_phy_reset.dev != NULL) && (nand_config->reset.dev != NULL)) { + if (!device_is_ready(nand_config->reset.dev)) { + LOG_ERR("Reset controller device not ready"); + return -ENODEV; + } + + ret = reset_line_toggle(nand_config->combo_phy_reset.dev, + nand_config->combo_phy_reset.id); + if (ret != 0) { + LOG_ERR("Combo phy reset failed"); + return ret; + } + + ret = reset_line_toggle(nand_config->reset.dev, nand_config->reset.id); + if (ret != 0) { + LOG_ERR("NAND reset failed"); + return ret; + } + } +#endif + nand_param->nand_base = DEVICE_MMIO_NAMED_GET(nand_dev, nand_reg); + nand_param->sdma_base = DEVICE_MMIO_NAMED_GET(nand_dev, sdma); + ret = k_mutex_init(&nand_data->nand_mutex); + if (ret != 0) { + LOG_ERR("Mutex creation Failed"); + return ret; + } + +#if CONFIG_CDNS_NAND_INTERRUPT_SUPPORT + + if (nand_config->irq_config == NULL) { + LOG_ERR("Interrupt function not initialized!!"); + return -EINVAL; + } + nand_config->irq_config(); + ret = k_sem_init(&nand_param->interrupt_sem_t, 0, 1); + if (ret != 0) { + LOG_ERR("Semaphore creation Failed"); + return ret; + } +#endif + nand_param->page_count = + (nand_param->npages_per_block * nand_param->nblocks_per_lun * nand_param->nluns); + /* NAND Memory Controller init */ + ret = cdns_nand_init(nand_param); + if (ret != 0) { + LOG_ERR("NAND initialization Failed"); + return ret; + } + return 0; +} + +#define CDNS_NAND_RESET_SPEC_INIT(inst) \ + .reset = RESET_DT_SPEC_INST_GET_BY_IDX(inst, 0), \ + .combo_phy_reset = RESET_DT_SPEC_INST_GET_BY_IDX(inst, 1), + +#define CREATE_FLASH_CADENCE_NAND_DEVICE(inst) \ + IF_ENABLED(CONFIG_CDNS_NAND_INTERRUPT_SUPPORT, \ + (static void cdns_nand_irq_config_##inst(void);)) \ + struct flash_cadence_nand_data flash_cadence_nand_data_##inst = { \ + .params = { \ + .datarate_mode = DT_INST_PROP(inst, data_rate_mode), \ + }}; \ + const struct flash_cadence_nand_config flash_cadence_nand_config_##inst = { \ + DEVICE_MMIO_NAMED_ROM_INIT_BY_NAME(nand_reg, DT_DRV_INST(inst)), \ + DEVICE_MMIO_NAMED_ROM_INIT_BY_NAME(sdma, DT_DRV_INST(inst)), \ + IF_ENABLED(DT_INST_NODE_HAS_PROP(inst, resets), (CDNS_NAND_RESET_SPEC_INIT(inst))) \ + IF_ENABLED(CONFIG_CDNS_NAND_INTERRUPT_SUPPORT, \ + (.irq_config = cdns_nand_irq_config_##inst,))}; \ + DEVICE_DT_INST_DEFINE(inst, flash_cdns_nand_init, NULL, &flash_cadence_nand_data_##inst, \ + &flash_cadence_nand_config_##inst, POST_KERNEL, \ + CONFIG_FLASH_INIT_PRIORITY, &flash_cdns_nand_api); \ + IF_ENABLED(CONFIG_CDNS_NAND_INTERRUPT_SUPPORT, \ + (static void cdns_nand_irq_config_##inst(void) \ + { \ + IRQ_CONNECT(DT_INST_IRQN(inst), DT_INST_IRQ(inst, priority), \ + cdns_nand_irq_handler, DEVICE_DT_INST_GET(inst), 0); \ + irq_enable(DT_INST_IRQN(inst)); \ + })) + +DT_INST_FOREACH_STATUS_OKAY(CREATE_FLASH_CADENCE_NAND_DEVICE) diff --git a/drivers/flash/flash_cadence_nand_ll.c b/drivers/flash/flash_cadence_nand_ll.c new file mode 100644 index 00000000000..a33eb424709 --- /dev/null +++ b/drivers/flash/flash_cadence_nand_ll.c @@ -0,0 +1,1472 @@ +/* + * Copyright (c) 2023, Intel Corporation. + * + * SPDX-License-Identifier: Apache-2.0 + */ +#include "flash_cadence_nand_ll.h" + +LOG_MODULE_REGISTER(flash_cdns_nand_ll, CONFIG_FLASH_LOG_LEVEL); + +/** + * Wait for the Cadence NAND controller to become idle. + * + * @param base_address The base address of the Cadence NAND controller. + * @retval 0 on success or -ETIMEDOUT error value on failure. + */ +static inline int32_t cdns_nand_wait_idle(uintptr_t base_address) +{ + /* Wait status command response ready */ + if (!WAIT_FOR(CNF_GET_CTRL_BUSY(sys_read32(CNF_CMDREG(base_address, CTRL_STATUS))) == 0U, + IDLE_TIME_OUT, k_msleep(1))) { + LOG_ERR("Timed out waiting for wait idle response"); + return -ETIMEDOUT; + } + return 0; +} + +/** + * Set the row address for a NAND flash memory device using the Cadence NAND controller. + * + * @param params The Cadence NAND parameters structure. + * @param local_row_address The row address. + * @param page_set The page set number. + */ +static void row_address_set(struct cadence_nand_params *params, uint32_t *local_row_address, + uint32_t page_set) +{ + uint32_t block_number = 0; + + block_number = ((page_set) / (params->npages_per_block)); + *local_row_address = 0; + *local_row_address |= ROW_VAL_SET((params->page_size_bit) - 1, 0, + ((page_set) % (params->npages_per_block))); + *local_row_address |= + ROW_VAL_SET((params->block_size_bit) - 1, (params->page_size_bit), block_number); + *local_row_address |= ROW_VAL_SET((params->lun_size_bit) - 1, (params->block_size_bit), + (block_number / params->nblocks_per_lun)); +} + +/** + * Retrieve information about the NAND flash device using the Cadence NAND controller. + * + * @param params The Cadence NAND parameters structure. + * @retval 0 on success or -ENXIO error value on failure. + */ +static int cdns_nand_device_info(struct cadence_nand_params *params) +{ + struct nf_ctrl_version *nf_ver; + uintptr_t base_address; + uint32_t reg_value = 0; + uint8_t type; + + base_address = params->nand_base; + + /* Read flash device version information */ + reg_value = sys_read32(CNF_CTRLPARAM(base_address, VERSION)); + nf_ver = (struct nf_ctrl_version *)®_value; + + LOG_INF("NAND Flash Version Information"); + LOG_INF("HPNFC Magic Number 0x%x", nf_ver->hpnfc_magic_number); + LOG_INF("Fixed number 0x%x", nf_ver->ctrl_fix); + LOG_INF("Controller Revision Number 0x%x", nf_ver->ctrl_rev); + + /* Interface Type */ + reg_value = sys_read32(CNF_CTRLPARAM(base_address, DEV_PARAMS0)); + type = CNF_GET_DEV_TYPE(reg_value); + if (type == CNF_DT_UNKNOWN) { + LOG_ERR("%s: device type unknown", __func__); + return -ENXIO; + } + + params->nluns = CNF_GET_NLUNS(reg_value); + LOG_INF("Number of LUMs %hhx", params->nluns); + + /* Pages per block */ + reg_value = sys_read32(CNF_CTRLCFG(base_address, DEV_LAYOUT)); + params->npages_per_block = GET_PAGES_PER_BLOCK(reg_value); + + /* Page size and spare size */ + reg_value = sys_read32(CNF_CTRLPARAM(base_address, DEV_AREA)); + params->page_size = GET_PAGE_SIZE(reg_value); + params->spare_size = GET_SPARE_SIZE(reg_value); + + /* Device blocks per LUN */ + params->nblocks_per_lun = sys_read32(CNF_CTRLPARAM(base_address, DEV_BLOCKS_PLUN)); + + /* Calculate block size and total device size */ + params->block_size = (params->npages_per_block * params->page_size); + params->device_size = ((long long)params->block_size * + (long long)(params->nblocks_per_lun * params->nluns)); + LOG_INF("block size %x total device size %llx", params->block_size, params->device_size); + + /* Calculate bit size of page, block and lun*/ + params->page_size_bit = find_msb_set((params->npages_per_block) - 1); + params->block_size_bit = find_msb_set((params->nblocks_per_lun) - 1); + params->lun_size_bit = find_msb_set((params->nluns) - 1); + return 0; +} + +/** + * Retrieve the status of a specific thread in the Cadence NAND controller. + * + * @param base_address The base address of the Cadence NAND controller. + * @param thread The thread identifier. + * @retval The status of the thread. + */ +static uint32_t cdns_nand_get_thrd_status(uintptr_t base_address, uint8_t thread) +{ + uint32_t status; + + sys_write32(THREAD_VAL(thread), (base_address + CMD_STATUS_PTR_ADDR)); + status = sys_read32((base_address + CMD_STAT_CMD_STATUS)); + return status; +} + +/** + * Wait for a specific thread in the Cadence controller to complete. + * + * @param base_address The base address of the Cadence controller. + * @param thread The thread identifier to wait for. + * @retval 0 on success or -ETIMEDOUT error value on failure. + */ +static int cdns_wait_for_thread(uintptr_t base_address, uint8_t thread) +{ + + if (!WAIT_FOR((sys_read32((base_address) + THR_STATUS) & BIT(thread)) == 0U, + THREAD_IDLE_TIME_OUT, k_msleep(1))) { + LOG_ERR("Timed out waiting for thread response"); + return -ETIMEDOUT; + } + + return 0; +} + +/** + * Set features in the Cadence NAND controller using PIO operations. + * + * @param base_address The base address of the Cadence NAND controller. + * @param feat_addr The address of the feature to be set. + * @param feat_val The value of the feature to be set. + * @param thread The thread identifier for the PIO operation. + * @param vol_id The volume identifier for the feature set operation. + * @param use_intr Flag indicating whether to use interrupts during the operation. + * @retval 0 on success or -ETIMEDOUT error value on failure. + */ +static int cdns_nand_pio_set_features(uintptr_t base_address, uint8_t feat_addr, uint8_t feat_val, + uint8_t thread, uint8_t vol_id) +{ + uint32_t status = 0; + int ret = 0; + + ret = cdns_wait_for_thread(base_address, thread); + + if (ret != 0) { + return ret; + } + + sys_write32(SET_FEAT_ADDR(feat_addr), (base_address + CDNS_CMD_REG1)); + sys_write32(feat_val, (base_address + CDNS_CMD_REG2)); + status = CMD_0_THREAD_POS_SET(thread); + status |= CMD_0_C_MODE_SET(CT_PIO_MODE); + status |= PIO_CMD0_CT_SET(PIO_SET_FEA_MODE); + status |= CMD_0_VOL_ID_SET(vol_id); + sys_write32(status, (base_address + CDNS_CMD_REG0)); + return 0; +} + +/** + * Check whether a transfer complete for PIO operation in the Cadence controller has finished. + * + * @param base_address The base address of the Cadence controller. + * @param thread The thread identifier for the PIO operation. + * @retval 0 on success or negative error value on failure. + */ +static int cdns_pio_transfer_complete(uintptr_t base_address, uint8_t thread) +{ + uint32_t status; + + status = WAIT_FOR(((cdns_nand_get_thrd_status(base_address, thread)) != 0), IDLE_TIME_OUT, + k_msleep(1)); + + if (status == 0) { + LOG_ERR("Timed out waiting for thread status response"); + return -ETIMEDOUT; + } + + if ((status & (BIT(F_CSTAT_COMP)))) { + if ((status & (BIT(F_CSTAT_FAIL)))) { + LOG_ERR("Cadence status operation failed %s", __func__); + return -EIO; + } + } else { + LOG_ERR("Cadence status complete failed %s", __func__); + return -EIO; + } + return 0; +} + +/** + * Set the operational mode for the Cadence NAND controller. + * + * @param base_address The base address of the Cadence NAND controller. + * @param opr_mode The operational mode SDR / NVDDR to set. + * @retval 0 on success or negative error value on failure. + */ +static int cdns_nand_set_opr_mode(uintptr_t base_address, uint8_t opr_mode) +{ + uint8_t device_type; + uint32_t timing_mode = 0; + uint32_t status; + int ret; + + if (opr_mode == CNF_OPR_WORK_MODE_SDR) { + + status = ONFI_TIMING_MODE_SDR( + sys_read32(CNF_CTRLPARAM(base_address, ONFI_TIMING_0))); + timing_mode = find_lsb_set(status) - 1; + + /* PHY Register Timing setting*/ + sys_write32(PHY_CTRL_REG_SDR, (base_address + PHY_CTRL_REG_OFFSET)); + sys_write32(PHY_TSEL_REG_SDR, (base_address + PHY_TSEL_REG_OFFSET)); + sys_write32(PHY_DQ_TIMING_REG_SDR, (base_address + PHY_DQ_TIMING_REG_OFFSET)); + sys_write32(PHY_DQS_TIMING_REG_SDR, (base_address + PHY_DQS_TIMING_REG_OFFSET)); + sys_write32(PHY_GATE_LPBK_CTRL_REG_SDR, (base_address + PHY_GATE_LPBK_OFFSET)); + sys_write32(PHY_DLL_MASTER_CTRL_REG_SDR, (base_address + PHY_DLL_MASTER_OFFSET)); + + /* Async mode timing settings */ + sys_write32((CNF_ASYNC_TIMINGS_TRH) | (CNF_ASYNC_TIMINGS_TRP) | + (CNF_ASYNC_TIMINGS_TWH) | (CNF_ASYNC_TIMINGS_TWP), + CNF_MINICTRL(base_address, ASYNC_TOGGLE_TIMINGS)); + + /* Set operation work mode in common settings */ + sys_clear_bits(CNF_MINICTRL(base_address, CMN_SETTINGS), + CNF_OPR_WORK_MODE_SDR_MASK); + + } else { + /* NVDDR MODE */ + status = ONFI_TIMING_MODE_NVDDR( + sys_read32(CNF_CTRLPARAM(base_address, ONFI_TIMING_0))); + timing_mode = find_lsb_set(status) - 1; + /* PHY Register Timing setting*/ + sys_write32(PHY_CTRL_REG_DDR, (base_address + PHY_CTRL_REG_OFFSET)); + sys_write32(PHY_TSEL_REG_DDR, (base_address + PHY_TSEL_REG_OFFSET)); + sys_write32(PHY_DQ_TIMING_REG_DDR, (base_address + PHY_DQ_TIMING_REG_OFFSET)); + sys_write32(PHY_DQS_TIMING_REG_DDR, (base_address + PHY_DQS_TIMING_REG_OFFSET)); + sys_write32(PHY_GATE_LPBK_CTRL_REG_DDR, (base_address + PHY_GATE_LPBK_OFFSET)); + sys_write32(PHY_DLL_MASTER_CTRL_REG_DDR, (base_address + PHY_DLL_MASTER_OFFSET)); + /* Set operation work mode in common settings */ + sys_set_bits(CNF_MINICTRL(base_address, CMN_SETTINGS), + CNF_OPR_WORK_MODE_NVDDR_MASK); + } + + /* Wait for controller to be in idle state */ + ret = cdns_nand_wait_idle(base_address); + if (ret != 0) { + LOG_ERR("Wait for controller to be in idle state Failed"); + return ret; + } + + /* Check device type */ + device_type = CNF_GET_DEV_TYPE(sys_read32(CNF_CTRLPARAM(base_address, DEV_PARAMS0))); + + if (device_type != ONFI_INTERFACE) { + LOG_ERR("Driver does not support this interface"); + return -ENOTSUP; + } + /* Reset DLL PHY */ + sys_clear_bit(CNF_MINICTRL(base_address, DLL_PHY_CTRL), CNF_DLL_PHY_RST_N); + + /* Wait for controller to be in idle state */ + ret = cdns_nand_wait_idle(base_address); + if (ret != 0) { + LOG_ERR("Wait for controller to be in idle state Failed"); + return ret; + } + + ret = cdns_nand_pio_set_features(base_address, SET_FEAT_TIMING_MODE_ADDRESS, timing_mode, + NF_TDEF_TRD_NUM, VOL_ID); + if (ret != 0) { + return ret; + } + + ret = cdns_pio_transfer_complete(base_address, NF_TDEF_TRD_NUM); + if (ret != 0) { + LOG_ERR("cdns pio check failed"); + return ret; + } + + ret = cdns_nand_wait_idle(base_address); + if (ret != 0) { + LOG_ERR("Wait for controller to be in idle state Failed"); + return ret; + } + + /* set dll_rst_n in dll_phy_ctrl to 1 */ + sys_set_bit(CNF_MINICTRL(base_address, DLL_PHY_CTRL), CNF_DLL_PHY_RST_N); + + ret = cdns_nand_wait_idle(base_address); + if (ret != 0) { + LOG_ERR("Wait for controller to be in idle state Failed"); + return ret; + } + + return 0; +} + +/** + * Configure the transfer settings of the Cadence NAND controller. + * + * @param base_address The base address of the Cadence NAND controller. + * @retval 0 on success or -ETIMEDOUT error value on failure. + */ +static int cdns_nand_transfer_config(uintptr_t base_address) +{ + int ret = 0; + /* Wait for controller to be in idle state */ + ret = cdns_nand_wait_idle(base_address); + + if (ret != 0) { + LOG_ERR("Wait for controller to be in idle state Failed"); + return ret; + } + + /* Configure data transfer parameters */ + sys_write32(ENABLE, CNF_CTRLCFG(base_address, TRANS_CFG0)); + + /* Disable cache and multiplane. */ + sys_write32(DISABLE, CNF_CTRLCFG(base_address, MULTIPLANE_CFG)); + sys_write32(DISABLE, CNF_CTRLCFG(base_address, CACHE_CFG)); + + /* Clear all interrupts. */ + sys_write32(CLEAR_ALL_INTERRUPT, (base_address + INTR_STATUS)); + return 0; +} + +/** + * Initialize the Cadence NAND controller. + * + * @param params The Cadence NAND parameters structure. + * @retval 0 on success or negative error value on failure. + */ +int cdns_nand_init(struct cadence_nand_params *params) +{ + uint32_t reg_value_read = 0; + uintptr_t base_address = params->nand_base; + uint8_t datarate_mode = params->datarate_mode; + int ret; + + if (!WAIT_FOR(CNF_GET_INIT_COMP(sys_read32(CNF_CMDREG(base_address, CTRL_STATUS))) != 0U, + IDLE_TIME_OUT, k_msleep(1))) { + LOG_ERR("Timed out waiting for NAND Controller Init complete status response"); + return -ETIMEDOUT; + } + + if (CNF_GET_INIT_FAIL(sys_read32(CNF_CMDREG(base_address, CTRL_STATUS))) != 0) { + LOG_ERR("NAND Controller Init complete Failed!!!"); + return -ENODEV; + } + + ret = cdns_nand_device_info(params); + if (ret != 0) { + return ret; + } + + /* Hardware Support Features */ + reg_value_read = sys_read32(CNF_CTRLPARAM(base_address, FEATURE)); + /* Enable data integrity parity check if the data integrity parity mechanism is */ + /* supported by the device */ + if (CNF_HW_DI_PR_SUPPORT(reg_value_read) != 0) { + sys_set_bit(CNF_DI(base_address, CONTROL), CNF_DI_PAR_EN); + } + + /* Enable data integrity CRC check if the data integrity CRC mechanism is */ + /* supported by the device */ + if (CNF_HW_DI_CRC_SUPPORT(reg_value_read) != 0) { + sys_set_bit(CNF_DI(base_address, CONTROL), CNF_DI_CRC_EN); + } + /* Status polling mode, device control and status register */ + ret = cdns_nand_wait_idle(base_address); + + if (ret != 0) { + LOG_ERR("Wait for controller to be in idle state Failed"); + return ret; + } + sys_write32(DEV_STAT_DEF_VALUE, CNF_CTRLCFG(base_address, DEV_STAT)); + + /* Set operation work mode */ + ret = cdns_nand_set_opr_mode(base_address, datarate_mode); + if (ret != 0) { + return ret; + } + + /* Set data transfer configuration parameters */ + ret = cdns_nand_transfer_config(base_address); + if (ret != 0) { + return ret; + } + + /* Wait for controller to be in idle state */ + ret = cdns_nand_wait_idle(base_address); + if (ret != 0) { + LOG_ERR("Wait for controller to be in idle state Failed"); + return ret; + } + + /* DMA Setting */ + sys_write32((F_BURST_SEL_SET(NF_TDEF_BURST_SEL)) | (BIT(F_OTE)), + (base_address + NF_DMA_SETTING)); + + /* Pre fetch */ + sys_write32(((NF_FIFO_TRIGG_LVL_SET(PRE_FETCH_VALUE)) | + (NF_DMA_PACKAGE_SIZE_SET(PRE_FETCH_VALUE))), + (base_address + NF_PRE_FETCH)); + /* Total bits in row addressing*/ + params->total_bit_row = find_msb_set(((params->npages_per_block) - 1)) + + find_msb_set((params->nblocks_per_lun) - 1); + + if (ret != 0) { + LOG_ERR("Failed to establish device access width!"); + return -EINVAL; + } + /* Enable Global Interrupt for NAND*/ +#ifdef CONFIG_CDNS_NAND_INTERRUPT_SUPPORT + sys_set_bit((base_address + INTERRUPT_STATUS_REG), GINTR_ENABLE); +#endif + return 0; +} + +#if CONFIG_CDNS_NAND_CDMA_MODE +/** + * + * This function performs Command descriptor structure prepareation. + * + * @param nf_mem determine which NF memory bank will be selected + * @param flash_ptr start ROW address in NF memory + * @param mem_ptr system memory pointer + * @param ctype Command type (read/write/erase) + * @param cmd_cnt counter for commands + * @param dma_sel select DMA engine (0 - slave DMA, 1 - master DMA) + * @param vol_id specify target volume ID + * + */ +void cdns_nand_cdma_prepare(char nf_mem, uint32_t flash_ptr, char *mem_ptr, uint16_t ctype, + int32_t cmd_cnt, uint8_t dma_sel, uint8_t vol_id, + struct cdns_cdma_command_descriptor *desc) +{ + struct cdns_cdma_command_descriptor *cdma_desc; + + cdma_desc = desc; + /* set fields for one descriptor */ + cdma_desc->flash_pointer = flash_ptr; + cdma_desc->bank_number = nf_mem; + cdma_desc->command_flags |= CDMA_CF_DMA_MASTER_SET(dma_sel) | F_CFLAGS_VOL_ID_SET(vol_id); + cdma_desc->memory_pointer = (uintptr_t)mem_ptr; + cdma_desc->status = 0; + cdma_desc->sync_flag_pointer = 0; + cdma_desc->sync_arguments = 0; + cdma_desc->ctrl_data_ptr = 0x40; + cdma_desc->command_type = ctype; + if (cmd_cnt > 1) { + cdma_desc->next_pointer = (uintptr_t)(desc + 1); + cdma_desc->command_flags |= CFLAGS_MPTRPC_SET | CFLAGS_MPTRPC_SET; + cdma_desc->command_flags |= CFLAGS_CONT_SET; + } else { + cdma_desc->next_pointer = 0; +#ifdef CONFIG_CDNS_NAND_INTERRUPT_SUPPORT + cdma_desc->command_flags |= CDMA_CF_INT_SET; +#endif + } +} + +/** + * Check a command descriptor transfer complete status in the Cadence NAND controller. + * + * @param desc_ptr The pointer to the command descriptor structure. + * @param params The Cadence NAND parameters structure. + * @retval 0 on success or negative error value on failure. + */ +static int cdns_transfer_complete(struct cdns_cdma_command_descriptor *desc_ptr, + struct cadence_nand_params *params) +{ +#ifdef CONFIG_CDNS_NAND_INTERRUPT_SUPPORT + uint32_t status = 0; + + NAND_INT_SEM_TAKE(params); + sys_write32(NF_TDEF_TRD_NUM, (params->nand_base + CMD_STATUS_PTR_ADDR)); + status = sys_read32((params->nand_base + CMD_STAT_CMD_STATUS)); + if ((status & (BIT(F_CSTAT_COMP)))) { + if ((status & (BIT(F_CSTAT_FAIL)))) { + LOG_ERR("Cadence status operation failed %s", __func__); + return -EIO; + } + } else { + LOG_ERR("Cadence status complete failed %s", __func__); + return -EIO; + } +#else + ARG_UNUSED(params); + + if (!WAIT_FOR(((desc_ptr->status & (BIT(F_CSTAT_COMP))) != 0), IDLE_TIME_OUT, + k_msleep(1))) { + LOG_ERR("Timed out waiting for thread status response"); + return -ETIMEDOUT; + } + if ((desc_ptr->status & (BIT(F_CSTAT_FAIL))) != 0) { + LOG_ERR("Cadence status operation failed %s", __func__); + return -EIO; + } +#endif + return 0; +} + +/** + * Send a command descriptor to the Cadence NAND controller for execution. + * + * @param base_address The base address of the Cadence NAND controller. + * @param desc_ptr The pointer to the command descriptor. + * @param thread The thread number for the execution. + * @retval 0 on success or -ETIMEDOUT error value on failure. + */ +static int cdns_nand_send(uintptr_t base_address, char *desc_ptr, uint8_t thread) +{ + uint64_t desc_address; + uint32_t status; + int ret; + + desc_address = (uint64_t)desc_ptr; + + ret = cdns_wait_for_thread(base_address, thread); + + if (ret != 0) { + return ret; + } + /* desc_ptr address passing */ + sys_write32(desc_address & U32_MASK_VAL, (base_address + CDNS_CMD_REG2)); + sys_write32((desc_address >> 32) & U32_MASK_VAL, (base_address + CDNS_CMD_REG3)); + /* Thread selection */ + status = CMD_0_THREAD_POS_SET(thread); + /* CDMA Mode selection */ + status |= CMD_0_C_MODE_SET(CT_CDMA_MODE); + /* CMD 0 Reg write*/ + sys_write32(status, (base_address + CDNS_CMD_REG0)); + return 0; +} + +static int cdns_cdma_desc_transfer_finish(struct cadence_nand_params *params, uint32_t page_count, + uint32_t max_page_desc, uint32_t ctype, + uint32_t cond_start, char *buffer) +{ + uint32_t page_count_pass = 0; + uint32_t row_address = 0; + uint32_t base_address; + uint32_t page_buffer_size; + struct cdns_cdma_command_descriptor *cdma_desc; + int ret; + + page_buffer_size = (page_count > max_page_desc) ? max_page_desc : page_count; + + cdma_desc = k_malloc(sizeof(struct cdns_cdma_command_descriptor) * page_buffer_size); + + if (cdma_desc == NULL) { + LOG_ERR("Memory allocation error occurred %s", __func__); + return -ENOSR; + } + + base_address = params->nand_base; + + while (page_count > 0) { + row_address_set(params, &row_address, cond_start); + + if (page_count > max_page_desc) { + page_count_pass = max_page_desc; + page_count = page_count - max_page_desc; + cond_start = cond_start + page_count_pass; + } else { + page_count_pass = page_count; + page_count = page_count - page_count_pass; + } + for (int index = 0; index < page_count_pass; index++) { + cdns_nand_cdma_prepare(NF_TDEF_DEV_NUM, row_address, buffer, + (ctype + index), (page_count_pass - index), + DMA_MS_SEL, VOL_ID, (cdma_desc + index)); + } + ret = cdns_nand_send(base_address, (char *)cdma_desc, NF_TDEF_TRD_NUM); + + if (ret != 0) { + k_free(cdma_desc); + return ret; + } + + if (ctype != CNF_CMD_ERASE) { + buffer = buffer + (max_page_desc * params->page_size); + } + + ret = cdns_transfer_complete(cdma_desc, params); + + if (ret != 0) { + k_free(cdma_desc); + return ret; + } + } + + k_free(cdma_desc); + + return 0; +} +/** + * Perform a CDMA write operation for the Cadence NAND controller. + * + * @param params The Cadence NAND parameters structure. + * @param start_page_number The starting page number for the write operation. + * @param buffer The buffer containing the data to be written. + * @param page_count The number of pages to be written. + * @retval 0 on success or negative error value on failure. + */ +static int cdns_nand_cdma_write(struct cadence_nand_params *params, uint32_t start_page_number, + char *buffer, uint32_t page_count) +{ + int ret; + + ret = cdns_cdma_desc_transfer_finish(params, page_count, CONFIG_FLASH_CDNS_CDMA_PAGE_COUNT, + CNF_CMD_WR, start_page_number, buffer); + + return ret; +} + +/** + * Perform a CDMA read operation for the Cadence NAND controller. + * + * @param params The Cadence NAND parameters structure. + * @param start_page_number The starting page number for the read operation. + * @param buffer The buffer to store the read data. + * @param page_count The number of pages to be read. + * @retval 0 on success or negative error value on failure. + */ +static int cdns_nand_cdma_read(struct cadence_nand_params *params, uint32_t start_page_number, + char *buffer, uint32_t page_count) +{ + int ret; + + ret = cdns_cdma_desc_transfer_finish(params, page_count, CONFIG_FLASH_CDNS_CDMA_PAGE_COUNT, + CNF_CMD_RD, start_page_number, buffer); + + return ret; +} + +/** + * Perform a CDMA erase operation for the Cadence NAND controller. + * + * @param params The Cadence NAND parameters structure. + * @param start_block_number The starting block number for the erase operation. + * @param block_count The number of blocks to be erased. + * @retval 0 on success or negative error value on failure. + */ +static int cdns_nand_cdma_erase(struct cadence_nand_params *params, uint32_t start_block_number, + uint32_t block_count) +{ + int ret; + + ret = cdns_cdma_desc_transfer_finish(params, block_count, + CONFIG_FLASH_CDNS_CDMA_BLOCK_COUNT, CNF_CMD_ERASE, + start_block_number, NULL); + + return ret; +} +#endif + +#if CONFIG_CDNS_NAND_PIO_MODE + +/** + * Perform an erase operation on the Cadence NAND controller using PIO. + * + * @param params The Cadence NAND parameters structure. + * @param thread The thread identifier for the PIO operation. + * @param bank The bank identifier for the erase operation. + * @param start_block The starting block number for the erase operation. + * @param ctype The command type for the erase operation. + * @param block_count The number of blocks to be erased. + * @retval 0 on success or negative error value on failure. + */ +static int cdns_nand_pio_erase(struct cadence_nand_params *params, uint8_t thread, uint8_t bank, + uint32_t start_block, uint16_t ctype, uint32_t block_count) +{ + uint32_t status; + uintptr_t base_address; + uint32_t row_address = 0; + uint32_t index = 0; + int ret; + + base_address = params->nand_base; + for (index = 0; index < block_count; index++) { + + ret = cdns_wait_for_thread(base_address, thread); + + if (ret != 0) { + return ret; + } + row_address_set(params, &row_address, (start_block * params->npages_per_block)); + sys_write32(row_address, (base_address + CDNS_CMD_REG1)); + start_block++; + sys_write32((NF_CMD4_BANK_SET(bank)), (base_address + CDNS_CMD_REG4)); + status = CMD_0_THREAD_POS_SET(thread); +#ifdef CONFIG_CDNS_NAND_INTERRUPT_SUPPORT + status |= BIT(PIO_CF_INT); +#endif + status |= CMD_0_C_MODE_SET(CT_PIO_MODE); + status |= PIO_CMD0_CT_SET(ctype); + sys_write32(status, (base_address + CDNS_CMD_REG0)); + NAND_INT_SEM_TAKE(params); + ret = cdns_pio_transfer_complete(base_address, thread); + if (ret != 0) { + return ret; + } + } + + return 0; +} + +/** + * Prepare for a PIO operation in the Cadence NAND controller. + * + * @param base_address The base address of the Cadence NAND controller. + * @param thread The thread ID associated with the operation. + * @param bank The bank ID for the operation. + * @param row_address The row address for the operation. + * @param buf The buffer containing the data for the operation. + * @param ctype The command type for the operation. + * @param dma_sel The DMA selection flag for the operation. + * @param vol_id The volume ID for the operation. + * @retval 0 on success or -ETIMEDOUT error value on failure. + */ +static int cdns_nand_pio_prepare(uintptr_t base_address, uint8_t thread, uint8_t bank, + uint32_t row_address, char *buf, uint16_t ctype, uint8_t dma_sel, + uint8_t vol_id) +{ + uint64_t buf_addr = (uintptr_t)buf; + uint32_t status; + int ret; + + ret = cdns_wait_for_thread(base_address, thread); + + if (ret != 0) { + return ret; + } + + sys_write32(row_address, (base_address + CDNS_CMD_REG1)); + sys_write32(NF_CMD4_BANK_SET(bank), (base_address + CDNS_CMD_REG4)); + sys_write32(buf_addr & U32_MASK_VAL, (base_address + CDNS_CMD_REG2)); + sys_write32((buf_addr >> 32) & U32_MASK_VAL, (base_address + CDNS_CMD_REG3)); + status = CMD_0_THREAD_POS_SET(thread); +#ifdef CONFIG_CDNS_NAND_INTERRUPT_SUPPORT + status |= PIO_CF_INT_SET; +#endif + status |= PIO_CF_DMA_MASTER_SET(dma_sel); + status |= CMD_0_C_MODE_SET(CT_PIO_MODE); + status |= PIO_CMD0_CT_SET(ctype); + status |= CMD_0_VOL_ID_SET(vol_id); + sys_write32(status, (base_address + CDNS_CMD_REG0)); + return 0; +} + +/** + * Perform a PIO write operation for the Cadence NAND controller. + * + * @param params The Cadence NAND parameters structure. + * @param row_address The row address for the write operation. + * @param buffer The buffer containing the data to be written. + * @retval 0 on success or negative error value on failure. + */ +static int cdns_nand_pio_write(struct cadence_nand_params *params, uint32_t row_address, + char *buffer) +{ + uintptr_t base_address; + int ret; + + base_address = params->nand_base; + + ret = cdns_nand_pio_prepare(base_address, NF_TDEF_TRD_NUM, NF_TDEF_DEV_NUM, row_address, + buffer, CNF_CMD_WR, DMA_MS_SEL, VOL_ID); + + if (ret != 0) { + return ret; + } + NAND_INT_SEM_TAKE(params); + ret = cdns_pio_transfer_complete(base_address, NF_TDEF_TRD_NUM); + if (ret != 0) { + return ret; + } + + return 0; +} + +/** + * Perform a PIO read operation for the Cadence NAND controller. + * + * @param params The Cadence NAND parameters structure. + * @param row_address The row address for the read operation. + * @param buffer The buffer to store the read data. + * @retval 0 on success or negative error value on failure. + */ +static int cdns_nand_pio_read(struct cadence_nand_params *params, uint32_t row_address, + char *buffer) +{ + uintptr_t base_address; + int ret; + + base_address = params->nand_base; + + ret = cdns_nand_pio_prepare(base_address, NF_TDEF_TRD_NUM, NF_TDEF_DEV_NUM, row_address, + buffer, CNF_CMD_RD, DMA_MS_SEL, VOL_ID); + + if (ret != 0) { + return ret; + } + + NAND_INT_SEM_TAKE(params); + ret = cdns_pio_transfer_complete(base_address, NF_TDEF_TRD_NUM); + if (ret != 0) { + return ret; + } + + return 0; +} + +/** + * Perform a combined PIO read and write operation for the Cadence NAND controller. + * + * @param params The Cadence NAND parameters structure. + * @param start_page_number The starting page number for the read/write operation. + * @param buffer The buffer containing the data to be written or to store the read data. + * @param page_count The number of pages to be read or written. + * @param mode The mode of operation (read, write). + * @retval 0 on success or negative error value on failure. + */ +static int cdns_nand_pio_read_write(struct cadence_nand_params *params, uint32_t start_page_number, + char *buffer, uint32_t page_count, uint8_t mode) +{ + uint32_t index; + uint32_t pio_row_address = 0; + int ret = 0; + + for (index = 0; index < page_count; index++) { + row_address_set(params, &pio_row_address, start_page_number++); + if (mode == CDNS_READ) { + ret = cdns_nand_pio_read(params, pio_row_address, + buffer + (index * (params->page_size))); + } else { + ret = cdns_nand_pio_write(params, pio_row_address, + buffer + (index * (params->page_size))); + } + } + return ret; +} +#endif + +#if CONFIG_CDNS_NAND_GENERIC_MODE +/** + * Send a generic command to the Cadence NAND controller. + * + * @param params The Cadence NAND parameters structure. + * @param mini_ctrl_cmd The command to be sent. + * @retval 0 on success or -ETIMEDOUT error value on failure. + */ +static int cdns_generic_send_cmd(struct cadence_nand_params *params, uint64_t mini_ctrl_cmd) +{ + + uint32_t mini_ctrl_cmd_l, mini_ctrl_cmd_h, status; + uintptr_t base_address; + int ret = 0; + + base_address = params->nand_base; + mini_ctrl_cmd_l = mini_ctrl_cmd & U32_MASK_VAL; + mini_ctrl_cmd_h = mini_ctrl_cmd >> 32; + ret = cdns_nand_wait_idle(base_address); + + if (ret != 0) { + LOG_ERR("Wait for controller to be in idle state Failed"); + return ret; + } + sys_write32(mini_ctrl_cmd_l, (base_address + CDNS_CMD_REG2)); + sys_write32(mini_ctrl_cmd_h, (base_address + CDNS_CMD_REG3)); + /* Select generic command. */ + status = CMD_0_THREAD_POS_SET(NF_TDEF_TRD_NUM); +#ifdef CONFIG_CDNS_NAND_INTERRUPT_SUPPORT + status |= GEN_CF_INT_SET(GEN_CF_INT_ENABLE); +#endif + status |= CMD_0_C_MODE_SET(CT_GENERIC_MODE); + sys_write32(status, (base_address + CDNS_CMD_REG0)); + return 0; +} + +/** + * Send a generic command data to the Cadence NAND controller. + * + * @param params The Cadence NAND parameters structure. + * @param mode The mode of operation (read, write). + * @param data_length The length of the associated data. + * @retval 0 on success or -ETIMEDOUT error value on failure. + */ +static int cdns_generic_cmd_data(struct cadence_nand_params *params, uint8_t mode, + uint32_t data_length) +{ + uint64_t mini_ctrl_cmd = 0; + int ret = 0; + + mini_ctrl_cmd |= GCMD_TWB_VALUE; + mini_ctrl_cmd |= GCMCD_DATA_SEQ; + mini_ctrl_cmd |= GEN_SECTOR_COUNT_SET; + mini_ctrl_cmd |= GEN_LAST_SECTOR_SIZE_SET((uint64_t)data_length); + mini_ctrl_cmd |= GEN_DIR_SET((uint64_t)mode); + mini_ctrl_cmd |= GEN_SECTOR_SET((uint64_t)data_length); + ret = cdns_generic_send_cmd(params, mini_ctrl_cmd); + return ret; +} + +/** + * Wait for the completion of an SDMA operation in the Cadence NAND controller. + * + * @param base_address The base address of the Cadence NAND controller. + * @retval 0 on success or -ETIMEDOUT error value on failure. + */ +static int cdns_wait_sdma(uintptr_t base_address) +{ + + if (!WAIT_FOR(((sys_read32(base_address + INTR_STATUS) & BIT(SDMA_TRIGG)) != 0), + IDLE_TIME_OUT, k_msleep(1))) { + LOG_ERR("Timed out waiting for sdma response"); + return -ETIMEDOUT; + } + sys_set_bit((base_address + INTR_STATUS), SDMA_TRIGG); + return 0; +} + +/** + * Perform buffer copying to SDMA regs in the Cadence NAND controller. + * + * @param sdma_base_address The base address of the SDMA in the Cadence NAND controller. + * @param buffer The source or destination buffer for the copy operation. + * @param data_length The length of the data to be copied. + */ +static void sdma_buffer_copy_in(uint32_t sdma_base_address, uint8_t *buffer, uint32_t data_length) +{ + uint32_t index; + + for (index = 0; index < data_length; index++) { + sys_write8(*(buffer + index), sdma_base_address + index); + } +} + +/** + * Perform buffer copying from SDMA regs in the Cadence NAND controller. + * + * @param sdma_base_address The base address of the SDMA in the Cadence NAND controller. + * @param buffer The source or destination buffer for the copy operation. + * @param data_length The length of the data to be copied. + */ +static void sdma_buffer_copy_out(uint32_t sdma_base_address, uint8_t *buffer, uint32_t data_length) +{ + uint32_t index; + + for (index = 0; index < data_length; index++) { + *(buffer + index) = sys_read8(sdma_base_address + index); + } +} + +/** + * Perform a generic page read operation in the Cadence NAND controller. + * + * @param params The Cadence NAND parameters structure. + * @param read_address The address from which to read the page. + * @param data_buffer The buffer to store the read data. + * @retval 0 on success or negative error value on failure. + */ +static int cdns_generic_page_read(struct cadence_nand_params *params, uint64_t read_address, + void *data_buffer) +{ + uint64_t mini_ctrl_cmd = 0; + uintptr_t base_address = params->nand_base; + int ret; + + mini_ctrl_cmd = PAGE_READ_CMD; + mini_ctrl_cmd |= GCMD_TWB_VALUE; + if ((params->nluns > 1) || (params->total_bit_row > 16)) { + mini_ctrl_cmd |= PAGE_MAX_BYTES(PAGE_MAX_SIZE); + } else { + mini_ctrl_cmd |= PAGE_MAX_BYTES(PAGE_MAX_SIZE - 1); + } + mini_ctrl_cmd |= read_address << 32; + ret = cdns_generic_send_cmd(params, mini_ctrl_cmd); + if (ret != 0) { + return ret; + } + NAND_INT_SEM_TAKE(params); + ret = cdns_generic_cmd_data(params, CDNS_READ, params->page_size); + if (ret != 0) { + return ret; + } + NAND_INT_SEM_TAKE(params); + ret = cdns_wait_sdma(base_address); + if (ret != 0) { + return ret; + } + sdma_buffer_copy_out(params->sdma_base, data_buffer, params->page_size); + return 0; +} + +/** + * Perform a generic page write operation in the Cadence NAND controller. + * + * @param params The Cadence NAND parameters structure. + * @param write_address The address to which the page will be written. + * @param data_buffer The buffer containing the data to be written. + * @retval 0 on success or negative error value on failure. + */ +static int cdns_generic_page_write(struct cadence_nand_params *params, uint64_t write_address, + void *data_buffer) +{ + uint64_t mini_ctrl_cmd = 0; + int ret; + + uintptr_t base_address = params->nand_base; + + mini_ctrl_cmd |= GCMD_TWB_VALUE; + mini_ctrl_cmd |= GEN_ADDR_WRITE_DATA((uint32_t)write_address); + if ((params->nluns > 1) || (params->total_bit_row > BIT16_CHECK)) { + mini_ctrl_cmd |= PAGE_MAX_BYTES(PAGE_MAX_SIZE); + } else { + mini_ctrl_cmd |= PAGE_MAX_BYTES(PAGE_MAX_SIZE - 1); + } + mini_ctrl_cmd |= PAGE_WRITE_CMD; + ret = cdns_generic_send_cmd(params, mini_ctrl_cmd); + if (ret != 0) { + return ret; + } + NAND_INT_SEM_TAKE(params); + ret = cdns_generic_cmd_data(params, CDNS_WRITE, params->page_size); + if (ret != 0) { + return ret; + } + sdma_buffer_copy_in(params->sdma_base, data_buffer, params->page_size); + NAND_INT_SEM_TAKE(params); + mini_ctrl_cmd = 0; + mini_ctrl_cmd |= PAGE_WRITE_10H_CMD; + mini_ctrl_cmd |= GCMD_TWB_VALUE; + mini_ctrl_cmd |= PAGE_CMOD_CMD; + ret = cdns_generic_send_cmd(params, mini_ctrl_cmd); + if (ret != 0) { + return ret; + } + NAND_INT_SEM_TAKE(params); + ret = cdns_wait_sdma(base_address); + return ret; +} + +/** + * Perform a generic read or write operation for a range of pages in the Cadence NAND controller. + * + * @param params The Cadence NAND parameters structure. + * @param start_page_number The starting page number for the read or write operation. + * @param buffer The buffer containing the data to be written or to store the read data. + * @param page_count The number of pages to be read or written. + * @param mode The mode of operation (read, write). + * @retval 0 on success or negative error value on failure. + */ +static int cdns_nand_gen_read_write(struct cadence_nand_params *params, uint32_t start_page_number, + char *buffer, uint32_t page_count, uint8_t mode) +{ + uint64_t address = 0; + uint32_t index = 0; + uint32_t gen_row_address = 0; + int ret = 0; + + for (index = 0; index < page_count; index++) { + row_address_set(params, &gen_row_address, start_page_number++); + address = ((uint64_t)gen_row_address); + if (mode == CDNS_READ) { + ret = cdns_generic_page_read(params, address, + buffer + (index * (params->page_size))); + if (ret != 0) { + LOG_ERR("Cadence NAND Generic Page Read Error!!"); + return ret; + } + } else { + ret = cdns_generic_page_write(params, address, + buffer + (index * (params->page_size))); + if (ret != 0) { + LOG_ERR("Cadence NAND Generic Page write Error!!"); + return ret; + } + } + } + return 0; +} + +/** + * Perform a generic erase operation for a range of blocks in the Cadence NAND controller. + * + * @param params The Cadence NAND parameters structure. + * @param start_block The starting block number for the erase operation. + * @param block_count The number of blocks to be erased. + * @retval 0 on success or -ETIMEDOUT error value on failure. + */ +static int cdns_nand_gen_erase(struct cadence_nand_params *params, uint32_t start_block, + uint32_t block_count) +{ + uint64_t mini_ctrl_cmd = 0; + uintptr_t base_address = 0; + uint32_t gen_row_address = 0; + uint32_t index = 0; + int ret = 0; + + for (index = 0; index < block_count; index++) { + row_address_set(params, &gen_row_address, (start_block * params->npages_per_block)); + start_block++; + base_address = params->nand_base; + mini_ctrl_cmd |= GCMD_TWB_VALUE; + mini_ctrl_cmd |= ERASE_ADDR_SIZE; + mini_ctrl_cmd |= ((gen_row_address) & (U32_MASK_VAL)); + mini_ctrl_cmd |= PAGE_ERASE_CMD; + ret = cdns_generic_send_cmd(params, mini_ctrl_cmd); + if (ret != 0) { + return ret; + } + NAND_INT_SEM_TAKE(params); + } + return 0; +} +#endif + +/** + * Read data from the Cadence NAND controller into a buffer. + */ +static inline int cdns_read_data(struct cadence_nand_params *params, uint32_t start_page_number, + const void *buffer, uint32_t page_count) +{ + int ret; + +#if CONFIG_CDNS_NAND_CDMA_MODE + ret = cdns_nand_cdma_read(params, start_page_number, (char *)buffer, page_count); +#elif CONFIG_CDNS_NAND_PIO_MODE + ret = cdns_nand_pio_read_write(params, start_page_number, (char *)buffer, page_count, + CDNS_READ); +#elif CONFIG_CDNS_NAND_GENERIC_MODE + ret = cdns_nand_gen_read_write(params, start_page_number, (char *)buffer, page_count, + CDNS_READ); +#endif + return ret; +} + +/** + * Read data from the Cadence NAND controller into a buffer. + * + * @param params The Cadence NAND parameters structure. + * @param buffer The buffer to store the read data. + * @param offset The offset within the NAND to start reading from. + * @param size The size of the data to read. + * @retval 0 on success or negative error value on failure. + */ +int cdns_nand_read(struct cadence_nand_params *params, const void *buffer, uint32_t offset, + uint32_t size) +{ + uint32_t start_page_number; + uint32_t end_page_number; + uint32_t page_count; + int ret = 0; + uint16_t r_bytes; + uint16_t bytes_dif; + uint16_t lp_bytes_dif; + uint8_t check_page_first = 0; + uint8_t check_page_last = 0; + uint8_t *first_end_page; + uint8_t *last_end_page; + + if (params == NULL) { + LOG_ERR("Wrong parameter passed!!"); + return -EINVAL; + } + + if (size == 0) { + return 0; + } + + if ((offset >= params->device_size) || (size > (params->device_size - offset))) { + LOG_ERR("Wrong offset or size value passed!!"); + return -EINVAL; + } + + start_page_number = offset / (params->page_size); + end_page_number = ((offset + size) - 1) / ((params->page_size)); + + if ((offset % params->page_size) == 0) { + check_page_first = 1; + } + if (((offset + size) % params->page_size) == 0) { + check_page_last = 1; + } + page_count = end_page_number - start_page_number; + page_count++; + if ((check_page_last == 1) && (check_page_first == 1)) { + ret = cdns_read_data(params, start_page_number, (char *)buffer, page_count); + if (ret != 0) { + return ret; + } + + } else if (((check_page_last == 0) && (check_page_first == 1) && (page_count == 1)) || + ((check_page_last == 0) && (check_page_first == 0) && (page_count == 1)) || + ((check_page_last == 1) && (check_page_first == 0) && (page_count == 1))) { + first_end_page = (char *)k_malloc(sizeof(char) * (params->page_size)); + if (first_end_page != NULL) { + memset(first_end_page, 0xFF, sizeof(char) * (params->page_size)); + } else { + LOG_ERR("Memory allocation error occurred %s", __func__); + return -ENOSR; + } + ret = cdns_read_data(params, start_page_number, first_end_page, page_count); + if (ret != 0) { + k_free(first_end_page); + return ret; + } + memcpy((char *)buffer, first_end_page + (offset % (params->page_size)), size); + k_free(first_end_page); + } else if (((check_page_last == 0) && (check_page_first == 1) && (page_count == 2)) || + ((check_page_last == 0) && (check_page_first == 0) && (page_count == 2)) || + ((check_page_last == 1) && (check_page_first == 0) && (page_count == 2))) { + first_end_page = (char *)k_malloc(sizeof(char) * (params->page_size * 2)); + if (first_end_page != NULL) { + memset(first_end_page, 0xFF, sizeof(char) * (params->page_size * 2)); + } else { + LOG_ERR("Memory allocation error occurred %s", __func__); + return -ENOSR; + } + ret = cdns_read_data(params, start_page_number, first_end_page, page_count); + if (ret < 0) { + k_free(first_end_page); + return ret; + } + memcpy((char *)buffer, first_end_page + (offset % (params->page_size)), size); + k_free(first_end_page); + + } else if ((check_page_last == 0) && (check_page_first == 1) && (page_count > 2)) { + first_end_page = (char *)k_malloc(sizeof(char) * (params->page_size)); + if (first_end_page != NULL) { + memset(first_end_page, 0xFF, sizeof(char) * (params->page_size)); + } else { + LOG_ERR("Memory allocation error occurred %s", __func__); + return -ENOSR; + } + ret = cdns_read_data(params, end_page_number, first_end_page, 1); + if (ret < 0) { + k_free(first_end_page); + return ret; + } + r_bytes = (offset + size) % (params->page_size); + ret = cdns_read_data(params, start_page_number, (char *)buffer, (--page_count)); + if (ret != 0) { + k_free(first_end_page); + return ret; + } + + memcpy((char *)buffer + ((page_count - 1) * params->page_size), first_end_page, + r_bytes); + k_free(first_end_page); + + } else if ((check_page_last == 1) && (check_page_first == 0) && (page_count > 2)) { + first_end_page = (char *)k_malloc(sizeof(char) * (params->page_size)); + if (first_end_page != NULL) { + memset(first_end_page, 0xFF, sizeof(char) * (params->page_size)); + } else { + LOG_ERR("Memory allocation error occurred %s", __func__); + return -ENOSR; + } + ret = cdns_read_data(params, start_page_number, first_end_page, 1); + if (ret < 0) { + k_free(first_end_page); + return ret; + } + r_bytes = (offset) % (params->page_size); + bytes_dif = (((start_page_number + 1) * params->page_size) - r_bytes); + r_bytes = (offset + size) % (params->page_size); + ret = cdns_read_data(params, (++start_page_number), ((char *)buffer + bytes_dif), + (--page_count)); + if (ret != 0) { + k_free(first_end_page); + return ret; + } + memcpy((char *)buffer, first_end_page + r_bytes, bytes_dif); + k_free(first_end_page); + } else if ((check_page_last == 0) && (check_page_first == 0) && (page_count > 2)) { + first_end_page = (char *)k_malloc(sizeof(char) * (params->page_size)); + last_end_page = (char *)k_malloc(sizeof(char) * (params->page_size)); + if ((first_end_page != NULL) && (last_end_page != NULL)) { + memset(first_end_page, 0xFF, sizeof(char) * (params->page_size)); + memset(last_end_page, 0xFF, sizeof(char) * (params->page_size)); + } else { + LOG_ERR("Memory allocation error occurred %s", __func__); + return -ENOSR; + } + ret = cdns_read_data(params, start_page_number, first_end_page, 1); + if (ret != 0) { + k_free(first_end_page); + k_free(last_end_page); + return ret; + } + r_bytes = (offset) % (params->page_size); + bytes_dif = (((start_page_number + 1) * params->page_size) - r_bytes); + lp_bytes_dif = (offset + size) % (params->page_size); + ret = cdns_read_data(params, end_page_number, last_end_page, 1); + if (ret != 0) { + k_free(last_end_page); + k_free(first_end_page); + return ret; + } + r_bytes = (offset + size) % (params->page_size); + ret = cdns_read_data(params, (++start_page_number), ((char *)buffer + bytes_dif), + (page_count - 2)); + if (ret != 0) { + k_free(last_end_page); + k_free(first_end_page); + return ret; + } + memcpy((char *)buffer, first_end_page + r_bytes, bytes_dif); + memcpy(((char *)buffer + bytes_dif + + ((page_count - 2) * (params->npages_per_block))), + last_end_page, lp_bytes_dif); + } + + return 0; +} + +/** + * Write data from a buffer to the Cadence NAND controller. + * + * @param params The Cadence NAND parameters structure. + * @param buffer The buffer containing the data to be written. + * @param offset The offset within the NAND to start writing to. + * @param len The length of the data to write. + * @retval 0 on success or negative error value on failure. + */ +int cdns_nand_write(struct cadence_nand_params *params, const void *buffer, uint32_t offset, + uint32_t len) +{ + uint32_t start_page_number; + uint32_t end_page_number; + uint32_t page_count; + int ret = 0; + + if (params == NULL) { + LOG_ERR("Wrong parameter passed!!"); + return -EINVAL; + } + + if (len == 0) { + return 0; + } + + if ((offset >= params->device_size) || (len > (params->device_size - offset))) { + LOG_ERR("Wrong offset or len value passed!!"); + return -EINVAL; + } + + if ((offset % params->page_size) != 0) { + LOG_ERR("offset not page aligned!!! Page size = 0x%x", params->page_size); + return -EINVAL; + } + + if ((len % params->page_size) != 0) { + LOG_ERR("length not page aligned!!! Page size = 0x%x", params->page_size); + return -EINVAL; + } + + start_page_number = offset / (params->page_size); + end_page_number = ((offset + len) - 1) / ((params->page_size)); + page_count = end_page_number - start_page_number; + +#if CONFIG_CDNS_NAND_CDMA_MODE + ret = cdns_nand_cdma_write(params, start_page_number, (char *)buffer, ++page_count); +#elif CONFIG_CDNS_NAND_PIO_MODE + ret = cdns_nand_pio_read_write(params, start_page_number, (char *)buffer, ++page_count, + CDNS_WRITE); +#elif CONFIG_CDNS_NAND_GENERIC_MODE + ret = cdns_nand_gen_read_write(params, start_page_number, (char *)buffer, ++page_count, + CDNS_WRITE); +#endif + if (ret != 0) { + LOG_ERR("Cadence driver write Failed!!!"); + } + + return ret; +} + +/** + * Perform an erase operation on the Cadence NAND controller. + * + * @param params The Cadence NAND parameters structure. + * @param offset The offset within the NAND to start erasing. + * @param size The size of the data to erase. + * @retval 0 on success or negative error value on failure. + */ +int cdns_nand_erase(struct cadence_nand_params *params, uint32_t offset, uint32_t size) +{ + uint32_t start_block_number; + uint32_t end_block_number; + uint32_t block_count; + int ret; + + if (params == NULL) { + LOG_ERR("Wrong parameter passed!!"); + return -EINVAL; + } + + if (size == 0) { + return 0; + } + + if ((offset >= params->device_size) || (size > (params->device_size - offset))) { + LOG_ERR("Wrong offset or size value passed!!"); + return -EINVAL; + } + if ((offset % (params->block_size)) != 0) { + LOG_ERR("Offset value not aligned with block size!! Erase block size = %x", + params->block_size); + return -EINVAL; + } + if ((size % (params->block_size)) != 0) { + LOG_ERR("Length value not aligned with block size!! Erase block size = %x", + params->block_size); + return -EINVAL; + } + + start_block_number = (offset / ((params->page_size))) / (params->npages_per_block); + end_block_number = + (((offset + size) - 1) / ((params->page_size))) / (params->npages_per_block); + block_count = end_block_number - start_block_number; +#if CONFIG_CDNS_NAND_CDMA_MODE + ret = cdns_nand_cdma_erase(params, start_block_number, ++block_count); +#elif CONFIG_CDNS_NAND_PIO_MODE + ret = cdns_nand_pio_erase(params, NF_TDEF_TRD_NUM, NF_TDEF_DEV_NUM, start_block_number, + CNF_CMD_ERASE, ++block_count); +#elif CONFIG_CDNS_NAND_GENERIC_MODE + ret = cdns_nand_gen_erase(params, start_block_number, ++block_count); +#endif + if (ret != 0) { + LOG_ERR("Cadence driver Erase Failed!!!"); + } + + return ret; +} + +#if CONFIG_CDNS_NAND_INTERRUPT_SUPPORT +void cdns_nand_irq_handler_ll(struct cadence_nand_params *params) +{ + uint32_t status = 0; + uint8_t thread_num = 0; + + status = sys_read32(params->nand_base + THREAD_INTERRUPT_STATUS); + thread_num = find_lsb_set(status); + + if (GET_INIT_SET_CHECK(status, (thread_num - 1)) != 0) { + /* Clear the interrupt*/ + sys_write32(BIT((thread_num - 1)), params->nand_base + THREAD_INTERRUPT_STATUS); + } +} +#endif diff --git a/drivers/flash/flash_cadence_nand_ll.h b/drivers/flash/flash_cadence_nand_ll.h new file mode 100644 index 00000000000..b52e7c90535 --- /dev/null +++ b/drivers/flash/flash_cadence_nand_ll.h @@ -0,0 +1,377 @@ +/* + * Copyright (c) 2023, Intel Corporation. + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#ifndef CDNS_NAND_LL_H +#define CDNS_NAND_LL_H + +#include +#include +#include + +#define NAND_INT_SEM_TAKE(param_ptr) \ + COND_CODE_1(IS_ENABLED(CONFIG_CDNS_NAND_INTERRUPT_SUPPORT), \ + (k_sem_take(&(param_ptr->interrupt_sem_t), K_FOREVER)), ()) + +#define CNF_GET_INIT_COMP(x) (FIELD_GET(BIT(9), x)) +#define CNF_GET_INIT_FAIL(x) (FIELD_GET(BIT(10), x)) +#define CNF_GET_CTRL_BUSY(x) (FIELD_GET(BIT(8), x)) +#define GET_PAGE_SIZE(x) (FIELD_GET(GENMASK(15, 0), x)) +#define GET_PAGES_PER_BLOCK(x) (FIELD_GET(GENMASK(15, 0), x)) +#define GET_SPARE_SIZE(x) (FIELD_GET(GENMASK(31, 16), x)) +#define ONFI_TIMING_MODE_SDR(x) (FIELD_GET(GENMASK(15, 0), x)) +#define ONFI_TIMING_MODE_NVDDR(x) (FIELD_GET(GENMASK(31, 15), x)) + +/* Controller parameter registers */ +#define CNF_GET_NLUNS(x) (FIELD_GET(GENMASK(7, 0), x)) +#define CNF_GET_DEV_TYPE(x) (FIELD_GET(GENMASK(31, 30), x)) + +#define CNF_CTRLPARAM_VERSION (0x800) +#define CNF_CTRLPARAM_FEATURE (0x804) +#define CNF_CTRLPARAM_MFR_ID (0x808) +#define CNF_CTRLPARAM_DEV_AREA (0x80C) +#define CNF_CTRLPARAM_DEV_PARAMS0 (0x810) +#define CNF_CTRLPARAM_DEV_PARAMS1 (0x814) +#define CNF_CTRLPARAM_DEV_FEATUERS (0x818) +#define CNF_CTRLPARAM_DEV_BLOCKS_PLUN (0x81C) +#define CNF_CTRLPARAM_ONFI_TIMING_0 (0x824) +#define CNF_CTRLPARAM(_base, _reg) (_base + (CNF_CTRLPARAM_##_reg)) + +#define CNF_CMDREG_CTRL_STATUS (0x118) +#define CNF_CMDREG(_base, _reg) (_base + (CNF_CMDREG_##_reg)) +#define PINSEL(_x) (PINSEL##_x) +#define PIN(_x) PINSEL(_x)##SEL + +/*Hardware Features Support*/ +#define CNF_HW_NF_16_SUPPORT(x) (FIELD_GET(BIT(29), x)) +#define CNF_HW_NVDDR_SS_SUPPORT(x) (FIELD_GET(BIT(27), x)) +#define CNF_HW_ASYNC_SUPPORT(x) (FIELD_GET(BIT(26), x)) +#define CNF_HW_DMA_DATA_WIDTH_SUPPORT(x) (FIELD_GET(BIT(21), x)) +#define CNF_HW_DMA_ADDR_WIDTH_SUPPORT(x) (FIELD_GET(BIT(20), x)) +#define CNF_HW_DI_PR_SUPPORT(x) (FIELD_GET(BIT(14), x)) +#define CNF_HW_ECC_SUPPORT(x) (FIELD_GET(BIT(17), x)) +#define CNF_HW_RMP_SUPPORT(x) (FIELD_GET(BIT(12), x)) +#define CNF_HW_DI_CRC_SUPPORT(x) (FIELD_GET(BIT(8), x)) +#define CNF_HW_WR_PT_SUPPORT(x) (FIELD_GET(BIT(9), x)) + +/* Device types */ +#define CNF_DT_UNKNOWN (0x00) +#define CNF_DT_ONFI (0x01) +#define CNF_DT_JEDEC (0x02) +#define CNF_DT_LEGACY (0x03) + +/* Controller configuration registers */ +#define CNF_CTRLCFG_TRANS_CFG0 (0x400) +#define CNF_CTRLCFG_TRANS_CFG1 (0x404) +#define CNF_CTRLCFG_LONG_POLL (0x408) +#define CNF_CTRLCFG_SHORT_POLL (0x40C) +#define CNF_CTRLCFG_DEV_STAT (0x410) +#define CNF_CTRLCFG_DEV_LAYOUT (0x424) +#define CNF_CTRLCFG_ECC_CFG0 (0x428) +#define CNF_CTRLCFG_ECC_CFG1 (0x42C) +#define CNF_CTRLCFG_MULTIPLANE_CFG (0x434) +#define CNF_CTRLCFG_CACHE_CFG (0x438) +#define CNF_CTRLCFG_DMA_SETTINGS (0x43C) +#define CNF_CTRLCFG_FIFO_TLEVEL (0x454) + +#define CNF_CTRLCFG(_base, _reg) (_base + (CNF_CTRLCFG_##_reg)) + +/* Data integrity registers */ +#define CNF_DI_PAR_EN (0) +#define CNF_DI_CRC_EN (1) +#define CNF_DI_CONTROL (0x700) +#define CNF_DI_INJECT0 (0x704) +#define CNF_DI_INJECT1 (0x708) +#define CNF_DI_ERR_REG_ADDR (0x70C) +#define CNF_DI_INJECT2 (0x710) + +#define CNF_DI(_base, _reg) (_base + (CNF_DI_##_reg)) + +/* Thread idle timeout */ +#define THREAD_IDLE_TIME_OUT 500U + +/* Operation work modes */ +#define CNF_OPR_WORK_MODE_SDR (0) +#define CNF_OPR_WORK_MODE_NVDDR (1) +#define CNF_OPR_WORK_MODE_SDR_MASK (GENMASK(1, 0)) +#define CNF_OPR_WORK_MODE_NVDDR_MASK (BIT(0)) + +#define ONFI_INTERFACE (0x01) +#define NV_DDR_TIMING_READ (16) + +/* Interrupt register field offsets */ +#define INTERRUPT_STATUS_REG (0x0114) +#define THREAD_INTERRUPT_STATUS (0x0138) + +/* Mini controller DLL PHY controller register field offsets */ +#define CNF_DLL_PHY_RST_N (24) +#define CNF_DLL_PHY_EXT_WR_MODE (17) +#define CNF_DLL_PHY_EXT_RD_MODE (16) + +#define CNF_MINICTRL_WP_SETTINGS (0x1000) +#define CNF_MINICTRL_RBN_SETTINGS (0x1004) +#define CNF_MINICTRL_CMN_SETTINGS (0x1008) +#define CNF_MINICTRL_SKIP_BYTES_CFG (0x100C) +#define CNF_MINICTRL_SKIP_BYTES_OFFSET (0x1010) +#define CNF_MINICTRL_TOGGLE_TIMINGS0 (0x1014) +#define CNF_MINICTRL_TOGGLE_TIMINGS1 (0x1018) +#define CNF_MINICTRL_ASYNC_TOGGLE_TIMINGS (0x101C) +#define CNF_MINICTRL_SYNC_TIMINGS (0x1020) +#define CNF_MINICTRL_DLL_PHY_CTRL (0x1034) + +#define CNF_MINICTRL(_base, _reg) (_base + (CNF_MINICTRL_##_reg)) + +/* Async mode register field offsets */ +#define CNF_ASYNC_TIMINGS_TRH FIELD_PREP(GENMASK(28, 24), 2) +#define CNF_ASYNC_TIMINGS_TRP FIELD_PREP(GENMASK(20, 16), 4) +#define CNF_ASYNC_TIMINGS_TWH FIELD_PREP(GENMASK(12, 8), 2) +#define CNF_ASYNC_TIMINGS_TWP FIELD_PREP(GENMASK(4, 0), 4) + +/* Mini controller common settings register field offsets */ +#define CNF_CMN_SETTINGS_WR_WUP (20) +#define CNF_CMN_SETTINGS_RD_WUP (16) +#define CNF_CMN_SETTINGS_DEV16 (8) +#define CNF_CMN_SETTINGS_OPR (0) + +/* Interrupt status register. */ +#define INTR_STATUS (0x0110) +#define GINTR_ENABLE (31) +#define INTERRUPT_DISABLE (0) +#define INTERRUPT_ENABLE (1) + +/* CDMA Command type descriptor*/ +/* CDMA Command type Erase*/ +#define CNF_CMD_ERASE (0x1000) +/* CDMA Program Page type */ +#define CNF_CMD_WR (0x2100) +/* CDMA Read Page type */ +#define CNF_CMD_RD (0x2200) +#define DMA_MS_SEL (1) +#define VOL_ID (0) +#define CDMA_CF_DMA_MASTER (10) +#define CDMA_CF_DMA_MASTER_SET(x) FIELD_PREP(BIT(CDMA_CF_DMA_MASTER), x) +#define F_CFLAGS_VOL_ID (4) +#define F_CFLAGS_VOL_ID_SET(x) FIELD_PREP(GENMASK(7, 4), x) +#define CDMA_CF_INT (8) +#define CDMA_CF_INT_SET BIT(CDMA_CF_INT) +#define COMMON_SET_DEVICE_16BIT (8) +#define CDNS_READ (0) +#define CDNS_WRITE (1) +#define MAX_PAGES_IN_ONE_DSC (8) +#define CFLAGS_MPTRPC (0) +#define CFLAGS_MPTRPC_SET FIELD_PREP(BIT(CFLAGS_MPTRPC), 1) +#define CFLAGS_FPTRPC (1) +#define CFLAGS_FPTRPC_SET FIELD_PREP(BIT(CFLAGS_FPTRPC), 1) +#define CFLAGS_CONT (9) +#define CFLAGS_CONT_SET FIELD_PREP(BIT(CFLAGS_CONT), 1) +#define CLEAR_ALL_INTERRUPT (0xFFFFFFFF) +#define ENABLE (1) +#define DISABLE (0) +#define DEV_STAT_DEF_VALUE (0x40400000) + +/*Command Resister*/ +#define CDNS_CMD_REG0 (0x00) +#define CDNS_CMD_REG1 (0x04) +#define CDNS_CMD_REG2 (0x08) +#define CDNS_CMD_REG3 (0x0C) +#define CMD_STATUS_PTR_ADDR (0x10) +#define CMD_STAT_CMD_STATUS (0x14) +#define CDNS_CMD_REG4 (0x20) + +/* Cdns Nand Operation Modes*/ +#define CT_CDMA_MODE (0) +#define CT_PIO_MODE (1) +#define CT_GENERIC_MODE (3) +#define OPERATING_MODE_CDMA (0) +#define OPERATING_MODE_PIO (1) +#define OPERATING_MODE_GENERIC (2) + +#define THR_STATUS (0x120) +#define CMD_0_THREAD_POS (24) +#define CMD_0_THREAD_POS_SET(x) (FIELD_PREP(GENMASK(26, 24), x)) +#define CMD_0_C_MODE (30) +#define CMD_0_C_MODE_SET(x) (FIELD_PREP(GENMASK(31, 30), x)) +#define CMD_0_VOL_ID_SET(x) (FIELD_PREP(GENMASK(19, 16), x)) +#define PIO_SET_FEA_MODE (0x0100) +#define SET_FEAT_TIMING_MODE_ADDRESS (0x01) + + /* default thread number*/ +#define NF_TDEF_TRD_NUM (0) + +/* NF device number */ +#define NF_TDEF_DEV_NUM (0) +#define F_OTE (16) +#define F_BURST_SEL_SET(x) (FIELD_PREP(GENMASK(7, 0), x)) + +/* DMA maximum burst size (0-127)*/ +#define NF_TDEF_BURST_SEL (127) +#define NF_DMA_SETTING (0x043C) +#define NF_PRE_FETCH (0x0454) +#define PRE_FETCH_VALUE (1024/8) +#define NF_FIFO_TRIGG_LVL_SET(x) (FIELD_PREP(GENMASK(15, 0), x)) +#define NF_DMA_PACKAGE_SIZE_SET(x) (FIELD_PREP(GENMASK(31, 16), x)) +#define NF_FIFO_TRIGG_LVL (0) + +/* BCH correction strength */ +#define NF_TDEF_CORR_STR (0) +#define F_CSTAT_COMP (15) +#define F_CSTAT_FAIL (14) +#define HPNFC_STAT_INPR (0) +#define HPNFC_STAT_FAIL (2) +#define HPNFC_STAT_OK (1) +#define NF_16_ENABLE (1) +#define NF_16_DISABLE (0) + +/*PIO Mode*/ +#define NF_CMD4_BANK_SET(x) (FIELD_PREP(GENMASK(31, 24), x)) +#define PIO_CMD0_CT_POS (0) +#define PIO_CMD0_CT_SET(x) (FIELD_PREP(GENMASK(15, 0), x)) +#define PIO_CF_INT (20) +#define PIO_CF_INT_SET (FIELD_PREP(BIT(PIO_CF_INT), 1)) +#define PIO_CF_DMA_MASTER (21) +#define PIO_CF_DMA_MASTER_SET(x) (FIELD_PREP(BIT(PIO_CF_DMA_MASTER), x)) + +/* Phy registers*/ +#define PHY_DQ_TIMING_REG_OFFSET (0x00002000) +#define PHY_DQS_TIMING_REG_OFFSET (0x00002004) +#define PHY_GATE_LPBK_OFFSET (0x00002008) +#define PHY_DLL_MASTER_OFFSET (0x0000200c) +#define PHY_CTRL_REG_OFFSET (0x00002080) +#define PHY_TSEL_REG_OFFSET (0x00002084) + +#define PHY_CTRL_REG_SDR (0x00004040) +#define PHY_TSEL_REG_SDR (0x00000000) +#define PHY_DQ_TIMING_REG_SDR (0x00000002) +#define PHY_DQS_TIMING_REG_SDR (0x00100004) +#define PHY_GATE_LPBK_CTRL_REG_SDR (0x00D80000) +#define PHY_DLL_MASTER_CTRL_REG_SDR (0x00800000) +#define PHY_DLL_SLAVE_CTRL_REG_SDR (0x00000000) + +#define PHY_CTRL_REG_DDR (0x00000000) +#define PHY_TSEL_REG_DDR (0x00000000) +#define PHY_DQ_TIMING_REG_DDR (0x00000002) +#define PHY_DQS_TIMING_REG_DDR (0x00000004) +#define PHY_GATE_LPBK_CTRL_REG_DDR (0x00380002) +#define PHY_DLL_MASTER_CTRL_REG_DDR (0x001400fe) +#define PHY_DLL_SLAVE_CTRL_REG_DDR (0x00003f3f) + +/*SDMA*/ +#define GCMD_TWB_VALUE BIT64(6) +#define GCMCD_ADDR_SEQ (1) +#define GCMCD_DATA_SEQ (2) +#define ERASE_ADDR_SIZE (FIELD_PREP(GENMASK64(13, 11), 3ULL)) +#define GEN_SECTOR_COUNT (1ULL) +#define GEN_SECTOR_COUNT_SET (FIELD_PREP(GENMASK64(39, 32),\ + GEN_SECTOR_COUNT)) +#define GEN_SECTOR_SIZE (0x100ULL) +#define GEN_LAST_SECTOR_SIZE_SET(x) (FIELD_PREP(GENMASK64(55, 40), x)) +#define SDMA_TRIGG (21ULL) +#define SDMA_SIZE_ADDR (0x0440) +#define SDMA_TRD_NUM_ADDR (0x0444) +#define SDMA_ADDR0_ADDR (0x044c) +#define SDMA_ADDR1_ADDR (0x0450) +#define PAGE_READ_CMD (0x3ULL) +#define PAGE_WRITE_CMD (0x4ULL) +#define PAGE_ERASE_CMD (0x6ULL) +#define PAGE_CMOD_CMD (0x00) +#define PAGE_MAX_SIZE (4) +#define PAGE_MAX_BYTES(x) (FIELD_PREP(GENMASK64(13, 11), x)) +#define GEN_CF_INT (20) +#define GEN_CF_INT_SET(x) (FIELD_PREP(BIT(GEN_CF_INT), x)) +#define GEN_CF_INT_ENABLE (1) +#define GEN_ADDR_POS (16) +#define GEN_DIR_SET(x) (FIELD_PREP(BIT64(11), x)) +#define GEN_SECTOR_SET(x) (FIELD_PREP(GENMASK64(31, 16), x)) +#define PAGE_WRITE_10H_CMD (FIELD_PREP(GENMASK64(23, 16), 0x10ULL)) +#define GEN_ADDR_WRITE_DATA(x) (FIELD_PREP(GENMASK64(63, 32), x)) +#define NUM_ONE (1) +#define U32_MASK_VAL (0xFFFFFFFF) +#define BIT16_CHECK (16) +#define IDLE_TIME_OUT (5000U) +#define ROW_VAL_SET(x, y, z) (FIELD_PREP(GENMASK(x, y), z)) +#define SET_FEAT_ADDR(x) (FIELD_PREP(GENMASK(7, 0), x)) +#define THREAD_VAL(x) (FIELD_PREP(GENMASK(2, 0), x)) +#define INCR_CMD_TYPE(x) (x++) +#define DECR_CNT_ONE(x) (--x) +#define GET_INIT_SET_CHECK(x, y) (FIELD_GET(BIT(y), x)) +struct nf_ctrl_version { + uint32_t ctrl_rev:8; + uint32_t ctrl_fix:8; + uint32_t hpnfc_magic_number:16; +}; + +/* Cadence cdma command descriptor*/ +struct cdns_cdma_command_descriptor { + /* Next descriptor address*/ + uint64_t next_pointer; + /* Flash address is a 32-bit address comprising of ROW ADDR. */ + uint32_t flash_pointer; + uint16_t bank_number; + uint16_t reserved_0; + /*operation the controller needs to perform*/ + uint16_t command_type; + uint16_t reserved_1; + /* Flags for operation of this command. */ + uint16_t command_flags; + uint16_t reserved_2; + /* System/host memory address required for data DMA commands. */ + uint64_t memory_pointer; + /* Status of operation. */ + uint64_t status; + /* Address pointer to sync buffer location. */ + uint64_t sync_flag_pointer; + /* Controls the buffer sync mechanism. */ + uint32_t sync_arguments; + uint32_t reserved_4; + /* Control data pointer. */ + uint64_t ctrl_data_ptr; + +} __aligned(64); + +/* Row Address */ +union row_address { + struct { + uint32_t page_address:7; + uint32_t block_address:10; + uint32_t lun_address:3; + } row_bit_reg; + + uint32_t row_address_raw; +}; + +/* device info structure */ +struct cadence_nand_params { + uintptr_t nand_base; + uintptr_t sdma_base; + uint8_t datarate_mode; + uint8_t nluns; + uint16_t page_size; + uint16_t spare_size; + uint16_t npages_per_block; + uint32_t nblocks_per_lun; + uint32_t block_size; + uint8_t total_bit_row; + uint8_t page_size_bit; + uint8_t block_size_bit; + uint8_t lun_size_bit; + size_t page_count; + unsigned long long device_size; +#ifdef CONFIG_CDNS_NAND_INTERRUPT_SUPPORT + struct k_sem interrupt_sem_t; +#endif +} __aligned(32); + +/* Global function Api */ +int cdns_nand_init(struct cadence_nand_params *params); +int cdns_nand_read(struct cadence_nand_params *params, const void *buffer, uint32_t offset, + uint32_t size); +int cdns_nand_write(struct cadence_nand_params *params, const void *buffer, uint32_t offset, + uint32_t len); +int cdns_nand_erase(struct cadence_nand_params *params, uint32_t offset, uint32_t size); +#if CONFIG_CDNS_NAND_INTERRUPT_SUPPORT +void cdns_nand_irq_handler_ll(struct cadence_nand_params *params); +#endif + +#endif From 6a8d011c6526c4a75857afdcef21659dcd2bb78a Mon Sep 17 00:00:00 2001 From: Navinkumar Balabakthan Date: Tue, 6 Jun 2023 08:06:39 +0000 Subject: [PATCH 3106/3723] samples: drivers: Added Nand Test Application Nand Test Application has added in sample/drivers folder. Signed-off-by: Navinkumar Balabakthan --- samples/drivers/soc_flash_nand/CMakeLists.txt | 8 + .../intel_socfpga_agilex5_socdk.overlay | 19 +++ samples/drivers/soc_flash_nand/prj.conf | 10 ++ samples/drivers/soc_flash_nand/sample.yaml | 28 ++++ samples/drivers/soc_flash_nand/src/main.c | 150 ++++++++++++++++++ 5 files changed, 215 insertions(+) create mode 100644 samples/drivers/soc_flash_nand/CMakeLists.txt create mode 100644 samples/drivers/soc_flash_nand/boards/intel_socfpga_agilex5_socdk.overlay create mode 100644 samples/drivers/soc_flash_nand/prj.conf create mode 100644 samples/drivers/soc_flash_nand/sample.yaml create mode 100644 samples/drivers/soc_flash_nand/src/main.c diff --git a/samples/drivers/soc_flash_nand/CMakeLists.txt b/samples/drivers/soc_flash_nand/CMakeLists.txt new file mode 100644 index 00000000000..ea5e877d899 --- /dev/null +++ b/samples/drivers/soc_flash_nand/CMakeLists.txt @@ -0,0 +1,8 @@ +# Copyright (c) 2023 Intel Corporation +# SPDX-License-Identifier: Apache-2.0 + +cmake_minimum_required(VERSION 3.20.0) +find_package(Zephyr REQUIRED HINTS $ENV{ZEPHYR_BASE}) +project(cdns_nand) + +target_sources(app PRIVATE src/main.c) diff --git a/samples/drivers/soc_flash_nand/boards/intel_socfpga_agilex5_socdk.overlay b/samples/drivers/soc_flash_nand/boards/intel_socfpga_agilex5_socdk.overlay new file mode 100644 index 00000000000..1275aa15a25 --- /dev/null +++ b/samples/drivers/soc_flash_nand/boards/intel_socfpga_agilex5_socdk.overlay @@ -0,0 +1,19 @@ +/* + * Copyright (C) 2023 Intel Corporation + * SPDX-License-Identifier: Apache-2.0 + */ + +/* The overlay file should be used to enable any + * dts nodes required by this application for this + * board. + */ + +/ { + aliases { + nand = &nand; + }; +}; + +&nand { + status = "okay"; +}; diff --git a/samples/drivers/soc_flash_nand/prj.conf b/samples/drivers/soc_flash_nand/prj.conf new file mode 100644 index 00000000000..463cd27a152 --- /dev/null +++ b/samples/drivers/soc_flash_nand/prj.conf @@ -0,0 +1,10 @@ +# Copyright (c) 2023, Intel Corporation. +# SPDX-License-Identifier: Apache-2.0 + +# Misc +CONFIG_HEAP_MEM_POOL_SIZE=363840 + +# Enable Flash +CONFIG_FLASH=y +CONFIG_FLASH_PAGE_LAYOUT=y +CONFIG_LOG=y diff --git a/samples/drivers/soc_flash_nand/sample.yaml b/samples/drivers/soc_flash_nand/sample.yaml new file mode 100644 index 00000000000..1e68da3131a --- /dev/null +++ b/samples/drivers/soc_flash_nand/sample.yaml @@ -0,0 +1,28 @@ +sample: + description: Cadence Nand Driver sample application. + name: cdns_nand +tests: + sample.drivers.flash.soc_flash_nand: + platform_allow: + - intel_socfpga_agilex5_socdk + integration_platforms: + - intel_socfpga_agilex5_socdk + tags: + - flash + - cdns + harness: console + harness_config: + fixture: external_flash + type: multi_line + ordered: true + regex: + - "Nand flash driver test sample" + - "Nand flash driver block size 20000" + - "The Page size of 800" + - "Nand flash driver data erase successful...." + - "Nand flash driver write completed...." + - "Nand flash driver read completed...." + - "Nand flash driver read verified" + - "Nand flash driver data erase successful...." + - "Nand flash driver read verified after erase...." + - "Nand flash driver test sample completed...." diff --git a/samples/drivers/soc_flash_nand/src/main.c b/samples/drivers/soc_flash_nand/src/main.c new file mode 100644 index 00000000000..ddcd8fcba91 --- /dev/null +++ b/samples/drivers/soc_flash_nand/src/main.c @@ -0,0 +1,150 @@ +/* + * Copyright (c) 2023, Intel Corporation. + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include +#include +#include +#include +#include + +#ifndef OFFSET_PAGE +#define OFFSET_PAGE 0x00 +#endif + +#ifndef NAND_NUM_PAGES +#define NAND_NUM_PAGES 50 +#endif + +#define NAND_DEV DEVICE_DT_GET(DT_ALIAS(nand)); + +int main(void) +{ + const struct device *nand_dev; + struct flash_pages_info page; + size_t flash_block_size; + size_t total_pages; + int ret; + uint8_t *w_Page_buffer; + uint8_t *r_Page_buffer; + uint8_t page_data = 0; + + printk("Nand flash driver test sample\n"); + + nand_dev = NAND_DEV; + + if (!device_is_ready(nand_dev)) { + printk("Nand flash driver is not ready\n"); + return -ENODEV; + } + + total_pages = flash_get_page_count(nand_dev); + + flash_block_size = flash_get_write_block_size(nand_dev); + printk("Nand flash driver block size %lx\n", flash_block_size); + + ret = flash_get_page_info_by_offs(nand_dev, 0x00, &page); + + if (ret < 0) { + printk("Nand flash driver page info error\n"); + return ret; + } + printk("The Page size of %lx\n", page.size); + + w_Page_buffer = (uint8_t *)k_malloc(page.size * NAND_NUM_PAGES); + + r_Page_buffer = (uint8_t *)k_malloc(page.size * NAND_NUM_PAGES); + + if (w_Page_buffer != NULL) { + + for (int index = 0; index < page.size * NAND_NUM_PAGES; index++) { + w_Page_buffer[index] = (page_data++ % 255); + } + + } else { + printk("Write memory not allocated\n"); + return -ENOSR; + } + + if (r_Page_buffer != NULL) { + memset(r_Page_buffer, 0x55, page.size * NAND_NUM_PAGES); + } else { + printk("Read memory not allocated\n"); + k_free(w_Page_buffer); + return -ENOSR; + } + + ret = flash_erase(nand_dev, OFFSET_PAGE, flash_block_size); + + if (ret < 0) { + printk("Nand flash driver read Error\n"); + k_free(w_Page_buffer); + k_free(r_Page_buffer); + return ret; + } + printk("Nand flash driver data erase successful....\n"); + + ret = flash_write(nand_dev, OFFSET_PAGE, w_Page_buffer, page.size * NAND_NUM_PAGES); + if (ret < 0) { + printk("Nand flash driver write error\n"); + k_free(w_Page_buffer); + k_free(r_Page_buffer); + return ret; + } + printk("Nand flash driver write completed....\n"); + + ret = flash_read(nand_dev, OFFSET_PAGE, r_Page_buffer, page.size * NAND_NUM_PAGES); + if (ret < 0) { + printk("Nand flash driver read error\n"); + k_free(w_Page_buffer); + k_free(r_Page_buffer); + return ret; + } + + printk("Nand flash driver read completed....\n"); + + ret = memcmp(w_Page_buffer, r_Page_buffer, page.size * NAND_NUM_PAGES); + + if (ret < 0) { + printk("Nand flash driver read not match\n"); + k_free(w_Page_buffer); + k_free(r_Page_buffer); + return ret; + } + printk("Nand flash driver read verified\n"); + + ret = flash_erase(nand_dev, OFFSET_PAGE, flash_block_size); + + if (ret < 0) { + printk("Nand flash driver read Error\n"); + k_free(w_Page_buffer); + k_free(r_Page_buffer); + return ret; + } + printk("Nand flash driver data erase successful....\n"); + + ret = flash_read(nand_dev, OFFSET_PAGE, r_Page_buffer, page.size * NAND_NUM_PAGES); + + if (ret != 0) { + printk("Nand flash driver read error\n"); + k_free(w_Page_buffer); + k_free(r_Page_buffer); + return ret; + } + memset(w_Page_buffer, 0xFF, page.size * NAND_NUM_PAGES); + + ret = memcmp(w_Page_buffer, r_Page_buffer, page.size * NAND_NUM_PAGES); + + if (ret < 0) { + printk("Nand flash driver read not match\n"); + k_free(w_Page_buffer); + k_free(r_Page_buffer); + return ret; + } + printk("Nand flash driver read verified after erase....\n"); + printk("Nand flash driver test sample completed....\n"); + + return 0; +} From e3b9ecba5fbcc8038d82f7d1977114b9e16078b5 Mon Sep 17 00:00:00 2001 From: Navinkumar Balabakthan Date: Thu, 13 Jul 2023 10:35:57 +0000 Subject: [PATCH 3107/3723] CODEOWNERS: Add owner update Code owner added for nandflash driver. Signed-off-by: Navinkumar Balabakthan --- CODEOWNERS | 1 + 1 file changed, 1 insertion(+) diff --git a/CODEOWNERS b/CODEOWNERS index 060830cf52b..df8b4cb4d42 100644 --- a/CODEOWNERS +++ b/CODEOWNERS @@ -234,6 +234,7 @@ /drivers/flash/*cc13xx_cc26xx* @pepe2k /drivers/flash/*nrf* @de-nordic /drivers/flash/*esp32* @sylvioalves +/drivers/flash/flash_cadence_nand* @nbalabak /drivers/gpio/*b91* @andy-liu-telink /drivers/gpio/*lmp90xxx* @henrikbrixandersen /drivers/gpio/*nct38xx* @MulinChao @ChiHuaL From 374d354d16dddf2f6c4a72bb43017efb2e1bf101 Mon Sep 17 00:00:00 2001 From: Jordan Yates Date: Fri, 26 Jan 2024 11:48:45 +1000 Subject: [PATCH 3108/3723] sensing: sensing_sensor: fix doxygen warnings Add missing parameter information in `SENSING_SENSORS_DT_DEFINE` and `SENSING_SENSORS_DT_INST_DEFINE`. Signed-off-by: Jordan Yates --- include/zephyr/sensing/sensing_sensor.h | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/include/zephyr/sensing/sensing_sensor.h b/include/zephyr/sensing/sensing_sensor.h index 65271d08704..434c13b9052 100644 --- a/include/zephyr/sensing/sensing_sensor.h +++ b/include/zephyr/sensing/sensing_sensor.h @@ -206,6 +206,8 @@ extern const struct rtio_iodev_api __sensing_iodev_api; * * @param reg_ptr Pointer to the device's sensing_sensor_register_info. * + * @param cb_list_ptr Pointer to devices callback list. + * * @param init_fn Name of the init function of the driver. * * @param pm_device PM device resources reference (NULL if device does not use @@ -245,9 +247,8 @@ extern const struct rtio_iodev_api __sensing_iodev_api; * * @param ... other parameters as expected by SENSING_SENSORS_DT_DEFINE(). */ -#define SENSING_SENSORS_DT_INST_DEFINE(inst, reg_ptr, cb_list_ptr, ...) \ - SENSING_SENSORS_DT_DEFINE(DT_DRV_INST(inst), reg_ptr, \ - cb_list_ptr, __VA_ARGS__) +#define SENSING_SENSORS_DT_INST_DEFINE(inst, ...) \ + SENSING_SENSORS_DT_DEFINE(DT_DRV_INST(inst), __VA_ARGS__) /** * @brief Get reporter handles of a given sensor instance by sensor type. From 9e9913a4fd9000a1c6b7825d771c76de0139b2a2 Mon Sep 17 00:00:00 2001 From: Jordan Yates Date: Fri, 26 Jan 2024 11:49:48 +1000 Subject: [PATCH 3109/3723] testsuite: ztest: fix doxygen warnings Document missing parameters on `ztest_run_test_suite`. Signed-off-by: Jordan Yates --- subsys/testsuite/ztest/include/zephyr/ztest_test.h | 3 +++ 1 file changed, 3 insertions(+) diff --git a/subsys/testsuite/ztest/include/zephyr/ztest_test.h b/subsys/testsuite/ztest/include/zephyr/ztest_test.h index eb6d16cf784..1370bd1a2aa 100644 --- a/subsys/testsuite/ztest/include/zephyr/ztest_test.h +++ b/subsys/testsuite/ztest/include/zephyr/ztest_test.h @@ -546,6 +546,9 @@ void ztest_simple_1cpu_after(void *data); * @brief Run the specified test suite. * * @param suite Test suite to run. + * @param shuffle Shuffle tests + * @param suite_iter Test suite repetitions. + * @param case_iter Test case repetitions. */ #define ztest_run_test_suite(suite, shuffle, suite_iter, case_iter) \ z_ztest_run_test_suite(STRINGIFY(suite), shuffle, suite_iter, case_iter) From c7dab3df08540f316b1c9769d6aabf97776f3e43 Mon Sep 17 00:00:00 2001 From: Andriy Gelman Date: Tue, 26 Dec 2023 12:05:00 -0500 Subject: [PATCH 3110/3723] drivers: can: Add xmc4xxx CAN support Adds CAN drivers for XMC4xxx SoCs. XMC4xxx has multiple CAN nodes. The nodes share a common clock and a message object pool. The CAN nodes do not have a loopback mode. Instead there is an internal bus which can be used to exchange messages between nodes on the SoC. For this reason tests/samples which rely on the loopback feature have been disabled. Signed-off-by: Andriy Gelman --- drivers/can/CMakeLists.txt | 1 + drivers/can/Kconfig | 1 + drivers/can/Kconfig.xmc4xxx | 43 + drivers/can/can_xmc4xxx.c | 999 ++++++++++++++++++ .../infineon/xmc4500_F100x1024-pinctrl.dtsi | 41 + dts/arm/infineon/xmc4500_F100x1024.dtsi | 4 + .../infineon/xmc4700_F144x2048-pinctrl.dtsi | 104 ++ dts/arm/infineon/xmc4700_F144x2048.dtsi | 24 + dts/arm/infineon/xmc4xxx.dtsi | 30 + .../can/infineon,xmc4xxx-can-node.yaml | 35 + dts/bindings/can/infineon,xmc4xxx-can.yaml | 24 + modules/Kconfig.infineon | 5 + samples/drivers/can/counter/sample.yaml | 1 + soc/arm/infineon_xmc/4xxx/Kconfig.series | 1 + tests/drivers/can/api/testcase.yaml | 2 + 15 files changed, 1315 insertions(+) create mode 100644 drivers/can/Kconfig.xmc4xxx create mode 100644 drivers/can/can_xmc4xxx.c create mode 100644 dts/bindings/can/infineon,xmc4xxx-can-node.yaml create mode 100644 dts/bindings/can/infineon,xmc4xxx-can.yaml diff --git a/drivers/can/CMakeLists.txt b/drivers/can/CMakeLists.txt index e704402e1fd..f53cf7d2c1e 100644 --- a/drivers/can/CMakeLists.txt +++ b/drivers/can/CMakeLists.txt @@ -20,6 +20,7 @@ zephyr_library_sources_ifdef(CONFIG_CAN_STM32H7_FDCAN can_stm32h7_fdcan.c) zephyr_library_sources_ifdef(CONFIG_CAN_TCAN4X5X can_tcan4x5x.c) zephyr_library_sources_ifdef(CONFIG_CAN_RCAR can_rcar.c) zephyr_library_sources_ifdef(CONFIG_CAN_NUMAKER can_numaker.c) +zephyr_library_sources_ifdef(CONFIG_CAN_XMC4XXX can_xmc4xxx.c) zephyr_library_sources_ifdef(CONFIG_CAN_SJA1000 can_sja1000.c) zephyr_library_sources_ifdef(CONFIG_CAN_ESP32_TWAI can_esp32_twai.c) zephyr_library_sources_ifdef(CONFIG_CAN_KVASER_PCI can_kvaser_pci.c) diff --git a/drivers/can/Kconfig b/drivers/can/Kconfig index d31d7b981b2..702676c09a3 100644 --- a/drivers/can/Kconfig +++ b/drivers/can/Kconfig @@ -108,6 +108,7 @@ source "drivers/can/Kconfig.fake" source "drivers/can/Kconfig.nxp_s32" source "drivers/can/Kconfig.tcan4x5x" source "drivers/can/Kconfig.mcp251xfd" +source "drivers/can/Kconfig.xmc4xxx" source "drivers/can/transceiver/Kconfig" diff --git a/drivers/can/Kconfig.xmc4xxx b/drivers/can/Kconfig.xmc4xxx new file mode 100644 index 00000000000..2fbb5df7064 --- /dev/null +++ b/drivers/can/Kconfig.xmc4xxx @@ -0,0 +1,43 @@ +# Infineon XMC4xxx CAN configuration options +# Copyright (c) 2023 Andriy Gelman +# SPDX-License-Identifier: Apache-2.0 + +config CAN_XMC4XXX + bool "Infineon XMC4xxx CAN Driver" + default y + depends on DT_HAS_INFINEON_XMC4XXX_CAN_NODE_ENABLED + help + Enable Infineon XMC4xxx CAN Driver + +if CAN_XMC4XXX + +config CAN_XMC4XXX_MAX_TX_QUEUE + int "Maximum number of queued messages" + default 8 + range 1 32 + help + Defines the array size of transmit callback pointers and semaphores, + as well as the number of messages in the TX queue. + +config CAN_XMC4XXX_RX_FIFO_ITEMS + int "Number of CAN messages allocated to each RX FIFO" + default 8 + range 1 32 + help + Defines the number of CAN messages in each RX FIFO. A separate RX FIFO + is created for each RX filter. + +config CAN_XMC4XXX_INTERNAL_BUS_MODE + bool "Internal bus mode" + help + Connects all XMC4XXX CAN devices to an internal bus. Enables + message exchange between MCU CAN devices without any external connectors. + +config CAN_MAX_FILTER + int "Maximum number of concurrent active filters" + default 4 + range 1 32 + help + Maximum number of filters supported by the can_add_rx_callback() API call. + +endif # CAN_XMC4XXX diff --git a/drivers/can/can_xmc4xxx.c b/drivers/can/can_xmc4xxx.c new file mode 100644 index 00000000000..b6c578595ea --- /dev/null +++ b/drivers/can/can_xmc4xxx.c @@ -0,0 +1,999 @@ +/* + * Copyright (c) 2023 Andriy Gelman + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#define DT_DRV_COMPAT infineon_xmc4xxx_can_node + +#include +#include +#include +#include +#include +#include + +#include +#include + +#include +LOG_MODULE_REGISTER(can_xmc4xxx, CONFIG_CAN_LOG_LEVEL); + +#define SP_IS_SET(inst) DT_INST_NODE_HAS_PROP(inst, sample_point) || + +/* + * Macro to exclude the sample point algorithm from compilation if not used + * Without the macro, the algorithm would always waste ROM + */ +#define USE_SP_ALGO (DT_INST_FOREACH_STATUS_OKAY(SP_IS_SET) 0) + +#define CAN_XMC4XXX_MULTICAN_NODE DT_INST(0, infineon_xmc4xxx_can) + +#define CAN_XMC4XXX_NUM_MESSAGE_OBJECTS DT_PROP(CAN_XMC4XXX_MULTICAN_NODE, message_objects) +#define CAN_XMC4XXX_CLOCK_PRESCALER DT_PROP(CAN_XMC4XXX_MULTICAN_NODE, clock_prescaler) + +static CAN_GLOBAL_TypeDef *const can_xmc4xxx_global_reg = + (CAN_GLOBAL_TypeDef *)DT_REG_ADDR(CAN_XMC4XXX_MULTICAN_NODE); + +static bool can_xmc4xxx_global_init; +static uint32_t can_xmc4xxx_clock_frequency; + +SYS_BITARRAY_DEFINE_STATIC(mo_usage_bitarray, CAN_XMC4XXX_NUM_MESSAGE_OBJECTS); +static int can_xmc4xxx_num_free_mo = CAN_XMC4XXX_NUM_MESSAGE_OBJECTS; + +#define CAN_XMC4XXX_IRQ_MIN 76 +#define CAN_XMC4XXX_MAX_DLC 8 + +#define CAN_XMC4XXX_REG_TO_NODE_IND(reg) (((uint32_t)(reg) - (uint32_t)CAN_NODE0_BASE) / 0x100) + +struct can_xmc4xxx_tx_callback { + can_tx_callback_t function; + void *user_data; +}; + +struct can_xmc4xxx_rx_callback { + can_rx_callback_t function; + void *user_data; +}; + +struct can_xmc4xxx_rx_fifo { + CAN_MO_TypeDef *base; + CAN_MO_TypeDef *top; + CAN_MO_TypeDef *tail; + CAN_MO_TypeDef *head; +}; + +struct can_xmc4xxx_data { + struct can_driver_data common; + + enum can_state state; + struct k_mutex mutex; + + struct k_sem tx_sem; + struct can_xmc4xxx_tx_callback tx_callbacks[CONFIG_CAN_XMC4XXX_MAX_TX_QUEUE]; + + uint32_t filter_usage; + struct can_xmc4xxx_rx_callback rx_callbacks[CONFIG_CAN_MAX_FILTER]; + struct can_xmc4xxx_rx_fifo rx_fifos[CONFIG_CAN_MAX_FILTER]; +#if defined(CONFIG_CAN_ACCEPT_RTR) + struct can_xmc4xxx_rx_fifo rtr_fifos[CONFIG_CAN_MAX_FILTER]; +#endif + + CAN_MO_TypeDef *tx_mo[CONFIG_CAN_XMC4XXX_MAX_TX_QUEUE]; +}; + +struct can_xmc4xxx_config { + struct can_driver_config common; + + CAN_NODE_TypeDef *can; + bool clock_div8; + + uint8_t sjw; + uint8_t prop_seg; + uint8_t phase_seg1; + uint8_t phase_seg2; + + uint8_t service_request; + void (*irq_config_func)(void); + + uint8_t input_src; + const struct pinctrl_dev_config *pcfg; +}; + +static int can_xmc4xxx_set_mode(const struct device *dev, can_mode_t mode) +{ + struct can_xmc4xxx_data *dev_data = dev->data; + const struct can_xmc4xxx_config *dev_cfg = dev->config; + + if (dev_data->common.started) { + return -EBUSY; + } + + if ((mode & (CAN_MODE_3_SAMPLES | CAN_MODE_ONE_SHOT | + CAN_MODE_LOOPBACK | CAN_MODE_FD)) != 0) { + return -ENOTSUP; + } + + if ((mode & CAN_MODE_LISTENONLY) != 0) { + XMC_CAN_NODE_SetAnalyzerMode(dev_cfg->can); + } else { + XMC_CAN_NODE_ReSetAnalyzerMode(dev_cfg->can); + } + + dev_data->common.mode = mode; + + return 0; +} + +static int can_xmc4xxx_set_timing(const struct device *dev, const struct can_timing *timing) +{ + struct can_xmc4xxx_data *dev_data = dev->data; + const struct can_xmc4xxx_config *dev_cfg = dev->config; + uint32_t reg; + + if (!timing) { + return -EINVAL; + } + + if (dev_data->common.started) { + return -EBUSY; + } + + k_mutex_lock(&dev_data->mutex, K_FOREVER); + + reg = FIELD_PREP(CAN_NODE_NBTR_DIV8_Msk, dev_cfg->clock_div8); + reg |= FIELD_PREP(CAN_NODE_NBTR_BRP_Msk, timing->prescaler - 1); + reg |= FIELD_PREP(CAN_NODE_NBTR_TSEG1_Msk, timing->prop_seg + timing->phase_seg1 - 1); + reg |= FIELD_PREP(CAN_NODE_NBTR_TSEG2_Msk, timing->phase_seg2 - 1); + reg |= FIELD_PREP(CAN_NODE_NBTR_SJW_Msk, timing->sjw - 1); + + dev_cfg->can->NBTR = reg; + + k_mutex_unlock(&dev_data->mutex); + + return 0; +} + +static int can_xmc4xxx_send(const struct device *dev, const struct can_frame *msg, + k_timeout_t timeout, can_tx_callback_t callback, void *callback_arg) +{ + struct can_xmc4xxx_data *dev_data = dev->data; + uint8_t mailbox_idx; + struct can_xmc4xxx_tx_callback *callbacks = &dev_data->tx_callbacks[0]; + CAN_MO_TypeDef *mo; + unsigned int key; + + LOG_DBG("Sending %d bytes. Id: 0x%x, ID type: %s %s %s %s", can_dlc_to_bytes(msg->dlc), + msg->id, msg->flags & CAN_FRAME_IDE ? "extended" : "standard", + msg->flags & CAN_FRAME_RTR ? "RTR" : "", + msg->flags & CAN_FRAME_FDF ? "FD frame" : "", + msg->flags & CAN_FRAME_BRS ? "BRS" : ""); + + __ASSERT_NO_MSG(callback != NULL); + + if (msg->dlc > CAN_XMC4XXX_MAX_DLC) { + return -EINVAL; + } + + if (!dev_data->common.started) { + return -ENETDOWN; + } + + if (dev_data->state == CAN_STATE_BUS_OFF) { + return -ENETUNREACH; + } + + if ((msg->flags & (CAN_FRAME_FDF | CAN_FRAME_BRS)) != 0) { + return -ENOTSUP; + } + + if (k_sem_take(&dev_data->tx_sem, timeout) != 0) { + return -EAGAIN; + } + + k_mutex_lock(&dev_data->mutex, K_FOREVER); + + for (mailbox_idx = 0; mailbox_idx < CONFIG_CAN_XMC4XXX_MAX_TX_QUEUE; mailbox_idx++) { + if (callbacks[mailbox_idx].function == NULL) { + break; + } + } + + __ASSERT_NO_MSG(mailbox_idx < CONFIG_CAN_XMC4XXX_MAX_TX_QUEUE); + + key = irq_lock(); + /* critical section in case can_xmc4xxx_reset_tx_fifos() called in isr */ + /* so that callback function and callback_arg are consistent */ + callbacks[mailbox_idx].function = callback; + callbacks[mailbox_idx].user_data = callback_arg; + irq_unlock(key); + + mo = dev_data->tx_mo[mailbox_idx]; + mo->MOCTR = CAN_MO_MOCTR_RESMSGVAL_Msk; + + if ((msg->flags & CAN_FRAME_IDE) != 0) { + /* MOAR - message object arbitration register */ + mo->MOAR = FIELD_PREP(CAN_MO_MOAR_PRI_Msk, 1) | + FIELD_PREP(CAN_MO_MOAR_ID_Msk, msg->id) | CAN_MO_MOAR_IDE_Msk; + } else { + mo->MOAR = FIELD_PREP(CAN_MO_MOAR_PRI_Msk, 1) | + FIELD_PREP(XMC_CAN_MO_MOAR_STDID_Msk, msg->id); + } + + mo->MOFCR &= ~CAN_MO_MOFCR_DLC_Msk; + mo->MOFCR |= FIELD_PREP(CAN_MO_MOFCR_DLC_Msk, msg->dlc); + + if ((msg->flags & CAN_FRAME_RTR) != 0) { + mo->MOCTR = CAN_MO_MOCTR_RESDIR_Msk; + } else { + mo->MOCTR = CAN_MO_MOCTR_SETDIR_Msk; + memcpy((void *)&mo->MODATAL, &msg->data[0], sizeof(uint32_t)); + memcpy((void *)&mo->MODATAH, &msg->data[4], sizeof(uint32_t)); + } + + mo->MOCTR = CAN_MO_MOCTR_SETTXEN0_Msk | CAN_MO_MOCTR_SETTXEN1_Msk | + CAN_MO_MOCTR_SETMSGVAL_Msk | CAN_MO_MOCTR_RESRXEN_Msk | + CAN_MO_MOCTR_RESRTSEL_Msk; + mo->MOCTR = CAN_MO_MOCTR_SETTXRQ_Msk; + + k_mutex_unlock(&dev_data->mutex); + return 0; +} + +static CAN_MO_TypeDef *can_xmc4xxx_get_mo(uint8_t *mo_index) +{ + int i; + + for (i = 0; i < CAN_XMC4XXX_NUM_MESSAGE_OBJECTS; i++) { + int prev_val; + + sys_bitarray_test_and_set_bit(&mo_usage_bitarray, i, &prev_val); + if (prev_val == 0) { + *mo_index = i; + can_xmc4xxx_num_free_mo--; + return &CAN_MO->MO[i]; + } + } + + return NULL; +} + +static void can_xmc4xxx_deinit_fifo(const struct device *dev, struct can_xmc4xxx_rx_fifo *fifo) +{ + CAN_MO_TypeDef *mo = fifo->base; + + while (mo != NULL) { + int next_index; + int index; + + /* invalidate message */ + mo->MOCTR = CAN_MO_MOCTR_RESMSGVAL_Msk; + + next_index = FIELD_GET(CAN_MO_MOSTAT_PNEXT_Msk, mo->MOSTAT); + index = ((uint32_t)mo - (uint32_t)&CAN_MO->MO[0]) / sizeof(*mo); + + if ((uint32_t)mo == (uint32_t)fifo->top) { + mo = NULL; + } else { + mo = &CAN_MO->MO[next_index]; + } + + /* we need to move the node back to the list of unallocated message objects, */ + /* which is list index = 0. 255 gets rolled over to 0 in the function below */ + XMC_CAN_AllocateMOtoNodeList(can_xmc4xxx_global_reg, 255, index); + + sys_bitarray_clear_bit(&mo_usage_bitarray, index); + can_xmc4xxx_num_free_mo++; + } +} + +static int can_xmc4xxx_init_fifo(const struct device *dev, const struct can_filter *filter, + struct can_xmc4xxx_rx_fifo *fifo, bool is_rtr) +{ + const struct can_xmc4xxx_config *dev_cfg = dev->config; + CAN_MO_TypeDef *mo; + uint32_t reg; + uint8_t mo_index = 0, base_index; + + if (can_xmc4xxx_num_free_mo < CONFIG_CAN_XMC4XXX_RX_FIFO_ITEMS) { + return -ENOMEM; + } + + mo = can_xmc4xxx_get_mo(&mo_index); + __ASSERT_NO_MSG(mo != NULL); + + base_index = mo_index; + fifo->base = mo; + fifo->tail = mo; + + XMC_CAN_AllocateMOtoNodeList(can_xmc4xxx_global_reg, + CAN_XMC4XXX_REG_TO_NODE_IND(dev_cfg->can), mo_index); + + /* setup the base object - this controls the filtering for the fifo */ + mo->MOCTR = CAN_MO_MOCTR_RESMSGVAL_Msk; + mo->MOAMR &= ~(CAN_MO_MOAMR_AM_Msk | CAN_MO_MOAMR_MIDE_Msk); + mo->MOAR = 0; + + if ((filter->flags & CAN_FILTER_IDE) != 0) { + mo->MOAMR |= FIELD_PREP(CAN_MO_MOAMR_AM_Msk, filter->mask) | CAN_MO_MOAMR_MIDE_Msk; + mo->MOAR |= FIELD_PREP(CAN_MO_MOAR_ID_Msk, filter->id) | CAN_MO_MOAR_IDE_Msk; + } else { + mo->MOAMR |= FIELD_PREP(XMC_CAN_MO_MOAR_STDID_Msk, filter->mask); + mo->MOAR |= FIELD_PREP(XMC_CAN_MO_MOAR_STDID_Msk, filter->id); + } + + mo->MOFCR = FIELD_PREP(CAN_MO_MOFCR_MMC_Msk, 1) | CAN_MO_MOFCR_RXIE_Msk; + if (is_rtr) { + mo->MOFCR |= CAN_MO_MOFCR_RMM_Msk; + mo->MOCTR = CAN_MO_MOCTR_SETDIR_Msk; + } else { + mo->MOCTR = CAN_MO_MOCTR_RESDIR_Msk; + } + + /* Writing to MOCTR sets or resets message object properties */ + mo->MOCTR = CAN_MO_MOCTR_RESTXEN0_Msk | CAN_MO_MOCTR_RESTXEN1_Msk | + CAN_MO_MOCTR_SETMSGVAL_Msk | CAN_MO_MOCTR_SETRXEN_Msk | + CAN_MO_MOCTR_RESRTSEL_Msk; + + mo->MOIPR = FIELD_PREP(CAN_MO_MOIPR_RXINP_Msk, dev_cfg->service_request); + + /* setup the remaining message objects in the fifo */ + for (int i = 1; i < CONFIG_CAN_XMC4XXX_RX_FIFO_ITEMS; i++) { + mo = can_xmc4xxx_get_mo(&mo_index); + __ASSERT_NO_MSG(mo != NULL); + + XMC_CAN_AllocateMOtoNodeList(can_xmc4xxx_global_reg, + CAN_XMC4XXX_REG_TO_NODE_IND(dev_cfg->can), mo_index); + + mo->MOCTR = CAN_MO_MOCTR_RESMSGVAL_Msk; + mo->MOCTR = CAN_MO_MOCTR_SETMSGVAL_Msk | CAN_MO_MOCTR_RESRXEN_Msk; + + /* all the other message objects in the fifo must point to the base object */ + mo->MOFGPR = FIELD_PREP(CAN_MO_MOFGPR_CUR_Msk, base_index); + } + + reg = 0; + reg |= FIELD_PREP(CAN_MO_MOFGPR_CUR_Msk, base_index); + reg |= FIELD_PREP(CAN_MO_MOFGPR_TOP_Msk, mo_index); + reg |= FIELD_PREP(CAN_MO_MOFGPR_BOT_Msk, base_index); + reg |= FIELD_PREP(CAN_MO_MOFGPR_SEL_Msk, base_index); + + fifo->base->MOFGPR = reg; + fifo->top = mo; + + return 0; +} + +static int can_xmc4xxx_add_rx_filter(const struct device *dev, can_rx_callback_t callback, + void *user_data, const struct can_filter *filter) +{ + struct can_xmc4xxx_data *dev_data = dev->data; + int filter_idx; + + if ((filter->flags & ~CAN_FILTER_IDE) != 0) { + LOG_ERR("Unsupported CAN filter flags 0x%02x", filter->flags); + return -ENOTSUP; + } + + k_mutex_lock(&dev_data->mutex, K_FOREVER); + + for (filter_idx = 0; filter_idx < CONFIG_CAN_MAX_FILTER; filter_idx++) { + if ((BIT(filter_idx) & dev_data->filter_usage) == 0) { + break; + } + } + + if (filter_idx >= CONFIG_CAN_MAX_FILTER) { + filter_idx = -ENOSPC; + } else { + unsigned int key = irq_lock(); + int ret; + + ret = can_xmc4xxx_init_fifo(dev, filter, &dev_data->rx_fifos[filter_idx], false); + if (ret < 0) { + irq_unlock(key); + k_mutex_unlock(&dev_data->mutex); + return ret; + } + +#if defined(CONFIG_CAN_ACCEPT_RTR) + ret = can_xmc4xxx_init_fifo(dev, filter, &dev_data->rtr_fifos[filter_idx], true); + if (ret < 0) { + can_xmc4xxx_deinit_fifo(dev, &dev_data->rx_fifos[filter_idx]); + irq_unlock(key); + k_mutex_unlock(&dev_data->mutex); + return ret; + } +#endif + + dev_data->filter_usage |= BIT(filter_idx); + dev_data->rx_callbacks[filter_idx].function = callback; + dev_data->rx_callbacks[filter_idx].user_data = user_data; + + irq_unlock(key); + } + + k_mutex_unlock(&dev_data->mutex); + + return filter_idx; +} + +static void can_xmc4xxx_remove_rx_filter(const struct device *dev, int filter_idx) +{ + struct can_xmc4xxx_data *dev_data = dev->data; + unsigned int key; + + if (filter_idx < 0 || filter_idx >= CONFIG_CAN_MAX_FILTER) { + LOG_ERR("Filter ID %d out of bounds", filter_idx); + return; + } + + k_mutex_lock(&dev_data->mutex, K_FOREVER); + + if ((dev_data->filter_usage & BIT(filter_idx)) == 0) { + k_mutex_unlock(&dev_data->mutex); + return; + } + + key = irq_lock(); + can_xmc4xxx_deinit_fifo(dev, &dev_data->rx_fifos[filter_idx]); +#if defined(CONFIG_CAN_ACCEPT_RTR) + can_xmc4xxx_deinit_fifo(dev, &dev_data->rtr_fifos[filter_idx]); +#endif + + dev_data->filter_usage &= ~BIT(filter_idx); + dev_data->rx_callbacks[filter_idx].function = NULL; + dev_data->rx_callbacks[filter_idx].user_data = NULL; + irq_unlock(key); + + k_mutex_unlock(&dev_data->mutex); +} + +static void can_xmc4xxx_set_state_change_callback(const struct device *dev, + can_state_change_callback_t cb, void *user_data) +{ + struct can_xmc4xxx_data *dev_data = dev->data; + unsigned int key; + + key = irq_lock(); + /* critical section so that state_change_cb and state_change_cb_data are consistent */ + dev_data->common.state_change_cb = cb; + dev_data->common.state_change_cb_user_data = user_data; + irq_unlock(key); +} + +static void can_xmc4xxx_get_state_from_status(const struct device *dev, enum can_state *state, + struct can_bus_err_cnt *err_cnt, uint32_t *status) +{ + struct can_xmc4xxx_data *dev_data = dev->data; + const struct can_xmc4xxx_config *dev_cfg = dev->config; + uint8_t tec = XMC_CAN_NODE_GetTransmitErrorCounter(dev_cfg->can); + uint8_t rec = XMC_CAN_NODE_GetTransmitErrorCounter(dev_cfg->can); + + if (err_cnt != NULL) { + err_cnt->tx_err_cnt = tec; + err_cnt->rx_err_cnt = rec; + } + + if (state == NULL) { + return; + } + + if (!dev_data->common.started) { + *state = CAN_STATE_STOPPED; + return; + } + + if ((*status & XMC_CAN_NODE_STATUS_BUS_OFF) != 0) { + *state = CAN_STATE_BUS_OFF; + } else if (tec >= 128 || rec >= 128) { + *state = CAN_STATE_ERROR_PASSIVE; + } else if ((*status & XMC_CAN_NODE_STATUS_ERROR_WARNING_STATUS) != 0) { + *state = CAN_STATE_ERROR_WARNING; + } else { + *state = CAN_STATE_ERROR_ACTIVE; + } +} + +static int can_xmc4xxx_get_state(const struct device *dev, enum can_state *state, + struct can_bus_err_cnt *err_cnt) +{ + const struct can_xmc4xxx_config *dev_cfg = dev->config; + uint32_t status; + + status = XMC_CAN_NODE_GetStatus(dev_cfg->can); + + can_xmc4xxx_get_state_from_status(dev, state, err_cnt, &status); + + return 0; +} + +static int can_xmc4xxx_get_core_clock(const struct device *dev, uint32_t *rate) +{ + const struct can_xmc4xxx_config *dev_cfg = dev->config; + + *rate = can_xmc4xxx_clock_frequency; + if (dev_cfg->clock_div8) { + *rate /= 8; + } + + return 0; +} + +static int can_xmc4xxx_get_max_filters(const struct device *dev, bool ide) +{ + ARG_UNUSED(ide); + + return CONFIG_CAN_MAX_FILTER; +} + +#ifndef CONFIG_CAN_AUTO_BUS_OFF_RECOVERY +static int can_xmc4xxx_recover(const struct device *dev, k_timeout_t timeout) +{ + struct can_xmc4xxx_data *dev_data = dev->data; + + ARG_UNUSED(timeout); + + if (!dev_data->common.started) { + return -ENETDOWN; + } + + return -ENOTSUP; +} +#endif + +static void can_xmc4xxx_reset_tx_fifos(const struct device *dev, int status) +{ + struct can_xmc4xxx_data *dev_data = dev->data; + struct can_xmc4xxx_tx_callback *tx_callbacks = &dev_data->tx_callbacks[0]; + + LOG_DBG("All Tx message objects reset"); + for (int i = 0; i < CONFIG_CAN_XMC4XXX_MAX_TX_QUEUE; i++) { + can_tx_callback_t callback; + void *user_data; + + callback = tx_callbacks[i].function; + user_data = tx_callbacks[i].user_data; + + tx_callbacks[i].function = NULL; + + if (callback) { + dev_data->tx_mo[i]->MOCTR = CAN_MO_MOCTR_RESMSGVAL_Msk; + callback(dev, status, user_data); + k_sem_give(&dev_data->tx_sem); + } + } +} + +static void can_xmc4xxx_tx_handler(const struct device *dev) +{ + struct can_xmc4xxx_data *dev_data = dev->data; + struct can_xmc4xxx_tx_callback *tx_callbacks = &dev_data->tx_callbacks[0]; + + for (int i = 0; i < CONFIG_CAN_XMC4XXX_MAX_TX_QUEUE; i++) { + CAN_MO_TypeDef *mo = dev_data->tx_mo[i]; + + if ((mo->MOSTAT & XMC_CAN_MO_STATUS_TX_PENDING) != 0) { + can_tx_callback_t callback; + void *user_data; + + mo->MOCTR = XMC_CAN_MO_RESET_STATUS_TX_PENDING; + + callback = tx_callbacks[i].function; + user_data = tx_callbacks[i].user_data; + + tx_callbacks[i].function = NULL; + + if (callback) { + callback(dev, 0, user_data); + k_sem_give(&dev_data->tx_sem); + } + } + } +} + +static inline void can_xmc4xxx_increment_fifo_tail(struct can_xmc4xxx_rx_fifo *fifo) +{ + uint8_t next_index; + + if ((uint32_t)fifo->tail == (uint32_t)fifo->top) { + fifo->tail = fifo->base; + return; + } + + next_index = FIELD_GET(CAN_MO_MOSTAT_PNEXT_Msk, fifo->tail->MOSTAT); + fifo->tail = &CAN_MO->MO[next_index]; +} + +static inline bool can_xmc4xxx_is_fifo_empty(struct can_xmc4xxx_rx_fifo *fifo) +{ + if (fifo->tail->MOSTAT & XMC_CAN_MO_STATUS_RX_PENDING) { + return false; + } + + return true; +} + +static inline void can_xmc4xxx_update_fifo_head(struct can_xmc4xxx_rx_fifo *fifo) +{ + uint32_t reg = fifo->base->MOFGPR; + uint8_t top_index, bot_index, cur_index; + uint8_t head_index = FIELD_GET(CAN_MO_MOFGPR_CUR_Msk, reg); + + fifo->head = &CAN_MO->MO[head_index]; + top_index = FIELD_GET(CAN_MO_MOFGPR_TOP_Msk, reg); + bot_index = FIELD_GET(CAN_MO_MOFGPR_BOT_Msk, reg); + cur_index = FIELD_GET(CAN_MO_MOFGPR_CUR_Msk, reg); + + LOG_DBG("Fifo: top %d, bot %d, cur %d", top_index, bot_index, cur_index); +} + +static void can_xmc4xxx_rx_fifo_handler(const struct device *dev, struct can_xmc4xxx_rx_fifo *fifo, + struct can_xmc4xxx_rx_callback *rx_callback) +{ + bool is_rtr = (fifo->base->MOSTAT & CAN_MO_MOSTAT_DIR_Msk) != 0; + + while (!can_xmc4xxx_is_fifo_empty(fifo)) { + struct can_frame frame; + CAN_MO_TypeDef *mo_tail = fifo->tail; + + memset(&frame, 0, sizeof(frame)); + + if ((mo_tail->MOAR & CAN_MO_MOAR_IDE_Msk) != 0) { + frame.flags |= CAN_FRAME_IDE; + frame.id = FIELD_GET(CAN_MO_MOAR_ID_Msk, mo_tail->MOAR); + } else { + frame.id = FIELD_GET(XMC_CAN_MO_MOAR_STDID_Msk, mo_tail->MOAR); + } + + frame.dlc = FIELD_GET(CAN_MO_MOFCR_DLC_Msk, mo_tail->MOFCR); + + if (!is_rtr) { + memcpy(&frame.data[0], (void *)&mo_tail->MODATAL, sizeof(uint32_t)); + memcpy(&frame.data[4], (void *)&mo_tail->MODATAH, sizeof(uint32_t)); + } else { + frame.flags |= CAN_FRAME_RTR; + memset(&frame.data[0], 0, CAN_MAX_DLEN); + } + + if (rx_callback->function != NULL) { + rx_callback->function(dev, &frame, rx_callback->user_data); + } + + /* reset the rx pending bit on the tail */ + mo_tail->MOCTR = XMC_CAN_MO_RESET_STATUS_RX_PENDING; + can_xmc4xxx_increment_fifo_tail(fifo); + } +} + +static void can_xmc4xxx_rx_handler(const struct device *dev) +{ + struct can_xmc4xxx_data *dev_data = dev->data; + + for (int i = 0; i < CONFIG_CAN_MAX_FILTER; i++) { + if ((BIT(i) & dev_data->filter_usage) == 0) { + continue; + } + + can_xmc4xxx_update_fifo_head(&dev_data->rx_fifos[i]); + can_xmc4xxx_rx_fifo_handler(dev, &dev_data->rx_fifos[i], + &dev_data->rx_callbacks[i]); +#if defined(CONFIG_CAN_ACCEPT_RTR) + can_xmc4xxx_update_fifo_head(&dev_data->rtr_fifos[i]); + can_xmc4xxx_rx_fifo_handler(dev, &dev_data->rtr_fifos[i], + &dev_data->rx_callbacks[i]); +#endif + } +} + +static void can_xmc4xxx_state_change_handler(const struct device *dev, uint32_t status) +{ + const struct can_xmc4xxx_config *dev_cfg = dev->config; + struct can_xmc4xxx_data *dev_data = dev->data; + enum can_state new_state; + struct can_bus_err_cnt err_cnt; + + can_xmc4xxx_get_state_from_status(dev, &new_state, &err_cnt, &status); + if (dev_data->state != new_state) { + if (dev_data->common.state_change_cb) { + dev_data->common.state_change_cb( + dev, new_state, err_cnt, + dev_data->common.state_change_cb_user_data); + } + + if (dev_data->state != CAN_STATE_STOPPED && new_state == CAN_STATE_BUS_OFF) { + /* re-enable the node after auto bus-off recovery completes */ + XMC_CAN_NODE_ResetInitBit(dev_cfg->can); + } + + dev_data->state = new_state; + + if (dev_data->state == CAN_STATE_BUS_OFF) { + can_xmc4xxx_reset_tx_fifos(dev, -ENETDOWN); + } + } +} + +static void can_xmc4xxx_isr(const struct device *dev) +{ + const struct can_xmc4xxx_config *dev_cfg = dev->config; + uint32_t status; + + status = XMC_CAN_NODE_GetStatus(dev_cfg->can); + XMC_CAN_NODE_ClearStatus(dev_cfg->can, status); + + if ((status & XMC_CAN_NODE_STATUS_TX_OK) != 0) { + can_xmc4xxx_tx_handler(dev); + } + + if ((status & XMC_CAN_NODE_STATUS_RX_OK) != 0) { + can_xmc4xxx_rx_handler(dev); + } + + if ((status & XMC_CAN_NODE_STATUS_ALERT_WARNING) != 0) { + /* change of bit NSRx.BOFF */ + /* change of bit NSRx.EWRN */ + can_xmc4xxx_state_change_handler(dev, status); + } +} + +static int can_xmc4xxx_get_capabilities(const struct device *dev, can_mode_t *cap) +{ + ARG_UNUSED(dev); + + *cap = CAN_MODE_NORMAL | CAN_MODE_LISTENONLY; + + return 0; +} + +static int can_xmc4xxx_start(const struct device *dev) +{ + struct can_xmc4xxx_data *dev_data = dev->data; + const struct can_xmc4xxx_config *dev_cfg = dev->config; + int ret = 0; + unsigned int key; + + if (dev_data->common.started) { + return -EALREADY; + } + + key = irq_lock(); + can_xmc4xxx_reset_tx_fifos(dev, -ENETDOWN); + irq_unlock(key); + + if (dev_cfg->common.phy != NULL) { + ret = can_transceiver_enable(dev_cfg->common.phy, dev_data->common.mode); + if (ret < 0) { + LOG_ERR("Failed to enable CAN transceiver [%d]", ret); + return ret; + } + } + + k_mutex_lock(&dev_data->mutex, K_FOREVER); + + XMC_CAN_NODE_DisableConfigurationChange(dev_cfg->can); + + dev_data->common.started = true; + XMC_CAN_NODE_ResetInitBit(dev_cfg->can); + + k_mutex_unlock(&dev_data->mutex); + + return ret; +} + +static int can_xmc4xxx_stop(const struct device *dev) +{ + struct can_xmc4xxx_data *dev_data = dev->data; + const struct can_xmc4xxx_config *dev_cfg = dev->config; + int ret = 0; + unsigned int key; + + if (!dev_data->common.started) { + return -EALREADY; + } + + key = irq_lock(); + XMC_CAN_NODE_SetInitBit(dev_cfg->can); + + XMC_CAN_NODE_EnableConfigurationChange(dev_cfg->can); + + can_xmc4xxx_reset_tx_fifos(dev, -ENETDOWN); + dev_data->common.started = false; + irq_unlock(key); + + if (dev_cfg->common.phy != NULL) { + ret = can_transceiver_disable(dev_cfg->common.phy); + if (ret < 0) { + LOG_ERR("Failed to disable CAN transceiver [%d]", ret); + return ret; + } + } + + return 0; +} + +static int can_xmc4xxx_init_timing_struct(struct can_timing *timing, const struct device *dev) +{ + int ret; + const struct can_xmc4xxx_config *dev_cfg = dev->config; + + if (USE_SP_ALGO && dev_cfg->common.sample_point > 0) { + ret = can_calc_timing(dev, timing, dev_cfg->common.bus_speed, + dev_cfg->common.sample_point); + if (ret < 0) { + return ret; + } + LOG_DBG("Presc: %d, BS1: %d, BS2: %d", timing->prescaler, timing->phase_seg1, + timing->phase_seg2); + LOG_DBG("Sample-point err : %d", ret); + } else { + timing->sjw = dev_cfg->sjw; + timing->prop_seg = dev_cfg->prop_seg; + timing->phase_seg1 = dev_cfg->phase_seg1; + timing->phase_seg2 = dev_cfg->phase_seg2; + ret = can_calc_prescaler(dev, timing, dev_cfg->common.bus_speed); + if (ret > 0) { + LOG_WRN("Bitrate error: %d", ret); + } + } + + return ret; +} + +static int can_xmc4xxx_init(const struct device *dev) +{ + struct can_xmc4xxx_data *dev_data = dev->data; + const struct can_xmc4xxx_config *dev_cfg = dev->config; + int ret; + struct can_timing timing = {0}; + CAN_MO_TypeDef *mo; + uint8_t mo_index = 0; + + k_sem_init(&dev_data->tx_sem, CONFIG_CAN_XMC4XXX_MAX_TX_QUEUE, + CONFIG_CAN_XMC4XXX_MAX_TX_QUEUE); + k_mutex_init(&dev_data->mutex); + + if (!can_xmc4xxx_global_init) { + uint32_t fdr_step; + uint32_t clk_module; + + XMC_CAN_Enable(can_xmc4xxx_global_reg); + XMC_CAN_SetBaudrateClockSource(can_xmc4xxx_global_reg, XMC_CAN_CANCLKSRC_FPERI); + + clk_module = XMC_CAN_GetBaudrateClockFrequency(can_xmc4xxx_global_reg); + fdr_step = 1024 - CAN_XMC4XXX_CLOCK_PRESCALER; + can_xmc4xxx_clock_frequency = clk_module / CAN_XMC4XXX_CLOCK_PRESCALER; + + LOG_DBG("Clock frequency %dHz\n", can_xmc4xxx_clock_frequency); + + can_xmc4xxx_global_reg->FDR &= ~(CAN_FDR_DM_Msk | CAN_FDR_STEP_Msk); + can_xmc4xxx_global_reg->FDR |= FIELD_PREP(CAN_FDR_DM_Msk, XMC_CAN_DM_NORMAL) | + FIELD_PREP(CAN_FDR_STEP_Msk, fdr_step); + + can_xmc4xxx_global_init = true; + } + + XMC_CAN_NODE_EnableConfigurationChange(dev_cfg->can); + + XMC_CAN_NODE_SetReceiveInput(dev_cfg->can, dev_cfg->input_src); + + XMC_CAN_NODE_SetInitBit(dev_cfg->can); + + XMC_CAN_NODE_SetEventNodePointer(dev_cfg->can, XMC_CAN_NODE_POINTER_EVENT_ALERT, + dev_cfg->service_request); + + XMC_CAN_NODE_SetEventNodePointer(dev_cfg->can, XMC_CAN_NODE_POINTER_EVENT_LEC, + dev_cfg->service_request); + + XMC_CAN_NODE_SetEventNodePointer(dev_cfg->can, XMC_CAN_NODE_POINTER_EVENT_TRANSFER_OK, + dev_cfg->service_request); + + XMC_CAN_NODE_SetEventNodePointer(dev_cfg->can, XMC_CAN_NODE_POINTER_EVENT_FRAME_COUNTER, + dev_cfg->service_request); + + XMC_CAN_NODE_EnableEvent(dev_cfg->can, XMC_CAN_NODE_EVENT_TX_INT | + XMC_CAN_NODE_EVENT_ALERT); + + /* set up tx messages */ + for (int i = 0; i < CONFIG_CAN_XMC4XXX_MAX_TX_QUEUE; i++) { + mo = can_xmc4xxx_get_mo(&mo_index); + if (mo == NULL) { + return -ENOMEM; + } + + dev_data->tx_mo[i] = mo; + + XMC_CAN_AllocateMOtoNodeList(can_xmc4xxx_global_reg, + CAN_XMC4XXX_REG_TO_NODE_IND(dev_cfg->can), mo_index); + + mo->MOIPR = FIELD_PREP(CAN_MO_MOIPR_TXINP_Msk, dev_cfg->service_request); + mo->MOFCR = FIELD_PREP(CAN_MO_MOFCR_MMC_Msk, 0) | CAN_MO_MOFCR_TXIE_Msk; + } + +#ifdef CONFIG_CAN_XMC4XXX_INTERNAL_BUS_MODE + /* The name of this function is misleading. It doesn't actually enable */ + /* loopback on a single node, but connects all CAN devices to an internal bus. */ + XMC_CAN_NODE_EnableLoopBack(dev_cfg->can); +#endif + + dev_cfg->irq_config_func(); + + dev_data->state = CAN_STATE_STOPPED; + +#ifndef CONFIG_CAN_XMC4XXX_INTERNAL_BUS_MODE + ret = pinctrl_apply_state(dev_cfg->pcfg, PINCTRL_STATE_DEFAULT); + if (ret < 0) { + return ret; + } +#endif + + ret = can_xmc4xxx_init_timing_struct(&timing, dev); + if (ret < 0) { + return ret; + } + + return can_set_timing(dev, &timing); +} + +static const struct can_driver_api can_xmc4xxx_api_funcs = { + .get_capabilities = can_xmc4xxx_get_capabilities, + .set_mode = can_xmc4xxx_set_mode, + .set_timing = can_xmc4xxx_set_timing, + .start = can_xmc4xxx_start, + .stop = can_xmc4xxx_stop, + .send = can_xmc4xxx_send, + .add_rx_filter = can_xmc4xxx_add_rx_filter, + .remove_rx_filter = can_xmc4xxx_remove_rx_filter, +#ifndef CONFIG_CAN_AUTO_BUS_OFF_RECOVERY + .recover = can_xmc4xxx_recover, +#endif + .get_state = can_xmc4xxx_get_state, + .set_state_change_callback = can_xmc4xxx_set_state_change_callback, + .get_core_clock = can_xmc4xxx_get_core_clock, + .get_max_filters = can_xmc4xxx_get_max_filters, + .timing_min = { + .sjw = 1, + .prop_seg = 0, + .phase_seg1 = 3, + .phase_seg2 = 2, + .prescaler = 1, + }, + .timing_max = { + .sjw = 4, + .prop_seg = 0, + .phase_seg1 = 16, + .phase_seg2 = 8, + .prescaler = 64, + }, +}; + +#define CAN_XMC4XXX_INIT(inst) \ + static void can_xmc4xxx_irq_config_##inst(void) \ + { \ + IRQ_CONNECT(DT_INST_IRQN(inst), DT_INST_IRQ(inst, priority), can_xmc4xxx_isr, \ + DEVICE_DT_INST_GET(inst), 0); \ + irq_enable(DT_INST_IRQN(inst)); \ + } \ + \ + PINCTRL_DT_INST_DEFINE(inst); \ + \ + static struct can_xmc4xxx_data can_xmc4xxx_data_##inst; \ + static const struct can_xmc4xxx_config can_xmc4xxx_config_##inst = { \ + .common = CAN_DT_DRIVER_CONFIG_INST_GET(inst, 1000000), \ + .can = (CAN_NODE_TypeDef *)DT_INST_REG_ADDR(inst), \ + .clock_div8 = DT_INST_PROP(inst, clock_div8), \ + .sjw = DT_INST_PROP(inst, sjw), \ + .prop_seg = DT_INST_PROP_OR(inst, prop_seg, 0), \ + .phase_seg1 = DT_INST_PROP_OR(inst, phase_seg1, 0), \ + .phase_seg2 = DT_INST_PROP_OR(inst, phase_seg2, 0), \ + .irq_config_func = can_xmc4xxx_irq_config_##inst, \ + .service_request = DT_INST_IRQN(inst) - CAN_XMC4XXX_IRQ_MIN, \ + .input_src = DT_INST_ENUM_IDX(inst, input_src), \ + .pcfg = PINCTRL_DT_INST_DEV_CONFIG_GET(inst), \ + }; \ + \ + CAN_DEVICE_DT_INST_DEFINE(inst, can_xmc4xxx_init, NULL, &can_xmc4xxx_data_##inst, \ + &can_xmc4xxx_config_##inst, POST_KERNEL, \ + CONFIG_CAN_INIT_PRIORITY, &can_xmc4xxx_api_funcs); + +DT_INST_FOREACH_STATUS_OKAY(CAN_XMC4XXX_INIT) diff --git a/dts/arm/infineon/xmc4500_F100x1024-pinctrl.dtsi b/dts/arm/infineon/xmc4500_F100x1024-pinctrl.dtsi index f0d7d31f9eb..4506e0c995f 100644 --- a/dts/arm/infineon/xmc4500_F100x1024-pinctrl.dtsi +++ b/dts/arm/infineon/xmc4500_F100x1024-pinctrl.dtsi @@ -573,4 +573,45 @@ /omit-if-no-ref/ eth_p6_6_clk_tx: eth_p6_6_clk_tx { pinmux = ; }; + + /omit-if-no-ref/ can_tx_p0_0_node0: can_tx_p0_0_node0 { + pinmux = ; + }; + /omit-if-no-ref/ can_tx_p1_4_node0: can_tx_p1_4_node0 { + pinmux = ; + }; + /omit-if-no-ref/ can_tx_p1_5_node1: can_tx_p1_5_node1 { + pinmux = ; + }; + /omit-if-no-ref/ can_tx_p1_9_node2: can_tx_p1_9_node2 { + pinmux = ; + }; + /omit-if-no-ref/ can_tx_p1_12_node1: can_tx_p1_12_node1 { + pinmux = ; + }; + /omit-if-no-ref/ can_tx_p2_7_node1: can_tx_p2_7_node1 { + pinmux = ; + }; + /omit-if-no-ref/ can_tx_p3_2_node0: can_tx_p3_2_node0 { + pinmux = ; + }; + + /omit-if-no-ref/ can_rx_p1_5_node0: can_rx_p1_5_node0 { + pinmux = ; /* CAN input src = RXDA */ + }; + /omit-if-no-ref/ can_rx_p14_3_node0: can_rx_p14_3_node0 { + pinmux = ; /* CAN input src = RXDB */ + }; + /omit-if-no-ref/ can_rx_p2_6_node1: can_rx_p2_6_node1 { + pinmux = ; /* CAN input src = RXDA */ + }; + /omit-if-no-ref/ can_rx_p1_13_node1: can_rx_p1_13_node1 { + pinmux = ; /* CAN input src = RXDC */ + }; + /omit-if-no-ref/ can_rx_p1_4_node1: can_rx_p1_4_node1 { + pinmux = ; /* CAN input src = RXDD */ + }; + /omit-if-no-ref/ can_rx_p1_8_node2: can_rx_p1_8_node2 { + pinmux = ; /* CAN input src = RXDA */ + }; }; diff --git a/dts/arm/infineon/xmc4500_F100x1024.dtsi b/dts/arm/infineon/xmc4500_F100x1024.dtsi index 8a84230511d..d368e397ea3 100644 --- a/dts/arm/infineon/xmc4500_F100x1024.dtsi +++ b/dts/arm/infineon/xmc4500_F100x1024.dtsi @@ -93,3 +93,7 @@ status = "disabled"; }; }; + +&can { + message-objects = <64>; +}; diff --git a/dts/arm/infineon/xmc4700_F144x2048-pinctrl.dtsi b/dts/arm/infineon/xmc4700_F144x2048-pinctrl.dtsi index 8962aa2731a..e6bab488049 100644 --- a/dts/arm/infineon/xmc4700_F144x2048-pinctrl.dtsi +++ b/dts/arm/infineon/xmc4700_F144x2048-pinctrl.dtsi @@ -1160,4 +1160,108 @@ /omit-if-no-ref/ eth_p6_6_clk_tx: eth_p6_6_clk_tx { pinmux = ; }; + + /omit-if-no-ref/ can_tx_p0_0_node0: can_tx_p0_0_node0 { + pinmux = ; + }; + /omit-if-no-ref/ can_tx_p1_4_node0: can_tx_p1_4_node0 { + pinmux = ; + }; + /omit-if-no-ref/ can_tx_p1_5_node1: can_tx_p1_5_node1 { + pinmux = ; + }; + /omit-if-no-ref/ can_tx_p1_9_node2: can_tx_p1_9_node2 { + pinmux = ; + }; + /omit-if-no-ref/ can_tx_p1_12_node1: can_tx_p1_12_node1 { + pinmux = ; + }; + /omit-if-no-ref/ can_tx_p2_0_node0: can_tx_p2_0_node0 { + pinmux = ; + }; + /omit-if-no-ref/ can_tx_p2_1_node5: can_tx_p2_1_node5 { + pinmux = ; + }; + /omit-if-no-ref/ can_tx_p2_7_node1: can_tx_p2_7_node1 { + pinmux = ; + }; + /omit-if-no-ref/ can_tx_p2_14_node4: can_tx_p2_14_node4 { + pinmux = ; + }; + /omit-if-no-ref/ can_tx_p3_2_node0: can_tx_p3_2_node0 { + pinmux = ; + }; + /omit-if-no-ref/ can_tx_p3_7_node2: can_tx_p3_7_node2 { + pinmux = ; + }; + /omit-if-no-ref/ can_tx_p3_9_node1: can_tx_p3_9_node1 { + pinmux = ; + }; + /omit-if-no-ref/ can_tx_p3_10_node0: can_tx_p3_10_node0 { + pinmux = ; + }; + /omit-if-no-ref/ can_tx_p4_0_node3: can_tx_p4_0_node3 { + pinmux = ; + }; + /omit-if-no-ref/ can_tx_p4_7_node2: can_tx_p4_7_node2 { + pinmux = ; + }; + /omit-if-no-ref/ can_tx_p5_8_node4: can_tx_p5_8_node4 { + pinmux = ; + }; + /omit-if-no-ref/ can_tx_p5_11_node5: can_tx_p5_11_node5 { + pinmux = ; + }; + /omit-if-no-ref/ can_tx_p6_5_node3: can_tx_p6_5_node3 { + pinmux = ; + }; + + /omit-if-no-ref/ can_rx_p1_5_node0: can_rx_p1_5_node0 { + pinmux = ; /* CAN input src = RXDA */ + }; + /omit-if-no-ref/ can_rx_p14_3_node0: can_rx_p14_3_node0 { + pinmux = ; /* CAN input src = RXDB */ + }; + /omit-if-no-ref/ can_rx_p3_12_node0: can_rx_p3_12_node0 { + pinmux = ; /* CAN input src = RXDC */ + }; + /omit-if-no-ref/ can_rx_p2_6_node1: can_rx_p2_6_node1 { + pinmux = ; /* CAN input src = RXDA */ + }; + /omit-if-no-ref/ can_rx_p3_11_node1: can_rx_p3_11_node1 { + pinmux = ; /* CAN input src = RXDB */ + }; + /omit-if-no-ref/ can_rx_p1_13_node1: can_rx_p1_13_node1 { + pinmux = ; /* CAN input src = RXDC */ + }; + /omit-if-no-ref/ can_rx_p1_4_node1: can_rx_p1_4_node1 { + pinmux = ; /* CAN input src = RXDD */ + }; + /omit-if-no-ref/ can_rx_p1_8_node2: can_rx_p1_8_node2 { + pinmux = ; /* CAN input src = RXDA */ + }; + /omit-if-no-ref/ can_rx_p3_8_node2: can_rx_p3_8_node2 { + pinmux = ; /* CAN input src = RXDB */ + }; + /omit-if-no-ref/ can_rx_p4_6_node2: can_rx_p4_6_node2 { + pinmux = ; /* CAN input src = RXDC */ + }; + /omit-if-no-ref/ can_rx_p0_8_node3: can_rx_p0_8_node3 { + pinmux = ; /* CAN input src = RXDA */ + }; + /omit-if-no-ref/ can_rx_p6_6_node3: can_rx_p6_6_node3 { + pinmux = ; /* CAN input src = RXDB */ + }; + /omit-if-no-ref/ can_rx_p2_15_node4: can_rx_p2_15_node4 { + pinmux = ; /* CAN input src = RXDA */ + }; + /omit-if-no-ref/ can_rx_p14_4_node4: can_rx_p14_4_node4 { + pinmux = ; /* CAN input src = RXDB */ + }; + /omit-if-no-ref/ can_rx_p5_10_node5: can_rx_p5_10_node5 { + pinmux = ; /* CAN input src = RXDA */ + }; + /omit-if-no-ref/ can_rx_p2_6_node5: can_rx_p2_6_node5 { + pinmux = ; /* CAN input src = RXDB */ + }; }; diff --git a/dts/arm/infineon/xmc4700_F144x2048.dtsi b/dts/arm/infineon/xmc4700_F144x2048.dtsi index 22a9eb30404..ad8e1ea6413 100644 --- a/dts/arm/infineon/xmc4700_F144x2048.dtsi +++ b/dts/arm/infineon/xmc4700_F144x2048.dtsi @@ -96,3 +96,27 @@ status = "disabled"; }; }; + +&can { + message-objects = <256>; + can_node3: can_node3@48014500 { + compatible = "infineon,xmc4xxx-can-node"; + reg = <0x48014500 0x100>; + interrupts = <79 1>; + status = "disabled"; + }; + + can_node4: can_node4@48014600 { + compatible = "infineon,xmc4xxx-can-node"; + reg = <0x48014600 0x100>; + interrupts = <80 1>; + status = "disabled"; + }; + + can_node5: can_node5@48014700 { + compatible = "infineon,xmc4xxx-can-node"; + reg = <0x48014700 0x100>; + interrupts = <81 1>; + status = "disabled"; + }; +}; diff --git a/dts/arm/infineon/xmc4xxx.dtsi b/dts/arm/infineon/xmc4xxx.dtsi index 90049348134..cab68fbff00 100644 --- a/dts/arm/infineon/xmc4xxx.dtsi +++ b/dts/arm/infineon/xmc4xxx.dtsi @@ -253,6 +253,36 @@ #size-cells = <0>; }; }; + + can: can@48014000 { + compatible = "infineon,xmc4xxx-can"; + reg = <0x48014000 0x4000>; + clock-prescaler = <1>; + + #address-cells = <1>; + #size-cells = <1>; + + can_node0: can_node0@48014200 { + compatible = "infineon,xmc4xxx-can-node"; + reg = <0x48014200 0x100>; + interrupts = <76 1>; + status = "disabled"; + }; + + can_node1: can_node1@48014300 { + compatible = "infineon,xmc4xxx-can-node"; + reg = <0x48014300 0x100>; + interrupts = <77 1>; + status = "disabled"; + }; + + can_node2: can_node2@48014400 { + compatible = "infineon,xmc4xxx-can-node"; + reg = <0x48014400 0x100>; + interrupts = <78 1>; + status = "disabled"; + }; + }; }; }; diff --git a/dts/bindings/can/infineon,xmc4xxx-can-node.yaml b/dts/bindings/can/infineon,xmc4xxx-can-node.yaml new file mode 100644 index 00000000000..8fa50922ace --- /dev/null +++ b/dts/bindings/can/infineon,xmc4xxx-can-node.yaml @@ -0,0 +1,35 @@ +# Copyright (c) 2023 Andriy Gelman +# SPDX-License-Identifier: Apache-2.0 +# + +description: | + Infineon XMC4xxx CAN Node + +compatible: "infineon,xmc4xxx-can-node" + +include: ["can-controller.yaml", "pinctrl-device.yaml"] + +properties: + reg: + required: true + + interrupts: + required: true + + clock_div8: + description: Option enables clock divide by a factor of 8. + type: boolean + + input-src: + description: Connects the CAN input line to a specific IO. + type: string + required: true + enum: + - "RXDA" + - "RXDB" + - "RXDC" + - "RXDD" + - "RXDE" + - "RXDF" + - "RXDG" + - "RXDH" diff --git a/dts/bindings/can/infineon,xmc4xxx-can.yaml b/dts/bindings/can/infineon,xmc4xxx-can.yaml new file mode 100644 index 00000000000..66b0fb72a87 --- /dev/null +++ b/dts/bindings/can/infineon,xmc4xxx-can.yaml @@ -0,0 +1,24 @@ +# Copyright (c) 2023 Andriy Gelman +# SPDX-License-Identifier: Apache-2.0 +# + +description: | + Infineon XMC4xxx CAN + +compatible: "infineon,xmc4xxx-can" + +include: base.yaml + +properties: + reg: + required: true + + clock-prescaler: + type: int + required: true + description: Clock divider for the input clock. Valid range is [1, 1023]. + + message-objects: + type: int + required: true + description: Number of total can messages supported by hardware. diff --git a/modules/Kconfig.infineon b/modules/Kconfig.infineon index 070508ccce4..7ca374f4f32 100644 --- a/modules/Kconfig.infineon +++ b/modules/Kconfig.infineon @@ -60,4 +60,9 @@ config HAS_XMCLIB_ETH help Enable XMCLIB Ethernet MAC +config HAS_XMCLIB_CAN + bool + help + Enable XMCLIB CAN + endif # HAS_XMCLIB diff --git a/samples/drivers/can/counter/sample.yaml b/samples/drivers/can/counter/sample.yaml index 579fc82a069..edbb0817c4d 100644 --- a/samples/drivers/can/counter/sample.yaml +++ b/samples/drivers/can/counter/sample.yaml @@ -7,6 +7,7 @@ tests: integration_platforms: - native_sim filter: dt_chosen_enabled("zephyr,canbus") and not dt_compat_enabled("kvaser,pcican") + and not dt_compat_enabled("infineon,xmc4xxx-can-node") harness: console harness_config: type: one_line diff --git a/soc/arm/infineon_xmc/4xxx/Kconfig.series b/soc/arm/infineon_xmc/4xxx/Kconfig.series index bfdbcc93091..7c7f9a85496 100644 --- a/soc/arm/infineon_xmc/4xxx/Kconfig.series +++ b/soc/arm/infineon_xmc/4xxx/Kconfig.series @@ -22,5 +22,6 @@ config SOC_SERIES_XMC_4XXX select HAS_XMCLIB_CCU select HAS_XMCLIB_WDT select HAS_XMCLIB_ETH + select HAS_XMCLIB_CAN help Enable support for XMC 4xxx MCU series diff --git a/tests/drivers/can/api/testcase.yaml b/tests/drivers/can/api/testcase.yaml index cd2211e0bb9..9ee9777fcef 100644 --- a/tests/drivers/can/api/testcase.yaml +++ b/tests/drivers/can/api/testcase.yaml @@ -6,8 +6,10 @@ common: tests: drivers.can.api: filter: dt_chosen_enabled("zephyr,canbus") and not dt_compat_enabled("kvaser,pcican") + and not dt_compat_enabled("infineon,xmc4xxx-can-node") drivers.can.api.rtr: filter: dt_chosen_enabled("zephyr,canbus") and not dt_compat_enabled("kvaser,pcican") + and not dt_compat_enabled("infineon,xmc4xxx-can-node") extra_configs: - CONFIG_CAN_ACCEPT_RTR=y drivers.can.api.twai: From 254a2b10dd67f22df6b8823960caeb1806c606e5 Mon Sep 17 00:00:00 2001 From: Andriy Gelman Date: Tue, 26 Dec 2023 12:06:27 -0500 Subject: [PATCH 3111/3723] boards: xmc47_relax_kit: Add CAN node to devicetree Adds CAN node to xmc47_relax_kit. Signed-off-by: Andriy Gelman --- .../xmc47_relax_kit/xmc47_relax_kit-pinctrl.dtsi | 11 +++++++++++ boards/arm/xmc47_relax_kit/xmc47_relax_kit.dts | 14 ++++++++++++++ 2 files changed, 25 insertions(+) diff --git a/boards/arm/xmc47_relax_kit/xmc47_relax_kit-pinctrl.dtsi b/boards/arm/xmc47_relax_kit/xmc47_relax_kit-pinctrl.dtsi index c81e1222cf8..e6688a7ebb2 100644 --- a/boards/arm/xmc47_relax_kit/xmc47_relax_kit-pinctrl.dtsi +++ b/boards/arm/xmc47_relax_kit/xmc47_relax_kit-pinctrl.dtsi @@ -125,3 +125,14 @@ drive-strength = "strong-medium-edge"; hwctrl = "disabled"; }; + +&can_tx_p1_12_node1 { + drive-strength = "strong-soft-edge"; + drive-push-pull; + hwctrl = "disabled"; +}; + +&can_rx_p1_13_node1 { + drive-strength = "strong-soft-edge"; + hwctrl = "disabled"; +}; diff --git a/boards/arm/xmc47_relax_kit/xmc47_relax_kit.dts b/boards/arm/xmc47_relax_kit/xmc47_relax_kit.dts index a9e0731fa0e..19cad242f1f 100644 --- a/boards/arm/xmc47_relax_kit/xmc47_relax_kit.dts +++ b/boards/arm/xmc47_relax_kit/xmc47_relax_kit.dts @@ -54,6 +54,7 @@ zephyr,shell-uart = &usic0ch0; zephyr,flash-controller = &flash_controller; zephyr,code-partition = &code_partition; + zephyr,canbus = &can_node1; }; }; @@ -199,3 +200,16 @@ reg = <0>; }; }; + +&can { + clock-prescaler = <6>; +}; + +&can_node1 { + status = "okay"; + bus-speed = <125000>; + sample-point = <875>; + input-src = "RXDC"; + pinctrl-0 = <&can_tx_p1_12_node1 &can_rx_p1_13_node1>; + pinctrl-names = "default"; +}; From 8e926377546a1ec2d0c4e470b72cf50b1cf8c411 Mon Sep 17 00:00:00 2001 From: Eve Redero Date: Mon, 29 Jan 2024 13:37:47 +0100 Subject: [PATCH 3112/3723] doc: fix comma typo in lvgl bindings Remove commas from dts array in lvgl bindings. Signed-off-by: Eve Redero --- dts/bindings/input/zephyr,lvgl-keypad-input.yaml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/dts/bindings/input/zephyr,lvgl-keypad-input.yaml b/dts/bindings/input/zephyr,lvgl-keypad-input.yaml index 2728d0e710c..5fdd3be735a 100644 --- a/dts/bindings/input/zephyr,lvgl-keypad-input.yaml +++ b/dts/bindings/input/zephyr,lvgl-keypad-input.yaml @@ -19,8 +19,8 @@ description: | keypad { compatible = "zephyr,lvgl-keypad-input"; input = <&buttons>; - input-codes = ; - lvgl-codes = ; + input-codes = ; + lvgl-codes = ; }; compatible: "zephyr,lvgl-keypad-input" From 41f7294d0691ff754df106507a5794a79dc0454b Mon Sep 17 00:00:00 2001 From: Anas Nashif Date: Tue, 30 Jan 2024 13:01:31 +0000 Subject: [PATCH 3113/3723] MAINTAINERS: Cleanup CI area Remove inactive user in this area and add new collaborators. Signed-off-by: Anas Nashif --- MAINTAINERS.yml | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/MAINTAINERS.yml b/MAINTAINERS.yml index 2df43c77a11..d025cff00b8 100644 --- a/MAINTAINERS.yml +++ b/MAINTAINERS.yml @@ -4608,7 +4608,9 @@ Continuous Integration: maintainers: - stephanosio - nashif - - galak + collaborators: + - fabiobaltieri + - kartben files: - .github/ - scripts/ci/ From 34f39800cfb81e606c25cc2e1c6c0358b885efdf Mon Sep 17 00:00:00 2001 From: Tom Burdick Date: Tue, 30 Jan 2024 10:51:50 -0600 Subject: [PATCH 3114/3723] llext: Extend test coverage The platform key using arch + simulation better provides coverage of unique architectures. Adds a testcase for writable module builds and loading which was uncovered previously and would've led to a failure on xtensa as xtensa currently requires writable storage. Signed-off-by: Tom Burdick --- tests/subsys/llext/hello_world/testcase.yaml | 15 ++++++++++++++- 1 file changed, 14 insertions(+), 1 deletion(-) diff --git a/tests/subsys/llext/hello_world/testcase.yaml b/tests/subsys/llext/hello_world/testcase.yaml index 23201d9d3f0..35370a65ece 100644 --- a/tests/subsys/llext/hello_world/testcase.yaml +++ b/tests/subsys/llext/hello_world/testcase.yaml @@ -16,9 +16,22 @@ tests: extra_configs: - arch:arm:CONFIG_ARM_MPU=n - CONFIG_LLEXT_STORAGE_WRITABLE=y - llext.simple.modules_enabled: + llext.simple.modules_enabled_writable: platform_key: - simulation + - arch + platform_exclude: + - qemu_cortex_a9 # MMU + extra_configs: + - arch:arm:CONFIG_ARM_MPU=n + - CONFIG_MODULES=y + - CONFIG_LLEXT_STORAGE_WRITABLE=y + - CONFIG_LLEXT_TEST_HELLO=m + llext.simple.modules_enabled_readonly: + arch_exclude: xtensa # for now + platform_key: + - simulation + - arch platform_exclude: - qemu_cortex_a9 # MMU extra_configs: From b1a15718aa9990c8820c2f426d7a559b88f74e29 Mon Sep 17 00:00:00 2001 From: Ian Morris Date: Wed, 27 Dec 2023 11:53:33 -0800 Subject: [PATCH 3115/3723] dts-bindings: pinctrl: renesas_ra: enabled config of i/o ports 4-7 The RA_PINCFG macro is used to generate a value that can be written directly to the pin function select register. In addition to the pin function this value also contains port and pin number information, located in bit fields that are unused by the register. The bit field used to store the port information consists of 3-bits. However, a typo in the mask definition limited the field to two bits meaning only ports 0-3 could be configured. This patch resolves the issue, allowing ports 0-7 to be configured. If the port is greater than 7 another field (port4) is used to store an additional bit (allowing an additional 8 ports to be supported). However, use of this field has not yet been implemented. Signed-off-by: Ian Morris --- .../zephyr/dt-bindings/pinctrl/renesas/pinctrl-ra-common.h | 2 +- soc/arm/renesas_ra/common/pinctrl_ra.h | 5 +++-- 2 files changed, 4 insertions(+), 3 deletions(-) diff --git a/include/zephyr/dt-bindings/pinctrl/renesas/pinctrl-ra-common.h b/include/zephyr/dt-bindings/pinctrl/renesas/pinctrl-ra-common.h index 88ea7ece75d..a7969523a93 100644 --- a/include/zephyr/dt-bindings/pinctrl/renesas/pinctrl-ra-common.h +++ b/include/zephyr/dt-bindings/pinctrl/renesas/pinctrl-ra-common.h @@ -12,7 +12,7 @@ #define PSEL_POS 24 #define PSEL_MASK 0x5 #define PORT_POS 21 -#define PORT_MASK 0x3 +#define PORT_MASK 0x7 #define PIN_POS 17 #define PIN_MASK 0xF #define OPT_POS 0 diff --git a/soc/arm/renesas_ra/common/pinctrl_ra.h b/soc/arm/renesas_ra/common/pinctrl_ra.h index d61f1e418d5..ed80b3fda18 100644 --- a/soc/arm/renesas_ra/common/pinctrl_ra.h +++ b/soc/arm/renesas_ra/common/pinctrl_ra.h @@ -56,7 +56,8 @@ struct pinctrl_ra_pin { uint8_t pin: 4; uint8_t port: 3; uint32_t UNUSED24: 5; - uint8_t port4: 3; + uint8_t port4: 1; + uint32_t UNUSED30: 2; }; }; }; @@ -90,4 +91,4 @@ extern int pinctrl_ra_query_config(uint32_t port, uint32_t pin, Z_PINCTRL_STATE_PIN_INIT) \ } -#endif /* ZEPHYR_SOC_ARM_RENESAS_RA_RA6E1_PINCTRL_SOC_H_ */ +#endif /* ZEPHYR_SOC_ARM_RENESAS_RA_COMMON_RA_PINCTRL_SOC_H_ */ From 9b3b34f16e9645524007050e52b96437f96334bb Mon Sep 17 00:00:00 2001 From: Magdalena Pastula Date: Thu, 18 Jan 2024 15:17:38 +0100 Subject: [PATCH 3116/3723] drivers: serial: align to nRF54L15 Align UARTE driver config to nRF54L15. Signed-off-by: Magdalena Pastula --- drivers/serial/Kconfig.nrfx | 27 +++++++++++++++++++++++ drivers/serial/Kconfig.nrfx_uart_instance | 1 + 2 files changed, 28 insertions(+) diff --git a/drivers/serial/Kconfig.nrfx b/drivers/serial/Kconfig.nrfx index 21a657fbaf4..8995b6b9fbf 100644 --- a/drivers/serial/Kconfig.nrfx +++ b/drivers/serial/Kconfig.nrfx @@ -31,6 +31,8 @@ config UART_NRFX_UARTE config UART_NRFX_UARTE_LEGACY_SHIM bool "Legacy UARTE shim" depends on UART_NRFX_UARTE + # NRF54L15 need new UARTE driver + depends on !SOC_SERIES_NRF54LX # New shim takes more ROM. Until it is fixed use legacy shim. default y @@ -64,6 +66,31 @@ nrfx_uart_num = 3 rsource "Kconfig.nrfx_uart_instance" endif +if HAS_HW_NRF_UARTE00 +nrfx_uart_num = 00 +rsource "Kconfig.nrfx_uart_instance" +endif + +if HAS_HW_NRF_UARTE20 +nrfx_uart_num = 20 +rsource "Kconfig.nrfx_uart_instance" +endif + +if HAS_HW_NRF_UARTE21 +nrfx_uart_num = 21 +rsource "Kconfig.nrfx_uart_instance" +endif + +if HAS_HW_NRF_UARTE22 +nrfx_uart_num = 22 +rsource "Kconfig.nrfx_uart_instance" +endif + +if HAS_HW_NRF_UARTE30 +nrfx_uart_num = 30 +rsource "Kconfig.nrfx_uart_instance" +endif + config NRFX_TIMER0 default y depends on UART_0_NRF_HW_ASYNC_TIMER = 0 \ diff --git a/drivers/serial/Kconfig.nrfx_uart_instance b/drivers/serial/Kconfig.nrfx_uart_instance index 76f74caa038..718631a4d09 100644 --- a/drivers/serial/Kconfig.nrfx_uart_instance +++ b/drivers/serial/Kconfig.nrfx_uart_instance @@ -20,6 +20,7 @@ config UART_$(nrfx_uart_num)_ASYNC config UART_$(nrfx_uart_num)_ENHANCED_POLL_OUT bool "Efficient poll out on port $(nrfx_uart_num)" + depends on !SOC_SERIES_NRF54LX default y depends on HAS_HW_NRF_UARTE$(nrfx_uart_num) select NRFX_PPI if HAS_HW_NRF_PPI From ae78cf017d9a2da978c89278a0e6de5f2269462e Mon Sep 17 00:00:00 2001 From: Witold Lukasik Date: Mon, 11 Dec 2023 15:10:04 +0100 Subject: [PATCH 3117/3723] drivers: timer: move SYSTEM_CLOCK_WAIT to Kconfig.nrf_xrtc SYSTEM_CLOCK_WAIT will be a common part for a next version of Nordic timer. Signed-off-by: Witold Lukasik --- drivers/timer/Kconfig | 1 + drivers/timer/Kconfig.nrf_rtc | 32 ---------------------------- drivers/timer/Kconfig.nrf_xrtc | 38 ++++++++++++++++++++++++++++++++++ 3 files changed, 39 insertions(+), 32 deletions(-) create mode 100644 drivers/timer/Kconfig.nrf_xrtc diff --git a/drivers/timer/Kconfig b/drivers/timer/Kconfig index 8a88e731986..b7e01eb5811 100644 --- a/drivers/timer/Kconfig +++ b/drivers/timer/Kconfig @@ -84,6 +84,7 @@ source "drivers/timer/Kconfig.mips_cp0" source "drivers/timer/Kconfig.native_posix" source "drivers/timer/Kconfig.npcx_itim" source "drivers/timer/Kconfig.nrf_rtc" +source "drivers/timer/Kconfig.nrf_xrtc" source "drivers/timer/Kconfig.rcar_cmt" source "drivers/timer/Kconfig.riscv_machine" source "drivers/timer/Kconfig.rv32m1_lptmr" diff --git a/drivers/timer/Kconfig.nrf_rtc b/drivers/timer/Kconfig.nrf_rtc index baa917282bc..729dc8d362a 100644 --- a/drivers/timer/Kconfig.nrf_rtc +++ b/drivers/timer/Kconfig.nrf_rtc @@ -42,36 +42,4 @@ config NRF_RTC_TIMER_TRIGGER_OVERFLOW When enabled, a function can be used to trigger RTC overflow and effectively shift time into the future. -choice - prompt "Clock startup policy" - default SYSTEM_CLOCK_WAIT_FOR_STABILITY - -config SYSTEM_CLOCK_NO_WAIT - bool "No wait" - help - System clock source is initiated but does not wait for clock readiness. - When this option is picked, system clock may not be ready when code relying - on kernel API is executed. Requested timeouts will be prolonged by the - remaining startup time. - -config SYSTEM_CLOCK_WAIT_FOR_AVAILABILITY - bool "Wait for availability" - help - System clock source initialization waits until clock is available. In some - systems, clock initially runs from less accurate source which has faster - startup time and then seamlessly switches to the target clock source when - it is ready. When this option is picked, system clock is available after - system clock driver initialization but it may be less accurate. Option is - equivalent to waiting for stability if clock source does not have - intermediate state. - -config SYSTEM_CLOCK_WAIT_FOR_STABILITY - bool "Wait for stability" - help - System clock source initialization waits until clock is stable. When this - option is picked, system clock is available and stable after system clock - driver initialization. - -endchoice - endif # NRF_RTC_TIMER diff --git a/drivers/timer/Kconfig.nrf_xrtc b/drivers/timer/Kconfig.nrf_xrtc new file mode 100644 index 00000000000..56efbc3a298 --- /dev/null +++ b/drivers/timer/Kconfig.nrf_xrtc @@ -0,0 +1,38 @@ +# Common RTC configuration + +# Copyright (c) 2023 Nordic Semiconductor ASA +# SPDX-License-Identifier: Apache-2.0 + +if NRF_RTC_TIMER +choice + prompt "Clock startup policy" + default SYSTEM_CLOCK_WAIT_FOR_STABILITY + +config SYSTEM_CLOCK_NO_WAIT + bool "No wait" + help + System clock source is initiated but does not wait for clock readiness. + When this option is picked, system clock may not be ready when code relying + on kernel API is executed. Requested timeouts will be prolonged by the + remaining startup time. + +config SYSTEM_CLOCK_WAIT_FOR_AVAILABILITY + bool "Wait for availability" + help + System clock source initialization waits until clock is available. In some + systems, clock initially runs from less accurate source which has faster + startup time and then seamlessly switches to the target clock source when + it is ready. When this option is picked, system clock is available after + system clock driver initialization but it may be less accurate. Option is + equivalent to waiting for stability if clock source does not have + intermediate state. + +config SYSTEM_CLOCK_WAIT_FOR_STABILITY + bool "Wait for stability" + help + System clock source initialization waits until clock is stable. When this + option is picked, system clock is available and stable after system clock + driver initialization. + +endchoice +endif # NRF_RTC_TIMER From daa888c37ba71da40b3e78a60ab77afb5463d2a4 Mon Sep 17 00:00:00 2001 From: Witold Lukasik Date: Mon, 11 Dec 2023 15:13:40 +0100 Subject: [PATCH 3118/3723] soc: arm: nordic_nrf: move NRF_RTC_TIMER not to be selected as default NRF_RTC_TIMER will not be a default timer in the next version of Nordic timer. It should be soc selection specific. Signed-off-by: Witold Lukasik --- soc/arm/nordic_nrf/Kconfig.defconfig | 5 +---- soc/arm/nordic_nrf/nrf51/Kconfig.defconfig.series | 4 ++++ soc/arm/nordic_nrf/nrf52/Kconfig.defconfig.series | 4 ++++ soc/arm/nordic_nrf/nrf53/Kconfig.defconfig.series | 4 ++++ soc/arm/nordic_nrf/nrf91/Kconfig.defconfig.series | 4 ++++ 5 files changed, 17 insertions(+), 4 deletions(-) diff --git a/soc/arm/nordic_nrf/Kconfig.defconfig b/soc/arm/nordic_nrf/Kconfig.defconfig index 858c60d1d88..c20df806186 100644 --- a/soc/arm/nordic_nrf/Kconfig.defconfig +++ b/soc/arm/nordic_nrf/Kconfig.defconfig @@ -7,15 +7,12 @@ if SOC_FAMILY_NRF source "soc/arm/nordic_nrf/*/Kconfig.defconfig.series" -# If the kernel has timer support, enable both clock control and timer +# If the kernel has timer support, enable clock control if SYS_CLOCK_EXISTS config CLOCK_CONTROL default y -config NRF_RTC_TIMER - default y - endif # SYS_CLOCK_EXISTS config SYS_CLOCK_HW_CYCLES_PER_SEC diff --git a/soc/arm/nordic_nrf/nrf51/Kconfig.defconfig.series b/soc/arm/nordic_nrf/nrf51/Kconfig.defconfig.series index 8c0bc74c02f..a4053bf7fed 100644 --- a/soc/arm/nordic_nrf/nrf51/Kconfig.defconfig.series +++ b/soc/arm/nordic_nrf/nrf51/Kconfig.defconfig.series @@ -14,4 +14,8 @@ config SOC_SERIES config NUM_IRQS default 26 +# If the kernel has timer support, enable the timer +config NRF_RTC_TIMER + default y if SYS_CLOCK_EXISTS + endif # SOC_SERIES_NRF51X diff --git a/soc/arm/nordic_nrf/nrf52/Kconfig.defconfig.series b/soc/arm/nordic_nrf/nrf52/Kconfig.defconfig.series index 4a7edf2aa95..2e89a5130a6 100644 --- a/soc/arm/nordic_nrf/nrf52/Kconfig.defconfig.series +++ b/soc/arm/nordic_nrf/nrf52/Kconfig.defconfig.series @@ -10,4 +10,8 @@ source "soc/arm/nordic_nrf/nrf52/Kconfig.defconfig.nrf52*" config SOC_SERIES default "nrf52" +# If the kernel has timer support, enable the timer +config NRF_RTC_TIMER + default y if SYS_CLOCK_EXISTS + endif # SOC_SERIES_NRF52X diff --git a/soc/arm/nordic_nrf/nrf53/Kconfig.defconfig.series b/soc/arm/nordic_nrf/nrf53/Kconfig.defconfig.series index 2857d5dd25d..7e5660cf514 100644 --- a/soc/arm/nordic_nrf/nrf53/Kconfig.defconfig.series +++ b/soc/arm/nordic_nrf/nrf53/Kconfig.defconfig.series @@ -10,4 +10,8 @@ source "soc/arm/nordic_nrf/nrf53/Kconfig.defconfig.nrf53*" config SOC_SERIES default "nrf53" +# If the kernel has timer support, enable the timer +config NRF_RTC_TIMER + default y if SYS_CLOCK_EXISTS + endif # SOC_SERIES_NRF53X diff --git a/soc/arm/nordic_nrf/nrf91/Kconfig.defconfig.series b/soc/arm/nordic_nrf/nrf91/Kconfig.defconfig.series index 9612555a4c8..6d6cccab999 100644 --- a/soc/arm/nordic_nrf/nrf91/Kconfig.defconfig.series +++ b/soc/arm/nordic_nrf/nrf91/Kconfig.defconfig.series @@ -10,4 +10,8 @@ source "soc/arm/nordic_nrf/nrf91/Kconfig.defconfig.nrf91*" config SOC_SERIES default "nrf91" +# If the kernel has timer support, enable the timer +config NRF_RTC_TIMER + default y if SYS_CLOCK_EXISTS + endif # SOC_SERIES_NRF91X From 1d91a09bfee6f66c5063034784afa44e02463a60 Mon Sep 17 00:00:00 2001 From: Magdalena Pastula Date: Tue, 9 Jan 2024 15:47:17 +0100 Subject: [PATCH 3119/3723] dts: binding: add binding for GRTC Add dts bindings for Global Real-Time Counter. Signed-off-by: Magdalena Pastula --- dts/bindings/misc/nordic,split-channels.yaml | 44 ++++++++++++++++++++ dts/bindings/timer/nordic,nrf-grtc.yaml | 25 +++++++++++ 2 files changed, 69 insertions(+) create mode 100644 dts/bindings/misc/nordic,split-channels.yaml create mode 100644 dts/bindings/timer/nordic,nrf-grtc.yaml diff --git a/dts/bindings/misc/nordic,split-channels.yaml b/dts/bindings/misc/nordic,split-channels.yaml new file mode 100644 index 00000000000..a875dc12d7f --- /dev/null +++ b/dts/bindings/misc/nordic,split-channels.yaml @@ -0,0 +1,44 @@ +# +# Copyright (c) 2024 Nordic Semiconductor ASA +# +# SPDX-License-Identifier: Apache-2.0 +# + +description: | + Nordic Split Channels + + Some of Nordic's peripherals support split ownership feature that allows to + be used by independent owners. As an example the configuration of the + Global Real Time Counter (GRTC) is shown below: + owned-channels = <0 1 2 3 4 5 6 7 8 9 10 11>; + child-owned-channels = <7 8 9 10 11>; + + Which means that channels 0-11 will be assigned to the particular CPU. + Other CPUs cannot use those and another set must be defined for them. + In addition, `child-owned-channels` property allows to use channels + 7-11 only by child subprocessor. If the CPU you're configuring has no + subprocessor(s) assigned, the `child-owned-channels` property + should not be defined. + +properties: + owned-channels: + type: array + description: | + List of channels in a split-ownership peripheral that are to be owned + for use by the compiled CPU. + + nonsecure-channels: + type: array + description: | + List of channels in a split-ownership, split-security peripheral that + are to be configured as nonsecure. In Trustzone systems, this property + is only evaluated for secure peripherals, as nonsecure channels are + implicitly specified through the owned-channels property. This property + is ignored in non-Trustzone systems. + + child-owned-channels: + type: array + description: | + List of channels in a split-ownership peripheral that are officially + owned by the compiled CPU but intended to be used by its child + subprocessor(s). diff --git a/dts/bindings/timer/nordic,nrf-grtc.yaml b/dts/bindings/timer/nordic,nrf-grtc.yaml new file mode 100644 index 00000000000..e78e57df97e --- /dev/null +++ b/dts/bindings/timer/nordic,nrf-grtc.yaml @@ -0,0 +1,25 @@ +# +# Copyright (c) 2024 Nordic Semiconductor ASA +# +# SPDX-License-Identifier: Apache-2.0 +# + +description: Nordic GRTC (Global RTC) + +compatible: "nordic,nrf-grtc" + +include: + - "base.yaml" + - "nordic,split-channels.yaml" + +properties: + reg: + required: true + + interrupts: + required: true + + cc-num: + description: Number of capture/compare channels + type: int + required: true From d3fa931dfdc01ac30c8fff4f443c2016317b5600 Mon Sep 17 00:00:00 2001 From: Magdalena Pastula Date: Tue, 9 Jan 2024 15:48:04 +0100 Subject: [PATCH 3120/3723] modules: hal_nordic: nrfx: add nRF54L15 GRTC instance Add GRTC instance in Nordic HAL configs. Signed-off-by: Magdalena Pastula --- modules/hal_nordic/nrfx/CMakeLists.txt | 7 +++++++ modules/hal_nordic/nrfx/Kconfig | 4 ++++ modules/hal_nordic/nrfx/Kconfig.logging | 4 ++++ modules/hal_nordic/nrfx/nrfx_config.h | 7 +++++++ 4 files changed, 22 insertions(+) diff --git a/modules/hal_nordic/nrfx/CMakeLists.txt b/modules/hal_nordic/nrfx/CMakeLists.txt index b395bc65a88..c7db70b4a4e 100644 --- a/modules/hal_nordic/nrfx/CMakeLists.txt +++ b/modules/hal_nordic/nrfx/CMakeLists.txt @@ -36,6 +36,8 @@ zephyr_compile_definitions_ifdef(CONFIG_SOC_NRF5340_CPUAPP NRF5340_XXAA_APP zephyr_compile_definitions_ifdef(CONFIG_SOC_COMPATIBLE_NRF5340_CPUAPP NRF5340_XXAA_APPLICATION) zephyr_compile_definitions_ifdef(CONFIG_SOC_NRF5340_CPUNET NRF5340_XXAA_NETWORK) zephyr_compile_definitions_ifdef(CONFIG_SOC_COMPATIBLE_NRF5340_CPUNET NRF5340_XXAA_NETWORK) +zephyr_compile_definitions_ifdef(CONFIG_SOC_NRF54L15_ENGA NRF54L15_ENGA_XXAA) +zephyr_compile_definitions_ifdef(CONFIG_SOC_NRF54L15_ENGA_CPUAPP NRF_APPLICATION) zephyr_compile_definitions_ifdef(CONFIG_SOC_NRF9120 NRF9120_XXAA) zephyr_compile_definitions_ifdef(CONFIG_SOC_NRF9160 NRF9160_XXAA) @@ -84,6 +86,7 @@ zephyr_library_sources_ifdef(CONFIG_NRFX_COMP ${SRC_DIR}/nrfx_comp.c) zephyr_library_sources_ifdef(CONFIG_NRFX_DPPI ${SRC_DIR}/nrfx_dppi.c) zephyr_library_sources_ifdef(CONFIG_NRFX_EGU ${SRC_DIR}/nrfx_egu.c) zephyr_library_sources_ifdef(CONFIG_NRFX_GPIOTE ${SRC_DIR}/nrfx_gpiote.c) +zephyr_library_sources_ifdef(CONFIG_NRFX_GRTC ${SRC_DIR}/nrfx_grtc.c) zephyr_library_sources_ifdef(CONFIG_NRFX_I2S ${SRC_DIR}/nrfx_i2s.c) zephyr_library_sources_ifdef(CONFIG_NRFX_IPC ${SRC_DIR}/nrfx_ipc.c) zephyr_library_sources_ifdef(CONFIG_NRFX_LPCOMP ${SRC_DIR}/nrfx_lpcomp.c) @@ -116,6 +119,10 @@ if(CONFIG_NRFX_TWI OR CONFIG_NRFX_TWIM) zephyr_library_sources(${SRC_DIR}/nrfx_twi_twim.c) endif() +if (CONFIG_NRF_GRTC_TIMER AND CONFIG_NRF_GRTC_TIMER_CLOCK_MANAGEMENT) + zephyr_library_compile_definitions(NRF_GRTC_HAS_EXTENDED=1) +endif() + # Inject HAL "CONFIG_NFCT_PINS_AS_GPIOS" definition if user requests to # configure the NFCT pins as GPIOS. Do the same with "CONFIG_GPIO_AS_PINRESET" # to configure the reset GPIO as nRESET. This way, the HAL will take care of diff --git a/modules/hal_nordic/nrfx/Kconfig b/modules/hal_nordic/nrfx/Kconfig index b4c00040ee1..bdca4016ee3 100644 --- a/modules/hal_nordic/nrfx/Kconfig +++ b/modules/hal_nordic/nrfx/Kconfig @@ -103,6 +103,10 @@ config NRFX_GPIOTE_NUM_OF_EVT_HANDLERS Specifies number of handlers that can be registered to nrfx_gpiote driver by the user. +config NRFX_GRTC + bool "GRTC driver" + depends on $(dt_has_compat,$(DT_COMPAT_NORDIC_NRF_GRTC)) + config NRFX_I2S bool diff --git a/modules/hal_nordic/nrfx/Kconfig.logging b/modules/hal_nordic/nrfx/Kconfig.logging index 7f7b785e70c..b24d683d3de 100644 --- a/modules/hal_nordic/nrfx/Kconfig.logging +++ b/modules/hal_nordic/nrfx/Kconfig.logging @@ -28,6 +28,10 @@ config NRFX_GPIOTE_LOG bool "GPIOTE driver logging" depends on NRFX_GPIOTE +config NRFX_GRTC_LOG + bool "GRTC driver logging" + depends on NRFX_GRTC + config NRFX_I2S_LOG bool "I2S driver logging" depends on NRFX_I2S diff --git a/modules/hal_nordic/nrfx/nrfx_config.h b/modules/hal_nordic/nrfx/nrfx_config.h index ac930b13639..451101c8f4b 100644 --- a/modules/hal_nordic/nrfx/nrfx_config.h +++ b/modules/hal_nordic/nrfx/nrfx_config.h @@ -109,6 +109,13 @@ #define NRFX_EGU5_ENABLED 1 #endif +#ifdef CONFIG_NRFX_GRTC +#define NRFX_GRTC_ENABLED 1 +#endif +#ifdef CONFIG_NRFX_GRTC_LOG +#define NRFX_GRTC_CONFIG_LOG_ENABLED 1 +#endif + #ifdef CONFIG_NRFX_GPIOTE #define NRFX_GPIOTE_ENABLED 1 #endif From 70b21845b219cbd7a4bffd4f997fe604b8edd87d Mon Sep 17 00:00:00 2001 From: Magdalena Pastula Date: Tue, 9 Jan 2024 15:49:11 +0100 Subject: [PATCH 3121/3723] soc: arm: nordic_nrf: add support for nRF54L15 GRTC instance Add GRTC as possible clock source. Signed-off-by: Magdalena Pastula --- soc/arm/nordic_nrf/Kconfig.defconfig | 2 ++ 1 file changed, 2 insertions(+) diff --git a/soc/arm/nordic_nrf/Kconfig.defconfig b/soc/arm/nordic_nrf/Kconfig.defconfig index c20df806186..879217a92fe 100644 --- a/soc/arm/nordic_nrf/Kconfig.defconfig +++ b/soc/arm/nordic_nrf/Kconfig.defconfig @@ -16,10 +16,12 @@ config CLOCK_CONTROL endif # SYS_CLOCK_EXISTS config SYS_CLOCK_HW_CYCLES_PER_SEC + default 1000000 if NRF_GRTC_TIMER default 32768 config SYS_CLOCK_TICKS_PER_SEC default 128 if !TICKLESS_KERNEL + default 10000 if NRF_GRTC_TIMER default 32768 config ARCH_HAS_CUSTOM_BUSY_WAIT From b605c4219bf34663d249ffbcdf0fb735f3daaead Mon Sep 17 00:00:00 2001 From: Magdalena Pastula Date: Tue, 9 Jan 2024 15:49:46 +0100 Subject: [PATCH 3122/3723] drivers: timer: add GRTC driver Add Nordic driver for GRTC. Signed-off-by: Magdalena Pastula --- drivers/timer/CMakeLists.txt | 1 + drivers/timer/Kconfig | 1 + drivers/timer/Kconfig.nrf_grtc | 48 ++ drivers/timer/Kconfig.nrf_xrtc | 4 +- drivers/timer/nrf_grtc_timer.c | 566 ++++++++++++++++++ include/zephyr/drivers/timer/nrf_grtc_timer.h | 202 +++++++ 6 files changed, 820 insertions(+), 2 deletions(-) create mode 100644 drivers/timer/Kconfig.nrf_grtc create mode 100644 drivers/timer/nrf_grtc_timer.c create mode 100644 include/zephyr/drivers/timer/nrf_grtc_timer.h diff --git a/drivers/timer/CMakeLists.txt b/drivers/timer/CMakeLists.txt index 47a10b358c1..36534e4716f 100644 --- a/drivers/timer/CMakeLists.txt +++ b/drivers/timer/CMakeLists.txt @@ -24,6 +24,7 @@ zephyr_library_sources_ifdef(CONFIG_MCUX_GPT_TIMER mcux_gpt_timer.c) zephyr_library_sources_ifdef(CONFIG_MIPS_CP0_TIMER mips_cp0_timer.c) zephyr_library_sources_ifdef(CONFIG_NATIVE_POSIX_TIMER native_posix_timer.c) zephyr_library_sources_ifdef(CONFIG_NPCX_ITIM_TIMER npcx_itim_timer.c) +zephyr_library_sources_ifdef(CONFIG_NRF_GRTC_TIMER nrf_grtc_timer.c) zephyr_library_sources_ifdef(CONFIG_NRF_RTC_TIMER nrf_rtc_timer.c) zephyr_library_sources_ifdef(CONFIG_RCAR_CMT_TIMER rcar_cmt_timer.c) zephyr_library_sources_ifdef(CONFIG_RISCV_MACHINE_TIMER riscv_machine_timer.c) diff --git a/drivers/timer/Kconfig b/drivers/timer/Kconfig index b7e01eb5811..f20442dd2c5 100644 --- a/drivers/timer/Kconfig +++ b/drivers/timer/Kconfig @@ -84,6 +84,7 @@ source "drivers/timer/Kconfig.mips_cp0" source "drivers/timer/Kconfig.native_posix" source "drivers/timer/Kconfig.npcx_itim" source "drivers/timer/Kconfig.nrf_rtc" +source "drivers/timer/Kconfig.nrf_grtc" source "drivers/timer/Kconfig.nrf_xrtc" source "drivers/timer/Kconfig.rcar_cmt" source "drivers/timer/Kconfig.riscv_machine" diff --git a/drivers/timer/Kconfig.nrf_grtc b/drivers/timer/Kconfig.nrf_grtc new file mode 100644 index 00000000000..442c524fd19 --- /dev/null +++ b/drivers/timer/Kconfig.nrf_grtc @@ -0,0 +1,48 @@ +# Timer driver configuration options +# Copyright (c) 2024 Nordic Semiconductor ASA + +menuconfig NRF_GRTC_TIMER + bool "nRF GRTC Timer" + default y if DT_HAS_NORDIC_NRF_GRTC_ENABLED + select TICKLESS_CAPABLE + select TIMER_HAS_64BIT_CYCLE_COUNTER + select NRFX_GRTC + help + This module implements a kernel device driver for the nRF Global Real + Time Counter NRF_GRTC and provides the standard "system clock driver" + interfaces. + +if NRF_GRTC_TIMER + +config NRF_GRTC_SLEEP_ALLOWED + def_bool y + depends on POWEROFF + help + This feature allows GRTC SYSCOUNTER to go to sleep state. + +config NRF_GRTC_TIMER_APP_DEFINED_INIT + bool "Application defines GRTC initialization" + help + Application defines the initialization procedure and time of the GRTC + drivers, rather than leaving it up to SYS_INIT. + +config NRF_GRTC_START_SYSCOUNTER + bool "Start SYSCOUNTER on driver init" + select NRF_GRTC_TIMER_CLOCK_MANAGEMENT + help + Start the SYSCOUNTER when initializing the GRTC. This should only be + handled by one processor in the system. + +config NRF_GRTC_TIMER_CLOCK_MANAGEMENT + bool + help + Compile additional driver code for enabling management functionality of + the GRTC. Usually this is only needed by the processor that is starting + the SYSCOUNTER, but can be shared by multiple processors in the system. + +config NRF_GRTC_SLEEP_MINIMUM_LATENCY + int + default 1000 + depends on NRF_GRTC_SLEEP_ALLOWED + +endif # NRF_GRTC_TIMER diff --git a/drivers/timer/Kconfig.nrf_xrtc b/drivers/timer/Kconfig.nrf_xrtc index 56efbc3a298..f9fa25a1c30 100644 --- a/drivers/timer/Kconfig.nrf_xrtc +++ b/drivers/timer/Kconfig.nrf_xrtc @@ -3,7 +3,7 @@ # Copyright (c) 2023 Nordic Semiconductor ASA # SPDX-License-Identifier: Apache-2.0 -if NRF_RTC_TIMER +if NRF_RTC_TIMER || NRF_GRTC_TIMER choice prompt "Clock startup policy" default SYSTEM_CLOCK_WAIT_FOR_STABILITY @@ -35,4 +35,4 @@ config SYSTEM_CLOCK_WAIT_FOR_STABILITY driver initialization. endchoice -endif # NRF_RTC_TIMER +endif # NRF_RTC_TIMER || NRF_GRTC_TIMER diff --git a/drivers/timer/nrf_grtc_timer.c b/drivers/timer/nrf_grtc_timer.c new file mode 100644 index 00000000000..dc6ac410905 --- /dev/null +++ b/drivers/timer/nrf_grtc_timer.c @@ -0,0 +1,566 @@ +/* + * Copyright (c) 2024 Nordic Semiconductor ASA + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include +#include +#include +#include +#include +#include +#include +#include + +#define CHAN_COUNT NRFX_GRTC_CONFIG_NUM_OF_CC_CHANNELS +#define EXT_CHAN_COUNT (CHAN_COUNT - 1) +/* The reset value of waketime is 1, which doesn't seem to work. + * It's being looked into, but for the time being use 4. + * Timeout must always be higher than waketime, so setting that to 5. + */ +#define WAKETIME (4) +#define TIMEOUT (WAKETIME + 1) + +#define GRTC_NODE DT_NODELABEL(grtc) + +#ifndef GRTC_SYSCOUNTERL_VALUE_Msk +#define GRTC_SYSCOUNTERL_VALUE_Msk GRTC_SYSCOUNTER_SYSCOUNTERL_VALUE_Msk +#endif + +#ifndef GRTC_SYSCOUNTERH_VALUE_Msk +#define GRTC_SYSCOUNTERH_VALUE_Msk GRTC_SYSCOUNTER_SYSCOUNTERH_VALUE_Msk +#endif + +#define MAX_CC_LATCH_WAIT_TIME_US 77 + +#define CYC_PER_TICK \ + ((uint64_t)sys_clock_hw_cycles_per_sec() / (uint64_t)CONFIG_SYS_CLOCK_TICKS_PER_SEC) + +#define COUNTER_SPAN (GRTC_SYSCOUNTERL_VALUE_Msk | ((uint64_t)GRTC_SYSCOUNTERH_VALUE_Msk << 32)) +#define MAX_TICKS \ + (((COUNTER_SPAN / CYC_PER_TICK) > INT_MAX) ? INT_MAX : (COUNTER_SPAN / CYC_PER_TICK)) + +#define MAX_CYCLES (MAX_TICKS * CYC_PER_TICK) + +/* The maximum SYSCOUNTERVALID settling time equals 1x32k cycles + 20x1MHz cycles. */ +#define GRTC_SYSCOUNTERVALID_SETTLE_MAX_TIME_US 51 + +#if defined(CONFIG_TEST) +const int32_t z_sys_timer_irq_for_test = DT_IRQN(GRTC_NODE); +#endif + +static void sys_clock_timeout_handler(int32_t id, uint64_t cc_val, void *p_context); + +static struct k_spinlock lock; +static uint64_t last_count; +static atomic_t int_mask; +static uint8_t ext_channels_allocated; +static nrfx_grtc_channel_t system_clock_channel_data = { + .handler = sys_clock_timeout_handler, + .p_context = NULL, + .channel = (uint8_t)-1, +}; + +#define IS_CHANNEL_ALLOWED_ASSERT(chan) \ + __ASSERT_NO_MSG((NRFX_GRTC_CONFIG_ALLOWED_CC_CHANNELS_MASK & (1UL << (chan))) && \ + ((chan) != system_clock_channel_data.channel)) + +static inline void grtc_active_set(void) +{ +#if defined(NRF_GRTC_HAS_SYSCOUNTER_ARRAY) && (NRF_GRTC_HAS_SYSCOUNTER_ARRAY == 1) + nrfy_grtc_sys_counter_active_set(NRF_GRTC, true); + while (!nrfy_grtc_sys_conter_ready_check(NRF_GRTC)) { + } +#else + nrfy_grtc_sys_counter_active_state_request_set(NRF_GRTC, true); + k_busy_wait(GRTC_SYSCOUNTERVALID_SETTLE_MAX_TIME_US); +#endif +} + +static inline void grtc_wakeup(void) +{ + if (IS_ENABLED(CONFIG_NRF_GRTC_SLEEP_ALLOWED)) { + grtc_active_set(); + } +} + +static inline void grtc_sleep(void) +{ + if (IS_ENABLED(CONFIG_NRF_GRTC_SLEEP_ALLOWED)) { +#if defined(NRF_GRTC_HAS_SYSCOUNTER_ARRAY) && (NRF_GRTC_HAS_SYSCOUNTER_ARRAY == 1) + nrfy_grtc_sys_counter_active_set(NRF_GRTC, false); +#else + nrfy_grtc_sys_counter_active_state_request_set(NRF_GRTC, false); +#endif + } +} + +static inline uint64_t counter_sub(uint64_t a, uint64_t b) +{ + return (a - b); +} + +static inline uint64_t counter(void) +{ + uint64_t now; + + grtc_wakeup(); + nrfx_grtc_syscounter_get(&now); + grtc_sleep(); + return now; +} + +static inline uint64_t get_comparator(uint32_t chan) +{ + uint64_t cc; + nrfx_err_t result; + + result = nrfx_grtc_syscounter_cc_value_read(chan, &cc); + if (result != NRFX_SUCCESS) { + if (result != NRFX_ERROR_INVALID_PARAM) { + return -EAGAIN; + } + return -EPERM; + } + return cc; +} + +static void system_timeout_set(uint64_t value) +{ + if (value <= NRF_GRTC_SYSCOUNTER_CCADD_MASK) { + grtc_wakeup(); + nrfx_grtc_syscounter_cc_relative_set(&system_clock_channel_data, value, true, + NRFX_GRTC_CC_RELATIVE_SYSCOUNTER); + grtc_sleep(); + } else { + nrfx_grtc_syscounter_cc_absolute_set(&system_clock_channel_data, value + counter(), + true); + } +} + +static bool compare_int_lock(int32_t chan) +{ + atomic_val_t prev = atomic_and(&int_mask, ~BIT(chan)); + + nrfx_grtc_syscounter_cc_int_disable(chan); + + return prev & BIT(chan); +} + +static void compare_int_unlock(int32_t chan, bool key) +{ + if (key) { + atomic_or(&int_mask, BIT(chan)); + nrfx_grtc_syscounter_cc_int_enable(chan); + } +} + +static void sys_clock_timeout_handler(int32_t id, uint64_t cc_val, void *p_context) +{ + ARG_UNUSED(id); + ARG_UNUSED(p_context); + uint64_t dticks; + uint64_t now = counter(); + + if (unlikely(now < cc_val)) { + return; + } + if (!IS_ENABLED(CONFIG_TICKLESS_KERNEL)) { + /* protection is not needed because we are in the GRTC interrupt + * so it won't get preempted by the interrupt. + */ + system_timeout_set(CYC_PER_TICK); + } + + dticks = counter_sub(now, last_count) / CYC_PER_TICK; + + last_count += dticks * CYC_PER_TICK; + sys_clock_announce(IS_ENABLED(CONFIG_TICKLESS_KERNEL) ? (int32_t)dticks : (dticks > 0)); +} + +int32_t z_nrf_grtc_timer_chan_alloc(void) +{ + uint8_t chan; + nrfx_err_t err_code; + + /* Prevent allocating all available channels - one must be left for system purposes. */ + if (ext_channels_allocated >= EXT_CHAN_COUNT) { + return -ENOMEM; + } + err_code = nrfx_grtc_channel_alloc(&chan); + if (err_code != NRFX_SUCCESS) { + return -ENOMEM; + } + ext_channels_allocated++; + return (int32_t)chan; +} + +void z_nrf_grtc_timer_chan_free(int32_t chan) +{ + IS_CHANNEL_ALLOWED_ASSERT(chan); + nrfx_err_t err_code = nrfx_grtc_channel_free(chan); + + if (err_code == NRFX_SUCCESS) { + ext_channels_allocated--; + } +} + +bool z_nrf_grtc_timer_compare_evt_check(int32_t chan) +{ + IS_CHANNEL_ALLOWED_ASSERT(chan); + + uint32_t event_address = nrfx_grtc_event_compare_address_get(chan); + + return *(volatile uint32_t *)event_address != 0; +} + +uint32_t z_nrf_grtc_timer_compare_evt_address_get(int32_t chan) +{ + IS_CHANNEL_ALLOWED_ASSERT(chan); + + return nrfx_grtc_event_compare_address_get(chan); +} + +uint32_t z_nrf_grtc_timer_capture_task_address_get(int32_t chan) +{ + IS_CHANNEL_ALLOWED_ASSERT(chan); + + return nrfx_grtc_capture_task_address_get(chan); +} + +uint64_t z_nrf_grtc_timer_read(void) +{ + return counter(); +} + +bool z_nrf_grtc_timer_compare_int_lock(int32_t chan) +{ + IS_CHANNEL_ALLOWED_ASSERT(chan); + + return compare_int_lock(chan); +} + +void z_nrf_grtc_timer_compare_int_unlock(int32_t chan, bool key) +{ + IS_CHANNEL_ALLOWED_ASSERT(chan); + + compare_int_unlock(chan, key); +} + +uint64_t z_nrf_grtc_timer_compare_read(int32_t chan) +{ + IS_CHANNEL_ALLOWED_ASSERT(chan); + + return get_comparator(chan); +} + +static int compare_set_nolocks(int32_t chan, uint64_t target_time, + z_nrf_grtc_timer_compare_handler_t handler, void *user_data) +{ + nrfx_err_t result; + + __ASSERT_NO_MSG(target_time < COUNTER_SPAN); + nrfx_grtc_channel_t user_channel_data = { + .handler = handler, + .p_context = user_data, + .channel = chan, + }; + result = nrfx_grtc_syscounter_cc_absolute_set(&user_channel_data, target_time, true); + if (result != NRFX_SUCCESS) { + return -EPERM; + } + return 0; +} + +static int compare_set(int32_t chan, uint64_t target_time, + z_nrf_grtc_timer_compare_handler_t handler, void *user_data) +{ + bool key = compare_int_lock(chan); + int ret = compare_set_nolocks(chan, target_time, handler, user_data); + + compare_int_unlock(chan, key); + + return ret; +} + +int z_nrf_grtc_timer_set(int32_t chan, uint64_t target_time, + z_nrf_grtc_timer_compare_handler_t handler, void *user_data) +{ + IS_CHANNEL_ALLOWED_ASSERT(chan); + + return compare_set(chan, target_time, (nrfx_grtc_cc_handler_t)handler, user_data); +} + +void z_nrf_grtc_timer_abort(int32_t chan) +{ + IS_CHANNEL_ALLOWED_ASSERT(chan); + + bool key = compare_int_lock(chan); + (void)nrfx_grtc_syscounter_cc_disable(chan); + compare_int_unlock(chan, key); +} + +uint64_t z_nrf_grtc_timer_get_ticks(k_timeout_t t) +{ + uint64_t curr_time; + int64_t curr_tick; + int64_t result; + int64_t abs_ticks; + + curr_time = counter(); + curr_tick = sys_clock_tick_get(); + + abs_ticks = Z_TICK_ABS(t.ticks); + if (abs_ticks < 0) { + /* relative timeout */ + return (t.ticks > (int64_t)COUNTER_SPAN) ? -EINVAL : (curr_time + t.ticks); + } + + /* absolute timeout */ + result = abs_ticks - curr_tick; + + if (result > (int64_t)COUNTER_SPAN) { + return -EINVAL; + } + + return curr_time + result; +} + +int z_nrf_grtc_timer_capture_prepare(int32_t chan) +{ + nrfx_grtc_channel_t user_channel_data = { + .handler = NULL, + .p_context = NULL, + .channel = chan, + }; + nrfx_err_t result; + + IS_CHANNEL_ALLOWED_ASSERT(chan); + + /* Set the CC value to mark channel as not triggered and also to enable it + * (makes CCEN=1). COUNTER_SPAN is used so as not to fire an event unnecessarily + * - it can be assumed that such a large value will never be reached. + */ + result = nrfx_grtc_syscounter_cc_absolute_set(&user_channel_data, COUNTER_SPAN, false); + + if (result != NRFX_SUCCESS) { + return -EPERM; + } + + return 0; +} + +int z_nrf_grtc_timer_capture_read(int32_t chan, uint64_t *captured_time) +{ + /* TODO: The implementation should probably go to nrfx_grtc and this + * should be just a wrapper for some nrfx_grtc_syscounter_capture_read. + */ + + uint64_t capt_time; + + IS_CHANNEL_ALLOWED_ASSERT(chan); + + /* TODO: Use `nrfy_grtc_sys_counter_enable_check` when available (NRFX-2480) */ + if (NRF_GRTC->CC[chan].CCEN == GRTC_CC_CCEN_ACTIVE_Enable) { + /* If the channel is enabled (.CCEN), it means that there was no capture + * triggering event. + */ + return -EBUSY; + } + + capt_time = nrfy_grtc_sys_counter_cc_get(NRF_GRTC, chan); + + __ASSERT_NO_MSG(capt_time < COUNTER_SPAN); + + *captured_time = capt_time; + + return 0; +} + +#if defined(CONFIG_NRF_GRTC_SLEEP_ALLOWED) +int z_nrf_grtc_wakeup_prepare(uint64_t wake_time_us) +{ + nrfx_err_t err_code; + static uint8_t systemoff_channel; + uint64_t now = counter(); + /* Minimum time that ensures valid execution of system-off procedure. */ + uint32_t minimum_latency_us = nrfy_grtc_waketime_get(NRF_GRTC) + + nrfy_grtc_timeout_get(NRF_GRTC) + + CONFIG_NRF_GRTC_SLEEP_MINIMUM_LATENCY; + uint32_t chan; + int ret; + + if (minimum_latency_us > wake_time_us) { + return -EINVAL; + } + k_spinlock_key_t key = k_spin_lock(&lock); + + err_code = nrfx_grtc_channel_alloc(&systemoff_channel); + if (err_code != NRFX_SUCCESS) { + k_spin_unlock(&lock, key); + return -ENOMEM; + } + (void)nrfx_grtc_syscounter_cc_int_disable(systemoff_channel); + ret = compare_set(systemoff_channel, now + wake_time_us, NULL, NULL); + if (ret < 0) { + k_spin_unlock(&lock, key); + return ret; + } + + for (uint32_t grtc_chan_mask = NRFX_GRTC_CONFIG_ALLOWED_CC_CHANNELS_MASK; + grtc_chan_mask > 0; grtc_chan_mask &= ~BIT(chan)) { + /* Clear all GRTC channels except the systemoff_channel. */ + chan = u32_count_trailing_zeros(grtc_chan_mask); + if (chan != systemoff_channel) { + nrfx_grtc_syscounter_cc_disable(chan); + } + } + + /* Make sure that wake_time_us was not triggered yet. */ + if (nrfy_grtc_sys_counter_compare_event_check(NRF_GRTC, systemoff_channel)) { + k_spin_unlock(&lock, key); + return -EINVAL; + } + + /* This mechanism ensures that stored CC value is latched. */ + uint32_t wait_time = + nrfy_grtc_timeout_get(NRF_GRTC) * CONFIG_SYS_CLOCK_HW_CYCLES_PER_SEC / 32768 + + MAX_CC_LATCH_WAIT_TIME_US; + k_busy_wait(wait_time); +#if NRF_GRTC_HAS_CLKSEL + nrfy_grtc_clksel_set(NRF_GRTC, NRF_GRTC_CLKSEL_LFXO); +#endif + k_spin_unlock(&lock, key); + return 0; +} +#endif /* CONFIG_NRF_GRTC_SLEEP_ALLOWED */ + +uint32_t sys_clock_cycle_get_32(void) +{ + k_spinlock_key_t key = k_spin_lock(&lock); + uint32_t ret = (uint32_t)counter(); + + k_spin_unlock(&lock, key); + return ret; +} + +uint64_t sys_clock_cycle_get_64(void) +{ + k_spinlock_key_t key = k_spin_lock(&lock); + uint64_t ret = counter(); + + k_spin_unlock(&lock, key); + return ret; +} + +uint32_t sys_clock_elapsed(void) +{ + if (!IS_ENABLED(CONFIG_TICKLESS_KERNEL)) { + return 0; + } + + return (uint32_t)(counter_sub(counter(), last_count) / CYC_PER_TICK); +} + +static int sys_clock_driver_init(void) +{ + nrfx_err_t err_code; + +#if defined(CONFIG_NRF_GRTC_TIMER_CLOCK_MANAGEMENT) && \ + (defined(NRF_GRTC_HAS_CLKSEL) && (NRF_GRTC_HAS_CLKSEL == 1)) + /* Use System LFCLK as the low-frequency clock source. */ + nrfy_grtc_clksel_set(NRF_GRTC, NRF_GRTC_CLKSEL_LFCLK); +#endif + +#if defined(CONFIG_NRF_GRTC_START_SYSCOUNTER) + /* SYSCOUNTER needs to be turned off before initialization. */ + nrfy_grtc_sys_counter_set(NRF_GRTC, false); + nrfy_grtc_timeout_set(NRF_GRTC, TIMEOUT); + nrfy_grtc_waketime_set(NRF_GRTC, WAKETIME); +#endif /* CONFIG_NRF_GRTC_START_SYSCOUNTER */ + + IRQ_CONNECT(DT_IRQN(GRTC_NODE), DT_IRQ(GRTC_NODE, priority), nrfx_grtc_irq_handler, 0, 0); + + err_code = nrfx_grtc_init(0); + if (err_code != NRFX_SUCCESS) { + return -EPERM; + } + +#if defined(CONFIG_NRF_GRTC_START_SYSCOUNTER) + err_code = nrfx_grtc_syscounter_start(true, &system_clock_channel_data.channel); + if (err_code != NRFX_SUCCESS) { + return err_code == NRFX_ERROR_NO_MEM ? -ENOMEM : -EPERM; + } + if (IS_ENABLED(CONFIG_NRF_GRTC_SLEEP_ALLOWED)) { + nrfy_grtc_sys_counter_auto_mode_set(NRF_GRTC, false); + } +#else + err_code = nrfx_grtc_channel_alloc(&system_clock_channel_data.channel); + if (err_code != NRFX_SUCCESS) { + return -ENOMEM; + } +#endif /* CONFIG_NRF_GRTC_START_SYSCOUNTER */ + + if (!IS_ENABLED(CONFIG_NRF_GRTC_SLEEP_ALLOWED)) { + grtc_active_set(); + } + + int_mask = NRFX_GRTC_CONFIG_ALLOWED_CC_CHANNELS_MASK; + if (!IS_ENABLED(CONFIG_TICKLESS_KERNEL)) { + system_timeout_set(CYC_PER_TICK); + } + + static const enum nrf_lfclk_start_mode mode = + IS_ENABLED(CONFIG_SYSTEM_CLOCK_NO_WAIT) + ? CLOCK_CONTROL_NRF_LF_START_NOWAIT + : (IS_ENABLED(CONFIG_SYSTEM_CLOCK_WAIT_FOR_AVAILABILITY) + ? CLOCK_CONTROL_NRF_LF_START_AVAILABLE + : CLOCK_CONTROL_NRF_LF_START_STABLE); + + z_nrf_clock_control_lf_on(mode); + + return 0; +} + +void sys_clock_set_timeout(int32_t ticks, bool idle) +{ + ARG_UNUSED(idle); + uint64_t cyc, off, now; + + if (!IS_ENABLED(CONFIG_TICKLESS_KERNEL)) { + return; + } + + ticks = (ticks == K_TICKS_FOREVER) ? MAX_TICKS : MIN(MAX_TICKS, MAX(ticks - 1, 0)); + + now = counter(); + + /* Round up to the next tick boundary */ + off = (now - last_count) + (CYC_PER_TICK - 1); + off = (off / CYC_PER_TICK) * CYC_PER_TICK; + + /* Get the offset with respect to now */ + off -= (now - last_count); + + /* Add the offset to get to the next tick boundary */ + cyc = (uint64_t)ticks * CYC_PER_TICK + off; + + /* Due to elapsed time the calculation above might produce a + * duration that laps the counter. Don't let it. + */ + if (cyc > MAX_CYCLES) { + cyc = MAX_CYCLES; + } + + system_timeout_set(cyc == 0 ? 1 : cyc); +} + +#if defined(CONFIG_NRF_GRTC_TIMER_APP_DEFINED_INIT) +int nrf_grtc_timer_clock_driver_init(void) +{ + return sys_clock_driver_init(); +} +#else +SYS_INIT(sys_clock_driver_init, PRE_KERNEL_2, CONFIG_SYSTEM_CLOCK_INIT_PRIORITY); +#endif diff --git a/include/zephyr/drivers/timer/nrf_grtc_timer.h b/include/zephyr/drivers/timer/nrf_grtc_timer.h new file mode 100644 index 00000000000..172a904fdef --- /dev/null +++ b/include/zephyr/drivers/timer/nrf_grtc_timer.h @@ -0,0 +1,202 @@ +/* + * Copyright (c) 2024 Nordic Semiconductor ASA + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#ifndef ZEPHYR_INCLUDE_DRIVERS_TIMER_NRF_GRTC_TIMER_H +#define ZEPHYR_INCLUDE_DRIVERS_TIMER_NRF_GRTC_TIMER_H + +#ifdef __cplusplus +extern "C" { +#endif + +#include + +/** @brief GRTC timer compare event handler. + * + * Called from GRTC ISR context when processing a compare event. + * + * @param id Compare channel ID. + * + * @param expire_time An actual absolute expiration time set for a compare + * channel. It can differ from the requested target time + * and the difference can be used to determine whether the + * time set was delayed. + * + * @param user_data Pointer to a user context data. + */ +typedef void (*z_nrf_grtc_timer_compare_handler_t)(int32_t id, uint64_t expire_time, + void *user_data); + +/** @brief Allocate GRTC capture/compare channel. + * + * @retval >=0 Non-negative indicates allocated channel ID. + * @retval -ENOMEM if channel cannot be allocated. + */ +int32_t z_nrf_grtc_timer_chan_alloc(void); + +/** @brief Free GRTC capture/compare channel. + * + * @param chan Previously allocated channel ID. + */ +void z_nrf_grtc_timer_chan_free(int32_t chan); + +/** @brief Read current absolute time. + * + * @return Current absolute time. + */ +uint64_t z_nrf_grtc_timer_read(void); + +/** @brief Check COMPARE event state. + * + * @param chan Channel ID. + * + * @retval true The event has been generated. + * @retval false The event has not been generated. + */ +bool z_nrf_grtc_timer_compare_evt_check(int32_t chan); + +/** @brief Get COMPARE event register address. + * + * Address can be used for DPPIC. + * + * @param chan Channel ID. + * + * @return Register address. + */ +uint32_t z_nrf_grtc_timer_compare_evt_address_get(int32_t chan); + +/** @brief Get CAPTURE task register address. + * + * Address can be used for DPPIC. + * + * @param chan Channel ID. + * + * @return Register address. + */ +uint32_t z_nrf_grtc_timer_capture_task_address_get(int32_t chan); + +/** @brief Safely disable compare event interrupt. + * + * Function returns key indicating whether interrupt was already disabled. + * + * @param chan Channel ID. + * + * @return key passed to z_nrf_grtc_timer_compare_int_unlock(). + */ +bool z_nrf_grtc_timer_compare_int_lock(int32_t chan); + +/** @brief Safely enable compare event interrupt. + * + * Event interrupt is conditionally enabled based on @p key. + * + * @param chan Channel ID. + * + * @param key Key returned by z_nrf_grtc_timer_compare_int_lock(). + */ +void z_nrf_grtc_timer_compare_int_unlock(int32_t chan, bool key); + +/** @brief Read compare register value. + * + * @param chan Channel ID. + * + * @retval >=0 Positive is a Value set in the compare register + * @retval -EAGAIN if compare for given channel is not set. + * @retval -EPERM if either channel is unavailable or SYSCOUNTER is not running. + */ +uint64_t z_nrf_grtc_timer_compare_read(int32_t chan); + +/** @brief Set compare channel to given value. + * + * @param chan Channel ID. + * + * @param target_time Absolute target time in ticks. + * + * @param handler User function called in the context of the GRTC interrupt. + * + * @param user_data Data passed to the handler. + * + * @retval 0 if the compare channel was set successfully. + * @retval -EPERM if either channel is unavailable or SYSCOUNTER is not running. + */ +int z_nrf_grtc_timer_set(int32_t chan, uint64_t target_time, + z_nrf_grtc_timer_compare_handler_t handler, void *user_data); + +/** @brief Abort a timer requested with z_nrf_grtc_timer_set(). + * + * If an abort operation is performed too late it is still possible for an event + * to fire. The user can detect a spurious event by comparing absolute time + * provided in callback and a result of z_nrf_grtc_timer_read(). During this + * operation interrupt from that compare channel is disabled. Other interrupts + * are not locked during this operation. + * + * @param chan Channel ID between 1 and CONFIG_NRF_RTC_TIMER_USER_CHAN_COUNT. + */ +void z_nrf_grtc_timer_abort(int32_t chan); + +/** @brief Convert system clock time to GRTC ticks. + * + * @p t can be absolute or relative. + * + * @retval >=0 Positive value represents @p t in GRTC tick value. + * @retval -EINVAL if @p t is out of range. + */ +uint64_t z_nrf_grtc_timer_get_ticks(k_timeout_t t); + +/** @brief Prepare channel for timestamp capture. + * + * Use z_nrf_grtc_timer_capture_task_address_get() to determine the register + * address that is used to trigger capture. + * + * @note Capture and compare are mutually exclusive features - they cannot be + * used simultaneously on the same GRTC channel. + * + * @param chan Channel ID. + * + * @retval 0 if the channel was successfully prepared. + * @retval -EPERM if either channel is unavailable or SYSCOUNTER is not running. + */ +int z_nrf_grtc_timer_capture_prepare(int32_t chan); + +/** @brief Read timestamp value captured on the channel. + * + * The @p chan must be prepared using z_nrf_grtc_timer_capture_prepare(). + * + * @param chan Channel ID. + * + * @param captured_time Pointer to store the value. + * + * @retval 0 if the timestamp was successfully caught and read. + * @retval -EBUSY if capturing has not been triggered. + */ +int z_nrf_grtc_timer_capture_read(int32_t chan, uint64_t *captured_time); + +/** @brief Prepare GRTC as a source of wake up event and set the wake up time. + * + * @note Calling this function should be immediately followed by low-power mode enter + * (if it executed successfully). + * + * @param wake_time_us Relative wake up time in microseconds. + * + * @retval 0 if wake up time was successfully set. + * @retval -EPERM if the SYSCOUNTER is not running. + * @retval -ENOMEM if no available GRTC channels were found. + * @retval -EINVAL if @p wake_time_us is too low. + */ +int z_nrf_grtc_wakeup_prepare(uint64_t wake_time_us); + +/** + * @brief Initialize the GRTC clock timer driver from an application- + * defined function. + * + * @retval 0 on success. + * @retval -errno Negative error code on failure. + */ +int nrf_grtc_timer_clock_driver_init(void); + +#ifdef __cplusplus +} +#endif + +#endif /* ZEPHYR_INCLUDE_DRIVERS_TIMER_NRF_GRTC_TIMER_H */ From 7322abe588bfaef767ade47edd9132d8545249ca Mon Sep 17 00:00:00 2001 From: Magdalena Pastula Date: Tue, 23 Jan 2024 14:55:47 +0100 Subject: [PATCH 3123/3723] modules: hal_nordic: nrfx: add nRF54L15 peripherals instances Add new TIMER and UARTE instances for nRF54L15. Signed-off-by: Magdalena Pastula --- modules/hal_nordic/nrfx/Kconfig | 60 +++++++++++++++++++++++++++ modules/hal_nordic/nrfx/nrfx_config.h | 36 ++++++++++++++++ 2 files changed, 96 insertions(+) diff --git a/modules/hal_nordic/nrfx/Kconfig b/modules/hal_nordic/nrfx/Kconfig index bdca4016ee3..d4efbb7cac8 100644 --- a/modules/hal_nordic/nrfx/Kconfig +++ b/modules/hal_nordic/nrfx/Kconfig @@ -422,6 +422,41 @@ config NRFX_TIMER4 depends on $(dt_nodelabel_has_compat,timer4,$(DT_COMPAT_NORDIC_NRF_TIMER)) select NRFX_TIMER +config NRFX_TIMER00 + bool "TIMER00 driver instance" + depends on $(dt_nodelabel_has_compat,timer00,$(DT_COMPAT_NORDIC_NRF_TIMER)) + select NRFX_TIMER + +config NRFX_TIMER10 + bool "TIMER10 driver instance" + depends on $(dt_nodelabel_has_compat,timer10,$(DT_COMPAT_NORDIC_NRF_TIMER)) + select NRFX_TIMER + +config NRFX_TIMER20 + bool "TIMER20 driver instance" + depends on $(dt_nodelabel_has_compat,timer20,$(DT_COMPAT_NORDIC_NRF_TIMER)) + select NRFX_TIMER + +config NRFX_TIMER21 + bool "TIMER21 driver instance" + depends on $(dt_nodelabel_has_compat,timer21,$(DT_COMPAT_NORDIC_NRF_TIMER)) + select NRFX_TIMER + +config NRFX_TIMER22 + bool "TIMER22 driver instance" + depends on $(dt_nodelabel_has_compat,timer22,$(DT_COMPAT_NORDIC_NRF_TIMER)) + select NRFX_TIMER + +config NRFX_TIMER23 + bool "TIMER23 driver instance" + depends on $(dt_nodelabel_has_compat,timer23,$(DT_COMPAT_NORDIC_NRF_TIMER)) + select NRFX_TIMER + +config NRFX_TIMER24 + bool "TIMER24 driver instance" + depends on $(dt_nodelabel_has_compat,timer24,$(DT_COMPAT_NORDIC_NRF_TIMER)) + select NRFX_TIMER + config NRFX_TWI bool @@ -577,6 +612,31 @@ config NRFX_UARTE3 depends on $(dt_nodelabel_has_compat,uart3,$(DT_COMPAT_NORDIC_NRF_UARTE)) select NRFX_UARTE +config NRFX_UARTE00 + bool "UARTE00 driver instance" + depends on $(dt_nodelabel_has_compat,uart00,$(DT_COMPAT_NORDIC_NRF_UARTE)) + select NRFX_UARTE + +config NRFX_UARTE20 + bool "UARTE20 driver instance" + depends on $(dt_nodelabel_has_compat,uart20,$(DT_COMPAT_NORDIC_NRF_UARTE)) + select NRFX_UARTE + +config NRFX_UARTE21 + bool "UARTE21 driver instance" + depends on $(dt_nodelabel_has_compat,uart21,$(DT_COMPAT_NORDIC_NRF_UARTE)) + select NRFX_UARTE + +config NRFX_UARTE22 + bool "UARTE22 driver instance" + depends on $(dt_nodelabel_has_compat,uart22,$(DT_COMPAT_NORDIC_NRF_UARTE)) + select NRFX_UARTE + +config NRFX_UARTE30 + bool "UARTE30 driver instance" + depends on $(dt_nodelabel_has_compat,uart30,$(DT_COMPAT_NORDIC_NRF_UARTE)) + select NRFX_UARTE + config NRFX_UARTE_CONFIG_SKIP_GPIO_CONFIG bool "UARTE GPIO configuration support" depends on NRFX_UARTE diff --git a/modules/hal_nordic/nrfx/nrfx_config.h b/modules/hal_nordic/nrfx/nrfx_config.h index 451101c8f4b..5d5746e2c88 100644 --- a/modules/hal_nordic/nrfx/nrfx_config.h +++ b/modules/hal_nordic/nrfx/nrfx_config.h @@ -451,6 +451,27 @@ #ifdef CONFIG_NRFX_TIMER4 #define NRFX_TIMER4_ENABLED 1 #endif +#ifdef CONFIG_NRFX_TIMER00 +#define NRFX_TIMER00_ENABLED 1 +#endif +#ifdef CONFIG_NRFX_TIMER10 +#define NRFX_TIMER10_ENABLED 1 +#endif +#ifdef CONFIG_NRFX_TIMER20 +#define NRFX_TIMER20_ENABLED 1 +#endif +#ifdef CONFIG_NRFX_TIMER21 +#define NRFX_TIMER21_ENABLED 1 +#endif +#ifdef CONFIG_NRFX_TIMER22 +#define NRFX_TIMER22_ENABLED 1 +#endif +#ifdef CONFIG_NRFX_TIMER23 +#define NRFX_TIMER23_ENABLED 1 +#endif +#ifdef CONFIG_NRFX_TIMER24 +#define NRFX_TIMER24_ENABLED 1 +#endif #ifdef CONFIG_NRFX_TWI #define NRFX_TWI_ENABLED 1 @@ -570,6 +591,21 @@ #ifdef CONFIG_NRFX_UARTE3 #define NRFX_UARTE3_ENABLED 1 #endif +#ifdef CONFIG_NRFX_UARTE00 +#define NRFX_UARTE00_ENABLED 1 +#endif +#ifdef CONFIG_NRFX_UARTE20 +#define NRFX_UARTE20_ENABLED 1 +#endif +#ifdef CONFIG_NRFX_UARTE21 +#define NRFX_UARTE21_ENABLED 1 +#endif +#ifdef CONFIG_NRFX_UARTE22 +#define NRFX_UARTE22_ENABLED 1 +#endif +#ifdef CONFIG_NRFX_UARTE30 +#define NRFX_UARTE30_ENABLED 1 +#endif #ifdef CONFIG_NRFX_UARTE_CONFIG_SKIP_GPIO_CONFIG #define NRFX_UARTE_CONFIG_SKIP_GPIO_CONFIG 1 #endif From a6bd4dbc33ea2362d1fed1bc16c99e877ab48813 Mon Sep 17 00:00:00 2001 From: Magdalena Pastula Date: Tue, 23 Jan 2024 14:57:47 +0100 Subject: [PATCH 3124/3723] soc: arm: nordic_nrf: add nRF54L15 peripherals instances Add support for nRF54L15 instances of UARTE, TIMER and WTD. Signed-off-by: Magdalena Pastula --- soc/arm/nordic_nrf/Kconfig.peripherals | 36 ++++++++++++++++++++ soc/arm/nordic_nrf/validate_base_addresses.c | 14 ++++++++ 2 files changed, 50 insertions(+) diff --git a/soc/arm/nordic_nrf/Kconfig.peripherals b/soc/arm/nordic_nrf/Kconfig.peripherals index 9e637f2661e..5eeff856c96 100644 --- a/soc/arm/nordic_nrf/Kconfig.peripherals +++ b/soc/arm/nordic_nrf/Kconfig.peripherals @@ -318,6 +318,27 @@ config HAS_HW_NRF_TIMER3 config HAS_HW_NRF_TIMER4 def_bool $(dt_nodelabel_enabled_with_compat,timer4,$(DT_COMPAT_NORDIC_NRF_TIMER)) +config HAS_HW_NRF_TIMER00 + def_bool $(dt_nodelabel_enabled_with_compat,timer00,$(DT_COMPAT_NORDIC_NRF_TIMER)) + +config HAS_HW_NRF_TIMER10 + def_bool $(dt_nodelabel_enabled_with_compat,timer10,$(DT_COMPAT_NORDIC_NRF_TIMER)) + +config HAS_HW_NRF_TIMER20 + def_bool $(dt_nodelabel_enabled_with_compat,timer20,$(DT_COMPAT_NORDIC_NRF_TIMER)) + +config HAS_HW_NRF_TIMER21 + def_bool $(dt_nodelabel_enabled_with_compat,timer21,$(DT_COMPAT_NORDIC_NRF_TIMER)) + +config HAS_HW_NRF_TIMER22 + def_bool $(dt_nodelabel_enabled_with_compat,timer22,$(DT_COMPAT_NORDIC_NRF_TIMER)) + +config HAS_HW_NRF_TIMER23 + def_bool $(dt_nodelabel_enabled_with_compat,timer23,$(DT_COMPAT_NORDIC_NRF_TIMER)) + +config HAS_HW_NRF_TIMER24 + def_bool $(dt_nodelabel_enabled_with_compat,timer24,$(DT_COMPAT_NORDIC_NRF_TIMER)) + config HAS_HW_NRF_TWI0 def_bool $(dt_nodelabel_enabled_with_compat,i2c0,$(DT_COMPAT_NORDIC_NRF_TWI)) @@ -402,6 +423,21 @@ config HAS_HW_NRF_UARTE2 config HAS_HW_NRF_UARTE3 def_bool $(dt_nodelabel_enabled_with_compat,uart3,$(DT_COMPAT_NORDIC_NRF_UARTE)) +config HAS_HW_NRF_UARTE00 + def_bool $(dt_nodelabel_enabled_with_compat,uart00,$(DT_COMPAT_NORDIC_NRF_UARTE)) + +config HAS_HW_NRF_UARTE20 + def_bool $(dt_nodelabel_enabled_with_compat,uart20,$(DT_COMPAT_NORDIC_NRF_UARTE)) + +config HAS_HW_NRF_UARTE21 + def_bool $(dt_nodelabel_enabled_with_compat,uart21,$(DT_COMPAT_NORDIC_NRF_UARTE)) + +config HAS_HW_NRF_UARTE22 + def_bool $(dt_nodelabel_enabled_with_compat,uart22,$(DT_COMPAT_NORDIC_NRF_UARTE)) + +config HAS_HW_NRF_UARTE30 + def_bool $(dt_nodelabel_enabled_with_compat,uart30,$(DT_COMPAT_NORDIC_NRF_UARTE)) + config HAS_HW_NRF_USBD def_bool $(dt_compat_enabled,$(DT_COMPAT_NORDIC_NRF_USBD)) diff --git a/soc/arm/nordic_nrf/validate_base_addresses.c b/soc/arm/nordic_nrf/validate_base_addresses.c index ee440c3252c..9daa820efa9 100644 --- a/soc/arm/nordic_nrf/validate_base_addresses.c +++ b/soc/arm/nordic_nrf/validate_base_addresses.c @@ -198,10 +198,22 @@ CHECK_DT_REG(timer1, NRF_TIMER1); CHECK_DT_REG(timer2, NRF_TIMER2); CHECK_DT_REG(timer3, NRF_TIMER3); CHECK_DT_REG(timer4, NRF_TIMER4); +CHECK_DT_REG(timer00, NRF_TIMER00); +CHECK_DT_REG(timer10, NRF_TIMER10); +CHECK_DT_REG(timer20, NRF_TIMER20); +CHECK_DT_REG(timer21, NRF_TIMER21); +CHECK_DT_REG(timer22, NRF_TIMER22); +CHECK_DT_REG(timer23, NRF_TIMER23); +CHECK_DT_REG(timer24, NRF_TIMER24); CHECK_UART_REG(uart0, 0); CHECK_DT_REG(uart1, NRF_UARTE1); CHECK_DT_REG(uart2, NRF_UARTE2); CHECK_DT_REG(uart3, NRF_UARTE3); +CHECK_DT_REG(uart00, NRF_UARTE00); +CHECK_DT_REG(uart20, NRF_UARTE20); +CHECK_DT_REG(uart21, NRF_UARTE21); +CHECK_DT_REG(uart22, NRF_UARTE22); +CHECK_DT_REG(uart30, NRF_UARTE30); CHECK_DT_REG(uicr, NRF_UICR); CHECK_DT_REG(usbd, NRF_USBD); CHECK_DT_REG(usbreg, NRF_USBREGULATOR); @@ -209,6 +221,8 @@ CHECK_DT_REG(vmc, NRF_VMC); CHECK_DT_REG(wdt, NRF_WDT0); /* this should be the same node as wdt0 */ CHECK_DT_REG(wdt0, NRF_WDT0); CHECK_DT_REG(wdt1, NRF_WDT1); +CHECK_DT_REG(wdt30, NRF_WDT30); +CHECK_DT_REG(wdt31, NRF_WDT31); /* nRF51/nRF52-specific addresses */ #if defined(CONFIG_SOC_SERIES_NRF51X) || defined(CONFIG_SOC_SERIES_NRF52X) From e65d4141e618ebe651b7e6bfa5f58473bde21e9d Mon Sep 17 00:00:00 2001 From: Gerard Marull-Paretas Date: Fri, 19 Jan 2024 13:21:53 +0100 Subject: [PATCH 3125/3723] dts: bindings: clock: add nordic,nrf-lfxo To describe the low frequency crystal oscillator present in some nRF series. Signed-off-by: Gerard Marull-Paretas --- dts/bindings/clock/nordic,nrf-lfxo.yaml | 58 +++++++++++++++++++++++++ 1 file changed, 58 insertions(+) create mode 100644 dts/bindings/clock/nordic,nrf-lfxo.yaml diff --git a/dts/bindings/clock/nordic,nrf-lfxo.yaml b/dts/bindings/clock/nordic,nrf-lfxo.yaml new file mode 100644 index 00000000000..f0090ff4a81 --- /dev/null +++ b/dts/bindings/clock/nordic,nrf-lfxo.yaml @@ -0,0 +1,58 @@ +# Copyright (c) 2024 Nordic Semiconductor ASA +# SPDX-License-Identifier: Apache-2.0 + +description: Nordic nRF low-frequency crystal oscillator + +compatible: "nordic,nrf-lfxo" + +include: [fixed-clock.yaml] + +properties: + clock-frequency: + const: 32768 + + load-capacitors: + type: string + enum: + - "internal" + - "external" + description: | + Type of load capacitors connected to the crystal. If not specified, + adjustments may still happen when the device trimming happens during + system initialization. + + load-capacitance-femtofarad: + type: int + enum: + - 4000 + - 4500 + - 5000 + - 5500 + - 6000 + - 6500 + - 7000 + - 7500 + - 8000 + - 8500 + - 9000 + - 9500 + - 10000 + - 10500 + - 11000 + - 11500 + - 12000 + - 12500 + - 13000 + - 13500 + - 14000 + - 14500 + - 15000 + - 15500 + - 16000 + - 16500 + - 17000 + - 17500 + - 18000 + description: | + Load capacitance in femtofarads. This property is only used when + load-capacitors is set to "internal". From 32c7cd551a2e8c95143818ab12a3d593482b7300 Mon Sep 17 00:00:00 2001 From: Gerard Marull-Paretas Date: Fri, 19 Jan 2024 13:39:19 +0100 Subject: [PATCH 3126/3723] dts: bindings: clock: add nordic,nrf-hfxo: Add bindings for the nRF HFXO present in some nRF SoCs. Signed-off-by: Gerard Marull-Paretas --- dts/bindings/clock/nordic,nrf-hfxo.yaml | 82 +++++++++++++++++++++++++ 1 file changed, 82 insertions(+) create mode 100644 dts/bindings/clock/nordic,nrf-hfxo.yaml diff --git a/dts/bindings/clock/nordic,nrf-hfxo.yaml b/dts/bindings/clock/nordic,nrf-hfxo.yaml new file mode 100644 index 00000000000..dc99c67e5cc --- /dev/null +++ b/dts/bindings/clock/nordic,nrf-hfxo.yaml @@ -0,0 +1,82 @@ +# Copyright (c) 2024 Nordic Semiconductor ASA +# SPDX-License-Identifier: Apache-2.0 + +description: Nordic nRF high-frequency crystal oscillator + +compatible: "nordic,nrf-hfxo" + +include: [fixed-clock.yaml] + +properties: + clock-frequency: + const: 32000000 + + load-capacitors: + type: string + enum: + - "internal" + - "external" + description: | + Type of load capacitors connected to the crystal. If not specified, + adjustments may still happen when the device trimming happens during + system initialization. + + load-capacitance-femtofarad: + type: int + enum: + - 4000 + - 4250 + - 4500 + - 4750 + - 5000 + - 5250 + - 5500 + - 5750 + - 6000 + - 6250 + - 6500 + - 6750 + - 7000 + - 7250 + - 7500 + - 7750 + - 8000 + - 8250 + - 8500 + - 8750 + - 9000 + - 9250 + - 9500 + - 9750 + - 10000 + - 10250 + - 10500 + - 10750 + - 11000 + - 11250 + - 11500 + - 11750 + - 12000 + - 12250 + - 12500 + - 12750 + - 13000 + - 13250 + - 13500 + - 13750 + - 14000 + - 14250 + - 14500 + - 14750 + - 15000 + - 15250 + - 15500 + - 15750 + - 16000 + - 16250 + - 16500 + - 16750 + - 17000 + description: | + Load capacitance in femtofarads. This property is only used when + load-capacitors is set to "internal". From 0b2ed9888afc6329f015d4a6e6ddc6521297d509 Mon Sep 17 00:00:00 2001 From: Witold Lukasik Date: Mon, 11 Dec 2023 17:26:19 +0100 Subject: [PATCH 3127/3723] dts: arm: nordic: add support for Nordic nRF54L15 Add dts files for nRF54L15 chip. Signed-off-by: Witold Lukasik --- dts/arm/nordic/nrf54l15_cpuapp.dtsi | 90 ++++ .../nordic/nrf54l15_cpuapp_peripherals.dtsi | 412 ++++++++++++++++++ dts/arm/nordic/nrf54l_common.dtsi | 33 ++ 3 files changed, 535 insertions(+) create mode 100644 dts/arm/nordic/nrf54l15_cpuapp.dtsi create mode 100644 dts/arm/nordic/nrf54l15_cpuapp_peripherals.dtsi create mode 100644 dts/arm/nordic/nrf54l_common.dtsi diff --git a/dts/arm/nordic/nrf54l15_cpuapp.dtsi b/dts/arm/nordic/nrf54l15_cpuapp.dtsi new file mode 100644 index 00000000000..7e90c8b1213 --- /dev/null +++ b/dts/arm/nordic/nrf54l15_cpuapp.dtsi @@ -0,0 +1,90 @@ +/* + * Copyright (c) 2024 Nordic Semiconductor ASA + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include +#include +#include + +/ { + cpus { + #address-cells = <1>; + #size-cells = <0>; + + cpu: cpu@0 { + clock-frequency = ; + device_type = "cpu"; + compatible = "arm,cortex-m33f"; + reg = <0>; + #address-cells = <1>; + #size-cells = <1>; + itm: itm@e0000000 { + compatible = "arm,armv8m-itm"; + reg = <0xe0000000 0x1000>; + swo-ref-frequency = ; + }; + }; + }; + + clocks { + lfxo: lfxo { + compatible = "nordic,nrf-lfxo"; + #clock-cells = <0>; + clock-frequency = <32768>; + }; + + hfxo: hfxo { + compatible = "nordic,nrf-hfxo"; + #clock-cells = <0>; + clock-frequency = ; + }; + }; + + soc { + uicr: uicr@ffd000 { + compatible = "nordic,nrf-uicr"; + reg = <0xffd000 0x1000>; + }; + + ficr: ficr@ffc000 { + compatible = "nordic,nrf-ficr"; + reg = <0xffc000 0x1000>; + }; + + sram0: memory@20000000 { + compatible = "mmio-sram"; + reg = <0x20000000 DT_SIZE_K(256)>; + }; + + peripheral@50000000 { + #address-cells = <1>; + #size-cells = <1>; + ranges = <0x0 0x50000000 0x10000000>; + + /* Common nRF54L15 peripheral description */ + #include "nrf54l15_cpuapp_peripherals.dtsi" + }; + }; +}; + +&nvic { + arm,num-irq-priority-bits = <3>; +}; + +&rram_controller { + rram0: rram@0 { + /* + * "1524 KB non-volatile memory (RRAM) and 256 KB RAM" + * -- Product Specification + * NB: 1524 = 1.5 * 1024 - 12 + */ + reg = <0x0 DT_SIZE_K(1524)>; + }; +}; + +/* Disable by default to use GRTC */ +&systick { + status = "disabled"; +}; diff --git a/dts/arm/nordic/nrf54l15_cpuapp_peripherals.dtsi b/dts/arm/nordic/nrf54l15_cpuapp_peripherals.dtsi new file mode 100644 index 00000000000..786c21ab215 --- /dev/null +++ b/dts/arm/nordic/nrf54l15_cpuapp_peripherals.dtsi @@ -0,0 +1,412 @@ +/* + * Copyright (c) 2024 Nordic Semiconductor ASA + * + * SPDX-License-Identifier: Apache-2.0 + */ + +dppic00: dppic@42000 { + compatible = "nordic,nrf-dppic"; + reg = <0x42000 0x808>; + status = "disabled"; +}; + +spi00: spi@4a000 { + /* + * This spi node can be either SPIM or SPIS, + * for the user to pick: + * compatible = "nordic,nrf-spim" or + * "nordic,nrf-spis". + */ + compatible = "nordic,nrf-spim"; + #address-cells = <1>; + #size-cells = <0>; + reg = <0x4a000 0x1000>; + interrupts = <74 NRF_DEFAULT_IRQ_PRIORITY>; + max-frequency = ; + easydma-maxcnt-bits = <16>; + status = "disabled"; +}; + +uart00: uart@4a000 { + compatible = "nordic,nrf-uarte"; + reg = <0x4a000 0x1000>; + interrupts = <74 NRF_DEFAULT_IRQ_PRIORITY>; + status = "disabled"; +}; + +gpio2: gpio@50400 { + compatible = "nordic,nrf-gpio"; + gpio-controller; + reg = <0x50400 0x300>; + #gpio-cells = <2>; + ngpios = <11>; + status = "disabled"; + port = <2>; +}; + +timer00: timer@55000 { + compatible = "nordic,nrf-timer"; + status = "disabled"; + reg = <0x55000 0x1000>; + cc-num = <6>; + max-bit-width = <32>; + interrupts = <85 NRF_DEFAULT_IRQ_PRIORITY>; + prescaler = <0>; +}; + +dppic10: dppic@82000 { + compatible = "nordic,nrf-dppic"; + reg = <0x82000 0x808>; + status = "disabled"; +}; + +timer10: timer@85000 { + compatible = "nordic,nrf-timer"; + status = "disabled"; + reg = <0x85000 0x1000>; + cc-num = <8>; + max-bit-width = <32>; + interrupts = <133 NRF_DEFAULT_IRQ_PRIORITY>; + prescaler = <0>; +}; + +egu10: egu@87000 { + compatible = "nordic,nrf-egu"; + reg = <0x87000 0x1000>; + interrupts = <135 NRF_DEFAULT_IRQ_PRIORITY>; + status = "disabled"; +}; + +radio: radio@8a000 { + compatible = "nordic,nrf-radio"; + reg = <0x8a000 0x1000>; + interrupts = <138 NRF_DEFAULT_IRQ_PRIORITY>; + status = "disabled"; + dfe-supported; + ieee802154-supported; + ble-2mbps-supported; + ble-coded-phy-supported; + + ieee802154: ieee802154 { + compatible = "nordic,nrf-ieee802154"; + status = "disabled"; + }; +}; + +dppic20: dppic@c2000 { + compatible = "nordic,nrf-dppic"; + reg = <0xc2000 0x808>; + status = "disabled"; +}; + +i2c20: i2c@c6000 { + compatible = "nordic,nrf-twim"; + #address-cells = <1>; + #size-cells = <0>; + reg = <0xc6000 0x1000>; + clock-frequency = ; + interrupts = <198 NRF_DEFAULT_IRQ_PRIORITY>; + status = "disabled"; +}; + +spi20: spi@c6000 { + /* + * This spi node can be either SPIM or SPIS, + * for the user to pick: + * compatible = "nordic,nrf-spim" or + * "nordic,nrf-spis". + */ + compatible = "nordic,nrf-spim"; + #address-cells = <1>; + #size-cells = <0>; + reg = <0xc6000 0x1000>; + interrupts = <198 NRF_DEFAULT_IRQ_PRIORITY>; + max-frequency = ; + easydma-maxcnt-bits = <16>; + status = "disabled"; +}; + +uart20: uart@c6000 { + compatible = "nordic,nrf-uarte"; + reg = <0xc6000 0x1000>; + interrupts = <198 NRF_DEFAULT_IRQ_PRIORITY>; + status = "disabled"; +}; + +i2c21: i2c@c7000 { + compatible = "nordic,nrf-twim"; + #address-cells = <1>; + #size-cells = <0>; + reg = <0xc7000 0x1000>; + clock-frequency = ; + interrupts = <199 NRF_DEFAULT_IRQ_PRIORITY>; + status = "disabled"; +}; + +spi21: spi@c7000 { + /* + * This spi node can be either SPIM or SPIS, + * for the user to pick: + * compatible = "nordic,nrf-spim" or + * "nordic,nrf-spis". + */ + compatible = "nordic,nrf-spim"; + #address-cells = <1>; + #size-cells = <0>; + reg = <0xc7000 0x1000>; + interrupts = <199 NRF_DEFAULT_IRQ_PRIORITY>; + max-frequency = ; + easydma-maxcnt-bits = <16>; + status = "disabled"; +}; + +uart21: uart@c7000 { + compatible = "nordic,nrf-uarte"; + reg = <0xc7000 0x1000>; + interrupts = <199 NRF_DEFAULT_IRQ_PRIORITY>; + status = "disabled"; +}; + +i2c22: i2c@c8000 { + compatible = "nordic,nrf-twim"; + #address-cells = <1>; + #size-cells = <0>; + reg = <0xc8000 0x1000>; + clock-frequency = ; + interrupts = <200 NRF_DEFAULT_IRQ_PRIORITY>; + status = "disabled"; +}; + +spi22: spi@c8000 { + /* + * This spi node can be either SPIM or SPIS, + * for the user to pick: + * compatible = "nordic,nrf-spim" or + * "nordic,nrf-spis". + */ + compatible = "nordic,nrf-spim"; + #address-cells = <1>; + #size-cells = <0>; + reg = <0xc8000 0x1000>; + interrupts = <200 NRF_DEFAULT_IRQ_PRIORITY>; + max-frequency = ; + easydma-maxcnt-bits = <16>; + status = "disabled"; +}; + +uart22: uart@c8000 { + compatible = "nordic,nrf-uarte"; + reg = <0xc8000 0x1000>; + interrupts = <200 NRF_DEFAULT_IRQ_PRIORITY>; + status = "disabled"; +}; + +egu20: egu@c9000 { + compatible = "nordic,nrf-egu"; + reg = <0xc9000 0x1000>; + interrupts = <201 NRF_DEFAULT_IRQ_PRIORITY>; + status = "disabled"; +}; + +timer20: timer@ca000 { + compatible = "nordic,nrf-timer"; + status = "disabled"; + reg = <0xca000 0x1000>; + cc-num = <6>; + max-bit-width = <32>; + interrupts = <202 NRF_DEFAULT_IRQ_PRIORITY>; + prescaler = <0>; +}; + +timer21: timer@cb000 { + compatible = "nordic,nrf-timer"; + status = "disabled"; + reg = <0xcb000 0x1000>; + cc-num = <6>; + max-bit-width = <32>; + interrupts = <203 NRF_DEFAULT_IRQ_PRIORITY>; + prescaler = <0>; +}; + +timer22: timer@cc000 { + compatible = "nordic,nrf-timer"; + status = "disabled"; + reg = <0xcc000 0x1000>; + cc-num = <6>; + max-bit-width = <32>; + interrupts = <204 NRF_DEFAULT_IRQ_PRIORITY>; + prescaler = <0>; +}; + +timer23: timer@cd000 { + compatible = "nordic,nrf-timer"; + status = "disabled"; + reg = <0xcd000 0x1000>; + cc-num = <6>; + max-bit-width = <32>; + interrupts = <205 NRF_DEFAULT_IRQ_PRIORITY>; + prescaler = <0>; +}; + +timer24: timer@ce000 { + compatible = "nordic,nrf-timer"; + status = "disabled"; + reg = <0xce000 0x1000>; + cc-num = <6>; + max-bit-width = <32>; + interrupts = <206 NRF_DEFAULT_IRQ_PRIORITY>; + prescaler = <0>; +}; + +adc: adc@d5000 { + compatible = "nordic,nrf-saadc"; + reg = <0xd5000 0x1000>; + interrupts = <213 NRF_DEFAULT_IRQ_PRIORITY>; + status = "disabled"; + #io-channel-cells = <1>; +}; + +nfct: nfct@d6000 { + compatible = "nordic,nrf-nfct"; + reg = <0xd6000 0x1000>; + interrupts = <214 NRF_DEFAULT_IRQ_PRIORITY>; + status = "disabled"; +}; + +temp: temp@d7000 { + compatible = "nordic,nrf-temp"; + reg = <0xd7000 0x1000>; + interrupts = <215 NRF_DEFAULT_IRQ_PRIORITY>; + status = "disabled"; +}; + +gpio1: gpio@d8200 { + compatible = "nordic,nrf-gpio"; + gpio-controller; + reg = <0xd8200 0x300>; + #gpio-cells = <2>; + ngpios = <16>; + status = "disabled"; + port = <1>; + gpiote-instance = <&gpiote20>; +}; + +gpiote20: gpiote@da000 { + compatible = "nordic,nrf-gpiote"; + reg = <0xda000 0x1000>; + interrupts = <219 NRF_DEFAULT_IRQ_PRIORITY>; + status = "disabled"; + instance = <20>; +}; + +i2s20: i2s@dd000 { + compatible = "nordic,nrf-i2s"; + #address-cells = <1>; + #size-cells = <0>; + reg = <0xdd000 0x1000>; + interrupts = <221 NRF_DEFAULT_IRQ_PRIORITY>; + status = "disabled"; +}; + +qdec20: qdec@e0000 { + compatible = "nordic,nrf-qdec"; + reg = <0xe0000 0x1000>; + interrupts = <224 NRF_DEFAULT_IRQ_PRIORITY>; + status = "disabled"; +}; + +qdec21: qdec@e1000 { + compatible = "nordic,nrf-qdec"; + reg = <0xe1000 0x1000>; + interrupts = <225 NRF_DEFAULT_IRQ_PRIORITY>; + status = "disabled"; +}; + +grtc: grtc@e2000 { + compatible = "nordic,nrf-grtc"; + reg = <0xe2000 0x1000>; + cc-num = <12>; + owned-channels = <0 1 2 3 4 5 6 7 8 9 10 11>; + interrupts = <228 NRF_DEFAULT_IRQ_PRIORITY>; + status = "disabled"; +}; + +dppic30: dppic@102000 { + compatible = "nordic,nrf-dppic"; + reg = <0x102000 0x808>; + status = "disabled"; +}; + +i2c30: i2c@104000 { + compatible = "nordic,nrf-twim"; + #address-cells = <1>; + #size-cells = <0>; + reg = <0x104000 0x1000>; + clock-frequency = ; + interrupts = <260 NRF_DEFAULT_IRQ_PRIORITY>; + status = "disabled"; +}; + +spi30: spi@104000 { + /* + * This spi node can be either SPIM or SPIS, + * for the user to pick: + * compatible = "nordic,nrf-spim" or + * "nordic,nrf-spis". + */ + compatible = "nordic,nrf-spim"; + #address-cells = <1>; + #size-cells = <0>; + reg = <0x104000 0x1000>; + interrupts = <260 NRF_DEFAULT_IRQ_PRIORITY>; + max-frequency = ; + easydma-maxcnt-bits = <16>; + status = "disabled"; +}; + +uart30: uart@104000 { + compatible = "nordic,nrf-uarte"; + reg = <0x104000 0x1000>; + interrupts = <260 NRF_DEFAULT_IRQ_PRIORITY>; + status = "disabled"; +}; + +wdt30: watchdog@108000 { + compatible = "nordic,nrf-wdt"; + reg = <0x108000 0x620>; + interrupts = <264 NRF_DEFAULT_IRQ_PRIORITY>; + status = "disabled"; +}; + +wdt31: watchdog@109000 { + compatible = "nordic,nrf-wdt"; + reg = <0x109000 0x620>; + interrupts = <265 NRF_DEFAULT_IRQ_PRIORITY>; + status = "disabled"; +}; + +gpio0: gpio@10a000 { + compatible = "nordic,nrf-gpio"; + gpio-controller; + reg = <0x10a000 0x300>; + #gpio-cells = <2>; + ngpios = <5>; + status = "disabled"; + port = <0>; + gpiote-instance = <&gpiote30>; +}; + +gpiote30: gpiote@10c000 { + compatible = "nordic,nrf-gpiote"; + reg = <0x10c000 0x1000>; + interrupts = <269 NRF_DEFAULT_IRQ_PRIORITY>; + status = "disabled"; + instance = <30>; +}; + +clock: clock@10e000 { + compatible = "nordic,nrf-clock"; + reg = <0x10e000 0x1000>; + interrupts = <270 NRF_DEFAULT_IRQ_PRIORITY>; + status = "disabled"; +}; diff --git a/dts/arm/nordic/nrf54l_common.dtsi b/dts/arm/nordic/nrf54l_common.dtsi new file mode 100644 index 00000000000..4fb7768bd3f --- /dev/null +++ b/dts/arm/nordic/nrf54l_common.dtsi @@ -0,0 +1,33 @@ +/* + * Copyright (c) 2024 Nordic Semiconductor ASA + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include +#include "nrf_common.dtsi" + +/ { + soc { + rram_controller: rram-controller@5004b000 { + compatible = "nordic,rram-controller"; + reg = <0x5004b000 0x1000>; + #address-cells = <1>; + #size-cells = <1>; + interrupts = <75 NRF_DEFAULT_IRQ_PRIORITY>; + rram0: rram@0 { + compatible = "soc-nv-flash"; + erase-block-size = <4096>; + write-block-size = <1>; + }; + }; + }; + + chosen { + zephyr,flash-controller = &rram_controller; + }; + + sw_pwm: sw-pwm { + generator = <&timer21>; + }; +}; From a5eeb6d6db3af44935efb2c4b5f3c9240c19d3d9 Mon Sep 17 00:00:00 2001 From: Witold Lukasik Date: Mon, 11 Dec 2023 17:30:04 +0100 Subject: [PATCH 3128/3723] soc: arm: nordic_nrf: add source code for validating rram partitions RRAM is a part of nRF54L15 SOC. Signed-off-by: Witold Lukasik --- soc/arm/nordic_nrf/validate_rram_partitions.c | 97 +++++++++++++++++++ 1 file changed, 97 insertions(+) create mode 100644 soc/arm/nordic_nrf/validate_rram_partitions.c diff --git a/soc/arm/nordic_nrf/validate_rram_partitions.c b/soc/arm/nordic_nrf/validate_rram_partitions.c new file mode 100644 index 00000000000..f35d9cf73f3 --- /dev/null +++ b/soc/arm/nordic_nrf/validate_rram_partitions.c @@ -0,0 +1,97 @@ +/* + * Copyright (c) 2024 Nordic Semiconductor ASA + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include +#include +#include + +#define PAIR__(f, sep, arg_first, ...) FOR_EACH_FIXED_ARG(f, sep, arg_first, __VA_ARGS__) +#define PAIR_(f, sep, args_to_expand) PAIR__(f, sep, args_to_expand) +#define PAIR(n, f, sep, ...) PAIR_(f, sep, GET_ARGS_LESS_N(n, __VA_ARGS__)) + +/** + * @brief Call a macro on every unique pair of the given variadic arguments. + * + * For example, FOR_EACH_PAIR(f, (,), 1, 2, 3, 4) should expand to: + * + * f(2, 1) , f(3, 1) , f(4, 1) , f(3, 2) , f(4, 2) , f(4, 3) + * + * @param f Macro to call. Must accept two arguments. + * @param sep Separator between macro calls. Must be in parentheses. + * + * @see FOR_EACH + */ +#define FOR_EACH_PAIR(f, sep, ...) \ + LISTIFY(NUM_VA_ARGS_LESS_1(__VA_ARGS__), PAIR, sep, f, sep, __VA_ARGS__) + +/** + * @brief Get a node's non-secure register block start address. + * + * @param node_id Node identifier. + */ +#define REG_ADDR_NS(node_id) (DT_REG_ADDR(node_id) & 0xEFFFFFFFUL) + +/** + * @brief Get a node's non-secure register block end address. + * + * @param node_id Node identifier. + */ +#define REG_END_NS(node_id) (REG_ADDR_NS(node_id) + DT_REG_SIZE(node_id)) + +/* clang-format off */ + +#define RRAM_BASE REG_ADDR_NS(DT_NODELABEL(rram0)) +#define RRAM_CONTROLLER DT_NODELABEL(rram_controller) + +#if !DT_NODE_EXISTS(RRAM_CONTROLLER) +#error "Missing \"rram-controller\" node" +#endif + +#define CHECK_RRAM_NODE_COMPATIBLE(node_id) \ + BUILD_ASSERT(DT_NODE_HAS_COMPAT(node_id, soc_nv_flash), \ + "Missing compatible \"soc-nv-flash\" from " DT_NODE_FULL_NAME(node_id) \ + " (required for all children of " DT_NODE_PATH(RRAM_CONTROLLER) ")") + +#define CHECK_RRAM_PARTITION_WITHIN_PARENT(node_id) \ + BUILD_ASSERT(RRAM_BASE + REG_ADDR_NS(node_id) >= REG_ADDR_NS(DT_GPARENT(node_id)) && \ + RRAM_BASE + REG_END_NS(node_id) <= REG_END_NS(DT_GPARENT(node_id)), \ + DT_NODE_FULL_NAME(node_id) " is not fully contained within its parent " \ + DT_NODE_PATH(DT_GPARENT(node_id))) + +#define CHECK_NODES_NON_OVERLAPPING(node_id_1, node_id_2) \ + BUILD_ASSERT(REG_ADDR_NS(node_id_1) >= REG_END_NS(node_id_2) || \ + REG_ADDR_NS(node_id_2) >= REG_END_NS(node_id_1), \ + DT_NODE_PATH(node_id_1) " and " DT_NODE_PATH(node_id_2) " are overlapping") + +/* Retrieve all RRAM nodes that are children of "rram-controller". */ +#define COMMA(x) x, +#define RRAM_NODES_LIST LIST_DROP_EMPTY(DT_FOREACH_CHILD(RRAM_CONTROLLER, COMMA)) + +#if !IS_EMPTY(RRAM_NODES_LIST) + +/* Check that every RRAM node matches the "soc-nv-flash" compatible. */ +FOR_EACH(CHECK_RRAM_NODE_COMPATIBLE, (;), RRAM_NODES_LIST); + +/* Check that no two RRAM nodes are overlapping. */ +FOR_EACH_PAIR(CHECK_NODES_NON_OVERLAPPING, (;), RRAM_NODES_LIST); + +#endif + +/* Retrieve all RRAM partitions by looking for "fixed-partitions" compatibles in each RRAM node. */ +#define PARTITION_(x) \ + COND_CODE_1(DT_NODE_HAS_COMPAT(x, fixed_partitions), (DT_FOREACH_CHILD(x, COMMA)), ()) +#define PARTITION(x, ...) DT_FOREACH_CHILD_STATUS_OKAY(x, PARTITION_) +#define RRAM_PARTITION_LIST LIST_DROP_EMPTY(DT_FOREACH_CHILD_VARGS(RRAM_CONTROLLER, PARTITION)) + +#if !IS_EMPTY(RRAM_PARTITION_LIST) + +/* Check that every RRAM partition is within the bounds of its parent RRAM node. */ +FOR_EACH(CHECK_RRAM_PARTITION_WITHIN_PARENT, (;), RRAM_PARTITION_LIST); + +/* Check that no two RRAM partitions are overlapping. */ +FOR_EACH_PAIR(CHECK_NODES_NON_OVERLAPPING, (;), RRAM_PARTITION_LIST); + +#endif From 1d9f70226098da5eb849dbaf4f4f9eddd710a86f Mon Sep 17 00:00:00 2001 From: Witold Lukasik Date: Mon, 11 Dec 2023 17:28:06 +0100 Subject: [PATCH 3129/3723] soc: arm: nordic_nrf: add support for Nordic nrf54l family Add soc files for new Nordic family. Signed-off-by: Witold Lukasik --- soc/arm/nordic_nrf/nrf54l/CMakeLists.txt | 12 ++ .../Kconfig.defconfig.nrf54l15_enga_cpuapp | 18 +++ .../nrf54l/Kconfig.defconfig.series | 19 +++ soc/arm/nordic_nrf/nrf54l/Kconfig.series | 13 ++ soc/arm/nordic_nrf/nrf54l/Kconfig.soc | 70 +++++++++ soc/arm/nordic_nrf/nrf54l/soc.c | 136 ++++++++++++++++++ soc/arm/nordic_nrf/nrf54l/soc.h | 21 +++ 7 files changed, 289 insertions(+) create mode 100644 soc/arm/nordic_nrf/nrf54l/CMakeLists.txt create mode 100644 soc/arm/nordic_nrf/nrf54l/Kconfig.defconfig.nrf54l15_enga_cpuapp create mode 100644 soc/arm/nordic_nrf/nrf54l/Kconfig.defconfig.series create mode 100644 soc/arm/nordic_nrf/nrf54l/Kconfig.series create mode 100644 soc/arm/nordic_nrf/nrf54l/Kconfig.soc create mode 100644 soc/arm/nordic_nrf/nrf54l/soc.c create mode 100644 soc/arm/nordic_nrf/nrf54l/soc.h diff --git a/soc/arm/nordic_nrf/nrf54l/CMakeLists.txt b/soc/arm/nordic_nrf/nrf54l/CMakeLists.txt new file mode 100644 index 00000000000..914aad289ef --- /dev/null +++ b/soc/arm/nordic_nrf/nrf54l/CMakeLists.txt @@ -0,0 +1,12 @@ +# Copyright (c) 2024 Nordic Semiconductor ASA +# SPDX-License-Identifier: Apache-2.0 + +zephyr_sources( + soc.c + ../validate_rram_partitions.c) + +set(SOC_LINKER_SCRIPT ${ZEPHYR_BASE}/include/zephyr/arch/arm/cortex_m/scripts/linker.ld CACHE INTERNAL "") + +if (CONFIG_ELV_GRTC_LFXO_ALLOWED) + message(WARNING "WARNING! ELV mode feature is EXPERIMENTAL and may brick your device!") +endif() diff --git a/soc/arm/nordic_nrf/nrf54l/Kconfig.defconfig.nrf54l15_enga_cpuapp b/soc/arm/nordic_nrf/nrf54l/Kconfig.defconfig.nrf54l15_enga_cpuapp new file mode 100644 index 00000000000..d19df604c02 --- /dev/null +++ b/soc/arm/nordic_nrf/nrf54l/Kconfig.defconfig.nrf54l15_enga_cpuapp @@ -0,0 +1,18 @@ +# Nordic Semiconductor nRF54L15 MCU + +# Copyright (c) 2024 Nordic Semiconductor ASA +# SPDX-License-Identifier: Apache-2.0 + +if SOC_NRF54L15_ENGA_CPUAPP + +config SOC + string + default "nrf54l15_cpuapp" + +config NUM_IRQS + default 271 + +config IEEE802154_NRF5 + default IEEE802154 + +endif # SOC_NRF54L15_ENGA_CPUAPP diff --git a/soc/arm/nordic_nrf/nrf54l/Kconfig.defconfig.series b/soc/arm/nordic_nrf/nrf54l/Kconfig.defconfig.series new file mode 100644 index 00000000000..6c0a5bc606d --- /dev/null +++ b/soc/arm/nordic_nrf/nrf54l/Kconfig.defconfig.series @@ -0,0 +1,19 @@ +# Nordic Semiconductor nRF54L MCU line + +# Copyright (c) 2024 Nordic Semiconductor ASA +# SPDX-License-Identifier: Apache-2.0 + +if SOC_SERIES_NRF54LX + +rsource "Kconfig.defconfig.nrf54l*" + +config SOC_SERIES + default "nrf54l" + +config CORTEX_M_SYSTICK + default !NRF_GRTC_TIMER + +config CACHE_NRF_CACHE + default y if EXTERNAL_CACHE + +endif # SOC_SERIES_NRF54LX diff --git a/soc/arm/nordic_nrf/nrf54l/Kconfig.series b/soc/arm/nordic_nrf/nrf54l/Kconfig.series new file mode 100644 index 00000000000..a9367a0bf36 --- /dev/null +++ b/soc/arm/nordic_nrf/nrf54l/Kconfig.series @@ -0,0 +1,13 @@ +# Nordic Semiconductor nRF54L MCU line + +# Copyright (c) 2024 Nordic Semiconductor ASA +# SPDX-License-Identifier: Apache-2.0 + +config SOC_SERIES_NRF54LX + bool "Nordic Semiconductor nRF54L series MCU" + select HAS_NRFX + select HAS_NORDIC_DRIVERS + select HAS_SEGGER_RTT if ZEPHYR_SEGGER_MODULE + select SOC_FAMILY_NRF + help + Enable support for nRF54L MCU series diff --git a/soc/arm/nordic_nrf/nrf54l/Kconfig.soc b/soc/arm/nordic_nrf/nrf54l/Kconfig.soc new file mode 100644 index 00000000000..c42c8cfc9b3 --- /dev/null +++ b/soc/arm/nordic_nrf/nrf54l/Kconfig.soc @@ -0,0 +1,70 @@ +# Nordic Semiconductor nRF54 MCU line + +# Copyright (c) 2024 Nordic Semiconductor ASA +# SPDX-License-Identifier: Apache-2.0 + +if SOC_SERIES_NRF54LX + +config SOC_NRF54L15 + bool "NRF54L15" + +config SOC_NRF54L15_ENGA + bool "NRF54L15 ENGA" + select SOC_NRF54L15 + +config SOC_NRF54L15_ENGA_CPUAPP + bool "NRF54L15 ENGA CPUAPP" + select ARM + select ARMV8_M_DSP + select CPU_CORTEX_M33 + select CPU_HAS_ARM_MPU + select CPU_HAS_ICACHE + select CPU_HAS_ARM_SAU + select CPU_HAS_FPU + select HAS_HW_NRF_RADIO_IEEE802154 + select HAS_POWEROFF + select SOC_NRF54L15_ENGA + +config SOC_NRF54LX_SKIP_CLOCK_CONFIG + bool "Skip clock frequency configuration in system initialization" + help + With this option, the CPU clock frequency is not set during system initialization. + The CPU runs with the default, hardware-selected frequency. + +config SOC_NRF_FORCE_CONSTLAT + bool "Force constant-latency mode" + help + In constant latency mode the CPU wakeup latency and the PPI task response + will be constant and kept at a minimum. This is secured by forcing a set + of base resources on while in sleep. The advantage of having a constant + and predictable latency will be at the cost of having increased power consumption. + +config SOC_NRF54L_VREG_MAIN_DCDC + bool "NRF54L DC/DC converter." + help + To enable, an inductor must be connected to the DC/DC converter pin. + +config SOC_NRF54L_NORMAL_VOLTAGE_MODE + bool "NRF54L Normal Voltage Mode." + +config SOC_NRF54L_GLITCHDET_WORKAROUND + bool "Workaround that disables glitch detector" + default y + help + Temporary workaround - disabling glitch detector to limit power consumption. + +if NRF_GRTC_TIMER + +config ELV_GRTC_LFXO_ALLOWED + bool + depends on NRF_GRTC_SLEEP_ALLOWED + select EXPERIMENTAL + help + This feature allows using ELV mode when GRTC operates with the LFXO as + a low-frequency clock source. The LFXO is automatically activated when + preparing to system-off. + WARNING! This feature is EXPERIMENTAL and may brick your device! + +endif # NRF_GRTC_TIMER + +endif # SOC_SERIES_NRF54LX diff --git a/soc/arm/nordic_nrf/nrf54l/soc.c b/soc/arm/nordic_nrf/nrf54l/soc.c new file mode 100644 index 00000000000..a7b286fa048 --- /dev/null +++ b/soc/arm/nordic_nrf/nrf54l/soc.c @@ -0,0 +1,136 @@ +/* + * Copyright (c) 2024 Nordic Semiconductor ASA + * + * SPDX-License-Identifier: Apache-2.0 + */ + +/** + * @file + * @brief System/hardware module for Nordic Semiconductor nRF54L family processor + * + * This module provides routines to initialize and support board-level hardware + * for the Nordic Semiconductor nRF54L family processor. + */ + +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include + +#include + +LOG_MODULE_REGISTER(soc, CONFIG_SOC_LOG_LEVEL); + +#define LFXO_NODE DT_NODELABEL(lfxo) +#define HFXO_NODE DT_NODELABEL(hfxo) + +static int nordicsemi_nrf54l_init(void) +{ + /* Update the SystemCoreClock global variable with current core clock + * retrieved from hardware state. + */ + SystemCoreClockUpdate(); + + /* Enable ICACHE */ + sys_cache_instr_enable(); + + if (IS_ENABLED(CONFIG_SOC_NRF54L_GLITCHDET_WORKAROUND)) { + nrf_glitchdet_enable_set(NRF_GLITCHDET, false); + } + +#if DT_ENUM_HAS_VALUE(LFXO_NODE, load_capacitors, internal) + uint32_t xosc32ktrim = NRF_FICR->XOSC32KTRIM; + + uint32_t offset_k = + (xosc32ktrim & FICR_XOSC32KTRIM_OFFSET_Msk) >> FICR_XOSC32KTRIM_OFFSET_Pos; + + uint32_t slope_field_k = + (xosc32ktrim & FICR_XOSC32KTRIM_SLOPE_Msk) >> FICR_XOSC32KTRIM_SLOPE_Pos; + uint32_t slope_mask_k = FICR_XOSC32KTRIM_SLOPE_Msk >> FICR_XOSC32KTRIM_SLOPE_Pos; + uint32_t slope_sign_k = (slope_mask_k - (slope_mask_k >> 1)); + int32_t slope_k = (int32_t)(slope_field_k ^ slope_sign_k) - (int32_t)slope_sign_k; + + /* As specified in the nRF54L15 PS: + * CAPVALUE = round( (CAPACITANCE - 4) * (FICR->XOSC32KTRIM.SLOPE + 0.765625 * 2^9)/(2^9) + * + FICR->XOSC32KTRIM.OFFSET/(2^6) ); + * where CAPACITANCE is the desired capacitor value in pF, holding any + * value between 4 pF and 18 pF in 0.5 pF steps. + */ + uint32_t mid_val = + (((DT_PROP(LFXO_NODE, load_capacitance_femtofarad) * 2UL) / 1000UL - 8UL) * + (uint32_t)(slope_k + 392)) + (offset_k << 4UL); + uint32_t capvalue_k = mid_val >> 10UL; + + /* Round. */ + if ((mid_val % 1024UL) >= 512UL) { + capvalue_k++; + } + nrf_oscillators_lfxo_cap_set(NRF_OSCILLATORS, (nrf_oscillators_lfxo_cap_t)capvalue_k); +#elif DT_ENUM_HAS_VALUE(LFXO_NODE, load_capacitors, external) + nrf_oscillators_lfxo_cap_set(NRF_OSCILLATORS, (nrf_oscillators_lfxo_cap_t)0); +#endif + +#if DT_ENUM_HAS_VALUE(HFXO_NODE, load_capacitors, internal) + uint32_t xosc32mtrim = NRF_FICR->XOSC32MTRIM; + /* The SLOPE field is in the two's complement form, hence this special + * handling. Ideally, it would result in just one SBFX instruction for + * extracting the slope value, at least gcc is capable of producing such + * output, but since the compiler apparently tries first to optimize + * additions and subtractions, it generates slightly less than optimal + * code. + */ + uint32_t slope_field = + (xosc32mtrim & FICR_XOSC32MTRIM_SLOPE_Msk) >> FICR_XOSC32MTRIM_SLOPE_Pos; + uint32_t slope_mask = FICR_XOSC32MTRIM_SLOPE_Msk >> FICR_XOSC32MTRIM_SLOPE_Pos; + uint32_t slope_sign = (slope_mask - (slope_mask >> 1)); + int32_t slope_m = (int32_t)(slope_field ^ slope_sign) - (int32_t)slope_sign; + uint32_t offset_m = + (xosc32mtrim & FICR_XOSC32MTRIM_OFFSET_Msk) >> FICR_XOSC32MTRIM_OFFSET_Pos; + /* As specified in the nRF54L15 PS: + * CAPVALUE = (((CAPACITANCE-5.5)*(FICR->XOSC32MTRIM.SLOPE+791)) + + * FICR->XOSC32MTRIM.OFFSET<<2)>>8; + * where CAPACITANCE is the desired total load capacitance value in pF, + * holding any value between 4.0 pF and 17.0 pF in 0.25 pF steps. + */ + uint32_t capvalue = + (((((DT_PROP(HFXO_NODE, load_capacitance_femtofarad) * 4UL) / 1000UL) - 22UL) * + (uint32_t)(slope_m + 791) / 4UL) + (offset_m << 2UL)) >> 8UL; + + nrf_oscillators_hfxo_cap_set(NRF_OSCILLATORS, true, capvalue); +#elif DT_ENUM_HAS_VALUE(HFXO_NODE, load_capacitors, external) + nrf_oscillators_hfxo_cap_set(NRF_OSCILLATORS, false, 0); +#endif + + if (IS_ENABLED(CONFIG_SOC_NRF_FORCE_CONSTLAT)) { + nrf_power_task_trigger(NRF_POWER, NRF_POWER_TASK_CONSTLAT); + } + + if (IS_ENABLED(CONFIG_SOC_NRF54L_VREG_MAIN_DCDC)) { + nrf_regulators_vreg_enable_set(NRF_REGULATORS, NRF_REGULATORS_VREG_MAIN, true); + } + + if (IS_ENABLED(CONFIG_SOC_NRF54L_NORMAL_VOLTAGE_MODE)) { + nrf_regulators_vreg_enable_set(NRF_REGULATORS, NRF_REGULATORS_VREG_MEDIUM, false); + } + +#if defined(CONFIG_ELV_GRTC_LFXO_ALLOWED) + nrf_regulators_elv_mode_allow_set(NRF_REGULATORS, NRF_REGULATORS_ELV_ELVGRTCLFXO_MASK); +#endif /* CONFIG_ELV_GRTC_LFXO_ALLOWED */ + + return 0; +} + +void arch_busy_wait(uint32_t time_us) +{ + nrfx_coredep_delay_us(time_us); +} + +SYS_INIT(nordicsemi_nrf54l_init, PRE_KERNEL_1, 0); diff --git a/soc/arm/nordic_nrf/nrf54l/soc.h b/soc/arm/nordic_nrf/nrf54l/soc.h new file mode 100644 index 00000000000..721e9336989 --- /dev/null +++ b/soc/arm/nordic_nrf/nrf54l/soc.h @@ -0,0 +1,21 @@ +/* + * Copyright (c) 2024 Nordic Semiconductor ASA + * + * SPDX-License-Identifier: Apache-2.0 + */ + +/** + * @file SoC configuration macros for the Nordic Semiconductor NRF54L family processors. + */ + +#ifndef _NORDICSEMI_NRF54L_SOC_H_ +#define _NORDICSEMI_NRF54L_SOC_H_ + +#define __ICACHE_PRESENT 1 + +#include + +#define FLASH_PAGE_ERASE_MAX_TIME_US 8000UL +#define FLASH_PAGE_MAX_CNT 381UL + +#endif /* _NORDICSEMI_NRF54L_SOC_H_ */ From 04e4e6e5e97ff1d72959e46a0f26d727aaeaecd5 Mon Sep 17 00:00:00 2001 From: Witold Lukasik Date: Mon, 11 Dec 2023 17:37:22 +0100 Subject: [PATCH 3130/3723] modules: hal_nordic: nrfx: add support for nRF54L15 SOC Add config files for nRF54L15. Signed-off-by: Witold Lukasik --- modules/hal_nordic/nrfx/CMakeLists.txt | 13 + modules/hal_nordic/nrfx/nrfx_config.h | 2 + .../nrfx_config_nrf54l15_enga_application.h | 1538 +++++++++++++++++ 3 files changed, 1553 insertions(+) create mode 100644 modules/hal_nordic/nrfx/nrfx_config_nrf54l15_enga_application.h diff --git a/modules/hal_nordic/nrfx/CMakeLists.txt b/modules/hal_nordic/nrfx/CMakeLists.txt index c7db70b4a4e..cee9540c1e5 100644 --- a/modules/hal_nordic/nrfx/CMakeLists.txt +++ b/modules/hal_nordic/nrfx/CMakeLists.txt @@ -71,6 +71,7 @@ zephyr_library_sources_ifdef(CONFIG_SOC_NRF52833 ${MDK_DIR}/system_nrf5283 zephyr_library_sources_ifdef(CONFIG_SOC_NRF52840 ${MDK_DIR}/system_nrf52840.c) zephyr_library_sources_ifdef(CONFIG_SOC_NRF5340_CPUAPP ${MDK_DIR}/system_nrf5340_application.c) zephyr_library_sources_ifdef(CONFIG_SOC_NRF5340_CPUNET ${MDK_DIR}/system_nrf5340_network.c) +zephyr_library_sources_ifdef(CONFIG_SOC_SERIES_NRF54LX ${MDK_DIR}/system_nrf54l.c) zephyr_library_sources_ifdef(CONFIG_SOC_SERIES_NRF91X ${MDK_DIR}/system_nrf91.c) zephyr_library_sources(nrfx_glue.c) @@ -140,3 +141,15 @@ if(DEFINED uicr_path) zephyr_library_compile_definitions(CONFIG_GPIO_AS_PINRESET) endif() endif() + +if(CONFIG_SOC_NRF54L15) + dt_prop(clock_frequency PATH "/cpus/cpu@0" PROPERTY "clock-frequency") + math(EXPR clock_frequency_mhz "${clock_frequency} / 1000000") + zephyr_compile_definitions("NRF_CONFIG_CPU_FREQ_MHZ=${clock_frequency_mhz}") +endif() + +zephyr_compile_definitions_ifdef(CONFIG_SOC_NRF54LX_SKIP_CLOCK_CONFIG NRF_SKIP_CLOCK_CONFIGURATION) + +if(CONFIG_SOC_SERIES_NRF54LX AND CONFIG_NRFX_DPPI) + zephyr_library_sources(${HELPERS_DIR}/nrfx_gppi_dppi_ppib_lumos.c) +endif() diff --git a/modules/hal_nordic/nrfx/nrfx_config.h b/modules/hal_nordic/nrfx/nrfx_config.h index 5d5746e2c88..543329b4a30 100644 --- a/modules/hal_nordic/nrfx/nrfx_config.h +++ b/modules/hal_nordic/nrfx/nrfx_config.h @@ -698,6 +698,8 @@ #include #elif defined(NRF9120_XXAA) || defined(NRF9160_XXAA) #include +#elif defined(NRF54L15_ENGA_XXAA) && defined(NRF_APPLICATION) + #include #else #error "Unknown device." #endif diff --git a/modules/hal_nordic/nrfx/nrfx_config_nrf54l15_enga_application.h b/modules/hal_nordic/nrfx/nrfx_config_nrf54l15_enga_application.h new file mode 100644 index 00000000000..46b0aa0eff7 --- /dev/null +++ b/modules/hal_nordic/nrfx/nrfx_config_nrf54l15_enga_application.h @@ -0,0 +1,1538 @@ +/* + * Copyright (c) 2024, Nordic Semiconductor ASA + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#ifndef NRFX_CONFIG_NRF54L15_APPLICATION_H__ +#define NRFX_CONFIG_NRF54L15_APPLICATION_H__ + +#ifndef NRFX_CONFIG_H__ +#error "This file should not be included directly. Include nrfx_config.h instead." +#endif + +/** + * @brief NRFX_CLOCK_ENABLED + * + * Boolean. Accepted values 0 and 1. + */ +#ifndef NRFX_CLOCK_ENABLED +#define NRFX_CLOCK_ENABLED 0 +#endif + +/** + * @brief NRFX_CLOCK_CONFIG_LF_SRC + * + * Integer value. + * Supported values: + * - RC = 0 + * - XTAL = 1 + * - Synth = 2 + */ +#ifndef NRFX_CLOCK_CONFIG_LF_SRC +#define NRFX_CLOCK_CONFIG_LF_SRC 0 +#endif + +/** + * @brief NRFX_CLOCK_CONFIG_LF_CAL_ENABLED + * + * Boolean. Accepted values 0 and 1. + */ +#ifndef NRFX_CLOCK_CONFIG_LF_CAL_ENABLED +#define NRFX_CLOCK_CONFIG_LF_CAL_ENABLED 0 +#endif + +/** + * @brief NRFX_CLOCK_CONFIG_LFXO_TWO_STAGE_ENABLED + * + * Boolean. Accepted values 0 and 1. + */ +#ifndef NRFX_CLOCK_CONFIG_LFXO_TWO_STAGE_ENABLED +#define NRFX_CLOCK_CONFIG_LFXO_TWO_STAGE_ENABLED 0 +#endif + +/** + * @brief NRFX_CLOCK_DEFAULT_CONFIG_IRQ_PRIORITY + * + * Integer value. Minimum: 0 Maximum: 7 + */ +#ifndef NRFX_CLOCK_DEFAULT_CONFIG_IRQ_PRIORITY +#define NRFX_CLOCK_DEFAULT_CONFIG_IRQ_PRIORITY 0 +#endif + +/** + * @brief NRFX_CLOCK_CONFIG_LOG_ENABLED + * + * Boolean. Accepted values 0 and 1. + */ +#ifndef NRFX_CLOCK_CONFIG_LOG_ENABLED +#define NRFX_CLOCK_CONFIG_LOG_ENABLED 0 +#endif + +/** + * @brief NRFX_CLOCK_CONFIG_LOG_LEVEL + * + * Integer value. + * Supported values: + * - Off = 0 + * - Error = 1 + * - Warning = 2 + * - Info = 3 + * - Debug = 4 + */ +#ifndef NRFX_CLOCK_CONFIG_LOG_LEVEL +#define NRFX_CLOCK_CONFIG_LOG_LEVEL 0 +#endif + +/** + * @brief NRFX_COMP_ENABLED + * + * Boolean. Accepted values 0 and 1. + */ +#ifndef NRFX_COMP_ENABLED +#define NRFX_COMP_ENABLED 0 +#endif + +/** + * @brief NRFX_COMP_DEFAULT_CONFIG_IRQ_PRIORITY + * + * Integer value. Minimum: 0 Maximum: 7 + */ +#ifndef NRFX_COMP_DEFAULT_CONFIG_IRQ_PRIORITY +#define NRFX_COMP_DEFAULT_CONFIG_IRQ_PRIORITY 0 +#endif + +/** + * @brief NRFX_COMP_CONFIG_LOG_ENABLED + * + * Boolean. Accepted values 0 and 1. + */ +#ifndef NRFX_COMP_CONFIG_LOG_ENABLED +#define NRFX_COMP_CONFIG_LOG_ENABLED 0 +#endif + +/** + * @brief NRFX_COMP_CONFIG_LOG_LEVEL + * + * Integer value. + * Supported values: + * - Off = 0 + * - Error = 1 + * - Warning = 2 + * - Info = 3 + * - Debug = 4 + */ +#ifndef NRFX_COMP_CONFIG_LOG_LEVEL +#define NRFX_COMP_CONFIG_LOG_LEVEL 0 +#endif + +/** + * @brief NRFX_DPPI_ENABLED + * + * Boolean. Accepted values 0 and 1. + */ +#ifndef NRFX_DPPI_ENABLED +#define NRFX_DPPI_ENABLED 0 +#endif + +/** + * @brief NRFX_DPPI_CONFIG_LOG_ENABLED + * + * Boolean. Accepted values 0 and 1. + */ +#ifndef NRFX_DPPI_CONFIG_LOG_ENABLED +#define NRFX_DPPI_CONFIG_LOG_ENABLED 0 +#endif + +/** + * @brief NRFX_DPPI_CONFIG_LOG_LEVEL + * + * Boolean. Accepted values 0 and 1. + */ +#ifndef NRFX_DPPI_CONFIG_LOG_LEVEL +#define NRFX_DPPI_CONFIG_LOG_LEVEL 0 +#endif + +/** + * @brief NRFX_EGU_ENABLED + * + * Boolean. Accepted values 0 and 1. + */ +#ifndef NRFX_EGU_ENABLED +#define NRFX_EGU_ENABLED 0 +#endif + +/** + * @brief NRFX_EGU10_ENABLED + * + * Boolean. Accepted values 0 and 1. + */ +#ifndef NRFX_EGU10_ENABLED +#define NRFX_EGU10_ENABLED 0 +#endif + +/** + * @brief NRFX_EGU20_ENABLED + * + * Boolean. Accepted values 0 and 1. + */ +#ifndef NRFX_EGU20_ENABLED +#define NRFX_EGU20_ENABLED 0 +#endif + +/** + * @brief NRFX_EGU_DEFAULT_CONFIG_IRQ_PRIORITY + * + * Integer value. Minimum: 0 Maximum: 7 + */ +#ifndef NRFX_EGU_DEFAULT_CONFIG_IRQ_PRIORITY +#define NRFX_EGU_DEFAULT_CONFIG_IRQ_PRIORITY 0 +#endif + +/** + * @brief NRFX_GPIOTE_ENABLED + * + * Boolean. Accepted values 0 and 1. + */ +#ifndef NRFX_GPIOTE_ENABLED +#define NRFX_GPIOTE_ENABLED 0 +#endif + +/** + * @brief NRFX_GPIOTE_CONFIG_NUM_OF_EVT_HANDLERS + * + * Integer value. Minimum: 0 Maximum: 15 + */ +#ifndef NRFX_GPIOTE_CONFIG_NUM_OF_EVT_HANDLERS +#define NRFX_GPIOTE_CONFIG_NUM_OF_EVT_HANDLERS 0 +#endif + +/** + * @brief NRFX_GPIOTE_DEFAULT_CONFIG_IRQ_PRIORITY + * + * Integer value. Minimum: 0 Maximum: 7 + */ +#ifndef NRFX_GPIOTE_DEFAULT_CONFIG_IRQ_PRIORITY +#define NRFX_GPIOTE_DEFAULT_CONFIG_IRQ_PRIORITY 0 +#endif + +/** + * @brief NRFX_GPIOTE_CONFIG_LOG_ENABLED + * + * Boolean. Accepted values 0 and 1. + */ +#ifndef NRFX_GPIOTE_CONFIG_LOG_ENABLED +#define NRFX_GPIOTE_CONFIG_LOG_ENABLED 0 +#endif + +/** + * @brief NRFX_GPIOTE_CONFIG_LOG_LEVEL + * + * Integer value. + * Supported values: + * - Off = 0 + * - Error = 1 + * - Warning = 2 + * - Info = 3 + * - Debug = 4 + */ +#ifndef NRFX_GPIOTE_CONFIG_LOG_LEVEL +#define NRFX_GPIOTE_CONFIG_LOG_LEVEL 0 +#endif + +/** + * @brief NRFX_GRTC_ENABLED + * + * Boolean. Accepted values 0 and 1. + */ +#ifndef NRFX_GRTC_ENABLED +#define NRFX_GRTC_ENABLED 0 +#endif + +/** + * @brief GRTC CC channels ownership mask. + */ +#ifndef NRFX_GRTC_CONFIG_ALLOWED_CC_CHANNELS_MASK +#if DT_HAS_COMPAT_STATUS_OKAY(nordic_nrf_grtc) +#if DT_NODE_HAS_PROP(DT_INST(0, nordic_nrf_grtc), owned_channels) +#define NRFX_CONFIG_BIT_DT(node_id, prop, idx) \ + BIT(DT_PROP_BY_IDX(node_id, prop, idx)) +#define NRFX_CONFIG_GRTC_MASK_DT(prop) \ + (COND_CODE_1(DT_NODE_HAS_PROP(DT_INST(0, nordic_nrf_grtc), prop), \ + (DT_FOREACH_PROP_ELEM_SEP(DT_INST(0, nordic_nrf_grtc), prop, \ + NRFX_CONFIG_BIT_DT, (|))), \ + (0))) + +#define NRFX_GRTC_CONFIG_ALLOWED_CC_CHANNELS_MASK \ + (NRFX_CONFIG_GRTC_MASK_DT(owned_channels) & \ + ~NRFX_CONFIG_GRTC_MASK_DT(child_owned_channels)) +#define NRFX_GRTC_CONFIG_NUM_OF_CC_CHANNELS \ + (DT_PROP_LEN_OR(DT_INST(0, nordic_nrf_grtc), owned_channels, 0) - \ + DT_PROP_LEN_OR(DT_INST(0, nordic_nrf_grtc), child_owned_channels, 0)) + +#if ((NRFX_CONFIG_GRTC_MASK_DT(owned_channels) | \ + NRFX_CONFIG_GRTC_MASK_DT(child_owned_channels)) != NRFX_CONFIG_GRTC_MASK_DT(owned_channels)) +#error "`child-owned-channels` property must be a subset of `owned-channels` property" +#endif +#else +#error "property `owned-channels` does not exist" +#endif /* DT_NODE_HAS_PROP(DT_INST(0, nordic_nrf_grtc), owned_channels) */ +#endif /* DT_HAS_COMPAT_STATUS_OKAY(nordic_nrf_grtc) */ + +#endif /* NRFX_GRTC_CONFIG_ALLOWED_CC_CHANNELS_MASK */ + +/** + * @brief NRFX_GRTC_DEFAULT_CONFIG_IRQ_PRIORITY + * + * Boolean. Accepted values 0 and 1. + */ +#ifndef NRFX_GRTC_DEFAULT_CONFIG_IRQ_PRIORITY +#define NRFX_GRTC_DEFAULT_CONFIG_IRQ_PRIORITY 0 +#endif + +/** + * @brief NRFX_I2S_ENABLED + * + * Boolean. Accepted values 0 and 1. + */ +#ifndef NRFX_I2S_ENABLED +#define NRFX_I2S_ENABLED 0 +#endif + +/** + * @brief NRFX_I2S_DEFAULT_CONFIG_IRQ_PRIORITY + * + * Integer value. Minimum: 0 Maximum: 7 + */ +#ifndef NRFX_I2S_DEFAULT_CONFIG_IRQ_PRIORITY +#define NRFX_I2S_DEFAULT_CONFIG_IRQ_PRIORITY 0 +#endif + +/** + * @brief NRFX_I2S_CONFIG_LOG_ENABLED + * + * Boolean. Accepted values 0 and 1. + */ +#ifndef NRFX_I2S_CONFIG_LOG_ENABLED +#define NRFX_I2S_CONFIG_LOG_ENABLED 0 +#endif + +/** + * @brief NRFX_I2S_CONFIG_LOG_LEVEL + * + * Integer value. + * Supported values: + * - Off = 0 + * - Error = 1 + * - Warning = 2 + * - Info = 3 + * - Debug = 4 + */ +#ifndef NRFX_I2S_CONFIG_LOG_LEVEL +#define NRFX_I2S_CONFIG_LOG_LEVEL 0 +#endif + +/** + * @brief NRFX_LPCOMP_ENABLED + * + * Boolean. Accepted values 0 and 1. + */ +#ifndef NRFX_LPCOMP_ENABLED +#define NRFX_LPCOMP_ENABLED 0 +#endif + +/** + * @brief NRFX_LPCOMP_DEFAULT_CONFIG_IRQ_PRIORITY + * + * Integer value. Minimum: 0 Maximum: 7 + */ +#ifndef NRFX_LPCOMP_DEFAULT_CONFIG_IRQ_PRIORITY +#define NRFX_LPCOMP_DEFAULT_CONFIG_IRQ_PRIORITY 0 +#endif + +/** + * @brief NRFX_LPCOMP_CONFIG_LOG_ENABLED + * + * Boolean. Accepted values 0 and 1. + */ +#ifndef NRFX_LPCOMP_CONFIG_LOG_ENABLED +#define NRFX_LPCOMP_CONFIG_LOG_ENABLED 0 +#endif + +/** + * @brief NRFX_LPCOMP_CONFIG_LOG_LEVEL + * + * Integer value. + * Supported values: + * - Off = 0 + * - Error = 1 + * - Warning = 2 + * - Info = 3 + * - Debug = 4 + */ +#ifndef NRFX_LPCOMP_CONFIG_LOG_LEVEL +#define NRFX_LPCOMP_CONFIG_LOG_LEVEL 0 +#endif + +/** + * @brief NRFX_NFCT_ENABLED + * + * Boolean. Accepted values 0 and 1. + */ +#ifndef NRFX_NFCT_ENABLED +#define NRFX_NFCT_ENABLED 0 +#endif + +/** + * @brief NRFX_NFCT_DEFAULT_CONFIG_IRQ_PRIORITY + * + * Integer value. Minimum: 0 Maximum: 7 + */ +#ifndef NRFX_NFCT_DEFAULT_CONFIG_IRQ_PRIORITY +#define NRFX_NFCT_DEFAULT_CONFIG_IRQ_PRIORITY 0 +#endif + +/** + * @brief NRFX_NFCT_CONFIG_TIMER_INSTANCE_ID + * + * Boolean. Accepted values 0 and 1. + */ +#ifndef NRFX_NFCT_CONFIG_TIMER_INSTANCE_ID +#define NRFX_NFCT_CONFIG_TIMER_INSTANCE_ID 0 +#endif + +/** + * @brief NRFX_NFCT_CONFIG_LOG_ENABLED + * + * Boolean. Accepted values 0 and 1. + */ +#ifndef NRFX_NFCT_CONFIG_LOG_ENABLED +#define NRFX_NFCT_CONFIG_LOG_ENABLED 0 +#endif + +/** + * @brief NRFX_NFCT_CONFIG_LOG_LEVEL + * + * Integer value. + * Supported values: + * - Off = 0 + * - Error = 1 + * - Warning = 2 + * - Info = 3 + * - Debug = 4 + */ +#ifndef NRFX_NFCT_CONFIG_LOG_LEVEL +#define NRFX_NFCT_CONFIG_LOG_LEVEL 0 +#endif + +/** + * @brief NRFX_PDM_ENABLED + * + * Boolean. Accepted values 0 and 1. + */ +#ifndef NRFX_PDM_ENABLED +#define NRFX_PDM_ENABLED 0 +#endif + +/** + * @brief NRFX_PDM_DEFAULT_CONFIG_IRQ_PRIORITY + * + * Integer value. Minimum: 0 Maximum: 7 + */ +#ifndef NRFX_PDM_DEFAULT_CONFIG_IRQ_PRIORITY +#define NRFX_PDM_DEFAULT_CONFIG_IRQ_PRIORITY 0 +#endif + +/** + * @brief NRFX_PDM_CONFIG_LOG_ENABLED + * + * Boolean. Accepted values 0 and 1. + */ +#ifndef NRFX_PDM_CONFIG_LOG_ENABLED +#define NRFX_PDM_CONFIG_LOG_ENABLED 0 +#endif + +/** + * @brief NRFX_PDM_CONFIG_LOG_LEVEL + * + * Integer value. + * Supported values: + * - Off = 0 + * - Error = 1 + * - Warning = 2 + * - Info = 3 + * - Debug = 4 + */ +#ifndef NRFX_PDM_CONFIG_LOG_LEVEL +#define NRFX_PDM_CONFIG_LOG_LEVEL 0 +#endif + +/** + * @brief NRFX_POWER_ENABLED + * + * Boolean. Accepted values 0 and 1. + */ +#ifndef NRFX_POWER_ENABLED +#define NRFX_POWER_ENABLED 0 +#endif + +/** + * @brief NRFX_POWER_DEFAULT_CONFIG_IRQ_PRIORITY + * + * Integer value. Minimum: 0 Maximum: 7 + */ +#ifndef NRFX_POWER_DEFAULT_CONFIG_IRQ_PRIORITY +#define NRFX_POWER_DEFAULT_CONFIG_IRQ_PRIORITY 0 +#endif + +/** + * @brief NRFX_PRS_ENABLED + * + * Boolean. Accepted values 0 and 1. + */ +#ifndef NRFX_PRS_ENABLED +#define NRFX_PRS_ENABLED 0 +#endif + +/** + * @brief NRFX_PRS_BOX_0_ENABLED + * + * Boolean. Accepted values 0 and 1. + */ +#ifndef NRFX_PRS_BOX_0_ENABLED +#define NRFX_PRS_BOX_0_ENABLED 0 +#endif + +/** + * @brief NRFX_PRS_BOX_1_ENABLED + * + * Boolean. Accepted values 0 and 1. + */ +#ifndef NRFX_PRS_BOX_1_ENABLED +#define NRFX_PRS_BOX_1_ENABLED 0 +#endif + +/** + * @brief NRFX_PRS_BOX_2_ENABLED + * + * Boolean. Accepted values 0 and 1. + */ +#ifndef NRFX_PRS_BOX_2_ENABLED +#define NRFX_PRS_BOX_2_ENABLED 0 +#endif + +/** + * @brief NRFX_PRS_BOX_3_ENABLED + * + * Boolean. Accepted values 0 and 1. + */ +#ifndef NRFX_PRS_BOX_3_ENABLED +#define NRFX_PRS_BOX_3_ENABLED 0 +#endif + +/** + * @brief NRFX_PRS_BOX_4_ENABLED + * + * Boolean. Accepted values 0 and 1. + */ +#ifndef NRFX_PRS_BOX_4_ENABLED +#define NRFX_PRS_BOX_4_ENABLED 0 +#endif + +/** + * @brief NRFX_PRS_BOX_5_ENABLED + * + * Boolean. Accepted values 0 and 1. + */ +#ifndef NRFX_PRS_BOX_5_ENABLED +#define NRFX_PRS_BOX_5_ENABLED 0 +#endif + +/** + * @brief NRFX_PRS_CONFIG_LOG_ENABLED + * + * Boolean. Accepted values 0 and 1. + */ +#ifndef NRFX_PRS_CONFIG_LOG_ENABLED +#define NRFX_PRS_CONFIG_LOG_ENABLED 0 +#endif + +/** + * @brief NRFX_PRS_CONFIG_LOG_LEVEL + * + * Integer value. + * Supported values: + * - Off = 0 + * - Error = 1 + * - Warning = 2 + * - Info = 3 + * - Debug = 4 + */ +#ifndef NRFX_PRS_CONFIG_LOG_LEVEL +#define NRFX_PRS_CONFIG_LOG_LEVEL 0 +#endif + +/** + * @brief NRFX_PWM_ENABLED + * + * Boolean. Accepted values 0 and 1. + */ +#ifndef NRFX_PWM_ENABLED +#define NRFX_PWM_ENABLED 0 +#endif + +/** + * @brief NRFX_PWM20_ENABLED + * + * Boolean. Accepted values 0 and 1. + */ +#ifndef NRFX_PWM20_ENABLED +#define NRFX_PWM20_ENABLED 0 +#endif + +/** + * @brief NRFX_PWM21_ENABLED + * + * Boolean. Accepted values 0 and 1. + */ +#ifndef NRFX_PWM21_ENABLED +#define NRFX_PWM21_ENABLED 0 +#endif + +/** + * @brief NRFX_PWM22_ENABLED + * + * Boolean. Accepted values 0 and 1. + */ +#ifndef NRFX_PWM22_ENABLED +#define NRFX_PWM22_ENABLED 0 +#endif + +/** + * @brief NRFX_PWM_DEFAULT_CONFIG_IRQ_PRIORITY + * + * Integer value. Minimum: 0 Maximum: 7 + */ +#ifndef NRFX_PWM_DEFAULT_CONFIG_IRQ_PRIORITY +#define NRFX_PWM_DEFAULT_CONFIG_IRQ_PRIORITY 0 +#endif + +/** + * @brief NRFX_PWM_CONFIG_LOG_ENABLED + * + * Boolean. Accepted values 0 and 1. + */ +#ifndef NRFX_PWM_CONFIG_LOG_ENABLED +#define NRFX_PWM_CONFIG_LOG_ENABLED 0 +#endif + +/** + * @brief NRFX_PWM_CONFIG_LOG_LEVEL + * + * Integer value. + * Supported values: + * - Off = 0 + * - Error = 1 + * - Warning = 2 + * - Info = 3 + * - Debug = 4 + */ +#ifndef NRFX_PWM_CONFIG_LOG_LEVEL +#define NRFX_PWM_CONFIG_LOG_LEVEL 0 +#endif + +/** + * @brief NRFX_QDEC_ENABLED + * + * Boolean. Accepted values 0 and 1. + */ +#ifndef NRFX_QDEC_ENABLED +#define NRFX_QDEC_ENABLED 0 +#endif + +/** + * @brief NRFX_QDEC20_ENABLED + * + * Boolean. Accepted values 0 and 1. + */ +#ifndef NRFX_QDEC20_ENABLED +#define NRFX_QDEC20_ENABLED 0 +#endif + +/** + * @brief NRFX_QDEC21_ENABLED + * + * Boolean. Accepted values 0 and 1. + */ +#ifndef NRFX_QDEC21_ENABLED +#define NRFX_QDEC21_ENABLED 0 +#endif + +/** + * @brief NRFX_QDEC_DEFAULT_CONFIG_IRQ_PRIORITY + * + * Integer value. Minimum: 0 Maximum: 7 + */ +#ifndef NRFX_QDEC_DEFAULT_CONFIG_IRQ_PRIORITY +#define NRFX_QDEC_DEFAULT_CONFIG_IRQ_PRIORITY 0 +#endif + +/** + * @brief NRFX_QDEC_CONFIG_LOG_ENABLED + * + * Boolean. Accepted values 0 and 1. + */ +#ifndef NRFX_QDEC_CONFIG_LOG_ENABLED +#define NRFX_QDEC_CONFIG_LOG_ENABLED 0 +#endif + +/** + * @brief NRFX_QDEC_CONFIG_LOG_LEVEL + * + * Integer value. + * Supported values: + * - Off = 0 + * - Error = 1 + * - Warning = 2 + * - Info = 3 + * - Debug = 4 + */ +#ifndef NRFX_QDEC_CONFIG_LOG_LEVEL +#define NRFX_QDEC_CONFIG_LOG_LEVEL 0 +#endif + +/** + * @brief NRFX_RTC_ENABLED + * + * Boolean. Accepted values 0 and 1. + */ +#ifndef NRFX_RTC_ENABLED +#define NRFX_RTC_ENABLED 0 +#endif + +/** + * @brief NRFX_RTC10_ENABLED + * + * Boolean. Accepted values 0 and 1. + */ +#ifndef NRFX_RTC10_ENABLED +#define NRFX_RTC10_ENABLED 0 +#endif + +/** + * @brief NRFX_RTC30_ENABLED + * + * Boolean. Accepted values 0 and 1. + */ +#ifndef NRFX_RTC30_ENABLED +#define NRFX_RTC30_ENABLED 0 +#endif + +/** + * @brief NRFX_RTC_DEFAULT_CONFIG_IRQ_PRIORITY + * + * Integer value. Minimum: 0 Maximum: 7 + */ +#ifndef NRFX_RTC_DEFAULT_CONFIG_IRQ_PRIORITY +#define NRFX_RTC_DEFAULT_CONFIG_IRQ_PRIORITY 0 +#endif + +/** + * @brief NRFX_RTC_CONFIG_LOG_ENABLED + * + * Boolean. Accepted values 0 and 1. + */ +#ifndef NRFX_RTC_CONFIG_LOG_ENABLED +#define NRFX_RTC_CONFIG_LOG_ENABLED 0 +#endif + +/** + * @brief NRFX_RTC_CONFIG_LOG_LEVEL + * + * Integer value. + * Supported values: + * - Off = 0 + * - Error = 1 + * - Warning = 2 + * - Info = 3 + * - Debug = 4 + */ +#ifndef NRFX_RTC_CONFIG_LOG_LEVEL +#define NRFX_RTC_CONFIG_LOG_LEVEL 0 +#endif + +/** + * @brief NRFX_SAADC_ENABLED + * + * Boolean. Accepted values 0 and 1. + */ +#ifndef NRFX_SAADC_ENABLED +#define NRFX_SAADC_ENABLED 0 +#endif + +/** + * @brief NRFX_SAADC_DEFAULT_CONFIG_IRQ_PRIORITY + * + * Integer value. Minimum: 0 Maximum: 7 + */ +#ifndef NRFX_SAADC_DEFAULT_CONFIG_IRQ_PRIORITY +#define NRFX_SAADC_DEFAULT_CONFIG_IRQ_PRIORITY 0 +#endif + +/** + * @brief NRFX_SAADC_CONFIG_LOG_ENABLED + * + * Boolean. Accepted values 0 and 1. + */ +#ifndef NRFX_SAADC_CONFIG_LOG_ENABLED +#define NRFX_SAADC_CONFIG_LOG_ENABLED 0 +#endif + +/** + * @brief NRFX_SAADC_CONFIG_LOG_LEVEL + * + * Integer value. + * Supported values: + * - Off = 0 + * - Error = 1 + * - Warning = 2 + * - Info = 3 + * - Debug = 4 + */ +#ifndef NRFX_SAADC_CONFIG_LOG_LEVEL +#define NRFX_SAADC_CONFIG_LOG_LEVEL 0 +#endif + +/** + * @brief NRFX_SPI_ENABLED + * + * Boolean. Accepted values 0 and 1. + */ +#ifndef NRFX_SPI_ENABLED +#define NRFX_SPI_ENABLED 0 +#endif + +/** + * @brief NRFX_SPI00_ENABLED + * + * Boolean. Accepted values 0 and 1. + */ +#ifndef NRFX_SPI00_ENABLED +#define NRFX_SPI00_ENABLED 0 +#endif + +/** + * @brief NRFX_SPI20_ENABLED + * + * Boolean. Accepted values 0 and 1. + */ +#ifndef NRFX_SPI20_ENABLED +#define NRFX_SPI20_ENABLED 0 +#endif + +/** + * @brief NRFX_SPI21_ENABLED + * + * Boolean. Accepted values 0 and 1. + */ +#ifndef NRFX_SPI21_ENABLED +#define NRFX_SPI21_ENABLED 0 +#endif + +/** + * @brief NRFX_SPI22_ENABLED + * + * Boolean. Accepted values 0 and 1. + */ +#ifndef NRFX_SPI22_ENABLED +#define NRFX_SPI22_ENABLED 0 +#endif + +/** + * @brief NRFX_SPI30_ENABLED + * + * Boolean. Accepted values 0 and 1. + */ +#ifndef NRFX_SPI30_ENABLED +#define NRFX_SPI30_ENABLED 0 +#endif + +/** + * @brief NRFX_SPI_DEFAULT_CONFIG_IRQ_PRIORITY + * + * Integer value. Minimum: 0 Maximum: 7 + */ +#ifndef NRFX_SPI_DEFAULT_CONFIG_IRQ_PRIORITY +#define NRFX_SPI_DEFAULT_CONFIG_IRQ_PRIORITY 0 +#endif + +/** + * @brief NRFX_SPI_CONFIG_LOG_ENABLED + * + * Boolean. Accepted values 0 and 1. + */ +#ifndef NRFX_SPI_CONFIG_LOG_ENABLED +#define NRFX_SPI_CONFIG_LOG_ENABLED 0 +#endif + +/** + * @brief NRFX_SPI_CONFIG_LOG_LEVEL + * + * Integer value. + * Supported values: + * - Off = 0 + * - Error = 1 + * - Warning = 2 + * - Info = 3 + * - Debug = 4 + */ +#ifndef NRFX_SPI_CONFIG_LOG_LEVEL +#define NRFX_SPI_CONFIG_LOG_LEVEL 0 +#endif + +/** + * @brief NRFX_SPIM_ENABLED + * + * Boolean. Accepted values 0 and 1. + */ +#ifndef NRFX_SPIM_ENABLED +#define NRFX_SPIM_ENABLED 0 +#endif + +/** + * @brief NRFX_SPIM00_ENABLED + * + * Boolean. Accepted values 0 and 1. + */ +#ifndef NRFX_SPIM00_ENABLED +#define NRFX_SPIM00_ENABLED 0 +#endif + +/** + * @brief NRFX_SPIM20_ENABLED + * + * Boolean. Accepted values 0 and 1. + */ +#ifndef NRFX_SPIM20_ENABLED +#define NRFX_SPIM20_ENABLED 0 +#endif + +/** + * @brief NRFX_SPIM21_ENABLED + * + * Boolean. Accepted values 0 and 1. + */ +#ifndef NRFX_SPIM21_ENABLED +#define NRFX_SPIM21_ENABLED 0 +#endif + +/** + * @brief NRFX_SPIM22_ENABLED + * + * Boolean. Accepted values 0 and 1. + */ +#ifndef NRFX_SPIM22_ENABLED +#define NRFX_SPIM22_ENABLED 0 +#endif + +/** + * @brief NRFX_SPIM30_ENABLED + * + * Boolean. Accepted values 0 and 1. + */ +#ifndef NRFX_SPIM30_ENABLED +#define NRFX_SPIM30_ENABLED 0 +#endif + +/** + * @brief NRFX_SPIM_EXTENDED_ENABLED + * + * Boolean. Accepted values 0 and 1. + */ +#ifndef NRFX_SPIM_EXTENDED_ENABLED +#define NRFX_SPIM_EXTENDED_ENABLED 0 +#endif + +/** + * @brief NRFX_SPIM_DEFAULT_CONFIG_IRQ_PRIORITY + * + * Integer value. Minimum: 0 Maximum: 7 + */ +#ifndef NRFX_SPIM_DEFAULT_CONFIG_IRQ_PRIORITY +#define NRFX_SPIM_DEFAULT_CONFIG_IRQ_PRIORITY 0 +#endif + +/** + * @brief NRFX_SPIM_CONFIG_LOG_ENABLED + * + * Boolean. Accepted values 0 and 1. + */ +#ifndef NRFX_SPIM_CONFIG_LOG_ENABLED +#define NRFX_SPIM_CONFIG_LOG_ENABLED 0 +#endif + +/** + * @brief NRFX_SPIM_CONFIG_LOG_LEVEL + * + * Integer value. + * Supported values: + * - Off = 0 + * - Error = 1 + * - Warning = 2 + * - Info = 3 + * - Debug = 4 + */ +#ifndef NRFX_SPIM_CONFIG_LOG_LEVEL +#define NRFX_SPIM_CONFIG_LOG_LEVEL 0 +#endif + +/** + * @brief NRFX_SPIS_ENABLED + * + * Boolean. Accepted values 0 and 1. + */ +#ifndef NRFX_SPIS_ENABLED +#define NRFX_SPIS_ENABLED 0 +#endif + +/** + * @brief NRFX_SPIS00_ENABLED + * + * Boolean. Accepted values 0 and 1. + */ +#ifndef NRFX_SPIS00_ENABLED +#define NRFX_SPIS00_ENABLED 0 +#endif + +/** + * @brief NRFX_SPIS20_ENABLED + * + * Boolean. Accepted values 0 and 1. + */ +#ifndef NRFX_SPIS20_ENABLED +#define NRFX_SPIS20_ENABLED 0 +#endif + +/** + * @brief NRFX_SPIS21_ENABLED + * + * Boolean. Accepted values 0 and 1. + */ +#ifndef NRFX_SPIS21_ENABLED +#define NRFX_SPIS21_ENABLED 0 +#endif + +/** + * @brief NRFX_SPIS22_ENABLED + * + * Boolean. Accepted values 0 and 1. + */ +#ifndef NRFX_SPIS22_ENABLED +#define NRFX_SPIS22_ENABLED 0 +#endif + +/** + * @brief NRFX_SPIS30_ENABLED + * + * Boolean. Accepted values 0 and 1. + */ +#ifndef NRFX_SPIS30_ENABLED +#define NRFX_SPIS30_ENABLED 0 +#endif + +/** + * @brief NRFX_SPIS_DEFAULT_CONFIG_IRQ_PRIORITY + * + * Integer value. Minimum: 0 Maximum: 7 + */ +#ifndef NRFX_SPIS_DEFAULT_CONFIG_IRQ_PRIORITY +#define NRFX_SPIS_DEFAULT_CONFIG_IRQ_PRIORITY 0 +#endif + +/** + * @brief NRFX_SPIS_CONFIG_LOG_ENABLED + * + * Boolean. Accepted values 0 and 1. + */ +#ifndef NRFX_SPIS_CONFIG_LOG_ENABLED +#define NRFX_SPIS_CONFIG_LOG_ENABLED 0 +#endif + +/** + * @brief NRFX_SPIS_CONFIG_LOG_LEVEL + * + * Integer value. + * Supported values: + * - Off = 0 + * - Error = 1 + * - Warning = 2 + * - Info = 3 + * - Debug = 4 + */ +#ifndef NRFX_SPIS_CONFIG_LOG_LEVEL +#define NRFX_SPIS_CONFIG_LOG_LEVEL 0 +#endif + +/** + * @brief NRFX_SYSTICK_ENABLED + * + * Boolean. Accepted values 0 and 1. + */ +#ifndef NRFX_SYSTICK_ENABLED +#define NRFX_SYSTICK_ENABLED 0 +#endif + +/** + * @brief NRFX_TEMP_ENABLED + * + * Boolean. Accepted values 0 and 1. + */ +#ifndef NRFX_TEMP_ENABLED +#define NRFX_TEMP_ENABLED 0 +#endif + +/** + * @brief NRFX_TEMP_DEFAULT_CONFIG_IRQ_PRIORITY + * + * Integer value. Minimum: 0 Maximum: 7 + */ +#ifndef NRFX_TEMP_DEFAULT_CONFIG_IRQ_PRIORITY +#define NRFX_TEMP_DEFAULT_CONFIG_IRQ_PRIORITY 0 +#endif + +/** + * @brief NRFX_TIMER_ENABLED + * + * Boolean. Accepted values 0 and 1. + */ +#ifndef NRFX_TIMER_ENABLED +#define NRFX_TIMER_ENABLED 0 +#endif + +/** + * @brief NRFX_TIMER10_ENABLED + * + * Boolean. Accepted values 0 and 1. + */ +#ifndef NRFX_TIMER10_ENABLED +#define NRFX_TIMER10_ENABLED 0 +#endif + +/** + * @brief NRFX_TIMER20_ENABLED + * + * Boolean. Accepted values 0 and 1. + */ +#ifndef NRFX_TIMER20_ENABLED +#define NRFX_TIMER20_ENABLED 0 +#endif + +/** + * @brief NRFX_TIMER21_ENABLED + * + * Boolean. Accepted values 0 and 1. + */ +#ifndef NRFX_TIMER21_ENABLED +#define NRFX_TIMER21_ENABLED 0 +#endif + +/** + * @brief NRFX_TIMER22_ENABLED + * + * Boolean. Accepted values 0 and 1. + */ +#ifndef NRFX_TIMER22_ENABLED +#define NRFX_TIMER22_ENABLED 0 +#endif + +/** + * @brief NRFX_TIMER23_ENABLED + * + * Boolean. Accepted values 0 and 1. + */ +#ifndef NRFX_TIMER23_ENABLED +#define NRFX_TIMER23_ENABLED 0 +#endif + +/** + * @brief NRFX_TIMER24_ENABLED + * + * Boolean. Accepted values 0 and 1. + */ +#ifndef NRFX_TIMER24_ENABLED +#define NRFX_TIMER24_ENABLED 0 +#endif + +/** + * @brief NRFX_TIMER_DEFAULT_CONFIG_IRQ_PRIORITY + * + * Integer value. Minimum: 0 Maximum: 7 + */ +#ifndef NRFX_TIMER_DEFAULT_CONFIG_IRQ_PRIORITY +#define NRFX_TIMER_DEFAULT_CONFIG_IRQ_PRIORITY 0 +#endif + +/** + * @brief NRFX_TIMER_CONFIG_LOG_ENABLED + * + * Boolean. Accepted values 0 and 1. + */ +#ifndef NRFX_TIMER_CONFIG_LOG_ENABLED +#define NRFX_TIMER_CONFIG_LOG_ENABLED 0 +#endif + +/** + * @brief NRFX_TIMER_CONFIG_LOG_LEVEL + * + * Integer value. + * Supported values: + * - Off = 0 + * - Error = 1 + * - Warning = 2 + * - Info = 3 + * - Debug = 4 + */ +#ifndef NRFX_TIMER_CONFIG_LOG_LEVEL +#define NRFX_TIMER_CONFIG_LOG_LEVEL 0 +#endif + +/** + * @brief NRFX_TWIM_ENABLED + * + * Boolean. Accepted values 0 and 1. + */ +#ifndef NRFX_TWIM_ENABLED +#define NRFX_TWIM_ENABLED 0 +#endif + +/** + * @brief NRFX_TWIM20_ENABLED + * + * Boolean. Accepted values 0 and 1. + */ +#ifndef NRFX_TWIM20_ENABLED +#define NRFX_TWIM20_ENABLED 0 +#endif + +/** + * @brief NRFX_TWIM21_ENABLED + * + * Boolean. Accepted values 0 and 1. + */ +#ifndef NRFX_TWIM21_ENABLED +#define NRFX_TWIM21_ENABLED 0 +#endif + +/** + * @brief NRFX_TWIM22_ENABLED + * + * Boolean. Accepted values 0 and 1. + */ +#ifndef NRFX_TWIM22_ENABLED +#define NRFX_TWIM22_ENABLED 0 +#endif + +/** + * @brief NRFX_TWIM30_ENABLED + * + * Boolean. Accepted values 0 and 1. + */ +#ifndef NRFX_TWIM30_ENABLED +#define NRFX_TWIM30_ENABLED 0 +#endif + +/** + * @brief NRFX_TWIM_DEFAULT_CONFIG_IRQ_PRIORITY + * + * Integer value. Minimum: 0 Maximum: 7 + */ +#ifndef NRFX_TWIM_DEFAULT_CONFIG_IRQ_PRIORITY +#define NRFX_TWIM_DEFAULT_CONFIG_IRQ_PRIORITY 0 +#endif + +/** + * @brief NRFX_TWIM_CONFIG_LOG_ENABLED + * + * Boolean. Accepted values 0 and 1. + */ +#ifndef NRFX_TWIM_CONFIG_LOG_ENABLED +#define NRFX_TWIM_CONFIG_LOG_ENABLED 0 +#endif + +/** + * @brief NRFX_TWIM_CONFIG_LOG_LEVEL + * + * Integer value. + * Supported values: + * - Off = 0 + * - Error = 1 + * - Warning = 2 + * - Info = 3 + * - Debug = 4 + */ +#ifndef NRFX_TWIM_CONFIG_LOG_LEVEL +#define NRFX_TWIM_CONFIG_LOG_LEVEL 0 +#endif + +/** + * @brief NRFX_TWIS_ENABLED + * + * Boolean. Accepted values 0 and 1. + */ +#ifndef NRFX_TWIS_ENABLED +#define NRFX_TWIS_ENABLED 0 +#endif + +/** + * @brief NRFX_TWIS00_ENABLED + * + * Boolean. Accepted values 0 and 1. + */ +#ifndef NRFX_TWIS00_ENABLED +#define NRFX_TWIS00_ENABLED 0 +#endif + +/** + * @brief NRFX_TWIS20_ENABLED + * + * Boolean. Accepted values 0 and 1. + */ +#ifndef NRFX_TWIS20_ENABLED +#define NRFX_TWIS20_ENABLED 0 +#endif + +/** + * @brief NRFX_TWIS21_ENABLED + * + * Boolean. Accepted values 0 and 1. + */ +#ifndef NRFX_TWIS21_ENABLED +#define NRFX_TWIS21_ENABLED 0 +#endif + +/** + * @brief NRFX_TWIS22_ENABLED + * + * Boolean. Accepted values 0 and 1. + */ +#ifndef NRFX_TWIS22_ENABLED +#define NRFX_TWIS22_ENABLED 0 +#endif + +/** + * @brief NRFX_TWIS30_ENABLED + * + * Boolean. Accepted values 0 and 1. + */ +#ifndef NRFX_TWIS30_ENABLED +#define NRFX_TWIS30_ENABLED 0 +#endif + +/** + * @brief NRFX_TWIS_ASSUME_INIT_AFTER_RESET_ONLY + * + * Boolean. Accepted values 0 and 1. + */ +#ifndef NRFX_TWIS_ASSUME_INIT_AFTER_RESET_ONLY +#define NRFX_TWIS_ASSUME_INIT_AFTER_RESET_ONLY 0 +#endif + +/** + * @brief NRFX_TWIS_NO_SYNC_MODE + * + * Boolean. Accepted values 0 and 1. + */ +#ifndef NRFX_TWIS_NO_SYNC_MODE +#define NRFX_TWIS_NO_SYNC_MODE 0 +#endif + +/** + * @brief NRFX_TWIS_DEFAULT_CONFIG_IRQ_PRIORITY + * + * Integer value. Minimum: 0 Maximum: 7 + */ +#ifndef NRFX_TWIS_DEFAULT_CONFIG_IRQ_PRIORITY +#define NRFX_TWIS_DEFAULT_CONFIG_IRQ_PRIORITY 0 +#endif + +/** + * @brief NRFX_TWIS_CONFIG_LOG_ENABLED + * + * Boolean. Accepted values 0 and 1. + */ +#ifndef NRFX_TWIS_CONFIG_LOG_ENABLED +#define NRFX_TWIS_CONFIG_LOG_ENABLED 0 +#endif + +/** + * @brief NRFX_TWIS_CONFIG_LOG_LEVEL + * + * Integer value. + * Supported values: + * - Off = 0 + * - Error = 1 + * - Warning = 2 + * - Info = 3 + * - Debug = 4 + */ +#ifndef NRFX_TWIS_CONFIG_LOG_LEVEL +#define NRFX_TWIS_CONFIG_LOG_LEVEL 0 +#endif + +/** + * @brief NRFX_UARTE_ENABLED + * + * Boolean. Accepted values 0 and 1. + */ +#ifndef NRFX_UARTE_ENABLED +#define NRFX_UARTE_ENABLED 0 +#endif + +/** + * @brief NRFX_UARTE00_ENABLED + * + * Boolean. Accepted values 0 and 1. + */ +#ifndef NRFX_UARTE00_ENABLED +#define NRFX_UARTE00_ENABLED 0 +#endif + +/** + * @brief NRFX_UARTE20_ENABLED + * + * Boolean. Accepted values 0 and 1. + */ +#ifndef NRFX_UARTE20_ENABLED +#define NRFX_UARTE20_ENABLED 0 +#endif + +/** + * @brief NRFX_UARTE21_ENABLED + * + * Boolean. Accepted values 0 and 1. + */ +#ifndef NRFX_UARTE21_ENABLED +#define NRFX_UARTE21_ENABLED 0 +#endif + +/** + * @brief NRFX_UARTE22_ENABLED + * + * Boolean. Accepted values 0 and 1. + */ +#ifndef NRFX_UARTE22_ENABLED +#define NRFX_UARTE22_ENABLED 0 +#endif + +/** + * @brief NRFX_UARTE30_ENABLED + * + * Boolean. Accepted values 0 and 1. + */ +#ifndef NRFX_UARTE30_ENABLED +#define NRFX_UARTE30_ENABLED 0 +#endif + +/** + * @brief NRFX_UARTE_DEFAULT_CONFIG_IRQ_PRIORITY + * + * Integer value. Minimum: 0 Maximum: 7 + */ +#ifndef NRFX_UARTE_DEFAULT_CONFIG_IRQ_PRIORITY +#define NRFX_UARTE_DEFAULT_CONFIG_IRQ_PRIORITY 0 +#endif + +/** + * @brief NRFX_UARTE_CONFIG_LOG_ENABLED + * + * Boolean. Accepted values 0 and 1. + */ +#ifndef NRFX_UARTE_CONFIG_LOG_ENABLED +#define NRFX_UARTE_CONFIG_LOG_ENABLED 0 +#endif + +/** + * @brief NRFX_UARTE_CONFIG_LOG_LEVEL + * + * Integer value. + * Supported values: + * - Off = 0 + * - Error = 1 + * - Warning = 2 + * - Info = 3 + * - Debug = 4 + */ +#ifndef NRFX_UARTE_CONFIG_LOG_LEVEL +#define NRFX_UARTE_CONFIG_LOG_LEVEL 0 +#endif + +/** + * @brief NRFX_WDT_ENABLED + * + * Boolean. Accepted values 0 and 1. + */ +#ifndef NRFX_WDT_ENABLED +#define NRFX_WDT_ENABLED 0 +#endif + +/** + * @brief NRFX_WDT30_ENABLED + * + * Boolean. Accepted values 0 and 1. + */ +#ifndef NRFX_WDT30_ENABLED +#define NRFX_WDT30_ENABLED 0 +#endif + +/** + * @brief NRFX_WDT31_ENABLED + * + * Boolean. Accepted values 0 and 1. + */ +#ifndef NRFX_WDT31_ENABLED +#define NRFX_WDT31_ENABLED 0 +#endif + +/** + * @brief NRFX_WDT_CONFIG_NO_IRQ + * + * Boolean. Accepted values 0 and 1. + */ +#ifndef NRFX_WDT_CONFIG_NO_IRQ +#define NRFX_WDT_CONFIG_NO_IRQ 0 +#endif + +/** + * @brief NRFX_WDT_DEFAULT_CONFIG_IRQ_PRIORITY + * + * Integer value. Minimum: 0 Maximum: 7 + */ +#ifndef NRFX_WDT_DEFAULT_CONFIG_IRQ_PRIORITY +#define NRFX_WDT_DEFAULT_CONFIG_IRQ_PRIORITY 0 +#endif + +/** + * @brief NRFX_WDT_CONFIG_LOG_ENABLED + * + * Boolean. Accepted values 0 and 1. + */ +#ifndef NRFX_WDT_CONFIG_LOG_ENABLED +#define NRFX_WDT_CONFIG_LOG_ENABLED 0 +#endif + +/** + * @brief NRFX_WDT_CONFIG_LOG_LEVEL + * + * Integer value. + * Supported values: + * - Off = 0 + * - Error = 1 + * - Warning = 2 + * - Info = 3 + * - Debug = 4 + */ +#ifndef NRFX_WDT_CONFIG_LOG_LEVEL +#define NRFX_WDT_CONFIG_LOG_LEVEL 0 +#endif + +#endif /* NRFX_CONFIG_NRF54L15_APPLICATION_H__ */ From 4a095bfb356c8d67c7ce828b8d7176ce63e747ad Mon Sep 17 00:00:00 2001 From: Witold Lukasik Date: Mon, 11 Dec 2023 17:43:27 +0100 Subject: [PATCH 3131/3723] boards: arm: add Nordic nrf54l15dk_nrf54l15 Add board files for nRF54L15 DK. Signed-off-by: Witold Lukasik --- boards/arm/nrf54l15pdk_nrf54l15/Kconfig.board | 6 + .../nrf54l15pdk_nrf54l15/Kconfig.defconfig | 12 ++ boards/arm/nrf54l15pdk_nrf54l15/board.cmake | 4 + .../doc/img/nrf54l15pdk_nrf54l15.webp | Bin 0 -> 35746 bytes boards/arm/nrf54l15pdk_nrf54l15/doc/index.rst | 134 ++++++++++++++++ .../nrf54l15pdk_nrf54l15_cpuapp-pinctrl.dtsi | 36 +++++ .../nrf54l15pdk_nrf54l15_cpuapp.dts | 149 ++++++++++++++++++ .../nrf54l15pdk_nrf54l15_cpuapp.yaml | 19 +++ .../nrf54l15pdk_nrf54l15_cpuapp_defconfig | 32 ++++ .../arm/nrf54l15pdk_nrf54l15/revision.cmake | 9 ++ 10 files changed, 401 insertions(+) create mode 100644 boards/arm/nrf54l15pdk_nrf54l15/Kconfig.board create mode 100644 boards/arm/nrf54l15pdk_nrf54l15/Kconfig.defconfig create mode 100644 boards/arm/nrf54l15pdk_nrf54l15/board.cmake create mode 100644 boards/arm/nrf54l15pdk_nrf54l15/doc/img/nrf54l15pdk_nrf54l15.webp create mode 100644 boards/arm/nrf54l15pdk_nrf54l15/doc/index.rst create mode 100644 boards/arm/nrf54l15pdk_nrf54l15/nrf54l15pdk_nrf54l15_cpuapp-pinctrl.dtsi create mode 100644 boards/arm/nrf54l15pdk_nrf54l15/nrf54l15pdk_nrf54l15_cpuapp.dts create mode 100644 boards/arm/nrf54l15pdk_nrf54l15/nrf54l15pdk_nrf54l15_cpuapp.yaml create mode 100644 boards/arm/nrf54l15pdk_nrf54l15/nrf54l15pdk_nrf54l15_cpuapp_defconfig create mode 100644 boards/arm/nrf54l15pdk_nrf54l15/revision.cmake diff --git a/boards/arm/nrf54l15pdk_nrf54l15/Kconfig.board b/boards/arm/nrf54l15pdk_nrf54l15/Kconfig.board new file mode 100644 index 00000000000..d95fe51009f --- /dev/null +++ b/boards/arm/nrf54l15pdk_nrf54l15/Kconfig.board @@ -0,0 +1,6 @@ +# Copyright (c) 2024 Nordic Semiconductor ASA +# SPDX-License-Identifier: Apache-2.0 + +config BOARD_NRF54L15PDK_NRF54L15_CPUAPP + bool "nRF54L15 PDK nRF54L15 Application MCU" + depends on SOC_NRF54L15_ENGA_CPUAPP diff --git a/boards/arm/nrf54l15pdk_nrf54l15/Kconfig.defconfig b/boards/arm/nrf54l15pdk_nrf54l15/Kconfig.defconfig new file mode 100644 index 00000000000..532ea07c859 --- /dev/null +++ b/boards/arm/nrf54l15pdk_nrf54l15/Kconfig.defconfig @@ -0,0 +1,12 @@ +# Copyright (c) 2024 Nordic Semiconductor ASA +# SPDX-License-Identifier: Apache-2.0 + +if BOARD_NRF54L15PDK_NRF54L15_CPUAPP + +config BOARD + default "nrf54l15pdk_nrf54l15_cpuapp" + +config BT_CTLR + default BT + +endif # BOARD_NRF54L15PDK_NRF54L15_CPUAPP diff --git a/boards/arm/nrf54l15pdk_nrf54l15/board.cmake b/boards/arm/nrf54l15pdk_nrf54l15/board.cmake new file mode 100644 index 00000000000..378b7bcdb57 --- /dev/null +++ b/boards/arm/nrf54l15pdk_nrf54l15/board.cmake @@ -0,0 +1,4 @@ +# Copyright (c) 2024 Nordic Semiconductor ASA +# SPDX-License-Identifier: Apache-2.0 + +include(${ZEPHYR_BASE}/boards/common/nrfjprog.board.cmake) diff --git a/boards/arm/nrf54l15pdk_nrf54l15/doc/img/nrf54l15pdk_nrf54l15.webp b/boards/arm/nrf54l15pdk_nrf54l15/doc/img/nrf54l15pdk_nrf54l15.webp new file mode 100644 index 0000000000000000000000000000000000000000..80fb2060a0772776c3ba1a4e092ba7c28f13bbd7 GIT binary patch literal 35746 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 c0000000000000000000000000000000Kr;4x&QzG literal 0 HcmV?d00001 diff --git a/boards/arm/nrf54l15pdk_nrf54l15/doc/index.rst b/boards/arm/nrf54l15pdk_nrf54l15/doc/index.rst new file mode 100644 index 00000000000..fa896f98398 --- /dev/null +++ b/boards/arm/nrf54l15pdk_nrf54l15/doc/index.rst @@ -0,0 +1,134 @@ +.. _nrf54l15pdk_nrf54l15: + +nRF54L15 PDK +############ + +Overview +******** + +The nRF54L15 Preview Development Kit hardware provides +support for the Nordic Semiconductor nRF54L15 Arm Cortex-M33 CPU and +the following devices: + +* :abbr:`SAADC (Successive Approximation Analog to Digital Converter)` +* CLOCK +* RRAM +* :abbr:`GPIO (General Purpose Input Output)` +* :abbr:`TWIM (I2C-compatible two-wire interface master with EasyDMA)` +* :abbr:`MPU (Memory Protection Unit)` +* :abbr:`NVIC (Nested Vectored Interrupt Controller)` +* :abbr:`PWM (Pulse Width Modulation)` +* :abbr:`GRTC (Global real-time counter)` +* Segger RTT (RTT Console) +* :abbr:`SPI (Serial Peripheral Interface)` +* :abbr:`UARTE (Universal asynchronous receiver-transmitter)` +* :abbr:`WDT (Watchdog Timer)` + +.. figure:: img/nrf54l15pdk_nrf54l15.webp + :align: center + :alt: nRF54L15 PDK + + nRF54L15 PDK (Credit: Nordic Semiconductor) + +Hardware +******** + +nRF54L15 PDK has two crystal oscillators: + +* High-frequency 32 MHz crystal oscillator (HFXO) +* Low-frequency 32.768 kHz crystal oscillator (LFXO) + +The crystal oscillators can be configured to use either +internal or external capacitors. + +Supported Features +================== + +The nrf54l15pdk_nrf54l15 board configuration supports the following +hardware features: + ++-----------+------------+----------------------+ +| Interface | Controller | Driver/Component | ++===========+============+======================+ +| SAADC | on-chip | adc | ++-----------+------------+----------------------+ +| CLOCK | on-chip | clock_control | ++-----------+------------+----------------------+ +| RRAM | on-chip | flash | ++-----------+------------+----------------------+ +| GPIO | on-chip | gpio | ++-----------+------------+----------------------+ +| TWIM | on-chip | i2c | ++-----------+------------+----------------------+ +| MPU | on-chip | arch/arm | ++-----------+------------+----------------------+ +| NVIC | on-chip | arch/arm | ++-----------+------------+----------------------+ +| PWM | on-chip | pwm | ++-----------+------------+----------------------+ +| GRTC | on-chip | counter | ++-----------+------------+----------------------+ +| RTT | Segger | console | ++-----------+------------+----------------------+ +| SPI(M/S) | on-chip | spi | ++-----------+------------+----------------------+ +| SPU | on-chip | system protection | ++-----------+------------+----------------------+ +| UARTE | on-chip | serial | ++-----------+------------+----------------------+ +| WDT | on-chip | watchdog | ++-----------+------------+----------------------+ + +Other hardware features have not been enabled yet for this board. + +Programming and Debugging +************************* + +Applications for the ``nrf54l15pdk_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. + +Flashing +======== + +As an example, this section shows how to build and flash the :ref:`hello_world` +application. + +.. warning:: + + When programming the device, you might get an error similar to the following message:: + + ERROR: The operation attempted is unavailable due to readback protection in + ERROR: your device. Please use --recover to unlock the device. + + This error occurs when readback protection is enabled. + To disable the readback protection, you must *recover* your device. + + Enter the following command to recover the core:: + + west flash --recover + + The ``--recover`` command erases the flash memory and then writes a small binary into + the recovered flash memory. + This binary prevents the readback protection from enabling itself again after a pin + reset or power cycle. + +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 nRF54L15 PDK, complete the following steps: + +First, connect the nRF54L15 PDK to you computer using the IMCU USB port on the PDK. +Next, build the sample by running the following command: + +.. zephyr-app-commands:: + :zephyr-app: samples/hello_world + :board: nrf54l15pdk_nrf54l15_cpuapp + :goals: build flash + +Testing the LEDs and buttons in the nRF54L15 PDK +************************************************ + +Test the nRF54L15 PDK with a :zephyr:code-sample:`blinky` sample. diff --git a/boards/arm/nrf54l15pdk_nrf54l15/nrf54l15pdk_nrf54l15_cpuapp-pinctrl.dtsi b/boards/arm/nrf54l15pdk_nrf54l15/nrf54l15pdk_nrf54l15_cpuapp-pinctrl.dtsi new file mode 100644 index 00000000000..02b02bc8171 --- /dev/null +++ b/boards/arm/nrf54l15pdk_nrf54l15/nrf54l15pdk_nrf54l15_cpuapp-pinctrl.dtsi @@ -0,0 +1,36 @@ +/* + * Copyright (c) 2024 Nordic Semiconductor + * SPDX-License-Identifier: Apache-2.0 + */ + +&pinctrl { + uart20_default: uart20_default { + group1 { + psels = , + ; + }; + }; + + uart20_sleep: uart20_sleep { + group1 { + psels = , + ; + low-power-enable; + }; + }; + + uart30_default: uart30_default { + group1 { + psels = , + ; + }; + }; + + uart30_sleep: uart30_sleep { + group1 { + psels = , + ; + low-power-enable; + }; + }; +}; diff --git a/boards/arm/nrf54l15pdk_nrf54l15/nrf54l15pdk_nrf54l15_cpuapp.dts b/boards/arm/nrf54l15pdk_nrf54l15/nrf54l15pdk_nrf54l15_cpuapp.dts new file mode 100644 index 00000000000..1e0245f6cc3 --- /dev/null +++ b/boards/arm/nrf54l15pdk_nrf54l15/nrf54l15pdk_nrf54l15_cpuapp.dts @@ -0,0 +1,149 @@ +/* + * Copyright (c) 2024 Nordic Semiconductor ASA + * + * SPDX-License-Identifier: Apache-2.0 + */ + +/dts-v1/; +#include +#include "nrf54l15pdk_nrf54l15_cpuapp-pinctrl.dtsi" +#include + +/ { + model = "Nordic nRF54L15 PDK nRF54L15 Application MCU"; + compatible = "nordic,nrf54l15pdk_nrf54l15-cpuapp"; + + chosen { + zephyr,console = &uart20; + zephyr,shell-uart = &uart20; + zephyr,sram = &sram0; + zephyr,flash = &rram0; + zephyr,code-partition = &slot0_partition; + zephyr,ieee802154 = &ieee802154; + }; + + leds { + compatible = "gpio-leds"; + led0: led_0 { + gpios = <&gpio0 4 GPIO_ACTIVE_HIGH>; + label = "Green LED 0"; + }; + led1: led_1 { + gpios = <&gpio1 8 GPIO_ACTIVE_HIGH>; + label = "Green LED 1"; + }; + led2: led_2 { + gpios = <&gpio1 13 GPIO_ACTIVE_HIGH>; + label = "Green LED 2"; + }; + led3: led_3 { + gpios = <&gpio1 14 GPIO_ACTIVE_HIGH>; + label = "Green LED 3"; + }; + }; + + buttons { + compatible = "gpio-keys"; + button0: button_0 { + gpios = <&gpio1 9 (GPIO_PULL_UP | GPIO_ACTIVE_LOW)>; + label = "Push button 0"; + zephyr,code = ; + }; + button1: button_1 { + gpios = <&gpio1 10 (GPIO_PULL_UP | GPIO_ACTIVE_LOW)>; + label = "Push button 1"; + zephyr,code = ; + }; + button2: button_2 { + gpios = <&gpio2 9 (GPIO_PULL_UP | GPIO_ACTIVE_LOW)>; + label = "Push button 2"; + zephyr,code = ; + }; + button3: button_3 { + gpios = <&gpio2 10 (GPIO_PULL_UP | GPIO_ACTIVE_LOW)>; + label = "Push button 3"; + zephyr,code = ; + }; + }; + + aliases { + led0 = &led0; + led1 = &led1; + led2 = &led2; + led3 = &led3; + watchdog0 = &wdt30; + sw0 = &button0; + sw1 = &button1; + sw2 = &button2; + sw3 = &button3; + }; +}; + +&lfxo { + load-capacitors = "internal"; + load-capacitance-femtofarad = <15500>; +}; + +&hfxo { + load-capacitors = "internal"; + load-capacitance-femtofarad = <15000>; +}; + +&uart20 { + status = "okay"; + current-speed = <115200>; + pinctrl-0 = <&uart20_default>; + pinctrl-1 = <&uart20_sleep>; + pinctrl-names = "default", "sleep"; +}; + +&uart30 { + current-speed = <115200>; + pinctrl-0 = <&uart30_default>; + pinctrl-1 = <&uart30_sleep>; + pinctrl-names = "default", "sleep"; +}; + +&grtc { + status = "okay"; +}; + +&gpio0 { + status = "okay"; +}; + +&gpio1 { + status = "okay"; +}; + +&gpio2 { + status = "okay"; +}; + +&gpiote20 { + status = "okay"; +}; + +&gpiote30 { + status = "okay"; +}; + +&rram0 { + partitions { + compatible = "fixed-partitions"; + #address-cells = <1>; + #size-cells = <1>; + slot0_partition: partition@0 { + label = "image-0"; + reg = <0x0 DT_SIZE_K(64)>; + }; + storage_partition: partition@f2000 { + label = "storage"; + reg = <0xf2000 DT_SIZE_K(24)>; + }; + }; +}; + +&clock { + status = "okay"; +}; diff --git a/boards/arm/nrf54l15pdk_nrf54l15/nrf54l15pdk_nrf54l15_cpuapp.yaml b/boards/arm/nrf54l15pdk_nrf54l15/nrf54l15pdk_nrf54l15_cpuapp.yaml new file mode 100644 index 00000000000..de5ce29d162 --- /dev/null +++ b/boards/arm/nrf54l15pdk_nrf54l15/nrf54l15pdk_nrf54l15_cpuapp.yaml @@ -0,0 +1,19 @@ +# Copyright (c) 2024 Nordic Semiconductor ASA +# SPDX-License-Identifier: Apache-2.0 + +identifier: nrf54l15pdk_nrf54l15_cpuapp +name: nRF54l15-PDK-nRF54l15-Application +type: mcu +arch: arm +toolchain: + - gnuarmemb + - xtools + - zephyr +ram: 256 +flash: 1536 +supported: + - gpio + - i2c + - spi + - watchdog + - i2s diff --git a/boards/arm/nrf54l15pdk_nrf54l15/nrf54l15pdk_nrf54l15_cpuapp_defconfig b/boards/arm/nrf54l15pdk_nrf54l15/nrf54l15pdk_nrf54l15_cpuapp_defconfig new file mode 100644 index 00000000000..bc74c3eeb33 --- /dev/null +++ b/boards/arm/nrf54l15pdk_nrf54l15/nrf54l15pdk_nrf54l15_cpuapp_defconfig @@ -0,0 +1,32 @@ +# Copyright (c) 2024 Nordic Semiconductor ASA +# SPDX-License-Identifier: Apache-2.0 + +CONFIG_SOC_SERIES_NRF54LX=y +CONFIG_SOC_NRF54L15_ENGA_CPUAPP=y +CONFIG_BOARD_NRF54L15PDK_NRF54L15_CPUAPP=y + +# Enable MPU +CONFIG_ARM_MPU=y + +# Enable hardware stack protection +CONFIG_HW_STACK_PROTECTION=y + +# MPU-based null-pointer dereferencing detection cannot +# be applied as the (0x0 - 0x400) is unmapped for this target. +CONFIG_NULL_POINTER_EXCEPTION_DETECTION_NONE=y + +# Enable Cache +CONFIG_CACHE_MANAGEMENT=y +CONFIG_EXTERNAL_CACHE=y + +CONFIG_UART_CONSOLE=y +CONFIG_CONSOLE=y +CONFIG_SERIAL=y + +# Enable GPIO +CONFIG_GPIO=y + +CONFIG_SOC_NRF_FORCE_CONSTLAT=y + +# Start SYSCOUNTER on driver init +CONFIG_NRF_GRTC_START_SYSCOUNTER=y diff --git a/boards/arm/nrf54l15pdk_nrf54l15/revision.cmake b/boards/arm/nrf54l15pdk_nrf54l15/revision.cmake new file mode 100644 index 00000000000..4fe5b260db3 --- /dev/null +++ b/boards/arm/nrf54l15pdk_nrf54l15/revision.cmake @@ -0,0 +1,9 @@ +# +# Copyright (c) 2024 Nordic Semiconductor ASA +# +# SPDX-License-Identifier: Apache-2.0 +# + +board_check_revision(FORMAT MAJOR.MINOR.PATCH + VALID_REVISIONS 0.2.0 + DEFAULT_REVISION 0.2.0) From 6d3009ff2bf80a8e76f1ab928a65b14621f05bb3 Mon Sep 17 00:00:00 2001 From: Witold Lukasik Date: Mon, 11 Dec 2023 15:01:50 +0100 Subject: [PATCH 3132/3723] drivers: cache: add Nordic cache driver Add Nordic driver for cache. Signed-off-by: Witold Lukasik --- drivers/cache/CMakeLists.txt | 1 + drivers/cache/Kconfig | 1 + drivers/cache/Kconfig.nrf | 9 + drivers/cache/cache_nrf.c | 390 +++++++++++++++++++++++++++++++++++ 4 files changed, 401 insertions(+) create mode 100644 drivers/cache/Kconfig.nrf create mode 100644 drivers/cache/cache_nrf.c diff --git a/drivers/cache/CMakeLists.txt b/drivers/cache/CMakeLists.txt index 47c790f0a89..23cb11afb6a 100644 --- a/drivers/cache/CMakeLists.txt +++ b/drivers/cache/CMakeLists.txt @@ -7,3 +7,4 @@ zephyr_library_property(ALLOW_EMPTY TRUE) zephyr_library_sources_ifdef(CONFIG_CACHE_ASPEED cache_aspeed.c) zephyr_library_sources_ifdef(CONFIG_USERSPACE cache_handlers.c) +zephyr_library_sources_ifdef(CONFIG_CACHE_NRF_CACHE cache_nrf.c) diff --git a/drivers/cache/Kconfig b/drivers/cache/Kconfig index 834cc49e181..4dcb64f488a 100644 --- a/drivers/cache/Kconfig +++ b/drivers/cache/Kconfig @@ -19,5 +19,6 @@ source "subsys/logging/Kconfig.template.log_config" comment "Device Drivers" source "drivers/cache/Kconfig.aspeed" +source "drivers/cache/Kconfig.nrf" endif # CACHE diff --git a/drivers/cache/Kconfig.nrf b/drivers/cache/Kconfig.nrf new file mode 100644 index 00000000000..820445db432 --- /dev/null +++ b/drivers/cache/Kconfig.nrf @@ -0,0 +1,9 @@ +# Copyright (c) 2024 Carlo Caione +# SPDX-License-Identifier: Apache-2.0 + +config CACHE_NRF_CACHE + bool "nRF cache driver" + select CACHE_HAS_DRIVER + depends on HAS_NRFX && CACHE_MANAGEMENT + help + Enable support for the nRF cache driver. diff --git a/drivers/cache/cache_nrf.c b/drivers/cache/cache_nrf.c new file mode 100644 index 00000000000..63d76a47d6e --- /dev/null +++ b/drivers/cache/cache_nrf.c @@ -0,0 +1,390 @@ +/* + * Copyright (c) 2024 Nordic Semiconductor ASA + * + * SPDX-License-Identifier: Apache-2.0 + */ +#include +#include +#include +#include + +LOG_MODULE_REGISTER(cache_nrfx, CONFIG_CACHE_LOG_LEVEL); + +#if !defined(NRF_ICACHE) && defined(NRF_CACHE) +#define NRF_ICACHE NRF_CACHE +#endif + +#define CACHE_LINE_SIZE 32 +#define CACHE_BUSY_RETRY_INTERVAL_US 10 + +static struct k_spinlock lock; + +enum k_nrf_cache_op { + /* + * Sequentially loop through all dirty lines and write those data units to + * memory. + * + * This is FLUSH in Zephyr nomenclature. + */ + K_NRF_CACHE_CLEAN, + + /* + * Mark all lines as invalid, ignoring any dirty data. + * + * This is INVALIDATE in Zephyr nomenclature. + */ + K_NRF_CACHE_INVD, + + /* + * Clean followed by invalidate + * + * This is FLUSH_AND_INVALIDATE in Zephyr nomenclature. + */ + K_NRF_CACHE_FLUSH, +}; + +static inline bool is_cache_busy(NRF_CACHE_Type *cache) +{ +#if NRF_CACHE_HAS_STATUS + return nrf_cache_busy_check(cache); +#else + return false; +#endif +} + +static inline void wait_for_cache(NRF_CACHE_Type *cache) +{ + while (is_cache_busy(cache)) { + k_busy_wait(CACHE_BUSY_RETRY_INTERVAL_US); + } +} + +static inline int _cache_all(NRF_CACHE_Type *cache, enum k_nrf_cache_op op) +{ + /* + * We really do not want to invalidate the whole cache. + */ + if (op == K_NRF_CACHE_INVD) { + return -ENOTSUP; + } + + k_spinlock_key_t key = k_spin_lock(&lock); + + /* + * Invalidating the whole cache is dangerous. For good measure + * disable the cache. + */ + nrf_cache_disable(cache); + + wait_for_cache(cache); + + switch (op) { + +#if NRF_CACHE_HAS_TASK_CLEAN + case K_NRF_CACHE_CLEAN: + nrf_cache_task_trigger(cache, NRF_CACHE_TASK_CLEANCACHE); + break; +#endif + + case K_NRF_CACHE_INVD: + nrf_cache_task_trigger(cache, NRF_CACHE_TASK_INVALIDATECACHE); + break; + +#if NRF_CACHE_HAS_TASK_FLUSH + case K_NRF_CACHE_FLUSH: + nrf_cache_task_trigger(cache, NRF_CACHE_TASK_FLUSHCACHE); + break; +#endif + + default: + break; + } + + wait_for_cache(cache); + + nrf_cache_enable(cache); + + k_spin_unlock(&lock, key); + + return 0; +} + +static inline void _cache_line(NRF_CACHE_Type *cache, enum k_nrf_cache_op op, uintptr_t line_addr) +{ + wait_for_cache(cache); + + nrf_cache_lineaddr_set(cache, line_addr); + + switch (op) { + +#if NRF_CACHE_HAS_TASK_CLEAN + case K_NRF_CACHE_CLEAN: + nrf_cache_task_trigger(cache, NRF_CACHE_TASK_CLEANLINE); + break; +#endif + + case K_NRF_CACHE_INVD: + nrf_cache_task_trigger(cache, NRF_CACHE_TASK_INVALIDATELINE); + break; + +#if NRF_CACHE_HAS_TASK_FLUSH + case K_NRF_CACHE_FLUSH: + nrf_cache_task_trigger(cache, NRF_CACHE_TASK_FLUSHLINE); + break; +#endif + + default: + break; + } + + wait_for_cache(cache); +} + +static inline int _cache_range(NRF_CACHE_Type *cache, enum k_nrf_cache_op op, void *addr, + size_t size) +{ + uintptr_t line_addr = (uintptr_t)addr; + uintptr_t end_addr = line_addr + size; + + /* + * Align address to line size + */ + line_addr &= ~(CACHE_LINE_SIZE - 1); + + do { + k_spinlock_key_t key = k_spin_lock(&lock); + + _cache_line(cache, op, line_addr); + + k_spin_unlock(&lock, key); + + line_addr += CACHE_LINE_SIZE; + + } while (line_addr < end_addr); + + return 0; +} + +static inline int _cache_checks(NRF_CACHE_Type *cache, enum k_nrf_cache_op op, void *addr, + size_t size, bool is_range) +{ + /* Check if the cache is enabled */ + if (!(cache->ENABLE & CACHE_ENABLE_ENABLE_Enabled)) { + return -EAGAIN; + } + + if (!is_range) { + return _cache_all(cache, op); + } + + /* Check for invalid address or size */ + if ((!addr) || (!size)) { + return -EINVAL; + } + + return _cache_range(cache, op, addr, size); +} + +#if defined(NRF_DCACHE) && NRF_CACHE_HAS_TASKS + +void cache_data_enable(void) +{ + nrf_cache_enable(NRF_DCACHE); +} + +void cache_data_disable(void) +{ + nrf_cache_disable(NRF_DCACHE); +} + +int cache_data_flush_all(void) +{ +#if NRF_CACHE_HAS_TASK_CLEAN + return _cache_checks(NRF_DCACHE, K_NRF_CACHE_CLEAN, NULL, 0, false); +#else + return -ENOTSUP; +#endif +} + +int cache_data_invd_all(void) +{ + return _cache_checks(NRF_DCACHE, K_NRF_CACHE_INVD, NULL, 0, false); +} + +int cache_data_flush_and_invd_all(void) +{ +#if NRF_CACHE_HAS_TASK_FLUSH + return _cache_checks(NRF_DCACHE, K_NRF_CACHE_FLUSH, NULL, 0, false); +#else + return -ENOTSUP; +#endif +} + +int cache_data_flush_range(void *addr, size_t size) +{ +#if NRF_CACHE_HAS_TASK_CLEAN + return _cache_checks(NRF_DCACHE, K_NRF_CACHE_CLEAN, addr, size, true); +#else + return -ENOTSUP; +#endif +} + +int cache_data_invd_range(void *addr, size_t size) +{ + return _cache_checks(NRF_DCACHE, K_NRF_CACHE_INVD, addr, size, true); +} + +int cache_data_flush_and_invd_range(void *addr, size_t size) +{ +#if NRF_CACHE_HAS_TASK_FLUSH + return _cache_checks(NRF_DCACHE, K_NRF_CACHE_FLUSH, addr, size, true); +#else + return -ENOTSUP; +#endif +} + +#else + +void cache_data_enable(void) +{ + /* Nothing */ +} + +void cache_data_disable(void) +{ + /* Nothing */ +} + +int cache_data_flush_all(void) +{ + return -ENOTSUP; +} + +int cache_data_invd_all(void) +{ + return -ENOTSUP; +} + +int cache_data_flush_and_invd_all(void) +{ + return -ENOTSUP; +} + +int cache_data_flush_range(void *addr, size_t size) +{ + return -ENOTSUP; +} + +int cache_data_invd_range(void *addr, size_t size) +{ + return -ENOTSUP; +} + +int cache_data_flush_and_invd_range(void *addr, size_t size) +{ + return -ENOTSUP; +} + +#endif /* NRF_DCACHE */ + +#if defined(NRF_ICACHE) && NRF_CACHE_HAS_TASKS + +void cache_instr_enable(void) +{ + nrf_cache_enable(NRF_ICACHE); +} + +void cache_instr_disable(void) +{ + nrf_cache_disable(NRF_ICACHE); +} + +int cache_instr_flush_all(void) +{ +#if NRF_CACHE_HAS_TASK_CLEAN + return _cache_checks(NRF_ICACHE, K_NRF_CACHE_CLEAN, NULL, 0, false); +#else + return -ENOTSUP; +#endif +} + +int cache_instr_invd_all(void) +{ + return _cache_checks(NRF_ICACHE, K_NRF_CACHE_INVD, NULL, 0, false); +} + +int cache_instr_flush_and_invd_all(void) +{ +#if NRF_CACHE_HAS_TASK_FLUSH + return _cache_checks(NRF_ICACHE, K_NRF_CACHE_FLUSH, NULL, 0, false); +#else + return -ENOTSUP; +#endif +} + +int cache_instr_flush_range(void *addr, size_t size) +{ +#if NRF_CACHE_HAS_TASK_CLEAN + return _cache_checks(NRF_ICACHE, K_NRF_CACHE_CLEAN, addr, size, true); +#else + return -ENOTSUP; +#endif +} + +int cache_instr_invd_range(void *addr, size_t size) +{ + return _cache_checks(NRF_ICACHE, K_NRF_CACHE_INVD, addr, size, true); +} + +int cache_instr_flush_and_invd_range(void *addr, size_t size) +{ +#if NRF_CACHE_HAS_TASK_FLUSH + return _cache_checks(NRF_ICACHE, K_NRF_CACHE_FLUSH, addr, size, true); +#else + return -ENOTSUP; +#endif +} + +#else + +void cache_instr_enable(void) +{ + /* Nothing */ +} + +void cache_instr_disable(void) +{ + /* Nothing */ +} + +int cache_instr_flush_all(void) +{ + return -ENOTSUP; +} + +int cache_instr_invd_all(void) +{ + return -ENOTSUP; +} + +int cache_instr_flush_and_invd_all(void) +{ + return -ENOTSUP; +} + +int cache_instr_flush_range(void *addr, size_t size) +{ + return -ENOTSUP; +} + +int cache_instr_invd_range(void *addr, size_t size) +{ + return -ENOTSUP; +} + +int cache_instr_flush_and_invd_range(void *addr, size_t size) +{ + return -ENOTSUP; +} + +#endif /* NRF_ICACHE */ From 13abdcccb3f81d1f0299246b298b74b984e8f74a Mon Sep 17 00:00:00 2001 From: Witold Lukasik Date: Mon, 11 Dec 2023 17:44:16 +0100 Subject: [PATCH 3133/3723] scripts: west_commands: runners: nrf_common: add support for nRF54L Add support for new Nordic family in west commands. Signed-off-by: Witold Lukasik --- scripts/west_commands/runners/nrf_common.py | 4 +++- scripts/west_commands/runners/nrfjprog.py | 2 +- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/scripts/west_commands/runners/nrf_common.py b/scripts/west_commands/runners/nrf_common.py index 2ff51d7e85d..788021c6191 100644 --- a/scripts/west_commands/runners/nrf_common.py +++ b/scripts/west_commands/runners/nrf_common.py @@ -59,7 +59,7 @@ def dev_id_help(cls) -> str: @classmethod def do_add_parser(cls, parser): parser.add_argument('--nrf-family', - choices=['NRF51', 'NRF52', 'NRF53', 'NRF91'], + choices=['NRF51', 'NRF52', 'NRF53', 'NRF54L', 'NRF91'], help='''MCU family; still accepted for compatibility only''') parser.add_argument('--softreset', required=False, @@ -161,6 +161,8 @@ def ensure_family(self): self.family = 'NRF52_FAMILY' elif self.build_conf.getboolean('CONFIG_SOC_SERIES_NRF53X'): self.family = 'NRF53_FAMILY' + elif self.build_conf.getboolean('CONFIG_SOC_SERIES_NRF54LX'): + self.family = 'NRF54L_FAMILY' elif self.build_conf.getboolean('CONFIG_SOC_SERIES_NRF91X'): self.family = 'NRF91_FAMILY' else: diff --git a/scripts/west_commands/runners/nrfjprog.py b/scripts/west_commands/runners/nrfjprog.py index 8762ce0e740..a28681ae6a5 100644 --- a/scripts/west_commands/runners/nrfjprog.py +++ b/scripts/west_commands/runners/nrfjprog.py @@ -46,7 +46,7 @@ def do_exec_op(self, op, force=False): # Translate the op families = {'NRF51_FAMILY': 'NRF51', 'NRF52_FAMILY': 'NRF52', - 'NRF53_FAMILY': 'NRF53', 'NRF91_FAMILY': 'NRF91'} + 'NRF53_FAMILY': 'NRF53', 'NRF54L_FAMILY': 'NRF54L', 'NRF91_FAMILY': 'NRF91'} cores = {'NRFDL_DEVICE_CORE_APPLICATION': 'CP_APPLICATION', 'NRFDL_DEVICE_CORE_NETWORK': 'CP_NETWORK'} From cac2990c04d6ea9c63031c7ef3c4ab830dedcb68 Mon Sep 17 00:00:00 2001 From: Witold Lukasik Date: Tue, 12 Dec 2023 10:39:07 +0100 Subject: [PATCH 3134/3723] tests: arch: arm: arm: align tests to nRF54L15 Changed _ISR_OFFSET to be 28 as specified in OPS. Removed console ISR. Signed-off-by: Witold Lukasik --- .../src/arm_irq_vector_table.c | 120 +++++------------- 1 file changed, 35 insertions(+), 85 deletions(-) diff --git a/tests/arch/arm/arm_irq_vector_table/src/arm_irq_vector_table.c b/tests/arch/arm/arm_irq_vector_table/src/arm_irq_vector_table.c index 7d793066109..f18c30dac9a 100644 --- a/tests/arch/arm/arm_irq_vector_table/src/arm_irq_vector_table.c +++ b/tests/arch/arm/arm_irq_vector_table/src/arm_irq_vector_table.c @@ -16,66 +16,22 @@ */ #define _ISR_OFFSET 0 -#if defined(CONFIG_SOC_SERIES_NRF51X) || defined(CONFIG_SOC_SERIES_NRF52X) -/* The customized solution for nRF51X-based and nRF52X-based - * platforms requires that the POWER_CLOCK_IRQn line equals 0. - */ -BUILD_ASSERT(POWER_CLOCK_IRQn == 0, - "POWER_CLOCK_IRQn != 0. Consider rework manual vector table."); - -/* The customized solution for nRF51X-based and nRF52X-based - * platforms requires that the RTC1 IRQ line equals 17. - */ -BUILD_ASSERT(RTC1_IRQn == 17, - "RTC1_IRQn != 17. Consider rework manual vector table."); - +#if defined(CONFIG_SOC_FAMILY_NRF) #undef _ISR_OFFSET -#if !defined(CONFIG_BOARD_QEMU_CORTEX_M0) -/* Interrupt line 0 is used by POWER_CLOCK */ -#define _ISR_OFFSET 1 +#if defined(CONFIG_BOARD_QEMU_CORTEX_M0) +/* For the nRF51-based QEMU Cortex-M0 platform, the first set of consecutive + * implemented interrupts that can be used by this test starts right after + * the TIMER0 IRQ line, which is used by the system timer. + */ +#define _ISR_OFFSET (TIMER0_IRQn + 1) +#elif defined(CONFIG_SOC_SERIES_NRF54LX) +/* For nRF54L Series, use SWI00-02 interrupt lines. */ +#define _ISR_OFFSET SWI00_IRQn #else -/* The customized solution for nRF51-based QEMU Cortex-M0 platform - * requires that the TIMER0 IRQ line equals 8. - */ -BUILD_ASSERT(TIMER0_IRQn == 8, - "TIMER0_IRQn != 8. Consider rework manual vector table."); -/* Interrupt lines 9-11 is the first set of consecutive interrupts implemented - * in QEMU Cortex M0. - */ -#define _ISR_OFFSET 9 - +/* For other nRF targets, use TIMER0-2 interrupt lines. */ +#define _ISR_OFFSET TIMER0_IRQn #endif - -#elif defined(CONFIG_SOC_SERIES_NRF53X) || defined(CONFIG_SOC_SERIES_NRF91X) -/* The customized solution for nRF91X-based and nRF53X-based - * platforms requires that the POWER_CLOCK_IRQn line equals 5. - */ -BUILD_ASSERT(CLOCK_POWER_IRQn == 5, - "POWER_CLOCK_IRQn != 5." - "Consider rework manual vector table."); - -#if !defined(CONFIG_SOC_NRF5340_CPUNET) -/* The customized solution for nRF91X-based platforms - * requires that the RTC1 IRQ line equals 21. - */ -BUILD_ASSERT(RTC1_IRQn == 21, - "RTC1_IRQn != 21. Consider rework manual vector table."); - -#else /* CONFIG_SOC_NRF5340_CPUNET */ -/* The customized solution for nRF5340_CPUNET - * requires that the RTC1 IRQ line equals 22. - */ -BUILD_ASSERT(RTC1_IRQn == 22, - "RTC1_IRQn != 22. Consider rework manual vector table."); -#endif -#undef _ISR_OFFSET -/* Interrupt lines 8-10 is the first set of consecutive interrupts implemented - * in nRF9160 SOC. - */ -#define _ISR_OFFSET 8 - -#endif /* CONFIG_SOC_SERIES_NRF52X */ - +#endif /* CONFIG_SOC_FAMILY_NRF */ struct k_sem sem[3]; @@ -182,40 +138,34 @@ typedef void (*vth)(void); /* Vector Table Handler */ * * Note: qemu_cortex_m0 uses TIMER0 to implement system timer. */ -void rtc_nrf_isr(void); void nrfx_power_clock_irq_handler(void); #if defined(CONFIG_SOC_SERIES_NRF51X) || defined(CONFIG_SOC_SERIES_NRF52X) +#define POWER_CLOCK_IRQ_NUM POWER_CLOCK_IRQn +#else +#define POWER_CLOCK_IRQ_NUM CLOCK_POWER_IRQn +#endif + #if defined(CONFIG_BOARD_QEMU_CORTEX_M0) void timer0_nrf_isr(void); -vth __irq_vector_table _irq_vector_table[] = { - nrfx_power_clock_irq_handler, 0, 0, 0, 0, 0, 0, 0, - timer0_nrf_isr, isr0, isr1, isr2 -}; -#else -vth __irq_vector_table _irq_vector_table[] = { - nrfx_power_clock_irq_handler, - isr0, isr1, isr2, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - rtc_nrf_isr -}; -#endif /* CONFIG_BOARD_QEMU_CORTEX_M0 */ -#elif defined(CONFIG_SOC_SERIES_NRF53X) || defined(CONFIG_SOC_SERIES_NRF91X) -#ifndef CONFIG_SOC_NRF5340_CPUNET -vth __irq_vector_table _irq_vector_table[] = { - 0, 0, 0, 0, 0, nrfx_power_clock_irq_handler, 0, 0, - isr0, isr1, isr2, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - rtc_nrf_isr -}; +#define TIMER_IRQ_HANDLER timer0_nrf_isr +#define TIMER_IRQ_NUM TIMER0_IRQn +#elif defined(CONFIG_SOC_SERIES_NRF54LX) +void nrfx_grtc_irq_handler(void); +#define TIMER_IRQ_HANDLER nrfx_grtc_irq_handler +#define TIMER_IRQ_NUM GRTC_0_IRQn #else -vth __irq_vector_table _irq_vector_table[] = { - 0, 0, 0, 0, 0, nrfx_power_clock_irq_handler, 0, 0, - isr0, isr1, isr2, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - rtc_nrf_isr -}; -#endif +void rtc_nrf_isr(void); +#define TIMER_IRQ_HANDLER rtc_nrf_isr +#define TIMER_IRQ_NUM RTC1_IRQn #endif + +#define IRQ_VECTOR_TABLE_SIZE (MAX(POWER_CLOCK_IRQ_NUM, MAX(TIMER_IRQ_NUM, _ISR_OFFSET + 2)) + 1) + +vth __irq_vector_table _irq_vector_table[IRQ_VECTOR_TABLE_SIZE] = { + [POWER_CLOCK_IRQ_NUM] = nrfx_power_clock_irq_handler, + [TIMER_IRQ_NUM] = TIMER_IRQ_HANDLER, + [_ISR_OFFSET] = isr0, isr1, isr2, +}; #elif defined(CONFIG_SOC_SERIES_CC13X2_CC26X2) || defined(CONFIG_SOC_SERIES_CC13X2X7_CC26X2X7) /* TI CC13x2/CC26x2 based platforms also employ a Hardware RTC peripheral * to implement the Kernel system timer, instead of the ARM Cortex-M From d8203d2e1f4917447757dfabd92f286ac51021a1 Mon Sep 17 00:00:00 2001 From: Magdalena Pastula Date: Tue, 23 Jan 2024 12:53:53 +0100 Subject: [PATCH 3135/3723] tests: drivers: add overlay files for nRF54L15 Add nRF54L15 overlay files for driver tests that need them. Signed-off-by: Magdalena Pastula --- .../nrf54l15pdk_nrf54l15_cpuapp.overlay | 21 +++++++++ .../nrf54l15pdk_nrf54l15_cpuapp.overlay | 30 ++++++++++++ .../nrf54l15pdk_nrf54l15_cpuapp.overlay | 30 ++++++++++++ .../nrf54l15pdk_nrf54l15_cpuapp.overlay | 46 +++++++++++++++++++ .../nrf54l15pdk_nrf54l15_cpuapp.overlay | 36 +++++++++++++++ .../nrf54l15pdk_nrf54l15_cpuapp.overlay | 43 +++++++++++++++++ .../nrf54l15pdk_nrf54l15_cpuapp.overlay | 36 +++++++++++++++ .../nrf54l15pdk_nrf54l15_cpuapp.overlay | 9 ++++ 8 files changed, 251 insertions(+) create mode 100644 tests/drivers/gpio/gpio_basic_api/boards/nrf54l15pdk_nrf54l15_cpuapp.overlay create mode 100644 tests/drivers/i2s/i2s_api/boards/nrf54l15pdk_nrf54l15_cpuapp.overlay create mode 100644 tests/drivers/i2s/i2s_speed/boards/nrf54l15pdk_nrf54l15_cpuapp.overlay create mode 100644 tests/drivers/spi/spi_loopback/boards/nrf54l15pdk_nrf54l15_cpuapp.overlay create mode 100644 tests/drivers/uart/uart_async_api/boards/nrf54l15pdk_nrf54l15_cpuapp.overlay create mode 100644 tests/drivers/uart/uart_mix_fifo_poll/boards/nrf54l15pdk_nrf54l15_cpuapp.overlay create mode 100644 tests/drivers/uart/uart_pm/boards/nrf54l15pdk_nrf54l15_cpuapp.overlay create mode 100644 tests/drivers/watchdog/wdt_basic_api/boards/nrf54l15pdk_nrf54l15_cpuapp.overlay diff --git a/tests/drivers/gpio/gpio_basic_api/boards/nrf54l15pdk_nrf54l15_cpuapp.overlay b/tests/drivers/gpio/gpio_basic_api/boards/nrf54l15pdk_nrf54l15_cpuapp.overlay new file mode 100644 index 00000000000..97702240047 --- /dev/null +++ b/tests/drivers/gpio/gpio_basic_api/boards/nrf54l15pdk_nrf54l15_cpuapp.overlay @@ -0,0 +1,21 @@ +/* + * Copyright (c) 2024 Nordic Semiconductor ASA + * + * SPDX-License-Identifier: Apache-2.0 + */ + + / { + resources { + compatible = "test-gpio-basic-api"; + out-gpios = <&gpio1 10 0>; + in-gpios = <&gpio1 11 0>; + }; +}; + +&gpiote20 { + status = "okay"; +}; + +&gpio1 { + status = "okay"; +}; diff --git a/tests/drivers/i2s/i2s_api/boards/nrf54l15pdk_nrf54l15_cpuapp.overlay b/tests/drivers/i2s/i2s_api/boards/nrf54l15pdk_nrf54l15_cpuapp.overlay new file mode 100644 index 00000000000..8b82825a0f2 --- /dev/null +++ b/tests/drivers/i2s/i2s_api/boards/nrf54l15pdk_nrf54l15_cpuapp.overlay @@ -0,0 +1,30 @@ +/* + * Copyright (c) 2024 Nordic Semiconductor ASA + * + * SPDX-License-Identifier: Apache-2.0 + */ + +/* i2s-node0 is the transmitter/receiver */ + +/ { + aliases { + i2s-node0 = &i2s20; + }; +}; + +&pinctrl { + i2s20_default_alt: i2s20_default_alt { + group1 { + psels = , + , + , + ; + }; + }; +}; + +&i2s20 { + status = "okay"; + pinctrl-0 = <&i2s20_default_alt>; + pinctrl-names = "default"; +}; diff --git a/tests/drivers/i2s/i2s_speed/boards/nrf54l15pdk_nrf54l15_cpuapp.overlay b/tests/drivers/i2s/i2s_speed/boards/nrf54l15pdk_nrf54l15_cpuapp.overlay new file mode 100644 index 00000000000..8b82825a0f2 --- /dev/null +++ b/tests/drivers/i2s/i2s_speed/boards/nrf54l15pdk_nrf54l15_cpuapp.overlay @@ -0,0 +1,30 @@ +/* + * Copyright (c) 2024 Nordic Semiconductor ASA + * + * SPDX-License-Identifier: Apache-2.0 + */ + +/* i2s-node0 is the transmitter/receiver */ + +/ { + aliases { + i2s-node0 = &i2s20; + }; +}; + +&pinctrl { + i2s20_default_alt: i2s20_default_alt { + group1 { + psels = , + , + , + ; + }; + }; +}; + +&i2s20 { + status = "okay"; + pinctrl-0 = <&i2s20_default_alt>; + pinctrl-names = "default"; +}; diff --git a/tests/drivers/spi/spi_loopback/boards/nrf54l15pdk_nrf54l15_cpuapp.overlay b/tests/drivers/spi/spi_loopback/boards/nrf54l15pdk_nrf54l15_cpuapp.overlay new file mode 100644 index 00000000000..f2e84b72f9b --- /dev/null +++ b/tests/drivers/spi/spi_loopback/boards/nrf54l15pdk_nrf54l15_cpuapp.overlay @@ -0,0 +1,46 @@ +/* + * Copyright (c) 2024 Nordic Semiconductor ASA + * + * SPDX-License-Identifier: Apache-2.0 + */ + +&pinctrl { + spi00_default: spi00_default { + group1 { + psels = , + , + ; + }; + }; + + spi00_sleep: spi00_sleep { + group1 { + psels = , + , + ; + low-power-enable; + }; + }; +}; + +&spi00 { + status = "okay"; + pinctrl-0 = <&spi00_default>; + pinctrl-1 = <&spi00_sleep>; + pinctrl-names = "default", "sleep"; + overrun-character = <0x00>; + slow@0 { + compatible = "test-spi-loopback-slow"; + reg = <0>; + spi-max-frequency = ; + }; + fast@0 { + compatible = "test-spi-loopback-fast"; + reg = <0>; + spi-max-frequency = ; + }; +}; + +&gpio2 { + status = "okay"; +}; diff --git a/tests/drivers/uart/uart_async_api/boards/nrf54l15pdk_nrf54l15_cpuapp.overlay b/tests/drivers/uart/uart_async_api/boards/nrf54l15pdk_nrf54l15_cpuapp.overlay new file mode 100644 index 00000000000..033aab401ac --- /dev/null +++ b/tests/drivers/uart/uart_async_api/boards/nrf54l15pdk_nrf54l15_cpuapp.overlay @@ -0,0 +1,36 @@ +/* + * Copyright (c) 2024 Nordic Semiconductor ASA + * + * SPDX-License-Identifier: Apache-2.0 + */ + +&pinctrl { + uart21_default: uart21_default { + group1 { + psels = , + ; + }; + }; + + uart21_sleep: uart21_sleep { + group1 { + psels = , + ; + low-power-enable; + }; + }; +}; + +/ { + chosen { + zephyr,console = &uart20; + }; +}; + +dut: &uart21 { + status = "okay"; + current-speed = <115200>; + pinctrl-0 = <&uart21_default>; + pinctrl-1 = <&uart21_sleep>; + pinctrl-names = "default", "sleep"; +}; diff --git a/tests/drivers/uart/uart_mix_fifo_poll/boards/nrf54l15pdk_nrf54l15_cpuapp.overlay b/tests/drivers/uart/uart_mix_fifo_poll/boards/nrf54l15pdk_nrf54l15_cpuapp.overlay new file mode 100644 index 00000000000..945b8628e7a --- /dev/null +++ b/tests/drivers/uart/uart_mix_fifo_poll/boards/nrf54l15pdk_nrf54l15_cpuapp.overlay @@ -0,0 +1,43 @@ +/* + * Copyright (c) 2024 Nordic Semiconductor ASA + * + * SPDX-License-Identifier: Apache-2.0 + */ + +&pinctrl { + uart21_default: uart21_default { + group1 { + psels = , + , + , + ; + }; + }; + + uart21_sleep: uart21_sleep { + group1 { + psels = , + , + , + ; + low-power-enable; + }; + }; +}; + +dut: &uart21 { + status = "okay"; + current-speed = <115200>; + pinctrl-0 = <&uart21_default>; + pinctrl-1 = <&uart21_sleep>; + pinctrl-names = "default", "sleep"; + hw-flow-control; +}; + +counter_dev: &timer00 { + status = "okay"; +}; + +&grtc { + interrupts = <228 2>; +}; diff --git a/tests/drivers/uart/uart_pm/boards/nrf54l15pdk_nrf54l15_cpuapp.overlay b/tests/drivers/uart/uart_pm/boards/nrf54l15pdk_nrf54l15_cpuapp.overlay new file mode 100644 index 00000000000..033aab401ac --- /dev/null +++ b/tests/drivers/uart/uart_pm/boards/nrf54l15pdk_nrf54l15_cpuapp.overlay @@ -0,0 +1,36 @@ +/* + * Copyright (c) 2024 Nordic Semiconductor ASA + * + * SPDX-License-Identifier: Apache-2.0 + */ + +&pinctrl { + uart21_default: uart21_default { + group1 { + psels = , + ; + }; + }; + + uart21_sleep: uart21_sleep { + group1 { + psels = , + ; + low-power-enable; + }; + }; +}; + +/ { + chosen { + zephyr,console = &uart20; + }; +}; + +dut: &uart21 { + status = "okay"; + current-speed = <115200>; + pinctrl-0 = <&uart21_default>; + pinctrl-1 = <&uart21_sleep>; + pinctrl-names = "default", "sleep"; +}; diff --git a/tests/drivers/watchdog/wdt_basic_api/boards/nrf54l15pdk_nrf54l15_cpuapp.overlay b/tests/drivers/watchdog/wdt_basic_api/boards/nrf54l15pdk_nrf54l15_cpuapp.overlay new file mode 100644 index 00000000000..aa2789dd45e --- /dev/null +++ b/tests/drivers/watchdog/wdt_basic_api/boards/nrf54l15pdk_nrf54l15_cpuapp.overlay @@ -0,0 +1,9 @@ +/* + * Copyright (c) 2024 Nordic Semiconductor ASA + * + * SPDX-License-Identifier: Apache-2.0 + */ + +&wdt30 { + status = "okay"; +}; From 361a5a11aa2ccb1f997b0de78b21eb6c3d94fb70 Mon Sep 17 00:00:00 2001 From: Magdalena Pastula Date: Tue, 23 Jan 2024 14:42:22 +0100 Subject: [PATCH 3136/3723] samples: add overlay files for nRF54L15 Add nRF54L15 overlays to samples that needed them. Signed-off-by: Magdalena Pastula --- .../nrf54l15pdk_nrf54l15_cpuapp.overlay | 8 ++++ .../nrf54l15pdk_nrf54l15_cpuapp.overlay | 43 +++++++++++++++++++ 2 files changed, 51 insertions(+) create mode 100644 samples/drivers/watchdog/boards/nrf54l15pdk_nrf54l15_cpuapp.overlay create mode 100644 samples/sensor/qdec/boards/nrf54l15pdk_nrf54l15_cpuapp.overlay diff --git a/samples/drivers/watchdog/boards/nrf54l15pdk_nrf54l15_cpuapp.overlay b/samples/drivers/watchdog/boards/nrf54l15pdk_nrf54l15_cpuapp.overlay new file mode 100644 index 00000000000..66157d79fb3 --- /dev/null +++ b/samples/drivers/watchdog/boards/nrf54l15pdk_nrf54l15_cpuapp.overlay @@ -0,0 +1,8 @@ +/* + * Copyright 2024 Nordic Semiconductor ASA + * SPDX-License-Identifier: Apache-2.0 + */ + +&wdt30 { + status = "okay"; +}; diff --git a/samples/sensor/qdec/boards/nrf54l15pdk_nrf54l15_cpuapp.overlay b/samples/sensor/qdec/boards/nrf54l15pdk_nrf54l15_cpuapp.overlay new file mode 100644 index 00000000000..3d872a2071b --- /dev/null +++ b/samples/sensor/qdec/boards/nrf54l15pdk_nrf54l15_cpuapp.overlay @@ -0,0 +1,43 @@ +/* + * Copyright 2024 Nordic Semiconductor ASA + * SPDX-License-Identifier: Apache-2.0 + */ + +/ { + aliases { + qdec0 = &qdec20; + qenca = &phase_a; + qencb = &phase_b; + }; + + encoder-emulate { + compatible = "gpio-leds"; + phase_a: phase_a { + gpios = <&gpio1 9 GPIO_ACTIVE_HIGH>; + }; + phase_b: phase_b { + gpios = <&gpio1 11 GPIO_ACTIVE_HIGH>; + }; + }; +}; + +&pinctrl { + qdec_pinctrl: qdec_pinctrl { + group1 { + psels = , + ; + }; + }; +}; + +&gpio1 { + status = "okay"; +}; + +&qdec20 { + status = "okay"; + pinctrl-0 = <&qdec_pinctrl>; + pinctrl-names = "default"; + steps = <120>; + led-pre = <500>; +}; From 5a32e6e21c2270641ba834e33470ff845afba437 Mon Sep 17 00:00:00 2001 From: Magdalena Pastula Date: Tue, 9 Jan 2024 15:27:01 +0100 Subject: [PATCH 3137/3723] drivers: hwinfo: update to be aligned to nRF54L15 Update hwinfo driver to be aligned to nRF54L15. Signed-off-by: Magdalena Pastula --- drivers/hwinfo/hwinfo_nrf.c | 60 ++++++++++++++++++++++++++++++------- 1 file changed, 49 insertions(+), 11 deletions(-) diff --git a/drivers/hwinfo/hwinfo_nrf.c b/drivers/hwinfo/hwinfo_nrf.c index 2a79f1d0c0d..4375cf05b2f 100644 --- a/drivers/hwinfo/hwinfo_nrf.c +++ b/drivers/hwinfo/hwinfo_nrf.c @@ -58,22 +58,56 @@ int z_impl_hwinfo_get_reset_cause(uint32_t *cause) if (reason & NRFX_RESET_REASON_DIF_MASK) { flags |= RESET_DEBUG; } + if (reason & NRFX_RESET_REASON_SREQ_MASK) { + flags |= RESET_SOFTWARE; + } -#if !NRF_POWER_HAS_RESETREAS +#if NRFX_RESET_REASON_HAS_CTRLAP if (reason & NRFX_RESET_REASON_CTRLAP_MASK) { flags |= RESET_DEBUG; } - if (reason & NRFX_RESET_REASON_DOG0_MASK) { - flags |= RESET_WATCHDOG; +#endif +#if NRFX_RESET_REASON_HAS_LPCOMP + if (reason & NRFX_RESET_REASON_LPCOMP_MASK) { + flags |= RESET_LOW_POWER_WAKE; + } +#endif +#if NRFX_RESET_REASON_HAS_NFC + if (reason & NRFX_RESET_REASON_NFC_MASK) { + flags |= RESET_LOW_POWER_WAKE; + } +#endif +#if NRFX_RESET_REASON_HAS_VBUS + if (reason & NRFX_RESET_REASON_VBUS_MASK) { + flags |= RESET_POR; + } +#endif +#if NRFX_RESET_REASON_HAS_CTRLAPSOFT + if (reason & NRFX_RESET_REASON_CTRLAPSOFT_MASK) { + flags |= RESET_DEBUG; + } +#endif +#if NRFX_RESET_REASON_HAS_CTRLAPHARD + if (reason & NRFX_RESET_REASON_CTRLAPHARD_MASK) { + flags |= RESET_DEBUG; + } +#endif +#if NRFX_RESET_REASON_HAS_CTRLAPPIN + if (reason & NRFX_RESET_REASON_CTRLAPPIN_MASK) { + flags |= RESET_DEBUG; } +#endif +#if !NRF_POWER_HAS_RESETREAS if (reason & NRFX_RESET_REASON_DOG1_MASK) { flags |= RESET_WATCHDOG; } - if (reason & NRFX_RESETREAS_SREQ_MASK) { - flags |= RESET_SOFTWARE; +#endif +#if NRFX_RESET_REASON_HAS_GRTC + if (reason & NRFX_RESET_REASON_GRTC_MASK) { + flags |= RESET_CLOCK; } - -#if NRF_RESET_HAS_NETWORK +#endif +#if NRFX_RESET_REASON_HAS_NETWORK if (reason & NRFX_RESET_REASON_LSREQ_MASK) { flags |= RESET_SOFTWARE; } @@ -87,10 +121,14 @@ int z_impl_hwinfo_get_reset_cause(uint32_t *cause) flags |= RESET_DEBUG; } #endif - -#else - if (reason & NRFX_RESET_REASON_SREQ_MASK) { - flags |= RESET_SOFTWARE; +#if defined(NRFX_RESET_REASON_TAMPC_MASK) + if (reason & NRFX_RESET_REASON_TAMPC_MASK) { + flags |= RESET_SECURITY; + } +#endif +#if defined(NRFX_RESET_REASON_SECTAMPER_MASK) + if (reason & NRFX_RESET_REASON_SECTAMPER_MASK) { + flags |= RESET_SECURITY; } #endif From e4aebf9cea50e26c666aa69b9de4a802b9bcc6dc Mon Sep 17 00:00:00 2001 From: Magdalena Pastula Date: Tue, 16 Jan 2024 17:24:22 +0100 Subject: [PATCH 3138/3723] soc: arm: nordic_nrf: align soc_secure.h to nRF54L In nRF54L15 FICR can be accessed also from non-secure code, so it does not have NRF_FICR_S defined. Signed-off-by: Magdalena Pastula --- soc/arm/nordic_nrf/common/soc_secure.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/soc/arm/nordic_nrf/common/soc_secure.h b/soc/arm/nordic_nrf/common/soc_secure.h index 948f38547aa..d38d66ab488 100644 --- a/soc/arm/nordic_nrf/common/soc_secure.h +++ b/soc/arm/nordic_nrf/common/soc_secure.h @@ -59,7 +59,7 @@ static inline void soc_secure_gpio_pin_mcu_select(uint32_t pin_number, #if defined(CONFIG_SOC_HFXO_CAP_INTERNAL) static inline uint32_t soc_secure_read_xosc32mtrim(void) { - return NRF_FICR_S->XOSC32MTRIM; + return NRF_FICR->XOSC32MTRIM; } #endif /* defined(CONFIG_SOC_HFXO_CAP_INTERNAL) */ From d7d254140d02ef30821262853e46c794f7b515e5 Mon Sep 17 00:00:00 2001 From: Magdalena Pastula Date: Tue, 30 Jan 2024 10:40:15 +0100 Subject: [PATCH 3139/3723] tests: lib: cpp: exclude nRF54L15 Exclude nRF54L15 from possible targets as its HAL is incompatible with C++98. Signed-off-by: Magdalena Pastula --- tests/lib/cpp/cxx/testcase.yaml | 2 ++ 1 file changed, 2 insertions(+) diff --git a/tests/lib/cpp/cxx/testcase.yaml b/tests/lib/cpp/cxx/testcase.yaml index 404d9a3a970..465a751dab3 100644 --- a/tests/lib/cpp/cxx/testcase.yaml +++ b/tests/lib/cpp/cxx/testcase.yaml @@ -34,6 +34,8 @@ tests: # -std=c++98) cpp.main.cpp98: arch_exclude: posix + # Exclude nRF54L15 as its HAL is not compatible with C++98. + platform_exclude: nrf54l15pdk_nrf54l15_cpuapp build_only: true extra_configs: - CONFIG_STD_CPP98=y From bdfcd30513e4262447b686a37a0320546b5a9b5c Mon Sep 17 00:00:00 2001 From: Pisit Sawangvonganan Date: Sun, 28 Jan 2024 19:50:04 +0700 Subject: [PATCH 3140/3723] dts: bindings: clock: fix typo Utilize a code spell-checking tool to scan for and correct spelling errors in all files within the dts/bindings/clock directory. Signed-off-by: Pisit Sawangvonganan --- dts/bindings/clock/microchip,xec-pcr.yaml | 2 +- dts/bindings/clock/pwm-clock.yaml | 2 +- dts/bindings/clock/raspberrypi,pico-rosc.yaml | 2 +- dts/bindings/clock/renesas,ra-clock-generation-circuit.yaml | 2 +- dts/bindings/clock/st,stm32-rcc.yaml | 2 +- dts/bindings/clock/st,stm32f1-pll-clock.yaml | 4 ++-- dts/bindings/clock/st,stm32f105-pll-clock.yaml | 2 +- dts/bindings/clock/st,stm32f3-rcc.yaml | 2 +- dts/bindings/clock/st,stm32wba-rcc.yaml | 2 +- dts/bindings/clock/st,stm32wl-hse-clock.yaml | 2 +- 10 files changed, 11 insertions(+), 11 deletions(-) diff --git a/dts/bindings/clock/microchip,xec-pcr.yaml b/dts/bindings/clock/microchip,xec-pcr.yaml index 5a07aec6d40..00acde17ff8 100644 --- a/dts/bindings/clock/microchip,xec-pcr.yaml +++ b/dts/bindings/clock/microchip,xec-pcr.yaml @@ -59,7 +59,7 @@ properties: type: int required: true description: | - Mininum number of consecutive 32KHz pulses that pass all monitor tests + Minimum number of consecutive 32KHz pulses that pass all monitor tests xtal-enable-delay-ms: type: int diff --git a/dts/bindings/clock/pwm-clock.yaml b/dts/bindings/clock/pwm-clock.yaml index 5e19a245809..d377aa0fb2b 100644 --- a/dts/bindings/clock/pwm-clock.yaml +++ b/dts/bindings/clock/pwm-clock.yaml @@ -22,7 +22,7 @@ description: | property. The PWM node may need to be properly configured to generate - the target period (i.e. using prescaler options). See the documention + the target period (i.e. using prescaler options). See the documentation for the target PWM driver. compatible: "pwm-clock" diff --git a/dts/bindings/clock/raspberrypi,pico-rosc.yaml b/dts/bindings/clock/raspberrypi,pico-rosc.yaml index 189ba12c0f5..79058bc75c3 100644 --- a/dts/bindings/clock/raspberrypi,pico-rosc.yaml +++ b/dts/bindings/clock/raspberrypi,pico-rosc.yaml @@ -34,5 +34,5 @@ properties: phase: type: int description: | - The phase-shift vlaue. + The phase-shift value. The valid range is 0 to 3 diff --git a/dts/bindings/clock/renesas,ra-clock-generation-circuit.yaml b/dts/bindings/clock/renesas,ra-clock-generation-circuit.yaml index 07b244ea79d..2769a02ce2d 100644 --- a/dts/bindings/clock/renesas,ra-clock-generation-circuit.yaml +++ b/dts/bindings/clock/renesas,ra-clock-generation-circuit.yaml @@ -37,7 +37,7 @@ properties: clock-source: type: phandle - description: System clock sorce + description: System clock source "#clock-cells": const: 1 diff --git a/dts/bindings/clock/st,stm32-rcc.yaml b/dts/bindings/clock/st,stm32-rcc.yaml index 94aafc01a85..1f6e487baa5 100644 --- a/dts/bindings/clock/st,stm32-rcc.yaml +++ b/dts/bindings/clock/st,stm32-rcc.yaml @@ -54,7 +54,7 @@ description: | Domain clock is independent from the bus/gatted clock and allows access to the device's register while the gated clock is off. As it doesn't feed the peripheral's controller, it allows peripheral operation, but can't be used for peripheral configuration. - It is peripheral driver's responsibility to querry and use clock source information in + It is peripheral driver's responsibility to query and use clock source information in accordance with clock_control API specifications. Since the peripheral subsystem rate is dictated by the clock used for peripheral diff --git a/dts/bindings/clock/st,stm32f1-pll-clock.yaml b/dts/bindings/clock/st,stm32f1-pll-clock.yaml index 5b30f52d3e5..04c9a8e2954 100644 --- a/dts/bindings/clock/st,stm32f1-pll-clock.yaml +++ b/dts/bindings/clock/st,stm32f1-pll-clock.yaml @@ -35,11 +35,11 @@ properties: xtpre: type: boolean description: | - Otpional HSE divider for PLL entry + Optional HSE divider for PLL entry usbpre: type: boolean description: | - Otpional PLL output divisor to generate a 48MHz USB clock. + Optional PLL output divisor to generate a 48MHz USB clock. When set, PLL clock is not divided. Otherwise, PLL output clock is divided by 1.5. diff --git a/dts/bindings/clock/st,stm32f105-pll-clock.yaml b/dts/bindings/clock/st,stm32f105-pll-clock.yaml index a503e247172..d2f01e8989b 100644 --- a/dts/bindings/clock/st,stm32f105-pll-clock.yaml +++ b/dts/bindings/clock/st,stm32f105-pll-clock.yaml @@ -55,6 +55,6 @@ properties: otgfspre: type: boolean description: | - Otpional PLL output divisor to generate a 48MHz USB clock. + Optional PLL output divisor to generate a 48MHz USB clock. When set, PLL output clock is not divided. Otherwise, PLL output clock is divided by 1.5. diff --git a/dts/bindings/clock/st,stm32f3-rcc.yaml b/dts/bindings/clock/st,stm32f3-rcc.yaml index 5e9825129f7..ca0e57dc719 100644 --- a/dts/bindings/clock/st,stm32f3-rcc.yaml +++ b/dts/bindings/clock/st,stm32f3-rcc.yaml @@ -52,4 +52,4 @@ properties: ADC 3 and 4 prescaler - 0: Disables the clock so the ADC can use AHB clock (synchronous mode) - Other values n: The ADC can use the PLL clock divided by n - Check RefMan for availabilty. + Check RefMan for availability. diff --git a/dts/bindings/clock/st,stm32wba-rcc.yaml b/dts/bindings/clock/st,stm32wba-rcc.yaml index d85ba13ad20..797c366da11 100644 --- a/dts/bindings/clock/st,stm32wba-rcc.yaml +++ b/dts/bindings/clock/st,stm32wba-rcc.yaml @@ -49,7 +49,7 @@ description: | ... } In this example I2C1 device is assigned HSI as clock source. - It is device driver's responsibility to querry and use clock source information in + It is device driver's responsibility to query and use clock source information in accordance with clock_control API specifications. compatible: "st,stm32wba-rcc" diff --git a/dts/bindings/clock/st,stm32wl-hse-clock.yaml b/dts/bindings/clock/st,stm32wl-hse-clock.yaml index c1bc2199b79..f765efc264e 100644 --- a/dts/bindings/clock/st,stm32wl-hse-clock.yaml +++ b/dts/bindings/clock/st,stm32wl-hse-clock.yaml @@ -12,7 +12,7 @@ properties: type: boolean description: | When set, TCXO is selected as external source clock for HSE. - Otherwise, external cyrstal is selected as HSE source clock. + Otherwise, external crystal is selected as HSE source clock. hse-div2: type: boolean From 250e6c01088e0f66c386321e6117b69871b6090e Mon Sep 17 00:00:00 2001 From: Pisit Sawangvonganan Date: Sun, 28 Jan 2024 19:54:08 +0700 Subject: [PATCH 3141/3723] dts: bindings: sensor: fix typo Utilize a code spell-checking tool to scan for and correct spelling errors in all files within the dts/bindings/sensor directory. Signed-off-by: Pisit Sawangvonganan --- dts/bindings/sensor/ams,tsl2540.yaml | 4 ++-- dts/bindings/sensor/maxim,max31875.yaml | 2 +- dts/bindings/sensor/nuvoton,adc-cmp.yaml | 2 +- dts/bindings/sensor/nxp,kinetis-temperature.yaml | 2 +- dts/bindings/sensor/st,lis2mdl-common.yaml | 2 +- dts/bindings/sensor/st,lsm6dsv16x-common.yaml | 2 +- dts/bindings/sensor/ti,fdc2x1x.yaml | 2 +- dts/bindings/sensor/ti,tmag5170.yaml | 2 +- 8 files changed, 9 insertions(+), 9 deletions(-) diff --git a/dts/bindings/sensor/ams,tsl2540.yaml b/dts/bindings/sensor/ams,tsl2540.yaml index e47f8a8e8f0..d19bd4ea002 100644 --- a/dts/bindings/sensor/ams,tsl2540.yaml +++ b/dts/bindings/sensor/ams,tsl2540.yaml @@ -20,7 +20,7 @@ properties: default: 100000 description: | Visible light attenuation. - Integer value for a represenation with 5 decimal points. + Integer value for a representation with 5 decimal points. This default value (1.00000) is chosen for free open space (no glass). Example: 1.2 would be 120000 @@ -29,6 +29,6 @@ properties: default: 100000 description: | Infa-red light attenuation. - Integer value for a represenation with 5 decimal points. + Integer value for a representation with 5 decimal points. This default value (1.00000) is chosen for free open space (no glass). Example: 1.2 would be 120000 diff --git a/dts/bindings/sensor/maxim,max31875.yaml b/dts/bindings/sensor/maxim,max31875.yaml index 4ded503bdbd..546a931e6f6 100644 --- a/dts/bindings/sensor/maxim,max31875.yaml +++ b/dts/bindings/sensor/maxim,max31875.yaml @@ -17,7 +17,7 @@ properties: conversions-per-second: description: | Number of temperature readings performed by the MAX31875 per second. - 0.25 converions per second is the power-on reset configuration. + 0.25 conversions per second is the power-on reset configuration. type: string default: "0.25" # Note: the driver relies on the ordering of this enum, diff --git a/dts/bindings/sensor/nuvoton,adc-cmp.yaml b/dts/bindings/sensor/nuvoton,adc-cmp.yaml index 40d0e1b6e0c..2cc687b8423 100644 --- a/dts/bindings/sensor/nuvoton,adc-cmp.yaml +++ b/dts/bindings/sensor/nuvoton,adc-cmp.yaml @@ -1,7 +1,7 @@ # Copyright (c) 2022 Intel Corporation # SPDX-License-Identifier: Apache-2.0 description: | - This will perform signal comparision with threshold established. + This will perform signal comparison with threshold established. compatible: "nuvoton,adc-cmp" diff --git a/dts/bindings/sensor/nxp,kinetis-temperature.yaml b/dts/bindings/sensor/nxp,kinetis-temperature.yaml index 0b2b4d9df9d..0ad50bf2e97 100644 --- a/dts/bindings/sensor/nxp,kinetis-temperature.yaml +++ b/dts/bindings/sensor/nxp,kinetis-temperature.yaml @@ -25,7 +25,7 @@ properties: type: int required: true description: | - Temperature sensor voltage at 25 degrees Celcius in microvolts + Temperature sensor voltage at 25 degrees Celsius in microvolts sensor-slope-cold: type: int diff --git a/dts/bindings/sensor/st,lis2mdl-common.yaml b/dts/bindings/sensor/st,lis2mdl-common.yaml index 4fe9e877bbc..53e0d723d93 100644 --- a/dts/bindings/sensor/st,lis2mdl-common.yaml +++ b/dts/bindings/sensor/st,lis2mdl-common.yaml @@ -16,7 +16,7 @@ properties: type: boolean description: | Set to config the sensor in single measurement mode. Leave - unset to configure the sensor in continious measurement mode. + unset to configure the sensor in continuous measurement mode. cancel-offset: type: boolean diff --git a/dts/bindings/sensor/st,lsm6dsv16x-common.yaml b/dts/bindings/sensor/st,lsm6dsv16x-common.yaml index 420c1d728c4..fc1d2c6d592 100644 --- a/dts/bindings/sensor/st,lsm6dsv16x-common.yaml +++ b/dts/bindings/sensor/st,lsm6dsv16x-common.yaml @@ -137,7 +137,7 @@ properties: The values are taken in accordance to lsm6dsv16x_data_rate_t enumerative in hal/st module. Please note that this values will not change the operating mode, which will remain High Performance (device default). Moreover, the values here which will be selected in the - DT are the only way to specifiy the odr accuracy even at runtime with + DT are the only way to specify the odr accuracy even at runtime with SENSOR_ATTR_SAMPLING_FREQUENCY. Default is power-up configuration. diff --git a/dts/bindings/sensor/ti,fdc2x1x.yaml b/dts/bindings/sensor/ti,fdc2x1x.yaml index 4d8d9c6f245..b79b2724889 100644 --- a/dts/bindings/sensor/ti,fdc2x1x.yaml +++ b/dts/bindings/sensor/ti,fdc2x1x.yaml @@ -44,7 +44,7 @@ properties: description: | Reference frequency of the used clock source in KHz. The internal clock oscillates at around 43360 KHz (43.36 MHz) - at 20 degrees Celcius. + at 20 degrees Celsius. Recommended external clock source frequency is 40000 KHz (40 MHz). rr-sequence: diff --git a/dts/bindings/sensor/ti,tmag5170.yaml b/dts/bindings/sensor/ti,tmag5170.yaml index c68e704c900..d4f5d3abffc 100644 --- a/dts/bindings/sensor/ti,tmag5170.yaml +++ b/dts/bindings/sensor/ti,tmag5170.yaml @@ -183,7 +183,7 @@ properties: type: int default: 1 description: | - The time in miliseconds the sensor will be in sleep during conversions. + The time in milliseconds the sensor will be in sleep during conversions. For this property to take effect sensor must be in `duty-cycled` mode. Note that to calculate total time between conversions, the conversion time itself must be taken into account. The conversion time is dependent From bbfdec437126301f294afb909de21884ddf1724f Mon Sep 17 00:00:00 2001 From: Pisit Sawangvonganan Date: Sun, 28 Jan 2024 19:57:14 +0700 Subject: [PATCH 3142/3723] dts: bindings: dma: fix typo Utilize a code spell-checking tool to scan for and correct spelling errors in all files within the dts/bindings/dma directory. Signed-off-by: Pisit Sawangvonganan --- dts/bindings/dma/andestech,atcdmac300.yaml | 2 +- dts/bindings/dma/st,stm32-dma-v1.yaml | 2 +- dts/bindings/dma/st,stm32-dma-v2.yaml | 2 +- dts/bindings/dma/st,stm32-dmamux.yaml | 2 +- 4 files changed, 4 insertions(+), 4 deletions(-) diff --git a/dts/bindings/dma/andestech,atcdmac300.yaml b/dts/bindings/dma/andestech,atcdmac300.yaml index 931cc1ffaeb..4c0020dd69d 100644 --- a/dts/bindings/dma/andestech,atcdmac300.yaml +++ b/dts/bindings/dma/andestech,atcdmac300.yaml @@ -29,7 +29,7 @@ description: | Andes DMA controller channel: a phandle to the DMA controller plus the following four integer cells: 1. channel: the dma channel - 2. slot: DMA peripherial request ID + 2. slot: DMA peripheral request ID 3. channel-config: A 32bit mask specifying the DMA channel configuration which is device dependent: -bit 0-1 : Direction (see dma.h) diff --git a/dts/bindings/dma/st,stm32-dma-v1.yaml b/dts/bindings/dma/st,stm32-dma-v1.yaml index 8e33887dace..c4658e6b30e 100644 --- a/dts/bindings/dma/st,stm32-dma-v1.yaml +++ b/dts/bindings/dma/st,stm32-dma-v1.yaml @@ -13,7 +13,7 @@ description: | 2. slot: DMA periph request ID, which is written in the DMAREQ_ID of the DMAMUX_CxCR this value is 0 for Memory-to-memory transfers or a value between <1> .. (not supported yet) - or a value beweeen +1 .. + + or a value between +1 .. + 3. channel-config: A 32bit mask specifying the DMA channel configuration which is device dependent: -bit 6-7 : Direction (see dma.h) diff --git a/dts/bindings/dma/st,stm32-dma-v2.yaml b/dts/bindings/dma/st,stm32-dma-v2.yaml index 38e968c1a3b..d3c9edac707 100644 --- a/dts/bindings/dma/st,stm32-dma-v2.yaml +++ b/dts/bindings/dma/st,stm32-dma-v2.yaml @@ -16,7 +16,7 @@ description: | 2. slot: DMA periph request ID, which is written in the DMAREQ_ID of the DMAMUX_CxCR this value is 0 for Memory-to-memory transfers or a value between <1> .. (not supported yet) - or a value beweeen +1 .. + + or a value between +1 .. + 3. channel-config: A 32bit mask specifying the DMA channel configuration A name custom DMA flags for channel configuration is used which is device dependent see stm32_dma.h: diff --git a/dts/bindings/dma/st,stm32-dmamux.yaml b/dts/bindings/dma/st,stm32-dmamux.yaml index 5ce00b95290..84d5e8668e4 100644 --- a/dts/bindings/dma/st,stm32-dmamux.yaml +++ b/dts/bindings/dma/st,stm32-dmamux.yaml @@ -41,7 +41,7 @@ description: | 0x1: medium 0x2: high 0x3: very high - exemple for stm32wb55x + example for stm32wb55x dmamux1: dmamux@40020800 { compatible = "st,stm32-dmamux"; ... From 9a286893759f8e308ea4a3a0d9b205f43440b6f5 Mon Sep 17 00:00:00 2001 From: Pisit Sawangvonganan Date: Sun, 28 Jan 2024 19:59:51 +0700 Subject: [PATCH 3143/3723] dts: bindings: pinctrl: fix typo Utilize a code spell-checking tool to scan for and correct spelling errors in all files within the dts/bindings/pinctrl directory. Signed-off-by: Pisit Sawangvonganan --- dts/bindings/pinctrl/ite,it8xxx2-pinctrl.yaml | 4 ++-- dts/bindings/pinctrl/renesas,rcar-pfc.yaml | 2 +- dts/bindings/pinctrl/st,stm32-pinctrl.yaml | 4 ++-- dts/bindings/pinctrl/st,stm32f1-pinctrl.yaml | 6 +++--- dts/bindings/pinctrl/telink,b91-pinctrl.yaml | 4 ++-- 5 files changed, 10 insertions(+), 10 deletions(-) diff --git a/dts/bindings/pinctrl/ite,it8xxx2-pinctrl.yaml b/dts/bindings/pinctrl/ite,it8xxx2-pinctrl.yaml index 36a3a7595a2..01a1c758a9c 100644 --- a/dts/bindings/pinctrl/ite,it8xxx2-pinctrl.yaml +++ b/dts/bindings/pinctrl/ite,it8xxx2-pinctrl.yaml @@ -46,7 +46,7 @@ description: | The 'uart1_rx_pb0_default' child node encodes the pin configurations for a particular state of a device; in this case, the default - (that is, active) sate. + (that is, active) state. To link pin configurations with a device, use a pinctrl-N property for some number N, like this example you could place in your board's DTS file: @@ -65,7 +65,7 @@ include: base.yaml child-binding: description: | - This binding gives a base representation of the ITE IT8XXX2 pins configration. + This binding gives a base representation of the ITE IT8XXX2 pins configuration. include: - name: pincfg-node.yaml diff --git a/dts/bindings/pinctrl/renesas,rcar-pfc.yaml b/dts/bindings/pinctrl/renesas,rcar-pfc.yaml index 8d7ee2c6bbb..1743f213193 100644 --- a/dts/bindings/pinctrl/renesas,rcar-pfc.yaml +++ b/dts/bindings/pinctrl/renesas,rcar-pfc.yaml @@ -40,7 +40,7 @@ description: | The 'can0_data_a_tx_default' child node encodes the pin configurations for a particular state of a device; in this case, the default - (that is, active) sate. You would specify the low-power configuration for + (that is, active) state. You would specify the low-power configuration for the same device in a separate child node. A pin configuration can also specify pin properties such as the diff --git a/dts/bindings/pinctrl/st,stm32-pinctrl.yaml b/dts/bindings/pinctrl/st,stm32-pinctrl.yaml index cfc1c2a6fa7..b412d5dfddb 100644 --- a/dts/bindings/pinctrl/st,stm32-pinctrl.yaml +++ b/dts/bindings/pinctrl/st,stm32-pinctrl.yaml @@ -34,7 +34,7 @@ properties: child-binding: description: | - This binding gives a base representation of the STM32 pins configration + This binding gives a base representation of the STM32 pins configuration include: - name: pincfg-node.yaml @@ -76,7 +76,7 @@ child-binding: This macro is available here: -include/zephyr/dt-bindings/pinctrl/stm32-pinctrl-common.h Some examples of macro usage: - GPIO A9 set as alernate function 2 + GPIO A9 set as alternate function 2 ... { pinmux = ; }; diff --git a/dts/bindings/pinctrl/st,stm32f1-pinctrl.yaml b/dts/bindings/pinctrl/st,stm32f1-pinctrl.yaml index f96b3c123ea..77efa78c064 100644 --- a/dts/bindings/pinctrl/st,stm32f1-pinctrl.yaml +++ b/dts/bindings/pinctrl/st,stm32f1-pinctrl.yaml @@ -41,7 +41,7 @@ properties: child-binding: description: | This binding gives a base representation of the STM32F1 pins - configration + configuration include: - name: pincfg-node.yaml @@ -85,11 +85,11 @@ child-binding: This macro is available here: -include/zephyr/dt-bindings/pinctrl/stm32f1-pinctrl.h Some examples of macro usage: - GPIO A9 set as alernate with no remap + GPIO A9 set as alternate with no remap ... { pinmux = ; }; - GPIO A9 set as alernate with full remap + GPIO A9 set as alternate with full remap ... { pinmux = ; }; diff --git a/dts/bindings/pinctrl/telink,b91-pinctrl.yaml b/dts/bindings/pinctrl/telink,b91-pinctrl.yaml index 2c19c46a080..df490ffa18a 100644 --- a/dts/bindings/pinctrl/telink,b91-pinctrl.yaml +++ b/dts/bindings/pinctrl/telink,b91-pinctrl.yaml @@ -39,7 +39,7 @@ description: | The 'uart0_tx_pb2_default' child node encodes the pin configurations for a particular state of a device; in this case, the default - (that is, active) sate. You would specify the low-power configuration for + (that is, active) state. You would specify the low-power configuration for the same device in a separate child node. A pin configuration can also specify pin properties such as the @@ -83,7 +83,7 @@ properties: child-binding: description: | - This binding gives a base representation of the Telink B91 pins configration. + This binding gives a base representation of the Telink B91 pins configuration. include: - name: pincfg-node.yaml From 22315d6a9d47b0091c4dad82884211e6819b49a7 Mon Sep 17 00:00:00 2001 From: Pisit Sawangvonganan Date: Sun, 28 Jan 2024 20:05:53 +0700 Subject: [PATCH 3144/3723] dts: bindings: fix typo in (timer, usb-c, usb, watchdog) Utilize a code spell-checking tool to scan for and correct spelling errors in all files within the dts/bindings/timer, usb-c, usb and watchdog. Signed-off-by: Pisit Sawangvonganan --- dts/bindings/timer/nuclei,systimer.yaml | 2 +- dts/bindings/timer/nxp,imx-gpt.yaml | 2 +- dts/bindings/usb-c/usb-c-connector.yaml | 8 ++++---- dts/bindings/usb/uac2/zephyr,uac2.yaml | 2 +- dts/bindings/usb/usb-audio-hs.yaml | 2 +- dts/bindings/usb/usb-audio-mic.yaml | 2 +- dts/bindings/watchdog/intel,adsp-watchdog.yaml | 2 +- dts/bindings/watchdog/lowrisc,opentitan-aontimer.yaml | 2 +- dts/bindings/watchdog/snps,designware-watchdog.yaml | 2 +- 9 files changed, 12 insertions(+), 12 deletions(-) diff --git a/dts/bindings/timer/nuclei,systimer.yaml b/dts/bindings/timer/nuclei,systimer.yaml index cee9e2bc9e7..5c8f319a7c5 100644 --- a/dts/bindings/timer/nuclei,systimer.yaml +++ b/dts/bindings/timer/nuclei,systimer.yaml @@ -44,5 +44,5 @@ properties: Setting clk-divider to 2 specifies the system timer uses the clock that CPU clock frequency divided by (2^2=)4, or 27MHz. - Devision ratio constants can be found in the + Division ratio constants can be found in the dt-bindings/timer/nuclei-systimer.h header file. diff --git a/dts/bindings/timer/nxp,imx-gpt.yaml b/dts/bindings/timer/nxp,imx-gpt.yaml index 31396093097..4d1aac49c14 100644 --- a/dts/bindings/timer/nxp,imx-gpt.yaml +++ b/dts/bindings/timer/nxp,imx-gpt.yaml @@ -17,4 +17,4 @@ properties: gptfreq: type: int required: true - description: gpt frequences + description: gpt frequencies diff --git a/dts/bindings/usb-c/usb-c-connector.yaml b/dts/bindings/usb-c/usb-c-connector.yaml index 4cbcf3f518c..334f2f06e18 100644 --- a/dts/bindings/usb-c/usb-c-connector.yaml +++ b/dts/bindings/usb-c/usb-c-connector.yaml @@ -115,7 +115,7 @@ properties: type: array description: | An array of source Power Data Objects (PDOs). - Use tht following macros to define the PDOs, defined in + Use the following macros to define the PDOs, defined in dt-bindings/usb-c/pd.h. * PDO_FIXED * PDO_BATT @@ -127,7 +127,7 @@ properties: type: array description: | An array of sink Power Data Objects (PDOs). - Use tht following macros to define the PDOs, defined in + Use the following macros to define the PDOs, defined in dt-bindings/usb-c/pd.h. * PDO_FIXED * PDO_BATT @@ -139,7 +139,7 @@ properties: type: array description: | An array of sink Vendor Defined Objects (VDOs). - Use tht following macros to define the VDOs, defined in + Use the following macros to define the VDOs, defined in dt-bindings/usb-c/pd.h. * VDO_IDH * VDO_CERT @@ -155,7 +155,7 @@ properties: type: array description: | An array of sink Vendor Defined Objects (VDOs). - Use tht following macros to define the VDOs, defined in + Use the following macros to define the VDOs, defined in dt-bindings/usb-c/pd.h. * VDO_IDH * VDO_CERT diff --git a/dts/bindings/usb/uac2/zephyr,uac2.yaml b/dts/bindings/usb/uac2/zephyr,uac2.yaml index 0f0aaf5b55f..a4283f219a0 100644 --- a/dts/bindings/usb/uac2/zephyr,uac2.yaml +++ b/dts/bindings/usb/uac2/zephyr,uac2.yaml @@ -13,7 +13,7 @@ compatible: "zephyr,uac2" # The only reason for putting Audio Streaming interfaces at the end is because # Audio Control entities derive their unique ID from child index (+ 1). For most # cases the order shouldn't really matter, but if there happen to be maximum -# possible number of entities (255) then the Audio Streaming would inadvertedly +# possible number of entities (255) then the Audio Streaming would inadvertently # "consume" one of the available IDs. properties: diff --git a/dts/bindings/usb/usb-audio-hs.yaml b/dts/bindings/usb/usb-audio-hs.yaml index e876746ebe3..f440186f5fe 100644 --- a/dts/bindings/usb/usb-audio-hs.yaml +++ b/dts/bindings/usb/usb-audio-hs.yaml @@ -23,7 +23,7 @@ properties: type: string description: | Type of endpoint synchronization for IN devices. - Default value is Sychronous. + Default value is Synchronous. Adaptive is not supported. enum: - "No Synchronization" diff --git a/dts/bindings/usb/usb-audio-mic.yaml b/dts/bindings/usb/usb-audio-mic.yaml index c8571084682..9a12b78b894 100644 --- a/dts/bindings/usb/usb-audio-mic.yaml +++ b/dts/bindings/usb/usb-audio-mic.yaml @@ -23,7 +23,7 @@ properties: type: string description: | Type of endpoint synchronization for IN devices. - Default value is Sychronous. + Default value is Synchronous. Adaptive is not supported. enum: - "No Synchronization" diff --git a/dts/bindings/watchdog/intel,adsp-watchdog.yaml b/dts/bindings/watchdog/intel,adsp-watchdog.yaml index 379e9e5edaa..f8e76ea23fa 100644 --- a/dts/bindings/watchdog/intel,adsp-watchdog.yaml +++ b/dts/bindings/watchdog/intel,adsp-watchdog.yaml @@ -16,7 +16,7 @@ properties: type: int description: | Clock frequency used by counter in Hz. You can specify a frequency here or specify a clock - using the clocks propertie. + using the clocks properties. reset-pulse-length: type: int diff --git a/dts/bindings/watchdog/lowrisc,opentitan-aontimer.yaml b/dts/bindings/watchdog/lowrisc,opentitan-aontimer.yaml index 558f598c542..5660ebf0051 100644 --- a/dts/bindings/watchdog/lowrisc,opentitan-aontimer.yaml +++ b/dts/bindings/watchdog/lowrisc,opentitan-aontimer.yaml @@ -22,5 +22,5 @@ properties: wdog-lock: type: boolean description: | - When set, lock watchdog configration after setup until the next + When set, lock watchdog configuration after setup until the next reset. diff --git a/dts/bindings/watchdog/snps,designware-watchdog.yaml b/dts/bindings/watchdog/snps,designware-watchdog.yaml index 58ce467f9b2..5b0b899c621 100644 --- a/dts/bindings/watchdog/snps,designware-watchdog.yaml +++ b/dts/bindings/watchdog/snps,designware-watchdog.yaml @@ -16,7 +16,7 @@ properties: type: int description: | Clock frequency used by counter in Hz. You can specify a frequency here or specify a clock - using the clocks propertie. + using the clocks properties. reset-pulse-length: type: int From 31a82699a8db5d95a0e59c4feb5fe16bbf4b2304 Mon Sep 17 00:00:00 2001 From: Pisit Sawangvonganan Date: Sun, 28 Jan 2024 20:08:43 +0700 Subject: [PATCH 3145/3723] dts: bindings: fix typo in (retained_mem, rng, serial, spi) Utilize a code spell-checking tool to scan for and correct spelling errors in all files within the dts/bindings/retained_mem, rng, serial and spi. Signed-off-by: Pisit Sawangvonganan --- dts/bindings/retained_mem/zephyr,retained-ram.yaml | 2 +- dts/bindings/rng/st,stm32-rng.yaml | 2 +- dts/bindings/serial/infineon,xmc4xxx-uart.yaml | 2 +- dts/bindings/serial/st,stm32-uart-base.yaml | 4 ++-- dts/bindings/spi/infineon,xmc4xxx-spi.yaml | 2 +- dts/bindings/spi/microchip,xec-qmspi-ldma.yaml | 6 +++--- 6 files changed, 9 insertions(+), 9 deletions(-) diff --git a/dts/bindings/retained_mem/zephyr,retained-ram.yaml b/dts/bindings/retained_mem/zephyr,retained-ram.yaml index 5f2c1df1244..0b11fdd1bff 100644 --- a/dts/bindings/retained_mem/zephyr,retained-ram.yaml +++ b/dts/bindings/retained_mem/zephyr,retained-ram.yaml @@ -1,7 +1,7 @@ # Copyright (c) 2023 Nordic Semiconductor ASA # SPDX-License-Identifier: Apache-2.0 -description: Unitialised RAM-based retained memory area. +description: Uninitialised RAM-based retained memory area. compatible: "zephyr,retained-ram" diff --git a/dts/bindings/rng/st,stm32-rng.yaml b/dts/bindings/rng/st,stm32-rng.yaml index a58a8a81aeb..58d4aea8f8e 100644 --- a/dts/bindings/rng/st,stm32-rng.yaml +++ b/dts/bindings/rng/st,stm32-rng.yaml @@ -18,7 +18,7 @@ properties: the clock domain used, for instance: <&rcc STM32_SRC_MSI CLK48_SEL(3)> /* RNG clock domain set to MSI */ A correctly configured domain clock is required to allow the integrated low - sampling clock detection mecanism to behave properly. + sampling clock detection mechanism to behave properly. In provided example, MSI should be configured to provide 48Mhz clock. nist-config: diff --git a/dts/bindings/serial/infineon,xmc4xxx-uart.yaml b/dts/bindings/serial/infineon,xmc4xxx-uart.yaml index c93ee940825..788ea54c956 100644 --- a/dts/bindings/serial/infineon,xmc4xxx-uart.yaml +++ b/dts/bindings/serial/infineon,xmc4xxx-uart.yaml @@ -100,7 +100,7 @@ properties: dma1 can connect to lines [8, 11]. 2. For a given interrupt, calculate the service request (SR) number. Note the following simple mapping: in USIC0 interrupt 84->SR0, interrupt 85->SR1, ... etc. - In USIC1, intterupt 90->SR0, 91->SR1, etc. + In USIC1, interrupt 90->SR0, 91->SR1, etc. 3. Select request_source from Table "DMA Request Source Selection" in XMC4XXX reference manual. diff --git a/dts/bindings/serial/st,stm32-uart-base.yaml b/dts/bindings/serial/st,stm32-uart-base.yaml index 230c384906a..9b4852bbc8c 100644 --- a/dts/bindings/serial/st,stm32-uart-base.yaml +++ b/dts/bindings/serial/st,stm32-uart-base.yaml @@ -90,9 +90,9 @@ properties: fifo-enable: type: boolean description: | - Enables transmit and receive FIFO using default FIFO confugration (typically threasholds + Enables transmit and receive FIFO using default FIFO configuration (typically thresholds set to 1/8). In TX, FIFO allows to work in burst mode, easing scheduling of loaded applications. It also allows more reliable communication with UART devices sensitive to variation of inter-frames delays. - In RX, FIFO reduces overrun occurences. + In RX, FIFO reduces overrun occurrences. diff --git a/dts/bindings/spi/infineon,xmc4xxx-spi.yaml b/dts/bindings/spi/infineon,xmc4xxx-spi.yaml index b3475924e14..a4f30d99400 100644 --- a/dts/bindings/spi/infineon,xmc4xxx-spi.yaml +++ b/dts/bindings/spi/infineon,xmc4xxx-spi.yaml @@ -55,7 +55,7 @@ properties: dma1 can connect to lines [8, 11]. 2. For a given interrupt, calculate the service request (SR) number. Note the following simple mapping: in USIC0 interrupt 84->SR0, interrupt 85->SR1, ... etc. - In USIC1, intterupt 90->SR0, 91->SR1, etc. + In USIC1, interrupt 90->SR0, 91->SR1, etc. 3. Select request_source from Table "DMA Request Source Selection" in XMC4XXX reference manual. diff --git a/dts/bindings/spi/microchip,xec-qmspi-ldma.yaml b/dts/bindings/spi/microchip,xec-qmspi-ldma.yaml index 7654612229a..418d874bb37 100644 --- a/dts/bindings/spi/microchip,xec-qmspi-ldma.yaml +++ b/dts/bindings/spi/microchip,xec-qmspi-ldma.yaml @@ -55,14 +55,14 @@ properties: type: int description: | Delay in QMSPI main clocks from CS# assertion to first clock edge. - If not present use hardware default value. Refer to chip documention + If not present use hardware default value. Refer to chip documentation for QMSPI input clock frequency. dckcsoff: type: int description: | Delay in QMSPI main clocks from last clock edge to CS# de-assertion. - If not present use hardware default value. Refer to chip documention + If not present use hardware default value. Refer to chip documentation for QMSPI input clock frequency. dldh: @@ -76,7 +76,7 @@ properties: type: int description: | Delay in QMSPI main clocks from CS# de-assertion to CS# assertion. - If not present use hardware default value. Refer to chip documention + If not present use hardware default value. Refer to chip documentation for QMSPI input clock frequency. cs1-freq: From cfa9eeb12ce8e7825d1c331dc19769b4f3cfe072 Mon Sep 17 00:00:00 2001 From: Pisit Sawangvonganan Date: Sun, 28 Jan 2024 20:11:16 +0700 Subject: [PATCH 3146/3723] dts: bindings: fix typo in (net, power-domain, pwm, qspi) Utilize a code spell-checking tool to scan for and correct spelling errors in all files within the dts/bindings/net, power-domain, pwm and qspi. Signed-off-by: Pisit Sawangvonganan --- dts/bindings/net/wireless/gpio-radio-coex.yaml | 2 +- dts/bindings/power-domain/power-domain-gpio-monitor.yaml | 2 +- dts/bindings/pwm/nxp,s32-emios-pwm.yaml | 2 +- dts/bindings/qspi/nxp,s32-qspi.yaml | 2 +- 4 files changed, 4 insertions(+), 4 deletions(-) diff --git a/dts/bindings/net/wireless/gpio-radio-coex.yaml b/dts/bindings/net/wireless/gpio-radio-coex.yaml index e21cc53d433..ab453e5652b 100644 --- a/dts/bindings/net/wireless/gpio-radio-coex.yaml +++ b/dts/bindings/net/wireless/gpio-radio-coex.yaml @@ -2,7 +2,7 @@ # SPDX-License-Identifier: Apache-2.0 description: | - Generic representation of Coexistance pin interface for radios. This + Generic representation of Coexistence pin interface for radios. This interface is usually available on Wifi/Bluetooth/LTE modules to interact with each other when sharing same antenna. This prevents any collisions between transmissions from different modules. The grant diff --git a/dts/bindings/power-domain/power-domain-gpio-monitor.yaml b/dts/bindings/power-domain/power-domain-gpio-monitor.yaml index d7dfd8779b7..ebc9b5b5038 100644 --- a/dts/bindings/power-domain/power-domain-gpio-monitor.yaml +++ b/dts/bindings/power-domain/power-domain-gpio-monitor.yaml @@ -6,7 +6,7 @@ description: | This power domain monitors the state of a GPIO pin to detect whether a power rail is on/off. Therefore, performing resume/suspend on power domain won't - change physical state of power rails and those action won't be triggerd on + change physical state of power rails and those action won't be triggered on child nodes. Additionally, due to the asynchronous nature of monitoring a pending transaction won't be interrupted by power state change. diff --git a/dts/bindings/pwm/nxp,s32-emios-pwm.yaml b/dts/bindings/pwm/nxp,s32-emios-pwm.yaml index 37de69e39e1..0b8a2ffc674 100644 --- a/dts/bindings/pwm/nxp,s32-emios-pwm.yaml +++ b/dts/bindings/pwm/nxp,s32-emios-pwm.yaml @@ -179,7 +179,7 @@ child-binding: default: 0 enum: [0, 2, 4, 8, 16] description: | - Select the minimim input pulse width, in filter clock cycles that can pass + Select the minimum input pulse width, in filter clock cycles that can pass through the input filter. The filter latency - the difference in time between the input and the response is three clock edges. Default 0 means the filter is bypassed. The clock source for programmable input filter is eMIOS clock. diff --git a/dts/bindings/qspi/nxp,s32-qspi.yaml b/dts/bindings/qspi/nxp,s32-qspi.yaml index 7d61e5d8104..0f59af09f25 100644 --- a/dts/bindings/qspi/nxp,s32-qspi.yaml +++ b/dts/bindings/qspi/nxp,s32-qspi.yaml @@ -70,7 +70,7 @@ properties: type: int default: 0 description: | - Column Address Space bit width. For example, if the coulmn address is + Column Address Space bit width. For example, if the column address is [2:0] of QSPI_SFAR/AHB address, then the column address space bit width must be 3. If there is no column address separation in any serial flash device connected to this controller, this value must be programmed to 0. From f0f1ba0610a5eaf0e7e70f5e13b0d84f20740eb5 Mon Sep 17 00:00:00 2001 From: Pisit Sawangvonganan Date: Sun, 28 Jan 2024 20:13:44 +0700 Subject: [PATCH 3147/3723] dts: bindings: fix typo in (ethernet, gpio, i2c, interrupt-controller) Utilize a code spell-checking tool to scan for and correct spelling errors in all files within the dts/bindings/ethernet, gpio, i2c and interrupt-controller. Signed-off-by: Pisit Sawangvonganan --- dts/bindings/ethernet/xlnx,gem.yaml | 2 +- dts/bindings/gpio/richtek,rt1718s.yaml | 2 +- dts/bindings/i2c/atmel,sam-i2c-twim.yaml | 2 +- dts/bindings/interrupt-controller/cypress,psoc6-intmux.yaml | 4 ++-- dts/bindings/interrupt-controller/nuvoton,npcx-miwu.yaml | 2 +- 5 files changed, 6 insertions(+), 6 deletions(-) diff --git a/dts/bindings/ethernet/xlnx,gem.yaml b/dts/bindings/ethernet/xlnx,gem.yaml index a4c16094b08..90cff14f260 100644 --- a/dts/bindings/ethernet/xlnx,gem.yaml +++ b/dts/bindings/ethernet/xlnx,gem.yaml @@ -303,7 +303,7 @@ properties: multicast-hash: type: boolean description: | - Optional feature flag - Enable multicast hash. When set, mutlicast + Optional feature flag - Enable multicast hash. When set, multicast frames will be accepted when the 6 bit hash function of the desti- nation address points to a bit that is set in the hash register. diff --git a/dts/bindings/gpio/richtek,rt1718s.yaml b/dts/bindings/gpio/richtek,rt1718s.yaml index 446cde37a55..7e1b6b89206 100644 --- a/dts/bindings/gpio/richtek,rt1718s.yaml +++ b/dts/bindings/gpio/richtek,rt1718s.yaml @@ -5,7 +5,7 @@ description: | Richtek RT1718S TCPC chip The Richtek RT1718S chip is TCPC, but also has 3 pins, which can be used as - a usual GPIO. This node collects common proprties for RT1718S chip e.g. I2C + a usual GPIO. This node collects common properties for RT1718S chip e.g. I2C address. Feature-specific(GPIO, TCPC) properties should be placed in a child node e.g. a number of GPIOs. diff --git a/dts/bindings/i2c/atmel,sam-i2c-twim.yaml b/dts/bindings/i2c/atmel,sam-i2c-twim.yaml index 1b865d256ca..f18860ed92a 100644 --- a/dts/bindings/i2c/atmel,sam-i2c-twim.yaml +++ b/dts/bindings/i2c/atmel,sam-i2c-twim.yaml @@ -14,7 +14,7 @@ description: | When using speeds above standard mode, user may need adjust clock and data lines slew and strength parameters. In general, slew 0 and minimal strength - is enougth for short buses and light loads. As reference, the below + is enough for short buses and light loads. As reference, the below is the lowest power configuration: std-clk-slew-lim = <0>; diff --git a/dts/bindings/interrupt-controller/cypress,psoc6-intmux.yaml b/dts/bindings/interrupt-controller/cypress,psoc6-intmux.yaml index 982d7b4aa08..3363a35a7fb 100644 --- a/dts/bindings/interrupt-controller/cypress,psoc6-intmux.yaml +++ b/dts/bindings/interrupt-controller/cypress,psoc6-intmux.yaml @@ -28,7 +28,7 @@ description: | ... intmux[7] = {ch31, ch30, ch29, ch28} - In pratical terms, the Cortex-M0+ requires user to define all NVIC interrupt + In practical terms, the Cortex-M0+ requires user to define all NVIC interrupt sources and the proper NVIC interrupt order. With that, the system configures the Cortex-M0+ Interrupt Multiplexer and interrupts can be processed. More information about it at PSoC-6 Architecture Technical Reference Manual, @@ -60,7 +60,7 @@ description: | The interrupt can be enabled/disable at NVIC at line 20 as usual. Notes: - 1) Multiple definitions will generate multiple interrutps + 1) Multiple definitions will generate multiple interrupts 2) The interrupt sources are shared between Cortex-M0+/M4. These means, can trigger action in parallel in both processors. 3) User can change priority at Cortex-M0+ NVIC by changing interrupt channels diff --git a/dts/bindings/interrupt-controller/nuvoton,npcx-miwu.yaml b/dts/bindings/interrupt-controller/nuvoton,npcx-miwu.yaml index 10d9ebc311b..d1319c9b1c2 100644 --- a/dts/bindings/interrupt-controller/nuvoton,npcx-miwu.yaml +++ b/dts/bindings/interrupt-controller/nuvoton,npcx-miwu.yaml @@ -16,7 +16,7 @@ properties: "#miwu-cells": type: int required: true - description: Number of items to present a MIWU input souce specifier + description: Number of items to present a MIWU input source specifier miwu-cells: - group From 13f8cece6ccebefa8942fc95cfd7489112112d97 Mon Sep 17 00:00:00 2001 From: Pisit Sawangvonganan Date: Sun, 28 Jan 2024 20:15:39 +0700 Subject: [PATCH 3148/3723] dts: bindings: fix typo in (bluetooth, can, dac, display) Utilize a code spell-checking tool to scan for and correct spelling errors in all files within the dts/bindings/bluetooth, can, dac and display. Signed-off-by: Pisit Sawangvonganan --- dts/bindings/bluetooth/ambiq,bt-hci-spi.yaml | 4 ++-- dts/bindings/bluetooth/infineon,cyw43xxx-bt-hci.yaml | 6 +++--- dts/bindings/can/microchip,mcp251xfd.yaml | 2 +- dts/bindings/dac/atmel,sam-dac.yaml | 2 +- dts/bindings/display/ilitek,ili9342c.yaml | 2 +- dts/bindings/display/nxp,imx-elcdif.yaml | 2 +- 6 files changed, 9 insertions(+), 9 deletions(-) diff --git a/dts/bindings/bluetooth/ambiq,bt-hci-spi.yaml b/dts/bindings/bluetooth/ambiq,bt-hci-spi.yaml index c939f27841f..752c0d56f26 100644 --- a/dts/bindings/bluetooth/ambiq,bt-hci-spi.yaml +++ b/dts/bindings/bluetooth/ambiq,bt-hci-spi.yaml @@ -27,6 +27,6 @@ properties: type: phandle-array description: | This clkreq gpio is used to send the XO32MHz clock request to host from - from controller. The host needs to enable XO32MHz when receiveing low to - high edge interrupt and disable XO32MHz when receiveing high to low edge + from controller. The host needs to enable XO32MHz when receiving low to + high edge interrupt and disable XO32MHz when receiving high to low edge interrupt. diff --git a/dts/bindings/bluetooth/infineon,cyw43xxx-bt-hci.yaml b/dts/bindings/bluetooth/infineon,cyw43xxx-bt-hci.yaml index e45c7c35983..25213af3ecc 100644 --- a/dts/bindings/bluetooth/infineon,cyw43xxx-bt-hci.yaml +++ b/dts/bindings/bluetooth/infineon,cyw43xxx-bt-hci.yaml @@ -66,10 +66,10 @@ properties: type: int description: | HCI UART boudrate for feature operation. If not defined - bus/current-speed wil be used as default. + bus/current-speed will be used as default. fw-download-speed: type: int description: | - HCI UART boudrate for FW dowload operation. If not defined - bus/current-speed wil be used as default. + HCI UART boudrate for FW download operation. If not defined + bus/current-speed will be used as default. diff --git a/dts/bindings/can/microchip,mcp251xfd.yaml b/dts/bindings/can/microchip,mcp251xfd.yaml index de86c320d30..c6cd1b9f097 100644 --- a/dts/bindings/can/microchip,mcp251xfd.yaml +++ b/dts/bindings/can/microchip,mcp251xfd.yaml @@ -48,7 +48,7 @@ properties: type: boolean description: | Enables controller PLL, which multiples input clock frequency x10. - This parameter also implicity sets whether the clock is from the PLL + This parameter also implicitly sets whether the clock is from the PLL output or directly from the oscillator. If this option is enabled the clock source is the PLL, otherwise its the oscillator. diff --git a/dts/bindings/dac/atmel,sam-dac.yaml b/dts/bindings/dac/atmel,sam-dac.yaml index 6b650d2bec1..6775164363f 100644 --- a/dts/bindings/dac/atmel,sam-dac.yaml +++ b/dts/bindings/dac/atmel,sam-dac.yaml @@ -20,7 +20,7 @@ properties: type: int default: 15 description: | - Peripheral Clock to DAC Clock Ratio. Prescaler value is calcuated as + Peripheral Clock to DAC Clock Ratio. Prescaler value is calculated as PRESCAL = (MCK / DACClock) - 2. Should be in range from 0 to 15. The value will be written to DACC_MR.PRESCALER bit-field. The property is applicable only to SAME70, SAMV71 series devices. diff --git a/dts/bindings/display/ilitek,ili9342c.yaml b/dts/bindings/display/ilitek,ili9342c.yaml index 37cf5999cd9..a2afb6d3983 100644 --- a/dts/bindings/display/ilitek,ili9342c.yaml +++ b/dts/bindings/display/ilitek,ili9342c.yaml @@ -16,7 +16,7 @@ properties: default: [0x01] description: select the desired Gamma curve for the current display. - A maximum of 4 fixed gamma curves canbe selected. + A maximum of 4 fixed gamma curves can be selected. ifmode: type: uint8-array diff --git a/dts/bindings/display/nxp,imx-elcdif.yaml b/dts/bindings/display/nxp,imx-elcdif.yaml index 5f9807bfdcf..a5ef4f13ded 100644 --- a/dts/bindings/display/nxp,imx-elcdif.yaml +++ b/dts/bindings/display/nxp,imx-elcdif.yaml @@ -34,5 +34,5 @@ properties: nxp,pxp: type: phandle description: - NXP PXP device phandle. The LCDIF can utilize the PXP for acclerated + NXP PXP device phandle. The LCDIF can utilize the PXP for accelerated display rotation via the DMA API, when present and enabled. From 9888db155bd607a131db98a5ac0df3e0365a76df Mon Sep 17 00:00:00 2001 From: Pisit Sawangvonganan Date: Sun, 28 Jan 2024 20:19:00 +0700 Subject: [PATCH 3149/3723] dts: bindings: fix typo in (adc, arm) Utilize a code spell-checking tool to scan for and correct spelling errors in all files within the dts/bindings/adc and arm. Signed-off-by: Pisit Sawangvonganan --- dts/bindings/adc/espressif,esp32-adc.yaml | 2 +- dts/bindings/adc/infineon,cat1-adc.yaml | 2 +- dts/bindings/adc/infineon,xmc4xxx-adc.yaml | 2 +- dts/bindings/arm/atmel,samd2x-pm.yaml | 2 +- 4 files changed, 4 insertions(+), 4 deletions(-) diff --git a/dts/bindings/adc/espressif,esp32-adc.yaml b/dts/bindings/adc/espressif,esp32-adc.yaml index 2aedb107c7a..d3907dba640 100644 --- a/dts/bindings/adc/espressif,esp32-adc.yaml +++ b/dts/bindings/adc/espressif,esp32-adc.yaml @@ -14,7 +14,7 @@ description: | Zephyr API is using gain unit to characterize ADC input. To achieve compatibility we choose to select those gain, - which coresponds to the ESP32 ADC attenuation feature. + which corresponds to the ESP32 ADC attenuation feature. ESP32,attenuation ~ zephyr,gain ----------------- ----------- diff --git a/dts/bindings/adc/infineon,cat1-adc.yaml b/dts/bindings/adc/infineon,cat1-adc.yaml index 1cff8da2dd9..7ae64d8845a 100644 --- a/dts/bindings/adc/infineon,cat1-adc.yaml +++ b/dts/bindings/adc/infineon,cat1-adc.yaml @@ -6,7 +6,7 @@ description: | Infineon Cat1 ADC Each ADC group Cat1 is assigned to a Zephyr device. Refer to the Infineon PSoC6 reference - manual (Section Port I/O functions) for the group/chanel mapping to a specific port-pin on + manual (Section Port I/O functions) for the group/channel mapping to a specific port-pin on the board. For example on the cy8cproto_062_4343w P10.0 is mapped to adc0,channel0 and P10.1 is mapped to adc0,channel1. diff --git a/dts/bindings/adc/infineon,xmc4xxx-adc.yaml b/dts/bindings/adc/infineon,xmc4xxx-adc.yaml index 4d1296b1c71..0631ea30367 100644 --- a/dts/bindings/adc/infineon,xmc4xxx-adc.yaml +++ b/dts/bindings/adc/infineon,xmc4xxx-adc.yaml @@ -4,7 +4,7 @@ description: | Infineon XMC4XXX ADC Each ADC group XMC4XXX is assigned to a Zephyr device. Refer to Infineon XMC4XXX reference manual - (Section Port I/O functions) for the group/chanel mapping to a specific port-pin on the board. + (Section Port I/O functions) for the group/channel mapping to a specific port-pin on the board. For example on the xmc45_relax_kit P14.0 is mapped to adc0,channel0 and P14.1 is mapped to adc0,channel1. diff --git a/dts/bindings/arm/atmel,samd2x-pm.yaml b/dts/bindings/arm/atmel,samd2x-pm.yaml index 00dfda33c03..7fa232b815d 100644 --- a/dts/bindings/arm/atmel,samd2x-pm.yaml +++ b/dts/bindings/arm/atmel,samd2x-pm.yaml @@ -1,7 +1,7 @@ # Copyright (c) 2020, Linaro Limited # SPDX-License-Identifier: Apache-2.0 -description: Atmel SAMD2x Power Manger (PM) +description: Atmel SAMD2x Power Manager (PM) compatible: "atmel,samd2x-pm" From d54e027a3867937f3cbe35c0785a77f6845e05f0 Mon Sep 17 00:00:00 2001 From: Pisit Sawangvonganan Date: Mon, 29 Jan 2024 11:04:06 +0700 Subject: [PATCH 3150/3723] dts: bindings: more typo correction and wording enhancement This change reflects further corrections and suggestions from @ajarmouni-st. Signed-off-by: Pisit Sawangvonganan --- dts/bindings/bluetooth/ambiq,bt-hci-spi.yaml | 6 +++--- dts/bindings/can/microchip,mcp251xfd.yaml | 2 +- dts/bindings/clock/st,stm32-rcc.yaml | 2 +- dts/bindings/dma/st,stm32-dma-v2.yaml | 2 +- dts/bindings/i2c/atmel,sam-i2c-twim.yaml | 2 +- dts/bindings/interrupt-controller/cypress,psoc6-intmux.yaml | 6 +++--- dts/bindings/net/wireless/gpio-radio-coex.yaml | 2 +- dts/bindings/power-domain/power-domain-gpio-monitor.yaml | 4 ++-- dts/bindings/rng/st,stm32-rng.yaml | 2 +- dts/bindings/sensor/st,lsm6dsv16x-common.yaml | 2 +- dts/bindings/serial/st,stm32-uart-base.yaml | 2 +- dts/bindings/watchdog/intel,adsp-watchdog.yaml | 2 +- 12 files changed, 17 insertions(+), 17 deletions(-) diff --git a/dts/bindings/bluetooth/ambiq,bt-hci-spi.yaml b/dts/bindings/bluetooth/ambiq,bt-hci-spi.yaml index 752c0d56f26..42df66d2180 100644 --- a/dts/bindings/bluetooth/ambiq,bt-hci-spi.yaml +++ b/dts/bindings/bluetooth/ambiq,bt-hci-spi.yaml @@ -27,6 +27,6 @@ properties: type: phandle-array description: | This clkreq gpio is used to send the XO32MHz clock request to host from - from controller. The host needs to enable XO32MHz when receiving low to - high edge interrupt and disable XO32MHz when receiving high to low edge - interrupt. + controller. The host needs to enable XO32MHz when receiving low to high + edge interrupts and disable XO32MHz when receiving high to low edge + interrupts. diff --git a/dts/bindings/can/microchip,mcp251xfd.yaml b/dts/bindings/can/microchip,mcp251xfd.yaml index c6cd1b9f097..b35cb0fa48a 100644 --- a/dts/bindings/can/microchip,mcp251xfd.yaml +++ b/dts/bindings/can/microchip,mcp251xfd.yaml @@ -47,7 +47,7 @@ properties: pll-enable: type: boolean description: | - Enables controller PLL, which multiples input clock frequency x10. + Enables controller PLL, which multiplies input clock frequency by 10. This parameter also implicitly sets whether the clock is from the PLL output or directly from the oscillator. If this option is enabled the clock source is the PLL, otherwise its diff --git a/dts/bindings/clock/st,stm32-rcc.yaml b/dts/bindings/clock/st,stm32-rcc.yaml index 1f6e487baa5..ebc6b7e84e3 100644 --- a/dts/bindings/clock/st,stm32-rcc.yaml +++ b/dts/bindings/clock/st,stm32-rcc.yaml @@ -51,7 +51,7 @@ description: | ... } In this example, I2C1 device is assigned HSI as domain clock source. - Domain clock is independent from the bus/gatted clock and allows access to the device's + Domain clock is independent from the bus/gated clock and allows access to the device's register while the gated clock is off. As it doesn't feed the peripheral's controller, it allows peripheral operation, but can't be used for peripheral configuration. It is peripheral driver's responsibility to query and use clock source information in diff --git a/dts/bindings/dma/st,stm32-dma-v2.yaml b/dts/bindings/dma/st,stm32-dma-v2.yaml index d3c9edac707..632ff53a90b 100644 --- a/dts/bindings/dma/st,stm32-dma-v2.yaml +++ b/dts/bindings/dma/st,stm32-dma-v2.yaml @@ -19,7 +19,7 @@ description: | or a value between +1 .. + 3. channel-config: A 32bit mask specifying the DMA channel configuration A name custom DMA flags for channel configuration is used - which is device dependent see stm32_dma.h: + which is device dependent. See stm32_dma.h: -bit 5 : DMA cyclic mode config 0x0: STM32_DMA_MODE_NORMAL 0x1: STM32_DMA_MODE_CYCLIC diff --git a/dts/bindings/i2c/atmel,sam-i2c-twim.yaml b/dts/bindings/i2c/atmel,sam-i2c-twim.yaml index f18860ed92a..90c5c6e8388 100644 --- a/dts/bindings/i2c/atmel,sam-i2c-twim.yaml +++ b/dts/bindings/i2c/atmel,sam-i2c-twim.yaml @@ -14,7 +14,7 @@ description: | When using speeds above standard mode, user may need adjust clock and data lines slew and strength parameters. In general, slew 0 and minimal strength - is enough for short buses and light loads. As reference, the below + is enough for short buses and light loads. As a reference, the below is the lowest power configuration: std-clk-slew-lim = <0>; diff --git a/dts/bindings/interrupt-controller/cypress,psoc6-intmux.yaml b/dts/bindings/interrupt-controller/cypress,psoc6-intmux.yaml index 3363a35a7fb..4e9770e65ce 100644 --- a/dts/bindings/interrupt-controller/cypress,psoc6-intmux.yaml +++ b/dts/bindings/interrupt-controller/cypress,psoc6-intmux.yaml @@ -57,12 +57,12 @@ description: | intmux[20 mod 8] |= 0x02 << (20 mod 4); These results in Cortex-M0+ NVIC line 20 handling PSoC-6 interrupt source 2. - The interrupt can be enabled/disable at NVIC at line 20 as usual. + The interrupt can be enabled/disabled at NVIC at line 20 as usual. Notes: 1) Multiple definitions will generate multiple interrupts - 2) The interrupt sources are shared between Cortex-M0+/M4. These means, can - trigger action in parallel in both processors. + 2) The interrupt sources are shared between Cortex-M0+/M4. This means, they + can trigger actions in parallel on both processors. 3) User can change priority at Cortex-M0+ NVIC by changing interrupt channels at interrupt-parent properties. 4) Only the peripherals used by Cortex-M0+ should be configured. diff --git a/dts/bindings/net/wireless/gpio-radio-coex.yaml b/dts/bindings/net/wireless/gpio-radio-coex.yaml index ab453e5652b..1acb8e7f9a9 100644 --- a/dts/bindings/net/wireless/gpio-radio-coex.yaml +++ b/dts/bindings/net/wireless/gpio-radio-coex.yaml @@ -4,7 +4,7 @@ description: | Generic representation of Coexistence pin interface for radios. This interface is usually available on Wifi/Bluetooth/LTE modules to - interact with each other when sharing same antenna. This prevents + interact with each other when sharing the same antenna. This prevents any collisions between transmissions from different modules. The grant signal should signal that the external transceiver/module is not transmitting. Therefore you are free to perform any TX operations as diff --git a/dts/bindings/power-domain/power-domain-gpio-monitor.yaml b/dts/bindings/power-domain/power-domain-gpio-monitor.yaml index ebc9b5b5038..734aab8e6f7 100644 --- a/dts/bindings/power-domain/power-domain-gpio-monitor.yaml +++ b/dts/bindings/power-domain/power-domain-gpio-monitor.yaml @@ -6,8 +6,8 @@ description: | This power domain monitors the state of a GPIO pin to detect whether a power rail is on/off. Therefore, performing resume/suspend on power domain won't - change physical state of power rails and those action won't be triggered on - child nodes. Additionally, due to the asynchronous nature of monitoring a + change physical state of power rails and that action won't be triggered on + child nodes. Additionally, due to the asynchronous nature of monitoring, a pending transaction won't be interrupted by power state change. compatible: "power-domain-gpio-monitor" diff --git a/dts/bindings/rng/st,stm32-rng.yaml b/dts/bindings/rng/st,stm32-rng.yaml index 58d4aea8f8e..c0e6d5e2ec3 100644 --- a/dts/bindings/rng/st,stm32-rng.yaml +++ b/dts/bindings/rng/st,stm32-rng.yaml @@ -19,7 +19,7 @@ properties: <&rcc STM32_SRC_MSI CLK48_SEL(3)> /* RNG clock domain set to MSI */ A correctly configured domain clock is required to allow the integrated low sampling clock detection mechanism to behave properly. - In provided example, MSI should be configured to provide 48Mhz clock. + In the provided example, MSI should be configured to provide 48Mhz clock. nist-config: type: int diff --git a/dts/bindings/sensor/st,lsm6dsv16x-common.yaml b/dts/bindings/sensor/st,lsm6dsv16x-common.yaml index fc1d2c6d592..84c0dce96a7 100644 --- a/dts/bindings/sensor/st,lsm6dsv16x-common.yaml +++ b/dts/bindings/sensor/st,lsm6dsv16x-common.yaml @@ -135,7 +135,7 @@ properties: description: | Specify the default gyro output data rate expressed in samples per second (Hz). The values are taken in accordance to lsm6dsv16x_data_rate_t enumerative in hal/st - module. Please note that this values will not change the operating mode, which will remain + module. Please note that these values will not change the operating mode, which will remain High Performance (device default). Moreover, the values here which will be selected in the DT are the only way to specify the odr accuracy even at runtime with SENSOR_ATTR_SAMPLING_FREQUENCY. diff --git a/dts/bindings/serial/st,stm32-uart-base.yaml b/dts/bindings/serial/st,stm32-uart-base.yaml index 9b4852bbc8c..3c20564bdda 100644 --- a/dts/bindings/serial/st,stm32-uart-base.yaml +++ b/dts/bindings/serial/st,stm32-uart-base.yaml @@ -90,7 +90,7 @@ properties: fifo-enable: type: boolean description: | - Enables transmit and receive FIFO using default FIFO configuration (typically thresholds + Enables transmit and receive FIFO using default FIFO configuration (typically threshold is set to 1/8). In TX, FIFO allows to work in burst mode, easing scheduling of loaded applications. It also allows more reliable communication with UART devices sensitive to variation of inter-frames diff --git a/dts/bindings/watchdog/intel,adsp-watchdog.yaml b/dts/bindings/watchdog/intel,adsp-watchdog.yaml index f8e76ea23fa..495ee67af84 100644 --- a/dts/bindings/watchdog/intel,adsp-watchdog.yaml +++ b/dts/bindings/watchdog/intel,adsp-watchdog.yaml @@ -16,7 +16,7 @@ properties: type: int description: | Clock frequency used by counter in Hz. You can specify a frequency here or specify a clock - using the clocks properties. + using the property "clocks". reset-pulse-length: type: int From 7de2fadaa376ea6e488f8d6c239775136a339bf3 Mon Sep 17 00:00:00 2001 From: Alberto Escolar Piedras Date: Sat, 27 Jan 2024 13:39:42 +0100 Subject: [PATCH 3151/3723] doc: release-notes: Mention removal of global SOURCE definitions Mention that we do not define these macros globally anymore Signed-off-by: Alberto Escolar Piedras --- doc/releases/release-notes-3.6.rst | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/doc/releases/release-notes-3.6.rst b/doc/releases/release-notes-3.6.rst index 60f461d5ce5..3fd9f0d2869 100644 --- a/doc/releases/release-notes-3.6.rst +++ b/doc/releases/release-notes-3.6.rst @@ -147,6 +147,11 @@ Build system and infrastructure * Fixed an issue whereby using some shields with sysbuild would cause a cmake Kconfig error. +* Fixed an issue where the macros ``_POSIX_C_SOURCE`` and ``_XOPEN_SOURCE`` would be defined + globally when building with Picolibc or for the native (``ARCH_POSIX``) targets. + After this change users may need to define them for their own applications or libraries if they + require them. + Drivers and Sensors ******************* From 7d1b3bc083070f1e1af7ae3cd5c58d1f1f77b87e Mon Sep 17 00:00:00 2001 From: Alberto Escolar Piedras Date: Sat, 27 Jan 2024 14:38:02 +0100 Subject: [PATCH 3152/3723] doc: release-notes: native targets related updates Add to the 3.6 release notes the native targets related updates. Signed-off-by: Alberto Escolar Piedras --- doc/releases/release-notes-3.6.rst | 42 +++++++++++++++++++++++++++++- 1 file changed, 41 insertions(+), 1 deletion(-) diff --git a/doc/releases/release-notes-3.6.rst b/doc/releases/release-notes-3.6.rst index 3fd9f0d2869..e317bd1049e 100644 --- a/doc/releases/release-notes-3.6.rst +++ b/doc/releases/release-notes-3.6.rst @@ -104,7 +104,27 @@ Boards & SoC Support * Made these changes for Xtensa boards: -* Made these changes for POSIX boards: +* Made these changes for native/POSIX boards: + + * The :ref:`simulated nrf5340 targets` now include the IPC and MUTEX peripherals, + and support OpenAMP to communicate between the cores. + It is now possible to run the BLE controller or 802.15.4 driver in the net core, and application + and BT host in the app core. + + * The nrf*_bsim simulated targets now include models of the UART peripheral. It is now possible + to connect a :ref:`nrf52_bsim` UART to another, or a UART in loopback, utilizing + both the new and legacy nRFx UART drivers, in any mode. + + * For the native simulator based targets it is now possible to set via Kconfig command line + options which will be handled by the executable as if they were provided from the invoking + shell. + + * For all native boards boards, the native logger backend will also be used even if the UART is + enabled. + + * Several bugfixes and other minor additions to the nRF5x HW models. + + * Multiple documentation updates and fixes for all native boards. * Removed support for these ARC boards: @@ -165,6 +185,8 @@ Drivers and Sensors * Add system call :c:func:`can_get_transceiver()` for getting the CAN transceiver associated with a CAN controller. + * The "native linux" driver now supports being built with embedded C libraries. + * Clock control * Renesas R-Car clock control driver now supports Gen4 SoCs @@ -172,6 +194,10 @@ Drivers and Sensors * Counter + * The nRFx counter driver now works with simulated nrf*_bsim targets. + + * counter_native_posix driver: Added support for top value configuration, and a bugfix. + * DAC * Disk @@ -184,8 +210,13 @@ Drivers and Sensors * Entropy + * The "native_posix" entropy driver now accepts a new command line option ``seed-random``. + When used, the random generator will be seeded from ``/dev/urandom`` + * Ethernet + * The "native_posix" ethernet driver now supports being built with embedded C libraries. + * Flash * ``spi_nor`` driver now sleeps between polls in ``spi_nor_wait_until_ready``. If this is not @@ -424,5 +455,14 @@ Tests and Samples :ref:`native_posix` remains supported and used in testing but will be deprecated in a future release. +* Bluetooth split stacks tests, where the BT host and controller are run in separate MCUs, are + now run in CI based on the :ref:`nrf5340_bsim` targets. + Several other runtime AMP tests based on these targets have been added to CI, including tests + of OpenAMP, the mbox and IPC drivers/subsystem, and the logger multidomain functionality. + +* Runtime UART tests have been added to CI based on the :ref:`nrf52_bsim` target. + These include tests of the nRFx UART driver and networked BT stack tests with the host and + controller in separate devices communicating over the HCI UART driver. + * Fixed an issue in :zephyr:code-sample:`smp-svr` sample whereby if USB was already initialised, application would fail to boot properly. From ed2e7eaefef0ed65dae70ba809b8a0225d5eee15 Mon Sep 17 00:00:00 2001 From: Alberto Escolar Piedras Date: Mon, 29 Jan 2024 15:51:19 +0100 Subject: [PATCH 3153/3723] doc: releases: migration-guide: 3.6: Add note on SOURCE macros Warn users about the SOURCE macros not being defined globally anymore and them needed to set them if they need them. Signed-off-by: Alberto Escolar Piedras --- doc/releases/migration-guide-3.6.rst | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/doc/releases/migration-guide-3.6.rst b/doc/releases/migration-guide-3.6.rst index d8a4c3facbd..e44293b570d 100644 --- a/doc/releases/migration-guide-3.6.rst +++ b/doc/releases/migration-guide-3.6.rst @@ -26,6 +26,16 @@ Build System * The deprecated ``prj_.conf`` Kconfig file support has been removed, projects that use this should switch to using board Kconfig fragments instead (``boards/.conf``). +* Until now ``_POSIX_C_SOURCE``, ``_XOPEN_SOURCE``, and ``_XOPEN_SOURCE_EXTENDED`` were defined + globally when building for the native (``ARCH_POSIX``) targets, and ``_POSIX_C_SOURCE`` when + building with PicolibC. Since this release, these are set only for the files that need them. + If your library or application needed this, you may start getting an "implicit declaration" + warning for functions whose prototypes are only exposed if one of these is defined. + If so, you can fix it by defining the corresponding macro in your C source file before any + include, or by adding the equivalent of + ``target_compile_definitions(app PRIVATE _POSIX_C_SOURCE=200809L)`` to your application + or ``zephyr_library_compile_definitions(_POSIX_C_SOURCE=200809L)`` to your library. + Kernel ====== From 0dcb0518be618140322becc5b2996b1949597890 Mon Sep 17 00:00:00 2001 From: Jordan Yates Date: Sat, 27 Jan 2024 14:26:39 +1000 Subject: [PATCH 3154/3723] ci: update Github actions versions Update Github actions to their latest versions to fix the following warnings on runs: ``` Node.js 16 actions are deprecated. Please update the following actions to use Node.js 20: actions/checkout@v3, actions/cache@v3, actions/upload-artifact@v3. For more information see: https://github.blog/changelog/2023-09-22-github-actions-transitioning-from-node-16-to-node-20/. ``` `actions/checkout` and `actions/cache` are straight Node version upgrades, `actions/upload-artifact` and `actions/download-artifact` have breaking changes, but don't appear to affect our usage. https://github.com/actions/upload-artifact Signed-off-by: Jordan Yates --- .github/workflows/assigner.yml | 2 +- .github/workflows/backport_issue_check.yml | 2 +- .github/workflows/bsim-tests.yaml | 6 +++--- .github/workflows/bug_snapshot.yaml | 2 +- .github/workflows/clang.yaml | 8 ++++---- .github/workflows/codecov.yaml | 10 +++++----- .github/workflows/coding_guidelines.yml | 4 ++-- .github/workflows/compliance.yml | 6 +++--- .github/workflows/daily_test_version.yml | 2 +- .github/workflows/devicetree_checks.yml | 8 ++++---- .github/workflows/doc-build.yml | 16 ++++++++-------- .github/workflows/errno.yml | 2 +- .github/workflows/footprint-tracking.yml | 2 +- .github/workflows/footprint.yml | 2 +- .../workflows/greet_first_time_contributor.yml | 2 +- .github/workflows/issue_count.yml | 2 +- .github/workflows/license_check.yml | 4 ++-- .github/workflows/manifest.yml | 2 +- .github/workflows/pylib_tests.yml | 4 ++-- .github/workflows/release.yml | 4 ++-- .github/workflows/scripts_tests.yml | 4 ++-- .github/workflows/stats_merged_prs.yml | 2 +- .github/workflows/twister.yaml | 14 +++++++------- .github/workflows/twister_tests.yml | 4 ++-- .github/workflows/twister_tests_blackbox.yml | 2 +- .github/workflows/west_cmds.yml | 8 ++++---- 26 files changed, 62 insertions(+), 62 deletions(-) diff --git a/.github/workflows/assigner.yml b/.github/workflows/assigner.yml index b1a53fc93e4..6e4e01c8ea1 100644 --- a/.github/workflows/assigner.yml +++ b/.github/workflows/assigner.yml @@ -28,7 +28,7 @@ jobs: pip3 install -U PyGithub>=1.55 west - name: Check out source code - uses: actions/checkout@v3 + uses: actions/checkout@v4 - name: Run assignment script env: diff --git a/.github/workflows/backport_issue_check.yml b/.github/workflows/backport_issue_check.yml index a66edd318f7..95175ecf1bb 100644 --- a/.github/workflows/backport_issue_check.yml +++ b/.github/workflows/backport_issue_check.yml @@ -13,7 +13,7 @@ jobs: steps: - name: Check out source code - uses: actions/checkout@v3 + uses: actions/checkout@v4 - name: Install Python dependencies run: | diff --git a/.github/workflows/bsim-tests.yaml b/.github/workflows/bsim-tests.yaml index c62c75c5ec0..b8b34315772 100644 --- a/.github/workflows/bsim-tests.yaml +++ b/.github/workflows/bsim-tests.yaml @@ -62,7 +62,7 @@ jobs: git remote set-url origin ${GITHUB_SERVER_URL}/${GITHUB_REPOSITORY} - name: Checkout - uses: actions/checkout@v3 + uses: actions/checkout@v4 with: fetch-depth: 0 @@ -191,7 +191,7 @@ jobs: - name: Upload Test Results if: always() - uses: actions/upload-artifact@v3 + uses: actions/upload-artifact@v4 with: name: bsim-test-results path: | @@ -207,7 +207,7 @@ jobs: - name: Upload Event Details if: always() - uses: actions/upload-artifact@v3 + uses: actions/upload-artifact@v4 with: name: event path: | diff --git a/.github/workflows/bug_snapshot.yaml b/.github/workflows/bug_snapshot.yaml index d19f881ddcd..16b251b7f2f 100644 --- a/.github/workflows/bug_snapshot.yaml +++ b/.github/workflows/bug_snapshot.yaml @@ -21,7 +21,7 @@ jobs: steps: - name: Checkout - uses: actions/checkout@v3 + uses: actions/checkout@v4 - name: Install Python dependencies run: | diff --git a/.github/workflows/clang.yaml b/.github/workflows/clang.yaml index dd1d0687d63..caebd7feda1 100644 --- a/.github/workflows/clang.yaml +++ b/.github/workflows/clang.yaml @@ -41,7 +41,7 @@ jobs: git remote set-url origin ${GITHUB_SERVER_URL}/${GITHUB_REPOSITORY} - name: Checkout - uses: actions/checkout@v3 + uses: actions/checkout@v4 with: ref: ${{ github.event.pull_request.head.sha }} fetch-depth: 0 @@ -126,7 +126,7 @@ jobs: - name: Upload Unit Test Results if: always() && steps.twister.outputs.report_needed != 0 - uses: actions/upload-artifact@v3 + uses: actions/upload-artifact@v4 with: name: Unit Test Results (Subset ${{ matrix.platform }}) path: twister-out/twister.xml @@ -138,7 +138,7 @@ jobs: if: (success() || failure() ) && needs.clang-build.outputs.report_needed != 0 steps: - name: Download Artifacts - uses: actions/download-artifact@v3 + uses: actions/download-artifact@v4 with: path: artifacts - name: Merge Test Results @@ -149,7 +149,7 @@ jobs: - name: Upload Unit Test Results in HTML if: always() - uses: actions/upload-artifact@v3 + uses: actions/upload-artifact@v4 with: name: HTML Unit Test Results if-no-files-found: ignore diff --git a/.github/workflows/codecov.yaml b/.github/workflows/codecov.yaml index 9a2add5aeb4..6924c7e587e 100644 --- a/.github/workflows/codecov.yaml +++ b/.github/workflows/codecov.yaml @@ -41,7 +41,7 @@ jobs: git remote set-url origin ${GITHUB_SERVER_URL}/${GITHUB_REPOSITORY} - name: checkout - uses: actions/checkout@v3 + uses: actions/checkout@v4 with: fetch-depth: 0 @@ -104,7 +104,7 @@ jobs: - name: Upload Coverage Results if: always() - uses: actions/upload-artifact@v3 + uses: actions/upload-artifact@v4 with: name: Coverage Data (Subset ${{ matrix.platform }}) path: coverage/reports/${{ matrix.platform }}.json @@ -118,11 +118,11 @@ jobs: steps: - name: checkout - uses: actions/checkout@v3 + uses: actions/checkout@v4 with: fetch-depth: 0 - name: Download Artifacts - uses: actions/download-artifact@v3 + uses: actions/download-artifact@v4 with: path: coverage/reports @@ -166,7 +166,7 @@ jobs: - name: Upload Merged Coverage Results if: always() - uses: actions/upload-artifact@v3 + uses: actions/upload-artifact@v4 with: name: Merged Coverage Data path: | diff --git a/.github/workflows/coding_guidelines.yml b/.github/workflows/coding_guidelines.yml index c810a22415e..1bc6ee2e666 100644 --- a/.github/workflows/coding_guidelines.yml +++ b/.github/workflows/coding_guidelines.yml @@ -8,13 +8,13 @@ jobs: name: Run coding guidelines checks on patch series (PR) steps: - name: Checkout the code - uses: actions/checkout@v3 + uses: actions/checkout@v4 with: ref: ${{ github.event.pull_request.head.sha }} fetch-depth: 0 - name: cache-pip - uses: actions/cache@v3 + uses: actions/cache@v4 with: path: ~/.cache/pip key: ${{ runner.os }}-pip-${{ hashFiles('.github/workflows/coding_guidelines.yml') }} diff --git a/.github/workflows/compliance.yml b/.github/workflows/compliance.yml index 95414359c85..219fbfae607 100644 --- a/.github/workflows/compliance.yml +++ b/.github/workflows/compliance.yml @@ -12,13 +12,13 @@ jobs: echo "$HOME/.local/bin" >> $GITHUB_PATH - name: Checkout the code - uses: actions/checkout@v3 + uses: actions/checkout@v4 with: ref: ${{ github.event.pull_request.head.sha }} fetch-depth: 0 - name: cache-pip - uses: actions/cache@v3 + uses: actions/cache@v4 with: path: ~/.cache/pip key: ${{ runner.os }}-pip-${{ hashFiles('.github/workflows/compliance.yml') }} @@ -61,7 +61,7 @@ jobs: -c origin/${BASE_REF}.. - name: upload-results - uses: actions/upload-artifact@v3 + uses: actions/upload-artifact@v4 continue-on-error: true with: name: compliance.xml diff --git a/.github/workflows/daily_test_version.yml b/.github/workflows/daily_test_version.yml index ba02bb68975..31e9fcde9b8 100644 --- a/.github/workflows/daily_test_version.yml +++ b/.github/workflows/daily_test_version.yml @@ -28,7 +28,7 @@ jobs: pip3 install gitpython - name: checkout - uses: actions/checkout@v3 + uses: actions/checkout@v4 with: fetch-depth: 0 diff --git a/.github/workflows/devicetree_checks.yml b/.github/workflows/devicetree_checks.yml index b2d73453b28..c8408f68c09 100644 --- a/.github/workflows/devicetree_checks.yml +++ b/.github/workflows/devicetree_checks.yml @@ -35,14 +35,14 @@ jobs: python-version: 3.6 steps: - name: checkout - uses: actions/checkout@v3 + uses: actions/checkout@v4 - name: Set up Python ${{ matrix.python-version }} uses: actions/setup-python@v4 with: python-version: ${{ matrix.python-version }} - name: cache-pip-linux if: startsWith(runner.os, 'Linux') - uses: actions/cache@v3 + uses: actions/cache@v4 with: path: ~/.cache/pip key: ${{ runner.os }}-pip-${{ matrix.python-version }} @@ -50,7 +50,7 @@ jobs: ${{ runner.os }}-pip-${{ matrix.python-version }} - name: cache-pip-mac if: startsWith(runner.os, 'macOS') - uses: actions/cache@v3 + uses: actions/cache@v4 with: path: ~/Library/Caches/pip # Trailing '-' was just to get a different cache name @@ -59,7 +59,7 @@ jobs: ${{ runner.os }}-pip-${{ matrix.python-version }}- - name: cache-pip-win if: startsWith(runner.os, 'Windows') - uses: actions/cache@v3 + uses: actions/cache@v4 with: path: ~\AppData\Local\pip\Cache key: ${{ runner.os }}-pip-${{ matrix.python-version }} diff --git a/.github/workflows/doc-build.yml b/.github/workflows/doc-build.yml index fa83fe252c7..9dde3128477 100644 --- a/.github/workflows/doc-build.yml +++ b/.github/workflows/doc-build.yml @@ -44,7 +44,7 @@ jobs: steps: - name: checkout - uses: actions/checkout@v3 + uses: actions/checkout@v4 with: ref: ${{ github.event.pull_request.head.sha }} fetch-depth: 0 @@ -70,7 +70,7 @@ jobs: echo "${PWD}/doxygen-${DOXYGEN_VERSION}/bin" >> $GITHUB_PATH - name: cache-pip - uses: actions/cache@v3 + uses: actions/cache@v4 with: path: ~/.cache/pip key: pip-${{ hashFiles('doc/requirements.txt') }} @@ -116,13 +116,13 @@ jobs: tar cfJ api-coverage.tar.xz coverage-report - name: upload-build - uses: actions/upload-artifact@v3 + uses: actions/upload-artifact@v4 with: name: html-output path: html-output.tar.xz - name: upload-api-coverage - uses: actions/upload-artifact@v3 + uses: actions/upload-artifact@v4 with: name: api-coverage path: api-coverage.tar.xz @@ -142,7 +142,7 @@ jobs: echo "API Coverage Report will be available shortly at: ${API_COVERAGE_URL}" >> $GITHUB_STEP_SUMMARY - name: upload-pr-number - uses: actions/upload-artifact@v3 + uses: actions/upload-artifact@v4 if: github.event_name == 'pull_request' with: name: pr_num @@ -166,7 +166,7 @@ jobs: git config --global --add safe.directory ${GITHUB_WORKSPACE} - name: checkout - uses: actions/checkout@v3 + uses: actions/checkout@v4 - name: install-pkgs run: | @@ -174,7 +174,7 @@ jobs: apt-get install -y python3-pip python3-venv ninja-build doxygen graphviz librsvg2-bin - name: cache-pip - uses: actions/cache@v3 + uses: actions/cache@v4 with: path: ~/.cache/pip key: pip-${{ hashFiles('doc/requirements.txt') }} @@ -210,7 +210,7 @@ jobs: - name: upload-build if: always() - uses: actions/upload-artifact@v3 + uses: actions/upload-artifact@v4 with: name: pdf-output if-no-files-found: ignore diff --git a/.github/workflows/errno.yml b/.github/workflows/errno.yml index 629e09bfca3..78e8b8e8ed6 100644 --- a/.github/workflows/errno.yml +++ b/.github/workflows/errno.yml @@ -22,7 +22,7 @@ jobs: git config --global --add safe.directory ${GITHUB_WORKSPACE} - name: checkout - uses: actions/checkout@v3 + uses: actions/checkout@v4 - name: Environment Setup run: | diff --git a/.github/workflows/footprint-tracking.yml b/.github/workflows/footprint-tracking.yml index a1b12d30eff..9b90cff1f9e 100644 --- a/.github/workflows/footprint-tracking.yml +++ b/.github/workflows/footprint-tracking.yml @@ -51,7 +51,7 @@ jobs: sudo pip3 install -U setuptools wheel pip gitpython - name: checkout - uses: actions/checkout@v3 + uses: actions/checkout@v4 with: ref: ${{ github.event.pull_request.head.sha }} fetch-depth: 0 diff --git a/.github/workflows/footprint.yml b/.github/workflows/footprint.yml index 89b57239bbe..2b907618082 100644 --- a/.github/workflows/footprint.yml +++ b/.github/workflows/footprint.yml @@ -31,7 +31,7 @@ jobs: echo "$HOME/.local/bin" >> $GITHUB_PATH - name: checkout - uses: actions/checkout@v3 + uses: actions/checkout@v4 with: ref: ${{ github.event.pull_request.head.sha }} fetch-depth: 0 diff --git a/.github/workflows/greet_first_time_contributor.yml b/.github/workflows/greet_first_time_contributor.yml index 13584774a54..5f62c03d6de 100644 --- a/.github/workflows/greet_first_time_contributor.yml +++ b/.github/workflows/greet_first_time_contributor.yml @@ -12,7 +12,7 @@ jobs: if: github.repository == 'zephyrproject-rtos/zephyr' steps: - - uses: actions/checkout@v3 + - uses: actions/checkout@v4 - uses: zephyrproject-rtos/action-first-interaction@v1.1.1-zephyr-5 with: repo-token: ${{ secrets.GITHUB_TOKEN }} diff --git a/.github/workflows/issue_count.yml b/.github/workflows/issue_count.yml index 9c143dbd1f4..f44ef5531d4 100644 --- a/.github/workflows/issue_count.yml +++ b/.github/workflows/issue_count.yml @@ -35,7 +35,7 @@ jobs: token: ${{ secrets.GITHUB_TOKEN }} - name: upload-stats - uses: actions/upload-artifact@v3 + uses: actions/upload-artifact@v4 continue-on-error: true with: name: ${{ env.OUTPUT_FILE_NAME }} diff --git a/.github/workflows/license_check.yml b/.github/workflows/license_check.yml index 0efedb13489..7d2d083faae 100644 --- a/.github/workflows/license_check.yml +++ b/.github/workflows/license_check.yml @@ -8,7 +8,7 @@ jobs: name: Scan code for licenses steps: - name: Checkout the code - uses: actions/checkout@v3 + uses: actions/checkout@v4 with: fetch-depth: 0 - name: Scan the code @@ -17,7 +17,7 @@ jobs: with: directory-to-scan: 'scan/' - name: Artifact Upload - uses: actions/upload-artifact@v3 + uses: actions/upload-artifact@v4 with: name: scancode path: ./artifacts diff --git a/.github/workflows/manifest.yml b/.github/workflows/manifest.yml index fcae7973996..040ec957e39 100644 --- a/.github/workflows/manifest.yml +++ b/.github/workflows/manifest.yml @@ -8,7 +8,7 @@ jobs: name: Manifest steps: - name: Checkout the code - uses: actions/checkout@v3 + uses: actions/checkout@v4 with: path: zephyrproject/zephyr ref: ${{ github.event.pull_request.head.sha }} diff --git a/.github/workflows/pylib_tests.yml b/.github/workflows/pylib_tests.yml index 4368a66d04f..70bd107f8e5 100644 --- a/.github/workflows/pylib_tests.yml +++ b/.github/workflows/pylib_tests.yml @@ -29,14 +29,14 @@ jobs: os: [ubuntu-22.04] steps: - name: checkout - uses: actions/checkout@v3 + uses: actions/checkout@v4 - name: Set up Python ${{ matrix.python-version }} uses: actions/setup-python@v4 with: python-version: ${{ matrix.python-version }} - name: cache-pip-linux if: startsWith(runner.os, 'Linux') - uses: actions/cache@v3 + uses: actions/cache@v4 with: path: ~/.cache/pip key: ${{ runner.os }}-pip-${{ matrix.python-version }} diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index ab0e9384ae7..ccecd17df80 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -10,7 +10,7 @@ jobs: release: runs-on: ubuntu-22.04 steps: - - uses: actions/checkout@v3 + - uses: actions/checkout@v4 with: fetch-depth: 0 @@ -26,7 +26,7 @@ jobs: args: spdx -o zephyr-${{ steps.get_version.outputs.VERSION }}.spdx - name: upload-results - uses: actions/upload-artifact@v3 + uses: actions/upload-artifact@v4 continue-on-error: true with: name: zephyr-${{ steps.get_version.outputs.VERSION }}.spdx diff --git a/.github/workflows/scripts_tests.yml b/.github/workflows/scripts_tests.yml index 7c1a2887ae6..2e2356910b1 100644 --- a/.github/workflows/scripts_tests.yml +++ b/.github/workflows/scripts_tests.yml @@ -29,7 +29,7 @@ jobs: os: [ubuntu-20.04] steps: - name: checkout - uses: actions/checkout@v3 + uses: actions/checkout@v4 with: ref: ${{ github.event.pull_request.head.sha }} fetch-depth: 0 @@ -52,7 +52,7 @@ jobs: - name: cache-pip-linux if: startsWith(runner.os, 'Linux') - uses: actions/cache@v3 + uses: actions/cache@v4 with: path: ~/.cache/pip key: ${{ runner.os }}-pip-${{ matrix.python-version }} diff --git a/.github/workflows/stats_merged_prs.yml b/.github/workflows/stats_merged_prs.yml index db1b6f37e5d..cd874b65b1a 100644 --- a/.github/workflows/stats_merged_prs.yml +++ b/.github/workflows/stats_merged_prs.yml @@ -12,7 +12,7 @@ jobs: runs-on: ubuntu-22.04 steps: - name: checkout - uses: actions/checkout@v3 + uses: actions/checkout@v4 - name: PR event env: GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} diff --git a/.github/workflows/twister.yaml b/.github/workflows/twister.yaml index 6d8c7dfdee5..7f65178e103 100644 --- a/.github/workflows/twister.yaml +++ b/.github/workflows/twister.yaml @@ -59,7 +59,7 @@ jobs: - name: Checkout if: github.event_name == 'pull_request_target' - uses: actions/checkout@v3 + uses: actions/checkout@v4 with: ref: ${{ github.event.pull_request.head.sha }} fetch-depth: 0 @@ -156,7 +156,7 @@ jobs: git remote set-url origin ${GITHUB_SERVER_URL}/${GITHUB_REPOSITORY} - name: Checkout - uses: actions/checkout@v3 + uses: actions/checkout@v4 with: ref: ${{ github.event.pull_request.head.sha }} fetch-depth: 0 @@ -271,7 +271,7 @@ jobs: - name: Upload Unit Test Results if: always() - uses: actions/upload-artifact@v3 + uses: actions/upload-artifact@v4 with: name: Unit Test Results (Subset ${{ matrix.subset }}) if-no-files-found: ignore @@ -293,7 +293,7 @@ jobs: - if: matrix.subset == 1 && github.event_name == 'push' name: Upload the list of Python packages - uses: actions/upload-artifact@v3 + uses: actions/upload-artifact@v4 with: name: Frozen PIP package set path: | @@ -313,13 +313,13 @@ jobs: # Needed for opensearch and upload script - if: github.event_name == 'push' || github.event_name == 'schedule' name: Checkout - uses: actions/checkout@v3 + uses: actions/checkout@v4 with: fetch-depth: 0 persist-credentials: false - name: Download Artifacts - uses: actions/download-artifact@v3 + uses: actions/download-artifact@v4 with: path: artifacts @@ -345,7 +345,7 @@ jobs: - name: Upload Unit Test Results in HTML if: always() - uses: actions/upload-artifact@v3 + uses: actions/upload-artifact@v4 with: name: HTML Unit Test Results if-no-files-found: ignore diff --git a/.github/workflows/twister_tests.yml b/.github/workflows/twister_tests.yml index 606c49dfdf9..2d7bc4ac06f 100644 --- a/.github/workflows/twister_tests.yml +++ b/.github/workflows/twister_tests.yml @@ -33,14 +33,14 @@ jobs: os: [ubuntu-22.04] steps: - name: checkout - uses: actions/checkout@v3 + uses: actions/checkout@v4 - name: Set up Python ${{ matrix.python-version }} uses: actions/setup-python@v4 with: python-version: ${{ matrix.python-version }} - name: cache-pip-linux if: startsWith(runner.os, 'Linux') - uses: actions/cache@v3 + uses: actions/cache@v4 with: path: ~/.cache/pip key: ${{ runner.os }}-pip-${{ matrix.python-version }} diff --git a/.github/workflows/twister_tests_blackbox.yml b/.github/workflows/twister_tests_blackbox.yml index 9ea454f8e59..3811b9b3fb8 100644 --- a/.github/workflows/twister_tests_blackbox.yml +++ b/.github/workflows/twister_tests_blackbox.yml @@ -34,7 +34,7 @@ jobs: git config --global --add safe.directory ${GITHUB_WORKSPACE} - name: Checkout - uses: actions/checkout@v3 + uses: actions/checkout@v4 - name: Environment Setup run: | diff --git a/.github/workflows/west_cmds.yml b/.github/workflows/west_cmds.yml index 4a3c1964643..25a5fc88fd6 100644 --- a/.github/workflows/west_cmds.yml +++ b/.github/workflows/west_cmds.yml @@ -36,14 +36,14 @@ jobs: python-version: 3.6 steps: - name: checkout - uses: actions/checkout@v3 + uses: actions/checkout@v4 - name: Set up Python ${{ matrix.python-version }} uses: actions/setup-python@v4 with: python-version: ${{ matrix.python-version }} - name: cache-pip-linux if: startsWith(runner.os, 'Linux') - uses: actions/cache@v3 + uses: actions/cache@v4 with: path: ~/.cache/pip key: ${{ runner.os }}-pip-${{ matrix.python-version }} @@ -51,7 +51,7 @@ jobs: ${{ runner.os }}-pip-${{ matrix.python-version }} - name: cache-pip-mac if: startsWith(runner.os, 'macOS') - uses: actions/cache@v3 + uses: actions/cache@v4 with: path: ~/Library/Caches/pip # Trailing '-' was just to get a different cache name @@ -60,7 +60,7 @@ jobs: ${{ runner.os }}-pip-${{ matrix.python-version }}- - name: cache-pip-win if: startsWith(runner.os, 'Windows') - uses: actions/cache@v3 + uses: actions/cache@v4 with: path: ~\AppData\Local\pip\Cache key: ${{ runner.os }}-pip-${{ matrix.python-version }} From 9ff1fcf7e7d752519b8a770800e837ab3c3c77ea Mon Sep 17 00:00:00 2001 From: Jordan Yates Date: Sat, 27 Jan 2024 12:59:03 +1000 Subject: [PATCH 3155/3723] net: conn_mgr: generic wifi_mgmt connectivity backend As connectivity backends need to be bound in the same file that the `net_if` is created in, define a common backend type for WiFi modems. All WiFi modems should be controllable through the `wifi_mgmt` API, so there should be no need for dedicated context. When enabled, the particular implementation to be used is chosen through `CONNECTIVITY_WIFI_MGMT_IMPL`. For now, the only choice is an application defined backend. Signed-off-by: Jordan Yates --- .../net/conn_mgr/connectivity_wifi_mgmt.h | 40 +++++++++++++++++++ subsys/net/conn_mgr/Kconfig | 19 +++++++++ 2 files changed, 59 insertions(+) create mode 100644 include/zephyr/net/conn_mgr/connectivity_wifi_mgmt.h diff --git a/include/zephyr/net/conn_mgr/connectivity_wifi_mgmt.h b/include/zephyr/net/conn_mgr/connectivity_wifi_mgmt.h new file mode 100644 index 00000000000..88ef775ad1e --- /dev/null +++ b/include/zephyr/net/conn_mgr/connectivity_wifi_mgmt.h @@ -0,0 +1,40 @@ +/* + * Copyright (c) 2024 CSIRO + * + * SPDX-License-Identifier: Apache-2.0 + */ + +/** + * @file + * @brief Connectivity implementation for drivers exposing the wifi_mgmt API + */ + +#ifndef ZEPHYR_INCLUDE_CONN_MGR_CONNECTIVITY_WIFI_MGMT_H_ +#define ZEPHYR_INCLUDE_CONN_MGR_CONNECTIVITY_WIFI_MGMT_H_ + +#include + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * Context type for generic WIFI_MGMT connectivity backend. + */ +#define CONNECTIVITY_WIFI_MGMT_CTX_TYPE void * + +/** + * @brief Associate the generic WIFI_MGMT implementation with a network device + * + * @param dev_id Network device id. + */ +#define CONNECTIVITY_WIFI_MGMT_BIND(dev_id) \ + IF_ENABLED(CONFIG_NET_CONNECTION_MANAGER_CONNECTIVITY_WIFI_MGMT, \ + (CONN_MGR_CONN_DECLARE_PUBLIC(CONNECTIVITY_WIFI_MGMT); \ + CONN_MGR_BIND_CONN(dev_id, CONNECTIVITY_WIFI_MGMT))) + +#ifdef __cplusplus +} +#endif + +#endif /* ZEPHYR_INCLUDE_CONN_MGR_CONNECTIVITY_WIFI_MGMT_H_ */ diff --git a/subsys/net/conn_mgr/Kconfig b/subsys/net/conn_mgr/Kconfig index e72e614d54c..683634de987 100644 --- a/subsys/net/conn_mgr/Kconfig +++ b/subsys/net/conn_mgr/Kconfig @@ -39,4 +39,23 @@ config NET_CONNECTION_MANAGER_AUTO_IF_DOWN bool "Automatically call net_if_down on ifaces that have given up on connecting" default y +config NET_CONNECTION_MANAGER_CONNECTIVITY_WIFI_MGMT + bool "Generic WiFi management connectivity implementation" + depends on NET_L2_WIFI_MGMT + help + Enable CONNECTIVITY_WIFI_MGMT connectivity bindings on WiFi drivers. + Which implementation is compiled is controlled via CONNECTIVITY_WIFI_MGMT_IMPL. + +choice CONNECTIVITY_WIFI_MGMT_IMPL + prompt "Implementation of the generic wifi_mgmt connectivity backend" + depends on NET_CONNECTION_MANAGER_CONNECTIVITY_WIFI_MGMT + default CONNECTIVITY_WIFI_MGMT_APPLICATION + +config CONNECTIVITY_WIFI_MGMT_APPLICATION + bool "Application specific implementation of the connectivity backend" + help + The application defines its own implementation of CONNECTIVITY_WIFI_MGMT. + +endchoice + endif # NET_CONNECTION_MANAGER From ef21569ac9158fe5fed5d768c8a3766ca5293bdf Mon Sep 17 00:00:00 2001 From: Jordan Yates Date: Sun, 21 Jan 2024 21:38:43 +1000 Subject: [PATCH 3156/3723] wifi: conn_mgr connectivity bindings Bind WiFi network devices to the generic WiFi connectivity backend if the appropriate option is set. Signed-off-by: Jordan Yates --- drivers/wifi/esp32/src/esp_wifi_drv.c | 3 +++ drivers/wifi/esp_at/esp.c | 3 +++ drivers/wifi/eswifi/eswifi_core.c | 3 +++ drivers/wifi/infineon/airoc_wifi.c | 3 +++ drivers/wifi/simplelink/simplelink.c | 3 +++ drivers/wifi/winc1500/wifi_winc1500.c | 3 +++ 6 files changed, 18 insertions(+) diff --git a/drivers/wifi/esp32/src/esp_wifi_drv.c b/drivers/wifi/esp32/src/esp_wifi_drv.c index 24266a9abad..2e86ef39552 100644 --- a/drivers/wifi/esp32/src/esp_wifi_drv.c +++ b/drivers/wifi/esp32/src/esp_wifi_drv.c @@ -13,6 +13,7 @@ LOG_MODULE_REGISTER(esp32_wifi, CONFIG_WIFI_LOG_LEVEL); #include #include #include +#include #include #include #include "esp_networking_priv.h" @@ -672,3 +673,5 @@ NET_DEVICE_DT_INST_DEFINE(0, &esp32_data, NULL, CONFIG_WIFI_INIT_PRIORITY, &esp32_api, ETHERNET_L2, NET_L2_GET_CTX_TYPE(ETHERNET_L2), NET_ETH_MTU); + +CONNECTIVITY_WIFI_MGMT_BIND(Z_DEVICE_DT_DEV_ID(DT_DRV_INST(0))); diff --git a/drivers/wifi/esp_at/esp.c b/drivers/wifi/esp_at/esp.c index bd410bd6dcc..e71a9b2bc1c 100644 --- a/drivers/wifi/esp_at/esp.c +++ b/drivers/wifi/esp_at/esp.c @@ -25,6 +25,7 @@ LOG_MODULE_REGISTER(wifi_esp_at, CONFIG_WIFI_LOG_LEVEL); #include #include #include +#include #include "esp.h" @@ -1284,6 +1285,8 @@ NET_DEVICE_DT_INST_OFFLOAD_DEFINE(0, esp_init, NULL, CONFIG_WIFI_INIT_PRIORITY, &esp_api, ESP_MTU); +CONNECTIVITY_WIFI_MGMT_BIND(Z_DEVICE_DT_DEV_ID(DT_DRV_INST(0))); + static int esp_init(const struct device *dev) { #if DT_INST_NODE_HAS_PROP(0, power_gpios) || DT_INST_NODE_HAS_PROP(0, reset_gpios) diff --git a/drivers/wifi/eswifi/eswifi_core.c b/drivers/wifi/eswifi/eswifi_core.c index 0beecd4a4fc..82f24982d1a 100644 --- a/drivers/wifi/eswifi/eswifi_core.c +++ b/drivers/wifi/eswifi/eswifi_core.c @@ -23,6 +23,7 @@ LOG_MODULE_REGISTER(LOG_MODULE_NAME); #include #include #include +#include #include #include @@ -806,3 +807,5 @@ NET_DEVICE_DT_INST_OFFLOAD_DEFINE(0, eswifi_init, NULL, CONFIG_WIFI_INIT_PRIORITY, &eswifi_offload_api, 1500); + +CONNECTIVITY_WIFI_MGMT_BIND(Z_DEVICE_DT_DEV_ID(DT_DRV_INST(0))); diff --git a/drivers/wifi/infineon/airoc_wifi.c b/drivers/wifi/infineon/airoc_wifi.c index c0c780822d8..752e6c9048a 100644 --- a/drivers/wifi/infineon/airoc_wifi.c +++ b/drivers/wifi/infineon/airoc_wifi.c @@ -12,6 +12,7 @@ #define DT_DRV_COMPAT infineon_airoc_wifi #include +#include #include LOG_MODULE_REGISTER(infineon_airoc_wifi, CONFIG_WIFI_LOG_LEVEL); @@ -770,3 +771,5 @@ static const struct net_wifi_mgmt_offload airoc_api = { NET_DEVICE_DT_INST_DEFINE(0, airoc_init, NULL, &airoc_wifi_data, &airoc_wifi_config, CONFIG_WIFI_INIT_PRIORITY, &airoc_api, ETHERNET_L2, NET_L2_GET_CTX_TYPE(ETHERNET_L2), WHD_LINK_MTU); + +CONNECTIVITY_WIFI_MGMT_BIND(Z_DEVICE_DT_DEV_ID(DT_DRV_INST(0))); diff --git a/drivers/wifi/simplelink/simplelink.c b/drivers/wifi/simplelink/simplelink.c index 6e89275ee6f..c4af70ce003 100644 --- a/drivers/wifi/simplelink/simplelink.c +++ b/drivers/wifi/simplelink/simplelink.c @@ -12,6 +12,7 @@ LOG_MODULE_REGISTER(LOG_MODULE_NAME); #include #include #include +#include #ifdef CONFIG_NET_SOCKETS_OFFLOAD #include #endif @@ -302,3 +303,5 @@ NET_DEVICE_OFFLOAD_INIT(simplelink, CONFIG_WIFI_SIMPLELINK_NAME, &simplelink_data, NULL, CONFIG_WIFI_INIT_PRIORITY, &simplelink_api, CONFIG_WIFI_SIMPLELINK_MAX_PACKET_SIZE); + +CONNECTIVITY_WIFI_MGMT_BIND(simplelink); diff --git a/drivers/wifi/winc1500/wifi_winc1500.c b/drivers/wifi/winc1500/wifi_winc1500.c index 95d97fcfeaa..588a2e3e0dc 100644 --- a/drivers/wifi/winc1500/wifi_winc1500.c +++ b/drivers/wifi/winc1500/wifi_winc1500.c @@ -21,6 +21,7 @@ LOG_MODULE_REGISTER(LOG_MODULE_NAME); #include #include #include +#include #include @@ -1187,3 +1188,5 @@ NET_DEVICE_OFFLOAD_INIT(winc1500, CONFIG_WIFI_WINC1500_NAME, winc1500_init, NULL, &w1500_data, NULL, CONFIG_WIFI_INIT_PRIORITY, &winc1500_api, CONFIG_WIFI_WINC1500_MAX_PACKET_SIZE); + +CONNECTIVITY_WIFI_MGMT_BIND(winc1500); From 651ffb1d0687e2b197110f8aa7c92c42dee21a47 Mon Sep 17 00:00:00 2001 From: Jordan Yates Date: Sat, 27 Jan 2024 13:15:39 +1000 Subject: [PATCH 3157/3723] tests: build_all: modem: test compilation with connectivity Ensure WiFi modems still build with the `CONNECTIVITY_WIFI_MGMT` connectivity backend enabled. Signed-off-by: Jordan Yates --- tests/drivers/build_all/modem/modem_esp_at.conf | 2 ++ tests/drivers/build_all/modem/src/main.c | 12 ++++++++++++ 2 files changed, 14 insertions(+) diff --git a/tests/drivers/build_all/modem/modem_esp_at.conf b/tests/drivers/build_all/modem/modem_esp_at.conf index 6ba79c82653..e24bee337af 100644 --- a/tests/drivers/build_all/modem/modem_esp_at.conf +++ b/tests/drivers/build_all/modem/modem_esp_at.conf @@ -5,3 +5,5 @@ CONFIG_NETWORKING=y CONFIG_NET_SOCKETS=y CONFIG_NET_IPV4=y CONFIG_WIFI=y +CONFIG_NET_CONNECTION_MANAGER=y +CONFIG_NET_CONNECTION_MANAGER_CONNECTIVITY_WIFI_MGMT=y diff --git a/tests/drivers/build_all/modem/src/main.c b/tests/drivers/build_all/modem/src/main.c index 90b910a7799..527f64e3f1e 100644 --- a/tests/drivers/build_all/modem/src/main.c +++ b/tests/drivers/build_all/modem/src/main.c @@ -8,3 +8,15 @@ int main(void) { return 0; } + +#ifdef CONFIG_CONNECTIVITY_WIFI_MGMT_APPLICATION + +#include +#include + +/* Bind L2 connectity APIs. */ +static struct conn_mgr_conn_api conn_api = { 0 }; + +CONN_MGR_CONN_DEFINE(CONNECTIVITY_WIFI_MGMT, &conn_api); + +#endif /* CONFIG_CONNECTIVITY_WIFI_MGMT_APPLICATION */ From 739ec3072b4108446c7fe142b95d685a0c1f7621 Mon Sep 17 00:00:00 2001 From: Mykola Kvach Date: Sat, 27 Jan 2024 01:24:38 +0200 Subject: [PATCH 3158/3723] drivers: serial: add missed binding for xen dom0 consoleio driver Add missed binding and appropriate changes for Xen Dom0/Dom0less UART driver. Signed-off-by: Mykola Kvach --- drivers/serial/Kconfig.xen | 2 +- drivers/serial/uart_hvc_xen_consoleio.c | 6 ++++-- dts/bindings/serial/xen,hvc-consoleio.yaml | 5 +++++ snippets/xen_dom0/xen_dom0.overlay | 2 +- 4 files changed, 11 insertions(+), 4 deletions(-) create mode 100644 dts/bindings/serial/xen,hvc-consoleio.yaml diff --git a/drivers/serial/Kconfig.xen b/drivers/serial/Kconfig.xen index 471e5eb7269..02492e7483f 100644 --- a/drivers/serial/Kconfig.xen +++ b/drivers/serial/Kconfig.xen @@ -18,7 +18,7 @@ config UART_XEN_HVC config UART_XEN_HVC_CONSOLEIO bool "Xen hypervisor consoleio UART driver" select SERIAL_HAS_DRIVER - depends on XEN_DOM0 || XEN_DOM0LESS + depends on DT_HAS_XEN_HVC_CONSOLEIO_ENABLED && (XEN_DOM0 || XEN_DOM0LESS) default y help Enable Xen hypervisor console driver. Used for Zephyr as diff --git a/drivers/serial/uart_hvc_xen_consoleio.c b/drivers/serial/uart_hvc_xen_consoleio.c index d60289565a8..97e411a9306 100644 --- a/drivers/serial/uart_hvc_xen_consoleio.c +++ b/drivers/serial/uart_hvc_xen_consoleio.c @@ -17,6 +17,8 @@ #include #include +#define DT_DRV_COMPAT xen_hvc_consoleio + static int xen_consoleio_poll_in(const struct device *dev, unsigned char *c) { @@ -44,12 +46,12 @@ static const struct uart_driver_api xen_consoleio_hvc_api = { .poll_out = xen_consoleio_poll_out, }; -int xen_consoleio_init(const struct device *dev) +static int xen_consoleio_init(const struct device *dev) { /* Nothing to do, but still needed for device API */ return 0; } -DEVICE_DT_DEFINE(DT_NODELABEL(xen_consoleio_hvc), xen_consoleio_init, NULL, NULL, +DEVICE_DT_INST_DEFINE(0, xen_consoleio_init, NULL, NULL, NULL, PRE_KERNEL_1, CONFIG_XEN_HVC_INIT_PRIORITY, &xen_consoleio_hvc_api); diff --git a/dts/bindings/serial/xen,hvc-consoleio.yaml b/dts/bindings/serial/xen,hvc-consoleio.yaml new file mode 100644 index 00000000000..720dc4e7377 --- /dev/null +++ b/dts/bindings/serial/xen,hvc-consoleio.yaml @@ -0,0 +1,5 @@ +description: Xen Dom0/Dom0less Platform HVC ConsoleIO + +compatible: "xen,hvc-consoleio" + +include: uart-controller.yaml diff --git a/snippets/xen_dom0/xen_dom0.overlay b/snippets/xen_dom0/xen_dom0.overlay index 98fe1e39d67..74642eb6b82 100644 --- a/snippets/xen_dom0/xen_dom0.overlay +++ b/snippets/xen_dom0/xen_dom0.overlay @@ -19,7 +19,7 @@ }; xen_consoleio_hvc: hvc { - compatible = "xen,uart_hvc"; + compatible = "xen,hvc-consoleio"; status = "okay"; }; }; From 1826e22334b395d768241b7519d22ff79e8b0ecd Mon Sep 17 00:00:00 2001 From: Lukasz Mrugala Date: Tue, 30 Jan 2024 07:14:33 +0000 Subject: [PATCH 3159/3723] .github: workflows: Add test trigger for pytest harness Pytest twister harness tests have been added to the twister_tests.yml workflow some time ago. However, the $ZEPHYR_BASE/scripts/pylib/pytest-twister-harness/** has not been monitored by the automatic GitHub Action triggers of that workflow. This change adds monitoring for the relevant files. Signed-off-by: Lukasz Mrugala --- .github/workflows/twister_tests.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/twister_tests.yml b/.github/workflows/twister_tests.yml index 2d7bc4ac06f..92de15b81b0 100644 --- a/.github/workflows/twister_tests.yml +++ b/.github/workflows/twister_tests.yml @@ -9,7 +9,7 @@ on: - main - v*-branch paths: - - 'scripts/pylib/twister/**' + - 'scripts/pylib/**' - 'scripts/twister' - 'scripts/tests/twister/**' - '.github/workflows/twister_tests.yml' @@ -18,7 +18,7 @@ on: - main - v*-branch paths: - - 'scripts/pylib/twister/**' + - 'scripts/pylib/**' - 'scripts/twister' - 'scripts/tests/twister/**' - '.github/workflows/twister_tests.yml' From 69787dad1778aceecc185cf3bc454b969d71608c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Benjamin=20Cab=C3=A9?= Date: Wed, 24 Jan 2024 12:07:10 +0100 Subject: [PATCH 3160/3723] doc: Clean up list of Fedora dependencies MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Fixed several issues with the install instructions for Fedora: - removed packages that are already pulled by "Development Tools" and "C Development Tools and Libraries" groups - added missing "which" package needed for SDK installation script - added python3-devel package (needed for some of the Python requirements) and install python3 instead of a fixed python38 Tested on a vanilla Fedora 39 Docker image. Signed-off-by: Benjamin Cabé --- doc/develop/getting_started/installation_linux.rst | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/doc/develop/getting_started/installation_linux.rst b/doc/develop/getting_started/installation_linux.rst index 4638eded332..6ef50b6d45a 100644 --- a/doc/develop/getting_started/installation_linux.rst +++ b/doc/develop/getting_started/installation_linux.rst @@ -86,9 +86,8 @@ need one. .. code-block:: console sudo dnf group install "Development Tools" "C Development Tools and Libraries" - sudo dnf install git cmake ninja-build gperf ccache dfu-util dtc wget \ - python3-pip python3-tkinter xz file glibc-devel.i686 libstdc++-devel.i686 python38 \ - SDL2-devel + sudo dnf install cmake ninja-build gperf dfu-util dtc wget which \ + python3-pip python3-tkinter xz file python3-devel SDL2-devel .. group-tab:: Clear Linux From cdcb853a98541df953442ac9bd880adc4d854f39 Mon Sep 17 00:00:00 2001 From: Lukasz Mrugala Date: Fri, 19 Jan 2024 12:34:36 +0000 Subject: [PATCH 3161/3723] scripts: pylib: twister: Fix --save-tests help As saving tests writes to file, rather than appending to it, we should indicate that in the --save-tests help. --load-tests help changed so its grammar is the same as --save-tests's. Signed-off-by: Lukasz Mrugala --- scripts/pylib/twister/twisterlib/environment.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/scripts/pylib/twister/twisterlib/environment.py b/scripts/pylib/twister/twisterlib/environment.py index 42e48b6abe0..03f6ab7f430 100644 --- a/scripts/pylib/twister/twisterlib/environment.py +++ b/scripts/pylib/twister/twisterlib/environment.py @@ -86,14 +86,14 @@ def add_parse_arguments(parser = None): "--save-tests", metavar="FILENAME", action="store", - help="Append list of tests and platforms to be run to file.") + help="Write a list of tests and platforms to be run to file.") case_select.add_argument( "-F", "--load-tests", metavar="FILENAME", action="store", - help="Load list of tests and platforms to be run from file.") + help="Load a list of tests and platforms to be run from file.") case_select.add_argument( "-T", "--testsuite-root", action="append", default=[], From 88568a3283f09354957adb2121c2f4464395a682 Mon Sep 17 00:00:00 2001 From: Abhinav Srivastava Date: Fri, 26 Jan 2024 03:37:36 -0500 Subject: [PATCH 3162/3723] posix: add headers for stropts Minimal header for stropts Signed-off-by: Abhinav Srivastava --- include/zephyr/posix/stropts.h | 25 +++++++++++++++++++++++++ 1 file changed, 25 insertions(+) create mode 100644 include/zephyr/posix/stropts.h diff --git a/include/zephyr/posix/stropts.h b/include/zephyr/posix/stropts.h new file mode 100644 index 00000000000..dd8988f9a72 --- /dev/null +++ b/include/zephyr/posix/stropts.h @@ -0,0 +1,25 @@ +/* + * Copyright (c) 2024 Abhinav Srivastava + * + * SPDX-License-Identifier: Apache-2.0 + */ +#ifndef ZEPHYR_INCLUDE_POSIX_STROPTS_H_ +#define ZEPHYR_INCLUDE_POSIX_STROPTS_H_ + +#ifdef __cplusplus +extern "C" { +#endif + +struct strbuf { + int maxlen; + int len; + char *buf; +}; + +int putmsg(int fildes, const struct strbuf *ctlptr, const struct strbuf *dataptr, int flags); + +#ifdef __cplusplus +} +#endif + +#endif /* ZEPHYR_INCLUDE_POSIX_STROPTS_H_ */ From 93e9491dd9226211b8c74fa0e6dd348f0086f67a Mon Sep 17 00:00:00 2001 From: Abhinav Srivastava Date: Fri, 26 Jan 2024 03:42:58 -0500 Subject: [PATCH 3163/3723] posix: putmsg implementation and configurations Add needed KConfig, CMakeList and Stropts.c Signed-off-by: Abhinav Srivastava --- lib/posix/CMakeLists.txt | 2 +- lib/posix/Kconfig | 1 + lib/posix/Kconfig.stropts | 9 +++++++++ lib/posix/stropts.c | 20 ++++++++++++++++++++ 4 files changed, 31 insertions(+), 1 deletion(-) create mode 100644 lib/posix/Kconfig.stropts create mode 100644 lib/posix/stropts.c diff --git a/lib/posix/CMakeLists.txt b/lib/posix/CMakeLists.txt index 5477e27b386..5d822bd375a 100644 --- a/lib/posix/CMakeLists.txt +++ b/lib/posix/CMakeLists.txt @@ -57,7 +57,7 @@ zephyr_library_sources_ifdef(CONFIG_PTHREAD_RWLOCK rwlock.c) zephyr_library_sources_ifdef(CONFIG_POSIX_PRIORITY_SCHEDULING sched.c) zephyr_library_sources_ifdef(CONFIG_PTHREAD_IPC semaphore.c) zephyr_library_sources_ifdef(CONFIG_PTHREAD_SPINLOCK spinlock.c) -zephyr_library_sources_ifdef(CONFIG_TIMER timer.c) +zephyr_library_sources_ifdef(CONFIG_POSIX_PUTMSG stropts.c) zephyr_library_include_directories( ${ZEPHYR_BASE}/kernel/include diff --git a/lib/posix/Kconfig b/lib/posix/Kconfig index b7a75e7933c..b2f379be8d1 100644 --- a/lib/posix/Kconfig +++ b/lib/posix/Kconfig @@ -75,6 +75,7 @@ source "lib/posix/Kconfig.signal" source "lib/posix/Kconfig.spinlock" source "lib/posix/Kconfig.timer" source "lib/posix/Kconfig.uname" +source "lib/posix/Kconfig.stropts" rsource "shell/Kconfig" diff --git a/lib/posix/Kconfig.stropts b/lib/posix/Kconfig.stropts new file mode 100644 index 00000000000..347f0f33c15 --- /dev/null +++ b/lib/posix/Kconfig.stropts @@ -0,0 +1,9 @@ +# copyright (c) 2024 Abhinav Srivastava +# +# SPDX-License-Identifier: Apache-2.0 + +config POSIX_PUTMSG + bool "Support for putmsg function" + default y if POSIX_API + help + This option provides support for the putmsg function used in message passing. diff --git a/lib/posix/stropts.c b/lib/posix/stropts.c new file mode 100644 index 00000000000..54fca00cc9f --- /dev/null +++ b/lib/posix/stropts.c @@ -0,0 +1,20 @@ +/* + * Copyright (c) 2024 Abhinav Srivastava + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include +#include +#include + +int putmsg(int fildes, const struct strbuf *ctlptr, const struct strbuf *dataptr, int flags) +{ + ARG_UNUSED(fildes); + ARG_UNUSED(ctlptr); + ARG_UNUSED(dataptr); + ARG_UNUSED(flags); + + errno = ENOSYS; + return -1; +} From 52485876f07d387b3170a2c5e1113415e8462a87 Mon Sep 17 00:00:00 2001 From: Abhinav Srivastava Date: Sun, 28 Jan 2024 23:49:24 -0500 Subject: [PATCH 3164/3723] posix: Add tests for stropts Add tests, Fix config issues, Re-add Timer Signed-off-by: Abhinav Srivastava --- include/zephyr/posix/stropts.h | 1 + lib/posix/CMakeLists.txt | 1 + tests/posix/common/src/stropts.c | 21 +++++++++++++++++++++ tests/posix/headers/src/stropts_h.c | 28 ++++++++++++++++++++++++++++ 4 files changed, 51 insertions(+) create mode 100644 tests/posix/common/src/stropts.c create mode 100644 tests/posix/headers/src/stropts_h.c diff --git a/include/zephyr/posix/stropts.h b/include/zephyr/posix/stropts.h index dd8988f9a72..9474c36edb2 100644 --- a/include/zephyr/posix/stropts.h +++ b/include/zephyr/posix/stropts.h @@ -5,6 +5,7 @@ */ #ifndef ZEPHYR_INCLUDE_POSIX_STROPTS_H_ #define ZEPHYR_INCLUDE_POSIX_STROPTS_H_ +#define RS_HIPRI BIT(0) #ifdef __cplusplus extern "C" { diff --git a/lib/posix/CMakeLists.txt b/lib/posix/CMakeLists.txt index 5d822bd375a..c8d836f5846 100644 --- a/lib/posix/CMakeLists.txt +++ b/lib/posix/CMakeLists.txt @@ -57,6 +57,7 @@ zephyr_library_sources_ifdef(CONFIG_PTHREAD_RWLOCK rwlock.c) zephyr_library_sources_ifdef(CONFIG_POSIX_PRIORITY_SCHEDULING sched.c) zephyr_library_sources_ifdef(CONFIG_PTHREAD_IPC semaphore.c) zephyr_library_sources_ifdef(CONFIG_PTHREAD_SPINLOCK spinlock.c) +zephyr_library_sources_ifdef(CONFIG_TIMER timer.c) zephyr_library_sources_ifdef(CONFIG_POSIX_PUTMSG stropts.c) zephyr_library_include_directories( diff --git a/tests/posix/common/src/stropts.c b/tests/posix/common/src/stropts.c new file mode 100644 index 00000000000..4c9221a398c --- /dev/null +++ b/tests/posix/common/src/stropts.c @@ -0,0 +1,21 @@ +/* + * Copyright (c) 2024 Abhinav Srivastava + * + * SPDX-License-Identifier: Apache-2.0 + */ +#include +#include +#include + +ZTEST(stropts, test_putmsg) +{ + const struct strbuf *ctrl = NULL; + const struct strbuf *data = NULL; + int fd = -1; + int ret = putmsg(fd, ctrl, data, 0); + + zassert_equal(ret, -1, "Expected return value -1, got %d", ret); + zassert_equal(errno, ENOSYS, "Expected errno ENOSYS, got %d", errno); +} + +ZTEST_SUITE(stropts, NULL, NULL, NULL, NULL, NULL); diff --git a/tests/posix/headers/src/stropts_h.c b/tests/posix/headers/src/stropts_h.c new file mode 100644 index 00000000000..a095c83c98c --- /dev/null +++ b/tests/posix/headers/src/stropts_h.c @@ -0,0 +1,28 @@ +/* + * Copyright (c) 2024 Abhinav Srivastava + * + * SPDX-License-Identifier: Apache-2.0 + */ +#include "_common.h" +#ifdef CONFIG_POSIX_API +#include +#else +#include +#endif + +/** + * @brief Test existence and basic functionality of stropts.h + * + * @see stropts.h + */ +ZTEST(posix_headers, test_stropts_h) +{ + #ifdef CONFIG_POSIX_API + zassert_not_null((void *)putmsg, "putmsg is null"); + + zassert_true(sizeof(((struct strbuf *)0)->maxlen) > 0, "maxlen size is 0"); + zassert_true(sizeof(((struct strbuf *)0)->len) > 0, "len size is 0"); + zassert_true(sizeof(((struct strbuf *)0)->buf) > 0, "buf size is 0"); + zassert_not_equal(RS_HIPRI, ~RS_HIPRI); + #endif +} From b3e67cf2a62b01fbf9f4c0eb618cd676b4dc3072 Mon Sep 17 00:00:00 2001 From: Jonathan Rico Date: Fri, 12 Jan 2024 08:48:51 +0100 Subject: [PATCH 3165/3723] Bluetooth: L2CAP: document error values of `bt_l2cap_chan_send()` They're still subject to change. At least now the users have some idea of what's happening. Signed-off-by: Jonathan Rico --- include/zephyr/bluetooth/l2cap.h | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/include/zephyr/bluetooth/l2cap.h b/include/zephyr/bluetooth/l2cap.h index d4046c431fb..dfd01dcc455 100644 --- a/include/zephyr/bluetooth/l2cap.h +++ b/include/zephyr/bluetooth/l2cap.h @@ -594,6 +594,13 @@ int bt_l2cap_chan_disconnect(struct bt_l2cap_chan *chan); * case of an error the caller retains the ownership of the buffer. * * @return 0 in case of success or negative value in case of error. + * @return -EINVAL if `buf` or `chan` is NULL. + * @return -EINVAL if `chan` is not either BR/EDR or LE credit-based. + * @return -EINVAL if buffer doesn't have enough bytes reserved to fit header. + * @return -EMSGSIZE if `buf` is larger than `chan`'s MTU. + * @return -ENOTCONN if underlying conn is disconnected. + * @return -ESHUTDOWN if L2CAP channel is disconnected. + * @return -other (from lower layers) if chan is BR/EDR. */ int bt_l2cap_chan_send(struct bt_l2cap_chan *chan, struct net_buf *buf); From 11c83e79831fc352f81f2e7b25749cdc047ed8b5 Mon Sep 17 00:00:00 2001 From: Sven Ginka Date: Sat, 27 Jan 2024 21:41:18 +0100 Subject: [PATCH 3166/3723] west.yml: update hal_atmel to include qdec SAME70b fix This update fixes the qdec in SAME70b, which could not be compiled prior to this fix, due to missing TC_CMR definitions. Moreover it fixes #65432. Signed-off-by: Sven Ginka --- west.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/west.yml b/west.yml index dff0e29705c..7b478c011fb 100644 --- a/west.yml +++ b/west.yml @@ -147,7 +147,7 @@ manifest: groups: - hal - name: hal_atmel - revision: b0cc87f2a494d8b3c383292d1d6c7d10323932bd + revision: aad79bf530b69b72712d18873df4120ad052d921 path: modules/hal/atmel groups: - hal From 69d7c2a6849a42c075eee2eb829617b99937bcad Mon Sep 17 00:00:00 2001 From: Sven Ginka Date: Wed, 22 Nov 2023 15:02:21 +0100 Subject: [PATCH 3167/3723] device-tree: sam_70_xplained: added config for qdec the device tree offers a default config (qdec0) for 1x qdec at TC0, however does not offer a default config for qdec1 - qdec3. this will be added with this commit. Fixes #65610 Signed-off-by: Sven Ginka --- .../sam_e70_xplained-pinctrl.dtsi | 21 ++++++++++++++++ .../arm/sam_e70_xplained/sam_e70_xplained.dts | 24 +++++++++++++++++++ 2 files changed, 45 insertions(+) diff --git a/boards/arm/sam_e70_xplained/sam_e70_xplained-pinctrl.dtsi b/boards/arm/sam_e70_xplained/sam_e70_xplained-pinctrl.dtsi index 2007cbe95b8..e41db2f1c55 100644 --- a/boards/arm/sam_e70_xplained/sam_e70_xplained-pinctrl.dtsi +++ b/boards/arm/sam_e70_xplained/sam_e70_xplained-pinctrl.dtsi @@ -83,6 +83,27 @@ }; }; + tc1_qdec_default: tc1_qdec_default { + group1 { + pinmux = , + ; + }; + }; + + tc2_qdec_default: tc2_qdec_default { + group1 { + pinmux = , + ; + }; + }; + + tc3_qdec_default: tc3_qdec_default { + group1 { + pinmux = , + ; + }; + }; + twihs0_default: twihs0_default { group1 { pinmux = , diff --git a/boards/arm/sam_e70_xplained/sam_e70_xplained.dts b/boards/arm/sam_e70_xplained/sam_e70_xplained.dts index 968b19e7562..ee002c846fa 100644 --- a/boards/arm/sam_e70_xplained/sam_e70_xplained.dts +++ b/boards/arm/sam_e70_xplained/sam_e70_xplained.dts @@ -23,3 +23,27 @@ pinctrl-0 = <&tc0_qdec_default>; pinctrl-names = "default"; }; + +&tc1 { + status = "disabled"; + compatible = "atmel,sam-tc-qdec"; + + pinctrl-0 = <&tc1_qdec_default>; + pinctrl-names = "default"; +}; + +&tc2 { + status = "disabled"; + compatible = "atmel,sam-tc-qdec"; + + pinctrl-0 = <&tc2_qdec_default>; + pinctrl-names = "default"; +}; + +&tc3 { + status = "disabled"; + compatible = "atmel,sam-tc-qdec"; + + pinctrl-0 = <&tc3_qdec_default>; + pinctrl-names = "default"; +}; From c592690649283bd01decfb7a500228579c791654 Mon Sep 17 00:00:00 2001 From: Filip Kokosinski Date: Tue, 16 Jan 2024 13:46:53 +0100 Subject: [PATCH 3168/3723] dts/bindings: move RISC-V cores bindings to `dts/bindings/cpu/` This commit moves the bindings of RISC-V cores from `dts/bindings/riscv` to `dts/bindings/cpu`. This change aligns the bindings of RISC-V cores with other architectures. Signed-off-by: Filip Kokosinski --- dts/bindings/{riscv => cpu}/riscv,cpus.yaml | 0 dts/bindings/{riscv => cpu}/sifive,e24.yaml | 0 dts/bindings/{riscv => cpu}/sifive,e31.yaml | 0 dts/bindings/{riscv => cpu}/sifive,e51.yaml | 0 dts/bindings/{riscv => cpu}/sifive,s7.yaml | 0 dts/bindings/{riscv => cpu}/sifive-common.yaml | 0 6 files changed, 0 insertions(+), 0 deletions(-) rename dts/bindings/{riscv => cpu}/riscv,cpus.yaml (100%) rename dts/bindings/{riscv => cpu}/sifive,e24.yaml (100%) rename dts/bindings/{riscv => cpu}/sifive,e31.yaml (100%) rename dts/bindings/{riscv => cpu}/sifive,e51.yaml (100%) rename dts/bindings/{riscv => cpu}/sifive,s7.yaml (100%) rename dts/bindings/{riscv => cpu}/sifive-common.yaml (100%) diff --git a/dts/bindings/riscv/riscv,cpus.yaml b/dts/bindings/cpu/riscv,cpus.yaml similarity index 100% rename from dts/bindings/riscv/riscv,cpus.yaml rename to dts/bindings/cpu/riscv,cpus.yaml diff --git a/dts/bindings/riscv/sifive,e24.yaml b/dts/bindings/cpu/sifive,e24.yaml similarity index 100% rename from dts/bindings/riscv/sifive,e24.yaml rename to dts/bindings/cpu/sifive,e24.yaml diff --git a/dts/bindings/riscv/sifive,e31.yaml b/dts/bindings/cpu/sifive,e31.yaml similarity index 100% rename from dts/bindings/riscv/sifive,e31.yaml rename to dts/bindings/cpu/sifive,e31.yaml diff --git a/dts/bindings/riscv/sifive,e51.yaml b/dts/bindings/cpu/sifive,e51.yaml similarity index 100% rename from dts/bindings/riscv/sifive,e51.yaml rename to dts/bindings/cpu/sifive,e51.yaml diff --git a/dts/bindings/riscv/sifive,s7.yaml b/dts/bindings/cpu/sifive,s7.yaml similarity index 100% rename from dts/bindings/riscv/sifive,s7.yaml rename to dts/bindings/cpu/sifive,s7.yaml diff --git a/dts/bindings/riscv/sifive-common.yaml b/dts/bindings/cpu/sifive-common.yaml similarity index 100% rename from dts/bindings/riscv/sifive-common.yaml rename to dts/bindings/cpu/sifive-common.yaml From 17670be2cca6f146d7d2e9d81b215cb35871ee4c Mon Sep 17 00:00:00 2001 From: Filip Kokosinski Date: Fri, 19 Jan 2024 08:55:34 +0100 Subject: [PATCH 3169/3723] dts/riscv: remove the `timebase-frequency` property The `timebase-frequency` is not defined by any of the YAML binding files. There was a discussion in #37420 to add this property, but in the end it was rejected. This resulted in the #37685 feature request being created. As of now, this property is not documented anywhere so this commit removes it from the RISC-V devicetrees, as RISC-V is the only architecture that is currently defining it - and even in RISC-V not all platforms do that. Signed-off-by: Filip Kokosinski --- dts/riscv/andes/andes_v5_ae350.dtsi | 1 - dts/riscv/efinix/sapphire_soc.dtsi | 1 - dts/riscv/lowrisc/opentitan_earlgrey.dtsi | 1 - dts/riscv/riscv32-litex-vexriscv.dtsi | 1 - dts/riscv/starfive/starfive_jh7100_beagle_v.dtsi | 1 - dts/riscv/virt.dtsi | 1 - 6 files changed, 6 deletions(-) diff --git a/dts/riscv/andes/andes_v5_ae350.dtsi b/dts/riscv/andes/andes_v5_ae350.dtsi index 8c008634ddf..5f040b45f40 100644 --- a/dts/riscv/andes/andes_v5_ae350.dtsi +++ b/dts/riscv/andes/andes_v5_ae350.dtsi @@ -15,7 +15,6 @@ cpus { #address-cells = <1>; #size-cells = <0>; - timebase-frequency = <60000000>; CPU0: cpu@0 { compatible = "riscv"; device_type = "cpu"; diff --git a/dts/riscv/efinix/sapphire_soc.dtsi b/dts/riscv/efinix/sapphire_soc.dtsi index 75043c9dfbb..675d2f9dd6f 100644 --- a/dts/riscv/efinix/sapphire_soc.dtsi +++ b/dts/riscv/efinix/sapphire_soc.dtsi @@ -32,7 +32,6 @@ reg = <0>; riscv,isa = "rv32ima_zicsr_zifencei"; status = "okay"; - timebase-frequency = <100000000>; hlic: interrupt-controller { compatible = "riscv,cpu-intc"; diff --git a/dts/riscv/lowrisc/opentitan_earlgrey.dtsi b/dts/riscv/lowrisc/opentitan_earlgrey.dtsi index 2df96d71eeb..3e6b30b38f7 100644 --- a/dts/riscv/lowrisc/opentitan_earlgrey.dtsi +++ b/dts/riscv/lowrisc/opentitan_earlgrey.dtsi @@ -12,7 +12,6 @@ cpus { #address-cells = <0x01>; #size-cells = <0x00>; - timebase-frequency = <10000000>; cpu@0 { device_type = "cpu"; diff --git a/dts/riscv/riscv32-litex-vexriscv.dtsi b/dts/riscv/riscv32-litex-vexriscv.dtsi index 3eefacccf6d..d85bccab0ae 100644 --- a/dts/riscv/riscv32-litex-vexriscv.dtsi +++ b/dts/riscv/riscv32-litex-vexriscv.dtsi @@ -25,7 +25,6 @@ reg = <0>; riscv,isa = "rv32ima_zicsr_zifencei"; status = "okay"; - timebase-frequency = <32768>; }; }; soc { diff --git a/dts/riscv/starfive/starfive_jh7100_beagle_v.dtsi b/dts/riscv/starfive/starfive_jh7100_beagle_v.dtsi index c355ac89a5f..c36ea625b02 100644 --- a/dts/riscv/starfive/starfive_jh7100_beagle_v.dtsi +++ b/dts/riscv/starfive/starfive_jh7100_beagle_v.dtsi @@ -16,7 +16,6 @@ cpus: cpus { #address-cells = <1>; #size-cells = <0>; - timebase-frequency = <6250000>; compatible = "starfive,fu74-g000"; cpu@0 { clock-frequency = <0>; diff --git a/dts/riscv/virt.dtsi b/dts/riscv/virt.dtsi index caef8cb28d3..20873731c6e 100644 --- a/dts/riscv/virt.dtsi +++ b/dts/riscv/virt.dtsi @@ -36,7 +36,6 @@ cpus { #address-cells = < 0x01 >; #size-cells = < 0x00 >; - timebase-frequency = < 10000000 >; cpu@0 { device_type = "cpu"; From 28c7674c668774f62504cc4bbcfdb8edede885e4 Mon Sep 17 00:00:00 2001 From: Filip Kokosinski Date: Tue, 16 Jan 2024 13:53:22 +0100 Subject: [PATCH 3170/3723] dts/riscv: add `riscv` compatible string where it's missing This commit adds the `riscv` compatible string to cpu nodes where it is currently missing. This is convention is already followed by some cpu nodes. Signed-off-by: Filip Kokosinski --- dts/riscv/espressif/esp32c3/esp32c3_common.dtsi | 2 +- dts/riscv/gd/gd32vf103.dtsi | 2 +- dts/riscv/ite/it8xxx2.dtsi | 2 +- dts/riscv/neorv32.dtsi | 2 +- dts/riscv/niosv/niosv-g.dtsi | 2 +- dts/riscv/niosv/niosv-m.dtsi | 2 +- dts/riscv/sifive/riscv32-fe310.dtsi | 2 +- dts/riscv/sifive/riscv64-fu540.dtsi | 2 +- dts/riscv/sifive/riscv64-fu740.dtsi | 10 +++++----- 9 files changed, 13 insertions(+), 13 deletions(-) diff --git a/dts/riscv/espressif/esp32c3/esp32c3_common.dtsi b/dts/riscv/espressif/esp32c3/esp32c3_common.dtsi index 3b2bb6d0781..caee77fc6ef 100644 --- a/dts/riscv/espressif/esp32c3/esp32c3_common.dtsi +++ b/dts/riscv/espressif/esp32c3/esp32c3_common.dtsi @@ -31,7 +31,7 @@ cpu0: cpu@0 { device_type = "cpu"; - compatible = "espressif,riscv"; + compatible = "espressif,riscv", "riscv"; riscv,isa = "rv32imc_zicsr"; reg = <0>; cpu-power-states = <&light_sleep &deep_sleep>; diff --git a/dts/riscv/gd/gd32vf103.dtsi b/dts/riscv/gd/gd32vf103.dtsi index b52aee61fbc..a631cd4ab18 100644 --- a/dts/riscv/gd/gd32vf103.dtsi +++ b/dts/riscv/gd/gd32vf103.dtsi @@ -23,7 +23,7 @@ cpu: cpu@0 { clock-frequency = ; - compatible = "nuclei,bumblebee"; + compatible = "nuclei,bumblebee", "riscv"; riscv,isa = "rv32imac_zicsr_zifencei"; reg = <0>; }; diff --git a/dts/riscv/ite/it8xxx2.dtsi b/dts/riscv/ite/it8xxx2.dtsi index 454e9c0c177..faa16fbaefe 100644 --- a/dts/riscv/ite/it8xxx2.dtsi +++ b/dts/riscv/ite/it8xxx2.dtsi @@ -28,7 +28,7 @@ #address-cells = <1>; #size-cells = <0>; cpu0: cpu@0 { - compatible = "ite,riscv-ite"; + compatible = "ite,riscv-ite", "riscv"; riscv,isa = "rv32imafc_zifencei"; device_type = "cpu"; reg = <0>; diff --git a/dts/riscv/neorv32.dtsi b/dts/riscv/neorv32.dtsi index 429d4372418..31fb06b1c49 100644 --- a/dts/riscv/neorv32.dtsi +++ b/dts/riscv/neorv32.dtsi @@ -19,7 +19,7 @@ #size-cells = <0>; cpu0: cpu@0 { - compatible = "neorv32-cpu"; + compatible = "neorv32-cpu", "riscv"; riscv,isa = "rv32imc_zicsr"; reg = <0>; device_type = "cpu"; diff --git a/dts/riscv/niosv/niosv-g.dtsi b/dts/riscv/niosv/niosv-g.dtsi index 90869676f2b..2022e984ff5 100644 --- a/dts/riscv/niosv/niosv-g.dtsi +++ b/dts/riscv/niosv/niosv-g.dtsi @@ -17,7 +17,7 @@ #size-cells = <0>; cpu0: cpu@0 { device_type = "cpu"; - compatible = "intel,niosv"; + compatible = "intel,niosv", "riscv"; riscv,isa = "rv32ima_zicsr_zifencei"; reg = <0>; clock-frequency = <50000000>; diff --git a/dts/riscv/niosv/niosv-m.dtsi b/dts/riscv/niosv/niosv-m.dtsi index 88f8042383c..e6594a23546 100644 --- a/dts/riscv/niosv/niosv-m.dtsi +++ b/dts/riscv/niosv/niosv-m.dtsi @@ -17,7 +17,7 @@ #size-cells = <0>; cpu0: cpu@0 { device_type = "cpu"; - compatible = "intel,niosv"; + compatible = "intel,niosv", "riscv"; riscv,isa = "rv32ia_zicsr_zifencei"; reg = <0>; clock-frequency = <50000000>; diff --git a/dts/riscv/sifive/riscv32-fe310.dtsi b/dts/riscv/sifive/riscv32-fe310.dtsi index c028db37c4e..f2128e1d37b 100644 --- a/dts/riscv/sifive/riscv32-fe310.dtsi +++ b/dts/riscv/sifive/riscv32-fe310.dtsi @@ -27,7 +27,7 @@ #address-cells = <1>; #size-cells = <0>; cpu: cpu@0 { - compatible = "sifive,e31"; + compatible = "sifive,e31", "riscv"; device_type = "cpu"; reg = <0>; riscv,isa = "rv32imac_zicsr_zifencei"; diff --git a/dts/riscv/sifive/riscv64-fu540.dtsi b/dts/riscv/sifive/riscv64-fu540.dtsi index ebb60e03aae..7ccd950129a 100644 --- a/dts/riscv/sifive/riscv64-fu540.dtsi +++ b/dts/riscv/sifive/riscv64-fu540.dtsi @@ -33,7 +33,7 @@ #size-cells = <0>; cpu: cpu@0 { - compatible = "sifive,e51"; + compatible = "sifive,e51", "riscv"; device_type = "cpu"; reg = <0>; riscv,isa = "rv64imac_zicsr_zifencei"; diff --git a/dts/riscv/sifive/riscv64-fu740.dtsi b/dts/riscv/sifive/riscv64-fu740.dtsi index bbe45b98aab..61421cd557e 100644 --- a/dts/riscv/sifive/riscv64-fu740.dtsi +++ b/dts/riscv/sifive/riscv64-fu740.dtsi @@ -32,7 +32,7 @@ #size-cells = <0>; cpu0: cpu@0 { - compatible = "sifive,s7"; + compatible = "sifive,s7", "riscv"; device_type = "cpu"; reg = <0>; riscv,isa = "rv64imac_zicsr_zifencei"; @@ -46,7 +46,7 @@ }; }; cpu1: cpu@1 { - compatible = "sifive,u74"; + compatible = "sifive,u74", "riscv"; device_type = "cpu"; mmu-type = "riscv,sv39"; reg = <0x1>; @@ -59,7 +59,7 @@ }; }; cpu2: cpu@2 { - compatible = "sifive,u74"; + compatible = "sifive,u74", "riscv"; device_type = "cpu"; mmu-type = "riscv,sv39"; reg = <0x2>; @@ -72,7 +72,7 @@ }; }; cpu3: cpu@3 { - compatible = "sifive,u74"; + compatible = "sifive,u74", "riscv"; device_type = "cpu"; mmu-type = "riscv,sv39"; reg = <0x3>; @@ -85,7 +85,7 @@ }; }; cpu4: cpu@4 { - compatible = "sifive,u74"; + compatible = "sifive,u74", "riscv"; device_type = "cpu"; mmu-type = "riscv,sv39"; reg = <0x4>; From a3a4bf915b7848ffcbecc4eb961d7d331b550b71 Mon Sep 17 00:00:00 2001 From: Filip Kokosinski Date: Wed, 17 Jan 2024 13:52:37 +0100 Subject: [PATCH 3171/3723] dts/riscv/litex: add `litex,vexriscv-standard` compatible string This commit adds the `litex,vexriscv-standard` compatible string. This helps identify the core type from the final devicetree alone. The VexRiscv core version is defined in this repository: https://github.com/litex-hub/zephyr-on-litex-vexriscv. Signed-off-by: Filip Kokosinski --- dts/bindings/cpu/litex,vexriscv-standard.yaml | 9 +++++++++ dts/riscv/riscv32-litex-vexriscv.dtsi | 2 +- 2 files changed, 10 insertions(+), 1 deletion(-) create mode 100644 dts/bindings/cpu/litex,vexriscv-standard.yaml diff --git a/dts/bindings/cpu/litex,vexriscv-standard.yaml b/dts/bindings/cpu/litex,vexriscv-standard.yaml new file mode 100644 index 00000000000..86de7c7a9c0 --- /dev/null +++ b/dts/bindings/cpu/litex,vexriscv-standard.yaml @@ -0,0 +1,9 @@ +# Copyright (c) 2024 Antmicro +# +# SPDX-License-Identifier: Apache-2.0 + +description: VexRiscv core with the standard configuration as used by LiteX + +compatible: "litex,vexriscv-standard" + +include: riscv,cpus.yaml diff --git a/dts/riscv/riscv32-litex-vexriscv.dtsi b/dts/riscv/riscv32-litex-vexriscv.dtsi index d85bccab0ae..8013decbafd 100644 --- a/dts/riscv/riscv32-litex-vexriscv.dtsi +++ b/dts/riscv/riscv32-litex-vexriscv.dtsi @@ -20,7 +20,7 @@ #size-cells = <0>; cpu@0 { clock-frequency = <100000000>; - compatible = "riscv"; + compatible = "litex,vexriscv-standard", "riscv"; device_type = "cpu"; reg = <0>; riscv,isa = "rv32ima_zicsr_zifencei"; From b5859ece4dc4f23aa48316dbd9a5899450f2b973 Mon Sep 17 00:00:00 2001 From: Filip Kokosinski Date: Thu, 18 Jan 2024 10:24:50 +0100 Subject: [PATCH 3172/3723] dts/riscv/microchip: add missing cpu nodes compats in `mpfs.dtsi` The cores used in the `mpfs.dtsi` file are: * 1x SiFive E51 (RV32) * 4x SiFive U54 (RV64) Signed-off-by: Filip Kokosinski --- dts/bindings/cpu/sifive,u54.yaml | 9 +++++++++ dts/riscv/microchip/mpfs.dtsi | 10 +++++----- 2 files changed, 14 insertions(+), 5 deletions(-) create mode 100644 dts/bindings/cpu/sifive,u54.yaml diff --git a/dts/bindings/cpu/sifive,u54.yaml b/dts/bindings/cpu/sifive,u54.yaml new file mode 100644 index 00000000000..2a0bbbfd58c --- /dev/null +++ b/dts/bindings/cpu/sifive,u54.yaml @@ -0,0 +1,9 @@ +# Copyright (c) 2024 Antmicro +# +# SPDX-License-Identifier: Apache-2.0 + +description: SiFive U54 Standard Core CPU + +compatible: "sifive,u54" + +include: sifive-common.yaml diff --git a/dts/riscv/microchip/mpfs.dtsi b/dts/riscv/microchip/mpfs.dtsi index 6b81720e095..fe7a0a773c9 100644 --- a/dts/riscv/microchip/mpfs.dtsi +++ b/dts/riscv/microchip/mpfs.dtsi @@ -16,7 +16,7 @@ #size-cells = <0>; cpu@0 { clock-frequency = <0>; - compatible = "riscv"; + compatible = "sifive,e51", "riscv"; device_type = "cpu"; reg = < 0x0 >; riscv,isa = "rv64imac_zicsr_zifencei"; @@ -30,7 +30,7 @@ cpu@1 { clock-frequency = <0>; - compatible = "riscv"; + compatible = "sifive,u54", "riscv"; device_type = "cpu"; reg = < 0x1 >; riscv,isa = "rv64gc"; @@ -44,7 +44,7 @@ cpu@2 { clock-frequency = <0>; - compatible = "riscv"; + compatible = "sifive,u54", "riscv"; device_type = "cpu"; reg = < 0x2 >; riscv,isa = "rv64gc"; @@ -58,7 +58,7 @@ cpu@3 { clock-frequency = <0>; - compatible = "riscv"; + compatible = "sifive,u54", "riscv"; device_type = "cpu"; reg = < 0x3 >; riscv,isa = "rv64gc"; @@ -72,7 +72,7 @@ cpu@4 { clock-frequency = <0>; - compatible = "riscv"; + compatible = "sifive,u54", "riscv"; device_type = "cpu"; reg = < 0x4 >; riscv,isa = "rv64gc"; From f80347ec95f17ab948f27051247bed9372a69669 Mon Sep 17 00:00:00 2001 From: Filip Kokosinski Date: Thu, 18 Jan 2024 10:27:01 +0100 Subject: [PATCH 3173/3723] dts/riscv/lowrisc: add `lowrisc,ibex` compatible string The OpenTitan Earlgrey SoC has the lowRISC Ibex CPU core. This commits adds the `lowrisc,ibex` compatible string to reflect that. Signed-off-by: Filip Kokosinski --- dts/bindings/cpu/lowrisc,ibex.yaml | 9 +++++++++ dts/riscv/lowrisc/opentitan_earlgrey.dtsi | 2 +- 2 files changed, 10 insertions(+), 1 deletion(-) create mode 100644 dts/bindings/cpu/lowrisc,ibex.yaml diff --git a/dts/bindings/cpu/lowrisc,ibex.yaml b/dts/bindings/cpu/lowrisc,ibex.yaml new file mode 100644 index 00000000000..051284f703f --- /dev/null +++ b/dts/bindings/cpu/lowrisc,ibex.yaml @@ -0,0 +1,9 @@ +# Copyright (c) 2024 Antmicro +# +# SPDX-License-Identifier: Apache-2.0 + +description: LowRISC Ibex RISC-V core + +compatible: "lowrisc,ibex" + +include: riscv,cpus.yaml diff --git a/dts/riscv/lowrisc/opentitan_earlgrey.dtsi b/dts/riscv/lowrisc/opentitan_earlgrey.dtsi index 3e6b30b38f7..1f6c23671dc 100644 --- a/dts/riscv/lowrisc/opentitan_earlgrey.dtsi +++ b/dts/riscv/lowrisc/opentitan_earlgrey.dtsi @@ -17,7 +17,7 @@ device_type = "cpu"; reg = <0x00>; status = "okay"; - compatible = "riscv"; + compatible = "lowrisc,ibex", "riscv"; riscv,isa = "rv32imcb_zicsr_zifencei"; hlic: interrupt-controller { From 6297f3640f98b4e0c8a68d99c284f6c06354bfa1 Mon Sep 17 00:00:00 2001 From: Filip Kokosinski Date: Thu, 18 Jan 2024 10:33:09 +0100 Subject: [PATCH 3174/3723] dts/riscv/andes: add `andestech,andescore-v5` compatible string This commit adds the `andestech,andescore-v5` compatible string. This helps identify the core tpye form the final devicetree alone. Andes doesn't define which core type from the v5 series the AE350 SoC uses, so we're using the whole series name here. Signed-off-by: Filip Kokosinski --- dts/bindings/cpu/andes,andescore-v5.yaml | 9 ++++ dts/riscv/andes/andes_v5_ae350.dtsi | 64 ++++++++++++------------ 2 files changed, 41 insertions(+), 32 deletions(-) create mode 100644 dts/bindings/cpu/andes,andescore-v5.yaml diff --git a/dts/bindings/cpu/andes,andescore-v5.yaml b/dts/bindings/cpu/andes,andescore-v5.yaml new file mode 100644 index 00000000000..d535b1dfd97 --- /dev/null +++ b/dts/bindings/cpu/andes,andescore-v5.yaml @@ -0,0 +1,9 @@ +# Copyright (c) 2024 Antmicro +# +# SPDX-License-Identifier: Apache-2.0 + +description: Andes Technology RISC-V core from the AndesCore v5 series + +compatible: "andestech,andescore-v5" + +include: riscv,cpus.yaml diff --git a/dts/riscv/andes/andes_v5_ae350.dtsi b/dts/riscv/andes/andes_v5_ae350.dtsi index 5f040b45f40..419aa712b73 100644 --- a/dts/riscv/andes/andes_v5_ae350.dtsi +++ b/dts/riscv/andes/andes_v5_ae350.dtsi @@ -15,8 +15,8 @@ cpus { #address-cells = <1>; #size-cells = <0>; - CPU0: cpu@0 { - compatible = "riscv"; + cpu0: cpu@0 { + compatible = "andestech,andescore-v5", "riscv"; device_type = "cpu"; reg = <0>; status = "okay"; @@ -25,15 +25,15 @@ clock-frequency = <60000000>; i-cache-line-size = <32>; d-cache-line-size = <32>; - CPU0_intc: interrupt-controller { + cpu0_intc: interrupt-controller { compatible = "riscv,cpu-intc"; #address-cells = <0>; #interrupt-cells = <1>; interrupt-controller; }; }; - CPU1: cpu@1 { - compatible = "riscv"; + cpu1: cpu@1 { + compatible = "andestech,andescore-v5", "riscv"; device_type = "cpu"; reg = <1>; status = "okay"; @@ -42,15 +42,15 @@ clock-frequency = <60000000>; i-cache-line-size = <32>; d-cache-line-size = <32>; - CPU1_intc: interrupt-controller { + cpu1_intc: interrupt-controller { compatible = "riscv,cpu-intc"; #address-cells = <0>; #interrupt-cells = <1>; interrupt-controller; }; }; - CPU2: cpu@2 { - compatible = "riscv"; + cpu2: cpu@2 { + compatible = "andestech,andescore-v5", "riscv"; device_type = "cpu"; reg = <2>; status = "okay"; @@ -59,15 +59,15 @@ clock-frequency = <60000000>; i-cache-line-size = <32>; d-cache-line-size = <32>; - CPU2_intc: interrupt-controller { + cpu2_intc: interrupt-controller { compatible = "riscv,cpu-intc"; #address-cells = <0>; #interrupt-cells = <1>; interrupt-controller; }; }; - CPU3: cpu@3 { - compatible = "riscv"; + cpu3: cpu@3 { + compatible = "andestech,andescore-v5", "riscv"; device_type = "cpu"; reg = <3>; status = "okay"; @@ -76,15 +76,15 @@ clock-frequency = <60000000>; i-cache-line-size = <32>; d-cache-line-size = <32>; - CPU3_intc: interrupt-controller { + cpu3_intc: interrupt-controller { compatible = "riscv,cpu-intc"; #address-cells = <0>; #interrupt-cells = <1>; interrupt-controller; }; }; - CPU4: cpu@4 { - compatible = "riscv"; + cpu4: cpu@4 { + compatible = "andestech,andescore-v5", "riscv"; device_type = "cpu"; reg = <4>; status = "okay"; @@ -93,15 +93,15 @@ clock-frequency = <60000000>; i-cache-line-size = <32>; d-cache-line-size = <32>; - CPU4_intc: interrupt-controller { + cpu4_intc: interrupt-controller { compatible = "riscv,cpu-intc"; #address-cells = <0>; #interrupt-cells = <1>; interrupt-controller; }; }; - CPU5: cpu@5 { - compatible = "riscv"; + cpu5: cpu@5 { + compatible = "andestech,andescore-v5", "riscv"; device_type = "cpu"; reg = <5>; status = "okay"; @@ -110,15 +110,15 @@ clock-frequency = <60000000>; i-cache-line-size = <32>; d-cache-line-size = <32>; - CPU5_intc: interrupt-controller { + cpu5_intc: interrupt-controller { compatible = "riscv,cpu-intc"; #address-cells = <0>; #interrupt-cells = <1>; interrupt-controller; }; }; - CPU6: cpu@6 { - compatible = "riscv"; + cpu6: cpu@6 { + compatible = "andestech,andescore-v5", "riscv"; device_type = "cpu"; reg = <6>; status = "okay"; @@ -127,15 +127,15 @@ clock-frequency = <60000000>; i-cache-line-size = <32>; d-cache-line-size = <32>; - CPU6_intc: interrupt-controller { + cpu6_intc: interrupt-controller { compatible = "riscv,cpu-intc"; #address-cells = <0>; #interrupt-cells = <1>; interrupt-controller; }; }; - CPU7: cpu@7 { - compatible = "riscv"; + cpu7: cpu@7 { + compatible = "andestech,andescore-v5", "riscv"; device_type = "cpu"; reg = <7>; status = "okay"; @@ -144,7 +144,7 @@ clock-frequency = <60000000>; i-cache-line-size = <32>; d-cache-line-size = <32>; - CPU7_intc: interrupt-controller { + cpu7_intc: interrupt-controller { compatible = "riscv,cpu-intc"; #address-cells = <0>; #interrupt-cells = <1>; @@ -173,10 +173,10 @@ reg = <0xe4000000 0x04000000>; riscv,max-priority = <255>; riscv,ndev = <1023>; - interrupts-extended = <&CPU0_intc 11 &CPU1_intc 11 - &CPU2_intc 11 &CPU3_intc 11 - &CPU4_intc 11 &CPU5_intc 11 - &CPU6_intc 11 &CPU7_intc 11>; + interrupts-extended = <&cpu0_intc 11 &cpu1_intc 11 + &cpu2_intc 11 &cpu3_intc 11 + &cpu4_intc 11 &cpu5_intc 11 + &cpu6_intc 11 &cpu7_intc 11>; }; mbox: mbox-controller@e6400000 { @@ -190,10 +190,10 @@ mtimer: timer@e6000000 { compatible = "andestech,machine-timer"; reg = <0xe6000000 0x10>; - interrupts-extended = <&CPU0_intc 7 &CPU1_intc 7 - &CPU2_intc 7 &CPU3_intc 7 - &CPU4_intc 7 &CPU5_intc 7 - &CPU6_intc 7 &CPU7_intc 7>; + interrupts-extended = <&cpu0_intc 7 &cpu1_intc 7 + &cpu2_intc 7 &cpu3_intc 7 + &cpu4_intc 7 &cpu5_intc 7 + &cpu6_intc 7 &cpu7_intc 7>; }; syscon: syscon@f0100000 { From 0458ac064c3f435f1db8f7bf659ad9b309d3ed68 Mon Sep 17 00:00:00 2001 From: Filip Kokosinski Date: Thu, 18 Jan 2024 10:38:08 +0100 Subject: [PATCH 3175/3723] dts/riscv/openisa: add compatible strings for the RI5CY cores This commits adds two new compatible strings: * `openisa,ri5cy` * `openisa,zero-ri5cy` Adding these two new compats help identify the specific core defined by the cpu node from the devicetree alone. Signed-off-by: Filip Kokosinski --- dts/bindings/cpu/openisa,ri5cy.yaml | 9 +++++++++ dts/bindings/cpu/openisa,zero-ri5cy.yaml | 9 +++++++++ dts/riscv/openisa/rv32m1.dtsi | 4 ++-- 3 files changed, 20 insertions(+), 2 deletions(-) create mode 100644 dts/bindings/cpu/openisa,ri5cy.yaml create mode 100644 dts/bindings/cpu/openisa,zero-ri5cy.yaml diff --git a/dts/bindings/cpu/openisa,ri5cy.yaml b/dts/bindings/cpu/openisa,ri5cy.yaml new file mode 100644 index 00000000000..9bcb53c9e89 --- /dev/null +++ b/dts/bindings/cpu/openisa,ri5cy.yaml @@ -0,0 +1,9 @@ +# Copyright (c) 2024 Antmicro +# +# SPDX-License-Identifier: Apache-2.0 + +description: OpenISA RI5CY core + +compatible: "openisa,ri5cy" + +include: riscv,cpus.yaml diff --git a/dts/bindings/cpu/openisa,zero-ri5cy.yaml b/dts/bindings/cpu/openisa,zero-ri5cy.yaml new file mode 100644 index 00000000000..33fe8450899 --- /dev/null +++ b/dts/bindings/cpu/openisa,zero-ri5cy.yaml @@ -0,0 +1,9 @@ +# Copyright (c) 2024 Antmicro +# +# SPDX-License-Identifier: Apache-2.0 + +description: OpenISA Zero-RI5CY core + +compatible: "openisa,zero-ri5cy" + +include: riscv,cpus.yaml diff --git a/dts/riscv/openisa/rv32m1.dtsi b/dts/riscv/openisa/rv32m1.dtsi index 567a6959f1f..afbc7c41c23 100644 --- a/dts/riscv/openisa/rv32m1.dtsi +++ b/dts/riscv/openisa/rv32m1.dtsi @@ -22,14 +22,14 @@ #size-cells = <0>; cpu@0 { device_type = "cpu"; - compatible = "riscv"; + compatible = "openisa,ri5cy", "riscv"; riscv,isa = "rv32ima_zicsr_zifencei"; reg = <0>; }; cpu@1 { device_type = "cpu"; - compatible = "riscv"; + compatible = "openisa,zero-ri5cy", "riscv"; riscv,isa = "rv32ima_zicsr_zifencei"; reg = <1>; }; From e08a77c8febe2abe17601d6d17a0a502dabf1bea Mon Sep 17 00:00:00 2001 From: Filip Kokosinski Date: Thu, 18 Jan 2024 10:39:43 +0100 Subject: [PATCH 3176/3723] dts/riscv/efinix: add the `efinix,vexriscv-sapphire` compatible string This commit adds the `efinix,vexriscv-sapphire` compatible string. This helps identify the core type from the final devicetree alone. The VexRiscv core configuration is specific to the Efinix Sapphire SoC. Signed-off-by: Filip Kokosinski --- dts/bindings/cpu/efinix,vexriscv-sapphire.yaml | 9 +++++++++ dts/riscv/efinix/sapphire_soc.dtsi | 2 +- 2 files changed, 10 insertions(+), 1 deletion(-) create mode 100644 dts/bindings/cpu/efinix,vexriscv-sapphire.yaml diff --git a/dts/bindings/cpu/efinix,vexriscv-sapphire.yaml b/dts/bindings/cpu/efinix,vexriscv-sapphire.yaml new file mode 100644 index 00000000000..ff0d6e2a420 --- /dev/null +++ b/dts/bindings/cpu/efinix,vexriscv-sapphire.yaml @@ -0,0 +1,9 @@ +# Copyright (c) 2024 Antmicro +# +# SPDX-License-Identifier: Apache-2.0 + +description: VexRiscv core with the configuration as used in the Efinix Sapphire SoC + +compatible: "efinix,vexriscv-sapphire" + +include: riscv,cpus.yaml diff --git a/dts/riscv/efinix/sapphire_soc.dtsi b/dts/riscv/efinix/sapphire_soc.dtsi index 675d2f9dd6f..b83c9bc1b0f 100644 --- a/dts/riscv/efinix/sapphire_soc.dtsi +++ b/dts/riscv/efinix/sapphire_soc.dtsi @@ -27,7 +27,7 @@ #size-cells = <0>; cpu@0 { clock-frequency = <100000000>; - compatible = "riscv"; + compatible = "efinix,vexriscv-sapphire", "riscv"; device_type = "cpu"; reg = <0>; riscv,isa = "rv32ima_zicsr_zifencei"; From 8a6c745e9f63e750a21d636cd5a86e377706bf9f Mon Sep 17 00:00:00 2001 From: Gaetan Perrot Date: Mon, 29 Jan 2024 14:23:24 +0900 Subject: [PATCH 3177/3723] posix: sched: Implement set APIs for scheduling parameters Implement `sched_setparam()` and `sched_setscheduler()` POSIX APIs as a part of PSE53 `_POSIX_PRIORITY_SCHEDULING` option group. Both functions are actually placeholders and just return `ENOSYS` since Zephyr does not yet support processes or process scheduling. signed-off-by: Gaetan Perrot --- include/zephyr/posix/sched.h | 3 +++ lib/posix/sched.c | 31 +++++++++++++++++++++++++++++++ 2 files changed, 34 insertions(+) diff --git a/include/zephyr/posix/sched.h b/include/zephyr/posix/sched.h index b7431fc3342..03b568fadea 100644 --- a/include/zephyr/posix/sched.h +++ b/include/zephyr/posix/sched.h @@ -51,6 +51,9 @@ int sched_get_priority_max(int policy); int sched_getparam(pid_t pid, struct sched_param *param); int sched_getscheduler(pid_t pid); +int sched_setparam(pid_t pid, const struct sched_param *param); +int sched_setscheduler(pid_t pid, int policy, const struct sched_param *param); + #ifdef __cplusplus } #endif diff --git a/lib/posix/sched.c b/lib/posix/sched.c index d5fa1d81ad4..195c5895752 100644 --- a/lib/posix/sched.c +++ b/lib/posix/sched.c @@ -70,3 +70,34 @@ int sched_getscheduler(pid_t pid) return -1; } + +/** + * @brief Set scheduling parameters + * + * See IEEE 1003.1 + */ +int sched_setparam(pid_t pid, const struct sched_param *param) +{ + ARG_UNUSED(pid); + ARG_UNUSED(param); + + errno = ENOSYS; + + return -1; +} + +/** + * @brief Set scheduling policy + * + * See IEEE 1003.1 + */ +int sched_setscheduler(pid_t pid, int policy, const struct sched_param *param) +{ + ARG_UNUSED(pid); + ARG_UNUSED(policy); + ARG_UNUSED(param); + + errno = ENOSYS; + + return -1; +} From c6c99245f66512efbaa07392b5b7a76e376a8d6f Mon Sep 17 00:00:00 2001 From: Gaetan Perrot Date: Mon, 29 Jan 2024 14:25:17 +0900 Subject: [PATCH 3178/3723] posix: sched: Implement tests for set APIs for scheduling parameters Implement tests for `sched_setparam()` and `sched_setscheduler()` . Both functions are actually placeholders and just return `ENOSYS` since Zephyr does not yet support processes or process scheduling. signed-off-by: Gaetan Perrot --- tests/posix/common/src/pthread.c | 22 ++++++++++++++++++++++ tests/posix/headers/src/sched_h.c | 4 ++-- 2 files changed, 24 insertions(+), 2 deletions(-) diff --git a/tests/posix/common/src/pthread.c b/tests/posix/common/src/pthread.c index 730e6664d7a..ffc408d9da4 100644 --- a/tests/posix/common/src/pthread.c +++ b/tests/posix/common/src/pthread.c @@ -405,6 +405,28 @@ ZTEST(pthread, test_sched_getscheduler) zassert_true((rc == -1 && err == ENOSYS)); } +ZTEST(pthread, test_sched_setparam) +{ + struct sched_param param = { + .sched_priority = 2, + }; + int rc = sched_setparam(0, ¶m); + int err = errno; + + zassert_true((rc == -1 && err == ENOSYS)); +} + +ZTEST(pthread, test_sched_setscheduler) +{ + struct sched_param param = { + .sched_priority = 2, + }; + int policy = 0; + int rc = sched_setscheduler(0, policy, ¶m); + int err = errno; + + zassert_true((rc == -1 && err == ENOSYS)); +} ZTEST(pthread, test_pthread_equal) { diff --git a/tests/posix/headers/src/sched_h.c b/tests/posix/headers/src/sched_h.c index fba7d17704c..e96e529de81 100644 --- a/tests/posix/headers/src/sched_h.c +++ b/tests/posix/headers/src/sched_h.c @@ -35,8 +35,8 @@ ZTEST(posix_headers, test_sched_h) /* zassert_not_null(sched_rr_get_interval); */ /* not implemented */ - /* zassert_not_null(sched_setparam); */ /* not implemented */ - /* zassert_not_null(sched_setscheduler); */ /* not implemented */ + zassert_not_null(sched_setparam); + zassert_not_null(sched_setscheduler); zassert_not_null(sched_yield); } From 19700040afb78e165eb0b988c55472b5e1c0b717 Mon Sep 17 00:00:00 2001 From: Gaetan Perrot Date: Mon, 29 Jan 2024 19:47:37 +0900 Subject: [PATCH 3179/3723] doc: posix: mark sched_setparam & sched_setscheduler as supported `sched_setparam()` and `sched_setscheduler()` is now implemented, mark it so. signed-off-by: Gaetan Perrot --- doc/services/portability/posix/option_groups/index.rst | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/doc/services/portability/posix/option_groups/index.rst b/doc/services/portability/posix/option_groups/index.rst index f2557df57c4..729bd0c5803 100644 --- a/doc/services/portability/posix/option_groups/index.rst +++ b/doc/services/portability/posix/option_groups/index.rst @@ -380,8 +380,8 @@ _POSIX_PRIORITY_SCHEDULING sched_getparam(), sched_getscheduler(), sched_rr_get_interval(), - sched_setparam(), - sched_setscheduler(), + sched_setparam(),yes + sched_setscheduler(),yes sched_yield(),yes .. _posix_option_reader_writer_locks: From c5818d4b3fe1f1befac1bd83430fc3d9e84645a3 Mon Sep 17 00:00:00 2001 From: Naga Sureshkumar Relli Date: Mon, 26 Jun 2023 14:43:37 +0530 Subject: [PATCH 3180/3723] dts: riscv: introduce Polarfire SOC SPI interface Add support for the Microchip Polarfire SOC SPI interface. Signed-off-by: Naga Sureshkumar Relli --- dts/bindings/spi/microchip,mpfs-spi.yaml | 15 +++++++++++++++ dts/riscv/microchip/mpfs.dtsi | 11 +++++++++++ 2 files changed, 26 insertions(+) create mode 100644 dts/bindings/spi/microchip,mpfs-spi.yaml diff --git a/dts/bindings/spi/microchip,mpfs-spi.yaml b/dts/bindings/spi/microchip,mpfs-spi.yaml new file mode 100644 index 00000000000..7ec6536ca83 --- /dev/null +++ b/dts/bindings/spi/microchip,mpfs-spi.yaml @@ -0,0 +1,15 @@ +# Copyright (c) 2022 Microchip Inc. +# SPDX-License-Identifier: Apache-2.0 + +description: Microchip Polarfire SOC SPI IP node + +compatible: "microchip,mpfs-spi" + +include: spi-controller.yaml + +properties: + reg: + required: true + + interrupts: + required: true diff --git a/dts/riscv/microchip/mpfs.dtsi b/dts/riscv/microchip/mpfs.dtsi index fe7a0a773c9..0ab207b28a3 100644 --- a/dts/riscv/microchip/mpfs.dtsi +++ b/dts/riscv/microchip/mpfs.dtsi @@ -195,6 +195,17 @@ clock-frequency = <150000000>; }; + spi1: spi@20109000 { + compatible = "microchip,mpfs-spi"; + #address-cells = <1>; + #size-cells = <0>; + reg = <0x20109000 0x1000>; + interrupt-parent = <&plic>; + interrupts = <55 1>; + status = "disabled"; + clock-frequency = <150000000>; + }; + gpio0: gpio@20120000 { compatible = "microchip,mpfs-gpio"; reg = <0x20120000 0x1000>; From 4d6a8bc65a3cfd16acfe4f154da15648ca537329 Mon Sep 17 00:00:00 2001 From: Naga Sureshkumar Relli Date: Wed, 28 Jun 2023 10:21:34 +0530 Subject: [PATCH 3181/3723] drivers: spi: Add support for Polarfire SOC SPI Add driver for the Microchip Polarfire SOC MSS SPI controller. The interrupts of the MSS SPI are routed through PLIC(Platform level interrupt controller). Tested with generic spi-nor flash driver(spi_flash) with both Fixed flash configuration and Read flash parameters at runtime(using SFDP). Signed-off-by: Naga Sureshkumar Relli --- drivers/spi/CMakeLists.txt | 2 +- drivers/spi/Kconfig | 2 + drivers/spi/Kconfig.mchp_mss | 11 + drivers/spi/spi_mchp_mss.c | 480 +++++++++++++++++++++++++++++++++++ 4 files changed, 494 insertions(+), 1 deletion(-) create mode 100644 drivers/spi/Kconfig.mchp_mss create mode 100644 drivers/spi/spi_mchp_mss.c diff --git a/drivers/spi/CMakeLists.txt b/drivers/spi/CMakeLists.txt index eccdc7325de..de004d6aa5f 100644 --- a/drivers/spi/CMakeLists.txt +++ b/drivers/spi/CMakeLists.txt @@ -44,7 +44,7 @@ zephyr_library_sources_ifdef(CONFIG_SPI_NUMAKER spi_numaker.c) zephyr_library_sources_ifdef(CONFIG_SPI_AMBIQ spi_ambiq.c) zephyr_library_sources_ifdef(CONFIG_SPI_RPI_PICO_PIO spi_rpi_pico_pio.c) zephyr_library_sources_ifdef(CONFIG_MSPI_AMBIQ mspi_ambiq.c) - +zephyr_library_sources_ifdef(CONFIG_SPI_MCHP_MSS spi_mchp_mss.c) zephyr_library_sources_ifdef(CONFIG_SPI_RTIO spi_rtio.c) zephyr_library_sources_ifdef(CONFIG_SPI_ASYNC spi_signal.c) zephyr_library_sources_ifdef(CONFIG_USERSPACE spi_handlers.c) diff --git a/drivers/spi/Kconfig b/drivers/spi/Kconfig index 8618b284b44..f5d49328fa6 100644 --- a/drivers/spi/Kconfig +++ b/drivers/spi/Kconfig @@ -139,4 +139,6 @@ source "drivers/spi/Kconfig.sedi" source "drivers/spi/Kconfig.npcx" +source "drivers/spi/Kconfig.mchp_mss" + endif # SPI diff --git a/drivers/spi/Kconfig.mchp_mss b/drivers/spi/Kconfig.mchp_mss new file mode 100644 index 00000000000..a12d64e36eb --- /dev/null +++ b/drivers/spi/Kconfig.mchp_mss @@ -0,0 +1,11 @@ +# Microchip Polarfire SOC SPI + +# Copyright (c) 2022 Microchip Technology Inc. +# SPDX-License-Identifier: Apache-2.0 + +config SPI_MCHP_MSS + bool "Microchip Polarfire SOC SPI driver" + default y + depends on DT_HAS_MICROCHIP_MPFS_SPI_ENABLED + help + Enable support for the Polarfire SOC SPI driver. diff --git a/drivers/spi/spi_mchp_mss.c b/drivers/spi/spi_mchp_mss.c new file mode 100644 index 00000000000..10ce776367f --- /dev/null +++ b/drivers/spi/spi_mchp_mss.c @@ -0,0 +1,480 @@ +/* + * Copyright (c) 2022 Microchip Technology Inc. + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#define DT_DRV_COMPAT microchip_mpfs_spi + +#include +#include +#include +#include +#include +#include + +LOG_MODULE_REGISTER(mss_spi, CONFIG_SPI_LOG_LEVEL); + +#include "spi_context.h" + +/* MSS SPI Register offsets */ +#define MSS_SPI_REG_CONTROL (0x00) +#define MSS_SPI_REG_TXRXDF_SIZE (0x04) +#define MSS_SPI_REG_STATUS (0x08) +#define MSS_SPI_REG_INT_CLEAR (0x0c) +#define MSS_SPI_REG_RX_DATA (0x10) +#define MSS_SPI_REG_TX_DATA (0x14) +#define MSS_SPI_REG_CLK_GEN (0x18) +#define MSS_SPI_REG_SS (0x1c) +#define MSS_SPI_REG_MIS (0x20) +#define MSS_SPI_REG_RIS (0x24) +#define MSS_SPI_REG_CONTROL2 (0x28) +#define MSS_SPI_REG_COMMAND (0x2c) +#define MSS_SPI_REG_PKTSIZE (0x30) +#define MSS_SPI_REG_CMD_SIZE (0x34) +#define MSS_SPI_REG_HWSTATUS (0x38) +#define MSS_SPI_REG_FRAMESUP (0x50) + +/* SPICR bit definitions */ +#define MSS_SPI_CONTROL_ENABLE BIT(0) +#define MSS_SPI_CONTROL_MASTER BIT(1) +#define MSS_SPI_CONTROL_PROTO_MSK BIT(2) +#define MSS_SPI_CONTROL_PROTO_MOTO (0 << 2) +#define MSS_SPI_CONTROL_RX_DATA_INT BIT(4) +#define MSS_SPI_CONTROL_TX_DATA_INT BIT(5) +#define MSS_SPI_CONTROL_RX_OVER_INT BIT(6) +#define MSS_SPI_CONTROL_TX_UNDER_INT BIT(7) +#define MSS_SPI_CONTROL_CNT_MSK (0xffff << 8) +#define MSS_SPI_CONTROL_CNT_SHF (8) +#define MSS_SPI_CONTROL_SPO BIT(24) +#define MSS_SPI_CONTROL_SPH BIT(25) +#define MSS_SPI_CONTROL_SPS BIT(26) +#define MSS_SPI_CONTROL_FRAMEURUN BIT(27) +#define MSS_SPI_CONTROL_CLKMODE BIT(28) +#define MSS_SPI_CONTROL_BIGFIFO BIT(29) +#define MSS_SPI_CONTROL_OENOFF BIT(30) +#define MSS_SPI_CONTROL_RESET BIT(31) + +/* SPIFRAMESIZE bit definitions */ +#define MSS_SPI_FRAMESIZE_DEFAULT (8) + +/* SPISS bit definitions */ +#define MSS_SPI_SSEL_MASK (0xff) +#define MSS_SPI_DIRECT (0x100) +#define MSS_SPI_SSELOUT (0x200) +#define MSS_SPI_MIN_SLAVE (0) +#define MSS_SPI_MAX_SLAVE (7) + +/* SPIST bit definitions */ +#define MSS_SPI_STATUS_ACTIVE BIT(14) +#define MSS_SPI_STATUS_SSEL BIT(13) +#define MSS_SPI_STATUS_FRAMESTART BIT(12) +#define MSS_SPI_STATUS_TXFIFO_EMPTY_NEXT_READ BIT(11) +#define MSS_SPI_STATUS_TXFIFO_EMPTY BIT(10) +#define MSS_SPI_STATUS_TXFIFO_FULL_NEXT_WRITE BIT(9) +#define MSS_SPI_STATUS_TXFIFO_FULL BIT(8) +#define MSS_SPI_STATUS_RXFIFO_EMPTY_NEXT_READ BIT(7) +#define MSS_SPI_STATUS_RXFIFO_EMPTY BIT(6) +#define MSS_SPI_STATUS_RXFIFO_FULL_NEXT_WRITE BIT(5) +#define MSS_SPI_STATUS_RXFIFO_FULL BIT(4) +#define MSS_SPI_STATUS_TX_UNDERRUN BIT(3) +#define MSS_SPI_STATUS_RX_OVERFLOW BIT(2) +#define MSS_SPI_STATUS_RXDAT_RCED BIT(1) +#define MSS_SPI_STATUS_TXDAT_SENT BIT(0) + +/* SPIINT register defines */ +#define MSS_SPI_INT_TXDONE BIT(0) +#define MSS_SPI_INT_RXRDY BIT(1) +#define MSS_SPI_INT_RX_CH_OVRFLW BIT(2) +#define MSS_SPI_INT_TX_CH_UNDRUN BIT(3) +#define MSS_SPI_INT_CMD BIT(4) +#define MSS_SPI_INT_SSEND BIT(5) + +/* SPICOMMAND bit definitions */ +#define MSS_SPI_COMMAND_FIFO_MASK (0xC) + +/* SPIFRAMESUP bit definitions */ +#define MSS_SPI_FRAMESUP_UP_BYTES_MSK (0xFFFF << 16) +#define MSS_SPI_FRAMESUP_LO_BYTES_MSK (0xFFFF << 0) + +struct mss_spi_config { + mm_reg_t base; + uint8_t clk_gen; + int clock_freq; +}; + +struct mss_spi_transfer { + uint32_t rx_len; + uint32_t control; +}; + +struct mss_spi_data { + struct spi_context ctx; + struct mss_spi_transfer xfer; +}; + +static inline uint32_t mss_spi_read(const struct mss_spi_config *cfg, mm_reg_t offset) +{ + return sys_read32(cfg->base + offset); +} + +static inline void mss_spi_write(const struct mss_spi_config *cfg, mm_reg_t offset, uint32_t val) +{ + sys_write32(val, cfg->base + offset); +} + +static inline void mss_spi_hw_tfsz_set(const struct mss_spi_config *cfg, int len) +{ + uint32_t control; + + mss_spi_write(cfg, MSS_SPI_REG_FRAMESUP, (len & MSS_SPI_FRAMESUP_UP_BYTES_MSK)); + control = mss_spi_read(cfg, MSS_SPI_REG_CONTROL); + control &= ~MSS_SPI_CONTROL_CNT_MSK; + control |= ((len & MSS_SPI_FRAMESUP_LO_BYTES_MSK) << MSS_SPI_CONTROL_CNT_SHF); + mss_spi_write(cfg, MSS_SPI_REG_CONTROL, control); +} + +static inline void mss_spi_enable_controller(const struct mss_spi_config *cfg) +{ + uint32_t control; + + control = mss_spi_read(cfg, MSS_SPI_REG_CONTROL); + control |= MSS_SPI_CONTROL_ENABLE; + mss_spi_write(cfg, MSS_SPI_REG_CONTROL, control); +} + +static inline void mss_spi_disable_controller(const struct mss_spi_config *cfg) +{ + uint32_t control; + + control = mss_spi_read(cfg, MSS_SPI_REG_CONTROL); + control &= ~MSS_SPI_CONTROL_ENABLE; + mss_spi_write(cfg, MSS_SPI_REG_CONTROL, control); +} + +static void mss_spi_enable_ints(const struct mss_spi_config *cfg) +{ + uint32_t control; + uint32_t mask = MSS_SPI_CONTROL_RX_DATA_INT | MSS_SPI_CONTROL_TX_DATA_INT | + MSS_SPI_CONTROL_RX_OVER_INT | MSS_SPI_CONTROL_TX_UNDER_INT; + + control = mss_spi_read(cfg, MSS_SPI_REG_CONTROL); + control |= mask; + mss_spi_write(cfg, MSS_SPI_REG_CONTROL, control); +} + +static void mss_spi_disable_ints(const struct mss_spi_config *cfg) +{ + uint32_t control; + uint32_t mask = MSS_SPI_CONTROL_RX_DATA_INT | MSS_SPI_CONTROL_TX_DATA_INT | + MSS_SPI_CONTROL_RX_OVER_INT | MSS_SPI_CONTROL_TX_UNDER_INT; + + mask = ~mask; + control = mss_spi_read(cfg, MSS_SPI_REG_CONTROL); + control &= ~mask; + mss_spi_write(cfg, MSS_SPI_REG_CONTROL, control); +} + +static inline void mss_spi_readwr_fifo(const struct device *dev) +{ + const struct mss_spi_config *cfg = dev->config; + struct mss_spi_data *data = dev->data; + struct spi_context *ctx = &data->ctx; + struct mss_spi_transfer *xfer = &data->xfer; + uint32_t rx_raw = 0, rd_byte_size, tr_len; + uint32_t data8, transfer_idx = 0; + int count; + + tr_len = spi_context_longest_current_buf(ctx); + count = spi_context_total_tx_len(ctx); + if (ctx->rx_buf) { + rd_byte_size = count - tr_len; + } else { + rd_byte_size = 0; + } + mss_spi_hw_tfsz_set(cfg, count); + + mss_spi_enable_ints(cfg); + spi_context_update_rx(ctx, 1, xfer->rx_len); + while (transfer_idx < count) { + if (!(mss_spi_read(cfg, MSS_SPI_REG_STATUS) & MSS_SPI_STATUS_RXFIFO_EMPTY)) { + rx_raw = mss_spi_read(cfg, MSS_SPI_REG_RX_DATA); + if (transfer_idx >= tr_len) { + if (spi_context_rx_buf_on(ctx)) { + UNALIGNED_PUT(rx_raw, (uint8_t *)ctx->rx_buf); + spi_context_update_rx(ctx, 1, 1); + } + } + ++transfer_idx; + } + + if (!(mss_spi_read(cfg, MSS_SPI_REG_STATUS) & MSS_SPI_STATUS_TXFIFO_FULL)) { + if (spi_context_tx_buf_on(ctx)) { + data8 = ctx->tx_buf[0]; + mss_spi_write(cfg, MSS_SPI_REG_TX_DATA, data8); + spi_context_update_tx(ctx, 1, 1); + } else { + mss_spi_write(cfg, MSS_SPI_REG_TX_DATA, 0x0); + } + } + } +} + +static inline int mss_spi_select_slave(const struct mss_spi_config *cfg, int cs) +{ + uint32_t slave; + uint32_t reg = mss_spi_read(cfg, MSS_SPI_REG_SS); + + slave = (cs >= MSS_SPI_MIN_SLAVE && cs <= MSS_SPI_MAX_SLAVE) ? (1 << cs) : 0; + reg &= ~MSS_SPI_SSEL_MASK; + reg |= slave; + + mss_spi_write(cfg, MSS_SPI_REG_SS, reg); + + return 0; +} + +static inline void mss_spi_activate_cs(struct mss_spi_config *cfg) +{ + uint32_t reg = mss_spi_read(cfg, MSS_SPI_REG_SS); + + reg |= MSS_SPI_SSELOUT; + mss_spi_write(cfg, MSS_SPI_REG_SS, reg); +} + +static inline void mss_spi_deactivate_cs(const struct mss_spi_config *cfg) +{ + uint32_t reg = mss_spi_read(cfg, MSS_SPI_REG_SS); + + reg &= ~MSS_SPI_SSELOUT; + mss_spi_write(cfg, MSS_SPI_REG_SS, reg); +} + +static inline int mss_spi_clk_gen_set(const struct mss_spi_config *cfg, + const struct spi_config *spi_cfg) +{ + uint32_t idx, clkrate, val = 0, speed; + + if (spi_cfg->frequency > cfg->clock_freq) { + speed = cfg->clock_freq / 2; + } + + for (idx = 1; idx < 16; idx++) { + clkrate = cfg->clock_freq / (2 * idx); + if (clkrate <= spi_cfg->frequency) { + val = idx; + break; + } + } + + mss_spi_write(cfg, MSS_SPI_REG_CLK_GEN, val); + + return 0; +} + +static inline int mss_spi_hw_mode_set(const struct mss_spi_config *cfg, unsigned int mode) +{ + uint32_t control = mss_spi_read(cfg, MSS_SPI_REG_CONTROL); + + /* set the mode */ + if (mode & SPI_MODE_CPHA) { + control |= MSS_SPI_CONTROL_SPH; + } else { + control &= ~MSS_SPI_CONTROL_SPH; + } + + if (mode & SPI_MODE_CPOL) { + control |= MSS_SPI_CONTROL_SPO; + } else { + control &= ~MSS_SPI_CONTROL_SPO; + } + + mss_spi_write(cfg, MSS_SPI_REG_CONTROL, control); + + return 0; +} + +static void mss_spi_interrupt(const struct device *dev) +{ + const struct mss_spi_config *cfg = dev->config; + struct mss_spi_data *data = dev->data; + struct spi_context *ctx = &data->ctx; + int intfield = mss_spi_read(cfg, MSS_SPI_REG_MIS) & 0xf; + + if (intfield == 0) { + return; + } + + mss_spi_write(cfg, MSS_SPI_REG_INT_CLEAR, intfield); + spi_context_complete(ctx, dev, 0); +} + +static int mss_spi_release(const struct device *dev, const struct spi_config *config) +{ + const struct mss_spi_config *cfg = dev->config; + struct mss_spi_data *data = dev->data; + + mss_spi_disable_ints(cfg); + + /* release kernel resources */ + spi_context_unlock_unconditionally(&data->ctx); + mss_spi_disable_controller(cfg); + + return 0; +} + +static int mss_spi_configure(const struct device *dev, const struct spi_config *spi_cfg) +{ + const struct mss_spi_config *cfg = dev->config; + struct mss_spi_data *data = dev->data; + struct spi_context *ctx = &data->ctx; + struct mss_spi_transfer *xfer = &data->xfer; + uint32_t control; + + if (spi_cfg->operation & (SPI_TRANSFER_LSB | SPI_OP_MODE_SLAVE | SPI_MODE_LOOP)) { + LOG_WRN("not supported operation\n\r"); + return -ENOTSUP; + } + + if (SPI_WORD_SIZE_GET(spi_cfg->operation) != MSS_SPI_FRAMESIZE_DEFAULT) { + return -ENOTSUP; + } + + ctx->config = spi_cfg; + mss_spi_select_slave(cfg, spi_cfg->slave); + control = mss_spi_read(cfg, MSS_SPI_REG_CONTROL); + + /* + * Fill up the default values + * Slave select behaviour set + * Fifo depth greater than 4 frames + * Methodology to calculate SPI Clock: + * 0: SPICLK = 1 / (2 CLK_GEN + 1) , CLK_GEN is from 0 to 15 + * 1: SPICLK = 1 / (2 * (CLK_GEN + 1)) , CLK_GEN is from 0 to 255 + */ + + mss_spi_write(cfg, MSS_SPI_REG_CONTROL, xfer->control); + + if (mss_spi_clk_gen_set(cfg, spi_cfg)) { + LOG_ERR("can't set clk divider\n"); + return -EINVAL; + } + + mss_spi_hw_mode_set(cfg, spi_cfg->operation); + mss_spi_write(cfg, MSS_SPI_REG_TXRXDF_SIZE, MSS_SPI_FRAMESIZE_DEFAULT); + mss_spi_enable_controller(cfg); + mss_spi_write(cfg, MSS_SPI_REG_COMMAND, MSS_SPI_COMMAND_FIFO_MASK); + + return 0; +} + +static int mss_spi_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 async, spi_callback_t cb, void *userdata) +{ + + const struct mss_spi_config *config = dev->config; + struct mss_spi_data *data = dev->data; + struct spi_context *ctx = &data->ctx; + struct mss_spi_transfer *xfer = &data->xfer; + int ret = 0; + + spi_context_lock(ctx, async, cb, userdata, spi_cfg); + + ret = mss_spi_configure(dev, spi_cfg); + if (ret) { + LOG_ERR("Fail to configure\n\r"); + goto out; + } + + spi_context_buffers_setup(ctx, tx_bufs, rx_bufs, 1); + xfer->rx_len = ctx->rx_len; + mss_spi_readwr_fifo(dev); + ret = spi_context_wait_for_completion(ctx); +out: + spi_context_release(ctx, ret); + mss_spi_disable_ints(config); + mss_spi_disable_controller(config); + + return ret; +} + +static int mss_spi_transceive_blocking(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 mss_spi_transceive(dev, spi_cfg, tx_bufs, rx_bufs, false, NULL, NULL); +} + +#ifdef CONFIG_SPI_ASYNC +static int mss_spi_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 mss_spi_transceive(dev, spi_cfg, tx_bufs, rx_bufs, true, cb, userdata); +} +#endif /* CONFIG_SPI_ASYNC */ + +static int mss_spi_init(const struct device *dev) +{ + const struct mss_spi_config *cfg = dev->config; + struct mss_spi_data *data = dev->data; + struct mss_spi_transfer *xfer = &data->xfer; + int ret = 0; + uint32_t control = 0; + + /* Remove SPI from Reset */ + control = mss_spi_read(cfg, MSS_SPI_REG_CONTROL); + control &= ~MSS_SPI_CONTROL_RESET; + mss_spi_write(cfg, MSS_SPI_REG_CONTROL, control); + + /* Set master mode */ + mss_spi_disable_controller(cfg); + xfer->control = (MSS_SPI_CONTROL_SPS | MSS_SPI_CONTROL_BIGFIFO | MSS_SPI_CONTROL_MASTER | + MSS_SPI_CONTROL_CLKMODE); + + spi_context_unlock_unconditionally(&data->ctx); + + return ret; +} + +#define MICROCHIP_SPI_PM_OPS (NULL) + +static const struct spi_driver_api mss_spi_driver_api = { + .transceive = mss_spi_transceive_blocking, +#ifdef CONFIG_SPI_ASYNC + .transceive_async = mss_spi_transceive_async, +#endif /* CONFIG_SPI_ASYNC */ + .release = mss_spi_release, +}; + +#define MSS_SPI_INIT(n) \ + static int mss_spi_init_##n(const struct device *dev) \ + { \ + mss_spi_init(dev); \ + \ + IRQ_CONNECT(DT_INST_IRQN(n), DT_INST_IRQ(n, priority), mss_spi_interrupt, \ + DEVICE_DT_INST_GET(n), 0); \ + \ + irq_enable(DT_INST_IRQN(n)); \ + \ + return 0; \ + } \ + \ + static const struct mss_spi_config mss_spi_config_##n = { \ + .base = DT_INST_REG_ADDR(n), \ + .clock_freq = DT_INST_PROP(n, clock_frequency), \ + }; \ + \ + static struct mss_spi_data mss_spi_data_##n = { \ + SPI_CONTEXT_INIT_LOCK(mss_spi_data_##n, ctx), \ + SPI_CONTEXT_INIT_SYNC(mss_spi_data_##n, ctx), \ + }; \ + \ + DEVICE_DT_INST_DEFINE(n, mss_spi_init_##n, NULL, &mss_spi_data_##n, &mss_spi_config_##n, \ + POST_KERNEL, CONFIG_KERNEL_INIT_PRIORITY_DEVICE, \ + &mss_spi_driver_api); + +DT_INST_FOREACH_STATUS_OKAY(MSS_SPI_INIT) From 8db71788709d0e13c0116306059339acb2605e00 Mon Sep 17 00:00:00 2001 From: Naga Sureshkumar Relli Date: Mon, 26 Jun 2023 14:49:29 +0530 Subject: [PATCH 3182/3723] boards: riscv: Add spi flash to Polarfire SOC icicle board On the Polarfire SOC Icicle Kit the SPI pins are routed to MikroBus. Enable SPI by default. Signed-off-by: Naga Sureshkumar Relli --- boards/riscv/mpfs_icicle/mpfs_icicle.dts | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/boards/riscv/mpfs_icicle/mpfs_icicle.dts b/boards/riscv/mpfs_icicle/mpfs_icicle.dts index 6faaca8d590..3eb8077f902 100644 --- a/boards/riscv/mpfs_icicle/mpfs_icicle.dts +++ b/boards/riscv/mpfs_icicle/mpfs_icicle.dts @@ -61,6 +61,10 @@ }; }; +&spi1 { + status = "okay"; +}; + &gpio2 { status = "okay"; }; From b173c21d9c310c044198a10d52d937e54c2528d2 Mon Sep 17 00:00:00 2001 From: Emil Gydesen Date: Thu, 25 Jan 2024 09:18:52 +0100 Subject: [PATCH 3183/3723] Bluetooth: BAP: client: Add support for source ASEs disconnects When the CIS of a source ASE disconnects, the server shall put it into the QoS Configured state, which is not really part of the state machine for source ASEs, but more like a hidden bonus state change. The state machine handler in the unicast client has been updated to support this state change. Signed-off-by: Emil Gydesen --- subsys/bluetooth/audio/bap_unicast_client.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/subsys/bluetooth/audio/bap_unicast_client.c b/subsys/bluetooth/audio/bap_unicast_client.c index e823a094de5..29d185b9df7 100644 --- a/subsys/bluetooth/audio/bap_unicast_client.c +++ b/subsys/bluetooth/audio/bap_unicast_client.c @@ -1047,6 +1047,8 @@ static void unicast_client_ep_set_status(struct bt_bap_ep *ep, struct net_buf_si case BT_BAP_EP_STATE_CODEC_CONFIGURED: /* or 0x02 (QoS Configured) */ case BT_BAP_EP_STATE_QOS_CONFIGURED: + /* or 0x04 (Streaming) if there is a disconnect */ + case BT_BAP_EP_STATE_STREAMING: /* or 0x05 (Disabling) */ case BT_BAP_EP_STATE_DISABLING: break; From a08604c631138623eb0241cb3d0cdf83bd2595f6 Mon Sep 17 00:00:00 2001 From: Mykola Kvach Date: Mon, 29 Jan 2024 12:35:23 +0200 Subject: [PATCH 3184/3723] boards: arm64: enable ARMV8_A_NS by default for R-Car boards We need to enable this configuration for all R-Car ARM64 boards. First and foremost, we definitely should run Zephyr on the boards in the NS-EL1 state. The EL3 is used for TF-A, EL2 is used for U-Boot, and Xen in the case when we run Zephyr as Dom-0. The S-EL1 is used for OP-Tee, and S-EL0 is used for OP-Tee apps. Signed-off-by: Mykola Kvach --- boards/arm64/rcar_h3ulcb_ca57/rcar_h3ulcb_ca57_defconfig | 1 + boards/arm64/rcar_salvator_xs_m3/rcar_salvator_xs_m3_defconfig | 1 + 2 files changed, 2 insertions(+) diff --git a/boards/arm64/rcar_h3ulcb_ca57/rcar_h3ulcb_ca57_defconfig b/boards/arm64/rcar_h3ulcb_ca57/rcar_h3ulcb_ca57_defconfig index a312d33601a..3995ececf44 100644 --- a/boards/arm64/rcar_h3ulcb_ca57/rcar_h3ulcb_ca57_defconfig +++ b/boards/arm64/rcar_h3ulcb_ca57/rcar_h3ulcb_ca57_defconfig @@ -12,6 +12,7 @@ CONFIG_SYS_CLOCK_HW_CYCLES_PER_SEC=8300000 CONFIG_XIP=n CONFIG_MAX_XLAT_TABLES=24 +CONFIG_ARMV8_A_NS=y # Enable console CONFIG_CONSOLE=y diff --git a/boards/arm64/rcar_salvator_xs_m3/rcar_salvator_xs_m3_defconfig b/boards/arm64/rcar_salvator_xs_m3/rcar_salvator_xs_m3_defconfig index 3dca6448ac4..a6eb4060d39 100644 --- a/boards/arm64/rcar_salvator_xs_m3/rcar_salvator_xs_m3_defconfig +++ b/boards/arm64/rcar_salvator_xs_m3/rcar_salvator_xs_m3_defconfig @@ -12,6 +12,7 @@ CONFIG_SYS_CLOCK_HW_CYCLES_PER_SEC=8300000 CONFIG_XIP=n CONFIG_MAX_XLAT_TABLES=24 +CONFIG_ARMV8_A_NS=y # Enable console CONFIG_CONSOLE=y From a147ac9a47dee34f16ebd26a3d0af59afbb7cb39 Mon Sep 17 00:00:00 2001 From: Robert Lubos Date: Thu, 25 Jan 2024 11:14:44 +0100 Subject: [PATCH 3185/3723] net: dhcpv4_server: Improve address pool range validation Not only check if the address pool belongs to the same subnet as the server, but also that it does not overlap with the server address - otherwise the server might end up assigning its own address. Signed-off-by: Robert Lubos --- subsys/net/lib/dhcpv4/dhcpv4_server.c | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/subsys/net/lib/dhcpv4/dhcpv4_server.c b/subsys/net/lib/dhcpv4/dhcpv4_server.c index 04610d8446a..91daaafd4d9 100644 --- a/subsys/net/lib/dhcpv4/dhcpv4_server.c +++ b/subsys/net/lib/dhcpv4/dhcpv4_server.c @@ -1224,6 +1224,13 @@ int net_dhcpv4_server_start(struct net_if *iface, struct in_addr *base_addr) return -EINVAL; } + if ((htonl(server_addr->s_addr) >= htonl(base_addr->s_addr)) && + (htonl(server_addr->s_addr) < + htonl(base_addr->s_addr) + CONFIG_NET_DHCPV4_SERVER_ADDR_COUNT)) { + LOG_ERR("Address pool overlaps with server address."); + return -EINVAL; + } + netmask = net_if_ipv4_get_netmask(iface); if (net_ipv4_is_addr_unspecified(&netmask)) { LOG_ERR("Failed to obtain subnet mask."); From 5a08fea48e0e504976f29b8c26c13da7dc09354e Mon Sep 17 00:00:00 2001 From: Robert Lubos Date: Mon, 29 Jan 2024 12:34:18 +0100 Subject: [PATCH 3186/3723] tests: net: dhcpv4_server: Add test to verify initialization Add test that verifies that initialization fails if wrong arguments are provided. Signed-off-by: Robert Lubos --- tests/net/dhcpv4/server/src/main.c | 21 +++++++++++++++++++++ 1 file changed, 21 insertions(+) diff --git a/tests/net/dhcpv4/server/src/main.c b/tests/net/dhcpv4/server/src/main.c index 2e077722da5..cfaa8561606 100644 --- a/tests/net/dhcpv4/server/src/main.c +++ b/tests/net/dhcpv4/server/src/main.c @@ -840,6 +840,25 @@ ZTEST(dhcpv4_server_tests, test_inform) verify_lease_count(0, 0, 0); } +/* Verify that the DHCP server can start and validate input properly. */ +ZTEST(dhcpv4_server_tests_no_init, test_initialization) +{ + struct in_addr base_addr_wrong_subnet = { { { 192, 0, 3, 10 } } }; + struct in_addr base_addr_overlap = { { { 192, 0, 2, 1 } } }; + int ret; + + ret = net_dhcpv4_server_start(test_ctx.iface, &base_addr_wrong_subnet); + zassert_equal(ret, -EINVAL, "Started server for wrong subnet"); + + ret = net_dhcpv4_server_start(test_ctx.iface, &base_addr_overlap); + zassert_equal(ret, -EINVAL, "Started server for overlapping address"); + + ret = net_dhcpv4_server_start(test_ctx.iface, &test_base_addr); + zassert_ok(ret, "Failed to start server for valid address range"); + + net_dhcpv4_server_stop(test_ctx.iface); +} + static void dhcpv4_server_tests_before(void *fixture) { ARG_UNUSED(fixture); @@ -865,3 +884,5 @@ static void dhcpv4_server_tests_after(void *fixture) ZTEST_SUITE(dhcpv4_server_tests, NULL, NULL, dhcpv4_server_tests_before, dhcpv4_server_tests_after, NULL); + +ZTEST_SUITE(dhcpv4_server_tests_no_init, NULL, NULL, NULL, NULL, NULL); From b03c3c0c48c0771c4bf0141dde7380429c41f2f4 Mon Sep 17 00:00:00 2001 From: Jukka Rissanen Date: Mon, 29 Jan 2024 13:31:25 +0200 Subject: [PATCH 3187/3723] net: socket: Start service thread from initialization function We cannot always start the service monitor thread statically because the static threads are started after the application level. This means that when config library wants to start dhcpv4 server which uses socket services, there would be a deadlock. Simplest solution is to start the service thread directly from socket service init function. Signed-off-by: Jukka Rissanen --- subsys/net/lib/sockets/sockets_service.c | 22 +++++++++++++++------- 1 file changed, 15 insertions(+), 7 deletions(-) diff --git a/subsys/net/lib/sockets/sockets_service.c b/subsys/net/lib/sockets/sockets_service.c index 19efef93add..4c9270af116 100644 --- a/subsys/net/lib/sockets/sockets_service.c +++ b/subsys/net/lib/sockets/sockets_service.c @@ -277,15 +277,23 @@ static void socket_service_thread(void) k_condvar_broadcast(&wait_start); } -K_THREAD_DEFINE(socket_service_monitor, CONFIG_NET_SOCKETS_SERVICE_STACK_SIZE, - socket_service_thread, NULL, NULL, NULL, - CLAMP(CONFIG_NET_SOCKETS_SERVICE_THREAD_PRIO, - K_HIGHEST_APPLICATION_THREAD_PRIO, - K_LOWEST_APPLICATION_THREAD_PRIO), 0, 0); - static int init_socket_service(void) { - k_thread_name_set(socket_service_monitor, "net_socket_service"); + k_tid_t ssm; + static struct k_thread service_thread; + + static K_THREAD_STACK_DEFINE(service_thread_stack, + CONFIG_NET_SOCKETS_SERVICE_STACK_SIZE); + + ssm = k_thread_create(&service_thread, + service_thread_stack, + K_THREAD_STACK_SIZEOF(service_thread_stack), + (k_thread_entry_t)socket_service_thread, NULL, NULL, NULL, + CLAMP(CONFIG_NET_SOCKETS_SERVICE_THREAD_PRIO, + K_HIGHEST_APPLICATION_THREAD_PRIO, + K_LOWEST_APPLICATION_THREAD_PRIO), 0, K_NO_WAIT); + + k_thread_name_set(ssm, "net_socket_service"); return 0; } From 197336c83f35d3379cd7a6697d2b144b9ea7f72d Mon Sep 17 00:00:00 2001 From: Anas Nashif Date: Wed, 31 Jan 2024 07:07:26 -0500 Subject: [PATCH 3188/3723] ci: codecov: stick with gcovr 6.0 for now gcovr 7.0 has some incompatible format, stick with 6.0 for now until we have a compatible solution with gcovr 7.0 output. Signed-off-by: Anas Nashif --- .github/workflows/codecov.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/codecov.yaml b/.github/workflows/codecov.yaml index 6924c7e587e..230fa28efae 100644 --- a/.github/workflows/codecov.yaml +++ b/.github/workflows/codecov.yaml @@ -89,7 +89,7 @@ jobs: export ZEPHYR_BASE=${PWD} export ZEPHYR_TOOLCHAIN_VARIANT=zephyr mkdir -p coverage/reports - pip3 install gcovr + pip3 install gcovr==6.0 ./scripts/twister -i --force-color -N -v --filter runnable -p ${{ matrix.platform }} --coverage -T tests --coverage-tool gcovr -xCONFIG_TEST_EXTRA_STACK_SIZE=4096 -e nano - name: ccache stats post From daf7c80c1599bcce969877b7d451e66496cf28e5 Mon Sep 17 00:00:00 2001 From: Vinayak Kariappa Chettimada Date: Tue, 9 Jan 2024 17:09:49 +0100 Subject: [PATCH 3189/3723] tests: bsim: Bluetooth: CAP broadcast AC testing updates Update testing of the Audio Configurations from the BAP spec using the CAP API. Signed-off-by: Vinayak Kariappa Chettimada --- .../audio/src/cap_initiator_broadcast_test.c | 19 ++++++++++++-- .../bsim/bluetooth/audio/src/gmap_ugg_test.c | 19 ++++++++++++-- .../audio/test_scripts/cap_broadcast_ac_12.sh | 10 +++---- .../audio/test_scripts/cap_broadcast_ac_13.sh | 26 +++++++++---------- .../audio/test_scripts/cap_broadcast_ac_14.sh | 14 +++++----- .../test_scripts/gmap_broadcast_ac_12.sh | 2 +- .../test_scripts/gmap_broadcast_ac_13.sh | 6 ++--- .../test_scripts/gmap_broadcast_ac_14.sh | 2 +- 8 files changed, 64 insertions(+), 34 deletions(-) diff --git a/tests/bsim/bluetooth/audio/src/cap_initiator_broadcast_test.c b/tests/bsim/bluetooth/audio/src/cap_initiator_broadcast_test.c index 001b0d0ddd9..56a74c90aad 100644 --- a/tests/bsim/bluetooth/audio/src/cap_initiator_broadcast_test.c +++ b/tests/bsim/bluetooth/audio/src/cap_initiator_broadcast_test.c @@ -15,6 +15,21 @@ #include "bap_common.h" #include "common.h" +/* Zephyr Controller works best while Extended Advertising interval to be a multiple + * of the ISO Interval minus 10 ms (max. advertising random delay). This is + * required to place the AUX_ADV_IND PDUs in a non-overlapping interval with the + * Broadcast ISO radio events. + */ +#define BT_LE_EXT_ADV_CUSTOM \ + BT_LE_ADV_PARAM(BT_LE_ADV_OPT_EXT_ADV | \ + BT_LE_ADV_OPT_USE_NAME, \ + 0x0080, 0x0080, NULL) + +#define BT_LE_PER_ADV_CUSTOM \ + BT_LE_PER_ADV_PARAM(0x0048, \ + 0x0048, \ + BT_LE_PER_ADV_OPT_NONE) + #define BROADCAST_STREMT_CNT CONFIG_BT_BAP_BROADCAST_SRC_STREAM_COUNT #define BROADCAST_ENQUEUE_COUNT 2U #define TOTAL_BUF_NEEDED (BROADCAST_ENQUEUE_COUNT * BROADCAST_STREMT_CNT) @@ -171,14 +186,14 @@ static void setup_extended_adv(struct bt_le_ext_adv **adv) int err; /* Create a non-connectable non-scannable advertising set */ - err = bt_le_ext_adv_create(BT_LE_EXT_ADV_NCONN_NAME, NULL, adv); + err = bt_le_ext_adv_create(BT_LE_EXT_ADV_CUSTOM, NULL, adv); if (err != 0) { FAIL("Unable to create extended advertising set: %d\n", err); return; } /* Set periodic advertising parameters */ - err = bt_le_per_adv_set_param(*adv, BT_LE_PER_ADV_DEFAULT); + err = bt_le_per_adv_set_param(*adv, BT_LE_PER_ADV_CUSTOM); if (err) { FAIL("Failed to set periodic advertising parameters: %d\n", err); return; diff --git a/tests/bsim/bluetooth/audio/src/gmap_ugg_test.c b/tests/bsim/bluetooth/audio/src/gmap_ugg_test.c index 3f9f0e1dbac..d48b0c18ffc 100644 --- a/tests/bsim/bluetooth/audio/src/gmap_ugg_test.c +++ b/tests/bsim/bluetooth/audio/src/gmap_ugg_test.c @@ -17,6 +17,21 @@ #include "common.h" #include "bap_common.h" +/* Zephyr Controller works best while Extended Advertising interval to be a multiple + * of the ISO Interval minus 10 ms (max. advertising random delay). This is + * required to place the AUX_ADV_IND PDUs in a non-overlapping interval with the + * Broadcast ISO radio events. + */ +#define BT_LE_EXT_ADV_CUSTOM \ + BT_LE_ADV_PARAM(BT_LE_ADV_OPT_EXT_ADV | \ + BT_LE_ADV_OPT_USE_NAME, \ + 0x0080, 0x0080, NULL) + +#define BT_LE_PER_ADV_CUSTOM \ + BT_LE_PER_ADV_PARAM(0x0048, \ + 0x0048, \ + BT_LE_PER_ADV_OPT_NONE) + #define UNICAST_SINK_SUPPORTED (CONFIG_BT_BAP_UNICAST_CLIENT_ASE_SNK_COUNT > 0) #define UNICAST_SRC_SUPPORTED (CONFIG_BT_BAP_UNICAST_CLIENT_ASE_SRC_COUNT > 0) @@ -973,14 +988,14 @@ static void setup_extended_adv(struct bt_le_ext_adv **adv) int err; /* Create a non-connectable non-scannable advertising set */ - err = bt_le_ext_adv_create(BT_LE_EXT_ADV_NCONN_NAME, NULL, adv); + err = bt_le_ext_adv_create(BT_LE_EXT_ADV_CUSTOM, NULL, adv); if (err != 0) { FAIL("Unable to create extended advertising set: %d\n", err); return; } /* Set periodic advertising parameters */ - err = bt_le_per_adv_set_param(*adv, BT_LE_PER_ADV_DEFAULT); + err = bt_le_per_adv_set_param(*adv, BT_LE_PER_ADV_CUSTOM); if (err) { FAIL("Failed to set periodic advertising parameters: %d\n", err); return; diff --git a/tests/bsim/bluetooth/audio/test_scripts/cap_broadcast_ac_12.sh b/tests/bsim/bluetooth/audio/test_scripts/cap_broadcast_ac_12.sh index ecfd5391da4..e0a48c20701 100755 --- a/tests/bsim/bluetooth/audio/test_scripts/cap_broadcast_ac_12.sh +++ b/tests/bsim/bluetooth/audio/test_scripts/cap_broadcast_ac_12.sh @@ -4,7 +4,7 @@ # # SPDX-License-Identifier: Apache-2.0 -SIMULATION_ID="cap_unicast_ac_12" +SIMULATION_ID="cap_broadcast_ac_12" VERBOSITY_LEVEL=2 EXECUTE_TIMEOUT=60 @@ -41,13 +41,13 @@ Execute_AC_12 24_1_1 Execute_AC_12 24_2_1 Execute_AC_12 32_1_1 Execute_AC_12 32_2_1 -# Execute_AC_12 441_1_1 # BT_ISO_FLAGS_ERROR +Execute_AC_12 441_1_1 Execute_AC_12 441_2_1 -# Execute_AC_12 48_1_1 # BT_ISO_FLAGS_ERROR +Execute_AC_12 48_1_1 Execute_AC_12 48_2_1 -# Execute_AC_12 48_3_1 # BT_ISO_FLAGS_ERROR +Execute_AC_12 48_3_1 Execute_AC_12 48_4_1 -# Execute_AC_12 48_5_1 # BT_ISO_FLAGS_ERROR +Execute_AC_12 48_5_1 Execute_AC_12 48_6_1 # High reliability diff --git a/tests/bsim/bluetooth/audio/test_scripts/cap_broadcast_ac_13.sh b/tests/bsim/bluetooth/audio/test_scripts/cap_broadcast_ac_13.sh index dd1859cbda4..c07b59e8856 100755 --- a/tests/bsim/bluetooth/audio/test_scripts/cap_broadcast_ac_13.sh +++ b/tests/bsim/bluetooth/audio/test_scripts/cap_broadcast_ac_13.sh @@ -4,7 +4,7 @@ # # SPDX-License-Identifier: Apache-2.0 -SIMULATION_ID="cap_unicast_ac_13" +SIMULATION_ID="cap_broadcast_ac_13" VERBOSITY_LEVEL=2 EXECUTE_TIMEOUT=60 @@ -32,22 +32,22 @@ function Execute_AC_13() { set -e # Exit on error -# Execute_AC_13 8_1_1 # BT_ISO_FLAGS_ERROR +Execute_AC_13 8_1_1 Execute_AC_13 8_2_1 -# Execute_AC_13 16_1_1 # BT_ISO_FLAGS_ERROR +Execute_AC_13 16_1_1 Execute_AC_13 16_2_1 -# Execute_AC_13 24_1_1 # BT_ISO_FLAGS_ERROR +Execute_AC_13 24_1_1 Execute_AC_13 24_2_1 -# Execute_AC_13 32_1_1 # BT_ISO_FLAGS_ERROR +Execute_AC_13 32_1_1 Execute_AC_13 32_2_1 -# Execute_AC_13 441_1_1 # BT_ISO_FLAGS_ERROR -# Execute_AC_13 441_2_1 # BT_ISO_FLAGS_ERROR -# Execute_AC_13 48_1_1 # BT_ISO_FLAGS_ERROR -# Execute_AC_13 48_2_1 # BT_ISO_FLAGS_ERROR -# Execute_AC_13 48_3_1 # BT_ISO_FLAGS_ERROR -# Execute_AC_13 48_4_1 # BT_ISO_FLAGS_ERROR -# Execute_AC_13 48_5_1 # BT_ISO_FLAGS_ERROR -# Execute_AC_13 48_6_1 # BT_ISO_FLAGS_ERROR +Execute_AC_13 441_1_1 +Execute_AC_13 441_2_1 +Execute_AC_13 48_1_1 +Execute_AC_13 48_2_1 +Execute_AC_13 48_3_1 +Execute_AC_13 48_4_1 +Execute_AC_13 48_5_1 +Execute_AC_13 48_6_1 # High reliability # Execute_AC_13 8_1_2 # BT_ISO_FLAGS_ERROR diff --git a/tests/bsim/bluetooth/audio/test_scripts/cap_broadcast_ac_14.sh b/tests/bsim/bluetooth/audio/test_scripts/cap_broadcast_ac_14.sh index 2b0735cd911..4788975e59f 100755 --- a/tests/bsim/bluetooth/audio/test_scripts/cap_broadcast_ac_14.sh +++ b/tests/bsim/bluetooth/audio/test_scripts/cap_broadcast_ac_14.sh @@ -4,7 +4,7 @@ # # SPDX-License-Identifier: Apache-2.0 -SIMULATION_ID="cap_unicast_ac_14" +SIMULATION_ID="cap_broadcast_ac_14" VERBOSITY_LEVEL=2 EXECUTE_TIMEOUT=60 @@ -41,14 +41,14 @@ Execute_AC_14 24_1_1 Execute_AC_14 24_2_1 Execute_AC_14 32_1_1 Execute_AC_14 32_2_1 -# Execute_AC_14 441_1_1 # BT_ISO_FLAGS_ERROR -# Execute_AC_14 441_2_1 # Failed to create BIG: -22 -# Execute_AC_14 48_1_1 # BT_ISO_FLAGS_ERROR +Execute_AC_14 441_1_1 +Execute_AC_14 441_2_1 +Execute_AC_14 48_1_1 Execute_AC_14 48_2_1 -# Execute_AC_14 48_3_1 # BT_ISO_FLAGS_ERROR +Execute_AC_14 48_3_1 Execute_AC_14 48_4_1 -# Execute_AC_14 48_5_1 # BT_ISO_FLAGS_ERROR -# Execute_AC_14 48_6_1 # Failed to create BIG: -22 +Execute_AC_14 48_5_1 +Execute_AC_14 48_6_1 # High reliability # Execute_AC_14 8_1_2 # BT_ISO_FLAGS_ERROR diff --git a/tests/bsim/bluetooth/audio/test_scripts/gmap_broadcast_ac_12.sh b/tests/bsim/bluetooth/audio/test_scripts/gmap_broadcast_ac_12.sh index 2038ef4a163..fa9d62b8e16 100755 --- a/tests/bsim/bluetooth/audio/test_scripts/gmap_broadcast_ac_12.sh +++ b/tests/bsim/bluetooth/audio/test_scripts/gmap_broadcast_ac_12.sh @@ -4,7 +4,7 @@ # # SPDX-License-Identifier: Apache-2.0 -SIMULATION_ID="gmap_unicast_ac_12" +SIMULATION_ID="gmap_broadcast_ac_12" VERBOSITY_LEVEL=2 EXECUTE_TIMEOUT=60 diff --git a/tests/bsim/bluetooth/audio/test_scripts/gmap_broadcast_ac_13.sh b/tests/bsim/bluetooth/audio/test_scripts/gmap_broadcast_ac_13.sh index a6bfcac4903..0f442f2e3a7 100755 --- a/tests/bsim/bluetooth/audio/test_scripts/gmap_broadcast_ac_13.sh +++ b/tests/bsim/bluetooth/audio/test_scripts/gmap_broadcast_ac_13.sh @@ -4,7 +4,7 @@ # # SPDX-License-Identifier: Apache-2.0 -SIMULATION_ID="gmap_unicast_ac_13" +SIMULATION_ID="gmap_broadcast_ac_13" VERBOSITY_LEVEL=2 EXECUTE_TIMEOUT=60 @@ -33,7 +33,7 @@ function Execute_AC_13() { set -e # Exit on error # Low latency tests -# Execute_AC_13 48_1_g # BT_ISO_FLAGS_ERROR +Execute_AC_13 48_1_g Execute_AC_13 48_2_g -# Execute_AC_13 48_3_g # BT_ISO_FLAGS_ERROR +Execute_AC_13 48_3_g Execute_AC_13 48_4_g diff --git a/tests/bsim/bluetooth/audio/test_scripts/gmap_broadcast_ac_14.sh b/tests/bsim/bluetooth/audio/test_scripts/gmap_broadcast_ac_14.sh index b73c67f42fe..dbde3ef33c7 100755 --- a/tests/bsim/bluetooth/audio/test_scripts/gmap_broadcast_ac_14.sh +++ b/tests/bsim/bluetooth/audio/test_scripts/gmap_broadcast_ac_14.sh @@ -4,7 +4,7 @@ # # SPDX-License-Identifier: Apache-2.0 -SIMULATION_ID="gmap_unicast_ac_14" +SIMULATION_ID="gmap_broadcast_ac_14" VERBOSITY_LEVEL=2 EXECUTE_TIMEOUT=60 From 6ec2dbf8ee3d7ed66bc7a1f5cbaeb599a58cf229 Mon Sep 17 00:00:00 2001 From: Gerard Marull-Paretas Date: Thu, 25 Jan 2024 16:59:40 +0100 Subject: [PATCH 3190/3723] dts: bindings: nordic,nrf-ficr: move to misc folder It's not related to ARM. Signed-off-by: Gerard Marull-Paretas --- dts/bindings/{arm => misc}/nordic,nrf-ficr.yaml | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename dts/bindings/{arm => misc}/nordic,nrf-ficr.yaml (100%) diff --git a/dts/bindings/arm/nordic,nrf-ficr.yaml b/dts/bindings/misc/nordic,nrf-ficr.yaml similarity index 100% rename from dts/bindings/arm/nordic,nrf-ficr.yaml rename to dts/bindings/misc/nordic,nrf-ficr.yaml From ed0fc03f677b5cc5552c477b0f288cb4a77aa4e9 Mon Sep 17 00:00:00 2001 From: Gerard Marull-Paretas Date: Mon, 20 Nov 2023 23:34:32 +0100 Subject: [PATCH 3191/3723] dts: bindings: arm: nordic,nrf-ficr: add #nordic,ficr-cells Add a new #nordic,ficr-cells property, so that we can specify a FICR offset in a phandle-array, e.g. nordic,ficrs = <&ficr 0xff>; Signed-off-by: Gerard Marull-Paretas --- dts/arm/nordic/nrf51822.dtsi | 1 + dts/arm/nordic/nrf52805.dtsi | 1 + dts/arm/nordic/nrf52810.dtsi | 1 + dts/arm/nordic/nrf52811.dtsi | 1 + dts/arm/nordic/nrf52820.dtsi | 1 + dts/arm/nordic/nrf52832.dtsi | 1 + dts/arm/nordic/nrf52833.dtsi | 1 + dts/arm/nordic/nrf52840.dtsi | 1 + dts/arm/nordic/nrf5340_cpuapp.dtsi | 1 + dts/arm/nordic/nrf5340_cpunet.dtsi | 1 + dts/arm/nordic/nrf54l15_cpuapp.dtsi | 1 + dts/arm/nordic/nrf91.dtsi | 1 + dts/bindings/misc/nordic,nrf-ficr.yaml | 8 ++++++++ 13 files changed, 20 insertions(+) diff --git a/dts/arm/nordic/nrf51822.dtsi b/dts/arm/nordic/nrf51822.dtsi index 020711a7e7f..499140a0fb8 100644 --- a/dts/arm/nordic/nrf51822.dtsi +++ b/dts/arm/nordic/nrf51822.dtsi @@ -24,6 +24,7 @@ ficr: ficr@10000000 { compatible = "nordic,nrf-ficr"; reg = <0x10000000 0x1000>; + #nordic,ficr-cells = <1>; status = "okay"; }; diff --git a/dts/arm/nordic/nrf52805.dtsi b/dts/arm/nordic/nrf52805.dtsi index a54e8eca9c6..c8839897f3c 100644 --- a/dts/arm/nordic/nrf52805.dtsi +++ b/dts/arm/nordic/nrf52805.dtsi @@ -28,6 +28,7 @@ ficr: ficr@10000000 { compatible = "nordic,nrf-ficr"; reg = <0x10000000 0x1000>; + #nordic,ficr-cells = <1>; status = "okay"; }; diff --git a/dts/arm/nordic/nrf52810.dtsi b/dts/arm/nordic/nrf52810.dtsi index ce5a2bce779..cd2543ce511 100644 --- a/dts/arm/nordic/nrf52810.dtsi +++ b/dts/arm/nordic/nrf52810.dtsi @@ -32,6 +32,7 @@ ficr: ficr@10000000 { compatible = "nordic,nrf-ficr"; reg = <0x10000000 0x1000>; + #nordic,ficr-cells = <1>; status = "okay"; }; diff --git a/dts/arm/nordic/nrf52811.dtsi b/dts/arm/nordic/nrf52811.dtsi index 9c9a3fa6b77..4034b4958e7 100644 --- a/dts/arm/nordic/nrf52811.dtsi +++ b/dts/arm/nordic/nrf52811.dtsi @@ -36,6 +36,7 @@ ficr: ficr@10000000 { compatible = "nordic,nrf-ficr"; reg = <0x10000000 0x1000>; + #nordic,ficr-cells = <1>; status = "okay"; }; diff --git a/dts/arm/nordic/nrf52820.dtsi b/dts/arm/nordic/nrf52820.dtsi index c210a7c23aa..c702cd45227 100644 --- a/dts/arm/nordic/nrf52820.dtsi +++ b/dts/arm/nordic/nrf52820.dtsi @@ -37,6 +37,7 @@ ficr: ficr@10000000 { compatible = "nordic,nrf-ficr"; reg = <0x10000000 0x1000>; + #nordic,ficr-cells = <1>; status = "okay"; }; diff --git a/dts/arm/nordic/nrf52832.dtsi b/dts/arm/nordic/nrf52832.dtsi index 2e1fd68946b..d3fb288f449 100644 --- a/dts/arm/nordic/nrf52832.dtsi +++ b/dts/arm/nordic/nrf52832.dtsi @@ -32,6 +32,7 @@ ficr: ficr@10000000 { compatible = "nordic,nrf-ficr"; reg = <0x10000000 0x1000>; + #nordic,ficr-cells = <1>; status = "okay"; }; diff --git a/dts/arm/nordic/nrf52833.dtsi b/dts/arm/nordic/nrf52833.dtsi index d55f0f6df9e..9ba7a85ad4a 100644 --- a/dts/arm/nordic/nrf52833.dtsi +++ b/dts/arm/nordic/nrf52833.dtsi @@ -36,6 +36,7 @@ ficr: ficr@10000000 { compatible = "nordic,nrf-ficr"; reg = <0x10000000 0x1000>; + #nordic,ficr-cells = <1>; status = "okay"; }; diff --git a/dts/arm/nordic/nrf52840.dtsi b/dts/arm/nordic/nrf52840.dtsi index e833835198b..ae7a0b58ae9 100644 --- a/dts/arm/nordic/nrf52840.dtsi +++ b/dts/arm/nordic/nrf52840.dtsi @@ -32,6 +32,7 @@ ficr: ficr@10000000 { compatible = "nordic,nrf-ficr"; reg = <0x10000000 0x1000>; + #nordic,ficr-cells = <1>; status = "okay"; }; diff --git a/dts/arm/nordic/nrf5340_cpuapp.dtsi b/dts/arm/nordic/nrf5340_cpuapp.dtsi index bc6b5316519..02b115b3cfe 100644 --- a/dts/arm/nordic/nrf5340_cpuapp.dtsi +++ b/dts/arm/nordic/nrf5340_cpuapp.dtsi @@ -41,6 +41,7 @@ ficr: ficr@ff0000 { compatible = "nordic,nrf-ficr"; reg = <0xff0000 0x1000>; + #nordic,ficr-cells = <1>; status = "okay"; }; diff --git a/dts/arm/nordic/nrf5340_cpunet.dtsi b/dts/arm/nordic/nrf5340_cpunet.dtsi index d930cf603c0..ae819dfb64f 100644 --- a/dts/arm/nordic/nrf5340_cpunet.dtsi +++ b/dts/arm/nordic/nrf5340_cpunet.dtsi @@ -35,6 +35,7 @@ ficr: ficr@1ff0000 { compatible = "nordic,nrf-ficr"; reg = <0x01ff0000 0x1000>; + #nordic,ficr-cells = <1>; status = "okay"; }; diff --git a/dts/arm/nordic/nrf54l15_cpuapp.dtsi b/dts/arm/nordic/nrf54l15_cpuapp.dtsi index 7e90c8b1213..df4ccc52294 100644 --- a/dts/arm/nordic/nrf54l15_cpuapp.dtsi +++ b/dts/arm/nordic/nrf54l15_cpuapp.dtsi @@ -51,6 +51,7 @@ ficr: ficr@ffc000 { compatible = "nordic,nrf-ficr"; reg = <0xffc000 0x1000>; + #nordic,ficr-cells = <1>; }; sram0: memory@20000000 { diff --git a/dts/arm/nordic/nrf91.dtsi b/dts/arm/nordic/nrf91.dtsi index 81be475d775..4ed7451bb61 100644 --- a/dts/arm/nordic/nrf91.dtsi +++ b/dts/arm/nordic/nrf91.dtsi @@ -91,6 +91,7 @@ ficr: ficr@ff0000 { compatible = "nordic,nrf-ficr"; reg = <0xff0000 0x1000>; + #nordic,ficr-cells = <1>; status = "okay"; }; diff --git a/dts/bindings/misc/nordic,nrf-ficr.yaml b/dts/bindings/misc/nordic,nrf-ficr.yaml index bea0762573e..ca199c24f07 100644 --- a/dts/bindings/misc/nordic,nrf-ficr.yaml +++ b/dts/bindings/misc/nordic,nrf-ficr.yaml @@ -7,3 +7,11 @@ include: base.yaml properties: reg: required: true + + "#nordic,ficr-cells": + type: int + required: true + const: 1 + +nordic,ficr-cells: + - offset From e57ad265fb4fd9f2fcd1237b8ee7897245b62fcd Mon Sep 17 00:00:00 2001 From: Gerard Marull-Paretas Date: Thu, 25 Jan 2024 17:06:24 +0100 Subject: [PATCH 3192/3723] dts: bindings: misc: add nordic-nrf-ficr-client So that FICR clients can include this file instead of redefining FICR properties every time. Signed-off-by: Gerard Marull-Paretas --- dts/bindings/misc/nordic-nrf-ficr-client.yaml | 14 ++++++++++++++ 1 file changed, 14 insertions(+) create mode 100644 dts/bindings/misc/nordic-nrf-ficr-client.yaml diff --git a/dts/bindings/misc/nordic-nrf-ficr-client.yaml b/dts/bindings/misc/nordic-nrf-ficr-client.yaml new file mode 100644 index 00000000000..06a1e727f3f --- /dev/null +++ b/dts/bindings/misc/nordic-nrf-ficr-client.yaml @@ -0,0 +1,14 @@ +# Copyright (c) 2024 Nordic Semiconductor ASA +# SPDX-License-Identifier: Apache-2.0 + +properties: + nordic,ficrs: + type: phandle-array + description: | + FICR entries, e.g. <&ficr OFFSET>. Available offsets (or FICR entries) are + available at . + + nordic,ficr-names: + type: string-array + description: | + Names of each nordic,ficrs entry. From 5273af6ba80a5919fd56e69d05b820beadb3ec0e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C5=81ukasz=20Duda?= Date: Sun, 28 Jan 2024 16:51:38 +0100 Subject: [PATCH 3193/3723] net: ipv6: nbr: Add IPv6 reachability confirmation API MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This commit introduces a new IPv6 API for positive reachability confirmation, as specified in RFC 4861, Section 7.3.1. This feature aims to enhance the effectiveness of the Neighbor Discovery mechanism, by enabling upper-layer protocols to signal that the connection makes a "forward progress". The implementation within TCP serves as a reference. Compliance with RFC 4861, especially Appendix E.1, was ensured by focusing on reliable handshake and acknowledgment of new data transmissions. Though initially integrated with TCP, the API is designed for broader applicability. For example, it might be used by some UDP-based protocols that can indicate two-way communication progress. Signed-off-by: Łukasz Duda --- subsys/net/ip/Kconfig.tcp | 9 +++++++++ subsys/net/ip/ipv6.h | 23 +++++++++++++++++++++++ subsys/net/ip/ipv6_nbr.c | 21 +++++++++++++++++++++ subsys/net/ip/tcp.c | 33 +++++++++++++++++++++++++++++++++ tests/net/ipv6/src/main.c | 25 +++++++++++++++++++++++++ 5 files changed, 111 insertions(+) diff --git a/subsys/net/ip/Kconfig.tcp b/subsys/net/ip/Kconfig.tcp index 034b3b99f81..8342acfb59a 100644 --- a/subsys/net/ip/Kconfig.tcp +++ b/subsys/net/ip/Kconfig.tcp @@ -244,4 +244,13 @@ config NET_TCP_REJECT_CONN_WITH_RST If enabled, TCP stack will reject connection attempts on unbound ports with TCP RST packet. +config NET_TCP_IPV6_ND_REACHABILITY_HINT + bool "Provide a reachability hint for IPv6 Neighbor Discovery" + depends on NET_TCP + depends on NET_IPV6_ND + help + If enabled, TCP stack will inform the IPv6 Neighbor Discovery process + about the active link to a specific neighbor by signaling recent + "forward progress" event as described in RFC 4861. + endif # NET_TCP diff --git a/subsys/net/ip/ipv6.h b/subsys/net/ip/ipv6.h index be97731577a..ae5342ef497 100644 --- a/subsys/net/ip/ipv6.h +++ b/subsys/net/ip/ipv6.h @@ -385,6 +385,29 @@ static inline void net_ipv6_nbr_foreach(net_nbr_cb_t cb, void *user_data) } #endif /* CONFIG_NET_IPV6_NBR_CACHE */ +/** + * @brief Provide a reachability hint for IPv6 Neighbor Discovery. + * + * This function is intended for upper-layer protocols to inform the IPv6 + * Neighbor Discovery process about the active link to a specific neighbor. + * By signaling recent "forward progress" event, such as the reception of + * an ACK, this function can help reducing unnecessary ND traffic as per the + * guidelines in RFC 4861 (section 7.3). + * + * @param iface A pointer to the network interface. + * @param ipv6_addr Pointer to the IPv6 address of the neighbor node. + */ +#if defined(CONFIG_NET_IPV6_ND) && defined(CONFIG_NET_NATIVE_IPV6) +void net_ipv6_nbr_reachability_hint(struct net_if *iface, const struct in6_addr *ipv6_addr); +#else +static inline void net_ipv6_nbr_reachability_hint(struct net_if *iface, + const struct in6_addr *ipv6_addr) +{ + ARG_UNUSED(iface); + ARG_UNUSED(ipv6_addr); +} +#endif + /** * @brief Set the neighbor reachable timer. * diff --git a/subsys/net/ip/ipv6_nbr.c b/subsys/net/ip/ipv6_nbr.c index 76029b47c11..0eef2907726 100644 --- a/subsys/net/ip/ipv6_nbr.c +++ b/subsys/net/ip/ipv6_nbr.c @@ -1536,6 +1536,27 @@ void net_ipv6_nbr_set_reachable_timer(struct net_if *iface, ipv6_nd_restart_reachable_timer(nbr, time); } + +void net_ipv6_nbr_reachability_hint(struct net_if *iface, + const struct in6_addr *ipv6_addr) +{ + struct net_nbr *nbr = NULL; + + nbr = nbr_lookup(&net_neighbor.table, iface, ipv6_addr); + + NET_DBG("nbr %p got rechability hint", nbr); + + if (nbr && net_ipv6_nbr_data(nbr)->state != NET_IPV6_NBR_STATE_INCOMPLETE && + net_ipv6_nbr_data(nbr)->state != NET_IPV6_NBR_STATE_STATIC) { + ipv6_nbr_set_state(nbr, NET_IPV6_NBR_STATE_REACHABLE); + + /* We might have active timer from PROBE */ + net_ipv6_nbr_data(nbr)->reachable = 0; + net_ipv6_nbr_data(nbr)->reachable_timeout = 0; + + net_ipv6_nbr_set_reachable_timer(iface, nbr); + } +} #endif /* CONFIG_NET_IPV6_ND */ #if defined(CONFIG_NET_IPV6_NBR_CACHE) diff --git a/subsys/net/ip/tcp.c b/subsys/net/ip/tcp.c index 41df924607c..b7dbc7b47b8 100644 --- a/subsys/net/ip/tcp.c +++ b/subsys/net/ip/tcp.c @@ -956,6 +956,23 @@ static void tcp_send_timer_cancel(struct tcp *conn) } } +#if defined(CONFIG_NET_TCP_IPV6_ND_REACHABILITY_HINT) + +static void tcp_nbr_reachability_hint(struct tcp *conn) +{ + if (net_context_get_family(conn->context) == AF_INET6) { + net_ipv6_nbr_reachability_hint( + net_context_get_iface(conn->context), + &conn->dst.sin6.sin6_addr); + } +} + +#else /* CONFIG_NET_TCP_IPV6_ND_REACHABILITY_HINT */ + +#define tcp_nbr_reachability_hint(...) + +#endif /* CONFIG_NET_TCP_IPV6_ND_REACHABILITY_HINT */ + static const char *tcp_state_to_str(enum tcp_state state, bool prefix) { const char *s = NULL; @@ -2921,6 +2938,11 @@ static enum net_verdict tcp_in(struct tcp *conn, struct net_pkt *pkt) } else { verdict = NET_OK; } + + /* ACK for SYN | ACK has been received. This signilizes that + * the connection makes a "forward progress". + */ + tcp_nbr_reachability_hint(conn); } break; case TCP_SYN_SENT: @@ -2957,6 +2979,11 @@ static enum net_verdict tcp_in(struct tcp *conn, struct net_pkt *pkt) * priority. */ connection_ok = true; + + /* ACK for SYN has been received. This signilizes that + * the connection makes a "forward progress". + */ + tcp_nbr_reachability_hint(conn); } else if (pkt) { net_tcp_reply_rst(pkt); } @@ -3090,6 +3117,12 @@ static enum net_verdict tcp_in(struct tcp *conn, struct net_pkt *pkt) conn_seq(conn, + len_acked); net_stats_update_tcp_seg_recv(conn->iface); + /* Receipt of an acknowledgment that covers a sequence number + * not previously acknowledged indicates that the connection + * makes a "forward progress". + */ + tcp_nbr_reachability_hint(conn); + conn_send_data_dump(conn); conn->send_data_retries = 0; diff --git a/tests/net/ipv6/src/main.c b/tests/net/ipv6/src/main.c index ea734afae3e..f9ca6832009 100644 --- a/tests/net/ipv6/src/main.c +++ b/tests/net/ipv6/src/main.c @@ -1657,4 +1657,29 @@ ZTEST(net_ipv6, test_no_nd_flag) net_if_flag_clear(iface, NET_IF_IPV6_NO_ND); } +ZTEST(net_ipv6, test_nd_reachability_hint) +{ + struct net_nbr *nbr; + + nbr = net_ipv6_nbr_lookup(TEST_NET_IF, &peer_addr); + zassert_not_null(nbr, "Neighbor %s not found in cache\n", + net_sprint_ipv6_addr(&peer_addr)); + + /* Configure neighbor's state to STALE. */ + net_ipv6_nbr_data(nbr)->state = NET_IPV6_NBR_STATE_STALE; + + net_ipv6_nbr_reachability_hint(TEST_NET_IF, &peer_addr); + zassert_equal(net_ipv6_nbr_data(nbr)->state, NET_IPV6_NBR_STATE_REACHABLE); + + /* Configure neighbor's state to PROBE. */ + net_ipv6_nbr_data(nbr)->state = NET_IPV6_NBR_STATE_PROBE; + + /* Additionally ensure that state is not changed for different interface ID. */ + net_ipv6_nbr_reachability_hint(TEST_NET_IF + 1, &peer_addr); + zassert_equal(net_ipv6_nbr_data(nbr)->state, NET_IPV6_NBR_STATE_PROBE); + + net_ipv6_nbr_reachability_hint(TEST_NET_IF, &peer_addr); + zassert_equal(net_ipv6_nbr_data(nbr)->state, NET_IPV6_NBR_STATE_REACHABLE); +} + ZTEST_SUITE(net_ipv6, NULL, ipv6_setup, NULL, NULL, ipv6_teardown); From b5a9e8b03191b9b235b09d83bf96c0f20d649a64 Mon Sep 17 00:00:00 2001 From: "Najumon B.A" Date: Thu, 9 Nov 2023 14:23:38 +0530 Subject: [PATCH 3194/3723] arch: x86: add a sperate timer interface for acpica lib add a separate timer interface for acpica lib instead of using system timer which might use driver interface such as HPET and this might cause init priority issue if a driver which need to init before system timer driver instantiate. Signed-off-by: Najumon B.A --- include/zephyr/arch/x86/x86_acpi_osal.h | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/include/zephyr/arch/x86/x86_acpi_osal.h b/include/zephyr/arch/x86/x86_acpi_osal.h index 8f742b024b7..2395cac1951 100644 --- a/include/zephyr/arch/x86/x86_acpi_osal.h +++ b/include/zephyr/arch/x86/x86_acpi_osal.h @@ -26,4 +26,9 @@ static inline void *acpi_rsdp_get(void) return bios_acpi_rsdp_get(); } #endif /* CONFIG_X86_EFI */ + +static inline uint64_t acpi_timer_get(void) +{ + return z_tsc_read(); +} #endif /* ZEPHYR_ARCH_X86_INCLUDE_X86_ACPI_H_ */ From 08c0b98eefc725ea3c0e0cb324888621f4cb9fe0 Mon Sep 17 00:00:00 2001 From: "Najumon B.A" Date: Thu, 9 Nov 2023 15:02:43 +0530 Subject: [PATCH 3195/3723] manifest: update west point to latest acpica commit update west to latest acpica commit for timer interface changes Signed-off-by: Najumon B.A --- west.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/west.yml b/west.yml index 7b478c011fb..70a8d7781fa 100644 --- a/west.yml +++ b/west.yml @@ -30,7 +30,7 @@ manifest: # Please add items below based on alphabetical order projects: - name: acpica - revision: 10ae1038e51eb9306f73c3bbcfc4fde954bb9625 + revision: da5f2721e1c7f188fe04aa50af76f4b94f3c3ea3 path: modules/lib/acpica - name: bsim repo-path: babblesim-manifest From dd9e0df06b74beeead8d2abf6ef0a5e64e9cba8e Mon Sep 17 00:00:00 2001 From: "Najumon B.A" Date: Fri, 15 Sep 2023 15:25:47 +0530 Subject: [PATCH 3196/3723] arch: x86: add interface for encode irq flags add interface for encode irq flags from acpica to arch specfic. Currently enabled only for x86 archiecture. Signed-off-by: Najumon B.A --- arch/x86/core/CMakeLists.txt | 1 + arch/x86/core/x86_acpi.c | 26 ++++++++++++++++++++++++++ include/zephyr/arch/x86/arch_inlines.h | 2 ++ include/zephyr/arch/x86/x86_acpi.h | 14 ++++++++++++++ 4 files changed, 43 insertions(+) create mode 100644 arch/x86/core/x86_acpi.c create mode 100644 include/zephyr/arch/x86/x86_acpi.h diff --git a/arch/x86/core/CMakeLists.txt b/arch/x86/core/CMakeLists.txt index 9268dc4cf4d..e8055c6fae2 100644 --- a/arch/x86/core/CMakeLists.txt +++ b/arch/x86/core/CMakeLists.txt @@ -16,6 +16,7 @@ zephyr_library_sources_ifdef(CONFIG_REBOOT_RST_CNT reboot_rst_cnt.c) zephyr_library_sources_ifdef(CONFIG_MULTIBOOT_INFO multiboot.c) zephyr_library_sources_ifdef(CONFIG_X86_EFI efi.c) zephyr_library_sources_ifdef(CONFIG_ACPI legacy_bios.c) +zephyr_library_sources_ifdef(CONFIG_ACPI x86_acpi.c) zephyr_library_sources_ifdef(CONFIG_X86_MMU x86_mmu.c) zephyr_library_sources_ifdef(CONFIG_USERSPACE userspace.c) zephyr_library_sources_ifdef(CONFIG_ARCH_CACHE cache.c) diff --git a/arch/x86/core/x86_acpi.c b/arch/x86/core/x86_acpi.c new file mode 100644 index 00000000000..badbd3b414f --- /dev/null +++ b/arch/x86/core/x86_acpi.c @@ -0,0 +1,26 @@ +/* + * Copyright (c) 2023, Intel Corporation + * + * SPDX-License-Identifier: Apache-2.0 + */ +#include +#include + +uint32_t arch_acpi_encode_irq_flags(uint8_t polarity, uint8_t trigger) +{ + uint32_t irq_flag = IRQ_DELIVERY_LOWEST; + + if (trigger == ACPI_LEVEL_SENSITIVE) { + irq_flag |= IRQ_TYPE_LEVEL; + } else { + irq_flag |= IRQ_TYPE_EDGE; + } + + if (polarity == ACPI_ACTIVE_HIGH) { + irq_flag |= IRQ_TYPE_HIGH; + } else if (polarity == ACPI_ACTIVE_LOW) { + irq_flag |= IRQ_TYPE_LOW; + } + + return irq_flag; +} diff --git a/include/zephyr/arch/x86/arch_inlines.h b/include/zephyr/arch/x86/arch_inlines.h index 4b255acc853..356e7920c66 100644 --- a/include/zephyr/arch/x86/arch_inlines.h +++ b/include/zephyr/arch/x86/arch_inlines.h @@ -10,6 +10,8 @@ #ifndef _ASMLANGUAGE +#include + #if defined(CONFIG_X86_64) #include diff --git a/include/zephyr/arch/x86/x86_acpi.h b/include/zephyr/arch/x86/x86_acpi.h new file mode 100644 index 00000000000..013400e6fe6 --- /dev/null +++ b/include/zephyr/arch/x86/x86_acpi.h @@ -0,0 +1,14 @@ +/* + * Copyright (c) 2023, Intel Corporation + * + * SPDX-License-Identifier: Apache-2.0 + */ + +/** + * @brief Encode interrupt flag for x86 architecture. + * + * @param polarity the interrupt polarity received from ACPICA lib + * @param trigger the interrupt level received from ACPICA lib + * @return return encoded interrupt flag + */ +uint32_t arch_acpi_encode_irq_flags(uint8_t polarity, uint8_t trigger); From 2f3fb49d762ccb0d141706c5645028091dc938b8 Mon Sep 17 00:00:00 2001 From: "Najumon B.A" Date: Fri, 15 Sep 2023 15:29:19 +0530 Subject: [PATCH 3197/3723] lib: acpi: add device resource enum support add device resource enumaration support such as irq and mmio. Signed-off-by: Najumon B.A --- dts/bindings/acpi/acpi.yaml | 23 ++++ include/zephyr/acpi/acpi.h | 138 ++++++++++++++++++--- lib/acpi/Kconfig | 22 ++-- lib/acpi/acpi.c | 235 +++++++++++++++++++++++++----------- 4 files changed, 322 insertions(+), 96 deletions(-) create mode 100644 dts/bindings/acpi/acpi.yaml diff --git a/dts/bindings/acpi/acpi.yaml b/dts/bindings/acpi/acpi.yaml new file mode 100644 index 00000000000..26a7dd803b1 --- /dev/null +++ b/dts/bindings/acpi/acpi.yaml @@ -0,0 +1,23 @@ +# Copyright (c) 2023 Intel Corporation +# SPDX-License-Identifier: Apache-2.0 + +# Common fields for ACPI informed based devices + +properties: + acpi-hid: + type: string + description: Used to supply OSPM with the device’s PNP ID or ACPI ID. + A node is consder as acpi based or not based on whether this property + is present or not. + + acpi-uid: + type: string + description: | + Provides OSPM with a logical device ID that does not change + across reboots. This object is optional, but is required when the device + has no other way to report a persistent unique device ID. The _UID must be + unique across all devices with either a common _HID or _CID. + + acpi-comp-id: + type: string-array + description: Used to supply OSPM with a device’s Plug and Play-Compatible Device ID diff --git a/include/zephyr/acpi/acpi.h b/include/zephyr/acpi/acpi.h index b74f4f10a15..0685355e6d1 100644 --- a/include/zephyr/acpi/acpi.h +++ b/include/zephyr/acpi/acpi.h @@ -15,10 +15,30 @@ #define ACPI_DMAR_FLAG_X2APIC_OPT_OUT BIT(1) #define ACPI_DMAR_FLAG_DMA_CTRL_PLATFORM_OPT_IN BIT(2) +#define ACPI_MMIO_GET(res) (res)->reg_base[0].mmio +#define ACPI_IO_GET(res) (res)->reg_base[0].port +#define ACPI_RESOURCE_SIZE_GET(res) (res)->reg_base[0].length +#define ACPI_RESOURCE_TYPE_GET(res) (res)->reg_base[0].type + +#define ACPI_MULTI_MMIO_GET(res, idx) (res)->reg_base[idx].mmio +#define ACPI_MULTI_IO_GET(res, idx) (res)->reg_base[idx].port +#define ACPI_MULTI_RESOURCE_SIZE_GET(res, idx) (res)->reg_base[idx].length +#define ACPI_MULTI_RESOURCE_TYPE_GET(res, idx) (res)->reg_base[idx].type + +#define ACPI_RESOURCE_COUNT_GET(res) (res)->mmio_max + +enum acpi_res_type { + /** IO mapped Resource type */ + ACPI_RES_TYPE_IO, + /** Memory mapped Resource type */ + ACPI_RES_TYPE_MEM, + /** Unknown Resource type */ + ACPI_RES_TYPE_UNKNOWN, +}; + struct acpi_dev { ACPI_HANDLE handle; char *path; - char hid[CONFIG_ACPI_HID_LEN_MAX]; ACPI_RESOURCE *res_lst; int res_type; ACPI_DEVICE_INFO *dev_info; @@ -40,6 +60,72 @@ struct acpi_mcfg { ACPI_MCFG_ALLOCATION pci_segs[]; } __packed; +struct acpi_irq_resource { + uint32_t flags; + union { + uint16_t irq; + uint16_t irqs[CONFIG_ACPI_IRQ_VECTOR_MAX]; + }; + uint8_t irq_vector_max; +}; + +struct acpi_reg_base { + enum acpi_res_type type; + union { + uintptr_t mmio; + uintptr_t port; + }; + uint32_t length; +}; + +struct acpi_mmio_resource { + struct acpi_reg_base reg_base[CONFIG_ACPI_MMIO_ENTRIES_MAX]; + uint8_t mmio_max; +}; + +/** + * @brief Get the ACPI HID for a node + * + * @param node_id DTS node identifier + * @return The HID of the ACPI node + */ +#define ACPI_DT_HID(node_id) DT_PROP(node_id, acpi_hid) + +/** + * @brief Get the ACPI UID for a node if one exist + * + * @param node_id DTS node identifier + * @return The UID of the ACPI node else NULL if does not exist + */ +#define ACPI_DT_UID(node_id) DT_PROP_OR(node_id, acpi_uid, NULL) + +/** + * @brief check whether the node has ACPI HID property or not + * + * @param node_id DTS node identifier + * @return 1 if the node has the HID, 0 otherwise. + */ +#define ACPI_DT_HAS_HID(node_id) DT_NODE_HAS_PROP(node_id, acpi_hid) + +/** + * @brief check whether the node has ACPI UID property or not + * + * @param node_id DTS node identifier + * @return 1 if the node has the UID, 0 otherwise. + */ +#define ACPI_DT_HAS_UID(node_id) DT_NODE_HAS_PROP(node_id, acpi_uid) + +/** + * @brief Init legacy interrupt routing table information from ACPI. + * Currently assume platform have only one PCI bus. + * + * @param hid the hardware id of the ACPI child device + * @param uid the unique id of the ACPI child device. The uid can be + * NULL if only one device with given hid present in the platform. + * @return return 0 on success or error code + */ +int acpi_legacy_irq_init(const char *hid, const char *uid); + /** * @brief Retrieve a legacy interrupt number for a PCI device. * @@ -75,16 +161,6 @@ int acpi_possible_resource_get(char *dev_name, ACPI_RESOURCE **res); */ int acpi_current_resource_free(ACPI_RESOURCE *res); -/** - * @brief Retrieve IRQ routing table of a bus. - * - * @param bus_name the name of the bus - * @param rt_table the IRQ routing table - * @param rt_size number of elements in the IRQ routing table - * @return return 0 on success or error code - */ -int acpi_get_irq_routing_table(char *bus_name, ACPI_PCI_ROUTING_TABLE *rt_table, size_t rt_size); - /** * @brief Parse resource table for a given resource type. * @@ -95,13 +171,14 @@ int acpi_get_irq_routing_table(char *bus_name, ACPI_PCI_ROUTING_TABLE *rt_table, ACPI_RESOURCE *acpi_resource_parse(ACPI_RESOURCE *res, int res_type); /** - * @brief Retrieve acpi device info for given hardware id and unique id. + * @brief Retrieve ACPI device info for given hardware id and unique id. * - * @param hid the hardware id of the acpi child device - * @param inst the unique id of the acpi child device - * @return acpi child device info on success or NULL + * @param hid the hardware id of the ACPI child device + * @param uid the unique id of the ACPI child device. The uid can be + * NULL if only one device with given HID present in the platform. + * @return ACPI child device info on success or NULL */ -struct acpi_dev *acpi_device_get(char *hid, int inst); +struct acpi_dev *acpi_device_get(const char *hid, const char *uid); /** * @brief Retrieve acpi device info from the index. @@ -124,6 +201,24 @@ static inline ACPI_RESOURCE_IRQ *acpi_irq_res_get(ACPI_RESOURCE *res_lst) return res ? &res->Data.Irq : NULL; } +/** + * @brief Parse resource table for irq info. + * + * @param child_dev the device object of the ACPI node + * @param irq_res irq resource info + * @return return 0 on success or error code + */ +int acpi_device_irq_get(struct acpi_dev *child_dev, struct acpi_irq_resource *irq_res); + +/** + * @brief Parse resource table for MMIO info. + * + * @param child_dev the device object of the ACPI node + * @param mmio_res MMIO resource info + * @return return 0 on success or error code + */ +int acpi_device_mmio_get(struct acpi_dev *child_dev, struct acpi_mmio_resource *mmio_res); + /** * @brief Parse resource table for identify resource type. * @@ -196,4 +291,15 @@ int acpi_dmar_ioapic_get(uint16_t *ioapic_id); * @return local apic info on success or NULL otherwise */ ACPI_MADT_LOCAL_APIC *acpi_local_apic_get(int cpu_num); + +/** + * @brief invoke an ACPI method and return the result. + * + * @param path the path name of the ACPI object + * @param arg_list the list of arguments to be pass down + * @param ret_obj the ACPI result to be return + * @return return 0 on success or error code + */ +int acpi_invoke_method(char *path, ACPI_OBJECT_LIST *arg_list, ACPI_OBJECT *ret_obj); + #endif diff --git a/lib/acpi/Kconfig b/lib/acpi/Kconfig index 5431a1c7e28..34710aad92c 100644 --- a/lib/acpi/Kconfig +++ b/lib/acpi/Kconfig @@ -16,12 +16,6 @@ source "subsys/logging/Kconfig.template.log_config" if PCIE_PRT -config ACPI_PRT_BUS_NAME - string "ACPI name of PCI bus" - default "_SB.PCI0" - help - ACPI name of PCI bus. - config ACPI_MAX_PRT_ENTRY int "Size of PRT buffer" default 4096 @@ -46,10 +40,16 @@ config ACPI_DEV_MAX help maximum acpi child devices. -endif # ACPI +config ACPI_IRQ_VECTOR_MAX + int "Interrupt vectors per device" + default 32 + help + Maximum interrupt vectors per device. -config ACPI_HID_LEN_MAX - int "Size of HID name" - default 12 +config ACPI_MMIO_ENTRIES_MAX + int "MMIO entries per device" + default 32 help - Size of HID string. + Maximum MMIO entries per device. + +endif # ACPI diff --git a/lib/acpi/acpi.c b/lib/acpi/acpi.c index d9ae1819511..b3c1d717971 100644 --- a/lib/acpi/acpi.c +++ b/lib/acpi/acpi.c @@ -34,12 +34,12 @@ static int check_init_status(void) acpi.status = acpi_init(); } - if (ACPI_SUCCESS(acpi.status)) { - return 0; - } else { + if (ACPI_FAILURE(acpi.status)) { LOG_ERR("ACPI init was not success"); return -EIO; } + + return 0; } static void notify_handler(ACPI_HANDLE device, UINT32 value, void *ctx) @@ -216,6 +216,10 @@ static ACPI_STATUS dev_resource_enum_callback(ACPI_HANDLE obj_handle, UINT32 lev return AE_NO_MEMORY; } + if (!(dev_info->Valid & ACPI_VALID_HID)) { + goto exit; + } + child_dev = (struct acpi_dev *)&acpi.child_dev[acpi.num_dev++]; child_dev->handle = obj_handle; child_dev->dev_info = dev_info; @@ -241,7 +245,7 @@ static ACPI_STATUS dev_resource_enum_callback(ACPI_HANDLE obj_handle, UINT32 lev exit: - return status; + return AE_OK; } static int acpi_enum_devices(void) @@ -302,10 +306,10 @@ int acpi_current_resource_get(char *dev_name, ACPI_RESOURCE **res) if (ACPI_FAILURE(status)) { LOG_ERR("AcpiGetCurrentResources failed: %s", AcpiFormatException(status)); return -ENOTSUP; - } else { - *res = rt_buffer.Pointer; } + *res = rt_buffer.Pointer; + return 0; } @@ -345,41 +349,69 @@ int acpi_current_resource_free(ACPI_RESOURCE *res) } #ifdef CONFIG_PCIE_PRT -static int acpi_get_irq_table(char *bus_name, ACPI_PCI_ROUTING_TABLE *rt_table, uint32_t rt_size) +uint32_t acpi_legacy_irq_get(pcie_bdf_t bdf) +{ + uint32_t slot = PCIE_BDF_TO_DEV(bdf), pin; + + LOG_DBG(""); + + if (check_init_status()) { + return UINT_MAX; + } + + pin = (pcie_conf_read(bdf, PCIE_CONF_INTR) >> 8) & 0x3; + + LOG_DBG("Device irq info: slot:%d pin:%d", slot, pin); + + for (int i = 0; i < CONFIG_ACPI_MAX_PRT_ENTRY; i++) { + if (((acpi.pci_prt_table[i].Address >> 16) & 0xffff) == slot && + acpi.pci_prt_table[i].Pin + 1 == pin) { + LOG_DBG("[%d]Device irq info: slot:%d pin:%d irq:%d", i, slot, pin, + acpi.pci_prt_table[i].SourceIndex); + return acpi.pci_prt_table[i].SourceIndex; + } + } + + return UINT_MAX; +} + +int acpi_legacy_irq_init(const char *hid, const char *uid) { + struct acpi_dev *child_dev = acpi_device_get(hid, uid); + ACPI_PCI_ROUTING_TABLE *rt_table = acpi.pci_prt_table; ACPI_BUFFER rt_buffer; ACPI_NAMESPACE_NODE *node; ACPI_STATUS status; - LOG_DBG("%s", bus_name); + if (!child_dev) { + LOG_ERR("no such PCI bus device %s %s", hid, uid); + return -ENODEV; + } - node = acpi_evaluate_method(bus_name, METHOD_NAME__PRT); + node = acpi_evaluate_method(child_dev->path, METHOD_NAME__PRT); if (!node) { - LOG_ERR("Evaluation failed for given device: %s", bus_name); + LOG_ERR("Evaluation failed for given device: %s", child_dev->path); return -ENODEV; } rt_buffer.Pointer = rt_table; - rt_buffer.Length = rt_size * sizeof(ACPI_PCI_ROUTING_TABLE); + rt_buffer.Length = ARRAY_SIZE(acpi.pci_prt_table) * sizeof(ACPI_PCI_ROUTING_TABLE); status = AcpiGetIrqRoutingTable(node, &rt_buffer); if (ACPI_FAILURE(status)) { - LOG_ERR("unable to retrieve IRQ Routing Table: %s", bus_name); + LOG_ERR("unable to retrieve IRQ Routing Table: %s", child_dev->path); return -EIO; } - return 0; -} - -static int acpi_retrieve_legacy_irq(void) -{ - int ret; - - /* TODO: assume platform have only one PCH with single PCI bus (bus 0). */ - ret = acpi_get_irq_table(CONFIG_ACPI_PRT_BUS_NAME, - acpi.pci_prt_table, ARRAY_SIZE(acpi.pci_prt_table)); - if (ret) { - return ret; + if (rt_table->Source[0]) { + /* + * If Name path exist then PCI interrupts are configurable and are not hardwired to + * any specific interrupt inputs on the interrupt controller. OSPM can uses + * _PRS/_CRS/_SRS to configure interrupts. But currently leave existing PCI bus + * driver with arch_irq_allocate() menthod for allocate and configure interrupts + * without conflicting. + */ + return -ENOENT; } for (size_t i = 0; i < ARRAY_SIZE(acpi.pci_prt_table); i++) { @@ -393,66 +425,125 @@ static int acpi_retrieve_legacy_irq(void) } return 0; - } +#endif /* CONFIG_PCIE_PRT */ -int acpi_get_irq_routing_table(char *bus_name, - ACPI_PCI_ROUTING_TABLE *rt_table, size_t rt_size) +ACPI_RESOURCE *acpi_resource_parse(ACPI_RESOURCE *res, int res_type) { - int ret; + do { + if (!res->Length) { + LOG_DBG("zero length found!"); + break; + } else if (res->Type == res_type) { + break; + } + res = ACPI_NEXT_RESOURCE(res); + } while (res->Type != ACPI_RESOURCE_TYPE_END_TAG); - ret = check_init_status(); - if (ret) { - return ret; + if (res->Type == ACPI_RESOURCE_TYPE_END_TAG) { + return NULL; } - return acpi_get_irq_table(bus_name, rt_table, rt_size); + return res; } -uint32_t acpi_legacy_irq_get(pcie_bdf_t bdf) +int acpi_device_irq_get(struct acpi_dev *child_dev, struct acpi_irq_resource *irq_res) { - uint32_t slot = PCIE_BDF_TO_DEV(bdf), pin; + ACPI_RESOURCE *res = acpi_resource_parse(child_dev->res_lst, ACPI_RESOURCE_TYPE_IRQ); - LOG_DBG(""); + if (!res) { + res = acpi_resource_parse(child_dev->res_lst, ACPI_RESOURCE_TYPE_EXTENDED_IRQ); + if (!res) { + return -ENODEV; + } - if (check_init_status()) { - return UINT_MAX; - } + if (res->Data.ExtendedIrq.InterruptCount > CONFIG_ACPI_IRQ_VECTOR_MAX) { + return -ENOMEM; + } - pin = (pcie_conf_read(bdf, PCIE_CONF_INTR) >> 8) & 0x3; + memset(irq_res, 0, sizeof(struct acpi_irq_resource)); + irq_res->irq_vector_max = res->Data.ExtendedIrq.InterruptCount; + for (int i = 0; i < irq_res->irq_vector_max; i++) { + irq_res->irqs[i] = (uint16_t)res->Data.ExtendedIrq.Interrupts[i]; + } - LOG_DBG("Device irq info: slot:%d pin:%d", slot, pin); + irq_res->flags = arch_acpi_encode_irq_flags(res->Data.ExtendedIrq.Polarity, + res->Data.ExtendedIrq.Triggering); + } else { + if (res->Data.Irq.InterruptCount > CONFIG_ACPI_IRQ_VECTOR_MAX) { + return -ENOMEM; + } - for (int i = 0; i < CONFIG_ACPI_MAX_PRT_ENTRY; i++) { - if (((acpi.pci_prt_table[i].Address >> 16) & 0xffff) == slot && - acpi.pci_prt_table[i].Pin + 1 == pin) { - LOG_DBG("[%d]Device irq info: slot:%d pin:%d irq:%d", i, slot, pin, - acpi.pci_prt_table[i].SourceIndex); - return acpi.pci_prt_table[i].SourceIndex; + irq_res->irq_vector_max = res->Data.Irq.InterruptCount; + for (int i = 0; i < irq_res->irq_vector_max; i++) { + irq_res->irqs[i] = (uint16_t)res->Data.Irq.Interrupts[i]; } + + irq_res->flags = arch_acpi_encode_irq_flags(res->Data.ExtendedIrq.Polarity, + res->Data.ExtendedIrq.Triggering); } - return UINT_MAX; + return 0; } -#endif /* CONFIG_PCIE_PRT */ -ACPI_RESOURCE *acpi_resource_parse(ACPI_RESOURCE *res, int res_type) +int acpi_device_mmio_get(struct acpi_dev *child_dev, struct acpi_mmio_resource *mmio_res) { + ACPI_RESOURCE *res = child_dev->res_lst; + struct acpi_reg_base *reg_base = mmio_res->reg_base; + int mmio_cnt = 0; + do { if (!res->Length) { - LOG_DBG("Error: zero length found!"); + LOG_DBG("Found Acpi resource with zero length!"); break; - } else if (res->Type == res_type) { + } + + switch (res->Type) { + case ACPI_RESOURCE_TYPE_IO: + reg_base[mmio_cnt].type = ACPI_RES_TYPE_IO; + reg_base[mmio_cnt].port = (uint32_t)res->Data.Io.Minimum; + reg_base[mmio_cnt++].length = res->Data.Io.AddressLength; + break; + + case ACPI_RESOURCE_TYPE_FIXED_IO: + reg_base[mmio_cnt].type = ACPI_RES_TYPE_IO; + reg_base[mmio_cnt].port = (uint32_t)res->Data.FixedIo.Address; + reg_base[mmio_cnt++].length = res->Data.FixedIo.AddressLength; + break; + + case ACPI_RESOURCE_TYPE_MEMORY24: + reg_base[mmio_cnt].type = ACPI_RES_TYPE_MEM; + reg_base[mmio_cnt].mmio = (uintptr_t)res->Data.Memory24.Minimum; + reg_base[mmio_cnt++].length = res->Data.Memory24.AddressLength; + break; + + case ACPI_RESOURCE_TYPE_MEMORY32: + reg_base[mmio_cnt].type = ACPI_RES_TYPE_MEM; + reg_base[mmio_cnt].mmio = (uintptr_t)res->Data.Memory32.Minimum; + reg_base[mmio_cnt++].length = res->Data.Memory32.AddressLength; + break; + + case ACPI_RESOURCE_TYPE_FIXED_MEMORY32: + reg_base[mmio_cnt].type = ACPI_RES_TYPE_MEM; + reg_base[mmio_cnt].mmio = (uintptr_t)res->Data.FixedMemory32.Address; + reg_base[mmio_cnt++].length = res->Data.FixedMemory32.AddressLength; break; } + res = ACPI_NEXT_RESOURCE(res); + if (mmio_cnt >= CONFIG_ACPI_MMIO_ENTRIES_MAX && + res->Type != ACPI_RESOURCE_TYPE_END_TAG) { + return -ENOMEM; + } } while (res->Type != ACPI_RESOURCE_TYPE_END_TAG); - if (res->Type == ACPI_RESOURCE_TYPE_END_TAG) { - return NULL; + if (!mmio_cnt) { + return -ENODEV; } - return res; + mmio_res->mmio_max = mmio_cnt; + + return 0; } static int acpi_res_type(ACPI_RESOURCE *res) @@ -513,10 +604,10 @@ int acpi_device_type_get(ACPI_RESOURCE *res) return type; } -struct acpi_dev *acpi_device_get(char *hid, int inst) +struct acpi_dev *acpi_device_get(const char *hid, const char *uid) { struct acpi_dev *child_dev; - int i = 0, inst_id; + int i = 0; LOG_DBG(""); @@ -537,9 +628,8 @@ struct acpi_dev *acpi_device_get(char *hid, int inst) } if (!strcmp(hid, child_dev->dev_info->HardwareId.String)) { - if (child_dev->dev_info->UniqueId.Length) { - inst_id = atoi(child_dev->dev_info->UniqueId.String); - if (inst_id == inst) { + if (uid && child_dev->dev_info->UniqueId.Length) { + if (!strcmp(child_dev->dev_info->UniqueId.String, uid)) { return child_dev; } } else { @@ -836,6 +926,23 @@ ACPI_MADT_LOCAL_APIC *acpi_local_apic_get(int cpu_num) return NULL; } +int acpi_invoke_method(char *path, ACPI_OBJECT_LIST *arg_list, ACPI_OBJECT *ret_obj) +{ + ACPI_STATUS status; + ACPI_BUFFER ret_buff; + + ret_buff.Length = sizeof(*ret_obj); + ret_buff.Pointer = ret_obj; + + status = AcpiEvaluateObject(NULL, path, arg_list, &ret_buff); + if (ACPI_FAILURE(status)) { + LOG_ERR("error While executing %s method: %d", path, status); + return -EIO; + } + + return 0; +} + static int acpi_init(void) { ACPI_STATUS status; @@ -857,16 +964,6 @@ static int acpi_init(void) LOG_WRN("Error in enable pic mode acpi method:%d", status); } -#ifdef CONFIG_PCIE_PRT - int ret = acpi_retrieve_legacy_irq(); - - if (ret) { - LOG_ERR("Error in retrieve legacy interrupt info:%d", ret); - status = AE_ERROR; - goto exit; - } -#endif - acpi_enum_devices(); exit: From 940c66f82e8cd3fe1850d95b6ca57cbc4e365e12 Mon Sep 17 00:00:00 2001 From: "Najumon B.A" Date: Tue, 31 Oct 2023 19:24:38 +0530 Subject: [PATCH 3198/3723] boards: x86: add pci controller node with acpi pnp id add acpi pnp/hw id for pcie node to enable support for retreive interrupt routing information for pci legacy interrupt via acpi Signed-off-by: Najumon B.A --- boards/x86/intel_adl/Kconfig.defconfig | 2 -- boards/x86/intel_ehl/Kconfig.defconfig | 4 ---- boards/x86/intel_rpl/Kconfig.defconfig | 2 -- boards/x86/qemu_x86/qemu_x86.dts | 3 ++- dts/x86/intel/alder_lake.dtsi | 3 ++- dts/x86/intel/apollo_lake.dtsi | 3 ++- dts/x86/intel/elkhart_lake.dtsi | 3 ++- dts/x86/intel/raptor_lake_p.dtsi | 3 ++- dts/x86/intel/raptor_lake_s.dtsi | 3 ++- 9 files changed, 12 insertions(+), 14 deletions(-) diff --git a/boards/x86/intel_adl/Kconfig.defconfig b/boards/x86/intel_adl/Kconfig.defconfig index 6211c525030..5a61d2f552e 100644 --- a/boards/x86/intel_adl/Kconfig.defconfig +++ b/boards/x86/intel_adl/Kconfig.defconfig @@ -37,8 +37,6 @@ config HEAP_MEM_POOL_ADD_SIZE_ACPI default 64000000 config MAIN_STACK_SIZE default 320000 -config ACPI_PRT_BUS_NAME - default "_SB.PC00" if SHELL config SHELL_STACK_SIZE diff --git a/boards/x86/intel_ehl/Kconfig.defconfig b/boards/x86/intel_ehl/Kconfig.defconfig index f3a5519ee9b..ae8270faa64 100644 --- a/boards/x86/intel_ehl/Kconfig.defconfig +++ b/boards/x86/intel_ehl/Kconfig.defconfig @@ -19,10 +19,6 @@ config SHELL_BACKEND_SERIAL_INTERRUPT_DRIVEN default n endif -config ACPI_PRT_BUS_NAME - depends on ACPI - default "_SB.PC00" - config HEAP_MEM_POOL_ADD_SIZE_ACPI default 2097152 depends on ACPI diff --git a/boards/x86/intel_rpl/Kconfig.defconfig b/boards/x86/intel_rpl/Kconfig.defconfig index 1a71b32f84c..0458aef89be 100644 --- a/boards/x86/intel_rpl/Kconfig.defconfig +++ b/boards/x86/intel_rpl/Kconfig.defconfig @@ -36,8 +36,6 @@ config HEAP_MEM_POOL_ADD_SIZE_ACPI default 64000000 config MAIN_STACK_SIZE default 320000 -config ACPI_PRT_BUS_NAME - default "_SB.PC00" if SHELL config SHELL_STACK_SIZE diff --git a/boards/x86/qemu_x86/qemu_x86.dts b/boards/x86/qemu_x86/qemu_x86.dts index 62dfaf57b05..6117d7927ab 100644 --- a/boards/x86/qemu_x86/qemu_x86.dts +++ b/boards/x86/qemu_x86/qemu_x86.dts @@ -49,7 +49,8 @@ pcie0: pcie0 { #address-cells = <1>; #size-cells = <1>; - compatible = "intel,pcie"; + compatible = "pcie-controller"; + acpi-hid = "PNP0A08"; ranges; can0: can0 { diff --git a/dts/x86/intel/alder_lake.dtsi b/dts/x86/intel/alder_lake.dtsi index 973e95db153..968ca3ab1cf 100644 --- a/dts/x86/intel/alder_lake.dtsi +++ b/dts/x86/intel/alder_lake.dtsi @@ -48,7 +48,8 @@ pcie0: pcie0 { #address-cells = <1>; #size-cells = <1>; - compatible = "intel,pcie"; + compatible = "pcie-controller"; + acpi-hid = "PNP0A08"; ranges; smbus0: smbus0 { diff --git a/dts/x86/intel/apollo_lake.dtsi b/dts/x86/intel/apollo_lake.dtsi index ffe50483434..a439feea175 100644 --- a/dts/x86/intel/apollo_lake.dtsi +++ b/dts/x86/intel/apollo_lake.dtsi @@ -47,7 +47,8 @@ pcie0: pcie0 { #address-cells = <1>; #size-cells = <1>; - compatible = "intel,pcie"; + compatible = "pcie-controller"; + acpi-hid = "PNP0A08"; ranges; uart0: uart0 { diff --git a/dts/x86/intel/elkhart_lake.dtsi b/dts/x86/intel/elkhart_lake.dtsi index e23183df1d0..07b8dc5dc1a 100644 --- a/dts/x86/intel/elkhart_lake.dtsi +++ b/dts/x86/intel/elkhart_lake.dtsi @@ -52,7 +52,8 @@ pcie0: pcie0 { #address-cells = <1>; #size-cells = <1>; - compatible = "intel,pcie"; + compatible = "pcie-controller"; + acpi-hid = "PNP0A08"; ranges; ptm_root0: ptm_root0 { diff --git a/dts/x86/intel/raptor_lake_p.dtsi b/dts/x86/intel/raptor_lake_p.dtsi index 8f7dec863e2..1c6de091d2f 100644 --- a/dts/x86/intel/raptor_lake_p.dtsi +++ b/dts/x86/intel/raptor_lake_p.dtsi @@ -43,9 +43,10 @@ }; pcie0: pcie0 { - compatible = "intel,pcie"; + compatible = "pcie-controller"; #address-cells = <1>; #size-cells = <1>; + acpi-hid = "PNP0A08"; ranges; smbus0: smbus0 { diff --git a/dts/x86/intel/raptor_lake_s.dtsi b/dts/x86/intel/raptor_lake_s.dtsi index bafee1dc403..0e55b60a0b3 100644 --- a/dts/x86/intel/raptor_lake_s.dtsi +++ b/dts/x86/intel/raptor_lake_s.dtsi @@ -47,7 +47,8 @@ pcie0: pcie0 { #address-cells = <1>; #size-cells = <1>; - compatible = "intel,pcie"; + compatible = "pcie-controller"; + acpi-hid = "PNP0A08"; ranges; smbus0: smbus0 { From 34a2fbfba1ce3df187bd5177b472b304b1d257c8 Mon Sep 17 00:00:00 2001 From: "Najumon B.A" Date: Tue, 31 Oct 2023 19:22:57 +0530 Subject: [PATCH 3199/3723] drivers: pci: update prt retrieve based on pnp id update prt retrieve based on acpi pnp id instead of acpi device path/name Signed-off-by: Najumon B.A --- drivers/pcie/host/pcie.c | 32 ++++++++++++++++++++- dts/bindings/pcie/host/intel,pcie.yaml | 8 ------ dts/bindings/pcie/host/pcie-controller.yaml | 6 +++- 3 files changed, 36 insertions(+), 10 deletions(-) delete mode 100644 dts/bindings/pcie/host/intel,pcie.yaml diff --git a/drivers/pcie/host/pcie.c b/drivers/pcie/host/pcie.c index d8e04a9ed73..0a98d8e8e06 100644 --- a/drivers/pcie/host/pcie.c +++ b/drivers/pcie/host/pcie.c @@ -5,6 +5,8 @@ * SPDX-License-Identifier: Apache-2.0 */ +#define DT_DRV_COMPAT pcie_controller + #include LOG_MODULE_REGISTER(pcie, LOG_LEVEL_ERR); @@ -28,6 +30,11 @@ LOG_MODULE_REGISTER(pcie, LOG_LEVEL_ERR); #include #endif +#ifdef CONFIG_PCIE_PRT +/* platform interrupt are hardwired or can be dynamically allocated. */ +static bool prt_en; +#endif + /* functions documented in drivers/pcie/pcie.h */ bool pcie_probe(pcie_bdf_t bdf, pcie_id_t id) @@ -303,8 +310,16 @@ unsigned int pcie_alloc_irq(pcie_bdf_t bdf) irq >= CONFIG_MAX_IRQ_LINES || arch_irq_is_used(irq)) { + /* In some platforms, PCI interrupts are hardwired to specific interrupt inputs + * on the interrupt controller and are not configurable. Hence we need to retrieve + * IRQ from acpi. But if it is configurable then we allocate irq dynamically. + */ #ifdef CONFIG_PCIE_PRT - irq = acpi_legacy_irq_get(bdf); + if (prt_en) { + irq = acpi_legacy_irq_get(bdf); + } else { + irq = arch_irq_allocate(); + } #else irq = arch_irq_allocate(); #endif @@ -545,6 +560,21 @@ static int pcie_init(void) .flags = PCIE_SCAN_RECURSIVE, }; +#ifdef CONFIG_PCIE_PRT + const char *hid, *uid = ACPI_DT_UID(DT_DRV_INST(0)); + int ret; + + BUILD_ASSERT(ACPI_DT_HAS_HID(DT_DRV_INST(0)), + "No HID property for PCIe devicetree node"); + hid = ACPI_DT_HID(DT_DRV_INST(0)); + + ret = acpi_legacy_irq_init(hid, uid); + if (!ret) { + prt_en = true; + } else { + __ASSERT(ret == -ENOENT, "Error retrieve interrupt routing table!"); + } +#endif STRUCT_SECTION_COUNT(pcie_dev, &data.max_dev); /* Don't bother calling pcie_scan() if there are no devices to look for */ diff --git a/dts/bindings/pcie/host/intel,pcie.yaml b/dts/bindings/pcie/host/intel,pcie.yaml deleted file mode 100644 index 991f44af054..00000000000 --- a/dts/bindings/pcie/host/intel,pcie.yaml +++ /dev/null @@ -1,8 +0,0 @@ -# Copyright (c) 2020 Intel Corporation -# SPDX-License-Identifier: Apache-2.0 - -description: Intel PCIe host controller - -compatible: "intel,pcie" - -include: pcie-controller.yaml diff --git a/dts/bindings/pcie/host/pcie-controller.yaml b/dts/bindings/pcie/host/pcie-controller.yaml index c5e1bcd83d6..2f83c01dbfe 100644 --- a/dts/bindings/pcie/host/pcie-controller.yaml +++ b/dts/bindings/pcie/host/pcie-controller.yaml @@ -3,7 +3,11 @@ # Common fields for PCIe bus controllers -include: base.yaml +include: [base.yaml, acpi.yaml] + +description: Generic PCIe host controller + +compatible: "pcie-controller" bus: pcie From 9d6a0ceeab9b809420844cc32b227daafcfc491e Mon Sep 17 00:00:00 2001 From: "Najumon B.A" Date: Sat, 23 Sep 2023 09:06:12 +0530 Subject: [PATCH 3200/3723] lib: acpi: add resource enumeration shell command add resource enumeration and acpi method shell commands such as retrieve mmio and interrupt resources. Signed-off-by: Najumon B.A --- lib/acpi/acpi_shell.c | 135 ++++++++++++++++++++++++++++++++++-------- 1 file changed, 109 insertions(+), 26 deletions(-) diff --git a/lib/acpi/acpi_shell.c b/lib/acpi/acpi_shell.c index e2db3aaa30e..aae237232da 100644 --- a/lib/acpi/acpi_shell.c +++ b/lib/acpi/acpi_shell.c @@ -103,9 +103,17 @@ static void dump_dev_res(const struct shell *sh, ACPI_RESOURCE *res_lst) case ACPI_RESOURCE_TYPE_EXTENDED_ADDRESS64: shell_print(sh, "ACPI_RESOURCE_TYPE_EXTENDED_ADDRESS64"); break; - case ACPI_RESOURCE_TYPE_EXTENDED_IRQ: + case ACPI_RESOURCE_TYPE_EXTENDED_IRQ: { + ACPI_RESOURCE_EXTENDED_IRQ *ext_irq_res = &res->Data.ExtendedIrq; + shell_print(sh, "ACPI_RESOURCE_TYPE_EXTENDED_IRQ"); + shell_print(sh, "\tTriggering: %x", ext_irq_res->Triggering); + shell_print(sh, "\tPolarity: %x", ext_irq_res->Polarity); + shell_print(sh, "\tShareable: %s", ext_irq_res->Shareable ? "YES":"NO"); + shell_print(sh, "\tInterruptCount: %d", ext_irq_res->InterruptCount); + shell_print(sh, "\tInterrupts[0]: %d", ext_irq_res->Interrupts[0]); break; + } case ACPI_RESOURCE_TYPE_GENERIC_REGISTER: shell_print(sh, "ACPI_RESOURCE_TYPE_GENERIC_REGISTER"); break; @@ -148,7 +156,7 @@ static int dump_dev_crs(const struct shell *sh, size_t argc, char **argv) ACPI_RESOURCE *res_lst; if (argc < 2) { - shell_error(sh, "invalid arugment"); + shell_error(sh, "invalid argument"); return -EINVAL; } @@ -171,7 +179,7 @@ static int dump_dev_prs(const struct shell *sh, size_t argc, char **argv) ACPI_RESOURCE *res_lst; if (argc < 2) { - shell_error(sh, "invalid arugment"); + shell_error(sh, "invalid argument"); return -EINVAL; } @@ -189,28 +197,26 @@ static int dump_dev_prs(const struct shell *sh, size_t argc, char **argv) static int dump_prt(const struct shell *sh, size_t argc, char **argv) { IF_ENABLED(CONFIG_PCIE_PRT, ({ - static ACPI_PCI_ROUTING_TABLE irq_prt_table[CONFIG_ACPI_MAX_PRT_ENTRY]; - int status, cnt; - ACPI_PCI_ROUTING_TABLE *prt; + int irq, bus, dev_num, func; + pcie_bdf_t bdf; - if (argc < 2) { - shell_error(sh, "invalid arugment"); + if (argc < 4) { + shell_error(sh, "invalid arguments [Eg: acpi prt ]"); return -EINVAL; } - status = acpi_get_irq_routing_table(argv[1], - irq_prt_table, ARRAY_SIZE(irq_prt_table)); - if (status) { - return status; - } - - prt = irq_prt_table; - for (cnt = 0; prt->Length; cnt++) { - shell_print(sh, "[%02X] PCI IRQ Routing Table Package", cnt); - shell_print(sh, "\tDevNum: %lld Pin: %d IRQ: %d", - (prt->Address >> 16) & 0xFFFF, prt->Pin, prt->SourceIndex); - - prt = ACPI_ADD_PTR(ACPI_PCI_ROUTING_TABLE, prt, prt->Length); + bus = atoi(argv[1]); + dev_num = atoi(argv[2]); + func = atoi(argv[3]); + + bdf = PCIE_BDF(bus, dev_num, func); + irq = acpi_legacy_irq_get(bdf); + if (irq != UINT_MAX) { + shell_print(sh, "PCI Legacy IRQ for bus %d dev %d func %d is: %d", + bus, dev_num, func, irq); + } else { + shell_print(sh, "PCI Legacy IRQ for bus %d dev %d func %d Not found", + bus, dev_num, func); } })); /* IF_ENABLED(CONFIG_PCIE_PRT) */ @@ -220,19 +226,93 @@ static int dump_prt(const struct shell *sh, size_t argc, char **argv) static int enum_dev(const struct shell *sh, size_t argc, char **argv) { struct acpi_dev *dev; + ACPI_RESOURCE *res_lst; - if (argc < 2) { + if (argc < 3) { + shell_error(sh, "Invalid arguments [Eg: acpi enum PNP0103 0]"); return -EINVAL; } - dev = acpi_device_get(argv[1], 0); + dev = acpi_device_get(argv[1], argv[2]); if (!dev || !dev->res_lst) { shell_error(sh, "acpi get device failed for HID: %s", argv[1]); return -EIO; } shell_print(sh, "Name: %s", dev->path ? dev->path : "None"); - dump_dev_res(sh, dev->res_lst); + + if (dev->path) { + if (!acpi_current_resource_get(dev->path, &res_lst)) { + dump_dev_res(sh, res_lst); + acpi_current_resource_free(res_lst); + } + } + + return 0; +} + +static int enum_all_dev(const struct shell *sh, size_t argc, char **argv) +{ + struct acpi_dev *dev; + + for (int i = 0; i < CONFIG_ACPI_DEV_MAX; i++) { + dev = acpi_device_by_index_get(i); + if (!dev) { + shell_print(sh, "No more ACPI device found!"); + break; + } + + if (!dev->dev_info) { + continue; + } + + shell_print(sh, "%d) Name: %s, HID: %s", i, dev->path ? dev->path : "None", + dev->dev_info->HardwareId.String ? dev->dev_info->HardwareId.String + : "None"); + } + + return 0; +} + +static int get_acpi_dev_resource(const struct shell *sh, size_t argc, char **argv) +{ + struct acpi_dev *dev; + struct acpi_irq_resource irq_res; + struct acpi_mmio_resource mmio_res; + + if (argc < 3) { + return -EINVAL; + } + + dev = acpi_device_get(argv[1], argv[2]); + if (!dev) { + shell_error(sh, "acpi get device failed for HID: %s", argv[1]); + return -EIO; + } + + if (dev->path) { + shell_print(sh, "Device Path: %s", dev->path); + + if (!acpi_device_mmio_get(dev, &mmio_res)) { + + shell_print(sh, "Device MMIO resources"); + for (int i = 0; i < ACPI_RESOURCE_COUNT_GET(&mmio_res); i++) { + shell_print(sh, "\tType: %x, Address: %p, Size: %d", + ACPI_MULTI_RESOURCE_TYPE_GET(&mmio_res, i), + (void *)ACPI_MULTI_MMIO_GET(&mmio_res, i), + ACPI_MULTI_RESOURCE_SIZE_GET(&mmio_res, i)); + } + } + + if (!acpi_device_irq_get(dev, &irq_res)) { + + shell_print(sh, "Device IRQ resources"); + for (int i = 0; i < irq_res.irq_vector_max; i++) { + shell_print(sh, "\tIRQ Num: %x, Flags: %x", irq_res.irqs[i], + irq_res.flags); + } + } + } return 0; } @@ -274,8 +354,11 @@ SHELL_STATIC_SUBCMD_SET_CREATE( SHELL_CMD(enum, NULL, "enumerate device using hid (for enum HPET timer device,eg:acpi enum PNP0103)", enum_dev), - SHELL_CMD(rd_table, NULL, - "read acpi table (for read mad table, eg:acpi read_table APIC)", + SHELL_CMD(enum_all, NULL, "enumerate all device in acpi name space (eg:acpi enum_all)", + enum_all_dev), + SHELL_CMD(dev_res, NULL, "retrieve device resource (eg: acpi dev_res PNP0501 2)", + get_acpi_dev_resource), + SHELL_CMD(rd_table, NULL, "read ACPI table (eg: acpi read_table APIC)", read_table), SHELL_SUBCMD_SET_END /* Array terminated. */ ); From 8b3bd500cd91e3645b74a1bc85eaef669aaca0df Mon Sep 17 00:00:00 2001 From: "Najumon B.A" Date: Fri, 1 Dec 2023 09:08:27 +0530 Subject: [PATCH 3201/3723] dts: rtc: mc146818: add acpi hid support in yaml file add acpi hid support for mc146818 yaml file. Currently this added for acpi test case support. Signed-off-by: Najumon B.A --- dts/bindings/rtc/motorola,mc146818.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/dts/bindings/rtc/motorola,mc146818.yaml b/dts/bindings/rtc/motorola,mc146818.yaml index 7974c1d68c3..eebb134351e 100644 --- a/dts/bindings/rtc/motorola,mc146818.yaml +++ b/dts/bindings/rtc/motorola,mc146818.yaml @@ -6,7 +6,7 @@ description: Motorola MC146818 compatible Real Timer Clock compatible: "motorola,mc146818" -include: rtc-device.yaml +include: [rtc-device.yaml, acpi.yaml] properties: clock-frequency: From f3d3be52974a93d206ff60fe16700421898c4de2 Mon Sep 17 00:00:00 2001 From: "Najumon B.A" Date: Fri, 17 Nov 2023 07:59:42 +0530 Subject: [PATCH 3202/3723] tests: remove pci bus compatible id dependency from overlay files remove pci bus compatible id dependency from qemu platforms overlay files for disk and ivshmem test apps. This already provided as part of respecitve board dts files and hence no need to duplicate here. Signed-off-by: Najumon B.A --- tests/drivers/disk/disk_access/boards/qemu_x86_64.overlay | 5 ----- .../drivers/disk/disk_performance/boards/qemu_x86_64.overlay | 5 ----- tests/drivers/virtualization/ivshmem/plain/app.overlay | 5 ----- 3 files changed, 15 deletions(-) diff --git a/tests/drivers/disk/disk_access/boards/qemu_x86_64.overlay b/tests/drivers/disk/disk_access/boards/qemu_x86_64.overlay index 65f66de9273..85b9b28246f 100644 --- a/tests/drivers/disk/disk_access/boards/qemu_x86_64.overlay +++ b/tests/drivers/disk/disk_access/boards/qemu_x86_64.overlay @@ -4,11 +4,6 @@ / { pcie0 { - #address-cells = <1>; - #size-cells = <1>; - compatible = "intel,pcie"; - ranges; - nvme0: nvme0 { compatible = "nvme-controller"; diff --git a/tests/drivers/disk/disk_performance/boards/qemu_x86_64.overlay b/tests/drivers/disk/disk_performance/boards/qemu_x86_64.overlay index 1485f30e4d5..037b2528d8c 100644 --- a/tests/drivers/disk/disk_performance/boards/qemu_x86_64.overlay +++ b/tests/drivers/disk/disk_performance/boards/qemu_x86_64.overlay @@ -4,11 +4,6 @@ / { pcie0 { - #address-cells = <1>; - #size-cells = <1>; - compatible = "intel,pcie"; - ranges; - nvme0: nvme0 { compatible = "nvme-controller"; diff --git a/tests/drivers/virtualization/ivshmem/plain/app.overlay b/tests/drivers/virtualization/ivshmem/plain/app.overlay index 6afb2993ae3..a869006c152 100644 --- a/tests/drivers/virtualization/ivshmem/plain/app.overlay +++ b/tests/drivers/virtualization/ivshmem/plain/app.overlay @@ -7,11 +7,6 @@ / { pcie0 { - #address-cells = <1>; - #size-cells = <1>; - compatible = "intel,pcie"; - ranges; - ivshmem0: ivshmem0 { compatible = "qemu,ivshmem"; From 359e5839fe76aea8cb7a75d84c0ca0906a1d2e5f Mon Sep 17 00:00:00 2001 From: "Najumon B.A" Date: Fri, 10 Nov 2023 19:03:22 +0530 Subject: [PATCH 3203/3723] tests: lib: acpi: update test cases for dev and resource enum update acpi test cases with device enumeration, mmio and irq resources enumeration. Signed-off-by: Najumon B.A --- tests/lib/acpi/boards/qemu_x86_64.overlay | 19 +++++++++ tests/lib/acpi/integration/src/main.c | 51 ++++++++++++++++++++--- 2 files changed, 64 insertions(+), 6 deletions(-) create mode 100644 tests/lib/acpi/boards/qemu_x86_64.overlay diff --git a/tests/lib/acpi/boards/qemu_x86_64.overlay b/tests/lib/acpi/boards/qemu_x86_64.overlay new file mode 100644 index 00000000000..d31a4b96990 --- /dev/null +++ b/tests/lib/acpi/boards/qemu_x86_64.overlay @@ -0,0 +1,19 @@ +/* + * Copyright (c) 2023 Intel Corporation + * + * SPDX-License-Identifier: Apache-2.0 + */ + +/* TODO: This overlay file need to update once mc146818 driver eneable for acpi support. + */ + +/ { + aliases { + acpi-dev = &rtc; + }; +}; + +&rtc { + acpi-hid = "PNP0B00"; + status = "okay"; +}; diff --git a/tests/lib/acpi/integration/src/main.c b/tests/lib/acpi/integration/src/main.c index e05a7181cc1..3b1dab9caee 100644 --- a/tests/lib/acpi/integration/src/main.c +++ b/tests/lib/acpi/integration/src/main.c @@ -8,6 +8,16 @@ #include #include +#define APCI_TEST_DEV ACPI_DT_HAS_HID(DT_ALIAS(acpi_dev)) + +#if APCI_TEST_DEV +#define DEV_HID ACPI_DT_HID(DT_ALIAS(acpi_dev)) +#define DEV_UID ACPI_DT_UID(DT_ALIAS(acpi_dev)) +#else +#define DEV_HID NULL +#define DEV_UID NULL +#endif + ZTEST(acpi, test_mcfg_table) { struct acpi_mcfg *mcfg; @@ -17,14 +27,43 @@ ZTEST(acpi, test_mcfg_table) zassert_not_null(mcfg, "Failed to get MCFG table"); } -ZTEST(acpi, test_irq_routing_table) +ZTEST(acpi, test_dev_enum) +{ + struct acpi_dev *dev; + ACPI_RESOURCE *res_lst; + int ret; + + Z_TEST_SKIP_IFNDEF(APCI_TEST_DEV); + + dev = acpi_device_get(DEV_HID, DEV_UID); + + zassert_not_null(dev, "Failed to get acpi device with given HID"); + + ret = acpi_current_resource_get(dev->path, &res_lst); + + zassert_ok(ret, "Failed to get current resource setting"); +} + +ZTEST(acpi, test_resource_enum) { - static ACPI_PCI_ROUTING_TABLE irq_prt_table[CONFIG_ACPI_MAX_PRT_ENTRY]; - int status; + struct acpi_dev *dev; + struct acpi_irq_resource irq_res; + struct acpi_mmio_resource mmio_res; + int ret; + + Z_TEST_SKIP_IFNDEF(APCI_TEST_DEV); + + dev = acpi_device_get(DEV_HID, DEV_UID); + + zassert_not_null(dev, "Failed to get acpi device with given HID"); + + ret = acpi_device_mmio_get(dev, &mmio_res); + + zassert_ok(ret, "Failed to get MMIO resources"); + + ret = acpi_device_irq_get(dev, &irq_res); - status = acpi_get_irq_routing_table(CONFIG_ACPI_PRT_BUS_NAME, - irq_prt_table, ARRAY_SIZE(irq_prt_table)); - zassert_ok(status, "Failed to get PRT"); + zassert_ok(ret, "Failed to get IRQ resources"); } ZTEST_SUITE(acpi, NULL, NULL, NULL, NULL, NULL); From 6e7f50d7aa75d5d2b080a018d129e2dc1430904c Mon Sep 17 00:00:00 2001 From: "Najumon B.A" Date: Fri, 17 Nov 2023 08:20:07 +0530 Subject: [PATCH 3204/3723] docs: rename intel,pcie compatible id to pcie-controller rename intel,pcie compatible id referance to pcie-controller in header file comments and rst files Signed-off-by: Najumon B.A --- doc/services/storage/disk/nvme.rst | 5 ----- include/zephyr/devicetree.h | 14 +++++++------- 2 files changed, 7 insertions(+), 12 deletions(-) diff --git a/doc/services/storage/disk/nvme.rst b/doc/services/storage/disk/nvme.rst index f9a2e935f34..efb6a3d7e1f 100644 --- a/doc/services/storage/disk/nvme.rst +++ b/doc/services/storage/disk/nvme.rst @@ -43,11 +43,6 @@ Any board exposing an NVMe disk should provide a DTS overlay to enable its use w #include / { pcie0 { - #address-cells = <1>; - #size-cells = <1>; - compatible = "intel,pcie"; - ranges; - nvme0: nvme0 { compatible = "nvme-controller"; vendor-id = ; diff --git a/include/zephyr/devicetree.h b/include/zephyr/devicetree.h index 483a659f46c..7a71cf2fb42 100644 --- a/include/zephyr/devicetree.h +++ b/include/zephyr/devicetree.h @@ -1612,7 +1612,7 @@ * * @code{.dts} * pcie0: pcie@0 { - * compatible = "intel,pcie"; + * compatible = "pcie-controller"; * reg = <0 1>; * #address-cells = <3>; * #size-cells = <2>; @@ -1657,7 +1657,7 @@ * * @code{.dts} * pcie0: pcie@0 { - * compatible = "intel,pcie"; + * compatible = "pcie-controller"; * reg = <0 1>; * #address-cells = <3>; * #size-cells = <2>; @@ -1711,7 +1711,7 @@ * #address-cells = <2>; * * pcie0: pcie@0 { - * compatible = "intel,pcie"; + * compatible = "pcie-controller"; * reg = <0 0 1>; * #address-cells = <3>; * #size-cells = <2>; @@ -1764,7 +1764,7 @@ * #address-cells = <2>; * * pcie0: pcie@0 { - * compatible = "intel,pcie"; + * compatible = "pcie-controller"; * reg = <0 0 1>; * #address-cells = <3>; * #size-cells = <2>; @@ -1804,7 +1804,7 @@ * #address-cells = <2>; * * pcie0: pcie@0 { - * compatible = "intel,pcie"; + * compatible = "pcie-controller"; * reg = <0 0 1>; * #address-cells = <3>; * #size-cells = <2>; @@ -1853,7 +1853,7 @@ * #address-cells = <2>; * * pcie0: pcie@0 { - * compatible = "intel,pcie"; + * compatible = "pcie-controller"; * reg = <0 0 1>; * #address-cells = <3>; * #size-cells = <2>; @@ -1902,7 +1902,7 @@ * #address-cells = <2>; * * pcie0: pcie@0 { - * compatible = "intel,pcie"; + * compatible = "pcie-controller"; * reg = <0 0 1>; * #address-cells = <3>; * #size-cells = <2>; From 62b2af70ba20a57b5e1246778c9813c185df0dc5 Mon Sep 17 00:00:00 2001 From: "Najumon B.A" Date: Mon, 22 Jan 2024 09:06:15 +0530 Subject: [PATCH 3205/3723] tests: lib: acpi: add fake x86 acpi function add fake x86 acpi function and config macros for acpi unit test Signed-off-by: Najumon B.A --- tests/lib/acpi/unit/src/mock.c | 3 ++- tests/lib/acpi/unit/src/mock.h | 3 +++ 2 files changed, 5 insertions(+), 1 deletion(-) diff --git a/tests/lib/acpi/unit/src/mock.c b/tests/lib/acpi/unit/src/mock.c index 687c5f26a21..d9b28362602 100644 --- a/tests/lib/acpi/unit/src/mock.c +++ b/tests/lib/acpi/unit/src/mock.c @@ -8,7 +8,6 @@ #include "mock.h" #include - #include #include #include @@ -65,3 +64,5 @@ FAKE_VALUE_FUNC(ACPI_STATUS, AcpiGetPossibleResources, ACPI_HANDLE, ACPI_BUFFER FAKE_VALUE_FUNC(ACPI_STATUS, AcpiGetTable, char *, UINT32, struct acpi_table_header **); + +FAKE_VALUE_FUNC(uint32_t, arch_acpi_encode_irq_flags, uint8_t, uint8_t); diff --git a/tests/lib/acpi/unit/src/mock.h b/tests/lib/acpi/unit/src/mock.h index d8c8df4da0b..e4d3b970e63 100644 --- a/tests/lib/acpi/unit/src/mock.h +++ b/tests/lib/acpi/unit/src/mock.h @@ -16,4 +16,7 @@ #define LOG_ERR(...) #define LOG_WRN(...) +#define CONFIG_ACPI_IRQ_VECTOR_MAX 32 +#define CONFIG_ACPI_MMIO_ENTRIES_MAX 32 + typedef uint32_t pcie_bdf_t; From a02011bac6bef001ec4177f5bd1858b3c1c6da2f Mon Sep 17 00:00:00 2001 From: Kevin Wang Date: Thu, 20 Jul 2023 11:34:58 +0800 Subject: [PATCH 3206/3723] drivers: spi: Refine some coding style for andes_atcspi200 1. Remove the redundant code. 2. Use sys_set_bits and sys_clear_bits instead of customized MACRO. Signed-off-by: Kevin Wang --- drivers/spi/spi_andes_atcspi200.c | 213 +++++++++++++++--------------- drivers/spi/spi_andes_atcspi200.h | 89 ++++++------- 2 files changed, 148 insertions(+), 154 deletions(-) diff --git a/drivers/spi/spi_andes_atcspi200.c b/drivers/spi/spi_andes_atcspi200.c index 3ae422c7673..09a1325221a 100644 --- a/drivers/spi/spi_andes_atcspi200.c +++ b/drivers/spi/spi_andes_atcspi200.c @@ -17,7 +17,6 @@ struct spi_atcspi200_data { uint32_t tx_fifo_size; uint32_t rx_fifo_size; int tx_cnt; - uint32_t is_cmdaddr_mode; size_t chunk_len; bool busy; }; @@ -39,61 +38,66 @@ static int spi_config(const struct device *dev, /* Set the divisor for SPI interface sclk */ sclk_div = (cfg->f_sys / (config->frequency << 1)) - 1; - CLR_MASK(SPI_TIMIN(dev), TIMIN_SCLK_DIV_MSK); - SET_MASK(SPI_TIMIN(dev), sclk_div); + sys_clear_bits(SPI_TIMIN(cfg->base), TIMIN_SCLK_DIV_MSK); + sys_set_bits(SPI_TIMIN(cfg->base), sclk_div); /* Set Master mode */ - CLR_MASK(SPI_TFMAT(dev), TFMAT_SLVMODE_MSK); + sys_clear_bits(SPI_TFMAT(cfg->base), TFMAT_SLVMODE_MSK); /* Disable data merge mode */ - CLR_MASK(SPI_TFMAT(dev), TFMAT_DATA_MERGE_MSK); + sys_clear_bits(SPI_TFMAT(cfg->base), TFMAT_DATA_MERGE_MSK); /* Set data length */ data_len = SPI_WORD_SIZE_GET(config->operation) - 1; - CLR_MASK(SPI_TFMAT(dev), TFMAT_DATA_LEN_MSK); - SET_MASK(SPI_TFMAT(dev), (data_len << TFMAT_DATA_LEN_OFFSET)); + sys_clear_bits(SPI_TFMAT(cfg->base), TFMAT_DATA_LEN_MSK); + sys_set_bits(SPI_TFMAT(cfg->base), (data_len << TFMAT_DATA_LEN_OFFSET)); /* Set SPI frame format */ if (config->operation & SPI_MODE_CPHA) { - SET_MASK(SPI_TFMAT(dev), TFMAT_CPHA_MSK); + sys_set_bits(SPI_TFMAT(cfg->base), TFMAT_CPHA_MSK); } else { - CLR_MASK(SPI_TFMAT(dev), TFMAT_CPHA_MSK); + sys_clear_bits(SPI_TFMAT(cfg->base), TFMAT_CPHA_MSK); } if (config->operation & SPI_MODE_CPOL) { - SET_MASK(SPI_TFMAT(dev), TFMAT_CPOL_MSK); + sys_set_bits(SPI_TFMAT(cfg->base), TFMAT_CPOL_MSK); } else { - CLR_MASK(SPI_TFMAT(dev), TFMAT_CPOL_MSK); + sys_clear_bits(SPI_TFMAT(cfg->base), TFMAT_CPOL_MSK); } /* Set SPI bit order */ if (config->operation & SPI_TRANSFER_LSB) { - SET_MASK(SPI_TFMAT(dev), TFMAT_LSB_MSK); + sys_set_bits(SPI_TFMAT(cfg->base), TFMAT_LSB_MSK); } else { - CLR_MASK(SPI_TFMAT(dev), TFMAT_LSB_MSK); + sys_clear_bits(SPI_TFMAT(cfg->base), TFMAT_LSB_MSK); } /* Set TX/RX FIFO threshold */ - CLR_MASK(SPI_CTRL(dev), CTRL_TX_THRES_MSK); - CLR_MASK(SPI_CTRL(dev), CTRL_RX_THRES_MSK); + sys_clear_bits(SPI_CTRL(cfg->base), CTRL_TX_THRES_MSK); + sys_clear_bits(SPI_CTRL(cfg->base), CTRL_RX_THRES_MSK); - SET_MASK(SPI_CTRL(dev), TX_FIFO_THRESHOLD << CTRL_TX_THRES_OFFSET); - SET_MASK(SPI_CTRL(dev), RX_FIFO_THRESHOLD << CTRL_RX_THRES_OFFSET); + sys_set_bits(SPI_CTRL(cfg->base), TX_FIFO_THRESHOLD << CTRL_TX_THRES_OFFSET); + sys_set_bits(SPI_CTRL(cfg->base), RX_FIFO_THRESHOLD << CTRL_RX_THRES_OFFSET); return 0; } -static int spi_transfer(const struct device *dev, uint32_t len) +static int spi_transfer(const struct device *dev) { struct spi_atcspi200_data * const data = dev->data; struct spi_context *ctx = &data->ctx; uint32_t data_len, tctrl, int_msk; + if (data->chunk_len != 0) { + data_len = data->chunk_len - 1; + } else { + data_len = 0; + } + if (len > MAX_TRANSFER_CNT) { return -EINVAL; } - data_len = len - 1; data->tx_cnt = 0; if (!spi_context_rx_on(ctx)) { @@ -113,15 +117,13 @@ static int spi_transfer(const struct device *dev, uint32_t len) IEN_END_MSK; } - sys_write32(tctrl, SPI_TCTRL(dev)); + sys_write32(tctrl, SPI_TCTRL(cfg->base)); /* Enable TX/RX FIFO interrupts */ - sys_write32(int_msk, SPI_INTEN(dev)); + sys_write32(int_msk, SPI_INTEN(cfg->base)); - if (!data->is_cmdaddr_mode) { - /* Start transferring */ - sys_write32(0, SPI_CMD(dev)); - } + /* Start transferring */ + sys_write32(0, SPI_CMD(cfg->base)); return 0; } @@ -162,31 +164,6 @@ static int configure(const struct device *dev, return 0; } -static void transfer_next_chunk(const struct device *dev) -{ - struct spi_atcspi200_data * const data = dev->data; - struct spi_context *ctx = &data->ctx; - int error = 0; - - size_t chunk_len = spi_context_max_continuous_chunk(ctx); - - if (chunk_len > 0) { - data->chunk_len = chunk_len; - error = spi_transfer(dev, chunk_len); - if (error == 0) { - return; - } - } - - spi_context_cs_control(ctx, false); - /* Reset TX/RX FIFO */ - SET_MASK(SPI_CTRL(dev), CTRL_TX_FIFO_RST_MSK); - SET_MASK(SPI_CTRL(dev), CTRL_RX_FIFO_RST_MSK); - - spi_context_complete(ctx, dev, error); - data->busy = false; -} - static int transceive(const struct device *dev, const struct spi_config *config, const struct spi_buf_set *tx_bufs, @@ -195,12 +172,13 @@ static int transceive(const struct device *dev, spi_callback_t cb, void *userdata) { + const struct spi_atcspi200_cfg * const cfg = dev->config; struct spi_atcspi200_data * const data = dev->data; struct spi_context *ctx = &data->ctx; int error, dfs; + size_t chunk_len; spi_context_lock(ctx, asynchronous, cb, userdata, config); - error = configure(dev, config); if (error == 0) { data->busy = true; @@ -210,8 +188,29 @@ static int transceive(const struct device *dev, spi_context_cs_control(ctx, true); transfer_next_chunk(dev); + sys_set_bits(SPI_CTRL(cfg->base), CTRL_TX_FIFO_RST_MSK); + sys_set_bits(SPI_CTRL(cfg->base), CTRL_RX_FIFO_RST_MSK); + + if (!spi_context_rx_on(ctx)) { + chunk_len = spi_context_total_tx_len(ctx); + } else if (!spi_context_tx_on(ctx)) { + chunk_len = spi_context_total_rx_len(ctx); + } else { + size_t rx_len = spi_context_total_rx_len(ctx); + size_t tx_len = spi_context_total_tx_len(ctx); + + chunk_len = MIN(rx_len, tx_len); + } + + data->chunk_len = chunk_len; + + error = spi_transfer(dev); + if (error != 0) { + return error; + } error = spi_context_wait_for_completion(ctx); + spi_context_cs_control(ctx, false); } spi_context_release(ctx, error); @@ -268,8 +267,8 @@ int spi_atcspi200_init(const struct device *dev) spi_context_unlock_unconditionally(&data->ctx); /* Get the TX/RX FIFO size of this device */ - data->tx_fifo_size = TX_FIFO_SIZE(dev); - data->rx_fifo_size = RX_FIFO_SIZE(dev); + data->tx_fifo_size = TX_FIFO_SIZE(cfg->base); + data->rx_fifo_size = RX_FIFO_SIZE(cfg->base); cfg->cfg_func(); @@ -294,20 +293,22 @@ static const struct spi_driver_api spi_atcspi200_api = { static void spi_atcspi200_irq_handler(void *arg) { const struct device * const dev = (const struct device *) arg; + const struct spi_atcspi200_cfg * const cfg = dev->config; struct spi_atcspi200_data * const data = dev->data; struct spi_context *ctx = &data->ctx; uint32_t rx_data, cur_tx_fifo_num, cur_rx_fifo_num; uint32_t i, dfs, intr_status, spi_status; uint32_t tx_num = 0, tx_data = 0; + int error = 0; - intr_status = sys_read32(SPI_INTST(dev)); + intr_status = sys_read32(SPI_INTST(cfg->base)); dfs = SPI_WORD_SIZE_GET(ctx->config->operation) >> 3; if ((intr_status & INTST_TX_FIFO_INT_MSK) && !(intr_status & INTST_END_INT_MSK)) { - spi_status = sys_read32(SPI_STAT(dev)); - cur_tx_fifo_num = GET_TX_NUM(dev); + spi_status = sys_read32(SPI_STAT(cfg->base)); + cur_tx_fifo_num = GET_TX_NUM(cfg->base); tx_num = data->tx_fifo_size - cur_tx_fifo_num; @@ -317,7 +318,7 @@ static void spi_atcspi200_irq_handler(void *arg) /* Have already sent a chunk of data, so stop * sending data! */ - CLR_MASK(SPI_INTEN(dev), IEN_TX_FIFO_MSK); + sys_clear_bits(SPI_INTEN(cfg->base), IEN_TX_FIFO_MSK); break; } @@ -335,26 +336,26 @@ static void spi_atcspi200_irq_handler(void *arg) } else if (spi_context_tx_on(ctx)) { tx_data = 0; } else { - CLR_MASK(SPI_INTEN(dev), IEN_TX_FIFO_MSK); + sys_clear_bits(SPI_INTEN(cfg->base), IEN_TX_FIFO_MSK); break; } - sys_write32(tx_data, SPI_DATA(dev)); + sys_write32(tx_data, SPI_DATA(cfg->base)); spi_context_update_tx(ctx, dfs, 1); data->tx_cnt++; } - sys_write32(INTST_TX_FIFO_INT_MSK, SPI_INTST(dev)); + sys_write32(INTST_TX_FIFO_INT_MSK, SPI_INTST(cfg->base)); } if (intr_status & INTST_RX_FIFO_INT_MSK) { - cur_rx_fifo_num = GET_RX_NUM(dev); + cur_rx_fifo_num = GET_RX_NUM(cfg->base); for (i = cur_rx_fifo_num; i > 0; i--) { - rx_data = sys_read32(SPI_DATA(dev)); + rx_data = sys_read32(SPI_DATA(cfg->base)); if (spi_context_rx_buf_on(ctx)) { @@ -368,28 +369,30 @@ static void spi_atcspi200_irq_handler(void *arg) } } else if (!spi_context_rx_on(ctx)) { - CLR_MASK(SPI_INTEN(dev), IEN_RX_FIFO_MSK); + sys_clear_bits(SPI_INTEN(cfg->base), IEN_RX_FIFO_MSK); } spi_context_update_rx(ctx, dfs, 1); } - sys_write32(INTST_RX_FIFO_INT_MSK, SPI_INTST(dev)); + sys_write32(INTST_RX_FIFO_INT_MSK, SPI_INTST(cfg->base)); } if (intr_status & INTST_END_INT_MSK) { /* Clear end interrupt */ - sys_write32(INTST_END_INT_MSK, SPI_INTST(dev)); + sys_write32(INTST_END_INT_MSK, SPI_INTST(cfg->base)); /* Disable all SPI interrupts */ - sys_write32(0, SPI_INTEN(dev)); + sys_write32(0, SPI_INTEN(cfg->base)); + + data->busy = false; + + spi_context_complete(ctx, dev, error); - transfer_next_chunk(dev); } } #define SPI_DMA_CHANNEL(id, dir, DIR, src, dest) -#define SPI_IF_NO_CMD(num) .is_cmdaddr_mode = 0, #define SPI_BUSY_INIT .busy = false, #if (CONFIG_XIP) @@ -398,43 +401,41 @@ static void spi_atcspi200_irq_handler(void *arg) #define SPI_ROM_CFG_XIP(node_id) false #endif -#define SPI_INIT(n) \ - static struct spi_atcspi200_data spi_atcspi200_dev_data_##n = { \ - SPI_CONTEXT_INIT_LOCK(spi_atcspi200_dev_data_##n, ctx), \ - SPI_CONTEXT_INIT_SYNC(spi_atcspi200_dev_data_##n, ctx), \ - SPI_CONTEXT_CS_GPIOS_INITIALIZE(DT_DRV_INST(n), ctx) \ - SPI_IF_NO_CMD(n) \ - SPI_BUSY_INIT \ - SPI_DMA_CHANNEL(n, rx, RX, PERIPHERAL, MEMORY) \ - SPI_DMA_CHANNEL(n, tx, TX, MEMORY, PERIPHERAL) \ - }; \ - static void spi_atcspi200_cfg_##n(void); \ - static const struct spi_atcspi200_cfg spi_atcspi200_dev_cfg_##n = { \ - .cfg_func = spi_atcspi200_cfg_##n, \ - .base = DT_INST_REG_ADDR(n), \ - .irq_num = DT_INST_IRQN(n), \ - .f_sys = DT_INST_PROP(n, clock_frequency), \ - .xip = SPI_ROM_CFG_XIP(DT_DRV_INST(n)), \ - }; \ - \ - DEVICE_DT_INST_DEFINE(n, \ - spi_atcspi200_init, \ - NULL, \ - &spi_atcspi200_dev_data_##n, \ - &spi_atcspi200_dev_cfg_##n, \ - POST_KERNEL, \ - CONFIG_SPI_INIT_PRIORITY, \ - &spi_atcspi200_api); \ - \ - static void spi_atcspi200_cfg_##n(void) \ - { \ - \ - IRQ_CONNECT(DT_INST_IRQN(n), \ - DT_INST_IRQ(n, priority), \ - spi_atcspi200_irq_handler, \ - DEVICE_DT_INST_GET(n), \ - 0); \ - \ - } +#define SPI_INIT(n) \ + static struct spi_atcspi200_data spi_atcspi200_dev_data_##n = {\ + .self_dev = DEVICE_DT_INST_GET(n), \ + SPI_CONTEXT_INIT_LOCK(spi_atcspi200_dev_data_##n, ctx), \ + SPI_CONTEXT_INIT_SYNC(spi_atcspi200_dev_data_##n, ctx), \ + SPI_CONTEXT_CS_GPIOS_INITIALIZE(DT_DRV_INST(n), ctx) \ + SPI_BUSY_INIT \ + SPI_DMA_CHANNEL(n, rx, RX, PERIPHERAL, MEMORY) \ + SPI_DMA_CHANNEL(n, tx, TX, MEMORY, PERIPHERAL) \ + }; \ + static void spi_atcspi200_cfg_##n(void); \ + static struct spi_atcspi200_cfg spi_atcspi200_dev_cfg_##n = { \ + .cfg_func = spi_atcspi200_cfg_##n, \ + .base = DT_INST_REG_ADDR(n), \ + .irq_num = DT_INST_IRQN(n), \ + .f_sys = DT_INST_PROP(n, clock_frequency), \ + .xip = SPI_ROM_CFG_XIP(DT_DRV_INST(n)), \ + }; \ + \ + DEVICE_DT_INST_DEFINE(n, \ + spi_atcspi200_init, \ + NULL, \ + &spi_atcspi200_dev_data_##n, \ + &spi_atcspi200_dev_cfg_##n, \ + POST_KERNEL, \ + CONFIG_SPI_INIT_PRIORITY, \ + &spi_atcspi200_api); \ + \ + static void spi_atcspi200_cfg_##n(void) \ + { \ + IRQ_CONNECT(DT_INST_IRQN(n), \ + DT_INST_IRQ(n, priority), \ + spi_atcspi200_irq_handler, \ + DEVICE_DT_INST_GET(n), \ + 0); \ + }; DT_INST_FOREACH_STATUS_OKAY(SPI_INIT) diff --git a/drivers/spi/spi_andes_atcspi200.h b/drivers/spi/spi_andes_atcspi200.h index f7b73ec6716..3eb9a53202b 100644 --- a/drivers/spi/spi_andes_atcspi200.h +++ b/drivers/spi/spi_andes_atcspi200.h @@ -11,34 +11,27 @@ LOG_MODULE_REGISTER(spi_atcspi200); #include #include -#define REG_IDR 0x00 -#define REG_TFMAT 0x10 -#define REG_DIRIO 0x14 -#define REG_TCTRL 0x20 -#define REG_CMD 0x24 -#define REG_ADDR 0x28 -#define REG_DATA 0x2c -#define REG_CTRL 0x30 -#define REG_STAT 0x34 -#define REG_INTEN 0x38 -#define REG_INTST 0x3c -#define REG_TIMIN 0x40 -#define REG_MCTRL 0x50 -#define REG_SLVST 0x60 -#define REG_SDCNT 0x64 -#define REG_CONFIG 0x7c - -#define SPI_BASE (((const struct spi_atcspi200_cfg *)(dev)->config)->base) -#define SPI_TFMAT(dev) (SPI_BASE + REG_TFMAT) -#define SPI_TCTRL(dev) (SPI_BASE + REG_TCTRL) -#define SPI_CMD(dev) (SPI_BASE + REG_CMD) -#define SPI_DATA(dev) (SPI_BASE + REG_DATA) -#define SPI_CTRL(dev) (SPI_BASE + REG_CTRL) -#define SPI_STAT(dev) (SPI_BASE + REG_STAT) -#define SPI_INTEN(dev) (SPI_BASE + REG_INTEN) -#define SPI_INTST(dev) (SPI_BASE + REG_INTST) -#define SPI_TIMIN(dev) (SPI_BASE + REG_TIMIN) -#define SPI_CONFIG(dev) (SPI_BASE + REG_CONFIG) +#define REG_TFMAT 0x10 +#define REG_TCTRL 0x20 +#define REG_CMD 0x24 +#define REG_DATA 0x2c +#define REG_CTRL 0x30 +#define REG_STAT 0x34 +#define REG_INTEN 0x38 +#define REG_INTST 0x3c +#define REG_TIMIN 0x40 +#define REG_CONFIG 0x7c + +#define SPI_TFMAT(base) (base + 0x10) +#define SPI_TCTRL(base) (base + 0x20) +#define SPI_CMD(base) (base + 0x24) +#define SPI_DATA(base) (base + 0x2c) +#define SPI_CTRL(base) (base + 0x30) +#define SPI_STAT(base) (base + 0x34) +#define SPI_INTEN(base) (base + 0x38) +#define SPI_INTST(base) (base + 0x3c) +#define SPI_TIMIN(base) (base + 0x40) +#define SPI_CONFIG(base) (base + 0x7c) /* Field mask of SPI transfer format register */ #define TFMAT_DATA_LEN_OFFSET (8) @@ -75,8 +68,8 @@ LOG_MODULE_REGISTER(spi_atcspi200); #define INTST_END_INT_MSK BIT(4) /* Field mask of SPI config register */ -#define CFG_RX_FIFO_SIZE_MSK GENMASK(1, 0) -#define CFG_TX_FIFO_SIZE_MSK GENMASK(5, 4) +#define CFG_RX_FIFO_SIZE_MSK GENMASK(3, 0) +#define CFG_TX_FIFO_SIZE_MSK GENMASK(7, 4) /* Field mask of SPI status register */ #define STAT_RX_NUM_MSK GENMASK(12, 8) @@ -90,30 +83,30 @@ LOG_MODULE_REGISTER(spi_atcspi200); #define CTRL_RX_FIFO_RST_MSK BIT(1) #define CTRL_TX_FIFO_RST_MSK BIT(2) +#define CTRL_RX_DMA_EN_MSK BIT(3) +#define CTRL_TX_DMA_EN_MSK BIT(4) #define CTRL_RX_THRES_MSK GENMASK(12, 8) #define CTRL_TX_THRES_MSK GENMASK(20, 16) /* Field mask of SPI status register */ #define TIMIN_SCLK_DIV_MSK GENMASK(7, 0) -#define SET_MASK(x, msk) sys_write32(sys_read32(x) | msk, x) -#define CLR_MASK(x, msk) sys_write32(sys_read32(x) & ~msk, x) - #define TX_FIFO_THRESHOLD (1) #define RX_FIFO_THRESHOLD (1) #define MAX_TRANSFER_CNT (512) - -#define TX_FIFO_SIZE_SETTING(dev) \ - (sys_read32(SPI_CONFIG(dev)) & CFG_TX_FIFO_SIZE_MSK) -#define TX_FIFO_SIZE(dev) \ - (2 << (TX_FIFO_SIZE_SETTING(dev) >> 4)) - -#define RX_FIFO_SIZE_SETTING(dev) \ - (sys_read32(SPI_CONFIG(dev)) & CFG_RX_FIFO_SIZE_MSK) -#define RX_FIFO_SIZE(dev) \ - (2 << (RX_FIFO_SIZE_SETTING(dev) >> 0)) - -#define TX_NUM_STAT(dev) (sys_read32(SPI_STAT(dev)) & STAT_TX_NUM_MSK) -#define RX_NUM_STAT(dev) (sys_read32(SPI_STAT(dev)) & STAT_RX_NUM_MSK) -#define GET_TX_NUM(dev) (TX_NUM_STAT(dev) >> 16) -#define GET_RX_NUM(dev) (RX_NUM_STAT(dev) >> 8) +#define MAX_CHAIN_SIZE (8) + +#define TX_FIFO_SIZE_SETTING(base) \ + (sys_read32(SPI_CONFIG(base)) & CFG_TX_FIFO_SIZE_MSK) +#define TX_FIFO_SIZE(base) \ + (2 << (TX_FIFO_SIZE_SETTING(base) >> 4)) + +#define RX_FIFO_SIZE_SETTING(base) \ + (sys_read32(SPI_CONFIG(base)) & CFG_RX_FIFO_SIZE_MSK) +#define RX_FIFO_SIZE(base) \ + (2 << (RX_FIFO_SIZE_SETTING(base) >> 0)) + +#define TX_NUM_STAT(base) (sys_read32(SPI_STAT(base)) & STAT_TX_NUM_MSK) +#define RX_NUM_STAT(base) (sys_read32(SPI_STAT(base)) & STAT_RX_NUM_MSK) +#define GET_TX_NUM(base) (TX_NUM_STAT(base) >> 16) +#define GET_RX_NUM(base) (RX_NUM_STAT(base) >> 8) From c181dcced454197b722e0c1923f63d627dfd0ffb Mon Sep 17 00:00:00 2001 From: Kevin Wang Date: Fri, 15 Sep 2023 10:18:16 +0800 Subject: [PATCH 3207/3723] drivers: spi: Support dma mode for atcspi200 1. Support the dma mode for andes_atcspi200 and use board adp_xc7k_ae350 for testing. 2. Refine the function mechanism. Signed-off-by: Kevin Wang --- drivers/spi/Kconfig.andes_atcspi200 | 9 + drivers/spi/spi_andes_atcspi200.c | 548 +++++++++++++++++++++++++++- drivers/spi/spi_andes_atcspi200.h | 24 +- 3 files changed, 563 insertions(+), 18 deletions(-) diff --git a/drivers/spi/Kconfig.andes_atcspi200 b/drivers/spi/Kconfig.andes_atcspi200 index 41b331023af..ad7dfca16cc 100644 --- a/drivers/spi/Kconfig.andes_atcspi200 +++ b/drivers/spi/Kconfig.andes_atcspi200 @@ -11,3 +11,12 @@ config SPI_ANDES_ATCSPI200 depends on DT_HAS_ANDESTECH_ATCSPI200_ENABLED help Enable driver for Andes ATCSPI200 SPI controller + +if SPI_ANDES_ATCSPI200 + +config ANDES_SPI_DMA_MODE + bool "Using DMA mode for spi" + default y + depends on DMA + +endif # SPI_ANDES_ATCSPI200 diff --git a/drivers/spi/spi_andes_atcspi200.c b/drivers/spi/spi_andes_atcspi200.c index 09a1325221a..adc7b2e9157 100644 --- a/drivers/spi/spi_andes_atcspi200.c +++ b/drivers/spi/spi_andes_atcspi200.c @@ -12,6 +12,27 @@ typedef void (*atcspi200_cfg_func_t)(void); +#ifdef CONFIG_ANDES_SPI_DMA_MODE + +#define ANDES_SPI_DMA_ERROR_FLAG 0x01 +#define ANDES_SPI_DMA_RX_DONE_FLAG 0x02 +#define ANDES_SPI_DMA_TX_DONE_FLAG 0x04 +#define ANDES_SPI_DMA_DONE_FLAG \ + (ANDES_SPI_DMA_RX_DONE_FLAG | ANDES_SPI_DMA_TX_DONE_FLAG) + +struct stream { + const struct device *dma_dev; + uint32_t channel; + uint32_t block_idx; + struct dma_config dma_cfg; + struct dma_block_config dma_blk_cfg; + struct dma_block_config chain_block[MAX_CHAIN_SIZE]; + uint8_t priority; + bool src_addr_increment; + bool dst_addr_increment; +}; +#endif + struct spi_atcspi200_data { struct spi_context ctx; uint32_t tx_fifo_size; @@ -19,6 +40,10 @@ struct spi_atcspi200_data { int tx_cnt; size_t chunk_len; bool busy; +#ifdef CONFIG_ANDES_SPI_DMA_MODE + struct stream dma_rx; + struct stream dma_tx; +#endif }; struct spi_atcspi200_cfg { @@ -85,6 +110,7 @@ static int spi_config(const struct device *dev, static int spi_transfer(const struct device *dev) { struct spi_atcspi200_data * const data = dev->data; + const struct spi_atcspi200_cfg * const cfg = dev->config; struct spi_context *ctx = &data->ctx; uint32_t data_len, tctrl, int_msk; @@ -94,7 +120,7 @@ static int spi_transfer(const struct device *dev) data_len = 0; } - if (len > MAX_TRANSFER_CNT) { + if (data_len > MAX_TRANSFER_CNT) { return -EINVAL; } @@ -164,6 +190,412 @@ static int configure(const struct device *dev, return 0; } + +#ifdef CONFIG_ANDES_SPI_DMA_MODE + +static int spi_dma_tx_load(const struct device *dev); +static int spi_dma_rx_load(const struct device *dev); + +static inline void spi_tx_dma_enable(const struct device *dev) +{ + const struct spi_atcspi200_cfg * const cfg = dev->config; + /* Enable TX DMA */ + sys_set_bits(SPI_CTRL(cfg->base), CTRL_TX_DMA_EN_MSK); +} + +static inline void spi_tx_dma_disable(const struct device *dev) +{ + const struct spi_atcspi200_cfg * const cfg = dev->config; + /* Disable TX DMA */ + sys_clear_bits(SPI_CTRL(cfg->base), CTRL_TX_DMA_EN_MSK); +} + +static inline void spi_rx_dma_enable(const struct device *dev) +{ + const struct spi_atcspi200_cfg * const cfg = dev->config; + /* Enable RX DMA */ + sys_set_bits(SPI_CTRL(cfg->base), CTRL_RX_DMA_EN_MSK); +} + +static inline void spi_rx_dma_disable(const struct device *dev) +{ + const struct spi_atcspi200_cfg * const cfg = dev->config; + /* Disable RX DMA */ + sys_clear_bits(SPI_CTRL(cfg->base), CTRL_RX_DMA_EN_MSK); +} + +static int spi_dma_move_buffers(const struct device *dev) +{ + struct spi_atcspi200_data *data = dev->data; + struct spi_context *ctx = &data->ctx; + uint32_t error = 0; + + data->dma_rx.dma_blk_cfg.next_block = NULL; + data->dma_tx.dma_blk_cfg.next_block = NULL; + + if (spi_context_tx_on(ctx)) { + error = spi_dma_tx_load(dev); + if (error != 0) { + return error; + } + } + + if (spi_context_rx_on(ctx)) { + error = spi_dma_rx_load(dev); + if (error != 0) { + return error; + } + } + + return 0; +} + +static inline void dma_rx_callback(const struct device *dev, void *user_data, + uint32_t channel, int status) +{ + const struct device *spi_dev = (struct device *)user_data; + struct spi_atcspi200_data *data = spi_dev->data; + struct spi_context *ctx = &data->ctx; + int error; + + dma_stop(data->dma_rx.dma_dev, data->dma_rx.channel); + spi_rx_dma_disable(spi_dev); + + if (spi_context_rx_on(ctx)) { + if (spi_dma_rx_load(spi_dev) != 0) { + return; + } + spi_rx_dma_enable(spi_dev); + error = dma_start(data->dma_rx.dma_dev, data->dma_rx.channel); + __ASSERT(error == 0, "dma_start was failed in rx callback"); + } +} + +static inline void dma_tx_callback(const struct device *dev, void *user_data, + uint32_t channel, int status) +{ + const struct device *spi_dev = (struct device *)user_data; + struct spi_atcspi200_data *data = spi_dev->data; + struct spi_context *ctx = &data->ctx; + int error; + + dma_stop(data->dma_tx.dma_dev, data->dma_tx.channel); + spi_tx_dma_disable(spi_dev); + + if (spi_context_tx_on(ctx)) { + if (spi_dma_tx_load(spi_dev) != 0) { + return; + } + spi_tx_dma_enable(spi_dev); + error = dma_start(data->dma_tx.dma_dev, data->dma_tx.channel); + __ASSERT(error == 0, "dma_start was failed in tx callback"); + } +} + +/* + * dummy value used for transferring NOP when tx buf is null + * and use as dummy sink for when rx buf is null + */ +uint32_t dummy_rx_tx_buffer; + +static int spi_dma_tx_load(const struct device *dev) +{ + const struct spi_atcspi200_cfg * const cfg = dev->config; + struct spi_atcspi200_data *data = dev->data; + struct spi_context *ctx = &data->ctx; + int remain_len, ret, dfs; + + /* prepare the block for this TX DMA channel */ + memset(&data->dma_tx.dma_blk_cfg, 0, sizeof(struct dma_block_config)); + + if (ctx->current_tx->len > data->chunk_len) { + data->dma_tx.dma_blk_cfg.block_size = data->chunk_len / + data->dma_tx.dma_cfg.dest_data_size; + } else { + data->dma_tx.dma_blk_cfg.block_size = ctx->current_tx->len / + data->dma_tx.dma_cfg.dest_data_size; + } + + /* tx direction has memory as source and periph as dest. */ + if (ctx->current_tx->buf == NULL) { + dummy_rx_tx_buffer = 0; + /* if tx buff is null, then sends NOP on the line. */ + data->dma_tx.dma_blk_cfg.source_address = (uintptr_t)&dummy_rx_tx_buffer; + data->dma_tx.dma_blk_cfg.source_addr_adj = DMA_ADDR_ADJ_NO_CHANGE; + } else { + data->dma_tx.dma_blk_cfg.source_address = (uintptr_t)ctx->current_tx->buf; + if (data->dma_tx.src_addr_increment) { + data->dma_tx.dma_blk_cfg.source_addr_adj = DMA_ADDR_ADJ_INCREMENT; + } else { + data->dma_tx.dma_blk_cfg.source_addr_adj = DMA_ADDR_ADJ_NO_CHANGE; + } + } + + dfs = SPI_WORD_SIZE_GET(ctx->config->operation) >> 3; + remain_len = data->chunk_len - ctx->current_tx->len; + spi_context_update_tx(ctx, dfs, ctx->current_tx->len); + + data->dma_tx.dma_blk_cfg.dest_address = (uint32_t)SPI_DATA(cfg->base); + /* fifo mode NOT USED there */ + if (data->dma_tx.dst_addr_increment) { + data->dma_tx.dma_blk_cfg.dest_addr_adj = DMA_ADDR_ADJ_INCREMENT; + } else { + data->dma_tx.dma_blk_cfg.dest_addr_adj = DMA_ADDR_ADJ_NO_CHANGE; + } + + /* direction is given by the DT */ + data->dma_tx.dma_cfg.head_block = &data->dma_tx.dma_blk_cfg; + data->dma_tx.dma_cfg.head_block->next_block = NULL; + /* give the client dev as arg, as the callback comes from the dma */ + data->dma_tx.dma_cfg.user_data = (void *)dev; + + if (data->dma_tx.dma_cfg.source_chaining_en) { + data->dma_tx.dma_cfg.block_count = ctx->tx_count; + data->dma_tx.dma_cfg.dma_callback = NULL; + data->dma_tx.block_idx = 0; + struct dma_block_config *blk_cfg = &data->dma_tx.dma_blk_cfg; + const struct spi_buf *current_tx = ctx->current_tx; + + while (remain_len > 0) { + struct dma_block_config *next_blk_cfg; + + next_blk_cfg = &data->dma_tx.chain_block[data->dma_tx.block_idx]; + data->dma_tx.block_idx += 1; + + blk_cfg->next_block = next_blk_cfg; + current_tx = ctx->current_tx; + + next_blk_cfg->block_size = current_tx->len / + data->dma_tx.dma_cfg.dest_data_size; + + /* tx direction has memory as source and periph as dest. */ + if (current_tx->buf == NULL) { + dummy_rx_tx_buffer = 0; + /* if tx buff is null, then sends NOP on the line. */ + next_blk_cfg->source_address = (uintptr_t)&dummy_rx_tx_buffer; + next_blk_cfg->source_addr_adj = DMA_ADDR_ADJ_NO_CHANGE; + } else { + next_blk_cfg->source_address = (uintptr_t)current_tx->buf; + if (data->dma_tx.src_addr_increment) { + next_blk_cfg->source_addr_adj = DMA_ADDR_ADJ_INCREMENT; + } else { + next_blk_cfg->source_addr_adj = DMA_ADDR_ADJ_NO_CHANGE; + } + } + + next_blk_cfg->dest_address = (uint32_t)SPI_DATA(cfg->base); + /* fifo mode NOT USED there */ + if (data->dma_tx.dst_addr_increment) { + next_blk_cfg->dest_addr_adj = DMA_ADDR_ADJ_INCREMENT; + } else { + next_blk_cfg->dest_addr_adj = DMA_ADDR_ADJ_NO_CHANGE; + } + + blk_cfg = next_blk_cfg; + next_blk_cfg->next_block = NULL; + remain_len -= ctx->current_tx->len; + spi_context_update_tx(ctx, dfs, ctx->current_tx->len); + } + + } else { + data->dma_tx.dma_blk_cfg.next_block = NULL; + data->dma_tx.dma_cfg.block_count = 1; + data->dma_tx.dma_cfg.dma_callback = dma_tx_callback; + } + + /* pass our client origin to the dma: data->dma_tx.dma_channel */ + ret = dma_config(data->dma_tx.dma_dev, data->dma_tx.channel, + &data->dma_tx.dma_cfg); + /* the channel is the actual stream from 0 */ + if (ret != 0) { + data->dma_tx.block_idx = 0; + data->dma_tx.dma_blk_cfg.next_block = NULL; + return ret; + } + + return 0; +} + +static int spi_dma_rx_load(const struct device *dev) +{ + const struct spi_atcspi200_cfg * const cfg = dev->config; + struct spi_atcspi200_data *data = dev->data; + struct spi_context *ctx = &data->ctx; + int remain_len, ret, dfs; + + /* prepare the block for this RX DMA channel */ + memset(&data->dma_rx.dma_blk_cfg, 0, sizeof(struct dma_block_config)); + + if (ctx->current_rx->len > data->chunk_len) { + data->dma_rx.dma_blk_cfg.block_size = data->chunk_len / + data->dma_rx.dma_cfg.dest_data_size; + } else { + data->dma_rx.dma_blk_cfg.block_size = ctx->current_rx->len / + data->dma_rx.dma_cfg.dest_data_size; + } + + /* rx direction has periph as source and mem as dest. */ + if (ctx->current_rx->buf == NULL) { + /* if rx buff is null, then write data to dummy address. */ + data->dma_rx.dma_blk_cfg.dest_address = (uintptr_t)&dummy_rx_tx_buffer; + data->dma_rx.dma_blk_cfg.dest_addr_adj = DMA_ADDR_ADJ_NO_CHANGE; + } else { + data->dma_rx.dma_blk_cfg.dest_address = (uintptr_t)ctx->current_rx->buf; + if (data->dma_rx.dst_addr_increment) { + data->dma_rx.dma_blk_cfg.dest_addr_adj = DMA_ADDR_ADJ_INCREMENT; + } else { + data->dma_rx.dma_blk_cfg.dest_addr_adj = DMA_ADDR_ADJ_NO_CHANGE; + } + } + + dfs = SPI_WORD_SIZE_GET(ctx->config->operation) >> 3; + remain_len = data->chunk_len - ctx->current_rx->len; + spi_context_update_rx(ctx, dfs, ctx->current_rx->len); + + data->dma_rx.dma_blk_cfg.source_address = (uint32_t)SPI_DATA(cfg->base); + + if (data->dma_rx.src_addr_increment) { + data->dma_rx.dma_blk_cfg.source_addr_adj = DMA_ADDR_ADJ_INCREMENT; + } else { + data->dma_rx.dma_blk_cfg.source_addr_adj = DMA_ADDR_ADJ_NO_CHANGE; + } + + data->dma_rx.dma_cfg.head_block = &data->dma_rx.dma_blk_cfg; + data->dma_rx.dma_cfg.head_block->next_block = NULL; + data->dma_rx.dma_cfg.user_data = (void *)dev; + + if (data->dma_rx.dma_cfg.source_chaining_en) { + data->dma_rx.dma_cfg.block_count = ctx->rx_count; + data->dma_rx.dma_cfg.dma_callback = NULL; + data->dma_rx.block_idx = 0; + struct dma_block_config *blk_cfg = &data->dma_rx.dma_blk_cfg; + const struct spi_buf *current_rx = ctx->current_rx; + + while (remain_len > 0) { + struct dma_block_config *next_blk_cfg; + + next_blk_cfg = &data->dma_rx.chain_block[data->dma_rx.block_idx]; + data->dma_rx.block_idx += 1; + + blk_cfg->next_block = next_blk_cfg; + current_rx = ctx->current_rx; + + next_blk_cfg->block_size = current_rx->len / + data->dma_rx.dma_cfg.dest_data_size; + + /* rx direction has periph as source and mem as dest. */ + if (current_rx->buf == NULL) { + /* if rx buff is null, then write data to dummy address. */ + next_blk_cfg->dest_address = (uintptr_t)&dummy_rx_tx_buffer; + next_blk_cfg->dest_addr_adj = DMA_ADDR_ADJ_NO_CHANGE; + } else { + next_blk_cfg->dest_address = (uintptr_t)current_rx->buf; + if (data->dma_rx.dst_addr_increment) { + next_blk_cfg->dest_addr_adj = DMA_ADDR_ADJ_INCREMENT; + } else { + next_blk_cfg->dest_addr_adj = DMA_ADDR_ADJ_NO_CHANGE; + } + } + + next_blk_cfg->source_address = (uint32_t)SPI_DATA(cfg->base); + + if (data->dma_rx.src_addr_increment) { + next_blk_cfg->source_addr_adj = DMA_ADDR_ADJ_INCREMENT; + } else { + next_blk_cfg->source_addr_adj = DMA_ADDR_ADJ_NO_CHANGE; + } + + blk_cfg = next_blk_cfg; + next_blk_cfg->next_block = NULL; + remain_len -= ctx->current_rx->len; + spi_context_update_rx(ctx, dfs, ctx->current_rx->len); + } + } else { + data->dma_rx.dma_blk_cfg.next_block = NULL; + data->dma_rx.dma_cfg.block_count = 1; + data->dma_rx.dma_cfg.dma_callback = dma_rx_callback; + } + + /* pass our client origin to the dma: data->dma_rx.channel */ + ret = dma_config(data->dma_rx.dma_dev, data->dma_rx.channel, + &data->dma_rx.dma_cfg); + /* the channel is the actual stream from 0 */ + if (ret != 0) { + data->dma_rx.block_idx = 0; + data->dma_rx.dma_blk_cfg.next_block = NULL; + return ret; + } + + return 0; +} + +static int spi_transfer_dma(const struct device *dev) +{ + const struct spi_atcspi200_cfg * const cfg = dev->config; + struct spi_atcspi200_data * const data = dev->data; + struct spi_context *ctx = &data->ctx; + uint32_t data_len, tctrl, dma_rx_enable, dma_tx_enable; + int error = 0; + + data_len = data->chunk_len - 1; + if (data_len > MAX_TRANSFER_CNT) { + return -EINVAL; + } + + if (!spi_context_rx_on(ctx)) { + tctrl = (TRNS_MODE_WRITE_ONLY << TCTRL_TRNS_MODE_OFFSET) | + (data_len << TCTRL_WR_TCNT_OFFSET); + dma_rx_enable = 0; + dma_tx_enable = 1; + } else if (!spi_context_tx_on(ctx)) { + tctrl = (TRNS_MODE_READ_ONLY << TCTRL_TRNS_MODE_OFFSET) | + (data_len << TCTRL_RD_TCNT_OFFSET); + dma_rx_enable = 1; + dma_tx_enable = 0; + } else { + tctrl = (TRNS_MODE_WRITE_READ << TCTRL_TRNS_MODE_OFFSET) | + (data_len << TCTRL_WR_TCNT_OFFSET) | + (data_len << TCTRL_RD_TCNT_OFFSET); + dma_rx_enable = 1; + dma_tx_enable = 1; + } + + sys_write32(tctrl, SPI_TCTRL(cfg->base)); + + /* Set sclk_div to zero */ + sys_clear_bits(SPI_TIMIN(cfg->base), 0xff); + + /* Enable END Interrupts */ + sys_write32(IEN_END_MSK, SPI_INTEN(cfg->base)); + + /* Setting DMA config*/ + error = spi_dma_move_buffers(dev); + if (error != 0) { + return error; + } + + /* Start transferring */ + sys_write32(0, SPI_CMD(cfg->base)); + + if (dma_rx_enable) { + spi_rx_dma_enable(dev); + error = dma_start(data->dma_rx.dma_dev, data->dma_rx.channel); + if (error != 0) { + return error; + } + } + if (dma_tx_enable) { + spi_tx_dma_enable(dev); + error = dma_start(data->dma_tx.dma_dev, data->dma_tx.channel); + if (error != 0) { + return error; + } + } + + return 0; +} +#endif + static int transceive(const struct device *dev, const struct spi_config *config, const struct spi_buf_set *tx_bufs, @@ -187,7 +619,6 @@ static int transceive(const struct device *dev, spi_context_buffers_setup(ctx, tx_bufs, rx_bufs, dfs); spi_context_cs_control(ctx, true); - transfer_next_chunk(dev); sys_set_bits(SPI_CTRL(cfg->base), CTRL_TX_FIFO_RST_MSK); sys_set_bits(SPI_CTRL(cfg->base), CTRL_RX_FIFO_RST_MSK); @@ -204,11 +635,23 @@ static int transceive(const struct device *dev, data->chunk_len = chunk_len; - error = spi_transfer(dev); - if (error != 0) { - return error; - } +#ifdef CONFIG_ANDES_SPI_DMA_MODE + if ((data->dma_tx.dma_dev != NULL) && (data->dma_rx.dma_dev != NULL)) { + error = spi_transfer_dma(dev); + if (error != 0) { + return error; + } + } else { +#endif /* CONFIG_ANDES_SPI_DMA_MODE */ + error = spi_transfer(dev); + if (error != 0) { + return error; + } + +#ifdef CONFIG_ANDES_SPI_DMA_MODE + } +#endif /* CONFIG_ANDES_SPI_DMA_MODE */ error = spi_context_wait_for_completion(ctx); spi_context_cs_control(ctx, false); } @@ -266,6 +709,18 @@ int spi_atcspi200_init(const struct device *dev) spi_context_unlock_unconditionally(&data->ctx); +#ifdef CONFIG_ANDES_SPI_DMA_MODE + if (!data->dma_tx.dma_dev) { + LOG_ERR("DMA device not found"); + return -ENODEV; + } + + if (!data->dma_rx.dma_dev) { + LOG_ERR("DMA device not found"); + return -ENODEV; + } +#endif + /* Get the TX/RX FIFO size of this device */ data->tx_fifo_size = TX_FIFO_SIZE(cfg->base); data->rx_fifo_size = RX_FIFO_SIZE(cfg->base); @@ -385,6 +840,24 @@ static void spi_atcspi200_irq_handler(void *arg) /* Disable all SPI interrupts */ sys_write32(0, SPI_INTEN(cfg->base)); +#ifdef CONFIG_ANDES_SPI_DMA_MODE + if ((data->dma_tx.dma_dev != NULL) && data->dma_tx.dma_cfg.source_chaining_en) { + + spi_tx_dma_disable(dev); + dma_stop(data->dma_tx.dma_dev, data->dma_tx.channel); + data->dma_tx.block_idx = 0; + data->dma_tx.dma_blk_cfg.next_block = NULL; + } + + if ((data->dma_rx.dma_dev != NULL) && data->dma_rx.dma_cfg.source_chaining_en) { + + spi_rx_dma_disable(dev); + dma_stop(data->dma_rx.dma_dev, data->dma_rx.channel); + data->dma_rx.block_idx = 0; + data->dma_rx.dma_blk_cfg.next_block = NULL; + } +#endif /* CONFIG_ANDES_SPI_DMA_MODE */ + data->busy = false; spi_context_complete(ctx, dev, error); @@ -392,7 +865,67 @@ static void spi_atcspi200_irq_handler(void *arg) } } +#if CONFIG_ANDES_SPI_DMA_MODE + +#define ANDES_DMA_CONFIG_DIRECTION(config) (FIELD_GET(GENMASK(1, 0), config)) +#define ANDES_DMA_CONFIG_PERIPHERAL_ADDR_INC(config) (FIELD_GET(BIT(2), config)) +#define ANDES_DMA_CONFIG_MEMORY_ADDR_INC(config) (FIELD_GET(BIT(3), config)) +#define ANDES_DMA_CONFIG_PERIPHERAL_DATA_SIZE(config) (1 << (FIELD_GET(GENMASK(6, 4), config))) +#define ANDES_DMA_CONFIG_MEMORY_DATA_SIZE(config) (1 << (FIELD_GET(GENMASK(9, 7), config))) +#define ANDES_DMA_CONFIG_PRIORITY(config) (FIELD_GET(BIT(10), config)) + +#define DMA_CHANNEL_CONFIG(id, dir) \ + DT_INST_DMAS_CELL_BY_NAME(id, dir, channel_config) + +#define SPI_DMA_CHANNEL_INIT(index, dir, dir_cap, src_dev, dest_dev) \ + .dma_dev = DEVICE_DT_GET(DT_INST_DMAS_CTLR_BY_NAME(index, dir)), \ + .channel = \ + DT_INST_DMAS_CELL_BY_NAME(index, dir, channel), \ + .dma_cfg = { \ + .dma_slot = \ + DT_INST_DMAS_CELL_BY_NAME(index, dir, slot), \ + .channel_direction = ANDES_DMA_CONFIG_DIRECTION( \ + DMA_CHANNEL_CONFIG(index, dir)), \ + .complete_callback_en = 0, \ + .error_callback_en = 0, \ + .source_data_size = \ + ANDES_DMA_CONFIG_##src_dev##_DATA_SIZE( \ + DMA_CHANNEL_CONFIG(index, dir) \ + ), \ + .dest_data_size = \ + ANDES_DMA_CONFIG_##dest_dev##_DATA_SIZE( \ + DMA_CHANNEL_CONFIG(index, dir) \ + ), \ + .source_burst_length = 1, /* SINGLE transfer */ \ + .dest_burst_length = 1, /* SINGLE transfer */ \ + .channel_priority = ANDES_DMA_CONFIG_PRIORITY( \ + DMA_CHANNEL_CONFIG(index, dir) \ + ), \ + .source_chaining_en = DT_PROP(DT_INST_DMAS_CTLR_BY_NAME( \ + index, dir), chain_transfer), \ + .dest_chaining_en = DT_PROP(DT_INST_DMAS_CTLR_BY_NAME( \ + index, dir), chain_transfer), \ + }, \ + .src_addr_increment = \ + ANDES_DMA_CONFIG_##src_dev##_ADDR_INC( \ + DMA_CHANNEL_CONFIG(index, dir) \ + ), \ + .dst_addr_increment = \ + ANDES_DMA_CONFIG_##dest_dev##_ADDR_INC( \ + DMA_CHANNEL_CONFIG(index, dir) \ + ) + +#define SPI_DMA_CHANNEL(id, dir, DIR, src, dest) \ + .dma_##dir = { \ + COND_CODE_1(DT_INST_DMAS_HAS_NAME(id, dir), \ + (SPI_DMA_CHANNEL_INIT(id, dir, DIR, src, dest)), \ + (NULL)) \ + }, + +#else #define SPI_DMA_CHANNEL(id, dir, DIR, src, dest) +#endif + #define SPI_BUSY_INIT .busy = false, #if (CONFIG_XIP) @@ -402,8 +935,7 @@ static void spi_atcspi200_irq_handler(void *arg) #endif #define SPI_INIT(n) \ - static struct spi_atcspi200_data spi_atcspi200_dev_data_##n = {\ - .self_dev = DEVICE_DT_INST_GET(n), \ + static struct spi_atcspi200_data spi_atcspi200_dev_data_##n = { \ SPI_CONTEXT_INIT_LOCK(spi_atcspi200_dev_data_##n, ctx), \ SPI_CONTEXT_INIT_SYNC(spi_atcspi200_dev_data_##n, ctx), \ SPI_CONTEXT_CS_GPIOS_INITIALIZE(DT_DRV_INST(n), ctx) \ diff --git a/drivers/spi/spi_andes_atcspi200.h b/drivers/spi/spi_andes_atcspi200.h index 3eb9a53202b..e498105f3e5 100644 --- a/drivers/spi/spi_andes_atcspi200.h +++ b/drivers/spi/spi_andes_atcspi200.h @@ -11,6 +11,10 @@ LOG_MODULE_REGISTER(spi_atcspi200); #include #include +#ifdef CONFIG_ANDES_SPI_DMA_MODE +#include +#endif + #define REG_TFMAT 0x10 #define REG_TCTRL 0x20 #define REG_CMD 0x24 @@ -22,16 +26,16 @@ LOG_MODULE_REGISTER(spi_atcspi200); #define REG_TIMIN 0x40 #define REG_CONFIG 0x7c -#define SPI_TFMAT(base) (base + 0x10) -#define SPI_TCTRL(base) (base + 0x20) -#define SPI_CMD(base) (base + 0x24) -#define SPI_DATA(base) (base + 0x2c) -#define SPI_CTRL(base) (base + 0x30) -#define SPI_STAT(base) (base + 0x34) -#define SPI_INTEN(base) (base + 0x38) -#define SPI_INTST(base) (base + 0x3c) -#define SPI_TIMIN(base) (base + 0x40) -#define SPI_CONFIG(base) (base + 0x7c) +#define SPI_TFMAT(base) (base + REG_TFMAT) +#define SPI_TCTRL(base) (base + REG_TCTRL) +#define SPI_CMD(base) (base + REG_CMD) +#define SPI_DATA(base) (base + REG_DATA) +#define SPI_CTRL(base) (base + REG_CTRL) +#define SPI_STAT(base) (base + REG_STAT) +#define SPI_INTEN(base) (base + REG_INTEN) +#define SPI_INTST(base) (base + REG_INTST) +#define SPI_TIMIN(base) (base + REG_TIMIN) +#define SPI_CONFIG(base) (base + REG_CONFIG) /* Field mask of SPI transfer format register */ #define TFMAT_DATA_LEN_OFFSET (8) From ec9dc5d73997a5f80e379bfe188384639a87dfc5 Mon Sep 17 00:00:00 2001 From: Gerard Marull-Paretas Date: Mon, 29 Jan 2024 16:09:25 +0100 Subject: [PATCH 3208/3723] scripts: west: runners: nrf: fix UICR check uicr_ranges dictionary entries did not contain the `_FAMILY` suffix, now used by self.family variable, resulting in an always false check. Signed-off-by: Gerard Marull-Paretas --- scripts/west_commands/runners/nrf_common.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/scripts/west_commands/runners/nrf_common.py b/scripts/west_commands/runners/nrf_common.py index 788021c6191..93871d831ee 100644 --- a/scripts/west_commands/runners/nrf_common.py +++ b/scripts/west_commands/runners/nrf_common.py @@ -178,9 +178,9 @@ def hex_has_uicr_content(self): # A map from SoCs which need this check to their UICR address # ranges. If self.family isn't in here, do nothing. uicr_ranges = { - 'NRF53': ((0x00FF8000, 0x00FF8800), - (0x01FF8000, 0x01FF8800)), - 'NRF91': ((0x00FF8000, 0x00FF8800),), + 'NRF53_FAMILY': ((0x00FF8000, 0x00FF8800), + (0x01FF8000, 0x01FF8800)), + 'NRF91_FAMILY': ((0x00FF8000, 0x00FF8800),), } if self.family not in uicr_ranges: From 6d6573812609608e8d35a0e317249b101f747f81 Mon Sep 17 00:00:00 2001 From: Armando Visconti Date: Fri, 12 Jan 2024 11:21:01 +0100 Subject: [PATCH 3209/3723] dts/bindings/sensor: lis2du12: fix macros typos Fix few macros typos. Signed-off-by: Armando Visconti --- dts/bindings/sensor/st,lis2du12-common.yaml | 30 ++++++++++----------- 1 file changed, 15 insertions(+), 15 deletions(-) diff --git a/dts/bindings/sensor/st,lis2du12-common.yaml b/dts/bindings/sensor/st,lis2du12-common.yaml index d9ca38d9e32..0304fd7c512 100644 --- a/dts/bindings/sensor/st,lis2du12-common.yaml +++ b/dts/bindings/sensor/st,lis2du12-common.yaml @@ -11,8 +11,8 @@ description: | lis2du12: lis2du12@0 { ... - accel-range = ; - accel-odr = ; + accel-range = ; + accel-odr = ; }; include: sensor-device.yaml @@ -74,19 +74,19 @@ properties: Default is power-up configuration. 0x00 # LIS2DU12_DT_ODR_OFF - 0x01 # 1Hz6 (ultra low power) - 0x02 # 3Hz (ultra low power) - 0x03 # 25Hz (ultra low power) - 0x04 # 6Hz (low power) - 0x05 # 12Hz5 (low power) - 0x06 # 25Hz (low power) - 0x07 # 50Hz (low power) - 0x08 # 100Hz (low power) - 0x09 # 200Hz (low power) - 0x0a # 400Hz (low power) - 0x0b # 800Hz (low power) - 0x0e # Single-shot high latency by INT2 - 0x0f # Single-shot high latency by IF + 0x01 # LIS2DU12_DT_ODR_AT_1Hz6_ULP + 0x02 # LIS2DU12_DT_ODR_AT_3Hz_ULP + 0x03 # LIS2DU12_DT_ODR_AT_6Hz_ULP + 0x04 # LIS2DU12_DT_ODR_AT_6Hz + 0x05 # LIS2DU12_DT_ODR_AT_12Hz + 0x06 # LIS2DU12_DT_ODR_AT_25Hz + 0x07 # LIS2DU12_DT_ODR_AT_50Hz + 0x08 # LIS2DU12_DT_ODR_AT_100Hz + 0x09 # LIS2DU12_DT_ODR_AT_200Hz + 0x0a # LIS2DU12_DT_ODR_AT_400Hz + 0x0b # LIS2DU12_DT_ODR_AT_800Hz + 0x0e # LIS2DU12_DT_ODR_TRIG_PIN + 0x0f # LIS2DU12_DT_ODR_TRIG_SW enum: [0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b, 0x0e, 0x0f] From dadac5d0ce27b862debd02ee33c88aa391c6e91d Mon Sep 17 00:00:00 2001 From: Armando Visconti Date: Tue, 16 Jan 2024 12:07:54 +0100 Subject: [PATCH 3210/3723] drivers/sensor: stmemsc: add new sets of i2c/spi APIs Add APIs to: 1. read/write sensor regs on i2c/spi bus enabling adrress auto-increment in a stmemsc specific way. 2. read/write sensor custom APIs. Signed-off-by: Armando Visconti --- drivers/sensor/stmemsc/CMakeLists.txt | 1 + drivers/sensor/stmemsc/stmemsc.h | 90 ++++++++++++++++++++----- drivers/sensor/stmemsc/stmemsc_i2c.c | 21 +++++- drivers/sensor/stmemsc/stmemsc_mdelay.c | 15 +++++ drivers/sensor/stmemsc/stmemsc_spi.c | 17 +++++ 5 files changed, 126 insertions(+), 18 deletions(-) create mode 100644 drivers/sensor/stmemsc/stmemsc_mdelay.c diff --git a/drivers/sensor/stmemsc/CMakeLists.txt b/drivers/sensor/stmemsc/CMakeLists.txt index 6ea84e2063e..d6c2c40f68f 100644 --- a/drivers/sensor/stmemsc/CMakeLists.txt +++ b/drivers/sensor/stmemsc/CMakeLists.txt @@ -9,3 +9,4 @@ zephyr_library() zephyr_library_sources_ifdef(CONFIG_I2C stmemsc_i2c.c) zephyr_library_sources_ifdef(CONFIG_I3C stmemsc_i3c.c) zephyr_library_sources_ifdef(CONFIG_SPI stmemsc_spi.c) +zephyr_library_sources(stmemsc_mdelay.c) diff --git a/drivers/sensor/stmemsc/stmemsc.h b/drivers/sensor/stmemsc/stmemsc.h index d4e6e0767bb..bd87e269b08 100644 --- a/drivers/sensor/stmemsc/stmemsc.h +++ b/drivers/sensor/stmemsc/stmemsc.h @@ -15,22 +15,18 @@ #include #include - -static inline void stmemsc_mdelay(uint32_t millisec) -{ - k_msleep(millisec); -} +void stmemsc_mdelay(uint32_t millisec); #ifdef CONFIG_I2C /* * Populate the stmdev_ctx_t structure pointed by stmdev_ctx_ptr with - * stmemsc i2c APIs. + * standard stmemsc i2c APIs. */ #define STMEMSC_CTX_I2C(stmdev_ctx_ptr) \ .ctx = { \ - .read_reg = (stmdev_read_ptr) stmemsc_i2c_read, \ - .write_reg = (stmdev_write_ptr) stmemsc_i2c_write, \ - .mdelay = (stmdev_mdelay_ptr) stmemsc_mdelay, \ + .read_reg = (stmdev_read_ptr)stmemsc_i2c_read, \ + .write_reg = (stmdev_write_ptr)stmemsc_i2c_write, \ + .mdelay = (stmdev_mdelay_ptr)stmemsc_mdelay, \ .handle = (void *)stmdev_ctx_ptr \ } @@ -38,18 +34,49 @@ int stmemsc_i2c_read(const struct i2c_dt_spec *stmemsc, uint8_t reg_addr, uint8_t *value, uint8_t len); int stmemsc_i2c_write(const struct i2c_dt_spec *stmemsc, uint8_t reg_addr, uint8_t *value, uint8_t len); + +/* + * Populate the stmdev_ctx_t structure pointed by stmdev_ctx_ptr with + * specific stmemsc i2c APIs that set reg_addr MSB to '1' in order to allow + * multiple read/write operations. This is common in some STMEMSC drivers + */ +#define STMEMSC_CTX_I2C_INCR(stmdev_ctx_ptr) \ + .ctx = { \ + .read_reg = (stmdev_read_ptr)stmemsc_i2c_read_incr, \ + .write_reg = (stmdev_write_ptr)stmemsc_i2c_write_incr, \ + .mdelay = (stmdev_mdelay_ptr)stmemsc_mdelay, \ + .handle = (void *)stmdev_ctx_ptr \ + } + +int stmemsc_i2c_read_incr(const struct i2c_dt_spec *stmemsc, + uint8_t reg_addr, uint8_t *value, uint8_t len); +int stmemsc_i2c_write_incr(const struct i2c_dt_spec *stmemsc, + uint8_t reg_addr, uint8_t *value, uint8_t len); + +/* + * Populate the stmdev_ctx_t structure pointed by stmdev_ctx_ptr with + * custom stmemsc i2c APIs specified by driver. + */ +#define STMEMSC_CTX_I2C_CUSTOM(stmdev_ctx_ptr, i2c_rd_api, i2c_wr_api) \ + .ctx = { \ + .read_reg = (stmdev_read_ptr)i2c_rd_api, \ + .write_reg = (stmdev_write_ptr)i2c_wr_api, \ + .mdelay = (stmdev_mdelay_ptr)stmemsc_mdelay, \ + .handle = (void *)stmdev_ctx_ptr \ + } + #endif #ifdef CONFIG_I3C /* * Populate the stmdev_ctx_t structure pointed by stmdev_ctx_ptr with - * stmemsc i3c APIs. + * standard stmemsc i3c APIs. */ #define STMEMSC_CTX_I3C(stmdev_ctx_ptr) \ .ctx = { \ - .read_reg = (stmdev_read_ptr) stmemsc_i3c_read, \ - .write_reg = (stmdev_write_ptr) stmemsc_i3c_write, \ - .mdelay = (stmdev_mdelay_ptr) stmemsc_mdelay, \ + .read_reg = (stmdev_read_ptr)stmemsc_i3c_read, \ + .write_reg = (stmdev_write_ptr)stmemsc_i3c_write, \ + .mdelay = (stmdev_mdelay_ptr)stmemsc_mdelay, \ .handle = (void *)stmdev_ctx_ptr \ } @@ -66,9 +93,9 @@ int stmemsc_i3c_write(void *stmemsc, */ #define STMEMSC_CTX_SPI(stmdev_ctx_ptr) \ .ctx = { \ - .read_reg = (stmdev_read_ptr) stmemsc_spi_read, \ - .write_reg = (stmdev_write_ptr) stmemsc_spi_write, \ - .mdelay = (stmdev_mdelay_ptr) stmemsc_mdelay, \ + .read_reg = (stmdev_read_ptr)stmemsc_spi_read, \ + .write_reg = (stmdev_write_ptr)stmemsc_spi_write, \ + .mdelay = (stmdev_mdelay_ptr)stmemsc_mdelay, \ .handle = (void *)stmdev_ctx_ptr \ } @@ -76,5 +103,36 @@ int stmemsc_spi_read(const struct spi_dt_spec *stmemsc, uint8_t reg_addr, uint8_t *value, uint8_t len); int stmemsc_spi_write(const struct spi_dt_spec *stmemsc, uint8_t reg_addr, uint8_t *value, uint8_t len); + +/* + * Populate the stmdev_ctx_t structure pointed by stmdev_ctx_ptr with + * specific stmemsc sp APIs that set reg_addr bit6 to '1' in order to allow + * multiple read/write operations. This is common in some STMEMSC drivers + */ +#define STMEMSC_CTX_SPI_INCR(stmdev_ctx_ptr) \ + .ctx = { \ + .read_reg = (stmdev_read_ptr)stmemsc_spi_read_incr, \ + .write_reg = (stmdev_write_ptr)stmemsc_spi_write_incr, \ + .mdelay = (stmdev_mdelay_ptr)stmemsc_mdelay, \ + .handle = (void *)stmdev_ctx_ptr \ + } + +int stmemsc_spi_read_incr(const struct spi_dt_spec *stmemsc, + uint8_t reg_addr, uint8_t *value, uint8_t len); +int stmemsc_spi_write_incr(const struct spi_dt_spec *stmemsc, + uint8_t reg_addr, uint8_t *value, uint8_t len); + +/* + * Populate the stmdev_ctx_t structure pointed by stmdev_ctx_ptr with + * custom stmemsc spi APIs specified by driver. + */ +#define STMEMSC_CTX_SPI_CUSTOM(stmdev_ctx_ptr, spi_rd_api, spi_wr_api) \ + .ctx = { \ + .read_reg = (stmdev_read_ptr)spi_rd_api, \ + .write_reg = (stmdev_write_ptr)spi_wr_api, \ + .mdelay = (stmdev_mdelay_ptr)stmemsc_mdelay, \ + .handle = (void *)stmdev_ctx_ptr \ + } + #endif #endif /* ZEPHYR_DRIVERS_SENSOR_STMEMSC_STMEMSC_H_ */ diff --git a/drivers/sensor/stmemsc/stmemsc_i2c.c b/drivers/sensor/stmemsc/stmemsc_i2c.c index 1b7f1833293..bf6ddebbd4f 100644 --- a/drivers/sensor/stmemsc/stmemsc_i2c.c +++ b/drivers/sensor/stmemsc/stmemsc_i2c.c @@ -9,14 +9,31 @@ #include "stmemsc.h" + /* Enable address auto-increment on some stmemsc sensors */ +#define STMEMSC_I2C_ADDR_AUTO_INCR BIT(7) + int stmemsc_i2c_read(const struct i2c_dt_spec *stmemsc, - uint8_t reg_addr, uint8_t *value, uint8_t len) + uint8_t reg_addr, uint8_t *value, uint8_t len) { return i2c_burst_read_dt(stmemsc, reg_addr, value, len); } int stmemsc_i2c_write(const struct i2c_dt_spec *stmemsc, - uint8_t reg_addr, uint8_t *value, uint8_t len) + uint8_t reg_addr, uint8_t *value, uint8_t len) { return i2c_burst_write_dt(stmemsc, reg_addr, value, len); } + +int stmemsc_i2c_read_incr(const struct i2c_dt_spec *stmemsc, + uint8_t reg_addr, uint8_t *value, uint8_t len) +{ + reg_addr |= STMEMSC_I2C_ADDR_AUTO_INCR; + return stmemsc_i2c_read(stmemsc, reg_addr, value, len); +} + +int stmemsc_i2c_write_incr(const struct i2c_dt_spec *stmemsc, + uint8_t reg_addr, uint8_t *value, uint8_t len) +{ + reg_addr |= STMEMSC_I2C_ADDR_AUTO_INCR; + return stmemsc_i2c_write(stmemsc, reg_addr, value, len); +} diff --git a/drivers/sensor/stmemsc/stmemsc_mdelay.c b/drivers/sensor/stmemsc/stmemsc_mdelay.c new file mode 100644 index 00000000000..0123e95b14f --- /dev/null +++ b/drivers/sensor/stmemsc/stmemsc_mdelay.c @@ -0,0 +1,15 @@ +/* ST Microelectronics STMEMS hal i/f + * + * Copyright (c) 2024 STMicroelectronics + * + * SPDX-License-Identifier: Apache-2.0 + * + * zephyrproject-rtos/modules/hal/st/sensor/stmemsc/ + */ + +#include "stmemsc.h" + +void stmemsc_mdelay(uint32_t millisec) +{ + k_msleep(millisec); +} diff --git a/drivers/sensor/stmemsc/stmemsc_spi.c b/drivers/sensor/stmemsc/stmemsc_spi.c index 0d3557ce135..3d728c78d8b 100644 --- a/drivers/sensor/stmemsc/stmemsc_spi.c +++ b/drivers/sensor/stmemsc/stmemsc_spi.c @@ -11,6 +11,9 @@ #define SPI_READ (1 << 7) + /* Enable address auto-increment on some stmemsc sensors */ +#define STMEMSC_SPI_ADDR_AUTO_INCR BIT(6) + /* * SPI read */ @@ -56,3 +59,17 @@ int stmemsc_spi_write(const struct spi_dt_spec *stmemsc, return spi_write_dt(stmemsc, &tx); } + +int stmemsc_spi_read_incr(const struct spi_dt_spec *stmemsc, + uint8_t reg_addr, uint8_t *value, uint8_t len) +{ + reg_addr |= STMEMSC_SPI_ADDR_AUTO_INCR; + return stmemsc_spi_read(stmemsc, reg_addr, value, len); +} + +int stmemsc_spi_write_incr(const struct spi_dt_spec *stmemsc, + uint8_t reg_addr, uint8_t *value, uint8_t len) +{ + reg_addr |= STMEMSC_SPI_ADDR_AUTO_INCR; + return stmemsc_spi_write(stmemsc, reg_addr, value, len); +} From 4828340b92a950213a7012cdf68bf34259ff7bf0 Mon Sep 17 00:00:00 2001 From: Armando Visconti Date: Fri, 12 Jan 2024 13:55:14 +0100 Subject: [PATCH 3211/3723] drivers/sensor: add support to LIS2DE12 accelerometer MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The LIS2DE12 is an ultra-low-power high- performance three-axis linear accelerometer belonging to the “femto” family with digital I2C/SPI serial interface standard output. This driver is based on stmemsc HAL i/f v2.3 https://www.st.com/en/datasheet/lis2de12.pdf Signed-off-by: Armando Visconti --- drivers/sensor/CMakeLists.txt | 1 + drivers/sensor/Kconfig | 1 + drivers/sensor/lis2de12/CMakeLists.txt | 12 + drivers/sensor/lis2de12/Kconfig | 30 ++ drivers/sensor/lis2de12/lis2de12.c | 471 ++++++++++++++++++ drivers/sensor/lis2de12/lis2de12.h | 95 ++++ drivers/sensor/lis2de12/lis2de12_trigger.c | 195 ++++++++ dts/bindings/sensor/st,lis2de12-common.yaml | 78 +++ dts/bindings/sensor/st,lis2de12-i2c.yaml | 10 + dts/bindings/sensor/st,lis2de12-spi.yaml | 10 + include/zephyr/dt-bindings/sensor/lis2de12.h | 27 + tests/drivers/build_all/sensor/app.overlay | 3 +- tests/drivers/build_all/sensor/i2c.dtsi | 10 + .../build_all/sensor/sensors_die_temp.conf | 1 + .../sensor/sensors_trigger_global.conf | 1 + .../sensor/sensors_trigger_none.conf | 1 + .../build_all/sensor/sensors_trigger_own.conf | 1 + tests/drivers/build_all/sensor/spi.dtsi | 9 + 18 files changed, 955 insertions(+), 1 deletion(-) create mode 100644 drivers/sensor/lis2de12/CMakeLists.txt create mode 100644 drivers/sensor/lis2de12/Kconfig create mode 100644 drivers/sensor/lis2de12/lis2de12.c create mode 100644 drivers/sensor/lis2de12/lis2de12.h create mode 100644 drivers/sensor/lis2de12/lis2de12_trigger.c create mode 100644 dts/bindings/sensor/st,lis2de12-common.yaml create mode 100644 dts/bindings/sensor/st,lis2de12-i2c.yaml create mode 100644 dts/bindings/sensor/st,lis2de12-spi.yaml create mode 100644 include/zephyr/dt-bindings/sensor/lis2de12.h diff --git a/drivers/sensor/CMakeLists.txt b/drivers/sensor/CMakeLists.txt index a2c3a0f34cb..effdf205427 100644 --- a/drivers/sensor/CMakeLists.txt +++ b/drivers/sensor/CMakeLists.txt @@ -70,6 +70,7 @@ add_subdirectory_ifdef(CONFIG_ISL29035 isl29035) add_subdirectory_ifdef(CONFIG_ISM330DHCX ism330dhcx) add_subdirectory_ifdef(CONFIG_ITDS wsen_itds) add_subdirectory_ifdef(CONFIG_LIS2DH lis2dh) +add_subdirectory_ifdef(CONFIG_LIS2DE12 lis2de12) add_subdirectory_ifdef(CONFIG_LIS2DS12 lis2ds12) add_subdirectory_ifdef(CONFIG_LIS2DU12 lis2du12) add_subdirectory_ifdef(CONFIG_LIS2DW12 lis2dw12) diff --git a/drivers/sensor/Kconfig b/drivers/sensor/Kconfig index 4a446e59783..c3b682175c8 100644 --- a/drivers/sensor/Kconfig +++ b/drivers/sensor/Kconfig @@ -150,6 +150,7 @@ source "drivers/sensor/ism330dhcx/Kconfig" source "drivers/sensor/ite_tach_it8xxx2/Kconfig" source "drivers/sensor/ite_vcmp_it8xxx2/Kconfig" source "drivers/sensor/lis2dh/Kconfig" +source "drivers/sensor/lis2de12/Kconfig" source "drivers/sensor/lis2ds12/Kconfig" source "drivers/sensor/lis2du12/Kconfig" source "drivers/sensor/lis2dw12/Kconfig" diff --git a/drivers/sensor/lis2de12/CMakeLists.txt b/drivers/sensor/lis2de12/CMakeLists.txt new file mode 100644 index 00000000000..d1ae338bc83 --- /dev/null +++ b/drivers/sensor/lis2de12/CMakeLists.txt @@ -0,0 +1,12 @@ +# ST Microelectronics LIS2DE12 3-axis accelerometer sensor driver +# +# Copyright (c) 2024 STMicroelectronics +# +# SPDX-License-Identifier: Apache-2.0 +# +zephyr_library() + +zephyr_library_sources(lis2de12.c) +zephyr_library_sources_ifdef(CONFIG_LIS2DE12_TRIGGER lis2de12_trigger.c) + +zephyr_library_include_directories(../stmemsc) diff --git a/drivers/sensor/lis2de12/Kconfig b/drivers/sensor/lis2de12/Kconfig new file mode 100644 index 00000000000..fe8402ce6e9 --- /dev/null +++ b/drivers/sensor/lis2de12/Kconfig @@ -0,0 +1,30 @@ +# ST Microelectronics LIS2DE12 3-axis accelerometer sensor driver + +# Copyright (c) 2024 STMicroelectronics +# SPDX-License-Identifier: Apache-2.0 + +menuconfig LIS2DE12 + bool "LIS2DE12 I2C/SPI smartxl Chip" + default y + depends on DT_HAS_ST_LIS2DE12_ENABLED + depends on ZEPHYR_HAL_ST_MODULE + select I2C if $(dt_compat_on_bus,$(DT_COMPAT_ST_LIS2DE12),i2c) + select SPI if $(dt_compat_on_bus,$(DT_COMPAT_ST_LIS2DE12),spi) + select HAS_STMEMSC + select USE_STDC_LIS2DE12 + help + Enable driver for LIS2DE12 smartxl sensor. + +if LIS2DE12 + +module = LIS2DE12 +thread_priority = 10 +thread_stack_size = 1024 +source "drivers/sensor/Kconfig.trigger_template" + +config LIS2DE12_ENABLE_TEMP + bool "Die temperature sensor" + help + Enable/disable die temperature sensor + +endif # LIS2DE12 diff --git a/drivers/sensor/lis2de12/lis2de12.c b/drivers/sensor/lis2de12/lis2de12.c new file mode 100644 index 00000000000..9cceccdeb20 --- /dev/null +++ b/drivers/sensor/lis2de12/lis2de12.c @@ -0,0 +1,471 @@ +/* ST Microelectronics LIS2DE12 3-axis accelerometer sensor driver + * + * Copyright (c) 2024 STMicroelectronics + * + * SPDX-License-Identifier: Apache-2.0 + * + * Datasheet: + * https://www.st.com/resource/en/datasheet/lis2de12.pdf + */ + +#define DT_DRV_COMPAT st_lis2de12 + +#include +#include +#include +#include +#include +#include +#include +#include + +#include "lis2de12.h" + +LOG_MODULE_REGISTER(LIS2DE12, CONFIG_SENSOR_LOG_LEVEL); + +static const uint16_t lis2de12_odr_map[10] = { 0, 1, 10, 25, 50, 100, 200, 400, 1620, 5376}; + +static int lis2de12_freq_to_odr_val(const struct device *dev, uint16_t freq) +{ + size_t i; + + for (i = 0; i < ARRAY_SIZE(lis2de12_odr_map); i++) { + if (freq <= lis2de12_odr_map[i]) { + return i; + } + } + + return -EINVAL; +} + +typedef struct { + uint16_t fs; + uint32_t gain; /* Accel sensor sensitivity in ug/LSB */ +} fs_map; + +static const fs_map lis2de12_accel_fs_map[] = { + {2, 15600}, + {4, 31200}, + {8, 62500}, + {16, 187500}, + }; + +static int lis2de12_accel_range_to_fs_val(int32_t range) +{ + size_t i; + + for (i = 0; i < ARRAY_SIZE(lis2de12_accel_fs_map); i++) { + if (range == lis2de12_accel_fs_map[i].fs) { + return i; + } + } + + return -EINVAL; +} + +static int lis2de12_accel_set_fs_raw(const struct device *dev, uint8_t fs) +{ + const struct lis2de12_config *cfg = dev->config; + stmdev_ctx_t *ctx = (stmdev_ctx_t *)&cfg->ctx; + struct lis2de12_data *data = dev->data; + + if (lis2de12_full_scale_set(ctx, fs) < 0) { + return -EIO; + } + + data->accel_fs = fs; + + return 0; +} + +static int lis2de12_accel_set_odr_raw(const struct device *dev, uint8_t odr) +{ + const struct lis2de12_config *cfg = dev->config; + stmdev_ctx_t *ctx = (stmdev_ctx_t *)&cfg->ctx; + struct lis2de12_data *data = dev->data; + + if (lis2de12_data_rate_set(ctx, odr) < 0) { + return -EIO; + } + + data->accel_freq = odr; + + return 0; +} + +static int lis2de12_accel_odr_set(const struct device *dev, uint16_t freq) +{ + int odr; + + odr = lis2de12_freq_to_odr_val(dev, freq); + if (odr < 0) { + return odr; + } + + if (lis2de12_accel_set_odr_raw(dev, odr) < 0) { + LOG_ERR("failed to set accelerometer sampling rate"); + return -EIO; + } + + return 0; +} + +static int lis2de12_accel_range_set(const struct device *dev, int32_t range) +{ + int fs; + struct lis2de12_data *data = dev->data; + + fs = lis2de12_accel_range_to_fs_val(range); + if (fs < 0) { + return fs; + } + + if (lis2de12_accel_set_fs_raw(dev, fs) < 0) { + LOG_ERR("failed to set accelerometer full-scale"); + return -EIO; + } + + data->acc_gain = lis2de12_accel_fs_map[fs].gain; + return 0; +} + +static int lis2de12_accel_config(const struct device *dev, + enum sensor_channel chan, + enum sensor_attribute attr, + const struct sensor_value *val) +{ + switch (attr) { + case SENSOR_ATTR_FULL_SCALE: + return lis2de12_accel_range_set(dev, sensor_ms2_to_g(val)); + case SENSOR_ATTR_SAMPLING_FREQUENCY: + return lis2de12_accel_odr_set(dev, val->val1); + default: + LOG_WRN("Accel attribute %d not supported.", attr); + return -ENOTSUP; + } +} + +static int lis2de12_attr_set(const struct device *dev, + enum sensor_channel chan, + enum sensor_attribute attr, + const struct sensor_value *val) +{ + switch (chan) { + case SENSOR_CHAN_ACCEL_XYZ: + return lis2de12_accel_config(dev, chan, attr, val); + default: + LOG_WRN("attribute %d not supported on this channel.", chan); + return -ENOTSUP; + } +} + +static int lis2de12_sample_fetch_accel(const struct device *dev) +{ + const struct lis2de12_config *cfg = dev->config; + stmdev_ctx_t *ctx = (stmdev_ctx_t *)&cfg->ctx; + struct lis2de12_data *data = dev->data; + + if (lis2de12_acceleration_raw_get(ctx, data->acc) < 0) { + LOG_ERR("Failed to read sample"); + return -EIO; + } + + return 0; +} + +#if defined(CONFIG_LIS2DE12_ENABLE_TEMP) +static int lis2de12_sample_fetch_temp(const struct device *dev) +{ + const struct lis2de12_config *cfg = dev->config; + stmdev_ctx_t *ctx = (stmdev_ctx_t *)&cfg->ctx; + struct lis2de12_data *data = dev->data; + + if (lis2de12_temperature_raw_get(ctx, &data->temp_sample) < 0) { + LOG_DBG("Failed to read sample"); + return -EIO; + } + + return 0; +} +#endif + +static int lis2de12_sample_fetch(const struct device *dev, + enum sensor_channel chan) +{ + switch (chan) { + case SENSOR_CHAN_ACCEL_XYZ: + lis2de12_sample_fetch_accel(dev); + break; +#if defined(CONFIG_LIS2DE12_ENABLE_TEMP) + case SENSOR_CHAN_DIE_TEMP: + lis2de12_sample_fetch_temp(dev); + break; +#endif + case SENSOR_CHAN_ALL: + lis2de12_sample_fetch_accel(dev); +#if defined(CONFIG_LIS2DE12_ENABLE_TEMP) + lis2de12_sample_fetch_temp(dev); +#endif + break; + default: + return -ENOTSUP; + } + + return 0; +} + +static inline void lis2de12_accel_convert(struct sensor_value *val, int raw_val, + uint32_t sensitivity) +{ + int64_t dval; + + /* Sensitivity is exposed in ug/LSB */ + /* Convert to m/s^2 */ + dval = (int64_t)(raw_val / 256) * sensitivity * SENSOR_G_DOUBLE; + val->val1 = (int32_t)(dval / 1000000); + val->val2 = (int32_t)(dval % 1000000); + +} + +static inline int lis2de12_accel_get_channel(enum sensor_channel chan, + struct sensor_value *val, + struct lis2de12_data *data, + uint32_t sensitivity) +{ + uint8_t i; + + switch (chan) { + case SENSOR_CHAN_ACCEL_X: + lis2de12_accel_convert(val, data->acc[0], sensitivity); + break; + case SENSOR_CHAN_ACCEL_Y: + lis2de12_accel_convert(val, data->acc[1], sensitivity); + break; + case SENSOR_CHAN_ACCEL_Z: + lis2de12_accel_convert(val, data->acc[2], sensitivity); + break; + case SENSOR_CHAN_ACCEL_XYZ: + for (i = 0; i < 3; i++) { + lis2de12_accel_convert(val++, data->acc[i], sensitivity); + } + break; + default: + return -ENOTSUP; + } + + return 0; +} + +static int lis2de12_accel_channel_get(enum sensor_channel chan, + struct sensor_value *val, + struct lis2de12_data *data) +{ + return lis2de12_accel_get_channel(chan, val, data, data->acc_gain); +} + +#if defined(CONFIG_LIS2DE12_ENABLE_TEMP) +static void lis2de12_temp_channel_get(struct sensor_value *val, struct lis2de12_data *data) +{ + int64_t micro_c; + + /* convert units to micro Celsius. Raw temperature samples are + * expressed in 256 LSB/deg_C units. And LSB output is 0 at 25 C. + */ + micro_c = ((int64_t)data->temp_sample * 1000000) / 256; + + val->val1 = micro_c / 1000000 + 25; + val->val2 = micro_c % 1000000; +} +#endif + +static int lis2de12_channel_get(const struct device *dev, + enum sensor_channel chan, + struct sensor_value *val) +{ + struct lis2de12_data *data = dev->data; + + switch (chan) { + case SENSOR_CHAN_ACCEL_X: + case SENSOR_CHAN_ACCEL_Y: + case SENSOR_CHAN_ACCEL_Z: + case SENSOR_CHAN_ACCEL_XYZ: + lis2de12_accel_channel_get(chan, val, data); + break; +#if defined(CONFIG_LIS2DE12_ENABLE_TEMP) + case SENSOR_CHAN_DIE_TEMP: + lis2de12_temp_channel_get(val, data); + break; +#endif + default: + return -ENOTSUP; + } + + return 0; +} + +static const struct sensor_driver_api lis2de12_driver_api = { + .attr_set = lis2de12_attr_set, +#if CONFIG_LIS2DE12_TRIGGER + .trigger_set = lis2de12_trigger_set, +#endif + .sample_fetch = lis2de12_sample_fetch, + .channel_get = lis2de12_channel_get, +}; + +static int lis2de12_init_chip(const struct device *dev) +{ + const struct lis2de12_config *cfg = dev->config; + stmdev_ctx_t *ctx = (stmdev_ctx_t *)&cfg->ctx; + struct lis2de12_data *lis2de12 = dev->data; + uint8_t chip_id; + uint8_t odr, fs; + + if (lis2de12_device_id_get(ctx, &chip_id) < 0) { + LOG_ERR("Failed reading chip id"); + return -EIO; + } + + if (chip_id != LIS2DE12_ID) { + LOG_ERR("Invalid chip id 0x%x", chip_id); + return -EIO; + } + + LOG_INF("chip id 0x%x", chip_id); + + if (lis2de12_block_data_update_set(ctx, 1) < 0) { + LOG_ERR("failed to set BDU"); + return -EIO; + } + + /* set FS from DT */ + fs = cfg->accel_range; + LOG_DBG("accel range is %d", fs); + if (lis2de12_accel_set_fs_raw(dev, fs) < 0) { + LOG_ERR("failed to set accelerometer range %d", fs); + return -EIO; + } + lis2de12->acc_gain = lis2de12_accel_fs_map[fs].gain; + + /* set odr from DT (the only way to go in high performance) */ + odr = cfg->accel_odr; + LOG_DBG("accel odr is %d", odr); + if (lis2de12_accel_set_odr_raw(dev, odr) < 0) { + LOG_ERR("failed to set accelerometer odr %d", odr); + return -EIO; + } + +#if defined(CONFIG_LIS2DE12_ENABLE_TEMP) + lis2de12_temperature_meas_set(ctx, LIS2DE12_TEMP_ENABLE); +#endif + + return 0; +} + +static int lis2de12_init(const struct device *dev) +{ +#ifdef CONFIG_LIS2DE12_TRIGGER + const struct lis2de12_config *cfg = dev->config; +#endif + struct lis2de12_data *data = dev->data; + + LOG_INF("Initialize device %s", dev->name); + data->dev = dev; + + if (lis2de12_init_chip(dev) < 0) { + LOG_ERR("failed to initialize chip"); + return -EIO; + } + +#ifdef CONFIG_LIS2DE12_TRIGGER + if (cfg->trig_enabled) { + if (lis2de12_init_interrupt(dev) < 0) { + LOG_ERR("Failed to initialize interrupt."); + return -EIO; + } + } +#endif + + return 0; +} + +/* + * Device creation macro, shared by LIS2DE12_DEFINE_SPI() and + * LIS2DE12_DEFINE_I2C(). + */ + +#define LIS2DE12_DEVICE_INIT(inst) \ + SENSOR_DEVICE_DT_INST_DEFINE(inst, \ + lis2de12_init, \ + NULL, \ + &lis2de12_data_##inst, \ + &lis2de12_config_##inst, \ + POST_KERNEL, \ + CONFIG_SENSOR_INIT_PRIORITY, \ + &lis2de12_driver_api); + +/* + * Instantiation macros used when a device is on a SPI bus. + */ + +#ifdef CONFIG_LIS2DE12_TRIGGER +#define LIS2DE12_CFG_IRQ(inst) \ + .trig_enabled = true, \ + .int1_gpio = GPIO_DT_SPEC_INST_GET_OR(inst, int1_gpios, { 0 }), \ + .int2_gpio = GPIO_DT_SPEC_INST_GET_OR(inst, int2_gpios, { 0 }), \ + .drdy_pulsed = DT_INST_PROP(inst, drdy_pulsed) +#else +#define LIS2DE12_CFG_IRQ(inst) +#endif /* CONFIG_LIS2DE12_TRIGGER */ + +#define LIS2DE12_SPI_OP (SPI_WORD_SET(8) | \ + SPI_OP_MODE_MASTER | \ + SPI_MODE_CPOL | \ + SPI_MODE_CPHA) \ + +#define LIS2DE12_CONFIG_COMMON(inst) \ + .accel_odr = DT_INST_PROP(inst, accel_odr), \ + .accel_range = DT_INST_PROP(inst, accel_range), \ + IF_ENABLED(UTIL_OR(DT_INST_NODE_HAS_PROP(inst, int1_gpios), \ + DT_INST_NODE_HAS_PROP(inst, int2_gpios)), \ + (LIS2DE12_CFG_IRQ(inst))) + +/* + * Instantiation macros used when a device is on a SPI bus. + */ + +#define LIS2DE12_CONFIG_SPI(inst) \ + { \ + STMEMSC_CTX_SPI(&lis2de12_config_##inst.stmemsc_cfg), \ + .stmemsc_cfg = { \ + .spi = SPI_DT_SPEC_INST_GET(inst, LIS2DE12_SPI_OP, 0), \ + }, \ + LIS2DE12_CONFIG_COMMON(inst) \ + } + +/* + * Instantiation macros used when a device is on an I2C bus. + */ + +#define LIS2DE12_CONFIG_I2C(inst) \ + { \ + STMEMSC_CTX_I2C_INCR(&lis2de12_config_##inst.stmemsc_cfg), \ + .stmemsc_cfg = { \ + .i2c = I2C_DT_SPEC_INST_GET(inst), \ + }, \ + LIS2DE12_CONFIG_COMMON(inst) \ + } + +/* + * Main instantiation macro. Use of COND_CODE_1() selects the right + * bus-specific macro at preprocessor time. + */ + +#define LIS2DE12_DEFINE(inst) \ + static struct lis2de12_data lis2de12_data_##inst; \ + static const struct lis2de12_config lis2de12_config_##inst = \ + COND_CODE_1(DT_INST_ON_BUS(inst, spi), \ + (LIS2DE12_CONFIG_SPI(inst)), \ + (LIS2DE12_CONFIG_I2C(inst))); \ + LIS2DE12_DEVICE_INIT(inst) + +DT_INST_FOREACH_STATUS_OKAY(LIS2DE12_DEFINE) diff --git a/drivers/sensor/lis2de12/lis2de12.h b/drivers/sensor/lis2de12/lis2de12.h new file mode 100644 index 00000000000..575fd50f962 --- /dev/null +++ b/drivers/sensor/lis2de12/lis2de12.h @@ -0,0 +1,95 @@ +/* ST Microelectronics LIS2DE12 3-axis accelerometer sensor driver + * + * Copyright (c) 2024 STMicroelectronics + * + * SPDX-License-Identifier: Apache-2.0 + * + * Datasheet: + * https://www.st.com/resource/en/datasheet/lis2de12.pdf + */ + +#ifndef ZEPHYR_DRIVERS_SENSOR_LIS2DE12_LIS2DE12_H_ +#define ZEPHYR_DRIVERS_SENSOR_LIS2DE12_LIS2DE12_H_ + +#include +#include +#include +#include +#include +#include "lis2de12_reg.h" + +#if DT_ANY_INST_ON_BUS_STATUS_OKAY(spi) +#include +#endif /* DT_ANY_INST_ON_BUS_STATUS_OKAY(spi) */ + +#if DT_ANY_INST_ON_BUS_STATUS_OKAY(i2c) +#include +#endif /* DT_ANY_INST_ON_BUS_STATUS_OKAY(i2c) */ + +#define LIS2DE12_EN_BIT 0x01 +#define LIS2DE12_DIS_BIT 0x00 + +#define SENSOR_G_DOUBLE (SENSOR_G / 1000000.0) + +struct lis2de12_config { + stmdev_ctx_t ctx; + union { +#if DT_ANY_INST_ON_BUS_STATUS_OKAY(i2c) + const struct i2c_dt_spec i2c; +#endif +#if DT_ANY_INST_ON_BUS_STATUS_OKAY(spi) + const struct spi_dt_spec spi; +#endif + } stmemsc_cfg; + uint8_t accel_pm; + uint8_t accel_odr; + uint8_t accel_range; + uint8_t drdy_pulsed; +#ifdef CONFIG_LIS2DE12_TRIGGER + const struct gpio_dt_spec int1_gpio; + const struct gpio_dt_spec int2_gpio; + bool trig_enabled; +#endif /* CONFIG_LIS2DE12_TRIGGER */ +}; + +union samples { + uint8_t raw[6]; + struct { + int16_t axis[3]; + }; +} __aligned(2); + +struct lis2de12_data { + const struct device *dev; + int16_t acc[3]; + int16_t temp_sample; + uint32_t acc_gain; + uint8_t accel_freq; + uint8_t accel_fs; + +#ifdef CONFIG_LIS2DE12_TRIGGER + struct gpio_dt_spec *drdy_gpio; + + struct gpio_callback gpio_cb; + sensor_trigger_handler_t handler_drdy_acc; + const struct sensor_trigger *trig_drdy_acc; + +#if defined(CONFIG_LIS2DE12_TRIGGER_OWN_THREAD) + K_KERNEL_STACK_MEMBER(thread_stack, CONFIG_LIS2DE12_THREAD_STACK_SIZE); + struct k_thread thread; + struct k_sem gpio_sem; +#elif defined(CONFIG_LIS2DE12_TRIGGER_GLOBAL_THREAD) + struct k_work work; +#endif +#endif /* CONFIG_LIS2DE12_TRIGGER */ +}; + +#ifdef CONFIG_LIS2DE12_TRIGGER +int lis2de12_trigger_set(const struct device *dev, + const struct sensor_trigger *trig, + sensor_trigger_handler_t handler); + +int lis2de12_init_interrupt(const struct device *dev); +#endif + +#endif /* ZEPHYR_DRIVERS_SENSOR_LIS2DE12_LIS2DE12_H_ */ diff --git a/drivers/sensor/lis2de12/lis2de12_trigger.c b/drivers/sensor/lis2de12/lis2de12_trigger.c new file mode 100644 index 00000000000..feee823bb91 --- /dev/null +++ b/drivers/sensor/lis2de12/lis2de12_trigger.c @@ -0,0 +1,195 @@ +/* ST Microelectronics LIS2DE12 3-axis accelerometer sensor driver + * + * Copyright (c) 2024 STMicroelectronics + * + * SPDX-License-Identifier: Apache-2.0 + * + * Datasheet: + * https://www.st.com/resource/en/datasheet/lis2de12.pdf + */ + +#define DT_DRV_COMPAT st_lis2de12 + +#include +#include +#include +#include + +#include "lis2de12.h" + +LOG_MODULE_DECLARE(LIS2DE12, CONFIG_SENSOR_LOG_LEVEL); + +/** + * lis2de12_enable_xl_int - XL enable selected int pin to generate interrupt + */ +static int lis2de12_enable_xl_int(const struct device *dev, int enable) +{ + const struct lis2de12_config *cfg = dev->config; + stmdev_ctx_t *ctx = (stmdev_ctx_t *)&cfg->ctx; + lis2de12_ctrl_reg3_t val = {0}; + int ret; + + if (enable) { + int16_t xl_data[3]; + + /* dummy read: re-trigger interrupt */ + lis2de12_acceleration_raw_get(ctx, xl_data); + } + + /* set interrupt */ + ret = lis2de12_pin_int1_config_get(ctx, &val); + if (ret < 0) { + LOG_ERR("pint_int1_route_get error"); + return ret; + } + + val.i1_zyxda = 1; + + return lis2de12_pin_int1_config_set(ctx, &val); +} + +/** + * lis2de12_trigger_set - link external trigger to event data ready + */ +int lis2de12_trigger_set(const struct device *dev, + const struct sensor_trigger *trig, + sensor_trigger_handler_t handler) +{ + const struct lis2de12_config *cfg = dev->config; + struct lis2de12_data *lis2de12 = dev->data; + + if (!cfg->trig_enabled) { + LOG_ERR("trigger_set op not supported"); + return -ENOTSUP; + } + + switch (trig->chan) { + case SENSOR_CHAN_ACCEL_XYZ: + lis2de12->handler_drdy_acc = handler; + lis2de12->trig_drdy_acc = trig; + if (handler) { + return lis2de12_enable_xl_int(dev, LIS2DE12_EN_BIT); + } + + return lis2de12_enable_xl_int(dev, LIS2DE12_DIS_BIT); + + default: + return -ENOTSUP; + } + +} + +/** + * lis2de12_handle_interrupt - handle the drdy event + * read data and call handler if registered any + */ +static void lis2de12_handle_interrupt(const struct device *dev) +{ + struct lis2de12_data *lis2de12 = dev->data; + const struct lis2de12_config *cfg = dev->config; + stmdev_ctx_t *ctx = (stmdev_ctx_t *)&cfg->ctx; + lis2de12_status_reg_t status; + + while (1) { + if (lis2de12_status_get(ctx, &status) < 0) { + LOG_ERR("failed reading status reg"); + return; + } + + if (status.zyxda == 0) { + /* spurious interrupt */ + break; + } + + if ((status.zyxda) && (lis2de12->handler_drdy_acc != NULL)) { + lis2de12->handler_drdy_acc(dev, lis2de12->trig_drdy_acc); + } + } + + gpio_pin_interrupt_configure_dt(lis2de12->drdy_gpio, + GPIO_INT_EDGE_TO_ACTIVE); +} + +static void lis2de12_gpio_callback(const struct device *dev, + struct gpio_callback *cb, uint32_t pins) +{ + struct lis2de12_data *lis2de12 = + CONTAINER_OF(cb, struct lis2de12_data, gpio_cb); + + ARG_UNUSED(pins); + + gpio_pin_interrupt_configure_dt(lis2de12->drdy_gpio, GPIO_INT_DISABLE); + +#if defined(CONFIG_LIS2DE12_TRIGGER_OWN_THREAD) + k_sem_give(&lis2de12->gpio_sem); +#elif defined(CONFIG_LIS2DE12_TRIGGER_GLOBAL_THREAD) + k_work_submit(&lis2de12->work); +#endif /* CONFIG_LIS2DE12_TRIGGER_OWN_THREAD */ +} + +#ifdef CONFIG_LIS2DE12_TRIGGER_OWN_THREAD +static void lis2de12_thread(struct lis2de12_data *lis2de12) +{ + while (1) { + k_sem_take(&lis2de12->gpio_sem, K_FOREVER); + lis2de12_handle_interrupt(lis2de12->dev); + } +} +#endif /* CONFIG_LIS2DE12_TRIGGER_OWN_THREAD */ + +#ifdef CONFIG_LIS2DE12_TRIGGER_GLOBAL_THREAD +static void lis2de12_work_cb(struct k_work *work) +{ + struct lis2de12_data *lis2de12 = + CONTAINER_OF(work, struct lis2de12_data, work); + + lis2de12_handle_interrupt(lis2de12->dev); +} +#endif /* CONFIG_LIS2DE12_TRIGGER_GLOBAL_THREAD */ + +int lis2de12_init_interrupt(const struct device *dev) +{ + struct lis2de12_data *lis2de12 = dev->data; + const struct lis2de12_config *cfg = dev->config; + int ret; + + lis2de12->drdy_gpio = (struct gpio_dt_spec *)&cfg->int1_gpio; + + /* setup data ready gpio interrupt */ + if (!gpio_is_ready_dt(lis2de12->drdy_gpio)) { + LOG_ERR("Cannot get pointer to drdy_gpio device (%p)", + lis2de12->drdy_gpio); + return -EINVAL; + } + +#if defined(CONFIG_LIS2DE12_TRIGGER_OWN_THREAD) + k_sem_init(&lis2de12->gpio_sem, 0, K_SEM_MAX_LIMIT); + + k_thread_create(&lis2de12->thread, lis2de12->thread_stack, + CONFIG_LIS2DE12_THREAD_STACK_SIZE, + (k_thread_entry_t)lis2de12_thread, lis2de12, + NULL, NULL, K_PRIO_COOP(CONFIG_LIS2DE12_THREAD_PRIORITY), + 0, K_NO_WAIT); + k_thread_name_set(&lis2de12->thread, dev->name); +#elif defined(CONFIG_LIS2DE12_TRIGGER_GLOBAL_THREAD) + lis2de12->work.handler = lis2de12_work_cb; +#endif /* CONFIG_LIS2DE12_TRIGGER_OWN_THREAD */ + + ret = gpio_pin_configure_dt(lis2de12->drdy_gpio, GPIO_INPUT); + if (ret < 0) { + LOG_ERR("Could not configure gpio: %d", ret); + return ret; + } + + gpio_init_callback(&lis2de12->gpio_cb, + lis2de12_gpio_callback, + BIT(lis2de12->drdy_gpio->pin)); + + if (gpio_add_callback(lis2de12->drdy_gpio->port, &lis2de12->gpio_cb) < 0) { + LOG_ERR("Could not set gpio callback"); + return -EIO; + } + + return gpio_pin_interrupt_configure_dt(lis2de12->drdy_gpio, + GPIO_INT_EDGE_TO_ACTIVE); +} diff --git a/dts/bindings/sensor/st,lis2de12-common.yaml b/dts/bindings/sensor/st,lis2de12-common.yaml new file mode 100644 index 00000000000..502efd15bdd --- /dev/null +++ b/dts/bindings/sensor/st,lis2de12-common.yaml @@ -0,0 +1,78 @@ +# Copyright (c) 2024 STMicroelectronics +# SPDX-License-Identifier: Apache-2.0 + +description: | + When setting the accel-range, accel-odr, properties in a .dts or .dtsi + file you may include lis2de12.h and use the macros defined there. + + Example: + #include + + lis2de12: lis2de12@0 { + ... + + accel-range = ; + accel-odr = ; + }; + +include: sensor-device.yaml + +properties: + int1-gpios: + type: phandle-array + description: | + INT1 pin + + This pin defaults to active high when produced by the sensor. + The property value should ensure the flags properly describe + the signal that is presented to the driver. + + int2-gpios: + type: phandle-array + description: | + INT2 pin + + This pin defaults to active high when produced by the sensor. + The property value should ensure the flags properly describe + the signal that is presented to the driver. + + accel-range: + type: int + default: 0 + description: | + Range in g. Default is power-up configuration. + + 0 # LIS2DE12_DT_FS_2G (15.6 mg/LSB) + 1 # LIS2DE12_DT_FS_4G (31.2 mg/LSB) + 2 # LIS2DE12_DT_FS_8G (62.5 mg/LSB) + 3 # LIS2DE12_DT_FS_16G (187.5 mg/LSB) + + enum: [0, 1, 2, 3] + + accel-odr: + type: int + default: 0x0 + description: | + Specify the default accelerometer output data rate expressed in samples per second (Hz). + The values are taken in accordance to lis2de12_md_t enumerative in hal/st + module. Please note that this values will also enable/disable High performance mode. + Default is power-up configuration. + + 0x00 # LIS2DE12_DT_ODR_OFF + 0x01 # LIS2DE12_DT_ODR_AT_1Hz + 0x02 # LIS2DE12_DT_ODR_AT_10Hz + 0x03 # LIS2DE12_DT_ODR_AT_25Hz + 0x04 # LIS2DE12_DT_ODR_AT_50Hz + 0x05 # LIS2DE12_DT_ODR_AT_100Hz + 0x06 # LIS2DE12_DT_ODR_AT_200Hz + 0x07 # LIS2DE12_DT_ODR_AT_400Hz + 0x08 # LIS2DE12_DT_ODR_AT_1kHz620 + 0x09 # LIS2DE12_DT_ODR_AT_5kHz376 + + enum: [0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09] + + drdy-pulsed: + type: boolean + description: | + Selects the pulsed mode for data-ready interrupt when enabled, + and the latched mode when disabled. diff --git a/dts/bindings/sensor/st,lis2de12-i2c.yaml b/dts/bindings/sensor/st,lis2de12-i2c.yaml new file mode 100644 index 00000000000..3e1b5b70f35 --- /dev/null +++ b/dts/bindings/sensor/st,lis2de12-i2c.yaml @@ -0,0 +1,10 @@ +# Copyright (c) 2024 STMicroelectronics +# SPDX-License-Identifier: Apache-2.0 + +description: | + STMicroelectronics LIS2DE12 3-axis ultra-low power accelerometer sensor + accessed through I2C bus + +compatible: "st,lis2de12" + +include: ["i2c-device.yaml", "st,lis2de12-common.yaml"] diff --git a/dts/bindings/sensor/st,lis2de12-spi.yaml b/dts/bindings/sensor/st,lis2de12-spi.yaml new file mode 100644 index 00000000000..525d587279a --- /dev/null +++ b/dts/bindings/sensor/st,lis2de12-spi.yaml @@ -0,0 +1,10 @@ +# Copyright (c) 2024 STMicroelectronics +# SPDX-License-Identifier: Apache-2.0 + +description: | + STMicroelectronics LIS2DE12 3-axis ultra-low power accelerometer sensor + accessed through SPI bus + +compatible: "st,lis2de12" + +include: ["spi-device.yaml", "st,lis2de12-common.yaml"] diff --git a/include/zephyr/dt-bindings/sensor/lis2de12.h b/include/zephyr/dt-bindings/sensor/lis2de12.h new file mode 100644 index 00000000000..afc1b8ee931 --- /dev/null +++ b/include/zephyr/dt-bindings/sensor/lis2de12.h @@ -0,0 +1,27 @@ +/* + * Copyright (c) 2024 STMicroelectronics + * + * SPDX-License-Identifier: Apache-2.0 + */ +#ifndef ZEPHYR_INCLUDE_DT_BINDINGS_ST_LIS2DE12_H_ +#define ZEPHYR_INCLUDE_DT_BINDINGS_ST_LIS2DE12_H_ + +/* Accel range */ +#define LIS2DE12_DT_FS_2G 0 +#define LIS2DE12_DT_FS_4G 1 +#define LIS2DE12_DT_FS_8G 2 +#define LIS2DE12_DT_FS_16G 3 + +/* Accel rates */ +#define LIS2DE12_DT_ODR_OFF 0x00 /* Power-Down */ +#define LIS2DE12_DT_ODR_AT_1Hz 0x01 /* 1Hz (normal) */ +#define LIS2DE12_DT_ODR_AT_10Hz 0x02 /* 10Hz (normal) */ +#define LIS2DE12_DT_ODR_AT_25Hz 0x03 /* 25Hz (normal) */ +#define LIS2DE12_DT_ODR_AT_50Hz 0x04 /* 50Hz (normal) */ +#define LIS2DE12_DT_ODR_AT_100Hz 0x05 /* 100Hz (normal) */ +#define LIS2DE12_DT_ODR_AT_200Hz 0x06 /* 200Hz (normal) */ +#define LIS2DE12_DT_ODR_AT_400Hz 0x07 /* 400Hz (normal) */ +#define LIS2DE12_DT_ODR_AT_1kHz620 0x08 /* 1KHz620 (normal) */ +#define LIS2DE12_DT_ODR_AT_5kHz376 0x09 /* 5KHz376 (normal) */ + +#endif /* ZEPHYR_INCLUDE_DT_BINDINGS_ST_LIS2DE12_H_ */ diff --git a/tests/drivers/build_all/sensor/app.overlay b/tests/drivers/build_all/sensor/app.overlay index c836a2b5fa8..e70d62e666d 100644 --- a/tests/drivers/build_all/sensor/app.overlay +++ b/tests/drivers/build_all/sensor/app.overlay @@ -123,7 +123,8 @@ <&test_gpio 0 0>, /* 0x25 */ <&test_gpio 0 0>, /* 0x26 */ <&test_gpio 0 0>, /* 0x27 */ - <&test_gpio 0 0>; /* 0x28 */ + <&test_gpio 0 0>, /* 0x28 */ + <&test_gpio 0 0>; /* 0x29 */ #include "spi.dtsi" }; diff --git a/tests/drivers/build_all/sensor/i2c.dtsi b/tests/drivers/build_all/sensor/i2c.dtsi index 4de9e954c1e..0a10dec83d3 100644 --- a/tests/drivers/build_all/sensor/i2c.dtsi +++ b/tests/drivers/build_all/sensor/i2c.dtsi @@ -18,6 +18,7 @@ #include #include #include +#include /**************************************** * PLEASE KEEP REG ADDRESSES SEQUENTIAL * @@ -895,3 +896,12 @@ test_i2c_bmp581: bmp581@7f { reg = <0x7f>; int-gpios = <&test_gpio 0 0>; }; + +test_i2c_lis2de12: lis2de12@80 { + compatible = "st,lis2de12"; + reg = <0x80>; + int1-gpios = <&test_gpio 0 0>; + int2-gpios = <&test_gpio 0 0>; + accel-range = ; + accel-odr = ; +}; diff --git a/tests/drivers/build_all/sensor/sensors_die_temp.conf b/tests/drivers/build_all/sensor/sensors_die_temp.conf index 1d629e9b94f..f66af170c55 100644 --- a/tests/drivers/build_all/sensor/sensors_die_temp.conf +++ b/tests/drivers/build_all/sensor/sensors_die_temp.conf @@ -3,6 +3,7 @@ CONFIG_IIS2ICLX_ENABLE_TEMP=y CONFIG_LSM6DS0_ENABLE_TEMP=y CONFIG_LSM6DSV16X_ENABLE_TEMP=y CONFIG_LSM6DSO_ENABLE_TEMP=y +CONFIG_LIS2DE12_ENABLE_TEMP=y CONFIG_LIS2DS12_ENABLE_TEMP=y CONFIG_LSM6DSO16IS_ENABLE_TEMP=y CONFIG_LSM6DSL_ENABLE_TEMP=y diff --git a/tests/drivers/build_all/sensor/sensors_trigger_global.conf b/tests/drivers/build_all/sensor/sensors_trigger_global.conf index 2dc30736420..ed045efbfb3 100644 --- a/tests/drivers/build_all/sensor/sensors_trigger_global.conf +++ b/tests/drivers/build_all/sensor/sensors_trigger_global.conf @@ -32,6 +32,7 @@ CONFIG_IIS3DHHC_TRIGGER_GLOBAL_THREAD=y CONFIG_ISL29035_TRIGGER_GLOBAL_THREAD=y CONFIG_ISM330DHCX_TRIGGER_GLOBAL_THREAD=y CONFIG_LIS2DH_TRIGGER_GLOBAL_THREAD=y +CONFIG_LIS2DE12_TRIGGER_GLOBAL_THREAD=y CONFIG_LIS2DS12_TRIGGER_GLOBAL_THREAD=y CONFIG_LIS2DU12_TRIGGER_GLOBAL_THREAD=y CONFIG_LIS2DW12_TRIGGER_GLOBAL_THREAD=y diff --git a/tests/drivers/build_all/sensor/sensors_trigger_none.conf b/tests/drivers/build_all/sensor/sensors_trigger_none.conf index 3012c09845b..a9036f88ca4 100644 --- a/tests/drivers/build_all/sensor/sensors_trigger_none.conf +++ b/tests/drivers/build_all/sensor/sensors_trigger_none.conf @@ -32,6 +32,7 @@ CONFIG_IIS3DHHC_TRIGGER_NONE=y CONFIG_ISL29035_TRIGGER_NONE=y CONFIG_ISM330DHCX_TRIGGER_NONE=y CONFIG_LIS2DH_TRIGGER_NONE=y +CONFIG_LIS2DE12_TRIGGER_NONE=y CONFIG_LIS2DS12_TRIGGER_NONE=y CONFIG_LIS2DU12_TRIGGER_NONE=y CONFIG_LIS2DW12_TRIGGER_NONE=y diff --git a/tests/drivers/build_all/sensor/sensors_trigger_own.conf b/tests/drivers/build_all/sensor/sensors_trigger_own.conf index 79ee1f82eae..1ffe64cf304 100644 --- a/tests/drivers/build_all/sensor/sensors_trigger_own.conf +++ b/tests/drivers/build_all/sensor/sensors_trigger_own.conf @@ -30,6 +30,7 @@ CONFIG_IIS3DHHC_TRIGGER_OWN_THREAD=y CONFIG_ISL29035_TRIGGER_OWN_THREAD=y CONFIG_ISM330DHCX_TRIGGER_OWN_THREAD=y CONFIG_LIS2DH_TRIGGER_OWN_THREAD=y +CONFIG_LIS2DE12_TRIGGER_OWN_THREAD=y CONFIG_LIS2DS12_TRIGGER_OWN_THREAD=y CONFIG_LIS2DU12_TRIGGER_OWN_THREAD=y CONFIG_LIS2DW12_TRIGGER_OWN_THREAD=y diff --git a/tests/drivers/build_all/sensor/spi.dtsi b/tests/drivers/build_all/sensor/spi.dtsi index 120b990fccd..0cbef7f130f 100644 --- a/tests/drivers/build_all/sensor/spi.dtsi +++ b/tests/drivers/build_all/sensor/spi.dtsi @@ -321,3 +321,12 @@ test_spi_lis2du12: lis2du12@28 { int2-gpios = <&test_gpio 0 0>; status = "okay"; }; + +test_spi_lis2de12: lis2de12@29 { + compatible = "st,lis2de12"; + reg = <0x29>; + spi-max-frequency = <0>; + int1-gpios = <&test_gpio 0 0>; + int2-gpios = <&test_gpio 0 0>; + status = "okay"; +}; From e26cd0ba915bc24d806c4e3885e273bc9065dfb4 Mon Sep 17 00:00:00 2001 From: Armando Visconti Date: Tue, 16 Jan 2024 14:49:38 +0100 Subject: [PATCH 3212/3723] sample/shield: x-nucleo-iks01a3: add support to lis2de12 on DIL24 The x-nucleo-iks01a3 shield is equipped with a DIL24 socket where different compatible sensors may fit. This commit add support to lis2de12 on DIL24 in such a way that, if sensor is not present, test would just skip it and proceed. Other sensors may be added in future. Signed-off-by: Armando Visconti --- .../x_nucleo_iks01a3/standard/README.rst | 11 +++ .../x_nucleo_iks01a3/standard/app.overlay | 19 ++++ .../x_nucleo_iks01a3/standard/prj.conf | 4 + .../x_nucleo_iks01a3/standard/src/main.c | 87 +++++++++++++++++++ 4 files changed, 121 insertions(+) create mode 100644 samples/shields/x_nucleo_iks01a3/standard/app.overlay diff --git a/samples/shields/x_nucleo_iks01a3/standard/README.rst b/samples/shields/x_nucleo_iks01a3/standard/README.rst index 03213d0006c..0677fad6c52 100644 --- a/samples/shields/x_nucleo_iks01a3/standard/README.rst +++ b/samples/shields/x_nucleo_iks01a3/standard/README.rst @@ -41,6 +41,17 @@ References - X-NUCLEO-IKS01A3: https://www.st.com/en/ecosystems/x-nucleo-iks01a3.html +DIL24 socket +************ + +In addition to sensors on board it is possible to place any other compatible +sensor on DIL24 socket. The sample is written in such a way that, if sensor is +not present, it will just be skipped. + +List of sensors currently supported on DIL24 by this sample: + +- LIS2DE12 + Building and Running ******************** diff --git a/samples/shields/x_nucleo_iks01a3/standard/app.overlay b/samples/shields/x_nucleo_iks01a3/standard/app.overlay new file mode 100644 index 00000000000..86abf4f60f4 --- /dev/null +++ b/samples/shields/x_nucleo_iks01a3/standard/app.overlay @@ -0,0 +1,19 @@ +/* + * Copyright (c) 2024 STMicroelectronics + * + * SPDX-License-Identifier: Apache-2.0 + */ + +/* + * Sensors declared here are possibly present on DIL24 + */ +&arduino_i2c { + status = "okay"; + + lis2de18_18_x_nucleo_iks01a3: lis2de12@18 { + compatible = "st,lis2de12"; + reg = <0x18>; + int1-gpios = <&arduino_header 5 GPIO_ACTIVE_HIGH>; /* A5 */ + }; + +}; diff --git a/samples/shields/x_nucleo_iks01a3/standard/prj.conf b/samples/shields/x_nucleo_iks01a3/standard/prj.conf index 8731ee38c54..ae43106404f 100644 --- a/samples/shields/x_nucleo_iks01a3/standard/prj.conf +++ b/samples/shields/x_nucleo_iks01a3/standard/prj.conf @@ -11,3 +11,7 @@ CONFIG_LIS2DW12_TRIGGER_OWN_THREAD=y CONFIG_LSM6DSO_ENABLE_TEMP=n CONFIG_LSM6DSO_TRIGGER_OWN_THREAD=y CONFIG_CBPRINTF_FP_SUPPORT=y + +# DIL24 section +CONFIG_LIS2DE12_ENABLE_TEMP=y +CONFIG_LIS2DE12_TRIGGER_NONE=y diff --git a/samples/shields/x_nucleo_iks01a3/standard/src/main.c b/samples/shields/x_nucleo_iks01a3/standard/src/main.c index 7520d74d599..023b7eab76e 100644 --- a/samples/shields/x_nucleo_iks01a3/standard/src/main.c +++ b/samples/shields/x_nucleo_iks01a3/standard/src/main.c @@ -80,6 +80,17 @@ static void lsm6dso_temp_trig_handler(const struct device *dev, } #endif +#ifdef CONFIG_LIS2DE12_TRIGGER +static int lis2de12_trig_cnt; + +static void lis2de12_trigger_handler(const struct device *dev, + const struct sensor_trigger *trig) +{ + sensor_sample_fetch_chan(dev, SENSOR_CHAN_ALL); + lis2de12_trig_cnt++; +} +#endif + static void lis2mdl_config(const struct device *lis2mdl) { struct sensor_value odr_attr; @@ -237,6 +248,37 @@ static void lsm6dso_config(const struct device *lsm6dso) #endif } +static void lis2de12_config(const struct device *lis2de12) +{ + struct sensor_value odr_attr, fs_attr; + + /* set LIS2DE12 accel/gyro sampling frequency to 100 Hz */ + odr_attr.val1 = 200; + odr_attr.val2 = 0; + + if (sensor_attr_set(lis2de12, SENSOR_CHAN_ACCEL_XYZ, + SENSOR_ATTR_SAMPLING_FREQUENCY, &odr_attr) < 0) { + printk("Cannot set sampling frequency for LIS2DE12 accel\n"); + return; + } + + sensor_g_to_ms2(2, &fs_attr); + + if (sensor_attr_set(lis2de12, SENSOR_CHAN_ACCEL_XYZ, + SENSOR_ATTR_FULL_SCALE, &fs_attr) < 0) { + printk("Cannot set sampling frequency for LIS2DE12 gyro\n"); + return; + } + +#ifdef CONFIG_LIS2DE12_TRIGGER + struct sensor_trigger trig; + + trig.type = SENSOR_TRIG_DATA_READY; + trig.chan = SENSOR_CHAN_ACCEL_XYZ; + sensor_trigger_set(lis2de12, &trig, lis2de12_trigger_handler); +#endif +} + int main(void) { struct sensor_value temp1, temp2, temp3, hum, press; @@ -247,13 +289,21 @@ int main(void) struct sensor_value accel1[3], accel2[3]; struct sensor_value gyro[3]; struct sensor_value magn[3]; + struct sensor_value lis2de12_xl[3]; +#ifdef CONFIG_LIS2DE12_ENABLE_TEMP + struct sensor_value lis2de12_die_temp; +#endif const struct device *const hts221 = DEVICE_DT_GET_ONE(st_hts221); const struct device *const lps22hh = DEVICE_DT_GET_ONE(st_lps22hh); const struct device *const stts751 = DEVICE_DT_GET_ONE(st_stts751); const struct device *const lis2mdl = DEVICE_DT_GET_ONE(st_lis2mdl); const struct device *const lis2dw12 = DEVICE_DT_GET_ONE(st_lis2dw12); const struct device *const lsm6dso = DEVICE_DT_GET_ONE(st_lsm6dso); + + /* on DIL24 */ + const struct device *const lis2de12 = DEVICE_DT_GET_ANY(st_lis2de12); int cnt = 1; + int lis2de12_on_dil24 = 0; if (!device_is_ready(hts221)) { printk("%s: device not ready.\n", hts221->name); @@ -279,12 +329,20 @@ int main(void) printk("%s: device not ready.\n", lsm6dso->name); return 0; } + if (device_is_ready(lis2de12)) { + lis2de12_on_dil24 = 1; + } else { + printf("Device %s is not ready\n", lis2de12->name); + /* no device on DIL24, skip it */ + } lis2mdl_config(lis2mdl); lps22hh_config(lps22hh); stts751_config(stts751); lis2dw12_config(lis2dw12); lsm6dso_config(lsm6dso); + if (lis2de12_on_dil24) + lis2de12_config(lis2de12); while (1) { /* Get sensor samples */ @@ -323,6 +381,14 @@ int main(void) return 0; } #endif +#ifndef CONFIG_LIS2DE12_TRIGGER + if (lis2de12_on_dil24) { + if (sensor_sample_fetch(lis2de12) < 0) { + printf("LIS2DE12 Sensor sample update error\n"); + return 0; + } + } +#endif /* Get sensor data */ @@ -339,6 +405,12 @@ int main(void) #ifdef CONFIG_LSM6DSO_ENABLE_TEMP sensor_channel_get(lsm6dso, SENSOR_CHAN_DIE_TEMP, &die_temp); #endif + if (lis2de12_on_dil24) { + sensor_channel_get(lis2de12, SENSOR_CHAN_ACCEL_XYZ, lis2de12_xl); +#ifdef CONFIG_LIS2DE12_ENABLE_TEMP + sensor_channel_get(lis2de12, SENSOR_CHAN_DIE_TEMP, &lis2de12_die_temp); +#endif + } /* Display sensor data */ @@ -396,6 +468,18 @@ int main(void) printf("LSM6DSO: Temperature: %.1f C\n", sensor_value_to_double(&die_temp)); #endif + if (lis2de12_on_dil24) { + printf("LIS2DE12: Accel (m.s-2): x: %.3f, y: %.3f, z: %.3f\n", + sensor_value_to_double(&lis2de12_xl[0]), + sensor_value_to_double(&lis2de12_xl[1]), + sensor_value_to_double(&lis2de12_xl[2])); + +#ifdef CONFIG_LIS2DE12_ENABLE_TEMP + /* temperature */ + printf("LIS2DE12: Temperature: %.1f C\n", + sensor_value_to_double(&lis2de12_die_temp)); +#endif + } #if defined(CONFIG_LIS2MDL_TRIGGER) printk("%d:: lis2mdl trig %d\n", cnt, lis2mdl_trig_cnt); @@ -419,6 +503,9 @@ int main(void) printk("%d:: lsm6dso temp trig %d\n", cnt, lsm6dso_temp_trig_cnt); #endif +#ifdef CONFIG_LIS2DE12_TRIGGER + printk("%d:: lis2de12 acc trig %d\n", cnt, lis2de12_trig_cnt); +#endif cnt++; k_sleep(K_MSEC(2000)); From 4521c8ec2be522953ef676e8b1ec01b95ae88ed3 Mon Sep 17 00:00:00 2001 From: Dominik Ermel Date: Wed, 24 Jan 2024 15:24:05 +0000 Subject: [PATCH 3213/3723] storage/flash_map: Retire macros deprecated in release 3.2 The commit removes macros: - FLASH_AREA_LABEL_EXISTS() - FLASH_AREA_LABEL_STR() - FLASH_AREA_ID() - FLASH_AREA_OFFSET() - FLASH_AREA_SIZE() That have been marked deprecated in release 3.2, by commit: 54db76b4cd23 storage/flash_map: Deprecate FLASH_AREA_ macros Signed-off-by: Dominik Ermel --- include/zephyr/storage/flash_map.h | 17 +---------------- 1 file changed, 1 insertion(+), 16 deletions(-) diff --git a/include/zephyr/storage/flash_map.h b/include/zephyr/storage/flash_map.h index 380e58691e9..12f4f4c34a2 100644 --- a/include/zephyr/storage/flash_map.h +++ b/include/zephyr/storage/flash_map.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2017 Nordic Semiconductor ASA + * Copyright (c) 2017-2024 Nordic Semiconductor ASA * Copyright (c) 2015 Runtime Inc * Copyright (c) 2023 Sensorfy B.V. * @@ -271,21 +271,6 @@ const char *flash_area_label(const struct flash_area *fa); */ uint8_t flash_area_erased_val(const struct flash_area *fa); -#define FLASH_AREA_LABEL_EXISTS(label) __DEPRECATED_MACRO \ - DT_HAS_FIXED_PARTITION_LABEL(label) - -#define FLASH_AREA_LABEL_STR(lbl) __DEPRECATED_MACRO \ - DT_PROP(DT_NODE_BY_FIXED_PARTITION_LABEL(lbl), label) - -#define FLASH_AREA_ID(label) __DEPRECATED_MACRO \ - DT_FIXED_PARTITION_ID(DT_NODE_BY_FIXED_PARTITION_LABEL(label)) - -#define FLASH_AREA_OFFSET(label) __DEPRECATED_MACRO \ - DT_REG_ADDR(DT_NODE_BY_FIXED_PARTITION_LABEL(label)) - -#define FLASH_AREA_SIZE(label) __DEPRECATED_MACRO \ - DT_REG_SIZE(DT_NODE_BY_FIXED_PARTITION_LABEL(label)) - /** * Returns non-0 value if fixed-partition of given DTS node label exists. * From d30265b2cfca636d16b231d263d431001fe2740a Mon Sep 17 00:00:00 2001 From: Dominik Ermel Date: Wed, 24 Jan 2024 15:36:58 +0000 Subject: [PATCH 3214/3723] doc/release: Add note on removed Flash Map API macros Note on removal of deprecated Flash Map API macros: - FLASH_AREA_LABEL_EXISTS() - FLASH_AREA_LABEL_STR() - FLASH_AREA_ID() - FLASH_AREA_OFFSET() - FLASH_AREA_SIZE() Signed-off-by: Dominik Ermel --- doc/releases/release-notes-3.6.rst | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/doc/releases/release-notes-3.6.rst b/doc/releases/release-notes-3.6.rst index e317bd1049e..243a56a4179 100644 --- a/doc/releases/release-notes-3.6.rst +++ b/doc/releases/release-notes-3.6.rst @@ -397,6 +397,10 @@ Libraries / Subsystems * File systems: LittleFS module has been updated to version 2.8.1. + * Following Flash Map API macros, marked in 3.2 as deprecated, have been removed: + ``FLASH_AREA_ID``, ``FLASH_AREA_OFFSET``, ``FLASH_AREA_SIZE``, + ``FLASH_AREA_LABEL_EXISTS`` and ``FLASH_AREA_DEVICE``. + * Binary descriptors * POSIX API From eb78b719148016a0852f0d43163663cd24330baa Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andrzej=20G=C5=82=C4=85bek?= Date: Tue, 9 Jan 2024 16:16:27 +0100 Subject: [PATCH 3215/3723] soc: arm: nordic_nrf: Clean up and unify a bit cmake code MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Consistently use `zephyr_library*` cmake functions for all nRF Series and set the Cortex-M linker script in a common place for all of them. Remove no longer needed include directories. Signed-off-by: Andrzej Głąbek --- soc/arm/nordic_nrf/CMakeLists.txt | 4 +++- soc/arm/nordic_nrf/common/CMakeLists.txt | 5 ++++- soc/arm/nordic_nrf/nrf51/CMakeLists.txt | 13 +------------ soc/arm/nordic_nrf/nrf52/CMakeLists.txt | 13 +------------ soc/arm/nordic_nrf/nrf53/CMakeLists.txt | 10 ++-------- soc/arm/nordic_nrf/nrf54l/CMakeLists.txt | 4 +--- soc/arm/nordic_nrf/nrf91/CMakeLists.txt | 6 +----- 7 files changed, 13 insertions(+), 42 deletions(-) diff --git a/soc/arm/nordic_nrf/CMakeLists.txt b/soc/arm/nordic_nrf/CMakeLists.txt index 3b097d73569..bd7725404b8 100644 --- a/soc/arm/nordic_nrf/CMakeLists.txt +++ b/soc/arm/nordic_nrf/CMakeLists.txt @@ -1,9 +1,11 @@ # SPDX-License-Identifier: Apache-2.0 +zephyr_library() + add_subdirectory(${SOC_SERIES}) add_subdirectory(common) -zephyr_sources( +zephyr_library_sources( validate_base_addresses.c validate_enabled_instances.c ) diff --git a/soc/arm/nordic_nrf/common/CMakeLists.txt b/soc/arm/nordic_nrf/common/CMakeLists.txt index 1c12813f2c3..ea05f3d369e 100644 --- a/soc/arm/nordic_nrf/common/CMakeLists.txt +++ b/soc/arm/nordic_nrf/common/CMakeLists.txt @@ -3,10 +3,13 @@ zephyr_library_sources_ifdef(CONFIG_SOC_FAMILY_NRF soc_nrf_common.S) zephyr_library_sources_ifdef(CONFIG_POWEROFF poweroff.c) + zephyr_include_directories(.) +set(SOC_LINKER_SCRIPT ${ZEPHYR_BASE}/include/zephyr/arch/arm/cortex_m/scripts/linker.ld CACHE INTERNAL "") + if (CONFIG_TFM_PARTITION_PLATFORM) - zephyr_sources(soc_secure.c) + zephyr_library_sources(soc_secure.c) zephyr_library_include_directories( $/api_ns/interface/include ) diff --git a/soc/arm/nordic_nrf/nrf51/CMakeLists.txt b/soc/arm/nordic_nrf/nrf51/CMakeLists.txt index 44d139e422a..35d47fb252b 100644 --- a/soc/arm/nordic_nrf/nrf51/CMakeLists.txt +++ b/soc/arm/nordic_nrf/nrf51/CMakeLists.txt @@ -1,14 +1,3 @@ # SPDX-License-Identifier: Apache-2.0 -zephyr_library() - -zephyr_library_sources( - soc.c - ) - -zephyr_library_include_directories( - ${ZEPHYR_BASE}/kernel/include - ${ZEPHYR_BASE}/arch/arm/include - ) - -set(SOC_LINKER_SCRIPT ${ZEPHYR_BASE}/include/zephyr/arch/arm/cortex_m/scripts/linker.ld CACHE INTERNAL "") +zephyr_library_sources(soc.c) diff --git a/soc/arm/nordic_nrf/nrf52/CMakeLists.txt b/soc/arm/nordic_nrf/nrf52/CMakeLists.txt index 04e255a3eb1..1b7d4d5257a 100644 --- a/soc/arm/nordic_nrf/nrf52/CMakeLists.txt +++ b/soc/arm/nordic_nrf/nrf52/CMakeLists.txt @@ -1,15 +1,6 @@ # SPDX-License-Identifier: Apache-2.0 -zephyr_library() - -zephyr_library_sources( - soc.c - ) - -zephyr_library_include_directories( - ${ZEPHYR_BASE}/kernel/include - ${ZEPHYR_BASE}/arch/arm/include - ) +zephyr_library_sources(soc.c) if(CONFIG_SOC_NRF52832_ALLOW_SPIM_DESPITE_PAN_58 AND CONFIG_SPI_NRFX_SPIM) message(WARNING "Both SOC_NRF52832_ALLOW_SPIM_DESPITE_PAN_58 and an NRF SPIM driver are enabled, therefore PAN 58 will apply if RXD.MAXCNT == 1 and TXD.MAXCNT <= 1") @@ -22,5 +13,3 @@ if(CONFIG_SOC_NRF52832) endif() endif() endif() - -set(SOC_LINKER_SCRIPT ${ZEPHYR_BASE}/include/zephyr/arch/arm/cortex_m/scripts/linker.ld CACHE INTERNAL "") diff --git a/soc/arm/nordic_nrf/nrf53/CMakeLists.txt b/soc/arm/nordic_nrf/nrf53/CMakeLists.txt index b4e82f52c28..be275df68f5 100644 --- a/soc/arm/nordic_nrf/nrf53/CMakeLists.txt +++ b/soc/arm/nordic_nrf/nrf53/CMakeLists.txt @@ -1,12 +1,8 @@ # SPDX-License-Identifier: Apache-2.0 -zephyr_sources( - soc.c - ) +zephyr_library_sources(soc.c) -zephyr_library_sources_ifdef(CONFIG_NRF53_SYNC_RTC - sync_rtc.c - ) +zephyr_library_sources_ifdef(CONFIG_NRF53_SYNC_RTC sync_rtc.c) if (CONFIG_SOC_NRF53_ANOMALY_160_WORKAROUND_NEEDED AND NOT CONFIG_SYS_CLOCK_EXISTS) @@ -19,5 +15,3 @@ if (CONFIG_SOC_NRF53_ANOMALY_160_WORKAROUND_NEEDED AND At your own risk, you can suppress this warning by setting CONFIG_SOC_NRF53_ANOMALY_160_WORKAROUND_NEEDED=n.") endif() - -set(SOC_LINKER_SCRIPT ${ZEPHYR_BASE}/include/zephyr/arch/arm/cortex_m/scripts/linker.ld CACHE INTERNAL "") diff --git a/soc/arm/nordic_nrf/nrf54l/CMakeLists.txt b/soc/arm/nordic_nrf/nrf54l/CMakeLists.txt index 914aad289ef..33036acce8f 100644 --- a/soc/arm/nordic_nrf/nrf54l/CMakeLists.txt +++ b/soc/arm/nordic_nrf/nrf54l/CMakeLists.txt @@ -1,12 +1,10 @@ # Copyright (c) 2024 Nordic Semiconductor ASA # SPDX-License-Identifier: Apache-2.0 -zephyr_sources( +zephyr_library_sources( soc.c ../validate_rram_partitions.c) -set(SOC_LINKER_SCRIPT ${ZEPHYR_BASE}/include/zephyr/arch/arm/cortex_m/scripts/linker.ld CACHE INTERNAL "") - if (CONFIG_ELV_GRTC_LFXO_ALLOWED) message(WARNING "WARNING! ELV mode feature is EXPERIMENTAL and may brick your device!") endif() diff --git a/soc/arm/nordic_nrf/nrf91/CMakeLists.txt b/soc/arm/nordic_nrf/nrf91/CMakeLists.txt index 7424bb9f7b9..35d47fb252b 100644 --- a/soc/arm/nordic_nrf/nrf91/CMakeLists.txt +++ b/soc/arm/nordic_nrf/nrf91/CMakeLists.txt @@ -1,7 +1,3 @@ # SPDX-License-Identifier: Apache-2.0 -zephyr_sources( - soc.c - ) - -set(SOC_LINKER_SCRIPT ${ZEPHYR_BASE}/include/zephyr/arch/arm/cortex_m/scripts/linker.ld CACHE INTERNAL "") +zephyr_library_sources(soc.c) From eb5ce8bfe0d9f4c269cb054a18bbefc7110035bb Mon Sep 17 00:00:00 2001 From: Vinayak Kariappa Chettimada Date: Fri, 26 Jan 2024 13:41:48 +0100 Subject: [PATCH 3216/3723] Bluetooth: Controller: Fix RXFIFO_DEFINE to reduce FLASH usage Fix RXFIFO_DEFINE to reduce FLASH usage by moving the pool outside the struct that is static initialized. Signed-off-by: Vinayak Kariappa Chettimada --- .../bluetooth/controller/ll_sw/ull_internal.h | 21 +++++++++++-------- subsys/bluetooth/controller/ll_sw/ull_iso.c | 4 ++-- 2 files changed, 14 insertions(+), 11 deletions(-) diff --git a/subsys/bluetooth/controller/ll_sw/ull_internal.h b/subsys/bluetooth/controller/ll_sw/ull_internal.h index a0f6b7a6a0d..9e634757e9d 100644 --- a/subsys/bluetooth/controller/ll_sw/ull_internal.h +++ b/subsys/bluetooth/controller/ll_sw/ull_internal.h @@ -107,19 +107,21 @@ void ull_drift_ticks_get(struct node_rx_event_done *done, #define RXFIFO_DEFINE(_name, _size, _count, _extra_links) \ MFIFO_DEFINE(_name, sizeof(void *), _count); \ \ - static struct { \ - void *free; \ + static const struct { \ uint16_t size; \ uint8_t count; \ uint8_t extra_links; \ - uint8_t pool[MROUND(_size) * (_count)]; \ } mem_##_name = { .size = MROUND(_size), .count = _count, \ .extra_links = _extra_links }; \ \ static struct { \ void *free; \ - uint8_t pool[sizeof(memq_link_t) * \ - (_count + _extra_links)]; \ + uint8_t pool[MROUND(_size) * (_count)]; \ + } mem_pool_##_name; \ + \ + static struct { \ + void *free; \ + uint8_t pool[sizeof(memq_link_t) * (_count + _extra_links)]; \ } mem_link_##_name /** @@ -129,8 +131,8 @@ void ull_drift_ticks_get(struct node_rx_event_done *done, */ #define RXFIFO_INIT(_name) \ MFIFO_INIT(_name); \ - mem_init(mem_##_name.pool, mem_##_name.size, \ - mem_##_name.count, &mem_##_name.free); \ + mem_init(mem_pool_##_name.pool, mem_##_name.size, \ + mem_##_name.count, &mem_pool_##_name.free); \ \ mem_init(mem_link_##_name.pool, sizeof(memq_link_t), mem_##_name.count + \ mem_##_name.extra_links, &mem_link_##_name.free) @@ -142,8 +144,9 @@ void ull_drift_ticks_get(struct node_rx_event_done *done, */ #define RXFIFO_ALLOC(_name, _count) \ ull_rxfifo_alloc(mfifo_##_name.s, mfifo_##_name.n, mfifo_##_name.f, \ - &mfifo_##_name.l, mfifo_##_name.m, &mem_##_name.free, \ - &mem_link_##_name.free, _count) + &mfifo_##_name.l, mfifo_##_name.m, \ + &mem_pool_##_name.free, &mem_link_##_name.free, \ + _count) /** * @brief Initialize and allocate MFIFO and pools diff --git a/subsys/bluetooth/controller/ll_sw/ull_iso.c b/subsys/bluetooth/controller/ll_sw/ull_iso.c index b21a9d20721..440777c78b8 100644 --- a/subsys/bluetooth/controller/ll_sw/ull_iso.c +++ b/subsys/bluetooth/controller/ll_sw/ull_iso.c @@ -1543,7 +1543,7 @@ void *ll_iso_rx_get(void) (void)memq_dequeue(memq_ll_iso_rx.tail, &memq_ll_iso_rx.head, NULL); mem_release(link, &mem_link_iso_rx.free); - mem_release(rx, &mem_iso_rx.free); + mem_release(rx, &mem_pool_iso_rx.free); RXFIFO_ALLOC(iso_rx, 1); link = memq_peek(memq_ll_iso_rx.head, memq_ll_iso_rx.tail, (void **)&rx); @@ -1589,7 +1589,7 @@ void ll_iso_rx_mem_release(void **node_rx) switch (rx_free->type) { case NODE_RX_TYPE_ISO_PDU: - mem_release(rx_free, &mem_iso_rx.free); + mem_release(rx_free, &mem_pool_iso_rx.free); break; default: /* Ignore other types as node may have been initialized due to From e3357ef271632b03230b5d1e8cc8652118b0fcdb Mon Sep 17 00:00:00 2001 From: Vinayak Kariappa Chettimada Date: Fri, 26 Jan 2024 14:05:48 +0100 Subject: [PATCH 3217/3723] Bluetooth: Controller: Minor indentation of RXFIFO_DEFINE Minor indentation of RXFIFO_DEFINE. Signed-off-by: Vinayak Kariappa Chettimada --- subsys/bluetooth/controller/ll_sw/ull_internal.h | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/subsys/bluetooth/controller/ll_sw/ull_internal.h b/subsys/bluetooth/controller/ll_sw/ull_internal.h index 9e634757e9d..02d078e93cf 100644 --- a/subsys/bluetooth/controller/ll_sw/ull_internal.h +++ b/subsys/bluetooth/controller/ll_sw/ull_internal.h @@ -134,8 +134,9 @@ void ull_drift_ticks_get(struct node_rx_event_done *done, mem_init(mem_pool_##_name.pool, mem_##_name.size, \ mem_##_name.count, &mem_pool_##_name.free); \ \ - mem_init(mem_link_##_name.pool, sizeof(memq_link_t), mem_##_name.count + \ - mem_##_name.extra_links, &mem_link_##_name.free) + mem_init(mem_link_##_name.pool, sizeof(memq_link_t), \ + (mem_##_name.count + mem_##_name.extra_links), \ + &mem_link_##_name.free) /** * @brief Allocate FIFO elements with backing From 354527f17babbd01d4e8bb4e5f049eebd890e68f Mon Sep 17 00:00:00 2001 From: Fabio Baltieri Date: Tue, 30 Jan 2024 17:28:54 +0000 Subject: [PATCH 3218/3723] MAINTAINERS: drop few "area: Sensors" from modules Few west areas are paired with the sensor labels right now, this causes the issue assignee workflow to assign sensor issues to the maintainers of these areas as well. Drop those areas from the maintainer file, they should get some different label if needed. Signed-off-by: Fabio Baltieri --- MAINTAINERS.yml | 6 ------ 1 file changed, 6 deletions(-) diff --git a/MAINTAINERS.yml b/MAINTAINERS.yml index d025cff00b8..b74c77f30b3 100644 --- a/MAINTAINERS.yml +++ b/MAINTAINERS.yml @@ -4188,8 +4188,6 @@ West: - erwango files: - modules/hal_st/Kconfig - labels: - - "area: Sensors" "West project: hal_stm32": status: maintained @@ -4228,8 +4226,6 @@ West: - mah-eiSmart files: - modules/Kconfig.wurthelektronik - labels: - - "area: Sensors" "West project: hal_xtensa": status: maintained @@ -4548,8 +4544,6 @@ West: maintainers: - microbuilder files: [] - labels: - - "area: Sensors" "West project: hostap": status: maintained From 6fc6b30fb38a9ba355dd278f3568df3d11ba7b07 Mon Sep 17 00:00:00 2001 From: Manuel Schappacher Date: Wed, 31 Jan 2024 09:13:51 +0100 Subject: [PATCH 3219/3723] net: gptp: Fix double converted byte order of BMCA info steps_removed Fixes #68320 Signed-off-by: Manuel Schappacher --- subsys/net/l2/ethernet/gptp/gptp_mi.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/subsys/net/l2/ethernet/gptp/gptp_mi.c b/subsys/net/l2/ethernet/gptp/gptp_mi.c index b081ab24003..03c8ee3ef0c 100644 --- a/subsys/net/l2/ethernet/gptp/gptp_mi.c +++ b/subsys/net/l2/ethernet/gptp/gptp_mi.c @@ -1701,7 +1701,7 @@ static int compute_best_vector(void) } global_ds->gm_priority.steps_removed = - htons(ntohs(best_vector->steps_removed) + 1); + ntohs(best_vector->steps_removed) + 1; if (&global_ds->gm_priority.src_port_id != &best_vector->src_port_id) { From 027549b82459c4c9f028dea862fba289b8230f30 Mon Sep 17 00:00:00 2001 From: Daniel DeGrasse Date: Fri, 27 Oct 2023 22:29:32 +0000 Subject: [PATCH 3220/3723] include: drivers: mipi_dsi: split MIPI DCS values into separate header Split MIPI DCS values into a separate header. This aligns with the way that Linux handles MIPI DCS values, since these are not specific to DSI hosts. Signed-off-by: Daniel DeGrasse --- include/zephyr/display/mipi_display.h | 163 ++++++++++++++++++++++++++ include/zephyr/drivers/mipi_dsi.h | 128 +------------------- 2 files changed, 164 insertions(+), 127 deletions(-) create mode 100644 include/zephyr/display/mipi_display.h diff --git a/include/zephyr/display/mipi_display.h b/include/zephyr/display/mipi_display.h new file mode 100644 index 00000000000..f369cb8de42 --- /dev/null +++ b/include/zephyr/display/mipi_display.h @@ -0,0 +1,163 @@ +/* + * Copyright 2023 NXP + * + * SPDX-License-Identifier: Apache-2.0 + */ + +/** + * @file + * @brief Display definitions for MIPI devices + */ + +#ifndef ZEPHYR_INCLUDE_DISPLAY_MIPI_DISPLAY_H_ +#define ZEPHYR_INCLUDE_DISPLAY_MIPI_DISPLAY_H_ + +/** + * @brief MIPI Display definitions + * @defgroup mipi_interface MIPI Display interface + * @ingroup io_interfaces + * @{ + */ + + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * @name MIPI-DSI DCS (Display Command Set) + * @{ + */ + +#define MIPI_DCS_NOP 0x00U +#define MIPI_DCS_SOFT_RESET 0x01U +#define MIPI_DCS_GET_COMPRESSION_MODE 0x03U +#define MIPI_DCS_GET_DISPLAY_ID 0x04U +#define MIPI_DCS_GET_RED_CHANNEL 0x06U +#define MIPI_DCS_GET_GREEN_CHANNEL 0x07U +#define MIPI_DCS_GET_BLUE_CHANNEL 0x08U +#define MIPI_DCS_GET_DISPLAY_STATUS 0x09U +#define MIPI_DCS_GET_POWER_MODE 0x0AU +#define MIPI_DCS_GET_ADDRESS_MODE 0x0BU +#define MIPI_DCS_GET_PIXEL_FORMAT 0x0CU +#define MIPI_DCS_GET_DISPLAY_MODE 0x0DU +#define MIPI_DCS_GET_SIGNAL_MODE 0x0EU +#define MIPI_DCS_GET_DIAGNOSTIC_RESULT 0x0FU +#define MIPI_DCS_ENTER_SLEEP_MODE 0x10U +#define MIPI_DCS_EXIT_SLEEP_MODE 0x11U +#define MIPI_DCS_ENTER_PARTIAL_MODE 0x12U +#define MIPI_DCS_ENTER_NORMAL_MODE 0x13U +#define MIPI_DCS_EXIT_INVERT_MODE 0x20U +#define MIPI_DCS_ENTER_INVERT_MODE 0x21U +#define MIPI_DCS_SET_GAMMA_CURVE 0x26U +#define MIPI_DCS_SET_DISPLAY_OFF 0x28U +#define MIPI_DCS_SET_DISPLAY_ON 0x29U +#define MIPI_DCS_SET_COLUMN_ADDRESS 0x2AU +#define MIPI_DCS_SET_PAGE_ADDRESS 0x2BU +#define MIPI_DCS_WRITE_MEMORY_START 0x2CU +#define MIPI_DCS_WRITE_LUT 0x2DU +#define MIPI_DCS_READ_MEMORY_START 0x2EU +#define MIPI_DCS_SET_PARTIAL_ROWS 0x30U +#define MIPI_DCS_SET_PARTIAL_COLUMNS 0x31U +#define MIPI_DCS_SET_SCROLL_AREA 0x33U +#define MIPI_DCS_SET_TEAR_OFF 0x34U +#define MIPI_DCS_SET_TEAR_ON 0x35U +#define MIPI_DCS_SET_ADDRESS_MODE 0x36U +#define MIPI_DCS_SET_SCROLL_START 0x37U +#define MIPI_DCS_EXIT_IDLE_MODE 0x38U +#define MIPI_DCS_ENTER_IDLE_MODE 0x39U +#define MIPI_DCS_SET_PIXEL_FORMAT 0x3AU +#define MIPI_DCS_WRITE_MEMORY_CONTINUE 0x3CU +#define MIPI_DCS_SET_3D_CONTROL 0x3DU +#define MIPI_DCS_READ_MEMORY_CONTINUE 0x3EU +#define MIPI_DCS_GET_3D_CONTROL 0x3FU +#define MIPI_DCS_SET_VSYNC_TIMING 0x40U +#define MIPI_DCS_SET_TEAR_SCANLINE 0x44U +#define MIPI_DCS_GET_SCANLINE 0x45U +#define MIPI_DCS_SET_DISPLAY_BRIGHTNESS 0x51U +#define MIPI_DCS_GET_DISPLAY_BRIGHTNESS 0x52U +#define MIPI_DCS_WRITE_CONTROL_DISPLAY 0x53U +#define MIPI_DCS_GET_CONTROL_DISPLAY 0x54U +#define MIPI_DCS_WRITE_POWER_SAVE 0x55U +#define MIPI_DCS_GET_POWER_SAVE 0x56U +#define MIPI_DCS_SET_CABC_MIN_BRIGHTNESS 0x5EU +#define MIPI_DCS_GET_CABC_MIN_BRIGHTNESS 0x5FU +#define MIPI_DCS_READ_DDB_START 0xA1U +#define MIPI_DCS_READ_DDB_CONTINUE 0xA8U + +#define MIPI_DCS_PIXEL_FORMAT_24BIT 0x77 +#define MIPI_DCS_PIXEL_FORMAT_18BIT 0x66 +#define MIPI_DCS_PIXEL_FORMAT_16BIT 0x55 +#define MIPI_DCS_PIXEL_FORMAT_12BIT 0x33 +#define MIPI_DCS_PIXEL_FORMAT_8BIT 0x22 +#define MIPI_DCS_PIXEL_FORMAT_3BIT 0x11 + +/** @} */ + +/** + * @name MIPI-DSI Address mode register fields. + * @{ + */ + +#define MIPI_DCS_ADDRESS_MODE_MIRROR_Y BIT(7) +#define MIPI_DCS_ADDRESS_MODE_MIRROR_X BIT(6) +#define MIPI_DCS_ADDRESS_MODE_SWAP_XY BIT(5) +#define MIPI_DCS_ADDRESS_MODE_REFRESH_BT BIT(4) +#define MIPI_DCS_ADDRESS_MODE_BGR BIT(3) +#define MIPI_DCS_ADDRESS_MODE_LATCH_RL BIT(2) +#define MIPI_DCS_ADDRESS_MODE_FLIP_X BIT(1) +#define MIPI_DCS_ADDRESS_MODE_FLIP_Y BIT(0) + +/** @} */ + +/** + * @name MIPI-DSI Processor-to-Peripheral transaction types. + * @{ + */ + +#define MIPI_DSI_V_SYNC_START 0x01U +#define MIPI_DSI_V_SYNC_END 0x11U +#define MIPI_DSI_H_SYNC_START 0x21U +#define MIPI_DSI_H_SYNC_END 0x31U +#define MIPI_DSI_COLOR_MODE_OFF 0x02U +#define MIPI_DSI_COLOR_MODE_ON 0x12U +#define MIPI_DSI_SHUTDOWN_PERIPHERAL 0x22U +#define MIPI_DSI_TURN_ON_PERIPHERAL 0x32U +#define MIPI_DSI_GENERIC_SHORT_WRITE_0_PARAM 0x03U +#define MIPI_DSI_GENERIC_SHORT_WRITE_1_PARAM 0x13U +#define MIPI_DSI_GENERIC_SHORT_WRITE_2_PARAM 0x23U +#define MIPI_DSI_GENERIC_READ_REQUEST_0_PARAM 0x04U +#define MIPI_DSI_GENERIC_READ_REQUEST_1_PARAM 0x14U +#define MIPI_DSI_GENERIC_READ_REQUEST_2_PARAM 0x24U +#define MIPI_DSI_DCS_SHORT_WRITE 0x05U +#define MIPI_DSI_DCS_SHORT_WRITE_PARAM 0x15U +#define MIPI_DSI_DCS_READ 0x06U +#define MIPI_DSI_SET_MAXIMUM_RETURN_PACKET_SIZE 0x37U +#define MIPI_DSI_END_OF_TRANSMISSION 0x08U +#define MIPI_DSI_NULL_PACKET 0x09U +#define MIPI_DSI_BLANKING_PACKET 0x19U +#define MIPI_DSI_GENERIC_LONG_WRITE 0x29U +#define MIPI_DSI_DCS_LONG_WRITE 0x39U +#define MIPI_DSI_LOOSELY_PACKED_PIXEL_STREAM_YCBCR20 0x0CU +#define MIPI_DSI_PACKED_PIXEL_STREAM_YCBCR24 0x1CU +#define MIPI_DSI_PACKED_PIXEL_STREAM_YCBCR16 0x2CU +#define MIPI_DSI_PACKED_PIXEL_STREAM_30 0x0DU +#define MIPI_DSI_PACKED_PIXEL_STREAM_36 0x1DU +#define MIPI_DSI_PACKED_PIXEL_STREAM_YCBCR12 0x3DU +#define MIPI_DSI_PACKED_PIXEL_STREAM_16 0x0EU +#define MIPI_DSI_PACKED_PIXEL_STREAM_18 0x1EU +#define MIPI_DSI_PIXEL_STREAM_3BYTE_18 0x2EU +#define MIPI_DSI_PACKED_PIXEL_STREAM_24 0x3EU + +/** @} */ + + +#ifdef __cplusplus +} +#endif + +/** + * @} + */ + +#endif /* ZEPHYR_INCLUDE_DISPLAY_MIPI_DISPLAY_H_ */ diff --git a/include/zephyr/drivers/mipi_dsi.h b/include/zephyr/drivers/mipi_dsi.h index e6ac1e0a787..f26a6928196 100644 --- a/include/zephyr/drivers/mipi_dsi.h +++ b/include/zephyr/drivers/mipi_dsi.h @@ -21,139 +21,13 @@ #include #include #include +#include #include #ifdef __cplusplus extern "C" { #endif -/** - * @name MIPI-DSI DCS (Display Command Set) - * @{ - */ - -#define MIPI_DCS_NOP 0x00U -#define MIPI_DCS_SOFT_RESET 0x01U -#define MIPI_DCS_GET_COMPRESSION_MODE 0x03U -#define MIPI_DCS_GET_DISPLAY_ID 0x04U -#define MIPI_DCS_GET_RED_CHANNEL 0x06U -#define MIPI_DCS_GET_GREEN_CHANNEL 0x07U -#define MIPI_DCS_GET_BLUE_CHANNEL 0x08U -#define MIPI_DCS_GET_DISPLAY_STATUS 0x09U -#define MIPI_DCS_GET_POWER_MODE 0x0AU -#define MIPI_DCS_GET_ADDRESS_MODE 0x0BU -#define MIPI_DCS_GET_PIXEL_FORMAT 0x0CU -#define MIPI_DCS_GET_DISPLAY_MODE 0x0DU -#define MIPI_DCS_GET_SIGNAL_MODE 0x0EU -#define MIPI_DCS_GET_DIAGNOSTIC_RESULT 0x0FU -#define MIPI_DCS_ENTER_SLEEP_MODE 0x10U -#define MIPI_DCS_EXIT_SLEEP_MODE 0x11U -#define MIPI_DCS_ENTER_PARTIAL_MODE 0x12U -#define MIPI_DCS_ENTER_NORMAL_MODE 0x13U -#define MIPI_DCS_EXIT_INVERT_MODE 0x20U -#define MIPI_DCS_ENTER_INVERT_MODE 0x21U -#define MIPI_DCS_SET_GAMMA_CURVE 0x26U -#define MIPI_DCS_SET_DISPLAY_OFF 0x28U -#define MIPI_DCS_SET_DISPLAY_ON 0x29U -#define MIPI_DCS_SET_COLUMN_ADDRESS 0x2AU -#define MIPI_DCS_SET_PAGE_ADDRESS 0x2BU -#define MIPI_DCS_WRITE_MEMORY_START 0x2CU -#define MIPI_DCS_WRITE_LUT 0x2DU -#define MIPI_DCS_READ_MEMORY_START 0x2EU -#define MIPI_DCS_SET_PARTIAL_ROWS 0x30U -#define MIPI_DCS_SET_PARTIAL_COLUMNS 0x31U -#define MIPI_DCS_SET_SCROLL_AREA 0x33U -#define MIPI_DCS_SET_TEAR_OFF 0x34U -#define MIPI_DCS_SET_TEAR_ON 0x35U -#define MIPI_DCS_SET_ADDRESS_MODE 0x36U -#define MIPI_DCS_SET_SCROLL_START 0x37U -#define MIPI_DCS_EXIT_IDLE_MODE 0x38U -#define MIPI_DCS_ENTER_IDLE_MODE 0x39U -#define MIPI_DCS_SET_PIXEL_FORMAT 0x3AU -#define MIPI_DCS_WRITE_MEMORY_CONTINUE 0x3CU -#define MIPI_DCS_SET_3D_CONTROL 0x3DU -#define MIPI_DCS_READ_MEMORY_CONTINUE 0x3EU -#define MIPI_DCS_GET_3D_CONTROL 0x3FU -#define MIPI_DCS_SET_VSYNC_TIMING 0x40U -#define MIPI_DCS_SET_TEAR_SCANLINE 0x44U -#define MIPI_DCS_GET_SCANLINE 0x45U -#define MIPI_DCS_SET_DISPLAY_BRIGHTNESS 0x51U -#define MIPI_DCS_GET_DISPLAY_BRIGHTNESS 0x52U -#define MIPI_DCS_WRITE_CONTROL_DISPLAY 0x53U -#define MIPI_DCS_GET_CONTROL_DISPLAY 0x54U -#define MIPI_DCS_WRITE_POWER_SAVE 0x55U -#define MIPI_DCS_GET_POWER_SAVE 0x56U -#define MIPI_DCS_SET_CABC_MIN_BRIGHTNESS 0x5EU -#define MIPI_DCS_GET_CABC_MIN_BRIGHTNESS 0x5FU -#define MIPI_DCS_READ_DDB_START 0xA1U -#define MIPI_DCS_READ_DDB_CONTINUE 0xA8U - -#define MIPI_DCS_PIXEL_FORMAT_24BIT 0x77 -#define MIPI_DCS_PIXEL_FORMAT_18BIT 0x66 -#define MIPI_DCS_PIXEL_FORMAT_16BIT 0x55 -#define MIPI_DCS_PIXEL_FORMAT_12BIT 0x33 -#define MIPI_DCS_PIXEL_FORMAT_8BIT 0x22 -#define MIPI_DCS_PIXEL_FORMAT_3BIT 0x11 - -/** @} */ - -/** - * @name MIPI-DSI Address mode register fields. - * @{ - */ - -#define MIPI_DCS_ADDRESS_MODE_MIRROR_Y BIT(7) -#define MIPI_DCS_ADDRESS_MODE_MIRROR_X BIT(6) -#define MIPI_DCS_ADDRESS_MODE_SWAP_XY BIT(5) -#define MIPI_DCS_ADDRESS_MODE_REFRESH_BT BIT(4) -#define MIPI_DCS_ADDRESS_MODE_BGR BIT(3) -#define MIPI_DCS_ADDRESS_MODE_LATCH_RL BIT(2) -#define MIPI_DCS_ADDRESS_MODE_FLIP_X BIT(1) -#define MIPI_DCS_ADDRESS_MODE_FLIP_Y BIT(0) - -/** @} */ - -/** - * @name MIPI-DSI Processor-to-Peripheral transaction types. - * @{ - */ - -#define MIPI_DSI_V_SYNC_START 0x01U -#define MIPI_DSI_V_SYNC_END 0x11U -#define MIPI_DSI_H_SYNC_START 0x21U -#define MIPI_DSI_H_SYNC_END 0x31U -#define MIPI_DSI_COLOR_MODE_OFF 0x02U -#define MIPI_DSI_COLOR_MODE_ON 0x12U -#define MIPI_DSI_SHUTDOWN_PERIPHERAL 0x22U -#define MIPI_DSI_TURN_ON_PERIPHERAL 0x32U -#define MIPI_DSI_GENERIC_SHORT_WRITE_0_PARAM 0x03U -#define MIPI_DSI_GENERIC_SHORT_WRITE_1_PARAM 0x13U -#define MIPI_DSI_GENERIC_SHORT_WRITE_2_PARAM 0x23U -#define MIPI_DSI_GENERIC_READ_REQUEST_0_PARAM 0x04U -#define MIPI_DSI_GENERIC_READ_REQUEST_1_PARAM 0x14U -#define MIPI_DSI_GENERIC_READ_REQUEST_2_PARAM 0x24U -#define MIPI_DSI_DCS_SHORT_WRITE 0x05U -#define MIPI_DSI_DCS_SHORT_WRITE_PARAM 0x15U -#define MIPI_DSI_DCS_READ 0x06U -#define MIPI_DSI_SET_MAXIMUM_RETURN_PACKET_SIZE 0x37U -#define MIPI_DSI_END_OF_TRANSMISSION 0x08U -#define MIPI_DSI_NULL_PACKET 0x09U -#define MIPI_DSI_BLANKING_PACKET 0x19U -#define MIPI_DSI_GENERIC_LONG_WRITE 0x29U -#define MIPI_DSI_DCS_LONG_WRITE 0x39U -#define MIPI_DSI_LOOSELY_PACKED_PIXEL_STREAM_YCBCR20 0x0CU -#define MIPI_DSI_PACKED_PIXEL_STREAM_YCBCR24 0x1CU -#define MIPI_DSI_PACKED_PIXEL_STREAM_YCBCR16 0x2CU -#define MIPI_DSI_PACKED_PIXEL_STREAM_30 0x0DU -#define MIPI_DSI_PACKED_PIXEL_STREAM_36 0x1DU -#define MIPI_DSI_PACKED_PIXEL_STREAM_YCBCR12 0x3DU -#define MIPI_DSI_PACKED_PIXEL_STREAM_16 0x0EU -#define MIPI_DSI_PACKED_PIXEL_STREAM_18 0x1EU -#define MIPI_DSI_PIXEL_STREAM_3BYTE_18 0x2EU -#define MIPI_DSI_PACKED_PIXEL_STREAM_24 0x3EU - -/** @} */ - /** MIPI-DSI display timings. */ struct mipi_dsi_timings { /** Horizontal active video. */ From 3ab65728561bf57ea7fd10a31cd45a51a9d870a4 Mon Sep 17 00:00:00 2001 From: Daniel DeGrasse Date: Fri, 27 Oct 2023 22:33:48 +0000 Subject: [PATCH 3221/3723] drivers: mipi_dbi: introduce MIPI DBI driver class Introduce MIPI DBI driver class. MIPI DBI devices encompass several interface types. All interfaces have a data/command, reset, chip select, and tearing effect signal Beyond this, MIPI DBI operates in 3 modes: Mode A- 16/8 data pins, one clock pin, one read/write pin. Similar to Motorola type 6800 bus Mode B- 16/8 data pins, one read/write pin. Similar to Intel 8080 bus Mode C- 1 data output pin, 1 data input pin, one clock pin. Implementable using SPI peripheral, or MIPI-DBI specific controller. Signed-off-by: Daniel DeGrasse --- MAINTAINERS.yml | 10 + drivers/CMakeLists.txt | 1 + drivers/Kconfig | 1 + drivers/mipi_dbi/CMakeLists.txt | 3 + drivers/mipi_dbi/Kconfig | 24 ++ .../mipi-dbi/mipi-dbi-controller.yaml | 20 ++ dts/bindings/mipi-dbi/mipi-dbi-device.yaml | 13 + .../mipi-dbi/mipi-dbi-spi-device.yaml | 36 +++ include/zephyr/drivers/mipi_dbi.h | 264 ++++++++++++++++++ 9 files changed, 372 insertions(+) create mode 100644 drivers/mipi_dbi/CMakeLists.txt create mode 100644 drivers/mipi_dbi/Kconfig create mode 100644 dts/bindings/mipi-dbi/mipi-dbi-controller.yaml create mode 100644 dts/bindings/mipi-dbi/mipi-dbi-device.yaml create mode 100644 dts/bindings/mipi-dbi/mipi-dbi-spi-device.yaml create mode 100644 include/zephyr/drivers/mipi_dbi.h diff --git a/MAINTAINERS.yml b/MAINTAINERS.yml index b74c77f30b3..1ef80d8f7c4 100644 --- a/MAINTAINERS.yml +++ b/MAINTAINERS.yml @@ -1952,6 +1952,16 @@ Release Notes: labels: - "area: Memory Management" +"Drivers: MIPI DBI": + status: maintained + maintainers: + - danieldegrasse + files: + - drivers/mipi_dbi/ + - dts/bindings/mipi-dbi/ + labels: + - "area: Display Controller" + "Drivers: Virtualization": status: maintained maintainers: diff --git a/drivers/CMakeLists.txt b/drivers/CMakeLists.txt index 6310146bb3d..f0236ef653a 100644 --- a/drivers/CMakeLists.txt +++ b/drivers/CMakeLists.txt @@ -56,6 +56,7 @@ add_subdirectory_ifdef(CONFIG_MBOX mbox) add_subdirectory_ifdef(CONFIG_MDIO mdio) add_subdirectory_ifdef(CONFIG_MEMC memc) add_subdirectory_ifdef(CONFIG_MFD mfd) +add_subdirectory_ifdef(CONFIG_MIPI_DBI mipi_dbi) add_subdirectory_ifdef(CONFIG_MIPI_DSI mipi_dsi) add_subdirectory_ifdef(CONFIG_MM_DRV mm) add_subdirectory_ifdef(CONFIG_MODEM modem) diff --git a/drivers/Kconfig b/drivers/Kconfig index 45b03e4829c..ac07add3c1f 100644 --- a/drivers/Kconfig +++ b/drivers/Kconfig @@ -52,6 +52,7 @@ source "drivers/mbox/Kconfig" source "drivers/mdio/Kconfig" source "drivers/memc/Kconfig" source "drivers/mfd/Kconfig" +source "drivers/mipi_dbi/Kconfig" source "drivers/mipi_dsi/Kconfig" source "drivers/misc/Kconfig" source "drivers/mm/Kconfig" diff --git a/drivers/mipi_dbi/CMakeLists.txt b/drivers/mipi_dbi/CMakeLists.txt new file mode 100644 index 00000000000..3a04db6a9ca --- /dev/null +++ b/drivers/mipi_dbi/CMakeLists.txt @@ -0,0 +1,3 @@ +# Copyright 2023 NXP +# +# SPDX-License-Identifier: Apache-2.0 diff --git a/drivers/mipi_dbi/Kconfig b/drivers/mipi_dbi/Kconfig new file mode 100644 index 00000000000..cc4e2344c64 --- /dev/null +++ b/drivers/mipi_dbi/Kconfig @@ -0,0 +1,24 @@ +# MIPI DBI controller options + +# Copyright 2023 NXP +# SPDX-License-Identifier: Apache-2.0 + +menuconfig MIPI_DBI + bool "MIPI-DBI Host Controller drivers [EXPERIMENTAL]" + select EXPERIMENTAL + help + Add support for MIPI-DBI compliant host controllers + +if MIPI_DBI + +module = MIPI_DBI +module-str = mipi_dbi +source "subsys/logging/Kconfig.template.log_config" + +config MIPI_DBI_INIT_PRIORITY + int "Initialization priority" + default 80 + help + MIPI-DBI Host Controllers initialization priority. + +endif diff --git a/dts/bindings/mipi-dbi/mipi-dbi-controller.yaml b/dts/bindings/mipi-dbi/mipi-dbi-controller.yaml new file mode 100644 index 00000000000..64425b5d914 --- /dev/null +++ b/dts/bindings/mipi-dbi/mipi-dbi-controller.yaml @@ -0,0 +1,20 @@ +# Copyright 2023 NXP +# SPDX-License-Identifier: Apache-2.0 + +# Common fields for MIPI-DBI controllers + +include: base.yaml + +bus: mipi-dbi + +properties: + clock-frequency: + type: int + description: | + Clock frequency of the SCL signal of the MBI-DBI peripheral, in Hz + "#address-cells": + required: true + const: 1 + "#size-cells": + required: true + const: 0 diff --git a/dts/bindings/mipi-dbi/mipi-dbi-device.yaml b/dts/bindings/mipi-dbi/mipi-dbi-device.yaml new file mode 100644 index 00000000000..a24ce07bb48 --- /dev/null +++ b/dts/bindings/mipi-dbi/mipi-dbi-device.yaml @@ -0,0 +1,13 @@ +# Copyright 2023 NXP +# SPDX-License-Identifier: Apache-2.0 +# +# Common fields for MIPI-DBI devices + +include: [base.yaml, power.yaml] + +on-bus: mipi-dbi + +properties: + mipi-max-frequency: + type: int + description: Maximum clock frequency of device's MIPI interface in Hz diff --git a/dts/bindings/mipi-dbi/mipi-dbi-spi-device.yaml b/dts/bindings/mipi-dbi/mipi-dbi-spi-device.yaml new file mode 100644 index 00000000000..2b8465a2667 --- /dev/null +++ b/dts/bindings/mipi-dbi/mipi-dbi-spi-device.yaml @@ -0,0 +1,36 @@ +# Copyright 2023 NXP +# SPDX-License-Identifier: Apache-2.0 +# +# Common fields for MIPI DBI devices using Mode C (SPI) + +include: [mipi-dbi-device.yaml] + +properties: + duplex: + type: int + default: 0 + description: | + SPI Duplex mode, full or half. By default it's always full duplex thus 0 + as this is, by far, the most common mode. + Use the macros not the actual enum value, here is the concordance + list (see dt-bindings/spi/spi.h) + 0 SPI_FULL_DUPLEX + 2048 SPI_HALF_DUPLEX + mipi-cpol: + type: boolean + description: | + SPI clock polarity which indicates the clock idle state. + If it is used, the clock idle state is logic high; otherwise, low. + mipi-cpha: + type: boolean + description: | + SPI clock phase that indicates on which edge data is sampled. + If it is used, data is sampled on the second edge; otherwise, on the first edge. + mipi-hold-cs: + type: boolean + description: | + In some cases, it is necessary for the master to manage SPI chip select + under software control, so that multiple spi transactions can be performed + without releasing it. A typical use case is variable length SPI packets + where the first spi transaction reads the length and the second spi transaction + reads length bytes. diff --git a/include/zephyr/drivers/mipi_dbi.h b/include/zephyr/drivers/mipi_dbi.h new file mode 100644 index 00000000000..4cd69845bff --- /dev/null +++ b/include/zephyr/drivers/mipi_dbi.h @@ -0,0 +1,264 @@ +/* + * Copyright 2023 NXP + * + * SPDX-License-Identifier: Apache-2.0 + */ + +/** + * @file + * @brief Public APIs for MIPI-DBI drivers + * + * MIPI-DBI defines the following 3 interfaces: + * Type A: Motorola 6800 type parallel bus + * Type B: Intel 8080 type parallel bus + * Type C: SPI Type (1 bit bus) with 3 options: + * 1. 9 write clocks per byte, final bit is command/data selection bit + * 2. Same as above, but 16 write clocks per byte + * 3. 8 write clocks per byte. Command/data selected via GPIO pin + * The current driver interface only supports type C modes 1 and 3 + */ + +#ifndef ZEPHYR_INCLUDE_DRIVERS_MIPI_DBI_H_ +#define ZEPHYR_INCLUDE_DRIVERS_MIPI_DBI_H_ + +/** + * @brief MIPI-DBI driver APIs + * @defgroup mipi_dbi_interface MIPI-DBI driver APIs + * @ingroup io_interfaces + * @{ + */ + +#include +#include +#include +#include + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * SPI 3 wire (Type C1). Uses 9 write clocks to send a byte of data. + * The bit sent on the 9th clock indicates whether the byte is a + * command or data byte + * + * + * .---. .---. .---. .---. .---. .---. .---. .---. + * SCK -' '---' '---' '---' '---' '---' '---' '---' '--- + * + * -.---.---.---.---.---.---.---.---.---.---.---.---.---.---.---. + * DOUT |D/C| D7| D6| D5| D4| D3| D2| D1| D0|D/C| D7| D6| D5| D4|...| + * -'---'---'---'---'---'---'---'---'---'---'---'---'---'---'---' + * | Word 1 | Word n + * + * -. .-- + * CS '-----------------------------------------------------------' + */ +#define MIPI_DBI_MODE_SPI_3WIRE 0x1 +/** + * SPI 4 wire (Type C3). Uses 8 write clocks to send a byte of data. + * an additional C/D pin will be use to indicate whether the byte is a + * command or data byte + * + * .---. .---. .---. .---. .---. .---. .---. .---. + * SCK -' '---' '---' '---' '---' '---' '---' '---' '--- + * + * -.---.---.---.---.---.---.---.---.---.---.---.---.---.---.---.---. + * DOUT | D7| D6| D5| D4| D3| D2| D1| D0| D7| D6| D5| D4| D3| D2| D1| D0| + * -'---'---'---'---'---'---'---'---'---'---'---'---'---'---'---'---' + * | Word 1 | Word n + * + * -. .-- + * CS '---------------------------------------------------------------' + * + * -.-------------------------------.-------------------------------.- + * CD | D/C | D/C | + * -'-------------------------------'-------------------------------'- + */ +#define MIPI_DBI_MODE_SPI_4WIRE 0x2 + +/** + * @brief initialize a MIPI DBI SPI configuration struct from devicetree + * + * This helper allows drivers to initialize a MIPI DBI SPI configuration + * structure using devicetree. + * @param node_id Devicetree node identifier for the MIPI DBI device whose + * struct spi_config to create an initializer for + * @param operation_ the desired operation field in the struct spi_config + * @param delay_ the desired delay field in the struct spi_config's + * spi_cs_control, if there is one + */ +#define MIPI_DBI_SPI_CONFIG_DT(node_id, operation_, delay_) \ + { \ + .frequency = DT_PROP(node_id, mipi_max_frequency), \ + .operation = (operation_) | \ + DT_PROP(node_id, duplex), \ + COND_CODE_1(DT_PROP(node_id, mipi_cpol), SPI_MODE_CPOL, (0)) | \ + COND_CODE_1(DT_PROP(node_id, mipi_cpha), SPI_MODE_CPHA, (0)) | \ + COND_CODE_1(DT_PROP(node_id, mipi_hold_cs), SPI_HOLD_ON_CS, (0)), \ + .slave = DT_REG_ADDR(node_id), \ + .cs = { \ + .gpio = GPIO_DT_SPEC_GET_BY_IDX_OR(DT_PHANDLE(DT_PARENT(node_id), \ + spi_dev), cs_gpios, \ + DT_REG_ADDR(node_id), \ + {}), \ + .delay = (delay_), \ + }, \ + } + +/** + * @brief MIPI DBI controller configuration + * + * Configuration for MIPI DBI controller write + */ +struct mipi_dbi_config { + /** MIPI DBI mode (SPI 3 wire or 4 wire) */ + uint8_t mode; + /** SPI configuration */ + struct spi_config config; +}; + + +/** MIPI-DBI host driver API */ +__subsystem struct mipi_dbi_driver_api { + int (*command_write)(const struct device *dev, + const struct mipi_dbi_config *config, uint8_t cmd, + const uint8_t *data, size_t len); + int (*command_read)(const struct device *dev, + const struct mipi_dbi_config *config, uint8_t *cmds, + size_t num_cmds, uint8_t *response, size_t len); + int (*write_display)(const struct device *dev, + const struct mipi_dbi_config *config, + const uint8_t *framebuf, + struct display_buffer_descriptor *desc, + enum display_pixel_format pixfmt); + int (*reset)(const struct device *dev, uint32_t delay); +}; + +/** + * @brief Write a command to the display controller + * + * Writes a command, along with an optional data buffer to the display. + * If data buffer and buffer length are NULL and 0 respectively, then + * only a command will be sent. + * + * @param dev mipi dbi controller + * @param config MIPI DBI configuration + * @param cmd command to write to display controller + * @param data optional data buffer to write after command + * @param len size of data buffer in bytes. Set to 0 to skip sending data. + * @retval 0 command write succeeded + * @retval -EIO I/O error + * @retval -ETIMEDOUT transfer timed out + * @retval -EBUSY controller is busy + * @retval -ENOSYS not implemented + */ +static inline int mipi_dbi_command_write(const struct device *dev, + const struct mipi_dbi_config *config, + uint8_t cmd, const uint8_t *data, + size_t len) +{ + const struct mipi_dbi_driver_api *api = + (const struct mipi_dbi_driver_api *)dev->api; + + if (api->command_write == NULL) { + return -ENOSYS; + } + return api->command_write(dev, config, cmd, data, len); +} + +/** + * @brief Read a command response from the display controller + * + * Reads a command response from the display controller. + * + * @param dev mipi dbi controller + * @param config MIPI DBI configuration + * @param cmds array of one byte commands to send to display controller + * @param num_cmd number of commands to write to display controller + * @param response response buffer, filled with display controller response + * @param len size of response buffer in bytes. + * @retval 0 command read succeeded + * @retval -EIO I/O error + * @retval -ETIMEDOUT transfer timed out + * @retval -EBUSY controller is busy + * @retval -ENOSYS not implemented + */ +static inline int mipi_dbi_command_read(const struct device *dev, + const struct mipi_dbi_config *config, + uint8_t *cmds, size_t num_cmd, + uint8_t *response, size_t len) +{ + const struct mipi_dbi_driver_api *api = + (const struct mipi_dbi_driver_api *)dev->api; + + if (api->command_read == NULL) { + return -ENOSYS; + } + return api->command_read(dev, config, cmds, num_cmd, response, len); +} + +/** + * @brief Write a display buffer to the display controller. + * + * Writes a display buffer to the controller. If the controller requires + * a "Write memory" command before writing display data, this should be + * sent with @ref mipi_dbi_command_write + * @param dev mipi dbi controller + * @param config MIPI DBI configuration + * @param framebuf: framebuffer to write to display + * @param desc: descriptor of framebuffer to write. Note that the pitch must + * be equal to width. + * @param pixfmt: pixel format of framebuffer data + * @retval 0 buffer write succeeded. + * @retval -EIO I/O error + * @retval -ETIMEDOUT transfer timed out + * @retval -EBUSY controller is busy + * @retval -ENOSYS not implemented + */ +static inline int mipi_dbi_write_display(const struct device *dev, + const struct mipi_dbi_config *config, + const uint8_t *framebuf, + struct display_buffer_descriptor *desc, + enum display_pixel_format pixfmt) +{ + const struct mipi_dbi_driver_api *api = + (const struct mipi_dbi_driver_api *)dev->api; + + if (api->write_display == NULL) { + return -ENOSYS; + } + return api->write_display(dev, config, framebuf, desc, pixfmt); +} + +/** + * @brief Resets attached display controller + * + * Resets the attached display controller. + * @param dev mipi dbi controller + * @param delay duration to set reset signal for, in milliseconds + * @retval 0 reset succeeded + * @retval -EIO I/O error + * @retval -ENOSYS not implemented + * @retval -ENOTSUP not supported + */ +static inline int mipi_dbi_reset(const struct device *dev, uint32_t delay) +{ + const struct mipi_dbi_driver_api *api = + (const struct mipi_dbi_driver_api *)dev->api; + + if (api->reset == NULL) { + return -ENOSYS; + } + return api->reset(dev, delay); +} + +#ifdef __cplusplus +} +#endif + +/** + * @} + */ + +#endif /* ZEPHYR_INCLUDE_DRIVERS_MIPI_DBI_H_ */ From 1074fbd91e368915f1fd722376c2b52dae869154 Mon Sep 17 00:00:00 2001 From: Daniel DeGrasse Date: Mon, 30 Oct 2023 13:14:28 -0500 Subject: [PATCH 3222/3723] doc: hardware: add peripheral documentation for MIPI DBI Add documentation for MIPI DBI peripheral class Signed-off-by: Daniel DeGrasse --- doc/hardware/peripherals/index.rst | 1 + doc/hardware/peripherals/mipi_dbi.rst | 27 +++++++++++++++++++++++++++ 2 files changed, 28 insertions(+) create mode 100644 doc/hardware/peripherals/mipi_dbi.rst diff --git a/doc/hardware/peripherals/index.rst b/doc/hardware/peripherals/index.rst index 19461b6c9f4..cd75fee0371 100644 --- a/doc/hardware/peripherals/index.rst +++ b/doc/hardware/peripherals/index.rst @@ -39,6 +39,7 @@ Peripherals kscan.rst led.rst mdio.rst + mipi_dbi.rst mipi_dsi.rst mbox.rst pcie.rst diff --git a/doc/hardware/peripherals/mipi_dbi.rst b/doc/hardware/peripherals/mipi_dbi.rst new file mode 100644 index 00000000000..640030c3f0b --- /dev/null +++ b/doc/hardware/peripherals/mipi_dbi.rst @@ -0,0 +1,27 @@ +.. _mipi_dbi_api: + +MIPI Display Bus Interface (DBI) +################################### + +The MIPI DBI driver class implements support for MIPI DBI compliant display +controllers. + +MIPI DBI defines 3 interface types: +* Type A: Motorola 6800 parallel bus + +* Type B: Intel 8080 parallel bus + +* Type C: SPI Type serial bit bus with 3 options: + + #. 9 write clocks per byte, final bit is command/data selection bit + + #. Same as above, but 16 write clocks per byte + + #. 8 write clocks per byte. Command/data selected via GPIO pin + +Currently, the API only supports Type C controllers, options 1 and 3. + +API Reference +************* + +.. doxygengroup:: mipi_dbi_interface From 571de47e1645622d16b20584d6068980e8622463 Mon Sep 17 00:00:00 2001 From: Daniel DeGrasse Date: Fri, 27 Oct 2023 22:42:32 +0000 Subject: [PATCH 3223/3723] drivers: mipi_dbi: add SPI based MIPI DBI mode C driver SPI controllers can easily implement MIPI DBI mode C, with the help of GPIO pins for the reset and command/data signals. Introduce a MIPI DBI compliant SPI driver, which emulates MIPI DBI mode C (SPI 3 and 4 wire). Signed-off-by: Daniel DeGrasse --- drivers/mipi_dbi/CMakeLists.txt | 2 + drivers/mipi_dbi/Kconfig | 2 + drivers/mipi_dbi/Kconfig.spi | 23 ++ drivers/mipi_dbi/mipi_dbi_spi.c | 312 ++++++++++++++++++ .../mipi-dbi/zephyr,mipi-dbi-spi.yaml | 35 ++ 5 files changed, 374 insertions(+) create mode 100644 drivers/mipi_dbi/Kconfig.spi create mode 100644 drivers/mipi_dbi/mipi_dbi_spi.c create mode 100644 dts/bindings/mipi-dbi/zephyr,mipi-dbi-spi.yaml diff --git a/drivers/mipi_dbi/CMakeLists.txt b/drivers/mipi_dbi/CMakeLists.txt index 3a04db6a9ca..5f00319bc82 100644 --- a/drivers/mipi_dbi/CMakeLists.txt +++ b/drivers/mipi_dbi/CMakeLists.txt @@ -1,3 +1,5 @@ # Copyright 2023 NXP # # SPDX-License-Identifier: Apache-2.0 + +zephyr_sources_ifdef(CONFIG_MIPI_DBI_SPI mipi_dbi_spi.c) diff --git a/drivers/mipi_dbi/Kconfig b/drivers/mipi_dbi/Kconfig index cc4e2344c64..f8305d29833 100644 --- a/drivers/mipi_dbi/Kconfig +++ b/drivers/mipi_dbi/Kconfig @@ -21,4 +21,6 @@ config MIPI_DBI_INIT_PRIORITY help MIPI-DBI Host Controllers initialization priority. +source "drivers/mipi_dbi/Kconfig.spi" + endif diff --git a/drivers/mipi_dbi/Kconfig.spi b/drivers/mipi_dbi/Kconfig.spi new file mode 100644 index 00000000000..090646e1c3f --- /dev/null +++ b/drivers/mipi_dbi/Kconfig.spi @@ -0,0 +1,23 @@ +# Copyright 2023 NXP +# SPDX-License-Identifier: Apache-2.0 + +config MIPI_DBI_SPI + bool "MIPI DBI SPI driver" + default y + depends on DT_HAS_ZEPHYR_MIPI_DBI_SPI_ENABLED + select SPI + help + Enable support for MIPI DBI SPI driver. This driver implements + a MIPI-DBI mode C compatible controller using a SPI device, as well + as GPIO outputs for the reset and D/C signals + +if MIPI_DBI_SPI + +config MIPI_DBI_SPI_3WIRE + bool "Emulated 3 wire SPI support" + help + Support 3 wire MIPI DBI (Mode C option 2) in MIPI DBI SPI + driver. This requires manually packing each byte with a data/command + bit, and may slow down display data transmission. + +endif # MIPI_DBI_SPI diff --git a/drivers/mipi_dbi/mipi_dbi_spi.c b/drivers/mipi_dbi/mipi_dbi_spi.c new file mode 100644 index 00000000000..6bc05dc2baf --- /dev/null +++ b/drivers/mipi_dbi/mipi_dbi_spi.c @@ -0,0 +1,312 @@ +/* + * Copyright 2023 NXP + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#define DT_DRV_COMPAT zephyr_mipi_dbi_spi + +#include +#include +#include + +#include +LOG_MODULE_REGISTER(mipi_dbi_spi, CONFIG_MIPI_DBI_LOG_LEVEL); + +struct mipi_dbi_spi_config { + /* SPI hardware used to send data */ + const struct device *spi_dev; + /* Command/Data gpio */ + const struct gpio_dt_spec cmd_data; + /* Reset GPIO */ + const struct gpio_dt_spec reset; +}; + +struct mipi_dbi_spi_data { + /* Used for 3 wire mode */ + uint16_t spi_byte; + struct k_spinlock lock; +}; + +/* Expands to 1 if the node does not have the `write-only` property */ +#define _WRITE_ONLY_ABSENT(n) (!DT_INST_PROP(n, write_only)) | + +/* This macro will evaluate to 1 if any of the nodes with zephyr,mipi-dbi-spi + * lack a `write-only` property. The intention here is to allow the entire + * command_read function to be optimized out when it is not needed. + */ +#define MIPI_DBI_SPI_READ_REQUIRED DT_INST_FOREACH_STATUS_OKAY(_WRITE_ONLY_ABSENT) 0 +uint32_t var = MIPI_DBI_SPI_READ_REQUIRED; + +/* In Type C mode 1 MIPI BIT communication, the 9th bit of the word + * (first bit sent in each word) indicates if the word is a command or + * data. Typically 0 indicates a command and 1 indicates data, but some + * displays may vary. + */ +#define MIPI_DBI_DC_BIT BIT(9) + +static int mipi_dbi_spi_write_helper(const struct device *dev, + const struct mipi_dbi_config *dbi_config, + bool cmd_present, uint8_t cmd, + const uint8_t *data_buf, size_t len) +{ + const struct mipi_dbi_spi_config *config = dev->config; + struct mipi_dbi_spi_data *data = dev->data; + struct spi_buf buffer; + struct spi_buf_set buf_set = { + .buffers = &buffer, + .count = 1, + }; + int ret = 0; + k_spinlock_key_t spinlock_key = k_spin_lock(&data->lock); + + if (dbi_config->mode == MIPI_DBI_MODE_SPI_3WIRE && + IS_ENABLED(CONFIG_MIPI_DBI_SPI_3WIRE)) { + struct spi_config tmp_cfg; + /* We have to emulate 3 wire mode by packing the data/command + * bit into the upper bit of the SPI transfer. + * switch SPI to 9 bit mode, and write the transfer + */ + memcpy(&tmp_cfg, &dbi_config->config, sizeof(tmp_cfg)); + tmp_cfg.operation &= ~SPI_WORD_SIZE_MASK; + tmp_cfg.operation |= SPI_WORD_SET(9); + buffer.buf = &data->spi_byte; + buffer.len = 1; + + /* Send command */ + if (cmd_present) { + data->spi_byte = cmd; + ret = spi_write(config->spi_dev, &tmp_cfg, &buf_set); + if (ret < 0) { + goto out; + } + } + /* Write data, byte by byte */ + for (size_t i = 0; i < len; i++) { + data->spi_byte = MIPI_DBI_DC_BIT | data_buf[i]; + ret = spi_write(config->spi_dev, &tmp_cfg, &buf_set); + if (ret < 0) { + goto out; + } + } + } else if (dbi_config->mode == MIPI_DBI_MODE_SPI_4WIRE) { + /* 4 wire mode is much simpler. We just toggle the + * command/data GPIO to indicate if we are sending + * a command or data + */ + buffer.buf = &cmd; + buffer.len = sizeof(cmd); + + if (cmd_present) { + /* Set CD pin low for command */ + gpio_pin_set_dt(&config->cmd_data, 0); + ret = spi_write(config->spi_dev, &dbi_config->config, + &buf_set); + if (ret < 0) { + goto out; + } + } + + if (len > 0) { + buffer.buf = (void *)data_buf; + buffer.len = len; + + /* Set CD pin high for data */ + gpio_pin_set_dt(&config->cmd_data, 1); + ret = spi_write(config->spi_dev, &dbi_config->config, + &buf_set); + if (ret < 0) { + goto out; + } + } + } else { + /* Otherwise, unsupported mode */ + ret = -ENOTSUP; + } +out: + k_spin_unlock(&data->lock, spinlock_key); + return ret; +} + +static int mipi_dbi_spi_command_write(const struct device *dev, + const struct mipi_dbi_config *dbi_config, + uint8_t cmd, const uint8_t *data_buf, + size_t len) +{ + return mipi_dbi_spi_write_helper(dev, dbi_config, true, cmd, + data_buf, len); +} + +static int mipi_dbi_spi_write_display(const struct device *dev, + const struct mipi_dbi_config *dbi_config, + const uint8_t *framebuf, + struct display_buffer_descriptor *desc, + enum display_pixel_format pixfmt) +{ + ARG_UNUSED(pixfmt); + + return mipi_dbi_spi_write_helper(dev, dbi_config, false, 0x0, + framebuf, desc->buf_size); +} + +#if MIPI_DBI_SPI_READ_REQUIRED + +static int mipi_dbi_spi_command_read(const struct device *dev, + const struct mipi_dbi_config *dbi_config, + uint8_t *cmds, size_t num_cmds, + uint8_t *response, size_t len) +{ + const struct mipi_dbi_spi_config *config = dev->config; + struct mipi_dbi_spi_data *data = dev->data; + struct spi_buf buffer; + struct spi_buf_set buf_set = { + .buffers = &buffer, + .count = 1, + }; + int ret = 0; + k_spinlock_key_t spinlock_key = k_spin_lock(&data->lock); + struct spi_config tmp_config; + + memcpy(&tmp_config, &dbi_config->config, sizeof(tmp_config)); + if (dbi_config->mode == MIPI_DBI_MODE_SPI_3WIRE && + IS_ENABLED(CONFIG_MIPI_DBI_SPI_3WIRE)) { + /* We have to emulate 3 wire mode by packing the data/command + * bit into the upper bit of the SPI transfer. + * switch SPI to 9 bit mode, and write the transfer + */ + tmp_config.operation &= ~SPI_WORD_SIZE_MASK; + tmp_config.operation |= SPI_WORD_SET(9); + + buffer.buf = &data->spi_byte; + buffer.len = 1; + /* Send each command */ + for (size_t i = 0; i < num_cmds; i++) { + data->spi_byte = cmds[i]; + ret = spi_write(config->spi_dev, &tmp_config, &buf_set); + if (ret < 0) { + goto out; + } + } + /* Now, we can switch to 8 bit mode, and read data */ + buffer.buf = (void *)response; + buffer.len = len; + ret = spi_read(config->spi_dev, &dbi_config->config, &buf_set); + } else if (dbi_config->mode == MIPI_DBI_MODE_SPI_4WIRE) { + /* 4 wire mode is much simpler. We just toggle the + * command/data GPIO to indicate if we are sending + * a command or data. Note that since some SPI displays + * require CS to be held low for the entire read sequence, + * we set SPI_HOLD_ON_CS + */ + tmp_config.operation |= SPI_HOLD_ON_CS; + + if (num_cmds > 0) { + buffer.buf = cmds; + buffer.len = num_cmds; + /* Set CD pin low for command */ + gpio_pin_set_dt(&config->cmd_data, 0); + + ret = spi_write(config->spi_dev, &tmp_config, + &buf_set); + if (ret < 0) { + goto out; + } + } + + if (len > 0) { + /* Set CD pin high for data */ + gpio_pin_set_dt(&config->cmd_data, 1); + + buffer.buf = (void *)response; + buffer.len = len; + ret = spi_read(config->spi_dev, &tmp_config, + &buf_set); + if (ret < 0) { + goto out; + } + } + } else { + /* Otherwise, unsupported mode */ + ret = -ENOTSUP; + } +out: + spi_release(config->spi_dev, &tmp_config); + k_spin_unlock(&data->lock, spinlock_key); + return ret; +} + +#endif /* MIPI_DBI_SPI_READ_REQUIRED */ + +static int mipi_dbi_spi_reset(const struct device *dev, uint32_t delay) +{ + const struct mipi_dbi_spi_config *config = dev->config; + int ret; + + if (config->reset.port == NULL) { + return -ENOTSUP; + } + + ret = gpio_pin_set_dt(&config->reset, 0); + if (ret < 0) { + return ret; + } + k_msleep(delay); + return gpio_pin_set_dt(&config->reset, 1); +} + +static int mipi_dbi_spi_init(const struct device *dev) +{ + const struct mipi_dbi_spi_config *config = dev->config; + int ret; + + if (!device_is_ready(config->spi_dev)) { + LOG_ERR("SPI device is not ready"); + return -ENODEV; + } + + if (config->cmd_data.port) { + ret = gpio_pin_configure_dt(&config->cmd_data, GPIO_OUTPUT); + if (ret < 0) { + LOG_ERR("Could not configure command/data GPIO (%d)", ret); + return ret; + } + } + + if (config->reset.port) { + ret = gpio_pin_configure_dt(&config->reset, GPIO_OUTPUT_INACTIVE); + if (ret < 0) { + LOG_ERR("Could not configure reset GPIO (%d)", ret); + return ret; + } + } + + return 0; +} + +static struct mipi_dbi_driver_api mipi_dbi_spi_driver_api = { + .reset = mipi_dbi_spi_reset, + .command_write = mipi_dbi_spi_command_write, + .write_display = mipi_dbi_spi_write_display, +#if MIPI_DBI_SPI_READ_REQUIRED + .command_read = mipi_dbi_spi_command_read, +#endif +}; + +#define MIPI_DBI_SPI_INIT(n) \ + static const struct mipi_dbi_spi_config \ + mipi_dbi_spi_config_##n = { \ + .spi_dev = DEVICE_DT_GET( \ + DT_INST_PHANDLE(n, spi_dev)), \ + .cmd_data = GPIO_DT_SPEC_INST_GET_OR(n, dc_gpios, {}), \ + .reset = GPIO_DT_SPEC_INST_GET_OR(n, reset_gpios, {}), \ + }; \ + static struct mipi_dbi_spi_data mipi_dbi_spi_data_##n; \ + \ + DEVICE_DT_INST_DEFINE(n, mipi_dbi_spi_init, NULL, \ + &mipi_dbi_spi_data_##n, \ + &mipi_dbi_spi_config_##n, \ + POST_KERNEL, \ + CONFIG_MIPI_DBI_INIT_PRIORITY, \ + &mipi_dbi_spi_driver_api); + +DT_INST_FOREACH_STATUS_OKAY(MIPI_DBI_SPI_INIT) diff --git a/dts/bindings/mipi-dbi/zephyr,mipi-dbi-spi.yaml b/dts/bindings/mipi-dbi/zephyr,mipi-dbi-spi.yaml new file mode 100644 index 00000000000..06ca9a2f465 --- /dev/null +++ b/dts/bindings/mipi-dbi/zephyr,mipi-dbi-spi.yaml @@ -0,0 +1,35 @@ +# Copyright 2023 NXP +# SPDX-License-Identifier: Apache-2.0 + +description: | + MIPI-DBI Mode C compatible SPI controller. This driver emulates MIPI DBI + mode C using a SPI controller and GPIO pins +compatible: "zephyr,mipi-dbi-spi" + +include: ["mipi-dbi-controller.yaml", "pinctrl-device.yaml"] + +properties: + spi-dev: + type: phandle + required: true + description: | + SPI device to use for data transfers with MIPI DBI commands. This SPI + device should be connected to the MIPI DBI display. + + dc-gpios: + type: phandle-array + description: | + Data/command gpio pin. Required when using 4 wire SPI mode (Mode C1). + Set to low when sending a command, or high when sending data. + + reset-gpios: + type: phandle-array + description: | + Reset GPIO pin. Used to reset the display during initialization. + Active low pin. + + write-only: + type: boolean + description: | + Controller is not readable, IE only DOUT pin is connected on the SPI + interface. From 3dbbb7331974bad70f09cb7afd526060cc4c42cb Mon Sep 17 00:00:00 2001 From: Daniel DeGrasse Date: Mon, 30 Oct 2023 11:22:15 -0500 Subject: [PATCH 3224/3723] drivers: display: ili9xxx: convert to MIPI DBI API Convert ili9xxx display drivers to use MIPI DBI API. Due to the fact this change requires a new devicetree structure for the display driver to build, required devicetree changes are also included in this commit for all boards and shields defining an instance of an ili9xxx display. Signed-off-by: Daniel DeGrasse --- .../bl5340_dvk/bl5340_dvk_cpuapp_common.dtsi | 29 +++-- .../arm/stm32f429i_disc1/stm32f429i_disc1.dts | 65 +++++----- boards/arm/wio_terminal/wio_terminal.dts | 34 ++++-- .../dts/adafruit_2_8_tft_touch_v2.dtsi | 45 ++++--- .../buydisplay_2_8_tft_touch_arduino.overlay | 44 ++++--- .../buydisplay_3_5_tft_touch_arduino.overlay | 42 ++++--- .../xtensa/esp_wrover_kit/esp_wrover_kit.dts | 32 +++-- boards/xtensa/m5stack_core2/Kconfig.defconfig | 9 ++ boards/xtensa/m5stack_core2/m5stack_core2.dts | 37 +++--- boards/xtensa/odroid_go/odroid_go.dts | 30 +++-- drivers/display/Kconfig.ili9xxx | 8 +- drivers/display/display_ili9xxx.c | 112 +++++------------- drivers/display/display_ili9xxx.h | 9 +- .../display/ilitek,ili9xxx-common.yaml | 19 +-- tests/drivers/build_all/display/app.overlay | 31 +++-- 15 files changed, 283 insertions(+), 263 deletions(-) diff --git a/boards/arm/bl5340_dvk/bl5340_dvk_cpuapp_common.dtsi b/boards/arm/bl5340_dvk/bl5340_dvk_cpuapp_common.dtsi index 04039294b76..5a748b1bf9d 100644 --- a/boards/arm/bl5340_dvk/bl5340_dvk_cpuapp_common.dtsi +++ b/boards/arm/bl5340_dvk/bl5340_dvk_cpuapp_common.dtsi @@ -107,6 +107,25 @@ bbram0 = &extrtc0; spi-flash0 = &mx25r64; }; + + mipi_dbi { + compatible = "zephyr,mipi-dbi-spi"; + reset-gpios = <&gpio0 6 GPIO_ACTIVE_HIGH>; + dc-gpios = <&gpio0 12 GPIO_ACTIVE_HIGH>; + spi-dev = <&spi2>; + write-only; + #address-cells = <1>; + #size-cells = <0>; + + ili9340: ili9340@0 { + compatible = "ilitek,ili9340"; + reg = <0>; + mipi-max-frequency = <32000000>; + rotation = <270>; + width = <320>; + height = <240>; + }; + }; }; &adc { @@ -224,16 +243,6 @@ pinctrl-0 = <&spi4_default>; pinctrl-1 = <&spi4_sleep>; pinctrl-names = "default", "sleep"; - ili9340: ili9340@0 { - compatible = "ilitek,ili9340"; - reg = <0>; - spi-max-frequency = <32000000>; - reset-gpios = <&gpio0 6 GPIO_ACTIVE_LOW>; - cmd-data-gpios = <&gpio0 12 GPIO_ACTIVE_LOW>; - rotation = <270>; - width = <320>; - height = <240>; - }; }; &uart0 { diff --git a/boards/arm/stm32f429i_disc1/stm32f429i_disc1.dts b/boards/arm/stm32f429i_disc1/stm32f429i_disc1.dts index 153f0cab3a9..51b7ac84d49 100644 --- a/boards/arm/stm32f429i_disc1/stm32f429i_disc1.dts +++ b/boards/arm/stm32f429i_disc1/stm32f429i_disc1.dts @@ -62,6 +62,43 @@ invert-x; invert-y; }; + + mipi_dbi { + compatible = "zephyr,mipi-dbi-spi"; + dc-gpios = <&gpiod 13 GPIO_ACTIVE_HIGH>; + write-only; + #address-cells = <1>; + #size-cells = <0>; + spi-dev = <&spi5>; + + ili9341: ili9341@0 { + compatible = "ilitek,ili9341"; + mipi-max-frequency = <5625000>; + reg = <0>; + width = <240>; + height = <320>; + rotation = <180>; + pixel-format = ; + pwctrla = [39 2c 00 34 02]; + pwctrlb = [00 c1 30]; + timctrla = [85 00 78]; + timctrlb = [00 00]; + pwseqctrl = [64 03 12 81]; + pumpratioctrl = [20]; + disctrl = [08 82 27 04]; + vmctrl1 = [45 15]; + vmctrl2 = [90]; + enable3g = [00]; + ifctl = [01 00 06]; + ifmode = [c2]; + gamset = [01]; + frmctr1 = [00 1b]; + pwctrl1 = [10]; + pwctrl2 = [10]; + pgamctrl = [0F 29 24 0c 0e 09 4e 78 3c 09 13 05 17 11 00]; + ngamctrl = [00 16 1b 04 11 07 31 33 42 05 0c 0a 28 2f 0f]; + }; + }; }; &clk_lsi { @@ -147,34 +184,6 @@ pinctrl-names = "default"; status = "okay"; cs-gpios = <&gpioc 2 GPIO_ACTIVE_LOW>; - ili9341: ili9341@0 { - compatible = "ilitek,ili9341"; - spi-max-frequency = <5625000>; - reg = <0>; - cmd-data-gpios = <&gpiod 13 GPIO_ACTIVE_LOW>; - width = <240>; - height = <320>; - rotation = <180>; - pixel-format = ; - pwctrla = [39 2c 00 34 02]; - pwctrlb = [00 c1 30]; - timctrla = [85 00 78]; - timctrlb = [00 00]; - pwseqctrl = [64 03 12 81]; - pumpratioctrl = [20]; - disctrl = [08 82 27 04]; - vmctrl1 = [45 15]; - vmctrl2 = [90]; - enable3g = [00]; - ifctl = [01 00 06]; - ifmode = [c2]; - gamset = [01]; - frmctr1 = [00 1b]; - pwctrl1 = [10]; - pwctrl2 = [10]; - pgamctrl = [0F 29 24 0c 0e 09 4e 78 3c 09 13 05 17 11 00]; - ngamctrl = [00 16 1b 04 11 07 31 33 42 05 0c 0a 28 2f 0f]; - }; }; &fmc { diff --git a/boards/arm/wio_terminal/wio_terminal.dts b/boards/arm/wio_terminal/wio_terminal.dts index 99e07373526..a88eeee9e94 100644 --- a/boards/arm/wio_terminal/wio_terminal.dts +++ b/boards/arm/wio_terminal/wio_terminal.dts @@ -123,6 +123,27 @@ regulator-name = "usb_power_5v_en"; enable-gpios = <&porta 27 GPIO_ACTIVE_LOW>; }; + + /* LCD */ + mipi_dbi { + compatible = "zephyr,mipi-dbi-spi"; + dc-gpios = <&portc 6 GPIO_ACTIVE_HIGH>; + reset-gpios = <&portc 7 GPIO_ACTIVE_HIGH>; + #address-cells = <1>; + #size-cells = <0>; + spi-dev = <&sercom7>; + write-only; + + ili9341: ili9341@0 { + compatible = "ilitek,ili9341"; + mipi-max-frequency = <24000000>; + reg = <0>; + pixel-format = ; + rotation = <270>; + width = <320>; + height = <240>; + }; + }; }; &cpu0 { @@ -271,19 +292,6 @@ pinctrl-0 = <&sercom7_spi_default>; pinctrl-names = "default"; cs-gpios = <&portb 21 GPIO_ACTIVE_LOW>; - - /* LCD */ - ili9341: ili9341@0 { - compatible = "ilitek,ili9341"; - spi-max-frequency = <24000000>; - reg = <0>; - cmd-data-gpios = <&portc 6 GPIO_ACTIVE_LOW>; - reset-gpios = <&portc 7 GPIO_ACTIVE_LOW>; - pixel-format = ; - rotation = <270>; - width = <320>; - height = <240>; - }; }; /* USB */ diff --git a/boards/shields/adafruit_2_8_tft_touch_v2/dts/adafruit_2_8_tft_touch_v2.dtsi b/boards/shields/adafruit_2_8_tft_touch_v2/dts/adafruit_2_8_tft_touch_v2.dtsi index 543d0b86df1..9413a7834d9 100644 --- a/boards/shields/adafruit_2_8_tft_touch_v2/dts/adafruit_2_8_tft_touch_v2.dtsi +++ b/boards/shields/adafruit_2_8_tft_touch_v2/dts/adafruit_2_8_tft_touch_v2.dtsi @@ -8,7 +8,7 @@ / { chosen { - zephyr,display = &ili9340; + zephyr,display = &adafruit_2_8_tft_touch_v2_ili9340; }; lvgl_pointer { @@ -18,6 +18,31 @@ invert-x; invert-y; }; + + adafruit_2_8_tft_touch_v2_mipi_dbi { + compatible = "zephyr,mipi-dbi-spi"; + spi-dev = <&arduino_spi>; + dc-gpios = <&arduino_header 15 GPIO_ACTIVE_HIGH>; /* D9 */ + write-only; + #address-cells = <1>; + #size-cells = <0>; + + adafruit_2_8_tft_touch_v2_ili9340: ili9340@0 { + compatible = "ilitek,ili9340"; + mipi-max-frequency = <15151515>; + reg = <0>; + width = <320>; + height = <240>; + pixel-format = ; + rotation = <90>; + frmctr1 = [00 18]; + pwctrl1 = [23 00]; + vmctrl1 = [3e 28]; + vmctrl2 = [86]; + pgamctrl = [0f 31 2b 0c 0e 08 4e f1 37 07 10 03 0e 09 00]; + ngamctrl = [00 0e 14 03 11 07 31 c1 48 08 0f 0c 31 36 0f]; + }; + }; }; &arduino_spi { @@ -25,24 +50,6 @@ cs-gpios = <&arduino_header 16 GPIO_ACTIVE_LOW>, /* D10 */ <&arduino_header 10 GPIO_ACTIVE_LOW>; /* D04 */ - - ili9340: ili9340@0 { - compatible = "ilitek,ili9340"; - spi-max-frequency = <15151515>; - reg = <0>; - cmd-data-gpios = <&arduino_header 15 GPIO_ACTIVE_LOW>; /* D9 */ - width = <320>; - height = <240>; - pixel-format = ; - rotation = <90>; - frmctr1 = [00 18]; - pwctrl1 = [23 00]; - vmctrl1 = [3e 28]; - vmctrl2 = [86]; - pgamctrl = [0f 31 2b 0c 0e 08 4e f1 37 07 10 03 0e 09 00]; - ngamctrl = [00 0e 14 03 11 07 31 c1 48 08 0f 0c 31 36 0f]; - }; - adafruit_2_8_tft_touch_v2_sdhc: sdhc@1 { compatible = "zephyr,sdhc-spi-slot"; reg = <1>; diff --git a/boards/shields/buydisplay_2_8_tft_touch_arduino/buydisplay_2_8_tft_touch_arduino.overlay b/boards/shields/buydisplay_2_8_tft_touch_arduino/buydisplay_2_8_tft_touch_arduino.overlay index 3cc257e9366..162b1450111 100644 --- a/boards/shields/buydisplay_2_8_tft_touch_arduino/buydisplay_2_8_tft_touch_arduino.overlay +++ b/boards/shields/buydisplay_2_8_tft_touch_arduino/buydisplay_2_8_tft_touch_arduino.overlay @@ -18,29 +18,37 @@ invert-x; invert-y; }; + + buydisplay_2_8_tft_touch_arduino_mipi_dbi { + compatible = "zephyr,mipi-dbi-spi"; + dc-gpios = <&arduino_header 13 GPIO_ACTIVE_HIGH>; /* D7 */ + reset-gpios = <&arduino_header 16 GPIO_ACTIVE_HIGH>; /* D10 */ + spi-dev = <&arduino_spi>; + write-only; + #address-cells = <1>; + #size-cells = <0>; + + ili9340_buydisplay_2_8_tft_touch_arduino: ili9340@0 { + compatible = "ilitek,ili9340"; + mipi-max-frequency = <25000000>; + reg = <0>; + width = <240>; + height = <320>; + pixel-format = ; + rotation = <0>; + frmctr1 = [00 18]; + pwctrl1 = [23 00]; + vmctrl1 = [3e 28]; + vmctrl2 = [86]; + pgamctrl = [0f 31 2b 0c 0e 08 4e f1 37 07 10 03 0e 09 00]; + ngamctrl = [00 0e 14 03 11 07 31 c1 48 08 0f 0c 31 36 0f]; + }; + }; }; &arduino_spi { status = "okay"; cs-gpios = <&arduino_header 15 GPIO_ACTIVE_LOW>; /* D9 */ - - ili9340_buydisplay_2_8_tft_touch_arduino: ili9340@0 { - compatible = "ilitek,ili9340"; - spi-max-frequency = <25000000>; - reg = <0>; - cmd-data-gpios = <&arduino_header 13 GPIO_ACTIVE_LOW>; /* D7 */ - reset-gpios = <&arduino_header 16 GPIO_ACTIVE_LOW>; /* D10 */ - width = <240>; - height = <320>; - pixel-format = ; - rotation = <0>; - frmctr1 = [00 18]; - pwctrl1 = [23 00]; - vmctrl1 = [3e 28]; - vmctrl2 = [86]; - pgamctrl = [0f 31 2b 0c 0e 08 4e f1 37 07 10 03 0e 09 00]; - ngamctrl = [00 0e 14 03 11 07 31 c1 48 08 0f 0c 31 36 0f]; - }; }; &arduino_i2c { diff --git a/boards/shields/buydisplay_3_5_tft_touch_arduino/buydisplay_3_5_tft_touch_arduino.overlay b/boards/shields/buydisplay_3_5_tft_touch_arduino/buydisplay_3_5_tft_touch_arduino.overlay index 5764c415460..0ba02cb5648 100644 --- a/boards/shields/buydisplay_3_5_tft_touch_arduino/buydisplay_3_5_tft_touch_arduino.overlay +++ b/boards/shields/buydisplay_3_5_tft_touch_arduino/buydisplay_3_5_tft_touch_arduino.overlay @@ -18,28 +18,36 @@ invert-x; invert-y; }; + + buydisplay_3_5_tft_touch_arduino_mipi_dbi { + compatible = "zephyr,mipi-dbi-spi"; + dc-gpios = <&arduino_header 13 GPIO_ACTIVE_HIGH>; /* D7 */ + reset-gpios = <&arduino_header 16 GPIO_ACTIVE_HIGH>; /* D10 */ + spi-dev = <&arduino_spi>; + write-only; + #address-cells = <1>; + #size-cells = <0>; + + ili9488_buydisplay_3_5_tft_touch_arduino: ili9488@0 { + compatible = "ilitek,ili9488"; + mipi-max-frequency = <25000000>; + reg = <0>; + pixel-format = ; + width = <320>; + height = <480>; + rotation = <0>; + frmctr1 = [a0 11]; + pwctrl1 = [17 15]; + pwctrl2 = [41]; + pgamctrl = [00 03 09 08 16 0a 3f 78 4c 09 0a 08 16 1a 0f]; + ngamctrl = [00 16 19 03 0f 05 32 45 46 04 0e 0d 35 37 0f]; + }; + }; }; &arduino_spi { status = "okay"; cs-gpios = <&arduino_header 15 GPIO_ACTIVE_LOW>; /* D9 */ - - ili9488_buydisplay_3_5_tft_touch_arduino: ili9488@0 { - compatible = "ilitek,ili9488"; - spi-max-frequency = <25000000>; - reg = <0>; - cmd-data-gpios = <&arduino_header 13 GPIO_ACTIVE_LOW>; /* D7 */ - reset-gpios = <&arduino_header 16 GPIO_ACTIVE_LOW>; /* D10 */ - pixel-format = ; - width = <320>; - height = <480>; - rotation = <0>; - frmctr1 = [a0 11]; - pwctrl1 = [17 15]; - pwctrl2 = [41]; - pgamctrl = [00 03 09 08 16 0a 3f 78 4c 09 0a 08 16 1a 0f]; - ngamctrl = [00 16 19 03 0f 05 32 45 46 04 0e 0d 35 37 0f]; - }; }; &arduino_i2c { diff --git a/boards/xtensa/esp_wrover_kit/esp_wrover_kit.dts b/boards/xtensa/esp_wrover_kit/esp_wrover_kit.dts index f5d366e0313..f7385037609 100644 --- a/boards/xtensa/esp_wrover_kit/esp_wrover_kit.dts +++ b/boards/xtensa/esp_wrover_kit/esp_wrover_kit.dts @@ -70,6 +70,26 @@ pwms = <&ledc0 2 PWM_HZ(100) PWM_POLARITY_NORMAL>; }; }; + + mipi_dbi { + compatible = "zephyr,mipi-dbi-spi"; + dc-gpios = <&gpio0 21 GPIO_ACTIVE_HIGH>; + reset-gpios = <&gpio0 18 GPIO_ACTIVE_HIGH>; + spi-dev = <&spi3>; + write-only; + #address-cells = <1>; + #size-cells = <0>; + + ili9341: ili9341@0 { + compatible = "ilitek,ili9341"; + mipi-max-frequency = <25000000>; + reg = <0>; + pixel-format = <0>; + rotation = <0>; + width = <240>; + height = <320>; + }; + }; }; &cpu0 { @@ -125,18 +145,6 @@ status = "okay"; pinctrl-0 = <&spim3_default>; pinctrl-names = "default"; - - ili9341: ili9341@0 { - compatible = "ilitek,ili9341"; - spi-max-frequency = <25000000>; - reg = <0>; - cmd-data-gpios = <&gpio0 21 GPIO_ACTIVE_LOW>; - reset-gpios = <&gpio0 18 GPIO_ACTIVE_LOW>; - pixel-format = <0>; - rotation = <0>; - width = <240>; - height = <320>; - }; }; &ledc0 { diff --git a/boards/xtensa/m5stack_core2/Kconfig.defconfig b/boards/xtensa/m5stack_core2/Kconfig.defconfig index 0edbda5d302..15dfc61483a 100644 --- a/boards/xtensa/m5stack_core2/Kconfig.defconfig +++ b/boards/xtensa/m5stack_core2/Kconfig.defconfig @@ -41,4 +41,13 @@ config INPUT config LV_COLOR_16_SWAP default y if LVGL +# Increase initialization priority of MIPI DBI device, so that it initializes +# after the GPIO controller +if MIPI_DBI + +config MIPI_DBI_INIT_PRIORITY + default 82 + +endif # MIPI_DBI + endif # BOARD_M5STACK_CORE2 diff --git a/boards/xtensa/m5stack_core2/m5stack_core2.dts b/boards/xtensa/m5stack_core2/m5stack_core2.dts index c17b540ca5d..c8c56b75ff9 100644 --- a/boards/xtensa/m5stack_core2/m5stack_core2.dts +++ b/boards/xtensa/m5stack_core2/m5stack_core2.dts @@ -48,6 +48,28 @@ input = <&ft5336_touch>; swap-xy; }; + + mipi_dbi { + compatible = "zephyr,mipi-dbi-spi"; + dc-gpios = <&gpio0 15 GPIO_ACTIVE_HIGH>; + reset-gpios = <&axp192_gpio 4 (GPIO_OPEN_DRAIN | GPIO_ACTIVE_HIGH)>; + spi-dev = <&spi3>; + write-only; + #address-cells = <1>; + #size-cells = <0>; + + ili9342c: ili9342c@0 { + compatible = "ilitek,ili9342c"; + mipi-max-frequency = <30000000>; + reg = <0>; + vin-supply = <&lcd_bg>; + pixel-format = ; + display-inversion; + width = <320>; + height = <240>; + rotation = <0>; + }; + }; }; &cpu0 { @@ -186,21 +208,6 @@ cs-gpios = <&gpio0 5 GPIO_ACTIVE_LOW>, <&gpio0 4 GPIO_ACTIVE_LOW>; - ili9342c: ili9342c@0 { - compatible = "ilitek,ili9342c"; - status = "okay"; - spi-max-frequency = <30000000>; - reg = <0>; - cmd-data-gpios = <&gpio0 15 GPIO_ACTIVE_LOW>; - vin-supply = <&lcd_bg>; - reset-gpios = <&axp192_gpio 4 (GPIO_OPEN_DRAIN | GPIO_ACTIVE_LOW)>; - pixel-format = ; - display-inversion; - width = <320>; - height = <240>; - rotation = <0>; - }; - sdhc0: sdhc@1 { compatible = "zephyr,sdhc-spi-slot"; reg = <1>; diff --git a/boards/xtensa/odroid_go/odroid_go.dts b/boards/xtensa/odroid_go/odroid_go.dts index 458a8251b1c..31ceee79d3c 100644 --- a/boards/xtensa/odroid_go/odroid_go.dts +++ b/boards/xtensa/odroid_go/odroid_go.dts @@ -77,6 +77,25 @@ sw0 = &menu_button; watchdog0 = &wdt0; }; + + mipi_dbi { + compatible = "zephyr,mipi-dbi-spi"; + dc-gpios = <&gpio0 21 GPIO_ACTIVE_HIGH>; + spi-dev = <&spi3>; + write-only; + #address-cells = <1>; + #size-cells = <0>; + + ili9341: ili9341@0 { + compatible = "ilitek,ili9341"; + mipi-max-frequency = <25000000>; + pixel-format = <0>; + reg = <0>; + rotation = <270>; + width = <320>; + height = <240>; + }; + }; }; &cpu0 { @@ -124,17 +143,6 @@ pinctrl-0 = <&spim3_default>; pinctrl-names = "default"; - ili9341: ili9341@0 { - compatible = "ilitek,ili9341"; - spi-max-frequency = <25000000>; - reg = <0>; - cmd-data-gpios = <&gpio0 21 GPIO_ACTIVE_LOW>; - pixel-format = <0>; - rotation = <270>; - width = <320>; - height = <240>; - }; - sdhc0: sdhc@1 { compatible = "zephyr,sdhc-spi-slot"; reg = <1>; diff --git a/drivers/display/Kconfig.ili9xxx b/drivers/display/Kconfig.ili9xxx index 0ae849260cf..ccd6778d04a 100644 --- a/drivers/display/Kconfig.ili9xxx +++ b/drivers/display/Kconfig.ili9xxx @@ -14,7 +14,7 @@ config ILI9340 bool "ILI9340 display driver" default y depends on DT_HAS_ILITEK_ILI9340_ENABLED - select SPI + select MIPI_DBI select ILI9XXX help Enable driver for ILI9340 display driver. @@ -23,7 +23,7 @@ config ILI9341 bool "ILI9341 display driver" default y depends on DT_HAS_ILITEK_ILI9341_ENABLED - select SPI + select MIPI_DBI select ILI9XXX help Enable driver for ILI9341 display driver. @@ -32,7 +32,7 @@ config ILI9342C bool "ILI9342C display driver" default y depends on DT_HAS_ILITEK_ILI9342C_ENABLED - select SPI + select MIPI_DBI select ILI9XXX help Enable driver for ILI9342C display driver. @@ -41,7 +41,7 @@ config ILI9488 bool "ILI9488 display driver" default y depends on DT_HAS_ILITEK_ILI9488_ENABLED - select SPI + select MIPI_DBI select ILI9XXX help Enable driver for ILI9488 display driver. diff --git a/drivers/display/display_ili9xxx.c b/drivers/display/display_ili9xxx.c index 2df7c60ea21..6f1ff01d6b1 100644 --- a/drivers/display/display_ili9xxx.c +++ b/drivers/display/display_ili9xxx.c @@ -26,33 +26,8 @@ int ili9xxx_transmit(const struct device *dev, uint8_t cmd, const void *tx_data, { const struct ili9xxx_config *config = dev->config; - int r; - struct spi_buf tx_buf; - struct spi_buf_set tx_bufs = { .buffers = &tx_buf, .count = 1U }; - - /* send command */ - tx_buf.buf = &cmd; - tx_buf.len = 1U; - - gpio_pin_set_dt(&config->cmd_data, ILI9XXX_CMD); - r = spi_write_dt(&config->spi, &tx_bufs); - if (r < 0) { - return r; - } - - /* send data (if any) */ - if (tx_data != NULL) { - tx_buf.buf = (void *)tx_data; - tx_buf.len = tx_len; - - gpio_pin_set_dt(&config->cmd_data, ILI9XXX_DATA); - r = spi_write_dt(&config->spi, &tx_bufs); - if (r < 0) { - return r; - } - } - - return 0; + return mipi_dbi_command_write(config->mipi_dev, &config->dbi_config, + cmd, tx_data, tx_len); } static int ili9xxx_exit_sleep(const struct device *dev) @@ -73,14 +48,7 @@ static void ili9xxx_hw_reset(const struct device *dev) { const struct ili9xxx_config *config = dev->config; - if (config->reset.port == NULL) { - return; - } - - gpio_pin_set_dt(&config->reset, 1); - k_sleep(K_MSEC(ILI9XXX_RESET_PULSE_TIME)); - gpio_pin_set_dt(&config->reset, 0); - + mipi_dbi_reset(config->mipi_dev, ILI9XXX_RESET_PULSE_TIME); k_sleep(K_MSEC(ILI9XXX_RESET_WAIT_TIME)); } @@ -115,11 +83,10 @@ static int ili9xxx_write(const struct device *dev, const uint16_t x, { const struct ili9xxx_config *config = dev->config; struct ili9xxx_data *data = dev->data; + struct display_buffer_descriptor mipi_desc; int r; const uint8_t *write_data_start = (const uint8_t *)buf; - struct spi_buf tx_buf; - struct spi_buf_set tx_bufs; uint16_t write_cnt; uint16_t nbr_of_writes; uint16_t write_h; @@ -139,26 +106,31 @@ static int ili9xxx_write(const struct device *dev, const uint16_t x, if (desc->pitch > desc->width) { write_h = 1U; nbr_of_writes = desc->height; + mipi_desc.height = 1; + mipi_desc.buf_size = desc->pitch * data->bytes_per_pixel; } else { write_h = desc->height; + mipi_desc.height = desc->height; + mipi_desc.buf_size = desc->buf_size; nbr_of_writes = 1U; } - r = ili9xxx_transmit(dev, ILI9XXX_RAMWR, write_data_start, - desc->width * data->bytes_per_pixel * write_h); + mipi_desc.width = desc->width; + mipi_desc.height = desc->height; + /* Per MIPI API, pitch must always match width */ + mipi_desc.pitch = desc->width; + + r = ili9xxx_transmit(dev, ILI9XXX_RAMWR, NULL, 0); if (r < 0) { return r; } - tx_bufs.buffers = &tx_buf; - tx_bufs.count = 1; - - write_data_start += desc->pitch * data->bytes_per_pixel; - for (write_cnt = 1U; write_cnt < nbr_of_writes; ++write_cnt) { - tx_buf.buf = (void *)write_data_start; - tx_buf.len = desc->width * data->bytes_per_pixel * write_h; - - r = spi_write_dt(&config->spi, &tx_bufs); + for (write_cnt = 0U; write_cnt < nbr_of_writes; ++write_cnt) { + r = mipi_dbi_write_display(config->mipi_dev, + &config->dbi_config, + write_data_start, + &mipi_desc, + data->pixel_format); if (r < 0) { return r; } @@ -363,35 +335,11 @@ static int ili9xxx_init(const struct device *dev) int r; - if (!spi_is_ready_dt(&config->spi)) { - LOG_ERR("SPI device is not ready"); + if (!device_is_ready(config->mipi_dev)) { + LOG_ERR("MIPI DBI device is not ready"); return -ENODEV; } - if (!gpio_is_ready_dt(&config->cmd_data)) { - LOG_ERR("Command/Data GPIO device not ready"); - return -ENODEV; - } - - r = gpio_pin_configure_dt(&config->cmd_data, GPIO_OUTPUT); - if (r < 0) { - LOG_ERR("Could not configure command/data GPIO (%d)", r); - return r; - } - - if (config->reset.port != NULL) { - if (!gpio_is_ready_dt(&config->reset)) { - LOG_ERR("Reset GPIO device not ready"); - return -ENODEV; - } - - r = gpio_pin_configure_dt(&config->reset, GPIO_OUTPUT_INACTIVE); - if (r < 0) { - LOG_ERR("Could not configure reset GPIO (%d)", r); - return r; - } - } - ili9xxx_hw_reset(dev); r = ili9xxx_transmit(dev, ILI9XXX_SWRESET, NULL, 0); @@ -463,13 +411,15 @@ static const struct ili9xxx_quirks ili9488_quirks = { \ static const struct ili9xxx_config ili9xxx_config_##n = { \ .quirks = &ili##t##_quirks, \ - .spi = SPI_DT_SPEC_GET(INST_DT_ILI9XXX(n, t), \ - SPI_OP_MODE_MASTER | SPI_WORD_SET(8), \ - 0), \ - .cmd_data = GPIO_DT_SPEC_GET(INST_DT_ILI9XXX(n, t), \ - cmd_data_gpios), \ - .reset = GPIO_DT_SPEC_GET_OR(INST_DT_ILI9XXX(n, t), \ - reset_gpios, {0}), \ + .mipi_dev = DEVICE_DT_GET(DT_PARENT(INST_DT_ILI9XXX(n, t))), \ + .dbi_config = { \ + .mode = MIPI_DBI_MODE_SPI_4WIRE, \ + .config = MIPI_DBI_SPI_CONFIG_DT( \ + INST_DT_ILI9XXX(n, t), \ + SPI_OP_MODE_MASTER | \ + SPI_WORD_SET(8), \ + 0), \ + }, \ .pixel_format = DT_PROP(INST_DT_ILI9XXX(n, t), pixel_format), \ .rotation = DT_PROP(INST_DT_ILI9XXX(n, t), rotation), \ .x_resolution = ILI##t##_X_RES, \ diff --git a/drivers/display/display_ili9xxx.h b/drivers/display/display_ili9xxx.h index 2cd6da98088..ddf8254224e 100644 --- a/drivers/display/display_ili9xxx.h +++ b/drivers/display/display_ili9xxx.h @@ -9,8 +9,7 @@ #ifndef ZEPHYR_DRIVERS_DISPLAY_DISPLAY_ILI9XXX_H_ #define ZEPHYR_DRIVERS_DISPLAY_DISPLAY_ILI9XXX_H_ -#include -#include +#include #include /* Commands/registers. */ @@ -65,10 +64,8 @@ struct ili9xxx_quirks { struct ili9xxx_config { const struct ili9xxx_quirks *quirks; - - struct spi_dt_spec spi; - struct gpio_dt_spec cmd_data; - struct gpio_dt_spec reset; + const struct device *mipi_dev; + struct mipi_dbi_config dbi_config; uint8_t pixel_format; uint16_t rotation; uint16_t x_resolution; diff --git a/dts/bindings/display/ilitek,ili9xxx-common.yaml b/dts/bindings/display/ilitek,ili9xxx-common.yaml index fe1fd852f87..802250002d6 100644 --- a/dts/bindings/display/ilitek,ili9xxx-common.yaml +++ b/dts/bindings/display/ilitek,ili9xxx-common.yaml @@ -4,26 +4,9 @@ description: ILI9XXX display controllers common properties. -include: [spi-device.yaml, display-controller.yaml] +include: [mipi-dbi-spi-device.yaml, display-controller.yaml] properties: - reset-gpios: - type: phandle-array - description: RESET pin. - - The RESET pin of ILI9340 is active low. - If connected directly the MCU pin should be configured - as active low. - - cmd-data-gpios: - type: phandle-array - required: true - description: D/CX pin. - - The D/CX pin of ILI9340 is active low (transmission command byte). - If connected directly the MCU pin should be configured - as active low. - pixel-format: type: int default: 0 diff --git a/tests/drivers/build_all/display/app.overlay b/tests/drivers/build_all/display/app.overlay index 2ce1a401b37..0e115ef6996 100644 --- a/tests/drivers/build_all/display/app.overlay +++ b/tests/drivers/build_all/display/app.overlay @@ -23,27 +23,36 @@ status = "okay"; }; - test_spi: spi@33334444 { + test_mipi_dbi { + compatible = "zephyr,mipi-dbi-spi"; + status = "okay"; + dc-gpios = <&test_gpio 0 0>; + spi-dev = <&test_spi>; #address-cells = <1>; #size-cells = <0>; - compatible = "vnd,spi"; - reg = <0x33334444 0x1000>; - status = "okay"; - clock-frequency = <2000000>; - /* one entry for every devices at spi.dtsi */ - cs-gpios = <&test_gpio 0 0>; - - test_spi_ili9342c: ili9342c@0 { + test_mipi_dbi_ili9342c: ili9342c@0 { compatible = "ilitek,ili9342c"; reg = <0>; - spi-max-frequency = <25000000>; - cmd-data-gpios = <&test_gpio 0 0>; + mipi-max-frequency = <25000000>; pixel-format = <0>; rotation = <270>; width = <320>; height = <240>; }; + }; + + + test_spi: spi@33334444 { + #address-cells = <1>; + #size-cells = <0>; + compatible = "vnd,spi"; + reg = <0x33334444 0x1000>; + status = "okay"; + clock-frequency = <2000000>; + + /* one entry for every devices at spi.dtsi */ + cs-gpios = <&test_gpio 0 0>; test_spi_gc9x01x: gc9x01x@1 { compatible = "galaxycore,gc9x01x"; From 0fc0c0fe3fc9b957e518d925b36f540c3ac3e9c2 Mon Sep 17 00:00:00 2001 From: Daniel DeGrasse Date: Mon, 30 Oct 2023 13:23:14 -0500 Subject: [PATCH 3225/3723] docs: migration-guide-3.6: Add note about migrating ILI9XXX displays Add note describing required devicetree changes to migrate ILI9XXX based displays to use new MIPI DBI SPI driver, instead of directly using the SPI API. Signed-off-by: Daniel DeGrasse --- doc/releases/migration-guide-3.6.rst | 40 ++++++++++++++++++++++++++++ 1 file changed, 40 insertions(+) diff --git a/doc/releases/migration-guide-3.6.rst b/doc/releases/migration-guide-3.6.rst index e44293b570d..c028555890f 100644 --- a/doc/releases/migration-guide-3.6.rst +++ b/doc/releases/migration-guide-3.6.rst @@ -228,6 +228,46 @@ Device Drivers and Device Tree :dtcompatible:`microchip,mcp3208` devicetree bindings were renamed from ``channel`` to the common ``input``, making it possible to use the various ADC DT macros with Microchip MCP320x ADC devices. +* ILI9XXX based displays now use the MIPI DBI driver class. These displays + must now be declared within a MIPI DBI driver wrapper device, which will + manage interfacing with the display. For an example, see below: + + .. code-block:: devicetree + + /* Legacy ILI9XXX display definition */ + &spi2 { + ili9340: ili9340@0 { + compatible = "ilitek,ili9340"; + reg = <0>; + spi-max-frequency = <32000000>; + reset-gpios = <&gpio0 6 GPIO_ACTIVE_LOW>; + cmd-data-gpios = <&gpio0 12 GPIO_ACTIVE_LOW>; + rotation = <270>; + width = <320>; + height = <240>; + }; + }; + + /* New display definition with MIPI DBI device */ + + mipi_dbi { + compatible = "zephyr,mipi-dbi-spi"; + reset-gpios = <&gpio0 6 GPIO_ACTIVE_LOW>; + dc-gpios = <&gpio0 12 GPIO_ACTIVE_LOW>; + spi-dev = <&spi2>; + #address-cells = <1>; + #size-cells = <0>; + + ili9340: ili9340@0 { + compatible = "ilitek,ili9340"; + reg = <0>; + mipi-max-frequency = <32000000>; + rotation = <270>; + width = <320>; + height = <240>; + }; + }; + * The :dtcompatible:`st,stm32h7-fdcan` CAN controller driver now supports configuring the domain/kernel clock via devicetree. Previously, the driver only supported using the PLL1_Q clock for kernel clock, but now it defaults to the HSE clock, which is the chip default. Boards that From d5b68bad12d42de67fc92f5c2d20bedfe02a0e54 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Stine=20=C3=85kredalen?= Date: Mon, 22 Jan 2024 04:56:04 -0800 Subject: [PATCH 3226/3723] tests: Bluetooth: Mesh: add proxy solicitation bsim test MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * Test that beacon is received after solicitation * Test for replay attack Signed-off-by: Stine Åkredalen --- tests/bsim/bluetooth/mesh/CMakeLists.txt | 6 + tests/bsim/bluetooth/mesh/compile.sh | 3 + tests/bsim/bluetooth/mesh/overlay_gatt.conf | 2 - tests/bsim/bluetooth/mesh/src/main.c | 6 + .../bsim/bluetooth/mesh/src/test_proxy_sol.c | 310 ++++++++++++++++++ .../proxy_sol/sol_beacon_rcvd.sh | 19 ++ .../tests_scripts/proxy_sol/sol_replay.sh | 45 +++ 7 files changed, 389 insertions(+), 2 deletions(-) create mode 100644 tests/bsim/bluetooth/mesh/src/test_proxy_sol.c create mode 100755 tests/bsim/bluetooth/mesh/tests_scripts/proxy_sol/sol_beacon_rcvd.sh create mode 100755 tests/bsim/bluetooth/mesh/tests_scripts/proxy_sol/sol_replay.sh diff --git a/tests/bsim/bluetooth/mesh/CMakeLists.txt b/tests/bsim/bluetooth/mesh/CMakeLists.txt index 70190be7840..3b9a63126ae 100644 --- a/tests/bsim/bluetooth/mesh/CMakeLists.txt +++ b/tests/bsim/bluetooth/mesh/CMakeLists.txt @@ -32,6 +32,12 @@ if(CONFIG_BT_MESH_USES_MBEDTLS_PSA) ) endif() +if(CONFIG_BT_MESH_GATT_PROXY AND CONFIG_BT_MESH_PROXY_SOLICITATION) + target_sources(app PRIVATE + src/test_proxy_sol.c + ) +endif() + elseif(CONFIG_BT_MESH_GATT_PROXY) target_sources(app PRIVATE diff --git a/tests/bsim/bluetooth/mesh/compile.sh b/tests/bsim/bluetooth/mesh/compile.sh index 06557ef0ebb..de112f96afc 100755 --- a/tests/bsim/bluetooth/mesh/compile.sh +++ b/tests/bsim/bluetooth/mesh/compile.sh @@ -26,5 +26,8 @@ app=tests/bsim/bluetooth/mesh conf_overlay="overlay_pst.conf;overlay_psa.conf" c app=tests/bsim/bluetooth/mesh conf_overlay="overlay_gatt.conf;overlay_psa.conf" compile app=tests/bsim/bluetooth/mesh conf_overlay="overlay_low_lat.conf;overlay_psa.conf" compile app=tests/bsim/bluetooth/mesh conf_overlay="overlay_gatt.conf;overlay_low_lat.conf" compile +app=tests/bsim/bluetooth/mesh conf_overlay="overlay_pst.conf;overlay_gatt.conf" compile +app=tests/bsim/bluetooth/mesh \ + conf_overlay="overlay_pst.conf;overlay_gatt.conf;overlay_psa.conf" compile wait_for_background_jobs diff --git a/tests/bsim/bluetooth/mesh/overlay_gatt.conf b/tests/bsim/bluetooth/mesh/overlay_gatt.conf index 7660313b700..a8ce71afaef 100644 --- a/tests/bsim/bluetooth/mesh/overlay_gatt.conf +++ b/tests/bsim/bluetooth/mesh/overlay_gatt.conf @@ -2,8 +2,6 @@ CONFIG_BT_PERIPHERAL=y CONFIG_BT_MESH_GATT_PROXY=y CONFIG_BT_MESH_PB_GATT=y -CONFIG_BT_MESH_LOW_POWER=n -CONFIG_BT_MESH_FRIEND=n CONFIG_BT_CENTRAL=y CONFIG_BT_MESH_PROXY_CLIENT=y CONFIG_BT_MESH_PROXY_SOLICITATION=y diff --git a/tests/bsim/bluetooth/mesh/src/main.c b/tests/bsim/bluetooth/mesh/src/main.c index 275bb75de69..4375b486741 100644 --- a/tests/bsim/bluetooth/mesh/src/main.c +++ b/tests/bsim/bluetooth/mesh/src/main.c @@ -15,6 +15,9 @@ extern struct bst_test_list *test_dfu_install(struct bst_test_list *test); extern struct bst_test_list *test_blob_pst_install(struct bst_test_list *test); extern struct bst_test_list *test_lcd_install(struct bst_test_list *test); extern struct bst_test_list *test_sar_pst_install(struct bst_test_list *test); +#if (CONFIG_BT_MESH_GATT_PROXY && CONFIG_BT_MESH_PROXY_SOLICITATION) +extern struct bst_test_list *test_proxy_sol_install(struct bst_test_list *test); +#endif #elif defined(CONFIG_BT_MESH_GATT_PROXY) extern struct bst_test_list *test_adv_install(struct bst_test_list *test); extern struct bst_test_list *test_suspend_install(struct bst_test_list *test); @@ -49,6 +52,9 @@ bst_test_install_t test_installers[] = { test_blob_pst_install, test_lcd_install, test_sar_pst_install, +#if (CONFIG_BT_MESH_GATT_PROXY && CONFIG_BT_MESH_PROXY_SOLICITATION) + test_proxy_sol_install, +#endif #elif defined(CONFIG_BT_MESH_GATT_PROXY) test_adv_install, test_suspend_install, diff --git a/tests/bsim/bluetooth/mesh/src/test_proxy_sol.c b/tests/bsim/bluetooth/mesh/src/test_proxy_sol.c new file mode 100644 index 00000000000..9f95496a787 --- /dev/null +++ b/tests/bsim/bluetooth/mesh/src/test_proxy_sol.c @@ -0,0 +1,310 @@ +/* + * Copyright (c) 2024 Nordic Semiconductor + * + * SPDX-License-Identifier: Apache-2.0 + * + * Proxy Solicitation test + */ + +#include "mesh_test.h" +#include "mesh/access.h" +#include "mesh/settings.h" +#include "mesh/net.h" +#include "mesh/crypto.h" +#include "mesh/proxy.h" +#include +#include +#include +#include + +LOG_MODULE_REGISTER(test_proxy_sol, LOG_LEVEL_INF); + +#define WAIT_TIME 60 /*seconds*/ +#define SEM_TIMEOUT 6 /*seconds*/ +#define BEACON_TYPE_NET_ID 0 +#define BEACON_TYPE_PRIVATE_NET_ID 2 +#define BEACON_NET_ID_LEN 20 +#define OTHER_ADV_TYPES_LEN 28 + +static struct bt_mesh_prov prov; +static struct bt_mesh_cfg_cli cfg_cli; +static struct bt_mesh_priv_beacon_cli priv_beacon_cli; +static struct bt_mesh_od_priv_proxy_cli od_priv_proxy_cli; +static struct k_sem beacon_sem; + +static const struct bt_mesh_test_cfg tester_cfg = { + .addr = 0x0001, + .dev_key = {0x01}, +}; +static const struct bt_mesh_test_cfg iut_cfg = { + .addr = 0x0002, + .dev_key = {0x02}, +}; + +static struct bt_mesh_model models[] = { + BT_MESH_MODEL_CFG_SRV, + BT_MESH_MODEL_CFG_CLI(&cfg_cli), + BT_MESH_MODEL_PRIV_BEACON_SRV, + BT_MESH_MODEL_PRIV_BEACON_CLI(&priv_beacon_cli), + BT_MESH_MODEL_OD_PRIV_PROXY_SRV, + BT_MESH_MODEL_OD_PRIV_PROXY_CLI(&od_priv_proxy_cli) +}; + +static struct bt_mesh_elem elems[] = { + BT_MESH_ELEM(0, models, BT_MESH_MODEL_NONE), +}; + +static const struct bt_mesh_comp comp = { + .cid = TEST_VND_COMPANY_ID, + .vid = 0xaaaa, + .pid = 0xbbbb, + .elem = elems, + .elem_count = ARRAY_SIZE(elems), +}; + +static bool is_tester_address(void) +{ + return bt_mesh_primary_addr() == tester_cfg.addr; +} + +static uint8_t proxy_adv_type_get(uint8_t adv_type, struct net_buf_simple *buf) +{ + uint8_t type; + uint8_t len = buf->len; + + if (adv_type != BT_GAP_ADV_TYPE_ADV_IND || len < 12) { + return 0xFF; + } + + (void)net_buf_simple_pull_mem(buf, 11); + type = net_buf_simple_pull_u8(buf); + + if (len != ((type == BEACON_TYPE_NET_ID) ? BEACON_NET_ID_LEN : OTHER_ADV_TYPES_LEN)) { + return 0xFF; + } + + return type; +} + +static void scan_recv(const struct bt_le_scan_recv_info *info, struct net_buf_simple *ad) +{ + uint8_t type = proxy_adv_type_get(info->adv_type, ad); + + if (is_tester_address() && type == BEACON_TYPE_PRIVATE_NET_ID) { + k_sem_give(&beacon_sem); + } +} + +static struct bt_le_scan_cb scan_cb = { + .recv = scan_recv, +}; + +static void tester_configure(void) +{ + uint8_t err, status; + + k_sem_init(&beacon_sem, 0, 1); + bt_le_scan_cb_register(&scan_cb); + + bt_mesh_test_cfg_set(NULL, WAIT_TIME); + bt_mesh_device_setup(&prov, &comp); + + ASSERT_OK_MSG(bt_mesh_provision(test_net_key, 0, 0, 0, tester_cfg.addr, tester_cfg.dev_key), + "Node failed to provision"); + + err = bt_mesh_cfg_cli_app_key_add(0, tester_cfg.addr, 0, 0, test_app_key, &status); + if (err || status) { + FAIL("AppKey add failed (err %d, status %u)", err, status); + } +} + +static void iut_configure(void) +{ + uint8_t err, status; + + bt_mesh_test_cfg_set(NULL, WAIT_TIME); + bt_mesh_device_setup(&prov, &comp); + + /* Configurations stored in flash during immediate_replay_attack */ + if (!bt_mesh_is_provisioned()) { + ASSERT_OK_MSG( + bt_mesh_provision(test_net_key, 0, 0, 0, iut_cfg.addr, iut_cfg.dev_key), + "Node failed to provision"); + + err = bt_mesh_cfg_cli_app_key_add(0, iut_cfg.addr, 0, 0, test_app_key, &status); + if (err || status) { + FAIL("AppKey add failed (err %d, status %u)", err, status); + } + err = bt_mesh_cfg_cli_gatt_proxy_set(0, iut_cfg.addr, BT_MESH_GATT_PROXY_DISABLED, + &status); + if (err || status) { + FAIL("Proxy state disable failed (err %d, status %u)", err, status); + } + err = bt_mesh_priv_beacon_cli_gatt_proxy_set(0, iut_cfg.addr, + BT_MESH_GATT_PROXY_DISABLED, &status); + if (err || status) { + FAIL("Private proxy state disable failed (err %d, status %u)", err, status); + } + err = bt_mesh_od_priv_proxy_cli_set(0, iut_cfg.addr, BT_MESH_FEATURE_ENABLED, + &status); + if (err || !status) { + FAIL("On-Demand Private Proxy enable failed (err %d, status %u)", err, + status); + } + } +} + +static void sol_fixed_pdu_create(struct bt_mesh_subnet *sub, struct net_buf_simple *pdu) +{ + uint32_t fixed_seq_n = 2; + + net_buf_simple_add_u8(pdu, sub->keys[SUBNET_KEY_TX_IDX(sub)].msg.nid); + net_buf_simple_add_u8(pdu, 0x80); + net_buf_simple_add_le24(pdu, sys_cpu_to_be24(fixed_seq_n)); + net_buf_simple_add_le16(pdu, sys_cpu_to_be16(bt_mesh_primary_addr())); + net_buf_simple_add_le16(pdu, 0x0000); + + ASSERT_OK(bt_mesh_net_encrypt(&sub->keys[SUBNET_KEY_TX_IDX(sub)].msg.enc, pdu, 0, + BT_MESH_NONCE_SOLICITATION)); + + ASSERT_OK(bt_mesh_net_obfuscate(pdu->data, 0, + &sub->keys[SUBNET_KEY_TX_IDX(sub)].msg.privacy)); + + net_buf_simple_push_u8(pdu, 0); + net_buf_simple_push_le16(pdu, BT_UUID_MESH_PROXY_SOLICITATION_VAL); +} + +static int sol_fixed_pdu_send(void) +{ + NET_BUF_SIMPLE_DEFINE(pdu, 20); + net_buf_simple_init(&pdu, 3); + + struct bt_mesh_subnet *sub = bt_mesh_subnet_find(NULL, NULL); + + uint16_t adv_int = BT_MESH_TRANSMIT_INT(CONFIG_BT_MESH_SOL_ADV_XMIT); + + sol_fixed_pdu_create(sub, &pdu); + + struct bt_data ad[] = { + BT_DATA_BYTES(BT_DATA_FLAGS, (BT_LE_AD_GENERAL | BT_LE_AD_NO_BREDR)), + BT_DATA_BYTES(BT_DATA_UUID16_ALL, + BT_UUID_16_ENCODE(BT_UUID_MESH_PROXY_SOLICITATION_VAL)), + BT_DATA(BT_DATA_SVC_DATA16, pdu.data, pdu.size), + }; + + return bt_mesh_adv_bt_data_send(CONFIG_BT_MESH_SOL_ADV_XMIT, adv_int, ad, 3); +} + +static void test_tester_beacon_rcvd(void) +{ + tester_configure(); + + /* Check that no beacons are currently being picked up by the scanner */ + ASSERT_EQUAL(-EAGAIN, k_sem_take(&beacon_sem, K_SECONDS(SEM_TIMEOUT))); + + ASSERT_OK(bt_mesh_proxy_solicit(0)); + + ASSERT_OK_MSG(k_sem_take(&beacon_sem, K_SECONDS(SEM_TIMEOUT)), + "No beacon (proxy advs) reveiced."); + + PASS(); +} + +static void test_tester_immediate_replay_attack(void) +{ + tester_configure(); + + /* Check that no beacons are currently being picked up by the scanner */ + ASSERT_EQUAL(-EAGAIN, k_sem_take(&beacon_sem, K_SECONDS(SEM_TIMEOUT))); + + /* Send initial solicitation PDU with fixed sequence number */ + ASSERT_OK(sol_fixed_pdu_send()); + + ASSERT_OK_MSG(k_sem_take(&beacon_sem, K_SECONDS(SEM_TIMEOUT)), + "No beacon (proxy advs) reveiced."); + k_sem_reset(&beacon_sem); + + /* Wait for iut proxy advs to time out */ + k_sleep(K_MSEC(200)); + ASSERT_EQUAL(-EAGAIN, k_sem_take(&beacon_sem, K_SECONDS(SEM_TIMEOUT))); + + /* Replay attack */ + ASSERT_OK(sol_fixed_pdu_send()); + + ASSERT_EQUAL(-EAGAIN, k_sem_take(&beacon_sem, K_SECONDS(SEM_TIMEOUT))); + + PASS(); +} + +static void test_tester_power_replay_attack(void) +{ + tester_configure(); + + /* Check that no beacons are currently being picked up by the scanner */ + ASSERT_EQUAL(-EAGAIN, k_sem_take(&beacon_sem, K_SECONDS(SEM_TIMEOUT))); + + /* Replay attack, using standard api, starting with sseq = 0 < fixed sseq */ + for (size_t i = 0; i < 3; i++) { + k_sleep(K_MSEC(100)); + ASSERT_OK(bt_mesh_proxy_solicit(0)); + } + + ASSERT_EQUAL(-EAGAIN, k_sem_take(&beacon_sem, K_SECONDS(SEM_TIMEOUT))); + + /* Send a sol pdu with sseq = 3 > fixed sseq (2) */ + ASSERT_OK(bt_mesh_proxy_solicit(0)); + ASSERT_OK_MSG(k_sem_take(&beacon_sem, K_SECONDS(SEM_TIMEOUT)), + "No beacon (proxy advs) reveiced."); + + PASS(); +} + +static void test_iut_beacon_send(void) +{ + iut_configure(); + k_sleep(K_SECONDS(3 * SEM_TIMEOUT)); + + PASS(); +} + +static void test_iut_immediate_replay_attack(void) +{ + iut_configure(); + k_sleep(K_SECONDS(5 * SEM_TIMEOUT)); + + PASS(); +} + +static void test_iut_power_replay_attack(void) +{ + iut_configure(); + k_sleep(K_SECONDS(4 * SEM_TIMEOUT)); + + PASS(); +} + +#define TEST_CASE(role, name, description) \ + { \ + .test_id = "proxy_sol_" #role "_" #name, \ + .test_descr = description, \ + .test_tick_f = bt_mesh_test_timeout, \ + .test_main_f = test_##role##_##name, \ + } + +static const struct bst_test_instance test_proxy_sol[] = { + + TEST_CASE(tester, beacon_rcvd, "Check for beacon after solicitation"), + TEST_CASE(tester, immediate_replay_attack, "Perform replay attack immediately"), + TEST_CASE(tester, power_replay_attack, "Perform replay attack after power cycle of iut"), + + TEST_CASE(iut, beacon_send, "Respond with beacon after solicitation"), + TEST_CASE(iut, immediate_replay_attack, "Device is under immediate replay attack"), + TEST_CASE(iut, power_replay_attack, "Device is under power cycle replay attack"), + + BSTEST_END_MARKER}; + +struct bst_test_list *test_proxy_sol_install(struct bst_test_list *tests) +{ + tests = bst_add_tests(tests, test_proxy_sol); + return tests; +} diff --git a/tests/bsim/bluetooth/mesh/tests_scripts/proxy_sol/sol_beacon_rcvd.sh b/tests/bsim/bluetooth/mesh/tests_scripts/proxy_sol/sol_beacon_rcvd.sh new file mode 100755 index 00000000000..fb4cc54c7e0 --- /dev/null +++ b/tests/bsim/bluetooth/mesh/tests_scripts/proxy_sol/sol_beacon_rcvd.sh @@ -0,0 +1,19 @@ +#!/usr/bin/env bash +# Copyright 2024 Nordic Semiconductor +# SPDX-License-Identifier: Apache-2.0 + +source $(dirname "${BASH_SOURCE[0]}")/../../_mesh_test.sh + +# Test procedure: +# 1. Initialize and configure tester and iut instances. +# 3. Tester sends a solicitation PDU. +# 4. Tester scans for beacons and expects to receive at least one private net ID advertisement. +overlay="overlay_pst_conf_overlay_gatt_conf" +RunTest proxy_sol_beacon_rcvd \ + proxy_sol_tester_beacon_rcvd \ + proxy_sol_iut_beacon_send + +overlay="overlay_pst_conf_overlay_gatt_conf_overlay_psa_conf" +RunTest proxy_sol_beacon_rcvd_psa \ + proxy_sol_tester_beacon_rcvd \ + proxy_sol_iut_beacon_send diff --git a/tests/bsim/bluetooth/mesh/tests_scripts/proxy_sol/sol_replay.sh b/tests/bsim/bluetooth/mesh/tests_scripts/proxy_sol/sol_replay.sh new file mode 100755 index 00000000000..c3da4435eb1 --- /dev/null +++ b/tests/bsim/bluetooth/mesh/tests_scripts/proxy_sol/sol_replay.sh @@ -0,0 +1,45 @@ +#!/usr/bin/env bash +# Copyright 2024 Nordic Semiconductor +# SPDX-License-Identifier: Apache-2.0 + +source $(dirname "${BASH_SOURCE[0]}")/../../_mesh_test.sh + +## Test persistence of Proxy Solicitation replay protection list + +# Test procedure: +# 1. Initialize and configure tester and IUT instances. +# 2. Tester scans for beacons for a few seconds to verify that none are +# currently advertised from the IUT. +# 3. Tester sends a modified solicitation PDU with a fixed sequence number. +# 4. Tester scans for beacons and expects to receive at least one private net ID advertisement. +# 5. IUT stops all ongoing advertisements (timeout). +# 6. Tester re-sends the same fixed solicitation PDU, and scans to verify that +# no beacons are received. +# 7. The IUT is rebooted. +# 8. Tester re-sends the same fixed solicitation PDU, and scans to verify that no +# beacons are received. +# 9. Tester sends a new solicitation PDU, with a new and unique sequence number, +# and scans to verify that a beacon is received. +overlay="overlay_pst_conf_overlay_gatt_conf" +RunTest mesh_srpl_replay_attack \ + proxy_sol_tester_immediate_replay_attack \ + proxy_sol_iut_immediate_replay_attack \ + -flash=../results/mesh_srpl_replay_attack/flash.bin -flash_erase + +overlay="overlay_pst_conf_overlay_gatt_conf" +RunTest mesh_srpl_replay_attack \ + proxy_sol_tester_power_replay_attack \ + proxy_sol_iut_power_replay_attack \ + -flash=../results/mesh_srpl_replay_attack/flash.bin -flash_rm + +overlay="overlay_pst_conf_overlay_gatt_conf_overlay_psa_conf" +RunTest mesh_srpl_replay_attack_psa \ + proxy_sol_tester_immediate_replay_attack \ + proxy_sol_iut_immediate_replay_attack \ + -flash=../results/mesh_srpl_replay_attack_psa/flash.bin -flash_erase + +overlay="overlay_pst_conf_overlay_gatt_conf_overlay_psa_conf" +RunTest mesh_srpl_replay_attack_psa \ + proxy_sol_tester_power_replay_attack \ + proxy_sol_iut_power_replay_attack \ + -flash=../results/mesh_srpl_replay_attack_psa/flash.bin -flash_rm From a1b9f0a7d6b3844a7836d993ae45b6790577d57a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Stine=20=C3=85kredalen?= Date: Wed, 31 Jan 2024 04:03:52 -0800 Subject: [PATCH 3227/3723] Bluetooth: Mesh: fix SRPL always accepting sol pdus with sseq 0 MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Updated logic in srpl_entry_save. Signed-off-by: Stine Åkredalen --- subsys/bluetooth/mesh/solicitation.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/subsys/bluetooth/mesh/solicitation.c b/subsys/bluetooth/mesh/solicitation.c index 642abfd87f1..a2872daecb0 100644 --- a/subsys/bluetooth/mesh/solicitation.c +++ b/subsys/bluetooth/mesh/solicitation.c @@ -65,7 +65,7 @@ static int srpl_entry_save(struct bt_mesh_subnet *sub, uint32_t sseq, uint16_t s entry = srpl_find_by_addr(ssrc); if (entry) { - if (entry->sseq >= sseq && sseq != 0) { + if (entry->sseq >= sseq) { LOG_WRN("Higher or equal SSEQ already saved for this SSRC"); return -EALREADY; } From d1ad1805674a8f2ea79e18dd11830bec599ed144 Mon Sep 17 00:00:00 2001 From: Dawid Niedzwiecki Date: Mon, 22 Jan 2024 10:18:31 +0100 Subject: [PATCH 3228/3723] ec_host_cmd: improve handling IN_PROGRESS commands Add the ec_host_cmd_send_in_progress_continue function which allows continuing execution of a handler, while the ec_host_cmd thread is not blocked and new commands can be handled. That means some long command handlers can executed in the background while the Host Command subsys is not frozen. Signed-off-by: Dawid Niedzwiecki --- include/zephyr/mgmt/ec_host_cmd/ec_host_cmd.h | 20 +++++- subsys/mgmt/ec_host_cmd/ec_host_cmd_handler.c | 69 ++++++++++--------- 2 files changed, 57 insertions(+), 32 deletions(-) diff --git a/include/zephyr/mgmt/ec_host_cmd/ec_host_cmd.h b/include/zephyr/mgmt/ec_host_cmd/ec_host_cmd.h index 018aa60e980..cc0127938e3 100644 --- a/include/zephyr/mgmt/ec_host_cmd/ec_host_cmd.h +++ b/include/zephyr/mgmt/ec_host_cmd/ec_host_cmd.h @@ -79,6 +79,7 @@ enum ec_host_cmd_log_level { }; typedef void (*ec_host_cmd_user_cb_t)(const struct ec_host_cmd_rx_ctx *rx_ctx, void *user_data); +typedef enum ec_host_cmd_status (*ec_host_cmd_in_progress_cb_t)(void *user_data); struct ec_host_cmd { struct ec_host_cmd_rx_ctx rx_ctx; @@ -281,7 +282,7 @@ int ec_host_cmd_init(struct ec_host_cmd_backend *backend); * @retval 0 if successful. */ int ec_host_cmd_send_response(enum ec_host_cmd_status status, - const struct ec_host_cmd_handler_args *args); + const struct ec_host_cmd_handler_args *args); /** * @brief Signal a new host command @@ -346,6 +347,23 @@ bool ec_host_cmd_send_in_progress_ended(void); * @retval The final status or EC_HOST_CMD_UNAVAILABLE if not available. */ enum ec_host_cmd_status ec_host_cmd_send_in_progress_status(void); + +/** + * @brief Continue processing a handler in callback after returning EC_HOST_CMD_IN_PROGRESS. + * + * A Host Command handler may return the EC_HOST_CMD_IN_PROGRESS, but needs to continue work. + * This function should be called before returning EC_HOST_CMD_IN_PROGRESS with a callback that + * will be executed. The return status of the callback will be stored and can be get with the + * ec_host_cmd_send_in_progress_status function. The ec_host_cmd_send_in_progress_ended function + * can be used to check if the callback has ended. + * + * @param[in] cb A callback to be called after returning from a command handler. + * @param[in] user_data User data to be passed to the callback. + * + * @retval EC_HOST_CMD_BUSY if any command is already in progress, EC_HOST_CMD_SUCCESS otherwise + */ +enum ec_host_cmd_status ec_host_cmd_send_in_progress_continue(ec_host_cmd_in_progress_cb_t cb, + void *user_data); #endif /* CONFIG_EC_HOST_CMD_IN_PROGRESS_STATUS */ /** diff --git a/subsys/mgmt/ec_host_cmd/ec_host_cmd_handler.c b/subsys/mgmt/ec_host_cmd/ec_host_cmd_handler.c index b8bf8cfbe6a..b628c891a5b 100644 --- a/subsys/mgmt/ec_host_cmd/ec_host_cmd_handler.c +++ b/subsys/mgmt/ec_host_cmd/ec_host_cmd_handler.c @@ -64,7 +64,10 @@ static bool cmd_in_progress; /* The final result of the last command that has sent EC_HOST_CMD_IN_PROGRESS */ static enum ec_host_cmd_status saved_status = EC_HOST_CMD_UNAVAILABLE; -#endif +static struct k_work work_in_progress; +ec_host_cmd_in_progress_cb_t cb_in_progress; +static void *user_data_in_progress; +#endif /* CONFIG_EC_HOST_CMD_IN_PROGRESS_STATUS */ #ifdef CONFIG_EC_HOST_CMD_LOG_SUPPRESSED static uint16_t suppressed_cmds[CONFIG_EC_HOST_CMD_LOG_SUPPRESSED_NUMBER]; @@ -97,6 +100,36 @@ enum ec_host_cmd_status ec_host_cmd_send_in_progress_status(void) return ret; } + +enum ec_host_cmd_status ec_host_cmd_send_in_progress_continue(ec_host_cmd_in_progress_cb_t cb, + void *user_data) +{ + if (cmd_in_progress) { + return EC_HOST_CMD_BUSY; + } + + cmd_in_progress = true; + cb_in_progress = cb; + user_data_in_progress = user_data; + saved_status = EC_HOST_CMD_UNAVAILABLE; + LOG_INF("HC pending"); + k_work_submit(&work_in_progress); + + return EC_HOST_CMD_SUCCESS; +} + +static void handler_in_progress(struct k_work *work) +{ + if (cb_in_progress != NULL) { + saved_status = cb_in_progress(user_data_in_progress); + LOG_INF("HC pending done, result=%d", saved_status); + } else { + saved_status = EC_HOST_CMD_UNAVAILABLE; + LOG_ERR("HC incorrect IN_PROGRESS callback"); + } + cb_in_progress = NULL; + cmd_in_progress = false; +} #endif /* CONFIG_EC_HOST_CMD_IN_PROGRESS_STATUS */ #ifdef CONFIG_EC_HOST_CMD_LOG_SUPPRESSED @@ -259,36 +292,6 @@ int ec_host_cmd_send_response(enum ec_host_cmd_status status, struct ec_host_cmd *hc = &ec_host_cmd; struct ec_host_cmd_tx_buf *tx = &hc->tx; -#ifdef CONFIG_EC_HOST_CMD_IN_PROGRESS_STATUS - if (cmd_in_progress) { - /* We previously got EC_HOST_CMD_IN_PROGRESS. This must be the completion - * of that command, so save the result code. - */ - LOG_INF("HC pending done, size=%d, result=%d", - args->output_buf_size, status); - - /* Don't support saving response data, so mark the response as unavailable - * in that case. - */ - if (args->output_buf_size != 0) { - saved_status = EC_HOST_CMD_UNAVAILABLE; - } else { - saved_status = status; - } - - /* We can't send the response back to the host now since we already sent - * the in-progress response and the host is on to other things now. - */ - cmd_in_progress = false; - - return EC_HOST_CMD_SUCCESS; - - } else if (status == EC_HOST_CMD_IN_PROGRESS) { - cmd_in_progress = true; - LOG_INF("HC pending"); - } -#endif /* CONFIG_EC_HOST_CMD_IN_PROGRESS_STATUS */ - if (status != EC_HOST_CMD_SUCCESS) { const struct ec_host_cmd_request_header *const rx_header = (const struct ec_host_cmd_request_header *const)hc->rx_ctx.buf; @@ -459,6 +462,10 @@ int ec_host_cmd_init(struct ec_host_cmd_backend *backend) /* Allow writing to rx buff at startup */ k_sem_init(&hc->rx_ready, 0, 1); +#ifdef CONFIG_EC_HOST_CMD_IN_PROGRESS_STATUS + k_work_init(&work_in_progress, handler_in_progress); +#endif /* CONFIG_EC_HOST_CMD_IN_PROGRESS_STATUS */ + handler_tx_buf = hc->tx.buf; handler_rx_buf = hc->rx_ctx.buf; handler_tx_buf_end = handler_tx_buf + CONFIG_EC_HOST_CMD_HANDLER_TX_BUFFER_SIZE; From a059da947c5e2ca73ed678f0fc0c3d4e40556324 Mon Sep 17 00:00:00 2001 From: Dino Li Date: Wed, 8 Nov 2023 14:11:23 +0800 Subject: [PATCH 3229/3723] soc/it8xxx2: add support for raising EC bus to 24MHz This change was made to reduce read/write EC registers latency. Without enabling CONFIG_SOC_IT8XXX2_EC_BUS_24MHZ: - Read EC register 64 times takes 80us latency. - Write EC register 64 times takes 60us latency. With enabling CONFIG_SOC_IT8XXX2_EC_BUS_24MHZ: - Read EC register 64 times takes 40us latency. - Write EC register 64 times takes 30us latency. Signed-off-by: Dino Li --- drivers/adc/adc_ite_it8xxx2.c | 11 +++++++++++ drivers/i2c/i2c_ite_it8xxx2.c | 18 ++++++++++++++++++ drivers/timer/ite_it8xxx2_timer.c | 17 ++++++++++------- soc/riscv/ite_ec/common/check_regs.c | 3 ++- soc/riscv/ite_ec/common/chip_chipregs.h | 10 +++++++++- soc/riscv/ite_ec/it8xxx2/Kconfig.soc | 12 ++++++++++++ soc/riscv/ite_ec/it8xxx2/soc.c | 4 ++++ 7 files changed, 66 insertions(+), 9 deletions(-) diff --git a/drivers/adc/adc_ite_it8xxx2.c b/drivers/adc/adc_ite_it8xxx2.c index 87c010933d4..53aec279fd2 100644 --- a/drivers/adc/adc_ite_it8xxx2.c +++ b/drivers/adc/adc_ite_it8xxx2.c @@ -43,6 +43,12 @@ LOG_MODULE_REGISTER(adc_ite_it8xxx2); #define ADC_13_16_FULL_SCALE_MASK GENMASK(3, 0) #endif +#ifdef CONFIG_SOC_IT8XXX2_EC_BUS_24MHZ +/* Select analog clock division factor */ +#define ADC_SACLKDIV_MASK GENMASK(6, 4) +#define ADC_SACLKDIV(div) FIELD_PREP(ADC_SACLKDIV_MASK, div) +#endif + /* List of ADC channels. */ enum chip_adc_channel { CHIP_ADC_CH0 = 0, @@ -451,6 +457,11 @@ static int adc_it8xxx2_init(const struct device *dev) * SCLKDIV has to be equal to or greater than 1h; */ adc_regs->ADCCTL = 1; + +#ifdef CONFIG_SOC_IT8XXX2_EC_BUS_24MHZ + adc_regs->ADCCTL1 = + (adc_regs->ADCCTL1 & ~ADC_SACLKDIV_MASK) | ADC_SACLKDIV(2); +#endif /* * Enable this bit, and data of VCHxDATL/VCHxDATM will be * kept until data valid is cleared. diff --git a/drivers/i2c/i2c_ite_it8xxx2.c b/drivers/i2c/i2c_ite_it8xxx2.c index b931a932030..734a38e5b25 100644 --- a/drivers/i2c/i2c_ite_it8xxx2.c +++ b/drivers/i2c/i2c_ite_it8xxx2.c @@ -210,6 +210,15 @@ static void i2c_standard_port_timing_regs_400khz(uint8_t port) /* Port clock frequency depends on setting of timing registers. */ IT8XXX2_SMB_SCLKTS(port) = 0; /* Suggested setting of timing registers of 400kHz. */ +#ifdef CONFIG_SOC_IT8XXX2_EC_BUS_24MHZ + IT8XXX2_SMB_4P7USL = 0x16; + IT8XXX2_SMB_4P0USL = 0x11; + IT8XXX2_SMB_300NS = 0x8; + IT8XXX2_SMB_250NS = 0x8; + IT8XXX2_SMB_45P3USL = 0xff; + IT8XXX2_SMB_45P3USH = 0x3; + IT8XXX2_SMB_4P7A4P0H = 0; +#else IT8XXX2_SMB_4P7USL = 0x3; IT8XXX2_SMB_4P0USL = 0; IT8XXX2_SMB_300NS = 0x1; @@ -217,6 +226,7 @@ static void i2c_standard_port_timing_regs_400khz(uint8_t port) IT8XXX2_SMB_45P3USL = 0x6a; IT8XXX2_SMB_45P3USH = 0x1; IT8XXX2_SMB_4P7A4P0H = 0; +#endif } /* Set clock frequency for i2c port A, B , or C */ @@ -1259,6 +1269,14 @@ BUILD_ASSERT((DT_PROP(DT_NODELABEL(i2c2), fifo_enable) == false), "Channel C cannot use FIFO mode."); #endif +#ifdef CONFIG_SOC_IT8XXX2_EC_BUS_24MHZ +#define I2C_IT8XXX2_CHECK_SUPPORTED_CLOCK(inst) \ + BUILD_ASSERT((DT_INST_PROP(inst, clock_frequency) == \ + I2C_BITRATE_FAST), "Only supports 400 KHz"); + +DT_INST_FOREACH_STATUS_OKAY(I2C_IT8XXX2_CHECK_SUPPORTED_CLOCK) +#endif + #define I2C_ITE_IT8XXX2_INIT(inst) \ PINCTRL_DT_INST_DEFINE(inst); \ BUILD_ASSERT((DT_INST_PROP(inst, clock_frequency) == \ diff --git a/drivers/timer/ite_it8xxx2_timer.c b/drivers/timer/ite_it8xxx2_timer.c index c29c978d189..69d42790ac7 100644 --- a/drivers/timer/ite_it8xxx2_timer.c +++ b/drivers/timer/ite_it8xxx2_timer.c @@ -16,6 +16,8 @@ #include LOG_MODULE_REGISTER(timer, LOG_LEVEL_ERR); +#define COUNT_1US (EC_FREQ / USEC_PER_SEC - 1) + BUILD_ASSERT(CONFIG_SYS_CLOCK_HW_CYCLES_PER_SEC == 32768, "ITE RTOS timer HW frequency is fixed at 32768Hz"); @@ -332,8 +334,8 @@ static int timer_init(enum ext_timer_idx ext_timer, hw_cnt = MS_TO_COUNT(1024, ms); else if (clock_source_sel == EXT_PSR_32) hw_cnt = MS_TO_COUNT(32, ms); - else if (clock_source_sel == EXT_PSR_8M) - hw_cnt = 8000 * ms; + else if (clock_source_sel == EXT_PSR_EC_CLK) + hw_cnt = MS_TO_COUNT(EC_FREQ, ms); else { LOG_ERR("Timer %d clock source error !", ext_timer); return -1; @@ -424,7 +426,7 @@ static int sys_clock_driver_init(void) IT8XXX2_EXT_CTRLX(BUSY_WAIT_L_TIMER) |= IT8XXX2_EXT_ETXCOMB; /* Set 32-bit timer6 to count-- every 1us */ - ret = timer_init(BUSY_WAIT_H_TIMER, EXT_PSR_8M, EXT_RAW_CNT, + ret = timer_init(BUSY_WAIT_H_TIMER, EXT_PSR_EC_CLK, EXT_RAW_CNT, BUSY_WAIT_TIMER_H_MAX_CNT, EXT_FIRST_TIME_ENABLE, BUSY_WAIT_H_TIMER_IRQ, BUSY_WAIT_H_TIMER_FLAG, EXT_WITHOUT_TIMER_INT, EXT_START_TIMER); @@ -438,11 +440,12 @@ static int sys_clock_driver_init(void) * NOTE: When the timer5 count down to overflow in combinational * mode, timer6 counter will automatically decrease one count * and timer5 will automatically re-start counting down - * from 0x7. Timer5 clock source is 8MHz (=0.125ns), so the - * time period from 0x7 to overflow is 0.125ns * 8 = 1us. + * from COUNT_1US. Timer5 clock source is EC_FREQ, so the + * time period from COUNT_1US to overflow is + * (1 / EC_FREQ) * (EC_FREQ / USEC_PER_SEC) = 1us. */ - ret = timer_init(BUSY_WAIT_L_TIMER, EXT_PSR_8M, EXT_RAW_CNT, - 0x7, EXT_FIRST_TIME_ENABLE, + ret = timer_init(BUSY_WAIT_L_TIMER, EXT_PSR_EC_CLK, EXT_RAW_CNT, + COUNT_1US, EXT_FIRST_TIME_ENABLE, BUSY_WAIT_L_TIMER_IRQ, BUSY_WAIT_L_TIMER_FLAG, EXT_WITHOUT_TIMER_INT, EXT_START_TIMER); if (ret < 0) { diff --git a/soc/riscv/ite_ec/common/check_regs.c b/soc/riscv/ite_ec/common/check_regs.c index c655f850dac..2fb6dcb4128 100644 --- a/soc/riscv/ite_ec/common/check_regs.c +++ b/soc/riscv/ite_ec/common/check_regs.c @@ -198,7 +198,7 @@ IT8XXX2_REG_OFFSET_CHECK(kscan_it8xxx2_regs, KBS_KSIGDAT, 0x08); IT8XXX2_REG_OFFSET_CHECK(kscan_it8xxx2_regs, KBS_KSOLGOEN, 0x0e); /* ADC register structure check */ -IT8XXX2_REG_SIZE_CHECK(adc_it8xxx2_regs, 0x6d); +IT8XXX2_REG_SIZE_CHECK(adc_it8xxx2_regs, 0xf1); IT8XXX2_REG_OFFSET_CHECK(adc_it8xxx2_regs, ADCGCR, 0x03); IT8XXX2_REG_OFFSET_CHECK(adc_it8xxx2_regs, VCH0DATM, 0x19); IT8XXX2_REG_OFFSET_CHECK(adc_it8xxx2_regs, ADCIVMFSCS1, 0x55); @@ -207,6 +207,7 @@ IT8XXX2_REG_OFFSET_CHECK(adc_it8xxx2_regs, ADCIVMFSCS3, 0x57); IT8XXX2_REG_OFFSET_CHECK(adc_it8xxx2_regs, adc_vchs_ctrl[0].VCHCTL, 0x60); IT8XXX2_REG_OFFSET_CHECK(adc_it8xxx2_regs, adc_vchs_ctrl[2].VCHDATM, 0x67); IT8XXX2_REG_OFFSET_CHECK(adc_it8xxx2_regs, ADCDVSTS2, 0x6c); +IT8XXX2_REG_OFFSET_CHECK(adc_it8xxx2_regs, ADCCTL1, 0xf0); /* Watchdog register structure check */ IT8XXX2_REG_SIZE_CHECK(wdt_it8xxx2_regs, 0x0f); diff --git a/soc/riscv/ite_ec/common/chip_chipregs.h b/soc/riscv/ite_ec/common/chip_chipregs.h index 240a8bb8234..c7d640fee33 100644 --- a/soc/riscv/ite_ec/common/chip_chipregs.h +++ b/soc/riscv/ite_ec/common/chip_chipregs.h @@ -38,8 +38,12 @@ * EC clock frequency (PWM and tachometer driver need it to reply * to api or calculate RPM) */ +#ifdef CONFIG_SOC_IT8XXX2_EC_BUS_24MHZ +#define EC_FREQ MHZ(24) +#else #define EC_FREQ MHZ(8) +#endif /* --- General Control (GCTRL) --- */ #define IT8XXX2_GCTRL_BASE 0x00F02000 @@ -403,7 +407,7 @@ enum ext_clk_src_sel { EXT_PSR_32P768K = 0, EXT_PSR_1P024K, EXT_PSR_32, - EXT_PSR_8M, + EXT_PSR_EC_CLK, }; /* * 24-bit timers: external timer 3, 5, and 7 @@ -1181,6 +1185,10 @@ struct adc_it8xxx2_regs { struct adc_vchs_ctrl_t adc_vchs_ctrl[4]; /* 0x6c: ADC Data Valid Status 2 */ volatile uint8_t ADCDVSTS2; + /* 0x6d-0xef: Reserved4 */ + volatile uint8_t reserved4[131]; + /* 0xf0: ADC Clock Control Register 1 */ + volatile uint8_t ADCCTL1; }; #endif /* !__ASSEMBLER__ */ diff --git a/soc/riscv/ite_ec/it8xxx2/Kconfig.soc b/soc/riscv/ite_ec/it8xxx2/Kconfig.soc index 800a2a9dafd..d918318dfaa 100644 --- a/soc/riscv/ite_ec/it8xxx2/Kconfig.soc +++ b/soc/riscv/ite_ec/it8xxx2/Kconfig.soc @@ -61,14 +61,17 @@ config SOC_IT81202_CX config SOC_IT82202_AX bool "IT82202 AX version" select SOC_IT8XXX2_REG_SET_V2 + select SOC_IT8XXX2_EC_BUS_24MHZ if !DT_HAS_ITE_IT82XX2_USB_ENABLED config SOC_IT82302_AX bool "IT82302 AX version" select SOC_IT8XXX2_REG_SET_V2 + select SOC_IT8XXX2_EC_BUS_24MHZ if !DT_HAS_ITE_IT82XX2_USB_ENABLED config SOC_IT82002_AW bool "IT82002 AW version" select SOC_IT8XXX2_REG_SET_V2 + select SOC_IT8XXX2_EC_BUS_24MHZ if !DT_HAS_ITE_IT82XX2_USB_ENABLED endchoice @@ -106,6 +109,15 @@ config SOC_IT8XXX2_CPU_IDLE_GATING gated by individual drivers. When this option is disabled, CPU idle mode is always permitted. +config SOC_IT8XXX2_EC_BUS_24MHZ + bool "EC bus is 24MHz" + help + Raise EC bus to 24MHz (default is 8MHz). + This reduces read/write EC registers latency by 50%. + NOTE: There is limitation to enabling this config on it81xx2 series. + The clock_frequency of ite,it8xxx2-i2c node (i2c0, i2c1, and i2c2) will + be fixed at 400KHz. + choice prompt "Clock source for PLL reference clock" diff --git a/soc/riscv/ite_ec/it8xxx2/soc.c b/soc/riscv/ite_ec/it8xxx2/soc.c index 48e9360e208..c1ab2e13562 100644 --- a/soc/riscv/ite_ec/it8xxx2/soc.c +++ b/soc/riscv/ite_ec/it8xxx2/soc.c @@ -110,7 +110,11 @@ static const struct pll_config_t pll_configuration[] = { .div_uart = 1, .div_smb = 1, .div_sspi = 1, +#ifdef CONFIG_SOC_IT8XXX2_EC_BUS_24MHZ + .div_ec = 1, +#else .div_ec = 6, +#endif .div_jtag = 1, .div_pwm = 0, .div_usbpd = 5} From 59a87038df1c17cc31adbc9402cba9b83c35784c Mon Sep 17 00:00:00 2001 From: Jeff Welder Date: Wed, 17 Jan 2024 15:01:17 -0500 Subject: [PATCH 3230/3723] drivers: veml7700: Add white channel Add the white light channel to the veml7700 sensor to allow for correction of light sources with strong infrared content. Signed-off-by: Jeff Welder --- drivers/sensor/veml7700/veml7700.c | 29 +++++++++++++++++++++++- include/zephyr/drivers/sensor/veml7700.h | 10 ++++++++ 2 files changed, 38 insertions(+), 1 deletion(-) diff --git a/drivers/sensor/veml7700/veml7700.c b/drivers/sensor/veml7700/veml7700.c index e008b725167..7aed13cbdca 100644 --- a/drivers/sensor/veml7700/veml7700.c +++ b/drivers/sensor/veml7700/veml7700.c @@ -1,5 +1,6 @@ /* * Copyright (c) 2023 Andreas Kilian + * Copyright (c) 2024 Jeff Welder (Ellenby Technologies, Inc.) * * SPDX-License-Identifier: Apache-2.0 */ @@ -87,6 +88,7 @@ struct veml7700_data { uint16_t thresh_low; uint16_t als_counts; uint32_t als_lux; + uint16_t white_counts; uint32_t int_flags; }; @@ -293,6 +295,23 @@ static int veml7700_fetch_als(const struct device *dev) return 0; } +static int veml7700_fetch_white(const struct device *dev) +{ + struct veml7700_data *data = dev->data; + uint16_t counts; + int ret; + + ret = veml7700_read(dev, VEML7700_CMDCODE_WHITE, &counts); + if (ret < 0) { + return ret; + } + + data->white_counts = counts; + LOG_DBG("Read White Light measurement: counts=%d", data->white_counts); + + return 0; +} + static int veml7700_fetch_int_flags(const struct device *dev) { struct veml7700_data *data = dev->data; @@ -428,6 +447,8 @@ static int veml7700_sample_fetch(const struct device *dev, } else { return -ENOTSUP; } + } else if ((enum sensor_channel_veml7700)chan == SENSOR_CHAN_VEML7700_WHITE_RAW_COUNTS) { + return veml7700_fetch_white(dev); } else if (chan == SENSOR_CHAN_ALL) { data = dev->data; if (data->int_mode != VEML7700_INT_DISABLED) { @@ -436,7 +457,10 @@ static int veml7700_sample_fetch(const struct device *dev, return ret; } } - + ret = veml7700_fetch_white(dev); + if (ret < 0) { + return ret; + } return veml7700_fetch_als(dev); } else { return -ENOTSUP; @@ -453,6 +477,8 @@ static int veml7700_channel_get(const struct device *dev, val->val1 = data->als_lux; } else if ((enum sensor_channel_veml7700)chan == SENSOR_CHAN_VEML7700_RAW_COUNTS) { val->val1 = data->als_counts; + } else if ((enum sensor_channel_veml7700)chan == SENSOR_CHAN_VEML7700_WHITE_RAW_COUNTS) { + val->val1 = data->white_counts; } else if ((enum sensor_channel_veml7700)chan == SENSOR_CHAN_VEML7700_INTERRUPT) { val->val1 = data->int_flags; } else { @@ -514,6 +540,7 @@ static int veml7700_init(const struct device *dev) data->int_mode = VEML7700_INT_DISABLED; data->als_counts = 0; data->als_lux = 0; + data->white_counts = 0; data->shut_down = (conf->psm != VEML7700_PSM_DISABLED) ? 0 : 1; /* Initialize sensor configuration */ diff --git a/include/zephyr/drivers/sensor/veml7700.h b/include/zephyr/drivers/sensor/veml7700.h index 05bcca14252..c2a716ed663 100644 --- a/include/zephyr/drivers/sensor/veml7700.h +++ b/include/zephyr/drivers/sensor/veml7700.h @@ -1,5 +1,6 @@ /* * Copyright (c) 2023 Andreas Kilian + * Copyright (c) 2024 Jeff Welder (Ellenby Technologies, Inc.) * * SPDX-License-Identifier: Apache-2.0 */ @@ -134,6 +135,15 @@ enum sensor_channel_veml7700 { */ SENSOR_CHAN_VEML7700_RAW_COUNTS = SENSOR_CHAN_PRIV_START, + /** + * @brief Channel for white light sensor values. + * + * This channel is the White Channel count output of the sensor. + * The white channel can be used to correct for light sources with + * strong infrared content in the 750-800nm spectrum. + */ + SENSOR_CHAN_VEML7700_WHITE_RAW_COUNTS, + /** * @brief This channel is used to query the ALS interrupt state (ALS_INT). * From df5548dddb7438b621efdeddf0e1d04e7d063f30 Mon Sep 17 00:00:00 2001 From: Aleksander Wasaznik Date: Wed, 24 Jan 2024 17:02:03 +0100 Subject: [PATCH 3231/3723] Bluetooth: Host: Remove overspecifying test for `bt_buf_get_evt` The next commit will change the behavior of `bt_buf_get_evt` to no longer use `bt_buf_get_cmd_complete`. We have to remove the test that would prevent this. Signed-off-by: Aleksander Wasaznik --- .../src/test_suite_hci_evt_cmd.c | 114 ------------------ 1 file changed, 114 deletions(-) diff --git a/tests/bluetooth/host/buf/bt_buf_get_evt/src/test_suite_hci_evt_cmd.c b/tests/bluetooth/host/buf/bt_buf_get_evt/src/test_suite_hci_evt_cmd.c index 8c4c1ca0b5e..2c4d2fed7aa 100644 --- a/tests/bluetooth/host/buf/bt_buf_get_evt/src/test_suite_hci_evt_cmd.c +++ b/tests/bluetooth/host/buf/bt_buf_get_evt/src/test_suite_hci_evt_cmd.c @@ -39,117 +39,3 @@ static struct net_buf_pool *get_memory_pool(void) return memory_pool; } - -ZTEST_SUITE(bt_buf_get_evt_cmd_type_returns_null, NULL, NULL, NULL, NULL, NULL); -ZTEST_SUITE(bt_buf_get_evt_cmd_type_returns_not_null, NULL, NULL, NULL, NULL, NULL); - -/* - * Return value from bt_buf_get_evt() should match the value returned - * from bt_buf_get_cmd_complete() which is NULL - * - * Constraints: - * - Event type 'BT_HCI_EVT_CMD_COMPLETE' or 'BT_HCI_EVT_CMD_STATUS' - * -'discardable' flag value doesn't care - * - bt_buf_get_cmd_complete() returns NULL - * - Timeout value is a positive non-zero value - * - * Expected behaviour: - * - net_buf_alloc() to be called with the correct memory allocation pool - * and the same timeout value passed to bt_buf_get_evt() - * - bt_buf_get_evt() returns NULL - */ -ZTEST(bt_buf_get_evt_cmd_type_returns_null, test_return_value_matches_bt_buf_get_cmd_complete_null) -{ - struct net_buf *returned_buf; - k_timeout_t timeout = Z_TIMEOUT_TICKS(1000); - struct testing_params const *params_vector; - uint8_t evt; - bool discardable; - - for (size_t i = 0; i < (ARRAY_SIZE(testing_params_lut)); i++) { - - /* Register resets */ - NET_BUF_FFF_FAKES_LIST(RESET_FAKE); - - params_vector = &testing_params_lut[i]; - evt = params_vector->evt; - discardable = params_vector->discardable; - - zassert_true((evt == BT_HCI_EVT_CMD_COMPLETE || evt == BT_HCI_EVT_CMD_STATUS), - "Invalid event type %u to this test", evt); - - bt_dev.sent_cmd = NULL; - net_buf_alloc_fixed_fake.return_val = NULL; - - returned_buf = bt_buf_get_evt(evt, discardable, timeout); - - expect_single_call_net_buf_alloc(get_memory_pool(), &timeout); - expect_not_called_net_buf_reserve(); - expect_not_called_net_buf_ref(); - - zassert_is_null(returned_buf, - "bt_buf_get_evt() returned non-NULL value while expecting NULL"); - } -} - -/* - * Return value from bt_buf_get_evt() should match the value returned - * from bt_buf_get_cmd_complete() which isn't NULL - * - * Constraints: - * - Event type 'BT_HCI_EVT_CMD_COMPLETE' or 'BT_HCI_EVT_CMD_STATUS' - * -'discardable' flag value doesn't care - * - bt_buf_get_cmd_complete() returns a valid reference - * - Timeout value is a positive non-zero value - * - * Expected behaviour: - * - net_buf_alloc() to be called with the correct memory allocation pool - * and the same timeout value passed to bt_buf_get_evt() - * - bt_buf_get_evt() returns the same reference returned by net_buf_alloc_fixed() - */ -ZTEST(bt_buf_get_evt_cmd_type_returns_not_null, - test_return_value_matches_bt_buf_get_cmd_complete_not_null) -{ - const size_t user_data_size = sizeof(struct bt_buf_data); - uint8_t *expected_buf_data[sizeof(struct net_buf) + user_data_size]; - struct net_buf *expected_buf = (struct net_buf *)expected_buf_data; - struct net_buf *returned_buf; - uint8_t returned_buffer_type; - k_timeout_t timeout = Z_TIMEOUT_TICKS(1000); - struct testing_params const *params_vector; - uint8_t evt; - bool discardable; - - expected_buf->user_data_size = user_data_size; - - for (size_t i = 0; i < (ARRAY_SIZE(testing_params_lut)); i++) { - - /* Register resets */ - NET_BUF_FFF_FAKES_LIST(RESET_FAKE); - - params_vector = &testing_params_lut[i]; - evt = params_vector->evt; - discardable = params_vector->discardable; - - zassert_true((evt == BT_HCI_EVT_CMD_COMPLETE || evt == BT_HCI_EVT_CMD_STATUS), - "Invalid event type %u to this test", evt); - - bt_dev.sent_cmd = NULL; - net_buf_alloc_fixed_fake.return_val = expected_buf; - - returned_buf = bt_buf_get_evt(evt, discardable, timeout); - - expect_single_call_net_buf_alloc(get_memory_pool(), &timeout); - expect_single_call_net_buf_reserve(expected_buf); - expect_not_called_net_buf_ref(); - - zassert_equal(returned_buf, expected_buf, - "bt_buf_get_evt() returned incorrect buffer pointer value"); - - returned_buffer_type = bt_buf_get_type(returned_buf); - zassert_equal( - returned_buffer_type, BT_BUF_EVT, - "bt_buf_get_evt() returned incorrect buffer type %u, expected %u (%s)", - returned_buffer_type, BT_BUF_EVT, STRINGIFY(BT_BUF_EVT)); - } -} From 1cb83a81f09c696d2a8eeb54398c150a64fd498f Mon Sep 17 00:00:00 2001 From: Aleksander Wasaznik Date: Mon, 22 Jan 2024 15:51:24 +0100 Subject: [PATCH 3232/3723] Bluetooth: Host: Remove use of `bt_buf_get_cmd_complete` `bt_buf_get_cmd_complete` is broken due to https://github.com/zephyrproject-rtos/zephyr/issues/64158, and fixing it would require changing its signature and put even more complexity into the HCI drivers, as it would require the drivers to perform an even deeper peek into the event in order to observe the opcode. Instead of the above, this patch removes the use of `bt_buf_get_cmd_complete` and adds logic to allow the host to accept command complete events in normal event buffers. The above means performing a copy into the destination buffer, which is the original command buffer. This is a small inefficiency for now, but we should strive to redesign the host into a streaming architecture as much as possible and handle events immediately instead of retaining buffers. This fixes https://github.com/zephyrproject-rtos/zephyr/issues/64158: Like all command completed events, the completion event for `BT_HCI_OP_HOST_NUM_COMPLETED_PACKETS` is now placed in normal event buffers. The the logic where the host discards this event is already present. Since it's discarded, it will not interfere with the logic around `bt_dev.cmd_send`. Signed-off-by: Aleksander Wasaznik --- subsys/bluetooth/host/buf.c | 3 --- subsys/bluetooth/host/hci_core.c | 46 ++++++++++++++++++++++++-------- 2 files changed, 35 insertions(+), 14 deletions(-) diff --git a/subsys/bluetooth/host/buf.c b/subsys/bluetooth/host/buf.c index 296d2aa0b5e..2623871c502 100644 --- a/subsys/bluetooth/host/buf.c +++ b/subsys/bluetooth/host/buf.c @@ -120,9 +120,6 @@ struct net_buf *bt_buf_get_evt(uint8_t evt, bool discardable, return buf; } #endif /* CONFIG_BT_CONN || CONFIG_BT_ISO */ - case BT_HCI_EVT_CMD_COMPLETE: - case BT_HCI_EVT_CMD_STATUS: - return bt_buf_get_cmd_complete(timeout); default: if (discardable) { struct net_buf *buf; diff --git a/subsys/bluetooth/host/hci_core.c b/subsys/bluetooth/host/hci_core.c index 2f54298b41b..b751cb989f1 100644 --- a/subsys/bluetooth/host/hci_core.c +++ b/subsys/bluetooth/host/hci_core.c @@ -2284,25 +2284,44 @@ static void hci_reset_complete(struct net_buf *buf) atomic_set(bt_dev.flags, flags); } -static void hci_cmd_done(uint16_t opcode, uint8_t status, struct net_buf *buf) +static void hci_cmd_done(uint16_t opcode, uint8_t status, struct net_buf *evt_buf) { - LOG_DBG("opcode 0x%04x status 0x%02x buf %p", opcode, status, buf); + /* Original command buffer. */ + struct net_buf *buf = NULL; - if (net_buf_pool_get(buf->pool_id) != &hci_cmd_pool) { - LOG_WRN("opcode 0x%04x pool id %u pool %p != &hci_cmd_pool %p", opcode, - buf->pool_id, net_buf_pool_get(buf->pool_id), &hci_cmd_pool); - return; + LOG_DBG("opcode 0x%04x status 0x%02x buf %p", opcode, status, evt_buf); + + /* Unsolicited cmd complete. This does not complete a command. + * The controller can send these for effect of the `ncmd` field. + */ + if (opcode == 0) { + goto exit; + } + + /* Take the original command buffer reference. */ + buf = atomic_ptr_clear((atomic_ptr_t *)&bt_dev.sent_cmd); + + if (!buf) { + LOG_ERR("No command sent for cmd complete 0x%04x", opcode); + goto exit; } if (cmd(buf)->opcode != opcode) { - LOG_WRN("OpCode 0x%04x completed instead of expected 0x%04x", opcode, + LOG_ERR("OpCode 0x%04x completed instead of expected 0x%04x", opcode, cmd(buf)->opcode); - return; + buf = atomic_ptr_set((atomic_ptr_t *)&bt_dev.sent_cmd, buf); + __ASSERT_NO_MSG(!buf); + goto exit; } - if (bt_dev.sent_cmd) { - net_buf_unref(bt_dev.sent_cmd); - bt_dev.sent_cmd = NULL; + /* Response data is to be delivered in the original command + * buffer. + */ + if (evt_buf != buf) { + net_buf_reset(buf); + bt_buf_set_type(buf, BT_BUF_EVT); + net_buf_reserve(buf, BT_BUF_RESERVE); + net_buf_add_mem(buf, evt_buf->data, evt_buf->len); } if (cmd(buf)->state && !status) { @@ -2316,6 +2335,11 @@ static void hci_cmd_done(uint16_t opcode, uint8_t status, struct net_buf *buf) cmd(buf)->status = status; k_sem_give(cmd(buf)->sync); } + +exit: + if (buf) { + net_buf_unref(buf); + } } static void hci_cmd_complete(struct net_buf *buf) From b6a10516b0c707f7fb12f18cb7ab37971dfe5d44 Mon Sep 17 00:00:00 2001 From: Aleksander Wasaznik Date: Wed, 24 Jan 2024 17:15:20 +0100 Subject: [PATCH 3233/3723] Bluetooth: Host: Remove `bt_buf_get_cmd_complete` After the previous commit, this function no longer has any users. Signed-off-by: Aleksander Wasaznik --- include/zephyr/bluetooth/buf.h | 11 -- subsys/bluetooth/host/buf.c | 16 -- subsys/bluetooth/host/hci_raw.c | 5 - .../bt_buf_get_cmd_complete/CMakeLists.txt | 16 -- .../host/buf/bt_buf_get_cmd_complete/prj.conf | 5 - .../buf/bt_buf_get_cmd_complete/src/main.c | 164 ------------------ .../buf/bt_buf_get_cmd_complete/testcase.yaml | 21 --- .../host/buf/mocks/net_buf_expects.h | 1 - 8 files changed, 239 deletions(-) delete mode 100644 tests/bluetooth/host/buf/bt_buf_get_cmd_complete/CMakeLists.txt delete mode 100644 tests/bluetooth/host/buf/bt_buf_get_cmd_complete/prj.conf delete mode 100644 tests/bluetooth/host/buf/bt_buf_get_cmd_complete/src/main.c delete mode 100644 tests/bluetooth/host/buf/bt_buf_get_cmd_complete/testcase.yaml diff --git a/include/zephyr/bluetooth/buf.h b/include/zephyr/bluetooth/buf.h index b6c377a9369..b079695d61c 100644 --- a/include/zephyr/bluetooth/buf.h +++ b/include/zephyr/bluetooth/buf.h @@ -129,17 +129,6 @@ struct net_buf *bt_buf_get_rx(enum bt_buf_type type, k_timeout_t timeout); struct net_buf *bt_buf_get_tx(enum bt_buf_type type, k_timeout_t timeout, const void *data, size_t size); -/** Allocate a buffer for an HCI Command Complete/Status Event - * - * This will set the buffer type so bt_buf_set_type() does not need to - * be explicitly called before bt_recv_prio(). - * - * @param timeout Non-negative waiting period to obtain a buffer or one of the - * special values K_NO_WAIT and K_FOREVER. - * @return A new buffer. - */ -struct net_buf *bt_buf_get_cmd_complete(k_timeout_t timeout); - /** Allocate a buffer for an HCI Event * * This will set the buffer type so bt_buf_set_type() does not need to diff --git a/subsys/bluetooth/host/buf.c b/subsys/bluetooth/host/buf.c index 2623871c502..b6c325f9b6f 100644 --- a/subsys/bluetooth/host/buf.c +++ b/subsys/bluetooth/host/buf.c @@ -86,22 +86,6 @@ struct net_buf *bt_buf_get_rx(enum bt_buf_type type, k_timeout_t timeout) return buf; } -struct net_buf *bt_buf_get_cmd_complete(k_timeout_t timeout) -{ - struct net_buf *buf; - - buf = (struct net_buf *)atomic_ptr_clear((atomic_ptr_t *)&bt_dev.sent_cmd); - if (buf) { - bt_buf_set_type(buf, BT_BUF_EVT); - buf->len = 0U; - net_buf_reserve(buf, BT_BUF_RESERVE); - - return buf; - } - - return bt_buf_get_rx(BT_BUF_EVT, timeout); -} - struct net_buf *bt_buf_get_evt(uint8_t evt, bool discardable, k_timeout_t timeout) { diff --git a/subsys/bluetooth/host/hci_raw.c b/subsys/bluetooth/host/hci_raw.c index e40ae4cbddb..16113c8d25a 100644 --- a/subsys/bluetooth/host/hci_raw.c +++ b/subsys/bluetooth/host/hci_raw.c @@ -177,11 +177,6 @@ struct net_buf *bt_buf_get_tx(enum bt_buf_type type, k_timeout_t timeout, return buf; } -struct net_buf *bt_buf_get_cmd_complete(k_timeout_t timeout) -{ - return bt_buf_get_rx(BT_BUF_EVT, timeout); -} - struct net_buf *bt_buf_get_evt(uint8_t evt, bool discardable, k_timeout_t timeout) { return bt_buf_get_rx(BT_BUF_EVT, timeout); diff --git a/tests/bluetooth/host/buf/bt_buf_get_cmd_complete/CMakeLists.txt b/tests/bluetooth/host/buf/bt_buf_get_cmd_complete/CMakeLists.txt deleted file mode 100644 index 59a79343598..00000000000 --- a/tests/bluetooth/host/buf/bt_buf_get_cmd_complete/CMakeLists.txt +++ /dev/null @@ -1,16 +0,0 @@ -# SPDX-License-Identifier: Apache-2.0 - -cmake_minimum_required(VERSION 3.20.0) - -project(bluetooth_bt_buf_get_cmd_complete) - -find_package(Zephyr COMPONENTS unittest REQUIRED HINTS $ENV{ZEPHYR_BASE}) - -add_subdirectory(${ZEPHYR_BASE}/tests/bluetooth/host host_mocks) -add_subdirectory(${ZEPHYR_BASE}/tests/bluetooth/host/buf mocks) - -target_link_libraries(testbinary PRIVATE mocks host_mocks) -target_sources(testbinary - PRIVATE - src/main.c -) diff --git a/tests/bluetooth/host/buf/bt_buf_get_cmd_complete/prj.conf b/tests/bluetooth/host/buf/bt_buf_get_cmd_complete/prj.conf deleted file mode 100644 index 652e7e5d169..00000000000 --- a/tests/bluetooth/host/buf/bt_buf_get_cmd_complete/prj.conf +++ /dev/null @@ -1,5 +0,0 @@ -CONFIG_ZTEST=y -CONFIG_BT=y -CONFIG_ASSERT=y -CONFIG_ASSERT_LEVEL=2 -CONFIG_ASSERT_VERBOSE=y diff --git a/tests/bluetooth/host/buf/bt_buf_get_cmd_complete/src/main.c b/tests/bluetooth/host/buf/bt_buf_get_cmd_complete/src/main.c deleted file mode 100644 index bd9d82f6316..00000000000 --- a/tests/bluetooth/host/buf/bt_buf_get_cmd_complete/src/main.c +++ /dev/null @@ -1,164 +0,0 @@ -/* - * Copyright (c) 2022 Nordic Semiconductor ASA - * - * SPDX-License-Identifier: Apache-2.0 - */ - -#include -#include -#include -#include -#include -#include "mocks/net_buf.h" -#include "mocks/net_buf_expects.h" -#include "mocks/buf_help_utils.h" - -DEFINE_FFF_GLOBALS; - -static void tc_setup(void *f) -{ - /* Register resets */ - NET_BUF_FFF_FAKES_LIST(RESET_FAKE); -} - -ZTEST_SUITE(bt_buf_get_cmd_complete_returns_not_null, NULL, NULL, tc_setup, NULL, NULL); -ZTEST_SUITE(bt_buf_get_cmd_complete_returns_null, NULL, NULL, tc_setup, NULL, NULL); - -/* - * Return value from bt_buf_get_cmd_complete() should be NULL - * - * This is to test the behaviour when memory allocation request fails - * - * Constraints: - * - bt_dev.sent_cmd value is NULL - * - Timeout value is a positive non-zero value - * - net_buf_alloc() returns a NULL value - * - * Expected behaviour: - * - net_buf_alloc() to be called with the correct memory allocation pool - * and the same timeout value passed to bt_buf_get_cmd_complete() - * - bt_dev.sent_cmd value is cleared after calling bt_buf_get_cmd_complete() - * - bt_buf_get_cmd_complete() returns NULL - */ -ZTEST(bt_buf_get_cmd_complete_returns_null, test_returns_null_sent_cmd_is_null) -{ - struct net_buf *returned_buf; - k_timeout_t timeout = Z_TIMEOUT_TICKS(1000); - - bt_dev.sent_cmd = NULL; - - struct net_buf_pool *memory_pool; - - if ((IS_ENABLED(CONFIG_BT_HCI_ACL_FLOW_CONTROL))) { - memory_pool = bt_buf_get_evt_pool(); - } else { - memory_pool = bt_buf_get_hci_rx_pool(); - } - - net_buf_alloc_fixed_fake.return_val = NULL; - - returned_buf = bt_buf_get_cmd_complete(timeout); - - expect_single_call_net_buf_alloc(memory_pool, &timeout); - expect_not_called_net_buf_reserve(); - expect_not_called_net_buf_ref(); - - zassert_is_null(returned_buf, - "bt_buf_get_cmd_complete() returned non-NULL value while expecting NULL"); - - zassert_equal(bt_dev.sent_cmd, NULL, - "bt_buf_get_cmd_complete() didn't clear bt_dev.sent_cmd"); -} - -/* - * Return value from bt_buf_get_cmd_complete() shouldn't be NULL - * - * Constraints: - * - bt_dev.sent_cmd value is NULL - * - Timeout value is a positive non-zero value - * - net_buf_alloc() return a not NULL value - * - * Expected behaviour: - * - net_buf_alloc() to be called with the correct memory allocation pool - * and the same timeout value passed to bt_buf_get_cmd_complete() - * - bt_dev.sent_cmd value is cleared after calling bt_buf_get_cmd_complete() - * - bt_buf_get_cmd_complete() returns the same value returned by net_buf_alloc_fixed() - * - Return buffer type is set to BT_BUF_EVT - */ -ZTEST(bt_buf_get_cmd_complete_returns_not_null, test_returns_not_null_sent_cmd_is_null) -{ - static struct net_buf expected_buf; - struct net_buf *returned_buf; - uint8_t returned_buffer_type; - k_timeout_t timeout = Z_TIMEOUT_TICKS(1000); - - bt_dev.sent_cmd = NULL; - - struct net_buf_pool *memory_pool; - - if ((IS_ENABLED(CONFIG_BT_HCI_ACL_FLOW_CONTROL))) { - memory_pool = bt_buf_get_evt_pool(); - } else { - memory_pool = bt_buf_get_hci_rx_pool(); - } - - net_buf_alloc_fixed_fake.return_val = &expected_buf; - - returned_buf = bt_buf_get_cmd_complete(timeout); - - expect_single_call_net_buf_alloc(memory_pool, &timeout); - expect_single_call_net_buf_reserve(&expected_buf); - expect_not_called_net_buf_ref(); - - zassert_equal(returned_buf, &expected_buf, - "bt_buf_get_cmd_complete() returned incorrect buffer pointer value"); - - returned_buffer_type = bt_buf_get_type(returned_buf); - zassert_equal(returned_buffer_type, BT_BUF_EVT, - "bt_buf_get_cmd_complete() returned incorrect buffer type %u, expected %u (%s)", - returned_buffer_type, BT_BUF_EVT, STRINGIFY(BT_BUF_EVT)); - - zassert_equal(bt_dev.sent_cmd, NULL, - "bt_buf_get_cmd_complete() didn't clear bt_dev.sent_cmd"); -} - -/* - * Return value from bt_buf_get_cmd_complete() shouldn't be NULL - * - * Constraints: - * - bt_dev.sent_cmd value isn't NULL - * - Timeout value is a positive non-zero value - * - * Expected behaviour: - * - net_buf_alloc() isn't called - * - bt_dev.sent_cmd value is cleared after calling bt_buf_get_cmd_complete() - * - bt_buf_get_cmd_complete() returns the same value set to bt_dev.sent_cmd - * - Return buffer type is set to BT_BUF_EVT - */ -ZTEST(bt_buf_get_cmd_complete_returns_not_null, test_returns_not_null_sent_cmd_is_not_null) -{ - static struct net_buf expected_buf; - struct net_buf *returned_buf; - uint8_t returned_buffer_type; - k_timeout_t timeout = Z_TIMEOUT_TICKS(1000); - - bt_dev.sent_cmd = &expected_buf; - - net_buf_ref_fake.return_val = &expected_buf; - - returned_buf = bt_buf_get_cmd_complete(timeout); - - expect_single_call_net_buf_reserve(&expected_buf); - expect_not_called_net_buf_alloc(); - - zassert_equal(returned_buf, &expected_buf, - "bt_buf_get_cmd_complete() returned incorrect buffer pointer value"); - - returned_buffer_type = bt_buf_get_type(returned_buf); - zassert_equal(returned_buffer_type, BT_BUF_EVT, - "bt_buf_get_cmd_complete() returned incorrect buffer type %u, expected %u (%s)", - returned_buffer_type, BT_BUF_EVT, STRINGIFY(BT_BUF_EVT)); - - zassert_equal(bt_dev.sent_cmd, NULL, - "bt_buf_get_cmd_complete() didn't clear bt_dev.sent_cmd"); -} diff --git a/tests/bluetooth/host/buf/bt_buf_get_cmd_complete/testcase.yaml b/tests/bluetooth/host/buf/bt_buf_get_cmd_complete/testcase.yaml deleted file mode 100644 index bf8ab566d6c..00000000000 --- a/tests/bluetooth/host/buf/bt_buf_get_cmd_complete/testcase.yaml +++ /dev/null @@ -1,21 +0,0 @@ -common: - tags: - - bluetooth - - host -tests: - bluetooth.host.bt_buf_get_cmd_complete.default: - type: unit - bluetooth.host.bt_buf_get_cmd_complete.hci_acl_flow_control: - type: unit - extra_configs: - - CONFIG_BT_CENTRAL=y - - CONFIG_BT_HCI_ACL_FLOW_CONTROL=y - bluetooth.host.bt_buf_get_cmd_complete.iso_unicast: - type: unit - # enable CONFIG_BT_ISO_UNICAST - extra_configs: - - CONFIG_BT_ISO_CENTRAL=y - bluetooth.host.bt_buf_get_cmd_complete.iso_sync_receiver: - type: unit - extra_configs: - - CONFIG_BT_ISO_SYNC_RECEIVER=y diff --git a/tests/bluetooth/host/buf/mocks/net_buf_expects.h b/tests/bluetooth/host/buf/mocks/net_buf_expects.h index b50662202f3..99e84fd85be 100644 --- a/tests/bluetooth/host/buf/mocks/net_buf_expects.h +++ b/tests/bluetooth/host/buf/mocks/net_buf_expects.h @@ -12,7 +12,6 @@ * Expected behaviour: * - net_buf_alloc() to be called once with : * - correct memory allocation pool - * - same timeout value passed to bt_buf_get_cmd_complete() */ void expect_single_call_net_buf_alloc(struct net_buf_pool *pool, k_timeout_t *timeout); From 9426309dbe2448c9d0f92a508c8a2a8dac1af681 Mon Sep 17 00:00:00 2001 From: Aleksander Wasaznik Date: Thu, 25 Jan 2024 11:27:30 +0100 Subject: [PATCH 3234/3723] Bluetooth: Host: Refactor `bt_buf_get_evt` This is purely a syntactical refactor. Signed-off-by: Aleksander Wasaznik --- subsys/bluetooth/host/buf.c | 32 ++++++++++++-------------------- 1 file changed, 12 insertions(+), 20 deletions(-) diff --git a/subsys/bluetooth/host/buf.c b/subsys/bluetooth/host/buf.c index b6c325f9b6f..9d87a6390e2 100644 --- a/subsys/bluetooth/host/buf.c +++ b/subsys/bluetooth/host/buf.c @@ -89,36 +89,28 @@ struct net_buf *bt_buf_get_rx(enum bt_buf_type type, k_timeout_t timeout) struct net_buf *bt_buf_get_evt(uint8_t evt, bool discardable, k_timeout_t timeout) { + struct net_buf *buf; + switch (evt) { #if defined(CONFIG_BT_CONN) || defined(CONFIG_BT_ISO) case BT_HCI_EVT_NUM_COMPLETED_PACKETS: - { - struct net_buf *buf; - - buf = net_buf_alloc(&num_complete_pool, timeout); - if (buf) { - net_buf_reserve(buf, BT_BUF_RESERVE); - bt_buf_set_type(buf, BT_BUF_EVT); - } - - return buf; - } + buf = net_buf_alloc(&num_complete_pool, timeout); + break; #endif /* CONFIG_BT_CONN || CONFIG_BT_ISO */ default: if (discardable) { - struct net_buf *buf; - buf = net_buf_alloc(&discardable_pool, timeout); - if (buf) { - net_buf_reserve(buf, BT_BUF_RESERVE); - bt_buf_set_type(buf, BT_BUF_EVT); - } - - return buf; + } else { + return bt_buf_get_rx(BT_BUF_EVT, timeout); } + } - return bt_buf_get_rx(BT_BUF_EVT, timeout); + if (buf) { + net_buf_reserve(buf, BT_BUF_RESERVE); + bt_buf_set_type(buf, BT_BUF_EVT); } + + return buf; } #ifdef ZTEST_UNITTEST From 2a6169e2feb9978a01857bf548a5d05c3108290b Mon Sep 17 00:00:00 2001 From: Vinayak Kariappa Chettimada Date: Mon, 29 Jan 2024 12:17:18 +0100 Subject: [PATCH 3235/3723] Bluetooth: Controller: Fix coverity issue 340852 Fix coverity issue 340852, Uninitialized scalar variable. Signed-off-by: Vinayak Kariappa Chettimada --- subsys/bluetooth/controller/ll_sw/ull_df.c | 1 + 1 file changed, 1 insertion(+) diff --git a/subsys/bluetooth/controller/ll_sw/ull_df.c b/subsys/bluetooth/controller/ll_sw/ull_df.c index 8be711539da..6d29d10fcd9 100644 --- a/subsys/bluetooth/controller/ll_sw/ull_df.c +++ b/subsys/bluetooth/controller/ll_sw/ull_df.c @@ -860,6 +860,7 @@ static uint8_t cte_info_set(struct ll_adv_set *adv, struct lll_df_adv_cfg *df_cf cte_info.type = df_cfg->cte_type; cte_info.time = df_cfg->cte_length; + cte_info.rfu = 0U; /* Note: ULL_ADV_PDU_EXTRA_DATA_ALLOC_ALWAYS is just information that extra_data * is required in case of this ull_adv_sync_pdu_alloc. From 2dbd9e5ecfa73233819f6873028007cd77ffd208 Mon Sep 17 00:00:00 2001 From: Anas Nashif Date: Wed, 31 Jan 2024 07:58:53 -0500 Subject: [PATCH 3236/3723] tests: dma: fix DT node label, avoid conflicts Simple rename of node label from test_dma to tst_dma to avoid conflicts and confusion about the test_ prefix when parsing test results in twister. Signed-off-by: Anas Nashif --- .../boards/adafruit_itsybitsy_m4_express.overlay | 2 +- .../dma/chan_blen_transfer/boards/adafruit_trinket_m0.overlay | 2 +- .../dma/chan_blen_transfer/boards/adp_xc7k_ae350.overlay | 2 +- .../dma/chan_blen_transfer/boards/arduino_mkrzero.overlay | 2 +- .../dma/chan_blen_transfer/boards/arduino_nano_33_iot.overlay | 2 +- .../dma/chan_blen_transfer/boards/arduino_zero.overlay | 2 +- .../dma/chan_blen_transfer/boards/atsamc21n_xpro.overlay | 2 +- .../dma/chan_blen_transfer/boards/atsamd21_xpro.overlay | 2 +- .../dma/chan_blen_transfer/boards/atsaml21_xpro.overlay | 2 +- .../dma/chan_blen_transfer/boards/atsamr34_xpro.overlay | 2 +- .../dma/chan_blen_transfer/boards/b_u585i_iot02a.overlay | 2 +- .../dma/chan_blen_transfer/boards/da1469x_dk_pro.overlay | 2 +- .../dma/chan_blen_transfer/boards/disco_l475_iot1.overlay | 2 +- .../dma/chan_blen_transfer/boards/esp32c3_devkitm.overlay | 2 +- .../dma/chan_blen_transfer/boards/esp32c3_luatos_core.overlay | 2 +- .../chan_blen_transfer/boards/esp32c3_luatos_core_usb.overlay | 2 +- .../dma/chan_blen_transfer/boards/esp32s3_devkitm.overlay | 2 +- .../dma/chan_blen_transfer/boards/esp32s3_luatos_core.overlay | 2 +- .../chan_blen_transfer/boards/esp32s3_luatos_core_usb.overlay | 2 +- tests/drivers/dma/chan_blen_transfer/boards/frdm_k64f.overlay | 2 +- .../dma/chan_blen_transfer/boards/intel_adsp_cavs25.overlay | 2 +- .../chan_blen_transfer/boards/intel_adsp_cavs25_tgph.overlay | 2 +- .../dma/chan_blen_transfer/boards/lpcxpresso55s36.overlay | 2 +- .../dma/chan_blen_transfer/boards/lpcxpresso55s69_ns.overlay | 2 +- .../dma/chan_blen_transfer/boards/mec172xevb_assy6906.overlay | 2 +- .../dma/chan_blen_transfer/boards/mimxrt1024_evk.overlay | 2 +- .../dma/chan_blen_transfer/boards/mimxrt1050_evk.overlay | 2 +- .../dma/chan_blen_transfer/boards/mimxrt1060_evk.overlay | 2 +- .../dma/chan_blen_transfer/boards/mimxrt1060_evkb.overlay | 2 +- .../dma/chan_blen_transfer/boards/mimxrt1064_evk.overlay | 2 +- .../dma/chan_blen_transfer/boards/mimxrt1160_evk_cm4.overlay | 2 +- .../dma/chan_blen_transfer/boards/mimxrt1160_evk_cm7.overlay | 2 +- .../dma/chan_blen_transfer/boards/mimxrt1170_evk_cm4.overlay | 2 +- .../dma/chan_blen_transfer/boards/mimxrt1170_evk_cm7.overlay | 2 +- .../dma/chan_blen_transfer/boards/mimxrt1170_evkb_cm4.overlay | 2 +- .../dma/chan_blen_transfer/boards/mimxrt595_evk_cm33.overlay | 2 +- .../dma/chan_blen_transfer/boards/mimxrt685_evk_cm33.overlay | 2 +- .../drivers/dma/chan_blen_transfer/boards/mm_feather.overlay | 2 +- .../drivers/dma/chan_blen_transfer/boards/mr_canhubk3.overlay | 2 +- .../dma/chan_blen_transfer/boards/native_posix.overlay | 2 +- .../dma/chan_blen_transfer/boards/native_posix_64.overlay | 2 +- .../dma/chan_blen_transfer/boards/nucleo_c031c6.overlay | 2 +- .../dma/chan_blen_transfer/boards/nucleo_f070rb.overlay | 2 +- .../dma/chan_blen_transfer/boards/nucleo_f091rc.overlay | 2 +- .../dma/chan_blen_transfer/boards/nucleo_f103rb.overlay | 2 +- .../dma/chan_blen_transfer/boards/nucleo_f207zg.overlay | 2 +- .../dma/chan_blen_transfer/boards/nucleo_f429zi.overlay | 2 +- .../dma/chan_blen_transfer/boards/nucleo_f746zg.overlay | 2 +- .../dma/chan_blen_transfer/boards/nucleo_f767zi.overlay | 2 +- .../dma/chan_blen_transfer/boards/nucleo_g071rb.overlay | 2 +- .../dma/chan_blen_transfer/boards/nucleo_g0b1re.overlay | 2 +- .../dma/chan_blen_transfer/boards/nucleo_g474re.overlay | 2 +- .../dma/chan_blen_transfer/boards/nucleo_h743zi.overlay | 4 ++-- .../dma/chan_blen_transfer/boards/nucleo_l053r8.overlay | 2 +- .../dma/chan_blen_transfer/boards/nucleo_l152re.overlay | 2 +- .../dma/chan_blen_transfer/boards/nucleo_l476rg.overlay | 2 +- .../dma/chan_blen_transfer/boards/nucleo_l496zg.overlay | 2 +- .../dma/chan_blen_transfer/boards/nucleo_l552ze_q.overlay | 2 +- .../dma/chan_blen_transfer/boards/nucleo_u575zi_q.overlay | 2 +- .../dma/chan_blen_transfer/boards/nucleo_wb55rg.overlay | 2 +- .../dma/chan_blen_transfer/boards/nucleo_wl55jc.overlay | 2 +- .../dma/chan_blen_transfer/boards/seeeduino_xiao.overlay | 2 +- .../dma/chan_blen_transfer/boards/stm32f3_disco.overlay | 2 +- .../dma/chan_blen_transfer/boards/stm32g0316_disco.overlay | 2 +- .../dma/chan_blen_transfer/boards/stm32h573i_dk.overlay | 2 +- .../dma/chan_blen_transfer/boards/stm32l562e_dk.overlay | 2 +- .../dma/chan_blen_transfer/boards/stm32mp157c_dk2.overlay | 2 +- tests/drivers/dma/chan_blen_transfer/boards/twr_ke18f.overlay | 2 +- tests/drivers/dma/chan_blen_transfer/src/test_dma.c | 2 +- tests/drivers/dma/chan_blen_transfer/testcase.yaml | 4 ++-- 70 files changed, 72 insertions(+), 72 deletions(-) diff --git a/tests/drivers/dma/chan_blen_transfer/boards/adafruit_itsybitsy_m4_express.overlay b/tests/drivers/dma/chan_blen_transfer/boards/adafruit_itsybitsy_m4_express.overlay index c2343bf0892..2731332e26b 100644 --- a/tests/drivers/dma/chan_blen_transfer/boards/adafruit_itsybitsy_m4_express.overlay +++ b/tests/drivers/dma/chan_blen_transfer/boards/adafruit_itsybitsy_m4_express.overlay @@ -4,4 +4,4 @@ * SPDX-License-Identifier: Apache-2.0 */ -test_dma0: &dmac { }; +tst_dma0: &dmac { }; diff --git a/tests/drivers/dma/chan_blen_transfer/boards/adafruit_trinket_m0.overlay b/tests/drivers/dma/chan_blen_transfer/boards/adafruit_trinket_m0.overlay index c2343bf0892..2731332e26b 100644 --- a/tests/drivers/dma/chan_blen_transfer/boards/adafruit_trinket_m0.overlay +++ b/tests/drivers/dma/chan_blen_transfer/boards/adafruit_trinket_m0.overlay @@ -4,4 +4,4 @@ * SPDX-License-Identifier: Apache-2.0 */ -test_dma0: &dmac { }; +tst_dma0: &dmac { }; diff --git a/tests/drivers/dma/chan_blen_transfer/boards/adp_xc7k_ae350.overlay b/tests/drivers/dma/chan_blen_transfer/boards/adp_xc7k_ae350.overlay index c58ffdfcc20..ac75c8827b4 100644 --- a/tests/drivers/dma/chan_blen_transfer/boards/adp_xc7k_ae350.overlay +++ b/tests/drivers/dma/chan_blen_transfer/boards/adp_xc7k_ae350.overlay @@ -4,6 +4,6 @@ * SPDX-License-Identifier: Apache-2.0 */ -test_dma0: &dma0 { +tst_dma0: &dma0 { status = "okay"; }; diff --git a/tests/drivers/dma/chan_blen_transfer/boards/arduino_mkrzero.overlay b/tests/drivers/dma/chan_blen_transfer/boards/arduino_mkrzero.overlay index c2343bf0892..2731332e26b 100644 --- a/tests/drivers/dma/chan_blen_transfer/boards/arduino_mkrzero.overlay +++ b/tests/drivers/dma/chan_blen_transfer/boards/arduino_mkrzero.overlay @@ -4,4 +4,4 @@ * SPDX-License-Identifier: Apache-2.0 */ -test_dma0: &dmac { }; +tst_dma0: &dmac { }; diff --git a/tests/drivers/dma/chan_blen_transfer/boards/arduino_nano_33_iot.overlay b/tests/drivers/dma/chan_blen_transfer/boards/arduino_nano_33_iot.overlay index c2343bf0892..2731332e26b 100644 --- a/tests/drivers/dma/chan_blen_transfer/boards/arduino_nano_33_iot.overlay +++ b/tests/drivers/dma/chan_blen_transfer/boards/arduino_nano_33_iot.overlay @@ -4,4 +4,4 @@ * SPDX-License-Identifier: Apache-2.0 */ -test_dma0: &dmac { }; +tst_dma0: &dmac { }; diff --git a/tests/drivers/dma/chan_blen_transfer/boards/arduino_zero.overlay b/tests/drivers/dma/chan_blen_transfer/boards/arduino_zero.overlay index c2343bf0892..2731332e26b 100644 --- a/tests/drivers/dma/chan_blen_transfer/boards/arduino_zero.overlay +++ b/tests/drivers/dma/chan_blen_transfer/boards/arduino_zero.overlay @@ -4,4 +4,4 @@ * SPDX-License-Identifier: Apache-2.0 */ -test_dma0: &dmac { }; +tst_dma0: &dmac { }; diff --git a/tests/drivers/dma/chan_blen_transfer/boards/atsamc21n_xpro.overlay b/tests/drivers/dma/chan_blen_transfer/boards/atsamc21n_xpro.overlay index c2343bf0892..2731332e26b 100644 --- a/tests/drivers/dma/chan_blen_transfer/boards/atsamc21n_xpro.overlay +++ b/tests/drivers/dma/chan_blen_transfer/boards/atsamc21n_xpro.overlay @@ -4,4 +4,4 @@ * SPDX-License-Identifier: Apache-2.0 */ -test_dma0: &dmac { }; +tst_dma0: &dmac { }; diff --git a/tests/drivers/dma/chan_blen_transfer/boards/atsamd21_xpro.overlay b/tests/drivers/dma/chan_blen_transfer/boards/atsamd21_xpro.overlay index c2343bf0892..2731332e26b 100644 --- a/tests/drivers/dma/chan_blen_transfer/boards/atsamd21_xpro.overlay +++ b/tests/drivers/dma/chan_blen_transfer/boards/atsamd21_xpro.overlay @@ -4,4 +4,4 @@ * SPDX-License-Identifier: Apache-2.0 */ -test_dma0: &dmac { }; +tst_dma0: &dmac { }; diff --git a/tests/drivers/dma/chan_blen_transfer/boards/atsaml21_xpro.overlay b/tests/drivers/dma/chan_blen_transfer/boards/atsaml21_xpro.overlay index c2343bf0892..2731332e26b 100644 --- a/tests/drivers/dma/chan_blen_transfer/boards/atsaml21_xpro.overlay +++ b/tests/drivers/dma/chan_blen_transfer/boards/atsaml21_xpro.overlay @@ -4,4 +4,4 @@ * SPDX-License-Identifier: Apache-2.0 */ -test_dma0: &dmac { }; +tst_dma0: &dmac { }; diff --git a/tests/drivers/dma/chan_blen_transfer/boards/atsamr34_xpro.overlay b/tests/drivers/dma/chan_blen_transfer/boards/atsamr34_xpro.overlay index c2343bf0892..2731332e26b 100644 --- a/tests/drivers/dma/chan_blen_transfer/boards/atsamr34_xpro.overlay +++ b/tests/drivers/dma/chan_blen_transfer/boards/atsamr34_xpro.overlay @@ -4,4 +4,4 @@ * SPDX-License-Identifier: Apache-2.0 */ -test_dma0: &dmac { }; +tst_dma0: &dmac { }; diff --git a/tests/drivers/dma/chan_blen_transfer/boards/b_u585i_iot02a.overlay b/tests/drivers/dma/chan_blen_transfer/boards/b_u585i_iot02a.overlay index dd4daeb0d57..0bd5ba64628 100644 --- a/tests/drivers/dma/chan_blen_transfer/boards/b_u585i_iot02a.overlay +++ b/tests/drivers/dma/chan_blen_transfer/boards/b_u585i_iot02a.overlay @@ -4,6 +4,6 @@ * SPDX-License-Identifier: Apache-2.0 */ -test_dma0: &gpdma1 { +tst_dma0: &gpdma1 { status = "okay"; }; diff --git a/tests/drivers/dma/chan_blen_transfer/boards/da1469x_dk_pro.overlay b/tests/drivers/dma/chan_blen_transfer/boards/da1469x_dk_pro.overlay index eca3c9dc752..5ac7a35afd3 100644 --- a/tests/drivers/dma/chan_blen_transfer/boards/da1469x_dk_pro.overlay +++ b/tests/drivers/dma/chan_blen_transfer/boards/da1469x_dk_pro.overlay @@ -4,6 +4,6 @@ * SPDX-License-Identifier: Apache-2.0 */ - test_dma0: &dma { + tst_dma0: &dma { status = "okay"; }; diff --git a/tests/drivers/dma/chan_blen_transfer/boards/disco_l475_iot1.overlay b/tests/drivers/dma/chan_blen_transfer/boards/disco_l475_iot1.overlay index d46897cf66d..f93b5145243 100644 --- a/tests/drivers/dma/chan_blen_transfer/boards/disco_l475_iot1.overlay +++ b/tests/drivers/dma/chan_blen_transfer/boards/disco_l475_iot1.overlay @@ -4,4 +4,4 @@ * SPDX-License-Identifier: Apache-2.0 */ -test_dma0: &dma1 { }; +tst_dma0: &dma1 { }; diff --git a/tests/drivers/dma/chan_blen_transfer/boards/esp32c3_devkitm.overlay b/tests/drivers/dma/chan_blen_transfer/boards/esp32c3_devkitm.overlay index 9098b0dd5b9..c93ef734fba 100644 --- a/tests/drivers/dma/chan_blen_transfer/boards/esp32c3_devkitm.overlay +++ b/tests/drivers/dma/chan_blen_transfer/boards/esp32c3_devkitm.overlay @@ -8,4 +8,4 @@ status = "okay"; }; -test_dma0: &dma { }; +tst_dma0: &dma { }; diff --git a/tests/drivers/dma/chan_blen_transfer/boards/esp32c3_luatos_core.overlay b/tests/drivers/dma/chan_blen_transfer/boards/esp32c3_luatos_core.overlay index 9098b0dd5b9..c93ef734fba 100644 --- a/tests/drivers/dma/chan_blen_transfer/boards/esp32c3_luatos_core.overlay +++ b/tests/drivers/dma/chan_blen_transfer/boards/esp32c3_luatos_core.overlay @@ -8,4 +8,4 @@ status = "okay"; }; -test_dma0: &dma { }; +tst_dma0: &dma { }; diff --git a/tests/drivers/dma/chan_blen_transfer/boards/esp32c3_luatos_core_usb.overlay b/tests/drivers/dma/chan_blen_transfer/boards/esp32c3_luatos_core_usb.overlay index 9098b0dd5b9..c93ef734fba 100644 --- a/tests/drivers/dma/chan_blen_transfer/boards/esp32c3_luatos_core_usb.overlay +++ b/tests/drivers/dma/chan_blen_transfer/boards/esp32c3_luatos_core_usb.overlay @@ -8,4 +8,4 @@ status = "okay"; }; -test_dma0: &dma { }; +tst_dma0: &dma { }; diff --git a/tests/drivers/dma/chan_blen_transfer/boards/esp32s3_devkitm.overlay b/tests/drivers/dma/chan_blen_transfer/boards/esp32s3_devkitm.overlay index ca3f3ca2c99..a6570c3a8bd 100644 --- a/tests/drivers/dma/chan_blen_transfer/boards/esp32s3_devkitm.overlay +++ b/tests/drivers/dma/chan_blen_transfer/boards/esp32s3_devkitm.overlay @@ -8,4 +8,4 @@ status = "okay"; }; -test_dma0: &dma { }; +tst_dma0: &dma { }; diff --git a/tests/drivers/dma/chan_blen_transfer/boards/esp32s3_luatos_core.overlay b/tests/drivers/dma/chan_blen_transfer/boards/esp32s3_luatos_core.overlay index ca3f3ca2c99..a6570c3a8bd 100644 --- a/tests/drivers/dma/chan_blen_transfer/boards/esp32s3_luatos_core.overlay +++ b/tests/drivers/dma/chan_blen_transfer/boards/esp32s3_luatos_core.overlay @@ -8,4 +8,4 @@ status = "okay"; }; -test_dma0: &dma { }; +tst_dma0: &dma { }; diff --git a/tests/drivers/dma/chan_blen_transfer/boards/esp32s3_luatos_core_usb.overlay b/tests/drivers/dma/chan_blen_transfer/boards/esp32s3_luatos_core_usb.overlay index ca3f3ca2c99..a6570c3a8bd 100644 --- a/tests/drivers/dma/chan_blen_transfer/boards/esp32s3_luatos_core_usb.overlay +++ b/tests/drivers/dma/chan_blen_transfer/boards/esp32s3_luatos_core_usb.overlay @@ -8,4 +8,4 @@ status = "okay"; }; -test_dma0: &dma { }; +tst_dma0: &dma { }; diff --git a/tests/drivers/dma/chan_blen_transfer/boards/frdm_k64f.overlay b/tests/drivers/dma/chan_blen_transfer/boards/frdm_k64f.overlay index 8a7bab0e501..e4501ae477d 100644 --- a/tests/drivers/dma/chan_blen_transfer/boards/frdm_k64f.overlay +++ b/tests/drivers/dma/chan_blen_transfer/boards/frdm_k64f.overlay @@ -4,4 +4,4 @@ * SPDX-License-Identifier: Apache-2.0 */ -test_dma0: &edma0 { }; +tst_dma0: &edma0 { }; diff --git a/tests/drivers/dma/chan_blen_transfer/boards/intel_adsp_cavs25.overlay b/tests/drivers/dma/chan_blen_transfer/boards/intel_adsp_cavs25.overlay index 4ada6a6a4dd..3110e90b5f5 100644 --- a/tests/drivers/dma/chan_blen_transfer/boards/intel_adsp_cavs25.overlay +++ b/tests/drivers/dma/chan_blen_transfer/boards/intel_adsp_cavs25.overlay @@ -4,4 +4,4 @@ * SPDX-License-Identifier: Apache-2.0 */ -test_dma0: &lpgpdma0 { }; +tst_dma0: &lpgpdma0 { }; diff --git a/tests/drivers/dma/chan_blen_transfer/boards/intel_adsp_cavs25_tgph.overlay b/tests/drivers/dma/chan_blen_transfer/boards/intel_adsp_cavs25_tgph.overlay index 4ada6a6a4dd..3110e90b5f5 100644 --- a/tests/drivers/dma/chan_blen_transfer/boards/intel_adsp_cavs25_tgph.overlay +++ b/tests/drivers/dma/chan_blen_transfer/boards/intel_adsp_cavs25_tgph.overlay @@ -4,4 +4,4 @@ * SPDX-License-Identifier: Apache-2.0 */ -test_dma0: &lpgpdma0 { }; +tst_dma0: &lpgpdma0 { }; diff --git a/tests/drivers/dma/chan_blen_transfer/boards/lpcxpresso55s36.overlay b/tests/drivers/dma/chan_blen_transfer/boards/lpcxpresso55s36.overlay index b1c2b20904c..a870cbfe779 100644 --- a/tests/drivers/dma/chan_blen_transfer/boards/lpcxpresso55s36.overlay +++ b/tests/drivers/dma/chan_blen_transfer/boards/lpcxpresso55s36.overlay @@ -1 +1 @@ -test_dma0: &dma0 { }; +tst_dma0: &dma0 { }; diff --git a/tests/drivers/dma/chan_blen_transfer/boards/lpcxpresso55s69_ns.overlay b/tests/drivers/dma/chan_blen_transfer/boards/lpcxpresso55s69_ns.overlay index 2b44336e3cd..5e4c6a1c43c 100644 --- a/tests/drivers/dma/chan_blen_transfer/boards/lpcxpresso55s69_ns.overlay +++ b/tests/drivers/dma/chan_blen_transfer/boards/lpcxpresso55s69_ns.overlay @@ -4,4 +4,4 @@ * SPDX-License-Identifier: Apache-2.0 */ -test_dma0: &dma0 { }; +tst_dma0: &dma0 { }; diff --git a/tests/drivers/dma/chan_blen_transfer/boards/mec172xevb_assy6906.overlay b/tests/drivers/dma/chan_blen_transfer/boards/mec172xevb_assy6906.overlay index 12ad52bf632..d829aebced7 100644 --- a/tests/drivers/dma/chan_blen_transfer/boards/mec172xevb_assy6906.overlay +++ b/tests/drivers/dma/chan_blen_transfer/boards/mec172xevb_assy6906.overlay @@ -4,6 +4,6 @@ * SPDX-License-Identifier: Apache-2.0 */ -test_dma: &dmac { +tst_dma: &dmac { status = "okay"; }; diff --git a/tests/drivers/dma/chan_blen_transfer/boards/mimxrt1024_evk.overlay b/tests/drivers/dma/chan_blen_transfer/boards/mimxrt1024_evk.overlay index 91e460ff4ea..43b7fc37826 100644 --- a/tests/drivers/dma/chan_blen_transfer/boards/mimxrt1024_evk.overlay +++ b/tests/drivers/dma/chan_blen_transfer/boards/mimxrt1024_evk.overlay @@ -11,4 +11,4 @@ zephyr,memory-attr = <( DT_MEM_ARM(ATTR_MPU_RAM_NOCACHE) )>; }; -test_dma0: &edma0 { }; +tst_dma0: &edma0 { }; diff --git a/tests/drivers/dma/chan_blen_transfer/boards/mimxrt1050_evk.overlay b/tests/drivers/dma/chan_blen_transfer/boards/mimxrt1050_evk.overlay index 91e460ff4ea..43b7fc37826 100644 --- a/tests/drivers/dma/chan_blen_transfer/boards/mimxrt1050_evk.overlay +++ b/tests/drivers/dma/chan_blen_transfer/boards/mimxrt1050_evk.overlay @@ -11,4 +11,4 @@ zephyr,memory-attr = <( DT_MEM_ARM(ATTR_MPU_RAM_NOCACHE) )>; }; -test_dma0: &edma0 { }; +tst_dma0: &edma0 { }; diff --git a/tests/drivers/dma/chan_blen_transfer/boards/mimxrt1060_evk.overlay b/tests/drivers/dma/chan_blen_transfer/boards/mimxrt1060_evk.overlay index bce7a33518c..82f0bbe94e8 100644 --- a/tests/drivers/dma/chan_blen_transfer/boards/mimxrt1060_evk.overlay +++ b/tests/drivers/dma/chan_blen_transfer/boards/mimxrt1060_evk.overlay @@ -11,4 +11,4 @@ zephyr,memory-attr = <( DT_MEM_ARM(ATTR_MPU_RAM_NOCACHE) )>; }; -test_dma0: &edma0 { }; +tst_dma0: &edma0 { }; diff --git a/tests/drivers/dma/chan_blen_transfer/boards/mimxrt1060_evkb.overlay b/tests/drivers/dma/chan_blen_transfer/boards/mimxrt1060_evkb.overlay index 91e460ff4ea..43b7fc37826 100644 --- a/tests/drivers/dma/chan_blen_transfer/boards/mimxrt1060_evkb.overlay +++ b/tests/drivers/dma/chan_blen_transfer/boards/mimxrt1060_evkb.overlay @@ -11,4 +11,4 @@ zephyr,memory-attr = <( DT_MEM_ARM(ATTR_MPU_RAM_NOCACHE) )>; }; -test_dma0: &edma0 { }; +tst_dma0: &edma0 { }; diff --git a/tests/drivers/dma/chan_blen_transfer/boards/mimxrt1064_evk.overlay b/tests/drivers/dma/chan_blen_transfer/boards/mimxrt1064_evk.overlay index 91e460ff4ea..43b7fc37826 100644 --- a/tests/drivers/dma/chan_blen_transfer/boards/mimxrt1064_evk.overlay +++ b/tests/drivers/dma/chan_blen_transfer/boards/mimxrt1064_evk.overlay @@ -11,4 +11,4 @@ zephyr,memory-attr = <( DT_MEM_ARM(ATTR_MPU_RAM_NOCACHE) )>; }; -test_dma0: &edma0 { }; +tst_dma0: &edma0 { }; diff --git a/tests/drivers/dma/chan_blen_transfer/boards/mimxrt1160_evk_cm4.overlay b/tests/drivers/dma/chan_blen_transfer/boards/mimxrt1160_evk_cm4.overlay index 7cc5ca66e24..5e8bafa1d9b 100644 --- a/tests/drivers/dma/chan_blen_transfer/boards/mimxrt1160_evk_cm4.overlay +++ b/tests/drivers/dma/chan_blen_transfer/boards/mimxrt1160_evk_cm4.overlay @@ -11,4 +11,4 @@ zephyr,memory-attr = <( DT_MEM_ARM(ATTR_MPU_RAM_NOCACHE) )>; }; -test_dma0: &edma_lpsr0 { }; +tst_dma0: &edma_lpsr0 { }; diff --git a/tests/drivers/dma/chan_blen_transfer/boards/mimxrt1160_evk_cm7.overlay b/tests/drivers/dma/chan_blen_transfer/boards/mimxrt1160_evk_cm7.overlay index bce7a33518c..82f0bbe94e8 100644 --- a/tests/drivers/dma/chan_blen_transfer/boards/mimxrt1160_evk_cm7.overlay +++ b/tests/drivers/dma/chan_blen_transfer/boards/mimxrt1160_evk_cm7.overlay @@ -11,4 +11,4 @@ zephyr,memory-attr = <( DT_MEM_ARM(ATTR_MPU_RAM_NOCACHE) )>; }; -test_dma0: &edma0 { }; +tst_dma0: &edma0 { }; diff --git a/tests/drivers/dma/chan_blen_transfer/boards/mimxrt1170_evk_cm4.overlay b/tests/drivers/dma/chan_blen_transfer/boards/mimxrt1170_evk_cm4.overlay index 7cc5ca66e24..5e8bafa1d9b 100644 --- a/tests/drivers/dma/chan_blen_transfer/boards/mimxrt1170_evk_cm4.overlay +++ b/tests/drivers/dma/chan_blen_transfer/boards/mimxrt1170_evk_cm4.overlay @@ -11,4 +11,4 @@ zephyr,memory-attr = <( DT_MEM_ARM(ATTR_MPU_RAM_NOCACHE) )>; }; -test_dma0: &edma_lpsr0 { }; +tst_dma0: &edma_lpsr0 { }; diff --git a/tests/drivers/dma/chan_blen_transfer/boards/mimxrt1170_evk_cm7.overlay b/tests/drivers/dma/chan_blen_transfer/boards/mimxrt1170_evk_cm7.overlay index bce7a33518c..82f0bbe94e8 100644 --- a/tests/drivers/dma/chan_blen_transfer/boards/mimxrt1170_evk_cm7.overlay +++ b/tests/drivers/dma/chan_blen_transfer/boards/mimxrt1170_evk_cm7.overlay @@ -11,4 +11,4 @@ zephyr,memory-attr = <( DT_MEM_ARM(ATTR_MPU_RAM_NOCACHE) )>; }; -test_dma0: &edma0 { }; +tst_dma0: &edma0 { }; diff --git a/tests/drivers/dma/chan_blen_transfer/boards/mimxrt1170_evkb_cm4.overlay b/tests/drivers/dma/chan_blen_transfer/boards/mimxrt1170_evkb_cm4.overlay index 7cc5ca66e24..5e8bafa1d9b 100644 --- a/tests/drivers/dma/chan_blen_transfer/boards/mimxrt1170_evkb_cm4.overlay +++ b/tests/drivers/dma/chan_blen_transfer/boards/mimxrt1170_evkb_cm4.overlay @@ -11,4 +11,4 @@ zephyr,memory-attr = <( DT_MEM_ARM(ATTR_MPU_RAM_NOCACHE) )>; }; -test_dma0: &edma_lpsr0 { }; +tst_dma0: &edma_lpsr0 { }; diff --git a/tests/drivers/dma/chan_blen_transfer/boards/mimxrt595_evk_cm33.overlay b/tests/drivers/dma/chan_blen_transfer/boards/mimxrt595_evk_cm33.overlay index 2b44336e3cd..5e4c6a1c43c 100644 --- a/tests/drivers/dma/chan_blen_transfer/boards/mimxrt595_evk_cm33.overlay +++ b/tests/drivers/dma/chan_blen_transfer/boards/mimxrt595_evk_cm33.overlay @@ -4,4 +4,4 @@ * SPDX-License-Identifier: Apache-2.0 */ -test_dma0: &dma0 { }; +tst_dma0: &dma0 { }; diff --git a/tests/drivers/dma/chan_blen_transfer/boards/mimxrt685_evk_cm33.overlay b/tests/drivers/dma/chan_blen_transfer/boards/mimxrt685_evk_cm33.overlay index 2b44336e3cd..5e4c6a1c43c 100644 --- a/tests/drivers/dma/chan_blen_transfer/boards/mimxrt685_evk_cm33.overlay +++ b/tests/drivers/dma/chan_blen_transfer/boards/mimxrt685_evk_cm33.overlay @@ -4,4 +4,4 @@ * SPDX-License-Identifier: Apache-2.0 */ -test_dma0: &dma0 { }; +tst_dma0: &dma0 { }; diff --git a/tests/drivers/dma/chan_blen_transfer/boards/mm_feather.overlay b/tests/drivers/dma/chan_blen_transfer/boards/mm_feather.overlay index 8a7bab0e501..e4501ae477d 100644 --- a/tests/drivers/dma/chan_blen_transfer/boards/mm_feather.overlay +++ b/tests/drivers/dma/chan_blen_transfer/boards/mm_feather.overlay @@ -4,4 +4,4 @@ * SPDX-License-Identifier: Apache-2.0 */ -test_dma0: &edma0 { }; +tst_dma0: &edma0 { }; diff --git a/tests/drivers/dma/chan_blen_transfer/boards/mr_canhubk3.overlay b/tests/drivers/dma/chan_blen_transfer/boards/mr_canhubk3.overlay index afc9c1b2495..fb42bb5c39c 100644 --- a/tests/drivers/dma/chan_blen_transfer/boards/mr_canhubk3.overlay +++ b/tests/drivers/dma/chan_blen_transfer/boards/mr_canhubk3.overlay @@ -4,4 +4,4 @@ * SPDX-License-Identifier: Apache-2.0 */ -test_dma0: &edma0 { }; +tst_dma0: &edma0 { }; diff --git a/tests/drivers/dma/chan_blen_transfer/boards/native_posix.overlay b/tests/drivers/dma/chan_blen_transfer/boards/native_posix.overlay index a93d9923627..28f19ac0f0d 100644 --- a/tests/drivers/dma/chan_blen_transfer/boards/native_posix.overlay +++ b/tests/drivers/dma/chan_blen_transfer/boards/native_posix.overlay @@ -9,4 +9,4 @@ status = "okay"; }; -test_dma0: &dma { }; +tst_dma0: &dma { }; diff --git a/tests/drivers/dma/chan_blen_transfer/boards/native_posix_64.overlay b/tests/drivers/dma/chan_blen_transfer/boards/native_posix_64.overlay index a93d9923627..28f19ac0f0d 100644 --- a/tests/drivers/dma/chan_blen_transfer/boards/native_posix_64.overlay +++ b/tests/drivers/dma/chan_blen_transfer/boards/native_posix_64.overlay @@ -9,4 +9,4 @@ status = "okay"; }; -test_dma0: &dma { }; +tst_dma0: &dma { }; diff --git a/tests/drivers/dma/chan_blen_transfer/boards/nucleo_c031c6.overlay b/tests/drivers/dma/chan_blen_transfer/boards/nucleo_c031c6.overlay index c9469506163..a1d9a663b26 100644 --- a/tests/drivers/dma/chan_blen_transfer/boards/nucleo_c031c6.overlay +++ b/tests/drivers/dma/chan_blen_transfer/boards/nucleo_c031c6.overlay @@ -4,6 +4,6 @@ * SPDX-License-Identifier: Apache-2.0 */ -test_dma0: &dma1 { +tst_dma0: &dma1 { status = "okay"; }; diff --git a/tests/drivers/dma/chan_blen_transfer/boards/nucleo_f070rb.overlay b/tests/drivers/dma/chan_blen_transfer/boards/nucleo_f070rb.overlay index 7236f2b10dd..9c803881efe 100644 --- a/tests/drivers/dma/chan_blen_transfer/boards/nucleo_f070rb.overlay +++ b/tests/drivers/dma/chan_blen_transfer/boards/nucleo_f070rb.overlay @@ -4,6 +4,6 @@ * SPDX-License-Identifier: Apache-2.0 */ -test_dma0: &dma1 { +tst_dma0: &dma1 { status = "okay"; }; diff --git a/tests/drivers/dma/chan_blen_transfer/boards/nucleo_f091rc.overlay b/tests/drivers/dma/chan_blen_transfer/boards/nucleo_f091rc.overlay index d46897cf66d..f93b5145243 100644 --- a/tests/drivers/dma/chan_blen_transfer/boards/nucleo_f091rc.overlay +++ b/tests/drivers/dma/chan_blen_transfer/boards/nucleo_f091rc.overlay @@ -4,4 +4,4 @@ * SPDX-License-Identifier: Apache-2.0 */ -test_dma0: &dma1 { }; +tst_dma0: &dma1 { }; diff --git a/tests/drivers/dma/chan_blen_transfer/boards/nucleo_f103rb.overlay b/tests/drivers/dma/chan_blen_transfer/boards/nucleo_f103rb.overlay index d46897cf66d..f93b5145243 100644 --- a/tests/drivers/dma/chan_blen_transfer/boards/nucleo_f103rb.overlay +++ b/tests/drivers/dma/chan_blen_transfer/boards/nucleo_f103rb.overlay @@ -4,4 +4,4 @@ * SPDX-License-Identifier: Apache-2.0 */ -test_dma0: &dma1 { }; +tst_dma0: &dma1 { }; diff --git a/tests/drivers/dma/chan_blen_transfer/boards/nucleo_f207zg.overlay b/tests/drivers/dma/chan_blen_transfer/boards/nucleo_f207zg.overlay index 34515723219..9efc8cf1c20 100644 --- a/tests/drivers/dma/chan_blen_transfer/boards/nucleo_f207zg.overlay +++ b/tests/drivers/dma/chan_blen_transfer/boards/nucleo_f207zg.overlay @@ -8,6 +8,6 @@ status = "okay"; }; -test_dma0: &dma2 { +tst_dma0: &dma2 { status = "okay"; }; diff --git a/tests/drivers/dma/chan_blen_transfer/boards/nucleo_f429zi.overlay b/tests/drivers/dma/chan_blen_transfer/boards/nucleo_f429zi.overlay index b0436e37a7e..2fee10c7ffd 100644 --- a/tests/drivers/dma/chan_blen_transfer/boards/nucleo_f429zi.overlay +++ b/tests/drivers/dma/chan_blen_transfer/boards/nucleo_f429zi.overlay @@ -4,4 +4,4 @@ * SPDX-License-Identifier: Apache-2.0 */ -test_dma0: &dma2 { }; +tst_dma0: &dma2 { }; diff --git a/tests/drivers/dma/chan_blen_transfer/boards/nucleo_f746zg.overlay b/tests/drivers/dma/chan_blen_transfer/boards/nucleo_f746zg.overlay index 185e392a70d..c0fbbe71408 100644 --- a/tests/drivers/dma/chan_blen_transfer/boards/nucleo_f746zg.overlay +++ b/tests/drivers/dma/chan_blen_transfer/boards/nucleo_f746zg.overlay @@ -4,7 +4,7 @@ * SPDX-License-Identifier: Apache-2.0 */ -test_dma0: &dma2 { }; +tst_dma0: &dma2 { }; /* The test driver expects the SRAM0 region to be non-cachable */ &sram0 { diff --git a/tests/drivers/dma/chan_blen_transfer/boards/nucleo_f767zi.overlay b/tests/drivers/dma/chan_blen_transfer/boards/nucleo_f767zi.overlay index b7a5c05779c..b234285c6b9 100644 --- a/tests/drivers/dma/chan_blen_transfer/boards/nucleo_f767zi.overlay +++ b/tests/drivers/dma/chan_blen_transfer/boards/nucleo_f767zi.overlay @@ -8,7 +8,7 @@ status = "okay"; }; -test_dma0: &dma2 { +tst_dma0: &dma2 { status = "okay"; }; diff --git a/tests/drivers/dma/chan_blen_transfer/boards/nucleo_g071rb.overlay b/tests/drivers/dma/chan_blen_transfer/boards/nucleo_g071rb.overlay index f6ef210b850..f7c6c591936 100644 --- a/tests/drivers/dma/chan_blen_transfer/boards/nucleo_g071rb.overlay +++ b/tests/drivers/dma/chan_blen_transfer/boards/nucleo_g071rb.overlay @@ -8,6 +8,6 @@ status = "okay"; }; -test_dma0: &dmamux1 { +tst_dma0: &dmamux1 { status = "okay"; }; diff --git a/tests/drivers/dma/chan_blen_transfer/boards/nucleo_g0b1re.overlay b/tests/drivers/dma/chan_blen_transfer/boards/nucleo_g0b1re.overlay index 1656a66dd9a..5489fe67d2f 100644 --- a/tests/drivers/dma/chan_blen_transfer/boards/nucleo_g0b1re.overlay +++ b/tests/drivers/dma/chan_blen_transfer/boards/nucleo_g0b1re.overlay @@ -12,6 +12,6 @@ status = "okay"; }; -test_dma0: &dmamux1 { +tst_dma0: &dmamux1 { status = "okay"; }; diff --git a/tests/drivers/dma/chan_blen_transfer/boards/nucleo_g474re.overlay b/tests/drivers/dma/chan_blen_transfer/boards/nucleo_g474re.overlay index 1656a66dd9a..5489fe67d2f 100644 --- a/tests/drivers/dma/chan_blen_transfer/boards/nucleo_g474re.overlay +++ b/tests/drivers/dma/chan_blen_transfer/boards/nucleo_g474re.overlay @@ -12,6 +12,6 @@ status = "okay"; }; -test_dma0: &dmamux1 { +tst_dma0: &dmamux1 { status = "okay"; }; diff --git a/tests/drivers/dma/chan_blen_transfer/boards/nucleo_h743zi.overlay b/tests/drivers/dma/chan_blen_transfer/boards/nucleo_h743zi.overlay index 35e5f3935d3..3e8bd92d5fb 100644 --- a/tests/drivers/dma/chan_blen_transfer/boards/nucleo_h743zi.overlay +++ b/tests/drivers/dma/chan_blen_transfer/boards/nucleo_h743zi.overlay @@ -12,7 +12,7 @@ status = "okay"; }; -test_dma0: &dmamux1 { +tst_dma0: &dmamux1 { status = "okay"; }; @@ -27,6 +27,6 @@ test_dma0: &dmamux1 { status = "okay"; }; -test_dma1: &dmamux2 { +tst_dma1: &dmamux2 { status = "okay"; }; diff --git a/tests/drivers/dma/chan_blen_transfer/boards/nucleo_l053r8.overlay b/tests/drivers/dma/chan_blen_transfer/boards/nucleo_l053r8.overlay index 5af4ad706a5..4e19e140606 100644 --- a/tests/drivers/dma/chan_blen_transfer/boards/nucleo_l053r8.overlay +++ b/tests/drivers/dma/chan_blen_transfer/boards/nucleo_l053r8.overlay @@ -4,6 +4,6 @@ * SPDX-License-Identifier: Apache-2.0 */ -test_dma0: &dma1 { +tst_dma0: &dma1 { status = "okay"; }; diff --git a/tests/drivers/dma/chan_blen_transfer/boards/nucleo_l152re.overlay b/tests/drivers/dma/chan_blen_transfer/boards/nucleo_l152re.overlay index d46897cf66d..f93b5145243 100644 --- a/tests/drivers/dma/chan_blen_transfer/boards/nucleo_l152re.overlay +++ b/tests/drivers/dma/chan_blen_transfer/boards/nucleo_l152re.overlay @@ -4,4 +4,4 @@ * SPDX-License-Identifier: Apache-2.0 */ -test_dma0: &dma1 { }; +tst_dma0: &dma1 { }; diff --git a/tests/drivers/dma/chan_blen_transfer/boards/nucleo_l476rg.overlay b/tests/drivers/dma/chan_blen_transfer/boards/nucleo_l476rg.overlay index 1fcaea554de..3bd993a9f4f 100644 --- a/tests/drivers/dma/chan_blen_transfer/boards/nucleo_l476rg.overlay +++ b/tests/drivers/dma/chan_blen_transfer/boards/nucleo_l476rg.overlay @@ -4,7 +4,7 @@ * SPDX-License-Identifier: Apache-2.0 */ -test_dma0: &dma1 { +tst_dma0: &dma1 { status = "okay"; }; diff --git a/tests/drivers/dma/chan_blen_transfer/boards/nucleo_l496zg.overlay b/tests/drivers/dma/chan_blen_transfer/boards/nucleo_l496zg.overlay index 34515723219..9efc8cf1c20 100644 --- a/tests/drivers/dma/chan_blen_transfer/boards/nucleo_l496zg.overlay +++ b/tests/drivers/dma/chan_blen_transfer/boards/nucleo_l496zg.overlay @@ -8,6 +8,6 @@ status = "okay"; }; -test_dma0: &dma2 { +tst_dma0: &dma2 { status = "okay"; }; diff --git a/tests/drivers/dma/chan_blen_transfer/boards/nucleo_l552ze_q.overlay b/tests/drivers/dma/chan_blen_transfer/boards/nucleo_l552ze_q.overlay index 2a76164fcef..dd0ed420811 100644 --- a/tests/drivers/dma/chan_blen_transfer/boards/nucleo_l552ze_q.overlay +++ b/tests/drivers/dma/chan_blen_transfer/boards/nucleo_l552ze_q.overlay @@ -12,6 +12,6 @@ status = "okay"; }; -test_dma0: &dmamux1 { +tst_dma0: &dmamux1 { status = "okay"; }; diff --git a/tests/drivers/dma/chan_blen_transfer/boards/nucleo_u575zi_q.overlay b/tests/drivers/dma/chan_blen_transfer/boards/nucleo_u575zi_q.overlay index dd4daeb0d57..0bd5ba64628 100644 --- a/tests/drivers/dma/chan_blen_transfer/boards/nucleo_u575zi_q.overlay +++ b/tests/drivers/dma/chan_blen_transfer/boards/nucleo_u575zi_q.overlay @@ -4,6 +4,6 @@ * SPDX-License-Identifier: Apache-2.0 */ -test_dma0: &gpdma1 { +tst_dma0: &gpdma1 { status = "okay"; }; diff --git a/tests/drivers/dma/chan_blen_transfer/boards/nucleo_wb55rg.overlay b/tests/drivers/dma/chan_blen_transfer/boards/nucleo_wb55rg.overlay index 9b3ea314827..eae38d89573 100644 --- a/tests/drivers/dma/chan_blen_transfer/boards/nucleo_wb55rg.overlay +++ b/tests/drivers/dma/chan_blen_transfer/boards/nucleo_wb55rg.overlay @@ -12,6 +12,6 @@ status = "okay"; }; -test_dma0: &dmamux1 { +tst_dma0: &dmamux1 { status = "okay"; }; diff --git a/tests/drivers/dma/chan_blen_transfer/boards/nucleo_wl55jc.overlay b/tests/drivers/dma/chan_blen_transfer/boards/nucleo_wl55jc.overlay index 9b3ea314827..eae38d89573 100644 --- a/tests/drivers/dma/chan_blen_transfer/boards/nucleo_wl55jc.overlay +++ b/tests/drivers/dma/chan_blen_transfer/boards/nucleo_wl55jc.overlay @@ -12,6 +12,6 @@ status = "okay"; }; -test_dma0: &dmamux1 { +tst_dma0: &dmamux1 { status = "okay"; }; diff --git a/tests/drivers/dma/chan_blen_transfer/boards/seeeduino_xiao.overlay b/tests/drivers/dma/chan_blen_transfer/boards/seeeduino_xiao.overlay index c2343bf0892..2731332e26b 100644 --- a/tests/drivers/dma/chan_blen_transfer/boards/seeeduino_xiao.overlay +++ b/tests/drivers/dma/chan_blen_transfer/boards/seeeduino_xiao.overlay @@ -4,4 +4,4 @@ * SPDX-License-Identifier: Apache-2.0 */ -test_dma0: &dmac { }; +tst_dma0: &dmac { }; diff --git a/tests/drivers/dma/chan_blen_transfer/boards/stm32f3_disco.overlay b/tests/drivers/dma/chan_blen_transfer/boards/stm32f3_disco.overlay index d46897cf66d..f93b5145243 100644 --- a/tests/drivers/dma/chan_blen_transfer/boards/stm32f3_disco.overlay +++ b/tests/drivers/dma/chan_blen_transfer/boards/stm32f3_disco.overlay @@ -4,4 +4,4 @@ * SPDX-License-Identifier: Apache-2.0 */ -test_dma0: &dma1 { }; +tst_dma0: &dma1 { }; diff --git a/tests/drivers/dma/chan_blen_transfer/boards/stm32g0316_disco.overlay b/tests/drivers/dma/chan_blen_transfer/boards/stm32g0316_disco.overlay index f6ef210b850..f7c6c591936 100644 --- a/tests/drivers/dma/chan_blen_transfer/boards/stm32g0316_disco.overlay +++ b/tests/drivers/dma/chan_blen_transfer/boards/stm32g0316_disco.overlay @@ -8,6 +8,6 @@ status = "okay"; }; -test_dma0: &dmamux1 { +tst_dma0: &dmamux1 { status = "okay"; }; diff --git a/tests/drivers/dma/chan_blen_transfer/boards/stm32h573i_dk.overlay b/tests/drivers/dma/chan_blen_transfer/boards/stm32h573i_dk.overlay index f2f99740762..785a4da6854 100644 --- a/tests/drivers/dma/chan_blen_transfer/boards/stm32h573i_dk.overlay +++ b/tests/drivers/dma/chan_blen_transfer/boards/stm32h573i_dk.overlay @@ -4,6 +4,6 @@ * SPDX-License-Identifier: Apache-2.0 */ -test_dma0: &gpdma1 { +tst_dma0: &gpdma1 { status = "okay"; }; diff --git a/tests/drivers/dma/chan_blen_transfer/boards/stm32l562e_dk.overlay b/tests/drivers/dma/chan_blen_transfer/boards/stm32l562e_dk.overlay index 2a76164fcef..dd0ed420811 100644 --- a/tests/drivers/dma/chan_blen_transfer/boards/stm32l562e_dk.overlay +++ b/tests/drivers/dma/chan_blen_transfer/boards/stm32l562e_dk.overlay @@ -12,6 +12,6 @@ status = "okay"; }; -test_dma0: &dmamux1 { +tst_dma0: &dmamux1 { status = "okay"; }; diff --git a/tests/drivers/dma/chan_blen_transfer/boards/stm32mp157c_dk2.overlay b/tests/drivers/dma/chan_blen_transfer/boards/stm32mp157c_dk2.overlay index ee813175428..184a60e7b85 100644 --- a/tests/drivers/dma/chan_blen_transfer/boards/stm32mp157c_dk2.overlay +++ b/tests/drivers/dma/chan_blen_transfer/boards/stm32mp157c_dk2.overlay @@ -10,6 +10,6 @@ status = "okay"; }; -test_dma0: &dmamux { +tst_dma0: &dmamux { status = "okay"; }; diff --git a/tests/drivers/dma/chan_blen_transfer/boards/twr_ke18f.overlay b/tests/drivers/dma/chan_blen_transfer/boards/twr_ke18f.overlay index 5069c0b0a5f..b2314c944bd 100644 --- a/tests/drivers/dma/chan_blen_transfer/boards/twr_ke18f.overlay +++ b/tests/drivers/dma/chan_blen_transfer/boards/twr_ke18f.overlay @@ -4,4 +4,4 @@ * SPDX-License-Identifier: Apache-2.0 */ -test_dma0: &edma { }; +tst_dma0: &edma { }; diff --git a/tests/drivers/dma/chan_blen_transfer/src/test_dma.c b/tests/drivers/dma/chan_blen_transfer/src/test_dma.c index a546715f37f..be1415fdaae 100644 --- a/tests/drivers/dma/chan_blen_transfer/src/test_dma.c +++ b/tests/drivers/dma/chan_blen_transfer/src/test_dma.c @@ -91,7 +91,7 @@ static int test_task(const struct device *dma, uint32_t chan_id, uint32_t blen) return TC_PASS; } -#define DMA_NAME(i, _) test_dma##i +#define DMA_NAME(i, _) tst_dma##i #define DMA_LIST LISTIFY(CONFIG_DMA_LOOP_TRANSFER_NUMBER_OF_DMAS, DMA_NAME, (,)) #if CONFIG_DMA_TRANSFER_BURST16 diff --git a/tests/drivers/dma/chan_blen_transfer/testcase.yaml b/tests/drivers/dma/chan_blen_transfer/testcase.yaml index 374ae8e6d48..22c62b9d50b 100644 --- a/tests/drivers/dma/chan_blen_transfer/testcase.yaml +++ b/tests/drivers/dma/chan_blen_transfer/testcase.yaml @@ -8,13 +8,13 @@ tests: integration_platforms: - native_posix - native_posix_64 - filter: dt_nodelabel_enabled("test_dma0") + filter: dt_nodelabel_enabled("tst_dma0") drivers.dma.chan_blen_transfer.low_footprint: tags: - dma min_ram: 12 depends_on: - dma - filter: dt_nodelabel_enabled("test_dma0") + filter: dt_nodelabel_enabled("tst_dma0") platform_allow: - nucleo_c031c6 From 8b80a2fd04e93eec6664a606ba6bfec29703c700 Mon Sep 17 00:00:00 2001 From: Anas Nashif Date: Wed, 31 Jan 2024 09:19:56 -0500 Subject: [PATCH 3237/3723] drivers: dma: andes: remove soc.h inclusion Not needed or present soc.h Signed-off-by: Anas Nashif --- drivers/dma/dma_andes_atcdmac300.c | 1 - 1 file changed, 1 deletion(-) diff --git a/drivers/dma/dma_andes_atcdmac300.c b/drivers/dma/dma_andes_atcdmac300.c index ef90868f943..8132dd1749c 100644 --- a/drivers/dma/dma_andes_atcdmac300.c +++ b/drivers/dma/dma_andes_atcdmac300.c @@ -11,7 +11,6 @@ #include #include #include -#include #define DT_DRV_COMPAT andestech_atcdmac300 From a1e03d079a781b1d779cbd1534cf314b0608abf7 Mon Sep 17 00:00:00 2001 From: Anas Nashif Date: Mon, 29 Jan 2024 17:54:42 +0000 Subject: [PATCH 3238/3723] console: winstream: define as a proper console eb2e5de01c2 made this a console driver but without adding the needed hooks. This adds the hooks to support the console interface. Fixes #65987 Fixes #66264 Signed-off-by: Anas Nashif --- drivers/console/winstream_console.c | 24 ++++++++++++++++++++++++ 1 file changed, 24 insertions(+) diff --git a/drivers/console/winstream_console.c b/drivers/console/winstream_console.c index abc5344593a..442616aaf3e 100644 --- a/drivers/console/winstream_console.c +++ b/drivers/console/winstream_console.c @@ -46,6 +46,29 @@ int arch_printk_char_out(int c) return 0; } +#if defined(CONFIG_STDOUT_CONSOLE) +extern void __stdout_hook_install(int (*hook)(int)); +#else +#define __stdout_hook_install(x) \ + do {/* nothing */ \ + } while ((0)) +#endif + +#if defined(CONFIG_PRINTK) +extern void __printk_hook_install(int (*fn)(int)); +#else +#define __printk_hook_install(x) \ + do {/* nothing */ \ + } while ((0)) +#endif + +static void winstream_console_hook_install(void) +{ + __stdout_hook_install(arch_printk_char_out); + __printk_hook_install(arch_printk_char_out); +} + + static int winstream_console_init(void) { const struct device *dev = DEVICE_DT_GET(DT_CHOSEN(zephyr_console)); @@ -58,6 +81,7 @@ static int winstream_console_init(void) arch_xtensa_uncached_ptr((__sparse_force void __sparse_cache *)config->mem_base); winstream = sys_winstream_init(buf, config->size); + winstream_console_hook_install(); return 0; } From a8490c3c3e7ae51ee6bb3769e5652267125105dc Mon Sep 17 00:00:00 2001 From: Navinkumar Balabakthan Date: Thu, 24 Aug 2023 06:03:17 +0000 Subject: [PATCH 3239/3723] drivers: interrupt_controller: changes in shared irq Updated the shared IRQ handler function in the shared interrupt controller drivers to include support for the 'irq_number' parameter. When a single driver manages multiple shared IRQs, it becomes challenging to determine which IRQ line is invoking the handler. Therefore, I've introduced an option to share the IRQ number to address this issue. Signed-off-by: Navinkumar Balabakthan --- drivers/interrupt_controller/intc_shared_irq.c | 4 ++-- include/zephyr/shared_irq.h | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/drivers/interrupt_controller/intc_shared_irq.c b/drivers/interrupt_controller/intc_shared_irq.c index 0ec50b0c2e6..337a1e432b7 100644 --- a/drivers/interrupt_controller/intc_shared_irq.c +++ b/drivers/interrupt_controller/intc_shared_irq.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2015 Intel Corporation. + * Copyright (c) 2015 - 2023 Intel Corporation. * * SPDX-License-Identifier: Apache-2.0 */ @@ -125,7 +125,7 @@ void shared_irq_isr(const struct device *dev) for (i = 0U; i < config->client_count; i++) { if (clients->client[i].isr_dev) { - clients->client[i].isr_func(clients->client[i].isr_dev); + clients->client[i].isr_func(clients->client[i].isr_dev, config->irq_num); } } } diff --git a/include/zephyr/shared_irq.h b/include/zephyr/shared_irq.h index d95d727076d..575ef119d3a 100644 --- a/include/zephyr/shared_irq.h +++ b/include/zephyr/shared_irq.h @@ -1,7 +1,7 @@ /* shared_irq - Shared interrupt driver */ /* - * Copyright (c) 2015 Intel corporation + * Copyright (c) 2015 - 2023 Intel corporation * * SPDX-License-Identifier: Apache-2.0 */ @@ -14,7 +14,7 @@ extern "C" { #endif -typedef int (*isr_t)(const struct device *dev); +typedef int (*isr_t)(const struct device *dev, unsigned int irq_number); /* driver API definition */ typedef int (*shared_irq_register_t)(const struct device *dev, From 253003d737898e66cf57c7a50d042efae14b8d1d Mon Sep 17 00:00:00 2001 From: Navinkumar Balabakthan Date: Fri, 5 Jan 2024 13:05:34 +0000 Subject: [PATCH 3240/3723] doc: releases: shared_irq changes added in doc shared_irq api changes updated in migration-guide-3.6. Signed-off-by: Navinkumar Balabakthan --- doc/releases/migration-guide-3.6.rst | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/doc/releases/migration-guide-3.6.rst b/doc/releases/migration-guide-3.6.rst index c028555890f..46587dea64e 100644 --- a/doc/releases/migration-guide-3.6.rst +++ b/doc/releases/migration-guide-3.6.rst @@ -112,6 +112,7 @@ Device Drivers and Device Tree drdy-pin = <2>; }; }; + * The optional :c:func:`setup()` function in the Bluetooth HCI driver API (enabled through :kconfig:option:`CONFIG_BT_HCI_SETUP`) has gained a function parameter of type :c:struct:`bt_hci_setup_params`. By default, the struct is empty, but drivers can opt-in to @@ -333,6 +334,13 @@ Device Drivers and Device Tree * ``CONFIG_PINCTRL_RA`` -> :kconfig:option:`CONFIG_PINCTRL_RENESAS_RA` * ``CONFIG_UART_RA`` -> :kconfig:option:`CONFIG_UART_RENESAS_RA` +* The function signature of the ``isr_t`` callback function passed to the ``shared_irq`` + interrupt controller driver API via :c:func:`shared_irq_isr_register()` has changed. + The callback now takes an additional `irq_number` parameter. Out-of-tree users of + this API will need to be updated. + + (:github:`66427`) + Power Management ================ From 2e001dda6b3ed7e4372eea2a6c827b0c7aac7780 Mon Sep 17 00:00:00 2001 From: Marco Widmer Date: Fri, 12 Jan 2024 15:16:05 +0100 Subject: [PATCH 3241/3723] rtio: Fix unused argument When compiling with CONFIG_RTIO_SYS_MEM_BLOCKS=n, rtio.h causes unused argument warnings. Align the implementation of rtio_block_pool_free with rtio_block_pool_alloc and add ARG_UNUSED() statements for the arguments. Signed-off-by: Marco Widmer --- include/zephyr/rtio/rtio.h | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/include/zephyr/rtio/rtio.h b/include/zephyr/rtio/rtio.h index fe0f5b72c97..79ab78dc58c 100644 --- a/include/zephyr/rtio/rtio.h +++ b/include/zephyr/rtio/rtio.h @@ -699,7 +699,11 @@ static inline int rtio_block_pool_alloc(struct rtio *r, size_t min_sz, static inline void rtio_block_pool_free(struct rtio *r, void *buf, uint32_t buf_len) { -#ifdef CONFIG_RTIO_SYS_MEM_BLOCKS +#ifndef CONFIG_RTIO_SYS_MEM_BLOCKS + ARG_UNUSED(r); + ARG_UNUSED(buf); + ARG_UNUSED(buf_len); +#else size_t num_blks = buf_len >> r->block_pool->info.blk_sz_shift; sys_mem_blocks_free_contiguous(r->block_pool, buf, num_blks); From ace435d0d17015bf97a07264c5f02a2cf64ed504 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Kristoffer=20Rist=20Sk=C3=B8ien?= Date: Mon, 29 Jan 2024 16:49:25 +0100 Subject: [PATCH 3242/3723] Bluetooth: Audio: Moved seq_num check MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Moved seq_num check to after bt_iso_chan_send. This prevents WRN prints if ISO send fails. Signed-off-by: Kristoffer Rist Skøien --- subsys/bluetooth/audio/bap_stream.c | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/subsys/bluetooth/audio/bap_stream.c b/subsys/bluetooth/audio/bap_stream.c index 8377ec6e20e..07ff97c064e 100644 --- a/subsys/bluetooth/audio/bap_stream.c +++ b/subsys/bluetooth/audio/bap_stream.c @@ -245,6 +245,7 @@ static bool bt_bap_stream_can_send(const struct bt_bap_stream *stream) int bt_bap_stream_send(struct bt_bap_stream *stream, struct net_buf *buf, uint16_t seq_num, uint32_t ts) { + int ret; struct bt_bap_ep *ep; if (stream == NULL || stream->ep == NULL) { @@ -265,6 +266,12 @@ int bt_bap_stream_send(struct bt_bap_stream *stream, struct net_buf *buf, return -EBADMSG; } + ret = bt_iso_chan_send(bt_bap_stream_iso_chan_get(stream), + buf, seq_num, ts); + if (ret) { + return ret; + } + #if defined(CONFIG_BT_BAP_DEBUG_STREAM_SEQ_NUM) if (stream->_prev_seq_num != 0U && seq_num != 0U && (stream->_prev_seq_num + 1U) != seq_num) { @@ -277,8 +284,7 @@ int bt_bap_stream_send(struct bt_bap_stream *stream, struct net_buf *buf, /* TODO: Add checks for broadcast sink */ - return bt_iso_chan_send(bt_bap_stream_iso_chan_get(stream), - buf, seq_num, ts); + return ret; } int bt_bap_stream_get_tx_sync(struct bt_bap_stream *stream, struct bt_iso_tx_info *info) From a8a39231e7acc28a0ac92111ac46977482227707 Mon Sep 17 00:00:00 2001 From: Pisit Sawangvonganan Date: Sat, 27 Jan 2024 16:58:45 +0700 Subject: [PATCH 3243/3723] wifi: shell: introduce local 'sh' variable This commit introduces a local variable 'sh' to store 'context.sh' for use with the 'shell_fprintf' function. By doing so, we avoid the repeated dereferencing of 'context.sh', thereby reducing the code footprint. Signed-off-by: Pisit Sawangvonganan --- subsys/net/l2/wifi/wifi_shell.c | 80 ++++++++++++++++++--------------- 1 file changed, 45 insertions(+), 35 deletions(-) diff --git a/subsys/net/l2/wifi/wifi_shell.c b/subsys/net/l2/wifi/wifi_shell.c index d84dbb39c8e..a9c4c3c8209 100644 --- a/subsys/net/l2/wifi/wifi_shell.c +++ b/subsys/net/l2/wifi/wifi_shell.c @@ -184,11 +184,12 @@ static void handle_wifi_raw_scan_result(struct net_mgmt_event_callback *cb) int rssi; int i = 0; uint8_t mac_string_buf[sizeof("xx:xx:xx:xx:xx:xx")]; + const struct shell *sh = context.sh; scan_result++; if (scan_result == 1U) { - print(context.sh, SHELL_NORMAL, + print(sh, SHELL_NORMAL, "\n%-4s | %-13s | %-4s | %-15s | %-15s | %-32s\n", "Num", "Channel (Band)", "RSSI", "BSSID", "Frame length", "Frame Body"); } @@ -197,7 +198,7 @@ static void handle_wifi_raw_scan_result(struct net_mgmt_event_callback *cb) channel = wifi_freq_to_channel(raw->frequency); band = wifi_freq_to_band(raw->frequency); - print(context.sh, SHELL_NORMAL, "%-4d | %-4u (%-6s) | %-4d | %s | %-4d ", + print(sh, SHELL_NORMAL, "%-4d | %-4u (%-6s) | %-4d | %s | %-4d ", scan_result, channel, wifi_band_txt(band), @@ -206,10 +207,10 @@ static void handle_wifi_raw_scan_result(struct net_mgmt_event_callback *cb) sizeof(mac_string_buf)), raw->frame_length); for (i = 0; i < 32; i++) { - print(context.sh, SHELL_NORMAL, "%02X ", *(raw->data + i)); + print(sh, SHELL_NORMAL, "%02X ", *(raw->data + i)); } - print(context.sh, SHELL_NORMAL, "\n"); + print(sh, SHELL_NORMAL, "\n"); } #endif /* CONFIG_WIFI_MGMT_RAW_SCAN_RESULTS */ @@ -217,12 +218,13 @@ static void handle_wifi_scan_done(struct net_mgmt_event_callback *cb) { const struct wifi_status *status = (const struct wifi_status *)cb->info; + const struct shell *sh = context.sh; if (status->status) { - print(context.sh, SHELL_WARNING, + print(sh, SHELL_WARNING, "Scan request failed (%d)\n", status->status); } else { - print(context.sh, SHELL_NORMAL, "Scan request done\n"); + print(sh, SHELL_NORMAL, "Scan request done\n"); } scan_result = 0U; @@ -266,47 +268,50 @@ static void print_twt_params(uint8_t dialog_token, uint8_t flow_id, bool trigger, uint32_t twt_wake_interval, uint64_t twt_interval) { - print(context.sh, SHELL_NORMAL, "TWT Dialog token: %d\n", + const struct shell *sh = context.sh; + + print(sh, SHELL_NORMAL, "TWT Dialog token: %d\n", dialog_token); - print(context.sh, SHELL_NORMAL, "TWT flow ID: %d\n", + print(sh, SHELL_NORMAL, "TWT flow ID: %d\n", flow_id); - print(context.sh, SHELL_NORMAL, "TWT negotiation type: %s\n", + print(sh, SHELL_NORMAL, "TWT negotiation type: %s\n", wifi_twt_negotiation_type_txt(negotiation_type)); - print(context.sh, SHELL_NORMAL, "TWT responder: %s\n", + print(sh, SHELL_NORMAL, "TWT responder: %s\n", responder ? "true" : "false"); - print(context.sh, SHELL_NORMAL, "TWT implicit: %s\n", + print(sh, SHELL_NORMAL, "TWT implicit: %s\n", implicit ? "true" : "false"); - print(context.sh, SHELL_NORMAL, "TWT announce: %s\n", + print(sh, SHELL_NORMAL, "TWT announce: %s\n", announce ? "true" : "false"); - print(context.sh, SHELL_NORMAL, "TWT trigger: %s\n", + print(sh, SHELL_NORMAL, "TWT trigger: %s\n", trigger ? "true" : "false"); - print(context.sh, SHELL_NORMAL, "TWT wake interval: %d us\n", + print(sh, SHELL_NORMAL, "TWT wake interval: %d us\n", twt_wake_interval); - print(context.sh, SHELL_NORMAL, "TWT interval: %lld us\n", + print(sh, SHELL_NORMAL, "TWT interval: %lld us\n", twt_interval); - print(context.sh, SHELL_NORMAL, "========================\n"); + print(sh, SHELL_NORMAL, "========================\n"); } static void handle_wifi_twt_event(struct net_mgmt_event_callback *cb) { const struct wifi_twt_params *resp = (const struct wifi_twt_params *)cb->info; + const struct shell *sh = context.sh; if (resp->operation == WIFI_TWT_TEARDOWN) { if (resp->teardown_status == WIFI_TWT_TEARDOWN_SUCCESS) { - print(context.sh, SHELL_NORMAL, "TWT teardown succeeded for flow ID %d\n", + print(sh, SHELL_NORMAL, "TWT teardown succeeded for flow ID %d\n", resp->flow_id); } else { - print(context.sh, SHELL_NORMAL, "TWT teardown failed for flow ID %d\n", + print(sh, SHELL_NORMAL, "TWT teardown failed for flow ID %d\n", resp->flow_id); } return; } if (resp->resp_status == WIFI_TWT_RESP_RECEIVED) { - print(context.sh, SHELL_NORMAL, "TWT response: %s\n", + print(sh, SHELL_NORMAL, "TWT response: %s\n", wifi_twt_setup_cmd_txt(resp->setup_cmd)); - print(context.sh, SHELL_NORMAL, "== TWT negotiated parameters ==\n"); + print(sh, SHELL_NORMAL, "== TWT negotiated parameters ==\n"); print_twt_params(resp->dialog_token, resp->flow_id, resp->negotiation_type, @@ -317,7 +322,7 @@ static void handle_wifi_twt_event(struct net_mgmt_event_callback *cb) resp->setup.twt_wake_interval, resp->setup.twt_interval); } else { - print(context.sh, SHELL_NORMAL, "TWT response timed out\n"); + print(sh, SHELL_NORMAL, "TWT response timed out\n"); } } @@ -325,12 +330,13 @@ static void handle_wifi_ap_enable_result(struct net_mgmt_event_callback *cb) { const struct wifi_status *status = (const struct wifi_status *)cb->info; + const struct shell *sh = context.sh; if (status->status) { - print(context.sh, SHELL_WARNING, + print(sh, SHELL_WARNING, "AP enable request failed (%d)\n", status->status); } else { - print(context.sh, SHELL_NORMAL, "AP enabled\n"); + print(sh, SHELL_NORMAL, "AP enabled\n"); } } @@ -338,12 +344,13 @@ static void handle_wifi_ap_disable_result(struct net_mgmt_event_callback *cb) { const struct wifi_status *status = (const struct wifi_status *)cb->info; + const struct shell *sh = context.sh; if (status->status) { - print(context.sh, SHELL_WARNING, + print(sh, SHELL_WARNING, "AP disable request failed (%d)\n", status->status); } else { - print(context.sh, SHELL_NORMAL, "AP disabled\n"); + print(sh, SHELL_NORMAL, "AP disabled\n"); } k_mutex_lock(&wifi_ap_sta_list_lock, K_FOREVER); @@ -355,10 +362,11 @@ static void handle_wifi_ap_sta_connected(struct net_mgmt_event_callback *cb) { const struct wifi_ap_sta_info *sta_info = (const struct wifi_ap_sta_info *)cb->info; + const struct shell *sh = context.sh; uint8_t mac_string_buf[sizeof("xx:xx:xx:xx:xx:xx")]; int i; - print(context.sh, SHELL_NORMAL, "Station connected: %s\n", + print(sh, SHELL_NORMAL, "Station connected: %s\n", net_sprint_ll_addr_buf(sta_info->mac, WIFI_MAC_ADDR_LEN, mac_string_buf, sizeof(mac_string_buf))); @@ -371,7 +379,7 @@ static void handle_wifi_ap_sta_connected(struct net_mgmt_event_callback *cb) } } if (i == CONFIG_WIFI_SHELL_MAX_AP_STA) { - print(context.sh, SHELL_WARNING, "No space to store station info: " + print(sh, SHELL_WARNING, "No space to store station info: " "Increase CONFIG_WIFI_SHELL_MAX_AP_STA\n"); } k_mutex_unlock(&wifi_ap_sta_list_lock); @@ -381,9 +389,10 @@ static void handle_wifi_ap_sta_disconnected(struct net_mgmt_event_callback *cb) { const struct wifi_ap_sta_info *sta_info = (const struct wifi_ap_sta_info *)cb->info; + const struct shell *sh = context.sh; uint8_t mac_string_buf[sizeof("xx:xx:xx:xx:xx:xx")]; - print(context.sh, SHELL_NORMAL, "Station disconnected: %s\n", + print(sh, SHELL_NORMAL, "Station disconnected: %s\n", net_sprint_ll_addr_buf(sta_info->mac, WIFI_MAC_ADDR_LEN, mac_string_buf, sizeof(mac_string_buf))); @@ -449,6 +458,7 @@ static int __wifi_args_to_params(size_t argc, char *argv[], { char *endptr; int idx = 1; + const struct shell *sh = context.sh; /* Defaults */ params->band = WIFI_FREQ_BAND_UNKNOWN; @@ -459,7 +469,7 @@ static int __wifi_args_to_params(size_t argc, char *argv[], params->ssid = argv[0]; params->ssid_length = strlen(params->ssid); if (params->ssid_length > WIFI_SSID_MAX_LEN) { - print(context.sh, SHELL_WARNING, + print(sh, SHELL_WARNING, "SSID too long (max %d characters)\n", WIFI_SSID_MAX_LEN); return -EINVAL; @@ -477,7 +487,7 @@ static int __wifi_args_to_params(size_t argc, char *argv[], size_t offset = 0; if (*endptr != '\0') { - print(context.sh, SHELL_ERROR, + print(sh, SHELL_ERROR, "Failed to parse channel: %s: endp: %s, err: %s\n", argv[idx], endptr, @@ -520,7 +530,7 @@ static int __wifi_args_to_params(size_t argc, char *argv[], band ? "," : "", wifi_band_txt(all_bands[band])); if (offset >= sizeof(bands_str)) { - print(context.sh, SHELL_ERROR, + print(sh, SHELL_ERROR, "Failed to parse channel: %s: " "band string too long\n", argv[idx]); @@ -535,7 +545,7 @@ static int __wifi_args_to_params(size_t argc, char *argv[], } if (!found) { - print(context.sh, SHELL_ERROR, + print(sh, SHELL_ERROR, "Invalid channel: %ld, checked bands: %s\n", channel, bands_str); @@ -571,7 +581,7 @@ static int __wifi_args_to_params(size_t argc, char *argv[], if (security == WIFI_SECURITY_TYPE_NONE || security == WIFI_SECURITY_TYPE_WPA_PSK) { - print(context.sh, SHELL_ERROR, + print(sh, SHELL_ERROR, "MFP not supported for security type %s\n", wifi_security_txt(security)); return -EINVAL; @@ -589,7 +599,7 @@ static int __wifi_args_to_params(size_t argc, char *argv[], params->psk_length > WIFI_PSK_MAX_LEN) || (params->security == WIFI_SECURITY_TYPE_SAE && params->psk_length > WIFI_SAE_PSWD_MAX_LEN)) { - print(context.sh, SHELL_ERROR, + print(sh, SHELL_ERROR, "Invalid PSK length (%d) for security type %s\n", params->psk_length, wifi_security_txt(params->security)); @@ -969,7 +979,7 @@ static int cmd_wifi_ps(const struct shell *sh, size_t argc, char *argv[]) config.twt_flows[i].trigger, config.twt_flows[i].twt_wake_interval, config.twt_flows[i].twt_interval); - shell_fprintf(context.sh, SHELL_NORMAL, + shell_fprintf(sh, SHELL_NORMAL, "TWT Wake ahead duration : %d us\n", config.twt_flows[i].twt_wake_ahead_duration); } From 10939c7a02120e91dc8743ee135a593e0707bd1f Mon Sep 17 00:00:00 2001 From: Pisit Sawangvonganan Date: Sat, 27 Jan 2024 23:27:18 +0700 Subject: [PATCH 3244/3723] wifi: shell: move "scan_result" variable into context struct Moved 'scan_result' from a standalone variable into the 'context' struct to enhance code optimization. Signed-off-by: Pisit Sawangvonganan --- subsys/net/l2/wifi/wifi_shell.c | 19 +++++++++---------- 1 file changed, 9 insertions(+), 10 deletions(-) diff --git a/subsys/net/l2/wifi/wifi_shell.c b/subsys/net/l2/wifi/wifi_shell.c index a9c4c3c8209..7f7d80c874f 100644 --- a/subsys/net/l2/wifi/wifi_shell.c +++ b/subsys/net/l2/wifi/wifi_shell.c @@ -52,6 +52,7 @@ LOG_MODULE_REGISTER(net_wifi_shell, LOG_LEVEL_INF); static struct { const struct shell *sh; + uint32_t scan_result; union { struct { @@ -64,8 +65,6 @@ static struct { }; } context; -static uint32_t scan_result; - static struct net_mgmt_event_callback wifi_shell_mgmt_cb; static struct wifi_reg_chan_info chan_info[MAX_REG_CHAN_NUM]; @@ -117,9 +116,9 @@ static void handle_wifi_scan_result(struct net_mgmt_event_callback *cb) (const struct wifi_scan_result *)cb->info; uint8_t mac_string_buf[sizeof("xx:xx:xx:xx:xx:xx")]; - scan_result++; + context.scan_result++; - if (scan_result == 1U) { + if (context.scan_result == 1U) { print(context.sh, SHELL_NORMAL, "\n%-4s | %-32s %-5s | %-13s | %-4s | %-15s | %-17s | %-8s\n", "Num", "SSID", "(len)", "Chan (Band)", "RSSI", "Security", "BSSID", "MFP"); @@ -127,7 +126,7 @@ static void handle_wifi_scan_result(struct net_mgmt_event_callback *cb) print(context.sh, SHELL_NORMAL, "%-4d | %-32s %-5u | %-4u (%-6s) | %-4d | %-15s | %-17s | %-8s\n", - scan_result, entry->ssid, entry->ssid_length, entry->channel, + context.scan_result, entry->ssid, entry->ssid_length, entry->channel, wifi_band_txt(entry->band), entry->rssi, wifi_security_txt(entry->security), @@ -186,9 +185,9 @@ static void handle_wifi_raw_scan_result(struct net_mgmt_event_callback *cb) uint8_t mac_string_buf[sizeof("xx:xx:xx:xx:xx:xx")]; const struct shell *sh = context.sh; - scan_result++; + context.scan_result++; - if (scan_result == 1U) { + if (context.scan_result == 1U) { print(sh, SHELL_NORMAL, "\n%-4s | %-13s | %-4s | %-15s | %-15s | %-32s\n", "Num", "Channel (Band)", "RSSI", "BSSID", "Frame length", "Frame Body"); @@ -199,7 +198,7 @@ static void handle_wifi_raw_scan_result(struct net_mgmt_event_callback *cb) band = wifi_freq_to_band(raw->frequency); print(sh, SHELL_NORMAL, "%-4d | %-4u (%-6s) | %-4d | %s | %-4d ", - scan_result, + context.scan_result, channel, wifi_band_txt(band), rssi, @@ -227,7 +226,7 @@ static void handle_wifi_scan_done(struct net_mgmt_event_callback *cb) print(sh, SHELL_NORMAL, "Scan request done\n"); } - scan_result = 0U; + context.scan_result = 0U; } static void handle_wifi_connect_result(struct net_mgmt_event_callback *cb) @@ -2052,7 +2051,7 @@ static int wifi_shell_init(void) context.sh = NULL; context.all = 0U; - scan_result = 0U; + context.scan_result = 0U; net_mgmt_init_event_callback(&wifi_shell_mgmt_cb, wifi_mgmt_event_handler, From 81342132fb9e5950016a255a160e3d8cef8ef459 Mon Sep 17 00:00:00 2001 From: Pisit Sawangvonganan Date: Sun, 28 Jan 2024 00:21:43 +0700 Subject: [PATCH 3245/3723] wifi: shell: refactor to use PR(...) from "net_shell_private.h" Replaced direct shell_fprintf calls with PR, PR_ERROR, PR_INFO and PR_WARNING macros. This change simplifies the code by using predefined macros. Signed-off-by: Pisit Sawangvonganan --- subsys/net/l2/wifi/CMakeLists.txt | 3 + subsys/net/l2/wifi/wifi_shell.c | 486 ++++++++++++++---------------- 2 files changed, 224 insertions(+), 265 deletions(-) diff --git a/subsys/net/l2/wifi/CMakeLists.txt b/subsys/net/l2/wifi/CMakeLists.txt index 445eb56c0a7..aaf825599f0 100644 --- a/subsys/net/l2/wifi/CMakeLists.txt +++ b/subsys/net/l2/wifi/CMakeLists.txt @@ -2,6 +2,9 @@ zephyr_library() zephyr_library_include_directories(${ZEPHYR_BASE}/subsys/net/ip) +zephyr_library_include_directories_ifdef( + CONFIG_NET_L2_WIFI_SHELL ${ZEPHYR_BASE}/subsys/net/lib/shell + ) zephyr_library_compile_definitions_ifdef( CONFIG_NEWLIB_LIBC __LINUX_ERRNO_EXTENSIONS__ ) diff --git a/subsys/net/l2/wifi/wifi_shell.c b/subsys/net/l2/wifi/wifi_shell.c index 7f7d80c874f..9d24473e5cc 100644 --- a/subsys/net/l2/wifi/wifi_shell.c +++ b/subsys/net/l2/wifi/wifi_shell.c @@ -27,13 +27,13 @@ LOG_MODULE_REGISTER(net_wifi_shell, LOG_LEVEL_INF); #include #include -#include "net_private.h" +#include "net_shell_private.h" #define WIFI_SHELL_MODULE "wifi" #define WIFI_SHELL_MGMT_EVENTS_COMMON (NET_EVENT_WIFI_SCAN_DONE |\ NET_EVENT_WIFI_CONNECT_RESULT |\ - NET_EVENT_WIFI_DISCONNECT_RESULT | \ + NET_EVENT_WIFI_DISCONNECT_RESULT |\ NET_EVENT_WIFI_TWT |\ NET_EVENT_WIFI_RAW_SCAN_RESULT |\ NET_EVENT_WIFI_AP_ENABLE_RESULT |\ @@ -57,9 +57,9 @@ static struct { union { struct { - uint8_t connecting : 1; - uint8_t disconnecting : 1; - uint8_t _unused : 6; + uint8_t connecting: 1; + uint8_t disconnecting: 1; + uint8_t _unused: 6; }; uint8_t all; }; @@ -163,9 +163,9 @@ static enum wifi_frequency_bands wifi_freq_to_band(int frequency) { enum wifi_frequency_bands band = WIFI_FREQ_BAND_2_4_GHZ; - if ((frequency >= 2401) && (frequency <= 2495)) { + if ((frequency >= 2401) && (frequency <= 2495)) { band = WIFI_FREQ_BAND_2_4_GHZ; - } else if ((frequency >= 5170) && (frequency <= 5895)) { + } else if ((frequency >= 5170) && (frequency <= 5895)) { band = WIFI_FREQ_BAND_5_GHZ; } else { band = WIFI_FREQ_BAND_6_GHZ; @@ -452,8 +452,8 @@ static void wifi_mgmt_event_handler(struct net_mgmt_event_callback *cb, } static int __wifi_args_to_params(size_t argc, char *argv[], - struct wifi_connect_req_params *params, - enum wifi_iface_mode iface_mode) + struct wifi_connect_req_params *params, + enum wifi_iface_mode iface_mode) { char *endptr; int idx = 1; @@ -508,14 +508,14 @@ static int __wifi_args_to_params(size_t argc, char *argv[], params->band = WIFI_FREQ_BAND_6_GHZ; break; default: - print(context.sh, SHELL_ERROR, + print(sh, SHELL_ERROR, "Invalid band: %ld\n", channel); return -EINVAL; } } } else { if (channel < 0) { - print(context.sh, SHELL_ERROR, + print(sh, SHELL_ERROR, "Invalid channel: %ld\n", channel); return -EINVAL; } @@ -524,10 +524,10 @@ static int __wifi_args_to_params(size_t argc, char *argv[], if (channel > 0) { for (band = 0; band < ARRAY_SIZE(all_bands); band++) { offset += snprintf(bands_str + offset, - sizeof(bands_str) - offset, - "%s%s", - band ? "," : "", - wifi_band_txt(all_bands[band])); + sizeof(bands_str) - offset, + "%s%s", + band ? "," : "", + wifi_band_txt(all_bands[band])); if (offset >= sizeof(bands_str)) { print(sh, SHELL_ERROR, "Failed to parse channel: %s: " @@ -546,8 +546,8 @@ static int __wifi_args_to_params(size_t argc, char *argv[], if (!found) { print(sh, SHELL_ERROR, "Invalid channel: %ld, checked bands: %s\n", - channel, - bands_str); + channel, + bands_str); return -EINVAL; } @@ -606,7 +606,6 @@ static int __wifi_args_to_params(size_t argc, char *argv[], } } - return 0; } @@ -626,14 +625,13 @@ static int cmd_wifi_connect(const struct shell *sh, size_t argc, if (net_mgmt(NET_REQUEST_WIFI_CONNECT, iface, &cnx_params, sizeof(struct wifi_connect_req_params))) { - shell_fprintf(sh, SHELL_WARNING, - "Connection request failed\n"); + PR_WARNING("Connection request failed\n"); context.connecting = false; return -ENOEXEC; } - shell_fprintf(sh, SHELL_NORMAL, "Connection requested\n"); + PR("Connection requested\n"); return 0; } @@ -653,23 +651,18 @@ static int cmd_wifi_disconnect(const struct shell *sh, size_t argc, context.disconnecting = false; if (status == -EALREADY) { - shell_fprintf(sh, SHELL_INFO, - "Already disconnected\n"); + PR_INFO("Already disconnected\n"); } else { - shell_fprintf(sh, SHELL_WARNING, - "Disconnect request failed\n"); + PR_WARNING("Disconnect request failed\n"); return -ENOEXEC; } } else { - shell_fprintf(sh, SHELL_NORMAL, - "Disconnect requested\n"); + PR("Disconnect requested\n"); } return 0; } - - static int wifi_scan_args_to_params(const struct shell *sh, size_t argc, char *argv[], @@ -702,7 +695,7 @@ static int wifi_scan_args_to_params(const struct shell *sh, } else if (!strncasecmp(optarg, "active", 6)) { params->scan_type = WIFI_SCAN_TYPE_ACTIVE; } else { - shell_fprintf(sh, SHELL_ERROR, "Invalid scan type %s\n", optarg); + PR_ERROR("Invalid scan type %s\n", optarg); return -ENOEXEC; } @@ -710,7 +703,7 @@ static int wifi_scan_args_to_params(const struct shell *sh, break; case 'b': if (wifi_utils_parse_scan_bands(optarg, ¶ms->bands)) { - shell_fprintf(sh, SHELL_ERROR, "Invalid band value(s)\n"); + PR_ERROR("Invalid band value(s)\n"); return -ENOEXEC; } @@ -720,7 +713,7 @@ static int wifi_scan_args_to_params(const struct shell *sh, val = atoi(optarg); if ((val < 5) || (val > 1000)) { - shell_fprintf(sh, SHELL_ERROR, "Invalid dwell_time_active val\n"); + PR_ERROR("Invalid dwell_time_active val\n"); return -ENOEXEC; } @@ -731,7 +724,7 @@ static int wifi_scan_args_to_params(const struct shell *sh, val = atoi(optarg); if ((val < 10) || (val > 1000)) { - shell_fprintf(sh, SHELL_ERROR, "Invalid dwell_time_passive val\n"); + PR_ERROR("Invalid dwell_time_passive val\n"); return -ENOEXEC; } @@ -742,7 +735,7 @@ static int wifi_scan_args_to_params(const struct shell *sh, if (wifi_utils_parse_scan_ssids(optarg, params->ssids, ARRAY_SIZE(params->ssids))) { - shell_fprintf(sh, SHELL_ERROR, "Invalid SSID(s)\n"); + PR_ERROR("Invalid SSID(s)\n"); return -ENOEXEC; } @@ -752,7 +745,7 @@ static int wifi_scan_args_to_params(const struct shell *sh, val = atoi(optarg); if ((val < 0) || (val > 65535)) { - shell_fprintf(sh, SHELL_ERROR, "Invalid max_bss val\n"); + PR_ERROR("Invalid max_bss val\n"); return -ENOEXEC; } @@ -763,9 +756,7 @@ static int wifi_scan_args_to_params(const struct shell *sh, if (wifi_utils_parse_scan_chan(optarg, params->band_chan, ARRAY_SIZE(params->band_chan))) { - shell_fprintf(sh, - SHELL_ERROR, - "Invalid band or channel value(s)\n"); + PR_ERROR("Invalid band or channel value(s)\n"); return -ENOEXEC; } @@ -778,8 +769,8 @@ static int wifi_scan_args_to_params(const struct shell *sh, break; case '?': default: - shell_fprintf(sh, SHELL_ERROR, "Invalid option or option usage: %s\n", - argv[opt_index + 1]); + PR_ERROR("Invalid option or option usage: %s\n", + argv[opt_index + 1]); return -ENOEXEC; } } @@ -803,23 +794,23 @@ static int cmd_wifi_scan(const struct shell *sh, size_t argc, char *argv[]) shell_help(sh); return -ENOEXEC; } else if (!opt_num) { - shell_fprintf(sh, SHELL_WARNING, "No valid option(s) found\n"); + PR_WARNING("No valid option(s) found\n"); do_scan = false; } } if (do_scan) { if (net_mgmt(NET_REQUEST_WIFI_SCAN, iface, ¶ms, sizeof(params))) { - shell_fprintf(sh, SHELL_WARNING, "Scan request failed\n"); + PR_WARNING("Scan request failed\n"); return -ENOEXEC; } - shell_fprintf(sh, SHELL_NORMAL, "Scan requested\n"); + PR("Scan requested\n"); return 0; } - shell_fprintf(sh, SHELL_WARNING, "Scan not initiated\n"); + PR_WARNING("Scan not initiated\n"); return -ENOEXEC; } @@ -831,43 +822,37 @@ static int cmd_wifi_status(const struct shell *sh, size_t argc, char *argv[]) context.sh = sh; if (net_mgmt(NET_REQUEST_WIFI_IFACE_STATUS, iface, &status, - sizeof(struct wifi_iface_status))) { - shell_fprintf(sh, SHELL_WARNING, "Status request failed\n"); + sizeof(struct wifi_iface_status))) { + PR_WARNING("Status request failed\n"); return -ENOEXEC; } - shell_fprintf(sh, SHELL_NORMAL, "Status: successful\n"); - shell_fprintf(sh, SHELL_NORMAL, "==================\n"); - shell_fprintf(sh, SHELL_NORMAL, "State: %s\n", wifi_state_txt(status.state)); + PR("Status: successful\n"); + PR("==================\n"); + PR("State: %s\n", wifi_state_txt(status.state)); if (status.state >= WIFI_STATE_ASSOCIATED) { uint8_t mac_string_buf[sizeof("xx:xx:xx:xx:xx:xx")]; - shell_fprintf(sh, SHELL_NORMAL, "Interface Mode: %s\n", - wifi_mode_txt(status.iface_mode)); - shell_fprintf(sh, SHELL_NORMAL, "Link Mode: %s\n", - wifi_link_mode_txt(status.link_mode)); - shell_fprintf(sh, SHELL_NORMAL, "SSID: %.32s\n", status.ssid); - shell_fprintf(sh, SHELL_NORMAL, "BSSID: %s\n", - net_sprint_ll_addr_buf(status.bssid, + PR("Interface Mode: %s\n", wifi_mode_txt(status.iface_mode)); + PR("Link Mode: %s\n", wifi_link_mode_txt(status.link_mode)); + PR("SSID: %.32s\n", status.ssid); + PR("BSSID: %s\n", + net_sprint_ll_addr_buf(status.bssid, WIFI_MAC_ADDR_LEN, mac_string_buf, - sizeof(mac_string_buf)) - ); - shell_fprintf(sh, SHELL_NORMAL, "Band: %s\n", - wifi_band_txt(status.band)); - shell_fprintf(sh, SHELL_NORMAL, "Channel: %d\n", status.channel); - shell_fprintf(sh, SHELL_NORMAL, "Security: %s\n", - wifi_security_txt(status.security)); - shell_fprintf(sh, SHELL_NORMAL, "MFP: %s\n", - wifi_mfp_txt(status.mfp)); + sizeof(mac_string_buf))); + PR("Band: %s\n", wifi_band_txt(status.band)); + PR("Channel: %d\n", status.channel); + PR("Security: %s\n", wifi_security_txt(status.security)); + PR("MFP: %s\n", wifi_mfp_txt(status.mfp)); if (status.iface_mode == WIFI_MODE_INFRA) { - shell_fprintf(sh, SHELL_NORMAL, "RSSI: %d\n", status.rssi); + PR("RSSI: %d\n", status.rssi); } - shell_fprintf(sh, SHELL_NORMAL, "Beacon Interval: %d\n", status.beacon_interval); - shell_fprintf(sh, SHELL_NORMAL, "DTIM: %d\n", status.dtim_period); - shell_fprintf(sh, SHELL_NORMAL, "TWT: %s\n", - status.twt_capable ? "Supported" : "Not supported"); + PR("Beacon Interval: %d\n", status.beacon_interval); + PR("DTIM: %d\n", status.dtim_period); + PR("TWT: %s\n", + status.twt_capable ? "Supported" : "Not supported"); } return 0; @@ -876,24 +861,23 @@ static int cmd_wifi_status(const struct shell *sh, size_t argc, char *argv[]) #if defined(CONFIG_NET_STATISTICS_WIFI) && \ defined(CONFIG_NET_STATISTICS_USER_API) static void print_wifi_stats(struct net_if *iface, struct net_stats_wifi *data, - const struct shell *sh) + const struct shell *sh) { - shell_fprintf(sh, SHELL_NORMAL, "Statistics for Wi-Fi interface %p [%d]\n", iface, - net_if_get_by_iface(iface)); - - shell_fprintf(sh, SHELL_NORMAL, "Bytes received : %u\n", data->bytes.received); - shell_fprintf(sh, SHELL_NORMAL, "Bytes sent : %u\n", data->bytes.sent); - shell_fprintf(sh, SHELL_NORMAL, "Packets received : %u\n", data->pkts.rx); - shell_fprintf(sh, SHELL_NORMAL, "Packets sent : %u\n", data->pkts.tx); - shell_fprintf(sh, SHELL_NORMAL, "Receive errors : %u\n", data->errors.rx); - shell_fprintf(sh, SHELL_NORMAL, "Send errors : %u\n", data->errors.tx); - shell_fprintf(sh, SHELL_NORMAL, "Bcast received : %u\n", data->broadcast.rx); - shell_fprintf(sh, SHELL_NORMAL, "Bcast sent : %u\n", data->broadcast.tx); - shell_fprintf(sh, SHELL_NORMAL, "Mcast received : %u\n", data->multicast.rx); - shell_fprintf(sh, SHELL_NORMAL, "Mcast sent : %u\n", data->multicast.tx); - shell_fprintf(sh, SHELL_NORMAL, "Beacons received : %u\n", data->sta_mgmt.beacons_rx); - shell_fprintf(sh, SHELL_NORMAL, "Beacons missed : %u\n", - data->sta_mgmt.beacons_miss); + PR("Statistics for Wi-Fi interface %p [%d]\n", iface, + net_if_get_by_iface(iface)); + + PR("Bytes received : %u\n", data->bytes.received); + PR("Bytes sent : %u\n", data->bytes.sent); + PR("Packets received : %u\n", data->pkts.rx); + PR("Packets sent : %u\n", data->pkts.tx); + PR("Receive errors : %u\n", data->errors.rx); + PR("Send errors : %u\n", data->errors.tx); + PR("Bcast received : %u\n", data->broadcast.rx); + PR("Bcast sent : %u\n", data->broadcast.tx); + PR("Mcast received : %u\n", data->multicast.rx); + PR("Mcast sent : %u\n", data->multicast.tx); + PR("Beacons received : %u\n", data->sta_mgmt.beacons_rx); + PR("Beacons missed : %u\n", data->sta_mgmt.beacons_miss); } #endif /* CONFIG_NET_STATISTICS_WIFI && CONFIG_NET_STATISTICS_USER_API */ @@ -914,7 +898,7 @@ static int cmd_wifi_stats(const struct shell *sh, size_t argc, char *argv[]) ARG_UNUSED(argc); ARG_UNUSED(argv); - shell_fprintf(sh, SHELL_INFO, "Set %s to enable %s support.\n", + PR_INFO("Set %s to enable %s support.\n", "CONFIG_NET_STATISTICS_WIFI and CONFIG_NET_STATISTICS_USER_API", "statistics"); #endif /* CONFIG_NET_STATISTICS_WIFI && CONFIG_NET_STATISTICS_USER_API */ @@ -930,7 +914,7 @@ static int cmd_wifi_ps(const struct shell *sh, size_t argc, char *argv[]) context.sh = sh; if (argc > 2) { - shell_fprintf(sh, SHELL_WARNING, "Invalid number of arguments\n"); + PR_WARNING("Invalid number of arguments\n"); return -ENOEXEC; } @@ -939,33 +923,32 @@ static int cmd_wifi_ps(const struct shell *sh, size_t argc, char *argv[]) if (net_mgmt(NET_REQUEST_WIFI_PS_CONFIG, iface, &config, sizeof(config))) { - shell_fprintf(sh, SHELL_WARNING, "Failed to get PS config\n"); + PR_WARNING("Failed to get PS config\n"); return -ENOEXEC; } - shell_fprintf(sh, SHELL_NORMAL, "PS status: %s\n", - wifi_ps_txt(config.ps_params.enabled)); + PR("PS status: %s\n", + wifi_ps_txt(config.ps_params.enabled)); if (config.ps_params.enabled) { - shell_fprintf(sh, SHELL_NORMAL, "PS mode: %s\n", - wifi_ps_mode_txt(config.ps_params.mode)); + PR("PS mode: %s\n", + wifi_ps_mode_txt(config.ps_params.mode)); } - shell_fprintf(sh, SHELL_NORMAL, "PS listen_interval: %d\n", - config.ps_params.listen_interval); + PR("PS listen_interval: %d\n", + config.ps_params.listen_interval); - shell_fprintf(sh, SHELL_NORMAL, "PS wake up mode: %s\n", - config.ps_params.wakeup_mode ? "Listen interval" : "DTIM"); + PR("PS wake up mode: %s\n", + config.ps_params.wakeup_mode ? "Listen interval" : "DTIM"); if (config.ps_params.timeout_ms) { - shell_fprintf(sh, SHELL_NORMAL, "PS timeout: %d ms\n", - config.ps_params.timeout_ms); + PR("PS timeout: %d ms\n", + config.ps_params.timeout_ms); } else { - shell_fprintf(sh, SHELL_NORMAL, "PS timeout: disabled\n"); + PR("PS timeout: disabled\n"); } - if (config.num_twt_flows == 0) { - shell_fprintf(sh, SHELL_NORMAL, "No TWT flows\n"); + PR("No TWT flows\n"); } else { for (int i = 0; i < config.num_twt_flows; i++) { print_twt_params( @@ -978,9 +961,8 @@ static int cmd_wifi_ps(const struct shell *sh, size_t argc, char *argv[]) config.twt_flows[i].trigger, config.twt_flows[i].twt_wake_interval, config.twt_flows[i].twt_interval); - shell_fprintf(sh, SHELL_NORMAL, - "TWT Wake ahead duration : %d us\n", - config.twt_flows[i].twt_wake_ahead_duration); + PR("TWT Wake ahead duration : %d us\n", + config.twt_flows[i].twt_wake_ahead_duration); } } return 0; @@ -991,21 +973,20 @@ static int cmd_wifi_ps(const struct shell *sh, size_t argc, char *argv[]) } else if (!strncasecmp(argv[1], "off", 3)) { params.enabled = WIFI_PS_DISABLED; } else { - shell_fprintf(sh, SHELL_WARNING, "Invalid argument\n"); + PR_WARNING("Invalid argument\n"); return -ENOEXEC; } params.type = WIFI_PS_PARAM_STATE; if (net_mgmt(NET_REQUEST_WIFI_PS, iface, ¶ms, sizeof(params))) { - shell_fprintf(sh, SHELL_WARNING, - "PS %s failed. Reason: %s\n", - params.enabled ? "enable" : "disable", - wifi_ps_get_config_err_code_str(params.fail_reason)); + PR_WARNING("PS %s failed. Reason: %s\n", + params.enabled ? "enable" : "disable", + wifi_ps_get_config_err_code_str(params.fail_reason)); return -ENOEXEC; } - shell_fprintf(sh, SHELL_NORMAL, "%s\n", wifi_ps_txt(params.enabled)); + PR("%s\n", wifi_ps_txt(params.enabled)); return 0; } @@ -1022,20 +1003,20 @@ static int cmd_wifi_ps_mode(const struct shell *sh, size_t argc, char *argv[]) } else if (!strncasecmp(argv[1], "WMM", 3)) { params.mode = WIFI_PS_MODE_WMM; } else { - shell_fprintf(sh, SHELL_WARNING, "Invalid PS mode\n"); + PR_WARNING("Invalid PS mode\n"); return -ENOEXEC; } params.type = WIFI_PS_PARAM_MODE; if (net_mgmt(NET_REQUEST_WIFI_PS, iface, ¶ms, sizeof(params))) { - shell_fprintf(sh, SHELL_WARNING, "%s failed Reason : %s\n", - wifi_ps_mode_txt(params.mode), - wifi_ps_get_config_err_code_str(params.fail_reason)); + PR_WARNING("%s failed Reason : %s\n", + wifi_ps_mode_txt(params.mode), + wifi_ps_get_config_err_code_str(params.fail_reason)); return -ENOEXEC; } - shell_fprintf(sh, SHELL_NORMAL, "%s\n", wifi_ps_mode_txt(params.mode)); + PR("%s\n", wifi_ps_mode_txt(params.mode)); return 0; } @@ -1060,23 +1041,22 @@ static int cmd_wifi_ps_timeout(const struct shell *sh, size_t argc, char *argv[] params.type = WIFI_PS_PARAM_TIMEOUT; if (net_mgmt(NET_REQUEST_WIFI_PS, iface, ¶ms, sizeof(params))) { - shell_fprintf(sh, SHELL_WARNING, - "Setting PS timeout failed. Reason : %s\n", - wifi_ps_get_config_err_code_str(params.fail_reason)); + PR_WARNING("Setting PS timeout failed. Reason : %s\n", + wifi_ps_get_config_err_code_str(params.fail_reason)); return -ENOEXEC; } if (params.timeout_ms) { - shell_fprintf(sh, SHELL_NORMAL, "PS timeout: %d ms\n", params.timeout_ms); + PR("PS timeout: %d ms\n", params.timeout_ms); } else { - shell_fprintf(sh, SHELL_NORMAL, "PS timeout: disabled\n"); + PR("PS timeout: disabled\n"); } return 0; } static int cmd_wifi_twt_setup_quick(const struct shell *sh, size_t argc, - char *argv[]) + char *argv[]) { struct net_if *iface = net_if_get_first_wifi(); struct wifi_twt_params params = { 0 }; @@ -1107,22 +1087,21 @@ static int cmd_wifi_twt_setup_quick(const struct shell *sh, size_t argc, params.setup.twt_interval = (uint64_t)value; if (net_mgmt(NET_REQUEST_WIFI_TWT, iface, ¶ms, sizeof(params))) { - shell_fprintf(sh, SHELL_WARNING, "%s with %s failed, reason : %s\n", - wifi_twt_operation_txt(params.operation), - wifi_twt_negotiation_type_txt(params.negotiation_type), - wifi_twt_get_err_code_str(params.fail_reason)); + PR_WARNING("%s with %s failed, reason : %s\n", + wifi_twt_operation_txt(params.operation), + wifi_twt_negotiation_type_txt(params.negotiation_type), + wifi_twt_get_err_code_str(params.fail_reason)); return -ENOEXEC; } - shell_fprintf(sh, SHELL_NORMAL, "TWT operation %s with dg: %d, flow_id: %d requested\n", - wifi_twt_operation_txt(params.operation), - params.dialog_token, params.flow_id); + PR("TWT operation %s with dg: %d, flow_id: %d requested\n", + wifi_twt_operation_txt(params.operation), + params.dialog_token, params.flow_id); return 0; } - static int cmd_wifi_twt_setup(const struct shell *sh, size_t argc, char *argv[]) { @@ -1193,23 +1172,23 @@ static int cmd_wifi_twt_setup(const struct shell *sh, size_t argc, params.setup.twt_wake_ahead_duration = (uint32_t)value; if (net_mgmt(NET_REQUEST_WIFI_TWT, iface, ¶ms, sizeof(params))) { - shell_fprintf(sh, SHELL_WARNING, "%s with %s failed. reason : %s\n", - wifi_twt_operation_txt(params.operation), - wifi_twt_negotiation_type_txt(params.negotiation_type), - wifi_twt_get_err_code_str(params.fail_reason)); + PR_WARNING("%s with %s failed. reason : %s\n", + wifi_twt_operation_txt(params.operation), + wifi_twt_negotiation_type_txt(params.negotiation_type), + wifi_twt_get_err_code_str(params.fail_reason)); return -ENOEXEC; } - shell_fprintf(sh, SHELL_NORMAL, "TWT operation %s with dg: %d, flow_id: %d requested\n", - wifi_twt_operation_txt(params.operation), - params.dialog_token, params.flow_id); + PR("TWT operation %s with dg: %d, flow_id: %d requested\n", + wifi_twt_operation_txt(params.operation), + params.dialog_token, params.flow_id); return 0; } static int cmd_wifi_twt_teardown(const struct shell *sh, size_t argc, - char *argv[]) + char *argv[]) { struct net_if *iface = net_if_get_first_wifi(); struct wifi_twt_params params = { 0 }; @@ -1243,23 +1222,23 @@ static int cmd_wifi_twt_teardown(const struct shell *sh, size_t argc, params.flow_id = (uint8_t)value; if (net_mgmt(NET_REQUEST_WIFI_TWT, iface, ¶ms, sizeof(params))) { - shell_fprintf(sh, SHELL_WARNING, "%s with %s failed, reason : %s\n", - wifi_twt_operation_txt(params.operation), - wifi_twt_negotiation_type_txt(params.negotiation_type), - wifi_twt_get_err_code_str(params.fail_reason)); + PR_WARNING("%s with %s failed, reason : %s\n", + wifi_twt_operation_txt(params.operation), + wifi_twt_negotiation_type_txt(params.negotiation_type), + wifi_twt_get_err_code_str(params.fail_reason)); return -ENOEXEC; } - shell_fprintf(sh, SHELL_NORMAL, "TWT operation %s with dg: %d, flow_id: %d success\n", - wifi_twt_operation_txt(params.operation), - params.dialog_token, params.flow_id); + PR("TWT operation %s with dg: %d, flow_id: %d success\n", + wifi_twt_operation_txt(params.operation), + params.dialog_token, params.flow_id); return 0; } static int cmd_wifi_twt_teardown_all(const struct shell *sh, size_t argc, - char *argv[]) + char *argv[]) { struct net_if *iface = net_if_get_first_wifi(); struct wifi_twt_params params = { 0 }; @@ -1270,16 +1249,16 @@ static int cmd_wifi_twt_teardown_all(const struct shell *sh, size_t argc, params.teardown.teardown_all = 1; if (net_mgmt(NET_REQUEST_WIFI_TWT, iface, ¶ms, sizeof(params))) { - shell_fprintf(sh, SHELL_WARNING, "%s with %s failed, reason : %s\n", - wifi_twt_operation_txt(params.operation), - wifi_twt_negotiation_type_txt(params.negotiation_type), - wifi_twt_get_err_code_str(params.fail_reason)); + PR_WARNING("%s with %s failed, reason : %s\n", + wifi_twt_operation_txt(params.operation), + wifi_twt_negotiation_type_txt(params.negotiation_type), + wifi_twt_get_err_code_str(params.fail_reason)); return -ENOEXEC; } - shell_fprintf(sh, SHELL_NORMAL, "TWT operation %s all flows success\n", - wifi_twt_operation_txt(params.operation)); + PR("TWT operation %s all flows success\n", + wifi_twt_operation_txt(params.operation)); return 0; } @@ -1300,13 +1279,13 @@ static int cmd_wifi_ap_enable(const struct shell *sh, size_t argc, k_mutex_init(&wifi_ap_sta_list_lock); ret = net_mgmt(NET_REQUEST_WIFI_AP_ENABLE, iface, &cnx_params, - sizeof(struct wifi_connect_req_params)); + sizeof(struct wifi_connect_req_params)); if (ret) { - shell_fprintf(sh, SHELL_WARNING, "AP mode enable failed: %s\n", strerror(-ret)); + PR_WARNING("AP mode enable failed: %s\n", strerror(-ret)); return -ENOEXEC; } - shell_fprintf(sh, SHELL_NORMAL, "AP mode enable requested\n"); + PR("AP mode enable requested\n"); return 0; } @@ -1319,11 +1298,11 @@ static int cmd_wifi_ap_disable(const struct shell *sh, size_t argc, ret = net_mgmt(NET_REQUEST_WIFI_AP_DISABLE, iface, NULL, 0); if (ret) { - shell_fprintf(sh, SHELL_WARNING, "AP mode disable failed: %s\n", strerror(-ret)); + PR_WARNING("AP mode disable failed: %s\n", strerror(-ret)); return -ENOEXEC; } - shell_fprintf(sh, SHELL_NORMAL, "AP mode disable requested\n"); + PR("AP mode disable requested\n"); return 0; } @@ -1335,8 +1314,8 @@ static int cmd_wifi_ap_stations(const struct shell *sh, size_t argc, ARG_UNUSED(argv); ARG_UNUSED(argc); - shell_fprintf(sh, SHELL_NORMAL, "AP stations:\n"); - shell_fprintf(sh, SHELL_NORMAL, "============\n"); + PR("AP stations:\n"); + PR("============\n"); k_mutex_lock(&wifi_ap_sta_list_lock, K_FOREVER); for (int i = 0; i < CONFIG_WIFI_SHELL_MAX_AP_STA; i++) { @@ -1349,21 +1328,21 @@ static int cmd_wifi_ap_stations(const struct shell *sh, size_t argc, sta = &sta_list[i].sta_info; - shell_fprintf(sh, SHELL_NORMAL, "Station %zu:\n", id++); - shell_fprintf(sh, SHELL_NORMAL, "==========\n"); - shell_fprintf(sh, SHELL_NORMAL, "MAC: %s\n", - net_sprint_ll_addr_buf(sta->mac, - WIFI_MAC_ADDR_LEN, - mac_string_buf, - sizeof(mac_string_buf))); - shell_fprintf(sh, SHELL_NORMAL, "Link mode: %s\n", - wifi_link_mode_txt(sta->link_mode)); - shell_fprintf(sh, SHELL_NORMAL, "TWT: %s\n", - sta->twt_capable ? "Supported" : "Not supported"); + PR("Station %zu:\n", id++); + PR("==========\n"); + PR("MAC: %s\n", + net_sprint_ll_addr_buf(sta->mac, + WIFI_MAC_ADDR_LEN, + mac_string_buf, + sizeof(mac_string_buf))); + PR("Link mode: %s\n", + wifi_link_mode_txt(sta->link_mode)); + PR("TWT: %s\n", + sta->twt_capable ? "Supported" : "Not supported"); } if (id == 1) { - shell_fprintf(sh, SHELL_NORMAL, "No stations connected\n"); + PR("No stations connected\n"); } k_mutex_unlock(&wifi_ap_sta_list_lock); @@ -1378,18 +1357,18 @@ static int cmd_wifi_ap_sta_disconnect(const struct shell *sh, size_t argc, int ret; if (net_bytes_from_str(mac, sizeof(mac), argv[1]) < 0) { - shell_fprintf(sh, SHELL_WARNING, "Invalid MAC address\n"); + PR_WARNING("Invalid MAC address\n"); return -ENOEXEC; } ret = net_mgmt(NET_REQUEST_WIFI_AP_STA_DISCONNECT, iface, mac, sizeof(mac)); if (ret) { - shell_fprintf(sh, SHELL_WARNING, "AP station disconnect failed: %s\n", - strerror(-ret)); + PR_WARNING("AP station disconnect failed: %s\n", + strerror(-ret)); return -ENOEXEC; } - shell_fprintf(sh, SHELL_NORMAL, "AP station disconnect requested\n"); + PR("AP station disconnect requested\n"); return 0; } @@ -1406,8 +1385,7 @@ static int cmd_wifi_reg_domain(const struct shell *sh, size_t argc, } else if (argc >= 2 && argc <= 3) { regd.oper = WIFI_MGMT_SET; if (strlen(argv[1]) != 2) { - shell_fprintf(sh, SHELL_WARNING, - "Invalid reg domain: Length should be two letters/digits\n"); + PR_WARNING("Invalid reg domain: Length should be two letters/digits\n"); return -ENOEXEC; } @@ -1415,8 +1393,7 @@ static int cmd_wifi_reg_domain(const struct shell *sh, size_t argc, if (((argv[1][0] < 'A' || argv[1][0] > 'Z') || (argv[1][1] < 'A' || argv[1][1] > 'Z')) && (argv[1][0] != '0' || argv[1][1] != '0')) { - shell_fprintf(sh, SHELL_WARNING, "Invalid reg domain %c%c\n", argv[1][0], - argv[1][1]); + PR_WARNING("Invalid reg domain %c%c\n", argv[1][0], argv[1][1]); return -ENOEXEC; } regd.country_code[0] = argv[1][0]; @@ -1426,7 +1403,7 @@ static int cmd_wifi_reg_domain(const struct shell *sh, size_t argc, if (strncmp(argv[2], "-f", 2) == 0) { regd.force = true; } else { - shell_fprintf(sh, SHELL_WARNING, "Invalid option %s\n", argv[2]); + PR_WARNING("Invalid option %s\n", argv[2]); return -ENOEXEC; } } @@ -1438,30 +1415,28 @@ static int cmd_wifi_reg_domain(const struct shell *sh, size_t argc, ret = net_mgmt(NET_REQUEST_WIFI_REG_DOMAIN, iface, ®d, sizeof(regd)); if (ret) { - shell_fprintf(sh, SHELL_WARNING, "Cannot %s Regulatory domain: %d\n", - regd.oper == WIFI_MGMT_GET ? "get" : "set", ret); + PR_WARNING("Cannot %s Regulatory domain: %d\n", + regd.oper == WIFI_MGMT_GET ? "get" : "set", ret); return -ENOEXEC; } if (regd.oper == WIFI_MGMT_GET) { - shell_fprintf(sh, SHELL_NORMAL, "Wi-Fi Regulatory domain is: %c%c\n", - regd.country_code[0], regd.country_code[1]); - shell_fprintf(sh, SHELL_NORMAL, - "\t

F~PE?A(N?gJn zjD=rpGHB--L{s&-DSp}G7Pu54-*b^a>v`IHpNP15l(G?nZw<3i{U0~6kzx_MR(P{0 zCUY9M8XL*4KG;c%pEV!<%RzAjWI-kMgxD~|enX>KrRPH+S};oTE;5DfyvNqr2(m~^ zP!QCE2&LCT@CvpTy{B41H9$k9a)3#a-#_w&f5ZF#Z-@Gzl6SLi~Arv}@i{i<9jik9;EVEPJBq6;0X_hqzk-%``cj{>f%^Pc1jdz}ni( zYlxxiBaE=v$R!Q00a?=+J~zPFuWvxv zQD@ZCPbJ+Q6S)Ao#316^WN=WrE`UKjbB94^dV=5cr&swl@;bixvxJ5N>XUO=`p^Zw z4yo-sJ>rlgYKQ?*lG_-}e^6p#xefdPwDh4P(o+U*eut`}*1UONH&EOI=!bU2k5D`27 zXucrmpYCL0{n^lc_ND;yg6a1p=5q2-r|V9`q&8F$6omxegXSKqRMe<+z@s_4-*tp? zRSQ9^H?65wbtq7B`U77Lk@B5aRIzC zga-(Hr$(*e0ZOaraHv%q2_9OHC}>*exLx~zHiF;tx;p^40mg)#q!Kx4WjO8Nhu635 zqFvG>aQ~+^wFGfr(T1p!m3A;>+GH|7Gr1g}Su619SyfM>&+wDh|# z4NQu79k)9Idm16cVW*i@zIz8Un_5O}x9Y^7!N}=cJYH^fW%PWcrCW^iX}bQbmH<`2zDH{awR2I=gNI;cx?`H0W&66=Qi_ z`*GJWpZ?9G4}KknVRw|1Quly`_>Ejda>HO5w(1!rW-Z`PD!0C9 zRsbO9&+0`^q{5`&hV8$JUTkUq0yM4Vg)wPfjFi!*RW{caJI)(i15tIteMVv29ehi* zQ9&l#oA~MSiPX>G;NiSJ4Xavo>A%(DTptb@d(-$Mln&>a<`@_dy;u-Q6_<8FLfvt& z293GHBzpLXb63Xcf!$aY72>@- zk$<4cO9*kp0BOP22acf5)U(=y)xqEKW7lFwUw0EICq8vm=-$aZa1p9(SmM-k7oT&9 zxECe*A3igv2@9B`E*XWLq+wFj!O8!)#wJC@%?Yt##TA|0shFkXnrCxBSJwV=i!;G8xS(}5keN{B5DU%T3#zt&>EeEsmONq`z-3!{b&9Lo^dJmgS_Z4xxPT^L*qs& zs-`Q8ZzgtwK2}Z}gbs|+w7x)EU z!UV7^rr=7mNBd?wK=6aIdfsM8GU~vO8Rm;8|G~klEV2le?gG!7HQ!wGy@!0t4|@N_ z9yMGCQfu!&hyjyV8Jcb)Ua+S&2(Ovt6~@AfQs2WJgD^<(Wri?bO=0wUla-T`g*#93 z1O5p0v8HQxnJDwwI!Qa18?N!3>$e2#kOfA9F1F`vJM|z5HSyuyyd}fFN8iU4I zDeJybRw;y<61$~tutqYsVN*Zt@n9-HD9FwmwtFt%gIxx6_ot=&Ce+!$+dgTXIfxc`I0ZZOF6#;6EC>Mn)8GH4^>FH6{Ybz_`tLTkVE{m)^oCyi?>0*d008F& z05E|6-NuCh0BCOfZMAl{^tAjhc{f*rKSW;7MTGxVC!lBq0EknsuMZ7xT!sPwSCiM* z7me4~S498-;S2!K_UC#QpbQ`-Apw#QlLCQ2GBQ$fN)Qz#1qCG&9X$<*b1-uV|6iBu zHUKRtA?(&WLIO^}Em{IXT7v6u0OlKyhzb6Ap#OIvAS5CtxdkM>p_<~oHF)lmvV0@|{*7Y78}0v1{XYtbNq{#*QCh&Q zTQ|ns0uU44A|d?8K7w1cgg2Ur=oNK1g^58TmL6cGV3GusXI}e{-waFp*E0Z0LV_Fb z2x$TGfRl5c{2-qEXh426&#h>lT=M@VNy%-4p1bG_@rRu3x z#9Ogl`4A@2V{yFdTg^1-#bJ6}+2IT&eJwRItX^3j@=E45=|!x5Q4^QwkY9s&Wn=1` zS%Z^s;!HyYwqkMYeE-JEnTR3VP!B7-dmNSP=M>R2{YLlMnO2Tg9UH&o<$hjzd4?LbF^6% zQ9Wv7^UP)H8Zc1&XH@-2jB_^{bFWd8HLd^U-#qz-;BwK;YruBu-W5{bMf8g@N}#07 zt)o@;8sKX3<(TKHet4Ym7Od4|=o;{i`yT=Pj7NG9v&vnuWlkq@w^N6w;JvEMrgj_K zY3Bxcbd9`*BBYrY_p_3)a^m(n+n3_%p9)`$_W$~XUIR+hc1nv>^1Gs|&wYmd%`C0~ zTeKJUclx!iN-3@Z+Htc;s~?ss3g@n4Z_YF2uax9n9*r^%U8u4hZCqiC_~}bZ9GYjx z;7?8q(KtW(hD`c=o**tk#G+;U(0a*(UXU(d@>h$LmKlZZCJWs+2*u64glhmsYbTdW zM<=|Cc2ijXsPqaO$U*V9q5B_{&rfGxviwS9M3-%Z`_GTPAM)D|uK{p*7oHCgohKJ_ zZs%X04S@p2-W=_`kr>hc?`I)$qss`4XN>$neNW-1nhu*wuof@)TV@|1ttT>xg5jK8pJ5p39t%+y8JQIc}X?#^4$-!hO~ev>UztP3`yS$%t=d zT))-=5A{YBVP#U#GU6=y8SUM{BmBC8w~E&?JF~0SPt~Jq0BPV6P|r|$^pfLbWLN8V zTO!a*L)LU73MqxHZak22HZ*5{T2(&{}E%$-7%xT3;&t^}Z8YB)7ZZLU`-QP0`{d z)^bfl&wl8N4lw>|mix()99k!=_a>&EGU+4(>&T;(KFNrWEK4p3K42-cOK5U_>`@rU zI_@uSkQ!DR6Fz5wu~a$c!EAgj{=f`nV;zsyYsb=1(ouWi4xeej`dBTUTjKFf2xMYj zd|@`J*dfCpolDx=KSw2{v|O+b#BOqV|5>e>nSh2tI{GPBv$&LrzWAuytVxYvVUm%rB1t*14!+w@X`E=yQi?4fNLxD5E6(Ht zx;kwVeY<#Jkg_j7i;Z>;p0`@KU@wr@L;b!j&P(WBu>s~Cu_#yy~$ zcqAR2XiDqnc6jP<_SbVKC7S9Hb?QDVHG=WCSa_LO5JQy);T{vo563D5AB#_03}D4I z=@d3Q)MVBw7PlBW9J+?_!MxH9r&JYoJIsVXe^u;Wj)X5)?01&g@Z)5Cxa*x9!8K|5 zL%PA-{wB6}2Q{THn{^G@9OEI~9;uZlMBxBo?dhI%_7H!z&n>x<-TtU0$syyf2fnTM zP73Y07Odb0#S7$sHuac-u>(y%SlduXx!$GAS5jGdDB1P}bo=3536K`uLdIyqjLSDh zaZm~LTZ1AwQx7i?J^sKY`j!}9>U)XP&W0%uS9yMAM`qQ%&Rs2{c#+>sTPnu;otsch zYv1o9{;%IGN+kyYgv>t6758zQyE0~?+kJ%OM%lXA0RSoM!?C48Fz+m#<1XqwdEB0` z@oOm*R$LgQEwXm#OgQ#1Fgb18sLnJahVeZ9$Y2EmcNX80umP2V^N6{xt{mw*6E+`j zdd&It8c3MUvko8Wp~acVUdjvSokO#JceKQCK#x##8j{5o!u9-}Q#x#xk@xMocwg~^ zND$%U-j;(l-qp^fJZa49(q>7W<{Nk(r9;gZCn!xrn4RnfVomM&0d-Y+*aVHG@Q9Yi_4-6ItvhiiE~J%hKgj{u!1; zE6}EQ)8Y6?J@XzzwRf`6 zi~W}+EyW3^>@q8K)YJ$a2&0-jTeuqQnjU$EV*5%&H)rDJEtTwzBQlkG+%U3Hv?9+z zyGL6tA~z*z(|Q{%b;*%<9A=mU3FWk&`FlVZZ;{u#v^;xJ5DY9<`0xE z^(c$8zkWdu64ROycK4N?`=+Ao>jX?v3zozihV>KEOc3lg`|+=zWj9ZQ?5tzC?aBMn zcZCD&#EesJ`K@ItwR8i{^*`yTI8RPjvEsQNRb7$u>Ln_rxVi^b#3TeyR!JMw{d^N~ z&jclwED_ux!O1udp|pXVa4%E&p;#2S{Y}~N1iS#WUvUaFlO?uCQ`HkgQxUK~8pM|! z2(kGNPD9Fap7@W7?4au^Ri~ALkPRYf=Ix04=mlSV@tbf-c?R=Wfb{Ta=9`N6C;x#lhH!+ca43CD(9`Lh^C;6gVzZXWU?-I z-`v^a(s!MKqVvG{?rhdi=A$aIyWQ)RpLC9%$BH0-5Q#oJw>3c#zIBQHG~_9{_=;EN zBPNSa{8-b88>&8FLpw#EEsMC|lfif)K23ZylhOV39PNYS@3jXX zX%e*IM;jd{%V+3gRl*s3La-kfxhYbW;Pw_EKxRll<|SX`BhBT%+)o~qr8{|ltg=32 zbui>ZBM>jJVL@2-6oxa!L8%v8#5S1`>ah{aa?A4yzC@kR(zy?Uy0vC_SFZu~2h8z} zruCJDxH_LA2Teu04)!y5EfpGMocEtNcU*_b!%o3M0g2!}emJBdAIkt`2Y7@9nzxMM zjqdzONw&I7PDf7@bcx4)qbnMtRwE~rg%5!zD)Nw{rGcy$EX#cerLn=^dfB8;S&I{* zBg@@(e!2xu-1&T;ie$zx!epOObDep{-&JRC5Kt!Aa&mb*P6}0>Dd7G%bwnUPz1)Jb zoJ%AO3W}rWf-#+0XUj1>DK*GvOy;oQQu}JOFS9uWKu<9-$vTNLOUnM8@!;+00vfmY z`*PN0rR|7c22EMdE5Z#|6S}|UWXqk8%sBg3={l=NzGze>KvF>}_?WhG1y$i%bA05p zvEiOUpMeuYI@bV_qJ~dnyr-JtMf zRZaatKWT>#=nUTmi20*(kFIzO3{PCtf#}s?M|;K4AlrGZZr#_4A$Ru-S^itfoz(4h zSkl==xB1jEv7VUQgG-qk?B268Q)?#L^5y(qOYM=dDW@{J5WMiPwA**tx z*JMT+>n_3lj@sdp@c2NR_3Dp8{T6eYfT4jT6?{Dm4NYOb?y+I^se!-3DX z?v-GQ-`p>$AnDB4{*y|d?Ng_e7~GtEe$jnlGNnwc?3AZYS!a^0^a-jJ3LH~g7+qG0 zmVb>#>M|RwV)uh4wGl`h+GLRK@dXI)l&5<{ zV7FRbx0Xw$j|n0-ia{d4U<&e$g1Fvw;Dc83d9ge91B7Sqs+SIqo^j(YsC3QOYKzxZ zalVp|CleSBzc{M;KSYNGk$#uQ%&Et7B|A@X!;wCLro`Df5+&K6IG)#Opw#DYiuvN4%02a?xNvrzjE!z$}cQnPHbS4eSt+h3k?t_zEg#nLV> zh1K@&vt5?6RC>Q)v2poMf|;F(S)OP#brGNgWl}=;j>q?VRS|V{260+HBp%OWD-5zs z9FtfI>rNtSa@_?%H0}x)?JVU_q`b_jtQ+Q>M+!_U(@OGaPBkKZ_@Ts|@pRb0;HTis z?6Bw9+p;w>2Fa%UJxF0i@7#RfzuW`<D+33zCY*yE2SzQCj3L+}(G<{n)jgf=wQB3gooDc#NS02s#IMl`ye<=Cqe+cYFI=PuT)Oj`XI~v1CNF<>^0=l@NMNGmfs|Q?Qcv#-eCQglT+4)8kf1cBA!p2_IZTye*=F`t z)_P93fJ3c%##m^LgJP#Ul>ix0P(h5HJvS5V3PRHmrZX)1Ji)=lmZNLVxr8o$ncS10 zy-Q7Ib-NPtgHdFsCe_4{htI>WZ%mSmg@8$Bf+w~I z<<$|)78oEGIbI7f{-FBp69>O|8lD3|-LQO{7RUA2RVf6e$RbJ7TL;v) zWQxJ|`0Uo8%GBbq0eGuQ_+764n5KjiOmWEQZH~w6JjER9(!Ee%aF;L9xZ^zXml=HJ zg&5S{p>SvJ92JfxH~5*L<|@+h_VlPiNQ=*73R}Q3@QMQa$$HJK*%J@bUAl9RJ)CfG zG+xd5d>=JCe#d9PYIVzTCT1@t`Lwi`TXF^M)%48dW(B0#GiIM+pF-fCL*{SHMI11q zN2es7E$*px`J&AB%MXoGMO)Jq?%>dz-o1=jNEtN>y~^2G*gxG|(5Yu%Rktjl_(OL3 zQPVQVI*df~Ss4I}=DoXsw!4JFVF+|Vt6uew<=@>UZ>o-;k zME^-<1cn*;AgI%Om__~>NK|e={T#FnDf5*fqo!J z4Vk)bN!=FCjwt;(Ch=CQN_kSP{~gsXI~P02cE9Nefio%K64HQ97*05rNxt~J8fzIL z_Cmgp=*`RD*=)@|zvgRp&i|UO7dc2eyi3dHto(sk1{0W!hWJV{Pbz*3ZS?n=Bsw%t z;b3Gd%sLlz*ee8CF~QT8d=b{bPBL)s7Z|slv!3j^?QMgd)=%=oWRA#e^;vz91*M_z zMmZ~(=8sXP@19jv*8uEf{l$Ao3t1l{L!5HP22K^IE$vettKse%keWLd5MaHr_RROI zB@fqeXbVsAC}ICh$(1VA3w&zHtg5Hp#@;t}>qd;H{(hAoNPnYr#l>lv`m7HP@;TrmNIzPaomvHoeIV#21VzGq!3&EB{|0_a%0k}s1lZz!5;#r*8 z z^v-2vLAlz_#pu=9;Xyw51Lpa&sB+T$Sx*-$;hGv@-Nck)JocE4w^}7H5=DTFuK*zR zyBr(Lnx-^w=}AD&^pZkIuRt-YY~|F@gV=|uoNbNGhy0&cBBoH8o(P1CW7n(7;CO;v zt`=a#WG;@-33TfdVC~ZtU&8z2Gi0$*z)EeCc&A6;U5SRTSq!EH`EzV?> zvMLgKM8V}6lfn9_GpL6jx>F+*Dt6R_mYpKyso+SS~Df!5JS7|*E7zv zPOnp=T&Z=_Van!_#DuoKD4-biYhyGifG$^9?mYP-tduAr_GiiX=cGF2u^BY~=YTxg z!&bx`%C!AF2)%}pVt5`Xl6xvWZX1E|_(UT^@VDNJZ+_&Ey3A1f!FdX~r`*Efwa)3qdGCd{VKF{SM`_A!Y~=W)R8b)DGv#xy)*FQq`}Xb%;O zHE=r@rf>>tQme7?CdY;oD2M1by2`_@0qEoW;hE>+xfu<+51SUHLf)5=gZ)PnD{j6S z-eszMEN>^Ix3b1%@+_ugi`R0jWh;J5;gBag7k`(<>FIie!~sWpue0A&H|WxLaNzwM zJW6*+sva*vI8z<+opl-%u3T2_?({26phHmE( zRQ{Z^s=8*eRs6R|na3q5AfDTPP$*31q_W@?eJ82@&H>N4L&?@FrnRH`osm~OF0lAq z@*n*9nY8gOp~v#EBOf#~#(0T}+FxiB6(*~qA{5)(S^Nzm+s4H=KIs7ji08CZ844f?uyv=N#NAp{q^hWhU)^<>avMYDoco8=#s6iFlY zg0i+LHC;O0-E#pl$vKsqrb3viNwTD+MzWNi#tQKZSDARFWHK_uWxj%#`&WPTNimy; zct3@Zz?0Q(LXI>+5Hcm9r!QD$zxxSlHe*6yK_E`yi3iuTq6msvLAeh}lT3LQkE+e| zN2k0#D&4Ipi~NOBZTNC)&*r%@e449gPyGE5MnxkfI3D$?IMlHDY8}$o`1!C(Y7ak) z>PI?AD=NjuheJ)nN^H#zWO++xRj#%_sq~bcq?({#cA!A1CW=!bNuQXAfidgsW39HF zy1n)J)+bOcaJONrrY)5lQLYPI5!{c~GFPD=hkar|r2O8g=o>k-jq3ODw-p~i%_ZPc zKp}}kFBWqoQ1EVL9ouOELH2-OUCN{a5hEkX6k%R#?5y+&L0Y;w$YqFHx`R~cd}w^G zy1m@8K|J<=^zL@(sH})FRbb$`F>9)Cx6q86%Np=dT{%kI%YkU;sE2!} zt+M{+b@GBGw+U#Cq6a(WL3?#e%!dVm%!gyYr6vuvGM+A^tn|5~=JLmMINF*UzJY2| zug2?fcT@JL(x|<{y*GorV&dTd{fLByjwacqC(&OQL?`g4aTw(9VIvPadvZcZA+?jV zz)#+B4x#6rdUo#|URtuR@@}ZYe!bpms-x(`UVVG|)4P=Qd?>0YNBwbehq^=vK1GU`J9>QLW;T3in(>lz_nn<+Yzi$H$38t2%RpUnck7!s zl*=5P{=zaFFemKkfZf~?ecK!RV3wuSiHDTJ0in~E9PfdDp`)t%8!S3sM}o1_>eV>F zOQxeE44E|gsHJYdt|cQU(>|ro_LR~KR6f;ngBU-<-Th4QtObEk@N&y>O!ZU^bYRh# z$elS-^(Rib_n9T(lRk!DuIrGea*_N`#WkR?jS0>Y=s#ZaV|c6vt5U-&K9XN^6tlve zY3a+($9~x1UNG@q*}t_P^By6gOr&i0lbl(T4*nFC5}Hjt0{_LQFkdJ&YkQ><;9#$) z9vqH=quLaBiIv%TcG+LDzAvmp=*wS(B?%fv30XX8naQd*F-{=|B)=83k*VP0Y3oQ< zQ@O3mC!@*G=~z^aD*IXTIl-)LmPn28_0jU3YrvD(bm&T^!ILX%vw3M3>F1L2mI!>M z`&PdT|KKN-CNx0rgLkvbvZsYfz9g?wm%9B%^3hzrFZ?uP!c)hfC%Un=q-mq4A$4Nq zLuMyYhmQ`Gnj4g#$Q9AMfgAz$tbIgPR&j3Mn`YSO=;f~|n*ZHLr(Qar$*Q2K^-S3? z&Ys173;DAF?w&`04ezI>ORR8V&V+b(6B3F_6uM1-hMMR3-#NmRbyD|mx?i&w0q(qz7=iqZR5}O%UD+?^>@DuAjJbk-G*ex+Dz8~$CAozmtLnN zjxh``3@J?gV}JX*1H19exKtNIv}hP06`8HQB8n~pH+TdAtN0cQHn+v1r@r}$lVrQx zg(L5|sQ=aB?b4cEXo-~5>|_Iee*zMF)NRu1Wx1dfH?cQ~AE{5vVv{1O6dqH@NBjH^ zO9{scE-Yu$qH*N1et5k3#QWi~H*24PW$6}g4obCPo+BwX-Xp!2It2MTmzm|!mDhkB z;ju4&;)usm^&B)5t}6ROa^No1d6PlNWQNQTATzB|(_oi}#amMC?%z$-d6kp%@@0?c z7t6*lPeO#i3(L7X?O>*L*)36~45_78`j`)*o(HLm>Jj%SoOoEB`BqUGzxk#Q%LnSf zQ20~hJ~BvPeT{bwOGuErzD?u9l|NH?-Ltx_7-M#m`m*V87AiGQc8@OOy972o?!YID zFUrn5Ts61eNeeB0KE3CEpO;EpQ#f7`#uBUFS6IPSn@z@#D;jTCihd(2mDI(j{7Bic zQ_DEXA`#UBipMge)8$-gIx-USy`R7}`(JmR8{40C7^GCQ=0PC|2i3V>$E-&xcl|~? z`CdfJOxk;W^`Q8jxI2E!a%;m+SEOeF*HB1oi-af)alRrGrqCq zPC`ALT#||HV|0lp;<3#)%S3#?oGm`bbmi*uq`b&nVs^{y^ZXoC*G68*779}$gKq{W zb!+~uUptzAY|UGyrupQ}{W_A}vFG)7VyPbdaQ)z=w<1XuUoS{#gIh!}Q;kxyK8`l{t{q`JA1ixd-``*$j9|kYmW;(4Zqemp~Xe38IC;p zEu$6xAqA#l;)`47uwmi3D(dqx%~mD9u47kAAcvpZ1pUvc2SI1^9oe}tdWg4V=sN0~ zaoF)`6|NMAir1Qd(nD0U2n1TPWqc%h+{XoY9_KIF^?D}g2N&V0Sptge^+BNhNhrFW zk`1Xb|4{*98lvRx&pf^x{Yl_w1;1N(SZwGq zRFWi_b|dX+-?*XVug4zbZu5rjiT!O$boU_-3w}K20?SH@z5O6|k=13^ha4$hDXCN; zwBG>WSBN?H=u$7I`BQ}POUP$o`4X<@U(wy!a-xa%s5AmPeC2w(CX(3+l^zOKhwYs^~F8O1+~uB*pOx7aD^IOAk#*KfsjlCyXJ7_Z6UbP? z@WmJr+u?z&ey#@HM(+H(4JF@c$gm}BRi0j(I&-ZKZv}V_zYGl6wJrg>{osm_U2U6U zLdn@lKz2RtJtvfTMMj`cD&02ajEQ6 zPa0+gV)RppsoGXp6^|KGP2Bv9Y%g`{{yg=let+8e^4PEuTiDQ78!x+3yk~f^y&m|e zL7KjU}4mFKqgSw16!?mTg(vrH(Gsi(T zrz({K$Y}~sE$l3x=H~*I=Zh3h?n?twEtJ%_({ug#HOTXds^*9egW1^ll~;LBhZLNs z-5!cny!bxP`xz@Qk&%qnZ(-T)uW~AN5EqgeF z^Z#Y^Ob4xF^5&0QgpPJ%-A5Hi^|yZl{isCG6K*l-x;E!yppMGXsB?>$#lRFcq*G+U zd?6Pl^p|BuJ!edjfnw?O2=r(o9&*<<5%McL{xHfcXe12w-Qdr`;<^2dYVUPUQOWG zrYpUE32DNYwwjM6rX5ORx*wax;)G?&bPSn;2!KqG%;hHYJFo7QCb;-CgoX8``C)6u zy!W7ViOZQ#lzVdU7^~k-sEK;PA4X@F#(PUH-c!zSt+e*OliaW%I)u)gnp+%0dfJ<} z-gRaLyuvyU;4YLL4T(zR`te&?TY9P}RVizhZRBp*M=7wRK<6WC9#3fssyr|+I&62v zy9dI3I@`Wuh-S=i5oSIUxx<&#h@foV7MfD0{lQdZ9dbJik`$b%g?ep9jC@CyKBH;H zmP39|*ULfC^Tfq)86+r}G~|!52Z@HU=CL#TFIVLChw;13u8Rn{G;s;v##MAAO%rQPs_~#C^~ZyL=h%Cl9{bOqa(Bq>;Q2jGk;YJ+8S+b+ z*!dvYGJ{%dzG^;lMH8#?thp|Ju9xr|6ma%d*_ZwND$|<5%mp{&q9HY=@-sf|mF&tz z-RC@ryQ*};f!O@ulI^EK;RTJQ6vp9&o?kU#M7fsiRNc(}9tJw8pBPKVjN*O_s)l^~ zAoEdpnjwG22CC*r{#M%=JeWzR2F7<9-Ou3PPwm{_V=g4-{X<3+O1 z_KehB{`NYzv^8NnSJfk_gl^qg0^}0huLDv0ZH`ni?A#Mc-)G9mef5FTpaGK~51Jwv zB$%Q0kFj7jpzjp_^VYsM0Q`(i*!e_7fF+uDHfkC5o+y&xw5ua2_H7TM%PSFfTp@Wr zUOr~rEOx-R^zaECsAEcX?So70GAz7OjU1B0yuy6TDIZTIoxSW+jO?hNDoIB`^6`b2xdduw(&0}UXoZZ|vcoI+x8i2}YjB)a zxM5kx0e+Mf(J97cBKP672^{(6E`5tF(Qhhi*@Dt0V~x&qIPI)oH7&U$wXFpp;N^Ee zujWG?Dd1a=SMe1oT+4}pBtT~GiOxKnDQC{2A zgUK8jR7};Q=P#h#y&Fzrw6myM0rECN073zB!r~+%rI=iZ-EI0nMnM!w5FJ){312I@ zQ~i*bn%JRhunn2Cq-x;tlVw|3*gUO%0NajpICV*Uund_0SxOjP=hZr! z@1t%#_+supxH)36e78nGO%?gf@>tZS+=HkjTfYq$XZ*unOz>}$y~?wweng-~xji}m zm0qcGt>mU|@fN?dZOcGVCFkf+=TqcQD-kHNjsPz&rP^9`f z5E&*cgq|l64AhYMgZt8h##IgRMO3T_DJk3dGXvnqOzU5aw>yVz*9QHbM-l~`qTTL1 z@`>uP)m_kiB>I;kYJMJqcgq93+}78;DBwtYpf=Zc`6LWE_xW~(Ex1TObjVVJzmwm| z7`{Gpy3f?Ba1I-& zi7I@r)5uwsv~9igW-5|QMC#)#7SZ^LN|9A|!(?yLgnAAF^{IFT%|k5VWDGuIPjpyp zSjKQz+5RT=Q#vEdq48bCI=D;`9g*M4+D}%nEyV116 zR8RZD_JpoBChW>41Sl&^tm>R${hd^G+Ib@7oz%8tCIYNHR$2 z<9+mW)uR2T@KCUvZUu55BEk{@j+FP4vxRw*GO<(I9O^qaz4rMj_rziMt_N6zRe2zO z=7R&|)Sk!!jo@a^KDxLUr;}zd`qHf%@lsiXG7PwAXx7iukCr*N=121dZT*MbdtRohej1SU6otk;r|+aHATt>+}Al?*dU*BSD`5H7Il|Y3$x1 zi$~sUq+1034wPJX)CB!Xk4q71uIfvepr7j-MJ#}lU)C~FheWpe1rH#s@#wWN}{JktNL-w5S3&jXV#lDZG zXK{`=jo3#Dwi_eKN0B#gG6*{q`T|nk4q*-lg`%O`ET!D09gXRT0~uiqI2@L|H;w*l z*@*wnW0ccts06*oF-cBWh4N$ANn^8rXuJv=cz2T=8=R<56!dW}G&@JCZy=IwhNK`C z8u89Eb=turBO29Vq5z?*c~vHP#h}7DW|2_Ki$bi6JwI1YaQ?*PLfkXR?PSf$`L#?F zzm+faT~_$pPO;ulU0uK7?L;~zR1~aDn<#`7<IQrC^ z0&Z|n)A|i#Q64&4vhuvSrZ8(d`BzDlk+!KMsZbGzugd|F90cRX$%h2`7asOh64LK9 z%u=`)n-o@Uah1TyQL_)Zzo`z_hsKk?1OS1O-}Q@(9-mHfFsgJ;(U}+}-ZNlxfpG}@ zRxnn(|M@bA_m6o+kqWnqf;ezrS zz_qt=crZq5^t|eEPs7H3(mk#2OMPp^1$At=8>(7Wsjk3n}0DvI#Xzi zz$I!{2%^|QC=v=TVb!}7pNKb1aMo{DK{4w(kt1u=N_x(2`^Sa*ljKYe?})<_WE?!q zTw#`Lvq5PeAkfE9q6*rM=G$rv>w%?YFxWPluUz2nsy=7Jhd5yF;6%)mNXbWz{TrUj za*Qj+CP;Cwj-;eZf!ydeo`^2ueM=Ss{dxrOaJl~W{RYhI6SDf-4XGU`l}}N6S>*`C z+281+KyJ`8m#7r?nZ0oEiRfzu!?22CSp`5Mplw4KUL{bBiPVZ~KK-k{G;q+bw6ZUr z{#+?O{pG4J`)*G|XUSd5DLf~piH;cU_r z3-21d=IiMGGe-sQNT#b!X3-;W5DuBmoz#jjknEOOCuGpK`I7(OWAMvN%mW##MKYxN z2Li;(i4LzMstJ&o@`KD%5 zIp3SwH4zd=@YH}{(6^ifQbaT_OLn?jI`N7V$Cb+1fuh4!e*2WI*Rq}{=)WF4`gPKP zw2Gq>9+kpX*r0sd6mB$^kD)U;$Sk34Uzgn0d-vxZ*SmN8`6^jD6t|>uOg!o6vI=bq zi<3rSEL%eY4iIcY5$nMGS^7>VmeYibvg_S$k9#GCK}x2dC^x&4-L9s{;=6{^Lypn5MCUkb~o(ucRVaax6#!1+9CMdWr;`NUZVbYRM@rtaRYO^TW)sYbsUL7RK z*nwiV1zaY0*e(~wY)Jm*E0b{w8pdZRpWVz^n7ZatKDENnB2k!~<)Eh|f-4NHm%868 z9TEh-Usnv0H&eA*g-$y^xKGWnPT7sd@KhSjRqHdyT;jSlQJDpcJX76KaZAN}n0?yG zPF4A2-oQ>xF({SPz{VDTcpm*r%uaDrZ#&y<$x}V0jk(P5^((6{F5m~_@#9pd-wFGp z{(3)(o?iEVeV+R5#ClOYhuvT~9JWNX;?)s}d8#({5fAN1O}`1?hvWXz53T$aiI&uG z4^i(`EjI3=2$pAFPW$GTYbF%lKP)@~H zw~Iz#?11`svb|oJNf|u!L5A2ncshyBJ5R>0OumL*tyrS+13FKi(BF~>t&&o@d5uzP zx%HUTR3%fY+;RsQV(TTNKUwy5<*$xG-F$qG3PkS*+4_!o3`iDbg(aD%l|QM6is`s% zR$v_FB764@J^o{f8`cr^~D zy)tZVQ?`!|Q-doa8IpJJH%V@9N8iRJ4%gD@QkQZM+&704eio#b6Jzk1WM~NqNhwdc z?Zhiu*E@Z%CeP{III@yXol=o^pH7Rg$QMAMpGE{*3ECZp-uIzCEp>=E9|jnVg@!+* z#9v(lq*hNj72P_MI0`xBlQFlndZ@8*BYlr3ybmH#uf^A8v6yM_RY6WewOtUz{I(+N zy-QB`U&uQuNiExrrWl!AugP70Q${rINa{+_dPRbNGBNjC|+w%fHFkQ6g|!p z+`Yb*@s>+)4LC_#>VVXvc*GM{F3Hrh4lb!URKblrpz#Dbkj4C6PRtt)?o@yBCpl!+ za%5|efE|#74g^+`ClPcb#7Wn=Ap!Wg(OuZ+2t~!$I4WYO!gD#FLIQO0O>jXAT5LrZW@GeL)nBXdR^ z>A$p=yrP2RutOs*QiUNpw|IJG0k&e_C*`BX+WTSQ5Yd@SBVMFwchr>5R0XTB6#e0* znKZksC}3aRQrRjVF1dp}9t;?d&CpNpciuSMQJJRU@fFebG=j6xNgqhcMdT^@y?+TW z_fC}g%4sXULne^!(r4*>ikPcxZ;zoq7FvmHUp6NxG%0VYceheNs*?w%&6rrS-ysFx zS6Iwe(>W+JiGk_}xHU>DdZx;#;L;>cgWEHAS(JjyR}tgTOKU;Q#}#9`e)0L(C1rAA zX?L%mVkL$jp^fRZ+)b|{28{SQ2zcXayBZ2ku#IhfnySKl&&TAt93}* zkJITEeHRNYn)pbrNhj>t(Y;j_e)oro?XuWHxsnotk9sLfcGSq>VV_?q;f!33x(e28 z)`2xv*#UOuVc-%Vn0oZQi1Q4f(3Aosy3b+O^U=pyG=2*mu4)?2 zPe#rTv18u{i878orkm( zDA{@GUxSjAdBIx0v>x{5>~5co^GoZ*%TMNT2kbo4pO;jB#3%%XflAE{07fE>i5Stc{mev=SBK=?{@ zW|LyP3{qwF9n;=q94x8Uq>!-KhBXA`W5Y2>CN(9}o(m`0lB*w&ID~BLAyrRGiQ#ad zW1kQX0FWeKeBC@-9Cw^L3;J+cmvp4fd){7ruT_;sR#=&9`Z==?UQIn*opeF3vX2?y zPp##cJs9FQHN0{^ZuzIWVq2=}nwd$dYA5AyL1geAHu}hROo_i}(3_+u)k>q3`Q{(h zrgIg?qcv<=VQ7T_XVL7uVH7Hys1n19kz5Q#N4DA(s6{eLy>IOI*Cq8EOJlPU&8?{{ zyGs-T>yf_)dDt)oBVTW>y$0aT_CO+wNKd)^ z!J1WE*p2=fz0oRO`Juxz;ckkjFEinHzcZ;zEVK;c>+F`PP8{Vhthldb+Vk+ZzA>cPJoa6Ww)A>K> zI?J~v-@xsU7Lbre8a83WAuXe%WAx}$N=jmMOM^6H1L@l6P`X8w7Le}l6p#|*`|x}5 z9LMj)^ZW((aojKN?K;o%^SN4MQbSf87c<4vuH*+v*pNfS@9*9Zn`uahR*yO~d3Hyj zscYre=P2`uyw#8Oprf)WQx1rgj9A?!r9_%C-Dp?+5j`muk_-9Iz-z$Vr^VwmSC2Hd z<|S9aEAif7QQmdH-U%?>O8$5lX`hfI^qrnh&Gl>IdTx=r8iyFK`)}LXuG)w5H+*sF zY}T&T4x8!AkLHs%JKY+9I85JJ@;4#4cygjq+`yLX0R3;L1|pmTrK~L8mp(Ypx)UDk ze!&{z8$dF>vUTXBKi2FWJXo^0$&gMErCM!_v z7m<|FE!><)I@JzXa?;BXdUrkp3l*-|3DK-J_9L6D@q}|s7E@?#GVg*ra%^&1wu+~> zNQ&1#jyYauP1AFpl5gzJ3VG;b^b%db!cq^G+UrB+jYvZMtq*E z;?J9%P}$fx;ok5yaC7@UAi3cPRVOu~X$Eg(LOTFgN9C9a*v5oWNgu} z{Wz#{(fhl}QrF2SOc$oI`yU_*fiOH1E0P`XzRQ?Q7v85v`QbO&zq(`|V7gxxFTMG2 zyt{2gH0nHLB}Nl%iSyG5QiqTsgr@u3#Wo zsP^yK%lh`O3HLsc{2#((n6BpO>Y{-0Jd$Y6GkG4?L~183VL5?40^W_EwVLy`&{1pg zC=HKD+TjlZUhW*@x*`>D52_xo_#^LgTd}VYTGyz;lc7 zlFLye+cxt(S4Q$JO0EwIddy9da<>4Qg2rt77L%AwM#{$qjT~$C8%qBHKs>_*1wj3L zCfqzW)~HQ-iXsR z((R}srS0+|#GmscIslZAv;8e!!(HzOOlmrXeXx)6TuN+}V^p zybk6};nW#vj|EA(75OTE1w3N^4`5U`VPuxJU4qbd6~NzDl*9TAM1@cj1q>yN|P6(0=_ z)0K5p5%6B?Pvksj9!iWmm1q+n6h$Zdr4I~uZeg=L6OWl`H)PSbA6I;E08e3&wNFfS zrB6#3BnT!&Z10M@UwM(m|9Fp5_%+`1_v(ti+OO%%lVscU2zsbuv53KAvg4QF@eJR- zhnbX(+%TvV&NOVP{DV|`XAt&R>b5yzmKgRQK;4YozV|Ve@(_>}G-kO`{{1;DY(tlObbztHL8#}!GOg~`lQm_%TLnpgSsVX6m zq~@08`gn_nO@)nHZ-5l46%64$XYb&ugSO$?4cMm?vaye+11l)GUSTVGRphrKaygoD z&qEr!T(m~tQ4PhkM3N%o_I!`+A~0#mQq!(7NZ%vB{LNabPi$_XpjbLO9)b>M6$ui6 zcloI%0`g39G8EnUEgTfdvr1=hG+qJIhp0b5^1wCIY>AQYp;fkz~J0tykO`bK>2!agOGPQ7t2_RsbuiOvm-WUF;!?Ow3aPKesDM zrPzFx+fz9M?_VG26wrc#B${(CH6)a$E^IS|?ZvV;m&vER>>Dq!Z2!0we;XJSO8-s{ zAjDT^-K={iSvu#_^ohC3vab!))I7Y5ns6nupiw}OZkAU!Uq3SoPjI$E@&!LVmDk>A z0)~;UJFqz~tnffRdANCmuO;P-lbhuMt>#RhkI+?-XSMG}C_A!peP;W7kgZW^k02TSQG3|iQOuMCKc~cia*#w^aW1P9i=A!$`G=1l-Ei+4e zP<~+I9=(=`lD{YSmuMN694;qPrKB7L$|$|#wHjyPHLP4%)aUEa**5nY8+J%Z_;>Bo z<}$jZb%1`y_eY5la;1s-#>|gAQ}{YHzd7^na!-lANMDEj;6r>5=BA-EMm^`4I*Ly? zAy!1$EBf@Nb-5rA7!Tno^I>@y-0yVrBZ`~r-7~@FMSiC~uF*n1H}!j#sC@8fH3v=| z=34~*_0Xs_(4N$}9`qcfd|i<4@s8nyo8q9#(^fQ#+*#S3WB!Q`N@b9z{9=?fowv*inxVIB2XZ{OwS4^_vOBTHfYH&3j>%p?d5nLv) zT^!`PLS1MvsPl{a?u0PqJz->g@)`V1t?ON@_I((mwOE_DP_*nu^E@M~?PG_HABU(P zF*5DWCH*9URmVo|$R@zXyJT*fGU3AMIA4MkBVe zJ6r#_GTtHLbieoPN_R#@5f}YsH5pAKmX63$8BO zbmp#jjWt%$=3dux4m#<;6SV=LO{+wUh25e9ht zsecGSuzQz zc-9wjREv8$c!sX|GKfMB>-tfre_pZh`XdRpFs(e~NcULnp30%ouX0&X8cgQ z$4{D@*o7<#fAL{|HUuq;2le$HixzWfG_i*x|njllSrCI zD*t?6vcy)YG%G4Sy;(EKH;4G)`$XwU+rc3dB)S@lK7q*VUhtJgs5*DF9GQMUK^1;t zrb**cgZMmSFv6!nV<`%g@rfUNt{!GJhiD|#s39Rl5Vn*WZfzFA++4fdkSp3g(nS=R zmRrI|XnpJFPKaHsgVr0q_7Tc)quDq;n5_OMjz@FZInNNK2agpQUF)<6kURO@nY)q$N@%OCdYTNQmDd3Am_A#(I;dtFPo=phEp6 zWX|M!!|A`Zzfo_x-)IAGo-U`qv01&;aBP*Z=j8g;f}gq z88IHYJm(2#au&g9d5UD4Fj;|dJXSPgDpdkb8|5~TwWqx|fCZZILp%ML1s~=>Zl@&|zn~*sOUjD- z1zwJs1Ogp{#)e;q|Ex-|%8IBVJ6YUgw-J!#87*p(+%j2=LjS_2)YcCEdJnesH&~c- z!`L!$Di*Jrf{u_@>gsUMLO^f$XYT6!=0oq5M=sBoBL4mo2rq468R;|dDZdb7!g>JP2Vbqpv z>p`w>#hnWI&n8XLuL#9sTCNY+`|-v4L*$>Q+i8;x8Svy{1Ha&uvxb&< zBD4?a%FN0dIS6A-hE+UHp*Rdm#{u{%2!Mg&;bv@aFunD|k)Zv02e9Txh=#S3-Xcmj zy%BAjhzMs3ueMrXA)}r08@@`O3Dcw3e$DO=qaNAexXf#ngZJ)^7 zJ{zN#A<^XPr%Y$`r09PIrT;58rB9jRVf3Y6?thW>@<&bd>$-_$%T?MT>j4%x+(N>5wbU0)*`lI#l^%Q;l$~`0Vn)v;eLza%niRpg!TW$f5@7_0F}$;xuM`$SG_Z zfmoQQ_S-AtOzRW8Jh*SoLSO;y3K<7x=L`h=6oq_Y^6;Pt5yKBYB2;6^F-^YM_gl$? zK^>`I98G2LxJUrAV56PE57owR&q7~)a?j0*%a0uq5SO;hfx{zc$ChXQuuLb(`^CpX zkHSxtemF{!k;N?}h2cLK4-K37&@xK8T#k6`u}#kfAq*+WcB*oZ3`+NPW*gK9F6@j( znQk$I@9j?$zxL;)5BsyesH+$_-sOcp&KvRFnXgDtJqXw5+K7_}4wb!W=S z0`k_>Wv4!lc`fh)?;K9b%|7O+pg0s^#0I;*wfc72`Ve~!qaD$jT-Jw=3N{RVPPZHa zCv&`mB#Sj%J|hL*{g6&{CF_B=j?v#-*5((m=BAgxhJXX!`lD>_uB0sZf8?5QAjl3$ zDU3C7+YmE3_~!`M*lXO1?JPdjgUz_>B+b?+Ev5z2Tmwp9gPkd$ z)9z{){4ky1#KgethVFykOAS1kTq2+=$vRO!%4UU@hd;LRL!@@w+Y>d+R-SDSu;w9O zA8xp>&Xle(@APFKwNc$x`q!sCQr9JVzpi=d?9;+J{aRWDC-g|5a{`H{ z+|XDdortAIRbQyVw!~=8IS?u>B2DvL5HoVVNaoo*UH+bVBT082POot>#7u|r*8r{z zffI@0?Bu*!4@#<-v@tpWFPj{j^DQzsbg+8o6Om{JTdb_6-{e9-=CW%KdV@$_iIwt; z4CG<}o3y)HF+P4Hu>l8Uc&ZT`*(-zlz1CXl=oK#56n{LC^H9@>r;H74wF+KpSQ9PJ zydQ#o59zB_L9dvNVY&S)-c5&i%e@=?fQ>=os=+I76EL9#mhwDF! zSFiZLv(AWQ+-!d&_Vk``dpbmx7}Wq)?Ds2OWUr~;b3=Ed zz82Z{9+g{pVp2tx;=K+u5KCP8o2mXV-fKgP_bBMxje|~1^hZv~!kpm#m9y4G;!~CF zR0*E!9R!n-I*mcXe}Ik;n~!})C*t7Kq-wnGNUKK4n+HIY1ZWZrKgsYCV7QX^l+x#^ za0YNaF!G9^qSxp2&o;ZH^r*s0|E-aL49$-ZeOeX@C%<3mzZ5`Q*V-YHb%JOEUjAyz8;;mql(^`ROD%JP>Z74>mJ{ zyy2kWeeO z4b)-_MH<15_sdw(#?uJHXPZZC)-E%7RM;<%Kx>Of>b+6yCz@q7bS3(iM`u0i#MR~TYZ+F&PNR2V(K-^>HpfW@obj`eu!>&PJ}hKn;21GNTFlvSLV?D()i>D%@- z5^7T8gq0kHo5ih?4;dKOv4VIi!s0vi5^RQpdtz@(O+Ga}-hUzrpCglG7T=5&{~)b> zXu=Xc4g(hGnf|(lIuAx}SwU-w>VF>Nlab4*keX4`!H5W{p0U*X*NA7wmJfE2f6)|y z&Zj+p{^;w#{OlY+ec0eRB?%Kjvdh4TRKfzAZjx{Yx4ZLf3kgsLCX`{x)!1*R=Dkit zJGN5t4Ua@N?{L#LbIzw)JpD4_Ibhi{GO-~3`1iyta+KV zMRISXjlypw=U;LQi1od{Hh3jFxg*|GMYv~u=6}*p1s^}$@`*8OrTJohsvsH;F`**9t4#X<_6S<{>J-gMzxyZ(Kk1XqU#;LbOZzAoK|Z44 zY&NK?zUWJ2uX;qu53Z28T(bz=5SE_X7982s^o?}%A=5#h^z5}rpIg=GT%URBMARlC z)%Z;DnrKlZx|F0G1eSGnHVHu#-CIwB1DY@U5ycYkl)CQ_G&CRZ(YbqWYQJW7hDKJ- z{qA?LXPKqFt}0HhbtG$Ka9tYADXeFE9eCg9SN6ObY#n-*Bq_~T$bTS*1^AVr^smNO z`Yc*A7`{uL6%$bh0f-*6tOh*EG_K*Dyb1SjuB7At_4(-DDwvc-`7; za2f5N><{B3>tQ1N)6E0hE%;b^))A3zO|q7tL_>#8T|oG~stOAX4XnJEz^U7JxWqcl z*ux<_+aZ#(WeYd)*ErocdGD_fcMs+vGvqXNAbY1x`(B!F_TNNX4oqyL*l6JPkHjAd zEN{F|5osNLizO4ltzj+QL*8I5(?Hh`^;iuP$N&e|jZwN)k=_dUTm<}U=;oX2-39<8 zt4o_#mhUMs>fn9~ew=aEX)9v+WA2;F7^)g6X}pkXhScIGO=@AK5lO%P7ntrIwKMA_ zIOK%YL_W>TmrxA)#P=Uy0H@9vAYi&>mKRdzm3+A7+K46SlG}kB>rYRKSLIw+mFRCi zI90P(?RC2Je`l(@l+-mwMgPug-|6Jm%*;jJJklfKRa)W(7p%_-B`9=YTGf)Nqou=n zi^rSjsYY@+i#E(8(rwgJCjY-h`~Uj?_&+tgA#t^NYPDx=+V`!xul8_7Qa!w>0TR}k zzYbSloc$D6Q^VljRK=sNcv)@UJvm6G0!khks+`l!W;oT9rIzONo($FG?CFySc`mk@ z>*ADX5cDVXi1T6ev=37 zxICZBGhHP7MoJwl?5Oxt#Q>(N7D9egjRpBfi{w&<`?z%)Itp2NDao` ze;uUA@%ZP^$IKrn#jyd`+2-cb;U1XWgM*`;A+{=O$LrJt%i1-H73p{Giv9KwCvv1> zWeW3NGAU2^fytbm*b}7+Vbhl>Tsxf_&MfkXcl}gjb(5PTq%szdGLWeGrb#Vmo{PiT zvi*RxZBi9sh#_V7C$h;y^Zw$-Wv=2;uB+RW_QR|jPHaP_ikdNuW$4g_#i6aqq09W# zF>$LhZr`KXg20c^136%p6Fhyoy!#PCQ~DWNqXBh)Q-X2t>De1i-@U3h^w0rf_<0zV z>4)0dKl-#Rtqaj_{+Zx|F}G~_^ZB?0(^se>w`piw5()BWlqp6P@%Cy2MLVf`Gp0gm zK+yhpOTrMFS_5o!KtGv^Gj!mklrRt2n&xW;gN4(;ADNtyaA#A}L;oIDyzCkW^Fwh2 z`rST~$NFX5pq@t=k7o*^SQ@(r#QRxg{W(q1+sI1`!>Byuc@Fbp(Li+ifM&mYqWJ=R zBbNby@xXWCIwPp#1r(?oVHMK5IjkR^zApoT-IK*ph7civH|=R7K;;33`E-)5Vi!n= z3p?$Q_H-5LU60S_3h4H*uTIiS%GgJlV+b?*<;(NA7`>qOJs>(z>vW;Q- zHT=BJ)A-uN1|G7^GTm=0+XE#R7S%4Qiuz%vLh~uNn=J`tnkCG*LSw^^dL>r_9Or4; zHmxrqYFqyvltHR8h?iN(4iuwpC)2*Ya@ewblvpEjl;w z?Rf=73bzZZbp1~WstQjzZ~DZC0N-5OQn@l33?2Q6(L`ddhscx|Gsh0}<|4UZs1|`^ ziYHPfQX7}?e^Fn>S_@4t5{93Nhc#mO3GoWd9$nF<$muQ zlx*~$b>>6>aSu%2H(?0NB-9XU65CflMjiI?%g=0`b9LuHU!e2T!aSDr9&Y^XU<9T~ zM;1XA2mJdsHni(dZ`MyS(0MmX*;Nbo>cjJlWqt?*QD4(%s`q)Et?GrEL}hIz*(P89 zcEQsrek*5st=9@qTBlqAGBXvF#F>d#L*vV;a2uFvEurY z)>p3*ZOR?XQ?%j*rWJ>HN1%)qKgK}Ykn?9QYu!=k666&SZ@l6#Xd0$(w+s?67$Of< zIHTJ<&!vn^2K+KW9;rywWJnA|87*xeNh6}Y=2H}eDLjezs`Q9vO7vtLC5dCAE3RZi!RCS$}1QcoFS6Wq;Nj0TTH2Joh%>FH_akA-z+$DMKXb7G^inRGbU z$Er^!v14|`!#RlOMA$OtW-M(4iIg1kC3m&=MQ!hXlNkc@v@x7Z)or`5V+O`E+QA0- zI9{C}RQB7j<~pd;N{G36hHKE-YCG?i)Px5Nh8gEDvA2yWd-^=WPKx&5eiW-}Ff3oS zk>iGC_af>j_(pObbtHE^*qd$ed!7APR1bZ~-y;>(x)Iaw_l^zr@lM@wIQ-RWNRp?!Pafs3=YyednJH|zPdp+bqp zuwMPA6AgYfe5CHUV3S1B^-HZ;&sa9rPIb))N7Vg0?+EL-|HSx?78%HyHHvx7 z$iuzMlzLh5tfF7HCO(*#Z=s-{XE-Qwu*|TwI{!%KlTSX)PgJldLqt64$Vu*xwQ+i? z`rSNzn7U4TVHj=Cj{*3rK|5APy@I?zazf^jifnV~=mTP2>7&_&F?bA*;BtWcHYOVP zGVuYIx;Eb4Tzsf+Y2TT$i6aX z0Ir;{H6jE*`ehTt$%XRAFRSTv_zxsF|2DR6&9>X+vhVssY^PE){B=iz{(Yuenq9Vl`T&-pQ%bG2YJ_Yr+iGn)XuO&ix-|Kor4zYU*BRu6q4vd!XicK zwD3a_6Z?^;9&3L`dL^?mTMu0NYNSdvJQJ#6_&I!$mG&4^HYWfv*u5sa*z_f9(0fDk7qq17Fz<>*H=*-B=NlJ|t zReMV5Sj8$6eJ59CGAn#_-DN3!6=kKzW@pFE*8PdoWmr`UG_e)aJO<5*u_f_1m`hu2 zzI$@to^541X7G!OJep~o4y%Be>g@!*W$qbny8@m$7qe!0`eaQVOd6G*TJO|vMc5?* z2{ys@@}^*3vVjV=Lu13V=XSnn?^_R8{uT?LKIg+1y&p@pfVcT7;DbG+yb_#|2bL{m zZf_&@r%9cf%-`uEBEz7B&m3l?({eo}UpFuA4^QcCsAOfBu zjUo71Q4n$Qi6FW!3F_?myyJII_>T)z4c1NC!R`3fmh{$a>LII9;rVJmzt+B!Svvf1<3E&%t;THI0_34rc^5olFb(oAMtccWynb4yME1N8 z$WNukq9Yh(T)XxH%~OMM}Q} z(lubIF}?S}nCe(V086@Zoc=;Q^>}=Zqb&;nsz(m=@>SBuN|Ox z(G`BUtlc$9OJSMlX~y%vFD{ouK<@7SU#i7Bur;U0g9DQmmi<{JqkAeaLk{GtNA)I(G)km%9#2Efk?dgQ8C9~SX^Gw>d1ntc$9mGn7^1^jzwjl>x7w!oKJ=>(o*#1 z;x(+|JDgd}1cY`)^?@%ww%E2x5BB4kumpc8Zg)s-s{C}Ia@n8%`s_L_rcrP$>PXXa zJ6gpxU~pU^w>&Z#Cgak@=4gd&lKn#=G0mg}ej|=q-HB@V+9f63&%KguB7fR=p&k9& z=tV=$TANy+QqCK9KOff`O6g*_FUa1h=O-XN7cZZ}IF!^P7+i0jPP)60#4R^(-1fCm z&InI!v6@=WNTPa^3@ z_qmLrWvLrJ{~rK`gxs4Bd1ahe7T&~tZ{tsC2wLkPiR!RHW9t#$eavrQR|pk}U-=SZ zl;Uw6!)=!9pj!$l7bHbzOCEx{z7u@{45a)IKsHypr^!yyV>QuI*aq-ys&rLEG zuXkE#nkreYT+)};Z0J{t;$#(9L%yPXqtp*J(Kg zML%?(G*3qP=^pQ%oODO?ap~~UE;~5x>(psZ?}g-9&OZf>Bo%^h&?B!TH;B}kVZHvp z*z?ZKjJOi|`dw(M_02lJwh9iqDW9K2D>qe3(2?k(bE#n~MsfA`D$8btd&#B;?%SjE zQ{y?bnSK_?9Ik3X6R=y^-c|>^)|a+~ET@Kq@K^fi0Y&JuC_fzXbhpslBZf4meby#2 z=V{q*=4u$S=Xac=*j&vNYzonc=wIhcKxsp!NCyhH;E^cp7pQc*$Tu*+ySr z@afflgJ5h5cTWLWPVavL|WoJE>Sr;vzseFKtu=kZS!9XW1mIs)Wr%z{AA z^ftpJD)b8no3(xE8o8b|HCEa5PRcVAL0GBf%l}eXip~_*S%c+pC0%N?bd6nnY!EC3 zn6o{s5bi%nLU^HLHS?L^h1#Y0>?lg2~s;u59?eCWW;b|@7}W@K>aDJXYz zZOcYA9&eDzES0LtlP|$@6`E!-72lwA&1QY@ocyF?)egJ^333_!4R!;TpGl&Kouw-@ zLu4dXX{cXI6wezi{}a5|gBn!H8kZlR>>cU6vfI8NA(PdmF7jCH;`j(|6eA&fyaC(U zKPCIL*d+XcZN4G5$RZhVpJKd$?Lg1`*w&yu)gXIKrTm3Bv~A1*yR)*E%GA^F!x|Qe?AFa|&?A+;lS?APPZTW^v5iCXUC; z(PRKfn;V%A+r-JZH4X*1t2T)|;YqAo$t0HA2Y)GF#H9D;E_BjJdL8nQpTxRoB?4B!hg+=`l5y>-E%)DUMWXwXv`anekWDY{V^cv->dA(TQ`P0Rt zIW{Y1Q+E-SBEGu+^A)n-xdnkKh3-sSo+`LQ-|00sB7B3BRlGAGeH^y0^EG?rpv&Ab z^WHYQ3>q{rGCHFwLrS$!r>c+Fjn!W#1Z!Ep&AQOvzr=f(f)=BFDG!Jed1z@U14fGUTH8_J;Jmwf^YO*o)VJK%4Takxu@Q{1e$_qbzL|e=hzve7sCU+93g- zE1MVy5_)5ne`&9F8V&o_&=(6~%g|UF4~dgL&j*+E;>6`AmesC$y(lcZieyUo?Ho6b z8YI9+*Sc8^K*VF*TRJ>ZTMt`DT$KFmLPgVB#Zkp+$=Gnqg%kHR0g5k)TdvUl>D?Q7 zuo@ix0lB;tUzKaP7Oo_ey(JGQUqw zL<`s@7VBS*6tyPHG#5d~gtolwW!+$zTC3xm5LJ%-i63Ov5%1g^)0@@=xd2-zfU!)A zQG=Na1?c%gV_a&!#%cGYlF91hh(#+EN}-*lyVhD>klt;M{+bs(PNvYZ(eC+1gS(qI z@3dVDs=8T+aEJ4kIvb^=p#g=ukAo3~7Mo@pGUQ4UU2a`AS=3nQH6TX zB2{=8MWOOd0P#Jh&qgv-W|=41H`eVh?&m(gX?Pp&#Ue4<3g&zg>bghiV^SeaH7uIq!N4!^f8Vp* zEJSbinmdnc#qvb##Ma^UBD9$1u@BYoNJo4`;Hy{GFiup!f%d_;3+-iBxcKvvZ{4k5 zz9eyJpOCW2nE)aaucc>m7XNN(4}UQKLbLhF(;`YhDzO}@=6)YP6{|^nK13eqUsCL; zS1klR)C|RcY>j#1^$Z8qxsdr zY1P2!f%N)CU?R0kjd|7f5u4)U69$RI_ceI*QoUo_bpgB|jpQzpzjT=g@pPD2AO2D> z|5pDpS&zuQ+@9yFaXN2tyzkXzpU8>$MyYXKmW7zAPZV*|prFbe9V=n71Y{u|F^D^(T-BFo2s0QhHshDA0v)%~XR5*u9 z#d&as)$734vAOG4N3+ecQ|^zoRl+D6AmsI|55({9Z218XXDwsJaoVw7Z)RQVcu&0u zZ{QwE!=qsdnR|lUOzQ%vIwuE~xwA(!v|g`%o$A(+X+Au{k zc|vm`4WD>4rJT~7)mm#J+1&k09C)0J#@Yt9?`|qXNKYsvAGHbE_1~0JNwC6EA23Do zT(G@LH3FG|dtaJBN$dW*(BWKv0lX-iH!)G@+c-b>H1H`M{oKi@Lr79b=>*x~@y$B< zdk-S;6%SWl8W3x!PON=|6!3NOsn=2af^^;U-%l%8s+i2dE)C2zat5^a{e~T9nv7)ocYis?J1f@ zHH!7@7fd&L}4Pe>96WPhnmS(I z+&{nL6DnhJ_?q~&m2ZL@KLxlr52Lgv@rPp}Bpw5WBwc~?Kl`Tr zS{JTk`wWvZH&LL!=PhMzU!dCOO|{DWbON8Jut5##6!Zbn-7|fARHPDaHY=Imk#V%l!eT?ArUOUtBylX+SED zNv58k);`5P%hwk=dzoV=K6#+A%B%;1^vI2~!EU$kQ;$9lJ>Qq6F%WUd?=ak?=xdIw zio3I-s4yYtk#=Y?`}9Z1NpP!IrNF+`$$I|6gl6s?sTYy+m~<78pd)<=r@y>qvI&h^ z{P9u)3^xhD_3O(6I3Nwn{NMHautiiDb13L59iYI=!>)YmR*`A&=*YzG@JxM4vlFQ; zW%^R++FmDA$?>V2wH@)6pt{DZhdwguhdMQ)L^=_pHA}g{T@&Ib@=#>g%l<sOn7>(n*0W=Lh z7-3`0^wc2|>OWu2rO#GoOP+PbUDPl>&?|zYG9Np8+0TD1=Xk{G73L|K+}$KFC-aPfBruAsZGV9Lyq2)kPi3wA2qu(WdnCzkpC^0X@qALq2U>WWr#CK@I*P01vD zz2xXlF`}mb4iTZ~uRh!`$0o@C&hq%p;k!G*Sh2jsvcpOu zQpHPEZTAC`;bK`wclJMUz z%$t!f^dXW3v2Vf@E8v~OW??-9Qv|^4sv)ED)miA+%bEvT-RJZQQiB1?n%$|wX|0qc z(yYku@goOp@ZCK4_tsL)=Mi+xUvlU$VJh3X)c!zff9|rkQ7qGp1e;= zDKRuyqmq|Sa%MX3wz?FRh0Jx+0Ep6U3`daiZ+jG72Ul`VpB69Xy=#T}3;rEcM;|%6 z@vBDr%ip^qmfC}z!$4p)H2`7ay-no(hmohE+d{e1_Q>brYlTZmV4MXM?0N}~MWNPm z0Myv>azEaD7Y?tN;hyNxcDQ+b>xqhw&@>sVPE6jG$I&ip+Ok3LLvIcruVj}pMlB}s z<6%=4r7LHRUrzm_ht?Vi3Nxr&3@?i|GWVDM&z>a|wmaKcvm0s@L|?ylDmR)dR&MK= zIh$|Od~-YEE4*}$K}SDxlyw(6IxqebfGJt*Tzn#Mx@eKg5_5kR0IRKHq4#q7<8=q% zx=)SF??n;D+YdF(BQ6I{ztW~a2js4@G>YXCaD{hzW3cL`{{WVj+iP{Y80Jh9s@CD9 z&+>|VUMzkoRh>9s-8~vOVAjaG)7ZifqW|po%-lbnYoKMNc9r`yPJe>ceu66o|1HyE z7$JXJTC&^=uk)tA?Hci^SCi*>aQ(Um7l=;}#igTJP$FrK<&SzGq`VRQ<1>|I6tB88 zM>Ivmf+EbN&}f>u*s%ZzL3)1KhCbHi2;JfJVJ+I-IDrkB$z#)Lnef?)5{Y>>KE=Gn zRP$1EQJb&!)9Y-i#@8E*uIFXTpjw+OWS?dRE{33E?6Ehe+u;9*Z;}hA5`$F3GG~X~ z^xZ(ZIizkvd=S6D`0LwuOlEqGTY1at#(Dq1yPYrA5QhOO$PPE;A58dK;rN*j-IR?K z>EC2GCcXJiR~X6Eg#ne`(oUr52wC#C_rv3s-A4{=AJxRAHtD_1Yu*=SjP*u%2wU6( zb^H@S2ylOsPiJ2!q6ysxeLpZ@Jy=2Jx+$2Rx{AOLCnJ%#CzR`iW0ADBtzU*9A*TB8 z033|T7IOdCW!ohsV0XQ3Xv=_poanvzj;8nAsuGW*V-Vk6otG6I?>aFLsYwQSo4m&wleY;aYv5ZtB%7rg8j9-r4~)L= z55!KutaP?d2)Y7{b{Uy)=26g9yTA5Irl%y{1-ILt9c#ign5U$J1Yf)_GN%#&A)b=# zf2l-Il$;$tic}xd*ojX`CR@Cur)tf#YaW(c>LvLRGG>6c9e&?z({{pej1VKh&tJbc7WZScBS@~h+aj*~3p-Psueg$FznIWoM_vgq-Y&UsxD z&js1%kzV@1Oy(LMWY7A>E$pv-C`c^?OZ3J+3LuU*8Bal zVh2i@qn|Q-GN2vVR@MuDtnwX;b+EzP;Vs&`wJK|oAGNeLQfUsv%IMp*_UojCB)F&6 z5%u|BU(;{6UDQ;+`ALoNEc9P4P(+x1GFe0&5!<-cgo2f0_?}j;wr8q-xz5Q<^h%qDGLq8{h@Nosj>jn}dP`>M5}Y%V@_b5`po&A}rY#iG9h zm%Ud09KOQc0LC`S>P6D0^Ie#$n}j-#_Kl~_^Ik*SG;t4t2`knyn4gJTGJxIEXFO?v zNp5Ndr6&v~6FbZAXC~eUs4KcjG05Vh{mJmGUN$$F#S1pC)n;6y?`*&2>}KYH;t6mUp%J95LsJ# z{2#u~DlDo$`qx8ANJ$A2g3Jg5f`EW@$Al6?$$%)`F?36VNDea~NXiTYlF}`pQVJ+3 z-7QEr{LcI@&dqtwIhXr(KhJmX^gSo}YCrkSIk>cNKYizOoy;^8 z7H>8chTG{5ATO;5VQ~5ZsdqT@O#^Lsyzm+XAiU)bo6-{VV=6mhhwM7Pe7sS7 z0h{I7lvo(m7O`XsW-0v&3zl3Yk77!J4tkx8zl5K8o(nLYGkP0d2Ak1XPE{P#gI3ux zMet_fKKzt@X(@QWWsaQ}i4yNWi*7x0l}uE@)mIh4;6#t%>dz1hO7`vjA=ZtoKqEX` z_o8D{hNccI^`^{<6Poyu%s#u=`KIPNhE_iuPmRn;miJ;gCFf|LM?dOdRW(z#sYfTxx9 zLAOizBk4RZFqj{3UKMCh;K@FOJNp<&Nlu6~<3C6Q)6E?%jm{@YWD_d1bS0akGwCd{ znf@ira~X(K&ZSgWkqo7w{qI+_1Tu^f1*jZ1(Rz5E+S&t`mS*3hQE^e{><{1{#rL#oOSoRTaTo9WZ~{JFC$mAe&uza*|?eZ8Z)QJ9@-V7 zhFDw&EYq0sK+8{=2~%~Yhzi()s-4znur4x?paE~fxxYd}Hfl%*jIHjsl`ArX=`RU3 ztWMW~w2AZ*E`#^W0t$f$%N3T~aX^gP4V^U`K@ zmEdWDb)${#^rvnx+5jm#o@)))O7yZE6nL{lNPRT)#Vi|B0mX4hRv7R z=NqzcXX6H{+E{)aq4*19h)jPRKR4C-zj9Cq@;a688&V-)!Ytln*tQ8H)~{<2CL!S= zpBEz>oGEbEf_9N*4ErC^NMi`1QG1AtFl3>kZzP!!^IF}N`BZW<^bb`*%0F?Nzkw3L z61QdvuQ*u%69+5jCeMP5#$2HcvJZuK)WV;7x z`;IGR(?Y=pZHB#IZ}Pz6t)t5*#^85FY1Jqh=&(amHBdzz}GjM}kA;R!68 z#zskosYBe(@WQVL-beO|{{e1W$w!rUq(r0`r_i)YS@M!4_Ad*t{-!-laMMEcux)a5 z*FHa=BnkVeSN+Q?lY{K%t(mX@3TPjf*LVTH&g@<4&0H4m>d{w$`ukmPwN?efvR77x zmWSI&hupB<0nab5(yu3NV>~xh9E+}=GAYD$tC|>uc~DsIO5nd{T?q#z2Q`0mr>l*U z)0=82v8ACV7r}3&_YDOex4{v^}15`0alI)Gp^4fmp=1haQvWdn3`IQ z0otE~ThTe0mkQCUfw%T#De6}n837AKC_QMA5?JX^@?9QoLg8ex1%u-xcYh%aS+ZZ> zFUyQa{L8|9oTvCWfo?1bqMlK41>)Y2_0v=0{i3nuG&G&Ykm=D~uA`%pA2whh$#I`> zFS`lh{(hD&UC^mJ-;3$g&CP=|<3J8q$gv`|%5k^{60hNM)By%VNyl_wGqMIcyu(e<SN6=+Z4xI*<8uNY zbnBL;hl0@y6lC3~?0eZeX&Tqe(kiX+M3Kh9^rc=z1L$g3je#8z0f9pP4RsgaEvldy zjeH)ZVZP++sy^wE*wQ4JmQ_!}BE zG!(jFC>Hwr&lNayzG1kk>77MfomMGp-t+gPA4`J$Ir6>w(rECg;<%>X`?t&V|vz4F`7tG@GX0OO0$|UVA z1ryG9@1$#ggB*}?AqjUOo#eap0>3U+ycKV(-d`b>m-BoD$P_+FB)iA!UU?y&)CzcJ z>FM=jCi{)j`gC<9g8TjkcV&4wqI5v8xgreL`nE^lMQT#pnWB?JSpSeHBSDK4BUcOlR}p&i8~5iW#Dyi|bFF=t65%1Clg#BmKw4!kUj3r>{Hk5s z;6K12I7Vwc2g>h(Nb6DWAYio2d5>mu18>eD=t0)cRZLr+U+w9t>2H_zjGKIISYru@ z{G{*2B&J}ZvWPjN)=?I&m-pu09F;a)(jrc!ENo)sFstf7`!DR5&P8O7B6N{oY5L8C z_$xiN<>PqKO2xeN&jsHByJOOSF>we_W!Deus%O7WJvUuQ9g#P{GO6jHikPDR@@5mL z^{y;+xvW2G^X5ik2m%jVK6so8;+;+8slKWJ%feIvNns3N{`><1u*7KUC_O)Ag^>Q! z791X{+X`S}>h+^$-(buKaG#xxnQvPms^4b-<#be$v6f+g&18+_0c426IMz7|2C5O}h~C#7V4wkNMHc z#=Fb-eZv+6df|u8+l@bax)XbYvUEo#gzgfsrpw$4Zk~(nUh{n6QjcR`;KufWk@8p6 zL+v=G?pu)MFb4Jc+{SV;wq!fcEYzdf6)l(Nw2S8-6zulLWY?{}M1{zOhrf8&p4H@d z!kLCr7q;wSnWA+hncdRyCnDn*1b&T8UFU4Y{q;ZK`?~i_9~-o#X3!d@q{77z+g*$< z9fgM`cBc(DJDolp|G781wm5BQsqJqoDqTW<^W+iP_!-jD?RUs5|LiNLqE@3 z^X~)eYMkLmD#`;-u~3cy^O}#3O=QOfT^`JQO}~UOUd0;Y(#1i8vUNR`>RtKg% zn|X9m(DGo~%BDnvy$=R6Gl?tnpm|H_Av>c>T0&mu>9CuuHPOuf%=G98>hYlNmVxJT z{rGpTFHPSfur}w7eM1()gLO>(bz@icxTgY}l*3cm7fA^>Ck21d3WN!6dO8PDi-9_d zRO8HHu2{twTQM%Uv-c-4QGu=KQVPY!`?j`qq{hcLTSkok0WzS6F{AMO=D__yaf5gE zHPzMpAAN6esIsJ@)q8`&Gke3j|hgSas2rr(OVitq0 zOtOVxF>Hu}Mn*-Mg|#AaU8@F-r@uU#0t}KFx^ekT!Gvh$Fu-#05PzL3&>^PqlXpW! zbVk;*x8grz^)f&pDpj?S+`>J7@$;M)I+wjP)YOdF{*Y;_PEJdk z?c3Ma<76wcLVO1koO>9*sM@rMvTM&kfc#p6egde3r2(Xdr(`%3M|soY#ibmbaIIUQv?gpB8?R{*k# z(WuaHVO<^9%zZ2AgtLTlBK&=KBtorzoxfREcgXZ~we)$Z$dr+-r6V_Di%oothMa8k zFkhMhus*_qCe#QSRAw+nD|}oEQ?PGWR5I+v{Q3_-AX{XC(Q~_nP2qs8A?GrVxC#yi+>MQQ~@HvTJ8E_T=BA+L&=plr`8?K%Po(;bQFY z-fqWx7je)&2qYrKN3RMJQhSL^FGPE#sB%MOcb#(sittdRWRm1q4I|>GandTttpq6O zHl-IrxgP@U)L*caeJFupDgO=`B33jPa>m_S_}|aXJ_^w_<%L@Dw*)&Byh#R=$oDOV zx@2cB;k8FE7-!f$4XHY5S!1%FF*4WICt!gg)~$~@HdCCEpTM_zT!VOno`PT1vdcr{ z_0E?^?1bmO2k@k}nu%V__0QH(J2Ec9T&g&x7b98;1Lx}G!AT*`%Pc+VOFQ}O>V zV9XMejt)CthuA9p;sts?I~GusFEfsvmMVh#$=t2N3US!azSP^8YG6W#ko0jJ-@jM+ zn>zB$4+s;4FCti}DpM@zc_N$0fb_?>;l#NeKY7ecAHS$#G_s5T=X>I!zk3Bnc#FXG zI(#}w=sc%C{%d3pi*E$9gB!ZkR{3Y3?d-z%*#sIfGpX6lRFIGl$eDMf+$A7?-~7Du zc#cWLiFcPy$ak&tM%7qp5X*KQ&{k9Sy2-8$`I|5WxBLZ?;B@89S#%s+?iR1F{8g*u1K$7nf6H}23n2S;5d$1U0@bRgb2 z>30VV@pF5PHzZg%C^!s0S3|x_ly?ky>q(Y|sJ=4N=>N5Ju%PZl?m7e%=C~0-sCYZJ z9OFHwk@b8^{K_w4GTMY3m?x-*2uO5yesi~I%*vCx2?ZlE4j=^pFr^H%#KkK)lnRl?#qyJ*2EAEn-s)rTu zL6b3QgQLak!`J~+{A{QMt4-R%w>RHZ#P1y6j@NS`4bFFiHEtP1z9v4*_%PvXOT65H!H=7b=U-msCtlH_fcils0gY`gy^f0X9!Ht02vDFk8U z&|icA&_h7()6)Ti1*Ff1<;Pd8XY@79ws5CIN ze#wrafzYL2|0%=}XjVw(6+NAYy<;kC95Y0OTJQTYyX?fQ{1u}68}dsJ)k~h@wO3YO zKUN>~rB=r8y*}B=M!bEGzAE%RV{0zMYZ;F1Qxj6Zr~7h|W}WgXq@2hDcR5xPvK z7sAsdYi%oTP#MHocM$y-p&^UMe(YIuSBHKROtmxI^peJ(SJlQDCFFt3;UlB>j&|J3 zT}*;#Wj?c~N~j+!msd9q@@gqP&^cxWzCH%{4dHF;*c#$}=yo~l?I!KyE2^gVfBg;^ zrfJnEheJu~maArzWIrwc2f)D3#YOx4<#swV!OUz>iP5z&Fs#>vznvv$nVbP;d<>eC z)KIfKyWp3cbQFZYHAzXZ^yjefRMUfY2N{iIeFTh`zv8Tu=7gJt3 z1z!%XedEgQcN)_O)6^mkjYE#^nSk^xHJWr;fVBry##sA3qxg6O_REfhS%4TjfTRNj z1Mh|P=)4_L%a>11t$^~ddvN6^M3YS1C<^1iRmGcd*Oe$f5Ln47x0GX*_rg!Mq&`Fn z)i}*8Ucxroqu-A>8Z8KbHT9!<)RB*7+a`tXHHvzlWHuH32cVsOWS~zC2`=tU@V);{ z#vrfZRs%}%82jX&aJ4joa0kQwlG-QX_&#fLd+YFy?0DVFVNV_dT@IZ^SLGH5y-uPD zTMYGGdK}m6-!k3&{5GZRV__n*Ht+%$($)I+9FIn($%%j0G2B|K@;B7t; zt-1A`3Rke?spsBnnN=|>cO2YfX8r>ld|LR6jXZJHp2<2~3~AvdFIs&BqO|Bg$+e<%17y4v0=6pMgO(QN*rJYU)j+&&O zYYrnJ-BjND5ol$(J6FG-d!8sMC4O^#Y~^-4b^~Yo{2zt>Sav!>cYWyoJs+f1-|iv9 z?*w-q>6va5{eO)&{Yoq2414i=jC!J;_113lEU5{uJ+m)!bb~!LhfUzBfB z-wd7`7`CPD9|bbYAv^!cV;!vRTN#;(w>Fo$Hv4&AQ&}2|VO^ zBav~M)kUWtLJ4l}r9AwzB~cT?9@hWp1^E zQg*LfBA^H331!{;m*I}*2sY<2kHA#L%=mzAUi_?wqV}x#It?d`?g7dsGsf)p3 z)1?R|w*>I>dSwC5!yaCSXC_**pI};u#I{DEd?(@A+Wynq*>OcLApSK`yVQd-sMQW2 zt#zcq-A|RtRR^|nc?P;Ew@uX))Z_)odUJ0ri7^Ccl@WE2ro>|>c+B5zvhVfFx?~f1 zEnI5tcvh~RVV@`|>KJlr*w2EP>%bILg-{I%5WY?5#15F|d`x;d95N`ZzczChTtC{t zIHxsQVh>F4Rjj$#*CiO6Pn$<1BGXMk-{fu(_!79TdJc~EHLXCBkX!X=dg+K>n)~P5 zfmsGWkot8>yrx^e4B@g$ja*(P<(Kf!O28t!6h|u2y4@Rctx+{bRf;YYT6V!hn*)b$ z7>z3pPM(%>xt3VVHPp^bvDrL{e~-#Ae=JChe#?{a9t7}njXUj^JZ7$QA34a;Fipio zOK(jgIBmg7dW;2)NjhGAeUV*fbS0?a!j^O~<-Fwkxk?wkbJlY1r?v&Fn9IXu{_h<;587@Cj~u7hjy(OB&ufN% z;9WOs)fh3wu%zN)gVrWb61T7yrR!cTb_d6@8AiPQ7kvwfI9YY#2YM(?jgY>(bTQx$ zeafMk4vPsk3ZDl1;b9G%@1lp7eo`e%zw{7X9aD(H0d0=CjyGhB{*0Vb#@<;6Na&t@ z{_c?$f!biWRfK%sWV-%v;l1TiRQgF9oj<~;TNM_8_Fst18rP3jeC#DTkAdeJ_2RxM$IugLAW z(7FbuAc<2ZvJ0z&Uo-3y{4pBQ%6Gr{(B+q?fYmv!B2WoSMP0)e;cIiw8;*2M-03rW z#yJ%-Safy)5u7FfG<<(=>X>w{7}D_Vh35lnzTpu(3_`=vtFVr`3?R74ogAzb85ip_ z;)LXe$=oO&)wV4#6{4w^7lisv`8(+}53KE;nf+{@rqGeZ4SJg;Nk62H}b4dH8_)Jt!A0YEY`ciL3s1(b0ZmMR%zkyPZm@e+Km-GN&XoN zq=*k^cASpB0p|VI1)hP3E%-X2{|k!$e+U6kI8-Hg^b%~ewi3(8#td3a@VZ>w+=Q^J z1UDmvke{(Ku)ZE0UH53@Q};yWSMUZX+FJ6s^N1C zmJ6&>;T)CoY08gqzz}R=Sp6MgCmw0%)A&2Rb6<_=;^xyR8khf?M`h)(qenN9;rnYH zkLnSacE)X8Ox#*xc?A++61+*MqzbY77$3tyI4_%l@m_M-?me#xHM!5o#*D0uJOn z#HF87dVfWtgxNrxZRxlo_ zuCp=jcHJTYFD&O?3%f$f=|R=n&nD>Wjfc@}daVIEPlkFHVGp&ss#(OI^rK}ib)`Df zCuCrQxBPo{ig23ZY7oeff~Rvfc=DiRWxUQ zjwP8Z?awm-@u@4^XPlrhOeEZ4M0F}XHZYh|SLeoDu&BX4?4i{#crJQ+|6?g`f&GAE zEiL~AyjC=R7+};!qfHsRe=?lkM*%P!Wb(iATT^O9nZg1yKN=?M|89o;_%v1XuIu)a zR6g4udKP={jOxM&>TUoLreA)9&H7O(Vk~ShM`q9}Steo|`qyx6cG9GHg>1&)Di;zL}AM{5n)ltX`RHqpRvJsD0%jUb)BA5h_Y|>tLv$~uDnJ#l}KYIO>m!(yb6W7 z>=66TcT~^rjn<8fBERXSeC>1byn}!p!tgkbJ zMk}OB#xwt(RnH}UrVvD)GCny?pjYjw5TY*_zUXH$d)6{_Ka)xR@3mQc?w!Fs5(I?f zsCU3s2sxV5f|x8whYA-=voR|OxS=^50-vva$M#Qw+z z+t#txDLj6Cc2958h14*@uu1}zf~GznNpgg*2#|Q`=)iUO1K^1fMZGdYgMl_lx|C9F zyA5Csmc&(T3Taw2t?zNA)(9+=EhcuM_e~eIX@}3ZaBS|aNow~005-v;6hgrF%sFo* z{&fXrW4YpekZ^$)#aB`F}=c2MImae>79tqRcba|BBoiZmr=fsd(=) zB%HxjDZh1#K`!PoURO?ueZs%6%~dhK@a5XnFfFK3MDD5fvuLqs$)#UUWpFYyoX0a2 zkvw0DvTVOsA8@&x4}0c5$%~O6O#?lYvwko$%t?t-gSXoTrsksl_?GaxcQ`Q7_MRVi z^@m>9j+BG(n8zgQlo3?C2@wpT;DbKzv!sGXSCR-ds-Xjfj-exAhQ8U536Vm|M7;u} zrM+^XEYG~Kn@^lPE&3b=RdSD2_6c16I`peLL4p zbJzJpT$;#x=2-gtI6dUzs`$zM^cPlg_h3KX!qhMofj;~KN#cD{S%Rp^TrxU;G`Gcg zCS(iRu|P7j%+67gylJ*g^Qvu9l*;ijsHQ0eudpUVlprUCq4q10x=uPt8gB#hbW5KL z$-FIIQvN5ZjIBMR>0)Eb`3_u339SV12pfBoYiEW02yM*-KZChFDb|`}gQ3F>Jfxy9+*X0-l#D zzv=1lI1x(Kyi8&`B=D(9LdmL}59uRW!e&sk{5+ZO1G(K?Fno_OSw2^j$l&x>uuf_< z7Cm-p`8xL4tbz{y^7s0%-n9EapVi`XLvH@O@Q!XJR&&3SUDN%}EoAcK>K9$1KF@}i z0-)zFAMkbCLPV)Ke0X2`nuN-9JLT!Za`j8^)i$^$UAT$j*XQRpy|JZ^bl0y02X)m` zv#q6=LQ0Y9qs{uW&xn}cr;rWT??2&vj%GdNzsm z+V?Ah&glEwLR+M3YF2|*#zToe<~`P5JCH1RifFd}I9^vEa{|3wR`;{OG2a^KTlcr9 z=RI@3`RWtC@)6PtKiljQ*I2F7w#^>fGZ&c7dd@2i@CrFEx-KwM!C$>d>={UT1L=Xi zLz+jsYqAyAZ+0*KnF{;r^3zSC?T8U4qOmh&%%Vl_cb&5zU!dWz(ajd7E#Ht3xhMZ= z-T0Z+sjuU{OMsv)fkQuF=dCJ(h$?UPdcPKB4;kL>j_B>zBqT$RulJOd`^xvP{lKEW zkAB5)gw&CPel1Q_>9GK|pxYyW^(AL_+gj5V?Rpu@4u8hvKqOvfy5%5P!v!+M#2k^G znrD!0lG|g(M1$!!3`;#bTQx5yiiF4-e(a^0q(a(GlbOEhFl%}tq{dWDia<~S z7kSgB0d|B(qvBf+#K(lhn!D)gXu~}3+w&bgo95_u2$81ujG`{$jDfDV&Ydd5@-%_n@?;6)+@HdhuoZ- zE5rsVb)F<6|9V%@>jY==FTeCXDp4`NawxjkKi{ra;gAwii&g|@qh4Y!On|vfW%h#A zyDR~$#SPuDrBsy?-T)t93v-GWY41>lTP1An> zq;SZN#ldyfs^81A!AY z@TUvee(PIzC&Q&T5HtRjjZ9Tj0V{#%K;NY*&0&RU6Oqmx*h$PBDv!xN3SaL5W5KKn zjNXUMI)YOln1Zx1oZyD)?Fvk}Yo(Bo-V`NA$B@#;8o7^OmHddTfq0IYqm^4%nyxg) z-?*E)Nsfk)Ej8-?)9ZZUbTsL)AK~y#Q&a<^VQN^~C|R-&wl(jlT>(>>e#LgrVw=fm zO}tA&WL;k;+H5vLt60 zpC+#dY`-zW5sXZ@^@8pYakG)qU6*f$c9}8vs9|O>wf_Jtn5e|U>{34da%)lH0KWhe z0h)THI=P~eG%PFeKCL{9v`$#LfxMM$1P}LP_TX_A6Zz1iMHAboqQAw_d_HY;=F%xOjOvcqXpNGHzc-}I-RLskmu4yT`w*U;+a^;^sF|+FsjDgC zY7vS1C-3aTIFHt1)W~>B*AoUI{*ONCI+~O#`<+C(pGy3E{|sMiK9{(*ugBG=qdnf` zH8R0nnoH-jFx{zix?^Qr7|u4y!y;2~I{6ICVfh^_->r6wl3)>dU6(u7{7xS_Di=>V z;`)@XFG+ikHYy)qKVF{C&`0@YuXMO>U|qd;#A6yhzA16L?3yd?JIKNKXd$r`&)<&P zeBtU?d=xJ_70={ddb<(d!~P5(b~_21cgKE&JJ}#t+$ho_^4S14y!iT>St%_JSbvFT ztg7GRGPA6^bJKgDf8c%;5<7w1cl(WZNwB(=7eEhkMYE`(bu%@>hXSjNmM1SBs;A6m z!fl%d+WE{V~D>~=F&6*+|<#^=d)rClI1J7Kr_hpYA z@`hf(Tk2b)*UX6=BX&#Ch_5=d#5JPV2SMxTP|D)+iVv9O3l2PZZR&px^1Dt&wl~0D z=zWooHCwNae!IYMHjjheP`P~|RSQ{tLETMB_KW2FQ+ruuKh0={LF;1)>>AB%E@epn z&|#wS1fNGfZHgj<1ydr!d%@^HZgLypXHUtppHM5Ow+K@KvXZjMaO@luOrUXP{+}#% z!yy3TSPs(?U81ssNM~Io<33aoV$3yH|IWuDJEclayC3i6)h?7`CtJr`0`IR9lc&dx z=#+!NYAn8qlf6B_i{MhcT=JdoysN^hy8P_D_p8Iy#*LRS3tfzC#;U+|_WMfC(ZB*H zXlG})rl1F?fn*C8rYIMAQJNf=51j6OK1HGrpnh(H23*Yc@iMfUeAG$N!ZzhYZ27*m z90U1Ni~~bAuC;e673-KD`wml6&P}b@E1NB-UdB~wHT97+1uwCrg=#M);{w4f3l&3-_Z3-hM1x@Gf&q zG-L|P8g)Dri`LbN9WLPv!Os-FtJy7@0!rId)p^`$bO#D7W|Q=7BTZ~BMY5tHcV510 zwstfS4p=%FSOBX;AUFm4dW42}up7_u3u}-{i^?%G(ie?p%V2SR7I}_QkfWMW3!law zbbFc`P$D#bk>9Hklk>T%zC)i1DYo=Amk*^!vMZ#Syu90Afl*H zW&?Dv$XQ)xX~{0okS_)9ZhQY}ox6TT`UT%dlco0b2)|O_gW&0Y;_5NSf|01wJD`(g zkVYz=pyBIc2YMp+n{^e>q&J+hD9VIj@lYMwC^PCY?QaZHaX0pVlu0WS@y(`8q*gjR z0URQss&MkK4GxvZy=aZHiZO%1z{pbu=hQjG`+Gk0 zwKEMw-9~`5>}L1O4o#2wJsfiML}a10DM;6%tkrSaMJ7=r!7VlY0t==uw|T^fi8|s~ z$qTEL9i^9LJ7WvSrr-0YWu@gx%{qB$&#(1q8$ZH0J>h%tJlR*Q-w)I_=kj;iP0s!c zZ2w2DS$nUFkJDFLSI|om9n|?Yhmp%WQLTS>ozn>yuzymt_+O*G#_48zBZ*g*va%b{ z(jmL822BI>><714@waaU4HH{_I62^U`q2=|T!zZ7VtBj|P2WsvnCe>X%|N-|4^W4b z?Plehh!;NjgjcS04N0&L{e=L?ppb}Tk-}u=XmK*z+E=j^Esu}VJihljVWR|d6CiV1 zEg=Cd!-1=FY-;fT+s1uXjvphcllu927*+KZybqHbiQKIxSuKhWmMJ$dLx>_RN5R`J z^@Z8IkqNZP?P#tKJL&3#iRX>?kmu)RTQC1AHMgj zLmQquGmfy~@ZD~TRgzC#mE2OBe9@`nK?E_E3)K9PNE|nsEy{*_ESC$WzKI08dd+ChMr8d;pbW-_0z^DKFk#7?Y3Do1E^Jlb{@Kw-g~?93 z?kH<7Z#6xBR*V*v{_svmO9xtjTbxeFf&HFeUGM+$UT5n6UhOpiX;&(X`2D5}^P#SwF5&z*qM!wcT|Kt9m0 z){Lu;|2o&b_*x;Cx6Js0nulinA>Ru4sfCmcgJW(59e;{Lha4cR&He;>O&hkQju zz$?JO1)7Xq=3fWzJ#UxG5h6(hxSA3>dDpp;Ld2i7&C1jGBj;w?Bn%gwXN3VH&BX8yP)6s<2c>R~?qi{dOH6MbvWH(r{}d@mSddw5cdw zW>vK{InfD=SqObLp7IqBb`YkS^5YSEvN>EL%0z@y{Bj)w%bJDdl|l6vl6npen0Wjt zqRX(4DNG@UT!xSG+8Yv>9(2N%!-OLogC-u}HD6h5lmCObKTU^D#`<;_F(dPv0Y`+vLX# zT;Rj>;eo9UISY|4uQKUTYBPR9pxf4L>{yWf*!ax!+Y%=RJ2>YmfQ|@&QHJVJEcD+Gm!HUDiYe_ zgjH{9kv>@!6x_*P=Dv~odV8$q>3-*z(YYU?VO8(2^;?G(+9<+9$wSwu)|AhU1OQ9w zC~clj9hu1{xpwQT3O6TCFR=DI#f^71tc$R#7r@*nBcG3MmHNo}Y<^ZXE_^w%(Xp+~ zd9Pb7M&TvF<3E7&7YnBrNd&?bFB`me(zVG7zX<4Un*GJ6E2J1ph>Q^RVS2j+-=wf(v}JoVppQZYq( zrK$0}E3G#RmA9;az>})0=OB(JA5NjC7<)VEsohuNJ>|I%bbrqQm zroUK!=Ra&YC8k_QT-S|PN9_;h?sTXIbfIC8E$Uv5>yXmuvSQG$-KDg!z&o(2C0zM! zZ`K1eo{KDLllQ!6`R8$WnD0Ym=C6cEwqGDBr594M9ImecIy(PUSafGXjW$N!dplfydPiiAcp<2XVL=Y!qGY%J{>9Yr98psUy7#t{4@7Xc!^%Z-Lt>N(i2KvgTA57 zwE?esPptSm@;qA9-_ebK2!(IF2CuQ?v*?hlRssHPBTes-={?7=vAIhxP0pv_-7VfNEaTJ; zZ!Yu;IPop#cr(IWFr&Ekq(RHnM^xLD2G+zIks`CO|KfIQv~q|yV;Dy=cfQKXBFFa0 z_~5fy%crKB{>^1@N1lslu~<`e2SiJDehQvJy?4NhAieUT^HezG_k@MxZIMsXP-;%U zLT)`&r&K~(`E0t8jSr(A4?ywL&7b!_H^M~an$>mi5=;YSiM{TTVFshv2oG(HUCqH{ z8b|urL)v=A1COaWn|kcULT+7AU0^kowVa}?&*o^qX=UPOf z@zG zpZ-oEA)39~w1KgRpdIe-`e>e4w|RMR#_@mBS?y~Ih8#Y#LJ zh0r96MA7o?WUNDZlBU>SI>O}FH1n=~-sn3rr!SVXeb$pggs3$Y52?q{fYuMa&!UoX zEMCjrmol3@Tqxuld+Sq***8!|?Wk1u8#Z%i(Y%bYvbqKQwLX7W?FX0~-p}G;_$nY&@iPyXP;jdBmRol))&4Wow*>Ba5F5uT%RmRN3dUu zgg}R?G7j|Kd!BR8HubW6sa|6s!-crdjwVf)}y z7SoW5FH++QcE4pnP@>twQD7uhjjfvK&H)q03+6xllJAEO_^}AN1|S;dx3W%RFp~cg`bt$^ndN+_~$Z?>ld_| zlpTNa^%GcC@0eO)LN3B0fBdHzVI!zA;;SYUJ)HNbyn&jWHOY_GJ}FOb|D5O+^MW9m zlSq@5_lFzWyK{q`S|X`{RmG}qw0kUUq;FuQOuf4=Z|Faqy!EjZRf`nqD91U`oPf-viADDEizqJ?8z^=&Go^xH-hEhnE<`jSDl^zHeU>QLr!XZI(gqF zq`di~=_J`wq0wFeTh&gaismi3E&v@SxY_MQh-koXX_@jFgB^pl>m_CuGP*BeROQF+AONL`MWi8&onAi#TC)Eu)DBl6egzRW3mHrjGJno z=9&5F`x2q%b~_FLcMxWm(dF#&3q~bJdujGqY)k}-)G62DEF`DvFGJ7>8z{t0Ef4(X zm%u;*SMi01vXSa2^5XEe*-L%~k~1+2s=ZtodPH6f_ZTdXsrKsj&}J`J`cmrgMe5Ks>O`pD)84!FEdAzTQ4&K*)tF{RERgBRnv99tEkG%_d0yYVJawrrm8F+h zu%3PuS9PNIFsk)nO(Hqkfr61X&UT^6h@|(nA{?R=Wv(QYBDmZDV;OGfQEAaoO_TAO z4T;2)A+3N=nj$&EuZ6+RT2iWI;)UQ?s&HhZATnwE*A_?)kL3knpNLu3*_V(Xes^~f z>2X$-#5YdA1KE51aD-p)T^yco(@$l@TxkmX0|Z%xBj*oF-&kQ6Hl&$=jBhxiGJ5$3 zgMzwHS5pMTFGY^gR|(Hg???HWliV0qkdS-xM8#K>3ZI)SN=I(nTB$cR~p z2<5=ra=7z-i(CS_0am#LZz@J9K`X7j@WDqZcofi{!B>EQ<+*}&-RMB zAo^As6vIDv&;$({TN;R_p9uqyO;pZ5_m765Y&BtO)LOd%M89!gzWiwl@$X(<3RkV~ z*P~)zCUkfg&xGpgjPdnA0+z90=Wdp4du1Pwv#W^g$pEU*t#o-r{>9be9*K08m* z9ofj321{e&ijmR}#p(XeWIrB+tPkV{8V6e8%W3o(z{3&L@?%XeNo$4_Wj3ekMDpw( z*Wwy^Vi(gVeOAi{wvA`dQyyA=9)8OSDZ=eAg*tl)m;9W7#v$SgbW{?MnqvH=`0yO3 zo-+kle@54>aljmYk`u6(J&Nz^l762b%Nt^n^pM*89A?xpS* zaQ!(wn!PTV2g7sXl-*?l=NKY|ugJ*wInFd6+I&c3yPA*Q`W5=uw-!?LvCUz$&#HZ|fA7koMRG?oL`#Vf+c*^Vh>CA-Z_; zu%9nXSj`z3zw+oUTMG4oxy4XJJ*^+c|m zm)oT-SBKJ?^&y+$et0 zyhDVWYNh7#Uh*(qZ-zZdxyfC?odB%>mT)?Lk@NCK=GSe@Pu&LWaUcCup28fZ{wjGE z734iymCYPgaZKEh3Er!Gc#EYCo+SvMix}Hf_E>0;sPg|z*tbOd_6{M~U>FH7Q%<%K>mJvMO5lOm;K?TV- zCF@ho&{L=pvqTcJ4#Zdb>FtU6x=uY2pb<#UXgE3P+Szt4TuzN@|S)C{71ObXF@+5 z)eWKbV0CCM0+RHWch}%ZQVriJ1B&9>bYKu!d?4_tMZn7iX&=k#TNuu|R+s4}`W&p*MBx>Si#NmXhGPKFVU15Hj(kYF4=BfJqh zQcgv}9JM8XvdV6lVOdKe8mCoH%HSQFoMCDus&h90PuH7YGeA{t-F_h!tId;SvQ_Eg zO1_DRUT62|DlxrOoQ-dU61L#HJIN%*Qjba-j`-QR9i2eMP#4ZqKu$s~%m_bXA>&;JwV>xHn^XgY@JhcfDD5v>snDQrR&@)jP z(ZkV<`OLF>_d{y#yZ%T)L_0|P?39)ISVpu!I##N|=HLU|jS*PQ1e!}poOnn6r|SOc zsG*bDOj|x?!R9!FbCG57>gvR=gDQc#RIDRcsU7 z%$EGna{AG9(C5L!pJv59_b9?_r2oJKqQo)Lz`i3Y-tgfdX0Mc8E$#1(?^BZTU$8Zd zyaChctWqdgvKoX+fRu`N{!c-xL2URyH1Zrx#TRIsnxCys+DW9@R(Do&!4%s{>whiAS`rA`UQ*~b1uIA7x zT>g&EY)f+S7Xj3Y(m`Gmt#QG2QwItwYTfbxMn6)IJtB{Wcf<$W@I1fhcJ$1IgW7*| zd04^j8{X>|R%=RIOATMhr7mSn-~CIFduHtBYb#PxL`$%zy5<4Kycj>Q#hw^kJ|#*? zv3QcperIotO4;E1tPSmo%8#=;s)tAR=VOACYmUSwPP?RT;sZzaX9&RIU&7UdxW10~ z3G;GmU?bJ_b}|;ij(nV$PjR4<7O0RlDYv=53*RX%WD6mERX{HAjxf#K|CS|`?W@s} zqx??4H&~sj#XAgQ5p&?LPqb+j)`p%x>lQykatm`-UfM41cZhvIm47Sm#5! z9e4Q8OI25;sMCDMnPpW^q2T~o^DrR==D!uEJ7xJ!N)z82z$-LdO~Yx{#7*+LJ5o&| zCE^W(uxEKXyfD|MFuH9+{Xyx=!MS`b)m_v~iOQD|{JkFLMzxUlL;@2V!z)aF>BzKW zd18zT*`!FO6bl77X5cuPil%V)SdOhT-d!_uM9A#T5LWP|(<%i&;LCUa;!{MR557Uk zPjvOcj;cvZsLjhx`Oc(Z4V>aT5PBiSfhf$0@D6i4PS~*40qtkyDoFQvMc_PdT^>-+x}!0SoZ#-YgA8q3B{E8u>!lbS{EZ@mHr`} zM6PcFZ~Z`^VtQJ?Dih=Ju%8={I2l03SuRrNdR>Vn42Vs-FJ;ofBAO}rBy;6;?EqB~ z6b8pfB-WY}m-mgO0s>#hbw1b5auYzW_lRCuSC?|asRT`Wb&HE#@*PfJS+-1^K6%F6 zz@^T6LNlC<wQw!-Q zHNO{4KSsS)f0)4t=fvjj*wl53dJV8fisXjUwQAS?R?klSxv+`(2sQiU2FV#x-c0yv zg=Gg3+maRu>%Qezb?mrT(zEyS$HDLyvuPo9)euBR4!FE70=wAoyNl=Gm*%qfX3mSZ zto9W&kMN|lIycOQrwH`53Xu50*%;r~eN6pgubADQdMb3zu5LK1u3^DcnN}d}s)^0y zt>Z@eUC~1&ibZRS3q>x>EQ>>b15xt?!eB$1ncJjaNZFsxe=E9@56=lo7yhThbe;bT z%?jZ9gZ9e%%J!>T`ki4IE-k8ZFInw6GVgpme)i_g?fEK$EdmEOL$KXXB)fiKyL(l8 zy^m=pm;My&&2EP(ptG%cd#T5nd~cKW+{bF7?)WbUOH_+zr#GIq=!A1MX!7A~?xsDt$hEH7r;)aOfuFJSnAu5m>=IcLjJ*8G-8+!4r zuY$GR6}p9J_#&FsZMZcJ8CrfnYE@F}ExSNvMtjR~Vrd$LKj*FFw%} z_oMA5OU)po#rLA7XekaO&}V4(Q46An5%c7Z`=+jb6psnhM2Y4FDL}EXR!rC_u$h8K1G}A9dJ+|<0R>`ydJg2}KBQZ|;+$M+_ zfBiblH4$m zUW~(^x}ukku#4odf*+uD)v+Z9I12Tgf)kA5iYgs`w4QA#DYnE@4QGcp@MC#StWAB9T`7v)2 zq5f7hha<>d|J&QW+*F+_7kV3_s@&&aO$XC17GL*MRqI)W3S>jtGC_$1B@sIg01Dghz^`9DA5|+kEYd?|G$h~L7_k71AL1o33UAE zIm5nBpJrT^6g^ar0f!xyjdW+8wqtqXoJBEl>}sq&*1+aH#MuWK?xT?>KIO2sD~ zQY;E7H)Q@1z)1hFPot|_m=eYv``)4qV5utOZA&TSQ|b+kwOVATL~OYc-~kPQM@B{3 z$j0FQv@-K>S#;H*hl`L2EUe*a>ivGoj(Qq;TB!W}p4#tgx5y$b_!si(!$5tM>ZgqX zdnf*e3`Ra3u3K2&-2w59qNNv&?eyt6n$uZYngNbb#wgYWYB<5s#(V~+k{GqWoiLJX z+ObR4-e4IE3G`uUmoiLl9&n`l@TBF%uZ!(NqX8SCXwf12Qk`fpgdHd$XG}uSVS4f* z&#lGBBsRBeaR0J%%a1&5iU=annBHMeb3eKbuS7NWoqtk#Pb<}BFk6Bw*Q4L`4zQcp zhBkrRio2-Plu_7&&ziRF!{TaKOR8t@7pLY7=TlNyrp#%>7Vf0chE<`;@C-y;Cs|J708149#x`HpNAtq3FwApy2^=?n+5Pf3vymfSL^+SU1VLK+|Sx^HHAdMSdr0 zmOj?avsyDwINsd;zUAdIxvGMx;ToR~!Bh6UJoULMPxJeJa9(uj!TZVVlGiUaxVPSb zv7mcIT-PzQ58ndUZsNTx+kSlR<5nHE@Fz4l=9wCmR)b{sXGukJPTii6E+#bNB-j1L zlj|mWgwO!hE&>PgRmL0XXi%pT9nc62Wy(~CvYI8*v7@=%090CD$2Bw|q8jb`fk|tJ ziK+vS`;Cl?pDT5Ek9Y5i+0ahdCi%HH2o!Iy0m;~H>Qd~L-|aH`rHx$DwgoG1SW}@l z*F1#;+#d!`8)MqQUewJM8e_@Ei#{EyuFbTLT*6f zaagCVH!pb4iPug+Kfawh-6r}w7W*;pN`=-z87`X+((h~6x@)OxKcN;t6jb}BPKw+& zZ*=fAOTl(0KT}t?ia{XPHITgSM8L6?c1j4;(0&6hF_erOZ4*@DITT!iRIUvmas;xMR0dg{(kMjd8wGC z;}ZGT6*;jWT%<1g#NIL=_e@AvCShwze7moJ{Z8<$_+ZJF>7*+->svdEx<^04P;EHJ zkX~Gdh%+yyB_Y^lJjXM|Gv{g0I?O+LgIm5({*GdN|Abraw89`-1eEG_PC^=g z_fAcH4D!cJr^Cdm#=Ww+F}SZi-6(}{6`VW{pu#}N96sASNN1k z)DM3CM9teFX<#5e9w1K zKqN07utxeI_@7-W@7Xv&zc-QTfV)N7n+pgx<<8{euNy!p>+VY zhz^L+DPt)n`z2{AvwOpF5y1{$@+t5BKKl2*lmfS(pvDG~OsTi$lK#cx0;g)fWVhXr z(R`<~-lI51TU;+r#wSNK6P@(fCbD8d;(dnEcueN z&pq*9&Igp^Q%QgEInUp9cTx~`k^*<|J7?Su2eQble@_U-ZygyaOBq@*F#R1%IhxmcV;y*#{5f#F3X><5$)1B7`t|T|oCUZ+f?j);xkWbnPb}l$f$jBln zdFcpsk4RPbb)Zj?$8L`to(^fMJiSvYy>tDxAxG~cButGdO`n`#dKKP3F5X3)(!Vnv z&)yef`Rs}aX7h$4fmt9%1|EX2S!5<{;`^V-%eiwRoxnUZyGB{fBA zRX`M#IK%i@29XtddR=#}a@7+VOFJ9ayN13s;7W|WFd}rEUWy@pCD8G6Kt{kK+!`2i z-~v>Y%;ShQ5QOqDX4Dk@<3x!inR>v5-Z_wa_=8a3_#Nc2ZM%#Xib+qOIv`L8T^yQd zG!mmStk$Ki`&DDYJUKUO1o^}7{+~-^u}yAr2E?!q8_vzsYxE-Pv>7r3I=SkLllW-prbi2As{^fzbP@7bK=0OUEHpRh{sBkXs<$d+Os|Sqvu;` zWk!Z`HHGZwW*WTPl`rxn%XRIpiYzr=F*etuo4>3qXj zWB)uKY2wI! zvmLLZ)W8vVM@xNx0s}edm2lt}3rmb!lJuGnhlAW+p?f9Ru;F&|tS(M-I@_tQC6ax<$=E!XCzRS!R9ky$z zBTg%EGKIZ|-0688bdQIOU`kbTqt#@mwo2N*R|l1reImEEYoo{{7DZhj<$9^tZ@Azo@lVt_2FDf6ao=D? z(%h7^?@vqI7C0p}PcCF<>#LHR(U4+tG0Q0~S?vkQspq^*(-wu?;X}x#)2^C=s{OGq zaRd)2;&J%mH26P&K;SG}5U>I6AZGDmD`FwbIeRLi)XY&;{mp~QfHAM{E&~frnUdPK zOs`AXSwF~_n%7fQyJs-YRfk!qf7DIK94=sz?`Q|V;E@wH@3d;^i9g8F34WfX0@2Y2quLX ztZ@K|V+~0a{l~uNkLt{8Z)lsJnc6O!s2$c4&Rhe3QF$LuhX3_Af3GAt$P%BJKqh`c z{TlA+@P6|9>bTQ&a${i!

0!&Z=fq!4<4}F?xB%KIP2ekkMKv&;rN@@BT63ht8>Qkd?nx`Q%FA3j zb^?joQ(b4SiVtr7o27JK*o`A4%AZa8R|>NY*hx2C1HlPOpmX!#s*EPyhTiJmnA=Ez zwq&ah^!(cJY{7*e=^&pHH00%Os1NhlbI{hTV0&r}UxEI`DWUgh$@-6oviQ>slI$T| z_jBj@my#8&i8^yN5Ulw*k}HSIcC>&jTP*nE+N02wzYnQVCUVWOehP4yPZ*%W!|YBb zJ#eA1pZkeX=i$*5Z!(s=6HlaH@Ev{q*G)r1kj1hb3NVN7J}(}v`2k8qAAbc9^^QDVV-gN5>rRX zBqCNf?DpOUOTraH>ZGC41z1Zw894WRylCD&ZZSE}A*9;m+1Ju$u$ME6q#FXWW7o0Q zoFAj5BTT;^WgR=u>p;FqytkQ`>6rJvO)pid82gK+6S0rKbqsjGw)|`RBTr8ny=h+k9-?*ssEFIxL7-DH&ex72V!(jVFZxVu|iSh z4LN@##2YA0@g2CpKe~%l{{Z+zCj)sz`g{>+2k&zw&c-bAd$pN+&J&kuLwp1J2UuE} z9?rYp(r+>nE<_QRalPEx(eBY2v5g%ygPF^xe+QO#*m<0&p`yN*b+rAV+so`iUnAk4 zz zUrRL2_fKeOdHS`o@G?jN#G}h1AY0KwhQq+euGepV_dU;;a`uMyJ(J7Et%sZh4ux_q zNFTVG{U~UzKlpi!c8aKu=ozDDo*R=jtjDrNwU@Z-I;MdS@gt{qRRCp7f2>S4R=tS6 z!L;)9mgTJ^Ou%pE@vp6sWycX;8OUqD3uDm23!r?x2{Hz!ZpejTDDgg<^sJ58X824|Iy8Jf-F<%*hEIN}bFFZ+>xKQ3PusBl7q_ihbJ7m`pLUVr?y@2{@%rH@ znW%B=qeq_}PKXxq^%3d6LQ3kenHuZljF)%hwiOHANrUdZWYaV%gCQ_kj}2w8|Jnl$ zeyH;$^K~w(xpBWqE9gj*oes*Jy}B&UA8;=n&%yhYzqcYzTAH!a`5|UX9w}S+Ox%oZ zi_sic+Ft4S2Y6v42vKzZufU5;9kOU!^l;k2;UM>#>GwAUbG3p_eFo_NnL4=0yTBSM zRa8=<)wwmsRfC)>$av}y@9P#ko2APmj^n!c`LXLS!#K1|BP-{STAXlEQ_|&inO*l? zL_W@gwd(FFg{4X)n&%72>EI2tmMHCD2gbnCG76dgWIssAZF6{2^$J4oy+!8wDn$j) zGuZx~(a-?157kMlHzFGVU=uVbE13AgN~p>YHjfgkESlYzU|uMkr$-qirwMekPC<^d ze8BI_MTsoysk7ta*49(lLe(8wX02M$eBZ5c1z3sBIGY}#8FQ;{x9z)kHxnBu+Llqm+1=|iyeG0uG8Mgeq4lkSLygr1fH+yN{>)t=Fy-q-QYF*AV~T!ew5>i3 zuiXya^i>$&BS}@}t~=MblNKqrtAP_SpF(i)%g;SM7wlj7IeA0k*(DgX`<9HIAzi}7 z*0!ezVlh$D{Y1`Is)Rs-@0UZEoZt#i>$8e!p385VuIs2wMCcD{kD5jR2><^B>+#^? zco*s?_E92AcaqADH}Ec50I@*kAMt02H#yB%E#^<~_iQyQyo)J{A~0BY zM~Mc7V5c?4UUgWlLVJ?hT5C`$DB6K|t0P2-HB@HauST=BiWQ615*5tR3-V96%~;6F%=iVh-S z_}7ok2tN1-3t5-^J$k}=&0OiLWBqSo`*#1xg9`_F7G)Xl*Lc=wNnTz}dXITi zGjH)9+>%tgQum2OI@x5F!%@|XZLtsd}(;&g_$uM+GyOHSvETVB~^>;93af+1o-SRsu zg#z8L1f1zeJn-e18P4bJeGrwa(iK_?Z$WxowRp?5%uqQux`JNGWHtjnQKsWSufH}~ z)y6cb8^;grNHp-av);KggaBo@^NQgYWw5%7>)m_h8J$h=*RH4Zwq*PK-My3N zQfmyIOPa9|i%YG0Zp{|E;s1Ob?btXF9YON`pB$EIO?~Z=KA8QvMWkvCz|EOqf@h+l zZq4z^ax7j_sBH~#jzQ#OhBWeM;M+aTvrQk0e(oUa78CCmP(CHA9U^lpmf-(FwS&8Z zRLnsO4HR4f((IH9I0>3YCd>FL=?n5fK8-u^*wak+_j6XhuZ^~{a7L5AFH}#98=fNJ zz|c56#e`pAc)++NEsgR%;K@Q|F2v9VCQtLJn)RX083SePlBKcVUdBhDsM1|}S$y}{ zFl>1B7&z{nBXmN9#`b>-Iu2RgD60EwvFMkt>Ph@J1X|3a9AssUo8K8&xZ`qxH)K1ZR{F5P& zvdfx@xV=fj61T~!hH@vyFINOp6%YuV`C@gTTFH4@LF8gRYiWhx5vjA$7iDiwd16ga ztZ_y@IqDfD61(o|p1mDM6*7_NSCQM$t-Z8^QAiT2G_;n~$}`R#dsR4)6J);vlKS%G zz4?5ivxwq}D(2d{7GSEo`$sBOtX?238W9xABRgIsm&&N-l zHhAPUw-Ce+4maUT6X`z#CBGhwTn#n3L)EV_oejP(nda6&`H?4JE3#>0B!1}mcH788 zama2@h7NVYVp`0?np z8KU=}QTODmP&IrWJ=uiW3L)i33ogZ9iyo~+3D zq?3~Qq17wk*m{fJ)`yhzj3{Z&JL)3a&BS#hC;bWasYV)k;Kq-a&HZ4d_T^`BZH}br zPWX4nqMnX{x?UwpM*pC`21ErEXIsi&Z&~dX z@DgNGMKcuD!(8n(RSoKS)$^0xn&(D_JolO;SzHO4h*jV^Sb3hG4RP)UM5p&lsWj)v z=?j^CK7I3}=jMTraH!*TvgWK?e}B%x?08XKYstj}s-xgodf%NP=X@iRw56AqhQ=_F z)#I^3l1&)CObeFa=EIj0dE(HsV9RYYCpT!g=Y;?IW;0C`y2D|H9~b(5^xKsib5Q5# zO^%9_R(~g_WIU~Sjm*bOv^Ua@Ul!g>GxtawdAQJH#Pc?9&dTu<*bF+YeU1o3u^58p znkB}0*CUKPV>)K$uBMt#bf%j7Nwd3e5{XZr_P`V=E&J@}I0%w0D+m2__?ABPOUPU90zHxCM~*j)sryvwoA@#bSI$n{U;5hciu$^fL`e@fn^yOrlxGCX0BlT%{kA-*R%L< z?cS$-rRd8yf9IIX)gN4SeP>>2h-Z~A=fXB0kRV#$2Yih2caUB7(W+l=P@%Bg#rX36 z`=O0c(8F2mT!hGT_72?>b!}wvWCC6{O8PSKSGPjT{jUc~(gVbPp_-yKcpvYF1*UoZ z$yGwtSo98y+iC_ld9Q<)TW81_8sD;AAZ+gID3xPTR5e@f5Dp1J{|GYhOaccM&u^)e z_E}6d%F{DVBKQhl1BLhWEzsVt71)v*Qr|hrX%rV(exC%8jp|#)E|( z3;b-YS5ej7_&5{K?UfOR=O*yoyT;%`y2h*u#4OSLD1_mVeQ7PoA{GVcs26JIkn1zSsuFX<8Y|{1uO){yhU50UL)q zBGN`h4GgzqG@;hu%D-dih#xv7-~^~Q1MC~d5OALs<^oufGnd4YWA#s*$Z6Zbb2xxU z@O0SGW0;~DN10#mwEYYunY=BAxu)=+Lt@>okgqzxcjExFF^Us)YTVD851=KCDw zNR$5H&CTM-^?`JWiWrqE_5+ge@s|O-TJ}of}bcgu7O!NJH0bZF0 zgwwwjy2a%g^N?MB=aKXamOQOu=<`-LbE;)^DMhiwPLSbkS*aoH5^@5eU_`5_5$Zc< zza>sS;(I{xAaewZdKrkDo;N+Khc-}e0quun@~t9jmYUQ}?T)_yPpIsPEHPlBvL-P! zup&EbCgF8f(0FLxfBaY@i3+8bx#Lg~;#kko@X5aahlgrXQ-!kF$1SA9AF9OEGUT zTp7;gw66VdD#^zlP@)!hRt<|BYvqSi$$3 znzKv92PT#m$w!$cm=n1bC4MGYo`{ux2)KuXX6m4>UsiIcWfu5|ctjPeNSoKPvva$O z5Vf%Ekvt{HYuBu{$IIT&X1qUZb12}jk7@LAIom(Qm{1HXg1YKL0|LhQUY^B)yPCbz zjYlS7=X>N?&ZZr*23+=!2+?HEWEqS%?*$a=}yN+R&EMc2sthTX~ zE2P}sW6IiayLI0&Cnw*)V(w-rYPj*6Sznojut^XZpzhkU8!@i&ylx7rJ@d~(Q=|QK zK-rjX2=Dt?VOv+JJY#h#rC0NL^?_ZNgu(K5Dfj(UO9qU{%^1E{ndQm7afg&&)A}BN zc(OY13aqVGk>vHZTY-pTK~WypcJRJq;2VMCI2+1gqa=?bTE~CJrTL&4#}O7=CRw{} zN=XY`9VdaV);udmOW@v({mfYGww`Hp2TY>*Y4@^@J+(erZ>j3PKPeiq^IsSWFj?MC z!vggv?#AMS;;Oq~HUHLhrj8%Q1$(rpcv-_&w=q-NjLw7IUpFFVehZ-LB#;-#jF<`| z>tIsrDH9O5S%=191&`6>{qeaA>vZq;-B7;= zA_r^PLDZ942RL3kht0|u$^tE7gt~KVu@0<)|3K|b^2`;9%ZN?f%-pPU1CGZ3K%x3j z?Nn$nDgdEEVh2^lvKoDjF^LLp+Aiw8G;}2t$W#H+rv>CS3r=Q!HmX9}t|)UQglt~k zRr2@sKTDT)zCo`R4!wsm7qd(_r5g(0kHxjJ#&WmPq~wh z3Q^`KuL1OF=pH+s9nS-Uz~jLSOS3m|8U=W8jE~2OShyRuvKmO4=Cyj=Sd7~SUX;Oh zbbW#U{)^bw$79I51_%1jiJvbiFp3+HLe#}`vEP#<)8;UtzE(HqmJ26GccO~k0Z1b% zz*fl(U^1up7A$g%%t;xK#k^vq{mzUS;*F;tNU*9C9%)t?8HpdRklOGY-l=k+McNcH zunW!(Reg}>lJ9@nA|5Wy?i=HhKap$OP*Cq>sZ)Rn-370Ajh@MXp)uZzyX&xThedD? zXVx)au&(u+NPf9`f~S=LgT@o*A4x+B<5wttXM%%6#iC#%U*rSy zoGgo6^|tf3^yC0#I(x(Gi3hD?t9Zt-_?gdAr4zR-2O^q@5bV6N;dh0#c)mvVpHIF( zezj`P(~6WKJ^B42Zy=u>51(B7^Z=mJd4*Kmo1SPdLun@G-9#d8X|vn=abA1_s&3ZI0yZ zz;CzsM(g0;+7QcI`%RutR~sn#Ks@U7+*_il-P8zC<)_>8jR#O3qU!^IyWhv;vVveG|01J^a|qE6-sFCqUXsYx1c)!7W6b~O4uBqtVNn3 z*M93(9tzVIFluh*&Vlk!_3~B(viCo#zbIGo2UMRo+s%iAvmDnb zbiH0>BGU8!qJq({e|ive3|-Fm&*M4=_XnDgb#FcDmo2~n1iGlrcmtY1}P-D*BdmIJ%5Nxdf<*Z3CfK+Nh~J) zpQ#mNTmyULcd4tA0_X@bj)6mInq) z25qh>&LrTA7)o|MC#g49yHxoXrs)!L!6DH`m9UI00Iui3qoh(aAUh9<1skX*|BE>y zit)yGlirVFrWoAlXcp+Llc6YbE>is=;;GB|U!J-Mt;gE(#&{iM7>g{kxY1{I%~2)K z&-Nc&Ixx|LG7~?62EbAU4ceKnS1nxY7sgZbF_QjwTD{w~10i5E0;0OP88|8uXvcS{l zY%~I$+8plB{3v6*GkO&pFaM4^z3xqTrb(&PqubXK&aRkVF0U1VrRxv&%(g%j7F042 zyU}BUd;qLuRjDK|o^?y3msKO>n)fijcSUUyyt_0+Z!aFs#)7cG+Q?G)|8#gWjUIW* zX$jK@0z~XOYIG{eRL&)pj67VHsNKd>&2Xl0KP8^?(F(YoY_DC0|A&AI2I#+DT=>HD zH6*>^1cD#D3$=?jsV+HM?-(18P;P{pP&IPtZvR8$2(!~$@6Y-O;6`#R96gZO>c|sC zw6p@he>eA7kh(Tagz_=@%YBXOm9G%Df;}<<|BEN~nr17O1=ovs)C;a8L`X>bM(Q0C zE09dnLT^b(GC>(!THseMbk%>P*cm7GUX%HeY7a0n{wON4sY2w)v zrdf%QO={J51+d3!rxSb4gLRZ zazyTNFUHdFbxwj3Z~FI${l~;;l3j}!Ec@{zc%g|M97DH$jT4GEIEJ|Dbm3*Kdsmcd z$YUx6Z)g#Zqp$rx*K14CB$_ua^7OkHU7Fs=tk8%1QHEK8Ht%BfGx90J z0wy<7gH;yGnft(S)c=M%vjZ8S@VwWo9x(xx0lrHJCPG>=Jjqmwhb^g9nn&w%$enJK z0^^7Q<=EY;$*o_ZHJ-~dlLwl+=+b|CIaq#3`7AOu>Pc$#mi(Ff#N<(o6}l#dE+!dh za6>&*`L+XfM{I-M?95a6oZAon?dPP`6&M)(<}}Q8oS*yfZHynaAi-c3KQMNNM`(P; z`AWhNglv@De+%#Xjz{oG|3$(4kGcI{Pi65zf~Www;lk|&lZSATHSzR?#-jSOJnIh= z<|QSw+?wv6yLtBqr$G8E_4p{C8Q5eAXAPuDj=3NU!@|(FR=6!-pHpL;QVKONBJ-qQ z|Ep^$c2jaJ04-mOIYHW+E@D*l6i(P~SuKAa5C4&g`tqJV?w@fSjGW<0IsP>&qs|%? zWF`#lykOD(EP!Fa%b0G00YVfCBbFs7}<;7?~{J=V>8!y=dx=)hlgrX#1@arbK zA!8QQKi$V@YQq1vq2hH{Ys)GNqh^^8>iLl)J8Jl}f%;Hk17f0iLzz@nF)Q4mX>8tAy(-D{HQ7` zKcR&*fVTX4_Vw$^m^!{};t1Q#jG3Uyk=s=L$`0BpROIoV4JwLi~Q_O($lA zdwq?V4mm~sS~IOPD#-g&E(O#beb2nOKx}&S*s*BPokMyPURjw-OG~S-HasLaEG+B< z{CtLjdsJ!?KwMLn?dj9pR&QzA@}5by}%AY;+dEq-~ zo0pg8oDM&)U~{(G-`{`q!-o(3JUl#uFzR}}yu6+~f+28&on1nVe_{>Yxm6t#53Bb7)Q2VcyK|Y2!kb4wFRXs59fWnC7qek zI=z7xFLp{h`XGlyrcs>J$Q?H&kC=zwY<%-#?MG zC@wK=^$FM?&jKTg!NZ~eH`bYvoqZ~W4O~%lh>S_Led6p?3#sO+ z5kUifL(+i!ATN}-V%ed<_z>cdcfz$b0Q(@j&izeN!TkJuS5;M&27pJCf$FJ;rnfFC zO5zzW%hG+>OMvI`<7ZJ((J)kzq+()X8i5k})a%_16|t+tiG(hwjt(v2*o#1?zB2+g za(1sHE{+5J_#t%ecil`&TRdcG*(C?@lnbceN@)Wg1MQFalzO(A%Ggv-ppEFgXldN< z+_F+-M)-w~GwI%KZEaRb$;mBo@$vC_=RcZhz=l2S9q4uSd&hfhXBui?hp1#%*}s97vhJXCYOq%H*bkxQ$W4V?Ls!ib}vSph645e;-B;ape$P*b-nd1K;VPN29N$ zDBl4%4rf5KJ=W!-h&5FZX{=(CV#UNN{fi9)hDhTVc&-Itb^2N#s2?;Hu zlzvTVYuln3Y4o(Isi{NoNM)(<@g^2G2q-=|^1M1&!x+wGPk;3~dGe^`qe$T71_G&N zxdZZOT);i$a|v=>L>LtJ*SROt3iq(>i9T^Hf#k}U=E~joS8fg&^>8mU`1ts?E4@1N zc1%u8G$1iP&(0s_G&;aNWc-{ooU@Z?R@Gm=ZYWAo8DDfNeg z*>{KQK7N{;3FYy}M@@kZ=l#3(cJ0eB#=rDBhx=Yv>(u=ebxQlK^r@2<;fT#{Wn~r9 z*w}b^7`z-x3=7&#=4>pSvzQzSMzSovp59g~HE2Xa=N=lnr1oOf(Bl1YE7#nadEAlL zAwPe8d*;hVxf8ZBqf$~-@tcQv zE^i)snGzNi$xaq%dpWp`kDs}GR^;K18fCMKu4iKWC?AEY4f_>#ub{xS+xNwA9H?~m zmVZz?PjNs4Px$pma7|0d%6@$aifJE)&2K%4+NS8uL-+Y;X1*h)#P?bZ=|@#C*wJGr}TYsLgK1C?l9&@V~Op3ZQrvvnXh$ zeF*^99lD;Ew{B?s%wx`xa4S#kkB>D2g8b&wA7f8^)oU2-a@G`#TQ5~GTW ziXce3M%3W-8UWGVlc3JL{SKG!{OxK$C=OraMEvBhBqZ3utba*}@@}W5VYL1ZrsKhq z+zBuHBM3{|)#%lI0f)&{EiB%mtXYUf(n9Jul%8^qDUQpkwF;U$NKg z)G5_L^Fsn`P$jYdl|W)ZUM%`8xliz73CrN?3&f3}>$Euy)c5UmP~;qUf&O9Pm5gqb zv&74X+w2+!7*)t;>MhK3M}2V8Sy7fZpwEYHpqYcuh0-1Y&1qPK$;N z1^ilFg4jNS-w+Y9v^t1!^+FdnH`kXx04?KhM>uq8Q#Jtmrac5l@aB;31E06$7Te_V zJ^fXof5Zf`uqwbh1i_>)0@{|n=-BLe2Zz^i{Lq10Bi4nyz$V;=ANvr6-d`w9!? z1G|r!2)Q#QKXi5d90_0SYXoS3Zv7J7XHno}$bNN9BZmZ`bi3}~zn}Bcvn}IBcI&0F zQdiQ^9{?^lIeL@_%m)FMv?0iClUNBbfMkygMh6cHcdE7Uh&Q@M%hCKB4(xoCY~TgQ z3X;A%bV6X?dv&SNKw=4M@Nbaps!^@I)(|z+3n`$<5(K;0NzsAhlikTLV|V@GG-IvA@AWphprZ>{ zClql=>6e??@q6(a{UCeha3;beE14Z#4UAb?3*p=>=CZy=7aGI{x0{~}TWoBi~ z{{#NlmO;6eJjcdQ9>W4y#}<)PL(%-1TXeR_3l}QK-*^bH)A+TuKD?-qxf@qp7D`94 z;_@tjk~iAvm?{{NT?df#$b1KJgVNr$id*mZZvjzC;g*^g`GmfH{ZR%@jkT~}H064_ ziEHo)p3{fnZdKeJv37tZ)DcEJA#vr$aQHa5t5PGNjlMPSvtxeHmM$1bE~{1~2mF)e zQ%b5IgUqSnY3FlMUn`lzxc%o0AmHKk=j{zYqHxK^bDrC(jSX}g=&?8ljcY6CE zYWit#(cY(R+DOJm^ZtY6U$8V>xxG3=fz8{^=;&xa=Vzx5TO3McRxeYCM&&1$I=z~B zBj}=TRQD1c181-E-@4oSj*+fPu!p|;LEmG>sr*w#4YL#3o|U)h6FS|N_T zt+lDD8~y3(FMuWTjJ5A_X#!h_FNV|cS_!v47wbcHX`G!3Hgq1S$5%obR|O-Jg!s8r z_pjP{dV1pi&|t^seYUtPNhcchf!`FB|vvZ{*lF@8f3}jcSoPuwXmB8voK=P5 zI$kmbNAjFzM(%Ai*_sdT?KfEH8Hfqtu3Go+%8?@9yq1aLb9j9^s5o_ZkP?Tl84x;{ zQx9yM_Wz=-t2=Z^ND_L)Q0~W$b_}jG_Yh|p${;}S zwueDSqTHI~Gk+1rHw=H+&p12hsoWoX@WN(@2dl)zlq5^*9y}B&&Y~NaCp1)EKjsU0 z)ckn)0YWxYEeDR8Uiy)?;sQGie0X!xm{CFi-VS#pYWpkuZe!jpaZ%Bl&LO1PhB?r- z8gzSWBz!?=Ng-7CNoH>D%U#MnhYwWTid~WmJ=Y}?i`vD?DSCQk|BEMGR@4BIz7Pa} zNEInv4a_j*ViIrc>}TEF_oArFmnKPeb1MwEOc;~7Omw?*80Mbm!Fy_-g?g7AF*WT& zLPN9Qi266cBXoA)ic{QL2V!q(lxlMh)e97Lb3K;251f<(Aqzo=c;wbr_TD@9mh#1o zu0oZ>w21rhl-C5~UQnK5?doi3H8S-br|1-vadma|i!Wcl9{7lJ;i{|qq&u=v7hf{x z4-07}iF7$)&_Ma&70EGX#^*HV2Nf99xzZw88JWo7t@Y_$sxUHV;!;AcxY6;^H2R6m zg*Y_R>x56k*Y(>=!SDX}fm@kAxpa;XOZ4{VkUl8ro`hYM|Ax#O46a$fpl#{z!hgQh zA}~0g&;6ml>U*=8VVO}FnbV*4ivNMUy7^u*xnVuQpV9B|=|?7UOZ+pD1R&8>oEyF5 zl1+WN(fGNMZbKL|qD3V}bqrRPBteA?B3)(otbCK zFFE@q^Tv&;C&oiB8^dGu*|kOp4va0kQn@bFKRHlO5ywRAokbZbqfhC&zGL*WDr1jT zxO6J9BuWxTke`GNkBy_F<2(5j8|NyHM~7M)>B)p(1)kH7(JL)4p07R{kYRL2&QNbj zB2_d&=9og*PP&jrR`R=}xiJc!vT;*qqy&lF%@8S?`wbCFKkCloqwjH_-g_jxdqs z=bp)NyVi_mVkfLvxQ?^$ePX`wXkt;{NMq0KM->Dl2ULLs~!II-mjkE~3>S1EY zSS*9{ALMM=6*jymUgX7}AMU4ro0a2*M)j%SakZNn8SZBt+`UZ+t^-!DEbG4?>j@p_ z@`F9{9>?myFQ4GB-h1)sB{mjk>it8BBp;aqz1NSQdwt%^v#5$<1}O#7AeHlB)xRY}jN@1@${WwdxmT_jFBNsIsN*ST@tn5Hyo`%VSOc z4@C0PdQodz!_%Z*PYb?qC|ic7bxIvFjE>sPntG_>txN19V5^l&>F9(@Q^bDt=?gxI z*DZqrA8Xn9dzcCv#*N8A+i>UaJ5gLv0zf&nRwwx|w+H6Bj=}Tex;awRcnc2+#LcJn zI#fOq8E&*;j3IeA@Cx%`asEq45@r*Yg)+I^HuGck{B?eHV$SV-tiugC+8N$oi2Wt| z*xoQ4FtIJ9H?rxxQDWB~%GO_Mf;X{mh!%BKB4_1VPk5Sdygsqs~TKSQO)9lN` z47gvJ0bb%|J6PdBI*4qN#QD!#GhU@bDJKcwXwSkK2n`Br948D=QUf1llK)V26Aw$& z;}`vyPAD<%A=5>ai}(0dC_;t!^hHK^HEfz88bBD;OO$wlW_p>S4R>;wCbEOUq@JSx z^G0d%?s8g%|7Gpr+d|)OJuIN* zI($9zAWMtKeYh+rA9g~?m+gyP32!L+)Vmu;b8>UdxuVZ8SbX`RXeICJapOXCIH5vD zV)3Qz&Sc6R4@Tf)r<#M$kwh3z~C$hBLz$YWzfXGPoF5f=4#47`)sjjGw_*_x&g3<9yP zQ})B{!tHhnaKfBZW7wLKq+Z}7b%Y3fAQIt=QIm^ zebS4Fm-0dRYF4%Zo$A9mw|44Y8DxWT4Nqft(fPNh3SCLcOb2tk#xzPdpOr;gFtzxy z21k;wpJQ1M;#g^BIJY9{n(FTt(Q zXkW@8P^n1CJZbS!gZF|M?DRRlxQ%IQPVXXu-J%wb;+r1NdFks68-u!7a}+`Hshl`V z$GHk67&(hN@U1T`Fbd%rqx6wo&WQU#m46K2qI1|&U*VQxvwG|psy5I}EEhZ;5Ss6MV(3LO%b}dXu@qSR1gT@#6F?FHb(#`FKEF2&QawTE{^BU0n~LK;xe>&gv3?#qW#=7rNw zsP~UQUKF+6k+(iYm;7UBV4*xbLU5(ATx#hKx8S*Pcnccr}(nEMkbSc{X~t2L4aZZ5F2PfQKxT zwpA<^9-P5`bFMm7`*PiP)DmWl>l>^+ErOc&;1HWl$nlSvF_P_2yr^Bk^*Z$AResnK z>%0@%*g(pt;Zmp}uxLv-DRtuf_de!=5~>8r<0%G@ICP!Cte!uB7U# zHLd#n^K<@Tf{2c%!Arp?}++{m_I-Bq6GFw;Xs|(%TmTiw`G|9x_0<|MpvJ2!2;6P zVBp1`=Su*It1%@y%7ImLsUUl3$FLEf!@T;rYG)|-{_TfC)EEssBC27PCU0N`tCvt! zsH9{P;)j@8j6}%+P2_sU-7j|nKf8Y z-Wg^e@JjGmP?2TT5JJ z@*pISrw=zf%PSr;0!AfQici4pBRY>7=KLeZtD4=f7_SsfJ|iE^iB-@SD$8~lLy$pI zBOI|Nd4E8}T?q2DIC;9SA2#&R)n^F4iP+0mPgy+znlLXixr0CMGpbCCer~UrDHorw z+3Ej_y|<2va$Up5-wB59?otT>2apg+5eozq2?-q#>68%3p+p5SQ0Y_=DG?En96&-r zKv6_;6h%6u1>tv(d!Mt<*}wg*^?m;z7sCQw&OGlE_jAW}U)Qr6^?Y*ZI#CD;RIL3> zS)KeSF}8JLpgtbK%Rv43(wQ@75~wf^?j=uJd>Y@p+DC-~_i{0!Ae<61QeSzz#Dm=a zv5@X}HJS0*pBCX=@~q5+718BdTtoCyRUk>Dn*k1vTB zvdm!5putIG1lTnIl5Y6*t5=tJkw}XRZe;(RoKW^)otFa3tJz!-8>>AfN_K6?TE6KL zs$T=n1l3GCWz$m{qqY_f&0N0POJ5Am`cV~(jY6#hgzgKs-xTr&H&k#}t^atq21TDw z5^cu*77QAUOmh2l@ZoIDfUR2DOI~*LU&FZl2 zE%RcFr#U(w6I(Lm>2S*$&j4|}B0}fgI~f*I`&pW&dpWaUIqj=Y9NE66xCnin76+(V zyj`=`hmm9MuAfM+G%A?!v7JCKdwta6No}P#Pj~y(4C*DK7pK5**mlVMSt#j;K$a(m zQtO-dx2uH+W6)43baU+;{82=mN);2s2+zK?k)u?W>nI`W$0*47u%N=&DuuOi2=1y& z!8Zb;<)x6C39^fr zD%OE>0`n=d0mPnk%VLd}mbg%n9X){1B=w8gkLX>E_$=dDovo0Lr6|_8KVbDhUDMrLjZs9cMv1|IIClH zY`QFTt=J^r%bOi_c780HwQ$;=f&E_Wp1MAkHA#+=N;;gsRb}nfbBvilLBPP^dbdTL zp>n6~mzP&tqS8Kj@Z2Xx53oq$UN$$+RCBc|T+3Qn+Xcy^doieJL%OV$lbJE78`n3A?Fb*95*RNHOH|i1_+MJ1w5Yof#CX3el9L8r+BPK^cAUS#?ss{LDcndZd z`kXjD5^~6Gaav~Hhw_eR_6 zG!yegNW2#;fkPwry0bIGV<42|{du=al|>AA0#}IUP#vA8I|P8WgQRS@UN+y#--0k= zL;%#MHGrA*y5aTZL=Ankc|(#PanA>9XX~1Pg}S9^4tgFfqBAG2RN4SL1)6?N>DFUZ zkqj+^A*4UKs>a`iB=Yj`unw^?1PB^3Oh@|-U{X$xyfAdAJkWL()pJUryB~=Bt`i&z z6W(^NYpk03=wnUPdrb%3WA|Vq!LhBNR4P0Bpkiw(S6-x`7uix}0F}yC?Cpev5!emt z3-Isp{+x__K`oLzdzU&C`pAIj_Yi1uj2~9!;Co>j-sKE-&3t_#`XxsmJX6cPaM0#$ zpgHDZlrR}j&=%>igQV6d*RyI1DT|2^d(IXsTWgd@c1gMRi`_h4Y3J?<<1RgX!$DQ4 zboHE2g>c`q9eoLm@^vUGI^3ng-9=w&SBI+|SEfG&0kNyDDdfNp zX6eDyINAkrgoaS&KzJbTucJ0CEr1emyaR9fflE(p{m+&x8HSn zpU)Ui0@iT0s4>weqcwnOrGq)6ym=s^;iyFVsglrNKViZccDH3K$@kf|$j|qT-gg;5 z!VLjo*7e~%NPK{Nv}7Re^uuh&xCGC@rM)X13f)qz=oYc84b5mIo|%J95{FMfF!vQw z5fdhbSy~Lu$(qr90x{#wzP+a%c^fe%HI~gbkn{6VC-XGR6NQ)-;MYJmm62c{ zZxKAS%Km)pT=V4+o?Zv5{Khg73jEKP)CD zc3IB465p?>Gp`n6Q=)^0o{HV#x!i!VD|*w`R@vl_H)o~iEj&r1mqkUhM3H`WkB*M+ zIRhyDmAEfYzG$IGTW{>ygqqe5|CxTj1X*{nbIEwC*B2e`VYhknQYgWv09a@D;`R>& zRwol!*!M$2F*_wB&c1*M*7*k1HNM61Dyo$|u5LtKw*ipPFsR^_h8#H17z<(;!JQ6l z5>#=-;z}x}@kh$`2ezR?;|;L93Zrzj=PN*?>$6|mh2QRLPwqQ?3d_Jw04-V7f=qff zu`P+}IbxQ2F4AbGyP4wAlkNhVWQZM%VNo(=76MmgTllf_PuJhtB8PVE*fFRaFi&m+ zg+hhPv*prtJGE6N_2phXm`O7apHnW*cWFlY}$^H=jYo zi#cgxvj0NtjcaqX)|bBBZSI1;jw45ow4H;5Q>?qvNtrzP3Q;_ge+|qCO_?gpiEO+z z=Qa3Q1bz-9jfDm{93f+u{SjdlLGyVMlfDdN0?x)?i<&_1Z||CSEqEJx zOb@~w)<1_2Znf?|_%w^8r|rb}#*7~wiHuuPCT~`Jj-?XtJ<<+c z88+;^yz8SYGXuhYuQEG7=x)h6+z#AbnS4>Y7Z7vK*e?hJwmTc#IdfRGsSf=;wPjx^ zQsu2tQBk=zCmd%EQ~JxBq2_<`4nUSD0o1jaxZ{L9OEPVV#614Pu%@)IrBt)I?IU4c zpU@cN32OP&Z;tY|s$UFqN~msCUaq{C*W|&!`g$OdPD;QHH(&YU8Yh}u0%djz8jh** z=VXCvG3>amZpbrJdtEtbz{{ zBSiHg(zLoKx2)?PYqp@7LL^Ze@IS-6ihKPisgl^W%TP{6M%@_zY@8GTo5cB3PMcgnjloah z4l8~C{=GkR%C@z2bbL*kzuTTH@DcWj`_cLoURJ*P%6M?SSi-qP0H#DGQb0%X%Dj;9 z;<0O-=1(k=%5R*ga73+jIGn{2LlL#)Ous2u<0uHX*#RWj57@9;3WPzpWpG@&o}C;; zhBEfxBDCe0jeYxO>ObE7c@&ssYu)v)I%M0q?2XmX*v~^Y*2AV563^jUqYj!FFaU3t znz(|(j}CZK4~XINtAK(0KHzM}mi)_-LV{MN8{pPEvp;NWGv~SM$IH#Ftzpk0U!!td zp7en!kQ09fRZI87vg3&94vL550ehajOHyzb4fl<+-rx&5U;Ug2J=)La_NgzJU=tSqB`+-H_4o zR8&+Pp`H&B+#!>l#X~Z4*K)F2J+|A$J!#)AKY`+Sh3JdEt|tk@TU&D=fwD47Kkf;(z}B56DMKK#BT{M(h6FJH35 zLAVUa*9xuAQSA9(xjN$EdN>3iBaO;nf&d^-DT?s6pBtl_^%Lb7ho3nbL7MF4B*0N} zA8+Pnn0Xx_6;WF&*&8?IkerGNIl^(YzW7!w9kuWMik7IzD!(b^Tp%HC0|3n0x%hn! zU65bcF9h(enV-w|BM(eT1BkpOsU%?GODVJFT9%rIhQ?k^%}^U)Uu%VbI*ZBD9=BAz z{9`C}SWkfcf+aWS^WWJuik0FEGIa+l#S*T?&f{L}t8|x9g7)ZIh>@brog(2gPr^=} zdOzRR)+P?j;~P+}eF5C;@%e&^4hHXmpqm2HQhsh&pI!mt)PSjU{0fSg{olTR zje@Chla`kLc@{7t(n#v0d_244lp{Bi`|Q-Qz4glvq*p{yb-EW)(XHS>dI@V%DR9NJ z$3XlslLWy1$cV^DT{xO2E&)l`!8n0^3P}UpVq%pWQeLltQehrU+ld{LRsdXHhCQ28 za0 zz!`~S%;!_{b&7$`T3>QfHwZQ#Jlym6RoG6zM)0r$52|rB$Rd}*N$qtTuGuHEcW;@D zx_YoHBx9MO)~JQ7J!F;d?k{f$kQZRDoFV31`+b)}gAXkZ^}$BL3=58=z+vKP?(q}@ z)`p*{cA1jhWG|mNpJN6F9YjF24+ENg2oh>`;$mX?RgignC2|drt#kl(p6G_p^&jkI z;pUD>O5*XI?qfBW;SmywFDb!CMOB^=$_m0`uHQ{ejFe)8{(}?7#>AQ$b+7$8ApYcT zY1uyv;MaU`8!0jaA%Lbi0ywZUPEO;+V4Ft33(}9&)W% z0Mnd;l;h$fe>mBq(BtqKkfKyz;rnb%OcF9uQ`_%6f|*T^?Yg8JJ@Yj{yCF&pr4c77 za#Gcpm2$#}fK(A7R2yE7r36ExG+uXaq0ys)_^|!v!>6~@o3@*L4Q1AvNYo300FUS5 z<9mHn*UjDCy)`8zMKJMk^c~# zRXHyMa-a5`_|&Cmt$NOMa;^poD@oc`h2F8s@6OO+sd6PytDkeGvP zcL^Vdzr|E#&`cYV_}C?-f5eEPD-=pB&K%pk=tC8KxzcKYHh`fO8*jR_mz+e3!*Nip zg~ihf>^}87n0vzlhS{OYk`as+3+ga?mKW(LI!sceZ~M*N&^nTpM@O2fMOgiGSgTA! z0~=K#Au5f*EBfZ1pB)w?;f;F!SaY(Imx3YIQVR9ao20qRi=U_@XEBOuMNhRJuoGr4 z^bQ{l4>2ftd0=bgr%EeLwZ+?GtOcik-+UC;`nuvfR?06T=+2$Si3GB>>-l7ge@I(d zHxTGref!Bw@A7XGdW+&cmRi~0p?Kwg`&vtcaAEt0`OF{h^k3h}MUD|PnH$(hv*8Apj6aXID&(#)607lU z>=f6_k!75QphEQO0hG21+QM;5lR;aWD5~tUjV2D`q~C~lLq{PaQA;KWWv}u?I{kMo z@Q)F105&OW|AF7$RF*ti90_*apT|w~O-x`arKQ=N^hciYRhQIx-qD8U$ompg$X{NW z6B9UNZ?YfxP@J(Wca|*bhKuF7omhNDd~POnR^gqVdlo0sPh4T(n&Rc5s67ESZGHEsmQH?RbDK_ zRFnX7mLgHTC$|+9Jbi)b$yv9JLJcI)0xu#uaA21fDu9Eezx@92t_rkj|I%0T0&_~k z4h_b@amJu=*#mDK_Y!Fmmc@|_YGbs>JGaB0h_m~syz%Zo-N>vNRtQyAep<_NQKr*~ z)(c(Jlcs9*eT#vtQ)EM8&-zO#;u3?L&Yn5_D0HE=Abl0rXx^P(NmL7dxzG# z&?SA}s$U@)7?S@-Qz2xYd4Ri^eaRIy=-G17OCvLfl%_U0dN3_~r%n3?(peHRZg?+h ztY2|>dZ1fvI-77I8;da#78U&6?F~y44i38xVI{SYGNSN%yS(Iyk0u}ADfp%TrtI1r znt(qTAkw$7XYjKy+sw2u$k3zbV?)Fn*+T%5lq`;frJn;yNeW=dBi}Z*H zns(b~f8YEJ_6iQh8 zfX6`l3C+E2#c1j&Pmv09uT-k`{YXplcJ6o7wmYpzm|_Lz{M2y-hmh?DP4Rsw!VY9B zvpG~KtitnERt5S+>8VsJMAEoqX>aZBwXlM{dieR5LMwYJPFk!8xYEgPrhg$_KsY!H z#TrOB-Rd5JwEzKfH?0d}g0*ZUE_>Km%bvamS+C z5<1|+lEYg6P7mS`6LgEQlea5*ex60xJGv?#MtJj$n`#g6iidyWFu77<_%IQnVrb_l zBPObVmGF>{=A2UhxZ?A0_*x{%f+{YN)VPLQN-0U)jl%mAO;f~p0_>Qhg#tZGYM2PO zV>QC4=A&j5X>oGIrGh^Xe%UTC7nUZT`LdMr+g*yS{Grj}Yx-R?2-o_IE|OKDTSVUn zu#mep9R=TfaZ!(yzVKyxFA+T;4>%zCv17Hr6wK04p)Dez27>##eOoUkiq$e#&QOq* zTv(5EXuzOp(Jy&DQ4X+@K!W%EM-94icdH%poURebS2gr@(WiK0h(R{fybNUO0Y^55 z!CEWdv_Hp&r4+GHea;ke1#PTl5@O!FZ^E%0U0mXscYmvR%w;os?BZa7r`|hH13ZB% z!fill<}{myN(FWSAHb7zbb5!<}l|d_T|p z87W#)!|00c3xD`sq?q4{GOWT(`uqzEkh3q@;q!yE1!PjXcy^KD=3(wISX?RUZO3Zj z6m~?ZNR0Vm9;7%Pp|e_vuJalm=2@*64d%fGJh`0C!HDoVKTtyPTaLyXvDG=B>H{Is z;Rx>t=|dASSZ1M7twOGWIP&S-UhA3CUjU4>^k2ySeVF<*gpz0@WTdch8k5-{dT|->8p>gXS(le^qkE@)kaIN&CH1W!Yxw%7$FOiEfo+k|rZrT3*vP%cFG807v>pOfx)Z4jO#H^Mh0 zv0m?v=zP8~AU}sv?b%EZbFJj_d?+3KK5cq&iYYgMuxeQX!0>lrg#BF~o)3SJ!`a&( zLd=;l#a~Pwl$0_X1NVUKr*qsKlE>1V`hTTL?ZCIAV?%y)`akMZ$6Cags-J$l&5bw& z5wdxjX6WuEHD29cOFuo#QOCvLfU5jZ7GuX8iMJfsaR?JIa_@OW%u&44{!yZ(^zYld z8%G&?WP0%~N>)OfokpFR7_>4Z#V~((4>rg}uWG!fc|@86{q7BCP$09{1(#pPO93k* zLm+C*jyl?UHF9@oEDes4G`6pfUF5)w%XL8y?YyFgV96Ku`JZvuNw=wq6MPp_>lgV9 z1f4z|Kt(*}da=_khj)q?qwq^akNw_Q08fcvJ#t0qNplj;jlLPeUfYe_Cb{F5>6|JS`1d_{E*R+*e#z z&2jtWtk~L8Kri55*%?bw%CRdk`LKiHIn0ZOKOGwmn_d4tsVQ;S`r&u`5Gf)RqA>M1 zbN86Rt$?U~yk{}Q0rug&qv-cLdFD^P9lJ+uXwSS?Vw|C~^{!V{n{ z4KkD6kwLb%x1qJmR_*W#r-oi%Yut0~Gt*OM z_cU#r2o#1hf3Km)D-PXCy{3#$4Qf3?DiI?+yCbZOf2TcvKlgt>w9_c$$@c!jWtlfU zcfirKc#>Cccey9tPees(mAaw5w0jEPCI7jWB4|SjMr%T2$HpI1s7^@-n%IR2bR{t{ z{BXL9Mq=N{a1Sastg)G8dy!%QNF6z z6-bii?Qrq`SQrYvv#9Lc2N}x3I5knm_+)Y21J6skc8uNc|FZf|o8*-b%Sp~=bVKiQ9FdD--(NDh((qC`*d&)wg zYE5G9HhuUHqfrHj4Cc}5&FS9`_TS!F3o_ee>hb)O|1g>~Ll{j@(2i~!>^}$ew{`!|Cp<`EhKXB4RptNbu~59!e}6p!7oNN%bUWlf-|f$z$<#1$n~06+ zp9Y#T-@>#H(3SKg4}=QIsc~!PM-0(;K~h+4u)B@n?+5yCAMTHV2xt>9M0UiDx|^Eh zd8SMXt*uN9K!R!lY;69>e*e=DwOH5o6JH>`7}ZZ4^y9W(D#RU#4dRQL#}e-&0ti8z zNRLEe0_gz|sa z_zq^F;L&`8ew)1C3#dIHM!3W?UFv=`i{O>C?~@iEsTB!K9pDN@d8rW>QK!&Jj3R8L zL}V9+yj*x-L6lM35!rU6!!0@FDNse4qiUG4201v)(0v2t^99c-GsvO}^Zp0P*S{xx z9vA)-8)=QKBIAyRv(zbfWiehFMC#+rSi_amIjBJza#0}k;MLQT&W){pN2@ZD&Leck zZ%_pa<^3^MRSKU?jDK9mejQ(Mx+JFQ?BKbJg6?wAfi3XkqkStdyH}sE>;kcf6r~1 zJbGK+L}-hOg0`$KbFSElhs-hpo$!M45Ys`d2Rh-syk+@E17!KP47Eb*RFzpGC_|hCyC>U+&>jN{wwJE>wx|7v6+;DhDl9T?*l2!>U0FZ#;Bctdd_6*Wo8ETchuUe&9nvF@>v8t8j)C! zvn}Bx9qDn+q9ZYmt&Si^5InoK6mbCMOI`AsgZmz0fys)wlzu&z8?80EFY-+v?qF9O z9mDN5oAO6^eSTw~VbnBO%_{$;$Q;1~d`X*ohwz}Pv zlTXQ!3A2%f-ee%RE4375WMrfi6iOWd9PkksZYlveU8;0+3)MW-Vo0(~eww_wZ=;dRiK z9(!yCTdOaV`0IrM13kTdd|cc#tAN1Z8|to|J|BFVO}ie>9)L)!+#suSH9IRy#6$lo zKr^m-Oo!wFOiihwp&?k}-G;GMUBdenBFy}6m_*Q3WYJKVgP(u@UKyF`Zur@rz@d>kJqc>C{^VtpHCG)!x&`Kb>7a-&I#xnYqqRC2Ficn^L$~`@&yS~2O_UhH!jhoDBrxH0( zo{&`|%igXs6k#D0kN;l~Qc@_t*G9inC@C*fm@uKU$)YyU?=28h7O1%QbMW%I*K>>l_ zV1VsK!GF93OJys5D6UTt8olBV3wR$K2eg0u{QNwZVhcZ~`=?SW;5-uq(v~xo!RtRJ zm#03q0ycP)je}$9D3H|!A)1SaG^#GstliX(?D_^Ig$z&9wWWJ~UbuZKZQN70cA)FL zh+l>qXLz}e_MEQ!{mc)?Sm$YB-)lDH$Ns!UVg866QZw*Po`^>)1W}?WTN~qhzKcq;fg8y^%YQUgVx_}x=H=z- z!)g>4=H-nm0f;gmSY7;b_CEu{NazuWR2dGyEPn6mvH`lI06;5^e1g`7NTiNkoOPZx zJf!Oz@X7@pPgcq;h-%b?7ad4)}8>iDNFx*b!UY&7mfy{nW*@zv=k;_BJ{?@3*XGU@eBfJ zpw`l|?a4i!xz_#V2%?p&6V{Hho^Gm23wEw$R?5COJ?a5$wol-|zuz!sSDn05t_K&x zz~r2^hkF;0seA&mNfYS9%D4#JbuIGu!>@hEQdDL-Qj~V@0c2lARu(xPpk?M7_18LC zP?5w1%8_-S)Z?~!@V%5*B|4+sfz3@X4D9&1hi$sSLFY6#mhie(<7xE%W-7Lb(A;N>W2s;}hKg zD?7W-3Fr^f0N8F(Eg);vfGy-1XZgGBrat* zdjV}%z7_y8^aILSddsp4rd%{IjGx(w@C|~ur8|fsH&8ZlpCymqU+)@ehX%*1fP}rg z{WYv^X({Krz=#<(vUqHx+qjnb(mIn1`9it(>d%gjj&)h{XD)0gM~VyD5$fD-md++9 z`0HIX_nE#~is5o^7ukI4Uq?O;{SYFms%r^gEHXx!`Abglxvi3ghw@q}x_ zg)-u;5CkFxzb5*CS&0(_JWkt!CGQd5>g{V@`W1@ZJNt9tGPyDc=9U{vMKux9cH>u8 ze!31E6vdx9X1^)Gv;alBZ;>LirR6bLDI#&;#dK-=JhZ@n0nw3GVDqc%dI^LC^uR>J zWC-U*=5(q3$aeq~w@^qVw|;Gm0s^-Y0QN*U)3X~Hyh2Rs^V%K2vvuN4I^Ooc3TS?$ zJ_l~x1eDvwJKhSpdbAc@6hQSm=(1dh50HT7$kl$Ek;b zg=?9u>U&1enu>>yhsSIKA{|xgjTX2F0Bpw#gMO16ELIJxsT3YdC*y+$qZW#N8mPE= zGGi`Zo^_Q}WFMqxscxJ&di3hTu+OjMk3Qi!-aMh2jmonbXpyF_vAjUmd3vy(p$)~y zY-oXQZsQjCB9Eb${;IdjN+gIn?bx-;4hGpGtX`aE5gpM07~ktlOTIP0Lb)-hAlpC& zfctNHOJKp)btA0LH!;8X5y8l>ETVAxbWWNnkfNTh0ixU6H8nNt$mSQBDf{F4ATj`0 zMU7=3RQ8|t`NSrWb}A-AUt;;tK>0(MCVdbU3RpUKL!&oap3U6aTaUscwC)Ej(%#nv z2YTz7qgF)=Zb&kmGB+Ou?UuuUFRoi3;|D^!?L%N` z+U)%snvE3dTabPdFv&IW4o;->cr=4i{=U&|flLW_mN0Oj_D~WK=d-HPzGH!uZ8ZRJ zn=d(co4sspZoU*6&ZRaAU0;e@k_wDnI@E$uu$@ELL+EhO^&@Erd{Y!iJEgz6u#_GL zh^%8W0Ouz+?aN0 z>f_u~GMRi7$P)e15;EJhzYPdfFIy|eWOOd$P`O3|N-pmoz-B8+sQ$Pgh)nd&3oRC0 zjvjsWa5kf-H=h2^swnVzgf0GRl?LBT75dZ{o`n6P2ix5QmSzFe!^qJ8qkzR0bXz5~ zdWr6Y2DAkmicsIZ&J2yzIb9fwZ%u=OF}CIioDy!^$&(rEM+^}uZ%AEZ$&ME>`i{laf2}cgpv>CQ-GeSbG~#7}3HmS=)} zpJv}sC;$FhfOP}6sKqNFiu&P+Y&%b{m9K<|z}>ThXMVrO37{N`{p|gU^a1*Y8$m(m z`Psyi7FXiqTY&PJkvU3Ra;&m?AXr$M5u1AcK21O*gkPS<@0C)Hk;kE(C#)P;gjw?6 z8p;hukoqtNoXs;B_@L74q&;V9`tSp641jOHd|2qx%e9Q+OT`g7?(VW%KN9N+&|J9& zO&@QcoFzQCnW5}%*#MN?=D-mwbv`=5^VD3Qzc1_{N9YXm+w_@8AH&U>E?MI|MyN`@ zZ9FtuDid_5YW@L7BR1rY$6J$xv2&6jf^i{pBA_&bx*o>Yi20upkIzp;kHohA#y1NzCz?kS@oZ_flT=ow^c z3Z|?5nhklS5yZh-DVq&PY=agDT}n#mZ7{yCZq`M!W5*7+3>D8aPqYK%G+a+lsatlPpPDw0DbMd*x|-2HIqDmmkurK^ z6az*U7~g=i&t)F^==kiA9(OR&=^Ia(4l-j3P#7G8Bt#BXMOj(kPsRsC*hf8qD`{TI z)~4PN4UYITlanXqte)EGeb?50SwsW0-h0b=ExtkHyh^#GwRbZojD9mCg2Zm5Zd*AZ z-RFJha6S*%>sq*3OmRhX5ccd{;g?d&K^}BNkez$DlvTnoqLpp<|J2`r)Y; zZt1@!NoGn(nr}^l?s_aR+l8yo_I|S^HFLCFvh$CF7SxYz=w`h{Vc<}$=fTl)$>7mD z6fAs2UgAqeMxkq@If|AY;+$iZjz-B^>Vk-GFbQG=7B8D#HHLVIQYiGsqr6HVCwA`N z&ky+Z76{g~SN9dD16T4PM7L`2Q^k(?jr@FRarbW6g4ac^7U|##)h+RYR+SgNy?z9_ z`(mHK`d6A=wDT{lt9+d)RNm@ZpT5Pxh4>{m)q_I(9RK6Tg{A3FJr>SDd~omcrIspuZ+B9;+o>YP3EkrfL`Bdki)U3*M@LGHVpG0imX(`#Z>i=9HDU<^==i6;rFb$ z74#zYOVv*0#B(h%iH%!=aPb^D{njQ;b4IUkE_Hn z5ZW|?)4VLA!{IS za#K4mTQVyqBab*PCEXmFk#mK!`pebY@U@CGI%(xQ_peY@_bqUoP~$qNLlYpDBbKd8 zHz6weZTr%g!FFWET@tuwik|Cri=CYt9Zw9Xjmh^v>fQhq0q$vw#JCR) zOL>C=H+U6svX*5Ot%8QUzTl*>p#5@5}%pjrz#xIpLe$DN9|Rg%$o`|KAx>P!9Eo$ z$M8_8_#?ca(4$V^dG41fgpa90LqLa4d<2#H(eVp0P=f-TT1=&GH_P35bVd!b{fudiqqJTDt`{GnU} zDO0WHjV~ZWZ<(i+xP+?MDD=5E$#zjW&`@0&5egSl$3>L3d!og8j zL}&k```Nq#%}fjp#9yDSlnM;eR9Pt;!mN5}p5$psY5^~8=g`ot^T_b?`3N$lJSar=%#aAcU%J#+^Diub3}YX)rQ!TcisSmqfG6YAESQmoy77ArzIM}3 z1kbnK6kP|?7QjX-uuSx4@e2`z$L)BlBKfb!P5@VGGfvccTOH9 zLQF%$VqrR!s_pCRd)nXMzic(KCMg;heoOrDY&z_m4J3nV-o|OkvUV@6J%-SIj0@+I z&&8B;|31W*rFJzcD~vl^E50*pEU}EY99R`>St5_6pwaqJn7r}0fXS#q1O!dIP+!I( z?NBysd-TUg1ptw8q*yKX{M>>Ga;52=F0N}Z_iLyl^`?=?dJTro_Dq13F@HacHHK2={ETmB;y(u~=?p6wC&M71EFbFsJ;k+H zilU*hw#$c(cown$c`2WXUNc+pr~mI;IG#yKpPy+5j}QHIt)?{x=_f&OdK z<+$7KoE|@f1IQ@xpl~feFGZ76r|fGcJU^8_WVPsiCKpD9vD}Gg5szlTmHz0s4Qr@< zBGQZ&q<~Uc_dXSkK#g)6KOl5aRbT6UXtSd!Unp}mQsgwxG%z__5+La#%GFN0f-l5h zz50pL0b6NSWck9W^0VTd0$?Hc1uFBh%CFqX88MBHlT98E*cci;UPo$?p}RW{*!g|U z7$V7Cdb)vl=#P&8XG)WinEfqT%2ro*^6kFkhQzwE8!6$;u5q@6#62^>{?Fiwc96>A zM70CIbes%sX~r>XdZ+$9GEDH^;c1g2Sx0}IPqb+n?B!AM5ZHWtzx<6_Gqr;Pp#|I3 z_&yIP2S3Qsmf;DuTH|s$t5~B3V((sG9Ri~3a1^X&LnLe6=|1Xf{5LdO=2^nHJP`l6 zVVm@w;WN;`$k~z6*svQd$=IdAab zJdpru?dTWl{hWEqsU^czv(^0H-=uzwma;NEaDzk&$Ix@{In%*|i(OLZ2wZ$5v|$9> zdArc}!Er2b{b*K=#_#W}{C3X@y^4KDs#6%}RpB*2wcgQQ8d3)d6~<>1{W-}!+v~6? zAcGcdJjM_7jqrmdMA zwgGQ@>h(2SV6TL3$ICYx$~9o??Dv{c9Mh(-Flon>9W1%#XerE4=U zJFhCFrqUhq^BcYhX_Xa4kJ{y4waggxIVEUI93QH#@XmZ5b$HllD)1gzk*WC&jaM3+d&$xG<(zW=#4AKnkPTL^sKuR!D2;DsyJe%Xkn^`T1UaW4q;C~vPU{)pQ7D<@w#X8j1G{IyS_((%foQ3x3oNX!7#<;XSU*;7j!j0M5Iw} zx1z%n9P)bW-X}BH0M$cJ;-0fYx7SI!4qWK&6ICayec$R?CZY&aU!lv1Z-CsBTiG zkSCL=BgylAMW$itY4FnqLK%fqRe1wcgH*n}#tRm4-n_?kDtOpdo#!58UYkntbNo2; zdZwq{f*}#qSLU1`s#&r}W;5&>(6Uf5a+NoH-)ZUc^mt1SuaXM~IQ1n2)OC(+8HOl* z*6^-_g|Yl0VHwrXA0KPwS<9Jt=5;F@kC_`>h>Z}$pR*`Bu}LW8zi|I%JAC#=cSyR*eO1U>*NckL&Nw|HxbgVNy)$VbvArEIg z$75~9`aqlLe09zXxYLU=dv^!_oOr}|D;qd5HuMY~v-Z~cE$uy9yj#`ECdB!5R}2I1 z?drhg$yK;aha0ye&J~$6MCPW2lgdH8_>KldL-x336IwyEWn#9XxoCe6CLtk#`#NO# zo_)J^u2ogCQ){K~TR2eXm4sqTOVDYn=@*d_gEgObT zUH)><5f629m~$Ohv?YtNOjdQ$MO$^=_G|B~0B)tdTfQqmQOWQ9By%%Tw@^V>^g{hy zL(PxZyIT}*et*WLcLj(=cn+ZSXv@F3zaUS&Xt%0$@DuLmhTRe;3q(RoE>iv}*Lm&07FZ%dA*|Rk!YaQwPxuF)bTT)Uo zOG7z?>})$eaW4vnkwEcDI+7`Tvc(}4mHYUe1$3X9VolRtgDv+pAN=_zw8l##Hc)SttVu% zeNX*f!}|pC)aeK=tgj7}x{5B2cn;CwCos8qbE$2}YXo{khet=WVsKqq>4Pl=_P6 zBTz;3pn6=>2uY=|@k^3!_gpNPPetfh7=?LJkAP&|b>O%03vjH*TOirx-%-V&z;;;WiQmNdgtygqp6apl9>&RA zW!ceN-*QJZFz90Wsca;jn&789#rSP;^Tk|XtNv$tI!i?b-MF1RYk~JHD!oLh_?mVS zqq(SkZN$XQO^6yA+tq> zkX_}>3SOj0OP;}Zgz?*l+&YygC?Q-n?%C(h$^*5B=aN9>@UGbUtG{2|S+UI@SzSW) z9P4`H>)$MUxVi5afB+I-1Ka5&*YwAuiB1S zWtWf7Inm3i{x+A9>RmHAz2_6Yn4LowAH*MrT-(LQ?#;5NujVzbp$u0Nz-EuEI+>h3Gm!pkqJ$Ng|*=cli^!lB0Uf%6k^WfzV z=H`#8zikK6<1!K&`V8YRr1Ev^GGHZ`yfIaZ=TUa!xy&r=;nv1`vH4iFz6w^;1Xy^? zKi&m`3`j9{(tq<#_Q@)amo{X@L9kjicX{;3`=p&b<9syI z;lLOmQIMZsYz1{r`mQ~(1mA19fqTy{$}C;HzemW1VO-+-RBUXn@6zJAN!5aG!OsvR zDvPaIo{h_veqUQ+y}#P3W9OZGuEPmPM-->>R&Hy(csDug4YC`+8VW% z9>`LA)MRDf%{5&sy=>P80%22&FWP^S_FqPA=y}^tzJI(Cmr%Ty;~21~_3R9%e!KH- zFLkiPsJ`&o(`?}5m@h#JcoL4Hx$_#6b%f4ZXYIK|!$2Rs3L2N8uR&%fAwr68UO)E5 z2sj=7;&xu4p>+!n7c#dusUdM#R4yQ*>iIDBED82vtcFbwox3P@Q)nOz1 ze>7A3rban4}r_R*a zzz`ruY@C8r9M7pt-&oCe5^VHmO?m`Hr}f=eZNMyfetxk&=0g?9dlH{Fb2_2{=e*o@ zE-Cbu6qR$8kvUcGXCU;l3dQZP?;kKsSL2n#FoeD$b^4l=Tmutz<2*%Y0OXpKGp-jd z-SqV-p_4tqV@{OgFng^VCc_Y**<+`8{R;&5*ELOc5Y(}nU2lJp6!pPQAO;!xo>OZ(ap7$(c?cmB@>AQ?fiII&~9{ zaXUTgoZXE-KEoD?NEjp$UW$>Q(MJ<0!eA_HYXVIMXb>v6b?Z3b?vqcZps?WL*rhe8 zEbblBg5o2?=kPtpCU^792h>?#TKVL7ol#9zfam4g0n6w;9$@d!VWpQsXG{AZTp@i| z0#-<^izC0Zo*cc9-Hd)Ff;Vdfo-o%k=jJ;<%JJlVWfus8k(8iYf@i$W_2ajqzym-G z7HOQmZ*{ra2Yj~eJwQ2m4U+GN6kUprfod@*XF?!$ejgNmd1h`Y-+J-1-9XD^%c}Vo zHvi){pr#d^nJ}8%%HHo8WtrHSnt-3Xb#{X5uIAHW^Q*Jf%ZIos*}*&tSbY#sgVb|W zr**WhQ4ok8rYGFI=`{j0sFsux_yaGVvV@i+rdzl5<)qwt3qQRE8AJ{8Ta}+l@BBT_ zS8gP$IoGA+?XgTej_o&Bv`o~=K$On%hgKxc zHtDd+^&D!VF2pNBklvqtmDV*Z#W=LrLgM;2AOVvJSpSxIA5w+8xH&jFR@mryUZi-? z=owBv`}zO1_vYbHzVH9=Ju`MAJ7WovP>8IRWh7dxB}LY7lujw*dHe|}&GobURu!|&vu zRRw$??1Kd>&G!iaG>)JO#U6I5Th6F_AYqpt*c@A|V|e;o>&Tp4uW6UvwTYJjAoVba zqN)O0f~Dh9na{6b#hycWtM;?!@z4*CqF2wSz{SKJ3Uz`kE9XK)U7Axb22Z?@(pFPb z3x@sAtf_}CVE6?@h8g@As0tf|>c{{x zm2e>PaAuFfV)>+MT-t!k@wt9TC5(Xb%b6z`G0XZnxLR}*R7e@+*z6o9BUpm8DZ-MB z-YYv=D*XjlP2(x>WZClWNqH}toBCGfH^g%0%$XU`C_1@AUOr<)Wt%n6RDAp7;dH{- z)6I#i9(D{!ewPzM$$OW*jdb6}(9lrhRdKPev7g^`$BE6Ri*?bhZ=kQ_Y@Xu<6dj^6 zVgy@wMCSS5m@ycx3$%1yQkZfS37yr&iMN&ra9fYetqMN?hEH;Ab)?d zd&X2EYs|kJEg&w+oNY!H>R;|9|3O^42)C1y11+E`(<%>TuXBSJ`IFE?=Vhqg`!$n= z_9lWQA`O&5=4qKscfQJ8mJc?`?JR?FE2u`L} zPa%L>L#*&*pY!fqEYj5FtWxdxdeIhMSG%rVOP|M|0Eor|tSPes1X^~~_dDj0e2ZnK zd>D&A_t&z08g(z96uFt28kC(8L$;oHX<)d;pjB7rrT+)tT(oB5u9UrMP3M5|SGG;E7 z0p$h9P(=_D(ndXAy+L8=C_=9imyE@9hbkhK3vW;J^Tuzx1k-R~YhHjroq?&*UNS9iPH*?X z;UFGvNgI+-reY*hnUk+kJuK1{cEv6Jq}&|iZIpnA0pGuln_Xa)#TY0sdG5&TPa~tP zayP$3B%;SgCJS@Ht=P-ifo=71zgoSmzF^k+FCXWJbm0=nHi=xneY<;$q~wDi#kHGu zXoD`80~Gl-H#V_q2K^=;J$f`TdaBA9wLXMQu_FNX%pvQ!)7ZqMXc_7^UjQr@3&G=> zw2aL0^vujEL8>+KAOQNT@{N*`h{7n3=f?RFOxG+2wVe3AJduR-;BM zU#$G8P8(J&dOmjB?#Ow5~M?jw{JA}e!prSz>V1okWs)EixD>(<}7 z1qDB>tgMo`KmoHIp80!#5y0t5@-7tE9>c)9F7TF+JUDzQ^lx#S2*piAZg8*aEM-Yif!! zfq4}lACH>DrCdu-f7Rl@nRF+-KOin+=xeQDr1+7oJ@yQWU-=)zGSQ`xy~dwF_*Gx- zIZ*lPu{_iy+nzWXRCPPSn;*-=!j|9t4MdZ#-MV!VWaB(Pl^h!1)nj?(6T3OoJMO5Q zdES3+L8BAuTVqRwn_G3uC-;my9P!ytK}nDPc2PJ?`S!NkPgIalztc+1WsKKEl9)aV z2WrqWX58R{O1P?)R;3XLTtPsccORzfFeJbH;H3yds2%=10xwPgi#E^Kz5|K9Ja}yf z6|n6vDjV&K-7d@zW!#=cCAGK%)EK4M zEqd7$YWWx!-||D7hD$^-X1ddM^+!x#;HbC=jfZ>mp8Lhh2Kr^u40DL?S}DC?gK1FfrVYNaQu$s&a{GR3H=8 z7CHIJbJfI;+9uw#dQ|L$p=UyQh<&>B zFpXLH!-d;(9DDn>L|zzRTW-pw=k(=(o7$9$50K2IOU2RHS61hBIl~L_vKj1+0n98b zNE~izFFCC1%>Jak7?Yt-_veY0*u{NH_b_^x)ofE!i`Md=T7AaV3=EaMzE6MvFrWu%=5ou9jd^^e0qV)Qesq`!-J{n7)r|F#`ap5Dh zYs)7Y!Zvl{IDJuBxrEeB0rlZ@gk*9JCahx3NDW~yFR>LW%gDy5*Y$lJ@Tq+9Ow}R7 zN9_gkAiMc#@6`oed+N*p-g)$829jSGeHkFHK z1N}M*v&Pr8R*D@> z9;tK4XQ_f`$2x-U8W1kBWVbv>esia+LUgJ;$BO!_b*VlCDM;(y`$#-_+gSzjf#zVP zr`1!Hbyo6~EWIPIVn>dskK5KRREYZ81r;gz4Bq_dXLtRIcEy|UKAHVWY8q>q1FWsM zWJcPBryZI|#U@%Z$8icg?@)S$_Z22LGU;$5#!n_*wxkQq8q#5bkD^1I&ikbxL411H zTj62L)3&BGpXTFt=Knlb>~PeSp0UqhpRPsPD*VOBwMJP$qPU%whSzcpVh)*!^xY&E&Yq;Sr(;NMt(J8{GwfN zBYhV7PE=IQ^cBkk2<_;M^*86#FG%A_%yMI&!i-=JN5FP6CcEu*vno9%HncCXW7oUw zcFiif`H_)LUUM+1O=IXakU$&Gaf%VqsTFH_5v0P&~J1 zXmQTJ`4l*YN9<0=d7iC4L?Uz%MA-z zWq<#we~JBN<)rwe z_mrH{(s;i19sWw@=k+bmWj^^D_8rWN5`n0O@-#;#$8jF*mbRE!GJUqRefxt4 z_>0;s1uBoESO`3fZVS|!;J3$5@G;od_R(y{V?2`QZm}Z@_wcNGYUO?({y1mM5v*~h z(zNpY?;+NrQ>zoNTHK#14dpQU@*>fng!OTm?s+Zq&@5+;tZ+1c5zlv{BxN-N0tZQ!w*@8pk}pf*-AQGzBY`i_AkSYunamF`Qr4)S$CB6nP;C@ zZ)gqGWFt>7^}X@M>DK$(kWx+gyjMpjbokz06Jq!q3*a9=C}duF=v7hS7N>n~jentt+lLYIa`PHdgqDwt-PZ_{fEe z5klPxle)Guw(PRXS;Mb#o|pcDr%_0Ma-_SY#r0ZUz}sMY*51ML`_jkxcNRL8XSMH% zxX8E9Uq?cs_3?4bt;hY+kE;6yJuHGIDqB~z$;A$EYMex8&G8i=wK54oOjYBYr_zRS z)1v>FDrH~>Xz$C(?0F$C|FH903k0$-geVNxZeG)`CdGd@FbpGk^Nn%g-^BRLxyJ6T z^~eweUlid?Aqnqy-?^LF=HCwMzXG6ykKrS=pCz^=Q(~oN|Jb+drX36omNvhoiXQsn z>KPqRC{>(ry|_=*$Ga==XIse2$c3(W3(h{OUx(g}ug%DCvR2>MX0>;HKW4T-Rk4yc z+sdq?=lfG*rGSKv?Z2mo>#wDW-fEMe3H(kJ+UafK_N;bZ+|1AtdqM&-kjlX$Ds?Jv zXB}?UGcgoIj;D1i^h=Ir)Qu-u99j-G8owODN3TU%FE-(}IC5E>ag?8K()#E;~ z<}V}YQQm8MaK>C?Qn9bD+h1#lzq6!8nxW%*WD=I=uz*>(&zlua{F~b|wR=XB_8V}N zpPbgBsu*`~X)WW(5RdODdLPZiAj~~^Z&^MIkpK?&(}GoCu0^rIx@52PLC_Up_T@g@ zVZB)JJ|<~(G{j>+w>`tBq1r;;pL@vtuJ7}pM$7Pi$VRoY{i}^}>hz4!?&I?k1ekr1 zyVTxUY*AV?R?}CY2+@iDc8hKe-mJFe_rhGC`eRKr6{=C=2O)@9^(mQy=ecIdvYPHT6`j}kVT$Ls;9u485Rl;I;C zT^Z+4@9y#Hs}Y#y5c7R8h@AL5-wgqrw0~QARCvFuqW!t)P)Cn*E6+YOxQ_GelYVE~ z`6bP$a@L#^lfyw13XZ+X!%L8ea^REWx&vn1-rjLrbh4uTgsh~o?Shdt?$SJA^pU27 zD~szA+xF-oxaTAm%Yk4+%(hmGAtaC7>+GE>dUGQ-dv*}hsx-59?;3dCQI$HUpG_+G z`N+*~wyR6cyGL`Nr_20ydghFmwByz`^T=v;x6O_Z+Mhn%{DJob-KaCM5t-a)fGNyh zAYX;vG0s zV?$In`050r_o2kQB+(@O9Y^ma>K2e?2~J^No}WYrwF=RqwPy7wMOLu!pSJ% z*t8-~!;rb{Px9^(8R1-@I(F_OK~~zl&$OYwe&S3gfa|8`s@7f^pM}$?>&GXOEUc_3 zvYY~bHR=F(7}scR!Hv0}19(|9iNre&4ei;@n%AfUJ*w`yt8?9y%T*Q{8ZVhUqelvZ z7WkWAB4^S`6VM7hh1k~i#J-k6IFJ@z2KI1%aO*?w4R(6DnzQXGDm*JmP-e-cJAax+4D4hO!Q24^{_Oj()jrn$5A+NrNO;s~;Zr&V^qCz1f zLQo(fV5BK$n7)S>Qb5#rwa=IMPXuBBwuSK>JTw$33D)zCbNu0QE*Yik2wr`sMF@b{hV^_pKCFH&@E z6VsKYP<#O=o&|}|`o|>)DansLKkm|12!!ljJ7}u|8<8GdBI}B(R^iiVtf>x!p3vP7 z_qm_~7IEiIccQdlDjzh=vpV1`UDsZnRTOfd*F1$_h{qeZr z3sg~R0lw_o`P8FZUiZ|c%a?VEPQ03e`nBM9_V4Z}-jLAnK7#z9pa2i1>e0_I^teAG zmn0Gt=pt_z?^y?{fzHQ>bw$VeFsZvm3AF;RISeLY~#HP)pmW0 zNQtW&Ttf|48vy4WM~Q=I@Z`@fmFXuCzb0z2AAx(_=l`YC3!MnLums}l_|b_lY!ZAd zB7B8pes76s{&2oJFg1h&I*-%?oJ9_=1rAjb&#M8670)T5f2{UyT6OM`d&MCOr;nMN z3wSdbetT0R7UQoy4?{dIkUn(@ejkq zO?}{dWATPk>#XcED8X%_FV`gtbgOknThfCzSnzG?@Kb^fCNAr1{ylWYb^7Nj$)gU7 zlH3pN*Wb+4nFf~+lIUPwpP;tzmOFdZ#*UA2!MWQH;o0=JG7c>8u)OAc?6Lx$t}TkB z8_%)A;ZZ`k4!LmKhF*g(N;H$m)=6Jy_y@x~ilLOni7|nX_1E0EVAKwH%ix|F!BV)- z9cbIXmAISgfYYAX8*a+*#s@{9vTki{`S$1&F3yC$SW3y$hvYfMV?&)t%obhkyHmQ$ z(B_~L**kK~BUyH#&4IGoh87=(GF&$z`UKm053HcOUh6THSV+m4AQWGUIJ&vQ??Kpr zbkv)l*MpiAEePIXtNmJ##DU%~*8i^!l*R<#7gl5&i$b4Hk1kwLQ`r0pQy}aglyRN) z?fCzuP3RcL{nZ>alTp@EQ4eAew8Lm~c0Uq4mWbZ(FS^|GXpeA&Q_wO@cUW;)GkFYTQt*XRf z4BZjc;ptHT{aT22(X3ekh5@vSBE^W7H#Ryu0TmMB?4TI04^B;Vh}0ed)~FN=q;e5- zjV036pyg%X^z-pB)v34ON6JoHtK^D71jF%_*>q;(gLGi-in)${C|(~Q==@kQG)E_0 zo67&I_-aFlok1gqFm~&a&h?RKx%sWftw3(hRStUx zwTU_X0|zEA$HmElIE8E+h&r%|odJKBUNEfK^{%n86hmuu1~HhM<%tiYw_>-Tgz|$% zxAzE%qr>>k{)cHB1MNA-ya-Vn(d!e%=F+tZgDB>K-uDsPnU%wT}pGtI2pWbEt%>Cm1`&)teD!ye42Ef}8 z7kn%#f}KxVPEHTl#XwUBdk@qu1xk5h!0tjzra%xp4DsMQcx^8QtC@7*O(z2mQ$SQS z6NEjUodp}sii|GoJTtY0h&!?ZZC^uoH_Hg7o_{9C`nWj5db8g8Qs;JT4e&O5xi*j<$*3LE-#j40$!A#R96L6#0gg+{;~Jq}$7 zDu7_e{dFww0)%|L;0fm80EPAw5R`^(my@%D!rF`^*$Ih_{Al@14(ko0n)*m7-;e$V z%x}_r%ifI+2JMgI0#;s)e=KH1uNBX!eXi+~e0!-C<7JkzS7NC#BsuYf~atE{~Igzx)9QoQLG z{(O83k)dZ7u{~iLhR+y2MZwX-kb!7`TR)qi`vpHX=~j3FYlPC!tG)iCz5rH!d!8A70ebWb zAm^;E05D8T{S~uAe%$3LV2Pt%hfOESeC-eC7^g$N)TvP!nZ)!6)fGN;<7Cym$m)Cgt*~s(+#Z;!+3>!qe;ifldH* zPc6V1`?$7dXaH*qhr z>~-$NI2grkehH_9qz2(Lh7+J)pe#b=j`xhpTC&8^Y-rsYV-By}5P8p2D_QF|fK$UTK zc$T)BuLRe{Vx#C_o6*I@VW;kX93nC^@S{G45JmqQ1~*_aaDgI&0Vgk5K-=PIKlR@W zA~anj2HQhVlSV{wqnqWgO+vQ@Hv`aCL}=HkgWn(?@6U##X8iuV4i9nkFp|^{?AZsv z6rBHcReQCJk9zhR$gLp|VsGcbEHNvrO&(L4y0P*sUw^%G-~^C{&_|xc#3`$Nv@vYN zzLdk4Wud;)Rdr;{^2pjdlu-<4;c!%|A@AkOXCjKsL>4k9l6-j(gDe*Y1Rp}}3x!~z zya1!@vpY;~Z_y%&`g1eQYLlTL`r!CwXvnAe?c2w7st0}>rE`Rn&?66i%)R3$`oJzk ztE|f@`f5Sf;D@_#R7K}uv>BUV^|7sP{sF2UC8F1W?J0y>ES><_pGR0#W$f`Yh&I-W zfkH?95TCnat1;B-HI-m0JZqGHS>XQu{vjTNW2uP)19qxz0 z8wmF2q3r#ePh(&|mQUW#wjLYoyF->FRIrnFlP@EmdI+^*+ax8OW&wG~{$jlFWysy2 zFPEjJU{J0lrKcO+j(DQ4;KV`}K+3UieD-T5XsZCu=`*nWmq5orz{5$aY`R_uEb>m> zo7^CTsJ-bb`9fWqthzeWsvTDK*eF$*S>v`7EIxs7z(gI+1Fo&4a!SIGJr)x--{h<0J5M0BE^^zurp4x2CGhyfQiuD5I%25?4vU zdc1VyO6`TY{un@g^{QV@TY+&&CAjS0PnQ6E!=WA!un@`wX`C!T=ehQmKU2)+ld~p- zp}B#mt)F{-OaS-D%uQsAJ=?`O&Z66J|4k375r|gma1$-oBPKEI zGcHiRUDe{Ejvxg3%6AEr7*xSS4R{`y8&W0-k32-ySsrtrgMHjAERrVso$PKQ2N249 z`>P3E-MLF}9yS4>)XPBdwv*F*D(Y)?^2m{JmyGiaKx?UI2n91~Fo9X4fG!x z06{w^prL)`^5tqsO!+mdbkhJKSJRfI8{fPNDh|^?6}Sru1Hdg2ikq3Jm@)o3JpAP~ z|C-C?HNXrK!od8syDi5=6c)lEc#e!6+($!5C#~k!cocg?Sp;Q0hd|b%0p-b;pq#!q zK@}EIp0NUNSFIIPb;A1+6PiOh!mqaYBgWi{y}|p1lhx2zZ|P1T5LsB`2r;2cKT8S9 zt{m`)MQqQ0bc&vzhIE#|2-ulkRUf59=F#K+WsQKM!6b0nnlC^m%mCml(TJ5$x#ev* z#j-)fK(X)hPh#qX^I&)(`^IWW;+}$1(QUtMQ)(a*|L!{V_hnGISiX2>xM??aKququ zCpSId`ZV`K2jaJNCw>X4rod`^!@<#U=PGm#!~rR^FRc#8nXP=PP<#*&&+Gvw=h|JE z4jRj~aEq(ww4ax3qtIhsM~oK@X!klnJU81L0!U$T-DAgY+Vh&)JYLjQB>OBsI^AO* zBd{W<`XkI@rKsXp>=tD-3Rxt?azGABAqpGI<=NPKI=qWxdC4s&{ke%+1$`t?89s8* zS1cKf)5kLU-*_yGuUuOVMinMLBymHYL3JMJRJTx!_(fQi8&V$Y2%cse7v^O8i(K64 z7K7sMrkIb;p+^)kJX0VmL&(pUT+}=IEDZXKb+>j{KL48L5oU1wxIhAYP7P#3weX~f zs*&@;Bkt?n;n>*NICmk$grDfCgLw5hjJnFKG0OI}(lP)zsTW{(y0ELE*0194ly?fv}%SU=id zWtU;Pi;X$M6Co2Vwl&8n{j7Sp$^1%=Ec2#J$$$+pSxP0{pF^2e12>xeuPFa?ZmX%! zwkhzLG1dwtf@@?A2&qZeGv+=FtXH6o0LE|6=-dEcnudH?7?fAm0FD1=x2B{dJuAQb zsi{L7%nQK%J<>{8T}cuflq2|>H4_+$Di^m~6xzBmZ3@|8vL%9Vlf^?Lg<=Q76imtn z!D%`TJ;qo89u8C}2V4(RYPcXiaV|S*h2F6|KJM`p%&?(E-Ax~3YQdH=d5jxU$kDD; z0)ucbqS}s$E%YZfQ50BUfcPLwT6h_jS`B1xJ{RKdKBfx*UD4NN z^v?oXfQAssgj&q{RC;jZ*V(u{r-sQkum)v16Fd{sJWfVn`U$SXlgFhOO-~hLMSdv( zr^6aS)vM6dF)9z!nEMNg3u>Pylt}l?38ZW5GzXg%HTXf1rqJmg2)ZXaT(Vd0qaO1X zc-*Qs>yS*_A`QljJ|L>Kj&r%E-hj1n*EU_y0>q3I^!f4M+Orj_iXMBFOd--n!|F#!-t>e%SfBtQCL>P$*=ifRZQhkuLf46r4R&u}sD(yI!lu z_zb(1he76Cphg!?c0f>=ikcp382advsiHbs;!EN(%w z2#yl1M{kg*RbKt&A2{~+WUhw?Nw%(kS+hg@BIxx#mi)T6h8%Y97H&uc9ADq>tR{V~ zIA3zG=lZQ%0eJGGfaXjs{%}(?S$WgN*Ib>8%5{h6+XEy%atwj@v7$e?)#~J5W}c@AMV`3&oR%AY~#rO zHwl`hPdNfo7<;X5=h!qckm!|VXLvRNv*0u+RNk$KWa+w{nZUj&{BOSbBrchb_LBB{ z-=kO}4NXUBI6mVDrAt0KT|OoBTz|t=hsJ<~;EOcjRodV6{#Tk$tfFFDpHi!a8K^Es z^BJ|DNbK!lrD?-CR!de>bA={0r`N2OhzyDMK}BaLE|8weg81tk;ly-9wv$#a^MSmP zkVC&xj?hKe+ZRhoNsag+J25?dxu5rre+8z#sV*?}e?ZQ_wUrj$GFBdBCKL|x9Y51| zIlViOeX)8cvP;j9t`BO6;X*Fvj{hn-hu3qK0mb~pS}735woWqriO)Yf@Kn=*P=TRs zMtG63g-=c{dv)@zDB?v_aH13ZwW$2X3}jq*YQ+xT=;(1a(OUSr3G zxgbtM#eDCm?-;wWk#Ix5(xsq$q!{2Msegn0VNEG4qxphEQWR`9?)E4pK*W3!Q`|J1 z9dX3&(Q&R%r9Nwe5RV17K*d6MPQ&|w$kvkFTxrnwApu5Qf2;<|C8tG`Kuv+Gzmgb+j!j(ytGKcAxtp8sBc3p>>{PnZb}t5Reg#VH2{r5I48=eD+0r zJzZCqGYD7CeFbej$5{F>83B$Tm!gK+mF3Mb*CoUAa}{!tW!#j@p4!B;aP;2wj;6eY(fa&4Rj~6cQ1$ zMM4568alrPI9;SWunM5UF;-y0tR-Pjd_%M@Q|9Tdxyb4V0&$+LAiqQ)N|NP}Q}%79 zls&EO=sXAt>fHU;2@)1DAoTr17@h$|Ehn1;V4}|KEv^Pm(o<}5k;s#qX+CcKJhc=H zXV7u^2>YPPM0Zi9m*>yiH(dB#N=ohJvzbBlb(guPAs!NlAVTg8p4?R^WQsr;(mvoR zz|&u&Su4&PuU`#mCDFRDwWX7L%SEU57;DaUR-hy~ zXC0kt!=y!}oNF%td!A%0ShBO4LZKj_1%tfr=(u+Kwo91|`py7koV8W;5v!~H zlqORCJ{MBZkWldLzv)igSkln1q`l!gFcr&Ca(4hw%Rh zeRzSB355=ai{}Sz)S}SUhN?*?j>P>#RShu%s;XMcI#sn!3L`tEUe(j&Xfh}!+(;fB z9o5UXcoeJgyG?hq;wqGhLzkxyK)8C@sDY+dMLf$zDZE|jjzdk)!LG_ghUOhA`Dtuqg&)a+NiP7 z@6DDNvH&6ZeD&e{H$kH{wBtQzZEbB=>_3InL#aI$@(t}zUHZp|kg_#5?(<1*X_K8~Uh0J@=h)M}K1jZSA&v}avyl2d}ioo<< zjf+!uU{>(@g33WkB&a)NdcT_gawVEn3^`|s&r|`IJK+$(P~hNF4*~)V%R;YXApIl^ zB7-NMk$mA?JE>+{uR-bEr_cz)^a`40EJw+hZ~I*TTy)T}FRSlo8VQA~aNbUSsh2+2tM1rBE2R_xYAWqJG zY^wkivNa;AZLu^dV)zdq4UB}TN4eeu6HkRX5oGn+&6~feptd$O8MYQYU>nI+Xd$&| zKrZCGZF`zojw!SU@`jNjBZ|&CyyRPhBIjyPChd{`jc)oYyE~cw-IB$u=-drUbAMls z&)5{p5aU15w-63G!5P3k_0hSF+@f+5RNRlPf*`E}B-C<-zkXeAFpwo}W6xfbWeG9q zj9^lagy-YZ6dAOUU0r`ZSqDi~{#OoXy7nrcrEhxykQ*1EUap*hES-6)#!M3?eeb#F zk1*!HrNSZ6_v}~U%ZX3izAEbJVjz5qmFd}x!^@dJjd0`Ob! zLUvwJTwdOL20rNo=&z(bl8dds%@T&{tC)wa|=kpR(n)m{kD$mc5gPoH6s`3k^3BrVX-TBaL z2KJ>PNZVAQH?fpWpfz8%pyy$7HBXed1Q$b#=k)(xR1ABTYt+r#wG?ONvws&|QmvgW3d`@B? zXX`Qk!|{V|)PXb-%JD1Fny%wEi1~}-r#>pym|v|a4GEdYuxCM1FXt2-Y`+PqdB+_x zHeQ{CO=<)?&qvf@yZ3-deP#OCjrqnm5pluGOg(5C_=2qYf5et(co~Uge*d1`#)&*) zAB{07s>t_%RFxWB+cM zXpGLxyfyWUj*!wj?X>50xYabjZL6qg2z*rDrnila%UPk3fP~|L|cJ$Pl|- zVgWgLpq3JCZG{~ilIc$m9EI%dlP9~N7D_2D=76f8VDM^s|H-h7`8Ib0z z;ZQI85az&ns8ol*%Mhxp{(n`jp=xcev|9WGWE0Kx^z|+D_wPRjWzVDodV06u-%0v< zdc0}?E-Su!SNt60@IJyFc4cQ2VpEW_shG_x)y;u)JWSHjJSo#kPk0a1iu&)-r*nsF z0nzf(e>Yb&oDPvQ4zMA=>Zg0L<%{0C*OIN$4o z1lAsgyiSkN3x@w#-k?uZxLh}pwc{eGqOnZ=PNeC+-)a`7xolP6jH!-gmRUeii_mn| z$HiisJc(Hp!x=#Ra#+FIjBT`hwhj;ayK%%^ZW0O0!ni!Ws@9JXj7 za>FKi1y+PUx)-r^X2`N}SgqpKxaul}vGV8&OJ7(x*>vfT5b_&@8j(jrpAaiH8n(l* z|K(Mas6kt|H_*G{{|%*D?<+uj{AN(tObjynBh=(v8|Jgv;!U2vvR((R1b`#jf9QeyPA4n{jyeHYbK7Zh3P)ME%hyF8Odn2+9&DN9>5I9jb_ic`4K@tqR@^3}#ijy88pBB{Acv*xBVLwaiBq-P#Fyqx-P_7#h0K#U%0=vWAUCp9{iL5~YyHBggdE{7;9x2l z@>tu*1>62ve*gW8SSK2(JQFYr`>$r0(-ddd z&5Qp1#Py&0-%I`v9b0pYs)9r#W#A_=jjXbP?^HLW@F+Y)Uh*sCGuBs$oPl& znT4bbhH>TC9$LFee(Kv{MJ3Euocil~t9vmexMEiDSQ_9)ZYHlRvQWPxJ;Sd-K~Gls zg_R?7x5r@=SjG`<4eMtc{okleSaq^=s8B`0);t*YwMMKwW0@L}CdRh6j!(fBR|H`Q z!e@pJDayT4{igAi?P(>yW&-Fi2!b#yF;JDvh}>Z&?Im*~O;}$h#QXP0OBMuWV4~0k z(rhgke!h3R4RVK$rZ&UQL|=ZKXQP4hA?I#3m`zOP1YMweQ(Z-N`JF<5Ykm$-6^ zNL2d-CAGoUU=Zb&t?w&lS9rvJ7vp=cdF><%MVmaJY4uT(V9QKWCx<0laCm;1L@MXZ z6exN%2ay9QE3*d_C>Qm($h^aWZzS2NQ5>)MHc-s2TkE)PntXnJ zBR^}ywF_OQVyWgx*~eE@$752dLZOvjF8Ih1jpel~NChixlTvhejzNU^>(d>RVF_;8 zCj1N_ZHWu)@HdfGVt?LPLv??tNvW>;vnl!zm#e1GcCj{flD93jUEfjQ=58!AfN44pp8_3zMI&pd2w5r6Yc z)&~e03Bc)!yR2K{QkF}9zF{}+Wv|(Vjc;R6q!(iPKYDUTp=O?0T9IQ_e}`HB1Tb)1 zLAMBmXnt$sbN=fq#~6C3T*T+C{nxiQS_51y2;dO&|Fp>b`|}};gR}vm9qG^q5FSc`G0Tnf1f0ox`x~B92X-o71ocyuS0sq`wRDx GBK{vCzA}IS diff --git a/doc/connectivity/networking/api/images/lwm2m_engine_state_machine.svg b/doc/connectivity/networking/api/images/lwm2m_engine_state_machine.svg new file mode 100644 index 00000000000..9cb203be9e0 --- /dev/null +++ b/doc/connectivity/networking/api/images/lwm2m_engine_state_machine.svg @@ -0,0 +1,4 @@ + + + +
lwm2m_rd_client_start()
lwm2m_rd_client_start()
IDLE
IDLE
INIT
INIT
LwM2M engine state machine
LwM2M engine state machine
DO
REGISTRATION
DO...
if bootstrap needed
if bootstrap needed
Send bootstrap registration message
Send bootstrap registration message
DO
BOOTSTRAP REG
DO...
Send registration message
Send registration message
REGISTRATION
SENT
REGISTRATION...
Succesful registration response
Emit event 5
Succesful registration response...
REGISTRATION
DONE
REGISTRATION...
Only in queue mode
after idle period.
Emit event 10
Only in queue mode...
RX OFF
IDLE
RX OFF...
UPDATE SENT
UPDATE SENT
Update
Update
Update
Update
Succesful update
Emit event 7
Succesful update...
Send deregistration message
Send deregistration message
DEREGISTER
DEREGISTER
acknowledged
acknowledged
DEREGISTRATION
SENT
DEREGISTRATION...
stop requested
Emit event 9
stop requested...
Server
is disabled
Server...
DEREGISTERED
DEREGISTERED
lwm2m_rd_client_stop()
lwm2m_rd_...
NETWORK
ERROR
NETWORK...
Messsage transmisison
failed
Messsage...
Succesful bootstrap registration response
Emit event 2
Succesful bootstrap registration response...
BOOTSTRAP REQ SENT
BOOTSTRAP REQ SENT
Bootstrap finish from server
Bootstrap finish from server
BOOTSTRAP REQ DONE
BOOTSTRAP REQ DONE
BOOTSTRAP TRANS DONE
BOOTSTRAP TRANS DONE
Emit event 3
Emit event 3
Emit event 11
Emit event 11
Timeout while sending message
If not bootstrap, emit event 6
Timeout while sending message...
Failure code in response
or timeout
Emit event 6
Failure code in response...
Registration failed,
emit event 4
Registration failed,...
Failure
Event 8
Failure...
UPDATE REGISTRATION
UPDATE REGISTRATION
Send update registration
message 
Send update registration...
Registration lifetime
is not yet expired
Registration lifetime...
fallback
fallback
Suspending
Suspending
lwm2m_engine_pause()
lwm2m_engine_pause()
lwm2m_engine_resume()
lwm2m_engine_resume()
ANY
STATE
ANY...
SUSPENDED
SUSPENDED
DO
REGISTRATION
DO...

state was
UPDATE_SENT?

state was...

Y

Y

N

N
REGISTRATION
DONE
REGISTRATION...

N

N

Y

Y

time for
update?

time for...
Bootstrap failed,
emit event 1
Bootstrap...

SERVER
DISABLED
SERVER...
Server disabled,
emit event 12
Server disabled,...
Cannot recover,
emit event 13
Cannot recover,...
Disable timer
expired
Disable timer...
connecting
connecting
connected
connected
stopped
stopped
Disconnected
for a perdiod
Disconnected...
Disconnecting
or stopping
Disconnecting...
Color coding
Color coding
recovering
recovering
Text is not SVG - cannot display
\ No newline at end of file diff --git a/doc/connectivity/networking/api/lwm2m.rst b/doc/connectivity/networking/api/lwm2m.rst index 3baa4516c5d..30bc439b72a 100644 --- a/doc/connectivity/networking/api/lwm2m.rst +++ b/doc/connectivity/networking/api/lwm2m.rst @@ -326,6 +326,9 @@ events, setup a callback function: LOG_DBG("Deregistration client"); break; + case LWM2M_RD_CLIENT_EVENT_SERVER_DISABLED: + LOG_DBG("LwM2M server disabled"); + break; } } @@ -545,7 +548,7 @@ The engine state machine shows when the events are spawned. Events depicted in the diagram are listed in the table. The events are prefixed with ``LWM2M_RD_CLIENT_EVENT_``. -.. figure:: images/lwm2m_engine_state_machine.png +.. figure:: images/lwm2m_engine_state_machine.svg :alt: LwM2M engine state machine State machine for the LwM2M engine @@ -557,79 +560,116 @@ The events are prefixed with ``LWM2M_RD_CLIENT_EVENT_``. * - Event ID - Event Name - Description - - Actions * - 0 - NONE - No event - - Do nothing * - 1 - BOOTSTRAP_REG_FAILURE - Bootstrap registration failed. Occurs if there is a timeout or failure in bootstrap registration. - - Retry bootstrap * - 2 - BOOTSTRAP_REG_COMPLETE - Bootstrap registration complete. Occurs after successful bootstrap registration. - - No actions needed * - 3 - BOOTSTRAP_TRANSFER_COMPLETE - Bootstrap finish command received from the server. - - No actions needed, client proceeds to registration. * - 4 - REGISTRATION_FAILURE - Registration to LwM2M server failed. Occurs if there is a failure in the registration. - - Retry registration * - 5 - REGISTRATION_COMPLETE - Registration to LwM2M server successful. Occurs after a successful registration reply from the LwM2M server or when session resumption is used. - - No actions needed * - 6 - REG_TIMEOUT - Registration or registration update timeout. - Occurs if there is a timeout during registration. - NOTE: If registration fails without a timeout, - a full registration is triggered automatically and - no registration update failure event is generated. - - No actions needed, client proceeds to re-registration automatically. + Occurs if there is a timeout during registration. Client have lost connection to the server. * - 7 - REG_UPDATE_COMPLETE - Registration update completed. Occurs after successful registration update reply from the LwM2M server. - - No actions needed * - 8 - DEREGISTER_FAILURE - Deregistration to LwM2M server failed. Occurs if there is a timeout or failure in the deregistration. - - No actions needed, client proceeds to idle state automatically. * - 9 - DISCONNECT - - Disconnected from LwM2M server. - Occurs if there is a timeout during communication with server. - Also triggered after deregistration has been done. - - If connection is required, the application should restart the client. + - LwM2M client have de-registered from server and is now stopped. + Triggered only if the application have requested the client to stop. * - 10 - QUEUE_MODE_RX_OFF - Used only in queue mode, not actively listening for incoming packets. In queue mode the client is not required to actively listen for the incoming packets after a configured time period. - - No actions needed * - 11 - ENGINE_SUSPENDED - Indicate that client has now paused as a result of calling :c:func:`lwm2m_engine_pause`. State machine is no longer running and the handler thread is suspended. All timers are stopped so notifications are not triggered. - - Engine can be resumed by calling :c:func:`lwm2m_engine_resume`. * - 12 + - SERVER_DISABLED + - Server have executed the disable command. + Client will deregister and stay idle for the disable period. + * - 13 - NETWORK_ERROR - Sending messages to the network failed too many times. - If sending a message fails, it will be retried. - If the retry counter reaches its limits, this event will be triggered. - - No actions needed, client will do a re-registrate automatically. + Client cannot reach any servers or fallback to bootstrap. + LwM2M engine cannot recover and have stopped. +The LwM2M client engine handles most of the state transitions automatically. The application +needs to handle only the events that indicate that the client have stopped or is in a state +where it cannot recover. + +.. list-table:: How application should react to events + :widths: auto + :header-rows: 1 + + * - Event Name + - How application should react + * - NONE + - Ignore the event. + * - BOOTSTRAP_REG_FAILURE + - Try to recover network connection. Then restart the client by calling :c:func:`lwm2m_rd_client_start`. + This might also indicate configuration issue. + * - BOOTSTRAP_REG_COMPLETE + - No actions needed + * - BOOTSTRAP_TRANSFER_COMPLETE + - No actions needed + * - REGISTRATION_FAILURE + - No actions needed + * - REGISTRATION_COMPLETE + - No actions needed. + Application can send or receive data. + * - REG_TIMEOUT + - No actions needed. + Client proceeds to re-registration automatically. Cannot send or receive data. + * - REG_UPDATE_COMPLETE + - No actions needed + Application can send or receive data. + * - DEREGISTER_FAILURE + - No actions needed, client proceeds to idle state automatically. Cannot send or receive data. + * - DISCONNECT + - Engine have stopped as a result of calling :c:func:`lwm2m_rd_client_stop`. + If connection is required, the application should restart the client by calling :c:func:`lwm2m_rd_client_start`. + * - QUEUE_MODE_RX_OFF + - No actions needed. + Application can send but cannot receive data. + Any data transmission will trigger a registration update. + * - ENGINE_SUSPENDED + - Engine can be resumed by calling :c:func:`lwm2m_engine_resume`. + Cannot send or receive data. + * - SERVER_DISABLED + - No actions needed, client will re-register once the disable period is over. + Cannot send or receive data. + * - NETWORK_ERROR + - Try to recover network connection. Then restart the client by calling :c:func:`lwm2m_rd_client_start`. + This might also indicate configuration issue. + +Sending of data in the table above refers to calling :c:func:`lwm2m_send_cb` or by writing into of of the observed resources where observation would trigger a notify message. +Receiving of data refers to receiving read, write or execute operations from the server. Application can register callbacks for these operations. Configuring lifetime and activity period **************************************** From d94d226fe1eb589fcea093648669a9fa46819e44 Mon Sep 17 00:00:00 2001 From: Fabian Blatz Date: Mon, 23 Oct 2023 11:27:35 +0200 Subject: [PATCH 0785/3723] modules: lvgl: input: add zephyr,lvgl-keypad-input device binding Add a pseudo device which can be used to hook into input events and emit lvgl keypad events. Signed-off-by: Fabian Blatz --- .../input/zephyr,lvgl-keypad-input.yaml | 41 ++++++++++ include/zephyr/dt-bindings/lvgl/lvgl.h | 25 +++++++ modules/lvgl/CMakeLists.txt | 1 + modules/lvgl/Kconfig.input | 13 ++++ modules/lvgl/include/lvgl_keypad_input.h | 22 ++++++ modules/lvgl/input/lvgl_common_input.c | 5 ++ modules/lvgl/input/lvgl_keypad_input.c | 75 +++++++++++++++++++ 7 files changed, 182 insertions(+) create mode 100644 dts/bindings/input/zephyr,lvgl-keypad-input.yaml create mode 100644 include/zephyr/dt-bindings/lvgl/lvgl.h create mode 100644 modules/lvgl/include/lvgl_keypad_input.h create mode 100644 modules/lvgl/input/lvgl_keypad_input.c diff --git a/dts/bindings/input/zephyr,lvgl-keypad-input.yaml b/dts/bindings/input/zephyr,lvgl-keypad-input.yaml new file mode 100644 index 00000000000..2728d0e710c --- /dev/null +++ b/dts/bindings/input/zephyr,lvgl-keypad-input.yaml @@ -0,0 +1,41 @@ +# Copyright 2023 Fabian Blatz +# SPDX-License-Identifier: Apache-2.0 + +description: | + LVGL keypad indev pseudo-device + + Listens for input events and routes the + lv_indev_data_t to the underlying keypad lv_indev_t managed by LVGL. + + The property input-codes can be used to setup a mapping of input codes + to the lvgl keys. There are lvgl keys that have a special function: + https://docs.lvgl.io/master/overview/indev.html#keys. + + The pseudo device can be associated to a specific device to listen only + for events from that device. Example configuration: + + #include + + keypad { + compatible = "zephyr,lvgl-keypad-input"; + input = <&buttons>; + input-codes = ; + lvgl-codes = ; + }; + +compatible: "zephyr,lvgl-keypad-input" + +include: zephyr,lvgl-common-input.yaml + +properties: + input-codes: + type: array + required: true + description: | + Array of input event key codes (INPUT_KEY_* or INPUT_BTN_*). + + lvgl-codes: + type: array + required: true + description: | + Array of mapped lvgl keys. diff --git a/include/zephyr/dt-bindings/lvgl/lvgl.h b/include/zephyr/dt-bindings/lvgl/lvgl.h new file mode 100644 index 00000000000..09ad0ae361b --- /dev/null +++ b/include/zephyr/dt-bindings/lvgl/lvgl.h @@ -0,0 +1,25 @@ +/* + * Copyright (c) 2023 Fabian Blatz + * + * SPDX-License-Identifier: Apache-2.0 + */ +#ifndef ZEPHYR_INCLUDE_DT_BINDINGS_LVGL_LVGL_H_ +#define ZEPHYR_INCLUDE_DT_BINDINGS_LVGL_LVGL_H_ + +/* Predefined keys to control the focused object. + * Values taken from enum _lv_key_t in lv_group.h + */ +#define LV_KEY_UP 17 +#define LV_KEY_DOWN 18 +#define LV_KEY_RIGHT 19 +#define LV_KEY_LEFT 20 +#define LV_KEY_ESC 27 +#define LV_KEY_DEL 127 +#define LV_KEY_BACKSPACE 8 +#define LV_KEY_ENTER 10 +#define LV_KEY_NEXT 9 +#define LV_KEY_PREV 11 +#define LV_KEY_HOME 2 +#define LV_KEY_END 3 + +#endif /* ZEPHYR_INCLUDE_DT_BINDINGS_LVGL_LVGL_H_ */ diff --git a/modules/lvgl/CMakeLists.txt b/modules/lvgl/CMakeLists.txt index 51eb2bd11da..9f119b016eb 100644 --- a/modules/lvgl/CMakeLists.txt +++ b/modules/lvgl/CMakeLists.txt @@ -228,6 +228,7 @@ zephyr_library_sources_ifdef(CONFIG_LV_Z_POINTER_KSCAN input/lvgl_pointer_kscan zephyr_library_sources_ifdef(CONFIG_LV_Z_POINTER_INPUT input/lvgl_pointer_input.c) zephyr_library_sources_ifdef(CONFIG_LV_Z_BUTTON_INPUT input/lvgl_button_input.c) zephyr_library_sources_ifdef(CONFIG_LV_Z_ENCODER_INPUT input/lvgl_encoder_input.c) +zephyr_library_sources_ifdef(CONFIG_LV_Z_KEYPAD_INPUT input/lvgl_keypad_input.c) zephyr_library_link_libraries(LVGL) target_link_libraries(LVGL INTERFACE zephyr_interface) diff --git a/modules/lvgl/Kconfig.input b/modules/lvgl/Kconfig.input index b6cbdad0c28..4f76643aa86 100644 --- a/modules/lvgl/Kconfig.input +++ b/modules/lvgl/Kconfig.input @@ -77,4 +77,17 @@ config LV_Z_ENCODER_INPUT_MSGQ_COUNT help Size of the encoder message queue buffering input events. +config LV_Z_KEYPAD_INPUT + bool "Input lvgl keypad" + default y + depends on INPUT + depends on DT_HAS_ZEPHYR_LVGL_KEYPAD_INPUT_ENABLED + +config LV_Z_KEYPAD_INPUT_MSGQ_COUNT + int "Input keypad queue message count" + default 4 + depends on LV_Z_KEYPAD_INPUT + help + Size of the keypad message queue buffering input events. + endmenu diff --git a/modules/lvgl/include/lvgl_keypad_input.h b/modules/lvgl/include/lvgl_keypad_input.h new file mode 100644 index 00000000000..f1d6e925f12 --- /dev/null +++ b/modules/lvgl/include/lvgl_keypad_input.h @@ -0,0 +1,22 @@ +/* + * Copyright 2023 Fabian Blatz + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#ifndef ZEPHYR_MODULES_LVGL_LVGL_KEYPAD_INPUT_H_ +#define ZEPHYR_MODULES_LVGL_LVGL_KEYPAD_INPUT_H_ + +#include + +#ifdef __cplusplus +extern "C" { +#endif + +int lvgl_keypad_input_init(const struct device *dev); + +#ifdef __cplusplus +} +#endif + +#endif /* ZEPHYR_MODULES_LVGL_LVGL_KEYPAD_INPUT_H_ */ diff --git a/modules/lvgl/input/lvgl_common_input.c b/modules/lvgl/input/lvgl_common_input.c index 2894538c62b..2f2e1d32bd1 100644 --- a/modules/lvgl/input/lvgl_common_input.c +++ b/modules/lvgl/input/lvgl_common_input.c @@ -12,6 +12,7 @@ #include "lvgl_pointer_input.h" #include "lvgl_button_input.h" #include "lvgl_encoder_input.h" +#include "lvgl_keypad_input.h" LOG_MODULE_DECLARE(lvgl, CONFIG_LV_Z_LOG_LEVEL); @@ -90,5 +91,9 @@ int lvgl_init_input_devices(void) lvgl_encoder_input_init); #endif /* CONFIG_LV_Z_ENCODER_INPUT */ +#ifdef CONFIG_LV_Z_KEYPAD_INPUT + DT_FOREACH_STATUS_OKAY_VARGS(zephyr_lvgl_keypad_input, LV_DEV_INIT, lvgl_keypad_input_init); +#endif /* CONFIG_LV_Z_KEYPAD_INPUT */ + return 0; } diff --git a/modules/lvgl/input/lvgl_keypad_input.c b/modules/lvgl/input/lvgl_keypad_input.c new file mode 100644 index 00000000000..08fd8a37a4e --- /dev/null +++ b/modules/lvgl/input/lvgl_keypad_input.c @@ -0,0 +1,75 @@ +/* + * Copyright 2023 Fabian Blatz + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#define DT_DRV_COMPAT zephyr_lvgl_keypad_input + +#include "lvgl_common_input.h" +#include "lvgl_keypad_input.h" +#include + +#include + +LOG_MODULE_DECLARE(lvgl); + +struct lvgl_keypad_input_config { + struct lvgl_common_input_config common_config; /* Needs to be first member */ + const uint16_t *input_codes; + const uint16_t *lvgl_codes; + uint8_t num_codes; +}; + +static void lvgl_keypad_process_event(const struct device *dev, struct input_event *evt) +{ + struct lvgl_common_input_data *data = dev->data; + const struct lvgl_keypad_input_config *cfg = dev->config; + uint8_t i; + + for (i = 0; i < cfg->num_codes; i++) { + if (evt->code == cfg->input_codes[i]) { + data->pending_event.key = cfg->lvgl_codes[i]; + break; + } + } + + if (i == cfg->num_codes) { + LOG_WRN("Ignored input event: %u", evt->code); + return; + } + + data->pending_event.state = evt->value ? LV_INDEV_STATE_PR : LV_INDEV_STATE_REL; + if (k_msgq_put(cfg->common_config.event_msgq, &data->pending_event, + K_NO_WAIT) != 0) { + LOG_WRN("Could not put input data into keypad queue"); + } +} + +int lvgl_keypad_input_init(const struct device *dev) +{ + return lvgl_input_register_driver(LV_INDEV_TYPE_KEYPAD, dev); +} + +#define ASSERT_PROPERTIES(inst) \ + BUILD_ASSERT(DT_INST_PROP_LEN(inst, input_codes) == DT_INST_PROP_LEN(inst, lvgl_codes), \ + "Property input-codes must have the same length as lvgl-codes."); + +#define LVGL_KEYPAD_INPUT_DEFINE(inst) \ + ASSERT_PROPERTIES(inst); \ + LVGL_INPUT_DEFINE(inst, keypad, CONFIG_LV_Z_KEYPAD_INPUT_MSGQ_COUNT, \ + lvgl_keypad_process_event); \ + static const uint16_t lvgl_keypad_input_codes_##inst[] = DT_INST_PROP(inst, input_codes); \ + static const uint16_t lvgl_keypad_lvgl_codes_##inst[] = DT_INST_PROP(inst, lvgl_codes); \ + static const struct lvgl_keypad_input_config lvgl_keypad_input_config_##inst = { \ + .common_config.event_msgq = &LVGL_INPUT_EVENT_MSGQ(inst, keypad), \ + .input_codes = lvgl_keypad_input_codes_##inst, \ + .lvgl_codes = lvgl_keypad_lvgl_codes_##inst, \ + .num_codes = DT_INST_PROP_LEN(inst, input_codes), \ + }; \ + static struct lvgl_common_input_data lvgl_common_input_data_##inst; \ + DEVICE_DT_INST_DEFINE(inst, NULL, NULL, &lvgl_common_input_data_##inst, \ + &lvgl_keypad_input_config_##inst, POST_KERNEL, \ + CONFIG_INPUT_INIT_PRIORITY, NULL); + +DT_INST_FOREACH_STATUS_OKAY(LVGL_KEYPAD_INPUT_DEFINE) From 02bf538d614d446e437f579a3c445869dbeffc52 Mon Sep 17 00:00:00 2001 From: Fabian Blatz Date: Thu, 30 Nov 2023 09:37:03 +0100 Subject: [PATCH 0786/3723] samples: subsys: display: lvgl: Add lvgl-keypad-input device Adds a zephyr,lvgl-keypad-input compatible to the native_posix board overlay and the required code to control an button matrix widget. Signed-off-by: Fabian Blatz --- .../display/lvgl/boards/native_posix.overlay | 35 +++++++++++++++---- samples/subsys/display/lvgl/src/main.c | 26 ++++++++++++-- 2 files changed, 52 insertions(+), 9 deletions(-) diff --git a/samples/subsys/display/lvgl/boards/native_posix.overlay b/samples/subsys/display/lvgl/boards/native_posix.overlay index 43cc9818d5a..29c03cc0928 100644 --- a/samples/subsys/display/lvgl/boards/native_posix.overlay +++ b/samples/subsys/display/lvgl/boards/native_posix.overlay @@ -5,6 +5,7 @@ */ #include +#include / { aliases { @@ -25,16 +26,31 @@ button0: button0 { /* gpio0 pin 0 is already aliased to led0 */ gpios = <&gpio0 1 GPIO_ACTIVE_HIGH>; - zephyr,code = ; + zephyr,code = ; }; button1: button1 { gpios = <&gpio0 2 GPIO_ACTIVE_HIGH>; - zephyr,code = ; + zephyr,code = ; }; encoder_button: encoder_button { gpios = <&gpio0 3 GPIO_ACTIVE_HIGH>; + zephyr,code = ; + }; + + button_left: button_left { + gpios = <&gpio0 6 GPIO_ACTIVE_HIGH>; + zephyr,code = ; + }; + + button_right: button_right { + gpios = <&gpio0 7 GPIO_ACTIVE_HIGH>; + zephyr,code = ; + }; + + button_enter: button_enter { + gpios = <&gpio0 8 GPIO_ACTIVE_HIGH>; zephyr,code = ; }; }; @@ -42,24 +58,31 @@ lvgl_button_input { compatible = "zephyr,lvgl-button-input"; input = <&keys>; - input-codes = ; + input-codes = ; coordinates = <160 120>; }; lvgl_encoder_input { compatible = "zephyr,lvgl-encoder-input"; rotation-input-code = ; - button-input-code = ; + button-input-code = ; + }; + + lvgl_keypad_input { + compatible = "zephyr,lvgl-keypad-input"; + input = <&keys>; + input-codes = ; + lvgl-codes = ; }; }; &gpio0 { - ngpios = <6>; + ngpios = <9>; sdl_gpio { status = "okay"; compatible = "zephyr,gpio-emul-sdl"; /* Skip pin 0 with the unknown code 0 */ - scancodes = <0 21 5 30 31 32>; + scancodes = <0 21 5 30 31 32 80 79 40>; }; }; diff --git a/samples/subsys/display/lvgl/src/main.c b/samples/subsys/display/lvgl/src/main.c index d58be550278..2fca16023ad 100644 --- a/samples/subsys/display/lvgl/src/main.c +++ b/samples/subsys/display/lvgl/src/main.c @@ -42,6 +42,11 @@ static const struct device *lvgl_encoder = DEVICE_DT_GET(DT_COMPAT_GET_ANY_STATUS_OKAY(zephyr_lvgl_encoder_input)); #endif /* CONFIG_LV_Z_ENCODER_INPUT */ +#ifdef CONFIG_LV_Z_KEYPAD_INPUT +static const struct device *lvgl_keypad = + DEVICE_DT_GET(DT_COMPAT_GET_ANY_STATUS_OKAY(zephyr_lvgl_keypad_input)); +#endif /* CONFIG_LV_Z_KEYPAD_INPUT */ + static void lv_btn_click_callback(lv_event_t *e) { ARG_UNUSED(e); @@ -95,7 +100,7 @@ int main(void) lv_group_t *arc_group; arc = lv_arc_create(lv_scr_act()); - lv_obj_align(arc, LV_ALIGN_CENTER, 0, 0); + lv_obj_align(arc, LV_ALIGN_CENTER, 0, -15); lv_obj_set_size(arc, 150, 150); arc_group = lv_group_create(); @@ -103,13 +108,28 @@ int main(void) lv_indev_set_group(lvgl_input_get_indev(lvgl_encoder), arc_group); #endif /* CONFIG_LV_Z_ENCODER_INPUT */ +#ifdef CONFIG_LV_Z_KEYPAD_INPUT + lv_obj_t *btn_matrix; + lv_group_t *btn_matrix_group; + static const char *const btnm_map[] = {"1", "2", "3", "4", ""}; + + btn_matrix = lv_btnmatrix_create(lv_scr_act()); + lv_obj_align(btn_matrix, LV_ALIGN_CENTER, 0, 70); + lv_btnmatrix_set_map(btn_matrix, (const char **)btnm_map); + lv_obj_set_size(btn_matrix, 100, 50); + + btn_matrix_group = lv_group_create(); + lv_group_add_obj(btn_matrix_group, btn_matrix); + lv_indev_set_group(lvgl_input_get_indev(lvgl_keypad), btn_matrix_group); +#endif /* CONFIG_LV_Z_KEYPAD_INPUT */ + if (IS_ENABLED(CONFIG_LV_Z_POINTER_KSCAN) || IS_ENABLED(CONFIG_LV_Z_POINTER_INPUT)) { lv_obj_t *hello_world_button; hello_world_button = lv_btn_create(lv_scr_act()); - lv_obj_align(hello_world_button, LV_ALIGN_CENTER, 0, 0); + lv_obj_align(hello_world_button, LV_ALIGN_CENTER, 0, -15); lv_obj_add_event_cb(hello_world_button, lv_btn_click_callback, LV_EVENT_CLICKED, - NULL); + NULL); hello_world_label = lv_label_create(hello_world_button); } else { hello_world_label = lv_label_create(lv_scr_act()); From 8fab08e8e2a8911d68ee0bdd984ebddac6a3c699 Mon Sep 17 00:00:00 2001 From: Jordan Yates Date: Thu, 16 Nov 2023 13:32:39 +1000 Subject: [PATCH 0787/3723] pm: device_runtime: release power domain multiple times Enable the automatic power domain management to release the domain as many times as it was claimed, instead of only once. This fixes the domain being permanently enabled if the supported device is claimed more than once. Signed-off-by: Jordan Yates --- subsys/pm/device.c | 3 ++- subsys/pm/device_runtime.c | 2 +- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/subsys/pm/device.c b/subsys/pm/device.c index 73554c66f58..15e8085773b 100644 --- a/subsys/pm/device.c +++ b/subsys/pm/device.c @@ -91,8 +91,9 @@ int pm_device_action_run(const struct device *dev, } pm->state = action_target_state[action]; - /* Power up failure flag is no longer relevant */ + /* Power up flags are no longer relevant */ if (action == PM_DEVICE_ACTION_TURN_OFF) { + atomic_clear_bit(&pm->flags, PM_DEVICE_FLAG_PD_CLAIMED); atomic_clear_bit(&pm->flags, PM_DEVICE_FLAG_TURN_ON_FAILED); } diff --git a/subsys/pm/device_runtime.c b/subsys/pm/device_runtime.c index 804cd5d2f57..dbb19c6926b 100644 --- a/subsys/pm/device_runtime.c +++ b/subsys/pm/device_runtime.c @@ -227,7 +227,7 @@ int pm_device_runtime_put(const struct device *dev) * Now put the domain */ if ((ret == 0) && - atomic_test_and_clear_bit(&dev->pm->flags, PM_DEVICE_FLAG_PD_CLAIMED)) { + atomic_test_bit(&dev->pm->flags, PM_DEVICE_FLAG_PD_CLAIMED)) { ret = pm_device_runtime_put(PM_DOMAIN(dev->pm)); } SYS_PORT_TRACING_FUNC_EXIT(pm, device_runtime_put, dev, ret); From 955bd413e1333320580f75a68891fd37b9005ea3 Mon Sep 17 00:00:00 2001 From: Jordan Yates Date: Thu, 16 Nov 2023 13:34:39 +1000 Subject: [PATCH 0788/3723] tests: pm: device_power_domains: test multiple claim Test claiming a device multiple times before releasing it, and validate that the power domain returns to off. Signed-off-by: Jordan Yates --- .../subsys/pm/device_power_domains/src/main.c | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) diff --git a/tests/subsys/pm/device_power_domains/src/main.c b/tests/subsys/pm/device_power_domains/src/main.c index 6123a8a5f54..6b19d33a57a 100644 --- a/tests/subsys/pm/device_power_domains/src/main.c +++ b/tests/subsys/pm/device_power_domains/src/main.c @@ -111,6 +111,24 @@ ZTEST(device_power_domain, test_device_power_domain) pm_device_state_get(reg_chained, &state); zassert_equal(PM_DEVICE_STATE_OFF, state, ""); + /* Directly request the supported device multiple times */ + pm_device_runtime_get(dev); + pm_device_runtime_get(dev); + /* Directly release the supported device the first time, check all still powered */ + pm_device_runtime_put(dev); + zassert_true(pm_device_is_powered(dev), ""); + pm_device_state_get(dev, &state); + zassert_equal(PM_DEVICE_STATE_ACTIVE, state, ""); + pm_device_state_get(reg_1, &state); + zassert_equal(PM_DEVICE_STATE_ACTIVE, state, ""); + /* Directly release the supported device the second time, check all off */ + pm_device_runtime_put(dev); + zassert_false(pm_device_is_powered(dev), ""); + pm_device_state_get(dev, &state); + zassert_equal(PM_DEVICE_STATE_OFF, state, ""); + pm_device_state_get(reg_1, &state); + zassert_equal(PM_DEVICE_STATE_SUSPENDED, state, ""); + TC_PRINT("DONE\n"); } From ca72fff802a45b1d903ff592e0573fbce00c994b Mon Sep 17 00:00:00 2001 From: Jordan Yates Date: Thu, 16 Nov 2023 13:34:10 +1000 Subject: [PATCH 0789/3723] tests: pm: device_power_domains: remove `CONFIG_PM` This test is unrelated to system PM. Signed-off-by: Jordan Yates --- tests/subsys/pm/device_power_domains/prj.conf | 1 - 1 file changed, 1 deletion(-) diff --git a/tests/subsys/pm/device_power_domains/prj.conf b/tests/subsys/pm/device_power_domains/prj.conf index e003169ea99..36fc76c9162 100644 --- a/tests/subsys/pm/device_power_domains/prj.conf +++ b/tests/subsys/pm/device_power_domains/prj.conf @@ -1,7 +1,6 @@ # Copyright (c) 2022, Commonwealth Scientific and Industrial Research # Organisation (CSIRO) ABN 41 687 119 230. CONFIG_ZTEST=y -CONFIG_PM=y CONFIG_PM_DEVICE=y CONFIG_PM_DEVICE_RUNTIME=y CONFIG_PM_DEVICE_POWER_DOMAIN=y From 808c0f1f784088a89aa0bc2b1e62803e2572667a Mon Sep 17 00:00:00 2001 From: Fabio Baltieri Date: Thu, 23 Nov 2023 17:36:53 +0000 Subject: [PATCH 0790/3723] input: kbd_matrix: add actual-key-mask support Add an optional actual-key-mask property to filter out key combinations that are not implemented in the actual keyboard matrix. Signed-off-by: Fabio Baltieri --- drivers/input/input_kbd_matrix.c | 5 +++++ dts/bindings/input/kbd-matrix-common.yaml | 8 ++++++++ include/zephyr/input/input_kbd_matrix.h | 10 ++++++++++ tests/drivers/build_all/input/app.overlay | 1 + 4 files changed, 24 insertions(+) diff --git a/drivers/input/input_kbd_matrix.c b/drivers/input/input_kbd_matrix.c index eb969acdbb7..af3e1974687 100644 --- a/drivers/input/input_kbd_matrix.c +++ b/drivers/input/input_kbd_matrix.c @@ -94,6 +94,11 @@ static bool input_kbd_matrix_scan(const struct device *dev) k_busy_wait(cfg->settle_time_us); row = api->read_row(dev); + + if (cfg->actual_key_mask != NULL) { + row &= cfg->actual_key_mask[col]; + } + cfg->matrix_new_state[col] = row; key_event |= row; } diff --git a/dts/bindings/input/kbd-matrix-common.yaml b/dts/bindings/input/kbd-matrix-common.yaml index 25b70d162db..075c217fe4d 100644 --- a/dts/bindings/input/kbd-matrix-common.yaml +++ b/dts/bindings/input/kbd-matrix-common.yaml @@ -49,6 +49,14 @@ properties: Delay between setting column output and reading the row values. Defaults to 50us if unspecified. + actual-key-mask: + type: array + description: + Keyboard scanning mask. For each keyboard column, specify which + keyboard rows actually exist. Can be used to avoid triggering the ghost + detection on non existing keys. No masking by default, any combination is + valid. + no-ghostkey-check: type: boolean description: | diff --git a/include/zephyr/input/input_kbd_matrix.h b/include/zephyr/input/input_kbd_matrix.h index 996aba12ff1..301e8b0311b 100644 --- a/include/zephyr/input/input_kbd_matrix.h +++ b/include/zephyr/input/input_kbd_matrix.h @@ -88,6 +88,7 @@ struct input_kbd_matrix_common_config { uint32_t debounce_up_us; uint32_t settle_time_us; bool ghostkey_check; + const kbd_row_t *actual_key_mask; /* extra data pointers */ kbd_row_t *matrix_stable_state; @@ -108,6 +109,12 @@ struct input_kbd_matrix_common_config { #define INPUT_KBD_MATRIX_DT_DEFINE_ROW_COL(node_id, _row_size, _col_size) \ BUILD_ASSERT(IN_RANGE(_row_size, 1, INPUT_KBD_MATRIX_ROW_BITS), "invalid row-size"); \ BUILD_ASSERT(IN_RANGE(_col_size, 1, UINT8_MAX), "invalid col-size"); \ + IF_ENABLED(DT_NODE_HAS_PROP(node_id, actual_key_mask), ( \ + BUILD_ASSERT(DT_PROP_LEN(node_id, actual_key_mask) == _col_size, \ + "actual-key-mask size does not match the number of columns"); \ + static const kbd_row_t INPUT_KBD_MATRIX_DATA_NAME(node_id, actual_key_mask)[_col_size] = \ + DT_PROP(node_id, actual_key_mask); \ + )) \ static kbd_row_t INPUT_KBD_MATRIX_DATA_NAME(node_id, stable_state)[_col_size]; \ static kbd_row_t INPUT_KBD_MATRIX_DATA_NAME(node_id, unstable_state)[_col_size]; \ static kbd_row_t INPUT_KBD_MATRIX_DATA_NAME(node_id, previous_state)[_col_size]; \ @@ -159,6 +166,9 @@ struct input_kbd_matrix_common_config { .debounce_up_us = DT_PROP(node_id, debounce_up_ms) * USEC_PER_MSEC, \ .settle_time_us = DT_PROP(node_id, settle_time_us), \ .ghostkey_check = !DT_PROP(node_id, no_ghostkey_check), \ + IF_ENABLED(DT_NODE_HAS_PROP(node_id, actual_key_mask), ( \ + .actual_key_mask = INPUT_KBD_MATRIX_DATA_NAME(node_id, actual_key_mask), \ + )) \ \ .matrix_stable_state = INPUT_KBD_MATRIX_DATA_NAME(node_id, stable_state), \ .matrix_unstable_state = INPUT_KBD_MATRIX_DATA_NAME(node_id, unstable_state), \ diff --git a/tests/drivers/build_all/input/app.overlay b/tests/drivers/build_all/input/app.overlay index 50f9b508387..eaaaa01bb39 100644 --- a/tests/drivers/build_all/input/app.overlay +++ b/tests/drivers/build_all/input/app.overlay @@ -33,6 +33,7 @@ col-gpios = <&test_gpio 2 GPIO_ACTIVE_LOW>, <&test_gpio 3 GPIO_ACTIVE_LOW>, <&test_gpio 4 GPIO_ACTIVE_LOW>; + actual-key-mask = <0x0f 0x0a 0x0b>; }; kbd-matrix-1 { From 686f7ef98230a7d3cf31ff931d9836baf09feec9 Mon Sep 17 00:00:00 2001 From: Andrei Emeltchenko Date: Mon, 27 Nov 2023 13:10:18 +0200 Subject: [PATCH 0791/3723] drivers: intc_ioapic: Fix get_vtd() Function acpi_drhd_get() gets pointer to union acpi_dmar_id and set its fields. Signed-off-by: Andrei Emeltchenko --- drivers/interrupt_controller/intc_ioapic.c | 13 ++++++++----- 1 file changed, 8 insertions(+), 5 deletions(-) diff --git a/drivers/interrupt_controller/intc_ioapic.c b/drivers/interrupt_controller/intc_ioapic.c index 22e9ecaf374..65615f269a3 100644 --- a/drivers/interrupt_controller/intc_ioapic.c +++ b/drivers/interrupt_controller/intc_ioapic.c @@ -125,13 +125,16 @@ static const struct device *const vtd = DEVICE_DT_GET_OR_NULL(DT_INST(0, intel_vt_d)); static uint16_t ioapic_id; - static bool get_vtd(void) { - union acpi_dmar_id *dmar_id; + union acpi_dmar_id dmar_id; int inst_cnt; - if (vtd != NULL) { + if (!device_is_ready(vtd)) { + return false; + } + + if (ioapic_id != 0) { return true; } @@ -140,9 +143,9 @@ static bool get_vtd(void) return false; } - ioapic_id = dmar_id->raw; + ioapic_id = dmar_id.raw; - return vtd == NULL ? false : true; + return true; } #endif /* CONFIG_INTEL_VTD_ICTL && !INTEL_VTD_ICTL_XAPIC_PASSTHROUGH */ From 2f7021064ffabab929ebca06bd6d42979e123222 Mon Sep 17 00:00:00 2001 From: Andrei Emeltchenko Date: Mon, 27 Nov 2023 14:23:01 +0200 Subject: [PATCH 0792/3723] arch: x86: pcie: Remove old include Remove old outdated include, causing build error. The acpi.h is not needed since it is already included if ACPI is enabled and INTEL_VTD_ICTL depends on ACPI. Signed-off-by: Andrei Emeltchenko --- arch/x86/core/pcie.c | 1 - 1 file changed, 1 deletion(-) diff --git a/arch/x86/core/pcie.c b/arch/x86/core/pcie.c index 5c1e83725bb..878e6886d7b 100644 --- a/arch/x86/core/pcie.c +++ b/arch/x86/core/pcie.c @@ -162,7 +162,6 @@ void pcie_conf_write(pcie_bdf_t bdf, unsigned int reg, uint32_t data) #ifdef CONFIG_INTEL_VTD_ICTL #include -#include static const struct device *const vtd = DEVICE_DT_GET_ONE(intel_vt_d); From 3879b02550352ce71e9cc2008ab78d116247d960 Mon Sep 17 00:00:00 2001 From: Andrei Emeltchenko Date: Thu, 30 Nov 2023 11:19:32 +0200 Subject: [PATCH 0793/3723] tests: threads: Remove unneeded option This option (CONFIG_HEAP_MEM_POOL_SIZE) is not used for the tests. Moreover it overrides the option, specified in the board's Kconfigs. Signed-off-by: Andrei Emeltchenko --- tests/kernel/threads/thread_apis/prj.conf | 1 - tests/kernel/threads/thread_error_case/prj.conf | 1 - 2 files changed, 2 deletions(-) diff --git a/tests/kernel/threads/thread_apis/prj.conf b/tests/kernel/threads/thread_apis/prj.conf index 68e030211e7..bf192b9247c 100644 --- a/tests/kernel/threads/thread_apis/prj.conf +++ b/tests/kernel/threads/thread_apis/prj.conf @@ -3,7 +3,6 @@ CONFIG_THREAD_MONITOR=y CONFIG_THREAD_CUSTOM_DATA=y CONFIG_THREAD_NAME=y CONFIG_THREAD_STACK_INFO=y -CONFIG_HEAP_MEM_POOL_SIZE=256 CONFIG_SCHED_CPU_MASK=y CONFIG_TEST_USERSPACE=y CONFIG_MP_MAX_NUM_CPUS=1 diff --git a/tests/kernel/threads/thread_error_case/prj.conf b/tests/kernel/threads/thread_error_case/prj.conf index 292c830bc05..f8f0ab6176a 100644 --- a/tests/kernel/threads/thread_error_case/prj.conf +++ b/tests/kernel/threads/thread_error_case/prj.conf @@ -3,7 +3,6 @@ CONFIG_THREAD_MONITOR=y CONFIG_THREAD_CUSTOM_DATA=y CONFIG_THREAD_NAME=y CONFIG_THREAD_STACK_INFO=y -CONFIG_HEAP_MEM_POOL_SIZE=256 CONFIG_SCHED_CPU_MASK=y CONFIG_TEST_USERSPACE=y CONFIG_MP_MAX_NUM_CPUS=1 From d5c7761314a0c3cdd1623f68d6b40b1b00196e08 Mon Sep 17 00:00:00 2001 From: Jukka Rissanen Date: Mon, 4 Dec 2023 09:44:49 +0200 Subject: [PATCH 0794/3723] net: ipv6: Silently drop unwanted NA messages Silently drop the IPv6 Neighbor Advertisement if we receive it for an unknown neighbor or if there some some issue in the packet. Returning error here would cause the ICMP module to print an actual error which just pollutes the log without any apparent benefit. Fixes #66063 Signed-off-by: Jukka Rissanen --- subsys/net/ip/ipv6_nbr.c | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/subsys/net/ip/ipv6_nbr.c b/subsys/net/ip/ipv6_nbr.c index 02c0932acf3..76029b47c11 100644 --- a/subsys/net/ip/ipv6_nbr.c +++ b/subsys/net/ip/ipv6_nbr.c @@ -1818,7 +1818,12 @@ static int handle_na_input(struct net_icmp_ctx *ctx, } if (!handle_na_neighbor(pkt, na_hdr, tllao_offset)) { - goto drop; + /* Update the statistics but silently drop NA msg if the sender + * is not known or if there was an error in the message. + * Returning <0 will cause error message to be printed which + * is too much for this non error. + */ + net_stats_update_ipv6_nd_drop(net_pkt_iface(pkt)); } return 0; From aa1ca171aa99cb96f9c11093125e25d68775daf6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Benjamin=20Cab=C3=A9?= Date: Mon, 4 Dec 2023 15:54:13 +0100 Subject: [PATCH 0795/3723] doc: sphinx: Load RTD theme as a Sphinx extension MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This commit loads the RTD theme as a Sphinx extension, which has the benefit of going through said extension's "setup" method, effectively setting useful settings such as default permalink icon (moving away from the default, not so pretty, "¶"). Signed-off-by: Benjamin Cabé --- doc/conf.py | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/doc/conf.py b/doc/conf.py index 85488318a0a..a6f6a1af3b4 100644 --- a/doc/conf.py +++ b/doc/conf.py @@ -8,8 +8,6 @@ import textwrap from sphinx.cmd.build import get_parser -import sphinx_rtd_theme - args = get_parser().parse_args() ZEPHYR_BASE = Path(__file__).resolve().parents[1] @@ -69,6 +67,7 @@ extensions = [ "breathe", + "sphinx_rtd_theme", "sphinx.ext.todo", "sphinx.ext.extlinks", "sphinx.ext.autodoc", @@ -136,7 +135,6 @@ # -- Options for HTML output ---------------------------------------------- html_theme = "sphinx_rtd_theme" -html_theme_path = [sphinx_rtd_theme.get_html_theme_path()] html_theme_options = { "logo_only": True, "prev_next_buttons_location": None From 4ab2dded8d1318e3e3a1b1df00637187e46ccc83 Mon Sep 17 00:00:00 2001 From: Robert Lubos Date: Mon, 4 Dec 2023 13:46:25 +0100 Subject: [PATCH 0796/3723] net: tcp: Eliminate race between input thread and TCP work queue Eliminate race between TCP input thread and TCP work queue, when dereferencing connection. This normally would not manifest itself during standard TCP operation, but could be a potential opening for abuse, when the already closed TCP connection is kept being spammed with packets. The test scenario involved sending multiple TCP RST packets as a response to establishing the connection, which could result in system crash. The following changes in the TCP stack made it stable in such scenario: 1. Use `tcp_lock` when searching for active connections, to avoid potential data corruption when connection is being removed when iterating. 2. Avoid memset() during connection dereference, not to destroy mutex associated with the connection. The connection context is only cleared during allocation now. 3. Lock the connection mutex while releasing connection. 4. In tcp_in(), after locking the mutex, verify the connection state, and quit early if the connection has already been dereferenced. 5. When closing connection from the TCP stack as a result of RST or malformed packet, verify connection state to make sure it's only done once, even if multiple RST packets were received. Signed-off-by: Robert Lubos --- subsys/net/ip/tcp.c | 45 +++++++++++++++++++++++-------------- subsys/net/ip/tcp_private.h | 3 ++- 2 files changed, 30 insertions(+), 18 deletions(-) diff --git a/subsys/net/ip/tcp.c b/subsys/net/ip/tcp.c index cd739d138d3..3662240ca60 100644 --- a/subsys/net/ip/tcp.c +++ b/subsys/net/ip/tcp.c @@ -537,14 +537,15 @@ static void tcp_conn_release(struct k_work *work) } } + k_mutex_lock(&conn->lock, K_FOREVER); + if (conn->context->conn_handler) { net_conn_unregister(conn->context->conn_handler); conn->context->conn_handler = NULL; } conn->context->tcp = NULL; - - net_context_unref(conn->context); + conn->state = TCP_UNUSED; tcp_send_queue_flush(conn); @@ -562,9 +563,12 @@ static void tcp_conn_release(struct k_work *work) (void)k_work_cancel_delayable(&conn->send_timer); (void)k_work_cancel_delayable(&conn->recv_queue_timer); - sys_slist_find_and_remove(&tcp_conns, &conn->next); + k_mutex_unlock(&conn->lock); - memset(conn, 0, sizeof(*conn)); + net_context_unref(conn->context); + conn->context = NULL; + + sys_slist_find_and_remove(&tcp_conns, &conn->next); k_mem_slab_free(&tcp_conns_slab, (void *)conn); @@ -751,6 +755,7 @@ static const char *tcp_state_to_str(enum tcp_state state, bool prefix) const char *s = NULL; #define _(_x) case _x: do { s = #_x; goto out; } while (0) switch (state) { + _(TCP_UNUSED); _(TCP_LISTEN); _(TCP_SYN_SENT); _(TCP_SYN_RECEIVED); @@ -1869,6 +1874,8 @@ static enum net_verdict tcp_recv(struct net_conn *net_conn, ARG_UNUSED(net_conn); ARG_UNUSED(proto); + k_mutex_lock(&tcp_lock, K_FOREVER); + conn = tcp_conn_search(pkt); if (conn) { goto in; @@ -1887,7 +1894,9 @@ static enum net_verdict tcp_recv(struct net_conn *net_conn, conn->accepted_conn = conn_old; } - in: +in: + k_mutex_unlock(&tcp_lock); + if (conn) { verdict = tcp_in(conn, pkt); } else { @@ -2428,6 +2437,12 @@ static enum net_verdict tcp_in(struct tcp *conn, struct net_pkt *pkt) k_mutex_lock(&conn->lock, K_FOREVER); + /* Connection context was already freed. */ + if (conn->state == TCP_UNUSED) { + k_mutex_unlock(&conn->lock); + return NET_DROP; + } + NET_DBG("%s", tcp_conn_state(conn, pkt)); if (th && th_off(th) < 5) { @@ -3138,10 +3153,15 @@ static enum net_verdict tcp_in(struct tcp *conn, struct net_pkt *pkt) goto next_state; } - /* If the conn->context is not set, then the connection was already - * closed. + /* Make sure we close the connection only once by checking connection + * state. */ - if (conn->context) { + if (do_close && conn->state != TCP_UNUSED && conn->state != TCP_CLOSED) { + tcp_conn_close(conn, close_status); + } else if (conn->context) { + /* If the conn->context is not set, then the connection was + * already closed. + */ conn_handler = (struct net_conn *)conn->context->conn_handler; } @@ -3164,15 +3184,6 @@ static enum net_verdict tcp_in(struct tcp *conn, struct net_pkt *pkt) } } - /* We must not try to unref the connection while having a connection - * lock because the unref will try to acquire net_context lock and the - * application might have that lock held already, and that might lead - * to a deadlock. - */ - if (do_close) { - tcp_conn_close(conn, close_status); - } - return verdict; } diff --git a/subsys/net/ip/tcp_private.h b/subsys/net/ip/tcp_private.h index 6d13c8cf6fd..80e101014cb 100644 --- a/subsys/net/ip/tcp_private.h +++ b/subsys/net/ip/tcp_private.h @@ -197,7 +197,8 @@ struct tcp_mss_option { }; enum tcp_state { - TCP_LISTEN = 1, + TCP_UNUSED = 0, + TCP_LISTEN, TCP_SYN_SENT, TCP_SYN_RECEIVED, TCP_ESTABLISHED, From 5f6b4479ed51f84e7e00bc0c8fb950865ff3bb6b Mon Sep 17 00:00:00 2001 From: Robert Lubos Date: Mon, 4 Dec 2023 16:26:49 +0100 Subject: [PATCH 0797/3723] net: conn: Improve thread safety in connection module Iterating over connection list w/o mutex lock could lead to a crash on constant incoming packet flow. Fix this by: 1. Adding mutex lock when iterating over an active connection list, to prevent list corruption. 2. Create a copy of the callback and user data pointers before releasing lock, to prevent NULL pointer dereference in case connection is released before callback is executed. Signed-off-by: Robert Lubos --- subsys/net/ip/connection.c | 21 +++++++++++++++++---- 1 file changed, 17 insertions(+), 4 deletions(-) diff --git a/subsys/net/ip/connection.c b/subsys/net/ip/connection.c index e32747bc38f..267521e1680 100644 --- a/subsys/net/ip/connection.c +++ b/subsys/net/ip/connection.c @@ -640,6 +640,8 @@ enum net_verdict net_conn_input(struct net_pkt *pkt, bool raw_pkt_delivered = false; bool raw_pkt_continue = false; struct net_conn *conn; + net_conn_cb_t cb = NULL; + void *user_data = NULL; if (IS_ENABLED(CONFIG_NET_IP)) { /* If we receive a packet with multicast destination address, we might @@ -657,6 +659,8 @@ enum net_verdict net_conn_input(struct net_pkt *pkt, } } + k_mutex_lock(&conn_lock, K_FOREVER); + SYS_SLIST_FOR_EACH_CONTAINER(&conn_used, conn, node) { /* Is the candidate connection matching the packet's interface? */ if (conn->context != NULL && @@ -731,6 +735,7 @@ enum net_verdict net_conn_input(struct net_pkt *pkt, enum net_verdict ret = conn_raw_socket(pkt, conn, proto); if (ret == NET_DROP) { + k_mutex_unlock(&conn_lock); goto drop; } else if (ret == NET_OK) { raw_pkt_delivered = true; @@ -805,6 +810,7 @@ enum net_verdict net_conn_input(struct net_pkt *pkt, mcast_pkt = net_pkt_clone(pkt, CLONE_TIMEOUT); if (!mcast_pkt) { + k_mutex_unlock(&conn_lock); goto drop; } @@ -823,6 +829,13 @@ enum net_verdict net_conn_input(struct net_pkt *pkt, } } /* loop end */ + if (best_match) { + cb = best_match->cb; + user_data = best_match->user_data; + } + + k_mutex_unlock(&conn_lock); + if (IS_ENABLED(CONFIG_NET_SOCKETS_PACKET) && pkt_family == AF_PACKET) { if (raw_pkt_continue) { /* When there is open connection different than @@ -850,11 +863,11 @@ enum net_verdict net_conn_input(struct net_pkt *pkt, return NET_OK; } - if (best_match) { - NET_DBG("[%p] match found cb %p ud %p rank 0x%02x", best_match, best_match->cb, - best_match->user_data, NET_CONN_RANK(best_match->flags)); + if (cb) { + NET_DBG("[%p] match found cb %p ud %p rank 0x%02x", best_match, cb, + user_data, NET_CONN_RANK(best_match->flags)); - if (best_match->cb(best_match, pkt, ip_hdr, proto_hdr, best_match->user_data) + if (cb(best_match, pkt, ip_hdr, proto_hdr, user_data) == NET_DROP) { goto drop; } From 571f94309e5aa6b85f548566f8c591423710aea3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Benjamin=20Cab=C3=A9?= Date: Mon, 4 Dec 2023 19:02:48 +0100 Subject: [PATCH 0798/3723] doc: net: sockets: fix terms list for Socket offloading section MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This commit fixes incorrect rendering of the list detailing the various parameters for the NET_SOCKET_OFFLOAD_REGISTER macro. This also improves the spelling and grammar of said list. Signed-off-by: Benjamin Cabé --- doc/connectivity/networking/api/sockets.rst | 30 +++++++++++++-------- 1 file changed, 19 insertions(+), 11 deletions(-) diff --git a/doc/connectivity/networking/api/sockets.rst b/doc/connectivity/networking/api/sockets.rst index 720bebeb820..139f4192444 100644 --- a/doc/connectivity/networking/api/sockets.rst +++ b/doc/connectivity/networking/api/sockets.rst @@ -157,17 +157,25 @@ option. A network driver that wants to register a new socket implementation should use :c:macro:`NET_SOCKET_OFFLOAD_REGISTER` macro. The macro accepts the following parameters: - * socket_name - an arbitrary name for the socket implementation. - * prio - socket implementation priority, the higher priority is, the earlier - particular implementation is processed when creating a new socket. - Lower numeric value indicate higher priority. - * _family - socket family implemented by the offloaded socket. ``AF_UNSPEC`` - indicate any family. - * _is_supported - a filtering function, used to verify whether particular - socket family, type and protocol are supported by the - offloaded socket implementation. - * _handler - a function compatible with :c:func:`socket` API, used to create - an offloaded socket. + * ``socket_name`` + An arbitrary name for the socket implementation. + + * ``prio`` + Socket implementation's priority. The higher the priority, the earlier this + particular implementation will be processed when creating a new socket. + Lower numeric value indicates higher priority. + + * ``_family`` + Socket family implemented by the offloaded socket. ``AF_UNSPEC`` indicates + any family. + + * ``_is_supported`` + A filtering function, used to verify whether a particular socket family, + type and protocol are supported by the offloaded socket implementation. + + * ``_handler`` + A function compatible with :c:func:`socket` API, used to create an + offloaded socket. Every offloaded socket implementation should also implement a set of socket APIs, specified in :c:struct:`socket_op_vtable` struct. From 210bd28a2455a184f59dae2bc280d6e30d0e004d Mon Sep 17 00:00:00 2001 From: Alberto Escolar Piedras Date: Tue, 5 Dec 2023 11:03:43 +0100 Subject: [PATCH 0799/3723] native_simulator: Allow to pass extra options for localizing symbols Some libraries (like Openthread's spinel code) define their API as externally linkable. This will make those symbols remain as externally linkable by default after the Zephyr build has produced the native simulator library (MCU code). When building an AMP native_simulator executable with several MCUs each including these, the linker will see those symbols as still linkable and duplicated, and throw an error. So let's give the option for users/developers of those libraries to define extra symbols they want to localize before assembling the final executable. Signed-off-by: Alberto Escolar Piedras --- arch/posix/CMakeLists.txt | 6 ++++++ boards/posix/common/natsim_config.cmake | 2 +- 2 files changed, 7 insertions(+), 1 deletion(-) diff --git a/arch/posix/CMakeLists.txt b/arch/posix/CMakeLists.txt index 1573ef82ea1..dc83cecc610 100644 --- a/arch/posix/CMakeLists.txt +++ b/arch/posix/CMakeLists.txt @@ -22,6 +22,11 @@ endif() # RUNNER_LINK_LIBRARIES: # Extra libraries to link with the runner # For ex. set_property(TARGET native_simulator APPEND PROPERTY RUNNER_LINK_LIBRARIES "mylib.a") +# LOCALIZE_EXTRA_OPTIONS: +# Extra options to be passed to objcopy when localizing each Zephyr MCU image symbols +# This can be used to hide symbols a library may have set as visible outside of +# itself once the MCU image has been assembled. +# For ex. set_property(TARGET native_simulator APPEND PROPERTY LOCALIZE_EXTRA_OPTIONS "--localize-symbol=spinel*") # Note: target_link_libraries() cannot be used on this library at this point. # target_link_libraries() updates INTERFACE_LINK_LIBRARIES but wrapping it with extra # information. This means we cannot directly pass it to the native_simulator runner build. @@ -30,6 +35,7 @@ endif() # We use target_link_options() instead add_library(native_simulator INTERFACE) set_property(TARGET native_simulator PROPERTY RUNNER_LINK_LIBRARIES "") +set_property(TARGET native_simulator PROPERTY LOCALIZE_EXTRA_OPTIONS "") set(NSI_DIR ${ZEPHYR_BASE}/scripts/native_simulator CACHE PATH "Path to the native simulator") diff --git a/boards/posix/common/natsim_config.cmake b/boards/posix/common/natsim_config.cmake index 2ab155af105..54e800cd327 100644 --- a/boards/posix/common/natsim_config.cmake +++ b/boards/posix/common/natsim_config.cmake @@ -20,7 +20,7 @@ set(nsi_config_content "NSI_EXTRA_LIBS:=$,\ >" "NSI_PATH:=${NSI_DIR}/" "NSI_N_CPUS:=${CONFIG_NATIVE_SIMULATOR_NUMBER_MCUS}" - "NSI_LOCALIZE_OPTIONS:=--localize-symbol=CONFIG_*" + "NSI_LOCALIZE_OPTIONS:=--localize-symbol=CONFIG_* $,\ >" ) string(REPLACE ";" "\n" nsi_config_content "${nsi_config_content}") From c161253287305d2cad5b49e40e39e39344387b9f Mon Sep 17 00:00:00 2001 From: Fabio Baltieri Date: Tue, 5 Dec 2023 23:18:02 +0000 Subject: [PATCH 0800/3723] drivers: input: fix few types Fix few wrong types in various input drivers. Signed-off-by: Fabio Baltieri --- drivers/input/input_gpio_kbd_matrix.c | 6 +++--- drivers/input/input_gpio_qdec.c | 2 +- drivers/input/input_npcx_kbd.c | 2 +- 3 files changed, 5 insertions(+), 5 deletions(-) diff --git a/drivers/input/input_gpio_kbd_matrix.c b/drivers/input/input_gpio_kbd_matrix.c index 988320e61f1..ccb7086c0c7 100644 --- a/drivers/input/input_gpio_kbd_matrix.c +++ b/drivers/input/input_gpio_kbd_matrix.c @@ -47,7 +47,7 @@ static void gpio_kbd_matrix_drive_column(const struct device *dev, int col) const struct gpio_kbd_matrix_config *cfg = dev->config; const struct input_kbd_matrix_common_config *common = &cfg->common; struct gpio_kbd_matrix_data *data = dev->data; - int state; + uint32_t state; if (col == INPUT_KBD_MATRIX_COLUMN_DRIVE_NONE) { state = 0; @@ -92,7 +92,7 @@ static kbd_row_t gpio_kbd_matrix_read_row(const struct device *dev) const struct gpio_kbd_matrix_config *cfg = dev->config; const struct input_kbd_matrix_common_config *common = &cfg->common; struct gpio_kbd_matrix_data *data = dev->data; - int val = 0; + kbd_row_t val = 0; if (data->direct_read) { const struct gpio_dt_spec *gpio0 = &cfg->row_gpio[0]; @@ -132,7 +132,7 @@ static void gpio_kbd_matrix_set_detect_mode(const struct device *dev, bool enabl { const struct gpio_kbd_matrix_config *cfg = dev->config; const struct input_kbd_matrix_common_config *common = &cfg->common; - unsigned int flags = enabled ? GPIO_INT_EDGE_BOTH : GPIO_INT_DISABLE; + gpio_flags_t flags = enabled ? GPIO_INT_EDGE_BOTH : GPIO_INT_DISABLE; int ret; if (cfg->idle_poll_dwork != NULL) { diff --git a/drivers/input/input_gpio_qdec.c b/drivers/input/input_gpio_qdec.c index 2b1a3578b34..fe02ad6ff83 100644 --- a/drivers/input/input_gpio_qdec.c +++ b/drivers/input/input_gpio_qdec.c @@ -131,7 +131,7 @@ static void gpio_qdec_event_worker(struct k_work *work) static void gpio_qdec_irq_setup(const struct device *dev, bool enable) { const struct gpio_qdec_config *cfg = dev->config; - unsigned int flags = enable ? GPIO_INT_EDGE_BOTH : GPIO_INT_DISABLE; + gpio_flags_t flags = enable ? GPIO_INT_EDGE_BOTH : GPIO_INT_DISABLE; int ret; for (int i = 0; i < GPIO_QDEC_GPIO_NUM; i++) { diff --git a/drivers/input/input_npcx_kbd.c b/drivers/input/input_npcx_kbd.c index 25f28e3e60e..cd0850e33f7 100644 --- a/drivers/input/input_npcx_kbd.c +++ b/drivers/input/input_npcx_kbd.c @@ -102,7 +102,7 @@ static kbd_row_t npcx_kbd_read_row(const struct device *dev) const struct npcx_kbd_config *config = dev->config; const struct input_kbd_matrix_common_config *common = &config->common; struct kbs_reg *const inst = config->base; - int val; + kbd_row_t val; val = inst->KBSIN; From ac5366c27dd07785870f6b2c25d42cc1c7afc0ed Mon Sep 17 00:00:00 2001 From: Fabio Baltieri Date: Fri, 1 Dec 2023 14:31:19 +0000 Subject: [PATCH 0801/3723] ci: compliance: keep-sorted: handle indented blocks MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Change the keep-sorted check to handle blocks of code uniformly indented. Suggested-by: Benjamin Cabé Signed-off-by: Fabio Baltieri --- scripts/ci/check_compliance.py | 29 +++++++++++++++++++++-------- 1 file changed, 21 insertions(+), 8 deletions(-) diff --git a/scripts/ci/check_compliance.py b/scripts/ci/check_compliance.py index 0a2da6bc9ca..a331fa1c7b9 100755 --- a/scripts/ci/check_compliance.py +++ b/scripts/ci/check_compliance.py @@ -17,6 +17,7 @@ import traceback import shlex import shutil +import textwrap from yamllint import config, linter @@ -1176,13 +1177,28 @@ class KeepSorted(ComplianceTest): MARKER = "zephyr-keep-sorted" + def block_is_sorted(self, block_data): + lines = [] + + for line in textwrap.dedent(block_data).splitlines(): + if len(lines) > 0 and line.startswith((" ", "\t")): + # Fold back indented lines + lines[-1] += line.strip() + else: + lines.append(line.strip()) + + if lines != sorted(lines): + return False + + return True + def check_file(self, file, fp): mime_type = magic.from_file(file, mime=True) if not mime_type.startswith("text/"): return - lines = [] + block_data = "" in_block = False start_marker = f"{self.MARKER}-start" @@ -1195,7 +1211,7 @@ def check_file(self, file, fp): self.fmtd_failure("error", "KeepSorted", file, line_num, desc=desc) in_block = True - lines = [] + block_data = "" elif stop_marker in line: if not in_block: desc = f"{stop_marker} without {start_marker}" @@ -1203,18 +1219,15 @@ def check_file(self, file, fp): desc=desc) in_block = False - if lines != sorted(lines): + if not self.block_is_sorted(block_data): desc = f"sorted block is not sorted" self.fmtd_failure("error", "KeepSorted", file, line_num, - desc=desc) + desc=desc) elif not line.strip() or line.startswith("#"): # Ignore comments and blank lines continue elif in_block: - if line.startswith((" ", "\t")): - lines[-1] += line - else: - lines.append(line) + block_data += line if in_block: self.failure(f"unterminated {start_marker} in {file}") From 33c30795bc5076a025588e93bda3486947833bc3 Mon Sep 17 00:00:00 2001 From: Fabio Baltieri Date: Fri, 1 Dec 2023 14:09:55 +0000 Subject: [PATCH 0802/3723] doc: redirects: add sorted block checks MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Add marker to keep the link list sorted. Suggested-by: Benjamin Cabé Signed-off-by: Fabio Baltieri --- doc/_scripts/redirects.py | 2 ++ 1 file changed, 2 insertions(+) diff --git a/doc/_scripts/redirects.py b/doc/_scripts/redirects.py index 0394c7c016a..6101ca8faa8 100644 --- a/doc/_scripts/redirects.py +++ b/doc/_scripts/redirects.py @@ -13,6 +13,7 @@ """ REDIRECTS = [ + # zephyr-keep-sorted-start ('application/index', 'develop/application/index'), ('boards/x86/ehl_crb/doc/index', 'boards/x86/intel_ehl/doc/index'), ('boards/x86/rpl_crb/doc/index', 'boards/x86/intel_rpl/doc/index'), @@ -165,4 +166,5 @@ ('samples/drivers/kscan_touch', 'samples/subsys/input/input'), ('samples/net/cloud/google_iot_mqtt', 'samples/net/cloud'), ('services/portability/posix', 'services/portability/posix/index'), + # zephyr-keep-sorted-stop ] From 84339bea7d900c2cfd507ebf5e8a197fa6d76c19 Mon Sep 17 00:00:00 2001 From: Abderrahmane Jarmouni Date: Mon, 20 Nov 2023 14:01:01 +0100 Subject: [PATCH 0803/3723] west.yml: hal stm32: Update STM32Cube packages Update STM32Cube packages: update stm32l4 to cube version V1.18.0 update stm32f7 to cube version V1.17.1 update stm32wb to cube version V1.18.0 update stm32f1 to cube version V1.8.5 update stm32h7 to cube version V1.11.1 update stm32wba to cube version V1.1.1 update stm32u5 to cube version V1.4.0 Update of lib/stm32/stm32wb package to version V1.18.0 Signed-off-by: Abderrahmane Jarmouni --- west.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/west.yml b/west.yml index bb943b245d7..e31e126f361 100644 --- a/west.yml +++ b/west.yml @@ -229,7 +229,7 @@ manifest: groups: - hal - name: hal_stm32 - revision: af2d314b6f7f87cfa8365009497132468ca3a686 + revision: 39903791f413a944b3ec926276557757ea47a691 path: modules/hal/stm32 groups: - hal From c3835e0cdf0a4e64e55229b65dfae8c469b21f21 Mon Sep 17 00:00:00 2001 From: Abderrahmane Jarmouni Date: Mon, 27 Nov 2023 14:39:29 +0100 Subject: [PATCH 0804/3723] drivers: counter: ll_stm32_timer: F1X changes Use "const LL_TIM_OC_GetCompareCH" & "const LL_TIM_IsEnabledIT_CCx" with STM32F1X series, following changes in stm32cube:stm32f1xx:drivers: include:stm32f1xx_ll_tim.h Signed-off-by: Abderrahmane Jarmouni --- drivers/counter/counter_ll_stm32_timer.c | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/drivers/counter/counter_ll_stm32_timer.c b/drivers/counter/counter_ll_stm32_timer.c index 3c7d561db0f..2c012d31c40 100644 --- a/drivers/counter/counter_ll_stm32_timer.c +++ b/drivers/counter/counter_ll_stm32_timer.c @@ -42,8 +42,7 @@ static void(*const set_timer_compare[TIMER_MAX_CH])(TIM_TypeDef *, }; /** Channel to compare get function mapping. */ -#if !defined(CONFIG_SOC_SERIES_STM32F1X) && \ - !defined(CONFIG_SOC_SERIES_STM32F4X) && \ +#if !defined(CONFIG_SOC_SERIES_STM32F4X) && \ !defined(CONFIG_SOC_SERIES_STM32G4X) && \ !defined(CONFIG_SOC_SERIES_STM32MP1X) static uint32_t(*const get_timer_compare[TIMER_MAX_CH])(const TIM_TypeDef *) = { @@ -70,8 +69,7 @@ static void(*const disable_it[TIMER_MAX_CH])(TIM_TypeDef *) = { #ifdef CONFIG_ASSERT /** Channel to interrupt enable check function mapping. */ -#if !defined(CONFIG_SOC_SERIES_STM32F1X) && \ - !defined(CONFIG_SOC_SERIES_STM32F4X) && \ +#if !defined(CONFIG_SOC_SERIES_STM32F4X) && \ !defined(CONFIG_SOC_SERIES_STM32G4X) && \ !defined(CONFIG_SOC_SERIES_STM32MP1X) static uint32_t(*const check_it_enabled[TIMER_MAX_CH])(const TIM_TypeDef *) = { From 7bf996d3a75a36ff13ed71c4c1925cf8fd75f03f Mon Sep 17 00:00:00 2001 From: Abderrahmane Jarmouni Date: Mon, 27 Nov 2023 15:21:47 +0100 Subject: [PATCH 0805/3723] drivers: pwm: pwm_stm32: F1X changes Use "const LL_TIM_IC_GetCaptureCHx" & "const LL_TIM_IsActiveFlag_CCx" with STM32F1X series, following changes in stm32cube:stm32f1xx:drivers: include:stm32f1xx_ll_tim.h Signed-off-by: Abderrahmane Jarmouni --- drivers/pwm/pwm_stm32.c | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/drivers/pwm/pwm_stm32.c b/drivers/pwm/pwm_stm32.c index ca989facd5d..4d899b19fea 100644 --- a/drivers/pwm/pwm_stm32.c +++ b/drivers/pwm/pwm_stm32.c @@ -141,8 +141,7 @@ static void (*const set_timer_compare[TIMER_MAX_CH])(TIM_TypeDef *, }; /** Channel to capture get function mapping. */ -#if !defined(CONFIG_SOC_SERIES_STM32F1X) && \ - !defined(CONFIG_SOC_SERIES_STM32F4X) && \ +#if !defined(CONFIG_SOC_SERIES_STM32F4X) && \ !defined(CONFIG_SOC_SERIES_STM32G4X) && \ !defined(CONFIG_SOC_SERIES_STM32MP1X) static uint32_t __maybe_unused (*const get_channel_capture[])(const TIM_TypeDef *) = { @@ -167,8 +166,7 @@ static void __maybe_unused (*const disable_capture_interrupt[])(TIM_TypeDef *) = }; /** Channel to is capture active flag mapping. */ -#if !defined(CONFIG_SOC_SERIES_STM32F1X) && \ - !defined(CONFIG_SOC_SERIES_STM32F4X) && \ +#if !defined(CONFIG_SOC_SERIES_STM32F4X) && \ !defined(CONFIG_SOC_SERIES_STM32G4X) && \ !defined(CONFIG_SOC_SERIES_STM32MP1X) static uint32_t __maybe_unused (*const is_capture_active[])(const TIM_TypeDef *) = { From 3ce60d2d34b94ebfb0ee13c1c4d227386f9cfe8e Mon Sep 17 00:00:00 2001 From: Abderrahmane Jarmouni Date: Fri, 1 Dec 2023 16:55:17 +0100 Subject: [PATCH 0806/3723] drivers: bluetooth: hci: ipm_stm32wb: naming fix STM32CubeWB v1.18.0 replaces Master with Central & Slave with Peripheral in the file app_conf.h (modified in the commit updating lib/stm32wb) Signed-off-by: Abderrahmane Jarmouni --- drivers/bluetooth/hci/ipm_stm32wb.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/bluetooth/hci/ipm_stm32wb.c b/drivers/bluetooth/hci/ipm_stm32wb.c index 59fef02b2c1..85fc875f139 100644 --- a/drivers/bluetooth/hci/ipm_stm32wb.c +++ b/drivers/bluetooth/hci/ipm_stm32wb.c @@ -99,8 +99,8 @@ static void stm32wb_start_ble(uint32_t rf_clock) CFG_BLE_PREPARE_WRITE_LIST_SIZE, CFG_BLE_MBLOCK_COUNT, CFG_BLE_MAX_ATT_MTU, - CFG_BLE_SLAVE_SCA, - CFG_BLE_MASTER_SCA, + CFG_BLE_PERIPHERAL_SCA, + CFG_BLE_CENTRAL_SCA, (rf_clock == STM32_SRC_LSE) ? CFG_BLE_LS_SOURCE : 0, CFG_BLE_MAX_CONN_EVENT_LENGTH, CFG_BLE_HSE_STARTUP_TIME, From 8e57cf1384c7c305d919ffd6e4f382c5b949c9b5 Mon Sep 17 00:00:00 2001 From: Richard Wheatley Date: Fri, 1 Dec 2023 10:23:14 -0600 Subject: [PATCH 0807/3723] boards: arm: apollo4p_evb: Add internal pullups to buttons and LEDs The LEDs and buttons on the evb need internal pullups. Signed-off-by: Richard Wheatley --- boards/arm/apollo4p_evb/apollo4p_evb.dts | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/boards/arm/apollo4p_evb/apollo4p_evb.dts b/boards/arm/apollo4p_evb/apollo4p_evb.dts index 5a4f9d26228..077262c49ab 100644 --- a/boards/arm/apollo4p_evb/apollo4p_evb.dts +++ b/boards/arm/apollo4p_evb/apollo4p_evb.dts @@ -28,15 +28,15 @@ leds { compatible = "gpio-leds"; led0: led_0 { - gpios = <&gpio0_31 30 GPIO_ACTIVE_LOW>; + gpios = <&gpio0_31 30 (GPIO_PULL_UP | GPIO_ACTIVE_LOW)>; label = "LED 0"; }; led1: led_1 { - gpios = <&gpio64_95 26 GPIO_ACTIVE_LOW>; + gpios = <&gpio64_95 26 (GPIO_PULL_UP | GPIO_ACTIVE_LOW)>; label = "LED 1"; }; led2: led_2 { - gpios = <&gpio96_127 1 GPIO_ACTIVE_LOW>; + gpios = <&gpio96_127 1 (GPIO_PULL_UP | GPIO_ACTIVE_LOW)>; label = "LED 2"; }; }; @@ -44,11 +44,11 @@ buttons { compatible = "gpio-keys"; button0: button_0 { - gpios = <&gpio0_31 18 GPIO_ACTIVE_LOW>; + gpios = <&gpio0_31 18 (GPIO_PULL_UP | GPIO_ACTIVE_LOW)>; label = "BTN0"; }; button1: button_1 { - gpios = <&gpio0_31 19 GPIO_ACTIVE_LOW>; + gpios = <&gpio0_31 19 (GPIO_PULL_UP | GPIO_ACTIVE_LOW)>; label = "BTN1"; }; }; From 1b3d29c53e1a5cb5a0d84bf3f5a757ced55659dc Mon Sep 17 00:00:00 2001 From: Aaron Ye Date: Sat, 2 Dec 2023 08:00:36 +0800 Subject: [PATCH 0808/3723] dts: arm: ambiq: Add GPIO instances to Apollo4 Blue Plus SoC This commit instantiates the GPIO peripherals. Also enables GPIO instances for apollo4p_blue_kxr_evb. Signed-off-by: Aaron Ye --- .../apollo4p_blue_kxr_evb.dts | 16 ++++++ dts/arm/ambiq/ambiq_apollo4p_blue.dtsi | 56 +++++++++++++++++++ 2 files changed, 72 insertions(+) diff --git a/boards/arm/apollo4p_blue_kxr_evb/apollo4p_blue_kxr_evb.dts b/boards/arm/apollo4p_blue_kxr_evb/apollo4p_blue_kxr_evb.dts index 68e0195056c..4644f8ee611 100644 --- a/boards/arm/apollo4p_blue_kxr_evb/apollo4p_blue_kxr_evb.dts +++ b/boards/arm/apollo4p_blue_kxr_evb/apollo4p_blue_kxr_evb.dts @@ -86,3 +86,19 @@ pinctrl-names = "default"; status = "okay"; }; + +&gpio0_31 { + status = "okay"; +}; + +&gpio32_63 { + status = "okay"; +}; + +&gpio64_95 { + status = "okay"; +}; + +&gpio96_127 { + status = "okay"; +}; diff --git a/dts/arm/ambiq/ambiq_apollo4p_blue.dtsi b/dts/arm/ambiq/ambiq_apollo4p_blue.dtsi index 65166caa335..d96bf4ff10d 100644 --- a/dts/arm/ambiq/ambiq_apollo4p_blue.dtsi +++ b/dts/arm/ambiq/ambiq_apollo4p_blue.dtsi @@ -4,6 +4,7 @@ #include #include #include +#include / { clocks { @@ -226,6 +227,61 @@ pinctrl: pin-controller@40010000 { compatible = "ambiq,apollo4-pinctrl"; reg = <0x40010000 0x800>; + #address-cells = <1>; + #size-cells = <0>; + + gpio: gpio@40010000 { + compatible = "ambiq,gpio"; + gpio-map-mask = <0xffffffe0 0xffffffc0>; + gpio-map-pass-thru = <0x1f 0x3f>; + gpio-map = < + 0x00 0x0 &gpio0_31 0x0 0x0 + 0x20 0x0 &gpio32_63 0x0 0x0 + 0x40 0x0 &gpio64_95 0x0 0x0 + 0x60 0x0 &gpio96_127 0x0 0x0 + >; + reg = <0x40010000>; + #gpio-cells = <2>; + #address-cells = <1>; + #size-cells = <0>; + ranges; + + gpio0_31: gpio0_31@0 { + compatible = "ambiq,gpio-bank"; + gpio-controller; + #gpio-cells = <2>; + reg = <0>; + interrupts = <56 0>; + status = "disabled"; + }; + + gpio32_63: gpio32_63@80 { + compatible = "ambiq,gpio-bank"; + gpio-controller; + #gpio-cells = <2>; + reg = <0x80>; + interrupts = <57 0>; + status = "disabled"; + }; + + gpio64_95: gpio64_95@100 { + compatible = "ambiq,gpio-bank"; + gpio-controller; + #gpio-cells = <2>; + reg = <0x100>; + interrupts = <58 0>; + status = "disabled"; + }; + + gpio96_127: gpio96_127@180 { + compatible = "ambiq,gpio-bank"; + gpio-controller; + #gpio-cells = <2>; + reg = <0x180>; + interrupts = <59 0>; + status = "disabled"; + }; + }; }; wdt0: watchdog@40024000 { From 39ec2d2ce0646d2af312b12e9bd0de7bd11a3c3e Mon Sep 17 00:00:00 2001 From: Aaron Ye Date: Sat, 2 Dec 2023 08:00:36 +0800 Subject: [PATCH 0809/3723] boards: arm: apollo4p_blue_kxr_evb: Enable LEDs. This commit adds leds instances and aliases for them on apollo4p_blue_kxr_evb. Signed-off-by: Aaron Ye --- .../apollo4p_blue_kxr_evb.dts | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+) diff --git a/boards/arm/apollo4p_blue_kxr_evb/apollo4p_blue_kxr_evb.dts b/boards/arm/apollo4p_blue_kxr_evb/apollo4p_blue_kxr_evb.dts index 4644f8ee611..60d99623f3d 100644 --- a/boards/arm/apollo4p_blue_kxr_evb/apollo4p_blue_kxr_evb.dts +++ b/boards/arm/apollo4p_blue_kxr_evb/apollo4p_blue_kxr_evb.dts @@ -17,6 +17,25 @@ }; aliases { watchdog0 = &wdt0; + led0 = &led0; + led1 = &led1; + led2 = &led2; + }; + + leds { + compatible = "gpio-leds"; + led0: led_0 { + gpios = <&gpio0_31 30 GPIO_ACTIVE_LOW>; + label = "LED 0"; + }; + led1: led_1 { + gpios = <&gpio0_31 16 GPIO_ACTIVE_LOW>; + label = "LED 1"; + }; + led2: led_2 { + gpios = <&gpio64_95 27 GPIO_ACTIVE_LOW>; + label = "LED 2"; + }; }; }; From d3cce8805c25d49fcee4d03cc8a3556bcec9c4ec Mon Sep 17 00:00:00 2001 From: Aaron Ye Date: Sat, 2 Dec 2023 08:56:16 +0800 Subject: [PATCH 0810/3723] boards: arm: apollo4p_blue_kxr_evb: Enable buttons. This commit adds buttons instances and aliases for them on apollo4p_blue_kxr_evb. Signed-off-by: Aaron Ye --- .../apollo4p_blue_kxr_evb.dts | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/boards/arm/apollo4p_blue_kxr_evb/apollo4p_blue_kxr_evb.dts b/boards/arm/apollo4p_blue_kxr_evb/apollo4p_blue_kxr_evb.dts index 60d99623f3d..4f698df2b78 100644 --- a/boards/arm/apollo4p_blue_kxr_evb/apollo4p_blue_kxr_evb.dts +++ b/boards/arm/apollo4p_blue_kxr_evb/apollo4p_blue_kxr_evb.dts @@ -6,6 +6,7 @@ / { model = "Ambiq Apollo4 Blue Plus KXR evaluation board"; compatible = "ambiq,apollo4p_blue_kxr_evb"; + chosen { zephyr,itcm = &tcm; zephyr,sram = &sram0; @@ -15,11 +16,14 @@ zephyr,uart-pipe = &uart0; zephyr,flash-controller = &flash; }; + aliases { watchdog0 = &wdt0; led0 = &led0; led1 = &led1; led2 = &led2; + sw0 = &button0; + sw1 = &button1; }; leds { @@ -38,6 +42,17 @@ }; }; + buttons { + compatible = "gpio-keys"; + button0: button_0 { + gpios = <&gpio0_31 17 (GPIO_PULL_UP | GPIO_ACTIVE_LOW)>; + label = "BTN0"; + }; + button1: button_1 { + gpios = <&gpio0_31 19 (GPIO_PULL_UP | GPIO_ACTIVE_LOW)>; + label = "BTN1"; + }; + }; }; &uart0 { From f779385b5960ce744759c91acea249440b2404e1 Mon Sep 17 00:00:00 2001 From: Daniel Leung Date: Mon, 4 Dec 2023 14:23:22 -0800 Subject: [PATCH 0811/3723] scripts: get_maintainer: __init__ to use filename if passed This changes the logic in __init__() so that if a path to MAINTAINERS.yml is passed in, it uses the passed-in value instead of blindly running git to find the top level of Zephyr tree. Signed-off-by: Daniel Leung --- scripts/get_maintainer.py | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/scripts/get_maintainer.py b/scripts/get_maintainer.py index 34db3708f50..08ecc1b8989 100755 --- a/scripts/get_maintainer.py +++ b/scripts/get_maintainer.py @@ -175,12 +175,12 @@ def __init__(self, filename=None): the top-level directory of the Git repository is used, and must exist. """ - self._toplevel = pathlib.Path(_git("rev-parse", "--show-toplevel")) - - if filename is None: - self.filename = self._toplevel / "MAINTAINERS.yml" - else: + if (filename is not None) and (pathlib.Path(filename).exists()): self.filename = pathlib.Path(filename) + self._toplevel = self.filename.parent + else: + self._toplevel = pathlib.Path(_git("rev-parse", "--show-toplevel")) + self.filename = self._toplevel / "MAINTAINERS.yml" self.areas = {} for area_name, area_dict in _load_maintainers(self.filename).items(): From ede9b0337c72ca5312d35961c2bdd4ad9334f42c Mon Sep 17 00:00:00 2001 From: Daniel Leung Date: Mon, 4 Dec 2023 14:26:17 -0800 Subject: [PATCH 0812/3723] doc: ext/gh_utils: pass MAINTAINERS.yml to Maintainers This changes to pass full path of MAINTAINERS.yml to get_maintainer.Maintainers(). Without this, Maintainers would use git to find the top level of Zephyr tree. This restricts building of doc only when the build directory is under Zephyr root. Since we have ZEPHYR_BASE in gh_utils, we can pass full path of MAINTAINERS.yml to Maintainers() so that doc build directory no longer has to be under Zephyr root. Fixes #65037 Signed-off-by: Daniel Leung --- doc/_extensions/zephyr/gh_utils.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/doc/_extensions/zephyr/gh_utils.py b/doc/_extensions/zephyr/gh_utils.py index 38c5cff316e..f2795e88496 100644 --- a/doc/_extensions/zephyr/gh_utils.py +++ b/doc/_extensions/zephyr/gh_utils.py @@ -53,7 +53,7 @@ from get_maintainer import Maintainers -MAINTAINERS : Final[Maintainers] = Maintainers() +MAINTAINERS : Final[Maintainers] = Maintainers(filename=f"{ZEPHYR_BASE}/MAINTAINERS.yml") __version__ = "0.1.0" From 281f27ec38aa2ab663cdacc76827cd55de430bab Mon Sep 17 00:00:00 2001 From: Armin Brauns Date: Thu, 30 Nov 2023 15:26:44 +0000 Subject: [PATCH 0813/3723] drivers: bluetooth: fix and clean up BlueNRG HCI setup() function If no public address was set, it should just do nothing instead of erroring. The function should also be static and there's no need to copy the address struct. Signed-off-by: Armin Brauns --- drivers/bluetooth/hci/spi.c | 22 ++++++++++------------ 1 file changed, 10 insertions(+), 12 deletions(-) diff --git a/drivers/bluetooth/hci/spi.c b/drivers/bluetooth/hci/spi.c index 8b5bbc4bd46..a2cabc46215 100644 --- a/drivers/bluetooth/hci/spi.c +++ b/drivers/bluetooth/hci/spi.c @@ -243,22 +243,20 @@ static int bt_spi_send_aci_config(uint8_t offset, const uint8_t *value, size_t v return bt_hci_cmd_send(BLUENRG_ACI_WRITE_CONFIG_DATA, buf); } -int bt_spi_bluenrg_setup(const struct bt_hci_setup_params *params) +static int bt_spi_bluenrg_setup(const struct bt_hci_setup_params *params) { int ret; - const bt_addr_t addr = params->public_addr; + const bt_addr_t *addr = ¶ms->public_addr; - if (bt_addr_eq(&addr, BT_ADDR_NONE) || bt_addr_eq(&addr, BT_ADDR_ANY)) { - return -EINVAL; - } + if (!bt_addr_eq(addr, BT_ADDR_NONE) && !bt_addr_eq(addr, BT_ADDR_ANY)) { + ret = bt_spi_send_aci_config( + BLUENRG_CONFIG_PUBADDR_OFFSET, + addr->val, sizeof(addr->val)); - ret = bt_spi_send_aci_config( - BLUENRG_CONFIG_PUBADDR_OFFSET, - addr.val, sizeof(addr.val)); - - if (ret != 0) { - LOG_ERR("Failed to set BlueNRG public address (%d)", ret); - return ret; + if (ret != 0) { + LOG_ERR("Failed to set BlueNRG public address (%d)", ret); + return ret; + } } return 0; From b8856aed0daef2c7d6e8a77309f3da2c23d80cc4 Mon Sep 17 00:00:00 2001 From: Armin Brauns Date: Mon, 4 Dec 2023 09:27:55 +0000 Subject: [PATCH 0814/3723] drivers: bluetooth: add more documentation for BT_HCI_SET_PUBLIC_ADDR Hopefully this should now aid driver developers as well as application developers. Signed-off-by: Armin Brauns --- drivers/bluetooth/hci/Kconfig | 3 +++ 1 file changed, 3 insertions(+) diff --git a/drivers/bluetooth/hci/Kconfig b/drivers/bluetooth/hci/Kconfig index 9964b57036f..86e450c52c2 100644 --- a/drivers/bluetooth/hci/Kconfig +++ b/drivers/bluetooth/hci/Kconfig @@ -175,6 +175,9 @@ config BT_HCI_SET_PUBLIC_ADDR public identity through vendor-specific commands. They can then implement the setup() HCI driver API function and get the address to set from the public_addr field. + From the application side, the public address is set using the first call to + bt_id_create(), before calling bt_enable(). + config BT_HCI_SETUP bool help From 47da4e2e76db4854d02a5b6977c7bd24ee4293bb Mon Sep 17 00:00:00 2001 From: Dmitrii Golovanov Date: Fri, 1 Dec 2023 21:19:09 +0100 Subject: [PATCH 0815/3723] twister: Improve recording at Harness The Console Harness is able to parse its log with patterns to compose extracted fields into records in 'recording.csv' file in the test's build directory. This feature allows to extract custom test results like performance counters. With this change the extracted records are also written into 'twister.json' as a part of each test suite object. This makes easier to store all the data collected by the test for its further processing. Other improvements: - compile parsing pattern only once instead of at each input line; - quote fields in '.csv' to avoid unexpected field separators; - make 'regex' a required schema field of 'harness_config'; - Twister documentation update. Signed-off-by: Dmitrii Golovanov --- doc/develop/test/twister.rst | 27 +++++++++----- scripts/pylib/twister/twisterlib/handlers.py | 15 ++++++-- scripts/pylib/twister/twisterlib/harness.py | 29 ++++++++------- scripts/pylib/twister/twisterlib/reports.py | 4 ++ .../pylib/twister/twisterlib/testinstance.py | 1 + scripts/schemas/twister/testsuite-schema.yaml | 4 +- scripts/tests/twister/test_handlers.py | 37 ++++++++----------- scripts/tests/twister/test_harness.py | 2 + 8 files changed, 69 insertions(+), 50 deletions(-) diff --git a/doc/develop/test/twister.rst b/doc/develop/test/twister.rst index 122e9c3871b..4677244725b 100644 --- a/doc/develop/test/twister.rst +++ b/doc/develop/test/twister.rst @@ -478,15 +478,9 @@ harness_config: type: (required) Depends on the regex string to be matched - - record: - regex: (required) - Any string that the particular test case prints to record test - results. - - regex: (required) - Any string that the particular test case prints to confirm test - runs as expected. + regex: (required) + Strings with regular expressions to match with the test's output + to confirm the test runs as expected. ordered: (default False) Check the regular expression strings in orderly or randomly fashion @@ -494,6 +488,21 @@ harness_config: repeat: Number of times to validate the repeated regex expression + record: (optional) + regex: (required) + The regular experssion with named subgroups to match data fields + at the test's output lines where the test provides some custom data + for further analysis. These records will be written into the build + directory 'recording.csv' file as well as 'recording' property + of the test suite object in 'twister.json'. + + For example, to extract three data fields 'metric', 'cycles', 'nanoseconds': + + .. code-block:: yaml + + record: + regex: "(?P.*):(?P.*) cycles, (?P.*) ns" + fixture: Specify a test case dependency on an external device(e.g., sensor), and identify setups that fulfill this dependency. It depends on diff --git a/scripts/pylib/twister/twisterlib/handlers.py b/scripts/pylib/twister/twisterlib/handlers.py index eed3cdae84f..0d6ec5976c7 100755 --- a/scripts/pylib/twister/twisterlib/handlers.py +++ b/scripts/pylib/twister/twisterlib/handlers.py @@ -100,12 +100,19 @@ def get_test_timeout(self): def record(self, harness): if harness.recording: + if self.instance.recording is None: + self.instance.recording = harness.recording.copy() + else: + self.instance.recording.extend(harness.recording) + filename = os.path.join(self.build_dir, "recording.csv") with open(filename, "at") as csvfile: - cw = csv.writer(csvfile, harness.fieldnames, lineterminator=os.linesep) - cw.writerow(harness.fieldnames) - for instance in harness.recording: - cw.writerow(instance) + cw = csv.DictWriter(csvfile, + fieldnames = harness.recording[0].keys(), + lineterminator = os.linesep, + quoting = csv.QUOTE_NONNUMERIC) + cw.writeheader() + cw.writerows(harness.recording) def terminate(self, proc): terminate_process(proc) diff --git a/scripts/pylib/twister/twisterlib/harness.py b/scripts/pylib/twister/twisterlib/harness.py index 8b8ad92fc51..c1d0b6fd23c 100644 --- a/scripts/pylib/twister/twisterlib/harness.py +++ b/scripts/pylib/twister/twisterlib/harness.py @@ -55,8 +55,8 @@ def __init__(self): self.capture_coverage = False self.next_pattern = 0 self.record = None + self.record_pattern = None self.recording = [] - self.fieldnames = [] self.ztest = False self.detected_suite_names = [] self.run_id = None @@ -80,6 +80,16 @@ def configure(self, instance): self.repeat = config.get('repeat', 1) self.ordered = config.get('ordered', True) self.record = config.get('record', {}) + if self.record: + self.record_pattern = re.compile(self.record.get("regex", "")) + + + def get_testcase_name(self): + """ + Get current TestCase name. + """ + return self.id + def process_test(self, line): @@ -172,7 +182,7 @@ def get_testcase_name(self): ''' if self.instance and len(self.instance.testcases) == 1: return self.instance.testcases[0].name - return self.id + return super(Console, self).get_testcase_name() def configure(self, instance): super(Console, self).configure(instance) @@ -240,19 +250,10 @@ def handle(self, line): elif self.GCOV_END in line: self.capture_coverage = False - - if self.record: - pattern = re.compile(self.record.get("regex", "")) - match = pattern.search(line) + if self.record_pattern: + match = self.record_pattern.search(line) if match: - csv = [] - if not self.fieldnames: - for k,v in match.groupdict().items(): - self.fieldnames.append(k) - - for k,v in match.groupdict().items(): - csv.append(v.strip()) - self.recording.append(csv) + self.recording.append({ k:v.strip() for k,v in match.groupdict(default="").items() }) self.process_test(line) # Reset the resulting test state to 'failed' when not all of the patterns were diff --git a/scripts/pylib/twister/twisterlib/reports.py b/scripts/pylib/twister/twisterlib/reports.py index 7425841a723..3d4b155fa9d 100644 --- a/scripts/pylib/twister/twisterlib/reports.py +++ b/scripts/pylib/twister/twisterlib/reports.py @@ -347,6 +347,10 @@ def json_report(self, filename, version="NA", platform=None): testcases.append(testcase) suite['testcases'] = testcases + + if instance.recording is not None: + suite['recording'] = instance.recording + suites.append(suite) report["testsuites"] = suites diff --git a/scripts/pylib/twister/twisterlib/testinstance.py b/scripts/pylib/twister/twisterlib/testinstance.py index d3cbbaf4986..b5e537892a2 100644 --- a/scripts/pylib/twister/twisterlib/testinstance.py +++ b/scripts/pylib/twister/twisterlib/testinstance.py @@ -48,6 +48,7 @@ def __init__(self, testsuite, platform, outdir): self.reason = "Unknown" self.metrics = dict() self.handler = None + self.recording = None self.outdir = outdir self.execution_time = 0 self.build_time = 0 diff --git a/scripts/schemas/twister/testsuite-schema.yaml b/scripts/schemas/twister/testsuite-schema.yaml index 1e198173c72..387a9b884c9 100644 --- a/scripts/schemas/twister/testsuite-schema.yaml +++ b/scripts/schemas/twister/testsuite-schema.yaml @@ -122,7 +122,7 @@ mapping: mapping: "regex": type: str - required: false + required: true "min_ram": type: int required: false @@ -326,7 +326,7 @@ mapping: mapping: "regex": type: str - required: false + required: true "min_ram": type: int required: false diff --git a/scripts/tests/twister/test_handlers.py b/scripts/tests/twister/test_handlers.py index 6675c4ae451..e66b73055c8 100644 --- a/scripts/tests/twister/test_handlers.py +++ b/scripts/tests/twister/test_handlers.py @@ -209,40 +209,35 @@ def test_handler_record(mocked_instance): instance.testcases = [mock.Mock()] handler = Handler(instance) - handler.suite_name_check = True - - harness = twisterlib.harness.Test() - harness.recording = ['dummy recording'] - type(harness).fieldnames = mock.PropertyMock(return_value=[]) - mock_writerow = mock.Mock() - mock_writer = mock.Mock(writerow=mock_writerow) + harness = twisterlib.harness.Harness() + harness.recording = [ {'field_1': 'recording_1_1', 'field_2': 'recording_1_2'}, + {'field_1': 'recording_2_1', 'field_2': 'recording_2_2'} + ] with mock.patch( 'builtins.open', mock.mock_open(read_data='') ) as mock_file, \ - mock.patch( - 'csv.writer', - mock.Mock(return_value=mock_writer) - ) as mock_writer_constructor: + mock.patch( + 'csv.DictWriter.writerow', + mock.Mock() + ) as mock_writeheader, \ + mock.patch( + 'csv.DictWriter.writerows', + mock.Mock() + ) as mock_writerows: handler.record(harness) + print(mock_file.mock_calls) + mock_file.assert_called_with( os.path.join(instance.build_dir, 'recording.csv'), 'at' ) - mock_writer_constructor.assert_called_with( - mock_file(), - harness.fieldnames, - lineterminator=os.linesep - ) - - mock_writerow.assert_has_calls( - [mock.call(harness.fieldnames)] + \ - [mock.call(recording) for recording in harness.recording] - ) + mock_writeheader.assert_has_calls([mock.call({ k:k for k in harness.recording[0].keys()})]) + mock_writerows.assert_has_calls([mock.call(harness.recording)]) def test_handler_terminate(mocked_instance): diff --git a/scripts/tests/twister/test_harness.py b/scripts/tests/twister/test_harness.py index 1da2aed3f46..247a9426f7b 100644 --- a/scripts/tests/twister/test_harness.py +++ b/scripts/tests/twister/test_harness.py @@ -43,6 +43,8 @@ def gtest(): mock_testsuite.detailed_test_id = True mock_testsuite.id = "id" mock_testsuite.testcases = [] + mock_testsuite.harness_config = {} + instance = TestInstance(testsuite=mock_testsuite, platform=mock_platform, outdir="") harness = Gtest() From a3d0c6379732664d000edb5ecad61e2baefcf648 Mon Sep 17 00:00:00 2001 From: Piotr Kosycarz Date: Wed, 6 Dec 2023 13:55:18 +0100 Subject: [PATCH 0816/3723] scripts: twister: testinstance: store run id between builds Cache value of run id between builds. Save it in file and later load during next build. Signed-off-by: Piotr Kosycarz --- .../pylib/twister/twisterlib/testinstance.py | 24 +++++++++++++------ 1 file changed, 17 insertions(+), 7 deletions(-) diff --git a/scripts/pylib/twister/twisterlib/testinstance.py b/scripts/pylib/twister/twisterlib/testinstance.py index b5e537892a2..438572040ca 100644 --- a/scripts/pylib/twister/twisterlib/testinstance.py +++ b/scripts/pylib/twister/twisterlib/testinstance.py @@ -55,7 +55,6 @@ def __init__(self, testsuite, platform, outdir): self.retries = 0 self.name = os.path.join(platform.name, testsuite.name) - self.run_id = self._get_run_id() self.dut = None if testsuite.detailed_test_id: self.build_dir = os.path.join(outdir, platform.name, testsuite.name) @@ -64,6 +63,7 @@ def __init__(self, testsuite, platform, outdir): source_dir_rel = testsuite.source_dir_rel.rsplit(os.pardir+os.path.sep, 1)[-1] self.build_dir = os.path.join(outdir, platform.name, source_dir_rel, testsuite.name) + self.run_id = self._get_run_id() self.domains = None self.run = False @@ -85,12 +85,22 @@ def init_cases(self): def _get_run_id(self): """ generate run id from instance unique identifier and a random - number""" - - hash_object = hashlib.md5(self.name.encode()) - random_str = f"{random.getrandbits(64)}".encode() - hash_object.update(random_str) - return hash_object.hexdigest() + number + If exist, get cached run id from previous run.""" + run_id = "" + run_id_file = os.path.join(self.build_dir, "run_id.txt") + if os.path.exists(run_id_file): + with open(run_id_file, "r") as fp: + run_id = fp.read() + else: + hash_object = hashlib.md5(self.name.encode()) + random_str = f"{random.getrandbits(64)}".encode() + hash_object.update(random_str) + run_id = hash_object.hexdigest() + os.makedirs(self.build_dir, exist_ok=True) + with open(run_id_file, 'w+') as fp: + fp.write(run_id) + return run_id def add_missing_case_status(self, status, reason=None): for case in self.testcases: From 5dcc0d753a93da28f28b265136a80a96e9946ec1 Mon Sep 17 00:00:00 2001 From: Jamie McCrae Date: Fri, 1 Dec 2023 13:04:18 +0000 Subject: [PATCH 0817/3723] cmake: Remove support for deprecated prj_board.conf Removes support for the deprecated features of having a prj file which has the board name on the end of it. Board Kconfig fragments should be used instead. Signed-off-by: Jamie McCrae --- cmake/modules/FindDeprecated.cmake | 7 ------- cmake/modules/configuration_files.cmake | 3 --- .../mec172xevb_assy6906.conf} | 0 3 files changed, 10 deletions(-) rename samples/drivers/espi/{prj_mec172xevb_assy6906.conf => boards/mec172xevb_assy6906.conf} (100%) diff --git a/cmake/modules/FindDeprecated.cmake b/cmake/modules/FindDeprecated.cmake index 66cac2a5583..f80d3419861 100644 --- a/cmake/modules/FindDeprecated.cmake +++ b/cmake/modules/FindDeprecated.cmake @@ -107,13 +107,6 @@ if("SOURCES" IN_LIST Deprecated_FIND_COMPONENTS) endif() endif() -if("PRJ_BOARD" IN_LIST Deprecated_FIND_COMPONENTS) - # This code was deprecated after Zephyr v3.3.0 - list(REMOVE_ITEM Deprecated_FIND_COMPONENTS PRJ_BOARD) - message(DEPRECATION "'prj_.conf' files are deprecated and should be " - "replaced with board Kconfig fragments instead.") -endif() - if("PYTHON_PREFER" IN_LIST Deprecated_FIND_COMPONENTS) # This code was deprecated after Zephyr v3.4.0 list(REMOVE_ITEM Deprecated_FIND_COMPONENTS PYTHON_PREFER) diff --git a/cmake/modules/configuration_files.cmake b/cmake/modules/configuration_files.cmake index 76d19e5ebbb..d4357425d10 100644 --- a/cmake/modules/configuration_files.cmake +++ b/cmake/modules/configuration_files.cmake @@ -68,9 +68,6 @@ elseif(CACHED_CONF_FILE) # That value has precedence over anything else than a new # `cmake -DCONF_FILE=` invocation. set(CONF_FILE ${CACHED_CONF_FILE}) -elseif(EXISTS ${APPLICATION_CONFIG_DIR}/prj_${BOARD}.conf) - set(CONF_FILE ${APPLICATION_CONFIG_DIR}/prj_${BOARD}.conf) - find_package(Deprecated COMPONENTS PRJ_BOARD) elseif(EXISTS ${APPLICATION_CONFIG_DIR}/prj.conf) set(CONF_FILE ${APPLICATION_CONFIG_DIR}/prj.conf) set(CONF_FILE_INCLUDE_FRAGMENTS true) diff --git a/samples/drivers/espi/prj_mec172xevb_assy6906.conf b/samples/drivers/espi/boards/mec172xevb_assy6906.conf similarity index 100% rename from samples/drivers/espi/prj_mec172xevb_assy6906.conf rename to samples/drivers/espi/boards/mec172xevb_assy6906.conf From 29e0c6c809e037dd3e79711b10877555ab89eef0 Mon Sep 17 00:00:00 2001 From: Jamie McCrae Date: Fri, 1 Dec 2023 13:08:11 +0000 Subject: [PATCH 0818/3723] doc: migration-guide: 3.6: Add note on prj_board.conf removal Adds a note on the removal of this option and how to adapt projects Signed-off-by: Jamie McCrae --- doc/releases/migration-guide-3.6.rst | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/doc/releases/migration-guide-3.6.rst b/doc/releases/migration-guide-3.6.rst index 36ef77f1deb..e3daffe35ab 100644 --- a/doc/releases/migration-guide-3.6.rst +++ b/doc/releases/migration-guide-3.6.rst @@ -17,8 +17,14 @@ Required changes Boards ====== - * The deprecated Nordic SoC Kconfig option ``NRF_STORE_REBOOT_TYPE_GPREGRET`` has been removed, - applications that use this should switch to using the :ref:`boot_mode_api` instead. +* The deprecated Nordic SoC Kconfig option ``NRF_STORE_REBOOT_TYPE_GPREGRET`` has been removed, + applications that use this should switch to using the :ref:`boot_mode_api` instead. + +Build System +============ + +* The deprecated ``prj_.conf`` Kconfig file support has been removed, projects that use + this should switch to using board Kconfig fragments instead (``boards/.conf``). Kernel ====== From 790388b7c0aa1dbdd232fcf920710a1ab8ab78d8 Mon Sep 17 00:00:00 2001 From: Torsten Rasmussen Date: Wed, 6 Dec 2023 11:51:36 +0100 Subject: [PATCH 0819/3723] cmake: tfm: propagate Zephyr Python3 interpreter to TF-M build The TF-M build uses the vanilla CMake FindPython3 mechanism which in several cases misbehaves, see #24308 for details. Ensure TF-M build uses same Python interpreter as Zephyr itself. Signed-off-by: Torsten Rasmussen --- modules/trusted-firmware-m/CMakeLists.txt | 1 + 1 file changed, 1 insertion(+) diff --git a/modules/trusted-firmware-m/CMakeLists.txt b/modules/trusted-firmware-m/CMakeLists.txt index 177a47e28d6..ae5941e5ef6 100644 --- a/modules/trusted-firmware-m/CMakeLists.txt +++ b/modules/trusted-firmware-m/CMakeLists.txt @@ -331,6 +331,7 @@ if (CONFIG_BUILD_WITH_TFM) -DTFM_PLATFORM=${CONFIG_TFM_BOARD} -DCONFIG_TFM_BUILD_LOG_QUIET=ON -DCONFIG_TFM_MEMORY_USAGE_QUIET=OFF + -DPython3_EXECUTABLE=${Python3_EXECUTABLE} ${TFM_CMAKE_ARGS} $> -DMBEDCRYPTO_PATH=$>,$,${ZEPHYR_MBEDTLS_MODULE_DIR}> From 031c842ecb768a2a98c33bd0259387e990cfece1 Mon Sep 17 00:00:00 2001 From: Henrik Brix Andersen Date: Wed, 6 Dec 2023 16:18:32 +0100 Subject: [PATCH 0820/3723] samples: userspace: hello_world_user: exclude qemu_xtensa_mmu Exclude the qemu_xtensa_mmu platform from this sample until #66029 is fixed. Signed-off-by: Henrik Brix Andersen --- samples/userspace/hello_world_user/sample.yaml | 2 ++ 1 file changed, 2 insertions(+) diff --git a/samples/userspace/hello_world_user/sample.yaml b/samples/userspace/hello_world_user/sample.yaml index f782f36cad4..b40042f71f5 100644 --- a/samples/userspace/hello_world_user/sample.yaml +++ b/samples/userspace/hello_world_user/sample.yaml @@ -16,4 +16,6 @@ tests: filter: CONFIG_ARCH_HAS_USERSPACE arch_exclude: - posix + platform_exclude: + - qemu_xtensa_mmu tags: introduction From c9daed971268f31f5c73416b79df1af30a41d800 Mon Sep 17 00:00:00 2001 From: Emil Gydesen Date: Fri, 13 Oct 2023 11:16:50 +0200 Subject: [PATCH 0821/3723] Bluetooth: BAP: Refactor bt_bap_base This removes the fixed size bt_bap_base, which provides 2 improvements: 1) The RAM usage of the broadcast sink has been reduced. For the Broadcast Sink sample it is a reduction of 120 octets, but with much better scaling for supporting more or larger BASEs. 2) The functions to parse BASEs now support arbitrary sized BASEs, where they were previously restricted by our local Kconfig options. This allow us to parse any BASE from a remote device, without encounting memory issues. We are still memory restricted on the devices we actually want to sync to. Signed-off-by: Emil Gydesen --- include/zephyr/bluetooth/audio/bap.h | 225 +++++-- .../bluetooth/broadcast_audio_sink/src/main.c | 79 ++- .../tmap_bmr/src/bap_broadcast_sink.c | 24 +- subsys/bluetooth/Kconfig.logging | 5 + subsys/bluetooth/audio/CMakeLists.txt | 1 + subsys/bluetooth/audio/Kconfig.bap | 3 + subsys/bluetooth/audio/audio.c | 211 ------- subsys/bluetooth/audio/bap_base.c | 564 ++++++++++++++++++ subsys/bluetooth/audio/bap_broadcast_sink.c | 311 ++++++---- subsys/bluetooth/audio/bap_endpoint.h | 13 +- subsys/bluetooth/audio/shell/audio.h | 94 ++- subsys/bluetooth/audio/shell/bap.c | 79 +-- .../audio/shell/bap_broadcast_assistant.c | 115 ++-- tests/bluetooth/tester/src/btp_bap.c | 82 ++- .../audio/src/bap_broadcast_assistant_test.c | 3 + .../audio/src/bap_broadcast_sink_test.c | 59 +- .../audio/src/bap_broadcast_source_test.c | 39 +- .../bluetooth/audio/src/cap_acceptor_test.c | 54 +- 18 files changed, 1305 insertions(+), 656 deletions(-) create mode 100644 subsys/bluetooth/audio/bap_base.c diff --git a/include/zephyr/bluetooth/audio/bap.h b/include/zephyr/bluetooth/audio/bap.h index 77c63ba598b..f2c231dcd81 100644 --- a/include/zephyr/bluetooth/audio/bap.h +++ b/include/zephyr/bluetooth/audio/bap.h @@ -34,22 +34,6 @@ extern "C" { #define BT_BAP_SCAN_DELEGATOR_MAX_SUBGROUPS 0 #endif -/** The minimum size of a Broadcast Audio Source Endpoint (BASE) - * 2 octets UUID - * 3 octets presentation delay - * 1 octet number of subgroups (which is minimum 1) - * 1 octet number of BIS (which is minimum 1) - * 5 octets codec_id - * 1 octet codec configuration length (which may be 0) - * 1 octet metadata length (which may be 0) - * 1 octet BIS index - * 1 octet BIS specific codec configuration length (which may be 0) - */ -#define BT_BAP_BASE_MIN_SIZE 16 - -/** The minimum size of a bt_bap_base_bis_data */ -#define BT_BAP_BASE_BIS_DATA_MIN_SIZE 2 /* index and length */ - /** Periodic advertising state reported by the Scan Delegator */ enum bt_bap_pa_state { /** The periodic advertising has not been synchronized */ @@ -102,17 +86,6 @@ enum bt_bap_bass_att_err { */ #define BT_BAP_BIS_SYNC_NO_PREF 0xFFFFFFFF -#if defined(CONFIG_BT_BAP_BROADCAST_SINK) -/* TODO: Since these are also used for the broadcast assistant, - * they should not be tied to the broadcast sink - */ -#define BROADCAST_SNK_STREAM_CNT CONFIG_BT_BAP_BROADCAST_SNK_STREAM_COUNT -#define BROADCAST_SNK_SUBGROUP_CNT CONFIG_BT_BAP_BROADCAST_SNK_SUBGROUP_COUNT -#else /* !CONFIG_BT_BAP_BROADCAST_SINK */ -#define BROADCAST_SNK_STREAM_CNT 0 -#define BROADCAST_SNK_SUBGROUP_CNT 0 -#endif /* CONFIG_BT_BAP_BROADCAST_SINK*/ - /** Endpoint states */ enum bt_bap_ep_state { /** Audio Stream Endpoint Idle state */ @@ -276,7 +249,6 @@ struct bt_bap_unicast_group; /** @brief Abstract Audio Endpoint structure. */ struct bt_bap_ep; -/* TODO: Replace with struct bt_bap_base_subgroup */ /** Struct to hold subgroup specific information for the receive state */ struct bt_bap_scan_delegator_subgroup { /** BIS synced bitfield */ @@ -1351,55 +1323,178 @@ int bt_bap_unicast_client_discover(struct bt_conn *conn, enum bt_audio_dir dir); * @{ */ -struct bt_bap_base_bis_data { +/** @brief Abstract Broadcast Audio Source Endpoint (BASE) subgroup structure. */ +struct bt_bap_base_subgroup; +/** @brief Abstract Broadcast Audio Source Endpoint (BASE) structure. */ +struct bt_bap_base; + +/** Codec ID structure for a Broadcast Audio Source Endpoint (BASE) */ +struct bt_bap_base_codec_id { + /** Codec ID */ + uint8_t id; + /** Codec Company ID */ + uint16_t cid; + /** Codec Company Vendor ID */ + uint16_t vid; +}; + +/** BIS structure for each BIS in a Broadcast Audio Source Endpoint (BASE) subgroup */ +struct bt_bap_base_subgroup_bis { /* Unique index of the BIS */ uint8_t index; -#if CONFIG_BT_AUDIO_CODEC_CFG_MAX_DATA_SIZE > 0 /** Codec Specific Data length. */ - size_t data_len; + uint8_t data_len; /** Codec Specific Data */ - uint8_t data[CONFIG_BT_AUDIO_CODEC_CFG_MAX_DATA_SIZE]; -#endif /* CONFIG_BT_AUDIO_CODEC_CFG_MAX_DATA_SIZE > 0 */ + uint8_t *data; }; -struct bt_bap_base_subgroup { - /* Number of BIS in the subgroup */ - size_t bis_count; - /** Codec information for the subgroup - * - * If the data_len of the codec is 0, then codec specific data may be - * found for each BIS in the bis_data. - */ - struct bt_audio_codec_cfg codec_cfg; - /* Array of BIS specific data for each BIS in the subgroup */ - struct bt_bap_base_bis_data bis_data[BROADCAST_SNK_STREAM_CNT]; -}; +/** + * @brief Generate a pointer to a BASE from periodic advertising data + * + * @param ad The periodic advertising data + * + * @retval NULL if the data does not contain a BASE + * @retval Pointer to a bt_bap_base structure + */ +const struct bt_bap_base *bt_bap_base_get_base_from_ad(const struct bt_data *ad); -struct bt_bap_base { - /** @brief QoS Presentation Delay in microseconds - * - * Value range 0 to @ref BT_AUDIO_PD_MAX. - */ - uint32_t pd; +/** + * @brief Get the presentation delay value of a BASE + * + * @param base The BASE pointer + * + * @retval -EINVAL if arguments are invalid + * @retval The 24-bit presentation delay value + */ +int bt_bap_base_get_pres_delay(const struct bt_bap_base *base); - /* Number of subgroups in the BASE */ - size_t subgroup_count; +/** + * @brief Get the subgroup count of a BASE + * + * @param base The BASE pointer + * + * @retval -EINVAL if arguments are invalid + * @retval The 8-bit subgroup count value + */ +int bt_bap_base_get_subgroup_count(const struct bt_bap_base *base); - /* Array of subgroups in the BASE */ - struct bt_bap_base_subgroup subgroups[BROADCAST_SNK_SUBGROUP_CNT]; -}; +/** + * @brief Get all BIS indexes of a BASE + * + * @param[in] base The BASE pointer + * @param[out] bis_indexes 32-bit BIS index bitfield that will be populated + * + * @retval -EINVAL if arguments are invalid + * @retval 0 on success + */ +int bt_bap_base_get_bis_indexes(const struct bt_bap_base *base, uint32_t *bis_indexes); + +/** + * @brief Iterate on all subgroups in the BASE + * + * @param base The BASE pointer + * @param func Callback function. Return true to continue iterating, or false to stop. + * @param user_data Userdata supplied to @p func + * + * @retval -EINVAL if arguments are invalid + * @retval -ECANCELED if iterating over the subgroups stopped prematurely by @p func + * @retval 0 if all subgroups were iterated + */ +int bt_bap_base_foreach_subgroup(const struct bt_bap_base *base, + bool (*func)(const struct bt_bap_base_subgroup *subgroup, + void *user_data), + void *user_data); + +/** + * @brief Get the codec ID of a subgroup + * + * @param[in] subgroup The subgroup pointer + * @param[out] codec_id Pointer to the struct where the results are placed + * + * @retval -EINVAL if arguments are invalid + * @retval 0 on success + */ +int bt_bap_base_get_subgroup_codec_id(const struct bt_bap_base_subgroup *subgroup, + struct bt_bap_base_codec_id *codec_id); + +/** + * @brief Get the codec configuration data of a subgroup + * + * @param[in] subgroup The subgroup pointer + * @param[out] data Pointer that will point to the resulting codec configuration data + * + * @retval -EINVAL if arguments are invalid + * @retval 0 on success + */ +int bt_bap_base_get_subgroup_codec_data(const struct bt_bap_base_subgroup *subgroup, + uint8_t **data); + +/** + * @brief Get the codec metadata of a subgroup + * + * @param[in] subgroup The subgroup pointer + * @param[out] meta Pointer that will point to the resulting codec metadata + * + * @retval -EINVAL if arguments are invalid + * @retval 0 on success + */ +int bt_bap_base_get_subgroup_codec_meta(const struct bt_bap_base_subgroup *subgroup, + uint8_t **meta); -/** @brief Decode a Broadcast Audio Source Endpoint (BASE) from advertising data +/** + * @brief Store subgroup codec data in a @ref bt_audio_codec_cfg + * + * @param[in] subgroup The subgroup pointer + * @param[out] codec_cfg Pointer to the struct where the results are placed * - * The BASE is sent via periodic advertising, and can be decoded into a - * bt_bap_base using this function. + * @retval -EINVAL if arguments are invalid + * @retval -ENOMEM if the @p codec_cfg cannot store the @p subgroup codec data + * @retval 0 on success + */ +int bt_bap_base_subgroup_codec_to_codec_cfg(const struct bt_bap_base_subgroup *subgroup, + struct bt_audio_codec_cfg *codec_cfg); + +/** + * @brief Get the BIS count of a subgroup * - * @param data The periodic advertising data - * @param base The output struct to put the decode BASE in + * @param subgroup The subgroup pointer * - * @return 0 in case of success or negative errno value in case of error. + * @retval -EINVAL if arguments are invalid + * @retval The 8-bit BIS count value + */ +int bt_bap_base_get_subgroup_bis_count(const struct bt_bap_base_subgroup *subgroup); + +/** + * @brief Iterate on all BIS in the subgroup + * + * @param subgroup The subgroup pointer + * @param func Callback function. Return true to continue iterating, or false to stop. + * @param user_data Userdata supplied to @p func + * + * @retval -EINVAL if arguments are invalid + * @retval -ECANCELED if iterating over the subgroups stopped prematurely by @p func + * @retval 0 if all BIS were iterated + */ +int bt_bap_base_subgroup_foreach_bis(const struct bt_bap_base_subgroup *subgroup, + bool (*func)(const struct bt_bap_base_subgroup_bis *bis, + void *user_data), + void *user_data); + +/** + * @brief Store BIS codec configuration data in a @ref bt_audio_codec_cfg + * + * This only sets the @ref bt_audio_codec_cfg data and @ref bt_audio_codec_cfg data_len, but is + * useful to use the BIS codec configuration data with the bt_audio_codec_cfg_* functions. + * + * @param[in] bis The BIS pointer + * @param[out] codec_cfg Pointer to the struct where the results are placed + * + * @retval -EINVAL if arguments are invalid + * @retval -ENOMEM if the @p codec_cfg cannot store the @p subgroup codec data + * @retval 0 on success */ -int bt_bap_decode_base(struct bt_data *data, struct bt_bap_base *base); +int bt_bap_base_subgroup_bis_codec_to_codec_cfg(const struct bt_bap_base_subgroup_bis *bis, + struct bt_audio_codec_cfg *codec_cfg); /** @} */ /* End of group bt_bap_broadcast */ @@ -1649,8 +1744,10 @@ struct bt_bap_broadcast_sink_cb { * * @param sink Pointer to the sink structure. * @param base Broadcast Audio Source Endpoint (BASE). + * @param base_size Size of the @p base */ - void (*base_recv)(struct bt_bap_broadcast_sink *sink, const struct bt_bap_base *base); + void (*base_recv)(struct bt_bap_broadcast_sink *sink, const struct bt_bap_base *base, + size_t base_size); /** @brief Broadcast sink is syncable * diff --git a/samples/bluetooth/broadcast_audio_sink/src/main.c b/samples/bluetooth/broadcast_audio_sink/src/main.c index 6b519b715f6..c9199f80673 100644 --- a/samples/bluetooth/broadcast_audio_sink/src/main.c +++ b/samples/bluetooth/broadcast_audio_sink/src/main.c @@ -252,44 +252,71 @@ static struct bt_bap_stream_ops stream_ops = { .recv = stream_recv_cb, }; -static void base_recv_cb(struct bt_bap_broadcast_sink *sink, const struct bt_bap_base *base) +#if defined(CONFIG_LIBLC3) +static bool base_subgroup_cb(const struct bt_bap_base_subgroup *subgroup, void *user_data) { - uint32_t base_bis_index_bitfield = 0U; + struct bt_audio_codec_cfg *codec_cfg = user_data; + struct bt_bap_base_codec_id codec_id; + int ret; - if (k_sem_count_get(&sem_base_received) != 0U) { - return; + ret = bt_bap_base_get_subgroup_codec_id(subgroup, &codec_id); + if (ret < 0) { + printk("Could not get codec id for subgroup %p: %d", subgroup, ret); + return true; } - printk("Received BASE with %u subgroups from broadcast sink %p\n", - base->subgroup_count, sink); + if (codec_id.id != BT_HCI_CODING_FORMAT_LC3) { + printk("Unsupported codec for subgroup %p: 0x%02x", subgroup, codec_id.id); + return true; /* parse next subgroup */ + } - for (size_t i = 0U; i < base->subgroup_count; i++) { - const size_t bis_count = base->subgroups[i].bis_count; + ret = bt_bap_base_subgroup_codec_to_codec_cfg(subgroup, codec_cfg); + if (ret < 0) { + printk("Could convert subgroup %p to codec_cfg: %d", subgroup, ret); + return true; + } - printk("Subgroup[%zu] has %zu streams\n", i, bis_count); + return false; /* We only care about the first subgroup with LC3 */ +} +#endif /* CONFIG_LIBLC3 */ - for (size_t j = 0U; j < bis_count; j++) { - const uint8_t index = base->subgroups[i].bis_data[j].index; +static void base_recv_cb(struct bt_bap_broadcast_sink *sink, const struct bt_bap_base *base, + size_t base_size) +{ + uint32_t base_bis_index_bitfield = 0U; + int err; - printk("\tIndex 0x%02x\n", index); + if (k_sem_count_get(&sem_base_received) != 0U) { + return; + } + + printk("Received BASE with %d subgroups from broadcast sink %p\n", + bt_bap_base_get_subgroup_count(base), sink); - base_bis_index_bitfield |= BIT(index); - } #if defined(CONFIG_LIBLC3) - int ret; - const struct bt_audio_codec_cfg *codec_cfg = &base->subgroups[i].codec_cfg; + struct bt_audio_codec_cfg codec_cfg = {0}; - if (codec_cfg->id != BT_HCI_CODING_FORMAT_LC3) { - printk("unsupported codec 0x%02x", codec_cfg->id); - return; - } + err = bt_bap_base_foreach_subgroup(base, base_subgroup_cb, &codec_cfg); + if (err != 0 && err != -ECANCELED) { + printk("Failed to parse subgroups: %d\n", err); + return; + } else if (codec_cfg.id != BT_HCI_CODING_FORMAT_LC3) { + /* No subgroups with LC3 was found */ + printk("Did not parse an LC3 codec\n"); + return; + } - ret = lc3_enable(codec_cfg); - if (ret < 0) { - printk("Error: cannot enable LC3 codec: %d", ret); - return; - } -#endif /* defined(CONFIG_LIBLC3) */ + err = lc3_enable(&codec_cfg); + if (err < 0) { + printk("Error: cannot enable LC3 codec: %d", err); + return; + } +#endif /* CONFIG_LIBLC3 */ + + err = bt_bap_base_get_bis_indexes(base, &base_bis_index_bitfield); + if (err != 0) { + printk("Failed to BIS indexes: %d\n", err); + return; } bis_index_bitfield = base_bis_index_bitfield & bis_index_mask; diff --git a/samples/bluetooth/tmap_bmr/src/bap_broadcast_sink.c b/samples/bluetooth/tmap_bmr/src/bap_broadcast_sink.c index 7a306cfb304..cc6c95a3fe6 100644 --- a/samples/bluetooth/tmap_bmr/src/bap_broadcast_sink.c +++ b/samples/bluetooth/tmap_bmr/src/bap_broadcast_sink.c @@ -215,29 +215,20 @@ static void broadcast_scan_timeout(void) static bool pa_decode_base(struct bt_data *data, void *user_data) { + const struct bt_bap_base *base = bt_bap_base_get_base_from_ad(data); uint32_t base_bis_index_bitfield = 0U; - struct bt_bap_base base = { 0 }; - - if (data->type != BT_DATA_SVC_DATA16) { - return true; - } + int err; - if (data->data_len < BT_BAP_BASE_MIN_SIZE) { + /* Base is NULL if the data does not contain a valid BASE */ + if (base == NULL) { return true; } - if (bt_bap_decode_base(data, &base) != 0) { + err = bt_bap_base_get_bis_indexes(base, &base_bis_index_bitfield); + if (err != 0) { return false; } - for (size_t i = 0U; i < base.subgroup_count; i++) { - for (size_t j = 0U; j < base.subgroups[i].bis_count; j++) { - const uint8_t index = base.subgroups[i].bis_data[j].index; - - base_bis_index_bitfield |= BIT(index); - } - } - bis_index_bitfield = base_bis_index_bitfield & bis_index_mask; k_sem_give(&sem_base_received); @@ -256,7 +247,8 @@ static void syncable_cb(struct bt_bap_broadcast_sink *sink, bool encrypted) k_sem_give(&sem_syncable); } -static void base_recv_cb(struct bt_bap_broadcast_sink *sink, const struct bt_bap_base *base) +static void base_recv_cb(struct bt_bap_broadcast_sink *sink, const struct bt_bap_base *base, + size_t base_size) { k_sem_give(&sem_base_received); } diff --git a/subsys/bluetooth/Kconfig.logging b/subsys/bluetooth/Kconfig.logging index 6d8b999e03c..679d719cdad 100644 --- a/subsys/bluetooth/Kconfig.logging +++ b/subsys/bluetooth/Kconfig.logging @@ -659,6 +659,11 @@ legacy-debug-sym = BT_BAP_DEBUG_STREAM module-str = "Bluetooth Audio Stream" source "subsys/bluetooth/common/Kconfig.template.log_config_bt" +parent-module = BT +module = BT_BAP_BASE +module-str = "Bluetooth Basic Audio Profile Broadcast Audio Source Endpoint" +source "subsys/logging/Kconfig.template.log_config_inherit" + parent-module = BT module = BT_AUDIO_CODEC module-str = "Bluetooth Audio Codec" diff --git a/subsys/bluetooth/audio/CMakeLists.txt b/subsys/bluetooth/audio/CMakeLists.txt index 2ae08c2d7b5..5c2a6eb3fea 100644 --- a/subsys/bluetooth/audio/CMakeLists.txt +++ b/subsys/bluetooth/audio/CMakeLists.txt @@ -49,6 +49,7 @@ zephyr_library_sources_ifdef(CONFIG_MCTL media_proxy.c) zephyr_library_sources_ifdef(CONFIG_BT_ASCS ascs.c) zephyr_library_sources_ifdef(CONFIG_BT_PACS pacs.c) zephyr_library_sources_ifdef(CONFIG_BT_BAP_STREAM bap_stream.c codec.c bap_iso.c) +zephyr_library_sources_ifdef(CONFIG_BT_BAP_BASE bap_base.c) zephyr_library_sources_ifdef(CONFIG_BT_BAP_UNICAST_SERVER bap_unicast_server.c) zephyr_library_sources_ifdef(CONFIG_BT_BAP_UNICAST_CLIENT bap_unicast_client.c) zephyr_library_sources_ifdef(CONFIG_BT_BAP_BROADCAST_SOURCE bap_broadcast_source.c) diff --git a/subsys/bluetooth/audio/Kconfig.bap b/subsys/bluetooth/audio/Kconfig.bap index 0b5e1c3e291..6921cf2c8c0 100644 --- a/subsys/bluetooth/audio/Kconfig.bap +++ b/subsys/bluetooth/audio/Kconfig.bap @@ -286,5 +286,8 @@ config BT_BAP_DEBUG_STREAM_SEQ_NUM the Bluetooth Audio functionality. This will provide a warning if the application provides unexpected sequence numbers. +config BT_BAP_BASE + def_bool BT_BAP_BROADCAST_SINK || BT_BAP_BROADCAST_ASSISTANT || BT_BAP_SCAN_DELEGATOR + rsource "Kconfig.pacs" rsource "Kconfig.ascs" diff --git a/subsys/bluetooth/audio/audio.c b/subsys/bluetooth/audio/audio.c index 31e8548376e..164a52afa5e 100644 --- a/subsys/bluetooth/audio/audio.c +++ b/subsys/bluetooth/audio/audio.c @@ -154,214 +154,3 @@ ssize_t bt_audio_ccc_cfg_write(struct bt_conn *conn, const struct bt_gatt_attr * return sizeof(value); } #endif /* CONFIG_BT_CONN */ - -/* Broadcast sink depends on Scan Delegator, so we can just guard it with the Scan Delegator */ -#if defined(CONFIG_BT_BAP_SCAN_DELEGATOR) - -static int decode_bis_data(struct net_buf_simple *buf, struct bt_bap_base_bis_data *bis) -{ - uint8_t len; - - if (buf->len < BT_BAP_BASE_BIS_DATA_MIN_SIZE) { - LOG_DBG("Not enough bytes (%u) to decode BIS data", buf->len); - - return -ENOMEM; - } - - bis->index = net_buf_simple_pull_u8(buf); - if (!IN_RANGE(bis->index, BT_ISO_BIS_INDEX_MIN, BT_ISO_BIS_INDEX_MAX)) { - LOG_DBG("Invalid BIS index %u", bis->index); - - return -EINVAL; - } - - /* codec config data length */ - len = net_buf_simple_pull_u8(buf); - if (len > buf->len) { - LOG_DBG("Invalid BIS specific codec config data length: %u (buf is %u)", len, - buf->len); - - return -EMSGSIZE; - } - - if (len > 0) { -#if CONFIG_BT_AUDIO_CODEC_CFG_MAX_METADATA_SIZE > 0 - void *ltv_data; - - if (len > sizeof(bis->data)) { - LOG_DBG("Cannot store codec config data of length %u", len); - - return -ENOMEM; - } - - ltv_data = net_buf_simple_pull_mem(buf, len); - - bis->data_len = len; - memcpy(bis->data, ltv_data, len); -#else /* CONFIG_BT_AUDIO_CODEC_CFG_MAX_METADATA_SIZE == 0 */ - LOG_DBG("Cannot store codec config data"); - - return -ENOMEM; -#endif /* CONFIG_BT_AUDIO_CODEC_CFG_MAX_METADATA_SIZE */ - } - - return 0; -} - -static int decode_subgroup(struct net_buf_simple *buf, struct bt_bap_base_subgroup *subgroup) -{ - struct bt_audio_codec_cfg *codec_cfg; - uint8_t len; - - codec_cfg = &subgroup->codec_cfg; - - subgroup->bis_count = net_buf_simple_pull_u8(buf); - if (subgroup->bis_count > ARRAY_SIZE(subgroup->bis_data)) { - LOG_DBG("BASE has more BIS %u than we support %u", subgroup->bis_count, - (uint8_t)ARRAY_SIZE(subgroup->bis_data)); - - return -ENOMEM; - } - - codec_cfg->id = net_buf_simple_pull_u8(buf); - codec_cfg->cid = net_buf_simple_pull_le16(buf); - codec_cfg->vid = net_buf_simple_pull_le16(buf); - - /* codec configuration data length */ - len = net_buf_simple_pull_u8(buf); - if (len > buf->len) { - LOG_DBG("Invalid codec config data length: %u (buf is %u)", len, buf->len); - - return -EINVAL; - } - -#if CONFIG_BT_AUDIO_CODEC_CFG_MAX_DATA_SIZE > 0 - void *cfg_ltv_data; - - if (len > sizeof(subgroup->codec_cfg.data)) { - LOG_DBG("Cannot store codec config data of length %u", len); - - return -ENOMEM; - } - - cfg_ltv_data = net_buf_simple_pull_mem(buf, len); - - subgroup->codec_cfg.data_len = len; - memcpy(subgroup->codec_cfg.data, cfg_ltv_data, len); -#else /* CONFIG_BT_AUDIO_CODEC_CFG_MAX_DATA_SIZE == 0 */ - if (len > 0) { - LOG_DBG("Cannot store codec config data of length %u", len); - - return -ENOMEM; - } -#endif /* CONFIG_BT_AUDIO_CODEC_CFG_MAX_DATA_SIZE > 0 */ - - /* codec metadata length */ - len = net_buf_simple_pull_u8(buf); - if (len > buf->len) { - LOG_DBG("Invalid codec config data length: %u (buf is %u)", len, buf->len); - - return -EMSGSIZE; - } - -#if CONFIG_BT_AUDIO_CODEC_CFG_MAX_METADATA_SIZE > 0 - void *meta_ltv_data; - - if (len > sizeof(subgroup->codec_cfg.meta)) { - LOG_DBG("Cannot store codec config meta of length %u", len); - - return -ENOMEM; - } - - meta_ltv_data = net_buf_simple_pull_mem(buf, len); - - subgroup->codec_cfg.meta_len = len; - memcpy(subgroup->codec_cfg.meta, meta_ltv_data, len); -#else /* CONFIG_BT_AUDIO_CODEC_CFG_MAX_METADATA_SIZE == 0 */ - if (len > 0) { - LOG_DBG("Cannot store metadata"); - - return -ENOMEM; - } -#endif /* CONFIG_BT_AUDIO_CODEC_CFG_MAX_METADATA_SIZE */ - - for (size_t i = 0U; i < subgroup->bis_count; i++) { - const int err = decode_bis_data(buf, &subgroup->bis_data[i]); - - if (err != 0) { - LOG_DBG("Failed to decode BIS data for bis[%zu]: %d", i, err); - - return err; - } - } - - return 0; -} - -int bt_bap_decode_base(struct bt_data *data, struct bt_bap_base *base) -{ - struct bt_uuid_16 broadcast_uuid; - struct net_buf_simple net_buf; - void *uuid; - - CHECKIF(data == NULL) { - LOG_DBG("data is NULL"); - - return -EINVAL; - } - - CHECKIF(base == NULL) { - LOG_DBG("base is NULL"); - - return -EINVAL; - } - - if (data->type != BT_DATA_SVC_DATA16) { - LOG_DBG("Invalid type: %u", data->type); - - return -ENOMSG; - } - - if (data->data_len < BT_BAP_BASE_MIN_SIZE) { - return -EMSGSIZE; - } - - net_buf_simple_init_with_data(&net_buf, (void *)data->data, - data->data_len); - - uuid = net_buf_simple_pull_mem(&net_buf, BT_UUID_SIZE_16); - if (!bt_uuid_create(&broadcast_uuid.uuid, uuid, BT_UUID_SIZE_16)) { - LOG_ERR("bt_uuid_create failed"); - - return -EINVAL; - } - - if (bt_uuid_cmp(&broadcast_uuid.uuid, BT_UUID_BASIC_AUDIO) != 0) { - LOG_DBG("Invalid UUID"); - - return -ENOMSG; - } - - base->pd = net_buf_simple_pull_le24(&net_buf); - base->subgroup_count = net_buf_simple_pull_u8(&net_buf); - - if (base->subgroup_count > ARRAY_SIZE(base->subgroups)) { - LOG_DBG("Cannot decode BASE with %u subgroups (max supported is %zu)", - base->subgroup_count, ARRAY_SIZE(base->subgroups)); - - return -ENOMEM; - } - - for (size_t i = 0U; i < base->subgroup_count; i++) { - const int err = decode_subgroup(&net_buf, &base->subgroups[i]); - - if (err != 0) { - LOG_DBG("Failed to decode subgroup[%zu]: %d", i, err); - - return err; - } - } - - return 0; -} -#endif /* CONFIG_BT_BAP_SCAN_DELEGATOR */ diff --git a/subsys/bluetooth/audio/bap_base.c b/subsys/bluetooth/audio/bap_base.c new file mode 100644 index 00000000000..67a58c27a3b --- /dev/null +++ b/subsys/bluetooth/audio/bap_base.c @@ -0,0 +1,564 @@ +/* bap_base.c - BAP BASE handling */ + +/* + * Copyright (c) 2023 Nordic Semiconductor ASA + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include +#include +#include +#include +#include + +LOG_MODULE_REGISTER(bt_bap_base, CONFIG_BT_BAP_BASE_LOG_LEVEL); + +/* The BASE and the following defines are defined by BAP v1.0.1, section 3.7.2.2 Basic Audio + * Announcements + */ +#define BASE_MAX_SIZE (UINT8_MAX - 1 /* type */ - BT_UUID_SIZE_16) +#define BASE_CODEC_ID_SIZE (1 /* id */ + 2 /* cid */ + 2 /* vid */) +#define BASE_PD_SIZE 3 +#define BASE_SUBGROUP_COUNT_SIZE 1 +#define BASE_NUM_BIS_SIZE 1 +#define BASE_CC_LEN_SIZE 1 +#define BASE_META_LEN_SIZE 1 +#define BASE_BIS_INDEX_SIZE 1 +#define BASE_BIS_CC_LEN_SIZE 1 +#define BASE_SUBGROUP_MAX_SIZE (BASE_MAX_SIZE - BASE_PD_SIZE - BASE_SUBGROUP_COUNT_SIZE) +#define BASE_SUBGROUP_MIN_SIZE \ + (BASE_NUM_BIS_SIZE + BASE_CODEC_ID_SIZE + BASE_CC_LEN_SIZE + BASE_META_LEN_SIZE + \ + BASE_BIS_INDEX_SIZE + BASE_BIS_CC_LEN_SIZE) +#define BASE_MIN_SIZE \ + (BT_UUID_SIZE_16 + BASE_PD_SIZE + BASE_SUBGROUP_COUNT_SIZE + BASE_SUBGROUP_MIN_SIZE) +#define BASE_SUBGROUP_MAX_COUNT (BASE_MAX_SIZE / BASE_SUBGROUP_MIN_SIZE) + +static uint32_t base_pull_pd(struct net_buf_simple *net_buf) +{ + return net_buf_simple_pull_le24(net_buf); +} + +static uint8_t base_pull_bis_count(struct net_buf_simple *net_buf) +{ + return net_buf_simple_pull_u8(net_buf); +} + +static void base_pull_codec_id(struct net_buf_simple *net_buf, + struct bt_bap_base_codec_id *codec_id) +{ + struct bt_bap_base_codec_id codec; + + codec.id = net_buf_simple_pull_u8(net_buf); /* coding format */ + codec.cid = net_buf_simple_pull_le16(net_buf); /* company id */ + codec.vid = net_buf_simple_pull_le16(net_buf); /* VS codec id */ + + if (codec_id != NULL) { + *codec_id = codec; + } +} + +static uint8_t base_pull_ltv(struct net_buf_simple *net_buf, uint8_t **data) +{ + const uint8_t len = net_buf_simple_pull_u8(net_buf); + + if (data == NULL) { + net_buf_simple_pull_mem(net_buf, len); + } else { + *data = net_buf_simple_pull_mem(net_buf, len); + } + + return len; +} + +static bool check_pull_ltv(struct net_buf_simple *net_buf) +{ + uint8_t ltv_len; + + if (net_buf->len < sizeof(ltv_len)) { + return false; + } + + ltv_len = net_buf_simple_pull_u8(net_buf); + if (net_buf->len < ltv_len) { + return false; + } + net_buf_simple_pull_mem(net_buf, ltv_len); + + return true; +} + +const struct bt_bap_base *bt_bap_base_get_base_from_ad(const struct bt_data *ad) +{ + struct bt_uuid_16 broadcast_uuid; + const struct bt_bap_base *base; + struct net_buf_simple net_buf; + uint8_t subgroup_count; + void *uuid; + + CHECKIF(ad == NULL) { + LOG_DBG("data is NULL"); + + return NULL; + } + + if (ad->type != BT_DATA_SVC_DATA16) { + LOG_DBG("Invalid type: %u", ad->type); + + return NULL; + } + + if (ad->data_len < BASE_MIN_SIZE) { + LOG_DBG("Invalid len: %u", ad->data_len); + + return NULL; + } + + net_buf_simple_init_with_data(&net_buf, (void *)ad->data, ad->data_len); + + uuid = net_buf_simple_pull_mem(&net_buf, BT_UUID_SIZE_16); + if (!bt_uuid_create(&broadcast_uuid.uuid, uuid, BT_UUID_SIZE_16)) { + LOG_ERR("bt_uuid_create failed"); + + return NULL; + } + + if (bt_uuid_cmp(&broadcast_uuid.uuid, BT_UUID_BASIC_AUDIO) != 0) { + LOG_DBG("Invalid UUID"); + + return NULL; + } + + /* Store the start of the BASE */ + base = (const struct bt_bap_base *)net_buf.data; + + /* Pull all data to verify that the result BASE is valid */ + base_pull_pd(&net_buf); + subgroup_count = net_buf_simple_pull_u8(&net_buf); + if (subgroup_count == 0 || subgroup_count > BASE_SUBGROUP_MAX_COUNT) { + LOG_DBG("Invalid subgroup count: %u", subgroup_count); + + return NULL; + } + + 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; + } + + bis_count = base_pull_bis_count(&net_buf); + if (bis_count == 0 || bis_count > BT_ISO_MAX_GROUP_ISO_COUNT) { + LOG_DBG("Subgroup[%u]: Invalid BIS count: %u", i, bis_count); + + 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 (bis_index == 0 || bis_index > 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; +} + +int bt_bap_base_get_pres_delay(const struct bt_bap_base *base) +{ + struct net_buf_simple net_buf; + uint32_t pd; + + CHECKIF(base == NULL) { + LOG_DBG("base is NULL"); + + return -EINVAL; + } + + net_buf_simple_init_with_data(&net_buf, (void *)base, sizeof(pd)); + pd = base_pull_pd(&net_buf); + + return (int)pd; /* PD is 24-bit so it fits in an int */ +} + +int bt_bap_base_get_subgroup_count(const struct bt_bap_base *base) +{ + struct net_buf_simple net_buf; + uint8_t subgroup_count; + + CHECKIF(base == NULL) { + LOG_DBG("base is NULL"); + + return -EINVAL; + } + + net_buf_simple_init_with_data(&net_buf, (void *)base, BASE_MAX_SIZE); + base_pull_pd(&net_buf); + subgroup_count = net_buf_simple_pull_u8(&net_buf); + + return (int)subgroup_count; /* subgroup_count is 8-bit so it fits in an int */ +} + +int bt_bap_base_foreach_subgroup(const struct bt_bap_base *base, + bool (*func)(const struct bt_bap_base_subgroup *data, + void *user_data), + void *user_data) +{ + struct bt_bap_base_subgroup *subgroup; + struct net_buf_simple net_buf; + uint8_t subgroup_count; + + CHECKIF(base == NULL) { + LOG_DBG("base is NULL"); + + return -EINVAL; + } + + CHECKIF(func == NULL) { + LOG_DBG("func is NULL"); + + return -EINVAL; + } + + net_buf_simple_init_with_data(&net_buf, (void *)base, BASE_MAX_SIZE); + base_pull_pd(&net_buf); + 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"); + + 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); + + /* meta */ + base_pull_ltv(&net_buf, NULL); + + for (uint8_t j = 0U; j < bis_count; j++) { + net_buf_simple_pull_u8(&net_buf); /* index */ + + /* Codec config */ + base_pull_ltv(&net_buf, NULL); + } + } + } + + return 0; +} + +int bt_bap_base_get_subgroup_codec_id(const struct bt_bap_base_subgroup *subgroup, + struct bt_bap_base_codec_id *codec_id) +{ + struct net_buf_simple net_buf; + + CHECKIF(subgroup == NULL) { + LOG_DBG("subgroup is NULL"); + + return -EINVAL; + } + + CHECKIF(codec_id == NULL) { + LOG_DBG("codec_id is NULL"); + + return -EINVAL; + } + + net_buf_simple_init_with_data(&net_buf, (void *)subgroup, BASE_SUBGROUP_MAX_SIZE); + base_pull_bis_count(&net_buf); + base_pull_codec_id(&net_buf, codec_id); + + return 0; +} + +int bt_bap_base_get_subgroup_codec_data(const struct bt_bap_base_subgroup *subgroup, uint8_t **data) +{ + struct net_buf_simple net_buf; + + CHECKIF(subgroup == NULL) { + LOG_DBG("subgroup is NULL"); + + return -EINVAL; + } + + CHECKIF(data == NULL) { + LOG_DBG("data is NULL"); + + return -EINVAL; + } + + net_buf_simple_init_with_data(&net_buf, (void *)subgroup, BASE_SUBGROUP_MAX_SIZE); + base_pull_bis_count(&net_buf); + base_pull_codec_id(&net_buf, NULL); + + /* Codec config */ + return base_pull_ltv(&net_buf, data); +} + +int bt_bap_base_get_subgroup_codec_meta(const struct bt_bap_base_subgroup *subgroup, uint8_t **meta) +{ + struct net_buf_simple net_buf; + + CHECKIF(subgroup == NULL) { + LOG_DBG("subgroup is NULL"); + + return -EINVAL; + } + + CHECKIF(meta == NULL) { + LOG_DBG("meta is NULL"); + + return -EINVAL; + } + + net_buf_simple_init_with_data(&net_buf, (void *)subgroup, BASE_SUBGROUP_MAX_SIZE); + base_pull_bis_count(&net_buf); + base_pull_codec_id(&net_buf, NULL); + + /* Codec config */ + base_pull_ltv(&net_buf, NULL); + + /* meta */ + return base_pull_ltv(&net_buf, meta); +} + +int bt_bap_base_subgroup_codec_to_codec_cfg(const struct bt_bap_base_subgroup *subgroup, + struct bt_audio_codec_cfg *codec_cfg) +{ + struct bt_bap_base_codec_id codec_id; + struct net_buf_simple net_buf; + uint8_t *ltv_data; + uint8_t ltv_len; + + CHECKIF(subgroup == NULL) { + LOG_DBG("subgroup is NULL"); + + return -EINVAL; + } + + CHECKIF(codec_cfg == NULL) { + LOG_DBG("codec_cfg is NULL"); + + return -EINVAL; + } + + net_buf_simple_init_with_data(&net_buf, (void *)subgroup, BASE_SUBGROUP_MAX_SIZE); + base_pull_bis_count(&net_buf); + base_pull_codec_id(&net_buf, &codec_id); + + codec_cfg->id = codec_id.id; + codec_cfg->cid = codec_id.cid; + codec_cfg->vid = codec_id.vid; + + /* Codec config */ + ltv_len = base_pull_ltv(&net_buf, <v_data); + + if (ltv_len > ARRAY_SIZE(codec_cfg->data)) { + LOG_DBG("Cannot fit %u octets of codec data (max %zu)", ltv_len, + ARRAY_SIZE(codec_cfg->data)); + + return -ENOMEM; + } + + codec_cfg->data_len = ltv_len; + memcpy(codec_cfg->data, ltv_data, ltv_len); + + /* Meta */ + ltv_len = base_pull_ltv(&net_buf, <v_data); + + if (ltv_len > ARRAY_SIZE(codec_cfg->meta)) { + LOG_DBG("Cannot fit %u octets of codec meta (max %zu)", ltv_len, + ARRAY_SIZE(codec_cfg->meta)); + + return -ENOMEM; + } + + codec_cfg->meta_len = ltv_len; + memcpy(codec_cfg->meta, ltv_data, ltv_len); + + return 0; +} +int bt_bap_base_get_subgroup_bis_count(const struct bt_bap_base_subgroup *subgroup) +{ + struct net_buf_simple net_buf; + + CHECKIF(subgroup == NULL) { + LOG_DBG("subgroup is NULL"); + + return -EINVAL; + } + + net_buf_simple_init_with_data(&net_buf, (void *)subgroup, BASE_SUBGROUP_MAX_SIZE); + + return base_pull_bis_count(&net_buf); +} + +int bt_bap_base_subgroup_foreach_bis(const struct bt_bap_base_subgroup *subgroup, + bool (*func)(const struct bt_bap_base_subgroup_bis *subgroup, + void *user_data), + void *user_data) +{ + struct net_buf_simple net_buf; + uint8_t bis_count; + + CHECKIF(subgroup == NULL) { + LOG_DBG("subgroup is NULL"); + + return -EINVAL; + } + + CHECKIF(func == NULL) { + LOG_DBG("func is NULL"); + + return -EINVAL; + } + + net_buf_simple_init_with_data(&net_buf, (void *)subgroup, BASE_SUBGROUP_MAX_SIZE); + + bis_count = base_pull_bis_count(&net_buf); + base_pull_codec_id(&net_buf, NULL); + + /* Codec config */ + base_pull_ltv(&net_buf, NULL); + + /* meta */ + base_pull_ltv(&net_buf, NULL); + + for (uint8_t i = 0U; i < bis_count; i++) { + struct bt_bap_base_subgroup_bis bis; + + bis.index = net_buf_simple_pull_u8(&net_buf); /* index */ + + /* Codec config */ + bis.data_len = base_pull_ltv(&net_buf, &bis.data); + + if (!func(&bis, user_data)) { + LOG_DBG("user stopped parsing"); + + return -ECANCELED; + } + } + + return 0; +} + +int bt_bap_base_subgroup_bis_codec_to_codec_cfg(const struct bt_bap_base_subgroup_bis *bis, + struct bt_audio_codec_cfg *codec_cfg) +{ + CHECKIF(bis == NULL) { + LOG_DBG("bis is NULL"); + + return -EINVAL; + } + + CHECKIF(codec_cfg == NULL) { + LOG_DBG("codec_cfg is NULL"); + + return -EINVAL; + } + + if (bis->data_len > ARRAY_SIZE(codec_cfg->data)) { + LOG_DBG("Cannot fit %u octets of codec data (max %zu)", bis->data_len, + ARRAY_SIZE(codec_cfg->data)); + + return -ENOMEM; + } + + codec_cfg->data_len = bis->data_len; + memcpy(codec_cfg->data, bis->data, bis->data_len); + + return 0; +} + +static bool base_subgroup_bis_cb(const struct bt_bap_base_subgroup_bis *bis, void *user_data) +{ + uint32_t *base_bis_index_bitfield = user_data; + + *base_bis_index_bitfield |= BIT(bis->index); + + return true; +} + +static bool base_subgroup_cb(const struct bt_bap_base_subgroup *subgroup, void *user_data) +{ + const int err = bt_bap_base_subgroup_foreach_bis(subgroup, base_subgroup_bis_cb, user_data); + + if (err != 0) { + LOG_DBG("Failed to parse all BIS: %d", err); + return false; + } + + return true; +} + +int bt_bap_base_get_bis_indexes(const struct bt_bap_base *base, uint32_t *bis_indexes) +{ + CHECKIF(base == NULL) { + LOG_DBG("base is NULL"); + + return -EINVAL; + } + + CHECKIF(bis_indexes == NULL) { + LOG_DBG("bis_indexes is NULL"); + + return -EINVAL; + } + + *bis_indexes = 0U; + + return bt_bap_base_foreach_subgroup(base, base_subgroup_cb, bis_indexes); +} diff --git a/subsys/bluetooth/audio/bap_broadcast_sink.c b/subsys/bluetooth/audio/bap_broadcast_sink.c index 4d2134455b8..d7e6914684b 100644 --- a/subsys/bluetooth/audio/bap_broadcast_sink.c +++ b/subsys/bluetooth/audio/bap_broadcast_sink.c @@ -41,7 +41,7 @@ LOG_MODULE_REGISTER(bt_bap_broadcast_sink, CONFIG_BT_BAP_BROADCAST_SINK_LOG_LEVE #define INVALID_BROADCAST_ID 0xFFFFFFFF static struct bt_bap_ep broadcast_sink_eps[CONFIG_BT_BAP_BROADCAST_SNK_COUNT] - [BROADCAST_SNK_STREAM_CNT]; + [CONFIG_BT_BAP_BROADCAST_SNK_STREAM_COUNT]; static struct bt_bap_broadcast_sink broadcast_sinks[CONFIG_BT_BAP_BROADCAST_SNK_COUNT]; struct codec_cap_lookup_id_data { @@ -91,8 +91,7 @@ static bool find_recv_state_by_pa_sync_cb(const struct bt_bap_scan_delegator_rec static void update_recv_state_big_synced(const struct bt_bap_broadcast_sink *sink) { const struct bt_bap_scan_delegator_recv_state *recv_state; - struct bt_bap_scan_delegator_mod_src_param mod_src_param = { 0 }; - const struct bt_bap_base *base; + struct bt_bap_scan_delegator_mod_src_param mod_src_param = {0}; int err; recv_state = bt_bap_scan_delegator_find_state(find_recv_state_by_sink_cb, (void *)sink); @@ -102,24 +101,13 @@ static void update_recv_state_big_synced(const struct bt_bap_broadcast_sink *sin return; } - base = &sink->base; - - mod_src_param.num_subgroups = base->subgroup_count; - for (uint8_t i = 0U; i < base->subgroup_count; i++) { + mod_src_param.num_subgroups = sink->subgroup_count; + for (uint8_t i = 0U; i < sink->subgroup_count; i++) { struct bt_bap_scan_delegator_subgroup *subgroup_param = &mod_src_param.subgroups[i]; - const struct bt_bap_base_subgroup *subgroup = &base->subgroups[i]; - - /* Update the BIS sync indexes for the subgroup based on the BASE*/ - for (size_t j = 0U; j < subgroup->bis_count; j++) { - const struct bt_bap_base_bis_data *bis_data = &subgroup->bis_data[j]; - - subgroup_param->bis_sync |= BIT(bis_data->index); - } + const struct bt_bap_broadcast_sink_subgroup *sink_subgroup = &sink->subgroups[i]; - /* Update the bis_sync so that the bis_sync value only contains the indexes that we - * are actually synced to - */ - subgroup_param->bis_sync &= sink->indexes_bitfield; + /* Set the bis_sync value to the indexes available per subgroup */ + subgroup_param->bis_sync = sink_subgroup->bis_indexes & sink->indexes_bitfield; } if (recv_state->encrypt_state == BT_BAP_BIG_ENC_STATE_BCODE_REQ) { @@ -443,33 +431,44 @@ static void broadcast_sink_add_src(struct bt_bap_broadcast_sink *sink) } } -static int update_recv_state_base_copy_meta(const struct bt_bap_base *base, - struct bt_bap_scan_delegator_mod_src_param *param) +static bool base_subgroup_meta_cb(const struct bt_bap_base_subgroup *subgroup, void *user_data) { - if (base->subgroup_count > ARRAY_SIZE(param->subgroups)) { - LOG_DBG("Could not fit %zu subgroups in the mod param (max %zu)", - base->subgroup_count, ARRAY_SIZE(param->subgroups)); + struct bt_bap_scan_delegator_mod_src_param *mod_src_param = user_data; + struct bt_bap_scan_delegator_subgroup *subgroup_param; + uint8_t *meta; + int ret; + + ret = bt_bap_base_get_subgroup_codec_meta(subgroup, &meta); + if (ret < 0) { + return false; } - param->num_subgroups = base->subgroup_count; + subgroup_param = &mod_src_param->subgroups[mod_src_param->num_subgroups++]; + subgroup_param->metadata_len = (uint8_t)ret; + memcpy(subgroup_param->metadata, meta, subgroup_param->metadata_len); + + return true; +} - for (uint8_t i = 0U; i < base->subgroup_count; i++) { - struct bt_bap_scan_delegator_subgroup *subgroup_param = ¶m->subgroups[i]; - const struct bt_bap_base_subgroup *subgroup = &base->subgroups[i]; +static int update_recv_state_base_copy_meta(const struct bt_bap_base *base, + struct bt_bap_scan_delegator_mod_src_param *param) +{ + int err; - subgroup_param->metadata_len = subgroup->codec_cfg.meta_len; - memcpy(subgroup_param->metadata, subgroup->codec_cfg.meta, - subgroup->codec_cfg.meta_len); + err = bt_bap_base_foreach_subgroup(base, base_subgroup_meta_cb, param); + if (err != 0) { + LOG_DBG("Failed to parse subgroups: %d", err); + return err; } return 0; } -static void update_recv_state_base(const struct bt_bap_broadcast_sink *sink) +static void update_recv_state_base(const struct bt_bap_broadcast_sink *sink, + const struct bt_bap_base *base) { struct bt_bap_scan_delegator_mod_src_param mod_src_param = { 0 }; const struct bt_bap_scan_delegator_recv_state *recv_state; - const struct bt_bap_base *base; int err; recv_state = bt_bap_scan_delegator_find_state(find_recv_state_by_sink_cb, (void *)sink); @@ -479,8 +478,6 @@ static void update_recv_state_base(const struct bt_bap_broadcast_sink *sink) return; } - base = &sink->base; - err = update_recv_state_base_copy_meta(base, &mod_src_param); if (err != 0) { LOG_WRN("Failed to modify Receive State for sink %p: %d", sink, err); @@ -498,55 +495,180 @@ static void update_recv_state_base(const struct bt_bap_broadcast_sink *sink) } } -static bool pa_decode_base(struct bt_data *data, void *user_data) +static bool codec_lookup_id(const struct bt_pacs_cap *cap, void *user_data) { - struct bt_bap_broadcast_sink *sink = (struct bt_bap_broadcast_sink *)user_data; - struct bt_bap_broadcast_sink_cb *listener; - struct bt_bap_base base = { 0 }; + struct codec_cap_lookup_id_data *data = user_data; - if (data->type != BT_DATA_SVC_DATA16) { - return true; + if (cap->codec_cap->id == data->id) { + data->codec_cap = cap->codec_cap; + + return false; } - if (data->data_len < BT_BAP_BASE_MIN_SIZE) { - return true; + return true; +} + +static bool base_subgroup_bis_index_cb(const struct bt_bap_base_subgroup_bis *bis, void *user_data) +{ + uint32_t *bis_indexes = user_data; + + *bis_indexes |= BIT(bis->index); + + return true; +} + +static bool base_subgroup_cb(const struct bt_bap_base_subgroup *subgroup, void *user_data) +{ + struct bt_bap_broadcast_sink *sink = user_data; + struct bt_bap_broadcast_sink_subgroup *sink_subgroup = + &sink->subgroups[sink->subgroup_count]; + struct codec_cap_lookup_id_data lookup_data = {0}; + int ret; + + if (sink->subgroup_count == ARRAY_SIZE(sink->subgroups)) { + /* We've parsed as many subgroups as we support */ + LOG_DBG("Could only store %u subgroups", sink->subgroup_count); + return false; } - if (bt_bap_decode_base(data, &base) != 0) { + ret = bt_bap_base_subgroup_codec_to_codec_cfg(subgroup, &sink_subgroup->codec_cfg); + if (ret < 0) { + LOG_DBG("Could not store codec_cfg: %d", ret); return false; } - if (atomic_test_bit(sink->flags, - BT_BAP_BROADCAST_SINK_FLAG_BIGINFO_RECEIVED)) { - uint8_t num_bis = 0; + ret = bt_bap_base_subgroup_foreach_bis(subgroup, base_subgroup_bis_index_cb, + &sink_subgroup->bis_indexes); + if (ret < 0) { + LOG_DBG("Could not parse BISes: %d", ret); + return false; + } - for (int i = 0; i < base.subgroup_count; i++) { - num_bis += base.subgroups[i].bis_count; - } + /* Lookup and assign path_id based on capabilities */ + lookup_data.id = sink_subgroup->codec_cfg.id; - if (num_bis > sink->biginfo_num_bis) { - LOG_WRN("BASE contains more BIS than reported by BIGInfo"); + bt_pacs_cap_foreach(BT_AUDIO_DIR_SINK, codec_lookup_id, &lookup_data); + if (lookup_data.codec_cap == NULL) { + LOG_DBG("Codec with id %u is not supported by our capabilities", lookup_data.id); + } else { + /* Add BIS to bitfield of valid BIS indexes we support */ + sink->valid_indexes_bitfield |= sink_subgroup->bis_indexes; + } + + sink->subgroup_count++; + + return true; +} + +static int store_base_info(struct bt_bap_broadcast_sink *sink, const struct bt_bap_base *base) +{ + int ret; + + sink->valid_indexes_bitfield = 0U; + sink->subgroup_count = 0U; + + ret = bt_bap_base_get_pres_delay(base); + if (ret < 0) { + LOG_DBG("Could not get presentation delay: %d", ret); + return ret; + } + + sink->codec_qos.pd = (uint32_t)ret; + + ret = bt_bap_base_foreach_subgroup(base, base_subgroup_cb, sink); + if (ret != 0) { + LOG_DBG("Failed to parse all subgroups: %d", ret); + return ret; + } + + return 0; +} + +static bool base_subgroup_bis_count_cb(const struct bt_bap_base_subgroup *subgroup, void *user_data) +{ + uint8_t *bis_cnt = user_data; + int ret; + + ret = bt_bap_base_get_subgroup_bis_count(subgroup); + if (ret < 0) { + return false; + } + + *bis_cnt += (uint8_t)ret; + + return true; +} + +static int base_get_bis_count(const struct bt_bap_base *base) +{ + uint8_t bis_cnt = 0U; + int err; + + err = bt_bap_base_foreach_subgroup(base, base_subgroup_bis_count_cb, &bis_cnt); + if (err != 0) { + LOG_DBG("Failed to parse subgroups: %d", err); + return err; + } + + return bis_cnt; +} + +static bool pa_decode_base(struct bt_data *data, void *user_data) +{ + struct bt_bap_broadcast_sink *sink = (struct bt_bap_broadcast_sink *)user_data; + const struct bt_bap_base *base = bt_bap_base_get_base_from_ad(data); + struct bt_bap_broadcast_sink_cb *listener; + size_t base_size; + int ret; + + /* Base is NULL if the data does not contain a valid BASE */ + if (base == NULL) { + return true; + } + + if (atomic_test_bit(sink->flags, BT_BAP_BROADCAST_SINK_FLAG_BIGINFO_RECEIVED)) { + ret = base_get_bis_count(base); + + if (ret < 0) { + LOG_DBG("Invalid BASE: %d", ret); + return false; + } else if (ret != sink->biginfo_num_bis) { + LOG_DBG("BASE contains different amount of BIS (%u) than reported by " + "BIGInfo (%u)", + ret, sink->biginfo_num_bis); return false; } } - sink->codec_qos.pd = base.pd; - if (memcmp(&sink->base, &base, sizeof(base)) != 0) { - /* We only overwrite the sink->base data once the base has - * successfully been decoded to avoid overwriting it with - * invalid data - */ - (void)memcpy(&sink->base, &base, sizeof(base)); + /* Store newest BASE info until we are BIG synced */ + if (sink->big == NULL) { + LOG_DBG("Updating BASE for sink %p with %d subgroups\n", sink, + bt_bap_base_get_subgroup_count(base)); - if (atomic_test_bit(sink->flags, - BT_BAP_BROADCAST_SINK_FLAG_SRC_ID_VALID)) { - update_recv_state_base(sink); + ret = store_base_info(sink, base); + if (ret < 0) { + LOG_DBG("Could not store BASE information: %d", ret); + + /* If it returns -ECANCELED it means that we stopped parsing ourselves due + * to lack of memory. In this case we can still provide the BASE to the + * application else abort + */ + if (ret != -ECANCELED) { + return false; + } } } + if (atomic_test_bit(sink->flags, BT_BAP_BROADCAST_SINK_FLAG_SRC_ID_VALID)) { + update_recv_state_base(sink, base); + } + + /* We provide the BASE without the service data UUID */ + base_size = data->data_len - BT_UUID_SIZE_16; + SYS_SLIST_FOR_EACH_CONTAINER(&sink_cbs, listener, _node) { if (listener->base_recv != NULL) { - listener->base_recv(sink, &base); + listener->base_recv(sink, base, base_size); } } @@ -815,36 +937,20 @@ static void broadcast_sink_cleanup(struct bt_bap_broadcast_sink *sink) (void)memset(sink, 0, sizeof(*sink)); /* also clears flags */ } - -static struct bt_audio_codec_cfg *codec_cfg_from_base_by_index(struct bt_bap_base *base, +static struct bt_audio_codec_cfg *codec_cfg_from_base_by_index(struct bt_bap_broadcast_sink *sink, uint8_t index) { - for (size_t i = 0U; i < base->subgroup_count; i++) { - struct bt_bap_base_subgroup *subgroup = &base->subgroups[i]; + for (size_t i = 0U; i < sink->subgroup_count; i++) { + struct bt_bap_broadcast_sink_subgroup *subgroup = &sink->subgroups[i]; - for (size_t j = 0U; j < subgroup->bis_count; j++) { - if (subgroup->bis_data[j].index == index) { - return &subgroup->codec_cfg; - } + if ((subgroup->bis_indexes & BIT(index)) != 0) { + return &subgroup->codec_cfg; } } return NULL; } -static bool codec_lookup_id(const struct bt_pacs_cap *cap, void *user_data) -{ - struct codec_cap_lookup_id_data *data = user_data; - - if (cap->codec_cap->id == data->id) { - data->codec_cap = cap->codec_cap; - - return false; - } - - return true; -} - int bt_bap_broadcast_sink_create(struct bt_le_per_adv_sync *pa_sync, uint32_t broadcast_id, struct bt_bap_broadcast_sink **out_sink) { @@ -906,7 +1012,7 @@ int bt_bap_broadcast_sink_sync(struct bt_bap_broadcast_sink *sink, uint32_t inde struct bt_bap_stream *streams[], const uint8_t broadcast_code[16]) { struct bt_iso_big_sync_param param; - struct bt_audio_codec_cfg *codec_cfgs[BROADCAST_SNK_STREAM_CNT] = {NULL}; + struct bt_audio_codec_cfg *codec_cfgs[CONFIG_BT_BAP_BROADCAST_SNK_SUBGROUP_COUNT] = {NULL}; uint8_t stream_count; int err; @@ -954,37 +1060,26 @@ int bt_bap_broadcast_sink_sync(struct bt_bap_broadcast_sink *sink, uint32_t inde } /* Validate that number of bits set is less than number of streams */ + if ((indexes_bitfield & sink->valid_indexes_bitfield) != indexes_bitfield) { + LOG_DBG("Request BIS indexes 0x%08X contains bits not support by the Broadcast " + "Sink 0x%08X", + indexes_bitfield, sink->valid_indexes_bitfield); + return -EINVAL; + } + stream_count = 0; for (int i = 1; i < BT_ISO_MAX_GROUP_ISO_COUNT; i++) { if ((indexes_bitfield & BIT(i)) != 0) { struct bt_audio_codec_cfg *codec_cfg = - codec_cfg_from_base_by_index(&sink->base, i); - struct codec_cap_lookup_id_data lookup_data = {}; - - if (codec_cfg == NULL) { - LOG_DBG("Index %d not found in BASE", i); - return -EINVAL; - } - - /* Lookup and assign path_id based on capabilities */ - lookup_data.id = codec_cfg->id; - - bt_pacs_cap_foreach(BT_AUDIO_DIR_SINK, codec_lookup_id, - &lookup_data); - if (lookup_data.codec_cap == NULL) { - LOG_DBG("Codec with id %u is not supported by our capabilities", - codec_cfg->id); - - return -ENOENT; - } + codec_cfg_from_base_by_index(sink, i); - codec_cfg->path_id = lookup_data.codec_cap->path_id; + __ASSERT(codec_cfg != NULL, "Index %d not found in sink", i); codec_cfgs[stream_count++] = codec_cfg; - if (stream_count > BROADCAST_SNK_STREAM_CNT) { - LOG_DBG("Cannot sync to more than %d streams", - BROADCAST_SNK_STREAM_CNT); + if (stream_count > CONFIG_BT_BAP_BROADCAST_SNK_STREAM_COUNT) { + LOG_DBG("Cannot sync to more than %d streams (%u was requested)", + CONFIG_BT_BAP_BROADCAST_SNK_STREAM_COUNT, stream_count); return -EINVAL; } } diff --git a/subsys/bluetooth/audio/bap_endpoint.h b/subsys/bluetooth/audio/bap_endpoint.h index 1c5aa3d5fc5..aa2f326a71f 100644 --- a/subsys/bluetooth/audio/bap_endpoint.h +++ b/subsys/bluetooth/audio/bap_endpoint.h @@ -124,19 +124,27 @@ enum bt_bap_broadcast_sink_flag { BT_BAP_BROADCAST_SINK_FLAG_NUM_FLAGS, }; +struct bt_bap_broadcast_sink_subgroup { + uint32_t bis_indexes; + struct bt_audio_codec_cfg codec_cfg; +}; + +#if defined(CONFIG_BT_BAP_BROADCAST_SINK) struct bt_bap_broadcast_sink { uint8_t index; /* index of broadcast_snks array */ uint8_t stream_count; uint8_t bass_src_id; + uint8_t subgroup_count; uint16_t iso_interval; uint16_t biginfo_num_bis; uint32_t broadcast_id; /* 24 bit */ uint32_t indexes_bitfield; - struct bt_bap_base base; + uint32_t valid_indexes_bitfield; /* based on codec support */ struct bt_audio_codec_qos codec_qos; struct bt_le_per_adv_sync *pa_sync; struct bt_iso_big *big; - struct bt_iso_chan *bis[BROADCAST_SNK_STREAM_CNT]; + struct bt_iso_chan *bis[CONFIG_BT_BAP_BROADCAST_SNK_STREAM_COUNT]; + struct bt_bap_broadcast_sink_subgroup subgroups[CONFIG_BT_BAP_BROADCAST_SNK_SUBGROUP_COUNT]; const struct bt_bap_scan_delegator_recv_state *recv_state; /* The streams used to create the broadcast sink */ sys_slist_t streams; @@ -144,6 +152,7 @@ struct bt_bap_broadcast_sink { /** Flags */ ATOMIC_DEFINE(flags, BT_BAP_BROADCAST_SINK_FLAG_NUM_FLAGS); }; +#endif /* CONFIG_BT_BAP_BROADCAST_SINK */ static inline const char *bt_bap_ep_state_str(uint8_t state) { diff --git a/subsys/bluetooth/audio/shell/audio.h b/subsys/bluetooth/audio/shell/audio.h index 8beae301036..37959fbe366 100644 --- a/subsys/bluetooth/audio/shell/audio.h +++ b/subsys/bluetooth/audio/shell/audio.h @@ -99,7 +99,8 @@ struct broadcast_source { struct broadcast_sink { struct bt_bap_broadcast_sink *bap_sink; struct bt_le_per_adv_sync *pa_sync; - struct bt_bap_base received_base; + uint8_t received_base[UINT8_MAX]; + uint8_t base_size; uint32_t broadcast_id; size_t stream_cnt; bool syncable; @@ -227,51 +228,84 @@ extern struct shell_stream broadcast_source_streams[CONFIG_BT_BAP_BROADCAST_SRC_ extern struct broadcast_source default_source; #endif /* CONFIG_BT_BAP_BROADCAST_SOURCE */ -#if BROADCAST_SNK_SUBGROUP_CNT > 0 -static inline void print_base(const struct shell *sh, const struct bt_bap_base *base) +static inline bool print_base_subgroup_bis_cb(const struct bt_bap_base_subgroup_bis *bis, + void *user_data) { - uint8_t bis_indexes[BT_ISO_MAX_GROUP_ISO_COUNT] = {0}; - /* "0xXX " requires 5 characters */ - char bis_indexes_str[5 * ARRAY_SIZE(bis_indexes) + 1]; - size_t index_count = 0; + struct bt_bap_base_codec_id *codec_id = user_data; - for (size_t i = 0U; i < base->subgroup_count; i++) { - const struct bt_bap_base_subgroup *subgroup; + shell_print(ctx_shell, "\t\tBIS index: 0x%02X", bis->index); + /* Print CC data */ + if (codec_id->id == BT_HCI_CODING_FORMAT_LC3) { + print_ltv_array(ctx_shell, "\t\tdata", bis->data, bis->data_len); + } else { /* If not LC3, we cannot assume it's LTV */ + shell_hexdump(ctx_shell, bis->data, bis->data_len); + } - subgroup = &base->subgroups[i]; + return true; +} - shell_print(sh, "Subgroup[%d]:", i); - print_codec_cfg(sh, &subgroup->codec_cfg); +static inline bool print_base_subgroup_cb(const struct bt_bap_base_subgroup *subgroup, + void *user_data) +{ + struct bt_bap_base_codec_id codec_id; + uint8_t *data; + int ret; - for (size_t j = 0U; j < subgroup->bis_count; j++) { - const struct bt_bap_base_bis_data *bis_data; + shell_print(ctx_shell, "Subgroup %p:", subgroup); - bis_data = &subgroup->bis_data[j]; + ret = bt_bap_base_get_subgroup_codec_id(subgroup, &codec_id); + if (ret < 0) { + return false; + } - shell_print(sh, "BIS[%d] index 0x%02x", j, bis_data->index); - bis_indexes[index_count++] = bis_data->index; + shell_print(ctx_shell, "\tCodec Format: 0x%02X", codec_id.id); + shell_print(ctx_shell, "\tCompany ID : 0x%04X", codec_id.cid); + shell_print(ctx_shell, "\tVendor ID : 0x%04X", codec_id.vid); -#if CONFIG_BT_AUDIO_CODEC_CFG_MAX_DATA_SIZE > 0 - shell_hexdump(sh, bis_data->data, bis_data->data_len); -#endif /* CONFIG_BT_AUDIO_CODEC_CFG_MAX_DATA_SIZE > 0 */ - } + ret = bt_bap_base_get_subgroup_codec_data(subgroup, &data); + if (ret < 0) { + return false; } - (void)memset(bis_indexes_str, 0, sizeof(bis_indexes_str)); + /* Print CC data */ + if (codec_id.id == BT_HCI_CODING_FORMAT_LC3) { + print_ltv_array(ctx_shell, "\tdata", data, (uint8_t)ret); + } else { /* If not LC3, we cannot assume it's LTV */ + shell_hexdump(ctx_shell, data, (uint8_t)ret); + } - /* Create space separated list of indexes as hex values */ - for (size_t i = 0U; i < index_count; i++) { - char bis_index_str[6]; + ret = bt_bap_base_get_subgroup_codec_meta(subgroup, &data); + if (ret < 0) { + return false; + } - sprintf(bis_index_str, "0x%02x ", bis_indexes[i]); + /* Print metadata */ + if (codec_id.id == BT_HCI_CODING_FORMAT_LC3) { + print_ltv_array(ctx_shell, "\tdata", data, (uint8_t)ret); + } else { /* If not LC3, we cannot assume it's LTV */ + shell_hexdump(ctx_shell, data, (uint8_t)ret); + } - strcat(bis_indexes_str, bis_index_str); - shell_print(sh, "[%d]: %s", i, bis_index_str); + ret = bt_bap_base_subgroup_foreach_bis(subgroup, print_base_subgroup_bis_cb, &codec_id); + if (ret < 0) { + return false; } - shell_print(sh, "Possible indexes: %s", bis_indexes_str); + return true; +} + +static inline void print_base(const struct bt_bap_base *base) +{ + int err; + + shell_print(ctx_shell, "Presentation delay: %d", bt_bap_base_get_pres_delay(base)); + shell_print(ctx_shell, "Subgroup count: %d", bt_bap_base_get_subgroup_count(base)); + + err = bt_bap_base_foreach_subgroup(base, print_base_subgroup_cb, NULL); + if (err < 0) { + shell_info(ctx_shell, "Invalid BASE: %d", err); + } } -#endif /* BROADCAST_SNK_SUBGROUP_CNT > 0 */ static inline void copy_unicast_stream_preset(struct shell_stream *stream, const struct named_lc3_preset *named_preset) diff --git a/subsys/bluetooth/audio/shell/bap.c b/subsys/bluetooth/audio/shell/bap.c index 69ff3342ab3..3e946cf6436 100644 --- a/subsys/bluetooth/audio/shell/bap.c +++ b/subsys/bluetooth/audio/shell/bap.c @@ -57,7 +57,7 @@ struct shell_stream broadcast_source_streams[CONFIG_BT_BAP_BROADCAST_SRC_STREAM_ struct broadcast_source default_source; #endif /* CONFIG_BT_BAP_BROADCAST_SOURCE */ #if defined(CONFIG_BT_BAP_BROADCAST_SINK) -static struct bt_bap_stream broadcast_sink_streams[BROADCAST_SNK_STREAM_CNT]; +static struct bt_bap_stream broadcast_sink_streams[CONFIG_BT_BAP_BROADCAST_SNK_STREAM_COUNT]; static struct broadcast_sink default_broadcast_sink; #endif /* CONFIG_BT_BAP_BROADCAST_SINK */ static struct bt_bap_stream *default_stream; @@ -1701,77 +1701,18 @@ static void broadcast_scan_recv(const struct bt_le_scan_recv_info *info, struct } } -static bool print_data_func_cb(struct bt_data *data, void *user_data) +static void base_recv(struct bt_bap_broadcast_sink *sink, const struct bt_bap_base *base, + size_t base_size) { - shell_print(ctx_shell, "type 0x%02x len %u", data->type, data->data_len); - shell_hexdump(ctx_shell, data->data, data->data_len); + /* Don't print duplicates */ + if (base_size != default_broadcast_sink.base_size || + memcmp(base, &default_broadcast_sink.received_base, base_size) != 0) { + shell_print(ctx_shell, "Received BASE from sink %p:", sink); + (void)memcpy(&default_broadcast_sink.received_base, base, base_size); + default_broadcast_sink.base_size = base_size; - return true; -} - -static void base_recv(struct bt_bap_broadcast_sink *sink, const struct bt_bap_base *base) -{ - uint8_t bis_indexes[BROADCAST_SNK_STREAM_CNT] = { 0 }; - /* "0xXX " requires 5 characters */ - char bis_indexes_str[5 * ARRAY_SIZE(bis_indexes) + 1]; - size_t index_count = 0; - - if (memcmp(base, &default_broadcast_sink.received_base, - sizeof(default_broadcast_sink.received_base)) == 0) { - /* Don't print duplicates */ - return; + print_base(base); } - - shell_print(ctx_shell, "Received BASE from sink %p:", sink); - shell_print(ctx_shell, "Presentation delay: %u", base->pd); - shell_print(ctx_shell, "Subgroup count: %u", base->subgroup_count); - - for (int i = 0; i < base->subgroup_count; i++) { - const struct bt_bap_base_subgroup *subgroup; - - subgroup = &base->subgroups[i]; - - shell_print(ctx_shell, "%2sSubgroup[%d]:", "", i); - print_codec_cfg(ctx_shell, &subgroup->codec_cfg); - - for (int j = 0; j < subgroup->bis_count; j++) { - const struct bt_bap_base_bis_data *bis_data; - - bis_data = &subgroup->bis_data[j]; - - shell_print(ctx_shell, "%4sBIS[%d] index 0x%02x", "", i, bis_data->index); - bis_indexes[index_count++] = bis_data->index; - - if (subgroup->codec_cfg.id == BT_HCI_CODING_FORMAT_LC3) { - const int err = - bt_audio_data_parse(bis_data->data, bis_data->data_len, - print_data_func_cb, NULL); - - if (err != 0) { - shell_error(ctx_shell, - "Failed to parse BIS codec config: %d", err); - } - } else { - shell_hexdump(ctx_shell, bis_data->data, bis_data->data_len); - } - } - } - - memset(bis_indexes_str, 0, sizeof(bis_indexes_str)); - /* Create space separated list of indexes as hex values */ - for (int i = 0; i < index_count; i++) { - char bis_index_str[6]; - - sprintf(bis_index_str, "0x%02x ", bis_indexes[i]); - - strcat(bis_indexes_str, bis_index_str); - shell_print(ctx_shell, "[%d]: %s", i, bis_index_str); - } - - shell_print(ctx_shell, "Possible indexes: %s", bis_indexes_str); - - (void)memcpy(&default_broadcast_sink.received_base, base, - sizeof(default_broadcast_sink.received_base)); } static void syncable(struct bt_bap_broadcast_sink *sink, bool encrypted) diff --git a/subsys/bluetooth/audio/shell/bap_broadcast_assistant.c b/subsys/bluetooth/audio/shell/bap_broadcast_assistant.c index 00892ec6187..64f0f5f3890 100644 --- a/subsys/bluetooth/audio/shell/bap_broadcast_assistant.c +++ b/subsys/bluetooth/audio/shell/bap_broadcast_assistant.c @@ -28,7 +28,8 @@ /* BIS sync is a 32-bit bitfield where BIT(0) is not allowed */ #define VALID_BIS_SYNC(_bis_sync) ((bis_sync & BIT(0)) == 0U && bis_sync < UINT32_MAX) -static struct bt_bap_base received_base; +static uint8_t received_base[UINT8_MAX]; +static uint8_t received_base_size; static struct bt_auto_scan { uint32_t broadcast_id; @@ -40,31 +41,20 @@ static struct bt_auto_scan { static bool pa_decode_base(struct bt_data *data, void *user_data) { - struct bt_bap_base base = { 0 }; - int err; - - if (data->type != BT_DATA_SVC_DATA16) { - return true; - } + const struct bt_bap_base *base = bt_bap_base_get_base_from_ad(data); - if (data->data_len < BT_BAP_BASE_MIN_SIZE) { + /* Base is NULL if the data does not contain a valid BASE */ + if (base == NULL) { return true; } - err = bt_bap_decode_base(data, &base); - if (err != 0 && err != -ENOMSG) { - shell_error(ctx_shell, "Failed to decode BASE: %d", err); - - return false; - } - /* Compare BASE and print if different */ - if (memcmp(&base, &received_base, sizeof(base)) != 0) { - (void)memcpy(&received_base, &base, sizeof(base)); + if (data->data_len != received_base_size || + memcmp(data->data, received_base, data->data_len) != 0) { + (void)memcpy(&received_base, data->data, data->data_len); + received_base_size = data->data_len; -#if BROADCAST_SNK_SUBGROUP_CNT > 0 - print_base(ctx_shell, &received_base); -#endif /* BROADCAST_SNK_SUBGROUP_CNT > 0 */ + print_base(base); } return false; @@ -779,6 +769,48 @@ static int cmd_bap_broadcast_assistant_mod_src(const struct shell *sh, return result; } +static inline bool add_pa_sync_base_subgroup_bis_cb(const struct bt_bap_base_subgroup_bis *bis, + void *user_data) +{ + struct bt_bap_scan_delegator_subgroup *subgroup_param = user_data; + + subgroup_param->bis_sync |= BIT(bis->index); + + return true; +} + +static inline bool add_pa_sync_base_subgroup_cb(const struct bt_bap_base_subgroup *subgroup, + void *user_data) +{ + struct bt_bap_broadcast_assistant_add_src_param *param = user_data; + struct bt_bap_scan_delegator_subgroup *subgroup_param; + uint8_t *data; + int ret; + + ret = bt_bap_base_get_subgroup_codec_meta(subgroup, &data); + if (ret < 0) { + return false; + } + + subgroup_param = ¶m->subgroups[param->num_subgroups]; + + if (ret > ARRAY_SIZE(subgroup_param->metadata)) { + shell_info(ctx_shell, "Cannot fit %d octets into subgroup param with size %zu", ret, + ARRAY_SIZE(subgroup_param->metadata)); + return false; + } + + ret = bt_bap_base_subgroup_foreach_bis(subgroup, add_pa_sync_base_subgroup_bis_cb, + subgroup_param); + if (ret < 0) { + return false; + } + + param->num_subgroups++; + + return true; +} + static int cmd_bap_broadcast_assistant_add_pa_sync(const struct shell *sh, size_t argc, char **argv) { @@ -855,45 +887,12 @@ static int cmd_bap_broadcast_assistant_add_pa_sync(const struct shell *sh, bis_bitfield_req |= BIT(index); } - /* The MIN is used to handle `array-bounds` error on some compilers */ - param.num_subgroups = MIN(received_base.subgroup_count, BROADCAST_SNK_SUBGROUP_CNT); -#if BROADCAST_SNK_SUBGROUP_CNT > 0 - struct bt_bap_scan_delegator_subgroup subgroup_params[BROADCAST_SNK_SUBGROUP_CNT] = {0}; - - param.subgroups = subgroup_params; - for (size_t i = 0; i < param.num_subgroups; i++) { - struct bt_bap_scan_delegator_subgroup *subgroup_param = &subgroup_params[i]; - const struct bt_bap_base_subgroup *subgroup = &received_base.subgroups[i]; - uint32_t subgroup_bis_indexes = 0U; - ssize_t metadata_len; - - for (size_t j = 0U; j < MIN(subgroup->bis_count, ARRAY_SIZE(subgroup->bis_data)); - j++) { - const struct bt_bap_base_bis_data *bis_data = &subgroup->bis_data[j]; - - subgroup_bis_indexes |= BIT(bis_data->index); - } - - subgroup_param->bis_sync = subgroup_bis_indexes & bis_bitfield_req; - -#if CONFIG_BT_AUDIO_CODEC_CFG_MAX_METADATA_SIZE > 0 - metadata_len = subgroup->codec_cfg.meta_len; - if (metadata_len > sizeof(subgroup_param->metadata)) { - shell_error(sh, - "Could not set %zu octets of metadata for subgroup_param of " - "size %zu", - metadata_len, sizeof(subgroup_param->metadata)); - - return -ENOEXEC; - } - - memcpy(subgroup_param->metadata, subgroup->codec_cfg.meta, metadata_len); -#else - metadata_len = 0U; -#endif /* CONFIG_BT_AUDIO_CODEC_CFG_MAX_METADATA_SIZE > 0 */ - subgroup_param->metadata_len = metadata_len; + err = bt_bap_base_foreach_subgroup((const struct bt_bap_base *)received_base, + add_pa_sync_base_subgroup_cb, ¶m); + if (err < 0) { + shell_error(ctx_shell, "Could not add BASE to params %d", err); + return -ENOEXEC; } -#endif /* BROADCAST_SNK_SUBGROUP_CNT > 0 */ err = bt_bap_broadcast_assistant_add_src(default_conn, ¶m); if (err != 0) { diff --git a/tests/bluetooth/tester/src/btp_bap.c b/tests/bluetooth/tester/src/btp_bap.c index d6149d2c3ac..c38ad00749f 100644 --- a/tests/bluetooth/tester/src/btp_bap.c +++ b/tests/bluetooth/tester/src/btp_bap.c @@ -1517,11 +1517,57 @@ static void btp_send_bis_found_ev(const bt_addr_le_t *address, uint32_t broadcas tester_rsp_buffer_unlock(); } -static void base_recv_cb(struct bt_bap_broadcast_sink *sink, const struct bt_bap_base *base) +struct base_parse_data { + uint32_t broadcast_id; + uint32_t pd; + struct bt_audio_codec_cfg codec_cfg; + uint8_t subgroup_cnt; + uint32_t bis_bitfield; + size_t stream_cnt; +}; + +static bool base_subgroup_bis_cb(const struct bt_bap_base_subgroup_bis *bis, void *user_data) +{ + struct base_parse_data *parse_data = user_data; + struct bt_audio_codec_cfg *codec_cfg = &parse_data->codec_cfg; + + parse_data->bis_bitfield |= BIT(bis->index); + + if (parse_data->stream_cnt < MAX_STREAMS_COUNT) { + broadcaster->streams[parse_data->stream_cnt++].bis_id = bis->index; + } + + btp_send_bis_found_ev(&broadcaster_addr, parse_data->broadcast_id, parse_data->pd, + parse_data->subgroup_cnt, bis->index, codec_cfg); + + return true; +} + +static bool base_subgroup_cb(const struct bt_bap_base_subgroup *subgroup, void *user_data) { - size_t stream_count = 0U; - uint32_t base_bis_index_bitfield = 0U; - const struct bt_audio_codec_cfg *codec_cfg; + struct base_parse_data *parse_data = user_data; + int err; + + err = bt_bap_base_subgroup_codec_to_codec_cfg(subgroup, &parse_data->codec_cfg); + if (err != 0) { + LOG_DBG("Failed to retrieve codec config: %d", err); + return false; + } + + err = bt_bap_base_subgroup_foreach_bis(subgroup, base_subgroup_bis_cb, user_data); + if (err != 0) { + LOG_DBG("Failed to parse all BIS: %d", err); + return false; + } + + return true; +} + +static void base_recv_cb(struct bt_bap_broadcast_sink *sink, const struct bt_bap_base *base, + size_t base_size) +{ + struct base_parse_data parse_data = {0}; + int ret; LOG_DBG(""); @@ -1529,25 +1575,25 @@ static void base_recv_cb(struct bt_bap_broadcast_sink *sink, const struct bt_bap return; } - LOG_DBG("Received BASE: broadcast sink %p subgroups %u", sink, base->subgroup_count); - - for (size_t i = 0U; i < base->subgroup_count; i++) { - for (size_t j = 0U; j < base->subgroups[i].bis_count; j++) { - const uint8_t index = base->subgroups[i].bis_data[j].index; + LOG_DBG("Received BASE: broadcast sink %p subgroups %u", + sink, bt_bap_base_get_subgroup_count(base)); - codec_cfg = &base->subgroups[i].codec_cfg; - base_bis_index_bitfield |= BIT(index); + ret = bt_bap_base_get_pres_delay(base); + if (ret < 0) { + LOG_ERR("Failed to get presentation delay: %d", ret); + return; + } - if (stream_count < MAX_STREAMS_COUNT) { - broadcaster->streams[stream_count++].bis_id = index; - } + parse_data.broadcast_id = sink->broadcast_id; + parse_data.pd = (uint32_t)ret; - btp_send_bis_found_ev(&broadcaster_addr, sink->broadcast_id, - sink->base.pd, i, index, codec_cfg); - } + ret = bt_bap_base_foreach_subgroup(base, base_subgroup_cb, &parse_data); + if (ret != 0) { + LOG_ERR("Failed to parse subgroups: %d", ret); + return; } - bis_index_bitfield = base_bis_index_bitfield & bis_index_mask; + bis_index_bitfield = parse_data.bis_bitfield & bis_index_mask; LOG_DBG("bis_index_bitfield 0x%08x", bis_index_bitfield); } diff --git a/tests/bsim/bluetooth/audio/src/bap_broadcast_assistant_test.c b/tests/bsim/bluetooth/audio/src/bap_broadcast_assistant_test.c index 9964bd29c0a..94b67b13493 100644 --- a/tests/bsim/bluetooth/audio/src/bap_broadcast_assistant_test.c +++ b/tests/bsim/bluetooth/audio/src/bap_broadcast_assistant_test.c @@ -527,6 +527,7 @@ static void test_main_client_sync(void) test_bass_mod_source(); test_bass_broadcast_code(); + printk("Waiting for receive state with BIS sync\n"); WAIT_FOR_FLAG(flag_recv_state_updated_with_bis_sync); test_bass_remove_source(); @@ -548,6 +549,7 @@ static void test_main_server_sync_client_rem(void) test_bass_broadcast_code(); + printk("Waiting for receive state with BIS sync\n"); WAIT_FOR_FLAG(flag_recv_state_updated_with_bis_sync); test_bass_remove_source(); @@ -569,6 +571,7 @@ static void test_main_server_sync_server_rem(void) test_bass_broadcast_code(); + printk("Waiting for receive state with BIS sync\n"); WAIT_FOR_FLAG(flag_recv_state_updated_with_bis_sync); WAIT_FOR_FLAG(flag_recv_state_removed); diff --git a/tests/bsim/bluetooth/audio/src/bap_broadcast_sink_test.c b/tests/bsim/bluetooth/audio/src/bap_broadcast_sink_test.c index 70e2e74d738..1f7c91288c8 100644 --- a/tests/bsim/bluetooth/audio/src/bap_broadcast_sink_test.c +++ b/tests/bsim/bluetooth/audio/src/bap_broadcast_sink_test.c @@ -45,8 +45,6 @@ static const struct bt_audio_codec_cap codec_cap = BT_AUDIO_CODEC_CAP_LC3( static K_SEM_DEFINE(sem_started, 0U, ARRAY_SIZE(streams)); static K_SEM_DEFINE(sem_stopped, 0U, ARRAY_SIZE(streams)); -static uint8_t metadata[CONFIG_BT_AUDIO_CODEC_CFG_MAX_METADATA_SIZE]; - /* Create a mask for the maximum BIS we can sync to using the number of streams * we have. We add an additional 1 since the bis indexes start from 1 and not * 0. @@ -54,36 +52,50 @@ static uint8_t metadata[CONFIG_BT_AUDIO_CODEC_CFG_MAX_METADATA_SIZE]; static const uint32_t bis_index_mask = BIT_MASK(ARRAY_SIZE(streams) + 1U); static uint32_t bis_index_bitfield; -static void base_recv_cb(struct bt_bap_broadcast_sink *sink, const struct bt_bap_base *base) +static bool base_subgroup_cb(const struct bt_bap_base_subgroup *subgroup, void *user_data) { - uint32_t base_bis_index_bitfield = 0U; - - if (TEST_FLAG(flag_base_received)) { + static uint8_t metadata[CONFIG_BT_AUDIO_CODEC_CFG_MAX_METADATA_SIZE]; + static size_t metadata_size; + uint8_t *meta; + int ret; - if (base->subgroup_count > 0 && - memcmp(metadata, base->subgroups[0].codec_cfg.meta, - sizeof(base->subgroups[0].codec_cfg.meta)) != 0) { + ret = bt_bap_base_get_subgroup_codec_meta(subgroup, &meta); + if (ret < 0) { + FAIL("Could not get subgroup meta: %d\n", ret); + return false; + } - (void)memcpy(metadata, base->subgroups[0].codec_cfg.meta, - sizeof(base->subgroups[0].codec_cfg.meta)); + if (TEST_FLAG(flag_base_received) && + ((size_t)ret != metadata_size || memcmp(meta, metadata, metadata_size) != 0)) { + printk("Metadata updated\n"); + SET_FLAG(flag_base_metadata_updated); + } - printk("Metadata updated\n"); - SET_FLAG(flag_base_metadata_updated); - } + metadata_size = (size_t)ret; + (void)memcpy(metadata, meta, metadata_size); - return; - } + return true; +} - printk("Received BASE with %u subgroups from broadcast sink %p\n", - base->subgroup_count, sink); +static void base_recv_cb(struct bt_bap_broadcast_sink *sink, const struct bt_bap_base *base, + size_t base_size) +{ + uint32_t base_bis_index_bitfield = 0U; + int ret; + printk("Received BASE with %d subgroups from broadcast sink %p\n", + bt_bap_base_get_subgroup_count(base), sink); - for (size_t i = 0U; i < base->subgroup_count; i++) { - for (size_t j = 0U; j < base->subgroups[i].bis_count; j++) { - const uint8_t index = base->subgroups[i].bis_data[j].index; + ret = bt_bap_base_foreach_subgroup(base, base_subgroup_cb, NULL); + if (ret != 0) { + FAIL("Failed to parse subgroups: %d\n", ret); + return; + } - base_bis_index_bitfield |= BIT(index); - } + ret = bt_bap_base_get_bis_indexes(base, &base_bis_index_bitfield); + if (ret != 0) { + FAIL("Failed to BIS indexes: %d\n", ret); + return; } bis_index_bitfield = base_bis_index_bitfield & bis_index_mask; @@ -667,6 +679,7 @@ static void test_common(void) /* Ensure that we also see the metadata update */ printk("Waiting for metadata update\n"); WAIT_FOR_FLAG(flag_base_metadata_updated) + backchannel_sync_send_all(); /* let other devices know we have received what we wanted */ } diff --git a/tests/bsim/bluetooth/audio/src/bap_broadcast_source_test.c b/tests/bsim/bluetooth/audio/src/bap_broadcast_source_test.c index 2c6c5bc1828..5410d76defa 100644 --- a/tests/bsim/bluetooth/audio/src/bap_broadcast_source_test.c +++ b/tests/bsim/bluetooth/audio/src/bap_broadcast_source_test.c @@ -306,6 +306,36 @@ static void test_broadcast_source_start(struct bt_bap_broadcast_source *source, } } +static void test_broadcast_source_update_metadata(struct bt_bap_broadcast_source *source, + struct bt_le_ext_adv *adv) +{ + uint8_t new_metadata[] = BT_AUDIO_CODEC_CFG_LC3_META(BT_AUDIO_CONTEXT_TYPE_ALERTS); + struct bt_data per_ad; + int err; + + NET_BUF_SIMPLE_DEFINE(base_buf, 128); + + printk("Updating metadata\n"); + err = bt_bap_broadcast_source_update_metadata(source, new_metadata, + ARRAY_SIZE(new_metadata)); + if (err != 0) { + FAIL("Failed to update metadata broadcast source: %d\n", err); + return; + } + + /* Get the new BASE */ + test_broadcast_source_get_base(source, &base_buf); + + /* Update the periodic advertising data with the new BASE */ + per_ad.type = BT_DATA_SVC_DATA16; + per_ad.data_len = base_buf.len; + per_ad.data = base_buf.data; + err = bt_le_per_adv_set_data(adv, &per_ad, 1); + if (err != 0) { + FAIL("Failed to set periodic advertising data: %d\n", err); + } +} + static void test_broadcast_source_stop(struct bt_bap_broadcast_source *source) { int err; @@ -369,7 +399,6 @@ static int stop_extended_adv(struct bt_le_ext_adv *adv) static void test_main(void) { - uint8_t new_metadata[] = BT_AUDIO_CODEC_CFG_LC3_META(BT_AUDIO_CONTEXT_TYPE_ALERTS); struct bt_bap_broadcast_source *source; struct bt_le_ext_adv *adv; int err; @@ -415,13 +444,7 @@ static void test_main(void) backchannel_sync_wait_any(); /* Update metadata while streaming */ - printk("Updating metadata\n"); - err = bt_bap_broadcast_source_update_metadata(source, new_metadata, - ARRAY_SIZE(new_metadata)); - if (err != 0) { - FAIL("Failed to update metadata broadcast source: %d\n", err); - return; - } + test_broadcast_source_update_metadata(source, adv); /* Wait for other devices to have received what they wanted */ backchannel_sync_wait_any(); diff --git a/tests/bsim/bluetooth/audio/src/cap_acceptor_test.c b/tests/bsim/bluetooth/audio/src/cap_acceptor_test.c index 97bedead284..a24e8232b8f 100644 --- a/tests/bsim/bluetooth/audio/src/cap_acceptor_test.c +++ b/tests/bsim/bluetooth/audio/src/cap_acceptor_test.c @@ -122,16 +122,20 @@ static bool subgroup_data_func_cb(struct bt_data *data, void *user_data) return true; } -static bool valid_subgroup_metadata(const struct bt_bap_base_subgroup *subgroup) +static bool valid_subgroup_metadata_cb(const struct bt_bap_base_subgroup *subgroup, void *user_data) { bool stream_context_found = false; - int err; + uint8_t *meta; + int ret; - printk("meta %p len %zu", subgroup->codec_cfg.meta, subgroup->codec_cfg.meta_len); + ret = bt_bap_base_get_subgroup_codec_meta(subgroup, &meta); + if (ret < 0) { + FAIL("Could not get subgroup meta: %d\n", ret); + return false; + } - err = bt_audio_data_parse(subgroup->codec_cfg.meta, subgroup->codec_cfg.meta_len, - subgroup_data_func_cb, &stream_context_found); - if (err != 0 && err != -ECANCELED) { + ret = bt_audio_data_parse(meta, (size_t)ret, subgroup_data_func_cb, &stream_context_found); + if (ret != 0 && ret != -ECANCELED) { return false; } @@ -139,39 +143,43 @@ static bool valid_subgroup_metadata(const struct bt_bap_base_subgroup *subgroup) printk("Subgroup did not have streaming context\n"); } + /* if this is false, the iterater will return early with an error */ return stream_context_found; } -static void base_recv_cb(struct bt_bap_broadcast_sink *sink, const struct bt_bap_base *base) +static void base_recv_cb(struct bt_bap_broadcast_sink *sink, const struct bt_bap_base *base, + size_t base_size) { uint32_t base_bis_index_bitfield = 0U; + int ret; if (TEST_FLAG(flag_base_received)) { return; } - printk("Received BASE with %u subgroups from broadcast sink %p\n", - base->subgroup_count, sink); - - if (base->subgroup_count == 0) { - FAIL("base->subgroup_count was 0"); + ret = bt_bap_base_get_subgroup_count(base); + if (ret < 0) { + FAIL("Failed to get subgroup count: %d\n", ret); return; } + printk("Received BASE with %d subgroups from broadcast sink %p\n", ret, sink); - for (size_t i = 0U; i < base->subgroup_count; i++) { - const struct bt_bap_base_subgroup *subgroup = &base->subgroups[i]; - - for (size_t j = 0U; j < subgroup->bis_count; j++) { - const uint8_t index = subgroup->bis_data[j].index; + if (ret == 0) { + FAIL("subgroup_count was 0"); + return; + } - base_bis_index_bitfield |= BIT(index); - } + ret = bt_bap_base_foreach_subgroup(base, valid_subgroup_metadata_cb, NULL); + if (ret != 0) { + FAIL("Failed to parse subgroups: %d\n", ret); + return; + } - if (!valid_subgroup_metadata(subgroup)) { - FAIL("Subgroup[%zu] has invalid metadata\n", i); - return; - } + ret = bt_bap_base_get_bis_indexes(base, &base_bis_index_bitfield); + if (ret != 0) { + FAIL("Failed to BIS indexes: %d\n", ret); + return; } bis_index_bitfield = base_bis_index_bitfield & bis_index_mask; From 92a813d28b30ad3610464ad996b64a36a7baac78 Mon Sep 17 00:00:00 2001 From: Emil Gydesen Date: Fri, 27 Oct 2023 15:46:32 +0200 Subject: [PATCH 0822/3723] tests: Bluetooth: Unittest of bt_bap_base API Adds unittesting of the bt_bap_base API. Signed-off-by: Emil Gydesen --- tests/bluetooth/audio/bap_base/CMakeLists.txt | 17 + tests/bluetooth/audio/bap_base/prj.conf | 14 + tests/bluetooth/audio/bap_base/src/main.c | 820 ++++++++++++++++++ tests/bluetooth/audio/bap_base/testcase.yaml | 7 + .../audio/bap_base/uut/CMakeLists.txt | 21 + tests/bluetooth/tester/src/btp_bap.c | 7 +- 6 files changed, 883 insertions(+), 3 deletions(-) create mode 100644 tests/bluetooth/audio/bap_base/CMakeLists.txt create mode 100644 tests/bluetooth/audio/bap_base/prj.conf create mode 100644 tests/bluetooth/audio/bap_base/src/main.c create mode 100644 tests/bluetooth/audio/bap_base/testcase.yaml create mode 100644 tests/bluetooth/audio/bap_base/uut/CMakeLists.txt diff --git a/tests/bluetooth/audio/bap_base/CMakeLists.txt b/tests/bluetooth/audio/bap_base/CMakeLists.txt new file mode 100644 index 00000000000..040cf14cd28 --- /dev/null +++ b/tests/bluetooth/audio/bap_base/CMakeLists.txt @@ -0,0 +1,17 @@ +# SPDX-License-Identifier: Apache-2.0 + +cmake_minimum_required(VERSION 3.20.0) + +project(bluetooth_codec) +find_package(Zephyr COMPONENTS unittest HINTS $ENV{ZEPHYR_BASE}) + +add_subdirectory(${ZEPHYR_BASE}/tests/bluetooth/audio/bap_base/uut uut) + +target_link_libraries(testbinary PRIVATE uut) + +target_include_directories(testbinary PRIVATE include) + +target_sources(testbinary + PRIVATE + src/main.c +) diff --git a/tests/bluetooth/audio/bap_base/prj.conf b/tests/bluetooth/audio/bap_base/prj.conf new file mode 100644 index 00000000000..7c39d9c4d23 --- /dev/null +++ b/tests/bluetooth/audio/bap_base/prj.conf @@ -0,0 +1,14 @@ +CONFIG_ZTEST=y + +CONFIG_BT=y +CONFIG_BT_AUDIO=y + +CONFIG_LOG=y +CONFIG_BT_AUDIO_LOG_LEVEL_DBG=y +CONFIG_BT_AUDIO_CODEC_LOG_LEVEL_DBG=y +CONFIG_BT_AUDIO_CODEC_CFG_MAX_METADATA_SIZE=15 +CONFIG_BT_AUDIO_CODEC_CAP_MAX_METADATA_SIZE=15 + +CONFIG_ASSERT=y +CONFIG_ASSERT_LEVEL=2 +CONFIG_ASSERT_VERBOSE=y diff --git a/tests/bluetooth/audio/bap_base/src/main.c b/tests/bluetooth/audio/bap_base/src/main.c new file mode 100644 index 00000000000..3636e6d4d42 --- /dev/null +++ b/tests/bluetooth/audio/bap_base/src/main.c @@ -0,0 +1,820 @@ +/* main.c - Application main entry point */ + +/* + * Copyright (c) 2023 Nordic Semiconductor ASA + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include + +#include +#include + +DEFINE_FFF_GLOBALS; + +struct bap_base_test_suite_fixture { + struct bt_data valid_base_ad; + uint8_t *valid_base_data; + struct bt_data invalid_base_ad; + uint8_t *invalid_base_data; +}; + +static void bap_base_test_suite_fixture_init(struct bap_base_test_suite_fixture *fixture) +{ + uint8_t base_data[] = { + 0x51, 0x18, /* uuid */ + 0x40, 0x9C, 0x00, /* pd */ + 0x02, /* subgroup count */ + 0x01, /* Subgroup 1: bis count */ + 0x06, 0x00, 0x00, 0x00, 0x00, /* LC3 codec_id*/ + 0x10, /* cc length */ + 0x02, 0x01, 0x03, 0x02, 0x02, 0x01, 0x05, 0x03, + 0x01, 0x00, 0x00, 0x00, 0x03, 0x04, 0x28, 0x00, /* cc */ + 0x04, /* meta length */ + 0x03, 0x02, 0x01, 0x00, /* meta */ + 0x01, /* bis index */ + 0x03, /* bis cc length */ + 0x02, 0x03, 0x03, /* bis cc length */ + 0x01, /* Subgroup 1: bis count */ + 0x06, 0x00, 0x00, 0x00, 0x00, /* LC3 codec_id*/ + 0x10, /* cc length */ + 0x02, 0x01, 0x03, 0x02, 0x02, 0x01, 0x05, 0x03, + 0x01, 0x00, 0x00, 0x00, 0x03, 0x04, 0x28, 0x00, /* cc */ + 0x04, /* meta length */ + 0x03, 0x02, 0x01, 0x00, /* meta */ + 0x02, /* bis index */ + 0x03, /* bis cc length */ + 0x02, 0x03, 0x03 /* bis cc length */ + }; + + fixture->valid_base_data = malloc(sizeof(base_data)); + zassert_not_null(fixture->valid_base_data); + memcpy(fixture->valid_base_data, base_data, sizeof(base_data)); + + fixture->valid_base_ad.type = 0x16; /* service data */ + fixture->valid_base_ad.data_len = sizeof(base_data); + fixture->valid_base_ad.data = fixture->valid_base_data; + + /* Modify the CC length to generate an invalid BASE for invalid BASE tests */ + base_data[12] = 0xaa; /* Set invalid CC length*/ + fixture->invalid_base_data = malloc(sizeof(base_data)); + zassert_not_null(fixture->invalid_base_data); + memcpy(fixture->invalid_base_data, base_data, sizeof(base_data)); + + fixture->invalid_base_ad.type = 0x16; /* service data */ + fixture->invalid_base_ad.data_len = sizeof(base_data); + fixture->invalid_base_ad.data = fixture->invalid_base_data; +} + +static void *bap_base_test_suite_setup(void) +{ + struct bap_base_test_suite_fixture *fixture; + + fixture = malloc(sizeof(*fixture)); + zassert_not_null(fixture); + + return fixture; +} + +static void bap_base_test_suite_before(void *f) +{ + memset(f, 0, sizeof(struct bap_base_test_suite_fixture)); + bap_base_test_suite_fixture_init(f); +} + +static void bap_base_test_suite_after(void *f) +{ + struct bap_base_test_suite_fixture *fixture = f; + + free(fixture->valid_base_data); +} + +static void bap_base_test_suite_teardown(void *f) +{ + free(f); +} + +ZTEST_SUITE(bap_base_test_suite, NULL, bap_base_test_suite_setup, bap_base_test_suite_before, + bap_base_test_suite_after, bap_base_test_suite_teardown); + +ZTEST_F(bap_base_test_suite, test_base_get_base_from_ad) +{ + const struct bt_bap_base *base = bt_bap_base_get_base_from_ad(&fixture->valid_base_ad); + + zassert_not_null(base); +} + +ZTEST_F(bap_base_test_suite, test_base_get_base_from_ad_inval_base) +{ + const struct bt_bap_base *base = bt_bap_base_get_base_from_ad(&fixture->invalid_base_ad); + + zassert_is_null(base); +} + +ZTEST_F(bap_base_test_suite, test_base_get_base_from_ad_inval_param_null) +{ + const struct bt_bap_base *base = bt_bap_base_get_base_from_ad(NULL); + + zassert_is_null(base); +} + +ZTEST_F(bap_base_test_suite, test_base_get_base_from_ad_inval_param_type) +{ + const struct bt_bap_base *base; + + fixture->valid_base_ad.type = 0x03; /* BT_DATA_UUID16_ALL */ + + base = bt_bap_base_get_base_from_ad(&fixture->valid_base_ad); + + zassert_is_null(base); +} + +ZTEST_F(bap_base_test_suite, test_base_get_base_from_ad_inval_param_len) +{ + const struct bt_bap_base *base; + + fixture->valid_base_ad.data_len = 0x03; /* Minimum len is BASE_MIN_SIZE (16) */ + + base = bt_bap_base_get_base_from_ad(&fixture->valid_base_ad); + + zassert_is_null(base); +} + +ZTEST_F(bap_base_test_suite, test_base_get_base_from_ad_inval_param_uuid) +{ + const struct bt_bap_base *base; + + /* Modify the BASE data to have invalid UUID */ + fixture->valid_base_data[0] = 0x01; + fixture->valid_base_data[1] = 0x02; + + base = bt_bap_base_get_base_from_ad(&fixture->valid_base_ad); + + zassert_is_null(base); +} + +ZTEST_F(bap_base_test_suite, test_base_get_pres_delay) +{ + const struct bt_bap_base *base = bt_bap_base_get_base_from_ad(&fixture->valid_base_ad); + int ret; + + zassert_not_null(base); + + ret = bt_bap_base_get_pres_delay(base); + zassert_equal(ret, 40000, "Unexpected presentation delay: %d", ret); +} + +ZTEST_F(bap_base_test_suite, test_base_get_pres_delay_inval_param_null) +{ + int ret; + + ret = bt_bap_base_get_pres_delay(NULL); + zassert_equal(ret, -EINVAL, "Unexpected return value: %d", ret); +} + +ZTEST_F(bap_base_test_suite, test_base_get_subgroup_count) +{ + const struct bt_bap_base *base = bt_bap_base_get_base_from_ad(&fixture->valid_base_ad); + int ret; + + zassert_not_null(base); + + ret = bt_bap_base_get_subgroup_count(base); + zassert_equal(ret, 2, "Unexpected presentation delay: %d", ret); +} + +ZTEST_F(bap_base_test_suite, test_base_get_subgroup_count_inval_param_null) +{ + int ret; + + ret = bt_bap_base_get_subgroup_count(NULL); + zassert_equal(ret, -EINVAL, "Unexpected return value: %d", ret); +} + +ZTEST_F(bap_base_test_suite, test_base_get_bis_indexes) +{ + const struct bt_bap_base *base = bt_bap_base_get_base_from_ad(&fixture->valid_base_ad); + uint32_t bis_indexes; + int ret; + + zassert_not_null(base); + + ret = bt_bap_base_get_bis_indexes(base, &bis_indexes); + zassert_equal(ret, 0, "Unexpected return value: %d", ret); + zassert_equal(bis_indexes, 0x00000006 /* Bit 1 and 2 */, + "Unexpected BIS index value: 0x%08X", bis_indexes); +} + +ZTEST_F(bap_base_test_suite, test_base_get_bis_indexes_inval_param_null_base) +{ + uint32_t bis_indexes; + int ret; + + ret = bt_bap_base_get_bis_indexes(NULL, &bis_indexes); + zassert_equal(ret, -EINVAL, "Unexpected return value: %d", ret); +} + +ZTEST_F(bap_base_test_suite, test_base_get_bis_indexes_inval_param_null_index) +{ + const struct bt_bap_base *base = bt_bap_base_get_base_from_ad(&fixture->valid_base_ad); + int ret; + + zassert_not_null(base); + + ret = bt_bap_base_get_bis_indexes(base, NULL); + zassert_equal(ret, -EINVAL, "Unexpected return value: %d", ret); +} + +static bool test_base_foreach_subgroup_cb(const struct bt_bap_base_subgroup *subgroup, + void *user_data) +{ + size_t *count = user_data; + + (*count)++; + + return true; +} + +ZTEST_F(bap_base_test_suite, test_base_foreach_subgroup) +{ + const struct bt_bap_base *base = bt_bap_base_get_base_from_ad(&fixture->valid_base_ad); + size_t count = 0U; + int ret; + + zassert_not_null(base); + + ret = bt_bap_base_foreach_subgroup(base, test_base_foreach_subgroup_cb, &count); + zassert_equal(ret, 0, "Unexpected return value: %d", ret); + zassert_equal(count, 0x02, "Unexpected subgroup count value: %u", count); +} + +ZTEST_F(bap_base_test_suite, test_base_foreach_subgroup_inval_param_null_base) +{ + size_t count; + int ret; + + ret = bt_bap_base_foreach_subgroup(NULL, test_base_foreach_subgroup_cb, &count); + zassert_equal(ret, -EINVAL, "Unexpected return value: %d", ret); +} + +ZTEST_F(bap_base_test_suite, test_base_foreach_subgroup_inval_param_null_cb) +{ + const struct bt_bap_base *base = bt_bap_base_get_base_from_ad(&fixture->valid_base_ad); + int ret; + + zassert_not_null(base); + + ret = bt_bap_base_foreach_subgroup(base, NULL, NULL); + zassert_equal(ret, -EINVAL, "Unexpected return value: %d", ret); +} + +static bool test_base_get_subgroup_codec_id_cb(const struct bt_bap_base_subgroup *subgroup, + void *user_data) +{ + struct bt_bap_base_codec_id codec_id; + int ret; + + ret = bt_bap_base_get_subgroup_codec_id(subgroup, &codec_id); + zassert_equal(ret, 0, "Unexpected return value: %d", ret); + zassert_equal(codec_id.id, 0x06, "Unexpected codec.id value: %u", codec_id.id); + zassert_equal(codec_id.cid, 0x0000, "Unexpected codec.cid value: %u", codec_id.cid); + zassert_equal(codec_id.vid, 0x0000, "Unexpected codec.vid value: %u", codec_id.vid); + + return true; +} + +ZTEST_F(bap_base_test_suite, test_base_get_subgroup_codec_id) +{ + const struct bt_bap_base *base = bt_bap_base_get_base_from_ad(&fixture->valid_base_ad); + int ret; + + zassert_not_null(base); + + ret = bt_bap_base_foreach_subgroup(base, test_base_get_subgroup_codec_id_cb, NULL); + zassert_equal(ret, 0, "Unexpected return value: %d", ret); +} + +static bool test_base_get_subgroup_codec_id_inval_param_null_subgroup_cb( + const struct bt_bap_base_subgroup *subgroup, void *user_data) +{ + struct bt_bap_base_codec_id codec_id; + int ret; + + ret = bt_bap_base_get_subgroup_codec_id(NULL, &codec_id); + zassert_equal(ret, -EINVAL, "Unexpected return value: %d", ret); + + return true; +} + +ZTEST_F(bap_base_test_suite, test_base_get_subgroup_codec_id_inval_param_null_subgroup) +{ + const struct bt_bap_base *base = bt_bap_base_get_base_from_ad(&fixture->valid_base_ad); + int ret; + + zassert_not_null(base); + + ret = bt_bap_base_foreach_subgroup( + base, test_base_get_subgroup_codec_id_inval_param_null_subgroup_cb, NULL); + zassert_equal(ret, 0, "Unexpected return value: %d", ret); +} + +static bool +test_base_get_subgroup_codec_id_inval_param_null_cb(const struct bt_bap_base_subgroup *subgroup, + void *user_data) +{ + int ret; + + ret = bt_bap_base_get_subgroup_codec_id(subgroup, NULL); + zassert_equal(ret, -EINVAL, "Unexpected return value: %d", ret); + + return true; +} + +ZTEST_F(bap_base_test_suite, test_base_get_subgroup_codec_id_inval_param_null) +{ + const struct bt_bap_base *base = bt_bap_base_get_base_from_ad(&fixture->valid_base_ad); + int ret; + + zassert_not_null(base); + + ret = bt_bap_base_foreach_subgroup(base, test_base_get_subgroup_codec_id_cb, NULL); + zassert_equal(ret, 0, "Unexpected return value: %d", ret); +} + +static bool test_base_get_subgroup_codec_data_cb(const struct bt_bap_base_subgroup *subgroup, + void *user_data) +{ + const uint8_t expected_data[] = { + 0x02, 0x01, 0x03, 0x02, 0x02, 0x01, 0x05, 0x03, + 0x01, 0x00, 0x00, 0x00, 0x03, 0x04, 0x28, 0x00, + }; + uint8_t *data; + int ret; + + ret = bt_bap_base_get_subgroup_codec_data(subgroup, &data); + zassert_equal(ret, sizeof(expected_data), "Unexpected return value: %d", ret); + zassert_mem_equal(data, expected_data, sizeof(expected_data)); + + return true; +} + +ZTEST_F(bap_base_test_suite, test_base_get_subgroup_codec_data) +{ + const struct bt_bap_base *base = bt_bap_base_get_base_from_ad(&fixture->valid_base_ad); + int ret; + + zassert_not_null(base); + + ret = bt_bap_base_foreach_subgroup(base, test_base_get_subgroup_codec_data_cb, NULL); + zassert_equal(ret, 0, "Unexpected return value: %d", ret); +} + +static bool test_base_get_subgroup_codec_data_inval_param_null_subgroup_cb( + const struct bt_bap_base_subgroup *subgroup, void *user_data) +{ + uint8_t *data; + int ret; + + ret = bt_bap_base_get_subgroup_codec_data(NULL, &data); + zassert_equal(ret, -EINVAL, "Unexpected return value: %d", ret); + + return true; +} + +ZTEST_F(bap_base_test_suite, test_base_get_subgroup_codec_data_inval_param_null_subgroup) +{ + const struct bt_bap_base *base = bt_bap_base_get_base_from_ad(&fixture->valid_base_ad); + int ret; + + zassert_not_null(base); + + ret = bt_bap_base_foreach_subgroup( + base, test_base_get_subgroup_codec_data_inval_param_null_subgroup_cb, NULL); + zassert_equal(ret, 0, "Unexpected return value: %d", ret); +} + +static bool +test_base_get_subgroup_codec_data_inval_param_null_cb(const struct bt_bap_base_subgroup *subgroup, + void *user_data) +{ + int ret; + + ret = bt_bap_base_get_subgroup_codec_data(subgroup, NULL); + zassert_equal(ret, -EINVAL, "Unexpected return value: %d", ret); + + return true; +} + +ZTEST_F(bap_base_test_suite, test_base_get_subgroup_codec_data_inval_param_null) +{ + const struct bt_bap_base *base = bt_bap_base_get_base_from_ad(&fixture->valid_base_ad); + int ret; + + zassert_not_null(base); + + ret = bt_bap_base_foreach_subgroup(base, test_base_get_subgroup_codec_data_cb, NULL); + zassert_equal(ret, 0, "Unexpected return value: %d", ret); +} + +static bool test_base_get_subgroup_codec_meta_cb(const struct bt_bap_base_subgroup *subgroup, + void *user_data) +{ + const uint8_t expected_data[] = {0x03, 0x02, 0x01, 0x00}; + uint8_t *data; + int ret; + + ret = bt_bap_base_get_subgroup_codec_meta(subgroup, &data); + zassert_equal(ret, sizeof(expected_data), "Unexpected return value: %d", ret); + zassert_mem_equal(data, expected_data, sizeof(expected_data)); + + return true; +} + +ZTEST_F(bap_base_test_suite, test_base_get_subgroup_codec_meta) +{ + const struct bt_bap_base *base = bt_bap_base_get_base_from_ad(&fixture->valid_base_ad); + int ret; + + zassert_not_null(base); + + ret = bt_bap_base_foreach_subgroup(base, test_base_get_subgroup_codec_meta_cb, NULL); + zassert_equal(ret, 0, "Unexpected return value: %d", ret); +} + +static bool test_base_get_subgroup_codec_meta_inval_param_null_subgroup_cb( + const struct bt_bap_base_subgroup *subgroup, void *user_data) +{ + uint8_t *data; + int ret; + + ret = bt_bap_base_get_subgroup_codec_meta(NULL, &data); + zassert_equal(ret, -EINVAL, "Unexpected return value: %d", ret); + + return true; +} + +ZTEST_F(bap_base_test_suite, test_base_get_subgroup_codec_meta_inval_param_null_subgroup) +{ + const struct bt_bap_base *base = bt_bap_base_get_base_from_ad(&fixture->valid_base_ad); + int ret; + + zassert_not_null(base); + + ret = bt_bap_base_foreach_subgroup( + base, test_base_get_subgroup_codec_meta_inval_param_null_subgroup_cb, NULL); + zassert_equal(ret, 0, "Unexpected return value: %d", ret); +} + +static bool +test_base_get_subgroup_codec_meta_inval_param_null_cb(const struct bt_bap_base_subgroup *subgroup, + void *user_data) +{ + int ret; + + ret = bt_bap_base_get_subgroup_codec_meta(subgroup, NULL); + zassert_equal(ret, -EINVAL, "Unexpected return value: %d", ret); + + return true; +} + +ZTEST_F(bap_base_test_suite, test_base_get_subgroup_codec_meta_inval_param_null) +{ + const struct bt_bap_base *base = bt_bap_base_get_base_from_ad(&fixture->valid_base_ad); + int ret; + + zassert_not_null(base); + + ret = bt_bap_base_foreach_subgroup(base, test_base_get_subgroup_codec_meta_cb, NULL); + zassert_equal(ret, 0, "Unexpected return value: %d", ret); +} + +static bool test_base_subgroup_codec_to_codec_cfg_cb(const struct bt_bap_base_subgroup *subgroup, + void *user_data) +{ + const uint8_t expected_meta[] = {0x03, 0x02, 0x01, 0x00}; + const uint8_t expected_data[] = { + 0x02, 0x01, 0x03, 0x02, 0x02, 0x01, 0x05, 0x03, + 0x01, 0x00, 0x00, 0x00, 0x03, 0x04, 0x28, 0x00, + }; + struct bt_audio_codec_cfg codec_cfg; + int ret; + + ret = bt_bap_base_subgroup_codec_to_codec_cfg(subgroup, &codec_cfg); + zassert_equal(ret, 0, "Unexpected return value: %d", ret); + zassert_equal(codec_cfg.data_len, sizeof(expected_data), "Unexpected data length: %d", ret); + zassert_equal(codec_cfg.meta_len, sizeof(expected_meta), "Unexpected meta length: %d", ret); + zassert_mem_equal(codec_cfg.data, expected_data, sizeof(expected_data)); + zassert_mem_equal(codec_cfg.meta, expected_meta, sizeof(expected_meta)); + + return true; +} + +ZTEST_F(bap_base_test_suite, test_base_subgroup_codec_to_codec_cfg) +{ + const struct bt_bap_base *base = bt_bap_base_get_base_from_ad(&fixture->valid_base_ad); + int ret; + + zassert_not_null(base); + + ret = bt_bap_base_foreach_subgroup(base, test_base_subgroup_codec_to_codec_cfg_cb, NULL); + zassert_equal(ret, 0, "Unexpected return value: %d", ret); +} + +static bool test_base_subgroup_codec_to_codec_cfg_inval_param_null_subgroup_cb( + const struct bt_bap_base_subgroup *subgroup, void *user_data) +{ + struct bt_audio_codec_cfg codec_cfg; + int ret; + + ret = bt_bap_base_subgroup_codec_to_codec_cfg(NULL, &codec_cfg); + zassert_equal(ret, -EINVAL, "Unexpected return value: %d", ret); + + return true; +} + +ZTEST_F(bap_base_test_suite, test_base_subgroup_codec_to_codec_cfg_inval_param_null_subgroup) +{ + const struct bt_bap_base *base = bt_bap_base_get_base_from_ad(&fixture->valid_base_ad); + int ret; + + zassert_not_null(base); + + ret = bt_bap_base_foreach_subgroup( + base, test_base_subgroup_codec_to_codec_cfg_inval_param_null_subgroup_cb, NULL); + zassert_equal(ret, 0, "Unexpected return value: %d", ret); +} + +static bool test_base_subgroup_codec_to_codec_cfg_inval_param_null_cb( + const struct bt_bap_base_subgroup *subgroup, void *user_data) +{ + int ret; + + ret = bt_bap_base_subgroup_codec_to_codec_cfg(subgroup, NULL); + zassert_equal(ret, -EINVAL, "Unexpected return value: %d", ret); + + return true; +} + +ZTEST_F(bap_base_test_suite, test_base_subgroup_codec_to_codec_cfg_inval_param_null) +{ + const struct bt_bap_base *base = bt_bap_base_get_base_from_ad(&fixture->valid_base_ad); + int ret; + + zassert_not_null(base); + + ret = bt_bap_base_foreach_subgroup(base, test_base_subgroup_codec_to_codec_cfg_cb, NULL); + zassert_equal(ret, 0, "Unexpected return value: %d", ret); +} + +static bool test_base_get_subgroup_bis_count_cb(const struct bt_bap_base_subgroup *subgroup, + void *user_data) +{ + int ret; + + ret = bt_bap_base_get_subgroup_bis_count(subgroup); + zassert_equal(ret, 0x01, "Unexpected return value: %d", ret); + + return true; +} + +ZTEST_F(bap_base_test_suite, test_base_get_subgroup_bis_count) +{ + const struct bt_bap_base *base = bt_bap_base_get_base_from_ad(&fixture->valid_base_ad); + int ret; + + zassert_not_null(base); + + ret = bt_bap_base_foreach_subgroup(base, test_base_get_subgroup_bis_count_cb, NULL); + zassert_equal(ret, 0, "Unexpected return value: %d", ret); +} + +static bool test_base_get_subgroup_bis_count_inval_param_null_subgroup_cb( + const struct bt_bap_base_subgroup *subgroup, void *user_data) +{ + int ret; + + ret = bt_bap_base_get_subgroup_bis_count(NULL); + zassert_equal(ret, -EINVAL, "Unexpected return value: %d", ret); + + return true; +} + +ZTEST_F(bap_base_test_suite, test_base_get_subgroup_bis_count_inval_param_null_subgroup) +{ + const struct bt_bap_base *base = bt_bap_base_get_base_from_ad(&fixture->valid_base_ad); + int ret; + + zassert_not_null(base); + + ret = bt_bap_base_foreach_subgroup( + base, test_base_get_subgroup_bis_count_inval_param_null_subgroup_cb, NULL); + zassert_equal(ret, 0, "Unexpected return value: %d", ret); +} + +static bool +test_base_subgroup_foreach_bis_subgroup_bis_cb(const struct bt_bap_base_subgroup_bis *bis, + void *user_data) +{ + size_t *count = user_data; + + (*count)++; + + return true; +} + +static bool test_base_subgroup_foreach_bis_subgroup_cb(const struct bt_bap_base_subgroup *subgroup, + void *user_data) +{ + size_t *total_count = user_data; + size_t count = 0U; + int ret; + + ret = bt_bap_base_subgroup_foreach_bis( + subgroup, test_base_subgroup_foreach_bis_subgroup_bis_cb, &count); + zassert_equal(ret, 0, "Unexpected return value: %d", ret); + zassert_equal(count, 0x01, "Unexpected subgroup count value: %u", count); + + *total_count += count; + + return true; +} + +ZTEST_F(bap_base_test_suite, test_base_subgroup_foreach_bis) +{ + const struct bt_bap_base *base = bt_bap_base_get_base_from_ad(&fixture->valid_base_ad); + size_t count = 0U; + int ret; + + zassert_not_null(base); + + ret = bt_bap_base_foreach_subgroup(base, test_base_subgroup_foreach_bis_subgroup_cb, + &count); + zassert_equal(ret, 0, "Unexpected return value: %d", ret); + zassert_equal(count, 0x02, "Unexpected subgroup count value: %u", count); +} + +static bool test_base_subgroup_foreach_bis_inval_param_null_subgroup_cb( + const struct bt_bap_base_subgroup *subgroup, void *user_data) +{ + size_t count; + int ret; + + ret = bt_bap_base_subgroup_foreach_bis(NULL, test_base_subgroup_foreach_bis_subgroup_bis_cb, + &count); + zassert_equal(ret, -EINVAL, "Unexpected return value: %d", ret); + + return true; +} + +ZTEST_F(bap_base_test_suite, test_base_subgroup_foreach_bis_inval_param_null_subgroup) +{ + const struct bt_bap_base *base = bt_bap_base_get_base_from_ad(&fixture->valid_base_ad); + int ret; + + zassert_not_null(base); + + ret = bt_bap_base_foreach_subgroup( + base, test_base_subgroup_foreach_bis_inval_param_null_subgroup_cb, NULL); + zassert_equal(ret, 0, "Unexpected return value: %d", ret); +} + +static bool +test_base_subgroup_foreach_bis_inval_param_null_cb_cb(const struct bt_bap_base_subgroup *subgroup, + void *user_data) +{ + int ret; + + ret = bt_bap_base_subgroup_foreach_bis(subgroup, NULL, NULL); + zassert_equal(ret, -EINVAL, "Unexpected return value: %d", ret); + + return true; +} + +ZTEST_F(bap_base_test_suite, test_base_subgroup_foreach_bis_inval_param_null_cb) +{ + const struct bt_bap_base *base = bt_bap_base_get_base_from_ad(&fixture->valid_base_ad); + int ret; + + zassert_not_null(base); + + ret = bt_bap_base_foreach_subgroup( + base, test_base_subgroup_foreach_bis_inval_param_null_cb_cb, NULL); + zassert_equal(ret, 0, "Unexpected return value: %d", ret); +} + +static bool +test_base_subgroup_bis_codec_to_codec_cfg_bis_cb(const struct bt_bap_base_subgroup_bis *bis, + void *user_data) +{ + const uint8_t expected_data[] = {0x02, 0x03, 0x03}; + struct bt_audio_codec_cfg codec_cfg; + int ret; + + ret = bt_bap_base_subgroup_bis_codec_to_codec_cfg(bis, &codec_cfg); + zassert_equal(ret, 0, "Unexpected return value: %d", ret); + zassert_equal(codec_cfg.data_len, sizeof(expected_data), "Unexpected data length: %d", ret); + zassert_mem_equal(codec_cfg.data, expected_data, sizeof(expected_data)); + + return true; +} + +static bool +test_base_subgroup_bis_codec_to_codec_cfg_subgroup_cb(const struct bt_bap_base_subgroup *subgroup, + void *user_data) +{ + int ret; + + ret = bt_bap_base_subgroup_foreach_bis( + subgroup, test_base_subgroup_bis_codec_to_codec_cfg_bis_cb, NULL); + zassert_equal(ret, 0, "Unexpected return value: %d", ret); + + return true; +} + +ZTEST_F(bap_base_test_suite, test_base_subgroup_bis_codec_to_codec_cfg) +{ + const struct bt_bap_base *base = bt_bap_base_get_base_from_ad(&fixture->valid_base_ad); + int ret; + + zassert_not_null(base); + + ret = bt_bap_base_foreach_subgroup( + base, test_base_subgroup_bis_codec_to_codec_cfg_subgroup_cb, NULL); + zassert_equal(ret, 0, "Unexpected return value: %d", ret); +} + +static bool test_base_subgroup_bis_codec_to_codec_cfg_inval_param_null_bis_bis_cb( + const struct bt_bap_base_subgroup_bis *bis, void *user_data) +{ + struct bt_audio_codec_cfg codec_cfg; + int ret; + + ret = bt_bap_base_subgroup_bis_codec_to_codec_cfg(NULL, &codec_cfg); + zassert_equal(ret, -EINVAL, "Unexpected return value: %d", ret); + + return true; +} + +static bool test_base_subgroup_bis_codec_to_codec_cfg_inval_param_null_bis_subgroup_cb( + const struct bt_bap_base_subgroup *subgroup, void *user_data) +{ + int ret; + + ret = bt_bap_base_subgroup_foreach_bis( + NULL, test_base_subgroup_bis_codec_to_codec_cfg_inval_param_null_bis_bis_cb, NULL); + zassert_equal(ret, -EINVAL, "Unexpected return value: %d", ret); + + return true; +} + +ZTEST_F(bap_base_test_suite, test_base_subgroup_foreach_bis_inval_param_null_bis) +{ + const struct bt_bap_base *base = bt_bap_base_get_base_from_ad(&fixture->valid_base_ad); + int ret; + + zassert_not_null(base); + + ret = bt_bap_base_foreach_subgroup( + base, test_base_subgroup_bis_codec_to_codec_cfg_inval_param_null_bis_subgroup_cb, + NULL); + zassert_equal(ret, 0, "Unexpected return value: %d", ret); +} + +static bool test_base_subgroup_bis_codec_to_codec_cfg_inval_param_null_codec_cfg_bis_cb( + const struct bt_bap_base_subgroup_bis *bis, void *user_data) +{ + int ret; + + ret = bt_bap_base_subgroup_bis_codec_to_codec_cfg(bis, NULL); + zassert_equal(ret, -EINVAL, "Unexpected return value: %d", ret); + + return true; +} + +static bool test_base_subgroup_bis_codec_to_codec_cfg_inval_param_null_codec_cfg_subgroup_cb( + const struct bt_bap_base_subgroup *subgroup, void *user_data) +{ + int ret; + + ret = bt_bap_base_subgroup_foreach_bis( + NULL, test_base_subgroup_bis_codec_to_codec_cfg_inval_param_null_codec_cfg_bis_cb, + NULL); + zassert_equal(ret, -EINVAL, "Unexpected return value: %d", ret); + + return true; +} + +ZTEST_F(bap_base_test_suite, test_base_subgroup_foreach_bis_inval_param_null_codec_cfg) +{ + const struct bt_bap_base *base = bt_bap_base_get_base_from_ad(&fixture->valid_base_ad); + int ret; + + zassert_not_null(base); + + ret = bt_bap_base_foreach_subgroup( + base, + test_base_subgroup_bis_codec_to_codec_cfg_inval_param_null_codec_cfg_subgroup_cb, + NULL); + zassert_equal(ret, 0, "Unexpected return value: %d", ret); +} diff --git a/tests/bluetooth/audio/bap_base/testcase.yaml b/tests/bluetooth/audio/bap_base/testcase.yaml new file mode 100644 index 00000000000..4db9dd64d8c --- /dev/null +++ b/tests/bluetooth/audio/bap_base/testcase.yaml @@ -0,0 +1,7 @@ +common: + tags: + - bluetooth + - bluetooth_audio +tests: + bluetooth.audio.bap_base.test_default: + type: unit diff --git a/tests/bluetooth/audio/bap_base/uut/CMakeLists.txt b/tests/bluetooth/audio/bap_base/uut/CMakeLists.txt new file mode 100644 index 00000000000..4891c4794d5 --- /dev/null +++ b/tests/bluetooth/audio/bap_base/uut/CMakeLists.txt @@ -0,0 +1,21 @@ +# +# Copyright (c) 2023 Codecoup +# +# SPDX-License-Identifier: Apache-2.0 +# +# CMakeLists.txt file for creating of uut library. +# + +add_library(uut STATIC + ${ZEPHYR_BASE}/subsys/bluetooth/audio/bap_base.c + ${ZEPHYR_BASE}/subsys/bluetooth/host/uuid.c + ${ZEPHYR_BASE}/subsys/bluetooth/common/bt_str.c + ${ZEPHYR_BASE}/subsys/logging/log_minimal.c + ${ZEPHYR_BASE}/subsys/net/buf_simple.c +) + +add_subdirectory(${ZEPHYR_BASE}/tests/bluetooth/audio/mocks mocks) + +target_link_libraries(uut PUBLIC test_interface mocks) + +target_compile_options(uut PRIVATE -std=c11 -include ztest.h) diff --git a/tests/bluetooth/tester/src/btp_bap.c b/tests/bluetooth/tester/src/btp_bap.c index c38ad00749f..73f4b0f5547 100644 --- a/tests/bluetooth/tester/src/btp_bap.c +++ b/tests/bluetooth/tester/src/btp_bap.c @@ -127,7 +127,8 @@ static uint32_t requested_bis_sync; static const struct bt_bap_scan_delegator_recv_state *sink_recv_state; static const struct bt_bap_scan_delegator_recv_state *broadcast_recv_state; static uint8_t sink_broadcast_code[BT_AUDIO_BROADCAST_CODE_SIZE]; -static struct bt_bap_scan_delegator_subgroup delegator_subgroups[BROADCAST_SNK_SUBGROUP_CNT]; +static struct bt_bap_scan_delegator_subgroup + delegator_subgroups[BT_BAP_SCAN_DELEGATOR_MAX_SUBGROUPS]; static bool print_cb(struct bt_data *data, void *user_data) { @@ -2213,7 +2214,7 @@ static uint8_t broadcast_assistant_add_src(const void *cmd, uint16_t cmd_len, param.pa_sync = cp->padv_sync > 0 ? true : false; param.broadcast_id = sys_get_le24(cp->broadcast_id); param.pa_interval = sys_le16_to_cpu(cp->padv_interval); - param.num_subgroups = MIN(cp->num_subgroups, BROADCAST_SNK_SUBGROUP_CNT); + param.num_subgroups = MIN(cp->num_subgroups, BT_BAP_SCAN_DELEGATOR_MAX_SUBGROUPS); param.subgroups = delegator_subgroups; ptr = cp->subgroups; @@ -2280,7 +2281,7 @@ static uint8_t broadcast_assistant_modify_src(const void *cmd, uint16_t cmd_len, param.src_id = cp->src_id; param.pa_sync = cp->padv_sync > 0 ? true : false; param.pa_interval = sys_le16_to_cpu(cp->padv_interval); - param.num_subgroups = MIN(cp->num_subgroups, BROADCAST_SNK_SUBGROUP_CNT); + param.num_subgroups = MIN(cp->num_subgroups, BT_BAP_SCAN_DELEGATOR_MAX_SUBGROUPS); param.subgroups = delegator_subgroups; ptr = cp->subgroups; From 38d73a6ccf3b912da5a680e3d63dd8aaac601b21 Mon Sep 17 00:00:00 2001 From: Emil Gydesen Date: Wed, 15 Nov 2023 15:11:37 +0100 Subject: [PATCH 0823/3723] Bluetooth: VCP: Add bt_vcp_vol_ctlr_get_by_conn Add function to get a volume controller from a connection pointer. This is required for the CAP to get a vol_ctlr pointer from the provided bt_conn. Signed-off-by: Emil Gydesen --- include/zephyr/bluetooth/audio/vcp.h | 14 +++++++++ subsys/bluetooth/audio/vcp_vol_ctlr.c | 44 +++++++++++++++++++++------ 2 files changed, 48 insertions(+), 10 deletions(-) diff --git a/include/zephyr/bluetooth/audio/vcp.h b/include/zephyr/bluetooth/audio/vcp.h index 961fed483d5..f050786ab63 100644 --- a/include/zephyr/bluetooth/audio/vcp.h +++ b/include/zephyr/bluetooth/audio/vcp.h @@ -383,6 +383,20 @@ int bt_vcp_vol_ctlr_cb_register(struct bt_vcp_vol_ctlr_cb *cb); int bt_vcp_vol_ctlr_discover(struct bt_conn *conn, struct bt_vcp_vol_ctlr **vol_ctlr); +/** + * @brief Get the volume controller from a connection pointer + * + * Get the Volume Control Profile Volume Controller pointer from a connection pointer. + * Only volume controllers that have been initiated via bt_vcp_vol_ctlr_discover() can be + * retrieved. + * + * @param conn Connection pointer. + * + * @retval Pointer to a Volume Control Profile Volume Controller instance + * @retval NULL if @p conn is NULL or if the connection has not done discovery yet + */ +struct bt_vcp_vol_ctlr *bt_vcp_vol_ctlr_get_by_conn(const struct bt_conn *conn); + /** * @brief Get the connection pointer of a client instance * diff --git a/subsys/bluetooth/audio/vcp_vol_ctlr.c b/subsys/bluetooth/audio/vcp_vol_ctlr.c index f8033ba99cf..3defcfbf917 100644 --- a/subsys/bluetooth/audio/vcp_vol_ctlr.c +++ b/subsys/bluetooth/audio/vcp_vol_ctlr.c @@ -34,6 +34,11 @@ static struct bt_vcp_vol_ctlr_cb *vcp_vol_ctlr_cb; static struct bt_vcp_vol_ctlr vol_ctlr_insts[CONFIG_BT_MAX_CONN]; static int vcp_vol_ctlr_common_vcs_cp(struct bt_vcp_vol_ctlr *vol_ctlr, uint8_t opcode); +static struct bt_vcp_vol_ctlr *vol_ctlr_get_by_conn(const struct bt_conn *conn) +{ + return &vol_ctlr_insts[bt_conn_index(conn)]; +} + static uint8_t vcp_vol_ctlr_notify_handler(struct bt_conn *conn, struct bt_gatt_subscribe_params *params, const void *data, uint16_t length) @@ -45,7 +50,7 @@ static uint8_t vcp_vol_ctlr_notify_handler(struct bt_conn *conn, return BT_GATT_ITER_CONTINUE; } - vol_ctlr = &vol_ctlr_insts[bt_conn_index(conn)]; + vol_ctlr = vol_ctlr_get_by_conn(conn); if (handle == vol_ctlr->state_handle && length == sizeof(vol_ctlr->state)) { @@ -74,7 +79,7 @@ static uint8_t vcp_vol_ctlr_read_vol_state_cb(struct bt_conn *conn, uint8_t err, const void *data, uint16_t length) { int cb_err = err; - struct bt_vcp_vol_ctlr *vol_ctlr = &vol_ctlr_insts[bt_conn_index(conn)]; + struct bt_vcp_vol_ctlr *vol_ctlr = vol_ctlr_get_by_conn(conn); vol_ctlr->busy = false; @@ -112,7 +117,7 @@ static uint8_t vcp_vol_ctlr_read_flag_cb(struct bt_conn *conn, uint8_t err, const void *data, uint16_t length) { int cb_err = err; - struct bt_vcp_vol_ctlr *vol_ctlr = &vol_ctlr_insts[bt_conn_index(conn)]; + struct bt_vcp_vol_ctlr *vol_ctlr = vol_ctlr_get_by_conn(conn); vol_ctlr->busy = false; @@ -193,7 +198,7 @@ static uint8_t internal_read_vol_state_cb(struct bt_conn *conn, uint8_t err, const void *data, uint16_t length) { int cb_err = 0; - struct bt_vcp_vol_ctlr *vol_ctlr = &vol_ctlr_insts[bt_conn_index(conn)]; + struct bt_vcp_vol_ctlr *vol_ctlr = vol_ctlr_get_by_conn(conn); uint8_t opcode = vol_ctlr->cp_val.cp.opcode; @@ -242,7 +247,7 @@ static uint8_t internal_read_vol_state_cb(struct bt_conn *conn, uint8_t err, static void vcp_vol_ctlr_write_vcs_cp_cb(struct bt_conn *conn, uint8_t err, struct bt_gatt_write_params *params) { - struct bt_vcp_vol_ctlr *vol_ctlr = &vol_ctlr_insts[bt_conn_index(conn)]; + struct bt_vcp_vol_ctlr *vol_ctlr = vol_ctlr_get_by_conn(conn); uint8_t opcode = vol_ctlr->cp_val.cp.opcode; int cb_err = err; @@ -288,7 +293,7 @@ static uint8_t vcs_discover_include_func(struct bt_conn *conn, struct bt_gatt_include *include; uint8_t inst_idx; int err; - struct bt_vcp_vol_ctlr *vol_ctlr = &vol_ctlr_insts[bt_conn_index(conn)]; + struct bt_vcp_vol_ctlr *vol_ctlr = vol_ctlr_get_by_conn(conn); if (attr == NULL) { LOG_DBG("Discover include complete for vol_ctlr: %u AICS and %u VOCS", @@ -389,7 +394,7 @@ static uint8_t vcs_discover_func(struct bt_conn *conn, int err = 0; struct bt_gatt_chrc *chrc; struct bt_gatt_subscribe_params *sub_params = NULL; - struct bt_vcp_vol_ctlr *vol_ctlr = &vol_ctlr_insts[bt_conn_index(conn)]; + struct bt_vcp_vol_ctlr *vol_ctlr = vol_ctlr_get_by_conn(conn); if (attr == NULL) { LOG_DBG("Setup complete for vol_ctlr"); @@ -467,7 +472,7 @@ static uint8_t primary_discover_func(struct bt_conn *conn, struct bt_gatt_discover_params *params) { struct bt_gatt_service_val *prim_service; - struct bt_vcp_vol_ctlr *vol_ctlr = &vol_ctlr_insts[bt_conn_index(conn)]; + struct bt_vcp_vol_ctlr *vol_ctlr = vol_ctlr_get_by_conn(conn); if (attr == NULL) { LOG_DBG("Could not find a vol_ctlr instance on the server"); @@ -661,7 +666,7 @@ static void vcp_vol_ctlr_reset(struct bt_vcp_vol_ctlr *vol_ctlr) static void disconnected(struct bt_conn *conn, uint8_t reason) { - struct bt_vcp_vol_ctlr *vol_ctlr = &vol_ctlr_insts[bt_conn_index(conn)]; + struct bt_vcp_vol_ctlr *vol_ctlr = vol_ctlr_get_by_conn(conn); if (vol_ctlr->conn == conn) { vcp_vol_ctlr_reset(vol_ctlr); @@ -733,7 +738,7 @@ int bt_vcp_vol_ctlr_discover(struct bt_conn *conn, struct bt_vcp_vol_ctlr **out_ return -EINVAL; } - vol_ctlr = &vol_ctlr_insts[bt_conn_index(conn)]; + vol_ctlr = vol_ctlr_get_by_conn(conn); if (vol_ctlr->busy) { return -EBUSY; @@ -837,6 +842,25 @@ int bt_vcp_vol_ctlr_included_get(struct bt_vcp_vol_ctlr *vol_ctlr, return 0; } +struct bt_vcp_vol_ctlr *bt_vcp_vol_ctlr_get_by_conn(const struct bt_conn *conn) +{ + struct bt_vcp_vol_ctlr *vol_ctlr; + + CHECKIF(conn == NULL) { + LOG_DBG("NULL conn pointer"); + return NULL; + } + + vol_ctlr = vol_ctlr_get_by_conn(conn); + if (vol_ctlr->conn == NULL) { + LOG_DBG("conn %p is not associated with volume controller. Do discovery first", + (void *)conn); + return NULL; + } + + return vol_ctlr; +} + int bt_vcp_vol_ctlr_conn_get(const struct bt_vcp_vol_ctlr *vol_ctlr, struct bt_conn **conn) { CHECKIF(vol_ctlr == NULL) { From f308299ca284ebcc2f81633ba339a4356ca5a2be Mon Sep 17 00:00:00 2001 From: Dmitrii Golovanov Date: Tue, 3 Oct 2023 17:55:46 +0200 Subject: [PATCH 0824/3723] debug: gdbstub: kconfig: Add GDBSTUB_TRACE config option Add GDBSTUB_TRACE config option to extend GDB backend debug logging for remote commands received and to debug the GDB stub itself. Signed-off-by: Dmitrii Golovanov --- arch/x86/core/ia32/gdbstub.c | 24 +++++++++++++++++++ subsys/debug/Kconfig | 6 +++++ subsys/debug/gdbstub.c | 16 ++++++++++++- subsys/debug/gdbstub/gdbstub_backend_serial.c | 7 ++++++ 4 files changed, 52 insertions(+), 1 deletion(-) diff --git a/arch/x86/core/ia32/gdbstub.c b/arch/x86/core/ia32/gdbstub.c index afda9b5a7e2..41b6a4500ff 100644 --- a/arch/x86/core/ia32/gdbstub.c +++ b/arch/x86/core/ia32/gdbstub.c @@ -218,17 +218,41 @@ size_t arch_gdb_reg_writeone(struct gdb_ctx *ctx, uint8_t *hex, size_t hexlen, static __used void z_gdb_debug_isr(z_arch_esf_t *esf) { +#ifdef CONFIG_GDBSTUB_TRACE + printk("gdbstub:enter %s (IV_DEBUG)\n", __func__); +#endif + z_gdb_interrupt(IV_DEBUG, esf); + +#ifdef CONFIG_GDBSTUB_TRACE + printk("gdbstub:exit %s (IV_DEBUG)\n", __func__); +#endif } static __used void z_gdb_break_isr(z_arch_esf_t *esf) { +#ifdef CONFIG_GDBSTUB_TRACE + printk("gdbstub:enter %s (IV_BREAKPOINT)\n", __func__); +#endif + z_gdb_interrupt(IV_BREAKPOINT, esf); + +#ifdef CONFIG_GDBSTUB_TRACE + printk("gdbstub:exit %s (IV_BREAKPOINT)\n", __func__); +#endif } void arch_gdb_init(void) { +#ifdef CONFIG_GDBSTUB_TRACE + printk("gdbstub:%s awaits GDB connection\n", __func__); +#endif + __asm__ volatile ("int3"); + +#ifdef CONFIG_GDBSTUB_TRACE + printk("gdbstub:%s GDB is connected\n", __func__); +#endif } /* Hook current IDT. */ diff --git a/subsys/debug/Kconfig b/subsys/debug/Kconfig index 54d83f18ff6..7da4440c010 100644 --- a/subsys/debug/Kconfig +++ b/subsys/debug/Kconfig @@ -424,6 +424,12 @@ config GDBSTUB_BUF_SZ for GDB backend. This needs to be big enough to hold one full GDB packet at a time. +config GDBSTUB_TRACE + bool "GDB backend extra logging" + help + Enable extra debug logging for the GDB backend, including + breakpoint interrupts and remote commands it receives. + endif config SEGGER_DEBUGMON diff --git a/subsys/debug/gdbstub.c b/subsys/debug/gdbstub.c index 3cced7b0310..e632ff8abf4 100644 --- a/subsys/debug/gdbstub.c +++ b/subsys/debug/gdbstub.c @@ -559,6 +559,10 @@ static int gdb_send_exception(uint8_t *buf, size_t len, uint8_t exception) { size_t size; +#ifdef CONFIG_GDBSTUB_TRACE + printk("gdbstub:%s exception=0x%x\n", __func__, exception); +#endif + *buf = 'T'; size = gdb_bin2hex(&exception, 1, buf + 1, len - 1); if (size == 0) { @@ -644,6 +648,10 @@ int z_gdb_main_loop(struct gdb_ctx *ctx) ptr = buf; +#ifdef CONFIG_GDBSTUB_TRACE + printk("gdbstub:%s got '%c'(0x%x) command\n", __func__, *ptr, *ptr); +#endif + switch (*ptr++) { /** @@ -823,13 +831,19 @@ int z_gdb_main_loop(struct gdb_ctx *ctx) int gdb_init(void) { - +#ifdef CONFIG_GDBSTUB_TRACE + printk("gdbstub:%s enter\n", __func__); +#endif if (z_gdb_backend_init() == -1) { LOG_ERR("Could not initialize gdbstub backend."); return -1; } arch_gdb_init(); + +#ifdef CONFIG_GDBSTUB_TRACE + printk("gdbstub:%s exit\n", __func__); +#endif return 0; } diff --git a/subsys/debug/gdbstub/gdbstub_backend_serial.c b/subsys/debug/gdbstub/gdbstub_backend_serial.c index e9c6c6f9152..c5806cd4e02 100644 --- a/subsys/debug/gdbstub/gdbstub_backend_serial.c +++ b/subsys/debug/gdbstub/gdbstub_backend_serial.c @@ -21,6 +21,10 @@ int z_gdb_backend_init(void) .flow_ctrl = UART_CFG_FLOW_CTRL_NONE }; +#ifdef CONFIG_GDBSTUB_TRACE + printk("gdbstub_serial:%s enter\n", __func__); +#endif + if (uart_dev == NULL) { uart_dev = DEVICE_DT_GET(DT_CHOSEN(zephyr_gdbstub_uart)); @@ -30,6 +34,9 @@ int z_gdb_backend_init(void) __ASSERT(ret == 0, "Could not configure uart device"); } +#ifdef CONFIG_GDBSTUB_TRACE + printk("gdbstub_serial:%s exit\n", __func__); +#endif return ret; } From 52442a7c49ebddf65062185106557a1027d8eb59 Mon Sep 17 00:00:00 2001 From: Dmitrii Golovanov Date: Tue, 28 Nov 2023 00:10:49 +0100 Subject: [PATCH 0825/3723] tests: gdbstub: Fix incomplete code coverage dump When the test runs with code coverage, make sure the coverage dump completes its output under pytest execution before the test debug session ends in both cases: for Zephyr gdbstub feature and for Qemu internal GDB stub. Add few more test operations with breakpoints. Signed-off-by: Dmitrii Golovanov --- tests/subsys/debug/gdbstub/prj.conf | 1 + tests/subsys/debug/gdbstub/pytest/test_gdbstub.py | 12 +++++++++++- tests/subsys/debug/gdbstub/test_breakpoints.gdbinit | 12 +++++++++++- 3 files changed, 23 insertions(+), 2 deletions(-) diff --git a/tests/subsys/debug/gdbstub/prj.conf b/tests/subsys/debug/gdbstub/prj.conf index 8b490380226..a60cee7f7e8 100644 --- a/tests/subsys/debug/gdbstub/prj.conf +++ b/tests/subsys/debug/gdbstub/prj.conf @@ -1,5 +1,6 @@ CONFIG_GDBSTUB=y CONFIG_GDBSTUB_SERIAL_BACKEND=y +CONFIG_GDBSTUB_TRACE=n CONFIG_NO_OPTIMIZATIONS=y CONFIG_USERSPACE=y CONFIG_KOBJECT_TEXT_AREA=4096 diff --git a/tests/subsys/debug/gdbstub/pytest/test_gdbstub.py b/tests/subsys/debug/gdbstub/pytest/test_gdbstub.py index fe063905df7..0878ab54ca1 100755 --- a/tests/subsys/debug/gdbstub/pytest/test_gdbstub.py +++ b/tests/subsys/debug/gdbstub/pytest/test_gdbstub.py @@ -57,6 +57,15 @@ def expected_gdb(): re.compile(r'Breakpoint 1, test '), re.compile(r'Breakpoint 2, main '), re.compile(r'GDB:PASSED'), + re.compile(r'Breakpoint 3, k_thread_abort '), + re.compile(r'2 .* breakpoint .* in main '), + ] + +@pytest.fixture(scope="module") +def unexpected_gdb(): + return [ + re.compile(r'breakpoint .* in test '), + re.compile(r'breakpoint .* in k_thread_abort '), ] @pytest.fixture(scope="module") @@ -67,7 +76,7 @@ def expected_gdb_detach(): ] -def test_gdbstub(dut: DeviceAdapter, gdb_process, expected_app, expected_gdb, expected_gdb_detach): +def test_gdbstub(dut: DeviceAdapter, gdb_process, expected_app, expected_gdb, expected_gdb_detach, unexpected_gdb): """ Test gdbstub feature using a GDB script. We connect to the DUT, run the GDB script then evaluate return code and expected patterns at the GDB @@ -76,6 +85,7 @@ def test_gdbstub(dut: DeviceAdapter, gdb_process, expected_app, expected_gdb, ex logger.debug(f"GDB output:\n{gdb_process.stdout}\n") assert gdb_process.returncode == 0 assert all([ex_re.search(gdb_process.stdout, re.MULTILINE) for ex_re in expected_gdb]), 'No expected GDB output' + assert not any([ex_re.search(gdb_process.stdout, re.MULTILINE) for ex_re in unexpected_gdb]), 'Unexpected GDB output' assert any([ex_re.search(gdb_process.stdout, re.MULTILINE) for ex_re in expected_gdb_detach]), 'No expected GDB quit' app_output = '\n'.join(dut.readlines(print_output = False)) logger.debug(f"App output:\n{app_output}\n") diff --git a/tests/subsys/debug/gdbstub/test_breakpoints.gdbinit b/tests/subsys/debug/gdbstub/test_breakpoints.gdbinit index d79e1aa5f28..b8f7b25d810 100644 --- a/tests/subsys/debug/gdbstub/test_breakpoints.gdbinit +++ b/tests/subsys/debug/gdbstub/test_breakpoints.gdbinit @@ -6,12 +6,22 @@ c s set var a = 2 c - # break at main() + +# set the last breakpoint before quit +b k_thread_abort + if ret == 6 printf "GDB:PASSED\n" + # exit main() and continue with code coverage dump, if configured + c + # remove some of the breakpoints to check. + clear test + clear k_thread_abort + info break quit 0 else printf "GDB:FAILED\n" + c quit 1 end From 4dad6616f776bbe6fa85093cefe495e22c3a19a7 Mon Sep 17 00:00:00 2001 From: Piotr Narajowski Date: Thu, 30 Nov 2023 15:47:04 +0100 Subject: [PATCH 0826/3723] bluetooth: audio: Add API to get MCS service ATT handles This is needed for upper tester. Signed-off-by: Piotr Narajowski --- subsys/bluetooth/audio/mcc.c | 94 +-------------------- subsys/bluetooth/audio/mcc_internal.h | 112 ++++++++++++++++++++++++++ 2 files changed, 114 insertions(+), 92 deletions(-) create mode 100644 subsys/bluetooth/audio/mcc_internal.h diff --git a/subsys/bluetooth/audio/mcc.c b/subsys/bluetooth/audio/mcc.c index 65972e87125..560ac41b11d 100644 --- a/subsys/bluetooth/audio/mcc.c +++ b/subsys/bluetooth/audio/mcc.c @@ -19,6 +19,7 @@ #include #include #include +#include "mcc_internal.h" #include #include "../services/ots/ots_client_internal.h" @@ -44,97 +45,6 @@ LOG_MODULE_REGISTER(bt_mcc, CONFIG_BT_MCC_LOG_LEVEL); #include "common/bt_str.h" -struct mcs_instance_t { - uint16_t start_handle; - uint16_t end_handle; - uint16_t player_name_handle; -#ifdef CONFIG_BT_MCC_OTS - uint16_t icon_obj_id_handle; -#endif /* CONFIG_BT_MCC_OTS */ - uint16_t icon_url_handle; - uint16_t track_changed_handle; - uint16_t track_title_handle; - uint16_t track_duration_handle; - uint16_t track_position_handle; - uint16_t playback_speed_handle; - uint16_t seeking_speed_handle; -#ifdef CONFIG_BT_MCC_OTS - uint16_t segments_obj_id_handle; - uint16_t current_track_obj_id_handle; - uint16_t next_track_obj_id_handle; - uint16_t current_group_obj_id_handle; - uint16_t parent_group_obj_id_handle; -#endif /* CONFIG_BT_MCC_OTS */ - uint16_t playing_order_handle; - uint16_t playing_orders_supported_handle; - uint16_t media_state_handle; - uint16_t cp_handle; - uint16_t opcodes_supported_handle; -#ifdef CONFIG_BT_MCC_OTS - uint16_t scp_handle; - uint16_t search_results_obj_id_handle; -#endif /* CONFIG_BT_MCC_OTS */ - uint16_t content_control_id_handle; - - - /* The write buffer is used for - * - track position (4 octets) - * - playback speed (1 octet) - * - playing order (1 octet) - * - the control point (5 octets) - * (1 octet opcode + optionally 4 octet param) - * (mpl_cmd.opcode + mpl_cmd.param) - * If the object transfer client is included, it is also used for - * - object IDs (6 octets - BT_OTS_OBJ_ID_SIZE) and - * - the search control point (64 octets - SEARCH_LEN_MAX) - * - * If there is no OTC, the largest is control point - * If OTC is included, the largest is the search control point - */ -#ifdef CONFIG_BT_MCC_OTS - char write_buf[SEARCH_LEN_MAX]; -#else - /* Trick to be able to use sizeof on members of a struct type */ - /* TODO: Rewrite the mpl_cmd to have the "use_param" parameter */ - /* separately, and the opcode and param alone as a struct */ - char write_buf[sizeof(((struct mpl_cmd *)0)->opcode) + - sizeof(((struct mpl_cmd *)0)->param)]; -#endif /* CONFIG_BT_MCC_OTS */ - - struct bt_gatt_discover_params discover_params; - struct bt_gatt_read_params read_params; - struct bt_gatt_write_params write_params; - -/** Any fields below here cannot be memset as part of a reset */ - bool busy; - - struct bt_gatt_subscribe_params player_name_sub_params; - struct bt_gatt_subscribe_params track_changed_sub_params; - struct bt_gatt_subscribe_params track_title_sub_params; - struct bt_gatt_subscribe_params track_duration_sub_params; - struct bt_gatt_subscribe_params track_position_sub_params; - struct bt_gatt_subscribe_params playback_speed_sub_params; - struct bt_gatt_subscribe_params seeking_speed_sub_params; -#ifdef CONFIG_BT_MCC_OTS - struct bt_gatt_subscribe_params current_track_obj_sub_params; - struct bt_gatt_subscribe_params next_track_obj_sub_params; - struct bt_gatt_subscribe_params parent_group_obj_sub_params; - struct bt_gatt_subscribe_params current_group_obj_sub_params; -#endif /* CONFIG_BT_MCC_OTS */ - struct bt_gatt_subscribe_params playing_order_sub_params; - struct bt_gatt_subscribe_params media_state_sub_params; - struct bt_gatt_subscribe_params cp_sub_params; - struct bt_gatt_subscribe_params opcodes_supported_sub_params; -#ifdef CONFIG_BT_MCC_OTS - struct bt_gatt_subscribe_params scp_sub_params; - struct bt_gatt_subscribe_params search_results_obj_sub_params; -#endif /* CONFIG_BT_MCC_OTS */ - -#ifdef CONFIG_BT_MCC_OTS - struct bt_ots_client otc; -#endif /* CONFIG_BT_MCC_OTS */ -}; - static struct mcs_instance_t mcs_instance; static struct bt_uuid_16 uuid = BT_UUID_INIT_16(0); @@ -161,7 +71,7 @@ int on_icon_content(struct bt_ots_client *otc_inst, uint32_t len, uint8_t *data_p, bool is_complete); #endif /* CONFIG_BT_MCC_OTS */ -static struct mcs_instance_t *lookup_inst_by_conn(struct bt_conn *conn) +struct mcs_instance_t *lookup_inst_by_conn(struct bt_conn *conn) { if (conn == NULL) { return NULL; diff --git a/subsys/bluetooth/audio/mcc_internal.h b/subsys/bluetooth/audio/mcc_internal.h new file mode 100644 index 00000000000..61c954d47af --- /dev/null +++ b/subsys/bluetooth/audio/mcc_internal.h @@ -0,0 +1,112 @@ +/** @file + * @brief Internal APIs for Bluetooth MCP. + */ + +/* + * Copyright (c) 2019 - 2021 Nordic Semiconductor ASA + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#ifndef ZEPHYR_INCLUDE_BLUETOOTH_AUDIO_MCP_INTERNAL_ +#define ZEPHYR_INCLUDE_BLUETOOTH_AUDIO_MCP_INTERNAL_ + +#include +#include +#include +#include "../services/ots/ots_client_internal.h" + +struct mcs_instance_t *lookup_inst_by_conn(struct bt_conn *conn); + +struct mcs_instance_t { + uint16_t start_handle; + uint16_t end_handle; + uint16_t player_name_handle; +#ifdef CONFIG_BT_MCC_OTS + uint16_t icon_obj_id_handle; +#endif /* CONFIG_BT_MCC_OTS */ + uint16_t icon_url_handle; + uint16_t track_changed_handle; + uint16_t track_title_handle; + uint16_t track_duration_handle; + uint16_t track_position_handle; + uint16_t playback_speed_handle; + uint16_t seeking_speed_handle; +#ifdef CONFIG_BT_MCC_OTS + uint16_t segments_obj_id_handle; + uint16_t current_track_obj_id_handle; + uint16_t next_track_obj_id_handle; + uint16_t current_group_obj_id_handle; + uint16_t parent_group_obj_id_handle; +#endif /* CONFIG_BT_MCC_OTS */ + uint16_t playing_order_handle; + uint16_t playing_orders_supported_handle; + uint16_t media_state_handle; + uint16_t cp_handle; + uint16_t opcodes_supported_handle; +#ifdef CONFIG_BT_MCC_OTS + uint16_t scp_handle; + uint16_t search_results_obj_id_handle; +#endif /* CONFIG_BT_MCC_OTS */ + uint16_t content_control_id_handle; + + + /* The write buffer is used for + * - track position (4 octets) + * - playback speed (1 octet) + * - playing order (1 octet) + * - the control point (5 octets) + * (1 octet opcode + optionally 4 octet param) + * (mpl_cmd.opcode + mpl_cmd.param) + * If the object transfer client is included, it is also used for + * - object IDs (6 octets - BT_OTS_OBJ_ID_SIZE) and + * - the search control point (64 octets - SEARCH_LEN_MAX) + * + * If there is no OTC, the largest is control point + * If OTC is included, the largest is the search control point + */ +#ifdef CONFIG_BT_MCC_OTS + char write_buf[SEARCH_LEN_MAX]; +#else + /* Trick to be able to use sizeof on members of a struct type */ + /* TODO: Rewrite the mpl_cmd to have the "use_param" parameter */ + /* separately, and the opcode and param alone as a struct */ + char write_buf[sizeof(((struct mpl_cmd *)0)->opcode) + + sizeof(((struct mpl_cmd *)0)->param)]; +#endif /* CONFIG_BT_MCC_OTS */ + + struct bt_gatt_discover_params discover_params; + struct bt_gatt_read_params read_params; + struct bt_gatt_write_params write_params; + +/** Any fields below here cannot be memset as part of a reset */ + bool busy; + + struct bt_gatt_subscribe_params player_name_sub_params; + struct bt_gatt_subscribe_params track_changed_sub_params; + struct bt_gatt_subscribe_params track_title_sub_params; + struct bt_gatt_subscribe_params track_duration_sub_params; + struct bt_gatt_subscribe_params track_position_sub_params; + struct bt_gatt_subscribe_params playback_speed_sub_params; + struct bt_gatt_subscribe_params seeking_speed_sub_params; +#ifdef CONFIG_BT_MCC_OTS + struct bt_gatt_subscribe_params current_track_obj_sub_params; + struct bt_gatt_subscribe_params next_track_obj_sub_params; + struct bt_gatt_subscribe_params parent_group_obj_sub_params; + struct bt_gatt_subscribe_params current_group_obj_sub_params; +#endif /* CONFIG_BT_MCC_OTS */ + struct bt_gatt_subscribe_params playing_order_sub_params; + struct bt_gatt_subscribe_params media_state_sub_params; + struct bt_gatt_subscribe_params cp_sub_params; + struct bt_gatt_subscribe_params opcodes_supported_sub_params; +#ifdef CONFIG_BT_MCC_OTS + struct bt_gatt_subscribe_params scp_sub_params; + struct bt_gatt_subscribe_params search_results_obj_sub_params; +#endif /* CONFIG_BT_MCC_OTS */ + +#ifdef CONFIG_BT_MCC_OTS + struct bt_ots_client otc; +#endif /* CONFIG_BT_MCC_OTS */ +}; + +#endif /* ZEPHYR_INCLUDE_BLUETOOTH_AUDIO_MCP_INTERNAL_ */ From 1f19cc782d531a4d488e14b022a65d6451a93d9d Mon Sep 17 00:00:00 2001 From: Piotr Narajowski Date: Fri, 1 Dec 2023 10:40:20 +0100 Subject: [PATCH 0827/3723] bluetooth: tester: MCP Client test Adding support for one missing MCP testcase - verifying characteristic handles during service discovery. Signed-off-by: Piotr Narajowski --- tests/bluetooth/tester/src/btp/btp_mcp.h | 37 +++++++ tests/bluetooth/tester/src/btp_mcp.c | 134 ++++++++++++++++++++++- 2 files changed, 169 insertions(+), 2 deletions(-) diff --git a/tests/bluetooth/tester/src/btp/btp_mcp.h b/tests/bluetooth/tester/src/btp/btp_mcp.h index d9b7f84e410..a7d45766cc2 100644 --- a/tests/bluetooth/tester/src/btp/btp_mcp.h +++ b/tests/bluetooth/tester/src/btp/btp_mcp.h @@ -150,6 +150,43 @@ struct btp_mcp_search_cmd { struct btp_mcp_discovered_ev { bt_addr_le_t address; uint8_t status; + struct { + uint16_t player_name; + uint16_t icon_obj_id; + uint16_t icon_url; + uint16_t track_changed; + uint16_t track_title; + uint16_t track_duration; + uint16_t track_position; + uint16_t playback_speed; + uint16_t seeking_speed; + uint16_t segments_obj_id; + uint16_t current_track_obj_id; + uint16_t next_track_obj_id; + uint16_t current_group_obj_id; + uint16_t parent_group_obj_id; + uint16_t playing_order; + uint16_t playing_orders_supported; + uint16_t media_state; + uint16_t cp; + uint16_t opcodes_supported; + uint16_t search_results_obj_id; + uint16_t scp; + uint16_t content_control_id; + } gmcs_handles; + + struct { + uint16_t feature; + uint16_t obj_name; + uint16_t obj_type; + uint16_t obj_size; + uint16_t obj_id; + uint16_t obj_created; + uint16_t obj_modified; + uint16_t obj_properties; + uint16_t oacp; + uint16_t olcp; + } ots_handles; } __packed; #define BTP_MCP_TRACK_DURATION_EV 0x81 diff --git a/tests/bluetooth/tester/src/btp_mcp.c b/tests/bluetooth/tester/src/btp_mcp.c index f189db909ee..b044c035c06 100644 --- a/tests/bluetooth/tester/src/btp_mcp.c +++ b/tests/bluetooth/tester/src/btp_mcp.c @@ -18,6 +18,7 @@ #include #include #include <../../subsys/bluetooth/audio/mpl_internal.h> +#include <../../subsys/bluetooth/audio/mcc_internal.h> #include #include @@ -37,6 +38,47 @@ static uint64_t next_track_obj_id; static uint8_t media_player_state; static uint64_t current_id; static uint64_t parent_id; +struct service_handles { + struct { + uint16_t player_name; + uint16_t icon_obj_id; + uint16_t icon_url; + uint16_t track_changed; + uint16_t track_title; + uint16_t track_duration; + uint16_t track_position; + uint16_t playback_speed; + uint16_t seeking_speed; + uint16_t segments_obj_id; + uint16_t current_track_obj_id; + uint16_t next_track_obj_id; + uint16_t current_group_obj_id; + uint16_t parent_group_obj_id; + uint16_t playing_order; + uint16_t playing_orders_supported; + uint16_t media_state; + uint16_t cp; + uint16_t opcodes_supported; + uint16_t search_results_obj_id; + uint16_t scp; + uint16_t content_control_id; + } gmcs_handles; + + struct { + uint16_t feature; + uint16_t obj_name; + uint16_t obj_type; + uint16_t obj_size; + uint16_t obj_properties; + uint16_t obj_created; + uint16_t obj_modified; + uint16_t obj_id; + uint16_t oacp; + uint16_t olcp; + } ots_handles; +}; + +struct service_handles svc_chrc_handles; #define SEARCH_LEN_MAX 64 @@ -44,13 +86,62 @@ static struct net_buf_simple *rx_ev_buf = NET_BUF_SIMPLE(SEARCH_LEN_MAX + sizeof(struct btp_mcp_search_cp_ev)); /* Media Control Profile */ -static void btp_send_mcp_found_ev(struct bt_conn *conn, uint8_t status) +static void btp_send_mcp_found_ev(struct bt_conn *conn, uint8_t status, + const struct service_handles svc_chrc_handles) { struct btp_mcp_discovered_ev ev; bt_addr_le_copy(&ev.address, bt_conn_get_dst(conn)); ev.status = status; + ev.gmcs_handles.player_name = sys_cpu_to_le16(svc_chrc_handles.gmcs_handles.player_name); + ev.gmcs_handles.icon_obj_id = sys_cpu_to_le16(svc_chrc_handles.gmcs_handles.icon_obj_id); + ev.gmcs_handles.icon_url = sys_cpu_to_le16(svc_chrc_handles.gmcs_handles.icon_url); + ev.gmcs_handles.track_changed = + sys_cpu_to_le16(svc_chrc_handles.gmcs_handles.track_changed); + ev.gmcs_handles.track_title = sys_cpu_to_le16(svc_chrc_handles.gmcs_handles.track_title); + ev.gmcs_handles.track_duration = + sys_cpu_to_le16(svc_chrc_handles.gmcs_handles.track_duration); + ev.gmcs_handles.track_position = + sys_cpu_to_le16(svc_chrc_handles.gmcs_handles.track_position); + ev.gmcs_handles.playback_speed = + sys_cpu_to_le16(svc_chrc_handles.gmcs_handles.playback_speed); + ev.gmcs_handles.seeking_speed = + sys_cpu_to_le16(svc_chrc_handles.gmcs_handles.seeking_speed); + ev.gmcs_handles.segments_obj_id = + sys_cpu_to_le16(svc_chrc_handles.gmcs_handles.segments_obj_id); + ev.gmcs_handles.current_track_obj_id = + sys_cpu_to_le16(svc_chrc_handles.gmcs_handles.current_track_obj_id); + ev.gmcs_handles.next_track_obj_id = + sys_cpu_to_le16(svc_chrc_handles.gmcs_handles.next_track_obj_id); + ev.gmcs_handles.current_group_obj_id = + sys_cpu_to_le16(svc_chrc_handles.gmcs_handles.current_group_obj_id); + ev.gmcs_handles.parent_group_obj_id = + sys_cpu_to_le16(svc_chrc_handles.gmcs_handles.parent_group_obj_id); + ev.gmcs_handles.playing_order = + sys_cpu_to_le16(svc_chrc_handles.gmcs_handles.playing_order); + ev.gmcs_handles.playing_orders_supported = + sys_cpu_to_le16(svc_chrc_handles.gmcs_handles.playing_orders_supported); + ev.gmcs_handles.media_state = sys_cpu_to_le16(svc_chrc_handles.gmcs_handles.media_state); + ev.gmcs_handles.cp = sys_cpu_to_le16(svc_chrc_handles.gmcs_handles.cp); + ev.gmcs_handles.opcodes_supported = + sys_cpu_to_le16(svc_chrc_handles.gmcs_handles.opcodes_supported); + ev.gmcs_handles.search_results_obj_id = + sys_cpu_to_le16(svc_chrc_handles.gmcs_handles.search_results_obj_id); + ev.gmcs_handles.scp = sys_cpu_to_le16(svc_chrc_handles.gmcs_handles.scp); + ev.gmcs_handles.content_control_id = + sys_cpu_to_le16(svc_chrc_handles.gmcs_handles.content_control_id); + ev.ots_handles.feature = sys_cpu_to_le16(svc_chrc_handles.ots_handles.feature); + ev.ots_handles.obj_name = sys_cpu_to_le16(svc_chrc_handles.ots_handles.obj_name); + ev.ots_handles.obj_type = sys_cpu_to_le16(svc_chrc_handles.ots_handles.obj_type); + ev.ots_handles.obj_size = sys_cpu_to_le16(svc_chrc_handles.ots_handles.obj_size); + ev.ots_handles.obj_properties = + sys_cpu_to_le16(svc_chrc_handles.ots_handles.obj_properties); + ev.ots_handles.obj_created = sys_cpu_to_le16(svc_chrc_handles.ots_handles.obj_created); + ev.ots_handles.obj_modified = sys_cpu_to_le16(svc_chrc_handles.ots_handles.obj_modified); + ev.ots_handles.obj_id = sys_cpu_to_le16(svc_chrc_handles.ots_handles.obj_id); + ev.ots_handles.oacp = sys_cpu_to_le16(svc_chrc_handles.ots_handles.oacp); + ev.ots_handles.olcp = sys_cpu_to_le16(svc_chrc_handles.ots_handles.olcp); tester_event(BTP_SERVICE_ID_MCP, BTP_MCP_DISCOVERED_EV, &ev, sizeof(ev)); } @@ -309,12 +400,51 @@ static void btp_send_search_notifications_ev(struct bt_conn *conn, uint8_t statu static void mcc_discover_cb(struct bt_conn *conn, int err) { + struct mcs_instance_t *mcc_inst; + if (err) { LOG_DBG("Discovery failed (%d)", err); return; } - btp_send_mcp_found_ev(conn, err ? BTP_STATUS_FAILED : BTP_STATUS_SUCCESS); + mcc_inst = lookup_inst_by_conn(conn); + + svc_chrc_handles.gmcs_handles.player_name = mcc_inst->player_name_handle; + svc_chrc_handles.gmcs_handles.icon_obj_id = mcc_inst->icon_obj_id_handle; + svc_chrc_handles.gmcs_handles.icon_url = mcc_inst->icon_url_handle; + svc_chrc_handles.gmcs_handles.track_changed = mcc_inst->track_changed_handle; + svc_chrc_handles.gmcs_handles.track_title = mcc_inst->track_title_handle; + svc_chrc_handles.gmcs_handles.track_duration = mcc_inst->track_duration_handle; + svc_chrc_handles.gmcs_handles.track_position = mcc_inst->track_position_handle; + svc_chrc_handles.gmcs_handles.playback_speed = mcc_inst->playback_speed_handle; + svc_chrc_handles.gmcs_handles.seeking_speed = mcc_inst->seeking_speed_handle; + svc_chrc_handles.gmcs_handles.segments_obj_id = mcc_inst->segments_obj_id_handle; + svc_chrc_handles.gmcs_handles.current_track_obj_id = mcc_inst->current_track_obj_id_handle; + svc_chrc_handles.gmcs_handles.next_track_obj_id = mcc_inst->next_track_obj_id_handle; + svc_chrc_handles.gmcs_handles.current_group_obj_id = mcc_inst->current_group_obj_id_handle; + svc_chrc_handles.gmcs_handles.parent_group_obj_id = mcc_inst->parent_group_obj_id_handle; + svc_chrc_handles.gmcs_handles.playing_order = mcc_inst->playing_order_handle; + svc_chrc_handles.gmcs_handles.playing_orders_supported = + mcc_inst->playing_orders_supported_handle; + svc_chrc_handles.gmcs_handles.media_state = mcc_inst->media_state_handle; + svc_chrc_handles.gmcs_handles.cp = mcc_inst->cp_handle; + svc_chrc_handles.gmcs_handles.opcodes_supported = mcc_inst->opcodes_supported_handle; + svc_chrc_handles.gmcs_handles.search_results_obj_id = + mcc_inst->search_results_obj_id_handle; + svc_chrc_handles.gmcs_handles.scp = mcc_inst->scp_handle; + svc_chrc_handles.gmcs_handles.content_control_id = mcc_inst->content_control_id_handle; + svc_chrc_handles.ots_handles.feature = mcc_inst->otc.feature_handle; + svc_chrc_handles.ots_handles.obj_name = mcc_inst->otc.obj_name_handle; + svc_chrc_handles.ots_handles.obj_type = mcc_inst->otc.obj_type_handle; + svc_chrc_handles.ots_handles.obj_size = mcc_inst->otc.obj_size_handle; + svc_chrc_handles.ots_handles.obj_id = mcc_inst->otc.obj_id_handle; + svc_chrc_handles.ots_handles.obj_properties = mcc_inst->otc.obj_properties_handle; + svc_chrc_handles.ots_handles.obj_created = mcc_inst->otc.obj_created_handle; + svc_chrc_handles.ots_handles.obj_modified = mcc_inst->otc.obj_modified_handle; + svc_chrc_handles.ots_handles.oacp = mcc_inst->otc.oacp_handle; + svc_chrc_handles.ots_handles.olcp = mcc_inst->otc.olcp_handle; + + btp_send_mcp_found_ev(conn, err ? BTP_STATUS_FAILED : BTP_STATUS_SUCCESS, svc_chrc_handles); } static void mcc_read_track_duration_cb(struct bt_conn *conn, int err, int32_t dur) From b68987fe9efde223a37a80762d81f014d2f448c4 Mon Sep 17 00:00:00 2001 From: Jonathan Rico Date: Wed, 29 Nov 2023 15:53:51 +0100 Subject: [PATCH 0828/3723] tests: Bluetooth: add pipelined ATT write test This verifies the zephyr host can tolerate a spec violating peer sending ATT requests without waiting for responses. It also tests the opposite, that is that the Zephyr host does not pipeline requests over the air. Signed-off-by: Jonathan Rico Co-authored-by: Aleksander Wasaznik --- .../host/att/pipeline/common/utils.h | 62 ++ .../host/att/pipeline/dut/CMakeLists.txt | 20 + .../bluetooth/host/att/pipeline/dut/prj.conf | 44 ++ .../host/att/pipeline/dut/src/main.c | 475 ++++++++++++ .../host/att/pipeline/scripts/_compile.sh | 20 + .../host/att/pipeline/scripts/run.sh | 42 ++ .../host/att/pipeline/tester/CMakeLists.txt | 17 + .../host/att/pipeline/tester/prj.conf | 21 + .../host/att/pipeline/tester/src/main.c | 706 ++++++++++++++++++ tests/bsim/bluetooth/host/compile.sh | 2 + 10 files changed, 1409 insertions(+) create mode 100644 tests/bsim/bluetooth/host/att/pipeline/common/utils.h create mode 100644 tests/bsim/bluetooth/host/att/pipeline/dut/CMakeLists.txt create mode 100644 tests/bsim/bluetooth/host/att/pipeline/dut/prj.conf create mode 100644 tests/bsim/bluetooth/host/att/pipeline/dut/src/main.c create mode 100755 tests/bsim/bluetooth/host/att/pipeline/scripts/_compile.sh create mode 100755 tests/bsim/bluetooth/host/att/pipeline/scripts/run.sh create mode 100644 tests/bsim/bluetooth/host/att/pipeline/tester/CMakeLists.txt create mode 100644 tests/bsim/bluetooth/host/att/pipeline/tester/prj.conf create mode 100644 tests/bsim/bluetooth/host/att/pipeline/tester/src/main.c diff --git a/tests/bsim/bluetooth/host/att/pipeline/common/utils.h b/tests/bsim/bluetooth/host/att/pipeline/common/utils.h new file mode 100644 index 00000000000..60f2396fbb9 --- /dev/null +++ b/tests/bsim/bluetooth/host/att/pipeline/common/utils.h @@ -0,0 +1,62 @@ +/* + * Copyright (c) 2023 Nordic Semiconductor ASA + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include "bs_tracing.h" +#include "bs_types.h" +#include "bstests.h" + +#define BS_SECONDS(dur_sec) ((bs_time_t)dur_sec * USEC_PER_SEC) + +extern enum bst_result_t bst_result; + +#define DECLARE_FLAG(flag) extern atomic_t flag +#define DEFINE_FLAG(flag) atomic_t flag = (atomic_t) false +#define TEST_FLAG(flag) (bool)atomic_get(&flag) +#define SET_FLAG(flag) (void)atomic_set(&flag, (atomic_t) true) +#define UNSET_FLAG(flag) (void)atomic_set(&flag, (atomic_t) false) + +#define WAIT_FOR_VAL(var, val) \ + while (atomic_get(&var) != val) { \ + (void)k_sleep(K_MSEC(1)); \ + } +#define WAIT_FOR_FLAG(flag) \ + while (!(bool)atomic_get(&flag)) { \ + (void)k_sleep(K_MSEC(1)); \ + } +#define WAIT_FOR_FLAG_UNSET(flag) \ + while ((bool)atomic_get(&flag)) { \ + (void)k_sleep(K_MSEC(1)); \ + } +#define TAKE_FLAG(flag) \ + while (!(bool)atomic_cas(&flag, true, false)) { \ + (void)k_sleep(K_MSEC(1)); \ + } + +#define ASSERT(expr, ...) \ + do { \ + if (!(expr)) { \ + FAIL(__VA_ARGS__); \ + } \ + } while (0) + +#define FAIL(...) \ + do { \ + bst_result = Failed; \ + bs_trace_error_time_line(__VA_ARGS__); \ + } while (0) + +#define PASS(...) \ + do { \ + bst_result = Passed; \ + bs_trace_info_time(1, __VA_ARGS__); \ + } while (0) + +#define TEST_TIMEOUT_SIMULATED BS_SECONDS(100) +#define HVX_HANDLE 0x0012 +#define DUT_DEVICE_NBR 0 + +/* Run for more than ATT_TIMEOUT */ +#define PROCEDURE_1_TIMEOUT_MS (1000 * 70) diff --git a/tests/bsim/bluetooth/host/att/pipeline/dut/CMakeLists.txt b/tests/bsim/bluetooth/host/att/pipeline/dut/CMakeLists.txt new file mode 100644 index 00000000000..2fa98735680 --- /dev/null +++ b/tests/bsim/bluetooth/host/att/pipeline/dut/CMakeLists.txt @@ -0,0 +1,20 @@ +# SPDX-License-Identifier: Apache-2.0 + +cmake_minimum_required(VERSION 3.20.0) + +find_package(Zephyr REQUIRED HINTS $ENV{ZEPHYR_BASE}) +project(bsim_test_pipeline_dut) + +add_subdirectory(${ZEPHYR_BASE}/tests/bluetooth/common/testlib testlib) + +target_sources(app PRIVATE + src/main.c +) + +zephyr_include_directories( + ../common/ + ${BSIM_COMPONENTS_PATH}/libUtilv1/src/ + ${BSIM_COMPONENTS_PATH}/libPhyComv1/src/ +) + +target_link_libraries(app PRIVATE testlib) diff --git a/tests/bsim/bluetooth/host/att/pipeline/dut/prj.conf b/tests/bsim/bluetooth/host/att/pipeline/dut/prj.conf new file mode 100644 index 00000000000..ed24dfcb947 --- /dev/null +++ b/tests/bsim/bluetooth/host/att/pipeline/dut/prj.conf @@ -0,0 +1,44 @@ +CONFIG_LOG=y +CONFIG_ASSERT=y + +CONFIG_BT=y +CONFIG_BT_CENTRAL=y +CONFIG_BT_PERIPHERAL=y +CONFIG_BT_MAX_CONN=3 + +CONFIG_BT_DEVICE_NAME="Sequential" + +CONFIG_BT_GATT_CLIENT=y +CONFIG_BT_GATT_ENFORCE_SUBSCRIPTION=n + +# Enable bt_testing_tx_tid_get() +CONFIG_BT_TESTING=y + +# Replace `Execute` with `gdb --args` in the shell script +# and get a nice backtrace on assert +CONFIG_ARCH_POSIX_TRAP_ON_FATAL=y + +# Prepend logs with thread names +CONFIG_THREAD_NAME=y +CONFIG_LOG_THREAD_ID_PREFIX=y + +# Enable those as needed +# CONFIG_BT_L2CAP_LOG_LEVEL_DBG=y +# CONFIG_BT_ATT_LOG_LEVEL_DBG=y +# CONFIG_BT_GATT_LOG_LEVEL_DBG=y + +# Allow whole L2CAP PDUs to fit on-air +CONFIG_BT_BUF_ACL_TX_SIZE=251 +CONFIG_BT_BUF_ACL_RX_SIZE=251 +CONFIG_BT_CTLR_DATA_LENGTH_MAX=251 +CONFIG_BT_DATA_LEN_UPDATE=y +CONFIG_BT_USER_DATA_LEN_UPDATE=y + +# Disable auto-initiated procedures so they don't +# mess with the test's execution. +CONFIG_BT_AUTO_PHY_UPDATE=n +CONFIG_BT_AUTO_DATA_LEN_UPDATE=n +CONFIG_BT_GAP_AUTO_UPDATE_CONN_PARAMS=n + +# Needed by `testlib` +CONFIG_BT_SMP=y diff --git a/tests/bsim/bluetooth/host/att/pipeline/dut/src/main.c b/tests/bsim/bluetooth/host/att/pipeline/dut/src/main.c new file mode 100644 index 00000000000..1a3c1480e1e --- /dev/null +++ b/tests/bsim/bluetooth/host/att/pipeline/dut/src/main.c @@ -0,0 +1,475 @@ +/* + * Copyright (c) 2023 Nordic Semiconductor ASA + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "testlib/att_read.h" + +#include /* For get_device_nbr() */ +#include "utils.h" +#include "bstests.h" + +#define strucc struct + +#include +LOG_MODULE_REGISTER(main, LOG_LEVEL_INF); + +DEFINE_FLAG(is_connected); +DEFINE_FLAG(is_subscribed); +DEFINE_FLAG(one_indication); +DEFINE_FLAG(two_notifications); +DEFINE_FLAG(flag_data_length_updated); + +static struct bt_conn *dconn; + +/* Defined in hci_core.c */ +extern k_tid_t bt_testing_tx_tid_get(void); + +static void connected(struct bt_conn *conn, uint8_t conn_err) +{ + char addr[BT_ADDR_LE_STR_LEN]; + + bt_addr_le_to_str(bt_conn_get_dst(conn), addr, sizeof(addr)); + + if (conn_err) { + FAIL("Failed to connect to %s (%u)", addr, conn_err); + return; + } + + LOG_DBG("%s", addr); + + dconn = bt_conn_ref(conn); + SET_FLAG(is_connected); +} + +static void disconnected(struct bt_conn *conn, uint8_t reason) +{ + char addr[BT_ADDR_LE_STR_LEN]; + + bt_addr_le_to_str(bt_conn_get_dst(conn), addr, sizeof(addr)); + + LOG_DBG("%p %s (reason 0x%02x)", conn, addr, reason); + + UNSET_FLAG(is_connected); +} + +static void data_len_updated(struct bt_conn *conn, + struct bt_conn_le_data_len_info *info) +{ + LOG_DBG("Data length updated: TX %d RX %d", + info->tx_max_len, + info->rx_max_len); + SET_FLAG(flag_data_length_updated); +} + +static void do_dlu(struct bt_conn *conn) +{ + int err; + struct bt_conn_le_data_len_param param; + + param.tx_max_len = CONFIG_BT_CTLR_DATA_LENGTH_MAX; + param.tx_max_time = 2500; + + LOG_INF("update DL"); + err = bt_conn_le_data_len_update(conn, ¶m); + ASSERT(err == 0, "Can't update data length (err %d)\n", err); + + WAIT_FOR_FLAG(flag_data_length_updated); +} + +BT_CONN_CB_DEFINE(conn_callbacks) = { + .connected = connected, + .disconnected = disconnected, + .le_data_len_updated = data_len_updated, +}; + +static void device_found(const bt_addr_le_t *addr, int8_t rssi, uint8_t type, + struct net_buf_simple *ad) +{ + char str[BT_ADDR_LE_STR_LEN]; + struct bt_le_conn_param *param; + struct bt_conn *conn; + int err; + + err = bt_le_scan_stop(); + if (err) { + FAIL("Stop LE scan failed (err %d)", err); + return; + } + + bt_addr_le_to_str(addr, str, sizeof(str)); + LOG_DBG("Connecting to %s", str); + + param = BT_LE_CONN_PARAM_DEFAULT; + err = bt_conn_le_create(addr, BT_CONN_LE_CREATE_CONN, param, &conn); + if (err) { + FAIL("Create conn failed (err %d)", err); + return; + } +} + +/* In your area */ +#define ADV_PARAM_SINGLE BT_LE_ADV_PARAM(BT_LE_ADV_OPT_CONNECTABLE | BT_LE_ADV_OPT_ONE_TIME, \ + BT_GAP_ADV_FAST_INT_MIN_2, \ + BT_GAP_ADV_FAST_INT_MAX_2, NULL) + +static strucc bt_conn *connecc(void) +{ + int err; + struct bt_conn *conn; + + UNSET_FLAG(is_connected); + + err = bt_le_adv_start(ADV_PARAM_SINGLE, NULL, 0, NULL, 0); + ASSERT(!err, "Adving failed to start (err %d)\n", err); + + LOG_DBG(" wait connecc..."); + + WAIT_FOR_FLAG(is_connected); + LOG_INF("conecd"); + + conn = dconn; + dconn = NULL; + + return conn; +} + +static struct bt_conn *connect(void) +{ + int err; + struct bt_conn *conn; + struct bt_le_scan_param scan_param = { + .type = BT_LE_SCAN_TYPE_ACTIVE, + .options = BT_LE_SCAN_OPT_NONE, + .interval = BT_GAP_SCAN_FAST_INTERVAL, + .window = BT_GAP_SCAN_FAST_WINDOW, + }; + + UNSET_FLAG(is_connected); + + err = bt_le_scan_start(&scan_param, device_found); + ASSERT(!err, "Scanning failed to start (err %d)\n", err); + + LOG_DBG("Central initiating connection..."); + WAIT_FOR_FLAG(is_connected); + LOG_INF("Connected as central"); + + conn = dconn; + dconn = NULL; + + return conn; +} + +static ssize_t read_from(struct bt_conn *conn, const struct bt_gatt_attr *attr, + void *buf, uint16_t buf_len, uint16_t offset) +{ + static uint16_t counter; + + LOG_INF("read from: len %d", buf_len); + + memset(buf, 0, buf_len); + sys_put_le16(counter, buf); + counter++; + + LOG_HEXDUMP_DBG(buf, buf_len, "Response data"); + + return sizeof(uint16_t); +} + +static ssize_t written_to(struct bt_conn *conn, + const struct bt_gatt_attr *attr, + const void *buf, + uint16_t len, + uint16_t offset, + uint8_t flags) +{ + LOG_INF("written to: handle 0x%x len %d flags 0x%x", + attr->handle, + len, + flags); + + LOG_HEXDUMP_DBG(buf, len, "Write data"); + + return len; +} + +#define test_service_uuid \ + BT_UUID_DECLARE_128(BT_UUID_128_ENCODE(0xf0debc9a, 0x7856, 0x3412, 0x7856, 0x341278563412)) +#define test_characteristic_uuid \ + BT_UUID_DECLARE_128(BT_UUID_128_ENCODE(0xf2debc9a, 0x7856, 0x3412, 0x7856, 0x341278563412)) + +BT_GATT_SERVICE_DEFINE(test_gatt_service, BT_GATT_PRIMARY_SERVICE(test_service_uuid), + BT_GATT_CHARACTERISTIC(test_characteristic_uuid, + (BT_GATT_CHRC_READ | BT_GATT_CHRC_WRITE | + BT_GATT_CHRC_NOTIFY | BT_GATT_CHRC_INDICATE), + BT_GATT_PERM_READ | BT_GATT_PERM_WRITE, + read_from, written_to, NULL), + BT_GATT_CCC(NULL, BT_GATT_PERM_READ | BT_GATT_PERM_WRITE),); + +static void send_write_handle(struct bt_conn *conn) +{ + int err; + uint16_t handle; + uint8_t data[sizeof(handle)]; + const struct bt_gatt_attr *attr = &test_gatt_service.attrs[2]; + + /* Inform tester which handle it should write to */ + handle = bt_gatt_attr_get_handle(attr); + sys_put_le16(handle, data); + + err = bt_gatt_notify(conn, attr, data, sizeof(data)); + ASSERT(!err, "Failed to transmit handle for write (err %d)\n", err); +} + +static void gatt_read(struct bt_conn *conn, uint16_t handle) +{ + static uint16_t prev_val; + uint16_t value; + int err; + + NET_BUF_SIMPLE_DEFINE(buf, BT_ATT_MAX_ATTRIBUTE_LEN); + + err = bt_testlib_att_read_by_handle_sync(&buf, NULL, NULL, conn, 0, handle, 0); + ASSERT(!err, "Failed read: err %d", err); + + value = net_buf_simple_pull_le16(&buf); + + ASSERT(prev_val == value, "Something's up: expected %d got %d", prev_val, value); + prev_val++; + + LOG_INF("Read by handle: handle %x val %d err %d", handle, value, err); +} + +static void find_the_chrc(struct bt_conn *conn, const struct bt_uuid *svc, + const struct bt_uuid *chrc, uint16_t *chrc_value_handle) +{ + uint16_t svc_handle; + uint16_t svc_end_handle; + uint16_t chrc_end_handle; + int err; + + err = bt_testlib_gatt_discover_primary(&svc_handle, &svc_end_handle, conn, svc, 1, 0xffff); + ASSERT(!err, "Failed to discover service %d"); + + LOG_DBG("svc_handle: %u, svc_end_handle: %u", svc_handle, svc_end_handle); + + err = bt_testlib_gatt_discover_characteristic(chrc_value_handle, &chrc_end_handle, + NULL, conn, chrc, (svc_handle + 1), + svc_end_handle); + ASSERT(!err, "Failed to get value handle %d"); + + LOG_DBG("chrc_value_handle: %u, chrc_end_handle: %u", *chrc_value_handle, chrc_end_handle); +} + +void good_peer_procedure(void) +{ + LOG_DBG("Test 0 start: good peer"); + int err; + uint16_t handle; + struct bt_conn *conn; + + err = bt_enable(NULL); + ASSERT(err == 0, "Can't enable Bluetooth (err %d)\n", err); + LOG_DBG("Central: Bluetooth initialized."); + + conn = connecc(); + + find_the_chrc(conn, test_service_uuid, test_characteristic_uuid, &handle); + + uint32_t timeout_ms = PROCEDURE_1_TIMEOUT_MS; + uint32_t start_time = k_uptime_get_32(); + + while (k_uptime_get_32() - start_time < timeout_ms) { + gatt_read(conn, handle); + } + + PASS("Good peer done\n"); +} + +void dut_procedure(void) +{ + LOG_DBG("Test 0 start: DUT"); + int err; + + struct bt_conn *good, *bad; + + err = bt_enable(NULL); + ASSERT(err == 0, "Can't enable Bluetooth (err %d)\n", err); + LOG_DBG("Central: Bluetooth initialized."); + + LOG_DBG("Central: Connect to good peer"); + good = connect(); + + LOG_DBG("Central: Connect to bad peer"); + bad = connect(); + + LOG_DBG("Central: Connected to both peers"); + + do_dlu(bad); + send_write_handle(bad); + + /* Pass unless some assert in callbacks fails. */ + PASS("DUT done\n"); +} + +void test_procedure_0(void) +{ + /* Test purpose: + * + * Verify that a Zephyr host server/client combo can tolerate a spec + * violating peer that batches ATT requests without waiting for + * responses. + * + * To do this, the application on the DUT will be connected to two + * peers: + * + * - a "nice" peer, running a legal stress test, that is, running a + * discovery procedure over and over again. + * - a "bad" peer, spamming ATT requests as fast as possible. + * + * The good peer uses the Zephyr host to send requests. + * The bad peer uses the tinyhost (raw hci) to send requests. + * + * The DUT is allowed to disconnect the ACL of the bad peer. + * If that happens, the bad peer will reconnect and continue. + * The connection with the good peer must remain stable. + * + * Test procedure: + * At the same time, and for T > ATT_TIMEOUT: + * - Good peer sends valid ATT write requests to DUT + * - Good peer validates ATT responses from DUT + * - Bad peer sends ATT requests as fast as it can + * + * [verdict] + * - no buffer allocation failures for responding to the good peer, + * timeouts or stalls. + */ + bool dut = (get_device_nbr() == DUT_DEVICE_NBR); + + /* We use the same image for both to lighten build load. */ + if (dut) { + dut_procedure(); + } else { + good_peer_procedure(); + } +} + +static void write_done(struct bt_conn *conn, uint8_t err, + struct bt_gatt_write_params *params) +{ + LOG_INF("Write done: err %d", err); +} + +static void gatt_write(struct bt_conn *conn, struct bt_gatt_write_params *params) +{ + static uint8_t data[10] = {1}; + int err; + + memset(params, 0, sizeof(*params)); + params->handle = 0x1337; + params->func = write_done; + params->length = sizeof(data); + params->data = data; + + LOG_INF("Queue GATT write"); + + err = bt_gatt_write(conn, params); + ASSERT(!err, "Failed write: err %d", err); +} + +void test_procedure_1(void) +{ + /* Test purpose: + * + * Verify that the Zephyr host does not pipeline ATT requests. + * I.e. always waits for a response before enqueuing the next request. + * + * Test procedure: + * + * - DUT sends a bunch of ATT reads in a loop + * - Tester delays responses to allow for the LL to transport any other requests. + * - Tester fails if it detects another request before it has sent the response + * + */ + + LOG_DBG("Test start: ATT pipeline protocol"); + int err; + + err = bt_enable(NULL); + ASSERT(err == 0, "Can't enable Bluetooth (err %d)\n", err); + LOG_DBG("Central: Bluetooth initialized."); + + struct bt_conn *tester = connect(); + + do_dlu(tester); + + static struct bt_gatt_write_params parmesans[100]; + + for (int i = 0; i < ARRAY_SIZE(parmesans); i++) { + gatt_write(tester, &parmesans[i]); + } + + bt_conn_disconnect(tester, BT_HCI_ERR_REMOTE_POWER_OFF); + bt_conn_unref(tester); + + /* Pass unless some assert in callbacks fails. */ + PASS("DUT done\n"); +} + +void test_tick(bs_time_t HW_device_time) +{ + bs_trace_debug_time(0, "Simulation ends now.\n"); + if (bst_result != Passed) { + bst_result = Failed; + bs_trace_error("Test did not pass before simulation ended.\n"); + } +} + +void test_init(void) +{ + bst_ticker_set_next_tick_absolute(TEST_TIMEOUT_SIMULATED); + bst_result = In_progress; +} + +static const struct bst_test_instance test_to_add[] = { + { + .test_id = "dut", + .test_pre_init_f = test_init, + .test_tick_f = test_tick, + .test_main_f = test_procedure_0, + }, + { + .test_id = "dut_1", + .test_pre_init_f = test_init, + .test_tick_f = test_tick, + .test_main_f = test_procedure_1, + }, + BSTEST_END_MARKER, +}; + +static struct bst_test_list *install(struct bst_test_list *tests) +{ + return bst_add_tests(tests, test_to_add); +}; + +bst_test_install_t test_installers[] = {install, NULL}; + +int main(void) +{ + bst_main(); + + return 0; +} diff --git a/tests/bsim/bluetooth/host/att/pipeline/scripts/_compile.sh b/tests/bsim/bluetooth/host/att/pipeline/scripts/_compile.sh new file mode 100755 index 00000000000..836f306cf1c --- /dev/null +++ b/tests/bsim/bluetooth/host/att/pipeline/scripts/_compile.sh @@ -0,0 +1,20 @@ +#!/usr/bin/env bash +# Copyright 2023 Nordic Semiconductor ASA +# SPDX-License-Identifier: Apache-2.0 + +# Path checks, etc +source ${ZEPHYR_BASE}/tests/bsim/sh_common.source + +BOARD="${BOARD:-nrf52_bsim}" +dut_exe="bs_${BOARD}_tests_bsim_bluetooth_host_att_pipeline_dut_prj_conf" +tester_exe="bs_${BOARD}_tests_bsim_bluetooth_host_att_pipeline_tester_prj_conf" + +# terminate running simulations (if any) +${BSIM_COMPONENTS_PATH}/common/stop_bsim.sh + +west build -b ${BOARD} -d build_a dut && \ + cp build_a/zephyr/zephyr.exe "${BSIM_OUT_PATH}/bin/${dut_exe}" && + +# b stands for bad +west build -b ${BOARD} -d build_b tester && \ + cp build_b/zephyr/zephyr.exe "${BSIM_OUT_PATH}/bin/${tester_exe}" diff --git a/tests/bsim/bluetooth/host/att/pipeline/scripts/run.sh b/tests/bsim/bluetooth/host/att/pipeline/scripts/run.sh new file mode 100755 index 00000000000..1edaf2e05a0 --- /dev/null +++ b/tests/bsim/bluetooth/host/att/pipeline/scripts/run.sh @@ -0,0 +1,42 @@ +#!/usr/bin/env bash +# Copyright 2023 Nordic Semiconductor ASA +# SPDX-License-Identifier: Apache-2.0 + +BOARD="${BOARD:-nrf52_bsim}" +dut_exe="bs_${BOARD}_tests_bsim_bluetooth_host_att_pipeline_dut_prj_conf" +tester_exe="bs_${BOARD}_tests_bsim_bluetooth_host_att_pipeline_tester_prj_conf" + +source ${ZEPHYR_BASE}/tests/bsim/sh_common.source + +test_name="att_pipeline" +simulation_id="${test_name}" +verbosity_level=2 +EXECUTE_TIMEOUT=30 +sim_length_us=100e6 + +cd ${BSIM_OUT_PATH}/bin + +Execute ./bs_2G4_phy_v1 \ + -v=${verbosity_level} -s="${simulation_id}" -D=2 -sim_length=${sim_length_us} $@ + +Execute "./$tester_exe" \ + -v=${verbosity_level} -s="${simulation_id}" -d=1 -testid=tester_1 -RealEncryption=1 -rs=100 + +Execute "./$dut_exe" \ + -v=${verbosity_level} -s="${simulation_id}" -d=0 -testid=dut_1 -RealEncryption=1 + +wait_for_background_jobs + +Execute ./bs_2G4_phy_v1 \ + -v=${verbosity_level} -s="${simulation_id}" -D=3 -sim_length=${sim_length_us} $@ + +Execute "./$tester_exe" \ + -v=${verbosity_level} -s="${simulation_id}" -d=2 -testid=tester -RealEncryption=1 -rs=100 + +Execute "./$dut_exe" \ + -v=${verbosity_level} -s="${simulation_id}" -d=1 -testid=dut -RealEncryption=1 -rs=2000 + +Execute "./$dut_exe" \ + -v=${verbosity_level} -s="${simulation_id}" -d=0 -testid=dut -RealEncryption=1 + +wait_for_background_jobs diff --git a/tests/bsim/bluetooth/host/att/pipeline/tester/CMakeLists.txt b/tests/bsim/bluetooth/host/att/pipeline/tester/CMakeLists.txt new file mode 100644 index 00000000000..440ae5e49c0 --- /dev/null +++ b/tests/bsim/bluetooth/host/att/pipeline/tester/CMakeLists.txt @@ -0,0 +1,17 @@ +# SPDX-License-Identifier: Apache-2.0 + +cmake_minimum_required(VERSION 3.20.0) + +find_package(Zephyr REQUIRED HINTS $ENV{ZEPHYR_BASE}) +project(bsim_test_pipeline_tester) + +target_sources(app PRIVATE + src/main.c +) + +zephyr_include_directories( + ../common/ + ${ZEPHYR_BASE}/subsys/bluetooth/common/ + ${BSIM_COMPONENTS_PATH}/libUtilv1/src/ + ${BSIM_COMPONENTS_PATH}/libPhyComv1/src/ +) diff --git a/tests/bsim/bluetooth/host/att/pipeline/tester/prj.conf b/tests/bsim/bluetooth/host/att/pipeline/tester/prj.conf new file mode 100644 index 00000000000..c05fc3aa163 --- /dev/null +++ b/tests/bsim/bluetooth/host/att/pipeline/tester/prj.conf @@ -0,0 +1,21 @@ +CONFIG_LOG=y +CONFIG_ASSERT=y + +CONFIG_BT=y +CONFIG_BT_HCI_RAW=y +CONFIG_BT_HCI_RAW_RESERVE=1 +CONFIG_BT_MAX_CONN=1 + +CONFIG_BT_BUF_CMD_TX_COUNT=10 + +CONFIG_BT_BUF_ACL_TX_COUNT=20 + +CONFIG_BT_BUF_ACL_RX_SIZE=255 +CONFIG_BT_BUF_CMD_TX_SIZE=255 +CONFIG_BT_BUF_EVT_DISCARDABLE_SIZE=255 + +# Allow whole L2CAP PDUs to fit on-air +CONFIG_BT_BUF_ACL_TX_SIZE=251 +CONFIG_BT_BUF_ACL_RX_SIZE=251 +CONFIG_BT_DATA_LEN_UPDATE=y +CONFIG_BT_CTLR_DATA_LENGTH_MAX=251 diff --git a/tests/bsim/bluetooth/host/att/pipeline/tester/src/main.c b/tests/bsim/bluetooth/host/att/pipeline/tester/src/main.c new file mode 100644 index 00000000000..90fdd6f7da9 --- /dev/null +++ b/tests/bsim/bluetooth/host/att/pipeline/tester/src/main.c @@ -0,0 +1,706 @@ +/* + * Copyright (c) 2023 Nordic Semiconductor ASA + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include +#include +#include + +#include +#include + +#include +#include +#include + +#include "common/bt_str.h" + +#include "host/conn_internal.h" +#include "host/l2cap_internal.h" + +#include "utils.h" +#include "bstests.h" + +#include +LOG_MODULE_REGISTER(bt_tinyhost, LOG_LEVEL_INF); + +#define BT_ATT_OP_MTU_REQ 0x02 +#define BT_ATT_OP_MTU_RSP 0x03 +#define BT_ATT_OP_WRITE_REQ 0x12 +#define BT_ATT_OP_WRITE_RSP 0x13 +#define BT_ATT_OP_NOTIFY 0x1b +#define BT_ATT_OP_INDICATE 0x1d +#define BT_ATT_OP_CONFIRM 0x1e +#define BT_ATT_OP_WRITE_CMD 0x52 +#define BT_L2CAP_CID_ATT 0x0004 +#define LAST_SUPPORTED_ATT_OPCODE 0x20 + +DEFINE_FLAG(is_connected); +DEFINE_FLAG(flag_data_length_updated); +DEFINE_FLAG(flag_handle); +DEFINE_FLAG(flag_notified); +DEFINE_FLAG(flag_write_ack); +DEFINE_FLAG(flag_req_in_progress); + +static uint16_t server_write_handle; + +typedef void (*att_handler_t)(struct net_buf *buf); +static att_handler_t att_handlers[LAST_SUPPORTED_ATT_OPCODE]; + +static K_FIFO_DEFINE(rx_queue); + +#define CMD_BUF_SIZE MAX(BT_BUF_EVT_RX_SIZE, BT_BUF_CMD_TX_SIZE) +NET_BUF_POOL_FIXED_DEFINE(hci_cmd_pool, CONFIG_BT_BUF_CMD_TX_COUNT, + CMD_BUF_SIZE, 8, NULL); + +static K_SEM_DEFINE(cmd_sem, 1, 1); +static struct k_sem acl_pkts; +static uint16_t conn_handle; + +static volatile uint16_t active_opcode = 0xFFFF; +static struct net_buf *cmd_rsp; + +struct net_buf *bt_hci_cmd_create(uint16_t opcode, uint8_t param_len) +{ + struct bt_hci_cmd_hdr *hdr; + struct net_buf *buf; + + LOG_DBG("opcode 0x%04x param_len %u", opcode, param_len); + + buf = net_buf_alloc(&hci_cmd_pool, K_FOREVER); + ASSERT(buf, "failed allocation"); + + LOG_DBG("buf %p", buf); + + net_buf_reserve(buf, BT_BUF_RESERVE); + + bt_buf_set_type(buf, BT_BUF_CMD); + + hdr = net_buf_add(buf, sizeof(*hdr)); + hdr->opcode = sys_cpu_to_le16(opcode); + hdr->param_len = param_len; + + return buf; +} + +static void handle_cmd_complete(struct net_buf *buf) +{ + struct bt_hci_evt_hdr *hdr; + uint8_t status, ncmd; + uint16_t opcode; + struct net_buf_simple_state state; + + net_buf_simple_save(&buf->b, &state); + + hdr = net_buf_pull_mem(buf, sizeof(*hdr)); + + if (hdr->evt == BT_HCI_EVT_CMD_COMPLETE) { + struct bt_hci_evt_cmd_complete *evt; + + evt = net_buf_pull_mem(buf, sizeof(*evt)); + status = 0; + ncmd = evt->ncmd; + opcode = sys_le16_to_cpu(evt->opcode); + + } else if (hdr->evt == BT_HCI_EVT_CMD_STATUS) { + struct bt_hci_evt_cmd_status *evt; + + evt = net_buf_pull_mem(buf, sizeof(*evt)); + status = buf->data[0]; + ncmd = evt->ncmd; + opcode = sys_le16_to_cpu(evt->opcode); + + } else { + FAIL("unhandled event 0x%x", hdr->evt); + } + + LOG_DBG("opcode 0x%04x status %x", opcode, status); + + ASSERT(status == 0x00, "cmd status: %x", status); + + ASSERT(active_opcode == opcode, "unexpected opcode %x != %x", active_opcode, opcode); + + if (active_opcode) { + active_opcode = 0xFFFF; + cmd_rsp = net_buf_ref(buf); + net_buf_simple_restore(&buf->b, &state); + } + + if (ncmd) { + k_sem_give(&cmd_sem); + } +} + +static void handle_meta_event(struct net_buf *buf) +{ + uint8_t code = buf->data[2]; + + switch (code) { + case BT_HCI_EVT_LE_ENH_CONN_COMPLETE: + case BT_HCI_EVT_LE_ENH_CONN_COMPLETE_V2: + conn_handle = sys_get_le16(&buf->data[4]); + LOG_DBG("connected: handle: %d", conn_handle); + SET_FLAG(is_connected); + break; + case BT_HCI_EVT_LE_DATA_LEN_CHANGE: + SET_FLAG(flag_data_length_updated); + break; + case BT_HCI_EVT_LE_CHAN_SEL_ALGO: + /* do nothing */ + break; + default: + LOG_ERR("unhandled meta event %x", code); + LOG_HEXDUMP_ERR(buf->data, buf->len, "HCI META EVT"); + } +} + +static void handle_ncp(struct net_buf *buf) +{ + struct bt_hci_evt_num_completed_packets *evt; + struct bt_hci_evt_hdr *hdr; + uint16_t handle, count; + + hdr = net_buf_pull_mem(buf, sizeof(*hdr)); + + evt = (void *)buf->data; + handle = sys_le16_to_cpu(evt->h[0].handle); + count = sys_le16_to_cpu(evt->h[0].count); + + LOG_DBG("sent %d packets", count); + + while (count--) { + k_sem_give(&acl_pkts); + } +} + +static void handle_att_notification(struct net_buf *buf) +{ + uint16_t handle = net_buf_pull_le16(buf); + + LOG_INF("Got notification for 0x%04x len %d", handle, buf->len); + LOG_HEXDUMP_DBG(buf->data, buf->len, "payload"); + + server_write_handle = net_buf_pull_le16(buf); + LOG_INF("Retrieved handle to write to: 0x%x", server_write_handle); + SET_FLAG(flag_handle); +} + +struct net_buf *alloc_l2cap_pdu(void); +static void send_l2cap_packet(struct net_buf *buf, uint16_t cid); + +static void send_write_rsp(void) +{ + struct net_buf *buf = alloc_l2cap_pdu(); + + UNSET_FLAG(flag_req_in_progress); + + net_buf_add_u8(buf, BT_ATT_OP_WRITE_RSP); + send_l2cap_packet(buf, BT_L2CAP_CID_ATT); +} + +static void handle_att_write_0(struct net_buf *buf) +{ + uint16_t handle = net_buf_pull_le16(buf); + + LOG_INF("Got write for 0x%04x len %d", handle, buf->len); + LOG_HEXDUMP_DBG(buf->data, buf->len, "payload"); + + ASSERT(!TEST_FLAG(flag_req_in_progress), + "Peer is pipelining REQs. This inSIGdent will be reported.\n"); + + SET_FLAG(flag_req_in_progress); + send_write_rsp(); +} + +static void handle_att_write_1(struct net_buf *buf) +{ + uint16_t handle = net_buf_pull_le16(buf); + + LOG_INF("Got write for 0x%04x len %d", handle, buf->len); + LOG_HEXDUMP_DBG(buf->data, buf->len, "payload"); + + ASSERT(!TEST_FLAG(flag_req_in_progress), + "Peer is pipelining REQs. This inSIGdent will be reported.\n"); + + SET_FLAG(flag_req_in_progress); + + /* For this test procedure, the response is sent from main */ +} + +static void handle_att(struct net_buf *buf) +{ + uint8_t op = net_buf_pull_u8(buf); + + if (ARRAY_SIZE(att_handlers) > op && att_handlers[op]) { + LOG_DBG("executing custom ATT handler for op %x", op); + att_handlers[op](buf); + return; + } + + switch (op) { + case BT_ATT_OP_NOTIFY: + handle_att_notification(buf); + return; + case BT_ATT_OP_WRITE_RSP: + LOG_INF("got ATT write RSP"); + SET_FLAG(flag_write_ack); + return; + case BT_ATT_OP_MTU_RSP: + LOG_INF("got ATT MTU RSP"); + return; + default: + LOG_HEXDUMP_ERR(buf->data, buf->len, "payload"); + FAIL("unhandled opcode %x\n", op); + return; + } +} + +static void handle_l2cap(struct net_buf *buf) +{ + struct bt_l2cap_hdr *hdr; + uint16_t cid; + + hdr = net_buf_pull_mem(buf, sizeof(*hdr)); + cid = sys_le16_to_cpu(hdr->cid); + + LOG_DBG("Packet for CID %u len %u", cid, buf->len); + LOG_HEXDUMP_DBG(buf->data, buf->len, "l2cap"); + + /* Make sure we don't have to recombine packets */ + ASSERT(buf->len == hdr->len, "buflen = %d != hdrlen %d", + buf->len, hdr->len); + + ASSERT(cid == BT_L2CAP_CID_ATT, "We only support (U)ATT"); + + /* (U)ATT PDU */ + handle_att(buf); +} + +static void handle_acl(struct net_buf *buf) +{ + struct bt_hci_acl_hdr *hdr; + uint16_t len, handle; + uint8_t flags; + + hdr = net_buf_pull_mem(buf, sizeof(*hdr)); + len = sys_le16_to_cpu(hdr->len); + handle = sys_le16_to_cpu(hdr->handle); + + flags = bt_acl_flags(handle); + handle = bt_acl_handle(handle); + + ASSERT(flags == BT_ACL_START, + "Fragmentation not supported"); + + LOG_DBG("ACL: conn %d len %d flags %d", handle, len, flags); + LOG_HEXDUMP_DBG(buf->data, buf->len, "HCI ACL"); + + handle_l2cap(buf); +} + +static void recv(struct net_buf *buf) +{ + LOG_HEXDUMP_DBG(buf->data, buf->len, "HCI RX"); + + uint8_t code = buf->data[0]; + + if (bt_buf_get_type(buf) == BT_BUF_EVT) { + switch (code) { + case BT_HCI_EVT_CMD_COMPLETE: + case BT_HCI_EVT_CMD_STATUS: + handle_cmd_complete(buf); + break; + case BT_HCI_EVT_LE_META_EVENT: + handle_meta_event(buf); + break; + case BT_HCI_EVT_DISCONN_COMPLETE: + UNSET_FLAG(is_connected); + break; + case BT_HCI_EVT_NUM_COMPLETED_PACKETS: + handle_ncp(buf); + break; + default: + LOG_ERR("unhandled msg %x", code); + LOG_HEXDUMP_ERR(buf->data, buf->len, "HCI EVT"); + } + + /* handlers should take a ref if they want to access the buffer + * later + */ + net_buf_unref(buf); + return; + } + + if (bt_buf_get_type(buf) == BT_BUF_ACL_IN) { + handle_acl(buf); + net_buf_unref(buf); + return; + } + + LOG_ERR("HCI RX (not data or event)"); + net_buf_unref(buf); +} + +static void send_cmd(uint16_t opcode, struct net_buf *cmd, struct net_buf **rsp) +{ + LOG_DBG("opcode %x", opcode); + + if (!cmd) { + cmd = bt_hci_cmd_create(opcode, 0); + } + + k_sem_take(&cmd_sem, K_FOREVER); + ASSERT(active_opcode == 0xFFFF, ""); + + active_opcode = opcode; + + LOG_HEXDUMP_DBG(cmd->data, cmd->len, "HCI TX"); + bt_send(cmd); + + /* Wait until the command completes */ + k_sem_take(&cmd_sem, K_FOREVER); + k_sem_give(&cmd_sem); + + net_buf_unref(cmd); + + /* return response. it's okay if cmd_rsp gets overwritten, since the app + * gets the ref to the underlying buffer when this fn returns. + */ + if (rsp) { + *rsp = cmd_rsp; + } else { + net_buf_unref(cmd_rsp); + cmd_rsp = NULL; + } +} + +static K_THREAD_STACK_DEFINE(rx_thread_stack, 1024); +static struct k_thread rx_thread_data; + +static void rx_thread(void *p1, void *p2, void *p3) +{ + LOG_DBG("start HCI rx"); + + while (true) { + struct net_buf *buf; + + /* Wait until a buffer is available */ + buf = net_buf_get(&rx_queue, K_FOREVER); + recv(buf); + } +} + +static void le_read_buffer_size_complete(struct net_buf *rsp) +{ + struct bt_hci_rp_le_read_buffer_size *rp = (void *)rsp->data; + + LOG_DBG("status 0x%02x", rp->status); + LOG_DBG("max len %d max num %d", rp->le_max_len, rp->le_max_num); + + k_sem_init(&acl_pkts, rp->le_max_num, rp->le_max_num); + net_buf_unref(rsp); +} + +static void read_max_data_len(uint16_t *tx_octets, uint16_t *tx_time) +{ + struct bt_hci_rp_le_read_max_data_len *rp; + struct net_buf *rsp; + + send_cmd(BT_HCI_OP_LE_READ_MAX_DATA_LEN, NULL, &rsp); + + rp = (void *)rsp->data; + *tx_octets = sys_le16_to_cpu(rp->max_tx_octets); + *tx_time = sys_le16_to_cpu(rp->max_tx_time); + net_buf_unref(rsp); +} + +static void write_default_data_len(uint16_t tx_octets, uint16_t tx_time) +{ + struct bt_hci_cp_le_write_default_data_len *cp; + struct net_buf *buf = bt_hci_cmd_create(BT_HCI_OP_LE_WRITE_DEFAULT_DATA_LEN, sizeof(*cp)); + + ASSERT(buf, ""); + + cp = net_buf_add(buf, sizeof(*cp)); + cp->max_tx_octets = sys_cpu_to_le16(tx_octets); + cp->max_tx_time = sys_cpu_to_le16(tx_time); + + send_cmd(BT_HCI_OP_LE_WRITE_DEFAULT_DATA_LEN, buf, NULL); +} + +static void set_data_len(void) +{ + uint16_t tx_octets, tx_time; + + read_max_data_len(&tx_octets, &tx_time); + write_default_data_len(tx_octets, tx_time); +} + +static void set_event_mask(uint16_t opcode) +{ + struct bt_hci_cp_set_event_mask *cp_mask; + struct net_buf *buf; + uint64_t mask = 0U; + + /* The two commands have the same length/params */ + buf = bt_hci_cmd_create(opcode, sizeof(*cp_mask)); + ASSERT(buf, ""); + + /* Forward all events */ + cp_mask = net_buf_add(buf, sizeof(*cp_mask)); + mask = UINT64_MAX; + sys_put_le64(mask, cp_mask->events); + + send_cmd(opcode, buf, NULL); +} + +static void set_random_address(void) +{ + struct net_buf *buf; + bt_addr_le_t addr = {BT_ADDR_LE_RANDOM, {{0x0A, 0x89, 0x67, 0x45, 0x23, 0xC1}}}; + + LOG_DBG("%s", bt_addr_str(&addr.a)); + + buf = bt_hci_cmd_create(BT_HCI_OP_LE_SET_RANDOM_ADDRESS, sizeof(addr.a)); + ASSERT(buf, ""); + + net_buf_add_mem(buf, &addr.a, sizeof(addr.a)); + send_cmd(BT_HCI_OP_LE_SET_RANDOM_ADDRESS, buf, NULL); +} + +void start_adv(void) +{ + struct bt_hci_cp_le_set_adv_param set_param; + struct net_buf *buf; + uint16_t interval = 60; /* Interval doesn't matter */ + + (void)memset(&set_param, 0, sizeof(set_param)); + + set_param.min_interval = sys_cpu_to_le16(interval); + set_param.max_interval = sys_cpu_to_le16(interval); + set_param.channel_map = 0x07; + set_param.filter_policy = BT_LE_ADV_FP_NO_FILTER; + set_param.type = BT_HCI_ADV_IND; + set_param.own_addr_type = 0x01; /* random */ + + /* configure */ + buf = bt_hci_cmd_create(BT_HCI_OP_LE_SET_ADV_PARAM, sizeof(set_param)); + net_buf_add_mem(buf, &set_param, sizeof(set_param)); + send_cmd(BT_HCI_OP_LE_SET_ADV_PARAM, buf, NULL); + + /* start */ + buf = bt_hci_cmd_create(BT_HCI_OP_LE_SET_ADV_ENABLE, 1); + net_buf_add_u8(buf, BT_HCI_LE_ADV_ENABLE); + send_cmd(BT_HCI_OP_LE_SET_ADV_ENABLE, buf, NULL); +} + +NET_BUF_POOL_DEFINE(acl_tx_pool, 5, BT_L2CAP_BUF_SIZE(200), 8, NULL); + +struct net_buf *alloc_l2cap_pdu(void) +{ + struct net_buf *buf; + uint16_t reserve; + + buf = net_buf_alloc(&acl_tx_pool, K_FOREVER); + ASSERT(buf, "failed ACL allocation"); + + reserve = sizeof(struct bt_l2cap_hdr); + reserve += sizeof(struct bt_hci_acl_hdr) + BT_BUF_RESERVE; + + net_buf_reserve(buf, reserve); + + return buf; +} + +static int send_acl(struct net_buf *buf) +{ + struct bt_hci_acl_hdr *hdr; + uint8_t flags = BT_ACL_START_NO_FLUSH; + + hdr = net_buf_push(buf, sizeof(*hdr)); + hdr->handle = sys_cpu_to_le16(bt_acl_handle_pack(conn_handle, flags)); + hdr->len = sys_cpu_to_le16(buf->len - sizeof(*hdr)); + + bt_buf_set_type(buf, BT_BUF_ACL_OUT); + + k_sem_take(&acl_pkts, K_FOREVER); + + return bt_send(buf); +} + +static void send_l2cap_packet(struct net_buf *buf, uint16_t cid) +{ + struct bt_l2cap_hdr *hdr; + + hdr = net_buf_push(buf, sizeof(*hdr)); + hdr->len = sys_cpu_to_le16(buf->len - sizeof(*hdr)); + hdr->cid = sys_cpu_to_le16(cid); + + /* Always entire packets, no HCI fragmentation */ + ASSERT(buf->len <= CONFIG_BT_BUF_ACL_TX_SIZE, + "Fragmentation not supported"); + + send_acl(buf); +} + +static void gatt_write(uint16_t op) +{ + static uint8_t data[] = "write"; + uint16_t handle = server_write_handle; + struct net_buf *buf = alloc_l2cap_pdu(); + + net_buf_add_u8(buf, op); + net_buf_add_le16(buf, handle); + net_buf_add_mem(buf, data, sizeof(data)); + + LOG_INF("send ATT write %s", + op == BT_ATT_OP_WRITE_REQ ? "REQ" : "CMD"); + + send_l2cap_packet(buf, BT_L2CAP_CID_ATT); +} + +static void prepare_controller(void) +{ + /* Initialize controller */ + struct net_buf *rsp; + + send_cmd(BT_HCI_OP_RESET, NULL, NULL); + send_cmd(BT_HCI_OP_LE_READ_BUFFER_SIZE, NULL, &rsp); + le_read_buffer_size_complete(rsp); + + set_data_len(); + set_event_mask(BT_HCI_OP_SET_EVENT_MASK); + set_event_mask(BT_HCI_OP_LE_SET_EVENT_MASK); + set_random_address(); +} + +static void init_tinyhost(void) +{ + bt_enable_raw(&rx_queue); + + /* Start the RX thread */ + k_thread_create(&rx_thread_data, rx_thread_stack, + K_THREAD_STACK_SIZEOF(rx_thread_stack), rx_thread, + NULL, NULL, NULL, K_PRIO_PREEMPT(0), 0, K_NO_WAIT); + k_thread_name_set(&rx_thread_data, "HCI RX"); + + k_thread_priority_set(k_current_get(), K_PRIO_PREEMPT(0)); + + prepare_controller(); +} + +void test_procedure_0(void) +{ + att_handlers[BT_ATT_OP_WRITE_REQ] = handle_att_write_0; + + init_tinyhost(); + + /* wait until the good peer has connected */ + k_msleep(1000); + + LOG_INF("init adv"); + + /* Start advertising & wait for a connection */ + start_adv(); + WAIT_FOR_FLAG(is_connected); + LOG_INF("connected"); + + /* We need this to be able to send whole L2CAP PDUs on-air. */ + WAIT_FOR_FLAG(flag_data_length_updated); + + /* Get handle we will write to */ + WAIT_FOR_FLAG(flag_handle); + + LOG_INF("##################### START TEST #####################"); + + uint32_t timeout_ms = PROCEDURE_1_TIMEOUT_MS; + uint32_t start_time = k_uptime_get_32(); + + while (k_uptime_get_32() - start_time < timeout_ms) { + gatt_write(BT_ATT_OP_WRITE_REQ); + } + + /* Verify we get at least one write */ + WAIT_FOR_FLAG(flag_write_ack); + + PASS("Tester done\n"); +} + +void test_procedure_1(void) +{ + att_handlers[BT_ATT_OP_WRITE_REQ] = handle_att_write_1; + + init_tinyhost(); + + /* Start advertising & wait for a connection */ + LOG_INF("init adv"); + start_adv(); + WAIT_FOR_FLAG(is_connected); + LOG_INF("connected"); + + /* We need this to be able to send whole L2CAP PDUs on-air. */ + WAIT_FOR_FLAG(flag_data_length_updated); + + LOG_INF("##################### START TEST #####################"); + + /* In this testcase, DUT is the aggressor. + * Tester verifies no spec violation happens. + */ + while (TEST_FLAG(is_connected)) { + /* Should be enough to allow DUT's app to batch a few requests. */ + k_msleep(1000); + if (TEST_FLAG(flag_req_in_progress)) { + send_write_rsp(); + } + } + + PASS("Tester done\n"); +} + +void test_tick(bs_time_t HW_device_time) +{ + bs_trace_debug_time(0, "Simulation ends now.\n"); + if (bst_result != Passed) { + bst_result = Failed; + bs_trace_error("Test did not pass before simulation ended.\n"); + } +} + +void test_init(void) +{ + bst_ticker_set_next_tick_absolute(TEST_TIMEOUT_SIMULATED); + bst_result = In_progress; +} + +static const struct bst_test_instance test_to_add[] = { + { + .test_id = "tester", + .test_pre_init_f = test_init, + .test_tick_f = test_tick, + .test_main_f = test_procedure_0, + }, + { + .test_id = "tester_1", + .test_pre_init_f = test_init, + .test_tick_f = test_tick, + .test_main_f = test_procedure_1, + }, + BSTEST_END_MARKER, +}; + +static struct bst_test_list *install(struct bst_test_list *tests) +{ + return bst_add_tests(tests, test_to_add); +}; + +bst_test_install_t test_installers[] = {install, NULL}; + + +int main(void) +{ + bst_main(); + + return 0; +} diff --git a/tests/bsim/bluetooth/host/compile.sh b/tests/bsim/bluetooth/host/compile.sh index 405586143e3..9eb87341430 100755 --- a/tests/bsim/bluetooth/host/compile.sh +++ b/tests/bsim/bluetooth/host/compile.sh @@ -39,6 +39,8 @@ app=tests/bsim/bluetooth/host/att/retry_on_sec_err/client compile app=tests/bsim/bluetooth/host/att/retry_on_sec_err/server compile app=tests/bsim/bluetooth/host/att/sequential/dut compile app=tests/bsim/bluetooth/host/att/sequential/tester compile +app=tests/bsim/bluetooth/host/att/pipeline/dut compile +app=tests/bsim/bluetooth/host/att/pipeline/tester compile app=tests/bsim/bluetooth/host/att/long_read compile app=tests/bsim/bluetooth/host/att/open_close compile From ea04fd95f939b8115358560df5887bb5f2baeab8 Mon Sep 17 00:00:00 2001 From: Jonathan Rico Date: Wed, 29 Nov 2023 13:14:31 +0100 Subject: [PATCH 0829/3723] Bluetooth: ATT: remove `BT_ATT_ENFORCE_FLOW` Enforcing the peer's behavior is not strictly necessary. All the host should do is make sure it is resilient to a spec-violating peer. Moreover, a growing number of platforms were disabling the check, as the spec allows "batching" HCI num complete packets events, stalling ATT RX. Signed-off-by: Jonathan Rico Co-authored-by: Aleksander Wasaznik --- drivers/bluetooth/hci/Kconfig.infineon | 5 ----- samples/bluetooth/peripheral_ht/prj.conf | 1 - subsys/bluetooth/host/Kconfig.gatt | 11 ----------- subsys/bluetooth/host/att.c | 23 ----------------------- 4 files changed, 40 deletions(-) diff --git a/drivers/bluetooth/hci/Kconfig.infineon b/drivers/bluetooth/hci/Kconfig.infineon index 1f4193bd28a..6204ed4f8a2 100644 --- a/drivers/bluetooth/hci/Kconfig.infineon +++ b/drivers/bluetooth/hci/Kconfig.infineon @@ -129,11 +129,6 @@ config AIROC_CUSTOM_FIRMWARE_HCD_BLOB config BT_BUF_CMD_TX_SIZE default 255 -# Disable ATT_ENFORCE_FLOW feature, CYW43XX informs about frees buffer -# (HCL Number Of Completed Packets event) after second packet. -config BT_ATT_ENFORCE_FLOW - default n - endif # BT_AIROC if BT_PSOC6_BLESS diff --git a/samples/bluetooth/peripheral_ht/prj.conf b/samples/bluetooth/peripheral_ht/prj.conf index d25259ec660..b8a3da4f5b5 100644 --- a/samples/bluetooth/peripheral_ht/prj.conf +++ b/samples/bluetooth/peripheral_ht/prj.conf @@ -7,5 +7,4 @@ CONFIG_BT_DIS_PNP=n CONFIG_BT_BAS=y CONFIG_BT_DEVICE_NAME="Zephyr Health Thermometer" CONFIG_BT_DEVICE_APPEARANCE=768 -CONFIG_BT_ATT_ENFORCE_FLOW=n CONFIG_CBPRINTF_FP_SUPPORT=y diff --git a/subsys/bluetooth/host/Kconfig.gatt b/subsys/bluetooth/host/Kconfig.gatt index 9209368f943..53b482a0a38 100644 --- a/subsys/bluetooth/host/Kconfig.gatt +++ b/subsys/bluetooth/host/Kconfig.gatt @@ -5,17 +5,6 @@ menu "ATT and GATT Options" -config BT_ATT_ENFORCE_FLOW - bool "Enforce strict flow control semantics for incoming PDUs" - default y if !(BOARD_QEMU_CORTEX_M3 || BOARD_QEMU_X86 || ARCH_POSIX || BT_SPI_BLUENRG) - help - Enforce flow control rules on incoming PDUs, preventing a peer - from sending new requests until a previous one has been responded - or sending a new indication until a previous one has been - confirmed. This may need to be disabled to avoid potential race - conditions arising from a USB based HCI transport that splits - HCI events and ACL data to separate endpoints. - config BT_ATT_PREPARE_COUNT int "Number of ATT prepare write buffers" default 0 diff --git a/subsys/bluetooth/host/att.c b/subsys/bluetooth/host/att.c index 70fc717aff6..2b5206bcd0f 100644 --- a/subsys/bluetooth/host/att.c +++ b/subsys/bluetooth/host/att.c @@ -72,8 +72,6 @@ K_MEM_SLAB_DEFINE(req_slab, sizeof(struct bt_att_req), CONFIG_BT_L2CAP_TX_BUF_COUNT, __alignof__(struct bt_att_req)); enum { - ATT_PENDING_RSP, - ATT_PENDING_CFM, ATT_CONNECTED, ATT_ENHANCED, ATT_PENDING_SENT, @@ -540,10 +538,6 @@ static void chan_cfm_sent(struct bt_conn *conn, struct bt_att_tx_meta_data *user LOG_DBG("chan %p", chan); - if (IS_ENABLED(CONFIG_BT_ATT_ENFORCE_FLOW)) { - atomic_clear_bit(chan->flags, ATT_PENDING_CFM); - } - tx_meta_data_free(data); } @@ -554,10 +548,6 @@ static void chan_rsp_sent(struct bt_conn *conn, struct bt_att_tx_meta_data *user LOG_DBG("chan %p", chan); - if (IS_ENABLED(CONFIG_BT_ATT_ENFORCE_FLOW)) { - atomic_clear_bit(chan->flags, ATT_PENDING_RSP); - } - tx_meta_data_free(data); } @@ -2908,19 +2898,6 @@ static int bt_att_recv(struct bt_l2cap_chan *chan, struct net_buf *buf) return 0; } - if (IS_ENABLED(CONFIG_BT_ATT_ENFORCE_FLOW)) { - if (handler->type == ATT_REQUEST && - atomic_test_and_set_bit(att_chan->flags, ATT_PENDING_RSP)) { - LOG_WRN("Ignoring unexpected request"); - return 0; - } else if (handler->type == ATT_INDICATION && - atomic_test_and_set_bit(att_chan->flags, - ATT_PENDING_CFM)) { - LOG_WRN("Ignoring unexpected indication"); - return 0; - } - } - if (buf->len < handler->expect_len) { LOG_ERR("Invalid len %u for code 0x%02x", buf->len, hdr->code); err = BT_ATT_ERR_INVALID_PDU; From 102bedc11fd3a9f509cb1e8922908bd2b78f795c Mon Sep 17 00:00:00 2001 From: Mariusz Skamra Date: Fri, 1 Dec 2023 11:47:13 +0100 Subject: [PATCH 0830/3723] Bluetooth: audio: pacs: Minor API description fix Remove the "Internal" word from public PACS API. Signed-off-by: Mariusz Skamra --- include/zephyr/bluetooth/audio/pacs.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/include/zephyr/bluetooth/audio/pacs.h b/include/zephyr/bluetooth/audio/pacs.h index 4b9b7e29a2a..ad8d5ec0a98 100644 --- a/include/zephyr/bluetooth/audio/pacs.h +++ b/include/zephyr/bluetooth/audio/pacs.h @@ -1,5 +1,5 @@ /* @file - * @brief Internal APIs for Audio Capabilities handling + * @brief APIs for Audio Capabilities handling * * Copyright (c) 2021 Intel Corporation * Copyright (c) 2021-2022 Nordic Semiconductor ASA From ef362e766ae45f32b3cf239b72e08d41fa218f68 Mon Sep 17 00:00:00 2001 From: Mariusz Skamra Date: Fri, 1 Dec 2023 13:28:09 +0100 Subject: [PATCH 0831/3723] Bluetooth: audio: pacs: Disallow changing supported contexts Disallow further changes of supported audio contexts characteristic is the GATT Characteristic Notify Property is not set. Signed-off-by: Mariusz Skamra --- subsys/bluetooth/audio/pacs.c | 90 ++++++++++++++++++----------------- 1 file changed, 47 insertions(+), 43 deletions(-) diff --git a/subsys/bluetooth/audio/pacs.c b/subsys/bluetooth/audio/pacs.c index 2ce6db23a9f..1c597ff080e 100644 --- a/subsys/bluetooth/audio/pacs.c +++ b/subsys/bluetooth/audio/pacs.c @@ -41,28 +41,17 @@ LOG_MODULE_REGISTER(bt_pacs, CONFIG_BT_PACS_LOG_LEVEL); #if defined(CONFIG_BT_PAC_SRC) static uint32_t pacs_src_location; static sys_slist_t src_pacs_list = SYS_SLIST_STATIC_INIT(&src_pacs_list); +static uint16_t src_supported_contexts; #endif /* CONFIG_BT_PAC_SRC */ #if defined(CONFIG_BT_PAC_SNK) static uint32_t pacs_snk_location; static sys_slist_t snk_pacs_list = SYS_SLIST_STATIC_INIT(&snk_pacs_list); +static uint16_t snk_supported_contexts; #endif /* CONFIG_BT_PAC_SNK */ -#if defined(CONFIG_BT_PAC_SNK) -static uint16_t snk_available_contexts; -static uint16_t snk_supported_contexts = BT_AUDIO_CONTEXT_TYPE_UNSPECIFIED; -#else -static uint16_t snk_available_contexts = BT_AUDIO_CONTEXT_TYPE_PROHIBITED; -static uint16_t snk_supported_contexts = BT_AUDIO_CONTEXT_TYPE_PROHIBITED; -#endif /* CONFIG_BT_PAC_SNK */ - -#if defined(CONFIG_BT_PAC_SRC) -static uint16_t src_available_contexts; -static uint16_t src_supported_contexts = BT_AUDIO_CONTEXT_TYPE_UNSPECIFIED; -#else static uint16_t src_available_contexts = BT_AUDIO_CONTEXT_TYPE_PROHIBITED; -static uint16_t src_supported_contexts = BT_AUDIO_CONTEXT_TYPE_PROHIBITED; -#endif /* CONFIG_BT_PAC_SRC */ +static uint16_t snk_available_contexts = BT_AUDIO_CONTEXT_TYPE_PROHIBITED; enum { FLAG_ACTIVE, @@ -212,13 +201,31 @@ static void supported_context_cfg_changed(const struct bt_gatt_attr *attr, } #endif /* CONFIG_BT_PACS_SUPPORTED_CONTEXT_NOTIFIABLE */ +static uint16_t supported_context_get(enum bt_audio_dir dir) +{ + switch (dir) { +#if defined(CONFIG_BT_PAC_SNK) + case BT_AUDIO_DIR_SINK: + return snk_supported_contexts | BT_AUDIO_CONTEXT_TYPE_UNSPECIFIED; +#endif /* CONFIG_BT_PAC_SNK */ +#if defined(CONFIG_BT_PAC_SRC) + case BT_AUDIO_DIR_SOURCE: + return src_supported_contexts | BT_AUDIO_CONTEXT_TYPE_UNSPECIFIED; +#endif /* CONFIG_BT_PAC_SRC */ + default: + break; + } + + return BT_AUDIO_CONTEXT_TYPE_PROHIBITED; +} + static ssize_t supported_context_read(struct bt_conn *conn, const struct bt_gatt_attr *attr, void *buf, uint16_t len, uint16_t offset) { struct bt_pacs_context context = { - .snk = sys_cpu_to_le16(snk_supported_contexts), - .src = sys_cpu_to_le16(src_supported_contexts), + .snk = sys_cpu_to_le16(supported_context_get(BT_AUDIO_DIR_SINK)), + .src = sys_cpu_to_le16(supported_context_get(BT_AUDIO_DIR_SOURCE)), }; LOG_DBG("conn %p attr %p buf %p len %u offset %u", conn, attr, buf, len, offset); @@ -321,22 +328,11 @@ static inline int set_snk_available_contexts(uint16_t contexts) return set_available_contexts(contexts, &snk_available_contexts, snk_supported_contexts); } - -static inline int set_snk_supported_contexts(uint16_t contexts) -{ - return set_supported_contexts(contexts, &snk_supported_contexts, - &snk_available_contexts); -} #else static inline int set_snk_available_contexts(uint16_t contexts) { return -ENOTSUP; } - -static inline int set_snk_supported_contexts(uint16_t contexts) -{ - return -ENOTSUP; -} #endif /* CONFIG_BT_PAC_SNK */ #if defined(CONFIG_BT_PAC_SNK_LOC) @@ -448,22 +444,11 @@ static inline int set_src_available_contexts(uint16_t contexts) return set_available_contexts(contexts, &src_available_contexts, src_supported_contexts); } - -static inline int set_src_supported_contexts(uint16_t contexts) -{ - return set_supported_contexts(contexts, &src_supported_contexts, - &src_available_contexts); -} #else static inline int set_src_available_contexts(uint16_t contexts) { return -ENOTSUP; } - -static inline int set_src_supported_contexts(uint16_t contexts) -{ - return -ENOTSUP; -} #endif /* CONFIG_BT_PAC_SRC */ #if defined(CONFIG_BT_PAC_SRC_LOC) @@ -749,8 +734,8 @@ static int available_contexts_notify(struct bt_conn *conn) static int supported_contexts_notify(struct bt_conn *conn) { struct bt_pacs_context context = { - .snk = sys_cpu_to_le16(snk_supported_contexts), - .src = sys_cpu_to_le16(src_supported_contexts), + .snk = sys_cpu_to_le16(supported_context_get(BT_AUDIO_DIR_SINK)), + .src = sys_cpu_to_le16(supported_context_get(BT_AUDIO_DIR_SOURCE)), }; int err; @@ -1128,14 +1113,33 @@ int bt_pacs_set_available_contexts(enum bt_audio_dir dir, enum bt_audio_context int bt_pacs_set_supported_contexts(enum bt_audio_dir dir, enum bt_audio_context contexts) { + uint16_t *supported_contexts = NULL; + uint16_t *available_contexts = NULL; + switch (dir) { case BT_AUDIO_DIR_SINK: - return set_snk_supported_contexts(contexts); +#if defined(CONFIG_BT_PAC_SNK) + supported_contexts = &snk_supported_contexts; + available_contexts = &snk_available_contexts; + break; +#endif /* CONFIG_BT_PAC_SNK */ + return -ENOTSUP; case BT_AUDIO_DIR_SOURCE: - return set_src_supported_contexts(contexts); +#if defined(CONFIG_BT_PAC_SRC) + supported_contexts = &src_supported_contexts; + available_contexts = &src_available_contexts; + break; +#endif /* CONFIG_BT_PAC_SRC */ + return -ENOTSUP; + default: + return -EINVAL; } - return -EINVAL; + if (IS_ENABLED(CONFIG_BT_PACS_SUPPORTED_CONTEXT_NOTIFIABLE) || *supported_contexts == 0) { + return set_supported_contexts(contexts, supported_contexts, available_contexts); + } + + return -EALREADY; } enum bt_audio_context bt_pacs_get_available_contexts(enum bt_audio_dir dir) From 014c22c9c0e627d356b3bf2f7373d8e3dd6ff03c Mon Sep 17 00:00:00 2001 From: Mariusz Skamra Date: Fri, 1 Dec 2023 14:44:26 +0100 Subject: [PATCH 0832/3723] Bluetooth: audio: pacs: Fix invalid lookup This fixes client lookup that was done with use of bt_conn_index while the size of the client array is CONFIG_BT_MAX_PAIRED. Signed-off-by: Mariusz Skamra --- subsys/bluetooth/audio/pacs.c | 21 ++++++++++++++++++++- 1 file changed, 20 insertions(+), 1 deletion(-) diff --git a/subsys/bluetooth/audio/pacs.c b/subsys/bluetooth/audio/pacs.c index 1c597ff080e..2fbe1c2de61 100644 --- a/subsys/bluetooth/audio/pacs.c +++ b/subsys/bluetooth/audio/pacs.c @@ -93,6 +93,20 @@ struct pac_records_build_data { struct net_buf_simple *buf; }; +static struct pacs_client *client_lookup_conn(const struct bt_conn *conn) +{ + __ASSERT_NO_MSG(conn != NULL); + + for (size_t i = 0; i < ARRAY_SIZE(clients); i++) { + if (atomic_test_bit(clients[i].flags, FLAG_ACTIVE) && + bt_addr_le_eq(&clients[i].addr, bt_conn_get_dst(conn))) { + return &clients[i]; + } + } + + return NULL; +} + static void pacs_set_notify_bit(int bit) { for (size_t i = 0U; i < ARRAY_SIZE(clients); i++) { @@ -789,7 +803,7 @@ static int pacs_gatt_notify(struct bt_conn *conn, static void notify_cb(struct bt_conn *conn, void *data) { - struct pacs_client *client = &clients[bt_conn_index(conn)]; + struct pacs_client *client; struct bt_conn_info info; int err = 0; @@ -806,6 +820,11 @@ static void notify_cb(struct bt_conn *conn, void *data) return; } + client = client_lookup_conn(conn); + if (client == NULL) { + return; + } + /* Check if we have unverified notifications in progress */ if (atomic_get(¬ify_rdy)) { return; From 78a4b33e5c3b39fed867fd8324ec2f7a3fba5b26 Mon Sep 17 00:00:00 2001 From: Mariusz Skamra Date: Fri, 1 Dec 2023 14:50:35 +0100 Subject: [PATCH 0833/3723] Bluetooth: audio: pacs: Add bt_pacs_set_available_contexts_for_conn This adds the function that sets the available contexts value per connection object so that API user can set different available contexts per connection. The lifetime of such overriden value is the same as connection lifetime, so on reconnection or device reboot all devices return to having the same available contexts value again. Fixes: #64968 Signed-off-by: Mariusz Skamra --- include/zephyr/bluetooth/audio/pacs.h | 31 ++++ subsys/bluetooth/audio/ascs.c | 10 +- subsys/bluetooth/audio/pacs.c | 193 ++++++++++++++++----- subsys/bluetooth/audio/pacs_internal.h | 2 - tests/bluetooth/audio/mocks/include/pacs.h | 2 + tests/bluetooth/audio/mocks/src/pacs.c | 6 +- 6 files changed, 199 insertions(+), 45 deletions(-) diff --git a/include/zephyr/bluetooth/audio/pacs.h b/include/zephyr/bluetooth/audio/pacs.h index ad8d5ec0a98..828851ff9dd 100644 --- a/include/zephyr/bluetooth/audio/pacs.h +++ b/include/zephyr/bluetooth/audio/pacs.h @@ -96,6 +96,37 @@ int bt_pacs_set_available_contexts(enum bt_audio_dir dir, */ enum bt_audio_context bt_pacs_get_available_contexts(enum bt_audio_dir dir); +/** @brief Set the available contexts for a given connection + * + * This function sets the available contexts value for a given @p conn connection object. + * If the @p contexts parameter is NULL the available contexts value is reset to default. + * The default value of the available contexts is set using @ref bt_pacs_set_available_contexts + * function. + * The Available Context Value is reset to default on ACL disconnection. + * + * @param conn Connection object. + * @param dir Direction of the endpoints to change available contexts for. + * @param contexts The contexts to be set or NULL to reset to default. + * + * @return 0 in case of success or negative value in case of error. + */ +int bt_pacs_conn_set_available_contexts_for_conn(struct bt_conn *conn, enum bt_audio_dir dir, + enum bt_audio_context *contexts); + +/** @brief Get the available contexts for a given connection + * + * This server function returns the available contexts value for a given @p conn connection object. + * The value returned is the one set with @ref bt_pacs_conn_set_available_contexts_for_conn function + * or the default value set with @ref bt_pacs_set_available_contexts function. + * + * @param conn Connection object. + * @param dir Direction of the endpoints to get contexts for. + * + * @return Bitmask of available contexts. + */ +enum bt_audio_context bt_pacs_get_available_contexts_for_conn(struct bt_conn *conn, + enum bt_audio_dir dir); + /** @brief Set the supported contexts for an endpoint type * * @param dir Direction of the endpoints to change available contexts for. diff --git a/subsys/bluetooth/audio/ascs.c b/subsys/bluetooth/audio/ascs.c index c20320aa411..b1f6a26999a 100644 --- a/subsys/bluetooth/audio/ascs.c +++ b/subsys/bluetooth/audio/ascs.c @@ -1992,10 +1992,16 @@ static ssize_t ascs_qos(struct bt_conn *conn, struct net_buf_simple *buf) struct ascs_parse_result { int err; + struct bt_conn *conn; struct bt_bap_ascs_rsp *rsp; const struct bt_bap_ep *ep; }; +static bool is_context_available(struct bt_conn *conn, enum bt_audio_dir dir, uint16_t context) +{ + return (context & bt_pacs_get_available_contexts_for_conn(conn, dir)) == context; +} + static bool ascs_parse_metadata(struct bt_data *data, void *user_data) { struct ascs_parse_result *result = user_data; @@ -2035,7 +2041,7 @@ static bool ascs_parse_metadata(struct bt_data *data, void *user_data) /* The CAP acceptor shall not accept metadata with unsupported stream context. */ if (IS_ENABLED(CONFIG_BT_CAP_ACCEPTOR) && data_type == BT_AUDIO_METADATA_TYPE_STREAM_CONTEXT) { - if (!bt_pacs_context_available(ep->dir, context)) { + if (!is_context_available(result->conn, ep->dir, context)) { LOG_WRN("Context 0x%04x is unavailable", context); *result->rsp = BT_BAP_ASCS_RSP( BT_BAP_ASCS_RSP_CODE_METADATA_REJECTED, data_type); @@ -2120,7 +2126,9 @@ static bool ascs_parse_metadata(struct bt_data *data, void *user_data) static int ascs_verify_metadata(struct bt_bap_ep *ep, const struct bt_ascs_metadata *meta, struct bt_bap_ascs_rsp *rsp) { + struct bt_ascs_ase *ase = CONTAINER_OF(ep, struct bt_ascs_ase, ep); struct ascs_parse_result result = { + .conn = ase->conn, .rsp = rsp, .err = 0, .ep = ep, diff --git a/subsys/bluetooth/audio/pacs.c b/subsys/bluetooth/audio/pacs.c index 2fbe1c2de61..1dfd7aa4710 100644 --- a/subsys/bluetooth/audio/pacs.c +++ b/subsys/bluetooth/audio/pacs.c @@ -67,6 +67,16 @@ enum { static struct pacs_client { bt_addr_le_t addr; +#if defined(CONFIG_BT_PAC_SNK) + /* Sink Available Contexts override value */ + uint16_t *snk_available_contexts; +#endif /* CONFIG_BT_PAC_SNK */ + +#if defined(CONFIG_BT_PAC_SRC) + /* Source Available Contexts override value */ + uint16_t *src_available_contexts; +#endif /* CONFIG_BT_PAC_SRC */ + /* Pending notification flags */ ATOMIC_DEFINE(flags, FLAG_NUM); } clients[CONFIG_BT_MAX_PAIRED]; @@ -197,8 +207,10 @@ static ssize_t available_contexts_read(struct bt_conn *conn, uint16_t len, uint16_t offset) { struct bt_pacs_context context = { - .snk = sys_cpu_to_le16(snk_available_contexts), - .src = sys_cpu_to_le16(src_available_contexts), + .snk = sys_cpu_to_le16( + bt_pacs_get_available_contexts_for_conn(conn, BT_AUDIO_DIR_SINK)), + .src = sys_cpu_to_le16( + bt_pacs_get_available_contexts_for_conn(conn, BT_AUDIO_DIR_SOURCE)), }; LOG_DBG("conn %p attr %p buf %p len %u offset %u", conn, attr, buf, len, offset); @@ -336,17 +348,6 @@ static void snk_cfg_changed(const struct bt_gatt_attr *attr, uint16_t value) LOG_DBG("attr %p value 0x%04x", attr, value); } #endif /* CONFIG_BT_PAC_SNK_NOTIFIABLE */ - -static inline int set_snk_available_contexts(uint16_t contexts) -{ - return set_available_contexts(contexts, &snk_available_contexts, - snk_supported_contexts); -} -#else -static inline int set_snk_available_contexts(uint16_t contexts) -{ - return -ENOTSUP; -} #endif /* CONFIG_BT_PAC_SNK */ #if defined(CONFIG_BT_PAC_SNK_LOC) @@ -452,17 +453,6 @@ static void src_cfg_changed(const struct bt_gatt_attr *attr, uint16_t value) LOG_DBG("attr %p value 0x%04x", attr, value); } #endif /* CONFIG_BT_PAC_SRC_NOTIFIABLE */ - -static inline int set_src_available_contexts(uint16_t contexts) -{ - return set_available_contexts(contexts, &src_available_contexts, - src_supported_contexts); -} -#else -static inline int set_src_available_contexts(uint16_t contexts) -{ - return -ENOTSUP; -} #endif /* CONFIG_BT_PAC_SRC */ #if defined(CONFIG_BT_PAC_SRC_LOC) @@ -730,8 +720,10 @@ static int pac_notify(struct bt_conn *conn, enum bt_audio_dir dir) static int available_contexts_notify(struct bt_conn *conn) { struct bt_pacs_context context = { - .snk = sys_cpu_to_le16(snk_available_contexts), - .src = sys_cpu_to_le16(src_available_contexts), + .snk = sys_cpu_to_le16( + bt_pacs_get_available_contexts_for_conn(conn, BT_AUDIO_DIR_SINK)), + .src = sys_cpu_to_le16( + bt_pacs_get_available_contexts_for_conn(conn, BT_AUDIO_DIR_SOURCE)), }; int err; @@ -961,8 +953,43 @@ static void pacs_security_changed(struct bt_conn *conn, bt_security_t level, } } +static void pacs_disconnected(struct bt_conn *conn, uint8_t reason) +{ + struct pacs_client *client; + + client = client_lookup_conn(conn); + if (client == NULL) { + return; + } + +#if defined(CONFIG_BT_PAC_SNK) + if (client->snk_available_contexts != NULL) { + uint16_t old = POINTER_TO_UINT(client->snk_available_contexts); + uint16_t new; + + client->snk_available_contexts = NULL; + new = bt_pacs_get_available_contexts_for_conn(conn, BT_AUDIO_DIR_SINK); + + atomic_set_bit_to(client->flags, FLAG_AVAILABLE_AUDIO_CONTEXT_CHANGED, old != new); + } +#endif /* CONFIG_BT_PAC_SNK */ + +#if defined(CONFIG_BT_PAC_SRC) + if (client->src_available_contexts != NULL) { + uint16_t old = POINTER_TO_UINT(client->src_available_contexts); + uint16_t new; + + client->src_available_contexts = NULL; + new = bt_pacs_get_available_contexts_for_conn(conn, BT_AUDIO_DIR_SOURCE); + + atomic_set_bit_to(client->flags, FLAG_AVAILABLE_AUDIO_CONTEXT_CHANGED, old != new); + } +#endif /* CONFIG_BT_PAC_SRC */ +} + static struct bt_conn_cb conn_callbacks = { .security_changed = pacs_security_changed, + .disconnected = pacs_disconnected, }; static struct bt_conn_auth_info_cb auth_callbacks = { @@ -970,19 +997,6 @@ static struct bt_conn_auth_info_cb auth_callbacks = { .bond_deleted = pacs_bond_deleted }; -bool bt_pacs_context_available(enum bt_audio_dir dir, uint16_t context) -{ - if (dir == BT_AUDIO_DIR_SOURCE) { - return (context & src_available_contexts) == context; - } - - if (dir == BT_AUDIO_DIR_SINK) { - return (context & snk_available_contexts) == context; - } - - return false; -} - void bt_pacs_cap_foreach(enum bt_audio_dir dir, bt_pacs_cap_foreach_func_t func, void *user_data) { sys_slist_t *pac; @@ -1122,14 +1136,75 @@ int bt_pacs_set_available_contexts(enum bt_audio_dir dir, enum bt_audio_context { switch (dir) { case BT_AUDIO_DIR_SINK: - return set_snk_available_contexts(contexts); + return set_available_contexts(contexts, &snk_available_contexts, + supported_context_get(dir)); case BT_AUDIO_DIR_SOURCE: - return set_src_available_contexts(contexts); + return set_available_contexts(contexts, &src_available_contexts, + supported_context_get(dir)); } return -EINVAL; } +int bt_pacs_conn_set_available_contexts_for_conn(struct bt_conn *conn, enum bt_audio_dir dir, + enum bt_audio_context *contexts) +{ + enum bt_audio_context old = bt_pacs_get_available_contexts_for_conn(conn, dir); + struct bt_conn_info info = { 0 }; + struct pacs_client *client; + int err; + + client = client_lookup_conn(conn); + if (client == NULL) { + return -ENOENT; + } + + err = bt_conn_get_info(conn, &info); + if (err < 0) { + LOG_ERR("Could not get conn info: %d", err); + return err; + } + + switch (dir) { +#if defined(CONFIG_BT_PAC_SNK) + case BT_AUDIO_DIR_SINK: + if (contexts != NULL) { + client->snk_available_contexts = UINT_TO_POINTER(*contexts); + } else { + client->snk_available_contexts = NULL; + } + + break; +#endif /* CONFIG_BT_PAC_SNK */ +#if defined(CONFIG_BT_PAC_SRC) + case BT_AUDIO_DIR_SOURCE: + if (contexts != NULL) { + client->src_available_contexts = UINT_TO_POINTER(*contexts); + } else { + client->src_available_contexts = NULL; + } + + break; +#endif /* CONFIG_BT_PAC_SRC */ + default: + return -EINVAL; + } + + if (bt_pacs_get_available_contexts_for_conn(conn, dir) == old) { + /* No change. Skip notification */ + return 0; + } + + atomic_set_bit(client->flags, FLAG_AVAILABLE_AUDIO_CONTEXT_CHANGED); + + /* Send notification on encrypted link only */ + if (info.security.level > BT_SECURITY_L1) { + k_work_submit(&deferred_nfy_work); + } + + return 0; +} + int bt_pacs_set_supported_contexts(enum bt_audio_dir dir, enum bt_audio_context contexts) { uint16_t *supported_contexts = NULL; @@ -1172,3 +1247,39 @@ enum bt_audio_context bt_pacs_get_available_contexts(enum bt_audio_dir dir) return BT_AUDIO_CONTEXT_TYPE_PROHIBITED; } + +enum bt_audio_context bt_pacs_get_available_contexts_for_conn(struct bt_conn *conn, + enum bt_audio_dir dir) +{ + const struct pacs_client *client; + + CHECKIF(conn == NULL) { + LOG_ERR("NULL conn"); + return -EINVAL; + } + + client = client_lookup_conn(conn); + if (client == NULL) { + LOG_ERR("No client context for conn %p", (void *)conn); + return bt_pacs_get_available_contexts(dir); + } + + switch (dir) { + case BT_AUDIO_DIR_SINK: +#if defined(CONFIG_BT_PAC_SNK) + if (client->snk_available_contexts != NULL) { + return POINTER_TO_UINT(client->snk_available_contexts); + } +#endif /* CONFIG_BT_PAC_SNK */ + break; + case BT_AUDIO_DIR_SOURCE: +#if defined(CONFIG_BT_PAC_SRC) + if (client->src_available_contexts != NULL) { + return POINTER_TO_UINT(client->src_available_contexts); + } +#endif /* CONFIG_BT_PAC_SRC */ + break; + } + + return bt_pacs_get_available_contexts(dir); +} diff --git a/subsys/bluetooth/audio/pacs_internal.h b/subsys/bluetooth/audio/pacs_internal.h index 9f5291ae579..2c449f7f4ad 100644 --- a/subsys/bluetooth/audio/pacs_internal.h +++ b/subsys/bluetooth/audio/pacs_internal.h @@ -36,5 +36,3 @@ struct bt_pacs_context { uint16_t snk; uint16_t src; } __packed; - -bool bt_pacs_context_available(enum bt_audio_dir dir, uint16_t context); diff --git a/tests/bluetooth/audio/mocks/include/pacs.h b/tests/bluetooth/audio/mocks/include/pacs.h index 217ad0eb370..d5cc81e6490 100644 --- a/tests/bluetooth/audio/mocks/include/pacs.h +++ b/tests/bluetooth/audio/mocks/include/pacs.h @@ -14,5 +14,7 @@ void mock_bt_pacs_init(void); void mock_bt_pacs_cleanup(void); DECLARE_FAKE_VOID_FUNC(bt_pacs_cap_foreach, enum bt_audio_dir, bt_pacs_cap_foreach_func_t, void *); +DECLARE_FAKE_VALUE_FUNC(enum bt_audio_context, bt_pacs_get_available_contexts_for_conn, + struct bt_conn *, enum bt_audio_dir); #endif /* MOCKS_PACS_H_ */ diff --git a/tests/bluetooth/audio/mocks/src/pacs.c b/tests/bluetooth/audio/mocks/src/pacs.c index 430a175a402..4e6e80ef4a4 100644 --- a/tests/bluetooth/audio/mocks/src/pacs.c +++ b/tests/bluetooth/audio/mocks/src/pacs.c @@ -10,7 +10,9 @@ #include "pacs.h" /* List of fakes used by this unit tester */ -#define PACS_FFF_FAKES_LIST(FAKE) FAKE(bt_pacs_cap_foreach) +#define PACS_FFF_FAKES_LIST(FAKE) \ + FAKE(bt_pacs_cap_foreach) \ + FAKE(bt_pacs_get_available_contexts_for_conn) \ static const struct bt_audio_codec_cap lc3_codec = BT_AUDIO_CODEC_CAP_LC3( BT_AUDIO_CODEC_LC3_FREQ_ANY, BT_AUDIO_CODEC_LC3_DURATION_10, @@ -18,6 +20,8 @@ static const struct bt_audio_codec_cap lc3_codec = BT_AUDIO_CODEC_CAP_LC3( (BT_AUDIO_CONTEXT_TYPE_CONVERSATIONAL | BT_AUDIO_CONTEXT_TYPE_MEDIA)); DEFINE_FAKE_VOID_FUNC(bt_pacs_cap_foreach, enum bt_audio_dir, bt_pacs_cap_foreach_func_t, void *); +DEFINE_FAKE_VALUE_FUNC(enum bt_audio_context, bt_pacs_get_available_contexts_for_conn, + struct bt_conn *, enum bt_audio_dir); static void pacs_cap_foreach_custom_fake(enum bt_audio_dir dir, bt_pacs_cap_foreach_func_t func, void *user_data) From 1b0e0fbd1497ec3dbb54baef2059f0be53881f17 Mon Sep 17 00:00:00 2001 From: Mariusz Skamra Date: Mon, 4 Dec 2023 08:54:07 +0100 Subject: [PATCH 0834/3723] tests: bsim: pacs: Change printk to LOG Replace combination of printk() to LOG_DBG() to fix the order of the test execution logs. The printk() is printed immediately, while logs are buffered, thus the messages from test are printed out before the stack logs. Signed-off-by: Mariusz Skamra --- .../audio/src/pacs_notify_client_test.c | 153 +++++++++--------- .../audio/src/pacs_notify_server_test.c | 63 ++++---- 2 files changed, 111 insertions(+), 105 deletions(-) diff --git a/tests/bsim/bluetooth/audio/src/pacs_notify_client_test.c b/tests/bsim/bluetooth/audio/src/pacs_notify_client_test.c index 9910f6f2c8c..448c0da23f5 100644 --- a/tests/bsim/bluetooth/audio/src/pacs_notify_client_test.c +++ b/tests/bsim/bluetooth/audio/src/pacs_notify_client_test.c @@ -10,6 +10,9 @@ #include "common.h" #include "common/bt_str.h" +#include +LOG_MODULE_REGISTER(pacs_notify_client_test, LOG_LEVEL_DBG); + struct pacs_instance_t { uint16_t start_handle; uint16_t end_handle; @@ -44,29 +47,29 @@ static uint8_t pacs_notify_handler(struct bt_conn *conn, struct bt_gatt_subscribe_params *params, const void *data, uint16_t length) { - printk("%p\n", params); + LOG_DBG("%p", params); if (params == &pacs_instance.sink_pacs_sub) { - printk("Received sink_pacs_sub notification\n"); + LOG_DBG("Received sink_pacs_sub notification"); pacs_instance.notify_received_mask |= BIT(0); } else if (params == &pacs_instance.source_pacs_sub) { - printk("Received source_pacs_sub notification\n"); + LOG_DBG("Received source_pacs_sub notification"); pacs_instance.notify_received_mask |= BIT(1); } else if (params == &pacs_instance.sink_loc_sub) { - printk("Received sink_loc_sub notification\n"); + LOG_DBG("Received sink_loc_sub notification"); pacs_instance.notify_received_mask |= BIT(2); } else if (params == &pacs_instance.source_loc_sub) { - printk("Received source_loc_sub notification\n"); + LOG_DBG("Received source_loc_sub notification"); pacs_instance.notify_received_mask |= BIT(3); } else if (params == &pacs_instance.available_contexts_sub) { - printk("Received available_contexts_sub notification\n"); + LOG_DBG("Received available_contexts_sub notification"); pacs_instance.notify_received_mask |= BIT(4); } else if (params == &pacs_instance.supported_contexts_sub) { - printk("Received supported_contexts_sub notification\n"); + LOG_DBG("Received supported_contexts_sub notification"); pacs_instance.notify_received_mask |= BIT(5); } - printk("pacs_instance.notify_received_mask is %d\n", pacs_instance.notify_received_mask); + LOG_DBG("pacs_instance.notify_received_mask is %d", pacs_instance.notify_received_mask); if (pacs_instance.notify_received_mask == (BIT(0) | BIT(1) | BIT(2) | BIT(3) | BIT(4) | BIT(5))) { @@ -84,13 +87,13 @@ static uint8_t discover_supported_contexts(struct bt_conn *conn, const struct bt int err; if (!attr) { - printk("Discover complete\n"); + LOG_DBG("Discover complete"); (void)memset(params, 0, sizeof(*params)); return BT_GATT_ITER_STOP; } if (!bt_uuid_cmp(params->uuid, BT_UUID_PACS_SUPPORTED_CONTEXT)) { - printk("PACS Supported Contexts Characteristic handle at %d\n", attr->handle); + LOG_DBG("PACS Supported Contexts Characteristic handle at %d", attr->handle); subscribe_params = &pacs_instance.supported_contexts_sub; memcpy(&uuid, BT_UUID_GATT_CCC, sizeof(uuid)); pacs_instance.discover_params.uuid = &uuid.uuid; @@ -100,10 +103,10 @@ static uint8_t discover_supported_contexts(struct bt_conn *conn, const struct bt err = bt_gatt_discover(conn, &pacs_instance.discover_params); if (err) { - printk("Discover failed (err %d)\n", err); + LOG_DBG("Discover failed (err %d)", err); } } else if (!bt_uuid_cmp(params->uuid, BT_UUID_GATT_CCC)) { - printk("CCC handle at %d\n", attr->handle); + LOG_DBG("CCC handle at %d", attr->handle); subscribe_params = &pacs_instance.supported_contexts_sub; subscribe_params->notify = pacs_notify_handler; subscribe_params->value = BT_GATT_CCC_NOTIFY; @@ -111,13 +114,13 @@ static uint8_t discover_supported_contexts(struct bt_conn *conn, const struct bt err = bt_gatt_subscribe(conn, subscribe_params); if (err && err != -EALREADY) { - printk("Subscribe failed (err %d)\n", err); + LOG_DBG("Subscribe failed (err %d)", err); } else { SET_FLAG(flag_supported_contexts_discovered); - printk("[SUBSCRIBED]\n"); + LOG_DBG("[SUBSCRIBED]"); } } else { - printk("Unknown handle at %d\n", attr->handle); + LOG_DBG("Unknown handle at %d", attr->handle); return BT_GATT_ITER_CONTINUE; } @@ -128,7 +131,7 @@ static void discover_and_subscribe_supported_contexts(void) { int err = 0; - printk("%s\n", __func__); + LOG_DBG(""); memcpy(&uuid, BT_UUID_PACS_SUPPORTED_CONTEXT, sizeof(uuid)); pacs_instance.discover_params.uuid = &uuid.uuid; @@ -139,7 +142,7 @@ static void discover_and_subscribe_supported_contexts(void) err = bt_gatt_discover(default_conn, &pacs_instance.discover_params); if (err != 0) { - FAIL("Service Discovery failed (err %d)\n", err); + FAIL("Service Discovery failed (err %d)", err); return; } } @@ -151,13 +154,13 @@ static uint8_t discover_available_contexts(struct bt_conn *conn, const struct bt int err; if (!attr) { - printk("Discover complete\n"); + LOG_DBG("Discover complete"); (void)memset(params, 0, sizeof(*params)); return BT_GATT_ITER_STOP; } if (!bt_uuid_cmp(params->uuid, BT_UUID_PACS_AVAILABLE_CONTEXT)) { - printk("PACS Available Contexts Characteristic handle at %d\n", attr->handle); + LOG_DBG("PACS Available Contexts Characteristic handle at %d", attr->handle); subscribe_params = &pacs_instance.available_contexts_sub; memcpy(&uuid, BT_UUID_GATT_CCC, sizeof(uuid)); pacs_instance.discover_params.uuid = &uuid.uuid; @@ -167,10 +170,10 @@ static uint8_t discover_available_contexts(struct bt_conn *conn, const struct bt err = bt_gatt_discover(conn, &pacs_instance.discover_params); if (err) { - printk("Discover failed (err %d)\n", err); + LOG_DBG("Discover failed (err %d)", err); } } else if (!bt_uuid_cmp(params->uuid, BT_UUID_GATT_CCC)) { - printk("CCC handle at %d\n", attr->handle); + LOG_DBG("CCC handle at %d", attr->handle); subscribe_params = &pacs_instance.available_contexts_sub; subscribe_params->notify = pacs_notify_handler; subscribe_params->value = BT_GATT_CCC_NOTIFY; @@ -178,13 +181,13 @@ static uint8_t discover_available_contexts(struct bt_conn *conn, const struct bt err = bt_gatt_subscribe(conn, subscribe_params); if (err && err != -EALREADY) { - printk("Subscribe failed (err %d)\n", err); + LOG_DBG("Subscribe failed (err %d)", err); } else { SET_FLAG(flag_available_contexts_discovered); - printk("[SUBSCRIBED]\n"); + LOG_DBG("[SUBSCRIBED]"); } } else { - printk("Unknown handle at %d\n", attr->handle); + LOG_DBG("Unknown handle at %d", attr->handle); return BT_GATT_ITER_CONTINUE; } @@ -195,7 +198,7 @@ static void discover_and_subscribe_available_contexts(void) { int err = 0; - printk("%s\n", __func__); + LOG_DBG(""); memcpy(&uuid, BT_UUID_PACS_AVAILABLE_CONTEXT, sizeof(uuid)); pacs_instance.discover_params.uuid = &uuid.uuid; @@ -206,7 +209,7 @@ static void discover_and_subscribe_available_contexts(void) err = bt_gatt_discover(default_conn, &pacs_instance.discover_params); if (err != 0) { - FAIL("Service Discovery failed (err %d)\n", err); + FAIL("Service Discovery failed (err %d)", err); return; } } @@ -218,13 +221,13 @@ static uint8_t discover_src_loc(struct bt_conn *conn, const struct bt_gatt_attr int err; if (!attr) { - printk("Discover complete\n"); + LOG_DBG("Discover complete"); (void)memset(params, 0, sizeof(*params)); return BT_GATT_ITER_STOP; } if (!bt_uuid_cmp(params->uuid, BT_UUID_PACS_SRC_LOC)) { - printk("PACS Source Location Characteristic handle at %d\n", attr->handle); + LOG_DBG("PACS Source Location Characteristic handle at %d", attr->handle); subscribe_params = &pacs_instance.source_loc_sub; memcpy(&uuid, BT_UUID_GATT_CCC, sizeof(uuid)); pacs_instance.discover_params.uuid = &uuid.uuid; @@ -234,10 +237,10 @@ static uint8_t discover_src_loc(struct bt_conn *conn, const struct bt_gatt_attr err = bt_gatt_discover(conn, &pacs_instance.discover_params); if (err) { - printk("Discover failed (err %d)\n", err); + LOG_DBG("Discover failed (err %d)", err); } } else if (!bt_uuid_cmp(params->uuid, BT_UUID_GATT_CCC)) { - printk("CCC handle at %d\n", attr->handle); + LOG_DBG("CCC handle at %d", attr->handle); subscribe_params = &pacs_instance.source_loc_sub; subscribe_params->notify = pacs_notify_handler; subscribe_params->value = BT_GATT_CCC_NOTIFY; @@ -245,13 +248,13 @@ static uint8_t discover_src_loc(struct bt_conn *conn, const struct bt_gatt_attr err = bt_gatt_subscribe(conn, subscribe_params); if (err && err != -EALREADY) { - printk("Subscribe failed (err %d)\n", err); + LOG_DBG("Subscribe failed (err %d)", err); } else { SET_FLAG(flag_src_loc_discovered); - printk("[SUBSCRIBED]\n"); + LOG_DBG("[SUBSCRIBED]"); } } else { - printk("Unknown handle at %d\n", attr->handle); + LOG_DBG("Unknown handle at %d", attr->handle); return BT_GATT_ITER_CONTINUE; } @@ -262,7 +265,7 @@ static void discover_and_subscribe_src_loc(void) { int err = 0; - printk("%s\n", __func__); + LOG_DBG(""); memcpy(&uuid, BT_UUID_PACS_SRC_LOC, sizeof(uuid)); pacs_instance.discover_params.uuid = &uuid.uuid; @@ -273,7 +276,7 @@ static void discover_and_subscribe_src_loc(void) err = bt_gatt_discover(default_conn, &pacs_instance.discover_params); if (err != 0) { - FAIL("Service Discovery failed (err %d)\n", err); + FAIL("Service Discovery failed (err %d)", err); return; } } @@ -285,13 +288,13 @@ static uint8_t discover_snk_loc(struct bt_conn *conn, const struct bt_gatt_attr int err; if (!attr) { - printk("Discover complete\n"); + LOG_DBG("Discover complete"); (void)memset(params, 0, sizeof(*params)); return BT_GATT_ITER_STOP; } if (!bt_uuid_cmp(params->uuid, BT_UUID_PACS_SNK_LOC)) { - printk("PACS Sink Location Characteristic handle at %d\n", attr->handle); + LOG_DBG("PACS Sink Location Characteristic handle at %d", attr->handle); subscribe_params = &pacs_instance.sink_loc_sub; memcpy(&uuid, BT_UUID_GATT_CCC, sizeof(uuid)); pacs_instance.discover_params.uuid = &uuid.uuid; @@ -301,10 +304,10 @@ static uint8_t discover_snk_loc(struct bt_conn *conn, const struct bt_gatt_attr err = bt_gatt_discover(conn, &pacs_instance.discover_params); if (err) { - printk("Discover failed (err %d)\n", err); + LOG_DBG("Discover failed (err %d)", err); } } else if (!bt_uuid_cmp(params->uuid, BT_UUID_GATT_CCC)) { - printk("CCC handle at %d\n", attr->handle); + LOG_DBG("CCC handle at %d", attr->handle); subscribe_params = &pacs_instance.sink_loc_sub; subscribe_params->notify = pacs_notify_handler; subscribe_params->value = BT_GATT_CCC_NOTIFY; @@ -312,13 +315,13 @@ static uint8_t discover_snk_loc(struct bt_conn *conn, const struct bt_gatt_attr err = bt_gatt_subscribe(conn, subscribe_params); if (err && err != -EALREADY) { - printk("Subscribe failed (err %d)\n", err); + LOG_DBG("Subscribe failed (err %d)", err); } else { SET_FLAG(flag_snk_loc_discovered); - printk("[SUBSCRIBED]\n"); + LOG_DBG("[SUBSCRIBED]"); } } else { - printk("Unknown handle at %d\n", attr->handle); + LOG_DBG("Unknown handle at %d", attr->handle); return BT_GATT_ITER_CONTINUE; } @@ -329,7 +332,7 @@ static void discover_and_subscribe_snk_loc(void) { int err = 0; - printk("%s\n", __func__); + LOG_DBG(""); memcpy(&uuid, BT_UUID_PACS_SNK_LOC, sizeof(uuid)); pacs_instance.discover_params.uuid = &uuid.uuid; @@ -340,7 +343,7 @@ static void discover_and_subscribe_snk_loc(void) err = bt_gatt_discover(default_conn, &pacs_instance.discover_params); if (err != 0) { - FAIL("Service Discovery failed (err %d)\n", err); + FAIL("Service Discovery failed (err %d)", err); return; } } @@ -352,13 +355,13 @@ static uint8_t discover_pacs_src(struct bt_conn *conn, const struct bt_gatt_attr int err; if (!attr) { - printk("Discover complete\n"); + LOG_DBG("Discover complete"); (void)memset(params, 0, sizeof(*params)); return BT_GATT_ITER_STOP; } if (!bt_uuid_cmp(params->uuid, BT_UUID_PACS_SRC)) { - printk("PACS Source Characteristic handle at %d\n", attr->handle); + LOG_DBG("PACS Source Characteristic handle at %d", attr->handle); subscribe_params = &pacs_instance.source_pacs_sub; memcpy(&uuid, BT_UUID_GATT_CCC, sizeof(uuid)); pacs_instance.discover_params.uuid = &uuid.uuid; @@ -368,10 +371,10 @@ static uint8_t discover_pacs_src(struct bt_conn *conn, const struct bt_gatt_attr err = bt_gatt_discover(conn, &pacs_instance.discover_params); if (err) { - printk("Discover failed (err %d)\n", err); + LOG_DBG("Discover failed (err %d)", err); } } else if (!bt_uuid_cmp(params->uuid, BT_UUID_GATT_CCC)) { - printk("CCC handle at %d\n", attr->handle); + LOG_DBG("CCC handle at %d", attr->handle); subscribe_params = &pacs_instance.source_pacs_sub; subscribe_params->notify = pacs_notify_handler; subscribe_params->value = BT_GATT_CCC_NOTIFY; @@ -379,13 +382,13 @@ static uint8_t discover_pacs_src(struct bt_conn *conn, const struct bt_gatt_attr err = bt_gatt_subscribe(conn, subscribe_params); if (err && err != -EALREADY) { - printk("Subscribe failed (err %d)\n", err); + LOG_DBG("Subscribe failed (err %d)", err); } else { SET_FLAG(flag_pacs_src_discovered); - printk("[SUBSCRIBED]\n"); + LOG_DBG("[SUBSCRIBED]"); } } else { - printk("Unknown handle at %d\n", attr->handle); + LOG_DBG("Unknown handle at %d", attr->handle); return BT_GATT_ITER_CONTINUE; } @@ -396,7 +399,7 @@ static void discover_and_subscribe_src_pacs(void) { int err = 0; - printk("%s\n", __func__); + LOG_DBG(""); memcpy(&uuid, BT_UUID_PACS_SRC, sizeof(uuid)); pacs_instance.discover_params.uuid = &uuid.uuid; @@ -407,7 +410,7 @@ static void discover_and_subscribe_src_pacs(void) err = bt_gatt_discover(default_conn, &pacs_instance.discover_params); if (err != 0) { - FAIL("Service Discovery failed (err %d)\n", err); + FAIL("Service Discovery failed (err %d)", err); return; } } @@ -419,13 +422,13 @@ static uint8_t discover_pacs_snk(struct bt_conn *conn, const struct bt_gatt_attr int err; if (!attr) { - printk("Discover complete\n"); + LOG_DBG("Discover complete"); (void)memset(params, 0, sizeof(*params)); return BT_GATT_ITER_STOP; } if (!bt_uuid_cmp(params->uuid, BT_UUID_PACS_SNK)) { - printk("PACS Sink Characteristic handle at %d\n", attr->handle); + LOG_DBG("PACS Sink Characteristic handle at %d", attr->handle); subscribe_params = &pacs_instance.sink_pacs_sub; memcpy(&uuid, BT_UUID_GATT_CCC, sizeof(uuid)); pacs_instance.discover_params.uuid = &uuid.uuid; @@ -435,10 +438,10 @@ static uint8_t discover_pacs_snk(struct bt_conn *conn, const struct bt_gatt_attr err = bt_gatt_discover(conn, &pacs_instance.discover_params); if (err) { - printk("Discover failed (err %d)\n", err); + LOG_DBG("Discover failed (err %d)", err); } } else if (!bt_uuid_cmp(params->uuid, BT_UUID_GATT_CCC)) { - printk("CCC handle at %d\n", attr->handle); + LOG_DBG("CCC handle at %d", attr->handle); subscribe_params = &pacs_instance.sink_pacs_sub; subscribe_params->notify = pacs_notify_handler; subscribe_params->value = BT_GATT_CCC_NOTIFY; @@ -446,13 +449,13 @@ static uint8_t discover_pacs_snk(struct bt_conn *conn, const struct bt_gatt_attr err = bt_gatt_subscribe(conn, subscribe_params); if (err && err != -EALREADY) { - printk("Subscribe failed (err %d)\n", err); + LOG_DBG("Subscribe failed (err %d)", err); } else { SET_FLAG(flag_pacs_snk_discovered); - printk("[SUBSCRIBED]\n"); + LOG_DBG("[SUBSCRIBED]"); } } else { - printk("Unknown handle at %d\n", attr->handle); + LOG_DBG("Unknown handle at %d", attr->handle); return BT_GATT_ITER_CONTINUE; } @@ -463,7 +466,7 @@ static void discover_and_subscribe_snk_pacs(void) { int err = 0; - printk("%s\n", __func__); + LOG_DBG(""); memcpy(&uuid, BT_UUID_PACS_SNK, sizeof(uuid)); pacs_instance.discover_params.uuid = &uuid.uuid; @@ -474,7 +477,7 @@ static void discover_and_subscribe_snk_pacs(void) err = bt_gatt_discover(default_conn, &pacs_instance.discover_params); if (err != 0) { - FAIL("Service Discovery failed (err %d)\n", err); + FAIL("Service Discovery failed (err %d)", err); return; } } @@ -483,32 +486,32 @@ static void test_main(void) { int err; - printk("Enabling Bluetooth\n"); + LOG_DBG("Enabling Bluetooth"); err = bt_enable(NULL); if (err != 0) { - FAIL("Bluetooth enable failed (err %d)\n", err); + FAIL("Bluetooth enable failed (err %d)", err); return; } bt_le_scan_cb_register(&common_scan_cb); - printk("Starting scan\n"); + LOG_DBG("Starting scan"); err = bt_le_scan_start(BT_LE_SCAN_PASSIVE, NULL); if (err != 0) { - FAIL("Could not start scanning (err %d)\n", err); + FAIL("Could not start scanning (err %d)", err); return; } WAIT_FOR_FLAG(flag_connected); - printk("Raising security\n"); + LOG_DBG("Raising security"); err = bt_conn_set_security(default_conn, BT_SECURITY_L2); if (err) { - FAIL("Failed to ser security level %d (err %d)\n", BT_SECURITY_L2, err); + FAIL("Failed to ser security level %d (err %d)", BT_SECURITY_L2, err); return; } - printk("Starting Discovery\n"); + LOG_DBG("Starting Discovery"); discover_and_subscribe_snk_pacs(); WAIT_FOR_FLAG(flag_pacs_snk_discovered); @@ -528,7 +531,7 @@ static void test_main(void) discover_and_subscribe_supported_contexts(); WAIT_FOR_FLAG(flag_supported_contexts_discovered); - printk("Waiting for all notifications to be received\n"); + LOG_DBG("Waiting for all notifications to be received"); WAIT_FOR_FLAG(flag_all_notifications_received); @@ -537,23 +540,23 @@ static void test_main(void) bt_conn_disconnect(default_conn, BT_HCI_ERR_REMOTE_USER_TERM_CONN); WAIT_FOR_UNSET_FLAG(flag_connected); - printk("Starting scan\n"); + LOG_DBG("Starting scan"); err = bt_le_scan_start(BT_LE_SCAN_PASSIVE, NULL); if (err != 0) { - FAIL("Could not start scanning (err %d)\n", err); + FAIL("Could not start scanning (err %d)", err); return; } WAIT_FOR_FLAG(flag_connected); - printk("Raising security\n"); + LOG_DBG("Raising security"); err = bt_conn_set_security(default_conn, BT_SECURITY_L2); if (err) { - FAIL("Failed to ser security level %d (err %d)\n", BT_SECURITY_L2, err); + FAIL("Failed to ser security level %d (err %d)", BT_SECURITY_L2, err); return; } - printk("Waiting for all notifications to be received\n"); + LOG_DBG("Waiting for all notifications to be received"); WAIT_FOR_FLAG(flag_all_notifications_received); bt_conn_disconnect(default_conn, BT_HCI_ERR_REMOTE_USER_TERM_CONN); diff --git a/tests/bsim/bluetooth/audio/src/pacs_notify_server_test.c b/tests/bsim/bluetooth/audio/src/pacs_notify_server_test.c index 9339b83cafb..86f116fb786 100644 --- a/tests/bsim/bluetooth/audio/src/pacs_notify_server_test.c +++ b/tests/bsim/bluetooth/audio/src/pacs_notify_server_test.c @@ -8,6 +8,9 @@ #include "common.h" +#include +LOG_MODULE_REGISTER(pacs_notify_server_test, LOG_LEVEL_DBG); + extern enum bst_result_t bst_result; static struct bt_audio_codec_cap lc3_codec_1 = @@ -34,7 +37,7 @@ static bool is_peer_subscribed(struct bt_conn *conn) attr = bt_gatt_find_by_uuid(NULL, 0, BT_UUID_PACS_SNK); if (!attr) { - printk("No BT_UUID_PACS_SNK attribute found\n"); + LOG_DBG("No BT_UUID_PACS_SNK attribute found"); } if (bt_gatt_is_subscribed(conn, attr, BT_GATT_CCC_NOTIFY)) { nbr_subscribed++; @@ -42,7 +45,7 @@ static bool is_peer_subscribed(struct bt_conn *conn) attr = bt_gatt_find_by_uuid(NULL, 0, BT_UUID_PACS_SNK_LOC); if (!attr) { - printk("No BT_UUID_PACS_SNK_LOC attribute found\n"); + LOG_DBG("No BT_UUID_PACS_SNK_LOC attribute found"); } if (bt_gatt_is_subscribed(conn, attr, BT_GATT_CCC_NOTIFY)) { nbr_subscribed++; @@ -50,7 +53,7 @@ static bool is_peer_subscribed(struct bt_conn *conn) attr = bt_gatt_find_by_uuid(NULL, 0, BT_UUID_PACS_SRC); if (!attr) { - printk("No BT_UUID_PACS_SRC attribute found\n"); + LOG_DBG("No BT_UUID_PACS_SRC attribute found"); } if (bt_gatt_is_subscribed(conn, attr, BT_GATT_CCC_NOTIFY)) { nbr_subscribed++; @@ -58,7 +61,7 @@ static bool is_peer_subscribed(struct bt_conn *conn) attr = bt_gatt_find_by_uuid(NULL, 0, BT_UUID_PACS_SRC_LOC); if (!attr) { - printk("No BT_UUID_PACS_SRC_LOC attribute found\n"); + LOG_DBG("No BT_UUID_PACS_SRC_LOC attribute found"); } if (bt_gatt_is_subscribed(conn, attr, BT_GATT_CCC_NOTIFY)) { nbr_subscribed++; @@ -66,7 +69,7 @@ static bool is_peer_subscribed(struct bt_conn *conn) attr = bt_gatt_find_by_uuid(NULL, 0, BT_UUID_PACS_AVAILABLE_CONTEXT); if (!attr) { - printk("No BT_UUID_PACS_AVAILABLE_CONTEXT attribute found\n"); + LOG_DBG("No BT_UUID_PACS_AVAILABLE_CONTEXT attribute found"); } if (bt_gatt_is_subscribed(conn, attr, BT_GATT_CCC_NOTIFY)) { nbr_subscribed++; @@ -74,7 +77,7 @@ static bool is_peer_subscribed(struct bt_conn *conn) attr = bt_gatt_find_by_uuid(NULL, 0, BT_UUID_PACS_SUPPORTED_CONTEXT); if (!attr) { - printk("No BT_UUID_PACS_SUPPORTED_CONTEXT attribute found\n"); + LOG_DBG("No BT_UUID_PACS_SUPPORTED_CONTEXT attribute found"); } if (bt_gatt_is_subscribed(conn, attr, BT_GATT_CCC_NOTIFY)) { nbr_subscribed++; @@ -97,7 +100,7 @@ static void trigger_notifications(void) enum bt_audio_location snk_loc; enum bt_audio_location src_loc; - printk("Triggering Notifications\n"); + LOG_DBG("Triggering Notifications"); if (i) { caps = &caps_1; @@ -111,27 +114,27 @@ static void trigger_notifications(void) i++; } - printk("Changing Sink PACs\n"); + LOG_DBG("Changing Sink PACs"); bt_pacs_cap_register(BT_AUDIO_DIR_SINK, caps); bt_pacs_cap_register(BT_AUDIO_DIR_SOURCE, caps); - printk("Changing Sink Location\n"); + LOG_DBG("Changing Sink Location"); err = bt_pacs_set_location(BT_AUDIO_DIR_SINK, snk_loc); if (err != 0) { - printk("Failed to set device sink location\n"); + LOG_DBG("Failed to set device sink location"); } - printk("Changing Source Location\n"); + LOG_DBG("Changing Source Location"); err = bt_pacs_set_location(BT_AUDIO_DIR_SOURCE, src_loc); if (err != 0) { - printk("Failed to set device source location\n"); + LOG_DBG("Failed to set device source location"); } - printk("Changing Supported Contexts Location\n"); + LOG_DBG("Changing Supported Contexts Location"); supported = supported ^ BT_AUDIO_CONTEXT_TYPE_MEDIA; bt_pacs_set_supported_contexts(BT_AUDIO_DIR_SINK, supported); - printk("Changing Available Contexts\n"); + LOG_DBG("Changing Available Contexts"); available = available ^ BT_AUDIO_CONTEXT_TYPE_MEDIA; bt_pacs_set_available_contexts(BT_AUDIO_DIR_SINK, available); } @@ -143,10 +146,10 @@ static void test_main(void) BT_DATA_BYTES(BT_DATA_FLAGS, (BT_LE_AD_GENERAL | BT_LE_AD_NO_BREDR)), }; - printk("Enabling Bluetooth\n"); + LOG_DBG("Enabling Bluetooth"); err = bt_enable(NULL); if (err != 0) { - FAIL("Bluetooth enable failed (err %d)\n", err); + FAIL("Bluetooth enable failed (err %d)", err); return; } @@ -155,59 +158,59 @@ static void test_main(void) bt_pacs_set_available_contexts(BT_AUDIO_DIR_SINK, BT_AUDIO_CONTEXT_TYPE_ANY); bt_pacs_set_available_contexts(BT_AUDIO_DIR_SOURCE, BT_AUDIO_CONTEXT_TYPE_ANY); - printk("Registereding PACS\n"); + LOG_DBG("Registereding PACS"); bt_pacs_cap_register(BT_AUDIO_DIR_SINK, &caps_1); bt_pacs_cap_register(BT_AUDIO_DIR_SOURCE, &caps_1); err = bt_pacs_set_location(BT_AUDIO_DIR_SINK, BT_AUDIO_LOCATION_FRONT_LEFT); if (err != 0) { - printk("Failed to set device sink location\n"); + LOG_DBG("Failed to set device sink location"); return; } err = bt_pacs_set_location(BT_AUDIO_DIR_SOURCE, BT_AUDIO_LOCATION_FRONT_RIGHT); if (err != 0) { - printk("Failed to set device source location\n"); + LOG_DBG("Failed to set device source location"); return; } - printk("Start Advertising\n"); + LOG_DBG("Start Advertising"); err = bt_le_adv_start(BT_LE_ADV_CONN_NAME, ad, ARRAY_SIZE(ad), NULL, 0); if (err != 0) { - FAIL("Advertising failed to start (err %d)\n", err); + FAIL("Advertising failed to start (err %d)", err); return; } - printk("Waiting to be connected\n"); + LOG_DBG("Waiting to be connected"); WAIT_FOR_FLAG(flag_connected); - printk("Connected\n"); - printk("Waiting to be subscribed\n"); + LOG_DBG("Connected"); + LOG_DBG("Waiting to be subscribed"); while (!is_peer_subscribed(default_conn)) { (void)k_sleep(K_MSEC(10)); } - printk("Subscribed\n"); + LOG_DBG("Subscribed"); trigger_notifications(); /* Now wait for client to disconnect, then stop adv so it does not reconnect */ - printk("Wait for client disconnect\n"); + LOG_DBG("Wait for client disconnect"); WAIT_FOR_UNSET_FLAG(flag_connected); - printk("Client disconnected\n"); + LOG_DBG("Client disconnected"); err = bt_le_adv_stop(); if (err != 0) { - FAIL("Advertising failed to stop (err %d)\n", err); + FAIL("Advertising failed to stop (err %d)", err); return; } /* Trigger changes while device is disconnected */ trigger_notifications(); - printk("Start Advertising\n"); + LOG_DBG("Start Advertising"); err = bt_le_adv_start(BT_LE_ADV_CONN_NAME, ad, ARRAY_SIZE(ad), NULL, 0); if (err != 0) { - FAIL("Advertising failed to start (err %d)\n", err); + FAIL("Advertising failed to start (err %d)", err); return; } From 6e856f1038e810e8f64637df879e505c25465865 Mon Sep 17 00:00:00 2001 From: Mariusz Skamra Date: Mon, 4 Dec 2023 09:56:47 +0100 Subject: [PATCH 0835/3723] tests: bsim: pacs: Test bt_pacs_{set, get}_available_contexts_for_conn This extends existing PACS BSIM tests with the new API function calls. Signed-off-by: Mariusz Skamra --- tests/bsim/bluetooth/audio/prj.conf | 1 + .../audio/src/pacs_notify_client_test.c | 56 ++++++++++++++++- .../audio/src/pacs_notify_server_test.c | 61 ++++++++++++++++++- 3 files changed, 115 insertions(+), 3 deletions(-) diff --git a/tests/bsim/bluetooth/audio/prj.conf b/tests/bsim/bluetooth/audio/prj.conf index 8f387c8016f..9d11e1c3dae 100644 --- a/tests/bsim/bluetooth/audio/prj.conf +++ b/tests/bsim/bluetooth/audio/prj.conf @@ -143,6 +143,7 @@ CONFIG_BT_PAC_SNK_NOTIFIABLE=y CONFIG_BT_PAC_SNK_LOC_WRITEABLE=y CONFIG_BT_PAC_SRC_LOC_WRITEABLE=y CONFIG_BT_GATT_AUTO_DISCOVER_CCC=y +CONFIG_BT_GATT_AUTO_RESUBSCRIBE=n # DEBUGGING CONFIG_LOG=y diff --git a/tests/bsim/bluetooth/audio/src/pacs_notify_client_test.c b/tests/bsim/bluetooth/audio/src/pacs_notify_client_test.c index 448c0da23f5..7068da7f06a 100644 --- a/tests/bsim/bluetooth/audio/src/pacs_notify_client_test.c +++ b/tests/bsim/bluetooth/audio/src/pacs_notify_client_test.c @@ -38,6 +38,7 @@ CREATE_FLAG(flag_src_loc_discovered); CREATE_FLAG(flag_available_contexts_discovered); CREATE_FLAG(flag_supported_contexts_discovered); CREATE_FLAG(flag_all_notifications_received); +CREATE_FLAG(flag_available_contexts_received); static struct bt_uuid_16 uuid = BT_UUID_INIT_16(0); @@ -64,6 +65,7 @@ static uint8_t pacs_notify_handler(struct bt_conn *conn, } else if (params == &pacs_instance.available_contexts_sub) { LOG_DBG("Received available_contexts_sub notification"); pacs_instance.notify_received_mask |= BIT(4); + SET_FLAG(flag_available_contexts_received); } else if (params == &pacs_instance.supported_contexts_sub) { LOG_DBG("Received supported_contexts_sub notification"); pacs_instance.notify_received_mask |= BIT(5); @@ -537,7 +539,8 @@ static void test_main(void) /* Disconnect and wait for server to advertise again (after notifications are triggered) */ UNSET_FLAG(flag_all_notifications_received); - bt_conn_disconnect(default_conn, BT_HCI_ERR_REMOTE_USER_TERM_CONN); + err = bt_conn_disconnect(default_conn, BT_HCI_ERR_REMOTE_USER_TERM_CONN); + __ASSERT_NO_MSG(err == 0); WAIT_FOR_UNSET_FLAG(flag_connected); LOG_DBG("Starting scan"); @@ -559,7 +562,56 @@ static void test_main(void) LOG_DBG("Waiting for all notifications to be received"); WAIT_FOR_FLAG(flag_all_notifications_received); - bt_conn_disconnect(default_conn, BT_HCI_ERR_REMOTE_USER_TERM_CONN); + err = bt_conn_disconnect(default_conn, BT_HCI_ERR_REMOTE_USER_TERM_CONN); + __ASSERT_NO_MSG(err == 0); + WAIT_FOR_UNSET_FLAG(flag_connected); + UNSET_FLAG(flag_available_contexts_received); + + LOG_DBG("Starting scan"); + err = bt_le_scan_start(BT_LE_SCAN_PASSIVE, NULL); + if (err != 0) { + FAIL("Could not start scanning (err %d)", err); + return; + } + + WAIT_FOR_FLAG(flag_connected); + + LOG_DBG("Raising security"); + err = bt_conn_set_security(default_conn, BT_SECURITY_L2); + if (err) { + FAIL("Failed to ser security level %d (err %d)", BT_SECURITY_L2, err); + return; + } + + LOG_DBG("Waiting for available contexts notification to be received"); + WAIT_FOR_FLAG(flag_available_contexts_received); + + err = bt_conn_disconnect(default_conn, BT_HCI_ERR_REMOTE_USER_TERM_CONN); + __ASSERT_NO_MSG(err == 0); + WAIT_FOR_UNSET_FLAG(flag_connected); + UNSET_FLAG(flag_available_contexts_received); + + LOG_DBG("Starting scan"); + err = bt_le_scan_start(BT_LE_SCAN_PASSIVE, NULL); + if (err != 0) { + FAIL("Could not start scanning (err %d)", err); + return; + } + + WAIT_FOR_FLAG(flag_connected); + + LOG_DBG("Raising security"); + err = bt_conn_set_security(default_conn, BT_SECURITY_L2); + if (err) { + FAIL("Failed to ser security level %d (err %d)", BT_SECURITY_L2, err); + return; + } + + LOG_DBG("Waiting for available contexts notification to be received"); + WAIT_FOR_FLAG(flag_available_contexts_received); + + err = bt_conn_disconnect(default_conn, BT_HCI_ERR_REMOTE_USER_TERM_CONN); + __ASSERT_NO_MSG(err == 0); WAIT_FOR_UNSET_FLAG(flag_connected); PASS("GATT client Passed\n"); diff --git a/tests/bsim/bluetooth/audio/src/pacs_notify_server_test.c b/tests/bsim/bluetooth/audio/src/pacs_notify_server_test.c index 86f116fb786..d5ab1d91590 100644 --- a/tests/bsim/bluetooth/audio/src/pacs_notify_server_test.c +++ b/tests/bsim/bluetooth/audio/src/pacs_notify_server_test.c @@ -142,6 +142,7 @@ static void trigger_notifications(void) static void test_main(void) { int err; + enum bt_audio_context available, available_for_conn; const struct bt_data ad[] = { BT_DATA_BYTES(BT_DATA_FLAGS, (BT_LE_AD_GENERAL | BT_LE_AD_NO_BREDR)), }; @@ -191,6 +192,7 @@ static void test_main(void) } LOG_DBG("Subscribed"); + LOG_INF("Trigger changes while device is connected"); trigger_notifications(); /* Now wait for client to disconnect, then stop adv so it does not reconnect */ @@ -204,7 +206,7 @@ static void test_main(void) return; } - /* Trigger changes while device is disconnected */ + LOG_INF("Trigger changes while device is disconnected"); trigger_notifications(); LOG_DBG("Start Advertising"); @@ -216,6 +218,63 @@ static void test_main(void) WAIT_FOR_FLAG(flag_connected); WAIT_FOR_UNSET_FLAG(flag_connected); + LOG_DBG("Client disconnected"); + + err = bt_le_adv_stop(); + if (err != 0) { + FAIL("Advertising failed to stop (err %d)", err); + return; + } + + LOG_DBG("Start Advertising"); + err = bt_le_adv_start(BT_LE_ADV_CONN_NAME, ad, ARRAY_SIZE(ad), NULL, 0); + if (err != 0) { + FAIL("Advertising failed to start (err %d)", err); + return; + } + + WAIT_FOR_FLAG(flag_connected); + LOG_DBG("Connected"); + + available = bt_pacs_get_available_contexts(BT_AUDIO_DIR_SINK); + __ASSERT_NO_MSG(bt_pacs_get_available_contexts_for_conn(default_conn, BT_AUDIO_DIR_SINK) == + available); + + available_for_conn = BT_AUDIO_CONTEXT_TYPE_UNSPECIFIED; + + LOG_INF("Override available contexts"); + err = bt_pacs_conn_set_available_contexts_for_conn(default_conn, BT_AUDIO_DIR_SINK, + &available_for_conn); + __ASSERT_NO_MSG(err == 0); + + __ASSERT_NO_MSG(bt_pacs_get_available_contexts(BT_AUDIO_DIR_SINK) == available); + __ASSERT_NO_MSG(bt_pacs_get_available_contexts_for_conn(default_conn, BT_AUDIO_DIR_SINK) == + available_for_conn); + + WAIT_FOR_UNSET_FLAG(flag_connected); + LOG_DBG("Client disconnected"); + + err = bt_le_adv_stop(); + if (err != 0) { + FAIL("Advertising failed to stop (err %d)", err); + return; + } + + LOG_DBG("Start Advertising"); + err = bt_le_adv_start(BT_LE_ADV_CONN_NAME, ad, ARRAY_SIZE(ad), NULL, 0); + if (err != 0) { + FAIL("Advertising failed to start (err %d)", err); + return; + } + + WAIT_FOR_FLAG(flag_connected); + LOG_DBG("Connected"); + + __ASSERT_NO_MSG(bt_pacs_get_available_contexts(BT_AUDIO_DIR_SINK) == available); + __ASSERT_NO_MSG(bt_pacs_get_available_contexts_for_conn(default_conn, BT_AUDIO_DIR_SINK) == + available); + + WAIT_FOR_UNSET_FLAG(flag_connected); PASS("PACS Notify Server passed\n"); } From 3e52c87323cb28882df01f9d4a897cfbd98d1509 Mon Sep 17 00:00:00 2001 From: Mariusz Skamra Date: Tue, 5 Dec 2023 16:26:14 +0100 Subject: [PATCH 0836/3723] Bluetooth: pacs: Fix missing return values in doxygen This fixes missing return values description in doxygen documentation. Signed-off-by: Mariusz Skamra --- include/zephyr/bluetooth/audio/pacs.h | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/include/zephyr/bluetooth/audio/pacs.h b/include/zephyr/bluetooth/audio/pacs.h index 828851ff9dd..6e0dcec4514 100644 --- a/include/zephyr/bluetooth/audio/pacs.h +++ b/include/zephyr/bluetooth/audio/pacs.h @@ -76,6 +76,7 @@ int bt_pacs_cap_unregister(enum bt_audio_dir dir, struct bt_pacs_cap *cap); * @param dir Direction of the endpoints to change location for. * @param location The location to be set. * + * @return 0 in case of success or negative value in case of error. */ int bt_pacs_set_location(enum bt_audio_dir dir, enum bt_audio_location location); @@ -84,6 +85,8 @@ int bt_pacs_set_location(enum bt_audio_dir dir, * * @param dir Direction of the endpoints to change available contexts for. * @param contexts The contexts to be set. + * + * @return 0 in case of success or negative value in case of error. */ int bt_pacs_set_available_contexts(enum bt_audio_dir dir, enum bt_audio_context contexts); @@ -131,6 +134,8 @@ enum bt_audio_context bt_pacs_get_available_contexts_for_conn(struct bt_conn *co * * @param dir Direction of the endpoints to change available contexts for. * @param contexts The contexts to be set. + * + * @return 0 in case of success or negative value in case of error. */ int bt_pacs_set_supported_contexts(enum bt_audio_dir dir, enum bt_audio_context contexts); From 98bc5450f8b763566518117c18b50c7d97863225 Mon Sep 17 00:00:00 2001 From: Conor Paxton Date: Thu, 30 Nov 2023 21:00:34 +0000 Subject: [PATCH 0837/3723] boards: mpfs_icicle: remove unused overlay In an effort to clean up, remove the unused overlay Signed-off-by: Conor Paxton --- boards/riscv/mpfs_icicle/mpfs_icicle_ddr.overlay | 11 ----------- 1 file changed, 11 deletions(-) delete mode 100644 boards/riscv/mpfs_icicle/mpfs_icicle_ddr.overlay diff --git a/boards/riscv/mpfs_icicle/mpfs_icicle_ddr.overlay b/boards/riscv/mpfs_icicle/mpfs_icicle_ddr.overlay deleted file mode 100644 index 15c38d914c7..00000000000 --- a/boards/riscv/mpfs_icicle/mpfs_icicle_ddr.overlay +++ /dev/null @@ -1,11 +0,0 @@ -/* - * Copyright (c) 2020-2021 Microchip Technology Inc - * - * SPDX-License-Identifier: Apache-2.0 - */ - -/ { - chosen { - zephyr,sram = &sram1; - }; -}; From 0ff8a7c03df205d81ce95d75bbeba65acbd4d834 Mon Sep 17 00:00:00 2001 From: Conor Paxton Date: Thu, 30 Nov 2023 21:08:07 +0000 Subject: [PATCH 0838/3723] boards: mpfs_icicle: remove unused CMakeLists THe CmakeLists file is not neing used to do anything out of the norm. remove it and add it back in at a later date, if required Signed-off-by: Conor Paxton --- boards/riscv/mpfs_icicle/CMakeLists.txt | 2 -- 1 file changed, 2 deletions(-) delete mode 100644 boards/riscv/mpfs_icicle/CMakeLists.txt diff --git a/boards/riscv/mpfs_icicle/CMakeLists.txt b/boards/riscv/mpfs_icicle/CMakeLists.txt deleted file mode 100644 index ef5e0226694..00000000000 --- a/boards/riscv/mpfs_icicle/CMakeLists.txt +++ /dev/null @@ -1,2 +0,0 @@ -# SPDX-License-Identifier: Apache-2.0 -zephyr_library_include_directories(${ZEPHYR_BASE}/drivers) From 3c7f10f8e1174ce03f7ccc6568ba7c1c342791ae Mon Sep 17 00:00:00 2001 From: Conor Paxton Date: Thu, 30 Nov 2023 21:25:05 +0000 Subject: [PATCH 0839/3723] dts: riscv: rename PolarFire SoC using device family name Microchip's PolarFire SoC (device family name: MPFS) is not specific to the Icicle Kit. Rename the devicetree sources to be more generic and to align with Linux and allow for other development boards to adopt. Signed-off-by: Conor Paxton --- boards/riscv/mpfs_icicle/mpfs_icicle.dts | 2 +- dts/riscv/microchip/{mpfs-icicle.dtsi => mpfs.dtsi} | 0 2 files changed, 1 insertion(+), 1 deletion(-) rename dts/riscv/microchip/{mpfs-icicle.dtsi => mpfs.dtsi} (100%) diff --git a/boards/riscv/mpfs_icicle/mpfs_icicle.dts b/boards/riscv/mpfs_icicle/mpfs_icicle.dts index 774a5533233..6faaca8d590 100644 --- a/boards/riscv/mpfs_icicle/mpfs_icicle.dts +++ b/boards/riscv/mpfs_icicle/mpfs_icicle.dts @@ -5,7 +5,7 @@ */ /dts-v1/; -#include +#include #include #include diff --git a/dts/riscv/microchip/mpfs-icicle.dtsi b/dts/riscv/microchip/mpfs.dtsi similarity index 100% rename from dts/riscv/microchip/mpfs-icicle.dtsi rename to dts/riscv/microchip/mpfs.dtsi From 13f8d809300299cb56abf763d289e0b2eec0d4dc Mon Sep 17 00:00:00 2001 From: Conor Paxton Date: Sat, 2 Dec 2023 18:19:18 +0000 Subject: [PATCH 0840/3723] dts: riscv: add all contexts and devices to the plic on mpfs Microchip's PolarFire SoC has a total of 9 contexts associated with the Platform Interrupt controller (PLIC). the E51 core has a single context (M Mode), and the application processor U54 cores have two each (M mode and S mode, respectively) While we are at it, there are a total of 186 interrupts, not 187. Signed-off-by: Conor Paxton --- dts/riscv/microchip/mpfs.dtsi | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/dts/riscv/microchip/mpfs.dtsi b/dts/riscv/microchip/mpfs.dtsi index 4ed4d45e305..e0d206789db 100644 --- a/dts/riscv/microchip/mpfs.dtsi +++ b/dts/riscv/microchip/mpfs.dtsi @@ -120,10 +120,13 @@ #address-cells = <1>; interrupt-controller; interrupts-extended = <&hlic0 11 - &hlic1 11>; + &hlic1 11 &hlic1 9 + &hlic2 11 &hlic2 9 + &hlic3 11 &hlic3 9 + &hlic4 11 &hlic4 9>; reg = <0x0c000000 0x04000000>; riscv,max-priority = <7>; - riscv,ndev = <187>; + riscv,ndev = <186>; }; uart0: uart@20000000 { From dc5cf9cb1c0df8d2ed22750a0e070026db5714f6 Mon Sep 17 00:00:00 2001 From: Conor Paxton Date: Mon, 4 Dec 2023 19:10:36 +0000 Subject: [PATCH 0841/3723] soc: mpfs: describe the correct amount of irqs available. Microchip's PolarFire SoC (MPFS) has 186 available interrupts. Fix the Kconfig symbols. While we're at at: remove commented out code Signed-off-by: Conor Paxton --- soc/riscv/riscv-privileged/mpfs/Kconfig.defconfig.series | 7 ++----- 1 file changed, 2 insertions(+), 5 deletions(-) diff --git a/soc/riscv/riscv-privileged/mpfs/Kconfig.defconfig.series b/soc/riscv/riscv-privileged/mpfs/Kconfig.defconfig.series index fb9f6d2d3af..12f9dcaa992 100644 --- a/soc/riscv/riscv-privileged/mpfs/Kconfig.defconfig.series +++ b/soc/riscv/riscv-privileged/mpfs/Kconfig.defconfig.series @@ -30,12 +30,9 @@ config 2ND_LVL_INTR_00_OFFSET default 11 config MAX_IRQ_PER_AGGREGATOR - default 30 + default 186 config NUM_IRQS - default 187 - -# config NO_OPTIMIZATIONS -# default y + default 186 endif # SOC_SERIES_RISCV64_MIV From e496cbe5126728bcadc531b088d78137a94f7248 Mon Sep 17 00:00:00 2001 From: Emil Gydesen Date: Mon, 4 Dec 2023 22:21:58 +0100 Subject: [PATCH 0842/3723] Bluetooth: VCP: Vol rend: Add check before notification log To avoid having "notification scheduled in 0ms" in the log, check to verify that the delay is not K_NO_WAIT. Signed-off-by: Emil Gydesen --- subsys/bluetooth/audio/vcp_vol_rend.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/subsys/bluetooth/audio/vcp_vol_rend.c b/subsys/bluetooth/audio/vcp_vol_rend.c index 831e9506432..d99aa948f29 100644 --- a/subsys/bluetooth/audio/vcp_vol_rend.c +++ b/subsys/bluetooth/audio/vcp_vol_rend.c @@ -97,7 +97,7 @@ static void notify_work_reschedule(struct bt_vcp_vol_rend *inst, enum vol_rend_n if (err < 0) { LOG_ERR("Failed to reschedule %s notification err %d", vol_rend_notify_str(notify), err); - } else { + } else if (!K_TIMEOUT_EQ(delay, K_NO_WAIT)) { LOG_DBG("%s notification scheduled in %dms", vol_rend_notify_str(notify), k_ticks_to_ms_floor32(k_work_delayable_remaining_get(&inst->notify_work))); } From b75a3f691d0130059e7943cb6aafebc21722b55a Mon Sep 17 00:00:00 2001 From: Nick Ward Date: Tue, 5 Dec 2023 07:59:37 +1100 Subject: [PATCH 0843/3723] net: lwm2m: device object: use LWM2M_DEVICE_ERROR_NONE Use LWM2M_DEVICE_ERROR_NONE macro. Signed-off-by: Nick Ward --- subsys/net/lib/lwm2m/lwm2m_obj_device.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/subsys/net/lib/lwm2m/lwm2m_obj_device.c b/subsys/net/lib/lwm2m/lwm2m_obj_device.c index c17815795c2..7df9df03a93 100644 --- a/subsys/net/lib/lwm2m/lwm2m_obj_device.c +++ b/subsys/net/lib/lwm2m/lwm2m_obj_device.c @@ -89,7 +89,7 @@ LOG_MODULE_REGISTER(LOG_MODULE_NAME); DEVICE_EXT_DEV_INFO_MAX) /* resource state variables */ -static uint8_t error_code_list[DEVICE_ERROR_CODE_MAX]; +static uint8_t error_code_list[DEVICE_ERROR_CODE_MAX] = { LWM2M_DEVICE_ERROR_NONE }; static time_t time_temp; static time_t time_offset; static uint8_t binding_mode[DEVICE_STRING_SHORT]; @@ -138,7 +138,7 @@ static int reset_error_list_cb(uint16_t obj_inst_id, /* "delete" error codes */ for (i = 0; i < DEVICE_ERROR_CODE_MAX; i++) { - error_code_list[i] = 0; + error_code_list[i] = LWM2M_DEVICE_ERROR_NONE; error_code_ri[i].res_inst_id = RES_INSTANCE_NOT_CREATED; } @@ -188,7 +188,7 @@ int lwm2m_device_add_err(uint8_t error_code) int i; for (i = 0; i < DEVICE_ERROR_CODE_MAX; i++) { - if (error_code_list[i] == 0) { + if (error_code_list[i] == LWM2M_DEVICE_ERROR_NONE) { break; } From b1d24e425c3a30cdf1aed3c54c25a2518061accc Mon Sep 17 00:00:00 2001 From: Nick Ward Date: Tue, 5 Dec 2023 08:11:36 +1100 Subject: [PATCH 0844/3723] net: lwm2m: device object: optionally store error list in settings A device can be reset before the error code list is communicated to a LwM2M server so optionally store error list in settings so it can restored after reset. Signed-off-by: Nick Ward --- subsys/net/lib/lwm2m/Kconfig | 7 ++ subsys/net/lib/lwm2m/lwm2m_obj_device.c | 106 ++++++++++++++++++++++-- 2 files changed, 105 insertions(+), 8 deletions(-) diff --git a/subsys/net/lib/lwm2m/Kconfig b/subsys/net/lib/lwm2m/Kconfig index dd3c0c45618..1e5a7ac8f6a 100644 --- a/subsys/net/lib/lwm2m/Kconfig +++ b/subsys/net/lib/lwm2m/Kconfig @@ -392,6 +392,13 @@ config LWM2M_COMPOSITE_PATH_LIST_SIZE help Define path list size for Composite Read and send operation. +config LWM2M_DEVICE_ERROR_CODE_SETTINGS + bool "Use settings to store error codes across device resets" + depends on SETTINGS + help + Store the device error code list in settings. Ensures error list can + be transferred to LwM2M server even if the device is reset. + config LWM2M_DEVICE_PWRSRC_MAX int "Maximum # of device power source records" default 5 diff --git a/subsys/net/lib/lwm2m/lwm2m_obj_device.c b/subsys/net/lib/lwm2m/lwm2m_obj_device.c index 7df9df03a93..9416b3cf92c 100644 --- a/subsys/net/lib/lwm2m/lwm2m_obj_device.c +++ b/subsys/net/lib/lwm2m/lwm2m_obj_device.c @@ -1,6 +1,7 @@ /* * Copyright (c) 2017 Linaro Limited * Copyright (c) 2018-2019 Foundries.io + * Copyright (c) 2023 FTP Technologies * * SPDX-License-Identifier: Apache-2.0 */ @@ -19,6 +20,7 @@ LOG_MODULE_REGISTER(LOG_MODULE_NAME); #include #include #include +#include #include "lwm2m_object.h" #include "lwm2m_engine.h" @@ -129,10 +131,12 @@ static struct lwm2m_engine_res_inst res_inst[RESOURCE_INSTANCE_COUNT]; /* save error code resource instance point so we can easily clear later */ static struct lwm2m_engine_res_inst *error_code_ri; +#define SETTINGS_SUBTREE_LWM2M_OBJ_DEVICE "lwm2m_obj_dev" +#define ERROR_LIST_KEY "err" + /* callbacks */ -static int reset_error_list_cb(uint16_t obj_inst_id, - uint8_t *args, uint16_t args_len) +static void reset_error_list(void) { int i; @@ -144,8 +148,29 @@ static int reset_error_list_cb(uint16_t obj_inst_id, /* Default error code indicating no error */ error_code_ri[0].res_inst_id = 0; +} + +static int reset_error_list_cb(uint16_t obj_inst_id, + uint8_t *args, uint16_t args_len) +{ + int ret = 0; + + ARG_UNUSED(obj_inst_id); + ARG_UNUSED(args); + ARG_UNUSED(args_len); + + reset_error_list(); - return 0; + lwm2m_notify_observer(LWM2M_OBJECT_DEVICE_ID, 0, DEVICE_ERROR_CODE_ID); + + if (IS_ENABLED(CONFIG_LWM2M_DEVICE_ERROR_CODE_SETTINGS)) { + ret = settings_delete(SETTINGS_SUBTREE_LWM2M_OBJ_DEVICE "/" ERROR_LIST_KEY); + if (ret != 0) { + LOG_ERR("Couldn't save error list: %d", ret); + } + } + + return ret; } static void *current_time_read_cb(uint16_t obj_inst_id, uint16_t res_id, @@ -182,9 +207,9 @@ static int current_time_post_write_cb(uint16_t obj_inst_id, uint16_t res_id, } /* error code function */ - int lwm2m_device_add_err(uint8_t error_code) { + int ret = 0; int i; for (i = 0; i < DEVICE_ERROR_CODE_MAX; i++) { @@ -206,7 +231,15 @@ int lwm2m_device_add_err(uint8_t error_code) error_code_ri[i].res_inst_id = i; lwm2m_notify_observer(LWM2M_OBJECT_DEVICE_ID, 0, DEVICE_ERROR_CODE_ID); - return 0; + if (IS_ENABLED(CONFIG_LWM2M_DEVICE_ERROR_CODE_SETTINGS)) { + ret = settings_save_one(SETTINGS_SUBTREE_LWM2M_OBJ_DEVICE "/" ERROR_LIST_KEY, + error_code_list, i + 1); + if (ret != 0) { + LOG_ERR("Couldn't save error list: %d", ret); + } + } + + return ret; } static void device_periodic_service(struct k_work *work) @@ -219,6 +252,49 @@ int lwm2m_update_device_service_period(uint32_t period_ms) return lwm2m_engine_update_service_period(device_periodic_service, period_ms); } +static int lwm2m_obj_device_settings_set(const char *name, size_t len, + settings_read_cb read_cb, void *cb_arg) +{ + const char *next; + int rc; + int i; + + if (settings_name_steq(name, ERROR_LIST_KEY, &next) && !next) { + if (len > sizeof(error_code_list)) { + LOG_ERR("Error code list too large: %u", len); + return -EINVAL; + } + + rc = read_cb(cb_arg, error_code_list, sizeof(error_code_list)); + if (rc == 0) { + reset_error_list(); + return 0; + } else if (rc > 0) { + for (i = 0; i < ARRAY_SIZE(error_code_list); i++) { + if (i < rc) { + error_code_ri[i].res_inst_id = i; + } else { + /* Reset remaining error code instances */ + error_code_list[i] = LWM2M_DEVICE_ERROR_NONE; + error_code_ri[i].res_inst_id = RES_INSTANCE_NOT_CREATED; + } + } + return 0; + } + + LOG_ERR("Error code list read failure: %d", rc); + + return rc; + } + + return -ENOENT; +} + +static struct settings_handler lwm2m_obj_device_settings_handler = { + .name = SETTINGS_SUBTREE_LWM2M_OBJ_DEVICE, + .h_set = lwm2m_obj_device_settings_set, +}; + static struct lwm2m_engine_obj_inst *device_create(uint16_t obj_inst_id) { int i = 0, j = 0; @@ -271,7 +347,7 @@ static struct lwm2m_engine_obj_inst *device_create(uint16_t obj_inst_id) static int lwm2m_device_init(void) { struct lwm2m_engine_obj_inst *obj_inst = NULL; - int ret = 0; + int ret; /* Set default values */ time_offset = 0U; @@ -294,12 +370,26 @@ static int lwm2m_device_init(void) LOG_DBG("Create LWM2M instance 0 error: %d", ret); } - /* Create the default error code resource instance */ - lwm2m_device_add_err(0); + /* Ensure error list is reset if not loaded from settings */ + reset_error_list(); + + /* Load error code resource instances */ + if (IS_ENABLED(CONFIG_LWM2M_DEVICE_ERROR_CODE_SETTINGS)) { + ret = settings_register(&lwm2m_obj_device_settings_handler); + if (ret == 0) { + ret = settings_load_subtree(SETTINGS_SUBTREE_LWM2M_OBJ_DEVICE); + if (ret != 0) { + LOG_ERR("Settings load failed: %d", ret); + } + } else { + LOG_ERR("Settings register failed: %d", ret); + } + } /* call device_periodic_service() every 10 seconds */ ret = lwm2m_engine_add_service(device_periodic_service, DEVICE_SERVICE_INTERVAL_MS); + return ret; } From 3bdd91a575cbfac8a8f65b0776cce0ca515a3b9c Mon Sep 17 00:00:00 2001 From: Luca Burelli Date: Wed, 30 Aug 2023 14:42:51 +0200 Subject: [PATCH 0845/3723] boards: arduino_giga_r1: add OpenOCD support Add support for OpenOCD runner to the Arduino Giga R1 board. This shares the same CPU as the STM32H747i Discovery, so that implementation can be reused. Signed-off-by: Luca Burelli --- boards/arm/arduino_giga_r1/board.cmake | 5 ++++ .../support/openocd_arduino_giga_r1_m4.cfg | 12 ++++++++ .../support/openocd_arduino_giga_r1_m7.cfg | 28 +++++++++++++++++++ 3 files changed, 45 insertions(+) create mode 100644 boards/arm/arduino_giga_r1/support/openocd_arduino_giga_r1_m4.cfg create mode 100644 boards/arm/arduino_giga_r1/support/openocd_arduino_giga_r1_m7.cfg diff --git a/boards/arm/arduino_giga_r1/board.cmake b/boards/arm/arduino_giga_r1/board.cmake index 74efbc12411..849f9f933f1 100644 --- a/boards/arm/arduino_giga_r1/board.cmake +++ b/boards/arm/arduino_giga_r1/board.cmake @@ -2,8 +2,12 @@ if(CONFIG_BOARD_ARDUINO_GIGA_R1_M7) board_runner_args(jlink "--device=STM32H747XI_M7" "--speed=4000") +board_runner_args(openocd "--config=${BOARD_DIR}/support/openocd_arduino_giga_r1_m7.cfg") +board_runner_args(openocd --target-handle=_CHIPNAME.cpu0) elseif(CONFIG_BOARD_ARDUINO_GIGA_R1_M4) board_runner_args(jlink "--device=STM32H747XI_M4" "--speed=4000") +board_runner_args(openocd "--config=${BOARD_DIR}/support/openocd_arduino_giga_r1_m4.cfg") +board_runner_args(openocd --target-handle=_CHIPNAME.cpu1) endif() board_runner_args(dfu-util "--pid=2341:0366" "--alt=0" "--dfuse") board_runner_args(blackmagicprobe "--connect-rst") @@ -11,3 +15,4 @@ board_runner_args(blackmagicprobe "--connect-rst") include(${ZEPHYR_BASE}/boards/common/dfu-util.board.cmake) include(${ZEPHYR_BASE}/boards/common/blackmagicprobe.board.cmake) include(${ZEPHYR_BASE}/boards/common/jlink.board.cmake) +include(${ZEPHYR_BASE}/boards/common/openocd.board.cmake) diff --git a/boards/arm/arduino_giga_r1/support/openocd_arduino_giga_r1_m4.cfg b/boards/arm/arduino_giga_r1/support/openocd_arduino_giga_r1_m4.cfg new file mode 100644 index 00000000000..ddceef92cb1 --- /dev/null +++ b/boards/arm/arduino_giga_r1/support/openocd_arduino_giga_r1_m4.cfg @@ -0,0 +1,12 @@ + +source [find interface/stlink.cfg] + +transport select hla_swd + +set DUAL_BANK 1 + +set DUAL_CORE 1 + +source [find target/stm32h7x.cfg] + +reset_config srst_only srst_nogate connect_assert_srst diff --git a/boards/arm/arduino_giga_r1/support/openocd_arduino_giga_r1_m7.cfg b/boards/arm/arduino_giga_r1/support/openocd_arduino_giga_r1_m7.cfg new file mode 100644 index 00000000000..75d441d1809 --- /dev/null +++ b/boards/arm/arduino_giga_r1/support/openocd_arduino_giga_r1_m7.cfg @@ -0,0 +1,28 @@ + +source [find interface/stlink.cfg] + +transport select hla_swd + +source [find target/stm32h7x.cfg] + +# Use connect_assert_srst here to be able to program +# even when core is in sleep mode +reset_config srst_only srst_nogate connect_assert_srst + +$_CHIPNAME.cpu0 configure -event gdb-attach { + echo "Debugger attaching: halting execution" + gdb_breakpoint_override hard +} + +$_CHIPNAME.cpu0 configure -event gdb-detach { + echo "Debugger detaching: resuming execution" + resume +} + +# Due to the use of connect_assert_srst, running gdb requires +# to reset halt just after openocd init. +rename init old_init +proc init {} { + old_init + reset halt +} From f61ce34998336c880c4526b5217df58d855ffb01 Mon Sep 17 00:00:00 2001 From: Yong Cong Sin Date: Wed, 6 Dec 2023 16:48:34 +0800 Subject: [PATCH 0846/3723] shell: shell_uart: reinstate multi-instance macro Reinstate the `SHELL_UART_DEFINE` macro and moved the struct declarations to header file, making it possible to create another UART shell backend instance by doing `SHELL_UART_DEFINE()` + `SHELL_DEFINE()` + `shell_init()`. Signed-off-by: Yong Cong Sin --- include/zephyr/shell/shell_uart.h | 74 +++++++++++++++++++++++++ subsys/shell/backends/shell_uart.c | 86 ++++-------------------------- 2 files changed, 85 insertions(+), 75 deletions(-) diff --git a/include/zephyr/shell/shell_uart.h b/include/zephyr/shell/shell_uart.h index 5032c56f65e..065ee418037 100644 --- a/include/zephyr/shell/shell_uart.h +++ b/include/zephyr/shell/shell_uart.h @@ -7,6 +7,7 @@ #ifndef SHELL_UART_H__ #define SHELL_UART_H__ +#include #include #include @@ -14,6 +15,79 @@ extern "C" { #endif +extern const struct shell_transport_api shell_uart_transport_api; + +#ifndef CONFIG_SHELL_BACKEND_SERIAL_RX_RING_BUFFER_SIZE +#define CONFIG_SHELL_BACKEND_SERIAL_RX_RING_BUFFER_SIZE 0 +#endif + +#ifndef CONFIG_SHELL_BACKEND_SERIAL_TX_RING_BUFFER_SIZE +#define CONFIG_SHELL_BACKEND_SERIAL_TX_RING_BUFFER_SIZE 0 +#endif + +#ifndef CONFIG_SHELL_BACKEND_SERIAL_ASYNC_RX_BUFFER_COUNT +#define CONFIG_SHELL_BACKEND_SERIAL_ASYNC_RX_BUFFER_COUNT 0 +#endif + +#ifndef CONFIG_SHELL_BACKEND_SERIAL_ASYNC_RX_BUFFER_SIZE +#define CONFIG_SHELL_BACKEND_SERIAL_ASYNC_RX_BUFFER_SIZE 0 +#endif + +#define ASYNC_RX_BUF_SIZE (CONFIG_SHELL_BACKEND_SERIAL_ASYNC_RX_BUFFER_COUNT * \ + (CONFIG_SHELL_BACKEND_SERIAL_ASYNC_RX_BUFFER_SIZE + \ + UART_ASYNC_RX_BUF_OVERHEAD)) + +struct shell_uart_common { + const struct device *dev; + shell_transport_handler_t handler; + void *context; + bool blocking_tx; +#ifdef CONFIG_MCUMGR_TRANSPORT_SHELL + struct smp_shell_data smp; +#endif /* CONFIG_MCUMGR_TRANSPORT_SHELL */ +}; + +struct shell_uart_int_driven { + struct shell_uart_common common; + struct ring_buf tx_ringbuf; + struct ring_buf rx_ringbuf; + uint8_t tx_buf[CONFIG_SHELL_BACKEND_SERIAL_TX_RING_BUFFER_SIZE]; + uint8_t rx_buf[CONFIG_SHELL_BACKEND_SERIAL_RX_RING_BUFFER_SIZE]; + struct k_timer dtr_timer; + atomic_t tx_busy; +}; + +struct shell_uart_async { + struct shell_uart_common common; + struct k_sem tx_sem; + struct uart_async_rx async_rx; + struct uart_async_rx_config async_rx_config; + atomic_t pending_rx_req; + uint8_t rx_data[ASYNC_RX_BUF_SIZE]; +}; + +struct shell_uart_polling { + struct shell_uart_common common; + struct ring_buf rx_ringbuf; + uint8_t rx_buf[CONFIG_SHELL_BACKEND_SERIAL_RX_RING_BUFFER_SIZE]; + struct k_timer rx_timer; +}; + +#ifdef CONFIG_SHELL_BACKEND_SERIAL_API_POLLING +#define SHELL_UART_STRUCT struct shell_uart_polling +#elif defined(CONFIG_SHELL_BACKEND_SERIAL_API_ASYNC) +#define SHELL_UART_STRUCT struct shell_uart_async +#else +#define SHELL_UART_STRUCT struct shell_uart_int_driven +#endif + +#define SHELL_UART_DEFINE(_name) \ + static SHELL_UART_STRUCT _name##_shell_uart; \ + struct shell_transport _name = { \ + .api = &shell_uart_transport_api, \ + .ctx = (struct shell_telnet *)&_name##_shell_uart, \ + } + /** * @brief This function provides pointer to the shell UART backend instance. * diff --git a/subsys/shell/backends/shell_uart.c b/subsys/shell/backends/shell_uart.c index 5e4e3bd2c95..e11eebc7850 100644 --- a/subsys/shell/backends/shell_uart.c +++ b/subsys/shell/backends/shell_uart.c @@ -23,65 +23,6 @@ LOG_MODULE_REGISTER(shell_uart); #define RX_POLL_PERIOD K_NO_WAIT #endif -#ifndef CONFIG_SHELL_BACKEND_SERIAL_RX_RING_BUFFER_SIZE -#define CONFIG_SHELL_BACKEND_SERIAL_RX_RING_BUFFER_SIZE 0 -#endif - -#ifndef CONFIG_SHELL_BACKEND_SERIAL_TX_RING_BUFFER_SIZE -#define CONFIG_SHELL_BACKEND_SERIAL_TX_RING_BUFFER_SIZE 0 -#endif - -#ifndef CONFIG_SHELL_BACKEND_SERIAL_ASYNC_RX_BUFFER_COUNT -#define CONFIG_SHELL_BACKEND_SERIAL_ASYNC_RX_BUFFER_COUNT 0 -#endif - -#ifndef CONFIG_SHELL_BACKEND_SERIAL_ASYNC_RX_BUFFER_SIZE -#define CONFIG_SHELL_BACKEND_SERIAL_ASYNC_RX_BUFFER_SIZE 0 -#endif - -#define ASYNC_RX_BUF_SIZE (CONFIG_SHELL_BACKEND_SERIAL_ASYNC_RX_BUFFER_COUNT * \ - (CONFIG_SHELL_BACKEND_SERIAL_ASYNC_RX_BUFFER_SIZE + \ - UART_ASYNC_RX_BUF_OVERHEAD)) - -struct shell_uart_common { - const struct device *dev; - shell_transport_handler_t handler; - void *context; - bool blocking_tx; -#ifdef CONFIG_MCUMGR_TRANSPORT_SHELL - struct smp_shell_data smp; -#endif /* CONFIG_MCUMGR_TRANSPORT_SHELL */ -}; - -struct shell_uart_int_driven { - struct shell_uart_common common; - struct ring_buf tx_ringbuf; - struct ring_buf rx_ringbuf; - struct k_timer dtr_timer; - atomic_t tx_busy; -}; - -struct shell_uart_async { - struct shell_uart_common common; - struct k_sem tx_sem; - struct uart_async_rx async_rx; - atomic_t pending_rx_req; -}; - -struct shell_uart_polling { - struct shell_uart_common common; - struct ring_buf rx_ringbuf; - struct k_timer rx_timer; -}; - -static uint8_t __noinit async_rx_data[ASYNC_RX_BUF_SIZE]; -static uint8_t __noinit rx_ringbuf_data[CONFIG_SHELL_BACKEND_SERIAL_RX_RING_BUFFER_SIZE]; -static uint8_t __noinit tx_ringbuf_data[CONFIG_SHELL_BACKEND_SERIAL_TX_RING_BUFFER_SIZE]; - -static struct shell_uart_int_driven shell_uart_i; -static struct shell_uart_async shell_uart_a; -static struct shell_uart_polling shell_uart_p; - #ifdef CONFIG_MCUMGR_TRANSPORT_SHELL NET_BUF_POOL_DEFINE(smp_shell_rx_pool, CONFIG_MCUMGR_TRANSPORT_SHELL_RX_BUF_COUNT, SMP_SHELL_RX_BUF_SIZE, 0, NULL); @@ -272,9 +213,9 @@ static void irq_init(struct shell_uart_int_driven *sh_uart) const struct device *dev = sh_uart->common.dev; ring_buf_init(&sh_uart->rx_ringbuf, CONFIG_SHELL_BACKEND_SERIAL_RX_RING_BUFFER_SIZE, - rx_ringbuf_data); + sh_uart->rx_buf); ring_buf_init(&sh_uart->tx_ringbuf, CONFIG_SHELL_BACKEND_SERIAL_TX_RING_BUFFER_SIZE, - tx_ringbuf_data); + sh_uart->tx_buf); sh_uart->tx_busy = 0; uart_irq_callback_user_data_set(dev, uart_callback, (void *)sh_uart); uart_irq_rx_enable(dev); @@ -292,18 +233,19 @@ static int rx_enable(const struct device *dev, uint8_t *buf, size_t len) static void async_init(struct shell_uart_async *sh_uart) { - static const struct uart_async_rx_config async_rx_config = { - .buffer = async_rx_data, - .length = sizeof(async_rx_data), - .buf_cnt = CONFIG_SHELL_BACKEND_SERIAL_ASYNC_RX_BUFFER_COUNT - }; const struct device *dev = sh_uart->common.dev; struct uart_async_rx *async_rx = &sh_uart->async_rx; int err; + sh_uart->async_rx_config = (struct uart_async_rx_config){ + .buffer = sh_uart->rx_data, + .length = ASYNC_RX_BUF_SIZE, + .buf_cnt = CONFIG_SHELL_BACKEND_SERIAL_ASYNC_RX_BUFFER_COUNT, + }; + k_sem_init(&sh_uart->tx_sem, 0, 1); - err = uart_async_rx_init(async_rx, &async_rx_config); + err = uart_async_rx_init(async_rx, &sh_uart->async_rx_config); (void)err; __ASSERT_NO_MSG(err == 0); @@ -339,7 +281,7 @@ static void polling_init(struct shell_uart_polling *sh_uart) k_timer_start(&sh_uart->rx_timer, RX_POLL_PERIOD, RX_POLL_PERIOD); ring_buf_init(&sh_uart->rx_ringbuf, CONFIG_SHELL_BACKEND_SERIAL_RX_RING_BUFFER_SIZE, - rx_ringbuf_data); + sh_uart->rx_buf); } static int init(const struct shell_transport *transport, @@ -575,13 +517,7 @@ const struct shell_transport_api shell_uart_transport_api = { #endif /* CONFIG_MCUMGR_TRANSPORT_SHELL */ }; -struct shell_transport shell_transport_uart = { - .api = &shell_uart_transport_api, - .ctx = IS_ENABLED(CONFIG_SHELL_BACKEND_SERIAL_API_POLLING) ? (void *)&shell_uart_p : - (IS_ENABLED(CONFIG_SHELL_BACKEND_SERIAL_API_ASYNC) ? (void *)&shell_uart_a : - (void *)&shell_uart_i) -}; - +SHELL_UART_DEFINE(shell_transport_uart); SHELL_DEFINE(shell_uart, CONFIG_SHELL_PROMPT_UART, &shell_transport_uart, CONFIG_SHELL_BACKEND_SERIAL_LOG_MESSAGE_QUEUE_SIZE, CONFIG_SHELL_BACKEND_SERIAL_LOG_MESSAGE_QUEUE_TIMEOUT, From a25e211ad232e74269fb1f9058dbda3eeb3b86c1 Mon Sep 17 00:00:00 2001 From: Yong Cong Sin Date: Wed, 6 Dec 2023 18:05:48 +0800 Subject: [PATCH 0847/3723] tests: shell: shell_uart: add test for multi-instance Add test that exercise the instance macros of the UART shell backend. Signed-off-by: Yong Cong Sin --- .../shell/shell_backend_uart/CMakeLists.txt | 8 ++ .../shell/shell_backend_uart/app.overlay | 15 +++ .../subsys/shell/shell_backend_uart/prj.conf | 8 ++ .../shell/shell_backend_uart/src/main.c | 126 ++++++++++++++++++ .../shell/shell_backend_uart/testcase.yaml | 12 ++ 5 files changed, 169 insertions(+) create mode 100644 tests/subsys/shell/shell_backend_uart/CMakeLists.txt create mode 100644 tests/subsys/shell/shell_backend_uart/app.overlay create mode 100644 tests/subsys/shell/shell_backend_uart/prj.conf create mode 100644 tests/subsys/shell/shell_backend_uart/src/main.c create mode 100644 tests/subsys/shell/shell_backend_uart/testcase.yaml diff --git a/tests/subsys/shell/shell_backend_uart/CMakeLists.txt b/tests/subsys/shell/shell_backend_uart/CMakeLists.txt new file mode 100644 index 00000000000..e8dd0eac3b3 --- /dev/null +++ b/tests/subsys/shell/shell_backend_uart/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(shell_backend_uart) + +FILE(GLOB app_sources src/*.c) +target_sources(app PRIVATE ${app_sources}) diff --git a/tests/subsys/shell/shell_backend_uart/app.overlay b/tests/subsys/shell/shell_backend_uart/app.overlay new file mode 100644 index 00000000000..d399b81be4c --- /dev/null +++ b/tests/subsys/shell/shell_backend_uart/app.overlay @@ -0,0 +1,15 @@ +/* + * Copyright (c) 2023 Meta + * + * SPDX-License-Identifier: Apache-2.0 + */ + +/ { + euart0: uart-emul0 { + compatible = "zephyr,uart-emul"; + status = "okay"; + current-speed = <0>; + rx-fifo-size = <256>; + tx-fifo-size = <256>; + }; +}; diff --git a/tests/subsys/shell/shell_backend_uart/prj.conf b/tests/subsys/shell/shell_backend_uart/prj.conf new file mode 100644 index 00000000000..7b71e09687f --- /dev/null +++ b/tests/subsys/shell/shell_backend_uart/prj.conf @@ -0,0 +1,8 @@ +CONFIG_SHELL=y +CONFIG_SHELL_BACKEND_SERIAL=y +CONFIG_SHELL_PROMPT_UART="" +CONFIG_SHELL_CMD_BUFF_SIZE=90 +CONFIG_SHELL_PRINTF_BUFF_SIZE=15 +CONFIG_SHELL_METAKEYS=n +CONFIG_LOG=n +CONFIG_ZTEST=y diff --git a/tests/subsys/shell/shell_backend_uart/src/main.c b/tests/subsys/shell/shell_backend_uart/src/main.c new file mode 100644 index 00000000000..0e5d2704eb4 --- /dev/null +++ b/tests/subsys/shell/shell_backend_uart/src/main.c @@ -0,0 +1,126 @@ +/* + * Copyright 2023 Meta + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#define EMUL_UART_NODE(i) DT_NODELABEL(euart##i) +#define EMUL_UART_TX_FIFO_SIZE(i) DT_PROP(DT_NODELABEL(euart##i), tx_fifo_size) +#define SAMPLE_DATA_SIZE EMUL_UART_TX_FIFO_SIZE(0) + +struct shell_backend_uart_fixture { + const struct device *dev; +}; + +static void before(void *f) +{ + struct shell_backend_uart_fixture *fixture = f; + + uart_irq_tx_enable(fixture->dev); + uart_irq_rx_enable(fixture->dev); + + uart_err_check(fixture->dev); +} + +static void after(void *f) +{ + struct shell_backend_uart_fixture *fixture = f; + + uart_irq_tx_disable(fixture->dev); + uart_irq_rx_disable(fixture->dev); + + uart_emul_flush_rx_data(fixture->dev); + uart_emul_flush_tx_data(fixture->dev); +} + +ZTEST(shell_backend_uart, test_backends_count) +{ + /* 2 backends: 1 for zephyr,shell-uart, another 1 is created in the test */ + zassert_equal(shell_backend_count_get(), 2, "Expecting 2, got %d", + shell_backend_count_get()); +} + +ZTEST_F(shell_backend_uart, test_backend_euart0_version) +{ + uint8_t tx_content[SAMPLE_DATA_SIZE] = {0}; + + uart_emul_put_rx_data(fixture->dev, "kernel version\n", sizeof("kernel version\n")); + + /* Let the shell to run */ + k_usleep(50); + + uart_emul_get_tx_data(fixture->dev, tx_content, SAMPLE_DATA_SIZE); + zassert_mem_equal(tx_content, "Zephyr version " KERNEL_VERSION_STRING, + strlen("Zephyr version " KERNEL_VERSION_STRING)); +} + +ZTEST_F(shell_backend_uart, test_backend_euart0_cycles) +{ + uint8_t tx_content[SAMPLE_DATA_SIZE] = {0}; + + uart_emul_put_rx_data(fixture->dev, "kernel cycles\n", sizeof("kernel cycles\n")); + + /* Let the shell to run */ + k_usleep(50); + + uart_emul_get_tx_data(fixture->dev, tx_content, SAMPLE_DATA_SIZE); + zassert_mem_equal(tx_content, "cycles: ", strlen("cycles: ")); +} + +ZTEST_F(shell_backend_uart, test_backend_euart0_uptime) +{ + uint8_t tx_content[SAMPLE_DATA_SIZE] = {0}; + + uart_emul_put_rx_data(fixture->dev, "kernel uptime\n", sizeof("kernel uptime\n")); + + /* Let the shell to run */ + k_usleep(50); + + uart_emul_get_tx_data(fixture->dev, tx_content, SAMPLE_DATA_SIZE); + zassert_mem_equal(tx_content, "Uptime: ", strlen("Uptime: ")); +} + +static int enable_shell_euart0(const struct device *euart0, const struct shell *sh) +{ + static const struct shell_backend_config_flags cfg_flags = {0}; + + if (!device_is_ready(euart0)) { + return -ENODEV; + } + + return shell_init(sh, euart0, cfg_flags, false, 0); +} + +SHELL_UART_DEFINE(shell_transport_euart0); +SHELL_DEFINE(shell_euart0, "", &shell_transport_euart0, + CONFIG_SHELL_BACKEND_SERIAL_LOG_MESSAGE_QUEUE_SIZE, + CONFIG_SHELL_BACKEND_SERIAL_LOG_MESSAGE_QUEUE_TIMEOUT, SHELL_FLAG_OLF_CRLF); + +static void *setup(void) +{ + static struct shell_backend_uart_fixture fixture = { + .dev = DEVICE_DT_GET(DT_NODELABEL(euart0)), + }; + + zassert_not_null(fixture.dev); + enable_shell_euart0(fixture.dev, &shell_euart0); + + /* Let the shell backend initialize. */ + k_usleep(10); + + return &fixture; +} + +ZTEST_SUITE(shell_backend_uart, NULL, setup, before, after, NULL); diff --git a/tests/subsys/shell/shell_backend_uart/testcase.yaml b/tests/subsys/shell/shell_backend_uart/testcase.yaml new file mode 100644 index 00000000000..e4a72a1bd6a --- /dev/null +++ b/tests/subsys/shell/shell_backend_uart/testcase.yaml @@ -0,0 +1,12 @@ +tests: + shell.backend.uart: + min_flash: 64 + min_ram: 32 + tags: + - shell + - backend + - uart + filter: ( CONFIG_SHELL ) + platform_allow: + - qemu_x86 + - qemu_riscv32 From be1720872c8e682d48d3e3096d705f49b94721c2 Mon Sep 17 00:00:00 2001 From: Flavio Ceolin Date: Wed, 22 Nov 2023 22:41:32 +0000 Subject: [PATCH 0848/3723] console: Fix Kconfig dependency for xtensa sim Xtensa simulator console should not be enabled when the target is using winstream console, otherwise we will have multiple definitions of the same function. Signed-off-by: Flavio Ceolin --- drivers/console/Kconfig | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/console/Kconfig b/drivers/console/Kconfig index 606ce1fe6d6..c6c81728b3f 100644 --- a/drivers/console/Kconfig +++ b/drivers/console/Kconfig @@ -222,6 +222,7 @@ endif # UART_MCUMGR config XTENSA_SIM_CONSOLE bool "Use Xtensa simulator console" depends on SIMULATOR_XTENSA + depends on !WINSTREAM_CONSOLE select CONSOLE_HAS_DRIVER default y help From eb2e5de01c2082069a1d36fce5e79d4be2bc1a1c Mon Sep 17 00:00:00 2001 From: Flavio Ceolin Date: Wed, 22 Nov 2023 22:43:38 +0000 Subject: [PATCH 0849/3723] console: winstream: Select CONSOLE_HAS_DRIVER Select symbol CONSOLE_HAS_DRIVER when enabling WINSTREAM_CONSOLE. Signed-off-by: Flavio Ceolin --- drivers/console/Kconfig | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/console/Kconfig b/drivers/console/Kconfig index c6c81728b3f..28dcf9fbc16 100644 --- a/drivers/console/Kconfig +++ b/drivers/console/Kconfig @@ -341,6 +341,7 @@ config EFI_CONSOLE config WINSTREAM_CONSOLE bool "Use Winstream console" depends on WINSTREAM + select CONSOLE_HAS_DRIVER help Use winstream as a console. From d131981257e481a9c05a957f859e75acef461c38 Mon Sep 17 00:00:00 2001 From: Jordan Yates Date: Tue, 28 Nov 2023 14:14:01 +1000 Subject: [PATCH 0850/3723] console: uart: remove `pm_device_runtime_is_enabled` check `pm_device_runtime_get` and `pm_device_runtime_put` have returned `0` when device runtime PM is not enabled since #56222. Manually checking the state is no longer required. Signed-off-by: Jordan Yates --- drivers/console/uart_console.c | 18 +++++++----------- 1 file changed, 7 insertions(+), 11 deletions(-) diff --git a/drivers/console/uart_console.c b/drivers/console/uart_console.c index 5214bbada3e..6cdf6e43856 100644 --- a/drivers/console/uart_console.c +++ b/drivers/console/uart_console.c @@ -87,13 +87,11 @@ static int console_out(int c) #endif /* CONFIG_UART_CONSOLE_DEBUG_SERVER_HOOKS */ - if (pm_device_runtime_is_enabled(uart_console_dev)) { - if (pm_device_runtime_get(uart_console_dev) < 0) { - /* Enabling the UART instance has failed but this - * function MUST return the byte output. - */ - return c; - } + if (pm_device_runtime_get(uart_console_dev) < 0) { + /* Enabling the UART instance has failed but this + * function MUST return the byte output. + */ + return c; } if ('\n' == c) { @@ -101,10 +99,8 @@ static int console_out(int c) } uart_poll_out(uart_console_dev, c); - if (pm_device_runtime_is_enabled(uart_console_dev)) { - /* As errors cannot be returned, ignore the return value */ - (void)pm_device_runtime_put(uart_console_dev); - } + /* As errors cannot be returned, ignore the return value */ + (void)pm_device_runtime_put(uart_console_dev); return c; } From 5bf8edc85f83882a1380163aa10d81c2c3493848 Mon Sep 17 00:00:00 2001 From: Jordan Yates Date: Tue, 28 Nov 2023 14:24:14 +1000 Subject: [PATCH 0851/3723] logging: uart: cleanup device runtime PM checks `pm_device_runtime_get` and `pm_device_runtime_put` have returned `0` when device runtime PM is not enabled since #56222. Manually checking the state is no longer required. Additionally, the functions have been able to run in an ISR context since #60785, which removed the need to special case `k_is_in_isr()`. Signed-off-by: Jordan Yates --- subsys/logging/backends/log_backend_uart.c | 27 +++++++--------------- 1 file changed, 8 insertions(+), 19 deletions(-) diff --git a/subsys/logging/backends/log_backend_uart.c b/subsys/logging/backends/log_backend_uart.c index 46fa12b92e1..4173180f627 100644 --- a/subsys/logging/backends/log_backend_uart.c +++ b/subsys/logging/backends/log_backend_uart.c @@ -86,13 +86,11 @@ static int char_out(uint8_t *data, size_t length, void *ctx) struct lbu_data *lb_data = cb_ctx->data; const struct device *uart_dev = LBU_UART_DEV(cb_ctx); - if (pm_device_runtime_is_enabled(uart_dev) && !k_is_in_isr()) { - if (pm_device_runtime_get(uart_dev) < 0) { - /* Enabling the UART instance has failed but this - * function MUST return the number of bytes consumed. - */ - return length; - } + if (pm_device_runtime_get(uart_dev) < 0) { + /* Enabling the UART instance has failed but this + * function MUST return the number of bytes consumed. + */ + return length; } if (IS_ENABLED(CONFIG_LOG_BACKEND_UART_OUTPUT_DICTIONARY_HEX)) { @@ -116,10 +114,8 @@ static int char_out(uint8_t *data, size_t length, void *ctx) (void)err; cleanup: - if (pm_device_runtime_is_enabled(uart_dev) && !k_is_in_isr()) { - /* As errors cannot be returned, ignore the return value */ - (void)pm_device_runtime_put(uart_dev); - } + /* As errors cannot be returned, ignore the return value */ + (void)pm_device_runtime_put(uart_dev); return length; } @@ -190,14 +186,7 @@ static void panic(struct log_backend const *const backend) /* Ensure that the UART device is in active mode */ #if defined(CONFIG_PM_DEVICE_RUNTIME) - if (pm_device_runtime_is_enabled(uart_dev)) { - if (k_is_in_isr()) { - /* pm_device_runtime_get cannot be used from ISRs */ - pm_device_action_run(uart_dev, PM_DEVICE_ACTION_RESUME); - } else { - pm_device_runtime_get(uart_dev); - } - } + pm_device_runtime_get(uart_dev); #elif defined(CONFIG_PM_DEVICE) enum pm_device_state pm_state; int rc; From cbed9fd785efdf8c62f55c39280bc6086917b1d3 Mon Sep 17 00:00:00 2001 From: Luca Burelli Date: Fri, 1 Dec 2023 18:25:18 +0100 Subject: [PATCH 0852/3723] llext: always initialize ext param in llext_load It is not safe to assume that on entry to llext_load, *ext contains either NULL or a previous reference to the same ext being loaded. For example, the shell sample was passing an uninitialized value. Initialize *ext from a search of the llext by name. If NULL, it is the first instance of this llext (and on load error, it stays that way). If not NULL, increment use count and return. Signed-off-by: Luca Burelli --- include/zephyr/llext/llext.h | 2 +- subsys/llext/llext.c | 2 ++ 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/include/zephyr/llext/llext.h b/include/zephyr/llext/llext.h index af215e6acc0..b10ba2468ae 100644 --- a/include/zephyr/llext/llext.h +++ b/include/zephyr/llext/llext.h @@ -121,7 +121,7 @@ struct llext_load_param { * * @param[in] loader An extension loader that provides input data and context * @param[in] name A string identifier for the extension - * @param[out] ext A pointer to a statically allocated llext struct + * @param[out] ext This will hold the pointer to the llext struct * @param[in] ldr_parm Loader parameters * * @retval 0 Success diff --git a/subsys/llext/llext.c b/subsys/llext/llext.c index 77a741f0636..80d83dbb152 100644 --- a/subsys/llext/llext.c +++ b/subsys/llext/llext.c @@ -894,6 +894,8 @@ int llext_load(struct llext_loader *ldr, const char *name, struct llext **ext, int ret; elf_ehdr_t ehdr; + *ext = llext_by_name(name); + k_mutex_lock(&llext_lock, K_FOREVER); if (*ext) { From e96b713caf275e79c50c6d9480f5b3548d17eb3f Mon Sep 17 00:00:00 2001 From: Luca Burelli Date: Fri, 1 Dec 2023 18:43:02 +0100 Subject: [PATCH 0853/3723] llext: record size of each stored section Store the size of each section in the llext structure. Signed-off-by: Luca Burelli --- include/zephyr/llext/llext.h | 7 +++++-- subsys/llext/llext.c | 7 ++++--- subsys/llext/shell.c | 2 +- 3 files changed, 10 insertions(+), 6 deletions(-) diff --git a/include/zephyr/llext/llext.h b/include/zephyr/llext/llext.h index b10ba2468ae..951b13b8acd 100644 --- a/include/zephyr/llext/llext.h +++ b/include/zephyr/llext/llext.h @@ -58,8 +58,11 @@ struct llext { /** Memory allocated on heap */ bool mem_on_heap[LLEXT_MEM_COUNT]; - /** Total size of the llext memory usage */ - size_t mem_size; + /** Size of each stored section */ + size_t mem_size[LLEXT_MEM_COUNT]; + + /** Total llext allocation size */ + size_t alloc_size; /* * These are all global symbols in the extension, all of them don't diff --git a/subsys/llext/llext.c b/subsys/llext/llext.c index 80d83dbb152..fc1fbf33269 100644 --- a/subsys/llext/llext.c +++ b/subsys/llext/llext.c @@ -302,6 +302,7 @@ static int llext_copy_section(struct llext_loader *ldr, struct llext *ext, if (!ldr->sects[sect_idx].sh_size) { return 0; } + ext->mem_size[mem_idx] = ldr->sects[sect_idx].sh_size; if (ldr->sects[sect_idx].sh_type != SHT_NOBITS && IS_ENABLED(CONFIG_LLEXT_STORAGE_WRITABLE)) { @@ -318,7 +319,7 @@ static int llext_copy_section(struct llext_loader *ldr, struct llext *ext, if (!ext->mem[mem_idx]) { return -ENOMEM; } - ext->mem_size += ldr->sects[sect_idx].sh_size; + ext->alloc_size += ldr->sects[sect_idx].sh_size; if (ldr->sects[sect_idx].sh_type == SHT_NOBITS) { memset(ext->mem[mem_idx], 0, ldr->sects[sect_idx].sh_size); @@ -431,7 +432,7 @@ static int llext_allocate_symtab(struct llext_loader *ldr, struct llext *ext) return -ENOMEM; } memset(sym_tab->syms, 0, syms_size); - ext->mem_size += syms_size; + ext->alloc_size += syms_size; return 0; } @@ -801,7 +802,7 @@ static int do_llext_load(struct llext_loader *ldr, struct llext *ext, memset(ldr->sect_map, 0, sect_map_sz); ldr->sect_cnt = ldr->hdr.e_shnum; - ext->mem_size += sect_map_sz; + ext->alloc_size += sect_map_sz; LOG_DBG("Finding ELF tables..."); ret = llext_find_tables(ldr); diff --git a/subsys/llext/shell.c b/subsys/llext/shell.c index 57f5b1d131b..3bc97c3be87 100644 --- a/subsys/llext/shell.c +++ b/subsys/llext/shell.c @@ -93,7 +93,7 @@ static int llext_shell_list_cb(struct llext *ext, void *arg) { struct llext_shell_list *sl = arg; - shell_print(sl->sh, "| %16s | %12d |", ext->name, ext->mem_size); + shell_print(sl->sh, "| %16s | %12d |", ext->name, ext->alloc_size); return 0; } From 173217753098d6b46cf3d510d0bda5c3dd2b51a8 Mon Sep 17 00:00:00 2001 From: Luca Burelli Date: Fri, 1 Dec 2023 18:43:40 +0100 Subject: [PATCH 0854/3723] llext: flush dcache in the llext memory range On architectures that have separate data and instruction caches, such as the Cortex-M7, it is required to flush the reloc changes to the actual RAM storage before trying to execute any code from the newly loaded llext. Signed-off-by: Luca Burelli --- subsys/llext/llext.c | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/subsys/llext/llext.c b/subsys/llext/llext.c index fc1fbf33269..d71dfca3a77 100644 --- a/subsys/llext/llext.c +++ b/subsys/llext/llext.c @@ -11,6 +11,7 @@ #include #include #include +#include #include LOG_MODULE_REGISTER(llext, CONFIG_LLEXT_LOG_LEVEL); @@ -776,6 +777,15 @@ static int llext_link(struct llext_loader *ldr, struct llext *ext, bool do_local } } +#ifdef CONFIG_CACHE_MANAGEMENT + /* Make sure changes to ext sections are flushed to RAM */ + for (i = 0; i < LLEXT_MEM_COUNT; ++i) { + if (ext->mem[i]) { + arch_dcache_flush_range(ext->mem[i], ext->mem_size[i]); + } + } +#endif + return 0; } From 57e1dc337a6ba91dd77e9bf4dadf5948d446e76b Mon Sep 17 00:00:00 2001 From: Luca Burelli Date: Fri, 1 Dec 2023 18:59:08 +0100 Subject: [PATCH 0855/3723] llext: shell: fix command completions Dynamic command handlers should be fully initialized to avoid undefined behavior. Also, fix the number of arguments required by each command, since llext_call_fn requires both the llext and the name of the function to be called. Signed-off-by: Luca Burelli --- subsys/llext/shell.c | 18 ++++++++++++++---- 1 file changed, 14 insertions(+), 4 deletions(-) diff --git a/subsys/llext/shell.c b/subsys/llext/shell.c index 3bc97c3be87..033a0a91ce2 100644 --- a/subsys/llext/shell.c +++ b/subsys/llext/shell.c @@ -81,10 +81,21 @@ static void llext_name_get(size_t idx, struct shell_static_entry *entry) entry->syntax = cmd.ext ? cmd.ext->name : NULL; entry->help = NULL; entry->subcmd = NULL; + entry->handler = NULL; + entry->args.mandatory = 0; + entry->args.optional = 0; } - SHELL_DYNAMIC_CMD_CREATE(msub_llext_name, llext_name_get); +static void llext_name_arg_get(size_t idx, struct shell_static_entry *entry) +{ + llext_name_get(idx, entry); + if (entry->syntax) { + entry->args.mandatory = 1; + } +} +SHELL_DYNAMIC_CMD_CREATE(msub_llext_name_arg, llext_name_arg_get); + struct llext_shell_list { const struct shell *sh; }; @@ -175,12 +186,11 @@ static int cmd_llext_call_fn(const struct shell *sh, size_t argc, char *argv[]) /* clang-format off */ SHELL_STATIC_SUBCMD_SET_CREATE(sub_llext, SHELL_CMD(list, NULL, LLEXT_LIST_HELP, cmd_llext_list), - SHELL_CMD_ARG(load_hex, NULL, LLEXT_LOAD_HEX_HELP, cmd_llext_load_hex, - 3, 0), + SHELL_CMD_ARG(load_hex, NULL, LLEXT_LOAD_HEX_HELP, cmd_llext_load_hex, 3, 0), SHELL_CMD_ARG(unload, &msub_llext_name, LLEXT_UNLOAD_HELP, cmd_llext_unload, 2, 0), SHELL_CMD_ARG(list_symbols, &msub_llext_name, LLEXT_LIST_SYMBOLS_HELP, cmd_llext_list_symbols, 2, 0), - SHELL_CMD_ARG(call_fn, &msub_llext_name, LLEXT_CALL_FN_HELP, + SHELL_CMD_ARG(call_fn, &msub_llext_name_arg, LLEXT_CALL_FN_HELP, cmd_llext_call_fn, 3, 0), SHELL_SUBCMD_SET_END From 8ff2ad7e5ef07cdbaab6f8a14bbc7aa87aeb6438 Mon Sep 17 00:00:00 2001 From: Luca Burelli Date: Tue, 5 Dec 2023 11:35:24 +0100 Subject: [PATCH 0856/3723] MAINTAINERS: add myself as a collaborator for llext Add @pillo79 as a collaborator for llext development. Signed-off-by: Luca Burelli --- MAINTAINERS.yml | 1 + 1 file changed, 1 insertion(+) diff --git a/MAINTAINERS.yml b/MAINTAINERS.yml index 5523a720ea5..c14008e8e8f 100644 --- a/MAINTAINERS.yml +++ b/MAINTAINERS.yml @@ -3975,6 +3975,7 @@ zbus: - teburd collaborators: - lyakh + - pillo79 files: - samples/subsys/llext/ - include/zephyr/llext/ From e0dc6f4fe4af2a01e555e69ef130d724ab6ea865 Mon Sep 17 00:00:00 2001 From: Sumit Batra Date: Tue, 5 Dec 2023 19:13:47 +0530 Subject: [PATCH 0857/3723] drivers: sensor: qdec_s32: Add QDEC support for S32 Add code to configure and program Lcu, Trgmux and Emios_Icu IPs to get the the rotations by the motor in radians. Co-authored-by: Benjamin Perseghetti Co-authored-by: Peter van der Perk Co-authored-by: Mayank Mahajan Signed-off-by: Sumit Batra --- .../arm/mr_canhubk3/mr_canhubk3-pinctrl.dtsi | 11 +- boards/arm/mr_canhubk3/mr_canhubk3.dts | 61 ++- drivers/sensor/CMakeLists.txt | 1 + drivers/sensor/Kconfig | 1 + drivers/sensor/qdec_nxp_s32/CMakeLists.txt | 6 + drivers/sensor/qdec_nxp_s32/Kconfig | 10 + drivers/sensor/qdec_nxp_s32/qdec_nxp_s32.c | 451 ++++++++++++++++++ dts/arm/nxp/nxp_s32k344_m7.dtsi | 18 + dts/bindings/misc/nxp,s32-lcu.yaml | 16 + dts/bindings/misc/nxp,s32-trgmux.yaml | 16 + dts/bindings/sensor/nxp,s32-qdec.yaml | 112 +++++ .../zephyr/dt-bindings/sensor/qdec_nxp_s32.h | 107 +++++ 12 files changed, 791 insertions(+), 19 deletions(-) create mode 100644 drivers/sensor/qdec_nxp_s32/CMakeLists.txt create mode 100644 drivers/sensor/qdec_nxp_s32/Kconfig create mode 100644 drivers/sensor/qdec_nxp_s32/qdec_nxp_s32.c create mode 100644 dts/bindings/misc/nxp,s32-lcu.yaml create mode 100644 dts/bindings/misc/nxp,s32-trgmux.yaml create mode 100644 dts/bindings/sensor/nxp,s32-qdec.yaml create mode 100644 include/zephyr/dt-bindings/sensor/qdec_nxp_s32.h diff --git a/boards/arm/mr_canhubk3/mr_canhubk3-pinctrl.dtsi b/boards/arm/mr_canhubk3/mr_canhubk3-pinctrl.dtsi index 0b2906f2982..e057aeb1ef6 100644 --- a/boards/arm/mr_canhubk3/mr_canhubk3-pinctrl.dtsi +++ b/boards/arm/mr_canhubk3/mr_canhubk3-pinctrl.dtsi @@ -287,7 +287,6 @@ pinmux = , , , , , , - , , ; output-enable; }; @@ -300,4 +299,14 @@ output-enable; }; }; + + qdec_s32: qdec_s32 { + group1 { + pinmux = , + , + , + ; + input-enable; + }; + }; }; diff --git a/boards/arm/mr_canhubk3/mr_canhubk3.dts b/boards/arm/mr_canhubk3/mr_canhubk3.dts index 50b72338da2..97bca1402b4 100644 --- a/boards/arm/mr_canhubk3/mr_canhubk3.dts +++ b/boards/arm/mr_canhubk3/mr_canhubk3.dts @@ -11,6 +11,7 @@ #include #include #include "mr_canhubk3-pinctrl.dtsi" +#include / { model = "NXP MR-CANHUBK3"; @@ -42,6 +43,7 @@ green-pwm-led = &user_led1_green_pwm; blue-pwm-led = &user_led1_blue_pwm; pwm-led0 = &user_led1_blue_pwm; + qdec0 = &qdec0; }; leds { @@ -77,6 +79,39 @@ }; }; + qdec0: qdec0 { + compatible = "nxp,qdec-s32"; + pinctrl-0 = <&qdec_s32>; + pinctrl-names = "default"; + micro-ticks-per-rev = <685440000>; + status = "okay"; + trgmux = <&trgmux>; + trgmux-io-config = + <0 TRGMUX_IP_OUTPUT_EMIOS0_CH5_9_IPP_IND_CH6 TRGMUX_IP_INPUT_LCU1_LC0_OUT_I2>, + <1 TRGMUX_IP_OUTPUT_EMIOS0_CH5_9_IPP_IND_CH7 TRGMUX_IP_INPUT_LCU1_LC0_OUT_I3>, + <2 TRGMUX_IP_OUTPUT_LCU1_0_INP_I0 TRGMUX_IP_INPUT_SIUL2_IN2>, + <3 TRGMUX_IP_OUTPUT_LCU1_0_INP_I1 TRGMUX_IP_INPUT_SIUL2_IN3>; + lcu = <&lcu1>; + lcu-input-idx = + ; + lcu-mux-sel = + ; + lcu-output-filter-config = + /* LCU Out HW ID, Rise Filter, Fall Filter */ + <0 5 5>, /* LCU O0 */ + <1 5 5>, /* LCU O1 */ + <2 2 2>, /* LCU O2 */ + <3 2 2>; /* LCU O3 */ + emios = <&emios0>; + /* + * eMios channel numbers for qdec should be beyond the channel numbers + * used by the emios pwm + */ + emios-channels = <6 7>; + }; + gpio_keys { compatible = "gpio-keys"; user_button_1: button_0 { @@ -501,24 +536,6 @@ polarity = "ACTIVE_HIGH"; }; - pwm_6 { - channel = <6>; - pwm-mode = "OPWFMB"; - period = <65535>; - duty-cycle = <0>; - prescaler = <8>; - polarity = "ACTIVE_HIGH"; - }; - - pwm_7 { - channel = <7>; - pwm-mode = "OPWFMB"; - period = <65535>; - duty-cycle = <0>; - prescaler = <8>; - polarity = "ACTIVE_HIGH"; - }; - rgb_red { channel = <19>; master-bus = <&emios0_bus_a>; @@ -576,6 +593,14 @@ }; }; +&lcu1 { + status = "okay"; +}; + +&trgmux { + status = "okay"; +}; + &edma0 { status = "okay"; }; diff --git a/drivers/sensor/CMakeLists.txt b/drivers/sensor/CMakeLists.txt index 76bb17bc822..afa200a06ab 100644 --- a/drivers/sensor/CMakeLists.txt +++ b/drivers/sensor/CMakeLists.txt @@ -112,6 +112,7 @@ add_subdirectory_ifdef(CONFIG_OPT3001 opt3001) add_subdirectory_ifdef(CONFIG_PCNT_ESP32 pcnt_esp32) add_subdirectory_ifdef(CONFIG_PMS7003 pms7003) add_subdirectory_ifdef(CONFIG_QDEC_MCUX qdec_mcux) +add_subdirectory_ifdef(CONFIG_QDEC_NXP_S32 qdec_nxp_s32) add_subdirectory_ifdef(CONFIG_QDEC_NRFX qdec_nrfx) add_subdirectory_ifdef(CONFIG_QDEC_SAM qdec_sam) add_subdirectory_ifdef(CONFIG_QDEC_STM32 qdec_stm32) diff --git a/drivers/sensor/Kconfig b/drivers/sensor/Kconfig index fba7501bad9..7e454740973 100644 --- a/drivers/sensor/Kconfig +++ b/drivers/sensor/Kconfig @@ -189,6 +189,7 @@ source "drivers/sensor/opt3001/Kconfig" source "drivers/sensor/pcnt_esp32/Kconfig" source "drivers/sensor/pms7003/Kconfig" source "drivers/sensor/qdec_mcux/Kconfig" +source "drivers/sensor/qdec_nxp_s32/Kconfig" source "drivers/sensor/qdec_nrfx/Kconfig" source "drivers/sensor/qdec_sam/Kconfig" source "drivers/sensor/qdec_stm32/Kconfig" diff --git a/drivers/sensor/qdec_nxp_s32/CMakeLists.txt b/drivers/sensor/qdec_nxp_s32/CMakeLists.txt new file mode 100644 index 00000000000..a3065a37aba --- /dev/null +++ b/drivers/sensor/qdec_nxp_s32/CMakeLists.txt @@ -0,0 +1,6 @@ +# Copyright 2023 NXP +# SPDX-License-Identifier: Apache-2.0 + +zephyr_library() + +zephyr_library_sources(qdec_nxp_s32.c) diff --git a/drivers/sensor/qdec_nxp_s32/Kconfig b/drivers/sensor/qdec_nxp_s32/Kconfig new file mode 100644 index 00000000000..4250d9b2654 --- /dev/null +++ b/drivers/sensor/qdec_nxp_s32/Kconfig @@ -0,0 +1,10 @@ +# Copyright 2023 NXP +# SPDX-License-Identifier: Apache-2.0 + +config QDEC_NXP_S32 + bool "NXP Quad Decoder S32 drivers" + default y + depends on DT_HAS_NXP_QDEC_S32_ENABLED + select NXP_S32_EMIOS + help + Enable drivers for NXP S32 QUADRATURE DECODER diff --git a/drivers/sensor/qdec_nxp_s32/qdec_nxp_s32.c b/drivers/sensor/qdec_nxp_s32/qdec_nxp_s32.c new file mode 100644 index 00000000000..31d6297d5d3 --- /dev/null +++ b/drivers/sensor/qdec_nxp_s32/qdec_nxp_s32.c @@ -0,0 +1,451 @@ +/* + * Copyright 2023 NXP + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include +#include + +#include +#include +#include +#include + +#ifndef M_PI +#define M_PI 3.14159265358979323846 +#endif + +#define EMIOS_CHANNEL_COUNT 2U +#define EMIOS_CW_CH_IDX 0 +#define EMIOS_CCW_CH_IDX 1 + +/* LCU LUT control values for each of the 4 LC outputs */ +/* These values decide the direction of motor rotation */ +#define LCU_O0_LUT 0xAAAA +#define LCU_O1_LUT 0xCCCC +#define LCU_O2_LUT 0x4182 +#define LCU_O3_LUT 0x2814 + +LOG_MODULE_REGISTER(nxp_qdec_s32, CONFIG_SENSOR_LOG_LEVEL); + +#include +#include +#include + +#define DT_DRV_COMPAT nxp_qdec_s32 + +typedef void (*emios_callback_t)(void); + +/* Configuration variables from eMIOS Icu driver */ +extern eMios_Icu_Ip_ChStateType eMios_Icu_Ip_ChState[EMIOS_ICU_IP_NUM_OF_CHANNELS_USED]; +extern uint8 eMios_Icu_Ip_IndexInChState[EMIOS_ICU_IP_INSTANCE_COUNT][EMIOS_ICU_IP_NUM_OF_CHANNELS]; + +struct qdec_s32_config { + uint8_t emios_inst; + uint8_t emios_channels[EMIOS_CHANNEL_COUNT]; + const struct pinctrl_dev_config *pincfg; + + const Trgmux_Ip_InitType *trgmux_config; + + const Lcu_Ip_InitType *lcu_config; + emios_callback_t emios_cw_overflow_cb; + emios_callback_t emios_ccw_overflow_cb; +}; + +struct qdec_s32_data { + uint32_t counter_CW; + uint32_t counter_CCW; + int32_t abs_counter; + float micro_ticks_per_rev; + uint32_t ticks_per_sec; + uint32_t emios_cw_overflow_count; + uint32_t emios_ccw_overflow_count; +}; + +static void qdec_emios_overflow_count_cw_callback(const struct device *dev) +{ + struct qdec_s32_data *data = dev->data; + + data->emios_cw_overflow_count++; +} + +static void qdec_emios_overflow_count_ccw_callback(const struct device *dev) +{ + struct qdec_s32_data *data = dev->data; + + data->emios_ccw_overflow_count++; +} + +static int qdec_s32_fetch(const struct device *dev, enum sensor_channel ch) +{ + const struct qdec_s32_config *config = dev->config; + struct qdec_s32_data *data = dev->data; + + if (ch != SENSOR_CHAN_ALL) { + return -ENOTSUP; + } + + data->counter_CW = (uint32_t)(Emios_Icu_Ip_GetEdgeNumbers( + config->emios_inst, config->emios_channels[EMIOS_CW_CH_IDX])); /* CW counter */ + data->counter_CCW = (uint32_t)(Emios_Icu_Ip_GetEdgeNumbers( + config->emios_inst, config->emios_channels[EMIOS_CCW_CH_IDX]));/* CCW counter*/ + + data->abs_counter = (int32_t)( + +(data->counter_CW + EMIOS_ICU_IP_COUNTER_MASK * + data->emios_cw_overflow_count) + -(data->counter_CCW + EMIOS_ICU_IP_COUNTER_MASK * + data->emios_ccw_overflow_count)); + + LOG_DBG("ABS_COUNT = %d CW = %u OverFlow_CW = %u CCW = %u Overflow_CCW = %u", + data->abs_counter, data->counter_CW, + data->emios_cw_overflow_count, + data->counter_CCW, data->emios_ccw_overflow_count); + + return 0; +} + +static int qdec_s32_ch_get(const struct device *dev, enum sensor_channel ch, + struct sensor_value *val) +{ + struct qdec_s32_data *data = dev->data; + + double rotation = (data->abs_counter * 2.0 * M_PI) / data->micro_ticks_per_rev; + + switch (ch) { + case SENSOR_CHAN_ROTATION: + sensor_value_from_double(val, rotation); + break; + default: + return -ENOTSUP; + } + + return 0; +} + +static const struct sensor_driver_api qdec_s32_api = { + .sample_fetch = &qdec_s32_fetch, + .channel_get = &qdec_s32_ch_get, +}; + +static int qdec_s32_initialize(const struct device *dev) +{ + const struct qdec_s32_config *config = dev->config; + uint8_t emios_inst, emios_hw_ch_cw, emios_hw_ch_ccw; + + pinctrl_apply_state(config->pincfg, PINCTRL_STATE_DEFAULT); + + if (Trgmux_Ip_Init(config->trgmux_config)) { + LOG_ERR("Could not initialize Trgmux"); + return -EINVAL; + } + + LOG_DBG("TRGMUX ACCESS Input[0] =%d Output[0]=%d", + config->trgmux_config->paxLogicTrigger[0]->Input, + config->trgmux_config->paxLogicTrigger[0]->Output); + + if (Lcu_Ip_Init(config->lcu_config)) { + LOG_ERR("Could not initialize Lcu"); + return -EINVAL; + } + + /* Unmask relevant LCU OUT Channels */ + Lcu_Ip_SyncOutputValueType EncLcuEnable[4U]; + + EncLcuEnable[0].LogicOutputId = LCU_LOGIC_OUTPUT_0; + EncLcuEnable[0].Value = 1U; + EncLcuEnable[1].LogicOutputId = LCU_LOGIC_OUTPUT_1; + EncLcuEnable[1].Value = 1U; + EncLcuEnable[2].LogicOutputId = LCU_LOGIC_OUTPUT_2; + EncLcuEnable[2].Value = 1U; + EncLcuEnable[3].LogicOutputId = LCU_LOGIC_OUTPUT_3; + EncLcuEnable[3].Value = 1U; + Lcu_Ip_SetSyncOutputEnable(EncLcuEnable, 4U); + + emios_inst = config->emios_inst; + emios_hw_ch_cw = config->emios_channels[EMIOS_CW_CH_IDX]; + emios_hw_ch_ccw = config->emios_channels[EMIOS_CCW_CH_IDX]; + + /* Initialize the positions of the eMios hw channels used for QDEC + * to be beyond the eMios pwm hw channels. Currently only pwm and qdec + * are using the eMios channels so qdec ones are the last two. + */ + eMios_Icu_Ip_IndexInChState[emios_inst][emios_hw_ch_cw] + = EMIOS_ICU_IP_NUM_OF_CHANNELS_USED - 2; + eMios_Icu_Ip_IndexInChState[emios_inst][emios_hw_ch_ccw] + = EMIOS_ICU_IP_NUM_OF_CHANNELS_USED - 1; + + /* Set Overflow Notification for eMIOS channels meant + * for Clockwise and Counterclock rotation counters + */ + eMios_Icu_Ip_ChState[eMios_Icu_Ip_IndexInChState[emios_inst][emios_hw_ch_cw]] + .eMiosOverflowNotification = config->emios_cw_overflow_cb; + eMios_Icu_Ip_ChState[eMios_Icu_Ip_IndexInChState[emios_inst][emios_hw_ch_ccw]] + .eMiosOverflowNotification = config->emios_ccw_overflow_cb; + + Emios_Icu_Ip_SetInitialCounterValue( + config->emios_inst, config->emios_channels[EMIOS_CW_CH_IDX], (uint32_t)0x1U); + Emios_Icu_Ip_SetInitialCounterValue( + config->emios_inst, config->emios_channels[EMIOS_CCW_CH_IDX], (uint32_t)0x1U); + + Emios_Icu_Ip_SetMaxCounterValue(config->emios_inst, + config->emios_channels[EMIOS_CW_CH_IDX], + EMIOS_ICU_IP_COUNTER_MASK); + Emios_Icu_Ip_SetMaxCounterValue(config->emios_inst, + config->emios_channels[EMIOS_CCW_CH_IDX], + EMIOS_ICU_IP_COUNTER_MASK); + + /* This API sets MCB/EMIOS_ICU_MODE_EDGE_COUNTER mode */ + Emios_Icu_Ip_EnableEdgeCount(config->emios_inst, config->emios_channels[EMIOS_CW_CH_IDX]); + Emios_Icu_Ip_EnableEdgeCount(config->emios_inst, config->emios_channels[EMIOS_CCW_CH_IDX]); + + LOG_DBG("Init complete"); + + return 0; +} + +#define EMIOS_NXP_S32_MCB_OVERFLOW_CALLBACK(n) \ + static void qdec##n##_emios_overflow_count_cw_callback(void) \ + { \ + qdec_emios_overflow_count_cw_callback(DEVICE_DT_INST_GET(n)); \ + } \ + \ + static void qdec##n##_emios_overflow_count_ccw_callback(void) \ + { \ + qdec_emios_overflow_count_ccw_callback(DEVICE_DT_INST_GET(n)); \ + } + +#define EMIOS_NXP_S32_INSTANCE_CHECK(idx, node_id) \ + ((DT_REG_ADDR(node_id) == IP_EMIOS_##idx##_BASE) ? idx : 0) + +#define EMIOS_NXP_S32_GET_INSTANCE(node_id) \ + LISTIFY(__DEBRACKET eMIOS_INSTANCE_COUNT, EMIOS_NXP_S32_INSTANCE_CHECK, (|), node_id) + +#define LCU_NXP_S32_INSTANCE_CHECK(idx, node_id) \ + ((DT_REG_ADDR(node_id) == IP_LCU_##idx##_BASE) ? idx : 0) + +#define LCU_NXP_S32_GET_INSTANCE(node_id) \ + LISTIFY(__DEBRACKET LCU_INSTANCE_COUNT, LCU_NXP_S32_INSTANCE_CHECK, (|), node_id) + +#define TRGMUX_NXP_S32_INSTANCE_CHECK(node_id) \ + ((DT_REG_ADDR(node_id) == IP_TRGMUX_BASE) ? 0 : -1) + +#define TRGMUX_NXP_S32_GET_INSTANCE(node_id) TRGMUX_NXP_S32_INSTANCE_CHECK(node_id) + +/* LCU Logic Input Configuration */ +#define LogicInputCfg_Common(n, mux_sel_idx) \ + { \ + .MuxSel = DT_INST_PROP_BY_IDX(n, lcu_mux_sel, mux_sel_idx), \ + .SwSynMode = LCU_IP_SW_SYNC_IMMEDIATE, \ + .SwValue = LCU_IP_SW_OVERRIDE_LOGIC_LOW, \ + }; +#define LogicInput_Config_Common(n, hw_lc_input_id, logic_input_n_cfg) \ + { \ + .xLogicInputId = { \ + .HwInstId = LCU_NXP_S32_GET_INSTANCE(DT_INST_PHANDLE(n, lcu)), \ + .HwLcInputId = DT_INST_PROP_BY_IDX(n, lcu_input_idx, hw_lc_input_id), \ + }, \ + .pxLcInputConfig = &logic_input_n_cfg, \ + }; + +/* LCU Logic Output Configuration */ +#define LogicOutputCfg_Common(En_Debug_Mode, Lut_Control, Lut_Rise_Filt, Lut_Fall_Filt) \ + { \ + .EnDebugMode = (boolean)En_Debug_Mode, \ + .LutControl = Lut_Control, \ + .LutRiseFilt = Lut_Rise_Filt, \ + .LutFallFilt = Lut_Fall_Filt, \ + .EnLutDma = (boolean)FALSE, \ + .EnForceDma = (boolean)FALSE, \ + .EnLutInt = (boolean)FALSE, \ + .EnForceInt = (boolean)FALSE, \ + .InvertOutput = (boolean)FALSE, \ + .ForceSignalSel = 0U, \ + .ClearForceMode = LCU_IP_CLEAR_FORCE_SIGNAL_IMMEDIATE, \ + .ForceSyncSel = LCU_IP_SYNC_SEL_INPUT0, \ + }; +#define LogicOutput_Config_Common(n, logic_output_cfg, hw_lc_output_id) \ + { \ + .xLogicOutputId = { \ + .HwInstId = LCU_NXP_S32_GET_INSTANCE(DT_INST_PHANDLE(n, lcu)), \ + .HwLcOutputId = hw_lc_output_id, \ + .IntCallback = NULL_PTR, \ + }, \ + .pxLcOutputConfig = &logic_output_cfg, \ + }; + +#define LCU_IP_INIT_CONFIG(n) \ + const Lcu_Ip_LogicInputConfigType LogicInput##n##_0_Cfg = \ + LogicInputCfg_Common(n, 0) \ + const Lcu_Ip_LogicInputConfigType LogicInput##n##_1_Cfg = \ + LogicInputCfg_Common(n, 1) \ + const Lcu_Ip_LogicInputConfigType LogicInput##n##_2_Cfg = \ + LogicInputCfg_Common(n, 2) \ + const Lcu_Ip_LogicInputConfigType LogicInput##n##_3_Cfg = \ + LogicInputCfg_Common(n, 3) \ + \ + const Lcu_Ip_LogicInputType LogicInput##n##_0_Config = \ + LogicInput_Config_Common(n, 0, LogicInput##n##_0_Cfg) \ + const Lcu_Ip_LogicInputType LogicInput##n##_1_Config = \ + LogicInput_Config_Common(n, 1, LogicInput##n##_1_Cfg) \ + const Lcu_Ip_LogicInputType LogicInput##n##_2_Config = \ + LogicInput_Config_Common(n, 2, LogicInput##n##_2_Cfg) \ + const Lcu_Ip_LogicInputType LogicInput##n##_3_Config = \ + LogicInput_Config_Common(n, 3, LogicInput##n##_3_Cfg) \ + \ + const Lcu_Ip_LogicInputType \ + *const Lcu_Ip_ppxLogicInputArray##n##_Config[LCU_IP_NOF_CFG_LOGIC_INPUTS] = { \ + &LogicInput##n##_0_Config, \ + &LogicInput##n##_1_Config, \ + &LogicInput##n##_2_Config, \ + &LogicInput##n##_3_Config, \ + }; \ + \ + const Lcu_Ip_LogicOutputConfigType LogicOutput##n##_0_Cfg = LogicOutputCfg_Common( \ + LCU_IP_DEBUG_DISABLE, LCU_O0_LUT, \ + DT_INST_PROP_BY_IDX(n, lcu_output_filter_config, 1), \ + DT_INST_PROP_BY_IDX(n, lcu_output_filter_config, 2)) \ + const Lcu_Ip_LogicOutputConfigType LogicOutput##n##_1_Cfg = LogicOutputCfg_Common( \ + LCU_IP_DEBUG_DISABLE, LCU_O1_LUT, \ + DT_INST_PROP_BY_IDX(n, lcu_output_filter_config, 4), \ + DT_INST_PROP_BY_IDX(n, lcu_output_filter_config, 5)) \ + const Lcu_Ip_LogicOutputConfigType LogicOutput##n##_2_Cfg = LogicOutputCfg_Common( \ + LCU_IP_DEBUG_ENABLE, LCU_O2_LUT, \ + DT_INST_PROP_BY_IDX(n, lcu_output_filter_config, 7), \ + DT_INST_PROP_BY_IDX(n, lcu_output_filter_config, 8)) \ + const Lcu_Ip_LogicOutputConfigType LogicOutput##n##_3_Cfg = LogicOutputCfg_Common( \ + LCU_IP_DEBUG_ENABLE, LCU_O3_LUT, \ + DT_INST_PROP_BY_IDX(n, lcu_output_filter_config, 10), \ + DT_INST_PROP_BY_IDX(n, lcu_output_filter_config, 11)) \ + \ + const Lcu_Ip_LogicOutputType LogicOutput##n##_0_Config = \ + LogicOutput_Config_Common(n, LogicOutput##n##_0_Cfg, \ + DT_INST_PROP_BY_IDX(n, lcu_output_filter_config, 0)) \ + const Lcu_Ip_LogicOutputType LogicOutput##n##_1_Config = \ + LogicOutput_Config_Common(n, LogicOutput##n##_1_Cfg, \ + DT_INST_PROP_BY_IDX(n, lcu_output_filter_config, 3)) \ + const Lcu_Ip_LogicOutputType LogicOutput##n##_2_Config = \ + LogicOutput_Config_Common(n, LogicOutput##n##_2_Cfg, \ + DT_INST_PROP_BY_IDX(n, lcu_output_filter_config, 6)) \ + const Lcu_Ip_LogicOutputType LogicOutput##n##_3_Config = \ + LogicOutput_Config_Common(n, LogicOutput##n##_3_Cfg, \ + DT_INST_PROP_BY_IDX(n, lcu_output_filter_config, 9)) \ + \ + const Lcu_Ip_LogicOutputType \ + *const Lcu_Ip_ppxLogicOutputArray##n##_Config[LCU_IP_NOF_CFG_LOGIC_OUTPUTS] = { \ + &LogicOutput##n##_0_Config, \ + &LogicOutput##n##_1_Config, \ + &LogicOutput##n##_2_Config, \ + &LogicOutput##n##_3_Config, \ + }; \ + \ + const Lcu_Ip_LogicInputConfigType Lcu_Ip_LogicInputResetConfig##n = { \ + .MuxSel = LCU_IP_MUX_SEL_LOGIC_0, \ + .SwSynMode = LCU_IP_SW_SYNC_IMMEDIATE, \ + .SwValue = LCU_IP_SW_OVERRIDE_LOGIC_LOW, \ + }; \ + \ + const Lcu_Ip_LogicOutputConfigType Lcu_Ip_LogicOutputResetConfig##n = \ + LogicOutputCfg_Common(LCU_IP_DEBUG_DISABLE, 0U, 0U, 0U) \ + \ + const Lcu_Ip_LogicInstanceType LcuLogicInstance##n##_0_Config = { \ + .HwInstId = LCU_NXP_S32_GET_INSTANCE(DT_INST_PHANDLE(n, lcu)), \ + .NumLogicCellConfig = 0U, \ + .ppxLogicCellConfigArray = NULL_PTR, \ + .OperationMode = LCU_IP_INTERRUPT_MODE, \ + }; \ + const Lcu_Ip_LogicInstanceType \ + *const Lcu_Ip_ppxLogicInstanceArray##n##_Config[LCU_IP_NOF_CFG_LOGIC_INSTANCES] = { \ + &LcuLogicInstance##n##_0_Config, \ + }; \ + \ + Lcu_Ip_HwOutputStateType HwOutput##n##_0_State_Config; \ + Lcu_Ip_HwOutputStateType HwOutput##n##_1_State_Config; \ + Lcu_Ip_HwOutputStateType HwOutput##n##_2_State_Config; \ + Lcu_Ip_HwOutputStateType HwOutput##n##_3_State_Config; \ + Lcu_Ip_HwOutputStateType \ + *Lcu_Ip_ppxHwOutputStateArray##n##_Config[LCU_IP_NOF_CFG_LOGIC_OUTPUTS] = { \ + &HwOutput##n##_0_State_Config, \ + &HwOutput##n##_1_State_Config, \ + &HwOutput##n##_2_State_Config, \ + &HwOutput##n##_3_State_Config, \ + }; \ + \ + const Lcu_Ip_InitType Lcu_Ip_Init_Config##n = { \ + .ppxHwOutputStateArray = &Lcu_Ip_ppxHwOutputStateArray##n##_Config[0], \ + .ppxLogicInstanceConfigArray = &Lcu_Ip_ppxLogicInstanceArray##n##_Config[0], \ + .pxLogicOutputResetConfigArray = &Lcu_Ip_LogicOutputResetConfig##n, \ + .pxLogicInputResetConfigArray = &Lcu_Ip_LogicInputResetConfig##n, \ + .ppxLogicOutputConfigArray = &Lcu_Ip_ppxLogicOutputArray##n##_Config[0], \ + .ppxLogicInputConfigArray = &Lcu_Ip_ppxLogicInputArray##n##_Config[0], \ + }; + +#define Trgmux_Ip_LogicTrigger_Config(n, logic_channel, output, input) \ + { \ + .LogicChannel = logic_channel, \ + .Output = output, \ + .Input = input, \ + .HwInstId = TRGMUX_NXP_S32_GET_INSTANCE(DT_INST_PHANDLE(n, trgmux)), \ + .Lock = (boolean)FALSE, \ + }; + +#define TRGMUX_IP_INIT_CONFIG(n) \ + const Trgmux_Ip_LogicTriggerType \ + Trgmux_Ip_LogicTrigger##n##_0_Config = Trgmux_Ip_LogicTrigger_Config(n, \ + DT_INST_PROP_BY_IDX(n, trgmux_io_config, 0), \ + DT_INST_PROP_BY_IDX(n, trgmux_io_config, 1), \ + DT_INST_PROP_BY_IDX(n, trgmux_io_config, 2)) \ + const Trgmux_Ip_LogicTriggerType \ + Trgmux_Ip_LogicTrigger##n##_1_Config = Trgmux_Ip_LogicTrigger_Config(n, \ + DT_INST_PROP_BY_IDX(n, trgmux_io_config, 3), \ + DT_INST_PROP_BY_IDX(n, trgmux_io_config, 4), \ + DT_INST_PROP_BY_IDX(n, trgmux_io_config, 5)) \ + const Trgmux_Ip_LogicTriggerType \ + Trgmux_Ip_LogicTrigger##n##_2_Config = Trgmux_Ip_LogicTrigger_Config(n, \ + DT_INST_PROP_BY_IDX(n, trgmux_io_config, 6), \ + DT_INST_PROP_BY_IDX(n, trgmux_io_config, 7), \ + DT_INST_PROP_BY_IDX(n, trgmux_io_config, 8)) \ + const Trgmux_Ip_LogicTriggerType \ + Trgmux_Ip_LogicTrigger##n##_3_Config = Trgmux_Ip_LogicTrigger_Config(n, \ + DT_INST_PROP_BY_IDX(n, trgmux_io_config, 9), \ + DT_INST_PROP_BY_IDX(n, trgmux_io_config, 10), \ + DT_INST_PROP_BY_IDX(n, trgmux_io_config, 11)) \ + const Trgmux_Ip_InitType Trgmux_Ip_Init_##n##_Config = { \ + .paxLogicTrigger = { \ + &Trgmux_Ip_LogicTrigger##n##_0_Config, \ + &Trgmux_Ip_LogicTrigger##n##_1_Config, \ + &Trgmux_Ip_LogicTrigger##n##_2_Config, \ + &Trgmux_Ip_LogicTrigger##n##_3_Config, \ + }, \ + }; + + +#define QDEC_NXP_S32_INIT(n) \ + \ + static struct qdec_s32_data qdec_s32_##n##_data = { \ + .micro_ticks_per_rev = (float)(DT_INST_PROP(n, micro_ticks_per_rev) / 1000000), \ + .counter_CW = 1, \ + .counter_CCW = 1, \ + }; \ + \ + PINCTRL_DT_INST_DEFINE(n); \ + TRGMUX_IP_INIT_CONFIG(n) \ + LCU_IP_INIT_CONFIG(n) \ + EMIOS_NXP_S32_MCB_OVERFLOW_CALLBACK(n) \ + \ + static const struct qdec_s32_config qdec_s32_##n##_config = { \ + .emios_inst = EMIOS_NXP_S32_GET_INSTANCE(DT_INST_PHANDLE(n, emios)), \ + .pincfg = PINCTRL_DT_INST_DEV_CONFIG_GET(n), \ + .trgmux_config = &Trgmux_Ip_Init_##n##_Config, \ + .lcu_config = &Lcu_Ip_Init_Config##n, \ + .emios_channels = {DT_INST_PROP_BY_IDX(n, emios_channels, EMIOS_CW_CH_IDX), \ + DT_INST_PROP_BY_IDX(n, emios_channels, EMIOS_CCW_CH_IDX)}, \ + .emios_cw_overflow_cb = &qdec##n##_emios_overflow_count_cw_callback, \ + .emios_ccw_overflow_cb = &qdec##n##_emios_overflow_count_ccw_callback, \ + }; \ + \ + SENSOR_DEVICE_DT_INST_DEFINE(n, qdec_s32_initialize, NULL, &qdec_s32_##n##_data, \ + &qdec_s32_##n##_config, POST_KERNEL, \ + CONFIG_SENSOR_INIT_PRIORITY, &qdec_s32_api); + +DT_INST_FOREACH_STATUS_OKAY(QDEC_NXP_S32_INIT) diff --git a/dts/arm/nxp/nxp_s32k344_m7.dtsi b/dts/arm/nxp/nxp_s32k344_m7.dtsi index 036b89a540d..0289b24f42e 100644 --- a/dts/arm/nxp/nxp_s32k344_m7.dtsi +++ b/dts/arm/nxp/nxp_s32k344_m7.dtsi @@ -827,6 +827,24 @@ status = "disabled"; }; }; + + lcu0: lcu@40098000 { + compatible = "nxp,s32-lcu"; + reg = <0x40098000 0x4000>; + status = "disabled"; + }; + + lcu1: lcu@4009c000 { + compatible = "nxp,s32-lcu"; + reg = <0x4009c000 0x4000>; + status = "disabled"; + }; + + trgmux: trgmux@40080000 { + compatible = "nxp,s32-trgmux"; + reg = <0x40080000 0x4000>; + status = "disabled"; + }; }; }; diff --git a/dts/bindings/misc/nxp,s32-lcu.yaml b/dts/bindings/misc/nxp,s32-lcu.yaml new file mode 100644 index 00000000000..51707de20e8 --- /dev/null +++ b/dts/bindings/misc/nxp,s32-lcu.yaml @@ -0,0 +1,16 @@ +# Copyright 2023 NXP +# SPDX-License-Identifier: Apache-2.0 + +description: | + NXP S32 Logic control Unit node for S32 SoCs. + LCU selects multiple inputs from timers, Pulse Width Modulation + signals, and Input/Output (I/O) pads, and combines them + using a programmable logic function to create output waveforms + +compatible: "nxp,s32-lcu" + +include: [base.yaml] + +properties: + reg: + required: true diff --git a/dts/bindings/misc/nxp,s32-trgmux.yaml b/dts/bindings/misc/nxp,s32-trgmux.yaml new file mode 100644 index 00000000000..55a589d6836 --- /dev/null +++ b/dts/bindings/misc/nxp,s32-trgmux.yaml @@ -0,0 +1,16 @@ +# Copyright 2023 NXP +# SPDX-License-Identifier: Apache-2.0 + +description: | + NXP S32 Trigger Multiplexing Control node for S32 SoCs. + The device supports the triggering scheme between peripherals. + The supported trigger sources and destination can be found in + the device Ref Manual + +compatible: "nxp,s32-trgmux" + +include: [base.yaml] + +properties: + reg: + required: true diff --git a/dts/bindings/sensor/nxp,s32-qdec.yaml b/dts/bindings/sensor/nxp,s32-qdec.yaml new file mode 100644 index 00000000000..935d2122f23 --- /dev/null +++ b/dts/bindings/sensor/nxp,s32-qdec.yaml @@ -0,0 +1,112 @@ +# Copyright 2023 NXP +# SPDX-License-Identifier: Apache-2.0 + +description: | + Quadrature Decoder driver which processes encoder signals to determine motor revs + with the cooperation of S32 IP blocks- eMIOS, TRGMUX and LCU. + The sensor qdec application can be used for testing this driver. + The following example uses TRGMUX IN2 and IN3 to connect to LCU1 LC0 I0 and I1. + LCU1 LC0 O2 and O3 connect to eMIOS0 CH6(Clockwise rotation) and + CH7(Counter Clockwise rotation) via TRGMUX_INT_OUT37 and TRGMUX_INT_OUT38 + micro-ticks-per-rev is set as per vehicle gearbox reduction. + lcu output filters are set to capture maximum speed sensitivity and avoid channel noise. + + qdec0 { + compatible = "nxp,qdec-s32"; + pinctrl-0 = <&qdec_s32>; + pinctrl-names = "default"; + micro-ticks-per-rev = <685440000>; + status = "okay"; + trgmux = <&trgmux>; + trgmux-io-config = + <0 TRGMUX_IP_OUTPUT_EMIOS0_CH5_9_IPP_IND_CH6 TRGMUX_IP_INPUT_LCU1_LC0_OUT_I2>, + <1 TRGMUX_IP_OUTPUT_EMIOS0_CH5_9_IPP_IND_CH7 TRGMUX_IP_INPUT_LCU1_LC0_OUT_I3>, + <2 TRGMUX_IP_OUTPUT_LCU1_0_INP_I0 TRGMUX_IP_INPUT_SIUL2_IN2>, + <3 TRGMUX_IP_OUTPUT_LCU1_0_INP_I1 TRGMUX_IP_INPUT_SIUL2_IN3>; + lcu = <&lcu1>; + lcu-input-idx = <1>; + ; + lcu-mux-sel = + ; + lcu-output-filter-config = + /* LCU Out HW ID, Rise Filter, Fall Filter */ + <0 5 5>, /* LCU O0 */ + <1 5 5>, /* LCU O1 */ + <2 2 2>, /* LCU O2 */ + <3 2 2>; /* LCU O3 */ + emios = <&emios0>; + emios-channels = <6 7>; + }; + +compatible: "nxp,qdec-s32" + +include: [pinctrl-device.yaml, sensor-device.yaml] + +properties: + micro-ticks-per-rev: + type: int + description: | + This is a number that is used to determine how many revolutions * 1000000 + were done based on the current counter's value. + + trgmux: + type: phandle + description: | + phandle to the TRGMUX node. + + trgmux-io-config: + type: array + description: | + This gives the logic triggers configuration of TRGMUX module. + It contains 3 values for each of the 4 logic triggers used: + logic trigger number, output, input. + Hence, it's length should be '12'. + Ex: + trgmux-io-config = + <0 TRGMUX_IP_OUTPUT_EMIOS0_CH5_9_IPP_IND_CH6 TRGMUX_IP_INPUT_LCU1_LC0_OUT_I2>, + <1 TRGMUX_IP_OUTPUT_EMIOS0_CH5_9_IPP_IND_CH7 TRGMUX_IP_INPUT_LCU1_LC0_OUT_I3>, + <2 TRGMUX_IP_OUTPUT_LCU1_0_INP_I0 TRGMUX_IP_INPUT_SIUL2_IN2>, + <3 TRGMUX_IP_OUTPUT_LCU1_0_INP_I1 TRGMUX_IP_INPUT_SIUL2_IN3>; + + lcu: + type: phandle + description: | + phandle to the LCU node. + + emios: + type: phandle + description: | + phandle to the eMIOS node. + + lcu-output-filter-config: + type: array + description: | + This array gives the configuration for each of the four outputs of LCU module. + It contains the following for each output: hardware output id, rise filter and fall filter. + The filters specify the delay in terms of CORE_CLK between the input and output line of LC. + We use this delay to generate short pulses at the rising and falling edges of input pulse. + It's length should be '12' - 3 entries for each of the four LCU outputs. + Ex: lcu-output-filter-config = + /* LCU Out HW ID, Rise Filter, Fall Filter */ + <0 5 5>, /* LCU O0 */ + <1 5 5>, /* LCU O1 */ + <2 2 2>, /* LCU O2 */ + <3 2 2>; /* LCU O3 */ + + lcu-mux-sel: + type: array + description: | + This array configures the sources of input to the LCU module by programming the muxsel. + + lcu-input-idx: + type: array + description: | + This array configures the input indices to the LCU module which help to determine the + Logic Cell number used inside an LCU instance. + + emios-channels: + type: array + description: | + This is the array containing 2 emios channel TypeG numbers used by the qdec. diff --git a/include/zephyr/dt-bindings/sensor/qdec_nxp_s32.h b/include/zephyr/dt-bindings/sensor/qdec_nxp_s32.h new file mode 100644 index 00000000000..c7df471d929 --- /dev/null +++ b/include/zephyr/dt-bindings/sensor/qdec_nxp_s32.h @@ -0,0 +1,107 @@ +/* + * Copyright 2023 NXP + * + * SPDX-License-Identifier: Apache-2.0 + */ + +/* Logic Trigger Numbers. See Trgmux_Ip_Init_PBcfg.h */ +#define TRGMUX_LOGIC_GROUP_0_TRIGGER_0 (0) /* Logic Trigger 0 */ +#define TRGMUX_LOGIC_GROUP_0_TRIGGER_1 (1) /* Logic Trigger 1 */ +#define TRGMUX_LOGIC_GROUP_1_TRIGGER_0 (2) /* Logic Trigger 2 */ +#define TRGMUX_LOGIC_GROUP_1_TRIGGER_1 (3) /* Logic Trigger 3 */ + +/*----------------------------------------------- + * TRGMUX HARDWARE TRIGGER INPUT + * See Trgmux_Ip_Cfg_Defines.h + *----------------------------------------------- + */ +#define TRGMUX_IP_INPUT_SIUL2_IN0 (60) +#define TRGMUX_IP_INPUT_SIUL2_IN1 (61) +#define TRGMUX_IP_INPUT_SIUL2_IN2 (62) +#define TRGMUX_IP_INPUT_SIUL2_IN3 (63) +#define TRGMUX_IP_INPUT_SIUL2_IN4 (64) +#define TRGMUX_IP_INPUT_SIUL2_IN5 (65) +#define TRGMUX_IP_INPUT_SIUL2_IN6 (66) +#define TRGMUX_IP_INPUT_SIUL2_IN7 (67) +#define TRGMUX_IP_INPUT_SIUL2_IN8 (68) +#define TRGMUX_IP_INPUT_SIUL2_IN9 (69) +#define TRGMUX_IP_INPUT_SIUL2_IN10 (70) +#define TRGMUX_IP_INPUT_SIUL2_IN11 (71) +#define TRGMUX_IP_INPUT_SIUL2_IN12 (72) +#define TRGMUX_IP_INPUT_SIUL2_IN13 (73) +#define TRGMUX_IP_INPUT_SIUL2_IN14 (74) +#define TRGMUX_IP_INPUT_SIUL2_IN15 (75) + +#define TRGMUX_IP_INPUT_LCU1_LC0_OUT_I0 (105) +#define TRGMUX_IP_INPUT_LCU1_LC0_OUT_I1 (106) +#define TRGMUX_IP_INPUT_LCU1_LC0_OUT_I2 (107) +#define TRGMUX_IP_INPUT_LCU1_LC0_OUT_I3 (108) + +/*----------------------------------------------- + * TRGMUX HARDWARE TRIGGER OUTPUT + * See Trgmux_Ip_Cfg_Defines.h + *----------------------------------------------- + */ +#define TRGMUX_IP_OUTPUT_LCU1_0_INP_I0 (144) +#define TRGMUX_IP_OUTPUT_LCU1_0_INP_I1 (145) +#define TRGMUX_IP_OUTPUT_LCU1_0_INP_I2 (146) +#define TRGMUX_IP_OUTPUT_LCU1_0_INP_I3 (147) + +#define TRGMUX_IP_OUTPUT_EMIOS0_CH1_4_IPP_IND_CH1 (32) +#define TRGMUX_IP_OUTPUT_EMIOS0_CH1_4_IPP_IND_CH2 (33) +#define TRGMUX_IP_OUTPUT_EMIOS0_CH1_4_IPP_IND_CH3 (34) +#define TRGMUX_IP_OUTPUT_EMIOS0_CH1_4_IPP_IND_CH4 (35) +#define TRGMUX_IP_OUTPUT_EMIOS0_CH5_9_IPP_IND_CH5 (36) +#define TRGMUX_IP_OUTPUT_EMIOS0_CH5_9_IPP_IND_CH6 (37) +#define TRGMUX_IP_OUTPUT_EMIOS0_CH5_9_IPP_IND_CH7 (38) +#define TRGMUX_IP_OUTPUT_EMIOS0_CH5_9_IPP_IND_CH9 (39) +#define TRGMUX_IP_OUTPUT_EMIOS0_CH10_13_IPP_IND_CH10 (40) +#define TRGMUX_IP_OUTPUT_EMIOS0_CH10_13_IPP_IND_CH11 (41) +#define TRGMUX_IP_OUTPUT_EMIOS0_CH10_13_IPP_IND_CH12 (42) +#define TRGMUX_IP_OUTPUT_EMIOS0_CH10_13_IPP_IND_CH13 (43) +#define TRGMUX_IP_OUTPUT_EMIOS0_CH14_15_IPP_IND_CH14 (44) +#define TRGMUX_IP_OUTPUT_EMIOS0_CH14_15_IPP_IND_CH15 (45) + +/*----------------------------------------------- + * LCU SOURCE MUX SELECT + * See Lcu_Ip_Cfg_Defines.h + *----------------------------------------------- + */ +#define LCU_IP_MUX_SEL_LOGIC_0 (0) +#define LCU_IP_MUX_SEL_LU_IN_0 (1) +#define LCU_IP_MUX_SEL_LU_IN_1 (2) +#define LCU_IP_MUX_SEL_LU_IN_2 (3) +#define LCU_IP_MUX_SEL_LU_IN_3 (4) +#define LCU_IP_MUX_SEL_LU_IN_4 (5) +#define LCU_IP_MUX_SEL_LU_IN_5 (6) +#define LCU_IP_MUX_SEL_LU_IN_6 (7) +#define LCU_IP_MUX_SEL_LU_IN_7 (8) +#define LCU_IP_MUX_SEL_LU_IN_8 (9) +#define LCU_IP_MUX_SEL_LU_IN_9 (10) +#define LCU_IP_MUX_SEL_LU_IN_10 (11) +#define LCU_IP_MUX_SEL_LU_IN_11 (12) +#define LCU_IP_MUX_SEL_LU_OUT_0 (13) +#define LCU_IP_MUX_SEL_LU_OUT_1 (14) +#define LCU_IP_MUX_SEL_LU_OUT_2 (15) +#define LCU_IP_MUX_SEL_LU_OUT_3 (16) +#define LCU_IP_MUX_SEL_LU_OUT_4 (17) +#define LCU_IP_MUX_SEL_LU_OUT_5 (18) +#define LCU_IP_MUX_SEL_LU_OUT_6 (19) +#define LCU_IP_MUX_SEL_LU_OUT_7 (20) +#define LCU_IP_MUX_SEL_LU_OUT_8 (21) +#define LCU_IP_MUX_SEL_LU_OUT_9 (22) +#define LCU_IP_MUX_SEL_LU_OUT_10 (23) +#define LCU_IP_MUX_SEL_LU_OUT_11 (24) + +#define LCU_IP_IN_0 (0) +#define LCU_IP_IN_1 (1) +#define LCU_IP_IN_2 (2) +#define LCU_IP_IN_3 (3) +#define LCU_IP_IN_4 (4) +#define LCU_IP_IN_5 (5) +#define LCU_IP_IN_6 (6) +#define LCU_IP_IN_7 (7) +#define LCU_IP_IN_8 (8) +#define LCU_IP_IN_9 (9) +#define LCU_IP_IN_10 (10) +#define LCU_IP_IN_11 (11) From dfd846283b897b3eb247e5ecef497ee8afbf642f Mon Sep 17 00:00:00 2001 From: Keith Short Date: Wed, 29 Nov 2023 16:36:21 -0700 Subject: [PATCH 0858/3723] espi: ite: Fix driver Kconfig Update the Kconfig for the it8xxx2 eSPI driver so it's automatically enabled if the devicetree node is enabled. Signed-off-by: Keith Short --- drivers/espi/Kconfig.it8xxx2 | 2 ++ 1 file changed, 2 insertions(+) diff --git a/drivers/espi/Kconfig.it8xxx2 b/drivers/espi/Kconfig.it8xxx2 index 3b1ac7c436f..e018f869515 100644 --- a/drivers/espi/Kconfig.it8xxx2 +++ b/drivers/espi/Kconfig.it8xxx2 @@ -3,6 +3,8 @@ config ESPI_IT8XXX2 bool "ITE IT8XXX2 embedded controller ESPI driver" + default y + depends on DT_HAS_ITE_IT8XXX2_ESPI_ENABLED depends on SOC_IT8XXX2 help Enable ITE IT8XXX2 ESPI driver. From 411cc38f7605cab0c1755bced2f81097c8af6f70 Mon Sep 17 00:00:00 2001 From: Keith Short Date: Wed, 29 Nov 2023 17:00:09 -0700 Subject: [PATCH 0859/3723] samples: drivers: espi: Fix compile errors The espi_saf.h header has a dependency on the eSPI driver supporing SAF. Guard the include to fix builds of the Nuvoton eval boards. Signed-off-by: Keith Short --- samples/drivers/espi/src/main.c | 331 +++++++++++++------------------- 1 file changed, 137 insertions(+), 194 deletions(-) diff --git a/samples/drivers/espi/src/main.c b/samples/drivers/espi/src/main.c index 71f0a86d75a..ce6cb08c322 100644 --- a/samples/drivers/espi/src/main.c +++ b/samples/drivers/espi/src/main.c @@ -10,33 +10,37 @@ #include #include #include -#include #include #include #include /* OOB operations will be attempted regardless of channel enabled or not */ #include "espi_oob_handler.h" + +#ifdef CONFIG_ESPI_SAF +#include +#endif + LOG_MODULE_DECLARE(espi, CONFIG_ESPI_LOG_LEVEL); /* eSPI flash parameters */ -#define MAX_TEST_BUF_SIZE 1024u -#define MAX_FLASH_REQUEST 64u -#define TARGET_FLASH_REGION 0x72000ul +#define MAX_TEST_BUF_SIZE 1024u +#define MAX_FLASH_REQUEST 64u +#define TARGET_FLASH_REGION 0x72000ul -#define ESPI_FREQ_20MHZ 20u -#define ESPI_FREQ_25MHZ 25u -#define ESPI_FREQ_66MHZ 66u +#define ESPI_FREQ_20MHZ 20u +#define ESPI_FREQ_25MHZ 25u +#define ESPI_FREQ_66MHZ 66u -#define K_WAIT_DELAY 100u +#define K_WAIT_DELAY 100u /* eSPI event */ -#define EVENT_MASK 0x0000FFFFu -#define EVENT_DETAILS_MASK 0xFFFF0000u -#define EVENT_DETAILS_POS 16u -#define EVENT_TYPE(x) (x & EVENT_MASK) -#define EVENT_DETAILS(x) ((x & EVENT_DETAILS_MASK) >> EVENT_DETAILS_POS) +#define EVENT_MASK 0x0000FFFFu +#define EVENT_DETAILS_MASK 0xFFFF0000u +#define EVENT_DETAILS_POS 16u +#define EVENT_TYPE(x) (x & EVENT_MASK) +#define EVENT_DETAILS(x) ((x & EVENT_DETAILS_MASK) >> EVENT_DETAILS_POS) -#define PWR_SEQ_TIMEOUT 3000u +#define PWR_SEQ_TIMEOUT 3000u /* The devicetree node identifier for the board power rails pins. */ #define BRD_PWR_NODE DT_NODELABEL(board_power) @@ -62,25 +66,25 @@ static uint8_t flash_read_buf[MAX_TEST_BUF_SIZE]; #endif #ifdef CONFIG_ESPI_SAF -#define SAF_BASE_ADDR DT_REG_ADDR(DT_NODELABEL(espi_saf0)) +#define SAF_BASE_ADDR DT_REG_ADDR(DT_NODELABEL(espi_saf0)) -#define SAF_TEST_FREQ_HZ 24000000U +#define SAF_TEST_FREQ_HZ 24000000U #define SAF_TEST_BUF_SIZE 4096U /* SPI address of 4KB sector modified by test */ #define SAF_SPI_TEST_ADDRESS 0x1000U -#define SPI_WRITE_STATUS1 0x01U -#define SPI_WRITE_STATUS2 0x31U -#define SPI_WRITE_DISABLE 0x04U -#define SPI_READ_STATUS1 0x05U -#define SPI_WRITE_ENABLE 0x06U -#define SPI_READ_STATUS2 0x35U +#define SPI_WRITE_STATUS1 0x01U +#define SPI_WRITE_STATUS2 0x31U +#define SPI_WRITE_DISABLE 0x04U +#define SPI_READ_STATUS1 0x05U +#define SPI_WRITE_ENABLE 0x06U +#define SPI_READ_STATUS2 0x35U #define SPI_WRITE_ENABLE_VS 0x50U -#define SPI_READ_JEDEC_ID 0x9FU +#define SPI_READ_JEDEC_ID 0x9FU #define SPI_STATUS1_BUSY 0x80U -#define SPI_STATUS2_QE 0x02U +#define SPI_STATUS2_QE 0x02U #define W25Q128_JEDEC_ID 0x001840efU @@ -95,10 +99,8 @@ struct saf_addr_info { uintptr_t saf_struct_addr; uintptr_t saf_exp_addr; }; -static const struct device *const qspi_dev = - DEVICE_DT_GET(DT_NODELABEL(spi0)); -static const struct device *const espi_saf_dev = - DEVICE_DT_GET(DT_NODELABEL(espi_saf0)); +static const struct device *const qspi_dev = DEVICE_DT_GET(DT_NODELABEL(spi0)); +static const struct device *const espi_saf_dev = DEVICE_DT_GET(DT_NODELABEL(espi_saf0)); static uint8_t safbuf[SAF_TEST_BUF_SIZE] __aligned(4); static uint8_t safbuf2[SAF_TEST_BUF_SIZE] __aligned(4); @@ -116,15 +118,8 @@ static const struct espi_saf_flash_cfg flash_w25q128 = { .cont_prefix = 0U, .cs_cfg_descr_ids = MCHP_CS0_CFG_DESCR_IDX_REG_VAL, .flags = 0, - .descr = { - MCHP_W25Q128_CM_RD_D0, - MCHP_W25Q128_CM_RD_D1, - MCHP_W25Q128_CM_RD_D2, - MCHP_W25Q128_ENTER_CM_D0, - MCHP_W25Q128_ENTER_CM_D1, - MCHP_W25Q128_ENTER_CM_D2 - } -}; + .descr = {MCHP_W25Q128_CM_RD_D0, MCHP_W25Q128_CM_RD_D1, MCHP_W25Q128_CM_RD_D2, + MCHP_W25Q128_ENTER_CM_D0, MCHP_W25Q128_ENTER_CM_D1, MCHP_W25Q128_ENTER_CM_D2}}; /* * SAF driver configuration. @@ -136,37 +131,27 @@ static const struct espi_saf_flash_cfg flash_w25q128 = { #ifdef CONFIG_ESPI_SAF_XEC_V2 static const struct espi_saf_cfg saf_cfg1 = { .nflash_devices = 1U, - .hwcfg = { - .version = 2U, /* TODO */ - .flags = 0U, /* TODO */ - .qmspi_cpha = 0U, /* TODO */ - .qmspi_cs_timing = 0U, /* TODO */ - .flash_pd_timeout = 0U, /* TODO */ - .flash_pd_min_interval = 0U, /* TODO */ - .generic_descr = { - MCHP_SAF_EXIT_CM_DESCR12, MCHP_SAF_EXIT_CM_DESCR13, - MCHP_SAF_POLL_DESCR14, MCHP_SAF_POLL_DESCR15 - }, - .tag_map = { 0U, 0U, 0U } - }, - .flash_cfgs = (struct espi_saf_flash_cfg *)&flash_w25q128 -}; + .hwcfg = {.version = 2U, /* TODO */ + .flags = 0U, /* TODO */ + .qmspi_cpha = 0U, /* TODO */ + .qmspi_cs_timing = 0U, /* TODO */ + .flash_pd_timeout = 0U, /* TODO */ + .flash_pd_min_interval = 0U, /* TODO */ + .generic_descr = {MCHP_SAF_EXIT_CM_DESCR12, MCHP_SAF_EXIT_CM_DESCR13, + MCHP_SAF_POLL_DESCR14, MCHP_SAF_POLL_DESCR15}, + .tag_map = {0U, 0U, 0U}}, + .flash_cfgs = (struct espi_saf_flash_cfg *)&flash_w25q128}; #else static const struct espi_saf_cfg saf_cfg1 = { .nflash_devices = 1U, - .hwcfg = { - .qmspi_freq_hz = 0U, - .qmspi_cs_timing = 0U, - .qmspi_cpha = 0U, - .flags = 0U, - .generic_descr = { - MCHP_SAF_EXIT_CM_DESCR12, MCHP_SAF_EXIT_CM_DESCR13, - MCHP_SAF_POLL_DESCR14, MCHP_SAF_POLL_DESCR15 - }, - .tag_map = { 0U, 0U, 0U } - }, - .flash_cfgs = (struct espi_saf_flash_cfg *)&flash_w25q128 -}; + .hwcfg = {.qmspi_freq_hz = 0U, + .qmspi_cs_timing = 0U, + .qmspi_cpha = 0U, + .flags = 0U, + .generic_descr = {MCHP_SAF_EXIT_CM_DESCR12, MCHP_SAF_EXIT_CM_DESCR13, + MCHP_SAF_POLL_DESCR14, MCHP_SAF_POLL_DESCR15}, + .tag_map = {0U, 0U, 0U}}, + .flash_cfgs = (struct espi_saf_flash_cfg *)&flash_w25q128}; #endif /* @@ -175,28 +160,24 @@ static const struct espi_saf_cfg saf_cfg1 = { static const struct espi_saf_pr w25q128_protect_regions[2] = { { .start = 0xe00000U, - .size = 0x100000U, + .size = 0x100000U, .master_bm_we = (1U << MCHP_SAF_MSTR_HOST_PCH_ME), .master_bm_rd = (1U << MCHP_SAF_MSTR_HOST_PCH_ME), .pr_num = 1U, - .flags = MCHP_SAF_PR_FLAG_ENABLE - | MCHP_SAF_PR_FLAG_LOCK, + .flags = MCHP_SAF_PR_FLAG_ENABLE | MCHP_SAF_PR_FLAG_LOCK, }, { .start = 0xf00000U, - .size = 0x100000U, + .size = 0x100000U, .master_bm_we = (1U << MCHP_SAF_MSTR_HOST_PCH_LAN), .master_bm_rd = (1U << MCHP_SAF_MSTR_HOST_PCH_LAN), .pr_num = 2U, - .flags = MCHP_SAF_PR_FLAG_ENABLE - | MCHP_SAF_PR_FLAG_LOCK, + .flags = MCHP_SAF_PR_FLAG_ENABLE | MCHP_SAF_PR_FLAG_LOCK, }, }; -static const struct espi_saf_protection saf_pr_w25q128 = { - .nregions = 2U, - .pregions = w25q128_protect_regions -}; +static const struct espi_saf_protection saf_pr_w25q128 = {.nregions = 2U, + .pregions = w25q128_protect_regions}; /* * Initialize the local attached SPI flash. @@ -230,8 +211,7 @@ int spi_saf_init(void) memset(safbuf2, 0x55, 4U); spi_cfg.frequency = SAF_TEST_FREQ_HZ; - spi_cfg.operation = SPI_OP_MODE_MASTER | SPI_TRANSFER_MSB - | SPI_WORD_SET(8); + spi_cfg.operation = SPI_OP_MODE_MASTER | SPI_TRANSFER_MSB | SPI_WORD_SET(8); /* * Use SPI master mode and inform driver the SPI controller hardware @@ -313,13 +293,13 @@ int spi_saf_init(void) rx_bufs.buffers = NULL; rx_bufs.count = 0U; - ret = spi_transceive(qspi_dev, - (const struct spi_config *)&spi_cfg, + ret = spi_transceive(qspi_dev, (const struct spi_config *)&spi_cfg, (const struct spi_buf_set *)&tx_bufs, (const struct spi_buf_set *)&rx_bufs); if (ret) { LOG_ERR("Send write enable volatile spi_transceive" - " failure: error %d", ret); + " failure: error %d", + ret); return ret; } @@ -335,13 +315,13 @@ int spi_saf_init(void) rx_bufs.buffers = NULL; rx_bufs.count = 0U; - ret = spi_transceive(qspi_dev, - (const struct spi_config *)&spi_cfg, + ret = spi_transceive(qspi_dev, (const struct spi_config *)&spi_cfg, (const struct spi_buf_set *)&tx_bufs, (const struct spi_buf_set *)&rx_bufs); if (ret) { LOG_ERR("Write SPI STATUS2 QE=1 spi_transceive" - " failure: error %d", ret); + " failure: error %d", + ret); return ret; } @@ -362,20 +342,21 @@ int spi_saf_init(void) rx_bufs.buffers = (const struct spi_buf *)&rxb; rx_bufs.count = 1U; - ret = spi_transceive(qspi_dev, - (const struct spi_config *)&spi_cfg, + ret = spi_transceive(qspi_dev, (const struct spi_config *)&spi_cfg, (const struct spi_buf_set *)&tx_bufs, (const struct spi_buf_set *)&rx_bufs); if (ret) { LOG_ERR("Read SPI STATUS1 spi_transceive" - " failure: error %d", ret); + " failure: error %d", + ret); return ret; } spi_status1 = safbuf2[0]; if (spi_status1 & SPI_STATUS1_BUSY) { LOG_ERR("SPI BUSY set after write to volatile STATUS2:" - " STATUS1=0x%02X", spi_status1); + " STATUS1=0x%02X", + spi_status1); return ret; } @@ -396,13 +377,13 @@ int spi_saf_init(void) rx_bufs.buffers = (const struct spi_buf *)&rxb; rx_bufs.count = 1U; - ret = spi_transceive(qspi_dev, - (const struct spi_config *)&spi_cfg, + ret = spi_transceive(qspi_dev, (const struct spi_config *)&spi_cfg, (const struct spi_buf_set *)&tx_bufs, (const struct spi_buf_set *)&rx_bufs); if (ret) { LOG_ERR("Read 2 of SPI STATUS2 spi_transceive" - " failure: error %d", ret); + " failure: error %d", + ret); return ret; } @@ -429,8 +410,7 @@ int espi_saf_init(void) LOG_INF("eSPI SAF configured successfully!"); } - ret = espi_saf_set_protection_regions(espi_saf_dev, - &saf_pr_w25q128); + ret = espi_saf_set_protection_regions(espi_saf_dev, &saf_pr_w25q128); if (ret) { LOG_ERR("Failed to set SAF protection region(s) %d", ret); } else { @@ -440,8 +420,7 @@ int espi_saf_init(void) return ret; } -static int pr_check_range(struct mchp_espi_saf *regs, - const struct espi_saf_pr *pr) +static int pr_check_range(struct mchp_espi_saf *regs, const struct espi_saf_pr *pr) { uint32_t limit; @@ -459,17 +438,14 @@ static int pr_check_range(struct mchp_espi_saf *regs, return 0; } -static int pr_check_enable(struct mchp_espi_saf *regs, - const struct espi_saf_pr *pr) +static int pr_check_enable(struct mchp_espi_saf *regs, const struct espi_saf_pr *pr) { if (pr->flags & MCHP_SAF_PR_FLAG_ENABLE) { - if (regs->SAF_PROT_RG[pr->pr_num].LIMIT > - regs->SAF_PROT_RG[pr->pr_num].START) { + if (regs->SAF_PROT_RG[pr->pr_num].LIMIT > regs->SAF_PROT_RG[pr->pr_num].START) { return 0; } } else { - if (regs->SAF_PROT_RG[pr->pr_num].START > - regs->SAF_PROT_RG[pr->pr_num].LIMIT) { + if (regs->SAF_PROT_RG[pr->pr_num].START > regs->SAF_PROT_RG[pr->pr_num].LIMIT) { return 0; } } @@ -477,8 +453,7 @@ static int pr_check_enable(struct mchp_espi_saf *regs, return -2; } -static int pr_check_lock(struct mchp_espi_saf *regs, - const struct espi_saf_pr *pr) +static int pr_check_lock(struct mchp_espi_saf *regs, const struct espi_saf_pr *pr) { if (pr->flags & MCHP_SAF_PR_FLAG_LOCK) { if (regs->SAF_PROT_LOCK & BIT(pr->pr_num)) { @@ -496,16 +471,13 @@ static int pr_check_lock(struct mchp_espi_saf *regs, /* * NOTE: bit[0] of bit map registers is read-only = 1 */ -static int pr_check_master_bm(struct mchp_espi_saf *regs, - const struct espi_saf_pr *pr) +static int pr_check_master_bm(struct mchp_espi_saf *regs, const struct espi_saf_pr *pr) { - if (regs->SAF_PROT_RG[pr->pr_num].WEBM != - (pr->master_bm_we | BIT(0))) { + if (regs->SAF_PROT_RG[pr->pr_num].WEBM != (pr->master_bm_we | BIT(0))) { return -4; } - if (regs->SAF_PROT_RG[pr->pr_num].RDBM != - (pr->master_bm_rd | BIT(0))) { + if (regs->SAF_PROT_RG[pr->pr_num].RDBM != (pr->master_bm_rd | BIT(0))) { return -4; } @@ -530,29 +502,25 @@ static int espi_saf_test_pr1(const struct espi_saf_protection *spr) for (size_t n = 0U; n < spr->nregions; n++) { rc = pr_check_range(saf_regs, pr); if (rc) { - LOG_INF("SAF Protection region %u range fail", - pr->pr_num); + LOG_INF("SAF Protection region %u range fail", pr->pr_num); return rc; } rc = pr_check_enable(saf_regs, pr); if (rc) { - LOG_INF("SAF Protection region %u enable fail", - pr->pr_num); + LOG_INF("SAF Protection region %u enable fail", pr->pr_num); return rc; } rc = pr_check_lock(saf_regs, pr); if (rc) { - LOG_INF("SAF Protection region %u lock check fail", - pr->pr_num); + LOG_INF("SAF Protection region %u lock check fail", pr->pr_num); return rc; } rc = pr_check_master_bm(saf_regs, pr); if (rc) { - LOG_INF("SAF Protection region %u Master select fail", - pr->pr_num); + LOG_INF("SAF Protection region %u Master select fail", pr->pr_num); return rc; } @@ -568,7 +536,7 @@ static int espi_saf_test_pr1(const struct espi_saf_protection *spr) static int saf_read(uint32_t spi_addr, uint8_t *dest, int len) { int rc, chunk_len, n; - struct espi_saf_packet saf_pkt = { 0 }; + struct espi_saf_packet saf_pkt = {0}; if ((dest == NULL) || (len < 0)) { return -EINVAL; @@ -589,8 +557,8 @@ static int saf_read(uint32_t spi_addr, uint8_t *dest, int len) rc = espi_saf_flash_read(espi_saf_dev, &saf_pkt); if (rc != 0) { LOG_INF("%s: error = %d: chunk_len = %d " - "spi_addr = %x", __func__, rc, chunk_len, - spi_addr); + "spi_addr = %x", + __func__, rc, chunk_len, spi_addr); return rc; } @@ -610,7 +578,7 @@ static int saf_read(uint32_t spi_addr, uint8_t *dest, int len) static int saf_erase_block(uint32_t spi_addr, enum saf_erase_size ersz) { int rc; - struct espi_saf_packet saf_pkt = { 0 }; + struct espi_saf_packet saf_pkt = {0}; switch (ersz) { case SAF_ERASE_4K: @@ -646,7 +614,7 @@ static int saf_erase_block(uint32_t spi_addr, enum saf_erase_size ersz) static int saf_page_prog(uint32_t spi_addr, const uint8_t *src, int progsz) { int rc, chunk_len, n; - struct espi_saf_packet saf_pkt = { 0 }; + struct espi_saf_packet saf_pkt = {0}; if ((src == NULL) || (progsz < 0) || (progsz > 256)) { return -EINVAL; @@ -670,8 +638,8 @@ static int saf_page_prog(uint32_t spi_addr, const uint8_t *src, int progsz) rc = espi_saf_flash_write(espi_saf_dev, &saf_pkt); if (rc != 0) { - LOG_INF("%s: error = %d: erase fail spi_addr = 0x%X", - __func__, rc, spi_addr); + LOG_INF("%s: error = %d: erase fail spi_addr = 0x%X", __func__, rc, + spi_addr); return rc; } @@ -683,7 +651,6 @@ static int saf_page_prog(uint32_t spi_addr, const uint8_t *src, int progsz) return progsz; } - int espi_saf_test1(uint32_t spi_addr) { int rc, retries; @@ -694,11 +661,9 @@ int espi_saf_test1(uint32_t spi_addr) LOG_INF("%s: activate = %d", __func__, rc); if (spi_addr & 0xfffU) { - LOG_INF("%s: SPI address 0x%08x not 4KB aligned", __func__, - spi_addr); - spi_addr &= ~(4096U-1U); - LOG_INF("%s: Aligned SPI address to 0x%08x", __func__, - spi_addr); + LOG_INF("%s: SPI address 0x%08x not 4KB aligned", __func__, spi_addr); + spi_addr &= ~(4096U - 1U); + LOG_INF("%s: Aligned SPI address to 0x%08x", __func__, spi_addr); } memset(safbuf, 0x55, sizeof(safbuf)); @@ -710,8 +675,8 @@ int espi_saf_test1(uint32_t spi_addr) /* read 4KB sector at 0 */ rc = saf_read(spi_addr, safbuf, 4096); if (rc != 4096) { - LOG_INF("%s: error=%d Read 4K sector at 0x%X failed", - __func__, rc, spi_addr); + LOG_INF("%s: error=%d Read 4K sector at 0x%X failed", __func__, rc, + spi_addr); return rc; } @@ -725,23 +690,25 @@ int espi_saf_test1(uint32_t spi_addr) if (rc == 0) { LOG_INF("4KB sector at 0x%x is in erased state. " - "Continue tests", spi_addr); + "Continue tests", + spi_addr); erased = true; } else { LOG_INF("4KB sector at 0x%x not in erased state. " - "Send 4K erase.", spi_addr); + "Send 4K erase.", + spi_addr); rc = saf_erase_block(spi_addr, SAF_ERASE_4K); if (rc != 0) { LOG_INF("SAF erase block at 0x%x returned " - "error %d", spi_addr, rc); + "error %d", + spi_addr, rc); return rc; } } } if (!erased) { - LOG_INF("%s: Could not erase 4KB sector at 0x%08x", - __func__, spi_addr); + LOG_INF("%s: Could not erase 4KB sector at 0x%08x", __func__, spi_addr); return -1; } @@ -762,11 +729,9 @@ int espi_saf_test1(uint32_t spi_addr) LOG_INF("%s: Program 4KB sector at 0x%X", __func__, saddr); while (n < progsz) { - rc = saf_page_prog(saddr, (const uint8_t *)src, - (int)chunksz); + rc = saf_page_prog(saddr, (const uint8_t *)src, (int)chunksz); if (rc != chunksz) { - LOG_INF("saf_page_prog error=%d at 0x%X", rc, - saddr); + LOG_INF("saf_page_prog error=%d at 0x%X", rc, saddr); break; } saddr += chunksz; @@ -801,17 +766,14 @@ static void host_warn_handler(uint32_t signal, uint32_t status) LOG_INF("Host reset warning %d", status); if (!IS_ENABLED(CONFIG_ESPI_AUTOMATIC_WARNING_ACKNOWLEDGE)) { LOG_INF("HOST RST ACK %d", status); - espi_send_vwire(espi_dev, - ESPI_VWIRE_SIGNAL_HOST_RST_ACK, - status); + espi_send_vwire(espi_dev, ESPI_VWIRE_SIGNAL_HOST_RST_ACK, status); } break; case ESPI_VWIRE_SIGNAL_SUS_WARN: LOG_INF("Host suspend warning %d", status); if (!IS_ENABLED(CONFIG_ESPI_AUTOMATIC_WARNING_ACKNOWLEDGE)) { LOG_INF("SUS ACK %d", status); - espi_send_vwire(espi_dev, ESPI_VWIRE_SIGNAL_SUS_ACK, - status); + espi_send_vwire(espi_dev, ESPI_VWIRE_SIGNAL_SUS_ACK, status); } break; default: @@ -820,8 +782,7 @@ static void host_warn_handler(uint32_t signal, uint32_t status) } /* eSPI bus event handler */ -static void espi_reset_handler(const struct device *dev, - struct espi_callback *cb, +static void espi_reset_handler(const struct device *dev, struct espi_callback *cb, struct espi_event event) { if (event.evt_type == ESPI_BUS_RESET) { @@ -831,8 +792,7 @@ static void espi_reset_handler(const struct device *dev, } /* eSPI logical channels enable/disable event handler */ -static void espi_ch_handler(const struct device *dev, - struct espi_callback *cb, +static void espi_ch_handler(const struct device *dev, struct espi_callback *cb, struct espi_event event) { if (event.evt_type == ESPI_BUS_EVENT_CHANNEL_READY) { @@ -868,8 +828,7 @@ static void vwire_handler(const struct device *dev, struct espi_callback *cb, break; case ESPI_VWIRE_SIGNAL_SUS_WARN: case ESPI_VWIRE_SIGNAL_HOST_RST_WARN: - host_warn_handler(event.evt_details, - event.evt_data); + host_warn_handler(event.evt_details, event.evt_data); break; } } @@ -894,8 +853,7 @@ static void periph_handler(const struct device *dev, struct espi_callback *cb, espi_remove_callback(espi_dev, &p80_cb); break; default: - LOG_INF("%s periph 0x%x [%x]", __func__, periph_type, - event.evt_data); + LOG_INF("%s periph 0x%x [%x]", __func__, periph_type, event.evt_data); } } @@ -923,8 +881,8 @@ int espi_init(void) ret = espi_config(espi_dev, &cfg); if (ret) { - LOG_ERR("Failed to configure eSPI slave channels:%x err: %d", - cfg.channel_caps, ret); + LOG_ERR("Failed to configure eSPI slave channels:%x err: %d", cfg.channel_caps, + ret); return ret; } else { LOG_INF("eSPI slave configured successfully!"); @@ -932,15 +890,11 @@ int espi_init(void) LOG_INF("eSPI test - callbacks initialization... "); espi_init_callback(&espi_bus_cb, espi_reset_handler, ESPI_BUS_RESET); - espi_init_callback(&vw_rdy_cb, espi_ch_handler, - ESPI_BUS_EVENT_CHANNEL_READY); - espi_init_callback(&vw_cb, vwire_handler, - ESPI_BUS_EVENT_VWIRE_RECEIVED); - espi_init_callback(&p80_cb, periph_handler, - ESPI_BUS_PERIPHERAL_NOTIFICATION); + espi_init_callback(&vw_rdy_cb, espi_ch_handler, ESPI_BUS_EVENT_CHANNEL_READY); + espi_init_callback(&vw_cb, vwire_handler, ESPI_BUS_EVENT_VWIRE_RECEIVED); + espi_init_callback(&p80_cb, periph_handler, ESPI_BUS_PERIPHERAL_NOTIFICATION); #ifdef CONFIG_ESPI_OOB_CHANNEL_RX_ASYNC - espi_init_callback(&oob_cb, oob_rx_handler, - ESPI_BUS_EVENT_OOB_RECEIVED); + espi_init_callback(&oob_cb, oob_rx_handler, ESPI_BUS_EVENT_OOB_RECEIVED); #endif LOG_INF("complete"); @@ -988,8 +942,7 @@ static int wait_for_pin(const struct gpio_dt_spec *gpio, uint16_t timeout, int e } #endif -static int wait_for_vwire(const struct device *espi_dev, - enum espi_vwire_signal signal, +static int wait_for_vwire(const struct device *espi_dev, enum espi_vwire_signal signal, uint16_t timeout, uint8_t exp_level) { int ret; @@ -1043,30 +996,30 @@ int espi_handshake(void) int ret; LOG_INF("eSPI test - Handshake with eSPI master..."); - ret = wait_for_vwire(espi_dev, ESPI_VWIRE_SIGNAL_SUS_WARN, - CONFIG_ESPI_VIRTUAL_WIRE_TIMEOUT, 1); + ret = wait_for_vwire(espi_dev, ESPI_VWIRE_SIGNAL_SUS_WARN, CONFIG_ESPI_VIRTUAL_WIRE_TIMEOUT, + 1); if (ret) { LOG_ERR("SUS_WARN Timeout"); return ret; } LOG_INF("1st phase completed"); - ret = wait_for_vwire(espi_dev, ESPI_VWIRE_SIGNAL_SLP_S5, - CONFIG_ESPI_VIRTUAL_WIRE_TIMEOUT, 1); + ret = wait_for_vwire(espi_dev, ESPI_VWIRE_SIGNAL_SLP_S5, CONFIG_ESPI_VIRTUAL_WIRE_TIMEOUT, + 1); if (ret) { LOG_ERR("SLP_S5 Timeout"); return ret; } - ret = wait_for_vwire(espi_dev, ESPI_VWIRE_SIGNAL_SLP_S4, - CONFIG_ESPI_VIRTUAL_WIRE_TIMEOUT, 1); + ret = wait_for_vwire(espi_dev, ESPI_VWIRE_SIGNAL_SLP_S4, CONFIG_ESPI_VIRTUAL_WIRE_TIMEOUT, + 1); if (ret) { LOG_ERR("SLP_S4 Timeout"); return ret; } - ret = wait_for_vwire(espi_dev, ESPI_VWIRE_SIGNAL_SLP_S3, - CONFIG_ESPI_VIRTUAL_WIRE_TIMEOUT, 1); + ret = wait_for_vwire(espi_dev, ESPI_VWIRE_SIGNAL_SLP_S3, CONFIG_ESPI_VIRTUAL_WIRE_TIMEOUT, + 1); if (ret) { LOG_ERR("SLP_S3 Timeout"); return ret; @@ -1074,8 +1027,8 @@ int espi_handshake(void) LOG_INF("2nd phase completed"); - ret = wait_for_vwire(espi_dev, ESPI_VWIRE_SIGNAL_PLTRST, - CONFIG_ESPI_VIRTUAL_WIRE_TIMEOUT, 1); + ret = wait_for_vwire(espi_dev, ESPI_VWIRE_SIGNAL_PLTRST, CONFIG_ESPI_VIRTUAL_WIRE_TIMEOUT, + 1); if (ret) { LOG_ERR("PLT_RST Timeout"); return ret; @@ -1091,7 +1044,7 @@ int read_test_block(uint8_t *buf, uint32_t start_flash_adr, uint16_t block_len) { uint8_t i = 0; uint32_t flash_addr = start_flash_adr; - uint16_t transactions = block_len/MAX_FLASH_REQUEST; + uint16_t transactions = block_len / MAX_FLASH_REQUEST; int ret = 0; struct espi_flash_packet pckt; @@ -1118,7 +1071,7 @@ int write_test_block(uint8_t *buf, uint32_t start_flash_adr, uint16_t block_len) { uint8_t i = 0; uint32_t flash_addr = start_flash_adr; - uint16_t transactions = block_len/MAX_FLASH_REQUEST; + uint16_t transactions = block_len / MAX_FLASH_REQUEST; int ret = 0; struct espi_flash_packet pckt; @@ -1154,8 +1107,7 @@ static int espi_flash_test(uint32_t start_flash_addr, uint8_t blocks) pattern = 0x99; for (i = 0; i <= blocks; i++) { memset(flash_write_buf, pattern++, sizeof(flash_write_buf)); - ret = write_test_block(flash_write_buf, flash_addr, - sizeof(flash_write_buf)); + ret = write_test_block(flash_write_buf, flash_addr, sizeof(flash_write_buf)); if (ret) { LOG_ERR("Failed to write to eSPI"); return ret; @@ -1172,20 +1124,17 @@ static int espi_flash_test(uint32_t start_flash_addr, uint8_t blocks) memset(flash_write_buf, pattern, sizeof(flash_write_buf)); /* Clear last read content */ memset(flash_read_buf, 0, sizeof(flash_read_buf)); - ret = read_test_block(flash_read_buf, flash_addr, - sizeof(flash_read_buf)); + ret = read_test_block(flash_read_buf, flash_addr, sizeof(flash_read_buf)); if (ret) { LOG_ERR("Failed to read from eSPI"); return ret; } /* Compare buffers */ - int cmp = memcmp(flash_write_buf, flash_read_buf, - sizeof(flash_write_buf)); + int cmp = memcmp(flash_write_buf, flash_read_buf, sizeof(flash_write_buf)); if (cmp != 0) { - LOG_ERR("eSPI read mismmatch at %d expected %x", - cmp, pattern); + LOG_ERR("eSPI read mismmatch at %d expected %x", cmp, pattern); } flash_addr += sizeof(flash_read_buf); @@ -1202,8 +1151,7 @@ static void send_slave_bootdone(void) int ret; uint8_t boot_done; - ret = espi_receive_vwire(espi_dev, ESPI_VWIRE_SIGNAL_SLV_BOOT_DONE, - &boot_done); + ret = espi_receive_vwire(espi_dev, ESPI_VWIRE_SIGNAL_SLV_BOOT_DONE, &boot_done); LOG_INF("%s boot_done: %d", __func__, boot_done); if (ret) { LOG_WRN("Fail to retrieve slave boot done"); @@ -1293,7 +1241,6 @@ int espi_test(void) return ret; } - ret = espi_saf_test_pr1(&saf_pr_w25q128); if (ret) { LOG_INF("eSPI SAF test pr1 returned error %d", ret); @@ -1334,16 +1281,13 @@ int espi_test(void) k_sleep(K_SECONDS(2)); do { - vw_ch_sts = espi_get_channel_status(espi_dev, - ESPI_CHANNEL_VWIRE); + vw_ch_sts = espi_get_channel_status(espi_dev, ESPI_CHANNEL_VWIRE); k_busy_wait(100); } while (!vw_ch_sts); - send_slave_bootdone(); #endif - #ifdef CONFIG_ESPI_FLASH_CHANNEL /* Flash operation need to be perform before VW handshake or * after eSPI host completes full initialization. @@ -1353,8 +1297,7 @@ int espi_test(void) bool flash_sts; do { - flash_sts = espi_get_channel_status(espi_dev, - ESPI_CHANNEL_FLASH); + flash_sts = espi_get_channel_status(espi_dev, ESPI_CHANNEL_FLASH); k_busy_wait(100); } while (!flash_sts); From 8fb92ba9cda8a3767f013dc43b7a135e89cb6f07 Mon Sep 17 00:00:00 2001 From: Keith Short Date: Wed, 29 Nov 2023 16:36:21 -0700 Subject: [PATCH 0860/3723] espi: npcx: Fix driver Kconfig Update the Kconfig for the npcx eSPI driver so it's automatically enabled if the devicetree node is enabled. Signed-off-by: Keith Short --- drivers/espi/Kconfig.npcx | 2 ++ soc/arm/nuvoton_npcx/npcx4/Kconfig.defconfig.series | 4 ---- soc/arm/nuvoton_npcx/npcx7/Kconfig.defconfig.series | 4 ---- soc/arm/nuvoton_npcx/npcx9/Kconfig.defconfig.series | 4 ---- 4 files changed, 2 insertions(+), 12 deletions(-) diff --git a/drivers/espi/Kconfig.npcx b/drivers/espi/Kconfig.npcx index d0680565a6d..69a7087fce7 100644 --- a/drivers/espi/Kconfig.npcx +++ b/drivers/espi/Kconfig.npcx @@ -5,7 +5,9 @@ config ESPI_NPCX bool "Nuvoton NPCX embedded controller (EC) ESPI driver" + default y depends on SOC_FAMILY_NPCX + depends on DT_HAS_NUVOTON_NPCX_ESPI_ENABLED help This option enables the Intel Enhanced Serial Peripheral Interface (eSPI) for NPCX family of processors. diff --git a/soc/arm/nuvoton_npcx/npcx4/Kconfig.defconfig.series b/soc/arm/nuvoton_npcx/npcx4/Kconfig.defconfig.series index 018a38cc14b..377575b1d9f 100644 --- a/soc/arm/nuvoton_npcx/npcx4/Kconfig.defconfig.series +++ b/soc/arm/nuvoton_npcx/npcx4/Kconfig.defconfig.series @@ -14,10 +14,6 @@ config NUM_IRQS config CORTEX_M_SYSTICK default !NPCX_ITIM_TIMER -config ESPI_NPCX - default y - depends on ESPI - source "soc/arm/nuvoton_npcx/npcx4/Kconfig.defconfig.npcx4*" endif # SOC_SERIES_NPCX4 diff --git a/soc/arm/nuvoton_npcx/npcx7/Kconfig.defconfig.series b/soc/arm/nuvoton_npcx/npcx7/Kconfig.defconfig.series index 4af311aebcb..9b12678dc8e 100644 --- a/soc/arm/nuvoton_npcx/npcx7/Kconfig.defconfig.series +++ b/soc/arm/nuvoton_npcx/npcx7/Kconfig.defconfig.series @@ -14,10 +14,6 @@ config NUM_IRQS config CORTEX_M_SYSTICK default !NPCX_ITIM_TIMER -config ESPI_NPCX - default y - depends on ESPI - source "soc/arm/nuvoton_npcx/npcx7/Kconfig.defconfig.npcx7*" endif # SOC_SERIES_NPCX7 diff --git a/soc/arm/nuvoton_npcx/npcx9/Kconfig.defconfig.series b/soc/arm/nuvoton_npcx/npcx9/Kconfig.defconfig.series index b5ffb594eed..6487b70cf59 100644 --- a/soc/arm/nuvoton_npcx/npcx9/Kconfig.defconfig.series +++ b/soc/arm/nuvoton_npcx/npcx9/Kconfig.defconfig.series @@ -14,10 +14,6 @@ config NUM_IRQS config CORTEX_M_SYSTICK default !NPCX_ITIM_TIMER -config ESPI_NPCX - default y - depends on ESPI - source "soc/arm/nuvoton_npcx/npcx9/Kconfig.defconfig.npcx9*" endif # SOC_SERIES_NPCX9 From 3b354bfc572e3665d48c56169b69e253484c6730 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Manuel=20Arg=C3=BCelles?= Date: Fri, 1 Dec 2023 13:28:35 +0700 Subject: [PATCH 0861/3723] soc: nxp: s32k146: add LPI2C support MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Add LPI2C nodes to S32K1xx devices. S32K146 has a single LPI2C instance. Signed-off-by: Manuel Argüelles --- dts/arm/nxp/nxp_s32k146.dtsi | 2 ++ dts/arm/nxp/nxp_s32k1xx.dtsi | 22 ++++++++++++++++++++++ soc/arm/nxp_s32/s32k1/Kconfig.series | 1 + 3 files changed, 25 insertions(+) diff --git a/dts/arm/nxp/nxp_s32k146.dtsi b/dts/arm/nxp/nxp_s32k146.dtsi index 834c0ad360d..9ca9c63635f 100644 --- a/dts/arm/nxp/nxp_s32k146.dtsi +++ b/dts/arm/nxp/nxp_s32k146.dtsi @@ -33,6 +33,8 @@ }; }; +/delete-node/ &lpi2c1; + &nvic { arm,num-irq-priority-bits = <4>; }; diff --git a/dts/arm/nxp/nxp_s32k1xx.dtsi b/dts/arm/nxp/nxp_s32k1xx.dtsi index e7a49f3fa17..a46c73598a2 100644 --- a/dts/arm/nxp/nxp_s32k1xx.dtsi +++ b/dts/arm/nxp/nxp_s32k1xx.dtsi @@ -6,6 +6,7 @@ #include #include +#include / { cpus { @@ -80,6 +81,27 @@ status = "okay"; }; + lpi2c0: i2c@40066000 { + compatible = "nxp,imx-lpi2c"; + clock-frequency = ; + #address-cells = <1>; + #size-cells = <0>; + reg = <0x40066000 0x1000>; + interrupts = <24 0>; + clocks = <&clock NXP_S32_LPI2C0_CLK>; + status = "disabled"; + }; + + lpi2c1: i2c@40067000 { + compatible = "nxp,imx-lpi2c"; + clock-frequency = ; + #address-cells = <1>; + #size-cells = <0>; + reg = <0x40067000 0x1000>; + interrupts = <25 0>; + status = "disabled"; + }; + lpuart0: uart@4006a000 { compatible = "nxp,kinetis-lpuart"; reg = <0x4006a000 0x1000>; diff --git a/soc/arm/nxp_s32/s32k1/Kconfig.series b/soc/arm/nxp_s32/s32k1/Kconfig.series index e12df1c488f..7359038ee54 100644 --- a/soc/arm/nxp_s32/s32k1/Kconfig.series +++ b/soc/arm/nxp_s32/s32k1/Kconfig.series @@ -14,5 +14,6 @@ config SOC_SERIES_S32K1XX select MPU_ALLOW_FLASH_WRITE if !XIP select CLOCK_CONTROL select HAS_MCUX_LPUART + select HAS_MCUX_LPI2C help Enable support for NXP S32K1XX MCU series. From 4f9e2c4a7ac986262c1683c7a8a2f7a0a8c61101 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Manuel=20Arg=C3=BCelles?= Date: Fri, 1 Dec 2023 13:28:35 +0700 Subject: [PATCH 0862/3723] boards: ucans32k1sic: enable LPI2C support MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Enable LPI2C support on ucans32k1sic board. Signed-off-by: Manuel Argüelles --- boards/arm/ucans32k1sic/doc/index.rst | 1 + boards/arm/ucans32k1sic/ucans32k1sic-pinctrl.dtsi | 7 +++++++ boards/arm/ucans32k1sic/ucans32k1sic.dts | 9 +++++++++ boards/arm/ucans32k1sic/ucans32k1sic.yaml | 1 + 4 files changed, 18 insertions(+) diff --git a/boards/arm/ucans32k1sic/doc/index.rst b/boards/arm/ucans32k1sic/doc/index.rst index 8fa73877772..5c49a974f92 100644 --- a/boards/arm/ucans32k1sic/doc/index.rst +++ b/boards/arm/ucans32k1sic/doc/index.rst @@ -47,6 +47,7 @@ SYSMPU on-chip mpu PORT on-chip pinctrl GPIO on-chip gpio LPUART on-chip serial +LPI2C on-chip i2c ============ ========== ================================ The default configuration can be found in the Kconfig file diff --git a/boards/arm/ucans32k1sic/ucans32k1sic-pinctrl.dtsi b/boards/arm/ucans32k1sic/ucans32k1sic-pinctrl.dtsi index 9f5eadadf36..566be6f93d8 100644 --- a/boards/arm/ucans32k1sic/ucans32k1sic-pinctrl.dtsi +++ b/boards/arm/ucans32k1sic/ucans32k1sic-pinctrl.dtsi @@ -20,4 +20,11 @@ drive-strength = "low"; }; }; + + lpi2c0_default: lpi2c0_default { + group1 { + pinmux = , ; + drive-strength = "low"; + }; + }; }; diff --git a/boards/arm/ucans32k1sic/ucans32k1sic.dts b/boards/arm/ucans32k1sic/ucans32k1sic.dts index fc304249546..797b7682038 100644 --- a/boards/arm/ucans32k1sic/ucans32k1sic.dts +++ b/boards/arm/ucans32k1sic/ucans32k1sic.dts @@ -27,6 +27,7 @@ led1 = &led1_green; led2 = &led1_blue; sw0 = &button_3; + i2c-0 = &lpi2c0; }; leds { @@ -89,3 +90,11 @@ current-speed = <115200>; status = "okay"; }; + +&lpi2c0 { + pinctrl-0 = <&lpi2c0_default>; + pinctrl-names = "default"; + scl-gpios = <&gpioa 3 GPIO_ACTIVE_HIGH>; + sda-gpios = <&gpioa 2 GPIO_ACTIVE_HIGH>; + status = "okay"; +}; diff --git a/boards/arm/ucans32k1sic/ucans32k1sic.yaml b/boards/arm/ucans32k1sic/ucans32k1sic.yaml index 03054d7ed9d..95813f7d1e1 100644 --- a/boards/arm/ucans32k1sic/ucans32k1sic.yaml +++ b/boards/arm/ucans32k1sic/ucans32k1sic.yaml @@ -15,3 +15,4 @@ supported: - gpio - uart - pinctrl + - i2c From 18202d0db316760c9060ef200f1470de8ac89334 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Manuel=20Arg=C3=BCelles?= Date: Fri, 1 Dec 2023 13:28:36 +0700 Subject: [PATCH 0863/3723] soc: nxp: s32k146: add LPSPI support MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Add LPSPI nodes to S32K1xx devices. Signed-off-by: Manuel Argüelles --- dts/arm/nxp/nxp_s32k146.dtsi | 8 ++++++++ dts/arm/nxp/nxp_s32k1xx.dtsi | 28 ++++++++++++++++++++++++++++ soc/arm/nxp_s32/s32k1/Kconfig.series | 1 + 3 files changed, 37 insertions(+) diff --git a/dts/arm/nxp/nxp_s32k146.dtsi b/dts/arm/nxp/nxp_s32k146.dtsi index 9ca9c63635f..b875f09ce65 100644 --- a/dts/arm/nxp/nxp_s32k146.dtsi +++ b/dts/arm/nxp/nxp_s32k146.dtsi @@ -51,3 +51,11 @@ &lpuart2 { clocks = <&clock NXP_S32_LPUART2_CLK>; }; + +&lpspi1 { + clocks = <&clock NXP_S32_LPSPI1_CLK>; +}; + +&lpspi2 { + clocks = <&clock NXP_S32_LPSPI2_CLK>; +}; diff --git a/dts/arm/nxp/nxp_s32k1xx.dtsi b/dts/arm/nxp/nxp_s32k1xx.dtsi index a46c73598a2..5a5a32fefa6 100644 --- a/dts/arm/nxp/nxp_s32k1xx.dtsi +++ b/dts/arm/nxp/nxp_s32k1xx.dtsi @@ -44,6 +44,34 @@ status = "disabled"; }; + lpspi0: spi@4002c000 { + compatible = "nxp,imx-lpspi"; + reg = <0x4002c000 0x1000>; + interrupts = <26 0>; + clocks = <&clock NXP_S32_LPSPI0_CLK>; + #address-cells = <1>; + #size-cells = <0>; + status = "disabled"; + }; + + lpspi1: spi@4002d000 { + compatible = "nxp,imx-lpspi"; + reg = <0x4002d000 0x1000>; + interrupts = <27 0>; + #address-cells = <1>; + #size-cells = <0>; + status = "disabled"; + }; + + lpspi2: spi@4002e000 { + compatible = "nxp,imx-lpspi"; + reg = <0x4002e000 0x1000>; + interrupts = <28 0>; + #address-cells = <1>; + #size-cells = <0>; + status = "disabled"; + }; + porta: pinmux@40049000 { compatible = "nxp,kinetis-pinmux"; reg = <0x40049000 0x1000>; diff --git a/soc/arm/nxp_s32/s32k1/Kconfig.series b/soc/arm/nxp_s32/s32k1/Kconfig.series index 7359038ee54..9b6f0086509 100644 --- a/soc/arm/nxp_s32/s32k1/Kconfig.series +++ b/soc/arm/nxp_s32/s32k1/Kconfig.series @@ -15,5 +15,6 @@ config SOC_SERIES_S32K1XX select CLOCK_CONTROL select HAS_MCUX_LPUART select HAS_MCUX_LPI2C + select HAS_MCUX_LPSPI help Enable support for NXP S32K1XX MCU series. From e4e3386f9c9c27795f29be851986e7b28e2e5be1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Manuel=20Arg=C3=BCelles?= Date: Fri, 1 Dec 2023 13:28:36 +0700 Subject: [PATCH 0864/3723] boards: ucans32k1sic: enable LPSPI support MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Enable LPSPI support on ucans32k1sic board. Signed-off-by: Manuel Argüelles --- boards/arm/ucans32k1sic/doc/index.rst | 1 + boards/arm/ucans32k1sic/ucans32k1sic-pinctrl.dtsi | 10 ++++++++++ boards/arm/ucans32k1sic/ucans32k1sic.dts | 6 ++++++ boards/arm/ucans32k1sic/ucans32k1sic.yaml | 1 + 4 files changed, 18 insertions(+) diff --git a/boards/arm/ucans32k1sic/doc/index.rst b/boards/arm/ucans32k1sic/doc/index.rst index 5c49a974f92..1291eeb9890 100644 --- a/boards/arm/ucans32k1sic/doc/index.rst +++ b/boards/arm/ucans32k1sic/doc/index.rst @@ -48,6 +48,7 @@ PORT on-chip pinctrl GPIO on-chip gpio LPUART on-chip serial LPI2C on-chip i2c +LPSPI on-chip spi ============ ========== ================================ The default configuration can be found in the Kconfig file diff --git a/boards/arm/ucans32k1sic/ucans32k1sic-pinctrl.dtsi b/boards/arm/ucans32k1sic/ucans32k1sic-pinctrl.dtsi index 566be6f93d8..d3926d9866e 100644 --- a/boards/arm/ucans32k1sic/ucans32k1sic-pinctrl.dtsi +++ b/boards/arm/ucans32k1sic/ucans32k1sic-pinctrl.dtsi @@ -27,4 +27,14 @@ drive-strength = "low"; }; }; + + lpspi0_default: lpspi0_default { + group0 { + pinmux = , + , + , + ; + drive-strength = "low"; + }; + }; }; diff --git a/boards/arm/ucans32k1sic/ucans32k1sic.dts b/boards/arm/ucans32k1sic/ucans32k1sic.dts index 797b7682038..49b30d168e2 100644 --- a/boards/arm/ucans32k1sic/ucans32k1sic.dts +++ b/boards/arm/ucans32k1sic/ucans32k1sic.dts @@ -98,3 +98,9 @@ sda-gpios = <&gpioa 2 GPIO_ACTIVE_HIGH>; status = "okay"; }; + +&lpspi0 { + pinctrl-0 = <&lpspi0_default>; + pinctrl-names = "default"; + status = "okay"; +}; diff --git a/boards/arm/ucans32k1sic/ucans32k1sic.yaml b/boards/arm/ucans32k1sic/ucans32k1sic.yaml index 95813f7d1e1..8519980aa60 100644 --- a/boards/arm/ucans32k1sic/ucans32k1sic.yaml +++ b/boards/arm/ucans32k1sic/ucans32k1sic.yaml @@ -16,3 +16,4 @@ supported: - uart - pinctrl - i2c + - spi From f46a27f20bed868c3ad8e90955fa7664aab8b760 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Manuel=20Arg=C3=BCelles?= Date: Fri, 1 Dec 2023 13:28:36 +0700 Subject: [PATCH 0865/3723] tests: drivers: spi: enable tests on ucans32k1sic MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Add overlays to enable SPI tests on ucans32k1sic board. Signed-off-by: Manuel Argüelles --- .../spi_loopback/boards/ucans32k1sic.overlay | 20 +++++++++++++++++++ 1 file changed, 20 insertions(+) create mode 100644 tests/drivers/spi/spi_loopback/boards/ucans32k1sic.overlay diff --git a/tests/drivers/spi/spi_loopback/boards/ucans32k1sic.overlay b/tests/drivers/spi/spi_loopback/boards/ucans32k1sic.overlay new file mode 100644 index 00000000000..eab363682cc --- /dev/null +++ b/tests/drivers/spi/spi_loopback/boards/ucans32k1sic.overlay @@ -0,0 +1,20 @@ +/* + * Copyright 2023 NXP + * + * SPDX-License-Identifier: Apache-2.0 + */ + +/* Short P1.3 (SPI0/MISO) with P1.4 (SPI0/MOSI) */ + +&lpspi0 { + 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 = <9000000>; + }; +}; From 429798c1418888206200c5b52dccb76264db25fb Mon Sep 17 00:00:00 2001 From: Robert Lubos Date: Wed, 6 Dec 2023 11:56:55 +0100 Subject: [PATCH 0866/3723] tests: net: socket: udp: Increase ztest stack size The default ztest stack size was too small to run new UDP tests on certain platforms (nrf52840 in this particular case), therefore increase teh stack size in prj.conf. Signed-off-by: Robert Lubos --- tests/net/socket/udp/prj.conf | 1 + 1 file changed, 1 insertion(+) diff --git a/tests/net/socket/udp/prj.conf b/tests/net/socket/udp/prj.conf index 4f7779fd049..1a376bb84d2 100644 --- a/tests/net/socket/udp/prj.conf +++ b/tests/net/socket/udp/prj.conf @@ -21,6 +21,7 @@ CONFIG_ETH_DRIVER=n CONFIG_TEST_RANDOM_GENERATOR=y CONFIG_MAIN_STACK_SIZE=2048 +CONFIG_ZTEST_STACK_SIZE=2048 CONFIG_HEAP_MEM_POOL_SIZE=256 CONFIG_ZTEST=y From 527640b72675b1030c047c023645d06988d4268a Mon Sep 17 00:00:00 2001 From: Pieter De Gendt Date: Fri, 1 Dec 2023 09:32:14 +0100 Subject: [PATCH 0867/3723] samples: net: sockets: coap_server: Remove observer events In preparation of migrating to net_mgmt events, we need to remove the observer event callback handler. Signed-off-by: Pieter De Gendt --- samples/net/sockets/coap_server/prj.conf | 1 - samples/net/sockets/coap_server/src/observer.c | 13 ------------- 2 files changed, 14 deletions(-) diff --git a/samples/net/sockets/coap_server/prj.conf b/samples/net/sockets/coap_server/prj.conf index 1a26e614786..e9ff24577b7 100644 --- a/samples/net/sockets/coap_server/prj.conf +++ b/samples/net/sockets/coap_server/prj.conf @@ -13,7 +13,6 @@ CONFIG_COAP=y CONFIG_COAP_SERVER=y CONFIG_COAP_SERVER_WELL_KNOWN_CORE=y CONFIG_COAP_WELL_KNOWN_BLOCK_WISE=n -CONFIG_COAP_OBSERVER_EVENTS=y # Kernel options CONFIG_ENTROPY_GENERATOR=y diff --git a/samples/net/sockets/coap_server/src/observer.c b/samples/net/sockets/coap_server/src/observer.c index 29b7b4ed472..6d39536e232 100644 --- a/samples/net/sockets/coap_server/src/observer.c +++ b/samples/net/sockets/coap_server/src/observer.c @@ -17,16 +17,6 @@ static int obs_counter; static void update_counter(struct k_work *work); K_WORK_DELAYABLE_DEFINE(obs_work, update_counter); -#ifdef CONFIG_COAP_OBSERVER_EVENTS - -static void observer_event(struct coap_resource *resource, struct coap_observer *observer, - enum coap_observer_event event) -{ - LOG_INF("Observer %s", event == COAP_OBSERVER_ADDED ? "added" : "removed"); -} - -#endif - static int send_notification_packet(struct coap_resource *resource, const struct sockaddr *addr, socklen_t addr_len, @@ -138,9 +128,6 @@ COAP_RESOURCE_DEFINE(obs, coap_server, .get = obs_get, .path = obs_path, .notify = obs_notify, -#ifdef CONFIG_COAP_OBSERVER_EVENTS - .observer_event_handler = observer_event, -#endif }); static void update_counter(struct k_work *work) From f712441840463e796fd4f3089ab2d128af1407da Mon Sep 17 00:00:00 2001 From: Pieter De Gendt Date: Fri, 1 Dec 2023 09:00:47 +0100 Subject: [PATCH 0868/3723] Revert "net: lib: coap: Add support for observer event callbacks" This reverts commit 5227f248153f67e05b0ede9f859deb6f63ed4456. The coap observer events will be replaced with net_mgmt events. Signed-off-by: Pieter De Gendt --- include/zephyr/net/coap.h | 30 ------------------------------ subsys/net/lib/coap/Kconfig | 6 ------ subsys/net/lib/coap/coap.c | 17 +---------------- 3 files changed, 1 insertion(+), 52 deletions(-) diff --git a/include/zephyr/net/coap.h b/include/zephyr/net/coap.h index a907d1311e1..dceed869b43 100644 --- a/include/zephyr/net/coap.h +++ b/include/zephyr/net/coap.h @@ -238,29 +238,6 @@ typedef int (*coap_method_t)(struct coap_resource *resource, typedef void (*coap_notify_t)(struct coap_resource *resource, struct coap_observer *observer); -/** - * @brief Event types for observer event callbacks. - */ -enum coap_observer_event { - /** An observer was added. */ - COAP_OBSERVER_ADDED = 0, - /** An observer was removed. */ - COAP_OBSERVER_REMOVED, -}; - -/** - * @typedef coap_observer_event_handler_t - * @brief Type of the handler being called when a resource's observers has been modified. - * Either an observer was added or removed. - * - * @param resource A pointer to a CoAP resource for which the event occurred - * @param observer The observer being added/removed - * @param event The event type - */ -typedef void (*coap_observer_event_handler_t)(struct coap_resource *resource, - struct coap_observer *observer, - enum coap_observer_event event); - /** * @brief Description of CoAP resource. * @@ -275,13 +252,6 @@ struct coap_resource { void *user_data; sys_slist_t observers; int age; -#if defined(CONFIG_COAP_OBSERVER_EVENTS) || defined(DOXYGEN) - /** - * Optional observer event callback function - * Only available when @kconfig{CONFIG_COAP_OBSERVER_EVENTS} is enabled. - */ - coap_observer_event_handler_t observer_event_handler; -#endif }; /** diff --git a/subsys/net/lib/coap/Kconfig b/subsys/net/lib/coap/Kconfig index 8e62983ea72..cc6bee04f53 100644 --- a/subsys/net/lib/coap/Kconfig +++ b/subsys/net/lib/coap/Kconfig @@ -89,12 +89,6 @@ config COAP_URI_WILDCARD This option enables MQTT-style wildcards in path. Disable it if resource path may contain plus or hash symbol. -config COAP_OBSERVER_EVENTS - bool "CoAP resource observer events" - help - This option enables to register a callback function to CoAP resources - that will be called when adding/removing observers. - config COAP_KEEP_USER_DATA bool "Keeping user data in the CoAP packet" help diff --git a/subsys/net/lib/coap/coap.c b/subsys/net/lib/coap/coap.c index 9fe62730b47..e2ff715aec6 100644 --- a/subsys/net/lib/coap/coap.c +++ b/subsys/net/lib/coap/coap.c @@ -1856,28 +1856,13 @@ bool coap_register_observer(struct coap_resource *resource, resource->age = 2; } -#ifdef CONFIG_COAP_OBSERVER_EVENTS - if (resource->observer_event_handler) { - resource->observer_event_handler(resource, observer, COAP_OBSERVER_ADDED); - } -#endif - return first; } bool coap_remove_observer(struct coap_resource *resource, struct coap_observer *observer) { - if (!sys_slist_find_and_remove(&resource->observers, &observer->list)) { - return false; - } - -#ifdef CONFIG_COAP_OBSERVER_EVENTS - if (resource->observer_event_handler) { - resource->observer_event_handler(resource, observer, COAP_OBSERVER_REMOVED); - } -#endif - return true; + return sys_slist_find_and_remove(&resource->observers, &observer->list); } static bool sockaddr_equal(const struct sockaddr *a, From 5182dd24c60ceeb15c7cadd119003b3328af23f7 Mon Sep 17 00:00:00 2001 From: Pieter De Gendt Date: Wed, 29 Nov 2023 16:53:09 +0100 Subject: [PATCH 0869/3723] net: lib: coap: Introduce net mgmt events for CoAP Allow users to register net mgmt events callbacks for CoAP events. Signed-off-by: Pieter De Gendt --- include/zephyr/net/coap_mgmt.h | 102 ++++++++++++++++++++++++++++++ subsys/net/lib/coap/coap.c | 30 ++++++++- subsys/net/lib/coap/coap_server.c | 25 +++++++- 3 files changed, 153 insertions(+), 4 deletions(-) create mode 100644 include/zephyr/net/coap_mgmt.h diff --git a/include/zephyr/net/coap_mgmt.h b/include/zephyr/net/coap_mgmt.h new file mode 100644 index 00000000000..f19eec6eb4b --- /dev/null +++ b/include/zephyr/net/coap_mgmt.h @@ -0,0 +1,102 @@ +/* + * Copyright (c) 2023 Basalte bv + * + * SPDX-License-Identifier: Apache-2.0 + */ + +/** + * @file + * @brief CoAP Events code public header + */ + +#ifndef ZEPHYR_INCLUDE_NET_COAP_MGMT_H_ +#define ZEPHYR_INCLUDE_NET_COAP_MGMT_H_ + +#include + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * @brief CoAP Manager Events + * @defgroup coap_mgmt CoAP Manager Events + * @ingroup networking + * @{ + */ + +/** @cond INTERNAL_HIDDEN */ + +/* CoAP events */ +#define _NET_COAP_LAYER NET_MGMT_LAYER_L4 +#define _NET_COAP_CODE 0x1c0 +#define _NET_COAP_IF_BASE (NET_MGMT_EVENT_BIT | \ + NET_MGMT_LAYER(_NET_COAP_LAYER) | \ + NET_MGMT_LAYER_CODE(_NET_COAP_CODE)) + +struct coap_service; +struct coap_resource; +struct coap_observer; + +/** @endcond */ + +enum net_event_coap_cmd { + /* Service events */ + NET_EVENT_COAP_CMD_SERVICE_STARTED = 1, + NET_EVENT_COAP_CMD_SERVICE_STOPPED, + /* Observer events */ + NET_EVENT_COAP_CMD_OBSERVER_ADDED, + NET_EVENT_COAP_CMD_OBSERVER_REMOVED, +}; + +/** + * @brief coap_mgmt event raised when a service has started + */ +#define NET_EVENT_COAP_SERVICE_STARTED \ + (_NET_COAP_IF_BASE | NET_EVENT_COAP_CMD_SERVICE_STARTED) + +/** + * @brief coap_mgmt event raised when a service has stopped + */ +#define NET_EVENT_COAP_SERVICE_STOPPED \ + (_NET_COAP_IF_BASE | NET_EVENT_COAP_CMD_SERVICE_STOPPED) + +/** + * @brief coap_mgmt event raised when an observer has been added to a resource + */ +#define NET_EVENT_COAP_OBSERVER_ADDED \ + (_NET_COAP_IF_BASE | NET_EVENT_COAP_CMD_OBSERVER_ADDED) + +/** + * @brief coap_mgmt event raised when an observer has been removed from a resource + */ +#define NET_EVENT_COAP_OBSERVER_REMOVED \ + (_NET_COAP_IF_BASE | NET_EVENT_COAP_CMD_OBSERVER_REMOVED) + +/** + * @brief CoAP Service event structure. + */ +struct net_event_coap_service { + /* The CoAP service for which the event is emitted */ + const struct coap_service *service; +}; + +/** + * @brief CoAP Observer event structure. + */ +struct net_event_coap_observer { + /* The CoAP resource for which the event is emitted */ + struct coap_resource *resource; + /* The observer that is added/removed */ + struct coap_observer *observer; +}; + +#ifdef __cplusplus +} +#endif + +/** + * @} + */ + +#endif /* ZEPHYR_INCLUDE_NET_COAP_MGMT_H_ */ diff --git a/subsys/net/lib/coap/coap.c b/subsys/net/lib/coap/coap.c index e2ff715aec6..c49264e6776 100644 --- a/subsys/net/lib/coap/coap.c +++ b/subsys/net/lib/coap/coap.c @@ -23,6 +23,7 @@ LOG_MODULE_REGISTER(net_coap, CONFIG_COAP_LOG_LEVEL); #include #include #include +#include #define COAP_PATH_ELEM_DELIM '/' #define COAP_PATH_ELEM_QUERY '?' @@ -1844,6 +1845,25 @@ void coap_observer_init(struct coap_observer *observer, net_ipaddr_copy(&observer->addr, addr); } +static inline void coap_observer_raise_event(struct coap_resource *resource, + struct coap_observer *observer, + uint32_t mgmt_event) +{ +#ifdef CONFIG_NET_MGMT_EVENT_INFO + const struct net_event_coap_observer net_event = { + .resource = resource, + .observer = observer, + }; + + net_mgmt_event_notify_with_info(mgmt_event, NULL, (void *)&net_event, sizeof(net_event)); +#else + ARG_UNUSED(resource); + ARG_UNUSED(observer); + + net_mgmt_event_notify(mgmt_event, NULL); +#endif +} + bool coap_register_observer(struct coap_resource *resource, struct coap_observer *observer) { @@ -1856,13 +1876,21 @@ bool coap_register_observer(struct coap_resource *resource, resource->age = 2; } + coap_observer_raise_event(resource, observer, NET_EVENT_COAP_OBSERVER_ADDED); + return first; } bool coap_remove_observer(struct coap_resource *resource, struct coap_observer *observer) { - return sys_slist_find_and_remove(&resource->observers, &observer->list); + if (!sys_slist_find_and_remove(&resource->observers, &observer->list)) { + return false; + } + + coap_observer_raise_event(resource, observer, NET_EVENT_COAP_OBSERVER_REMOVED); + + return true; } static bool sockaddr_equal(const struct sockaddr *a, diff --git a/subsys/net/lib/coap/coap_server.c b/subsys/net/lib/coap/coap_server.c index 386bc2081bb..ce312968ea7 100644 --- a/subsys/net/lib/coap/coap_server.c +++ b/subsys/net/lib/coap/coap_server.c @@ -14,6 +14,7 @@ LOG_MODULE_DECLARE(net_coap, CONFIG_COAP_LOG_LEVEL); #include #include #include +#include #include #ifdef CONFIG_ARCH_POSIX #include @@ -345,6 +346,21 @@ static inline bool coap_service_in_section(const struct coap_service *service) STRUCT_SECTION_END(coap_service) > service; } +static inline void coap_service_raise_event(const struct coap_service *service, uint32_t mgmt_event) +{ +#if defined(CONFIG_NET_MGMT_EVENT_INFO) + const struct net_event_coap_service net_event = { + .service = service, + }; + + net_mgmt_event_notify_with_info(mgmt_event, NULL, (void *)&net_event, sizeof(net_event)); +#else + ARG_UNUSED(service); + + net_mgmt_event_notify(mgmt_event, NULL); +#endif +} + int coap_service_start(const struct coap_service *service) { int ret; @@ -446,6 +462,8 @@ int coap_service_start(const struct coap_service *service) coap_server_update_services(); + coap_service_raise_event(service, NET_EVENT_COAP_SERVICE_STARTED); + return ret; close: @@ -469,17 +487,18 @@ int coap_service_stop(const struct coap_service *service) k_mutex_lock(&lock, K_FOREVER); if (service->data->sock_fd < 0) { - ret = -EALREADY; - goto end; + k_mutex_unlock(&lock); + return -EALREADY; } /* Closing a socket will trigger a poll event */ ret = zsock_close(service->data->sock_fd); service->data->sock_fd = -1; -end: k_mutex_unlock(&lock); + coap_service_raise_event(service, NET_EVENT_COAP_SERVICE_STOPPED); + return ret; } From 8b22c769a76f4618648f5d1e0ff7d9656f17665a Mon Sep 17 00:00:00 2001 From: Pieter De Gendt Date: Fri, 1 Dec 2023 10:12:19 +0100 Subject: [PATCH 0870/3723] samples: net: sockets: coap_server: Add CoAP events example Add an example handler for CoAP events triggered by net_mgmt. Signed-off-by: Pieter De Gendt --- samples/net/sockets/coap_server/prj.conf | 5 ++ samples/net/sockets/coap_server/src/events.c | 50 ++++++++++++++++++++ 2 files changed, 55 insertions(+) create mode 100644 samples/net/sockets/coap_server/src/events.c diff --git a/samples/net/sockets/coap_server/prj.conf b/samples/net/sockets/coap_server/prj.conf index e9ff24577b7..59d444db456 100644 --- a/samples/net/sockets/coap_server/prj.conf +++ b/samples/net/sockets/coap_server/prj.conf @@ -29,6 +29,11 @@ CONFIG_COAP_SERVER_SHELL=y # Configuration CONFIG_NET_CONFIG_SETTINGS=y +# Events +CONFIG_NET_MGMT=y +CONFIG_NET_MGMT_EVENT=y +CONFIG_NET_MGMT_EVENT_INFO=y + # Enable only one protocol, if you enable both sources # won't compile. # IPv6 Support diff --git a/samples/net/sockets/coap_server/src/events.c b/samples/net/sockets/coap_server/src/events.c new file mode 100644 index 00000000000..3f843fba017 --- /dev/null +++ b/samples/net/sockets/coap_server/src/events.c @@ -0,0 +1,50 @@ +/* + * Copyright (c) 2023 Basalte bv + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include +LOG_MODULE_DECLARE(net_coap_service_sample); + +#include +#include + +#define COAP_EVENTS_SET (NET_EVENT_COAP_OBSERVER_ADDED | NET_EVENT_COAP_OBSERVER_REMOVED | \ + NET_EVENT_COAP_SERVICE_STARTED | NET_EVENT_COAP_SERVICE_STOPPED) + +void coap_event_handler(uint32_t mgmt_event, struct net_if *iface, + void *info, size_t info_length, void *user_data) +{ + ARG_UNUSED(iface); + ARG_UNUSED(user_data); + + switch (mgmt_event) { + case NET_EVENT_COAP_OBSERVER_ADDED: + LOG_INF("CoAP observer added"); + break; + case NET_EVENT_COAP_OBSERVER_REMOVED: + LOG_INF("CoAP observer removed"); + break; + case NET_EVENT_COAP_SERVICE_STARTED: + if (info != NULL && info_length == sizeof(struct net_event_coap_service)) { + struct net_event_coap_service *net_event = info; + + LOG_INF("CoAP service %s started", net_event->service->name); + } else { + LOG_INF("CoAP service started"); + } + break; + case NET_EVENT_COAP_SERVICE_STOPPED: + if (info != NULL && info_length == sizeof(struct net_event_coap_service)) { + struct net_event_coap_service *net_event = info; + + LOG_INF("CoAP service %s stopped", net_event->service->name); + } else { + LOG_INF("CoAP service stopped"); + } + break; + } +} + +NET_MGMT_REGISTER_EVENT_HANDLER(coap_events, COAP_EVENTS_SET, coap_event_handler, NULL); From 1f52a755d3d1038af993208b1a7d3bd4a40b89c6 Mon Sep 17 00:00:00 2001 From: Pieter De Gendt Date: Fri, 1 Dec 2023 10:25:30 +0100 Subject: [PATCH 0871/3723] doc: connectivity: networking: Update CoAP event handling example Change the CoAP documentation to demonstrate CoAP events using net_mgmt. Signed-off-by: Pieter De Gendt --- .../networking/api/coap_server.rst | 62 +++++++++++++++---- 1 file changed, 49 insertions(+), 13 deletions(-) diff --git a/doc/connectivity/networking/api/coap_server.rst b/doc/connectivity/networking/api/coap_server.rst index 9a91081f449..13b4aa9491e 100644 --- a/doc/connectivity/networking/api/coap_server.rst +++ b/doc/connectivity/networking/api/coap_server.rst @@ -125,9 +125,7 @@ Observable resources ******************** The CoAP server provides logic for parsing observe requests and stores these using the runtime data -of CoAP services. Together with observer events, enabled with -:kconfig:option:`CONFIG_COAP_OBSERVER_EVENTS`, the application can easily keep track of clients -and send state updates. An example using a temperature sensor can look like: +of CoAP services. An example using a temperature sensor can look like: .. code-block:: c @@ -138,15 +136,6 @@ and send state updates. An example using a temperature sensor can look like: static void notify_observers(struct k_work *work); K_WORK_DELAYABLE_DEFINE(temp_work, notify_observers); - static void temp_observer_event(struct coap_resource *resource, struct coap_observer *observer, - enum coap_observer_event event) - { - /* Only track the sensor temperature if an observer is active */ - if (event == COAP_OBSERVER_ADDED) { - k_work_schedule(&temp_work, K_SECONDS(1)); - } - } - static int send_temperature(struct coap_resource *resource, const struct sockaddr *addr, socklen_t addr_len, uint16_t age, uint16_t id, const uint8_t *token, uint8_t tkl, @@ -221,7 +210,6 @@ and send state updates. An example using a temperature sensor can look like: .path = temp_resource_path, .get = temp_get, .notify = temp_notify, - .observer_event_handler = temp_observer_event, }); static void notify_observers(struct k_work *work) @@ -234,6 +222,54 @@ and send state updates. An example using a temperature sensor can look like: k_work_reschedule(&temp_work, K_SECONDS(1)); } +CoAP Events +*********** + +By enabling :kconfig:option:`CONFIG_NET_MGMT_EVENT` the user can register for CoAP events. The +following example simply prints when an event occurs. + +.. code-block:: c + + #include + #include + #include + + #define COAP_EVENTS_SET (NET_EVENT_COAP_OBSERVER_ADDED | NET_EVENT_COAP_OBSERVER_REMOVED | \ + NET_EVENT_COAP_SERVICE_STARTED | NET_EVENT_COAP_SERVICE_STOPPED) + + void coap_event_handler(uint32_t mgmt_event, struct net_if *iface, + void *info, size_t info_length, void *user_data) + { + switch (mgmt_event) { + case NET_EVENT_COAP_OBSERVER_ADDED: + printk("CoAP observer added"); + break; + case NET_EVENT_COAP_OBSERVER_REMOVED: + printk("CoAP observer removed"); + break; + case NET_EVENT_COAP_SERVICE_STARTED: + if (info != NULL && info_length == sizeof(struct net_event_coap_service)) { + struct net_event_coap_service *net_event = info; + + printk("CoAP service %s started", net_event->service->name); + } else { + printk("CoAP service started"); + } + break; + case NET_EVENT_COAP_SERVICE_STOPPED: + if (info != NULL && info_length == sizeof(struct net_event_coap_service)) { + struct net_event_coap_service *net_event = info; + + printk("CoAP service %s stopped", net_event->service->name); + } else { + printk("CoAP service stopped"); + } + break; + } + } + + NET_MGMT_REGISTER_EVENT_HANDLER(coap_events, COAP_EVENTS_SET, coap_event_handler, NULL); + CoRE Link Format **************** From ac520e6f99ce477f512a797f90ec08b063850fe1 Mon Sep 17 00:00:00 2001 From: Pieter De Gendt Date: Fri, 1 Dec 2023 10:33:18 +0100 Subject: [PATCH 0872/3723] doc: release: 3.6: Add CoAP events documentation Update the release notes and migration guide for CoAP events using the Network Events subsystem. Signed-off-by: Pieter De Gendt --- doc/releases/migration-guide-3.6.rst | 4 ++++ doc/releases/release-notes-3.6.rst | 2 ++ 2 files changed, 6 insertions(+) diff --git a/doc/releases/migration-guide-3.6.rst b/doc/releases/migration-guide-3.6.rst index e3daffe35ab..059b487a921 100644 --- a/doc/releases/migration-guide-3.6.rst +++ b/doc/releases/migration-guide-3.6.rst @@ -202,6 +202,10 @@ Networking ``request`` argument for :c:func:`coap_well_known_core_get` is made ``const``. (:github:`64265`) +* CoAP observer events have moved from a callback function in a CoAP resource to the Network Events + subsystem. The ``CONFIG_COAP_OBSERVER_EVENTS`` configuration option has been removed. + (:github:`65936`) + * The IGMP multicast library now supports IGMPv3. This results in a minor change to the existing api. The :c:func:`net_ipv4_igmp_join` now takes an additional argument of the type ``const struct igmp_param *param``. This allows IGMPv3 to exclude/include certain groups of diff --git a/doc/releases/release-notes-3.6.rst b/doc/releases/release-notes-3.6.rst index a0be585f618..3295a128ded 100644 --- a/doc/releases/release-notes-3.6.rst +++ b/doc/releases/release-notes-3.6.rst @@ -206,6 +206,8 @@ Networking * CoAP: + * Emit observer/service network events using the Network Event subsystem. + * Connection Manager: * DHCP: From 35761f724d2474c4dac0e3e2b08f4d8c92a6ba52 Mon Sep 17 00:00:00 2001 From: Pieter De Gendt Date: Fri, 1 Dec 2023 13:54:33 +0100 Subject: [PATCH 0873/3723] net: lib: shell: Add CoAP descriptions to event monitor Add a description for each CoAP event on L4. Signed-off-by: Pieter De Gendt --- subsys/net/lib/shell/events.c | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/subsys/net/lib/shell/events.c b/subsys/net/lib/shell/events.c index 047fd1e2186..f263e517850 100644 --- a/subsys/net/lib/shell/events.c +++ b/subsys/net/lib/shell/events.c @@ -12,6 +12,7 @@ LOG_MODULE_DECLARE(net_shell); #include #include #include +#include #include "common.h" @@ -251,6 +252,18 @@ static const char *get_l4_desc(uint32_t event) case NET_EVENT_DNS_SERVER_DEL: desc = "DNS server del"; break; + case NET_EVENT_COAP_SERVICE_STARTED: + desc = "CoAP service started"; + break; + case NET_EVENT_COAP_SERVICE_STOPPED: + desc = "CoAP service stopped"; + break; + case NET_EVENT_COAP_OBSERVER_ADDED: + desc = "CoAP observer added"; + break; + case NET_EVENT_COAP_OBSERVER_REMOVED: + desc = "CoAP observer removed"; + break; } return desc; From 3ddd36ff7724594140ddb9d8d1b72d9c1f55472d Mon Sep 17 00:00:00 2001 From: Yuval Peress Date: Fri, 1 Dec 2023 15:52:46 -0700 Subject: [PATCH 0874/3723] llvm: Allow llvm-readelf Enable multiple names for the readelf program under llvm Signed-off-by: Yuval Peress --- cmake/bintools/llvm/target.cmake | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/cmake/bintools/llvm/target.cmake b/cmake/bintools/llvm/target.cmake index 447d2adf555..9489491968f 100644 --- a/cmake/bintools/llvm/target.cmake +++ b/cmake/bintools/llvm/target.cmake @@ -26,7 +26,11 @@ find_program(CMAKE_OBJCOPY NAMES llvm-objcopy-${CLANGVER} objcopy ${find_program_binutils_args}) -find_program(CMAKE_READELF readelf ${find_program_binutils_args}) +find_program(CMAKE_READELF NAMES + llvm-readelf + llvm-readelf-${CLANGVER} + readelf + ${find_program_binutils_args}) # Use the gnu binutil abstraction include(${ZEPHYR_BASE}/cmake/bintools/llvm/target_bintools.cmake) From 0096a980d397cbc877a8a2329475952dc814b88b Mon Sep 17 00:00:00 2001 From: Marcus Folkesson Date: Tue, 5 Dec 2023 12:22:19 +0100 Subject: [PATCH 0875/3723] include: drivers: display: verify if optional API is implemented Basically all display drivers implements a few dummy functions that just returns due to lack of capabilities. Move that validation to the driver API instead. Signed-off-by: Marcus Folkesson --- include/zephyr/drivers/display.h | 35 ++++++++++++++++++++++++++++++++ 1 file changed, 35 insertions(+) diff --git a/include/zephyr/drivers/display.h b/include/zephyr/drivers/display.h index ae879401dd5..010443e319f 100644 --- a/include/zephyr/drivers/display.h +++ b/include/zephyr/drivers/display.h @@ -260,6 +260,7 @@ static inline int display_write(const struct device *dev, const uint16_t x, * @param buf Pointer to buffer array * * @retval 0 on success else negative errno code. + * @retval -ENOSYS if not implemented. */ static inline int display_read(const struct device *dev, const uint16_t x, const uint16_t y, @@ -269,6 +270,10 @@ static inline int display_read(const struct device *dev, const uint16_t x, struct display_driver_api *api = (struct display_driver_api *)dev->api; + if (api->read == NULL) { + return -ENOSYS; + } + return api->read(dev, x, y, desc, buf); } @@ -286,6 +291,10 @@ static inline void *display_get_framebuffer(const struct device *dev) struct display_driver_api *api = (struct display_driver_api *)dev->api; + if (api->get_framebuffer == NULL) { + return NULL; + } + return api->get_framebuffer(dev); } @@ -306,12 +315,17 @@ static inline void *display_get_framebuffer(const struct device *dev) * @param dev Pointer to device structure * * @retval 0 on success else negative errno code. + * @retval -ENOSYS if not implemented. */ static inline int display_blanking_on(const struct device *dev) { struct display_driver_api *api = (struct display_driver_api *)dev->api; + if (api->blanking_on == NULL) { + return -ENOSYS; + } + return api->blanking_on(dev); } @@ -325,12 +339,17 @@ static inline int display_blanking_on(const struct device *dev) * @param dev Pointer to device structure * * @retval 0 on success else negative errno code. + * @retval -ENOSYS if not implemented. */ static inline int display_blanking_off(const struct device *dev) { struct display_driver_api *api = (struct display_driver_api *)dev->api; + if (api->blanking_off == NULL) { + return -ENOSYS; + } + return api->blanking_off(dev); } @@ -344,6 +363,7 @@ static inline int display_blanking_off(const struct device *dev) * @param brightness Brightness in steps of 1/256 * * @retval 0 on success else negative errno code. + * @retval -ENOSYS if not implemented. */ static inline int display_set_brightness(const struct device *dev, uint8_t brightness) @@ -351,6 +371,10 @@ static inline int display_set_brightness(const struct device *dev, struct display_driver_api *api = (struct display_driver_api *)dev->api; + if (api->set_brightness == NULL) { + return -ENOSYS; + } + return api->set_brightness(dev, brightness); } @@ -364,12 +388,17 @@ static inline int display_set_brightness(const struct device *dev, * @param contrast Contrast in steps of 1/256 * * @retval 0 on success else negative errno code. + * @retval -ENOSYS if not implemented. */ static inline int display_set_contrast(const struct device *dev, uint8_t contrast) { struct display_driver_api *api = (struct display_driver_api *)dev->api; + if (api->set_contrast == NULL) { + return -ENOSYS; + } + return api->set_contrast(dev, contrast); } @@ -396,6 +425,7 @@ static inline void display_get_capabilities(const struct device *dev, * @param pixel_format Pixel format to be used by display * * @retval 0 on success else negative errno code. + * @retval -ENOSYS if not implemented. */ static inline int display_set_pixel_format(const struct device *dev, @@ -404,6 +434,10 @@ display_set_pixel_format(const struct device *dev, struct display_driver_api *api = (struct display_driver_api *)dev->api; + if (api->set_pixel_format == NULL) { + return -ENOSYS; + } + return api->set_pixel_format(dev, pixel_format); } @@ -414,6 +448,7 @@ display_set_pixel_format(const struct device *dev, * @param orientation Orientation to be used by display * * @retval 0 on success else negative errno code. + * @retval -ENOSYS if not implemented. */ static inline int display_set_orientation(const struct device *dev, const enum display_orientation From 7c9205bc417f3c9c2c24088971804d09dd7cb857 Mon Sep 17 00:00:00 2001 From: Marcus Folkesson Date: Tue, 5 Dec 2023 12:28:03 +0100 Subject: [PATCH 0876/3723] display: display_max7219: remove dummy functions for unsupported API As the display API now check against valid callback functions and returns -ENOSYS (or equalent), there is no need to provide such functions in the driver code. Signed-off-by: Marcus Folkesson --- drivers/display/display_max7219.c | 46 ------------------------------- 1 file changed, 46 deletions(-) diff --git a/drivers/display/display_max7219.c b/drivers/display/display_max7219.c index 6613e4c5e47..f3ccc52c9d4 100644 --- a/drivers/display/display_max7219.c +++ b/drivers/display/display_max7219.c @@ -139,20 +139,6 @@ static inline void skip_pixel(uint8_t *mask, uint8_t *data, const uint8_t **buf, } } -static int max7219_blanking_on(const struct device *dev) -{ - ARG_UNUSED(dev); - - return -ENOTSUP; -} - -static int max7219_blanking_off(const struct device *dev) -{ - ARG_UNUSED(dev); - - return -ENOTSUP; -} - static int max7219_write(const struct device *dev, const uint16_t x, const uint16_t y, const struct display_buffer_descriptor *desc, const void *buf) { @@ -213,25 +199,6 @@ static int max7219_write(const struct device *dev, const uint16_t x, const uint1 return 0; } -static int max7219_read(const struct device *dev, const uint16_t x, const uint16_t y, - const struct display_buffer_descriptor *desc, void *buf) -{ - ARG_UNUSED(dev); - ARG_UNUSED(x); - ARG_UNUSED(y); - ARG_UNUSED(desc); - ARG_UNUSED(buf); - - return -ENOTSUP; -} - -static void *max7219_get_framebuffer(const struct device *dev) -{ - ARG_UNUSED(dev); - - return NULL; -} - static int max7219_set_brightness(const struct device *dev, const uint8_t brightness) { int ret; @@ -249,14 +216,6 @@ static int max7219_set_brightness(const struct device *dev, const uint8_t bright return 0; } -static int max7219_set_contrast(const struct device *dev, const uint8_t contrast) -{ - ARG_UNUSED(dev); - ARG_UNUSED(contrast); - - return -ENOTSUP; -} - static int max7219_set_pixel_format(const struct device *dev, const enum display_pixel_format format) { @@ -296,13 +255,8 @@ static void max7219_get_capabilities(const struct device *dev, struct display_ca } static const struct display_driver_api max7219_api = { - .blanking_on = max7219_blanking_on, - .blanking_off = max7219_blanking_off, .write = max7219_write, - .read = max7219_read, - .get_framebuffer = max7219_get_framebuffer, .set_brightness = max7219_set_brightness, - .set_contrast = max7219_set_contrast, .get_capabilities = max7219_get_capabilities, .set_pixel_format = max7219_set_pixel_format, .set_orientation = max7219_set_orientation, From b9453d52ed352a031b89b77ed8159846dbc1c70e Mon Sep 17 00:00:00 2001 From: Robert Lubos Date: Tue, 5 Dec 2023 12:43:43 +0100 Subject: [PATCH 0877/3723] net: doc: Reference the Kconfig option that enables app libraries Several application protocol libraries documentation missed information on how can they be enabled (i. e. missed info about associated Kconfig symbol). This commit fixes it. Signed-off-by: Robert Lubos --- doc/connectivity/networking/api/coap.rst | 3 ++- doc/connectivity/networking/api/coap_client.rst | 1 + doc/connectivity/networking/api/http.rst | 1 + doc/connectivity/networking/api/lwm2m.rst | 2 ++ doc/connectivity/networking/api/mqtt.rst | 3 ++- doc/connectivity/networking/api/mqtt_sn.rst | 3 ++- doc/connectivity/networking/api/tftp.rst | 6 ++++++ 7 files changed, 16 insertions(+), 3 deletions(-) diff --git a/doc/connectivity/networking/api/coap.rst b/doc/connectivity/networking/api/coap.rst index ffb794a0c8a..e3a4d01d594 100644 --- a/doc/connectivity/networking/api/coap.rst +++ b/doc/connectivity/networking/api/coap.rst @@ -17,7 +17,8 @@ that support CoAP's features. For more information about the protocol itself, see `IETF RFC7252 The Constrained Application Protocol `_. Zephyr provides a CoAP library which supports client and server roles. -The library is configurable as per user needs. The Zephyr CoAP library +The library can be enabled with :kconfig:option:`CONFIG_COAP` Kconfig option and +is configurable as per user needs. The Zephyr CoAP library is implemented using plain buffers. Users of the API create sockets for communication and pass the buffer to the library for parsing and other purposes. The library itself doesn't create any sockets for users. diff --git a/doc/connectivity/networking/api/coap_client.rst b/doc/connectivity/networking/api/coap_client.rst index 2251bb3d0da..0d682a04746 100644 --- a/doc/connectivity/networking/api/coap_client.rst +++ b/doc/connectivity/networking/api/coap_client.rst @@ -11,6 +11,7 @@ Overview ******** The CoAP client library allows application to send CoAP requests and parse CoAP responses. +The library can be enabled with :kconfig:option:`CONFIG_COAP_CLIENT` Kconfig option. The application is notified about the response via a callback that is provided to the API in the request. The CoAP client handles the communication over sockets. As the CoAP client doesn't create socket it is using, the application is responsible for creating diff --git a/doc/connectivity/networking/api/http.rst b/doc/connectivity/networking/api/http.rst index 060a41643d9..d32748e77fa 100644 --- a/doc/connectivity/networking/api/http.rst +++ b/doc/connectivity/networking/api/http.rst @@ -13,6 +13,7 @@ Overview The HTTP client library allows you to send HTTP requests and parse HTTP responses. The library communicates over the sockets API but it does not create sockets on its own. +It can be enabled with :kconfig:option:`CONFIG_HTTP_CLIENT` Kconfig option. The application must be responsible for creating a socket and passing it to the library. Therefore, depending on the application's needs, the library can communicate over diff --git a/doc/connectivity/networking/api/lwm2m.rst b/doc/connectivity/networking/api/lwm2m.rst index 30bc439b72a..26b544144df 100644 --- a/doc/connectivity/networking/api/lwm2m.rst +++ b/doc/connectivity/networking/api/lwm2m.rst @@ -25,6 +25,8 @@ REST API to manage various interfaces with the client. LwM2M uses a simple resource model with the core set of objects and resources defined in the specification. +The LwM2M library can be enabled with :kconfig:option:`CONFIG_LWM2M` Kconfig option. + Example LwM2M object and resources: Device ****************************************** diff --git a/doc/connectivity/networking/api/mqtt.rst b/doc/connectivity/networking/api/mqtt.rst index 973b61860e3..9c75a20c5c2 100644 --- a/doc/connectivity/networking/api/mqtt.rst +++ b/doc/connectivity/networking/api/mqtt.rst @@ -16,7 +16,8 @@ publish/subscribe messaging transport for machine-to-machine communication. For more information about the protocol itself, see http://mqtt.org/. Zephyr provides an MQTT client library built on top of BSD sockets API. The -library is configurable at a per-client basis, with support for MQTT versions +library can be enabled with :kconfig:option:`CONFIG_MQTT_LIB` Kconfig option and +is configurable at a per-client basis, with support for MQTT versions 3.1.0 and 3.1.1. The Zephyr MQTT implementation can be used with either plain sockets communicating over TCP, or with secure sockets communicating over TLS. See :ref:`bsd_sockets_interface` for more information about Zephyr sockets. diff --git a/doc/connectivity/networking/api/mqtt_sn.rst b/doc/connectivity/networking/api/mqtt_sn.rst index 3da4d903725..318073bbe22 100644 --- a/doc/connectivity/networking/api/mqtt_sn.rst +++ b/doc/connectivity/networking/api/mqtt_sn.rst @@ -17,7 +17,8 @@ over any message-based transport. Originally, it was mainly created with ZigBee but others like Bluetooth, UDP or even a UART can be used just as well. Zephyr provides an MQTT-SN client library built on top of BSD sockets API. The -library is configurable at a per-client basis, with support for MQTT-SN version +library can be enabled with :kconfig:option:`CONFIG_MQTT_SN_LIB` Kconfig option +and is configurable at a per-client basis, with support for MQTT-SN version 1.2. The Zephyr MQTT-SN implementation can be used with any message-based transport, but support for UDP is already built-in. diff --git a/doc/connectivity/networking/api/tftp.rst b/doc/connectivity/networking/api/tftp.rst index 36d9d2cf0bb..6bb309e0791 100644 --- a/doc/connectivity/networking/api/tftp.rst +++ b/doc/connectivity/networking/api/tftp.rst @@ -3,6 +3,12 @@ TFTP #### +Zephyr provides a simple TFTP client library that can enabled with +:kconfig:option:`CONFIG_MQTT_SN_LIB` Kconfig option. + +See :zephyr:code-sample:`TFTP client sample application ` for +more information about the library usage. + API Reference ************* From ffc425191eb3000b71cc9fc60853b595e157cbcf Mon Sep 17 00:00:00 2001 From: Robert Lubos Date: Tue, 5 Dec 2023 12:57:18 +0100 Subject: [PATCH 0878/3723] net: doc: Remove Network Connectivity API page The Network Connectivity API page is kind of pointless, as it provides little information (which can be found elsewhere as well) and it was pointer out that it kind of creates noise in the documentation as it can be confused with the page which provides a summary of network APIs. Therefore, remove the page, and move the information from it elsewhere. The brief summary of what APIs to use was moved the Networking APIs index page. The information about the samples demonstrating BSD sockets API usage was moved to the BSD sockets documentation page itself. Signed-off-by: Robert Lubos --- doc/_scripts/redirects.py | 1 + doc/connectivity/networking/api/index.rst | 11 +++++++++++ doc/connectivity/networking/api/sockets.rst | 4 ++++ doc/connectivity/networking/index.rst | 1 - .../networking/networking-api-usage.rst | 16 ---------------- 5 files changed, 16 insertions(+), 17 deletions(-) delete mode 100644 doc/connectivity/networking/networking-api-usage.rst diff --git a/doc/_scripts/redirects.py b/doc/_scripts/redirects.py index 6101ca8faa8..dfabef8b880 100644 --- a/doc/_scripts/redirects.py +++ b/doc/_scripts/redirects.py @@ -17,6 +17,7 @@ ('application/index', 'develop/application/index'), ('boards/x86/ehl_crb/doc/index', 'boards/x86/intel_ehl/doc/index'), ('boards/x86/rpl_crb/doc/index', 'boards/x86/intel_rpl/doc/index'), + ('connectivity/networking/networking-api-usage', 'connectivity/networking/api/index'), ('development_process/code_flow', 'project/code_flow'), ('development_process/index', 'project/index'), ('development_process/issues', 'project/issues'), diff --git a/doc/connectivity/networking/api/index.rst b/doc/connectivity/networking/api/index.rst index 2386a075460..1264ff2aafb 100644 --- a/doc/connectivity/networking/api/index.rst +++ b/doc/connectivity/networking/api/index.rst @@ -3,6 +3,17 @@ Networking APIs ############### +Zephyr provides support for the standard BSD socket APIs (defined in +:zephyr_file:`include/zephyr/net/socket.h`) for the applications to +use. See :ref:`BSD socket API ` for more details. + +Apart of the standard API, Zephyr provides a set of custom networking APIs and +libraries for the application to use. See the list below for details. + +.. note:: + The legacy connectivity API in :zephyr_file:`include/zephyr/net/net_context.h` + should not be used by applications. + .. toctree:: :maxdepth: 2 diff --git a/doc/connectivity/networking/api/sockets.rst b/doc/connectivity/networking/api/sockets.rst index 139f4192444..5ea4429cf13 100644 --- a/doc/connectivity/networking/api/sockets.rst +++ b/doc/connectivity/networking/api/sockets.rst @@ -57,6 +57,10 @@ there is a table mapping file descriptors to internal object pointers. The file descriptor table is used by the BSD Sockets API even if the rest of the POSIX subsystem (filesystem, stdin/stdout) is not enabled. +See :zephyr:code-sample:`sockets-echo-server` and :zephyr:code-sample:`sockets-echo-client` +sample applications to learn how to create a simple server or client BSD socket based +application. + .. _secure_sockets_interface: Secure Sockets diff --git a/doc/connectivity/networking/index.rst b/doc/connectivity/networking/index.rst index f900bb56330..14efb069eac 100644 --- a/doc/connectivity/networking/index.rst +++ b/doc/connectivity/networking/index.rst @@ -12,7 +12,6 @@ operation of the stacks and how they were implemented. overview.rst net-stack-architecture.rst - networking-api-usage.rst networking_with_host.rst network_monitoring.rst api/index.rst diff --git a/doc/connectivity/networking/networking-api-usage.rst b/doc/connectivity/networking/networking-api-usage.rst deleted file mode 100644 index 0145482fec9..00000000000 --- a/doc/connectivity/networking/networking-api-usage.rst +++ /dev/null @@ -1,16 +0,0 @@ -.. _networking_api_usage: - -Network Connectivity API -######################## - -Applications should use the BSD socket API defined in -:zephyr_file:`include/zephyr/net/socket.h` to create a connection, send or receive data, -and close a connection. The same API can be used when working with UDP or -TCP data. See :ref:`BSD socket API ` for more details. - -See :zephyr:code-sample:`sockets-echo-server` and :zephyr:code-sample:`sockets-echo-client` -sample applications to learn how to create a simple server or client BSD socket based -application. - -The legacy connectivity API in :zephyr_file:`include/zephyr/net/net_context.h` should not be -used by applications. From 3e56b12c5811107700b5ce37e4748f2e45b64a82 Mon Sep 17 00:00:00 2001 From: Jonathan Rico Date: Tue, 5 Dec 2023 14:17:04 +0100 Subject: [PATCH 0879/3723] Bluetooth: ATT: don't access l2cap ops struct It's bad form, especially since in that case, it's always the same function that is called `bt_att_sent()`. Signed-off-by: Jonathan Rico --- subsys/bluetooth/host/att.c | 14 +++++++++++--- 1 file changed, 11 insertions(+), 3 deletions(-) diff --git a/subsys/bluetooth/host/att.c b/subsys/bluetooth/host/att.c index 2b5206bcd0f..6bae608ff55 100644 --- a/subsys/bluetooth/host/att.c +++ b/subsys/bluetooth/host/att.c @@ -212,17 +212,25 @@ static void bt_att_disconnected(struct bt_l2cap_chan *chan); struct net_buf *bt_att_create_rsp_pdu(struct bt_att_chan *chan, uint8_t op, size_t len); +static void bt_att_sent(struct bt_l2cap_chan *ch); + void att_sent(struct bt_conn *conn, void *user_data) { struct bt_att_tx_meta_data *data = user_data; struct bt_att_chan *att_chan = data->att_chan; struct bt_l2cap_chan *chan = &att_chan->chan.chan; + __ASSERT_NO_MSG(!bt_att_is_enhanced(att_chan)); + LOG_DBG("conn %p chan %p", conn, chan); - if (chan->ops->sent) { - chan->ops->sent(chan); - } + /* For EATT, `bt_att_sent` is assigned to the `.sent` L2 callback. + * L2CAP will then call it once the SDU has finished sending. + * + * For UATT, this won't happen, as static LE l2cap channels don't have + * SDUs. Call it manually instead. + */ + bt_att_sent(chan); } static int att_chan_send_cb(struct bt_att_chan *att_chan, From 0c26bdd86f1cbd92a3488aac0fb02b71ccc1f372 Mon Sep 17 00:00:00 2001 From: Torsten Rasmussen Date: Tue, 5 Dec 2023 14:55:19 +0100 Subject: [PATCH 0880/3723] doc: add EXTRA_DTC_OVERLAY_FILE to list of important build variables The EXTRA_DTC_OVERLAY_FILE is also an important build system variable, therefore add it to the list and give a brief description. Signed-off-by: Torsten Rasmussen --- doc/develop/application/index.rst | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/doc/develop/application/index.rst b/doc/develop/application/index.rst index f2be0d8b551..4346e011670 100644 --- a/doc/develop/application/index.rst +++ b/doc/develop/application/index.rst @@ -429,6 +429,11 @@ should know about. See :ref:`set-devicetree-overlays` for examples and :ref:`devicetree-intro` for information about devicetree and Zephyr. +* :makevar:`EXTRA_DTC_OVERLAY_FILE`: Additional devicetree overlay files to use. + Multiple files can be separated with semicolons. This can be useful to leave + :makevar:`DTC_OVERLAY_FILE` at its default value, but "mix in" some additional + overlay files. + * :makevar:`SHIELD`: see :ref:`shields` * :makevar:`ZEPHYR_MODULES`: A `CMake list`_ containing absolute paths of From 8358cdd6975799c45dcfb3706851d6644bbbbbf6 Mon Sep 17 00:00:00 2001 From: Marc Lasch Date: Tue, 5 Dec 2023 16:06:11 +0100 Subject: [PATCH 0881/3723] net: lwm2m: Reduce dependency on firmware update pull Kconfig There are functions whose headers are only visible when CONFIG_LWM2M_FIRMWARE_UPDATE_PULL_SUPPORT is selected. However these functions are used outside the scope of the firmware update pull functionality. This change allows to disable CONFIG_LWM2M_FIRMWARE_UPDATE_PULL_SUPPORT while still being able to use the firmware update object. Signed-off-by: Marc Lasch --- include/zephyr/net/lwm2m.h | 3 --- 1 file changed, 3 deletions(-) diff --git a/include/zephyr/net/lwm2m.h b/include/zephyr/net/lwm2m.h index 6ac0458af87..51324f63153 100644 --- a/include/zephyr/net/lwm2m.h +++ b/include/zephyr/net/lwm2m.h @@ -551,7 +551,6 @@ void lwm2m_firmware_set_cancel_cb_inst(uint16_t obj_inst_id, lwm2m_engine_user_c */ lwm2m_engine_user_cb_t lwm2m_firmware_get_cancel_cb_inst(uint16_t obj_inst_id); -#if defined(CONFIG_LWM2M_FIRMWARE_UPDATE_PULL_SUPPORT) || defined(__DOXYGEN__) /** * @brief Set data callback to handle firmware update execute events. * @@ -588,8 +587,6 @@ void lwm2m_firmware_set_update_cb_inst(uint16_t obj_inst_id, lwm2m_engine_execut */ lwm2m_engine_execute_cb_t lwm2m_firmware_get_update_cb_inst(uint16_t obj_inst_id); #endif -#endif - #if defined(CONFIG_LWM2M_SWMGMT_OBJ_SUPPORT) || defined(__DOXYGEN__) From 8add7cb62f2a5430a8e676d54853aa56c544d4b9 Mon Sep 17 00:00:00 2001 From: Alberto Escolar Piedras Date: Tue, 5 Dec 2023 17:09:20 +0100 Subject: [PATCH 0882/3723] soc/posix posix_native_task: Replace native_posix in description Replace native_posix in the NATIVE_TASK description. Signed-off-by: Alberto Escolar Piedras --- soc/posix/inf_clock/posix_native_task.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/soc/posix/inf_clock/posix_native_task.h b/soc/posix/inf_clock/posix_native_task.h index cb6fded1ccd..3cb5e310ee1 100644 --- a/soc/posix/inf_clock/posix_native_task.h +++ b/soc/posix/inf_clock/posix_native_task.h @@ -16,8 +16,8 @@ extern "C" { /** * NATIVE_TASK * - * For native_posix, register a function to be called at particular moments - * during the native_posix execution. + * For native targets (POSIX arch based), register a function to be called at particular moments + * during the native target execution. * * There is 5 choices for when the function will be called (level): * * PRE_BOOT_1: Will be called before the command line parameters are parsed, From 9323a3f9c71b1c244be9996b7ae70bd6669583b3 Mon Sep 17 00:00:00 2001 From: Alberto Escolar Piedras Date: Tue, 5 Dec 2023 17:10:46 +0100 Subject: [PATCH 0883/3723] arch/Kconfig: Fix ARCH_POSIX comment The comment applies to all POSIX arch based targets, not just native_posix. Signed-off-by: Alberto Escolar Piedras --- arch/Kconfig | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/arch/Kconfig b/arch/Kconfig index 2884540ef37..bc99f789014 100644 --- a/arch/Kconfig +++ b/arch/Kconfig @@ -140,7 +140,7 @@ config ARCH_POSIX select NATIVE_BUILD select HAS_COVERAGE_SUPPORT select BARRIER_OPERATIONS_BUILTIN - # native_posix gets its memory cleared on entry by the host OS + # POSIX arch based targets get their memory cleared on entry by the host OS select SKIP_BSS_CLEAR help POSIX (native) architecture From 94b16c4d2d1d99292214479757e6bd63257866c0 Mon Sep 17 00:00:00 2001 From: Alberto Escolar Piedras Date: Tue, 5 Dec 2023 17:11:28 +0100 Subject: [PATCH 0884/3723] drivers/sensor Kconfig: Replace native_posix with native_sim Use native_sim in the help messages platforms examples instead of native_posix. Signed-off-by: Alberto Escolar Piedras --- drivers/sensor/akm09918c/Kconfig | 2 +- drivers/sensor/icm42688/Kconfig | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/sensor/akm09918c/Kconfig b/drivers/sensor/akm09918c/Kconfig index 2765d70a21e..d90f8662dc5 100644 --- a/drivers/sensor/akm09918c/Kconfig +++ b/drivers/sensor/akm09918c/Kconfig @@ -16,4 +16,4 @@ config EMUL_AKM09918C depends on EMUL help Enable the hardware emulator for the AKM09918C. Doing so allows exercising - sensor APIs for this magnetometer in native_posix and qemu. + sensor APIs for this magnetometer in native_sim and qemu. diff --git a/drivers/sensor/icm42688/Kconfig b/drivers/sensor/icm42688/Kconfig index d7ee43bc761..08779dc72d9 100644 --- a/drivers/sensor/icm42688/Kconfig +++ b/drivers/sensor/icm42688/Kconfig @@ -19,7 +19,7 @@ config EMUL_ICM42688 depends on EMUL help Enable the hardware emulator for the ICM42688. Doing so allows exercising - sensor APIs for this IMU in native_posix and qemu. + sensor APIs for this IMU in native_sim and qemu. config ICM42688_DECODER bool "ICM42688 decoder logic" From 53bbded264854556502a5ac61979ae4c7d964d44 Mon Sep 17 00:00:00 2001 From: Alberto Escolar Piedras Date: Tue, 5 Dec 2023 17:12:43 +0100 Subject: [PATCH 0885/3723] drivers/serial native: Replace native_posix with native_sim in comments In the kconfig descriptions and the links to documents replace native_posix with native_sim, or a generally applicable description. Signed-off-by: Alberto Escolar Piedras --- drivers/serial/Kconfig.native_posix | 12 ++++++------ drivers/serial/uart_native_tty.c | 4 ++-- 2 files changed, 8 insertions(+), 8 deletions(-) diff --git a/drivers/serial/Kconfig.native_posix b/drivers/serial/Kconfig.native_posix index 39acf155f9b..3af6601b5c7 100644 --- a/drivers/serial/Kconfig.native_posix +++ b/drivers/serial/Kconfig.native_posix @@ -1,14 +1,14 @@ # SPDX-License-Identifier: Apache-2.0 config UART_NATIVE_POSIX - bool "UART driver for native_posix" + bool "UART driver for native_sim/posix" default y depends on DT_HAS_ZEPHYR_NATIVE_POSIX_UART_ENABLED select SERIAL_HAS_DRIVER help This enables a UART driver for the POSIX ARCH with up to 2 UARTs. For the first UART port, the driver can be configured - to either connect to the terminal from which native_posix was run, or into + to either connect to the terminal from which the executable was run, or into one dedicated pseudoterminal for that UART. if UART_NATIVE_POSIX @@ -22,14 +22,14 @@ config NATIVE_UART_0_ON_OWN_PTY help Connect this UART to its own pseudoterminal. This is the preferred option for users who want to use Zephyr's shell. - Moreover this option does not conflict with any other native_posix - backend which may use the calling shell standard input/output. + Moreover this option does not conflict with any other native + backend which may use the invoking shell standard input/output. config NATIVE_UART_0_ON_STDINOUT bool "Connect the UART to the invoking shell stdin/stdout" help Connect this UART to the stdin & stdout of the calling shell/terminal - which invoked the native_posix executable. This is good enough for + which invoked the native executable. This is good enough for automated testing, or when feeding from a file/pipe. Note that other, non UART messages, will also be printed to the terminal. @@ -60,7 +60,7 @@ config NATIVE_UART_AUTOATTACH_DEFAULT_CMD string "Default command to attach the UART to a new terminal" default "xterm -e screen %s &" help - If the native_posix executable is called with the --attach_uart + If the native executable is called with the --attach_uart command line option, this will be the default command which will be run to attach a new terminal to the 1st UART. Note that this command must have one, and only one, '%s' as diff --git a/drivers/serial/uart_native_tty.c b/drivers/serial/uart_native_tty.c index 22f2b0e539f..5f6de6e0cbe 100644 --- a/drivers/serial/uart_native_tty.c +++ b/drivers/serial/uart_native_tty.c @@ -6,9 +6,9 @@ * command line options or at runtime. * * To learn more see Native TTY section at: - * https://docs.zephyrproject.org/latest/boards/posix/native_posix/doc/index.html + * https://docs.zephyrproject.org/latest/boards/posix/native_sim/doc/index.html * or - * ${ZEPHYR_BASE}/boards/posix/native_posix/doc/index.rst + * ${ZEPHYR_BASE}/boards/posix/native_sim/doc/index.rst * * Copyright (c) 2023 Marko Sagadin * SPDX-License-Identifier: Apache-2.0 From 9f15c41a7eb4a3a5ceca09808635ed78ff049706 Mon Sep 17 00:00:00 2001 From: Alberto Escolar Piedras Date: Tue, 5 Dec 2023 17:14:05 +0100 Subject: [PATCH 0886/3723] drivers/timer native: Replace native_posix with native_posix/sim This driver is applicable to both targets. Let's be clear about that. Signed-off-by: Alberto Escolar Piedras --- drivers/timer/Kconfig.native_posix | 4 ++-- drivers/timer/native_posix_timer.c | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/drivers/timer/Kconfig.native_posix b/drivers/timer/Kconfig.native_posix index 6fe1c3bde4d..278feeec2a8 100644 --- a/drivers/timer/Kconfig.native_posix +++ b/drivers/timer/Kconfig.native_posix @@ -4,12 +4,12 @@ # SPDX-License-Identifier: Apache-2.0 config NATIVE_POSIX_TIMER - bool "(POSIX) native_posix timer driver" + bool "(POSIX) native_sim/posix timer driver" default y depends on BOARD_NATIVE_POSIX select TICKLESS_CAPABLE select TIMER_HAS_64BIT_CYCLE_COUNTER select SYSTEM_TIMER_HAS_DISABLE_SUPPORT help - This module implements a kernel device driver for the native_posix HW timer + This module implements a kernel device driver for the native_sim/posix HW timer model diff --git a/drivers/timer/native_posix_timer.c b/drivers/timer/native_posix_timer.c index 31d1fc3bc69..7376034ef62 100644 --- a/drivers/timer/native_posix_timer.c +++ b/drivers/timer/native_posix_timer.c @@ -5,7 +5,7 @@ */ /** - * Driver for the timer model of the POSIX native_posix board + * Driver for the timer model of the POSIX native_sim/posix board * It provides the interfaces required by the kernel and the sanity testcases * It also provides a custom k_busy_wait() which can be used with the * POSIX arch and InfClock SOC From 19ac0a28399f4232644f49bd21045677bab55674 Mon Sep 17 00:00:00 2001 From: Alberto Escolar Piedras Date: Tue, 5 Dec 2023 17:15:01 +0100 Subject: [PATCH 0887/3723] drivers adc_emul: Refer to native_sim overlay instead of native_posix Refer to the native_sim overlay instead of the native_posix one. Signed-off-by: Alberto Escolar Piedras --- include/zephyr/drivers/adc/adc_emul.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/include/zephyr/drivers/adc/adc_emul.h b/include/zephyr/drivers/adc/adc_emul.h index a07b86e38c9..03c2fbbb3fd 100644 --- a/include/zephyr/drivers/adc/adc_emul.h +++ b/include/zephyr/drivers/adc/adc_emul.h @@ -38,7 +38,7 @@ extern "C" { * function which will be used to obtain voltage on emulated ADC input * * An example of an appropriate Device Tree overlay file is in - * tests/drivers/adc/adc_api/boards/native_posix.overlay + * tests/drivers/adc/adc_api/boards/native_sim.overlay * * An example of using emulated ADC backend API is in the file * tests/drivers/adc/adc_emul/src/main.c From 093c7f4137cb88f1a5cd9152c2b2fd1052224527 Mon Sep 17 00:00:00 2001 From: Peter Mitsis Date: Tue, 5 Dec 2023 10:59:22 -0500 Subject: [PATCH 0888/3723] tests: benchmark: Add case for object core stats Updates both the app_kernel and latency_measure testcase scripts to include a scenario involving object core statistics. This can then be used to estimate the performance cost of using this feature post-execution by comparing its results to the scenario where it is not enabled. Signed-off-by: Peter Mitsis --- tests/benchmarks/app_kernel/testcase.yaml | 16 +++++++ .../benchmarks/latency_measure/testcase.yaml | 42 +++++++++++++++++++ 2 files changed, 58 insertions(+) diff --git a/tests/benchmarks/app_kernel/testcase.yaml b/tests/benchmarks/app_kernel/testcase.yaml index 19aeb6fbe52..07a3720993a 100644 --- a/tests/benchmarks/app_kernel/testcase.yaml +++ b/tests/benchmarks/app_kernel/testcase.yaml @@ -10,9 +10,25 @@ tests: integration_platforms: - mps2_an385 - qemu_x86 + benchmark.kernel.application.objcore.stats: + integration_platforms: + - mps2_an385 + - qemu_x86 + extra_configs: + - CONFIG_OBJ_CORE=y + - CONFIG_OBJ_CORE_STATS=y benchmark.kernel.application.user: extra_args: CONF_FILE=prj_user.conf filter: CONFIG_ARCH_HAS_USERSPACE integration_platforms: - qemu_x86 - qemu_cortex_a53 + benchmark.kernel.application.user.objcore.stats: + extra_args: CONF_FILE=prj_user.conf + filter: CONFIG_ARCH_HAS_USERSPACE + integration_platforms: + - qemu_x86 + - qemu_cortex_a53 + extra_configs: + - CONFIG_OBJ_CORE=y + - CONFIG_OBJ_CORE_STATS=y diff --git a/tests/benchmarks/latency_measure/testcase.yaml b/tests/benchmarks/latency_measure/testcase.yaml index eb63c107d86..e63fc9e5b30 100644 --- a/tests/benchmarks/latency_measure/testcase.yaml +++ b/tests/benchmarks/latency_measure/testcase.yaml @@ -21,6 +21,27 @@ tests: - "PROJECT EXECUTION SUCCESSFUL" + benchmark.kernel.latency.objcore.stats: + # FIXME: no DWT and no RTC_TIMER for qemu_cortex_m0 + platform_exclude: + - qemu_cortex_m0 + - m2gl025_miv + filter: CONFIG_PRINTK and not CONFIG_SOC_FAMILY_STM32 + harness: console + integration_platforms: + - qemu_x86 + - qemu_arc_em + extra_configs: + - CONFIG_OBJ_CORE=y + - CONFIG_OBJ_CORE_STATS=y + harness_config: + type: one_line + record: + regex: "(?P.*):(?P.*) cycles ,(?P.*) ns" + regex: + - "PROJECT EXECUTION SUCCESSFUL" + + # Cortex-M has 24bit systick, so default 1 TICK per seconds # is achievable only if frequency is below 0x00FFFFFF (around 16MHz) # 20 Ticks per secondes allows a frequency up to 335544300Hz (335MHz) @@ -53,3 +74,24 @@ tests: regex: "(?P.*):(?P.*) cycles ,(?P.*) ns" regex: - "PROJECT EXECUTION SUCCESSFUL" + + # Obtain the benchmark results with object core statistics enabled for + # various user thread / kernel thread configurations on platforms that + # support user space + benchmark.user.latency.objcore.stats: + filter: CONFIG_ARCH_HAS_USERSPACE + timeout: 300 + extra_args: CONF_FILE=prj_user.conf + harness: console + integration_platforms: + - qemu_x86 + - qemu_cortex_a53 + extra_configs: + - CONFIG_OBJ_CORE=y + - CONFIG_OBJ_CORE_STATS=y + harness_config: + type: one_line + record: + regex: "(?P.*):(?P.*) cycles ,(?P.*) ns" + regex: + - "PROJECT EXECUTION SUCCESSFUL" From a3e5af95de0469f17488892daa966c5b06db78bc Mon Sep 17 00:00:00 2001 From: Peter Mitsis Date: Tue, 5 Dec 2023 13:40:19 -0500 Subject: [PATCH 0889/3723] kernel: Update k_sleep() and k_usleep() return values Updates both the k_sleep() and k_usleep() return values so that if the thread was woken up prematurely, they will return the time left to sleep rounded up to the nearest millisecond (for k_sleep) or microsecond (for k_usleep) instead of rounding down. This removes ambiguity should there be a non-zero number of remaining ticks that correlate to a time of less than 1 millisecond or 1 microsecond. Signed-off-by: Peter Mitsis --- include/zephyr/kernel.h | 15 +++++++++------ kernel/sched.c | 8 +++++--- 2 files changed, 14 insertions(+), 9 deletions(-) diff --git a/include/zephyr/kernel.h b/include/zephyr/kernel.h index 1ea059e5df4..7f62ef1e768 100644 --- a/include/zephyr/kernel.h +++ b/include/zephyr/kernel.h @@ -467,8 +467,9 @@ __syscall int k_thread_join(struct k_thread *thread, k_timeout_t timeout); * * @param timeout Desired duration of sleep. * - * @return Zero if the requested time has elapsed or the number of milliseconds - * left to sleep, if thread was woken up by \ref k_wakeup call. + * @return Zero if the requested time has elapsed or if the thread was woken up + * by the \ref k_wakeup call, the time left to sleep rounded up to the nearest + * millisecond. */ __syscall int32_t k_sleep(k_timeout_t timeout); @@ -479,8 +480,9 @@ __syscall int32_t k_sleep(k_timeout_t timeout); * * @param ms Number of milliseconds to sleep. * - * @return Zero if the requested time has elapsed or the number of milliseconds - * left to sleep, if thread was woken up by \ref k_wakeup call. + * @return Zero if the requested time has elapsed or if the thread was woken up + * by the \ref k_wakeup call, the time left to sleep rounded up to the nearest + * millisecond. */ static inline int32_t k_msleep(int32_t ms) { @@ -499,8 +501,9 @@ static inline int32_t k_msleep(int32_t ms) * * @param us Number of microseconds to sleep. * - * @return Zero if the requested time has elapsed or the number of microseconds - * left to sleep, if thread was woken up by \ref k_wakeup call. + * @return Zero if the requested time has elapsed or if the thread was woken up + * by the \ref k_wakeup call, the time left to sleep rounded up to the nearest + * microsecond. */ __syscall int32_t k_usleep(int32_t us); diff --git a/kernel/sched.c b/kernel/sched.c index 7dd782c9490..f2fd98d0cfd 100644 --- a/kernel/sched.c +++ b/kernel/sched.c @@ -1590,7 +1590,7 @@ int32_t z_impl_k_sleep(k_timeout_t timeout) ticks = z_tick_sleep(ticks); - int32_t ret = k_ticks_to_ms_floor64(ticks); + int32_t ret = k_ticks_to_ms_ceil64(ticks); SYS_PORT_TRACING_FUNC_EXIT(k_thread, sleep, timeout, ret); @@ -1614,9 +1614,11 @@ int32_t z_impl_k_usleep(int us) ticks = k_us_to_ticks_ceil64(us); ticks = z_tick_sleep(ticks); - SYS_PORT_TRACING_FUNC_EXIT(k_thread, usleep, us, k_ticks_to_us_floor64(ticks)); + int32_t ret = k_ticks_to_us_ceil64(ticks); - return k_ticks_to_us_floor64(ticks); + SYS_PORT_TRACING_FUNC_EXIT(k_thread, usleep, us, ret); + + return ret; } #ifdef CONFIG_USERSPACE From ed610400bcb74338d25e4b29f948709efe12f3a3 Mon Sep 17 00:00:00 2001 From: Nikos Agianniotis Date: Tue, 5 Dec 2023 22:21:44 +0100 Subject: [PATCH 0890/3723] drivers: sensor: mcp9600: fix wrong register address The address of most of the registers defined in the driver are wrong. This fixes it, following the correct numbering as can be found in the device's datasheet. Moreover, re-grouping of the macros according to their functionality. Signed-off-by: Nikos Agianniotis --- drivers/sensor/mcp9600/mcp9600.c | 33 ++++++++++++++++---------------- 1 file changed, 17 insertions(+), 16 deletions(-) diff --git a/drivers/sensor/mcp9600/mcp9600.c b/drivers/sensor/mcp9600/mcp9600.c index ed5fb8b97f7..dfec3a5d064 100644 --- a/drivers/sensor/mcp9600/mcp9600.c +++ b/drivers/sensor/mcp9600/mcp9600.c @@ -25,22 +25,23 @@ LOG_MODULE_REGISTER(MCP9600, CONFIG_SENSOR_LOG_LEVEL); #define MCP9600_REG_TC_CONFIG 0x05 #define MCP9600_REG_DEV_CONFIG 0x06 -#define MCP9600_REG_A1_CONFIG 0x07 - -#define MCP9600_REG_A2_CONFIG 0x08 -#define MCP9600_REG_A3_CONFIG 0x09 -#define MCP9600_REG_A4_CONFIG 0x0A -#define MCP9600_A1_HYST 0x0B - -#define MCP9600_A2_HYST 0x0C -#define MCP9600_A3_HYST 0x0D -#define MCP9600_A4_HYST 0x0E -#define MCP9600_A1_LIMIT 0x0F - -#define MCP9600_A2_LIMIT 0x10 -#define MCP9600_A3_LIMIT 0x11 -#define MCP9600_A4_LIMIT 0x12 -#define MCP9600_REG_ID_REVISION 0x13 + +#define MCP9600_REG_A1_CONFIG 0x08 +#define MCP9600_REG_A2_CONFIG 0x09 +#define MCP9600_REG_A3_CONFIG 0x0A +#define MCP9600_REG_A4_CONFIG 0x0B + +#define MCP9600_A1_HYST 0x0C +#define MCP9600_A2_HYST 0x0D +#define MCP9600_A3_HYST 0x0E +#define MCP9600_A4_HYST 0x0F + +#define MCP9600_A1_LIMIT 0x10 +#define MCP9600_A2_LIMIT 0x11 +#define MCP9600_A3_LIMIT 0x12 +#define MCP9600_A4_LIMIT 0x13 + +#define MCP9600_REG_ID_REVISION 0x20 struct mcp9600_data { int32_t temp; From f147e8b8f58a6069b60ac4745056162a9806ed0c Mon Sep 17 00:00:00 2001 From: Jamie McCrae Date: Mon, 4 Dec 2023 15:38:32 +0000 Subject: [PATCH 0891/3723] dfu: boot: mcuboot_shell: Prevent erasing MCUboot/app flash areas Prevents the user from potentially bricking a device by erasing the MCUboot or currently running application flash areas with the mcuboot erase command Signed-off-by: Jamie McCrae --- subsys/dfu/boot/mcuboot_shell.c | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/subsys/dfu/boot/mcuboot_shell.c b/subsys/dfu/boot/mcuboot_shell.c index c069edf9c31..be4e558713f 100644 --- a/subsys/dfu/boot/mcuboot_shell.c +++ b/subsys/dfu/boot/mcuboot_shell.c @@ -1,5 +1,6 @@ /* * Copyright (c) 2020 Grinn + * Copyright (c) 2023 Nordic Semiconductor ASA * * SPDX-License-Identifier: Apache-2.0 */ @@ -91,6 +92,21 @@ static int cmd_mcuboot_erase(const struct shell *sh, size_t argc, id = strtoul(argv[1], NULL, 0); + /* Check if this is the parent (MCUboot) or own slot and if so, deny the request */ +#if FIXED_PARTITION_EXISTS(boot_partition) + if (id == FIXED_PARTITION_ID(boot_partition)) { + shell_error(sh, "Cannot erase boot partition"); + return -EACCES; + } +#endif + +#if DT_FIXED_PARTITION_EXISTS(DT_CHOSEN(zephyr_code_partition)) + if (id == DT_FIXED_PARTITION_ID(DT_CHOSEN(zephyr_code_partition))) { + shell_error(sh, "Cannot erase active partitions"); + return -EACCES; + } +#endif + err = boot_erase_img_bank(id); if (err) { shell_error(sh, "failed to erase bank %u", id); From 227905ac4df141441ddea6a301cb9bd80821d2ca Mon Sep 17 00:00:00 2001 From: Jamie McCrae Date: Mon, 4 Dec 2023 15:41:01 +0000 Subject: [PATCH 0892/3723] doc: release: 3.6: Add note on fixed MCUboot erase issue Adds a note that the shell mcuboot erase command can no longer erase the MCUboot or application slots Signed-off-by: Jamie McCrae --- doc/releases/release-notes-3.6.rst | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/doc/releases/release-notes-3.6.rst b/doc/releases/release-notes-3.6.rst index 3295a128ded..1fc6620c756 100644 --- a/doc/releases/release-notes-3.6.rst +++ b/doc/releases/release-notes-3.6.rst @@ -280,9 +280,12 @@ Libraries / Subsystems * Implemented datetime functionality in MCUmgr OS management group, this makes use of the RTC driver API. - * Fixes an issue in MCUmgr console UART input whereby the FIFO would be read outside of an ISR, + * Fixed an issue in MCUmgr console UART input whereby the FIFO would be read outside of an ISR, which is not supported in the next USB stack. + * Fixed an issue whereby the ``mcuboot erase`` DFU shell command could be used to erase the + MCUboot or currently running application slot. + * File systems * Modem modules From 3fec3964e046064b83eec405c5130a0e3b53f3fe Mon Sep 17 00:00:00 2001 From: Emil Gydesen Date: Thu, 2 Nov 2023 20:31:09 +0100 Subject: [PATCH 0893/3723] Bluetooth: CAP: Move initiator/commander common code to cap_common The CAP Initiator and the CAP Commendar share quite a lot of functionality in terms of discovery and performing set-based procedures. The code for handling most of this has been moved to cap_common.c to avoid duplicating code. Signed-off-by: Emil Gydesen --- subsys/bluetooth/Kconfig.logging | 5 + subsys/bluetooth/audio/CMakeLists.txt | 3 + subsys/bluetooth/audio/Kconfig.cap | 3 + subsys/bluetooth/audio/cap_common.c | 334 +++++++++ subsys/bluetooth/audio/cap_initiator.c | 670 +++++------------- subsys/bluetooth/audio/cap_internal.h | 104 ++- tests/bluetooth/shell/audio.conf | 1 + .../audio/src/cap_initiator_unicast_test.c | 6 +- 8 files changed, 627 insertions(+), 499 deletions(-) create mode 100644 subsys/bluetooth/audio/cap_common.c diff --git a/subsys/bluetooth/Kconfig.logging b/subsys/bluetooth/Kconfig.logging index 679d719cdad..0da05c687fd 100644 --- a/subsys/bluetooth/Kconfig.logging +++ b/subsys/bluetooth/Kconfig.logging @@ -726,6 +726,11 @@ module = BT_CAP_COMMANDER module-str = "Common Audio Profile Commander" source "subsys/logging/Kconfig.template.log_config_inherit" +parent-module = BT +module = BT_CAP_COMMON +module-str = "Common Audio Profile Common" +source "subsys/logging/Kconfig.template.log_config_inherit" + parent-module = BT module = BT_CAP_STREAM module-str = "Common Audio Profile Stream" diff --git a/subsys/bluetooth/audio/CMakeLists.txt b/subsys/bluetooth/audio/CMakeLists.txt index 5c2a6eb3fea..5e73695c5c3 100644 --- a/subsys/bluetooth/audio/CMakeLists.txt +++ b/subsys/bluetooth/audio/CMakeLists.txt @@ -62,4 +62,7 @@ zephyr_library_sources_ifdef(CONFIG_BT_CAP cap_stream.c) zephyr_library_sources_ifdef(CONFIG_BT_CAP_ACCEPTOR cap_acceptor.c) zephyr_library_sources_ifdef(CONFIG_BT_CAP_INITIATOR cap_initiator.c) zephyr_library_sources_ifdef(CONFIG_BT_CAP_COMMANDER cap_commander.c) +if (CONFIG_BT_CAP_INITIATOR OR CONFIG_BT_CAP_COMMANDER) + zephyr_library_sources(cap_common.c) +endif() zephyr_library_sources_ifdef(CONFIG_BT_TMAP tmap.c) diff --git a/subsys/bluetooth/audio/Kconfig.cap b/subsys/bluetooth/audio/Kconfig.cap index 0488b610a08..2a130f53d9a 100644 --- a/subsys/bluetooth/audio/Kconfig.cap +++ b/subsys/bluetooth/audio/Kconfig.cap @@ -28,6 +28,9 @@ config BT_CAP_ACCEPTOR_SET_MEMBER Enabling will take one of the allocated CSIS instances (BT_CSIP_SET_MEMBER_MAX_INSTANCE_COUNT). +config BT_CAP_INITIATOR_UNICAST + def_bool BT_CAP_INITIATOR && BT_BAP_UNICAST_CLIENT + config BT_CAP_INITIATOR bool "Common Audio Profile Initiator Role Support [EXPERIMENTAL]" depends on (BT_BAP_UNICAST_CLIENT && BT_CSIP_SET_COORDINATOR) || BT_BAP_BROADCAST_SOURCE diff --git a/subsys/bluetooth/audio/cap_common.c b/subsys/bluetooth/audio/cap_common.c new file mode 100644 index 00000000000..c0862f3e98b --- /dev/null +++ b/subsys/bluetooth/audio/cap_common.c @@ -0,0 +1,334 @@ +/* + * Copyright (c) 2023 Nordic Semiconductor ASA + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include + +#include "cap_internal.h" +#include "csip_internal.h" + +LOG_MODULE_REGISTER(bt_cap_common, CONFIG_BT_CAP_COMMON_LOG_LEVEL); + +#include "common/bt_str.h" + +static struct bt_cap_common_client bt_cap_common_clients[CONFIG_BT_MAX_CONN]; +static const struct bt_uuid *cas_uuid = BT_UUID_CAS; +static struct bt_cap_common_proc active_proc; +static bt_cap_common_discover_func_t discover_cb_func; + +struct bt_cap_common_proc *bt_cap_common_get_active_proc(void) +{ + return &active_proc; +} + +void bt_cap_common_clear_active_proc(void) +{ + (void)memset(&active_proc, 0, sizeof(active_proc)); +} + +void bt_cap_common_start_proc(enum bt_cap_common_proc_type proc_type, size_t proc_cnt) +{ + atomic_set_bit(active_proc.proc_state_flags, BT_CAP_COMMON_PROC_STATE_ACTIVE); + active_proc.proc_cnt = proc_cnt; + active_proc.proc_type = proc_type; + active_proc.proc_done_cnt = 0U; + active_proc.proc_initiated_cnt = 0U; +} + +#if defined(CONFIG_BT_CAP_INITIATOR_UNICAST) +void bt_cap_common_set_subproc(enum bt_cap_common_subproc_type subproc_type) +{ + active_proc.proc_done_cnt = 0U; + active_proc.proc_initiated_cnt = 0U; + active_proc.subproc_type = subproc_type; +} + +bool bt_cap_common_subproc_is_type(enum bt_cap_common_subproc_type subproc_type) +{ + return active_proc.subproc_type == subproc_type; +} +#endif /* CONFIG_BT_CAP_INITIATOR_UNICAST */ + +bool bt_cap_common_proc_is_active(void) +{ + return atomic_test_bit(active_proc.proc_state_flags, BT_CAP_COMMON_PROC_STATE_ACTIVE); +} + +bool bt_cap_common_proc_is_aborted(void) +{ + return atomic_test_bit(active_proc.proc_state_flags, BT_CAP_COMMON_PROC_STATE_ABORTED); +} + +bool bt_cap_common_proc_all_streams_handled(void) +{ + return active_proc.proc_done_cnt == active_proc.proc_initiated_cnt; +} + +bool bt_cap_common_proc_is_done(void) +{ + return active_proc.proc_done_cnt == active_proc.proc_cnt; +} + +void bt_cap_common_abort_proc(struct bt_conn *conn, int err) +{ + if (bt_cap_common_proc_is_aborted()) { + /* no-op */ + return; + } + + active_proc.err = err; + active_proc.failed_conn = conn; + atomic_set_bit(active_proc.proc_state_flags, BT_CAP_COMMON_PROC_STATE_ABORTED); +} + +#if defined(CONFIG_BT_CAP_INITIATOR_UNICAST) +static bool active_proc_is_initiator(void) +{ + switch (active_proc.proc_type) { + case BT_CAP_COMMON_PROC_TYPE_START: + case BT_CAP_COMMON_PROC_TYPE_UPDATE: + case BT_CAP_COMMON_PROC_TYPE_STOP: + return true; + default: + return false; + } +} +#endif /* CONFIG_BT_CAP_INITIATOR_UNICAST */ + +bool bt_cap_common_conn_in_active_proc(const struct bt_conn *conn) +{ + if (!bt_cap_common_proc_is_active()) { + return false; + } + +#if defined(CONFIG_BT_CAP_INITIATOR_UNICAST) + if (active_proc_is_initiator()) { + for (size_t i = 0U; i < active_proc.proc_initiated_cnt; i++) { + if (active_proc.proc_param.initiator[i].stream->bap_stream.conn == conn) { + return true; + } + } + } +#endif /* CONFIG_BT_CAP_INITIATOR_UNICAST */ + + return false; +} + +bool bt_cap_common_stream_in_active_proc(const struct bt_cap_stream *cap_stream) +{ + if (!bt_cap_common_proc_is_active()) { + return false; + } + +#if defined(CONFIG_BT_CAP_INITIATOR_UNICAST) + if (active_proc_is_initiator()) { + for (size_t i = 0U; i < active_proc.proc_cnt; i++) { + if (active_proc.proc_param.initiator[i].stream == cap_stream) { + return true; + } + } + } +#endif /* CONFIG_BT_CAP_INITIATOR_UNICAST */ + + return false; +} + +void bt_cap_common_disconnected(struct bt_conn *conn, uint8_t reason) +{ + struct bt_cap_common_client *client = bt_cap_common_get_client_by_acl(conn); + + if (client->conn != NULL) { + bt_conn_unref(client->conn); + } + (void)memset(client, 0, sizeof(*client)); + + if (bt_cap_common_conn_in_active_proc(conn)) { + bt_cap_common_abort_proc(conn, -ENOTCONN); + } +} + +BT_CONN_CB_DEFINE(conn_callbacks) = { + .disconnected = bt_cap_common_disconnected, +}; + +struct bt_cap_common_client *bt_cap_common_get_client_by_acl(const struct bt_conn *acl) +{ + if (acl == NULL) { + return NULL; + } + + return &bt_cap_common_clients[bt_conn_index(acl)]; +} + +struct bt_cap_common_client * +bt_cap_common_get_client_by_csis(const struct bt_csip_set_coordinator_csis_inst *csis_inst) +{ + if (csis_inst == NULL) { + return NULL; + } + + for (size_t i = 0U; i < ARRAY_SIZE(bt_cap_common_clients); i++) { + struct bt_cap_common_client *client = &bt_cap_common_clients[i]; + + if (client->csis_inst == csis_inst) { + return client; + } + } + + return NULL; +} + +static void cap_common_discover_complete(struct bt_conn *conn, int err, + const struct bt_csip_set_coordinator_csis_inst *csis_inst) +{ + if (discover_cb_func != NULL) { + const bt_cap_common_discover_func_t cb_func = discover_cb_func; + + discover_cb_func = NULL; + cb_func(conn, err, csis_inst); + } +} + +static void csis_client_discover_cb(struct bt_conn *conn, + const struct bt_csip_set_coordinator_set_member *member, + int err, size_t set_count) +{ + struct bt_cap_common_client *client; + + if (err != 0) { + LOG_DBG("CSIS client discover failed: %d", err); + + cap_common_discover_complete(conn, err, NULL); + + return; + } + + client = bt_cap_common_get_client_by_acl(conn); + client->csis_inst = + bt_csip_set_coordinator_csis_inst_by_handle(conn, client->csis_start_handle); + + if (member == NULL || set_count == 0 || client->csis_inst == NULL) { + LOG_ERR("Unable to find CSIS for CAS"); + + cap_common_discover_complete(conn, -ENODATA, NULL); + } else { + LOG_DBG("Found CAS with CSIS"); + cap_common_discover_complete(conn, 0, client->csis_inst); + } +} + +static uint8_t bt_cap_common_discover_included_cb(struct bt_conn *conn, + const struct bt_gatt_attr *attr, + struct bt_gatt_discover_params *params) +{ + if (attr == NULL) { + LOG_DBG("CAS CSIS include not found"); + + cap_common_discover_complete(conn, 0, NULL); + } else { + const struct bt_gatt_include *included_service = attr->user_data; + struct bt_cap_common_client *client = + CONTAINER_OF(params, struct bt_cap_common_client, param); + + /* If the remote CAS includes CSIS, we first check if we + * have already discovered it, and if so we can just retrieve it + * and forward it to the application. If not, then we start + * CSIS discovery + */ + client->csis_start_handle = included_service->start_handle; + client->csis_inst = bt_csip_set_coordinator_csis_inst_by_handle( + conn, client->csis_start_handle); + + if (client->csis_inst == NULL) { + static struct bt_csip_set_coordinator_cb csis_client_cb = { + .discover = csis_client_discover_cb, + }; + static bool csis_cbs_registered; + int err; + + LOG_DBG("CAS CSIS not known, discovering"); + + if (!csis_cbs_registered) { + bt_csip_set_coordinator_register_cb(&csis_client_cb); + csis_cbs_registered = true; + } + + err = bt_csip_set_coordinator_discover(conn); + if (err != 0) { + LOG_DBG("Discover failed (err %d)", err); + cap_common_discover_complete(conn, err, NULL); + } + } else { + LOG_DBG("Found CAS with CSIS"); + cap_common_discover_complete(conn, 0, client->csis_inst); + } + } + + return BT_GATT_ITER_STOP; +} + +static uint8_t bt_cap_common_discover_cas_cb(struct bt_conn *conn, const struct bt_gatt_attr *attr, + struct bt_gatt_discover_params *params) +{ + if (attr == NULL) { + cap_common_discover_complete(conn, -ENODATA, NULL); + } else { + const struct bt_gatt_service_val *prim_service = attr->user_data; + struct bt_cap_common_client *client = + CONTAINER_OF(params, struct bt_cap_common_client, param); + int err; + + client->cas_found = true; + client->conn = bt_conn_ref(conn); + + if (attr->handle == prim_service->end_handle) { + LOG_DBG("Found CAS without CSIS"); + cap_common_discover_complete(conn, 0, NULL); + + return BT_GATT_ITER_STOP; + } + + LOG_DBG("Found CAS, discovering included CSIS"); + + params->uuid = NULL; + params->start_handle = attr->handle + 1; + params->end_handle = prim_service->end_handle; + params->type = BT_GATT_DISCOVER_INCLUDE; + params->func = bt_cap_common_discover_included_cb; + + err = bt_gatt_discover(conn, params); + if (err != 0) { + LOG_DBG("Discover failed (err %d)", err); + + cap_common_discover_complete(conn, err, NULL); + } + } + + return BT_GATT_ITER_STOP; +} + +int bt_cap_common_discover(struct bt_conn *conn, bt_cap_common_discover_func_t func) +{ + struct bt_gatt_discover_params *param; + int err; + + if (discover_cb_func != NULL) { + return -EBUSY; + } + + param = &bt_cap_common_clients[bt_conn_index(conn)].param; + param->func = bt_cap_common_discover_cas_cb; + param->uuid = cas_uuid; + param->type = BT_GATT_DISCOVER_PRIMARY; + param->start_handle = BT_ATT_FIRST_ATTRIBUTE_HANDLE; + param->end_handle = BT_ATT_LAST_ATTRIBUTE_HANDLE; + + err = bt_gatt_discover(conn, param); + if (err == 0) { + discover_cb_func = func; + } + + return err; +} diff --git a/subsys/bluetooth/audio/cap_initiator.c b/subsys/bluetooth/audio/cap_initiator.c index 46b39afcb41..2b171548af2 100644 --- a/subsys/bluetooth/audio/cap_initiator.c +++ b/subsys/bluetooth/audio/cap_initiator.c @@ -312,358 +312,24 @@ int bt_cap_initiator_broadcast_get_base(struct bt_cap_broadcast_source *broadcas #endif /* CONFIG_BT_BAP_BROADCAST_SOURCE */ #if defined(CONFIG_BT_BAP_UNICAST_CLIENT) -enum { - CAP_UNICAST_PROC_STATE_ACTIVE, - CAP_UNICAST_PROC_STATE_ABORTED, - - CAP_UNICAST_PROC_STATE_FLAG_NUM, -} cap_unicast_proc_state; - -enum cap_unicast_proc_type { - CAP_UNICAST_PROC_TYPE_NONE, - CAP_UNICAST_PROC_TYPE_START, - CAP_UNICAST_PROC_TYPE_UPDATE, - CAP_UNICAST_PROC_TYPE_STOP, -}; - -enum cap_unicast_subproc_type { - CAP_UNICAST_SUBPROC_TYPE_NONE, - CAP_UNICAST_SUBPROC_TYPE_CODEC_CONFIG, - CAP_UNICAST_SUBPROC_TYPE_QOS_CONFIG, - CAP_UNICAST_SUBPROC_TYPE_ENABLE, - CAP_UNICAST_SUBPROC_TYPE_START, - CAP_UNICAST_SUBPROC_TYPE_META_UPDATE, - CAP_UNICAST_SUBPROC_TYPE_RELEASE, -}; - -struct cap_unicast_proc_param { - struct bt_cap_stream *stream; - union { - struct { - struct bt_conn *conn; - struct bt_bap_ep *ep; - struct bt_audio_codec_cfg codec_cfg; - } start; - struct { - /** Codec Specific Capabilities Metadata count */ - size_t meta_len; - /** Codec Specific Capabilities Metadata */ - uint8_t meta[CONFIG_BT_AUDIO_CODEC_CFG_MAX_METADATA_SIZE]; - } meta_update; - }; -}; - -struct cap_unicast_proc { - ATOMIC_DEFINE(proc_state_flags, CAP_UNICAST_PROC_STATE_FLAG_NUM); - /* Total number of streams in the procedure*/ - size_t stream_cnt; - /* Number of streams where a subprocedure have been started */ - size_t stream_initiated_cnt; - /* Number of streams done with the procedure */ - size_t stream_done_cnt; - enum cap_unicast_proc_type proc_type; - enum cap_unicast_subproc_type subproc_type; - int err; - struct bt_conn *failed_conn; - struct cap_unicast_proc_param proc_param[CONFIG_BT_BAP_UNICAST_CLIENT_GROUP_STREAM_COUNT]; - struct bt_bap_unicast_group *unicast_group; -}; - -struct cap_unicast_client { - struct bt_conn *conn; - struct bt_gatt_discover_params param; - uint16_t csis_start_handle; - const struct bt_csip_set_coordinator_csis_inst *csis_inst; - bool cas_found; -}; - -static struct cap_unicast_client bt_cap_unicast_clients[CONFIG_BT_MAX_CONN]; -static const struct bt_uuid *cas_uuid = BT_UUID_CAS; -static struct cap_unicast_proc active_proc; - -static void cap_set_subproc(enum cap_unicast_subproc_type subproc_type) -{ - active_proc.stream_done_cnt = 0U; - active_proc.stream_initiated_cnt = 0U; - active_proc.subproc_type = subproc_type; -} - -static bool cap_proc_is_active(void) -{ - return atomic_test_bit(active_proc.proc_state_flags, CAP_UNICAST_PROC_STATE_ACTIVE); -} - -static bool cap_proc_is_aborted(void) -{ - return atomic_test_bit(active_proc.proc_state_flags, CAP_UNICAST_PROC_STATE_ABORTED); -} - -static bool cap_proc_all_streams_handled(void) -{ - return active_proc.stream_done_cnt == active_proc.stream_initiated_cnt; -} - -static bool cap_proc_is_done(void) -{ - return active_proc.stream_done_cnt == active_proc.stream_cnt; -} - -static void cap_abort_proc(struct bt_conn *conn, int err) -{ - if (cap_proc_is_aborted()) { - /* no-op */ - return; - } - - active_proc.err = err; - active_proc.failed_conn = conn; - atomic_set_bit(active_proc.proc_state_flags, CAP_UNICAST_PROC_STATE_ABORTED); -} - -static bool cap_conn_in_active_proc(const struct bt_conn *conn) -{ - if (!cap_proc_is_active()) { - return false; - } - - for (size_t i = 0U; i < active_proc.stream_initiated_cnt; i++) { - if (active_proc.proc_param[i].stream->bap_stream.conn == conn) { - return true; - } - } - - return false; -} - -static void cap_initiator_disconnected(struct bt_conn *conn, uint8_t reason) -{ - struct cap_unicast_client *client; - - client = &bt_cap_unicast_clients[bt_conn_index(conn)]; - - if (client->conn != NULL) { - bt_conn_unref(client->conn); - } - (void)memset(client, 0, sizeof(*client)); - - if (cap_conn_in_active_proc(conn)) { - cap_abort_proc(conn, -ENOTCONN); - } -} - -BT_CONN_CB_DEFINE(conn_callbacks) = { - .disconnected = cap_initiator_disconnected, -}; - -static struct cap_unicast_client *lookup_unicast_client_by_csis( - const struct bt_csip_set_coordinator_csis_inst *csis_inst) -{ - if (csis_inst == NULL) { - return NULL; - } - - for (size_t i = 0U; i < ARRAY_SIZE(bt_cap_unicast_clients); i++) { - struct cap_unicast_client *client = &bt_cap_unicast_clients[i]; - - if (client->csis_inst == csis_inst) { - return client; - } - } - - return NULL; -} - -static void csis_client_discover_cb(struct bt_conn *conn, - const struct bt_csip_set_coordinator_set_member *member, - int err, size_t set_count) -{ - struct cap_unicast_client *client; - - if (err != 0) { - LOG_DBG("CSIS client discover failed: %d", err); - - if (cap_cb && cap_cb->unicast_discovery_complete) { - cap_cb->unicast_discovery_complete(conn, err, NULL); - } - - return; - } - - client = &bt_cap_unicast_clients[bt_conn_index(conn)]; - client->csis_inst = bt_csip_set_coordinator_csis_inst_by_handle( - conn, client->csis_start_handle); - - if (member == NULL || set_count == 0 || client->csis_inst == NULL) { - LOG_ERR("Unable to find CSIS for CAS"); - - if (cap_cb && cap_cb->unicast_discovery_complete) { - cap_cb->unicast_discovery_complete(conn, -ENODATA, - NULL); - } - } else { - LOG_DBG("Found CAS with CSIS"); - if (cap_cb && cap_cb->unicast_discovery_complete) { - cap_cb->unicast_discovery_complete(conn, 0, - client->csis_inst); - } - } -} - -static uint8_t cap_unicast_discover_included_cb(struct bt_conn *conn, - const struct bt_gatt_attr *attr, - struct bt_gatt_discover_params *params) -{ - params->func = NULL; - - if (attr == NULL) { - LOG_DBG("CAS CSIS include not found"); - - if (cap_cb && cap_cb->unicast_discovery_complete) { - cap_cb->unicast_discovery_complete(conn, 0, NULL); - } - } else { - const struct bt_gatt_include *included_service = attr->user_data; - struct cap_unicast_client *client = CONTAINER_OF(params, - struct cap_unicast_client, - param); - - /* If the remote CAS includes CSIS, we first check if we - * have already discovered it, and if so we can just retrieve it - * and forward it to the application. If not, then we start - * CSIS discovery - */ - client->csis_start_handle = included_service->start_handle; - client->csis_inst = bt_csip_set_coordinator_csis_inst_by_handle( - conn, client->csis_start_handle); - - if (client->csis_inst == NULL) { - static struct bt_csip_set_coordinator_cb csis_client_cb = { - .discover = csis_client_discover_cb - }; - static bool csis_cbs_registered; - int err; - - LOG_DBG("CAS CSIS not known, discovering"); - - if (!csis_cbs_registered) { - bt_csip_set_coordinator_register_cb(&csis_client_cb); - csis_cbs_registered = true; - } - err = bt_csip_set_coordinator_discover(conn); - if (err != 0) { - LOG_DBG("Discover failed (err %d)", err); - if (cap_cb && cap_cb->unicast_discovery_complete) { - cap_cb->unicast_discovery_complete(conn, - err, - NULL); - } - } - } else if (cap_cb && cap_cb->unicast_discovery_complete) { - LOG_DBG("Found CAS with CSIS"); - cap_cb->unicast_discovery_complete(conn, 0, - client->csis_inst); - } - } - - return BT_GATT_ITER_STOP; -} - -static uint8_t cap_unicast_discover_cas_cb(struct bt_conn *conn, - const struct bt_gatt_attr *attr, - struct bt_gatt_discover_params *params) +static void +bt_cap_initiator_discover_complete(struct bt_conn *conn, int err, + const struct bt_csip_set_coordinator_csis_inst *csis_inst) { - params->func = NULL; - - if (attr == NULL) { - if (cap_cb && cap_cb->unicast_discovery_complete) { - cap_cb->unicast_discovery_complete(conn, -ENODATA, - NULL); - } - } else { - const struct bt_gatt_service_val *prim_service = attr->user_data; - struct cap_unicast_client *client = CONTAINER_OF(params, - struct cap_unicast_client, - param); - int err; - - client->cas_found = true; - client->conn = bt_conn_ref(conn); - - if (attr->handle == prim_service->end_handle) { - LOG_DBG("Found CAS without CSIS"); - cap_cb->unicast_discovery_complete(conn, 0, NULL); - - return BT_GATT_ITER_STOP; - } - - LOG_DBG("Found CAS, discovering included CSIS"); - - params->uuid = NULL; - params->start_handle = attr->handle + 1; - params->end_handle = prim_service->end_handle; - params->type = BT_GATT_DISCOVER_INCLUDE; - params->func = cap_unicast_discover_included_cb; - - err = bt_gatt_discover(conn, params); - if (err != 0) { - LOG_DBG("Discover failed (err %d)", err); - - params->func = NULL; - if (cap_cb && cap_cb->unicast_discovery_complete) { - cap_cb->unicast_discovery_complete(conn, err, - NULL); - } - } + if (cap_cb && cap_cb->unicast_discovery_complete) { + cap_cb->unicast_discovery_complete(conn, err, csis_inst); } - - return BT_GATT_ITER_STOP; } int bt_cap_initiator_unicast_discover(struct bt_conn *conn) { - struct bt_gatt_discover_params *param; - int err; - CHECKIF(conn == NULL) { LOG_DBG("NULL conn"); return -EINVAL; } - param = &bt_cap_unicast_clients[bt_conn_index(conn)].param; - - /* use param->func to tell if a client is "busy" */ - if (param->func != NULL) { - return -EBUSY; - } - - param->func = cap_unicast_discover_cas_cb; - param->uuid = cas_uuid; - param->type = BT_GATT_DISCOVER_PRIMARY; - param->start_handle = BT_ATT_FIRST_ATTRIBUTE_HANDLE; - param->end_handle = BT_ATT_LAST_ATTRIBUTE_HANDLE; - - err = bt_gatt_discover(conn, param); - if (err != 0) { - param->func = NULL; - } - - return err; -} - -static bool cap_stream_in_active_proc(const struct bt_cap_stream *cap_stream) -{ - if (!cap_proc_is_active()) { - return false; - } - - for (size_t i = 0U; i < active_proc.stream_cnt; i++) { - if (active_proc.proc_param[i].stream == cap_stream) { - return true; - } - } - - return false; + return bt_cap_common_discover(conn, bt_cap_initiator_discover_complete); } static bool valid_unicast_audio_start_param(const struct bt_cap_unicast_audio_start_param *param, @@ -721,14 +387,14 @@ static bool valid_unicast_audio_start_param(const struct bt_cap_unicast_audio_st } if (param->type == BT_CAP_SET_TYPE_AD_HOC) { - struct cap_unicast_client *client; + struct bt_cap_common_client *client; CHECKIF(member->member == NULL) { LOG_DBG("param->members[%zu] is NULL", i); return false; } - client = &bt_cap_unicast_clients[bt_conn_index(member->member)]; + client = bt_cap_common_get_client_by_acl(member->member); if (!client->cas_found) { LOG_DBG("CAS was not found for param->members[%zu]", i); @@ -737,14 +403,14 @@ static bool valid_unicast_audio_start_param(const struct bt_cap_unicast_audio_st } if (param->type == BT_CAP_SET_TYPE_CSIP) { - struct cap_unicast_client *client; + struct bt_cap_common_client *client; CHECKIF(member->csip == NULL) { LOG_DBG("param->csip.set[%zu] is NULL", i); return false; } - client = lookup_unicast_client_by_csis(member->csip); + client = bt_cap_common_get_client_by_csis(member->csip); if (client == NULL) { LOG_DBG("CSIS was not found for param->members[%zu]", i); return false; @@ -790,38 +456,39 @@ static bool valid_unicast_audio_start_param(const struct bt_cap_unicast_audio_st static void cap_initiator_unicast_audio_proc_complete(void) { + struct bt_cap_common_proc *active_proc = bt_cap_common_get_active_proc(); struct bt_bap_unicast_group *unicast_group; - enum cap_unicast_proc_type proc_type; + enum bt_cap_common_proc_type proc_type; struct bt_conn *failed_conn; int err; - unicast_group = active_proc.unicast_group; - failed_conn = active_proc.failed_conn; - err = active_proc.err; - proc_type = active_proc.proc_type; - (void)memset(&active_proc, 0, sizeof(active_proc)); + unicast_group = active_proc->unicast_group; + failed_conn = active_proc->failed_conn; + err = active_proc->err; + proc_type = active_proc->proc_type; + bt_cap_common_clear_active_proc(); if (cap_cb == NULL) { return; } switch (proc_type) { - case CAP_UNICAST_PROC_TYPE_START: + case BT_CAP_COMMON_PROC_TYPE_START: if (cap_cb->unicast_start_complete != NULL) { cap_cb->unicast_start_complete(unicast_group, err, failed_conn); } break; - case CAP_UNICAST_PROC_TYPE_UPDATE: + case BT_CAP_COMMON_PROC_TYPE_UPDATE: if (cap_cb->unicast_update_complete != NULL) { cap_cb->unicast_update_complete(err, failed_conn); } break; - case CAP_UNICAST_PROC_TYPE_STOP: + case BT_CAP_COMMON_PROC_TYPE_STOP: if (cap_cb->unicast_stop_complete != NULL) { cap_cb->unicast_stop_complete(unicast_group, err, failed_conn); } break; - case CAP_UNICAST_PROC_TYPE_NONE: + case BT_CAP_COMMON_PROC_TYPE_NONE: default: __ASSERT(false, "Invalid proc_type: %u", proc_type); } @@ -830,7 +497,8 @@ static void cap_initiator_unicast_audio_proc_complete(void) static int cap_initiator_unicast_audio_configure( const struct bt_cap_unicast_audio_start_param *param) { - struct cap_unicast_proc_param *proc_param; + struct bt_cap_common_proc *active_proc = bt_cap_common_get_active_proc(); + struct bt_cap_initiator_proc_param *proc_param; struct bt_audio_codec_cfg *codec_cfg; struct bt_bap_stream *bap_stream; struct bt_bap_ep *ep; @@ -850,12 +518,12 @@ static int cap_initiator_unicast_audio_configure( if (param->type == BT_CAP_SET_TYPE_AD_HOC) { conn = member->member; } else { - struct cap_unicast_client *client; + struct bt_cap_common_client *client; /* We have verified that `client` wont be NULL in * `valid_unicast_audio_start_param`. */ - client = lookup_unicast_client_by_csis(member->csip); + client = bt_cap_common_get_client_by_csis(member->csip); __ASSERT(client != NULL, "client is NULL"); conn = client->conn; } @@ -866,22 +534,20 @@ static int cap_initiator_unicast_audio_configure( /* Store the necessary parameters as we cannot assume that the supplied parameters * are kept valid */ - active_proc.proc_param[i].stream = cap_stream; - active_proc.proc_param[i].start.ep = stream_param->ep; - active_proc.proc_param[i].start.conn = conn; - memcpy(&active_proc.proc_param[i].start.codec_cfg, stream_param->codec_cfg, - sizeof(*stream_param->codec_cfg)); + active_proc->proc_param.initiator[i].stream = cap_stream; + active_proc->proc_param.initiator[i].start.ep = stream_param->ep; + active_proc->proc_param.initiator[i].start.conn = conn; + memcpy(&active_proc->proc_param.initiator[i].start.codec_cfg, + stream_param->codec_cfg, sizeof(*stream_param->codec_cfg)); } /* Store the information about the active procedure so that we can * continue the procedure after each step */ - atomic_set_bit(active_proc.proc_state_flags, CAP_UNICAST_PROC_STATE_ACTIVE); - active_proc.stream_cnt = param->count; - - cap_set_subproc(CAP_UNICAST_SUBPROC_TYPE_CODEC_CONFIG); + bt_cap_common_start_proc(BT_CAP_COMMON_PROC_TYPE_START, param->count); + bt_cap_common_set_subproc(BT_CAP_COMMON_SUBPROC_TYPE_CODEC_CONFIG); - proc_param = &active_proc.proc_param[0]; + proc_param = &active_proc->proc_param.initiator[0]; bap_stream = &proc_param->stream->bap_stream; codec_cfg = &proc_param->start.codec_cfg; conn = proc_param->start.conn; @@ -895,9 +561,9 @@ static int cap_initiator_unicast_audio_configure( if (err != 0) { LOG_DBG("Failed to config stream %p: %d", proc_param->stream, err); - (void)memset(&active_proc, 0, sizeof(active_proc)); + bt_cap_common_clear_active_proc(); } else { - active_proc.stream_initiated_cnt++; + active_proc->proc_initiated_cnt++; } return err; @@ -906,7 +572,9 @@ static int cap_initiator_unicast_audio_configure( int bt_cap_initiator_unicast_audio_start(const struct bt_cap_unicast_audio_start_param *param, struct bt_bap_unicast_group *unicast_group) { - if (cap_proc_is_active()) { + struct bt_cap_common_proc *active_proc = bt_cap_common_get_active_proc(); + + if (bt_cap_common_proc_is_active()) { LOG_DBG("A CAP procedure is already in progress"); return -EBUSY; @@ -921,8 +589,7 @@ int bt_cap_initiator_unicast_audio_start(const struct bt_cap_unicast_audio_start return -EINVAL; } - active_proc.unicast_group = unicast_group; - active_proc.proc_type = CAP_UNICAST_PROC_TYPE_START; + active_proc->unicast_group = unicast_group; return cap_initiator_unicast_audio_configure(param); } @@ -931,49 +598,55 @@ void bt_cap_initiator_codec_configured(struct bt_cap_stream *cap_stream) { struct bt_conn *conns[MIN(CONFIG_BT_MAX_CONN, CONFIG_BT_BAP_UNICAST_CLIENT_GROUP_STREAM_COUNT)]; - struct cap_unicast_proc_param *proc_param; + struct bt_cap_common_proc *active_proc = bt_cap_common_get_active_proc(); + struct bt_cap_initiator_proc_param *proc_param; struct bt_bap_unicast_group *unicast_group; - if (!cap_stream_in_active_proc(cap_stream)) { + if (!bt_cap_common_stream_in_active_proc(cap_stream)) { /* State change happened outside of a procedure; ignore */ return; } - if (active_proc.subproc_type == CAP_UNICAST_SUBPROC_TYPE_RELEASE) { + if (bt_cap_common_subproc_is_type(BT_CAP_COMMON_SUBPROC_TYPE_RELEASE)) { /* When releasing a stream, it may go into the codec configured state if * the unicast server caches the configuration - We treat it as a release */ bt_cap_initiator_released(cap_stream); return; - } else if (active_proc.subproc_type != CAP_UNICAST_SUBPROC_TYPE_CODEC_CONFIG) { + } else if (!bt_cap_common_subproc_is_type(BT_CAP_COMMON_SUBPROC_TYPE_CODEC_CONFIG)) { /* Unexpected callback - Abort */ - cap_abort_proc(cap_stream->bap_stream.conn, -EBADMSG); + bt_cap_common_abort_proc(cap_stream->bap_stream.conn, -EBADMSG); } else { - active_proc.stream_done_cnt++; + active_proc->proc_done_cnt++; LOG_DBG("Stream %p configured (%zu/%zu streams done)", cap_stream, - active_proc.stream_done_cnt, active_proc.stream_cnt); + active_proc->proc_done_cnt, active_proc->proc_cnt); } - if (cap_proc_is_aborted()) { - if (cap_proc_all_streams_handled()) { + if (bt_cap_common_proc_is_aborted()) { + if (bt_cap_common_proc_all_streams_handled()) { cap_initiator_unicast_audio_proc_complete(); } return; } - if (!cap_proc_is_done()) { - struct bt_cap_stream *next_cap_stream = - active_proc.proc_param[active_proc.stream_done_cnt].stream; - struct bt_conn *conn = - active_proc.proc_param[active_proc.stream_done_cnt].start.conn; - struct bt_bap_ep *ep = active_proc.proc_param[active_proc.stream_done_cnt].start.ep; - struct bt_audio_codec_cfg *codec_cfg = - &active_proc.proc_param[active_proc.stream_done_cnt].start.codec_cfg; - struct bt_bap_stream *bap_stream = &next_cap_stream->bap_stream; + if (!bt_cap_common_proc_is_done()) { + const size_t proc_done_cnt = active_proc->proc_done_cnt; + struct bt_cap_stream *next_cap_stream; + struct bt_audio_codec_cfg *codec_cfg; + struct bt_bap_stream *bap_stream; + struct bt_conn *conn; + struct bt_bap_ep *ep; int err; + proc_param = &active_proc->proc_param.initiator[proc_done_cnt]; + next_cap_stream = proc_param->stream; + conn = proc_param->start.conn; + ep = proc_param->start.ep; + codec_cfg = &proc_param->start.codec_cfg; + bap_stream = &next_cap_stream->bap_stream; + /* Since BAP operations may require a write long or a read long on the notification, * we cannot assume that we can do multiple streams at once, thus do it one at a * time. @@ -984,10 +657,10 @@ void bt_cap_initiator_codec_configured(struct bt_cap_stream *cap_stream) if (err != 0) { LOG_DBG("Failed to config stream %p: %d", next_cap_stream, err); - cap_abort_proc(conn, err); + bt_cap_common_abort_proc(conn, err); cap_initiator_unicast_audio_proc_complete(); } else { - active_proc.stream_initiated_cnt++; + active_proc->proc_initiated_cnt++; } return; @@ -998,8 +671,9 @@ void bt_cap_initiator_codec_configured(struct bt_cap_stream *cap_stream) * for the procedure */ (void)memset(conns, 0, sizeof(conns)); - for (size_t i = 0U; i < active_proc.stream_cnt; i++) { - struct bt_conn *stream_conn = active_proc.proc_param[i].stream->bap_stream.conn; + for (size_t i = 0U; i < active_proc->proc_cnt; i++) { + struct bt_conn *stream_conn = + active_proc->proc_param.initiator[i].stream->bap_stream.conn; struct bt_conn **free_conn = NULL; bool already_added = false; @@ -1026,9 +700,9 @@ void bt_cap_initiator_codec_configured(struct bt_cap_stream *cap_stream) /* All streams in the procedure share the same unicast group, so we just * use the reference from the first stream */ - proc_param = &active_proc.proc_param[0]; + proc_param = &active_proc->proc_param.initiator[0]; unicast_group = (struct bt_bap_unicast_group *)proc_param->stream->bap_stream.group; - cap_set_subproc(CAP_UNICAST_SUBPROC_TYPE_QOS_CONFIG); + bt_cap_common_set_subproc(BT_CAP_COMMON_SUBPROC_TYPE_QOS_CONFIG); for (size_t i = 0U; i < ARRAY_SIZE(conns); i++) { int err; @@ -1047,7 +721,7 @@ void bt_cap_initiator_codec_configured(struct bt_cap_stream *cap_stream) * If we have sent any requests over air, we will abort * once all sent requests has completed */ - cap_abort_proc(conns[i], err); + bt_cap_common_abort_proc(conns[i], err); if (i == 0U) { cap_initiator_unicast_audio_proc_complete(); } @@ -1055,47 +729,48 @@ void bt_cap_initiator_codec_configured(struct bt_cap_stream *cap_stream) return; } - active_proc.stream_initiated_cnt++; + active_proc->proc_initiated_cnt++; } } void bt_cap_initiator_qos_configured(struct bt_cap_stream *cap_stream) { - struct cap_unicast_proc_param *proc_param; + struct bt_cap_common_proc *active_proc = bt_cap_common_get_active_proc(); + struct bt_cap_initiator_proc_param *proc_param; struct bt_cap_stream *next_cap_stream; struct bt_bap_stream *bap_stream; int err; - if (!cap_stream_in_active_proc(cap_stream)) { + if (!bt_cap_common_stream_in_active_proc(cap_stream)) { /* State change happened outside of a procedure; ignore */ return; } - if (active_proc.subproc_type != CAP_UNICAST_SUBPROC_TYPE_QOS_CONFIG) { + if (!bt_cap_common_subproc_is_type(BT_CAP_COMMON_SUBPROC_TYPE_QOS_CONFIG)) { /* Unexpected callback - Abort */ - cap_abort_proc(cap_stream->bap_stream.conn, -EBADMSG); + bt_cap_common_abort_proc(cap_stream->bap_stream.conn, -EBADMSG); } else { - active_proc.stream_done_cnt++; + active_proc->proc_done_cnt++; LOG_DBG("Stream %p QoS configured (%zu/%zu streams done)", cap_stream, - active_proc.stream_done_cnt, active_proc.stream_cnt); + active_proc->proc_done_cnt, active_proc->proc_cnt); } - if (cap_proc_is_aborted()) { - if (cap_proc_all_streams_handled()) { + if (bt_cap_common_proc_is_aborted()) { + if (bt_cap_common_proc_all_streams_handled()) { cap_initiator_unicast_audio_proc_complete(); } return; } - if (!cap_proc_is_done()) { + if (!bt_cap_common_proc_is_done()) { /* Not yet finished, wait for all */ return; } - cap_set_subproc(CAP_UNICAST_SUBPROC_TYPE_ENABLE); - proc_param = &active_proc.proc_param[0]; + bt_cap_common_set_subproc(BT_CAP_COMMON_SUBPROC_TYPE_ENABLE); + proc_param = &active_proc->proc_param.initiator[0]; next_cap_stream = proc_param->stream; bap_stream = &next_cap_stream->bap_stream; @@ -1108,45 +783,46 @@ void bt_cap_initiator_qos_configured(struct bt_cap_stream *cap_stream) if (err != 0) { LOG_DBG("Failed to enable stream %p: %d", next_cap_stream, err); - cap_abort_proc(bap_stream->conn, err); + bt_cap_common_abort_proc(bap_stream->conn, err); cap_initiator_unicast_audio_proc_complete(); } else { - active_proc.stream_initiated_cnt++; + active_proc->proc_initiated_cnt++; } } void bt_cap_initiator_enabled(struct bt_cap_stream *cap_stream) { - struct cap_unicast_proc_param *proc_param; + struct bt_cap_common_proc *active_proc = bt_cap_common_get_active_proc(); + struct bt_cap_initiator_proc_param *proc_param; struct bt_bap_stream *bap_stream; int err; - if (!cap_stream_in_active_proc(cap_stream)) { + if (!bt_cap_common_stream_in_active_proc(cap_stream)) { /* State change happened outside of a procedure; ignore */ return; } - if (active_proc.subproc_type != CAP_UNICAST_SUBPROC_TYPE_ENABLE) { + if (!bt_cap_common_subproc_is_type(BT_CAP_COMMON_SUBPROC_TYPE_ENABLE)) { /* Unexpected callback - Abort */ - cap_abort_proc(cap_stream->bap_stream.conn, -EBADMSG); + bt_cap_common_abort_proc(cap_stream->bap_stream.conn, -EBADMSG); } else { - active_proc.stream_done_cnt++; + active_proc->proc_done_cnt++; LOG_DBG("Stream %p enabled (%zu/%zu streams done)", cap_stream, - active_proc.stream_done_cnt, active_proc.stream_cnt); + active_proc->proc_done_cnt, active_proc->proc_cnt); } - if (cap_proc_is_aborted()) { - if (cap_proc_all_streams_handled()) { + if (bt_cap_common_proc_is_aborted()) { + if (bt_cap_common_proc_all_streams_handled()) { cap_initiator_unicast_audio_proc_complete(); } return; } - if (!cap_proc_is_done()) { + if (!bt_cap_common_proc_is_done()) { struct bt_cap_stream *next_cap_stream = - active_proc.proc_param[active_proc.stream_done_cnt].stream; + active_proc->proc_param.initiator[active_proc->proc_done_cnt].stream; struct bt_bap_stream *next_bap_stream = &next_cap_stream->bap_stream; /* Since BAP operations may require a write long or a read long on the notification, @@ -1160,17 +836,17 @@ void bt_cap_initiator_enabled(struct bt_cap_stream *cap_stream) if (err != 0) { LOG_DBG("Failed to enable stream %p: %d", next_cap_stream, err); - cap_abort_proc(next_bap_stream->conn, err); + bt_cap_common_abort_proc(next_bap_stream->conn, err); cap_initiator_unicast_audio_proc_complete(); } else { - active_proc.stream_initiated_cnt++; + active_proc->proc_initiated_cnt++; } return; } - cap_set_subproc(CAP_UNICAST_SUBPROC_TYPE_START); - proc_param = &active_proc.proc_param[0]; + bt_cap_common_set_subproc(BT_CAP_COMMON_SUBPROC_TYPE_START); + proc_param = &active_proc->proc_param.initiator[0]; bap_stream = &proc_param->stream->bap_stream; /* Since BAP operations may require a write long or a read long on the notification, we @@ -1185,7 +861,7 @@ void bt_cap_initiator_enabled(struct bt_cap_stream *cap_stream) * If we have sent any requests over air, we will abort * once all sent requests has completed */ - cap_abort_proc(bap_stream->conn, err); + bt_cap_common_abort_proc(bap_stream->conn, err); cap_initiator_unicast_audio_proc_complete(); return; @@ -1194,29 +870,30 @@ void bt_cap_initiator_enabled(struct bt_cap_stream *cap_stream) void bt_cap_initiator_started(struct bt_cap_stream *cap_stream) { - if (!cap_stream_in_active_proc(cap_stream)) { + struct bt_cap_common_proc *active_proc = bt_cap_common_get_active_proc(); + + if (!bt_cap_common_stream_in_active_proc(cap_stream)) { /* State change happened outside of a procedure; ignore */ return; } - if (active_proc.subproc_type != CAP_UNICAST_SUBPROC_TYPE_START) { + if (!bt_cap_common_subproc_is_type(BT_CAP_COMMON_SUBPROC_TYPE_START)) { /* Unexpected callback - Abort */ - cap_abort_proc(cap_stream->bap_stream.conn, -EBADMSG); + bt_cap_common_abort_proc(cap_stream->bap_stream.conn, -EBADMSG); } else { - active_proc.stream_done_cnt++; + active_proc->proc_done_cnt++; - LOG_DBG("Stream %p started (%zu/%zu streams done)", - cap_stream, active_proc.stream_done_cnt, - active_proc.stream_cnt); + LOG_DBG("Stream %p started (%zu/%zu streams done)", cap_stream, + active_proc->proc_done_cnt, active_proc->proc_cnt); } /* Since bt_bap_stream_start connects the ISO, we can, at this point, * only do this one by one due to a restriction in the ISO layer * (maximum 1 outstanding ISO connection request at any one time). */ - if (!cap_proc_is_done()) { + if (!bt_cap_common_proc_is_done()) { struct bt_cap_stream *next_cap_stream = - active_proc.proc_param[active_proc.stream_done_cnt].stream; + active_proc->proc_param.initiator[active_proc->proc_done_cnt].stream; struct bt_bap_stream *bap_stream = &next_cap_stream->bap_stream; int err; @@ -1229,7 +906,7 @@ void bt_cap_initiator_started(struct bt_cap_stream *cap_stream) * If we have sent any requests over air, we will abort * once all sent requests has completed */ - cap_abort_proc(bap_stream->conn, err); + bt_cap_common_abort_proc(bap_stream->conn, err); cap_initiator_unicast_audio_proc_complete(); } } else { @@ -1260,7 +937,8 @@ static bool can_update_metadata(const struct bt_bap_stream *bap_stream) int bt_cap_initiator_unicast_audio_update(const struct bt_cap_unicast_audio_update_param params[], size_t count) { - struct cap_unicast_proc_param *proc_param; + struct bt_cap_common_proc *active_proc = bt_cap_common_get_active_proc(); + struct bt_cap_initiator_proc_param *proc_param; struct bt_bap_stream *bap_stream; const uint8_t *meta; size_t meta_len; @@ -1278,7 +956,7 @@ int bt_cap_initiator_unicast_audio_update(const struct bt_cap_unicast_audio_upda return -EINVAL; } - if (cap_proc_is_active()) { + if (bt_cap_common_proc_is_active()) { LOG_DBG("A CAP procedure is already in progress"); return -EBUSY; @@ -1320,19 +998,16 @@ int bt_cap_initiator_unicast_audio_update(const struct bt_cap_unicast_audio_upda return -EINVAL; } - active_proc.proc_param[i].stream = cap_stream; - active_proc.proc_param[i].meta_update.meta_len = params[i].meta_len; - memcpy(&active_proc.proc_param[i].meta_update.meta, params[i].meta, + active_proc->proc_param.initiator[i].stream = cap_stream; + active_proc->proc_param.initiator[i].meta_update.meta_len = params[i].meta_len; + memcpy(&active_proc->proc_param.initiator[i].meta_update.meta, params[i].meta, params[i].meta_len); } - atomic_set_bit(active_proc.proc_state_flags, CAP_UNICAST_PROC_STATE_ACTIVE); - active_proc.stream_cnt = count; + bt_cap_common_start_proc(BT_CAP_COMMON_PROC_TYPE_UPDATE, count); + bt_cap_common_set_subproc(BT_CAP_COMMON_SUBPROC_TYPE_META_UPDATE); - active_proc.proc_type = CAP_UNICAST_PROC_TYPE_UPDATE; - cap_set_subproc(CAP_UNICAST_SUBPROC_TYPE_META_UPDATE); - - proc_param = &active_proc.proc_param[0]; + proc_param = &active_proc->proc_param.initiator[0]; bap_stream = &proc_param->stream->bap_stream; meta_len = proc_param->meta_update.meta_len; meta = proc_param->meta_update.meta; @@ -1341,9 +1016,9 @@ int bt_cap_initiator_unicast_audio_update(const struct bt_cap_unicast_audio_upda if (err != 0) { LOG_DBG("Failed to update metadata for stream %p: %d", proc_param->stream, err); - (void)memset(&active_proc, 0, sizeof(active_proc)); + bt_cap_common_clear_active_proc(); } else { - active_proc.stream_initiated_cnt++; + active_proc->proc_initiated_cnt++; } return err; @@ -1351,13 +1026,13 @@ int bt_cap_initiator_unicast_audio_update(const struct bt_cap_unicast_audio_upda int bt_cap_initiator_unicast_audio_cancel(void) { - if (!cap_proc_is_active() && !cap_proc_is_aborted()) { + if (!bt_cap_common_proc_is_active() && !bt_cap_common_proc_is_aborted()) { LOG_DBG("No CAP procedure is in progress"); return -EALREADY; } - cap_abort_proc(NULL, -ECANCELED); + bt_cap_common_abort_proc(NULL, -ECANCELED); cap_initiator_unicast_audio_proc_complete(); return 0; @@ -1365,40 +1040,46 @@ int bt_cap_initiator_unicast_audio_cancel(void) void bt_cap_initiator_metadata_updated(struct bt_cap_stream *cap_stream) { - if (!cap_stream_in_active_proc(cap_stream)) { + struct bt_cap_common_proc *active_proc = bt_cap_common_get_active_proc(); + + if (!bt_cap_common_stream_in_active_proc(cap_stream)) { /* State change happened outside of a procedure; ignore */ return; } - if (active_proc.subproc_type != CAP_UNICAST_SUBPROC_TYPE_META_UPDATE) { + if (!bt_cap_common_subproc_is_type(BT_CAP_COMMON_SUBPROC_TYPE_META_UPDATE)) { /* Unexpected callback - Abort */ - cap_abort_proc(cap_stream->bap_stream.conn, -EBADMSG); + bt_cap_common_abort_proc(cap_stream->bap_stream.conn, -EBADMSG); } else { - active_proc.stream_done_cnt++; + active_proc->proc_done_cnt++; - LOG_DBG("Stream %p QoS metadata updated (%zu/%zu streams done)", - cap_stream, active_proc.stream_done_cnt, - active_proc.stream_cnt); + LOG_DBG("Stream %p QoS metadata updated (%zu/%zu streams done)", cap_stream, + active_proc->proc_done_cnt, active_proc->proc_cnt); } - if (cap_proc_is_aborted()) { - if (cap_proc_all_streams_handled()) { + if (bt_cap_common_proc_is_aborted()) { + if (bt_cap_common_proc_all_streams_handled()) { cap_initiator_unicast_audio_proc_complete(); } return; } - if (!cap_proc_is_done()) { - const size_t meta_len = - active_proc.proc_param[active_proc.stream_done_cnt].meta_update.meta_len; - const uint8_t *meta = - active_proc.proc_param[active_proc.stream_done_cnt].meta_update.meta; - struct bt_cap_stream *next_cap_stream = - active_proc.proc_param[active_proc.stream_done_cnt].stream; - struct bt_bap_stream *bap_stream = &next_cap_stream->bap_stream; + if (!bt_cap_common_proc_is_done()) { + const size_t proc_done_cnt = active_proc->proc_done_cnt; + struct bt_cap_initiator_proc_param *proc_param; + struct bt_cap_stream *next_cap_stream; + struct bt_bap_stream *bap_stream; + const uint8_t *meta; + size_t meta_len; int err; + proc_param = &active_proc->proc_param.initiator[proc_done_cnt]; + meta_len = proc_param->meta_update.meta_len; + meta = proc_param->meta_update.meta; + next_cap_stream = proc_param->stream; + bap_stream = &next_cap_stream->bap_stream; + /* Since BAP operations may require a write long or a read long on the notification, * we cannot assume that we can do multiple streams at once, thus do it one at a * time. @@ -1411,10 +1092,10 @@ void bt_cap_initiator_metadata_updated(struct bt_cap_stream *cap_stream) LOG_DBG("Failed to update metadata for stream %p: %d", next_cap_stream, err); - cap_abort_proc(bap_stream->conn, err); + bt_cap_common_abort_proc(bap_stream->conn, err); cap_initiator_unicast_audio_proc_complete(); } else { - active_proc.stream_initiated_cnt++; + active_proc->proc_initiated_cnt++; } return; @@ -1444,12 +1125,13 @@ static bool can_release(const struct bt_bap_stream *bap_stream) int bt_cap_initiator_unicast_audio_stop(struct bt_bap_unicast_group *unicast_group) { - struct cap_unicast_proc_param *proc_param; + struct bt_cap_common_proc *active_proc = bt_cap_common_get_active_proc(); + struct bt_cap_initiator_proc_param *proc_param; struct bt_bap_stream *bap_stream; size_t stream_cnt; int err; - if (cap_proc_is_active()) { + if (bt_cap_common_proc_is_active()) { LOG_DBG("A CAP procedure is already in progress"); return -EBUSY; @@ -1465,7 +1147,7 @@ int bt_cap_initiator_unicast_audio_stop(struct bt_bap_unicast_group *unicast_gro if (can_release(bap_stream)) { struct bt_cap_stream *cap_stream = CONTAINER_OF(bap_stream, struct bt_cap_stream, bap_stream); - active_proc.proc_param[stream_cnt].stream = cap_stream; + active_proc->proc_param.initiator[stream_cnt].stream = cap_stream; stream_cnt++; } } @@ -1476,28 +1158,25 @@ int bt_cap_initiator_unicast_audio_stop(struct bt_bap_unicast_group *unicast_gro return -EALREADY; } - atomic_set_bit(active_proc.proc_state_flags, - CAP_UNICAST_PROC_STATE_ACTIVE); - active_proc.stream_cnt = stream_cnt; - active_proc.unicast_group = unicast_group; - active_proc.proc_type = CAP_UNICAST_PROC_TYPE_STOP; + bt_cap_common_start_proc(BT_CAP_COMMON_PROC_TYPE_STOP, stream_cnt); + active_proc->unicast_group = unicast_group; - cap_set_subproc(CAP_UNICAST_SUBPROC_TYPE_RELEASE); + bt_cap_common_set_subproc(BT_CAP_COMMON_SUBPROC_TYPE_RELEASE); /** TODO: If this is a CSIP set, then the order of the procedures may * not match the order in the parameters, and the CSIP ordered access * procedure should be used. */ - proc_param = &active_proc.proc_param[0]; + proc_param = &active_proc->proc_param.initiator[0]; bap_stream = &proc_param->stream->bap_stream; err = bt_bap_stream_release(bap_stream); if (err != 0) { LOG_DBG("Failed to stop bap_stream %p: %d", proc_param->stream, err); - (void)memset(&active_proc, 0, sizeof(active_proc)); + bt_cap_common_clear_active_proc(); } else { - active_proc.stream_initiated_cnt++; + active_proc->proc_initiated_cnt++; } return err; @@ -1505,33 +1184,34 @@ int bt_cap_initiator_unicast_audio_stop(struct bt_bap_unicast_group *unicast_gro void bt_cap_initiator_released(struct bt_cap_stream *cap_stream) { - if (!cap_stream_in_active_proc(cap_stream)) { + struct bt_cap_common_proc *active_proc = bt_cap_common_get_active_proc(); + + if (!bt_cap_common_stream_in_active_proc(cap_stream)) { /* State change happened outside of a procedure; ignore */ return; } - if (active_proc.subproc_type != CAP_UNICAST_SUBPROC_TYPE_RELEASE) { + if (!bt_cap_common_subproc_is_type(BT_CAP_COMMON_SUBPROC_TYPE_RELEASE)) { /* Unexpected callback - Abort */ - cap_abort_proc(cap_stream->bap_stream.conn, -EBADMSG); + bt_cap_common_abort_proc(cap_stream->bap_stream.conn, -EBADMSG); } else { - active_proc.stream_done_cnt++; + active_proc->proc_done_cnt++; - LOG_DBG("Stream %p released (%zu/%zu streams done)", - cap_stream, active_proc.stream_done_cnt, - active_proc.stream_cnt); + LOG_DBG("Stream %p released (%zu/%zu streams done)", cap_stream, + active_proc->proc_done_cnt, active_proc->proc_cnt); } - if (cap_proc_is_aborted()) { - if (cap_proc_all_streams_handled()) { + if (bt_cap_common_proc_is_aborted()) { + if (bt_cap_common_proc_all_streams_handled()) { cap_initiator_unicast_audio_proc_complete(); } return; } - if (!cap_proc_is_done()) { + if (!bt_cap_common_proc_is_done()) { struct bt_cap_stream *next_cap_stream = - active_proc.proc_param[active_proc.stream_done_cnt].stream; + active_proc->proc_param.initiator[active_proc->proc_done_cnt].stream; struct bt_bap_stream *bap_stream = &next_cap_stream->bap_stream; int err; @@ -1545,10 +1225,10 @@ void bt_cap_initiator_released(struct bt_cap_stream *cap_stream) if (err != 0) { LOG_DBG("Failed to release stream %p: %d", next_cap_stream, err); - cap_abort_proc(bap_stream->conn, err); + bt_cap_common_abort_proc(bap_stream->conn, err); cap_initiator_unicast_audio_proc_complete(); } else { - active_proc.stream_initiated_cnt++; + active_proc->proc_initiated_cnt++; } } else { cap_initiator_unicast_audio_proc_complete(); diff --git a/subsys/bluetooth/audio/cap_internal.h b/subsys/bluetooth/audio/cap_internal.h index ac07f3f817c..8823b3da2bb 100644 --- a/subsys/bluetooth/audio/cap_internal.h +++ b/subsys/bluetooth/audio/cap_internal.h @@ -1,14 +1,18 @@ /* Bluetooth Audio Common Audio Profile internal header */ /* - * Copyright (c) 2022 Nordic Semiconductor ASA + * Copyright (c) 2022-2023 Nordic Semiconductor ASA * * SPDX-License-Identifier: Apache-2.0 */ #include #include +#include +#include +#include #include +#include bool bt_cap_acceptor_ccid_exist(const struct bt_conn *conn, uint8_t ccid); @@ -19,3 +23,101 @@ void bt_cap_initiator_started(struct bt_cap_stream *cap_stream); void bt_cap_initiator_metadata_updated(struct bt_cap_stream *cap_stream); void bt_cap_initiator_released(struct bt_cap_stream *cap_stream); void bt_cap_stream_ops_register_bap(struct bt_cap_stream *cap_stream); + +enum bt_cap_common_proc_state { + BT_CAP_COMMON_PROC_STATE_ACTIVE, + BT_CAP_COMMON_PROC_STATE_ABORTED, + + BT_CAP_COMMON_PROC_STATE_FLAG_NUM, +}; + +enum bt_cap_common_proc_type { + BT_CAP_COMMON_PROC_TYPE_NONE, + BT_CAP_COMMON_PROC_TYPE_START, + BT_CAP_COMMON_PROC_TYPE_UPDATE, + BT_CAP_COMMON_PROC_TYPE_STOP, +}; + +enum bt_cap_common_subproc_type { + BT_CAP_COMMON_SUBPROC_TYPE_NONE, + BT_CAP_COMMON_SUBPROC_TYPE_CODEC_CONFIG, + BT_CAP_COMMON_SUBPROC_TYPE_QOS_CONFIG, + BT_CAP_COMMON_SUBPROC_TYPE_ENABLE, + BT_CAP_COMMON_SUBPROC_TYPE_START, + BT_CAP_COMMON_SUBPROC_TYPE_META_UPDATE, + BT_CAP_COMMON_SUBPROC_TYPE_RELEASE, +}; + +struct bt_cap_initiator_proc_param { + struct bt_cap_stream *stream; + union { + struct { + struct bt_conn *conn; + struct bt_bap_ep *ep; + struct bt_audio_codec_cfg codec_cfg; + } start; + struct { + /** Codec Specific Capabilities Metadata count */ + size_t meta_len; + /** Codec Specific Capabilities Metadata */ + uint8_t meta[CONFIG_BT_AUDIO_CODEC_CFG_MAX_METADATA_SIZE]; + } meta_update; + }; +}; + +struct bt_cap_common_proc_param { + union { +#if defined(CONFIG_BT_CAP_INITIATOR_UNICAST) + struct bt_cap_initiator_proc_param + initiator[CONFIG_BT_BAP_UNICAST_CLIENT_GROUP_STREAM_COUNT]; +#endif /* CONFIG_BT_CAP_INITIATOR_UNICAST */ + /* TODO: Add commander_proc_param struct */ + }; +}; + +struct bt_cap_common_proc { + ATOMIC_DEFINE(proc_state_flags, BT_CAP_COMMON_PROC_STATE_FLAG_NUM); + /* Total number of items (streams or connections) in the procedure*/ + size_t proc_cnt; + /* Number of items where a subprocedure have been started */ + size_t proc_initiated_cnt; + /* Number of items done with the procedure */ + size_t proc_done_cnt; + enum bt_cap_common_proc_type proc_type; + int err; + struct bt_conn *failed_conn; + struct bt_cap_common_proc_param proc_param; +#if defined(CONFIG_BT_CAP_INITIATOR_UNICAST) + struct bt_bap_unicast_group *unicast_group; + enum bt_cap_common_subproc_type subproc_type; +#endif /* CONFIG_BT_CAP_INITIATOR_UNICAST */ +}; + +struct bt_cap_common_client { + struct bt_conn *conn; + struct bt_gatt_discover_params param; + uint16_t csis_start_handle; + const struct bt_csip_set_coordinator_csis_inst *csis_inst; + bool cas_found; +}; + +struct bt_cap_common_proc *bt_cap_common_get_active_proc(void); +void bt_cap_common_clear_active_proc(void); +void bt_cap_common_start_proc(enum bt_cap_common_proc_type proc_type, size_t proc_cnt); +void bt_cap_common_set_subproc(enum bt_cap_common_subproc_type subproc_type); +bool bt_cap_common_subproc_is_type(enum bt_cap_common_subproc_type subproc_type); +bool bt_cap_common_proc_is_active(void); +bool bt_cap_common_proc_is_aborted(void); +bool bt_cap_common_proc_all_streams_handled(void); +bool bt_cap_common_proc_is_done(void); +void bt_cap_common_abort_proc(struct bt_conn *conn, int err); +bool bt_cap_common_conn_in_active_proc(const struct bt_conn *conn); +bool bt_cap_common_stream_in_active_proc(const struct bt_cap_stream *cap_stream); +void bt_cap_common_disconnected(struct bt_conn *conn, uint8_t reason); +struct bt_cap_common_client *bt_cap_common_get_client_by_acl(const struct bt_conn *acl); +struct bt_cap_common_client * +bt_cap_common_get_client_by_csis(const struct bt_csip_set_coordinator_csis_inst *csis_inst); + +typedef void (*bt_cap_common_discover_func_t)( + struct bt_conn *conn, int err, const struct bt_csip_set_coordinator_csis_inst *csis_inst); +int bt_cap_common_discover(struct bt_conn *conn, bt_cap_common_discover_func_t func); diff --git a/tests/bluetooth/shell/audio.conf b/tests/bluetooth/shell/audio.conf index 8cf39af0bdb..5e441ad7140 100644 --- a/tests/bluetooth/shell/audio.conf +++ b/tests/bluetooth/shell/audio.conf @@ -203,4 +203,5 @@ CONFIG_BT_CSIP_SET_MEMBER_LOG_LEVEL_DBG=y CONFIG_BT_CAP_ACCEPTOR_LOG_LEVEL_DBG=y CONFIG_BT_CAP_INITIATOR_LOG_LEVEL_DBG=y CONFIG_BT_CAP_COMMANDER_LOG_LEVEL_DBG=y +CONFIG_BT_CAP_COMMON_LOG_LEVEL_DBG=y CONFIG_BT_TMAP_LOG_LEVEL_DBG=y diff --git a/tests/bsim/bluetooth/audio/src/cap_initiator_unicast_test.c b/tests/bsim/bluetooth/audio/src/cap_initiator_unicast_test.c index 335b2894838..4f3671d3d13 100644 --- a/tests/bsim/bluetooth/audio/src/cap_initiator_unicast_test.c +++ b/tests/bsim/bluetooth/audio/src/cap_initiator_unicast_test.c @@ -4,7 +4,7 @@ * SPDX-License-Identifier: Apache-2.0 */ -#if defined(CONFIG_BT_CAP_INITIATOR) && defined(CONFIG_BT_BAP_UNICAST_CLIENT) +#if defined(CONFIG_BT_CAP_INITIATOR_UNICAST) #include #include @@ -1741,11 +1741,11 @@ struct bst_test_list *test_cap_initiator_unicast_install(struct bst_test_list *t return bst_add_tests(tests, test_cap_initiator_unicast); } -#else /* !(defined(CONFIG_BT_CAP_INITIATOR) && defined(CONFIG_BT_BAP_UNICAST_CLIENT)) */ +#else /* !CONFIG_BT_CAP_INITIATOR_UNICAST */ struct bst_test_list *test_cap_initiator_unicast_install(struct bst_test_list *tests) { return tests; } -#endif /* defined(CONFIG_BT_CAP_INITIATOR) && defined(CONFIG_BT_BAP_UNICAST_CLIENT) */ +#endif /* CONFIG_BT_CAP_INITIATOR_UNICAST */ From c1204affab1d15e5eb83a482363f43bf2b48c27d Mon Sep 17 00:00:00 2001 From: Pieter De Gendt Date: Fri, 1 Dec 2023 13:21:39 +0100 Subject: [PATCH 0894/3723] net: ip: net_mgmt: Support system work queue and synchronous callbacks Add Kconfig choice for the user to select how Network Events are handled. It's own thread, the system work queue or synchronous when events are emitted. By default a separate thread is created to be backwards compatible. Signed-off-by: Pieter De Gendt --- subsys/net/ip/Kconfig.mgmt | 40 ++++++++++++++ subsys/net/ip/net_mgmt.c | 109 +++++++++++++++++++++++++------------ 2 files changed, 113 insertions(+), 36 deletions(-) diff --git a/subsys/net/ip/Kconfig.mgmt b/subsys/net/ip/Kconfig.mgmt index cc5c514afde..e5adb9e5728 100644 --- a/subsys/net/ip/Kconfig.mgmt +++ b/subsys/net/ip/Kconfig.mgmt @@ -19,6 +19,42 @@ config NET_MGMT_EVENT if NET_MGMT_EVENT +choice NET_MGMT_EVENT_WORKER + prompt "Network event scheduling" + default NET_MGMT_EVENT_THREAD + +config NET_MGMT_EVENT_THREAD + bool "Separate network events thread" + help + Create a dedicated thread for network event callback handlers. + If NET_MGMT_EVENT_INFO is enabled the data will be copied to + a message queue. + +config NET_MGMT_EVENT_SYSTEM_WORKQUEUE + bool "System work queue" + help + Submit work to the system work queue to schedule calling network + event callback handlers. + If NET_MGMT_EVENT_INFO is enabled the data will be copied to + a message queue. + +config NET_MGMT_EVENT_DIRECT + bool "Trigger callback on event emit" + help + Call network event handlers when the event is emitted. + If NET_MGMT_EVENT_INFO is enabled a data pointer is passed to + callback handlers, no info data is copied. + +endchoice + +config NET_MGMT_EVENT_QUEUE + bool + default y + depends on NET_MGMT_EVENT_THREAD || NET_MGMT_EVENT_SYSTEM_WORKQUEUE + help + Hidden option to enable the network event's queue if asynchronous + callbacks are done. + config NET_MGMT_EVENT_STACK_SIZE int "Stack size for the inner thread handling event callbacks" default 4096 if WIFI_NM_WPA_SUPPLICANT @@ -26,6 +62,7 @@ config NET_MGMT_EVENT_STACK_SIZE default 840 if X86 default 800 if THREAD_LOCAL_STORAGE default 768 + depends on NET_MGMT_EVENT_THREAD help Set the internal stack size for NM to run registered callbacks on events. @@ -35,6 +72,7 @@ config NET_MGMT_EVENT_QUEUE_SIZE default 16 if NET_MGMT_EVENT_MONITOR default 5 range 1 1024 + depends on NET_MGMT_EVENT_QUEUE help Numbers of events which can be queued at same time. Note that if a 3rd event comes in, the first will be removed without generating any @@ -45,6 +83,7 @@ config NET_MGMT_EVENT_QUEUE_TIMEOUT int "Timeout for event queue" default 10 range 1 10000 + depends on NET_MGMT_EVENT_QUEUE help Timeout in milliseconds for the event queue. This timeout is used to wait for the queue to be available. @@ -83,6 +122,7 @@ source "subsys/net/Kconfig.template.log_config.net" config NET_DEBUG_MGMT_EVENT_STACK bool "Stack analysis output on Net MGMT event core" select INIT_STACKS + depends on NET_MGMT_EVENT_THREAD help Add debug messages output on how much Net MGMT event stack is used. diff --git a/subsys/net/ip/net_mgmt.c b/subsys/net/ip/net_mgmt.c index 1ea04fc4791..c351b3df4d1 100644 --- a/subsys/net/ip/net_mgmt.c +++ b/subsys/net/ip/net_mgmt.c @@ -19,8 +19,12 @@ LOG_MODULE_REGISTER(net_mgmt, CONFIG_NET_MGMT_EVENT_LOG_LEVEL); #include "net_private.h" struct mgmt_event_entry { -#ifdef CONFIG_NET_MGMT_EVENT_INFO +#if defined(CONFIG_NET_MGMT_EVENT_INFO) +#if defined(CONFIG_NET_MGMT_EVENT_QUEUE) uint8_t info[NET_EVENT_INFO_MAX_SIZE]; +#else + const void *info; +#endif /* CONFIG_NET_MGMT_EVENT_QUEUE */ size_t info_length; #endif /* CONFIG_NET_MGMT_EVENT_INFO */ uint32_t event; @@ -36,18 +40,32 @@ struct mgmt_event_wait { }; static K_MUTEX_DEFINE(net_mgmt_callback_lock); -static K_MUTEX_DEFINE(net_mgmt_event_lock); +#if defined(CONFIG_NET_MGMT_EVENT_THREAD) K_KERNEL_STACK_DEFINE(mgmt_stack, CONFIG_NET_MGMT_EVENT_STACK_SIZE); -static struct k_thread mgmt_thread_data; + +static struct k_work_q mgmt_work_q_obj; +#endif + static uint32_t global_event_mask; static sys_slist_t event_callbacks = SYS_SLIST_STATIC_INIT(&event_callbacks); +/* Forward declaration for the actual caller */ +static void mgmt_run_callbacks(const struct mgmt_event_entry * const mgmt_event); + +#if defined(CONFIG_NET_MGMT_EVENT_QUEUE) + +static K_MUTEX_DEFINE(net_mgmt_event_lock); /* event structure used to prevent increasing the stack usage on the caller thread */ static struct mgmt_event_entry new_event; K_MSGQ_DEFINE(event_msgq, sizeof(struct mgmt_event_entry), CONFIG_NET_MGMT_EVENT_QUEUE_SIZE, sizeof(uint32_t)); +static struct k_work_q *mgmt_work_q = COND_CODE_1(CONFIG_NET_MGMT_EVENT_SYSTEM_WORKQUEUE, + (&k_sys_work_q), (&mgmt_work_q_obj)); + +static void mgmt_event_work_handler(struct k_work *work); +static K_WORK_DEFINE(mgmt_work, mgmt_event_work_handler); static inline void mgmt_push_event(uint32_t mgmt_event, struct net_if *iface, const void *info, size_t length) @@ -88,14 +106,43 @@ static inline void mgmt_push_event(uint32_t mgmt_event, struct net_if *iface, } (void)k_mutex_unlock(&net_mgmt_event_lock); + + k_work_submit_to_queue(mgmt_work_q, &mgmt_work); +} + +static void mgmt_event_work_handler(struct k_work *work) +{ + struct mgmt_event_entry mgmt_event; + + ARG_UNUSED(work); + + while (k_msgq_get(&event_msgq, &mgmt_event, K_FOREVER) == 0) { + NET_DBG("Handling events, forwarding it relevantly"); + + mgmt_run_callbacks(&mgmt_event); + + /* forcefully give up our timeslot, to give time to the callback */ + k_yield(); + } } -static inline void mgmt_pop_event(struct mgmt_event_entry *dst) +#else + +static inline void mgmt_push_event(uint32_t event, struct net_if *iface, + const void *info, size_t length) { - do { - } while (k_msgq_get(&event_msgq, dst, K_FOREVER) != 0); + const struct mgmt_event_entry mgmt_event = { + .info = info, + .info_length = length, + .event = event, + .iface = iface, + }; + + mgmt_run_callbacks(&mgmt_event); } +#endif /* CONFIG_NET_MGMT_EVENT_QUEUE */ + static inline void mgmt_add_event_mask(uint32_t event_mask) { global_event_mask |= event_mask; @@ -129,7 +176,7 @@ static inline bool mgmt_is_event_handled(uint32_t mgmt_event) NET_MGMT_GET_COMMAND(mgmt_event))); } -static inline void mgmt_run_callbacks(const struct mgmt_event_entry * const mgmt_event) +static inline void mgmt_run_slist_callbacks(const struct mgmt_event_entry * const mgmt_event) { sys_snode_t *prev = NULL; struct net_mgmt_event_callback *cb, *tmp; @@ -189,7 +236,7 @@ static inline void mgmt_run_callbacks(const struct mgmt_event_entry * const mgmt } #ifdef CONFIG_NET_DEBUG_MGMT_EVENT_STACK - log_stack_usage(&mgmt_thread_data); + log_stack_usage(&mgmt_work_q->thread); #endif } @@ -217,32 +264,15 @@ static inline void mgmt_run_static_callbacks(const struct mgmt_event_entry * con } } -static void mgmt_thread(void *p1, void *p2, void *p3) +static void mgmt_run_callbacks(const struct mgmt_event_entry * const mgmt_event) { - ARG_UNUSED(p1); - ARG_UNUSED(p2); - ARG_UNUSED(p3); - - struct mgmt_event_entry mgmt_event; - - mgmt_rebuild_global_event_mask(); - - while (1) { - mgmt_pop_event(&mgmt_event); - - NET_DBG("Handling events, forwarding it relevantly"); - - /* take the lock to prevent changes to the callback structure during use */ - (void)k_mutex_lock(&net_mgmt_callback_lock, K_FOREVER); - - mgmt_run_static_callbacks(&mgmt_event); - mgmt_run_callbacks(&mgmt_event); + /* take the lock to prevent changes to the callback structure during use */ + (void)k_mutex_lock(&net_mgmt_callback_lock, K_FOREVER); - (void)k_mutex_unlock(&net_mgmt_callback_lock); + mgmt_run_static_callbacks(mgmt_event); + mgmt_run_slist_callbacks(mgmt_event); - /* forcefully give up our timeslot, to give time to the callback */ - k_yield(); - } + (void)k_mutex_unlock(&net_mgmt_callback_lock); } static int mgmt_event_wait_call(struct net_if *iface, @@ -369,20 +399,27 @@ int net_mgmt_event_wait_on_iface(struct net_if *iface, void net_mgmt_event_init(void) { + mgmt_rebuild_global_event_mask(); + +#if defined(CONFIG_NET_MGMT_EVENT_THREAD) #if defined(CONFIG_NET_TC_THREAD_COOPERATIVE) /* Lowest priority cooperative thread */ #define THREAD_PRIORITY K_PRIO_COOP(CONFIG_NUM_COOP_PRIORITIES - 1) #else #define THREAD_PRIORITY K_PRIO_PREEMPT(CONFIG_NUM_PREEMPT_PRIORITIES - 1) #endif + struct k_work_queue_config q_cfg = { + .name = "net_mgmt", + .no_yield = false, + }; - k_thread_create(&mgmt_thread_data, mgmt_stack, - K_KERNEL_STACK_SIZEOF(mgmt_stack), - mgmt_thread, NULL, NULL, NULL, - THREAD_PRIORITY, 0, K_NO_WAIT); - k_thread_name_set(&mgmt_thread_data, "net_mgmt"); + k_work_queue_init(&mgmt_work_q_obj); + k_work_queue_start(&mgmt_work_q_obj, mgmt_stack, + K_KERNEL_STACK_SIZEOF(mgmt_stack), + THREAD_PRIORITY, &q_cfg); NET_DBG("Net MGMT initialized: queue of %u entries, stack size of %u", CONFIG_NET_MGMT_EVENT_QUEUE_SIZE, CONFIG_NET_MGMT_EVENT_STACK_SIZE); +#endif /* CONFIG_NET_MGMT_EVENT_THREAD */ } From 8084a1c908d1ccdebdb7234ba5711bc89b53a652 Mon Sep 17 00:00:00 2001 From: Pieter De Gendt Date: Fri, 1 Dec 2023 13:24:25 +0100 Subject: [PATCH 0895/3723] tests: net: mgmt: Add test cases new worker options Run the Network event tests also on the system work queue and synchronous. Signed-off-by: Pieter De Gendt --- tests/net/mgmt/testcase.yaml | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/tests/net/mgmt/testcase.yaml b/tests/net/mgmt/testcase.yaml index d27c01b595d..1c6d970b7c5 100644 --- a/tests/net/mgmt/testcase.yaml +++ b/tests/net/mgmt/testcase.yaml @@ -11,3 +11,9 @@ tests: net.management.preempt: extra_configs: - CONFIG_NET_TC_THREAD_PREEMPTIVE=y + net.workqueue: + extra_configs: + - CONFIG_NET_MGMT_EVENT_SYSTEM_WORKQUEUE=y + net.synchronous: + extra_configs: + - CONFIG_NET_MGMT_EVENT_DIRECT=y From a51af147290301f762f87fd986e39ff322138c3f Mon Sep 17 00:00:00 2001 From: Pieter De Gendt Date: Fri, 1 Dec 2023 13:27:40 +0100 Subject: [PATCH 0896/3723] doc: release: 3.6: Add note on net_mgmt worker Kconfig Added an entry for the Kconfig choice CONFIG_NET_MGMT_EVENT_WORKER. Signed-off-by: Pieter De Gendt --- doc/releases/release-notes-3.6.rst | 3 +++ 1 file changed, 3 insertions(+) diff --git a/doc/releases/release-notes-3.6.rst b/doc/releases/release-notes-3.6.rst index 1fc6620c756..85511a103f9 100644 --- a/doc/releases/release-notes-3.6.rst +++ b/doc/releases/release-notes-3.6.rst @@ -231,6 +231,9 @@ Networking * Added support for compile time network event handlers using the macro :c:macro:`NET_MGMT_REGISTER_EVENT_HANDLER`. + * The :kconfig:option:`CONFIG_NET_MGMT_EVENT_WORKER` choice is added to + allow emitting network events using the system work queue or synchronously. + * MQTT-SN: * OpenThread: From 786b9a0ad405c3475382545aa29e3b815129e68a Mon Sep 17 00:00:00 2001 From: Lingao Meng Date: Tue, 5 Dec 2023 17:52:21 +0800 Subject: [PATCH 0897/3723] Bluetooth: Host: Add const prefix for UUID Add const prefix for service uuid and char uuid. Since Service UUID and Char UUID should not change in the service definition, they are most reasonably defined as rodata, also for save some ram footprint. The field `attr->user_data` type is `void *`, as this PR change all Service UUID to rodata, so there must add (void *) to avoid warning. Signed-off-by: Lingao Meng --- include/zephyr/bluetooth/gatt.h | 4 +-- include/zephyr/bluetooth/uuid.h | 6 ++--- samples/bluetooth/central_hr/src/main.c | 2 +- samples/bluetooth/central_ht/src/main.c | 2 +- samples/bluetooth/central_otc/src/main.c | 2 +- samples/bluetooth/direct_adv/src/main.c | 6 ++--- samples/bluetooth/eddystone/src/main.c | 26 +++++++++---------- .../peripheral/src/peripheral_mtu_update.c | 4 +-- .../bluetooth/periodic_sync_rsp/src/main.c | 4 +-- samples/bluetooth/peripheral/src/main.c | 6 ++--- .../peripheral_accept_list/src/main.c | 6 ++--- samples/bluetooth/st_ble_sensor/src/main.c | 6 ++--- samples/bluetooth/tmap_central/src/main.c | 2 +- .../bluetooth/unicast_audio_client/src/main.c | 2 +- samples/boards/bbc_microbit/pong/src/ble.c | 6 ++--- .../boards/reel_board/mesh_badge/src/main.c | 4 +-- subsys/bluetooth/audio/micp_mic_ctlr.c | 2 +- subsys/bluetooth/audio/mpl.c | 10 +++---- subsys/bluetooth/host/gatt.c | 2 +- subsys/bluetooth/shell/gatt.c | 8 +++--- subsys/mgmt/mcumgr/transport/src/smp_bt.c | 4 +-- subsys/net/l2/bluetooth/bluetooth.c | 2 +- tests/bluetooth/gatt/src/main.c | 6 ++--- tests/bluetooth/tester/src/btp_gatt.c | 4 +-- .../bluetooth/audio/src/tmap_client_test.c | 2 +- .../host/att/eatt_notif/src/client_test.c | 2 +- .../host/gatt/ccc_store/src/peripheral.c | 5 ++-- .../host/gatt/general/src/gatt_client_test.c | 2 +- .../host/gatt/notify/src/gatt_client_test.c | 2 +- .../notify_multiple/src/gatt_client_test.c | 2 +- .../host/gatt/settings/src/gatt_utils.c | 6 ++--- .../host/misc/disable/src/gatt_client_test.c | 2 +- .../host/security/ccc_update/src/peripheral.c | 5 ++-- .../bluetooth/ll/conn/src/test_connect1.c | 2 +- .../edtt/gatt_test_app/src/gatt/gatt_macs.h | 4 +-- 35 files changed, 81 insertions(+), 79 deletions(-) diff --git a/include/zephyr/bluetooth/gatt.h b/include/zephyr/bluetooth/gatt.h index c53422648f0..15d3536a4f6 100644 --- a/include/zephyr/bluetooth/gatt.h +++ b/include/zephyr/bluetooth/gatt.h @@ -626,7 +626,7 @@ ssize_t bt_gatt_attr_read_service(struct bt_conn *conn, */ #define BT_GATT_PRIMARY_SERVICE(_service) \ BT_GATT_ATTRIBUTE(BT_UUID_GATT_PRIMARY, BT_GATT_PERM_READ, \ - bt_gatt_attr_read_service, NULL, _service) + bt_gatt_attr_read_service, NULL, (void *)_service) /** * @brief Secondary Service Declaration Macro. @@ -640,7 +640,7 @@ ssize_t bt_gatt_attr_read_service(struct bt_conn *conn, */ #define BT_GATT_SECONDARY_SERVICE(_service) \ BT_GATT_ATTRIBUTE(BT_UUID_GATT_SECONDARY, BT_GATT_PERM_READ, \ - bt_gatt_attr_read_service, NULL, _service) + bt_gatt_attr_read_service, NULL, (void *)_service) /** @brief Read Include Attribute helper. * diff --git a/include/zephyr/bluetooth/uuid.h b/include/zephyr/bluetooth/uuid.h index cab12eac74b..8aeaecf1942 100644 --- a/include/zephyr/bluetooth/uuid.h +++ b/include/zephyr/bluetooth/uuid.h @@ -110,7 +110,7 @@ struct bt_uuid_128 { * @return Pointer to a generic UUID. */ #define BT_UUID_DECLARE_16(value) \ - ((struct bt_uuid *) ((struct bt_uuid_16[]) {BT_UUID_INIT_16(value)})) + ((const struct bt_uuid *) ((const struct bt_uuid_16[]) {BT_UUID_INIT_16(value)})) /** @brief Helper to declare a 32-bit UUID inline. * @@ -119,7 +119,7 @@ struct bt_uuid_128 { * @return Pointer to a generic UUID. */ #define BT_UUID_DECLARE_32(value) \ - ((struct bt_uuid *) ((struct bt_uuid_32[]) {BT_UUID_INIT_32(value)})) + ((const struct bt_uuid *) ((const struct bt_uuid_32[]) {BT_UUID_INIT_32(value)})) /** @brief Helper to declare a 128-bit UUID inline. * @@ -130,7 +130,7 @@ struct bt_uuid_128 { * @return Pointer to a generic UUID. */ #define BT_UUID_DECLARE_128(value...) \ - ((struct bt_uuid *) ((struct bt_uuid_128[]) {BT_UUID_INIT_128(value)})) + ((const struct bt_uuid *) ((const struct bt_uuid_128[]) {BT_UUID_INIT_128(value)})) /** Helper macro to access the 16-bit UUID from a generic UUID. */ #define BT_UUID_16(__u) CONTAINER_OF(__u, struct bt_uuid_16, uuid) diff --git a/samples/bluetooth/central_hr/src/main.c b/samples/bluetooth/central_hr/src/main.c index ecb262c8517..305066bccd6 100644 --- a/samples/bluetooth/central_hr/src/main.c +++ b/samples/bluetooth/central_hr/src/main.c @@ -113,7 +113,7 @@ static bool eir_found(struct bt_data *data, void *user_data) for (i = 0; i < data->data_len; i += sizeof(uint16_t)) { struct bt_le_conn_param *param; - struct bt_uuid *uuid; + const struct bt_uuid *uuid; uint16_t u16; int err; diff --git a/samples/bluetooth/central_ht/src/main.c b/samples/bluetooth/central_ht/src/main.c index f2396115cc2..cc9bdae61c1 100644 --- a/samples/bluetooth/central_ht/src/main.c +++ b/samples/bluetooth/central_ht/src/main.c @@ -174,7 +174,7 @@ static bool eir_found(struct bt_data *data, void *user_data) } for (i = 0; i < data->data_len; i += sizeof(uint16_t)) { - struct bt_uuid *uuid; + const struct bt_uuid *uuid; uint16_t u16; int err; diff --git a/samples/bluetooth/central_otc/src/main.c b/samples/bluetooth/central_otc/src/main.c index 5dd9412ff65..7c2c659f510 100644 --- a/samples/bluetooth/central_otc/src/main.c +++ b/samples/bluetooth/central_otc/src/main.c @@ -237,7 +237,7 @@ static bool eir_found(struct bt_data *data, void *user_data) for (i = 0; i < data->data_len; i += sizeof(uint16_t)) { struct bt_le_conn_param *param; - struct bt_uuid *uuid; + const struct bt_uuid *uuid; uint16_t u16; int err; diff --git a/samples/bluetooth/direct_adv/src/main.c b/samples/bluetooth/direct_adv/src/main.c index d93f77083eb..c8ebda0df9b 100644 --- a/samples/bluetooth/direct_adv/src/main.c +++ b/samples/bluetooth/direct_adv/src/main.c @@ -23,13 +23,13 @@ #define BT_UUID_CUSTOM_SERVICE_VAL \ BT_UUID_128_ENCODE(0x12345678, 0x1234, 0x5678, 0x1234, 0x56789abcdef0) -static struct bt_uuid_128 primary_service_uuid = BT_UUID_INIT_128( +static const struct bt_uuid_128 primary_service_uuid = BT_UUID_INIT_128( BT_UUID_CUSTOM_SERVICE_VAL); -static struct bt_uuid_128 read_characteristic_uuid = BT_UUID_INIT_128( +static const struct bt_uuid_128 read_characteristic_uuid = BT_UUID_INIT_128( BT_UUID_128_ENCODE(0x12345678, 0x1234, 0x5678, 0x1234, 0x56789abcdef1)); -static struct bt_uuid_128 write_characteristic_uuid = BT_UUID_INIT_128( +static const struct bt_uuid_128 write_characteristic_uuid = BT_UUID_INIT_128( BT_UUID_128_ENCODE(0x12345678, 0x1234, 0x5678, 0x1234, 0x56789abcdef2)); static int signed_value; diff --git a/samples/bluetooth/eddystone/src/main.c b/samples/bluetooth/eddystone/src/main.c index ff4ab59cd9c..86a99aaac4c 100644 --- a/samples/bluetooth/eddystone/src/main.c +++ b/samples/bluetooth/eddystone/src/main.c @@ -40,55 +40,55 @@ static const struct bt_data ad[] = { /* Eddystone Service Variables */ /* Service UUID a3c87500-8ed3-4bdf-8a39-a01bebede295 */ -static struct bt_uuid_128 eds_uuid = BT_UUID_INIT_128( +static const struct bt_uuid_128 eds_uuid = BT_UUID_INIT_128( BT_UUID_128_ENCODE(0xa3c87500, 0x8ed3, 0x4bdf, 0x8a39, 0xa01bebede295)); /* Characteristic UUID a3c87501-8ed3-4bdf-8a39-a01bebede295 */ -static struct bt_uuid_128 eds_caps_uuid = BT_UUID_INIT_128( +static const struct bt_uuid_128 eds_caps_uuid = BT_UUID_INIT_128( BT_UUID_128_ENCODE(0xa3c87501, 0x8ed3, 0x4bdf, 0x8a39, 0xa01bebede295)); /* Characteristic UUID a3c87502-8ed3-4bdf-8a39-a01bebede295 */ -static struct bt_uuid_128 eds_slot_uuid = BT_UUID_INIT_128( +static const struct bt_uuid_128 eds_slot_uuid = BT_UUID_INIT_128( BT_UUID_128_ENCODE(0xa3c87502, 0x8ed3, 0x4bdf, 0x8a39, 0xa01bebede295)); /* Characteristic UUID a3c87503-8ed3-4bdf-8a39-a01bebede295 */ -static struct bt_uuid_128 eds_intv_uuid = BT_UUID_INIT_128( +static const struct bt_uuid_128 eds_intv_uuid = BT_UUID_INIT_128( BT_UUID_128_ENCODE(0xa3c87503, 0x8ed3, 0x4bdf, 0x8a39, 0xa01bebede295)); /* Characteristic UUID a3c87504-8ed3-4bdf-8a39-a01bebede295 */ -static struct bt_uuid_128 eds_tx_uuid = BT_UUID_INIT_128( +static const struct bt_uuid_128 eds_tx_uuid = BT_UUID_INIT_128( BT_UUID_128_ENCODE(0xa3c87504, 0x8ed3, 0x4bdf, 0x8a39, 0xa01bebede295)); /* Characteristic UUID a3c87505-8ed3-4bdf-8a39-a01bebede295 */ -static struct bt_uuid_128 eds_adv_tx_uuid = BT_UUID_INIT_128( +static const struct bt_uuid_128 eds_adv_tx_uuid = BT_UUID_INIT_128( BT_UUID_128_ENCODE(0xa3c87505, 0x8ed3, 0x4bdf, 0x8a39, 0xa01bebede295)); /* Characteristic UUID a3c87506-8ed3-4bdf-8a39-a01bebede295 */ -static struct bt_uuid_128 eds_lock_uuid = BT_UUID_INIT_128( +static const struct bt_uuid_128 eds_lock_uuid = BT_UUID_INIT_128( BT_UUID_128_ENCODE(0xa3c87506, 0x8ed3, 0x4bdf, 0x8a39, 0xa01bebede295)); /* Characteristic UUID a3c87507-8ed3-4bdf-8a39-a01bebede295 */ -static struct bt_uuid_128 eds_unlock_uuid = BT_UUID_INIT_128( +static const struct bt_uuid_128 eds_unlock_uuid = BT_UUID_INIT_128( BT_UUID_128_ENCODE(0xa3c87507, 0x8ed3, 0x4bdf, 0x8a39, 0xa01bebede295)); /* Characteristic UUID a3c87508-8ed3-4bdf-8a39-a01bebede295 */ -static struct bt_uuid_128 eds_ecdh_uuid = BT_UUID_INIT_128( +static const struct bt_uuid_128 eds_ecdh_uuid = BT_UUID_INIT_128( BT_UUID_128_ENCODE(0xa3c87508, 0x8ed3, 0x4bdf, 0x8a39, 0xa01bebede295)); /* Characteristic UUID a3c87509-8ed3-4bdf-8a39-a01bebede295 */ -static struct bt_uuid_128 eds_eid_uuid = BT_UUID_INIT_128( +static const struct bt_uuid_128 eds_eid_uuid = BT_UUID_INIT_128( BT_UUID_128_ENCODE(0xa3c87509, 0x8ed3, 0x4bdf, 0x8a39, 0xa01bebede295)); /* Characteristic UUID a3c8750a-8ed3-4bdf-8a39-a01bebede295 */ -static struct bt_uuid_128 eds_data_uuid = BT_UUID_INIT_128( +static const struct bt_uuid_128 eds_data_uuid = BT_UUID_INIT_128( BT_UUID_128_ENCODE(0xa3c8750a, 0x8ed3, 0x4bdf, 0x8a39, 0xa01bebede295)); /* Characteristic UUID a3c8750b-8ed3-4bdf-8a39-a01bebede295 */ -static struct bt_uuid_128 eds_reset_uuid = BT_UUID_INIT_128( +static const struct bt_uuid_128 eds_reset_uuid = BT_UUID_INIT_128( BT_UUID_128_ENCODE(0xa3c8750b, 0x8ed3, 0x4bdf, 0x8a39, 0xa01bebede295)); /* Characteristic UUID a3c8750c-8ed3-4bdf-8a39-a01bebede295 */ -static struct bt_uuid_128 eds_connectable_uuid = BT_UUID_INIT_128( +static const struct bt_uuid_128 eds_connectable_uuid = BT_UUID_INIT_128( BT_UUID_128_ENCODE(0xa3c8750c, 0x8ed3, 0x4bdf, 0x8a39, 0xa01bebede295)); enum { diff --git a/samples/bluetooth/mtu_update/peripheral/src/peripheral_mtu_update.c b/samples/bluetooth/mtu_update/peripheral/src/peripheral_mtu_update.c index f30e50a85ab..66af1bf86b5 100644 --- a/samples/bluetooth/mtu_update/peripheral/src/peripheral_mtu_update.c +++ b/samples/bluetooth/mtu_update/peripheral/src/peripheral_mtu_update.c @@ -16,9 +16,9 @@ #define MTU_TEST_SERVICE_TYPE BT_UUID_128_ENCODE(0x2e2b8dc3, 0x06e0, 0x4f93, 0x9bb2, 0x734091c356f0) -static struct bt_uuid_128 mtu_test_service = BT_UUID_INIT_128(MTU_TEST_SERVICE_TYPE); +static const struct bt_uuid_128 mtu_test_service = BT_UUID_INIT_128(MTU_TEST_SERVICE_TYPE); -static struct bt_uuid_128 notify_characteristic_uuid = +static const struct bt_uuid_128 notify_characteristic_uuid = BT_UUID_INIT_128(BT_UUID_128_ENCODE(0x2e2b8dc3, 0x06e0, 0x4f93, 0x9bb2, 0x734091c356f3)); static const struct bt_data adv_ad_data[] = { diff --git a/samples/bluetooth/periodic_sync_rsp/src/main.c b/samples/bluetooth/periodic_sync_rsp/src/main.c index d39a7814943..24be636d8c9 100644 --- a/samples/bluetooth/periodic_sync_rsp/src/main.c +++ b/samples/bluetooth/periodic_sync_rsp/src/main.c @@ -122,9 +122,9 @@ static struct bt_le_per_adv_sync_cb sync_callbacks = { .recv = recv_cb, }; -static struct bt_uuid_128 pawr_svc_uuid = +static const struct bt_uuid_128 pawr_svc_uuid = BT_UUID_INIT_128(BT_UUID_128_ENCODE(0x12345678, 0x1234, 0x5678, 0x1234, 0x56789abcdef0)); -static struct bt_uuid_128 pawr_char_uuid = +static const struct bt_uuid_128 pawr_char_uuid = BT_UUID_INIT_128(BT_UUID_128_ENCODE(0x12345678, 0x1234, 0x5678, 0x1234, 0x56789abcdef1)); static ssize_t write_timing(struct bt_conn *conn, const struct bt_gatt_attr *attr, const void *buf, diff --git a/samples/bluetooth/peripheral/src/main.c b/samples/bluetooth/peripheral/src/main.c index 53847832e16..7cd65636037 100644 --- a/samples/bluetooth/peripheral/src/main.c +++ b/samples/bluetooth/peripheral/src/main.c @@ -31,13 +31,13 @@ #define BT_UUID_CUSTOM_SERVICE_VAL \ BT_UUID_128_ENCODE(0x12345678, 0x1234, 0x5678, 0x1234, 0x56789abcdef0) -static struct bt_uuid_128 vnd_uuid = BT_UUID_INIT_128( +static const struct bt_uuid_128 vnd_uuid = BT_UUID_INIT_128( BT_UUID_CUSTOM_SERVICE_VAL); -static struct bt_uuid_128 vnd_enc_uuid = BT_UUID_INIT_128( +static const struct bt_uuid_128 vnd_enc_uuid = BT_UUID_INIT_128( BT_UUID_128_ENCODE(0x12345678, 0x1234, 0x5678, 0x1234, 0x56789abcdef1)); -static struct bt_uuid_128 vnd_auth_uuid = BT_UUID_INIT_128( +static const struct bt_uuid_128 vnd_auth_uuid = BT_UUID_INIT_128( BT_UUID_128_ENCODE(0x12345678, 0x1234, 0x5678, 0x1234, 0x56789abcdef2)); #define VND_MAX_LEN 20 diff --git a/samples/bluetooth/peripheral_accept_list/src/main.c b/samples/bluetooth/peripheral_accept_list/src/main.c index e9b4b670578..f185bfdd6c8 100644 --- a/samples/bluetooth/peripheral_accept_list/src/main.c +++ b/samples/bluetooth/peripheral_accept_list/src/main.c @@ -19,13 +19,13 @@ #define BT_UUID_CUSTOM_SERVICE_VAL \ BT_UUID_128_ENCODE(0x12345678, 0x1234, 0x5678, 0x1234, 0x56789abcdef0) -static struct bt_uuid_128 primary_service_uuid = BT_UUID_INIT_128( +static const struct bt_uuid_128 primary_service_uuid = BT_UUID_INIT_128( BT_UUID_CUSTOM_SERVICE_VAL); -static struct bt_uuid_128 read_characteristic_uuid = BT_UUID_INIT_128( +static const struct bt_uuid_128 read_characteristic_uuid = BT_UUID_INIT_128( BT_UUID_128_ENCODE(0x12345678, 0x1234, 0x5678, 0x1234, 0x56789abcdef1)); -static struct bt_uuid_128 write_characteristic_uuid = BT_UUID_INIT_128( +static const struct bt_uuid_128 write_characteristic_uuid = BT_UUID_INIT_128( BT_UUID_128_ENCODE(0x12345678, 0x1234, 0x5678, 0x1234, 0x56789abcdef2)); static int signed_value; diff --git a/samples/bluetooth/st_ble_sensor/src/main.c b/samples/bluetooth/st_ble_sensor/src/main.c index 3a65cc0d777..95060f9167a 100644 --- a/samples/bluetooth/st_ble_sensor/src/main.c +++ b/samples/bluetooth/st_ble_sensor/src/main.c @@ -36,15 +36,15 @@ static ssize_t recv(struct bt_conn *conn, uint16_t len, uint16_t offset, uint8_t flags); /* ST Custom Service */ -static struct bt_uuid_128 st_service_uuid = BT_UUID_INIT_128( +static const struct bt_uuid_128 st_service_uuid = BT_UUID_INIT_128( BT_UUID_128_ENCODE(0x0000fe40, 0xcc7a, 0x482a, 0x984a, 0x7f2ed5b3e58f)); /* ST LED service */ -static struct bt_uuid_128 led_char_uuid = BT_UUID_INIT_128( +static const struct bt_uuid_128 led_char_uuid = BT_UUID_INIT_128( BT_UUID_128_ENCODE(0x0000fe41, 0x8e22, 0x4541, 0x9d4c, 0x21edae82ed19)); /* ST Notify button service */ -static struct bt_uuid_128 but_notif_uuid = BT_UUID_INIT_128( +static const struct bt_uuid_128 but_notif_uuid = BT_UUID_INIT_128( BT_UUID_128_ENCODE(0x0000fe42, 0x8e22, 0x4541, 0x9d4c, 0x21edae82ed19)); #define DEVICE_NAME CONFIG_BT_DEVICE_NAME diff --git a/samples/bluetooth/tmap_central/src/main.c b/samples/bluetooth/tmap_central/src/main.c index d890eb77107..fa75817c8f9 100644 --- a/samples/bluetooth/tmap_central/src/main.c +++ b/samples/bluetooth/tmap_central/src/main.c @@ -138,7 +138,7 @@ static bool check_audio_support_and_connect(struct bt_data *data, void *user_dat { bt_addr_le_t *addr = user_data; struct net_buf_simple tmas_svc_data; - struct bt_uuid *uuid; + const struct bt_uuid *uuid; uint16_t uuid_val; uint16_t peer_tmap_role = 0; int err; diff --git a/samples/bluetooth/unicast_audio_client/src/main.c b/samples/bluetooth/unicast_audio_client/src/main.c index 3953bee99f0..14ad2bb80e7 100644 --- a/samples/bluetooth/unicast_audio_client/src/main.c +++ b/samples/bluetooth/unicast_audio_client/src/main.c @@ -402,7 +402,7 @@ static bool check_audio_support_and_connect(struct bt_data *data, bt_addr_le_t *addr = user_data; uint8_t announcement_type; uint32_t audio_contexts; - struct bt_uuid *uuid; + const struct bt_uuid *uuid; uint16_t uuid_val; uint8_t meta_len; size_t min_size; diff --git a/samples/boards/bbc_microbit/pong/src/ble.c b/samples/boards/bbc_microbit/pong/src/ble.c index 08ebe38a254..89f34f3585f 100644 --- a/samples/boards/bbc_microbit/pong/src/ble.c +++ b/samples/boards/bbc_microbit/pong/src/ble.c @@ -30,9 +30,9 @@ #define PONG_CHR_UUID \ BT_UUID_128_ENCODE(0xabbf8f1c, 0xc56a, 0x82b5, 0xc640, 0x2ccdd7af94dd) -static struct bt_uuid_128 pong_svc_uuid = BT_UUID_INIT_128(PONG_SVC_UUID); -static struct bt_uuid_128 pong_chr_uuid = BT_UUID_INIT_128(PONG_CHR_UUID); -static struct bt_uuid *gatt_ccc_uuid = BT_UUID_GATT_CCC; +static const struct bt_uuid_128 pong_svc_uuid = BT_UUID_INIT_128(PONG_SVC_UUID); +static const struct bt_uuid_128 pong_chr_uuid = BT_UUID_INIT_128(PONG_CHR_UUID); +static const struct bt_uuid *gatt_ccc_uuid = BT_UUID_GATT_CCC; static struct bt_gatt_discover_params discov_param; static struct bt_gatt_subscribe_params subscribe_param; diff --git a/samples/boards/reel_board/mesh_badge/src/main.c b/samples/boards/reel_board/mesh_badge/src/main.c index 13dedb3a5c1..49dd110ec0e 100644 --- a/samples/boards/reel_board/mesh_badge/src/main.c +++ b/samples/boards/reel_board/mesh_badge/src/main.c @@ -59,10 +59,10 @@ static ssize_t write_name(struct bt_conn *conn, const struct bt_gatt_attr *attr, return len; } -static struct bt_uuid_128 name_uuid = BT_UUID_INIT_128( +static const struct bt_uuid_128 name_uuid = BT_UUID_INIT_128( BT_UUID_128_ENCODE(0x12345678, 0x1234, 0x5678, 0x1234, 0x56789abcdef0)); -static struct bt_uuid_128 name_enc_uuid = BT_UUID_INIT_128( +static const struct bt_uuid_128 name_enc_uuid = BT_UUID_INIT_128( BT_UUID_128_ENCODE(0x12345678, 0x1234, 0x5678, 0x1234, 0x56789abcdef1)); #define CPF_FORMAT_UTF8 0x19 diff --git a/subsys/bluetooth/audio/micp_mic_ctlr.c b/subsys/bluetooth/audio/micp_mic_ctlr.c index 55fa6c3c5db..4865ccb28ce 100644 --- a/subsys/bluetooth/audio/micp_mic_ctlr.c +++ b/subsys/bluetooth/audio/micp_mic_ctlr.c @@ -31,7 +31,7 @@ LOG_MODULE_REGISTER(bt_micp_mic_ctlr, CONFIG_BT_MICP_MIC_CTLR_LOG_LEVEL); static struct bt_micp_mic_ctlr_cb *micp_mic_ctlr_cb; static struct bt_micp_mic_ctlr mic_ctlrs[CONFIG_BT_MAX_CONN]; -static struct bt_uuid *mics_uuid = BT_UUID_MICS; +static const struct bt_uuid *mics_uuid = BT_UUID_MICS; static uint8_t mute_notify_handler(struct bt_conn *conn, struct bt_gatt_subscribe_params *params, diff --git a/subsys/bluetooth/audio/mpl.c b/subsys/bluetooth/audio/mpl.c index cce2403b5b6..1b9d89e7a99 100644 --- a/subsys/bluetooth/audio/mpl.c +++ b/subsys/bluetooth/audio/mpl.c @@ -450,7 +450,7 @@ static int add_icon_object(struct mpl_mediaplayer *pl) int ret; struct bt_ots_obj_add_param add_param = {}; struct bt_ots_obj_created_desc created_desc = {}; - struct bt_uuid *icon_type = BT_UUID_OTS_TYPE_MPL_ICON; + const struct bt_uuid *icon_type = BT_UUID_OTS_TYPE_MPL_ICON; static char *icon_name = "Icon"; if (obj.busy) { @@ -488,7 +488,7 @@ static int add_current_track_segments_object(struct mpl_mediaplayer *pl) int ret; struct bt_ots_obj_add_param add_param = {}; struct bt_ots_obj_created_desc created_desc = {}; - struct bt_uuid *segs_type = BT_UUID_OTS_TYPE_TRACK_SEGMENT; + const struct bt_uuid *segs_type = BT_UUID_OTS_TYPE_TRACK_SEGMENT; if (obj.busy) { LOG_ERR("Object busy"); @@ -522,7 +522,7 @@ static int add_track_object(struct mpl_track *track) { struct bt_ots_obj_add_param add_param = {}; struct bt_ots_obj_created_desc created_desc = {}; - struct bt_uuid *track_type = BT_UUID_OTS_TYPE_TRACK; + const struct bt_uuid *track_type = BT_UUID_OTS_TYPE_TRACK; int ret; if (obj.busy) { @@ -565,7 +565,7 @@ static int add_parent_group_object(struct mpl_mediaplayer *pl) int ret; struct bt_ots_obj_add_param add_param = {}; struct bt_ots_obj_created_desc created_desc = {}; - struct bt_uuid *group_type = BT_UUID_OTS_TYPE_GROUP; + const struct bt_uuid *group_type = BT_UUID_OTS_TYPE_GROUP; if (obj.busy) { LOG_ERR("Object busy"); @@ -599,7 +599,7 @@ static int add_group_object(struct mpl_group *group) { struct bt_ots_obj_add_param add_param = {}; struct bt_ots_obj_created_desc created_desc = {}; - struct bt_uuid *group_type = BT_UUID_OTS_TYPE_GROUP; + const struct bt_uuid *group_type = BT_UUID_OTS_TYPE_GROUP; int ret; if (obj.busy) { diff --git a/subsys/bluetooth/host/gatt.c b/subsys/bluetooth/host/gatt.c index 103229ea245..19295fbde9e 100644 --- a/subsys/bluetooth/host/gatt.c +++ b/subsys/bluetooth/host/gatt.c @@ -1758,7 +1758,7 @@ ssize_t bt_gatt_attr_read_service(struct bt_conn *conn, const struct bt_gatt_attr *attr, void *buf, uint16_t len, uint16_t offset) { - struct bt_uuid *uuid = attr->user_data; + const struct bt_uuid *uuid = attr->user_data; if (uuid->type == BT_UUID_TYPE_16) { uint16_t uuid16 = sys_cpu_to_le16(BT_UUID_16(uuid)->val); diff --git a/subsys/bluetooth/shell/gatt.c b/subsys/bluetooth/shell/gatt.c index 1a31b9e2f1a..f221cebeec5 100644 --- a/subsys/bluetooth/shell/gatt.c +++ b/subsys/bluetooth/shell/gatt.c @@ -761,10 +761,10 @@ static int cmd_show_db(const struct shell *sh, size_t argc, char *argv[]) #if defined(CONFIG_BT_GATT_DYNAMIC_DB) /* Custom Service Variables */ -static struct bt_uuid_128 vnd_uuid = BT_UUID_INIT_128( +static const struct bt_uuid_128 vnd_uuid = BT_UUID_INIT_128( BT_UUID_128_ENCODE(0x12345678, 0x1234, 0x5678, 0x1234, 0x56789abcdef0)); -static struct bt_uuid_128 vnd_auth_uuid = BT_UUID_INIT_128( +static const struct bt_uuid_128 vnd_auth_uuid = BT_UUID_INIT_128( BT_UUID_128_ENCODE(0x12345678, 0x1234, 0x5678, 0x1234, 0x56789abcdef2)); static const struct bt_uuid_128 vnd_long_uuid1 = BT_UUID_INIT_128( @@ -775,7 +775,7 @@ static const struct bt_uuid_128 vnd_long_uuid2 = BT_UUID_INIT_128( static uint8_t vnd_value[] = { 'V', 'e', 'n', 'd', 'o', 'r' }; -static struct bt_uuid_128 vnd1_uuid = BT_UUID_INIT_128( +static const struct bt_uuid_128 vnd1_uuid = BT_UUID_INIT_128( BT_UUID_128_ENCODE(0x12345678, 0x1234, 0x5678, 0x12340, 0x56789abcdef4)); static const struct bt_uuid_128 vnd1_echo_uuid = BT_UUID_INIT_128( @@ -1093,7 +1093,7 @@ static int cmd_notify_mult(const struct shell *sh, size_t argc, char *argv[]) } #endif /* CONFIG_BT_GATT_NOTIFY_MULTIPLE */ -static struct bt_uuid_128 met_svc_uuid = BT_UUID_INIT_128( +static const struct bt_uuid_128 met_svc_uuid = BT_UUID_INIT_128( BT_UUID_128_ENCODE(0x12345678, 0x1234, 0x5678, 0x1234, 0x56789abcde01)); static const struct bt_uuid_128 met_char_uuid = BT_UUID_INIT_128( BT_UUID_128_ENCODE(0x12345678, 0x1234, 0x5678, 0x1234, 0x56789abcde02)); diff --git a/subsys/mgmt/mcumgr/transport/src/smp_bt.c b/subsys/mgmt/mcumgr/transport/src/smp_bt.c index 85377a12e2a..e646c80b35b 100644 --- a/subsys/mgmt/mcumgr/transport/src/smp_bt.c +++ b/subsys/mgmt/mcumgr/transport/src/smp_bt.c @@ -91,13 +91,13 @@ static struct conn_param_data conn_data[CONFIG_BT_MAX_CONN]; /* SMP service. * {8D53DC1D-1DB7-4CD3-868B-8A527460AA84} */ -static struct bt_uuid_128 smp_bt_svc_uuid = BT_UUID_INIT_128( +static const struct bt_uuid_128 smp_bt_svc_uuid = BT_UUID_INIT_128( BT_UUID_128_ENCODE(0x8d53dc1d, 0x1db7, 0x4cd3, 0x868b, 0x8a527460aa84)); /* SMP characteristic; used for both requests and responses. * {DA2E7828-FBCE-4E01-AE9E-261174997C48} */ -static struct bt_uuid_128 smp_bt_chr_uuid = BT_UUID_INIT_128( +static const struct bt_uuid_128 smp_bt_chr_uuid = BT_UUID_INIT_128( BT_UUID_128_ENCODE(0xda2e7828, 0xfbce, 0x4e01, 0xae9e, 0x261174997c48)); static void connected(struct bt_conn *conn, uint8_t err); diff --git a/subsys/net/l2/bluetooth/bluetooth.c b/subsys/net/l2/bluetooth/bluetooth.c index 8e7685c550f..984b02a62de 100644 --- a/subsys/net/l2/bluetooth/bluetooth.c +++ b/subsys/net/l2/bluetooth/bluetooth.c @@ -419,7 +419,7 @@ static bool eir_found(uint8_t type, const uint8_t *data, uint8_t data_len, } for (i = 0; i < data_len; i += sizeof(uint16_t)) { - struct bt_uuid *uuid; + const struct bt_uuid *uuid; uint16_t u16; memcpy(&u16, &data[i], sizeof(u16)); diff --git a/tests/bluetooth/gatt/src/main.c b/tests/bluetooth/gatt/src/main.c index d5c03272667..37a8c0d63dd 100644 --- a/tests/bluetooth/gatt/src/main.c +++ b/tests/bluetooth/gatt/src/main.c @@ -15,16 +15,16 @@ #include /* Custom Service Variables */ -static struct bt_uuid_128 test_uuid = BT_UUID_INIT_128( +static const struct bt_uuid_128 test_uuid = BT_UUID_INIT_128( 0xf0, 0xde, 0xbc, 0x9a, 0x78, 0x56, 0x34, 0x12, 0x78, 0x56, 0x34, 0x12, 0x78, 0x56, 0x34, 0x12); -static struct bt_uuid_128 test_chrc_uuid = BT_UUID_INIT_128( +static const struct bt_uuid_128 test_chrc_uuid = BT_UUID_INIT_128( 0xf2, 0xde, 0xbc, 0x9a, 0x78, 0x56, 0x34, 0x12, 0x78, 0x56, 0x34, 0x12, 0x78, 0x56, 0x34, 0x12); static uint8_t test_value[] = { 'T', 'e', 's', 't', '\0' }; -static struct bt_uuid_128 test1_uuid = BT_UUID_INIT_128( +static const struct bt_uuid_128 test1_uuid = BT_UUID_INIT_128( 0xf4, 0xde, 0xbc, 0x9a, 0x78, 0x56, 0x34, 0x12, 0x78, 0x56, 0x34, 0x12, 0x78, 0x56, 0x34, 0x12); diff --git a/tests/bluetooth/tester/src/btp_gatt.c b/tests/bluetooth/tester/src/btp_gatt.c index 6509ca7fe4b..f1a656c435f 100644 --- a/tests/bluetooth/tester/src/btp_gatt.c +++ b/tests/bluetooth/tester/src/btp_gatt.c @@ -2164,7 +2164,7 @@ static uint8_t notify_mult(const void *cmd, uint16_t cmd_len, struct get_attrs_foreach_data { struct net_buf_simple *buf; - struct bt_uuid *uuid; + const struct bt_uuid *uuid; uint8_t count; }; @@ -2353,7 +2353,7 @@ static uint8_t get_attr_val(const void *cmd, uint16_t cmd_len, return BTP_STATUS_FAILED; } -static struct bt_uuid_128 test_uuid = BT_UUID_INIT_128( +static const struct bt_uuid_128 test_uuid = BT_UUID_INIT_128( 0x94, 0x99, 0xb6, 0xa9, 0xcd, 0x1c, 0x42, 0x95, 0xb2, 0x07, 0x2f, 0x7f, 0xec, 0xc0, 0xc7, 0x5b); diff --git a/tests/bsim/bluetooth/audio/src/tmap_client_test.c b/tests/bsim/bluetooth/audio/src/tmap_client_test.c index 3b2fe69089b..4dbd8b9c5be 100644 --- a/tests/bsim/bluetooth/audio/src/tmap_client_test.c +++ b/tests/bsim/bluetooth/audio/src/tmap_client_test.c @@ -38,7 +38,7 @@ static bool check_audio_support_and_connect(struct bt_data *data, void *user_dat { bt_addr_le_t *addr = user_data; struct net_buf_simple tmas_svc_data; - struct bt_uuid *uuid; + const struct bt_uuid *uuid; uint16_t uuid_val; uint16_t peer_tmap_role = 0; int err; diff --git a/tests/bsim/bluetooth/host/att/eatt_notif/src/client_test.c b/tests/bsim/bluetooth/host/att/eatt_notif/src/client_test.c index 8b399c1c4c3..973400b16d2 100644 --- a/tests/bsim/bluetooth/host/att/eatt_notif/src/client_test.c +++ b/tests/bsim/bluetooth/host/att/eatt_notif/src/client_test.c @@ -27,7 +27,7 @@ CREATE_FLAG(flag_is_encrypted); static struct bt_conn *g_conn; static const struct bt_gatt_attr *local_attr; -static struct bt_uuid *test_svc_uuid = TEST_SERVICE_UUID; +static const struct bt_uuid *test_svc_uuid = TEST_SERVICE_UUID; #define NUM_NOTIF 100 #define SAMPLE_DATA 1 diff --git a/tests/bsim/bluetooth/host/gatt/ccc_store/src/peripheral.c b/tests/bsim/bluetooth/host/gatt/ccc_store/src/peripheral.c index 1fc2b0704de..3555e453d55 100644 --- a/tests/bsim/bluetooth/host/gatt/ccc_store/src/peripheral.c +++ b/tests/bsim/bluetooth/host/gatt/ccc_store/src/peripheral.c @@ -30,9 +30,10 @@ CREATE_FLAG(security_updated_flag); CREATE_FLAG(ccc_cfg_changed_flag); -static struct bt_uuid_128 dummy_service = BT_UUID_INIT_128(DUMMY_SERVICE_TYPE); +static const struct bt_uuid_128 dummy_service = BT_UUID_INIT_128(DUMMY_SERVICE_TYPE); -static struct bt_uuid_128 notify_characteristic_uuid = BT_UUID_INIT_128(DUMMY_SERVICE_NOTIFY_TYPE); +static const struct bt_uuid_128 notify_characteristic_uuid = + BT_UUID_INIT_128(DUMMY_SERVICE_NOTIFY_TYPE); static struct bt_conn *default_conn; diff --git a/tests/bsim/bluetooth/host/gatt/general/src/gatt_client_test.c b/tests/bsim/bluetooth/host/gatt/general/src/gatt_client_test.c index 3b535965209..b91929054a1 100644 --- a/tests/bsim/bluetooth/host/gatt/general/src/gatt_client_test.c +++ b/tests/bsim/bluetooth/host/gatt/general/src/gatt_client_test.c @@ -17,7 +17,7 @@ CREATE_FLAG(flag_read_complete); static struct bt_conn *g_conn; static uint16_t chrc_handle; static uint16_t long_chrc_handle; -static struct bt_uuid *test_svc_uuid = TEST_SERVICE_UUID; +static const struct bt_uuid *test_svc_uuid = TEST_SERVICE_UUID; #define ARRAY_ITEM(i, _) i static uint8_t chrc_data[] = { LISTIFY(CHRC_SIZE, ARRAY_ITEM, (,)) }; /* 1, 2, 3 ... */ diff --git a/tests/bsim/bluetooth/host/gatt/notify/src/gatt_client_test.c b/tests/bsim/bluetooth/host/gatt/notify/src/gatt_client_test.c index e31c275e62e..0331a469466 100644 --- a/tests/bsim/bluetooth/host/gatt/notify/src/gatt_client_test.c +++ b/tests/bsim/bluetooth/host/gatt/notify/src/gatt_client_test.c @@ -18,7 +18,7 @@ CREATE_FLAG(flag_long_subscribed); static struct bt_conn *g_conn; static uint16_t chrc_handle; static uint16_t long_chrc_handle; -static struct bt_uuid *test_svc_uuid = TEST_SERVICE_UUID; +static const struct bt_uuid *test_svc_uuid = TEST_SERVICE_UUID; static void connected(struct bt_conn *conn, uint8_t err) { diff --git a/tests/bsim/bluetooth/host/gatt/notify_multiple/src/gatt_client_test.c b/tests/bsim/bluetooth/host/gatt/notify_multiple/src/gatt_client_test.c index 7266fe98ed2..338045f63f9 100644 --- a/tests/bsim/bluetooth/host/gatt/notify_multiple/src/gatt_client_test.c +++ b/tests/bsim/bluetooth/host/gatt/notify_multiple/src/gatt_client_test.c @@ -20,7 +20,7 @@ static struct bt_conn *g_conn; static uint16_t chrc_handle; static uint16_t long_chrc_handle; static uint16_t csf_handle; -static struct bt_uuid *test_svc_uuid = TEST_SERVICE_UUID; +static const struct bt_uuid *test_svc_uuid = TEST_SERVICE_UUID; static void exchange_func(struct bt_conn *conn, uint8_t err, struct bt_gatt_exchange_params *params) { diff --git a/tests/bsim/bluetooth/host/gatt/settings/src/gatt_utils.c b/tests/bsim/bluetooth/host/gatt/settings/src/gatt_utils.c index abfcbcfafc8..db050848021 100644 --- a/tests/bsim/bluetooth/host/gatt/settings/src/gatt_utils.c +++ b/tests/bsim/bluetooth/host/gatt/settings/src/gatt_utils.c @@ -14,15 +14,15 @@ #include /* Custom Service Variables */ -static struct bt_uuid_128 test_svc_uuid = BT_UUID_INIT_128( +static const struct bt_uuid_128 test_svc_uuid = BT_UUID_INIT_128( 0xf0, 0xde, 0xbc, 0x9a, 0x78, 0x56, 0x34, 0x12, 0x78, 0x56, 0x34, 0x12, 0x78, 0x56, 0x34, 0x12); -static struct bt_uuid_128 test_svc_uuid_2 = BT_UUID_INIT_128( +static const struct bt_uuid_128 test_svc_uuid_2 = BT_UUID_INIT_128( 0xf1, 0xdd, 0xbc, 0x9a, 0x78, 0x56, 0x34, 0x12, 0x78, 0x56, 0x34, 0x12, 0x78, 0x56, 0x34, 0x12); -static struct bt_uuid_128 test_chrc_uuid = BT_UUID_INIT_128( +static const struct bt_uuid_128 test_chrc_uuid = BT_UUID_INIT_128( 0xf2, 0xde, 0xbc, 0x9a, 0x78, 0x56, 0x34, 0x12, 0x78, 0x56, 0x34, 0x12, 0x78, 0x56, 0x34, 0x12); diff --git a/tests/bsim/bluetooth/host/misc/disable/src/gatt_client_test.c b/tests/bsim/bluetooth/host/misc/disable/src/gatt_client_test.c index 91302380ef7..7fd32dccfca 100644 --- a/tests/bsim/bluetooth/host/misc/disable/src/gatt_client_test.c +++ b/tests/bsim/bluetooth/host/misc/disable/src/gatt_client_test.c @@ -17,7 +17,7 @@ CREATE_FLAG(flag_read_complete); static struct bt_conn *g_conn; static uint16_t chrc_handle; static uint16_t long_chrc_handle; -static struct bt_uuid *test_svc_uuid = TEST_SERVICE_UUID; +static const struct bt_uuid *test_svc_uuid = TEST_SERVICE_UUID; #define NUM_ITERATIONS 10 diff --git a/tests/bsim/bluetooth/host/security/ccc_update/src/peripheral.c b/tests/bsim/bluetooth/host/security/ccc_update/src/peripheral.c index ac6307dae6a..9813a6b0b60 100644 --- a/tests/bsim/bluetooth/host/security/ccc_update/src/peripheral.c +++ b/tests/bsim/bluetooth/host/security/ccc_update/src/peripheral.c @@ -31,9 +31,10 @@ CREATE_FLAG(security_updated_flag); CREATE_FLAG(ccc_cfg_changed_flag); -static struct bt_uuid_128 dummy_service = BT_UUID_INIT_128(DUMMY_SERVICE_TYPE); +static const struct bt_uuid_128 dummy_service = BT_UUID_INIT_128(DUMMY_SERVICE_TYPE); -static struct bt_uuid_128 notify_characteristic_uuid = BT_UUID_INIT_128(DUMMY_SERVICE_NOTIFY_TYPE); +static const struct bt_uuid_128 notify_characteristic_uuid = + BT_UUID_INIT_128(DUMMY_SERVICE_NOTIFY_TYPE); static struct bt_conn *default_conn; diff --git a/tests/bsim/bluetooth/ll/conn/src/test_connect1.c b/tests/bsim/bluetooth/ll/conn/src/test_connect1.c index 3b469585c84..795648c53cb 100644 --- a/tests/bsim/bluetooth/ll/conn/src/test_connect1.c +++ b/tests/bsim/bluetooth/ll/conn/src/test_connect1.c @@ -314,7 +314,7 @@ static bool eir_found(struct bt_data *data, void *user_data) } for (i = 0; i < data->data_len; i += sizeof(uint16_t)) { - struct bt_uuid *uuid; + const struct bt_uuid *uuid; struct bt_le_conn_param *param; uint16_t u16; int err; diff --git a/tests/bsim/bluetooth/ll/edtt/gatt_test_app/src/gatt/gatt_macs.h b/tests/bsim/bluetooth/ll/edtt/gatt_test_app/src/gatt/gatt_macs.h index 5c837ad110a..01e82571ebd 100644 --- a/tests/bsim/bluetooth/ll/edtt/gatt_test_app/src/gatt/gatt_macs.h +++ b/tests/bsim/bluetooth/ll/edtt/gatt_test_app/src/gatt/gatt_macs.h @@ -83,7 +83,7 @@ extern "C" { BT_GATT_PERM_READ, \ bt_gatt_attr_read_service, \ NULL, \ - _service, \ + (void *)_service, \ _handle) /** @@ -99,7 +99,7 @@ extern "C" { BT_GATT_PERM_READ, \ bt_gatt_attr_read_service, \ NULL, \ - _service, \ + (void *)_service, \ _handle) /** From 1106b86bdef291bb5391223017f36bc58ebbdf81 Mon Sep 17 00:00:00 2001 From: Lingao Meng Date: Wed, 6 Dec 2023 10:53:55 +0800 Subject: [PATCH 0898/3723] doc: release: Add migration for bluetooth uuid The Bluetooth UUID has been declare as rodata. Signed-off-by: Lingao Meng --- doc/releases/migration-guide-3.6.rst | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/doc/releases/migration-guide-3.6.rst b/doc/releases/migration-guide-3.6.rst index 059b487a921..bd37aa56fb1 100644 --- a/doc/releases/migration-guide-3.6.rst +++ b/doc/releases/migration-guide-3.6.rst @@ -183,6 +183,11 @@ Bluetooth * The Bluetooth Mesh ``element`` declaration has been changed to add prefix ``const``. The ``elem->addr`` field has been changed to the new runtime structure, replaced by ``elem->rt->addr``. (:github:`65388`) +* The Bluetooth UUID has been modified to rodata in ``BT_UUID_DECLARE_16``, ``BT_UUID_DECLARE_32` + and ``BT_UUID_DECLARE_128`` as the return value has been changed to `const`. + Any pointer to a UUID must be prefixed with `const`, otherwise there will be a compilation warning. + For example change ``struct bt_uuid *uuid = BT_UUID_DECLARE_16(xx)`` to + ``const struct bt_uuid *uuid = BT_UUID_DECLARE_16(xx)``. (:github:`66136`) LoRaWAN ======= From 5e08f73f7d54cec9e525fe16afef340c9f89bd96 Mon Sep 17 00:00:00 2001 From: Robert Baruch Date: Tue, 5 Dec 2023 14:49:52 -0500 Subject: [PATCH 0899/3723] samples: net: wifi: boards: added missing files for xiao_esp32c3 The conf and overlay files to properly compile the wifi samples were omitted for the Xiao_esp32c3 board. I've added those two files and confirmed that the sample properly compiles and runs. Signed-off-by: Robert Baruch --- samples/net/wifi/boards/xiao_esp32c3.conf | 11 +++++++++++ samples/net/wifi/boards/xiao_esp32c3.overlay | 9 +++++++++ 2 files changed, 20 insertions(+) create mode 100644 samples/net/wifi/boards/xiao_esp32c3.conf create mode 100644 samples/net/wifi/boards/xiao_esp32c3.overlay diff --git a/samples/net/wifi/boards/xiao_esp32c3.conf b/samples/net/wifi/boards/xiao_esp32c3.conf new file mode 100644 index 00000000000..a72fdf39efa --- /dev/null +++ b/samples/net/wifi/boards/xiao_esp32c3.conf @@ -0,0 +1,11 @@ +CONFIG_WIFI=y + +CONFIG_NETWORKING=y +CONFIG_NET_L2_ETHERNET=y + +CONFIG_NET_IPV6=n +CONFIG_NET_IPV4=y +CONFIG_NET_DHCPV4=y +CONFIG_ESP32_WIFI_STA_AUTO_DHCPV4=y + +CONFIG_NET_LOG=y diff --git a/samples/net/wifi/boards/xiao_esp32c3.overlay b/samples/net/wifi/boards/xiao_esp32c3.overlay new file mode 100644 index 00000000000..4d69fe29493 --- /dev/null +++ b/samples/net/wifi/boards/xiao_esp32c3.overlay @@ -0,0 +1,9 @@ +/* + * Copyright (c) 2023 Espressif Systems (Shanghai) Co., Ltd. + * + * SPDX-License-Identifier: Apache-2.0 + */ + +&wifi { + status = "okay"; +}; From 026908b7b823276d9cd3af9217ab51bc005441a6 Mon Sep 17 00:00:00 2001 From: Ederson de Souza Date: Mon, 28 Aug 2023 10:51:15 -0700 Subject: [PATCH 0900/3723] include/zephyr/net: Add 'brief' to group description So it doesn't extend previous directive. Signed-off-by: Ederson de Souza --- include/zephyr/net/wifi.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/include/zephyr/net/wifi.h b/include/zephyr/net/wifi.h index 5c7d5b493fa..be12a0961f6 100644 --- a/include/zephyr/net/wifi.h +++ b/include/zephyr/net/wifi.h @@ -12,7 +12,7 @@ /** * @defgroup wifi_mgmt Wi-Fi Management - * Wi-Fi Management API. + * @brief Wi-Fi Management API. * @ingroup networking * @{ */ From 28ff83515ddb30ded56c3b2ed0a6d84d07f67822 Mon Sep 17 00:00:00 2001 From: Dmitrii Golovanov Date: Wed, 29 Nov 2023 20:06:07 +0100 Subject: [PATCH 0901/3723] tests: drivers: coredump: Enable code coverage Enable code coverage for debug.coredump.drivers.api.* test suite adding custom fatal error handler to dump code coverage data when the test halts as expected. Signed-off-by: Dmitrii Golovanov --- tests/drivers/coredump/coredump_api/src/main.c | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) diff --git a/tests/drivers/coredump/coredump_api/src/main.c b/tests/drivers/coredump/coredump_api/src/main.c index abe30a8163d..ddac6d04585 100644 --- a/tests/drivers/coredump/coredump_api/src/main.c +++ b/tests/drivers/coredump/coredump_api/src/main.c @@ -22,12 +22,29 @@ #define TEST_MEMORY_VALUE_8 0xbabababa +#ifdef CONFIG_COVERAGE_DUMP +#include +#endif + static uint32_t values_to_dump[3]; static struct coredump_mem_region_node dump_region0 = { .start = (uintptr_t)&values_to_dump, .size = sizeof(values_to_dump) }; +void k_sys_fatal_error_handler(unsigned int reason, const z_arch_esf_t *pEsf) +{ + ARG_UNUSED(pEsf); + + printk("%s as expected; reason = %u; halting ...\n", __func__, reason); + +#ifdef CONFIG_COVERAGE_DUMP + gcov_coverage_dump(); /* LCOV_EXCL_LINE */ +#endif + k_fatal_halt(reason); +} + + static void test_coredump_callback(uintptr_t dump_area, size_t dump_area_size) { uint32_t expected_size = DT_PROP_BY_IDX(DT_NODELABEL(coredump_devicecb), memory_regions, 1); From 27d519b260b25826689a4e5283af8a7f188d121c Mon Sep 17 00:00:00 2001 From: Hake Huang Date: Wed, 6 Dec 2023 15:49:55 +0800 Subject: [PATCH 0902/3723] samples: logging: disable usermode for rtt platfroms Those platfroms using rtt as debug port, are conflicted with usermode. same with 163e9ba9a356e1a891dafd1c9c76449c3e4c913f Signed-off-by: Hake Huang --- samples/subsys/logging/logger/sample.yaml | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/samples/subsys/logging/logger/sample.yaml b/samples/subsys/logging/logger/sample.yaml index 2364dabd6b4..8ef962daeb9 100644 --- a/samples/subsys/logging/logger/sample.yaml +++ b/samples/subsys/logging/logger/sample.yaml @@ -32,6 +32,12 @@ tests: sample.logger.usermode: integration_platforms: - mps2_an385 + platform_exclude: + - ip_k66f + - bl652_dvk + - bl654_dvk + - decawave_dwm1001_dev + - segger_trb_stm32f407 arch_exclude: - posix tags: From f69641f7d204864aa26f8bdd9fecab259e535da2 Mon Sep 17 00:00:00 2001 From: Fabio Baltieri Date: Tue, 5 Dec 2023 16:28:59 +0000 Subject: [PATCH 0903/3723] input: gpio_kbd_matrix: do not enable interrupt if there's no callbacks Change the gpio_kbd_matrix_set_detect_mode to skip setting gpio interrupts if we don't have callbacks configured. This is the case if the driver is running in poll or scan mode. Signed-off-by: Fabio Baltieri --- drivers/input/input_gpio_kbd_matrix.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/drivers/input/input_gpio_kbd_matrix.c b/drivers/input/input_gpio_kbd_matrix.c index ccb7086c0c7..b869616a14f 100644 --- a/drivers/input/input_gpio_kbd_matrix.c +++ b/drivers/input/input_gpio_kbd_matrix.c @@ -143,6 +143,10 @@ static void gpio_kbd_matrix_set_detect_mode(const struct device *dev, bool enabl return; } + if (cfg->gpio_cb == NULL) { + return; + } + for (int i = 0; i < common->row_size; i++) { const struct gpio_dt_spec *gpio = &cfg->row_gpio[i]; From 8ab1c75e9b40e25f9f924f2f7f252857f08c9917 Mon Sep 17 00:00:00 2001 From: Maxmillion McLaughlin Date: Thu, 31 Aug 2023 15:40:59 -0600 Subject: [PATCH 0904/3723] feat: add support for TDK NTCG103JF103FT1 thermistor Adds compensation table and bindings for NTCG103JF103FT1 thermistor Signed-off-by: Maxmillion McLaughlin --- drivers/sensor/ntc_thermistor/Kconfig | 3 ++- .../sensor/ntc_thermistor/ntc_thermistor.c | 26 +++++++++++++++++++ dts/bindings/sensor/tdk,ntcg163jf103ft1.yaml | 8 ++++++ dts/bindings/vendor-prefixes.txt | 1 + tests/drivers/build_all/sensor/adc.dtsi | 9 +++++++ 5 files changed, 46 insertions(+), 1 deletion(-) create mode 100644 dts/bindings/sensor/tdk,ntcg163jf103ft1.yaml diff --git a/drivers/sensor/ntc_thermistor/Kconfig b/drivers/sensor/ntc_thermistor/Kconfig index 8ab04aaf184..140d324e9aa 100644 --- a/drivers/sensor/ntc_thermistor/Kconfig +++ b/drivers/sensor/ntc_thermistor/Kconfig @@ -7,7 +7,8 @@ config NTC_THERMISTOR default y depends on DT_HAS_NTC_THERMISTOR_GENERIC_ENABLED || \ DT_HAS_EPCOS_B57861S0103A039_ENABLED || \ - DT_HAS_MURATA_NCP15WB473_ENABLED + DT_HAS_MURATA_NCP15WB473_ENABLED || \ + DT_HAS_TDK_NTCG163JF103FT1_ENABLED select ADC help Enable driver for Zephyr NTC Thermistor. diff --git a/drivers/sensor/ntc_thermistor/ntc_thermistor.c b/drivers/sensor/ntc_thermistor/ntc_thermistor.c index 4f76ddc30f8..185e8c27673 100644 --- a/drivers/sensor/ntc_thermistor/ntc_thermistor.c +++ b/drivers/sensor/ntc_thermistor/ntc_thermistor.c @@ -217,3 +217,29 @@ static __unused const struct ntc_compensation comp_murata_ncp15wb473[] = { DT_INST_FOREACH_STATUS_OKAY_VARGS(NTC_THERMISTOR_DEFINE, DT_DRV_COMPAT, comp_murata_ncp15wb473) + +/* tdk,ntcg163jf103ft1 */ +#undef DT_DRV_COMPAT +#define DT_DRV_COMPAT tdk_ntcg163jf103ft1 + +static __unused const struct ntc_compensation comp_tdk_ntcg163jf103ft1[] = { + { -25, 86560 }, + { -15, 53460 }, + { -5, 33930 }, + { 5, 22070 }, + { 15, 14700 }, + { 25, 10000 }, + { 35, 6942 }, + { 45, 4911 }, + { 55, 3536 }, + { 65, 2588 }, + { 75, 1924 }, + { 85, 1451 }, + { 95, 1110 }, + { 105, 860 }, + { 115, 674 }, + { 125, 534 }, +}; + +DT_INST_FOREACH_STATUS_OKAY_VARGS(NTC_THERMISTOR_DEFINE, DT_DRV_COMPAT, + comp_tdk_ntcg163jf103ft1) diff --git a/dts/bindings/sensor/tdk,ntcg163jf103ft1.yaml b/dts/bindings/sensor/tdk,ntcg163jf103ft1.yaml new file mode 100644 index 00000000000..88883e14706 --- /dev/null +++ b/dts/bindings/sensor/tdk,ntcg163jf103ft1.yaml @@ -0,0 +1,8 @@ +# Copyright (c) 2023 Urban Sky LLC. +# SPDX-License-Identifier: Apache-2.0 + +description: TDK NTCG163JF103FT1 thermistor + +compatible: "tdk,ntcg163jf103ft1" + +include: ntc-thermistor.yaml diff --git a/dts/bindings/vendor-prefixes.txt b/dts/bindings/vendor-prefixes.txt index 29a7b78aa70..4096d5cad0d 100644 --- a/dts/bindings/vendor-prefixes.txt +++ b/dts/bindings/vendor-prefixes.txt @@ -606,6 +606,7 @@ tbs-biometrics Touchless Biometric Systems AG tcg Trusted Computing Group tcl Toby Churchill Ltd. tcs Shenzhen City Tang Cheng Technology Co., Ltd. +tdk TDK Corporation. tdo Shangai Top Display Optoelectronics Co., Ltd technexion TechNexion technologic Technologic Systems diff --git a/tests/drivers/build_all/sensor/adc.dtsi b/tests/drivers/build_all/sensor/adc.dtsi index e05c9bd0368..3ee9c2b8d42 100644 --- a/tests/drivers/build_all/sensor/adc.dtsi +++ b/tests/drivers/build_all/sensor/adc.dtsi @@ -70,3 +70,12 @@ test_murata_ncp15wb473: murata-ncp15wb473 { pulldown-ohm = <10000>; connected-positive; }; + +test_tdk_ntcg163jf103ft1: tdk-ntcg163jf103ft1 { + compatible = "tdk,ntcg163jf103ft1"; + io-channels = <&adc0 0>; + pullup-uv = <3300000>; + pullup-ohm = <0>; + pulldown-ohm = <10000>; + connected-positive; +}; From 203949c42ceeb7c76d82228a6997b5f8ef792ea2 Mon Sep 17 00:00:00 2001 From: Emil Gydesen Date: Wed, 22 Nov 2023 14:06:59 +0100 Subject: [PATCH 0905/3723] Bluetooth: VCP: Allow for multiple vol_ctrl cb registers Modify the VCP volume controller callbacks to support multiple registers by making it into a linked list. This allow for multiple applications to get the information from procedures or notifications. Signed-off-by: Emil Gydesen --- include/zephyr/bluetooth/audio/vcp.h | 18 +- subsys/bluetooth/audio/shell/vcp_vol_ctlr.c | 13 +- subsys/bluetooth/audio/vcp_vol_ctlr.c | 498 +++++++++++++------- tests/bluetooth/tester/src/btp_vcp.c | 9 +- 4 files changed, 360 insertions(+), 178 deletions(-) diff --git a/include/zephyr/bluetooth/audio/vcp.h b/include/zephyr/bluetooth/audio/vcp.h index f050786ab63..a902ceaed4d 100644 --- a/include/zephyr/bluetooth/audio/vcp.h +++ b/include/zephyr/bluetooth/audio/vcp.h @@ -353,6 +353,9 @@ struct bt_vcp_vol_ctlr_cb { /* Audio Input Control Service callbacks */ struct bt_aics_cb aics_cb; + + /** Internally used field for list handling */ + sys_snode_t _node; }; /** @@ -360,10 +363,23 @@ struct bt_vcp_vol_ctlr_cb { * * @param cb The callback structure. * - * @return 0 if success, errno on failure. + * @retval 0 on success + * @retval -EINVAL if @p cb is NULL + * @retval -EALREADY if @p cb was already registered */ int bt_vcp_vol_ctlr_cb_register(struct bt_vcp_vol_ctlr_cb *cb); +/** + * @brief Unregisters the callbacks used by the Volume Controller. + * + * @param cb The callback structure. + * + * @retval 0 on success + * @retval -EINVAL if @p cb is NULL + * @retval -EALREADY if @p cb was not registered + */ +int bt_vcp_vol_ctlr_cb_unregister(struct bt_vcp_vol_ctlr_cb *cb); + /** * @brief Discover Volume Control Service and included services. * diff --git a/subsys/bluetooth/audio/shell/vcp_vol_ctlr.c b/subsys/bluetooth/audio/shell/vcp_vol_ctlr.c index 2925d594280..38d0abb0915 100644 --- a/subsys/bluetooth/audio/shell/vcp_vol_ctlr.c +++ b/subsys/bluetooth/audio/shell/vcp_vol_ctlr.c @@ -326,16 +326,21 @@ static struct bt_vcp_vol_ctlr_cb vcp_cbs = { static int cmd_vcp_vol_ctlr_discover(const struct shell *sh, size_t argc, char **argv) { + static bool cb_registered; int result; if (!ctx_shell) { ctx_shell = sh; } - result = bt_vcp_vol_ctlr_cb_register(&vcp_cbs); - if (result != 0) { - shell_print(sh, "CB register failed: %d", result); - return result; + if (!cb_registered) { + result = bt_vcp_vol_ctlr_cb_register(&vcp_cbs); + if (result != 0) { + shell_print(sh, "CB register failed: %d", result); + return result; + } + + cb_registered = true; } if (default_conn == NULL) { diff --git a/subsys/bluetooth/audio/vcp_vol_ctlr.c b/subsys/bluetooth/audio/vcp_vol_ctlr.c index 3defcfbf917..4cc2af2762d 100644 --- a/subsys/bluetooth/audio/vcp_vol_ctlr.c +++ b/subsys/bluetooth/audio/vcp_vol_ctlr.c @@ -29,7 +29,7 @@ LOG_MODULE_REGISTER(bt_vcp_vol_ctlr, CONFIG_BT_VCP_VOL_CTLR_LOG_LEVEL); #include "common/bt_str.h" /* Callback functions */ -static struct bt_vcp_vol_ctlr_cb *vcp_vol_ctlr_cb; +static sys_slist_t vcp_vol_ctlr_cbs = SYS_SLIST_STATIC_INIT(&vcp_vol_ctlr_cbs); static struct bt_vcp_vol_ctlr vol_ctlr_insts[CONFIG_BT_MAX_CONN]; static int vcp_vol_ctlr_common_vcs_cp(struct bt_vcp_vol_ctlr *vol_ctlr, uint8_t opcode); @@ -39,6 +39,41 @@ static struct bt_vcp_vol_ctlr *vol_ctlr_get_by_conn(const struct bt_conn *conn) return &vol_ctlr_insts[bt_conn_index(conn)]; } +static void vcp_vol_ctlr_state_changed(struct bt_vcp_vol_ctlr *vol_ctlr, int err) +{ + struct bt_vcp_vol_ctlr_cb *listener, *next; + + SYS_SLIST_FOR_EACH_CONTAINER_SAFE(&vcp_vol_ctlr_cbs, listener, next, _node) { + if (listener->state) { + listener->state(vol_ctlr, err, err == 0 ? vol_ctlr->state.volume : 0, + err == 0 ? vol_ctlr->state.mute : 0); + } + } +} + +static void vcp_vol_ctlr_flags_changed(struct bt_vcp_vol_ctlr *vol_ctlr, int err) +{ + struct bt_vcp_vol_ctlr_cb *listener, *next; + + SYS_SLIST_FOR_EACH_CONTAINER_SAFE(&vcp_vol_ctlr_cbs, listener, next, _node) { + if (listener->flags) { + listener->flags(vol_ctlr, err, err == 0 ? vol_ctlr->flags : 0); + } + } +} + +static void vcp_vol_ctlr_discover_complete(struct bt_vcp_vol_ctlr *vol_ctlr, int err) +{ + struct bt_vcp_vol_ctlr_cb *listener, *next; + + SYS_SLIST_FOR_EACH_CONTAINER_SAFE(&vcp_vol_ctlr_cbs, listener, next, _node) { + if (listener->discover) { + listener->discover(vol_ctlr, err, err == 0 ? vol_ctlr->vocs_inst_cnt : 0, + err == 0 ? vol_ctlr->aics_inst_cnt : 0); + } + } +} + static uint8_t vcp_vol_ctlr_notify_handler(struct bt_conn *conn, struct bt_gatt_subscribe_params *params, const void *data, uint16_t length) @@ -58,17 +93,12 @@ static uint8_t vcp_vol_ctlr_notify_handler(struct bt_conn *conn, LOG_DBG("Volume %u, mute %u, counter %u", vol_ctlr->state.volume, vol_ctlr->state.mute, vol_ctlr->state.change_counter); - if (vcp_vol_ctlr_cb && vcp_vol_ctlr_cb->state) { - vcp_vol_ctlr_cb->state(vol_ctlr, 0, vol_ctlr->state.volume, - vol_ctlr->state.mute); - } + vcp_vol_ctlr_state_changed(vol_ctlr, 0); } else if (handle == vol_ctlr->flag_handle && length == sizeof(vol_ctlr->flags)) { memcpy(&vol_ctlr->flags, data, length); LOG_DBG("Flags %u", vol_ctlr->flags); - if (vcp_vol_ctlr_cb && vcp_vol_ctlr_cb->flags) { - vcp_vol_ctlr_cb->flags(vol_ctlr, 0, vol_ctlr->flags); - } + vcp_vol_ctlr_flags_changed(vol_ctlr, 0); } return BT_GATT_ITER_CONTINUE; @@ -99,15 +129,7 @@ static uint8_t vcp_vol_ctlr_read_vol_state_cb(struct bt_conn *conn, uint8_t err, } } - if (vcp_vol_ctlr_cb && vcp_vol_ctlr_cb->state) { - if (cb_err) { - vcp_vol_ctlr_cb->state(vol_ctlr, cb_err, 0, 0); - } else { - vcp_vol_ctlr_cb->state(vol_ctlr, cb_err, - vol_ctlr->state.volume, - vol_ctlr->state.mute); - } - } + vcp_vol_ctlr_state_changed(vol_ctlr, cb_err); return BT_GATT_ITER_STOP; } @@ -134,62 +156,58 @@ static uint8_t vcp_vol_ctlr_read_flag_cb(struct bt_conn *conn, uint8_t err, } } - if (vcp_vol_ctlr_cb && vcp_vol_ctlr_cb->flags) { - if (cb_err) { - vcp_vol_ctlr_cb->flags(vol_ctlr, cb_err, 0); - } else { - vcp_vol_ctlr_cb->flags(vol_ctlr, cb_err, vol_ctlr->flags); - } - } + vcp_vol_ctlr_flags_changed(vol_ctlr, cb_err); return BT_GATT_ITER_STOP; } static void vcs_cp_notify_app(struct bt_vcp_vol_ctlr *vol_ctlr, uint8_t opcode, int err) { - if (vcp_vol_ctlr_cb == NULL) { - return; - } + struct bt_vcp_vol_ctlr_cb *listener, *next; - switch (opcode) { - case BT_VCP_OPCODE_REL_VOL_DOWN: - if (vcp_vol_ctlr_cb->vol_down) { - vcp_vol_ctlr_cb->vol_down(vol_ctlr, err); - } - break; - case BT_VCP_OPCODE_REL_VOL_UP: - if (vcp_vol_ctlr_cb->vol_up) { - vcp_vol_ctlr_cb->vol_up(vol_ctlr, err); - } - break; - case BT_VCP_OPCODE_UNMUTE_REL_VOL_DOWN: - if (vcp_vol_ctlr_cb->vol_down_unmute) { - vcp_vol_ctlr_cb->vol_down_unmute(vol_ctlr, err); - } - break; - case BT_VCP_OPCODE_UNMUTE_REL_VOL_UP: - if (vcp_vol_ctlr_cb->vol_up_unmute) { - vcp_vol_ctlr_cb->vol_up_unmute(vol_ctlr, err); - } - break; - case BT_VCP_OPCODE_SET_ABS_VOL: - if (vcp_vol_ctlr_cb->vol_set) { - vcp_vol_ctlr_cb->vol_set(vol_ctlr, err); - } - break; - case BT_VCP_OPCODE_UNMUTE: - if (vcp_vol_ctlr_cb->unmute) { - vcp_vol_ctlr_cb->unmute(vol_ctlr, err); - } - break; - case BT_VCP_OPCODE_MUTE: - if (vcp_vol_ctlr_cb->mute) { - vcp_vol_ctlr_cb->mute(vol_ctlr, err); + LOG_DBG("%p opcode %u err %d", vol_ctlr, opcode, err); + + SYS_SLIST_FOR_EACH_CONTAINER_SAFE(&vcp_vol_ctlr_cbs, listener, next, _node) { + switch (opcode) { + case BT_VCP_OPCODE_REL_VOL_DOWN: + if (listener->vol_down) { + listener->vol_down(vol_ctlr, err); + } + break; + case BT_VCP_OPCODE_REL_VOL_UP: + if (listener->vol_up) { + listener->vol_up(vol_ctlr, err); + } + break; + case BT_VCP_OPCODE_UNMUTE_REL_VOL_DOWN: + if (listener->vol_down_unmute) { + listener->vol_down_unmute(vol_ctlr, err); + } + break; + case BT_VCP_OPCODE_UNMUTE_REL_VOL_UP: + if (listener->vol_up_unmute) { + listener->vol_up_unmute(vol_ctlr, err); + } + break; + case BT_VCP_OPCODE_SET_ABS_VOL: + if (listener->vol_set) { + listener->vol_set(vol_ctlr, err); + } + break; + case BT_VCP_OPCODE_UNMUTE: + if (listener->unmute) { + listener->unmute(vol_ctlr, err); + } + break; + case BT_VCP_OPCODE_MUTE: + if (listener->mute) { + listener->mute(vol_ctlr, err); + } + break; + default: + LOG_DBG("Unknown opcode 0x%02x", opcode); + break; } - break; - default: - LOG_DBG("Unknown opcode 0x%02x", opcode); - break; } } @@ -300,14 +318,7 @@ static uint8_t vcs_discover_include_func(struct bt_conn *conn, vol_ctlr->aics_inst_cnt, vol_ctlr->vocs_inst_cnt); (void)memset(params, 0, sizeof(*params)); - if (vcp_vol_ctlr_cb && vcp_vol_ctlr_cb->discover) { - /* - * TODO: Validate that all mandatory handles were found - */ - vcp_vol_ctlr_cb->discover(vol_ctlr, 0, - vol_ctlr->vocs_inst_cnt, - vol_ctlr->aics_inst_cnt); - } + vcp_vol_ctlr_discover_complete(vol_ctlr, 0); return BT_GATT_ITER_STOP; } @@ -339,10 +350,7 @@ static uint8_t vcs_discover_include_func(struct bt_conn *conn, ¶m); if (err != 0) { LOG_DBG("AICS Discover failed (err %d)", err); - if (vcp_vol_ctlr_cb && vcp_vol_ctlr_cb->discover) { - vcp_vol_ctlr_cb->discover(vol_ctlr, err, - 0, 0); - } + vcp_vol_ctlr_discover_complete(vol_ctlr, err); } return BT_GATT_ITER_STOP; @@ -367,10 +375,7 @@ static uint8_t vcs_discover_include_func(struct bt_conn *conn, ¶m); if (err != 0) { LOG_DBG("VOCS Discover failed (err %d)", err); - if (vcp_vol_ctlr_cb && vcp_vol_ctlr_cb->discover) { - vcp_vol_ctlr_cb->discover(vol_ctlr, err, - 0, 0); - } + vcp_vol_ctlr_discover_complete(vol_ctlr, err); } return BT_GATT_ITER_STOP; @@ -409,14 +414,10 @@ static uint8_t vcs_discover_func(struct bt_conn *conn, err = bt_gatt_discover(conn, &vol_ctlr->discover_params); if (err != 0) { LOG_DBG("Discover failed (err %d)", err); - if (vcp_vol_ctlr_cb && vcp_vol_ctlr_cb->discover) { - vcp_vol_ctlr_cb->discover(vol_ctlr, err, 0, 0); - } + vcp_vol_ctlr_discover_complete(vol_ctlr, err); } #else - if (vcp_vol_ctlr_cb && vcp_vol_ctlr_cb->discover) { - vcp_vol_ctlr_cb->discover(vol_ctlr, err, 0, 0); - } + vcp_vol_ctlr_discover_complete(vol_ctlr, err); #endif /* (CONFIG_BT_VCP_VOL_CTLR_MAX_AICS_INST > 0 || CONFIG_BT_VCP_VOL_CTLR_MAX_VOCS_INST > 0) */ return BT_GATT_ITER_STOP; @@ -476,9 +477,8 @@ static uint8_t primary_discover_func(struct bt_conn *conn, if (attr == NULL) { LOG_DBG("Could not find a vol_ctlr instance on the server"); - if (vcp_vol_ctlr_cb && vcp_vol_ctlr_cb->discover) { - vcp_vol_ctlr_cb->discover(vol_ctlr, -ENODATA, 0, 0); - } + vcp_vol_ctlr_discover_complete(vol_ctlr, -ENODATA); + return BT_GATT_ITER_STOP; } @@ -503,9 +503,7 @@ static uint8_t primary_discover_func(struct bt_conn *conn, err = bt_gatt_discover(conn, &vol_ctlr->discover_params); if (err != 0) { LOG_DBG("Discover failed (err %d)", err); - if (vcp_vol_ctlr_cb && vcp_vol_ctlr_cb->discover) { - vcp_vol_ctlr_cb->discover(vol_ctlr, err, 0, 0); - } + vcp_vol_ctlr_discover_complete(vol_ctlr, err); } return BT_GATT_ITER_STOP; @@ -567,20 +565,143 @@ static struct bt_vcp_vol_ctlr *lookup_vcp_by_aics(const struct bt_aics *aics) return NULL; } -static void aics_discover_cb(struct bt_aics *inst, int err) +static void vcp_vol_ctlr_aics_state_cb(struct bt_aics *inst, int err, int8_t gain, uint8_t mute, + uint8_t mode) +{ + struct bt_vcp_vol_ctlr_cb *listener, *next; + + SYS_SLIST_FOR_EACH_CONTAINER_SAFE(&vcp_vol_ctlr_cbs, listener, next, _node) { + if (listener->aics_cb.state) { + listener->aics_cb.state(inst, err, gain, mute, mode); + } + } +} + +static void vcp_vol_ctlr_aics_gain_setting_cb(struct bt_aics *inst, int err, uint8_t units, + int8_t minimum, int8_t maximum) +{ + struct bt_vcp_vol_ctlr_cb *listener, *next; + + SYS_SLIST_FOR_EACH_CONTAINER_SAFE(&vcp_vol_ctlr_cbs, listener, next, _node) { + if (listener->aics_cb.gain_setting) { + listener->aics_cb.gain_setting(inst, err, units, minimum, maximum); + } + } +} + +static void vcp_vol_ctlr_aics_type_cb(struct bt_aics *inst, int err, uint8_t type) +{ + struct bt_vcp_vol_ctlr_cb *listener, *next; + + SYS_SLIST_FOR_EACH_CONTAINER_SAFE(&vcp_vol_ctlr_cbs, listener, next, _node) { + if (listener->aics_cb.type) { + listener->aics_cb.type(inst, err, type); + } + } +} + +static void vcp_vol_ctlr_aics_status_cb(struct bt_aics *inst, int err, bool active) +{ + struct bt_vcp_vol_ctlr_cb *listener, *next; + + SYS_SLIST_FOR_EACH_CONTAINER_SAFE(&vcp_vol_ctlr_cbs, listener, next, _node) { + if (listener->aics_cb.status) { + listener->aics_cb.status(inst, err, active); + } + } +} + +static void vcp_vol_ctlr_aics_description_cb(struct bt_aics *inst, int err, char *description) +{ + struct bt_vcp_vol_ctlr_cb *listener, *next; + + SYS_SLIST_FOR_EACH_CONTAINER_SAFE(&vcp_vol_ctlr_cbs, listener, next, _node) { + if (listener->aics_cb.description) { + listener->aics_cb.description(inst, err, description); + } + } +} + +static void vcp_vol_ctlr_aics_discover_cb(struct bt_aics *inst, int err) { struct bt_vcp_vol_ctlr *vol_ctlr = lookup_vcp_by_aics(inst); + struct bt_vcp_vol_ctlr_cb *listener, *next; + + if (vol_ctlr == NULL) { + LOG_ERR("Could not lookup vol_ctlr from aics"); + vcp_vol_ctlr_discover_complete(vol_ctlr, BT_GATT_ERR(BT_ATT_ERR_UNLIKELY)); + + return; + } if (err == 0) { /* Continue discovery of included services */ - err = bt_gatt_discover(vol_ctlr->conn, - &vol_ctlr->discover_params); + err = bt_gatt_discover(vol_ctlr->conn, &vol_ctlr->discover_params); } if (err != 0) { LOG_DBG("Discover failed (err %d)", err); - if (vcp_vol_ctlr_cb && vcp_vol_ctlr_cb->discover) { - vcp_vol_ctlr_cb->discover(vol_ctlr, err, 0, 0); + vcp_vol_ctlr_discover_complete(vol_ctlr, err); + } + + SYS_SLIST_FOR_EACH_CONTAINER_SAFE(&vcp_vol_ctlr_cbs, listener, next, _node) { + if (listener->aics_cb.discover) { + listener->aics_cb.discover(inst, err); + } + } +} + +static void vcp_vol_ctlr_aics_set_gain_cb(struct bt_aics *inst, int err) +{ + struct bt_vcp_vol_ctlr_cb *listener, *next; + + SYS_SLIST_FOR_EACH_CONTAINER_SAFE(&vcp_vol_ctlr_cbs, listener, next, _node) { + if (listener->aics_cb.set_gain) { + listener->aics_cb.set_gain(inst, err); + } + } +} + +static void vcp_vol_ctlr_aics_unmute_cb(struct bt_aics *inst, int err) +{ + struct bt_vcp_vol_ctlr_cb *listener, *next; + + SYS_SLIST_FOR_EACH_CONTAINER_SAFE(&vcp_vol_ctlr_cbs, listener, next, _node) { + if (listener->aics_cb.unmute) { + listener->aics_cb.unmute(inst, err); + } + } +} + +static void vcp_vol_ctlr_aics_mute_cb(struct bt_aics *inst, int err) +{ + struct bt_vcp_vol_ctlr_cb *listener, *next; + + SYS_SLIST_FOR_EACH_CONTAINER_SAFE(&vcp_vol_ctlr_cbs, listener, next, _node) { + if (listener->aics_cb.mute) { + listener->aics_cb.mute(inst, err); + } + } +} + +static void vcp_vol_ctlr_aics_set_manual_mode_cb(struct bt_aics *inst, int err) +{ + struct bt_vcp_vol_ctlr_cb *listener, *next; + + SYS_SLIST_FOR_EACH_CONTAINER_SAFE(&vcp_vol_ctlr_cbs, listener, next, _node) { + if (listener->aics_cb.set_manual_mode) { + listener->aics_cb.set_manual_mode(inst, err); + } + } +} + +static void vcp_vol_ctlr_aics_set_auto_mode_cb(struct bt_aics *inst, int err) +{ + struct bt_vcp_vol_ctlr_cb *listener, *next; + + SYS_SLIST_FOR_EACH_CONTAINER_SAFE(&vcp_vol_ctlr_cbs, listener, next, _node) { + if (listener->aics_cb.set_auto_mode) { + listener->aics_cb.set_auto_mode(inst, err); } } } @@ -602,32 +723,75 @@ static struct bt_vcp_vol_ctlr *lookup_vcp_by_vocs(const struct bt_vocs *vocs) return NULL; } -static void vocs_discover_cb(struct bt_vocs *inst, int err) +static void vcp_vol_ctlr_vocs_state_cb(struct bt_vocs *inst, int err, int16_t offset) +{ + struct bt_vcp_vol_ctlr_cb *listener, *next; + + SYS_SLIST_FOR_EACH_CONTAINER_SAFE(&vcp_vol_ctlr_cbs, listener, next, _node) { + if (listener->vocs_cb.state) { + listener->vocs_cb.state(inst, err, offset); + } + } +} + +static void vcp_vol_ctlr_vocs_location_cb(struct bt_vocs *inst, int err, uint32_t location) +{ + struct bt_vcp_vol_ctlr_cb *listener, *next; + + SYS_SLIST_FOR_EACH_CONTAINER_SAFE(&vcp_vol_ctlr_cbs, listener, next, _node) { + if (listener->vocs_cb.location) { + listener->vocs_cb.location(inst, err, location); + } + } +} + +static void vcp_vol_ctlr_vocs_description_cb(struct bt_vocs *inst, int err, char *description) +{ + struct bt_vcp_vol_ctlr_cb *listener, *next; + + SYS_SLIST_FOR_EACH_CONTAINER_SAFE(&vcp_vol_ctlr_cbs, listener, next, _node) { + if (listener->vocs_cb.description) { + listener->vocs_cb.description(inst, err, description); + } + } +} + +static void vcp_vol_ctlr_vocs_discover_cb(struct bt_vocs *inst, int err) { struct bt_vcp_vol_ctlr *vol_ctlr = lookup_vcp_by_vocs(inst); + struct bt_vcp_vol_ctlr_cb *listener, *next; if (vol_ctlr == NULL) { LOG_ERR("Could not lookup vol_ctlr from vocs"); - - if (vcp_vol_ctlr_cb && vcp_vol_ctlr_cb->discover) { - vcp_vol_ctlr_cb->discover(vol_ctlr, - BT_GATT_ERR(BT_ATT_ERR_UNLIKELY), - 0, 0); - } + vcp_vol_ctlr_discover_complete(vol_ctlr, BT_GATT_ERR(BT_ATT_ERR_UNLIKELY)); return; } if (err == 0) { /* Continue discovery of included services */ - err = bt_gatt_discover(vol_ctlr->conn, - &vol_ctlr->discover_params); + err = bt_gatt_discover(vol_ctlr->conn, &vol_ctlr->discover_params); } if (err != 0) { LOG_DBG("Discover failed (err %d)", err); - if (vcp_vol_ctlr_cb && vcp_vol_ctlr_cb->discover) { - vcp_vol_ctlr_cb->discover(vol_ctlr, err, 0, 0); + vcp_vol_ctlr_discover_complete(vol_ctlr, err); + } + + SYS_SLIST_FOR_EACH_CONTAINER_SAFE(&vcp_vol_ctlr_cbs, listener, next, _node) { + if (listener->vocs_cb.discover) { + listener->vocs_cb.discover(inst, err); + } + } +} + +static void vcp_vol_ctlr_vocs_set_offset_cb(struct bt_vocs *inst, int err) +{ + struct bt_vcp_vol_ctlr_cb *listener, *next; + + SYS_SLIST_FOR_EACH_CONTAINER_SAFE(&vcp_vol_ctlr_cbs, listener, next, _node) { + if (listener->vocs_cb.set_offset) { + listener->vocs_cb.set_offset(inst, err); } } } @@ -679,37 +843,53 @@ BT_CONN_CB_DEFINE(conn_callbacks) = { static void bt_vcp_vol_ctlr_init(void) { - int i, j; +#if defined(CONFIG_BT_VCP_VOL_CTLR_VOCS) + for (size_t i = 0U; i < ARRAY_SIZE(vol_ctlr_insts); i++) { + for (size_t j = 0U; j < ARRAY_SIZE(vol_ctlr_insts[i].vocs); j++) { + static struct bt_vocs_cb vocs_cb = { + .state = vcp_vol_ctlr_vocs_state_cb, + .location = vcp_vol_ctlr_vocs_location_cb, + .description = vcp_vol_ctlr_vocs_description_cb, + .discover = vcp_vol_ctlr_vocs_discover_cb, + .set_offset = vcp_vol_ctlr_vocs_set_offset_cb, + }; - if (IS_ENABLED(CONFIG_BT_VOCS_CLIENT) && - CONFIG_BT_VCP_VOL_CTLR_MAX_VOCS_INST > 0) { - for (i = 0; i < ARRAY_SIZE(vol_ctlr_insts); i++) { - for (j = 0; j < ARRAY_SIZE(vol_ctlr_insts[i].vocs); j++) { - vol_ctlr_insts[i].vocs[j] = bt_vocs_client_free_instance_get(); + vol_ctlr_insts[i].vocs[j] = bt_vocs_client_free_instance_get(); - __ASSERT(vol_ctlr_insts[i].vocs[j], - "Could not allocate VOCS client instance"); + __ASSERT(vol_ctlr_insts[i].vocs[j], + "Could not allocate VOCS client instance"); - bt_vocs_client_cb_register(vol_ctlr_insts[i].vocs[j], - &vcp_vol_ctlr_cb->vocs_cb); - } + bt_vocs_client_cb_register(vol_ctlr_insts[i].vocs[j], &vocs_cb); } } +#endif /* CONFIG_BT_VCP_VOL_CTLR_VOCS */ - if (IS_ENABLED(CONFIG_BT_AICS_CLIENT) && - CONFIG_BT_VCP_VOL_CTLR_MAX_AICS_INST > 0) { - for (i = 0; i < ARRAY_SIZE(vol_ctlr_insts); i++) { - for (j = 0; j < ARRAY_SIZE(vol_ctlr_insts[i].aics); j++) { - vol_ctlr_insts[i].aics[j] = bt_aics_client_free_instance_get(); +#if defined(CONFIG_BT_VCP_VOL_CTLR_AICS) + for (size_t i = 0U; i < ARRAY_SIZE(vol_ctlr_insts); i++) { + for (size_t j = 0U; j < ARRAY_SIZE(vol_ctlr_insts[i].aics); j++) { + static struct bt_aics_cb aics_cb = { + .state = vcp_vol_ctlr_aics_state_cb, + .gain_setting = vcp_vol_ctlr_aics_gain_setting_cb, + .type = vcp_vol_ctlr_aics_type_cb, + .status = vcp_vol_ctlr_aics_status_cb, + .description = vcp_vol_ctlr_aics_description_cb, + .discover = vcp_vol_ctlr_aics_discover_cb, + .set_gain = vcp_vol_ctlr_aics_set_gain_cb, + .unmute = vcp_vol_ctlr_aics_unmute_cb, + .mute = vcp_vol_ctlr_aics_mute_cb, + .set_manual_mode = vcp_vol_ctlr_aics_set_manual_mode_cb, + .set_auto_mode = vcp_vol_ctlr_aics_set_auto_mode_cb, + }; - __ASSERT(vol_ctlr_insts[i].aics[j], - "Could not allocate AICS client instance"); + vol_ctlr_insts[i].aics[j] = bt_aics_client_free_instance_get(); - bt_aics_client_cb_register(vol_ctlr_insts[i].aics[j], - &vcp_vol_ctlr_cb->aics_cb); - } + __ASSERT(vol_ctlr_insts[i].aics[j], + "Could not allocate AICS client instance"); + + bt_aics_client_cb_register(vol_ctlr_insts[i].aics[j], &aics_cb); } } +#endif /* CONFIG_BT_VCP_VOL_CTLR_AICS */ } int bt_vcp_vol_ctlr_discover(struct bt_conn *conn, struct bt_vcp_vol_ctlr **out_vol_ctlr) @@ -769,59 +949,33 @@ int bt_vcp_vol_ctlr_discover(struct bt_conn *conn, struct bt_vcp_vol_ctlr **out_ int bt_vcp_vol_ctlr_cb_register(struct bt_vcp_vol_ctlr_cb *cb) { -#if defined(CONFIG_BT_VCP_VOL_CTLR_VOCS) - struct bt_vocs_cb *vocs_cb = NULL; - - if (cb != NULL) { - /* Ensure that the cb->vocs_cb.discover is the vocs_discover_cb */ - CHECKIF(cb->vocs_cb.discover != NULL && - cb->vocs_cb.discover != vocs_discover_cb) { - LOG_ERR("VOCS discover callback shall not be set"); - return -EINVAL; - } - cb->vocs_cb.discover = vocs_discover_cb; + struct bt_vcp_vol_ctlr_cb *tmp; - vocs_cb = &cb->vocs_cb; + CHECKIF(cb == NULL) { + return -EINVAL; } - for (int i = 0; i < ARRAY_SIZE(vol_ctlr_insts); i++) { - for (int j = 0; j < ARRAY_SIZE(vol_ctlr_insts[i].vocs); j++) { - struct bt_vocs *vocs = vol_ctlr_insts[i].vocs[j]; - - if (vocs != NULL) { - bt_vocs_client_cb_register(vocs, vocs_cb); - } + SYS_SLIST_FOR_EACH_CONTAINER(&vcp_vol_ctlr_cbs, tmp, _node) { + if (tmp == cb) { + LOG_DBG("Already registered"); + return -EALREADY; } } -#endif /* CONFIG_BT_VCP_VOL_CTLR_VOCS */ -#if defined(CONFIG_BT_VCP_VOL_CTLR_AICS) - struct bt_aics_cb *aics_cb = NULL; + sys_slist_append(&vcp_vol_ctlr_cbs, &cb->_node); - if (cb != NULL) { - /* Ensure that the cb->aics_cb.discover is the aics_discover_cb */ - CHECKIF(cb->aics_cb.discover != NULL && - cb->aics_cb.discover != aics_discover_cb) { - LOG_ERR("AICS discover callback shall not be set"); - return -EINVAL; - } - cb->aics_cb.discover = aics_discover_cb; + return 0; +} - aics_cb = &cb->aics_cb; +int bt_vcp_vol_ctlr_cb_unregister(struct bt_vcp_vol_ctlr_cb *cb) +{ + CHECKIF(cb == NULL) { + return -EINVAL; } - for (int i = 0; i < ARRAY_SIZE(vol_ctlr_insts); i++) { - for (int j = 0; j < ARRAY_SIZE(vol_ctlr_insts[i].aics); j++) { - struct bt_aics *aics = vol_ctlr_insts[i].aics[j]; - - if (aics != NULL) { - bt_aics_client_cb_register(aics, aics_cb); - } - } + if (!sys_slist_find_and_remove(&vcp_vol_ctlr_cbs, &cb->_node)) { + return -EALREADY; } -#endif /* CONFIG_BT_VCP_VOL_CTLR_AICS */ - - vcp_vol_ctlr_cb = cb; return 0; } diff --git a/tests/bluetooth/tester/src/btp_vcp.c b/tests/bluetooth/tester/src/btp_vcp.c index 04e82c35807..1f3bd1b9203 100644 --- a/tests/bluetooth/tester/src/btp_vcp.c +++ b/tests/bluetooth/tester/src/btp_vcp.c @@ -1024,6 +1024,13 @@ uint8_t tester_init_vcp(void) uint8_t tester_unregister_vcp(void) { - (void)bt_vcp_vol_ctlr_cb_register(NULL); + int err; + + err = bt_vcp_vol_ctlr_cb_unregister(&vcp_cbs); + if (err != 0) { + LOG_DBG("Failed to unregister callbacks: %d", err); + return BTP_STATUS_FAILED; + } + return BTP_STATUS_SUCCESS; } From 339d0ac4a560ec98fca5ea393a74fcb7d96c4836 Mon Sep 17 00:00:00 2001 From: Andrei Emeltchenko Date: Thu, 23 Nov 2023 11:20:30 +0200 Subject: [PATCH 0906/3723] tests: btp_mcp: Fix dead code warning Remove return statement preventing to return error code. Signed-off-by: Andrei Emeltchenko --- tests/bluetooth/tester/src/btp_mcp.c | 1 - 1 file changed, 1 deletion(-) diff --git a/tests/bluetooth/tester/src/btp_mcp.c b/tests/bluetooth/tester/src/btp_mcp.c index b044c035c06..a31a5be30a6 100644 --- a/tests/bluetooth/tester/src/btp_mcp.c +++ b/tests/bluetooth/tester/src/btp_mcp.c @@ -404,7 +404,6 @@ static void mcc_discover_cb(struct bt_conn *conn, int err) if (err) { LOG_DBG("Discovery failed (%d)", err); - return; } mcc_inst = lookup_inst_by_conn(conn); From 643984c4326a9983f9ee3801a89ec12ae32af0fc Mon Sep 17 00:00:00 2001 From: Jordan Yates Date: Fri, 8 Dec 2023 11:57:23 +1100 Subject: [PATCH 0907/3723] pm: device_runtime: don't assert in ISR put Don't assert that `pm_device_runtime_get` is not running in an ISR context, as `runtime_suspend` properly handles that condition. Signed-off-by: Jordan Yates --- subsys/pm/device_runtime.c | 2 -- 1 file changed, 2 deletions(-) diff --git a/subsys/pm/device_runtime.c b/subsys/pm/device_runtime.c index dbb19c6926b..56f0b066a91 100644 --- a/subsys/pm/device_runtime.c +++ b/subsys/pm/device_runtime.c @@ -214,8 +214,6 @@ int pm_device_runtime_put(const struct device *dev) { int ret; - __ASSERT(!k_is_in_isr(), "use pm_device_runtime_put_async() in ISR"); - if (dev->pm == NULL) { return 0; } From 405b8b5f1980515d5fba6eaa0f61a97c4a7c9e91 Mon Sep 17 00:00:00 2001 From: Jukka Rissanen Date: Mon, 4 Dec 2023 14:33:16 +0200 Subject: [PATCH 0908/3723] net: context: Add docs for getter/setter of TTL/hoplimit values The IPv4 TTL and IPv6 hop limit value getter and setter functions were not documented properly. Signed-off-by: Jukka Rissanen --- include/zephyr/net/net_context.h | 83 ++++++++++++++++++++++++++++++-- 1 file changed, 79 insertions(+), 4 deletions(-) diff --git a/include/zephyr/net/net_context.h b/include/zephyr/net/net_context.h index 937cc9cf2a7..fc37cfa5264 100644 --- a/include/zephyr/net/net_context.h +++ b/include/zephyr/net/net_context.h @@ -349,12 +349,12 @@ __net_socket struct net_context { /** IPv6 hop limit or IPv4 ttl for packets sent via this context. */ union { struct { - uint8_t ipv6_hop_limit; - uint8_t ipv6_mcast_hop_limit; + uint8_t ipv6_hop_limit; /**< IPv6 hop limit */ + uint8_t ipv6_mcast_hop_limit; /**< IPv6 multicast hop limit */ }; struct { - uint8_t ipv4_ttl; - uint8_t ipv4_mcast_ttl; + uint8_t ipv4_ttl; /**< IPv4 TTL */ + uint8_t ipv4_mcast_ttl; /**< IPv4 multicast TTL */ }; }; @@ -698,44 +698,119 @@ static inline void net_context_bind_iface(struct net_context *context, net_context_set_iface(context, iface); } +/** + * @brief Get IPv4 TTL (time-to-live) value for this context. + * + * @details This function returns the IPv4 TTL (time-to-live) value that is + * set to this context. + * + * @param context Network context. + * + * @return IPv4 TTL value + */ static inline uint8_t net_context_get_ipv4_ttl(struct net_context *context) { return context->ipv4_ttl; } +/** + * @brief Set IPv4 TTL (time-to-live) value for this context. + * + * @details This function sets the IPv4 TTL (time-to-live) value for + * this context. + * + * @param context Network context. + * @param ttl IPv4 time-to-live value. + */ static inline void net_context_set_ipv4_ttl(struct net_context *context, uint8_t ttl) { context->ipv4_ttl = ttl; } +/** + * @brief Get IPv4 multicast TTL (time-to-live) value for this context. + * + * @details This function returns the IPv4 multicast TTL (time-to-live) value + * that is set to this context. + * + * @param context Network context. + * + * @return IPv4 multicast TTL value + */ static inline uint8_t net_context_get_ipv4_mcast_ttl(struct net_context *context) { return context->ipv4_mcast_ttl; } +/** + * @brief Set IPv4 multicast TTL (time-to-live) value for this context. + * + * @details This function sets the IPv4 multicast TTL (time-to-live) value for + * this context. + * + * @param context Network context. + * @param ttl IPv4 multicast time-to-live value. + */ static inline void net_context_set_ipv4_mcast_ttl(struct net_context *context, uint8_t ttl) { context->ipv4_mcast_ttl = ttl; } +/** + * @brief Get IPv6 hop limit value for this context. + * + * @details This function returns the IPv6 hop limit value that is set to this + * context. + * + * @param context Network context. + * + * @return IPv6 hop limit value + */ static inline uint8_t net_context_get_ipv6_hop_limit(struct net_context *context) { return context->ipv6_hop_limit; } +/** + * @brief Set IPv6 hop limit value for this context. + * + * @details This function sets the IPv6 hop limit value for this context. + * + * @param context Network context. + * @param hop_limit IPv6 hop limit value. + */ static inline void net_context_set_ipv6_hop_limit(struct net_context *context, uint8_t hop_limit) { context->ipv6_hop_limit = hop_limit; } +/** + * @brief Get IPv6 multicast hop limit value for this context. + * + * @details This function returns the IPv6 multicast hop limit value + * that is set to this context. + * + * @param context Network context. + * + * @return IPv6 multicast hop limit value + */ static inline uint8_t net_context_get_ipv6_mcast_hop_limit(struct net_context *context) { return context->ipv6_mcast_hop_limit; } +/** + * @brief Set IPv6 multicast hop limit value for this context. + * + * @details This function sets the IPv6 multicast hop limit value for + * this context. + * + * @param context Network context. + * @param hop_limit IPv6 multicast hop limit value. + */ static inline void net_context_set_ipv6_mcast_hop_limit(struct net_context *context, uint8_t hop_limit) { From 039c6a304deca9fedfd074881f72afe458dacd3c Mon Sep 17 00:00:00 2001 From: Jukka Rissanen Date: Mon, 4 Dec 2023 14:52:20 +0200 Subject: [PATCH 0909/3723] net: context: Document socks proxy settings Documentation for socks proxy was missing. Signed-off-by: Jukka Rissanen --- include/zephyr/net/net_context.h | 32 +++++++++++++++++++++++++++----- 1 file changed, 27 insertions(+), 5 deletions(-) diff --git a/include/zephyr/net/net_context.h b/include/zephyr/net/net_context.h index fc37cfa5264..c578597807e 100644 --- a/include/zephyr/net/net_context.h +++ b/include/zephyr/net/net_context.h @@ -303,6 +303,7 @@ __net_socket struct net_context { bool txtime; #endif #if defined(CONFIG_SOCKS) + /** Socks proxy address */ struct { struct sockaddr addr; socklen_t addrlen; @@ -817,17 +818,21 @@ static inline void net_context_set_ipv6_mcast_hop_limit(struct net_context *cont context->ipv6_mcast_hop_limit = hop_limit; } +/** + * @brief Enable or disable socks proxy support for this context. + * + * @details This function either enables or disables socks proxy support for + * this context. + * + * @param context Network context. + * @param enable Enable socks proxy or disable it. + */ #if defined(CONFIG_SOCKS) static inline void net_context_set_proxy_enabled(struct net_context *context, bool enable) { context->proxy_enabled = enable; } - -static inline bool net_context_is_proxy_enabled(struct net_context *context) -{ - return context->proxy_enabled; -} #else static inline void net_context_set_proxy_enabled(struct net_context *context, bool enable) @@ -835,7 +840,24 @@ static inline void net_context_set_proxy_enabled(struct net_context *context, ARG_UNUSED(context); ARG_UNUSED(enable); } +#endif +/** + * @brief Is socks proxy support enabled or disabled for this context. + * + * @details This function returns current socks proxy status for + * this context. + * + * @param context Network context. + * + * @return True if socks proxy is enabled for this context, False otherwise + */ +#if defined(CONFIG_SOCKS) +static inline bool net_context_is_proxy_enabled(struct net_context *context) +{ + return context->proxy_enabled; +} +#else static inline bool net_context_is_proxy_enabled(struct net_context *context) { return false; From 825bc325d29229039999e476166417222b7ee2a1 Mon Sep 17 00:00:00 2001 From: Jukka Rissanen Date: Mon, 4 Dec 2023 14:53:02 +0200 Subject: [PATCH 0910/3723] net: context: Document misc settings and functions Various misc settings and functions were not documented so fix it. Signed-off-by: Jukka Rissanen --- include/zephyr/net/net_context.h | 28 ++++++++++++++++++++++++++++ 1 file changed, 28 insertions(+) diff --git a/include/zephyr/net/net_context.h b/include/zephyr/net/net_context.h index c578597807e..55548917c45 100644 --- a/include/zephyr/net/net_context.h +++ b/include/zephyr/net/net_context.h @@ -300,6 +300,7 @@ __net_socket struct net_context { uint8_t priority; #endif #if defined(CONFIG_NET_CONTEXT_TXTIME) + /** When to send the packet out */ bool txtime; #endif #if defined(CONFIG_SOCKS) @@ -310,30 +311,42 @@ __net_socket struct net_context { } proxy; #endif #if defined(CONFIG_NET_CONTEXT_RCVTIMEO) + /** Receive timeout */ k_timeout_t rcvtimeo; #endif #if defined(CONFIG_NET_CONTEXT_SNDTIMEO) + /** Send timeout */ k_timeout_t sndtimeo; #endif #if defined(CONFIG_NET_CONTEXT_RCVBUF) + /** Receive buffer maximum size */ uint16_t rcvbuf; #endif #if defined(CONFIG_NET_CONTEXT_SNDBUF) + /** Send buffer maximum size */ uint16_t sndbuf; #endif #if defined(CONFIG_NET_CONTEXT_DSCP_ECN) + /** + * DSCP (Differentiated Services Code point) and + * ECN (Explicit Congestion Notification) values. + */ uint8_t dscp_ecn; #endif #if defined(CONFIG_NET_CONTEXT_REUSEADDR) + /** Re-use address (SO_REUSEADDR) flag on a socket. */ bool reuseaddr; #endif #if defined(CONFIG_NET_CONTEXT_REUSEPORT) + /** Re-use port (SO_REUSEPORT) flag on a socket. */ bool reuseport; #endif #if defined(CONFIG_NET_IPV4_MAPPING_TO_IPV6) + /** Support v4-mapped-on-v6 addresses */ bool ipv6_v6only; #endif #if defined(CONFIG_NET_CONTEXT_RECV_PKTINFO) + /** Receive network packet information in recvmsg() call */ bool recv_pktinfo; #endif } options; @@ -360,11 +373,19 @@ __net_socket struct net_context { }; #if defined(CONFIG_SOCKS) + /** Is socks proxy enabled */ bool proxy_enabled; #endif }; +/** + * @brief Is this context used or not. + * + * @param context Network context. + * + * @return True if the context is currently in use, False otherwise. + */ static inline bool net_context_is_used(struct net_context *context) { NET_ASSERT(context); @@ -372,6 +393,13 @@ static inline bool net_context_is_used(struct net_context *context) return context->flags & NET_CONTEXT_IN_USE; } +/** + * @brief Is this context bound to a network interface. + * + * @param context Network context. + * + * @return True if the context is bound to network interface, False otherwise. + */ static inline bool net_context_is_bound_to_iface(struct net_context *context) { NET_ASSERT(context); From 8f2b7a121bbf7b64fdf46c5c19231a12f96c4166 Mon Sep 17 00:00:00 2001 From: Przemyslaw Bida Date: Tue, 5 Dec 2023 13:48:37 +0100 Subject: [PATCH 0911/3723] net: openthread: Openthread upmerge to `4ed44bc` This commit bumps openthread commit to `4ed44bc` and implements `CONFIG_OPENTHREAD_MULTIPAN_RCP` option. Signed-off-by: Przemyslaw Bida --- modules/openthread/CMakeLists.txt | 6 ++++++ modules/openthread/Kconfig.features | 3 +++ west.yml | 2 +- 3 files changed, 10 insertions(+), 1 deletion(-) diff --git a/modules/openthread/CMakeLists.txt b/modules/openthread/CMakeLists.txt index 94351a38d6d..56bebc32c29 100644 --- a/modules/openthread/CMakeLists.txt +++ b/modules/openthread/CMakeLists.txt @@ -334,6 +334,12 @@ else() set(OT_MLR OFF CACHE BOOL "Enable Multicast Listener Registration feature for Thread 1.2" FORCE) endif() +if(CONFIG_OPENTHREAD_MULTIPAN_RCP) + set(OT_MULTIPAN_RCP ON CACHE BOOL "Enable Multi-PAN RCP" FORCE) +else() + set(OT_MULTIPAN_RCP OFF CACHE BOOL "Enable Multi-PAN RCP" FORCE) +endif() + if(CONFIG_OPENTHREAD_MULTIPLE_INSTANCE) set(OT_MULTIPLE_INSTANCE ON CACHE BOOL "Enable multiple instances" FORCE) else() diff --git a/modules/openthread/Kconfig.features b/modules/openthread/Kconfig.features index 36ce7615e35..927be23e187 100644 --- a/modules/openthread/Kconfig.features +++ b/modules/openthread/Kconfig.features @@ -214,6 +214,9 @@ config OPENTHREAD_MLR help Enable Multicast Listener Registration support for Thread 1.2 +config OPENTHREAD_MULTIPAN_RCP + bool "OpenThread multipan rcp" + config OPENTHREAD_MULTIPLE_INSTANCE bool "OpenThread multiple instances" diff --git a/west.yml b/west.yml index e31e126f361..a15c617d11c 100644 --- a/west.yml +++ b/west.yml @@ -301,7 +301,7 @@ manifest: revision: 214f9fc1539f8e5937c0474cb6ee29b6dcb2d4b8 path: modules/lib/open-amp - name: openthread - revision: 75694d2860282d216d7286f3956388e957c7cfb5 + revision: 4ed44bc7d58d9a98c6cca13a50d38129045ab3df path: modules/lib/openthread - name: percepio path: modules/debug/percepio From 304b98391cc2c41f24b591f72da29c13a1786766 Mon Sep 17 00:00:00 2001 From: Przemyslaw Bida Date: Tue, 5 Dec 2023 16:13:06 +0100 Subject: [PATCH 0912/3723] net: openthread: Add openthread TCAT implementation. MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This commit adds bbtc implementation. New file in modules/openthread/platform/ble.c New corresponding kconfig option `OPENTHREAD_BLE_TCAT`. Co-authored-by: Piotr Jasiński Signed-off-by: Przemyslaw Bida Signed-off-by: Piotr Jasiński --- modules/openthread/CMakeLists.txt | 6 + modules/openthread/Kconfig.features | 4 + modules/openthread/Kconfig.thread | 12 + modules/openthread/platform/CMakeLists.txt | 1 + modules/openthread/platform/ble.c | 458 +++++++++++++++++++++ 5 files changed, 481 insertions(+) create mode 100644 modules/openthread/platform/ble.c diff --git a/modules/openthread/CMakeLists.txt b/modules/openthread/CMakeLists.txt index 56bebc32c29..150039863d9 100644 --- a/modules/openthread/CMakeLists.txt +++ b/modules/openthread/CMakeLists.txt @@ -58,6 +58,12 @@ else() set(OT_BACKBONE_ROUTER_MULTICAST_ROUTING OFF CACHE BOOL "Enable BBR MR support" FORCE) endif() +if(CONFIG_OPENTHREAD_BLE_TCAT) + set(OT_BLE_TCAT ON CACHE BOOL "Enable BLE TCAT support" FORCE) +else() + set(OT_BLE_TCAT OFF CACHE BOOL "Enable BLE TCAT support" FORCE) +endif() + if(CONFIG_OPENTHREAD_BORDER_AGENT) set(OT_BORDER_AGENT ON CACHE BOOL "Enable Border Agent" FORCE) else() diff --git a/modules/openthread/Kconfig.features b/modules/openthread/Kconfig.features index 927be23e187..952a7853b43 100644 --- a/modules/openthread/Kconfig.features +++ b/modules/openthread/Kconfig.features @@ -39,6 +39,10 @@ config OPENTHREAD_BACKBONE_ROUTER_DUA_NDPROXYING config OPENTHREAD_BACKBONE_ROUTER_MULTICAST_ROUTING bool "BBR MR support" +config OPENTHREAD_BLE_TCAT + bool "BLE TCAT support" + select EXPERIMENTAL + config OPENTHREAD_BORDER_AGENT bool "Border Agent support" diff --git a/modules/openthread/Kconfig.thread b/modules/openthread/Kconfig.thread index 891365b4672..66e039b7300 100644 --- a/modules/openthread/Kconfig.thread +++ b/modules/openthread/Kconfig.thread @@ -181,3 +181,15 @@ config OPENTHREAD_DEFAULT_TX_POWER default 0 help Set the default TX output power [dBm] in radio driver for OpenThread purpose. + +config OPENTHREAD_BLE_TCAT_THREAD_STACK_SIZE + int "Openthread default TCAT stack size" + default 4200 + help + Openthread default TCAT stack size. + +config OPENTHREAD_BLE_TCAT_RING_BUF_SIZE + int "Openthread BLE ringbuffer size" + default 512 + help + Openthread BLE TCAT ringbuffer size. diff --git a/modules/openthread/platform/CMakeLists.txt b/modules/openthread/platform/CMakeLists.txt index d363bcda7df..542aa5186ea 100644 --- a/modules/openthread/platform/CMakeLists.txt +++ b/modules/openthread/platform/CMakeLists.txt @@ -10,6 +10,7 @@ zephyr_library_sources( spi.c ) +zephyr_library_sources_ifdef(CONFIG_OPENTHREAD_BLE_TCAT ble.c) zephyr_library_sources_ifdef(CONFIG_OPENTHREAD_DIAG diag.c) zephyr_library_sources_ifdef(CONFIG_OPENTHREAD_COPROCESSOR uart.c) zephyr_library_sources_ifdef(CONFIG_OPENTHREAD_CRYPTO_PSA crypto_psa.c) diff --git a/modules/openthread/platform/ble.c b/modules/openthread/platform/ble.c new file mode 100644 index 00000000000..7b41556b617 --- /dev/null +++ b/modules/openthread/platform/ble.c @@ -0,0 +1,458 @@ +/* + * Copyright (c) 2023 Nordic Semiconductor ASA + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include +#include +#include + +#include +#include +#include +#include + +#include +#include +#include +#include +#include + +/* Zephyr OpenThread integration Library */ +#include + +/* OpenThread BLE driver API */ +#include + +/* Zephyr Logging */ + +#define LOG_MODULE_NAME net_openthread_tcat +#define LOG_LEVEL CONFIG_OPENTHREAD_LOG_LEVEL + +LOG_MODULE_REGISTER(LOG_MODULE_NAME); + +#define DEVICE_NAME CONFIG_BT_DEVICE_NAME +#define DEVICE_NAME_LEN (sizeof(DEVICE_NAME) - 1) + +/* BLE connection constants as defined in thread specification. */ +#define TOBLE_SERVICE_UUID 0xfffb +#define RX_CHARACTERISTIC_UUID \ + BT_UUID_128_ENCODE(0x6bd10d8b, 0x85a7, 0x4e5a, 0xba2d, 0xc83558a5f220) +#define TX_CHARACTERISTIC_UUID \ + BT_UUID_128_ENCODE(0x7fddf61f, 0x280a, 0x4773, 0xb448, 0xba1b8fe0dd69) + +#define BT_UUID_TCAT_SERVICE BT_UUID_DECLARE_16(TOBLE_SERVICE_UUID) +#define BT_UUID_TCAT_SERVICE_RX BT_UUID_DECLARE_128(RX_CHARACTERISTIC_UUID) +#define BT_UUID_TCAT_SERVICE_TX BT_UUID_DECLARE_128(TX_CHARACTERISTIC_UUID) + +#define PLAT_BLE_THREAD_DEALY 500 +#define PLAT_BLE_MSG_DATA_MAX CONFIG_BT_L2CAP_TX_MTU /* must match the maximum MTU size used */ + +#define PLAT_BLE_MSG_CONNECT (PLAT_BLE_MSG_DATA_MAX + 1U) +#define PLAT_BLE_MSG_DISCONNECT (PLAT_BLE_MSG_CONNECT + 1U) + +/* Zephyr Kernel Objects */ + +static void ot_plat_ble_thread(void *, void *, void *); +static uint8_t ot_plat_ble_msg_buf[PLAT_BLE_MSG_DATA_MAX]; + +static K_SEM_DEFINE(ot_plat_ble_init_semaphore, 0, 1); +static K_SEM_DEFINE(ot_plat_ble_event_semaphore, 0, K_SEM_MAX_LIMIT); +RING_BUF_DECLARE(ot_plat_ble_ring_buf, CONFIG_OPENTHREAD_BLE_TCAT_RING_BUF_SIZE); +static K_THREAD_DEFINE(ot_plat_ble_tid, CONFIG_OPENTHREAD_BLE_TCAT_THREAD_STACK_SIZE, + ot_plat_ble_thread, NULL, NULL, NULL, 5, 0, PLAT_BLE_THREAD_DEALY); + +/* OpenThread Objects */ + +static otInstance *ble_openthread_instance; + +/* BLE service Objects */ + +/* forward declaration for callback functions */ +static ssize_t on_receive(struct bt_conn *conn, const struct bt_gatt_attr *attr, const void *buf, + uint16_t len, uint16_t offset, uint8_t flags); +static void on_cccd_changed(const struct bt_gatt_attr *attr, uint16_t value); + +/* Service Declaration and Registration */ +BT_GATT_SERVICE_DEFINE(my_service, BT_GATT_PRIMARY_SERVICE(BT_UUID_TCAT_SERVICE), + BT_GATT_CHARACTERISTIC(BT_UUID_TCAT_SERVICE_RX, + BT_GATT_CHRC_WRITE | BT_GATT_CHRC_WRITE_WITHOUT_RESP, + BT_GATT_PERM_READ | BT_GATT_PERM_WRITE, NULL, + on_receive, NULL), + BT_GATT_CHARACTERISTIC(BT_UUID_TCAT_SERVICE_TX, BT_GATT_CHRC_NOTIFY, + BT_GATT_PERM_READ, NULL, NULL, NULL), + BT_GATT_CCC(on_cccd_changed, BT_GATT_PERM_READ | BT_GATT_PERM_WRITE),); + +/* Zephyr BLE Objects */ + +/* forward declaration for callback functions */ +static void connected(struct bt_conn *conn, uint8_t err); +static void disconnected(struct bt_conn *conn, uint8_t reason); +static bool le_param_req(struct bt_conn *conn, struct bt_le_conn_param *param); +static void le_param_updated(struct bt_conn *conn, uint16_t interval, uint16_t latency, + uint16_t timeout); + +static struct bt_conn *ot_plat_ble_connection; + +static struct bt_conn_cb conn_callbacks = {.connected = connected, + .disconnected = disconnected, + .le_param_req = le_param_req, + .le_param_updated = le_param_updated}; + +static const struct bt_data ad[] = { + BT_DATA_BYTES(BT_DATA_FLAGS, (BT_LE_AD_GENERAL | BT_LE_AD_NO_BREDR)), + BT_DATA(BT_DATA_NAME_COMPLETE, DEVICE_NAME, DEVICE_NAME_LEN), +}; + +static const struct bt_data sd[] = { + BT_DATA_BYTES(BT_DATA_UUID16_ALL, BT_UUID_16_ENCODE(TOBLE_SERVICE_UUID)), +}; + +/* Zephyr BLE Message Queue and Thread */ + +static bool ot_plat_ble_queue_msg(const uint8_t *aData, uint16_t aLen, int8_t aRssi) +{ + otError error = OT_ERROR_NONE; + uint16_t len = 0; + + if (aLen <= PLAT_BLE_MSG_DATA_MAX && aData == NULL) { + return OT_ERROR_INVALID_ARGS; + } + + k_sched_lock(); + + len = sizeof(aLen) + sizeof(aRssi) + ((aLen <= PLAT_BLE_MSG_DATA_MAX) ? aLen : 0); + + if (ring_buf_space_get(&ot_plat_ble_ring_buf) >= len) { + ring_buf_put(&ot_plat_ble_ring_buf, (uint8_t *)&aLen, sizeof(aLen)); + ring_buf_put(&ot_plat_ble_ring_buf, &aRssi, sizeof(aRssi)); + if (aLen <= PLAT_BLE_MSG_DATA_MAX) { + ring_buf_put(&ot_plat_ble_ring_buf, aData, aLen); + } + k_sem_give(&ot_plat_ble_event_semaphore); + } else { + error = OT_ERROR_NO_BUFS; + } + + k_sched_unlock(); + + return error; +} + +static void ot_plat_ble_thread(void *unused1, void *unused2, void *unused3) +{ + ARG_UNUSED(unused1); + ARG_UNUSED(unused2); + ARG_UNUSED(unused3); + + uint16_t len; + int8_t rssi; + otBleRadioPacket my_packet; + + LOG_INF("%s started", __func__); + + while (1) { + k_sem_take(&ot_plat_ble_event_semaphore, K_FOREVER); + ring_buf_get(&ot_plat_ble_ring_buf, (uint8_t *)&len, sizeof(len)); + ring_buf_get(&ot_plat_ble_ring_buf, &rssi, sizeof(rssi)); + if (len <= PLAT_BLE_MSG_DATA_MAX) { + ring_buf_get(&ot_plat_ble_ring_buf, ot_plat_ble_msg_buf, len); + } + + openthread_api_mutex_lock(openthread_get_default_context()); + + if (len <= PLAT_BLE_MSG_DATA_MAX) { + /* The packet parameter in otPlatBleGattServerOnWriteRequest is not const. + * Re-write all members. + */ + my_packet.mValue = ot_plat_ble_msg_buf; + my_packet.mPower = rssi; + my_packet.mLength = len; + otPlatBleGattServerOnWriteRequest(ble_openthread_instance, 0, &my_packet); + } else if (len == PLAT_BLE_MSG_CONNECT) { + otPlatBleGapOnConnected(ble_openthread_instance, 0); + } else if (len == PLAT_BLE_MSG_DISCONNECT) { + otPlatBleGapOnDisconnected(ble_openthread_instance, 0); + } + openthread_api_mutex_unlock(openthread_get_default_context()); + } +} + +/* Zephyr BLE service callbacks */ + +/* This function is called whenever the RX Characteristic has been written to by a Client */ +static ssize_t on_receive(struct bt_conn *conn, const struct bt_gatt_attr *attr, const void *buf, + uint16_t len, uint16_t offset, uint8_t flags) +{ + LOG_DBG("Received data, handle %" PRIu16 ", len %" PRIu16, attr->handle, len); + + otError error = ot_plat_ble_queue_msg(buf, len, 0); + + if (error != OT_ERROR_NONE) { + LOG_WRN("Error queuing message: %s", otThreadErrorToString(error)); + } + + return len; +} + +/* This function is called whenever a Notification has been sent by the TX Characteristic */ +static void on_sent(struct bt_conn *conn, void *user_data) +{ + ARG_UNUSED(conn); + ARG_UNUSED(user_data); + + LOG_DBG("Data sent"); +} + +/* This function is called whenever the CCCD register has been changed by the client */ +void on_cccd_changed(const struct bt_gatt_attr *attr, uint16_t value) +{ + uint16_t mtu; + otError error = OT_ERROR_NONE; + + ARG_UNUSED(attr); + + switch (value) { + case BT_GATT_CCC_NOTIFY: + + error = ot_plat_ble_queue_msg(NULL, PLAT_BLE_MSG_CONNECT, 0); + if (error != OT_ERROR_NONE) { + LOG_WRN("Error queuing message: %s", otThreadErrorToString(error)); + } + + error = otPlatBleGattMtuGet(ble_openthread_instance, &mtu); + if (error != OT_ERROR_NONE) { + LOG_WRN("Error retrieving mtu: %s", otThreadErrorToString(error)); + } + + LOG_INF("CCCD update (mtu=%" PRIu16 ")!", mtu); + + break; + + default: + break; + } +} + +otError otPlatBleGattServerIndicate(otInstance *aInstance, uint16_t aHandle, + const otBleRadioPacket *aPacket) +{ + ARG_UNUSED(aInstance); + + /* TO DO change to indications. */ + const struct bt_gatt_attr *attr = &my_service.attrs[3]; + + struct bt_gatt_notify_params params = {.uuid = BT_UUID_TCAT_SERVICE_TX, + .attr = attr, + .data = aPacket->mValue, + .len = aPacket->mLength, + .func = on_sent}; + + LOG_DBG("Send data, handle %d, len %d", attr->handle, aPacket->mLength); + + /* Only one connection supported */ + if (aHandle != 0) { + return OT_ERROR_INVALID_ARGS; + } + + if (ot_plat_ble_connection == NULL) { + return OT_ERROR_INVALID_STATE; + } + + /* Check whether notifications are enabled or not */ + if (bt_gatt_is_subscribed(ot_plat_ble_connection, attr, BT_GATT_CCC_NOTIFY)) { + if (bt_gatt_notify_cb(ot_plat_ble_connection, ¶ms)) { + LOG_WRN("Error, unable to send notification"); + return OT_ERROR_INVALID_ARGS; + } + } else { + LOG_WRN("Warning, notification not enabled on the selected attribute"); + return OT_ERROR_INVALID_STATE; + } + + return OT_ERROR_NONE; +} + +otError otPlatBleGattMtuGet(otInstance *aInstance, uint16_t *aMtu) +{ + ARG_UNUSED(aInstance); + + if (ot_plat_ble_connection == NULL) { + return OT_ERROR_FAILED; + } + + if (aMtu != NULL) { + *aMtu = bt_gatt_get_mtu(ot_plat_ble_connection); + } + + return OT_ERROR_NONE; +} + +otError otPlatBleGapDisconnect(otInstance *aInstance) +{ + ARG_UNUSED(aInstance); + + if (ot_plat_ble_connection == NULL) { + return OT_ERROR_INVALID_STATE; + } + + if (bt_conn_disconnect(ot_plat_ble_connection, BT_HCI_ERR_REMOTE_USER_TERM_CONN)) { + return OT_ERROR_INVALID_STATE; + } + + return OT_ERROR_NONE; +} + +/* Zephyr BLE callbacks */ + +static void connected(struct bt_conn *conn, uint8_t err) +{ + struct bt_conn_info info; + char addr[BT_ADDR_LE_STR_LEN]; + uint16_t mtu; + otError error = OT_ERROR_NONE; + + ot_plat_ble_connection = bt_conn_ref(conn); + + if (err) { + LOG_WRN("Connection failed (err %u)", err); + return; + } else if (bt_conn_get_info(conn, &info)) { + LOG_WRN("Could not parse connection info"); + } else { + bt_addr_le_to_str(bt_conn_get_dst(conn), addr, sizeof(addr)); + + error = otPlatBleGattMtuGet(ble_openthread_instance, &mtu); + if (error != OT_ERROR_NONE) { + LOG_WRN("Error retrieving mtu: %s", otThreadErrorToString(error)); + } + + LOG_INF("Connection established (mtu=%" PRIu16 ")!", mtu); + } +} + +static void disconnected(struct bt_conn *conn, uint8_t reason) +{ + otError error = OT_ERROR_NONE; + + LOG_INF("Disconnected (reason %" PRIu8 ")", reason); + + if (ot_plat_ble_connection) { + bt_conn_unref(ot_plat_ble_connection); + ot_plat_ble_connection = NULL; + + error = ot_plat_ble_queue_msg(NULL, PLAT_BLE_MSG_DISCONNECT, 0); + if (error != OT_ERROR_NONE) { + LOG_WRN("Error queuing message: %s", otThreadErrorToString(error)); + } + } +} + +static bool le_param_req(struct bt_conn *conn, struct bt_le_conn_param *param) +{ + return true; +} + +static void le_param_updated(struct bt_conn *conn, uint16_t interval, uint16_t latency, + uint16_t timeout) +{ + struct bt_conn_info info; + char addr[BT_ADDR_LE_STR_LEN]; + uint16_t mtu; + otError error = OT_ERROR_NONE; + + if (bt_conn_get_info(conn, &info)) { + LOG_INF("Could not parse connection info"); + } else { + bt_addr_le_to_str(bt_conn_get_dst(conn), addr, sizeof(addr)); + + error = otPlatBleGattMtuGet(ble_openthread_instance, &mtu); + + if (error != OT_ERROR_NONE) { + LOG_WRN("Error retrieving mtu: %s", otThreadErrorToString(error)); + } + + LOG_INF("Connection parameters updated (mtu=%" PRIu16 ")!", mtu); + } +} + +static void bt_ready(int err) +{ + if (err) { + LOG_WRN("BLE init failed with error code %d", err); + return; + } + + bt_conn_cb_register(&conn_callbacks); + k_sem_give(&ot_plat_ble_init_semaphore); /* BLE stack up an running */ +} + +otError otPlatBleGapAdvStart(otInstance *aInstance, uint16_t aInterval) +{ + ARG_UNUSED(aInstance); + ARG_UNUSED(aInterval); + + /* TO DO advertisement format change */ + int err = bt_le_adv_start(BT_LE_ADV_CONN, ad, ARRAY_SIZE(ad), sd, ARRAY_SIZE(sd)); + + if (err != 0 && err != -EALREADY) { + LOG_WRN("Advertising failed to start (err %d)", err); + return OT_ERROR_INVALID_STATE; + } + + LOG_INF("Advertising successfully started"); + + return OT_ERROR_NONE; +} + +otError otPlatBleGapAdvStop(otInstance *aInstance) +{ + ARG_UNUSED(aInstance); + + int err = bt_le_adv_stop(); + + if (err != 0 && err != -EALREADY) { + LOG_WRN("Advertisement failed to stop (err %d)", err); + return OT_ERROR_FAILED; + } + return OT_ERROR_NONE; +} + +/* Zephyr BLE initialization */ + +otError otPlatBleEnable(otInstance *aInstance) +{ + int err; + + ble_openthread_instance = aInstance; + err = bt_enable(bt_ready); + + if (err != 0 && err != -EALREADY) { + LOG_WRN("BLE enable failed with error code %d", err); + return OT_ERROR_FAILED; + } else if (err == -EALREADY) { + err = k_sem_take(&ot_plat_ble_init_semaphore, K_MSEC(500)); + return OT_ERROR_NONE; + } + + err = k_sem_take(&ot_plat_ble_init_semaphore, K_MSEC(500)); + + if (!err) { + LOG_INF("Bluetooth initialized"); + } else { + LOG_INF("BLE initialization did not complete in time"); + return OT_ERROR_FAILED; + } + + return OT_ERROR_NONE; +} + +otError otPlatBleDisable(otInstance *aInstance) +{ + ARG_UNUSED(aInstance); + /* This function intentionally does nothing since disabling advertisement disables BLE + * stack. + */ + return OT_ERROR_NONE; +} From 6aa242cdfb8165104858aa8d857e2a8bc3ff4b70 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Manuel=20Arg=C3=BCelles?= Date: Tue, 5 Dec 2023 19:29:42 +0700 Subject: [PATCH 0913/3723] soc: arm: nxp_s32: s32k1: fix code cache init MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Currently Code Cache cannot be enabled because its initialization is guarded by Kconfig options which depend on CPU core cache support, but S32K14x devices has a SoC specific L1 cache controller. Hence, introduce a SoC-specific symbol to enable Code Cache. Note that the cache controller is not available for S32K11x devices. Signed-off-by: Manuel Argüelles --- soc/arm/nxp_s32/s32k1/Kconfig.soc | 11 +++++++++++ soc/arm/nxp_s32/s32k1/soc.c | 2 +- 2 files changed, 12 insertions(+), 1 deletion(-) diff --git a/soc/arm/nxp_s32/s32k1/Kconfig.soc b/soc/arm/nxp_s32/s32k1/Kconfig.soc index dd1cdf77538..78caf49f677 100644 --- a/soc/arm/nxp_s32/s32k1/Kconfig.soc +++ b/soc/arm/nxp_s32/s32k1/Kconfig.soc @@ -20,36 +20,42 @@ config SOC_S32K142 select CPU_CORTEX_M4 select CPU_CORTEX_M_HAS_DWT select CPU_HAS_FPU + select HAS_MCUX_CACHE config SOC_S32K142W bool "S32K142W" select CPU_CORTEX_M4 select CPU_CORTEX_M_HAS_DWT select CPU_HAS_FPU + select HAS_MCUX_CACHE config SOC_S32K144 bool "S32K144" select CPU_CORTEX_M4 select CPU_CORTEX_M_HAS_DWT select CPU_HAS_FPU + select HAS_MCUX_CACHE config SOC_S32K144W bool "S32K144W" select CPU_CORTEX_M4 select CPU_CORTEX_M_HAS_DWT select CPU_HAS_FPU + select HAS_MCUX_CACHE config SOC_S32K146 bool "S32K146" select CPU_CORTEX_M4 select CPU_CORTEX_M_HAS_DWT select CPU_HAS_FPU + select HAS_MCUX_CACHE config SOC_S32K148 bool "S32K148" select CPU_CORTEX_M4 select CPU_CORTEX_M_HAS_DWT select CPU_HAS_FPU + select HAS_MCUX_CACHE endchoice @@ -431,4 +437,9 @@ config NXP_S32_FLASH_CONFIG_FDPROT endif # NXP_S32_FLASH_CONFIG +config NXP_S32_ENABLE_CODE_CACHE + bool "Code cache" + default y + depends on HAS_MCUX_CACHE + endif # SOC_SERIES_S32K1XX diff --git a/soc/arm/nxp_s32/s32k1/soc.c b/soc/arm/nxp_s32/s32k1/soc.c index 8c73b4fa6f5..175b6fe6442 100644 --- a/soc/arm/nxp_s32/s32k1/soc.c +++ b/soc/arm/nxp_s32/s32k1/soc.c @@ -63,7 +63,7 @@ static int soc_init(void) IP_MPU->CESR = tmp; #endif /* !CONFIG_ARM_MPU */ -#if defined(CONFIG_DCACHE) && defined(CONFIG_ICACHE) +#if defined(CONFIG_HAS_MCUX_CACHE) && defined(CONFIG_NXP_S32_ENABLE_CODE_CACHE) /* Invalidate all ways */ IP_LMEM->PCCCR |= LMEM_PCCCR_INVW1_MASK | LMEM_PCCCR_INVW0_MASK; IP_LMEM->PCCCR |= LMEM_PCCCR_GO_MASK; From 0ee663296773add0491140e99a8961cbece6399b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Manuel=20Arg=C3=BCelles?= Date: Tue, 5 Dec 2023 19:35:12 +0700 Subject: [PATCH 0914/3723] soc: arm: nxp_s32: s32k1: use HAL to init code cache MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Use the HAL cache driver to initialize the Code Cache. Signed-off-by: Manuel Argüelles --- soc/arm/nxp_s32/s32k1/soc.c | 16 +++++----------- west.yml | 2 +- 2 files changed, 6 insertions(+), 12 deletions(-) diff --git a/soc/arm/nxp_s32/s32k1/soc.c b/soc/arm/nxp_s32/s32k1/soc.c index 175b6fe6442..50cff147846 100644 --- a/soc/arm/nxp_s32/s32k1/soc.c +++ b/soc/arm/nxp_s32/s32k1/soc.c @@ -15,6 +15,10 @@ #include #include +#if defined(CONFIG_HAS_MCUX_CACHE) +#include +#endif + #if defined(CONFIG_WDOG_INIT) #define WDOG_UPDATE_KEY 0xD928C520U @@ -64,17 +68,7 @@ static int soc_init(void) #endif /* !CONFIG_ARM_MPU */ #if defined(CONFIG_HAS_MCUX_CACHE) && defined(CONFIG_NXP_S32_ENABLE_CODE_CACHE) - /* Invalidate all ways */ - IP_LMEM->PCCCR |= LMEM_PCCCR_INVW1_MASK | LMEM_PCCCR_INVW0_MASK; - IP_LMEM->PCCCR |= LMEM_PCCCR_GO_MASK; - - /* Wait until the command completes */ - while (IP_LMEM->PCCCR & LMEM_PCCCR_GO_MASK) { - ; - } - - /* Enable cache */ - IP_LMEM->PCCCR |= (LMEM_PCCCR_ENCACHE_MASK); + L1CACHE_EnableCodeCache(); barrier_isync_fence_full(); #endif diff --git a/west.yml b/west.yml index a15c617d11c..b721d93327e 100644 --- a/west.yml +++ b/west.yml @@ -193,7 +193,7 @@ manifest: groups: - hal - name: hal_nxp - revision: d0c424e1c6ef0acac3099a07280a46a24951a47a + revision: 1b2f3608ab0d5f2cf2a4c2973ae9f6353fb43e72 path: modules/hal/nxp groups: - hal From 0e73c225bb5492678b719d390589d22ad74ec6da Mon Sep 17 00:00:00 2001 From: Jaroslaw Stelter Date: Tue, 5 Dec 2023 14:36:06 +0100 Subject: [PATCH 0915/3723] drivers: ssp: Reverted CPA check condition There is reverted CPA check condition in routines: dai_ssp_pm_runtime_en_ssp_power() dai_ssp_pm_runtime_dis_ssp_power() In result disable always timeouts while enable returns before CPA bit set. This cause sporadic exceptions on HW. Signed-off-by: Jaroslaw Stelter --- drivers/dai/intel/ssp/ssp.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/drivers/dai/intel/ssp/ssp.c b/drivers/dai/intel/ssp/ssp.c index 34f93ff01d6..4b8f6e00742 100644 --- a/drivers/dai/intel/ssp/ssp.c +++ b/drivers/dai/intel/ssp/ssp.c @@ -723,7 +723,7 @@ static void dai_ssp_pm_runtime_en_ssp_power(struct dai_intel_ssp *dp, uint32_t i /* Check if powered on. */ ret = dai_ssp_poll_for_register_delay(dai_ip_base(dp) + I2SLCTL_OFFSET, - I2SLCTL_CPA(index), 0, + I2SLCTL_CPA(index), I2SLCTL_CPA(index), DAI_INTEL_SSP_MAX_SEND_TIME_PER_SAMPLE); #elif CONFIG_SOC_INTEL_ACE20_LNL sys_write32(sys_read32(dai_hdamlssp_base(dp) + I2SLCTL_OFFSET) | @@ -731,7 +731,7 @@ static void dai_ssp_pm_runtime_en_ssp_power(struct dai_intel_ssp *dp, uint32_t i dai_hdamlssp_base(dp) + I2SLCTL_OFFSET); /* Check if powered on. */ ret = dai_ssp_poll_for_register_delay(dai_hdamlssp_base(dp) + I2SLCTL_OFFSET, - I2SLCTL_CPA(index), 0, + I2SLCTL_CPA(index), I2SLCTL_CPA(index), DAI_INTEL_SSP_MAX_SEND_TIME_PER_SAMPLE); #else #error need to define SOC @@ -759,7 +759,7 @@ static void dai_ssp_pm_runtime_dis_ssp_power(struct dai_intel_ssp *dp, uint32_t /* Check if powered off. */ ret = dai_ssp_poll_for_register_delay(dai_ip_base(dp) + I2SLCTL_OFFSET, - I2SLCTL_CPA(index), I2SLCTL_CPA(index), + I2SLCTL_CPA(index), 0, DAI_INTEL_SSP_MAX_SEND_TIME_PER_SAMPLE); #elif CONFIG_SOC_INTEL_ACE20_LNL sys_write32(sys_read32(dai_hdamlssp_base(dp) + I2SLCTL_OFFSET) & (~I2SLCTL_SPA(index)), @@ -767,7 +767,7 @@ static void dai_ssp_pm_runtime_dis_ssp_power(struct dai_intel_ssp *dp, uint32_t /* Check if powered off. */ ret = dai_ssp_poll_for_register_delay(dai_hdamlssp_base(dp) + I2SLCTL_OFFSET, - I2SLCTL_CPA(index), I2SLCTL_CPA(index), + I2SLCTL_CPA(index), 0, DAI_INTEL_SSP_MAX_SEND_TIME_PER_SAMPLE); #else #error need to define SOC From 22ef2bed33bbeb5adfd4de60394b660a8938e526 Mon Sep 17 00:00:00 2001 From: Jamie McCrae Date: Wed, 6 Dec 2023 11:21:34 +0000 Subject: [PATCH 0916/3723] west.yml: MCUboot synchronization from upstream Update Zephyr fork of MCUboot to revision: 212997395ed34ff1721f5f4461b800e81abeb68d Brings following Zephyr relevant fixes: - 21299739 zephyr: firmware/single_loader: Fix compile warning - a88e2293 zephyr: sysflash: Fix if condition for zephyr applications - 2a74a2b5 zephyr: io: add 'io_led_set()' - 8c6c6701 zephyr: io: include 'bootutil_log.h' and declare log module membership - d99154f4 zephyr: rename 'led_init()' to 'io_led_init()' - c43a20fd boot: zephyr: add support for mimxrt1040_evk Signed-off-by: Jamie McCrae --- west.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/west.yml b/west.yml index b721d93327e..932570330f5 100644 --- a/west.yml +++ b/west.yml @@ -282,7 +282,7 @@ manifest: groups: - crypto - name: mcuboot - revision: 05d11942774fc15b90af101232ec5305051216ec + revision: 212997395ed34ff1721f5f4461b800e81abeb68d path: bootloader/mcuboot - name: mipi-sys-t path: modules/debug/mipi-sys-t From bcd2aba4d755a73f06add63ea62df7b142f76ecc Mon Sep 17 00:00:00 2001 From: Pavel Vasilyev Date: Wed, 6 Dec 2023 13:24:15 +0100 Subject: [PATCH 0917/3723] Bluetooth: Mesh: Allow custom RPL use mesh settings work This change allows a custom RPL use pending mechanism and the mesh settings work to store pending RPL entries. `bt_mesh_rpl_pending_store` is a public API and should be implemented anyway. The custom RPL implementation has to trigger settings with the `BT_MESH_SETTINGS_RPL_PENDING` flag to ask the mesh settings work to call `bt_mesh_rpl_pending_store`. Signed-off-by: Pavel Vasilyev --- subsys/bluetooth/mesh/settings.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/subsys/bluetooth/mesh/settings.c b/subsys/bluetooth/mesh/settings.c index 9cfcb3f5c2c..8ec9c66481a 100644 --- a/subsys/bluetooth/mesh/settings.c +++ b/subsys/bluetooth/mesh/settings.c @@ -186,8 +186,7 @@ static void store_pending(struct k_work *work) { LOG_DBG(""); - if (IS_ENABLED(CONFIG_BT_MESH_RPL_STORAGE_MODE_SETTINGS) && - atomic_test_and_clear_bit(pending_flags, BT_MESH_SETTINGS_RPL_PENDING)) { + if (atomic_test_and_clear_bit(pending_flags, BT_MESH_SETTINGS_RPL_PENDING)) { bt_mesh_rpl_pending_store(BT_MESH_ADDR_ALL_NODES); } From ef1f2d133674255580395b6af6ed3446f4ba3412 Mon Sep 17 00:00:00 2001 From: Pavel Vasilyev Date: Wed, 6 Dec 2023 13:32:01 +0100 Subject: [PATCH 0918/3723] Bluetooth: Mesh: Convert no opcode error to debug log This error message may confuse when `CONFIG_BT_MESH_ACCESS_LAYER_MSG` is enabled and all messages are processed by the callback anyway. This error message also confuses when a node is subscribed to the same address as it publishes to, which makes it generating the error message every time it publishes a message. Signed-off-by: Pavel Vasilyev --- subsys/bluetooth/mesh/access.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/subsys/bluetooth/mesh/access.c b/subsys/bluetooth/mesh/access.c index dcf7f0f783b..81e2902afd1 100644 --- a/subsys/bluetooth/mesh/access.c +++ b/subsys/bluetooth/mesh/access.c @@ -1424,7 +1424,7 @@ static int element_model_recv(struct bt_mesh_msg_ctx *ctx, struct net_buf_simple op = find_op(elem, opcode, &model); if (!op) { - LOG_ERR("No OpCode 0x%08x for elem 0x%02x", opcode, elem->rt->addr); + LOG_DBG("No OpCode 0x%08x for elem 0x%02x", opcode, elem->rt->addr); return ACCESS_STATUS_WRONG_OPCODE; } From 6003927ac2cd162dc1b3b5503e13c436116e7ff1 Mon Sep 17 00:00:00 2001 From: Jasper Smit Date: Wed, 6 Dec 2023 14:03:12 +0100 Subject: [PATCH 0919/3723] net: sntp: Add option for SNTP uncertainty SNTP response is not analyzed for uncertainty, and no uncertainty is given to the `struct sntp_time` returned. Fix it with a Kconfig option that adds optional SNTP uncertainty and timestamp fields in SNTP time struct, and calculates these when parsing the response. Adds two helper functions to convert Q16.16/Q32.32 in seconds to `int64_t` in microseconds to facilitate this. Also changes combined `lvm` field in `struct sntp_pkt` to bit-fields `li`, `vn`, and `mode`. Signed-off-by: Jasper Smit --- include/zephyr/net/sntp.h | 18 +++-- subsys/net/lib/sntp/Kconfig | 10 +++ subsys/net/lib/sntp/sntp.c | 125 +++++++++++++++++++++++---------- subsys/net/lib/sntp/sntp_pkt.h | 28 +++----- 4 files changed, 117 insertions(+), 64 deletions(-) diff --git a/include/zephyr/net/sntp.h b/include/zephyr/net/sntp.h index cb83675a3cd..c03c3a11206 100644 --- a/include/zephyr/net/sntp.h +++ b/include/zephyr/net/sntp.h @@ -21,6 +21,16 @@ extern "C" { * @{ */ +/** Time as returned by SNTP API, fractional seconds since 1 Jan 1970 */ +struct sntp_time { + uint64_t seconds; + uint32_t fraction; +#if defined(CONFIG_SNTP_UNCERTAINTY) + uint64_t uptime_us; + uint32_t uncertainty_us; +#endif +}; + /** SNTP context */ struct sntp_ctx { struct { @@ -33,13 +43,7 @@ struct sntp_ctx { * This is used to check if the originated timestamp in the server * reply matches the one in client request. */ - uint32_t expected_orig_ts; -}; - -/** Time as returned by SNTP API, fractional seconds since 1 Jan 1970 */ -struct sntp_time { - uint64_t seconds; - uint32_t fraction; + struct sntp_time expected_orig_ts; }; /** diff --git a/subsys/net/lib/sntp/Kconfig b/subsys/net/lib/sntp/Kconfig index b7f027b7047..44d28975c6a 100644 --- a/subsys/net/lib/sntp/Kconfig +++ b/subsys/net/lib/sntp/Kconfig @@ -9,6 +9,16 @@ menuconfig SNTP if SNTP +config SNTP_UNCERTAINTY + bool "Calculate SNTP uncertainty and set uptime timestamp" + help + Get a more reliable timestamp by supplying the sntp_time struct with an + uptime timestamp of when the time was valid and an uncertainty of the + time in microseconds. Time is then given as: + seconds,fraction +/- uncertainty at uptime timestamp. + Enabling this option uses more resources (memory) and is not normally + needed. + module = SNTP module-dep = NET_LOG module-str = Log level for SNTP diff --git a/subsys/net/lib/sntp/sntp.c b/subsys/net/lib/sntp/sntp.c index f885d24f8df..d6f4620272e 100644 --- a/subsys/net/lib/sntp/sntp.c +++ b/subsys/net/lib/sntp/sntp.c @@ -10,6 +10,7 @@ LOG_MODULE_REGISTER(net_sntp, CONFIG_SNTP_LOG_LEVEL); #include #include "sntp_pkt.h" +#include #define SNTP_LI_MAX 3 #define SNTP_VERSION_NUMBER 3 @@ -24,45 +25,60 @@ static void sntp_pkt_dump(struct sntp_pkt *pkt) return; } - NET_DBG("li %x", SNTP_GET_LI(pkt->lvm)); - NET_DBG("vn %x", SNTP_GET_VN(pkt->lvm)); - NET_DBG("mode %x", SNTP_GET_MODE(pkt->lvm)); + NET_DBG("li %x", pkt->li); + NET_DBG("vn %x", pkt->vn); + NET_DBG("mode %x", pkt->mode); NET_DBG("stratum: %x", pkt->stratum); NET_DBG("poll: %x", pkt->poll); NET_DBG("precision: %x", pkt->precision); - NET_DBG("root_delay: %x", pkt->root_delay); - NET_DBG("root_dispersion: %x", pkt->root_dispersion); - NET_DBG("ref_id: %x", pkt->ref_id); - NET_DBG("ref_tm_s: %x", pkt->ref_tm_s); - NET_DBG("ref_tm_f: %x", pkt->ref_tm_f); - NET_DBG("orig_tm_s: %x", pkt->orig_tm_s); - NET_DBG("orig_tm_f: %x", pkt->orig_tm_f); - NET_DBG("rx_tm_s: %x", pkt->rx_tm_s); - NET_DBG("rx_tm_f: %x", pkt->rx_tm_f); - NET_DBG("tx_tm_s: %x", pkt->tx_tm_s); - NET_DBG("tx_tm_f: %x", pkt->tx_tm_f); + NET_DBG("root_delay: %x", ntohl(pkt->root_delay)); + NET_DBG("root_dispersion: %x", ntohl(pkt->root_dispersion)); + NET_DBG("ref_id: %x", ntohl(pkt->ref_id)); + NET_DBG("ref_tm_s: %x", ntohl(pkt->ref_tm_s)); + NET_DBG("ref_tm_f: %x", ntohl(pkt->ref_tm_f)); + NET_DBG("orig_tm_s: %x", ntohl(pkt->orig_tm_s)); + NET_DBG("orig_tm_f: %x", ntohl(pkt->orig_tm_f)); + NET_DBG("rx_tm_s: %x", ntohl(pkt->rx_tm_s)); + NET_DBG("rx_tm_f: %x", ntohl(pkt->rx_tm_f)); + NET_DBG("tx_tm_s: %x", ntohl(pkt->tx_tm_s)); + NET_DBG("tx_tm_f: %x", ntohl(pkt->tx_tm_f)); } -static int32_t parse_response(uint8_t *data, uint16_t len, uint32_t orig_ts, - struct sntp_time *time) +#if defined(CONFIG_SNTP_UNCERTAINTY) +static int64_t q16_16_s_to_ll_us(uint32_t t) +{ + return (int64_t)(t >> 16) * (int64_t)USEC_PER_SEC + + (((int64_t)(t & 0xFFFF) * (int64_t)USEC_PER_SEC) >> 16); +} + +static int64_t q32_32_s_to_ll_us(uint32_t t_s, uint32_t t_f) +{ + return (uint64_t)t_s * USEC_PER_SEC + (((uint64_t)t_f * (uint64_t)USEC_PER_SEC) >> 32); +} +#endif + +static int32_t parse_response(uint8_t *data, uint16_t len, struct sntp_time *expected_orig_ts, + struct sntp_time *res) { struct sntp_pkt *pkt = (struct sntp_pkt *)data; uint32_t ts; sntp_pkt_dump(pkt); - if (ntohl(pkt->orig_tm_s) != orig_ts) { - NET_DBG("Mismatch originate timestamp: %d, expect: %d", - ntohl(pkt->orig_tm_s), orig_ts); + if (ntohl(pkt->orig_tm_s) != expected_orig_ts->seconds || + ntohl(pkt->orig_tm_f) != expected_orig_ts->fraction) { + NET_DBG("Mismatch originate timestamp: %d.%09d, expect: %llu.%09u", + ntohl(pkt->orig_tm_s), ntohl(pkt->orig_tm_f), expected_orig_ts->seconds, + expected_orig_ts->fraction); return -EINVAL; } - if (SNTP_GET_MODE(pkt->lvm) != SNTP_MODE_SERVER) { + if (pkt->mode != SNTP_MODE_SERVER) { /* For unicast and manycast, server should return 4. * For broadcast (which is not supported now), server should * return 5. */ - NET_DBG("Unexpected mode: %d", SNTP_GET_MODE(pkt->lvm)); + NET_DBG("Unexpected mode: %d", pkt->mode); return -EINVAL; } @@ -76,7 +92,43 @@ static int32_t parse_response(uint8_t *data, uint16_t len, uint32_t orig_ts, return -EINVAL; } - time->fraction = ntohl(pkt->tx_tm_f); +#if defined(CONFIG_SNTP_UNCERTAINTY) + + int64_t dest_ts_us = k_ticks_to_us_near64(k_uptime_ticks()); + int64_t orig_ts_us = + q32_32_s_to_ll_us(expected_orig_ts->seconds, expected_orig_ts->fraction); + + int64_t rx_ts_us = q32_32_s_to_ll_us(ntohl(pkt->rx_tm_s), ntohl(pkt->rx_tm_f)); + int64_t tx_ts_us = q32_32_s_to_ll_us(ntohl(pkt->tx_tm_s), ntohl(pkt->tx_tm_f)); + + if (rx_ts_us > tx_ts_us || orig_ts_us > dest_ts_us) { + NET_DBG("Invalid timestamps from SNTP server"); + return -EINVAL; + } + + int64_t d_us = (dest_ts_us - orig_ts_us) - (tx_ts_us - rx_ts_us); + int64_t clk_offset_us = ((rx_ts_us - orig_ts_us) + (tx_ts_us - dest_ts_us)) / 2; + int64_t root_dispersion_us = q16_16_s_to_ll_us(ntohl(pkt->root_dispersion)); + int64_t root_delay_us = q16_16_s_to_ll_us(ntohl(pkt->root_delay)); + uint32_t precision_us; + + if (pkt->precision <= 0) { + precision_us = (uint32_t)(USEC_PER_SEC + USEC_PER_SEC / 2) >> -pkt->precision; + } else if (pkt->precision <= 10) { + precision_us = (uint32_t)(USEC_PER_SEC + USEC_PER_SEC / 2) << pkt->precision; + } else { + NET_DBG("SNTP packet precision out of range: %d", pkt->precision); + return -EINVAL; + } + + res->uptime_us = dest_ts_us; + res->seconds = (res->uptime_us + clk_offset_us) / USEC_PER_SEC; + res->fraction = (res->uptime_us + clk_offset_us) % USEC_PER_SEC; + res->uncertainty_us = (d_us + root_delay_us + precision_us) / 2 + root_dispersion_us; +#else + res->fraction = ntohl(pkt->tx_tm_f); + res->seconds = ntohl(pkt->tx_tm_s); +#endif ts = ntohl(pkt->tx_tm_s); /* Check if most significant bit is set */ @@ -85,7 +137,7 @@ static int32_t parse_response(uint8_t *data, uint16_t len, uint32_t orig_ts, * on 1 January 1900. */ if (ts >= OFFSET_1970_JAN_1) { - time->seconds = ts - OFFSET_1970_JAN_1; + res->seconds -= OFFSET_1970_JAN_1; } else { return -EINVAL; } @@ -93,7 +145,7 @@ static int32_t parse_response(uint8_t *data, uint16_t len, uint32_t orig_ts, /* UTC time is reckoned from 6h 28m 16s UTC * on 7 February 2036. */ - time->seconds = ts + 0x100000000ULL - OFFSET_1970_JAN_1; + res->seconds += 0x100000000ULL - OFFSET_1970_JAN_1; } return 0; @@ -126,20 +178,11 @@ static int sntp_recv_response(struct sntp_ctx *sntp, uint32_t timeout, } status = parse_response((uint8_t *)&buf, sizeof(buf), - sntp->expected_orig_ts, + &sntp->expected_orig_ts, time); return status; } -static uint32_t get_uptime_in_sec(void) -{ - uint64_t time; - - time = k_uptime_get_32(); - - return time / MSEC_PER_SEC; -} - int sntp_init(struct sntp_ctx *ctx, struct sockaddr *addr, socklen_t addr_len) { int ret; @@ -174,17 +217,21 @@ int sntp_query(struct sntp_ctx *ctx, uint32_t timeout, struct sntp_time *time) { struct sntp_pkt tx_pkt = { 0 }; int ret = 0; + int64_t ts_us = 0; if (!ctx || !time) { return -EFAULT; } /* prepare request pkt */ - SNTP_SET_LI(tx_pkt.lvm, 0); - SNTP_SET_VN(tx_pkt.lvm, SNTP_VERSION_NUMBER); - SNTP_SET_MODE(tx_pkt.lvm, SNTP_MODE_CLIENT); - ctx->expected_orig_ts = get_uptime_in_sec() + OFFSET_1970_JAN_1; - tx_pkt.tx_tm_s = htonl(ctx->expected_orig_ts); + tx_pkt.li = 0; + tx_pkt.vn = SNTP_VERSION_NUMBER; + tx_pkt.mode = SNTP_MODE_CLIENT; + ts_us = k_ticks_to_us_near64(k_uptime_ticks()); + ctx->expected_orig_ts.seconds = ts_us / USEC_PER_SEC; + ctx->expected_orig_ts.fraction = (ts_us % USEC_PER_SEC) * (UINT32_MAX / USEC_PER_SEC); + tx_pkt.tx_tm_s = htonl(ctx->expected_orig_ts.seconds); + tx_pkt.tx_tm_f = htonl(ctx->expected_orig_ts.fraction); ret = zsock_send(ctx->sock.fd, (uint8_t *)&tx_pkt, sizeof(tx_pkt), 0); if (ret < 0) { diff --git a/subsys/net/lib/sntp/sntp_pkt.h b/subsys/net/lib/sntp/sntp_pkt.h index 979348383f2..5d8a29650d2 100644 --- a/subsys/net/lib/sntp/sntp_pkt.h +++ b/subsys/net/lib/sntp/sntp_pkt.h @@ -9,27 +9,19 @@ #include -#define SNTP_LI_MASK 0xC0 -#define SNTP_VN_MASK 0x38 -#define SNTP_MODE_MASK 0x07 - -#define SNTP_LI_SHIFT 6 -#define SNTP_VN_SHIFT 3 -#define SNTP_MODE_SHIFT 0 - -#define SNTP_GET_LI(x) ((x & SNTP_LI_MASK) >> SNTP_LI_SHIFT) -#define SNTP_GET_VN(x) ((x & SNTP_VN_MASK) >> SNTP_VN_SHIFT) -#define SNTP_GET_MODE(x) ((x & SNTP_MODE_MASK) >> SNTP_MODE_SHIFT) - -#define SNTP_SET_LI(x, v) (x = x | (v << SNTP_LI_SHIFT)) -#define SNTP_SET_VN(x, v) (x = x | (v << SNTP_VN_SHIFT)) -#define SNTP_SET_MODE(x, v) (x = x | (v << SNTP_MODE_SHIFT)) - struct sntp_pkt { - uint8_t lvm; /* li, vn, and mode in big endian fashion */ +#if defined(CONFIG_LITTLE_ENDIAN) + uint8_t mode: 3; + uint8_t vn: 3; + uint8_t li: 2; +#else + uint8_t li: 2; + uint8_t vn: 3; + uint8_t mode: 3; +#endif /* CONFIG_LITTLE_ENDIAN */ uint8_t stratum; uint8_t poll; - uint8_t precision; + int8_t precision; uint32_t root_delay; uint32_t root_dispersion; uint32_t ref_id; From 8deaf18d8bcb1724190ceb931d5c705e90c8c02a Mon Sep 17 00:00:00 2001 From: Ryan Erickson Date: Wed, 6 Dec 2023 10:34:45 -0600 Subject: [PATCH 0920/3723] drivers: modem: hl7800: fix low power modes Do not allow the modem to sleep if the driver is busy. Fix CTS filtering. Ignore small pulses on the CTS line. Fix socket restoration. Restored sockets could be mismatched with a wrong type. UDP sockets could be duplicated during restore. Improve IO debug mode. Use warning message for IO debug mode to easily see IO transitions color coded in a terminal. Ensure the UART is enabled whenever the driver needs to send commands to the modem. Ensure DNS resolver is re-initialized after the modem is powered off. PROD-307 Signed-off-by: Ryan Erickson --- drivers/modem/Kconfig.hl7800 | 15 +- drivers/modem/hl7800.c | 331 ++++++++++++++++++++++------------- 2 files changed, 220 insertions(+), 126 deletions(-) diff --git a/drivers/modem/Kconfig.hl7800 b/drivers/modem/Kconfig.hl7800 index 01c607c391a..615dd5bdf87 100644 --- a/drivers/modem/Kconfig.hl7800 +++ b/drivers/modem/Kconfig.hl7800 @@ -354,6 +354,10 @@ endchoice config MODEM_HL7800_ALLOW_SLEEP_DELAY_MS int "Milliseconds to delay before allowing modem to sleep" default 5000 + range 5000 3600000 + help + This value should be set larger than the network latency. Otherwise + the modem can go to sleep before having a chance to receive socket data. config MODEM_HL7800_RSSI_RATE_SECONDS int "Rate to automatically query RSSI" @@ -361,11 +365,10 @@ config MODEM_HL7800_RSSI_RATE_SECONDS default 30 config MODEM_HL7800_CTS_FILTER_US - int "Duration in microseconds between samples of CTS signal" - default 10 - -config MODEM_HL7800_CTS_FILTER_MAX_ITERATIONS - int "Maximum filter loops" - default 5 + int "CTS signal filter time (microseconds)" + default 20 + help + This value is used to filter the CTS signal from the modem. + CTS pulses shorter than this value will be ignored. endif # MODEM_HL7800 diff --git a/drivers/modem/hl7800.c b/drivers/modem/hl7800.c index c635016197e..9846cf86f84 100644 --- a/drivers/modem/hl7800.c +++ b/drivers/modem/hl7800.c @@ -82,7 +82,7 @@ LOG_MODULE_REGISTER(LOG_MODULE_NAME, CONFIG_MODEM_LOG_LEVEL); #define HL7800_IO_DBG_LOG(fmt, ...) \ do { \ if (IS_ENABLED(HL7800_IO_LOG)) { \ - LOG_DBG(fmt, ##__VA_ARGS__); \ + LOG_WRN(fmt, ##__VA_ARGS__); \ } \ } while (false) @@ -208,6 +208,7 @@ struct xmodem_packet { * and that its actual ID hasn't been assigned yet. */ #define MDM_CREATE_SOCKET_ID (MDM_MAX_SOCKETS + 1) +#define MDM_INVALID_SOCKET_ID -1 #define BUF_ALLOC_TIMEOUT K_SECONDS(1) @@ -439,6 +440,8 @@ struct hl7800_iface_ctx { int dsr_state; int gpio6_state; int cts_state; + int last_cts_state; + int last_cts_time; /* RX specific attributes */ struct mdm_receiver_context mdm_ctx; @@ -504,8 +507,9 @@ struct hl7800_iface_ctx { char mdm_pdp_addr_fam[MDM_ADDR_FAM_MAX_LEN]; /* modem state */ + bool busy; + bool socket_cmd; bool allow_sleep; - bool uart_on; enum mdm_hl7800_sleep desired_sleep_level; enum mdm_hl7800_sleep sleep_state; enum hl7800_lpm low_power_mode; @@ -613,6 +617,7 @@ static int queue_stale_socket(enum net_sock_type type, uint8_t id) sock = alloc_stale_socket(); if (sock != NULL) { + LOG_DBG("Queueing stale socket %d", id); sock->type = type; sock->id = id; k_queue_append(&iface_ctx.stale_socket_queue, (void *)sock); @@ -805,6 +810,11 @@ static struct hl7800_socket *socket_from_id(int socket_id) return sock; } +static inline void set_busy(bool busy) +{ + iface_ctx.busy = busy; +} + static void socket_put(struct hl7800_socket *sock) { if (!sock) { @@ -812,7 +822,7 @@ static void socket_put(struct hl7800_socket *sock) } sock->context = NULL; - sock->socket_id = -1; + sock->socket_id = MDM_INVALID_SOCKET_ID; sock->created = false; sock->reconfig = false; sock->error = 0; @@ -859,6 +869,17 @@ void mdm_hl7800_register_cts_callback(void (*func)(int state)) iface_ctx.cts_callback = func; } +static void modem_assert_reset(bool assert) +{ + if (assert) { + HL7800_IO_DBG_LOG("MDM_RESET -> ASSERTED"); + gpio_pin_set_dt(&hl7800_cfg.gpio[MDM_RESET], 1); + } else { + HL7800_IO_DBG_LOG("MDM_RESET -> NOT_ASSERTED"); + gpio_pin_set_dt(&hl7800_cfg.gpio[MDM_RESET], 0); + } +} + static void modem_assert_wake(bool assert) { int state; @@ -903,19 +924,28 @@ static void modem_assert_fast_shutd(bool assert) static void allow_sleep_work_callback(struct k_work *item) { ARG_UNUSED(item); - LOG_DBG("Allow sleep"); - iface_ctx.allow_sleep = true; - set_sleep_state(iface_ctx.desired_sleep_level); - modem_assert_wake(false); + if (!iface_ctx.busy) { + LOG_DBG("Allow sleep"); + iface_ctx.allow_sleep = true; + set_sleep_state(iface_ctx.desired_sleep_level); + modem_assert_wake(false); + } else { + k_work_reschedule_for_queue(&hl7800_workq, &iface_ctx.allow_sleep_work, + K_MSEC(CONFIG_MODEM_HL7800_ALLOW_SLEEP_DELAY_MS)); + } } static void allow_sleep(bool allow) { #ifdef CONFIG_MODEM_HL7800_LOW_POWER_MODE if (allow) { - k_work_reschedule_for_queue(&hl7800_workq, - &iface_ctx.allow_sleep_work, - K_MSEC(CONFIG_MODEM_HL7800_ALLOW_SLEEP_DELAY_MS)); + if (!iface_ctx.restarting && !iface_ctx.busy) { + k_work_reschedule_for_queue( + &hl7800_workq, &iface_ctx.allow_sleep_work, + K_MSEC(CONFIG_MODEM_HL7800_ALLOW_SLEEP_DELAY_MS)); + } else { + k_work_cancel_delayable(&iface_ctx.allow_sleep_work); + } } else { LOG_DBG("Keep awake"); k_work_cancel_delayable(&iface_ctx.allow_sleep_work); @@ -967,8 +997,10 @@ static int send_at_cmd(struct hl7800_socket *sock, const uint8_t *data, if (!sock) { k_sem_reset(&iface_ctx.response_sem); iface_ctx.last_socket_id = 0; + iface_ctx.socket_cmd = false; } else { sock->error = 0; + iface_ctx.socket_cmd = true; k_sem_reset(&sock->sock_send_sem); iface_ctx.last_socket_id = sock->socket_id; } @@ -1014,6 +1046,7 @@ static int send_at_cmd(struct hl7800_socket *sock, const uint8_t *data, static int wakeup_hl7800(void) { + set_busy(true); #ifdef CONFIG_MODEM_HL7800_LOW_POWER_MODE int ret; @@ -1049,6 +1082,7 @@ int32_t mdm_hl7800_send_at_cmd(const uint8_t *data) wakeup_hl7800(); iface_ctx.last_socket_id = 0; ret = send_at_cmd(NULL, data, MDM_CMD_SEND_TIMEOUT, 0, false); + set_busy(false); allow_sleep(true); hl7800_unlock(); return ret; @@ -1065,6 +1099,7 @@ int32_t mdm_hl7800_update_apn(char *access_point_name) wakeup_hl7800(); iface_ctx.last_socket_id = 0; ret = write_apn(access_point_name); + set_busy(false); allow_sleep(true); hl7800_unlock(); @@ -1119,6 +1154,7 @@ int32_t mdm_hl7800_update_rat(enum mdm_hl7800_radio_mode value) error: + set_busy(false); allow_sleep(true); hl7800_unlock(); @@ -1143,6 +1179,7 @@ int32_t mdm_hl7800_get_local_time(struct tm *tm, int32_t *offset) wakeup_hl7800(); iface_ctx.last_socket_id = 0; ret = send_at_cmd(NULL, "AT+CCLK?", MDM_CMD_SEND_TIMEOUT, 0, false); + set_busy(false); allow_sleep(true); if (iface_ctx.local_time_valid) { memcpy(tm, &iface_ctx.local_time, sizeof(struct tm)); @@ -1163,6 +1200,7 @@ int32_t mdm_hl7800_get_operator_index(void) iface_ctx.last_socket_id = 0; ret = send_at_cmd(NULL, "AT+KCARRIERCFG?", MDM_CMD_SEND_TIMEOUT, 0, false); + set_busy(false); allow_sleep(true); hl7800_unlock(); if (ret < 0) { @@ -1180,6 +1218,7 @@ int32_t mdm_hl7800_get_functionality(void) wakeup_hl7800(); iface_ctx.last_socket_id = 0; ret = send_at_cmd(NULL, "AT+CFUN?", MDM_CMD_SEND_TIMEOUT, 0, false); + set_busy(false); allow_sleep(true); hl7800_unlock(); @@ -1201,6 +1240,7 @@ int32_t mdm_hl7800_set_functionality(enum mdm_hl7800_functionality mode) iface_ctx.last_socket_id = 0; ret = send_at_cmd(NULL, buf, MDM_CMD_SEND_TIMEOUT, MDM_DEFAULT_AT_CMD_RETRIES, false); + set_busy(false); allow_sleep(true); hl7800_unlock(); @@ -1247,6 +1287,7 @@ int32_t mdm_hl7800_set_gps_rate(uint32_t rate) } LOG_DBG("GPS status: %d rate: %u", ret, rate); + set_busy(false); allow_sleep(true); hl7800_unlock(); return ret; @@ -1267,6 +1308,7 @@ int32_t mdm_hl7800_polte_register(void) SEND_AT_CMD_EXPECT_OK("AT%POLTECMD=\"REGISTER\""); error: LOG_DBG("PoLTE register status: %d", ret); + set_busy(false); allow_sleep(true); hl7800_unlock(); return ret; @@ -1290,6 +1332,7 @@ int32_t mdm_hl7800_polte_enable(char *user, char *password) error: LOG_DBG("PoLTE register status: %d", ret); + set_busy(false); allow_sleep(true); hl7800_unlock(); return ret; @@ -1304,6 +1347,7 @@ int32_t mdm_hl7800_polte_locate(void) SEND_AT_CMD_EXPECT_OK("AT%POLTECMD=\"LOCATE\",2,1"); error: LOG_DBG("PoLTE locate status: %d", ret); + set_busy(false); allow_sleep(true); hl7800_unlock(); return ret; @@ -1322,6 +1366,7 @@ int32_t mdm_hl7800_perform_site_survey(void) hl7800_lock(); wakeup_hl7800(); ret = send_at_cmd(NULL, "at%meas=\"97\"", MDM_CMD_SEND_TIMEOUT, 0, false); + set_busy(false); allow_sleep(true); hl7800_unlock(); return ret; @@ -1841,6 +1886,7 @@ static void dns_work_cb(struct k_work *work) struct dns_resolve_context *dnsCtx; struct sockaddr temp_addr; bool valid_address = false; + bool retry = false; static const char *const dns_servers_str[] = { #ifdef CONFIG_NET_IPV6 iface_ctx.dns_v6_string, @@ -1874,12 +1920,29 @@ static void dns_work_cb(struct k_work *work) /* set new DNS addr in DNS resolver */ LOG_DBG("Refresh DNS resolver"); dnsCtx = dns_resolve_get_default(); - ret = dns_resolve_reconfigure(dnsCtx, (const char **)dns_servers_str, NULL); - if (ret < 0) { - LOG_ERR("dns_resolve_init fail (%d)", ret); - return; + if (dnsCtx->state == DNS_RESOLVE_CONTEXT_INACTIVE) { + LOG_DBG("Initializing DNS resolver"); + ret = dns_resolve_init(dnsCtx, (const char **)dns_servers_str, NULL); + if (ret < 0) { + LOG_ERR("dns_resolve_init fail (%d)", ret); + retry = true; + } + } else { + LOG_DBG("Reconfiguring DNS resolver"); + ret = dns_resolve_reconfigure(dnsCtx, (const char **)dns_servers_str, NULL); + if (ret < 0) { + LOG_ERR("dns_resolve_reconfigure fail (%d)", ret); + retry = true; + } + } + if (!retry) { + LOG_DBG("DNS ready"); + iface_ctx.dns_ready = true; + } else { + LOG_DBG("DNS not ready, schedule a retry"); + k_work_reschedule_for_queue(&hl7800_workq, &iface_ctx.dns_work, + K_SECONDS(DNS_WORK_DELAY_SECS * 2)); } - iface_ctx.dns_ready = true; } #endif } @@ -2374,6 +2437,7 @@ int mdm_hl7800_set_desired_sleep_level(enum mdm_hl7800_sleep level) hl7800_lock(); wakeup_hl7800(); r = set_sleep_level(); + set_busy(false); allow_sleep(true); hl7800_unlock(); } @@ -2382,8 +2446,6 @@ int mdm_hl7800_set_desired_sleep_level(enum mdm_hl7800_sleep level) return r; } -#ifdef CONFIG_MODEM_HL7800_LOW_POWER_MODE - static void initialize_sleep_level(void) { if (iface_ctx.desired_sleep_level == HL7800_SLEEP_UNINITIALIZED) { @@ -2399,6 +2461,7 @@ static void initialize_sleep_level(void) } } +#ifdef CONFIG_MODEM_HL7800_LOW_POWER_MODE static int set_sleep_level(void) { char cmd[sizeof("AT+KSLEEP=#,#,##")]; @@ -2789,6 +2852,7 @@ static void rssi_query(void) hl7800_lock(); wakeup_hl7800(); hl7800_query_rssi(); + set_busy(false); allow_sleep(true); hl7800_unlock(); } @@ -2845,6 +2909,7 @@ static void gps_work_callback(struct k_work *work) hl7800_lock(); wakeup_hl7800(); r = send_at_cmd(NULL, "AT+GNSSLOC?", MDM_CMD_SEND_TIMEOUT, 1, false); + set_busy(false); allow_sleep(true); hl7800_unlock(); @@ -3300,6 +3365,7 @@ static void iface_status_work_cb(struct k_work *work) SEND_AT_CMD_IGNORE_ERROR("AT+KBND?"); } LOG_DBG("Network state updated"); + set_busy(false); allow_sleep(true); done: hl7800_unlock(); @@ -3614,6 +3680,7 @@ static bool on_cmd_network_report(struct net_buf **buf, uint16_t len) } /* keep HL7800 awake because we want to process the network state soon */ + set_busy(true); allow_sleep(false); /* start work to adjust iface */ k_work_reschedule_for_queue(&hl7800_workq, &iface_ctx.iface_status_work, @@ -3675,7 +3742,7 @@ static bool on_cmd_sockok(struct net_buf **buf, uint16_t len) struct hl7800_socket *sock = NULL; sock = socket_from_id(iface_ctx.last_socket_id); - if (!sock) { + if (!sock || !iface_ctx.socket_cmd) { iface_ctx.last_error = 0; k_sem_give(&iface_ctx.response_sem); } else { @@ -3891,6 +3958,8 @@ static void delete_untracked_socket_work_cb(struct k_work *item) { struct stale_socket *sock = NULL; + hl7800_lock(); + wakeup_hl7800(); do { sock = dequeue_stale_socket(); if (sock != NULL) { @@ -3899,6 +3968,10 @@ static void delete_untracked_socket_work_cb(struct k_work *item) free_stale_socket(sock); } } while (sock != NULL); + + set_busy(false); + allow_sleep(true); + hl7800_unlock(); } static bool on_cmd_sockcreate(enum net_sock_type type, struct net_buf **buf, uint16_t len) @@ -3921,7 +3994,7 @@ static bool on_cmd_sockcreate(enum net_sock_type type, struct net_buf **buf, uin if (!sock) { LOG_DBG("look up new socket by creation id"); sock = socket_from_id(MDM_CREATE_SOCKET_ID); - if (!sock) { + if (!sock || sock->type != type) { if (queue_stale_socket(type, iface_ctx.last_socket_id) == 0) { /* delay some time before socket cleanup in case there * are multiple sockets to cleanup @@ -4126,6 +4199,7 @@ static void sock_read(struct net_buf **buf, uint16_t len) sock->state = SOCK_IDLE; } exit: + set_busy(false); allow_sleep(true); hl7800_TX_unlock(); } @@ -4277,6 +4351,7 @@ static bool on_cmd_sockdataind(struct net_buf **buf, uint16_t len) k_work_submit_to_queue(&hl7800_workq, &sock->rx_data_work); } else { if (left_bytes > 0) { + wakeup_hl7800(); rc = start_socket_rx(sock, left_bytes); if (rc < 0) { goto error; @@ -4708,16 +4783,19 @@ static void shutdown_uart(void) { #ifdef CONFIG_PM_DEVICE int rc; + enum pm_device_state state; - if (iface_ctx.uart_on) { + rc = pm_device_state_get(iface_ctx.mdm_ctx.uart_dev, &state); + if (rc) { + LOG_ERR("Error getting UART power state (%d)", rc); + } + if (state != PM_DEVICE_STATE_SUSPENDED) { HL7800_IO_DBG_LOG("Power OFF the UART"); uart_irq_rx_disable(iface_ctx.mdm_ctx.uart_dev); rc = pm_device_action_run(iface_ctx.mdm_ctx.uart_dev, PM_DEVICE_ACTION_SUSPEND); if (rc) { LOG_ERR("Error disabling UART peripheral (%d)", rc); uart_irq_rx_enable(iface_ctx.mdm_ctx.uart_dev); - } else { - iface_ctx.uart_on = false; } } #endif @@ -4727,8 +4805,13 @@ static void power_on_uart(void) { #ifdef CONFIG_PM_DEVICE int rc; + enum pm_device_state state; - if (!iface_ctx.uart_on) { + rc = pm_device_state_get(iface_ctx.mdm_ctx.uart_dev, &state); + if (rc) { + LOG_ERR("Error getting UART power state (%d)", rc); + } + if (state != PM_DEVICE_STATE_ACTIVE) { HL7800_IO_DBG_LOG("Power ON the UART"); rc = pm_device_action_run(iface_ctx.mdm_ctx.uart_dev, PM_DEVICE_ACTION_RESUME); if (rc) { @@ -4736,7 +4819,6 @@ static void power_on_uart(void) uart_irq_rx_disable(iface_ctx.mdm_ctx.uart_dev); } else { uart_irq_rx_enable(iface_ctx.mdm_ctx.uart_dev); - iface_ctx.uart_on = true; } } #endif @@ -4774,9 +4856,12 @@ static void mdm_vgpio_work_cb(struct k_work *item) hl7800_unlock(); } -void mdm_vgpio_callback_isr(const struct device *port, struct gpio_callback *cb, - uint32_t pins) +void mdm_vgpio_callback_isr(const struct device *port, struct gpio_callback *cb, uint32_t pins) { + ARG_UNUSED(port); + ARG_UNUSED(cb); + ARG_UNUSED(pins); + iface_ctx.vgpio_state = read_pin(1, &hl7800_cfg.gpio[MDM_VGPIO]); HL7800_IO_DBG_LOG("VGPIO:%d", iface_ctx.vgpio_state); if (!iface_ctx.vgpio_state) { @@ -4784,7 +4869,6 @@ void mdm_vgpio_callback_isr(const struct device *port, struct gpio_callback *cb, if (!iface_ctx.restarting && iface_ctx.initialized) { iface_ctx.reconfig_IP_connection = true; } - check_hl7800_awake(); } else { if (iface_ctx.off) { return; @@ -4798,10 +4882,11 @@ void mdm_vgpio_callback_isr(const struct device *port, struct gpio_callback *cb, /* Keep the modem awake to see if it has anything to send to us. */ allow_sleep(false); /* Allow the modem to go back to sleep if it was the one who - * sourced the CTS transition. + * sourced the transition. */ allow_sleep(true); } + check_hl7800_awake(); /* When the network state changes a semaphore must be taken. * This can't be done in interrupt context because the wait time != 0. @@ -4809,9 +4894,12 @@ void mdm_vgpio_callback_isr(const struct device *port, struct gpio_callback *cb, k_work_submit_to_queue(&hl7800_workq, &iface_ctx.mdm_vgpio_work); } -void mdm_uart_dsr_callback_isr(const struct device *port, - struct gpio_callback *cb, uint32_t pins) +void mdm_uart_dsr_callback_isr(const struct device *port, struct gpio_callback *cb, uint32_t pins) { + ARG_UNUSED(port); + ARG_UNUSED(cb); + ARG_UNUSED(pins); + iface_ctx.dsr_state = read_pin(1, &hl7800_cfg.gpio[MDM_UART_DSR]); HL7800_IO_DBG_LOG("MDM_UART_DSR:%d", iface_ctx.dsr_state); } @@ -4832,12 +4920,15 @@ static void mark_sockets_for_reconfig(void) } #endif -void mdm_gpio6_callback_isr(const struct device *port, struct gpio_callback *cb, - uint32_t pins) +void mdm_gpio6_callback_isr(const struct device *port, struct gpio_callback *cb, uint32_t pins) { -#ifdef CONFIG_MODEM_HL7800_LOW_POWER_MODE + ARG_UNUSED(port); + ARG_UNUSED(cb); + ARG_UNUSED(pins); + iface_ctx.gpio6_state = read_pin(1, &hl7800_cfg.gpio[MDM_GPIO6]); HL7800_IO_DBG_LOG("MDM_GPIO6:%d", iface_ctx.gpio6_state); +#ifdef CONFIG_MODEM_HL7800_LOW_POWER_MODE if (!iface_ctx.gpio6_state) { /* HL7800 is not awake, shut down UART to save power */ shutdown_uart(); @@ -4845,102 +4936,95 @@ void mdm_gpio6_callback_isr(const struct device *port, struct gpio_callback *cb, iface_ctx.wait_for_KSUP_tries = 0; iface_ctx.reconfig_IP_connection = true; mark_sockets_for_reconfig(); - /* TODO: may need to indicate all TCP connections lost here */ } else { if (iface_ctx.off) { return; + } else if (iface_ctx.vgpio_state) { + power_on_uart(); + /* Keep the modem awake to see if it has anything to send to us. */ + allow_sleep(false); + /* Allow the modem to go back to sleep if it was the one who + * sourced the transition. + */ + allow_sleep(true); } - power_on_uart(); } + check_hl7800_awake(); if ((iface_ctx.gpio6_callback != NULL) && ((iface_ctx.desired_sleep_level == HL7800_SLEEP_HIBERNATE) || (iface_ctx.desired_sleep_level == HL7800_SLEEP_LITE_HIBERNATE))) { iface_ctx.gpio6_callback(iface_ctx.gpio6_state); } - - check_hl7800_awake(); -#else - HL7800_IO_DBG_LOG("Spurious gpio6 interrupt from the modem"); #endif } -/** - * @brief Short spikes in CTS can be removed in the signal used by the application - */ -static int glitch_filter(int default_state, const struct gpio_dt_spec *spec, - uint32_t usec_to_wait, uint32_t max_iterations) -{ - int i = 0; - int state1; - int state2; - - do { - state1 = read_pin(-1, spec); - k_busy_wait(usec_to_wait); - state2 = read_pin(-1, spec); - i += 1; - } while (((state1 != state2) || (state1 < 0) || (state2 < 0)) && (i < max_iterations)); - - if (i >= max_iterations) { - LOG_WRN("glitch filter max iterations exceeded %d", i); - if (state1 < 0) { - if (state2 < 0) { - state1 = read_pin(default_state, spec); - } else { - state1 = state2; - } - } - } - - return state1; -} - -void mdm_uart_cts_callback(const struct device *port, struct gpio_callback *cb, uint32_t pins) +void mdm_uart_cts_callback_isr(const struct device *port, struct gpio_callback *cb, uint32_t pins) { ARG_UNUSED(port); ARG_UNUSED(cb); ARG_UNUSED(pins); - - iface_ctx.cts_state = - glitch_filter(0, &hl7800_cfg.gpio[MDM_UART_CTS], - CONFIG_MODEM_HL7800_CTS_FILTER_US, - CONFIG_MODEM_HL7800_CTS_FILTER_MAX_ITERATIONS); - - /* CTS toggles A LOT, - * comment out the debug print unless we really need it. - */ - /* HL7800_IO_DBG_LOG("MDM_UART_CTS:%d", iface_ctx.cts_state); */ - - if ((iface_ctx.cts_callback != NULL) && - (iface_ctx.desired_sleep_level == HL7800_SLEEP_SLEEP)) { - iface_ctx.cts_callback(iface_ctx.cts_state); + uint64_t now; + uint64_t elapsed; + int resample_state; + + iface_ctx.cts_state = read_pin(0, &hl7800_cfg.gpio[MDM_UART_CTS]); + + /* Debounce the CTS signal */ + now = k_ticks_to_us_floor64(k_uptime_ticks()); + elapsed = now - iface_ctx.last_cts_time; + if (iface_ctx.last_cts_time <= 0) { + /* This is the first transition we have seen, continue */ + } else if (elapsed <= CONFIG_MODEM_HL7800_CTS_FILTER_US) { + /* CTS changed too quickly, ignore this transition */ + iface_ctx.last_cts_time = now; + return; + } + iface_ctx.last_cts_time = now; + k_busy_wait(CONFIG_MODEM_HL7800_CTS_FILTER_US); + resample_state = read_pin(0, &hl7800_cfg.gpio[MDM_UART_CTS]); + if (iface_ctx.cts_state != resample_state) { + /* CTS changed while we were debouncing, ignore it */ + iface_ctx.cts_state = resample_state; + return; + } + iface_ctx.cts_state = resample_state; + if (iface_ctx.cts_state != iface_ctx.last_cts_state) { + iface_ctx.last_cts_state = iface_ctx.cts_state; + } else { + return; } + HL7800_IO_DBG_LOG("MDM_UART_CTS:%d(%llu)", iface_ctx.cts_state, elapsed); + #ifdef CONFIG_MODEM_HL7800_LOW_POWER_MODE - if (iface_ctx.cts_state) { - /* HL7800 is not awake, shut down UART to save power */ - if (iface_ctx.allow_sleep) { - shutdown_uart(); - } + if (iface_ctx.cts_state && iface_ctx.allow_sleep) { + /* HL7800 cannot receive UART data, shut down UART to save power. + * This is critical for proper low power operation. If the UART is disabled + * after VGPIO is low, the UART will not suspend properly. + */ + shutdown_uart(); } else { if (iface_ctx.off) { return; } - if (iface_ctx.desired_sleep_level != HL7800_SLEEP_HIBERNATE) { + if (iface_ctx.vgpio_state && iface_ctx.gpio6_state) { power_on_uart(); - if (iface_ctx.sleep_state == HL7800_SLEEP_SLEEP) { - /* Wake up the modem to see if it has anything to send to us. */ - allow_sleep(false); - /* Allow the modem to go back to sleep if it was the one who - * sourced the CTS transition. - */ - allow_sleep(true); - } + /* Wake up the modem to see if it has anything to send to us. */ + allow_sleep(false); + /* Allow the modem to go back to sleep if it was the one who + * sourced the CTS transition. + */ + allow_sleep(true); } } #endif + if ((iface_ctx.cts_callback != NULL) && + (iface_ctx.desired_sleep_level == HL7800_SLEEP_SLEEP)) { + iface_ctx.cts_callback(iface_ctx.cts_state); + } + check_hl7800_awake(); } @@ -4950,7 +5034,7 @@ static void modem_reset(void) LOG_INF("Modem Reset"); /* Hard reset the modem */ - gpio_pin_set_dt(&hl7800_cfg.gpio[MDM_RESET], 1); + modem_assert_reset(true); /* >20 milliseconds required for reset low */ k_sleep(MDM_RESET_LOW_TIME); @@ -4973,10 +5057,10 @@ static void modem_reset(void) static void modem_run(void) { LOG_INF("Modem Run"); - gpio_pin_set_dt(&hl7800_cfg.gpio[MDM_RESET], 0); - k_sleep(MDM_RESET_HIGH_TIME); iface_ctx.off = false; + modem_assert_reset(false); allow_sleep(false); + k_sleep(MDM_RESET_HIGH_TIME); } static int modem_boot_handler(char *reason) @@ -4986,9 +5070,7 @@ static int modem_boot_handler(char *reason) LOG_DBG("%s", reason); ret = k_sem_take(&iface_ctx.mdm_awake, MDM_BOOT_TIME); if (ret) { - LOG_ERR("Err waiting for boot: %d, DSR: %u", ret, - iface_ctx.dsr_state); - return -1; + LOG_WRN("Err waiting for boot: %d, DSR: %u", ret, iface_ctx.dsr_state); } else { LOG_INF("Modem booted!"); } @@ -5172,6 +5254,7 @@ static int modem_reset_and_configure(void) "\",\"" CONFIG_MODEM_HL7800_PSM_ACTIVE_TIME "\""; #endif + set_busy(true); iface_ctx.restarting = true; iface_ctx.dns_ready = false; if (iface_ctx.iface) { @@ -5179,6 +5262,7 @@ static int modem_reset_and_configure(void) } hl7800_stop_rssi_work(); + initialize_sleep_level(); reboot: modem_reset(); @@ -5352,7 +5436,6 @@ static int modem_reset_and_configure(void) /* enable GPIO6 low power monitoring */ SEND_AT_CMD_EXPECT_OK("AT+KHWIOCFG=3,1,6"); - initialize_sleep_level(); ret = set_sleep_level(); if (ret < 0) { goto error; @@ -5453,7 +5536,7 @@ static int modem_reset_and_configure(void) SEND_COMPLEX_AT_CMD("AT+CEREG?"); /* Turn on EPS network registration status reporting */ - SEND_AT_CMD_EXPECT_OK("AT+CEREG=4"); + SEND_AT_CMD_EXPECT_OK("AT+CEREG=5"); /* query all socket configs to cleanup any sockets that are not * tracked by the driver @@ -5472,6 +5555,7 @@ static int modem_reset_and_configure(void) LOG_INF("Modem ready!"); iface_ctx.restarting = false; iface_ctx.configured = true; + set_busy(false); allow_sleep(sleep); /* trigger APN update event */ event_handler(HL7800_EVENT_APN_UPDATE, &iface_ctx.mdm_apn); @@ -5563,6 +5647,7 @@ static void mdm_power_off_work_callback(struct k_work *item) iface_ctx.dns_ready = false; iface_ctx.configured = false; iface_ctx.off = true; + set_busy(false); /* bring the iface down */ if (iface_ctx.iface) { net_if_carrier_off(iface_ctx.iface); @@ -5771,6 +5856,9 @@ static int reconfigure_IP_connection(void) /* query all UDP socket configs */ ret = send_at_cmd(NULL, "AT+KUDPCFG?", MDM_CMD_SEND_TIMEOUT, 0, false); + + /* TODO: to make this better, wait for +KUDP_IND or timeout */ + k_sleep(K_SECONDS(1)); } done: @@ -5811,18 +5899,18 @@ static int offload_get(sa_family_t family, enum net_sock_type type, wakeup_hl7800(); /* reconfig IP connection if necessary */ - if (reconfigure_IP_connection() < 0) { - socket_put(sock); - goto done; - } + (void)reconfigure_IP_connection(); - ret = configure_UDP_socket(sock); - if (ret < 0) { - socket_put(sock); - goto done; + if (!sock->created) { + ret = configure_UDP_socket(sock); + if (ret < 0) { + socket_put(sock); + goto done; + } } } done: + set_busy(false); allow_sleep(true); hl7800_unlock(); return ret; @@ -5947,6 +6035,7 @@ static int offload_connect(struct net_context *context, } done: + set_busy(false); allow_sleep(true); hl7800_unlock(); @@ -6010,6 +6099,7 @@ static int offload_sendto(struct net_pkt *pkt, const struct sockaddr *dst_addr, ret = send_data(sock, pkt); + set_busy(false); allow_sleep(true); hl7800_unlock(); @@ -6109,6 +6199,7 @@ static int offload_put(struct net_context *context) /* delete session */ delete_socket(sock, sock->type, sock->socket_id); } + set_busy(false); allow_sleep(true); socket_put(sock); @@ -6216,6 +6307,9 @@ static int hl7800_init(const struct device *dev) LOG_DBG("HL7800 Init"); + /* The UART starts in the on state and CTS is set low by the HL7800 */ + iface_ctx.cts_state = iface_ctx.last_cts_state = 0; + /* Prevent the network interface from starting until * the modem has been initialized * because the modem may not have a valid SIM card. @@ -6229,7 +6323,7 @@ static int hl7800_init(const struct device *dev) /* init sockets */ for (i = 0; i < MDM_MAX_SOCKETS; i++) { - iface_ctx.sockets[i].socket_id = -1; + iface_ctx.sockets[i].socket_id = MDM_INVALID_SOCKET_ID; k_work_init(&iface_ctx.sockets[i].recv_cb_work, sockreadrecv_cb_work); k_work_init(&iface_ctx.sockets[i].rx_data_work, @@ -6334,9 +6428,6 @@ static int hl7800_init(const struct device *dev) return ret; } - /* when this driver starts, the UART peripheral is already enabled */ - iface_ctx.uart_on = true; - modem_assert_wake(false); modem_assert_pwr_on(false); modem_assert_fast_shutd(false); @@ -6394,7 +6485,7 @@ static int hl7800_init(const struct device *dev) } /* UART CTS */ - gpio_init_callback(&iface_ctx.mdm_uart_cts_cb, mdm_uart_cts_callback, + gpio_init_callback(&iface_ctx.mdm_uart_cts_cb, mdm_uart_cts_callback_isr, BIT(hl7800_cfg.gpio[MDM_UART_CTS].pin)); ret = gpio_add_callback(hl7800_cfg.gpio[MDM_UART_CTS].port, &iface_ctx.mdm_uart_cts_cb); From edf32335cb11c3a2770827172162d41817b15d6c Mon Sep 17 00:00:00 2001 From: Ryan McClelland Date: Tue, 5 Dec 2023 13:57:49 -0800 Subject: [PATCH 0921/3723] test: drivers: sensor: adltc2990: fix double promotion Fix double promotion warning Signed-off-by: Ryan McClelland --- tests/drivers/sensor/adltc2990/src/main.c | 70 ++++++++++++----------- 1 file changed, 37 insertions(+), 33 deletions(-) diff --git a/tests/drivers/sensor/adltc2990/src/main.c b/tests/drivers/sensor/adltc2990/src/main.c index fabeb8ab0dc..a196412f2ef 100644 --- a/tests/drivers/sensor/adltc2990/src/main.c +++ b/tests/drivers/sensor/adltc2990/src/main.c @@ -18,36 +18,39 @@ zassert_ok(sensor_sample_fetch_chan(fixture->dev, SENSOR_CHAN_VOLTAGE)); \ zassert_ok(sensor_channel_get(fixture->dev, SENSOR_CHAN_VOLTAGE, sensor_val)); \ zassert_between_inclusive( \ - sensor_val[index].val1 + (double)sensor_val[index].val2 / 1000000, \ + sensor_val[index].val1 + (float)sensor_val[index].val2 / 1000000, \ (pin_voltage - 0.01f) * ((r1 + r2) / (float)r2), \ (pin_voltage + 0.01f) * ((r1 + r2) / (float)r2), \ "%f Out of Range [%f,%f] input %f, [%dmΩ, %dmΩ] " \ "\nCheck if the sensor node is configured correctly", \ - sensor_val[index].val1 + (double)sensor_val[index].val2 / 1000000, \ - (pin_voltage - 0.01f) * ((r1 + r2) / (float)r2), \ - (pin_voltage + 0.01f) * ((r1 + r2) / (float)r2), pin_voltage, r1, r2); + (double)(sensor_val[index].val1 + (float)sensor_val[index].val2 / 1000000), \ + (double)((pin_voltage - 0.01f) * ((r1 + r2) / (float)r2)), \ + (double)((pin_voltage + 0.01f) * ((r1 + r2) / (float)r2)), (double)pin_voltage, \ + r1, r2); #define CHECK_CURRENT(sensor_val, index, pin_voltage, r_microohms) \ zassert_ok(sensor_sample_fetch_chan(fixture->dev, SENSOR_CHAN_CURRENT)); \ zassert_ok(sensor_channel_get(fixture->dev, SENSOR_CHAN_CURRENT, sensor_val)); \ zassert_between_inclusive( \ - sensor_val[index].val1 + (double)sensor_val[index].val2 / 1000000, \ + sensor_val[index].val1 + (float)sensor_val[index].val2 / 1000000, \ (pin_voltage - 0.01f) * ADLTC2990_MICROOHM_CONVERSION_FACTOR / r_microohms, \ (pin_voltage + 0.01f) * ADLTC2990_MICROOHM_CONVERSION_FACTOR / r_microohms, \ "%f Out of Range [%f,%f] input %f, current-resistor: %dµΩ\nCheck if the sensor " \ "node is configured correctly", \ - sensor_val[index].val1 + (double)sensor_val[index].val2 / 1000000, \ - (pin_voltage - 0.001f) * ADLTC2990_MICROOHM_CONVERSION_FACTOR / r_microohms, \ - (pin_voltage + 0.001f) * ADLTC2990_MICROOHM_CONVERSION_FACTOR / r_microohms, \ - pin_voltage, r_microohms); + (double)(sensor_val[index].val1 + (float)sensor_val[index].val2 / 1000000), \ + (double)((pin_voltage - 0.001f) * ADLTC2990_MICROOHM_CONVERSION_FACTOR / \ + r_microohms), \ + (double)((pin_voltage + 0.001f) * ADLTC2990_MICROOHM_CONVERSION_FACTOR / \ + r_microohms), \ + (double)pin_voltage, r_microohms); #define CHECK_TEMPERATURE(sensor_val, index, expected_temperature, temperature_type) \ zassert_ok(sensor_sample_fetch_chan(fixture->dev, temperature_type)); \ zassert_ok(sensor_channel_get(fixture->dev, temperature_type, sensor_val)); \ zassert_equal(expected_temperature, \ sensor_val[index].val1 + (float)sensor_val[index].val2 / 1000000, \ - "expected %f, got %f", expected_temperature, \ - sensor_val[index].val1 + (float)sensor_val[index].val2 / 1000000); + "expected %f, got %f", (double)expected_temperature, \ + (double)(sensor_val[index].val1 + (float)sensor_val[index].val2 / 1000000)); /*** TEST-SUITE: ADLTC2990 Measurement Mode 0 0***/ @@ -165,7 +168,7 @@ ZTEST_F(adltc2990_1_3, test_die_temperature) struct sensor_value temp_value[1]; - CHECK_TEMPERATURE(temp_value, 0, 125.00, SENSOR_CHAN_DIE_TEMP); + CHECK_TEMPERATURE(temp_value, 0, 125.00f, SENSOR_CHAN_DIE_TEMP); /*0b00011101 0b10000000 –40.0000*/ msb = 0b00011101; @@ -174,7 +177,7 @@ ZTEST_F(adltc2990_1_3, test_die_temperature) adltc2990_emul_set_reg(fixture->target, ADLTC2990_REG_INTERNAL_TEMP_MSB, &msb); adltc2990_emul_set_reg(fixture->target, ADLTC2990_REG_INTERNAL_TEMP_LSB, &lsb); - CHECK_TEMPERATURE(temp_value, 0, -40.00, SENSOR_CHAN_DIE_TEMP); + CHECK_TEMPERATURE(temp_value, 0, -40.00f, SENSOR_CHAN_DIE_TEMP); } ZTEST_F(adltc2990_1_3, test_ambient_temperature) @@ -186,7 +189,7 @@ ZTEST_F(adltc2990_1_3, test_ambient_temperature) adltc2990_emul_set_reg(fixture->target, ADLTC2990_REG_V3_MSB, &msb); adltc2990_emul_set_reg(fixture->target, ADLTC2990_REG_V3_LSB, &lsb); - CHECK_TEMPERATURE(temp_ambient, 0, 25.06250, SENSOR_CHAN_AMBIENT_TEMP); + CHECK_TEMPERATURE(temp_ambient, 0, 25.06250f, SENSOR_CHAN_AMBIENT_TEMP); } ZTEST_F(adltc2990_1_3, test_current) @@ -200,13 +203,13 @@ ZTEST_F(adltc2990_1_3, test_current) struct sensor_value current_values[1]; const struct adltc2990_config *dev_config = fixture->target->dev->config; - CHECK_CURRENT(current_values, 0, 0.3, dev_config->pins_v1_v2.pins_current_resistor); + CHECK_CURRENT(current_values, 0, 0.3f, dev_config->pins_v1_v2.pins_current_resistor); /* 0b00100000 0b00000000 +0.159 */ msb_reg_value = 0b00100000, lsb_reg_value = 0b00000000; adltc2990_emul_set_reg(fixture->target, ADLTC2990_REG_V1_MSB, &msb_reg_value); adltc2990_emul_set_reg(fixture->target, ADLTC2990_REG_V1_LSB, &lsb_reg_value); - CHECK_CURRENT(current_values, 0, 0.159, dev_config->pins_v1_v2.pins_current_resistor); + CHECK_CURRENT(current_values, 0, 0.159f, dev_config->pins_v1_v2.pins_current_resistor); } ZTEST_F(adltc2990_1_3, test_V1_MINUS_V2_VCC) @@ -229,12 +232,12 @@ ZTEST_F(adltc2990_1_3, test_V1_MINUS_V2_VCC) float test_value = voltage_values[0].val1 + (float)voltage_values[0].val2 / 1000000; - zassert_between_inclusive(test_value, -0.16, -0.159, "Out of Range [-0.16,-0.159]%.6f", - test_value); + zassert_between_inclusive(test_value, -0.16f, -0.159f, "Out of Range [-0.16,-0.159]%.6f", + (double)test_value); - test_value = voltage_values[1].val1 + (double)voltage_values[1].val2 / 1000000; - zassert_between_inclusive(test_value, 2.69, 2.7, "Out of Range [2.69, 2.7]%.6f", - test_value); + test_value = voltage_values[1].val1 + (float)voltage_values[1].val2 / 1000000; + zassert_between_inclusive(test_value, 2.69f, 2.7f, "Out of Range [2.69, 2.7]%.6f", + (double)test_value); } /*** TEST-SUITE: ADLTC2990 Measurement Mode 5 3***/ @@ -275,14 +278,14 @@ ZTEST_F(adltc2990_5_3, test_ambient_temperature) struct sensor_value temp_value[2]; - CHECK_TEMPERATURE(temp_value, 0, 273.1250, SENSOR_CHAN_AMBIENT_TEMP); + CHECK_TEMPERATURE(temp_value, 0, 273.1250f, SENSOR_CHAN_AMBIENT_TEMP); /*Kelvin 0b00001110 0b10010010 233.125*/ msb = 0b00001110; lsb = 0b10010010; adltc2990_emul_set_reg(fixture->target, ADLTC2990_REG_V3_MSB, &msb); adltc2990_emul_set_reg(fixture->target, ADLTC2990_REG_V3_LSB, &lsb); - CHECK_TEMPERATURE(temp_value, 1, 233.1250, SENSOR_CHAN_AMBIENT_TEMP); + CHECK_TEMPERATURE(temp_value, 1, 233.1250f, SENSOR_CHAN_AMBIENT_TEMP); } ZTEST_F(adltc2990_5_3, test_die_temperature) @@ -295,7 +298,7 @@ ZTEST_F(adltc2990_5_3, test_die_temperature) struct sensor_value temp_value[1]; - CHECK_TEMPERATURE(temp_value, 0, 398.1250, SENSOR_CHAN_DIE_TEMP); + CHECK_TEMPERATURE(temp_value, 0, 398.1250f, SENSOR_CHAN_DIE_TEMP); } /*** TEST-SUITE: ADLTC2990 Measurement Mode 7 3***/ @@ -337,13 +340,13 @@ ZTEST_F(adltc2990_6_3, test_current) struct sensor_value current_values[2]; const struct adltc2990_config *dev_config = fixture->target->dev->config; - CHECK_CURRENT(current_values, 0, 0.3, dev_config->pins_v1_v2.pins_current_resistor); + CHECK_CURRENT(current_values, 0, 0.3f, dev_config->pins_v1_v2.pins_current_resistor); /* 0b00100000 0b00000000 +0.159 */ msb_reg_value = 0b00100000, lsb_reg_value = 0b00000000; adltc2990_emul_set_reg(fixture->target, ADLTC2990_REG_V3_MSB, &msb_reg_value); adltc2990_emul_set_reg(fixture->target, ADLTC2990_REG_V3_LSB, &lsb_reg_value); - CHECK_CURRENT(current_values, 1, 0.159, dev_config->pins_v3_v4.pins_current_resistor); + CHECK_CURRENT(current_values, 1, 0.159f, dev_config->pins_v3_v4.pins_current_resistor); } /*** TEST-SUITE: ADLTC2990 Measurement Mode 7 3***/ @@ -406,7 +409,7 @@ ZTEST_F(adltc2990_7_3, test_die_temperature) struct sensor_value die_temp_value[1]; - CHECK_TEMPERATURE(die_temp_value, 0, 398.1250, SENSOR_CHAN_DIE_TEMP); + CHECK_TEMPERATURE(die_temp_value, 0, 398.1250f, SENSOR_CHAN_DIE_TEMP); } ZTEST_F(adltc2990_7_3, test_V1_V2_V3_V4_VCC) @@ -445,25 +448,26 @@ ZTEST_F(adltc2990_7_3, test_V1_V2_V3_V4_VCC) const struct adltc2990_config *dev_config = fixture->dev->config; - CHECK_SINGLE_ENDED_VOLTAGE(voltage_values, 0, 5.0, + CHECK_SINGLE_ENDED_VOLTAGE(voltage_values, 0, 5.0f, dev_config->pins_v1_v2.voltage_divider_resistors.v1_r1_r2[0], dev_config->pins_v1_v2.voltage_divider_resistors.v1_r1_r2[1]); - CHECK_SINGLE_ENDED_VOLTAGE(voltage_values, 1, 3.5, + CHECK_SINGLE_ENDED_VOLTAGE(voltage_values, 1, 3.5f, dev_config->pins_v1_v2.voltage_divider_resistors.v2_r1_r2[0], dev_config->pins_v1_v2.voltage_divider_resistors.v2_r1_r2[1]); - CHECK_SINGLE_ENDED_VOLTAGE(voltage_values, 2, 2.5, + CHECK_SINGLE_ENDED_VOLTAGE(voltage_values, 2, 2.5f, dev_config->pins_v3_v4.voltage_divider_resistors.v3_r1_r2[0], dev_config->pins_v3_v4.voltage_divider_resistors.v3_r1_r2[1]); - CHECK_SINGLE_ENDED_VOLTAGE(voltage_values, 3, -0.3, + CHECK_SINGLE_ENDED_VOLTAGE(voltage_values, 3, -0.3f, dev_config->pins_v3_v4.voltage_divider_resistors.v4_r1_r2[0], dev_config->pins_v3_v4.voltage_divider_resistors.v4_r1_r2[1]); - float test_value = voltage_values[4].val1 + (double)voltage_values[4].val2 / 1000000; + double test_value = voltage_values[4].val1 + (double)voltage_values[4].val2 / 1000000; - zassert_between_inclusive(test_value, 6.0, 6.1, "Out of Range [6.0,6.1] %.6f", test_value); + zassert_between_inclusive(test_value, 6.0, 6.1, "Out of Range [6.0,6.1] %.6f", + (double)test_value); zassert_equal(6, voltage_values[4].val1); } From 917770952dac3620df8c08ac733fa46285557d87 Mon Sep 17 00:00:00 2001 From: Fabian Blatz Date: Thu, 7 Dec 2023 09:11:08 +0100 Subject: [PATCH 0922/3723] samples: subsys: display: lvgl: Update README Update the readme to better describe contents of the sample, which is now used to showcase the various input device types that LVGL offers. Signed-off-by: Fabian Blatz --- samples/subsys/display/lvgl/README.rst | 31 +++++++++++++++++++++----- 1 file changed, 25 insertions(+), 6 deletions(-) diff --git a/samples/subsys/display/lvgl/README.rst b/samples/subsys/display/lvgl/README.rst index 84bb5fdb40b..be5eecd9db1 100644 --- a/samples/subsys/display/lvgl/README.rst +++ b/samples/subsys/display/lvgl/README.rst @@ -1,17 +1,36 @@ .. zephyr:code-sample:: lvgl :name: LVGL basic sample - :relevant-api: display_interface + :relevant-api: display_interface input_interface - Display "Hello World" and a dynamic counter using LVGL. + Display a "Hello World" and react to user input using LVGL. Overview ******** This sample application displays "Hello World" in the center of the screen -and a counter at the bottom which increments every second. If an input driver -is supported, such as the touch panel controller on mimxrt10{50,60,64}_evk -boards, "Hello World" is enclosed in a button that changes to the toggled state -when touched. +and a counter at the bottom which increments every second. +Based on the available input devices on the board used to run the sample, +additional widgets may be displayed and additional interactions enabled: + +* Pointer + If your board has a touch panel controller + (:dtcompatible:`zephyr,lvgl-pointer-input`), a button widget is displayed + in the center of the screen. Otherwise a label widget is displayed. +* Button + The button pseudo device (:dtcompatible:`zephyr,lvgl-button-input`) maps + a press/release action to a specific coordinate on screen. In the case + of this sample, the coordinates are mapped to the center of the screen. +* Encoder + The encoder pseudo device (:dtcompatible:`zephyr,lvgl-encoder-input`) + can be used to navigate between widgets and edit their values. If the + board contains an encoder, an arc widget is displayed, which can be + edited. +* Keypad + The keypad pseudo device (:dtcompatible:`zephyr,lvgl-keypad-input`) can + be used for focus shifting and also entering characters inside editable + widgets such as text areas. If the board used with this sample has a + keypad device, a button matrix is displayed at the bottom of the screen + to showcase the focus shifting capabilities. Requirements ************ From 4e9f73b0dd73d4147efbf409f88b1d550ef31967 Mon Sep 17 00:00:00 2001 From: Flavio Ceolin Date: Thu, 7 Dec 2023 15:47:04 -0800 Subject: [PATCH 0923/3723] doc: pm: nrf target does not enable PM samples/boards/nrf/system_off does not enable CONFIG_PM so it should not be listed as an example in system power management documentation. Signed-off-by: Flavio Ceolin --- doc/services/pm/system.rst | 1 - 1 file changed, 1 deletion(-) diff --git a/doc/services/pm/system.rst b/doc/services/pm/system.rst index 989fcdb4a91..b71b793c94d 100644 --- a/doc/services/pm/system.rst +++ b/doc/services/pm/system.rst @@ -24,7 +24,6 @@ The following diagram describes system power management: Some handful examples using different power management features: * :zephyr_file:`samples/boards/stm32/power_mgmt/blinky/` -* :zephyr_file:`samples/boards/nrf/system_off/` * :zephyr_file:`samples/boards/esp32/deep_sleep/` * :zephyr_file:`samples/subsys/pm/device_pm/` * :zephyr_file:`tests/subsys/pm/power_mgmt/` From 0a3fe40505095bc679139ceb81796b7a65a06945 Mon Sep 17 00:00:00 2001 From: Yong Cong Sin Date: Sat, 25 Nov 2023 22:31:49 +0800 Subject: [PATCH 0924/3723] drivers: intc: plic: set edge-triggered register address using compat Define the edge-trigger register base address based on whether the PLIC node in the devicetree has an additional compatible that supports edge-triggered interrupt. Limited the implementation to Andes NCEPLIC100 only, updated the devicetree binding of `andes_v5_ae350` accordingly. Signed-off-by: Yong Cong Sin --- drivers/interrupt_controller/intc_plic.c | 49 +++++++++++++++++------- dts/riscv/andes/andes_v5_ae350.dtsi | 2 +- 2 files changed, 37 insertions(+), 14 deletions(-) diff --git a/drivers/interrupt_controller/intc_plic.c b/drivers/interrupt_controller/intc_plic.c index b8ca3234d12..9705380ea7b 100644 --- a/drivers/interrupt_controller/intc_plic.c +++ b/drivers/interrupt_controller/intc_plic.c @@ -42,7 +42,19 @@ * However, it is defined and supported by at least the Andes & Telink datasheet, and supported * in Linux's SiFive PLIC driver */ +#define PLIC_TRIG_LEVEL ((uint32_t)~BIT(0)) +#define PLIC_TRIG_EDGE ((uint32_t)BIT(0)) +#define PLIC_DRV_HAS_COMPAT(compat) \ + DT_NODE_HAS_COMPAT(DT_COMPAT_GET_ANY_STATUS_OKAY(DT_DRV_COMPAT), compat) + +#if PLIC_DRV_HAS_COMPAT(andestech_nceplic100) +#define PLIC_SUPPORTS_TRIG_TYPE 1 +#define PLIC_REG_TRIG_TYPE_WIDTH 1 #define PLIC_REG_TRIG_TYPE_OFFSET 0x1080 +#else +/* Trigger-type not supported */ +#define PLIC_REG_TRIG_TYPE_WIDTH 0 +#endif /* PLIC registers are 32-bit memory-mapped */ #define PLIC_REG_SIZE 32 @@ -124,7 +136,7 @@ static inline const struct device *get_plic_dev_from_irq(uint32_t irq) } /** - * @brief return edge irq value or zero + * @brief Return the value of the trigger type register for the IRQ * * In the event edge irq is enable this will return the trigger * value of the irq. In the event edge irq is not supported this @@ -133,14 +145,19 @@ static inline const struct device *get_plic_dev_from_irq(uint32_t irq) * @param dev PLIC-instance device * @param local_irq PLIC-instance IRQ number to add to the trigger * - * @return irq value when enabled 0 otherwise + * @return Trigger type register value if PLIC supports trigger type, PLIC_TRIG_LEVEL otherwise */ -static int riscv_plic_is_edge_irq(const struct device *dev, uint32_t local_irq) +static uint32_t __maybe_unused riscv_plic_irq_trig_val(const struct device *dev, uint32_t local_irq) { + if (!IS_ENABLED(PLIC_SUPPORTS_TRIG_TYPE)) { + return PLIC_TRIG_LEVEL; + } + const struct plic_config *config = dev->config; mem_addr_t trig_addr = config->trig + local_irq_to_reg_offset(local_irq); + uint32_t offset = local_irq * PLIC_REG_TRIG_TYPE_WIDTH; - return sys_read32(trig_addr) & BIT(local_irq & PLIC_REG_MASK); + return sys_read32(trig_addr) & GENMASK(offset + PLIC_REG_TRIG_TYPE_WIDTH - 1, offset); } static void plic_irq_enable_set_state(uint32_t irq, bool enable) @@ -259,7 +276,7 @@ static void plic_irq_handler(const struct device *dev) const struct plic_config *config = dev->config; mem_addr_t claim_complete_addr = get_claim_complete_addr(dev); struct _isr_table_entry *ite; - int edge_irq; + uint32_t __maybe_unused trig_val; /* Get the IRQ number generating the interrupt */ const uint32_t local_irq = sys_read32(claim_complete_addr); @@ -291,16 +308,16 @@ static void plic_irq_handler(const struct device *dev) z_irq_spurious(NULL); } - edge_irq = riscv_plic_is_edge_irq(dev, local_irq); - +#if IS_ENABLED(PLIC_DRV_HAS_COMPAT(andestech_nceplic100)) + trig_val = riscv_plic_irq_trig_val(dev, local_irq); /* - * For edge triggered interrupts, write to the claim_complete register - * to indicate to the PLIC controller that the IRQ has been handled - * for edge triggered interrupts. + * Edge-triggered interrupts on Andes NCEPLIC100 have to be acknowledged first before + * getting handled so that we don't miss on the next edge-triggered interrupt. */ - if (edge_irq != 0) { + if (trig_val == PLIC_TRIG_EDGE) { sys_write32(local_irq, claim_complete_addr); } +#endif const uint32_t parent_irq = COND_CODE_1(IS_ENABLED(CONFIG_DYNAMIC_INTERRUPTS), (z_get_sw_isr_irq_from_device(dev)), (0U)); @@ -318,9 +335,14 @@ static void plic_irq_handler(const struct device *dev) * PLIC controller that the IRQ has been handled * for level triggered interrupts. */ - if (edge_irq == 0) { +#if IS_ENABLED(PLIC_DRV_HAS_COMPAT(andestech_nceplic100)) + /* For NCEPLIC100, handle only if level-triggered */ + if (trig_val == PLIC_TRIG_LEVEL) { sys_write32(local_irq, claim_complete_addr); } +#else + sys_write32(local_irq, claim_complete_addr); +#endif } /** @@ -495,7 +517,8 @@ SHELL_CMD_ARG_REGISTER(plic, &plic_cmds, "PLIC shell commands", .prio = PLIC_BASE_ADDR(n) + PLIC_REG_PRIO_OFFSET, \ .irq_en = PLIC_BASE_ADDR(n) + PLIC_REG_IRQ_EN_OFFSET, \ .reg = PLIC_BASE_ADDR(n) + PLIC_REG_REGS_OFFSET, \ - .trig = PLIC_BASE_ADDR(n) + PLIC_REG_TRIG_TYPE_OFFSET, \ + IF_ENABLED(PLIC_SUPPORTS_TRIG_TYPE, \ + (.trig = PLIC_BASE_ADDR(n) + PLIC_REG_TRIG_TYPE_OFFSET,)) \ .max_prio = DT_INST_PROP(n, riscv_max_priority), \ .num_irqs = DT_INST_PROP(n, riscv_ndev), \ .irq_config_func = plic_irq_config_func_##n, \ diff --git a/dts/riscv/andes/andes_v5_ae350.dtsi b/dts/riscv/andes/andes_v5_ae350.dtsi index 7af3e25ef62..8c008634ddf 100644 --- a/dts/riscv/andes/andes_v5_ae350.dtsi +++ b/dts/riscv/andes/andes_v5_ae350.dtsi @@ -167,7 +167,7 @@ ranges; plic0: interrupt-controller@e4000000 { - compatible = "sifive,plic-1.0.0"; + compatible = "sifive,plic-1.0.0", "andestech,nceplic100"; #address-cells = <1>; #interrupt-cells = <2>; interrupt-controller; From 22447c9736dddcf2205563193c5fee752fefbee2 Mon Sep 17 00:00:00 2001 From: Daniel Leung Date: Mon, 4 Dec 2023 16:22:31 -0800 Subject: [PATCH 0925/3723] kernel: mmu: fix typo K_DIRECT_MAP to K_MEM_DIRECT_MAP Fix typo in comment to reflect the actual macro named K_MEM_DIRECT_MAP. Signed-off-by: Daniel Leung --- kernel/mmu.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/kernel/mmu.c b/kernel/mmu.c index f3133926a42..eb1d95ec684 100644 --- a/kernel/mmu.c +++ b/kernel/mmu.c @@ -242,7 +242,7 @@ static void virt_region_free(void *vaddr, size_t size) } #ifndef CONFIG_KERNEL_DIRECT_MAP - /* Without the need to support K_DIRECT_MAP, the region must be + /* Without the need to support K_MEM_DIRECT_MAP, the region must be * able to be represented in the bitmap. So this case is * simple. */ @@ -259,7 +259,7 @@ static void virt_region_free(void *vaddr, size_t size) num_bits = size / CONFIG_MMU_PAGE_SIZE; (void)sys_bitarray_free(&virt_region_bitmap, num_bits, offset); #else /* !CONFIG_KERNEL_DIRECT_MAP */ - /* With K_DIRECT_MAP, the region can be outside of the virtual + /* With K_MEM_DIRECT_MAP, the region can be outside of the virtual * memory space, wholly within it, or overlap partially. * So additional processing is needed to make sure we only * mark the pages within the bitmap. From 397c0011811fa660faf845be8de82d62afd77872 Mon Sep 17 00:00:00 2001 From: Daniel Leung Date: Tue, 21 Nov 2023 16:09:00 -0800 Subject: [PATCH 0926/3723] doc: kernel/mm: add a page about virtual memory This adds a page about virtual memory under kernel's memory management. Signed-off-by: Daniel Leung --- doc/kernel/memory_management/index.rst | 1 + .../memory_management/virtual_memory.rst | 197 ++++++++++++++++++ 2 files changed, 198 insertions(+) create mode 100644 doc/kernel/memory_management/virtual_memory.rst diff --git a/doc/kernel/memory_management/index.rst b/doc/kernel/memory_management/index.rst index 7fbb03f6574..0bbf2f7a428 100644 --- a/doc/kernel/memory_management/index.rst +++ b/doc/kernel/memory_management/index.rst @@ -13,3 +13,4 @@ The following contains various topics regarding memory management. slabs.rst sys_mem_blocks.rst demand_paging.rst + virtual_memory.rst diff --git a/doc/kernel/memory_management/virtual_memory.rst b/doc/kernel/memory_management/virtual_memory.rst new file mode 100644 index 00000000000..dbc95fb7b52 --- /dev/null +++ b/doc/kernel/memory_management/virtual_memory.rst @@ -0,0 +1,197 @@ +.. _memory_management_api_virtual_memory: + +Virtual Memory +############## + +Virtual memory (VM) in Zephyr provides developers with the ability to fine tune +access to memory. To utilize virtual memory, the platform must support +Memory Management Unit (MMU) and it must be enabled in the build. Due to +the target of Zephyr mainly being embedded systems, virtual memory +support in Zephyr differs a bit from that in traditional operating +systems: + +Mapping of Kernel Image + Default is to do 1:1 mapping for the kernel image (including code and data) + between physical and virtual memory address spaces, if demand paging + is not enabled. Deviation from this requires careful manipulation of + linker script. + +Secondary Storage + Basic virtual memory support does not utilize secondary storage to + extend usable memory. The maximum usable memory is the same as + the physical memory. + + * :ref:`memory_management_api_demand_paging` enables utilizing + secondary storage as a backing store for virtual memory, thus + allowing larger usable memory than the available physical memory. + Note that demand paging needs to be explicitly enabled. + + * Although the virtual memory space can be larger than physical + memory space, without enabling demand paging, all virtually + mapped memory must be backed by physical memory. + + +Kconfigs +******** + +Required +======== + +These are the Kconfigs that need to be enabled or defined for kernel to support +virtual memory. + +* :kconfig:option:`CONFIG_MMU`: must be enabled for virtual memory support in + kernel. + +* :kconfig:option:`CONFIG_MMU_PAGE_SIZE`: size of a memory page. Default is 4KB. + +* :kconfig:option:`CONFIG_KERNEL_VM_BASE`: base address of virtual address space. + +* :kconfig:option:`CONFIG_KERNEL_VM_SIZE`: size of virtual address space. + Default is 8MB. + +* :kconfig:option:`CONFIG_KERNEL_VM_OFFSET`: kernel image starts at this offset + from :kconfig:option:`CONFIG_KERNEL_VM_BASE`. + +Optional +======== + +* :kconfig:option:`CONFIG_KERNEL_DIRECT_MAP`: permits 1:1 mappings between + virtual and physical addresses, instead of kernel choosing addresses within + the virtual address space. This is useful for mapping device MMIO regions for + more precise access control. + + +Memory Map Overview +******************* + +This is an overview of the memory map of the virtual memory address space. +Note that the ``Z_*`` macros, which are used in code, may have different +meanings depending on architecture and Kconfigs, which will be explained +below. + +.. code-block:: none + :emphasize-lines: 1, 3, 9, 22, 24 + + +--------------+ <- Z_VIRT_RAM_START + | Undefined VM | <- architecture specific reserved area + +--------------+ <- Z_KERNEL_VIRT_START + | Mapping for | + | main kernel | + | image | + | | + | | + +--------------+ <- Z_FREE_VM_START + | | + | Unused, | + | Available VM | + | | + |..............| <- grows downward as more mappings are made + | Mapping | + +--------------+ + | Mapping | + +--------------+ + | ... | + +--------------+ + | Mapping | + +--------------+ <- memory mappings start here + | Reserved | <- special purpose virtual page(s) of size Z_VM_RESERVED + +--------------+ <- Z_VIRT_RAM_END + +* ``Z_VIRT_RAM_START`` is the beginning of the virtual memory address space. + This needs to be page aligned. Currently, it is the same as + :kconfig:option:`CONFIG_KERNEL_VM_BASE`. + +* ``Z_VIRT_RAM_SIZE`` is the size of the virtual memory address space. + This needs to be page aligned. Currently, it is the same as + :kconfig:option:`CONFIG_KERNEL_VM_SIZE`. + +* ``Z_VIRT_RAM_END`` is simply (``Z_VIRT_RAM_START`` + ``Z_VIRT_RAM_SIZE``). + +* ``Z_KERNEL_VIRT_START`` is the same as ``z_mapped_start`` specified in the linker + script. This is the virtual address of the beginning of the kernel image at + boot time. + +* ``Z_KERNEL_VIRT_END`` is the same as ``z_mapped_end`` specified in the linker + script. This is the virtual address of the end of the kernel image at boot time. + +* ``Z_FREE_VM_START`` is the beginning of the virtual address space where addresses + can be allocated for memory mapping. This depends on whether + :kconfig:option:`CONFIG_ARCH_MAPS_ALL_RAM` is enabled. + + * If it is enabled, which means all physical memory are mapped in virtual + memory address space, and it is the same as + (:kconfig:option:`CONFIG_SRAM_BASE_ADDRESS` + :kconfig:option:`CONFIG_SRAM_SIZE`). + + * If it is disabled, ``Z_FREE_VM_START`` is the same ``Z_KERNEL_VIRT_END`` which + is the end of the kernel image. + +* ``Z_VM_RESERVED`` is an area reserved to support kernel functions. For example, + some addresses are reserved to support demand paging. + + +Virtual Memory Mappings +*********************** + +Setting up Mappings at Boot +=========================== + +In general, most supported architectures set up the memory mappings at boot as +following: + +* ``.text`` section is read-only and executable. It is accessible in + both kernel and user modes. + +* ``.rodata`` section is read-only and non-executable. It is accessible + in both kernel and user modes. + +* Other kernel sections, such as ``.data``, ``.bss`` and ``.noinit``, are + read-write and non-executable. They are only accessible in kernel mode. + + * Stacks for user mode threads are automatically granted read-write access + to their corresponding user mode threads during thread creation. + + * Global variables, by default, are not accessible to user mode threads. + Refer to :ref:`Memory Domains and Partitions` on how to + use global variables in user mode threads, and on how to share data + between user mode threads. + +Caching modes for these mappings are architecture specific. They can be +none, write-back, or write-through. + +Note that SoCs have their own additional mappings required to boot where +these mappings are defined under their own SoC configurations. These mappings +usually include device MMIO regions needed to setup the hardware. + + +Mapping Anonymous Memory +======================== + +The unused physical memory can be mapped in virtual address space on demand. +This is conceptually similar to memory allocation from heap, but these +mappings must be aligned on page size and have finer access control. + +* :c:func:`k_mem_map` can be used to map unused physical memory: + + * The requested size must be multiple of page size. + + * The address returned is inside the virtual address space between + ``Z_FREE_VM_START`` and ``Z_VIRT_RAM_END``. + + * The mapped region is not guaranteed to be physically contiguous in memory. + + * Guard pages immediately before and after the mapped virtual region are + automatically allocated to catch access issue due to buffer underrun + or overrun. + +* The mapped region can be unmapped (i.e. freed) via :c:func:`k_mem_unmap`: + + * Caution must be exercised to give the pass the same region size to + both :c:func:`k_mem_map` and :c:func:`k_mem_unmap`. The unmapping + function does not check if it is a valid mapped region before unmapping. + + +API Reference +************* + +.. doxygengroup:: kernel_memory_management From 48d9af46e3a528060e2958abb7975beeca162854 Mon Sep 17 00:00:00 2001 From: Yong Cong Sin Date: Thu, 16 Nov 2023 18:47:46 +0800 Subject: [PATCH 0927/3723] arch: common: multilevel irq: fix issues where the intc device is NULL The `irq` argument of the `Z_IF_DT_INTC_IRQN_EQ` macro coincides with the `'irq'` argument passed into the `DT_IRQ` macro, the former was supposed to be a number, while the latter is a string/type, together this means that it was intepreted as: ```c DT_IRQ(node_id, ) ``` instead of ```c DT_IRQ(node_id, irq) ``` as intended, so the macros never managed to match a device with the IRQ properly, resulting in the `dev` member of the table being NULL. Solve this by renaming all the `irq` args in the macros to `_irq` to avoid mixed usage. Signed-off-by: Yong Cong Sin --- arch/common/multilevel_irq.c | 20 ++++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/arch/common/multilevel_irq.c b/arch/common/multilevel_irq.c index 96f3ab0801f..790089a19c3 100644 --- a/arch/common/multilevel_irq.c +++ b/arch/common/multilevel_irq.c @@ -16,25 +16,25 @@ IF_ENABLED(DT_NODE_HAS_PROP(node_id, interrupt_controller), (code)) /* - * Expands to node_id if its IRQN is equal to `irq`, nothing otherwise - * This only works for `irq` between 0 & 4095, see `IS_EQ` + * Expands to node_id if its IRQN is equal to `_irq`, nothing otherwise + * This only works for `_irq` between 0 & 4095, see `IS_EQ` */ -#define Z_IF_DT_INTC_IRQN_EQ(node_id, irq) IF_ENABLED(IS_EQ(DT_IRQ(node_id, irq), irq), (node_id)) +#define Z_IF_DT_INTC_IRQN_EQ(node_id, _irq) IF_ENABLED(IS_EQ(DT_IRQ(node_id, irq), _irq), (node_id)) /* * Expands to node_id if it's an interrupt controller & its IRQN is `irq`, or nothing otherwise */ -#define Z_DT_INTC_GET_IRQN(node_id, irq) \ - Z_IF_DT_IS_INTC(node_id, Z_IF_DT_INTC_IRQN_EQ(node_id, irq)) +#define Z_DT_INTC_GET_IRQN(node_id, _irq) \ + Z_IF_DT_IS_INTC(node_id, Z_IF_DT_INTC_IRQN_EQ(node_id, _irq)) /** - * Loop through child of "/soc" and get root interrupt controllers with `irq` as IRQN, + * Loop through child of "/soc" and get root interrupt controllers with `_irq` as IRQN, * this assumes only one device has the IRQN - * @param irq irq number - * @return node_id(s) that has the `irq` number, or empty if none of them has the `irq` + * @param _irq irq number + * @return node_id(s) that has the `_irq` number, or empty if none of them has the `_irq` */ -#define INTC_DT_IRQN_GET(irq) \ - DT_FOREACH_CHILD_STATUS_OKAY_VARGS(DT_PATH(soc), Z_DT_INTC_GET_IRQN, irq) +#define INTC_DT_IRQN_GET(_irq) \ + DT_FOREACH_CHILD_STATUS_OKAY_VARGS(DT_PATH(soc), Z_DT_INTC_GET_IRQN, _irq) /* If can't find any matching interrupt controller, fills with `NULL` */ #define INTC_DEVICE_INIT(node_id) .dev = DEVICE_DT_GET_OR_NULL(node_id), From 0274821bb74344e851ca3e2a4d4b4450223598de Mon Sep 17 00:00:00 2001 From: Yong Cong Sin Date: Mon, 20 Nov 2023 16:44:53 +0800 Subject: [PATCH 0928/3723] arch: common: multilevel irq: move CAT_3RD_LVL_LIST into 3rd level guard The `CAT_3RD_LVL_LIST` macro is only used when `CONFIG_3RD_LEVEL_INTERRUPTS` is enabled, so move it into the compiler guard. Signed-off-by: Yong Cong Sin --- arch/common/multilevel_irq.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/arch/common/multilevel_irq.c b/arch/common/multilevel_irq.c index 790089a19c3..2c604abda17 100644 --- a/arch/common/multilevel_irq.c +++ b/arch/common/multilevel_irq.c @@ -54,12 +54,12 @@ const struct _irq_parent_entry _lvl2_irq_list[CONFIG_NUM_2ND_LEVEL_AGGREGATORS] = { LISTIFY(CONFIG_NUM_2ND_LEVEL_AGGREGATORS, CAT_2ND_LVL_LIST, (,), CONFIG_2ND_LVL_ISR_TBL_OFFSET) }; +#ifdef CONFIG_3RD_LEVEL_INTERRUPTS + #define CAT_3RD_LVL_LIST(i, base) \ INIT_IRQ_PARENT_OFFSET(INTC_DT_IRQN_GET(CONFIG_3RD_LVL_INTR_0##i##_OFFSET), \ CONFIG_3RD_LVL_INTR_0##i##_OFFSET, IRQ_INDEX_TO_OFFSET(i, base)) -#ifdef CONFIG_3RD_LEVEL_INTERRUPTS - const struct _irq_parent_entry _lvl3_irq_list[CONFIG_NUM_3RD_LEVEL_AGGREGATORS] = { LISTIFY(CONFIG_NUM_3RD_LEVEL_AGGREGATORS, CAT_3RD_LVL_LIST, (,), CONFIG_3RD_LVL_ISR_TBL_OFFSET) }; From a28da922dbb88db15200c8bdec3312ae1ec8b259 Mon Sep 17 00:00:00 2001 From: Yong Cong Sin Date: Mon, 20 Nov 2023 17:59:44 +0800 Subject: [PATCH 0929/3723] tests: interrupt: refactor the sw_isr_irq_parent_table tests Split the `sw_isr_irq_parent_table` test into one that tests the IRQ table index function which is generic and should always be tested, and one that tests multi-instance -related functions which only work in interrupt controller drivers that has multi-instance implementation. Signed-off-by: Yong Cong Sin --- tests/kernel/interrupt/src/sw_isr_table.c | 53 ++++++++++++++++------- 1 file changed, 38 insertions(+), 15 deletions(-) diff --git a/tests/kernel/interrupt/src/sw_isr_table.c b/tests/kernel/interrupt/src/sw_isr_table.c index 385f2c244b5..165dd866657 100644 --- a/tests/kernel/interrupt/src/sw_isr_table.c +++ b/tests/kernel/interrupt/src/sw_isr_table.c @@ -10,27 +10,59 @@ extern const struct _irq_parent_entry _lvl2_irq_list[]; +#if DT_HAS_COMPAT_STATUS_OKAY(sifive_plic_1_0_0) +#define INTC_SUPPORTS_MULTI_INSTANCE 1 +#endif + +/** + * @brief Test sw_isr_table index-related function(s) + * + * @details Validates that: + * - z_get_sw_isr_table_idx() returns the corresponding SW ISR table index for an IRQN + */ +ZTEST(interrupt_feature, test_sw_isr_irq_parent_table_idx) +{ + unsigned int parent_irq; + unsigned int parent_isr_offset; + unsigned int test_irq; + unsigned int test_isr_offset; + + for (size_t i = 0; i < CONFIG_NUM_2ND_LEVEL_AGGREGATORS; i++) { + parent_irq = _lvl2_irq_list[i].irq; + parent_isr_offset = _lvl2_irq_list[i].offset; + + for (unsigned int local_irq = 0; + local_irq < BIT_MASK(CONFIG_2ND_LEVEL_INTERRUPT_BITS); local_irq++) { + test_irq = irq_to_level_2(local_irq) | parent_irq; + test_isr_offset = z_get_sw_isr_table_idx(test_irq); + zassert_equal(parent_isr_offset + local_irq, test_isr_offset, + "expected offset: %d, got: %d", parent_isr_offset + local_irq, + test_isr_offset); + } + } +} + /** - * @brief Test sw_isr_table function + * @brief Test sw_isr_table device-related function(s) + * + * This test only works on driver that supports multi-instances * * @details Validates that: * - z_get_sw_isr_device_from_irq() returns the parent interrupt controller for an IRQN * - z_get_sw_isr_irq_from_device() returns the IRQN of a parent interrupt controller - * - z_get_sw_isr_table_idx() returns the corresponding SW ISR table index for an IRQN */ -ZTEST(interrupt_feature, test_sw_isr_irq_parent_table) +ZTEST(interrupt_feature, test_sw_isr_irq_parent_table_dev) { const struct device *parent_dev; unsigned int parent_irq; - unsigned int parent_isr_offset; const struct device *test_dev; unsigned int test_irq; - unsigned int test_isr_offset; + + Z_TEST_SKIP_IFNDEF(INTC_SUPPORTS_MULTI_INSTANCE); for (size_t i = 0; i < CONFIG_NUM_2ND_LEVEL_AGGREGATORS; i++) { parent_dev = _lvl2_irq_list[i].dev; parent_irq = _lvl2_irq_list[i].irq; - parent_isr_offset = _lvl2_irq_list[i].offset; for (unsigned int local_irq = 0; local_irq < BIT_MASK(CONFIG_2ND_LEVEL_INTERRUPT_BITS); local_irq++) { @@ -43,14 +75,5 @@ ZTEST(interrupt_feature, test_sw_isr_irq_parent_table) test_irq = z_get_sw_isr_irq_from_device(parent_dev); zassert_equal(parent_irq, test_irq, "expected offset: %d, got: %d", parent_irq, test_irq); - - for (unsigned int local_irq = 0; - local_irq < BIT_MASK(CONFIG_2ND_LEVEL_INTERRUPT_BITS); local_irq++) { - test_irq = irq_to_level_2(local_irq) | parent_irq; - test_isr_offset = z_get_sw_isr_table_idx(test_irq); - zassert_equal(parent_isr_offset + local_irq, test_isr_offset, - "expected offset: %d, got: %d", parent_isr_offset + local_irq, - test_isr_offset); - } } } From f3da086ac3bcd3e4e5ab2b9421b74bf90d4017b5 Mon Sep 17 00:00:00 2001 From: Yong Cong Sin Date: Mon, 20 Nov 2023 18:18:32 +0800 Subject: [PATCH 0930/3723] arch: common: sw_isr: make sure that the table index is within range Assert that the `local_irq` of each levels should only ranges from `0` to `CONFIG_MAX_IRQ_PER_AGGREGATOR`, so that it doesn't overflow the other aggregators. Also, assert that the output of `z_get_sw_isr_table_idx` shouldn't overflow the ISR table. Update the `sw_isr_table` tests to test the range of `CONFIG_MAX_IRQ_PER_AGGREGATOR` instead of the entire range of level bits. Signed-off-by: Yong Cong Sin --- arch/common/multilevel_irq.c | 15 +++++++++++---- arch/common/sw_isr_common.c | 6 +++++- tests/kernel/interrupt/src/sw_isr_table.c | 4 ++-- 3 files changed, 18 insertions(+), 7 deletions(-) diff --git a/arch/common/multilevel_irq.c b/arch/common/multilevel_irq.c index 2c604abda17..c55362cfa1f 100644 --- a/arch/common/multilevel_irq.c +++ b/arch/common/multilevel_irq.c @@ -6,7 +6,9 @@ */ #include +#include #include +#include #include /* @@ -133,28 +135,31 @@ unsigned int z_get_sw_isr_irq_from_device(const struct device *dev) unsigned int z_get_sw_isr_table_idx(unsigned int irq) { - unsigned int table_idx; - unsigned int level, parent_irq, parent_offset; + unsigned int table_idx, level, parent_irq, local_irq, parent_offset; const struct _irq_parent_entry *entry = NULL; level = irq_get_level(irq); if (level == 2U) { + local_irq = irq_from_level_2(irq); + __ASSERT_NO_MSG(local_irq < CONFIG_MAX_IRQ_PER_AGGREGATOR); parent_irq = irq_parent_level_2(irq); entry = get_parent_entry(parent_irq, _lvl2_irq_list, CONFIG_NUM_2ND_LEVEL_AGGREGATORS); parent_offset = entry != NULL ? entry->offset : 0U; - table_idx = parent_offset + irq_from_level_2(irq); + table_idx = parent_offset + local_irq; } #ifdef CONFIG_3RD_LEVEL_INTERRUPTS else if (level == 3U) { + local_irq = irq_from_level_3(irq); + __ASSERT_NO_MSG(local_irq < CONFIG_MAX_IRQ_PER_AGGREGATOR); parent_irq = irq_parent_level_3(irq); entry = get_parent_entry(parent_irq, _lvl3_irq_list, CONFIG_NUM_3RD_LEVEL_AGGREGATORS); parent_offset = entry != NULL ? entry->offset : 0U; - table_idx = parent_offset + irq_from_level_3(irq); + table_idx = parent_offset + local_irq; } #endif /* CONFIG_3RD_LEVEL_INTERRUPTS */ else { @@ -163,5 +168,7 @@ unsigned int z_get_sw_isr_table_idx(unsigned int irq) table_idx -= CONFIG_GEN_IRQ_START_VECTOR; + __ASSERT_NO_MSG(table_idx < IRQ_TABLE_SIZE); + return table_idx; } diff --git a/arch/common/sw_isr_common.c b/arch/common/sw_isr_common.c index 5efdeb89a67..43395cd5916 100644 --- a/arch/common/sw_isr_common.c +++ b/arch/common/sw_isr_common.c @@ -15,5 +15,9 @@ unsigned int __weak z_get_sw_isr_table_idx(unsigned int irq) { - return irq - CONFIG_GEN_IRQ_START_VECTOR; + unsigned int table_idx = irq - CONFIG_GEN_IRQ_START_VECTOR; + + __ASSERT_NO_MSG(table_idx < IRQ_TABLE_SIZE); + + return table_idx; } diff --git a/tests/kernel/interrupt/src/sw_isr_table.c b/tests/kernel/interrupt/src/sw_isr_table.c index 165dd866657..dac603b6d5b 100644 --- a/tests/kernel/interrupt/src/sw_isr_table.c +++ b/tests/kernel/interrupt/src/sw_isr_table.c @@ -32,7 +32,7 @@ ZTEST(interrupt_feature, test_sw_isr_irq_parent_table_idx) parent_isr_offset = _lvl2_irq_list[i].offset; for (unsigned int local_irq = 0; - local_irq < BIT_MASK(CONFIG_2ND_LEVEL_INTERRUPT_BITS); local_irq++) { + local_irq < CONFIG_MAX_IRQ_PER_AGGREGATOR; local_irq++) { test_irq = irq_to_level_2(local_irq) | parent_irq; test_isr_offset = z_get_sw_isr_table_idx(test_irq); zassert_equal(parent_isr_offset + local_irq, test_isr_offset, @@ -65,7 +65,7 @@ ZTEST(interrupt_feature, test_sw_isr_irq_parent_table_dev) parent_irq = _lvl2_irq_list[i].irq; for (unsigned int local_irq = 0; - local_irq < BIT_MASK(CONFIG_2ND_LEVEL_INTERRUPT_BITS); local_irq++) { + local_irq < CONFIG_MAX_IRQ_PER_AGGREGATOR; local_irq++) { test_irq = irq_to_level_2(local_irq) | parent_irq; test_dev = z_get_sw_isr_device_from_irq(test_irq); zassert_equal_ptr(parent_dev, test_dev, "expected dev: %p, got: %p", From 7934a473323b345e8aa3dd77fbe557cfe8dcc09e Mon Sep 17 00:00:00 2001 From: Yong Cong Sin Date: Tue, 21 Nov 2023 00:00:08 +0800 Subject: [PATCH 0931/3723] tests: interrupt: sw_isr_table: use devicetree/Kconfig as ground truth Updated the tests to use info from the devicetree or Kconfig as ground truth and compare that with the output from the functions under test. Signed-off-by: Yong Cong Sin --- tests/kernel/interrupt/src/sw_isr_table.c | 58 +++++++++++++---------- 1 file changed, 33 insertions(+), 25 deletions(-) diff --git a/tests/kernel/interrupt/src/sw_isr_table.c b/tests/kernel/interrupt/src/sw_isr_table.c index dac603b6d5b..dcd205854cd 100644 --- a/tests/kernel/interrupt/src/sw_isr_table.c +++ b/tests/kernel/interrupt/src/sw_isr_table.c @@ -10,8 +10,12 @@ extern const struct _irq_parent_entry _lvl2_irq_list[]; +#define PARENT_IRQ_FN(i, _) CONFIG_2ND_LVL_INTR_0##i##_OFFSET #if DT_HAS_COMPAT_STATUS_OKAY(sifive_plic_1_0_0) +#define PARENT_DEV_FN(i, _) DEVICE_DT_GET(DT_INST(i, sifive_plic_1_0_0)) #define INTC_SUPPORTS_MULTI_INSTANCE 1 +#else +#define PARENT_DEV_FN(i, _) (NULL) #endif /** @@ -22,22 +26,21 @@ extern const struct _irq_parent_entry _lvl2_irq_list[]; */ ZTEST(interrupt_feature, test_sw_isr_irq_parent_table_idx) { - unsigned int parent_irq; - unsigned int parent_isr_offset; - unsigned int test_irq; - unsigned int test_isr_offset; + /* ground truths */ + const unsigned int parent_irq[CONFIG_NUM_2ND_LEVEL_AGGREGATORS] = { + LISTIFY(CONFIG_NUM_2ND_LEVEL_AGGREGATORS, PARENT_IRQ_FN, (,)), + }; + const unsigned int l2_isr_offset = CONFIG_2ND_LVL_ISR_TBL_OFFSET; for (size_t i = 0; i < CONFIG_NUM_2ND_LEVEL_AGGREGATORS; i++) { - parent_irq = _lvl2_irq_list[i].irq; - parent_isr_offset = _lvl2_irq_list[i].offset; - for (unsigned int local_irq = 0; local_irq < CONFIG_MAX_IRQ_PER_AGGREGATOR; local_irq++) { - test_irq = irq_to_level_2(local_irq) | parent_irq; - test_isr_offset = z_get_sw_isr_table_idx(test_irq); - zassert_equal(parent_isr_offset + local_irq, test_isr_offset, - "expected offset: %d, got: %d", parent_isr_offset + local_irq, - test_isr_offset); + unsigned int test_irq = irq_to_level_2(local_irq) | parent_irq[i]; + unsigned int test_isr_offset = z_get_sw_isr_table_idx(test_irq); + + zassert_equal(l2_isr_offset + local_irq, test_isr_offset, + "%d: expected offset: %d, got: %d", i, + l2_isr_offset + local_irq, test_isr_offset); } } } @@ -53,27 +56,32 @@ ZTEST(interrupt_feature, test_sw_isr_irq_parent_table_idx) */ ZTEST(interrupt_feature, test_sw_isr_irq_parent_table_dev) { - const struct device *parent_dev; - unsigned int parent_irq; - const struct device *test_dev; - unsigned int test_irq; - Z_TEST_SKIP_IFNDEF(INTC_SUPPORTS_MULTI_INSTANCE); + /* ground truths */ + const struct device *parent_dev[CONFIG_NUM_2ND_LEVEL_AGGREGATORS] = { + LISTIFY(CONFIG_NUM_2ND_LEVEL_AGGREGATORS, PARENT_DEV_FN, (,)), + }; + const unsigned int parent_irq[CONFIG_NUM_2ND_LEVEL_AGGREGATORS] = { + LISTIFY(CONFIG_NUM_2ND_LEVEL_AGGREGATORS, PARENT_IRQ_FN, (,)), + }; + for (size_t i = 0; i < CONFIG_NUM_2ND_LEVEL_AGGREGATORS; i++) { - parent_dev = _lvl2_irq_list[i].dev; - parent_irq = _lvl2_irq_list[i].irq; + const struct device *test_dev; + unsigned int test_irq; + + zassert_not_null(parent_dev[i]); for (unsigned int local_irq = 0; local_irq < CONFIG_MAX_IRQ_PER_AGGREGATOR; local_irq++) { - test_irq = irq_to_level_2(local_irq) | parent_irq; + test_irq = irq_to_level_2(local_irq) | parent_irq[i]; test_dev = z_get_sw_isr_device_from_irq(test_irq); - zassert_equal_ptr(parent_dev, test_dev, "expected dev: %p, got: %p", - parent_dev, test_dev); + zassert_equal_ptr(parent_dev[i], test_dev, "%d: expected dev: %p, got: %p", + i, parent_dev[i], test_dev); } - test_irq = z_get_sw_isr_irq_from_device(parent_dev); - zassert_equal(parent_irq, test_irq, "expected offset: %d, got: %d", parent_irq, - test_irq); + test_irq = z_get_sw_isr_irq_from_device(parent_dev[i]); + zassert_equal(parent_irq[i], test_irq, "%d: expected offset: %d, got: %d", i, + parent_irq[i], test_irq); } } From 2e37da45e51932bbf1fd2fb8b6cc15a90c5d57f9 Mon Sep 17 00:00:00 2001 From: Yong Cong Sin Date: Tue, 21 Nov 2023 00:13:37 +0800 Subject: [PATCH 0932/3723] tests: interrupt: sw_isr_table: fix index test for n+1 instance The index test did not account for the level 2 table offset when testing the (n + 1) instance, fix that. Signed-off-by: Yong Cong Sin --- tests/kernel/interrupt/src/sw_isr_table.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/tests/kernel/interrupt/src/sw_isr_table.c b/tests/kernel/interrupt/src/sw_isr_table.c index dcd205854cd..f9ad6cfe847 100644 --- a/tests/kernel/interrupt/src/sw_isr_table.c +++ b/tests/kernel/interrupt/src/sw_isr_table.c @@ -37,10 +37,12 @@ ZTEST(interrupt_feature, test_sw_isr_irq_parent_table_idx) local_irq < CONFIG_MAX_IRQ_PER_AGGREGATOR; local_irq++) { unsigned int test_irq = irq_to_level_2(local_irq) | parent_irq[i]; unsigned int test_isr_offset = z_get_sw_isr_table_idx(test_irq); + unsigned int isr_offset = + l2_isr_offset + local_irq + (i * CONFIG_MAX_IRQ_PER_AGGREGATOR); - zassert_equal(l2_isr_offset + local_irq, test_isr_offset, + zassert_equal(isr_offset, test_isr_offset, "%d: expected offset: %d, got: %d", i, - l2_isr_offset + local_irq, test_isr_offset); + isr_offset, test_isr_offset); } } } From 9bfe6efbb5ad7c1d7a7567660c0ba7caaf3ff972 Mon Sep 17 00:00:00 2001 From: Yong Cong Sin Date: Tue, 21 Nov 2023 15:51:42 +0800 Subject: [PATCH 0933/3723] arch: common: multilevel irq: verify interrupt level bits configuration Add `BUILD_ASSERT`s to make sure that the interrupt bits allocated to each levels are enough to cover the number of IRQs in each respective level. Signed-off-by: Yong Cong Sin --- arch/common/multilevel_irq.c | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/arch/common/multilevel_irq.c b/arch/common/multilevel_irq.c index c55362cfa1f..53f8e03a4d8 100644 --- a/arch/common/multilevel_irq.c +++ b/arch/common/multilevel_irq.c @@ -11,6 +11,10 @@ #include #include +BUILD_ASSERT((CONFIG_NUM_2ND_LEVEL_AGGREGATORS * CONFIG_MAX_IRQ_PER_AGGREGATOR) <= + BIT(CONFIG_2ND_LEVEL_INTERRUPT_BITS), + "L2 bits not enough to cover the number of L2 IRQs"); + /* * Insert code if the node_id is an interrupt controller */ @@ -58,6 +62,10 @@ const struct _irq_parent_entry _lvl2_irq_list[CONFIG_NUM_2ND_LEVEL_AGGREGATORS] #ifdef CONFIG_3RD_LEVEL_INTERRUPTS +BUILD_ASSERT((CONFIG_NUM_3RD_LEVEL_AGGREGATORS * CONFIG_MAX_IRQ_PER_AGGREGATOR) <= + BIT(CONFIG_3RD_LEVEL_INTERRUPT_BITS), + "L3 bits not enough to cover the number of L3 IRQs"); + #define CAT_3RD_LVL_LIST(i, base) \ INIT_IRQ_PARENT_OFFSET(INTC_DT_IRQN_GET(CONFIG_3RD_LVL_INTR_0##i##_OFFSET), \ CONFIG_3RD_LVL_INTR_0##i##_OFFSET, IRQ_INDEX_TO_OFFSET(i, base)) From 85b398be657165f4c9e3b93af8a62de689d6e3e1 Mon Sep 17 00:00:00 2001 From: Adam Wojasinski Date: Fri, 1 Dec 2023 14:53:27 +0100 Subject: [PATCH 0934/3723] manifest: hal_nordic: Update revision with fixed workaround in nrfx_qspi Pulls update in nrfx_qspi driver with fixed order of applying workaround for anomaly 215 on nRF52840 and anomaly 43 on nRF5340. Signed-off-by: Adam Wojasinski --- west.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/west.yml b/west.yml index 932570330f5..522a451738d 100644 --- a/west.yml +++ b/west.yml @@ -183,7 +183,7 @@ manifest: groups: - hal - name: hal_nordic - revision: 56e0b052dff311c2f8eb08c6804e60fc79feb56f + revision: b9633ecea67bf52925d4c61455046223b46402b1 path: modules/hal/nordic groups: - hal From bc849c707816a59c75e85d415ceb6e3db3f54677 Mon Sep 17 00:00:00 2001 From: Fabio Baltieri Date: Wed, 22 Nov 2023 17:04:28 +0000 Subject: [PATCH 0935/3723] input: kbd_matrix: add print helper define Add a print helper define for the keyboard matrix row paired with the row typedef. Signed-off-by: Fabio Baltieri --- drivers/input/input_kbd_matrix.c | 2 +- include/zephyr/input/input_kbd_matrix.h | 2 ++ 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/drivers/input/input_kbd_matrix.c b/drivers/input/input_kbd_matrix.c index af3e1974687..ee830beac28 100644 --- a/drivers/input/input_kbd_matrix.c +++ b/drivers/input/input_kbd_matrix.c @@ -212,7 +212,7 @@ static bool input_kbd_matrix_check_key_events(const struct device *dev) key_pressed = input_kbd_matrix_scan(dev); for (int c = 0; c < cfg->col_size; c++) { - LOG_DBG("c=%2d u=%02x p=%02x n=%02x", + LOG_DBG("c=%2d u=" PRIkbdrow " p=" PRIkbdrow " n=" PRIkbdrow, c, cfg->matrix_unstable_state[c], cfg->matrix_previous_state[c], diff --git a/include/zephyr/input/input_kbd_matrix.h b/include/zephyr/input/input_kbd_matrix.h index 301e8b0311b..2ae1ee56b16 100644 --- a/include/zephyr/input/input_kbd_matrix.h +++ b/include/zephyr/input/input_kbd_matrix.h @@ -32,8 +32,10 @@ /** Row entry data type */ #if CONFIG_INPUT_KBD_MATRIX_16_BIT_ROW typedef uint16_t kbd_row_t; +#define PRIkbdrow "%04x" #else typedef uint8_t kbd_row_t; +#define PRIkbdrow "%02x" #endif /** Maximum number of rows */ From e4796521f229a961cf4616c8b250cc715b22c721 Mon Sep 17 00:00:00 2001 From: Fabio Baltieri Date: Wed, 22 Nov 2023 17:24:06 +0000 Subject: [PATCH 0936/3723] input: kbd_matrix: add an kbd_matrix_state shell command Add a "input kbd_matrix_state" shell command. This prints the state of a keyboard matrix in a much more compact representation than the normal input event dump, but also keeps track of any key seen during the execution and reports that on the "off" command. The output can be used to help setting the actual-key-mask property. Signed-off-by: Fabio Baltieri --- drivers/input/Kconfig.kbd_matrix | 15 +++ subsys/input/input_utils.c | 159 +++++++++++++++++++++++++++++++ 2 files changed, 174 insertions(+) diff --git a/drivers/input/Kconfig.kbd_matrix b/drivers/input/Kconfig.kbd_matrix index 4c121fe959b..e75402c7346 100644 --- a/drivers/input/Kconfig.kbd_matrix +++ b/drivers/input/Kconfig.kbd_matrix @@ -20,6 +20,21 @@ config INPUT_KBD_MATRIX_16_BIT_ROW Use a 16 bit type for the internal structure, allow using a matrix with up to 16 rows if the driver supports it. +config INPUT_SHELL_KBD_MATRIX_STATE + bool "Input kbd_matrix_state shell command" + depends on INPUT_SHELL + help + Enable an input kbd_matrix_state shell command to log the state of a + keyboard matrix device. + +config INPUT_SHELL_KBD_MATRIX_STATE_MAX_COLS + int "Maximum column count for the kbd_matrix_state command" + default 32 + depends on INPUT_SHELL_KBD_MATRIX_STATE + help + Maximum column count for a device processed by the input + kbd_matrix_state shell command. + config INPUT_KBD_DRIVE_COLUMN_HOOK bool help diff --git a/subsys/input/input_utils.c b/subsys/input/input_utils.c index c0477aad23b..0a08f1ad2fa 100644 --- a/subsys/input/input_utils.c +++ b/subsys/input/input_utils.c @@ -4,7 +4,11 @@ * SPDX-License-Identifier: Apache-2.0 */ +#include #include +#ifdef CONFIG_INPUT_SHELL_KBD_MATRIX_STATE +#include +#endif #include #include #include @@ -111,6 +115,154 @@ static int input_cmd_report(const struct shell *sh, size_t argc, char *argv[]) return 0; } +#ifdef CONFIG_INPUT_SHELL_KBD_MATRIX_STATE +static const struct device *kbd_matrix_state_dev; +static kbd_row_t kbd_matrix_state[CONFIG_INPUT_SHELL_KBD_MATRIX_STATE_MAX_COLS]; +static kbd_row_t kbd_matrix_key_mask[CONFIG_INPUT_SHELL_KBD_MATRIX_STATE_MAX_COLS]; + +/* Keep space for each column value, 2 char per byte + space. */ +#define KEY_MATRIX_ENTRY_LEN (sizeof(kbd_row_t) * 2 + 1) +#define KEY_MATRIX_BUF_SZ (CONFIG_INPUT_SHELL_KBD_MATRIX_STATE_MAX_COLS * \ + KEY_MATRIX_ENTRY_LEN) +static char kbd_matrix_buf[KEY_MATRIX_BUF_SZ]; + +static void kbd_matrix_state_log_entry(char *header, kbd_row_t *data) +{ + const struct input_kbd_matrix_common_config *cfg = kbd_matrix_state_dev->config; + char *buf = kbd_matrix_buf; + int size = sizeof(kbd_matrix_buf); + int ret; + char blank[KEY_MATRIX_ENTRY_LEN]; + int count = 0; + + memset(blank, '-', sizeof(blank) - 1); + blank[sizeof(blank) - 1] = '\0'; + + for (int i = 0; i < cfg->col_size; i++) { + char *sep = (i + 1) < cfg->col_size ? " " : ""; + + if (data[i] != 0) { + ret = snprintf(buf, size, PRIkbdrow "%s", data[i], sep); + } else { + ret = snprintf(buf, size, "%s%s", blank, sep); + } + size -= ret; + buf += ret; + + count += POPCOUNT(data[i]); + + /* Last byte is for the string termination */ + if (size < 1) { + LOG_ERR("kbd_matrix_buf too small"); + return; + } + } + + LOG_INF("%s %s [%s] (%d)", + kbd_matrix_state_dev->name, header, kbd_matrix_buf, count); +} + +static void kbd_matrix_state_log(struct input_event *evt) +{ + const struct input_kbd_matrix_common_config *cfg; + static int row, col, val; + + if (kbd_matrix_state_dev == NULL || kbd_matrix_state_dev != evt->dev) { + return; + } + + cfg = kbd_matrix_state_dev->config; + + switch (evt->code) { + case INPUT_ABS_X: + col = evt->value; + break; + case INPUT_ABS_Y: + row = evt->value; + break; + case INPUT_BTN_TOUCH: + val = evt->value; + break; + } + + if (!evt->sync) { + return; + } + + if (col > (CONFIG_INPUT_SHELL_KBD_MATRIX_STATE_MAX_COLS - 1)) { + LOG_ERR("column index too large for the state buffer: %d", col); + return; + } + + if (col > (cfg->col_size - 1)) { + LOG_ERR("invalid column index: %d", col); + return; + } + + if (row > (cfg->row_size - 1)) { + LOG_ERR("invalid row index: %d", row); + return; + } + + WRITE_BIT(kbd_matrix_state[col], row, val); + if (val != 0) { + WRITE_BIT(kbd_matrix_key_mask[col], row, 1); + } + + kbd_matrix_state_log_entry("state", kbd_matrix_state); +} +INPUT_CALLBACK_DEFINE(NULL, kbd_matrix_state_log); + +static int input_cmd_kbd_matrix_state_dump(const struct shell *sh, + size_t argc, char *argv[]) +{ + const struct device *dev; + + if (!strcmp(argv[1], "off")) { + if (kbd_matrix_state_dev != NULL) { + kbd_matrix_state_log_entry("key-mask", + kbd_matrix_key_mask); + } + + kbd_matrix_state_dev = NULL; + shell_info(sh, "Keyboard state logging disabled"); + return 0; + } + + dev = device_get_binding(argv[1]); + if (dev == NULL) { + shell_error(sh, "Invalid device: %s", argv[1]); + return -ENODEV; + } + + if (kbd_matrix_state_dev != NULL && kbd_matrix_state_dev != dev) { + shell_error(sh, "Already logging for %s, disable logging first", + kbd_matrix_state_dev->name); + return -EINVAL; + } + + memset(kbd_matrix_state, 0, sizeof(kbd_matrix_state)); + memset(kbd_matrix_key_mask, 0, sizeof(kbd_matrix_state)); + kbd_matrix_state_dev = dev; + + shell_info(sh, "Keyboard state logging enabled for %s", dev->name); + + return 0; +} + +static void device_name_get(size_t idx, struct shell_static_entry *entry) +{ + const struct device *dev = shell_device_lookup(idx, NULL); + + entry->syntax = (dev != NULL) ? dev->name : NULL; + entry->handler = NULL; + entry->help = NULL; + entry->subcmd = NULL; +} + +SHELL_DYNAMIC_CMD_CREATE(dsub_device_name, device_name_get); +#endif /* CONFIG_INPUT_SHELL_KBD_MATRIX_STATE */ + SHELL_STATIC_SUBCMD_SET_CREATE( sub_input_cmds, #ifdef CONFIG_INPUT_EVENT_DUMP @@ -119,6 +271,13 @@ SHELL_STATIC_SUBCMD_SET_CREATE( "usage: dump ", input_cmd_dump, 2, 0), #endif /* CONFIG_INPUT_EVENT_DUMP */ +#ifdef CONFIG_INPUT_SHELL_KBD_MATRIX_STATE + SHELL_CMD_ARG(kbd_matrix_state_dump, &dsub_device_name, + "Print the state of a keyboard matrix device each time a " + "key is pressed or released\n" + "usage: kbd_matrix_state_dump |off", + input_cmd_kbd_matrix_state_dump, 2, 0), +#endif /* CONFIG_INPUT_SHELL_KBD_MATRIX_STATE */ SHELL_CMD_ARG(report, NULL, "Trigger an input report event\n" "usage: report []", From fa8a7c38981bab87980f1d73ef3806915c8d7668 Mon Sep 17 00:00:00 2001 From: Fabio Baltieri Date: Wed, 22 Nov 2023 18:32:13 +0000 Subject: [PATCH 0937/3723] test: add a test for the kbd_matrix_state command Add a test for the kbd_matrix_state shell command, both 8 and 16 bit row variants. Signed-off-by: Fabio Baltieri --- .../kbd_matrix_state_dump/CMakeLists.txt | 8 +++ .../input/kbd_matrix_state_dump/Kconfig | 7 ++ .../input/kbd_matrix_state_dump/prj.conf | 12 ++++ .../input/kbd_matrix_state_dump/src/main.c | 66 +++++++++++++++++++ .../input/kbd_matrix_state_dump/testcase.yaml | 47 +++++++++++++ 5 files changed, 140 insertions(+) create mode 100644 tests/subsys/input/kbd_matrix_state_dump/CMakeLists.txt create mode 100644 tests/subsys/input/kbd_matrix_state_dump/Kconfig create mode 100644 tests/subsys/input/kbd_matrix_state_dump/prj.conf create mode 100644 tests/subsys/input/kbd_matrix_state_dump/src/main.c create mode 100644 tests/subsys/input/kbd_matrix_state_dump/testcase.yaml diff --git a/tests/subsys/input/kbd_matrix_state_dump/CMakeLists.txt b/tests/subsys/input/kbd_matrix_state_dump/CMakeLists.txt new file mode 100644 index 00000000000..0b40280dbaa --- /dev/null +++ b/tests/subsys/input/kbd_matrix_state_dump/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(input_kbd_matrix_state_dump) + +target_sources(app PRIVATE src/main.c) diff --git a/tests/subsys/input/kbd_matrix_state_dump/Kconfig b/tests/subsys/input/kbd_matrix_state_dump/Kconfig new file mode 100644 index 00000000000..2be5f756afa --- /dev/null +++ b/tests/subsys/input/kbd_matrix_state_dump/Kconfig @@ -0,0 +1,7 @@ +# Copyright 2023 Google LLC +# SPDX-License-Identifier: Apache-2.0 + +config INPUT_KBD_MATRIX + default y + +source "Kconfig.zephyr" diff --git a/tests/subsys/input/kbd_matrix_state_dump/prj.conf b/tests/subsys/input/kbd_matrix_state_dump/prj.conf new file mode 100644 index 00000000000..352a8d07f13 --- /dev/null +++ b/tests/subsys/input/kbd_matrix_state_dump/prj.conf @@ -0,0 +1,12 @@ +# SPDX-License-Identifier: Apache-2.0 + +CONFIG_LOG=y +CONFIG_LOG_MODE_MINIMAL=y +CONFIG_SHELL=y +CONFIG_SHELL_BACKEND_SERIAL=n +CONFIG_SHELL_BACKEND_DUMMY=y + +CONFIG_INPUT=y +CONFIG_INPUT_MODE_SYNCHRONOUS=y +CONFIG_INPUT_SHELL=y +CONFIG_INPUT_SHELL_KBD_MATRIX_STATE=y diff --git a/tests/subsys/input/kbd_matrix_state_dump/src/main.c b/tests/subsys/input/kbd_matrix_state_dump/src/main.c new file mode 100644 index 00000000000..42e3f532cdc --- /dev/null +++ b/tests/subsys/input/kbd_matrix_state_dump/src/main.c @@ -0,0 +1,66 @@ +/* + * Copyright 2023 Google LLC + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include +#include +#include +#include +#include +#include + +static const struct input_kbd_matrix_common_config test_cfg = { + .row_size = INPUT_KBD_MATRIX_ROW_BITS, + .col_size = 4, +}; + +DEVICE_DEFINE(kbd_matrix, "kbd-matrix", NULL, NULL, + NULL, &test_cfg, + POST_KERNEL, CONFIG_KERNEL_INIT_PRIORITY_DEVICE, NULL); + +static void report_matrix_entry(int row, int col, int val) +{ + const struct device *dev = &DEVICE_NAME_GET(kbd_matrix); + + input_report_abs(dev, INPUT_ABS_X, col, false, K_FOREVER); + input_report_abs(dev, INPUT_ABS_Y, row, false, K_FOREVER); + input_report_key(dev, INPUT_BTN_TOUCH, val, true, K_FOREVER); +} + +int main(void) +{ + const struct shell *sh = shell_backend_dummy_get_ptr(); + int err; + + err = shell_execute_cmd(sh, "input kbd_matrix_state_dump kbd-matrix"); + if (err) { + printf("Failed to execute the shell command: %d\n", err); + } + + report_matrix_entry(0, 0, 1); + report_matrix_entry(4, 0, 1); + report_matrix_entry(1, 1, 1); + report_matrix_entry(2, 2, 1); + + report_matrix_entry(0, 0, 0); + report_matrix_entry(4, 0, 0); + report_matrix_entry(1, 1, 0); + report_matrix_entry(2, 2, 0); + + report_matrix_entry(3, 3, 1); + report_matrix_entry(3, 3, 0); + +#if CONFIG_INPUT_KBD_MATRIX_16_BIT_ROW + report_matrix_entry(12, 0, 1); + report_matrix_entry(12, 0, 0); +#endif + + err = shell_execute_cmd(sh, "input kbd_matrix_state_dump off"); + if (err) { + printf("Failed to execute the shell command: %d\n", err); + } + + return 0; +} diff --git a/tests/subsys/input/kbd_matrix_state_dump/testcase.yaml b/tests/subsys/input/kbd_matrix_state_dump/testcase.yaml new file mode 100644 index 00000000000..187a2046831 --- /dev/null +++ b/tests/subsys/input/kbd_matrix_state_dump/testcase.yaml @@ -0,0 +1,47 @@ +# SPDX-License-Identifier: Apache-2.0 + +common: + tags: input + platform_allow: + - native_posix + - native_posix_64 + - native_sim + - native_sim_64 + integration_platforms: + - native_sim + harness: console +tests: + input.kbd_matrix_state_dump: + harness_config: + type: multi_line + regex: + - "I: kbd-matrix state \\[01 -- -- --\\] \\(1\\)" + - "I: kbd-matrix state \\[11 -- -- --\\] \\(2\\)" + - "I: kbd-matrix state \\[11 02 -- --\\] \\(3\\)" + - "I: kbd-matrix state \\[11 02 04 --\\] \\(4\\)" + - "I: kbd-matrix state \\[10 02 04 --\\] \\(3\\)" + - "I: kbd-matrix state \\[-- 02 04 --\\] \\(2\\)" + - "I: kbd-matrix state \\[-- -- 04 --\\] \\(1\\)" + - "I: kbd-matrix state \\[-- -- -- --\\] \\(0\\)" + - "I: kbd-matrix state \\[-- -- -- 08\\] \\(1\\)" + - "I: kbd-matrix state \\[-- -- -- --\\] \\(0\\)" + - "I: kbd-matrix key-mask \\[11 02 04 08\\] \\(5\\)" + input.kbd_matrix_state_dump_16_bit_rows: + extra_configs: + - CONFIG_INPUT_KBD_MATRIX_16_BIT_ROW=y + harness_config: + type: multi_line + regex: + - "I: kbd-matrix state \\[0001 ---- ---- ----\\] \\(1\\)" + - "I: kbd-matrix state \\[0011 ---- ---- ----\\] \\(2\\)" + - "I: kbd-matrix state \\[0011 0002 ---- ----\\] \\(3\\)" + - "I: kbd-matrix state \\[0011 0002 0004 ----\\] \\(4\\)" + - "I: kbd-matrix state \\[0010 0002 0004 ----\\] \\(3\\)" + - "I: kbd-matrix state \\[---- 0002 0004 ----\\] \\(2\\)" + - "I: kbd-matrix state \\[---- ---- 0004 ----\\] \\(1\\)" + - "I: kbd-matrix state \\[---- ---- ---- ----\\] \\(0\\)" + - "I: kbd-matrix state \\[---- ---- ---- 0008\\] \\(1\\)" + - "I: kbd-matrix state \\[---- ---- ---- ----\\] \\(0\\)" + - "I: kbd-matrix state \\[1000 ---- ---- ----\\] \\(1\\)" + - "I: kbd-matrix state \\[---- ---- ---- ----\\] \\(0\\)" + - "I: kbd-matrix key-mask \\[1011 0002 0004 0008\\] \\(6\\)" From 72bb10dc8422f7c929c753b87b7c39f4b369feea Mon Sep 17 00:00:00 2001 From: Fabio Baltieri Date: Fri, 24 Nov 2023 18:27:11 +0000 Subject: [PATCH 0938/3723] samples: input_dump: enable shell commands by default Enable INPUT_SHELL and INPUT_KBD_MATRIX_STATE by default if the sample is compiled with CONFIG_SHELL=y. This makes it easier to use the shell commands in the sample by just enabling the shell and let any help command turn on automatically. Signed-off-by: Fabio Baltieri --- samples/subsys/input/input_dump/Kconfig | 10 ++++++++++ samples/subsys/input/input_dump/sample.yaml | 14 +++++++++----- 2 files changed, 19 insertions(+), 5 deletions(-) create mode 100644 samples/subsys/input/input_dump/Kconfig diff --git a/samples/subsys/input/input_dump/Kconfig b/samples/subsys/input/input_dump/Kconfig new file mode 100644 index 00000000000..680cafae127 --- /dev/null +++ b/samples/subsys/input/input_dump/Kconfig @@ -0,0 +1,10 @@ +# Copyright 2023 Google LLC +# SPDX-License-Identifier: Apache-2.0 + +configdefault INPUT_SHELL + default y + +configdefault INPUT_SHELL_KBD_MATRIX_STATE + default y + +source "Kconfig.zephyr" diff --git a/samples/subsys/input/input_dump/sample.yaml b/samples/subsys/input/input_dump/sample.yaml index 1fb4d9d30a9..7015f6026ae 100644 --- a/samples/subsys/input/input_dump/sample.yaml +++ b/samples/subsys/input/input_dump/sample.yaml @@ -1,8 +1,12 @@ sample: name: Input Dump +common: + tags: input + build_only: true + integration_platforms: + - native_sim tests: - sample.input.input_dump: - tags: input - build_only: true - integration_platforms: - - native_sim + sample.input.input_dump: {} + sample.input.input_dump_shell: + extra_configs: + - CONFIG_SHELL=y From 093efc444d65a6477688b5884915be5151fc62f1 Mon Sep 17 00:00:00 2001 From: Juha Heiskanen Date: Wed, 29 Nov 2023 17:51:11 +0200 Subject: [PATCH 0939/3723] modem: modem_cmux: Support modem CMUX DCE role Added missing command and message handling for use existing modem cmux for DCE role. DCE CMUX connection can be now initialized from DTE side. Signed-off-by: Juha Heiskanen --- subsys/modem/modem_cmux.c | 108 ++++++++++++++++++++++++++++++++++---- 1 file changed, 99 insertions(+), 9 deletions(-) diff --git a/subsys/modem/modem_cmux.c b/subsys/modem/modem_cmux.c index 9c95e124fc2..29ff41c1ca7 100644 --- a/subsys/modem/modem_cmux.c +++ b/subsys/modem/modem_cmux.c @@ -340,9 +340,11 @@ static void modem_cmux_acknowledge_received_frame(struct modem_cmux *cmux) } } -static void modem_cmux_on_msc_command(struct modem_cmux *cmux) +static void modem_cmux_on_msc_command(struct modem_cmux *cmux, struct modem_cmux_command *command) { - modem_cmux_acknowledge_received_frame(cmux); + if (command->type.cr) { + modem_cmux_acknowledge_received_frame(cmux); + } } static void modem_cmux_on_fcon_command(struct modem_cmux *cmux) @@ -361,17 +363,27 @@ static void modem_cmux_on_fcoff_command(struct modem_cmux *cmux) modem_cmux_acknowledge_received_frame(cmux); } -static void modem_cmux_on_cld_command(struct modem_cmux *cmux) +static void modem_cmux_on_cld_command(struct modem_cmux *cmux, struct modem_cmux_command *command) { - if (cmux->state != MODEM_CMUX_STATE_DISCONNECTING) { + if (command->type.cr) { + modem_cmux_acknowledge_received_frame(cmux); + } + + if (cmux->state != MODEM_CMUX_STATE_DISCONNECTING && + cmux->state != MODEM_CMUX_STATE_CONNECTED) { LOG_WRN("Unexpected close down"); + return; + } + + if (cmux->state == MODEM_CMUX_STATE_DISCONNECTING) { + k_work_cancel_delayable(&cmux->disconnect_work); } cmux->state = MODEM_CMUX_STATE_DISCONNECTED; k_mutex_lock(&cmux->transmit_rb_lock, K_FOREVER); cmux->flow_control_on = false; k_mutex_unlock(&cmux->transmit_rb_lock); - k_work_cancel_delayable(&cmux->disconnect_work); + modem_cmux_raise_event(cmux, MODEM_CMUX_EVENT_DISCONNECTED); k_event_clear(&cmux->event, MODEM_CMUX_EVENT_CONNECTED_BIT); k_event_post(&cmux->event, MODEM_CMUX_EVENT_DISCONNECTED_BIT); @@ -381,7 +393,6 @@ static void modem_cmux_on_control_frame_ua(struct modem_cmux *cmux) { if (cmux->state != MODEM_CMUX_STATE_CONNECTING) { LOG_DBG("Unexpected UA frame"); - return; } @@ -414,11 +425,11 @@ static void modem_cmux_on_control_frame_uih(struct modem_cmux *cmux) switch (command->type.value) { case MODEM_CMUX_COMMAND_CLD: - modem_cmux_on_cld_command(cmux); + modem_cmux_on_cld_command(cmux, command); break; case MODEM_CMUX_COMMAND_MSC: - modem_cmux_on_msc_command(cmux); + modem_cmux_on_msc_command(cmux, command); break; case MODEM_CMUX_COMMAND_FCON: @@ -435,6 +446,40 @@ static void modem_cmux_on_control_frame_uih(struct modem_cmux *cmux) } } +static void modem_cmux_connect_response_transmit(struct modem_cmux *cmux) +{ + struct modem_cmux_frame frame = { + .dlci_address = cmux->frame.dlci_address, + .cr = cmux->frame.cr, + .pf = cmux->frame.pf, + .type = MODEM_CMUX_FRAME_TYPE_UA, + .data = NULL, + .data_len = 0, + }; + + LOG_DBG("SABM/DISC request state send ack"); + modem_cmux_transmit_cmd_frame(cmux, &frame); +} + +static void modem_cmux_on_control_frame_sabm(struct modem_cmux *cmux) +{ + modem_cmux_connect_response_transmit(cmux); + + if ((cmux->state == MODEM_CMUX_STATE_CONNECTED) || + (cmux->state == MODEM_CMUX_STATE_DISCONNECTING)) { + LOG_DBG("Connect request not accepted"); + return; + } + + cmux->state = MODEM_CMUX_STATE_CONNECTED; + k_mutex_lock(&cmux->transmit_rb_lock, K_FOREVER); + cmux->flow_control_on = true; + k_mutex_unlock(&cmux->transmit_rb_lock); + modem_cmux_raise_event(cmux, MODEM_CMUX_EVENT_CONNECTED); + k_event_clear(&cmux->event, MODEM_CMUX_EVENT_DISCONNECTED_BIT); + k_event_post(&cmux->event, MODEM_CMUX_EVENT_CONNECTED_BIT); +} + static void modem_cmux_on_control_frame(struct modem_cmux *cmux) { modem_cmux_log_received_frame(&cmux->frame); @@ -448,6 +493,10 @@ static void modem_cmux_on_control_frame(struct modem_cmux *cmux) modem_cmux_on_control_frame_uih(cmux); break; + case MODEM_CMUX_FRAME_TYPE_SABM: + modem_cmux_on_control_frame_sabm(cmux); + break; + default: LOG_WRN("Unknown %s frame type", "control"); break; @@ -509,6 +558,39 @@ static void modem_cmux_on_dlci_frame_uih(struct modem_cmux_dlci *dlci) modem_pipe_notify_receive_ready(&dlci->pipe); } +static void modem_cmux_on_dlci_frame_sabm(struct modem_cmux_dlci *dlci) +{ + struct modem_cmux *cmux = dlci->cmux; + + modem_cmux_connect_response_transmit(cmux); + + if (dlci->state == MODEM_CMUX_DLCI_STATE_OPEN) { + LOG_DBG("Unexpected SABM frame"); + return; + } + + dlci->state = MODEM_CMUX_DLCI_STATE_OPEN; + modem_pipe_notify_opened(&dlci->pipe); + k_mutex_lock(&dlci->receive_rb_lock, K_FOREVER); + ring_buf_reset(&dlci->receive_rb); + k_mutex_unlock(&dlci->receive_rb_lock); +} + +static void modem_cmux_on_dlci_frame_disc(struct modem_cmux_dlci *dlci) +{ + struct modem_cmux *cmux = dlci->cmux; + + modem_cmux_connect_response_transmit(cmux); + + if (dlci->state != MODEM_CMUX_DLCI_STATE_OPEN) { + LOG_DBG("Unexpected Disc frame"); + return; + } + + dlci->state = MODEM_CMUX_DLCI_STATE_CLOSED; + modem_pipe_notify_closed(&dlci->pipe); +} + static void modem_cmux_on_dlci_frame(struct modem_cmux *cmux) { struct modem_cmux_dlci *dlci; @@ -532,6 +614,14 @@ static void modem_cmux_on_dlci_frame(struct modem_cmux *cmux) modem_cmux_on_dlci_frame_uih(dlci); break; + case MODEM_CMUX_FRAME_TYPE_SABM: + modem_cmux_on_dlci_frame_sabm(dlci); + break; + + case MODEM_CMUX_FRAME_TYPE_DISC: + modem_cmux_on_dlci_frame_disc(dlci); + break; + default: LOG_WRN("Unknown %s frame type", "DLCI"); break; @@ -996,6 +1086,7 @@ void modem_cmux_init(struct modem_cmux *cmux, const struct modem_cmux_config *co k_work_init_delayable(&cmux->connect_work, modem_cmux_connect_handler); k_work_init_delayable(&cmux->disconnect_work, modem_cmux_disconnect_handler); k_event_init(&cmux->event); + k_event_clear(&cmux->event, MODEM_CMUX_EVENT_CONNECTED_BIT); k_event_post(&cmux->event, MODEM_CMUX_EVENT_DISCONNECTED_BIT); } @@ -1071,7 +1162,6 @@ int modem_cmux_disconnect(struct modem_cmux *cmux) if (ret < 0) { return ret; } - if (k_event_wait(&cmux->event, MODEM_CMUX_EVENT_DISCONNECTED_BIT, false, MODEM_CMUX_T2_TIMEOUT) == 0) { return -EAGAIN; From 6943cd497c8e0e81816364f6570641d367172da4 Mon Sep 17 00:00:00 2001 From: Juha Heiskanen Date: Wed, 29 Nov 2023 17:47:55 +0200 Subject: [PATCH 0940/3723] tests: modem: Modem backend mock update Added possibility for link 2 modem mock instance for validating P2P communication without any data stubbing. Signed-off-by: Juha Heiskanen --- tests/subsys/modem/mock/modem_backend_mock.c | 15 +++++++++++++++ tests/subsys/modem/mock/modem_backend_mock.h | 5 +++++ 2 files changed, 20 insertions(+) diff --git a/tests/subsys/modem/mock/modem_backend_mock.c b/tests/subsys/modem/mock/modem_backend_mock.c index 55c5679f35f..0a12fc43674 100644 --- a/tests/subsys/modem/mock/modem_backend_mock.c +++ b/tests/subsys/modem/mock/modem_backend_mock.c @@ -42,6 +42,15 @@ static int modem_backend_mock_transmit(void *data, const uint8_t *buf, size_t si int ret; size = (mock->limit < size) ? mock->limit : size; + + if (mock->bridge) { + struct modem_backend_mock *t_mock = mock->bridge; + + ret = ring_buf_put(&t_mock->rx_rb, buf, size); + k_work_submit(&t_mock->received_work_item.work); + return ret; + } + ret = ring_buf_put(&mock->tx_rb, buf, size); if (modem_backend_mock_update(mock, buf, size)) { modem_backend_mock_put(mock, mock->transaction->put, @@ -130,3 +139,9 @@ void modem_backend_mock_prime(struct modem_backend_mock *mock, mock->transaction = transaction; mock->transaction_match_cnt = 0; } + +void modem_backend_mock_bridge(struct modem_backend_mock *mock_a, struct modem_backend_mock *mock_b) +{ + mock_a->bridge = mock_b; + mock_b->bridge = mock_a; +} diff --git a/tests/subsys/modem/mock/modem_backend_mock.h b/tests/subsys/modem/mock/modem_backend_mock.h index 1c221963aa8..7d9ad11bf41 100644 --- a/tests/subsys/modem/mock/modem_backend_mock.h +++ b/tests/subsys/modem/mock/modem_backend_mock.h @@ -41,6 +41,8 @@ struct modem_backend_mock { /* Max allowed read/write size */ size_t limit; + /* Mock Brige pair */ + struct modem_backend_mock *bridge; }; struct modem_backend_mock_config { @@ -63,4 +65,7 @@ void modem_backend_mock_put(struct modem_backend_mock *mock, const uint8_t *buf, void modem_backend_mock_prime(struct modem_backend_mock *mock, const struct modem_backend_mock_transaction *transaction); +void modem_backend_mock_bridge(struct modem_backend_mock *mock_a, + struct modem_backend_mock *mock_b); + #endif /* ZEPHYR_DRIVERS_MODEM_MODEM_PIPE_MOCK */ From 34d4e503745b7f2b6b572f9c994d7140214c6847 Mon Sep 17 00:00:00 2001 From: Juha Heiskanen Date: Wed, 29 Nov 2023 17:43:05 +0200 Subject: [PATCH 0941/3723] tests: mode: Modem CMUX DTE / DCE test Added unite test for for validate modem CMUX DTE & DCE role communication together. Signed-off-by: Juha Heiskanen --- .../modem/modem_cmux_pair/CMakeLists.txt | 9 + tests/subsys/modem/modem_cmux_pair/prj.conf | 9 + tests/subsys/modem/modem_cmux_pair/src/main.c | 596 ++++++++++++++++++ .../modem/modem_cmux_pair/testcase.yaml | 8 + 4 files changed, 622 insertions(+) create mode 100644 tests/subsys/modem/modem_cmux_pair/CMakeLists.txt create mode 100644 tests/subsys/modem/modem_cmux_pair/prj.conf create mode 100644 tests/subsys/modem/modem_cmux_pair/src/main.c create mode 100644 tests/subsys/modem/modem_cmux_pair/testcase.yaml diff --git a/tests/subsys/modem/modem_cmux_pair/CMakeLists.txt b/tests/subsys/modem/modem_cmux_pair/CMakeLists.txt new file mode 100644 index 00000000000..00efcc5695b --- /dev/null +++ b/tests/subsys/modem/modem_cmux_pair/CMakeLists.txt @@ -0,0 +1,9 @@ +# Copyright (c) 2023 Nordic Semiconductor ASA +# SPDX-License-Identifier: Apache-2.0 + +cmake_minimum_required(VERSION 3.20.0) +find_package(Zephyr REQUIRED HINTS $ENV{ZEPHYR_BASE}) +project(modem_cmux_pair_test) + +target_sources(app PRIVATE src/main.c ../mock/modem_backend_mock.c) +target_include_directories(app PRIVATE ../mock) diff --git a/tests/subsys/modem/modem_cmux_pair/prj.conf b/tests/subsys/modem/modem_cmux_pair/prj.conf new file mode 100644 index 00000000000..bf21fcb42ac --- /dev/null +++ b/tests/subsys/modem/modem_cmux_pair/prj.conf @@ -0,0 +1,9 @@ +# Copyright (c) 2023 Nordic Semiconductor ASA +# SPDX-License-Identifier: Apache-2.0 + +CONFIG_NO_OPTIMIZATIONS=y + +CONFIG_MODEM_MODULES=y +CONFIG_MODEM_CMUX=y + +CONFIG_ZTEST=y diff --git a/tests/subsys/modem/modem_cmux_pair/src/main.c b/tests/subsys/modem/modem_cmux_pair/src/main.c new file mode 100644 index 00000000000..6c38fd7e98b --- /dev/null +++ b/tests/subsys/modem/modem_cmux_pair/src/main.c @@ -0,0 +1,596 @@ +/* + * Copyright (c) 2023 Nordic Semiconductor ASA + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include +#include +#include + +#include +#include + +/* CMUX state flags */ +#define EVENT_CMUX_CONNECTED BIT(0) +#define EVENT_CMUX_DLCI1_OPEN BIT(1) +#define EVENT_CMUX_DLCI2_OPEN BIT(2) +#define EVENT_CMUX_DLCI1_CLOSED BIT(3) +#define EVENT_CMUX_DLCI2_CLOSED BIT(4) +#define EVENT_CMUX_DISCONNECTED BIT(5) +#define EVENT_CMUX_DLCI1_RX_DATA BIT(6) +#define EVENT_CMUX_DLCI2_RX_DATA BIT(7) + +/* CMUX DTE variables */ +static struct modem_cmux cmux_dte; +static uint8_t cmux_receive_buf[127]; +static uint8_t cmux_transmit_buf[149]; +static struct modem_cmux_dlci dlci1; +static struct modem_cmux_dlci dlci2; +static struct modem_pipe *dlci1_pipe; +static struct modem_pipe *dlci2_pipe; + +/* CMUX DCE variables */ +static struct modem_cmux cmux_dce; +static uint8_t cmux_receive_buf_dce[127]; +static uint8_t cmux_transmit_buf_dce[149]; +static struct modem_cmux_dlci dlci1_dce; +static struct modem_cmux_dlci dlci2_dce; +static struct modem_pipe *dlci1_pipe_dce; +static struct modem_pipe *dlci2_pipe_dce; + +/* DTE & DCE Event */ +static struct k_event cmux_event_dte; +static struct k_event cmux_event_dce; + +/* Backend MOCK */ +static struct modem_backend_mock bus_mock_dte; +static struct modem_backend_mock bus_mock_dce; +static uint8_t bus_mock_rx_buf[2048]; +static uint8_t bus_mock_tx_buf[2048]; +static uint8_t bus_mock_rx_buf_dce[2048]; +static uint8_t bus_mock_tx_buf_dce[2048]; +static struct modem_pipe *bus_mock_pipe; +static struct modem_pipe *bus_mock_pipe_dce; + +static uint8_t dlci1_receive_buf[127]; +static uint8_t dlci2_receive_buf[127]; +static uint8_t dlci1_receive_buf_dce[127]; +static uint8_t dlci2_receive_buf_dce[127]; + +static uint8_t buffer1[2048]; +static uint8_t buffer2[2048]; + +static void test_dlci1_pipe_cb(struct modem_pipe *pipe, enum modem_pipe_event event, + void *user_data) +{ + switch (event) { + case MODEM_PIPE_EVENT_OPENED: + k_event_post(&cmux_event_dte, EVENT_CMUX_DLCI1_OPEN); + break; + + case MODEM_PIPE_EVENT_CLOSED: + k_event_post(&cmux_event_dte, EVENT_CMUX_DLCI1_CLOSED); + break; + + case MODEM_PIPE_EVENT_RECEIVE_READY: + k_event_post(&cmux_event_dte, EVENT_CMUX_DLCI1_RX_DATA); + break; + + default: + break; + } +} + +static void test_dlci2_pipe_cb(struct modem_pipe *pipe, enum modem_pipe_event event, + void *user_data) +{ + switch (event) { + case MODEM_PIPE_EVENT_OPENED: + k_event_post(&cmux_event_dte, EVENT_CMUX_DLCI2_OPEN); + break; + + case MODEM_PIPE_EVENT_CLOSED: + k_event_post(&cmux_event_dte, EVENT_CMUX_DLCI2_CLOSED); + break; + case MODEM_PIPE_EVENT_RECEIVE_READY: + k_event_post(&cmux_event_dte, EVENT_CMUX_DLCI2_RX_DATA); + break; + + default: + break; + } +} + +static void test_dlci1_pipe_cb_dce(struct modem_pipe *pipe, enum modem_pipe_event event, + void *user_data) +{ + switch (event) { + case MODEM_PIPE_EVENT_OPENED: + k_event_post(&cmux_event_dce, EVENT_CMUX_DLCI1_OPEN); + break; + + case MODEM_PIPE_EVENT_CLOSED: + k_event_post(&cmux_event_dce, EVENT_CMUX_DLCI1_CLOSED); + break; + + case MODEM_PIPE_EVENT_RECEIVE_READY: + k_event_post(&cmux_event_dce, EVENT_CMUX_DLCI1_RX_DATA); + break; + + default: + break; + } +} + +static void test_dlci2_pipe_cb_dce(struct modem_pipe *pipe, enum modem_pipe_event event, + void *user_data) +{ + switch (event) { + case MODEM_PIPE_EVENT_OPENED: + k_event_post(&cmux_event_dce, EVENT_CMUX_DLCI2_OPEN); + break; + + case MODEM_PIPE_EVENT_CLOSED: + k_event_post(&cmux_event_dce, EVENT_CMUX_DLCI2_CLOSED); + break; + case MODEM_PIPE_EVENT_RECEIVE_READY: + k_event_post(&cmux_event_dce, EVENT_CMUX_DLCI2_RX_DATA); + break; + + default: + break; + } +} + +/*************************************************************************************************/ +/* DLCI2 AT CMUX frames */ +/*************************************************************************************************/ +static uint8_t cmux_frame_data_dlci2_at_cgdcont[] = { + 0x41, 0x54, 0x2B, 0x43, 0x47, 0x44, 0x43, 0x4F, 0x4E, 0x54, 0x3D, + 0x31, 0x2C, 0x22, 0x49, 0x50, 0x22, 0x2C, 0x22, 0x74, 0x72, 0x61, + 0x63, 0x6B, 0x75, 0x6E, 0x69, 0x74, 0x2E, 0x6D, 0x32, 0x6D, 0x22}; + +static uint8_t cmux_frame_data_dlci2_at_newline[] = {0x0D, 0x0A}; + +/*************************************************************************************************/ +/* DLCI1 AT CMUX frames */ +/*************************************************************************************************/ +static uint8_t cmux_frame_data_dlci1_at_at[] = {0x41, 0x54}; + +static uint8_t cmux_frame_data_dlci1_at_newline[] = {0x0D, 0x0A}; + +/*************************************************************************************************/ +/* DLCI2 PPP CMUX frames */ +/*************************************************************************************************/ +static uint8_t cmux_frame_data_dlci2_ppp_52[] = { + 0x7E, 0xFF, 0x7D, 0x23, 0xC0, 0x21, 0x7D, 0x21, 0x7D, 0x20, 0x7D, 0x20, 0x7D, + 0x38, 0x7D, 0x22, 0x7D, 0x26, 0x7D, 0x20, 0x7D, 0x20, 0x7D, 0x20, 0x7D, 0x20, + 0x7D, 0x23, 0x7D, 0x24, 0xC0, 0x23, 0x7D, 0x25, 0x7D, 0x26, 0x53, 0x96, 0x7D, + 0x38, 0xAA, 0x7D, 0x27, 0x7D, 0x22, 0x7D, 0x28, 0x7D, 0x22, 0xD5, 0xA8, 0x7E}; + +static uint8_t cmux_frame_data_dlci2_ppp_18[] = {0x7E, 0xFF, 0x7D, 0x23, 0xC0, 0x21, + 0x7D, 0x22, 0x7D, 0x21, 0x7D, 0x20, + 0x7D, 0x24, 0x7D, 0x3C, 0x90, 0x7E}; + +static void test_cmux_ctrl_cb(struct modem_cmux *cmux, enum modem_cmux_event event, void *user_data) +{ + if (event == MODEM_CMUX_EVENT_CONNECTED) { + k_event_post(&cmux_event_dte, EVENT_CMUX_CONNECTED); + return; + } + + if (event == MODEM_CMUX_EVENT_DISCONNECTED) { + k_event_post(&cmux_event_dte, EVENT_CMUX_DISCONNECTED); + return; + } +} + +static void test_cmux_ctrl_cb_dce(struct modem_cmux *cmux, enum modem_cmux_event event, + void *user_data) +{ + if (event == MODEM_CMUX_EVENT_CONNECTED) { + k_event_post(&cmux_event_dce, EVENT_CMUX_CONNECTED); + return; + } + + if (event == MODEM_CMUX_EVENT_DISCONNECTED) { + k_event_post(&cmux_event_dce, EVENT_CMUX_DISCONNECTED); + return; + } +} + +static void cmux_dte_init(void) +{ + struct modem_cmux_dlci_config dlci1_config = { + .dlci_address = 1, + .receive_buf = dlci1_receive_buf, + .receive_buf_size = sizeof(dlci1_receive_buf), + }; + + struct modem_cmux_dlci_config dlci2_config = { + .dlci_address = 2, + .receive_buf = dlci2_receive_buf, + .receive_buf_size = sizeof(dlci2_receive_buf), + }; + + struct modem_cmux_config cmux_config = { + .callback = test_cmux_ctrl_cb, + .user_data = NULL, + .receive_buf = cmux_receive_buf, + .receive_buf_size = sizeof(cmux_receive_buf), + .transmit_buf = cmux_transmit_buf, + .transmit_buf_size = ARRAY_SIZE(cmux_transmit_buf), + }; + + const struct modem_backend_mock_config bus_mock_config = { + .rx_buf = bus_mock_rx_buf, + .rx_buf_size = sizeof(bus_mock_rx_buf), + .tx_buf = bus_mock_tx_buf, + .tx_buf_size = sizeof(bus_mock_tx_buf), + .limit = 32, + }; + + modem_cmux_init(&cmux_dte, &cmux_config); + dlci1_pipe = modem_cmux_dlci_init(&cmux_dte, &dlci1, &dlci1_config); + dlci2_pipe = modem_cmux_dlci_init(&cmux_dte, &dlci2, &dlci2_config); + /* Init Backend DTE */ + bus_mock_pipe = modem_backend_mock_init(&bus_mock_dte, &bus_mock_config); + __ASSERT_NO_MSG(modem_pipe_open(bus_mock_pipe) == 0); + __ASSERT_NO_MSG(modem_cmux_attach(&cmux_dte, bus_mock_pipe) == 0); + modem_pipe_attach(dlci1_pipe, test_dlci1_pipe_cb, NULL); + modem_pipe_attach(dlci2_pipe, test_dlci2_pipe_cb, NULL); +} + +static void cmux_dce_init(void) +{ + struct modem_cmux_dlci_config dlci1_config = { + .dlci_address = 1, + .receive_buf = dlci1_receive_buf_dce, + .receive_buf_size = sizeof(dlci1_receive_buf_dce), + }; + + struct modem_cmux_dlci_config dlci2_config = { + .dlci_address = 2, + .receive_buf = dlci2_receive_buf_dce, + .receive_buf_size = sizeof(dlci2_receive_buf_dce), + }; + + struct modem_cmux_config cmux_config_dce = { + .callback = test_cmux_ctrl_cb_dce, + .user_data = NULL, + .receive_buf = cmux_receive_buf_dce, + .receive_buf_size = sizeof(cmux_receive_buf_dce), + .transmit_buf = cmux_transmit_buf_dce, + .transmit_buf_size = ARRAY_SIZE(cmux_transmit_buf_dce), + }; + + const struct modem_backend_mock_config bus_mock_config = { + .rx_buf = bus_mock_rx_buf_dce, + .rx_buf_size = sizeof(bus_mock_rx_buf_dce), + .tx_buf = bus_mock_tx_buf_dce, + .tx_buf_size = sizeof(bus_mock_tx_buf_dce), + .limit = 32, + }; + + modem_cmux_init(&cmux_dce, &cmux_config_dce); + dlci1_pipe_dce = modem_cmux_dlci_init(&cmux_dce, &dlci1_dce, &dlci1_config); + dlci2_pipe_dce = modem_cmux_dlci_init(&cmux_dce, &dlci2_dce, &dlci2_config); + /* Init Backend DCE */ + bus_mock_pipe_dce = modem_backend_mock_init(&bus_mock_dce, &bus_mock_config); + __ASSERT_NO_MSG(modem_pipe_open(bus_mock_pipe_dce) == 0); + __ASSERT_NO_MSG(modem_cmux_attach(&cmux_dce, bus_mock_pipe_dce) == 0); + modem_pipe_attach(dlci1_pipe_dce, test_dlci1_pipe_cb_dce, NULL); + modem_pipe_attach(dlci2_pipe_dce, test_dlci2_pipe_cb_dce, NULL); +} + +static void *test_setup(void) +{ + uint32_t events; + + /* Init Event mask's */ + k_event_init(&cmux_event_dte); + k_event_init(&cmux_event_dce); + + /* Init CMUX, Pipe and Backend instances */ + cmux_dte_init(); + cmux_dce_init(); + + /* Create MOCK bridge */ + modem_backend_mock_bridge(&bus_mock_dte, &bus_mock_dce); + + /* Connect CMUX by DTE */ + __ASSERT_NO_MSG(modem_cmux_connect_async(&cmux_dte) == 0); + events = k_event_wait(&cmux_event_dte, EVENT_CMUX_CONNECTED, false, K_MSEC(100)); + __ASSERT_NO_MSG((events & EVENT_CMUX_CONNECTED)); + events = k_event_wait(&cmux_event_dce, EVENT_CMUX_CONNECTED, false, K_MSEC(100)); + __ASSERT_NO_MSG((events & EVENT_CMUX_CONNECTED)); + + /* Open DLCI channels init by DTE */ + __ASSERT_NO_MSG(modem_pipe_open_async(dlci1_pipe) == 0); + events = k_event_wait(&cmux_event_dte, EVENT_CMUX_DLCI1_OPEN, false, K_MSEC(100)); + __ASSERT_NO_MSG((events & EVENT_CMUX_DLCI1_OPEN)); + events = k_event_wait(&cmux_event_dce, EVENT_CMUX_DLCI1_OPEN, false, K_MSEC(100)); + __ASSERT_NO_MSG((events & EVENT_CMUX_DLCI1_OPEN)); + + __ASSERT_NO_MSG(modem_pipe_open_async(dlci2_pipe) == 0); + events = k_event_wait(&cmux_event_dte, EVENT_CMUX_DLCI2_OPEN, false, K_MSEC(100)); + __ASSERT_NO_MSG((events & EVENT_CMUX_DLCI2_OPEN)); + events = k_event_wait(&cmux_event_dce, EVENT_CMUX_DLCI2_OPEN, false, K_MSEC(100)); + __ASSERT_NO_MSG((events & EVENT_CMUX_DLCI2_OPEN)); + + return NULL; +} + +static void test_before(void *f) +{ + /* Reset events */ + k_event_clear(&cmux_event_dte, UINT32_MAX); + k_event_clear(&cmux_event_dce, UINT32_MAX); + + /* Reset mock pipes */ + modem_backend_mock_reset(&bus_mock_dte); + modem_backend_mock_reset(&bus_mock_dce); +} + +ZTEST(modem_cmux_pair, test_modem_cmux_dce_receive_dlci2_at) +{ + int ret; + uint32_t events; + + modem_pipe_transmit(dlci2_pipe, cmux_frame_data_dlci2_at_cgdcont, + sizeof(cmux_frame_data_dlci2_at_cgdcont)); + + modem_pipe_transmit(dlci2_pipe, cmux_frame_data_dlci2_at_newline, + sizeof(cmux_frame_data_dlci2_at_newline)); + + k_msleep(100); + + events = k_event_wait(&cmux_event_dce, EVENT_CMUX_DLCI2_RX_DATA, false, K_MSEC(100)); + zassert_true((events & EVENT_CMUX_DLCI2_RX_DATA), "DLCI2 dce not rx data"); + + ret = modem_pipe_receive(dlci2_pipe_dce, buffer2, sizeof(buffer2)); + zassert_true(ret == (sizeof(cmux_frame_data_dlci2_at_cgdcont) + + sizeof(cmux_frame_data_dlci2_at_newline)), + "Incorrect number of bytes received"); + + zassert_true(memcmp(buffer2, cmux_frame_data_dlci2_at_cgdcont, + sizeof(cmux_frame_data_dlci2_at_cgdcont)) == 0, + "Incorrect data received"); + + zassert_true(memcmp(&buffer2[sizeof(cmux_frame_data_dlci2_at_cgdcont)], + cmux_frame_data_dlci2_at_newline, + sizeof(cmux_frame_data_dlci2_at_newline)) == 0, + "Incorrect data received"); +} + +ZTEST(modem_cmux_pair, test_modem_cmux_dce_receive_dlci1_at) +{ + int ret; + uint32_t events; + + modem_pipe_transmit(dlci1_pipe, cmux_frame_data_dlci1_at_at, + sizeof(cmux_frame_data_dlci1_at_at)); + modem_pipe_transmit(dlci1_pipe, cmux_frame_data_dlci1_at_newline, + sizeof(cmux_frame_data_dlci1_at_newline)); + + k_msleep(100); + + events = k_event_wait(&cmux_event_dce, EVENT_CMUX_DLCI1_RX_DATA, false, K_MSEC(100)); + zassert_true((events & EVENT_CMUX_DLCI1_RX_DATA), "DLCI1 dce not rx data"); + + ret = modem_pipe_receive(dlci1_pipe_dce, buffer1, sizeof(buffer1)); + zassert_true(ret == (sizeof(cmux_frame_data_dlci1_at_at) + + sizeof(cmux_frame_data_dlci1_at_newline)), + "Incorrect number of bytes received"); + + zassert_true(memcmp(buffer1, cmux_frame_data_dlci1_at_at, + sizeof(cmux_frame_data_dlci1_at_at)) == 0, + "Incorrect data received"); + + zassert_true(memcmp(&buffer1[sizeof(cmux_frame_data_dlci1_at_at)], + cmux_frame_data_dlci1_at_newline, + sizeof(cmux_frame_data_dlci1_at_newline)) == 0, + "Incorrect data received"); +} + +ZTEST(modem_cmux_pair, test_modem_cmux_dce_receive_dlci2_ppp) +{ + int ret; + + uint32_t events; + + modem_pipe_transmit(dlci2_pipe, cmux_frame_data_dlci2_ppp_52, + sizeof(cmux_frame_data_dlci2_ppp_52)); + modem_pipe_transmit(dlci2_pipe, cmux_frame_data_dlci2_ppp_18, + sizeof(cmux_frame_data_dlci2_ppp_18)); + + k_msleep(100); + + events = k_event_wait(&cmux_event_dce, EVENT_CMUX_DLCI2_RX_DATA, false, K_MSEC(100)); + zassert_true((events & EVENT_CMUX_DLCI2_RX_DATA), "DLCI2 dce not rx data"); + + ret = modem_pipe_receive(dlci2_pipe_dce, buffer2, sizeof(buffer2)); + zassert_true(ret == (sizeof(cmux_frame_data_dlci2_ppp_52) + + sizeof(cmux_frame_data_dlci2_ppp_18)), + "Incorrect number of bytes received"); + + zassert_true(memcmp(buffer2, cmux_frame_data_dlci2_ppp_52, + sizeof(cmux_frame_data_dlci2_ppp_52)) == 0, + "Incorrect data received"); + + zassert_true(memcmp(&buffer2[sizeof(cmux_frame_data_dlci2_ppp_52)], + cmux_frame_data_dlci2_ppp_18, + sizeof(cmux_frame_data_dlci2_ppp_18)) == 0, + "Incorrect data received"); +} + +ZTEST(modem_cmux_pair, test_modem_cmux_dce_transmit_dlci2_ppp) +{ + int ret; + uint32_t events; + + ret = modem_pipe_transmit(dlci2_pipe_dce, cmux_frame_data_dlci2_ppp_52, + sizeof(cmux_frame_data_dlci2_ppp_52)); + + zassert_true(ret == sizeof(cmux_frame_data_dlci2_ppp_52), "Failed to send DLCI2 PPP 52 %d", + ret); + ret = modem_pipe_transmit(dlci2_pipe_dce, cmux_frame_data_dlci2_ppp_18, + sizeof(cmux_frame_data_dlci2_ppp_18)); + + zassert_true(ret == sizeof(cmux_frame_data_dlci2_ppp_18), "Failed to send DLCI2 PPP 18"); + + k_msleep(100); + + events = k_event_wait(&cmux_event_dte, EVENT_CMUX_DLCI2_RX_DATA, false, K_MSEC(100)); + zassert_true((events & EVENT_CMUX_DLCI2_RX_DATA), "DLCI2 dce not rx data"); + + ret = modem_pipe_receive(dlci2_pipe, buffer2, sizeof(buffer2)); + zassert_true(ret == (sizeof(cmux_frame_data_dlci2_ppp_52) + + sizeof(cmux_frame_data_dlci2_ppp_18)), + "Incorrect number of bytes received"); + + zassert_true(memcmp(buffer2, cmux_frame_data_dlci2_ppp_52, + sizeof(cmux_frame_data_dlci2_ppp_52)) == 0, + "Incorrect data received"); + + zassert_true(memcmp(&buffer2[sizeof(cmux_frame_data_dlci2_ppp_52)], + cmux_frame_data_dlci2_ppp_18, + sizeof(cmux_frame_data_dlci2_ppp_18)) == 0, + "Incorrect data received"); +} + +ZTEST(modem_cmux_pair, test_modem_cmux_dlci1_close_open) +{ + uint32_t events; + + /* Close DLCI1 */ + zassert_true(modem_pipe_close_async(dlci1_pipe) == 0, "Failed to close DLCI1 pipe"); + k_msleep(100); + events = k_event_wait_all(&cmux_event_dte, (EVENT_CMUX_DLCI1_CLOSED), false, K_MSEC(100)); + + zassert_true((events & EVENT_CMUX_DLCI1_CLOSED), "DLCI1 not closed as expected"); + events = k_event_wait_all(&cmux_event_dce, (EVENT_CMUX_DLCI1_CLOSED), false, K_MSEC(100)); + + zassert_true((events & EVENT_CMUX_DLCI1_CLOSED), "DLCI1 not closed as expected"); + + /* Open DLCI1 */ + zassert_true(modem_pipe_open_async(dlci1_pipe) == 0, "Failed to open DLCI1 pipe"); + + k_msleep(100); + + events = k_event_wait_all(&cmux_event_dte, (EVENT_CMUX_DLCI1_OPEN), false, K_MSEC(100)); + + zassert_true((events & EVENT_CMUX_DLCI1_OPEN), "DLCI1 not opened as expected"); + events = k_event_wait_all(&cmux_event_dce, (EVENT_CMUX_DLCI1_OPEN), false, K_MSEC(100)); + + zassert_true((events & EVENT_CMUX_DLCI1_OPEN), "DLCI1 not opened as expected"); +} + +ZTEST(modem_cmux_pair, test_modem_cmux_disconnect_connect) +{ + uint32_t events; + + /* Disconnect CMUX */ + zassert_true(modem_pipe_close_async(dlci1_pipe) == 0, "Failed to close DLCI1"); + zassert_true(modem_pipe_close_async(dlci2_pipe) == 0, "Failed to close DLCI2"); + k_msleep(100); + + events = k_event_wait_all(&cmux_event_dte, + (EVENT_CMUX_DLCI1_CLOSED | EVENT_CMUX_DLCI2_CLOSED), false, + K_MSEC(100)); + + zassert_true((events & EVENT_CMUX_DLCI1_CLOSED), "Failed to close DLCI1"); + zassert_true((events & EVENT_CMUX_DLCI2_CLOSED), "Failed to close DLCI2"); + + /* Discard CMUX DLCI DISC commands */ + modem_backend_mock_reset(&bus_mock_dte); + zassert_true(modem_cmux_disconnect_async(&cmux_dte) == 0, "Failed to disconnect CMUX"); + + k_msleep(100); + + events = k_event_wait_all(&cmux_event_dte, (EVENT_CMUX_DISCONNECTED), false, K_MSEC(100)); + zassert_true((events & EVENT_CMUX_DISCONNECTED), "Failed to disconnect CMUX"); + + /* Reconnect CMUX */ + zassert_true(modem_cmux_connect_async(&cmux_dte) == 0, "Failed to connect CMUX"); + + k_msleep(100); + + events = k_event_wait_all(&cmux_event_dte, (EVENT_CMUX_CONNECTED), false, K_MSEC(100)); + zassert_true((events & EVENT_CMUX_CONNECTED), "Failed to connect CMUX"); + + /* Open DLCI1 */ + zassert_true(modem_pipe_open_async(dlci1_pipe) == 0, "Failed to open DLCI1 pipe"); + + k_msleep(100); + + events = k_event_wait_all(&cmux_event_dte, (EVENT_CMUX_DLCI1_OPEN), false, K_MSEC(100)); + + zassert_true((events & EVENT_CMUX_DLCI1_OPEN), "DLCI1 not opened as expected"); + + /* Open DLCI2 */ + zassert_true(modem_pipe_open_async(dlci2_pipe) == 0, "Failed to open DLCI2 pipe"); + + k_msleep(100); + + events = k_event_wait_all(&cmux_event_dte, (EVENT_CMUX_DLCI2_OPEN), false, K_MSEC(100)); + + zassert_true((events & EVENT_CMUX_DLCI2_OPEN), "DLCI1 not opened as expected"); +} + +ZTEST(modem_cmux_pair, test_modem_cmux_disconnect_connect_sync) +{ + uint32_t events; + + zassert_true(modem_pipe_close(dlci1_pipe) == 0, "Failed to close DLCI1"); + zassert_true(modem_pipe_close(dlci2_pipe) == 0, "Failed to close DLCI2"); + events = k_event_wait_all(&cmux_event_dce, + (EVENT_CMUX_DLCI1_CLOSED | EVENT_CMUX_DLCI2_CLOSED), false, + K_MSEC(100)); + zassert_true((events & EVENT_CMUX_DLCI1_CLOSED), "DCE DLCI1 not closed as expected"); + zassert_true((events & EVENT_CMUX_DLCI2_CLOSED), "DCE DLCI2 not closed as expected"); + + zassert_true(modem_cmux_disconnect(&cmux_dte) == 0, "Failed to disconnect CMUX"); + zassert_true(modem_cmux_disconnect(&cmux_dte) == -EALREADY, + "Should already be disconnected"); + zassert_true(modem_cmux_disconnect(&cmux_dce) == -EALREADY, + "Should already be disconnected"); + + k_msleep(100); + + zassert_true(modem_cmux_connect(&cmux_dte) == 0, "Failed to connect CMUX"); + zassert_true(modem_cmux_connect(&cmux_dte) == -EALREADY, "Should already be connected"); + zassert_true(modem_cmux_connect(&cmux_dce) == -EALREADY, "Should already be connected"); + + zassert_true(modem_pipe_open(dlci1_pipe) == 0, "Failed to open DLCI1 pipe"); + zassert_true(modem_pipe_open(dlci2_pipe) == 0, "Failed to open DLCI2 pipe"); + events = k_event_wait_all(&cmux_event_dce, (EVENT_CMUX_DLCI1_OPEN | EVENT_CMUX_DLCI2_OPEN), + false, K_MSEC(100)); + zassert_true((events & EVENT_CMUX_DLCI1_OPEN), "DCE DLCI1 not open as expected"); + zassert_true((events & EVENT_CMUX_DLCI2_OPEN), "DCE DLCI2 not open as expected"); +} + +ZTEST(modem_cmux_pair, test_modem_cmux_dlci_close_open_sync) +{ + uint32_t events; + + zassert_true(modem_pipe_close(dlci1_pipe) == 0, "Failed to close DLCI1"); + zassert_true(modem_pipe_close(dlci2_pipe) == 0, "Failed to close DLCI2"); + + events = k_event_wait_all(&cmux_event_dce, + (EVENT_CMUX_DLCI1_CLOSED | EVENT_CMUX_DLCI2_CLOSED), false, + K_MSEC(100)); + zassert_true((events & EVENT_CMUX_DLCI1_CLOSED), "DCE DLCI1 not closed as expected"); + zassert_true((events & EVENT_CMUX_DLCI2_CLOSED), "DCE DLCI2 not closed as expected"); + + zassert_true(modem_pipe_open(dlci1_pipe) == 0, "Failed to open DLCI1 pipe"); + zassert_true(modem_pipe_open(dlci2_pipe) == 0, "Failed to open DLCI2 pipe"); + /* Verify DCE side channels are open also */ + events = k_event_wait_all(&cmux_event_dce, (EVENT_CMUX_DLCI1_OPEN | EVENT_CMUX_DLCI2_OPEN), + false, K_MSEC(100)); + zassert_true((events & EVENT_CMUX_DLCI1_OPEN), "DCE DLCI1 not open as expected"); + zassert_true((events & EVENT_CMUX_DLCI2_OPEN), "DCE DLCI2 not open as expected"); +} + +ZTEST_SUITE(modem_cmux_pair, NULL, test_setup, test_before, NULL, NULL); diff --git a/tests/subsys/modem/modem_cmux_pair/testcase.yaml b/tests/subsys/modem/modem_cmux_pair/testcase.yaml new file mode 100644 index 00000000000..9d0cdf33420 --- /dev/null +++ b/tests/subsys/modem/modem_cmux_pair/testcase.yaml @@ -0,0 +1,8 @@ +# Copyright (c) 2023 Nordic Semiconductor ASA +# SPDX-License-Identifier: Apache-2.0 + +tests: + modem.modem_cmux_pair: + tags: modem_cmux + harness: ztest + platform_allow: native_sim From 51869b3e459f3872ee137ed66d25ccd1fd6ac3aa Mon Sep 17 00:00:00 2001 From: Seppo Takalo Date: Thu, 23 Nov 2023 16:57:41 +0200 Subject: [PATCH 0942/3723] test: lwm2m: Implement bootstrap tests 4 - 7 * LightweightM2M-1.1-int-4 - Bootstrap Delete * LightweightM2M-1.1-int-5 - Server Initiated Bootstrap * LightweightM2M-1.1-int-6 - Bootstrap Sequence * LightweightM2M-1.1-int-7 - Fallback to bootstrap Signed-off-by: Seppo Takalo --- tests/net/lib/lwm2m/interop/README.md | 8 +++ tests/net/lib/lwm2m/interop/prj.conf | 5 ++ .../lwm2m/interop/pytest/test_bootstrap.py | 63 ++++++++++++++++--- .../net/lib/lwm2m/interop/src/lwm2m-client.c | 11 ++++ 4 files changed, 79 insertions(+), 8 deletions(-) diff --git a/tests/net/lib/lwm2m/interop/README.md b/tests/net/lib/lwm2m/interop/README.md index 3acbfcc71f8..28d8e12ccca 100644 --- a/tests/net/lib/lwm2m/interop/README.md +++ b/tests/net/lib/lwm2m/interop/README.md @@ -125,6 +125,14 @@ Tests are written from test spec; |---------|------|-----| |LightweightM2M-1.1-int-0 - Client Initiated Bootstrap |:white_check_mark:| | |LightweightM2M-1.1-int-1 - Client Initiated Bootstrap Full (PSK) |:white_check_mark:| | +|LightweightM2M-1.1-int-2 - Client Initiated Bootstrap Full (Cert) | |testcase not implemented | +|LightweightM2M-1.1-int-3 – Simple Bootstrap from Smartcard |:large_orange_diamond:|We don't have any smartcard support.| +|LightweightM2M-1.1-int-4 - Bootstrap Delete |:white_check_mark:| | +|LightweightM2M-1.1-int-5 - Server Initiated Bootstrap |:white_check_mark:| | +|LightweightM2M-1.1-int-6 - Bootstrap Sequence |:white_check_mark:| | +|LightweightM2M-1.1-int-7 - Fallback to bootstrap |:white_check_mark:| | +|LightweightM2M-1.1-int-8 - Bootstrap Read | |Test cannot be implemented from client side.| +|LightweightM2M-1.1-int-9 - Bootstrap and Configuration Consistency | |testcase not implemented | |LightweightM2M-1.1-int-101 - Initial Registration |:white_check_mark:| | |LightweightM2M-1.1-int-102 - Registration Update |:white_check_mark:| | |LightweightM2M-1.1-int-103 - Deregistration |:large_orange_diamond:|We don't have "disabled" functionality in server object| diff --git a/tests/net/lib/lwm2m/interop/prj.conf b/tests/net/lib/lwm2m/interop/prj.conf index 07bd9a0535d..43d4e73f081 100644 --- a/tests/net/lib/lwm2m/interop/prj.conf +++ b/tests/net/lib/lwm2m/interop/prj.conf @@ -44,6 +44,11 @@ CONFIG_LWM2M_RW_OMA_TLV_SUPPORT=y CONFIG_COAP_EXTENDED_OPTIONS_LEN=y CONFIG_COAP_EXTENDED_OPTIONS_LEN_VALUE=40 +# Speed up testing, we are running in non-lossy network +CONFIG_COAP_INIT_ACK_TIMEOUT_MS=1000 +CONFIG_COAP_RANDOMIZE_ACK_TIMEOUT=n +CONFIG_LWM2M_RD_CLIENT_MAX_RETRIES=2 + # Use QUEUE mode by default CONFIG_LWM2M_QUEUE_MODE_ENABLED=y CONFIG_LWM2M_QUEUE_MODE_UPTIME=20 diff --git a/tests/net/lib/lwm2m/interop/pytest/test_bootstrap.py b/tests/net/lib/lwm2m/interop/pytest/test_bootstrap.py index 65561db0676..2a45669d912 100644 --- a/tests/net/lib/lwm2m/interop/pytest/test_bootstrap.py +++ b/tests/net/lib/lwm2m/interop/pytest/test_bootstrap.py @@ -15,9 +15,11 @@ """ import logging +import pytest from leshan import Leshan from twister_harness import Shell from twister_harness import DeviceAdapter +from conftest import Endpoint logger = logging.getLogger(__name__) @@ -29,24 +31,69 @@ # Bootstrap Interface: [0-99] # -def verify_LightweightM2M_1_1_int_0(shell: Shell, dut: DeviceAdapter): +def verify_LightweightM2M_1_1_int_0(dut: DeviceAdapter, endpoint_bootstrap: Endpoint): """LightweightM2M-1.1-int-0 - Client Initiated Bootstrap""" - dut.readlines_until(regex='.*Bootstrap started with endpoint', timeout=5.0) - dut.readlines_until(regex='.*Bootstrap registration done', timeout=5.0) - dut.readlines_until(regex='.*Bootstrap data transfer done', timeout=5.0) + dut.readlines_until(regex='.*Bootstrap transfer complete', timeout=5.0) + endpoint_bootstrap.bootstrap = True -def test_LightweightM2M_1_1_int_1(shell: Shell, dut: DeviceAdapter, leshan: Leshan, endpoint_bootstrap: str): +def test_LightweightM2M_1_1_int_1(shell: Shell, dut: DeviceAdapter, leshan: Leshan, endpoint_bootstrap: Endpoint): """LightweightM2M-1.1-int-1 - Client Initiated Bootstrap Full (PSK)""" - verify_LightweightM2M_1_1_int_0(shell, dut) + verify_LightweightM2M_1_1_int_0(dut, endpoint_bootstrap) verify_LightweightM2M_1_1_int_101(shell, dut, leshan, endpoint_bootstrap) verify_LightweightM2M_1_1_int_401(shell, leshan, endpoint_bootstrap) -def verify_LightweightM2M_1_1_int_101(shell: Shell, dut: DeviceAdapter, leshan: Leshan, endpoint: str): +def test_LightweightM2M_1_1_int_4(shell: Shell, dut: DeviceAdapter, leshan: Leshan, endpoint: Endpoint): + """LightweightM2M-1.1-int-4 - Bootstrap Delete""" + shell.exec_command('lwm2m create 1/2') + shell.exec_command('lwm2m read 1/2/0') + retval = int(shell.get_filtered_output(shell.exec_command('retval'))[0]) + assert retval == 0 + leshan.execute(endpoint, '1/0/9') + dut.readlines_until(regex='.*Registration Done', timeout=5.0) + shell.exec_command('lwm2m read 1/2/0') + retval = int(shell.get_filtered_output(shell.exec_command('retval'))[0]) + assert retval < 0 + logger.info('retval: %s', retval) + +def test_LightweightM2M_1_1_int_5(dut: DeviceAdapter, leshan: Leshan, endpoint: Endpoint): + """LightweightM2M-1.1-int-5 - Server Initiated Bootstrap""" + leshan.execute(endpoint, '1/0/9') + dut.readlines_until(regex='.*Server Initiated Bootstrap', timeout=1) + dut.readlines_until(regex='.*Bootstrap transfer complete', timeout=5.0) + dut.readlines_until(regex='.*Registration Done', timeout=5.0) + +def test_LightweightM2M_1_1_int_6(shell: Shell, dut: DeviceAdapter, endpoint: Endpoint): + """LightweightM2M-1.1-int-6 - Bootstrap Sequence""" + shell.exec_command('lwm2m stop') + dut.readlines_until(regex=r'.*Deregistration success', timeout=5) + shell.exec_command(f'lwm2m start {endpoint}') + lines = dut.readlines_until(regex='.*Registration Done', timeout=5.0) + assert not any("Bootstrap" in line for line in lines) + shell.exec_command('lwm2m stop') + dut.readlines_until(regex=r'.*Deregistration success', timeout=5) + shell.exec_command("lwm2m delete 1/0") + shell.exec_command("lwm2m delete 0/1") + shell.exec_command(f'lwm2m start {endpoint}') + lines = dut.readlines_until(regex='.*Registration Done', timeout=5.0) + assert any("Bootstrap" in line for line in lines) + +@pytest.mark.slow +def test_LightweightM2M_1_1_int_7(shell: Shell, dut: DeviceAdapter, endpoint: Endpoint): + """LightweightM2M-1.1-int-7 - Fallback to bootstrap""" + shell.exec_command('lwm2m stop') + dut.readlines_until(regex=r'.*Deregistration success', timeout=5) + shell.exec_command('lwm2m write 0/1/0 -s coaps://10.10.10.10:5684') + shell.exec_command(f'lwm2m start {endpoint}') + lines = dut.readlines_until(regex='.*Registration Done', timeout=600.0) + assert any("Bootstrap" in line for line in lines) + +def verify_LightweightM2M_1_1_int_101(shell: Shell, dut: DeviceAdapter, leshan: Leshan, endpoint: Endpoint): """LightweightM2M-1.1-int-101 - Initial Registration""" dut.readlines_until(regex='.*Registration Done', timeout=5.0) assert leshan.get(f'/clients/{endpoint}') + endpoint.registered = True -def verify_LightweightM2M_1_1_int_401(shell: Shell, leshan: Leshan, endpoint: str): +def verify_LightweightM2M_1_1_int_401(shell: Shell, leshan: Leshan, endpoint: Endpoint): """LightweightM2M-1.1-int-401 - UDP Channel Security - Pre-shared Key Mode""" lines = shell.get_filtered_output(shell.exec_command('lwm2m read 0/0/0 -s')) host = lines[0] diff --git a/tests/net/lib/lwm2m/interop/src/lwm2m-client.c b/tests/net/lib/lwm2m/interop/src/lwm2m-client.c index b6634069fbd..a150f1b41cb 100644 --- a/tests/net/lib/lwm2m/interop/src/lwm2m-client.c +++ b/tests/net/lib/lwm2m/interop/src/lwm2m-client.c @@ -73,6 +73,17 @@ int set_socketoptions(struct lwm2m_ctx *ctx) ret = -errno; LOG_ERR("Failed to enable TLS_DTLS_CID: %d", ret); } + + /* Allow DTLS handshake to timeout much faster. + * these tests run on TUN/TAP network, so there should be no network latency. + */ + uint32_t min = 100; + uint32_t max = 500; + + zsock_setsockopt(ctx->sock_fd, SOL_TLS, TLS_DTLS_HANDSHAKE_TIMEOUT_MIN, &min, + sizeof(min)); + zsock_setsockopt(ctx->sock_fd, SOL_TLS, TLS_DTLS_HANDSHAKE_TIMEOUT_MAX, &max, + sizeof(max)); } return lwm2m_set_default_sockopt(ctx); } From 725ceb72b70a836459b483a3f6634827493866f1 Mon Sep 17 00:00:00 2001 From: Seppo Takalo Date: Mon, 4 Dec 2023 13:14:53 +0200 Subject: [PATCH 0943/3723] test: lwm2m: Implement missing test case 103 Testcase 103 required "Disabled" functionality. Signed-off-by: Seppo Takalo --- tests/net/lib/lwm2m/interop/README.md | 2 +- tests/net/lib/lwm2m/interop/pytest/test_lwm2m.py | 11 +++++++++++ 2 files changed, 12 insertions(+), 1 deletion(-) diff --git a/tests/net/lib/lwm2m/interop/README.md b/tests/net/lib/lwm2m/interop/README.md index 28d8e12ccca..7df931203aa 100644 --- a/tests/net/lib/lwm2m/interop/README.md +++ b/tests/net/lib/lwm2m/interop/README.md @@ -135,7 +135,7 @@ Tests are written from test spec; |LightweightM2M-1.1-int-9 - Bootstrap and Configuration Consistency | |testcase not implemented | |LightweightM2M-1.1-int-101 - Initial Registration |:white_check_mark:| | |LightweightM2M-1.1-int-102 - Registration Update |:white_check_mark:| | -|LightweightM2M-1.1-int-103 - Deregistration |:large_orange_diamond:|We don't have "disabled" functionality in server object| +|LightweightM2M-1.1-int-103 - Deregistration |:white_check_mark:| | |LightweightM2M-1.1-int-104 - Registration Update Trigge |:white_check_mark:| | |LightweightM2M-1.1-int-105 - Discarded Register Update |:white_check_mark:| | |LightweightM2M-1.1-int-107 - Extending the lifetime of a registration |:white_check_mark:| | diff --git a/tests/net/lib/lwm2m/interop/pytest/test_lwm2m.py b/tests/net/lib/lwm2m/interop/pytest/test_lwm2m.py index ed7aaceac20..4e0ae207e8d 100644 --- a/tests/net/lib/lwm2m/interop/pytest/test_lwm2m.py +++ b/tests/net/lib/lwm2m/interop/pytest/test_lwm2m.py @@ -44,6 +44,17 @@ def test_LightweightM2M_1_1_int_102(shell: Shell, dut: DeviceAdapter, leshan: Le assert latest["lifetime"] == lifetime shell.exec_command('lwm2m write 1/0/1 -u32 86400') +def test_LightweightM2M_1_1_int_103(shell: Shell, dut: DeviceAdapter, leshan: Leshan, endpoint: str): + """LightweightM2M-1.1-int-103 - Deregistration""" + leshan.execute(endpoint, '1/0/4') + dut.readlines_until(regex='LwM2M server disabled', timeout=5.0) + dut.readlines_until(regex='Deregistration success', timeout=5.0) + # Reset timers by restarting the client + shell.exec_command('lwm2m stop') + time.sleep(1) + shell.exec_command(f'lwm2m start {endpoint}') + dut.readlines_until(regex='.*Registration Done', timeout=5.0) + def test_LightweightM2M_1_1_int_104(shell: Shell, dut: DeviceAdapter, leshan: Leshan, endpoint: str): """LightweightM2M-1.1-int-104 - Registration Update Trigger""" shell.exec_command('lwm2m update') From 683098728ab548a8fdb34c575e30e6b9b7a3ed40 Mon Sep 17 00:00:00 2001 From: Lingao Meng Date: Tue, 5 Dec 2023 10:01:19 +0800 Subject: [PATCH 0944/3723] Bluetooth: Mesh: Use memslab replace with net_buf_pool Use memslab more efficiency than net_buf_pool and consume less ram with flash resource. Signed-off-by: Lingao Meng --- subsys/bluetooth/mesh/access.c | 1 - subsys/bluetooth/mesh/adv.c | 195 ++++++++++-------- subsys/bluetooth/mesh/adv.h | 51 +++-- subsys/bluetooth/mesh/adv_ext.c | 193 +++++++++-------- subsys/bluetooth/mesh/adv_legacy.c | 65 +++--- subsys/bluetooth/mesh/app_keys.c | 1 - subsys/bluetooth/mesh/beacon.c | 49 +++-- subsys/bluetooth/mesh/cfg.c | 1 - subsys/bluetooth/mesh/cfg_srv.c | 1 - subsys/bluetooth/mesh/friend.c | 15 +- subsys/bluetooth/mesh/gatt_cli.c | 1 - subsys/bluetooth/mesh/health_srv.c | 1 - subsys/bluetooth/mesh/lpn.c | 1 - subsys/bluetooth/mesh/main.c | 1 - subsys/bluetooth/mesh/net.c | 49 +++-- subsys/bluetooth/mesh/net.h | 3 +- subsys/bluetooth/mesh/pb_adv.c | 143 +++++++------ subsys/bluetooth/mesh/pb_gatt.c | 1 - subsys/bluetooth/mesh/pb_gatt_cli.c | 1 - subsys/bluetooth/mesh/pb_gatt_srv.c | 1 - subsys/bluetooth/mesh/priv_beacon_srv.c | 1 - subsys/bluetooth/mesh/prov_device.c | 1 - subsys/bluetooth/mesh/provisioner.c | 1 - subsys/bluetooth/mesh/proxy.h | 2 +- subsys/bluetooth/mesh/proxy_cli.c | 5 +- subsys/bluetooth/mesh/proxy_cli.h | 2 +- subsys/bluetooth/mesh/proxy_msg.c | 15 +- subsys/bluetooth/mesh/proxy_msg.h | 2 +- subsys/bluetooth/mesh/proxy_srv.c | 7 +- subsys/bluetooth/mesh/rpl.c | 1 - subsys/bluetooth/mesh/rpr_srv.c | 1 - subsys/bluetooth/mesh/solicitation.c | 1 - subsys/bluetooth/mesh/statistic.c | 17 +- subsys/bluetooth/mesh/statistic.h | 4 +- subsys/bluetooth/mesh/subnet.c | 1 - subsys/bluetooth/mesh/transport.c | 31 ++- subsys/bluetooth/mesh/transport_legacy.c | 31 ++- .../bsim/bluetooth/mesh/src/test_advertiser.c | 142 +++++++------ tests/bsim/bluetooth/mesh/src/test_beacon.c | 1 - tests/bsim/bluetooth/mesh/src/test_blob.c | 2 +- tests/bsim/bluetooth/mesh/src/test_dfu.c | 1 - .../bsim/bluetooth/mesh/src/test_provision.c | 1 - tests/bsim/bluetooth/mesh/src/test_scanner.c | 1 - 43 files changed, 521 insertions(+), 524 deletions(-) diff --git a/subsys/bluetooth/mesh/access.c b/subsys/bluetooth/mesh/access.c index 81e2902afd1..f7de46fe167 100644 --- a/subsys/bluetooth/mesh/access.c +++ b/subsys/bluetooth/mesh/access.c @@ -19,7 +19,6 @@ #include "host/testing.h" #include "mesh.h" -#include "adv.h" #include "net.h" #include "lpn.h" #include "transport.h" diff --git a/subsys/bluetooth/mesh/adv.c b/subsys/bluetooth/mesh/adv.c index 548e7f3fe15..00e2a4aa7bb 100644 --- a/subsys/bluetooth/mesh/adv.c +++ b/subsys/bluetooth/mesh/adv.c @@ -17,7 +17,6 @@ #include "common/bt_str.h" -#include "adv.h" #include "net.h" #include "foundation.h" #include "beacon.h" @@ -47,124 +46,144 @@ static K_FIFO_DEFINE(bt_mesh_adv_queue); static K_FIFO_DEFINE(bt_mesh_relay_queue); static K_FIFO_DEFINE(bt_mesh_friend_queue); -void bt_mesh_adv_send_start(uint16_t duration, int err, struct bt_mesh_adv *adv) +K_MEM_SLAB_DEFINE_STATIC(local_adv_pool, sizeof(struct bt_mesh_adv), + CONFIG_BT_MESH_ADV_BUF_COUNT, __alignof__(struct bt_mesh_adv)); + +#if defined(CONFIG_BT_MESH_RELAY_BUF_COUNT) +K_MEM_SLAB_DEFINE_STATIC(relay_adv_pool, sizeof(struct bt_mesh_adv), + CONFIG_BT_MESH_RELAY_BUF_COUNT, __alignof__(struct bt_mesh_adv)); +#endif + +#if defined(CONFIG_BT_MESH_ADV_EXT_FRIEND_SEPARATE) +K_MEM_SLAB_DEFINE_STATIC(friend_adv_pool, sizeof(struct bt_mesh_adv), + CONFIG_BT_MESH_FRIEND_LPN_COUNT, __alignof__(struct bt_mesh_adv)); +#endif + +void bt_mesh_adv_send_start(uint16_t duration, int err, struct bt_mesh_adv_ctx *ctx) { - if (!adv->started) { - adv->started = 1; + if (!ctx->started) { + ctx->started = 1; - if (adv->cb && adv->cb->start) { - adv->cb->start(duration, err, adv->cb_data); + if (ctx->cb && ctx->cb->start) { + ctx->cb->start(duration, err, ctx->cb_data); } if (err) { - adv->cb = NULL; + ctx->cb = NULL; } else if (IS_ENABLED(CONFIG_BT_MESH_STATISTIC)) { - bt_mesh_stat_succeeded_count(adv); + bt_mesh_stat_succeeded_count(ctx); } } } -static void bt_mesh_adv_send_end(int err, struct bt_mesh_adv const *adv) +static void bt_mesh_adv_send_end(int err, struct bt_mesh_adv_ctx const *ctx) { - if (adv->started && adv->cb && adv->cb->end) { - adv->cb->end(err, adv->cb_data); + if (ctx->started && ctx->cb && ctx->cb->end) { + ctx->cb->end(err, ctx->cb_data); } } -static void adv_buf_destroy(struct net_buf *buf) +static struct bt_mesh_adv *adv_create_from_pool(struct k_mem_slab *buf_pool, + enum bt_mesh_adv_type type, + enum bt_mesh_adv_tag tag, + uint8_t xmit, k_timeout_t timeout) { - struct bt_mesh_adv adv = *BT_MESH_ADV(buf); + struct bt_mesh_adv_ctx *ctx; + struct bt_mesh_adv *adv; + int err; - net_buf_destroy(buf); + if (atomic_test_bit(bt_mesh.flags, BT_MESH_SUSPENDED)) { + LOG_WRN("Refusing to allocate buffer while suspended"); + return NULL; + } - bt_mesh_adv_send_end(0, &adv); -} + err = k_mem_slab_alloc(buf_pool, (void **)&adv, timeout); + if (err) { + return NULL; + } -NET_BUF_POOL_DEFINE(adv_buf_pool, CONFIG_BT_MESH_ADV_BUF_COUNT, - BT_MESH_ADV_DATA_SIZE, BT_MESH_ADV_USER_DATA_SIZE, - adv_buf_destroy); + adv->__ref = 1; -static struct bt_mesh_adv adv_local_pool[CONFIG_BT_MESH_ADV_BUF_COUNT]; + net_buf_simple_init_with_data(&adv->b, adv->__bufs, BT_MESH_ADV_DATA_SIZE); + net_buf_simple_reset(&adv->b); -#if defined(CONFIG_BT_MESH_RELAY) -NET_BUF_POOL_DEFINE(relay_buf_pool, CONFIG_BT_MESH_RELAY_BUF_COUNT, - BT_MESH_ADV_DATA_SIZE, BT_MESH_ADV_USER_DATA_SIZE, - adv_buf_destroy); + ctx = &adv->ctx; -static struct bt_mesh_adv adv_relay_pool[CONFIG_BT_MESH_RELAY_BUF_COUNT]; -#endif + (void)memset(ctx, 0, sizeof(*ctx)); -#if defined(CONFIG_BT_MESH_ADV_EXT_FRIEND_SEPARATE) -NET_BUF_POOL_DEFINE(friend_buf_pool, CONFIG_BT_MESH_FRIEND_LPN_COUNT, - BT_MESH_ADV_DATA_SIZE, BT_MESH_ADV_USER_DATA_SIZE, - adv_buf_destroy); + ctx->type = type; + ctx->tag = tag; + ctx->xmit = xmit; -static struct bt_mesh_adv adv_friend_pool[CONFIG_BT_MESH_FRIEND_LPN_COUNT]; -#endif + return adv; +} -static struct net_buf *bt_mesh_adv_create_from_pool(struct net_buf_pool *buf_pool, - struct bt_mesh_adv *adv_pool, - enum bt_mesh_adv_type type, - enum bt_mesh_adv_tag tag, - uint8_t xmit, k_timeout_t timeout) +struct bt_mesh_adv *bt_mesh_adv_ref(struct bt_mesh_adv *adv) { - struct bt_mesh_adv *adv; - struct net_buf *buf; + __ASSERT_NO_MSG(adv->__ref < UINT8_MAX); - if (atomic_test_bit(bt_mesh.flags, BT_MESH_SUSPENDED)) { - LOG_WRN("Refusing to allocate buffer while suspended"); - return NULL; - } + adv->__ref++; - buf = net_buf_alloc(buf_pool, timeout); - if (!buf) { - return NULL; + return adv; +} + +void bt_mesh_adv_unref(struct bt_mesh_adv *adv) +{ + __ASSERT_NO_MSG(adv->__ref > 0); + + if (--adv->__ref > 0) { + return; } - adv = &adv_pool[net_buf_id(buf)]; - BT_MESH_ADV(buf) = adv; + struct k_mem_slab *slab = &local_adv_pool; + struct bt_mesh_adv_ctx ctx = adv->ctx; - (void)memset(adv, 0, sizeof(*adv)); +#if defined(CONFIG_BT_MESH_RELAY) + if (adv->ctx.tag == BT_MESH_ADV_TAG_RELAY) { + slab = &relay_adv_pool; + } +#endif - adv->type = type; - adv->tag = tag; - adv->xmit = xmit; +#if defined(CONFIG_BT_MESH_ADV_EXT_FRIEND_SEPARATE) + if (adv->ctx.tag == BT_MESH_ADV_TAG_FRIEND) { + slab = &friend_adv_pool; + } +#endif - return buf; + k_mem_slab_free(slab, (void *)adv); + bt_mesh_adv_send_end(0, &ctx); } -struct net_buf *bt_mesh_adv_create(enum bt_mesh_adv_type type, - enum bt_mesh_adv_tag tag, - uint8_t xmit, k_timeout_t timeout) +struct bt_mesh_adv *bt_mesh_adv_create(enum bt_mesh_adv_type type, + enum bt_mesh_adv_tag tag, + uint8_t xmit, k_timeout_t timeout) { #if defined(CONFIG_BT_MESH_RELAY) if (tag == BT_MESH_ADV_TAG_RELAY) { - return bt_mesh_adv_create_from_pool(&relay_buf_pool, - adv_relay_pool, type, - tag, xmit, timeout); + return adv_create_from_pool(&relay_adv_pool, + type, tag, xmit, timeout); } #endif #if defined(CONFIG_BT_MESH_ADV_EXT_FRIEND_SEPARATE) if (tag == BT_MESH_ADV_TAG_FRIEND) { - return bt_mesh_adv_create_from_pool(&friend_buf_pool, - adv_friend_pool, type, - tag, xmit, timeout); + return adv_create_from_pool(&friend_adv_pool, + type, tag, xmit, timeout); } #endif - return bt_mesh_adv_create_from_pool(&adv_buf_pool, adv_local_pool, type, - tag, xmit, timeout); + return adv_create_from_pool(&local_adv_pool, type, + tag, xmit, timeout); } -static struct net_buf *process_events(struct k_poll_event *ev, int count) +static struct bt_mesh_adv *process_events(struct k_poll_event *ev, int count) { for (; count; ev++, count--) { LOG_DBG("ev->state %u", ev->state); switch (ev->state) { case K_POLL_STATE_FIFO_DATA_AVAILABLE: - return net_buf_get(ev->fifo, K_NO_WAIT); + return k_fifo_get(ev->fifo, K_NO_WAIT); case K_POLL_STATE_NOT_READY: case K_POLL_STATE_CANCELLED: break; @@ -177,7 +196,7 @@ static struct net_buf *process_events(struct k_poll_event *ev, int count) return NULL; } -struct net_buf *bt_mesh_adv_buf_get(k_timeout_t timeout) +struct bt_mesh_adv *bt_mesh_adv_get(k_timeout_t timeout) { int err; struct k_poll_event events[] = { @@ -204,22 +223,22 @@ struct net_buf *bt_mesh_adv_buf_get(k_timeout_t timeout) return process_events(events, ARRAY_SIZE(events)); } -struct net_buf *bt_mesh_adv_buf_get_by_tag(enum bt_mesh_adv_tag_bit tags, k_timeout_t timeout) +struct bt_mesh_adv *bt_mesh_adv_get_by_tag(enum bt_mesh_adv_tag_bit tags, k_timeout_t timeout) { if (IS_ENABLED(CONFIG_BT_MESH_ADV_EXT_FRIEND_SEPARATE) && tags & BT_MESH_ADV_TAG_BIT_FRIEND) { - return net_buf_get(&bt_mesh_friend_queue, timeout); + return k_fifo_get(&bt_mesh_friend_queue, timeout); } if (IS_ENABLED(CONFIG_BT_MESH_RELAY) && !(tags & BT_MESH_ADV_TAG_BIT_LOCAL)) { - return net_buf_get(&bt_mesh_relay_queue, timeout); + return k_fifo_get(&bt_mesh_relay_queue, timeout); } - return bt_mesh_adv_buf_get(timeout); + return bt_mesh_adv_get(timeout); } -void bt_mesh_adv_buf_get_cancel(void) +void bt_mesh_adv_get_cancel(void) { LOG_DBG(""); @@ -234,38 +253,38 @@ void bt_mesh_adv_buf_get_cancel(void) } } -void bt_mesh_adv_send(struct net_buf *buf, const struct bt_mesh_send_cb *cb, +void bt_mesh_adv_send(struct bt_mesh_adv *adv, const struct bt_mesh_send_cb *cb, void *cb_data) { - LOG_DBG("type 0x%02x len %u: %s", BT_MESH_ADV(buf)->type, buf->len, - bt_hex(buf->data, buf->len)); + LOG_DBG("type 0x%02x len %u: %s", adv->ctx.type, adv->b.len, + bt_hex(adv->b.data, adv->b.len)); - BT_MESH_ADV(buf)->cb = cb; - BT_MESH_ADV(buf)->cb_data = cb_data; - BT_MESH_ADV(buf)->busy = 1U; + adv->ctx.cb = cb; + adv->ctx.cb_data = cb_data; + adv->ctx.busy = 1U; if (IS_ENABLED(CONFIG_BT_MESH_STATISTIC)) { - bt_mesh_stat_planned_count(BT_MESH_ADV(buf)); + bt_mesh_stat_planned_count(&adv->ctx); } if (IS_ENABLED(CONFIG_BT_MESH_ADV_EXT_FRIEND_SEPARATE) && - BT_MESH_ADV(buf)->tag == BT_MESH_ADV_TAG_FRIEND) { - net_buf_put(&bt_mesh_friend_queue, net_buf_ref(buf)); - bt_mesh_adv_buf_friend_ready(); + adv->ctx.tag == BT_MESH_ADV_TAG_FRIEND) { + k_fifo_put(&bt_mesh_friend_queue, bt_mesh_adv_ref(adv)); + bt_mesh_adv_friend_ready(); return; } if ((IS_ENABLED(CONFIG_BT_MESH_RELAY) && - BT_MESH_ADV(buf)->tag == BT_MESH_ADV_TAG_RELAY) || + adv->ctx.tag == BT_MESH_ADV_TAG_RELAY) || (IS_ENABLED(CONFIG_BT_MESH_PB_ADV_USE_RELAY_SETS) && - BT_MESH_ADV(buf)->tag == BT_MESH_ADV_TAG_PROV)) { - net_buf_put(&bt_mesh_relay_queue, net_buf_ref(buf)); - bt_mesh_adv_buf_relay_ready(); + adv->ctx.tag == BT_MESH_ADV_TAG_PROV)) { + k_fifo_put(&bt_mesh_relay_queue, bt_mesh_adv_ref(adv)); + bt_mesh_adv_relay_ready(); return; } - net_buf_put(&bt_mesh_adv_queue, net_buf_ref(buf)); - bt_mesh_adv_buf_local_ready(); + k_fifo_put(&bt_mesh_adv_queue, bt_mesh_adv_ref(adv)); + bt_mesh_adv_local_ready(); } int bt_mesh_adv_gatt_send(void) diff --git a/subsys/bluetooth/mesh/adv.h b/subsys/bluetooth/mesh/adv.h index 42b07601ad5..0c936a1aa52 100644 --- a/subsys/bluetooth/mesh/adv.h +++ b/subsys/bluetooth/mesh/adv.h @@ -4,14 +4,12 @@ * SPDX-License-Identifier: Apache-2.0 */ +#ifndef ZEPHYR_SUBSYS_BLUETOOTH_MESH_ADV_H_ +#define ZEPHYR_SUBSYS_BLUETOOTH_MESH_ADV_H_ + /* Maximum advertising data payload for a single data type */ #define BT_MESH_ADV_DATA_SIZE 29 -/* The user data is a pointer (4 bytes) to struct bt_mesh_adv */ -#define BT_MESH_ADV_USER_DATA_SIZE 4 - -#define BT_MESH_ADV(buf) (*(struct bt_mesh_adv **)net_buf_user_data(buf)) - #define BT_MESH_ADV_SCAN_UNIT(_ms) ((_ms) * 8 / 5) #define BT_MESH_SCAN_INTERVAL_MS 30 #define BT_MESH_SCAN_WINDOW_MS 30 @@ -41,7 +39,7 @@ enum bt_mesh_adv_tag_bit { BT_MESH_ADV_TAG_BIT_PROV = BIT(BT_MESH_ADV_TAG_PROV), }; -struct bt_mesh_adv { +struct bt_mesh_adv_ctx { const struct bt_mesh_send_cb *cb; void *cb_data; @@ -53,24 +51,39 @@ struct bt_mesh_adv { uint8_t xmit; }; +struct bt_mesh_adv { + sys_snode_t node; + + struct bt_mesh_adv_ctx ctx; + + struct net_buf_simple b; + + uint8_t __ref; + + uint8_t __bufs[BT_MESH_ADV_DATA_SIZE]; +}; + /* Lookup table for Advertising data types for bt_mesh_adv_type: */ extern const uint8_t bt_mesh_adv_type[BT_MESH_ADV_TYPES]; +struct bt_mesh_adv *bt_mesh_adv_ref(struct bt_mesh_adv *adv); +void bt_mesh_adv_unref(struct bt_mesh_adv *adv); + /* xmit_count: Number of retransmissions, i.e. 0 == 1 transmission */ -struct net_buf *bt_mesh_adv_create(enum bt_mesh_adv_type type, - enum bt_mesh_adv_tag tag, - uint8_t xmit, k_timeout_t timeout); +struct bt_mesh_adv *bt_mesh_adv_create(enum bt_mesh_adv_type type, + enum bt_mesh_adv_tag tag, + uint8_t xmit, k_timeout_t timeout); -void bt_mesh_adv_send(struct net_buf *buf, const struct bt_mesh_send_cb *cb, +void bt_mesh_adv_send(struct bt_mesh_adv *adv, const struct bt_mesh_send_cb *cb, void *cb_data); -struct net_buf *bt_mesh_adv_buf_get(k_timeout_t timeout); +struct bt_mesh_adv *bt_mesh_adv_get(k_timeout_t timeout); -struct net_buf *bt_mesh_adv_buf_get_by_tag(enum bt_mesh_adv_tag_bit tags, k_timeout_t timeout); +struct bt_mesh_adv *bt_mesh_adv_get_by_tag(enum bt_mesh_adv_tag_bit tags, k_timeout_t timeout); void bt_mesh_adv_gatt_update(void); -void bt_mesh_adv_buf_get_cancel(void); +void bt_mesh_adv_get_cancel(void); void bt_mesh_adv_init(void); @@ -83,13 +96,13 @@ int bt_mesh_adv_enable(void); /* Should not be called from work queue due to undefined behavior */ int bt_mesh_adv_disable(void); -void bt_mesh_adv_buf_local_ready(void); +void bt_mesh_adv_local_ready(void); -void bt_mesh_adv_buf_relay_ready(void); +void bt_mesh_adv_relay_ready(void); -void bt_mesh_adv_buf_terminate(const struct net_buf *buf); +void bt_mesh_adv_terminate(struct bt_mesh_adv *adv); -void bt_mesh_adv_buf_friend_ready(void); +void bt_mesh_adv_friend_ready(void); int bt_mesh_adv_gatt_send(void); @@ -97,9 +110,11 @@ int bt_mesh_adv_gatt_start(const struct bt_le_adv_param *param, int32_t duration const struct bt_data *ad, size_t ad_len, const struct bt_data *sd, size_t sd_len); -void bt_mesh_adv_send_start(uint16_t duration, int err, struct bt_mesh_adv *adv); +void bt_mesh_adv_send_start(uint16_t duration, int err, struct bt_mesh_adv_ctx *ctx); int bt_mesh_scan_active_set(bool active); int bt_mesh_adv_bt_data_send(uint8_t num_events, uint16_t adv_interval, const struct bt_data *ad, size_t ad_len); + +#endif /* ZEPHYR_SUBSYS_BLUETOOTH_MESH_ADV_H_ */ diff --git a/subsys/bluetooth/mesh/adv_ext.c b/subsys/bluetooth/mesh/adv_ext.c index 38efbb4901c..d3bc8a3af82 100644 --- a/subsys/bluetooth/mesh/adv_ext.c +++ b/subsys/bluetooth/mesh/adv_ext.c @@ -18,7 +18,6 @@ #include "host/hci_core.h" -#include "adv.h" #include "net.h" #include "proxy.h" #include "solicitation.h" @@ -60,14 +59,14 @@ struct bt_mesh_ext_adv { const enum bt_mesh_adv_tag_bit tags; ATOMIC_DEFINE(flags, ADV_FLAGS_NUM); struct bt_le_ext_adv *instance; - struct net_buf *buf; + struct bt_mesh_adv *adv; uint64_t timestamp; struct k_work_delayable work; struct bt_le_adv_param adv_param; }; static void send_pending_adv(struct k_work *work); -static bool schedule_send(struct bt_mesh_ext_adv *adv); +static bool schedule_send(struct bt_mesh_ext_adv *ext_adv); static struct bt_mesh_ext_adv advs[] = { [0] = { @@ -136,7 +135,7 @@ static inline struct bt_mesh_ext_adv *gatt_adv_get(void) } } -static int adv_start(struct bt_mesh_ext_adv *adv, +static int adv_start(struct bt_mesh_ext_adv *ext_adv, const struct bt_le_adv_param *param, struct bt_le_ext_adv_start_param *start, const struct bt_data *ad, size_t ad_len, @@ -144,47 +143,47 @@ static int adv_start(struct bt_mesh_ext_adv *adv, { int err; - if (!adv->instance) { + if (!ext_adv->instance) { LOG_ERR("Mesh advertiser not enabled"); return -ENODEV; } - if (atomic_test_and_set_bit(adv->flags, ADV_FLAG_ACTIVE)) { + if (atomic_test_and_set_bit(ext_adv->flags, ADV_FLAG_ACTIVE)) { LOG_ERR("Advertiser is busy"); return -EBUSY; } - if (atomic_test_bit(adv->flags, ADV_FLAG_UPDATE_PARAMS)) { - err = bt_le_ext_adv_update_param(adv->instance, param); + if (atomic_test_bit(ext_adv->flags, ADV_FLAG_UPDATE_PARAMS)) { + err = bt_le_ext_adv_update_param(ext_adv->instance, param); if (err) { LOG_ERR("Failed updating adv params: %d", err); - atomic_clear_bit(adv->flags, ADV_FLAG_ACTIVE); + atomic_clear_bit(ext_adv->flags, ADV_FLAG_ACTIVE); return err; } - atomic_set_bit_to(adv->flags, ADV_FLAG_UPDATE_PARAMS, - param != &adv->adv_param); + atomic_set_bit_to(ext_adv->flags, ADV_FLAG_UPDATE_PARAMS, + param != &ext_adv->adv_param); } - err = bt_le_ext_adv_set_data(adv->instance, ad, ad_len, sd, sd_len); + err = bt_le_ext_adv_set_data(ext_adv->instance, ad, ad_len, sd, sd_len); if (err) { LOG_ERR("Failed setting adv data: %d", err); - atomic_clear_bit(adv->flags, ADV_FLAG_ACTIVE); + atomic_clear_bit(ext_adv->flags, ADV_FLAG_ACTIVE); return err; } - adv->timestamp = k_uptime_get(); + ext_adv->timestamp = k_uptime_get(); - err = bt_le_ext_adv_start(adv->instance, start); + err = bt_le_ext_adv_start(ext_adv->instance, start); if (err) { LOG_ERR("Advertising failed: err %d", err); - atomic_clear_bit(adv->flags, ADV_FLAG_ACTIVE); + atomic_clear_bit(ext_adv->flags, ADV_FLAG_ACTIVE); } return err; } -static int bt_data_send(struct bt_mesh_ext_adv *adv, uint8_t num_events, uint16_t adv_interval, +static int bt_data_send(struct bt_mesh_ext_adv *ext_adv, uint8_t num_events, uint16_t adv_interval, const struct bt_data *ad, size_t ad_len) { struct bt_le_ext_adv_start_param start = { @@ -194,41 +193,41 @@ static int bt_data_send(struct bt_mesh_ext_adv *adv, uint8_t num_events, uint16_ adv_interval = MAX(ADV_INT_FAST_MS, adv_interval); /* Only update advertising parameters if they're different */ - if (adv->adv_param.interval_min != BT_MESH_ADV_SCAN_UNIT(adv_interval)) { - adv->adv_param.interval_min = BT_MESH_ADV_SCAN_UNIT(adv_interval); - adv->adv_param.interval_max = adv->adv_param.interval_min; - atomic_set_bit(adv->flags, ADV_FLAG_UPDATE_PARAMS); + if (ext_adv->adv_param.interval_min != BT_MESH_ADV_SCAN_UNIT(adv_interval)) { + ext_adv->adv_param.interval_min = BT_MESH_ADV_SCAN_UNIT(adv_interval); + ext_adv->adv_param.interval_max = ext_adv->adv_param.interval_min; + atomic_set_bit(ext_adv->flags, ADV_FLAG_UPDATE_PARAMS); } - return adv_start(adv, &adv->adv_param, &start, ad, ad_len, NULL, 0); + return adv_start(ext_adv, &ext_adv->adv_param, &start, ad, ad_len, NULL, 0); } -static int buf_send(struct bt_mesh_ext_adv *adv, struct net_buf *buf) +static int adv_send(struct bt_mesh_ext_adv *ext_adv, struct bt_mesh_adv *adv) { - uint8_t num_events = BT_MESH_TRANSMIT_COUNT(BT_MESH_ADV(buf)->xmit) + 1; + uint8_t num_events = BT_MESH_TRANSMIT_COUNT(adv->ctx.xmit) + 1; uint16_t duration, adv_int; struct bt_data ad; int err; - adv_int = BT_MESH_TRANSMIT_INT(BT_MESH_ADV(buf)->xmit); + adv_int = BT_MESH_TRANSMIT_INT(adv->ctx.xmit); /* Upper boundary estimate: */ duration = num_events * (adv_int + 10); - LOG_DBG("type %u len %u: %s", BT_MESH_ADV(buf)->type, - buf->len, bt_hex(buf->data, buf->len)); + LOG_DBG("type %u len %u: %s", adv->ctx.type, + adv->b.len, bt_hex(adv->b.data, adv->b.len)); LOG_DBG("count %u interval %ums duration %ums", num_events, adv_int, duration); - ad.type = bt_mesh_adv_type[BT_MESH_ADV(buf)->type]; - ad.data_len = buf->len; - ad.data = buf->data; + ad.type = bt_mesh_adv_type[adv->ctx.type]; + ad.data_len = adv->b.len; + ad.data = adv->b.data; - err = bt_data_send(adv, num_events, adv_int, &ad, 1); + err = bt_data_send(ext_adv, num_events, adv_int, &ad, 1); if (!err) { - adv->buf = net_buf_ref(buf); + ext_adv->adv = bt_mesh_adv_ref(adv); } - bt_mesh_adv_send_start(duration, err, BT_MESH_ADV(buf)); + bt_mesh_adv_send_start(duration, err, &adv->ctx); return err; } @@ -243,50 +242,50 @@ static const char * const adv_tag_to_str[] = { static void send_pending_adv(struct k_work *work) { - struct bt_mesh_ext_adv *adv; - struct net_buf *buf; + struct bt_mesh_ext_adv *ext_adv; + struct bt_mesh_adv *adv; int err; - adv = CONTAINER_OF(work, struct bt_mesh_ext_adv, work.work); + ext_adv = CONTAINER_OF(work, struct bt_mesh_ext_adv, work.work); - if (atomic_test_and_clear_bit(adv->flags, ADV_FLAG_SENT)) { + if (atomic_test_and_clear_bit(ext_adv->flags, ADV_FLAG_SENT)) { /* Calling k_uptime_delta on a timestamp moves it to the current time. * This is essential here, as schedule_send() uses the end of the event * as a reference to avoid sending the next advertisement too soon. */ - int64_t duration = k_uptime_delta(&adv->timestamp); + int64_t duration = k_uptime_delta(&ext_adv->timestamp); LOG_DBG("Advertising stopped after %u ms for %s", (uint32_t)duration, - adv->buf ? adv_tag_to_str[BT_MESH_ADV(adv->buf)->tag] : + ext_adv->adv ? adv_tag_to_str[ext_adv->adv->ctx.tag] : adv_tag_to_str[BT_MESH_ADV_TAG_PROXY]); - atomic_clear_bit(adv->flags, ADV_FLAG_ACTIVE); - atomic_clear_bit(adv->flags, ADV_FLAG_PROXY); - atomic_clear_bit(adv->flags, ADV_FLAG_PROXY_START); + atomic_clear_bit(ext_adv->flags, ADV_FLAG_ACTIVE); + atomic_clear_bit(ext_adv->flags, ADV_FLAG_PROXY); + atomic_clear_bit(ext_adv->flags, ADV_FLAG_PROXY_START); - if (adv->buf) { - net_buf_unref(adv->buf); - adv->buf = NULL; + if (ext_adv->adv) { + bt_mesh_adv_unref(ext_adv->adv); + ext_adv->adv = NULL; } - (void)schedule_send(adv); + (void)schedule_send(ext_adv); return; } - atomic_clear_bit(adv->flags, ADV_FLAG_SCHEDULED); + atomic_clear_bit(ext_adv->flags, ADV_FLAG_SCHEDULED); - while ((buf = bt_mesh_adv_buf_get_by_tag(adv->tags, K_NO_WAIT))) { + while ((adv = bt_mesh_adv_get_by_tag(ext_adv->tags, K_NO_WAIT))) { /* busy == 0 means this was canceled */ - if (!BT_MESH_ADV(buf)->busy) { - net_buf_unref(buf); + if (!adv->ctx.busy) { + bt_mesh_adv_unref(adv); continue; } - BT_MESH_ADV(buf)->busy = 0U; - err = buf_send(adv, buf); + adv->ctx.busy = 0U; + err = adv_send(ext_adv, adv); - net_buf_unref(buf); + bt_mesh_adv_unref(adv); if (!err) { return; /* Wait for advertising to finish */ @@ -294,7 +293,7 @@ static void send_pending_adv(struct k_work *work) } if (!IS_ENABLED(CONFIG_BT_MESH_GATT_SERVER) || - !(adv->tags & BT_MESH_ADV_TAG_BIT_PROXY)) { + !(ext_adv->tags & BT_MESH_ADV_TAG_BIT_PROXY)) { return; } @@ -303,51 +302,51 @@ static void send_pending_adv(struct k_work *work) return; } - atomic_set_bit(adv->flags, ADV_FLAG_PROXY_START); + atomic_set_bit(ext_adv->flags, ADV_FLAG_PROXY_START); if (!bt_mesh_adv_gatt_send()) { - atomic_set_bit(adv->flags, ADV_FLAG_PROXY); + atomic_set_bit(ext_adv->flags, ADV_FLAG_PROXY); } - if (atomic_test_and_clear_bit(adv->flags, ADV_FLAG_SCHEDULE_PENDING)) { - schedule_send(adv); + if (atomic_test_and_clear_bit(ext_adv->flags, ADV_FLAG_SCHEDULE_PENDING)) { + schedule_send(ext_adv); } } -static bool schedule_send(struct bt_mesh_ext_adv *adv) +static bool schedule_send(struct bt_mesh_ext_adv *ext_adv) { uint64_t timestamp; int64_t delta; - timestamp = adv->timestamp; + timestamp = ext_adv->timestamp; - if (atomic_test_and_clear_bit(adv->flags, ADV_FLAG_PROXY)) { - atomic_clear_bit(adv->flags, ADV_FLAG_PROXY_START); - (void)bt_le_ext_adv_stop(adv->instance); + if (atomic_test_and_clear_bit(ext_adv->flags, ADV_FLAG_PROXY)) { + atomic_clear_bit(ext_adv->flags, ADV_FLAG_PROXY_START); + (void)bt_le_ext_adv_stop(ext_adv->instance); - atomic_clear_bit(adv->flags, ADV_FLAG_ACTIVE); + atomic_clear_bit(ext_adv->flags, ADV_FLAG_ACTIVE); } - if (atomic_test_bit(adv->flags, ADV_FLAG_ACTIVE)) { - atomic_set_bit(adv->flags, ADV_FLAG_SCHEDULE_PENDING); + if (atomic_test_bit(ext_adv->flags, ADV_FLAG_ACTIVE)) { + atomic_set_bit(ext_adv->flags, ADV_FLAG_SCHEDULE_PENDING); return false; - } else if (atomic_test_and_set_bit(adv->flags, ADV_FLAG_SCHEDULED)) { + } else if (atomic_test_and_set_bit(ext_adv->flags, ADV_FLAG_SCHEDULED)) { return false; } - atomic_clear_bit(adv->flags, ADV_FLAG_SCHEDULE_PENDING); + atomic_clear_bit(ext_adv->flags, ADV_FLAG_SCHEDULE_PENDING); if ((IS_ENABLED(CONFIG_BT_MESH_ADV_EXT_FRIEND_SEPARATE) && - adv->tags & BT_MESH_ADV_TAG_BIT_FRIEND) || - (CONFIG_BT_MESH_RELAY_ADV_SETS > 0 && adv->tags & BT_MESH_ADV_TAG_BIT_RELAY)) { - k_work_reschedule(&adv->work, K_NO_WAIT); + ext_adv->tags & BT_MESH_ADV_TAG_BIT_FRIEND) || + (CONFIG_BT_MESH_RELAY_ADV_SETS > 0 && ext_adv->tags & BT_MESH_ADV_TAG_BIT_RELAY)) { + k_work_reschedule(&ext_adv->work, K_NO_WAIT); } else { /* The controller will send the next advertisement immediately. * Introduce a delay here to avoid sending the next mesh packet closer * to the previous packet than what's permitted by the specification. */ delta = k_uptime_delta(×tamp); - k_work_reschedule(&adv->work, K_MSEC(ADV_INT_FAST_MS - delta)); + k_work_reschedule(&ext_adv->work, K_MSEC(ADV_INT_FAST_MS - delta)); } return true; @@ -358,17 +357,17 @@ void bt_mesh_adv_gatt_update(void) (void)schedule_send(gatt_adv_get()); } -void bt_mesh_adv_buf_local_ready(void) +void bt_mesh_adv_local_ready(void) { (void)schedule_send(advs); } -void bt_mesh_adv_buf_relay_ready(void) +void bt_mesh_adv_relay_ready(void) { - struct bt_mesh_ext_adv *adv = relay_adv_get(); + struct bt_mesh_ext_adv *ext_adv = relay_adv_get(); for (int i = 0; i < CONFIG_BT_MESH_RELAY_ADV_SETS; i++) { - if (schedule_send(&adv[i])) { + if (schedule_send(&ext_adv[i])) { return; } } @@ -379,7 +378,7 @@ void bt_mesh_adv_buf_relay_ready(void) } } -void bt_mesh_adv_buf_friend_ready(void) +void bt_mesh_adv_friend_ready(void) { if (IS_ENABLED(CONFIG_BT_MESH_ADV_EXT_FRIEND_SEPARATE)) { schedule_send(&advs[1 + CONFIG_BT_MESH_RELAY_ADV_SETS]); @@ -388,33 +387,33 @@ void bt_mesh_adv_buf_friend_ready(void) } } -void bt_mesh_adv_buf_terminate(const struct net_buf *buf) +void bt_mesh_adv_terminate(struct bt_mesh_adv *adv) { int err; for (int i = 0; i < ARRAY_SIZE(advs); i++) { - struct bt_mesh_ext_adv *adv = &advs[i]; + struct bt_mesh_ext_adv *ext_adv = &advs[i]; - if (adv->buf != buf) { + if (ext_adv->adv != adv) { continue; } - if (!atomic_test_bit(adv->flags, ADV_FLAG_ACTIVE)) { + if (!atomic_test_bit(ext_adv->flags, ADV_FLAG_ACTIVE)) { return; } - err = bt_le_ext_adv_stop(adv->instance); + err = bt_le_ext_adv_stop(ext_adv->instance); if (err) { LOG_ERR("Failed to stop adv %d", err); return; } /* Do not call `cb:end`, since this user action */ - BT_MESH_ADV(adv->buf)->cb = NULL; + adv->ctx.cb = NULL; - atomic_set_bit(adv->flags, ADV_FLAG_SENT); + atomic_set_bit(ext_adv->flags, ADV_FLAG_SENT); - k_work_submit(&adv->work.work); + k_work_submit(&ext_adv->work.work); return; } @@ -450,31 +449,31 @@ static struct bt_mesh_ext_adv *adv_instance_find(struct bt_le_ext_adv *instance) static void adv_sent(struct bt_le_ext_adv *instance, struct bt_le_ext_adv_sent_info *info) { - struct bt_mesh_ext_adv *adv = adv_instance_find(instance); + struct bt_mesh_ext_adv *ext_adv = adv_instance_find(instance); - if (!adv) { + if (!ext_adv) { LOG_WRN("Unexpected adv instance"); return; } - if (!atomic_test_bit(adv->flags, ADV_FLAG_ACTIVE)) { + if (!atomic_test_bit(ext_adv->flags, ADV_FLAG_ACTIVE)) { return; } - atomic_set_bit(adv->flags, ADV_FLAG_SENT); + atomic_set_bit(ext_adv->flags, ADV_FLAG_SENT); - k_work_submit(&adv->work.work); + k_work_submit(&ext_adv->work.work); } #if defined(CONFIG_BT_MESH_GATT_SERVER) static void connected(struct bt_le_ext_adv *instance, struct bt_le_ext_adv_connected_info *info) { - struct bt_mesh_ext_adv *adv = gatt_adv_get(); + struct bt_mesh_ext_adv *ext_adv = gatt_adv_get(); - if (atomic_test_and_clear_bit(adv->flags, ADV_FLAG_PROXY_START)) { - atomic_clear_bit(adv->flags, ADV_FLAG_ACTIVE); - (void)schedule_send(adv); + if (atomic_test_and_clear_bit(ext_adv->flags, ADV_FLAG_PROXY_START)) { + atomic_clear_bit(ext_adv->flags, ADV_FLAG_ACTIVE); + (void)schedule_send(ext_adv); } } #endif /* CONFIG_BT_MESH_GATT_SERVER */ @@ -541,7 +540,7 @@ int bt_mesh_adv_gatt_start(const struct bt_le_adv_param *param, const struct bt_data *ad, size_t ad_len, const struct bt_data *sd, size_t sd_len) { - struct bt_mesh_ext_adv *adv = gatt_adv_get(); + struct bt_mesh_ext_adv *ext_adv = gatt_adv_get(); struct bt_le_ext_adv_start_param start = { /* Timeout is set in 10 ms steps, with 0 indicating "forever" */ .timeout = (duration == SYS_FOREVER_MS) ? 0 : MAX(1, duration / 10), @@ -549,9 +548,9 @@ int bt_mesh_adv_gatt_start(const struct bt_le_adv_param *param, LOG_DBG("Start advertising %d ms", duration); - atomic_set_bit(adv->flags, ADV_FLAG_UPDATE_PARAMS); + atomic_set_bit(ext_adv->flags, ADV_FLAG_UPDATE_PARAMS); - return adv_start(adv, param, &start, ad, ad_len, sd, sd_len); + return adv_start(ext_adv, param, &start, ad, ad_len, sd, sd_len); } int bt_mesh_adv_bt_data_send(uint8_t num_events, uint16_t adv_interval, diff --git a/subsys/bluetooth/mesh/adv_legacy.c b/subsys/bluetooth/mesh/adv_legacy.c index aef13864131..d4003e497bb 100644 --- a/subsys/bluetooth/mesh/adv_legacy.c +++ b/subsys/bluetooth/mesh/adv_legacy.c @@ -19,7 +19,6 @@ #include "host/hci_core.h" -#include "adv.h" #include "net.h" #include "foundation.h" #include "beacon.h" @@ -43,7 +42,7 @@ static bool enabled; static int bt_data_send(uint8_t num_events, uint16_t adv_int, const struct bt_data *ad, size_t ad_len, - struct bt_mesh_adv *adv) + struct bt_mesh_adv_ctx *ctx) { struct bt_le_adv_param param = {}; uint64_t uptime = k_uptime_get(); @@ -101,8 +100,8 @@ static int bt_data_send(uint8_t num_events, uint16_t adv_int, LOG_DBG("Advertising started. Sleeping %u ms", duration); - if (adv) { - bt_mesh_adv_send_start(duration, err, adv); + if (ctx) { + bt_mesh_adv_send_start(duration, err, ctx); } k_sleep(K_MSEC(duration)); @@ -124,37 +123,37 @@ int bt_mesh_adv_bt_data_send(uint8_t num_events, uint16_t adv_int, return bt_data_send(num_events, adv_int, ad, ad_len, NULL); } -static inline void buf_send(struct net_buf *buf) +static inline void adv_send(struct bt_mesh_adv *adv) { - uint16_t num_events = BT_MESH_TRANSMIT_COUNT(BT_MESH_ADV(buf)->xmit) + 1; + uint16_t num_events = BT_MESH_TRANSMIT_COUNT(adv->ctx.xmit) + 1; uint16_t adv_int; struct bt_data ad; - adv_int = BT_MESH_TRANSMIT_INT(BT_MESH_ADV(buf)->xmit); + adv_int = BT_MESH_TRANSMIT_INT(adv->ctx.xmit); - LOG_DBG("type %u len %u: %s", BT_MESH_ADV(buf)->type, - buf->len, bt_hex(buf->data, buf->len)); + LOG_DBG("type %u len %u: %s", adv->ctx.type, + adv->b.len, bt_hex(adv->b.data, adv->b.len)); - ad.type = bt_mesh_adv_type[BT_MESH_ADV(buf)->type]; - ad.data_len = buf->len; - ad.data = buf->data; + ad.type = bt_mesh_adv_type[adv->ctx.type]; + ad.data_len = adv->b.len; + ad.data = adv->b.data; - bt_data_send(num_events, adv_int, &ad, 1, BT_MESH_ADV(buf)); + bt_data_send(num_events, adv_int, &ad, 1, &adv->ctx); } static void adv_thread(void *p1, void *p2, void *p3) { LOG_DBG("started"); - struct net_buf *buf; + struct bt_mesh_adv *adv; while (enabled) { if (IS_ENABLED(CONFIG_BT_MESH_GATT_SERVER)) { - buf = bt_mesh_adv_buf_get(K_NO_WAIT); - if (IS_ENABLED(CONFIG_BT_MESH_PROXY_SOLICITATION) && !buf) { + adv = bt_mesh_adv_get(K_NO_WAIT); + if (IS_ENABLED(CONFIG_BT_MESH_PROXY_SOLICITATION) && !adv) { (void)bt_mesh_sol_send(); } - while (!buf) { + while (!adv) { /* Adv timeout may be set by a call from proxy * to bt_mesh_adv_gatt_start: @@ -162,58 +161,58 @@ static void adv_thread(void *p1, void *p2, void *p3) adv_timeout = SYS_FOREVER_MS; (void)bt_mesh_adv_gatt_send(); - buf = bt_mesh_adv_buf_get(SYS_TIMEOUT_MS(adv_timeout)); + adv = bt_mesh_adv_get(SYS_TIMEOUT_MS(adv_timeout)); bt_le_adv_stop(); - if (IS_ENABLED(CONFIG_BT_MESH_PROXY_SOLICITATION) && !buf) { + if (IS_ENABLED(CONFIG_BT_MESH_PROXY_SOLICITATION) && !adv) { (void)bt_mesh_sol_send(); } } } else { - buf = bt_mesh_adv_buf_get(K_FOREVER); + adv = bt_mesh_adv_get(K_FOREVER); } - if (!buf) { + if (!adv) { continue; } /* busy == 0 means this was canceled */ - if (BT_MESH_ADV(buf)->busy) { - BT_MESH_ADV(buf)->busy = 0U; - buf_send(buf); + if (adv->ctx.busy) { + adv->ctx.busy = 0U; + adv_send(adv); } - net_buf_unref(buf); + bt_mesh_adv_unref(adv); /* Give other threads a chance to run */ k_yield(); } /* Empty the advertising pool when advertising is disabled */ - while ((buf = bt_mesh_adv_buf_get(K_NO_WAIT))) { - bt_mesh_adv_send_start(0, -ENODEV, BT_MESH_ADV(buf)); - net_buf_unref(buf); + while ((adv = bt_mesh_adv_get(K_NO_WAIT))) { + bt_mesh_adv_send_start(0, -ENODEV, &adv->ctx); + bt_mesh_adv_unref(adv); } } -void bt_mesh_adv_buf_local_ready(void) +void bt_mesh_adv_local_ready(void) { /* Will be handled automatically */ } -void bt_mesh_adv_buf_relay_ready(void) +void bt_mesh_adv_relay_ready(void) { /* Will be handled automatically */ } void bt_mesh_adv_gatt_update(void) { - bt_mesh_adv_buf_get_cancel(); + bt_mesh_adv_get_cancel(); } -void bt_mesh_adv_buf_terminate(const struct net_buf *buf) +void bt_mesh_adv_terminate(struct bt_mesh_adv *adv) { - ARG_UNUSED(buf); + ARG_UNUSED(adv); } void bt_mesh_adv_init(void) diff --git a/subsys/bluetooth/mesh/app_keys.c b/subsys/bluetooth/mesh/app_keys.c index a47d31447c5..5afd887a8e8 100644 --- a/subsys/bluetooth/mesh/app_keys.c +++ b/subsys/bluetooth/mesh/app_keys.c @@ -17,7 +17,6 @@ #include "rpl.h" #include "settings.h" #include "crypto.h" -#include "adv.h" #include "proxy.h" #include "friend.h" #include "foundation.h" diff --git a/subsys/bluetooth/mesh/beacon.c b/subsys/bluetooth/mesh/beacon.c index afdea5b4c6a..ef337f9f510 100644 --- a/subsys/bluetooth/mesh/beacon.c +++ b/subsys/bluetooth/mesh/beacon.c @@ -16,7 +16,6 @@ #include "common/bt_str.h" -#include "adv.h" #include "mesh.h" #include "net.h" #include "prov.h" @@ -256,7 +255,7 @@ static bool net_beacon_send(struct bt_mesh_subnet *sub, struct bt_mesh_beacon *b .end = beacon_complete, }; uint32_t now = k_uptime_get_32(); - struct net_buf *buf; + struct bt_mesh_adv *adv; uint32_t time_diff; uint32_t time_since_last_recv; int err; @@ -271,19 +270,19 @@ static bool net_beacon_send(struct bt_mesh_subnet *sub, struct bt_mesh_beacon *b return false; } - buf = bt_mesh_adv_create(BT_MESH_ADV_BEACON, BT_MESH_ADV_TAG_LOCAL, + adv = bt_mesh_adv_create(BT_MESH_ADV_BEACON, BT_MESH_ADV_TAG_LOCAL, PROV_XMIT, K_NO_WAIT); - if (!buf) { - LOG_ERR("Unable to allocate beacon buffer"); + if (!adv) { + LOG_ERR("Unable to allocate beacon adv"); return true; /* Bail out */ } - err = beacon_create(sub, &buf->b); + err = beacon_create(sub, &adv->b); if (!err) { - bt_mesh_adv_send(buf, &send_cb, beacon); + bt_mesh_adv_send(adv, &send_cb, beacon); } - net_buf_unref(buf); + bt_mesh_adv_unref(adv); return err != 0; } @@ -330,22 +329,22 @@ static int unprovisioned_beacon_send(void) { const struct bt_mesh_prov *prov; uint8_t uri_hash[16] = { 0 }; - struct net_buf *buf; + struct bt_mesh_adv *adv; uint16_t oob_info; LOG_DBG(""); - buf = bt_mesh_adv_create(BT_MESH_ADV_BEACON, BT_MESH_ADV_TAG_LOCAL, + adv = bt_mesh_adv_create(BT_MESH_ADV_BEACON, BT_MESH_ADV_TAG_LOCAL, UNPROV_XMIT, K_NO_WAIT); - if (!buf) { - LOG_ERR("Unable to allocate beacon buffer"); + if (!adv) { + LOG_ERR("Unable to allocate beacon adv"); return -ENOBUFS; } prov = bt_mesh_prov_get(); - net_buf_add_u8(buf, BEACON_TYPE_UNPROVISIONED); - net_buf_add_mem(buf, prov->uuid, 16); + net_buf_simple_add_u8(&adv->b, BEACON_TYPE_UNPROVISIONED); + net_buf_simple_add_mem(&adv->b, prov->uuid, 16); if (prov->uri && bt_mesh_s1_str(prov->uri, uri_hash) == 0) { oob_info = prov->oob_info | BT_MESH_PROV_OOB_URI; @@ -353,31 +352,31 @@ static int unprovisioned_beacon_send(void) oob_info = prov->oob_info; } - net_buf_add_be16(buf, oob_info); - net_buf_add_mem(buf, uri_hash, 4); + net_buf_simple_add_be16(&adv->b, oob_info); + net_buf_simple_add_mem(&adv->b, uri_hash, 4); - bt_mesh_adv_send(buf, NULL, NULL); - net_buf_unref(buf); + bt_mesh_adv_send(adv, NULL, NULL); + bt_mesh_adv_unref(adv); if (prov->uri) { size_t len; - buf = bt_mesh_adv_create(BT_MESH_ADV_URI, BT_MESH_ADV_TAG_LOCAL, + adv = bt_mesh_adv_create(BT_MESH_ADV_URI, BT_MESH_ADV_TAG_LOCAL, UNPROV_XMIT, K_NO_WAIT); - if (!buf) { - LOG_ERR("Unable to allocate URI buffer"); + if (!adv) { + LOG_ERR("Unable to allocate URI adv"); return -ENOBUFS; } len = strlen(prov->uri); - if (net_buf_tailroom(buf) < len) { + if (net_buf_simple_tailroom(&adv->b) < len) { LOG_WRN("Too long URI to fit advertising data"); } else { - net_buf_add_mem(buf, prov->uri, len); - bt_mesh_adv_send(buf, NULL, NULL); + net_buf_simple_add_mem(&adv->b, prov->uri, len); + bt_mesh_adv_send(adv, NULL, NULL); } - net_buf_unref(buf); + bt_mesh_adv_unref(adv); } return 0; diff --git a/subsys/bluetooth/mesh/cfg.c b/subsys/bluetooth/mesh/cfg.c index c7bea0d29b0..4fef60d5c8d 100644 --- a/subsys/bluetooth/mesh/cfg.c +++ b/subsys/bluetooth/mesh/cfg.c @@ -14,7 +14,6 @@ #include "settings.h" #include "heartbeat.h" #include "friend.h" -#include "adv.h" #include "cfg.h" #include "od_priv_proxy.h" #include "priv_beacon.h" diff --git a/subsys/bluetooth/mesh/cfg_srv.c b/subsys/bluetooth/mesh/cfg_srv.c index fa6bb48703a..268f883d8b8 100644 --- a/subsys/bluetooth/mesh/cfg_srv.c +++ b/subsys/bluetooth/mesh/cfg_srv.c @@ -21,7 +21,6 @@ #include "host/testing.h" #include "mesh.h" -#include "adv.h" #include "net.h" #include "rpl.h" #include "lpn.h" diff --git a/subsys/bluetooth/mesh/friend.c b/subsys/bluetooth/mesh/friend.c index 73b75eadf4f..6fbd9f81a68 100644 --- a/subsys/bluetooth/mesh/friend.c +++ b/subsys/bluetooth/mesh/friend.c @@ -13,7 +13,6 @@ #include #include "crypto.h" -#include "adv.h" #include "mesh.h" #include "net.h" #include "app_keys.h" @@ -1239,7 +1238,7 @@ static void friend_timeout(struct k_work *work) .start = buf_send_start, .end = buf_send_end, }; - struct net_buf *buf; + struct bt_mesh_adv *adv; uint8_t md; if (!friend_is_allocated(frnd)) { @@ -1281,19 +1280,19 @@ static void friend_timeout(struct k_work *work) frnd->queue_size--; send_last: - buf = bt_mesh_adv_create(BT_MESH_ADV_DATA, BT_MESH_ADV_TAG_FRIEND, + adv = bt_mesh_adv_create(BT_MESH_ADV_DATA, BT_MESH_ADV_TAG_FRIEND, FRIEND_XMIT, K_NO_WAIT); - if (!buf) { - LOG_ERR("Unable to allocate friend adv buffer"); + if (!adv) { + LOG_ERR("Unable to allocate friend adv"); return; } - net_buf_add_mem(buf, frnd->last->data, frnd->last->len); + net_buf_simple_add_mem(&adv->b, frnd->last->data, frnd->last->len); frnd->pending_req = 0U; frnd->pending_buf = 1U; - bt_mesh_adv_send(buf, &buf_sent_cb, frnd); - net_buf_unref(buf); + bt_mesh_adv_send(adv, &buf_sent_cb, frnd); + bt_mesh_adv_unref(adv); } static void subnet_evt(struct bt_mesh_subnet *sub, enum bt_mesh_key_evt evt) diff --git a/subsys/bluetooth/mesh/gatt_cli.c b/subsys/bluetooth/mesh/gatt_cli.c index bff9b567011..7814f32f27f 100644 --- a/subsys/bluetooth/mesh/gatt_cli.c +++ b/subsys/bluetooth/mesh/gatt_cli.c @@ -18,7 +18,6 @@ #include "common/bt_str.h" #include "mesh.h" -#include "adv.h" #include "net.h" #include "rpl.h" #include "transport.h" diff --git a/subsys/bluetooth/mesh/health_srv.c b/subsys/bluetooth/mesh/health_srv.c index 8611e1004f6..3db3410aa34 100644 --- a/subsys/bluetooth/mesh/health_srv.c +++ b/subsys/bluetooth/mesh/health_srv.c @@ -16,7 +16,6 @@ #include #include "mesh.h" -#include "adv.h" #include "net.h" #include "transport.h" #include "access.h" diff --git a/subsys/bluetooth/mesh/lpn.c b/subsys/bluetooth/mesh/lpn.c index 2b655f729f3..f6f906b12fe 100644 --- a/subsys/bluetooth/mesh/lpn.c +++ b/subsys/bluetooth/mesh/lpn.c @@ -13,7 +13,6 @@ #include #include "crypto.h" -#include "adv.h" #include "mesh.h" #include "net.h" #include "transport.h" diff --git a/subsys/bluetooth/mesh/main.c b/subsys/bluetooth/mesh/main.c index 24bbd7c7e94..89115ebe3e8 100644 --- a/subsys/bluetooth/mesh/main.c +++ b/subsys/bluetooth/mesh/main.c @@ -18,7 +18,6 @@ #include #include "test.h" -#include "adv.h" #include "prov.h" #include "provisioner.h" #include "net.h" diff --git a/subsys/bluetooth/mesh/net.c b/subsys/bluetooth/mesh/net.c index 6a9f29b4064..943a5e83c23 100644 --- a/subsys/bluetooth/mesh/net.c +++ b/subsys/bluetooth/mesh/net.c @@ -20,7 +20,6 @@ #include "common/bt_str.h" #include "crypto.h" -#include "adv.h" #include "mesh.h" #include "net.h" #include "rpl.h" @@ -526,19 +525,19 @@ static int net_loopback(const struct bt_mesh_net_tx *tx, const uint8_t *data, return 0; } -int bt_mesh_net_send(struct bt_mesh_net_tx *tx, struct net_buf *buf, +int bt_mesh_net_send(struct bt_mesh_net_tx *tx, struct bt_mesh_adv *adv, const struct bt_mesh_send_cb *cb, void *cb_data) { const struct bt_mesh_net_cred *cred; int err; LOG_DBG("src 0x%04x dst 0x%04x len %u headroom %zu tailroom %zu", tx->src, tx->ctx->addr, - buf->len, net_buf_headroom(buf), net_buf_tailroom(buf)); - LOG_DBG("Payload len %u: %s", buf->len, bt_hex(buf->data, buf->len)); + adv->b.len, net_buf_simple_headroom(&adv->b), net_buf_simple_tailroom(&adv->b)); + LOG_DBG("Payload len %u: %s", adv->b.len, bt_hex(adv->b.data, adv->b.len)); LOG_DBG("Seq 0x%06x", bt_mesh.seq); cred = net_tx_cred_get(tx); - err = net_header_encode(tx, cred->nid, &buf->b); + err = net_header_encode(tx, cred->nid, &adv->b); if (err) { goto done; } @@ -546,7 +545,7 @@ int bt_mesh_net_send(struct bt_mesh_net_tx *tx, struct net_buf *buf, /* Deliver to local network interface if necessary */ if (bt_mesh_fixed_group_match(tx->ctx->addr) || bt_mesh_has_addr(tx->ctx->addr)) { - err = net_loopback(tx, buf->data, buf->len); + err = net_loopback(tx, adv->b.data, adv->b.len); /* Local unicast messages should not go out to network */ if (BT_MESH_ADDR_IS_UNICAST(tx->ctx->addr) || @@ -569,28 +568,28 @@ int bt_mesh_net_send(struct bt_mesh_net_tx *tx, struct net_buf *buf, goto done; } - err = net_encrypt(&buf->b, cred, BT_MESH_NET_IVI_TX, BT_MESH_NONCE_NETWORK); + err = net_encrypt(&adv->b, cred, BT_MESH_NET_IVI_TX, BT_MESH_NONCE_NETWORK); if (err) { goto done; } - BT_MESH_ADV(buf)->cb = cb; - BT_MESH_ADV(buf)->cb_data = cb_data; + adv->ctx.cb = cb; + adv->ctx.cb_data = cb_data; /* Deliver to GATT Proxy Clients if necessary. */ if (IS_ENABLED(CONFIG_BT_MESH_GATT_PROXY)) { - (void)bt_mesh_proxy_relay(buf, tx->ctx->addr); + (void)bt_mesh_proxy_relay(adv, tx->ctx->addr); } /* Deliver to GATT Proxy Servers if necessary. */ if (IS_ENABLED(CONFIG_BT_MESH_PROXY_CLIENT)) { - (void)bt_mesh_proxy_cli_relay(buf); + (void)bt_mesh_proxy_cli_relay(adv); } - bt_mesh_adv_send(buf, cb, cb_data); + bt_mesh_adv_send(adv, cb, cb_data); done: - net_buf_unref(buf); + bt_mesh_adv_unref(adv); return err; } @@ -684,7 +683,7 @@ static void bt_mesh_net_relay(struct net_buf_simple *sbuf, struct bt_mesh_net_rx *rx) { const struct bt_mesh_net_cred *cred; - struct net_buf *buf; + struct bt_mesh_adv *adv; uint8_t transmit; if (rx->ctx.recv_ttl <= 1U) { @@ -711,10 +710,10 @@ static void bt_mesh_net_relay(struct net_buf_simple *sbuf, transmit = bt_mesh_net_transmit_get(); } - buf = bt_mesh_adv_create(BT_MESH_ADV_DATA, BT_MESH_ADV_TAG_RELAY, + adv = bt_mesh_adv_create(BT_MESH_ADV_DATA, BT_MESH_ADV_TAG_RELAY, transmit, K_NO_WAIT); - if (!buf) { - LOG_DBG("Out of relay buffers"); + if (!adv) { + LOG_DBG("Out of relay advs"); return; } @@ -722,23 +721,23 @@ static void bt_mesh_net_relay(struct net_buf_simple *sbuf, sbuf->data[1] &= 0x80; sbuf->data[1] |= rx->ctx.recv_ttl - 1U; - net_buf_add_mem(buf, sbuf->data, sbuf->len); + net_buf_simple_add_mem(&adv->b, sbuf->data, sbuf->len); cred = &rx->sub->keys[SUBNET_KEY_TX_IDX(rx->sub)].msg; - LOG_DBG("Relaying packet. TTL is now %u", TTL(buf->data)); + LOG_DBG("Relaying packet. TTL is now %u", TTL(adv->b.data)); /* Update NID if RX or RX was with friend credentials */ if (rx->friend_cred) { - buf->data[0] &= 0x80; /* Clear everything except IVI */ - buf->data[0] |= cred->nid; + adv->b.data[0] &= 0x80; /* Clear everything except IVI */ + adv->b.data[0] |= cred->nid; } /* We re-encrypt and obfuscate using the received IVI rather than * the normal TX IVI (which may be different) since the transport * layer nonce includes the IVI. */ - if (net_encrypt(&buf->b, cred, BT_MESH_NET_IVI_RX(rx), BT_MESH_NONCE_NETWORK)) { + if (net_encrypt(&adv->b, cred, BT_MESH_NET_IVI_RX(rx), BT_MESH_NONCE_NETWORK)) { LOG_ERR("Re-encrypting failed"); goto done; } @@ -751,15 +750,15 @@ static void bt_mesh_net_relay(struct net_buf_simple *sbuf, (rx->friend_cred || bt_mesh_gatt_proxy_get() == BT_MESH_GATT_PROXY_ENABLED || bt_mesh_priv_gatt_proxy_get() == BT_MESH_PRIV_GATT_PROXY_ENABLED)) { - bt_mesh_proxy_relay(buf, rx->ctx.recv_dst); + bt_mesh_proxy_relay(adv, rx->ctx.recv_dst); } if (relay_to_adv(rx->net_if) || rx->friend_cred) { - bt_mesh_adv_send(buf, NULL, NULL); + bt_mesh_adv_send(adv, NULL, NULL); } done: - net_buf_unref(buf); + bt_mesh_adv_unref(adv); } void bt_mesh_net_header_parse(struct net_buf_simple *buf, diff --git a/subsys/bluetooth/mesh/net.h b/subsys/bluetooth/mesh/net.h index 04179a4dd49..28c21da3eaf 100644 --- a/subsys/bluetooth/mesh/net.h +++ b/subsys/bluetooth/mesh/net.h @@ -4,6 +4,7 @@ * SPDX-License-Identifier: Apache-2.0 */ +#include "adv.h" #include "subnet.h" #include @@ -291,7 +292,7 @@ bool bt_mesh_net_iv_update(uint32_t iv_index, bool iv_update); int bt_mesh_net_encode(struct bt_mesh_net_tx *tx, struct net_buf_simple *buf, enum bt_mesh_nonce_type type); -int bt_mesh_net_send(struct bt_mesh_net_tx *tx, struct net_buf *buf, +int bt_mesh_net_send(struct bt_mesh_net_tx *tx, struct bt_mesh_adv *adv, const struct bt_mesh_send_cb *cb, void *cb_data); int bt_mesh_net_decode(struct net_buf_simple *in, enum bt_mesh_net_if net_if, diff --git a/subsys/bluetooth/mesh/pb_adv.c b/subsys/bluetooth/mesh/pb_adv.c index e273739ed72..f723ff48c14 100644 --- a/subsys/bluetooth/mesh/pb_adv.c +++ b/subsys/bluetooth/mesh/pb_adv.c @@ -11,7 +11,6 @@ #include #include "host/testing.h" #include "net.h" -#include "adv.h" #include "crypto.h" #include "beacon.h" #include "prov.h" @@ -101,8 +100,8 @@ struct pb_adv { /* Transaction timeout in seconds */ uint8_t timeout; - /* Pending outgoing buffer(s) */ - struct net_buf *buf[3]; + /* Pending outgoing adv(s) */ + struct bt_mesh_adv *adv[3]; prov_bearer_send_complete_t cb; @@ -170,24 +169,24 @@ static void free_segments(void) { int i; - for (i = 0; i < ARRAY_SIZE(link.tx.buf); i++) { - struct net_buf *buf = link.tx.buf[i]; + for (i = 0; i < ARRAY_SIZE(link.tx.adv); i++) { + struct bt_mesh_adv *adv = link.tx.adv[i]; - if (!buf) { + if (!adv) { break; } - link.tx.buf[i] = NULL; + link.tx.adv[i] = NULL; /* Terminate active adv */ - if (BT_MESH_ADV(buf)->busy == 0U) { - bt_mesh_adv_buf_terminate(buf); + if (adv->ctx.busy == 0U) { + bt_mesh_adv_terminate(adv); } else { /* Mark as canceled */ - BT_MESH_ADV(buf)->busy = 0U; + adv->ctx.busy = 0U; } - net_buf_unref(buf); + bt_mesh_adv_unref(adv); } } @@ -200,7 +199,7 @@ static void prov_clear_tx(void) { LOG_DBG(""); - /* If this fails, the work handler will not find any buffers to send, + /* If this fails, the work handler will not find any advs to send, * and return without rescheduling. The work handler also checks the * LINK_ACTIVE flag, so if this call is part of reset_adv_link, it'll * exit early. @@ -254,19 +253,19 @@ static void close_link(enum prov_bearer_link_status reason) cb->link_closed(&bt_mesh_pb_adv, cb_data, reason); } -static struct net_buf *adv_buf_create(uint8_t retransmits) +static struct bt_mesh_adv *adv_create(uint8_t retransmits) { - struct net_buf *buf; + struct bt_mesh_adv *adv; - buf = bt_mesh_adv_create(BT_MESH_ADV_PROV, BT_MESH_ADV_TAG_PROV, + adv = bt_mesh_adv_create(BT_MESH_ADV_PROV, BT_MESH_ADV_TAG_PROV, BT_MESH_TRANSMIT(retransmits, 20), BUF_TIMEOUT); - if (!buf) { - LOG_ERR("Out of provisioning buffers"); + if (!adv) { + LOG_ERR("Out of provisioning advs"); return NULL; } - return buf; + return adv; } static void ack_complete(uint16_t duration, int err, void *user_data) @@ -328,7 +327,7 @@ static void gen_prov_ack_send(uint8_t xact_id) .start = ack_complete, }; const struct bt_mesh_send_cb *complete; - struct net_buf *buf; + struct bt_mesh_adv *adv; bool pending = atomic_test_and_set_bit(link.flags, ADV_ACK_PENDING); LOG_DBG("xact_id 0x%x", xact_id); @@ -338,8 +337,8 @@ static void gen_prov_ack_send(uint8_t xact_id) return; } - buf = adv_buf_create(RETRANSMITS_ACK); - if (!buf) { + adv = adv_create(RETRANSMITS_ACK); + if (!adv) { atomic_clear_bit(link.flags, ADV_ACK_PENDING); return; } @@ -351,12 +350,12 @@ static void gen_prov_ack_send(uint8_t xact_id) complete = &cb; } - net_buf_add_be32(buf, link.id); - net_buf_add_u8(buf, xact_id); - net_buf_add_u8(buf, GPC_ACK); + net_buf_simple_add_be32(&adv->b, link.id); + net_buf_simple_add_u8(&adv->b, xact_id); + net_buf_simple_add_u8(&adv->b, GPC_ACK); - bt_mesh_adv_send(buf, complete, NULL); - net_buf_unref(buf); + bt_mesh_adv_send(adv, complete, NULL); + bt_mesh_adv_unref(adv); } static void gen_prov_cont(struct prov_rx *rx, struct net_buf_simple *buf) @@ -431,7 +430,7 @@ static void gen_prov_ack(struct prov_rx *rx, struct net_buf_simple *buf) { LOG_DBG("len %u", buf->len); - if (!link.tx.buf[0]) { + if (!link.tx.adv[0]) { return; } @@ -596,20 +595,20 @@ static void send_reliable(void) { int i; - for (i = 0; i < ARRAY_SIZE(link.tx.buf); i++) { - struct net_buf *buf = link.tx.buf[i]; + for (i = 0; i < ARRAY_SIZE(link.tx.adv); i++) { + struct bt_mesh_adv *adv = link.tx.adv[i]; - if (!buf) { + if (!adv) { break; } - if (BT_MESH_ADV(buf)->busy) { + if (adv->ctx.busy) { continue; } - LOG_DBG("%u bytes: %s", buf->len, bt_hex(buf->data, buf->len)); + LOG_DBG("%u bytes: %s", adv->b.len, bt_hex(adv->b.data, adv->b.len)); - bt_mesh_adv_send(buf, NULL, NULL); + bt_mesh_adv_send(adv, NULL, NULL); } k_work_reschedule(&link.tx.retransmit, RETRANSMIT_TIMEOUT); @@ -633,30 +632,30 @@ static void prov_retransmit(struct k_work *work) send_reliable(); } -static struct net_buf *ctl_buf_create(uint8_t op, const void *data, uint8_t data_len, - uint8_t retransmits) +static struct bt_mesh_adv *ctl_adv_create(uint8_t op, const void *data, uint8_t data_len, + uint8_t retransmits) { - struct net_buf *buf; + struct bt_mesh_adv *adv; LOG_DBG("op 0x%02x data_len %u", op, data_len); - buf = adv_buf_create(retransmits); - if (!buf) { + adv = adv_create(retransmits); + if (!adv) { return NULL; } - net_buf_add_be32(buf, link.id); + net_buf_simple_add_be32(&adv->b, link.id); /* Transaction ID, always 0 for Bearer messages */ - net_buf_add_u8(buf, 0x00); - net_buf_add_u8(buf, GPC_CTL(op)); - net_buf_add_mem(buf, data, data_len); + net_buf_simple_add_u8(&adv->b, 0x00); + net_buf_simple_add_u8(&adv->b, GPC_CTL(op)); + net_buf_simple_add_mem(&adv->b, data, data_len); - return buf; + return adv; } -static int bearer_ctl_send(struct net_buf *buf) +static int bearer_ctl_send(struct bt_mesh_adv *adv) { - if (!buf) { + if (!adv) { return -ENOMEM; } @@ -664,23 +663,23 @@ static int bearer_ctl_send(struct net_buf *buf) k_work_reschedule(&link.prot_timer, bt_mesh_prov_protocol_timeout_get()); link.tx.start = k_uptime_get(); - link.tx.buf[0] = buf; + link.tx.adv[0] = adv; send_reliable(); return 0; } -static int bearer_ctl_send_unacked(struct net_buf *buf, void *user_data) +static int bearer_ctl_send_unacked(struct bt_mesh_adv *adv, void *user_data) { - if (!buf) { + if (!adv) { return -ENOMEM; } prov_clear_tx(); k_work_reschedule(&link.prot_timer, bt_mesh_prov_protocol_timeout_get()); - bt_mesh_adv_send(buf, &buf_sent_cb, user_data); - net_buf_unref(buf); + bt_mesh_adv_send(adv, &buf_sent_cb, user_data); + bt_mesh_adv_unref(adv); return 0; } @@ -688,26 +687,26 @@ static int bearer_ctl_send_unacked(struct net_buf *buf, void *user_data) static int prov_send_adv(struct net_buf_simple *msg, prov_bearer_send_complete_t cb, void *cb_data) { - struct net_buf *start, *buf; + struct bt_mesh_adv *start, *adv; uint8_t seg_len, seg_id; prov_clear_tx(); k_work_reschedule(&link.prot_timer, bt_mesh_prov_protocol_timeout_get()); - start = adv_buf_create(RETRANSMITS_RELIABLE); + start = adv_create(RETRANSMITS_RELIABLE); if (!start) { return -ENOBUFS; } link.tx.id = next_transaction_id(link.tx.id); - net_buf_add_be32(start, link.id); - net_buf_add_u8(start, link.tx.id); + net_buf_simple_add_be32(&start->b, link.id); + net_buf_simple_add_u8(&start->b, link.tx.id); - net_buf_add_u8(start, GPC_START(last_seg(msg->len))); - net_buf_add_be16(start, msg->len); - net_buf_add_u8(start, bt_mesh_fcs_calc(msg->data, msg->len)); + net_buf_simple_add_u8(&start->b, GPC_START(last_seg(msg->len))); + net_buf_simple_add_be16(&start->b, msg->len); + net_buf_simple_add_u8(&start->b, bt_mesh_fcs_calc(msg->data, msg->len)); - link.tx.buf[0] = start; + link.tx.adv[0] = start; link.tx.cb = cb; link.tx.cb_data = cb_data; link.tx.start = k_uptime_get(); @@ -716,33 +715,33 @@ static int prov_send_adv(struct net_buf_simple *msg, seg_len = MIN(msg->len, START_PAYLOAD_MAX); LOG_DBG("seg 0 len %u: %s", seg_len, bt_hex(msg->data, seg_len)); - net_buf_add_mem(start, msg->data, seg_len); + net_buf_simple_add_mem(&start->b, msg->data, seg_len); net_buf_simple_pull(msg, seg_len); - buf = start; + adv = start; for (seg_id = 1U; msg->len > 0; seg_id++) { - if (seg_id >= ARRAY_SIZE(link.tx.buf)) { + if (seg_id >= ARRAY_SIZE(link.tx.adv)) { LOG_ERR("Too big message"); free_segments(); return -E2BIG; } - buf = adv_buf_create(RETRANSMITS_RELIABLE); - if (!buf) { + adv = adv_create(RETRANSMITS_RELIABLE); + if (!adv) { free_segments(); return -ENOBUFS; } - link.tx.buf[seg_id] = buf; + link.tx.adv[seg_id] = adv; seg_len = MIN(msg->len, CONT_PAYLOAD_MAX); LOG_DBG("seg %u len %u: %s", seg_id, seg_len, bt_hex(msg->data, seg_len)); - net_buf_add_be32(buf, link.id); - net_buf_add_u8(buf, link.tx.id); - net_buf_add_u8(buf, GPC_CONT(seg_id)); - net_buf_add_mem(buf, msg->data, seg_len); + net_buf_simple_add_be32(&adv->b, link.id); + net_buf_simple_add_u8(&adv->b, link.tx.id); + net_buf_simple_add_u8(&adv->b, GPC_CONT(seg_id)); + net_buf_simple_add_mem(&adv->b, msg->data, seg_len); net_buf_simple_pull(msg, seg_len); } @@ -776,7 +775,7 @@ static void link_open(struct prov_rx *rx, struct net_buf_simple *buf) LOG_DBG("Resending link ack"); /* Ignore errors, message will be attempted again if we keep receiving link open: */ (void)bearer_ctl_send_unacked( - ctl_buf_create(LINK_ACK, NULL, 0, RETRANSMITS_ACK), + ctl_adv_create(LINK_ACK, NULL, 0, RETRANSMITS_ACK), (void *)PROV_BEARER_LINK_STATUS_SUCCESS); return; } @@ -791,7 +790,7 @@ static void link_open(struct prov_rx *rx, struct net_buf_simple *buf) net_buf_simple_reset(link.rx.buf); err = bearer_ctl_send_unacked( - ctl_buf_create(LINK_ACK, NULL, 0, RETRANSMITS_ACK), + ctl_adv_create(LINK_ACK, NULL, 0, RETRANSMITS_ACK), (void *)PROV_BEARER_LINK_STATUS_SUCCESS); if (err) { reset_adv_link(); @@ -891,7 +890,7 @@ static int prov_link_open(const uint8_t uuid[16], uint8_t timeout, net_buf_simple_reset(link.rx.buf); - return bearer_ctl_send(ctl_buf_create(LINK_OPEN, uuid, 16, RETRANSMITS_RELIABLE)); + return bearer_ctl_send(ctl_adv_create(LINK_OPEN, uuid, 16, RETRANSMITS_RELIABLE)); } static int prov_link_accept(const struct prov_bearer_cb *cb, void *cb_data) @@ -936,7 +935,7 @@ static void prov_link_close(enum prov_bearer_link_status status) link.tx.timeout = CLOSING_TIMEOUT; /* Ignore errors, the link will time out eventually if this doesn't get sent */ bearer_ctl_send_unacked( - ctl_buf_create(LINK_CLOSE, &status, 1, RETRANSMITS_LINK_CLOSE), + ctl_adv_create(LINK_CLOSE, &status, 1, RETRANSMITS_LINK_CLOSE), (void *)status); } diff --git a/subsys/bluetooth/mesh/pb_gatt.c b/subsys/bluetooth/mesh/pb_gatt.c index f8acc8f6c5a..849914f4b5f 100644 --- a/subsys/bluetooth/mesh/pb_gatt.c +++ b/subsys/bluetooth/mesh/pb_gatt.c @@ -8,7 +8,6 @@ #include #include "net.h" #include "proxy.h" -#include "adv.h" #include "prov.h" #include "pb_gatt.h" #include "proxy_msg.h" diff --git a/subsys/bluetooth/mesh/pb_gatt_cli.c b/subsys/bluetooth/mesh/pb_gatt_cli.c index 9231cc0f0b1..bf7dc14029a 100644 --- a/subsys/bluetooth/mesh/pb_gatt_cli.c +++ b/subsys/bluetooth/mesh/pb_gatt_cli.c @@ -16,7 +16,6 @@ #include #include "mesh.h" -#include "adv.h" #include "net.h" #include "rpl.h" #include "transport.h" diff --git a/subsys/bluetooth/mesh/pb_gatt_srv.c b/subsys/bluetooth/mesh/pb_gatt_srv.c index f6d9298fc78..f4fdac53570 100644 --- a/subsys/bluetooth/mesh/pb_gatt_srv.c +++ b/subsys/bluetooth/mesh/pb_gatt_srv.c @@ -17,7 +17,6 @@ #include "common/bt_str.h" #include "mesh.h" -#include "adv.h" #include "net.h" #include "rpl.h" #include "transport.h" diff --git a/subsys/bluetooth/mesh/priv_beacon_srv.c b/subsys/bluetooth/mesh/priv_beacon_srv.c index 5b5e62f1736..98be589fc22 100644 --- a/subsys/bluetooth/mesh/priv_beacon_srv.c +++ b/subsys/bluetooth/mesh/priv_beacon_srv.c @@ -5,7 +5,6 @@ */ #include #include "net.h" -#include "adv.h" #include #include "proxy.h" #include "foundation.h" diff --git a/subsys/bluetooth/mesh/prov_device.c b/subsys/bluetooth/mesh/prov_device.c index af890396ac7..6ca65c2ec63 100644 --- a/subsys/bluetooth/mesh/prov_device.c +++ b/subsys/bluetooth/mesh/prov_device.c @@ -20,7 +20,6 @@ #include "common/bt_str.h" #include "crypto.h" -#include "adv.h" #include "mesh.h" #include "net.h" #include "rpl.h" diff --git a/subsys/bluetooth/mesh/provisioner.c b/subsys/bluetooth/mesh/provisioner.c index aba2449892f..ba02723e830 100644 --- a/subsys/bluetooth/mesh/provisioner.c +++ b/subsys/bluetooth/mesh/provisioner.c @@ -21,7 +21,6 @@ #include "common/bt_str.h" #include "crypto.h" -#include "adv.h" #include "mesh.h" #include "net.h" #include "rpl.h" diff --git a/subsys/bluetooth/mesh/proxy.h b/subsys/bluetooth/mesh/proxy.h index a2f6bb45ff6..34a119c3df6 100644 --- a/subsys/bluetooth/mesh/proxy.h +++ b/subsys/bluetooth/mesh/proxy.h @@ -34,6 +34,6 @@ int bt_mesh_proxy_adv_start(void); void bt_mesh_proxy_identity_start(struct bt_mesh_subnet *sub, bool private); void bt_mesh_proxy_identity_stop(struct bt_mesh_subnet *sub); -bool bt_mesh_proxy_relay(struct net_buf *buf, uint16_t dst); +bool bt_mesh_proxy_relay(struct bt_mesh_adv *adv, uint16_t dst); void bt_mesh_proxy_addr_add(struct net_buf_simple *buf, uint16_t addr); uint8_t bt_mesh_proxy_srv_connected_cnt(void); diff --git a/subsys/bluetooth/mesh/proxy_cli.c b/subsys/bluetooth/mesh/proxy_cli.c index a0a25751b41..5dd6b02361f 100644 --- a/subsys/bluetooth/mesh/proxy_cli.c +++ b/subsys/bluetooth/mesh/proxy_cli.c @@ -16,7 +16,6 @@ #include #include "mesh.h" -#include "adv.h" #include "net.h" #include "rpl.h" #include "transport.h" @@ -79,7 +78,7 @@ static struct bt_mesh_proxy_server *find_proxy_srv_by_conn(struct bt_conn *conn) return NULL; } -bool bt_mesh_proxy_cli_relay(struct net_buf *buf) +bool bt_mesh_proxy_cli_relay(struct bt_mesh_adv *adv) { bool relayed = false; int i; @@ -91,7 +90,7 @@ bool bt_mesh_proxy_cli_relay(struct net_buf *buf) continue; } - if (bt_mesh_proxy_relay_send(server->role->conn, buf)) { + if (bt_mesh_proxy_relay_send(server->role->conn, adv)) { continue; } diff --git a/subsys/bluetooth/mesh/proxy_cli.h b/subsys/bluetooth/mesh/proxy_cli.h index 8c1fae10e84..c0b69f4aaf6 100644 --- a/subsys/bluetooth/mesh/proxy_cli.h +++ b/subsys/bluetooth/mesh/proxy_cli.h @@ -8,6 +8,6 @@ void bt_mesh_proxy_cli_adv_recv(const struct bt_le_scan_recv_info *info, struct net_buf_simple *buf); -bool bt_mesh_proxy_cli_relay(struct net_buf *buf); +bool bt_mesh_proxy_cli_relay(struct bt_mesh_adv *adv); bool bt_mesh_proxy_cli_is_connected(uint16_t net_idx); diff --git a/subsys/bluetooth/mesh/proxy_msg.c b/subsys/bluetooth/mesh/proxy_msg.c index 025909e0503..b2fa113d456 100644 --- a/subsys/bluetooth/mesh/proxy_msg.c +++ b/subsys/bluetooth/mesh/proxy_msg.c @@ -21,7 +21,6 @@ #include "common/bt_str.h" #include "mesh.h" -#include "adv.h" #include "net.h" #include "rpl.h" #include "transport.h" @@ -196,12 +195,12 @@ int bt_mesh_proxy_msg_send(struct bt_conn *conn, uint8_t type, static void buf_send_end(struct bt_conn *conn, void *user_data) { - struct net_buf *buf = user_data; + struct bt_mesh_adv *adv = user_data; - net_buf_unref(buf); + bt_mesh_adv_unref(adv); } -int bt_mesh_proxy_relay_send(struct bt_conn *conn, struct net_buf *buf) +int bt_mesh_proxy_relay_send(struct bt_conn *conn, struct bt_mesh_adv *adv) { int err; @@ -211,12 +210,12 @@ int bt_mesh_proxy_relay_send(struct bt_conn *conn, struct net_buf *buf) * so we need to make a copy. */ net_buf_simple_reserve(&msg, 1); - net_buf_simple_add_mem(&msg, buf->data, buf->len); + net_buf_simple_add_mem(&msg, adv->b.data, adv->b.len); err = bt_mesh_proxy_msg_send(conn, BT_MESH_PROXY_NET_PDU, - &msg, buf_send_end, net_buf_ref(buf)); + &msg, buf_send_end, bt_mesh_adv_ref(adv)); - bt_mesh_adv_send_start(0, err, BT_MESH_ADV(buf)); + bt_mesh_adv_send_start(0, err, &adv->ctx); if (err) { LOG_ERR("Failed to send proxy message (err %d)", err); @@ -225,7 +224,7 @@ int bt_mesh_proxy_relay_send(struct bt_conn *conn, struct net_buf *buf) * which is just opaque data to segment_and send) reference given * to segment_and_send() here. */ - net_buf_unref(buf); + bt_mesh_adv_unref(adv); } return err; diff --git a/subsys/bluetooth/mesh/proxy_msg.h b/subsys/bluetooth/mesh/proxy_msg.h index 7d4bd51ae4f..7ad4be7ae5d 100644 --- a/subsys/bluetooth/mesh/proxy_msg.h +++ b/subsys/bluetooth/mesh/proxy_msg.h @@ -51,7 +51,7 @@ ssize_t bt_mesh_proxy_msg_recv(struct bt_conn *conn, int bt_mesh_proxy_msg_send(struct bt_conn *conn, uint8_t type, struct net_buf_simple *msg, bt_gatt_complete_func_t end, void *user_data); -int bt_mesh_proxy_relay_send(struct bt_conn *conn, struct net_buf *buf); +int bt_mesh_proxy_relay_send(struct bt_conn *conn, struct bt_mesh_adv *adv); struct bt_mesh_proxy_role *bt_mesh_proxy_role_setup(struct bt_conn *conn, proxy_send_cb_t send, proxy_recv_cb_t recv); diff --git a/subsys/bluetooth/mesh/proxy_srv.c b/subsys/bluetooth/mesh/proxy_srv.c index 571144ceaed..45e29915325 100644 --- a/subsys/bluetooth/mesh/proxy_srv.c +++ b/subsys/bluetooth/mesh/proxy_srv.c @@ -20,7 +20,6 @@ #include "common/bt_str.h" #include "mesh.h" -#include "adv.h" #include "net.h" #include "rpl.h" #include "transport.h" @@ -1022,12 +1021,12 @@ static bool client_filter_match(struct bt_mesh_proxy_client *client, return false; } -bool bt_mesh_proxy_relay(struct net_buf *buf, uint16_t dst) +bool bt_mesh_proxy_relay(struct bt_mesh_adv *adv, uint16_t dst) { bool relayed = false; int i; - LOG_DBG("%u bytes to dst 0x%04x", buf->len, dst); + LOG_DBG("%u bytes to dst 0x%04x", adv->b.len, dst); for (i = 0; i < ARRAY_SIZE(clients); i++) { struct bt_mesh_proxy_client *client = &clients[i]; @@ -1040,7 +1039,7 @@ bool bt_mesh_proxy_relay(struct net_buf *buf, uint16_t dst) continue; } - if (bt_mesh_proxy_relay_send(client->cli->conn, buf)) { + if (bt_mesh_proxy_relay_send(client->cli->conn, adv)) { continue; } diff --git a/subsys/bluetooth/mesh/rpl.c b/subsys/bluetooth/mesh/rpl.c index e19df33908f..df67ddf9d2e 100644 --- a/subsys/bluetooth/mesh/rpl.c +++ b/subsys/bluetooth/mesh/rpl.c @@ -20,7 +20,6 @@ #include #include "mesh.h" -#include "adv.h" #include "net.h" #include "rpl.h" #include "settings.h" diff --git a/subsys/bluetooth/mesh/rpr_srv.c b/subsys/bluetooth/mesh/rpr_srv.c index 9813842a367..e97df35f28f 100644 --- a/subsys/bluetooth/mesh/rpr_srv.c +++ b/subsys/bluetooth/mesh/rpr_srv.c @@ -14,7 +14,6 @@ #include #include #include "access.h" -#include "adv.h" #include "prov.h" #include "crypto.h" #include "rpr.h" diff --git a/subsys/bluetooth/mesh/solicitation.c b/subsys/bluetooth/mesh/solicitation.c index e2100fa42db..642abfd87f1 100644 --- a/subsys/bluetooth/mesh/solicitation.c +++ b/subsys/bluetooth/mesh/solicitation.c @@ -12,7 +12,6 @@ #include #include #include "access.h" -#include "adv.h" #include "cfg.h" #include "crypto.h" #include "mesh.h" diff --git a/subsys/bluetooth/mesh/statistic.c b/subsys/bluetooth/mesh/statistic.c index 21c451bee73..b9f542a5923 100644 --- a/subsys/bluetooth/mesh/statistic.c +++ b/subsys/bluetooth/mesh/statistic.c @@ -6,7 +6,6 @@ #include -#include "adv.h" #include "net.h" #include "statistic.h" @@ -22,24 +21,24 @@ void bt_mesh_stat_reset(void) memset(&stat, 0, sizeof(struct bt_mesh_statistic)); } -void bt_mesh_stat_planned_count(struct bt_mesh_adv *adv) +void bt_mesh_stat_planned_count(struct bt_mesh_adv_ctx *ctx) { - if (adv->tag == BT_MESH_ADV_TAG_LOCAL) { + if (ctx->tag == BT_MESH_ADV_TAG_LOCAL) { stat.tx_local_planned++; - } else if (adv->tag == BT_MESH_ADV_TAG_RELAY) { + } else if (ctx->tag == BT_MESH_ADV_TAG_RELAY) { stat.tx_adv_relay_planned++; - } else if (adv->tag == BT_MESH_ADV_TAG_FRIEND) { + } else if (ctx->tag == BT_MESH_ADV_TAG_FRIEND) { stat.tx_friend_planned++; } } -void bt_mesh_stat_succeeded_count(struct bt_mesh_adv *adv) +void bt_mesh_stat_succeeded_count(struct bt_mesh_adv_ctx *ctx) { - if (adv->tag == BT_MESH_ADV_TAG_LOCAL) { + if (ctx->tag == BT_MESH_ADV_TAG_LOCAL) { stat.tx_local_succeeded++; - } else if (adv->tag == BT_MESH_ADV_TAG_RELAY) { + } else if (ctx->tag == BT_MESH_ADV_TAG_RELAY) { stat.tx_adv_relay_succeeded++; - } else if (adv->tag == BT_MESH_ADV_TAG_FRIEND) { + } else if (ctx->tag == BT_MESH_ADV_TAG_FRIEND) { stat.tx_friend_succeeded++; } } diff --git a/subsys/bluetooth/mesh/statistic.h b/subsys/bluetooth/mesh/statistic.h index fdb488f0d81..4cd9187f45a 100644 --- a/subsys/bluetooth/mesh/statistic.h +++ b/subsys/bluetooth/mesh/statistic.h @@ -7,8 +7,8 @@ #ifndef ZEPHYR_SUBSYS_BLUETOOTH_MESH_STATISTIC_H_ #define ZEPHYR_SUBSYS_BLUETOOTH_MESH_STATISTIC_H_ -void bt_mesh_stat_planned_count(struct bt_mesh_adv *adv); -void bt_mesh_stat_succeeded_count(struct bt_mesh_adv *adv); +void bt_mesh_stat_planned_count(struct bt_mesh_adv_ctx *ctx); +void bt_mesh_stat_succeeded_count(struct bt_mesh_adv_ctx *ctx); void bt_mesh_stat_rx(enum bt_mesh_net_if net_if); #endif /* ZEPHYR_SUBSYS_BLUETOOTH_MESH_STATISTIC_H_ */ diff --git a/subsys/bluetooth/mesh/subnet.c b/subsys/bluetooth/mesh/subnet.c index ef90ff8f725..695dd321b49 100644 --- a/subsys/bluetooth/mesh/subnet.c +++ b/subsys/bluetooth/mesh/subnet.c @@ -22,7 +22,6 @@ #include "common/bt_str.h" #include "crypto.h" -#include "adv.h" #include "mesh.h" #include "net.h" #include "lpn.h" diff --git a/subsys/bluetooth/mesh/transport.c b/subsys/bluetooth/mesh/transport.c index 94c1f698e91..47e8492a901 100644 --- a/subsys/bluetooth/mesh/transport.c +++ b/subsys/bluetooth/mesh/transport.c @@ -22,7 +22,6 @@ #include "host/testing.h" #include "crypto.h" -#include "adv.h" #include "mesh.h" #include "net.h" #include "app_keys.h" @@ -122,26 +121,26 @@ static int send_unseg(struct bt_mesh_net_tx *tx, struct net_buf_simple *sdu, const struct bt_mesh_send_cb *cb, void *cb_data, const uint8_t *ctl_op) { - struct net_buf *buf; + struct bt_mesh_adv *adv; - buf = bt_mesh_adv_create(BT_MESH_ADV_DATA, BT_MESH_ADV_TAG_LOCAL, + adv = bt_mesh_adv_create(BT_MESH_ADV_DATA, BT_MESH_ADV_TAG_LOCAL, tx->xmit, BUF_TIMEOUT); - if (!buf) { - LOG_ERR("Out of network buffers"); + if (!adv) { + LOG_ERR("Out of network advs"); return -ENOBUFS; } - net_buf_reserve(buf, BT_MESH_NET_HDR_LEN); + net_buf_simple_reserve(&adv->b, BT_MESH_NET_HDR_LEN); if (ctl_op) { - net_buf_add_u8(buf, TRANS_CTL_HDR(*ctl_op, 0)); + net_buf_simple_add_u8(&adv->b, TRANS_CTL_HDR(*ctl_op, 0)); } else if (BT_MESH_IS_DEV_KEY(tx->ctx->app_idx)) { - net_buf_add_u8(buf, UNSEG_HDR(0, 0)); + net_buf_simple_add_u8(&adv->b, UNSEG_HDR(0, 0)); } else { - net_buf_add_u8(buf, UNSEG_HDR(1, tx->aid)); + net_buf_simple_add_u8(&adv->b, UNSEG_HDR(1, tx->aid)); } - net_buf_add_mem(buf, sdu->data, sdu->len); + net_buf_simple_add_mem(&adv->b, sdu->data, sdu->len); if (IS_ENABLED(CONFIG_BT_MESH_FRIEND)) { if (!bt_mesh_friend_queue_has_space(tx->sub->net_idx, @@ -149,7 +148,7 @@ static int send_unseg(struct bt_mesh_net_tx *tx, struct net_buf_simple *sdu, NULL, 1)) { if (BT_MESH_ADDR_IS_UNICAST(tx->ctx->addr)) { LOG_ERR("Not enough space in Friend Queue"); - net_buf_unref(buf); + bt_mesh_adv_unref(adv); return -ENOBUFS; } else { LOG_WRN("No space in Friend Queue"); @@ -158,19 +157,19 @@ static int send_unseg(struct bt_mesh_net_tx *tx, struct net_buf_simple *sdu, } if (bt_mesh_friend_enqueue_tx(tx, BT_MESH_FRIEND_PDU_SINGLE, - NULL, 1, &buf->b) && + NULL, 1, &adv->b) && BT_MESH_ADDR_IS_UNICAST(tx->ctx->addr)) { /* PDUs for a specific Friend should only go * out through the Friend Queue. */ - net_buf_unref(buf); + bt_mesh_adv_unref(adv); send_cb_finalize(cb, cb_data); return 0; } } send: - return bt_mesh_net_send(tx, buf, cb, cb_data); + return bt_mesh_net_send(tx, adv, cb, cb_data); } static inline uint8_t seg_len(bool ctl) @@ -405,7 +404,7 @@ static void seg_tx_send_unacked(struct seg_tx *tx) (uint16_t)(tx->seq_auth & TRANS_SEQ_ZERO_MASK), tx->attempts_left); while (tx->seg_o <= tx->seg_n) { - struct net_buf *seg; + struct bt_mesh_adv *seg; int err; if (!tx->seg[tx->seg_o]) { @@ -421,7 +420,7 @@ static void seg_tx_send_unacked(struct seg_tx *tx) goto end; } - net_buf_reserve(seg, BT_MESH_NET_HDR_LEN); + net_buf_simple_reserve(&seg->b, BT_MESH_NET_HDR_LEN); seg_tx_buf_build(tx, tx->seg_o, &seg->b); LOG_DBG("Sending %u/%u", tx->seg_o, tx->seg_n); diff --git a/subsys/bluetooth/mesh/transport_legacy.c b/subsys/bluetooth/mesh/transport_legacy.c index da0c1830f73..1a826db4ac4 100644 --- a/subsys/bluetooth/mesh/transport_legacy.c +++ b/subsys/bluetooth/mesh/transport_legacy.c @@ -22,7 +22,6 @@ #include "host/testing.h" #include "crypto.h" -#include "adv.h" #include "mesh.h" #include "net.h" #include "app_keys.h" @@ -129,26 +128,26 @@ static int send_unseg(struct bt_mesh_net_tx *tx, struct net_buf_simple *sdu, const struct bt_mesh_send_cb *cb, void *cb_data, const uint8_t *ctl_op) { - struct net_buf *buf; + struct bt_mesh_adv *adv; - buf = bt_mesh_adv_create(BT_MESH_ADV_DATA, BT_MESH_ADV_TAG_LOCAL, + adv = bt_mesh_adv_create(BT_MESH_ADV_DATA, BT_MESH_ADV_TAG_LOCAL, tx->xmit, BUF_TIMEOUT); - if (!buf) { - LOG_ERR("Out of network buffers"); + if (!adv) { + LOG_ERR("Out of network advs"); return -ENOBUFS; } - net_buf_reserve(buf, BT_MESH_NET_HDR_LEN); + net_buf_simple_reserve(&adv->b, BT_MESH_NET_HDR_LEN); if (ctl_op) { - net_buf_add_u8(buf, TRANS_CTL_HDR(*ctl_op, 0)); + net_buf_simple_add_u8(&adv->b, TRANS_CTL_HDR(*ctl_op, 0)); } else if (BT_MESH_IS_DEV_KEY(tx->ctx->app_idx)) { - net_buf_add_u8(buf, UNSEG_HDR(0, 0)); + net_buf_simple_add_u8(&adv->b, UNSEG_HDR(0, 0)); } else { - net_buf_add_u8(buf, UNSEG_HDR(1, tx->aid)); + net_buf_simple_add_u8(&adv->b, UNSEG_HDR(1, tx->aid)); } - net_buf_add_mem(buf, sdu->data, sdu->len); + net_buf_simple_add_mem(&adv->b, sdu->data, sdu->len); if (IS_ENABLED(CONFIG_BT_MESH_FRIEND)) { if (!bt_mesh_friend_queue_has_space(tx->sub->net_idx, @@ -156,7 +155,7 @@ static int send_unseg(struct bt_mesh_net_tx *tx, struct net_buf_simple *sdu, NULL, 1)) { if (BT_MESH_ADDR_IS_UNICAST(tx->ctx->addr)) { LOG_ERR("Not enough space in Friend Queue"); - net_buf_unref(buf); + bt_mesh_adv_unref(adv); return -ENOBUFS; } @@ -165,19 +164,19 @@ static int send_unseg(struct bt_mesh_net_tx *tx, struct net_buf_simple *sdu, } if (bt_mesh_friend_enqueue_tx(tx, BT_MESH_FRIEND_PDU_SINGLE, - NULL, 1, &buf->b) && + NULL, 1, &adv->b) && BT_MESH_ADDR_IS_UNICAST(tx->ctx->addr)) { /* PDUs for a specific Friend should only go * out through the Friend Queue. */ - net_buf_unref(buf); + bt_mesh_adv_unref(adv); send_cb_finalize(cb, cb_data); return 0; } } send: - return bt_mesh_net_send(tx, buf, cb, cb_data); + return bt_mesh_net_send(tx, adv, cb, cb_data); } static inline uint8_t seg_len(bool ctl) @@ -392,7 +391,7 @@ static void seg_tx_send_unacked(struct seg_tx *tx) tx->attempts); while (tx->seg_o <= tx->seg_n) { - struct net_buf *seg; + struct bt_mesh_adv *seg; int err; if (!tx->seg[tx->seg_o]) { @@ -408,7 +407,7 @@ static void seg_tx_send_unacked(struct seg_tx *tx) goto end; } - net_buf_reserve(seg, BT_MESH_NET_HDR_LEN); + net_buf_simple_reserve(&seg->b, BT_MESH_NET_HDR_LEN); seg_tx_buf_build(tx, tx->seg_o, &seg->b); LOG_DBG("Sending %u/%u", tx->seg_o, tx->seg_n); diff --git a/tests/bsim/bluetooth/mesh/src/test_advertiser.c b/tests/bsim/bluetooth/mesh/src/test_advertiser.c index 073651ae843..47851fc72f4 100644 --- a/tests/bsim/bluetooth/mesh/src/test_advertiser.c +++ b/tests/bsim/bluetooth/mesh/src/test_advertiser.c @@ -7,7 +7,6 @@ #include #include #include "mesh_test.h" -#include "mesh/adv.h" #include "mesh/net.h" #include "mesh/mesh.h" #include "mesh/foundation.h" @@ -78,25 +77,25 @@ static void adv_init(void) ASSERT_OK_MSG(bt_mesh_adv_enable(), "Mesh adv init failed"); } -static void allocate_all_array(struct net_buf **buf, size_t num_buf, uint8_t xmit) +static void allocate_all_array(struct bt_mesh_adv **adv, size_t num_adv, uint8_t xmit) { - for (int i = 0; i < num_buf; i++) { - *buf = bt_mesh_adv_create(BT_MESH_ADV_DATA, BT_MESH_ADV_TAG_LOCAL, + for (int i = 0; i < num_adv; i++) { + *adv = bt_mesh_adv_create(BT_MESH_ADV_DATA, BT_MESH_ADV_TAG_LOCAL, xmit, K_NO_WAIT); - ASSERT_FALSE_MSG(!*buf, "Out of buffers\n"); - buf++; + ASSERT_FALSE_MSG(!*adv, "Out of advs\n"); + adv++; } } static void verify_adv_queue_overflow(void) { - struct net_buf *dummy_buf; + struct bt_mesh_adv *dummy_adv; /* Verity Queue overflow */ - dummy_buf = bt_mesh_adv_create(BT_MESH_ADV_DATA, BT_MESH_ADV_TAG_LOCAL, + dummy_adv = bt_mesh_adv_create(BT_MESH_ADV_DATA, BT_MESH_ADV_TAG_LOCAL, BT_MESH_TRANSMIT(2, 20), K_NO_WAIT); - ASSERT_TRUE_MSG(!dummy_buf, "Unexpected extra buffer\n"); + ASSERT_TRUE_MSG(!dummy_adv, "Unexpected extra adv\n"); } static bool check_delta_time(uint8_t transmit, uint64_t interval) @@ -157,12 +156,12 @@ static void single_end_cb(int err, void *cb_data) static void realloc_end_cb(int err, void *cb_data) { - struct net_buf *buf = (struct net_buf *)cb_data; + struct bt_mesh_adv *adv = (struct bt_mesh_adv *)cb_data; ASSERT_EQUAL(0, err); - buf = bt_mesh_adv_create(BT_MESH_ADV_DATA, BT_MESH_ADV_TAG_LOCAL, + adv = bt_mesh_adv_create(BT_MESH_ADV_DATA, BT_MESH_ADV_TAG_LOCAL, BT_MESH_TRANSMIT(2, 20), K_NO_WAIT); - ASSERT_FALSE_MSG(!buf, "Out of buffers\n"); + ASSERT_FALSE_MSG(!adv, "Out of advs\n"); k_sem_give(&observer_sem); } @@ -305,13 +304,13 @@ static void rx_xmit_adv(void) static void send_order_start_cb(uint16_t duration, int err, void *user_data) { - struct net_buf *buf = (struct net_buf *)user_data; + struct bt_mesh_adv *adv = (struct bt_mesh_adv *)user_data; ASSERT_OK_MSG(err, "Failed adv start cb err (%d)", err); - ASSERT_EQUAL(2, buf->len); + ASSERT_EQUAL(2, adv->b.len); - uint8_t current = buf->data[0]; - uint8_t previous = buf->data[1]; + uint8_t current = adv->b.data[0]; + uint8_t previous = adv->b.data[1]; LOG_INF("tx start: current(%d) previous(%d)", current, previous); @@ -321,10 +320,7 @@ static void send_order_start_cb(uint16_t duration, int err, void *user_data) static void send_order_end_cb(int err, void *user_data) { - struct net_buf *buf = (struct net_buf *)user_data; - ASSERT_OK_MSG(err, "Failed adv start cb err (%d)", err); - ASSERT_TRUE_MSG(!buf->data, "Data not cleared!\n"); seq_checker++; LOG_INF("tx end: seq(%d)", seq_checker); @@ -380,19 +376,19 @@ static void receive_order(int expect_adv) ASSERT_FALSE_MSG(err && err != -EALREADY, "Stopping scan failed (err %d)\n", err); } -static void send_adv_buf(struct net_buf *buf, uint8_t curr, uint8_t prev) +static void send_adv_buf(struct bt_mesh_adv *adv, uint8_t curr, uint8_t prev) { send_cb.start = send_order_start_cb; send_cb.end = send_order_end_cb; - (void)net_buf_add_u8(buf, curr); - (void)net_buf_add_u8(buf, prev); + (void)net_buf_simple_add_u8(&adv->b, curr); + (void)net_buf_simple_add_u8(&adv->b, prev); - bt_mesh_adv_send(buf, &send_cb, buf); - net_buf_unref(buf); + bt_mesh_adv_send(adv, &send_cb, adv); + bt_mesh_adv_unref(adv); } -static void send_adv_array(struct net_buf **buf, size_t num_buf, bool reverse) +static void send_adv_array(struct bt_mesh_adv **adv, size_t num_buf, bool reverse) { uint8_t previous; int i; @@ -405,13 +401,13 @@ static void send_adv_array(struct net_buf **buf, size_t num_buf, bool reverse) i = num_buf - 1; } while ((!reverse && i < num_buf) || (reverse && i >= 0)) { - send_adv_buf(*buf, (uint8_t)i, previous); + send_adv_buf(*adv, (uint8_t)i, previous); previous = (uint8_t)i; if (!reverse) { - buf++; + adv++; i++; } else { - buf--; + adv--; i--; } } @@ -419,24 +415,24 @@ static void send_adv_array(struct net_buf **buf, size_t num_buf, bool reverse) static void test_tx_cb_single(void) { - struct net_buf *buf; + struct bt_mesh_adv *adv; int err; bt_init(); adv_init(); - buf = bt_mesh_adv_create(BT_MESH_ADV_DATA, BT_MESH_ADV_TAG_LOCAL, + adv = bt_mesh_adv_create(BT_MESH_ADV_DATA, BT_MESH_ADV_TAG_LOCAL, BT_MESH_TRANSMIT(2, 20), K_NO_WAIT); - ASSERT_FALSE_MSG(!buf, "Out of buffers\n"); + ASSERT_FALSE_MSG(!adv, "Out of advs\n"); send_cb.start = single_start_cb; send_cb.end = single_end_cb; - net_buf_add_mem(buf, txt_msg, sizeof(txt_msg)); + net_buf_simple_add_mem(&adv->b, txt_msg, sizeof(txt_msg)); seq_checker = 0; tx_timestamp = k_uptime_get(); - bt_mesh_adv_send(buf, &send_cb, (void *)cb_msg); - net_buf_unref(buf); + bt_mesh_adv_send(adv, &send_cb, (void *)cb_msg); + bt_mesh_adv_unref(adv); err = k_sem_take(&observer_sem, K_SECONDS(1)); ASSERT_OK_MSG(err, "Didn't call end tx cb."); @@ -457,37 +453,37 @@ static void test_rx_xmit(void) static void test_tx_cb_multi(void) { - struct net_buf *buf[CONFIG_BT_MESH_ADV_BUF_COUNT]; + struct bt_mesh_adv *adv[CONFIG_BT_MESH_ADV_BUF_COUNT]; int err; bt_init(); adv_init(); - /* Allocate all network buffers. */ - allocate_all_array(buf, ARRAY_SIZE(buf), BT_MESH_TRANSMIT(2, 20)); + /* Allocate all network advs. */ + allocate_all_array(adv, ARRAY_SIZE(adv), BT_MESH_TRANSMIT(2, 20)); - /* Start single adv to reallocate one network buffer in callback. - * Check that the buffer is freed before cb is triggered. + /* Start single adv to reallocate one network adv in callback. + * Check that the adv is freed before cb is triggered. */ send_cb.start = NULL; send_cb.end = realloc_end_cb; - net_buf_add_mem(buf[0], txt_msg, sizeof(txt_msg)); + net_buf_simple_add_mem(&(adv[0]->b), txt_msg, sizeof(txt_msg)); - bt_mesh_adv_send(buf[0], &send_cb, buf[0]); - net_buf_unref(buf[0]); + bt_mesh_adv_send(adv[0], &send_cb, adv[0]); + bt_mesh_adv_unref(adv[0]); err = k_sem_take(&observer_sem, K_SECONDS(1)); - ASSERT_OK_MSG(err, "Didn't call the end tx cb that reallocates buffer one more time."); + ASSERT_OK_MSG(err, "Didn't call the end tx cb that reallocates adv one more time."); - /* Start multi advs to check that all buffers are sent and cbs are triggered. */ + /* Start multi advs to check that all advs are sent and cbs are triggered. */ send_cb.start = seq_start_cb; send_cb.end = seq_end_cb; seq_checker = 0; for (int i = 0; i < CONFIG_BT_MESH_ADV_BUF_COUNT; i++) { - net_buf_add_le32(buf[i], i); - bt_mesh_adv_send(buf[i], &send_cb, (void *)(intptr_t)i); - net_buf_unref(buf[i]); + net_buf_simple_add_le32(&(adv[i]->b), i); + bt_mesh_adv_send(adv[i], &send_cb, (void *)(intptr_t)i); + bt_mesh_adv_unref(adv[i]); } err = k_sem_take(&observer_sem, K_SECONDS(10)); @@ -530,10 +526,10 @@ static void test_tx_proxy_mixin(void) * Advertising the proxy service should be resumed after * finishing advertising the message. */ - struct net_buf *buf = bt_mesh_adv_create(BT_MESH_ADV_DATA, BT_MESH_ADV_TAG_LOCAL, + struct bt_mesh_adv *adv = bt_mesh_adv_create(BT_MESH_ADV_DATA, BT_MESH_ADV_TAG_LOCAL, BT_MESH_TRANSMIT(5, 20), K_NO_WAIT); - net_buf_add_mem(buf, txt_msg, sizeof(txt_msg)); - bt_mesh_adv_send(buf, NULL, NULL); + net_buf_simple_add_mem(&adv->b, txt_msg, sizeof(txt_msg)); + bt_mesh_adv_send(adv, NULL, NULL); k_sleep(K_MSEC(150)); /* Let the tester to measure an interval between advertisements again. */ @@ -577,46 +573,46 @@ static void test_rx_proxy_mixin(void) static void test_tx_send_order(void) { - struct net_buf *buf[CONFIG_BT_MESH_ADV_BUF_COUNT]; + struct bt_mesh_adv *adv[CONFIG_BT_MESH_ADV_BUF_COUNT]; uint8_t xmit = BT_MESH_TRANSMIT(2, 20); bt_init(); adv_init(); /* Verify sending order */ - allocate_all_array(buf, ARRAY_SIZE(buf), xmit); + allocate_all_array(adv, ARRAY_SIZE(adv), xmit); verify_adv_queue_overflow(); - send_adv_array(&buf[0], ARRAY_SIZE(buf), false); + send_adv_array(&adv[0], ARRAY_SIZE(adv), false); /* Wait for no message receive window to end. */ ASSERT_OK_MSG(k_sem_take(&observer_sem, K_SECONDS(10)), "Didn't call the last end tx cb."); - /* Verify buffer allocation/deallocation after sending */ - allocate_all_array(buf, ARRAY_SIZE(buf), xmit); + /* Verify adv allocation/deallocation after sending */ + allocate_all_array(adv, ARRAY_SIZE(adv), xmit); verify_adv_queue_overflow(); for (int i = 0; i < CONFIG_BT_MESH_ADV_BUF_COUNT; i++) { - net_buf_unref(buf[i]); - buf[i] = NULL; + bt_mesh_adv_unref(adv[i]); + adv[i] = NULL; } - /* Check that it possible to add just one net buf. */ - allocate_all_array(buf, 1, xmit); + /* Check that it possible to add just one net adv. */ + allocate_all_array(adv, 1, xmit); PASS(); } static void test_tx_reverse_order(void) { - struct net_buf *buf[CONFIG_BT_MESH_ADV_BUF_COUNT]; + struct bt_mesh_adv *adv[CONFIG_BT_MESH_ADV_BUF_COUNT]; uint8_t xmit = BT_MESH_TRANSMIT(2, 20); bt_init(); adv_init(); /* Verify reversed sending order */ - allocate_all_array(buf, ARRAY_SIZE(buf), xmit); + allocate_all_array(adv, ARRAY_SIZE(adv), xmit); - send_adv_array(&buf[CONFIG_BT_MESH_ADV_BUF_COUNT - 1], ARRAY_SIZE(buf), true); + send_adv_array(&adv[CONFIG_BT_MESH_ADV_BUF_COUNT - 1], ARRAY_SIZE(adv), true); /* Wait for no message receive window to end. */ ASSERT_OK_MSG(k_sem_take(&observer_sem, K_SECONDS(10)), @@ -627,31 +623,31 @@ static void test_tx_reverse_order(void) static void test_tx_random_order(void) { - struct net_buf *buf[3]; + struct bt_mesh_adv *adv[3]; uint8_t xmit = BT_MESH_TRANSMIT(0, 20); bt_init(); adv_init(); /* Verify random order calls */ - num_adv_sent = ARRAY_SIZE(buf); + num_adv_sent = ARRAY_SIZE(adv); previous_checker = 0xff; - buf[0] = bt_mesh_adv_create(BT_MESH_ADV_DATA, BT_MESH_ADV_TAG_LOCAL, + adv[0] = bt_mesh_adv_create(BT_MESH_ADV_DATA, BT_MESH_ADV_TAG_LOCAL, xmit, K_NO_WAIT); - ASSERT_FALSE_MSG(!buf[0], "Out of buffers\n"); - buf[1] = bt_mesh_adv_create(BT_MESH_ADV_DATA, BT_MESH_ADV_TAG_LOCAL, + ASSERT_FALSE_MSG(!adv[0], "Out of advs\n"); + adv[1] = bt_mesh_adv_create(BT_MESH_ADV_DATA, BT_MESH_ADV_TAG_LOCAL, xmit, K_NO_WAIT); - ASSERT_FALSE_MSG(!buf[1], "Out of buffers\n"); + ASSERT_FALSE_MSG(!adv[1], "Out of advs\n"); - send_adv_buf(buf[0], 0, 0xff); + send_adv_buf(adv[0], 0, 0xff); - buf[2] = bt_mesh_adv_create(BT_MESH_ADV_DATA, BT_MESH_ADV_TAG_LOCAL, + adv[2] = bt_mesh_adv_create(BT_MESH_ADV_DATA, BT_MESH_ADV_TAG_LOCAL, xmit, K_NO_WAIT); - ASSERT_FALSE_MSG(!buf[2], "Out of buffers\n"); + ASSERT_FALSE_MSG(!adv[2], "Out of advs\n"); - send_adv_buf(buf[2], 2, 0); + send_adv_buf(adv[2], 2, 0); - send_adv_buf(buf[1], 1, 2); + send_adv_buf(adv[1], 1, 2); /* Wait for no message receive window to end. */ ASSERT_OK_MSG(k_sem_take(&observer_sem, K_SECONDS(10)), diff --git a/tests/bsim/bluetooth/mesh/src/test_beacon.c b/tests/bsim/bluetooth/mesh/src/test_beacon.c index e93c2301e46..038c705f2cb 100644 --- a/tests/bsim/bluetooth/mesh/src/test_beacon.c +++ b/tests/bsim/bluetooth/mesh/src/test_beacon.c @@ -6,7 +6,6 @@ #include #include #include "mesh_test.h" -#include "mesh/adv.h" #include "mesh/net.h" #include "mesh/beacon.h" #include "mesh/mesh.h" diff --git a/tests/bsim/bluetooth/mesh/src/test_blob.c b/tests/bsim/bluetooth/mesh/src/test_blob.c index 4258ff77c62..0d3a69da2fc 100644 --- a/tests/bsim/bluetooth/mesh/src/test_blob.c +++ b/tests/bsim/bluetooth/mesh/src/test_blob.c @@ -6,9 +6,9 @@ #include "mesh_test.h" #include "dfu_blob_common.h" #include "friendship_common.h" +#include "mesh/adv.h" #include "mesh/blob.h" #include "argparse.h" -#include "mesh/adv.h" #define LOG_MODULE_NAME test_blob diff --git a/tests/bsim/bluetooth/mesh/src/test_dfu.c b/tests/bsim/bluetooth/mesh/src/test_dfu.c index 06f7248a6ad..1b54e873cc5 100644 --- a/tests/bsim/bluetooth/mesh/src/test_dfu.c +++ b/tests/bsim/bluetooth/mesh/src/test_dfu.c @@ -6,7 +6,6 @@ #include "mesh_test.h" #include "mesh/dfd_srv_internal.h" #include "mesh/dfu_slot.h" -#include "mesh/adv.h" #include "mesh/dfu.h" #include "mesh/blob.h" #include "argparse.h" diff --git a/tests/bsim/bluetooth/mesh/src/test_provision.c b/tests/bsim/bluetooth/mesh/src/test_provision.c index 0d7f1811833..9a83f874e11 100644 --- a/tests/bsim/bluetooth/mesh/src/test_provision.c +++ b/tests/bsim/bluetooth/mesh/src/test_provision.c @@ -28,7 +28,6 @@ #define LOG_MODULE_NAME mesh_prov #include -#include "mesh/adv.h" #include "mesh/rpr.h" LOG_MODULE_REGISTER(LOG_MODULE_NAME); diff --git a/tests/bsim/bluetooth/mesh/src/test_scanner.c b/tests/bsim/bluetooth/mesh/src/test_scanner.c index 12557b7e1b2..a63284701df 100644 --- a/tests/bsim/bluetooth/mesh/src/test_scanner.c +++ b/tests/bsim/bluetooth/mesh/src/test_scanner.c @@ -6,7 +6,6 @@ #include #include "mesh_test.h" #include "mesh/net.h" -#include "mesh/adv.h" #include "mesh/mesh.h" #include "mesh/foundation.h" From b493d51bb13d8f04e609fc8f068ece79d8a5c2a3 Mon Sep 17 00:00:00 2001 From: Bryan Zhu Date: Fri, 8 Dec 2023 08:45:29 +0800 Subject: [PATCH 0945/3723] drivers: i2c: i2c_ambiq: fixing error in bitrate setting During init i2c_ambiq device, the bitrate calculation is not correct, results in incorrect device speed, or failed to configure i2c device if clock-frequency is set to higher than I2C_BITRATE_STANDARD Signed-off-by: Bryan Zhu --- drivers/i2c/i2c_ambiq.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/i2c/i2c_ambiq.c b/drivers/i2c/i2c_ambiq.c index 432bfbe4f00..d5b94686739 100644 --- a/drivers/i2c/i2c_ambiq.c +++ b/drivers/i2c/i2c_ambiq.c @@ -139,7 +139,7 @@ static int i2c_ambiq_init(const struct device *dev) ret = config->pwr_func(); - ret = i2c_ambiq_configure(dev, I2C_MODE_CONTROLLER | I2C_SPEED_SET(bitrate_cfg)); + ret = i2c_ambiq_configure(dev, I2C_MODE_CONTROLLER | bitrate_cfg); ret = pinctrl_apply_state(config->pcfg, PINCTRL_STATE_DEFAULT); From a9b0230360dbddbd3a241c42c5d09eb1ed548f4a Mon Sep 17 00:00:00 2001 From: Arkadiusz Wadowski Date: Thu, 7 Dec 2023 09:34:49 +0100 Subject: [PATCH 0946/3723] mgmt/osdp: Fix compilation when CONFIG_OSDP_SC_ENABLED enabled The 2 issues were found after CONFIG_OSDP_SC_ENABLED was enabled: - missing curly brace after if - typo in type name Signed-off-by: Arkadiusz Wadowski --- subsys/mgmt/osdp/src/osdp_phy.c | 3 +-- subsys/mgmt/osdp/src/osdp_sc.c | 2 +- 2 files changed, 2 insertions(+), 3 deletions(-) diff --git a/subsys/mgmt/osdp/src/osdp_phy.c b/subsys/mgmt/osdp/src/osdp_phy.c index 2399b545c0d..ce01bb65694 100644 --- a/subsys/mgmt/osdp/src/osdp_phy.c +++ b/subsys/mgmt/osdp/src/osdp_phy.c @@ -193,8 +193,7 @@ int osdp_phy_packet_finalize(struct osdp_pd *pd, uint8_t *buf, uint8_t *data; int i, data_len; - if (sc_is_active(pd) && - (pkt->control & PKT_CONTROL_SCB) && pkt->data[1] >= SCS_15) + if (sc_is_active(pd) && (pkt->control & PKT_CONTROL_SCB) && pkt->data[1] >= SCS_15) { if (pkt->data[1] == SCS_17 || pkt->data[1] == SCS_18) { /** * Only the data portion of message (after id byte) diff --git a/subsys/mgmt/osdp/src/osdp_sc.c b/subsys/mgmt/osdp/src/osdp_sc.c index 2ceb607fb3c..e816aa49f82 100644 --- a/subsys/mgmt/osdp/src/osdp_sc.c +++ b/subsys/mgmt/osdp/src/osdp_sc.c @@ -25,7 +25,7 @@ static const uint8_t osdp_scbk_default[16] = { static void osdp_memzero(void *mem, size_t size) { size_t i; - volatile uin8_t *p = mem; + volatile uint8_t *p = mem; for (i = 0; i < size; i++) { p[i] = 0; From 3fc40c977974bf734613c6b039b031dfdfdf0e42 Mon Sep 17 00:00:00 2001 From: Arkadiusz Wadowski Date: Thu, 7 Dec 2023 09:41:16 +0100 Subject: [PATCH 0947/3723] mgmt/osdp: Remove unused variable from osdp_phy_packet_finalize() The variable was removed to avoid generating compilation warrning. Signed-off-by: Arkadiusz Wadowski --- subsys/mgmt/osdp/src/osdp_phy.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/subsys/mgmt/osdp/src/osdp_phy.c b/subsys/mgmt/osdp/src/osdp_phy.c index ce01bb65694..1f7c452458c 100644 --- a/subsys/mgmt/osdp/src/osdp_phy.c +++ b/subsys/mgmt/osdp/src/osdp_phy.c @@ -191,7 +191,7 @@ int osdp_phy_packet_finalize(struct osdp_pd *pd, uint8_t *buf, #ifdef CONFIG_OSDP_SC_ENABLED uint8_t *data; - int i, data_len; + int data_len; if (sc_is_active(pd) && (pkt->control & PKT_CONTROL_SCB) && pkt->data[1] >= SCS_15) { if (pkt->data[1] == SCS_17 || pkt->data[1] == SCS_18) { From b49fb0d289856310c4cb77664363235cbf03fc2f Mon Sep 17 00:00:00 2001 From: Arkadiusz Wadowski Date: Thu, 7 Dec 2023 10:27:58 +0100 Subject: [PATCH 0948/3723] mgmt/osdp: Add build-only tests for OSDP samples Such tests will help to catch any compilation errors in future Signed-off-by: Arkadiusz Wadowski --- .../mgmt/osdp/control_panel/prj_sc.conf | 19 ++++++++++++++++++ .../mgmt/osdp/control_panel/sample.yaml | 20 ++++++++++++------- .../mgmt/osdp/peripheral_device/prj_sc.conf | 19 ++++++++++++++++++ .../mgmt/osdp/peripheral_device/sample.yaml | 20 ++++++++++++------- 4 files changed, 64 insertions(+), 14 deletions(-) create mode 100644 samples/subsys/mgmt/osdp/control_panel/prj_sc.conf create mode 100644 samples/subsys/mgmt/osdp/peripheral_device/prj_sc.conf diff --git a/samples/subsys/mgmt/osdp/control_panel/prj_sc.conf b/samples/subsys/mgmt/osdp/control_panel/prj_sc.conf new file mode 100644 index 00000000000..a13fc8f12b7 --- /dev/null +++ b/samples/subsys/mgmt/osdp/control_panel/prj_sc.conf @@ -0,0 +1,19 @@ +# +# Copyright (c) 2020 Siddharth Chandrasekaran +# +# SPDX-License-Identifier: Apache-2.0 +# + +CONFIG_PRINTK=y +CONFIG_LOG=y +CONFIG_GPIO=y + +# OSDP config +CONFIG_OSDP=y +CONFIG_OSDP_MODE_CP=y + +# Secure Channel +CONFIG_ENTROPY_GENERATOR=y +CONFIG_OSDP_SC_ENABLED=y + +CONFIG_OSDP_LOG_LEVEL=4 diff --git a/samples/subsys/mgmt/osdp/control_panel/sample.yaml b/samples/subsys/mgmt/osdp/control_panel/sample.yaml index c9322a4ebd9..5fecf6ad24a 100644 --- a/samples/subsys/mgmt/osdp/control_panel/sample.yaml +++ b/samples/subsys/mgmt/osdp/control_panel/sample.yaml @@ -1,12 +1,18 @@ sample: description: OSDP Control Panel Sample name: osdp +common: + tags: osdp + depends_on: gpio + filter: dt_enabled_alias_with_parent_compat("led0", "gpio-leds") and + dt_chosen_enabled("zephyr,osdp-uart") and CONFIG_SERIAL + harness: osdp + integration_platforms: + - stm32_min_dev_black tests: sample.mgmt.osdp.control_panel: - tags: osdp - depends_on: gpio - filter: dt_enabled_alias_with_parent_compat("led0", "gpio-leds") and - dt_chosen_enabled("zephyr,osdp-uart") and CONFIG_SERIAL - harness: osdp - integration_platforms: - - stm32_min_dev_black + extra_args: CONF_FILE=prj.conf + + sample.mgmt.osdp.control_panel_sc: + build_only: true + extra_args: CONF_FILE=prj_sc.conf diff --git a/samples/subsys/mgmt/osdp/peripheral_device/prj_sc.conf b/samples/subsys/mgmt/osdp/peripheral_device/prj_sc.conf new file mode 100644 index 00000000000..cd67c09e7bc --- /dev/null +++ b/samples/subsys/mgmt/osdp/peripheral_device/prj_sc.conf @@ -0,0 +1,19 @@ +# +# Copyright (c) 2020 Siddharth Chandrasekaran +# +# SPDX-License-Identifier: Apache-2.0 +# + +CONFIG_PRINTK=y +CONFIG_LOG=y +CONFIG_GPIO=y + +# OSDP config +CONFIG_OSDP=y +CONFIG_OSDP_MODE_PD=y + +# Secure Channel +CONFIG_ENTROPY_GENERATOR=y +CONFIG_OSDP_SC_ENABLED=y + +CONFIG_OSDP_LOG_LEVEL=4 diff --git a/samples/subsys/mgmt/osdp/peripheral_device/sample.yaml b/samples/subsys/mgmt/osdp/peripheral_device/sample.yaml index ded4397ac41..994ea535e3f 100644 --- a/samples/subsys/mgmt/osdp/peripheral_device/sample.yaml +++ b/samples/subsys/mgmt/osdp/peripheral_device/sample.yaml @@ -1,12 +1,18 @@ sample: description: OSDP Peripheral Device Sample name: osdp +common: + tags: osdp + depends_on: gpio + filter: dt_enabled_alias_with_parent_compat("led0", "gpio-leds") and + dt_chosen_enabled("zephyr,osdp-uart") and CONFIG_SERIAL + harness: osdp + integration_platforms: + - stm32_min_dev_black tests: sample.mgmt.osdp.peripheral_device: - tags: osdp - depends_on: gpio - filter: dt_enabled_alias_with_parent_compat("led0", "gpio-leds") and - dt_chosen_enabled("zephyr,osdp-uart") and CONFIG_SERIAL - harness: osdp - integration_platforms: - - stm32_min_dev_black + extra_args: CONF_FILE=prj.conf + + sample.mgmt.osdp.peripheral_device_sc: + build_only: true + extra_args: CONF_FILE=prj_sc.conf From 23964234ac7e495108b2822d5627cf6e2288c48f Mon Sep 17 00:00:00 2001 From: Adam Wojasinski Date: Thu, 7 Dec 2023 15:11:27 +0100 Subject: [PATCH 0949/3723] boards: Add alias to boards with spi-flash node This is continuation of the 64fbbd9a446ce18a6a941bbbffd7572b338eb123 where spi-flash0 alias was defined for some of boards' devicetrees. It's needed to turn on building samples/drivers/spi_flash for boards with "nordic,qspi-nor" compatible. Signed-off-by: Adam Wojasinski --- boards/arm/bl5340_dvk/bl5340_dvk_cpuapp_ns.dts | 5 ----- boards/arm/bt610/bt610.dts | 1 + boards/arm/mg100/mg100.dts | 1 + boards/arm/pinnacle_100_dvk/pinnacle_100_dvk.dts | 1 + .../arm/ubx_bmd340eval_nrf52840/ubx_bmd340eval_nrf52840.dts | 1 + .../arm/ubx_bmd345eval_nrf52840/ubx_bmd345eval_nrf52840.dts | 1 + .../arm/ubx_bmd380eval_nrf52840/ubx_bmd380eval_nrf52840.dts | 1 + 7 files changed, 6 insertions(+), 5 deletions(-) diff --git a/boards/arm/bl5340_dvk/bl5340_dvk_cpuapp_ns.dts b/boards/arm/bl5340_dvk/bl5340_dvk_cpuapp_ns.dts index b0c2935e621..9fdcba5f0e3 100644 --- a/boards/arm/bl5340_dvk/bl5340_dvk_cpuapp_ns.dts +++ b/boards/arm/bl5340_dvk/bl5340_dvk_cpuapp_ns.dts @@ -17,11 +17,6 @@ zephyr,flash = &flash0; zephyr,code-partition = &slot0_ns_partition; }; - - /* Aliases for deleted nodes must be removed */ - aliases { - /delete-property/ spi-flash0; - }; }; zephyr_udc0: &usbd { diff --git a/boards/arm/bt610/bt610.dts b/boards/arm/bt610/bt610.dts index 489401a5fb3..c6b9bad9910 100644 --- a/boards/arm/bt610/bt610.dts +++ b/boards/arm/bt610/bt610.dts @@ -77,6 +77,7 @@ mcuboot-button0 = &button1; mcuboot-led0 = &led1; watchdog0 = &wdt0; + spi-flash0 = &mx25r64; }; mag1: mag_1 { diff --git a/boards/arm/mg100/mg100.dts b/boards/arm/mg100/mg100.dts index 1bbaa146dd6..67f4b3677a5 100644 --- a/boards/arm/mg100/mg100.dts +++ b/boards/arm/mg100/mg100.dts @@ -65,6 +65,7 @@ mcuboot-button0 = &button1; mcuboot-led0 = &led1; watchdog0 = &wdt0; + spi-flash0 = &mx25r64; }; }; diff --git a/boards/arm/pinnacle_100_dvk/pinnacle_100_dvk.dts b/boards/arm/pinnacle_100_dvk/pinnacle_100_dvk.dts index 19f9e6ff41e..b50c526be4c 100644 --- a/boards/arm/pinnacle_100_dvk/pinnacle_100_dvk.dts +++ b/boards/arm/pinnacle_100_dvk/pinnacle_100_dvk.dts @@ -81,6 +81,7 @@ mcuboot-button0 = &button1; mcuboot-led0 = &led1; watchdog0 = &wdt0; + spi-flash0 = &mx25r64; }; }; diff --git a/boards/arm/ubx_bmd340eval_nrf52840/ubx_bmd340eval_nrf52840.dts b/boards/arm/ubx_bmd340eval_nrf52840/ubx_bmd340eval_nrf52840.dts index 070730c69d2..d06986a8afa 100644 --- a/boards/arm/ubx_bmd340eval_nrf52840/ubx_bmd340eval_nrf52840.dts +++ b/boards/arm/ubx_bmd340eval_nrf52840/ubx_bmd340eval_nrf52840.dts @@ -129,6 +129,7 @@ sw2 = &button2; sw3 = &button3; watchdog0 = &wdt0; + spi-flash0 = &mx25r64; }; }; diff --git a/boards/arm/ubx_bmd345eval_nrf52840/ubx_bmd345eval_nrf52840.dts b/boards/arm/ubx_bmd345eval_nrf52840/ubx_bmd345eval_nrf52840.dts index 68b3755123b..ef145eabe54 100644 --- a/boards/arm/ubx_bmd345eval_nrf52840/ubx_bmd345eval_nrf52840.dts +++ b/boards/arm/ubx_bmd345eval_nrf52840/ubx_bmd345eval_nrf52840.dts @@ -141,6 +141,7 @@ mcuboot-button0 = &button0; mcuboot-led0 = &led0; watchdog0 = &wdt0; + spi-flash0 = &mx25r64; }; }; diff --git a/boards/arm/ubx_bmd380eval_nrf52840/ubx_bmd380eval_nrf52840.dts b/boards/arm/ubx_bmd380eval_nrf52840/ubx_bmd380eval_nrf52840.dts index d7a21c98b44..404678ad952 100644 --- a/boards/arm/ubx_bmd380eval_nrf52840/ubx_bmd380eval_nrf52840.dts +++ b/boards/arm/ubx_bmd380eval_nrf52840/ubx_bmd380eval_nrf52840.dts @@ -90,6 +90,7 @@ sw2 = &button2; sw3 = &button3; watchdog0 = &wdt0; + spi-flash0 = &mx25r64; }; }; From 8fdb8004dd0a81a171637c72d3d9fa880a88548b Mon Sep 17 00:00:00 2001 From: Adam Wojasinski Date: Thu, 7 Dec 2023 13:17:07 +0100 Subject: [PATCH 0950/3723] samples: drivers: spi_flash: Add nordic,qspi-nor to test filter When commit 5b4f4253c1962b85720f0c4d9833b80db5548a08 introduced "nordic,qspi-nor" dts binding the sample wasn't aligned to the change. From that moment the sample started to be filtered out by the Twister. The patch adds Nordic's compatible to the test filter. Signed-off-by: Adam Wojasinski --- samples/drivers/spi_flash/sample.yaml | 1 + 1 file changed, 1 insertion(+) diff --git a/samples/drivers/spi_flash/sample.yaml b/samples/drivers/spi_flash/sample.yaml index e24f9a00525..b3bec006e9c 100644 --- a/samples/drivers/spi_flash/sample.yaml +++ b/samples/drivers/spi_flash/sample.yaml @@ -7,6 +7,7 @@ tests: - flash filter: dt_compat_enabled("jedec,spi-nor") or dt_compat_enabled("st,stm32-qspi-nor") or dt_compat_enabled("st,stm32-ospi-nor") + or (dt_compat_enabled("nordic,qspi-nor") and CONFIG_NORDIC_QSPI_NOR) platform_exclude: hifive_unmatched harness: console harness_config: From 7b78393b07a61cc5491ba0b8fc4e45b6b1414a18 Mon Sep 17 00:00:00 2001 From: Adam Wojasinski Date: Fri, 8 Dec 2023 12:35:54 +0100 Subject: [PATCH 0951/3723] samples: drivers: spi_flash: Extend requirements description The patch updates README with detailed description of the requirements regarding target devicetree needed to correctly build the sample. Signed-off-by: Adam Wojasinski --- samples/drivers/spi_flash/README.rst | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/samples/drivers/spi_flash/README.rst b/samples/drivers/spi_flash/README.rst index 70b523a58a4..6f2e81959be 100644 --- a/samples/drivers/spi_flash/README.rst +++ b/samples/drivers/spi_flash/README.rst @@ -15,8 +15,13 @@ savings is correctly implemented. Building and Running ******************** -The application will build only for a target that has a :ref:`devicetree -` entry with ``jedec,spi-nor`` as a compatible. +The application will build only for a target that has a :ref:`devicetree ` +``spi-flash0`` alias that refers to an entry with one of the following bindings as a compatible: + +* :dtcompatible:`jedec,spi-nor`, +* :dtcompatible:`st,stm32-qspi-nor`, +* :dtcompatible:`st,stm32-ospi-nor`, +* :dtcompatible:`nordic,qspi-nor`. .. zephyr-app-commands:: :zephyr-app: samples/drivers/spi_flash From bf7d7d62146e0ba1c339e7f7e30e2359584e46d7 Mon Sep 17 00:00:00 2001 From: Anas Nashif Date: Fri, 8 Dec 2023 07:37:39 -0500 Subject: [PATCH 0952/3723] modules/hal_ethos_u: do not expose module kconfigs if not enabled Do not expose module Kconfigs if not enabled or used. Signed-off-by: Anas Nashif --- modules/hal_ethos_u/Kconfig | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/modules/hal_ethos_u/Kconfig b/modules/hal_ethos_u/Kconfig index bfed9b94d82..ddb2d0a8ed6 100644 --- a/modules/hal_ethos_u/Kconfig +++ b/modules/hal_ethos_u/Kconfig @@ -9,10 +9,10 @@ config ARM_ETHOS_U help This option enables the Arm Ethos-U core driver. +if ARM_ETHOS_U menu "Arm Ethos-U NPU configuration" choice ARM_ETHOS_U_NPU_CONFIG prompt "Arm Ethos-U NPU configuration" - depends on ARM_ETHOS_U default ARM_ETHOS_U55_128 config ARM_ETHOS_U55_64 bool "using Ethos-U55 with 64 macs" @@ -69,3 +69,5 @@ config ARM_ETHOS_U_LOG_LEVEL default 2 if ARM_ETHOS_U_LOG_LEVEL_WRN default 3 if ARM_ETHOS_U_LOG_LEVEL_INF default 4 if ARM_ETHOS_U_LOG_LEVEL_DBG + +endif From 052590b0c180c5340c6dedb12374d388b0bf7df9 Mon Sep 17 00:00:00 2001 From: Flavio Ceolin Date: Mon, 20 Nov 2023 22:50:12 -0800 Subject: [PATCH 0953/3723] doc: vuln: Disclose information about CVE-2023-4424 Information about CVE-2023-4424 Signed-off-by: Flavio Ceolin --- doc/security/vulnerabilities.rst | 20 +++++++++++++++++++- 1 file changed, 19 insertions(+), 1 deletion(-) diff --git a/doc/security/vulnerabilities.rst b/doc/security/vulnerabilities.rst index d8e4a2a56ca..2ee308c6450 100644 --- a/doc/security/vulnerabilities.rst +++ b/doc/security/vulnerabilities.rst @@ -1501,7 +1501,25 @@ This has been fixed in main for v3.4.0 CVE-2023-4424 ------------- -Under embargo until 2023/11/01 +bt: hci: DoS and possible RCE + +- `Zephyr project bug tracker GHSA-j4qm-xgpf-qjw3 + `_ + +This has been fixed in main for v3.5.0 + +- `PR 61651 fix for main + `_ + +- `PR 61696 fix for 3.4 + `_ + +- `PR 61695 fix for 3.3 + `_ + +- `PR 61694 fix for 2.7 + `_ + CVE-2023-5055 ------------- From 399eb55381c2670438cb1371de59cb284f8c88e8 Mon Sep 17 00:00:00 2001 From: Henrik Brix Andersen Date: Thu, 30 Nov 2023 13:00:20 +0100 Subject: [PATCH 0954/3723] drivers: can: native_posix_linux: remove unused functions Remove the functions linux_socketcan_setsockopt() and linux_socketcan_getsockopt() as they are unused. Signed-off-by: Henrik Brix Andersen --- drivers/can/can_native_posix_linux_socketcan.c | 12 ------------ drivers/can/can_native_posix_linux_socketcan.h | 6 ------ 2 files changed, 18 deletions(-) diff --git a/drivers/can/can_native_posix_linux_socketcan.c b/drivers/can/can_native_posix_linux_socketcan.c index 56295a8f843..4adaf6f5f99 100644 --- a/drivers/can/can_native_posix_linux_socketcan.c +++ b/drivers/can/can_native_posix_linux_socketcan.c @@ -149,18 +149,6 @@ ssize_t linux_socketcan_write_data(int fd, void *buf, size_t buf_len) return write(fd, buf, buf_len); } -int linux_socketcan_setsockopt(int fd, int level, int optname, - const void *optval, socklen_t optlen) -{ - return setsockopt(fd, level, optname, optval, optlen); -} - -int linux_socketcan_getsockopt(int fd, int level, int optname, - void *optval, socklen_t *optlen) -{ - return getsockopt(fd, level, optname, optval, optlen); -} - int linux_socketcan_set_mode_fd(int fd, bool mode_fd) { int opt = mode_fd ? 1 : 0; diff --git a/drivers/can/can_native_posix_linux_socketcan.h b/drivers/can/can_native_posix_linux_socketcan.h index 76db602af98..5156e0a0b0a 100644 --- a/drivers/can/can_native_posix_linux_socketcan.h +++ b/drivers/can/can_native_posix_linux_socketcan.h @@ -21,12 +21,6 @@ ssize_t linux_socketcan_read_data(int fd, void *buf, size_t buf_len, bool *msg_c ssize_t linux_socketcan_write_data(int fd, void *buf, size_t buf_len); -int linux_socketcan_setsockopt(int fd, int level, int optname, const void *optval, - socklen_t optlen); - -int linux_socketcan_getsockopt(int fd, int level, int optname, void *optval, - socklen_t *optlen); - int linux_socketcan_set_mode_fd(int fd, bool mode_fd); #endif /* ZEPHYR_DRIVERS_CAN_NATIVE_POSIX_LINUX_SOCKETCAN_H_ */ From c86f5c0f611992e94927965c91ba90370b442668 Mon Sep 17 00:00:00 2001 From: Henrik Brix Andersen Date: Thu, 30 Nov 2023 10:25:26 +0100 Subject: [PATCH 0955/3723] drivers: can: native_posix_linux: add embedded libc support Add support for compiling the native POSIX Linux (SocketCAN) driver with an embedded C-library. Signed-off-by: Henrik Brix Andersen --- boards/posix/native_sim/doc/index.rst | 2 +- drivers/can/CMakeLists.txt | 32 ++++++++++--------- drivers/can/Kconfig.native_posix_linux | 1 + .../can/can_native_posix_linux_socketcan.c | 1 + 4 files changed, 20 insertions(+), 16 deletions(-) diff --git a/boards/posix/native_sim/doc/index.rst b/boards/posix/native_sim/doc/index.rst index 9d9206e2203..b88f5283dc3 100644 --- a/boards/posix/native_sim/doc/index.rst +++ b/boards/posix/native_sim/doc/index.rst @@ -615,7 +615,7 @@ host libC (:kconfig:option:`CONFIG_EXTERNAL_LIBC`): adc, ADC emul, :kconfig:option:`CONFIG_ADC_EMUL`, all bluetooth, userchan, :kconfig:option:`CONFIG_BT_USERCHAN`, host libC - can, can native posix, :kconfig:option:`CONFIG_CAN_NATIVE_POSIX_LINUX`, host libC + can, can native posix, :kconfig:option:`CONFIG_CAN_NATIVE_POSIX_LINUX`, all console backend, POSIX arch console, :kconfig:option:`CONFIG_POSIX_ARCH_CONSOLE`, all display, display SDL, :kconfig:option:`CONFIG_SDL_DISPLAY`, all entropy, native posix entropy, :kconfig:option:`CONFIG_FAKE_ENTROPY_NATIVE_POSIX`, all diff --git a/drivers/can/CMakeLists.txt b/drivers/can/CMakeLists.txt index c7d9de93f2e..18e3ba67ac8 100644 --- a/drivers/can/CMakeLists.txt +++ b/drivers/can/CMakeLists.txt @@ -20,28 +20,30 @@ zephyr_library_sources_ifdef(CONFIG_CAN_STM32H7_FDCAN can_stm32h7_fdcan.c) zephyr_library_sources_ifdef(CONFIG_CAN_TCAN4X5X can_tcan4x5x.c) zephyr_library_sources_ifdef(CONFIG_CAN_RCAR can_rcar.c) zephyr_library_sources_ifdef(CONFIG_CAN_NUMAKER can_numaker.c) +zephyr_library_sources_ifdef(CONFIG_CAN_SJA1000 can_sja1000.c) +zephyr_library_sources_ifdef(CONFIG_CAN_ESP32_TWAI can_esp32_twai.c) +zephyr_library_sources_ifdef(CONFIG_CAN_KVASER_PCI can_kvaser_pci.c) + +zephyr_library_sources_ifdef(CONFIG_USERSPACE can_handlers.c) +zephyr_library_sources_ifdef(CONFIG_CAN_SHELL can_shell.c) +zephyr_library_sources_ifdef(CONFIG_CAN_NXP_S32_CANXL can_nxp_s32_canxl.c) if(CONFIG_CAN_NATIVE_POSIX_LINUX) if(${CMAKE_HOST_SYSTEM_NAME} STREQUAL Linux) zephyr_library_include_directories(${ZEPHYR_BASE}/subsys/net/l2) - zephyr_library_compile_definitions(NO_POSIX_CHEATS) - zephyr_library_compile_definitions(_BSD_SOURCE) - zephyr_library_compile_definitions(_DEFAULT_SOURCE) - zephyr_library_sources( - can_native_posix_linux.c - can_native_posix_linux_socketcan.c - ) + zephyr_library_sources(can_native_posix_linux.c) + + if (CONFIG_NATIVE_APPLICATION) + set_source_files_properties(can_native_posix_linux_socketcan.c + PROPERTIES COMPILE_DEFINITIONS + "NO_POSIX_CHEATS;_BSD_SOURCE;_DEFAULT_SOURCE") + zephyr_library_sources(can_native_posix_linux_socketcan.c) + else() + target_sources(native_simulator INTERFACE can_native_posix_linux_socketcan.c) + endif() else() message(FATAL_ERROR "CONFIG_CAN_NATIVE_POSIX_LINUX only available on Linux") endif() endif() -zephyr_library_sources_ifdef(CONFIG_CAN_SJA1000 can_sja1000.c) -zephyr_library_sources_ifdef(CONFIG_CAN_ESP32_TWAI can_esp32_twai.c) -zephyr_library_sources_ifdef(CONFIG_CAN_KVASER_PCI can_kvaser_pci.c) - -zephyr_library_sources_ifdef(CONFIG_USERSPACE can_handlers.c) -zephyr_library_sources_ifdef(CONFIG_CAN_SHELL can_shell.c) -zephyr_library_sources_ifdef(CONFIG_CAN_NXP_S32_CANXL can_nxp_s32_canxl.c) - add_subdirectory(transceiver) diff --git a/drivers/can/Kconfig.native_posix_linux b/drivers/can/Kconfig.native_posix_linux index c6719e1de49..f11006ec6da 100644 --- a/drivers/can/Kconfig.native_posix_linux +++ b/drivers/can/Kconfig.native_posix_linux @@ -7,6 +7,7 @@ config CAN_NATIVE_POSIX_LINUX bool "Native Linux SocketCAN Driver" default y depends on DT_HAS_ZEPHYR_NATIVE_POSIX_LINUX_CAN_ENABLED + depends on ARCH_POSIX help Enable native Linux SocketCAN Driver diff --git a/drivers/can/can_native_posix_linux_socketcan.c b/drivers/can/can_native_posix_linux_socketcan.c index 4adaf6f5f99..63b955e76e3 100644 --- a/drivers/can/can_native_posix_linux_socketcan.c +++ b/drivers/can/can_native_posix_linux_socketcan.c @@ -27,6 +27,7 @@ #include #include #include +#include #include #include #else From 0bf4efc78080ceefaad7becf0d01c8d7fb2a8119 Mon Sep 17 00:00:00 2001 From: Henrik Brix Andersen Date: Thu, 30 Nov 2023 10:28:12 +0100 Subject: [PATCH 0956/3723] tests: drivers: build_all: can: add build test for native posix linux Add build-only test for the native POSIX Linux (SocketCAN) driver. Signed-off-by: Henrik Brix Andersen --- .../build_all/can/boards/native_posix.overlay | 7 +++++++ .../build_all/can/boards/native_posix_64.overlay | 7 +++++++ .../drivers/build_all/can/boards/native_sim.overlay | 13 +++++++++++++ .../build_all/can/boards/native_sim_64.overlay | 7 +++++++ tests/drivers/build_all/can/testcase.yaml | 6 ++++++ 5 files changed, 40 insertions(+) create mode 100644 tests/drivers/build_all/can/boards/native_posix.overlay create mode 100644 tests/drivers/build_all/can/boards/native_posix_64.overlay create mode 100644 tests/drivers/build_all/can/boards/native_sim.overlay create mode 100644 tests/drivers/build_all/can/boards/native_sim_64.overlay diff --git a/tests/drivers/build_all/can/boards/native_posix.overlay b/tests/drivers/build_all/can/boards/native_posix.overlay new file mode 100644 index 00000000000..84e4247ccc8 --- /dev/null +++ b/tests/drivers/build_all/can/boards/native_posix.overlay @@ -0,0 +1,7 @@ +/* + * Copyright (c) 2023 Vestas Wind Systems A/S + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include "native_sim.overlay" diff --git a/tests/drivers/build_all/can/boards/native_posix_64.overlay b/tests/drivers/build_all/can/boards/native_posix_64.overlay new file mode 100644 index 00000000000..6c218eaa9cc --- /dev/null +++ b/tests/drivers/build_all/can/boards/native_posix_64.overlay @@ -0,0 +1,7 @@ +/* + * Copyright (c) 2023 Vestas Wind Systems A/S + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include "native_posix.overlay" diff --git a/tests/drivers/build_all/can/boards/native_sim.overlay b/tests/drivers/build_all/can/boards/native_sim.overlay new file mode 100644 index 00000000000..607cd8bed72 --- /dev/null +++ b/tests/drivers/build_all/can/boards/native_sim.overlay @@ -0,0 +1,13 @@ +/* + * Copyright (c) 2023 Vestas Wind Systems A/S + * + * SPDX-License-Identifier: Apache-2.0 + */ + +&can_loopback0 { + status = "disabled"; +}; + +&can0 { + status = "okay"; +}; diff --git a/tests/drivers/build_all/can/boards/native_sim_64.overlay b/tests/drivers/build_all/can/boards/native_sim_64.overlay new file mode 100644 index 00000000000..84e4247ccc8 --- /dev/null +++ b/tests/drivers/build_all/can/boards/native_sim_64.overlay @@ -0,0 +1,7 @@ +/* + * Copyright (c) 2023 Vestas Wind Systems A/S + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include "native_sim.overlay" diff --git a/tests/drivers/build_all/can/testcase.yaml b/tests/drivers/build_all/can/testcase.yaml index c276b24c652..6cce877620e 100644 --- a/tests/drivers/build_all/can/testcase.yaml +++ b/tests/drivers/build_all/can/testcase.yaml @@ -19,3 +19,9 @@ tests: drivers.can.build_all.mcp251xfd: extra_args: SHIELD=mikroe_mcp2518fd_click platform_allow: lpcxpresso55s28 + drivers.can.build_all.native_posix_linux: + platform_allow: + - native_posix + - native_posix_64 + - native_sim + - native_sim_64 From 3533178713b93d5090db12cc956680b997ce618b Mon Sep 17 00:00:00 2001 From: Cong Nguyen Huu Date: Thu, 16 Nov 2023 09:58:27 +0700 Subject: [PATCH 0957/3723] drivers: eth_nxp_s32_netc: use instance-based DT macros At present, many of the NXP S32 shim drivers do not make use of devicetree instance-based macros because the NXP S32 HAL relies on an index-based approach, requiring knowledge of the peripheral instance index during both compilation and runtime, and this index might not align with the devicetree instance index. The proposed solution in this patch eliminates this limitation by determining the peripheral instance index during compilation through macrobatics and defining the handler of SI Rx event within the shim driver itself. Signed-off-by: Cong Nguyen Huu --- drivers/ethernet/eth_nxp_s32_netc_priv.h | 16 +- drivers/ethernet/eth_nxp_s32_netc_psi.c | 358 ++++++++++++----------- drivers/ethernet/eth_nxp_s32_netc_vsi.c | 54 ++-- west.yml | 2 +- 4 files changed, 215 insertions(+), 215 deletions(-) diff --git a/drivers/ethernet/eth_nxp_s32_netc_priv.h b/drivers/ethernet/eth_nxp_s32_netc_priv.h index c4948af3d53..4a3496ee58b 100644 --- a/drivers/ethernet/eth_nxp_s32_netc_priv.h +++ b/drivers/ethernet/eth_nxp_s32_netc_priv.h @@ -1,5 +1,5 @@ /* - * Copyright 2022 NXP + * Copyright 2022-2023 NXP * * SPDX-License-Identifier: Apache-2.0 */ @@ -78,16 +78,23 @@ mac_addr[5] = (id + n) & 0xff; \ } while (0) -#define NETC_GENERATE_MAC_ADDRESS(node, n) \ +#define NETC_GENERATE_MAC_ADDRESS(n) \ static void nxp_s32_eth##n##_generate_mac(uint8_t mac_addr[6]) \ { \ - COND_CODE_1(DT_PROP(node, zephyr_random_mac_address), \ + COND_CODE_1(DT_INST_PROP(n, zephyr_random_mac_address), \ (_NETC_GENERATE_MAC_ADDRESS_RANDOM), \ - (COND_CODE_0(DT_NODE_HAS_PROP(node, local_mac_address), \ + (COND_CODE_0(DT_INST_NODE_HAS_PROP(n, local_mac_address),\ (_NETC_GENERATE_MAC_ADDRESS_UNIQUE(n)), \ (ARG_UNUSED(mac_addr))))); \ } +#define NETC_SI_NXP_S32_HW_INSTANCE_CHECK(i, n) \ + ((DT_INST_REG_ADDR(n) == IP_NETC__ENETC0_SI##i##_BASE) ? i : 0) + +#define NETC_SI_NXP_S32_HW_INSTANCE(n) \ + LISTIFY(__DEBRACKET FEATURE_NETC_ETH_NUMBER_OF_CTRLS, \ + NETC_SI_NXP_S32_HW_INSTANCE_CHECK, (|), n) + /* Helper macros to concatenate tokens that require further expansions */ #define _CONCAT3(a, b, c) DT_CAT3(a, b, c) @@ -127,5 +134,6 @@ enum ethernet_hw_caps nxp_s32_eth_get_capabilities(const struct device *dev); void nxp_s32_eth_mcast_cb(struct net_if *iface, const struct net_addr *addr, bool is_joined); int nxp_s32_eth_set_config(const struct device *dev, enum ethernet_config_type type, const struct ethernet_config *config); +extern void Netc_Eth_Ip_MSIX_Rx(uint8_t si_idx); #endif /* ZEPHYR_DRIVERS_ETHERNET_ETH_NXP_S32_NETC_PRIV_H_ */ diff --git a/drivers/ethernet/eth_nxp_s32_netc_psi.c b/drivers/ethernet/eth_nxp_s32_netc_psi.c index 8a3242be911..623ca943c6e 100644 --- a/drivers/ethernet/eth_nxp_s32_netc_psi.c +++ b/drivers/ethernet/eth_nxp_s32_netc_psi.c @@ -1,9 +1,11 @@ /* - * Copyright 2022 NXP + * Copyright 2022-2023 NXP * * SPDX-License-Identifier: Apache-2.0 */ +#define DT_DRV_COMPAT nxp_s32_netc_psi + #define LOG_LEVEL CONFIG_ETHERNET_LOG_LEVEL #include LOG_MODULE_REGISTER(nxp_s32_eth_psi); @@ -26,9 +28,6 @@ LOG_MODULE_REGISTER(nxp_s32_eth_psi); #include "eth.h" #include "eth_nxp_s32_netc_priv.h" -#define PSI_NODE DT_COMPAT_GET_ANY_STATUS_OKAY(nxp_s32_netc_psi) -#define PHY_NODE DT_PHANDLE(PSI_NODE, phy_handle) -#define INIT_VSIS DT_NODE_HAS_PROP(PSI_NODE, vsis) #define TX_RING_IDX 1 #define RX_RING_IDX 0 @@ -206,19 +205,6 @@ static void nxp_s32_eth_iface_init(struct net_if *iface) } } -static void nxp_s32_eth0_rx_callback(const uint8_t unused, const uint8_t ring) -{ - const struct device *dev = DEVICE_DT_GET(PSI_NODE); - const struct nxp_s32_eth_config *cfg = dev->config; - struct nxp_s32_eth_data *ctx = dev->data; - - ARG_UNUSED(unused); - - if (ring == cfg->rx_ring_idx) { - k_sem_give(&ctx->rx_sem); - } -} - static const struct ethernet_api nxp_s32_eth_api = { .iface_api.init = nxp_s32_eth_iface_init, .get_capabilities = nxp_s32_eth_get_capabilities, @@ -238,22 +224,22 @@ BUILD_ASSERT(DT_NUM_INST_STATUS_OKAY(nxp_s32_netc_psi) == 1, "Only one PSI enabl | NETC_F3_PSICFGR0_SIVC_SVLAN_BIT), \ } -#define NETC_VSI_RX_MSG_BUF(node, prop, idx) \ +#define NETC_VSI_RX_MSG_BUF(node, prop, idx, n) \ BUILD_ASSERT((DT_PROP_BY_IDX(node, prop, idx) > NETC_ETH_IP_PSI_INDEX) \ && (DT_PROP_BY_IDX(node, prop, idx) <= FEATURE_NETC_ETH_NUM_OF_VIRTUAL_CTRLS), \ "Invalid VSI index"); \ static Netc_Eth_Ip_VsiToPsiMsgType \ - _CONCAT3(nxp_s32_eth0_vsi, DT_PROP_BY_IDX(node, prop, idx), _rx_msg_buf) \ + _CONCAT3(nxp_s32_eth##n##_vsi, DT_PROP_BY_IDX(node, prop, idx), _rx_msg_buf) \ __aligned(FEATURE_NETC_ETH_VSI_MSG_ALIGNMENT) -#define NETC_VSI_RX_MSG_BUF_ARRAY(node, prop, idx) \ +#define NETC_VSI_RX_MSG_BUF_ARRAY(node, prop, idx, n) \ [DT_PROP_BY_IDX(node, prop, idx) - 1] = \ - &_CONCAT3(nxp_s32_eth0_vsi, DT_PROP_BY_IDX(node, prop, idx), _rx_msg_buf) + &_CONCAT3(nxp_s32_eth##n##_vsi, DT_PROP_BY_IDX(node, prop, idx), _rx_msg_buf) -#define NETC_SWITCH_PORT_CFG(_, __) \ +#define NETC_SWITCH_PORT_CFG(_, n) \ { \ - .ePort = &nxp_s32_eth0_switch_port_egress_cfg, \ - .iPort = &nxp_s32_eth0_switch_port_ingress_cfg, \ + .ePort = &nxp_s32_eth##n##_switch_port_egress_cfg, \ + .iPort = &nxp_s32_eth##n##_switch_port_ingress_cfg, \ .EthSwtPortMacLayerPortEnable = true, \ .EthSwtPortMacLayerSpeed = ETHTRCV_BAUD_RATE_1000MBIT, \ .EthSwtPortMacLayerDuplexMode = NETC_ETHSWT_PORT_FULL_DUPLEX, \ @@ -261,155 +247,181 @@ BUILD_ASSERT(DT_NUM_INST_STATUS_OKAY(nxp_s32_netc_psi) == 1, "Only one PSI enabl .EthSwtPortPruningEnable = true, \ } -static Netc_Eth_Ip_StateType nxp_s32_eth0_state; - -static Netc_Eth_Ip_MACFilterHashTableEntryType -nxp_s32_eth0_mac_filter_hash_table[CONFIG_ETH_NXP_S32_MAC_FILTER_TABLE_SIZE]; - -NETC_TX_RING(0, 0, NETC_MIN_RING_LEN, NETC_MIN_RING_BUF_SIZE); -NETC_TX_RING(0, TX_RING_IDX, - CONFIG_ETH_NXP_S32_TX_RING_LEN, CONFIG_ETH_NXP_S32_TX_RING_BUF_SIZE); -NETC_RX_RING(0, RX_RING_IDX, - CONFIG_ETH_NXP_S32_RX_RING_LEN, CONFIG_ETH_NXP_S32_RX_RING_BUF_SIZE); - -static const Netc_Eth_Ip_RxRingConfigType nxp_s32_eth0_rxring_cfg[1] = { - { - .RingDesc = nxp_s32_eth0_rxring0_desc, - .Buffer = nxp_s32_eth0_rxring0_buf, - .ringSize = CONFIG_ETH_NXP_S32_RX_RING_LEN, - .maxRingSize = CONFIG_ETH_NXP_S32_RX_RING_LEN, - .bufferLen = CONFIG_ETH_NXP_S32_TX_RING_BUF_SIZE, - .maxBuffLen = CONFIG_ETH_NXP_S32_TX_RING_BUF_SIZE, - .TimerThreshold = CONFIG_ETH_NXP_S32_RX_IRQ_TIMER_THRESHOLD, - .PacketsThreshold = CONFIG_ETH_NXP_S32_RX_IRQ_PACKET_THRESHOLD, - .Callback = nxp_s32_eth0_rx_callback, - } -}; - -static const Netc_Eth_Ip_TxRingConfigType nxp_s32_eth0_txring_cfg[2] = { - { - .RingDesc = nxp_s32_eth0_txring0_desc, - .Buffer = nxp_s32_eth0_txring0_buf, - .ringSize = NETC_MIN_RING_LEN, - .maxRingSize = NETC_MIN_RING_LEN, - .bufferLen = NETC_MIN_RING_BUF_SIZE, - .maxBuffLen = NETC_MIN_RING_BUF_SIZE, - }, - { - .RingDesc = nxp_s32_eth0_txring1_desc, - .Buffer = nxp_s32_eth0_txring1_buf, - .ringSize = CONFIG_ETH_NXP_S32_TX_RING_LEN, - .maxRingSize = CONFIG_ETH_NXP_S32_TX_RING_LEN, - .bufferLen = CONFIG_ETH_NXP_S32_TX_RING_BUF_SIZE, - .maxBuffLen = CONFIG_ETH_NXP_S32_TX_RING_BUF_SIZE, - } -}; - -static const Netc_Eth_Ip_GeneralSIConfigType -nxp_s32_eth0_psi_cfg[FEATURE_NETC_ETH_NUMBER_OF_CTRLS] = { - [NETC_ETH_IP_PSI_INDEX] = { - .siId = NETC_ETH_IP_PSI_INDEX, - .enableSi = true, - .NumberOfRxBDR = 1, - .NumberOfTxBDR = 2, - .SIVlanControl = (NETC_F3_PSICFGR0_SIVC_CVLAN_BIT - | NETC_F3_PSICFGR0_SIVC_SVLAN_BIT), - }, - COND_CODE_1(INIT_VSIS, - (DT_FOREACH_PROP_ELEM_SEP(PSI_NODE, vsis, NETC_VSI_GENERAL_CFG, (,))), - (EMPTY)) -}; - -COND_CODE_1(INIT_VSIS, - (DT_FOREACH_PROP_ELEM_SEP(PSI_NODE, vsis, NETC_VSI_RX_MSG_BUF, (;))), - (EMPTY)); - -static const Netc_Eth_Ip_EnetcGeneralConfigType nxp_s32_eth0_enetc_general_cfg = { - .numberOfConfiguredSis = FEATURE_NETC_ETH_NUMBER_OF_CTRLS, - .stationInterfaceGeneralConfig = &nxp_s32_eth0_psi_cfg, -#if defined(CONFIG_NET_PROMISCUOUS_MODE) - .maskMACPromiscuousMulticastEnable = (uint16_t)true, - .maskMACPromiscuousUnicastEnable = (uint16_t)true, -#endif - .RxVsiMsgCmdToPsi = { - COND_CODE_1(INIT_VSIS, - (DT_FOREACH_PROP_ELEM_SEP(PSI_NODE, vsis, - NETC_VSI_RX_MSG_BUF_ARRAY, (,))), - (EMPTY)) - }, -}; - -static const Netc_Eth_Ip_StationInterfaceConfigType nxp_s32_eth0_si_cfg = { - .NumberOfRxBDR = 1, - .NumberOfTxBDR = 2, - .txMruMailboxAddr = NULL, - .rxMruMailboxAddr = (uint32_t *)MRU_MBOX_ADDR(PSI_NODE, rx), - .siMsgMruMailboxAddr = COND_CODE_1(INIT_VSIS, - ((uint32_t *)MRU_MBOX_ADDR(PSI_NODE, vsi_msg)), (NULL)), - .RxInterrupts = (uint32_t)true, - .TxInterrupts = (uint32_t)false, - .MACFilterTableMaxNumOfEntries = CONFIG_ETH_NXP_S32_MAC_FILTER_TABLE_SIZE, -}; - -static uint8_t nxp_s32_eth0_switch_vlandr2dei_cfg[NETC_ETHSWT_NUMBER_OF_DR]; -static Netc_EthSwt_Ip_PortIngressType nxp_s32_eth0_switch_port_ingress_cfg; -static Netc_EthSwt_Ip_PortEgressType nxp_s32_eth0_switch_port_egress_cfg = { - .vlanDrToDei = &nxp_s32_eth0_switch_vlandr2dei_cfg, -}; -static Netc_EthSwt_Ip_PortType nxp_s32_eth0_switch_ports_cfg[NETC_ETHSWT_NUMBER_OF_PORTS] = { - LISTIFY(NETC_ETHSWT_NUMBER_OF_PORTS, NETC_SWITCH_PORT_CFG, (,)) -}; - -static const Netc_EthSwt_Ip_ConfigType nxp_s32_eth0_switch_cfg = { - .port = &nxp_s32_eth0_switch_ports_cfg, - .EthSwtArlTableEntryTimeout = NETC_SWITCH_PORT_AGING, - .netcClockFrequency = DT_PROP(PSI_NODE, clock_frequency), - .MacLearningOption = ETHSWT_MACLEARNINGOPTION_HWDISABLED, - .MacForwardingOption = ETHSWT_NO_FDB_LOOKUP_FLOOD_FRAME, - .Timer1588ClkSrc = ETHSWT_REFERENCE_CLOCK_DISABLED, -}; - -PINCTRL_DT_DEFINE(PSI_NODE); - -NETC_GENERATE_MAC_ADDRESS(PSI_NODE, 0) - -static const struct nxp_s32_eth_config nxp_s32_eth0_config = { - .netc_cfg = { - .SiType = NETC_ETH_IP_PHYSICAL_SI, - .siConfig = &nxp_s32_eth0_si_cfg, - .generalConfig = &nxp_s32_eth0_enetc_general_cfg, - .stateStructure = &nxp_s32_eth0_state, - .paCtrlRxRingConfig = &nxp_s32_eth0_rxring_cfg, - .paCtrlTxRingConfig = &nxp_s32_eth0_txring_cfg, - }, - .si_idx = NETC_ETH_IP_PSI_INDEX, - .port_idx = NETC_SWITCH_PORT_IDX, - .tx_ring_idx = TX_RING_IDX, - .rx_ring_idx = RX_RING_IDX, - .msix = { - NETC_MSIX(PSI_NODE, rx, Netc_Eth_Ip_0_MSIX_RxEvent), - COND_CODE_1(INIT_VSIS, - (NETC_MSIX(PSI_NODE, vsi_msg, Netc_Eth_Ip_MSIX_SIMsgEvent)), - (EMPTY)) - }, - .mac_filter_hash_table = &nxp_s32_eth0_mac_filter_hash_table[0], - .generate_mac = nxp_s32_eth0_generate_mac, - .phy_dev = DEVICE_DT_GET(PHY_NODE), - .pincfg = PINCTRL_DT_DEV_CONFIG_GET(PSI_NODE), -}; - -static struct nxp_s32_eth_data nxp_s32_eth0_data = { - .mac_addr = DT_PROP_OR(PSI_NODE, local_mac_address, {0}), -}; - -ETH_NET_DEVICE_DT_DEFINE(PSI_NODE, - nxp_s32_eth_initialize, - NULL, - &nxp_s32_eth0_data, - &nxp_s32_eth0_config, - CONFIG_ETH_INIT_PRIORITY, - &nxp_s32_eth_api, - NET_ETH_MTU); +#define PHY_NODE(n) DT_INST_PHANDLE(n, phy_handle) +#define INIT_VSIS(n) DT_INST_NODE_HAS_PROP(n, vsis) + +#define NETC_PSI_INSTANCE_DEFINE(n) \ +void nxp_s32_eth_psi##n##_rx_event(uint8_t chan, const uint32_t *buf, uint8_t buf_size) \ +{ \ + ARG_UNUSED(chan); \ + ARG_UNUSED(buf); \ + ARG_UNUSED(buf_size); \ + \ + Netc_Eth_Ip_MSIX_Rx(NETC_SI_NXP_S32_HW_INSTANCE(n)); \ +} \ + \ +static void nxp_s32_eth##n##_rx_callback(const uint8_t unused, const uint8_t ring) \ +{ \ + const struct device *dev = DEVICE_DT_INST_GET(n); \ + const struct nxp_s32_eth_config *cfg = dev->config; \ + struct nxp_s32_eth_data *ctx = dev->data; \ + \ + ARG_UNUSED(unused); \ + \ + if (ring == cfg->rx_ring_idx) { \ + k_sem_give(&ctx->rx_sem); \ + } \ +} \ + \ +static Netc_Eth_Ip_StateType nxp_s32_eth##n##_state; \ +static Netc_Eth_Ip_MACFilterHashTableEntryType \ +nxp_s32_eth##n##_mac_filter_hash_table[CONFIG_ETH_NXP_S32_MAC_FILTER_TABLE_SIZE]; \ + \ +NETC_TX_RING(n, 0, NETC_MIN_RING_LEN, NETC_MIN_RING_BUF_SIZE); \ +NETC_TX_RING(n, TX_RING_IDX, \ + CONFIG_ETH_NXP_S32_TX_RING_LEN, CONFIG_ETH_NXP_S32_TX_RING_BUF_SIZE); \ +NETC_RX_RING(n, RX_RING_IDX, \ + CONFIG_ETH_NXP_S32_RX_RING_LEN, CONFIG_ETH_NXP_S32_RX_RING_BUF_SIZE); \ + \ +static const Netc_Eth_Ip_RxRingConfigType nxp_s32_eth##n##_rxring_cfg[1] = { \ + { \ + .RingDesc = nxp_s32_eth##n##_rxring0_desc, \ + .Buffer = nxp_s32_eth##n##_rxring0_buf, \ + .ringSize = CONFIG_ETH_NXP_S32_RX_RING_LEN, \ + .maxRingSize = CONFIG_ETH_NXP_S32_RX_RING_LEN, \ + .bufferLen = CONFIG_ETH_NXP_S32_TX_RING_BUF_SIZE, \ + .maxBuffLen = CONFIG_ETH_NXP_S32_TX_RING_BUF_SIZE, \ + .TimerThreshold = CONFIG_ETH_NXP_S32_RX_IRQ_TIMER_THRESHOLD, \ + .PacketsThreshold = CONFIG_ETH_NXP_S32_RX_IRQ_PACKET_THRESHOLD, \ + .Callback = nxp_s32_eth##n##_rx_callback, \ + } \ +}; \ + \ +static const Netc_Eth_Ip_TxRingConfigType nxp_s32_eth##n##_txring_cfg[2] = { \ + { \ + .RingDesc = nxp_s32_eth##n##_txring0_desc, \ + .Buffer = nxp_s32_eth##n##_txring0_buf, \ + .ringSize = NETC_MIN_RING_LEN, \ + .maxRingSize = NETC_MIN_RING_LEN, \ + .bufferLen = NETC_MIN_RING_BUF_SIZE, \ + .maxBuffLen = NETC_MIN_RING_BUF_SIZE, \ + }, \ + { \ + .RingDesc = nxp_s32_eth##n##_txring1_desc, \ + .Buffer = nxp_s32_eth##n##_txring1_buf, \ + .ringSize = CONFIG_ETH_NXP_S32_TX_RING_LEN, \ + .maxRingSize = CONFIG_ETH_NXP_S32_TX_RING_LEN, \ + .bufferLen = CONFIG_ETH_NXP_S32_TX_RING_BUF_SIZE, \ + .maxBuffLen = CONFIG_ETH_NXP_S32_TX_RING_BUF_SIZE, \ + } \ +}; \ + \ +static const Netc_Eth_Ip_GeneralSIConfigType \ +nxp_s32_eth##n##_psi_cfg[FEATURE_NETC_ETH_NUMBER_OF_CTRLS] = { \ + [NETC_SI_NXP_S32_HW_INSTANCE(n)] = { \ + .siId = NETC_SI_NXP_S32_HW_INSTANCE(n), \ + .enableSi = true, \ + .NumberOfRxBDR = 1, \ + .NumberOfTxBDR = 2, \ + .SIVlanControl = (NETC_F3_PSICFGR0_SIVC_CVLAN_BIT \ + | NETC_F3_PSICFGR0_SIVC_SVLAN_BIT), \ + }, \ + COND_CODE_1(INIT_VSIS(n), \ + (DT_INST_FOREACH_PROP_ELEM_SEP(n, vsis, NETC_VSI_GENERAL_CFG, (,))), \ + (EMPTY)) \ +}; \ + \ +COND_CODE_1(INIT_VSIS(n), \ + (DT_INST_FOREACH_PROP_ELEM_SEP_VARGS(n, vsis, NETC_VSI_RX_MSG_BUF, (;), n)), \ + (EMPTY)); \ + \ +static const Netc_Eth_Ip_EnetcGeneralConfigType nxp_s32_eth##n##_enetc_general_cfg = { \ + .numberOfConfiguredSis = FEATURE_NETC_ETH_NUMBER_OF_CTRLS, \ + .stationInterfaceGeneralConfig = &nxp_s32_eth##n##_psi_cfg, \ + IF_ENABLED(CONFIG_NET_PROMISCUOUS_MODE, \ + (.maskMACPromiscuousMulticastEnable = (uint16_t)true, \ + .maskMACPromiscuousUnicastEnable = (uint16_t)true,)) \ + .RxVsiMsgCmdToPsi = { \ + COND_CODE_1(INIT_VSIS(n), \ + (DT_INST_FOREACH_PROP_ELEM_SEP_VARGS(n, vsis, \ + NETC_VSI_RX_MSG_BUF_ARRAY, (,), n)), \ + (EMPTY)) \ + }, \ +}; \ + \ +static const Netc_Eth_Ip_StationInterfaceConfigType nxp_s32_eth##n##_si_cfg = { \ + .NumberOfRxBDR = 1, \ + .NumberOfTxBDR = 2, \ + .txMruMailboxAddr = NULL, \ + .rxMruMailboxAddr = (uint32_t *)MRU_MBOX_ADDR(DT_DRV_INST(n), rx), \ + .siMsgMruMailboxAddr = COND_CODE_1(INIT_VSIS(n), \ + ((uint32_t *)MRU_MBOX_ADDR(DT_DRV_INST(n), vsi_msg)), (NULL)), \ + .RxInterrupts = (uint32_t)true, \ + .TxInterrupts = (uint32_t)false, \ + .MACFilterTableMaxNumOfEntries = CONFIG_ETH_NXP_S32_MAC_FILTER_TABLE_SIZE, \ +}; \ + \ +static uint8_t nxp_s32_eth##n##_switch_vlandr2dei_cfg[NETC_ETHSWT_NUMBER_OF_DR]; \ +static Netc_EthSwt_Ip_PortIngressType nxp_s32_eth##n##_switch_port_ingress_cfg; \ +static Netc_EthSwt_Ip_PortEgressType nxp_s32_eth##n##_switch_port_egress_cfg = { \ + .vlanDrToDei = &nxp_s32_eth##n##_switch_vlandr2dei_cfg, \ +}; \ +static Netc_EthSwt_Ip_PortType nxp_s32_eth##n##_switch_ports_cfg[NETC_ETHSWT_NUMBER_OF_PORTS] = {\ + LISTIFY(NETC_ETHSWT_NUMBER_OF_PORTS, NETC_SWITCH_PORT_CFG, (,), n) \ +}; \ + \ +static const Netc_EthSwt_Ip_ConfigType nxp_s32_eth##n##_switch_cfg = { \ + .port = &nxp_s32_eth##n##_switch_ports_cfg, \ + .EthSwtArlTableEntryTimeout = NETC_SWITCH_PORT_AGING, \ + .netcClockFrequency = DT_INST_PROP(n, clock_frequency), \ + .MacLearningOption = ETHSWT_MACLEARNINGOPTION_HWDISABLED, \ + .MacForwardingOption = ETHSWT_NO_FDB_LOOKUP_FLOOD_FRAME, \ + .Timer1588ClkSrc = ETHSWT_REFERENCE_CLOCK_DISABLED, \ +}; \ + \ +PINCTRL_DT_INST_DEFINE(n); \ + \ +NETC_GENERATE_MAC_ADDRESS(n) \ + \ +static const struct nxp_s32_eth_config nxp_s32_eth##n##_config = { \ + .netc_cfg = { \ + .SiType = NETC_ETH_IP_PHYSICAL_SI, \ + .siConfig = &nxp_s32_eth##n##_si_cfg, \ + .generalConfig = &nxp_s32_eth##n##_enetc_general_cfg, \ + .stateStructure = &nxp_s32_eth##n##_state, \ + .paCtrlRxRingConfig = &nxp_s32_eth##n##_rxring_cfg, \ + .paCtrlTxRingConfig = &nxp_s32_eth##n##_txring_cfg, \ + }, \ + .si_idx = NETC_SI_NXP_S32_HW_INSTANCE(n), \ + .port_idx = NETC_SWITCH_PORT_IDX, \ + .tx_ring_idx = TX_RING_IDX, \ + .rx_ring_idx = RX_RING_IDX, \ + .msix = { \ + NETC_MSIX(DT_DRV_INST(n), rx, nxp_s32_eth_psi##n##_rx_event), \ + COND_CODE_1(INIT_VSIS(n), \ + (NETC_MSIX(DT_DRV_INST(n), vsi_msg, Netc_Eth_Ip_MSIX_SIMsgEvent)),\ + (EMPTY)) \ + }, \ + .mac_filter_hash_table = &nxp_s32_eth##n##_mac_filter_hash_table[0], \ + .generate_mac = nxp_s32_eth##n##_generate_mac, \ + .phy_dev = DEVICE_DT_GET(PHY_NODE(n)), \ + .pincfg = PINCTRL_DT_INST_DEV_CONFIG_GET(n), \ +}; \ + \ +static struct nxp_s32_eth_data nxp_s32_eth##n##_data = { \ + .mac_addr = DT_INST_PROP_OR(n, local_mac_address, {0}), \ +}; \ + \ +ETH_NET_DEVICE_DT_INST_DEFINE(n, \ + nxp_s32_eth_initialize, \ + NULL, \ + &nxp_s32_eth##n##_data, \ + &nxp_s32_eth##n##_config, \ + CONFIG_ETH_INIT_PRIORITY, \ + &nxp_s32_eth_api, \ + NET_ETH_MTU); \ + +DT_INST_FOREACH_STATUS_OKAY(NETC_PSI_INSTANCE_DEFINE) static int nxp_s32_eth_switch_init(void) { diff --git a/drivers/ethernet/eth_nxp_s32_netc_vsi.c b/drivers/ethernet/eth_nxp_s32_netc_vsi.c index 1a159529814..0847db8148c 100644 --- a/drivers/ethernet/eth_nxp_s32_netc_vsi.c +++ b/drivers/ethernet/eth_nxp_s32_netc_vsi.c @@ -1,9 +1,11 @@ /* - * Copyright 2022 NXP + * Copyright 2022-2023 NXP * * SPDX-License-Identifier: Apache-2.0 */ +#define DT_DRV_COMPAT nxp_s32_netc_vsi + #define LOG_LEVEL CONFIG_ETHERNET_LOG_LEVEL #include LOG_MODULE_REGISTER(nxp_s32_eth_vsi); @@ -26,7 +28,6 @@ LOG_MODULE_REGISTER(nxp_s32_eth_vsi); #include "eth.h" #include "eth_nxp_s32_netc_priv.h" -#define VSI_NODE(n) DT_NODELABEL(enetc_vsi##n) #define TX_RING_IDX 0 #define RX_RING_IDX 0 @@ -83,11 +84,16 @@ static const struct ethernet_api nxp_s32_eth_api = { BUILD_ASSERT(DT_NUM_INST_STATUS_OKAY(nxp_s32_netc_vsi) == 1, "Only one VSI enabled supported"); #define NETC_VSI_INSTANCE_DEFINE(n) \ - NETC_GENERATE_MAC_ADDRESS(VSI_NODE(n), n) \ + NETC_GENERATE_MAC_ADDRESS(n) \ + \ + void nxp_s32_eth_vsi##n##_rx_event(uint8_t chan, const uint32_t *buf, uint8_t buf_size) \ + { \ + Netc_Eth_Ip_MSIX_Rx(NETC_SI_NXP_S32_HW_INSTANCE(n)); \ + } \ \ static void nxp_s32_eth##n##_rx_callback(const uint8_t unused, const uint8_t ring) \ { \ - const struct device *dev = DEVICE_DT_GET(VSI_NODE(n)); \ + const struct device *dev = DEVICE_DT_INST_GET(n); \ const struct nxp_s32_eth_config *cfg = dev->config; \ struct nxp_s32_eth_data *ctx = dev->data; \ \ @@ -135,7 +141,7 @@ BUILD_ASSERT(DT_NUM_INST_STATUS_OKAY(nxp_s32_netc_vsi) == 1, "Only one VSI enabl .NumberOfRxBDR = 1, \ .NumberOfTxBDR = 1, \ .txMruMailboxAddr = NULL, \ - .rxMruMailboxAddr = (uint32_t *)MRU_MBOX_ADDR(VSI_NODE(n), rx), \ + .rxMruMailboxAddr = (uint32_t *)MRU_MBOX_ADDR(DT_DRV_INST(n), rx), \ .RxInterrupts = (uint32_t)true, \ .TxInterrupts = (uint32_t)false, \ .MACFilterTableMaxNumOfEntries = CONFIG_ETH_NXP_S32_MAC_FILTER_TABLE_SIZE, \ @@ -143,7 +149,7 @@ BUILD_ASSERT(DT_NUM_INST_STATUS_OKAY(nxp_s32_netc_vsi) == 1, "Only one VSI enabl }; \ \ static struct nxp_s32_eth_data nxp_s32_eth##n##_data = { \ - .mac_addr = DT_PROP_OR(VSI_NODE(n), local_mac_address, {0}), \ + .mac_addr = DT_INST_PROP_OR(n, local_mac_address, {0}), \ }; \ \ static const struct nxp_s32_eth_config nxp_s32_eth##n##_cfg = { \ @@ -154,49 +160,23 @@ BUILD_ASSERT(DT_NUM_INST_STATUS_OKAY(nxp_s32_netc_vsi) == 1, "Only one VSI enabl .paCtrlRxRingConfig = &nxp_s32_eth##n##_rxring_cfg, \ .paCtrlTxRingConfig = &nxp_s32_eth##n##_txring_cfg, \ }, \ - .si_idx = n, \ + .si_idx = NETC_SI_NXP_S32_HW_INSTANCE(n), \ .tx_ring_idx = TX_RING_IDX, \ .rx_ring_idx = RX_RING_IDX, \ .msix = { \ - NETC_MSIX(VSI_NODE(n), rx, Netc_Eth_Ip_##n##_MSIX_RxEvent), \ + NETC_MSIX(DT_DRV_INST(n), rx, nxp_s32_eth_vsi##n##_rx_event), \ }, \ .mac_filter_hash_table = &nxp_s32_eth##n##_mac_filter_hash_table[0], \ .generate_mac = nxp_s32_eth##n##_generate_mac, \ }; \ \ - ETH_NET_DEVICE_DT_DEFINE(VSI_NODE(n), \ + ETH_NET_DEVICE_DT_INST_DEFINE(n, \ nxp_s32_eth_initialize_common, \ NULL, \ &nxp_s32_eth##n##_data, \ &nxp_s32_eth##n##_cfg, \ CONFIG_ETH_NXP_S32_VSI_INIT_PRIORITY, \ &nxp_s32_eth_api, \ - NET_ETH_MTU) - -#if DT_NODE_HAS_STATUS(VSI_NODE(1), okay) -NETC_VSI_INSTANCE_DEFINE(1); -#endif - -#if DT_NODE_HAS_STATUS(VSI_NODE(2), okay) -NETC_VSI_INSTANCE_DEFINE(2); -#endif - -#if DT_NODE_HAS_STATUS(VSI_NODE(3), okay) -NETC_VSI_INSTANCE_DEFINE(3); -#endif - -#if DT_NODE_HAS_STATUS(VSI_NODE(4), okay) -NETC_VSI_INSTANCE_DEFINE(4); -#endif - -#if DT_NODE_HAS_STATUS(VSI_NODE(5), okay) -NETC_VSI_INSTANCE_DEFINE(5); -#endif - -#if DT_NODE_HAS_STATUS(VSI_NODE(6), okay) -NETC_VSI_INSTANCE_DEFINE(6); -#endif + NET_ETH_MTU); -#if DT_NODE_HAS_STATUS(VSI_NODE(7), okay) -NETC_VSI_INSTANCE_DEFINE(7); -#endif +DT_INST_FOREACH_STATUS_OKAY(NETC_VSI_INSTANCE_DEFINE) diff --git a/west.yml b/west.yml index 522a451738d..d639b0217bd 100644 --- a/west.yml +++ b/west.yml @@ -193,7 +193,7 @@ manifest: groups: - hal - name: hal_nxp - revision: 1b2f3608ab0d5f2cf2a4c2973ae9f6353fb43e72 + revision: cbf2cd1f099585eeef2cdb0c68d72e9e67e89c24 path: modules/hal/nxp groups: - hal From d175ac0572c454eec99b11f9f6d0350efa5a5f8b Mon Sep 17 00:00:00 2001 From: Aleksandr Khromykh Date: Mon, 20 Nov 2023 16:43:25 +0100 Subject: [PATCH 0958/3723] Bluetooth: Mesh: access tx msg randomizer Commit adds implementation of the specification recommendations regarding randomization of responses on the access layer. 3.7.3.1 Transmitting an Access messages Signed-off-by: Aleksandr Khromykh --- .../bluetooth/api/mesh/access.rst | 33 ++ doc/releases/release-notes-3.6.rst | 5 + include/zephyr/bluetooth/mesh/msg.h | 3 + .../bluetooth/mesh/boards/bbc_microbit.conf | 1 + .../mesh_demo/boards/bbc_microbit.conf | 1 + subsys/bluetooth/mesh/CMakeLists.txt | 2 + subsys/bluetooth/mesh/Kconfig | 35 ++ subsys/bluetooth/mesh/access.c | 29 ++ subsys/bluetooth/mesh/access.h | 17 + subsys/bluetooth/mesh/delayable_msg.c | 314 ++++++++++++++++++ subsys/bluetooth/mesh/delayable_msg.h | 16 + subsys/bluetooth/mesh/main.c | 4 + 12 files changed, 460 insertions(+) create mode 100644 subsys/bluetooth/mesh/delayable_msg.c create mode 100644 subsys/bluetooth/mesh/delayable_msg.h diff --git a/doc/connectivity/bluetooth/api/mesh/access.rst b/doc/connectivity/bluetooth/api/mesh/access.rst index e4a94440556..7030a3c14b2 100644 --- a/doc/connectivity/bluetooth/api/mesh/access.rst +++ b/doc/connectivity/bluetooth/api/mesh/access.rst @@ -222,6 +222,39 @@ They are used to represent the new content of the mirrored pages when the Compos change after a firmware update. See :ref:`bluetooth_mesh_dfu_srv_comp_data_and_models_metadata` for details. +Delayable messages +================== + +The delayable message functionality is enabled with Kconfig option +:kconfig:option:`CONFIG_BT_MESH_ACCESS_DELAYABLE_MSG`. +This is an optional functionality that implements specification recommendations for +messages that are transmitted by a model in a response to a received message, also called +response messages. + +Response messages should be sent with the following random delays: + +* Between 20 and 50 milliseconds if the received message was sent + to a unicast address +* Between 20 and 500 milliseconds if the received message was sent + to a group or virtual address + +The delayable message functionality is triggered if the :c:member:`bt_mesh_msg_ctx.rnd_delay` +flag is set. +The delayable message functionality stores messages in the local memory while they are +waiting for the random delay expiration. + +If the transport layer doesn't have sufficient memory to send a message at the moment +the random delay expires, the message is postponed for another 10 milliseconds. +If the transport layer cannot send a message for any other reason, the delayable message +functionality raises the :c:member:`bt_mesh_send_cb.start` callback with a transport layer +error code. + +If the delayable message functionality cannot find enough free memory to store an incoming +message, it will send messages with delay close to expiration to free memory. + +When the mesh stack is suspended or reset, messages not yet sent are removed and +the :c:member:`bt_mesh_send_cb.start` callback is raised with an error code. + API reference ************* diff --git a/doc/releases/release-notes-3.6.rst b/doc/releases/release-notes-3.6.rst index 85511a103f9..f5f55ecd92b 100644 --- a/doc/releases/release-notes-3.6.rst +++ b/doc/releases/release-notes-3.6.rst @@ -52,6 +52,11 @@ Bluetooth * Mesh + * Added the delayable messages functionality to apply random delays for + the transmitted responses on the Access layer. + The functionality is enabled by the :kconfig:option:`CONFIG_BT_MESH_ACCESS_DELAYABLE_MSG` + Kconfig option. + * Controller Boards & SoC Support diff --git a/include/zephyr/bluetooth/mesh/msg.h b/include/zephyr/bluetooth/mesh/msg.h index e52ca85e3a4..8a7ce1a7128 100644 --- a/include/zephyr/bluetooth/mesh/msg.h +++ b/include/zephyr/bluetooth/mesh/msg.h @@ -98,6 +98,9 @@ struct bt_mesh_msg_ctx { /** Force sending reliably by using segment acknowledgment */ bool send_rel; + /** Send message with a random delay according to the Access layer transmitting rules. */ + bool rnd_delay; + /** TTL, or BT_MESH_TTL_DEFAULT for default TTL. */ uint8_t send_ttl; }; diff --git a/samples/bluetooth/mesh/boards/bbc_microbit.conf b/samples/bluetooth/mesh/boards/bbc_microbit.conf index 26fb05301c1..1655768864b 100644 --- a/samples/bluetooth/mesh/boards/bbc_microbit.conf +++ b/samples/bluetooth/mesh/boards/bbc_microbit.conf @@ -32,3 +32,4 @@ CONFIG_BT_MESH_SUBNET_COUNT=1 CONFIG_BT_MESH_APP_KEY_COUNT=1 CONFIG_BT_MESH_MODEL_GROUP_COUNT=1 CONFIG_BT_MESH_LABEL_COUNT=0 +CONFIG_BT_MESH_ACCESS_DELAYABLE_MSG=n diff --git a/samples/bluetooth/mesh_demo/boards/bbc_microbit.conf b/samples/bluetooth/mesh_demo/boards/bbc_microbit.conf index 5eb087c4ced..64adc465794 100644 --- a/samples/bluetooth/mesh_demo/boards/bbc_microbit.conf +++ b/samples/bluetooth/mesh_demo/boards/bbc_microbit.conf @@ -22,3 +22,4 @@ CONFIG_BT_MESH_BEACON_ENABLED=n CONFIG_BT_MESH_LABEL_COUNT=1 CONFIG_BT_MESH_SETTINGS_WORKQ=n +CONFIG_BT_MESH_ACCESS_DELAYABLE_MSG=n diff --git a/subsys/bluetooth/mesh/CMakeLists.txt b/subsys/bluetooth/mesh/CMakeLists.txt index 10b142e87f5..3fd2e7c3bfc 100644 --- a/subsys/bluetooth/mesh/CMakeLists.txt +++ b/subsys/bluetooth/mesh/CMakeLists.txt @@ -122,6 +122,8 @@ zephyr_library_sources_ifdef(CONFIG_BT_MESH_SOLICITATION solicitation.c) zephyr_library_sources_ifdef(CONFIG_BT_MESH_STATISTIC statistic.c) +zephyr_library_sources_ifdef(CONFIG_BT_MESH_ACCESS_DELAYABLE_MSG delayable_msg.c) + if (CONFIG_BT_MESH_USES_TINYCRYPT) zephyr_library_sources(crypto_tc.c) else() diff --git a/subsys/bluetooth/mesh/Kconfig b/subsys/bluetooth/mesh/Kconfig index ae7b25a6dd7..bd453f8f91c 100644 --- a/subsys/bluetooth/mesh/Kconfig +++ b/subsys/bluetooth/mesh/Kconfig @@ -628,6 +628,41 @@ config BT_MESH_LABEL_NO_RECOVER unprovisioned before upgrading to the version with this option). The option is marked as deprecated to remove the recovery code eventually. +menuconfig BT_MESH_ACCESS_DELAYABLE_MSG + bool "Access layer tx delayable message" + help + Enable following of the message transmitting recommendations, the Access layer + specification. The recommendations are optional. + However, they are strictly recommended if the device participates in the network with + intensive communication where the device receives a lot of requests that require responses. + +if BT_MESH_ACCESS_DELAYABLE_MSG + +config BT_MESH_ACCESS_DELAYABLE_MSG_COUNT + int "Number of simultaneously delayed messages" + default 4 + help + The maximum number of messages the Access layer can manage to delay + at the same time. The number of messages can be handled only if the Access layer + has a sufficient amount of memory to store the model payload for them. + +config BT_MESH_ACCESS_DELAYABLE_MSG_CHUNK_SIZE + int "Maximum delayable message storage chunk" + default 20 + help + Size of memory that Access layer uses to split model message to. It allocates + a sufficient number of these chunks from the pool to store the full model payload. + +config BT_MESH_ACCESS_DELAYABLE_MSG_CHUNK_COUNT + int "Maximum number of available chunks" + default 20 + help + The maximum number of available chunks the Access layer allocates to store model payload. + It is recommended to keep chunk size equal to the reasonable small value to prevent + unnecessary memory wasting. + +endif # BT_MESH_ACCESS_DELAYABLE_MSG + endmenu # Access layer menu "Models" diff --git a/subsys/bluetooth/mesh/access.c b/subsys/bluetooth/mesh/access.c index f7de46fe167..4cffe064329 100644 --- a/subsys/bluetooth/mesh/access.c +++ b/subsys/bluetooth/mesh/access.c @@ -27,6 +27,7 @@ #include "op_agg.h" #include "settings.h" #include "va.h" +#include "delayable_msg.h" #define LOG_LEVEL CONFIG_BT_MESH_ACCESS_LOG_LEVEL #include @@ -1518,6 +1519,13 @@ int bt_mesh_model_send(const struct bt_mesh_model *model, struct bt_mesh_msg_ctx return -EINVAL; } +#if defined CONFIG_BT_MESH_ACCESS_DELAYABLE_MSG + if (ctx->rnd_delay) { + return bt_mesh_delayable_msg_manage(ctx, msg, bt_mesh_model_elem(model)->rt->addr, + cb, cb_data); + } +#endif + return bt_mesh_access_send(ctx, msg, bt_mesh_model_elem(model)->rt->addr, cb, cb_data); } @@ -2613,3 +2621,24 @@ uint8_t bt_mesh_comp_parse_page(struct net_buf_simple *buf) return page; } + +void bt_mesh_access_init(void) +{ +#if defined CONFIG_BT_MESH_ACCESS_DELAYABLE_MSG + bt_mesh_delayable_msg_init(); +#endif +} + +void bt_mesh_access_suspend(void) +{ +#if defined CONFIG_BT_MESH_ACCESS_DELAYABLE_MSG + bt_mesh_delayable_msg_stop(); +#endif +} + +void bt_mesh_access_reset(void) +{ +#if defined CONFIG_BT_MESH_ACCESS_DELAYABLE_MSG + bt_mesh_delayable_msg_stop(); +#endif +} diff --git a/subsys/bluetooth/mesh/access.h b/subsys/bluetooth/mesh/access.h index 48e0eadec10..210fceee319 100644 --- a/subsys/bluetooth/mesh/access.h +++ b/subsys/bluetooth/mesh/access.h @@ -96,8 +96,25 @@ void bt_mesh_msg_cb_set(void (*cb)(uint32_t opcode, struct bt_mesh_msg_ctx *ctx, * * @param ctx The Bluetooth Mesh message context. * @param buf The message payload. + * @param src_addr The source address of model + * @param cb Callback function. + * @param cb_data Callback data. * * @return 0 on success or negative error code on failure. */ int bt_mesh_access_send(struct bt_mesh_msg_ctx *ctx, struct net_buf_simple *buf, uint16_t src_addr, const struct bt_mesh_send_cb *cb, void *cb_data); + +/** @brief Initialize the Access layer. + * + * Initialize the delayable message mechanism if it has been enabled. + */ +void bt_mesh_access_init(void); + +/** @brief Suspend the Access layer. + */ +void bt_mesh_access_suspend(void); + +/** @brief Reset the Access layer. + */ +void bt_mesh_access_reset(void); diff --git a/subsys/bluetooth/mesh/delayable_msg.c b/subsys/bluetooth/mesh/delayable_msg.c new file mode 100644 index 00000000000..5fa43205d63 --- /dev/null +++ b/subsys/bluetooth/mesh/delayable_msg.c @@ -0,0 +1,314 @@ +/* + * Copyright (c) 2023 Nordic Semiconductor ASA + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include +#include +#include +#include + +#include +#include + +#include "msg.h" +#include "access.h" +#include "net.h" + +#define LOG_LEVEL CONFIG_BT_MESH_ACCESS_LOG_LEVEL +#include +LOG_MODULE_REGISTER(bt_mesh_delayable_msg); + +static void delayable_msg_handler(struct k_work *w); +static bool push_msg_from_delayable_msgs(void); + +static struct delayable_msg_chunk { + sys_snode_t node; + uint8_t data[CONFIG_BT_MESH_ACCESS_DELAYABLE_MSG_CHUNK_SIZE]; +} delayable_msg_chunks[CONFIG_BT_MESH_ACCESS_DELAYABLE_MSG_CHUNK_COUNT]; + +static struct delayable_msg_ctx { + sys_snode_t node; + sys_slist_t chunks; + struct bt_mesh_msg_ctx ctx; + uint16_t src_addr; + const struct bt_mesh_send_cb *cb; + void *cb_data; + uint32_t fired_time; + uint16_t len; +} delayable_msgs_ctx[CONFIG_BT_MESH_ACCESS_DELAYABLE_MSG_COUNT]; + +static struct { + sys_slist_t busy_ctx; + sys_slist_t free_ctx; + sys_slist_t free_chunks; + struct k_work_delayable random_delay; +} access_delayable_msg = {.random_delay = Z_WORK_DELAYABLE_INITIALIZER(delayable_msg_handler)}; + +static void put_ctx_to_busy_list(struct delayable_msg_ctx *ctx) +{ + struct delayable_msg_ctx *curr_ctx; + sys_slist_t *list = &access_delayable_msg.busy_ctx; + sys_snode_t *head = sys_slist_peek_head(list); + sys_snode_t *curr = head; + sys_snode_t *prev = curr; + + if (!head) { + sys_slist_append(list, &ctx->node); + return; + } + + do { + curr_ctx = CONTAINER_OF(curr, struct delayable_msg_ctx, node); + if (ctx->fired_time < curr_ctx->fired_time) { + if (curr == head) { + sys_slist_prepend(list, &ctx->node); + } else { + sys_slist_insert(list, prev, &ctx->node); + } + return; + } + prev = curr; + } while ((curr = sys_slist_peek_next(curr))); + + sys_slist_append(list, &ctx->node); +} + +static struct delayable_msg_ctx *peek_pending_msg(void) +{ + struct delayable_msg_ctx *pending_msg = NULL; + sys_snode_t *node = sys_slist_peek_head(&access_delayable_msg.busy_ctx); + + if (node) { + pending_msg = CONTAINER_OF(node, struct delayable_msg_ctx, node); + } + + return pending_msg; +} + +static void reschedule_delayable_msg(struct delayable_msg_ctx *msg) +{ + uint32_t curr_time; + k_timeout_t delay = K_NO_WAIT; + struct delayable_msg_ctx *pending_msg; + + if (msg) { + put_ctx_to_busy_list(msg); + } + + pending_msg = peek_pending_msg(); + + if (!pending_msg) { + return; + } + + curr_time = k_uptime_get_32(); + if (curr_time < pending_msg->fired_time) { + delay = K_MSEC(pending_msg->fired_time - curr_time); + } + + k_work_reschedule(&access_delayable_msg.random_delay, delay); +} + +static int allocate_delayable_msg_chunks(struct delayable_msg_ctx *msg, int number) +{ + sys_snode_t *node; + + for (int i = 0; i < number; i++) { + node = sys_slist_get(&access_delayable_msg.free_chunks); + if (!node) { + LOG_WRN("Unable allocate %u chunks, allocated %u", number, i); + return i; + } + sys_slist_append(&msg->chunks, node); + } + + return number; +} + +static void release_delayable_msg_chunks(struct delayable_msg_ctx *msg) +{ + sys_snode_t *node; + + while ((node = sys_slist_get(&msg->chunks))) { + sys_slist_append(&access_delayable_msg.free_chunks, node); + } +} + +static struct delayable_msg_ctx *allocate_delayable_msg_ctx(void) +{ + struct delayable_msg_ctx *msg; + sys_snode_t *node; + + if (sys_slist_is_empty(&access_delayable_msg.free_ctx)) { + LOG_WRN("Purge pending delayable message."); + if (!push_msg_from_delayable_msgs()) { + return NULL; + } + } + + node = sys_slist_get(&access_delayable_msg.free_ctx); + msg = CONTAINER_OF(node, struct delayable_msg_ctx, node); + sys_slist_init(&msg->chunks); + + return msg; +} + +static void release_delayable_msg_ctx(struct delayable_msg_ctx *ctx) +{ + if (sys_slist_find_and_remove(&access_delayable_msg.busy_ctx, &ctx->node)) { + sys_slist_append(&access_delayable_msg.free_ctx, &ctx->node); + } +} + +static bool push_msg_from_delayable_msgs(void) +{ + sys_snode_t *node; + struct delayable_msg_chunk *chunk; + struct delayable_msg_ctx *msg = peek_pending_msg(); + uint16_t len = msg->len; + int err; + + if (!msg) { + return false; + } + + NET_BUF_SIMPLE_DEFINE(buf, BT_MESH_TX_SDU_MAX); + + SYS_SLIST_FOR_EACH_NODE(&msg->chunks, node) { + uint16_t tmp = MIN(CONFIG_BT_MESH_ACCESS_DELAYABLE_MSG_CHUNK_SIZE, len); + + chunk = CONTAINER_OF(node, struct delayable_msg_chunk, node); + memcpy(net_buf_simple_add(&buf, tmp), chunk->data, tmp); + len -= tmp; + } + + msg->ctx.rnd_delay = false; + err = bt_mesh_access_send(&msg->ctx, &buf, msg->src_addr, msg->cb, msg->cb_data); + msg->ctx.rnd_delay = true; + + if (err == -EBUSY || err == -ENOBUFS) { + return false; + } + + release_delayable_msg_chunks(msg); + release_delayable_msg_ctx(msg); + + if (err && msg->cb && msg->cb->start) { + msg->cb->start(0, err, msg->cb_data); + } + + return true; +} + +static void delayable_msg_handler(struct k_work *w) +{ + if (!push_msg_from_delayable_msgs()) { + sys_snode_t *node = sys_slist_get(&access_delayable_msg.busy_ctx); + struct delayable_msg_ctx *pending_msg = + CONTAINER_OF(node, struct delayable_msg_ctx, node); + + pending_msg->fired_time += 10; + reschedule_delayable_msg(pending_msg); + } else { + reschedule_delayable_msg(NULL); + } +} + +int bt_mesh_delayable_msg_manage(struct bt_mesh_msg_ctx *ctx, struct net_buf_simple *buf, + uint16_t src_addr, const struct bt_mesh_send_cb *cb, void *cb_data) +{ + sys_snode_t *node; + struct delayable_msg_ctx *msg; + uint16_t random_delay; + int total_number = DIV_ROUND_UP(buf->size, CONFIG_BT_MESH_ACCESS_DELAYABLE_MSG_CHUNK_SIZE); + int allocated_number = 0; + uint16_t len = buf->len; + + if (atomic_test_bit(bt_mesh.flags, BT_MESH_SUSPENDED)) { + LOG_WRN("Refusing to allocate message context while suspended"); + return -ENODEV; + } + + if (total_number > CONFIG_BT_MESH_ACCESS_DELAYABLE_MSG_CHUNK_COUNT) { + return -EINVAL; + } + + msg = allocate_delayable_msg_ctx(); + if (!msg) { + LOG_WRN("No available free delayable message context."); + return -ENOMEM; + } + + do { + allocated_number += + allocate_delayable_msg_chunks(msg, total_number - allocated_number); + + if (total_number > allocated_number) { + LOG_DBG("Unable allocate %u chunks, allocated %u", total_number, + allocated_number); + if (!push_msg_from_delayable_msgs()) { + LOG_WRN("No available chunk memory."); + release_delayable_msg_chunks(msg); + release_delayable_msg_ctx(msg); + return -ENOMEM; + } + } + } while (total_number > allocated_number); + + SYS_SLIST_FOR_EACH_NODE(&msg->chunks, node) { + uint16_t tmp = MIN(CONFIG_BT_MESH_ACCESS_DELAYABLE_MSG_CHUNK_SIZE, buf->len); + + struct delayable_msg_chunk *chunk = + CONTAINER_OF(node, struct delayable_msg_chunk, node); + + memcpy(chunk->data, net_buf_simple_pull_mem(buf, tmp), tmp); + } + + bt_rand(&random_delay, sizeof(uint16_t)); + random_delay = 20 + random_delay % (BT_MESH_ADDR_IS_UNICAST(ctx->recv_dst) ? 30 : 480); + msg->fired_time = k_uptime_get_32() + random_delay; + msg->ctx = *ctx; + msg->src_addr = src_addr; + msg->cb = cb; + msg->cb_data = cb_data; + msg->len = len; + + reschedule_delayable_msg(msg); + + return 0; +} + +void bt_mesh_delayable_msg_init(void) +{ + sys_slist_init(&access_delayable_msg.busy_ctx); + sys_slist_init(&access_delayable_msg.free_ctx); + sys_slist_init(&access_delayable_msg.free_chunks); + + for (int i = 0; i < CONFIG_BT_MESH_ACCESS_DELAYABLE_MSG_COUNT; i++) { + sys_slist_append(&access_delayable_msg.free_ctx, &delayable_msgs_ctx[i].node); + } + + for (int i = 0; i < CONFIG_BT_MESH_ACCESS_DELAYABLE_MSG_CHUNK_COUNT; i++) { + sys_slist_append(&access_delayable_msg.free_chunks, &delayable_msg_chunks[i].node); + } +} + +void bt_mesh_delayable_msg_stop(void) +{ + sys_snode_t *node; + struct delayable_msg_ctx *ctx; + + k_work_cancel_delayable(&access_delayable_msg.random_delay); + + while ((node = sys_slist_peek_head(&access_delayable_msg.busy_ctx))) { + ctx = CONTAINER_OF(node, struct delayable_msg_ctx, node); + release_delayable_msg_chunks(ctx); + release_delayable_msg_ctx(ctx); + + if (ctx->cb && ctx->cb->start) { + ctx->cb->start(0, -ENODEV, ctx->cb_data); + } + } +} diff --git a/subsys/bluetooth/mesh/delayable_msg.h b/subsys/bluetooth/mesh/delayable_msg.h new file mode 100644 index 00000000000..1ab5dde2e76 --- /dev/null +++ b/subsys/bluetooth/mesh/delayable_msg.h @@ -0,0 +1,16 @@ +/* + * Copyright (c) 2023 Nordic Semiconductor ASA + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#ifndef ZEPHYR_INCLUDE_BLUETOOTH_MESH_DELAYABLE_MSG_H__ +#define ZEPHYR_INCLUDE_BLUETOOTH_MESH_DELAYABLE_MSG_H__ + +int bt_mesh_delayable_msg_manage(struct bt_mesh_msg_ctx *ctx, struct net_buf_simple *buf, + uint16_t src_addr, const struct bt_mesh_send_cb *cb, + void *cb_data); +void bt_mesh_delayable_msg_init(void); +void bt_mesh_delayable_msg_stop(void); + +#endif /* ZEPHYR_INCLUDE_BLUETOOTH_MESH_DELAYABLE_MSG_H__ */ diff --git a/subsys/bluetooth/mesh/main.c b/subsys/bluetooth/mesh/main.c index 89115ebe3e8..2689a3355c1 100644 --- a/subsys/bluetooth/mesh/main.c +++ b/subsys/bluetooth/mesh/main.c @@ -359,6 +359,7 @@ void bt_mesh_reset(void) */ (void)k_work_cancel_delayable(&bt_mesh.ivu_timer); + bt_mesh_access_reset(); bt_mesh_model_reset(); bt_mesh_cfg_default_set(); bt_mesh_trans_reset(); @@ -459,6 +460,8 @@ int bt_mesh_suspend(void) bt_mesh_model_foreach(model_suspend, NULL); + bt_mesh_access_suspend(); + err = bt_mesh_adv_disable(); if (err) { atomic_clear_bit(bt_mesh.flags, BT_MESH_SUSPENDED); @@ -558,6 +561,7 @@ int bt_mesh_init(const struct bt_mesh_prov *prov, bt_mesh_cfg_default_set(); bt_mesh_net_init(); bt_mesh_trans_init(); + bt_mesh_access_init(); bt_mesh_hb_init(); bt_mesh_beacon_init(); bt_mesh_adv_init(); From 450ad68ca88ffb06c30bc1d3229501611bb5100b Mon Sep 17 00:00:00 2001 From: Aleksandr Khromykh Date: Fri, 1 Dec 2023 08:14:50 +0100 Subject: [PATCH 0959/3723] tests: Bluetooth: Mesh: delayable message unit tests Commit adds unit tests for the newly created access delayable messages. Signed-off-by: Aleksandr Khromykh --- .../mesh/delayable_msg/CMakeLists.txt | 23 ++ tests/bluetooth/mesh/delayable_msg/prj.conf | 5 + tests/bluetooth/mesh/delayable_msg/src/main.c | 338 ++++++++++++++++++ .../mesh/delayable_msg/testcase.yaml | 10 + 4 files changed, 376 insertions(+) create mode 100644 tests/bluetooth/mesh/delayable_msg/CMakeLists.txt create mode 100644 tests/bluetooth/mesh/delayable_msg/prj.conf create mode 100644 tests/bluetooth/mesh/delayable_msg/src/main.c create mode 100644 tests/bluetooth/mesh/delayable_msg/testcase.yaml diff --git a/tests/bluetooth/mesh/delayable_msg/CMakeLists.txt b/tests/bluetooth/mesh/delayable_msg/CMakeLists.txt new file mode 100644 index 00000000000..51bf28d8320 --- /dev/null +++ b/tests/bluetooth/mesh/delayable_msg/CMakeLists.txt @@ -0,0 +1,23 @@ +# SPDX-License-Identifier: Apache-2.0 + +cmake_minimum_required(VERSION 3.20.0) +find_package(Zephyr REQUIRED HINTS $ENV{ZEPHYR_BASE}) +project(bluetooth_mesh_delayable_msg) + +FILE(GLOB app_sources src/*.c) +target_sources(app + PRIVATE + ${app_sources} + ${ZEPHYR_BASE}/subsys/bluetooth/mesh/delayable_msg.c) + +target_include_directories(app + PRIVATE + ${ZEPHYR_BASE}/subsys/bluetooth/mesh) + +target_compile_options(app + PRIVATE + -DCONFIG_BT_MESH_TX_SEG_MAX=32 + -DCONFIG_BT_MESH_ACCESS_DELAYABLE_MSG_COUNT=4 + -DCONFIG_BT_MESH_ACCESS_DELAYABLE_MSG_CHUNK_SIZE=20 + -DCONFIG_BT_MESH_ACCESS_DELAYABLE_MSG_CHUNK_COUNT=20 + -DCONFIG_BT_MESH_USES_TINYCRYPT) diff --git a/tests/bluetooth/mesh/delayable_msg/prj.conf b/tests/bluetooth/mesh/delayable_msg/prj.conf new file mode 100644 index 00000000000..27ca237b68d --- /dev/null +++ b/tests/bluetooth/mesh/delayable_msg/prj.conf @@ -0,0 +1,5 @@ +CONFIG_ZTEST=y +CONFIG_ZTEST_MOCKING=y + +CONFIG_NET_BUF=y +CONFIG_TEST_RANDOM_GENERATOR=y diff --git a/tests/bluetooth/mesh/delayable_msg/src/main.c b/tests/bluetooth/mesh/delayable_msg/src/main.c new file mode 100644 index 00000000000..ce96c19c7a7 --- /dev/null +++ b/tests/bluetooth/mesh/delayable_msg/src/main.c @@ -0,0 +1,338 @@ +/* + * Copyright (c) 2023 Nordic Semiconductor ASA + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include +#include +#include +#include + +#include "net.h" +#include "access.h" +#include "delayable_msg.h" + +#define SRC_ADDR 0x0002 +#define RX_ADDR 0xc000 + +static void start_cb(uint16_t duration, int err, void *cb_data); + +struct bt_mesh_net bt_mesh; + +static struct bt_mesh_msg_ctx gctx = {.net_idx = 0, + .app_idx = 0, + .addr = 0, + .recv_dst = RX_ADDR, + .uuid = NULL, + .recv_rssi = 0, + .recv_ttl = 0x05, + .send_rel = false, + .rnd_delay = true, + .send_ttl = 0x06}; + +static struct bt_mesh_send_cb send_cb = { + .start = start_cb, +}; + +static bool is_fake_random; +static bool check_expectations; +static bool accum_mask; +static bool do_not_call_cb; +static uint16_t fake_random; +static uint8_t *buf_data; +static size_t buf_data_size; +static uint16_t id_mask; +static int cb_err_status; + +K_SEM_DEFINE(delayed_msg_sent, 0, 1); + +/**** Mocked functions ****/ +int bt_mesh_access_send(struct bt_mesh_msg_ctx *ctx, struct net_buf_simple *buf, uint16_t src_addr, + const struct bt_mesh_send_cb *cb, void *cb_data) +{ + if (check_expectations) { + gctx.rnd_delay = false; + ztest_check_expected_data(ctx, sizeof(struct bt_mesh_msg_ctx)); + gctx.rnd_delay = true; + ztest_check_expected_value(src_addr); + ztest_check_expected_data(cb, sizeof(struct bt_mesh_send_cb)); + ztest_check_expected_data(cb_data, sizeof(uint32_t)); + zexpect_mem_equal(buf->data, buf_data, buf_data_size, "Buffer data corrupted"); + } + + if (cb && !do_not_call_cb) { + cb->start(0x0, cb_err_status, cb_data); + } + + return cb_err_status; +} + +int bt_rand(void *buf, size_t len) +{ + if (is_fake_random) { + *(uint16_t *)buf = fake_random; + } else { + sys_rand_get(buf, len); + } + return 0; +} +/**** Mocked functions ****/ + +static void start_cb(uint16_t duration, int err, void *cb_data) +{ + + zassert_equal(err, cb_err_status, "err: %d, cb_err_status: %d", err, cb_err_status); + + if (accum_mask) { + id_mask |= 1 << *(uint16_t *)cb_data; + } else { + k_sem_give(&delayed_msg_sent); + } +} + +static void set_expectation(struct net_buf_simple *buf, uint32_t *buf_id) +{ + ztest_expect_data(bt_mesh_access_send, ctx, &gctx); + ztest_expect_value(bt_mesh_access_send, src_addr, SRC_ADDR); + ztest_expect_data(bt_mesh_access_send, cb, &send_cb); + ztest_expect_data(bt_mesh_access_send, cb_data, buf_id); + buf_data = buf->__buf; + buf_data_size = buf->size; + check_expectations = true; +} + +static void tc_setup(void *fixture) +{ + is_fake_random = false; + check_expectations = false; + accum_mask = false; + id_mask = 0; + do_not_call_cb = false; + cb_err_status = 0; + k_sem_reset(&delayed_msg_sent); + bt_mesh_delayable_msg_init(); +} + +static void tc_teardown(void *fixture) +{ + zassert_equal(gctx.net_idx, 0); + zassert_equal(gctx.app_idx, 0); + zassert_equal(gctx.addr, 0); + zassert_equal(gctx.recv_dst, RX_ADDR); + zassert_is_null(gctx.uuid); + zassert_equal(gctx.recv_rssi, 0); + zassert_equal(gctx.recv_ttl, 0x05); + zassert_false(gctx.send_rel); + zassert_true(gctx.rnd_delay); + zassert_equal(gctx.send_ttl, 0x06); +} + +ZTEST_SUITE(bt_mesh_delayable_msg, NULL, NULL, tc_setup, tc_teardown, NULL); + +/* Simple single message sending with full size. + */ +ZTEST(bt_mesh_delayable_msg, test_single_sending) +{ + uint32_t buf_id = 0x55aa55aa; + uint8_t *payload; + + NET_BUF_SIMPLE_DEFINE(buf, BT_MESH_TX_SDU_MAX); + + payload = net_buf_simple_add(&buf, BT_MESH_TX_SDU_MAX); + for (int i = 0; i < BT_MESH_TX_SDU_MAX; i++) { + payload[i] = i; + } + + set_expectation(&buf, &buf_id); + zexpect_ok(bt_mesh_delayable_msg_manage(&gctx, &buf, SRC_ADDR, &send_cb, &buf_id)); + + zassert_ok(k_sem_take(&delayed_msg_sent, K_SECONDS(1)), + "Delayed message has not been sent."); +} + +/* The test checks that the delayed message mechanism sorts + * the incoming messages according to the transmission start timestamp. + */ +ZTEST(bt_mesh_delayable_msg, test_self_sorting) +{ + uint8_t tx_data[20]; + uint32_t buf1_id = 1; + uint32_t buf2_id = 2; + uint32_t buf3_id = 3; + uint32_t buf4_id = 4; + + NET_BUF_SIMPLE_DEFINE(buf1, 20); + NET_BUF_SIMPLE_DEFINE(buf2, 20); + NET_BUF_SIMPLE_DEFINE(buf3, 20); + NET_BUF_SIMPLE_DEFINE(buf4, 20); + + memset(tx_data, 1, 20); + memcpy(net_buf_simple_add(&buf1, 20), tx_data, 20); + memset(tx_data, 2, 20); + memcpy(net_buf_simple_add(&buf2, 20), tx_data, 20); + memset(tx_data, 3, 20); + memcpy(net_buf_simple_add(&buf3, 20), tx_data, 20); + memset(tx_data, 4, 20); + memcpy(net_buf_simple_add(&buf4, 20), tx_data, 20); + + is_fake_random = true; + fake_random = 30; + zexpect_ok(bt_mesh_delayable_msg_manage(&gctx, &buf1, SRC_ADDR, &send_cb, &buf1_id)); + fake_random = 10; + zexpect_ok(bt_mesh_delayable_msg_manage(&gctx, &buf2, SRC_ADDR, &send_cb, &buf2_id)); + fake_random = 20; + zexpect_ok(bt_mesh_delayable_msg_manage(&gctx, &buf3, SRC_ADDR, &send_cb, &buf3_id)); + fake_random = 40; + zexpect_ok(bt_mesh_delayable_msg_manage(&gctx, &buf4, SRC_ADDR, &send_cb, &buf4_id)); + + set_expectation(&buf2, &buf2_id); + zassert_ok(k_sem_take(&delayed_msg_sent, K_MSEC(100)), + "Delayed message has not been sent."); + set_expectation(&buf3, &buf3_id); + zassert_ok(k_sem_take(&delayed_msg_sent, K_MSEC(100)), + "Delayed message has not been sent."); + set_expectation(&buf1, &buf1_id); + zassert_ok(k_sem_take(&delayed_msg_sent, K_MSEC(100)), + "Delayed message has not been sent."); + set_expectation(&buf4, &buf4_id); + zassert_ok(k_sem_take(&delayed_msg_sent, K_MSEC(100)), + "Delayed message has not been sent."); +} + +/* The test checks that the delayed msg mechanism can allocate new context + * if all contexts are in use by sending the message, that is the closest to + * the tx time. + */ +ZTEST(bt_mesh_delayable_msg, test_ctx_reallocation) +{ + uint8_t tx_data[20]; + uint32_t buf_id1 = 0; + uint32_t buf_id2 = 1; + uint32_t buf_id3 = 2; + uint32_t buf_id4 = 3; + uint32_t buf_id5 = 4; + + NET_BUF_SIMPLE_DEFINE(buf, 20); + + memset(tx_data, 1, 20); + memcpy(net_buf_simple_add(&buf, 20), tx_data, 20); + + accum_mask = true; + is_fake_random = true; + fake_random = 10; + zexpect_ok(bt_mesh_delayable_msg_manage(&gctx, &buf, SRC_ADDR, &send_cb, &buf_id1)); + fake_random = 30; + zexpect_ok(bt_mesh_delayable_msg_manage(&gctx, &buf, SRC_ADDR, &send_cb, &buf_id2)); + fake_random = 20; + zexpect_ok(bt_mesh_delayable_msg_manage(&gctx, &buf, SRC_ADDR, &send_cb, &buf_id3)); + fake_random = 40; + zexpect_ok(bt_mesh_delayable_msg_manage(&gctx, &buf, SRC_ADDR, &send_cb, &buf_id4)); + fake_random = 40; + zexpect_ok(bt_mesh_delayable_msg_manage(&gctx, &buf, SRC_ADDR, &send_cb, &buf_id5)); + zassert_equal(id_mask, 0x0001, "Delayed message context reallocation was broken"); + k_sleep(K_MSEC(500)); + zassert_equal(id_mask, 0x001F); +} + +/* The test checks that the delayed msg mechanism can allocate new chunks + * if all chunks are in use by sending the other messages. + */ +ZTEST(bt_mesh_delayable_msg, test_chunk_reallocation) +{ + uint8_t tx_data[BT_MESH_TX_SDU_MAX]; + uint32_t buf_id1 = 0; + uint32_t buf_id2 = 1; + uint32_t buf_id3 = 2; + uint32_t buf_id4 = 3; + + NET_BUF_SIMPLE_DEFINE(buf1, 20); + NET_BUF_SIMPLE_DEFINE(buf2, BT_MESH_TX_SDU_MAX); + + memset(tx_data, 1, BT_MESH_TX_SDU_MAX); + memcpy(net_buf_simple_add(&buf1, 20), tx_data, 20); + memcpy(net_buf_simple_add(&buf2, BT_MESH_TX_SDU_MAX), tx_data, BT_MESH_TX_SDU_MAX); + + accum_mask = true; + zexpect_ok(bt_mesh_delayable_msg_manage(&gctx, &buf1, SRC_ADDR, &send_cb, &buf_id1)); + zexpect_ok(bt_mesh_delayable_msg_manage(&gctx, &buf1, SRC_ADDR, &send_cb, &buf_id2)); + zexpect_ok(bt_mesh_delayable_msg_manage(&gctx, &buf1, SRC_ADDR, &send_cb, &buf_id3)); + zexpect_ok(bt_mesh_delayable_msg_manage(&gctx, &buf2, SRC_ADDR, &send_cb, &buf_id4)); + zassert_equal(id_mask, 0x0007, "Delayed message chunks reallocation was broken"); + k_sleep(K_MSEC(500)); + zassert_equal(id_mask, 0x000F); +} + +/* The test checks that the delayed msg mechanism can reschedule access messages + * transport layes doesn't have enough memory or buffers at the moment. + * Also it checks that the delayed msg mechanism can handle the other transport + * layer errors without rescheduling appropriate access messages. + */ +ZTEST(bt_mesh_delayable_msg, test_cb_error_status) +{ + uint32_t buf_id = 0x55aa55aa; + uint8_t tx_data[BT_MESH_TX_SDU_MAX]; + + NET_BUF_SIMPLE_DEFINE(buf1, 20); + NET_BUF_SIMPLE_DEFINE(buf2, 20); + NET_BUF_SIMPLE_DEFINE(buf3, 20); + + memset(tx_data, 1, BT_MESH_TX_SDU_MAX); + memcpy(net_buf_simple_add(&buf1, 20), tx_data, 20); + memcpy(net_buf_simple_add(&buf2, 20), tx_data, 20); + memcpy(net_buf_simple_add(&buf3, 20), tx_data, 20); + + cb_err_status = -ENOBUFS; + zexpect_ok(bt_mesh_delayable_msg_manage(&gctx, &buf1, SRC_ADDR, &send_cb, &buf_id)); + zassert_ok(k_sem_take(&delayed_msg_sent, K_SECONDS(1)), + "Delayed message has not been handled."); + cb_err_status = 0; + zassert_ok(k_sem_take(&delayed_msg_sent, K_SECONDS(1)), + "Delayed message has not been sent."); + + cb_err_status = -EBUSY; + zexpect_ok(bt_mesh_delayable_msg_manage(&gctx, &buf2, SRC_ADDR, &send_cb, &buf_id)); + zassert_ok(k_sem_take(&delayed_msg_sent, K_SECONDS(1)), + "Delayed message has not been handled."); + cb_err_status = 0; + zassert_ok(k_sem_take(&delayed_msg_sent, K_SECONDS(1)), + "Delayed message has not been sent."); + + cb_err_status = -EINVAL; + do_not_call_cb = true; + zexpect_ok(bt_mesh_delayable_msg_manage(&gctx, &buf3, SRC_ADDR, &send_cb, &buf_id)); + zassert_ok(k_sem_take(&delayed_msg_sent, K_SECONDS(1)), + "Delayed message has not been handled."); + cb_err_status = 0; + zexpect_not_ok(k_sem_take(&delayed_msg_sent, K_SECONDS(1)), + "Delayed message has not been handled."); +} + +/* The test checks that the delayed msg mechanism raises + * the model message callback with the appropriate error code after + * stopping the functionality. + */ +ZTEST(bt_mesh_delayable_msg, test_stop_handler) +{ + uint8_t tx_data[20]; + uint32_t buf_id1 = 0; + uint32_t buf_id2 = 1; + uint32_t buf_id3 = 2; + uint32_t buf_id4 = 3; + + NET_BUF_SIMPLE_DEFINE(buf, 20); + + memset(tx_data, 1, 20); + memcpy(net_buf_simple_add(&buf, 20), tx_data, 20); + + accum_mask = true; + cb_err_status = -ENODEV; + zexpect_ok(bt_mesh_delayable_msg_manage(&gctx, &buf, SRC_ADDR, &send_cb, &buf_id1)); + zexpect_ok(bt_mesh_delayable_msg_manage(&gctx, &buf, SRC_ADDR, &send_cb, &buf_id2)); + zexpect_ok(bt_mesh_delayable_msg_manage(&gctx, &buf, SRC_ADDR, &send_cb, &buf_id3)); + zexpect_ok(bt_mesh_delayable_msg_manage(&gctx, &buf, SRC_ADDR, &send_cb, &buf_id4)); + bt_mesh_delayable_msg_stop(); + zexpect_not_ok(k_sem_take(&delayed_msg_sent, K_SECONDS(1)), + "Delayed message has been sent after stopping."); + zassert_equal(id_mask, 0x000F, "Not all scheduled messages were handled after stopping"); +} diff --git a/tests/bluetooth/mesh/delayable_msg/testcase.yaml b/tests/bluetooth/mesh/delayable_msg/testcase.yaml new file mode 100644 index 00000000000..5b5e9ee0f37 --- /dev/null +++ b/tests/bluetooth/mesh/delayable_msg/testcase.yaml @@ -0,0 +1,10 @@ +tests: + bluetooth.mesh.delayable_msg: + platform_allow: + - native_posix + - native_sim + tags: + - bluetooth + - mesh + integration_platforms: + - native_sim From 899d4f997e6eebd7e647beeb123dc5deb2821cc9 Mon Sep 17 00:00:00 2001 From: Flavio Ceolin Date: Tue, 21 Nov 2023 12:59:39 -0800 Subject: [PATCH 0960/3723] userspace: Additional checks in K_SYSCALL_MEMORY This macros needed additional checks before invoking arch_buffer_validate. - size can not be less then 0. Some functions invoke this macro using signed type which will be promote to unsigned when invoking arch_buffer_validate. We need to do an early check. - We need to check for possible overflow, since a malicious user application could use a negative number that would be promoted to a big value that would cause a integer overflow when adding it to the buffer address, leading to invalid checks. Signed-off-by: Flavio Ceolin --- include/zephyr/internal/syscall_handler.h | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/include/zephyr/internal/syscall_handler.h b/include/zephyr/internal/syscall_handler.h index f692c17dc1f..74352ef484b 100644 --- a/include/zephyr/internal/syscall_handler.h +++ b/include/zephyr/internal/syscall_handler.h @@ -413,8 +413,9 @@ int k_usermode_string_copy(char *dst, const char *src, size_t maxlen); * functionality in the Zephyr tree. */ #define K_SYSCALL_MEMORY(ptr, size, write) \ - K_SYSCALL_VERIFY_MSG(arch_buffer_validate((void *)ptr, size, write) \ - == 0, \ + K_SYSCALL_VERIFY_MSG((size >= 0) && !Z_DETECT_POINTER_OVERFLOW(ptr, size) \ + && (arch_buffer_validate((void *)ptr, size, write) \ + == 0), \ "Memory region %p (size %zu) %s access denied", \ (void *)(ptr), (size_t)(size), \ write ? "write" : "read") From a2184305f2424c6cd93679fbb07eafdc6a71267b Mon Sep 17 00:00:00 2001 From: Szymon Janc Date: Thu, 30 Nov 2023 15:13:58 +0100 Subject: [PATCH 0961/3723] bluetooth: tester: Enable Periodic Advertising support This is required by GAP/PADV/PASM/BV-01-C and GAP/PADV/PAM/BV-01-C qualification test cases. Signed-off-by: Szymon Janc --- tests/bluetooth/tester/prj.conf | 2 ++ 1 file changed, 2 insertions(+) diff --git a/tests/bluetooth/tester/prj.conf b/tests/bluetooth/tester/prj.conf index b24eca84c6a..ac240dbe63c 100644 --- a/tests/bluetooth/tester/prj.conf +++ b/tests/bluetooth/tester/prj.conf @@ -31,6 +31,8 @@ CONFIG_BT_GATT_NOTIFY_MULTIPLE=y CONFIG_BT_ATT_RETRY_ON_SEC_ERR=n CONFIG_BT_GATT_DYNAMIC_DB=y CONFIG_BT_EXT_ADV=y +CONFIG_BT_PER_ADV=y +CONFIG_BT_PER_ADV_SYNC=y CONFIG_BT_BUF_ACL_RX_SIZE=100 CONFIG_BT_RX_STACK_SIZE=4096 From 19773a61c6445149a661a172ca9ef9678b96e994 Mon Sep 17 00:00:00 2001 From: Declan Snyder Date: Thu, 30 Nov 2023 14:26:02 -0600 Subject: [PATCH 0962/3723] drivers: ksz8081: Some bug fixes & 25MHz RMII - PHY can be set up as rmii but still use 25 MHz MDC, add DT property value for this case - Fix KSZ8081 driver spamming phy status in debug level logging, and fix some other state/logging logic - Fix PHY driver not rescheduling monitor work if first configuration fails, change code path to use goto for errors - Handle case where some phys are not using the gpio pins in phy driver Make GPIO properties of ksz8081 phy optional since these hardware pins may be unused on some boards Signed-off-by: Declan Snyder --- drivers/ethernet/phy/phy_microchip_ksz8081.c | 95 +++++++++++++------- dts/bindings/ethernet/microchip,ksz8081.yaml | 3 +- 2 files changed, 66 insertions(+), 32 deletions(-) diff --git a/drivers/ethernet/phy/phy_microchip_ksz8081.c b/drivers/ethernet/phy/phy_microchip_ksz8081.c index 46382a37df6..10d7f78172c 100644 --- a/drivers/ethernet/phy/phy_microchip_ksz8081.c +++ b/drivers/ethernet/phy/phy_microchip_ksz8081.c @@ -35,14 +35,19 @@ LOG_MODULE_REGISTER(LOG_MODULE_NAME); enum ksz8081_interface { KSZ8081_MII, KSZ8081_RMII, + KSZ8081_RMII_25MHZ, }; struct mc_ksz8081_config { uint8_t addr; const struct device *mdio_dev; enum ksz8081_interface phy_iface; +#if DT_ANY_INST_HAS_PROP_STATUS_OKAY(mc_reset_gpio) const struct gpio_dt_spec reset_gpio; +#endif +#if DT_ANY_INST_HAS_PROP_STATUS_OKAY(mc_interrupt_gpio) const struct gpio_dt_spec interrupt_gpio; +#endif }; struct mc_ksz8081_data { @@ -137,6 +142,7 @@ static int phy_mc_ksz8081_get_link(const struct device *dev, uint32_t bmsr = 0; uint32_t anar = 0; uint32_t anlpar = 0; + struct phy_link_state old_state = data->state; /* Lock mutex */ ret = k_mutex_lock(&data->mutex, K_FOREVER); @@ -154,7 +160,9 @@ static int phy_mc_ksz8081_get_link(const struct device *dev, } state->is_up = bmsr & MII_BMSR_LINK_STATUS; - LOG_DBG("PHY %d is %s", config->addr, data->state.is_up ? "up" : "down"); + if (!state->is_up) { + goto result; + } /* Read currently configured advertising options */ ret = phy_mc_ksz8081_read(dev, MII_ANAR, &anar); @@ -186,15 +194,18 @@ static int phy_mc_ksz8081_get_link(const struct device *dev, } else if (mutual_capabilities & MII_ADVERTISE_10_HALF) { state->speed = LINK_HALF_10BASE_T; } else { - LOG_ERR("No valid PHY %d capabilities", config->addr); - return -EIO; + ret = -EIO; } - LOG_DBG("PHY (%d) Link speed %s Mb, %s duplex\n", config->addr, - (PHY_LINK_IS_SPEED_100M(state->speed) ? "100" : "10"), - PHY_LINK_IS_FULL_DUPLEX(state->speed) ? "full" : "half"); +result: + if (memcmp(&old_state, state, sizeof(struct phy_link_state)) != 0) { + LOG_DBG("PHY %d is %s", config->addr, state->is_up ? "up" : "down"); + LOG_DBG("PHY (%d) Link speed %s Mb, %s duplex\n", config->addr, + (PHY_LINK_IS_SPEED_100M(state->speed) ? "100" : "10"), + PHY_LINK_IS_FULL_DUPLEX(state->speed) ? "full" : "half"); + } - return 0; + return ret; } /* @@ -255,7 +266,7 @@ static int phy_mc_ksz8081_cfg_link(const struct device *dev, ret = k_mutex_lock(&data->mutex, K_FOREVER); if (ret) { LOG_ERR("PHY mutex lock error"); - return ret; + goto done; } /* We are going to reconfigure the phy, don't need to monitor until done */ @@ -264,16 +275,14 @@ static int phy_mc_ksz8081_cfg_link(const struct device *dev, /* DT configurations */ ret = phy_mc_ksz8081_static_cfg(dev); if (ret) { - k_mutex_unlock(&data->mutex); - return ret; + goto done; } /* Read ANAR register to write back */ ret = phy_mc_ksz8081_read(dev, MII_ANAR, &anar); if (ret) { LOG_ERR("Error reading phy (%d) advertising register", config->addr); - k_mutex_unlock(&data->mutex); - return -EIO; + goto done; } /* Setup advertising register */ @@ -302,31 +311,18 @@ static int phy_mc_ksz8081_cfg_link(const struct device *dev, ret = phy_mc_ksz8081_write(dev, MII_ANAR, anar); if (ret) { LOG_ERR("Error writing phy (%d) advertising register", config->addr); - k_mutex_unlock(&data->mutex); - return ret; + goto done; } /* (re)do autonegotiation */ ret = phy_mc_ksz8081_autonegotiate(dev); if (ret) { LOG_ERR("Error in autonegotiation"); - k_mutex_unlock(&data->mutex); - return ret; + goto done; } - /* Unlock mutex */ - k_mutex_unlock(&data->mutex); - - /* Get link status */ ret = phy_mc_ksz8081_get_link(dev, &data->state); - if (ret) { - return ret; - } - - /* Start monitoring */ - k_work_schedule(&data->phy_monitor_work, - K_MSEC(CONFIG_PHY_MONITOR_PERIOD)); /* Log the results of the configuration */ LOG_INF("PHY %d is %s", config->addr, data->state.is_up ? "up" : "down"); @@ -334,7 +330,15 @@ static int phy_mc_ksz8081_cfg_link(const struct device *dev, (PHY_LINK_IS_SPEED_100M(data->state.speed) ? "100" : "10"), PHY_LINK_IS_FULL_DUPLEX(data->state.speed) ? "full" : "half"); - return 0; +done: + /* Unlock mutex */ + k_mutex_unlock(&data->mutex); + + /* Start monitoring */ + k_work_reschedule(&data->phy_monitor_work, + K_MSEC(CONFIG_PHY_MONITOR_PERIOD)); + + return ret; } static int phy_mc_ksz8081_link_cb_set(const struct device *dev, @@ -389,12 +393,26 @@ static int phy_mc_ksz8081_init(const struct device *dev) mdio_bus_enable(config->mdio_dev); +#if DT_ANY_INST_HAS_PROP_STATUS_OKAY(mc_interrupt_gpio) + if (!config->interrupt_gpio.port) { + goto skip_int_gpio; + } + /* Prevent NAND TREE mode */ ret = gpio_pin_configure_dt(&config->interrupt_gpio, GPIO_OUTPUT_ACTIVE); if (ret) { return ret; } +skip_int_gpio: +#endif /* DT_ANY_INST_HAS_PROP_STATUS_OKAY(mc_interrupt_gpio) */ + + +#if DT_ANY_INST_HAS_PROP_STATUS_OKAY(mc_reset_gpio) + if (!config->reset_gpio.port) { + goto skip_reset_gpio; + } + /* Start reset */ ret = gpio_pin_configure_dt(&config->reset_gpio, GPIO_OUTPUT_INACTIVE); if (ret) { @@ -410,6 +428,9 @@ static int phy_mc_ksz8081_init(const struct device *dev) return ret; } +skip_reset_gpio: +#endif /* DT_ANY_INST_HAS_PROP_STATUS_OKAY(mc_reset_gpio) */ + k_work_init_delayable(&data->phy_monitor_work, phy_mc_ksz8081_monitor_work_handler); @@ -424,13 +445,27 @@ static const struct ethphy_driver_api mc_ksz8081_phy_api = { .write = phy_mc_ksz8081_write, }; +#if DT_ANY_INST_HAS_PROP_STATUS_OKAY(mc_reset_gpio) +#define RESET_GPIO(n) \ + .reset_gpio = GPIO_DT_SPEC_INST_GET_OR(n, mc_reset_gpio, {0}), +#else +#define RESET_GPIO(n) +#endif /* reset gpio */ + +#if DT_ANY_INST_HAS_PROP_STATUS_OKAY(mc_interrupt_gpio) +#define INTERRUPT_GPIO(n) \ + .interrupt_gpio = GPIO_DT_SPEC_INST_GET_OR(n, mc_interrupt_gpio, {0}), +#else +#define INTERRUPT_GPIO(n) +#endif /* interrupt gpio */ + #define MICROCHIP_KSZ8081_INIT(n) \ static const struct mc_ksz8081_config mc_ksz8081_##n##_config = { \ .addr = DT_INST_REG_ADDR(n), \ .mdio_dev = DEVICE_DT_GET(DT_INST_PARENT(n)), \ .phy_iface = DT_INST_ENUM_IDX(n, mc_interface_type), \ - .reset_gpio = GPIO_DT_SPEC_INST_GET(n, mc_reset_gpio), \ - .interrupt_gpio = GPIO_DT_SPEC_INST_GET(n, mc_interrupt_gpio), \ + RESET_GPIO(n) \ + INTERRUPT_GPIO(n) \ }; \ \ static struct mc_ksz8081_data mc_ksz8081_##n##_data; \ diff --git a/dts/bindings/ethernet/microchip,ksz8081.yaml b/dts/bindings/ethernet/microchip,ksz8081.yaml index 14ccfe7cc78..83a6be9f72d 100644 --- a/dts/bindings/ethernet/microchip,ksz8081.yaml +++ b/dts/bindings/ethernet/microchip,ksz8081.yaml @@ -10,12 +10,10 @@ include: ethernet-phy.yaml properties: mc,reset-gpio: type: phandle-array - required: true specifier-space: gpio description: GPIO connected to PHY reset signal pin. Reset is active low. mc,interrupt-gpio: type: phandle-array - required: true specifier-space: gpio description: GPIO for interrupt signal indicating PHY state change. mc,interface-type: @@ -25,3 +23,4 @@ properties: enum: - "mii" - "rmii" + - "rmii-25MHz" From 20af909df5cdf2dff7bac9e4b0aa56f0c7739dfe Mon Sep 17 00:00:00 2001 From: Declan Snyder Date: Thu, 30 Nov 2023 14:40:11 -0600 Subject: [PATCH 0963/3723] drivers: nxp_enet: Do clock init from zephyr Need to do the ENET module-level clock initialization from zephyr instead of MCUX HAL, because now there are multiple zephyr drivers with different init priorities that rely on the module being clocked. MDIO must be initialized before the ENET MAC, and the MAC driver currently calls ENET_Init from the HAL to initialize the clock, but MDIO needs the module clock enabled first on some platforms. So replace the MAC init with ENET_Up from the HAL, which doesn't include clock init, then do clock init from a higher priority sys init based on the parent compatible. Also, add support for enet clock ungating with clock_control_on on ccm driver do this with current platforms supported. Signed-off-by: Declan Snyder --- .../clock_control/clock_control_mcux_ccm.c | 6 ++++ drivers/ethernet/eth_nxp_enet.c | 29 +++++++++++++++++-- 2 files changed, 33 insertions(+), 2 deletions(-) diff --git a/drivers/clock_control/clock_control_mcux_ccm.c b/drivers/clock_control/clock_control_mcux_ccm.c index 1918673142f..355f85dfc3e 100644 --- a/drivers/clock_control/clock_control_mcux_ccm.c +++ b/drivers/clock_control/clock_control_mcux_ccm.c @@ -106,6 +106,12 @@ static int mcux_ccm_on(const struct device *dev, CLOCK_EnableClock(lpuart_clocks[instance]); return 0; #endif + +#if defined(CONFIG_ETH_NXP_ENET) + case IMX_CCM_ENET_CLK: + CLOCK_EnableClock(kCLOCK_Enet); + return 0; +#endif default: (void)instance; return 0; diff --git a/drivers/ethernet/eth_nxp_enet.c b/drivers/ethernet/eth_nxp_enet.c index 6537ea1c840..9c18b2d129a 100644 --- a/drivers/ethernet/eth_nxp_enet.c +++ b/drivers/ethernet/eth_nxp_enet.c @@ -800,7 +800,7 @@ static int eth_nxp_enet_init(const struct device *dev) enet_config.callback = eth_callback; enet_config.userData = (void *)dev; - ENET_Init(config->base, + ENET_Up(config->base, &data->enet_handle, &enet_config, &config->buffer_config, @@ -971,7 +971,7 @@ static const struct ethernet_api api_funcs = { .txFrameInfo = NULL #endif -#define NXP_ENET_INIT(n) \ +#define NXP_ENET_MAC_INIT(n) \ NXP_ENET_GENERATE_MAC(n) \ \ PINCTRL_DT_INST_DEFINE(n); \ @@ -1047,4 +1047,29 @@ static const struct ethernet_api api_funcs = { CONFIG_ETH_INIT_PRIORITY, \ &api_funcs, NET_ETH_MTU); +DT_INST_FOREACH_STATUS_OKAY(NXP_ENET_MAC_INIT) + + +/* + * ENET module-level management + */ + +#undef DT_DRV_COMPAT +#define DT_DRV_COMPAT nxp_enet + +#define NXP_ENET_INIT(n) \ + \ +int nxp_enet_##n##_init(void) \ +{ \ + clock_control_on(DEVICE_DT_GET(DT_INST_CLOCKS_CTLR(n)), \ + (void *)DT_INST_CLOCKS_CELL_BY_IDX(n, 0, name)); \ + \ + ENET_Reset((ENET_Type *)DT_INST_REG_ADDR(n)); \ + \ + return 0; \ +} \ + \ + /* Init the module before any of the MAC, MDIO, or PTP clock */ \ + SYS_INIT(nxp_enet_##n##_init, POST_KERNEL, 0); + DT_INST_FOREACH_STATUS_OKAY(NXP_ENET_INIT) From 3ec0f3a462a4aff9ffdbb566aa90d67d23bc8d67 Mon Sep 17 00:00:00 2001 From: Declan Snyder Date: Thu, 30 Nov 2023 14:43:15 -0600 Subject: [PATCH 0964/3723] drivers: clock_control: Support NXP_ENET Support ENET peripheral clock in MCUX SIM and CCM_REV2 driver Signed-off-by: Declan Snyder --- drivers/clock_control/clock_control_mcux_ccm_rev2.c | 5 +++++ drivers/clock_control/clock_control_mcux_sim.c | 9 +++++++++ include/zephyr/dt-bindings/clock/imx_ccm_rev2.h | 1 + include/zephyr/dt-bindings/clock/kinetis_sim.h | 2 ++ 4 files changed, 17 insertions(+) diff --git a/drivers/clock_control/clock_control_mcux_ccm_rev2.c b/drivers/clock_control/clock_control_mcux_ccm_rev2.c index bcf61353b1f..f7ef8b80b59 100644 --- a/drivers/clock_control/clock_control_mcux_ccm_rev2.c +++ b/drivers/clock_control/clock_control_mcux_ccm_rev2.c @@ -17,6 +17,11 @@ LOG_MODULE_REGISTER(clock_control); static int mcux_ccm_on(const struct device *dev, clock_control_subsys_t sub_system) { +#ifdef CONFIG_ETH_NXP_ENET + if ((uint32_t)sub_system == IMX_CCM_ENET_CLK) { + CLOCK_EnableClock(kCLOCK_Enet); + } +#endif return 0; } diff --git a/drivers/clock_control/clock_control_mcux_sim.c b/drivers/clock_control/clock_control_mcux_sim.c index ce589c9a6bf..ed74ff941f5 100644 --- a/drivers/clock_control/clock_control_mcux_sim.c +++ b/drivers/clock_control/clock_control_mcux_sim.c @@ -20,6 +20,12 @@ static int mcux_sim_on(const struct device *dev, { clock_ip_name_t clock_ip_name = (clock_ip_name_t) sub_system; +#ifdef CONFIG_ETH_NXP_ENET + if ((uint32_t)sub_system == KINETIS_SIM_ENET_CLK) { + clock_ip_name = kCLOCK_Enet0; + } +#endif + CLOCK_EnableClock(clock_ip_name); return 0; @@ -45,6 +51,9 @@ static int mcux_sim_get_subsys_rate(const struct device *dev, case KINETIS_SIM_LPO_CLK: clock_name = kCLOCK_LpoClk; break; + case KINETIS_SIM_ENET_CLK: + clock_name = kCLOCK_CoreSysClk; + break; default: clock_name = (clock_name_t) sub_system; break; diff --git a/include/zephyr/dt-bindings/clock/imx_ccm_rev2.h b/include/zephyr/dt-bindings/clock/imx_ccm_rev2.h index 75de126bd29..fc7be3628d8 100644 --- a/include/zephyr/dt-bindings/clock/imx_ccm_rev2.h +++ b/include/zephyr/dt-bindings/clock/imx_ccm_rev2.h @@ -86,6 +86,7 @@ /* ENET */ #define IMX_CCM_ENET_CLK 0x3000UL +#define IMX_CCM_ENET_PLL 0x3001UL #endif /* ZEPHYR_INCLUDE_DT_BINDINGS_CLOCK_IMX_CCM_REV2_H_ */ diff --git a/include/zephyr/dt-bindings/clock/kinetis_sim.h b/include/zephyr/dt-bindings/clock/kinetis_sim.h index 6c06928ec80..8395a05b483 100644 --- a/include/zephyr/dt-bindings/clock/kinetis_sim.h +++ b/include/zephyr/dt-bindings/clock/kinetis_sim.h @@ -24,5 +24,7 @@ #define KINETIS_SIM_ER32KSEL_RTC 2 #define KINETIS_SIM_ER32KSEL_LPO1KHZ 3 +#define KINETIS_SIM_ENET_CLK 4321 + #endif /* ZEPHYR_INCLUDE_DT_BINDINGS_CLOCK_KINETIS_SIM_H_ */ From 7008350a32d125838795a8d4b290854999c0964e Mon Sep 17 00:00:00 2001 From: Declan Snyder Date: Wed, 6 Dec 2023 10:13:02 -0600 Subject: [PATCH 0965/3723] drivers: mdio_nxp_enet: Fix typo in MDC frequency MDC frequency had one extra 0 by mistake Signed-off-by: Declan Snyder --- drivers/mdio/mdio_nxp_enet.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/mdio/mdio_nxp_enet.c b/drivers/mdio/mdio_nxp_enet.c index 88a25f8c981..cc704f2271a 100644 --- a/drivers/mdio/mdio_nxp_enet.c +++ b/drivers/mdio/mdio_nxp_enet.c @@ -17,7 +17,7 @@ #include /* Target MDC frequency 2.5 MHz */ -#define NXP_ENET_MDIO_MDC_FREQ 25000000U +#define NXP_ENET_MDIO_MDC_FREQ 2500000U struct nxp_enet_mdio_config { ENET_Type *base; From e66876126ee24ded3efdf98d9eb1e9b7942bd929 Mon Sep 17 00:00:00 2001 From: Declan Snyder Date: Thu, 30 Nov 2023 14:43:51 -0600 Subject: [PATCH 0966/3723] soc: k6x: Support NXP ENET Driver NXP ENET driver support from soc.c for k6x series Signed-off-by: Declan Snyder --- soc/arm/nxp_kinetis/k6x/soc.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/soc/arm/nxp_kinetis/k6x/soc.c b/soc/arm/nxp_kinetis/k6x/soc.c index 083f695db32..2463b5ddc28 100644 --- a/soc/arm/nxp_kinetis/k6x/soc.c +++ b/soc/arm/nxp_kinetis/k6x/soc.c @@ -105,7 +105,7 @@ static ALWAYS_INLINE void clock_init(void) CLOCK_SetLpuartClock(LPUART0SRC_OSCERCLK); #endif -#if CONFIG_ETH_MCUX +#if CONFIG_ETH_MCUX || CONFIG_ETH_NXP_ENET CLOCK_SetEnetTime0Clock(TIMESRC_OSCERCLK); #endif #if CONFIG_ETH_MCUX_RMII_EXT_CLK From 17a99367d25397b4325cca74e88abd8c841eaeed Mon Sep 17 00:00:00 2001 From: Declan Snyder Date: Tue, 5 Dec 2023 13:21:26 -0600 Subject: [PATCH 0967/3723] soc: rt11xx: support nxp_enet in soc Support NXP ENET on RT11xx soc Signed-off-by: Declan Snyder --- soc/arm/nxp_imx/rt/soc_rt11xx.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/soc/arm/nxp_imx/rt/soc_rt11xx.c b/soc/arm/nxp_imx/rt/soc_rt11xx.c index 190be4746ed..9c38f3e7963 100644 --- a/soc/arm/nxp_imx/rt/soc_rt11xx.c +++ b/soc/arm/nxp_imx/rt/soc_rt11xx.c @@ -277,7 +277,7 @@ static ALWAYS_INLINE void clock_init(void) CLOCK_InitPfd(kCLOCK_PllSys2, kCLOCK_Pfd2, 24); /* Init System Pll2 pfd3. */ -#ifdef CONFIG_ETH_MCUX +#if CONFIG_ETH_MCUX || CONFIG_ETH_NXP_ENET CLOCK_InitPfd(kCLOCK_PllSys2, kCLOCK_Pfd3, 24); #else CLOCK_InitPfd(kCLOCK_PllSys2, kCLOCK_Pfd3, 32); @@ -324,7 +324,7 @@ static ALWAYS_INLINE void clock_init(void) #endif /* Configure BUS using SYS_PLL3_CLK */ -#ifdef CONFIG_ETH_MCUX +#if CONFIG_ETH_MCUX || CONFIG_ETH_NXP_ENET /* Configure root bus clock at 198M */ rootCfg.mux = kCLOCK_BUS_ClockRoot_MuxSysPll2Pfd3; rootCfg.div = 2; @@ -396,7 +396,7 @@ static ALWAYS_INLINE void clock_init(void) #endif -#ifdef CONFIG_ETH_MCUX +#if CONFIG_ETH_MCUX || CONFIG_ETH_NXP_ENET #if DT_NODE_HAS_STATUS(DT_NODELABEL(enet), okay) /* 50 MHz ENET clock */ rootCfg.mux = kCLOCK_ENET1_ClockRoot_MuxSysPll1Div2; From 3d6c1fd6f712d63d558f46121dd0333e7b5b264f Mon Sep 17 00:00:00 2001 From: Declan Snyder Date: Tue, 5 Dec 2023 13:21:50 -0600 Subject: [PATCH 0968/3723] boards: nxp: Support NXP ENET FRDM_K64F & RT11xx Support NXP ENET on FRDM_K64F and rt11xx boards. Document the experimental driver in all boards. Signed-off-by: Declan Snyder --- boards/arm/frdm_k64f/doc/index.rst | 10 ++ .../dts/nxp,enet-experimental.overlay | 108 +++++++++++++++ boards/arm/mimxrt1160_evk/doc/index.rst | 10 ++ .../dts/nxp,enet-experimental.overlay | 123 ++++++++++++++++++ boards/arm/mimxrt1170_evk/doc/index.rst | 10 ++ .../dts/nxp,enet-experimental.overlay | 123 ++++++++++++++++++ 6 files changed, 384 insertions(+) create mode 100644 boards/arm/frdm_k64f/dts/nxp,enet-experimental.overlay create mode 100644 boards/arm/mimxrt1160_evk/dts/nxp,enet-experimental.overlay create mode 100644 boards/arm/mimxrt1170_evk/dts/nxp,enet-experimental.overlay diff --git a/boards/arm/frdm_k64f/doc/index.rst b/boards/arm/frdm_k64f/doc/index.rst index 6d9c86a5714..e2fce31a9b1 100644 --- a/boards/arm/frdm_k64f/doc/index.rst +++ b/boards/arm/frdm_k64f/doc/index.rst @@ -378,3 +378,13 @@ of pyocd commands: .. _OpenSDA Serial and Debug Adapter: https://www.nxp.com/design/microcontrollers-developer-resources/ides-for-kinetis-mcus/opensda-serial-and-debug-adapter:OPENSDA#FRDM-K64F + +Experimental ENET Driver +======================== + +Current default ethernet driver is eth_mcux, with binding `nxp,kinetis-ethernet`. There is a new +driver with binding `nxp,enet`, which is experimental and undergoing development, but will have +enhanced capability, such as not hardcoding code for only one phy in the driver like eth_mcux. + +To build for this EVK with the new driver, include the experimental overlay to west build with +the option `-DEXTRA_DTC_OVERLAY_FILE=nxp,enet-experimental.overlay`. diff --git a/boards/arm/frdm_k64f/dts/nxp,enet-experimental.overlay b/boards/arm/frdm_k64f/dts/nxp,enet-experimental.overlay new file mode 100644 index 00000000000..9dfc07e9b08 --- /dev/null +++ b/boards/arm/frdm_k64f/dts/nxp,enet-experimental.overlay @@ -0,0 +1,108 @@ +/* + * Copyright 2023 NXP + * + * Experimental ENET binding overlay + */ + +/ { + soc { + /delete-node/ ethernet@400c0000; + + enet: ethernet@400c0000 { + compatible = "nxp,enet"; + reg = <0x400c0000 0x620>; + clocks = <&sim KINETIS_SIM_ENET_CLK 0 0>; + enet_mac: ethernet { + compatible = "nxp,enet-mac"; + interrupts = <83 0>, <84 0>, <85 0>; + interrupt-names = "TX", "RX", "ERR"; + nxp,mdio = <&enet_mdio>; + nxp,ptp-clock = <&enet_ptp_clock>; + phy-connection-type = "rmii"; + status = "disabled"; + }; + enet_mdio: mdio { + compatible = "nxp,enet-mdio"; + status = "disabled"; + #address-cells = <1>; + #size-cells = <0>; + }; + enet_ptp_clock: ptp_clock { + compatible = "nxp,enet-ptp-clock"; + interrupts = <82 0>; + interrupt-names = "IEEE1588_TMR"; + status = "disabled"; + }; + }; + }; +}; + +&enet_mac { + status = "okay"; + pinctrl-0 = <&pinmux_enet>; + pinctrl-names = "default"; + phy-handle = <&phy>; +}; + + +&enet_mdio { + status = "okay"; + pinctrl-0 = <&pinmux_enet_mdio>; + pinctrl-names = "default"; + phy: phy@0 { + compatible = "microchip,ksz8081"; + reg = <0>; + status = "okay"; + mc,interface-type = "rmii-25MHz"; + }; +}; + +&enet_ptp_clock { + status = "okay"; + pinctrl-0 = <&pinmux_ptp>; + pinctrl-names = "default"; +}; + +&pinctrl { + /delete-node/ ptp_default; + /delete-node/ enet_default; + + pinmux_enet: pinmux_enet { + group1 { + pinmux = , + , + , + , + , + , + ; + drive-strength = "low"; + slew-rate = "fast"; + }; + }; + + pinmux_enet_mdio: pinmux_enet_mdio { + group0 { + pinmux = ; + drive-strength = "low"; + drive-open-drain; + bias-pull-up; + slew-rate = "fast"; + }; + group1 { + pinmux = ; + drive-strength = "low"; + slew-rate = "fast"; + }; + }; + + pinmux_ptp: pinmux_ptp { + group0 { + pinmux = , + , + ; + drive-strength = "low"; + slew-rate = "fast"; + }; + }; +}; diff --git a/boards/arm/mimxrt1160_evk/doc/index.rst b/boards/arm/mimxrt1160_evk/doc/index.rst index d3ee99ad731..2449429a891 100644 --- a/boards/arm/mimxrt1160_evk/doc/index.rst +++ b/boards/arm/mimxrt1160_evk/doc/index.rst @@ -354,3 +354,13 @@ should see the following message in the terminal: .. _AN13264: https://www.nxp.com/docs/en/application-note/AN13264.pdf + +Experimental ENET Driver +======================== + +Current default ethernet driver is eth_mcux, with binding `nxp,kinetis-ethernet`. There is a new +driver with binding `nxp,enet`, which is experimental and undergoing development, but will have +enhanced capability, such as not hardcoding code for only one phy in the driver like eth_mcux. + +To build for this EVK with the new driver, include the experimental overlay to west build with +the option `-DEXTRA_DTC_OVERLAY_FILE=nxp,enet-experimental.overlay`. diff --git a/boards/arm/mimxrt1160_evk/dts/nxp,enet-experimental.overlay b/boards/arm/mimxrt1160_evk/dts/nxp,enet-experimental.overlay new file mode 100644 index 00000000000..58b8a801622 --- /dev/null +++ b/boards/arm/mimxrt1160_evk/dts/nxp,enet-experimental.overlay @@ -0,0 +1,123 @@ +/* + * Copyright 2023 NXP + * + * Experimental ENET binding overlay + */ + + +/ { + soc { + /delete-node/ ethernet@40424000; + + enet: ethernet@40424000 { + compatible = "nxp,enet"; + reg = <0x40424000 0x628>; + clocks = <&ccm IMX_CCM_ENET_CLK 0 0>; + enet_mac: ethernet { + compatible = "nxp,enet-mac"; + interrupts = <137 0>; + interrupt-names = "COMMON"; + nxp,mdio = <&enet_mdio>; + nxp,ptp-clock = <&enet_ptp_clock>; + status = "disabled"; + }; + enet_mdio: mdio { + compatible = "nxp,enet-mdio"; + status = "disabled"; + #address-cells = <1>; + #size-cells = <0>; + }; + enet_ptp_clock: ptp_clock { + compatible = "nxp,enet-ptp-clock"; + interrupts = <138 0>; + status = "disabled"; + clocks = <&ccm IMX_CCM_ENET_PLL 0 0>; + }; + }; + }; +}; + +&enet_mac { + status = "okay"; + pinctrl-0 = <&pinmux_enet>; + pinctrl-names = "default"; + phy-handle = <&phy>; + phy-connection-type = "rmii"; +}; + +&enet_mdio { + status = "okay"; + pinctrl-0 = <&pinmux_enet_mdio>; + pinctrl-names = "default"; + phy: phy@0 { + compatible = "microchip,ksz8081"; + reg = <0>; + status = "okay"; + mc,reset-gpio = <&gpio12 12 GPIO_ACTIVE_HIGH>; + mc,interrupt-gpio = <&gpio9 11 GPIO_ACTIVE_HIGH>; + mc,interface-type = "rmii"; + }; +}; + +&enet_ptp_clock { + status = "okay"; + pinctrl-0 = <&pinmux_ptp>; + pinctrl-names = "default"; +}; + + + +&pinctrl { + /delete-node/ pinmux_ptp; + /delete-node/ pinmux_enet; + + pinmux_enet: pinmux_enet { + group0 { + pinmux = <&iomuxc_gpio_ad_12_gpio9_io11>, + <&iomuxc_gpio_disp_b2_08_enet_rx_en>, + <&iomuxc_gpio_disp_b2_09_enet_rx_er>; + drive-strength = "high"; + bias-pull-down; + slew-rate = "fast"; + }; + group1 { + pinmux = <&iomuxc_gpio_disp_b2_06_enet_rdata00>, + <&iomuxc_gpio_disp_b2_07_enet_rdata01>; + drive-strength = "high"; + bias-pull-down; + slew-rate = "fast"; + input-enable; + }; + group2 { + pinmux = <&iomuxc_lpsr_gpio_lpsr_12_gpio12_io12>; + drive-strength = "high"; + bias-pull-up; + slew-rate = "fast"; + }; + group3 { + pinmux = <&iomuxc_gpio_disp_b2_02_enet_tdata00>, + <&iomuxc_gpio_disp_b2_03_enet_tdata01>, + <&iomuxc_gpio_disp_b2_04_enet_tx_en>; + drive-strength = "high"; + slew-rate = "fast"; + }; + group4 { + pinmux = <&iomuxc_gpio_disp_b2_05_enet_ref_clk>; + drive-strength = "high"; + slew-rate = "slow"; + input-enable; + }; + }; + + pinmux_enet_mdio: pinmux_enet_mdio { + group0 { + pinmux = <&iomuxc_gpio_ad_32_enet_mdc>, + <&iomuxc_gpio_ad_33_enet_mdio>; + drive-strength = "high"; + slew-rate = "fast"; + }; + }; + + pinmux_ptp: pinmux_ptp { + }; +}; diff --git a/boards/arm/mimxrt1170_evk/doc/index.rst b/boards/arm/mimxrt1170_evk/doc/index.rst index 15a66875d31..faff1975ca8 100644 --- a/boards/arm/mimxrt1170_evk/doc/index.rst +++ b/boards/arm/mimxrt1170_evk/doc/index.rst @@ -442,3 +442,13 @@ should see the following message in the terminal: .. _NXP MCUXpresso for Visual Studio Code: https://www.nxp.com/design/software/development-software/mcuxpresso-software-and-tools-/mcuxpresso-for-visual-studio-code:MCUXPRESSO-VSC + +Experimental ENET Driver +======================== + +Current default ethernet driver is eth_mcux, with binding `nxp,kinetis-ethernet`. There is a new +driver with binding `nxp,enet`, which is experimental and undergoing development, but will have +enhanced capability, such as not hardcoding code for only one phy in the driver like eth_mcux. + +To build for this EVK with the new driver, include the experimental overlay to west build with +the option `-DEXTRA_DTC_OVERLAY_FILE=nxp,enet-experimental.overlay`. diff --git a/boards/arm/mimxrt1170_evk/dts/nxp,enet-experimental.overlay b/boards/arm/mimxrt1170_evk/dts/nxp,enet-experimental.overlay new file mode 100644 index 00000000000..58b8a801622 --- /dev/null +++ b/boards/arm/mimxrt1170_evk/dts/nxp,enet-experimental.overlay @@ -0,0 +1,123 @@ +/* + * Copyright 2023 NXP + * + * Experimental ENET binding overlay + */ + + +/ { + soc { + /delete-node/ ethernet@40424000; + + enet: ethernet@40424000 { + compatible = "nxp,enet"; + reg = <0x40424000 0x628>; + clocks = <&ccm IMX_CCM_ENET_CLK 0 0>; + enet_mac: ethernet { + compatible = "nxp,enet-mac"; + interrupts = <137 0>; + interrupt-names = "COMMON"; + nxp,mdio = <&enet_mdio>; + nxp,ptp-clock = <&enet_ptp_clock>; + status = "disabled"; + }; + enet_mdio: mdio { + compatible = "nxp,enet-mdio"; + status = "disabled"; + #address-cells = <1>; + #size-cells = <0>; + }; + enet_ptp_clock: ptp_clock { + compatible = "nxp,enet-ptp-clock"; + interrupts = <138 0>; + status = "disabled"; + clocks = <&ccm IMX_CCM_ENET_PLL 0 0>; + }; + }; + }; +}; + +&enet_mac { + status = "okay"; + pinctrl-0 = <&pinmux_enet>; + pinctrl-names = "default"; + phy-handle = <&phy>; + phy-connection-type = "rmii"; +}; + +&enet_mdio { + status = "okay"; + pinctrl-0 = <&pinmux_enet_mdio>; + pinctrl-names = "default"; + phy: phy@0 { + compatible = "microchip,ksz8081"; + reg = <0>; + status = "okay"; + mc,reset-gpio = <&gpio12 12 GPIO_ACTIVE_HIGH>; + mc,interrupt-gpio = <&gpio9 11 GPIO_ACTIVE_HIGH>; + mc,interface-type = "rmii"; + }; +}; + +&enet_ptp_clock { + status = "okay"; + pinctrl-0 = <&pinmux_ptp>; + pinctrl-names = "default"; +}; + + + +&pinctrl { + /delete-node/ pinmux_ptp; + /delete-node/ pinmux_enet; + + pinmux_enet: pinmux_enet { + group0 { + pinmux = <&iomuxc_gpio_ad_12_gpio9_io11>, + <&iomuxc_gpio_disp_b2_08_enet_rx_en>, + <&iomuxc_gpio_disp_b2_09_enet_rx_er>; + drive-strength = "high"; + bias-pull-down; + slew-rate = "fast"; + }; + group1 { + pinmux = <&iomuxc_gpio_disp_b2_06_enet_rdata00>, + <&iomuxc_gpio_disp_b2_07_enet_rdata01>; + drive-strength = "high"; + bias-pull-down; + slew-rate = "fast"; + input-enable; + }; + group2 { + pinmux = <&iomuxc_lpsr_gpio_lpsr_12_gpio12_io12>; + drive-strength = "high"; + bias-pull-up; + slew-rate = "fast"; + }; + group3 { + pinmux = <&iomuxc_gpio_disp_b2_02_enet_tdata00>, + <&iomuxc_gpio_disp_b2_03_enet_tdata01>, + <&iomuxc_gpio_disp_b2_04_enet_tx_en>; + drive-strength = "high"; + slew-rate = "fast"; + }; + group4 { + pinmux = <&iomuxc_gpio_disp_b2_05_enet_ref_clk>; + drive-strength = "high"; + slew-rate = "slow"; + input-enable; + }; + }; + + pinmux_enet_mdio: pinmux_enet_mdio { + group0 { + pinmux = <&iomuxc_gpio_ad_32_enet_mdc>, + <&iomuxc_gpio_ad_33_enet_mdio>; + drive-strength = "high"; + slew-rate = "fast"; + }; + }; + + pinmux_ptp: pinmux_ptp { + }; +}; From 247f9e61ef193e4388dc02469fc201e45f0661a0 Mon Sep 17 00:00:00 2001 From: Declan Snyder Date: Mon, 4 Dec 2023 09:24:30 -0600 Subject: [PATCH 0969/3723] samples: zperf: Add NXP driver test case Test the experimental NXP ENET driver Signed-off-by: Declan Snyder --- samples/net/zperf/sample.yaml | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/samples/net/zperf/sample.yaml b/samples/net/zperf/sample.yaml index 201940c23a9..99b8f50d31a 100644 --- a/samples/net/zperf/sample.yaml +++ b/samples/net/zperf/sample.yaml @@ -80,3 +80,16 @@ tests: depends_on: - arduino_spi - arduino_gpio + sample.net.zperf.nxp_enet_experimental: + extra_args: EXTRA_DTC_OVERLAY_FILE="nxp,enet-experimental.overlay" + tags: + - net + - zperf + platform_allow: + - mimxrt1050_evk + - mimxrt1060_evk + - mimxrt1064_evk + - mimxrt1024_evk + - frdm_k64f + - mimxrt1170_evk_cm7 + - mimxrt1160_evk_cm7 From 79b00f6cd3988ae710a56e7ba898e7b8d6db7826 Mon Sep 17 00:00:00 2001 From: Declan Snyder Date: Thu, 7 Dec 2023 12:00:18 -0600 Subject: [PATCH 0970/3723] drivers: nxp_enet: Add link state logging message Add info logging message to NXP ENET MAC driver about link state. Signed-off-by: Declan Snyder --- drivers/ethernet/eth_nxp_enet.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/drivers/ethernet/eth_nxp_enet.c b/drivers/ethernet/eth_nxp_enet.c index 9c18b2d129a..293143fd1a1 100644 --- a/drivers/ethernet/eth_nxp_enet.c +++ b/drivers/ethernet/eth_nxp_enet.c @@ -598,6 +598,8 @@ static void nxp_enet_phy_cb(const struct device *phy, } else { net_eth_carrier_on(data->iface); } + + LOG_INF("Link is %s", state->is_up ? "up" : "down"); } From 352980be98eb1b5cd3613057e09615af15c5ec77 Mon Sep 17 00:00:00 2001 From: Marc Herbert Date: Fri, 1 Dec 2023 06:55:52 +0000 Subject: [PATCH 0971/3723] scripts/build: make struct_tags.json deterministic It's not good to see struct_tags.json change from one build to the next when nothing changes. Python's sets are not deterministic, see long story for older commit f896fc2306a0 ("scripts: gen_handles: Sort the device handles") Simply convert multiple_directories to a sorted list before using it. Fixes commit 80e78208e6cd ("kernel: syscalls: no need to include all syscalls in binary") Signed-off-by: Marc Herbert --- scripts/build/parse_syscalls.py | 3 +++ 1 file changed, 3 insertions(+) diff --git a/scripts/build/parse_syscalls.py b/scripts/build/parse_syscalls.py index 636404950db..ebdb9bb73ab 100644 --- a/scripts/build/parse_syscalls.py +++ b/scripts/build/parse_syscalls.py @@ -84,6 +84,9 @@ def analyze_headers(include_dir, scan_dir, file_list): if scan_dir: multiple_directories |= set(scan_dir) + # Convert to a list to keep the output deterministic + multiple_directories = sorted(multiple_directories) + # Look for source files under various directories. # Due to "syscalls/*.h" being included unconditionally in various # other header files. We must generate the associated syscall From f390f7d0a1942d4794c030d0c6058c1ed000ac23 Mon Sep 17 00:00:00 2001 From: Joakim Andersson Date: Fri, 1 Dec 2023 18:33:02 +0100 Subject: [PATCH 0972/3723] bluetooth: shell: Use helper function to convert string to int Use helper function to convert string to int for appearance value. This makes the code more clear, as the big-endian conversion function gives the wrong impression about the byte order of advertising data. Signed-off-by: Joakim Andersson --- subsys/bluetooth/shell/bt.c | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/subsys/bluetooth/shell/bt.c b/subsys/bluetooth/shell/bt.c index 774ab6fc291..c2a0b8c9795 100644 --- a/subsys/bluetooth/shell/bt.c +++ b/subsys/bluetooth/shell/bt.c @@ -1196,17 +1196,21 @@ static int cmd_appearance(const struct shell *sh, size_t argc, char *argv[]) #if defined(CONFIG_BT_DEVICE_APPEARANCE_DYNAMIC) uint16_t app; - int err; + int err = 0; const char *val; val = argv[1]; - if (strlen(val) != 6 || strncmp(val, "0x", 2) || - !hex2bin(&val[2], strlen(&val[2]), ((uint8_t *)&app), sizeof(app))) { + + if (strlen(val) != 6 || strncmp(val, "0x", 2)) { shell_error(sh, "Argument must be 0x followed by exactly 4 hex digits."); return -EINVAL; } - app = sys_be16_to_cpu(app); + app = shell_strtoul(val, 16, &err); + if (err) { + shell_error(sh, "Argument must be 0x followed by exactly 4 hex digits."); + return -EINVAL; + } err = bt_set_appearance(app); if (err) { From 41c2c3d4b8030bedc126f0eda877b47a6927ab28 Mon Sep 17 00:00:00 2001 From: Mahesh Mahadevan Date: Fri, 1 Dec 2023 22:17:37 +0000 Subject: [PATCH 0973/3723] drivers: dma_mcux_lpc: Clear out the dma channel structure The DMA channel data structure can retain config information. We need to clear this everytime dma_configure is called on a channel. Signed-off-by: Mahesh Mahadevan --- drivers/dma/dma_mcux_lpc.c | 15 ++++++++++++--- 1 file changed, 12 insertions(+), 3 deletions(-) diff --git a/drivers/dma/dma_mcux_lpc.c b/drivers/dma/dma_mcux_lpc.c index 9aa1eae9c61..0a34efb9dca 100644 --- a/drivers/dma/dma_mcux_lpc.c +++ b/drivers/dma/dma_mcux_lpc.c @@ -259,6 +259,15 @@ static int dma_mcux_lpc_queue_descriptors(struct channel_data *data, return 0; } +static void dma_mcux_lpc_clear_channel_data(struct channel_data *data) +{ + data->dma_callback = NULL; + data->dir = 0; + data->descriptors_queued = false; + data->num_of_descriptors = 0; + data->curr_descriptor = NULL; + data->width = 0; +} /* Configure a channel */ static int dma_mcux_lpc_configure(const struct device *dev, uint32_t channel, @@ -376,6 +385,8 @@ static int dma_mcux_lpc_configure(const struct device *dev, uint32_t channel, data = DEV_CHANNEL_DATA(dev, virtual_channel); } + dma_mcux_lpc_clear_channel_data(data); + data->dir = config->channel_direction; if (data->busy) { @@ -386,10 +397,8 @@ static int dma_mcux_lpc_configure(const struct device *dev, uint32_t channel, k_spinlock_key_t otrigs_key = k_spin_lock(&configuring_otrigs); - data->descriptors_queued = false; - data->num_of_descriptors = 0; data->width = width; - data->curr_descriptor = NULL; + if (config->source_chaining_en || config->dest_chaining_en) { /* Chaining is enabled */ if (!dev_config->otrig_base_address || !dev_config->itrig_base_address) { From 7ddc0f713f9e7e0f19066d1bc838e6e98edd2fff Mon Sep 17 00:00:00 2001 From: Henrik Brix Andersen Date: Mon, 4 Dec 2023 11:25:45 +0100 Subject: [PATCH 0974/3723] drivers: spi: mcux: lpspi: fix error on first configure on MKE1xF Fix error writing to the CR register on the first call to SPI configure on NXP MKE1xF. On the first call, the module clock is not enabled and writing to the CR register will fail. Fixes: #66036 Signed-off-by: Henrik Brix Andersen --- drivers/spi/spi_mcux_lpspi.c | 17 +++++++++++------ 1 file changed, 11 insertions(+), 6 deletions(-) diff --git a/drivers/spi/spi_mcux_lpspi.c b/drivers/spi/spi_mcux_lpspi.c index 16d840992cc..9bda7a98c9b 100644 --- a/drivers/spi/spi_mcux_lpspi.c +++ b/drivers/spi/spi_mcux_lpspi.c @@ -249,13 +249,18 @@ static int spi_mcux_configure(const struct device *dev, return -EINVAL; } - /* Setting the baud rate in LPSPI_MasterInit requires module to be disabled */ - LPSPI_Enable(base, false); - while ((base->CR & LPSPI_CR_MEN_MASK) != 0U) { - /* Wait until LPSPI is disabled. Datasheet: - * After writing 0, MEN (Module Enable) remains set until the LPSPI has completed - * the current transfer and is idle. + if (data->ctx.config != NULL) { + /* Setting the baud rate in LPSPI_MasterInit requires module to be disabled. Only + * disable if already configured, otherwise the clock is not enabled and the + * CR register cannot be written. */ + LPSPI_Enable(base, false); + while ((base->CR & LPSPI_CR_MEN_MASK) != 0U) { + /* Wait until LPSPI is disabled. Datasheet: + * After writing 0, MEN (Module Enable) remains set until the LPSPI has + * completed the current transfer and is idle. + */ + } } LPSPI_MasterInit(base, &master_config, clock_freq); From 01bd94ac4ffcd66ab15b16b07a0d5e0d55f8720b Mon Sep 17 00:00:00 2001 From: Emil Gydesen Date: Mon, 4 Dec 2023 11:22:06 +0100 Subject: [PATCH 0975/3723] Bluetooth: Shell: Remove tolower from is_substring The tolower is not necessary and is what strncasecmp does anyhow. Signed-off-by: Emil Gydesen --- subsys/bluetooth/shell/bt.c | 12 +++++------- 1 file changed, 5 insertions(+), 7 deletions(-) diff --git a/subsys/bluetooth/shell/bt.c b/subsys/bluetooth/shell/bt.c index c2a0b8c9795..7cba031f6d9 100644 --- a/subsys/bluetooth/shell/bt.c +++ b/subsys/bluetooth/shell/bt.c @@ -234,14 +234,12 @@ static bool is_substring(const char *substr, const char *str) } for (size_t pos = 0; pos < str_len; pos++) { - if (tolower(substr[pos]) == tolower(str[pos])) { - if (pos + sub_str_len > str_len) { - return false; - } + if (pos + sub_str_len > str_len) { + return false; + } - if (strncasecmp(substr, &str[pos], sub_str_len) == 0) { - return true; - } + if (strncasecmp(substr, &str[pos], sub_str_len) == 0) { + return true; } } From e54902bdbee9889117f90b69e16fea2815ce8bdf Mon Sep 17 00:00:00 2001 From: Emil Gydesen Date: Mon, 4 Dec 2023 13:07:36 +0100 Subject: [PATCH 0976/3723] Samples: Bluetooth: Fix bug in is_substring for broadcast sink The is_substring did not work for true substrings, as it would always compare [0] to [0], so it would return false for the substring "BC" being in "ABC". Removed the tolower as it is not necessary and fixes the issue. Signed-off-by: Emil Gydesen --- samples/bluetooth/broadcast_audio_sink/src/main.c | 12 +++++------- 1 file changed, 5 insertions(+), 7 deletions(-) diff --git a/samples/bluetooth/broadcast_audio_sink/src/main.c b/samples/bluetooth/broadcast_audio_sink/src/main.c index c9199f80673..587cb59dc51 100644 --- a/samples/bluetooth/broadcast_audio_sink/src/main.c +++ b/samples/bluetooth/broadcast_audio_sink/src/main.c @@ -618,14 +618,12 @@ static bool is_substring(const char *substr, const char *str) } for (size_t pos = 0; pos < str_len; pos++) { - if (tolower(substr[pos]) == tolower(str[pos])) { - if (pos + sub_str_len > str_len) { - return false; - } + if (pos + sub_str_len > str_len) { + return false; + } - if (strncasecmp(substr, &str[pos], sub_str_len) == 0) { - return true; - } + if (strncasecmp(substr, &str[pos], sub_str_len) == 0) { + return true; } } From 6158ff03f53dd2cf56edc1a46e8b94cf3124f80b Mon Sep 17 00:00:00 2001 From: Emil Gydesen Date: Mon, 4 Dec 2023 13:30:31 +0100 Subject: [PATCH 0977/3723] Bluetooth: Shell: Only auto-connect to unconnected devices The bt connect and bt connect-name commands should only attempt to connect to connectable devices that we are not already connected to. This commit moves the check for BT_GAP_ADV_PROP_CONNECTABLE as well as checks that we do not already have a connection to that device with the current ID. Signed-off-by: Emil Gydesen --- subsys/bluetooth/shell/bt.c | 31 ++++++++++++++++++++----------- 1 file changed, 20 insertions(+), 11 deletions(-) diff --git a/subsys/bluetooth/shell/bt.c b/subsys/bluetooth/shell/bt.c index 7cba031f6d9..1d4c61a84f7 100644 --- a/subsys/bluetooth/shell/bt.c +++ b/subsys/bluetooth/shell/bt.c @@ -493,22 +493,31 @@ static void scan_recv(const struct bt_le_scan_recv_info *info, struct net_buf_si shell_info(ctx_shell, "%*s[SCAN DATA END]", strlen(scan_response_label), ""); } - /* Store address for later use */ #if defined(CONFIG_BT_CENTRAL) - auto_connect.addr_set = true; - bt_addr_le_copy(&auto_connect.addr, info->addr); + if ((info->adv_props & BT_GAP_ADV_PROP_CONNECTABLE) != 0U) { + struct bt_conn *conn = bt_conn_lookup_addr_le(selected_id, info->addr); - /* Use the above auto_connect.addr address to automatically connect */ - if ((info->adv_props & BT_GAP_ADV_PROP_CONNECTABLE) != 0U && auto_connect.connect_name) { - auto_connect.connect_name = false; + /* Only store auto-connect address for devices we are not already connected to */ + if (conn == NULL) { + /* Store address for later use */ + auto_connect.addr_set = true; + bt_addr_le_copy(&auto_connect.addr, info->addr); - cmd_scan_off(ctx_shell); + /* Use the above auto_connect.addr address to automatically connect */ + if (auto_connect.connect_name) { + auto_connect.connect_name = false; - /* "name" is what would be in argv[0] normally */ - cmd_scan_filter_clear_name(ctx_shell, 1, (char *[]){ "name" }); + cmd_scan_off(ctx_shell); + + /* "name" is what would be in argv[0] normally */ + cmd_scan_filter_clear_name(ctx_shell, 1, (char *[]){"name"}); - /* "connect" is what would be in argv[0] normally */ - cmd_connect_le(ctx_shell, 1, (char *[]){ "connect" }); + /* "connect" is what would be in argv[0] normally */ + cmd_connect_le(ctx_shell, 1, (char *[]){"connect"}); + } + } else { + bt_conn_unref(conn); + } } #endif /* CONFIG_BT_CENTRAL */ } From a42fb9d5861e4035b708930414c7bcceae69a965 Mon Sep 17 00:00:00 2001 From: Mariusz Skamra Date: Mon, 4 Dec 2023 17:20:22 +0100 Subject: [PATCH 0978/3723] tests: bsim: gatt: Fix missing connection reference release This fixes missing connection reference release. The bt_conn_le_create returns the connection object reference that needs to be released by API caller. Signed-off-by: Mariusz Skamra --- .../bluetooth/host/gatt/settings/src/utils.c | 36 +++++++++++-------- 1 file changed, 22 insertions(+), 14 deletions(-) diff --git a/tests/bsim/bluetooth/host/gatt/settings/src/utils.c b/tests/bsim/bluetooth/host/gatt/settings/src/utils.c index 64dc5c8ede0..b1b9262e235 100644 --- a/tests/bsim/bluetooth/host/gatt/settings/src/utils.c +++ b/tests/bsim/bluetooth/host/gatt/settings/src/utils.c @@ -9,6 +9,8 @@ #include #include +static struct bt_conn *default_conn; + DEFINE_FLAG(flag_is_connected); DEFINE_FLAG(flag_test_end); @@ -29,18 +31,34 @@ void wait_disconnected(void) static void disconnected(struct bt_conn *conn, uint8_t reason) { - bt_conn_unref(conn); + __ASSERT_NO_MSG(default_conn == conn); + + bt_conn_unref(default_conn); + default_conn = NULL; + UNSET_FLAG(flag_is_connected); gatt_clear_flags(); } static void connected(struct bt_conn *conn, uint8_t err) { + struct bt_conn_info info = { 0 }; + int ret; + if (err != 0) { return; } - bt_conn_ref(conn); + ret = bt_conn_get_info(conn, &info); + __ASSERT_NO_MSG(ret == 0); + + if (info.role == BT_CONN_ROLE_PERIPHERAL) { + __ASSERT_NO_MSG(default_conn == NULL); + default_conn = bt_conn_ref(conn); + } + + __ASSERT_NO_MSG(default_conn != NULL); + SET_FLAG(flag_is_connected); } @@ -64,7 +82,6 @@ BT_CONN_CB_DEFINE(conn_callbacks) = { static void scan_connect_to_first_result_device_found(const bt_addr_le_t *addr, int8_t rssi, uint8_t type, struct net_buf_simple *ad) { - struct bt_conn *conn; char addr_str[BT_ADDR_LE_STR_LEN]; int err; @@ -82,7 +99,7 @@ static void scan_connect_to_first_result_device_found(const bt_addr_le_t *addr, err = bt_conn_le_create(addr, BT_CONN_LE_CREATE_CONN, BT_LE_CONN_PARAM_DEFAULT, - &conn); + &default_conn); __ASSERT(!err, "Err bt_conn_le_create %d", err); } @@ -122,18 +139,9 @@ void disconnect(struct bt_conn *conn) WAIT_FOR_FLAG_UNSET(flag_is_connected); } -static void get_active_conn_cb(struct bt_conn *src, void *dst) -{ - *(struct bt_conn **)dst = src; -} - struct bt_conn *get_conn(void) { - struct bt_conn *ret; - - bt_conn_foreach(BT_CONN_TYPE_LE, get_active_conn_cb, &ret); - - return ret; + return default_conn; } DEFINE_FLAG(flag_pairing_complete); From 923ac2bb1b673bb953bb8f5d663da1c201038481 Mon Sep 17 00:00:00 2001 From: Andrej Butok Date: Tue, 5 Dec 2023 16:16:41 +0100 Subject: [PATCH 0979/3723] doc: mimxrt1040_evk: fix documentation links Fix mimxrt1040_evk documentation links. Signed-off-by: Andrej Butok --- boards/arm/mimxrt1040_evk/doc/index.rst | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/boards/arm/mimxrt1040_evk/doc/index.rst b/boards/arm/mimxrt1040_evk/doc/index.rst index a17a87fe632..651a0aebff9 100644 --- a/boards/arm/mimxrt1040_evk/doc/index.rst +++ b/boards/arm/mimxrt1040_evk/doc/index.rst @@ -354,7 +354,7 @@ flashing or debugging it, or remove jumper J80. https://www.nxp.com/design/development-boards/i-mx-evaluation-and-development-boards/i-mx-rt1040-evaluation-kit:MIMXRT1040-EVK .. _MIMXRT1040-EVK User Guide: - https://www.nxp.com/docs/en/user-manual/MIMXRT1040-EVKUM.pdf + https://www.nxp.com/webapp/Download?colCode=MIMXRT1040-EVKUM .. _MIMXRT1040-EVK Design Files: https://www.nxp.com/webapp/Download?colCode=MIMXRT1040-EVK-DESIGNFILES @@ -363,7 +363,7 @@ flashing or debugging it, or remove jumper J80. https://www.nxp.com/products/processors-and-microcontrollers/arm-microcontrollers/i-mx-rt-crossover-mcus/i-mx-rt1040-crossover-mcu-with-arm-cortex-m7-core:i.MX-RT1040 .. _i.MX RT1040 Datasheet: - https://www.nxp.com/docs/en/data-sheet/IMXRT1040CECDS.pdf + https://www.nxp.com/docs/en/data-sheet/IMXRT1040CEC.pdf .. _i.MX RT1040 Reference Manual: https://www.nxp.com/webapp/Download?colCode=IMXRT1040RM From 3b24ef305fa29b41af18e0d3e99a07933c13833f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sebastian=20B=C3=B8e?= Date: Wed, 6 Dec 2023 13:01:36 +0100 Subject: [PATCH 0980/3723] tz: Remove unused trustzone driver MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The arm_core_tz.c trustzone driver was developed by Nordic and was previously used by Nordic, but it is not used by us any more. Since we stopped using it I can see that it has bit rotted (the include path for tz.h is not available), so no else has started using it either evidently. Remove the broken and dead code. We keep the HAS_ARM_SAU Kconfig as it is selected by a myriad of platforms and determines if __SAUREGION_PRESENT is defined. I have been unable to prove that this define is also unused. Signed-off-by: Sebastian Bøe --- arch/arm/core/cortex_m/tz/CMakeLists.txt | 6 - arch/arm/core/cortex_m/tz/arm_core_tz.c | 166 ----------- arch/arm/include/cortex_m/tz.h | 338 ----------------------- 3 files changed, 510 deletions(-) delete mode 100644 arch/arm/core/cortex_m/tz/arm_core_tz.c delete mode 100644 arch/arm/include/cortex_m/tz.h diff --git a/arch/arm/core/cortex_m/tz/CMakeLists.txt b/arch/arm/core/cortex_m/tz/CMakeLists.txt index 67f7e0ab367..19c67476e40 100644 --- a/arch/arm/core/cortex_m/tz/CMakeLists.txt +++ b/arch/arm/core/cortex_m/tz/CMakeLists.txt @@ -33,9 +33,3 @@ endif() zephyr_link_libraries_ifdef(CONFIG_ARM_FIRMWARE_USES_SECURE_ENTRY_FUNCS ${CMAKE_BINARY_DIR}/${CONFIG_ARM_ENTRY_VENEERS_LIB_NAME} ) - -if(CONFIG_ARM_SECURE_FIRMWARE) - zephyr_library() - - zephyr_library_sources(arm_core_tz.c) -endif() diff --git a/arch/arm/core/cortex_m/tz/arm_core_tz.c b/arch/arm/core/cortex_m/tz/arm_core_tz.c deleted file mode 100644 index 8371a08bfef..00000000000 --- a/arch/arm/core/cortex_m/tz/arm_core_tz.c +++ /dev/null @@ -1,166 +0,0 @@ -/* - * Copyright (c) 2018 Nordic Semiconductor ASA. - * - * SPDX-License-Identifier: Apache-2.0 - */ - -#include -#include -#include - -static void configure_nonsecure_vtor_offset(uint32_t vtor_ns) -{ - SCB_NS->VTOR = vtor_ns; -} - -static void configure_nonsecure_msp(uint32_t msp_ns) -{ - __TZ_set_MSP_NS(msp_ns); -} - -static void configure_nonsecure_psp(uint32_t psp_ns) -{ - __TZ_set_PSP_NS(psp_ns); -} - -static void configure_nonsecure_control(uint32_t spsel_ns, uint32_t npriv_ns) -{ - uint32_t control_ns = __TZ_get_CONTROL_NS(); - - /* Only nPRIV and SPSEL bits are banked between security states. */ - control_ns &= ~(CONTROL_SPSEL_Msk | CONTROL_nPRIV_Msk); - - if (spsel_ns) { - control_ns |= CONTROL_SPSEL_Msk; - } - if (npriv_ns) { - control_ns |= CONTROL_nPRIV_Msk; - } - - __TZ_set_CONTROL_NS(control_ns); -} - -#if defined(CONFIG_ARMV8_M_MAINLINE) - -/* Only ARMv8-M Mainline implementations have Non-Secure instances of - * Stack Pointer Limit registers. - */ - -void tz_nonsecure_msplim_set(uint32_t val) -{ - __TZ_set_MSPLIM_NS(val); -} - -void tz_nonsecure_psplim_set(uint32_t val) -{ - __TZ_set_PSPLIM_NS(val); -} -#endif /* CONFIG_ARMV8_M_MAINLINE */ - -void tz_nonsecure_state_setup(const tz_nonsecure_setup_conf_t *p_ns_conf) -{ - configure_nonsecure_vtor_offset(p_ns_conf->vtor_ns); - configure_nonsecure_msp(p_ns_conf->msp_ns); - configure_nonsecure_psp(p_ns_conf->psp_ns); - /* Select which stack-pointer to use (MSP or PSP) and - * the privilege level for thread mode. - */ - configure_nonsecure_control(p_ns_conf->control_ns.spsel, - p_ns_conf->control_ns.npriv); -} - -void tz_nbanked_exception_target_state_set(int secure_state) -{ - uint32_t aircr_payload = SCB->AIRCR & (~(SCB_AIRCR_VECTKEY_Msk)); - if (secure_state) { - aircr_payload &= ~(SCB_AIRCR_BFHFNMINS_Msk); - } else { - aircr_payload |= SCB_AIRCR_BFHFNMINS_Msk; - } - SCB->AIRCR = ((AIRCR_VECT_KEY_PERMIT_WRITE << SCB_AIRCR_VECTKEY_Pos) - & SCB_AIRCR_VECTKEY_Msk) - | aircr_payload; -} - -void tz_nonsecure_exception_prio_config(int secure_boost) -{ - uint32_t aircr_payload = SCB->AIRCR & (~(SCB_AIRCR_VECTKEY_Msk)); - if (secure_boost) { - aircr_payload |= SCB_AIRCR_PRIS_Msk; - } else { - aircr_payload &= ~(SCB_AIRCR_PRIS_Msk); - } - SCB->AIRCR = ((AIRCR_VECT_KEY_PERMIT_WRITE << SCB_AIRCR_VECTKEY_Pos) - & SCB_AIRCR_VECTKEY_Msk) - | aircr_payload; -} - -void tz_nonsecure_system_reset_req_block(int block) -{ - uint32_t aircr_payload = SCB->AIRCR & (~(SCB_AIRCR_VECTKEY_Msk)); - if (block) { - aircr_payload |= SCB_AIRCR_SYSRESETREQS_Msk; - } else { - aircr_payload &= ~(SCB_AIRCR_SYSRESETREQS_Msk); - } - SCB->AIRCR = ((0x5FAUL << SCB_AIRCR_VECTKEY_Pos) - & SCB_AIRCR_VECTKEY_Msk) - | aircr_payload; -} - -#if defined(CONFIG_ARMV7_M_ARMV8_M_FP) -void tz_nonsecure_fpu_access_enable(void) -{ - SCB->NSACR |= - (1UL << SCB_NSACR_CP10_Pos) | (1UL << SCB_NSACR_CP11_Pos); -} -#endif /* CONFIG_ARMV7_M_ARMV8_M_FP */ - -void tz_sau_configure(int enable, int allns) -{ - if (enable) { - TZ_SAU_Enable(); - } else { - TZ_SAU_Disable(); - if (allns) { - SAU->CTRL |= SAU_CTRL_ALLNS_Msk; - } else { - SAU->CTRL &= ~(SAU_CTRL_ALLNS_Msk); - } - } -} - -uint32_t tz_sau_number_of_regions_get(void) -{ - return SAU->TYPE & SAU_TYPE_SREGION_Msk; -} - -#if defined(CONFIG_CPU_HAS_ARM_SAU) -#if defined (__SAUREGION_PRESENT) && (__SAUREGION_PRESENT == 1U) -int tz_sau_region_configure_enable(tz_sau_conf_t *p_sau_conf) -{ - uint32_t regions = tz_sau_number_of_regions_get(); - - if ((p_sau_conf->region_num == 0) || - (p_sau_conf->region_num > (regions - 1))) { - return 0; - } - - /* Valid region */ - SAU->RNR = p_sau_conf->region_num & SAU_RNR_REGION_Msk; - - if (p_sau_conf->enable) { - SAU->RLAR = SAU_RLAR_ENABLE_Msk - | (SAU_RLAR_LADDR_Msk & p_sau_conf->limit_addr) - | (p_sau_conf->nsc ? SAU_RLAR_NSC_Msk : 0); - SAU->RBAR = p_sau_conf->base_addr & SAU_RBAR_BADDR_Msk; - } else { - SAU->RLAR &= ~(SAU_RLAR_ENABLE_Msk); - } - - return 1; -} -#else -#error "ARM SAU not implemented" -#endif -#endif /* CONFIG_CPU_HAS_ARM_SAU */ diff --git a/arch/arm/include/cortex_m/tz.h b/arch/arm/include/cortex_m/tz.h deleted file mode 100644 index 0262376469e..00000000000 --- a/arch/arm/include/cortex_m/tz.h +++ /dev/null @@ -1,338 +0,0 @@ -/* - * Copyright (c) 2018 Nordic Semiconductor ASA - * - * SPDX-License-Identifier: Apache-2.0 - */ - -/** - * @file - * @brief TrustZone API - * - * TrustZone API for Cortex-M23/M33 CPUs implementing the Security Extension. - */ - -#ifndef ZEPHYR_ARCH_ARM_INCLUDE_AARCH32_CORTEX_M_TZ_H_ -#define ZEPHYR_ARCH_ARM_INCLUDE_AARCH32_CORTEX_M_TZ_H_ - -#ifdef _ASMLANGUAGE - -/* nothing */ - -#else - -#include -#include - -#ifdef __cplusplus -extern "C" { -#endif - -/** - * - * @brief Initial Non-Secure state configuration - * - * A convenient struct to include all required Non-Secure - * state configuration. - */ -typedef struct tz_nonsecure_setup_conf { - uint32_t msp_ns; - uint32_t psp_ns; - uint32_t vtor_ns; - struct { - uint32_t npriv:1; - uint32_t spsel:1; - uint32_t reserved:30; - } control_ns; -} tz_nonsecure_setup_conf_t; - - -/** - * - * @brief Setup Non-Secure state core registers - * - * Configure the Non-Secure instances of the VTOR, MSP, PSP, - * and CONTROL register. - * - * @param p_ns_conf Pointer to a structure holding the desired configuration. - * - * Notes: - * - * This function shall only be called from Secure state, otherwise the - * Non-Secure instances of the core registers are RAZ/WI. - * - * This function shall be called before the Secure Firmware may transition - * to Non-Secure state. - * - */ -void tz_nonsecure_state_setup(const tz_nonsecure_setup_conf_t *p_ns_conf); - -#if defined(CONFIG_ARMV8_M_MAINLINE) - -/** - * - * @brief Setup Non-Secure Main Stack Pointer limit register - * - * Configure the Non-Secure instance of the MSPLIM register. - * - * @param val value to configure the MSPLIM_NS register with. - * - * Notes: - * - * This function shall only be called from Secure state. - * Only ARMv8-M Mainline implementations have Non-Secure MSPLIM instance. - * - */ -void tz_nonsecure_msplim_set(uint32_t val); - -/** - * - * @brief Setup Non-Secure Process Stack Pointer limit register - * - * Configure the Non-Secure instance of the PSPLIM register. - * - * @param val value to configure the PSPLIM_NS register with. - * - * Notes: - * - * This function shall only be called from Secure state. - * Only ARMv8-M Mainline implementations have Non-Secure PSPLIM instance. - * - */ -void tz_nonsecure_psplim_set(uint32_t val); - -#endif /* CONFIG_ARMV8_M_MAINLINE */ - -/** - * @brief Block or permit Non-Secure System Reset Requests - * - * Function allows the user to configure the system to block or - * permit the Non-Secure domain to issue System Reset Requests. - * - * @param block Flag indicating whether Non-Secure System Reset - * Requests shall be blocked (1), or permitted (0). - * - * Note: - * - * This function shall only be called from Secure state. - */ -void tz_nonsecure_system_reset_req_block(int block); - -/** - * @brief Prioritize Secure exceptions - * - * Function allows the user to prioritize Secure exceptions over Non-Secure, - * enabling Secure exception priority boosting. - * - * @param secure_boost Flag indicating whether Secure priority boosting - * is desired; select 1 for priority boosting, otherwise 0. - * - * Note: - * - * This function shall only be called from Secure state. - */ -void tz_nonsecure_exception_prio_config(int secure_boost); - -/** - * @brief Set target state for exceptions not banked between security states - * - * Function sets the security state (Secure or Non-Secure) target - * for ARMv8-M HardFault, NMI, and BusFault exception. - * - * @param secure_state 1 if target state is Secure, 0 if target state - * is Non-Secure. - * - * Secure state: BusFault, HardFault, and NMI are Secure. - * Non-Secure state: BusFault and NMI are Non-Secure and exceptions can - * target Non-Secure HardFault. - * - * Notes: - * - * - This function shall only be called from Secure state. - * - NMI and BusFault are not banked between security states; they - * shall either target Secure or Non-Secure state based on user selection. - * - HardFault exception generated through escalation will target the - * security state of the original fault before its escalation to HardFault. - * - If secure_state is set to 1 (Secure), all Non-Secure HardFaults are - * escalated to Secure HardFaults. - * - BusFault is present only if the Main Extension is implemented. - */ -void tz_nbanked_exception_target_state_set(int secure_state); - -#if defined(CONFIG_ARMV7_M_ARMV8_M_FP) -/** - * @brief Allow Non-Secure firmware to access the FPU - * - * Function allows the Non-Secure firmware to access the Floating Point Unit. - * - * Relevant for ARMv8-M MCUs supporting the Floating Point Extension. - * - * Note: - * - * This function shall only be called from Secure state. - */ -void tz_nonsecure_fpu_access_enable(void); -#endif /* CONFIG_ARMV7_M_ARMV8_M_FP */ - -/** - * - * @brief Configure SAU - * - * Configure (enable or disable) the ARMv8-M Security Attribution Unit. - * - * @param enable SAU enable flag: 1 if SAU is to be enabled, 0 if SAU is - * to be disabled. - * @param allns SAU_CTRL.ALLNS flag: select 1 to set SAU_CTRL.ALLNS, 0 - * to clear SAU_CTRL.ALLNS. - * - * Notes: - * - * SAU_CTRL.ALLNS bit: All Non-secure. When SAU_CTRL.ENABLE is 0 - * this bit controls if the memory is marked as Non-secure or Secure. - * Values: - * Secure (not Non-Secure Callable): 0 - * Non-Secure: 1 - * - * This function shall only be called from Secure state, otherwise the - * Non-Secure instance of SAU_CTRL register is RAZ/WI. - * - * This function shall be called before the Secure Firmware may transition - * to Non-Secure state. - * - */ -void tz_sau_configure(int enable, int allns); - -/** - * - * @brief Get number of SAU regions - * - * Get the number of regions implemented by the Security Attribution Unit, - * indicated by SAU_TYPE.SREGION (read-only) register field. - * - * Notes: - * - * The SREGION field reads as an IMPLEMENTATION DEFINED value. - * - * This function shall only be called from Secure state, otherwise the - * Non-Secure instance of SAU_TYPE register is RAZ. - * - * @return The number of configured SAU regions. - */ -uint32_t tz_sau_number_of_regions_get(void); - -#if defined(CONFIG_CPU_HAS_ARM_SAU) -/** - * - * @brief SAU Region configuration - * - * A convenient struct to include all required elements - * for a SAU region configuration. - */ -typedef struct { - uint8_t region_num; - uint8_t enable:1; - uint8_t nsc:1; - uint32_t base_addr; - uint32_t limit_addr; -} tz_sau_conf_t; - - -/** - * - * @brief Configure SAU Region - * - * Configure an existing ARMv8-M SAU region. - * - * @param p_sau_conf pointer to a tz_sau_conf_t structure - * - * This function shall only be called from Secure state, otherwise the - * Non-Secure instances of SAU RNR, RLAR, RBAR registers are RAZ/WI. - * - * This function shall be called before the Secure Firmware may transition - * to Non-Secure state. - * - * @return 1 if configuration is successful, otherwise 0. - - */ -int tz_sau_region_configure(tz_sau_conf_t *p_sau_conf); - -#endif /* CONFIG_CPU_HAS_ARM_SAU */ - -/** - * @brief Non-Secure function type - * - * Defines a function pointer type to implement a non-secure function call, - * i.e. a function call that switches state from Secure to Non-secure. - * - * Note: - * - * A non-secure function call can only happen through function pointers. - * This is a consequence of separating secure and non-secure code into - * separate executable files. - */ -typedef void __attribute__((cmse_nonsecure_call)) (*tz_ns_func_ptr_t) (void); - -/* Required for C99 compilation (required for GCC-8.x version, - * where typeof is used instead of __typeof__) - */ -#ifndef typeof -#define typeof __typeof__ -#endif - -#if defined(CONFIG_ARM_FIRMWARE_HAS_SECURE_ENTRY_FUNCS) -/** - * @brief Non-Secure entry function attribute. - * - * Declares a non-secure entry function that may be called from Non-Secure - * or from Secure state using the CMSE _cmse_nonsecure_entry intrinsic. - * - * Note: - * - * The function must reside in Non-Secure Callable memory region. - */ -#define __TZ_NONSECURE_ENTRY_FUNC \ - __attribute__((cmse_nonsecure_entry, noinline)) - -#endif /* CONFIG_ARM_FIRMWARE_HAS_SECURE_ENTRY_FUNCS */ - -/** - * @brief Declare a pointer of non-secure function type - * - * Note: - * - * A non-secure function type must only be used as a base type of pointer. - */ -#define TZ_NONSECURE_FUNC_PTR_DECLARE(fptr) tz_ns_func_ptr_t fptr - -/** - * @brief Define a non-secure function pointer - * - * A non-secure function pointer is a function pointer that has its LSB unset. - * The macro uses the CMSE intrinsic: cmse_nsfptr_create(p) to return the - * value of a pointer with its LSB cleared. - */ -#define TZ_NONSECURE_FUNC_PTR_CREATE(fptr) \ - ((tz_ns_func_ptr_t)(cmse_nsfptr_create(fptr))) - -/** - * @brief Check if pointer can be of non-secure function type - * - * A non-secure function pointer is a function pointer that has its LSB unset. - * The macro uses the CMSE intrinsic: cmse_is_nsfptr(p) to evaluate whether - * the supplied pointer has its LSB cleared and, thus, can be of non-secure - * function type. - * - * @param fptr supplied pointer to be checked - * - * @return non-zero if pointer can be of non-secure function type - * (i.e. with LSB unset), zero otherwise. - */ -#define TZ_NONSECURE_FUNC_PTR_IS_NS(fptr) \ - cmse_is_nsfptr(fptr) - -#ifdef __cplusplus -} -#endif - -#endif /* _ASMLANGUAGE */ - -#endif /* ZEPHYR_ARCH_ARM_INCLUDE_AARCH32_CORTEX_M_TZ_H_ */ From eee09a55c5928739eb724161c94c19dab6305f37 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Manuel=20Arg=C3=BCelles?= Date: Wed, 6 Dec 2023 19:04:57 +0700 Subject: [PATCH 0981/3723] drivers: pwm: mcux_ftm: check against period cycles overflow MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The FTM counter modulo register (MOD) holds a 16-bit value, but PWM set_cycles API allows to set 32-bit cycles values. Fixes #66226 Signed-off-by: Manuel Argüelles --- drivers/pwm/pwm_mcux_ftm.c | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/drivers/pwm/pwm_mcux_ftm.c b/drivers/pwm/pwm_mcux_ftm.c index 27ed76df7ee..0f9d7deccf2 100644 --- a/drivers/pwm/pwm_mcux_ftm.c +++ b/drivers/pwm/pwm_mcux_ftm.c @@ -78,6 +78,11 @@ static int mcux_ftm_set_cycles(const struct device *dev, uint32_t channel, return -ENOTSUP; } + if (period_cycles > UINT16_MAX) { + LOG_ERR("Period cycles must be less or equal than %u", UINT16_MAX); + return -EINVAL; + } + if (channel >= config->channel_count) { LOG_ERR("Invalid channel"); return -ENOTSUP; From effca0609d46a8c7f67e864c547004f9bb606ae3 Mon Sep 17 00:00:00 2001 From: Andrei Emeltchenko Date: Thu, 7 Dec 2023 10:45:26 +0200 Subject: [PATCH 0982/3723] tests: fatal: Add message explaining OOPS Add message explaining the cause of the OOPS like it is done in many other cases. Signed-off-by: Andrei Emeltchenko --- tests/kernel/fatal/message_capture/src/main.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/tests/kernel/fatal/message_capture/src/main.c b/tests/kernel/fatal/message_capture/src/main.c index e0dfe8ea4db..906b68855e9 100644 --- a/tests/kernel/fatal/message_capture/src/main.c +++ b/tests/kernel/fatal/message_capture/src/main.c @@ -28,6 +28,8 @@ void k_sys_fatal_error_handler(unsigned int reason, const z_arch_esf_t *pEsf) k_fatal_halt(reason); } + printk("Fatal error expected as part of test case.\n"); + expected_reason = -1; } From cbae54c7f7f51eeff68faec2510b4cce79f09303 Mon Sep 17 00:00:00 2001 From: Marcus Folkesson Date: Wed, 6 Dec 2023 13:09:08 +0100 Subject: [PATCH 0983/3723] drivers: display: remove dummy functions for unsupported API As the display API now check against valid callback functions and returns -ENOSYS (or equalent), there is no need to provide such functions in the driver code Signed-off-by: Marcus Folkesson --- drivers/display/display_hx8394.c | 33 ----------------- drivers/display/display_intel_multibootfb.c | 32 ----------------- drivers/display/display_mcux_elcdif.c | 39 --------------------- drivers/display/display_nrf_led_matrix.c | 16 --------- drivers/display/display_otm8009a.c | 33 ----------------- drivers/display/display_rm67162.c | 16 --------- drivers/display/display_rm68200.c | 33 ----------------- drivers/display/display_sdl.c | 20 ----------- drivers/display/display_st7735r.c | 30 ---------------- drivers/display/display_st7789v.c | 30 ---------------- drivers/display/display_stm32_ltdc.c | 26 -------------- 11 files changed, 308 deletions(-) diff --git a/drivers/display/display_hx8394.c b/drivers/display/display_hx8394.c index d5fecfb4fe1..b14846ae343 100644 --- a/drivers/display/display_hx8394.c +++ b/drivers/display/display_hx8394.c @@ -415,21 +415,6 @@ static int hx8394_write(const struct device *dev, const uint16_t x, return 0; } -static int hx8394_read(const struct device *dev, const uint16_t x, - const uint16_t y, - const struct display_buffer_descriptor *desc, - void *buf) -{ - LOG_WRN("Read not implemented"); - return -ENOTSUP; -} - -static void *hx8394_get_framebuffer(const struct device *dev) -{ - LOG_WRN("Direct framebuffer access not implemented"); - return NULL; -} - static int hx8394_blanking_off(const struct device *dev) { const struct hx8394_config *config = dev->config; @@ -452,20 +437,6 @@ static int hx8394_blanking_on(const struct device *dev) } } -static int hx8394_set_brightness(const struct device *dev, - const uint8_t brightness) -{ - LOG_WRN("Set brightness not implemented"); - return -ENOTSUP; -} - -static int hx8394_set_contrast(const struct device *dev, - const uint8_t contrast) -{ - LOG_WRN("Set contrast not implemented"); - return -ENOTSUP; -} - static int hx8394_set_pixel_format(const struct device *dev, const enum display_pixel_format pixel_format) { @@ -526,10 +497,6 @@ static const struct display_driver_api hx8394_api = { .blanking_on = hx8394_blanking_on, .blanking_off = hx8394_blanking_off, .write = hx8394_write, - .read = hx8394_read, - .get_framebuffer = hx8394_get_framebuffer, - .set_brightness = hx8394_set_brightness, - .set_contrast = hx8394_set_contrast, .get_capabilities = hx8394_get_capabilities, .set_pixel_format = hx8394_set_pixel_format, .set_orientation = hx8394_set_orientation, diff --git a/drivers/display/display_intel_multibootfb.c b/drivers/display/display_intel_multibootfb.c index fc2ef3f32f5..e2b93b60940 100644 --- a/drivers/display/display_intel_multibootfb.c +++ b/drivers/display/display_intel_multibootfb.c @@ -26,33 +26,6 @@ struct framebuf_dev_data { uint32_t pitch; }; -static int framebuf_blanking_on(const struct device *dev) -{ - return -ENOTSUP; -} - -static int framebuf_blanking_off(const struct device *dev) -{ - return -ENOTSUP; -} - -static void *framebuf_get_framebuffer(const struct device *dev) -{ - return NULL; -} - -static int framebuf_set_brightness(const struct device *dev, - const uint8_t brightness) -{ - return -ENOTSUP; -} - -static int framebuf_set_contrast(const struct device *dev, - const uint8_t contrast) -{ - return -ENOTSUP; -} - static int framebuf_set_pixel_format(const struct device *dev, const enum display_pixel_format format) { @@ -133,13 +106,8 @@ static int framebuf_read(const struct device *dev, const uint16_t x, } const struct display_driver_api framebuf_display_api = { - .blanking_on = framebuf_blanking_on, - .blanking_off = framebuf_blanking_off, .write = framebuf_write, .read = framebuf_read, - .get_framebuffer = framebuf_get_framebuffer, - .set_brightness = framebuf_set_brightness, - .set_contrast = framebuf_set_contrast, .get_capabilities = framebuf_get_capabilities, .set_pixel_format = framebuf_set_pixel_format, .set_orientation = framebuf_set_orientation diff --git a/drivers/display/display_mcux_elcdif.c b/drivers/display/display_mcux_elcdif.c index 830bc3e9a0c..304638011f1 100644 --- a/drivers/display/display_mcux_elcdif.c +++ b/drivers/display/display_mcux_elcdif.c @@ -211,27 +211,6 @@ static int mcux_elcdif_write(const struct device *dev, const uint16_t x, return ret; } -static int mcux_elcdif_read(const struct device *dev, const uint16_t x, - const uint16_t y, - const struct display_buffer_descriptor *desc, - void *buf) -{ - LOG_ERR("Read not implemented"); - return -ENOTSUP; -} - -static void *mcux_elcdif_get_framebuffer(const struct device *dev) -{ - /* - * Direct FB access is not available. If the user wants to set - * the framebuffer directly, they must provide a buffer to - * `display_write` equal in size to the connected display, - * with coordinates [0,0] - */ - LOG_ERR("Direct framebuffer access not available"); - return NULL; -} - static int mcux_elcdif_display_blanking_off(const struct device *dev) { const struct mcux_elcdif_config *config = dev->config; @@ -246,20 +225,6 @@ static int mcux_elcdif_display_blanking_on(const struct device *dev) return gpio_pin_set_dt(&config->backlight_gpio, 0); } -static int mcux_elcdif_set_brightness(const struct device *dev, - const uint8_t brightness) -{ - LOG_WRN("Set brightness not implemented"); - return -ENOTSUP; -} - -static int mcux_elcdif_set_contrast(const struct device *dev, - const uint8_t contrast) -{ - LOG_ERR("Set contrast not implemented"); - return -ENOTSUP; -} - static int mcux_elcdif_set_pixel_format(const struct device *dev, const enum display_pixel_format pixel_format) @@ -368,10 +333,6 @@ static const struct display_driver_api mcux_elcdif_api = { .blanking_on = mcux_elcdif_display_blanking_on, .blanking_off = mcux_elcdif_display_blanking_off, .write = mcux_elcdif_write, - .read = mcux_elcdif_read, - .get_framebuffer = mcux_elcdif_get_framebuffer, - .set_brightness = mcux_elcdif_set_brightness, - .set_contrast = mcux_elcdif_set_contrast, .get_capabilities = mcux_elcdif_get_capabilities, .set_pixel_format = mcux_elcdif_set_pixel_format, .set_orientation = mcux_elcdif_set_orientation, diff --git a/drivers/display/display_nrf_led_matrix.c b/drivers/display/display_nrf_led_matrix.c index dd36126a7ce..5468347551d 100644 --- a/drivers/display/display_nrf_led_matrix.c +++ b/drivers/display/display_nrf_led_matrix.c @@ -188,12 +188,6 @@ static int api_set_brightness(const struct device *dev, return 0; } -static int api_set_contrast(const struct device *dev, - const uint8_t contrast) -{ - return -ENOTSUP; -} - static int api_set_pixel_format(const struct device *dev, const enum display_pixel_format format) { @@ -279,22 +273,12 @@ static int api_write(const struct device *dev, return 0; } -static int api_read(const struct device *dev, - const uint16_t x, const uint16_t y, - const struct display_buffer_descriptor *desc, - void *buf) -{ - return -ENOTSUP; -} - const struct display_driver_api driver_api = { .blanking_on = api_blanking_on, .blanking_off = api_blanking_off, .write = api_write, - .read = api_read, .get_framebuffer = api_get_framebuffer, .set_brightness = api_set_brightness, - .set_contrast = api_set_contrast, .get_capabilities = api_get_capabilities, .set_pixel_format = api_set_pixel_format, .set_orientation = api_set_orientation, diff --git a/drivers/display/display_otm8009a.c b/drivers/display/display_otm8009a.c index 2463b431144..c2349a3dfd6 100644 --- a/drivers/display/display_otm8009a.c +++ b/drivers/display/display_otm8009a.c @@ -586,27 +586,11 @@ static int otm8009a_write(const struct device *dev, uint16_t x, uint16_t y, return -ENOTSUP; } -static int otm8009a_read(const struct device *dev, uint16_t x, uint16_t y, - const struct display_buffer_descriptor *desc, void *buf) -{ - return -ENOTSUP; -} - -static void *otm8009a_get_framebuffer(const struct device *dev) -{ - return NULL; -} - static int otm8009a_set_brightness(const struct device *dev, uint8_t brightness) { return otm8009a_dcs_write(dev, MIPI_DCS_SET_DISPLAY_BRIGHTNESS, &brightness, 1); } -static int otm8009a_set_contrast(const struct device *dev, uint8_t contrast) -{ - return -ENOTSUP; -} - static void otm8009a_get_capabilities(const struct device *dev, struct display_capabilities *capabilities) { @@ -621,29 +605,12 @@ static void otm8009a_get_capabilities(const struct device *dev, capabilities->current_orientation = data->orientation; } -static int otm8009a_set_pixel_format(const struct device *dev, - enum display_pixel_format pixel_format) -{ - return -ENOTSUP; -} - -static int otm8009a_set_orientation(const struct device *dev, - enum display_orientation orientation) -{ - return -ENOTSUP; -} - static const struct display_driver_api otm8009a_api = { .blanking_on = otm8009a_blanking_on, .blanking_off = otm8009a_blanking_off, .write = otm8009a_write, - .read = otm8009a_read, - .get_framebuffer = otm8009a_get_framebuffer, .set_brightness = otm8009a_set_brightness, - .set_contrast = otm8009a_set_contrast, .get_capabilities = otm8009a_get_capabilities, - .set_pixel_format = otm8009a_set_pixel_format, - .set_orientation = otm8009a_set_orientation, }; static int otm8009a_init(const struct device *dev) diff --git a/drivers/display/display_rm67162.c b/drivers/display/display_rm67162.c index afb7f4dd851..e63a4461810 100644 --- a/drivers/display/display_rm67162.c +++ b/drivers/display/display_rm67162.c @@ -512,20 +512,6 @@ static int rm67162_blanking_on(const struct device *dev) } } -static int rm67162_set_brightness(const struct device *dev, - const uint8_t brightness) -{ - LOG_WRN("Set brightness not implemented"); - return -ENOTSUP; -} - -static int rm67162_set_contrast(const struct device *dev, - const uint8_t contrast) -{ - LOG_ERR("Set contrast not implemented"); - return -ENOTSUP; -} - static int rm67162_set_pixel_format(const struct device *dev, const enum display_pixel_format pixel_format) { @@ -595,8 +581,6 @@ static const struct display_driver_api rm67162_api = { .blanking_off = rm67162_blanking_off, .get_capabilities = rm67162_get_capabilities, .write = rm67162_write, - .set_brightness = rm67162_set_brightness, - .set_contrast = rm67162_set_contrast, .set_pixel_format = rm67162_set_pixel_format, .set_orientation = rm67162_set_orientation, }; diff --git a/drivers/display/display_rm68200.c b/drivers/display/display_rm68200.c index a89e0d0201a..7048790bdf3 100644 --- a/drivers/display/display_rm68200.c +++ b/drivers/display/display_rm68200.c @@ -102,21 +102,6 @@ static int rm68200_write(const struct device *dev, const uint16_t x, return 0; } -static int rm68200_read(const struct device *dev, const uint16_t x, - const uint16_t y, - const struct display_buffer_descriptor *desc, - void *buf) -{ - LOG_ERR("Read not implemented"); - return -ENOTSUP; -} - -static void *rm68200_get_framebuffer(const struct device *dev) -{ - LOG_ERR("Direct framebuffer access not implemented"); - return NULL; -} - static int rm68200_blanking_off(const struct device *dev) { const struct rm68200_config *config = dev->config; @@ -139,20 +124,6 @@ static int rm68200_blanking_on(const struct device *dev) } } -static int rm68200_set_brightness(const struct device *dev, - const uint8_t brightness) -{ - LOG_WRN("Set brightness not implemented"); - return -ENOTSUP; -} - -static int rm68200_set_contrast(const struct device *dev, - const uint8_t contrast) -{ - LOG_ERR("Set contrast not implemented"); - return -ENOTSUP; -} - static int rm68200_set_pixel_format(const struct device *dev, const enum display_pixel_format pixel_format) { @@ -192,10 +163,6 @@ static const struct display_driver_api rm68200_api = { .blanking_on = rm68200_blanking_on, .blanking_off = rm68200_blanking_off, .write = rm68200_write, - .read = rm68200_read, - .get_framebuffer = rm68200_get_framebuffer, - .set_brightness = rm68200_set_brightness, - .set_contrast = rm68200_set_contrast, .get_capabilities = rm68200_get_capabilities, .set_pixel_format = rm68200_set_pixel_format, .set_orientation = rm68200_set_orientation, diff --git a/drivers/display/display_sdl.c b/drivers/display/display_sdl.c index b411896b5b1..dabd0a0c0a2 100644 --- a/drivers/display/display_sdl.c +++ b/drivers/display/display_sdl.c @@ -269,11 +269,6 @@ static int sdl_display_read(const struct device *dev, const uint16_t x, disp_data->renderer, buf, desc->pitch); } -static void *sdl_display_get_framebuffer(const struct device *dev) -{ - return NULL; -} - static int sdl_display_blanking_off(const struct device *dev) { struct sdl_display_data *disp_data = dev->data; @@ -299,18 +294,6 @@ static int sdl_display_blanking_on(const struct device *dev) return 0; } -static int sdl_display_set_brightness(const struct device *dev, - const uint8_t brightness) -{ - return -ENOTSUP; -} - -static int sdl_display_set_contrast(const struct device *dev, - const uint8_t contrast) -{ - return -ENOTSUP; -} - static void sdl_display_get_capabilities( const struct device *dev, struct display_capabilities *capabilities) { @@ -361,9 +344,6 @@ static const struct display_driver_api sdl_display_api = { .blanking_off = sdl_display_blanking_off, .write = sdl_display_write, .read = sdl_display_read, - .get_framebuffer = sdl_display_get_framebuffer, - .set_brightness = sdl_display_set_brightness, - .set_contrast = sdl_display_set_contrast, .get_capabilities = sdl_display_get_capabilities, .set_pixel_format = sdl_display_set_pixel_format, }; diff --git a/drivers/display/display_st7735r.c b/drivers/display/display_st7735r.c index a20242d9703..88c282d89f8 100644 --- a/drivers/display/display_st7735r.c +++ b/drivers/display/display_st7735r.c @@ -159,15 +159,6 @@ static int st7735r_blanking_off(const struct device *dev) return st7735r_transmit(dev, ST7735R_CMD_DISP_ON, NULL, 0); } -static int st7735r_read(const struct device *dev, - const uint16_t x, - const uint16_t y, - const struct display_buffer_descriptor *desc, - void *buf) -{ - return -ENOTSUP; -} - static int st7735r_set_mem_area(const struct device *dev, const uint16_t x, const uint16_t y, const uint16_t w, const uint16_t h) @@ -267,23 +258,6 @@ static int st7735r_write(const struct device *dev, return ret; } -static void *st7735r_get_framebuffer(const struct device *dev) -{ - return NULL; -} - -static int st7735r_set_brightness(const struct device *dev, - const uint8_t brightness) -{ - return -ENOTSUP; -} - -static int st7735r_set_contrast(const struct device *dev, - const uint8_t contrast) -{ - return -ENOTSUP; -} - static void st7735r_get_capabilities(const struct device *dev, struct display_capabilities *capabilities) { @@ -548,10 +522,6 @@ static const struct display_driver_api st7735r_api = { .blanking_on = st7735r_blanking_on, .blanking_off = st7735r_blanking_off, .write = st7735r_write, - .read = st7735r_read, - .get_framebuffer = st7735r_get_framebuffer, - .set_brightness = st7735r_set_brightness, - .set_contrast = st7735r_set_contrast, .get_capabilities = st7735r_get_capabilities, .set_pixel_format = st7735r_set_pixel_format, .set_orientation = st7735r_set_orientation, diff --git a/drivers/display/display_st7789v.c b/drivers/display/display_st7789v.c index 56440c369c9..0d3a9eb37aa 100644 --- a/drivers/display/display_st7789v.c +++ b/drivers/display/display_st7789v.c @@ -141,15 +141,6 @@ static int st7789v_blanking_off(const struct device *dev) return 0; } -static int st7789v_read(const struct device *dev, - const uint16_t x, - const uint16_t y, - const struct display_buffer_descriptor *desc, - void *buf) -{ - return -ENOTSUP; -} - static void st7789v_set_mem_area(const struct device *dev, const uint16_t x, const uint16_t y, const uint16_t w, const uint16_t h) { @@ -204,23 +195,6 @@ static int st7789v_write(const struct device *dev, return 0; } -static void *st7789v_get_framebuffer(const struct device *dev) -{ - return NULL; -} - -static int st7789v_set_brightness(const struct device *dev, - const uint8_t brightness) -{ - return -ENOTSUP; -} - -static int st7789v_set_contrast(const struct device *dev, - const uint8_t contrast) -{ - return -ENOTSUP; -} - static void st7789v_get_capabilities(const struct device *dev, struct display_capabilities *capabilities) { @@ -413,10 +387,6 @@ static const struct display_driver_api st7789v_api = { .blanking_on = st7789v_blanking_on, .blanking_off = st7789v_blanking_off, .write = st7789v_write, - .read = st7789v_read, - .get_framebuffer = st7789v_get_framebuffer, - .set_brightness = st7789v_set_brightness, - .set_contrast = st7789v_set_contrast, .get_capabilities = st7789v_get_capabilities, .set_pixel_format = st7789v_set_pixel_format, .set_orientation = st7789v_set_orientation, diff --git a/drivers/display/display_stm32_ltdc.c b/drivers/display/display_stm32_ltdc.c index 99001c3b37b..447252990e2 100644 --- a/drivers/display/display_stm32_ltdc.c +++ b/drivers/display/display_stm32_ltdc.c @@ -86,16 +86,6 @@ struct display_stm32_ltdc_config { const struct pinctrl_dev_config *pctrl; }; -static int stm32_ltdc_blanking_on(const struct device *dev) -{ - return -ENOTSUP; -} - -static int stm32_ltdc_blanking_off(const struct device *dev) -{ - return -ENOTSUP; -} - static void *stm32_ltdc_get_framebuffer(const struct device *dev) { struct display_stm32_ltdc_data *data = dev->data; @@ -103,18 +93,6 @@ static void *stm32_ltdc_get_framebuffer(const struct device *dev) return (void *) data->frame_buffer; } -static int stm32_ltdc_set_brightness(const struct device *dev, - const uint8_t brightness) -{ - return -ENOTSUP; -} - -static int stm32_ltdc_set_contrast(const struct device *dev, - const uint8_t contrast) -{ - return -ENOTSUP; -} - static int stm32_ltdc_set_pixel_format(const struct device *dev, const enum display_pixel_format format) { @@ -379,13 +357,9 @@ static int stm32_ltdc_pm_action(const struct device *dev, #endif /* CONFIG_PM_DEVICE */ static const struct display_driver_api stm32_ltdc_display_api = { - .blanking_on = stm32_ltdc_blanking_on, - .blanking_off = stm32_ltdc_blanking_off, .write = stm32_ltdc_write, .read = stm32_ltdc_read, .get_framebuffer = stm32_ltdc_get_framebuffer, - .set_brightness = stm32_ltdc_set_brightness, - .set_contrast = stm32_ltdc_set_contrast, .get_capabilities = stm32_ltdc_get_capabilities, .set_pixel_format = stm32_ltdc_set_pixel_format, .set_orientation = stm32_ltdc_set_orientation From 6c9ff66e5f51578bcceb5aa0ec5db8d80e1eb243 Mon Sep 17 00:00:00 2001 From: Mateusz Karlic Date: Thu, 7 Dec 2023 12:20:14 +0100 Subject: [PATCH 0984/3723] dts: arm: ambiq: Add SoC compat string Add `compatible` node to Ambiq SoCs, along with secondary common compat, since they share many similarities. Signed-off-by: Mateusz Karlic --- dts/arm/ambiq/ambiq_apollo4p.dtsi | 2 ++ dts/arm/ambiq/ambiq_apollo4p_blue.dtsi | 2 ++ 2 files changed, 4 insertions(+) diff --git a/dts/arm/ambiq/ambiq_apollo4p.dtsi b/dts/arm/ambiq/ambiq_apollo4p.dtsi index 666acda801a..10aa631a12e 100644 --- a/dts/arm/ambiq/ambiq_apollo4p.dtsi +++ b/dts/arm/ambiq/ambiq_apollo4p.dtsi @@ -44,6 +44,8 @@ }; soc { + compatible = "ambiq,apollo4p", "ambiq,apollo4x", "simple-bus"; + pwrcfg: pwrcfg@40021000 { compatible = "ambiq,pwrctrl"; reg = <0x40021000 0x400>; diff --git a/dts/arm/ambiq/ambiq_apollo4p_blue.dtsi b/dts/arm/ambiq/ambiq_apollo4p_blue.dtsi index d96bf4ff10d..c0baab83b80 100644 --- a/dts/arm/ambiq/ambiq_apollo4p_blue.dtsi +++ b/dts/arm/ambiq/ambiq_apollo4p_blue.dtsi @@ -49,6 +49,8 @@ }; soc { + compatible = "ambiq,apollo4p-blue", "ambiq,apollo4x", "simple-bus"; + flash: flash-controller@18000 { compatible = "ambiq,flash-controller"; reg = <0x00018000 0x1e8000>; From 08413e1fb805fbc042bb115a18a8c2b784b70aea Mon Sep 17 00:00:00 2001 From: Joakim Andersson Date: Thu, 7 Dec 2023 15:05:13 +0100 Subject: [PATCH 0985/3723] soc: nordic_nrf: Enable the TF-M NS storage partition for nordic boards Enable the TF-M NS storage partition for nordic boards. This partition is otherwise not used, and configured as secure. Fixes: #59376 Signed-off-by: Joakim Andersson --- soc/arm/nordic_nrf/CMakeLists.txt | 4 ++++ soc/arm/nordic_nrf/Kconfig | 4 ++++ 2 files changed, 8 insertions(+) diff --git a/soc/arm/nordic_nrf/CMakeLists.txt b/soc/arm/nordic_nrf/CMakeLists.txt index 47364b35ffb..3b097d73569 100644 --- a/soc/arm/nordic_nrf/CMakeLists.txt +++ b/soc/arm/nordic_nrf/CMakeLists.txt @@ -25,4 +25,8 @@ if(CONFIG_BUILD_WITH_TFM) set_property(TARGET zephyr_property_target APPEND PROPERTY TFM_CMAKE_OPTIONS -DZEPHYR_BASE=${ZEPHYR_BASE} ) + + set_property(TARGET zephyr_property_target + APPEND PROPERTY TFM_CMAKE_OPTIONS -DNRF_NS_STORAGE=${CONFIG_TFM_NRF_NS_STORAGE} + ) endif() diff --git a/soc/arm/nordic_nrf/Kconfig b/soc/arm/nordic_nrf/Kconfig index 21f59f458f3..f2a20321d6b 100644 --- a/soc/arm/nordic_nrf/Kconfig +++ b/soc/arm/nordic_nrf/Kconfig @@ -45,6 +45,10 @@ config TFM_LOG_LEVEL_SILENCE Disable TF-M secure output if the uart1 node has not assigned GPIO pins using pinctrl. +config TFM_NRF_NS_STORAGE + bool "TF-M non-secure storage partition" + default y + endif # BUILD_WITH_TFM From 3063c6ae46b8ebfde294869adcca7fd2dda53e78 Mon Sep 17 00:00:00 2001 From: Joakim Andersson Date: Thu, 7 Dec 2023 19:13:35 +0100 Subject: [PATCH 0986/3723] samples: soc_flash_nrf: Stop erasing outside of test partition Stop erasing outside of the test partition. We shouldn't really on this being accesible memory. This region may be consider as secure when application is non-secure. Signed-off-by: Joakim Andersson --- samples/drivers/soc_flash_nrf/README.rst | 2 +- samples/drivers/soc_flash_nrf/src/main.c | 6 +++--- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/samples/drivers/soc_flash_nrf/README.rst b/samples/drivers/soc_flash_nrf/README.rst index 496688e8b65..de49eb6db28 100644 --- a/samples/drivers/soc_flash_nrf/README.rst +++ b/samples/drivers/soc_flash_nrf/README.rst @@ -62,7 +62,7 @@ Sample Output Data read: 1234 Data read matches data written. Good! - Test 3: Flash erase (4 pages at 0x80000) + Test 3: Flash erase (2 pages at 0x80000) Flash erase succeeded! Test 4: Flash write (word array 2) diff --git a/samples/drivers/soc_flash_nrf/src/main.c b/samples/drivers/soc_flash_nrf/src/main.c index a438a67cf2f..91a763c781d 100644 --- a/samples/drivers/soc_flash_nrf/src/main.c +++ b/samples/drivers/soc_flash_nrf/src/main.c @@ -84,9 +84,9 @@ int main(void) } } - offset = TEST_PARTITION_OFFSET - FLASH_PAGE_SIZE * 2; - printf("\nTest 3: Flash erase (4 pages at 0x%x)\n", offset); - if (flash_erase(flash_dev, offset, FLASH_PAGE_SIZE * 4) != 0) { + offset = TEST_PARTITION_OFFSET; + printf("\nTest 3: Flash erase (2 pages at 0x%x)\n", offset); + if (flash_erase(flash_dev, offset, FLASH_PAGE_SIZE * 2) != 0) { printf(" Flash erase failed!\n"); } else { printf(" Flash erase succeeded!\n"); From 29fc537bfbd0c4dc354d2c858e0e46d64393846b Mon Sep 17 00:00:00 2001 From: Joakim Andersson Date: Thu, 7 Dec 2023 19:16:57 +0100 Subject: [PATCH 0987/3723] samples: soc_flash_nrf: Print finished message Print a finished message, so that it is clear that this in the end of the sample. This makes it certain that we didn't crash without output on the last test. Signed-off-by: Joakim Andersson --- samples/drivers/soc_flash_nrf/README.rst | 2 ++ samples/drivers/soc_flash_nrf/sample.yaml | 1 + samples/drivers/soc_flash_nrf/src/main.c | 2 ++ 3 files changed, 5 insertions(+) diff --git a/samples/drivers/soc_flash_nrf/README.rst b/samples/drivers/soc_flash_nrf/README.rst index de49eb6db28..2ee87739aad 100644 --- a/samples/drivers/soc_flash_nrf/README.rst +++ b/samples/drivers/soc_flash_nrf/README.rst @@ -131,3 +131,5 @@ Sample Output Test 8: Write block size API write-block-size = 1 + + Finished! diff --git a/samples/drivers/soc_flash_nrf/sample.yaml b/samples/drivers/soc_flash_nrf/sample.yaml index b8a59328be4..d1f635ca93f 100644 --- a/samples/drivers/soc_flash_nrf/sample.yaml +++ b/samples/drivers/soc_flash_nrf/sample.yaml @@ -29,3 +29,4 @@ tests: - "Data read matches data written. Good!" - "SoC flash consists of \\d+ pages." - "write-block-size = 1" + - "Finished!" diff --git a/samples/drivers/soc_flash_nrf/src/main.c b/samples/drivers/soc_flash_nrf/src/main.c index 91a763c781d..33ab9b28e1d 100644 --- a/samples/drivers/soc_flash_nrf/src/main.c +++ b/samples/drivers/soc_flash_nrf/src/main.c @@ -191,5 +191,7 @@ int main(void) printf("\nTest 8: Write block size API\n"); printf(" write-block-size = %u\n", flash_get_write_block_size(flash_dev)); + + printf("\nFinished!\n"); return 0; } From afe4cce83139833fec7457832382b710c5d2f8f1 Mon Sep 17 00:00:00 2001 From: Joakim Andersson Date: Thu, 7 Dec 2023 19:21:06 +0100 Subject: [PATCH 0988/3723] samples: soc_flash_nrf: Make sure that the flash partition is valid Make sure that the flash partition is valid. With TF-M enabled the storage_partition can be used as memory that is known to be configured as non-secure flash region. The slot1_ns_partition partition is only correct when TF-M is built with BL2 enabled. Signed-off-by: Joakim Andersson --- samples/drivers/soc_flash_nrf/prj.conf | 4 ++++ samples/drivers/soc_flash_nrf/src/main.c | 6 +----- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/samples/drivers/soc_flash_nrf/prj.conf b/samples/drivers/soc_flash_nrf/prj.conf index 9909ef3b29f..48e64121b6a 100644 --- a/samples/drivers/soc_flash_nrf/prj.conf +++ b/samples/drivers/soc_flash_nrf/prj.conf @@ -3,3 +3,7 @@ CONFIG_FLASH=y CONFIG_FLASH_PAGE_LAYOUT=y CONFIG_MPU_ALLOW_FLASH_WRITE=y CONFIG_SOC_FLASH_NRF_EMULATE_ONE_BYTE_WRITE_ACCESS=y +CONFIG_FCB=y +CONFIG_FLASH_MAP=y +CONFIG_SETTINGS=y +CONFIG_SETTINGS_FCB=y diff --git a/samples/drivers/soc_flash_nrf/src/main.c b/samples/drivers/soc_flash_nrf/src/main.c index 33ab9b28e1d..29606a9ca5d 100644 --- a/samples/drivers/soc_flash_nrf/src/main.c +++ b/samples/drivers/soc_flash_nrf/src/main.c @@ -13,11 +13,7 @@ #include -#ifdef CONFIG_TRUSTED_EXECUTION_NONSECURE -#define TEST_PARTITION slot1_ns_partition -#else -#define TEST_PARTITION slot1_partition -#endif +#define TEST_PARTITION storage_partition #define TEST_PARTITION_OFFSET FIXED_PARTITION_OFFSET(TEST_PARTITION) #define TEST_PARTITION_DEVICE FIXED_PARTITION_DEVICE(TEST_PARTITION) From a8e340eb7e775823e1bad6b3bb1126593c32557b Mon Sep 17 00:00:00 2001 From: Joakim Andersson Date: Thu, 7 Dec 2023 19:35:48 +0100 Subject: [PATCH 0989/3723] tests: flash: Use a flash partition that is known to be nonsecure With TF-M enabled the storage_partition can be used as memory that is known to be configured as non-secure flash region. The slot1_ns_partition partition is only correct when TF-M is built with BL2 enabled. Signed-off-by: Joakim Andersson --- .../flash/common/boards/nrf5340dk_nrf5340_cpuapp_ns.conf | 4 ++++ tests/drivers/flash/common/boards/nrf9160dk_nrf9160_ns.conf | 4 ++++ tests/drivers/flash/common/boards/nrf9161dk_nrf9161_ns.conf | 4 ++++ tests/drivers/flash/common/src/main.c | 3 --- tests/drivers/flash/common/testcase.yaml | 2 +- 5 files changed, 13 insertions(+), 4 deletions(-) create mode 100644 tests/drivers/flash/common/boards/nrf5340dk_nrf5340_cpuapp_ns.conf create mode 100644 tests/drivers/flash/common/boards/nrf9160dk_nrf9160_ns.conf create mode 100644 tests/drivers/flash/common/boards/nrf9161dk_nrf9161_ns.conf diff --git a/tests/drivers/flash/common/boards/nrf5340dk_nrf5340_cpuapp_ns.conf b/tests/drivers/flash/common/boards/nrf5340dk_nrf5340_cpuapp_ns.conf new file mode 100644 index 00000000000..821a5e77e5b --- /dev/null +++ b/tests/drivers/flash/common/boards/nrf5340dk_nrf5340_cpuapp_ns.conf @@ -0,0 +1,4 @@ +CONFIG_FCB=y +CONFIG_FLASH_MAP=y +CONFIG_SETTINGS=y +CONFIG_SETTINGS_FCB=y diff --git a/tests/drivers/flash/common/boards/nrf9160dk_nrf9160_ns.conf b/tests/drivers/flash/common/boards/nrf9160dk_nrf9160_ns.conf new file mode 100644 index 00000000000..821a5e77e5b --- /dev/null +++ b/tests/drivers/flash/common/boards/nrf9160dk_nrf9160_ns.conf @@ -0,0 +1,4 @@ +CONFIG_FCB=y +CONFIG_FLASH_MAP=y +CONFIG_SETTINGS=y +CONFIG_SETTINGS_FCB=y diff --git a/tests/drivers/flash/common/boards/nrf9161dk_nrf9161_ns.conf b/tests/drivers/flash/common/boards/nrf9161dk_nrf9161_ns.conf new file mode 100644 index 00000000000..821a5e77e5b --- /dev/null +++ b/tests/drivers/flash/common/boards/nrf9161dk_nrf9161_ns.conf @@ -0,0 +1,4 @@ +CONFIG_FCB=y +CONFIG_FLASH_MAP=y +CONFIG_SETTINGS=y +CONFIG_SETTINGS_FCB=y diff --git a/tests/drivers/flash/common/src/main.c b/tests/drivers/flash/common/src/main.c index 4e73617ba41..79d75ca9b13 100644 --- a/tests/drivers/flash/common/src/main.c +++ b/tests/drivers/flash/common/src/main.c @@ -14,9 +14,6 @@ #define TEST_AREA_DEV_NODE DT_INST(0, nordic_qspi_nor) #elif defined(CONFIG_SPI_NOR) #define TEST_AREA_DEV_NODE DT_INST(0, jedec_spi_nor) -#elif defined(CONFIG_TRUSTED_EXECUTION_NONSECURE) -/* SoC embedded NVM */ -#define TEST_AREA slot1_ns_partition #else #define TEST_AREA storage_partition #endif diff --git a/tests/drivers/flash/common/testcase.yaml b/tests/drivers/flash/common/testcase.yaml index a3624f76be2..e0caddbd773 100644 --- a/tests/drivers/flash/common/testcase.yaml +++ b/tests/drivers/flash/common/testcase.yaml @@ -38,7 +38,7 @@ tests: drivers.flash.common.tfm_ns: build_only: true filter: (CONFIG_FLASH_HAS_DRIVER_ENABLED and CONFIG_TRUSTED_EXECUTION_NONSECURE - and dt_label_with_parent_compat_enabled("slot1_ns_partition", "fixed-partitions")) + and dt_label_with_parent_compat_enabled("storage_partition", "fixed-partitions")) integration_platforms: - nrf9161dk_nrf9161_ns drivers.flash.common.stm32: From b8d887f0e147caf3fdf9c94c51e827813b921069 Mon Sep 17 00:00:00 2001 From: Sylvio Alves Date: Thu, 7 Dec 2023 11:47:04 -0300 Subject: [PATCH 0990/3723] net: wifi: esp32: disable automatic reconnection on leaving Automatic Wi-Fi station reconnection is forced even when application requests disconnection. This PR adds a check in the disconnection event reason to decide whether or not perform the reconnection. Signed-off-by: Sylvio Alves --- drivers/wifi/esp32/src/esp_wifi_drv.c | 25 ++++++++++++++++++++++--- 1 file changed, 22 insertions(+), 3 deletions(-) diff --git a/drivers/wifi/esp32/src/esp_wifi_drv.c b/drivers/wifi/esp32/src/esp_wifi_drv.c index 4b2f299c123..dcd3139e437 100644 --- a/drivers/wifi/esp32/src/esp_wifi_drv.c +++ b/drivers/wifi/esp32/src/esp_wifi_drv.c @@ -243,8 +243,10 @@ static void esp_wifi_handle_connect_event(void) #endif } -static void esp_wifi_handle_disconnect_event(void) +static void esp_wifi_handle_disconnect_event(void *event_data) { + wifi_event_sta_disconnected_t *event = (wifi_event_sta_disconnected_t *)event_data; + if (esp32_data.state == ESP32_STA_CONNECTED) { #if defined(CONFIG_ESP32_WIFI_STA_AUTO_DHCPV4) net_dhcpv4_stop(esp32_wifi_iface); @@ -254,7 +256,24 @@ static void esp_wifi_handle_disconnect_event(void) wifi_mgmt_raise_disconnect_result_event(esp32_wifi_iface, -1); } - if (IS_ENABLED(CONFIG_ESP32_WIFI_STA_RECONNECT)) { + LOG_DBG("Disconnect reason: %d", event->reason); + switch (event->reason) { + case WIFI_REASON_AUTH_EXPIRE: + case WIFI_REASON_4WAY_HANDSHAKE_TIMEOUT: + case WIFI_REASON_AUTH_FAIL: + case WIFI_REASON_HANDSHAKE_TIMEOUT: + case WIFI_REASON_MIC_FAILURE: + LOG_DBG("STA Auth Error"); + break; + case WIFI_REASON_NO_AP_FOUND: + LOG_DBG("AP Not found"); + break; + default: + break; + } + + if (IS_ENABLED(CONFIG_ESP32_WIFI_STA_RECONNECT) && + (event->reason != WIFI_REASON_ASSOC_LEAVE)) { esp32_data.state = ESP32_STA_CONNECTING; esp_wifi_connect(); } else { @@ -286,7 +305,7 @@ static void esp_wifi_event_task(void *p1, void *p2, void *p3) esp_wifi_handle_connect_event(); break; case ESP32_WIFI_EVENT_STA_DISCONNECTED: - esp_wifi_handle_disconnect_event(); + esp_wifi_handle_disconnect_event(&evt.event_info); break; case ESP32_WIFI_EVENT_SCAN_DONE: scan_done_handler(); From 005dc60d24bc378dffdc7c4ce12f4cd0cee1744a Mon Sep 17 00:00:00 2001 From: Seppo Takalo Date: Thu, 7 Dec 2023 17:17:30 +0200 Subject: [PATCH 0991/3723] net: lwm2m: Fix pmin handling on tickless If observed resource was written during the pMin period, it did not schedule any wake-up event into the future. Notify message would then only be generated as a result of any other (like Update) event. Refactor check_notifications() to follow same pattern as retransmit_req(). Return the next event timestamp, which could be now. Signed-off-by: Seppo Takalo --- subsys/net/lib/lwm2m/lwm2m_engine.c | 29 ++++++++++++++++++++++------- 1 file changed, 22 insertions(+), 7 deletions(-) diff --git a/subsys/net/lib/lwm2m/lwm2m_engine.c b/subsys/net/lib/lwm2m/lwm2m_engine.c index 45d3822bdbb..959d07419d3 100644 --- a/subsys/net/lib/lwm2m/lwm2m_engine.c +++ b/subsys/net/lib/lwm2m/lwm2m_engine.c @@ -581,14 +581,24 @@ void lwm2m_socket_del(struct lwm2m_ctx *ctx) lwm2m_engine_wake_up(); } -static void check_notifications(struct lwm2m_ctx *ctx, const int64_t timestamp) +/* Generate notify messages. Return timestamp of next Notify event */ +static int64_t check_notifications(struct lwm2m_ctx *ctx, const int64_t timestamp) { struct observe_node *obs; int rc; + int64_t next = INT64_MAX; lwm2m_registry_lock(); SYS_SLIST_FOR_EACH_CONTAINER(&ctx->observer, obs, node) { - if (!obs->event_timestamp || timestamp < obs->event_timestamp) { + if (!obs->event_timestamp) { + continue; + } + + if (obs->event_timestamp < next) { + next = obs->event_timestamp; + } + + if (timestamp < obs->event_timestamp) { continue; } /* Check That There is not pending process*/ @@ -604,6 +614,7 @@ static void check_notifications(struct lwm2m_ctx *ctx, const int64_t timestamp) obs->event_timestamp = engine_observe_shedule_next_event(obs, ctx->srv_obj_inst, timestamp); obs->last_timestamp = timestamp; + if (!rc) { /* create at most one notification */ goto cleanup; @@ -611,6 +622,7 @@ static void check_notifications(struct lwm2m_ctx *ctx, const int64_t timestamp) } cleanup: lwm2m_registry_unlock(); + return next; } static int socket_recv_message(struct lwm2m_ctx *client_ctx) @@ -704,7 +716,7 @@ static void socket_loop(void *p1, void *p2, void *p3) int i, rc; int64_t now, next; - int64_t timeout, next_retransmit; + int64_t timeout, next_tx; bool rd_client_paused; while (1) { @@ -741,12 +753,15 @@ static void socket_loop(void *p1, void *p2, void *p3) if (!sys_slist_is_empty(&sock_ctx[i]->pending_sends)) { continue; } - next_retransmit = retransmit_request(sock_ctx[i], now); - if (next_retransmit < next) { - next = next_retransmit; + next_tx = retransmit_request(sock_ctx[i], now); + if (next_tx < next) { + next = next_tx; } if (lwm2m_rd_client_is_registred(sock_ctx[i])) { - check_notifications(sock_ctx[i], now); + next_tx = check_notifications(sock_ctx[i], now); + if (next_tx < next) { + next = next_tx; + } } } From b4bdbfd76bca5f7b8dc321d0bea53e40d1a71d20 Mon Sep 17 00:00:00 2001 From: Seppo Takalo Date: Thu, 7 Dec 2023 17:18:50 +0200 Subject: [PATCH 0992/3723] test: lwm2m: Run interop tests in tickless mode Tickless mode is important to be tested against real server. Signed-off-by: Seppo Takalo --- tests/net/lib/lwm2m/interop/prj.conf | 3 +++ 1 file changed, 3 insertions(+) diff --git a/tests/net/lib/lwm2m/interop/prj.conf b/tests/net/lib/lwm2m/interop/prj.conf index 43d4e73f081..6115e6f40e3 100644 --- a/tests/net/lib/lwm2m/interop/prj.conf +++ b/tests/net/lib/lwm2m/interop/prj.conf @@ -18,6 +18,9 @@ CONFIG_LWM2M=y CONFIG_LWM2M_IPSO_SUPPORT=y CONFIG_LWM2M_SHELL=y +CONFIG_LWM2M_TICKLESS=y +CONFIG_NET_SOCKETPAIR=y + #Enable Portfolio object CONFIG_LWM2M_PORTFOLIO_OBJ_SUPPORT=y From b3453c3f7476e9211ca8ea8f9748806a38478b33 Mon Sep 17 00:00:00 2001 From: Chaitanya Tata Date: Thu, 7 Dec 2023 20:50:55 +0530 Subject: [PATCH 0993/3723] wifi: Add an enum for connect result status This can be used to interpret the "status" in the connect result event. To start with a few common reasons are enumerated but can be extended in the future. Signed-off-by: Chaitanya Tata --- include/zephyr/net/wifi_mgmt.h | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/include/zephyr/net/wifi_mgmt.h b/include/zephyr/net/wifi_mgmt.h index faf83b42b84..91c9ad088a8 100644 --- a/include/zephyr/net/wifi_mgmt.h +++ b/include/zephyr/net/wifi_mgmt.h @@ -321,6 +321,22 @@ struct wifi_connect_req_params { int timeout; }; +/** Wi-Fi connect result codes. To be overlaid on top of \ref wifi_status + * in the connect result event for detailed status. + */ +enum wifi_conn_status { + /** Connection successful */ + WIFI_STATUS_CONN_SUCCESS = 0, + /** Connection failed - generic failure */ + WIFI_STATUS_CONN_FAIL, + /** Connection failed - wrong password */ + WIFI_STATUS_CONN_WRONG_PASSWORD, + /** Connection timed out */ + WIFI_STATUS_CONN_TIMEOUT, + /** Connection failed - AP not found */ + WIFI_STATUS_CONN_AP_NOT_FOUND, +}; + /** Generic Wi-Fi status for commands and events */ struct wifi_status { int status; From d8d4c7760367b7c809bf095191cbe6a540465c9b Mon Sep 17 00:00:00 2001 From: Chaitanya Tata Date: Thu, 7 Dec 2023 20:57:14 +0530 Subject: [PATCH 0994/3723] wifi: Add an enum for disconnect reasons This can be used to interpret the "status" in the disconnect result event. To start with a few common reasons are enumerated but can be extended in the future. Signed-off-by: Chaitanya Tata --- include/zephyr/net/wifi_mgmt.h | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/include/zephyr/net/wifi_mgmt.h b/include/zephyr/net/wifi_mgmt.h index 91c9ad088a8..e52cefd2d68 100644 --- a/include/zephyr/net/wifi_mgmt.h +++ b/include/zephyr/net/wifi_mgmt.h @@ -337,6 +337,20 @@ enum wifi_conn_status { WIFI_STATUS_CONN_AP_NOT_FOUND, }; +/** Wi-Fi disconnect reason codes. To be overlaid on top of \ref wifi_status + * in the disconnect result event for detailed reason. + */ +enum wifi_disconn_reason { + /** Unspecified reason */ + WIFI_REASON_DISCONN_UNSPECIFIED = 0, + /** Disconnected due to user request */ + WIFI_REASON_DISCONN_USER_REQUEST, + /** Disconnected due to AP leaving */ + WIFI_REASON_DISCONN_AP_LEAVING, + /** Disconnected due to inactivity */ + WIFI_REASON_DISCONN_INACTIVITY, +}; + /** Generic Wi-Fi status for commands and events */ struct wifi_status { int status; From ceee997c6fbedfb55a97f8bee1ed857c7599850e Mon Sep 17 00:00:00 2001 From: Chaitanya Tata Date: Fri, 8 Dec 2023 12:15:05 +0530 Subject: [PATCH 0995/3723] wifi: Add the enums to the status This helps to demonstrate that the enumerations have to be used to interpret the status. Signed-off-by: Chaitanya Tata --- include/zephyr/net/wifi_mgmt.h | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/include/zephyr/net/wifi_mgmt.h b/include/zephyr/net/wifi_mgmt.h index e52cefd2d68..babf67722c1 100644 --- a/include/zephyr/net/wifi_mgmt.h +++ b/include/zephyr/net/wifi_mgmt.h @@ -353,7 +353,11 @@ enum wifi_disconn_reason { /** Generic Wi-Fi status for commands and events */ struct wifi_status { - int status; + union { + int status; + enum wifi_conn_status conn_status; + enum wifi_disconn_reason disconn_reason; + }; }; /** Wi-Fi interface status */ From 0ebeca2eb7d0303340c32c3a62e34657b4c5615e Mon Sep 17 00:00:00 2001 From: Anas Nashif Date: Thu, 7 Dec 2023 23:00:27 +0000 Subject: [PATCH 0996/3723] intel_adsp: ace: add firmware loading tool Add python script for loading intel_adsp ACE FW into hardware. Signed-off-by: Anas Nashif --- soc/xtensa/intel_adsp/tools/acetool.py | 727 +++++++++++++++++++++++++ 1 file changed, 727 insertions(+) create mode 100755 soc/xtensa/intel_adsp/tools/acetool.py diff --git a/soc/xtensa/intel_adsp/tools/acetool.py b/soc/xtensa/intel_adsp/tools/acetool.py new file mode 100755 index 00000000000..0d0897c0234 --- /dev/null +++ b/soc/xtensa/intel_adsp/tools/acetool.py @@ -0,0 +1,727 @@ +#!/usr/bin/env python3 +# Copyright(c) 2022 Intel Corporation. All rights reserved. +# SPDX-License-Identifier: Apache-2.0 + +import os +import sys +import struct +import logging +import asyncio +import time +import subprocess +import ctypes +import mmap +import argparse + +start_output = True + +logging.basicConfig(level=logging.INFO) +log = logging.getLogger("ace-fw") + +PAGESZ = 4096 +HUGEPAGESZ = 2 * 1024 * 1024 +HUGEPAGE_FILE = "/dev/hugepages/ace-fw-dma.tmp." + +# SRAM windows. Each appears in a 128k region starting at 512k. +# +# Window 0 is the FW_STATUS area, and 4k after that the IPC "outbox" +# Window 1 is the IPC "inbox" (host-writable memory, just 384 bytes currently) +# Window 2 is unused by this script +# Window 3 is winstream-formatted log output +WINDOW_BASE = 0x180000 +WINDOW_STRIDE = 0x8000 + +OUTBOX_OFFSET = (512 + (0 * 128)) * 1024 + 4096 +INBOX_OFFSET = (512 + (1 * 128)) * 1024 +WINSTREAM_OFFSET = WINDOW_BASE + WINDOW_STRIDE*3 + +# ADSPCS bits +CRST = 0 +CSTALL = 8 +SPA = 16 +CPA = 24 + +class HDAStream: + # creates an hda stream with at 2 buffers of buf_len + def __init__(self, stream_id: int): + self.stream_id = stream_id + self.base = hdamem + 0x0080 + (stream_id * 0x20) + log.info(f"Mapping registers for hda stream {self.stream_id} at base {self.base:x}") + + self.hda = Regs(hdamem) + self.hda.GCAP = 0x0000 + self.hda.GCTL = 0x0008 + self.hda.DPLBASE = 0x0070 + self.hda.DPUBASE = 0x0074 + self.hda.SPBFCH = 0x0700 + self.hda.SPBFCTL = 0x0704 + self.hda.PPCH = 0x0800 + self.hda.PPCTL = 0x0804 + self.hda.PPSTS = 0x0808 + self.hda.SPIB = 0x0708 + stream_id*0x08 + self.hda.freeze() + + self.regs = Regs(self.base) + self.regs.CTL = 0x00 + self.regs.STS = 0x03 + self.regs.LPIB = 0x04 + self.regs.CBL = 0x08 + self.regs.LVI = 0x0c + self.regs.FIFOW = 0x0e + self.regs.FIFOS = 0x10 + self.regs.FMT = 0x12 + self.regs.FIFOL= 0x14 + self.regs.BDPL = 0x18 + self.regs.BDPU = 0x1c + self.regs.freeze() + + self.dbg0 = Regs(hdamem + 0x0084 + (0x20*stream_id)) + self.dbg0.DPIB = 0x00 + self.dbg0.EFIFOS = 0x10 + self.dbg0.freeze() + + self.reset() + + def __del__(self): + self.reset() + + def config(self, buf_len: int): + log.info(f"Configuring stream {self.stream_id}") + self.buf_len = buf_len + log.info("Allocating huge page and setting up buffers") + self.mem, self.hugef, self.buf_list_addr, self.pos_buf_addr, self.n_bufs = self.setup_buf(buf_len) + + log.info("Setting buffer list, length, and stream id and traffic priority bit") + self.regs.CTL = ((self.stream_id & 0xFF) << 20) | (1 << 18) # must be set to something other than 0? + self.regs.BDPU = (self.buf_list_addr >> 32) & 0xffffffff + self.regs.BDPL = self.buf_list_addr & 0xffffffff + self.regs.CBL = buf_len + self.regs.LVI = self.n_bufs - 1 + self.mem.seek(0) + self.debug() + log.info(f"Configured stream {self.stream_id}") + + def write(self, data): + + bufl = min(len(data), self.buf_len) + log.info(f"Writing data to stream {self.stream_id}, len {bufl}, SPBFCTL {self.hda.SPBFCTL:x}, SPIB {self.hda.SPIB}") + self.mem[0:bufl] = data[0:bufl] + self.mem[bufl:bufl+bufl] = data[0:bufl] + self.hda.SPBFCTL |= (1 << self.stream_id) + self.hda.SPIB += bufl + log.info(f"Wrote data to stream {self.stream_id}, SPBFCTL {self.hda.SPBFCTL:x}, SPIB {self.hda.SPIB}") + + def start(self): + log.info(f"Starting stream {self.stream_id}, CTL {self.regs.CTL:x}") + self.regs.CTL |= 2 + log.info(f"Started stream {self.stream_id}, CTL {self.regs.CTL:x}") + + def stop(self): + log.info(f"Stopping stream {self.stream_id}, CTL {self.regs.CTL:x}") + self.regs.CTL &= 2 + time.sleep(0.1) + self.regs.CTL |= 1 + log.info(f"Stopped stream {self.stream_id}, CTL {self.regs.CTL:x}") + + def setup_buf(self, buf_len: int): + (mem, phys_addr, hugef) = map_phys_mem(self.stream_id) + + log.info(f"Mapped 2M huge page at 0x{phys_addr:x} for buf size ({buf_len})") + + # create two buffers in the page of buf_len and mark them + # in a buffer descriptor list for the hardware to use + buf0_len = buf_len + buf1_len = buf_len + bdl_off = buf0_len + buf1_len + # bdl is 2 (64bits, 16 bytes) per entry, we have two + mem[bdl_off:bdl_off + 32] = struct.pack("> self.stream_id) & 1, self.regs.CTL, self.regs.LPIB, self.regs.BDPU, + self.regs.BDPL, self.regs.CBL, self.regs.LVI) + log.debug(" FIFOW %d, FIFOS %d, FMT %x, FIFOL %d, DPIB %d, EFIFOS %d", + self.regs.FIFOW & 0x7, self.regs.FIFOS, self.regs.FMT, self.regs.FIFOL, self.dbg0.DPIB, self.dbg0.EFIFOS) + log.debug(" status: FIFORDY %d, DESE %d, FIFOE %d, BCIS %d", + (self.regs.STS >> 5) & 1, (self.regs.STS >> 4) & 1, (self.regs.STS >> 3) & 1, (self.regs.STS >> 2) & 1) + + def reset(self): + # Turn DMA off and reset the stream. Clearing START first is a + # noop per the spec, but absolutely required for stability. + # Apparently the reset doesn't stop the stream, and the next load + # starts before it's ready and kills the load (and often the DSP). + # The sleep too is required, on at least one board (a fast + # chromebook) putting the two writes next each other also hangs + # the DSP! + log.info(f"Resetting stream {self.stream_id}") + self.debug() + self.regs.CTL &= ~2 # clear START + time.sleep(0.1) + # set enter reset bit + self.regs.CTL = 1 + while (self.regs.CTL & 1) == 0: pass + # clear enter reset bit to exit reset + self.regs.CTL = 0 + while (self.regs.CTL & 1) == 1: pass + + log.info(f"Disable SPIB and set position 0 of stream {self.stream_id}") + self.hda.SPBFCTL = 0 + self.hda.SPIB = 0 + + #log.info("Setting dma position buffer and enable it") + #self.hda.DPUBASE = self.pos_buf_addr >> 32 & 0xffffffff + #self.hda.DPLBASE = self.pos_buf_addr & 0xfffffff0 | 1 + + log.info(f"Enabling dsp capture (PROCEN) of stream {self.stream_id}") + self.hda.PPCTL |= (1 << self.stream_id) + + self.debug() + log.info(f"Reset stream {self.stream_id}") + + +def map_regs(): + p = runx(f"grep -iEl 'PCI_CLASS=40(10|38)0' /sys/bus/pci/devices/*/uevent") + pcidir = os.path.dirname(p) + + # Platform/quirk detection. ID lists cribbed from the SOF kernel driver + did = int(open(f"{pcidir}/device").read().rstrip(), 16) + ace15 = did in [ 0x7e28 ] + ace20 = did in [ 0xa828 ] + if ace15: + log.info("Detected MTL hardware") + elif ace20: + log.info("Detected LNL hardware") + + # Check sysfs for a loaded driver and remove it + if os.path.exists(f"{pcidir}/driver"): + mod = os.path.basename(os.readlink(f"{pcidir}/driver/module")) + found_msg = f"Existing driver \"{mod}\" found" + if args.log_only: + log.info(found_msg) + else: + log.warning(found_msg + ", unloading module") + runx(f"rmmod -f {mod}") + # Disengage runtime power management so the kernel doesn't put it to sleep + log.info(f"Forcing {pcidir}/power/control to always 'on'") + with open(f"{pcidir}/power/control", "w") as ctrl: + ctrl.write("on") + + # Make sure PCI memory space access and busmastering are enabled. + # Also disable interrupts so as not to confuse the kernel. + with open(f"{pcidir}/config", "wb+") as cfg: + cfg.seek(4) + cfg.write(b'\x06\x04') + + # Standard HD Audio Registers + global hdamem + (hdamem, _) = bar_map(pcidir, 0) + hda = Regs(hdamem) + hda.GCAP = 0x0000 + hda.GCTL = 0x0008 + hda.SPBFCTL = 0x0704 + hda.PPCTL = 0x0804 + + # Find the ID of the first output stream + hda_ostream_id = (hda.GCAP >> 8) & 0x0f # number of input streams + log.info(f"Selected output stream {hda_ostream_id} (GCAP = 0x{hda.GCAP:x})") + hda.SD_SPIB = 0x0708 + (8 * hda_ostream_id) + hda.freeze() + + + # Standard HD Audio Stream Descriptor + sd = Regs(hdamem + 0x0080 + (hda_ostream_id * 0x20)) + sd.CTL = 0x00 + sd.CBL = 0x08 + sd.LVI = 0x0c + sd.BDPL = 0x18 + sd.BDPU = 0x1c + sd.freeze() + + # Intel ACE Audio DSP Registers + global bar4_mmap + (bar4_mem, bar4_mmap) = bar_map(pcidir, 4) + dsp = Regs(bar4_mem) + dsp.HFDSSCS = 0x1000 + dsp.HFPWRCTL = 0x1d18 + dsp.HFPWRSTS = 0x1d1c + dsp.DSP2CXCTL_PRIMARY = 0x178d04 + dsp.HFIPCXTDR = 0x73200 + dsp.HFIPCXTDA = 0x73204 + dsp.HFIPCXIDR = 0x73210 + dsp.HFIPCXIDA = 0x73214 + dsp.HFIPCXCTL = 0x73228 + dsp.HFIPCXTDDY = 0x73300 + dsp.HFIPCXIDDY = 0x73380 + dsp.SRAM_FW_STATUS = WINDOW_BASE + dsp.freeze() + + return (hda, sd, dsp, hda_ostream_id) + +def setup_dma_mem(fw_bytes): + (mem, phys_addr, _) = map_phys_mem(hda_ostream_id) + mem[0:len(fw_bytes)] = fw_bytes + + log.info("Mapped 2M huge page at 0x%x to contain %d bytes of firmware" + % (phys_addr, len(fw_bytes))) + + # HDA requires at least two buffers be defined, but we don't care about + # boundaries because it's all a contiguous region. Place a vestigial + # 128-byte (minimum size and alignment) buffer after the main one, and put + # the 4-entry BDL list into the final 128 bytes of the page. + buf0_len = HUGEPAGESZ - 2 * 128 + buf1_len = 128 + bdl_off = buf0_len + buf1_len + mem[bdl_off:bdl_off + 32] = struct.pack(" /proc/sys/vm/nr_hugepages") + + hugef_name = HUGEPAGE_FILE + str(stream_id) + hugef = open(hugef_name, "w+") + hugef.truncate(HUGEPAGESZ) + mem = mmap.mmap(hugef.fileno(), HUGEPAGESZ) + log.info("type of mem is %s", str(type(mem))) + global_mmaps.append(mem) + os.unlink(hugef_name) + + # Find the local process address of the mapping, then use that to extract + # the physical address from the kernel's pagemap interface. The physical + # page frame number occupies the bottom bits of the entry. + mem[0] = 0 # Fault the page in so it has an address! + vaddr = ctypes.addressof(ctypes.c_int.from_buffer(mem)) + vpagenum = vaddr >> 12 + pagemap = open("/proc/self/pagemap", "rb") + pagemap.seek(vpagenum * 8) + pent = pagemap.read(8) + paddr = (struct.unpack("Q", pent)[0] & ((1 << 55) - 1)) * PAGESZ + pagemap.close() + return (mem, paddr, hugef) + +# Maps a PCI BAR and returns the in-process address +def bar_map(pcidir, barnum): + f = open(pcidir + "/resource" + str(barnum), "r+") + mm = mmap.mmap(f.fileno(), os.fstat(f.fileno()).st_size) + global_mmaps.append(mm) + log.info("Mapped PCI bar %d of length %d bytes." + % (barnum, os.fstat(f.fileno()).st_size)) + return (ctypes.addressof(ctypes.c_int.from_buffer(mm)), mm) + +# Syntactic sugar to make register block definition & use look nice. +# Instantiate from a base address, assign offsets to (uint32) named registers as +# fields, call freeze(), then the field acts as a direct alias for the register! +class Regs: + def __init__(self, base_addr): + vars(self)["base_addr"] = base_addr + vars(self)["ptrs"] = {} + vars(self)["frozen"] = False + def freeze(self): + vars(self)["frozen"] = True + def __setattr__(self, name, val): + if not self.frozen and name not in self.ptrs: + addr = self.base_addr + val + self.ptrs[name] = ctypes.c_uint32.from_address(addr) + else: + self.ptrs[name].value = val + def __getattr__(self, name): + return self.ptrs[name].value + +def runx(cmd): + return subprocess.check_output(cmd, shell=True).decode().rstrip() + +def load_firmware(fw_file): + try: + fw_bytes = open(fw_file, "rb").read() + # Resize fw_bytes for MTL + if len(fw_bytes) < 512 * 1024: + fw_bytes += b'\x00' * (512 * 1024 - len(fw_bytes)) + except Exception as e: + log.error(f"Could not read firmware file: `{fw_file}'") + log.error(e) + sys.exit(1) + + (magic, sz) = struct.unpack("4sI", fw_bytes[0:8]) + if magic == b'$AE1': + log.info(f"Trimming {sz} bytes of extended manifest") + fw_bytes = fw_bytes[sz:len(fw_bytes)] + + # This actually means "enable access to BAR4 registers"! + hda.PPCTL |= (1 << 30) # GPROCEN, "global processing enable" + + log.info("Resetting HDA device") + hda.GCTL = 0 + while hda.GCTL & 1: pass + hda.GCTL = 1 + while not hda.GCTL & 1: pass + + log.info("Turning of DSP subsystem") + dsp.HFDSSCS &= ~(1 << 16) # clear SPA bit + time.sleep(0.002) + # wait for CPA bit clear + while dsp.HFDSSCS & (1 << 24): + log.info("Waiting for DSP subsystem power off") + time.sleep(0.1) + + log.info("Turning on DSP subsystem") + dsp.HFDSSCS |= (1 << 16) # set SPA bit + time.sleep(0.002) # needed as the CPA bit may be unstable + # wait for CPA bit + while not dsp.HFDSSCS & (1 << 24): + log.info("Waiting for DSP subsystem power on") + time.sleep(0.1) + + log.info("Turning on Domain0") + dsp.HFPWRCTL |= 0x1 # set SPA bit + time.sleep(0.002) # needed as the CPA bit may be unstable + # wait for CPA bit + while not dsp.HFPWRSTS & 0x1: + log.info("Waiting for DSP domain0 power on") + time.sleep(0.1) + + log.info("Turning off Primary Core") + dsp.DSP2CXCTL_PRIMARY &= ~(0x1) # clear SPA + time.sleep(0.002) # wait for CPA settlement + while dsp.DSP2CXCTL_PRIMARY & (1 << 8): + log.info("Waiting for DSP primary core power off") + time.sleep(0.1) + + + log.info(f"Configuring HDA stream {hda_ostream_id} to transfer firmware image") + (buf_list_addr, num_bufs) = setup_dma_mem(fw_bytes) + sd.CTL = 1 + while (sd.CTL & 1) == 0: pass + sd.CTL = 0 + while (sd.CTL & 1) == 1: pass + sd.CTL |= (1 << 20) # Set stream ID to anything non-zero + sd.BDPU = (buf_list_addr >> 32) & 0xffffffff + sd.BDPL = buf_list_addr & 0xffffffff + sd.CBL = len(fw_bytes) + sd.LVI = num_bufs - 1 + hda.PPCTL |= (1 << hda_ostream_id) + + # SPIB ("Software Position In Buffer") is an Intel HDA extension + # that puts a transfer boundary into the stream beyond which the + # other side will not read. The ROM wants to poll on a "buffer + # full" bit on the other side that only works with this enabled. + hda.SPBFCTL |= (1 << hda_ostream_id) + hda.SD_SPIB = len(fw_bytes) + + + # Send the DSP an IPC message to tell the device how to boot. + # Note: with cAVS 1.8+ the ROM receives the stream argument as an + # index within the array of output streams (and we always use the + # first one by construction). But with 1.5 it's the HDA index, + # and depends on the number of input streams on the device. + stream_idx = 0 + ipcval = ( (1 << 31) # BUSY bit + | (0x01 << 24) # type = PURGE_FW + | (1 << 14) # purge_fw = 1 + | (stream_idx << 9)) # dma_id + log.info(f"Sending IPC command, HFIPCXIDR = 0x{ipcval:x}") + dsp.HFIPCXIDR = ipcval + + + log.info("Turning on Primary Core") + dsp.DSP2CXCTL_PRIMARY |= 0x1 # clear SPA + time.sleep(0.002) # wait for CPA settlement + while not dsp.DSP2CXCTL_PRIMARY & (1 << 8): + log.info("Waiting for DSP primary core power on") + time.sleep(0.1) + + log.info("Waiting for IPC acceptance") + while dsp.HFIPCXIDR & (1 << 31): + log.info("Waiting for IPC busy bit clear") + time.sleep(0.1) + + log.info("ACK IPC") + dsp.HFIPCXIDA |= (1 << 31) + + log.info(f"Starting DMA, FW_STATUS = 0x{dsp.SRAM_FW_STATUS:x}") + sd.CTL |= 2 # START flag + + wait_fw_entered() + + # Turn DMA off and reset the stream. Clearing START first is a + # noop per the spec, but absolutely required for stability. + # Apparently the reset doesn't stop the stream, and the next load + # starts before it's ready and kills the load (and often the DSP). + # The sleep too is required, on at least one board (a fast + # chromebook) putting the two writes next each other also hangs + # the DSP! + sd.CTL &= ~2 # clear START + time.sleep(0.1) + sd.CTL |= 1 + log.info(f"cAVS firmware load complete") + +def fw_is_alive(): + return dsp.SRAM_FW_STATUS & ((1 << 28) - 1) == 5 # "FW_ENTERED" + +def wait_fw_entered(timeout_s=2): + log.info("Waiting %s for firmware handoff, FW_STATUS = 0x%x", + "forever" if timeout_s is None else f"{timeout_s} seconds", + dsp.SRAM_FW_STATUS) + hertz = 100 + attempts = None if timeout_s is None else timeout_s * hertz + while True: + alive = fw_is_alive() + if alive: + break + if attempts is not None: + attempts -= 1 + if attempts < 0: + break + time.sleep(1 / hertz) + + if not alive: + log.warning("Load failed? FW_STATUS = 0x%x", dsp.SRAM_FW_STATUS) + else: + log.info("FW alive, FW_STATUS = 0x%x", dsp.SRAM_FW_STATUS) + + +# This SHOULD be just "mem[start:start+length]", but slicing an mmap +# array seems to be unreliable on one of my machines (python 3.6.9 on +# Ubuntu 18.04). Read out bytes individually. +def win_read(start, length): + try: + return b''.join(bar4_mmap[WINSTREAM_OFFSET + x].to_bytes(1, 'little') + for x in range(start, start + length)) + except IndexError as ie: + # A FW in a bad state may cause winstream garbage + log.error("IndexError in bar4_mmap[%d + %d]", WINSTREAM_OFFSET, start) + log.error("bar4_mmap.size()=%d", bar4_mmap.size()) + raise ie + +def win_hdr(): + return struct.unpack(" ((end - start) % wlen): + return (seq, "") + copy = (end - behind) % wlen + suffix = min(behind, wlen - copy) + result = win_read(16 + copy, suffix) + if suffix < behind: + result += win_read(16, behind - suffix) + (wlen, start1, end, seq1) = win_hdr() + if start1 == start and seq1 == seq: + # Best effort attempt at decoding, replacing unusable characters + # Found to be useful when it really goes wrong + return (seq, result.decode("utf-8", "replace")) + + +async def ipc_delay_done(): + await asyncio.sleep(0.1) + dsp.HFIPCXTDA = ~(1<<31) & dsp.HFIPCXTDA # Signal done + + +ipc_timestamp = 0 + +# Super-simple command language, driven by the test code on the DSP +def ipc_command(data, ext_data): + send_msg = False + done = True + log.debug ("ipc data %d, ext_data %x", data, ext_data) + if data == 0: # noop, with synchronous DONE + pass + elif data == 1: # async command: signal DONE after a delay (on 1.8+) + done = False + asyncio.ensure_future(ipc_delay_done()) + elif data == 2: # echo back ext_data as a message command + send_msg = True + elif data == 3: # set ADSPCS + dsp.ADSPCS = ext_data + elif data == 4: # echo back microseconds since last timestamp command + global ipc_timestamp + t = round(time.time() * 1e6) + ext_data = t - ipc_timestamp + ipc_timestamp = t + send_msg = True + elif data == 5: # copy word at outbox[ext_data >> 16] to inbox[ext_data & 0xffff] + src = OUTBOX_OFFSET + 4 * (ext_data >> 16) + dst = INBOX_OFFSET + 4 * (ext_data & 0xffff) + for i in range(4): + bar4_mmap[dst + i] = bar4_mmap[src + i] + elif data == 6: # HDA RESET (init if not exists) + stream_id = ext_data & 0xff + if stream_id in hda_streams: + hda_streams[stream_id].reset() + else: + hda_str = HDAStream(stream_id) + hda_streams[stream_id] = hda_str + elif data == 7: # HDA CONFIG + stream_id = ext_data & 0xFF + buf_len = ext_data >> 8 & 0xFFFF + hda_str = hda_streams[stream_id] + hda_str.config(buf_len) + elif data == 8: # HDA START + stream_id = ext_data & 0xFF + hda_streams[stream_id].start() + hda_streams[stream_id].mem.seek(0) + + elif data == 9: # HDA STOP + stream_id = ext_data & 0xFF + hda_streams[stream_id].stop() + elif data == 10: # HDA VALIDATE + stream_id = ext_data & 0xFF + hda_str = hda_streams[stream_id] + hda_str.debug() + is_ramp_data = True + hda_str.mem.seek(0) + for (i, val) in enumerate(hda_str.mem.read(256)): + if i != val: + is_ramp_data = False + # log.info("stream[%d][%d]: %d", stream_id, i, val) # debug helper + log.info("Is ramp data? " + str(is_ramp_data)) + ext_data = int(is_ramp_data) + log.info(f"Ext data to send back on ramp status {ext_data}") + send_msg = True + elif data == 11: # HDA HOST OUT SEND + stream_id = ext_data & 0xff + buf = bytearray(256) + for i in range(0, 256): + buf[i] = i + hda_streams[stream_id].write(buf) + elif data == 12: # HDA PRINT + stream_id = ext_data & 0xFF + buf_len = ext_data >> 8 & 0xFFFF + hda_str = hda_streams[stream_id] + # check for wrap here + pos = hda_str.mem.tell() + read_lens = [buf_len, 0] + if pos + buf_len >= hda_str.buf_len*2: + read_lens[0] = hda_str.buf_len*2 - pos + read_lens[1] = buf_len - read_lens[0] + # validate the read lens + assert (read_lens[0] + pos) <= (hda_str.buf_len*2) + assert read_lens[0] % 128 == 0 + assert read_lens[1] % 128 == 0 + buf_data0 = hda_str.mem.read(read_lens[0]) + hda_msg0 = buf_data0.decode("utf-8", "replace") + sys.stdout.write(hda_msg0) + if read_lens[1] != 0: + hda_str.mem.seek(0) + buf_data1 = hda_str.mem.read(read_lens[1]) + hda_msg1 = buf_data1.decode("utf-8", "replace") + sys.stdout.write(hda_msg1) + pos = hda_str.mem.tell() + sys.stdout.flush() + else: + log.warning(f"acetool: Unrecognized IPC command 0x{data:x} ext 0x{ext_data:x}") + if not fw_is_alive(): + if args.log_only: + log.info("DSP power seems off") + wait_fw_entered(timeout_s=None) + else: + log.warning("DSP power seems off?!") + time.sleep(2) # potential spam reduction + + return + + dsp.HFIPCXTDR = 1<<31 # Ack local interrupt, also signals DONE on v1.5 + if done: + dsp.HFIPCXTDA = ~(1<<31) & dsp.HFIPCXTDA # Signal done + if send_msg: + log.debug("ipc: sending msg 0x%08x" % ext_data) + dsp.HFIPCXIDDY = ext_data + dsp.HFIPCXIDR = (1<<31) | ext_data + +async def main(): + #TODO this bit me, remove the globals, write a little FirmwareLoader class or something to contain. + global hda, sd, dsp, hda_ostream_id, hda_streams + + try: + (hda, sd, dsp, hda_ostream_id) = map_regs() + except Exception as e: + log.error("Could not map device in sysfs; run as root?") + log.error(e) + sys.exit(1) + + if args.log_only: + wait_fw_entered(timeout_s=None) + else: + if not args.fw_file: + log.error("Firmware file argument missing") + sys.exit(1) + + load_firmware(args.fw_file) + time.sleep(0.1) + if not args.quiet: + sys.stdout.write("--\n") + + hda_streams = dict() + + last_seq = 0 + while start_output is True: + await asyncio.sleep(0.03) + (last_seq, output) = winstream_read(last_seq) + if output: + sys.stdout.write(output) + sys.stdout.flush() + if not args.log_only: + if dsp.HFIPCXIDA & 0x80000000: + log.debug("ipc: Ack DSP reply with IDA_DONE") + dsp.HFIPCXIDA = 1<<31 # must ACK any DONE interrupts that arrive! + if dsp.HFIPCXTDR & 0x80000000: + ipc_command(dsp.HFIPCXTDR & ~0x80000000, dsp.HFIPCXTDDY) + + +ap = argparse.ArgumentParser(description="DSP loader/logger tool", allow_abbrev=False) +ap.add_argument("-q", "--quiet", action="store_true", + help="No loader output, just DSP logging") +ap.add_argument("-v", "--verbose", action="store_true", + help="More loader output, DEBUG logging level") +ap.add_argument("-l", "--log-only", action="store_true", + help="Don't load firmware, just show log output") +ap.add_argument("-n", "--no-history", action="store_true", + help="No current log buffer at start, just new output") +ap.add_argument("fw_file", nargs="?", help="Firmware file") + +args = ap.parse_args() + +if args.quiet: + log.setLevel(logging.WARN) +elif args.verbose: + log.setLevel(logging.DEBUG) + +if __name__ == "__main__": + try: + asyncio.get_event_loop().run_until_complete(main()) + except KeyboardInterrupt: + start_output = False From 54573e7c4c77b5b9311108d19c8d9543e3f0b936 Mon Sep 17 00:00:00 2001 From: Yong Cong Sin Date: Mon, 11 Dec 2023 13:06:53 +0800 Subject: [PATCH 0997/3723] boards: arm: Add RTC clock source for mikroe_mini_m4_for_stm32 The `mikroe_mini_m4_for_stm32` board doesn't have its RTC node enabled, and is failing the following test: `tests/benchmarks/footprints/benchmark.kernel.footprints.pm` This board seems to have been missed out from 44b8370, let's enable the rtc & clk_lsi here. Signed-off-by: Yong Cong Sin --- .../mikroe_mini_m4_for_stm32.dts | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/boards/arm/mikroe_mini_m4_for_stm32/mikroe_mini_m4_for_stm32.dts b/boards/arm/mikroe_mini_m4_for_stm32/mikroe_mini_m4_for_stm32.dts index 60f270855a7..e9d3b46d3b4 100644 --- a/boards/arm/mikroe_mini_m4_for_stm32/mikroe_mini_m4_for_stm32.dts +++ b/boards/arm/mikroe_mini_m4_for_stm32/mikroe_mini_m4_for_stm32.dts @@ -38,6 +38,10 @@ }; }; +&clk_lsi { + status = "okay"; +}; + &clk_hse { clock-frequency = ; status = "okay"; @@ -99,3 +103,9 @@ zephyr_udc0: &usbotg_fs { &cryp { status = "okay"; }; + +&rtc { + clocks = <&rcc STM32_CLOCK_BUS_APB1 0x10000000>, + <&rcc STM32_SRC_LSI RTC_SEL(2)>; + status = "okay"; +}; From 51b3420b803ac174f7e62ae1b143e8c58bc61cb8 Mon Sep 17 00:00:00 2001 From: Daniel Leung Date: Thu, 7 Dec 2023 15:31:46 -0800 Subject: [PATCH 0998/3723] doc: doxygen: move float_apis group into correct place The float_apis group is incorrectly placed in x86/32 header. This should be in kernel.h enclosing k_float_* functions. So move it. Signed-off-by: Daniel Leung --- include/zephyr/arch/x86/ia32/arch.h | 12 ------------ include/zephyr/kernel.h | 10 ++++++++++ 2 files changed, 10 insertions(+), 12 deletions(-) diff --git a/include/zephyr/arch/x86/ia32/arch.h b/include/zephyr/arch/x86/ia32/arch.h index e4bc3c5dba9..bd6ae1ed040 100644 --- a/include/zephyr/arch/x86/ia32/arch.h +++ b/include/zephyr/arch/x86/ia32/arch.h @@ -397,18 +397,6 @@ static ALWAYS_INLINE unsigned int arch_irq_lock(void) */ #define NANO_SOFT_IRQ ((unsigned int) (-1)) -/** - * @defgroup float_apis Floating Point APIs - * @ingroup kernel_apis - * @{ - */ - -struct k_thread; - -/** - * @} - */ - #ifdef CONFIG_X86_ENABLE_TSS extern struct task_state_segment _main_tss; #endif diff --git a/include/zephyr/kernel.h b/include/zephyr/kernel.h index 7f62ef1e768..c7840420b9c 100644 --- a/include/zephyr/kernel.h +++ b/include/zephyr/kernel.h @@ -5964,6 +5964,12 @@ void z_timer_expiration_handler(struct _timeout *t); __syscall void k_str_out(char *c, size_t n); #endif +/** + * @defgroup float_apis Floating Point APIs + * @ingroup kernel_apis + * @{ + */ + /** * @brief Disable preservation of floating point context information. * @@ -6026,6 +6032,10 @@ __syscall int k_float_disable(struct k_thread *thread); */ __syscall int k_float_enable(struct k_thread *thread, unsigned int options); +/** + * @} + */ + /** * @brief Get the runtime statistics of a thread * From 3e456e8cfb9598f9ca4ec98ff43f5788fae8b5db Mon Sep 17 00:00:00 2001 From: Bryan Zhu Date: Fri, 8 Dec 2023 16:31:29 +0800 Subject: [PATCH 0999/3723] drivers: serial: pl011: Remove busy wait in Ambiq UART initiate Ambiq UART requires specific busy wait during initialization for propagating powering control registers, original k_busy_wait() used here generated a dead loop because k_busy_wait() relays on timer, who's driver is initialized after UART(UART init in PRE_KERNEL_1, timer init in PRE_KERNEL_2), replace k_busy_wait() with checking power status register is more suitable here. Signed-off-by: Bryan Zhu --- drivers/serial/uart_pl011_ambiq.h | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/drivers/serial/uart_pl011_ambiq.h b/drivers/serial/uart_pl011_ambiq.h index 2223cbed577..470e0e35a95 100644 --- a/drivers/serial/uart_pl011_ambiq.h +++ b/drivers/serial/uart_pl011_ambiq.h @@ -50,9 +50,9 @@ static inline int clk_enable_ambiq_uart(const struct device *dev, uint32_t clk) return pl011_ambiq_clk_set(dev, clk); } -/* Problem: writes to pwrcfg reg take at most PWCTRL_MAX_WAIT_US time to propagate. - * Solution: busy wait for PWCTRL_MAX_WAIT_US microseconds to ensure that register - * writes have propagated. +/* Problem: writes to power configure register takes some time to take effective. + * Solution: Check device's power status to ensure that register has taken effective. + * Note: busy wait is not allowed to use here due to UART is initiated before timer starts. */ #define QUIRK_AMBIQ_UART_DEFINE(n) \ @@ -60,8 +60,12 @@ static inline int clk_enable_ambiq_uart(const struct device *dev, uint32_t clk) { \ uint32_t addr = DT_REG_ADDR(DT_INST_PHANDLE(n, ambiq_pwrcfg)) + \ DT_INST_PHA(n, ambiq_pwrcfg, offset); \ + uint32_t pwr_status_addr = addr + 4; \ sys_write32((sys_read32(addr) | DT_INST_PHA(n, ambiq_pwrcfg, mask)), addr); \ - k_busy_wait(PWRCTRL_MAX_WAIT_US); \ + while ((sys_read32(pwr_status_addr) & DT_INST_PHA(n, ambiq_pwrcfg, mask)) != \ + DT_INST_PHA(n, ambiq_pwrcfg, mask)) { \ + arch_nop(); \ + }; \ return 0; \ } From 22f751658dc0bbe5a83c0d1bbfc9ad4c30f4bfcd Mon Sep 17 00:00:00 2001 From: Marc Herbert Date: Fri, 8 Dec 2023 07:18:08 +0000 Subject: [PATCH 1000/3723] boards: xtensa: docs: rimage is no more a separate git repository Fix intel_adsp_generic.rst following the merge of the rimage git repository back into the sof git repository: - https://github.com/thesofproject/sof/issues/7270 Signed-off-by: Marc Herbert --- .../doc/intel_adsp_generic.rst | 25 ++++++------------- 1 file changed, 7 insertions(+), 18 deletions(-) diff --git a/boards/xtensa/intel_adsp_cavs25/doc/intel_adsp_generic.rst b/boards/xtensa/intel_adsp_cavs25/doc/intel_adsp_generic.rst index 737cdbee05b..fe97ed6466a 100644 --- a/boards/xtensa/intel_adsp_cavs25/doc/intel_adsp_generic.rst +++ b/boards/xtensa/intel_adsp_cavs25/doc/intel_adsp_generic.rst @@ -64,9 +64,10 @@ you will also need to set up the SOF rimage signing tool and key. .. code-block:: shell - cd zephyrproject/modules/audio/sof/ - git clone https://github.com/thesofproject/rimage --recurse-submodules - cd rimage + cd zephyrproject + west config manifest.project-filter -- +sof + west update + cd modules/audio/sof/tools/rimage Follow the instructions in the rimage :file:`README.md` to build the tool on your system. You can either copy the executable to a directory in your PATH or @@ -74,21 +75,9 @@ use ``west config rimage.path /path/to/rimage-build/rimage``; see more details in the output of ``west sign -h``. Running directly from the build directory makes you less likely to use an obsolete rimage version by mistake. -Until https://github.com/zephyrproject-rtos/zephyr/issues/58212 gets -implemented, you must manually and regularly update and rebuild rimage. - -The SOF project does not require this manual step because its west manifest -automatically downloads and builds a specific rimage version validated with -matching SOF sources. An indirect Zephyr -> SOF -> rimage dependency chain is -unfortunately not appropriate because unlike rimage, SOF is *not* required to -run Zephyr on cAVS/ACE hardware. - -Until https://github.com/thesofproject/sof/issues/7270 is implemented, -platform-specific configuration files are also located in the rimage -repository, more specifically in the ``rimage/config/`` subdirectory; this is -another reason to update rimage regularly. If you cloned rimage in a location -different from above (not recommended) then you must also run ``west config -build.cmake-args -- -DRIMAGE_CONFIG_PATH=/path/to/source/rimage/config``. +Platform-specific configuration files are located in the ``rimage/config/`` +subdirectory. For a different configuration directory you can use: +``west config build.cmake-args -- -DRIMAGE_CONFIG_PATH=/path/to/my/rimage/config``. Xtensa Toolchain (Optional) From 694fa3c293fb2c01f8abe98fd8a6aca7c6a3bd33 Mon Sep 17 00:00:00 2001 From: Yuval Peress Date: Fri, 8 Dec 2023 02:39:04 -0700 Subject: [PATCH 1001/3723] rtio: Fix i2c implementation - Allow non RTIO i2c drivers to be intermixed with RTIO drivers - Remove reference to rtio_spsc_drop_all() - Fix impllicit cast which throws an error with more restrictive compile flags Signed-off-by: Yuval Peress --- drivers/i2c/CMakeLists.txt | 12 ++++++------ drivers/i2c/i2c_rtio.c | 2 +- include/zephyr/drivers/i2c.h | 2 +- 3 files changed, 8 insertions(+), 8 deletions(-) diff --git a/drivers/i2c/CMakeLists.txt b/drivers/i2c/CMakeLists.txt index 406ce5dd4c5..fe96c112202 100644 --- a/drivers/i2c/CMakeLists.txt +++ b/drivers/i2c/CMakeLists.txt @@ -6,10 +6,7 @@ zephyr_library() zephyr_library_sources(i2c_common.c) -if(CONFIG_I2C_RTIO) -zephyr_library_sources(i2c_rtio.c) -zephyr_library_sources_ifdef(CONFIG_I2C_SAM_TWIHS i2c_sam_twihs_rtio.c) -else() +zephyr_library_sources_ifdef(CONFIG_I2C_RTIO i2c_rtio.c) zephyr_library_sources_ifdef(CONFIG_I2C_SHELL i2c_shell.c) zephyr_library_sources_ifdef(CONFIG_I2C_BITBANG i2c_bitbang.c) zephyr_library_sources_ifdef(CONFIG_I2C_TELINK_B91 i2c_b91.c) @@ -29,7 +26,11 @@ zephyr_library_sources_ifdef(CONFIG_I2C_EMUL i2c_emul.c) zephyr_library_sources_ifdef(CONFIG_I2C_NRFX_TWI i2c_nrfx_twi.c) zephyr_library_sources_ifdef(CONFIG_I2C_NRFX_TWIM i2c_nrfx_twim.c) zephyr_library_sources_ifdef(CONFIG_I2C_SAM_TWI i2c_sam_twi.c) -zephyr_library_sources_ifdef(CONFIG_I2C_SAM_TWIHS i2c_sam_twihs.c) +if(CONFIG_RTIO) + zephyr_library_sources_ifdef(CONFIG_I2C_SAM_TWIHS i2c_sam_twihs_rtio.c) +else() + zephyr_library_sources_ifdef(CONFIG_I2C_SAM_TWIHS i2c_sam_twihs.c) +endif() zephyr_library_sources_ifdef(CONFIG_I2C_SAM_TWIM i2c_sam4l_twim.c) zephyr_library_sources_ifdef(CONFIG_I2C_SBCON i2c_sbcon.c) zephyr_library_sources_ifdef(CONFIG_I2C_SIFIVE i2c_sifive.c) @@ -65,7 +66,6 @@ zephyr_library_sources_ifdef(CONFIG_I2C_STM32_V2 i2c_ll_stm32_v2.c i2c_ll_stm32.c ) -endif() zephyr_library_sources_ifdef(CONFIG_I2C_TEST i2c_test.c) diff --git a/drivers/i2c/i2c_rtio.c b/drivers/i2c/i2c_rtio.c index 7e74329612d..6c02837065d 100644 --- a/drivers/i2c/i2c_rtio.c +++ b/drivers/i2c/i2c_rtio.c @@ -26,7 +26,7 @@ struct rtio_sqe *i2c_rtio_copy(struct rtio *r, sqe = rtio_sqe_acquire(r); if (sqe == NULL) { - rtio_spsc_drop_all(r->sq); + rtio_sqe_drop_all(r); return NULL; } diff --git a/include/zephyr/drivers/i2c.h b/include/zephyr/drivers/i2c.h index f0268322ecb..ea0036eb3de 100644 --- a/include/zephyr/drivers/i2c.h +++ b/include/zephyr/drivers/i2c.h @@ -972,7 +972,7 @@ static inline int i2c_transfer_signal(const struct device *dev, */ static inline void i2c_iodev_submit(struct rtio_iodev_sqe *iodev_sqe) { - const struct i2c_dt_spec *dt_spec = iodev_sqe->sqe->iodev->data; + const struct i2c_dt_spec *dt_spec = (const struct i2c_dt_spec *)iodev_sqe->sqe.iodev->data; const struct device *dev = dt_spec->bus; const struct i2c_driver_api *api = (const struct i2c_driver_api *)dev->api; From a150380d656a5a08f7d33925f2464e91255b66eb Mon Sep 17 00:00:00 2001 From: Robert Lubos Date: Fri, 8 Dec 2023 10:54:13 +0100 Subject: [PATCH 1002/3723] net: tcp: Implement Keep-alive support When a TCP connection is established, if there is no data exchange between the two parties within the set time, the side that enables TCP Keep-alive will send a TCP probe packet with the same sequence number as the previous TCP packet. This TCP probe packet is an empty ACK packet (the specification recommends that it should not contain any data, but can also contain 1 nonsense byte, such as 0x00.). If there is no response from the other side after several consecutive probe packets are sent, it is determined that the tcp connection has failed, and the connection is closed. The keep-alive default parameters are aligned with Linux defaults. Signed-off-by: Horse Ma Signed-off-by: Robert Lubos --- include/zephyr/net/socket.h | 8 +- subsys/net/ip/Kconfig | 32 ++++ subsys/net/ip/tcp.c | 265 +++++++++++++++++++++++++++++++ subsys/net/ip/tcp_internal.h | 4 + subsys/net/ip/tcp_private.h | 12 ++ subsys/net/lib/sockets/sockets.c | 84 ++++++++++ 6 files changed, 404 insertions(+), 1 deletion(-) diff --git a/include/zephyr/net/socket.h b/include/zephyr/net/socket.h index 5336f11e886..7be9faa68f1 100644 --- a/include/zephyr/net/socket.h +++ b/include/zephyr/net/socket.h @@ -1054,7 +1054,7 @@ struct ifreq { /** sockopt: Size of socket recv buffer */ #define SO_RCVBUF 8 -/** sockopt: Enable sending keep-alive messages on connections (ignored, for compatibility) */ +/** Enable sending keep-alive messages on connections */ #define SO_KEEPALIVE 9 /** sockopt: Place out-of-band data into receive stream (ignored, for compatibility) */ #define SO_OOBINLINE 10 @@ -1095,6 +1095,12 @@ struct ifreq { /* Socket options for IPPROTO_TCP level */ /** sockopt: Disable TCP buffering (ignored, for compatibility) */ #define TCP_NODELAY 1 +/** Start keepalives after this period (seconds) */ +#define TCP_KEEPIDLE 2 +/** Interval between keepalives (seconds) */ +#define TCP_KEEPINTVL 3 +/** Number of keepalives before dropping connection */ +#define TCP_KEEPCNT 4 /* Socket options for IPPROTO_IP level */ /** sockopt: Set or receive the Type-Of-Service value for an outgoing packet. */ diff --git a/subsys/net/ip/Kconfig b/subsys/net/ip/Kconfig index 1f78eaaf839..72562b7645d 100644 --- a/subsys/net/ip/Kconfig +++ b/subsys/net/ip/Kconfig @@ -547,6 +547,38 @@ config NET_TCP_PKT_ALLOC_TIMEOUT This value indicates how long the stack should wait for the packet to be allocated, before returning an internal error and trying again. +config NET_TCP_KEEPALIVE + bool "TCP keep-alive support" + depends on NET_TCP + help + Enabling this option allows the TCP stack to send periodic TCP + keep-alive probes. Enables SO_KEEPALIVE, TCP_KEEPIDLE, TCP_KEEPINTVL + and TCP_KEEPCNT options processing. + +config NET_TCP_KEEPIDLE_DEFAULT + int "TCP_KEEPIDLE default value" + depends on NET_TCP_KEEPALIVE + default 7200 + help + The time (in seconds) the connection needs to remain idle before TCP + starts sending keepalive probes, if the socket option SO_KEEPALIVE has + been set on this socket. + +config NET_TCP_KEEPINTVL_DEFAULT + int "TCP_KEEPINTVL default value" + depends on NET_TCP_KEEPALIVE + default 75 + help + The time (in seconds) between individual keepalive probes. + +config NET_TCP_KEEPCNT_DEFAULT + int "TCP_KEEPCNT default value" + depends on NET_TCP_KEEPALIVE + default 9 + help + The maximum number of keepalive probes TCP should send before dropping + the connection. + config NET_TCP_WORKQ_STACK_SIZE int "TCP work queue thread stack size" default 1200 if X86 diff --git a/subsys/net/ip/tcp.c b/subsys/net/ip/tcp.c index 3662240ca60..50972a9211b 100644 --- a/subsys/net/ip/tcp.c +++ b/subsys/net/ip/tcp.c @@ -507,6 +507,194 @@ static void tcp_ca_pkts_acked(struct tcp *conn, uint32_t acked_len) { } #endif +#if defined(CONFIG_NET_TCP_KEEPALIVE) + +static void tcp_send_keepalive_probe(struct k_work *work); + +static void keep_alive_timer_init(struct tcp *conn) +{ + conn->keep_alive = false; + conn->keep_idle = CONFIG_NET_TCP_KEEPIDLE_DEFAULT; + conn->keep_intvl = CONFIG_NET_TCP_KEEPINTVL_DEFAULT; + conn->keep_cnt = CONFIG_NET_TCP_KEEPCNT_DEFAULT; + NET_DBG("keepalive timer init idle = %d, interval = %d, cnt = %d", + conn->keep_idle, conn->keep_intvl, conn->keep_cnt); + k_work_init_delayable(&conn->keepalive_timer, tcp_send_keepalive_probe); +} + +static void keep_alive_param_copy(struct tcp *to, struct tcp *from) +{ + to->keep_alive = from->keep_alive; + to->keep_idle = from->keep_idle; + to->keep_intvl = from->keep_intvl; + to->keep_cnt = from->keep_cnt; +} + +static void keep_alive_timer_restart(struct tcp *conn) +{ + if (!conn->keep_alive || conn->state != TCP_ESTABLISHED) { + return; + } + + conn->keep_cur = 0; + k_work_reschedule_for_queue(&tcp_work_q, &conn->keepalive_timer, + K_SECONDS(conn->keep_idle)); +} + +static void keep_alive_timer_stop(struct tcp *conn) +{ + k_work_cancel_delayable(&conn->keepalive_timer); +} + +static int set_tcp_keep_alive(struct tcp *conn, const void *value, size_t len) +{ + int keep_alive; + + if (conn == NULL || value == NULL || len != sizeof(int)) { + return -EINVAL; + } + + keep_alive = *(int *)value; + if ((keep_alive < 0) || (keep_alive > 1)) { + return -EINVAL; + } + + conn->keep_alive = (bool)keep_alive; + + if (keep_alive) { + keep_alive_timer_restart(conn); + } else { + keep_alive_timer_stop(conn); + } + + return 0; +} + +static int set_tcp_keep_idle(struct tcp *conn, const void *value, size_t len) +{ + int keep_idle; + + if (conn == NULL || value == NULL || len != sizeof(int)) { + return -EINVAL; + } + + keep_idle = *(int *)value; + if (keep_idle < 1) { + return -EINVAL; + } + + conn->keep_idle = keep_idle; + + keep_alive_timer_restart(conn); + + return 0; +} + +static int set_tcp_keep_intvl(struct tcp *conn, const void *value, size_t len) +{ + int keep_intvl; + + if (conn == NULL || value == NULL || len != sizeof(int)) { + return -EINVAL; + } + + keep_intvl = *(int *)value; + if (keep_intvl < 1) { + return -EINVAL; + } + + conn->keep_intvl = keep_intvl; + + keep_alive_timer_restart(conn); + + return 0; +} + +static int set_tcp_keep_cnt(struct tcp *conn, const void *value, size_t len) +{ + int keep_cnt; + + if (conn == NULL || value == NULL || len != sizeof(int)) { + return -EINVAL; + } + + keep_cnt = *(int *)value; + if (keep_cnt < 1) { + return -EINVAL; + } + + conn->keep_cnt = keep_cnt; + + keep_alive_timer_restart(conn); + + return 0; +} + +static int get_tcp_keep_alive(struct tcp *conn, void *value, size_t *len) +{ + if (conn == NULL || value == NULL || len == NULL || + *len != sizeof(int)) { + return -EINVAL; + } + + *((int *)value) = (int)conn->keep_alive; + + return 0; +} + +static int get_tcp_keep_idle(struct tcp *conn, void *value, size_t *len) +{ + if (conn == NULL || value == NULL || len == NULL || + *len != sizeof(int)) { + return -EINVAL; + } + + *((int *)value) = (int)conn->keep_idle; + + return 0; +} + +static int get_tcp_keep_intvl(struct tcp *conn, void *value, size_t *len) +{ + if (conn == NULL || value == NULL || len == NULL || + *len != sizeof(int)) { + return -EINVAL; + } + + *((int *)value) = (int)conn->keep_intvl; + + return 0; +} + +static int get_tcp_keep_cnt(struct tcp *conn, void *value, size_t *len) +{ + if (conn == NULL || value == NULL || len == NULL || + *len != sizeof(int)) { + return -EINVAL; + } + + *((int *)value) = (int)conn->keep_cnt; + + return 0; +} + +#else /* CONFIG_NET_TCP_KEEPALIVE */ + +#define keep_alive_timer_init(...) +#define keep_alive_param_copy(...) +#define keep_alive_timer_restart(...) +#define keep_alive_timer_stop(...) +#define set_tcp_keep_alive(...) (-ENOPROTOOPT) +#define set_tcp_keep_idle(...) (-ENOPROTOOPT) +#define set_tcp_keep_intvl(...) (-ENOPROTOOPT) +#define set_tcp_keep_cnt(...) (-ENOPROTOOPT) +#define get_tcp_keep_alive(...) (-ENOPROTOOPT) +#define get_tcp_keep_idle(...) (-ENOPROTOOPT) +#define get_tcp_keep_intvl(...) (-ENOPROTOOPT) +#define get_tcp_keep_cnt(...) (-ENOPROTOOPT) + +#endif /* CONFIG_NET_TCP_KEEPALIVE */ + static void tcp_send_queue_flush(struct tcp *conn) { struct net_pkt *pkt; @@ -562,6 +750,7 @@ static void tcp_conn_release(struct k_work *work) (void)k_work_cancel_delayable(&conn->ack_timer); (void)k_work_cancel_delayable(&conn->send_timer); (void)k_work_cancel_delayable(&conn->recv_queue_timer); + keep_alive_timer_stop(conn); k_mutex_unlock(&conn->lock); @@ -623,6 +812,7 @@ static int tcp_conn_close(struct tcp *conn, int status) #endif k_mutex_lock(&conn->lock, K_FOREVER); conn_state(conn, TCP_CLOSED); + keep_alive_timer_stop(conn); k_mutex_unlock(&conn->lock); if (conn->in_connect) { @@ -1603,6 +1793,8 @@ static void tcp_resend_data(struct k_work *work) conn_seq(conn, + 1); } + keep_alive_timer_stop(conn); + goto out; } } else if (ret == -ENODATA) { @@ -1669,6 +1861,39 @@ static void tcp_fin_timeout(struct k_work *work) (void)tcp_conn_close(conn, -ETIMEDOUT); } +#if defined(CONFIG_NET_TCP_KEEPALIVE) +static void tcp_send_keepalive_probe(struct k_work *work) +{ + struct k_work_delayable *dwork = k_work_delayable_from_work(work); + struct tcp *conn = CONTAINER_OF(dwork, struct tcp, keepalive_timer); + + if (conn->state != TCP_ESTABLISHED) { + NET_DBG("conn: %p TCP connection not established", conn); + return; + } + + if (!conn->keep_alive) { + NET_DBG("conn: %p keepalive is not enabled", conn); + return; + } + + conn->keep_cur++; + if (conn->keep_cur > conn->keep_cnt) { + NET_DBG("conn: %p keepalive probe failed multiple times", + conn); + tcp_conn_close(conn, -ETIMEDOUT); + return; + } + + NET_DBG("conn: %p keepalive probe", conn); + k_work_reschedule_for_queue(&tcp_work_q, &conn->keepalive_timer, + K_SECONDS(conn->keep_intvl)); + + + (void)tcp_out_ext(conn, ACK, NULL, conn->seq - 1); +} +#endif /* CONFIG_NET_TCP_KEEPALIVE */ + static void tcp_send_zwp(struct k_work *work) { struct k_work_delayable *dwork = k_work_delayable_from_work(work); @@ -1784,6 +2009,7 @@ static struct tcp *tcp_conn_alloc(void) k_work_init_delayable(&conn->persist_timer, tcp_send_zwp); k_work_init_delayable(&conn->ack_timer, tcp_send_ack); k_work_init(&conn->conn_release, tcp_conn_release); + keep_alive_timer_init(conn); tcp_conn_ref(conn); @@ -2569,6 +2795,7 @@ static enum net_verdict tcp_in(struct tcp *conn, struct net_pkt *pkt) if (conn->accepted_conn != NULL) { accept_cb = conn->accepted_conn->accept_cb; context = conn->accepted_conn->context; + keep_alive_param_copy(conn, conn->accepted_conn); } k_work_cancel_delayable(&conn->establish_timer); @@ -2591,6 +2818,8 @@ static enum net_verdict tcp_in(struct tcp *conn, struct net_pkt *pkt) break; } + keep_alive_timer_restart(conn); + net_ipaddr_copy(&conn->context->remote, &conn->dst.sa); /* Check if v4-mapping-to-v6 needs to be done for @@ -2669,6 +2898,7 @@ static enum net_verdict tcp_in(struct tcp *conn, struct net_pkt *pkt) NET_CONTEXT_CONNECTED); tcp_ca_init(conn); tcp_out(conn, ACK); + keep_alive_timer_restart(conn); /* The connection semaphore is released *after* * we have changed the connection state. This way @@ -2695,12 +2925,14 @@ static enum net_verdict tcp_in(struct tcp *conn, struct net_pkt *pkt) tcp_out(conn, FIN | ACK); next = TCP_LAST_ACK; verdict = NET_OK; + keep_alive_timer_stop(conn); break; } else if (th && FL(&fl, ==, FIN, th_seq(th) == conn->ack)) { conn_ack(conn, + 1); tcp_out(conn, ACK); next = TCP_CLOSE_WAIT; verdict = NET_OK; + keep_alive_timer_stop(conn); break; } else if (th && FL(&fl, ==, (FIN | ACK | PSH), th_seq(th) == conn->ack)) { @@ -2717,9 +2949,15 @@ static enum net_verdict tcp_in(struct tcp *conn, struct net_pkt *pkt) conn_ack(conn, + len + 1); tcp_out(conn, FIN | ACK); next = TCP_LAST_ACK; + keep_alive_timer_stop(conn); break; } + /* Whatever we've received, we know that peer is alive, so reset + * the keepalive timer. + */ + keep_alive_timer_restart(conn); + #ifdef CONFIG_NET_TCP_FAST_RETRANSMIT if (th && (net_tcp_seq_cmp(th_ack(th), conn->seq) == 0)) { /* Only if there is pending data, increment the duplicate ack count */ @@ -2821,6 +3059,7 @@ static enum net_verdict tcp_in(struct tcp *conn, struct net_pkt *pkt) tcp_out(conn, FIN | ACK); conn_seq(conn, + 1); verdict = NET_OK; + keep_alive_timer_stop(conn); break; } @@ -3232,6 +3471,8 @@ int net_tcp_put(struct net_context *context) } conn_state(conn, TCP_FIN_WAIT_1); + + keep_alive_timer_stop(conn); } } else if (conn && conn->in_connect) { conn->in_connect = false; @@ -3998,6 +4239,18 @@ int net_tcp_set_option(struct net_context *context, case TCP_OPT_NODELAY: ret = set_tcp_nodelay(conn, value, len); break; + case TCP_OPT_KEEPALIVE: + ret = set_tcp_keep_alive(conn, value, len); + break; + case TCP_OPT_KEEPIDLE: + ret = set_tcp_keep_idle(conn, value, len); + break; + case TCP_OPT_KEEPINTVL: + ret = set_tcp_keep_intvl(conn, value, len); + break; + case TCP_OPT_KEEPCNT: + ret = set_tcp_keep_cnt(conn, value, len); + break; } k_mutex_unlock(&conn->lock); @@ -4023,6 +4276,18 @@ int net_tcp_get_option(struct net_context *context, case TCP_OPT_NODELAY: ret = get_tcp_nodelay(conn, value, len); break; + case TCP_OPT_KEEPALIVE: + ret = get_tcp_keep_alive(conn, value, len); + break; + case TCP_OPT_KEEPIDLE: + ret = get_tcp_keep_idle(conn, value, len); + break; + case TCP_OPT_KEEPINTVL: + ret = get_tcp_keep_intvl(conn, value, len); + break; + case TCP_OPT_KEEPCNT: + ret = get_tcp_keep_cnt(conn, value, len); + break; } k_mutex_unlock(&conn->lock); diff --git a/subsys/net/ip/tcp_internal.h b/subsys/net/ip/tcp_internal.h index 1dd3f235532..a9921bbe91f 100644 --- a/subsys/net/ip/tcp_internal.h +++ b/subsys/net/ip/tcp_internal.h @@ -32,6 +32,10 @@ extern "C" { enum tcp_conn_option { TCP_OPT_NODELAY = 1, + TCP_OPT_KEEPALIVE = 2, + TCP_OPT_KEEPIDLE = 3, + TCP_OPT_KEEPINTVL = 4, + TCP_OPT_KEEPCNT = 5, }; /** diff --git a/subsys/net/ip/tcp_private.h b/subsys/net/ip/tcp_private.h index 80e101014cb..5d5d78d916b 100644 --- a/subsys/net/ip/tcp_private.h +++ b/subsys/net/ip/tcp_private.h @@ -275,6 +275,9 @@ struct tcp { /* TCP connection */ struct k_work_delayable timewait_timer; struct k_work_delayable persist_timer; struct k_work_delayable ack_timer; +#if defined(CONFIG_NET_TCP_KEEPALIVE) + struct k_work_delayable keepalive_timer; +#endif /* CONFIG_NET_TCP_KEEPALIVE */ struct k_work conn_release; union { @@ -295,6 +298,12 @@ struct tcp { /* TCP connection */ enum tcp_data_mode data_mode; uint32_t seq; uint32_t ack; +#if defined(CONFIG_NET_TCP_KEEPALIVE) + uint32_t keep_idle; + uint32_t keep_intvl; + uint32_t keep_cnt; + uint32_t keep_cur; +#endif /* CONFIG_NET_TCP_KEEPALIVE */ uint16_t recv_win_max; uint16_t recv_win; uint16_t send_win_max; @@ -313,6 +322,9 @@ struct tcp { /* TCP connection */ bool in_retransmission : 1; bool in_connect : 1; bool in_close : 1; +#if defined(CONFIG_NET_TCP_KEEPALIVE) + bool keep_alive : 1; +#endif /* CONFIG_NET_TCP_KEEPALIVE */ bool tcp_nodelay : 1; }; diff --git a/subsys/net/lib/sockets/sockets.c b/subsys/net/lib/sockets/sockets.c index 56a456aa89b..4664b18424e 100644 --- a/subsys/net/lib/sockets/sockets.c +++ b/subsys/net/lib/sockets/sockets.c @@ -2375,6 +2375,20 @@ static inline int z_vrfy_zsock_inet_pton(sa_family_t family, #include #endif +static enum tcp_conn_option get_tcp_option(int optname) +{ + switch (optname) { + case TCP_KEEPIDLE: + return TCP_OPT_KEEPIDLE; + case TCP_KEEPINTVL: + return TCP_OPT_KEEPINTVL; + case TCP_KEEPCNT: + return TCP_OPT_KEEPCNT; + } + + return -EINVAL; +} + int zsock_getsockopt_ctx(struct net_context *ctx, int level, int optname, void *optval, socklen_t *optlen) { @@ -2490,6 +2504,22 @@ int zsock_getsockopt_ctx(struct net_context *ctx, int level, int optname, return 0; } break; + + case SO_KEEPALIVE: + if (IS_ENABLED(CONFIG_NET_TCP_KEEPALIVE) && + net_context_get_proto(ctx) == IPPROTO_TCP) { + ret = net_tcp_get_option(ctx, + TCP_OPT_KEEPALIVE, + optval, optlen); + if (ret < 0) { + errno = -ret; + return -1; + } + + return 0; + } + + break; } break; @@ -2499,6 +2529,25 @@ int zsock_getsockopt_ctx(struct net_context *ctx, int level, int optname, case TCP_NODELAY: ret = net_tcp_get_option(ctx, TCP_OPT_NODELAY, optval, optlen); return ret; + + case TCP_KEEPIDLE: + __fallthrough; + case TCP_KEEPINTVL: + __fallthrough; + case TCP_KEEPCNT: + if (IS_ENABLED(CONFIG_NET_TCP_KEEPALIVE)) { + ret = net_tcp_get_option(ctx, + get_tcp_option(optname), + optval, optlen); + if (ret < 0) { + errno = -ret; + return -1; + } + + return 0; + } + + break; } break; @@ -2991,6 +3040,22 @@ int zsock_setsockopt_ctx(struct net_context *ctx, int level, int optname, case SO_LINGER: /* ignored. for compatibility purposes only */ return 0; + + case SO_KEEPALIVE: + if (IS_ENABLED(CONFIG_NET_TCP_KEEPALIVE) && + net_context_get_proto(ctx) == IPPROTO_TCP) { + ret = net_tcp_set_option(ctx, + TCP_OPT_KEEPALIVE, + optval, optlen); + if (ret < 0) { + errno = -ret; + return -1; + } + + return 0; + } + + break; } break; @@ -3001,6 +3066,25 @@ int zsock_setsockopt_ctx(struct net_context *ctx, int level, int optname, ret = net_tcp_set_option(ctx, TCP_OPT_NODELAY, optval, optlen); return ret; + + case TCP_KEEPIDLE: + __fallthrough; + case TCP_KEEPINTVL: + __fallthrough; + case TCP_KEEPCNT: + if (IS_ENABLED(CONFIG_NET_TCP_KEEPALIVE)) { + ret = net_tcp_set_option(ctx, + get_tcp_option(optname), + optval, optlen); + if (ret < 0) { + errno = -ret; + return -1; + } + + return 0; + } + + break; } break; From 2cc0d31d9f5228af483f155e9ed3e33a880f9957 Mon Sep 17 00:00:00 2001 From: Robert Lubos Date: Fri, 8 Dec 2023 10:54:21 +0100 Subject: [PATCH 1003/3723] net: tcp: Move TCP Kconfig options to separate file The number of Kconfig options for the TCP stack grew considerably, therefore it makes sense to move them to a separate file not to bloat the Kconfig file with generic networking options. Take this opportunity to reorder TCP options, so that protocol parameters (timings/buffer sizes) are not mixed up with optional protocol features (fast retransmit/congestion avoidance etc.). Signed-off-by: Robert Lubos --- subsys/net/ip/Kconfig | 237 +----------------------------------- subsys/net/ip/Kconfig.tcp | 247 ++++++++++++++++++++++++++++++++++++++ 2 files changed, 248 insertions(+), 236 deletions(-) create mode 100644 subsys/net/ip/Kconfig.tcp diff --git a/subsys/net/ip/Kconfig b/subsys/net/ip/Kconfig index 72562b7645d..0d5216d9112 100644 --- a/subsys/net/ip/Kconfig +++ b/subsys/net/ip/Kconfig @@ -385,242 +385,7 @@ config NET_MAX_MCAST_ROUTES This determines how many entries can be stored in multicast routing table. -config NET_TCP - bool "TCP" - depends on NET_IP - help - The value depends on your network needs. - -config NET_TCP_CHECKSUM - bool "Check TCP checksum" - default y - depends on NET_TCP - help - Enables TCP handler to check TCP checksum. If the checksum is invalid, - then the packet is discarded. - -if NET_TCP -module = NET_TCP -module-dep = NET_LOG -module-str = Log level for TCP -module-help = Enables TCP handler output debug messages -source "subsys/net/Kconfig.template.log_config.net" -endif # NET_TCP - -config NET_TCP_TIME_WAIT_DELAY - int "How long to wait in TIME_WAIT state (in milliseconds)" - depends on NET_TCP - default 1500 - help - To avoid a (low-probability) issue when delayed packets from - previous connection get delivered to next connection reusing - the same local/remote ports, RFC 793 (TCP) suggests to keep - an old, closed connection in a special "TIME_WAIT" state for - the duration of 2*MSL (Maximum Segment Lifetime). The RFC - suggests to use MSL of 2 minutes, but notes "This is an - engineering choice, and may be changed if experience indicates - it is desirable to do so." For low-resource systems, having - large MSL may lead to quick resource exhaustion (and related - DoS attacks). At the same time, the issue of packet misdelivery - is largely alleviated in the modern TCP stacks by using random, - non-repeating port numbers and initial sequence numbers. Due - to this, Zephyr uses much lower value of 1500ms by default. - Value of 0 disables TIME_WAIT state completely. - -config NET_TCP_ACK_TIMEOUT - int "How long to wait for ACK (in milliseconds)" - depends on NET_TCP - default 1000 - range 1 2147483647 - help - This value affects the timeout when waiting ACK to arrive in - various TCP states. The value is in milliseconds. Note that - having a very low value here could prevent connectivity. - -config NET_TCP_INIT_RETRANSMISSION_TIMEOUT - int "Initial value of Retransmission Timeout (RTO) (in milliseconds)" - depends on NET_TCP - default 200 - range 100 60000 - help - This value affects the timeout between initial retransmission - of TCP data packets. The value is in milliseconds. - -config NET_TCP_RETRY_COUNT - int "Maximum number of TCP segment retransmissions" - depends on NET_TCP - default 9 - help - The following formula can be used to determine the time (in ms) - that a segment will be be buffered awaiting retransmission: - n=NET_TCP_RETRY_COUNT - Sum((1< Date: Fri, 8 Dec 2023 12:35:22 +0100 Subject: [PATCH 1004/3723] tests: net: socket: tcp: Add tests for TCP keep alive feature Verify that TCP keep alive options can be set properly and that TCP connections time out correctly when keep-alive probes fail to get replies. Signed-off-by: Robert Lubos --- tests/net/socket/tcp/prj.conf | 1 + tests/net/socket/tcp/src/main.c | 155 ++++++++++++++++++++++++++++++++ 2 files changed, 156 insertions(+) diff --git a/tests/net/socket/tcp/prj.conf b/tests/net/socket/tcp/prj.conf index 15499df7131..77f483a0486 100644 --- a/tests/net/socket/tcp/prj.conf +++ b/tests/net/socket/tcp/prj.conf @@ -38,6 +38,7 @@ CONFIG_NET_BUF_TX_COUNT=64 # Reduce the retry count, so the close always finishes within a second CONFIG_NET_TCP_RETRY_COUNT=3 CONFIG_NET_TCP_INIT_RETRANSMISSION_TIMEOUT=120 +CONFIG_NET_TCP_KEEPALIVE=y CONFIG_ZTEST=y CONFIG_ZTEST_STACK_SIZE=2048 diff --git a/tests/net/socket/tcp/src/main.c b/tests/net/socket/tcp/src/main.c index 6ab2ca97c70..c7a8357f661 100644 --- a/tests/net/socket/tcp/src/main.c +++ b/tests/net/socket/tcp/src/main.c @@ -2193,6 +2193,8 @@ static void test_ioctl_fionread_common(int af) close(fd[SERVER]); close(fd[CLIENT]); close(fd[ACCEPT]); + + test_context_cleanup(); } ZTEST(net_socket_tcp, test_ioctl_fionread_v4) @@ -2336,6 +2338,159 @@ ZTEST(net_socket_tcp, test_connect_and_wait_for_v4_poll) zassert_equal(ret, 0, "close failed, %d", errno); } +ZTEST(net_socket_tcp, test_so_keepalive) +{ + struct sockaddr_in bind_addr4; + int sock, ret; + int optval; + socklen_t optlen = sizeof(optval); + + prepare_sock_tcp_v4(MY_IPV4_ADDR, ANY_PORT, &sock, &bind_addr4); + + /* Keep-alive should be disabled by default. */ + ret = getsockopt(sock, SOL_SOCKET, SO_KEEPALIVE, &optval, &optlen); + zassert_equal(ret, 0, "getsockopt failed (%d)", errno); + zassert_equal(optval, 0, "getsockopt got invalid value"); + zassert_equal(optlen, sizeof(optval), "getsockopt got invalid size"); + + /* Enable keep-alive. */ + optval = 1; + ret = setsockopt(sock, SOL_SOCKET, SO_KEEPALIVE, + &optval, sizeof(optval)); + zassert_equal(ret, 0, "setsockopt failed (%d)", errno); + + ret = getsockopt(sock, SOL_SOCKET, SO_KEEPALIVE, &optval, &optlen); + zassert_equal(ret, 0, "getsockopt failed (%d)", errno); + zassert_equal(optval, 1, "getsockopt got invalid value"); + zassert_equal(optlen, sizeof(optval), "getsockopt got invalid size"); + + /* Check keep-alive parameters defaults. */ + ret = getsockopt(sock, IPPROTO_TCP, TCP_KEEPIDLE, &optval, &optlen); + zassert_equal(ret, 0, "getsockopt failed (%d)", errno); + zassert_equal(optval, CONFIG_NET_TCP_KEEPIDLE_DEFAULT, + "getsockopt got invalid value"); + zassert_equal(optlen, sizeof(optval), "getsockopt got invalid size"); + + ret = getsockopt(sock, IPPROTO_TCP, TCP_KEEPINTVL, &optval, &optlen); + zassert_equal(ret, 0, "getsockopt failed (%d)", errno); + zassert_equal(optval, CONFIG_NET_TCP_KEEPINTVL_DEFAULT, + "getsockopt got invalid value"); + zassert_equal(optlen, sizeof(optval), "getsockopt got invalid size"); + + ret = getsockopt(sock, IPPROTO_TCP, TCP_KEEPCNT, &optval, &optlen); + zassert_equal(ret, 0, "getsockopt failed (%d)", errno); + zassert_equal(optval, CONFIG_NET_TCP_KEEPCNT_DEFAULT, + "getsockopt got invalid value"); + zassert_equal(optlen, sizeof(optval), "getsockopt got invalid size"); + + /* Check keep-alive parameters update. */ + optval = 123; + ret = setsockopt(sock, IPPROTO_TCP, TCP_KEEPIDLE, + &optval, sizeof(optval)); + zassert_equal(ret, 0, "setsockopt failed (%d)", errno); + + optval = 10; + ret = setsockopt(sock, IPPROTO_TCP, TCP_KEEPINTVL, + &optval, sizeof(optval)); + zassert_equal(ret, 0, "setsockopt failed (%d)", errno); + + optval = 2; + ret = setsockopt(sock, IPPROTO_TCP, TCP_KEEPCNT, + &optval, sizeof(optval)); + zassert_equal(ret, 0, "setsockopt failed (%d)", errno); + + ret = getsockopt(sock, IPPROTO_TCP, TCP_KEEPIDLE, &optval, &optlen); + zassert_equal(ret, 0, "getsockopt failed (%d)", errno); + zassert_equal(optval, 123, "getsockopt got invalid value"); + zassert_equal(optlen, sizeof(optval), "getsockopt got invalid size"); + + ret = getsockopt(sock, IPPROTO_TCP, TCP_KEEPINTVL, &optval, &optlen); + zassert_equal(ret, 0, "getsockopt failed (%d)", errno); + zassert_equal(optval, 10, "getsockopt got invalid value"); + zassert_equal(optlen, sizeof(optval), "getsockopt got invalid size"); + + ret = getsockopt(sock, IPPROTO_TCP, TCP_KEEPCNT, &optval, &optlen); + zassert_equal(ret, 0, "getsockopt failed (%d)", errno); + zassert_equal(optval, 2, "getsockopt got invalid value"); + zassert_equal(optlen, sizeof(optval), "getsockopt got invalid size"); + + test_close(sock); + + test_context_cleanup(); +} + +ZTEST(net_socket_tcp, test_keepalive_timeout) +{ + struct sockaddr_in c_saddr, s_saddr; + int c_sock, s_sock, new_sock; + uint8_t rx_buf; + int optval; + int ret; + + prepare_sock_tcp_v4(MY_IPV4_ADDR, ANY_PORT, &c_sock, &c_saddr); + prepare_sock_tcp_v4(MY_IPV4_ADDR, SERVER_PORT, &s_sock, &s_saddr); + + /* Enable keep-alive on both ends and set timeouts/retries to minimum */ + optval = 1; + ret = setsockopt(c_sock, SOL_SOCKET, SO_KEEPALIVE, + &optval, sizeof(optval)); + zassert_equal(ret, 0, "setsockopt failed (%d)", errno); + ret = setsockopt(s_sock, SOL_SOCKET, SO_KEEPALIVE, + &optval, sizeof(optval)); + zassert_equal(ret, 0, "setsockopt failed (%d)", errno); + + optval = 1; + ret = setsockopt(c_sock, IPPROTO_TCP, TCP_KEEPIDLE, + &optval, sizeof(optval)); + zassert_equal(ret, 0, "setsockopt failed (%d)", errno); + ret = setsockopt(s_sock, IPPROTO_TCP, TCP_KEEPIDLE, + &optval, sizeof(optval)); + zassert_equal(ret, 0, "setsockopt failed (%d)", errno); + + optval = 1; + ret = setsockopt(c_sock, IPPROTO_TCP, TCP_KEEPINTVL, + &optval, sizeof(optval)); + zassert_equal(ret, 0, "setsockopt failed (%d)", errno); + ret = setsockopt(s_sock, IPPROTO_TCP, TCP_KEEPINTVL, + &optval, sizeof(optval)); + zassert_equal(ret, 0, "setsockopt failed (%d)", errno); + + optval = 1; + ret = setsockopt(c_sock, IPPROTO_TCP, TCP_KEEPCNT, + &optval, sizeof(optval)); + zassert_equal(ret, 0, "setsockopt failed (%d)", errno); + ret = setsockopt(s_sock, IPPROTO_TCP, TCP_KEEPCNT, + &optval, sizeof(optval)); + zassert_equal(ret, 0, "setsockopt failed (%d)", errno); + + /* Establish connection */ + test_bind(s_sock, (struct sockaddr *)&s_saddr, sizeof(s_saddr)); + test_listen(s_sock); + test_connect(c_sock, (struct sockaddr *)&s_saddr, sizeof(s_saddr)); + test_accept(s_sock, &new_sock, NULL, NULL); + + /* Kill communication - expect that connection will be closed after + * a timeout period. + */ + loopback_set_packet_drop_ratio(1.0f); + + ret = recv(c_sock, &rx_buf, sizeof(rx_buf), 0); + zassert_equal(ret, -1, "recv() should've failed"); + zassert_equal(errno, ETIMEDOUT, "wrong errno value, %d", errno); + + /* Same on the other end. */ + ret = recv(new_sock, &rx_buf, sizeof(rx_buf), 0); + zassert_equal(ret, -1, "recv() should've failed"); + zassert_equal(errno, ETIMEDOUT, "wrong errno value, %d", errno); + + test_close(c_sock); + test_close(new_sock); + test_close(s_sock); + + loopback_set_packet_drop_ratio(0.0f); + test_context_cleanup(); +} + static void after(void *arg) { ARG_UNUSED(arg); From 240dd53e1888a01da9691183dba5bd02294fe554 Mon Sep 17 00:00:00 2001 From: Daniel Leung Date: Fri, 8 Dec 2023 12:42:46 -0800 Subject: [PATCH 1005/3723] sys: arch_interface: fix doc in arch_user_mode_enter The transition is to USER mode, and not kernel mode. Signed-off-by: Daniel Leung --- include/zephyr/sys/arch_interface.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/include/zephyr/sys/arch_interface.h b/include/zephyr/sys/arch_interface.h index 1e5eaad87b1..dc1d8f2e5a8 100644 --- a/include/zephyr/sys/arch_interface.h +++ b/include/zephyr/sys/arch_interface.h @@ -800,7 +800,7 @@ int arch_buffer_validate(void *addr, size_t size, int write); size_t arch_virt_region_align(uintptr_t phys, size_t size); /** - * Perform a one-way transition from supervisor to kernel mode. + * Perform a one-way transition from supervisor to user mode. * * Implementations of this function must do the following: * From 640712054ecded69329c4ad0b4335b2c8e48db52 Mon Sep 17 00:00:00 2001 From: Gustavo Romero Date: Fri, 8 Dec 2023 22:04:24 +0000 Subject: [PATCH 1006/3723] include: arch: arm: Fix arch_curr_cpu() for Cortex-M Currently, the arch_curr_cpu() implementation always uses the TPIDRURO register, even on Cortex-M CPUs where such a register is not available, causing a CPU fault. This commit fixes it by reverting to the use of generic kernel struct to obtain the current cpu instead of using the TPIDRURO register. Signed-off-by: Gustavo Romero --- include/zephyr/arch/arm/arch_inlines.h | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) diff --git a/include/zephyr/arch/arm/arch_inlines.h b/include/zephyr/arch/arm/arch_inlines.h index 96822e0eff1..acc3d2e9588 100644 --- a/include/zephyr/arch/arm/arch_inlines.h +++ b/include/zephyr/arch/arm/arch_inlines.h @@ -8,14 +8,24 @@ #define ZEPHYR_INCLUDE_ARCH_ARM_AARCH32_ARCH_INLINES_H #include +#if defined(CONFIG_CPU_AARCH32_CORTEX_R) || defined(CONFIG_CPU_AARCH32_CORTEX_A) #include #include static ALWAYS_INLINE _cpu_t *arch_curr_cpu(void) { - /* Dummy implementation always return the first cpu */ return (_cpu_t *)(read_tpidruro() & TPIDRURO_CURR_CPU); } +#else + +#ifndef CONFIG_SMP +static ALWAYS_INLINE _cpu_t *arch_curr_cpu(void) +{ + /* Dummy implementation always return the first cpu */ + return &_kernel.cpus[0]; +} +#endif +#endif static ALWAYS_INLINE uint32_t arch_proc_id(void) { From 84f4ffce7c217b3dd4c9b4dc8044f6220775a020 Mon Sep 17 00:00:00 2001 From: Maximilian Deubel Date: Mon, 4 Dec 2023 16:47:01 +0100 Subject: [PATCH 1007/3723] soc: arm: nordic_nrf: nrf91: add nRF9151 LACA This patch adds definitions for the nRF9151, which is software-compatible with nRF9161. Signed-off-by: Maximilian Deubel --- dts/arm/nordic/nrf9151_laca.dtsi | 23 +++++++++++++++++++ dts/arm/nordic/nrf9151ns_laca.dtsi | 23 +++++++++++++++++++ .../nrf91/Kconfig.defconfig.nrf9151_LACA | 14 +++++++++++ soc/arm/nordic_nrf/nrf91/Kconfig.soc | 4 ++++ 4 files changed, 64 insertions(+) create mode 100644 dts/arm/nordic/nrf9151_laca.dtsi create mode 100644 dts/arm/nordic/nrf9151ns_laca.dtsi create mode 100644 soc/arm/nordic_nrf/nrf91/Kconfig.defconfig.nrf9151_LACA diff --git a/dts/arm/nordic/nrf9151_laca.dtsi b/dts/arm/nordic/nrf9151_laca.dtsi new file mode 100644 index 00000000000..9ed20274017 --- /dev/null +++ b/dts/arm/nordic/nrf9151_laca.dtsi @@ -0,0 +1,23 @@ +/* + * Copyright (c) 2023 Nordic Semiconductor ASA + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include +#include + +&flash0 { + reg = <0x00000000 DT_SIZE_K(1024)>; +}; + +&sram0 { + reg = <0x20000000 DT_SIZE_K(256)>; +}; + +/ { + soc { + compatible = "nordic,nrf9151-laca", "nordic,nrf9120", + "nordic,nrf91", "simple-bus"; + }; +}; diff --git a/dts/arm/nordic/nrf9151ns_laca.dtsi b/dts/arm/nordic/nrf9151ns_laca.dtsi new file mode 100644 index 00000000000..ac31c6e19c6 --- /dev/null +++ b/dts/arm/nordic/nrf9151ns_laca.dtsi @@ -0,0 +1,23 @@ +/* + * Copyright (c) 2023 Nordic Semiconductor ASA + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include +#include + +&flash0 { + reg = <0x00000000 DT_SIZE_K(1024)>; +}; + +&sram0 { + reg = <0x20000000 DT_SIZE_K(256)>; +}; + +/ { + soc { + compatible = "nordic,nrf9151-laca", "nordic,nrf9120", + "nordic,nrf91", "simple-bus"; + }; +}; diff --git a/soc/arm/nordic_nrf/nrf91/Kconfig.defconfig.nrf9151_LACA b/soc/arm/nordic_nrf/nrf91/Kconfig.defconfig.nrf9151_LACA new file mode 100644 index 00000000000..1b3ea88e359 --- /dev/null +++ b/soc/arm/nordic_nrf/nrf91/Kconfig.defconfig.nrf9151_LACA @@ -0,0 +1,14 @@ +# Nordic Semiconductor nRF9151 MCU + +# Copyright (c) 2023 Nordic Semiconductor ASA +# SPDX-License-Identifier: Apache-2.0 + +if SOC_NRF9151_LACA + +config SOC + default "nRF9151_LACA" + +config NUM_IRQS + default 65 + +endif # SOC_NRF9151_LACA diff --git a/soc/arm/nordic_nrf/nrf91/Kconfig.soc b/soc/arm/nordic_nrf/nrf91/Kconfig.soc index c9b8c54438b..0267ada4850 100644 --- a/soc/arm/nordic_nrf/nrf91/Kconfig.soc +++ b/soc/arm/nordic_nrf/nrf91/Kconfig.soc @@ -34,6 +34,10 @@ config SOC_NRF9131_LACA bool "NRF9131_LACA" select SOC_NRF9120 +config SOC_NRF9151_LACA + bool "NRF9151_LACA" + select SOC_NRF9120 + endchoice config NRF_ENABLE_ICACHE From c055561a6b12dd530fa54452be6e80d138dfbd50 Mon Sep 17 00:00:00 2001 From: Maximilian Deubel Date: Mon, 4 Dec 2023 16:57:34 +0100 Subject: [PATCH 1008/3723] boards: arm: add nrf9151dk_nrf9151 This patch adds the nRF9151-DK board. Signed-off-by: Maximilian Deubel --- boards/arm/nrf9151dk_nrf9151/Kconfig.board | 14 + .../arm/nrf9151dk_nrf9151/Kconfig.defconfig | 47 +++ boards/arm/nrf9151dk_nrf9151/board.cmake | 14 + boards/arm/nrf9151dk_nrf9151/doc/index.rst | 203 +++++++++++++ .../nordic,nrf9151dk-nrf5340-reset.yaml | 18 ++ .../dts/nrf9151dk_buttons_on_io_expander.dtsi | 25 ++ .../dts/nrf9151dk_leds_on_io_expander.dtsi | 25 ++ .../nrf9151dk_nrf9151/nrf9151dk_nrf9151.dts | 19 ++ .../nrf9151dk_nrf9151/nrf9151dk_nrf9151.yaml | 22 ++ .../nrf9151dk_nrf9151_common-pinctrl.dtsi | 96 +++++++ .../nrf9151dk_nrf9151_common.dtsi | 268 ++++++++++++++++++ .../nrf9151dk_nrf9151_defconfig | 24 ++ .../nrf9151dk_nrf9151_ns.dts | 22 ++ .../nrf9151dk_nrf9151_ns.yaml | 20 ++ .../nrf9151dk_nrf9151_ns_defconfig | 27 ++ .../nrf9151dk_nrf9151_partition_conf.dtsi | 60 ++++ .../arm/nrf9151dk_nrf9151/pre_dt_board.cmake | 7 + 17 files changed, 911 insertions(+) create mode 100644 boards/arm/nrf9151dk_nrf9151/Kconfig.board create mode 100644 boards/arm/nrf9151dk_nrf9151/Kconfig.defconfig create mode 100644 boards/arm/nrf9151dk_nrf9151/board.cmake create mode 100644 boards/arm/nrf9151dk_nrf9151/doc/index.rst create mode 100644 boards/arm/nrf9151dk_nrf9151/dts/bindings/nordic,nrf9151dk-nrf5340-reset.yaml create mode 100644 boards/arm/nrf9151dk_nrf9151/dts/nrf9151dk_buttons_on_io_expander.dtsi create mode 100644 boards/arm/nrf9151dk_nrf9151/dts/nrf9151dk_leds_on_io_expander.dtsi create mode 100644 boards/arm/nrf9151dk_nrf9151/nrf9151dk_nrf9151.dts create mode 100644 boards/arm/nrf9151dk_nrf9151/nrf9151dk_nrf9151.yaml create mode 100644 boards/arm/nrf9151dk_nrf9151/nrf9151dk_nrf9151_common-pinctrl.dtsi create mode 100644 boards/arm/nrf9151dk_nrf9151/nrf9151dk_nrf9151_common.dtsi create mode 100644 boards/arm/nrf9151dk_nrf9151/nrf9151dk_nrf9151_defconfig create mode 100644 boards/arm/nrf9151dk_nrf9151/nrf9151dk_nrf9151_ns.dts create mode 100644 boards/arm/nrf9151dk_nrf9151/nrf9151dk_nrf9151_ns.yaml create mode 100644 boards/arm/nrf9151dk_nrf9151/nrf9151dk_nrf9151_ns_defconfig create mode 100644 boards/arm/nrf9151dk_nrf9151/nrf9151dk_nrf9151_partition_conf.dtsi create mode 100644 boards/arm/nrf9151dk_nrf9151/pre_dt_board.cmake diff --git a/boards/arm/nrf9151dk_nrf9151/Kconfig.board b/boards/arm/nrf9151dk_nrf9151/Kconfig.board new file mode 100644 index 00000000000..92352ddc16f --- /dev/null +++ b/boards/arm/nrf9151dk_nrf9151/Kconfig.board @@ -0,0 +1,14 @@ +# nRF9151 DK NRF9151 board configuration + +# Copyright (c) 2023 Nordic Semiconductor ASA +# SPDX-License-Identifier: Apache-2.0 + +if SOC_NRF9151_LACA + +config BOARD_NRF9151DK_NRF9151 + bool "nRF9151 DK NRF9151" + +config BOARD_NRF9151DK_NRF9151_NS + bool "nRF9151 DK NRF9151 non-secure" + +endif # SOC_NRF9151_LACA diff --git a/boards/arm/nrf9151dk_nrf9151/Kconfig.defconfig b/boards/arm/nrf9151dk_nrf9151/Kconfig.defconfig new file mode 100644 index 00000000000..3cbff101d63 --- /dev/null +++ b/boards/arm/nrf9151dk_nrf9151/Kconfig.defconfig @@ -0,0 +1,47 @@ +# nRF9151 DK NRF9151 board configuration + +# Copyright (c) 2023 Nordic Semiconductor ASA +# SPDX-License-Identifier: Apache-2.0 + +if BOARD_NRF9151DK_NRF9151 || BOARD_NRF9151DK_NRF9151_NS + +config BOARD + default "nrf9151dk_nrf9151" + +# 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)) + depends on BOARD_NRF9151DK_NRF9151 && TRUSTED_EXECUTION_SECURE + +if BOARD_NRF9151DK_NRF9151_NS + +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)) + +endif # BOARD_NRF9151DK_NRF9151_NS + +config BT_HCI_VS + default y if BT + +config BT_WAIT_NOP + default BT && $(dt_nodelabel_enabled,nrf5340_reset) + +config I2C + default $(dt_compat_on_bus,$(DT_COMPAT_NXP_PCAL6408A),i2c) + +endif # BOARD_NRF9151DK_NRF9151 || BOARD_NRF9151DK_NRF9151_NS diff --git a/boards/arm/nrf9151dk_nrf9151/board.cmake b/boards/arm/nrf9151dk_nrf9151/board.cmake new file mode 100644 index 00000000000..a3126c941d9 --- /dev/null +++ b/boards/arm/nrf9151dk_nrf9151/board.cmake @@ -0,0 +1,14 @@ +# SPDX-License-Identifier: Apache-2.0 + +if(CONFIG_BOARD_NRF9151DK_NRF9151_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() + +# TODO: change to nRF9151_xxAA when such device is available in JLink +board_runner_args(jlink "--device=nRF9160_xxAA" "--speed=4000") +include(${ZEPHYR_BASE}/boards/common/nrfjprog.board.cmake) +include(${ZEPHYR_BASE}/boards/common/jlink.board.cmake) diff --git a/boards/arm/nrf9151dk_nrf9151/doc/index.rst b/boards/arm/nrf9151dk_nrf9151/doc/index.rst new file mode 100644 index 00000000000..4c02e7ed372 --- /dev/null +++ b/boards/arm/nrf9151dk_nrf9151/doc/index.rst @@ -0,0 +1,203 @@ +.. _nrf9151dk_nrf9151: + +nRF9151 DK +########## + +Overview +******** + +The nRF9151 DK (PCA10171) is a single-board development kit for evaluation and +development on the nRF9151 SiP for DECT NR+ and LTE-M/NB-IoT with GNSS. The nrf9151dk_nrf9151 +board configuration provides support for the Nordic Semiconductor nRF9151 ARM +Cortex-M33F CPU with ARMv8-M Security Extension and the following devices: + +* :abbr:`ADC (Analog to Digital Converter)` +* CLOCK +* FLASH +* :abbr:`GPIO (General Purpose Input Output)` +* :abbr:`I2C (Inter-Integrated Circuit)` +* :abbr:`MPU (Memory Protection Unit)` +* :abbr:`NVIC (Nested Vectored Interrupt Controller)` +* :abbr:`PWM (Pulse Width Modulation)` +* :abbr:`RTC (nRF RTC System Clock)` +* Segger RTT (RTT Console) +* :abbr:`SPI (Serial Peripheral Interface)` +* :abbr:`UARTE (Universal asynchronous receiver-transmitter with EasyDMA)` +* :abbr:`WDT (Watchdog Timer)` +* :abbr:`IDAU (Implementation Defined Attribution Unit)` + +More information about the board can be found at the +`nRF9151 DK website`_. The `Nordic Semiconductor Infocenter`_ +contains the processor's information and the datasheet. + + +Hardware +******** + +nRF9151 DK has two external oscillators. The frequency of +the slow clock is 32.768 kHz. The frequency of the main clock +is 32 MHz. + +Supported Features +================== + +The nrf9151dk_nrf9151 board configuration supports the following +hardware features: + ++-----------+------------+----------------------+ +| Interface | Controller | Driver/Component | ++===========+============+======================+ +| ADC | on-chip | adc | ++-----------+------------+----------------------+ +| CLOCK | on-chip | clock_control | ++-----------+------------+----------------------+ +| FLASH | on-chip | flash | ++-----------+------------+----------------------+ +| FLASH | external | spi | ++-----------+------------+----------------------+ +| GPIO | on-chip | gpio | ++-----------+------------+----------------------+ +| GPIO | external | i2c | ++-----------+------------+----------------------+ +| I2C(M) | on-chip | i2c | ++-----------+------------+----------------------+ +| MPU | on-chip | arch/arm | ++-----------+------------+----------------------+ +| NVIC | on-chip | arch/arm | ++-----------+------------+----------------------+ +| PWM | on-chip | pwm | ++-----------+------------+----------------------+ +| RTC | on-chip | system clock | ++-----------+------------+----------------------+ +| RTT | nRF53 | console | ++-----------+------------+----------------------+ +| SPI(M/S) | on-chip | spi | ++-----------+------------+----------------------+ +| SPU | on-chip | system protection | ++-----------+------------+----------------------+ +| UARTE | on-chip | serial | ++-----------+------------+----------------------+ +| WDT | on-chip | watchdog | ++-----------+------------+----------------------+ + + +.. _nrf9151dk_additional_hardware: + +Other hardware features have not been enabled yet for this board. +See `nRF9151 DK website`_ and `Nordic Semiconductor Infocenter`_ +for a complete list of nRF9151 DK board hardware features. + +Connections and IOs +=================== + +LED +--- + +* LED1 (green) = P0.0 +* LED2 (green) = P0.1 +* LED3 (green) = P0.4 +* LED4 (green) = P0.5 + +Push buttons and Switches +------------------------- + +* BUTTON1 = P0.8 +* BUTTON2 = P0.9 +* SWITCH1 = P0.18 +* SWITCH2 = P0.19 +* BOOT = SW5 = boot/reset + +Security components +=================== + +- Implementation Defined Attribution Unit (`IDAU`_). The IDAU is implemented + with the System Protection Unit and is used to define secure and non-secure + memory maps. By default, all of the memory space (Flash, SRAM, and + peripheral address space) is defined to be secure accessible only. +- Secure boot. + + +Programming and Debugging +************************* + +nrf9151dk_nrf9151 supports the Armv8m Security Extension, and by default boots +in the Secure state. + +Building Secure/Non-Secure Zephyr applications with Arm |reg| TrustZone |reg| +============================================================================= + +The process requires the following steps: + +1. Build the Secure Zephyr application using ``-DBOARD=nrf9151dk_nrf9151`` and + ``CONFIG_TRUSTED_EXECUTION_SECURE=y`` in the application project configuration file. +2. Build the Non-Secure Zephyr application using ``-DBOARD=nrf9151dk_nrf9151_ns``. +3. Merge the two binaries together. + +When building a Secure/Non-Secure application, the Secure application will +have to set the IDAU (SPU) configuration to allow Non-Secure access to all +CPU resources utilized by the Non-Secure application firmware. SPU +configuration shall take place before jumping to the Non-Secure application. + +Building a Secure only application +================================== + +Build the Zephyr app in the usual way (see :ref:`build_an_application` +and :ref:`application_run`), using ``-DBOARD=nrf9151dk_nrf9151``. + +Flashing +======== + +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`. Then build and flash +applications as usual (see :ref:`build_an_application` and +:ref:`application_run` for more details). + +Here is an example for the :ref:`hello_world` application. + +First, run your favorite terminal program to listen for output. + +.. code-block:: console + + $ minicom -D -b 115200 + +Replace :code:`` with the port where the nRF9151 DK +can be found. For example, under Linux, :code:`/dev/ttyACM0`. + +Then build and flash the application in the usual way. + +.. zephyr-app-commands:: + :zephyr-app: samples/hello_world + :board: nrf9151dk_nrf9151 + :goals: build flash + +Debugging +========= + +Refer to the :ref:`nordic_segger` page to learn about debugging Nordic boards with a +Segger IC. + + +Testing the LEDs and buttons in the nRF9151 DK +********************************************** + +There are 2 samples that allow you to test that the buttons (switches) and LEDs on +the board are working properly with Zephyr: + +* :zephyr:code-sample:`blinky` +* :zephyr:code-sample:`button` + +You can build and flash the examples to make sure Zephyr is running correctly on +your board. The button and LED definitions can be found in +:zephyr_file:`boards/arm/nrf9151dk_nrf9151/nrf9151dk_nrf9151_common.dtsi`. + +References +********** + +.. target-notes:: + +.. _IDAU: + https://developer.arm.com/docs/100690/latest/attribution-units-sau-and-idau +.. _nRF9151 DK website: https://www.nordicsemi.com/Software-and-Tools/Development-Kits/nRF9151-DK +.. _Nordic Semiconductor Infocenter: https://infocenter.nordicsemi.com +.. _Trusted Firmware M: https://www.trustedfirmware.org/projects/tf-m/ diff --git a/boards/arm/nrf9151dk_nrf9151/dts/bindings/nordic,nrf9151dk-nrf5340-reset.yaml b/boards/arm/nrf9151dk_nrf9151/dts/bindings/nordic,nrf9151dk-nrf5340-reset.yaml new file mode 100644 index 00000000000..2b51125312c --- /dev/null +++ b/boards/arm/nrf9151dk_nrf9151/dts/bindings/nordic,nrf9151dk-nrf5340-reset.yaml @@ -0,0 +1,18 @@ +# Copyright (c) 2023 Nordic Semiconductor ASA +# SPDX-License-Identifier: Apache-2.0 + +description: GPIO used to reset nRF5340 on nRF9151 DK + +compatible: "nordic,nrf9151dk-nrf5340-reset" + +include: base.yaml + +properties: + status: + required: true + + gpios: + type: phandle-array + required: true + description: | + GPIO to use as nRF5340 reset line: output in nRF9151, input in nRF5340. diff --git a/boards/arm/nrf9151dk_nrf9151/dts/nrf9151dk_buttons_on_io_expander.dtsi b/boards/arm/nrf9151dk_nrf9151/dts/nrf9151dk_buttons_on_io_expander.dtsi new file mode 100644 index 00000000000..20f7d2406a5 --- /dev/null +++ b/boards/arm/nrf9151dk_nrf9151/dts/nrf9151dk_buttons_on_io_expander.dtsi @@ -0,0 +1,25 @@ +/* + * Copyright (c) 2023 Nordic Semiconductor ASA + * + * SPDX-License-Identifier: Apache-2.0 + */ + +&pcal6408a { + status = "okay"; +}; + +&button0 { + gpios = <&pcal6408a 0 (GPIO_PULL_UP | GPIO_ACTIVE_LOW)>; +}; + +&button1 { + gpios = <&pcal6408a 1 (GPIO_PULL_UP | GPIO_ACTIVE_LOW)>; +}; + +&button2 { + gpios = <&pcal6408a 2 (GPIO_PULL_UP | GPIO_ACTIVE_LOW)>; +}; + +&button3 { + gpios = <&pcal6408a 3 (GPIO_PULL_UP | GPIO_ACTIVE_LOW)>; +}; diff --git a/boards/arm/nrf9151dk_nrf9151/dts/nrf9151dk_leds_on_io_expander.dtsi b/boards/arm/nrf9151dk_nrf9151/dts/nrf9151dk_leds_on_io_expander.dtsi new file mode 100644 index 00000000000..d80c509d215 --- /dev/null +++ b/boards/arm/nrf9151dk_nrf9151/dts/nrf9151dk_leds_on_io_expander.dtsi @@ -0,0 +1,25 @@ +/* + * Copyright (c) 2023 Nordic Semiconductor ASA + * + * SPDX-License-Identifier: Apache-2.0 + */ + +&pcal6408a { + status = "okay"; +}; + +&led0 { + gpios = <&pcal6408a 4 GPIO_ACTIVE_HIGH>; +}; + +&led1 { + gpios = <&pcal6408a 5 GPIO_ACTIVE_HIGH>; +}; + +&led2 { + gpios = <&pcal6408a 6 GPIO_ACTIVE_HIGH>; +}; + +&led3 { + gpios = <&pcal6408a 7 GPIO_ACTIVE_HIGH>; +}; diff --git a/boards/arm/nrf9151dk_nrf9151/nrf9151dk_nrf9151.dts b/boards/arm/nrf9151dk_nrf9151/nrf9151dk_nrf9151.dts new file mode 100644 index 00000000000..8c3b4921434 --- /dev/null +++ b/boards/arm/nrf9151dk_nrf9151/nrf9151dk_nrf9151.dts @@ -0,0 +1,19 @@ +/* + * Copyright (c) 2023 Nordic Semiconductor ASA + * + * SPDX-License-Identifier: Apache-2.0 + */ + +/dts-v1/; +#include +#include "nrf9151dk_nrf9151_common.dtsi" + +/ { + chosen { + zephyr,sram = &sram0_s; + zephyr,flash = &flash0; + zephyr,code-partition = &slot0_partition; + zephyr,sram-secure-partition = &sram0_s; + zephyr,sram-non-secure-partition = &sram0_ns; + }; +}; diff --git a/boards/arm/nrf9151dk_nrf9151/nrf9151dk_nrf9151.yaml b/boards/arm/nrf9151dk_nrf9151/nrf9151dk_nrf9151.yaml new file mode 100644 index 00000000000..3ad90fea76d --- /dev/null +++ b/boards/arm/nrf9151dk_nrf9151/nrf9151dk_nrf9151.yaml @@ -0,0 +1,22 @@ +identifier: nrf9151dk_nrf9151 +name: nRF9151-DK-NRF9151 +type: mcu +arch: arm +toolchain: + - gnuarmemb + - xtools + - zephyr +ram: 88 +flash: 1024 +supported: + - arduino_gpio + - arduino_i2c + - arduino_serial + - arduino_spi + - gpio + - i2c + - pwm + - spi + - watchdog + - counter +vendor: nordic diff --git a/boards/arm/nrf9151dk_nrf9151/nrf9151dk_nrf9151_common-pinctrl.dtsi b/boards/arm/nrf9151dk_nrf9151/nrf9151dk_nrf9151_common-pinctrl.dtsi new file mode 100644 index 00000000000..a1680e830f4 --- /dev/null +++ b/boards/arm/nrf9151dk_nrf9151/nrf9151dk_nrf9151_common-pinctrl.dtsi @@ -0,0 +1,96 @@ +/* + * Copyright (c) 2023 Nordic Semiconductor + * SPDX-License-Identifier: Apache-2.0 + */ + +&pinctrl { + uart0_default: uart0_default { + group1 { + psels = , + ; + }; + group2 { + psels = , + ; + bias-pull-up; + }; + }; + + uart0_sleep: uart0_sleep { + group1 { + psels = , + , + , + ; + low-power-enable; + }; + }; + + uart1_default: uart1_default { + group1 { + psels = , + ; + }; + group2 { + psels = , + ; + bias-pull-up; + }; + }; + + uart1_sleep: uart1_sleep { + group1 { + psels = , + , + , + ; + low-power-enable; + }; + }; + + i2c2_default: i2c2_default { + group1 { + psels = , + ; + }; + }; + + i2c2_sleep: i2c2_sleep { + group1 { + psels = , + ; + low-power-enable; + }; + }; + + pwm0_default: pwm0_default { + group1 { + psels = ; + }; + }; + + pwm0_sleep: pwm0_sleep { + group1 { + psels = ; + low-power-enable; + }; + }; + + spi3_default: spi3_default { + group1 { + psels = , + , + ; + nordic,drive-mode = ; + }; + }; + + spi3_sleep: spi3_sleep { + group1 { + psels = , + , + ; + low-power-enable; + }; + }; +}; diff --git a/boards/arm/nrf9151dk_nrf9151/nrf9151dk_nrf9151_common.dtsi b/boards/arm/nrf9151dk_nrf9151/nrf9151dk_nrf9151_common.dtsi new file mode 100644 index 00000000000..958e864c63c --- /dev/null +++ b/boards/arm/nrf9151dk_nrf9151/nrf9151dk_nrf9151_common.dtsi @@ -0,0 +1,268 @@ +/* + * Copyright (c) 2023 Nordic Semiconductor ASA + * + * SPDX-License-Identifier: Apache-2.0 + */ +#include "nrf9151dk_nrf9151_common-pinctrl.dtsi" +#include + +/ { + model = "Nordic nRF9151 DK NRF9151"; + compatible = "nordic,nrf9151-dk-nrf9151"; + + chosen { + zephyr,console = &uart0; + zephyr,shell-uart = &uart0; + zephyr,uart-mcumgr = &uart0; + }; + + leds { + compatible = "gpio-leds"; + led0: led_0 { + gpios = <&gpio0 0 GPIO_ACTIVE_HIGH>; + label = "Green LED 1"; + }; + led1: led_1 { + gpios = <&gpio0 1 GPIO_ACTIVE_HIGH>; + label = "Green LED 2"; + }; + led2: led_2 { + gpios = <&gpio0 4 GPIO_ACTIVE_HIGH>; + label = "Green LED 3"; + }; + led3: led_3 { + gpios = <&gpio0 5 GPIO_ACTIVE_HIGH>; + label = "Green LED 4"; + }; + }; + + pwmleds { + compatible = "pwm-leds"; + pwm_led0: pwm_led_0 { + pwms = <&pwm0 0 PWM_MSEC(20) PWM_POLARITY_NORMAL>; + }; + }; + + buttons { + compatible = "gpio-keys"; + button0: button_0 { + gpios = <&gpio0 8 (GPIO_PULL_UP | GPIO_ACTIVE_LOW)>; + label = "Push button 1"; + zephyr,code = ; + }; + button1: button_1 { + gpios = <&gpio0 9 (GPIO_PULL_UP | GPIO_ACTIVE_LOW)>; + label = "Push button 2"; + zephyr,code = ; + }; + button2: button_2 { + gpios = <&gpio0 18 (GPIO_PULL_UP | GPIO_ACTIVE_LOW)>; + label = "Push button 3"; + zephyr,code = ; + }; + button3: button_3 { + gpios = <&gpio0 19 (GPIO_PULL_UP | GPIO_ACTIVE_LOW)>; + label = "Push button 4"; + zephyr,code = ; + }; + }; + + nrf5340_reset: gpio-reset { + compatible = "nordic,nrf9151dk-nrf5340-reset"; + status = "disabled"; + gpios = <&gpio0 21 GPIO_ACTIVE_LOW>; + }; + + arduino_header: connector { + compatible = "arduino-header-r3"; + #gpio-cells = <2>; + gpio-map-mask = <0xffffffff 0xffffffc0>; + gpio-map-pass-thru = <0 0x3f>; + gpio-map = <0 0 &gpio0 14 0>, /* A0 */ + <1 0 &gpio0 15 0>, /* A1 */ + <2 0 &gpio0 16 0>, /* A2 */ + <3 0 &gpio0 17 0>, /* A3 */ + <4 0 &gpio0 18 0>, /* A4 */ + <5 0 &gpio0 19 0>, /* A5 */ + <6 0 &gpio0 0 0>, /* D0 */ + <7 0 &gpio0 1 0>, /* D1 */ + <8 0 &gpio0 2 0>, /* D2 */ + <9 0 &gpio0 3 0>, /* D3 */ + <10 0 &gpio0 4 0>, /* D4 */ + <11 0 &gpio0 5 0>, /* D5 */ + <12 0 &gpio0 6 0>, /* D6 */ + <13 0 &gpio0 7 0>, /* D7 */ + <14 0 &gpio0 8 0>, /* D8 */ + <15 0 &gpio0 9 0>, /* D9 */ + <16 0 &gpio0 10 0>, /* D10 */ + <17 0 &gpio0 11 0>, /* D11 */ + <18 0 &gpio0 12 0>, /* D12 */ + <19 0 &gpio0 13 0>, /* D13 */ + <20 0 &gpio0 30 0>, /* D14 */ + <21 0 &gpio0 31 0>; /* D15 */ + }; + + arduino_adc: analog-connector { + compatible = "arduino,uno-adc"; + #io-channel-cells = <1>; + io-channel-map = <0 &adc 1>, /* A0 = P0.14 = AIN1 */ + <1 &adc 2>, /* A1 = P0.15 = AIN2 */ + <2 &adc 3>, /* A2 = P0.16 = AIN3 */ + <3 &adc 4>, /* A3 = P0.17 = AIN4 */ + <4 &adc 5>, /* A4 = P0.18 = AIN5 */ + <5 &adc 6>; /* A5 = P0.19 = AIN6 */ + }; + + /* These aliases are provided for compatibility with samples */ + aliases { + led0 = &led0; + led1 = &led1; + led2 = &led2; + led3 = &led3; + pwm-led0 = &pwm_led0; + sw0 = &button0; + sw1 = &button1; + sw2 = &button2; + sw3 = &button3; + bootloader-led0 = &led0; + mcuboot-button0 = &button0; + mcuboot-led0 = &led0; + watchdog0 = &wdt0; + spi-flash0 = &gd25wb256; + }; +}; + +&adc { + status = "okay"; +}; + +&gpiote { + status = "okay"; +}; + +&gpio0 { + status = "okay"; +}; + +&uart0 { + status = "okay"; + current-speed = <115200>; + pinctrl-0 = <&uart0_default>; + pinctrl-1 = <&uart0_sleep>; + pinctrl-names = "default", "sleep"; +}; + +arduino_serial: &uart1 { + status = "okay"; + current-speed = <115200>; + pinctrl-0 = <&uart1_default>; + pinctrl-1 = <&uart1_sleep>; + pinctrl-names = "default", "sleep"; +}; + +arduino_i2c: &i2c2 { + compatible = "nordic,nrf-twim"; + status = "okay"; + pinctrl-0 = <&i2c2_default>; + pinctrl-1 = <&i2c2_sleep>; + pinctrl-names = "default", "sleep"; + clock-frequency = ; + + pcal6408a: pcal6408a@21 { + compatible = "nxp,pcal6408a"; + status = "disabled"; + reg = <0x21>; + gpio-controller; + #gpio-cells = <2>; + ngpios = <8>; + int-gpios = <&gpio0 19 (GPIO_PULL_UP | GPIO_ACTIVE_LOW)>; + }; +}; + +&pwm0 { + status = "okay"; + pinctrl-0 = <&pwm0_default>; + pinctrl-1 = <&pwm0_sleep>; + pinctrl-names = "default", "sleep"; +}; + +arduino_spi: &spi3 { + compatible = "nordic,nrf-spim"; + status = "okay"; + cs-gpios = <&arduino_header 16 GPIO_ACTIVE_LOW>, /* D10 */ + <&gpio0 20 GPIO_ACTIVE_LOW>; + pinctrl-0 = <&spi3_default>; + pinctrl-1 = <&spi3_sleep>; + pinctrl-names = "default", "sleep"; + + gd25wb256: gd25wb256e3ir@1 { + compatible = "jedec,spi-nor"; + status = "disabled"; + reg = <1>; + spi-max-frequency = <8000000>; + size = <268435456>; + has-dpd; + t-enter-dpd = <3000>; + t-exit-dpd = <40000>; + sfdp-bfp = [ + e5 20 f3 ff ff ff ff 0f 44 eb 08 6b 08 3b 42 bb + ee ff ff ff ff ff 00 ff ff ff 00 ff 0c 20 0f 52 + 10 d8 00 ff 44 7a c9 fe 83 67 26 62 ec 82 18 44 + 7a 75 7a 75 04 c4 d5 5c 00 06 74 00 08 50 00 01 + ]; + jedec-id = [c8 65 19]; + }; +}; + +&flash0 { + partitions { + compatible = "fixed-partitions"; + #address-cells = <1>; + #size-cells = <1>; + + boot_partition: partition@0 { + label = "mcuboot"; + reg = <0x00000000 0x10000>; + }; + slot0_partition: partition@10000 { + label = "image-0"; + }; + slot0_ns_partition: partition@50000 { + label = "image-0-nonsecure"; + }; + slot1_partition: partition@85000 { + label = "image-1"; + }; + slot1_ns_partition: partition@c5000 { + label = "image-1-nonsecure"; + }; + storage_partition: partition@fa000 { + label = "storage"; + reg = <0x000fa000 0x00006000>; + }; + }; +}; + +/ { + + reserved-memory { + #address-cells = <1>; + #size-cells = <1>; + ranges; + + sram0_s: image_s@20000000 { + /* Secure image memory */ + }; + + sram0_modem: image_modem@20016000 { + /* Modem (shared) memory */ + }; + + sram0_ns: image_ns@20020000 { + /* Non-Secure image memory */ + }; + }; +}; + +/* Include partition configuration file */ +#include "nrf9151dk_nrf9151_partition_conf.dtsi" diff --git a/boards/arm/nrf9151dk_nrf9151/nrf9151dk_nrf9151_defconfig b/boards/arm/nrf9151dk_nrf9151/nrf9151dk_nrf9151_defconfig new file mode 100644 index 00000000000..7afe5ac7aa9 --- /dev/null +++ b/boards/arm/nrf9151dk_nrf9151/nrf9151dk_nrf9151_defconfig @@ -0,0 +1,24 @@ +# SPDX-License-Identifier: Apache-2.0 + +CONFIG_SOC_SERIES_NRF91X=y +CONFIG_SOC_NRF9151_LACA=y +CONFIG_BOARD_NRF9151DK_NRF9151=y + +# Enable MPU +CONFIG_ARM_MPU=y + +# Enable hardware stack protection +CONFIG_HW_STACK_PROTECTION=y + +# Enable TrustZone-M +CONFIG_ARM_TRUSTZONE_M=y + +# enable GPIO +CONFIG_GPIO=y + +# Enable uart driver +CONFIG_SERIAL=y + +# enable console +CONFIG_CONSOLE=y +CONFIG_UART_CONSOLE=y diff --git a/boards/arm/nrf9151dk_nrf9151/nrf9151dk_nrf9151_ns.dts b/boards/arm/nrf9151dk_nrf9151/nrf9151dk_nrf9151_ns.dts new file mode 100644 index 00000000000..a41c4aad388 --- /dev/null +++ b/boards/arm/nrf9151dk_nrf9151/nrf9151dk_nrf9151_ns.dts @@ -0,0 +1,22 @@ +/* + * Copyright (c) 2023 Nordic Semiconductor ASA + * + * SPDX-License-Identifier: Apache-2.0 + */ + +/dts-v1/; +#include +#include "nrf9151dk_nrf9151_common.dtsi" + +/ { + chosen { + zephyr,flash = &flash0; + zephyr,sram = &sram0_ns; + zephyr,code-partition = &slot0_ns_partition; + }; +}; + +/* Disable UART1, because it is used by default in TF-M */ +&uart1 { + status = "disabled"; +}; diff --git a/boards/arm/nrf9151dk_nrf9151/nrf9151dk_nrf9151_ns.yaml b/boards/arm/nrf9151dk_nrf9151/nrf9151dk_nrf9151_ns.yaml new file mode 100644 index 00000000000..c5d4fe92541 --- /dev/null +++ b/boards/arm/nrf9151dk_nrf9151/nrf9151dk_nrf9151_ns.yaml @@ -0,0 +1,20 @@ +identifier: nrf9151dk_nrf9151_ns +name: nRF9151-DK-NRF9151-Non-Secure +type: mcu +arch: arm +toolchain: + - gnuarmemb + - xtools + - zephyr +ram: 128 +flash: 192 +supported: + - arduino_gpio + - arduino_i2c + - arduino_serial + - arduino_spi + - i2c + - pwm + - watchdog + - netif:modem +vendor: nordic diff --git a/boards/arm/nrf9151dk_nrf9151/nrf9151dk_nrf9151_ns_defconfig b/boards/arm/nrf9151dk_nrf9151/nrf9151dk_nrf9151_ns_defconfig new file mode 100644 index 00000000000..949ef39f856 --- /dev/null +++ b/boards/arm/nrf9151dk_nrf9151/nrf9151dk_nrf9151_ns_defconfig @@ -0,0 +1,27 @@ +# SPDX-License-Identifier: Apache-2.0 + +CONFIG_SOC_SERIES_NRF91X=y +CONFIG_SOC_NRF9151_LACA=y +CONFIG_BOARD_NRF9151DK_NRF9151_NS=y + +# Enable MPU +CONFIG_ARM_MPU=y + +# Enable hardware stack protection +CONFIG_HW_STACK_PROTECTION=y + +# Enable TrustZone-M +CONFIG_ARM_TRUSTZONE_M=y + +# This Board implies building Non-Secure firmware +CONFIG_TRUSTED_EXECUTION_NONSECURE=y + +# enable GPIO +CONFIG_GPIO=y + +# Enable uart driver +CONFIG_SERIAL=y + +# enable console +CONFIG_CONSOLE=y +CONFIG_UART_CONSOLE=y diff --git a/boards/arm/nrf9151dk_nrf9151/nrf9151dk_nrf9151_partition_conf.dtsi b/boards/arm/nrf9151dk_nrf9151/nrf9151dk_nrf9151_partition_conf.dtsi new file mode 100644 index 00000000000..b209608a725 --- /dev/null +++ b/boards/arm/nrf9151dk_nrf9151/nrf9151dk_nrf9151_partition_conf.dtsi @@ -0,0 +1,60 @@ +/* + * Copyright (c) 2023 Nordic Semiconductor ASA + * + * SPDX-License-Identifier: Apache-2.0 + */ + +/* + * Default Flash planning for nRF9151dk_nrf9151. + * + * Zephyr build for nRF9151 with ARM TrustZone-M support, + * implies building Secure and Non-Secure Zephyr images. + * + * Secure image will be placed, by default, in flash0 + * (or in slot0, if MCUboot is present). + * Secure image will use sram0 for system memory. + * + * Non-Secure image will be placed in slot0_ns, and use + * sram0_ns for system memory. + * + * Note that the Secure image only requires knowledge of + * the beginning of the Non-Secure image (not its size). + */ + +&slot0_partition { + reg = <0x00010000 0x40000>; +}; + +&slot0_ns_partition { + reg = <0x00050000 0x35000>; +}; + +&slot1_partition { + reg = <0x00085000 0x40000>; +}; + +&slot1_ns_partition { + reg = <0x000c5000 0x35000>; +}; + +/* Default SRAM planning when building for nRF9151 with + * ARM TrustZone-M support + * - Lowest 88 kB SRAM allocated to Secure image (sram0_s). + * - 40 kB SRAM reserved for and used by the modem library + * (sram0_modem). This memory is Non-Secure. + * - Upper 128 kB allocated to Non-Secure image (sram0_ns). + * When building with TF-M, both sram0_modem and sram0_ns + * are allocated to the Non-Secure image. + */ + +&sram0_s { + reg = <0x20000000 DT_SIZE_K(88)>; +}; + +&sram0_modem { + reg = <0x20016000 DT_SIZE_K(40)>; +}; + +&sram0_ns { + reg = <0x20020000 DT_SIZE_K(128)>; +}; diff --git a/boards/arm/nrf9151dk_nrf9151/pre_dt_board.cmake b/boards/arm/nrf9151dk_nrf9151/pre_dt_board.cmake new file mode 100644 index 00000000000..c8267afd1b4 --- /dev/null +++ b/boards/arm/nrf9151dk_nrf9151/pre_dt_board.cmake @@ -0,0 +1,7 @@ +# Copyright (c) 2021 Linaro Limited +# SPDX-License-Identifier: Apache-2.0 + +# Suppress "unique_unit_address_if_enabled" to handle the following overlaps: +# - flash-controller@39000 & kmu@39000 +# - power@5000 & clock@5000 +list(APPEND EXTRA_DTC_FLAGS "-Wno-unique_unit_address_if_enabled") From f5337fc7a3c809e9cde6662dffd517e81a4e296b Mon Sep 17 00:00:00 2001 From: Andrzej Kuros Date: Mon, 4 Dec 2023 13:23:41 +0100 Subject: [PATCH 1009/3723] modules: hal_nordic: nRF 802.15.4 customizable asserts MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Recent nRF 802.15.4 Radio Driver provides assert abstraction layer. The assert abstraction layer is implemented in Zephyr in following ways depending on the `NRF_802154_ASSERT_CHOICE` Kconfig choice. `NRF_802154_ASSERT_ZEPHYR_MINIMAL` (default) gives ability to still perform run-time checking of the nRF 802.15.4 Radio Driver operation with minimum memory overhead and configurable behavior on fault detection regardless of the `CONFIG_ASSERT` Kconfig option value. `NRF_802154_ASSERT_ZEPHYR` gives ability to use asserts provided and configurable by Zephyr including the ability to turn off the run-time checking of the nRF 802.15.4 Radio Driver operation. Signed-off-by: Andrzej Kuroś --- modules/hal_nordic/Kconfig | 28 +++++++++++++++++- modules/hal_nordic/nrf_802154/CMakeLists.txt | 5 ++++ .../include/nrf_802154_assert_zephyr.h | 29 +++++++++++++++++++ .../nrf_802154/nrf_802154_assert_handler.c | 26 +++++++++++++++++ 4 files changed, 87 insertions(+), 1 deletion(-) create mode 100644 modules/hal_nordic/nrf_802154/include/nrf_802154_assert_zephyr.h create mode 100644 modules/hal_nordic/nrf_802154/nrf_802154_assert_handler.c diff --git a/modules/hal_nordic/Kconfig b/modules/hal_nordic/Kconfig index f842d2cb646..44c12e88685 100644 --- a/modules/hal_nordic/Kconfig +++ b/modules/hal_nordic/Kconfig @@ -205,13 +205,39 @@ endif endmenu # NRF_802154_SER_HOST || NRF_802154_SER_RADIO +if NRF_802154_RADIO_DRIVER || NRF_802154_SERIALIZATION + config NRF_802154_CARRIER_FUNCTIONS bool "nRF 802.15.4 carrier functions" - depends on NRF_802154_RADIO_DRIVER || NRF_802154_SERIALIZATION help This option enables functions such as modulated carrier and continuous carrier. If this option is modified on a multicore SoC, its remote counterpart must be set to the exact same value. +choice NRF_802154_ASSERT_CHOICE + prompt "nRF 802.15.4 assert implementation" + default NRF_802154_ASSERT_ZEPHYR_MINIMAL + +config NRF_802154_ASSERT_ZEPHYR_MINIMAL + bool "nRF 802.15.4 minimal assertions" + help + This option provides minimal run-time checking of the nRF 802.15.4 Radio Driver's operation, + even if kernel-wide CONFIG_ASSERT is disabled. In case of an abnormal condition the function + `nrf_802154_assert_handler()` is called. File and line debug information are not provided + to save memory of the image file. Default implementation of the `nrf_802154_assert_handler` + involves a call to `k_panic`/`k_oops` and allows further tweaking of the behavior. + You can also provide your own implementation of `nrf_802154_assert_handler`. + +config NRF_802154_ASSERT_ZEPHYR + bool "nRF 802.15.4 Radio Driver assertions as Zephyr's standard __ASERT_NO_MSG" + help + The run-time checking of the nRF 802.15.4 Radio Driver depends fully on the configuration + of the `__ASSERT_NO_MSG` macro, including the ability to completely turn off the run-time + checking. + +endchoice # NRF_802154_ASSERT_CHOICE + +endif # NRF_802154_RADIO_DRIVER || NRF_802154_SERIALIZATION + endmenu # HAS_NORDIC_DRIVERS rsource "nrfx/Kconfig" diff --git a/modules/hal_nordic/nrf_802154/CMakeLists.txt b/modules/hal_nordic/nrf_802154/CMakeLists.txt index c338981b651..cd5ace0b278 100644 --- a/modules/hal_nordic/nrf_802154/CMakeLists.txt +++ b/modules/hal_nordic/nrf_802154/CMakeLists.txt @@ -95,6 +95,11 @@ endif() if (CONFIG_NRF_802154_RADIO_DRIVER OR CONFIG_NRF_802154_SERIALIZATION) target_compile_definitions(zephyr-802154-interface INTERFACE NRF_802154_ENERGY_DETECTED_VERSION=1) + if (CONFIG_NRF_802154_ASSERT_ZEPHYR OR CONFIG_NRF_802154_ASSERT_ZEPHYR_MINIMAL) + target_include_directories(zephyr-802154-interface INTERFACE include) + target_compile_definitions(zephyr-802154-interface INTERFACE NRF_802154_PLATFORM_ASSERT_INCLUDE=\"nrf_802154_assert_zephyr.h\") + target_sources(nrf-802154-platform PRIVATE nrf_802154_assert_handler.c) + endif() endif() set(NRF52_SERIES ${CONFIG_SOC_SERIES_NRF52X}) diff --git a/modules/hal_nordic/nrf_802154/include/nrf_802154_assert_zephyr.h b/modules/hal_nordic/nrf_802154/include/nrf_802154_assert_zephyr.h new file mode 100644 index 00000000000..ecd09de609a --- /dev/null +++ b/modules/hal_nordic/nrf_802154/include/nrf_802154_assert_zephyr.h @@ -0,0 +1,29 @@ +/* + * Copyright (c) 2023, Nordic Semiconductor ASA + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#ifndef NRF_802154_ASSERT_ZEPHYR_H__ +#define NRF_802154_ASSERT_ZEPHYR_H__ + +#if defined(CONFIG_NRF_802154_ASSERT_ZEPHYR) + +#include + +#define NRF_802154_ASSERT(condition) __ASSERT_NO_MSG(condition) + +#elif defined(CONFIG_NRF_802154_ASSERT_ZEPHYR_MINIMAL) + +extern void nrf_802154_assert_handler(void); + +#define NRF_802154_ASSERT(condition) \ + do { \ + if (!(condition)) { \ + nrf_802154_assert_handler(); \ + } \ + } while (0) + +#endif /* CONFIG_NRF_802154_ASSERT_ZEPHYR_MINIMAL */ + +#endif /* NRF_802154_ASSERT_ZEPHYR_H__*/ diff --git a/modules/hal_nordic/nrf_802154/nrf_802154_assert_handler.c b/modules/hal_nordic/nrf_802154/nrf_802154_assert_handler.c new file mode 100644 index 00000000000..14d964724c6 --- /dev/null +++ b/modules/hal_nordic/nrf_802154/nrf_802154_assert_handler.c @@ -0,0 +1,26 @@ +/* + * Copyright (c) 2023 Nordic Semiconductor ASA + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include +#include "nrf_802154_assert_zephyr.h" + +#if defined(CONFIG_NRF_802154_ASSERT_ZEPHYR_MINIMAL) + +__weak void nrf_802154_assert_handler(void) +{ +#ifdef CONFIG_USERSPACE + /* User threads aren't allowed to induce kernel panics; generate + * an oops instead. + */ + if (k_is_user_context()) { + k_oops(); + } +#endif + + k_panic(); +} + +#endif /* CONFIG_NRF_802154_ASSERT_ZEPHYR_MINIMAL */ From b6d9ed095d7bc395be602072db2679d201735113 Mon Sep 17 00:00:00 2001 From: Jukka Rissanen Date: Sat, 9 Dec 2023 09:02:22 +0200 Subject: [PATCH 1010/3723] net: Move trickle files to lib The trickle algorithm files are clearly a library so move them under lib/ directory. Signed-off-by: Jukka Rissanen --- subsys/net/ip/CMakeLists.txt | 1 - subsys/net/ip/Kconfig | 14 -------------- subsys/net/lib/CMakeLists.txt | 1 + subsys/net/lib/Kconfig | 2 ++ subsys/net/lib/trickle/CMakeLists.txt | 7 +++++++ subsys/net/lib/trickle/Kconfig | 18 ++++++++++++++++++ subsys/net/{ip => lib/trickle}/trickle.c | 0 7 files changed, 28 insertions(+), 15 deletions(-) create mode 100644 subsys/net/lib/trickle/CMakeLists.txt create mode 100644 subsys/net/lib/trickle/Kconfig rename subsys/net/{ip => lib/trickle}/trickle.c (100%) diff --git a/subsys/net/ip/CMakeLists.txt b/subsys/net/ip/CMakeLists.txt index b9493b894a7..3a93e5020d4 100644 --- a/subsys/net/ip/CMakeLists.txt +++ b/subsys/net/ip/CMakeLists.txt @@ -45,7 +45,6 @@ zephyr_library_sources_ifdef(CONFIG_NET_ROUTE route.c) zephyr_library_sources_ifdef(CONFIG_NET_STATISTICS net_stats.c) zephyr_library_sources_ifdef(CONFIG_NET_TCP tcp.c) zephyr_library_sources_ifdef(CONFIG_NET_TEST_PROTOCOL tp.c) -zephyr_library_sources_ifdef(CONFIG_NET_TRICKLE trickle.c) zephyr_library_sources_ifdef(CONFIG_NET_UDP udp.c) zephyr_library_sources_ifdef(CONFIG_NET_PROMISCUOUS_MODE promiscuous.c) diff --git a/subsys/net/ip/Kconfig b/subsys/net/ip/Kconfig index 0d5216d9112..705ffdcae1c 100644 --- a/subsys/net/ip/Kconfig +++ b/subsys/net/ip/Kconfig @@ -563,20 +563,6 @@ config NET_SLIP_TAP communicate via the SLIP driver. See net-tools project at https://github.com/zephyrproject-rtos/net-tools for more details. -config NET_TRICKLE - bool "Trickle library" - help - Normally this is enabled automatically if needed, - so say 'n' if unsure. - -if NET_TRICKLE -module = NET_TRICKLE -module-dep = NET_LOG -module-str = Log level for Trickle algorithm -module-help = Enables Trickle library output debug messages -source "subsys/net/Kconfig.template.log_config.net" -endif # NET_TRICKLE - endif # NET_RAW_MODE config NET_PKT_RX_COUNT diff --git a/subsys/net/lib/CMakeLists.txt b/subsys/net/lib/CMakeLists.txt index 756adb41341..5e4eae7e028 100644 --- a/subsys/net/lib/CMakeLists.txt +++ b/subsys/net/lib/CMakeLists.txt @@ -14,6 +14,7 @@ add_subdirectory_ifdef(CONFIG_TLS_CREDENTIALS tls_credentials) add_subdirectory_ifdef(CONFIG_NET_CAPTURE capture) add_subdirectory_ifdef(CONFIG_NET_ZPERF zperf) add_subdirectory_ifdef(CONFIG_NET_SHELL shell) +add_subdirectory_ifdef(CONFIG_NET_TRICKLE trickle) if (CONFIG_DNS_RESOLVER OR CONFIG_MDNS_RESPONDER diff --git a/subsys/net/lib/Kconfig b/subsys/net/lib/Kconfig index 5df4a445885..b70105d5f9b 100644 --- a/subsys/net/lib/Kconfig +++ b/subsys/net/lib/Kconfig @@ -39,6 +39,8 @@ menu "Network additional services" source "subsys/net/lib/capture/Kconfig" +source "subsys/net/lib/trickle/Kconfig" + source "subsys/net/lib/zperf/Kconfig" endmenu diff --git a/subsys/net/lib/trickle/CMakeLists.txt b/subsys/net/lib/trickle/CMakeLists.txt new file mode 100644 index 00000000000..b9cf222aab5 --- /dev/null +++ b/subsys/net/lib/trickle/CMakeLists.txt @@ -0,0 +1,7 @@ +# SPDX-License-Identifier: Apache-2.0 + +zephyr_library() + +zephyr_library_sources( + trickle.c + ) diff --git a/subsys/net/lib/trickle/Kconfig b/subsys/net/lib/trickle/Kconfig new file mode 100644 index 00000000000..edc4f8fcf56 --- /dev/null +++ b/subsys/net/lib/trickle/Kconfig @@ -0,0 +1,18 @@ +# Trickle Library for Zephyr + +# Copyright (c) 2016 Intel Corporation. +# SPDX-License-Identifier: Apache-2.0 + +config NET_TRICKLE + bool "Trickle library" + help + Normally this is enabled automatically if needed, + so say 'n' if unsure. + +if NET_TRICKLE +module = NET_TRICKLE +module-dep = NET_LOG +module-str = Log level for Trickle algorithm +module-help = Enables Trickle library output debug messages +source "subsys/net/Kconfig.template.log_config.net" +endif # NET_TRICKLE diff --git a/subsys/net/ip/trickle.c b/subsys/net/lib/trickle/trickle.c similarity index 100% rename from subsys/net/ip/trickle.c rename to subsys/net/lib/trickle/trickle.c From 37aedd953f138899553290427490590dd1c5a28d Mon Sep 17 00:00:00 2001 From: Steffen Jahnke Date: Mon, 23 Oct 2023 12:19:30 +0000 Subject: [PATCH 1011/3723] boards: arm: Add PAN1783A evaluation board The PAN1783A evaluation board is a development tool for the nRF5340 from Nordic Semiconductor. Signed-off-by: Steffen Jahnke --- boards/arm/pan1783_evb/CMakeLists.txt | 7 -- boards/arm/pan1783_evb/board.cmake | 12 ---- boards/arm/pan1783_evb/doc/index.rst | 55 ---------------- .../arm/pan1783_pan1783a_evb/CMakeLists.txt | 7 ++ .../Kconfig | 11 ++-- .../Kconfig.board | 8 +++ .../Kconfig.defconfig | 12 ++-- boards/arm/pan1783_pan1783a_evb/board.cmake | 12 ++++ .../doc/img/pan1783_evb.jpg | Bin .../doc/img/pan1783a_evb.jpg | Bin 0 -> 62330 bytes boards/arm/pan1783_pan1783a_evb/doc/index.rst | 62 ++++++++++++++++++ .../pan1783_evb_cpuapp.dts | 2 +- .../pan1783_evb_cpuapp.yaml | 0 .../pan1783_evb_cpuapp_defconfig | 0 .../pan1783_evb_cpunet.dts | 23 +++++++ .../pan1783_evb_cpunet.yaml | 0 .../pan1783_evb_cpunet_defconfig | 0 ...n1783_pan1783a_cpuapp_common-pinctrl.dtsi} | 0 .../pan1783_pan1783a_cpuapp_common.dtsi} | 4 +- ...n1783_pan1783a_cpuapp_partition_conf.dtsi} | 4 +- .../pan1783_pan1783a_cpunet-pinctrl.dtsi} | 0 .../pan1783_pan1783a_cpunet_common.dtsi} | 46 ++++++------- .../pan1783_pan1783a_evb_cpunet_reset.c} | 6 ++ ...3_pan1783a_shared_sram_planning_conf.dtsi} | 0 .../pan1783a_evb_cpuapp.dts | 21 ++++++ .../pan1783a_evb_cpuapp.yaml | 21 ++++++ .../pan1783a_evb_cpuapp_defconfig | 25 +++++++ .../pan1783a_evb_cpunet.dts | 23 +++++++ .../pan1783a_evb_cpunet.yaml | 14 ++++ .../pan1783a_evb_cpunet_defconfig | 18 +++++ .../pre_dt_board.cmake | 0 31 files changed, 276 insertions(+), 117 deletions(-) delete mode 100644 boards/arm/pan1783_evb/CMakeLists.txt delete mode 100644 boards/arm/pan1783_evb/board.cmake delete mode 100644 boards/arm/pan1783_evb/doc/index.rst create mode 100644 boards/arm/pan1783_pan1783a_evb/CMakeLists.txt rename boards/arm/{pan1783_evb => pan1783_pan1783a_evb}/Kconfig (79%) rename boards/arm/{pan1783_evb => pan1783_pan1783a_evb}/Kconfig.board (61%) rename boards/arm/{pan1783_evb => pan1783_pan1783a_evb}/Kconfig.defconfig (55%) create mode 100644 boards/arm/pan1783_pan1783a_evb/board.cmake rename boards/arm/{pan1783_evb => pan1783_pan1783a_evb}/doc/img/pan1783_evb.jpg (100%) create mode 100644 boards/arm/pan1783_pan1783a_evb/doc/img/pan1783a_evb.jpg create mode 100644 boards/arm/pan1783_pan1783a_evb/doc/index.rst rename boards/arm/{pan1783_evb => pan1783_pan1783a_evb}/pan1783_evb_cpuapp.dts (90%) rename boards/arm/{pan1783_evb => pan1783_pan1783a_evb}/pan1783_evb_cpuapp.yaml (100%) rename boards/arm/{pan1783_evb => pan1783_pan1783a_evb}/pan1783_evb_cpuapp_defconfig (100%) create mode 100644 boards/arm/pan1783_pan1783a_evb/pan1783_evb_cpunet.dts rename boards/arm/{pan1783_evb => pan1783_pan1783a_evb}/pan1783_evb_cpunet.yaml (100%) rename boards/arm/{pan1783_evb => pan1783_pan1783a_evb}/pan1783_evb_cpunet_defconfig (100%) rename boards/arm/{pan1783_evb/pan1783_evb_cpuapp_common-pinctrl.dtsi => pan1783_pan1783a_evb/pan1783_pan1783a_cpuapp_common-pinctrl.dtsi} (100%) rename boards/arm/{pan1783_evb/pan1783_evb_cpuapp_common.dtsi => pan1783_pan1783a_evb/pan1783_pan1783a_cpuapp_common.dtsi} (98%) rename boards/arm/{pan1783_evb/pan1783_evb_cpuapp_partition_conf.dtsi => pan1783_pan1783a_evb/pan1783_pan1783a_cpuapp_partition_conf.dtsi} (87%) rename boards/arm/{pan1783_evb/pan1783_evb_cpunet-pinctrl.dtsi => pan1783_pan1783a_evb/pan1783_pan1783a_cpunet-pinctrl.dtsi} (100%) rename boards/arm/{pan1783_evb/pan1783_evb_cpunet.dts => pan1783_pan1783a_evb/pan1783_pan1783a_cpunet_common.dtsi} (83%) rename boards/arm/{pan1783_evb/pan1783_evb_cpunet_reset.c => pan1783_pan1783a_evb/pan1783_pan1783a_evb_cpunet_reset.c} (83%) rename boards/arm/{pan1783_evb/pan1783_evb_shared_sram_planning_conf.dtsi => pan1783_pan1783a_evb/pan1783_pan1783a_shared_sram_planning_conf.dtsi} (100%) create mode 100644 boards/arm/pan1783_pan1783a_evb/pan1783a_evb_cpuapp.dts create mode 100644 boards/arm/pan1783_pan1783a_evb/pan1783a_evb_cpuapp.yaml create mode 100644 boards/arm/pan1783_pan1783a_evb/pan1783a_evb_cpuapp_defconfig create mode 100644 boards/arm/pan1783_pan1783a_evb/pan1783a_evb_cpunet.dts create mode 100644 boards/arm/pan1783_pan1783a_evb/pan1783a_evb_cpunet.yaml create mode 100644 boards/arm/pan1783_pan1783a_evb/pan1783a_evb_cpunet_defconfig rename boards/arm/{pan1783_evb => pan1783_pan1783a_evb}/pre_dt_board.cmake (100%) diff --git a/boards/arm/pan1783_evb/CMakeLists.txt b/boards/arm/pan1783_evb/CMakeLists.txt deleted file mode 100644 index f8bc359b603..00000000000 --- a/boards/arm/pan1783_evb/CMakeLists.txt +++ /dev/null @@ -1,7 +0,0 @@ -# Copyright (c) 2023 Panasonic Industrial Devices Europe GmbH -# SPDX-License-Identifier: Apache-2.0 - -if ((CONFIG_BOARD_PAN1783_EVB_CPUAPP) AND (CONFIG_BOARD_ENABLE_CPUNET)) -zephyr_library() -zephyr_library_sources(pan1783_evb_cpunet_reset.c) -endif() diff --git a/boards/arm/pan1783_evb/board.cmake b/boards/arm/pan1783_evb/board.cmake deleted file mode 100644 index f75151ecb94..00000000000 --- a/boards/arm/pan1783_evb/board.cmake +++ /dev/null @@ -1,12 +0,0 @@ -# SPDX-License-Identifier: Apache-2.0 - -if(CONFIG_BOARD_PAN1783_EVB_CPUAPP) -board_runner_args(jlink "--device=nrf5340_xxaa_app" "--speed=4000") -endif() - -if(CONFIG_BOARD_PAN1783_EVB_CPUNET) -board_runner_args(jlink "--device=nrf5340_xxaa_net" "--speed=4000") -endif() - -include(${ZEPHYR_BASE}/boards/common/nrfjprog.board.cmake) -include(${ZEPHYR_BASE}/boards/common/jlink.board.cmake) diff --git a/boards/arm/pan1783_evb/doc/index.rst b/boards/arm/pan1783_evb/doc/index.rst deleted file mode 100644 index 39fe7fdff8f..00000000000 --- a/boards/arm/pan1783_evb/doc/index.rst +++ /dev/null @@ -1,55 +0,0 @@ -.. _pan1783_evb: - -PAN1783 Evaluation Board -######################## - -Overview -******** - -The PAN1783 Evaluation Board (pan1783_evb) is a development tool for the -PAN1783 Module which is based on the nRF5340 chipset from Nordic Semiconductor. - -You can find more information about the PAN1783 Module and Evaluation Board -on the `product website`_. - -.. figure:: img/pan1783_evb.jpg - :align: center - :alt: PAN1783 EVB - - PAN1783 EVB (Credit: Panasonic) - -The PAN1783 Evaluation Board is closely linked to these other evaluation -boards: - -* pan1783a_evb -* pan1783a_pa_evb - -Usage -***** - -For detailed information, you can find the `user guide`_ for the PAN1783 -Evaluation Board in the `Panasonic Wireless Connectivity Development Hub`_. - -The User Guide contains (amongst other things) detailed information about - -* pin mapping -* powering options -* breakout pin header interface -* current consumption measurement -* software development - -The schematics for the PAN1783 Evaluation Board are available in the -`download section`_ of the `Panasonic Wireless Connectivity Development Hub`_. - -Programming and Debugging -************************* - -Please use the ``pan1783_evb_cpuapp`` for application core or -``pan1783_evb_cpunet`` board configuration for network core -when :ref:`build_an_application` and :ref:`application_run`. - -.. target-notes:: -.. _product website: https://industry.panasonic.eu/products/devices/wireless-connectivity/bluetooth-low-energy-modules/pan1783-nrf5340 -.. _Panasonic Wireless Connectivity Development Hub: https://pideu.panasonic.de/development-hub/ -.. _user guide: https://pideu.panasonic.de/development-hub/pan1783/evaluation_board/user_guide/ -.. _download section: https://pideu.panasonic.de/development-hub/pan1783/downloads/ diff --git a/boards/arm/pan1783_pan1783a_evb/CMakeLists.txt b/boards/arm/pan1783_pan1783a_evb/CMakeLists.txt new file mode 100644 index 00000000000..9530e370252 --- /dev/null +++ b/boards/arm/pan1783_pan1783a_evb/CMakeLists.txt @@ -0,0 +1,7 @@ +# Copyright (c) 2023 Panasonic Industrial Devices Europe GmbH +# SPDX-License-Identifier: Apache-2.0 + +if((CONFIG_BOARD_PAN1783_EVB_CPUAPP OR CONFIG_BOARD_PAN1783A_EVB_CPUAPP) AND (CONFIG_BOARD_ENABLE_CPUNET)) + zephyr_library() + zephyr_library_sources(pan1783_pan1783a_evb_cpunet_reset.c) +endif() diff --git a/boards/arm/pan1783_evb/Kconfig b/boards/arm/pan1783_pan1783a_evb/Kconfig similarity index 79% rename from boards/arm/pan1783_evb/Kconfig rename to boards/arm/pan1783_pan1783a_evb/Kconfig index b9c84ba66ff..a699840cad9 100644 --- a/boards/arm/pan1783_evb/Kconfig +++ b/boards/arm/pan1783_pan1783a_evb/Kconfig @@ -3,7 +3,7 @@ # Copyright (c) 2023 Panasonic Industrial Devices Europe GmbH # SPDX-License-Identifier: Apache-2.0 -if BOARD_PAN1783_EVB_CPUAPP +if BOARD_PAN1783_EVB_CPUAPP || BOARD_PAN1783A_EVB_CPUAPP config BOARD_ENABLE_DCDC_APP bool "Application MCU DCDC converter" @@ -33,7 +33,8 @@ config BOARD_ENABLE_CPUNET config DOMAIN_CPUNET_BOARD string - default "pan1783_evb_cpunet" + default "pan1783_evb_cpunet" if BOARD_PAN1783_EVB_CPUAPP + default "pan1783a_evb_cpunet" if BOARD_PAN1783A_EVB_CPUAPP depends on BOARD_ENABLE_CPUNET help The board which will be used for CPUNET domain when creating a multi @@ -41,12 +42,12 @@ config DOMAIN_CPUNET_BOARD another board. For example hci_ipc on the nRF5340_cpunet for Bluetooth applications. -endif # BOARD_PAN1783_EVB_CPUAPP +endif # BOARD_PAN1783_EVB_CPUAPP || BOARD_PAN1783A_EVB_CPUAPP config DOMAIN_CPUAPP_BOARD string - default "pan1783_evb_cpuapp" - depends on BOARD_PAN1783_EVB_CPUNET + default "pan1783_evb_cpuapp" if BOARD_PAN1783_EVB_CPUNET + default "pan1783a_evb_cpuapp" if BOARD_PAN1783A_EVB_CPUNET help The board which will be used for CPUAPP domain when creating a multi image application where one or more images should be located on diff --git a/boards/arm/pan1783_evb/Kconfig.board b/boards/arm/pan1783_pan1783a_evb/Kconfig.board similarity index 61% rename from boards/arm/pan1783_evb/Kconfig.board rename to boards/arm/pan1783_pan1783a_evb/Kconfig.board index d66c99aac36..cfb5629b24c 100644 --- a/boards/arm/pan1783_evb/Kconfig.board +++ b/boards/arm/pan1783_pan1783a_evb/Kconfig.board @@ -7,6 +7,14 @@ config BOARD_PAN1783_EVB_CPUAPP bool "PAN1783 EVB (nRF5340) Application MCU" depends on SOC_NRF5340_CPUAPP_QKAA +config BOARD_PAN1783A_EVB_CPUAPP + bool "PAN1783A EVB (nRF5340) Application MCU" + depends on SOC_NRF5340_CPUAPP_QKAA + config BOARD_PAN1783_EVB_CPUNET bool "PAN1783 EVB (NRF5340) Network MCU" depends on SOC_NRF5340_CPUNET_QKAA + +config BOARD_PAN1783A_EVB_CPUNET + bool "PAN1783A EVB (NRF5340) Network MCU" + depends on SOC_NRF5340_CPUNET_QKAA diff --git a/boards/arm/pan1783_evb/Kconfig.defconfig b/boards/arm/pan1783_pan1783a_evb/Kconfig.defconfig similarity index 55% rename from boards/arm/pan1783_evb/Kconfig.defconfig rename to boards/arm/pan1783_pan1783a_evb/Kconfig.defconfig index b26b4970d84..a8e70837d3a 100644 --- a/boards/arm/pan1783_evb/Kconfig.defconfig +++ b/boards/arm/pan1783_pan1783a_evb/Kconfig.defconfig @@ -5,14 +5,14 @@ config BOARD default "pan1783_evb_cpuapp" if BOARD_PAN1783_EVB_CPUAPP - -config BOARD + default "pan1783a_evb_cpuapp" if BOARD_PAN1783A_EVB_CPUAPP default "pan1783_evb_cpunet" if BOARD_PAN1783_EVB_CPUNET + default "pan1783a_evb_cpunet" if BOARD_PAN1783A_EVB_CPUNET config MBOX_NRFX_IPC default MBOX -if BOARD_PAN1783_EVB_CPUAPP +if BOARD_PAN1783_EVB_CPUAPP || BOARD_PAN1783A_EVB_CPUAPP choice BT_HCI_BUS_TYPE default BT_HCI_IPC if BT @@ -21,11 +21,11 @@ endchoice config HEAP_MEM_POOL_SIZE default 4096 if BT_HCI_IPC -endif # BOARD_PAN1783_EVB_CPUAPP +endif # BOARD_PAN1783_EVB_CPUAPP || BOARD_PAN1783A_EVB_CPUAPP -if BOARD_PAN1783_EVB_CPUNET +if BOARD_PAN1783_EVB_CPUNET || BOARD_PAN1783A_EVB_CPUNET config BT_CTLR default y if BT -endif # BOARD_PAN1783_EVB_CPUNET +endif # BOARD_PAN1783_EVB_CPUNET || BOARD_PAN1783A_EVB_CPUNET diff --git a/boards/arm/pan1783_pan1783a_evb/board.cmake b/boards/arm/pan1783_pan1783a_evb/board.cmake new file mode 100644 index 00000000000..5fe4b0507c7 --- /dev/null +++ b/boards/arm/pan1783_pan1783a_evb/board.cmake @@ -0,0 +1,12 @@ +# SPDX-License-Identifier: Apache-2.0 + +if(CONFIG_BOARD_PAN1783_EVB_CPUAPP OR CONFIG_BOARD_PAN1783A_EVB_CPUAPP) + board_runner_args(jlink "--device=nrf5340_xxaa_app" "--speed=4000") +endif() + +if(CONFIG_BOARD_PAN1783_EVB_CPUNET OR CONFIG_BOARD_PAN1783A_EVB_CPUNET) + board_runner_args(jlink "--device=nrf5340_xxaa_net" "--speed=4000") +endif() + +include(${ZEPHYR_BASE}/boards/common/nrfjprog.board.cmake) +include(${ZEPHYR_BASE}/boards/common/jlink.board.cmake) diff --git a/boards/arm/pan1783_evb/doc/img/pan1783_evb.jpg b/boards/arm/pan1783_pan1783a_evb/doc/img/pan1783_evb.jpg similarity index 100% rename from boards/arm/pan1783_evb/doc/img/pan1783_evb.jpg rename to boards/arm/pan1783_pan1783a_evb/doc/img/pan1783_evb.jpg diff --git a/boards/arm/pan1783_pan1783a_evb/doc/img/pan1783a_evb.jpg b/boards/arm/pan1783_pan1783a_evb/doc/img/pan1783a_evb.jpg new file mode 100644 index 0000000000000000000000000000000000000000..aeab9bdb96a1143a7fd5da3b3a59a3000a1fe71f GIT binary patch literal 62330 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 -#include "pan1783_evb_cpuapp_common.dtsi" +#include "pan1783_pan1783a_cpuapp_common.dtsi" / { model = "Panasonic PAN1783 EVB (NRF5340) Application"; diff --git a/boards/arm/pan1783_evb/pan1783_evb_cpuapp.yaml b/boards/arm/pan1783_pan1783a_evb/pan1783_evb_cpuapp.yaml similarity index 100% rename from boards/arm/pan1783_evb/pan1783_evb_cpuapp.yaml rename to boards/arm/pan1783_pan1783a_evb/pan1783_evb_cpuapp.yaml diff --git a/boards/arm/pan1783_evb/pan1783_evb_cpuapp_defconfig b/boards/arm/pan1783_pan1783a_evb/pan1783_evb_cpuapp_defconfig similarity index 100% rename from boards/arm/pan1783_evb/pan1783_evb_cpuapp_defconfig rename to boards/arm/pan1783_pan1783a_evb/pan1783_evb_cpuapp_defconfig diff --git a/boards/arm/pan1783_pan1783a_evb/pan1783_evb_cpunet.dts b/boards/arm/pan1783_pan1783a_evb/pan1783_evb_cpunet.dts new file mode 100644 index 00000000000..bd84c622126 --- /dev/null +++ b/boards/arm/pan1783_pan1783a_evb/pan1783_evb_cpunet.dts @@ -0,0 +1,23 @@ +/* + * Copyright (c) 2023 Panasonic Industrial Devices Europe GmbH + * + * SPDX-License-Identifier: Apache-2.0 + */ + +/dts-v1/; +#include +#include "pan1783_pan1783a_cpunet_common.dtsi" + +/ { + model = "Panasonic PAN1783 EVB (NRF5340) Network"; + compatible = "panasonic,pan1783-evb-cpunet"; + + chosen { + zephyr,sram = &sram1; + zephyr,flash = &flash1; + zephyr,code-partition = &slot0_partition; + }; +}; + +/* Include shared RAM configuration file */ +#include "pan1783_pan1783a_shared_sram_planning_conf.dtsi" diff --git a/boards/arm/pan1783_evb/pan1783_evb_cpunet.yaml b/boards/arm/pan1783_pan1783a_evb/pan1783_evb_cpunet.yaml similarity index 100% rename from boards/arm/pan1783_evb/pan1783_evb_cpunet.yaml rename to boards/arm/pan1783_pan1783a_evb/pan1783_evb_cpunet.yaml diff --git a/boards/arm/pan1783_evb/pan1783_evb_cpunet_defconfig b/boards/arm/pan1783_pan1783a_evb/pan1783_evb_cpunet_defconfig similarity index 100% rename from boards/arm/pan1783_evb/pan1783_evb_cpunet_defconfig rename to boards/arm/pan1783_pan1783a_evb/pan1783_evb_cpunet_defconfig diff --git a/boards/arm/pan1783_evb/pan1783_evb_cpuapp_common-pinctrl.dtsi b/boards/arm/pan1783_pan1783a_evb/pan1783_pan1783a_cpuapp_common-pinctrl.dtsi similarity index 100% rename from boards/arm/pan1783_evb/pan1783_evb_cpuapp_common-pinctrl.dtsi rename to boards/arm/pan1783_pan1783a_evb/pan1783_pan1783a_cpuapp_common-pinctrl.dtsi diff --git a/boards/arm/pan1783_evb/pan1783_evb_cpuapp_common.dtsi b/boards/arm/pan1783_pan1783a_evb/pan1783_pan1783a_cpuapp_common.dtsi similarity index 98% rename from boards/arm/pan1783_evb/pan1783_evb_cpuapp_common.dtsi rename to boards/arm/pan1783_pan1783a_evb/pan1783_pan1783a_cpuapp_common.dtsi index 175475f5b0e..82f49665338 100644 --- a/boards/arm/pan1783_evb/pan1783_evb_cpuapp_common.dtsi +++ b/boards/arm/pan1783_pan1783a_evb/pan1783_pan1783a_cpuapp_common.dtsi @@ -3,7 +3,7 @@ * * SPDX-License-Identifier: Apache-2.0 */ -#include "pan1783_evb_cpuapp_common-pinctrl.dtsi" +#include "pan1783_pan1783a_cpuapp_common-pinctrl.dtsi" #include / { @@ -297,4 +297,4 @@ zephyr_udc0: &usbd { }; /* Include partition configuration file */ -#include "pan1783_evb_cpuapp_partition_conf.dtsi" +#include "pan1783_pan1783a_cpuapp_partition_conf.dtsi" diff --git a/boards/arm/pan1783_evb/pan1783_evb_cpuapp_partition_conf.dtsi b/boards/arm/pan1783_pan1783a_evb/pan1783_pan1783a_cpuapp_partition_conf.dtsi similarity index 87% rename from boards/arm/pan1783_evb/pan1783_evb_cpuapp_partition_conf.dtsi rename to boards/arm/pan1783_pan1783a_evb/pan1783_pan1783a_cpuapp_partition_conf.dtsi index 50e32748bec..0ddf9287c7e 100644 --- a/boards/arm/pan1783_evb/pan1783_evb_cpuapp_partition_conf.dtsi +++ b/boards/arm/pan1783_pan1783a_evb/pan1783_pan1783a_cpuapp_partition_conf.dtsi @@ -24,7 +24,7 @@ /* Default SRAM planning when building for nRF5340 * - Lowest 448 kB SRAM allocated to Secure image (sram0_s) * - Upper 64 kB SRAM allocated as Shared memory (sram0_shared) - * (see pan1783_evb_shared_sram_planning_conf.dts) + * (see shared_sram_planning_conf.dtsi) */ &sram0_image { reg = <0x20000000 DT_SIZE_K(448)>; @@ -35,4 +35,4 @@ }; /* Include shared RAM configuration file */ -#include "pan1783_evb_shared_sram_planning_conf.dtsi" +#include "pan1783_pan1783a_shared_sram_planning_conf.dtsi" diff --git a/boards/arm/pan1783_evb/pan1783_evb_cpunet-pinctrl.dtsi b/boards/arm/pan1783_pan1783a_evb/pan1783_pan1783a_cpunet-pinctrl.dtsi similarity index 100% rename from boards/arm/pan1783_evb/pan1783_evb_cpunet-pinctrl.dtsi rename to boards/arm/pan1783_pan1783a_evb/pan1783_pan1783a_cpunet-pinctrl.dtsi diff --git a/boards/arm/pan1783_evb/pan1783_evb_cpunet.dts b/boards/arm/pan1783_pan1783a_evb/pan1783_pan1783a_cpunet_common.dtsi similarity index 83% rename from boards/arm/pan1783_evb/pan1783_evb_cpunet.dts rename to boards/arm/pan1783_pan1783a_evb/pan1783_pan1783a_cpunet_common.dtsi index 6506c46aeed..8cd2d154e8e 100644 --- a/boards/arm/pan1783_evb/pan1783_evb_cpunet.dts +++ b/boards/arm/pan1783_pan1783a_evb/pan1783_pan1783a_cpunet_common.dtsi @@ -3,15 +3,10 @@ * * SPDX-License-Identifier: Apache-2.0 */ - -/dts-v1/; -#include -#include "pan1783_evb_cpunet-pinctrl.dtsi" +#include "pan1783_pan1783a_cpunet-pinctrl.dtsi" #include / { - model = "Panasonic PAN1783 EVB (NRF5340) Network"; - compatible = "panasonic,pan1783-evb-cpunet"; chosen { zephyr,console = &uart0; @@ -21,9 +16,6 @@ zephyr,bt-c2h-uart = &uart0; zephyr,bt-hci-ipc = &ipc0; nordic,802154-spinel-ipc = &ipc0; - zephyr,sram = &sram1; - zephyr,flash = &flash1; - zephyr,code-partition = &slot0_partition; zephyr,ieee802154 = &ieee802154; }; @@ -76,22 +68,22 @@ #gpio-cells = <2>; gpio-map-mask = <0xffffffff 0xffffffc0>; gpio-map-pass-thru = <0 0x3f>; - gpio-map = <0 0 &gpio0 4 0>, /* AN */ - /* Not a GPIO*/ /* RST */ - <2 0 &gpio1 12 0>, /* CS */ - <3 0 &gpio1 15 0>, /* SCK */ - <4 0 &gpio1 14 0>, /* MISO */ - <5 0 &gpio1 13 0>, /* MOSI */ - /* +3.3V */ - /* GND */ - <6 0 &gpio1 7 0>, /* PWM */ - <7 0 &gpio1 4 0>, /* INT */ - <8 0 &gpio1 0 0>, /* RX */ - <9 0 &gpio1 1 0>, /* TX */ - <10 0 &gpio1 3 0>, /* SCL */ - <11 0 &gpio1 2 0>; /* SDA */ - /* +5V */ - /* GND */ + gpio-map = <0 0 &gpio0 4 0>, /* AN */ + /* Not a GPIO*/ /* RST */ + <2 0 &gpio1 12 0>, /* CS */ + <3 0 &gpio1 15 0>, /* SCK */ + <4 0 &gpio1 14 0>, /* MISO */ + <5 0 &gpio1 13 0>, /* MOSI */ + /* +3.3V */ + /* GND */ + <6 0 &gpio1 7 0>, /* PWM */ + <7 0 &gpio1 4 0>, /* INT */ + <8 0 &gpio1 0 0>, /* RX */ + <9 0 &gpio1 1 0>, /* TX */ + <10 0 &gpio1 3 0>, /* SCL */ + <11 0 &gpio1 2 0>; /* SDA */ + /* +5V */ + /* GND */ }; arduino_header: connector { @@ -160,7 +152,7 @@ pinctrl-names = "default", "sleep"; }; -arduino_serial: &uart0{}; +arduino_serial: &uart0 {}; arduino_i2c: &i2c0 { compatible = "nordic,nrf-twim"; @@ -212,4 +204,4 @@ arduino_spi: &spi0 { }; /* Include shared RAM configuration file */ -#include "pan1783_evb_shared_sram_planning_conf.dtsi" +#include "pan1783_pan1783a_shared_sram_planning_conf.dtsi" diff --git a/boards/arm/pan1783_evb/pan1783_evb_cpunet_reset.c b/boards/arm/pan1783_pan1783a_evb/pan1783_pan1783a_evb_cpunet_reset.c similarity index 83% rename from boards/arm/pan1783_evb/pan1783_evb_cpunet_reset.c rename to boards/arm/pan1783_pan1783a_evb/pan1783_pan1783a_evb_cpunet_reset.c index 5b30492a1f9..0c957e0ed3b 100644 --- a/boards/arm/pan1783_evb/pan1783_evb_cpunet_reset.c +++ b/boards/arm/pan1783_pan1783a_evb/pan1783_pan1783a_evb_cpunet_reset.c @@ -11,7 +11,13 @@ #include #include +#if defined(CONFIG_BOARD_PAN1783_EVB_CPUAPP) LOG_MODULE_REGISTER(pan1783_evb_cpuapp, CONFIG_LOG_DEFAULT_LEVEL); +#elif defined(CONFIG_BOARD_PAN1783A_EVB_CPUAPP) +LOG_MODULE_REGISTER(pan1783a_evb_cpuapp, CONFIG_LOG_DEFAULT_LEVEL); +#else +#error "No board selected!" +#endif #if defined(CONFIG_BT_CTLR_DEBUG_PINS_CPUAPP) #include <../subsys/bluetooth/controller/ll_sw/nordic/hal/nrf5/debug.h> diff --git a/boards/arm/pan1783_evb/pan1783_evb_shared_sram_planning_conf.dtsi b/boards/arm/pan1783_pan1783a_evb/pan1783_pan1783a_shared_sram_planning_conf.dtsi similarity index 100% rename from boards/arm/pan1783_evb/pan1783_evb_shared_sram_planning_conf.dtsi rename to boards/arm/pan1783_pan1783a_evb/pan1783_pan1783a_shared_sram_planning_conf.dtsi diff --git a/boards/arm/pan1783_pan1783a_evb/pan1783a_evb_cpuapp.dts b/boards/arm/pan1783_pan1783a_evb/pan1783a_evb_cpuapp.dts new file mode 100644 index 00000000000..dc3ff1357e4 --- /dev/null +++ b/boards/arm/pan1783_pan1783a_evb/pan1783a_evb_cpuapp.dts @@ -0,0 +1,21 @@ +/* + * Copyright (c) 2023 Panasonic Industrial Devices Europe GmbH + * + * SPDX-License-Identifier: Apache-2.0 + */ + +/dts-v1/; +#include +#include "pan1783_pan1783a_cpuapp_common.dtsi" + +/ { + model = "Panasonic PAN1783A EVB (NRF5340) Application"; + compatible = "panasonic,pan1783a-evb-cpuapp"; + + chosen { + zephyr,sram = &sram0_image; + zephyr,flash = &flash0; + zephyr,code-partition = &slot0_partition; + zephyr,sram-secure-partition = &sram0_s; + }; +}; diff --git a/boards/arm/pan1783_pan1783a_evb/pan1783a_evb_cpuapp.yaml b/boards/arm/pan1783_pan1783a_evb/pan1783a_evb_cpuapp.yaml new file mode 100644 index 00000000000..2a89c3f1f37 --- /dev/null +++ b/boards/arm/pan1783_pan1783a_evb/pan1783a_evb_cpuapp.yaml @@ -0,0 +1,21 @@ +identifier: pan1783a_evb_cpuapp +name: PAN1783A-EVB-application-MCU +type: mcu +arch: arm +toolchain: + - gnuarmemb + - xtools + - zephyr +ram: 448 +flash: 1024 +supported: + - gpio + - i2c + - i2s + - pwm + - watchdog + - usb_cdc + - usb_device + - netif:openthread + - gpio +vendor: panasonic diff --git a/boards/arm/pan1783_pan1783a_evb/pan1783a_evb_cpuapp_defconfig b/boards/arm/pan1783_pan1783a_evb/pan1783a_evb_cpuapp_defconfig new file mode 100644 index 00000000000..2f624e1db0c --- /dev/null +++ b/boards/arm/pan1783_pan1783a_evb/pan1783a_evb_cpuapp_defconfig @@ -0,0 +1,25 @@ +# SPDX-License-Identifier: Apache-2.0 + +CONFIG_SOC_SERIES_NRF53X=y +CONFIG_SOC_NRF5340_CPUAPP_QKAA=y +CONFIG_BOARD_PAN1783A_EVB_CPUAPP=y + +# Enable MPU +CONFIG_ARM_MPU=y + +# Enable hardware stack protection +CONFIG_HW_STACK_PROTECTION=y + +# enable GPIO +CONFIG_GPIO=y + +# Enable uart driver +CONFIG_SERIAL=y + +# enable console +CONFIG_CONSOLE=y +CONFIG_UART_CONSOLE=y + +# clock config +CONFIG_CLOCK_CONTROL_NRF_K32SRC_RC=y +CONFIG_CLOCK_CONTROL_NRF_K32SRC_XTAL=n diff --git a/boards/arm/pan1783_pan1783a_evb/pan1783a_evb_cpunet.dts b/boards/arm/pan1783_pan1783a_evb/pan1783a_evb_cpunet.dts new file mode 100644 index 00000000000..8be0b5966a8 --- /dev/null +++ b/boards/arm/pan1783_pan1783a_evb/pan1783a_evb_cpunet.dts @@ -0,0 +1,23 @@ +/* + * Copyright (c) 2023 Panasonic Industrial Devices Europe GmbH + * + * SPDX-License-Identifier: Apache-2.0 + */ + +/dts-v1/; +#include +#include "pan1783_pan1783a_cpunet_common.dtsi" + +/ { + model = "Panasonic PAN1783A EVB (NRF5340) Network"; + compatible = "panasonic,pan1783a-evb-cpunet"; + + chosen { + zephyr,sram = &sram1; + zephyr,flash = &flash1; + zephyr,code-partition = &slot0_partition; + }; +}; + +/* Include shared RAM configuration file */ +#include "pan1783_pan1783a_shared_sram_planning_conf.dtsi" diff --git a/boards/arm/pan1783_pan1783a_evb/pan1783a_evb_cpunet.yaml b/boards/arm/pan1783_pan1783a_evb/pan1783a_evb_cpunet.yaml new file mode 100644 index 00000000000..2dd985f61ff --- /dev/null +++ b/boards/arm/pan1783_pan1783a_evb/pan1783a_evb_cpunet.yaml @@ -0,0 +1,14 @@ +identifier: pan1783a_evb_cpunet +name: PAN1783A-EVB-network-MCU +type: mcu +arch: arm +toolchain: + - gnuarmemb + - xtools + - zephyr +ram: 64 +flash: 256 +supported: + - watchdog + - gpio +vendor: panasonic diff --git a/boards/arm/pan1783_pan1783a_evb/pan1783a_evb_cpunet_defconfig b/boards/arm/pan1783_pan1783a_evb/pan1783a_evb_cpunet_defconfig new file mode 100644 index 00000000000..3e44ff7338c --- /dev/null +++ b/boards/arm/pan1783_pan1783a_evb/pan1783a_evb_cpunet_defconfig @@ -0,0 +1,18 @@ +# SPDX-License-Identifier: Apache-2.0 + +CONFIG_SOC_SERIES_NRF53X=y +CONFIG_SOC_NRF5340_CPUNET_QKAA=y +CONFIG_BOARD_PAN1783A_EVB_CPUNET=y + +# Enable MPU +CONFIG_ARM_MPU=y + +# Enable hardware stack protection +CONFIG_HW_STACK_PROTECTION=y + +# enable GPIO +CONFIG_GPIO=y + +# clock config +CONFIG_CLOCK_CONTROL_NRF_K32SRC_RC=y +CONFIG_CLOCK_CONTROL_NRF_K32SRC_XTAL=n diff --git a/boards/arm/pan1783_evb/pre_dt_board.cmake b/boards/arm/pan1783_pan1783a_evb/pre_dt_board.cmake similarity index 100% rename from boards/arm/pan1783_evb/pre_dt_board.cmake rename to boards/arm/pan1783_pan1783a_evb/pre_dt_board.cmake From 49a7038d1f041554c9e7c3f7633659eeeec8ef48 Mon Sep 17 00:00:00 2001 From: Mariusz Skamra Date: Fri, 1 Dec 2023 09:03:05 +0100 Subject: [PATCH 1012/3723] modules: liblc3: Bump to 1.0.4 Bump up liblc3 to the 1.0.4. Signed-off-by: Mariusz Skamra --- west.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/west.yml b/west.yml index d639b0217bd..eb803769b91 100644 --- a/west.yml +++ b/west.yml @@ -263,7 +263,7 @@ manifest: groups: - hal - name: liblc3 - revision: 448f3de31f49a838988a162ef1e23a89ddf2d2ed + revision: 1a5938ebaca4f13fe79ce074f5dee079783aa29f path: modules/lib/liblc3 - name: littlefs path: modules/fs/littlefs From 501384a57915f4ef0254bcb4b8bc3733441f24a0 Mon Sep 17 00:00:00 2001 From: Cong Nguyen Huu Date: Wed, 6 Dec 2023 08:46:20 +0700 Subject: [PATCH 1013/3723] drivers: nxp_s32_netc: configure to grant SI permissions Configure to grant SI permissions to allow to set MAC, update hash filter table and promiscuous multicast. Fixes #66198 Signed-off-by: Cong Nguyen Huu --- drivers/ethernet/eth_nxp_s32_netc_psi.c | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/drivers/ethernet/eth_nxp_s32_netc_psi.c b/drivers/ethernet/eth_nxp_s32_netc_psi.c index 623ca943c6e..977825ddd7a 100644 --- a/drivers/ethernet/eth_nxp_s32_netc_psi.c +++ b/drivers/ethernet/eth_nxp_s32_netc_psi.c @@ -222,6 +222,10 @@ BUILD_ASSERT(DT_NUM_INST_STATUS_OKAY(nxp_s32_netc_psi) == 1, "Only one PSI enabl .NumberOfTxBDR = 1, \ .SIVlanControl = (NETC_F3_PSICFGR0_SIVC_CVLAN_BIT \ | NETC_F3_PSICFGR0_SIVC_SVLAN_BIT), \ + .changeMACAllowed = true, \ + .hashFilterUpdateAllowed = true, \ + IF_ENABLED(CONFIG_NET_PROMISCUOUS_MODE, \ + (.multicastPromiscuousChangeAllowed = true,)) \ } #define NETC_VSI_RX_MSG_BUF(node, prop, idx, n) \ @@ -325,6 +329,10 @@ nxp_s32_eth##n##_psi_cfg[FEATURE_NETC_ETH_NUMBER_OF_CTRLS] = { \ .NumberOfTxBDR = 2, \ .SIVlanControl = (NETC_F3_PSICFGR0_SIVC_CVLAN_BIT \ | NETC_F3_PSICFGR0_SIVC_SVLAN_BIT), \ + .changeMACAllowed = true, \ + .hashFilterUpdateAllowed = true, \ + IF_ENABLED(CONFIG_NET_PROMISCUOUS_MODE, \ + (.multicastPromiscuousChangeAllowed = true,)) \ }, \ COND_CODE_1(INIT_VSIS(n), \ (DT_INST_FOREACH_PROP_ELEM_SEP(n, vsis, NETC_VSI_GENERAL_CFG, (,))), \ From 0ddb6aa82e39e99e9506eadde81e3b2ed74cc4a5 Mon Sep 17 00:00:00 2001 From: Lingao Meng Date: Wed, 6 Dec 2023 14:53:42 +0800 Subject: [PATCH 1014/3723] Bluetooth: Host: Use actual user_data size Use actual user_data size not default by 8. Signed-off-by: Lingao Meng --- subsys/bluetooth/controller/hci/hci.c | 3 ++- subsys/bluetooth/host/buf.c | 11 ++++++----- subsys/bluetooth/host/hci_core.c | 2 +- subsys/bluetooth/host/hci_raw.c | 11 +++++++---- subsys/bluetooth/host/hfp_hf.c | 2 +- subsys/bluetooth/host/iso.c | 3 ++- subsys/bluetooth/shell/rfcomm.c | 2 +- 7 files changed, 20 insertions(+), 14 deletions(-) diff --git a/subsys/bluetooth/controller/hci/hci.c b/subsys/bluetooth/controller/hci/hci.c index fac24c8be4a..2fd7dc41a9e 100644 --- a/subsys/bluetooth/controller/hci/hci.c +++ b/subsys/bluetooth/controller/hci/hci.c @@ -4953,7 +4953,8 @@ static void vs_read_tx_power_level(struct net_buf *buf, struct net_buf **evt) #if defined(CONFIG_BT_HCI_VS_FATAL_ERROR) /* A memory pool for vandor specific events for fatal error reporting purposes. */ -NET_BUF_POOL_FIXED_DEFINE(vs_err_tx_pool, 1, BT_BUF_EVT_RX_SIZE, 8, NULL); +NET_BUF_POOL_FIXED_DEFINE(vs_err_tx_pool, 1, BT_BUF_EVT_RX_SIZE, + sizeof(struct bt_buf_data), NULL); /* The alias for convenience of Controller HCI implementation. Controller is build for * a particular architecture hence the alias will allow to avoid conditional compilation. diff --git a/subsys/bluetooth/host/buf.c b/subsys/bluetooth/host/buf.c index 50b567d31b7..296d2aa0b5e 100644 --- a/subsys/bluetooth/host/buf.c +++ b/subsys/bluetooth/host/buf.c @@ -33,12 +33,13 @@ * Having a dedicated pool for it ensures that exhaustion of the RX pool * cannot block the delivery of this priority event. */ -NET_BUF_POOL_FIXED_DEFINE(num_complete_pool, 1, NUM_COMLETE_EVENT_SIZE, 8, NULL); +NET_BUF_POOL_FIXED_DEFINE(num_complete_pool, 1, NUM_COMLETE_EVENT_SIZE, + sizeof(struct bt_buf_data), NULL); #endif /* CONFIG_BT_CONN || CONFIG_BT_ISO */ NET_BUF_POOL_FIXED_DEFINE(discardable_pool, CONFIG_BT_BUF_EVT_DISCARDABLE_COUNT, - BT_BUF_EVT_SIZE(CONFIG_BT_BUF_EVT_DISCARDABLE_SIZE), 8, - NULL); + BT_BUF_EVT_SIZE(CONFIG_BT_BUF_EVT_DISCARDABLE_SIZE), + sizeof(struct bt_buf_data), NULL); #if defined(CONFIG_BT_HCI_ACL_FLOW_CONTROL) NET_BUF_POOL_DEFINE(acl_in_pool, CONFIG_BT_BUF_ACL_RX_COUNT, @@ -46,11 +47,11 @@ NET_BUF_POOL_DEFINE(acl_in_pool, CONFIG_BT_BUF_ACL_RX_COUNT, sizeof(struct acl_data), bt_hci_host_num_completed_packets); NET_BUF_POOL_FIXED_DEFINE(evt_pool, CONFIG_BT_BUF_EVT_RX_COUNT, - BT_BUF_EVT_RX_SIZE, 8, + BT_BUF_EVT_RX_SIZE, sizeof(struct bt_buf_data), NULL); #else NET_BUF_POOL_FIXED_DEFINE(hci_rx_pool, BT_BUF_RX_COUNT, - BT_BUF_RX_SIZE, 8, + BT_BUF_RX_SIZE, sizeof(struct bt_buf_data), NULL); #endif /* CONFIG_BT_HCI_ACL_FLOW_CONTROL */ diff --git a/subsys/bluetooth/host/hci_core.c b/subsys/bluetooth/host/hci_core.c index ae716406c2b..b003afa56d5 100644 --- a/subsys/bluetooth/host/hci_core.c +++ b/subsys/bluetooth/host/hci_core.c @@ -130,7 +130,7 @@ void bt_hci_cmd_state_set_init(struct net_buf *buf, */ #define CMD_BUF_SIZE MAX(BT_BUF_EVT_RX_SIZE, BT_BUF_CMD_TX_SIZE) NET_BUF_POOL_FIXED_DEFINE(hci_cmd_pool, CONFIG_BT_BUF_CMD_TX_COUNT, - CMD_BUF_SIZE, 8, NULL); + CMD_BUF_SIZE, sizeof(struct bt_buf_data), NULL); struct event_handler { uint8_t event; diff --git a/subsys/bluetooth/host/hci_raw.c b/subsys/bluetooth/host/hci_raw.c index 69ac82679e8..e40ae4cbddb 100644 --- a/subsys/bluetooth/host/hci_raw.c +++ b/subsys/bluetooth/host/hci_raw.c @@ -41,14 +41,17 @@ static uint8_t raw_mode; #endif NET_BUF_POOL_FIXED_DEFINE(hci_rx_pool, BT_BUF_RX_COUNT, - BT_BUF_RX_SIZE, 8, NULL); + BT_BUF_RX_SIZE, sizeof(struct bt_buf_data), NULL); NET_BUF_POOL_FIXED_DEFINE(hci_cmd_pool, CONFIG_BT_BUF_CMD_TX_COUNT, - BT_BUF_CMD_SIZE(CONFIG_BT_BUF_CMD_TX_SIZE), 8, NULL); + BT_BUF_CMD_SIZE(CONFIG_BT_BUF_CMD_TX_SIZE), + sizeof(struct bt_buf_data), NULL); NET_BUF_POOL_FIXED_DEFINE(hci_acl_pool, CONFIG_BT_BUF_ACL_TX_COUNT, - BT_BUF_ACL_SIZE(CONFIG_BT_BUF_ACL_TX_SIZE), 8, NULL); + BT_BUF_ACL_SIZE(CONFIG_BT_BUF_ACL_TX_SIZE), + sizeof(struct bt_buf_data), NULL); #if defined(CONFIG_BT_ISO) NET_BUF_POOL_FIXED_DEFINE(hci_iso_pool, CONFIG_BT_ISO_TX_BUF_COUNT, - BT_ISO_SDU_BUF_SIZE(CONFIG_BT_ISO_TX_MTU), 8, NULL); + BT_ISO_SDU_BUF_SIZE(CONFIG_BT_ISO_TX_MTU), + sizeof(struct bt_buf_data), NULL); #endif /* CONFIG_BT_ISO */ struct bt_dev_raw bt_dev; diff --git a/subsys/bluetooth/host/hfp_hf.c b/subsys/bluetooth/host/hfp_hf.c index 8487bea2081..9ad49278111 100644 --- a/subsys/bluetooth/host/hfp_hf.c +++ b/subsys/bluetooth/host/hfp_hf.c @@ -35,7 +35,7 @@ LOG_MODULE_REGISTER(bt_hfp_hf); struct bt_hfp_hf_cb *bt_hf; NET_BUF_POOL_FIXED_DEFINE(hf_pool, CONFIG_BT_MAX_CONN + 1, - BT_RFCOMM_BUF_SIZE(BT_HF_CLIENT_MAX_PDU), 8, NULL); + BT_RFCOMM_BUF_SIZE(BT_HF_CLIENT_MAX_PDU), 0, NULL); static struct bt_hfp_hf bt_hfp_hf_pool[CONFIG_BT_MAX_CONN]; diff --git a/subsys/bluetooth/host/iso.c b/subsys/bluetooth/host/iso.c index 42e9c877a9a..9559a552371 100644 --- a/subsys/bluetooth/host/iso.c +++ b/subsys/bluetooth/host/iso.c @@ -36,7 +36,8 @@ LOG_MODULE_REGISTER(bt_iso); #if defined(CONFIG_BT_ISO_UNICAST) || defined(CONFIG_BT_ISO_SYNC_RECEIVER) NET_BUF_POOL_FIXED_DEFINE(iso_rx_pool, CONFIG_BT_ISO_RX_BUF_COUNT, - BT_ISO_SDU_BUF_SIZE(CONFIG_BT_ISO_RX_MTU), 8, NULL); + BT_ISO_SDU_BUF_SIZE(CONFIG_BT_ISO_RX_MTU), + sizeof(struct iso_data), NULL); static struct bt_iso_recv_info iso_info_data[CONFIG_BT_ISO_RX_BUF_COUNT]; #define iso_info(buf) (&iso_info_data[net_buf_id(buf)]) diff --git a/subsys/bluetooth/shell/rfcomm.c b/subsys/bluetooth/shell/rfcomm.c index 382e8ca1401..fd578f9a33d 100644 --- a/subsys/bluetooth/shell/rfcomm.c +++ b/subsys/bluetooth/shell/rfcomm.c @@ -33,7 +33,7 @@ #define DATA_MTU 48 -NET_BUF_POOL_FIXED_DEFINE(pool, 1, DATA_MTU, 8, NULL); +NET_BUF_POOL_FIXED_DEFINE(pool, 1, DATA_MTU, 0, NULL); static struct bt_sdp_attribute spp_attrs[] = { BT_SDP_NEW_SERVICE, From ffd716b4a21451e5989c2a10c1f2ade0b43e1c09 Mon Sep 17 00:00:00 2001 From: Lingao Meng Date: Wed, 6 Dec 2023 20:04:09 +0800 Subject: [PATCH 1015/3723] Bluetooth: Host: iso_data extend bt_buf_data Explicitly declare that iso_data extends bt_buf_data. Signed-off-by: Lingao Meng --- subsys/bluetooth/host/iso_internal.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/subsys/bluetooth/host/iso_internal.h b/subsys/bluetooth/host/iso_internal.h index 10fc9409643..a48607c61c3 100644 --- a/subsys/bluetooth/host/iso_internal.h +++ b/subsys/bluetooth/host/iso_internal.h @@ -12,8 +12,8 @@ #include struct iso_data { - /** BT_BUF_ISO_IN */ - uint8_t type; + /* Extend the bt_buf user data */ + struct bt_buf_data buf_data; /* Index into the bt_conn storage array */ uint8_t index; From 23e15c480ac85ae450fc99e9a75cf04e3f188931 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andrzej=20G=C5=82=C4=85bek?= Date: Tue, 28 Nov 2023 13:05:59 +0100 Subject: [PATCH 1016/3723] soc: nrf53: Add implementation of workaround for anomaly 168 MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Use the already available in the tree mechanism of adding assembly instructions right after WFI/WFE to implement the workaround for nRF5340 anomaly 168 (replace the 4 NOP solution used on the network core as it turned out to be insufficient) and provide two related Kconfig options so that users are able to adjust the workaround to their actual needs (disable it entirely or use it in the extended version). Signed-off-by: Andrzej Głąbek --- soc/arm/nordic_nrf/nrf53/Kconfig.soc | 22 +++++++++++++++++++++- soc/arm/nordic_nrf/nrf53/soc_cpu_idle.h | 10 ++++++++-- 2 files changed, 29 insertions(+), 3 deletions(-) diff --git a/soc/arm/nordic_nrf/nrf53/Kconfig.soc b/soc/arm/nordic_nrf/nrf53/Kconfig.soc index 3afcd96f70d..3ecf09ecd92 100644 --- a/soc/arm/nordic_nrf/nrf53/Kconfig.soc +++ b/soc/arm/nordic_nrf/nrf53/Kconfig.soc @@ -12,13 +12,14 @@ config SOC_NRF5340_CPUAPP select HAS_POWEROFF select SOC_COMPATIBLE_NRF5340_CPUAPP imply SOC_NRF53_RTC_PRETICK + imply SOC_NRF53_ANOMALY_168_WORKAROUND config SOC_NRF5340_CPUNET bool - select ARM_ON_EXIT_CPU_IDLE select SOC_COMPATIBLE_NRF5340_CPUNET imply SOC_NRF53_ANOMALY_160_WORKAROUND_NEEDED imply SOC_NRF53_RTC_PRETICK if !WDT_NRFX + imply SOC_NRF53_ANOMALY_168_WORKAROUND choice prompt "nRF53x MCU Selection" @@ -79,6 +80,25 @@ config SOC_NRF53_RTC_PRETICK_IPC_CH_TO_NET endif +config SOC_NRF53_ANOMALY_168_WORKAROUND + bool "Workaround for nRF5340 anomaly 168" + select ARM_ON_EXIT_CPU_IDLE + help + Indicates that the workaround for the anomaly 168 that affects + the nRF5340 SoC should be applied. + The workaround involves execution of 8 NOP instructions when the CPU + exist its idle state (when the WFI/WFE instruction returns) and it is + enabled by default for both the application and network core. + +config SOC_NRF53_ANOMALY_168_WORKAROUND_FOR_EXECUTION_FROM_RAM + bool "Extend the workaround to execution at 128 MHz from RAM" + depends on SOC_NRF53_ANOMALY_168_WORKAROUND && SOC_NRF5340_CPUAPP + help + Indicates that the anomaly 168 workaround is to be extended to cover + also a specific case when the WFI/WFE instruction is executed at 128 + MHz from RAM. Then, 26 instead of 8 NOP instructions needs to be + executed after WFI/WFE. This extension is not enabled by default. + if SOC_NRF5340_CPUAPP config SOC_DCDC_NRF53X_APP diff --git a/soc/arm/nordic_nrf/nrf53/soc_cpu_idle.h b/soc/arm/nordic_nrf/nrf53/soc_cpu_idle.h index b6cd92ca092..dcb0c73d068 100644 --- a/soc/arm/nordic_nrf/nrf53/soc_cpu_idle.h +++ b/soc/arm/nordic_nrf/nrf53/soc_cpu_idle.h @@ -11,10 +11,16 @@ #if defined(_ASMLANGUAGE) +#if defined(CONFIG_SOC_NRF53_ANOMALY_168_WORKAROUND_FOR_EXECUTION_FROM_RAM) #define SOC_ON_EXIT_CPU_IDLE \ + .rept 26 \ nop; \ + .endr +#elif defined(CONFIG_SOC_NRF53_ANOMALY_168_WORKAROUND) +#define SOC_ON_EXIT_CPU_IDLE \ + .rept 8 \ nop; \ - nop; \ - nop; + .endr +#endif #endif /* _ASMLANGUAGE */ From 2b20c0e3e67bbcbafa33671736de30da2855f31c Mon Sep 17 00:00:00 2001 From: Benjamin Perseghetti Date: Mon, 11 Dec 2023 04:28:19 -0500 Subject: [PATCH 1017/3723] manifest: update hal_nxp for s32k3 lpspi. Update hal_nxp to remove S32K3X4-0P55A-1P55A-ERRATA by disabling FSL_FEATURE_LPSPI_HAS_ERRATA_050456. This allows for lpspi to work correctly on mr_canhubk3. Signed-off-by: Benjamin Perseghetti --- west.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/west.yml b/west.yml index eb803769b91..6400a94f14a 100644 --- a/west.yml +++ b/west.yml @@ -193,7 +193,7 @@ manifest: groups: - hal - name: hal_nxp - revision: cbf2cd1f099585eeef2cdb0c68d72e9e67e89c24 + revision: 2a294b540c09b36f7cddece44d25628bfde5970e path: modules/hal/nxp groups: - hal From 7c46b0b8984e1d3dacace7f10acb2c9ac3b29382 Mon Sep 17 00:00:00 2001 From: Xiao Qin Date: Thu, 14 Sep 2023 14:32:17 -0700 Subject: [PATCH 1018/3723] drivers: display: uc81xx: add support for uc8175 Add support for uc8175 display driver. uc8175 has a slightly different command/data length requirements for certain registers, namely TRES and PTL, compared to uc8176/uc8179 This commit refactors the driver code and such that setting TRES and PTL registers are now done by function pointers provided by config->quirks, by the same token as how it is done for setting CDI register Signed-off-by: Xiao Qin --- drivers/display/Kconfig.uc81xx | 2 +- drivers/display/uc81xx.c | 118 +++++++++++++++++---- drivers/display/uc81xx_regs.h | 26 ++++- dts/bindings/display/ultrachip,uc8175.yaml | 8 ++ 4 files changed, 126 insertions(+), 28 deletions(-) create mode 100644 dts/bindings/display/ultrachip,uc8175.yaml diff --git a/drivers/display/Kconfig.uc81xx b/drivers/display/Kconfig.uc81xx index 31951bd8180..75678d2f663 100644 --- a/drivers/display/Kconfig.uc81xx +++ b/drivers/display/Kconfig.uc81xx @@ -6,7 +6,7 @@ config UC81XX bool "UltraChip UC81xx compatible display controller driver" default y - depends on DT_HAS_ULTRACHIP_UC8176_ENABLED || DT_HAS_ULTRACHIP_UC8179_ENABLED + depends on DT_HAS_ULTRACHIP_UC8175_ENABLED || DT_HAS_ULTRACHIP_UC8176_ENABLED || DT_HAS_ULTRACHIP_UC8179_ENABLED select SPI help Enable driver for UC81xx compatible controller. diff --git a/drivers/display/uc81xx.c b/drivers/display/uc81xx.c index 88df6be0289..38a68cdfaf0 100644 --- a/drivers/display/uc81xx.c +++ b/drivers/display/uc81xx.c @@ -66,6 +66,10 @@ struct uc81xx_quirks { bool auto_copy; int (*set_cdi)(const struct device *dev, bool border); + int (*set_tres)(const struct device *dev); + int (*set_ptl)(const struct device *dev, uint16_t x, uint16_t y, + uint16_t x_end_idx, uint16_t y_end_idx, + const struct display_buffer_descriptor *desc); }; struct uc81xx_config { @@ -224,10 +228,6 @@ static int uc81xx_set_profile(const struct device *dev, UC81XX_PSR_SHL | UC81XX_PSR_SHD | UC81XX_PSR_RST; - const struct uc81xx_tres tres = { - .hres = sys_cpu_to_be16(config->width), - .vres = sys_cpu_to_be16(config->height), - }; if (type >= UC81XX_NUM_PROFILES) { return -EINVAL; @@ -272,9 +272,7 @@ static int uc81xx_set_profile(const struct device *dev, } /* Set panel resolution */ - LOG_HEXDUMP_DBG(&tres, sizeof(tres), "TRES"); - if (uc81xx_write_cmd(dev, UC81XX_CMD_TRES, - (const void *)&tres, sizeof(tres))) { + if (config->quirks->set_tres(dev)) { return -EIO; } @@ -403,13 +401,6 @@ static int uc81xx_write(const struct device *dev, const uint16_t x, const uint16 uint16_t x_end_idx = x + desc->width - 1; uint16_t y_end_idx = y + desc->height - 1; - const struct uc81xx_ptl ptl = { - .hrst = sys_cpu_to_be16(x), - .hred = sys_cpu_to_be16(x_end_idx), - .vrst = sys_cpu_to_be16(y), - .vred = sys_cpu_to_be16(y_end_idx), - .flags = UC81XX_PTL_FLAG_PT_SCAN, - }; size_t buf_len; const uint8_t back_buffer = data->blanking_on ? UC81XX_CMD_DTM1 : UC81XX_CMD_DTM2; @@ -448,15 +439,11 @@ static int uc81xx_write(const struct device *dev, const uint16_t x, const uint16 } } - /* Setup Partial Window and enable Partial Mode */ - LOG_HEXDUMP_DBG(&ptl, sizeof(ptl), "ptl"); - if (uc81xx_write_cmd(dev, UC81XX_CMD_PTIN, NULL, 0)) { return -EIO; } - if (uc81xx_write_cmd(dev, UC81XX_CMD_PTL, - (const void *)&ptl, sizeof(ptl))) { + if (config->quirks->set_ptl(dev, x, y, x_end_idx, y_end_idx, desc)) { return -EIO; } @@ -487,8 +474,7 @@ static int uc81xx_write(const struct device *dev, const uint16_t x, const uint16 * needed. */ - if (uc81xx_write_cmd(dev, UC81XX_CMD_PTL, - (const void *)&ptl, sizeof(ptl))) { + if (config->quirks->set_ptl(dev, x, y, x_end_idx, y_end_idx, desc)) { return -EIO; } @@ -654,7 +640,73 @@ static int uc81xx_init(const struct device *dev) return uc81xx_controller_init(dev); } -#if DT_HAS_COMPAT_STATUS_OKAY(ultrachip_uc8176) +#if DT_HAS_COMPAT_STATUS_OKAY(ultrachip_uc8175) +static int uc81xx_set_tres_8(const struct device *dev) +{ + const struct uc81xx_config *config = dev->config; + const struct uc81xx_tres8 tres = { + .hres = config->width, + .vres = config->height, + }; + + LOG_HEXDUMP_DBG(&tres, sizeof(tres), "TRES"); + + return uc81xx_write_cmd(dev, UC81XX_CMD_TRES, (const void *)&tres, sizeof(tres)); +} + +static inline int uc81xx_set_ptl_8(const struct device *dev, uint16_t x, uint16_t y, + uint16_t x_end_idx, uint16_t y_end_idx, + const struct display_buffer_descriptor *desc) +{ + const struct uc81xx_ptl8 ptl = { + .hrst = x, + .hred = x_end_idx, + .vrst = y, + .vred = y_end_idx, + .flags = UC81XX_PTL_FLAG_PT_SCAN, + }; + + /* Setup Partial Window and enable Partial Mode */ + LOG_HEXDUMP_DBG(&ptl, sizeof(ptl), "ptl"); + + return uc81xx_write_cmd(dev, UC81XX_CMD_PTL, (const void *)&ptl, sizeof(ptl)); +} +#endif + +#if DT_HAS_COMPAT_STATUS_OKAY(ultrachip_uc8176) || DT_HAS_COMPAT_STATUS_OKAY(ultrachip_uc8179) +static int uc81xx_set_tres_16(const struct device *dev) +{ + const struct uc81xx_config *config = dev->config; + const struct uc81xx_tres8 tres = { + .hres = sys_cpu_to_be16(config->width), + .vres = sys_cpu_to_be16(config->height), + }; + + LOG_HEXDUMP_DBG(&tres, sizeof(tres), "TRES"); + + return uc81xx_write_cmd(dev, UC81XX_CMD_TRES, (const void *)&tres, sizeof(tres)); +} + +static inline int uc81xx_set_ptl_16(const struct device *dev, uint16_t x, uint16_t y, + uint16_t x_end_idx, uint16_t y_end_idx, + const struct display_buffer_descriptor *desc) +{ + const struct uc81xx_ptl16 ptl = { + .hrst = sys_cpu_to_be16(x), + .hred = sys_cpu_to_be16(x_end_idx), + .vrst = sys_cpu_to_be16(y), + .vred = sys_cpu_to_be16(y_end_idx), + .flags = UC81XX_PTL_FLAG_PT_SCAN, + }; + + /* Setup Partial Window and enable Partial Mode */ + LOG_HEXDUMP_DBG(&ptl, sizeof(ptl), "ptl"); + + return uc81xx_write_cmd(dev, UC81XX_CMD_PTL, (const void *)&ptl, sizeof(ptl)); +} +#endif + +#if DT_HAS_COMPAT_STATUS_OKAY(ultrachip_uc8175) || DT_HAS_COMPAT_STATUS_OKAY(ultrachip_uc8176) static int uc8176_set_cdi(const struct device *dev, bool border) { const struct uc81xx_config *config = dev->config; @@ -675,7 +727,22 @@ static int uc8176_set_cdi(const struct device *dev, bool border) LOG_DBG("CDI: %#hhx", cdi); return uc81xx_write_cmd_uint8(dev, UC81XX_CMD_CDI, cdi); } +#endif + +#if DT_HAS_COMPAT_STATUS_OKAY(ultrachip_uc8175) +static const struct uc81xx_quirks uc8175_quirks = { + .max_width = 80, + .max_height = 160, + .auto_copy = false, + + .set_cdi = uc8176_set_cdi, + .set_tres = uc81xx_set_tres_8, + .set_ptl = uc81xx_set_ptl_8, +}; +#endif + +#if DT_HAS_COMPAT_STATUS_OKAY(ultrachip_uc8176) static const struct uc81xx_quirks uc8176_quirks = { .max_width = 400, .max_height = 300, @@ -683,6 +750,8 @@ static const struct uc81xx_quirks uc8176_quirks = { .auto_copy = false, .set_cdi = uc8176_set_cdi, + .set_tres = uc81xx_set_tres_16, + .set_ptl = uc81xx_set_ptl_16, }; #endif @@ -714,6 +783,8 @@ static const struct uc81xx_quirks uc8179_quirks = { .auto_copy = true, .set_cdi = uc8179_set_cdi, + .set_tres = uc81xx_set_tres_16, + .set_ptl = uc81xx_set_ptl_16, }; #endif @@ -814,6 +885,9 @@ static struct display_driver_api uc81xx_driver_api = { CONFIG_DISPLAY_INIT_PRIORITY, \ &uc81xx_driver_api); +DT_FOREACH_STATUS_OKAY_VARGS(ultrachip_uc8175, UC81XX_DEFINE, + &uc8175_quirks); + DT_FOREACH_STATUS_OKAY_VARGS(ultrachip_uc8176, UC81XX_DEFINE, &uc8176_quirks); diff --git a/drivers/display/uc81xx_regs.h b/drivers/display/uc81xx_regs.h index 322423324ad..aba38ac3e7f 100644 --- a/drivers/display/uc81xx_regs.h +++ b/drivers/display/uc81xx_regs.h @@ -106,14 +106,31 @@ #define UC8179_CDI_DDX1 BIT(1) #define UC8179_CDI_DDX0 BIT(0) -struct uc81xx_tres { +struct uc81xx_tres8 { + uint8_t hres; + uint8_t vres; +} __packed; + +BUILD_ASSERT(sizeof(struct uc81xx_tres8) == 2); + +struct uc81xx_ptl8 { + uint8_t hrst; + uint8_t hred; + uint8_t vrst; + uint8_t vred; + uint8_t flags; +} __packed; + +BUILD_ASSERT(sizeof(struct uc81xx_ptl8) == 5); + +struct uc81xx_tres16 { uint16_t hres; uint16_t vres; } __packed; -BUILD_ASSERT(sizeof(struct uc81xx_tres) == 4); +BUILD_ASSERT(sizeof(struct uc81xx_tres16) == 4); -struct uc81xx_ptl { +struct uc81xx_ptl16 { uint16_t hrst; uint16_t hred; uint16_t vrst; @@ -121,11 +138,10 @@ struct uc81xx_ptl { uint8_t flags; } __packed; -BUILD_ASSERT(sizeof(struct uc81xx_ptl) == 9); +BUILD_ASSERT(sizeof(struct uc81xx_ptl16) == 9); #define UC81XX_PTL_FLAG_PT_SCAN BIT(0) - /* Time constants in ms */ #define UC81XX_RESET_DELAY 10U #define UC81XX_PON_DELAY 100U diff --git a/dts/bindings/display/ultrachip,uc8175.yaml b/dts/bindings/display/ultrachip,uc8175.yaml new file mode 100644 index 00000000000..8c89c86aded --- /dev/null +++ b/dts/bindings/display/ultrachip,uc8175.yaml @@ -0,0 +1,8 @@ +# Copyright (c) 2022 Andreas Sandberg +# SPDX-License-Identifier: Apache-2.0 + +description: UltraChip UC8175 EPD controller + +compatible: "ultrachip,uc8175" + +include: ultrachip,uc81xx-common.yaml From 7913ebfba31170fa0f7e97ccf3f7de468145868f Mon Sep 17 00:00:00 2001 From: Emil Gydesen Date: Thu, 24 Aug 2023 14:57:47 +0200 Subject: [PATCH 1019/3723] Bluetooth: GMAP: Add initial implementation of GMAP Add initial implementation of Gaming Audio Profile (GMAP). This is a top layer profile in the LE Audio stack, designed for low latency audio ideal for gaming. Signed-off-by: Emil Gydesen --- include/zephyr/bluetooth/audio/gmap.h | 235 ++++++ .../zephyr/bluetooth/audio/gmap_lc3_preset.h | 182 +++++ include/zephyr/bluetooth/uuid.h | 55 ++ subsys/bluetooth/audio/CMakeLists.txt | 1 + subsys/bluetooth/audio/Kconfig | 1 + subsys/bluetooth/audio/Kconfig.gmap | 30 + subsys/bluetooth/audio/gmap_client.c | 682 ++++++++++++++++++ subsys/bluetooth/audio/gmap_server.c | 417 +++++++++++ 8 files changed, 1603 insertions(+) create mode 100644 include/zephyr/bluetooth/audio/gmap.h create mode 100644 include/zephyr/bluetooth/audio/gmap_lc3_preset.h create mode 100644 subsys/bluetooth/audio/Kconfig.gmap create mode 100644 subsys/bluetooth/audio/gmap_client.c create mode 100644 subsys/bluetooth/audio/gmap_server.c diff --git a/include/zephyr/bluetooth/audio/gmap.h b/include/zephyr/bluetooth/audio/gmap.h new file mode 100644 index 00000000000..292fd6eca2b --- /dev/null +++ b/include/zephyr/bluetooth/audio/gmap.h @@ -0,0 +1,235 @@ +/** + * @file + * @brief Header for Bluetooth Gaming Audio Profile (GMAP). + * + * Copyright (c) 2023 Nordic Semiconductor ASA + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#ifndef ZEPHYR_INCLUDE_BLUETOOTH_AUDIO_GMAP_ +#define ZEPHYR_INCLUDE_BLUETOOTH_AUDIO_GMAP_ + +#include +#include + +/** + * @brief Bluetooth Gaming Audio Profile (GMAP) + * @defgroup bt_gmap Bluetooth Gaming Audio Profile + * @ingroup bluetooth + * @{ + */ + +/** Gaming Role bitfield */ +enum bt_gmap_role { + /** + * @brief Gaming Role Unicast Game Gateway + * + * Requires @kconfig{CONFIG_BT_CAP_INITIATOR}, @kconfig{CONFIG_BT_BAP_UNICAST_CLIENT} and + * @kconfig{CONFIG_BT_VCP_VOL_CTLR} to be enabled. + */ + BT_GMAP_ROLE_UGG = BIT(0), + /** + * @brief Gaming Role Unicast Game Terminal + * + * Requires @kconfig{CONFIG_BT_CAP_ACCEPTOR} and @kconfig{CONFIG_BT_BAP_UNICAST_SERVER} to + * be enabled. + */ + BT_GMAP_ROLE_UGT = BIT(1), + /** + * @brief Gaming Role Broadcast Game Sender + * + * Requires @kconfig{CONFIG_BT_CAP_INITIATOR} and @kconfig{CONFIG_BT_BAP_BROADCAST_SOURCE} + * to be enabled. + */ + BT_GMAP_ROLE_BGS = BIT(2), + /** + * @brief Gaming Role Broadcast Game Receiver + * + * Requires @kconfig{CONFIG_BT_CAP_ACCEPTOR}, @kconfig{CONFIG_BT_BAP_BROADCAST_SINK} and + * @kconfig{CONFIG_BT_VCP_VOL_REND} to be enabled. + */ + BT_GMAP_ROLE_BGR = BIT(3), +}; + +/** Unicast Game Gateway Feature bitfield */ +enum bt_gmap_ugg_feat { + /** + * @brief Support transmitting multiple LC3 codec frames per block in an SDU + * + * Requires @kconfig{CONFIG_BT_BAP_UNICAST_CLIENT_ASE_SRC_COUNT} > 0 + */ + BT_GMAP_UGG_FEAT_MULTIPLEX = BIT(0), + /** + * @brief 96 kbps source support + * + * Requires @kconfig{CONFIG_BT_BAP_UNICAST_CLIENT_ASE_SRC_COUNT} > 0 + */ + BT_GMAP_UGG_FEAT_96KBPS_SOURCE = BIT(1), + /** + * @brief Support for receiving at least two channels of audio, each in a separate CIS + * + * Requires @kconfig{CONFIG_BT_BAP_UNICAST_CLIENT_ASE_SNK_COUNT} > 1 and + * @kconfig{CONFIG_BT_BAP_UNICAST_CLIENT_GROUP_STREAM_COUNT} > 1 + */ + BT_GMAP_UGG_FEAT_MULTISINK = BIT(2), +}; + +/** Unicast Game Terminal Feature bitfield */ +enum bt_gmap_ugt_feat { + /** + * @brief Source support + * + * Requires @kconfig{CONFIG_BT_ASCS_ASE_SRC_COUNT} > 0 + */ + BT_GMAP_UGT_FEAT_SOURCE = BIT(0), + /** + * @brief 80 kbps source support + * + * Requires BT_GMAP_UGT_FEAT_SOURCE to be set as well + */ + BT_GMAP_UGT_FEAT_80KBPS_SOURCE = BIT(1), + /** + * @brief Sink support + * + * Requires @kconfig{CONFIG_BT_ASCS_ASE_SNK_COUNT} > 0 + */ + BT_GMAP_UGT_FEAT_SINK = BIT(2), + /** + * @brief 64 kbps sink support + * + * Requires BT_GMAP_UGT_FEAT_SINK to be set as well + */ + BT_GMAP_UGT_FEAT_64KBPS_SINK = BIT(3), + /** + * @brief Support for receiving multiple LC3 codec frames per block in an SDU + * + * Requires BT_GMAP_UGT_FEAT_SINK to be set as well + */ + BT_GMAP_UGT_FEAT_MULTIPLEX = BIT(4), + /** + * @brief Support for receiving at least two audio channels, each in a separate CIS + * + * Requires @kconfig{CONFIG_BT_ASCS_ASE_SNK_COUNT} > 1 and + * @kconfig{CONFIG_BT_ASCS_MAX_ACTIVE_ASES} > 1, and BT_GMAP_UGT_FEAT_SINK to be set as well + */ + BT_GMAP_UGT_FEAT_MULTISINK = BIT(5), + /** + * @brief Support for sending at least two audio channels, each in a separate CIS + * + * Requires @kconfig{CONFIG_BT_ASCS_ASE_SRC_COUNT} > 1 and + * @kconfig{CONFIG_BT_ASCS_MAX_ACTIVE_ASES} > 1, and BT_GMAP_UGT_FEAT_SOURCE to be set + * as well + */ + BT_GMAP_UGT_FEAT_MULTISOURCE = BIT(6), +}; + +/** Broadcast Game Sender Feature bitfield */ +enum bt_gmap_bgs_feat { + /** 96 kbps support */ + BT_GMAP_BGS_FEAT_96KBPS = BIT(0), +}; + +/** Broadcast Game Receiver Feature bitfield */ +enum bt_gmap_bgr_feat { + /** + * @brief Support for receiving at least two audio channels, each in a separate BIS + * + * Requires @kconfig{CONFIG_BT_BAP_BROADCAST_SNK_STREAM_COUNT} > 1 + */ + BT_GMAP_BGR_FEAT_MULTISINK = BIT(0), + /** @brief Support for receiving multiple LC3 codec frames per block in an SDU */ + BT_GMAP_BGR_FEAT_MULTIPLEX = BIT(1), +}; + +/** Broadcast Game Receiver Feature bitfield */ +struct bt_gmap_feat { + /** Unicast Game Gateway features */ + enum bt_gmap_ugg_feat ugg_feat; + /** Unicast Game Terminal features */ + enum bt_gmap_ugt_feat ugt_feat; + /** Remote Broadcast Game Sender features */ + enum bt_gmap_bgs_feat bgs_feat; + /** Remote Broadcast Game Receiver features */ + enum bt_gmap_bgr_feat bgr_feat; +}; + +/** @brief Hearing Access Service Client callback structure. */ +struct bt_gmap_cb { + /** + * @brief Callback function for bt_has_discover. + * + * This callback is called when discovery procedure is complete. + * + * @param conn Bluetooth connection object. + * @param err 0 on success, ATT error or negative errno otherwise. + * @param role Role of remote device. 0 on failure. + * @param features Remote features. + */ + void (*discover)(struct bt_conn *conn, int err, enum bt_gmap_role role, + struct bt_gmap_feat features); +}; + +/** + * @brief Registers the callbacks used by the Gaming Audio Profile. + * + * @param cb The callback structure. + * + * @retval -EINVAL if @p cb is NULL + * @retval -EALREADY if callbacks have already be registered + * @retval 0 on success + */ +int bt_gmap_cb_register(const struct bt_gmap_cb *cb); + +/** + * @brief Discover Gaming Service on a remote device. + * + * Procedure to find a Gaming Service on a server identified by @p conn. + * The @ref bt_gmap_cb.discover callback is called when the discovery procedure completes of fails. + * On discovery success the callback contains information about the remote device. + * + * @param conn Bluetooth connection object. + * + * @retval -EINVAL if @p conn is NULL + * @retval -EBUSY if discovery is already in progress for @p conn + * @retval -ENOEXEC if discovery failed to initiate + * @retval 0 on success + */ +int bt_gmap_discover(struct bt_conn *conn); + +/** + * @brief Adds GMAS instance to database and sets the received Gaming Audio Profile role(s). + * + * @param role Gaming Audio Profile role(s) of the device (one or multiple). + * @param features Features of the roles. If a role is not in the @p role parameter, then the + * feature value for that role is simply ignored. + * + * @retval -EINVAL on invalid arguments + * @retval -ENOEXEC on service register failure + * @retval 0 on success + */ +int bt_gmap_register(enum bt_gmap_role role, struct bt_gmap_feat features); + +/** + * @brief Set one or multiple Gaming Audio Profile roles and features dynamically. + * + * Previously registered value will be overwritten. If there is a role change, this will trigger + * a Gaming Audio Service (GMAS) service change. If there is only a feature change, no service + * change will happen. + * + * @param role Gaming Audio Profile role(s). + * @param features Features of the roles. If a role is not in the @p role parameter, then the + * feature value for that role is simply ignored. + * + * @retval -ENOEXEC if the service has not yet been registered + * @retval -EINVAL on invalid arguments + * @retval -EALREADY if the @p role and @p features are the same as existing ones + * @retval -ENOENT on service unregister failure + * @retval -ECANCELED on service re-register failure + * @retval 0 on success + */ +int bt_gmap_set_role(enum bt_gmap_role role, struct bt_gmap_feat features); + +/** @} */ /* end of bt_gmap */ + +#endif /* ZEPHYR_INCLUDE_BLUETOOTH_AUDIO_GMAP_ */ diff --git a/include/zephyr/bluetooth/audio/gmap_lc3_preset.h b/include/zephyr/bluetooth/audio/gmap_lc3_preset.h new file mode 100644 index 00000000000..695df5dd79e --- /dev/null +++ b/include/zephyr/bluetooth/audio/gmap_lc3_preset.h @@ -0,0 +1,182 @@ +/** @file + * @brief Header for Bluetooth GMAP LC3 presets. + * + * Copyright (c) 2023 Nordic Semiconductor ASA + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#ifndef ZEPHYR_INCLUDE_BLUETOOTH_AUDIO_GMAP_LC3_PRESET_ +#define ZEPHYR_INCLUDE_BLUETOOTH_AUDIO_GMAP_LC3_PRESET_ + +#include + +/* GMAP LC3 unicast presets defined by table 3.16 in the GMAP v1.0 specification */ + +/** + * @brief Helper to declare LC3 32_1_gr codec configuration + * + * @param _loc Audio channel location bitfield (@ref bt_audio_location) + * @param _stream_context Stream context (BT_AUDIO_CONTEXT_*) + */ +#define BT_GMAP_LC3_PRESET_32_1_GR(_loc, _stream_context) \ + BT_BAP_LC3_PRESET(BT_AUDIO_CODEC_LC3_CONFIG_32_1(_loc, _stream_context), \ + BT_AUDIO_CODEC_LC3_QOS_7_5_UNFRAMED(60U, 1U, 15U, 10000U)) + +/** + * @brief Helper to declare LC3 32_2_gr codec configuration + * + * @param _loc Audio channel location bitfield (@ref bt_audio_location) + * @param _stream_context Stream context (BT_AUDIO_CONTEXT_*) + */ +#define BT_GMAP_LC3_PRESET_32_2_GR(_loc, _stream_context) \ + BT_BAP_LC3_PRESET(BT_AUDIO_CODEC_LC3_CONFIG_32_2(_loc, _stream_context), \ + BT_AUDIO_CODEC_LC3_QOS_10_UNFRAMED(80U, 1U, 20U, 10000U)) + +/** + * @brief Helper to declare LC3 48_1_gr codec configuration + * + * @param _loc Audio channel location bitfield (@ref bt_audio_location) + * @param _stream_context Stream context (BT_AUDIO_CONTEXT_*) + */ +#define BT_GMAP_LC3_PRESET_48_1_GR(_loc, _stream_context) \ + BT_BAP_LC3_PRESET(BT_AUDIO_CODEC_LC3_CONFIG_48_1(_loc, _stream_context), \ + BT_AUDIO_CODEC_LC3_QOS_7_5_UNFRAMED(75U, 1U, 15U, 10000U)) + +/** + * @brief Helper to declare LC3 48_2_gr codec configuration + * + * Mandatory to support as both unicast client and server + * + * @param _loc Audio channel location bitfield (@ref bt_audio_location) + * @param _stream_context Stream context (BT_AUDIO_CONTEXT_*) + */ +#define BT_GMAP_LC3_PRESET_48_2_GR(_loc, _stream_context) \ + BT_BAP_LC3_PRESET(BT_AUDIO_CODEC_LC3_CONFIG_48_2(_loc, _stream_context), \ + BT_AUDIO_CODEC_LC3_QOS_10_UNFRAMED(100U, 1U, 20U, 10000U)) + +/** + * @brief Helper to declare LC3 48_3_gr codec configuration + * + * @param _loc Audio channel location bitfield (@ref bt_audio_location) + * @param _stream_context Stream context (BT_AUDIO_CONTEXT_*) + */ +#define BT_GMAP_LC3_PRESET_48_3_GR(_loc, _stream_context) \ + BT_BAP_LC3_PRESET(BT_AUDIO_CODEC_LC3_CONFIG_48_3(_loc, _stream_context), \ + BT_AUDIO_CODEC_LC3_QOS_7_5_UNFRAMED(90U, 1U, 15U, 10000U)) + +/** + * @brief Helper to declare LC3 48_4_gr codec configuration + * + * Mandatory to support as unicast server + * + * @param _loc Audio channel location bitfield (@ref bt_audio_location) + * @param _stream_context Stream context (BT_AUDIO_CONTEXT_*) + */ +#define BT_GMAP_LC3_PRESET_48_4_GR(_loc, _stream_context) \ + BT_BAP_LC3_PRESET(BT_AUDIO_CODEC_LC3_CONFIG_48_4(_loc, _stream_context), \ + BT_AUDIO_CODEC_LC3_QOS_10_UNFRAMED(120U, 1U, 20U, 10000U)) + +/** + * @brief Helper to declare LC3 16_1_gs codec configuration + * + * @param _loc Audio channel location bitfield (@ref bt_audio_location) + * @param _stream_context Stream context (BT_AUDIO_CONTEXT_*) + */ +#define BT_GMAP_LC3_PRESET_16_1_GS(_loc, _stream_context) \ + BT_BAP_LC3_PRESET(BT_AUDIO_CODEC_LC3_CONFIG_16_1(_loc, _stream_context), \ + BT_AUDIO_CODEC_LC3_QOS_7_5_UNFRAMED(30U, 1U, 15U, 60000U)) + +/** + * @brief Helper to declare LC3 16_2_gs codec configuration + * + * @param _loc Audio channel location bitfield (@ref bt_audio_location) + * @param _stream_context Stream context (BT_AUDIO_CONTEXT_*) + */ +#define BT_GMAP_LC3_PRESET_16_2_GS(_loc, _stream_context) \ + BT_BAP_LC3_PRESET(BT_AUDIO_CODEC_LC3_CONFIG_16_2(_loc, _stream_context), \ + BT_AUDIO_CODEC_LC3_QOS_10_UNFRAMED(40U, 1U, 20U, 60000U)) + +/** + * @brief Helper to declare LC3 32_1_gs codec configuration + * + * @param _loc Audio channel location bitfield (@ref bt_audio_location) + * @param _stream_context Stream context (BT_AUDIO_CONTEXT_*) + */ +#define BT_GMAP_LC3_PRESET_32_1_GS(_loc, _stream_context) \ + BT_BAP_LC3_PRESET(BT_AUDIO_CODEC_LC3_CONFIG_32_1(_loc, _stream_context), \ + BT_AUDIO_CODEC_LC3_QOS_7_5_UNFRAMED(60U, 1U, 15U, 60000U)) + +/** + * @brief Helper to declare LC3 32_2_gs codec configuration + * + * @param _loc Audio channel location bitfield (@ref bt_audio_location) + * @param _stream_context Stream context (BT_AUDIO_CONTEXT_*) + */ +#define BT_GMAP_LC3_PRESET_32_2_GS(_loc, _stream_context) \ + BT_BAP_LC3_PRESET(BT_AUDIO_CODEC_LC3_CONFIG_32_2(_loc, _stream_context), \ + BT_AUDIO_CODEC_LC3_QOS_10_UNFRAMED(80U, 1U, 20U, 60000U)) + +/** + * @brief Helper to declare LC3 48_1_gs codec configuration + * + * @param _loc Audio channel location bitfield (@ref bt_audio_location) + * @param _stream_context Stream context (BT_AUDIO_CONTEXT_*) + */ +#define BT_GMAP_LC3_PRESET_48_1_GS(_loc, _stream_context) \ + BT_BAP_LC3_PRESET(BT_AUDIO_CODEC_LC3_CONFIG_48_1(_loc, _stream_context), \ + BT_AUDIO_CODEC_LC3_QOS_7_5_UNFRAMED(75U, 1U, 15U, 60000U)) + +/** + * @brief Helper to declare LC3 48_2_gs codec configuration + * + * @param _loc Audio channel location bitfield (@ref bt_audio_location) + * @param _stream_context Stream context (BT_AUDIO_CONTEXT_*) + */ +#define BT_GMAP_LC3_PRESET_48_2_GS(_loc, _stream_context) \ + BT_BAP_LC3_PRESET(BT_AUDIO_CODEC_LC3_CONFIG_48_2(_loc, _stream_context), \ + BT_AUDIO_CODEC_LC3_QOS_10_UNFRAMED(100U, 1U, 20U, 60000U)) + +/* GMAP LC3 broadcast presets defined by table 3.22 in the GMAP v1.0 specification */ + +/** + * @brief Helper to declare LC3 48_1_g codec configuration + * + * @param _loc Audio channel location bitfield (@ref bt_audio_location) + * @param _stream_context Stream context (BT_AUDIO_CONTEXT_*) + */ +#define BT_GMAP_LC3_PRESET_48_1_G(_loc, _stream_context) \ + BT_BAP_LC3_PRESET(BT_AUDIO_CODEC_LC3_CONFIG_48_1(_loc, _stream_context), \ + BT_AUDIO_CODEC_LC3_QOS_7_5_UNFRAMED(75U, 1U, 8U, 10000U)) + +/** + * @brief Helper to declare LC3 48_2_g codec configuration + * + * @param _loc Audio channel location bitfield (@ref bt_audio_location) + * @param _stream_context Stream context (BT_AUDIO_CONTEXT_*) + */ +#define BT_GMAP_LC3_PRESET_48_2_G(_loc, _stream_context) \ + BT_BAP_LC3_PRESET(BT_AUDIO_CODEC_LC3_CONFIG_48_2(_loc, _stream_context), \ + BT_AUDIO_CODEC_LC3_QOS_10_UNFRAMED(100U, 1U, 10U, 10000U)) + +/** + * @brief Helper to declare LC3 48_3_g codec configuration + * + * @param _loc Audio channel location bitfield (@ref bt_audio_location) + * @param _stream_context Stream context (BT_AUDIO_CONTEXT_*) + */ +#define BT_GMAP_LC3_PRESET_48_3_G(_loc, _stream_context) \ + BT_BAP_LC3_PRESET(BT_AUDIO_CODEC_LC3_CONFIG_48_3(_loc, _stream_context), \ + BT_AUDIO_CODEC_LC3_QOS_7_5_UNFRAMED(90U, 1U, 8U, 10000U)) + +/** + * @brief Helper to declare LC3 48_4_g codec configuration + * + * @param _loc Audio channel location bitfield (@ref bt_audio_location) + * @param _stream_context Stream context (BT_AUDIO_CONTEXT_*) + */ +#define BT_GMAP_LC3_PRESET_48_4_G(_loc, _stream_context) \ + BT_BAP_LC3_PRESET(BT_AUDIO_CODEC_LC3_CONFIG_48_4(_loc, _stream_context), \ + BT_AUDIO_CODEC_LC3_QOS_10_UNFRAMED(120U, 1U, 10U, 10000U)) + +#endif /* ZEPHYR_INCLUDE_BLUETOOTH_AUDIO_GMAP_LC3_PRESET_ */ diff --git a/include/zephyr/bluetooth/uuid.h b/include/zephyr/bluetooth/uuid.h index 8aeaecf1942..16943f89e63 100644 --- a/include/zephyr/bluetooth/uuid.h +++ b/include/zephyr/bluetooth/uuid.h @@ -5090,6 +5090,61 @@ struct bt_uuid_128 { */ #define BT_UUID_GATT_SL \ BT_UUID_DECLARE_16(BT_UUID_GATT_SL_VAL) + +/** + * @brief Gaming Service UUID value + */ +#define BT_UUID_GMAS_VAL 0x1858 +/** + * @brief Common Audio Service + */ +#define BT_UUID_GMAS BT_UUID_DECLARE_16(BT_UUID_GMAS_VAL) + +/** + * @brief Gaming Audio Profile Role UUID value + */ +#define BT_UUID_GMAP_ROLE_VAL 0x2C00 +/** + * @brief Gaming Audio Profile Role + */ +#define BT_UUID_GMAP_ROLE BT_UUID_DECLARE_16(BT_UUID_GMAP_ROLE_VAL) + +/** + * @brief Gaming Audio Profile Unicast Game Gateway Features UUID value + */ +#define BT_UUID_GMAP_UGG_FEAT_VAL 0x2C01 +/** + * @brief Gaming Audio Profile Unicast Game Gateway Features + */ +#define BT_UUID_GMAP_UGG_FEAT BT_UUID_DECLARE_16(BT_UUID_GMAP_UGG_FEAT_VAL) + +/** + * @brief Gaming Audio Profile Unicast Game Terminal Features UUID value + */ +#define BT_UUID_GMAP_UGT_FEAT_VAL 0x2C02 +/** + * @brief Gaming Audio Profile Unicast Game Terminal Features + */ +#define BT_UUID_GMAP_UGT_FEAT BT_UUID_DECLARE_16(BT_UUID_GMAP_UGT_FEAT_VAL) + +/** + * @brief Gaming Audio Profile Broadcast Game Sender Features UUID value + */ +#define BT_UUID_GMAP_BGS_FEAT_VAL 0x2C03 +/** + * @brief Gaming Audio Profile Broadcast Game Sender Features + */ +#define BT_UUID_GMAP_BGS_FEAT BT_UUID_DECLARE_16(BT_UUID_GMAP_BGS_FEAT_VAL) + +/** + * @brief Gaming Audio Profile Broadcast Game Receiver Features UUID value + */ +#define BT_UUID_GMAP_BGR_FEAT_VAL 0x2C04 +/** + * @brief Gaming Audio Profile Broadcast Game Receiver Features + */ +#define BT_UUID_GMAP_BGR_FEAT BT_UUID_DECLARE_16(BT_UUID_GMAP_BGR_FEAT_VAL) + /* * Protocol UUIDs */ diff --git a/subsys/bluetooth/audio/CMakeLists.txt b/subsys/bluetooth/audio/CMakeLists.txt index 5e73695c5c3..26185111ce9 100644 --- a/subsys/bluetooth/audio/CMakeLists.txt +++ b/subsys/bluetooth/audio/CMakeLists.txt @@ -66,3 +66,4 @@ if (CONFIG_BT_CAP_INITIATOR OR CONFIG_BT_CAP_COMMANDER) zephyr_library_sources(cap_common.c) endif() zephyr_library_sources_ifdef(CONFIG_BT_TMAP tmap.c) +zephyr_library_sources_ifdef(CONFIG_BT_GMAP gmap_client.c gmap_server.c) diff --git a/subsys/bluetooth/audio/Kconfig b/subsys/bluetooth/audio/Kconfig index 7e7bbfd0951..d720b095223 100644 --- a/subsys/bluetooth/audio/Kconfig +++ b/subsys/bluetooth/audio/Kconfig @@ -60,6 +60,7 @@ rsource "Kconfig.mpl" rsource "Kconfig.mctl" rsource "Kconfig.cap" rsource "Kconfig.tmap" +rsource "Kconfig.gmap" module = BT_AUDIO module-str = "Bluetooth Audio" diff --git a/subsys/bluetooth/audio/Kconfig.gmap b/subsys/bluetooth/audio/Kconfig.gmap new file mode 100644 index 00000000000..a9bd3024aa3 --- /dev/null +++ b/subsys/bluetooth/audio/Kconfig.gmap @@ -0,0 +1,30 @@ +# Bluetooth Audio - Gaming Audio Profile (GMAP) options +# +# Copyright (c) 2023 Nordic Semiconductor ASA +# +# SPDX-License-Identifier: Apache-2.0 +# + +config BT_GMAP_UGG_SUPPORTED + def_bool BT_CAP_INITIATOR && BT_BAP_UNICAST_CLIENT && BT_VCP_VOL_CTLR + +config BT_GMAP_UGT_SUPPORTED + def_bool BT_CAP_ACCEPTOR && BT_BAP_UNICAST_SERVER + +config BT_GMAP_BGS_SUPPORTED + def_bool BT_CAP_INITIATOR && BT_BAP_BROADCAST_SOURCE + +config BT_GMAP_BGR_SUPPORTED + def_bool BT_CAP_ACCEPTOR && BT_BAP_BROADCAST_SINK && BT_VCP_VOL_REND + +config BT_GMAP + bool "Gaming Audio Profile [EXPERIMENTAL]" + depends on BT_CAP_ACCEPTOR || BT_CAP_INITIATOR + select EXPERIMENTAL + help + Enabling this will enable GMAP. + +parent-module = BT +module = BT_GMAP +module-str = "Bluetooth Gaming Audio Profile" +source "subsys/logging/Kconfig.template.log_config_inherit" diff --git a/subsys/bluetooth/audio/gmap_client.c b/subsys/bluetooth/audio/gmap_client.c new file mode 100644 index 00000000000..dff67356b76 --- /dev/null +++ b/subsys/bluetooth/audio/gmap_client.c @@ -0,0 +1,682 @@ +/* + * Copyright (c) 2023 Nordic Semiconductor ASA + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include +#include +#include +#include + +#include "audio_internal.h" + +LOG_MODULE_REGISTER(bt_gmap_client, CONFIG_BT_GMAP_LOG_LEVEL); + +static const struct bt_uuid *gmas_uuid = BT_UUID_GMAS; +static const struct bt_uuid *gmap_role_uuid = BT_UUID_GMAP_ROLE; +static const struct bt_uuid *gmap_ugg_feat_uuid = BT_UUID_GMAP_UGG_FEAT; +static const struct bt_uuid *gmap_ugt_feat_uuid = BT_UUID_GMAP_UGT_FEAT; +static const struct bt_uuid *gmap_bgs_feat_uuid = BT_UUID_GMAP_BGS_FEAT; +static const struct bt_uuid *gmap_bgr_feat_uuid = BT_UUID_GMAP_BGR_FEAT; + +static const struct bt_gmap_cb *gmap_cb; + +static struct bt_gmap_client { + /** Profile connection reference */ + struct bt_conn *conn; + + /* Remote role and features */ + enum bt_gmap_role role; + struct bt_gmap_feat feat; + + uint16_t svc_start_handle; + uint16_t svc_end_handle; + + bool busy; + + /* GATT procedure parameters */ + union { + struct bt_gatt_read_params read; + struct bt_gatt_discover_params discover; + } params; +} gmap_insts[CONFIG_BT_MAX_CONN]; + +static void gmap_reset(struct bt_gmap_client *gmap_cli) +{ + if (gmap_cli->conn != NULL) { + bt_conn_unref(gmap_cli->conn); + } + + memset(gmap_cli, 0, sizeof(*gmap_cli)); +} + +static struct bt_gmap_client *client_by_conn(struct bt_conn *conn) +{ + struct bt_gmap_client *gmap_cli = &gmap_insts[bt_conn_index(conn)]; + + if (gmap_cli->conn == conn) { + return gmap_cli; + } + + return NULL; +} + +static void disconnected(struct bt_conn *conn, uint8_t reason) +{ + struct bt_gmap_client *gmap_cli = client_by_conn(conn); + + if (gmap_cli != NULL) { + bt_conn_unref(gmap_cli->conn); + gmap_cli->conn = NULL; + } +} + +BT_CONN_CB_DEFINE(conn_callbacks) = { + .disconnected = disconnected, +}; + +static void discover_complete(struct bt_gmap_client *gmap_cli) +{ + LOG_DBG("conn %p", (void *)gmap_cli->conn); + + gmap_cli->busy = false; + + if (gmap_cb->discover != NULL) { + gmap_cb->discover(gmap_cli->conn, 0, gmap_cli->role, gmap_cli->feat); + } +} + +static void discover_failed(struct bt_gmap_client *gmap_cli, int err) +{ + struct bt_conn *conn = gmap_cli->conn; + + gmap_reset(gmap_cli); + + LOG_DBG("conn %p err %d", (void *)conn, err); + + gmap_cb->discover(conn, err, 0, (struct bt_gmap_feat){0}); +} + +static uint8_t bgr_feat_read_cb(struct bt_conn *conn, uint8_t att_err, + struct bt_gatt_read_params *params, const void *data, uint16_t len) +{ + struct bt_gmap_client *gmap_cli = client_by_conn(conn); + struct net_buf_simple buf; + int err = att_err; + + __ASSERT(gmap_cli, "no instance for conn %p", (void *)conn); + + LOG_DBG("conn %p att_err 0x%02x params %p data %p len %u", (void *)conn, att_err, params, + data, len); + + if (data == NULL || att_err != BT_ATT_ERR_SUCCESS || len != sizeof(uint8_t)) { + if (att_err == BT_ATT_ERR_SUCCESS) { + att_err = BT_ATT_ERR_INVALID_ATTRIBUTE_LEN; + } + + discover_failed(gmap_cli, err); + + return BT_GATT_ITER_STOP; + } + + net_buf_simple_init_with_data(&buf, (void *)data, len); + + gmap_cli->feat.bgr_feat = net_buf_simple_pull_u8(&buf); + LOG_DBG("bgr_feat 0x%02x", gmap_cli->feat.bgr_feat); + + discover_complete(gmap_cli); + + return BT_GATT_ITER_STOP; +} + +static int gmap_read_bgr_feat(struct bt_gmap_client *gmap_cli, uint16_t handle) +{ + LOG_DBG("conn %p handle 0x%04x", (void *)gmap_cli->conn, handle); + + memset(&gmap_cli->params.read, 0, sizeof(gmap_cli->params.read)); + + gmap_cli->params.read.func = bgr_feat_read_cb; + gmap_cli->params.read.handle_count = 1u; + gmap_cli->params.read.single.handle = handle; + gmap_cli->params.read.single.offset = 0u; + + return bt_gatt_read(gmap_cli->conn, &gmap_cli->params.read); +} + +static uint8_t bgr_feat_discover_func(struct bt_conn *conn, const struct bt_gatt_attr *attr, + struct bt_gatt_discover_params *params) +{ + struct bt_gmap_client *gmap_cli = client_by_conn(conn); + const struct bt_gatt_chrc *chrc; + int err; + + __ASSERT(gmap_cli != NULL, "no instance for conn %p", (void *)conn); + + LOG_DBG("conn %p attr %p params %p", (void *)conn, attr, params); + + if (attr == NULL) { + discover_failed(gmap_cli, -ENOENT); + + return BT_GATT_ITER_STOP; + } + + chrc = attr->user_data; + + /* Read features */ + err = gmap_read_bgr_feat(gmap_cli, chrc->value_handle); + if (err != 0) { + discover_failed(gmap_cli, err); + } + + return BT_GATT_ITER_STOP; +} + +static int gmap_discover_bgr_feat(struct bt_gmap_client *gmap_cli) +{ + LOG_DBG("conn %p", (void *)gmap_cli->conn); + + memset(&gmap_cli->params.discover, 0, sizeof(gmap_cli->params.discover)); + + gmap_cli->params.discover.func = bgr_feat_discover_func; + gmap_cli->params.discover.uuid = gmap_bgr_feat_uuid; + gmap_cli->params.discover.type = BT_GATT_DISCOVER_CHARACTERISTIC; + gmap_cli->params.discover.start_handle = gmap_cli->svc_start_handle; + gmap_cli->params.discover.end_handle = gmap_cli->svc_end_handle; + + return bt_gatt_discover(gmap_cli->conn, &gmap_cli->params.discover); +} + +static uint8_t bgs_feat_read_cb(struct bt_conn *conn, uint8_t att_err, + struct bt_gatt_read_params *params, const void *data, uint16_t len) +{ + struct bt_gmap_client *gmap_cli = client_by_conn(conn); + struct net_buf_simple buf; + int err = att_err; + + __ASSERT(gmap_cli, "no instance for conn %p", (void *)conn); + + LOG_DBG("conn %p att_err 0x%02x params %p data %p len %u", (void *)conn, att_err, params, + data, len); + + if (data == NULL || att_err != BT_ATT_ERR_SUCCESS || len != sizeof(uint8_t)) { + if (att_err == BT_ATT_ERR_SUCCESS) { + att_err = BT_ATT_ERR_INVALID_ATTRIBUTE_LEN; + } + + discover_failed(gmap_cli, err); + + return BT_GATT_ITER_STOP; + } + + net_buf_simple_init_with_data(&buf, (void *)data, len); + + gmap_cli->feat.bgs_feat = net_buf_simple_pull_u8(&buf); + LOG_DBG("bgs_feat 0x%02x", gmap_cli->feat.bgs_feat); + + if ((gmap_cli->role & BT_GMAP_ROLE_BGR) != 0) { + err = gmap_discover_bgr_feat(gmap_cli); + } else { + discover_complete(gmap_cli); + + return BT_GATT_ITER_STOP; + } + + if (err) { + discover_failed(gmap_cli, err); + } + + return BT_GATT_ITER_STOP; +} + +static int gmap_read_bgs_feat(struct bt_gmap_client *gmap_cli, uint16_t handle) +{ + LOG_DBG("conn %p handle 0x%04x", (void *)gmap_cli->conn, handle); + + memset(&gmap_cli->params.read, 0, sizeof(gmap_cli->params.read)); + + gmap_cli->params.read.func = bgs_feat_read_cb; + gmap_cli->params.read.handle_count = 1u; + gmap_cli->params.read.single.handle = handle; + gmap_cli->params.read.single.offset = 0u; + + return bt_gatt_read(gmap_cli->conn, &gmap_cli->params.read); +} + +static uint8_t bgs_feat_discover_func(struct bt_conn *conn, const struct bt_gatt_attr *attr, + struct bt_gatt_discover_params *params) +{ + struct bt_gmap_client *gmap_cli = client_by_conn(conn); + const struct bt_gatt_chrc *chrc; + int err; + + __ASSERT(gmap_cli != NULL, "no instance for conn %p", (void *)conn); + + LOG_DBG("conn %p attr %p params %p", (void *)conn, attr, params); + + if (attr == NULL) { + discover_failed(gmap_cli, -ENOENT); + + return BT_GATT_ITER_STOP; + } + + chrc = attr->user_data; + + /* Read features */ + err = gmap_read_bgs_feat(gmap_cli, chrc->value_handle); + if (err != 0) { + discover_failed(gmap_cli, err); + } + + return BT_GATT_ITER_STOP; +} + +static int gmap_discover_bgs_feat(struct bt_gmap_client *gmap_cli) +{ + LOG_DBG("conn %p", (void *)gmap_cli->conn); + + memset(&gmap_cli->params.discover, 0, sizeof(gmap_cli->params.discover)); + + gmap_cli->params.discover.func = bgs_feat_discover_func; + gmap_cli->params.discover.uuid = gmap_bgs_feat_uuid; + gmap_cli->params.discover.type = BT_GATT_DISCOVER_CHARACTERISTIC; + gmap_cli->params.discover.start_handle = gmap_cli->svc_start_handle; + gmap_cli->params.discover.end_handle = gmap_cli->svc_end_handle; + + return bt_gatt_discover(gmap_cli->conn, &gmap_cli->params.discover); +} + +static uint8_t ugt_feat_read_cb(struct bt_conn *conn, uint8_t att_err, + struct bt_gatt_read_params *params, const void *data, uint16_t len) +{ + struct bt_gmap_client *gmap_cli = client_by_conn(conn); + struct net_buf_simple buf; + int err = att_err; + + __ASSERT(gmap_cli, "no instance for conn %p", (void *)conn); + + LOG_DBG("conn %p att_err 0x%02x params %p data %p len %u", (void *)conn, att_err, params, + data, len); + + if (data == NULL || att_err != BT_ATT_ERR_SUCCESS || len != sizeof(uint8_t)) { + if (att_err == BT_ATT_ERR_SUCCESS) { + att_err = BT_ATT_ERR_INVALID_ATTRIBUTE_LEN; + } + + discover_failed(gmap_cli, err); + + return BT_GATT_ITER_STOP; + } + + net_buf_simple_init_with_data(&buf, (void *)data, len); + + gmap_cli->feat.ugt_feat = net_buf_simple_pull_u8(&buf); + LOG_DBG("ugt_feat 0x%02x", gmap_cli->feat.ugt_feat); + + if ((gmap_cli->role & BT_GMAP_ROLE_BGS) != 0) { + err = gmap_discover_bgs_feat(gmap_cli); + } else if ((gmap_cli->role & BT_GMAP_ROLE_BGR) != 0) { + err = gmap_discover_bgr_feat(gmap_cli); + } else { + discover_complete(gmap_cli); + + return BT_GATT_ITER_STOP; + } + + if (err) { + discover_failed(gmap_cli, err); + } + + return BT_GATT_ITER_STOP; +} + +static int gmap_read_ugt_feat(struct bt_gmap_client *gmap_cli, uint16_t handle) +{ + LOG_DBG("conn %p handle 0x%04x", (void *)gmap_cli->conn, handle); + + memset(&gmap_cli->params.read, 0, sizeof(gmap_cli->params.read)); + + gmap_cli->params.read.func = ugt_feat_read_cb; + gmap_cli->params.read.handle_count = 1u; + gmap_cli->params.read.single.handle = handle; + gmap_cli->params.read.single.offset = 0u; + + return bt_gatt_read(gmap_cli->conn, &gmap_cli->params.read); +} + +static uint8_t ugt_feat_discover_func(struct bt_conn *conn, const struct bt_gatt_attr *attr, + struct bt_gatt_discover_params *params) +{ + struct bt_gmap_client *gmap_cli = client_by_conn(conn); + const struct bt_gatt_chrc *chrc; + int err; + + __ASSERT(gmap_cli != NULL, "no instance for conn %p", (void *)conn); + + LOG_DBG("conn %p attr %p params %p", (void *)conn, attr, params); + + if (attr == NULL) { + discover_failed(gmap_cli, -ENOENT); + + return BT_GATT_ITER_STOP; + } + + chrc = attr->user_data; + + /* Read features */ + err = gmap_read_ugt_feat(gmap_cli, chrc->value_handle); + if (err != 0) { + discover_failed(gmap_cli, err); + } + + return BT_GATT_ITER_STOP; +} + +static int gmap_discover_ugt_feat(struct bt_gmap_client *gmap_cli) +{ + LOG_DBG("conn %p", (void *)gmap_cli->conn); + + memset(&gmap_cli->params.discover, 0, sizeof(gmap_cli->params.discover)); + + gmap_cli->params.discover.func = ugt_feat_discover_func; + gmap_cli->params.discover.uuid = gmap_ugt_feat_uuid; + gmap_cli->params.discover.type = BT_GATT_DISCOVER_CHARACTERISTIC; + gmap_cli->params.discover.start_handle = gmap_cli->svc_start_handle; + gmap_cli->params.discover.end_handle = gmap_cli->svc_end_handle; + + return bt_gatt_discover(gmap_cli->conn, &gmap_cli->params.discover); +} + +static uint8_t ugg_feat_read_cb(struct bt_conn *conn, uint8_t att_err, + struct bt_gatt_read_params *params, const void *data, uint16_t len) +{ + struct bt_gmap_client *gmap_cli = client_by_conn(conn); + struct net_buf_simple buf; + int err = att_err; + + __ASSERT(gmap_cli, "no instance for conn %p", (void *)conn); + + LOG_DBG("conn %p att_err 0x%02x params %p data %p len %u", (void *)conn, att_err, params, + data, len); + + if (data == NULL || att_err != BT_ATT_ERR_SUCCESS || len != sizeof(uint8_t)) { + if (att_err == BT_ATT_ERR_SUCCESS) { + att_err = BT_ATT_ERR_INVALID_ATTRIBUTE_LEN; + } + + discover_failed(gmap_cli, err); + + return BT_GATT_ITER_STOP; + } + + net_buf_simple_init_with_data(&buf, (void *)data, len); + + gmap_cli->feat.ugg_feat = net_buf_simple_pull_u8(&buf); + LOG_DBG("ugg_feat 0x%02x", gmap_cli->feat.ugg_feat); + + if ((gmap_cli->role & BT_GMAP_ROLE_UGT) != 0) { + err = gmap_discover_ugt_feat(gmap_cli); + } else if ((gmap_cli->role & BT_GMAP_ROLE_BGS) != 0) { + err = gmap_discover_bgs_feat(gmap_cli); + } else if ((gmap_cli->role & BT_GMAP_ROLE_BGR) != 0) { + err = gmap_discover_bgr_feat(gmap_cli); + } else { + discover_complete(gmap_cli); + + return BT_GATT_ITER_STOP; + } + + if (err) { + discover_failed(gmap_cli, err); + } + + return BT_GATT_ITER_STOP; +} + +static int gmap_read_ugg_feat(struct bt_gmap_client *gmap_cli, uint16_t handle) +{ + LOG_DBG("conn %p handle 0x%04x", (void *)gmap_cli->conn, handle); + + memset(&gmap_cli->params.read, 0, sizeof(gmap_cli->params.read)); + + gmap_cli->params.read.func = ugg_feat_read_cb; + gmap_cli->params.read.handle_count = 1u; + gmap_cli->params.read.single.handle = handle; + gmap_cli->params.read.single.offset = 0u; + + return bt_gatt_read(gmap_cli->conn, &gmap_cli->params.read); +} + +static uint8_t ugg_feat_discover_func(struct bt_conn *conn, const struct bt_gatt_attr *attr, + struct bt_gatt_discover_params *params) +{ + struct bt_gmap_client *gmap_cli = client_by_conn(conn); + const struct bt_gatt_chrc *chrc; + int err; + + __ASSERT(gmap_cli != NULL, "no instance for conn %p", (void *)conn); + + LOG_DBG("conn %p attr %p params %p", (void *)conn, attr, params); + + if (attr == NULL) { + discover_failed(gmap_cli, -ENOENT); + + return BT_GATT_ITER_STOP; + } + + chrc = attr->user_data; + + /* Read features */ + err = gmap_read_ugg_feat(gmap_cli, chrc->value_handle); + if (err != 0) { + discover_failed(gmap_cli, err); + } + + return BT_GATT_ITER_STOP; +} + +static int gmap_discover_ugg_feat(struct bt_gmap_client *gmap_cli) +{ + LOG_DBG("conn %p", (void *)gmap_cli->conn); + + memset(&gmap_cli->params.discover, 0, sizeof(gmap_cli->params.discover)); + + gmap_cli->params.discover.func = ugg_feat_discover_func; + gmap_cli->params.discover.uuid = gmap_ugg_feat_uuid; + gmap_cli->params.discover.type = BT_GATT_DISCOVER_CHARACTERISTIC; + gmap_cli->params.discover.start_handle = gmap_cli->svc_start_handle; + gmap_cli->params.discover.end_handle = gmap_cli->svc_end_handle; + + return bt_gatt_discover(gmap_cli->conn, &gmap_cli->params.discover); +} + +static uint8_t role_read_cb(struct bt_conn *conn, uint8_t att_err, + struct bt_gatt_read_params *params, const void *data, uint16_t len) +{ + struct bt_gmap_client *gmap_cli = client_by_conn(conn); + struct net_buf_simple buf; + int err = att_err; + + __ASSERT(gmap_cli, "no instance for conn %p", (void *)conn); + + LOG_DBG("conn %p att_err 0x%02x params %p data %p len %u", (void *)conn, att_err, params, + data, len); + + if (data == NULL || att_err != BT_ATT_ERR_SUCCESS || len != sizeof(uint8_t)) { + if (att_err == BT_ATT_ERR_SUCCESS) { + att_err = BT_ATT_ERR_INVALID_ATTRIBUTE_LEN; + } + + discover_failed(gmap_cli, err); + + return BT_GATT_ITER_STOP; + } + + net_buf_simple_init_with_data(&buf, (void *)data, len); + + gmap_cli->role = net_buf_simple_pull_u8(&buf); + LOG_DBG("role 0x%02x", gmap_cli->role); + + if ((gmap_cli->role & BT_GMAP_ROLE_UGG) != 0) { + err = gmap_discover_ugg_feat(gmap_cli); + } else if ((gmap_cli->role & BT_GMAP_ROLE_UGT) != 0) { + err = gmap_discover_ugt_feat(gmap_cli); + } else if ((gmap_cli->role & BT_GMAP_ROLE_BGS) != 0) { + err = gmap_discover_bgs_feat(gmap_cli); + } else if ((gmap_cli->role & BT_GMAP_ROLE_BGR) != 0) { + err = gmap_discover_bgr_feat(gmap_cli); + } else { + LOG_DBG("Remote device does not support any known roles"); + err = -ECANCELED; + } + + if (err) { + discover_failed(gmap_cli, err); + } + + return BT_GATT_ITER_STOP; +} + +static int gmap_read_role(struct bt_gmap_client *gmap_cli, uint16_t handle) +{ + LOG_DBG("conn %p handle 0x%04x", (void *)gmap_cli->conn, handle); + + memset(&gmap_cli->params.read, 0, sizeof(gmap_cli->params.read)); + + gmap_cli->params.read.func = role_read_cb; + gmap_cli->params.read.handle_count = 1u; + gmap_cli->params.read.single.handle = handle; + gmap_cli->params.read.single.offset = 0u; + + return bt_gatt_read(gmap_cli->conn, &gmap_cli->params.read); +} + +static uint8_t role_discover_func(struct bt_conn *conn, const struct bt_gatt_attr *attr, + struct bt_gatt_discover_params *params) +{ + struct bt_gmap_client *gmap_cli = client_by_conn(conn); + const struct bt_gatt_chrc *chrc; + int err; + + __ASSERT(gmap_cli != NULL, "no instance for conn %p", (void *)conn); + + LOG_DBG("conn %p attr %p params %p", (void *)conn, attr, params); + + if (attr == NULL) { + discover_failed(gmap_cli, -ENOENT); + + return BT_GATT_ITER_STOP; + } + + chrc = attr->user_data; + + /* Read features */ + err = gmap_read_role(gmap_cli, chrc->value_handle); + if (err != 0) { + discover_failed(gmap_cli, err); + } + + return BT_GATT_ITER_STOP; +} + +static int gmap_discover_role(struct bt_gmap_client *gmap_cli) +{ + LOG_DBG("conn %p", (void *)gmap_cli->conn); + + memset(&gmap_cli->params.discover, 0, sizeof(gmap_cli->params.discover)); + + gmap_cli->params.discover.func = role_discover_func; + gmap_cli->params.discover.uuid = gmap_role_uuid; + gmap_cli->params.discover.type = BT_GATT_DISCOVER_CHARACTERISTIC; + gmap_cli->params.discover.start_handle = gmap_cli->svc_start_handle; + gmap_cli->params.discover.end_handle = gmap_cli->svc_end_handle; + + return bt_gatt_discover(gmap_cli->conn, &gmap_cli->params.discover); +} + +static uint8_t gmas_discover_func(struct bt_conn *conn, const struct bt_gatt_attr *attr, + struct bt_gatt_discover_params *params) +{ + struct bt_gmap_client *gmap_cli = client_by_conn(conn); + const struct bt_gatt_service_val *svc; + int err; + + __ASSERT(gmap_cli != NULL, "no instance for conn %p", (void *)conn); + + LOG_DBG("conn %p attr %p params %p", (void *)conn, attr, params); + + if (attr == NULL) { + discover_failed(gmap_cli, -ENOENT); + + return BT_GATT_ITER_STOP; + } + + svc = (struct bt_gatt_service_val *)attr->user_data; + gmap_cli->svc_start_handle = attr->handle; + gmap_cli->svc_end_handle = svc->end_handle; + + err = gmap_discover_role(gmap_cli); + if (err != 0) { + discover_failed(gmap_cli, err); + } + + return BT_GATT_ITER_STOP; +} + +int bt_gmap_discover(struct bt_conn *conn) +{ + struct bt_gmap_client *gmap_cli; + int err; + + CHECKIF(conn == NULL) { + LOG_DBG("NULL conn"); + + return -EINVAL; + } + + gmap_cli = &gmap_insts[bt_conn_index(conn)]; + + if (gmap_cli->busy) { + LOG_DBG("Busy"); + + return -EBUSY; + } + + gmap_reset(gmap_cli); + + gmap_cli->params.discover.func = gmas_discover_func; + gmap_cli->params.discover.uuid = gmas_uuid; + gmap_cli->params.discover.type = BT_GATT_DISCOVER_PRIMARY; + gmap_cli->params.discover.start_handle = BT_ATT_FIRST_ATTRIBUTE_HANDLE; + gmap_cli->params.discover.end_handle = BT_ATT_LAST_ATTRIBUTE_HANDLE; + + err = bt_gatt_discover(conn, &gmap_cli->params.discover); + if (err != 0) { + LOG_DBG("Failed to initiate discovery: %d", err); + + return -ENOEXEC; + } + + gmap_cli->conn = bt_conn_ref(conn); + + return 0; +} + +int bt_gmap_cb_register(const struct bt_gmap_cb *cb) +{ + CHECKIF(cb == NULL) { + LOG_DBG("cb is NULL"); + + return -EINVAL; + } + + if (gmap_cb != NULL) { + LOG_DBG("GMAP callbacks already registered"); + + return -EALREADY; + } + + gmap_cb = cb; + + return 0; +} diff --git a/subsys/bluetooth/audio/gmap_server.c b/subsys/bluetooth/audio/gmap_server.c new file mode 100644 index 00000000000..5bc16ee686f --- /dev/null +++ b/subsys/bluetooth/audio/gmap_server.c @@ -0,0 +1,417 @@ +/* + * Copyright (c) 2023 Nordic Semiconductor ASA + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include +#include +#include + +#include + +#include "audio_internal.h" + +LOG_MODULE_REGISTER(bt_gmap_server, CONFIG_BT_GMAP_LOG_LEVEL); + +#define BT_GMAP_ROLE_MASK \ + (BT_GMAP_ROLE_UGG | BT_GMAP_ROLE_UGT | BT_GMAP_ROLE_BGS | BT_GMAP_ROLE_BGR) + +static uint8_t gmap_role; +static struct bt_gmap_feat gmap_features; + +static ssize_t read_gmap_role(struct bt_conn *conn, const struct bt_gatt_attr *attr, void *buf, + uint16_t len, uint16_t offset) +{ + LOG_DBG("role 0x%02X", gmap_role); + + return bt_gatt_attr_read(conn, attr, buf, len, offset, &gmap_role, sizeof(gmap_role)); +} + +#if defined(CONFIG_BT_GMAP_UGG_SUPPORTED) +static ssize_t read_gmap_ugg_feat(struct bt_conn *conn, const struct bt_gatt_attr *attr, void *buf, + uint16_t len, uint16_t offset) +{ + const uint8_t feat = (uint8_t)gmap_features.ugg_feat; + + LOG_DBG("feat 0x%02X", feat); + + return bt_gatt_attr_read(conn, attr, buf, len, offset, &feat, sizeof(feat)); +} + +static const struct bt_gatt_attr ugg_feat_chrc[] = { + BT_AUDIO_CHRC(BT_UUID_GMAP_UGG_FEAT, BT_GATT_CHRC_READ, BT_GATT_PERM_READ_ENCRYPT, + read_gmap_ugg_feat, NULL, NULL), +}; +#endif /* CONFIG_BT_GMAP_UGG_SUPPORTED */ + +#if defined(CONFIG_BT_GMAP_UGT_SUPPORTED) +static ssize_t read_gmap_ugt_feat(struct bt_conn *conn, const struct bt_gatt_attr *attr, void *buf, + uint16_t len, uint16_t offset) +{ + const uint8_t feat = (uint8_t)gmap_features.ugt_feat; + + LOG_DBG("feat 0x%02X", feat); + + return bt_gatt_attr_read(conn, attr, buf, len, offset, &feat, sizeof(feat)); +} + +static const struct bt_gatt_attr ugt_feat_chrc[] = { + BT_AUDIO_CHRC(BT_UUID_GMAP_UGT_FEAT, BT_GATT_CHRC_READ, BT_GATT_PERM_READ_ENCRYPT, + read_gmap_ugt_feat, NULL, NULL), +}; + +#endif /* CONFIG_BT_GMAP_UGT_SUPPORTED */ + +#if defined(CONFIG_BT_GMAP_BGS_SUPPORTED) +static ssize_t read_gmap_bgs_feat(struct bt_conn *conn, const struct bt_gatt_attr *attr, void *buf, + uint16_t len, uint16_t offset) +{ + const uint8_t feat = (uint8_t)gmap_features.bgs_feat; + + LOG_DBG("feat 0x%02X", feat); + + return bt_gatt_attr_read(conn, attr, buf, len, offset, &feat, sizeof(feat)); +} + +static const struct bt_gatt_attr bgs_feat_chrc[] = { + BT_AUDIO_CHRC(BT_UUID_GMAP_BGS_FEAT, BT_GATT_CHRC_READ, BT_GATT_PERM_READ_ENCRYPT, + read_gmap_bgs_feat, NULL, NULL), +}; +#endif /* CONFIG_BT_GMAP_BGS_SUPPORTED */ + +#if defined(CONFIG_BT_GMAP_BGR_SUPPORTED) +static ssize_t read_gmap_bgr_feat(struct bt_conn *conn, const struct bt_gatt_attr *attr, void *buf, + uint16_t len, uint16_t offset) +{ + const uint8_t feat = (uint8_t)gmap_features.bgr_feat; + + LOG_DBG("feat 0x%02X", feat); + + return bt_gatt_attr_read(conn, attr, buf, len, offset, &feat, sizeof(feat)); +} + +static const struct bt_gatt_attr bgr_feat_chrc[] = { + BT_AUDIO_CHRC(BT_UUID_GMAP_BGR_FEAT, BT_GATT_CHRC_READ, BT_GATT_PERM_READ_ENCRYPT, + read_gmap_bgr_feat, NULL, NULL), +}; +#endif /* CONFIG_BT_GMAP_BGR_SUPPORTED */ + +/* There are 4 optional characteristics - Use a dummy definition to allocate memory and then add the + * characteristics at will when registering or modifying the role(s) + */ +#define GMAS_DUMMY_CHRC BT_AUDIO_CHRC(0, 0, 0, NULL, NULL, NULL) + +/* Gaming Audio Service attributes */ +static struct bt_gatt_attr svc_attrs[] = { + BT_GATT_PRIMARY_SERVICE(BT_UUID_GMAS), + BT_AUDIO_CHRC(BT_UUID_GMAP_ROLE, BT_GATT_CHRC_READ, BT_GATT_PERM_READ_ENCRYPT, + read_gmap_role, NULL, NULL), +#if defined(CONFIG_BT_GMAP_UGG_SUPPORTED) + GMAS_DUMMY_CHRC, +#endif /* CONFIG_BT_GMAP_UGG_SUPPORTED */ +#if defined(CONFIG_BT_GMAP_UGT_SUPPORTED) + GMAS_DUMMY_CHRC, +#endif /* CONFIG_BT_GMAP_UGT_SUPPORTED */ +#if defined(CONFIG_BT_GMAP_BGS_SUPPORTED) + GMAS_DUMMY_CHRC, +#endif /* CONFIG_BT_GMAP_BGS_SUPPORTED */ +#if defined(CONFIG_BT_GMAP_BGR_SUPPORTED) + GMAS_DUMMY_CHRC, +#endif /* CONFIG_BT_GMAP_BGR_SUPPORTED */ +}; +static struct bt_gatt_service gmas; + +static bool valid_gmap_role(enum bt_gmap_role role) +{ + if (role == 0 || (role & BT_GMAP_ROLE_MASK) != role) { + LOG_DBG("Invalid role %d", role); + } + + if ((role & BT_GMAP_ROLE_UGG) != 0 && !IS_ENABLED(CONFIG_BT_GMAP_UGG_SUPPORTED)) { + LOG_DBG("Device does not support the UGG role"); + + return false; + } + + if ((role & BT_GMAP_ROLE_UGT) != 0 && !IS_ENABLED(CONFIG_BT_GMAP_UGT_SUPPORTED)) { + LOG_DBG("Device does not support the UGT role"); + + return false; + } + + if ((role & BT_GMAP_ROLE_BGS) != 0 && !IS_ENABLED(CONFIG_BT_GMAP_BGS_SUPPORTED)) { + LOG_DBG("Device does not support the BGS role"); + + return false; + } + + if ((role & BT_GMAP_ROLE_BGR) != 0 && !IS_ENABLED(CONFIG_BT_GMAP_BGR_SUPPORTED)) { + LOG_DBG("Device does not support the BGR role"); + + return false; + } + + return true; +} + +static bool valid_gmap_features(enum bt_gmap_role role, struct bt_gmap_feat features) +{ + /* Guard with BT_GMAP_UGG_SUPPORTED as the Kconfigs may not be available without it*/ +#if defined(CONFIG_BT_GMAP_UGG_SUPPORTED) + if ((role & BT_GMAP_ROLE_UGG) != 0) { + enum bt_gmap_ugg_feat ugg_feat = features.ugg_feat; + + if ((ugg_feat & BT_GMAP_UGG_FEAT_MULTIPLEX) != 0 && + CONFIG_BT_BAP_UNICAST_CLIENT_ASE_SRC_COUNT == 0) { + LOG_DBG("Cannot support BT_GMAP_UGG_FEAT_MULTIPLEX with " + "CONFIG_BT_BAP_UNICAST_CLIENT_ASE_SRC_COUNT == 0"); + + return false; + } + + if ((ugg_feat & BT_GMAP_UGG_FEAT_96KBPS_SOURCE) != 0 && + CONFIG_BT_BAP_UNICAST_CLIENT_ASE_SRC_COUNT == 0) { + LOG_DBG("Cannot support BT_GMAP_UGG_FEAT_96KBPS_SOURCE with " + "CONFIG_BT_BAP_UNICAST_CLIENT_ASE_SRC_COUNT == 0"); + + return false; + } + + if ((ugg_feat & BT_GMAP_UGG_FEAT_MULTISINK) != 0 && + (CONFIG_BT_BAP_UNICAST_CLIENT_ASE_SNK_COUNT < 2 || + CONFIG_BT_BAP_UNICAST_CLIENT_GROUP_STREAM_COUNT < 2)) { + LOG_DBG("Cannot support BT_GMAP_UGG_FEAT_MULTISINK with " + "CONFIG_BT_BAP_UNICAST_CLIENT_ASE_SNK_COUNT (%d) or " + "CONFIG_BT_BAP_UNICAST_CLIENT_GROUP_STREAM_COUNT (%d) < 2", + CONFIG_BT_BAP_UNICAST_CLIENT_ASE_SNK_COUNT, + CONFIG_BT_BAP_UNICAST_CLIENT_GROUP_STREAM_COUNT); + + return false; + } + } +#endif /* CONFIG_BT_BAP_UNICAST_CLIENT */ + +#if defined(CONFIG_BT_GMAP_UGT_SUPPORTED) + if ((role & BT_GMAP_ROLE_UGT) != 0) { + enum bt_gmap_ugt_feat ugt_feat = features.ugt_feat; + enum bt_gmap_bgr_feat bgr_feat = features.bgr_feat; + + if ((ugt_feat & BT_GMAP_UGT_FEAT_SOURCE) == 0 && + (ugt_feat & BT_GMAP_UGT_FEAT_SINK) == 0) { + LOG_DBG("Device shall support either BT_GMAP_UGT_FEAT_SOURCE or " + "BT_GMAP_UGT_FEAT_SINK"); + + return false; + } + + if ((ugt_feat & BT_GMAP_UGT_FEAT_SOURCE) == 0 && + ((ugt_feat & BT_GMAP_UGT_FEAT_80KBPS_SOURCE) != 0 || + (ugt_feat & BT_GMAP_UGT_FEAT_MULTISOURCE) != 0)) { + LOG_DBG("Device shall support BT_GMAP_UGT_FEAT_SOURCE if " + "BT_GMAP_UGT_FEAT_80KBPS_SOURCE or BT_GMAP_UGT_FEAT_MULTISOURCE is " + "supported"); + + return false; + } + + if ((ugt_feat & BT_GMAP_UGT_FEAT_SOURCE) != 0 && + CONFIG_BT_ASCS_ASE_SRC_COUNT == 0) { + LOG_DBG("Cannot support BT_GMAP_UGT_FEAT_SOURCE with " + "CONFIG_BT_ASCS_ASE_SRC_COUNT == 0"); + + return false; + } + + if ((ugt_feat & BT_GMAP_UGT_FEAT_MULTISOURCE) != 0 && + (CONFIG_BT_ASCS_ASE_SRC_COUNT < 2 || CONFIG_BT_ASCS_MAX_ACTIVE_ASES < 2)) { + LOG_DBG("Cannot support BT_GMAP_UGT_FEAT_MULTISOURCE with " + "CONFIG_BT_ASCS_ASE_SRC_COUNT (%d) or " + "CONFIG_BT_ASCS_MAX_ACTIVE_ASES (%d) < 2", + CONFIG_BT_ASCS_ASE_SRC_COUNT, CONFIG_BT_ASCS_MAX_ACTIVE_ASES); + + return false; + } + + if ((ugt_feat & BT_GMAP_UGT_FEAT_SINK) != 0 && CONFIG_BT_ASCS_ASE_SNK_COUNT == 0) { + LOG_DBG("Cannot support BT_GMAP_UGT_FEAT_SINK with " + "CONFIG_BT_ASCS_ASE_SNK_COUNT == 0"); + + return false; + } + + if ((ugt_feat & BT_GMAP_UGT_FEAT_SINK) == 0 && + ((ugt_feat & BT_GMAP_UGT_FEAT_64KBPS_SINK) != 0 || + (ugt_feat & BT_GMAP_UGT_FEAT_MULTISINK) != 0 || + (ugt_feat & BT_GMAP_UGT_FEAT_MULTIPLEX) != 0)) { + LOG_DBG("Device shall support BT_GMAP_UGT_FEAT_SINK if " + "BT_GMAP_UGT_FEAT_64KBPS_SINK, BT_GMAP_UGT_FEAT_MULTISINK or " + "BT_GMAP_UGT_FEAT_MULTIPLEX is supported"); + + return false; + } + + if ((ugt_feat & BT_GMAP_UGT_FEAT_MULTISINK) != 0 && + (CONFIG_BT_ASCS_ASE_SNK_COUNT < 2 || CONFIG_BT_ASCS_MAX_ACTIVE_ASES < 2)) { + LOG_DBG("Cannot support BT_GMAP_UGT_FEAT_MULTISINK with " + "CONFIG_BT_ASCS_ASE_SNK_COUNT (%d) or " + "CONFIG_BT_ASCS_MAX_ACTIVE_ASES (%d) < 2", + CONFIG_BT_ASCS_ASE_SNK_COUNT, CONFIG_BT_ASCS_MAX_ACTIVE_ASES); + + return false; + } + + /* If the device supports both the UGT and BGT roles, then it needs have the same + * support for multiplexing for both roles + */ + if ((role & BT_GMAP_ROLE_BGR) != 0 && !IS_ENABLED(CONFIG_BT_GMAP_BGR_SUPPORTED) && + (ugt_feat & BT_GMAP_UGT_FEAT_MULTIPLEX) != + (bgr_feat & BT_GMAP_BGR_FEAT_MULTIPLEX)) { + LOG_DBG("Device shall support BT_GMAP_UGT_FEAT_MULTIPLEX if " + "BT_GMAP_BGR_FEAT_MULTIPLEX is supported, and vice versa"); + } + } +#endif /* CONFIG_BT_GMAP_UGT_SUPPORTED */ + +#if defined(CONFIG_BT_GMAP_BGR_SUPPORTED) + if ((role & BT_GMAP_ROLE_BGR) != 0) { + enum bt_gmap_bgr_feat bgr_feat = features.bgr_feat; + + if ((bgr_feat & BT_GMAP_BGR_FEAT_MULTISINK) != 0 && + CONFIG_BT_BAP_BROADCAST_SNK_STREAM_COUNT < 2) { + LOG_DBG("Cannot support BT_GMAP_BGR_FEAT_MULTISINK with " + "CONFIG_BT_BAP_BROADCAST_SNK_STREAM_COUNT (%d) < 2", + CONFIG_BT_BAP_BROADCAST_SNK_STREAM_COUNT); + + return false; + } + } +#endif /* CONFIG_BT_GMAP_BGR_SUPPORTED */ + + /* If the roles are not supported, then the feature characteristics are not instantiated and + * the feature values do not need to be checked, as they will never be read (thus ignore by + * the stack) + */ + + return true; +} + +static void update_service(enum bt_gmap_role role) +{ + gmas.attrs = svc_attrs; + gmas.attr_count = 3; /* service + 2 attributes for BT_UUID_GMAP_ROLE */ + + /* Add characteristics based on the role selected and what is supported */ +#if defined(CONFIG_BT_GMAP_UGG_SUPPORTED) + if (role & BT_GMAP_ROLE_UGG) { + memcpy(&gmas.attrs[gmas.attr_count], ugg_feat_chrc, sizeof(ugg_feat_chrc)); + gmas.attr_count += ARRAY_SIZE(ugg_feat_chrc); + } +#endif /* CONFIG_BT_GMAP_UGG_SUPPORTED */ + +#if defined(CONFIG_BT_GMAP_UGT_SUPPORTED) + if (role & BT_GMAP_ROLE_UGT) { + memcpy(&gmas.attrs[gmas.attr_count], ugt_feat_chrc, sizeof(ugt_feat_chrc)); + gmas.attr_count += ARRAY_SIZE(ugt_feat_chrc); + } +#endif /* CONFIG_BT_GMAP_UGT_SUPPORTED */ + +#if defined(CONFIG_BT_GMAP_BGS_SUPPORTED) + if (role & BT_GMAP_ROLE_BGS) { + memcpy(&gmas.attrs[gmas.attr_count], bgs_feat_chrc, sizeof(bgs_feat_chrc)); + gmas.attr_count += ARRAY_SIZE(bgs_feat_chrc); + } +#endif /* CONFIG_BT_GMAP_BGS_SUPPORTED */ + +#if defined(CONFIG_BT_GMAP_BGR_SUPPORTED) + if (role & BT_GMAP_ROLE_BGR) { + memcpy(&gmas.attrs[gmas.attr_count], bgr_feat_chrc, sizeof(bgr_feat_chrc)); + gmas.attr_count += ARRAY_SIZE(bgr_feat_chrc); + } +#endif /* CONFIG_BT_GMAP_BGR_SUPPORTED */ +} + +int bt_gmap_register(enum bt_gmap_role role, struct bt_gmap_feat features) +{ + int err; + + CHECKIF(!valid_gmap_role(role)) { + LOG_DBG("Invalid role: %d", role); + + return -EINVAL; + } + + CHECKIF(!valid_gmap_features(role, features)) { + LOG_DBG("Invalid features"); + + return -EINVAL; + } + + update_service(role); + + err = bt_gatt_service_register(&gmas); + if (err) { + LOG_DBG("Could not register the GMAS service"); + + return -ENOEXEC; + } + + gmap_role = role; + gmap_features = features; + + return 0; +} + +int bt_gmap_set_role(enum bt_gmap_role role, struct bt_gmap_feat features) +{ + int err; + + if (gmap_role == 0) { /* not registered if this is 0 */ + LOG_DBG("GMAP not registered"); + + return -ENOEXEC; + } + + CHECKIF(!valid_gmap_role(role)) { + LOG_DBG("Invalid role: %d", role); + + return -EINVAL; + } + + CHECKIF(!valid_gmap_features(role, features)) { + LOG_DBG("Invalid features"); + + return -EINVAL; + } + + if (gmap_role == role) { + LOG_DBG("No role change"); + + if (memcmp(&gmap_features, &features, sizeof(gmap_features)) == 0) { + LOG_DBG("No feature change"); + + return -EALREADY; + } + + gmap_features = features; + + return 0; + } + + /* Re-register the service to trigger a db_changed() if the roles changed */ + err = bt_gatt_service_unregister(&gmas); + if (err != 0) { + LOG_DBG("Failed to unregister service: %d", err); + + return -ENOENT; + } + + err = bt_gmap_register(role, gmap_features); + if (err != 0) { + LOG_DBG("Failed to update GMAS: %d", err); + + return -ECANCELED; + } + + return 0; +} From 9c8ec58bebed7478901551c2538c642ea3f2660e Mon Sep 17 00:00:00 2001 From: Emil Gydesen Date: Thu, 24 Aug 2023 14:59:17 +0200 Subject: [PATCH 1020/3723] Bluetooth: GMAP: Add GMAP shell Add the GMAP shell module with support for running the various audio configurations in an easy way. Signed-off-by: Emil Gydesen --- doc/connectivity/bluetooth/api/index.rst | 1 + doc/connectivity/bluetooth/api/shell/gmap.rst | 82 +++ subsys/bluetooth/audio/shell/CMakeLists.txt | 4 + subsys/bluetooth/audio/shell/audio.h | 15 +- subsys/bluetooth/audio/shell/bap.c | 34 +- subsys/bluetooth/audio/shell/cap_initiator.c | 12 +- subsys/bluetooth/audio/shell/gmap.c | 564 ++++++++++++++++++ subsys/bluetooth/shell/bt.c | 8 +- tests/bluetooth/shell/audio.conf | 8 + tests/bluetooth/shell/testcase.yaml | 6 + 10 files changed, 715 insertions(+), 19 deletions(-) create mode 100644 doc/connectivity/bluetooth/api/shell/gmap.rst create mode 100644 subsys/bluetooth/audio/shell/gmap.c diff --git a/doc/connectivity/bluetooth/api/index.rst b/doc/connectivity/bluetooth/api/index.rst index 51c36386114..9152aa7ff10 100644 --- a/doc/connectivity/bluetooth/api/index.rst +++ b/doc/connectivity/bluetooth/api/index.rst @@ -35,6 +35,7 @@ Bluetooth APIs shell/cap.rst shell/ccp.rst shell/csip.rst + shell/gmap.rst shell/iso.rst shell/mcp.rst shell/tmap.rst diff --git a/doc/connectivity/bluetooth/api/shell/gmap.rst b/doc/connectivity/bluetooth/api/shell/gmap.rst new file mode 100644 index 00000000000..11259297a5b --- /dev/null +++ b/doc/connectivity/bluetooth/api/shell/gmap.rst @@ -0,0 +1,82 @@ +Bluetooth: Gaming Audio Profile Shell +##################################### + +This document describes how to run the Gaming Audio Profile shell functionality. +Unlike most other low-layer profiles, GMAP is a profile that exists and has a service (GMAS) on all +devices. Thus both the initiator and acceptor (or central and peripheral) should do a discovery of +the remote device's GMAS to see what GMAP roles and features they support. + +Using the GMAP Shell +******************** + +When the Bluetooth stack has been initialized (:code:`bt init`), the GMAS can be registered by +by calling :code:`gmap init`. It is also strongly suggested to enable BAP via :code:`bap init`. + +.. code-block:: console + + gmap --help + gmap - Bluetooth GMAP shell commands + Subcommands: + init :[none] + set_role :[ugt | ugg | bgr | bgs] + discover :[none] + ac_1 : + ac_2 : + ac_3 : + ac_4 : + ac_5 : + ac_6_i : + ac_6_ii : + ac_7_ii : + ac_8_i : + ac_8_ii : + ac_11_i : + ac_11_ii : + ac_12 : + ac_13 : + ac_14 : + +The :code:`set_role` command can be used to change the role at runtime, assuming that the device +supports the role (the GMAP roles depend on some BAP configurations). + +Example Central with GMAP UGT role +********************************** + +Connect and establish Gaming Audio streams using Audio Configuration (AC) 3 +(some logging has been omitted for clarity): + +.. code-block:: console + + uart:~$ bt init + uart:~$ bap init + uart:~$ gmap init + uart:~$ bt connect